diff --git a/Engine/Binaries/ThirdParty/AppLocalDependencies/DirectXRedist.tps b/Engine/Binaries/ThirdParty/AppLocalDependencies/DirectXRedist.tps new file mode 100644 index 000000000000..dd9418e59b88 --- /dev/null +++ b/Engine/Binaries/ThirdParty/AppLocalDependencies/DirectXRedist.tps @@ -0,0 +1,9 @@ + + + + /Engine/Binaries/ThirdParty/AppLocalDependencies/DirectX/ + +Redirect: ../../../../Source/Programs/PrereqInstaller/CustomAction/Resources/DirectXRedist/DirectXRedist.tps + + + \ No newline at end of file diff --git a/Engine/Binaries/ThirdParty/Phonon/Phonon.tps b/Engine/Binaries/ThirdParty/Phonon/Phonon.tps index 9406a434bfc9..bf88b5684c52 100644 --- a/Engine/Binaries/ThirdParty/Phonon/Phonon.tps +++ b/Engine/Binaries/ThirdParty/Phonon/Phonon.tps @@ -1,25 +1,9 @@  - Phonon - - 2017-01-20T11:16:30.8126987-08:00 - Physics-based audio for games and virtual reality - To get realistic occlusion, reverb, and spatialization tech - - PC - Mac - Android - Linux - - - UE4 - - lib - - - false - false - None - + + /Engine/Binaries/ThirdParty/Phonon/ + +Redirect: ../../../Source/ThirdParty/libPhonon/LibPhonon.tps + \ No newline at end of file diff --git a/Engine/Build/Android/Java/aar-imports.txt b/Engine/Build/Android/Java/aar-imports.txt index 39dfaf398fc5..12759fa754ff 100644 --- a/Engine/Build/Android/Java/aar-imports.txt +++ b/Engine/Build/Android/Java/aar-imports.txt @@ -1,7 +1,7 @@ repositories $(ANDROID_HOME)/extras repositories $(ENGINEDIR)/Source/ThirdParty/Android/extras -com.google.android.gms,play-services-ads,9.2.0 -com.google.android.gms,play-services-auth,9.2.0 -com.google.android.gms,play-services-games,9.2.0 -com.google.android.gms,play-services-nearby,9.2.0 -com.google.android.gms,play-services-plus,9.2.0 +com.google.android.gms,play-services-ads,9.8.0 +com.google.android.gms,play-services-auth,9.8.0 +com.google.android.gms,play-services-games,9.8.0 +com.google.android.gms,play-services-nearby,9.8.0 +com.google.android.gms,play-services-plus,9.8.0 diff --git a/Engine/Build/Android/Java/proguard-project.txt b/Engine/Build/Android/Java/proguard-project.txt index 81133f0474b8..1391d4b0d748 100644 --- a/Engine/Build/Android/Java/proguard-project.txt +++ b/Engine/Build/Android/Java/proguard-project.txt @@ -66,6 +66,12 @@ -keep class com.epicgames.ue4.WebViewControl { public *; } +-keep class com.epicgames.ue4.WebViewControl$ViewClient { + public *; +} +-keep class com.epicgames.ue4.WebViewControl$ChromeClient { + public *; +} -keep class com.epicgames.ue4.WebViewControl$ViewClient { public *; diff --git a/Engine/Build/Android/Java/src/com/epicgames/ue4/GameActivity.java b/Engine/Build/Android/Java/src/com/epicgames/ue4/GameActivity.java index 82674b8c48ae..ca2cf288c694 100644 --- a/Engine/Build/Android/Java/src/com/epicgames/ue4/GameActivity.java +++ b/Engine/Build/Android/Java/src/com/epicgames/ue4/GameActivity.java @@ -19,6 +19,9 @@ import android.util.Log; import android.os.Vibrator; import android.os.SystemClock; +//@HSL_BEGIN - chance.lyon - Adding Handler for Sticky window callbacks +import android.os.Handler; +//@HSL_END import android.app.AlertDialog; import android.app.Dialog; @@ -46,6 +49,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.FeatureInfo; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; +import android.provider.Settings.Secure; import android.content.pm.PackageInfo; @@ -53,6 +57,9 @@ import android.media.AudioManager; import android.util.DisplayMetrics; import android.view.InputDevice; +//@HSL_BEGIN - chance.lyon - Adding KeyEvent for Sticky window callbacks +import android.view.KeyEvent; +//@HSL_END import android.view.Gravity; import android.view.MotionEvent; import android.view.View; @@ -83,6 +90,8 @@ import com.google.android.gms.ads.AdView; import com.google.android.gms.ads.AdSize; import com.google.android.gms.ads.AdListener; import com.google.android.gms.ads.InterstitialAd; +import com.google.android.gms.ads.identifier.AdvertisingIdClient; +import com.google.android.gms.ads.identifier.AdvertisingIdClient.Info; import com.google.android.gms.plus.Plus; @@ -243,6 +252,7 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba /** Whether this application is for distribution */ private boolean IsForDistribution = false; + /** Application build configuration */ private String BuildConfiguration = ""; @@ -405,7 +415,7 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba } } - //Check for target sdk. If less than 23 than warn that permission handling is not used. + //Check for target sdk. If 23 or higher then warn that permission handling may mean features don't work if user denies them. int targetSdkVersion = 0; try { @@ -417,9 +427,9 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba Log.debug(e.getMessage()); } - if(targetSdkVersion < 23) //23 is the API level (Marshmallow) where runtime permission handling is available + if (ANDROID_BUILD_VERSION >= 23 && targetSdkVersion >= 23) //23 is the API level (Marshmallow) where runtime permission handling is available { - Log.debug("Target SDK is lower than 23. This may cause issues if permissions are denied by the user." ); + Log.debug("Target SDK is " + targetSdkVersion + ". This may cause issues if permissions are denied by the user." ); } @@ -668,8 +678,7 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba { Log.debug( "UI hiding not found. Leaving as " + ShouldHideUI); } - - if (bundle.containsKey("com.epicgames.ue4.GameActivity.BuildConfiguration")) + if(bundle.containsKey("com.epicgames.ue4.GameActivity.BuildConfiguration")) { BuildConfiguration = bundle.getString("com.epicgames.ue4.GameActivity.BuildConfiguration"); Log.debug( "BuildConfiguration set to " + BuildConfiguration); @@ -971,6 +980,64 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba Log.debug("==============> GameActive.onCreate complete!"); } + +//@HSL_BEGIN - chance.lyon - Adding Handler for Sticky window callbacks + private Handler mRestoreImmersiveModeHandler = new Handler(); + private Runnable restoreImmersiveModeRunnable = new Runnable() + { + public void run() + { + restoreTransparentBars(); + } + }; + + public void restoreTranslucentBarsDelayed() + { + // we restore it now and after 500 ms! + restoreTransparentBars(); + mRestoreImmersiveModeHandler.postDelayed(restoreImmersiveModeRunnable, 500); + } + + public void restoreTransparentBars() + { + if(android.os.Build.VERSION.SDK_INT >= 19) { + try { + View decorView = getWindow().getDecorView(); + + Log.debug("=== Restoring Transparent Bars ==="); + // Clear the flag and then restore it + decorView.setSystemUiVisibility( + View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_FULLSCREEN + /*| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY*/); + + decorView.setSystemUiVisibility( + View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); + + } catch (Exception e) {} + } + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) + { + if(keyCode == KeyEvent.KEYCODE_BACK ||keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP) + { + Log.debug("=== Restoring Transparent Bars due to KeyCode ==="); + restoreTranslucentBarsDelayed(); + } + + return super.onKeyDown(keyCode, event); + } +//@HSL_END @Override public void onResume() @@ -983,45 +1050,29 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba // only do this on KitKat and above if (ShouldHideUI) { - +//@HSL_BEGIN - chance.lyon - Adding Handler for Sticky window callbacks + restoreTransparentBars(); View decorView = getWindow().getDecorView(); - if(android.os.Build.VERSION.SDK_INT >= 19) { - decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_FULLSCREEN - | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); - } /*else { - decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_FULLSCREEN); - }*/ - decorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() { - @Override public void onSystemUiVisibilityChange(int visibility) { - View decorView = getWindow().getDecorView(); - if(android.os.Build.VERSION.SDK_INT >= 19) { - decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_FULLSCREEN - | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); - } /*else { - decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_FULLSCREEN); + @Override + public void onSystemUiVisibilityChange(int visibility) + { + Log.debug("=== Restoring Transparent Bars due to Visibility Change ==="); + restoreTransparentBars(); + } + }); - }*/ - } + decorView.setOnFocusChangeListener(new View.OnFocusChangeListener() { + @Override + public void onFocusChange(View v, boolean hasFocus) + { + Log.debug("=== Restoring Transparent Bars due to Focus Change ==="); + restoreTransparentBars(); + } }); } +//@HSL_END if(HasAllFiles) { @@ -1390,23 +1441,56 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba } } }); + // @HSL_END - Josh.May - 3/28/2017 } public void AndroidThunkJava_LaunchURL(String URL) { + Log.debug("[JAVA} AndroidThunkJava_LaunchURL: URL = " + URL); + if (!URL.contains("://")) + { + URL = "http://" + URL; + Log.debug("[JAVA} AndroidThunkJava_LaunchURL: corrected URL = " + URL); + } try { Intent BrowserIntent = new Intent(Intent.ACTION_VIEW, android.net.Uri.parse(URL)); - startActivity(BrowserIntent); + + // open browser on its own task + BrowserIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); + BrowserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); + + // make sure there is a web browser to handle the URL before trying to start activity (or may crash!) + if (BrowserIntent.resolveActivity(getPackageManager()) != null) + { + Log.debug("[JAVA} AndroidThunkJava_LaunchURL: Starting activity"); + startActivity(BrowserIntent); + } + else + { + Log.debug("[JAVA} AndroidThunkJava_LaunchURL: Could not find an application to receive the URL intent"); + } } catch (Exception e) { - Log.debug("LaunchURL failed with exception " + e.getMessage()); + Log.debug("[JAVA} AndroidThunkJava_LaunchURL: Failed with exception " + e.getMessage()); } } + public String AndroidThunkJava_GetAndroidId() + { + try { + String androidId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); + return androidId; + } catch (Exception e) { + Log.debug("GetAndroidId failed: " + e.getMessage()); + } + return null; + } + public void AndroidThunkJava_ResetAchievements() { + /* Disable so don't need GET_ACCOUNTS - we don't need this try { String accesstoken = GetAccessToken(); @@ -1439,6 +1523,8 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba { Log.debug("AndroidThunkJava_ResetAchievements failed: " + e.getMessage()); } + */ + Log.debug("AndroidThunkJava_ResetAchievements: disabled"); } // TODO: replace this with non-depreciated method (OK now for up to API-25) @@ -1664,6 +1750,17 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba } } + public String AndroidThunkJava_GetAdvertisingId() + { + try { + AdvertisingIdClient.Info adInfo = AdvertisingIdClient.getAdvertisingIdInfo(getApplicationContext()); + return adInfo.getId(); + } catch (Exception e) { + Log.debug("GetAdvertisingId failed: " + e.getMessage()); + } + return null; + } + public void AndroidThunkJava_GoogleClientConnect() { if (googleClient != null) @@ -1690,6 +1787,7 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba { public void run() { + /* Don't do this since deprecated and don't want to request GET_ACCOUNTS permission try { String accesstoken = GetAccessToken(); @@ -1710,6 +1808,8 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba nativeGoogleClientConnectCompleted(false, ""); } + */ + nativeGoogleClientConnectCompleted(true, "NOT_ACQUIRED"); } }).start(); } diff --git a/Engine/Build/Android/Java/src/com/epicgames/ue4/GooglePlayStoreHelper.java b/Engine/Build/Android/Java/src/com/epicgames/ue4/GooglePlayStoreHelper.java index 7f4f8dfd773a..ca3ca5abf241 100644 --- a/Engine/Build/Android/Java/src/com/epicgames/ue4/GooglePlayStoreHelper.java +++ b/Engine/Build/Android/Java/src/com/epicgames/ue4/GooglePlayStoreHelper.java @@ -160,9 +160,9 @@ public class GooglePlayStoreHelper implements StoreHelper prices.add(price); Log.debug("[GooglePlayStoreHelper] - price: " + price); - Float priceRaw = (float) object.getInt("price_amount_micros") / 1000000.0f; - pricesRaw.add(priceRaw); - Log.debug("[GooglePlayStoreHelper] - price_amount_micros: " + priceRaw.toString()); + double priceRaw = object.getDouble("price_amount_micros") / 1000000.0; + pricesRaw.add((float)priceRaw); + Log.debug("[GooglePlayStoreHelper] - price_amount_micros: " + priceRaw); String currencyCode = object.getString("price_currency_code"); currencyCodes.add(currencyCode); diff --git a/Engine/Build/Android/Java/src/com/epicgames/ue4/LocalNotificationReceiver.java b/Engine/Build/Android/Java/src/com/epicgames/ue4/LocalNotificationReceiver.java index 6a79ba7d597a..f34c6ba9da0f 100644 --- a/Engine/Build/Android/Java/src/com/epicgames/ue4/LocalNotificationReceiver.java +++ b/Engine/Build/Android/Java/src/com/epicgames/ue4/LocalNotificationReceiver.java @@ -36,7 +36,11 @@ notificationIntent.putExtra("localNotificationAppLaunched" , true); notificationIntent.putExtra("localNotificationLaunchActivationEvent", activationEvent); - int notificationIconID = context.getResources().getIdentifier("icon", "drawable", context.getPackageName()); + int notificationIconID = context.getResources().getIdentifier("ic_notification", "drawable", context.getPackageName()); + if (notificationIconID == 0) + { + notificationIconID = context.getResources().getIdentifier("icon", "drawable", context.getPackageName()); + } PendingIntent pendingNotificationIntent = PendingIntent.getActivity(context, notificationID, notificationIntent, 0); NotificationCompat.Builder builder = new NotificationCompat.Builder(context) @@ -45,6 +49,10 @@ .setWhen(System.currentTimeMillis()) .setTicker(details) // note: will not show up on Lollipop up except for accessibility .setContentTitle(title); + if (android.os.Build.VERSION.SDK_INT >= 21) + { + builder.setColor(0xff0e1e43); + } Notification notification = builder.build(); // Stick with the defaults diff --git a/Engine/Build/Android/Java/src/com/epicgames/ue4/MediaPlayer14.java b/Engine/Build/Android/Java/src/com/epicgames/ue4/MediaPlayer14.java index a9bf235fbc83..2313dfc6aeac 100644 --- a/Engine/Build/Android/Java/src/com/epicgames/ue4/MediaPlayer14.java +++ b/Engine/Build/Android/Java/src/com/epicgames/ue4/MediaPlayer14.java @@ -572,13 +572,16 @@ public class MediaPlayer14 mTriangleVerticesDirty = true; // Set up GL state - GLES20.glDisable(GLES20.GL_BLEND); - GLES20.glDisable(GLES20.GL_CULL_FACE); - GLES20.glDisable(GLES20.GL_SCISSOR_TEST); - GLES20.glDisable(GLES20.GL_STENCIL_TEST); - GLES20.glDisable(GLES20.GL_DEPTH_TEST); - GLES20.glDisable(GLES20.GL_DITHER); - GLES20.glColorMask(true,true,true,true); + if (mUseOwnContext) + { + GLES20.glDisable(GLES20.GL_BLEND); + GLES20.glDisable(GLES20.GL_CULL_FACE); + GLES20.glDisable(GLES20.GL_SCISSOR_TEST); + GLES20.glDisable(GLES20.GL_STENCIL_TEST); + GLES20.glDisable(GLES20.GL_DEPTH_TEST); + GLES20.glDisable(GLES20.GL_DITHER); + GLES20.glColorMask(true,true,true,true); + } } private void UpdateVertexData() @@ -603,10 +606,7 @@ public class MediaPlayer14 mTriangleVertices, GLES20.GL_STATIC_DRAW); // restore VBO state - if (previousVBO > 0) - { - GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, previousVBO); - } + GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, previousVBO); mTriangleVerticesDirty = false; } @@ -950,14 +950,14 @@ public class MediaPlayer14 // connect 'VideoTexture' to video source texture (mTextureID). // mTextureID is bound to GL_TEXTURE_EXTERNAL_OES in updateTexImage + GLES20.glUniform1i(mTextureUniform, 0); GLES20.glActiveTexture(GLES20.GL_TEXTURE0); GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureID); - GLES20.glUniform1i(mTextureUniform, 0); // Draw the video texture mesh. GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); - GLES20.glFinish(); + GLES20.glFlush(); // Read the FBO texture pixels into raw data. if (null != destData) @@ -992,19 +992,13 @@ public class MediaPlayer14 } else { - if (previousFBO > 0) - { - GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, previousFBO); - } + GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, previousFBO); if (null != destData && FBOTextureID > 0) { glInt[0] = FBOTextureID; GLES20.glDeleteTextures(1, glInt, 0); } - if (previousVBO > 0) - { - GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, previousVBO); - } + GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, previousVBO); GLES20.glViewport(previousViewport[0], previousViewport[1], previousViewport[2], previousViewport[3]); if (previousBlend) GLES20.glEnable(GLES20.GL_BLEND); @@ -1016,6 +1010,11 @@ public class MediaPlayer14 GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, previousMinFilter); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, previousMagFilter); + + // invalidate cached state in RHI + GLES20.glDisableVertexAttribArray(mPositionAttrib); + GLES20.glDisableVertexAttribArray(mTexCoordsAttrib); + nativeClearCachedAttributeState(mPositionAttrib, mTexCoordsAttrib); } return true; @@ -1354,4 +1353,7 @@ public class MediaPlayer14 return VideoTracks; } + + public native void nativeClearCachedAttributeState(int PositionAttrib, int TexCoordsAttrib); + } diff --git a/Engine/Build/Android/Java/src/com/epicgames/ue4/WebViewControl.java b/Engine/Build/Android/Java/src/com/epicgames/ue4/WebViewControl.java index e56c713f66de..ea57eb5e515a 100644 --- a/Engine/Build/Android/Java/src/com/epicgames/ue4/WebViewControl.java +++ b/Engine/Build/Android/Java/src/com/epicgames/ue4/WebViewControl.java @@ -14,6 +14,9 @@ import android.webkit.WebResourceResponse; import android.webkit.JsResult; import android.webkit.JsPromptResult; import android.graphics.Bitmap; +// @HSL_BEGIN - Josh.May - 3/08/2017 - Added background transparency support for AndroidWebBrowserWidget. +import android.graphics.Color; +// @HSL_END - Josh.May - 3/08/2017 import android.webkit.WebBackForwardList; import java.io.ByteArrayInputStream; import java.util.concurrent.ConcurrentHashMap; @@ -41,7 +44,9 @@ class WebViewPositionLayout extends ViewGroup // Wrapper for the layout and WebView for the C++ to call class WebViewControl { - public WebViewControl(long inNativePtr, final boolean bEnableRemoteDebugging) + // @HSL_BEGIN - Josh.May - 3/08/2017 - Added background transparency support for AndroidWebBrowserWidget. + public WebViewControl(long inNativePtr, final boolean bEnableRemoteDebugging, final boolean bUseTransparency) + // @HSL_END - Josh.May - 3/08/2017 { final WebViewControl w = this; @@ -65,6 +70,13 @@ class WebViewControl webView.getSettings().setLightTouchEnabled(true); webView.setFocusableInTouchMode(true); + // @HSL_BEGIN - Josh.May - 3/08/2017 - Added background transparency support for AndroidWebBrowserWidget. + if (bUseTransparency) + { + webView.setBackgroundColor(Color.TRANSPARENT); + } + // @HSL_END - Josh.May - 3/08/2017 + // Wrap the webview in a layout that will do absolute positioning for us positionLayout = new WebViewPositionLayout(GameActivity._activity, w); positionLayout.addView(webView); @@ -174,6 +186,11 @@ class WebViewControl @Override public void run() { + if (bClosed) + { + // queued up run()s can occur after Close() called; don't want to show it again + return; + } if (!bShown) { bShown = true; @@ -222,9 +239,19 @@ class WebViewControl { if (bShown) { - ((ViewGroup)webView.getParent()).removeView(webView); + ViewGroup parent = (ViewGroup)webView.getParent(); + if (parent != null) + { + parent.removeView(webView); + } + parent = (ViewGroup)positionLayout.getParent(); + if (parent != null) + { + parent.removeView(positionLayout); + } bShown = false; } + bClosed = true; } }); } @@ -289,7 +316,6 @@ class WebViewControl return WebViewControl.this.nativePtr; } } - public long GetNativePtr() { return nativePtr; @@ -299,6 +325,7 @@ class WebViewControl private WebViewPositionLayout positionLayout; public int curX, curY, curW, curH; private boolean bShown; + private boolean bClosed; private String NextURL; private String NextContent; diff --git a/Engine/Build/BatchFiles/Linux/Setup.sh b/Engine/Build/BatchFiles/Linux/Setup.sh index 49aa14ded868..ee545efad6d3 100755 --- a/Engine/Build/BatchFiles/Linux/Setup.sh +++ b/Engine/Build/BatchFiles/Linux/Setup.sh @@ -249,7 +249,7 @@ if [ -e /etc/os-release ]; then update-mime-database ~/.local/share/mime fi # Generate .desktop file - if [ ! -f ~/.local/share/applications/UE4Editor.desktop ]; then + if [ -d ~/.local/share/applications ] && [ ! -f ~/.local/share/applications/UE4Editor.desktop ]; then ICON_DIR=$(cd $TOP_DIR/../../.. ; pwd) echo "#!/usr/bin/env xdg-open [Desktop Entry] diff --git a/Engine/Build/BuildFarm/PostpExtensions.pl b/Engine/Build/BuildFarm/PostpExtensions.pl index d17cba7042ed..19ea8df92713 100644 --- a/Engine/Build/BuildFarm/PostpExtensions.pl +++ b/Engine/Build/BuildFarm/PostpExtensions.pl @@ -21,8 +21,15 @@ # Temporary PS4 deprecation warnings ".*OnlineSubsystemPS4.*warning:.*\\[-Wdeprecated-declarations\\]", - ".*PS4Application\\.cpp.*warning:.*\\[-Wdeprecated-declarations\\]" + ".*PS4Application\\.cpp.*warning:.*\\[-Wdeprecated-declarations\\]", + # Missing Steam DLLs/Dylibs when building samples + "STEAM: Steam API disabled!", + "LogMac:Warning: dlopen failed:.*libsteam_api.dylib.*: image not found", + "LogOnline:Warning: STEAM:.*libraries not present.*failed to load!", + + # Some doxygen output can confuse the post-processor, because it lists a symbol containing "Warning::" + "doxygen>.*(Warning|Error)::.*", # ".*ERROR: The process.*not found", # ".*ERROR: This operation returned because the timeout period expired.*", @@ -114,6 +121,11 @@ unshift @::gMatchers, ( pattern => q{([^:]+):[\d:]+ warning:}, action => q{incValue("warnings"); diagnostic($1, "warning", backWhile(": In function"), 0)}, }, + { + id => "genericDoctoolError", + pattern => q{Error:}, + action => q{incValue("errors"); diagnostic("", "error")} + }, { id => "ubtFailedToProduceItem", pattern => q{(ERROR: )?UBT ERROR: Failed to produce item: }, @@ -142,7 +154,12 @@ unshift @::gMatchers, ( { id => "automationException", pattern => q{AutomationTool\\.AutomationException: }, - action => q{incValue("errors"); diagnostic("Exception", "error", 0, forwardWhile("^ at "));} + action => q{incValue("errors"); diagnostic("Exception", "error", 0, forwardWhile("^ at "));} + }, + { + id => "generalException", + pattern => q{^ERROR: [a-zA-Z0-9_]+\\.[a-zA-Z0-9_]+Exception: }, + action => q{incValue("errors"); diagnostic("Exception", "error", 0, forwardWhile("^ at "));} }, { id => "ubtFatal", diff --git a/Engine/Build/BuildFarm/PostpFilter.pl b/Engine/Build/BuildFarm/PostpFilter.pl index 9068c33cca53..0881a1318702 100644 --- a/Engine/Build/BuildFarm/PostpFilter.pl +++ b/Engine/Build/BuildFarm/PostpFilter.pl @@ -7,6 +7,9 @@ select(STDERR); $| = 1; select($previous_handle); +# keep track of whether to output messages +my $output_enabled = 1; + # read everything from stdin while(<>) { @@ -27,7 +30,20 @@ while(<>) { s/^\[[0-9.:-]+\]\[\s*\d+\]//; } - + + # look for a special marker to disable output + $output_enabled-- if /<-- Suspend Log Parsing -->/i; + # output the line - print $_; + if($output_enabled > 0) + { + print $_; + } + else + { + print "\n"; + } + + # look for a special marker to re-enable output + $output_enabled++ if /<-- Resume Log Parsing -->/i; } diff --git a/Engine/Build/Commit.gitdeps.xml b/Engine/Build/Commit.gitdeps.xml index 1182991f8c4a..df7c025c2c3d 100644 --- a/Engine/Build/Commit.gitdeps.xml +++ b/Engine/Build/Commit.gitdeps.xml @@ -5,10 +5,10 @@ - - + + - + @@ -24,12 +24,12 @@ - + - - + + @@ -102,14 +102,18 @@ - - + + + + + + @@ -155,6 +159,10 @@ + + + + @@ -1396,7 +1404,7 @@ - + @@ -1408,177 +1416,177 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2406,7 +2414,7 @@ - + @@ -2432,13 +2440,13 @@ - + - - - + + + - + @@ -2513,7 +2521,7 @@ - + @@ -2629,9 +2637,9 @@ - + - + @@ -3007,6 +3015,7 @@ + @@ -3022,6 +3031,7 @@ + @@ -3663,6 +3673,8 @@ + + @@ -5657,39 +5669,40 @@ - - - - - - + + + + + + - - - - - + + + + + - - - - + + + + + - - - - - - - - + + + + + + + + - - - - + + + + @@ -6145,10 +6158,12 @@ - + + + @@ -6177,9 +6192,9 @@ - - - + + + @@ -6633,11 +6648,11 @@ - + - + @@ -14540,66 +14555,66 @@ - - - + + + - - - - + + + + - - - + + + - - - - - - - + + + + + + + - - - + + + - - - - - - - + + + + + + + - - - - + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + @@ -14617,11 +14632,11 @@ - + - + @@ -14629,129 +14644,130 @@ - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + - - - + + + - + - + - + - - + + - - + + - + - + - + - + - - - - - + + + + + - - - + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - + + + + + - + + @@ -14968,6 +14984,7 @@ + @@ -14983,6 +15000,7 @@ + @@ -15221,8 +15239,8 @@ - - + + @@ -15503,9 +15521,9 @@ - - - + + + @@ -15547,9 +15565,9 @@ - + - + @@ -15564,8 +15582,8 @@ - - + + @@ -15575,9 +15593,9 @@ - - - + + + @@ -15591,9 +15609,9 @@ - - - + + + @@ -15611,33 +15629,33 @@ - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + @@ -15651,9 +15669,9 @@ - + - + @@ -15687,9 +15705,9 @@ - - - + + + @@ -15711,13 +15729,13 @@ - + - + - + @@ -15727,9 +15745,17 @@ - + - + + + + + + + + + @@ -15751,9 +15777,9 @@ - + - + @@ -15762,10 +15788,10 @@ - + - - + + @@ -15780,8 +15806,8 @@ - - + + @@ -15872,7 +15898,7 @@ - + @@ -15880,15 +15906,15 @@ - + - + - + - + @@ -15896,7 +15922,7 @@ - + @@ -15960,6 +15986,8 @@ + + @@ -18829,13 +18857,13 @@ - + - - - + + + @@ -24817,18 +24845,18 @@ - - - - - - + + + + + + - + @@ -24976,41 +25004,41 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -25112,7 +25140,7 @@ - + @@ -26549,47 +26577,47 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + @@ -26609,129 +26637,88 @@ - + - - + + - - - - - + + + + + - - + + - - + + - - + + - - + + - - + + - + - - + + - - + + - - + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - + + - - - - - + + + + + - - + + - - + + - - + + - - + + - - + + - + - - + + - - + + - - + + - - + + - + @@ -26814,183 +26801,171 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + @@ -27033,6 +27008,9 @@ + + + @@ -27077,6 +27055,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -27149,19 +27168,25 @@ - - - - - - - - - + + + + + + + + + + + + + + + @@ -27321,7 +27346,6 @@ - @@ -27337,7 +27361,6 @@ - @@ -27383,7 +27406,6 @@ - @@ -27530,7 +27552,7 @@ - + @@ -27538,14 +27560,14 @@ - - - - - - - - + + + + + + + + @@ -27568,6 +27590,18 @@ + + + + + + + + + + + + @@ -27580,6 +27614,18 @@ + + + + + + + + + + + + @@ -27592,6 +27638,18 @@ + + + + + + + + + + + + @@ -27604,6 +27662,12 @@ + + + + + + @@ -27628,6 +27692,18 @@ + + + + + + + + + + + + @@ -27715,6 +27791,18 @@ + + + + + + + + + + + + @@ -27739,12 +27827,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + @@ -27758,236 +27870,234 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -28749,8 +28859,12 @@ + + + + @@ -28758,8 +28872,12 @@ + + + + @@ -28956,7 +29074,15 @@ - + + + + + + + + + @@ -28973,7 +29099,7 @@ - + @@ -29207,16 +29333,16 @@ - - - - - + + + + + - - + + @@ -29287,24 +29413,24 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + @@ -29856,73 +29982,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -29955,42 +30014,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -30290,8 +30313,8 @@ - - + + @@ -30516,7 +30539,7 @@ - + @@ -30719,21 +30742,16 @@ - + - - - - - - - - - - - - - + + + + + + + + @@ -31704,14 +31722,14 @@ - - + + - + @@ -31760,90 +31778,102 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -31912,111 +31942,111 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -32044,331 +32074,331 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + @@ -32422,6 +32452,8 @@ + + @@ -32765,9 +32797,9 @@ - - - + + + @@ -34247,15 +34279,16 @@ - + + - + @@ -34264,19 +34297,17 @@ - - - + + - + - @@ -34285,6 +34316,7 @@ + @@ -34293,16 +34325,20 @@ + + + + - + @@ -34314,15 +34350,16 @@ - + - + - + + @@ -34332,28 +34369,26 @@ - + - + - + - - - + + - - + - + - + @@ -34362,12 +34397,13 @@ - - + + + @@ -34376,6 +34412,7 @@ + @@ -34384,12 +34421,13 @@ - - + + - + + - + @@ -34398,9 +34436,10 @@ - + + @@ -34409,12 +34448,12 @@ - - + + - + @@ -34422,24 +34461,25 @@ - + + - + + - + + - - @@ -34453,28 +34493,25 @@ - - + - + - - - - + + - + @@ -34483,12 +34520,13 @@ - + + @@ -34502,7 +34540,7 @@ - + @@ -34511,43 +34549,39 @@ - - + - - + - - + + - + - - + - - + @@ -34555,18 +34589,18 @@ - - + - + + @@ -34582,12 +34616,11 @@ - + - + - @@ -34599,11 +34632,12 @@ - + + - + - + @@ -34614,25 +34648,23 @@ - + - + - + - + - - - + - + @@ -34650,25 +34682,20 @@ - - - - - + + - - - + @@ -34683,11 +34710,10 @@ - + - @@ -34697,50 +34723,46 @@ - - + - + - - + - - + + - - + - - - - + + + - - + + @@ -34754,9 +34776,8 @@ - + - @@ -34765,17 +34786,19 @@ - + - + + + @@ -34786,21 +34809,23 @@ - + - + - - + + + + @@ -34811,13 +34836,14 @@ - - + + + - - + + @@ -34826,127 +34852,125 @@ - + + - - + - - - - + + + - - + - + - - + - + - - - + + + - + - + - + - - - + + - + - + + - - + + - + - - - - - + + + - + + + + @@ -34954,11 +34978,11 @@ + - @@ -34977,9 +35001,10 @@ - + + @@ -34989,46 +35014,44 @@ - - + - - + + - - + + - + - + - + - - + - + @@ -35043,26 +35066,24 @@ - + - - - + - + - + @@ -35071,9 +35092,9 @@ + - - + @@ -35084,68 +35105,65 @@ - - + - - - + + + + - + - - - + + + - - + - + - - + + - - + + - - - + - - + + @@ -35154,8 +35172,8 @@ - - + + @@ -35164,13 +35182,13 @@ - + - + @@ -35185,41 +35203,39 @@ + - + - - + - + - - + - - + @@ -35227,66 +35243,70 @@ + - + - + - - + - - + + + + - - + + - + - + + + - + + - + - @@ -35297,8 +35317,7 @@ - - + @@ -35321,29 +35340,26 @@ - + - - - - + + - + - - + - + @@ -35353,9 +35369,7 @@ - - @@ -35363,18 +35377,21 @@ - + - + + + - + + @@ -35383,9 +35400,9 @@ - + @@ -35402,9 +35419,10 @@ + - + @@ -35414,18 +35432,18 @@ + - + - @@ -35440,40 +35458,40 @@ - + + - - + - + + - + - + - - + @@ -35483,29 +35501,30 @@ + + - + - - + - + - + @@ -35516,7 +35535,6 @@ - @@ -35529,19 +35547,21 @@ + - + - + - + + - + @@ -35549,29 +35569,29 @@ - - - + - + + - + + - + - - + + - + @@ -35582,7 +35602,7 @@ - + @@ -35594,11 +35614,12 @@ - + + @@ -35606,21 +35627,24 @@ - - + + + + - + - + + @@ -35629,42 +35653,43 @@ + - + - + - + - - + + - + - + - + + - @@ -35672,30 +35697,29 @@ + - + - + - - + - - + @@ -35710,20 +35734,19 @@ - - - + + - - + + - + @@ -35738,7 +35761,6 @@ - @@ -35746,32 +35768,35 @@ + - - + + - + + + - + @@ -35780,36 +35805,38 @@ - + + - + - - + + + - + - + - + - - + + @@ -35819,6 +35846,7 @@ + @@ -35830,7 +35858,7 @@ - + @@ -35845,10 +35873,9 @@ - + - @@ -35860,7 +35887,7 @@ - + @@ -35870,7 +35897,7 @@ - + @@ -35879,25 +35906,24 @@ - + - + - + - + - + - @@ -35905,11 +35931,9 @@ - - + - - + @@ -35924,29 +35948,33 @@ - + - + + + + - - + + - + + - + @@ -35955,15 +35983,14 @@ - + - + - + - @@ -35978,22 +36005,21 @@ - + - - + + - + - - + - + @@ -36004,14 +36030,13 @@ - + - @@ -36023,9 +36048,9 @@ - + - + @@ -36033,28 +36058,35 @@ + + - - + + + + + + + @@ -36064,25 +36096,28 @@ + + + - - + + + - + - + - @@ -36095,42 +36130,42 @@ - - - + - + + + - - + + - + - + - + - + @@ -36146,9 +36181,10 @@ + + - @@ -36166,8 +36202,7 @@ - - + @@ -36178,26 +36213,25 @@ - - - + + + - - + + - + - @@ -36205,11 +36239,11 @@ - - - + + + - + @@ -36221,13 +36255,13 @@ - + - + @@ -36236,32 +36270,32 @@ - - - + + + - + - + + - @@ -36269,7 +36303,6 @@ - @@ -36277,25 +36310,26 @@ - + - + - - + - + + + - + @@ -36308,7 +36342,6 @@ - @@ -36319,47 +36352,49 @@ - + - + + - + + - - + - + - - - + + + + @@ -36367,10 +36402,8 @@ - - @@ -36383,34 +36416,39 @@ + - - + + + + + + - + - - - + + + - - + + @@ -36429,8 +36467,9 @@ + - + @@ -36442,48 +36481,47 @@ - - + + - - + - + + - - - + - - - + + + - + + @@ -36491,19 +36529,20 @@ - + - - + + + @@ -36511,9 +36550,9 @@ - + - + @@ -36523,9 +36562,9 @@ - + - + @@ -36533,6 +36572,7 @@ + @@ -36540,25 +36580,25 @@ - + + - - + - + @@ -36567,6 +36607,7 @@ + @@ -36587,8 +36628,9 @@ - + + @@ -36600,48 +36642,47 @@ - + - + - - + + + - - + - + - - - + + + - - + + - + - @@ -36654,10 +36695,9 @@ - + - @@ -36669,6 +36709,8 @@ + + @@ -36677,23 +36719,22 @@ - + - - - + + - + - + - + @@ -36701,21 +36742,18 @@ - - + - - - + @@ -36724,7 +36762,7 @@ - + @@ -36733,13 +36771,13 @@ - + - + - + - + @@ -36747,20 +36785,21 @@ - + - + - - + - + + + @@ -36773,18 +36812,21 @@ + + - + - + + @@ -36797,12 +36839,12 @@ - + + - @@ -36812,51 +36854,49 @@ - - - + - + + - + - + - + + + + - - - + - - + - - + @@ -36869,22 +36909,21 @@ + - + - - @@ -36896,7 +36935,7 @@ - + @@ -36906,14 +36945,17 @@ + + - + + @@ -36925,13 +36967,11 @@ + - - - @@ -36943,16 +36983,16 @@ - - + + - + @@ -36968,20 +37008,22 @@ - + + + + - - + @@ -36991,7 +37033,7 @@ - + @@ -36999,13 +37041,14 @@ + + - @@ -37016,30 +37059,29 @@ + - + - + - + - - + - @@ -37055,75 +37097,72 @@ - - + - - - + + + + - + - + + - - + - - + - + - - + - + - + - - + - - + + @@ -37132,24 +37171,23 @@ - + - + - + - + - - + @@ -37166,17 +37204,18 @@ - + + - + @@ -37189,22 +37228,19 @@ - + - - - @@ -37216,7 +37252,6 @@ - @@ -37238,7 +37273,7 @@ - + @@ -37248,7 +37283,8 @@ - + + @@ -37258,13 +37294,14 @@ + - + @@ -37275,8 +37312,9 @@ - + + @@ -37284,21 +37322,18 @@ - - + + - + - - + - - @@ -37307,7 +37342,7 @@ - + @@ -37317,24 +37352,18 @@ - - - - - + - - - - - + + + @@ -37343,11 +37372,11 @@ + - @@ -37355,8 +37384,9 @@ - + + @@ -37367,12 +37397,12 @@ - + - + @@ -37381,33 +37411,30 @@ - - - + + - - - - - + + - - - + + + + - + - + @@ -37423,27 +37450,30 @@ - + + + - + + - + - - + + @@ -37453,15 +37483,13 @@ - + - + - - @@ -37469,12 +37497,13 @@ + - - + + @@ -37484,14 +37513,13 @@ - - + @@ -37502,24 +37530,24 @@ - - + + - + - + - + - + @@ -37528,38 +37556,40 @@ - - + + - + - + - + - - + + + - + - + + @@ -37573,22 +37603,20 @@ - + - + - + - - + - @@ -37596,24 +37624,21 @@ - - - + + - + - - - + @@ -37630,14 +37655,16 @@ - + + + @@ -37646,22 +37673,20 @@ + - + - - + - + - - - + @@ -37669,18 +37694,17 @@ - + - + - @@ -37689,16 +37713,15 @@ - + - + - @@ -37706,16 +37729,17 @@ - + - + + - + @@ -37723,10 +37747,12 @@ + + + - @@ -37736,23 +37762,22 @@ - + - - + + - - + - + - + @@ -37764,15 +37789,14 @@ - - - + + - + @@ -37785,26 +37809,24 @@ - + - + - - + - - + @@ -37812,7 +37834,6 @@ - @@ -37826,35 +37847,35 @@ + + + + - - - - - - + + @@ -37869,17 +37890,19 @@ + + - - + + @@ -37888,6 +37911,7 @@ + @@ -37895,7 +37919,7 @@ - + @@ -37908,16 +37932,15 @@ + - - - + @@ -37930,16 +37953,14 @@ + - - - @@ -37952,30 +37973,34 @@ - + + + - + + + - + - + - + @@ -37984,7 +38009,7 @@ - + @@ -37993,7 +38018,6 @@ - @@ -38002,19 +38026,19 @@ - - + + @@ -38023,51 +38047,49 @@ - - - - + + + - + - - + - + - - + - + + - + - - + + @@ -38075,7 +38097,6 @@ - @@ -38089,11 +38110,13 @@ + - - + + + @@ -38111,7 +38134,6 @@ - @@ -38133,7 +38155,7 @@ - + @@ -38152,14 +38174,12 @@ - + - - @@ -38171,7 +38191,9 @@ - + + + @@ -38181,28 +38203,24 @@ + - - - + - - + - - @@ -38210,18 +38228,20 @@ - + + + - + @@ -38234,85 +38254,88 @@ + - + - + - - + - + + - + - - - - + + - + + - + + + - + - - + + - + + - + - + + - @@ -38321,8 +38344,8 @@ - - + + @@ -38335,31 +38358,27 @@ - - + - + - - + - + - + - + - - @@ -38375,7 +38394,6 @@ - @@ -38383,7 +38401,7 @@ - + @@ -38403,15 +38421,14 @@ - - + + - - + @@ -38423,18 +38440,20 @@ + - + - + + @@ -38443,10 +38462,12 @@ - + + - + + @@ -38457,16 +38478,14 @@ - + - - - + @@ -38475,11 +38494,12 @@ - + + @@ -38492,21 +38512,20 @@ - + + + - - - + - - + @@ -38517,24 +38536,27 @@ - - + + + + - + + - - - + + - + + @@ -38542,16 +38564,18 @@ + + - + - + @@ -38561,30 +38585,28 @@ - - + - - + - + - + - - + + @@ -38609,40 +38631,37 @@ - + - + - - + - + - - - - + + + - + - - + - + @@ -38652,11 +38671,13 @@ + + @@ -38667,14 +38688,14 @@ - + + - @@ -38687,14 +38708,15 @@ - + - - + + + @@ -38713,20 +38735,21 @@ + - + - + + - @@ -38734,8 +38757,10 @@ + + @@ -38747,20 +38772,20 @@ - + - + - + - - + + @@ -38772,11 +38797,8 @@ - - - - + @@ -38787,7 +38809,7 @@ - + @@ -38799,25 +38821,23 @@ - + - - + - - + - + @@ -38829,84 +38849,85 @@ - + - - + + - - + - - + - + - - + - + + + - + - + - + - + - - + + - + + + - + @@ -38922,7 +38943,6 @@ - @@ -38931,25 +38951,27 @@ + + - + - + - - + + @@ -38958,27 +38980,25 @@ - - + + - + - + - + - - @@ -38989,24 +39009,23 @@ - + + - - + - @@ -39020,55 +39039,53 @@ - + - + - + - + - + + - - - + + - + - + - + - - - - - + + + - + - + @@ -39077,15 +39094,14 @@ - - + @@ -39095,9 +39111,10 @@ + - + @@ -39114,10 +39131,11 @@ + - + @@ -39127,21 +39145,18 @@ - - - + + + - + - - - - + @@ -39151,15 +39166,13 @@ - + - - @@ -39170,25 +39183,25 @@ - + + - + - - + - + - + @@ -39196,12 +39209,12 @@ - + - + @@ -39213,32 +39226,29 @@ - + - - + + - - + - - - + - + - - + + @@ -39246,24 +39256,25 @@ - + + - + - + - + - + @@ -39272,48 +39283,49 @@ - - - + + - - + + + - + - + - + + - + - - + + @@ -39321,9 +39333,8 @@ - - + @@ -39331,7 +39342,7 @@ - + @@ -39344,8 +39355,9 @@ + - + @@ -39354,7 +39366,6 @@ - @@ -39363,7 +39374,7 @@ - + @@ -39372,28 +39383,33 @@ + + + - + - + + + - - + + @@ -39402,11 +39418,9 @@ - + - - @@ -39418,12 +39432,11 @@ - - + @@ -39436,6 +39449,7 @@ + @@ -39446,16 +39460,14 @@ - + - + - - @@ -39464,9 +39476,9 @@ - + - + @@ -39475,17 +39487,15 @@ - - - + - - + + @@ -39494,14 +39504,15 @@ + + - @@ -39510,16 +39521,14 @@ - + - - @@ -39531,56 +39540,59 @@ - + - - + + + + + - + - + - - + - + + - - + + @@ -39591,8 +39603,8 @@ + - @@ -39601,23 +39613,25 @@ - + - + - - + + + + @@ -39625,30 +39639,29 @@ - - + - - + - + + - + @@ -39656,11 +39669,11 @@ - + - - - + + + @@ -39670,57 +39683,55 @@ + - + + - - - + + + - - - + + + - - + - + - - - - + @@ -39735,7 +39746,7 @@ - + @@ -39747,43 +39758,43 @@ - + - - + - + - + + - - + + - + - + @@ -39792,8 +39803,7 @@ - - + @@ -39803,12 +39813,11 @@ - - + - + @@ -39825,10 +39834,9 @@ - - + @@ -39837,34 +39845,40 @@ - + - - + + + - + - + + + - + + + + @@ -39879,23 +39893,22 @@ - - + - + - + @@ -39903,15 +39916,14 @@ - + - - + @@ -39919,21 +39931,20 @@ - + - + - - + @@ -39948,14 +39959,16 @@ - + + + - + @@ -39974,43 +39987,45 @@ - + - + - - + - + - + + + - + + @@ -40021,54 +40036,57 @@ + - + + - + + - - + + + - - + - + - + + - - + + - @@ -40086,12 +40104,10 @@ - - - + + - @@ -40102,7 +40118,7 @@ - + @@ -40111,7 +40127,6 @@ - @@ -40125,7 +40140,7 @@ - + @@ -40147,12 +40162,13 @@ + + - @@ -40170,18 +40186,15 @@ - + - - - @@ -40193,22 +40206,22 @@ + - - - + - + + @@ -40222,63 +40235,67 @@ - - - + + + - + - + - + + - + + + - + - - + + - - + + + - + - + @@ -40291,13 +40308,13 @@ - - + + @@ -40316,25 +40333,24 @@ - + - + - + - - + @@ -40344,8 +40360,8 @@ - - + + @@ -40353,20 +40369,20 @@ - + - - + + @@ -40377,10 +40393,9 @@ - - - + + @@ -40400,21 +40415,22 @@ + - + - + - + - - + + @@ -40428,6 +40444,7 @@ + @@ -40438,22 +40455,20 @@ - + - + - + - - - + @@ -40462,45 +40477,41 @@ - + - - - + + - - + - - + - - + - + - + @@ -40509,40 +40520,40 @@ - + - + - + + - + - - + @@ -40550,41 +40561,40 @@ - - + + - + - + + - + - - - - + - - + + + @@ -40593,11 +40603,11 @@ - - - + + + @@ -40618,26 +40628,25 @@ - + - + + - - + - - + - + - + @@ -40648,49 +40657,46 @@ - + + - - - - + + - + + - - + - + - - @@ -40701,7 +40707,9 @@ + + @@ -40723,10 +40731,13 @@ + + + @@ -40747,20 +40758,21 @@ - - + + + @@ -40779,16 +40791,16 @@ - + - - + - + + @@ -40799,13 +40811,12 @@ - - + @@ -40818,19 +40829,19 @@ - + - + - + - + @@ -40853,20 +40864,20 @@ - + - + - + - + - + @@ -40879,11 +40890,11 @@ - + - + - + @@ -40901,30 +40912,28 @@ - + + - + - - + - + - - @@ -40938,12 +40947,12 @@ - + @@ -40957,13 +40966,12 @@ - + - @@ -40971,7 +40979,7 @@ - + @@ -40979,20 +40987,20 @@ - + + - + - - - + + @@ -41006,10 +41014,12 @@ + + @@ -41019,41 +41029,43 @@ - + + - + + - - + + - + - + - - + + @@ -41065,27 +41077,25 @@ - + - + - + - + - - @@ -41094,34 +41104,34 @@ - - + + + - + - - + - + - + @@ -41130,10 +41140,8 @@ - - @@ -41143,6 +41151,7 @@ + @@ -41156,16 +41165,18 @@ + + - + @@ -41174,14 +41185,15 @@ + - + - + @@ -41190,7 +41202,7 @@ - + @@ -41200,6 +41212,7 @@ + @@ -41210,12 +41223,12 @@ - - - + + + - + @@ -41224,6 +41237,7 @@ + @@ -41242,19 +41256,17 @@ - + - - + + - + - - @@ -41263,9 +41275,9 @@ - + - + @@ -41276,29 +41288,30 @@ - - + - + - + - - + + + + @@ -41306,7 +41319,6 @@ - @@ -41326,7 +41338,7 @@ - + @@ -41342,39 +41354,40 @@ - + - - + - + - - + + + + @@ -41386,63 +41399,63 @@ - + + - + - + - + - - + - + - + - + + - - - + - + + - - - + + + + - + - + - @@ -41450,33 +41463,37 @@ - + + + + - + + - + @@ -41485,22 +41502,26 @@ - + + + + - + - + + @@ -41511,11 +41532,12 @@ - + + - + @@ -41523,13 +41545,13 @@ - + - + @@ -41541,26 +41563,27 @@ + - + + - - + - + @@ -41568,7 +41591,6 @@ - @@ -41577,9 +41599,8 @@ - - + @@ -41588,61 +41609,60 @@ + - + - - + - + + + - + - + + - - + - - - - + + - + - - + @@ -41650,17 +41670,21 @@ + + - - + + + + + - + - @@ -41671,9 +41695,9 @@ - + - + @@ -41681,7 +41705,9 @@ - + + + @@ -41693,11 +41719,9 @@ - - + - - + @@ -41705,14 +41729,12 @@ - - - - + + - + @@ -41725,22 +41747,19 @@ - - - + - @@ -41756,28 +41775,24 @@ - - - - + + - + - + - - + - @@ -41785,16 +41800,14 @@ - - + - @@ -41808,27 +41821,24 @@ - - + + - - - + + - - + - - - + + @@ -41838,10 +41848,10 @@ - + @@ -41850,12 +41860,12 @@ - + - + @@ -41868,10 +41878,11 @@ - + + @@ -41879,6 +41890,7 @@ + @@ -41886,9 +41898,7 @@ - - @@ -41900,21 +41910,21 @@ - + - - + - + + @@ -41924,8 +41934,9 @@ + - + @@ -41934,32 +41945,33 @@ - - + + - + - - + + - + + + - - + @@ -41967,7 +41979,7 @@ - + @@ -41983,16 +41995,15 @@ - - + - + @@ -42000,10 +42011,11 @@ - + + @@ -42017,24 +42029,22 @@ - - + + - - + - @@ -42045,31 +42055,26 @@ - - - - + - - - - + + @@ -42080,15 +42085,14 @@ - + - + - - + @@ -42105,36 +42109,34 @@ - - + + - - + - - + - + @@ -42149,30 +42151,31 @@ - + - + - + + - + + - - + + - - + + - @@ -42182,7 +42185,6 @@ - @@ -42194,66 +42196,69 @@ - - - + + - - - + + + - - + - + - + + + + - + - + - + - + + - + - + + - + + - + - @@ -42269,27 +42274,29 @@ - + + - - + + - + + - + @@ -42299,14 +42306,16 @@ + + - + - + @@ -42315,17 +42324,21 @@ + - + + + + - + @@ -42338,41 +42351,44 @@ - + + - + - + - + + - - + + + + - + - @@ -42381,17 +42397,18 @@ - - + + - + - + + @@ -42407,15 +42424,16 @@ - - + + + - - + + @@ -42431,28 +42449,29 @@ - - + + - + + - - + - + - + + @@ -42465,25 +42484,25 @@ + - - + - - + + + - @@ -42493,7 +42512,7 @@ - + @@ -42501,30 +42520,28 @@ - + - - - + - - + - + + @@ -42546,7 +42563,7 @@ - + @@ -42555,7 +42572,7 @@ - + @@ -42571,7 +42588,6 @@ - @@ -42580,9 +42596,11 @@ + - + + @@ -42596,26 +42614,25 @@ + - - + - - + - + @@ -42623,31 +42640,28 @@ - - - - + - - + - + + @@ -42658,7 +42672,6 @@ - @@ -42675,52 +42688,49 @@ + - - - - + + - + - + - + - + - - - + - - + + @@ -42728,9 +42738,8 @@ - - + @@ -42740,7 +42749,6 @@ - @@ -42751,35 +42759,33 @@ - + - - - + + - + - + - + - @@ -42788,55 +42794,57 @@ - + - + - + - + - - + - - + + - - + - + - - - + + + + - + + - + - - - + + + + + @@ -42845,10 +42853,10 @@ - + - + @@ -42868,62 +42876,66 @@ - + - + - + - + - + - + + - + - + - + + - + + - - + + + @@ -42935,11 +42947,10 @@ - + - @@ -42955,42 +42966,43 @@ + - + - + - - + + - + - + + - - + - - + + - + @@ -42999,23 +43011,24 @@ + - + - - + + - + @@ -43027,12 +43040,12 @@ - + - + @@ -43041,11 +43054,11 @@ - + - + @@ -43056,11 +43069,12 @@ + - + @@ -43073,9 +43087,11 @@ - + + + @@ -43090,7 +43106,7 @@ - + @@ -43098,17 +43114,17 @@ - - + - + + - + @@ -43118,22 +43134,21 @@ - + + - - - + + - - + @@ -43145,7 +43160,7 @@ - + @@ -43155,10 +43170,10 @@ - + + - @@ -43179,29 +43194,29 @@ - + + - - + + - - + + - - + @@ -43211,7 +43226,7 @@ - + @@ -43222,16 +43237,16 @@ - + + - - + - + @@ -43246,6 +43261,7 @@ + @@ -43253,42 +43269,43 @@ - + - + + - + + - + + + - - - @@ -43299,20 +43316,19 @@ - + - - - + + @@ -43320,35 +43336,32 @@ - - - + - + - + - + - + - - - + + - + @@ -43356,14 +43369,14 @@ - + - + - + @@ -43374,48 +43387,55 @@ - + + - + - - + + - + + - + - - + + - + + + - + - + + - + + + @@ -43424,24 +43444,21 @@ - - - + - - + - + @@ -43457,6 +43474,7 @@ + @@ -43465,9 +43483,11 @@ + + - + @@ -43476,11 +43496,10 @@ - + - @@ -43493,7 +43512,6 @@ - @@ -43502,79 +43520,77 @@ + - - + - - + - - + - - + + - + - - + - - + + + - + + - + + - + - - @@ -43586,22 +43602,20 @@ - - - + + - - + @@ -43612,50 +43626,47 @@ - - + + - + - + - + - + - + - + - - + - - + - + - + - - + @@ -43669,12 +43680,11 @@ - - + - + @@ -43688,9 +43698,9 @@ + - @@ -43698,21 +43708,20 @@ - + - + - + - + - - + - + @@ -43727,26 +43736,25 @@ - + - - - + - + + - + - + @@ -43754,13 +43762,13 @@ + - - + @@ -43770,91 +43778,97 @@ + + - + - + - + - + + - + + - + + + - + - + - + + - + - - + - + + - + - + - - + - + - + @@ -43867,7 +43881,7 @@ - + @@ -43879,17 +43893,15 @@ - - + - @@ -43899,7 +43911,9 @@ - + + + @@ -43917,11 +43931,10 @@ - - - + + @@ -43935,7 +43948,6 @@ - @@ -43943,22 +43955,25 @@ - + - - + + + + + @@ -43966,19 +43981,19 @@ - - - - + + - + + + - + @@ -43991,6 +44006,7 @@ + @@ -43998,6 +44014,8 @@ + + @@ -44006,31 +44024,30 @@ - - + + + - + - + - + - - + - @@ -44038,6 +44055,7 @@ + @@ -44045,10 +44063,11 @@ + - + - + @@ -44056,22 +44075,22 @@ - + + - + - + - + - @@ -44079,23 +44098,24 @@ - - + - + + - - - + + + - + + @@ -44104,6 +44124,7 @@ + @@ -44116,7 +44137,7 @@ - + @@ -44124,23 +44145,21 @@ - - + - - - + + + - + - @@ -44148,29 +44167,29 @@ - - + + - + - + - + - + @@ -44186,7 +44205,6 @@ - @@ -44195,6 +44213,7 @@ + @@ -44203,7 +44222,8 @@ - + + @@ -44212,22 +44232,21 @@ - - + + - + - - + @@ -44263,29 +44282,31 @@ + - + - + + + - @@ -44297,13 +44318,13 @@ + - @@ -44316,45 +44337,46 @@ - - - + + - + - - + + + - + - + + @@ -44363,21 +44385,22 @@ - + + - - + + @@ -44387,14 +44410,15 @@ + - - + - + + @@ -44402,24 +44426,22 @@ - + - + - - + - - + @@ -44434,58 +44456,58 @@ - - + + + + - + - - - - + - + - + - + + @@ -44498,89 +44520,87 @@ - + - + - + + - + + - - + - - - - + + + + + - + - - - - - - + + + - - + - - + - + - + + @@ -44588,6 +44608,7 @@ + @@ -44595,12 +44616,14 @@ + + - + - + @@ -44610,42 +44633,41 @@ - + - + - - - + + - + + - - + + - @@ -44654,40 +44676,39 @@ - + - + + - - + - + + - - + - @@ -44695,20 +44716,21 @@ - + - - + + - + + - + @@ -44719,8 +44741,10 @@ - + + + @@ -44728,7 +44752,6 @@ - @@ -44738,19 +44761,18 @@ - - + + - - + + - + - + - - + @@ -44765,7 +44787,6 @@ - @@ -44775,9 +44796,10 @@ + - + @@ -44789,25 +44811,24 @@ - - - + + - + - + @@ -44820,7 +44841,6 @@ - @@ -44829,26 +44849,26 @@ - - + - + - + - + + - + - + @@ -44856,13 +44876,13 @@ - + - + @@ -44874,10 +44894,10 @@ - + - + @@ -44888,7 +44908,7 @@ - + @@ -44897,7 +44917,6 @@ - @@ -44906,7 +44925,7 @@ - + @@ -44916,35 +44935,33 @@ - + - + - + - + - - + - @@ -44959,11 +44976,9 @@ - - - + @@ -44972,22 +44987,20 @@ - + - - + - - + @@ -44998,45 +45011,44 @@ - + - - - + + - + - + - - + + + - + - @@ -45046,11 +45058,12 @@ + - + @@ -45058,16 +45071,20 @@ + - + + - + + + @@ -45075,8 +45092,8 @@ - - + + @@ -45084,6 +45101,7 @@ + @@ -45097,10 +45115,11 @@ - + + @@ -45109,56 +45128,57 @@ - + - + - + - - - + - + + - - + + + + - + - + - + @@ -45176,16 +45196,17 @@ - + + - + - + @@ -45195,7 +45216,7 @@ - + @@ -45205,38 +45226,42 @@ - - + + + - + - + - - + + - + + + + @@ -45245,7 +45270,6 @@ - @@ -45254,7 +45278,6 @@ - @@ -45264,11 +45287,10 @@ - + - @@ -45276,11 +45298,10 @@ - - + - + @@ -45300,50 +45321,51 @@ - + - - - + + + + - - - + + - + - + + - + - + - - - + + + @@ -45356,13 +45378,12 @@ - - + @@ -45370,18 +45391,17 @@ - - + + - @@ -45391,23 +45411,23 @@ - + - - + + @@ -45424,11 +45444,10 @@ - - + + - - + @@ -45438,16 +45457,16 @@ + - + - - + @@ -45467,25 +45486,25 @@ + + - - - + @@ -45493,11 +45512,9 @@ - - @@ -45507,26 +45524,24 @@ + - - + - + - - + - @@ -45534,43 +45549,43 @@ + - + - + + - - + - - + - + @@ -45579,7 +45594,6 @@ - @@ -45590,8 +45604,8 @@ - - + + @@ -45601,25 +45615,26 @@ - + + - - + - + - - + + - - + + + @@ -45631,9 +45646,10 @@ - + - + + @@ -45642,30 +45658,28 @@ - + - + - - + - + - - - + + + - - + @@ -45674,11 +45688,13 @@ + + @@ -45691,16 +45707,17 @@ - + - - + + + - + @@ -45709,8 +45726,7 @@ - - + @@ -45722,17 +45738,15 @@ - - - - + + - + - + - + @@ -45748,16 +45762,18 @@ - - + - + + + + @@ -45773,14 +45789,17 @@ + + - + + @@ -45788,7 +45807,7 @@ - + @@ -45796,6 +45815,7 @@ + @@ -45810,29 +45830,29 @@ + + - + - - - + + - + - @@ -45840,30 +45860,27 @@ - - - - + - - + + - + - + @@ -45875,50 +45892,48 @@ - - - + - - - + + - - - + + + + - + - + - + @@ -45934,7 +45949,6 @@ - @@ -45950,16 +45964,17 @@ - + + - + @@ -45974,21 +45989,22 @@ - + + - + + - + - + - @@ -45998,25 +46014,23 @@ - + - - + - + - @@ -46030,8 +46044,7 @@ - - + @@ -46040,7 +46053,6 @@ - @@ -46050,6 +46062,7 @@ + @@ -46057,27 +46070,25 @@ - + - - + - + - - + + - - + @@ -46087,11 +46098,12 @@ - + + @@ -46099,11 +46111,12 @@ + + - @@ -46116,8 +46129,7 @@ - - + @@ -46125,7 +46137,6 @@ - @@ -46140,45 +46151,45 @@ - - - + + - - + + - - - + + - - + + - + - + + + @@ -46186,30 +46197,32 @@ + - - + - + + - + - + + @@ -46222,9 +46235,9 @@ + - @@ -46255,14 +46268,12 @@ - - @@ -46281,8 +46292,7 @@ - - + @@ -46292,7 +46302,8 @@ - + + @@ -46301,13 +46312,13 @@ - + - + @@ -46323,12 +46334,11 @@ - + - - - - + + + @@ -46341,6 +46351,7 @@ + @@ -46350,38 +46361,37 @@ - + - - - + + - + - + - + - - + + @@ -46389,22 +46399,21 @@ - + + - + - + - - @@ -46415,51 +46424,52 @@ - + - + - + - + - - - + + + + - - + + - - + + - - + + @@ -46468,48 +46478,53 @@ + - + + - + + - + + + - + - + - - - - - + + + + - + + @@ -46518,46 +46533,47 @@ - - + + + - + + + - - + + - - + - + - - + @@ -46571,29 +46587,30 @@ + - - + + - + - - + + - + - + + + - - @@ -46606,11 +46623,11 @@ - + + - - + @@ -46618,6 +46635,7 @@ + @@ -46632,14 +46650,14 @@ - + - + @@ -46655,7 +46673,6 @@ - @@ -46663,7 +46680,7 @@ - + @@ -46676,8 +46693,7 @@ - - + @@ -46689,14 +46705,12 @@ - - + + - - - + @@ -46712,7 +46726,7 @@ - + @@ -46723,18 +46737,19 @@ + - + - + - + @@ -46746,8 +46761,8 @@ - - + + @@ -46757,13 +46772,14 @@ + - - + + @@ -46772,9 +46788,11 @@ - - + + + + @@ -46783,46 +46801,47 @@ - - - + - - + + - + + - + + - + + @@ -46830,12 +46849,11 @@ - - + @@ -46843,17 +46861,17 @@ - + - + - + @@ -46863,9 +46881,9 @@ - + - + @@ -46880,31 +46898,33 @@ - + - + - + + - + - + - + - - + + + @@ -46916,70 +46936,71 @@ - - + + - + - - + - - - + + - + - - - + + + - - + + - - + + + - + - + - + + - + + - + @@ -46987,7 +47008,6 @@ - @@ -46996,10 +47016,10 @@ - + - + @@ -47015,7 +47035,7 @@ - + @@ -47031,16 +47051,15 @@ - + - + - - + - + @@ -47048,15 +47067,17 @@ - - + + - + + + @@ -47065,44 +47086,46 @@ - - - + + - + + - + + - + - + - - + + + - - + + @@ -47118,52 +47141,46 @@ - + - - - - + - - - - + - + - + @@ -47173,16 +47190,13 @@ + - - - - - + @@ -47199,23 +47213,23 @@ - - + - + + - + + - @@ -47224,7 +47238,7 @@ - + @@ -47235,9 +47249,10 @@ - + + @@ -47246,12 +47261,10 @@ - - + - @@ -47270,34 +47283,33 @@ - - + - + - + - - - + + + - - + + @@ -47307,27 +47319,29 @@ - + + + - + - + - - + + - + - + @@ -47341,7 +47355,6 @@ - @@ -47350,35 +47363,35 @@ - - - + + + - + - - + + - - + + - + - + - + @@ -47386,18 +47399,16 @@ - - - + @@ -47408,8 +47419,7 @@ - - + @@ -47419,56 +47429,52 @@ - - + - + - + + - + - - - - + - + + + - - - - + @@ -47479,16 +47485,15 @@ - + - - + @@ -47502,31 +47507,35 @@ + - + + - + + - - + + + @@ -47538,7 +47547,7 @@ - + @@ -47549,8 +47558,8 @@ - - + + @@ -47558,13 +47567,14 @@ + - + @@ -47572,31 +47582,32 @@ - + - - + + - + - - - + - - + + + + + @@ -47604,34 +47615,34 @@ - + - + - - + + - + - - + + @@ -47642,18 +47653,18 @@ - + + + - - @@ -47661,7 +47672,6 @@ - @@ -47674,9 +47684,9 @@ + - @@ -47689,38 +47699,43 @@ - - - - + + + + - + - - + + + + - + + + + - + - + @@ -47728,7 +47743,6 @@ - @@ -47737,11 +47751,12 @@ + - - + + @@ -47752,32 +47767,37 @@ + - + + + + - + - + - + + @@ -47792,8 +47812,7 @@ - - + @@ -47802,15 +47821,17 @@ + - + + @@ -47823,10 +47844,9 @@ - - + @@ -47839,25 +47859,29 @@ + + + - + - + + - - + + @@ -47873,27 +47897,28 @@ + - + - + + - - + - + @@ -47901,65 +47926,67 @@ - - + + + - + - + - + - + - + + - + + - - + - + @@ -47969,11 +47996,12 @@ + - + @@ -47981,29 +48009,29 @@ - + + - + - - + @@ -48013,35 +48041,34 @@ + - - - - + - - + - + + + @@ -48059,6 +48086,7 @@ + @@ -48068,10 +48096,11 @@ - + - + + @@ -48084,52 +48113,48 @@ - - - + - - + - + - + - - + + - + - @@ -48138,13 +48163,14 @@ + - + @@ -48153,23 +48179,22 @@ - - + + - + - @@ -48177,6 +48202,7 @@ + @@ -48192,79 +48218,72 @@ - - + - + + + - + - - + - - - - - + - + - + - + - - - + - + - @@ -48272,53 +48291,50 @@ - - - + + - - + - + - - - + + + - + - - + - + - + - + - + @@ -48336,12 +48352,11 @@ - + - - + + - @@ -48356,25 +48371,22 @@ - + - + - + - - - + - @@ -48394,11 +48406,9 @@ - - - + @@ -48408,10 +48418,11 @@ - + + @@ -48423,33 +48434,33 @@ + - - - + - - + - + - + + - + + @@ -48463,33 +48474,34 @@ - + - + + - + - + - + - + - + @@ -48499,19 +48511,16 @@ - - + - - - - + + @@ -48528,6 +48537,7 @@ + @@ -48539,21 +48549,21 @@ - - + - + + @@ -48565,10 +48575,8 @@ - - @@ -48577,43 +48585,43 @@ - + + - + + - - - + - + - + - + - + @@ -48628,7 +48636,8 @@ - + + @@ -48648,15 +48657,13 @@ - - - + @@ -48665,7 +48672,7 @@ - + @@ -48685,47 +48692,54 @@ - + + - + + + + - + + - + - - + + + + @@ -48737,25 +48751,26 @@ + - - + + - + - - + + - + @@ -48763,47 +48778,48 @@ - + + - - - + + - + + - - + - + + - + @@ -48817,13 +48833,13 @@ - + - - - + + + @@ -48831,19 +48847,18 @@ - + - + - - + @@ -48853,7 +48868,7 @@ - + @@ -48863,19 +48878,18 @@ - - + - + - - + + @@ -48886,30 +48900,29 @@ - - + - + - - + + - + @@ -48918,8 +48931,9 @@ - - + + + @@ -48927,14 +48941,13 @@ - + - @@ -48945,7 +48958,7 @@ - + @@ -48954,18 +48967,18 @@ - + - + + - @@ -48974,7 +48987,7 @@ - + @@ -48983,6 +48996,7 @@ + @@ -48992,9 +49006,8 @@ - + - @@ -49005,9 +49018,9 @@ - + - + @@ -49021,17 +49034,18 @@ - + - + - + + @@ -49040,15 +49054,15 @@ - + - + - + - + @@ -49063,18 +49077,15 @@ - - - + - - + @@ -49084,7 +49095,7 @@ - + @@ -49093,71 +49104,73 @@ + + - + - + - + + - - + - + - - + - + - + - + - - + + + - - + + - + - + @@ -49172,10 +49185,10 @@ - + - + @@ -49183,18 +49196,20 @@ - - + + - + + + - + - + @@ -49204,8 +49219,7 @@ - - + @@ -49224,13 +49238,14 @@ + - + @@ -49244,21 +49259,21 @@ - + - + - - + - + + @@ -49268,37 +49283,34 @@ - - + + + + - - - - + + - - - + - @@ -49308,29 +49320,29 @@ + - + - + - + - - + @@ -49339,11 +49351,12 @@ - + + - - + + @@ -49360,28 +49373,28 @@ - - + - + - + - - + + - + - - + + + @@ -49400,15 +49413,17 @@ + - + + - + @@ -49416,6 +49431,7 @@ + @@ -49426,6 +49442,7 @@ + @@ -49433,17 +49450,16 @@ - - - + + - + @@ -49454,6 +49470,7 @@ + @@ -49463,7 +49480,7 @@ - + @@ -49472,61 +49489,66 @@ + - + + - + - + - + - + + + + + - + - + - - + + + - - @@ -49535,11 +49557,9 @@ - - @@ -49552,9 +49572,9 @@ + - @@ -49564,33 +49584,32 @@ - + - - - + + + - + + - - @@ -49600,28 +49619,25 @@ - - - + - + - + - + - - + @@ -49630,27 +49646,28 @@ - + + - - + + - + - + - + - - + + @@ -49662,23 +49679,25 @@ - + + + - + - + @@ -49695,34 +49714,34 @@ - + + + - + - + - + - + - - - - + - + + @@ -49736,14 +49755,14 @@ - - - + + + - + @@ -49752,11 +49771,12 @@ + - + @@ -49769,21 +49789,22 @@ + - - - + + - + + - + @@ -49799,37 +49820,38 @@ - - + + + - + - + + - + - + - - + - + @@ -49837,29 +49859,29 @@ + - + - - - - + + + + - - + @@ -49871,22 +49893,19 @@ - - - - + + - - - + + @@ -49896,15 +49915,15 @@ - - - + + + @@ -49912,24 +49931,25 @@ - + - - - + + - + + + @@ -49939,19 +49959,17 @@ - - - - + + + + - - @@ -49959,6 +49977,7 @@ + @@ -49972,8 +49991,9 @@ + - + @@ -49981,14 +50001,14 @@ - + - + @@ -49996,63 +50016,65 @@ + + - + - + - + - + - + - + - + - - + - + + - + @@ -50060,36 +50082,40 @@ - - + + + + - + + - - + + - + + - + @@ -50097,39 +50123,37 @@ - + - + - + + - + - + - - - - - + + - + @@ -50139,28 +50163,26 @@ - + - - - + + - - - + - - + + + @@ -50173,13 +50195,14 @@ + + - - + @@ -50190,30 +50213,31 @@ - - + + - - - + + + + - + - + - + @@ -50231,12 +50255,13 @@ - + - + + @@ -50251,32 +50276,34 @@ - + - + - + - - + + + - + + @@ -50293,12 +50320,11 @@ - + - @@ -50310,13 +50336,13 @@ - + - + - - + + @@ -50325,6 +50351,7 @@ + @@ -50332,12 +50359,12 @@ + - - + @@ -50348,7 +50375,8 @@ - + + @@ -50360,19 +50388,16 @@ - - - + - @@ -50382,10 +50407,10 @@ + - - + @@ -50401,8 +50426,8 @@ - + @@ -50413,14 +50438,16 @@ - + + + @@ -50429,38 +50456,40 @@ + - + - - - + - - + + - + + + + - + @@ -50475,7 +50504,6 @@ - @@ -50484,6 +50512,7 @@ + @@ -50491,7 +50520,7 @@ - + @@ -50502,12 +50531,12 @@ - + - + - + @@ -50519,7 +50548,6 @@ - @@ -50528,6 +50556,7 @@ + @@ -50537,13 +50566,13 @@ - + - + @@ -50563,13 +50592,12 @@ - + - - + @@ -50578,6 +50606,7 @@ + @@ -50593,8 +50622,8 @@ + - @@ -50605,11 +50634,10 @@ - + - - + @@ -50619,6 +50647,7 @@ + @@ -50628,7 +50657,7 @@ - + @@ -50641,10 +50670,9 @@ - - + @@ -50653,7 +50681,7 @@ - + @@ -50666,34 +50694,30 @@ - - - + - - + - - + - + @@ -50705,10 +50729,12 @@ + + @@ -50723,11 +50749,11 @@ - + - + @@ -50745,6 +50771,7 @@ + @@ -50754,21 +50781,21 @@ - - + + - + - + - + @@ -50791,25 +50818,23 @@ - + - + - - + + - - @@ -50821,30 +50846,28 @@ - + - - + - - + + + - + - - + - + - @@ -50860,28 +50883,25 @@ - + - - + - - + + - - - + + - @@ -50894,7 +50914,6 @@ - @@ -50903,49 +50922,47 @@ - - - - - - + + + + - + - - + + - + + - - + - + @@ -50961,24 +50978,25 @@ + - - + - - + + + - + @@ -50986,18 +51004,17 @@ - - + - + - + @@ -51006,32 +51023,36 @@ - - + + + + + + - + + - @@ -51039,7 +51060,7 @@ - + @@ -51056,34 +51077,32 @@ - + - + + - - - + - + - @@ -51093,36 +51112,36 @@ - + - + - - + - + - - + + - + + @@ -51130,14 +51149,15 @@ + - + - + @@ -51146,29 +51166,26 @@ - - - + - - - + + - - + + @@ -51182,16 +51199,15 @@ - + - - + - + @@ -51203,7 +51219,7 @@ - + @@ -51216,7 +51232,7 @@ - + @@ -51235,21 +51251,23 @@ + + - + - - + + - + @@ -51266,27 +51284,27 @@ - + + - - + - - + + @@ -51295,17 +51313,17 @@ - + - + - + @@ -51314,22 +51332,21 @@ - + - - + + - + - + - @@ -51337,14 +51354,14 @@ - - - + + + - - + + @@ -51376,18 +51393,20 @@ - + - + + + @@ -51398,14 +51417,15 @@ - + + - + - + @@ -51417,12 +51437,13 @@ - + - + + @@ -51431,9 +51452,9 @@ - + - + @@ -51442,20 +51463,19 @@ + - + - - @@ -51471,8 +51491,7 @@ - - + @@ -51483,14 +51502,14 @@ - + - - + + - + @@ -51500,35 +51519,34 @@ - + + - - + - - + + - - + - + - - + + @@ -51536,7 +51554,7 @@ - + @@ -51549,23 +51567,22 @@ - + - + - + - @@ -51575,10 +51592,9 @@ - - + @@ -51590,26 +51606,26 @@ + - + + + - - - + - + - @@ -51622,6 +51638,7 @@ + @@ -51636,26 +51653,24 @@ - + - + - - + - + - + - @@ -51667,33 +51682,28 @@ - - - + - - + - - + - + - + - + - @@ -51707,9 +51717,10 @@ - - + + + @@ -51720,31 +51731,31 @@ - + - - + + - + + - @@ -51756,33 +51767,35 @@ - + + - + + + - - + - - + + @@ -51793,14 +51806,13 @@ - + - - + @@ -51808,9 +51820,8 @@ - + - @@ -51823,46 +51834,47 @@ - + - + - + + - + + + - + + + - - - - @@ -51880,18 +51892,19 @@ - + + - + @@ -51904,13 +51917,15 @@ - + + + - + @@ -51920,29 +51935,28 @@ - - + - + + - - + @@ -51962,36 +51976,37 @@ + - - + + + - - - + + + - - + - + @@ -52005,25 +52020,24 @@ + - + + - - + + - - - - + @@ -52036,7 +52050,7 @@ - + @@ -52044,15 +52058,16 @@ - + + - - + + @@ -52061,31 +52076,31 @@ + + - - + - + - + - - + - + @@ -52095,18 +52110,18 @@ - + - + - + @@ -52114,25 +52129,25 @@ - + - + - - + - + - - + + - + + + - @@ -52152,12 +52167,13 @@ - + - + + @@ -52168,23 +52184,21 @@ - - + - - + + + - - - + @@ -52207,6 +52221,7 @@ + @@ -52218,13 +52233,13 @@ - + + - - + @@ -52233,11 +52248,12 @@ - + + @@ -52251,22 +52267,24 @@ - + - + + + - + - + - + @@ -52275,25 +52293,24 @@ - - + + + - - + + - - + - - + - + @@ -52306,16 +52323,16 @@ - - + + @@ -52338,12 +52355,15 @@ + + - - + + + @@ -52351,9 +52371,8 @@ - - - + + @@ -52369,20 +52388,21 @@ - + - + + + - @@ -52397,16 +52417,16 @@ + - + + - - - + @@ -52418,9 +52438,11 @@ + + @@ -52433,53 +52455,56 @@ - - + - + + + + - + - + - + + - - + + - + - + - + @@ -52488,13 +52513,11 @@ - - - + @@ -52506,29 +52529,27 @@ - + + - + - + - - - - + + - @@ -52550,22 +52571,25 @@ - + - + + + - + - + + @@ -52574,7 +52598,6 @@ - @@ -52591,7 +52614,7 @@ - + @@ -52600,17 +52623,15 @@ - + - + - - - - - - - + + + + + @@ -52620,28 +52641,27 @@ - + - - + - - + + @@ -52652,10 +52672,11 @@ - + + - + @@ -52667,30 +52688,30 @@ - + - + - + - + - + - + - + - + @@ -52709,11 +52730,10 @@ - - + @@ -52722,12 +52742,12 @@ - + @@ -52736,47 +52756,48 @@ - - + - + - + - - + + - + - + - - + - + + + - + + @@ -52786,16 +52807,18 @@ - + - + + - + + @@ -52804,9 +52827,11 @@ - + + + @@ -52818,6 +52843,7 @@ + @@ -52829,10 +52855,11 @@ - + - + + @@ -52841,15 +52868,17 @@ - + + + - + - + @@ -52861,7 +52890,7 @@ - + @@ -52869,8 +52898,7 @@ - - + @@ -52878,12 +52906,11 @@ - + - - + @@ -52892,20 +52919,22 @@ + + - - + + - + @@ -52922,14 +52951,13 @@ - + - @@ -52937,10 +52965,10 @@ + - @@ -52950,8 +52978,7 @@ - - + @@ -52959,30 +52986,29 @@ - - + - + - + - + - + @@ -53000,28 +53026,30 @@ - - + + - + + - + + + - @@ -53029,15 +53057,14 @@ - + + - + - - @@ -53045,8 +53072,10 @@ + + @@ -53063,8 +53092,8 @@ - - + + @@ -53074,8 +53103,6 @@ - - @@ -53083,10 +53110,10 @@ - + - + @@ -53105,44 +53132,46 @@ - - + + + - - - + + - - + + - + + - + - + + @@ -53151,25 +53180,24 @@ - - + - + - - + + @@ -53177,22 +53205,19 @@ - - + - + - - @@ -53221,11 +53246,10 @@ - - + @@ -53233,7 +53257,7 @@ - + @@ -53245,24 +53269,23 @@ - - + - + - - + + @@ -53271,7 +53294,6 @@ - @@ -53279,10 +53301,9 @@ - + - @@ -53294,7 +53315,7 @@ - + @@ -53304,7 +53325,6 @@ - @@ -53313,14 +53333,16 @@ + - + + - + @@ -53331,7 +53353,7 @@ - + @@ -53340,16 +53362,18 @@ + - + + - + @@ -53359,16 +53383,16 @@ - - + + + - - + - + @@ -53377,9 +53401,9 @@ - + - + @@ -53393,35 +53417,35 @@ - + - - + - - + + + - + - + - - + + - + @@ -53429,16 +53453,19 @@ + - + + + @@ -53446,28 +53473,28 @@ - + - + - + - + @@ -53483,57 +53510,60 @@ - + - + - - - + - - + - + + + - + + - + - + + - + + + @@ -53543,26 +53573,29 @@ + - + + - - + + + - + @@ -53572,15 +53605,16 @@ - - + + + - - + + - + @@ -53592,20 +53626,21 @@ - - + + - - + + - + + + - @@ -53614,7 +53649,6 @@ - @@ -53626,22 +53660,24 @@ - - - - + + + + - + - + + + @@ -53657,13 +53693,12 @@ - + - - + @@ -53673,10 +53708,10 @@ - + @@ -53688,15 +53723,15 @@ - + - - + + - - + + @@ -53706,12 +53741,12 @@ - - + + @@ -53720,7 +53755,8 @@ - + + @@ -53730,42 +53766,45 @@ - + + - + - + - + - + - + + - + + - + - + - + @@ -53780,14 +53819,13 @@ - + + - - @@ -53822,15 +53860,15 @@ - + + - + - - + @@ -53845,28 +53883,30 @@ - + + + + - + - - + @@ -53877,10 +53917,12 @@ + + - + @@ -53892,38 +53934,40 @@ - + + - - + + - + - + + - + @@ -53931,7 +53975,7 @@ - + @@ -53941,6 +53985,7 @@ + @@ -53953,7 +53998,7 @@ - + @@ -53965,16 +54010,19 @@ - + + - + - + - + + + @@ -53982,12 +54030,12 @@ - + - + - - + + @@ -53997,31 +54045,30 @@ - - + - + - + - - + + - - + - + + @@ -54031,17 +54078,16 @@ - + - - + @@ -54053,44 +54099,40 @@ - + - - - + - + - + - + - + - - - + - + @@ -54104,30 +54146,28 @@ - - - - - - + + + + - + - - - + + + @@ -54139,8 +54179,7 @@ - - + @@ -54150,18 +54189,17 @@ - - - + + - + @@ -54172,17 +54210,18 @@ + - + - + @@ -54195,10 +54234,10 @@ + - + - @@ -54215,12 +54254,11 @@ + - + - - @@ -54229,21 +54267,21 @@ - + + - - + - - + - - + + + @@ -54251,20 +54289,20 @@ - - + + - + - + - + @@ -54274,6 +54312,7 @@ + @@ -54285,8 +54324,9 @@ - + + @@ -54299,58 +54339,57 @@ - + + + - - + + - - + + - + - - - - - + - - + - - + + - + - + + + @@ -54363,13 +54402,10 @@ - - - @@ -54381,12 +54417,12 @@ - + + - @@ -54398,39 +54434,34 @@ - + - + - - - + + - + - - - - + - + - @@ -54444,12 +54475,12 @@ - - + - + + @@ -54457,8 +54488,7 @@ - - + @@ -54470,10 +54500,8 @@ - - - - + + @@ -54481,58 +54509,61 @@ - + - + - + + - + + - + + - + + - + - + - + - - - + + - + @@ -54541,17 +54572,18 @@ + - + - + - + @@ -54566,7 +54598,6 @@ - @@ -54580,26 +54611,25 @@ + - - + - - - + + - + - + @@ -54617,9 +54647,8 @@ - - + @@ -54640,36 +54669,38 @@ - + - + - + + - + - + + - + - + @@ -54680,9 +54711,8 @@ - - + @@ -54690,24 +54720,26 @@ - + - + - + + + - - + + @@ -54716,7 +54748,7 @@ - + @@ -54724,6 +54756,7 @@ + @@ -54737,23 +54770,27 @@ + + + - - - + + + + - + @@ -54764,14 +54801,13 @@ - + - - + @@ -54780,11 +54816,12 @@ - + - + + @@ -54792,9 +54829,8 @@ - - + @@ -54802,13 +54838,16 @@ - + + + + @@ -54816,9 +54855,9 @@ - + - + @@ -54832,7 +54871,7 @@ - + @@ -54843,9 +54882,10 @@ - + + @@ -54853,33 +54893,36 @@ - + - - + + + - + - + - + - + + + - + @@ -54896,14 +54939,13 @@ - + - + - @@ -54914,17 +54956,15 @@ - + - - - - + + @@ -54934,22 +54974,20 @@ - + - - - + @@ -54968,15 +55006,16 @@ + - + - + @@ -54991,7 +55030,7 @@ - + @@ -55000,8 +55039,8 @@ + - @@ -55013,34 +55052,34 @@ + - + + - + - + + - - - + - @@ -55055,42 +55094,38 @@ - + - - + - + - - - - - - - + + + + @@ -55098,12 +55133,11 @@ - + - @@ -55112,12 +55146,12 @@ - + + - @@ -55145,25 +55179,26 @@ - + - - - - + + + + + - + @@ -55172,23 +55207,25 @@ - + - + + + + - - + @@ -55208,18 +55245,18 @@ - + + - - - + + - + @@ -55234,7 +55271,7 @@ - + @@ -55246,15 +55283,14 @@ - - + - + @@ -55273,13 +55309,13 @@ + - - + @@ -55291,9 +55327,8 @@ - + - @@ -55301,24 +55336,19 @@ - - - + + - - - + - - - + @@ -55326,17 +55356,18 @@ + - + - + - + @@ -55345,26 +55376,23 @@ - - + - - + - + - + + - - @@ -55375,8 +55403,9 @@ + - + @@ -55386,14 +55415,14 @@ + - - + @@ -55411,14 +55440,14 @@ - + + - @@ -55426,22 +55455,24 @@ - + - + + + - + @@ -55453,63 +55484,62 @@ - + + - - + - + - + - + - + + - + - + - + - - - - + + - + @@ -55525,7 +55555,7 @@ - + @@ -55533,25 +55563,26 @@ - + - + - - + + - + + - + - + @@ -55561,24 +55592,26 @@ + - + - - + + - - + + + @@ -55589,11 +55622,9 @@ - - @@ -55616,18 +55647,17 @@ - - + - + - + - + @@ -55635,11 +55665,10 @@ - - + - + @@ -55647,10 +55676,12 @@ + + @@ -55660,18 +55691,17 @@ - + + - - @@ -55682,7 +55712,7 @@ - + @@ -55691,16 +55721,17 @@ - + + - + - - + + @@ -55709,22 +55740,22 @@ - + + - + - + - - + @@ -55735,25 +55766,22 @@ - + - - + - - - - + + @@ -55768,6 +55796,8 @@ + + @@ -55789,12 +55819,15 @@ + + - + + @@ -55805,6 +55838,7 @@ + @@ -55813,13 +55847,13 @@ - + + - + - @@ -55841,10 +55875,11 @@ + - + @@ -55860,7 +55895,6 @@ - @@ -55877,18 +55911,14 @@ - - - - - + @@ -55898,19 +55928,20 @@ - + + + - - + @@ -55926,20 +55957,20 @@ - - + - + - + - + + @@ -55949,7 +55980,6 @@ - @@ -55957,16 +55987,14 @@ - + - + - - @@ -55980,7 +56008,6 @@ - @@ -56000,23 +56027,24 @@ - + - - + + + - - + + + - - + @@ -56029,20 +56057,20 @@ - - + + - + - + + - @@ -56051,8 +56079,8 @@ - - + + @@ -56063,56 +56091,57 @@ - + - - - - + + + - + - + - + + + @@ -56123,16 +56152,17 @@ - - + + + - + @@ -56143,7 +56173,6 @@ - @@ -56152,19 +56181,19 @@ - + + - @@ -56174,6 +56203,9 @@ + + + @@ -56183,18 +56215,17 @@ - + - + - - + @@ -56209,55 +56240,50 @@ - - + + - + - - - - + - - + + - - + - + - @@ -56277,15 +56303,15 @@ + - - + @@ -56294,25 +56320,28 @@ + + + + - + - @@ -56323,24 +56352,24 @@ - + - + - + - + - - + + @@ -56349,15 +56378,15 @@ - + - - - + + + @@ -56365,23 +56394,23 @@ - + + - - + - + + - @@ -56394,12 +56423,13 @@ + - + @@ -56413,6 +56443,7 @@ + @@ -56421,20 +56452,19 @@ - - + + - - + + - + - @@ -56446,12 +56476,12 @@ - + - + - + @@ -56462,7 +56492,7 @@ - + @@ -56487,27 +56517,26 @@ - - + - + - + + - + - @@ -56517,17 +56546,15 @@ - - + - @@ -56539,23 +56566,25 @@ + - + - + + - + - + @@ -56571,11 +56600,13 @@ + - + + @@ -56584,11 +56615,10 @@ - + - @@ -56603,24 +56633,22 @@ - - - + + - + - + - - + @@ -56634,14 +56662,13 @@ - - + - + @@ -56655,14 +56682,14 @@ - + - + @@ -56677,22 +56704,19 @@ - - - - + - + - + @@ -56705,7 +56729,7 @@ - + @@ -56719,12 +56743,13 @@ + - - + + @@ -56733,9 +56758,8 @@ - + - @@ -56755,28 +56779,30 @@ - + + - + + + + - - + - @@ -56784,7 +56810,7 @@ - + @@ -56792,10 +56818,11 @@ + - + @@ -56807,27 +56834,29 @@ + - + + - + - + + - + - - - + + @@ -56844,7 +56873,7 @@ - + @@ -56860,13 +56889,12 @@ - + - @@ -56889,17 +56917,17 @@ - - + + - + - + @@ -56910,7 +56938,7 @@ - + @@ -56923,20 +56951,22 @@ - + + + - + - + @@ -56947,6 +56977,7 @@ + @@ -56957,16 +56988,16 @@ - + - + - + @@ -56978,6 +57009,7 @@ + @@ -56985,15 +57017,17 @@ + + - + - + @@ -57002,31 +57036,32 @@ - + + + - - + @@ -57038,13 +57073,13 @@ - + - + - - + + @@ -57055,44 +57090,49 @@ + - - + + + + + + - + - + - + - + @@ -57100,6 +57140,7 @@ + @@ -57112,18 +57153,18 @@ - + - - + - + + @@ -57132,43 +57173,47 @@ - + - + - + + + - + - + - + - + + + - + - + @@ -57189,14 +57234,15 @@ - + + - + @@ -57205,9 +57251,10 @@ - - + + + @@ -57215,14 +57262,13 @@ - - - + + - + @@ -57233,7 +57279,8 @@ - + + @@ -57245,16 +57292,16 @@ - + - + - - + - + + @@ -57266,15 +57313,15 @@ - + - + - + @@ -57285,19 +57332,21 @@ - + - + + + - - + + @@ -57307,20 +57356,18 @@ - - + - + - @@ -57335,44 +57382,43 @@ + - + - + - - + - + + - - + - + - @@ -57383,33 +57429,36 @@ - + + + - - + + - - + - + - + + + @@ -57417,27 +57466,27 @@ - + - - + + - + + - @@ -57450,10 +57499,12 @@ - + + + @@ -57469,31 +57520,31 @@ + - + - - + + - + - @@ -57505,10 +57556,11 @@ - + - + + @@ -57516,79 +57568,83 @@ - + - + + - - + - + + - + + - + + - + + - + - - + - + + + - - + + - + - @@ -57601,16 +57657,17 @@ - + - + - + - + + @@ -57619,7 +57676,6 @@ - @@ -57630,47 +57686,46 @@ - + - + - + - + - + - - + + - - + @@ -57678,22 +57733,22 @@ - + + - - + - + + - + - @@ -57707,54 +57762,61 @@ + + - + - + + - + - + - + + + - + - - + + - + - + - + + + @@ -57766,6 +57828,7 @@ + @@ -57776,6 +57839,7 @@ + @@ -57798,7 +57862,7 @@ - + @@ -57813,38 +57877,38 @@ - + - + - + - + - + - + + - + - + - - + @@ -57853,14 +57917,19 @@ + + + + + - - + + @@ -57873,21 +57942,20 @@ - + - - - + - - + + + @@ -57899,27 +57967,28 @@ - + - + - - + + - + + - + @@ -57934,7 +58003,6 @@ - @@ -57944,14 +58012,14 @@ - + + - + - @@ -57960,13 +58028,14 @@ - + + @@ -57975,8 +58044,6 @@ - - @@ -57986,29 +58053,29 @@ - - - + + + - - + + @@ -58020,26 +58087,28 @@ - + - + + + - + - + @@ -58050,25 +58119,26 @@ + - - + + - + @@ -58080,110 +58150,125 @@ - + - - - + - - + + + - - - + + - - + + - + - + + - + + - - - + + - + + + - - - + + + + - + + + + + + + - + + + - + - - - + + + + + + + - - + + + @@ -58193,45 +58278,44 @@ - - - + - - + + - - + + - - + + + @@ -58241,24 +58325,27 @@ + + + - + - - + + - - - + + + - + - + @@ -58266,169 +58353,169 @@ - - + + - - + + - - - - - + - - - + - + + - + - - + - - + + + + + + + + - - + - + - - + + + + + - + - - + - + + + - - - + + - - + - + - - - + + - + - - - - - + + + - + - + - + + + + - - - + - - + + + + - @@ -58436,181 +58523,191 @@ - + - + - - + + + + - - - + + + - + + + + + + - - - + - + + - + + - - - - - - + + - + + + + - - + + - - - + - + + + + + - + - - + + + - - - - + + + - + + + + - - + + - - + + + + + + + - - - - - - - + + - @@ -58619,133 +58716,126 @@ - + - + - + + - - + + + - - + - - + - - - + + + + - + - + + + - + - - - - - - - + - + + - - - + - - - - + + - - - + - - + + - + + @@ -58754,152 +58844,149 @@ - + + + + + - - - - - + + + + + - + + - + + - - + - - + - - - - + - - - + + - - - + - + - + + + - + + - - + - - + + + - - - + + - - - + + - - - + + + - - + - @@ -58907,14 +58994,16 @@ - + - + + + - + @@ -58922,12 +59011,9 @@ - - - @@ -58936,17 +59022,16 @@ - + + - - + + + - - - @@ -58957,239 +59042,238 @@ - - + + - - - - - + - + - + + + - - - - + + - + - + - - - - + - + + - - - + + - + + - - + + - - + - - - - + - + - + + - + - - - - + + + + + - - + + - - + - + + + + - + - - - + - + - - - - + - - - - + + + + + - - + + - + + + + + - - - - - - + + + + + + + + - + + + + + - - - + + @@ -59198,16 +59282,14 @@ + - - - - + @@ -59215,116 +59297,111 @@ + - + - - - + + - + - + - + - - + - + - + - + + + - - - - - + - - - - + - - - + + + + + + + - + - - - - - - - + + + + @@ -59335,9 +59412,9 @@ - - + + @@ -59345,72 +59422,76 @@ - + + - - + - + + + + - - + + - + + - + + - + - - - + + - - - + + + + + - + - - @@ -59418,86 +59499,86 @@ - - + - - + + - + - - - + - + + + + - - + + - + - - + - + - + + - + + - - - + + - - + + + - @@ -59505,62 +59586,67 @@ - + - - + + + - + + - + - + - - + + - + + - + + + + + - + + - - - + + - - @@ -59568,114 +59654,111 @@ - - - + + + + - + + + - - + - - - + + + + - - + - - + - - + + - + + - + - + + - - - - - + + - - - + - - - - + + - + + - - + + + - + - - + @@ -59684,37 +59767,35 @@ - + + + + + - - + - - - - + + - - - @@ -59723,42 +59804,46 @@ + + - + + - + + + - - - - + + + + - @@ -59767,69 +59852,61 @@ - + + + - - - - - - + + - - - - + + - - - + + + - + + - - + + + - - - - - - + - - + - + @@ -59837,47 +59914,52 @@ - + - + + - + + - + + - + - + + + + - - - + + + + - + - - - - + + @@ -59885,31 +59967,38 @@ - - + + + - + + + + + + + - - + + @@ -59917,159 +60006,159 @@ + - - - - + + + - + - - + + - + + + + + + - - + + - - + + - + - - - - + + + + + + - - + + + - + - - + - - - - + - + + - + - - + + - + - - + + - - + + + - + - + - - + - - - - - + + - - @@ -60077,106 +60166,116 @@ + + - - - - + - - - + + + + + + - + - - + + + + + - + + + + + + + - - - + + - - + + - - - + - - + + + + - + + + - - - - + + + - @@ -60184,9 +60283,11 @@ + + - + @@ -60197,266 +60298,287 @@ - - + + + - - + - + + + + + - - + - - + + + - + - + + + + - + - - + + - - + + + + + - - + - + - + + - + + + - + - + + - + - + - + + + - - + + - + - + + + - - + + + + + + + - - - + - + + - - - - - - + + - + - + + - - + + - - - - + + + + + - - - + - - + + + + - + - + + - + - + + - + - + - + + - - - + - - + - + + + + - - - - + + + - + - + - + @@ -60472,20 +60594,17 @@ - - - - - + + @@ -60495,8 +60614,6 @@ - - diff --git a/Engine/Build/HTML5/GameX.html.template b/Engine/Build/HTML5/GameX.html.template index b9108170f186..ee05f214258c 100644 --- a/Engine/Build/HTML5/GameX.html.template +++ b/Engine/Build/HTML5/GameX.html.template @@ -5,6 +5,20 @@ + + @@ -615,7 +635,13 @@ function taskFinished(taskId, error) { } window.onerror = function(e) { - showErrorDialog(e.toString()); + e = e.toString(); + if (e.toLowerCase().indexOf('memory') != -1) { + e += '
'; + if (!heuristic64BitBrowser) e += ' Try running in a 64-bit browser to resolve.'; + if (runningAsmJs) e += ' If you are the developer, make sure to deploy a minified Shipping build and consider migrating to WebAssembly for optimized memory usage.'; + } + showErrorDialog(e); } function formatBytes(bytes) { @@ -724,18 +750,34 @@ function download(url, responseType) { }); } +function getIDBRequestErrorString(req) { + try { return req.error ? ('IndexedDB ' + req.error.name + ': ' + req.error.message) : req.result; + } catch(ex) { return null; } +} + function deleteIndexedDBStorage(dbName, onsuccess, onerror, onblocked) { - var idb = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; - if (Module['dbInstance']) Module['dbInstance'].close(); - if (!dbName) dbName = Module['UE4_indexedDBName']; - var req = idb.deleteDatabase(dbName); - req.onsuccess = function() { console.log('Deleted IndexedDB storage ' + dbName + '!'); reportDataBytesStoredInIndexedDB(null); if (onsuccess) onsuccess(); } - req.onerror = function(e) { console.error('Failed to delete IndexedDB storage ' + dbName + '!'); console.error(e); if (onerror) onerror(e); return false; } - req.onblocked = function(e) { console.error('Failed to delete IndexedDB storage ' + dbName + ', DB was blocked!'); console.error(e); if (onblocked) onblocked(e); return false; } + var idb = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; + if (Module['dbInstance']) Module['dbInstance'].close(); + if (!dbName) dbName = Module['UE4_indexedDBName']; + var req = idb.deleteDatabase(dbName); + req.onsuccess = function() { console.log('Deleted IndexedDB storage ' + dbName + '!'); reportDataBytesStoredInIndexedDB(null); if (onsuccess) onsuccess(); } + req.onerror = function(evt) { + var errorString = getIDBRequestErrorString(req); + console.error('Failed to delete IndexedDB storage ' + dbName + ', ' + errorString); + evt.preventDefault(); + if (onerror) onerror(errorString); + }; + req.onblocked = function(evt) { + var errorString = getIDBRequestErrorString(req); + console.error('Failed to delete IndexedDB storage ' + dbName + ', DB was blocked! ' + errorString); + evt.preventDefault(); + if (onblocked) onblocked(errorString); + } } var enableReadFromIndexedDB = (location.search.indexOf('noidbread') == -1); var enableWriteToIndexedDB = enableReadFromIndexedDB && (location.search.indexOf('noidbwrite') == -1); +%DISABLE_INDEXEDDB% if (!enableReadFromIndexedDB) showWarningRibbon('Running with IndexedDB access disabled.'); else if (!enableWriteToIndexedDB) showWarningRibbon('Running in read-only IndexedDB access mode.'); @@ -744,8 +786,7 @@ function storeToIndexedDB(db, key, value) { return new Promise(function(resolve, reject) { if (!enableWriteToIndexedDB) return reject('storeToIndexedDB: IndexedDB writes disabled by "?noidbwrite" option'); function fail(e) { - console.error('Failed to store file ' + key + ' to IndexedDB storage! error:'); - console.error(e); + console.error('Failed to store file ' + key + ' to IndexedDB storage! error: ' + e); if (!Module['idberrorShown']) { showWarningRibbon('Failed to store file ' + key + ' to IndexedDB, error: ' + e); Module['idberrorShown'] = true; @@ -759,13 +800,14 @@ function storeToIndexedDB(db, key, value) { var transaction = db.transaction(['FILES'], 'readwrite'); var packages = transaction.objectStore('FILES'); var putRequest = packages.put(value, "file/" + Module.key + '/' + key); - putRequest.onsuccess = function(event) { + putRequest.onsuccess = function(evt) { if (value.byteLength || value.length) reportDataBytesStoredInIndexedDB(value.size || value.byteLength || value.length); resolve(key); }; - putRequest.onerror = function(error) { - fail(error); - return false; /* Don't propagate the error to window.onerror handler. */ + putRequest.onerror = function(evt) { + var errorString = getIDBRequestErrorString(putRequest) || ('IndexedDB request error: ' + evt); + evt.preventDefault(); + fail(errorString); }; } catch(e) { fail(e); @@ -790,17 +832,21 @@ function fetchFromIndexedDB(db, key) { var transaction = db.transaction(['FILES'], 'readonly'); var packages = transaction.objectStore('FILES'); var getRequest = packages.get("file/" + Module.key + '/' + key); - getRequest.onsuccess = function(event) { - if (event.target.result) { - var len = event.target.result.size || event.target.result.byteLength || event.target.result.length; + getRequest.onsuccess = function(evt) { + if (evt.target.result) { + var len = evt.target.result.size || evt.target.result.byteLength || evt.target.result.length; if (len) reportDataBytesStoredInIndexedDB(len); - resolve(event.target.result); + resolve(evt.target.result); } else { // Succeeded to load, but the load came back with the value of undefined, treat that as an error since we never store undefined in db. reject(); } }; - getRequest.onerror = function(error) { fail(error); return false; /* Don't propagate the error to window.onerror handler. */ }; + getRequest.onerror = function(evt) { + var errorString = getIDBRequestErrorString(getRequest) || ('IndexedDB.get request error: ' + evt); + evt.preventDefault(); + fail(errorString); + }; } catch(e) { fail(e); } @@ -830,20 +876,24 @@ function fetchOrDownloadAndStore(db, url, responseType) { function openIndexedDB(dbName, dbVersion) { return new Promise(function(resolve, reject) { if (!enableReadFromIndexedDB) return reject('openIndexedDB: IndexedDB disabled by "?noidbread" option'); - try { + try { var idb = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; - var openRequest = idb.open(dbName, dbVersion); - } catch(e) { return reject(e); } + var openRequest = idb.open(dbName, dbVersion); + } catch(e) { return reject(e); } - openRequest.onupgradeneeded = function(event) { - var db = event.target.result; + openRequest.onupgradeneeded = function(evt) { + var db = evt.target.result; if (db.objectStoreNames.contains('FILES')) db.deleteObjectStore('FILES'); db.createObjectStore('FILES'); }; - openRequest.onsuccess = function(event) { - resolve(event.target.result); + openRequest.onsuccess = function(evt) { + resolve(evt.target.result); + }; + openRequest.onerror = function(evt) { + var errorString = getIDBRequestErrorString(openRequest) || ('IndexedDB request error: ' + evt); + evt.preventDefault(); + reject(errorString); }; - openRequest.onerror = function(error) { reject(error); return false; /* Don't propagate the error to window.onerror handler. */ }; }); } @@ -1000,7 +1050,7 @@ function compileShadersFromJson(jsonData) { console.error('Precompiling shaders got GL error: ' + e); return reject('Precompiling shaders got GL error: ' + e); } - Module['precompiledPrograms'].push({ + Module['precompiledPrograms'].push({ program: program, programInfos: ptable, vs: p.vs, @@ -1011,7 +1061,7 @@ function compileShadersFromJson(jsonData) { setTimeout(buildProgram, 0); }) - return promise; + return promise; } $(document).ready(function() { @@ -1019,7 +1069,7 @@ $(document).ready(function() { showWarningRibbon('Your browser does not support WebAssembly, so running the asm.js fallback of this page. This can impact performance.
Try updating to latest 64-bit Firefox for a browser that supports WebAssembly.
Current user agent: ' + navigator.userAgent); } - if (!Module['buffer']) { + if (!Module['buffer'] && allocateHeapUpFront) { showErrorDialog('Failed to allocate ' + MB(MIN_MEMORY) + ' of linear memory for the ' + (runningAsmJs?'asm.js':'WebAssembly') + ' heap!'); return; } @@ -1046,7 +1096,7 @@ $(document).ready(function() { if (!heuristicIs64Bit('browser')) { if (heuristicIs64Bit('os')) { - showWarningRibbon('It looks like you are running a 32-bit browser on a 64-bit operating system. This can dramatically affect performance. Try updating to 64-bit Firefox for an optimized experience.'); + showWarningRibbon('It looks like you are running a 32-bit browser on a 64-bit operating system. This can dramatically affect performance and risk running out of memory on large applications. Try updating to 64-bit Firefox for an optimized experience.'); } else { showWarningRibbon('It looks like your computer hardware is 32-bit. This can dramatically affect performance.'); } @@ -1068,7 +1118,7 @@ $(document).ready(function() { // The following WebGL extensions would be preferred to exist for best features/performance, but are not strictly needed and UE4 can fall back if not available. var preferredToHaveWebGLExtensions = [// The following are core in WebGL 2: - 'ANGLE_instanced_arrays', // UE4 uses instanced rendering where possible, but can fallback to noninstanced. + 'ANGLE_instanced_arrays', // UE4 uses instanced rendering where possible, but can fallback to noninstanced. 'EXT_color_buffer_half_float', 'EXT_sRGB', 'EXT_shader_texture_lod', // textureLod() is needed for correct reflections, without this reflection shaders are missing and render out black. @@ -1129,14 +1179,25 @@ $(document).ready(function() { Module['wasmInstantiateActionReject'] = reject; }); - var mainJsDownload = fetchOrDownloadAndStore(db, Module.locateFile('%CONFIG%.js')).then(addScriptToDom); - if (runningAsmJs) mainJsDownload = mainJsDownload.catch(noAsmJsFallbackHostedError); + var mainJsDownload = fetchOrDownloadAndStore(db, Module.locateFile('%CONFIG%.js')).then(function(data) { + return addScriptToDom(data).then(function() { + addRunDependency('wait-for-compiled-code'); + }); + }); } else { - var mainCompiledCode = fetchOrDownloadAndStore(db, Module.locateFile('%CONFIG%.asm.js'), 'arraybuffer').then(function(data) { + var mainCompiledCode = fetchOrDownloadAndStore(db, Module.locateFile('%CONFIG%.asm.js'), 'arraybuffer').then(function(data) { taskProgress(TASK_COMPILING); return addScriptToDom(data).then(function() { taskFinished(TASK_COMPILING); }).catch(function(e) { + if (e.toString().toLowerCase().indexOf('memory') != -1) { + // Unminified asm.js pages are really large, they need a 64-bit browser to run. + if (data && data.byteLength > 150*1024*1024) { + e = 'Out of memory!
The size of asm.js code is quite large (' + ((data.byteLength/1024/1024)|0) + 'MB) which suggests this was a nonminified build. Try running development builds either on a 64-bit browser, restrict to a smaller asm.js heap size than the current ' + (Module['buffer'].byteLength/1024/1024) + ' MB, consider migrating to WebAssembly, or deploy a minified Shipping build instead.'; + } else { + e = 'Out of memory!
Try restricting to a smaller asm.js heap size than the current ' + (Module['buffer'].byteLength/1024/1024) + ' MB or consider migrating to WebAssembly.'; + } + } taskFinished(TASK_COMPILING, e); }); }).catch(function(e) { @@ -1144,7 +1205,11 @@ $(document).ready(function() { }); var compiledCodeInstantiateAction = true; // There is no need to manually instantiate asm.js, so instead of having a Promise() to resolve that, pass through true as a no-op. var asmJsRuntimeDownload = fetchOrDownloadAndStore(db, Module.locateFile('%CONFIG%_asm.js')).catch(noAsmJsFallbackHostedError); - var mainJsDownload = Promise.all([asmJsRuntimeDownload, mainCompiledCode]).then(function(results) { addScriptToDom(results[0]); }); + var mainJsDownload = Promise.all([asmJsRuntimeDownload, mainCompiledCode]).then(function(results) { + return addScriptToDom(results[0]).then(function() { + addRunDependency('wait-for-compiled-code'); + }); + }); } var dataJsDownload = fetchOrDownloadAndStore(db, Module.locateFile('%GAME%.data.js')); @@ -1186,9 +1251,7 @@ $(document).ready(function() { Module['precompiledShaders'] = Module['precompiledPrograms'] = Module['preinitializedWebGLContext'] = Module['glIDCounter'] = Module['precompiledUniforms'] = null; } taskProgress(TASK_MAIN); - setTimeout(function() { - removeRunDependency('wait-for-compiled-code'); // Now we are ready to call main() - }, 100); + removeRunDependency('wait-for-compiled-code'); // Now we are ready to call main() }); }; diff --git a/Engine/Build/IOS/XcodeSupportFiles/prepackage.sh b/Engine/Build/IOS/XcodeSupportFiles/prepackage.sh index ae233b4da6bf..85e56b6ba9b5 100755 --- a/Engine/Build/IOS/XcodeSupportFiles/prepackage.sh +++ b/Engine/Build/IOS/XcodeSupportFiles/prepackage.sh @@ -67,6 +67,7 @@ then fi fi + if [ -e $1.entitlements ] then if [ -d ../../../Intermediate/IOS ] diff --git a/Engine/Build/InstalledEngineBuild.xml b/Engine/Build/InstalledEngineBuild.xml index 095ecd0c6be2..4c1dde6e2ce8 100644 --- a/Engine/Build/InstalledEngineBuild.xml +++ b/Engine/Build/InstalledEngineBuild.xml @@ -342,6 +342,7 @@ + @@ -382,7 +383,7 @@ - + diff --git a/Engine/Build/InstalledEngineFilters.xml b/Engine/Build/InstalledEngineFilters.xml index 2edf6476f18f..76bcf2edc545 100644 --- a/Engine/Build/InstalledEngineFilters.xml +++ b/Engine/Build/InstalledEngineFilters.xml @@ -283,6 +283,7 @@ Engine/Build/Android/... Engine/Source/ThirdParty/Android/cxa_demangle/... Engine/Source/ThirdParty/Android/extras/... + Engine/Source/ThirdParty/AndroidPermission/... Engine/Source/ThirdParty/GoogleVR/... Engine/Source/ThirdParty/Oculus/OculusMobile/SDK_1_0_3/Libs/... Engine/Source/ThirdParty/Oculus/LibOVRPlatform/LibOVRPlatform_APL.xml diff --git a/Engine/Build/PhysXBuild.xml b/Engine/Build/PhysXBuild.xml index 1585f27faff1..c90b222c1014 100644 --- a/Engine/Build/PhysXBuild.xml +++ b/Engine/Build/PhysXBuild.xml @@ -108,7 +108,7 @@ - + @@ -143,5 +143,5 @@ - + diff --git a/Engine/Build/Target.cs.template b/Engine/Build/Target.cs.template index f44a164a69f3..7c191664fb00 100644 --- a/Engine/Build/Target.cs.template +++ b/Engine/Build/Target.cs.template @@ -5,11 +5,11 @@ using System.Collections.Generic; public class {GAME_NAME}Target : TargetRules { - public {GAME_NAME}Target(TargetInfo Target) : base(Target) + public {GAME_NAME}Target(TargetInfo Target) : base(Target) { Type = TargetType.Game; - ExtraModuleNames.Add("UE4Game"); + ExtraModuleNames.Add("UE4Game"); } // diff --git a/Engine/Config/Android/AndroidEngine.ini b/Engine/Config/Android/AndroidEngine.ini index ef2c09e54d0e..93dcc1876483 100644 --- a/Engine/Config/Android/AndroidEngine.ini +++ b/Engine/Config/Android/AndroidEngine.ini @@ -1,5 +1,8 @@ [Audio] AudioDeviceModuleName=AndroidAudio +; Uncomment below (and comment above) to use multi-platform mixer module by default +;AudioDeviceModuleName=AudioMixerAndroid + ; Defines a platform-specific volume headroom (in dB) for audio to provide better platform consistency with respect to volume levels. PlatformHeadroomDB=0 @@ -10,7 +13,12 @@ DeviceProfileSelectionModule="AndroidDeviceProfileSelector" DefaultProviderName=AndroidAdvertising [OnlineSubsystem] -DefaultPlatformService=GooglePlay +;this is intentional, GooglePlay is a supporting OSS +DefaultPlatformService=MCP + +[OnlineSubsystemGooglePlay.Store] +bSupportsInAppPurchasing=true +bUseStoreV2=true [SlateRenderer] NumPreallocatedVertices=200 @@ -24,6 +32,25 @@ ConnectionRetryDelay=0 [LocalNotification] DefaultPlatformService=AndroidLocalNotification -[ConsoleVariables] -Slate.CacheRenderData=0 +[DeviceScreenDensity] ++Devices=(Model="Nexus 5",Density=445) ++Devices=(Model="Nexus 5X",Density=424) ++Devices=(Model="Nexus 6",Density=493) ++Devices=(Model="Nexus 6P",Density=518) ++Devices=(Model="SM-G930.+",Density=577,IsRegex=true) ; Samsung Galaxy S7 ++Devices=(Model="SM-G935.+",Density=534,IsRegex=true) ; Samsung Galaxy S7 Edge ++Devices=(Model="SM-N920.+",Density=515,IsRegex=true) ; Samsung Galaxy Note 5 ++Devices=(Model="Pixel",Density=441) ++Devices=(Model="Pixel C",Density=308) ++Devices=(Model="Pixel XL",Density=534) ++Devices=(Model="HTC 10",Density=564) ++Devices=(Model="EVA-L09",Density=423) ; Huawei P9 + +;GalaxyS5=432 +;GalaxyS6=577 + +[ConsoleVariables] +Slate.CacheRenderData=1 + +;GalaxyS6Edge=577 diff --git a/Engine/Config/BaseDeviceProfiles.ini b/Engine/Config/BaseDeviceProfiles.ini index ae2469b039f6..64bd055ca5bd 100644 --- a/Engine/Config/BaseDeviceProfiles.ini +++ b/Engine/Config/BaseDeviceProfiles.ini @@ -29,11 +29,9 @@ +DeviceProfileNameAndTypes=iPhone7Plus,IOS +DeviceProfileNameAndTypes=iPhoneSE,IOS +DeviceProfileNameAndTypes=iPadPro,IOS -+DeviceProfileNameAndTypes=iPadPro129,IOS -+DeviceProfileNameAndTypes=iPadPro97,IOS ++DeviceProfileNameAndTypes=iPadPro_12.9,IOS ++DeviceProfileNameAndTypes=iPadPro_9.7,IOS +DeviceProfileNameAndTypes=AppleTV,IOS -+DeviceProfileNameAndTypes=PS4,PS4 -+DeviceProfileNameAndTypes=XboxOne,XboxOne +DeviceProfileNameAndTypes=HTML5,HTML5 +DeviceProfileNameAndTypes=Mac,Mac +DeviceProfileNameAndTypes=MacClient,Mac @@ -446,23 +444,6 @@ DeviceType=Android BaseProfileName=Android_Mali_T8xx +CVars=r.Android.DisableVulkanSupport=1 -[PS4 DeviceProfile] -DeviceType=PS4 -BaseProfileName= - -[XboxOne DeviceProfile] -DeviceType=XboxOne -BaseProfileName= -; we output 10:10:10, not 8:8:8 so we don't need color quantization -+CVars=r.Tonemapper.GrainQuantization=0 -; For SSAO we rely on TemporalAA (with a randomized sample pattern over time) so we can use less samples -+CVars=r.AmbientOcclusionSampleSetQuality=0 -; less passes, and no upsampling as even upsampling costs some performance -+CVars=r.AmbientOcclusionLevels=1 -; larger radius to compensate for fewer passes -+CVars=r.AmbientOcclusionRadiusScale=2 - - [HTML5 DeviceProfile] DeviceType=HTML5 BaseProfileName= @@ -475,7 +456,6 @@ BaseProfileName= +CVars=r.DFShadowScatterTileCulling=0 +CVars=r.Shaders.ZeroInitialise=1 +CVars=r.Shaders.BoundsChecking=1 -+CVars=r.RHICmdStateCacheEnable=0 [MacClient DeviceProfile] DeviceType=Mac diff --git a/Engine/Config/BaseEditor.ini b/Engine/Config/BaseEditor.ini index 122d93955295..690cc4262def 100644 --- a/Engine/Config/BaseEditor.ini +++ b/Engine/Config/BaseEditor.ini @@ -388,9 +388,12 @@ bUseFullGCAssetClassNames=true +ConfigSettingBlacklist=*.Engine:WindowsApplication.Accessibility +ConfigSettingBlacklist=*.EditorKeyBindings +ConfigSettingBlacklist=*.GameplayAbilities:CoreRedirects -+ConfigSettingBlacklist=*.Engine.MemReportFullCommands ++ConfigSettingBlacklist=*.Engine:MemReportFullCommands +ConfigSettingBlacklist=*:CoreRedirects +ConfigSettingBlacklist=*.OnlineGameplayFramework:/Script/Engine.Engine ++ConfigSettingBlacklist=*.Engine:OnlineSubsystem*:/Script/Engine.Engine ++ConfigSettingBlacklist=*.Engine:Audio ++ConfigSettingBlacklist=*.Engine:/Script/LinuxTargetPlatform.LinuxTargetSettings +VersionedIntRValues=r.AllowStaticLighting @@ -406,15 +409,21 @@ bUseFullGCAssetClassNames=true +VersionedIntRValues=r.MobileHDR +[CookPlatformDataCacheSettings] +MaterialInstance=100 +Material=100 +Texture2D=50 + + [/Script/Localization.LocalizationSettings] -+EngineTargetsSettings=(Name="Engine",Guid=33482D004789784C9DA695A682ACCA1B,TargetDependencies=,AdditionalManifestDependencies=,RequiredModuleNames=,GatherFromTextFiles=(IsEnabled=True,SearchDirectories=((Path="Source/Runtime/"),(Path="Source/Developer/"),(Path="Config/")),ExcludePathWildcards=((Pattern="Source/Developer/NoRedist/CommunityPortalServices/*"),(Pattern="Source/Developer/NoRedist/UnrealEngineLauncherServices/*"),(Pattern="Source/Developer/NoRedist/BuildPatchServices/*")),FileExtensions=((Pattern="cpp"),(Pattern="h"),(Pattern="c"),(Pattern="inl"),(Pattern="mm"),(Pattern="ini"))),GatherFromPackages=(IsEnabled=True,IncludePathWildcards=((Pattern="Content/*")),ExcludePathWildcards=((Pattern="Content/Editor/*"),(Pattern="Content/Tutorial/*"),(Pattern="Content/Developers/*"),(Pattern="Content/TestPackages/*"),(Pattern="Content/QA_Assets/*"),(Pattern="Content/Maps/Automation/*"),(Pattern="Content/EngineSounds/*")),FileExtensions=((Pattern="umap"),(Pattern="uasset")),ShouldGatherFromEditorOnlyData=True),GatherFromMetaData=(IsEnabled=False,IncludePathWildcards=,ExcludePathWildcards=,KeySpecifications=,ShouldGatherFromEditorOnlyData=True),NativeCultureIndex=0,SupportedCulturesStatistics=((CultureName="en"),(CultureName="es"),(CultureName="ja"),(CultureName="ko"),(CultureName="pt-BR"),(CultureName="zh-CN"))) -+EngineTargetsSettings=(Name="Editor",Guid=AC8BFD2A41A2FB2893BB8EA0AF903E6D,TargetDependencies=(33482D004789784C9DA695A682ACCA1B),AdditionalManifestDependencies=,RequiredModuleNames=,GatherFromTextFiles=(IsEnabled=True,SearchDirectories=((Path="Source/Editor/")),ExcludePathWildcards=,FileExtensions=((Pattern="cpp"),(Pattern="h"),(Pattern="c"),(Pattern="inl"),(Pattern="mm"))),GatherFromPackages=(IsEnabled=True,IncludePathWildcards=((Pattern="Content/Editor/*"),(Pattern="Content/Editor*")),ExcludePathWildcards=,FileExtensions=((Pattern="umap"),(Pattern="uasset")),ShouldGatherFromEditorOnlyData=True),GatherFromMetaData=(IsEnabled=False,IncludePathWildcards=,ExcludePathWildcards=,KeySpecifications=,ShouldGatherFromEditorOnlyData=True),NativeCultureIndex=0,SupportedCulturesStatistics=((CultureName="en"),(CultureName="es"),(CultureName="ja"),(CultureName="ko"),(CultureName="pt-BR"),(CultureName="zh-CN"))) -+EngineTargetsSettings=(Name="EditorTutorials",Guid=00F8E3AD47F0A73D50D46881C14DF28F,TargetDependencies=(33482D004789784C9DA695A682ACCA1B,AC8BFD2A41A2FB2893BB8EA0AF903E6D),AdditionalManifestDependencies=,RequiredModuleNames=("IntroTutorials"),GatherFromTextFiles=(IsEnabled=False,SearchDirectories=,ExcludePathWildcards=,FileExtensions=((Pattern="h"),(Pattern="cpp"),(Pattern="ini"))),GatherFromPackages=(IsEnabled=True,IncludePathWildcards=((Pattern="Content/Tutorial/*")),ExcludePathWildcards=,FileExtensions=((Pattern="umap"),(Pattern="uasset")),ShouldGatherFromEditorOnlyData=True),GatherFromMetaData=(IsEnabled=False,IncludePathWildcards=,ExcludePathWildcards=,KeySpecifications=,ShouldGatherFromEditorOnlyData=True),NativeCultureIndex=0,SupportedCulturesStatistics=((CultureName="en"),(CultureName="es"),(CultureName="ja"),(CultureName="ko"),(CultureName="pt-BR"),(CultureName="zh-CN"))) -+EngineTargetsSettings=(Name="PropertyNames",Guid=E391A8B149980E8154E056AF2DA49479,TargetDependencies=(33482D004789784C9DA695A682ACCA1B,AC8BFD2A41A2FB2893BB8EA0AF903E6D),AdditionalManifestDependencies=,RequiredModuleNames=,GatherFromTextFiles=(IsEnabled=False,SearchDirectories=,ExcludePathWildcards=,FileExtensions=((Pattern="h"),(Pattern="cpp"),(Pattern="ini"))),GatherFromPackages=(IsEnabled=False,IncludePathWildcards=,ExcludePathWildcards=,FileExtensions=((Pattern="umap"),(Pattern="uasset")),ShouldGatherFromEditorOnlyData=True),GatherFromMetaData=(IsEnabled=True,IncludePathWildcards=((Pattern="Source/Editor/*"),(Pattern="Source/Runtime/*"),(Pattern="Source/Developer/*")),ExcludePathWildcards=((Pattern="Source/Developer/NoRedist/CommunityPortalServices/*")),KeySpecifications=((MetaDataKey=(Name="DisplayName"),TextNamespace="UObjectDisplayNames",TextKeyPattern=(Pattern="{FieldPath}"))),ShouldGatherFromEditorOnlyData=True),NativeCultureIndex=0,SupportedCulturesStatistics=((CultureName="en"),(CultureName="es"),(CultureName="ja"),(CultureName="ko"),(CultureName="pt-BR"),(CultureName="zh-CN"))) -+EngineTargetsSettings=(Name="ToolTips",Guid=0F116534468918AEA432DD8C77703BA8,TargetDependencies=(33482D004789784C9DA695A682ACCA1B,AC8BFD2A41A2FB2893BB8EA0AF903E6D),AdditionalManifestDependencies=,RequiredModuleNames=,GatherFromTextFiles=(IsEnabled=False,SearchDirectories=,ExcludePathWildcards=,FileExtensions=((Pattern="h"),(Pattern="cpp"),(Pattern="ini"))),GatherFromPackages=(IsEnabled=False,IncludePathWildcards=,ExcludePathWildcards=,FileExtensions=((Pattern="umap"),(Pattern="uasset")),ShouldGatherFromEditorOnlyData=True),GatherFromMetaData=(IsEnabled=True,IncludePathWildcards=((Pattern="Source/Editor/*"),(Pattern="Source/Runtime/*"),(Pattern="Source/Developer/*")),ExcludePathWildcards=((Pattern="Source/Developer/NoRedist/CommunityPortalServices/*")),KeySpecifications=((MetaDataKey=(Name="ToolTip"),TextNamespace="UObjectToolTips",TextKeyPattern=(Pattern="{FieldPath}")),(MetaDataKey=(Name="ShortToolTip"),TextNamespace="UObjectShortToolTips",TextKeyPattern=(Pattern="{FieldPath}"))),ShouldGatherFromEditorOnlyData=True),NativeCultureIndex=0,SupportedCulturesStatistics=((CultureName="en"),(CultureName="es"),(CultureName="ja"),(CultureName="ko"),(CultureName="pt-BR"),(CultureName="zh-CN"))) -+EngineTargetsSettings=(Name="Keywords",Guid=AE89AECB47475F420D0D69A5547515DC,TargetDependencies=(33482D004789784C9DA695A682ACCA1B,AC8BFD2A41A2FB2893BB8EA0AF903E6D),AdditionalManifestDependencies=,RequiredModuleNames=,GatherFromTextFiles=(IsEnabled=False,SearchDirectories=,ExcludePathWildcards=,FileExtensions=((Pattern="h"),(Pattern="cpp"),(Pattern="ini"))),GatherFromPackages=(IsEnabled=False,IncludePathWildcards=,ExcludePathWildcards=,FileExtensions=((Pattern="umap"),(Pattern="uasset")),ShouldGatherFromEditorOnlyData=True),GatherFromMetaData=(IsEnabled=True,IncludePathWildcards=((Pattern="Source/Editor/*"),(Pattern="Source/Runtime/*"),(Pattern="Source/Developer/*")),ExcludePathWildcards=((Pattern="Source/Developer/NoRedist/CommunityPortalServices/*")),KeySpecifications=((MetaDataKey=(Name="Keywords"),TextNamespace="UObjectKeywords",TextKeyPattern=(Pattern="{FieldPath}"))),ShouldGatherFromEditorOnlyData=True),NativeCultureIndex=0,SupportedCulturesStatistics=((CultureName="en"),(CultureName="es"),(CultureName="ja"),(CultureName="ko"),(CultureName="pt-BR"),(CultureName="zh-CN"))) -+EngineTargetsSettings=(Name="Category",Guid=14B8DEE642A6A7AFEB5A28B959EC373A,TargetDependencies=,AdditionalManifestDependencies=,RequiredModuleNames=,GatherFromTextFiles=(IsEnabled=False,SearchDirectories=,ExcludePathWildcards=,FileExtensions=((Pattern="h"),(Pattern="cpp"),(Pattern="ini"))),GatherFromPackages=(IsEnabled=False,IncludePathWildcards=,ExcludePathWildcards=,FileExtensions=((Pattern="umap"),(Pattern="uasset")),ShouldGatherFromEditorOnlyData=False),GatherFromMetaData=(IsEnabled=True,IncludePathWildcards=((Pattern="Source/Editor/*"),(Pattern="Source/Runtime/*"),(Pattern="Source/Developer/*")),ExcludePathWildcards=((Pattern="Source/Developer/NoRedist/CommunityPortalServices/*")),KeySpecifications=((MetaDataKey=(Name="Category"),TextNamespace="UObjectCategory",TextKeyPattern=(Pattern="{FieldPath}"))),ShouldGatherFromEditorOnlyData=True),NativeCultureIndex=0,SupportedCulturesStatistics=((CultureName="en"),(CultureName="es"),(CultureName="ja"),(CultureName="ko"),(CultureName="pt-BR"),(CultureName="zh-CN"))) -+GameTargetsSettings=(Name="Game",Guid=AE0EA34A45461A25BA65A391026F19F8,TargetDependencies=(33482D004789784C9DA695A682ACCA1B,AC8BFD2A41A2FB2893BB8EA0AF903E6D),AdditionalManifestDependencies=,RequiredModuleNames=,GatherFromTextFiles=(IsEnabled=False,SearchDirectories=,ExcludePathWildcards=,FileExtensions=((Pattern="h"),(Pattern="cpp"),(Pattern="ini"))),GatherFromPackages=(IsEnabled=False,IncludePathWildcards=,ExcludePathWildcards=,FileExtensions=((Pattern="umap"),(Pattern="uasset")),ShouldGatherFromEditorOnlyData=False),GatherFromMetaData=(IsEnabled=False,IncludePathWildcards=,ExcludePathWildcards=,KeySpecifications=,ShouldGatherFromEditorOnlyData=False),NativeCultureIndex=-1,SupportedCulturesStatistics=((CultureName="en"))) ++EngineTargetsSettings=(Name="Engine",Guid=33482D004789784C9DA695A682ACCA1B,TargetDependencies=(),AdditionalManifestDependencies=(),RequiredModuleNames=(),GatherFromTextFiles=(IsEnabled=True,SearchDirectories=((Path="Source/Runtime/"),(Path="Source/Developer/"),(Path="Config/")),ExcludePathWildcards=((Pattern="Source/Developer/NoRedist/CommunityPortalServices/*"),(Pattern="Source/Developer/NoRedist/UnrealEngineLauncherServices/*"),(Pattern="Source/Developer/NoRedist/BuildPatchServices/*")),FileExtensions=((Pattern="cpp"),(Pattern="h"),(Pattern="c"),(Pattern="inl"),(Pattern="mm"),(Pattern="ini"))),GatherFromPackages=(IsEnabled=True,IncludePathWildcards=((Pattern="Content/*")),ExcludePathWildcards=((Pattern="Content/Editor/*"),(Pattern="Content/Tutorial/*"),(Pattern="Content/Developers/*"),(Pattern="Content/TestPackages/*"),(Pattern="Content/QA_Assets/*"),(Pattern="Content/Maps/Automation/*"),(Pattern="Content/EngineSounds/*")),FileExtensions=((Pattern="umap"),(Pattern="uasset")),ShouldGatherFromEditorOnlyData=True),GatherFromMetaData=(IsEnabled=False,IncludePathWildcards=(),ExcludePathWildcards=(),KeySpecifications=(),ShouldGatherFromEditorOnlyData=True),NativeCultureIndex=0,SupportedCulturesStatistics=((CultureName="en"),(CultureName="es"),(CultureName="ja"),(CultureName="ko"),(CultureName="pt-BR"),(CultureName="zh-CN"))) ++EngineTargetsSettings=(Name="Editor",Guid=AC8BFD2A41A2FB2893BB8EA0AF903E6D,TargetDependencies=(33482D004789784C9DA695A682ACCA1B),AdditionalManifestDependencies=(),RequiredModuleNames=(),GatherFromTextFiles=(IsEnabled=True,SearchDirectories=((Path="Source/Editor/")),ExcludePathWildcards=(),FileExtensions=((Pattern="cpp"),(Pattern="h"),(Pattern="c"),(Pattern="inl"),(Pattern="mm"))),GatherFromPackages=(IsEnabled=True,IncludePathWildcards=((Pattern="Content/Editor/*"),(Pattern="Content/Editor*")),ExcludePathWildcards=(),FileExtensions=((Pattern="umap"),(Pattern="uasset")),ShouldGatherFromEditorOnlyData=True),GatherFromMetaData=(IsEnabled=False,IncludePathWildcards=(),ExcludePathWildcards=(),KeySpecifications=(),ShouldGatherFromEditorOnlyData=True),NativeCultureIndex=0,SupportedCulturesStatistics=((CultureName="en"),(CultureName="es"),(CultureName="ja"),(CultureName="ko"),(CultureName="pt-BR"),(CultureName="zh-CN"))) ++EngineTargetsSettings=(Name="EditorTutorials",Guid=00F8E3AD47F0A73D50D46881C14DF28F,TargetDependencies=(33482D004789784C9DA695A682ACCA1B,AC8BFD2A41A2FB2893BB8EA0AF903E6D),AdditionalManifestDependencies=(),RequiredModuleNames=("IntroTutorials"),GatherFromTextFiles=(IsEnabled=False,SearchDirectories=(),ExcludePathWildcards=(),FileExtensions=((Pattern="h"),(Pattern="cpp"),(Pattern="ini"))),GatherFromPackages=(IsEnabled=True,IncludePathWildcards=((Pattern="Content/Tutorial/*")),ExcludePathWildcards=(),FileExtensions=((Pattern="umap"),(Pattern="uasset")),ShouldGatherFromEditorOnlyData=True),GatherFromMetaData=(IsEnabled=False,IncludePathWildcards=(),ExcludePathWildcards=(),KeySpecifications=(),ShouldGatherFromEditorOnlyData=True),NativeCultureIndex=0,SupportedCulturesStatistics=((CultureName="en"),(CultureName="es"),(CultureName="ja"),(CultureName="ko"),(CultureName="pt-BR"),(CultureName="zh-CN"))) ++EngineTargetsSettings=(Name="PropertyNames",Guid=E391A8B149980E8154E056AF2DA49479,TargetDependencies=(33482D004789784C9DA695A682ACCA1B,AC8BFD2A41A2FB2893BB8EA0AF903E6D),AdditionalManifestDependencies=(),RequiredModuleNames=(),GatherFromTextFiles=(IsEnabled=False,SearchDirectories=(),ExcludePathWildcards=(),FileExtensions=((Pattern="h"),(Pattern="cpp"),(Pattern="ini"))),GatherFromPackages=(IsEnabled=False,IncludePathWildcards=(),ExcludePathWildcards=(),FileExtensions=((Pattern="umap"),(Pattern="uasset")),ShouldGatherFromEditorOnlyData=True),GatherFromMetaData=(IsEnabled=True,IncludePathWildcards=((Pattern="Source/Editor/*"),(Pattern="Source/Runtime/*"),(Pattern="Source/Developer/*")),ExcludePathWildcards=((Pattern="Source/Developer/NoRedist/CommunityPortalServices/*")),KeySpecifications=((MetaDataKey=(Name="DisplayName"),TextNamespace="UObjectDisplayNames",TextKeyPattern=(Pattern="{FieldPath}"))),ShouldGatherFromEditorOnlyData=True),NativeCultureIndex=0,SupportedCulturesStatistics=((CultureName="en"),(CultureName="es"),(CultureName="ja"),(CultureName="ko"),(CultureName="pt-BR"),(CultureName="zh-CN"))) ++EngineTargetsSettings=(Name="ToolTips",Guid=0F116534468918AEA432DD8C77703BA8,TargetDependencies=(33482D004789784C9DA695A682ACCA1B,AC8BFD2A41A2FB2893BB8EA0AF903E6D),AdditionalManifestDependencies=(),RequiredModuleNames=(),GatherFromTextFiles=(IsEnabled=False,SearchDirectories=(),ExcludePathWildcards=(),FileExtensions=((Pattern="h"),(Pattern="cpp"),(Pattern="ini"))),GatherFromPackages=(IsEnabled=False,IncludePathWildcards=(),ExcludePathWildcards=(),FileExtensions=((Pattern="umap"),(Pattern="uasset")),ShouldGatherFromEditorOnlyData=True),GatherFromMetaData=(IsEnabled=True,IncludePathWildcards=((Pattern="Source/Editor/*"),(Pattern="Source/Runtime/*"),(Pattern="Source/Developer/*")),ExcludePathWildcards=((Pattern="Source/Developer/NoRedist/CommunityPortalServices/*")),KeySpecifications=((MetaDataKey=(Name="ToolTip"),TextNamespace="UObjectToolTips",TextKeyPattern=(Pattern="{FieldPath}")),(MetaDataKey=(Name="ShortToolTip"),TextNamespace="UObjectShortToolTips",TextKeyPattern=(Pattern="{FieldPath}"))),ShouldGatherFromEditorOnlyData=True),NativeCultureIndex=0,SupportedCulturesStatistics=((CultureName="en"),(CultureName="es"),(CultureName="ja"),(CultureName="ko"),(CultureName="pt-BR"),(CultureName="zh-CN"))) ++EngineTargetsSettings=(Name="Keywords",Guid=AE89AECB47475F420D0D69A5547515DC,TargetDependencies=(33482D004789784C9DA695A682ACCA1B,AC8BFD2A41A2FB2893BB8EA0AF903E6D),AdditionalManifestDependencies=(),RequiredModuleNames=(),GatherFromTextFiles=(IsEnabled=False,SearchDirectories=(),ExcludePathWildcards=(),FileExtensions=((Pattern="h"),(Pattern="cpp"),(Pattern="ini"))),GatherFromPackages=(IsEnabled=False,IncludePathWildcards=(),ExcludePathWildcards=(),FileExtensions=((Pattern="umap"),(Pattern="uasset")),ShouldGatherFromEditorOnlyData=True),GatherFromMetaData=(IsEnabled=True,IncludePathWildcards=((Pattern="Source/Editor/*"),(Pattern="Source/Runtime/*"),(Pattern="Source/Developer/*")),ExcludePathWildcards=((Pattern="Source/Developer/NoRedist/CommunityPortalServices/*")),KeySpecifications=((MetaDataKey=(Name="Keywords"),TextNamespace="UObjectKeywords",TextKeyPattern=(Pattern="{FieldPath}"))),ShouldGatherFromEditorOnlyData=True),NativeCultureIndex=0,SupportedCulturesStatistics=((CultureName="en"),(CultureName="es"),(CultureName="ja"),(CultureName="ko"),(CultureName="pt-BR"),(CultureName="zh-CN"))) ++EngineTargetsSettings=(Name="Category",Guid=14B8DEE642A6A7AFEB5A28B959EC373A,TargetDependencies=(),AdditionalManifestDependencies=(),RequiredModuleNames=(),GatherFromTextFiles=(IsEnabled=False,SearchDirectories=(),ExcludePathWildcards=(),FileExtensions=((Pattern="h"),(Pattern="cpp"),(Pattern="ini"))),GatherFromPackages=(IsEnabled=False,IncludePathWildcards=(),ExcludePathWildcards=(),FileExtensions=((Pattern="umap"),(Pattern="uasset")),ShouldGatherFromEditorOnlyData=False),GatherFromMetaData=(IsEnabled=True,IncludePathWildcards=((Pattern="Source/Editor/*"),(Pattern="Source/Runtime/*"),(Pattern="Source/Developer/*")),ExcludePathWildcards=((Pattern="Source/Developer/NoRedist/CommunityPortalServices/*")),KeySpecifications=((MetaDataKey=(Name="Category"),TextNamespace="UObjectCategory",TextKeyPattern=(Pattern="{FieldPath}"))),ShouldGatherFromEditorOnlyData=True),NativeCultureIndex=0,SupportedCulturesStatistics=((CultureName="en"),(CultureName="es"),(CultureName="ja"),(CultureName="ko"),(CultureName="pt-BR"),(CultureName="zh-CN"))) ++GameTargetsSettings=(Name="Game",Guid=AE0EA34A45461A25BA65A391026F19F8,TargetDependencies=(33482D004789784C9DA695A682ACCA1B,AC8BFD2A41A2FB2893BB8EA0AF903E6D),AdditionalManifestDependencies=(),RequiredModuleNames=(),GatherFromTextFiles=(IsEnabled=False,SearchDirectories=(),ExcludePathWildcards=(),FileExtensions=((Pattern="h"),(Pattern="cpp"),(Pattern="ini"))),GatherFromPackages=(IsEnabled=False,IncludePathWildcards=(),ExcludePathWildcards=(),FileExtensions=((Pattern="umap"),(Pattern="uasset")),ShouldGatherFromEditorOnlyData=False),GatherFromMetaData=(IsEnabled=False,IncludePathWildcards=(),ExcludePathWildcards=(),KeySpecifications=(),ShouldGatherFromEditorOnlyData=False),NativeCultureIndex=-1,SupportedCulturesStatistics=((CultureName="en"))) [/Script/UnrealEd.EditorProjectAppearanceSettings] bDisplayUnits=True diff --git a/Engine/Config/BaseEditorPerProjectUserSettings.ini b/Engine/Config/BaseEditorPerProjectUserSettings.ini index 98d090122ee7..acb7439bc6da 100644 --- a/Engine/Config/BaseEditorPerProjectUserSettings.ini +++ b/Engine/Config/BaseEditorPerProjectUserSettings.ini @@ -53,6 +53,9 @@ PropertyMatrix_NumberOfPasteOperationsBeforeWarning=20 ; Blueprint Editor SCS Editor settings bSCSEditorShowGrid=true +; Import +bShowImportDialogAtReimport=False + ; Export bKeepAttachHierarchy=true FbxExportCompatibility=FBX_2013 @@ -126,8 +129,10 @@ DeveloperFolderType=CVDT_CurrentUser NumObjectsToLoadBeforeWarning=20 ; Whether to render thumbnails for loaded assets in real-time in the Content Browser RealTimeThumbnails=True -; Whether to display folders in the assets view of the content browser. Note that this implies 'Show Only Assets in Selected Folders'. +; Whether to display folders in the asset view of the content browser. Note that this implies 'Show Only Assets in Selected Folders'. DisplayFolders=True +; Whether to display empty folders in the asset view of the content browser. +DisplayEmptyFolders=True ; Whether to display the engine folders in the assets view of the content browser. Note that this implies 'Display Folders'. DisplayEngineFolder=False ; Whether to display the developers folder in the path or assets view of the content browser @@ -608,9 +613,11 @@ bImportRigidMesh=False bCombineMeshes=True bCreatePhysicsAsset=True bImportMesh=True +bResetMaterialSlots=False MinimumLodNumber=0 LodNumber=0 bAutoComputeLodDistances=True +bIsReimportPreview=False [/Script/UnrealEd.FbxStaticMeshImportData] diff --git a/Engine/Config/BaseEditorSettings.ini b/Engine/Config/BaseEditorSettings.ini index f0d75687fcd7..834e3bd3c70f 100644 --- a/Engine/Config/BaseEditorSettings.ini +++ b/Engine/Config/BaseEditorSettings.ini @@ -8,16 +8,6 @@ Source=NEWSFEED_Cdn MaxItemsToShow=10 ShowOnlyUnreadItems=True -[/Script/EditorLiveStreaming.EditorLiveStreamingSettings] -FrameRate=30 -ScreenScaling=0.75 -bPrimaryMonitorOnly=true -bEnableWebCam=true -WebCamResolution=Normal_640x480 -bMirrorWebCamImage=false -bCaptureAudioFromComputer=true -bCaptureAudioFromMicrophone=true - [/Script/IntroTutorials.EditorTutorialSettings] +Categories=(Identifier="Basics",Title=NSLOCTEXT("TutorialCategories","BasicsTitle","Basics"),Description=NSLOCTEXT("TutorialCategories","BasicsDescription","Getting started with Unreal Engine 4."),Icon="PlayWorld.RepeatLastPlay",Texture=None,SortOrder=100) +Categories=(Identifier="Blueprints",Title=NSLOCTEXT("TutorialCategories","BlueprintsTitle","Blueprints"),Description=NSLOCTEXT("TutorialCategories","BlueprintsDescription","Tutorials covering the creation and usage of Blueprints."),Icon="FullBlueprintEditor.EditGlobalOptions",Texture=/Engine/Tutorial/BlueprintTutorials/TutorialAssets/Blueprint_64x.Blueprint_64x,SortOrder=200) diff --git a/Engine/Config/BaseEngine.ini b/Engine/Config/BaseEngine.ini index 7698542d3115..35373fdbb8af 100644 --- a/Engine/Config/BaseEngine.ini +++ b/Engine/Config/BaseEngine.ini @@ -61,6 +61,7 @@ DefaultDiffuseTextureName=/Engine/EngineMaterials/DefaultDiffuse.DefaultDiffuse DefaultBSPVertexTextureName=/Engine/EditorResources/BSPVertex.BSPVertex HighFrequencyNoiseTextureName=/Engine/EngineMaterials/Good64x64TilingNoiseHighFreq.Good64x64TilingNoiseHighFreq DefaultBokehTextureName=/Engine/EngineMaterials/DefaultBokeh.DefaultBokeh +DefaultBloomKernelTextureName=/Engine/EngineMaterials/DefaultBloomKernel.DefaultBloomKernel GeomMaterialName=/Engine/EngineDebugMaterials/GeomMaterial.GeomMaterial DebugMeshMaterialName=/Engine/EngineDebugMaterials/DebugMeshMaterial.DebugMeshMaterial PreIntegratedSkinBRDFTextureName=/Engine/EngineMaterials/PreintegratedSkinBRDF.PreintegratedSkinBRDF @@ -204,6 +205,8 @@ bEnableOnScreenDebugMessages=true DurationOfErrorsAndWarningsOnHUD=0 NearClipPlane=10.0 bUseStreamingPause=false +bSuppressWarningOnEmptyMorphTargetAnimation=false + ; Matinee redirects (starts-with match and replace) +MatineeTrackRedirects=(TargetClassName="/Script/Engine.CameraActor",OldFieldName="PostProcessSettings.EyeAdaptationLowPercent",NewFieldName="CameraComponent.PostProcessSettings.AutoExposureLowPercent") @@ -416,6 +419,10 @@ bUseStreamingPause=false +PropertyRedirects=(OldName="Box2D.IsValid",NewName="bIsValid") +; 4.17 + ++PropertyRedirects=(OldName="StaticMesh.bRequiresAreaWeightedSampling",NewName="StaticMesh.bSupportUniformlyDistributedSampling") + [CoreUObject.Metadata] ; Note: UnrealHeaderTool should be rerun after making changes to MetadataRedirects to catch any keys specified in class headers +MetadataRedirects=(OldKey="K2Protected", NewKey="BlueprintProtected") @@ -453,6 +460,7 @@ bSerializeStartupPackagesFromMemory=true bFullyCompressStartupPackages=false +Package=/Engine/EngineMaterials/BlinkingCaret +Package=/Engine/EngineMaterials/DefaultBokeh ++Package=/Engine/EngineMaterials/DefaultBloomKernel +Package=/Engine/EngineMaterials/DefaultDeferredDecalMaterial ;+Package=/Engine/EngineMaterials/DefaultPostProcessMaterial +Package=/Engine/EngineMaterials/DefaultDiffuse @@ -518,7 +526,6 @@ UseSeperateBulkDataFiles=False HangDuration=0.0 [/Script/Engine.StreamingSettings] -s.AsyncIOBandwidthLimit=0 s.MinBulkDataSizeForAsyncLoading=131072 s.AsyncLoadingThreadEnabled=False s.EventDrivenLoaderEnabled=True @@ -604,6 +611,7 @@ AllowPeerConnections=False AllowPeerVoice=False ConnectionTimeout=60.0 InitialConnectTimeout=60.0 +TimeoutMultiplierForUnoptimizedBuilds=1 KeepAliveTime=0.2 MaxClientRate=15000 MaxInternetClientRate=10000 @@ -726,6 +734,7 @@ AutoSaveIndex=0 +PackagesToBeFullyLoadedAtStartup=/Engine/EngineMaterials/BlinkingCaret +PackagesToBeFullyLoadedAtStartup=/Engine/EngineMaterials/DefaultBokeh ++PackagesToBeFullyLoadedAtStartup=/Engine/EngineMaterials/DefaultBloomKernel +PackagesToBeFullyLoadedAtStartup=/Engine/EngineMaterials/DefaultDeferredDecalMaterial ;+PackagesToBeFullyLoadedAtStartup=/Engine/EngineMaterials/DefaultPostProcessMaterial +PackagesToBeFullyLoadedAtStartup=/Engine/EngineMaterials/DefaultDiffuse @@ -905,6 +914,7 @@ ConfigClass= [MemReportCommands] ; These commands are run when memreport is executed, and output to a profile file +Cmd="Mem FromReport" ++Cmd="LogCountedInstances" +Cmd="obj list -alphasort" +Cmd="rhi.DumpMemory" +Cmd="LogOutStatLevels" @@ -990,20 +1000,33 @@ bForceEnabledInEditor=false [OnlineSubsystemAmazon] bEnabled=false +[OnlineSubsystemGoogle] +bEnabled=false + +[OnlineSubsystemGoogle.OnlineIdentityGoogle] +LoginRedirectUrl="http://127.0.0.1" +RedirectPort=9001 + [OnlineSubsystemFacebook] bEnabled=false -[OnlineSubsystemAmazon] -bEnabled=false - [OnlineSubsystemFacebook.OnlineIdentityFacebook] -LoginUrl="https://www.facebook.com/dialog/oauth" +LoginUrl="https://www.facebook.com/v2.8/dialog/oauth" LoginRedirectUrl="https://www.facebook.com/connect/login_success.html" -LoginTimeout=60 +MeURL="https://graph.facebook.com/v2.8/me?access_token=`token" +bUsePopup=false +ProfileFields=locale ++ProfileFields=link ++ProfileFields=gender + +[OnlineSubsystemFacebook.OnlineSharingFacebook] +PermissionsURL="https://graph.facebook.com/v2.8/me/permissions?access_token=`token" [OnlineSubsystemFacebook.OnlineFriendsFacebook] -FriendsUrl="https://graph.facebook.com/me/friends?fields=`fields&access_token=`token" -FriendsFields=gender +FriendsUrl="https://graph.facebook.com/v2.8/me/friends?fields=`fields&access_token=`token" +FriendsFields=locale ++FriendsFields=link ++FriendsFields=gender [OnlineSubsystemNull] bEnabled=true @@ -1461,6 +1484,7 @@ RSyncUsername= SSHPrivateKeyOverridePath= bEnableRemoteNotificationsSupport=False bEnableCloudKitSupport=False +bGenerateCrashReportSymbols=false bAutomaticSigning=false ; These are the defaults for Android settings, and they need to be in the .ini since UBT reads the .ini settings, without instantiating the class @@ -1607,14 +1631,15 @@ NameForGameView5="GameView5" Compressed=False HeapSizeDevelopment=1024 HeapSizeShipping=1024 -TargetWasm=True -TargetWebGL2=True -EnableSIMD=True +TargetAsmjs=True +TargetWebGL1=False +EnableIndexedDB=False +EnableSIMD=False EnableMultithreading=False DeployServerPort=53501 EnableTracing=False -; common browser locations - this will be merged to Editor:Launch(arrow) [/Script/HTML5PlatformEditor.HTML5SDKSettings] +; common browser locations - add your custom locations here [/Script/HTML5PlatformEditor.HTML5Browsers] ; windows +BrowserLauncher=(BrowserName="Nightly(64bit)", BrowserPath=(FilePath="C:/Program Files/Nightly/firefox.exe")) @@ -1622,14 +1647,22 @@ EnableTracing=False +BrowserLauncher=(BrowserName="Firefox(64bit)", BrowserPath=(FilePath="C:/Program Files/Mozilla Firefox/firefox.exe")) +BrowserLauncher=(BrowserName="Firefox", BrowserPath=(FilePath="C:/Program Files (x86)/Mozilla Firefox/firefox.exe")) +BrowserLauncher=(BrowserName="Chrome", BrowserPath=(FilePath="C:/Program Files (x86)/Google/Chrome/Application/chrome.exe")) -; Edge is part of Windows10 -- detection will be special cased... + +; Chrome Canary -- edit path to canary installation location +;+BrowserLauncher=(BrowserName="Canary", BrowserPath=(FilePath="C:/Users/your_username/AppData/Local/Google/Chrome SxS/Application/chrome.exe")) + +; Edge -- uncomment following if you have Windows10 ;+BrowserLauncher=(BrowserName="Edge", BrowserPath=(FilePath="start microsoft-edge:")) + ; osx +BrowserLauncher=(BrowserName="Safari", BrowserPath=(FilePath="/Applications/Safari.app")) +BrowserLauncher=(BrowserName="Firefox", BrowserPath=(FilePath="/Applications/Firefox.app")) +BrowserLauncher=(BrowserName="Chrome", BrowserPath=(FilePath="/Applications/Google Chrome.app")) + ; linux +BrowserLauncher=(BrowserName="Firefox", BrowserPath=(FilePath="/usr/bin/firefox")) ++BrowserLauncher=(BrowserName="Chrome", BrowserPath=(FilePath="/usr/bin/google-chrome")) ++BrowserLauncher=(BrowserName="Chromium", BrowserPath=(FilePath="/usr/bin/chromium-browser")) [/Script/HTML5Networking.WebSocketNetDriver] AllowPeerConnections=False diff --git a/Engine/Config/BaseGame.ini b/Engine/Config/BaseGame.ini index 6371e519b707..c08ebe8d360a 100644 --- a/Engine/Config/BaseGame.ini +++ b/Engine/Config/BaseGame.ini @@ -121,5 +121,7 @@ QueryCountWarningThreshold=0 QueryCountWarningInterval=30.0 [/Script/Engine.AssetManagerSettings] +; These lines should never be changed, due to the way config diffing works if the defaults are changed here games will be broken +; For individual games, they can avoid this issue by replacing -PrimaryAssetTypesToScan lines with !PrimaryAssetTypesToScan=ClearArray +PrimaryAssetTypesToScan=(PrimaryAssetType="Map",AssetBaseClass=/Script/Engine.World,bHasBlueprintClasses=False,bIsEditorOnly=True,Directories=((Path="/Game/Maps"))) +PrimaryAssetTypesToScan=(PrimaryAssetType="PrimaryAssetLabel",AssetBaseClass=/Script/Engine.PrimaryAssetLabel,bHasBlueprintClasses=False,bIsEditorOnly=True,Directories=((Path="/Game"))) diff --git a/Engine/Config/BaseInput.ini b/Engine/Config/BaseInput.ini index e9dfffb20bf6..918db2678fcd 100644 --- a/Engine/Config/BaseInput.ini +++ b/Engine/Config/BaseInput.ini @@ -110,9 +110,9 @@ MaxScrollbackSize=1024 +ManualAutoCompleteList=(Command="MemReport",Desc="Outputs memory stats to a profile file. -Full gives more data, -Log outputs to the log") +ManualAutoCompleteList=(Command="ListTextures",Desc="Lists all loaded textures and their current memory footprint") +ManualAutoCompleteList=(Command="ListStreamingTextures",Desc="Lists info all streaming textures") -+ManualAutoCompleteList=(Command="InvestigateTexture",Desc="shows streaming info about the specified texture") ++ManualAutoCompleteList=(Command="InvestigateTexture",Desc="Shows streaming info about the specified texture") ;placed here so we can type res to restartlevel as we often do that -+ManualAutoCompleteList=(Command="RestartLevel",Desc="restarts the level") ++ManualAutoCompleteList=(Command="RestartLevel",Desc="Restarts the level") ;from Audio.cpp +ManualAutoCompleteList=(Command="Module List",Desc="Lists all known modules") +ManualAutoCompleteList=(Command="Module Load",Desc="Attempts to load the specified module name") @@ -167,6 +167,7 @@ MaxScrollbackSize=1024 +ManualAutoCompleteList=(Command="StartMovieCapture",Desc=) +ManualAutoCompleteList=(Command="StopMovieCapture",Desc=) +ManualAutoCompleteList=(Command="TraceTag",Desc="Draw traces that use the specified tag") ++ManualAutoCompleteList=(Command="TraceTagAll",Desc="Draw all scene queries regardless of the trace tag") +ManualAutoCompleteList=(Command="VisLog",Desc="Launches Log Visualizer tool") +ManualAutoCompleteList=(Command="CycleNavDrawn",Desc="Cycles through navigation data (navmeshes for example) to draw one at a time") +ManualAutoCompleteList=(Command="Log ",Desc=" Change verbosity level for a log category") diff --git a/Engine/Config/BaseScalability.ini b/Engine/Config/BaseScalability.ini index 7cec049c44eb..468646b107f1 100644 --- a/Engine/Config/BaseScalability.ini +++ b/Engine/Config/BaseScalability.ini @@ -114,6 +114,7 @@ r.DistanceFieldAO=1 r.VolumetricFog=1 r.VolumetricFog.GridPixelSize=16 r.VolumetricFog.GridSizeZ=64 +r.VolumetricFog.HistoryMissSupersampleCount=4 [ShadowQuality@3] r.LightFunctionQuality=1 @@ -129,6 +130,7 @@ r.DistanceFieldAO=1 r.VolumetricFog=1 r.VolumetricFog.GridPixelSize=8 r.VolumetricFog.GridSizeZ=128 +r.VolumetricFog.HistoryMissSupersampleCount=4 [ShadowQuality@Cine] r.LightFunctionQuality=1 @@ -144,6 +146,7 @@ r.DistanceFieldAO=1 r.VolumetricFog=1 r.VolumetricFog.GridPixelSize=4 r.VolumetricFog.GridSizeZ=128 +r.VolumetricFog.HistoryMissSupersampleCount=16 ;----------------------------------------------------------------------------------------------------------------- diff --git a/Engine/Config/ConsoleVariables.ini b/Engine/Config/ConsoleVariables.ini index fd5e3180412a..5b4219342524 100644 --- a/Engine/Config/ConsoleVariables.ini +++ b/Engine/Config/ConsoleVariables.ini @@ -32,7 +32,7 @@ [Startup] ; Uncomment to get detailed logs on shader compiles and the opportunity to retry on errors -;r.ShaderDevelopmentMode=1 +; r.ShaderDevelopmentMode=1 ; Uncomment to dump shaders in the Saved folder ; Warning: leaving this on for a while will fill your hard drive with many small files and folders ;r.DumpShaderDebugInfo=1 diff --git a/Engine/Config/IOS/IOSEngine.ini b/Engine/Config/IOS/IOSEngine.ini index 352d71204a78..8812a31949ac 100644 --- a/Engine/Config/IOS/IOSEngine.ini +++ b/Engine/Config/IOS/IOSEngine.ini @@ -3,6 +3,9 @@ gc.MaxObjectsInGame=131072 [Audio] AudioDeviceModuleName=IOSAudio +;Uncomment below and comment out above line to enable new audio mixer +;AudioDeviceModuleName=AudioMixerAudioUnit + ; Defines a platform-specific volume headroom (in dB) for audio to provide better platform consistency with respect to volume levels. PlatformHeadroomDB=0 @@ -29,7 +32,7 @@ NumPreallocatedVertices=200 DefaultPlatformService=IOSLocalNotification [ConsoleVariables] -Slate.CacheRenderData=0 +Slate.CacheRenderData=1 [TextureStreaming] ; PoolSizeVRAMPercentage is how much percentage of GPU Dedicated VRAM should be used as a TexturePool cache for streaming textures (0 - unlimited streaming) diff --git a/Engine/Config/Mac/MacEngine.ini b/Engine/Config/Mac/MacEngine.ini index e2b9ed1d7283..6fa6f3dcf5a4 100644 --- a/Engine/Config/Mac/MacEngine.ini +++ b/Engine/Config/Mac/MacEngine.ini @@ -1,5 +1,8 @@ [Audio] AudioDeviceModuleName=CoreAudio +;Uncomment below and comment out above line to enable new audio mixer +;AudioDeviceModuleName=AudioMixerCoreAudio + ; Defines a platform-specific volume headroom (in dB) for audio to provide better platform consistency with respect to volume levels. PlatformHeadroomDB=-6 diff --git a/Engine/Documentation/Source/Engine/Actors/Actors.INT.udn b/Engine/Documentation/Source/Engine/Actors/Actors.INT.udn index edda92a47a31..e6f8098512ce 100644 --- a/Engine/Documentation/Source/Engine/Actors/Actors.INT.udn +++ b/Engine/Documentation/Source/Engine/Actors/Actors.INT.udn @@ -6,46 +6,9 @@ Navigation:topic parent:Engine/Editor order:5 type:landing +topic-image:Engine/Actors/Placement/actorplacement_topic.png track:LevelDesign_Beginner|7 -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Actors:title%](Engine/Actors/Placement/actorplacement_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors:title% - [/PARAM] - [PARAM:description] - %Engine/Actors:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors] - [/PARAM] -[/OBJECT] -[/VAR] -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Actors:title%](Engine/Actors/Placement/actorplacement_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors:title% - [/PARAM] - [PARAM:description] - %Engine/Actors:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors] - [/PARAM] -[/OBJECT] -[/VAR] [REGION:banner] ![](actorBanner.png) @@ -64,32 +27,9 @@ properties will be modified to cause them to look or behave appropriately. ## Working with Actors -[REGION:topics half] -%Engine/Actors/Placement:topiccompact% -%Engine/Actors/Selection:topiccompact% -%Engine/Actors/Transform:topiccompact% -%Engine/Actors/Grouping:topiccompact% -[/REGION] +[DIR(output:"topic" parent:"Engine/Actors" org:"hierarchy" end:"1" path:"!Engine/Actors/Types")] +## Actor Types -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/levels_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - [](Engine/Actors/Types "%Engine/Actors/Types:description%") - [/PARAM] - [PARAM:links] - * [Static Mesh Actors](Engine/Actors/StaticMeshActor "%Engine/Actors/StaticMeshActor:description%") - * [](Engine/Actors/SkeletalMeshActors "%Engine/Actors/SkeletalMeshActors:description%") - * [Geometry Brush Actors](Engine/Actors/Brushes "%Engine/Actors/Brushes:description%") - * [](Engine/Actors/Volumes "%Engine/Actors/Volumes:description%") - * [](Engine/Actors/Triggers "%Engine/Actors/Triggers:description%") - * [](Engine/Actors/DecalActor "%Engine/Actors/DecalActor:description%") - * [](Engine/Actors/FogEffects "%Engine/Actors/FogEffects:description%") - * [](Engine/Actors/TargetPoint "%Engine/Actors/TargetPoint:description%") - * [](Engine/Actors/Mobility "%Engine/Actors/Mobility:description%") - * [](Engine/Actors/PlayerStart "%Engine/Actors/PlayerStart:description%") - * [](Engine/Actors/CameraActors "%Engine/Actors/CameraActors:description%") - [/PARAM] -[/OBJECT] +%Engine/Actors/Types:topic% +[DIR(output:"topic" parent:"Engine/Actors/Types")] diff --git a/Engine/Documentation/Source/Engine/Actors/Actors.JPN.udn b/Engine/Documentation/Source/Engine/Actors/Actors.JPN.udn index e33fb638c5c0..221f321009a5 100644 --- a/Engine/Documentation/Source/Engine/Actors/Actors.JPN.udn +++ b/Engine/Documentation/Source/Engine/Actors/Actors.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3275878 +NTSourceChangelist:3429225 Availability:Public Title:アクタとジオメトリ Crumbs:%ROOT%, Engine @@ -7,46 +7,9 @@ Navigation:topic parent:Engine/Editor order:5 type:landing +topic-image:Engine/Actors/Placement/actorplacement_topic.png track:LevelDesign_Beginner|7 -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Actors:title%](Engine/Actors/Placement/actorplacement_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors:title% - [/PARAM] - [PARAM:description] - %Engine/Actors:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors] - [/PARAM] -[/OBJECT] -[/VAR] -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Actors:title%](Engine/Actors/Placement/actorplacement_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors:title% - [/PARAM] - [PARAM:description] - %Engine/Actors:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors] - [/PARAM] -[/OBJECT] -[/VAR] [REGION:banner] ![](actorBanner.png) @@ -65,32 +28,9 @@ Light、Static Mesh、Particle System Emitter のアクタやその他、どの ## アクタの作業 -[REGION:topics half] -%Engine/Actors/Placement:topiccompact% -%Engine/Actors/Selection:topiccompact% -%Engine/Actors/Transform:topiccompact% -%Engine/Actors/Grouping:topiccompact% -[/REGION] +[DIR(output:"topic" parent:"Engine/Actors" org:"hierarchy" end:"1" path:"!Engine/Actors/Types")] +## アクタの種類 -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/levels_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - [](Engine/Actors/Types "%Engine/Actors/Types:description%") - [/PARAM] - [PARAM:links] - * [StaticMesh アクタ](Engine/Actors/StaticMeshActor "%Engine/Actors/StaticMeshActor:description%") - * [](Engine/Actors/SkeletalMeshActors "%Engine/Actors/SkeletalMeshActors:description%") - * [Geometry Brush アクタ](Engine/Actors/Brushes "%Engine/Actors/Brushes:description%") - * [](Engine/Actors/Volumes "%Engine/Actors/Volumes:description%") - * [](Engine/Actors/Triggers "%Engine/Actors/Triggers:description%") - * [](Engine/Actors/DecalActor "%Engine/Actors/DecalActor:description%") - * [](Engine/Actors/FogEffects "%Engine/Actors/FogEffects:description%") - * [](Engine/Actors/TargetPoint "%Engine/Actors/TargetPoint:description%") - * [](Engine/Actors/Mobility "%Engine/Actors/Mobility:description%") - * [](Engine/Actors/PlayerStart "%Engine/Actors/PlayerStart:description%") - * [](Engine/Actors/CameraActors "%Engine/Actors/CameraActors:description%") - [/PARAM] -[/OBJECT] +%Engine/Actors/Types:topic% +[DIR(output:"topic" parent:"Engine/Actors/Types")] diff --git a/Engine/Documentation/Source/Engine/Actors/Actors.KOR.udn b/Engine/Documentation/Source/Engine/Actors/Actors.KOR.udn index b62428a40181..27cd5d5532c3 100644 --- a/Engine/Documentation/Source/Engine/Actors/Actors.KOR.udn +++ b/Engine/Documentation/Source/Engine/Actors/Actors.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3275878 +INTSourceChangelist:3429225 Availability:Public Title: 액터 & 지오메트리 Crumbs:%ROOT%, Engine @@ -7,46 +7,9 @@ Navigation:topic parent:Engine/Editor order:5 type:landing +topic-image:Engine/Actors/Placement/actorplacement_topic.png track:LevelDesign_Beginner|7 -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Actors:title%](Engine/Actors/Placement/actorplacement_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors:title% - [/PARAM] - [PARAM:description] - %Engine/Actors:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors] - [/PARAM] -[/OBJECT] -[/VAR] -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Actors:title%](Engine/Actors/Placement/actorplacement_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors:title% - [/PARAM] - [PARAM:description] - %Engine/Actors:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors] - [/PARAM] -[/OBJECT] -[/VAR] [REGION:banner] ![](actorBanner.png) @@ -65,32 +28,9 @@ track:LevelDesign_Beginner|7 ## 액터 작업하기 -[REGION:topics half] -%Engine/Actors/Placement:topiccompact% -%Engine/Actors/Selection:topiccompact% -%Engine/Actors/Transform:topiccompact% -%Engine/Actors/Grouping:topiccompact% -[/REGION] +[DIR(output:"topic" parent:"Engine/Actors" org:"hierarchy" end:"1" path:"!Engine/Actors/Types")] +## 액터 유형 -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/levels_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - [](Engine/Actors/Types "%Engine/Actors/Types:description%") - [/PARAM] - [PARAM:links] - * [스태틱 메시 액터](Engine/Actors/StaticMeshActor "%Engine/Actors/StaticMeshActor:description%") - * [](Engine/Actors/SkeletalMeshActors "%Engine/Actors/SkeletalMeshActors:description%") - * [지오메트리 브러시 액터](Engine/Actors/Brushes "%Engine/Actors/Brushes:description%") - * [](Engine/Actors/Volumes "%Engine/Actors/Volumes:description%") - * [](Engine/Actors/Triggers "%Engine/Actors/Triggers:description%") - * [](Engine/Actors/DecalActor "%Engine/Actors/DecalActor:description%") - * [](Engine/Actors/FogEffects "%Engine/Actors/FogEffects:description%") - * [](Engine/Actors/TargetPoint "%Engine/Actors/TargetPoint:description%") - * [](Engine/Actors/Mobility "%Engine/Actors/Mobility:description%") - * [](Engine/Actors/PlayerStart "%Engine/Actors/PlayerStart:description%") - * [](Engine/Actors/CameraActors "%Engine/Actors/CameraActors:description%") - [/PARAM] -[/OBJECT] +%Engine/Actors/Types:topic% +[DIR(output:"topic" parent:"Engine/Actors/Types")] diff --git a/Engine/Documentation/Source/Engine/Actors/Brushes/Brushes.INT.udn b/Engine/Documentation/Source/Engine/Actors/Brushes/Brushes.INT.udn index 146d953d1440..5e13034029b2 100644 --- a/Engine/Documentation/Source/Engine/Actors/Brushes/Brushes.INT.udn +++ b/Engine/Documentation/Source/Engine/Actors/Brushes/Brushes.INT.udn @@ -6,46 +6,10 @@ Related: Engine/UI/LevelEditor Related: Engine/UI/LevelEditor/Modes Related: Engine/Actors/Volumes version: 4.9 - - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Actors/Brushes:title%](Brushes_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Brushes:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Brushes:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Brushes] - [/PARAM] -[/OBJECT] -[/VAR] -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Actors/Brushes:title%](Brushes_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Brushes:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Brushes:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Brushes] - [/PARAM] -[/OBJECT] -[/VAR] +Parent:Engine/Actors/Types +order:1 +type:overview +topic-image:Brushes_topic.png [TOC (end:2)] diff --git a/Engine/Documentation/Source/Engine/Actors/Brushes/Brushes.JPN.udn b/Engine/Documentation/Source/Engine/Actors/Brushes/Brushes.JPN.udn index e8f28bfe7c64..0cf7e4e6bc1d 100644 --- a/Engine/Documentation/Source/Engine/Actors/Brushes/Brushes.JPN.udn +++ b/Engine/Documentation/Source/Engine/Actors/Brushes/Brushes.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3275367 +INTSourceChangelist:3429227 Availability:Public Title:Geometry Brush アクタ Crumbs:%ROOT%, Engine, Engine/Actors @@ -7,46 +7,10 @@ Related:Engine/UI/LevelEditor Related:Engine/UI/LevelEditor/Modes Related:Engine/Actors/Volumes version:4.9 - - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Actors/Brushes:title%](Brushes_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Brushes:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Brushes:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Brushes] - [/PARAM] -[/OBJECT] -[/VAR] -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Actors/Brushes:title%](Brushes_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Brushes:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Brushes:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Brushes] - [/PARAM] -[/OBJECT] -[/VAR] +Parent:Engine/Actors/Types +order:1 +type:overview +topic-image:Brushes_topic.png [TOC (end:2)] diff --git a/Engine/Documentation/Source/Engine/Actors/Brushes/Brushes.KOR.udn b/Engine/Documentation/Source/Engine/Actors/Brushes/Brushes.KOR.udn index 3201c25e0e7d..3f9d131d3e91 100644 --- a/Engine/Documentation/Source/Engine/Actors/Brushes/Brushes.KOR.udn +++ b/Engine/Documentation/Source/Engine/Actors/Brushes/Brushes.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3275367 +INTSourceChangelist:3429227 Availability: Public Title:지오메트리 브러시 액터 Crumbs:%ROOT%, Engine, Engine/Actors @@ -7,46 +7,10 @@ Related: Engine/UI/LevelEditor Related: Engine/UI/LevelEditor/Modes Related: Engine/Actors/Volumes version: 4.9 - - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Actors/Brushes:title%](Brushes_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Brushes:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Brushes:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Brushes] - [/PARAM] -[/OBJECT] -[/VAR] -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Actors/Brushes:title%](Brushes_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Brushes:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Brushes:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Brushes] - [/PARAM] -[/OBJECT] -[/VAR] +Parent:Engine/Actors/Types +order:1 +type:overview +topic-image:Brushes_topic.png [TOC (end:2)] diff --git a/Engine/Documentation/Source/Engine/Actors/CameraActors/CameraActors.INT.udn b/Engine/Documentation/Source/Engine/Actors/CameraActors/CameraActors.INT.udn index f7d4fdb8fa82..258dd85b7e4b 100644 --- a/Engine/Documentation/Source/Engine/Actors/CameraActors/CameraActors.INT.udn +++ b/Engine/Documentation/Source/Engine/Actors/CameraActors/CameraActors.INT.udn @@ -3,6 +3,9 @@ Title:Camera Actors Crumbs: %ROOT%, Engine, Engine/Actors Description:Guide to placing and using Camera Actors within the Editor. version: 4.9 +Parent:Engine/Actors/Types +order:4 +type:overview ![](CameraActorHeader.png) diff --git a/Engine/Documentation/Source/Engine/Actors/CameraActors/CameraActors.JPN.udn b/Engine/Documentation/Source/Engine/Actors/CameraActors/CameraActors.JPN.udn index 2fee8050b2bf..f857050af060 100644 --- a/Engine/Documentation/Source/Engine/Actors/CameraActors/CameraActors.JPN.udn +++ b/Engine/Documentation/Source/Engine/Actors/CameraActors/CameraActors.JPN.udn @@ -1,8 +1,12 @@ -Availability:Public +INTSourceChangelist:3429227 +Availability:Public Title:Camera アクタ Crumbs: %ROOT%, Engine, Engine/Actors Description:エディタでカメラを配置および使用するためのガイド version:4.9 +Parent:Engine/Actors/Types +order:4 +type:overview ![](CameraActorHeader.png) diff --git a/Engine/Documentation/Source/Engine/Actors/CameraActors/CameraActors.KOR.udn b/Engine/Documentation/Source/Engine/Actors/CameraActors/CameraActors.KOR.udn index b6696816dbef..2ecfb9747f65 100644 --- a/Engine/Documentation/Source/Engine/Actors/CameraActors/CameraActors.KOR.udn +++ b/Engine/Documentation/Source/Engine/Actors/CameraActors/CameraActors.KOR.udn @@ -1,9 +1,12 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429227 Availability: Public Title:카메라 액터 Crumbs: %ROOT%, Engine, Engine/Actors Description:에디터 안에서 카메라 액터를 배치하고 사용하는 방법 안내서입니다. version: 4.9 +Parent:Engine/Actors/Types +order:4 +type:overview ![](CameraActorHeader.png) diff --git a/Engine/Documentation/Source/Engine/Actors/DecalActor/DecalUserGuide.INT.udn b/Engine/Documentation/Source/Engine/Actors/DecalActor/DecalUserGuide.INT.udn index 55645917c5e9..bde674c7a396 100644 --- a/Engine/Documentation/Source/Engine/Actors/DecalActor/DecalUserGuide.INT.udn +++ b/Engine/Documentation/Source/Engine/Actors/DecalActor/DecalUserGuide.INT.udn @@ -3,47 +3,12 @@ Title:Decal Actor User Guide Crumbs:%ROOT%, Engine, Engine/Actors Description:A guide to using the Deferred Decal actor. Version: 4.9 +Parent:Engine/Actors/Types +order:6 +type:overview +topic-image:decal_topic.png -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Actors/DecalActor:title%](Engine/Actors/DecalActor/decal_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/DecalActor:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/DecalActor:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/DecalActor] - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Actors/DecalActor:title%](Engine/Actors/DecalActor/decal_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/DecalActor:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/DecalActor:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/DecalActor] - [/PARAM] -[/OBJECT] -[/VAR] [TOC(start:2)] diff --git a/Engine/Documentation/Source/Engine/Actors/DecalActor/DecalUserGuide.JPN.udn b/Engine/Documentation/Source/Engine/Actors/DecalActor/DecalUserGuide.JPN.udn index 2e1b352e0dc3..640766791c4d 100644 --- a/Engine/Documentation/Source/Engine/Actors/DecalActor/DecalUserGuide.JPN.udn +++ b/Engine/Documentation/Source/Engine/Actors/DecalActor/DecalUserGuide.JPN.udn @@ -1,50 +1,15 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429227 Availability:Public Title:Decal アクタの操作ガイド Crumbs:%ROOT%, Engine, Engine/Actors Description:Deferred Decal アクタの操作ガイド Version:4.9 +Parent:Engine/Actors/Types +order:6 +type:overview +topic-image:decal_topic.png -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Actors/DecalActor:title%](Engine/Actors/DecalActor/decal_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/DecalActor:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/DecalActor:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/DecalActor] - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Actors/DecalActor:title%](Engine/Actors/DecalActor/decal_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/DecalActor:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/DecalActor:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/DecalActor] - [/PARAM] -[/OBJECT] -[/VAR] [TOC(start:2)] diff --git a/Engine/Documentation/Source/Engine/Actors/DecalActor/DecalUserGuide.KOR.udn b/Engine/Documentation/Source/Engine/Actors/DecalActor/DecalUserGuide.KOR.udn index ab09faa1c78e..20b93afd7c71 100644 --- a/Engine/Documentation/Source/Engine/Actors/DecalActor/DecalUserGuide.KOR.udn +++ b/Engine/Documentation/Source/Engine/Actors/DecalActor/DecalUserGuide.KOR.udn @@ -1,56 +1,143 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429227 Availability:Public +Title:Decal Actor User Guide +Crumbs:%ROOT%, Engine, Engine/Actors +Description:A guide to using the Deferred Decal actor. +Version: 4.9 +Parent:Engine/Actors/Types +order:6 +type:overview +topic-image:decal_topic.png + + +[TOC(start:2)] + + +Deferred decals offer better performance and easier maintenance. Writing to the GBuffer instead of recalculating lighting has several benefits: + +* The performance with many lights gets much more predictable because there is no limit on the light count or type as the same code path is used for all of them. +* Manipulating a screen space mask also allows effects that otherwise would be considered difficult (e.g. wet layer). + + +The decal is rendered by rendering a box around the decal affecting area. + +## Adding decals to the level + +The easiest way to add decals to a scene is to select an appropriate decal material in the **Content Browser**, then **right-click** inside the Viewport and choose **Place Actor** from the context menu. The decal may then be resized and oriented using the transformation tools. + +![Decal_1.png](Decal_1.png)(w:720) + + +## Sizing, tiling and offsetting + +Once the decal is created, it can be positioned and oriented using the translation and rotation widgets. + +![Decal_2.png](Decal_2.png)(w:720) + +The non-uniform scaling widget controls the width, height, and far-plane distance of the decal volume. + + +## Deferred Decal Properties + +A deferred decal has only a couple of properties: + +| Item | Description | +|--- | --- | +|**Material**| This holds the material that will be used as a decal. | +|**Sort Order** | This allows the user to set a value to control how multiple decals will sort when stacked. Higher values render on top. | + +[REGION:warning] + Be careful when setting sort values. Setting too many sort values on too many different decals prevents those decals from being sorted via state, which can harm performance. +[/REGION] + +## Material Settings + +The **DecalBlendMode** setting defines how the material properties (diffuse, specular, normal, opacity, ...) are applied to the GBuffer. + +The opacity is used to blend the decal contribution. An efficient decal is manipulating only few GBuffer properties. +The cases we currently optimize for are represented by the other modes: **_DBM_Diffuse_**, **_DBM_Specular_**, **_DBM_Emissive_**, **_DBM_Normal_**. + +| Item | Description | +|--- | --- | +| **Translucent** | This will blend the full material, updating the GBuffer, and does not work for baked lighting. | +| **Stain** | This is Modulate BaseColor, blend rest, updating the GBuffer, and does not work for baked lighting. | +| **Normal** | This will only blend normal, updating the GBuffer, and does not work for baked lighting. | +| **Emissive** | This is for Additive emissive only. | +| **DBuffer_Translucent Color, Normal, Roughness** | This is for non-metal, put into DBuffer to work for baked lighting as well. This will become DBM_TranslucentNormal if normal is not hooked up. | +| **DBuffer_Translucent Color** | This is for non-metal, put into DBuffer to work for baked lighting as well. | +| **DBuffer_Translucent Color, Normal** | This is for non-metal, put into the DBuffer to work for baked lighting as well. This will become DBM_DBuffer_Color if normal is not hooked up. | +| **DBuffer_Translucent Color, Roughness** | This is for non-metal, put into DBuffer to work for baked lighting as well. | +| **DBuffer_Translucent Normal** | This is for non-metal, put into DBuffer to work for baked lighting as well. | +| **DBuffer_Translucent Normal, Roughness** | This is for non-metal, put into DBuffer to work for baked lighting as well. This will become DBM_DBuffer_Roughness if normal is not hooked up. | +| **DBuffer_Translucent Roughness** | This is for non-metal, put into DBuffer to work for baked lighting as well. | +| **Volumetric Distance Function (experimental)** | This will output a signed distance in Opacity depending on LightVector. | + + +**_DBM_ScreenSpaceMask_** is special as it affects a special masking channel which is currently used by SSAO (Ambient Occlusion). This allows the decal to override or fade the contribution in some areas. + +**_DBM_DiffuseSpecularEmissive_** is the mode that affects multiple GBuffer channels. + +Note that the material blend mode also affects how the GBuffer values are blended together. So it is possible to multiply the diffuse color. + +You can use the GBuffer view mode to inspect the GBuffer values that are stored per pixel. + +The decal local position is a 3d position in the range 0 to 1. The texture UV is giving you the x and y component. In case you need the z component, you can hook up a CameraVector node to get all 3 vector components. + +## Performance + +The mesh complexity of the objects affected by the decal is not affecting the performance. The decal performance depends on the shader complexity and the shader box size on the screen. + +We can further improve the per decal performance. Ideally the bounding box of the decal is small to get better per pixel performance. This can be done manually. An automated method is possible but a good designer can also adjust the placement to improve performance further. + + +The view mode **ShaderComplexity** (editor UI or "viewmode ShaderComplexity") can be used to see the impact on the pixel shading cost, it uses a pixel shader cost estimate and accumulates where multiple decals overlap. +At the moment the decal masking feature has no effect there (masked parts should have a small constant cost because of using the stencil hardware feature). +The following shows a scene without (left) and with decals (right), in normal rendering (top) and with the ShaderComplexity enabled (bottom): + +![](DecalShaderComplexity.jpg) + +The darker color indicates a higher performance cost of those pixels. This information can be used to optimize the right shaders, remove barely visible decals or place them more efficiently. + +## Current limitations + +* We currently only support deferred decals and they only work on static objects. +* Normal blending is currently not wrapping around the object. +* Streaming is not yet hooked up so make sure the texture is not streamed. +* Masking decals (not affecting other object) is not fully implemented. + +## The 2x2 block artifacts fix + +Decals may have 2x2 pixels block artifacts on edges as shown in the screenshot below. + +![](2x2_artifacts.bmp) + +This is where the node "Decal Derivative" comes in. This node must be used carefully as it has a very big performance impact. It returns the derivatives on the X and Y axis of the decal's default texture coordinates necessary for anisotropic texture filtering, but computed differently than using the hardware's default and DDX/DDY nodes, to avoid this 2x2 pixel block artifact. + +![](Decal_Derivative.png) + +And using it fixes the artifacts on the decal that benefits from it. + +![](2x2_no_artifacts.bmp) + +### Current limitations + +* DecalMipmapLevel doesn't support custom UV, but you can patch up its output.Availability:Public Title:데칼 액터 사용 안내서 Crumbs:%ROOT%, Engine, Engine/Actors Description:Deferred Decal, 디퍼드 데칼 액터 사용 안내서입니다. Version: 4.9 +Parent:Engine/Actors/Types +order:6 +type:overview +topic-image:decal_topic.png -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Actors/DecalActor:title%](Engine/Actors/DecalActor/decal_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/DecalActor:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/DecalActor:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/DecalActor] - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Actors/DecalActor:title%](Engine/Actors/DecalActor/decal_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/DecalActor:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/DecalActor:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/DecalActor] - [/PARAM] -[/OBJECT] -[/VAR] [TOC(start:2)] Deferred decal (디퍼드 데칼)은 향상된 퍼포먼스에 관리도 더욱 쉽습니다. 라이팅을 재계산하지 않고 GBuffer 에 쓸 수 있다는 것은 여러가지 장점이 있습니다: -* 라이트의 갯수나 유형이 얼마나 되든, 그 전부에 같은 코드 패쓰가 사용되기에, 라이트가 많은 환경에서의 퍼포먼스 예측이 훨씬 쉬워집니다. +* 라이트의 갯수나 유형이 얼마나 되든, 그 전부에 같은 코드 패스가 사용되기에, 라이트가 많은 환경에서의 퍼포먼스 예측이 훨씬 쉬워집니다. * 스크린 스페이스 마스크 조작을 통해 (젖은 레이어 등) 다른 방식으로는 만들어내기 어려운 이펙트가 쉽게 가능합니다. diff --git a/Engine/Documentation/Source/Engine/Actors/FogEffects/FogEffects.JPN.udn b/Engine/Documentation/Source/Engine/Actors/FogEffects/FogEffects.JPN.udn index 1f116e7fd874..aa4e56e89a38 100644 --- a/Engine/Documentation/Source/Engine/Actors/FogEffects/FogEffects.JPN.udn +++ b/Engine/Documentation/Source/Engine/Actors/FogEffects/FogEffects.JPN.udn @@ -1,4 +1,5 @@ -Availability:Public +INTSourceChangelist:3429227 +Availability:Public Title:フォグ エフェクト Crumbs: %ROOT%, Engine Description:フォグを使用してワールドの周囲の環境を加えて背景の雰囲気を作ります。 diff --git a/Engine/Documentation/Source/Engine/Actors/FogEffects/FogEffects.KOR.udn b/Engine/Documentation/Source/Engine/Actors/FogEffects/FogEffects.KOR.udn index 086b54e19469..b12901f324b8 100644 --- a/Engine/Documentation/Source/Engine/Actors/FogEffects/FogEffects.KOR.udn +++ b/Engine/Documentation/Source/Engine/Actors/FogEffects/FogEffects.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3151855 +INTSourceChangelist:3429227 Availability: Public Title:포그 이펙트 Crumbs: %ROOT%, Engine diff --git a/Engine/Documentation/Source/Engine/Actors/Grouping/Grouping.INT.udn b/Engine/Documentation/Source/Engine/Actors/Grouping/Grouping.INT.udn index ae02082a0398..98162e6d7826 100644 --- a/Engine/Documentation/Source/Engine/Actors/Grouping/Grouping.INT.udn +++ b/Engine/Documentation/Source/Engine/Actors/Grouping/Grouping.INT.udn @@ -3,46 +3,10 @@ Title:Grouping Actors Crumbs:%ROOT%, Engine, Engine/Actors Description:Guide to creating and working with groups of actors within Unreal Editor. version: 4.9 - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Actors/Grouping:title%](Engine/Actors/Grouping/actorgrouping_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Grouping:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Grouping:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Grouping] - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Actors/Grouping:title%](Engine/Actors/Grouping/actorgrouping_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Grouping:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Grouping:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Grouping] - [/PARAM] -[/OBJECT] -[/VAR] +parent:Engine/Actors +type:overview +order:5 +topic-image:actorgrouping_topic.png [TOC(start:2)] diff --git a/Engine/Documentation/Source/Engine/Actors/Grouping/Grouping.JPN.udn b/Engine/Documentation/Source/Engine/Actors/Grouping/Grouping.JPN.udn index 71b02079e77a..47852fd1a4c3 100644 --- a/Engine/Documentation/Source/Engine/Actors/Grouping/Grouping.JPN.udn +++ b/Engine/Documentation/Source/Engine/Actors/Grouping/Grouping.JPN.udn @@ -1,49 +1,13 @@ -INTSourceChangelist:3275202 +INTSourceChangelist:3429227 Availability:Public Title:アクタのグループ化 Crumbs:%ROOT%, Engine, Engine/Actors Description:アンリアル エディタ内でアクタのグループを作成および操作するためのガイド version:4.9 - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Actors/Grouping:title%](Engine/Actors/Grouping/actorgrouping_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Grouping:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Grouping:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Grouping] - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Actors/Grouping:title%](Engine/Actors/Grouping/actorgrouping_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Grouping:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Grouping:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Grouping] - [/PARAM] -[/OBJECT] -[/VAR] +parent:Engine/Actors +type:overview +order:5 +topic-image:actorgrouping_topic.png [TOC(start:2)] @@ -52,7 +16,7 @@ version:4.9 アクタをグループ化することで、同時に複数アクタを容易に管理できます。グループ化されたアクタは、回転、平行移動、スケーリングで、まとめて変形できます。グループのロックを解除して、個々のアクタを一時的に操作することができます。再びグループをロックすると、グループ内のアクタをグループ化して、個々のアクタが変形されないようにすることができます。アクタをグループへ追加またはグループから削除することができます。別のグループのメンバーとして 1 つのグループを持つことでグループをネストする事も可能です。 [REGION:note] -アクタが 1 度に属することのできるグループは 1 つだけです。ただし、大きなグループ内にグループそのものがネストしている場合はこの限りではありません。 +アクタが一度に属することのできるグループは 1 つだけです。ただし、大きなグループ内にグループそのものがネストしている場合はこの限りではありません。 [/REGION] ## アクタのグループ化 diff --git a/Engine/Documentation/Source/Engine/Actors/Grouping/Grouping.KOR.udn b/Engine/Documentation/Source/Engine/Actors/Grouping/Grouping.KOR.udn index a9705f1b123c..40fcd4dfdadd 100644 --- a/Engine/Documentation/Source/Engine/Actors/Grouping/Grouping.KOR.udn +++ b/Engine/Documentation/Source/Engine/Actors/Grouping/Grouping.KOR.udn @@ -1,49 +1,13 @@ -INTSourceChangelist:3275202 +INTSourceChangelist:3429227 Availability: Public Title:액터 그룹 Crumbs:%ROOT%, Engine, Engine/Actors Description:언리얼 에디터에서 액터 그룹 관련 작업을 하는 방법 안내서입니다. version: 4.9 - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Actors/Grouping:title%](Engine/Actors/Grouping/actorgrouping_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Grouping:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Grouping:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Grouping] - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Actors/Grouping:title%](Engine/Actors/Grouping/actorgrouping_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Grouping:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Grouping:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Grouping] - [/PARAM] -[/OBJECT] -[/VAR] +parent:Engine/Actors +type:overview +order:5 +topic-image:actorgrouping_topic.png [TOC(start:2)] diff --git a/Engine/Documentation/Source/Engine/Actors/Merging/ActorMerging.INT.udn b/Engine/Documentation/Source/Engine/Actors/Merging/ActorMerging.INT.udn index 0b9bb37addea..d94a3c8b3336 100644 --- a/Engine/Documentation/Source/Engine/Actors/Merging/ActorMerging.INT.udn +++ b/Engine/Documentation/Source/Engine/Actors/Merging/ActorMerging.INT.udn @@ -4,8 +4,9 @@ Crumbs: %ROOT%, Engine, Engine/Actors, Engine/Actors/Merging Description:How to use the Actor Merge tool to combine multiple Static Meshes into one in UE4. Related: Engine/Actors/StaticMeshActor Version: 4.12 - - +parent:Engine/Actors +type:overview +order:6 [TOC(start:2 end:2)] @@ -15,7 +16,33 @@ The Merge Actors tool enables the user to combine multiple Static Meshes into a The Merge Actor feature is officially supported in 4.12 and later. In 4.8 to 4.11, it must be activated from the Editor Settings under the Experimental tab. If you are using a version of the engine earlier than 4.12, this feature is considered experimental and is not officially supported. [/REGION] -![](MergeActorsWindow.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](MergeActors_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](MergeActors_Mac.png) +[/PARAM] +[/OBJECT] ## Actor Merging Worklow diff --git a/Engine/Documentation/Source/Engine/Actors/Merging/ActorMerging.JPN.udn b/Engine/Documentation/Source/Engine/Actors/Merging/ActorMerging.JPN.udn index 2c6b08e49e3a..a06369255d8f 100644 --- a/Engine/Documentation/Source/Engine/Actors/Merging/ActorMerging.JPN.udn +++ b/Engine/Documentation/Source/Engine/Actors/Merging/ActorMerging.JPN.udn @@ -1,12 +1,13 @@ -INTSourceChangelist:3122737 -Availability: Public +INTSourceChangelist:3481084 +Availability:Public Title:アクタのマージ Crumbs: %ROOT%, Engine, Engine/Actors, Engine/Actors/Merging Description:Actor の Merge ツールを使って、UE4 で複数のスタティックメッシュをひとつに結合します。 Related:Engine/Actors/StaticMeshActor Version:4.12 - - +parent:Engine/Actors +type:overview +order:6 [TOC(start:2 end:2)] @@ -16,7 +17,33 @@ Merge Actors ツールを使用すると、複数のスタティックメッシ この Merge Actor 機能は 4.12 以降、公式にサポートされるようになりました。4.8 から 4.11 では、エディタ設定の [Experimental] タブからアクティベートしなければなりません。4.12 よりも前のバージョンのエンジンを使用している場合、この機能は実験的なものとみなされ、公式にはサポートされていません。 [/REGION] -![](MergeActorsWindow.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](MergeActors_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](MergeActors_Mac.png) +[/PARAM] +[/OBJECT] ## アクタのマージのワークフロー diff --git a/Engine/Documentation/Source/Engine/Actors/Merging/ActorMerging.KOR.udn b/Engine/Documentation/Source/Engine/Actors/Merging/ActorMerging.KOR.udn index 0011459f6ad0..b1222d87f170 100644 --- a/Engine/Documentation/Source/Engine/Actors/Merging/ActorMerging.KOR.udn +++ b/Engine/Documentation/Source/Engine/Actors/Merging/ActorMerging.KOR.udn @@ -1,12 +1,13 @@ -INTSourceChangelist:3122737 +INTSourceChangelist:3481084 Availability: Public Title:액터 병합 Crumbs: %ROOT%, Engine, Engine/Actors, Engine/Actors/Merging Description:UE4 에서 다수의 스태틱 메시를 하나로 합치는 데 사용되는 Actor Merge, 액터 병합 툴 사용법입니다. Related: Engine/Actors/StaticMeshActor Version: 4.12 - - +parent:Engine/Actors +type:overview +order:6 [TOC(start:2 end:2)] @@ -16,7 +17,33 @@ Merge Actors (액터 병합) 툴은 다수의 스태틱 메시를 하나의 새 액터 병합 기능은 4.12 버전 이후로 공식 지원됩니다. 4.8 에서 4.11 까지는 에디터 세팅의 실험단계 탭에서 켜줘야 합니다. 4.12 이전 버전을 사용하시는 경우, 이 기능은 실험단계 기능으로 간주되어 공식 지원되지 않습니다. [/REGION] -![](MergeActorsWindow.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](MergeActors_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](MergeActors_Mac.png) +[/PARAM] +[/OBJECT] ## 액터 병합 작업방식 diff --git a/Engine/Documentation/Source/Engine/Actors/Mobility/ActorMobility.INT.udn b/Engine/Documentation/Source/Engine/Actors/Mobility/ActorMobility.INT.udn index 5316a8b90b98..9409f9c6b226 100644 --- a/Engine/Documentation/Source/Engine/Actors/Mobility/ActorMobility.INT.udn +++ b/Engine/Documentation/Source/Engine/Actors/Mobility/ActorMobility.INT.udn @@ -3,6 +3,10 @@ Title:Actor Mobility Crumbs: %ROOT%, Engine, Engine/Actors Description:Setting that controls whether an Actor will be allowed to move or change in some way during gameplay. version: 4.9 +parent:Engine/Actors +type:overview +order:4 + [EXCERPT:Intro] ![](TransformMobility.png) diff --git a/Engine/Documentation/Source/Engine/Actors/Mobility/ActorMobility.JPN.udn b/Engine/Documentation/Source/Engine/Actors/Mobility/ActorMobility.JPN.udn index 485c6d33026b..6998a0161186 100644 --- a/Engine/Documentation/Source/Engine/Actors/Mobility/ActorMobility.JPN.udn +++ b/Engine/Documentation/Source/Engine/Actors/Mobility/ActorMobility.JPN.udn @@ -1,9 +1,13 @@ -INTSourceChangelist:3275202 +INTSourceChangelist:3429227 Availability:Public Title:アクタの可動性 Crumbs: %ROOT%, Engine, Engine/Actors Description:ゲームプレイ中のアクタの移動や変更を制御します。 version:4.9 +parent:Engine/Actors +type:overview +order:4 + [EXCERPT:Intro] ![](TransformMobility.png) diff --git a/Engine/Documentation/Source/Engine/Actors/Mobility/ActorMobility.KOR.udn b/Engine/Documentation/Source/Engine/Actors/Mobility/ActorMobility.KOR.udn index 9ecdbd3543bf..29c8d3f15a4c 100644 --- a/Engine/Documentation/Source/Engine/Actors/Mobility/ActorMobility.KOR.udn +++ b/Engine/Documentation/Source/Engine/Actors/Mobility/ActorMobility.KOR.udn @@ -1,9 +1,13 @@ -INTSourceChangelist:3275202 +INTSourceChangelist:3429227 Availability:Public Title:액터 모빌리티 Crumbs: %ROOT%, Engine, Engine/Actors Description:액터를 게임플레이 도중 어떤 방식으로 이동 또는 변화할 수 있도록 할지를 제어하는 세팅입니다. version: 4.9 +parent:Engine/Actors +type:overview +order:4 + [EXCERPT:Intro] ![](TransformMobility.png) diff --git a/Engine/Documentation/Source/Engine/Actors/Placement/PlacingActors.INT.udn b/Engine/Documentation/Source/Engine/Actors/Placement/PlacingActors.INT.udn index f0d812f37b59..7fc835d1aacb 100644 --- a/Engine/Documentation/Source/Engine/Actors/Placement/PlacingActors.INT.udn +++ b/Engine/Documentation/Source/Engine/Actors/Placement/PlacingActors.INT.udn @@ -5,47 +5,12 @@ Description:Shows how you can place Actors such as props, lights, cameras, etc. Related: Engine/UI/ClassViewer Related: GettingStarted\HowTo version: 4.9 +Parent:Engine/Actors +type:overview +order:1 +topic-image:actorplacement_topic.png track:LevelDesign_Beginner|8 -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Actors/Placement:title%](Engine/Actors/Placement/actorplacement_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Placement:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Placement:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Placement] - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Actors/Placement:title%](Engine/Actors/Placement/actorplacement_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Placement:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Placement:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Placement] - [/PARAM] -[/OBJECT] -[/VAR] At the most fundamental level, an **Actor** is any Object that you can place in a level and this page will show you the various methods in which you can place those Actors inside your levels. diff --git a/Engine/Documentation/Source/Engine/Actors/Placement/PlacingActors.JPN.udn b/Engine/Documentation/Source/Engine/Actors/Placement/PlacingActors.JPN.udn index abeec728005d..15e40cd05455 100644 --- a/Engine/Documentation/Source/Engine/Actors/Placement/PlacingActors.JPN.udn +++ b/Engine/Documentation/Source/Engine/Actors/Placement/PlacingActors.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3275878 +INTSourceChangelist:3429227 Availability:Public Title:アクタの配置 Crumbs: %ROOT%, Engine, Engine/Actors @@ -6,47 +6,12 @@ Description:プロップ、ライト、カメラなどのアクタをレベル Related:Engine/UI/ClassViewer Related:GettingStarted\HowTo version:4.9 +Parent:Engine/Actors +type:overview +order:1 +topic-image:actorplacement_topic.png track:LevelDesign_Beginner|8 -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Actors/Placement:title%](Engine/Actors/Placement/actorplacement_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Placement:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Placement:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Placement] - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Actors/Placement:title%](Engine/Actors/Placement/actorplacement_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Placement:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Placement:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Placement] - [/PARAM] -[/OBJECT] -[/VAR] 最も基本的なレベルでは、 **アクタ** はレベルに配置可能なオブジェクトです。このページではアクタをレベルに配置する様々な方法について説明します。 diff --git a/Engine/Documentation/Source/Engine/Actors/Placement/PlacingActors.KOR.udn b/Engine/Documentation/Source/Engine/Actors/Placement/PlacingActors.KOR.udn index a5b6eab1af99..325c6d6f83b2 100644 --- a/Engine/Documentation/Source/Engine/Actors/Placement/PlacingActors.KOR.udn +++ b/Engine/Documentation/Source/Engine/Actors/Placement/PlacingActors.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3275878 +INTSourceChangelist:3429227 Availability:Public Title:액터 배치하기 Crumbs: %ROOT%, Engine, Engine/Actors @@ -6,47 +6,12 @@ Description:레벨에 소품, 라이트, 카메라와 같은 액터를 배치하 Related: Engine/UI/ClassViewer Related: GettingStarted\HowTo version: 4.9 +Parent:Engine/Actors +type:overview +order:1 +topic-image:actorplacement_topic.png track:LevelDesign_Beginner|8 -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Actors/Placement:title%](Engine/Actors/Placement/actorplacement_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Placement:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Placement:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Placement] - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Actors/Placement:title%](Engine/Actors/Placement/actorplacement_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Placement:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Placement:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Placement] - [/PARAM] -[/OBJECT] -[/VAR] 가장 근본적인 수준에서 **Actor**, 액터란 레벨에 배치할 수 있는 오브젝트를 말하며, 여기서는 레벨에 그러한 액터를 배치할 수 있는 여러가지 방법을 보여드리겠습니다. diff --git a/Engine/Documentation/Source/Engine/Actors/PlayerStart/PlayerStart.INT.udn b/Engine/Documentation/Source/Engine/Actors/PlayerStart/PlayerStart.INT.udn index c4e0ed5100af..eeb865815b0c 100644 --- a/Engine/Documentation/Source/Engine/Actors/PlayerStart/PlayerStart.INT.udn +++ b/Engine/Documentation/Source/Engine/Actors/PlayerStart/PlayerStart.INT.udn @@ -3,6 +3,9 @@ Title:Player Start Crumbs: %ROOT%, Engine, Engine/Actors Description:Guide to using Player Starts. version: 4.9 +Parent:Engine/Actors/Types +order:5 +type:overview ![](Player_Start_Actor.png) diff --git a/Engine/Documentation/Source/Engine/Actors/PlayerStart/PlayerStart.JPN.udn b/Engine/Documentation/Source/Engine/Actors/PlayerStart/PlayerStart.JPN.udn index 092b89755b71..1796145085e7 100644 --- a/Engine/Documentation/Source/Engine/Actors/PlayerStart/PlayerStart.JPN.udn +++ b/Engine/Documentation/Source/Engine/Actors/PlayerStart/PlayerStart.JPN.udn @@ -1,8 +1,12 @@ -Availability:Public +INTSourceChangelist:3429227 +Availability:Public Title:Player Start Crumbs: %ROOT%, Engine, Engine/Actors Description:Player Start 使用のガイド version:4.9 +Parent:Engine/Actors/Types +order:5 +type:overview ![](Player_Start_Actor.png) diff --git a/Engine/Documentation/Source/Engine/Actors/PlayerStart/PlayerStart.KOR.udn b/Engine/Documentation/Source/Engine/Actors/PlayerStart/PlayerStart.KOR.udn index 299e4944e154..8891627dca39 100644 --- a/Engine/Documentation/Source/Engine/Actors/PlayerStart/PlayerStart.KOR.udn +++ b/Engine/Documentation/Source/Engine/Actors/PlayerStart/PlayerStart.KOR.udn @@ -1,9 +1,12 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429227 Availability: Public Title:플레이어 스타트 Crumbs: %ROOT%, Engine, Engine/Actors Description:Player Start, 플레이어 스타트 사용 안내서입니다. version: 4.9 +Parent:Engine/Actors/Types +order:5 +type:overview ![](Player_Start_Actor.png) diff --git a/Engine/Documentation/Source/Engine/Actors/Selection/ActorSelection.INT.udn b/Engine/Documentation/Source/Engine/Actors/Selection/ActorSelection.INT.udn index c471b9c0ac77..ff111892b145 100644 --- a/Engine/Documentation/Source/Engine/Actors/Selection/ActorSelection.INT.udn +++ b/Engine/Documentation/Source/Engine/Actors/Selection/ActorSelection.INT.udn @@ -3,46 +3,10 @@ Title:Selecting Actors Crumbs: %ROOT%, Engine, Engine/Actors Description:Overview of methods available for selecting Actors in the Level Editor viewports. version: 4.9 - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Actors/Selection:title%](Engine/Actors/Selection/actorselection_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Selection:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Selection:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Selection] - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Actors/Selection:title%](Engine/Actors/Selection/actorselection_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Selection:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Selection:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Selection] - [/PARAM] -[/OBJECT] -[/VAR] +Parent:Engine/Actors +type:overview +order:2 +topic-image:actorselection_topic.png [TOC(start:2)] diff --git a/Engine/Documentation/Source/Engine/Actors/Selection/ActorSelection.JPN.udn b/Engine/Documentation/Source/Engine/Actors/Selection/ActorSelection.JPN.udn index 138d5357d99b..4770eff9b0df 100644 --- a/Engine/Documentation/Source/Engine/Actors/Selection/ActorSelection.JPN.udn +++ b/Engine/Documentation/Source/Engine/Actors/Selection/ActorSelection.JPN.udn @@ -1,49 +1,13 @@ -INTSourceChangelist:3275202 +INTSourceChangelist:3429227 Availability:Public Title:アクタの選択 Crumbs: %ROOT%, Engine, Engine/Actors Description:レベルエディタのビューポートでアクタを選択するために利用可能な方法の概要 version:4.9 - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Actors/Selection:title%](Engine/Actors/Selection/actorselection_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Selection:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Selection:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Selection] - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Actors/Selection:title%](Engine/Actors/Selection/actorselection_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Selection:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Selection:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Selection] - [/PARAM] -[/OBJECT] -[/VAR] +Parent:Engine/Actors +type:overview +order:2 +topic-image:actorselection_topic.png [TOC(start:2)] diff --git a/Engine/Documentation/Source/Engine/Actors/Selection/ActorSelection.KOR.udn b/Engine/Documentation/Source/Engine/Actors/Selection/ActorSelection.KOR.udn index 28d122cd2732..1da7f6fab8a8 100644 --- a/Engine/Documentation/Source/Engine/Actors/Selection/ActorSelection.KOR.udn +++ b/Engine/Documentation/Source/Engine/Actors/Selection/ActorSelection.KOR.udn @@ -1,49 +1,13 @@ -INTSourceChangelist:3275202 +INTSourceChangelist:3429227 Availability:Public Title:액터 선택 Crumbs: %ROOT%, Engine, Engine/Actors Description:레벨 에디터 뷰포트에서 액터를 선택하는 데 사용할 수 있는 방법에 대한 개요입니다. version: 4.9 - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Actors/Selection:title%](Engine/Actors/Selection/actorselection_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Selection:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Selection:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Selection] - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Actors/Selection:title%](Engine/Actors/Selection/actorselection_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Selection:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Selection:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Selection] - [/PARAM] -[/OBJECT] -[/VAR] +Parent:Engine/Actors +type:overview +order:2 +topic-image:actorselection_topic.png [TOC(start:2)] diff --git a/Engine/Documentation/Source/Engine/Actors/SkeletalMeshActors/SkeletalMeshActors.INT.udn b/Engine/Documentation/Source/Engine/Actors/SkeletalMeshActors/SkeletalMeshActors.INT.udn index aa5b47fbb76f..7d3839bdd7c5 100644 --- a/Engine/Documentation/Source/Engine/Actors/SkeletalMeshActors/SkeletalMeshActors.INT.udn +++ b/Engine/Documentation/Source/Engine/Actors/SkeletalMeshActors/SkeletalMeshActors.INT.udn @@ -5,7 +5,9 @@ Description:Creating and using Skeletal Mesh Actors Related: Engine/Actors Related: Engine/Animation version: 4.9 - +Parent:Engine/Actors/Types +order:3 +type:overview [TOC(start:2 end:3)] @@ -34,7 +36,7 @@ You can drag and drop Skeletal Mesh Actors right from the **Content Browser** ri 1. Release the **Left Mouse Button** to place the mesh in the map as a Skeletal Mesh, as seen in the **Details** panel. -![](Skeletal_Mesh_Drag_&_Drop.gif) +![](SkeletalMeshContextMenu.png) **Context Menus** @@ -46,7 +48,7 @@ You can also place Skeletal Mesh Actors in the world using the **Right-click** c 1. Once the **Place Actor: Skeletal Mesh** option has been clicked on with the mouse, the Skeletal Mesh you selected should now be placed in the scene. -![](Skeletal_Mesh_Context_Menu.gif.gif) +![](SkeletalMeshDragAndDrop.png) ## Playing Animation on a Skeletal Mesh Actor Getting a Skeletal Mesh Actor so that it will animate while the game is running can be done two different ways inside of UE4. You can use an [Animation Blueprint]( Engine/Animation/AnimBlueprints), which will allow you to play and blend multiple animations together. Or you can use and Animation Asset to play a single [Animation Sequence]( Engine/Animation/Sequences). In this tutorial, we will be focusing on using an Animation Sequence to play our animation while the game is running. @@ -98,7 +100,7 @@ To create a Physics Asset for your mesh, all you have to do is simply **Right-cl ### Assigning a Physics Asset Once your Physics Asset has been created, it is now time to assign it to your mesh. Physics Assets can be assigned to Skeletal Meshes by simply opening up the Skeletal Mesh and then assigning the Physics Asset to the **Physics Asset** slot that is under the **Physics** section. -![](SkeletalMeshActor_Add_Physics_Assets.png) +![](SkeletalMeshActor_Assign_Physics_Asset.png) You can also override Physics Assets in your level by simply selecting your Skeletal Mesh and then under the **Physics** section of the **Details** panel, you can supply a new Physics Asset in the **Physics Asset Override** section. diff --git a/Engine/Documentation/Source/Engine/Actors/SkeletalMeshActors/SkeletalMeshActors.JPN.udn b/Engine/Documentation/Source/Engine/Actors/SkeletalMeshActors/SkeletalMeshActors.JPN.udn index bdb6c727f6fa..532d9f6a5cd9 100644 --- a/Engine/Documentation/Source/Engine/Actors/SkeletalMeshActors/SkeletalMeshActors.JPN.udn +++ b/Engine/Documentation/Source/Engine/Actors/SkeletalMeshActors/SkeletalMeshActors.JPN.udn @@ -1,11 +1,14 @@ -Availability:Public +INTSourceChangelist:3481084 +Availability:Public Title:Skeletal Mesh アクタ Crumbs: %ROOT%, Engine, Engine/Actors -Description:Skeletal Mesh アクタを作成して使用する +Description:Skeletal Mesh アクタを作成して使用する Related:Engine/Actors Related:Engine/Animation version:4.9 - +Parent:Engine/Actors/Types +order:3 +type:overview [TOC(start:2 end:3)] @@ -13,47 +16,47 @@ version:4.9 ![](SkeletalMeshActor_Matinee_Example.png) -UE4 を使用するビデオ ゲームでプレイする場合、画面上で制御するキャラクターは多くの場合、**Skeletal Mesh アクタ** と呼ばれる特殊なメッシュで作られています。Skeletal Mesh アクタは、外部の 3D アプリケーションで作られた複雑なアニメーション データを表示するために使用可能であり、UE4 にインポートできる特殊なものです。以下のガイドでは、UE4 で Skeletal Mesh アクタを使用するためのノウハウをご紹介します。 +UE4 を使用するビデオ ゲームでプレイする場合、画面上で制御するキャラクターは多くの場合、**Skeletal Mesh アクタ** と呼ばれる特殊なメッシュで作られています。Skeletal Mesh アクタは、外部の 3D アプリケーションで作られた複雑なアニメーション データを表示し、UE4 にインポートできる特殊なものです。以下のガイドでは、UE4 でスケルタルメッシュ アクタを使用するためのノウハウをご紹介します。 [region:tip] このチュートリアルの全コンテンツは、Matinee のデモのものです。このデモは、Learn (ラーニング) タブから無料ダウンロードできます。 [/region] ## Skeletal Mesh アクタとは何か -Skeletal Mesh アクタは、外部の 3D アニメーション プログラムで作成された複雑なアニメーション データを表示するために使用する特殊なタイプのアクタです。Skeletal Mesh アクタは、Static Mesh アクタとは異なります。Skeletal Mesh アクタは、複雑なスケルトンを持ち、スケルタルメッシュの個々の頂点を、再生中の現在のアニメーションと一致するように動かすのに役立ちます。Skeletal Mesh アクタには複雑なスケルトンを使用する機能があるため、一般的にキャラクター、クリーチャー、複雑な機械など変形や複雑な動きを示す必要があるものに使用します。UE4 では、Skeletal Mesh アクタがキャラクターだけでなく、マチネでシネマティック シーケンスを作成するためにも使用されます。 +Skeletal Mesh アクタは、外部の 3D アニメーション プログラムで作成された複雑なアニメーション データを表示するために使用する特殊なタイプのアクタです。Skeletal Mesh アクタは、Static Mesh アクタとは異なります。Skeletal Mesh アクタは、複雑なスケルトンを持ち、スケルタルメッシュの個々の頂点を、再生中の現在のアニメーションと一致するように動かすのに役立ちます。Skeletal Mesh アクタで複雑なスケルトンを使用する機能があるため、一般的にキャラクター、クリーチャー、複雑な機械など変形や複雑な動きを示す必要があるものに使用されます。UE4 では、Skeletal Mesh アクタがキャラクターだけでなく、マチネでシネマティック シーケンスを作成するためにも使用されます。 ## Skeletal Mesh アクタをレベルに配置する -Skeletal Mesh アクタは一般的なアクタ配置方法を用いてマップに配置します。ビューポートのコンテキストメニューを **右クリック** するか、[コンテンツブラウザ](Engine/Content/Browser) からドラッグ&ドロップして配置します。 +Skeletal Mesh アクタは一般的なアクタ配置方法でマップに配置します。ビューポートで **右クリック** してコンテキストメニューから行うか、[コンテンツ ブラウザ](Engine/Content/Browser) からドラッグ&ドロップして配置します。 **ドラッグ&ドロップ** -以下の手順に従い、**コンテンツ ブラウザ** から Skeletal Mesh アクタを作業するレベルにドラッグ&ドロップできます +以下の手順に従い、**コンテンツ ブラウザ** から Skeletal Mesh アクタをドラッグして、作業するレベルにドロップできます 1. **[コンテンツ ブラウザ]** で、Skeletal Mesh アクタとしてマップへ追加するスケルタルメッシュを探します。 -1. **[コンテンツ ブラウザ]** でスケルタルメッシュを **左クリック** して、ビューポート内のメッシュを配置する位置へドラッグします (この時 **左マウスボタン** は押したままです)。正確な追加位置でなくても構いません。後でいつでも配置しなおしたり、回転することができます。 +1. **[コンテンツ ブラウザ]** でスケルタルメッシュ上で **左クリック** して、ビューポート内のメッシュを配置する位置へドラッグします (この時 **左マウスボタン** は押したままです)。位置は必ずしも正確である必要はありません。後でいつでも再配置、回転、スケーリングできます。 1. **左マウスボタン** を放し、**[Details (詳細)] ** パネルに表示されているように、メッシュをスケルタルメッシュとしてマップへ配置します。 -![](Skeletal_Mesh_Drag_&_Drop.gif) +![](SkeletalMeshContextMenu.png) -** コンテキスト メニュー** +**コンテキスト メニュー** 以下の簡単な手順に従い、**右クリック** してコンテキスト メニューを使用してワールドに Skeletal Mesh アクタを配置することもできます。 -1. **[コンテンツ ブラウザ]** で、Skeletal Mesh アクタとしてレベルへ追加する Skeletal Mesh アクタを選択します。 +1. **[コンテンツ ブラウザ]** で、レベルへ追加する Skeletal Mesh アクタを選択します。 -1. メッシュを追加するビューポート内で **右クリック** して、コンテキスト メニューから、**[Place Actor:Skeletal Mesh]** を選択します。正確な追加位置でなくても構いません。後でいつでも配置しなおしたり、回転することができます。 +1. メッシュを追加するビューポート内で **右クリック** して、コンテキストメニューから、**[Place Actor:Skeletal Mesh]** を選択します。位置は必ずしも正確である必要はありません。後でいつでも再配置、回転、スケーリングできます。 1. **[Place Actor:Skeletal Mesh]** オプションをクリックすると、選択した Skeletal Mesh がシーンに配置されます。 -![](Skeletal_Mesh_Context_Menu.gif.gif) +![](SkeletalMeshDragAndDrop.png) ## Skeletal Mesh アクタでアニメーションを再生する -ゲーム実行中に Skeletal Mesh アクタをアニメートさせるには、UE4 内で行われる以下の 2 種類の方法があります。複数のアニメーションをまとめて再生し、ブレンドすることができる [Animation ブループリント]( Engine/Animation/AnimBlueprints) を使用できます。または、アニメーション アセットを使用して、ひとつの [アニメーション シーケンス]( Engine/Animation/Sequences) を再生できます。このチュートリアルでは、アニメーション シーケンスを使用して、ゲーム実行中にアニメーションを再生させることに焦点を当てて説明します。 +ゲーム実行中に Skeletal Mesh アクタをアニメートさせるには、UE4 内で行う以下の 2 種類の方法があります。複数のアニメーションをまとめて再生し、ブレンドすることができる [アニメーション ブループリント]( Engine/Animation/AnimBlueprints) を使用できます。または、アニメーション アセットを使用して、単独の [アニメーション シーケンス]( Engine/Animation/Sequences) を再生できます。このチュートリアルでは、アニメーション シーケンスを使用して、ゲーム実行中にアニメーションを再生させることに焦点を当てて説明します。 ### Skeletal Mesh アクタのセットアップ アニメーションを再生できるように Skeletal Mesh アクタをセットアップするのは、非常に簡単です。以下の手順に従い行うことができます。 -1. **コンテンツ ブラウザ** で、必要な **スケルタルメッシュ** を選択します。 +1. **コンテンツ ブラウザ** 内で、必要な **スケルタルメッシュ** を選択します。 1. 使用する **スケルタルメッシュ** が見つかったら、ドラッグ & ドロップ または **コンテキスト メニュー** を使用してレベルに追加します。 1. 完了すると以下のようになります。 ![](SkeletalMeshActor_Adding_Mesh_To_Scene.png) @@ -68,7 +71,7 @@ Skeletal Mesh アクタがレベルに追加されたら、以下の手順に従 ![](SkeletalMeshActor_Use_Anim_Asset.png) -1. **アニメーション モード** を正しく設定したら、再生するアニメーションを選択します。これを行うには、 **[コンテンツ ブラウザ]** で再生する **アニメーション シーケンス** を選択し、それを **Anim to Play** セクションに適用します。適用の方法は、**アニメーション シーケンス** を **[Anim to Play]** にドラッグ&ドロップするか、または **[Anim to Play]** 入力ボックスの右側の矢印を使用します。 +1. **アニメーション モード** を正確に設定したら、再生するアニメーションを選択します。これを行うには、 **[コンテンツ ブラウザ]** で再生する **アニメーション シーケンス** を選択し、それを **Anim to Play** セクションに適用します。適用の方法は、**アニメーション シーケンス** を **[Anim to Play]** にドラッグ&ドロップするか、または **[Anim to Play]** 入力ボックスの右側の矢印を使用します。 ![](SkeletalMeshActor_Anim_To_Play.png) @@ -79,15 +82,15 @@ Skeletal Mesh アクタがレベルに追加されたら、以下の手順に従 ![](SkeletalMeshActor_Looping_Playing.png) -## マテリアル オーバーライド -作業対象の Skeletal Mesh アクタに既に適用されているマテリアルをオーバーライドする必要が生じるかもしれません。Skeletal Mesh アクタのマテリアル配列に新規マテリアルを手動で追加するか、エディタ ビューポートでマテリアルを Skeletal Mesh アクタにドラッグ&ドロップします。Skeletal Mesh アクタでマテリアルを変更するのは、他のアクタでマテリアルを変更するのと変わりありません。 +##マテリアル オーバーライド +作業する Skeletal Mesh アクタに適用済みのマテリアルをオーバーライドする必要が生じるかもしれません。Skeletal Mesh アクタのマテリアル配列に新規マテリアルを手動で追加するか、エディタ ビューポートでマテリアルをドラッグして Skeletal Mesh アクタにドロップします。Skeletal Mesh アクタでマテリアルを変更することは、他のアクタでマテリアルを変更することと同じです。 [Region:note] -Skeletal Mesh アクタで使用するマテリアルが正しく機能するためには、マテリアル使用フラグ、**[Used with Skeletal Mesh (スケルタルメッシュで使用)]** を有効にする必要があります。このフラグは、マテリアルの **[Details (詳細)]** パネルの **[Usage (使用)]** セクションにあります。 +Skeletal Mesh アクタで使用するマテリアルが正しく機能するためには、マテリアル使用フラグ、**Used with Skeletal Mesh** を有効にする必要があります。このフラグは、マテリアルの **[Details (詳細)]** パネルの **[Usage]** セクションにあります。 ![](SkeletalMeshActor_Material_Usage_Flag.png) [/region] ## コリジョン -通常のコリジョン作成と検出は、Skeletal Mesh アクタでは機能しません。スケルタルメッシュがレベル内のオブジェクトとコリジョン (衝突) するには、Skeletal Mesh アクタがオブジェクト専用に作成された物理アセットを持つ必要があります。 +通常のコリジョン作成と検出は、Skeletal Mesh アクタでは機能しません。スケルタルメッシュがレベル内のオブジェクトとコリジョン (衝突) するには、Skeletal Mesh アクタがオブジェクト専用に作成された物理アセットを持つようにします。 ### Skeletal Mesh アクタのコリジョンを作成する @@ -96,11 +99,11 @@ Skeletal Mesh アクタで使用するマテリアルが正しく機能するた ![](SkeletalMeshActor_Create_Physics_Asset.png) ### 物理アセットを割り当てる -物理アセットを作成したら、それをメッシュに割り当てます。物理アセットをスケルタルメッシュに割り当てるには、スケルタルメッシュを開いて、その物理アセットを **[Physics (物理)]** セクションの **[Physics Asset (物理アセット)]** に割り当てます。 +物理アセットを作成したら、それをメッシュに割り当てます。物理アセットをスケルタルメッシュに割り当てるには、スケルタルメッシュを開いて、 **[Physics]** セクションの **[Physics Asset]** スロットに割り当てます。 -![](SkeletalMeshActor_Add_Physics_Assets.png) +![](SkeletalMeshActor_Assign_Physics_Asset.png) -レベルの物理アセットをオーバーライドすることもできます。これを行うには、スケルタルメッシュを選択し、**[Details (詳細)]** パネルの **[Physics (物理)]** セクションで、新しい物理アセットを **[Physics Asset Override (物理アセットのオーバーライド)]** セクションに入力します。 +レベルの物理アセットをオーバーライドすることもできます。これを行うには、スケルタルメッシュを選択し、**[詳細]** パネルの **[Physics]** セクションで、新規物理アセットを **[Physics Asset Override (物理アセットのオーバーライド)]** セクションに入力します。 ![](SkeletalMeshActor_Add_Physics_Assets_In_Level.png) diff --git a/Engine/Documentation/Source/Engine/Actors/SkeletalMeshActors/SkeletalMeshActors.KOR.udn b/Engine/Documentation/Source/Engine/Actors/SkeletalMeshActors/SkeletalMeshActors.KOR.udn index 63386b5024c6..b4427555a7e8 100644 --- a/Engine/Documentation/Source/Engine/Actors/SkeletalMeshActors/SkeletalMeshActors.KOR.udn +++ b/Engine/Documentation/Source/Engine/Actors/SkeletalMeshActors/SkeletalMeshActors.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3481084 Availability: Public Title:스켈레탈 메시 액터 Crumbs: %ROOT%, Engine, Engine/Actors @@ -6,7 +6,9 @@ Description:스켈레탈 메시 액터 만들고 사용하기 입니다. Related: Engine/Actors Related: Engine/Animation version: 4.9 - +Parent:Engine/Actors/Types +order:3 +type:overview [TOC(start:2 end:3)] @@ -35,7 +37,7 @@ version: 4.9 1. **왼쪽 마우스 버튼** 을 놓으면 **디테일 패널** 에 보이는 것처럼 맵에 메시가 스켈레탈 메시로 배치됩니다. -![](Skeletal_Mesh_Drag_&_Drop.gif) +![](SkeletalMeshContextMenu.png) **맥락 메뉴** @@ -47,7 +49,7 @@ version: 4.9 1. 마우스로 **액터 배치: 스켈레탈 메시** 옵션을 선택하고 나면, 선택한 스켈레탈 메시가 씬에 배치될 것입니다. -![](Skeletal_Mesh_Context_Menu.gif.gif) +![](SkeletalMeshDragAndDrop.png) ## 스켈레탈 메시 액터에 애니메이션 재생하기 게임 실행 도중 애니메이션이 적용되는 스켈레탈 메시 액터를 구하는 것은 UE4 안에서 두 가지 다른 방식으로 가능합니다. 먼저 [애니메이션 블루프린트](Engine/Animation/AnimBlueprints) 를 사용하는 것으로, 다수의 애니메이션을 블렌딩하여 재생할 수 있도록 해 주는 것입니다. 아니면 애니메이션 애셋을 사용하여 하나의 [애니메이션 시퀀스](Engine/Animation/Sequences) 를 재생할 수 있습니다. 이 튜토리얼에서는 애니메이션 시퀀스를 사용하여 게임 실행 도중 애니메이션을 재생시키는 법에 대해서 집중해 보도록 하겠습니다. @@ -99,7 +101,7 @@ version: 4.9 ### 피직스 애셋 할당하기 피직스 애셋을 생성하고난 후에는 메시에 할당할 차례입니다. 피직스 애셋을 스켈레탈 메시에 할당하는 방법은, 스켈레탈 메시를 연 다음 피직스 애셋을 Physics 섹션 아래 있는 Physics Asset 슬롯에 할당해 주면 됩니다. -![](SkeletalMeshActor_Add_Physics_Assets.png) +![](SkeletalMeshActor_Assign_Physics_Asset.png) 레벨에 스켈레탈 메시를 선택하고 **디테일** 패널 내 **Physics** 섹션 아래 있는 **Physics Asset Override** 섹션에 새로운 피직스 애셋을 제공해 주는 것으로 덮어쓰는 것도 가능합니다. diff --git a/Engine/Documentation/Source/Engine/Actors/StaticMeshActor/UserGuide.INT.udn b/Engine/Documentation/Source/Engine/Actors/StaticMeshActor/UserGuide.INT.udn index e37da593ed61..ad52996e95a3 100644 --- a/Engine/Documentation/Source/Engine/Actors/StaticMeshActor/UserGuide.INT.udn +++ b/Engine/Documentation/Source/Engine/Actors/StaticMeshActor/UserGuide.INT.udn @@ -3,6 +3,9 @@ Title:Static Mesh Actors Crumbs:%ROOT%, Engine, Engine/Actors Description:Guide to placing and working with StaticMeshActors for creating world geometry in your environments. version: 4.9 +Parent:Engine/Actors/Types +order:2 +type:overview [TOC(start:2)] diff --git a/Engine/Documentation/Source/Engine/Actors/StaticMeshActor/UserGuide.JPN.udn b/Engine/Documentation/Source/Engine/Actors/StaticMeshActor/UserGuide.JPN.udn index baee36352f1e..ec2600ca639d 100644 --- a/Engine/Documentation/Source/Engine/Actors/StaticMeshActor/UserGuide.JPN.udn +++ b/Engine/Documentation/Source/Engine/Actors/StaticMeshActor/UserGuide.JPN.udn @@ -1,9 +1,12 @@ -INTSourceChangelist:3275202 +INTSourceChangelist:3429227 Availability:Public Title:StaticMesh アクタ Crumbs:%ROOT%, Engine, Engine/Actors Description:背景にワールド ジオメトリを作成するために StaticMesh アクタを配置し使用するためのガイド version:4.9 +Parent:Engine/Actors/Types +order:2 +type:overview [TOC(start:2)] @@ -51,7 +54,9 @@ StaticMesh アクタ は一般的なアクタ配置方法でマップに配置 1. **[プロパティ]** ウィンドウに表示されているように、StaticMesh が StaticMesh アクタとしてマップに配置されました。 -## StaticMesh アクタを可動にする + ## StaticMesh アクタを可動にする + + プレイ中に StaticMesh アクタを移動、回転、スケーリングするためには、必ず最初に StaticMesh アクタ を **Movable (可動)** にする必要があります。これを行うには、StaticMesh アクタを選択し、**[Details]** パネルの **[Mobility]** から **[Moveable]** を選択します。 diff --git a/Engine/Documentation/Source/Engine/Actors/StaticMeshActor/UserGuide.KOR.udn b/Engine/Documentation/Source/Engine/Actors/StaticMeshActor/UserGuide.KOR.udn index 942b9e60cbe8..b6bc18cfb71d 100644 --- a/Engine/Documentation/Source/Engine/Actors/StaticMeshActor/UserGuide.KOR.udn +++ b/Engine/Documentation/Source/Engine/Actors/StaticMeshActor/UserGuide.KOR.udn @@ -1,9 +1,12 @@ -INTSourceChangelist:3275202 +INTSourceChangelist:3429227 Availability: Public Title:스태틱 메시 액터 Crumbs:%ROOT%, Engine, Engine/Actors Description:Static Mesh Actor, 스태틱 메시 액터를 배치하고 작업하여 환경에 월드 지오메트리를 만드는 방법 안내서입니다. version: 4.9 +Parent:Engine/Actors/Types +order:2 +type:overview [TOC(start:2)] diff --git a/Engine/Documentation/Source/Engine/Actors/TargetPoint/TargetPoint.INT.udn b/Engine/Documentation/Source/Engine/Actors/TargetPoint/TargetPoint.INT.udn index 96276eb43e79..b0a0ff0359da 100644 --- a/Engine/Documentation/Source/Engine/Actors/TargetPoint/TargetPoint.INT.udn +++ b/Engine/Documentation/Source/Engine/Actors/TargetPoint/TargetPoint.INT.udn @@ -4,6 +4,9 @@ Crumbs: %ROOT%, Engine, Engine/Actors Description:Guide to creating and using Target Actors. Related: Gameplay/HowTo/SpawnAndDestroyActors/Blueprints version: 4.9 +Parent:Engine/Actors/Types +order:9 +type:overview ![](Target_Point_Actors.png) diff --git a/Engine/Documentation/Source/Engine/Actors/TargetPoint/TargetPoint.JPN.udn b/Engine/Documentation/Source/Engine/Actors/TargetPoint/TargetPoint.JPN.udn index a271d870ca4e..b09cdfb6a2c1 100644 --- a/Engine/Documentation/Source/Engine/Actors/TargetPoint/TargetPoint.JPN.udn +++ b/Engine/Documentation/Source/Engine/Actors/TargetPoint/TargetPoint.JPN.udn @@ -1,10 +1,13 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429227 Availability:Public Title:Target Point アクタ Crumbs: %ROOT%, Engine, Engine/Actors Description:Target アクタの作成と使用に関するガイド Related:Gameplay/HowTo/SpawnAndDestroyActors/Blueprints version:4.9 +Parent:Engine/Actors/Types +order:9 +type:overview ![](Target_Point_Actors.png) diff --git a/Engine/Documentation/Source/Engine/Actors/TargetPoint/TargetPoint.KOR.udn b/Engine/Documentation/Source/Engine/Actors/TargetPoint/TargetPoint.KOR.udn index 3bfe50a6f36c..e82225715075 100644 --- a/Engine/Documentation/Source/Engine/Actors/TargetPoint/TargetPoint.KOR.udn +++ b/Engine/Documentation/Source/Engine/Actors/TargetPoint/TargetPoint.KOR.udn @@ -1,10 +1,13 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429227 Availability: Public Title:타겟 포인트 액터 Crumbs: %ROOT%, Engine, Engine/Actors Description:타겟 액터 생성 및 사용법 안내서입니다. Related: Gameplay/HowTo/SpawnAndDestroyActors/Blueprints version: 4.9 +Parent:Engine/Actors/Types +order:9 +type:overview ![](Target_Point_Actors.png) diff --git a/Engine/Documentation/Source/Engine/Actors/Transform/ActorTransform.INT.udn b/Engine/Documentation/Source/Engine/Actors/Transform/ActorTransform.INT.udn index 5851d0c7d45e..4fd285ce42e0 100644 --- a/Engine/Documentation/Source/Engine/Actors/Transform/ActorTransform.INT.udn +++ b/Engine/Documentation/Source/Engine/Actors/Transform/ActorTransform.INT.udn @@ -2,46 +2,10 @@ Availability:Public Title:Transforming Actors Crumbs: %ROOT%, Engine, Engine/Actors Description:Modifying the location, rotation, and scale of Actors placed in levels. - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Actors/Transform:title%](Engine/Actors/Transform/actortransform_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Transform:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Transform:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Transform] - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Actors/Transform:title%](Engine/Actors/Transform/actortransform_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Transform:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Transform:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Transform] - [/PARAM] -[/OBJECT] -[/VAR] +parent:Engine/Actors +type:overview +order:3 +topic-image:actortransform_topic.png [TOC(start:2)] diff --git a/Engine/Documentation/Source/Engine/Actors/Transform/ActorTransform.JPN.udn b/Engine/Documentation/Source/Engine/Actors/Transform/ActorTransform.JPN.udn index 250ea3c792d9..05b030261c87 100644 --- a/Engine/Documentation/Source/Engine/Actors/Transform/ActorTransform.JPN.udn +++ b/Engine/Documentation/Source/Engine/Actors/Transform/ActorTransform.JPN.udn @@ -1,48 +1,12 @@ -INTSourceChangelist:3275202 +INTSourceChangelist:3429227 Availability:Public Title:アクタのトランスフォーム Crumbs: %ROOT%, Engine, Engine/Actors Description:レベルに配置されたアクタの位置、回転、スケーリングを修正します。 - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Actors/Transform:title%](Engine/Actors/Transform/actortransform_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Transform:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Transform:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Transform] - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Actors/Transform:title%](Engine/Actors/Transform/actortransform_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Transform:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Transform:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Transform] - [/PARAM] -[/OBJECT] -[/VAR] +parent:Engine/Actors +type:overview +order:3 +topic-image:actortransform_topic.png [TOC(start:2)] diff --git a/Engine/Documentation/Source/Engine/Actors/Transform/ActorTransform.KOR.udn b/Engine/Documentation/Source/Engine/Actors/Transform/ActorTransform.KOR.udn index 01120b8cd9cc..ac8e34273ae1 100644 --- a/Engine/Documentation/Source/Engine/Actors/Transform/ActorTransform.KOR.udn +++ b/Engine/Documentation/Source/Engine/Actors/Transform/ActorTransform.KOR.udn @@ -1,48 +1,12 @@ -INTSourceChangelist:3275202 +INTSourceChangelist:3429227 Availability:Public Title:액터 트랜스폼 Crumbs: %ROOT%, Engine, Engine/Actors Description:레벨에 배치된 액터의 위치, 회전, 스케일 변경하기 입니다. - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Actors/Transform:title%](Engine/Actors/Transform/actortransform_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Transform:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Transform:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Transform] - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Actors/Transform:title%](Engine/Actors/Transform/actortransform_topic.png)(convert:false) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Actors/Transform:title% - [/PARAM] - [PARAM:description] - %Engine/Actors/Transform:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Actors/Transform] - [/PARAM] -[/OBJECT] -[/VAR] +parent:Engine/Actors +type:overview +order:3 +topic-image:actortransform_topic.png [TOC(start:2)] diff --git a/Engine/Documentation/Source/Engine/Actors/Triggers/TriggerActors.INT.udn b/Engine/Documentation/Source/Engine/Actors/Triggers/TriggerActors.INT.udn index 7a7abac88b5e..38a2e1185958 100644 --- a/Engine/Documentation/Source/Engine/Actors/Triggers/TriggerActors.INT.udn +++ b/Engine/Documentation/Source/Engine/Actors/Triggers/TriggerActors.INT.udn @@ -3,6 +3,9 @@ Title: Trigger Actors Crumbs: %ROOT%, Engine, Engine/Actors Description:Actor that can be activated and cause events to occur in the level. version: 4.9 +Parent:Engine/Actors/Types +order:7 +type:overview [TOC(start:2)] diff --git a/Engine/Documentation/Source/Engine/Actors/Triggers/TriggerActors.JPN.udn b/Engine/Documentation/Source/Engine/Actors/Triggers/TriggerActors.JPN.udn index 7a118842bac4..08bccfa0d6d8 100644 --- a/Engine/Documentation/Source/Engine/Actors/Triggers/TriggerActors.JPN.udn +++ b/Engine/Documentation/Source/Engine/Actors/Triggers/TriggerActors.JPN.udn @@ -1,9 +1,12 @@ -INTSourceChangelist:3275202 +INTSourceChangelist:3429227 Availability:Public Title:Trigger アクタ Crumbs: %ROOT%, Engine, Engine/Actors Description:レベル内でアクティベートされイベントを発生させることができるアクタ version:4.9 +Parent:Engine/Actors/Types +order:7 +type:overview [TOC(start:2)] diff --git a/Engine/Documentation/Source/Engine/Actors/Triggers/TriggerActors.KOR.udn b/Engine/Documentation/Source/Engine/Actors/Triggers/TriggerActors.KOR.udn index c74ec59feb74..077294f4b98c 100644 --- a/Engine/Documentation/Source/Engine/Actors/Triggers/TriggerActors.KOR.udn +++ b/Engine/Documentation/Source/Engine/Actors/Triggers/TriggerActors.KOR.udn @@ -1,9 +1,12 @@ -INTSourceChangelist:3275202 +INTSourceChangelist:3429227 Availability:Public Title: 트리거 액터 Crumbs: %ROOT%, Engine, Engine/Actors Description:활성화되면 레벨에 이벤트가 발생하도록 하는 액터입니다. version: 4.9 +Parent:Engine/Actors/Types +order:7 +type:overview [TOC(start:2)] diff --git a/Engine/Documentation/Source/Engine/Actors/Types/CommonActorTypes.INT.udn b/Engine/Documentation/Source/Engine/Actors/Types/CommonActorTypes.INT.udn index f40a92c7c711..a39b4929f1b7 100644 --- a/Engine/Documentation/Source/Engine/Actors/Types/CommonActorTypes.INT.udn +++ b/Engine/Documentation/Source/Engine/Actors/Types/CommonActorTypes.INT.udn @@ -2,6 +2,9 @@ Availability:Public Title: Common Actor Types Crumbs: %ROOT%, Engine, Engine/Actors Description:Listing and descriptions of common types of Actors used in levels. +parent:Engine/Actors +type:overview +order:0 Below is a quick rundown of some of the Actors you will most commonly use or come across while developing games with Unreal Engine to familiarize you with what they are and why you would use them. diff --git a/Engine/Documentation/Source/Engine/Actors/Types/CommonActorTypes.JPN.udn b/Engine/Documentation/Source/Engine/Actors/Types/CommonActorTypes.JPN.udn index e9418eba4f54..3018cab48345 100644 --- a/Engine/Documentation/Source/Engine/Actors/Types/CommonActorTypes.JPN.udn +++ b/Engine/Documentation/Source/Engine/Actors/Types/CommonActorTypes.JPN.udn @@ -1,8 +1,11 @@ -INTSourceChangelist:3275202 +INTSourceChangelist:3429227 Availability:Public Title:一般的なアクタの種類 Crumbs: %ROOT%, Engine, Engine/Actors Description:レベルで使用する一般的なアクタの種類のリストおよび説明 +parent:Engine/Actors +type:overview +order:0 以下は、アンリアル エンジンを用いてゲーム開発をする場合に一般的に使用するアクタを簡単に分類したものです。 この分類は、どのようなアクタか、なぜ使用するかについて慣れ親しんでいただくためのものです。 diff --git a/Engine/Documentation/Source/Engine/Actors/Types/CommonActorTypes.KOR.udn b/Engine/Documentation/Source/Engine/Actors/Types/CommonActorTypes.KOR.udn index b435b0c44611..e1958bdf94ad 100644 --- a/Engine/Documentation/Source/Engine/Actors/Types/CommonActorTypes.KOR.udn +++ b/Engine/Documentation/Source/Engine/Actors/Types/CommonActorTypes.KOR.udn @@ -1,8 +1,11 @@ -INTSourceChangelist:3275202 +INTSourceChangelist:3429227 Availability:Public Title: 흔한 액터 유형 Crumbs: %ROOT%, Engine, Engine/Actors Description:레벨에 자주 사용되는 액터 유형에 대한 목록과 설명입니다. +parent:Engine/Actors +type:overview +order:0 아래는 언리얼 엔진으로 게임을 개발할 때 가장 자주 사용 또는 접하게 되는 액터는 무엇인지, 왜 사용해야 하는지, 이해를 돕기 위한 간략 소개입니다. diff --git a/Engine/Documentation/Source/Engine/Actors/Volumes/AudioVolumeDetails/AudioVolumeDetails.CHN.udn b/Engine/Documentation/Source/Engine/Actors/Volumes/AudioVolumeDetails/AudioVolumeDetails.CHN.udn new file mode 100644 index 000000000000..add911263bb2 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Actors/Volumes/AudioVolumeDetails/AudioVolumeDetails.CHN.udn @@ -0,0 +1,38 @@ +INTSourceChangelist:0 +Availability: Docs +Title:Volumes Overview +Crumbs:%ROOT%, Engine, Engine/Actors, Engine/Actors/Volumes +Description:Audio Volume reference details +version:4.16 +type:reference + + +### Audio Volume + +Several properties can be adjusted from the **Details** panel on this volume to allow for more control over its effects as seen below. + +![](audiovolume.png) + +|Property| Description | +| ------- | ------------ | +| **Priority** | In the event of overlapping volumes, the highest priority volume will be used. The order is undefined if two or more overlapping volumes have the same priority. | +| **Apply Reverb** | Determines if the reverb settings should be used. | +| **Reverb Effect** | This is the reverb asset to use for the volume. | +| **Volume** | This is the overall volume level of the reverb effect. | +| **Fade Time** | This is the time (in seconds) to fade from the current reverb settings into the volumes setting. | +| **Enabled** | Determines whether the volume is currently enabled and is able to affect sounds. | + +**Ambient Zone Settings** define how Sound Actors located inside the associated Audio Volume will be altered by the Player's location. The Ambient Zone Settings can be adjusted from the **Details** panel. + +|Property| Description | +| ------- | ------------ | +| **Exterior Volume** | The final volume of exterior sounds when the player is inside the volume. | +| **Exterior Time** | Time to fade to new exterior volme in seconds. | +| **Exterior LPF** | Lowpass Filter multiplier applied to exterior sounds when inside (1.0 to apply the maximum LPF). | +| **Exterior LPFTime** | Time to fade to new Lowpass Filter level in seconds. | +| **Interior Volume** | The final volume of interior sounds when the player is outside the volume. | +| **Interior Time** | Time to fade to new interior volume in seconds. | +| **Interior LPF** | Lowpass Filter multiplier applied to interior sounds when outside (1.0 to apply the maximum LPF). | +| **Interior LPFTime** | Time to fade to new Lowpass Filter level in seconds. | + + diff --git a/Engine/Documentation/Source/Engine/Actors/Volumes/AudioVolumeDetails/AudioVolumeDetails.INT.udn b/Engine/Documentation/Source/Engine/Actors/Volumes/AudioVolumeDetails/AudioVolumeDetails.INT.udn new file mode 100644 index 000000000000..b00c51653b8f --- /dev/null +++ b/Engine/Documentation/Source/Engine/Actors/Volumes/AudioVolumeDetails/AudioVolumeDetails.INT.udn @@ -0,0 +1,37 @@ +Availability: Docs +Title:Volumes Overview +Crumbs:%ROOT%, Engine, Engine/Actors, Engine/Actors/Volumes +Description:Audio Volume reference details +version:4.16 +type:reference + + +### Audio Volume + +Several properties can be adjusted from the **Details** panel on this volume to allow for more control over its effects as seen below. + +![](audiovolume.png) + +|Property| Description | +| ------- | ------------ | +| **Priority** | In the event of overlapping volumes, the highest priority volume will be used. The order is undefined if two or more overlapping volumes have the same priority. | +| **Apply Reverb** | Determines if the reverb settings should be used. | +| **Reverb Effect** | This is the reverb asset to use for the volume. | +| **Volume** | This is the overall volume level of the reverb effect. | +| **Fade Time** | This is the time (in seconds) to fade from the current reverb settings into the volumes setting. | +| **Enabled** | Determines whether the volume is currently enabled and is able to affect sounds. | + +**Ambient Zone Settings** define how Sound Actors located inside the associated Audio Volume will be altered by the Player's location. The Ambient Zone Settings can be adjusted from the **Details** panel. + +|Property| Description | +| ------- | ------------ | +| **Exterior Volume** | The final volume of exterior sounds when the player is inside the volume. | +| **Exterior Time** | Time to fade to new exterior volme in seconds. | +| **Exterior LPF** | Lowpass Filter multiplier applied to exterior sounds when inside (1.0 to apply the maximum LPF). | +| **Exterior LPFTime** | Time to fade to new Lowpass Filter level in seconds. | +| **Interior Volume** | The final volume of interior sounds when the player is outside the volume. | +| **Interior Time** | Time to fade to new interior volume in seconds. | +| **Interior LPF** | Lowpass Filter multiplier applied to interior sounds when outside (1.0 to apply the maximum LPF). | +| **Interior LPFTime** | Time to fade to new Lowpass Filter level in seconds. | + + diff --git a/Engine/Documentation/Source/Engine/Actors/Volumes/AudioVolumeDetails/AudioVolumeDetails.JPN.udn b/Engine/Documentation/Source/Engine/Actors/Volumes/AudioVolumeDetails/AudioVolumeDetails.JPN.udn new file mode 100644 index 000000000000..a20412ada9f5 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Actors/Volumes/AudioVolumeDetails/AudioVolumeDetails.JPN.udn @@ -0,0 +1,38 @@ +INTSourceChangelist:3379420 +Availability:Docs +Title:ボリュームの概要 +Crumbs:%ROOT%, Engine, Engine/Actors, Engine/Actors/Volumes +Description:Audio Volume のリファレンスの詳細 +version:4.16 +type:reference + + +### Audio Volume + +このボリュームの **[Details]** パネルからプロパティをいくつか調整すると、下図のようにエフェクトをより制御できるようになります。 + +![](audiovolume.png) + +| プロパティ | 説明 | +| ------- | ------------ | +| **Priority** | ボリュームがオーバーラップする場合、優先度の一番高いボリュームが使用されます。2 つ以上のオーバーラップしているボリュームが同じ優先度の場合、順序は決まっていません。| +| **Apply Reverb** | リバーブ設定を使うかどうかを判断します。 | +| **Reverb Effect** | ボリュームに使うリバーブ アセットです。 | +| **Volume** | リバーブ エフェクトの全体的なボリューム レベルです。 | +| **Fade Time** | 現在のリバーブ設定からボリューム設定へフェードする時間 (秒) です。 | +| **Enabled** | ボリュームが現在有効で、音に影響を与えることができるかどうかを判断します。 | + +**Ambient Zone Settings** は、関連する Audio Volume 内に置かれている Sound アクタがプレイヤーの位置によってどのように変化するかを定義します。Ambient Zone Settings は **[Details]** パネルからも調整することができます。 + +| プロパティ | 説明 | +| ------- | ------------ | +| **Exterior Volume** | プレイヤーがボリューム内にいる時の外部サウンドの最終的なボリューム。 | +| **Exterior Time** | 新規の外部ボリュームへフェードする秒時間。 | +| **Exterior LPF** | プレイヤーがボリューム内部にいる場合に、外部サウンドに適用されるローパスフィルタ乗数 (最大 LPF の適用は 0.1)。 | +| **Exterior LPFTime** | 新規のローパスフィルタ レベルにフェードする秒時間。 | +| **Interior Volume** | プレイヤーがボリューム外にいる時の内部サウンドの最終的なボリューム。 | +| **Interior Time** | 新規の内部ボリュームにフェードする秒時間。 | +| **Interior LPF** | プレイヤーがボリュームの外側にいる時の内側のサウンドに適用されるローパスフィルタ乗数 (最大 LPF の適用は 0.1)。 | +| **Interior LPFTime** | 新規のローパス フィルタ レベルにフェードする秒時間。 | + + diff --git a/Engine/Documentation/Source/Engine/Actors/Volumes/AudioVolumeDetails/AudioVolumeDetails.KOR.udn b/Engine/Documentation/Source/Engine/Actors/Volumes/AudioVolumeDetails/AudioVolumeDetails.KOR.udn new file mode 100644 index 000000000000..c6c47b2c9c3e --- /dev/null +++ b/Engine/Documentation/Source/Engine/Actors/Volumes/AudioVolumeDetails/AudioVolumeDetails.KOR.udn @@ -0,0 +1,38 @@ +INTSourceChangelist:3379420 +Availability: Docs +Title:볼륨 개요 +Crumbs:%ROOT%, Engine, Engine/Actors, Engine/Actors/Volumes +Description:Audio Volume 참고서입니다. +version:4.16 +type:reference + + +### Audio Volume + +이 볼륨의 **디테일** 패널에서 여러가지 프로퍼티를 조절하여 아래와 같은 이펙트에 대한 세밀한 제어가 가능합니다. + +![](audiovolume.png) + +|프로퍼티| 설명 | +| ------- | ------------ | +| **Priority** | 우선권 - 볼륨이 겹치는 경우 우선권이 가장 높은 것이 사용됩니다. 둘 이상의 볼륨에 우선권이 같은 경우 순서는 미정입니다. | +| **Apply Reverb** | 리버브 적용 - 리버브 세팅을 사용할지를 나타냅니다. | +| **Reverb Effect** | 리버브 이펙트 - 볼륨에 사용할 리버브 애셋입니다. | +| **Volume** | 볼륨 - 리버브 이펙트의 전체적인 볼륨 크기입니다. | +| **Fade Time** | 페이드 시간 - 현재 리버브 세팅에서 볼륨 세팅으로 페이드하는 데 걸리는 (초 단위) 시간입니다. | +| **Enabled** | 켜짐 - 이 볼륨이 현재 켜져있어 사운드에 영향을 끼칠 수 있는지를 나타냅니다. | + +'앰비언트 존'은 연관된 오디오 볼륨 안에 위치한 사운드 액터가 플레이어 위치에 따라 어떻게 변경되는지를 정의합니다. 앰비언트 존에 대한 세팅은 **디테일** 패널에서도 조절할 수 있습니다. + +|프로퍼티| 설명 | +| ------- | ------------ | +| **Exterior Volume** | 외부 볼륨 - 볼륨 안에 플레이어가 있을 때의 외부 사운드 최종 볼륨입니다. | +| **Exterior Time** | 외부 시간 - 새로운 외부 볼륨으로 페이드하는 데 걸리는 초 단위 시간입니다. | +| **Exterior LPF** | 외부 LPF - 내부에 있을 때 외부 사운드에 적용할 로우패스 필터 배수입니다 (1.0 은 최대 LPF 를 적용합니다). | +| **Exterior LPFTime** | 외부 LPF 시간 - 새로운 로우 패스 필터 레벨로 페이드하는 데 걸리는 초 단위 시간입니다. | +| **Interior Volume** | 내부 볼륨 - 플레이어가 볼륨 밖에 있을 때 내부 사운드의 최종 볼륨입니다. | +| **Interior Time** | 내부 시간 - 새로운 내부 볼륨으로 페이드하는 데 걸리는 초 단위 시간입니다. | +| **Interior LPF** | 내부 LPF - 밖에 있을 때 내부 사운드에 적용되는 로우패스 필더 배수입니다 (1.0 이면 최대 LPF 를 적용합니다). | +| **Interior LPFTime** | 내부 LPF 시간 - 새로운 로우패스 필터 레벨로 페이드하는 데 걸리는 초 단위 시간입니다. | + + diff --git a/Engine/Documentation/Source/Engine/Actors/Volumes/PainCausingVolumeDetails/PainCausingVolumeDetails.CHN.udn b/Engine/Documentation/Source/Engine/Actors/Volumes/PainCausingVolumeDetails/PainCausingVolumeDetails.CHN.udn new file mode 100644 index 000000000000..8cc6a68df84f --- /dev/null +++ b/Engine/Documentation/Source/Engine/Actors/Volumes/PainCausingVolumeDetails/PainCausingVolumeDetails.CHN.udn @@ -0,0 +1,22 @@ +INTSourceChangelist:0 +Availability: Docs +Title:Volumes Overview +Crumbs:%ROOT%, Engine, Engine/Actors, Engine/Actors/Volumes +Description:Pain-Causing Volume reference details +version:4.16 +type:reference + + +### Pain-Causing Volume + +In addition to the properties that can be assigned from a Physics Volume, the Pain Causing Volume also has its own set of specific propteries outlined below. + +![](paincausingvolume.png) + +| Property | Description | +| ------- | ------------ | +| **Pain Causing** | Whether the volume currently causes damage or not. | +| **Damage Per Sec** | Damage done per second to the Actors in the volume when Pain Causing is enabled. | +| **Damage Type** | This determines the type of damage done to the Actor. | +| **Pain Interval** | This is the amount of time, in seconds, between applied damage when Pain Causing is enabled. | +| **Entry Pain** | Determines whether or not damage will be applied immediately upon entering the volume, assuming that **Pain Causing** is enabled. This damage is in addition to the recurring damage applied based on the **Pain Interval**. | diff --git a/Engine/Documentation/Source/Engine/Actors/Volumes/PainCausingVolumeDetails/PainCausingVolumeDetails.INT.udn b/Engine/Documentation/Source/Engine/Actors/Volumes/PainCausingVolumeDetails/PainCausingVolumeDetails.INT.udn new file mode 100644 index 000000000000..f81772b6e58c --- /dev/null +++ b/Engine/Documentation/Source/Engine/Actors/Volumes/PainCausingVolumeDetails/PainCausingVolumeDetails.INT.udn @@ -0,0 +1,21 @@ +Availability: Docs +Title:Volumes Overview +Crumbs:%ROOT%, Engine, Engine/Actors, Engine/Actors/Volumes +Description:Pain-Causing Volume reference details +version:4.16 +type:reference + + +### Pain-Causing Volume + +In addition to the properties that can be assigned from a Physics Volume, the Pain Causing Volume also has its own set of specific propteries outlined below. + +![](paincausingvolume.png) + +| Property | Description | +| ------- | ------------ | +| **Pain Causing** | Whether the volume currently causes damage or not. | +| **Damage Per Sec** | Damage done per second to the Actors in the volume when Pain Causing is enabled. | +| **Damage Type** | This determines the type of damage done to the Actor. | +| **Pain Interval** | This is the amount of time, in seconds, between applied damage when Pain Causing is enabled. | +| **Entry Pain** | Determines whether or not damage will be applied immediately upon entering the volume, assuming that **Pain Causing** is enabled. This damage is in addition to the recurring damage applied based on the **Pain Interval**. | diff --git a/Engine/Documentation/Source/Engine/Actors/Volumes/PainCausingVolumeDetails/PainCausingVolumeDetails.JPN.udn b/Engine/Documentation/Source/Engine/Actors/Volumes/PainCausingVolumeDetails/PainCausingVolumeDetails.JPN.udn new file mode 100644 index 000000000000..450a7ea16ef3 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Actors/Volumes/PainCausingVolumeDetails/PainCausingVolumeDetails.JPN.udn @@ -0,0 +1,22 @@ +INTSourceChangelist:3379420 +Availability:Docs +Title:ボリュームの概要 +Crumbs:%ROOT%, Engine, Engine/Actors, Engine/Actors/Volumes +Description:Pain-Causing Volume のリファレンスの詳細 +version:4.16 +type:reference + + +### Pain-Causing Volume + +Physics Volume から割り当てが可能なプロパティの他に、Pain Causing Volume には以下の固有のプロパティもあります。 + +![](paincausingvolume.png) + +| プロパティ | 説明 | +| ------- | ------------ | +| **Pain Causing** | Volume が現在ダメージを与えるかどうかを決定します。 | +| **Damage Per Sec** | Pain Causing が有効な場合、ボリューム内のアクタに毎秒単位で与えられるダメージです。 | +| **Damage Type** | アクタに与えるダメージの種類を決定します。 | +| **Pain Interval** | Pain Causing が有効な場合にダメージが与えられる間隔の秒単位の時間です。 | +| **Entry Pain** | **Pain Causing** が有効な場合、ボリュームに入るとただちにダメージが適用されるかどうかを決定します。このダメージは、 **Pain Interval** に基づき繰り返し適用されるダメージに追加で適用されます。 | diff --git a/Engine/Documentation/Source/Engine/Actors/Volumes/PainCausingVolumeDetails/PainCausingVolumeDetails.KOR.udn b/Engine/Documentation/Source/Engine/Actors/Volumes/PainCausingVolumeDetails/PainCausingVolumeDetails.KOR.udn new file mode 100644 index 000000000000..8f1715d0721b --- /dev/null +++ b/Engine/Documentation/Source/Engine/Actors/Volumes/PainCausingVolumeDetails/PainCausingVolumeDetails.KOR.udn @@ -0,0 +1,22 @@ +INTSourceChangelist:3379420 +Availability: Docs +Title:볼륨 개요 +Crumbs:%ROOT%, Engine, Engine/Actors, Engine/Actors/Volumes +Description:Pain-Causing Volume 참고서입니다. +version:4.16 +type:reference + + +### Pain-Causing Volume + +Physics Volume 에서 할당 가능한 프로퍼티 이외에 Pain Causing Volume 에도 다음과 같은 프로퍼티 세트가 있습니다. + +![](paincausingvolume.png) + +|프로퍼티| 설명 | +| ------- | ------------ | +| **Pain Causing** | 피해 유발 - 볼륨이 현재 대미지를 입힐지 말지 입니다. | +| **Damage Per Sec** | 초당 대미지 - Pain Causing 이 켜져 있을 때 볼륨에 있는 액터에게 입히는 초당 대미지입니다. | +| **Damage Type** | 대미지 유형 - 액터에 가해지는 대미지 유형을 나타냅니다. | +| **Pain Interval** | Pain Causing 이 켜졌을 때 대미지가 적용되는 초단위 간격입니다. | +| **Entry Pain** | 진입 피해 - Pain Causing 이 켜진 볼륨에 들어설 때 Pain Interval 에 따른 지속 대미지에 추가로 즉시 적용할 대미지를 나타냅니다. | \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Actors/Volumes/PhysicsVolumeDetails/PhysicsVolumeDetails.CHN.udn b/Engine/Documentation/Source/Engine/Actors/Volumes/PhysicsVolumeDetails/PhysicsVolumeDetails.CHN.udn new file mode 100644 index 000000000000..cb77f49fb60d --- /dev/null +++ b/Engine/Documentation/Source/Engine/Actors/Volumes/PhysicsVolumeDetails/PhysicsVolumeDetails.CHN.udn @@ -0,0 +1,22 @@ +INTSourceChangelist:0 +Availability: Docs +Title:Volumes Overview +Crumbs:%ROOT%, Engine, Engine/Actors, Engine/Actors/Volumes +Description:Physics Volume reference details +version:4.16 +type:reference + + +### Physics Volume + +There are some properties that are designated for this volume which can be adjusted from the **Details** panel, pictured below. + +![](PhysicsVolumeDetails.png) + +|Property| Description | +| ------- | ------------ | +| **Terminal Velocity** | Determines the Terminal Velocity of Pawns using CharacterMovement when falling. | +| **Priority** | Determines which PhysicsVolume takes precedence if they overlap. | +| **Fluid Friction** | Determines the amount of friction applied by the volume as Pawns using CharacterMovement move through it.
The higher this value, the harder it will feel to move through the volume. | +| **Water Volume** | Determines if the volume contains a fluid, like water. | +| **Physics on Contact** | Determines if the Actor is affected by the volume by touching it (by Default, an Actor must be inside the volume for it to affect them). | diff --git a/Engine/Documentation/Source/Engine/Actors/Volumes/PhysicsVolumeDetails/PhysicsVolumeDetails.INT.udn b/Engine/Documentation/Source/Engine/Actors/Volumes/PhysicsVolumeDetails/PhysicsVolumeDetails.INT.udn new file mode 100644 index 000000000000..46f40ca234d6 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Actors/Volumes/PhysicsVolumeDetails/PhysicsVolumeDetails.INT.udn @@ -0,0 +1,21 @@ +Availability: Docs +Title:Volumes Overview +Crumbs:%ROOT%, Engine, Engine/Actors, Engine/Actors/Volumes +Description:Physics Volume reference details +version:4.16 +type:reference + + +### Physics Volume + +There are some properties that are designated for this volume which can be adjusted from the **Details** panel, pictured below. + +![](PhysicsVolumeDetails.png) + +|Property| Description | +| ------- | ------------ | +| **Terminal Velocity** | Determines the Terminal Velocity of Pawns using CharacterMovement when falling. | +| **Priority** | Determines which PhysicsVolume takes precedence if they overlap. | +| **Fluid Friction** | Determines the amount of friction applied by the volume as Pawns using CharacterMovement move through it.
The higher this value, the harder it will feel to move through the volume. | +| **Water Volume** | Determines if the volume contains a fluid, like water. | +| **Physics on Contact** | Determines if the Actor is affected by the volume by touching it (by Default, an Actor must be inside the volume for it to affect them). | diff --git a/Engine/Documentation/Source/Engine/Actors/Volumes/PhysicsVolumeDetails/PhysicsVolumeDetails.JPN.udn b/Engine/Documentation/Source/Engine/Actors/Volumes/PhysicsVolumeDetails/PhysicsVolumeDetails.JPN.udn new file mode 100644 index 000000000000..664de1d27ec5 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Actors/Volumes/PhysicsVolumeDetails/PhysicsVolumeDetails.JPN.udn @@ -0,0 +1,22 @@ +INTSourceChangelist:3379420 +Availability:Docs +Title:ボリュームの概要 +Crumbs:%ROOT%, Engine, Engine/Actors, Engine/Actors/Volumes +Description:Physics Volume のリファレンスの詳細 +version:4.16 +type:reference + + +### Physics Volume + +このボリューム用に指定されたプロパティの中には、以下の画像のように、**[Details (詳細)]** パネルから調整可能なものもあります。 + +![](PhysicsVolumeDetails.png) + +| プロパティ | 説明 | +| ------- | ------------ | +| **Terminal Velocity** | 落下時に CharacterMovement を使ってポーンの Terminal Velocity を判断します。 | +| **Priority** | オーバーラップした場合、優先する PhysicsVolume を判断します。 | +| **Fluid Friction** | CharacterMovement を使用しているポーンが通過する際にボリュームが適用する摩擦量を判断します。
この値が高いほど、ボリューム内の移動が困難になります。 | +| **Water Volume** | ボリュームに水などの液体が含まれているかを判断します。 | +| **Physics on Contact** | ボリュームに触れることでアクタが影響を受けるかを判断します (アクタが影響を受けるためには、デフォルトでボリューム内にいる必要があります)。 | diff --git a/Engine/Documentation/Source/Engine/Actors/Volumes/PhysicsVolumeDetails/PhysicsVolumeDetails.KOR.udn b/Engine/Documentation/Source/Engine/Actors/Volumes/PhysicsVolumeDetails/PhysicsVolumeDetails.KOR.udn new file mode 100644 index 000000000000..39e130e20354 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Actors/Volumes/PhysicsVolumeDetails/PhysicsVolumeDetails.KOR.udn @@ -0,0 +1,22 @@ +INTSourceChangelist:3379420 +Availability: Docs +Title:볼륨 개요 +Crumbs:%ROOT%, Engine, Engine/Actors, Engine/Actors/Volumes +Description:Physics Volume 참고서입니다. +version:4.16 +type:reference + + +### Physics Volume + +이 볼륨용으로 고안된 프로퍼티가 몇 가지 있으며, 아래 그림과 같이 **디테일** 패널에서 조정 가능합니다. + +![](PhysicsVolumeDetails.png) + +|프로퍼티| 설명 | +| ------- | ------------ | +| **Terminal Velocity** | 종단 속도 - 낙하시 CharacterMovement 를 사용하여 Pawn 의 종단 속도를 결정합니다. | +| **Priority** | 우선권 - 다수의 PhysicsVolume 이 겹칠 때의 우선권을 결정합니다. | +| **Fluid Friction** | 유체 마찰 - CharacterMovement 를 사용하는 Pawn 이 볼륨을 지나갈 때 볼륨에 적용시킬 마찰력의 양을 결정합니다.
값이 클 수록 볼륨을 통과하기가 어렵게 느껴집니다. | +| **Water Volume** | 수량 - 볼륨에 물과 같은 유체가 들어있는지를 나타냅니다. | +| **Physics on Contact** | 접촉시 물리 - 액터를 건드리면 볼륨에 영향을 받을지를 결정합니다 (기본적으로 액터는 볼륨 안에 있어야 영향을 받을 수 있습니다). | \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Actors/Volumes/Volumes.CHN.udn b/Engine/Documentation/Source/Engine/Actors/Volumes/Volumes.CHN.udn index 78cf4ac00495..090830dc670b 100644 --- a/Engine/Documentation/Source/Engine/Actors/Volumes/Volumes.CHN.udn +++ b/Engine/Documentation/Source/Engine/Actors/Volumes/Volumes.CHN.udn @@ -3,10 +3,11 @@ Availability: Public Title:体积用户指南 Crumbs:%ROOT%, Engine, Engine/Actors Description: 关于放置及应用体积来增加关卡的行为及设置的指南。 +version:4.16 +type:overview -[TOC(start:2 end:2)] - +[TOC(start:2 end:3)] **体积** 是指您的关卡中的三维区域,每个体积都有其特定的用途。 其中一些用途包括: @@ -61,7 +62,6 @@ h:301 ## 体积类型 - ### 阻挡体积 **Blocking Volume(阻挡体积)** 用作为碰撞模型,对象将不能通过该模型。 您可以通过调整体积(下图所示)上的碰撞通道,来控制允许哪种类型的对象通过该体积,如果有可以通过该体积的对象,那么当这些对象通过该体积时还应该生成重叠事件。 请参照[碰撞相关文档](Engine\Physics\Collision)获得更多细节。 @@ -107,8 +107,6 @@ h:301 有一些针对该体积设置的属性,您可以从 **详细信息** 面板中调整这些属性,如下图所示: -![](killZdetails.png) - | 属性 | 描述 | | ------- | ------------ | | Terminal Velocity(末速度) |决定了应用CharacterMovement 的Pawn下落时的末速度。 | @@ -183,7 +181,6 @@ h:301 您可以从该体积的 **详细信息** 面板中调整它的几个属性,来更好地控制它的效果,如下所示: -![](audiovolume.png) | 属性 | 描述 | | ------- | ------------ | diff --git a/Engine/Documentation/Source/Engine/Actors/Volumes/Volumes.INT.udn b/Engine/Documentation/Source/Engine/Actors/Volumes/Volumes.INT.udn index 13b285f9af1f..6d10a92bafab 100644 --- a/Engine/Documentation/Source/Engine/Actors/Volumes/Volumes.INT.udn +++ b/Engine/Documentation/Source/Engine/Actors/Volumes/Volumes.INT.udn @@ -1,30 +1,31 @@ Availability: Public -Title:Volumes User Guide +Title:Volumes Overview Crumbs:%ROOT%, Engine, Engine/Actors Description:Guide to placing and working with Volumes to augment the behavior and setup of your levels. +version:4.16 +type:overview +Parent:Engine/Actors/Types +order:8 +type:overview -[TOC(start:2 end:2)] +[TOC(start:2 end:3)] - -**Volumes** are 3-dimensional areas within your levels, each of which serve a specific purpose. Some of these purposes include: +**Volumes** are 3-dimensional areas within your levels that can serve variety of purposes. Some of these purposes include: * Causing damage to the Player. -* Blocking the Player from entering the volume, acting as a collision surface. -* Changing the way a level is calculated for lighting or visibility. +* Blocking Actors from entering the volume, acting as a collision surface. +* Detecting and reacting to Actors entering or leaving the volume. +* Changing the way a level calculates its lighting or visibility. -There are many types of volumes that perform a variety of tasks. This document will demonstrate the creation of volumes for your levels, and discuss each of the volume types available in Unreal Engine 4. +## Volume Placement Considerations -### Using Volumes Wisely in Level Design +There are two important points to keep in mind about using volumes: -One aspect about volumes that is critical to new level designers is the importance of using them wisely in a level. This boils down to two key points: +1. Volumes are support actors, generally used to detect when certain Actor types have entered a specific area and trigger an effect in response. +1. Volumes sometimes have built-in effects of their own (either in code or Blueprints), but most often they'll provide cues to other Actors. They should usually be thought of as components of a greater effect, with some other level element acting as a visual cue. -1. Volumes are invisible during gameplay; Players cannot see them! -1. Due to the first point, very rarely will you use a volume by itself for any effect. - -Because volumes are invisible, Players will generally not know that they have entered one; not unless you, as the level designer, help them a bit. Volumes should generally be thought of as components of a greater effect, with some other level element acting as a visual cue to lend understanding and complete the effect. - -Take a **Pain Causing Volume**, for example (which causes damage to anything inside the volume). If one were sitting in the middle of the level, like so... +As an example, a **Pain-Causing Volume**, which causes damage to anything inside the volume, could be placed into a level like this: [VAR:VolumeDemoSize] h:301 @@ -33,20 +34,19 @@ h:301 [REGION:imagetable] |![](PainCausingVolume_NoEffect.png)(%VolumeDemoSize%)|![](PainCausingVolume_NoEffect_NoVolume.png)(%VolumeDemoSize%)| |:-----------:|:----------:| -|Volume placement|What the player will see| +| In Editor | In Game | [/REGION] -Then the Player would not understand why they were suddenly hurt when they entered the area. However, if there were a fiery particle effect in the middle of the volume... +In this case, the player will not know to avoid the volume, or understand why they take damage when they enter it. The level designer should provide a hint to the player that explains the Pain Causing Volume: [REGION:imagetable] |![](PainCausingVolume_Effect.png)(h:343)|![](PainCausingVolume_Effect_NoVolume.png)(h:343)| |:-----------:|:----------:| -|Volume placement|What the player will see| +| In Editor | In Game | [/REGION] -Then the Player has a reason to understand why it hurts to stand there! - +In this case, the fire particle effect provides a visual explanation of why the area is dangerous, while the Pain Causing Volume supports the visuals with a gameplay effect of decreasing the player's health during exposure to the fire. ## Creating Volumes @@ -60,105 +60,25 @@ Once the volume has been placed in the level, you can then resize and (or) repos ## Volume Types +### Audio Volume +**Audio Volumes** allow you to control and apply various sounds in your level as well as provide an avenue to create compartmentilized audio zones where you can control what is heard inside and outside of the volume. Through the use of Audio Volumes, you can generate audio transitions via fading and control the Ambient Zone settings within the volumes themselves. +[REGION:note]See the [details page](Engine/Actors/Volumes/AudioVolumeDetails) for more information on the specific properties of Audio Volumes.[/REGION] + + ### Blocking Volume -A **Blocking Volume** serves as a collision shape through which objects are not intended to pass. By adjusting the collision channels on the volume (pictured below), you can control which types of objects will be allowed to pass, and if any objects should also generate overlap events when they pass through the volume. See the [Collision Documentation](Engine\Physics\Collision) for more details. +A **Blocking Volume** serves as a collision shape through which objects are not intended to pass. By adjusting the collision channels on the volume (pictured below), you can control which types of objects will be allowed to pass, and if any objects should also generate overlap events when they pass through the volume. +[REGION:note]See the [Collision Documentation](Engine\Physics\Collision) for more details.[/REGION] ![](blocking_volume_details.png) -Blocking Volumes can be used in the place of collision surfaces on Static Meshes, particularly in the case of walls in structures. When used in this way, they generally have a few advantages over mesh collision surfaces. The first is that they are easier to calculate than more complex collision models. The second is that since the nature of a volume is to know what objects are within it, a Blocking Volume can be more useful when colliding with high-speed physics objects. +Blocking Volumes can be used in the place of collision surfaces on Static Meshes, particularly in the case of walls in structures. This can cause scenes to operate more predictably, since physical objects won't interact with small details like bumps on the floor and walls. It can also improve performance by reducing the cost of physics simulation. ### Camera Blocking Volume -**Camera Blocking Volumes** are similar in nature to Blocking Volumes in that they are used to define a space where a Camera Actor is not intended to pass through. An example of this would be in a third person perspective, when you want to keep your player's camera confined to your play space and not allow them to rotate the camera outside of the world. +**Camera Blocking Volumes** are volumes with their collision settings pre-configured to block only cameras and ignore everything else. They are intended to define invisible barriers that keep the camera out of bad locations. An example of this might be in a third-person game, when the walls of the play area have decorative coverings like leafy vines. In these cases, a thin Camera Blocking Volume can be placed against the wall so that the camera doesn't bump into the vines or go behind the leaves, leaving it to slide smoothly and provide an unobstructed view of the action in the room. -The properites of the Camera Blocking Volume can be adjusted in the same manner as a Blocking Volume by adjusting their collision channels. - - -### Trigger Volume - -**Trigger Volumes** are used as a way to cause events when a Player or other object enters or exits them. They can be used quickly with the **Level Blueprint** to test out events and gameplay scenarios or functionality without the need for additional Blueprints. - -For example: you could place a TriggerVolume in your level and in your **Level Blueprint**, create an overlap event for the volume which can play a SoundCue, start a Cinematic or even open a door. - - -### Nav Mesh Bounds Volume - -**Nav Mesh Bounds Volumes** are used as a way to control where Nav Meshes will be calculated in a level. Nav Meshes are used to calculate navigation paths throughout the areas of a level. - -Within the volume, a Nav Mesh is constructed on all surfaces with an appropriate angle to be walked upon. You may overlap as many of these as you need to generate the desired Nav Mesh. - -To use the Nav Mesh Bounds Volume, simply create one (or more) that encloses the navigable areas of your level. The Nav Mesh will be built automatically. - -[REGION:tip] -You can press **P** at any time in the viewport to visualize the Nav Mesh. -[/REGION] - -Please see the Content Examples and [Nav Mesh Documentation](Resources\ContentExamples\NavMesh) for more details and examples. - - - -### Physics Volume - -**Physics Volumes** are volumes in which the physical setup that affects characters and other physics objects can be manipulated. A common use for them is for the creation of watery environments in which the player needs to swim. But you could just as easily use one to create an area with low or no gravity and affect the terminal velocity of objects that pass through it. - -There are some properties that are designated for this volume which can be adjusted from the **Details** panel, pictured below. - -![](killZdetails.png) - -|Property| Description | -| ------- | ------------ | -| **Terminal Velocity** | Determines the Terminal Velocity of Pawns using CharacterMovement when falling. | -| **Priority** | Determines which PhysicsVolume takes precedence if they overlap. | -| **Fluid Friction** | Determines the amount of friction applied by the volume as Pawns using CharacterMovement move through it.
The higher this value, the harder it will feel to move through the volume. | -| **Water Volume** | Determines if the volume contains a fluid, like water. | -| **Physics on Contact** | Determines if the Actor is affected by the volume by touching it (by Default, an Actor must be inside the volume for it to affect them). | - - -### Pain Causing Volume - -**Pain Causing Volumes** are actually Physics Volumes with the added ability to inflict damage on players. These are useful when you have obvious areas of a level that the player should not go, such as a lava pit, a cloud of toxic gas, and so on. - -In addition to the properties that can be assigned from a Physics Volume, the Pain Causing Volume also has its own set of specific propteries outlined below. - -![](paincausingvolume.png) - -|Property| Description | -| ------- | ------------ | -| **Pain Causing** | Whether the volume currently causes damage or not. | -| **Damage Per Sec** | Damage done per second to the Actors in the volume when Pain Causing is enabled. | -| **Damage Type** | This determines the type of damage done to the Actor. | -| **Pain Interval** | This is the amount of time, in seconds, between applied damage when Pain Causing is enabled. | -| **Entry Pain** | Determines if damage is applied when entering the volume if Pain Causing is enabled in addition to damage applied based on the Pain Interval. | - - - -### Kill Z Volume - -The **Kill Z Volume** or "Kill-Brush" essentially destroys any Actor that enters the volume (this includes the Player). One usage for this type of volume would be to set it up below a cliffside or high ledge that you want to kill the Player or Actor that falls down into it. - - - -### Level Streaming Volumes - -[EXCERPT:LSV] -**Level Streaming Volumes** are used to aid in the [level streaming](Engine/LevelStreaming) process. They provide for a simple way to encapsulate a level, as well as control when it streams in and out of memory, based on when a Player enters and exits the volume. - -You can adjust how a Level Streaming Volume handles level streaming by adjusting the properties from the **Details** panel, pictured below. - -![](levelstreamingvolume.png) - -|Property| Description | -| ------- | ------------ | -| **Streaming Levels** | Displays the levels affected by the volume. | -| **Editor Pre Vis Only** | Determines if the streaming volume should only be used for editor streaming level previs. | -| **Disabled** | If true, the streaming volume is ignored by the streaming volume code.
Also used to either disable a Level Streaming Volume without disassociating it from the level, or to toggle the control of a level's streaming between Blueprints and Volume Streaming. | -| **Streaming Usage** | Determines what the volume is used for, e.g. whether to control loading, loading and visibility, or just visibility (blocking on load). | - -[/EXCERPT] - -For more on Level Streaming Volumes, see [](Engine/LevelStreaming/StreamingVolumes). ### Cull Distance Volume @@ -170,66 +90,93 @@ Cull Distance Volume setup is dependent on the **Cull Distances** property, show In the image above, the properties define the following behavior: -* Objects within the volume that have a size closest to 50 units (85 units or less) will be culled (disappear) when they are 500 units away from the camera or farther. -* Objects within the volume that have a size closest to 120 units (85 to 210 units) will be culled (disappear) when they are 1000 units away from the camera or farther. -* Objects within the volume that have a size closest to 300 units (210 units or more) will never be culled, since 0 in this case is considered to be infinity, meaning that the camera can never get far enough away. +* Objects within the volume that have a size closest to 50 units (distance equal to or less than 85 units) will be culled (disappear) when they are 500 units away from the camera or farther. +* Objects within the volume that have a size closest to 120 units (distance between 85 units and 210 units) will be culled (disappear) when they are 1000 units away from the camera or farther. +* Objects within the volume that have a size closest to 300 units (distance equal to or greater than 210 units) will never be culled, since 0 in this case is treated as infinity, meaning that the camera can never get far enough away. -Setup starts with adding a new entry into the Cull Distances array, which is done by clicking the ![](button_Plus.png) button. Next, simply fill in the size of a given object and the desired distance at which you want objects of that size or smaller to be culled. These properties do not have to be created in a specific order. +Setup starts with adding a new entry into the Cull Distances array, which is done by clicking the ![](button_Plus.png) button. Next, simply fill in the size of a given object and the desired distance at which you want objects of that size or smaller to be culled. These properties do not have to be created in a specific order. -### Audio Volume -**Audio Volumes** allow you to control and apply various sounds in your level as well as provide an avenue to create compartmentilized audio zones where you can control what is heard inside and outside of the volume. Through the use of Audio Volumes, you can generate transitions between audio through fading and control the Ambient Zone settings within the volume itself. -Several properties can be adjusted from the **Details** panel on this volume to allow for more control over its effects as seen below. +### Hierarchical LOD Volume -![](audiovolume.png) +**Hierarchical LOD Volumes** have no special properties, but are used by the [HLOD](Engine/HLOD) system to group Actors into a single HLOD cluster. When generating clusters, the Unreal Engine will override its normal generation process in deference to manually-placed volumes. -|Property| Description | -| ------- | ------------ | -| **Priority** | In the event of overlapping volumes, the highest priority volume will be used. The order is undefined if two or more overlapping volumes have the same priority. | -| **Apply Reverb** | Determines if the reverb settings should be used. | -| **Reverb Effect** | This is the reverb asset to use for the volume. | -| **Volume** | This is the overall volume level of the reverb effect. | -| **Fade Time** | This is the time (in seconds) to fade from the current reverb settings into the volumes setting. | -| **Enabled** | Determines whether the volume is currently enabled and is able to affect sounds. | -**Ambient Zones** define how Sound Actors located inside the associated Audio Volume will be altered by the Player's location. The settings for the Ambient Zone can also be adjusted from the **Details** panel. +### Kill Z Volume -|Property| Description | -| ------- | ------------ | -| **Exterior Volume** | The final volume of exterior sounds when the player is inside the volume. | -| **Exterior Time** | Time to fade to new exterior volme in seconds. | -| **Exterior LPF** | Lowpass Filter multiplier applied to exterior sounds when inside (1.0 to apply the maximum LPF). | -| **Exterior LPFTime** | Time to fade to new Lowpass Filter level in seconds. | -| **Interior Volume** | The final volume of interior sounds when the player is outside the volume. | -| **Interior Time** | Time to fade to new interior volume in seconds. | -| **Interior LPF** | Lowpass Filter multiplier applied to interior sounds when outside (1.0 to apply the maximum LPF). | -| **Interior LPFTime** | Time to fade to new Lowpass Filter level in seconds. | +The purpose of **Kill Z Volume** is to prevent objects from going out of bounds in certain types of games, such as falling off of a cliff or into a pit in a platformer game, or leaving a spaceship without a suit in a science-fiction setting. The Kill Z Volume will call the `FellOutOfWorld` function on any Actor that enters it, and by default, Actors will go through a quick cleanup procedure and then destroy themselves. You can override this behavior for any of your Actor types if your game requires something different. For example, if a key or other item that the player is required to collect in order to continue the game falls into a lava pit, your game might want to teleport the item back up to an area the player can reach rather than destroying it, or at least inform the player that the item was lost and reload the last checkpoint, rather than leaving the game in an unwinnable state. + + +### Level Streaming Volumes + +[EXCERPT:LSV] +**Level Streaming Volumes** are used to aid in the [level streaming](Engine/LevelStreaming) process. They provide a simple way to encapsulate a level, as well as control when it streams in and out of memory, based on when a Player enters or exits the volume. +[/EXCERPT] + + +### Lightmass Character Indirect Detail Volume + +The **Lightmass Character Indirect Detail Volume** is similar to the Lightmass Importance Volume and generates indirect light samples, not just at Player height above ground, but generates them inside the entire Volume. An example usage of this type of Volume would be an elevator shaft to ensure the indirect lighting is correct extending up/down the shaft. + + +### Lightmass Importance Volume + +**Lightmass Importance Volumes** are used to focus Lightmass calculations. Lightmass is the precalculated lighting and global illumination system used in Unreal Engine 4. In order to minimize - and thereby optimize - the amount of processing needed to generate precalculated lights in a level, Lightmass Importance Volumes are use to enclose the areas of the level geometry. Lightmass will only calculate within that area, skipping anything outside of it. +[REGION:note]For more information on Lightmass and Lightmass Importance Volumes, please see the [Lightmass documentation](Engine/Rendering/LightingAndShadows/Lightmass).[/REGION] + + +### Mesh Merge Culling Volume + +**Mesh Merge Culling Volumes** mark the mesh objects they contain so that these objects will be combined into a single mesh. This can improve performance by making a collection of small meshes in a contained area all cull together as one mesh, or by causing [HLOD](Engine/HLOD) generation to reduce geometry in a more optimal way. + + +### Nav Mesh Bounds Volume + +**Nav Mesh Bounds Volumes** are used as a way to control where Nav Meshes will be built in a level. Nav Meshes are used to calculate navigation paths throughout the areas of a level. + +Within the volume, a Nav Mesh is constructed on all surfaces with an appropriate angle to be walked upon. You may overlap as many of these as you need to generate the desired Nav Mesh. + +To use the Nav Mesh Bounds Volume, simply create one (or more) that encloses the navigable areas of your level. The Nav Mesh will be built automatically. + +[REGION:tip] +You can press **P** at any time in the viewport to visualize the Nav Mesh. +[/REGION] + +[REGION:note]Please see the Content Examples and [Nav Mesh Documentation](Resources\ContentExamples\NavMesh) for more details and examples.[/REGION] + + +### Pain-Causing Volume + +**Pain-Causing Volumes** are Physics Volumes with the ability to inflict damage on players. These are useful when you have obvious areas of a level that the player should not go, such as a lava pit, a cloud of toxic gas, and so on. +[REGION:note]See the [details page](Engine/Actors/Volumes/PainCausingVolumeDetails) for more information on the specific properties of Pain-Causing Volumes.[/REGION] + + +### Physics Volume + +**Physics Volumes** are volumes in which the physical setup that affects characters and other physics objects can be manipulated. A common use for them is for the creation of watery environments in which the player needs to swim. The effects of Physics Volumes are visible and can be interpreted as desired. The Character Movement Component class uses the current fields to adjust how their owning `Character` moves through the environment. If your game has custom physics, deriving your own child class from `APhysicsVolume` can help you to provide it. +[REGION:note]See the [details page](Engine/Actors/Volumes/PhysicsVolumeDetails) for more information on the specific properties of Physics Volumes.[/REGION] - ### Post Process Volume A **Post Process Volume** is a space in which the Post Process settings applied to the camera can be overridden by adjusting the properties in the **Details** panel. - -For more information on Post Processing, please see the [Post Processing Documentation](Engine/Rendering/PostProcessEffects). +[REGION:note]For more information on Post Processing, please see the [Post Processing Documentation](Engine/Rendering/PostProcessEffects).[/REGION] -### Lightmass Importance Volume - -**Lightmass Importance Volumes** are used to focus Lightmass calculations. Lightmass is the precalculated lighting and global illumination system used in Unreal Engine 4. In order to minimize - and thereby optimize - the amount of processing needed to generate precalculated lights in a level, Lightmass Importance Volumes are use to enclose the areas of the level geometry. Lightmass will only calculate within that area, skipping anything outside of it. - -For more information on Lightmass and Lightmass Importance Volumes, please see the [Lightmass documentation](Engine/Rendering/LightingAndShadows/Lightmass). - - -### Lightmass Character Indirect Detail Volume -The **Lightmass Character Indirect Detail Volume** is similar to the Lightmass Importance Volume and generates indirect light samples, not just at Player height above ground, but generates them inside the entire Volume. An example usage of this type of Volume would be an elevator shaft to ensure the indirect lighting is correct extending up/down the shaft. - - -### Precomputed Visibility Volume -**Precomputed Visibility Volumes** are used primiarly for performance optimization. These volumes store the visibility of Actors for their location in the world. These should be placed only in areas the Player can access. +### Precomputed Visibility Volume +**Precomputed Visibility Volumes** are used primiarly for performance optimization. These volumes store the visibility of Actors for their location in the world. These should be placed only in areas the Player can access. ### Precomputed Visibility Override Volume -**Precomputed Visibility Override Volumes** let you manually override the visibility of Actors for their location in the world if the auto generated result of a Precomputed Visibilty Volume is undesired. These are also used for performance optimization and should only be placed in areas where the Player can access. - +**Precomputed Visibility Override Volumes** let you manually override the visibility of Actors for their location in the world if the auto generated result of a Precomputed Visibilty Volume is undesired. These are also used for performance optimization and should only be placed in areas where the Player can access. + +### Trigger Volume + +**Trigger Volumes** are used as a way to cause events when a Player or other object enters or exits them. They can be used quickly with the **Level Blueprint** to test out events and gameplay scenarios or functionality without the need for additional Blueprints. + +For example, you could place a TriggerVolume in your level, then create an overlap event for the volume in your **Level Blueprint** which can play a sound, open a door, or start a cinematic scene. + +[REGION:note] +Remember to check the collision settings to ensure that your trigger will react to the intended Actors with the Overlap collision response setting. +[/REGION] diff --git a/Engine/Documentation/Source/Engine/Actors/Volumes/Volumes.JPN.udn b/Engine/Documentation/Source/Engine/Actors/Volumes/Volumes.JPN.udn index 5faae51ec188..992bf943b0b6 100644 --- a/Engine/Documentation/Source/Engine/Actors/Volumes/Volumes.JPN.udn +++ b/Engine/Documentation/Source/Engine/Actors/Volumes/Volumes.JPN.udn @@ -1,31 +1,32 @@ -INTSourceChangelist:3283566 +INTSourceChangelist:3429227 Availability:Public -Title:ボリュームに関するユーザーガイド +Title:ボリュームの概要 Crumbs:%ROOT%, Engine, Engine/Actors Description:ボリュームを配置および操作してビヘイビアとレベル設定を拡張してみましょう +version:4.16 +type:overview +Parent:Engine/Actors/Types +order:8 +type:overview -[TOC(start:2 end:2)] +[TOC(start:2 end:3)] - -**ボリューム** とはレベル内の 3D 領域のことです。各ボリュームには以下のような特定の用途があります。 +**ボリューム** とはレベル内の 3D 領域のことであり、以下のような多様な用途に対応します。 * プレイヤーにダメージを与えます。 -* コリジョン サーフェスとして、プレイヤーがボリューム内へ立ち入ることをブロックします。 -* ライティングや可視性を考慮してレベルの計算方法を変更します。 +* コリジョン サーフェスとして、アクタがボリューム内へ立ち入ることをブロックします。 +* ボリュームに入る、または離れるアクタを検知し、反応します。 +* レベルがライティングや可視性を計算する方法を変更します。 -ボリュームには数多くの種類があり、様々なタスクを実行します。このドキュメントでは、レベルでボリュームを作成する方法を紹介します。またアンリアル エンジン 4 (UE4) で利用できるボリュームの種類についても説明します。 +## ボリュームを配置する際の考慮事項 -### レベル デザインでボリュームを賢く使う方法 +ボリューム使用に際して覚えておく重要なポイントは以下の 2 つです。 -レベル デザイナーにとって、レベル内でボリュームをうまく使いこなせることが非常に重要です。ポイントは大きく以下の 2 つです。 +1. ボリュームはサポート アクタであり、一般的に特定タイプのアクタが特定エリアに入ったときに検知して反応しエフェクトをトリガーします。 +1. ボリュームによっては独自のビルトイン エフェクトを持つ (コードまたはブループリントで) ことがありますが、多くの場合、他のアクタに手がかりを与えます。ボリュームは、一般的により大きなエフェクトのコンポーネントとして考えられます。他のレベル エレメントが、視覚的手ががりになります。 -1. ボリュームはゲームプレイ中は目に見えないため、プレイヤーが見ることはできません! -1. つまり、ボリューム自体を何かのエフェクトに使用することはほとんどありません。 - -ボリュームは不可視であるため、レベルデザイナーが手がかりを与えない限り、プレイヤーはボリュームへ入ったことに通常気づきません。ボリュームは、一般的により大きなエフェクトのコンポーネントとして考えられます。他のレベル エレメントが、そのエフェクトをわかりやすくし、完成させる視覚的手ががりになります。 - -**Pain Causing Volume** を例に見てみましょう (ボリューム内のもの全てに対してダメージを与えます)。例えばこのようにレベルの真ん中に人が座っている場合… +例として **Pain-Causing Volume** があります。これは、ボリューム内にあるものに対してダメージを与えます。以下のようにレベルに配置します。 [VAR:VolumeDemoSize] h:301 @@ -34,20 +35,19 @@ h:301 [REGION:imagetable] |![](PainCausingVolume_NoEffect.png)(%VolumeDemoSize%)|![](PainCausingVolume_NoEffect_NoVolume.png)(%VolumeDemoSize%)| |:-----------:|:----------:| -|ボリュームの配置 | プレイヤーからの見え方| +| エディタ内 | インゲーム | [/REGION] -プレイヤーは、その領域へ入った途端、なぜ自分が怪我するのか理解できません。しかしながら、火を使用したパーティクル エフェクトがボリュームの中央にあると… +この場合、プレイヤーはボリュームを避ける方法を知らないか、中に入ったら何故ダメージを受けるかを理解しています。レベル デザイナーは、Pain Causing ボリュームを説明するヒントをプレイヤーに与えるようにします。 [REGION:imagetable] |![](PainCausingVolume_Effect.png)(h:343)|![](PainCausingVolume_Effect_NoVolume.png)(h:343)| |:-----------:|:----------:| -|ボリュームの配置 | プレイヤーからの見え方| +| エディタ内 | インゲーム | [/REGION] -この場所に立つと、なぜ怪我をするのか、プレイヤーから一目瞭然です。 - +この場合、炎のパーティクル エフェクトが何故そのエリアが危険であるかを視覚的に説明しますが、Pain Causing ボリュームには炎にさらされたときにプレイヤーのヘルスを減らすゲームプレイ エフェクトで視覚的にサポートします。 ## ボリュームの作成 @@ -56,181 +56,128 @@ h:301 ![](creatingVolumes.png) -ボリュームがレベル内に配置されると、ぴったりするまでボリュームのリサイズおよび再配置ができるようになります。 +ボリュームがレベル内に配置すると、見た目が適切になるようにボリュームのリサイズおよび再配置ができるようになります。 ## ボリュームの種類 +### Audio Volume +**Audio Volume** は、ボリュームの内外で聞こえるものを制御する区切られたオーディオゾーンを作成するだけでなく、レベル内で様々なサウンドの制御と適用を可能にします。Audio Volume を使用すると、フェーディングによりオーディオ間のトランジションを生成し、ボリューム自体の中で Ambient Zone 設定を制御することができます。 +[REGION:note]Audio Volume の各プロパティの情報については、 [詳細ページ](Engine/Actors/Volumes/AudioVolumeDetails) をご覧ください。[/REGION] + + ### Blocking Volume -**Blocking Volume** は、オブジェクトが通過できないコリジョン形状の役割をします。ボリューム上でコリジョン チャネルが調整されると (下の画像)、どのタイプのオブジェクトが通過できるのか、また、ボリュームを通過する時にオブジェクトがオーバーラップ イベントを生成すべきかどうかを制御できるようになります。詳細は、 [コリジョンのドキュメント](Engine\Physics\Collision) をご覧ください。 +**Blocking Volume** は、オブジェクトが通過できないコリジョン形状の役割をします。ボリューム上でコリジョン チャンネルを調整すると (下の画像)、どのタイプのオブジェクトが通過できるのか、また、ボリュームを通過する時にオブジェクトがオーバーラップ イベントを生成すべきかを制御できるようになります。 +[REGION:note]詳細は、 [コリジョンのドキュメント](Engine\Physics\Collision) をご覧ください。[/REGION] ![](blocking_volume_details.png) -Blocking Volume はスタティックメッシュ上のコリジョン サーフェスの場所、特に構造体の中に壁がある場合に使用することができます。このように使用すると、通常、メッシュ コリジョン サーフェスよりも優れた点が幾つかあります。まず、複雑なコリジョン モデルよりも、計算が簡単にできます。次に、ボリュームはその性質上、中にどのようなオブジェクトがあるか分かるため、高速の物理オブジェクトと衝突する場合、Blocking Volume が便利です。 +Blocking Volume はスタティックメッシュ上のコリジョン サーフェスの場所、特に構造体の中に壁がある場合に使用することができます。これにより、シーンは予測しやすくなります。物理オブジェクトは床や壁のバンプなどの小さなものとインタラクションしなくなるからです。物理シミュレーションの負荷を減らすことでパフォーマンスも向上します。 ### Camera Blocking Volume -**Camera Blocking Volume** は、カメラ アクタが通過しないことを意図した空間の定義に使用されるという点で本質的に Blocking Volume と似ています。三人称視点がその例です。プレイヤーのカメラをプレイ スペースだけに制限したいので、カメラがワールドの外側で回転しないようにします。 +**Camera Blocking Volume** はコリジョン設定でカメラだけをブロックし他のものは無視するように事前設定します。カメラが不適切な位置にならないように目に見えないバリアを定義することを意図しています。この例として、三人称視点のゲームでプレイ エリアの壁がツタの葉などの装飾で覆われている場合があります。このような場合、薄い Camera Blocking Volume を壁に対して配置し、カメラがツタにぶつからないようにしたり、葉の裏側に行かないようにし、滑らかにスライドさせて、室内のアクションをさえぎる物がない状態で見えるようにします。 -Camera Blocking Volume のプロパティは、Blocking Volume と同じく、コリジョン チャンネルで調節します。 - - -### Trigger Volume - -**Trigger Volume** は、プレイヤーまたは他のオブジェクトがそこに出入りする際にイベントを発生させるために使います。Trigger Volume は、 **Level ブループリント** と一緒に手軽に使用して、イベントとゲームプレイのシナリオや機能をブループリントの追加を一切せずにテストすることができます。 - -例えば、レベル内および **Level ブループリント** 内に TriggerVolume を配置し、そのボリュームで SoundCue を再生したり、シネマティックスを開始したり、ドアを開けることもできるオーバーラップ イベントを作成します。 - - -### Nav Mesh Bounds Volume - -**Nav Mesh Bounds Volume** は、レベル内における Nav Mesh の計算場所を制御するために使用します。Nav Mesh は、レベル領域のすべての場所でナビゲーション パスを計算するために使用します。 - -ボリューム内で、適切な歩行角度で全てのサーフェス上に Nav Mesh が作成されます。必要に応じて、これらの Nav Mesh を好きなだけオーバーラップすることができます。 - -レベル内でナビゲーションが可能な領域を囲む Nav Mesh を 1 つ以上作成するだけで、Nav Mesh Bounds Volume が使用できるようになります。Nav Mesh が自動的にビルドされます。 - -[REGION:tip] -**[P]** を押せば、いつでも Nav Mesh をビューポートに表示することができます。 -[/REGION] - -詳細は、コンテンツ サンプルと [NavMesh に関するドキュメント](Resources\ContentExamples\NavMesh) をご覧ください。 - - - -### Physics Volume - -**Physics Volume** は、キャラクターや他の物理オブジェクトに影響を与える物理のセットアップを操作できるボリュームです。主に、プレイヤーが泳がなければならない水のある背景の作成に使用されます。ただし、低重力、または無重力の領域を作成し、そこを通るオブジェクトの終端速度に影響を与えるためにも簡単に使用できます。 - -このボリューム用に指定されたプロパティの中には、以下の画像のように、**[Details (詳細)]** パネルから調整可能なものもあります。 - -![](killZdetails.png) - -| プロパティ | 説明 | -| ------- | ------------ | -| **Terminal Velocity** | 落下時に CharacterMovement を使ってポーンの Terminal Velocity を判断します。 | -| **Priority** | オーバーラップした場合、優先する PhysicsVolume を判断します。 | -| **Fluid Friction** | CharacterMovement を使用しているポーンが通過する際にボリュームが適用する摩擦量を判断します。
この値が高いほど、ボリューム内の移動が困難になります。 | -| **Water Volume** | ボリュームに水などの液体が含まれているかを判断します。 | -| **Physics on Contact** | ボリュームに触れることでアクタが影響を受けるかを判断します (アクタが影響を受けるためには、デフォルトでボリューム内にいる必要があります)。 | - - -### Pain Causing Volume - -**Pain Causing Volume** は、実は Physics Volume にプレーヤーにダメージを与える機能を追加したものです。溶岩の穴、毒ガスのもくもくした塊など、明らかにプレイヤーが行くべきでない領域がレベルに存在する場合に便利です。 - -Physics Volume から割り当てが可能なプロパティの他に、Pain Causing Volume には以下の固有のプロパティも付いています。 - -![](paincausingvolume.png) - -| プロパティ | 説明 | -| ------- | ------------ | -| **Pain Causing** | Volume が現在ダメージを与えるかどうかを決定します。 | -| **Damage Per Sec** | Pain Causing が有効な場合、ボリューム内のアクタに毎秒単位で与えられるダメージです。 | -| **Damage Type** | アクタに与えるダメージの種類を決定します。 | -| **Pain Interval** | Pain Causing が有効な場合にダメージが与えられる間隔の秒単位の時間です。 | -| **Entry Pain** | Pain Causing が有効な場合、Pain Interval により適用されたダメージに加えて、ボリュームに入った時点でダメージが与えられるかどうかを決定します。 | - - - -### Kill Z Volume - -**Kill Z Volume** または「Kill-Brush」は、ボリュームに入ってきたアクタを基本的に全て破壊します (プレイヤーも含まれます)。この種類のボリュームの使用方法としては、崖または高いレッジの下に設定し、そこに落ちたプレイヤーやアクタを消去する、などがあげられます。 - - - -### Level Streaming Volume - -[EXCERPT:LSV] -**Level Streaming Volume** は [レベル ストリーミング](Engine/LevelStreaming) のプロセスを支援するために使用します。また、プレイヤーのボリュームの出入りに合わせてレベルがメモリに入出力される際、レベルを簡単にカプセル化および制御できるようにします。 - -以下の画像のように、**[Details (詳細)]** パネルからプロパティを調整すれば、Level Streaming Volume のレベル ストリーミング処理方法を調整できます。 - -![](levelstreamingvolume.png) - -| プロパティ | 説明 | -| ------- | ------------ | -| **Streaming Levels** | ボリュームの影響を受けるレベルを表示します。 | -| **Editor Pre Vis Only** | ストリーミング ボリュームをエディタ ストリーミング レベルのプレビズ用にのみ使用するかを判断します。 | -| **Disabled** | true の場合、ストリーミング ボリュームはストリーミング ボリューム コードで無視されます。
レベルから切り離さないで Level Streaming Volume を無効化するか、または Blueprints と Volume Streaming 間でのレベルのストリーミングの切り替えのためにも使用されます。| -| **Streaming Usage** | ボリュームを何に使うのか、ロードの制御、ロードと可視性または可視性のみなのか (ロード時にブロック) などを判断します。 | - -[/EXCERPT] - -Level Streaming Volume に関する詳しい情報は、[](Engine/LevelStreaming/StreamingVolumes) をご覧ください。 ### Cull Distance Volume -**Cull Distance Volume** は、オブジェクトのカメラからの距離とサイズに応じてオブジェクトをカリング (すなわちスクリーンに描画されないように) できる最適化ツールです。重要でないとみなされるくらい小さなオブジェクトをシーンに描画しないことにより最適化します。サイズは、最長寸法に合わせてバウンディング ボックスで計算され、選択されるカリング距離がそのサイズに最も近いものになります。 +**Cull Distance Volume** は、オブジェクトのカメラからの距離とサイズに応じてオブジェクトをカリング (すなわちスクリーンに描画されないように) できる最適化ツールです。小さくて重要でないと思われるオブジェクトをシーンに描画しないことにより最適化します。サイズは、最長寸法に合わせてバウンディング ボックスで計算され、選択されるカリング距離がそのサイズに最も近いものになります。 -Cull Distance Volume 設定は、以下の **[Details]** パネルに表示されている **Cull Distances** プロパティにより異なります。 +Cull Distance Volume 設定は、以下の **[Details]** パネルに表示されている **[Cull Distances]** プロパティに依存します。 ![](CullDistancesProperty.png) 上図のプロパティでは、動作が以下のように定義されます。 -* サイズが 50 ユニット (85 ユニット未満) に最も近いボリューム内のオブジェクトは、カメラから 500 ユニット位以上離れるとカリングされ (消滅し) ます。 -* サイズが 120 ユニット(85 から 210 ユニット) に最も近いボリューム内のオブジェクトは、カメラから 1000 ユニット位以上離れるとカリングされ (消滅し) ます。 -* サイズが 300 ユニット (210 ユニット以上) に最も近いボリューム内のオブジェクトは、このケースでは 0 は無限遠とみなされ、カメラが十分に遠ざかることはできないため、カリングされることはありません。 +* サイズが 50 ユニット (85 ユニット以下の距離) に最も近いボリューム内のオブジェクトは、カメラから 500 ユニット以上離れるとカリングされ (消滅し) ます。 +* サイズが 120 ユニット(85 から 210 ユニットの間の距離) に最も近いボリューム内のオブジェクトは、カメラから 1000 ユニット以上離れるとカリングされ (消滅し) ます。 +* サイズが 300 ユニット (210 ユニット以上の距離) に最も近いボリューム内のオブジェクトは、この場合 0 は無限遠として扱われ、カメラが十分に遠ざかることができないため、カリングされることはありません。 -Cull Distances 配列にエントリを新規に追加して設定を開始します。これは ![](button_Plus.png) ボタンをクリックすれば完了です。次に、任意のオブジェクトのサイズ、およびそのサイズ以下のオブジェクトをカリングしたい希望の距離を入力します。これらのプロパティは、特定の順序で作成する必要はありません。 +Cull Distances 配列にエントリを新規に追加して設定を開始します。これは ![](button_Plus.png) ボタンをクリックすれば完了です。次に、任意のオブジェクトのサイズ、およびそのサイズ以下のオブジェクトをカリングしたい希望の距離を入力します。これらのプロパティは、特定の順序で作成する必要はありません。 -### Audio Volume -**Audio Volumes** は、ボリュームの内外で聞こえるものを制御する区切られたオーディオゾーンを作成する方法を提供するだけでなく、レベル内で様々なサウンドの制御と適用を可能にします。Audio Volumes を使用すると、フェーディングによりオーディオ間のトランジションを生成し、ボリューム自体の中で Ambient Zone 設定を制御することができます。 -このボリュームの **[Details]** パネルからプロパティをいくつか調整し、下図のようにエフェクトをより制御できるようになります。 +### Hierarchical LOD Volume -![](audiovolume.png) +**Hierarchical LOD Volume** には特殊なプロパティはありませんが、[HLOD](Engine/HLOD) システムが複数アクタを単一の HLOD クラスタにグループ化するために使われます。クラスタ生成時にアンリアル エンジンは手動配置したボリュームに配慮して通常の生成プロセスをオーバーライドします。 -| プロパティ | 説明 | -| ------- | ------------ | -| **Priority** | ボリュームがオーバーラップする場合、優先度の一番高いボリュームが使用されます。2 つ以上のオーバーラップしているボリュームが同じ優先度の場合、順序は決まっていません。| -| **Apply Reverb** | リバーブ設定を使うかどうかを判断します。 | -| **Reverb Effect** | ボリュームに使うリバーブ アセットです。 | -| **Volume** | リバーブ エフェクトの全体的なボリューム レベルです。 | -| **Fade Time** | 現在のリバーブ設定からボリューム設定へフェードする時間 (秒) です。 | -| **Enabled** | ボリュームが現在有効で、音に影響を与えることができるかどうかを判断します。 | -**Ambient Zone** は、関連する Audio Volume 内に置かれているサウンド アクタがプレイヤーの位置によってどのように変化するかを定義します。Ambient Zone の設定は **[Details]** パネルからも調整することができます。 +### Kill Z Volume -| プロパティ | 説明 | -| ------- | ------------ | -| **Exterior Volume** | プレイヤーがボリューム内にいる時の外部サウンドの最終的なボリューム。 | -| **Exterior Time** | 新規の外部ボリュームへフェードする秒時間。 | -| **Exterior LPF** | プレイヤーがボリューム内部にいる場合に、外部サウンドへ適用されるローパスフィルタ乗数 (最大適用 LPF は 0.1)。 | -| **Exterior LPFTime** | 新規のローパスフィルタ レベルにフェードする秒時間。 | -| **Interior Volume** | プレイヤーがボリューム外にいる時の内部サウンドの最終的なボリューム。 | -| **Interior Time** | 新規の内部ボリュームにフェードする秒時間。 | -| **Interior LPF** | プレイヤーがボリュームの外側にいる時の内側のサウンドのローパスフィルタ乗数 (最大 LPF の適用は 0.1)。 | -| **Interior LPFTime** | 新規のローパス フィルタ レベルにフェードする秒時間。 | +**Kill Z Volume** は、ある種のゲームでオブジェクトが境界から出るのを防ぐためのものです。例えば、プラットフォーマー ゲームで崖から落ちる、穴に落ちる、または SF ゲームでスーツを着用せずに宇宙船を離れるなどを防ぎます。Kill Z Volume は任意のアクタが入ってくると `FellOutOfWorld` 関数を呼び出します。デフォルトでアクタは迅速なクリーンアップ プロシージャを経て自己を破壊します。制作しているゲームで何か違うものを必要としているならば、どのアクタのタイプでもこのビヘイビアをオーバーライドすることができます。例えば、プレイヤーがゲームを続けるために集める必要があるキーまたはその他のアイテムが溶岩の穴に落ちたら、破棄して勝つ見込みがない状態のままにするよりも、ゲームではそのアイテムをテレポートしてプレイヤーが届く場所に戻すのが望ましいでしょう。または少なくともプレイヤーにアイテムが失われたことを通知し、最後のチェックポイントをリロードするとよいでしょう。 - -### Post Process Volume +### Level Streaming Volume -**Post Process Volume** は **[Details]** パネルのプロパティを調整することでオーバーライドできるカメラに適用される Post Process 設定のあるスペースです。 - -ポストプロセスに関する詳細は [ポストプロセスのドキュメント](Engine/Rendering/PostProcessEffects) を参照してください。 - - -### Lightmass Importance Volume - -**Lightmass Importance Volume** は Lightmass 計算にフォーカスするために使用します。Lightmass とは、事前に計算した光源およびグローバル イルミネーション システムで、アンリアル エンジン 4 で使用されています。レベル内に事前計算されたライトの作成に必要な処理量を最小限に抑える、つまり最適化するために、 Lightmass Importance Volume を使用してレベル ジオメトリ領域を囲います。Lightmass は、領域外のものは飛ばして、その領域内でのみ計算を行います。 - -Lightmass および Lightmass Importance Volumes に関する詳細は、 [Lightmass に関するドキュメント](Engine/Rendering/LightingAndShadows/Lightmass) を参照してください。 +[EXCERPT:LSV] +**Level Streaming Volume** は [レベル ストリーミング](Engine/LevelStreaming) プロセスを支援するために使用します。また、プレイヤーのボリュームの出入りに合わせてレベルがメモリに入出力される際、レベルを簡単にカプセル化および制御できるようにします。 +[/EXCERPT] ### Lightmass Character Indirect Detail Volume -**Lightmass Character Indirect Detail Volume** は Lightmass Importance Volume と同様に間接ライトのサンプルを生成します。グラウンド上のプレイヤーの高さだけではなく、ボリューム全体の内部にもサンプルを生成します。このタイプのボリュームの使用例は、間接ライティングが確実にシャフトの方向へ正しく伸びるようにするエレベータ シャフトです。 + +**Lightmass Character Indirect Detail Volume** は Lightmass Importance Volume に類似しており、間接ライトのサンプルを生成します。グラウンド上のプレイヤーの高さだけではなく、ボリューム全体の内部にもサンプルを生成します。このタイプのボリュームの使用例として、間接ライティングが確実にシャフトの方向へ上下に正しく伸びるエレベータ シャフトがあります。 -### Precomputed Visibility Volume -**Precomputed Visibility Volume** は主にパフォーマンスの最適化に使用されます。これらのボリュームは、ワールド内の位置に対するアクタの可視性を格納します。プレイヤーがアクセスできるエリアのみに配置されます。 +### Lightmass Importance Volume + +**Lightmass Importance Volume** は Lightmass 計算にフォーカスするために使用します。Lightmass とは、事前計算されたライティングおよびグローバル イルミネーション システムで、アンリアル エンジン 4 で使用されています。レベル内に事前計算されたライトの生成に必要な処理量を最小限に抑える、つまり最適化するために、 Lightmass Importance Volume を使用してレベル ジオメトリ領域を囲います。Lightmass は、領域外のものはスキップして、その領域内でのみ計算を行います。 +[REGION:note]Lightmass および Lightmass Importance Volumes に関する詳細は、 [Lightmass に関するドキュメント](Engine/Rendering/LightingAndShadows/Lightmass) を参照してください。[/REGION] + + +### Mesh Merge Culling Volume + +**Mesh Merge Culling Volumes** は、そこに含まれるメッシュ オブジェクトをマーク付けし、こうしたオブジェクトが単一のメッシュに結合されるようにします。これはあるエリアに含まれる小さなメッシュの集まりをひとつのメッシュとしてまとめてカリングする、または [HLOD](Engine/HLOD) 生成によって最適な方法でジオメトリを減らすことでパフォーマンスを向上させます。 + + +### Nav Mesh Bounds Volume + +**Nav Mesh Bounds Volume** は、レベル内のどこに Nav Mesh をビルドするかを制御するために使用します。Nav Mesh は、レベル領域のすべての場所でナビゲーション パスを計算するために使用します。 + +ボリューム内で、適切な歩行角度で全てのサーフェス上に Nav Mesh が作成されます。必要に応じて、これらの Nav Mesh を好きなだけオーバーラップさせて望ましい Nav Mesh を生成することができます。 + +レベル内でナビゲーションが可能な領域を囲む Nav Mesh を 1 つ以上作成するだけで、Nav Mesh Bounds Volume が使用できるようになります。Nav Mesh が自動的にビルドされます。 + +[REGION:tip] +ビューポートで **[P]** を押せば、いつでも Nav Mesh を表示することができます。 +[/REGION] + +[REGION:note]詳細は、コンテンツ サンプルと [NavMesh に関するドキュメント](Resources\ContentExamples\NavMesh) をご覧ください。[/REGION] + + +### Pain-Causing Volume + +**Pain Causing Volume** は、Physics Volume にプレーヤーにダメージを与える機能を追加したものです。溶岩の穴、毒ガスのもくもくした塊など、明らかにプレイヤーが行くべきでない領域がレベルに存在する場合に便利です。 +[REGION:note]Pain-Causing Volume の各プロパティの情報については、 [詳細ページ](Engine/Actors/Volumes/PainCausingVolumeDetails) をご覧ください。[/REGION] + + +### Physics Volume + +**Physics Volume** は、キャラクターや他の物理オブジェクトに影響を与える物理のセットアップを操作できるボリュームです。主に、プレイヤーが泳がなければならない水のある背景の作成に使用されます。Physics Volume のエフェクトは可視であり、必要に応じて使用することができます。Character Movement Component クラスでは現在のフィールドを使って、所有している `Character` が背景をどのように動くかを調整します。ゲームにカスタム物理がある場合、`APhysicsVolume` から独自の子クラスを派生させるとそれを実現するのに役立ちます。 +[REGION:note]Physics Volume の特定のプロパティに関する情報は、 [詳細ページ](Engine/Actors/Volumes/PhysicsVolumeDetails) をご覧ください。[/REGION] + + +### Post Process Volume + +**Post Process Volume** は **[Details]** パネルのプロパティを調整することでカメラに適用される Post Process 設定をオーバーライドできるスペースです。 +[REGION:note]ポストプロセスに関する詳細は [ポストプロセスのドキュメント](Engine/Rendering/PostProcessEffects) を参照してください。[/REGION] + + +### Precomputed Visibility Volume +**Precomputed Visibility Volume** は主にパフォーマンスの最適化に使用します。これらのボリュームは、ワールド内の位置に対するアクタの可視性を保存しています。プレイヤーがアクセスできるエリアのみに配置されます。 ### Precomputed Visibility Override Volume -**Precomputed Visibility Override Volume** を使えば、Precomputed Visibilty Volume の自動生成結果を望まない場合に、手書きのコードでワールド内の位置に対してアクタの可視性をオーバーライドすることができます。これらはまたパフォーマンスの最適化にも使用され、プレイヤーがアクセス可能なエリアのみに配置することができます。 - +**Precomputed Visibility Override Volume** を使えば、Precomputed Visibilty Volume の自動生成結果が望ましくない場合に、手書きのコードでワールド内の位置に対してアクタの可視性をオーバーライドすることができます。これらはまたパフォーマンスの最適化にも使用され、プレイヤーがアクセス可能なエリアのみに配置することができます。 + +### Trigger Volume + +**Trigger Volume** は、プレイヤーまたはオブジェクトが出入りする際にイベントを発生させるために使います。Trigger Volume は、 **Level ブループリント** と一緒に使用して、イベントとゲームプレイのシナリオや機能を、ブループリントを追加する必要なくテストすることができます。 + +例えば、レベル内に TriggerVolume を配置し、**Level ブループリント** でボリュームのオーバーラップ イベントを作成し、これでサウンドを再生したり、シネマティックスを開始したり、ドアを開けることもできるオーバーラップ イベントを作成します。 + +[REGION:note] +コリジョン設定をチェックして、Overlap コリジョン反応の設定でトリガーが意図したアクタに反応するようにしてください。 +[/REGION] diff --git a/Engine/Documentation/Source/Engine/Actors/Volumes/Volumes.KOR.udn b/Engine/Documentation/Source/Engine/Actors/Volumes/Volumes.KOR.udn index 478f66f70c47..ea34dae6ebb5 100644 --- a/Engine/Documentation/Source/Engine/Actors/Volumes/Volumes.KOR.udn +++ b/Engine/Documentation/Source/Engine/Actors/Volumes/Volumes.KOR.udn @@ -1,31 +1,32 @@ -INTSourceChangelist:3283566 +INTSourceChangelist:3429227 Availability: Public -Title:볼륨 사용 안내서 +Title:볼륨 개요 Crumbs:%ROOT%, Engine, Engine/Actors -Description:레벨의 작동방식이나 구성법 강화를 위한 볼륨 배치 및 작업방식 안내서입니다. +Description:Volume, 볼륨을 어떻게 배치하고 사용하면 레벨의 작동방식이나 구성 상태를 증강시킬 수 있는지에 대한 안내입니다. +version:4.16 +type:overview +Parent:Engine/Actors/Types +order:8 +type:overview -[TOC(start:2 end:2)] +[TOC(start:2 end:3)] - -볼륨은 레벨에 있는 3차원 공간으로, 저마다 특정한 목적이 있으며, 그 목적은 다음과 같습니다: +볼륨은 레벨에 있는 3차원 공간으로, 그 안에서 다양한 목적을 수행할 수 있습니다. 그 목적은 다음과 같습니다: * 플레이어에게 대미지 유발 -* 플레이어의 볼륨 진입 금지, 즉 충돌 표면 역할 +* 액터의 볼륨 진입 금지, 즉 충돌 표면 역할 +* 볼륨을 드나드는 액터 감지 및 반응 * 레벨의 라이팅 또는 표시여부 계산 방식 변경 -그 외에도 다양한 용도의 볼륨이 여러가지 있습니다. 여기서는 레벨의 볼륨을 생성하는 데모를 선보이고, 언리얼 엔진 4 에서 사용할 수 있는 볼륨 유형에 대해 논해보겠습니다. +## 볼륨 배치 고려사항 -### 레벨 디자인시 볼륨 잘 사용하기 +볼륨 사용 시 염두에 두어야 할 중요한 점이 두 가지 있습니다: -볼륨에 관해서 초보 레벨 디자이너에게 너무도 중요한 한 가지 사항은, 레벨에 볼륨을 '잘' 사용해야 한다는 것입니다. 핵심은 두 가지로 요약해 볼 수 있습니다: +1. 볼륨은 지원형 액터로, 보통 특정 액터 유형이 어떤 지역에 들어섰는지 감지하고 그에 대한 반응으로 이펙트를 발동시키는 데 사용됩니다. +1. 볼륨은 가끔 자체적으로 내장된 (코드 또는 블루프린트 형식의) 이펙트가 있습니다만, 거의 대부분 다른 액터에 대한 큐를 제공합니다. 보통은 더 큰 이펙트의 성분으로 간주되며, 몇 가지 다른 레벨 엘리먼트는 비주얼 큐 역할을 합니다. -1. 볼륨은 게임플레이 도중엔 투명하다! 플레이어가 볼 수 없습니다. -1. 1 번의 이유로 인해, **볼륨 자체로 어떤 효과를 내기 위해 사용할 일은 거의 없습니다.** - -볼륨은 투명하기 때문에, 레벨 디자이너가 힌트를 주지 않는 이상 플레이어는 그 진입 여부를 알 수 없습니다. 볼륨은 보통 조금 더 큰 커다란 이펙트의 구성요소로 생각해 볼 수 있습니다. 이해를 돕기 위한 시각적 역할을 하는 다른 요소와 함께 이펙트를 완성시키는 것입니다. - -Pain Causing (고통 유발) 볼륨을 예로 들어봅시다. 레벨 한가운데 다음과 같이 앉아 있다면... +예를 들어 **Pain-Causing Volume** (페인 코징 볼륨)은 그 안의 모든 것에 대미지를 입히는 것으로, 다음과 같이 레벨에 배치할 수 있습니다: [VAR:VolumeDemoSize] h:301 @@ -34,20 +35,19 @@ h:301 [REGION:imagetable] |![](PainCausingVolume_NoEffect.png)(%VolumeDemoSize%)|![](PainCausingVolume_NoEffect_NoVolume.png)(%VolumeDemoSize%)| |:-----------:|:----------:| -|볼륨 배치|플레이어 화면| +| 에디터내 | 게임내 | [/REGION] -거기 들어갔다고 왜 갑자기 아프기 시작했는지 플레이어는 알지 못할 것입니다. 그러나 볼륨 한가운데 화염 파티클 이펙트가 있었다면... +이 경우 플레이어는 볼륨을 피할 길이 없으며, 대미지를 입는데도 왜 그런지 알 수가 없습니다. 레벨 디자이너는 플레이어가 페인 코징 볼륨에 들어섰다는 것을 알려주는 힌트를 제공해야 합니다: [REGION:imagetable] |![](PainCausingVolume_Effect.png)(h:343)|![](PainCausingVolume_Effect_NoVolume.png)(h:343)| |:-----------:|:----------:| -|볼륨 배치|플레이어 화면| +| 에디터내 | 게임내 | [/REGION] -이제 저기 서있으면 왜 아픈지, 플레이어가 이해할 수 있습니다! - +이 경우 화염 파티클 이펙트가 이 지역이 왜 위험한지를 시각적으로 설명해 주는 반면, 페인 코징 볼륨은 플레이어가 불에 닿았기 때문에 생명력이 감소하는 게임플레이 이펙트로 비주얼을 지원하는 역할을 합니다. ## 볼륨 생성하기 @@ -61,105 +61,25 @@ h:301 ## 볼륨 유형 +### Audio Volume +**오디오 볼륨** 은 레벨의 다양한 사운드를 제어하고 적용할 수 있을 뿐만 아니라 구획으로 나눈 오디오 지역을 만들어 볼륨 안팎에서 들리는 것을 제어할 수 있습니다. 오디오 볼륨을 사용하면 페이드를 통한 오디오 전환 효과 및 볼륨 자체 내 Ambient Zone (앰비언트 존) 세팅을 제어할 수도 있습니다. +[REGION:note]오디오 볼륨 관련 프로퍼티 상세 정보는 [](Engine/Actors/Volumes/AudioVolumeDetails) 문서를 참고하세요.[/REGION] + + ### Blocking Volume -블로킹 볼륨은 오브젝트의 통과를 막기 위한 콜리전 모양 역할을 합니다. (아래 그림과 같이) 볼륨의 콜리전 채널 조절을 통해 통과시킬 오브젝트 유형을 결정할 수도 있고, 볼륨을 통과할 때 오버랩 이벤트를 생성하도록 할 수도 있습니다. 자세한 것은 [콜리전 문서](Engine/Physics\Collision) 를 참고해 주시기 바랍니다. +블로킹 볼륨은 오브젝트의 통과를 막기 위한 콜리전 모양 역할을 합니다. (아래 그림과 같이) 볼륨의 콜리전 채널 조절을 통해 통과시킬 오브젝트 유형을 결정할 수도 있고, 볼륨을 통과할 때 오버랩 이벤트를 생성하도록 할 수도 있습니다. +[REGION:note]자세한 것은 [](Engine\Physics\Collision) 문서를 참고해 주시기 바랍니다.[/REGION] ![](blocking_volume_details.png) -블로킹 볼륨은 스태틱 메시의 콜리전 표면 대신 사용 가능합니다. 구조물의 벽이 특히 그러한데, 이런 식으로 사용하면 메시 콜리전 표면에 비해 보통 몇 가지 장점이 있습니다. 첫째, 더욱 복잡한 콜리전 모델보다 계산하기가 쉽습니다. 둘째, 볼륨이란 것의 속성상 그 안에 어떤 오브젝트가 있음을 알기 위함이므로, 고속 물리 오브젝트와의 충돌시 블로킹 볼륨이 더욱 유용하게 쓰일 수 있습니다. +블로킹 볼륨은 스태틱 메시의 콜리전 표면 대신 사용 가능합니다. 구조물의 벽이 특히 그러합니다. 그러면 씬의 작동방식 예측이 보다 쉬워지는데, 피지컬 오브젝트가 바닥이나 벽의 돌기같은 작은 것에 반응하지 않기 때문입니다. 피직스 시뮬레이션 비용이 줄어드니 퍼포먼스 향상도 기대할 수 있습니다. ### Camera Blocking Volume -카메라 블로킹 볼륨은 카메라 액터가 통과하지 못하는 공간을 정의하는 데 사용된다는 점에서 블로킹 볼륨과 속성상 유사합니다. 삼인칭 시점에서의 예제를 들 수 있는데, 플레이어의 카메라를 플레이 공간에 한정시켜 카메라를 월드 바깥에서 회전되지 않도록 할 때 사용할 수 있습니다. +**Camera Blocking Volume** (카메라 블로킹 볼륨)은 카메라만 막고 다른 모든 것들은 무시하도록 미리 설정된 콜리전 세팅의 볼륨입니다. 카메라가 안좋은 위치에 오지 않도록 보이지 않는 장벽 역할을 합니다. 삼인칭 게임에서 예제로, 플레이 영역의 벽에 잎사귀 덩굴같은 장식 덮개가 있는 경우입니다. 그런 경우 카메라 블로킹 볼륨을 벽에 배치하면 카메라가 덩굴이나 잎사귀 뒤로 넘어가지 않도록 하여, 부드럽게 미끄러지며 방의 동작을 방해받지 않고 볼 수 있도록 해줍니다. -카메라 블로킹 볼륨의 프로퍼티 조정은 블로킹 볼륨과 마찬가지로 콜리전 채널 조정을 통해 가능합니다. - - -### Trigger Volume - -트리거 볼륨은 플레이어나 기타 오브젝트가 볼륨에 드나들 때 이벤트를 유발시키는 방편으로 사용됩니다. 레벨 블루프린트와 간단히 사용하여 이벤트 및 게임플레이 시나리오나 함수성을 별도의 블루프린트 추가 없이 테스트할 수 있습니다. - -예를 들어 레벨에 TriggerVolume 을 배치한 다음 레벨 블루프린트에서 오버랩 이벤트를 만들어 그 볼륨에 겹치면 사운드 큐를 재생하고, 시네마틱을 시작하거나 심지어 문을 열 수도 있습니다. - - -### Nav Mesh Bounds Volume - -내비 메시 바운드 볼륨은 레벨의 내비 메시 계산 부분을 조절하는 데 사용됩니다. 내비 메시는 레벨 영역 내 돌아다닐 수 있는 경로를 계산하는 데 사용됩니다. - -볼륨 내 걸어다니기 적합한 각도의 모든 표면상에 내비 메시를 구성합니다. 필요하다면 얼마든지 겹쳐 원하는 내비 메시를 만들 수 있습니다. - -내비 메시 바운드 볼륨을 사용하기 위해서는, 하나(이상)의 볼륨으로 레벨 내 돌아다닐 수 있는 영역을 둘러싸 주기만 하면 됩니다. 그러면 내비 메시는 자동으로 빌드됩니다. - -[REGION:tip] -언제든 뷰포트에서 **P** 키를 누르면 내비 메시를 시각화시켜 볼 수 있습니다. -[/REGION] - -자세한 설명과 예제는 콘텐츠 예제와 [내비 메시 문서](Resources\ContentExamples\NavMesh) 를 참고해 주시기 바랍니다. - - - -### Physics Volume - -피직스 볼륨은 캐릭터와 다른 물리 오브젝트에 영향을 끼치는 물리 설정을 조작할 수 있는 볼륨입니다. 플레이어가 헤엄쳐야 하는 수중 환경을 생성하는 데 자주 쓰입니다. 하지만 무중력 또는 저중력 상태를 만들거나, 통과하는 오브젝트의 종단 속도에 영향을 끼치는 볼륨을 만드는 데도 간단히 사용할 수 있습니다. - -이 볼륨용으로 고안된 프로퍼티가 몇 가지 있으며, 아래 그림과 같이 **디테일** 패널에서 조정 가능합니다. - -![](killZdetails.png) - -|프로퍼티| 설명 | -| ------- | ------------ | -| Terminal Velocity | 종단 속도 - 낙하시 CharacterMovement 를 사용하여 Pawn 의 종단 속도를 결정합니다. | -| Priority | 우선권 - 다수의 PhysicsVolume 이 겹칠 때의 우선권을 결정합니다. | -| Fluid Friction | 유체 마찰 - CharacterMovement 를 사용하는 Pawn 이 볼륨을 지나갈 때 볼륨에 적용시킬 마찰력의 양을 결정합니다.
값이 클 수록 볼륨을 통과하기가 어렵게 느껴집니다. | -| Water Volume | 수량 - 볼륨에 물과 같은 유체가 들어있는지를 나타냅니다. | -| Physics on Contact | 접촉시 물리 - 액터를 건드리면 볼륨에 영향을 받을지를 결정합니다 (기본적으로 액터는 볼륨 안에 있어야 영향을 받을 수 있습니다). | - - -### Pain Causing Volume - -피해 유발 볼륨은 사실 플레이어에게 대미지를 입히는 기능이 추가된 피직스 볼륨입니다. 레벨에 용암 구덩이라던가, 유독 가스 구름이라든가, 플레이어가 가지 말아야 할 곳이 있는 경우 좋습니다. - -Physics Volume 에서 할당 가능한 프로퍼티 이외에 Pain Causing Volume 에도 다음과 같은 프로퍼티 세트가 있습니다. - -![](paincausingvolume.png) - -|프로퍼티| 설명 | -| ------- | ------------ | -| Pain Causing | 피해 유발 - 볼륨이 현재 대미지를 입힐지 말지 입니다. | -| Damage Per Sec | 초당 대미지 - Pain Causing 이 켜져 있을 때 볼륨에 있는 액터에게 입히는 초당 대미지입니다. | -| Damage Type | 대미지 유형 - 액터에 가해지는 대미지 유형을 나타냅니다. | -| Pain Interval | Pain Causing 이 켜졌을 때 대미지가 적용되는 초단위 간격입니다. | -| Entry Pain | 진입 피해 - Pain Causing 이 켜진 볼륨에 들어설 때 Pain Interval 에 따른 지속 대미지에 추가로 즉시 적용할 대미지를 나타냅니다. | - - - -### Kill Z Volume - -**Kill Z Volume** 또는 "Kill-Brush" 는 (플레이어를 포함해서) 볼륨에 들어서는 액터를 사실상 소멸시킵니다. 이러한 볼륨 유형의 사용 예는, 절벽이나 높은 턱 아래 플레이어나 액터가 떨어지면 바로 죽여버리는 용도로 설치해 두면 됩니다. - - - -### Level Streaming Volume - -[EXCERPT:LSV] -레벨 스트리밍 볼륨은 [레벨 스트리밍](Engine/LevelStreaming) 프로세스를 보조하는 데 사용됩니다. 레벨 캡슐화는 물론, 플레이어의 볼륨 출입에 따라 메모리에서의 레벨 스트림 인/아웃 시기 제어를 간단한 방법으로 처리할 수 있습니다. - -아래 그림처럼 **디테일** 패널에서 프로퍼티를 조절하여 Level Streaming Volume 의 레벨 스트리밍 처리 방식을 조절할 수 있습니다. - -![](levelstreamingvolume.png) - -|프로퍼티| 설명 | -| ------- | ------------ | -| Streaming Levels | 스트리밍 레벨 - 볼륨에 영향받는 레벨을 표시합니다. | -| Editor Pre Vis Only | 에디터 미리보기 전용 - 스트리밍 볼륨을 에디터 스트리밍 레벨 미리보기 전용으로만 사용할지 나타냅니다. | -| Disabled | 꺼짐 - True 면 이 스트리밍 볼륨은 스트리밍 볼륨 코드에 무시됩니다.
또한 레벨에 할당된 상태를 유지하면서 Level Streaming Volume 을 끄거나, 블루프린트와 볼륨 스트리밍 사이의 레벨 스트리밍 제어를 토글하는 데도 사용됩니다. | -| Streaming Usage | 스트리밍 용도 - 볼륨의 용도를 로딩만, 로딩과 표시여부, 표시여부만 (로드시 블록) 제어하는데 사용할 것인지를 나타냅니다. | - -[/EXCERPT] - -Level Streaming Volume 관련 상세 정보는 [](Engine/LevelStreaming/StreamingVolumes) 문서를 참고하세요. ### Cull Distance Volume @@ -171,66 +91,92 @@ Level Streaming Volume 관련 상세 정보는 [](Engine/LevelStreaming/Streamin 위 그림의 프로퍼티에서 정의되는 작동방식은 다음과 같습니다: -* 볼륨 내 오브젝트 중 크기가 (85 유닛 이하) 50 유닛에 가장 가까운 것은 카메라와의 거리가 500 유닛 이상일 때 컬링됩(사라집)니다. -* 볼륨 내 오브젝트 중 크기가 (85 에서 210 유닛 사이) 120 유닛에 가장 가까운 것은 카메라와의 거리가 1000 유닛 이상일 때 컬링됩(사라집)니다. -* 볼륨 내 오브젝트 중 크기가 (210 유닛 이상) 300 유닛에 가장 가까운 것은 컬링되지 않습니다. 여기서 0 은 무한으로 간주되기에, 카메라가 그만큼 멀어질 수 없습니다. +* 볼륨 내 오브젝트 중 크기가 (거리 85 유닛 이하) 50 유닛에 가장 가까운 것은 카메라와의 거리가 500 유닛 이상일 때 컬링됩(사라집)니다. +* 볼륨 내 오브젝트 중 크기가 (거리 85 에서 210 유닛 사이) 120 유닛에 가장 가까운 것은 카메라와의 거리가 1000 유닛 이상일 때 컬링됩(사라집)니다. +* 볼륨 내 오브젝트 중 크기가 (거리 210 유닛 이상) 300 유닛에 가장 가까운 것은 컬링되지 않습니다. 여기서 0 은 무한으로 간주되기에, 카메라가 그만큼 멀어질 수 없습니다. 셋업은 Cull Distances 배열에 새 항목을 추가, 즉 ![](button_Plus.png) 버튼을 클릭하는 것으로 시작합니다. 그 다음, 오브젝트의 크기, 그리고 해당 크기 이하의 오브젝트가 컬링되었으면 하는 위치를 입력합니다. 프로퍼티를 입력하는 데 있어 정해진 순서는 없습니다. -### Audio Volume -오디오 볼륨은 레벨에 다양한 사운드 제어 및 적용은 물론 볼륨 내부와 외부에서 들리는 소리를 제어할 수 있도록 구역화된 오디오 존 생성을 위한 방편이 됩니다. 오디오 볼륨을 사용하면 자체 내 Ambient Zone 세팅 제어 및 페이드를 통한 오디오 페이드 가능합니다. -이 볼륨의 **디테일** 패널에서 여러가지 프로퍼티를 조절하여 아래와 같은 이펙트에 대한 세밀한 제어가 가능합니다. +### Hierarchical LOD Volume -![](audiovolume.png) +**Hierarchical LOD Volume** (계층형 LOD 볼륨)에는 별다른 프로퍼티는 없지만, [HLOD](Engine/HLOD) 시스템에서 다수의 액터의 하나의 HLOD 클러스터로 그룹짓는 데 사용됩니다. 클러스터 생성 시 언리얼 엔진은 일반 생성 프로세스보다 수동 배치된 볼륨을 우선시합니다. -|프로퍼티| 설명 | -| ------- | ------------ | -| Priority | 우선권 - 볼륨이 겹치는 경우 우선권이 가장 높은 것이 사용됩니다. 둘 이상의 볼륨에 우선권이 같은 경우 순서는 미정입니다. | -| Apply Reverb | 리버브 적용 - 리버브 세팅을 사용할지를 나타냅니다. | -| Reverb Effect | 리버브 이펙트 - 볼륨에 사용할 리버브 애셋입니다. | -| Volume | 볼륨 - 리버브 이펙트의 전체적인 볼륨 크기입니다. | -| Fade Time | 페이드 시간 - 현재 리버브 세팅에서 볼륨 세팅으로 페이드하는 데 걸리는 (초 단위) 시간입니다. | -| Enabled | 켜짐 - 이 볼륨이 현재 켜져있어 사운드에 영향을 끼칠 수 있는지를 나타냅니다. | -'앰비언트 존'은 연관된 오디오 볼륨 안에 위치한 사운드 액터가 플레이어 위치에 따라 어떻게 변경되는지를 정의합니다. 앰비언트 존에 대한 세팅은 **디테일** 패널에서도 조절할 수 있습니다. +### Kill Z Volume -|프로퍼티| 설명 | -| ------- | ------------ | -| Exterior Volume | 외부 볼륨 - 볼륨 안에 플레이어가 있을 때의 외부 사운드 최종 볼륨입니다. | -| Exterior Time | 외부 시간 - 새로운 외부 볼륨으로 페이드하는 데 걸리는 초 단위 시간입니다. | -| Exterior LPF | 외부 LPF - 내부에 있을 때 외부 사운드에 적용할 로우패스 필터 배수입니다 (1.0 은 최대 LPF 를 적용합니다). | -| Exterior LPFTime | 외부 LPF 시간 - 새로운 로우 패스 필터 레벨로 페이드하는 데 걸리는 초 단위 시간입니다. | -| Interior Volume | 내부 볼륨 - 플레이어가 볼륨 밖에 있을 때 내부 사운드의 최종 볼륨입니다. | -| Interior Time | 내부 시간 - 새로운 내부 볼륨으로 페이드하는 데 걸리는 초 단위 시간입니다. | -| Interior LPF | 내부 LPF - 밖에 있을 때 내부 사운드에 적용되는 로우패스 필더 배수입니다 (1.0 이면 최대 LPF 를 적용합니다). | -| Interior LPFTime | 내부 LPF 시간 - 새로운 로우패스 필터 레벨로 페이드하는 데 걸리는 초 단위 시간입니다. | +**Kill Z Volume** (킬 Z 볼륨)은 플랫포머 게임에서 절벽 또는 구덩이로 떨어지거나, 공상 과학 설정에서 우주복 없이 우주선 밖을 나가거나 하는 등, 특정 유형 게임에서 오브젝트가 경계를 벗어나지 못하도록 하는 데 쓰입니다. 킬 Z 볼륨은 들어서는 액터에 대해 `FellOutOfWorld` 함수를 호출하고, 기본적으로 액터는 빠른 클린업 절차 이후 자체 소멸됩니다. 다른 동작이 필요한 게임에서는 그 액터에 맞는 작동방식을 덮어쓸 수 있습니다. 예를 들어, 플레이어가 게임을 계속하기 위해 수집해야 하는 키나 다른 아이템이 용암 구덩이에 떨어진 경우, 그냥 소멸시켜 버리기 보다는 그 아이템을 플레이어가 도달할 수 있는 곳으로 순간이동시키거나, 아니면 게임이 끝나지 않는 상태로 놔두기 보다는 최소한 플레이어에게 아이템을 잃었으니 지난 체크포인트를 다시 로드하라고 알리기라도 해야 할 것입니다. - -### Post Process Volume +### Level Streaming Volume -포스트 프로세스 볼륨은 그 공간 안에 있는 카메라에 포스트 프로세스 세팅을 적용하는 것으로, 이 세팅은 **디테일** 패널에서 프로퍼티를 조절하여 덮어쓸 수 있습니다. +[EXCERPT:LSV] +레벨 스트리밍 볼륨은 [레벨 스트리밍](Engine/LevelStreaming) 프로세스를 보조하는 데 사용됩니다. 레벨 캡슐화는 물론, 플레이어의 볼륨 출입에 따라 메모리에서의 레벨 스트림 인/아웃 시기를 간단히 제어할 수 있습니다. +[/EXCERPT] + + +### Lightmass Character Indirect Detail Volume + +라이트매스 캐릭터 간접 디테일 볼륨은 라이트매스 임포턴스 볼륨과 비슷하게 간접광 샘플을 생성하지만, 땅 위의 플레이어 높이에서만이 아니라 전체 볼륨 내부에 대해 생성합니다. 이 볼륨은 간접광이 위아래로 올바르게 나와야 하는 엘리베이터에 주로 사용됩니다. -포스트 프로세싱 관련 상세 정보는 [포스트 프로세싱 문서](Engine/Rendering/PostProcessEffects) 를 참고하세요. - ### Lightmass Importance Volume 라이트매스 임포턴스 볼륨은 라이트매스 계산을 집중시키는 데 사용됩니다. 라이트매스는 언리얼 엔진 4 에서 사용되는 글로벌 일루미네이션 시스템으로, 라이팅을 미리계산하는 방식입니다. 레벨에 미리계산된 라이트를 생성하는 데 필요한 처리량을 최소화, 즉 최적화시키기 위해서는, 라이트매스 임포턴스 볼륨을 사용해서 레벨 지오메트리의 특정 영역을 감싸줘야 합니다. 그러면 라이트매스는 해당 영역 안쪽만 계산하며, 그 외 부분은 생략합니다. - -라이트매스와 라이트매스 임포턴스 볼륨 관련 상세 정보는 [라이트매스 문서](Engine/Rendering/LightingAndShadows/Lightmass) 를 참고해 주시기 바랍니다. +[REGION:note]라이트매스와 라이트매스 임포턴스 볼륨 관련 상세 정보는 [](Engine/Rendering/LightingAndShadows/Lightmass) 문서를 참고해 주시기 바랍니다.[/REGION] -### Lightmass Character Indirect Detail Volume -라이트매스 캐릭터 간접 디테일 볼륨은 라이트매스 임포턴스 볼륨과 비슷하게 간접광 샘플을 생성하지만, 땅 위의 플레이어 높이에서만이 아니라 전체 볼륨 내부에 대해 생성합니다. 이 볼륨은 간접광이 위아래로 올바르게 나와야 하는 엘리베이터에 주로 사용됩니다. +### Mesh Merge Culling Volume + +**Mesh Merge Culling Volume** (메시 머지 컬링 볼륨)은 그 안에 들어있는 메시 오브젝트를 하나의 메시로 합칠 수 있도록 마킹합니다. 일정 영역의 작은 메시 집합을 하나의 메시로 한꺼번에 컬링되도록 만들거나, [HLOD](Engine/HLOD) 생성 시 지오메트리 감소를 좀 더 최적화된 방식으로 하도록 하여 퍼포먼스를 향상시킬 수 있습니다. -### Precomputed Visibility Volume +### Nav Mesh Bounds Volume + +내비 메시 바운드 볼륨은 레벨의 내비 메시를 만드는 부분을 조절하는 데 사용됩니다. 내비 메시는 레벨 영역 내 돌아다닐 수 있는 경로를 계산하는 데 사용됩니다. + +볼륨 내 걸어다니기 적합한 각도의 모든 표면상에 내비 메시를 구성합니다. 필요하다면 얼마든지 겹쳐 원하는 내비 메시를 만들 수 있습니다. + +내비 메시 바운드 볼륨을 사용하기 위해서는, 하나(이상)의 볼륨으로 레벨 내 돌아다닐 수 있는 영역을 둘러싸 주기만 하면 됩니다. 그러면 내비 메시는 자동으로 빌드됩니다. + +[REGION:tip] +언제든 뷰포트에서 **P** 키를 누르면 내비 메시를 시각화시켜 볼 수 있습니다. +[/REGION] + +[REGION:note]자세한 설명과 예제는 콘텐츠 예제와 [](Resources\ContentExamples\NavMesh) 문서를 참고해 주시기 바랍니다.[/REGION] + + +### Pain-Causing Volume + +**Pain-Causing Volume** (페인 코징 볼륨)은 사실 플레이어에게 대미지를 입히는 기능이 추가된 피직스 볼륨입니다. 레벨에 용암 구덩이라던가, 유독 가스 구름이라든가, 플레이어가 가지 말아야 할 곳이 있는 경우 좋습니다. +[REGION:note]페인 코징 볼륨 관련 프로퍼티 상세 정보는 [](Engine/Actors/Volumes/PainCausingVolumeDetails) 문서를 참고하세요.[/REGION] + + +### Physics Volume + +피직스 볼륨은 캐릭터와 다른 물리 오브젝트에 영향을 끼치는 물리 설정을 조작할 수 있는 볼륨입니다. 플레이어가 헤엄쳐야 하는 수중 환경을 생성하는 데 자주 쓰입니다. 피직스 볼륨의 이펙트는 눈에 보이며, 원하는 대로 해석 가능합니다. Character Movement Component 클래스는 현재 필드를 사용하여 소유중인 `Character` 의 환경 이동 방식을 조절합니다. 게임에 커스텀 피직스 세팅이 있는 경우, `APhysicsVolume` 에서 자체 자손 클래스를 파생시키면 도움이 될 수 있습니다. +[REGION:note]피직스 볼륨 프로퍼티 관련 상세 정보는 [](Engine/Actors/Volumes/PhysicsVolumeDetails) 문서를 참고하세요.[/REGION] + + +### Post Process Volume + +포스트 프로세스 볼륨은 그 공간 안에 있는 카메라에 포스트 프로세스 세팅을 적용하는 것으로, 이 세팅은 **디테일** 패널에서 프로퍼티를 조절하여 덮어쓸 수 있습니다. +[REGION:note]포스트 프로세싱 관련 상세 정보는 [](Engine/Rendering/PostProcessEffects) 문서를 참고하세요.[/REGION] + + +### Precomputed Visibility Volume 프리컴퓨티드 비저빌리티 볼륨은 주로 퍼포먼스 최적화에 사용됩니다. 이 볼륨은 액터의 월드상 위치에 대한 표시여부를 저장하며, 플레이어가 접근할 수 있는 영역에만 배치해야 합니다. ### Precomputed Visibility Override Volume 프리컴퓨터드 비저빌리티 오버라이드 볼륨은 프리컴퓨티드 비저빌리티 볼륨의 자동 생성 결과가 마음에 들지 않을 때 액터의 비저빌리티를 수동으로 덮어쓸 수 있습니다. 퍼포먼스 최적화에도 사용되며, 플레이어가 접근할 수 있는 영역에만 배치해야 합니다. - + +### Trigger Volume + +트리거 볼륨은 플레이어나 기타 오브젝트가 볼륨에 드나들 때 이벤트를 유발시키는 방편으로 사용됩니다. 레벨 블루프린트와 간단히 사용하여 이벤트 및 게임플레이 시나리오나 함수성을 별도의 블루프린트 추가 없이 테스트할 수 있습니다. + +예를 들면 레벨에 트리거 볼륨을 배치한 뒤, **레벨 블루프린트** 에서 그 볼륨에 대한 오버랩 이벤트를 만들어 사운드 재생, 문 열기, 시네마틱 씬 시작 등의 작업을 할 수 있습니다. +[REGION:note] +트리거가 의도된 액터에 오버랩 콜리전 리스폰스 세팅으로 반응하도록 되어 있는지 콜리전 세팅을 확인해 주시기 바랍니다. +[/REGION] diff --git a/Engine/Documentation/Source/Engine/Animation/AimOffset/AimOffset.INT.udn b/Engine/Documentation/Source/Engine/Animation/AimOffset/AimOffset.INT.udn index 72658445ff5d..35e6e7a7544c 100644 --- a/Engine/Documentation/Source/Engine/Animation/AimOffset/AimOffset.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/AimOffset/AimOffset.INT.udn @@ -1,7 +1,7 @@ Availability:Public Title: Aim Offset Crumbs: %ROOT%, Engine, Engine/Animation -Description:An **Aim Offset** is an asset that stores a blendable series of poses to help a character aim a weapon. +Description:An Aim Offset is an asset that stores a blendable series of poses to help a character aim a weapon. Related: Engine/Content/FBX/Animations Related: Engine/Content/Types/SkeletalMeshes Related: Engine/Animation/PhysicallyDrivenAnimation @@ -9,6 +9,8 @@ Related: Engine/Animation/StateMachines Related: Gameplay/AI Related: Engine/Content/Tools/MayaRiggingTool version: 4.9 +tags:Assets +topic-image:AimOffset_topic.png [REGION:fullwidth] ![](AimOffset.png) diff --git a/Engine/Documentation/Source/Engine/Animation/AimOffset/AimOffset.JPN.udn b/Engine/Documentation/Source/Engine/Animation/AimOffset/AimOffset.JPN.udn index 4ed59f2c9456..34945f498b69 100644 --- a/Engine/Documentation/Source/Engine/Animation/AimOffset/AimOffset.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/AimOffset/AimOffset.JPN.udn @@ -1,15 +1,17 @@ -INTSourceChangelist:2754176 +INTSourceChangelist:3467293 Availability:Public Title:Aim Offset Crumbs: %ROOT%, Engine, Engine/Animation Description:Aim Offset は、キャラクターが武器の照準を合わせやすいように、ブレンド可能な様々なポーズを格納しているアセットです。 -Related: Engine/Content/FBX/Animations -Related: Engine/Content/Types/SkeletalMeshes -Related: Engine/Animation/PhysicallyDrivenAnimation -Related: Engine/Animation/StateMachines -Related: Gameplay/AI -Related: Engine/Content/Tools/MayaRiggingTool +Related:Engine/Content/FBX/Animations +Related:Engine/Content/Types/SkeletalMeshes +Related:Engine/Animation/PhysicallyDrivenAnimation +Related:Engine/Animation/StateMachines +Related:Gameplay/AI +Related:Engine/Content/Tools/MayaRiggingTool version:4.9 +tags:Assets +topic-image:AimOffset_topic.png [REGION:fullwidth] ![](AimOffset.png) @@ -29,7 +31,7 @@ Aim Offset をキャラクターに適用した例として、セクション 1. ## Aim Offset を作成する -他のアセットと同様に、Aim Offset は **[コンテンツ ブラウザ]** で作成します。**右クリック** または ![](New_Asset_Button.png) ボタンを使ってコンテキスト メニューから **[Animation] > [Aim Offset]** を選択します。 お気づきのように、** Aim Offset 1D** というオプションもあります。これは Aim Offset と同じですが、ブレンドを制御するために標準の Aim Offset が 2 つの変数からの入力をサポートするのに対し、 1 つの変数からの入力のみをサポートします。 +他のアセットと同様に、Aim Offset は **[コンテンツ ブラウザ]** で作成します。**右クリック** または ![](New_Asset_Button.png) ボタンを使ってコンテキストメニューから **[Animation] > [Aim Offset]** の順に選択します。 お気づきのように、**Aim Offset 1D** というオプションもあります。これは Aim Offset と同じですが、ブレンドを制御するために標準の Aim Offset が 2 つの変数からの入力をサポートするのに対し、 1 つの変数からの入力のみをサポートします。 Aim Offset を新規作成する場合、スケルトン アセットを指定します。Aim Offset で使用したいスケルタル メッシュで使うものと同じアセットを選択するようにしてください。 @@ -98,8 +100,10 @@ Aim Offset はメッシュ空間では Additive Aim Type のみアニメーシ メッシュ空間はアニメーション シーケンスのプロパティとして設定されます。**[Additive Settings]** カテゴリに **[Additive Anim Type]** プロパティがあります。これをメッシュ空間に設定すると、説明したとおりのメッシュ座標空間が使用されます。このブレンディング操作はかなり負荷が高くなります。そのため、Aim Offset のケースのように、アニメーションを一定方向に移動させる必要があると分かっている特定のタイプのブレンド スペースのみで使用するのが一般的です。 +## パフォーマンス +![](animOffsetNode.png) +Aim Offset ノードを **Anim Graph** に配置すると、4.11 で導入された **LOD Threshold** プロパティを使ってパフォーマンスを調整することができます。この設定は、**Aim Offset** ノードの [Details (詳細)] パネルにあります。 - - +[INCLUDE:Engine/Animation/NodeReference/SkeletalControls#lodthresh] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Animation/AimOffset/AimOffset.KOR.udn b/Engine/Documentation/Source/Engine/Animation/AimOffset/AimOffset.KOR.udn index b69b607f5766..c2ad243682c0 100644 --- a/Engine/Documentation/Source/Engine/Animation/AimOffset/AimOffset.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/AimOffset/AimOffset.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3467293 Availability:Public Title: 에임 오프셋 Crumbs: %ROOT%, Engine, Engine/Animation @@ -10,6 +10,8 @@ Related: Engine/Animation/StateMachines Related: Gameplay/AI Related: Engine/Content/Tools/MayaRiggingTool version: 4.9 +tags:Assets +topic-image:AimOffset_topic.png [REGION:fullwidth] ![](AimOffset.png) diff --git a/Engine/Documentation/Source/Engine/Animation/AnimBlueprints/Interface/AnimationBlueprintUI.INT.udn b/Engine/Documentation/Source/Engine/Animation/AnimBlueprints/Interface/AnimationBlueprintUI.INT.udn index b89dc7e664b3..2ca7b6a9bb2a 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimBlueprints/Interface/AnimationBlueprintUI.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimBlueprints/Interface/AnimationBlueprintUI.INT.udn @@ -1,24 +1,26 @@ -Availability:Public -Title:Animation Blueprint Editor +Availability: Docs Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/AnimBlueprints +Title:Animation Blueprint Editor Description:Highlights the core features of the Animation Blueprint Editor in Unreal Engine 4. -related:Engine\Animation\AnimBlueprints -related:Engine\Animation\AnimBlueprints\Creation -related:Engine\Animation\AnimBlueprints\EventGraph -related:Engine\Animation\AnimBlueprints\AnimGraph -version: 4.14 -type:reference -topic-image:AnimBPUITopic.png +Type: Landing +version: 4.16 +Parent: Engine/Animation/AnimBlueprints +Order: 1 tags:Animation tags:Animation Blueprint tags:Blueprints +topic-image:AnimBPUITopic.png + +[REGION:banner] +![](AnimBPBanner.png) +[/REGION] The **Animation Blueprint Editor** shares similar functionality to the normal [Blueprint Editor](Engine/Blueprints) but is geared more towards character animation scripting. -![](AnimGraphUI.png) - Please refer to each section below for a breakdown of the Animation Blueprint Editor user interface: +![](AnimGraphUI.png) + ## 1. Toolbar The **Toolbar** inside the Animation Blueprint Editor allows you to compile your Blueprints, Save, locate the Animation Blueprint asset in the **Content Browser**, and define **Class Settings** and **Class Defaults** settings like the [Blueprint Editor Toolbar.](Engine/Blueprints/Editor/UIComponents/Toolbar) @@ -33,10 +35,12 @@ The [Viewport](Engine/Animation/Persona/Viewport) window allows you to preview p The **Graph** panel includes two main graph types: the [Event Graph](Engine/Animation/AnimBlueprints/EventGraph) which contains the animation event nodes used to trigger the updating of Skeletal Mesh poses and the [Anim Graph,](Engine/Animation/AnimBlueprints/AnimGraph) which is used to evaluate a final pose for the Skeletal Mesh to actually enter for the current frame. These two graphs work together and drive the logic and poses for your character to enter during gameplay. -## 4. Details +## 4. Details / Preview Scene Settings The **Details** panel in the Animation Blueprint Editor is the same as the [](Engine/Blueprints/Editor/UIComponents/Details) in the Blueprint Editor and is where you can access and edit properties related to any variables you have created as well as the nodes placed within your graph. +Also located in this section is a tab for [Preview Settings](Engine\Animation\Persona\PreviewSettings) which enable the ability to define the viewport settings such as the **Animation Mode** or **Animation** to use as a preview, switch **Skeletal Meshes** that are used for the preview, as well as viewport lighting and Post Process settings applied so you can preview your settings with various lighting applied. + ## 5. My Blueprint diff --git a/Engine/Documentation/Source/Engine/Animation/AnimBlueprints/VimBlueprints.INT.udn b/Engine/Documentation/Source/Engine/Animation/AnimBlueprints/VimBlueprints.INT.udn index 926e36ae3fd6..256dcecaf586 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimBlueprints/VimBlueprints.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimBlueprints/VimBlueprints.INT.udn @@ -11,11 +11,12 @@ Related: Gameplay/AI Related: Engine/Content/Tools/MayaRiggingTool version: 4.14 type:landing -topic-image:animbptopic.png tags:Animation tags:Animation Blueprint tags:Blueprints tags:State Machine +tags:Assets +topic-image:Engine/Animation/Overview/AnimationBlueprintTopic.png [REGION:banner] ![](AnimationBlueprint.png) diff --git a/Engine/Documentation/Source/Engine/Animation/AnimBlueprints/VimBlueprints.JPN.udn b/Engine/Documentation/Source/Engine/Animation/AnimBlueprints/VimBlueprints.JPN.udn index f0ac98b2329e..d119dd3b0b2b 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimBlueprints/VimBlueprints.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimBlueprints/VimBlueprints.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3273317 +INTSourceChangelist:3481084 Availability:Public Title:Animation ブループリント Crumbs: %ROOT%, Engine, Engine/Animation @@ -12,11 +12,12 @@ Related:Gameplay/AI Related:Engine/Content/Tools/MayaRiggingTool version:4.14 type:landing -topic-image:animbptopic.png tags:Animation tags:Animation Blueprint tags:Blueprints tags:State Machine +tags:Assets +topic-image:Engine/Animation/Overview/AnimationBlueprintTopic.png [REGION:banner] ![](AnimationBlueprint.png) diff --git a/Engine/Documentation/Source/Engine/Animation/AnimBlueprints/VimBlueprints.KOR.udn b/Engine/Documentation/Source/Engine/Animation/AnimBlueprints/VimBlueprints.KOR.udn index 9e4286964d52..e3e88060c5a7 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimBlueprints/VimBlueprints.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimBlueprints/VimBlueprints.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3273317 +INTSourceChangelist:3481084 Availability:Public Title: 애니메이션 블루프린트 Crumbs: %ROOT%, Engine, Engine/Animation @@ -12,11 +12,12 @@ Related: Gameplay/AI Related: Engine/Content/Tools/MayaRiggingTool version: 4.14 type:landing -topic-image:animbptopic.png tags:Animation tags:Animation Blueprint tags:Blueprints tags:State Machine +tags:Assets +topic-image:Engine/Animation/Overview/AnimationBlueprintTopic.png [REGION:banner] ![](AnimationBlueprint.png) diff --git a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimBPOverride/AnimBPOverrideHowTo.INT.udn b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimBPOverride/AnimBPOverrideHowTo.INT.udn index d8f5f6030c42..8eecece84057 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimBPOverride/AnimBPOverrideHowTo.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimBPOverride/AnimBPOverrideHowTo.INT.udn @@ -9,7 +9,6 @@ Related: Engine\Animation\Overview version: 4.14 skilllevel: Advanced type:how-to -topic-image:animbpoverride_topic.png tags:Animation tags:Animation Blueprint diff --git a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimBPOverride/AnimBPOverrideHowTo.JPN.udn b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimBPOverride/AnimBPOverrideHowTo.JPN.udn index 37de8589dc59..4240dfa236d3 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimBPOverride/AnimBPOverrideHowTo.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimBPOverride/AnimBPOverrideHowTo.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3255885 +INTSourceChangelist:3429233 Availability:Public Title:Animation ブループリントのオーバーライド Crumbs: %ROOT%, Engine, Engine\Animation, Engine\Animation\AnimHowTo @@ -10,7 +10,6 @@ Related:Engine\Animation\Overview version:4.14 skilllevel:Advanced type:how-to -topic-image:animbpoverride_topic.png tags:Animation tags:Animation Blueprint diff --git a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimBPOverride/AnimBPOverrideHowTo.KOR.udn b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimBPOverride/AnimBPOverrideHowTo.KOR.udn index 746d031e1c01..022036115f8e 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimBPOverride/AnimBPOverrideHowTo.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimBPOverride/AnimBPOverrideHowTo.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3255885 +INTSourceChangelist:3429233 Availability: Public Title:애니메이션 블루프린트 오버라이드 Crumbs: %ROOT%, Engine, Engine\Animation, Engine\Animation\AnimHowTo @@ -10,7 +10,6 @@ Related: Engine\Animation\Overview version: 4.14 skilllevel: Advanced type:how-to -topic-image:animbpoverride_topic.png tags:Animation tags:Animation Blueprint diff --git a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimDynamics/ApplyDynamics/ApplyingDynamics.INT.udn b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimDynamics/ApplyDynamics/ApplyingDynamics.INT.udn index ee0389d9a550..9f6b41d80a61 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimDynamics/ApplyDynamics/ApplyingDynamics.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimDynamics/ApplyDynamics/ApplyingDynamics.INT.udn @@ -4,6 +4,7 @@ Crumbs: %ROOT%, Engine, Engine\Animation, Engine\Animation\AnimHowTo, Engine\Ani Description:In this step we apply AnimDynamics to the harness and furnace the character is carrying so it reacts to movement. version: 4.12 skilllevel: Advanced +Order: 2 [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimDynamics/ApplyDynamics/ApplyingDynamics.JPN.udn b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimDynamics/ApplyDynamics/ApplyingDynamics.JPN.udn index fcfdd2eb596a..bf01f2dc0786 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimDynamics/ApplyDynamics/ApplyingDynamics.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimDynamics/ApplyDynamics/ApplyingDynamics.JPN.udn @@ -1,10 +1,11 @@ -INTSourceChangelist:2988432 +INTSourceChangelist:3376720 Availability:Public Title:2 - AnimDynamics を適用する Crumbs: %ROOT%, Engine, Engine\Animation, Engine\Animation\AnimHowTo, Engine\Animation\AnimHowTo\AnimDynamics -Description:このステップでは動きに反応できるようにキャラクターが運んでいるものに AnimDynamics を適用します。 +Description:このステップでは、動きに反応できるようにキャラクターが運んでいるものに AnimDynamics を適用します。 version:4.12 skilllevel:Advanced +Order:2 [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimDynamics/ApplyDynamics/ApplyingDynamics.KOR.udn b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimDynamics/ApplyDynamics/ApplyingDynamics.KOR.udn index a8f9afb4351b..90ac361a326e 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimDynamics/ApplyDynamics/ApplyingDynamics.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimDynamics/ApplyDynamics/ApplyingDynamics.KOR.udn @@ -1,10 +1,11 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3376720 Availability: Public Title:2 - 애님 다이내믹스 적용 Crumbs: %ROOT%, Engine, Engine\Animation, Engine\Animation\AnimHowTo, Engine\Animation\AnimHowTo\AnimDynamics Description:이번 단계에서는 캐릭터가 맨 장비와 풀무에 AnimDynamics 를 적용하여 움직임에 반응하도록 합니다. version: 4.12 skilllevel: Advanced +Order: 2 [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimDynamics/Setup/AnimDynamic_Setup.INT.udn b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimDynamics/Setup/AnimDynamic_Setup.INT.udn index bd8130c2fc23..88dbd9dffc50 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimDynamics/Setup/AnimDynamic_Setup.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimDynamics/Setup/AnimDynamic_Setup.INT.udn @@ -5,6 +5,7 @@ Description:In this step we will set up the character we will use to apply dynam SkillLevel:Advanced Version:4.11 checkpoint: editorqs +Order: 1 [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimDynamics/Setup/AnimDynamic_Setup.JPN.udn b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimDynamics/Setup/AnimDynamic_Setup.JPN.udn index a5e0d7c169fe..3cc4e0fe501e 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimDynamics/Setup/AnimDynamic_Setup.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimDynamics/Setup/AnimDynamic_Setup.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:2988432 +INTSourceChangelist:3376720 Availability:Public Title:1 - 必要な設定 Crumbs: %ROOT%, Engine, Engine\Animation, Engine\Animation\AnimHowTo, Engine\Animation\AnimHowTo\AnimDynamics @@ -6,6 +6,7 @@ Description:動的アニメーションを適用するキャラクターをセ SkillLevel:Advanced Version:4.11 checkpoint: editorqs +Order:1 [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimDynamics/Setup/AnimDynamic_Setup.KOR.udn b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimDynamics/Setup/AnimDynamic_Setup.KOR.udn index 27a624ddfe37..9a1698179b8b 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimDynamics/Setup/AnimDynamic_Setup.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimDynamics/Setup/AnimDynamic_Setup.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3376720 Availability:Public Title:1 - 필수 구성 Crumbs: %ROOT%, Engine, Engine\Animation, Engine\Animation\AnimHowTo, Engine\Animation\AnimHowTo\AnimDynamics @@ -6,6 +6,7 @@ Description:여기서는 다이내믹 애니메이션을 적용하는 데 사용 SkillLevel:Advanced Version:4.11 checkpoint: editorqs +Order: 1 [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimHowToOverview.INT.udn b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimHowToOverview.INT.udn index f8c18cc325a9..07f1cb1f07d0 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimHowToOverview.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimHowToOverview.INT.udn @@ -2,6 +2,8 @@ Availability: Public Title:Animation How To's Crumbs: %ROOT%, Engine, Engine\Animation, Engine\Animation\AnimHowTo Description:Examples of different aspects of the Animation system in Unreal Engine 4 are demonstrated through several step-by-step How To guides. +type:how-to +type:landing The Animation How To's provide several step-by-step examples of working with and using the different [](Engine\Animation\Persona\Modes) within Unreal Engine 4. Whether you are new to animation in Unreal Engine 4 or want to learn how to work with the different tools, the How To pages below cover a broad range of topics and aim to give you a place to start or expand upon your current knowledge. @@ -17,8 +19,8 @@ Refer to the tables below for more information and click each link to view its c ## Intermediate |How To | Description | | ------- | ------------ | -| [](Engine\Animation\AnimHowTo\PropertyBasedBlending) | %Engine\Animation\AnimHowTo\PropertyBasedBlending:description% | | [](Engine\Animation\AnimHowTo\AimOffset) | %Engine\Animation\AnimHowTo\AimOffset:description% | +| [](Engine\Animation\AnimHowTo\Blendspace) | %Engine\Animation\AnimHowTo\Blendspace:description% | | [](Engine\Animation\AnimHowTo\Retargeting) | %Engine\Animation\AnimHowTo\Retargeting:description% | | [](Engine\Animation\AnimHowTo\CreatePoseAsset) | %Engine\Animation\AnimHowTo\CreatePoseAsset:description% | | [](Engine\Animation\AnimHowTo\SubAnimInstance) | %Engine\Animation\AnimHowTo\SubAnimInstance:description% | @@ -29,6 +31,7 @@ Refer to the tables below for more information and click each link to view its c | ------- | ------------ | | [](Engine\Animation\AnimHowTo\AdditiveAnimations) | %Engine\Animation\AnimHowTo\AdditiveAnimations:description% | | [](Engine\Animation\AnimHowTo\AnimDynamics) | %Engine\Animation\AnimHowTo\AnimDynamics:description% | +| [](Engine\Animation\AnimHowTo\CurveDrivenAnimation) | %Engine\Animation\AnimHowTo\CurveDrivenAnimation:description% | | [](Engine\Animation\AnimHowTo\LayerEditing) | %Engine\Animation\AnimHowTo\LayerEditing:description% | | [](Engine\Animation\AnimHowTo\AnimBPOverride) | %Engine\Animation\AnimHowTo\AnimBPOverride:description% | diff --git a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimHowToOverview.JPN.udn b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimHowToOverview.JPN.udn index 49792062ebca..1e5e8d1ca27c 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimHowToOverview.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimHowToOverview.JPN.udn @@ -1,8 +1,10 @@ -INTSourceChangelist:3231230 +INTSourceChangelist:3462657 Availability:Public Title:アニメーションの基本操作方法 Crumbs: %ROOT%, Engine, Engine\Animation, Engine\Animation\AnimHowTo Description:アンリアル エンジン 4 のアニメーション システムの様々な側面の例を段階的操作ガイドで説明します。 +type:how-to +type:landing アニメーションの操作ガイドでは、アンリアル エンジン 4 (UE4) 内の様々な [](Engine\Animation\Persona\Modes) を使用して作業する手順の例を説明します。 UE4 でのアニメーションの操作が初めての場合、または様々なツールで作業する方法を学習したい場合のいずれであっても、以下の操作ガイドでは幅広いトピックを扱い、学習の開始点、または知識を拡げる場所を提供します。 @@ -18,8 +20,8 @@ UE4 でのアニメーションの操作が初めての場合、または様々 ## Intermediate |操作ガイド | 説明 | | ------- | ------------ | -| [](Engine\Animation\AnimHowTo\PropertyBasedBlending) | %Engine\Animation\AnimHowTo\PropertyBasedBlending:description% | | [](Engine\Animation\AnimHowTo\AimOffset) | %Engine\Animation\AnimHowTo\AimOffset:description% | +| [](Engine\Animation\AnimHowTo\Blendspace) | %Engine\Animation\AnimHowTo\Blendspace:description% | | [](Engine\Animation\AnimHowTo\Retargeting) | %Engine\Animation\AnimHowTo\Retargeting:description% | | [](Engine\Animation\AnimHowTo\CreatePoseAsset) | %Engine\Animation\AnimHowTo\CreatePoseAsset:description% | | [](Engine\Animation\AnimHowTo\SubAnimInstance) | %Engine\Animation\AnimHowTo\SubAnimInstance:description% | @@ -30,6 +32,7 @@ UE4 でのアニメーションの操作が初めての場合、または様々 | ------- | ------------ | | [](Engine\Animation\AnimHowTo\AdditiveAnimations) | %Engine\Animation\AnimHowTo\AdditiveAnimations:description% | | [](Engine\Animation\AnimHowTo\AnimDynamics) | %Engine\Animation\AnimHowTo\AnimDynamics:description% | +| [](Engine\Animation\AnimHowTo\CurveDrivenAnimation) | %Engine\Animation\AnimHowTo\CurveDrivenAnimation:description% | | [](Engine\Animation\AnimHowTo\LayerEditing) | %Engine\Animation\AnimHowTo\LayerEditing:description% | | [](Engine\Animation\AnimHowTo\AnimBPOverride) | %Engine\Animation\AnimHowTo\AnimBPOverride:description% | diff --git a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimHowToOverview.KOR.udn b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimHowToOverview.KOR.udn index 66b588b43f2c..f7530892a6e0 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimHowToOverview.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/AnimHowToOverview.KOR.udn @@ -1,8 +1,10 @@ -INTSourceChangelist:3231230 +INTSourceChangelist:3462657 Availability: Public Title:애니메이션 비법 Crumbs: %ROOT%, Engine, Engine\Animation, Engine\Animation\AnimHowTo Description:여러가지 단계별 비법 안내를 통해 알아보는 언리얼 엔진 4 의 애니메이션 시스템 다양한 부분에 대한 예제입니다. +type:how-to +type:landing **애니메이션 비법** 페이지에는 언리얼 엔진 4 의 다양한 [](Engine\Animation\Persona\Modes) 사용법 및 작업 방법 관련 단계별 예제가 여럿 제공됩니다. UE4 의 애니메이션이 처음이거나 다양한 툴 사용법을 배우고자 하는 분들의 지식을 넓히기 위한 출발점이 될 것입니다. @@ -18,8 +20,8 @@ UE4 의 애니메이션이 처음이거나 다양한 툴 사용법을 배우고 ## 중급 |비법 | 설명 | | ------- | ------------ | -| [](Engine\Animation\AnimHowTo\PropertyBasedBlending) | %Engine\Animation\AnimHowTo\PropertyBasedBlending:description% | | [](Engine\Animation\AnimHowTo\AimOffset) | %Engine\Animation\AnimHowTo\AimOffset:description% | +| [](Engine\Animation\AnimHowTo\Blendspace) | %Engine\Animation\AnimHowTo\Blendspace:description% | | [](Engine\Animation\AnimHowTo\Retargeting) | %Engine\Animation\AnimHowTo\Retargeting:description% | | [](Engine\Animation\AnimHowTo\CreatePoseAsset) | %Engine\Animation\AnimHowTo\CreatePoseAsset:description% | | [](Engine\Animation\AnimHowTo\SubAnimInstance) | %Engine\Animation\AnimHowTo\SubAnimInstance:description% | @@ -30,6 +32,7 @@ UE4 의 애니메이션이 처음이거나 다양한 툴 사용법을 배우고 | ------- | ------------ | | [](Engine\Animation\AnimHowTo\AdditiveAnimations) | %Engine\Animation\AnimHowTo\AdditiveAnimations:description% | | [](Engine\Animation\AnimHowTo\AnimDynamics) | %Engine\Animation\AnimHowTo\AnimDynamics:description% | +| [](Engine\Animation\AnimHowTo\CurveDrivenAnimation) | %Engine\Animation\AnimHowTo\CurveDrivenAnimation:description% | | [](Engine\Animation\AnimHowTo\LayerEditing) | %Engine\Animation\AnimHowTo\LayerEditing:description% | | [](Engine\Animation\AnimHowTo\AnimBPOverride) | %Engine\Animation\AnimHowTo\AnimBPOverride:description% | diff --git a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/BlendSpace/BlendspaceHowTo.INT.udn b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/BlendSpace/BlendspaceHowTo.INT.udn index 3f4b2b60d169..e546fb47fd0e 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/BlendSpace/BlendspaceHowTo.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/BlendSpace/BlendspaceHowTo.INT.udn @@ -1,34 +1,28 @@ -Availability:Public -Title:Locomotion Based Blending +Availability: Docs Crumbs: %ROOT%, Engine, Engine\Animation, Engine\Animation\AnimHowTo +Title:Locomotion Based Blending Description:Example of a Blend Space used to blend a character's animations from walking and jogging. -version: 4.15 +Type: how-to skilllevel: Intermediate -type:how-to +version: 4.16 +Parent: Engine\Animation\AnimHowTo +Order: 1 tags:Animation tags:Blend Space +topic-image:BlendSpaceTopicCompact.png Related: Engine/Animation/Blendspaces Related: Engine/Animation/AimOffset Related: Engine/Animation/StateMachines Related: Engine/Animation/Skeleton + [Blend Spaces](Engine/Animation/Blendspaces) are special assets which can be sampled in **AnimGraphs** that allow for blending of animations based on the values of two inputs. Simple blending between two animations based on a single input can be performed using one of the standard [Blend Nodes](Engine/Animation/NodeReference/Blend) available in Animation Blueprints. Blend Spaces provide a means of doing more complex blending between multiple animations based on multiple values (currently limited to two). -In this How-to, we use a Blend Space to blend between walking and jogging animations based on the character's movement speed and movement direction similar to below. +In this How-to, we use a Blend Space to blend between walking and jogging animations based on the character's movement speed and movement direction. -[OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -jVtczzmNwQ4 -[/PARAMLITERAL] -[/OBJECT] +![](EndResultImage.png) ## Steps @@ -53,7 +47,7 @@ You can download the Animation Starter pack for free through the **Marketplace** We need to delete this character from the level in order to spawn in as the character from the previous step. -1. In the **Content/AnimStarterPack/UE4_Mannequin/Mesh** folder, **Right-click** on the **UE4_Mannequin** and under **Create**, select **Blend Space** and give it a name. +1. In the **Content/AnimStarterPack/UE4_Mannequin/Mesh** folder, right-click on the **UE4_Mannequin** and under **Create**, select **Blend Space** and give it a name. ![](BlendSpace3.png) @@ -141,7 +135,7 @@ You can download the Animation Starter pack for free through the **Marketplace** By default, the Animation Starter Pack has bindings created for crouch which our project does not. For this example, we will remove the ability to crouch walk. -1. **Right-click** in the graph and add a **Left Shift** Key Event, then drag the **CharacterMovement** into the graph from the **Components** tab. +1. Right-click in the graph and add a **Left Shift** Key Event, then drag the **CharacterMovement** into the graph from the **Components** tab. ![](BlendSpace15.png) @@ -151,7 +145,7 @@ You can download the Animation Starter pack for free through the **Marketplace** ![](BlendSpace17.png) - We are changing our movement speed based on if Left Shift is held and will alter our character's movement speed in game. + We are changing our movement speed based on if Left Shift is held and will alter our character's movement speed in-game. 1. Click the **CharacterMovement** component, then in the **Details** panel set the **Max Walk Speed** to **100**. @@ -163,7 +157,7 @@ You can download the Animation Starter pack for free through the **Marketplace** ![](BlendSpace18.png) - This will turn off the collision capsule debug display in game. + This will turn off the collision capsule debug display in-game. 1. Click **Compile** then click the **Play** in editor button from the Toolbar. @@ -171,15 +165,21 @@ You can download the Animation Starter pack for free through the **Marketplace** ## End Result [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -jVtczzmNwQ4 -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + jVtczzmNwQ4 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] When playing in the Editor, using **WASD** to move around, the character will now walk by default and blend between walking animations when changing directions. @@ -203,4 +203,5 @@ While standing, pressing and holding **Left Shift** while using WASD will cause + diff --git a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/BlendSpace/BlendspaceHowTo.JPN.udn b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/BlendSpace/BlendspaceHowTo.JPN.udn index 7939916053ca..dc60718f8519 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/BlendSpace/BlendspaceHowTo.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/BlendSpace/BlendspaceHowTo.JPN.udn @@ -1,29 +1,41 @@ -INTSourceChangelist:3255885 -Availability:Public -Title:ブレンドスペースを作成する +INTSourceChangelist:3477699 +Availability:Docs Crumbs: %ROOT%, Engine, Engine\Animation, Engine\Animation\AnimHowTo -Description:アニメーションの歩行 / ジョギング間で滑らかにキャラクターを切り替えるために使うブレンドスペースの例。 -version:4.14 +Title:ロコモーション ベースのブレンド +Description:キャラクター アニメーションを歩行からジョギングへとブレンドするために使うブレンドスペースの例。 +Type: how-to skilllevel:Intermediate -type:how-to +version:4.16 +Parent:Engine\Animation\AnimHowTo +Order:1 tags:Animation tags:Blend Space +topic-image:BlendSpaceTopicCompact.png Related:Engine/Animation/Blendspaces Related:Engine/Animation/AimOffset Related:Engine/Animation/StateMachines Related:Engine/Animation/Skeleton + [ブレンドスペース](Engine/Animation/Blendspaces) は 2 つの入力値に基づいたアニメーションのブレンドを可能にする **AnimGraph** でサンプリングできる特殊なアセットです。 -単一の入力に基づいた 2 つのアニメーションの単純なブレンドは、Animation ブループリントで利用可能な標準の [ブレンド ノード](Engine/Animation/NodeReference/Blend) の一つを使用して行うことができます。 +単一の入力に基づいた 2 つのアニメーションの単純なブレンドは、Animation ブループリントで利用可能な標準の [ブレンド ノード](Engine/Animation/NodeReference/Blend) のひとつを使用して行うことができます。 ブレンドスペースは、複数の値 (現在は 2 に限定) に基づいた複数のアニメーション間で一段と複雑なブレンドを可能にします。 このガイドでは、キャラクターの移動の速度と方向に基づき歩行とジョギングのアニメーション間でブレンドするためにブレンドスペースを使用します。 - -[INCLUDE:Engine\Animation\AnimHowTo\AdditiveAnimations\01_BlendSetup#intro] +![](EndResultImage.png) ## ステップ +[REGION:note] +このガイドでは **Blueprint Third Person** プロジェクトを使用し、**Animation Starter Pack** をプロジェクトに追加しました。 + +![](AnimationAssetPack.png)(w:800) + +Animation Starter Pack はエピックのランチャーの **マーケットプレイス** から無料でダウンロードすることができます。 + +[/REGION] + 1. プロジェクトの「 **Content/ThirdPersonBP/Blueprints** 」フォルダで **ThirdPersonGameMode** を開き、**Default Pawn Class** を **Ue4ASP_Character** に設定します。 ![](BlendSpace1.png) @@ -36,46 +48,61 @@ Related:Engine/Animation/Skeleton 前のステップからのキャラクターとしてスポーンするためには、レベルからこのキャラクターを削除する必要があります。 -1. **「Content/AnimStarterPack/UE4_Mannequin/Mesh」** フォルダで **UE4_Mannequin** 上で **右クリック** し **[Create]** で **[Blend Space]** を選択します。 +1. **「Content/AnimStarterPack/UE4_Mannequin/Mesh」** フォルダで UE4_Mannequin 上で **右クリック** し **[Create]** で **[Blend Space]** を選択して名前を付けます。 ![](BlendSpace3.png) - Blend Space アセットは参照する Skeleton アセットが必要です。ここではショートカットを使ってこの Skeleton アセットからブレンドスペースを作成します。 + Blend Space アセットは参照する Skeleton アセットが必要です。ここではショートカットを使ってこの Skeleton アセットからブレンドスペースを作成し、**MyBlendSpace** と呼びます。 -1. **[Parameters]** セクションで、以下の値を適用し、**[Apply Parameter Changes]** ボタンを押します。 +1. ブレンドスペース内の **[Asset Details]** パネルの **[Axis Settings]** で以下の値を追加します。 ![](BlendSpace4.png) - * **X Axis Label** を **Direction** に設定します。 - * **X Axis Range** を **-180 から 180** に設定します。 - * **Y Axis Label** を **Speed** に設定します。 - * **Y Axis Range** を **150 - 260** に設定します。 + 横軸は **移動** 方向を角度で決定します。 - **Direction** と **Speed** のパラメータを使うブレンドスペースは、どのポーズを使用し、ブレンドするかを判断します。 + |横軸の設定 | 値| + |---|---| + |**Name**| Direction | + |**Minimum Axis Value**| -180 | + |**Maximum Axis Value**| 180 | + |**Number of Grid Divisions**| 4 | + |**Interpolation Time**| 0 | + |**Interpolation Type**| Averaged Interpolation | + + 縦軸ではキャラクターが移動する **速度** を決めます。 + + |縦軸の設定 | 値| + |---|---| + |**Name**| Speed | + |**Minimum Axis Value**| 0 | + |**Maximum Axis Value**| 250 | + |**Number of Grid Divisions**| 4 | + |**Interpolation Time**| 0 | + |**Interpolation Type**| Averaged Interpolation | 1. **アセットブラウザ** で **Walk_Fwd_Rifle_Ironsights** アニメーションをグリッド上の下部中央にドラッグします。 ![](BlendSpace5.png) - このアニメーションをここに配置すると、 Speed が 150 で、方向は右でも左でもない場合に、アイアンサイト レベルでライフルを構えて前進することを示しています。 + ここはブレンドスペースに入ったときの開始位置になります。 -1. 以下のように **Walk_Lt_Rifle_Ironsights** アニメーションを位置 1 に **Walk_Rt_Rifle_Ironsights** アニメーションを位置 2 にドラッグします。 +1. 以下のように **Walk_Lt_Rifle_Ironsights** アニメーションを位置 1 に、**Walk_Rt_Rifle_Ironsights** アニメーションを位置 2 にドラッグします。 ![](BlendSpace6.png) - ここでは左右に動き、スピードが 150 のときに使用するアニメーションを配置します。 + ここでは左右に移動するときに使うアニメーションを配置します。 1. 以下のように **Walk_Bwd_Rifle_Ironsights** アニメーションを位置 **1** と位置 **2** にドラッグします。 ![](BlendSpace7.png) - ここでは後方に動き、スピードが 150 のときに使用するアニメーションを配置します。 + ここでは後方に移動するときに使うアニメーションを配置します。 1. **アセットブラウザ** で **Jog_Fwd_Rifle** アニメーションをグリッド上の上部中央にドラッグします。 ![](BlendSpace8.png) - これでスピードが最高限度 270 で、左右に動いていないときに前方向にジョギングする別のアニメーションを使用することができます。 + これでスピードが最高限度 250 で、左右に動いていないときに前方向にジョギングする別のアニメーションを使用することができます。 1. 以下のように **Jog_Lt_Rifle** アニメーションを位置 **1** に **Jog_Rt_Rifle** アニメーションを位置 **2** にドラッグします。 @@ -95,7 +122,7 @@ Related:Engine/Animation/Skeleton [ステートマシン](Engine/Animation/StateMachines) には既に Jog State があり、その中に別の Jogging モーションのためのブレンドスペースがあります。 -1. **[アセットブラウザ]** から、**Walk_Jog_BS** をグラフにドラッグし、 **BS_Jog** ブレンドスペースを以下のように置き換えます。 +1. **[アセットブラウザ]** から、**MyBlendSpace** アセットをグラフにドラッグし、**BS_Jog** ブレンドスペースを以下のように置き換えます。 ![](BlendSpace13.png) @@ -103,35 +130,29 @@ Related:Engine/Animation/Skeleton 1. **「Content/AnimStarterPack」** フォルダで、**Ue4ASP_Character** を開きます。 -1. グラフで **Crouch** セクションを見つけて、**InputAction Crouch** ノードを **C** Key Event に置き換えます。 +1. グラフで **Crouch** セクションを見つけて削除して警告エラーを取り除きます。 ![](BlendSpace14.png) - デフォルトで Animation Starter Pack には crouch (かがむ) のために作成されたバインディングがあります。これは、通常の **C** 押下 (または crouch で使う任意のキー) と置き換えます。 + デフォルトで Animation Starter Pack には crouch (かがむ) のために作成されたバインディングがありますが、これはこのプロジェクトにはありません。この例では、かがんで歩く機能を取り除きます。 -1. グラフ内を **右クリック** して、**Left Shift** Key Event を追加します。次に **[Components]** タブから **CharacterMovement** をグラフにドラッグします。 +1. グラフ内で 右クリック して、**Left Shift** Key Event を追加します。次に **[Components]** タブから **CharacterMovement** をグラフにドラッグします。 ![](BlendSpace15.png) [Left Shift] ボタンを押して保持すると、歩行からジョギングに切り替わります。 -1. **B** キーを押してグラフ内で **左クリック** して、**Branch** ノードを 2 つ作成します。**Crouch Button Down** 変数をドラッグして以下のように接続します。 - - ![](BlendSpace16.png) - - シフトキーを押している間、かがまないようにチェックする必要があります (例えば、かがんでいないときだけ、全速力で走ることができるからです)。 - -1. 両方の **Branch** ノードに対して、**CharacterMovement** ノードと **Set Max Walk Speed (最高歩行速度の設定)** をドラッグし、それぞれの値を **260** と **150** にします。 +1. **CharacterMovement** ノードと **Set Max Walk Speed (最高歩行速度の設定)** を **Pressed** と **Released** にドラッグし、それぞれの値を **250** と **150** にします。 ![](BlendSpace17.png) 左シフトを保持しているかに基づき移動速度を変更しており、ゲーム内のキャラクターの移動速度が変わります。 -1. グラフ内で **右クリック** して、**Event Begin Play** ノードを追加し、**CharacterMovement** コンポーネントを接続し、**Set Max Walk Speed** を **150** にします。 +1. **[CharacterMovement]** コンポーネントをクリックします。次に、 **[Details (詳細)]** パネルで **Max Walk Speed** を **100** に変更します。 ![](BlendSpace20.png) - ゲームを開始するために、キャラクターのデフォルトの移動速度を更新し、歩行を開始するようにします。 + キャラクターのデフォルトの移動速度を更新し、歩行を開始するようにします。 1. **[Components]** タブで **CapsuleComponent** をクリックします。次に **[Details (詳細)]** パネルの **[Hidden in Game (ゲーム内で非表示)]** オプションにチェックを入れます。 @@ -139,31 +160,31 @@ Related:Engine/Animation/Skeleton これでゲーム内のコリジョンのカプセルのデバッグ表示がオフになります。 -1. **[CharacterMovement]** コンポーネントをクリックします。次に、 **[Details (詳細)]** パネルで **Max Walk Speed** を **260** に変更します。 - - ![](BlendSpace19.png) - - ここで移動速度の最高限度を定め、ブレンドスペースにあるものを反映します。 - 1. **コンパイル** をクリックし、ツールバーで **[**Play** in editor ]** ボタンをクリックします。 ## 最終結果 [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -vn0_YKcu1RU -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + jVtczzmNwQ4 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] エディタでプレイする場合、 **WASD** を使用して移動すると、キャラクターがデフォルトで歩行し、方向を変えるときに歩行のアニメーション間でブレンドします。 立った状態で、WASD を使用しながら **Left Shift** を押して保持すると、キャラクターは歩行 / 照準のアニメーションから身を低くして / 照準して走るアニメーションにブレンドし、基本的にキャラクターを「スプリント」 (すばやく走ること) させます。 -**C** を押して保持すると、Animation Starter Pack プロジェクトの一部として作成したブレンドスペースを使って、かがんで歩行するアニメーション間でブレンドし、かがみながら歩行することができます。 + diff --git a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/BlendSpace/BlendspaceHowTo.KOR.udn b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/BlendSpace/BlendspaceHowTo.KOR.udn index 77e2ab2e4309..54b4467d683e 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/BlendSpace/BlendspaceHowTo.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/BlendSpace/BlendspaceHowTo.KOR.udn @@ -1,9 +1,9 @@ -INTSourceChangelist:3255885 +INTSourceChangelist:3441237 Availability:Public -Title:블렌드 스페이스 만들기 +Title:보행이동 기반 블렌딩 Crumbs: %ROOT%, Engine, Engine\Animation, Engine\Animation\AnimHowTo -Description:블렌드 스페이스를 사용하여 캐릭터의 걷기/달리기 애니메이션을 부드럽게 전환하는 예제입니다. -version: 4.14 +Description:캐릭터의 걷기에서 달리기 애니메이션 블렌딩에 블렌드 스페이스를 사용하는 예제입니다. +version: 4.15 skilllevel: Intermediate type:how-to tags:Animation @@ -17,13 +17,21 @@ Related: Engine/Animation/Skeleton 단일 입력에 따른 두 애니메이션 사이의 단순 블렌딩은 애니메이션 블루프린트에서 사용할 수 있는 표준 [블렌드 모드](Engine/Animation/NodeReference/Blend) 중 하나를 사용하여 가능합니다. 블렌드 스페이스는 (현재는 둘로 제한되어 있지만) 다수의 값에 따라 다수의 애니메이션에 대해 보다 복잡한 블렌딩을 할 수 있는 방편을 마련해 줍니다. -여기서는 블렌드 스페이스를 사용하여 캐릭터의 이동 속력과 방향에 따라 걷기/뛰기 애니메이션을 블렌딩하도록 하겠습니다. +여기서는 아래와 같이 블렌드 스페이스를 사용하여 캐릭터의 이동 속력과 방향에 따라 걷기/뛰기 애니메이션을 블렌딩하도록 하겠습니다. - -[INCLUDE:Engine\Animation\AnimHowTo\AdditiveAnimations\01_BlendSetup#intro] +![](EndResultImage.png) ## 단계 +[REGION:note] +여기서는 **블루프린트 삼인칭 템플릿** 프로젝트에 **Animation Starter Pack** 를 추가한 것을 사용합니다. + +![](AnimationAssetPack.png)(w:800) + +Animation Starter Pack 은 에픽 런처의 **마켓플레이스** 에서 무료로 받을 수 있습니다. + +[/REGION] + 1. 프로젝트의 **Content/ThirdPersonBP/Blueprints** 폴더에서 **ThirdPersonGameMode** 를 열고 **Default Pawn Class** 를 **Ue4ASP_Character** 로 설정합니다. ![](BlendSpace1.png) @@ -36,46 +44,61 @@ Related: Engine/Animation/Skeleton 레벨에서 이 캐릭터를 지우는 것은, 예전 단계의 캐릭터를 스폰시키기 위함입니다. -1. **Content/AnimStarterPack/UE4_Mannequin/Mesh** 폴더에서 **UE4_Mannequin** 에 **우클릭** 하고 **생성** 아래 **블렌드 스페이스** 를 선택합니다. +1. **Content/AnimStarterPack/UE4_Mannequin/Mesh** 폴더에서 **UE4_Mannequin** 에 **우클릭** 하고 **생성** 아래 **블렌드 스페이스** 를 선택하고 이름을 짓습니다. ![](BlendSpace3.png) - 블렌드 스페이스 애셋은 레퍼런싱할 스켈레톤 애셋이 필요한데, 여기서는 이 스켈레톤 애셋에서 블렌드 스페이스를 생성하는 단축 방법을 사용하고 있습니다. + 블렌드 스페이스 애셋은 레퍼런싱할 스켈레톤 애셋이 필요한데, 여기서는 이 스켈레톤 애셋에서 블렌드 스페이스를 생성하는 단축 방법을 사용하고 있습니다. 그 이름은 **MyBlendSpace** 입니다. -1. **Parameters** (파라미터) 섹션에서 아래 값을 적용한 뒤 **Apply Parameter Changes** (파라미터 변경사항 적용) 버튼을 클릭합니다. +1. 블렌드 스페이스의 **애셋 디테일** 패널에서 **Axis Settings** 아래 다음 값을 추가합니다: ![](BlendSpace4.png) - * **X Axis Label**: **Direction** - * **X Axis Range**: **-180 - 180** - * **Y Axis Label**: **Speed** - * **Y Axis Range**: **150 - 260** + Horizontal Axis (가로 축)은 이동 **Direction** (방향)을 각도 단위로 나타냅니다: - 이 블렌드 스페이스는 **Direction** 및 **Speed** 파라미터를 사용하여 to determine which pose we should be using or blending to or from. + |가로 축 세팅 | 값 | + |---|---| + |**Name**| Direction | + |**Minimum Axis Value**| -180 | + |**Maximum Axis Value**| 180 | + |**Number of Grid Divisions**| 4 | + |**Interpolation Time**| 0 | + |**Interpolation Type**| Averaged Interpolation | + + Vertical Axis (세로 축)은 캐릭터의 이동 **Speed** (속력)을 나타냅니다: + + |세로 축 세팅 | 값 | + |---|---| + |**Name**| Speed | + |**Minimum Axis Value**| 0 | + |**Maximum Axis Value**| 250 | + |**Number of Grid Divisions**| 4 | + |**Interpolation Time**| 0 | + |**Interpolation Type**| Averaged Interpolation | 1. **애셋 브라우저** 창에서 **Walk_Fwd_Rifle_Ironsights** 애니메이션을 끌어 그리드의 중앙 하단 위치에 놓습니다. ![](BlendSpace5.png) - 이 애니메이션을 여기 놓으면 속력은 150 이고 방향이 왼쪽이나 오른쪽은 아니라는 것을 나타냅니다. 라이플을 들고 ironsights 레벨까지 걸어가야 할 것입니다. + 그러면 이 블렌드 스페이스에 들어설 때 시작 위치가 됩니다. 1. 아래처럼 **Walk_Lt_Rifle_Ironsights** 애니메이션을 **1** 위치로, **Walk_Rt_Rifle_Ironsights** 애니메이션을 **2** 위치로 끌어 놓습니다. ![](BlendSpace6.png) - 여기서 좌우로 움직이고 속력이 150 일때 사용할 애니메이션을 배치합니다. + 여기서 좌우로 움직일 때 사용할 애니메이션을 배치합니다. 1. 아래처럼 **Walk_Bwd_Rifle_Ironsights** 애니메이션을 **1** 과 **2** 위치로 끌어 놓습니다. ![](BlendSpace7.png) - 여기서 뒤쪽 150 속력으로 움직일 때 사용할 애니메이션을 배치합니다. + 여기서 뒤로 움직일 때 사용할 애니메이션을 배치합니다. 1. **애셋 브라우저** 에서 **Jog_Fwd_Rifle** 애니메이션을 그리드 중앙 상단으로 끌어 놓습니다. ![](BlendSpace8.png) - 이렇게 하면 속력이 최대 270 이면서 좌우로 움직이지 않을 때, 즉 전방으로 뛸 때 다양한 애니메이션을 사용할 수 있습니다. + 이렇게 하면 속력이 최대 250 이면서 좌우로 움직이지 않을 때, 즉 전방으로 뛸 때 다양한 애니메이션을 사용할 수 있습니다. 1. 아래처럼 **Jog_Lt_Rifle** 애니메이션을 **1** 위치로, **Jog_Rt_Rifle** 애니메이션을 **2** 위치로 끌어 놓습니다. @@ -95,7 +118,7 @@ Related: Engine/Animation/Skeleton 이 [스테이트 머신](Engine/Animation/StateMachines) 에는 이미 Jog 스테이트가, 그 안에는 다양한 Jogging 모션에 대한 블렌드 스페이스가 있습니다. -1. 아래와 같이 **애셋 브라우저** 에서 **Walk_Jog_BS** 를 끌어 그래프에 놓고 **BS_Jog** 블렌드 스페이스를 대체합니다. +1. 아래와 같이 **애셋 브라우저** 에서 **MyBlendSpace** 를 끌어 그래프에 놓고 **BS_Jog** 블렌드 스페이스를 대체합니다. ![](BlendSpace13.png) @@ -103,11 +126,11 @@ Related: Engine/Animation/Skeleton 1. **Content/AnimStarterPack** 폴더의 **Ue4ASP_Character** 를 엽니다. -1. 그래프에서 **Crouch** 라 적인 부분을 찾아 **InputAction Crouch** 노드를 **C** Key Event 로 대체합니다. +1. 그래프에서 **Crouch** 라 적힌 부분을 찾아 지우면 경고와 오류가 제거됩니다. ![](BlendSpace14.png) - 기본적으로 Animation Starter Pack 은 웅크리기에 대한 바인딩이 있으나, 이를 일반 **C** 키( 또는 원하는 다른 키)로 대체하겠습니다. + 기본적으로 Animation Starter Pack 에는 웅크리기 키 바인딩이 되어 있지만, 우리 프로젝트에는 되어있지 않습니다. 이 예제에서는 웅크려 걷기 기능을 제거하겠습니다. 1. 그래프에 **우클릭** 하고 **Left Shift** Key Event 를 추가한 뒤, **컴포넌트** 탭에서 **CharacterMovement** 를 끌어 그래프에 놓습니다. @@ -115,23 +138,17 @@ Related: Engine/Animation/Skeleton Left Shift 키를 누르고 있으면 걷기에서 달리기로 전환됩니다. -1. 그래프에서 **B** 키를 누르고 **좌클릭** 하여 **Branch** (분기) 노드를 둘 추가한 뒤, **Crouch Button Down** 변수를 끌어 놓고 아래와 같이 연결합니다. - - ![](BlendSpace16.png) - - Shift 를 누르고 있을 때는 웅크리고 있지 않은지 확인해야 합니다 (이 예제에서 질주는 웅크리지 않은 상태에서만 가능합니다). - -1. **CharacterMovement** 노드를 끌어 놓고 양쪽 **Branch** (분기) 노드에 대해 **Set Max Walk Speed** 를 **260** 과 **150** 으로 각각 설정합니다. +1. **CharacterMovement** 노드를 끌어 놓고 **Pressed** 와 **Released** 에 대한 **Set Max Walk Speed** 를 각각 **250** 과 **100** 으로 설정합니다. ![](BlendSpace17.png) Left Shift 가 눌렸는지에 따라 이동 속력이 변경되고, 그에 따라 게임에서의 캐릭터 이동 속력이 변경됩니다. -1. 그래프에 **우클릭** 하고 **Event Begin Play** 노드를 추가한 뒤 **CharacterMovement** 컴포넌트를 **Set Max Walk Speed** **150** 에 연결합니다. +1. **CharacterMovement** 컴포넌트를 클릭한 뒤 **디테일** 패널에서 **Max Walk Speed** 를 **100** 으로 설정합니다. ![](BlendSpace20.png) - 게임을 시작하려면, 캐릭터가 걷기 상태로 시작할 수 있도록 기본 이동 속력을 업데이트해 줘야 합니다. + 캐릭터가 걷기 상태로 시작할 수 있도록 기본 이동 속력을 업데이트해 줘야 합니다. 1. **컴포넌트** 탭에서 **CapsuleComponent** 를 클릭하고, **디테일** 패널에서 **Hidden in Game** 옵션을 체크합니다. @@ -139,32 +156,32 @@ Related: Engine/Animation/Skeleton 그러면 게임에서의 콜리전 캡슐 디버그 표시가 꺼집니다. -1. **CharacterMovement** 컴포넌트를 클릭한 뒤, **디테일** 패널에서 **Max Walk Speed** 를 **260** 으로 설정합니다. - - ![](BlendSpace19.png) - - 여기서 최대 이동 속력을 제한시켜 블렌드 스페이스의 내용을 반영하고 있습니다. - 1. **컴파일** 후 툴바의 에디터에서 **플레이** 버튼을 클릭합니다. ## 최종 결과 [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -vn0_YKcu1RU -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + jVtczzmNwQ4 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] 에디터에서 플레이하면 **WASD** 키로 움직이며, 캐릭터는 기본적으로 걸어다니다가 방향을 바꾸면 걷기 애니메이션이 블렌딩됩니다. 서 있을 때 WASD 키를 누르며 **왼쪽 Shift** 를 누르고 있으면 캐릭터가 걷기/조준 애니메이션에서 낮춘/조준 뛰기 애니메이션으로 블렌딩되어, 사실상 캐릭터의 질주 자세가 됩니다. -**C** 키를 누르고 있을 수도 있는데, Animation Starter Pack 프로젝트의 일부로 생성된 블렌드 스페이스를 사용하여 웅크려 걷기 애니메이션을 블렌딩하여 웅크려 다닙니다. + @@ -183,3 +200,4 @@ vn0_YKcu1RU + diff --git a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/AnimBP/AnimBPSetup.INT.udn b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/AnimBP/AnimBPSetup.INT.udn index 1d949caa3a3c..3219721833d2 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/AnimBP/AnimBPSetup.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/AnimBP/AnimBPSetup.INT.udn @@ -1,4 +1,4 @@ -Availability: Public +Availability: docs Title:2. Setting up the Animation Blueprint Crumbs: %ROOT%, Engine, Engine\Animation, Engine\Animation\AnimHowTo, Engine\Animation\AnimHowTo\PropertyBasedBlending Description:In this step we set up the Animation Blueprint and State Machine to use our Blend Space diff --git a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/AnimBP/AnimBPSetup.JPN.udn b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/AnimBP/AnimBPSetup.JPN.udn index ddb460bf05e1..9985b030a99c 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/AnimBP/AnimBPSetup.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/AnimBP/AnimBPSetup.JPN.udn @@ -1,5 +1,5 @@ -INTSourceChangelist:3150518 -Availability:Public +INTSourceChangelist:3452142 +Availability: docs Title:2.Animation ブループリントをセットアップする Crumbs: %ROOT%, Engine, Engine\Animation, Engine\Animation\AnimHowTo, Engine\Animation\AnimHowTo\PropertyBasedBlending Description:Animation ブループリントとステートマシンを設定してブレンドスペースを使用します。 diff --git a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/AnimBP/AnimBPSetup.KOR.udn b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/AnimBP/AnimBPSetup.KOR.udn index 29147255304f..05c7074a3e22 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/AnimBP/AnimBPSetup.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/AnimBP/AnimBPSetup.KOR.udn @@ -1,5 +1,5 @@ -INTSourceChangelist:3150518 -Availability: Public +INTSourceChangelist:3452142 +Availability: docs Title:2. 애니메이션 블루프린트 구성 Crumbs: %ROOT%, Engine, Engine\Animation, Engine\Animation\AnimHowTo, Engine\Animation\AnimHowTo\PropertyBasedBlending Description:블렌드 스페이스에서 사용할 애니메이션 블루프린트와 스테이트 머신을 구성합니다. diff --git a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/Character/CharacterSetup.INT.udn b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/Character/CharacterSetup.INT.udn index 5be2b7824a8e..b87c59da198d 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/Character/CharacterSetup.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/Character/CharacterSetup.INT.udn @@ -1,4 +1,4 @@ -Availability: Public +Availability: docs Title:3. Setting up the Character Blueprint Crumbs: %ROOT%, Engine, Engine\Animation, Engine\Animation\AnimHowTo, Engine\Animation\AnimHowTo\PropertyBasedBlending Description:In this final step we provide a way for the player to press a key to alter the Speed parameter in our Blend Space. diff --git a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/Character/CharacterSetup.JPN.udn b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/Character/CharacterSetup.JPN.udn index 82eb533216d6..9b6264d4a355 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/Character/CharacterSetup.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/Character/CharacterSetup.JPN.udn @@ -1,5 +1,5 @@ -INTSourceChangelist:3150518 -Availability:Public +INTSourceChangelist:3452142 +Availability: docs Title:3.Character ブループリントを設定する Crumbs: %ROOT%, Engine, Engine\Animation, Engine\Animation\AnimHowTo, Engine\Animation\AnimHowTo\PropertyBasedBlending Description:この最後のステップでは、プレイヤーがキーを押してブレンドスペースで Speed パラメータを変更できるようにします。 diff --git a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/Character/CharacterSetup.KOR.udn b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/Character/CharacterSetup.KOR.udn index c8e6a7a34ab8..286bf822d7d4 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/Character/CharacterSetup.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/Character/CharacterSetup.KOR.udn @@ -1,5 +1,5 @@ -INTSourceChangelist:3150518 -Availability: Public +INTSourceChangelist:3452142 +Availability: docs Title:3. 캐릭터 블루프린트 구성 Crumbs: %ROOT%, Engine, Engine\Animation, Engine\Animation\AnimHowTo, Engine\Animation\AnimHowTo\PropertyBasedBlending Description:마지막으로 플레이어가 키를 눌러 블렌드 스페이스의 Speed 파라미터를 변경할 수 있는 방편을 마련합니다. diff --git a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/PropertyBasedBlending.INT.udn b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/PropertyBasedBlending.INT.udn index 26514a22d9e3..0d8b90d2b849 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/PropertyBasedBlending.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/PropertyBasedBlending.INT.udn @@ -9,6 +9,14 @@ checkpoint: animpropertyblend type:how-to +[OBJECT:Redirect] +[PARAM:link] +[](Engine/Animation/AnimHowTo/BlendSpace) +[/PARAM] +[/OBJECT] + + + diff --git a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/PropertyBasedBlending.JPN.udn b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/PropertyBasedBlending.JPN.udn index 1e3f4af4e085..f863f545593c 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/PropertyBasedBlending.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/PropertyBasedBlending.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3150518 +INTSourceChangelist:3452142 Availability:Public Title:プロパティ ベースのブレンド Crumbs: %ROOT%, Engine, Engine\Animation, Engine\Animation\AnimHowTo @@ -10,6 +10,14 @@ checkpoint: animpropertyblend type:how-to +[OBJECT:Redirect] +[PARAM:link] +[](Engine/Animation/AnimHowTo/BlendSpace) +[/PARAM] +[/OBJECT] + + + diff --git a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/PropertyBasedBlending.KOR.udn b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/PropertyBasedBlending.KOR.udn index d89c728685df..0dd62845739a 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/PropertyBasedBlending.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/PropertyBasedBlending.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3150518 +INTSourceChangelist:3452142 Availability: Public Title:프로퍼티 기반 블렌딩 Crumbs: %ROOT%, Engine, Engine\Animation, Engine\Animation\AnimHowTo @@ -10,6 +10,14 @@ checkpoint: animpropertyblend type:how-to +[OBJECT:Redirect] +[PARAM:link] +[](Engine/Animation/AnimHowTo/BlendSpace) +[/PARAM] +[/OBJECT] + + + diff --git a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/Setup/BlendSpaceSetup.INT.udn b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/Setup/BlendSpaceSetup.INT.udn index e198855bb367..9f24fa67c9f2 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/Setup/BlendSpaceSetup.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/Setup/BlendSpaceSetup.INT.udn @@ -1,4 +1,4 @@ -Availability: Public +Availability: docs Title:1. Setting up the Blend Space Crumbs: %ROOT%, Engine, Engine\Animation, Engine\Animation\AnimHowTo, Engine\Animation\AnimHowTo\PropertyBasedBlending Description:In this first step we create the Blend Space that will be used to blend our character animations. diff --git a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/Setup/BlendSpaceSetup.JPN.udn b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/Setup/BlendSpaceSetup.JPN.udn index 6b1f5f53031c..5eb60c42ce14 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/Setup/BlendSpaceSetup.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/Setup/BlendSpaceSetup.JPN.udn @@ -1,5 +1,5 @@ -INTSourceChangelist:3150518 -Availability:Public +INTSourceChangelist:3452142 +Availability: docs Title:1.ブレンドスペースを設定する Crumbs: %ROOT%, Engine, Engine\Animation, Engine\Animation\AnimHowTo, Engine\Animation\AnimHowTo\PropertyBasedBlending Description:この最初のステップでは、キャラクターのアニメーションをブレンドするために使うブレンドスペースを作成します。 diff --git a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/Setup/BlendSpaceSetup.KOR.udn b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/Setup/BlendSpaceSetup.KOR.udn index 9bebabe37762..fc9ea4339826 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/Setup/BlendSpaceSetup.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimHowTo/PropertyBasedBlending/Setup/BlendSpaceSetup.KOR.udn @@ -1,5 +1,5 @@ -INTSourceChangelist:3150518 -Availability: Public +INTSourceChangelist:3452142 +Availability: docs Title:1. 블렌드 스페이스 구성 Crumbs: %ROOT%, Engine, Engine\Animation, Engine\Animation\AnimHowTo, Engine\Animation\AnimHowTo\PropertyBasedBlending Description:먼저 캐릭터 애니메이션 블렌딩에 사용할 블렌드 스페이스를 만듭니다. diff --git a/Engine/Documentation/Source/Engine/Animation/AnimMontage/AnimMontage.INT.udn b/Engine/Documentation/Source/Engine/Animation/AnimMontage/AnimMontage.INT.udn index 9bc715cf34bd..0a7481e5bfb1 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimMontage/AnimMontage.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimMontage/AnimMontage.INT.udn @@ -16,6 +16,8 @@ Order: tags:Animation Montage tags:Animation type:overview +tags:Assets +topic-image:Engine/Animation/Overview/MontageTopic.png [TOC(start:2 end:3)] diff --git a/Engine/Documentation/Source/Engine/Animation/AnimMontage/AnimMontage.JPN.udn b/Engine/Documentation/Source/Engine/Animation/AnimMontage/AnimMontage.JPN.udn index 68bcf3ce07d4..24e6f7886737 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimMontage/AnimMontage.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimMontage/AnimMontage.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3318622 +INTSourceChangelist:3429233 Availability:Public Title:AnimMontage Crumbs: @@ -17,6 +17,8 @@ Order: tags:Animation Montage tags:Animation type:overview +tags:Assets +topic-image:Engine/Animation/Overview/MontageTopic.png [TOC(start:2 end:3)] diff --git a/Engine/Documentation/Source/Engine/Animation/AnimMontage/AnimMontage.KOR.udn b/Engine/Documentation/Source/Engine/Animation/AnimMontage/AnimMontage.KOR.udn index 3c022fb1b77e..06f6c2a70492 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimMontage/AnimMontage.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimMontage/AnimMontage.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3318622 +INTSourceChangelist:3429233 Availability:Public Title:애님 몽타주 Crumbs: @@ -17,6 +17,8 @@ Order: tags:Animation Montage tags:Animation type:overview +tags:Assets +topic-image:Engine/Animation/Overview/MontageTopic.png [TOC(start:2 end:3)] diff --git a/Engine/Documentation/Source/Engine/Animation/AnimPose/AnimBPPoseNodes/AnimBPPoseNodes.INT.udn b/Engine/Documentation/Source/Engine/Animation/AnimPose/AnimBPPoseNodes/AnimBPPoseNodes.INT.udn index 24420b91f67c..c02488154db5 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimPose/AnimBPPoseNodes/AnimBPPoseNodes.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimPose/AnimBPPoseNodes/AnimBPPoseNodes.INT.udn @@ -1,18 +1,25 @@ -Availability:Public -Title: AnimGraph Pose Nodes +Availability: Docs Crumbs: %ROOT%, Engine, Engine/Animation +Title: AnimGraph Pose Nodes Description:Describes how Pose Assets, Animation Blueprints, and Pose Nodes can be used to play curve driven animation at runtime. +Type: Reference +Version: 4.16 +Parent: Engine/Animation +Order: 1 +topic-image:PoseNodeTopic.png Related: Engine\Animation\AnimHowTo\CreatePoseAsset Related: Engine\Animation\Persona\AnimCurves Related: Engine\Animation\Sequences\Curves Related: Engine\Animation\AnimBlueprints Related: Engine\Animation\NodeReference\SkeletalControls -version: 4.14 - -[Pose Assets](Engine\Animation\AnimPose) can be driven at runtime with **Animation Blueprints** as the **AnimGraph** supports a few different Pose Nodes. +Tags:Animation +Tags:Animation Blueprint +Tags:Animation Blending [TOC (start:2 end:2)] +[Pose Assets](Engine\Animation\AnimPose) can be driven at runtime with **Animation Blueprints** as the **AnimGraph** supports a few different Pose Nodes. + ## Pose by Name / Pose Blender Nodes One way of driving **Pose Assets** is through the **Pose by Name** and **Pose Blender** nodes: @@ -23,23 +30,30 @@ One way of driving **Pose Assets** is through the **Pose by Name** and **Pose Bl In the example below, we have a face that uses a **Pose Asset** to smile when the player is close and frown when moving away. [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -d3oGXxq2ekw -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + d3oGXxq2ekw + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] + Our State Machine inside our Animation Blueprint is set up with three states: ![](StateMachine.png) Our default **State** which is our neutral expression, our **Smile** state which is entered when the player enters a trigger volume and our **Frown** state when the player leaves the trigger volume. -In this example, we only move between smiling and frowning states after triggering the first smile. Inside each state we use the **Pose Blender** and our animation sequence to apply the curve driven animation. +In this example, we only move between smiling and frowning states after triggering the first smile. Inside each state, we use the **Pose Blender** and our animation sequence to apply the curve driven animation. ![](PoseBlender.png) @@ -53,7 +67,7 @@ Additionally, using just a Pose Blender without supplying any incoming curve dat ![](NoCurveData.png) -You can also convert a Pose Blender node to a **Pose by Name** (which can also be converted to a Pose Blender node) through the **Right-click** context menu. +You can also convert a Pose Blender node to a **Pose by Name** (which can also be converted to a Pose Blender node) through the right-click context menu. ![](PoseByName.png) @@ -76,18 +90,24 @@ One use for this node would be to create a pose space deformer to drive correcti For example, in the clip below, clavicle bone poses are being used to move the shoulder relative to the arm bone's movement. [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -tJSYgPmzoKc -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + tJSYgPmzoKc + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] -To achieve this, an **RBF (Radial Basis Function)** interpolates driven values based on the orientation of a target bone. +To achieve this, a **RBF (Radial Basis Function)** interpolates driven values based on the orientation of a target bone. You will need to create a **Pose Asset** and define the target poses for the bone and the desired curve values at each pose. On the **Pose Driver** node itself, you have the following options: @@ -114,18 +134,28 @@ On the **Pose Driver** node itself, you have the following options: --> For additional information see the Unreal Engine Live Stream on Animation Topics which include a **Pose Driver** example: - + [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -h2egrj1pXzw -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + h2egrj1pXzw + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] + + + + diff --git a/Engine/Documentation/Source/Engine/Animation/AnimPose/AnimPose.INT.udn b/Engine/Documentation/Source/Engine/Animation/AnimPose/AnimPose.INT.udn index 343f59ed626c..9b45ab8caac1 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimPose/AnimPose.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimPose/AnimPose.INT.udn @@ -5,6 +5,8 @@ Description:Describes the Animation Pose Asset which can be used to drive animat Related: Engine\Animation\Persona\AnimCurves Related: Engine\Animation\AnimBlueprints version: 4.14 +tags:Assets +topic-image:AnimationPoseAssets_topic.png Traditional animation consists of a series of keyframed poses that are blended over a timeline to achieve the desired motion. In facial animation, curve driven animation is very popular as various weighted values can drive a particular expression. @@ -23,10 +25,12 @@ To illustrate how blending works, consider the following two key poses: We could weight the value of each pose to produce the resulting output pose (shown in the images across the top): +[REGION:imagetable] | |![](Pose_A.png)(w:200) |![](Pose_B.png)(w:204) | ![](Pose_C.png)(w:154)| | ----------- |------|------|------| | **Pose A Weight** | 0 | 1 | 0.5 | | **Pose B Weight** | 1 | 0 | 0.5 | +[/REGION] Above, if we weighted Pose A to 0 and Pose B to 1 (full influence), the resulting pose would be Pose B (right foot forward). If we weighted Pose A to 1 and Pose B to 0, the resulting pose would be left foot forward. diff --git a/Engine/Documentation/Source/Engine/Animation/AnimPose/AnimPose.JPN.udn b/Engine/Documentation/Source/Engine/Animation/AnimPose/AnimPose.JPN.udn index 3d08fb43fc39..f54dd2e7a44e 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimPose/AnimPose.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimPose/AnimPose.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3200922 +INTSourceChangelist:3467293 Availability:Public Title:Animation Pose アセット Crumbs: %ROOT%, Engine, Engine/Animation @@ -6,6 +6,8 @@ Description:ウェイト付けしたカーブ データを使ってアニメー Related:Engine\Animation\Persona\AnimCurves Related:Engine\Animation\AnimBlueprints version:4.14 +tags:Assets +topic-image:AnimationPoseAssets_topic.png 従来のアニメーションは、一連のキーフレーム化されたポーズで構成されます。これらは、タイムライン上でブレンドされて必要な動作を実現します。 フェイシャル アニメーションでは、カーブで操作されるアニメーションは非常に一般的です。様々なウェイト付けした値を使って特定の表現を操作できるからです。 @@ -24,10 +26,12 @@ UE4 のアニメーション システムは、**Animation Pose アセット** ( 各ポーズの値にウェイト付けし、その結果の出力ポーズを作ります (上部の画像)。 +[REGION:imagetable] | |![](Pose_A.png)(w:200) |![](Pose_B.png)(w:204) | ![](Pose_C.png)(w:154)| | ----------- |------|------|------| | **Pose A Weight** | 0 | 1 | 0.5 | | **Pose B Weight** | 1 | 0 | 0.5 | +[/REGION] 上記で、Pose A を 0 に、Pose B を 1 (完全に影響を与えます) にウェイト付けした結果のポーズが、 Pose B (右足を前) になります。 上記で、Pose A を 1 に、Pose B を 0 にウェイト付けした結果のポーズは左足を前になります。 diff --git a/Engine/Documentation/Source/Engine/Animation/AnimPose/AnimPose.KOR.udn b/Engine/Documentation/Source/Engine/Animation/AnimPose/AnimPose.KOR.udn index bf8cd62e57d1..88f44dd1f724 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimPose/AnimPose.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimPose/AnimPose.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3200922 +INTSourceChangelist:3467293 Availability:Public Title: 애니메이션 포즈 애셋 Crumbs: %ROOT%, Engine, Engine/Animation @@ -6,6 +6,8 @@ Description:가중치를 입힌 커브 데이터를 통해 애니메이션을 Related: Engine\Animation\Persona\AnimCurves Related: Engine\Animation\AnimBlueprints version: 4.14 +tags:Assets +topic-image:AnimationPoseAssets_topic.png 전통적인 애니메이션은 일련의 키프레임 포즈를 타임라인상에서 블렌딩하여 원하는 모션을 만들어내는 것입니다. 얼굴 애니메이션에서는 커브 구동 애니메이션이 인기를 끌고 있는데, 다양한 가중치(weight) 값으로 특정 표정을 구동시킬 수 있기 때문입니다. @@ -24,10 +26,12 @@ version: 4.14 각 포즈의 값에 가중치를 적용하여 (상단 이미지에 보이는) 결과 출력 포즈를 만들어낼 수 있습니다: +[REGION:imagetable] | |![](Pose_A.png)(w:200) |![](Pose_B.png)(w:204) | ![](Pose_C.png)(w:154)| | ----------- |------|------|------| | **포즈 A 가중치** | 0 | 1 | 0.5 | | **포즈 B 가중치** | 1 | 0 | 0.5 | +[/REGION] 위에서, 포즈 A 의 가중치를 0, 포즈 B 를 1 (최대 영향력) 으로 설정했다면, 결과 포즈는 포즈 B (오른 발 앞 상태)가 될 것입니다. 포즈 A 의 가중치를 1, 포즈 B 를 0 으로 설정했다면, 결과 포즈는 왼발이 앞인 상태가 될 것입니다. diff --git a/Engine/Documentation/Source/Engine/Animation/Animation.INT.udn b/Engine/Documentation/Source/Engine/Animation/Animation.INT.udn index 7d61f97bc6eb..5c27c1182858 100644 --- a/Engine/Documentation/Source/Engine/Animation/Animation.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/Animation.INT.udn @@ -51,6 +51,29 @@ order:3 [INCLUDE:Engine/Animation/Overview#Intro] +## Starting Out + +[DIR(output:"topic" parent:"Engine/Animation" org:"flat" tags:"Getting Started" type:"!how-to")] + +## Asset Types + +[DIR(output:"topic" parent:"Engine/Animation" org:"flat" tags:"Assets" type:"!how-to")] + +## Tools + +[DIR(output:"topic" parent:"Engine/Animation" end:"3" org:"hierarchy" tags:"!Assets" tags:"Tools" type:"!how-to")] + +## Features + +[DIR(output:"topic" parent:"Engine/Animation" end:"1" org:"hierarchy" tags:"!Assets" tags:"!Getting Started" tags:"!Tools" type:"!how-to")] + +## Guides + +[DIR(output:"fancy" parent:"Engine/Animation/AnimHowTo" end:"1" org:"hierarchy" tags:"!Assets" tags:"!Getting Started" type:"how-to" skilllevel:"Beginner")] +[DIR(output:"fancy" parent:"Engine/Animation/AnimHowTo" end:"1" org:"hierarchy" tags:"!Assets" tags:"!Getting Started" type:"how-to" skilllevel:"Intermediate")] +[DIR(output:"fancy" parent:"Engine/Animation/AnimHowTo" end:"1" org:"hierarchy" tags:"!Assets" tags:"!Getting Started" type:"how-to" skilllevel:"Advanced")] + +[PUBLISH:docs] [OBJECT:TopicButtonList] [PARAM:icon] ![](%ROOT%/start_icon.png)(convert:false) @@ -142,8 +165,4 @@ order:3 * [](Engine/Animation/UsingMixamoContent "%Engine/Animation/UsingMixamoContent:description%") [/PARAM] [/OBJECT] - - - - - +[/PUBLISH:docs] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Animation/Animation.JPN.udn b/Engine/Documentation/Source/Engine/Animation/Animation.JPN.udn index da71779ce755..541a1663119c 100644 --- a/Engine/Documentation/Source/Engine/Animation/Animation.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/Animation.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3231087 +INTSourceChangelist:3429229 Availability:Public Title:スケルタルメッシュのアニメーション システム Crumbs: %ROOT%, Engine @@ -52,6 +52,29 @@ order:3 [INCLUDE:Engine/Animation/Overview#Intro] +## はじめよう + +[DIR(output:"topic" parent:"Engine/Animation" org:"flat" tags:"Getting Started" type:"!how-to")] + +## アセットの種類 + +[DIR(output:"topic" parent:"Engine/Animation" org:"flat" tags:"Assets" type:"!how-to")] + +## ツール + +[DIR(output:"topic" parent:"Engine/Animation" end:"3" org:"hierarchy" tags:"!Assets" tags:"Tools" type:"!how-to")] + +## 機能 + +[DIR(output:"topic" parent:"Engine/Animation" end:"1" org:"hierarchy" tags:"!Assets" tags:"!Getting Started" tags:"!Tools" type:"!how-to")] + +## ガイド + +[DIR(output:"fancy" parent:"Engine/Animation/AnimHowTo" end:"1" org:"hierarchy" tags:"!Assets" tags:"!Getting Started" type:"how-to" skilllevel:"Beginner")] +[DIR(output:"fancy" parent:"Engine/Animation/AnimHowTo" end:"1" org:"hierarchy" tags:"!Assets" tags:"!Getting Started" type:"how-to" skilllevel:"Intermediate")] +[DIR(output:"fancy" parent:"Engine/Animation/AnimHowTo" end:"1" org:"hierarchy" tags:"!Assets" tags:"!Getting Started" type:"how-to" skilllevel:"Advanced")] + +[PUBLISH:docs] [OBJECT:TopicButtonList] [PARAM:icon] ![](%ROOT%/start_icon.png)(convert:false) @@ -143,8 +166,4 @@ order:3 * [](Engine/Animation/UsingMixamoContent "%Engine/Animation/UsingMixamoContent:description%") [/PARAM] [/OBJECT] - - - - - +[/PUBLISH:docs] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Animation/Animation.KOR.udn b/Engine/Documentation/Source/Engine/Animation/Animation.KOR.udn index 4d7dbbabd214..b68b220e6c32 100644 --- a/Engine/Documentation/Source/Engine/Animation/Animation.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/Animation.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3231087 +INTSourceChangelist:3429229 Availability:Public Title: 스켈레탈 메시 애니메이션 시스템 Crumbs: %ROOT%, Engine @@ -47,11 +47,34 @@ order:3 [/VAR] [REGION:banner] -![Animation System](animation_banner.png)(convert:false) +![애니메이션 시스템](animation_banner.png)(convert:false) [/REGION] [INCLUDE:Engine/Animation/Overview#Intro] +## 시작하기 + +[DIR(output:"topic" parent:"Engine/Animation" org:"flat" tags:"Getting Started" type:"!how-to")] + +## 애셋 유형 + +[DIR(output:"topic" parent:"Engine/Animation" org:"flat" tags:"Assets" type:"!how-to")] + +## 툴 + +[DIR(output:"topic" parent:"Engine/Animation" end:"3" org:"hierarchy" tags:"!Assets" tags:"Tools" type:"!how-to")] + +## 기능 + +[DIR(output:"topic" parent:"Engine/Animation" end:"1" org:"hierarchy" tags:"!Assets" tags:"!Getting Started" tags:"!Tools" type:"!how-to")] + +## 가이드 + +[DIR(output:"fancy" parent:"Engine/Animation/AnimHowTo" end:"1" org:"hierarchy" tags:"!Assets" tags:"!Getting Started" type:"how-to" skilllevel:"Beginner")] +[DIR(output:"fancy" parent:"Engine/Animation/AnimHowTo" end:"1" org:"hierarchy" tags:"!Assets" tags:"!Getting Started" type:"how-to" skilllevel:"Intermediate")] +[DIR(output:"fancy" parent:"Engine/Animation/AnimHowTo" end:"1" org:"hierarchy" tags:"!Assets" tags:"!Getting Started" type:"how-to" skilllevel:"Advanced")] + +[PUBLISH:docs] [OBJECT:TopicButtonList] [PARAM:icon] ![](%ROOT%/start_icon.png)(convert:false) @@ -143,8 +166,4 @@ order:3 * [](Engine/Animation/UsingMixamoContent "%Engine/Animation/UsingMixamoContent:description%") [/PARAM] [/OBJECT] - - - - - +[/PUBLISH:docs] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Animation/AnimationBlending/AnimationBlending.INT.udn b/Engine/Documentation/Source/Engine/Animation/AnimationBlending/AnimationBlending.INT.udn index 4f9b3c0ff85f..e1a9b60bfc66 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimationBlending/AnimationBlending.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimationBlending/AnimationBlending.INT.udn @@ -3,6 +3,7 @@ Title: Blending Animations Crumbs: %ROOT%, Engine, Engine/Animation description:Transitioning smoothly between two animations on a single Skeletal Mesh version: 4.9 +topic-image:BlendingAnimations_topic.png Animation blending, as a concept, simply means making a smooth transition between two or more animations on a single character or Skeletal Mesh. In Unreal Engine 4, there are various ways in which such blending can be applied. In this document, we will overview each one and how they can be applied to your characters. diff --git a/Engine/Documentation/Source/Engine/Animation/AnimationBlending/AnimationBlending.JPN.udn b/Engine/Documentation/Source/Engine/Animation/AnimationBlending/AnimationBlending.JPN.udn index 458e3b50218a..a8aab36399d7 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimationBlending/AnimationBlending.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimationBlending/AnimationBlending.JPN.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3467293 Availability:Public Title:アニメーション ブレンディング Crumbs: %ROOT%, Engine, Engine/Animation Description:単一のスケルタルメッシュで 2 つのアニメーション間を滑らかに遷移させます。 version:4.9 +topic-image:BlendingAnimations_topic.png アニメーションのブレンドとは、単一のキャラクターもしくはスケルタルメッシュ上の 2 つ以上のアニメーション間を滑らかに遷移させる、ということです。UE4 には、こうしたブレンドを適用できる様々な方法があります。このページはそれぞれの概要を示し、その適用方法を説明します。 diff --git a/Engine/Documentation/Source/Engine/Animation/AnimationBlending/AnimationBlending.KOR.udn b/Engine/Documentation/Source/Engine/Animation/AnimationBlending/AnimationBlending.KOR.udn index 5a3ac131f0a4..17e4b989aeec 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimationBlending/AnimationBlending.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimationBlending/AnimationBlending.KOR.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3467293 Availability:Public Title: 블렌드 스페이스 Crumbs: %ROOT%, Engine, Engine/Animation description:하나의 스켈레탈 메시에 두 개이 애니메이션을 부드럽게 전환하는 방법입니다. version: 4.9 +topic-image:BlendingAnimations_topic.png 애니메이션 블렌딩이란, 개념적으로, 하나의 캐릭터 또는 스켈레탈 메시에 둘 이상의 애니메이션이 부드럽게 전환되도록 만드는 것입니다. 언리얼 엔진 4 에서는 그러한 블렌딩을 적용할 수 있는 방법이 여러가지 있습니다. 이 문서에서는 그 각각을 개괄적으로 살펴보고 캐릭터에 적용할 수 있는 방법을 알아보도록 하겠습니다. diff --git a/Engine/Documentation/Source/Engine/Animation/AnimationComposite/AnimationComposite.INT.udn b/Engine/Documentation/Source/Engine/Animation/AnimationComposite/AnimationComposite.INT.udn index b20e19140ded..d3e99c11ec8d 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimationComposite/AnimationComposite.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimationComposite/AnimationComposite.INT.udn @@ -3,6 +3,8 @@ Title: Animation Composite Crumbs: %ROOT%, Engine, Engine/Animation Description:Animation Composites serve as a way to combine multiple animations together and treat them as a single unit. version: 4.9 +tags:Assets +topic-image:AnimationgComposite_topic.png [REGION:fullwidth] ![](AnimationCompositeHeader.png) diff --git a/Engine/Documentation/Source/Engine/Animation/AnimationComposite/AnimationComposite.JPN.udn b/Engine/Documentation/Source/Engine/Animation/AnimationComposite/AnimationComposite.JPN.udn index f864a0cc542e..098bcfe1c333 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimationComposite/AnimationComposite.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimationComposite/AnimationComposite.JPN.udn @@ -1,9 +1,11 @@ -INTSourceChangelist:2989492 +INTSourceChangelist:3467293 Availability:Public -Title:アニメーション合成 +Title:アニメーションの合成 Crumbs: %ROOT%, Engine, Engine/Animation Description:アニメーション合成は複数のアニメーションを結合し、単一ユニットとして扱います。 version:4.9 +tags:Assets +topic-image:AnimationgComposite_topic.png [REGION:fullwidth] ![](AnimationCompositeHeader.png) @@ -12,7 +14,7 @@ version:4.9 [TOC(start:2 end:2)] -一定の状況下では、いくつかのアニメーション シーケンスをつなぎ合わせて、多数のシーケンスではなく、単一シーケンスとして使用できるようにする必要があるかもしれません。まさにこれが **アニメーション合成** の用途です。アニメーション合成は複数のアニメーションを結合し、単一ユニットとして扱えるように設計されたアニメーション アセットです。しかし、合成はアニメーションを単につなげるだけで、ブレンド機能はないことに注意してください。 +一定の状況下では、いくつかのアニメーション シーケンスをつなぎ合わせて、多数のシーケンスではなく、単一シーケンスとして使用できるようにする必要があるかもしれません。これこそまさに、**アニメーション合成** の用途です。アニメーション合成は複数のアニメーションを結合し、単一ユニットとして扱えるように設計されたアニメーション アセットです。ただし、合成はアニメーションを単につなげるだけで、ブレンド機能はないことに注意してください。 [REGION:note] アニメーション合成は、[通知](Engine/Animation/Sequences\Notifies) と [カーブ](Engine/Animation/Sequences\Curves) の独自のセットを持つこともできます。 @@ -20,7 +22,7 @@ version:4.9 ## 合成を作成する -新規アニメーション合成を作成するには、**コンテンツ ブラウザ** で **右クリック** (または **Add New** ボタンを選択) して、**アニメーション** を選択して、表示されるコンテキストメニューから **Animation Composite** を選択します。 +新規アニメーション合成を作成するには、**コンテンツ ブラウザ** で **右クリック** (または **[Add New]** ボタンを選択) して、**アニメーション** を選択して、表示されるコンテキストメニューから **[Animation Composite]** を選択します。 ![](AnimationCompositeContextMenu.png) @@ -29,18 +31,18 @@ version:4.9 ![](PickSkeleton.png) [REGION:caption] -プロジェクトで使用可能なもののリストからスケルトンを選択します。 +プロジェクトで利用可能なもののリストからスケルトンを選択します。 [/REGION] -次に合成に名前を付ける必要があります。 +次に合成したもの (Composite) に名前を付けます。 ![](NameComposite.png) -これで合成が作成され、編集できるようになりました。 +Composite が作成されて編集の準備ができました。 ## 合成を編集する -合成を **ダブルクリック** すると、その合成が選択され、編集できる状態でアニメーション モードでペルソナが開きます。 +Composite (合成) を **ダブルクリック** すると、その合成が選択され、編集できる状態でアニメーション モードでペルソナが開きます。 ![](AnimationCompositeEdit.png)(w:600) @@ -52,15 +54,15 @@ version:4.9 ![](CompositeTrack.png)(w:600) -合成にアニメーション シーケンスを追加するには、**アセット ブラウザ** から アニメーション シーケンスを **Composite Track** にドラッグ & ドロップします。 +合成にアニメーション シーケンスを追加するには、**アセット ブラウザ** からアニメーション シーケンスを **Composite Track** にドラッグ & ドロップします。 ![](AddingAnimationsToComposite.png)(w:900) [REGION:caption] -さらにシーケンスをドラッグすると、自動的に追加されます。 +さらに多くのシーケンスをドラッグすると、自動的に追加されます。 [/REGION] -シーケンスをドラッグして **合成トラック** に沿って移動できます。また、シーケンス上で **右クリック** してコンテキスト メニューから **[Delete Segment (セグメントの削除)]** を選択して削除することができます。 +シーケンスをドラッグして **合成トラック** に沿って移動できます。また、シーケンス上で **右クリック** してコンテキスト メニューから **[Delete Segment (セグメントの削除)]** を選択してトラックを取り除くことができます。 ![](DeleteSegment.png) @@ -92,26 +94,26 @@ qm0KEa8K1A8 -##Anim アセットの詳細 +## Anim アセットの詳細 -**ペルソナ** でアニメーション合成を開く場合、**Anim Asset Details** パネル内で調整できるいくつかのプロパティがあり、アセットの処理方法を決めることができます。こうしたプロパティには、再生速度の微調整、メタ データのアセットへの割り当てなどがあり、以下の表で説明します。 +**ペルソナ** でアニメーション合成を開く場合、**[Anim Asset Details]** パネル内で調整できるいくつかのプロパティがあり、アセットの処理方法を決めることができます。こうしたプロパティには、再生速度の微調整、メタ データのアセットへの割り当てなどがあり、以下の表で説明します。 ![](AnimAssetDetailsComposite.png) |合成のプロパティ|| |---|---| -|[REGION:tablesection]加算設定[/REGION]|| +|[REGION:tablesection]追加設定[/REGION]|| |**Preview Base Pose**| 加算ブレンドスペースのためのベース ポーズをプレビューします。| |[REGION:tablesection]長さ[/REGION]|| |**Sequence Length**| 速度 1.0 (調整不可) で再生した場合の AnimSequence の長さ (秒単位) | |[REGION:tablesection]アニメーション[/REGION]|| -|**Rate Scale**| アニメーションの再生レートをグローバルに微調整する数値 | +|**Rate Scale**| アニメーションの再生レートをグローバルに微調整する数値です。 | |**Skeleton**| アセットを再生できるスケルトンへのポインタ (調整不可)| -|[REGION:tablesection]メタ データ[/REGION]|| -|**Meta Data**| アセットと共に保存可能なメタ データです。このメタデータは Anim Meta Data クラスから派生したブループリントで利用可能なクラスです。カスタムのメタ データを Animation アセットに追加できます (Anim Sequence、 Anim Montage、 Anim Composite、 および Blendspace はすべてサポートされます)。C++ で Animation アセットからこうしたデータをクエリーできます。`GetMetaData()` メソッドを呼び出すか、Anim Montages で `GetSectionMetaData()` を使用します。 +|[REGION:tablesection]メタデータ[/REGION]|| +|**Meta Data**| アセットと共に保存可能なメタデータです。このメタデータは Anim Meta Data クラスから派生したブループリントで利用可能なクラスです。カスタムのメタデータを Animation アセットに追加できます (Anim Sequence、 Anim Montage、 Anim Composite、 および Blendspace はすべてサポートされます)。C++ で Animation アセットからこうしたデータをクエリーできます。`GetMetaData()` メソッドを呼び出すか、Anim Montages で `GetSectionMetaData()` を使用します。 |[REGION:tablesection]サムネイル[/REGION]|| -| **Orbit Pitch** | アセット周囲の軌道カメラのピッチ | -| **Orbit Yaw** | アセット周囲の軌道カメラのヨー (左右回転) | -| **Orbit Zoom** | アセットから境界の球体の距離のオフセット | +| **Orbit Pitch** | アセット周囲の軌道カメラのピッチです。 | +| **Orbit Yaw** | アセット周囲の軌道カメラのヨー (左右回転) です。 | +| **Orbit Zoom** | アセットから境界の球体の距離のオフセットです。 | diff --git a/Engine/Documentation/Source/Engine/Animation/AnimationComposite/AnimationComposite.KOR.udn b/Engine/Documentation/Source/Engine/Animation/AnimationComposite/AnimationComposite.KOR.udn index 2afa24242d7a..cdc865699249 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimationComposite/AnimationComposite.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimationComposite/AnimationComposite.KOR.udn @@ -1,9 +1,11 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3467293 Availability:Public Title: 애니메이션 컴포짓 Crumbs: %ROOT%, Engine, Engine/Animation Description:Animation Composite, 애니메이션 컴포짓은 다수의 애니메이션을 합쳐 하나의 단위로 취급할 수 있도록 해 주는 역할을 합니다. version: 4.9 +tags:Assets +topic-image:AnimationgComposite_topic.png [REGION:fullwidth] ![](AnimationCompositeHeader.png) diff --git a/Engine/Documentation/Source/Engine/Animation/AnimationRetargeting/AnimationRetargeting.INT.udn b/Engine/Documentation/Source/Engine/Animation/AnimationRetargeting/AnimationRetargeting.INT.udn index c0cca19116f4..420051f6acfe 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimationRetargeting/AnimationRetargeting.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimationRetargeting/AnimationRetargeting.INT.udn @@ -3,6 +3,7 @@ Title: Animation Retargeting Crumbs: %ROOT%, Engine, Engine/Animation Description:Describes how retargeted animations can be used with multiple Skeletal Meshes, allowing you to share animations. version:4.14 +topic-image:AnimationgRetargeting_topic.png [REGION:fullwidth] ![](RetargetingHeader.png) diff --git a/Engine/Documentation/Source/Engine/Animation/AnimationRetargeting/AnimationRetargeting.JPN.udn b/Engine/Documentation/Source/Engine/Animation/AnimationRetargeting/AnimationRetargeting.JPN.udn index b9593c013d51..24443540b808 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimationRetargeting/AnimationRetargeting.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimationRetargeting/AnimationRetargeting.JPN.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:3206402 +INTSourceChangelist:3467293 Availability:Public Title:アニメーション リターゲット Crumbs: %ROOT%, Engine, Engine/Animation Description:リターゲットしたアニメーションを複数のスケルタルメッシュで使用して、アニメーションを共有できるようにします。 version:4.14 +topic-image:AnimationgRetargeting_topic.png [REGION:fullwidth] ![](RetargetingHeader.png) diff --git a/Engine/Documentation/Source/Engine/Animation/AnimationRetargeting/AnimationRetargeting.KOR.udn b/Engine/Documentation/Source/Engine/Animation/AnimationRetargeting/AnimationRetargeting.KOR.udn index 3613c32be264..5f6c0b5aee6f 100644 --- a/Engine/Documentation/Source/Engine/Animation/AnimationRetargeting/AnimationRetargeting.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/AnimationRetargeting/AnimationRetargeting.KOR.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:3206402 +INTSourceChangelist:3467293 Availability:Public Title: 애니메이션 리타게팅 Crumbs: %ROOT%, Engine, Engine/Animation Description:리타게팅된 애니메이션을 여러 스켈레탈 메시에 사용하여, 애니메이션을 공유하는 법입니다. version:4.14 +topic-image:AnimationgRetargeting_topic.png [REGION:fullwidth] ![](RetargetingHeader.png) diff --git a/Engine/Documentation/Source/Engine/Animation/Blendspaces/Blendspaces.INT.udn b/Engine/Documentation/Source/Engine/Animation/Blendspaces/Blendspaces.INT.udn index 4726dc991f96..27e5423f7460 100644 --- a/Engine/Documentation/Source/Engine/Animation/Blendspaces/Blendspaces.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/Blendspaces/Blendspaces.INT.udn @@ -1,38 +1,22 @@ -Availability:Public +Availability: Docs +Crumbs: %ROOT% Title: Blend Spaces -Crumbs: %ROOT%, Engine, Engine/Animation Description:Blend Spaces are assets that allow any number of animations to be blended between based on the values of multiple inputs. -Related: Engine/Animation/AnimBlueprints -Related: Engine/Content/FBX/Animations -Related: Engine/Animation/AnimMontage -Related: Engine\Animation\AnimHowTo\BlendSpace -Related: Engine/Animation/NodeReference/Blend -Related: Engine/Animation/StateMachines -Related: Engine/Animation/AnimBlueprints/AnimGraph -version: 4.15 +Type: Landing +Version: 4.16 +Parent: Engine/Animation +Order: 1 +tags:Blend Space +tags:Animation Blending +tags:Animation +topic-image:BlendTopic.png -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Animation/Blend Spaces:title%](Engine/Animation/animation_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Animation/Blend Spaces:title% - [/PARAM] - [PARAM:description] - %Engine/Animation/Blend Spaces:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Animation/Blend Spaces] - [/PARAM] -[/OBJECT] -[/VAR] +[REGION:banner] +![](BlendBanner.png) +[/REGION] [EXCERPT:Intro] -**Blend Spaces** are special assets which can be sampled in AnimGraphs that allow for blending of +**Blend Spaces** are special assets which can be sampled in **AnimGraphs** that allow for blending of animations based on the values of two inputs. Simple blending between two animations based on a single input can be performed using one of the standard [Blend nodes](Engine/Animation/NodeReference/Blend) available in [Animation Blueprints](Engine/Animation/AnimBlueprints). Blend Spaces provide a means of doing more complex blending diff --git a/Engine/Documentation/Source/Engine/Animation/Blendspaces/Blendspaces.JPN.udn b/Engine/Documentation/Source/Engine/Animation/Blendspaces/Blendspaces.JPN.udn index dcb02bf4a931..3b285a3165c9 100644 --- a/Engine/Documentation/Source/Engine/Animation/Blendspaces/Blendspaces.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/Blendspaces/Blendspaces.JPN.udn @@ -1,40 +1,24 @@ -INTSourceChangelist:3358386 -Availability:Public +INTSourceChangelist:3477699 +Availability:Docs +Crumbs: %ROOT% Title:Blend Spaces -Crumbs: %ROOT%, Engine, Engine/Animation Description:ブレンドスペースは複数入力値に基づいていくつものアニメーションのブレンドを可能にするアセットです。 -Related:Engine/Animation/AnimBlueprints -Related:Engine/Content/FBX/Animations -Related:Engine/Animation/AnimMontage -Related:Engine\Animation\AnimHowTo\BlendSpace -Related:Engine/Animation/NodeReference/Blend -Related:Engine/Animation/StateMachines -Related:Engine/Animation/AnimBlueprints/AnimGraph -version:4.15 +Type:Landing +Version:4.16 +Parent:Engine/Animation +Order:1 +tags:Blend Space +tags:Animation Blending +tags:Animation +topic-image:BlendTopic.png -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Animation/Blend Spaces:title%](Engine/Animation/animation_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Animation/Blend Spaces:title% - [/PARAM] - [PARAM:description] - %Engine/Animation/Blend Spaces:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Animation/Blend Spaces] - [/PARAM] -[/OBJECT] -[/VAR] +[REGION:banner] +![](BlendBanner.png) +[/REGION] [EXCERPT:Intro] **ブレンドスペース** は 2 つの入力値に基づいたアニメーションのブレンドを可能にする -AnimGraphs でサンプリングできる特別なアセットです。単一入力に基づいた 2 つのアニメーション間の簡単なブレンドは、 +**AnimGraphs** でサンプリングできる特別なアセットです。単一入力に基づいた 2 つのアニメーション間の簡単なブレンドは、 [Animation ブループリント](Engine/Animation/AnimBlueprints)で利用可能な標準の [Blend ノード](Engine/Animation/NodeReference/Blend) のひとつを使用して 行うことができます。ブレンドスペースは多値 (現時点では 2 値に制限) に基づいた複数アニメーションの 複雑なブレンドを可能にします。 diff --git a/Engine/Documentation/Source/Engine/Animation/Blendspaces/Blendspaces.KOR.udn b/Engine/Documentation/Source/Engine/Animation/Blendspaces/Blendspaces.KOR.udn index d6f0d757879b..761e529c1428 100644 --- a/Engine/Documentation/Source/Engine/Animation/Blendspaces/Blendspaces.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/Blendspaces/Blendspaces.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429233 Availability:Public Title: 블렌드 스페이스 Crumbs: %ROOT%, Engine, Engine/Animation @@ -6,41 +6,18 @@ Description:Blend Space, 블렌드 스페이스는 여러 입력값에 따라 Related: Engine/Animation/AnimBlueprints Related: Engine/Content/FBX/Animations Related: Engine/Animation/AnimMontage -Related: Engine/Animation/PhysicallyDrivenAnimation +Related: Engine\Animation\AnimHowTo\BlendSpace Related: Engine/Animation/NodeReference/Blend Related: Engine/Animation/StateMachines Related: Engine/Animation/AnimBlueprints/AnimGraph -Related: Engine/Content/Tools/MayaRiggingTool -version: 4.9 - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Animation/Blend Spaces:title%](Engine/Animation/animation_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Animation/Blend Spaces:title% - [/PARAM] - [PARAM:description] - %Engine/Animation/Blend Spaces:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Animation/Blend Spaces] - [/PARAM] -[/OBJECT] -[/VAR] - -[TOC (start:2 end:2)] - - +version: 4.15 +tags:Assets +topic-image:Engine/Animation/Overview/BlendSpaceTopic.png [EXCERPT:Intro] **블렌드 스페이스** (Blend Space) 는 애님그래프(AnimGraph) 에서 샘플링할 수 있는 특수 애셋으로, 두 입력값에 따라 애니메이션을 블렌딩시켜 주는 것입니다. 하나의 입력에 따라 두 애니메이션을 섞는 단순 블렌딩은 -애니메이션 블루프린트에서 쓸 수 있는 표준 [블렌드 노드](Engine/Animation/NodeReference/Blend) 를 사용하면 됩니다. +[애니메이션 블루프린트](Engine/Animation/AnimBlueprints) 에서 쓸 수 있는 표준 [블렌드 노드](Engine/Animation/NodeReference/Blend) 를 사용하면 됩니다. 블렌드 스페이스를 통해 (현재는 둘로 제한되어 있지만) 다수의 값에 따라 다수의 애니메이션을 블렌딩하는 복잡한 작업을 할 수 있습니다. @@ -50,154 +27,10 @@ version: 4.9 사실상 어떤 유형의 블렌딩도 범용 블렌드 스페이스를 사용해서 이뤄낼 수 있습니다. [/EXCERPT:Intro] - - - -[REGION:topics third] +[REGION:topics half] +%Engine\Animation\Blendspaces\Overview:topic% %Engine/Animation/Blendspaces/Creation:topic% %Engine/Animation/Blendspaces/Editor:topic% %Engine/Animation/Blendspaces/UserGuide:topic% [/REGION] -[REGION:tip] -**블렌드 스페이스** 의 적절한 예는 [애니메이션 콘텐츠 예제](Resources\ContentExamples\Animation) 문서의 1.3 섹션 아래에서 찾아볼 수 있습니다. -[/REGION] - -## 블렌드 스페이스 작동방식 - -블렌드 스페이스의 목적은 특정 속성이나 조건에 따라 블렌딩을 할 때마다 별개의 노드를 하드코딩하여 만드는 노고를 덜기 -위함입니다. 입력, 애니메이션, 애니메이션 끼리의 블렌딩을 위해 입력을 어떻게 사용할 것인지 등을 애니메이터나 -프로그래머가 지정할 수 있도록 하여, 사실상 어떤 유형의 블렌딩도 범용 블렌드 스페이스를 사용해서 이뤄낼 수 있습니다. -이는 언리얼 엔진 3 의 애님트리가 같은 작업을 처리하던 방식과는 완전 반대입니다. 복잡한 블렌딩을 해야 할 -때마다 새로운 노드를 만들어서 그 블렌딩을 처리해 줘야 했지요. 블렌드 스페이스는 완벽히 범용이라 블렌딩을 결정하는 -요인이 각 개별 블렌드 스페이스에 지정되도록 할 수 있습니다. 각 블렌드 스페이스에는 단순히 값만 받아들이는 입력이 -있습니다. 이 값은 (이벤트 그래프를 통해) 애니메이션 블루프린트의 업데이트 사이클 도중 계산하여 게임플레이 -코드나 다른 방법으로 구동 가능합니다. 이로 인해 확보되는 -엄청난 유연성 덕에, 애니메이션을 원하는 대로 블렌딩할 수 있는 능력을 -애님그래프를 만드는 사람의 손에 쥐어줄 수 있게 된 것입니다. - -![Input Flow](bs_flow.png) - -블렌드 스페이스는 일종의 2D 그래프로 생각해 볼 수 있습니다. 한 축을 따라서는 각각의 입력과 애니메이션이 다양한 시점에서 -그래프상에 뿌려지는 그래프로 말이지요. 블렌딩된 애니메이션에 대한 계산은, 현재 입력 값으로 지정된 위치에 -따라 그래프 상의 애니메이션끼리 블렌딩하는 식으로 이루어집니다. - -![](BlendSpaceLayout_2.png) - -1. 애니메이션 시퀀스 1 -1. 애니메이션 시퀀스 2 -1. 애니메이션 시퀀스 3 -1. 입력 1 축 (X-축) -1. 입력 2 축 (Y-축) - - -플레이어의 이동 속력과 방향에 따라 빈둥 애니메이션과 방향성 달리기 애니메이션을 블렌딩하는 전형적인 것을 -예로 들어 봅시다. - -언리얼 엔진 3 에서 이 작업은 방향성 블렌딩 노드와 속력 블렌딩 노드를 합쳐 사용하는 식으로 했었습니다. -이 노드 각각은 딱 그 블렌딩만 할 수 있도록 하드코딩되어 있었구요. 그 블렌딩에 사용된 값도 코드에 숨겨져 있어서, -프로그래머 말고는 블렌딩을 미세조정할 수 있는 방법도 없었을 뿐더러 코드에서 값을 수정한다 해도 그를 활용하는 모든 -애님트리에 있는 노드 인스턴스 전부에 영향을 끼치곤 했습니다. -별로 바람직하지는 않지요. - -블렌드 스페이스를 가지고서는, 같은 블렌딩 작업을 블렌드 스페이스 하나로 해낼 수 있습니다. -플레이어의 (-180 에서 180 까지 각도로 나타나는) 방향과 (0 에서 250 까지 초당 유닛 수로 나타나는) 속력이 -블렌드 스페이스에 입력으로 전해주는 값이 될 것이며, 애니메이션은 이 입력값에 따라 적절히 -블렌딩되도록 설정해야 할 것입니다. - -![](BlendSpaceDirection.png)(w:720) - -딱 하나의 노드만 있어도 된다는 것에 더해, 입력으로 사용되는 값을 애님블루프린트의 이벤트그래프에서 -직접 계산한 다음 애님그래프의 블렌드 스페이스에 전해줄 수도 있습니다. 입력값 미세조정도 쉽게 가능하며, -애니메이션 블렌딩 한계치도 그래픽 에디터를 통해 직관적으로 빠르게 조절할 수 있습니다. -기존 시스템에 비하면 유연성과 사용하기 쉽다는 점이 큰 장점입니다. - -## 1차원 블렌드 스페이스 - -블렌드 스페이스는 1차원 포맷으로도 생성 가능한데, **Blend Space 1D** (블렌드 스페이스 1D)라고도 합니다. 포즈나 애니메이션을 몇 개든 블렌딩 가능한데, 하나의 입력 값에 대해서만입니다. 사용 예라면, 캐릭터 질주시 기울이는 동작입니다. 포즈는 왼쪽 기울이기와 오른쪽 기울이기 둘이고, 캐릭터 질주시 플레이어가 얼마나 회전시키는가에 따라 결정되는 입력을 하나 사용합니다. 기울이기 포즈를 더하기식으로 블렌딩함으로써, 캐릭터의 기울이기가 급선회처럼 보이니 달리기 애니메이션에 생동감이 더욱 살아납니다. - -축이 두 개가 아니라 하나뿐이라는 점만 제외하면 블렌드 스페이스 1D 는 표준 양축 블렌드 스페이스와 똑같습니다. 그렇기에 이 문서에서는 2D 버전에 초점을 맞추겠습니다. 모든 규칙과 프로퍼티가 그대로 유지된다는 점만 알아두시면 되겠습니다. - -[OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -2mkn8FZL2KA -[/PARAMLITERAL] -[/OBJECT] - -## 구조 - -블렌드 스페이스의 근간을 이루는 구조는 꽤나 단순합니다. 입력값과 샘플링된 애니메이션, -이 주요한 부분은 앞서 다뤘습니다. - -### 스켈레톤 - -각 블렌드 스페이스는 다른 애니메이션 애셋 유형과 마찬가지로 특정 **스켈레톤** 을 타겟으로 담습니다. -블렌드 스페이스에 연결되는 스켈레톤은 블렌드 스페이스 생성시 설정되며, 블렌드 스페이스 안에서 어떤 애니메이션이 -샘플링 가능할지를 결정합니다. 어떤 애니메이션 블루프린트가 샘플링 가능할지도 결정하는데, -둘 다 같은 스켈레톤을 타겟으로 삼아야 하기 때문입니다. - -### 블렌드 파라미터 - -[EXCERPT:BlendParameters] -블렌드 스페이스의 **블렌드 파라미터** (Blend Parameter)는 본질적으로 앞서 말한 입력입니다. -각 블렌드 스페이스에는 세 개의 블렌드 파라미터 배열이 있으며, 각 블렌드 파라미터에는 -다음과 같은 프로퍼티가 있습니다: - -| 프로퍼티 | 설명 | -| -------- | ---- | -| **Label** | 라벨 - 블렌드 스페이스 에디터에서 _애니메이션 블루프린트_ 의 _AnimGraph_ 내 _BlendSpace_ 노드상의 이 입력에 대한 데이터 핀 위, 이 입력에 대한 축을 따라 표시되는 친근한 이름입니다. | -| **Range** | 범위 - 입력 데이터를 제한시킬 최소-최대값입니다. | -| **Divisions** | 분할 수 - 보간에 사용되는 애니메이션 데이터에서 샘플을 뽑아낼 지점 수입니다. 값이 높을 수록 결과가 정교해 집니다. 블렌드 스페이스 에디터에서는 이 입력에 대한 축에 따른 격자선으로 표시됩니다. | -[/EXCERPT:BlendParameters] - -### 샘플 데이터 - -[EXCERPT:SampleData] -블렌드 스페이스에 대한 **샘플 데이터** (Sample Data)는 애니에미션과 샘플 값 모음입니다. -샘플 값이란 그 특정 애니메이션의 웨이트(weight, 가중치)를 결정하는 데 사용되는 것입니다. -위의 방향성 이동을 예로 들면, 샘플 값이 (0.0, 250.0, 0.0) 인 **_Run_Fwd_** 애니메이션은, -방향 입력이 0.0 이고 속력 입력이 250.0 일 때 최대로 블렌딩되었습니다. -[/EXCERPT:SampleData] - -Sample Data 배열에 있는 각 항목에는 다음과 같은 프로퍼티가 들어있습니다: - -| 프로퍼티 | 설명 | -| -------- | ---- | -| **Animation** | 애니메이션 - 블렌딩 대상 AnimationSequence 애셋입니다. | -| **Sample Value** | 샘플 값 - **Animation** 이 최대 영향력을 갖는 입력값 (블렌드 파라미터에 상응하는 X, Y) 입니다. | - - -## 애님 애셋 디테일 - -블렌드 스페이스 애셋 구성시 **페르소나** 의 **애님 애셋 디테일** 패널을 통해 설정할 수 있는 추가 옵션이 있습니다. 기본적으로 이 창은 페르소나 에디터의 **애니메이션** 탭 좌하단 구석에 있으며, 다음과 같은 프로퍼티가 있습니다: - -![](BlendSpaceDetails.png) - -| 프로퍼티 | 설명 | -|---|---| -| [REGION:tablesection]Blend Space[/REGION] | 블렌드 스페이스 | -|**Display Editor Vertically**| 에디터 세로 표시 - 1D 블렌드 스페이스 애셋에만 사용가능한 옵션으로, 블렌드 스페이스 그래프의 표시 방식을 세로 또는 가로로 토글시킵니다. | -| [REGION:tablesection]Input Interpolation[/REGION] | 입력 보간 | -|**Axis to Scale Animation**| 애니메이션 스케일 조절 축 - 1D 블렌드 스페이스 애셋에는 사용할 수 없는 옵션으로, (입력 보간이 있는 경우) 어느 축으로 애니메이션 속도 (스케일) 구동을 시킬지 결정합니다. 예를 들어 보행 애니메이션의 경우, 속력 축이 애니메이션 속도를 구동(시켜 스케일을 조절)시킬 것입니다. | -|**Interpolation Params**| 보간 파라미터 - 세 축 모두에 대한 입력 보간 파라미터는, 각 축 입력에 대해 '보간 시간'과 '보간 유형'을 설정하여 입력 보간 방식을 결정합니다. | -| [REGION:tablesection]Sample Interpolation[/REGION] | 샘플 보간 | -|**Target Weight Interpolation Speed Per Sec**| 초당 타겟 위젯 보간 속도 - 타겟 샘플이 설정된 경우, 타겟으로의 보간 속도를 얼마나 빠르게 할지 설정하여 타겟 블렌딩을 향상시킵니다. 예를 들어 입력을 보간하는 경우, 왼쪽에서 오른쪽으로 빠르게 움직이면 전방을 통해 보간됩니다. 하지만 타겟 가중치 보간을 사용하면, 전방은 건너뛰고 좌우만 보간합니다. | -|**Per Bone Blend**| 본 별 블렌드 - 본 별 타겟 가중치 보간을 정의합니다. 각 본의 세팅별로 각기 다른 속도로 블렌드 인 됩니다. | -| [REGION:tablesection]Animation Notifies[/REGION] | 애니메이션 노티파이 | -|**Notify Trigger Mode**| 노티파이 트리거 모드 - 블렌드 스페이스에서 발동시킬 애니메이션 노티파이 결정을 위해 사용되는 현재 모드를 할당합니다. 그 옵션은 '모든 애니메이션' (모든 노티파이 이벤트 발동), '최고 가중치 애니메이션' (가중치가 최고인 애니메이션의 노티파이 이벤트만 발동), '없음' (어떤 애니메이션에서도 노티파이 이벤트가 발동되지 않음) 입니다. | -| [REGION:tablesection]Additive Settings[/REGION] | 애디티브 세팅 | -|**Preview Base Pose**| 프리뷰 베이스 포즈 - 애디티브 블렌드 스페이스에 대한 프리뷰 베이스 포즈입니다. | -| [REGION:tablesection]Animation[/REGION] | 애니메이션 | -|**Skeleton**|스켈레톤 - 이 애셋을 재생시킬 수 있는 스켈레톤으로의 포인터입니다 (조정불가). | -| [REGION:tablesection]Meta Data[/REGION] | 메타 데이터 | -|**Meta Data**| 메타 데이터 - 애셋과 함께 저장할 수 있는 메타 데이터입니다. Meta Data 는 Anim Meta Data 클래스에서 파생된 Blueprintable 클래스입니다. 이를 통해 애니메이션 애셋 (애님 시퀀스, 애님 몽타주, 애님 컴포짓, 블렌드 스페이스 모두 지원) 에 커스텀 메타 데이터를 추가시킬 수 있습니다. 애니메이션 애셋에 있는 데이터 쿼리는 C++ 에서 `GetMetaData()` 메소드를 호출하거나, 애님 몽타주에서 `GetSectionMetaData()` 를 사용하면 됩니다. | -| [REGION:tablesection]Thumbnail[/REGION] | 썸네일 | -|**Orbit Pitch**| 공전 핏치 - 애셋 주변을 공전하는 카메라의 핏치(상하) 입니다. | -|**Orbit Yaw**| 공전 요 - 애셋 주변을 공전하는 카메라의 요(좌우) 입니다. | -|**Orbit Zoom**| 공전 줌 - 애셋과의 바운드 구체 거리에 적용할 오프셋입니다. | \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Animation/Blendspaces/Creation/BlendspaceCreation.INT.udn b/Engine/Documentation/Source/Engine/Animation/Blendspaces/Creation/BlendspaceCreation.INT.udn index 88052407720b..052d96d815ce 100644 --- a/Engine/Documentation/Source/Engine/Animation/Blendspaces/Creation/BlendspaceCreation.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/Blendspaces/Creation/BlendspaceCreation.INT.udn @@ -1,26 +1,31 @@ -Availability:Public -Title: Creating Blend Spaces +Availability: Docs Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Blendspaces +Title: Creating Blend Spaces Description:Overview of creating a Blend Space and Blend Space 1D asset for use in Animation Blueprints. +Type: how-to +SkillLevel: Beginner +version: 4.16 +Parent: Engine/Animation/Blendspaces +Order: 1 +tags:Animation +tags:Animation Blueprint +tags:Blend Space +topic-image:createblendspacetopic.png Related: Engine\Animation\AnimHowTo\BlendSpace Related: Engine/Animation/Blendspaces/Editor Related: Engine/Animation/StateMachines Related: Engine/Animation/AnimBlueprints Related: Engine/Animation/AnimBlueprints/AnimGraph -version: 4.15 -type:how-to -tags:Animation -tags:Animation Blueprint -tags:Blend Space -topic-image:createblendspacetopic.png -This page covers how to create both **Blend Space** and **Blend Space 1D** assets as you will need to select a [Skeleton](Engine/Animation/Skeleton) to associate the Blend Space with. +This page covers how to create both **Blend Space** and **Blend Space 1D** assets using a [Skeleton](Engine/Animation/Skeleton) to associate the Blend Space with. + +## Steps [REGION:note] Creating a Blend Space and Blend Space 1D are generally the same, however, [](Engine/Animation/Blendspaces/Editor) slightly differs based on which asset you are working with. [/REGION] -1. In the **Content Browser**, click the **Add New** button (or **Right-click** in the Content Browser) and choose **Animation** > **Blend Space**. +1. In the **Content Browser** of your project, click the **Add New** button (or right-click in the Content Browser) and choose **Animation** > **Blend Space**. ![](NewBlendSpace.png) @@ -32,7 +37,9 @@ Creating a Blend Space and Blend Space 1D are generally the same, however, [](En ![](SkeletonList.png) - Your list of **Skeleton Assets** may look different based on the number of Skeleton Assets you have in your project. + [REGION:note] + Your list of assets may look different based on the number of Skeleton Assets you have in your project. + [/REGION] 1. Enter a name for your new Blend Space asset. @@ -42,6 +49,16 @@ Creating a Blend Space and Blend Space 1D are generally the same, however, [](En ![](AssetBrowserBlendList.png) +## End Result + +After creating a Blend Space, you can open it and it will appear empty (below). + +![](BlendSpaceAsset.png) + +From here you can begin creating [](Engine/Animation/AnimHowTo/BlendSpace) or your desired blending effect. + + + diff --git a/Engine/Documentation/Source/Engine/Animation/Blendspaces/Creation/BlendspaceCreation.JPN.udn b/Engine/Documentation/Source/Engine/Animation/Blendspaces/Creation/BlendspaceCreation.JPN.udn index cc9d7749a252..21693a2cb144 100644 --- a/Engine/Documentation/Source/Engine/Animation/Blendspaces/Creation/BlendspaceCreation.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/Blendspaces/Creation/BlendspaceCreation.JPN.udn @@ -1,27 +1,32 @@ -INTSourceChangelist:3358386 -Availability:Public -Title:ブレンド スペースの作成 +INTSourceChangelist:3477699 +Availability:Docs Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Blendspaces +Title:ブレンド スペースの作成 Description:Animation ブループリントで使用するための Blend Space と Blend Space 1D アセット作成の概要。 +Type: how-to +SkillLevel:Beginner +version:4.16 +Parent:Engine/Animation/Blendspaces +Order:1 +tags:Animation +tags:Animation Blueprint +tags:Blend Space +topic-image:createblendspacetopic.png Related:Engine\Animation\AnimHowTo\BlendSpace Related:Engine/Animation/Blendspaces/Editor Related:Engine/Animation/StateMachines Related:Engine/Animation/AnimBlueprints Related:Engine/Animation/AnimBlueprints/AnimGraph -version:4.15 -type:how-to -tags:Animation -tags:Animation Blueprint -tags:Blend Space -topic-image:createblendspacetopic.png -このページでは、**Blend Space** アセットと **Blend Space 1D** アセットの作成方法を説明します。ブレンドスペースを関連付ける [スケルトン](Engine/Animation/Skeleton) を選択する必要があるからです。 +このページでは、ブレンドスペースを関連付ける [スケルトン](Engine/Animation/Skeleton) を使って **Blend Space** アセットと **Blend Space 1D** アセットの作成方法を説明します。 + +## ステップ [REGION:note] Blend Space と Blend Space 1D の作成は一般的に同じですが、どのアセットで作業するかに応じて、[](Engine/Animation/Blendspaces/Editor) が若干異なります。 [/REGION] -1. **コンテンツ ブラウザ** で、 **[Add New (新規追加)]** ボタンをクリックします (またはコンテンツブラウザで **右クリック**)。次に **[Animation ]** > **[Blend Space]** の順に選択します。 +1. プロジェクトの **コンテンツ ブラウザ** で、 **[Add New (新規追加)]** ボタンをクリックします (またはコンテンツブラウザで右クリック)。次に **[Animation ]** > **[Blend Space]** の順に選択します。 ![](NewBlendSpace.png) @@ -33,7 +38,9 @@ Blend Space と Blend Space 1D の作成は一般的に同じですが、どの ![](SkeletonList.png) - **Skeleton Assets** のリストの内容は、プロジェクトに Skeleton アセットがいくつあるかに応じて異なります。 + [REGION:note] + アセットのリストの内容は、プロジェクトに Skeleton アセットがいくつあるかに応じて異なります。 + [/REGION] 1. 新しい Blend Space アセットの名前を入力します。 @@ -42,3 +49,18 @@ Blend Space と Blend Space 1D の作成は一般的に同じですが、どの ブレンドスペースは、そのブレンドスペースと同じスケルトンをターゲットとする Animation ブループリントの **AnimGraphs** でも利用可能です。 ![](AssetBrowserBlendList.png) + +## 最終結果 + +ブレンドスペースを作成したらそれを開くことができます。空の状態になっています (以下)。 + +![](BlendSpaceAsset.png) + +ここから [](Engine/Animation/AnimHowTo/BlendSpace) や必要なブレンド エフェクトを作成することができます。 + + + + + + + diff --git a/Engine/Documentation/Source/Engine/Animation/Blendspaces/Creation/BlendspaceCreation.KOR.udn b/Engine/Documentation/Source/Engine/Animation/Blendspaces/Creation/BlendspaceCreation.KOR.udn index 3f753fd31e11..503f862def29 100644 --- a/Engine/Documentation/Source/Engine/Animation/Blendspaces/Creation/BlendspaceCreation.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/Blendspaces/Creation/BlendspaceCreation.KOR.udn @@ -1,51 +1,48 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3358386 Availability:Public -Title: 블렌드 스페이스 만들기 +Title: 블렌드 스페이스 생성 Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Blendspaces -Description:애니메이션 블루프린트 애셋의 애님 그래프에서 사용할 다중입력 애니메이션 블렌딩 애셋인 Blend Space, 블렌드 스페이스를 새로 만드는 방법 안내서입니다. -version: 4.9 +Description:애니메이션 블루프린트에서 사용할 블렌드 스페이스 및 블렌드 스페이스 1D 애셋 생성 개요입니다. +Related: Engine\Animation\AnimHowTo\BlendSpace +Related: Engine/Animation/Blendspaces/Editor +Related: Engine/Animation/StateMachines +Related: Engine/Animation/AnimBlueprints +Related: Engine/Animation/AnimBlueprints/AnimGraph +version: 4.15 +type:how-to +tags:Animation +tags:Animation Blueprint +tags:Blend Space +topic-image:createblendspacetopic.png -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Animation/Blendspaces/Creation:title%](Engine/Animation/Blendspaces/create.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Animation/Blendspaces/Creation:title% - [/PARAM] - [PARAM:description] - %Engine/Animation/Blendspaces/Creation:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Animation/Blendspaces/Creation] - [/PARAM] -[/OBJECT] -[/VAR] +여기서는 **블렌드 스페이스** 및 **블렌드 스페이스 1D** 애셋을 만들어 블렌드 스페이스에 할당시킬 [스켈레톤](Engine/Animation/Skeleton) 을 선택하는 법을 다룹니다. +[REGION:note] +블렌드 스페이스 및 블렌드 스페이스 1D 는 거의 같습니다만, 작업중인 애셋에 따라 [](Engine/Animation/Blendspaces/Editor) 가 살짝 다릅니다. +[/REGION] -Blend Space (블렌드 스페이스)는 일반적인 애셋으로, 다른 애셋처럼 콘텐츠 브라우저를 통해 만들어야 합니다. - -**블렌드 스페이스 새로 만들기:** - -1. 콘텐츠 브라우저에서 새 블렌드 스페이스를 만들어 넣을 폴더로 이동한 다음, ![](Shared/EditorButtons/button_NewAsset.png) 버튼을 클릭하거나 우클릭 후 **애니메이션** > **블렌드 스페이스** 를 선택하면 됩니다. +1. **콘텐츠 브라우저** 에서 **신규 추가** 버튼 (또는 콘텐츠 브라우저에 **우클릭**) 후 **애니메이션** > **블렌드 스페이스** 를 선택합니다. ![](NewBlendSpace.png) -1. **스켈레톤 선택** 대화창에서 블렌드 스페이스가 타겟으로 삼을 스켈레톤을 선택합니다: + **블렌드 스페이스 1D** 를 생성하고자 하는 경우, 대신 그 옵션을 선택합니다. + + ![](blendspace1dcreate.png) + +1. **스켈레톤 선택** 대화창에서 블렌드 스페이스가 타겟으로 삼을 스켈레톤을 선택합니다. ![](SkeletonList.png) -1. 새로운 블렌드 스페이스 애셋이 콘텐츠 브라우저의 지정된 위치에 나타납니다: + **스켈레톤 애셋** 목록은 프로젝트에 있는 스켈레톤 애셋 수에 따라 달라보일 수 있습니다. + +1. 새로운 블렌드 스페이스 애셋의 이름을 입력합니다. + + ![Create Blueprint - Asset Created](bs_create_asset.png) + + 블렌드 스페이스는 블렌드 스페이스와 같은 스켈레톤을 타겟으로 하여 애니메이션 블루프린트의 **애님 그래프** 에서도 사용할 수 있습니다: + + ![](AssetBrowserBlendList.png) + - ![블루프린트 생성 - 애셋 생성됨](bs_create_asset.png) - 블렌드 스페이스는 그와 같은 스켈레톤을 타겟으로 삼는 애니메이션 블루프린트의 애님그래프에서 사용할 수도 있습니다: - [REGION:imagetable] - | ![](AssetBrowserBlendList.png)(h:400) | ![](ContextMenuBlendList.png)(h:400) | - | :---: | :---: | - | **애셋 브라우저** | **맥락 메뉴** | - [/REGION] diff --git a/Engine/Documentation/Source/Engine/Animation/Blendspaces/Editor/BlendspaceEditor.INT.udn b/Engine/Documentation/Source/Engine/Animation/Blendspaces/Editor/BlendspaceEditor.INT.udn index 075e368dea9c..d7a0cae03b14 100644 --- a/Engine/Documentation/Source/Engine/Animation/Blendspaces/Editor/BlendspaceEditor.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/Blendspaces/Editor/BlendspaceEditor.INT.udn @@ -1,30 +1,33 @@ -Availability:Public -Title: Editing Blend Spaces +Availability: Docs Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Blendspaces +Title: Editing Blend Spaces Description:Outlines how you can edit and set up the parameters that drive your Blend Space asset. +Type: Reference +version: 4.16 +Parent: Engine/Animation/Blendspaces +Order: 1 +tags:Animation +tags:Animation Blueprint +tags:Blend Space +topic-image:editblendspacetopic.png Related: Engine\Animation\AnimHowTo\BlendSpace Related: Engine\Animation\Blendspaces\Creation Related: Engine/Animation/StateMachines Related: Engine/Animation/AnimBlueprints Related: Engine/Animation/AnimBlueprints/AnimGraph -version: 4.15 -type:reference -topic-image:editblendspacetopic.png -tags:Animation -tags:Animation Blueprint -tags:Blend Space - -After [Creating a Blend Space](Engine\Animation\Blendspaces\Creation) and opening the asset, you will need to define the properties that drive the blending as well as specify what animations you want to sample from. [TOC(start:2 end:2)] +After [Creating a Blend Space](Engine\Animation\Blendspaces\Creation) and opening the asset, you will need to define the **Axis Settings** (or properties that drive the blending) as well as specify what animations to use as **Sample Poses**. +With those two elements defined, you can further adjust your Blend Space by altering properties within the **Blend Space Asset Details** panel. + ## Axis Settings The first thing you will want to do is set up your grid by defining the **Axis Settings** from the [Asset Details](Engine/Animation/Persona/AnimAssetDetails) panel. ![](AxisSettings.png) -For the normal Blend Space asset, you can define the **Horizontal Axis** and **Vertical Axis** as your inputs while Blend Space 1D assets use the horizontal axis only. +For a normal [Blend Space](Engine\Animation\AnimHowTo\BlendSpace) asset, you can define the **Horizontal Axis** and **Vertical Axis** as your inputs while Blend Space 1D assets use the Horizontal Axis only. For either axis, the properties that can be defined are the same: @@ -55,11 +58,15 @@ With your Axis Settings defined, the next thing you will want to do is add some In the example above, we have dragged an Idle animation from the **Asset Browser** into the grid at the point where Direction/Speed values are 0, or the character is not moving. -You can **Right-click** on a sample point to expand a roll-out menu with adjustable options for the sample. +You can right-click on a sample point to expand a roll-out menu with adjustable options for the sample. ![](RightClickSamplePoint.png) -You can change the location of the sample by adjusting either Axis Value, change the Animation or adjust the **Rate Scale** (or playback speed of the animation). +You can change the location of the sample by adjusting either Axis Value (in the case above, Direction or Speed), change the Animation or adjust the **Rate Scale**. + +[REGION:tip] +You can also edit sample values using the numeric entry boxes for the sample located in the upper-left section of the Blendspace Grid. +[/REGION] In addition to using the roll-out menu to move the sample by changing the Axis Value properties, you can drag-and-drop the sample to a new location on the grid. @@ -67,49 +74,68 @@ In addition to using the roll-out menu to move the sample by changing the Axis V To remove a sample from the grid, select your sample and press the **Delete** key. +You can also replace samples by drag-and-dropping a new sample on top of an existing sample. + +![](ChangeSample.png) + ### Previewing Blend Spaces Once you have a few sample poses placed on the grid, you can hold the **Shift** key and drag the green diamond around to view the blend between poses. [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -Kh3EubQ1IWM -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + G46ZWMJHkDA + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] +While holding **Shift**, you can also hold the **Ctrl** key to show actual sample values while previewing. + +![](ControlDownPreview.png) + When you release the **Shift** key, the green diamond will remain in its location enabling you to freely move the camera in the viewport to view the pose from different angles. ![](StickyKey.png) + + ### Grid Options -Inside the Blend Space Editor grid, you can also **Show Triangulation** or adjust **Stretch** settings. +Inside the Blend Space Editor grid, you can also **Show Triangulation**, **Show Animation Names** or adjust **Stretch** settings. ![](GridOptionsImage.png) -The video below illustrates the effects of both options and you can experiment to reach your desired effect. +The video below illustrates the effects of each option and you can experiment with each option to reach your desired effect. [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -rmTo7dcN6k4 -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + eeiHXdHuZTo + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] - - - ## Blend Space Asset Details While defining the Axis Settings and Sample Poses are two of the more critical elements to setting up your Blend Space, there are other properties in the **Asset Details** panel that you can adjust to further define how your Blend Space is used. @@ -158,11 +184,10 @@ This section enables you to smooth out interpolation between sample poses on a p This section defines the mode used by the Blend Space to determine which [Animation Notifiy](Engine/Animation/Sequences/Notifies) to fire. -Notify Trigger Modes include: - -* **All Animations** - All notify events will fire. -* **Highest Weighted Animation** - Notify events will only fire from the highest weight animation. -* **None** - No notify events will fire from any animations. +|---|---| +|**All Animations**| All notify events will fire. | +|**Highest Weighted Animation**| Notify events will only fire from the highest weight animation. | +|**None**| No notify events will fire from any animations. | ### Meta Data @@ -174,3 +199,4 @@ This section enables you to adjust the view perspective inside the asset thumbnail that appears in the **Content Browser**. + diff --git a/Engine/Documentation/Source/Engine/Animation/Blendspaces/Editor/BlendspaceEditor.JPN.udn b/Engine/Documentation/Source/Engine/Animation/Blendspaces/Editor/BlendspaceEditor.JPN.udn index 049e179a93ae..3eca57033913 100644 --- a/Engine/Documentation/Source/Engine/Animation/Blendspaces/Editor/BlendspaceEditor.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/Blendspaces/Editor/BlendspaceEditor.JPN.udn @@ -1,31 +1,34 @@ -INTSourceChangelist:3361084 -Availability:Public -Title:ブレンド スペースの編集 +INTSourceChangelist:3477699 +Availability:Docs Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Blendspaces +Title:ブレンド スペースの編集 Description:Blend Space アセットを操作するパラメータを編集し、セットアップする方法についての概要 +Type:Reference +version:4.16 +Parent:Engine/Animation/Blendspaces +Order:1 +tags:Animation +tags:Animation Blueprint +tags:Blend Space +topic-image:editblendspacetopic.png Related:Engine\Animation\AnimHowTo\BlendSpace Related:Engine\Animation\Blendspaces\Creation Related:Engine/Animation/StateMachines Related:Engine/Animation/AnimBlueprints Related:Engine/Animation/AnimBlueprints/AnimGraph -version:4.15 -type:reference -topic-image:editblendspacetopic.png -tags:Animation -tags:Animation Blueprint -tags:Blend Space - -[ブレンドスペース作成](Engine\Animation\Blendspaces\Creation) 後、アセットを開いたら、ブレンドを操作するプロパティを定義し、サンプリングするアニメーションも指定する必要があります。 [TOC(start:2 end:2)] +[ブレンドスペース作成](Engine\Animation\Blendspaces\Creation) 後、アセットを開いたら、**Axis Settings (軸の設定)** (ブレンドを操作するプロパティ) を定義し、**Sample Poses** として使用するアニメーションも指定する必要があります。 +こうした 2 つのエレメントを定義した状態で、**[Blend Space Asset Details (ブレンドスペースのアセット詳細)]** パネル内のプロパティを変更することでブレンドスペースをさらに調整することができます。 + ## 軸の設定 最初に、[Asset Details](Engine/Animation/Persona/AnimAssetDetails) パネルから **Axis Settings (軸の設定)** を定義してグリッドをセットアップします。 ![](AxisSettings.png) -通常の Blend Space アセットでは、入力として **Horizontal Axis** と **Vertical Axis** を定義することができますが、Blend Space 1D アセットでは水平軸のみを使用します。 +通常の [Blend Space](Engine\Animation\AnimHowTo\BlendSpace) アセットでは、入力として **Horizontal Axis** と **Vertical Axis** を定義することができますが、Blend Space 1D アセットでは水平軸のみを使用します。 いずれの軸でも定義可能なプロパティは同じで以下のとおりです。 @@ -60,7 +63,11 @@ tags:Blend Space ![](RightClickSamplePoint.png) -軸の値を調整、アニメーションを変更、または **[Rate Scale]** (またはアニメーションの再生速度)を調整してサンプルの位置を変更することができます。 +軸の値 (上のケースでは、 Direction または Speed) を調整、アニメーションを変更、または **[Rate Scale]** を調整してサンプルの位置を変更することができます。 + +[REGION:tip] +ブレンドスペース グリッドの左上にあるサンプルの数値入力ボックスを使ってサンプル値を編集することもできます。 +[/REGION] 展開メニューを使って軸値のプロパティを変更してサンプルを移動する以外に、サンプルをグリッド上の新しい位置にドラッグ&ドロップすることができます。 @@ -68,49 +75,68 @@ tags:Blend Space グリッドからサンプルを取り除くには、サンプルを選択し、**[Delete]** キーを押します。 +既存サンプルの上に新規サンプルをドラッグ&ドロップしてサンプルを置き換えることもできます。 + +![](ChangeSample.png) + ### ブレンドスペースのプレビュー グリッドにいくつかのサンプル ポーズがある場合、**[Shift]** キーを押しながら緑のダイヤ型アイコンをドラッグしてポーズ間のブレンドを見ることができます。 [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -Kh3EubQ1IWM -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + G46ZWMJHkDA + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] +**Shift** キーを押しながら、**Ctrl** キーを押してプレビュー中に実際のサンプル値を表示させることができます。 + +![](ControlDownPreview.png) + **Shift** キーを放すと、緑のダイヤ型アイコンがその位置にとどまり、ビューポート内でカメラを自由に動かし、様々なアングルからポーズを見ることができます。 ![](StickyKey.png) + + ### グリッドのオプション -ブレンドスペース エディタのグリッド内で、**Show Triangulation (トライアングル化を表示)** したり、**Stretch** 設定を調整することもできます。 +ブレンドスペース エディタのグリッド内で、**Show Triangulation (トライアングル化を表示)**、 **Show Animation Names (アニメーション名を表示)**、**Stretch** 設定を調整することもできます。 ![](GridOptionsImage.png) -以下の動画は、両方のオプションの効果を示しています。必要な結果が得られるようにいろいろ試すことができます。 +以下の動画は、各オプションの効果を示しています。必要な結果が得られるように各オプションを使って試すことができます。 [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -rmTo7dcN6k4 -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + eeiHXdHuZTo + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] - - - ## Blend Space アセットの詳細 軸設定とサンプル ポーズの定義はブレンドスペースの設定の中でも重要なものですが、**[Asset Details]** パネルにはブレンドスペースをどのように使うかをさらに定義するプロパティが他にもあります。 @@ -159,11 +185,10 @@ rmTo7dcN6k4 このセクションでは、ブレンドスペースが使用するモードを定義し、どの [アニメーション通知](Engine/Animation/Sequences/Notifies) を発行するかを決めます。 -通知トリガー モードには以下があります。 - -* **All Animations** - すべての通知イベントが発行します。 -* **Highest Weighted Animation** - 一番高いウェイトのアニメーションからのみ通知イベントが発行します。 -* **None** - どのアニメーションからも通知イベントは発行しません。 +|---|---| +|**All Animations**| すべての通知イベントが発行します。 | +|**Highest Weighted Animation**| 一番高いウェイトのアニメーションからのみ通知イベントが発行します。 | +|**None**| - どのアニメーションからも通知イベントは発行しません。 | ### Meta Data @@ -175,3 +200,4 @@ rmTo7dcN6k4 **コンテンツ ブラウザ** に表示されるアセットのサムネイル内の表示の視点を調整します。 + diff --git a/Engine/Documentation/Source/Engine/Animation/Blendspaces/Editor/BlendspaceEditor.KOR.udn b/Engine/Documentation/Source/Engine/Animation/Blendspaces/Editor/BlendspaceEditor.KOR.udn index e72458a33d69..0009bda1a1f6 100644 --- a/Engine/Documentation/Source/Engine/Animation/Blendspaces/Editor/BlendspaceEditor.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/Blendspaces/Editor/BlendspaceEditor.KOR.udn @@ -1,189 +1,199 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3441237 Availability:Public -Title: 블렌드 스페이스 편집하기 +Title: 블렌드 스페이스 편집 Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Blendspaces -Description:복잡한 다중입력 애니메이션 블렌딩을 위해 블렌드 스페이스에 샘플 파라미터와 애니메이션 샘플을 셋업하는 방법 안내서입니다. -version: 4.9 +Description:블렌드 스페이스 애셋을 구동시키는 파라미터 편집 및 구성 방법 개요입니다. +Related: Engine\Animation\AnimHowTo\BlendSpace +Related: Engine\Animation\Blendspaces\Creation +Related: Engine/Animation/StateMachines +Related: Engine/Animation/AnimBlueprints +Related: Engine/Animation/AnimBlueprints/AnimGraph +version: 4.15 +type:reference +topic-image:editblendspacetopic.png +tags:Animation +tags:Animation Blueprint +tags:Blend Space +[](Engine\Animation\Blendspaces\Creation) 및 애셋을 연 후, 블렌딩을 구동시킬 프로퍼티 정의는 물론 샘플링해 오고자 하는 애니메이션을 지정해 줘야 합니다. -[VAR:topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Animation/BlendSpaces/Editor:title%](Engine/Animation/BlendSpaces/edit.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Animation/BlendSpaces/Editor:title% - [/PARAM] - [PARAM:description] - %Engine/Animation/BlendSpaces/Editor:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Animation/BlendSpaces/Editor] - [/PARAM] -[/OBJECT] -[/VAR] +[TOC(start:2 end:2)] +## 축 세팅 +먼저 해 줄 작업은 [](Engine/Animation/Persona/AnimAssetDetails) 패널에서 **Axis Settings** (축 세팅)을 정의하여 그리드를 구성해 주는 작업입니다. -[REGION:banner] -![Blendspace Editor](bs_editor_banner.png)(convert:false) -[/REGION] +![](AxisSettings.png) -[EXCERPT:overview] -**Blend Space Editor**, 블렌드 스페이스 에디터는 _블렌드 스페이스_ 의 _블렌드 파라미터_ 설정은 물론 -샘플 포즈의 위치를 그래픽으로 보며 편집하고, 그 샘플 포즈간의 블렌딩 결과를 대화식으로 -확인할 수도 있습니다. -[/EXCERPT:overview] +일반적인 블렌드 스페이스 애셋의 경우, **Horizontal Axis** (가로 축)과 **Vertical Axis** (세로 축)을 입력으로, 블렌드 스페이스 1D 는 가로 축만 사용하도록 정의하면 됩니다. -[TOC(start:2)] +어느 축이든, 정의할 수 있는 프로퍼티는 같습니다: -## 인터페이스 +[EXCERPT:axissettings] +|축 세팅|| +|---|---| +|**Name**| 블렌드 스페이스 에디터 그리드에서 이 축에 표시할 이름입니다 (애니메이션 블루프린트 안의 블렌드 스페이스 노드에 노출된 핀 이름이기도 합니다). | +|**Minimum Axis Value**| 최소 축 값 - 이 파라미터에 대해 입력 데이터 클램핑을 적용할 최소 값입니다. | +|**Maximum Axis Value**| 최대 축 값 - 이 파라미터에 대해 입력 데이터 클램핑을 적용할 최대 값입니다. | +|**Number of Grid Divisions**| 그리드 분할 수 - 애니메이션 데이터에서 보간에 사용되는 샘플링 지점 수입니다. 값이 클 수록 결과가 정교해집니다. 이 입력 축을 따라 블렌드 스페이스 에디터 그리드에 그리드 선으로 표시됩니다. | +|**Interpolation Time**| 보간 시간 - 입력에 대한 보간 시간으로, 입력을 받으면 이 시간을 사용하여 타겟으로 보간합니다. 부드러운 보간에 사용됩니다. | +|**Interpolation Type**| 보간 유형 - 입력 값 필터링에 사용되는 보간 유형으로, 타겟에 이르는 방법을 결정합니다. | +[/EXCERPT:axissettings] -![](TestBlendShape.png)(w:720) +보통 여러 방향 보행 이동의 경우, 한 축은 이동 각도로 나타나는 **Direction** (방향)으로, 다른 축은 이동 **Speed** (속력)으로 정의합니다. -1. **Parameters** - _블렌드 스페이스_ 셋업을 위한 _블렌드 파라미터_ 프로퍼티 부분입니다. -1. **Samples** - _블렌드 스페이스_ 의 모든 샘플 편집가능 목록입니다. -1. **Options** - _블렌드 스페이스_ 에 대한 미리보기 옵션입니다. -1. **Graph** - 샘플을 놓고 그 블렌딩을 미리보기 위한 2D 그래프입니다. - - -## 파라미터 셋업 - -_블렌드 스페이스_ 에 대한 파라미터의 셋업은 UI 의 **파라미터** 부분에서 이루어집니다. - -![Blendspace Parameters](bs_params.png) - -[INCLUDE:Engine/Animation/Blendspaces#BlendParameters] - -각각의 블렌드 파라미터에 적합한 값을 설정한 뒤, ![Apply Parameter Changes](button_apply_changes.png) 버튼을 누르면 -_블렌드 스페이스_ 에 값이 적용되고, **그래프** 가 업데이트됩니다. - -![](BlendSpaceSetup.png) - -## 샘플 포즈 작업하기 - -[INCLUDE:Engine/Animation/Blendspaces#SampleData] - -### 샘플 추가하기 - -**애셋 브라우저** 에서 _애니메이션 시퀀스_ 를 **그래프** 에 끌어놓는 방식으로 -_블렌드 스페이스_ 에 샘플을 추가합니다. +![](LocoMotionBlendSpace.png) [REGION:note] -_에임오프셋 블렌드스페이스_ 작업을 할 때, _애니메이션 시퀀스_ 는 반드시 **Additive Anim Type** 을 -_AAT_RotationOffsetMeshSpace_ 로 설정해 둬야 샘플로 추가할 수 있습니다. +블렌드 스페이스로 여러 방향 보행 이동을 구성하는 방법 안내는 [](Engine\Animation\AnimHowTo\BlendSpace\) 문서를 참고하세요. [/REGION] -![](BlendShapeDragDrop.png)(w:720) +## 샘플 포즈 -**그래프** 내 위치에 노드가 놓입니다: +축 세팅을 정의했으니, 다음으로 해 줄 작업은 블렌드 스페이스 에디터 그리드에 샘플링해올 애니메이션을 추가하는 작업입니다. -![Sample node](bs_sample_node.png) +![](DragDropToGrid.png) -### 샘플 위치조정 +위 예제에서는 **애셋 브라우저** 에서 Idle 애니메이션을 끌어 Direction/Speed 값이 0 인 그리드 지점, 다른 말로 캐릭터가 움직이지 않는 지점에 끌어 놓았습니다. -샘플의 위치 이동은 대화식 또는 수동식으로 가능합니다. 대화식 이동은 -매우 직관적이나 수동식에 비해 정확도가 떨어집니다. +샘플 포인트에 **우클릭** 하여 메뉴를 펼치면 샘플에 조절할 수 있는 옵션이 나옵니다. -대화식 샘플 이동: +![](RightClickSamplePoint.png) -**그래프** 에서 노드를 클릭하고 끕니다: +하나의 Axis Value (위의 경우, Direction 또는 Speed)를 조절, 애니메이션 변경, **Rate Scale** 조정으로 샘플 위치를 변경할 수 있습니다. -![Move Sample by Dragging](bs_sample_move_drag.png)(convert:false) - -수동식 샘플 이동: - -노드를 클릭한 다음 노드를 위치시킬 **X**, **Y** 값을 지정합니다: - -![Move Node Manually](bs_sample_move_manual.png) - -### 샘플 대체 - -_블렌드 스페이스_ 에 놓은 샘플은 _드래그 앤 드롭_ 또는 UI 의 **샘플** 부분을 통해 다른 샘플로 -대체 가능합니다. - -드래그 앤 드롭 대체: - -**그래프** 의 샘플을 대체하려면, **애셋 브라우저** 에서 새로운 _애니메이션 시퀀스_ 를 기존 노드에 -직접 끌어다 놓습니다. - -[REGION:fullwidth] -![Replace Sample by Dragging](bs_sample_replace_drag.png)(convert:false) +[REGION:tip] +블렌드스페이스 그리드 좌상단 부분에 위치한 샘플의 수치 입력 박스를 사용해서 샘플 값을 편집할 수도 있습니다. [/REGION] -[REGION:imagetable] -| ![Original Sample](bs_sample_replace_before.png)(h:220) | ![Replaced Sample](bs_sample_replace_after.png)(w:175 h:220) | -| ------ | ------ | -| 원래 샘플 | 대체된 샘플 | -[/REGION] +펼침 메뉴에서 Axis Value 프로퍼티를 변경하여 샘플을 이동시키는 것에 추가로, 샘플을 그리드의 새 위치로 끌어 놓을 수도 있습니다. -수동식 대체: +![](MovedKey.png) -**샘플** 부분의 샘플을 대체하려면 **콘텐츠 브라우저** 에서 새로운 _애니메이션 시퀀스_ 를 선택한 다음 -목록에 있는 샘플에 대해 ![Use Selected Asset](button_use_selected.png) 버튼을 누릅니다. +그리드에서 샘플을 제거하려면, 샘플을 선택하고 **Delete** 키를 누르면 됩니다. -[REGION:note] - 이 경우 반드시 콘텐츠 브라우저에서 애니메이션 시퀀스를 선택해야 합니다. 페르소나의 **애셋 브라우저** 에서는 애셋을 선택해도 읽지 _않습니다_. -[/REGION] +드래그 앤 드롭으로 기존 샘플을 새로운 샘플로 대체할 수도 있습니다. -![Select New Animation](bs_sample_replace_manual_select.png)(convert:false) +![](ChangeSample.png) -![Replace Sample Manually](bs_sample_replace_manual.png)(convert:false) +### 블렌드 스페이스 미리보기 -### 샘플 제거 - -UI 의 **샘플** 부분을 사용하거나 아니면 **그래프** 에서 바로 샘플을 지울 수 있습니다. - -그래프에서 삭제하려면: - -**그래프** 의 Sample 노드를 선택하여 편집창을 띄운 다음 ![Delete](button_delete.png) 버튼을 눌러 -샘플을 제거합니다. - -![Remove Sample in Graph](bs_sample_remove.png)(convert:false) - -샘플 섹션에서 삭제하려면: - -목록에서 제거할 샘플에 대해 ![Remove Sample](button_clear_reference.png) 버튼을 누릅니다. - -![Remove Sample Manually](bs_sample_remove_manual.png)(convert:false) - -## 미리보기 - -포즈간의 블렌딩 결과는 **그래프** 를 사용하여 **페르소나** 의 **뷰포트** 패널에서 대화식으로 -미리볼 수 있습니다. 커서의 위치가 블렌딩을 하는 데 사용되는 **X**, **Y** 파라미터 값을 결정하며, -그 결과 포즈가 **뷰포트** 패널에 표시됩니다. - -_블렌드 스페이스_ 미리보기를 켜려면, UI 의 **옵션** 부분에서 **블렌드 스페이스 미리보기 켜기** 옵션을 -체크합니다. - -![Enable Preview Blendspace Option](bs_options_preview.png) - -미리보기를 켠 후, **그래프** 에서 커서를 움직이면 그 위치에 따라 블렌딩되는 포즈가 **뷰포트** 패널에 -표시됩니다. 커서가 들어있는 그리드 블록은 음영 표시되고, -블록을 이루는 샘플 지점 사이의 블렌딩을 나타내는 값이 표시됩니다. - -![Graph Grid Block](bs_samples_block.png) - -커서 위치와 블렌딩중인 샘플 관련 상세 정보를 확인하려면 **툴팁 표시 켜기** 옵션을 -체크하면 됩니다. - -![Enable Tooltip Display Option](bs_options_tooltip.png) - -![Graph Tooltip](bs_samples_tooltip.png) - -블렌드 스페이스 미리보기 예제는 아래와 같습니다. +그리드에 샘플 포즈를 몇 개 배치했으면, **Shift** 키를 누르고 초록 다이아몬드를 끌어 여러 포즈 사이 블렌딩을 확인할 수 있습니다. [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -L435S6VaUMY -[/PARAMLITERAL] -[/OBJECT] \ No newline at end of file + [PARAMLITERAL:videoid] + G46ZWMJHkDA + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +**Shift** 키를 누르고 있는 동안 **Ctrl** 키를 같이 누르면 미리보면서 실제 샘플 값을 표시할 수도 있습니다. + +![](ControlDownPreview.png) + +**Shift** 키를 놓으면 초록 다이아몬드가 그 위치에 남아 뷰포트의 카메라를 자유롭게 움직여 그 포즈를 다른 각도에서 확인할 수 있습니다. + +![](StickyKey.png) + + + +### 그리드 옵션 + +블렌드 스페이스 에디터 그리드 안에서는, **Show Triangulation** (트라이앵글화 표시), **Show Animation Names** (애니메이션 이름 표시) 또는 **Stretch** (스트레치) 세팅 조절도 가능합니다. + +![](GridOptionsImage.png) + +아래 비디오는 각 옵션의 효과와 다양한 실험을 통해 원하는 효과를 내는 방법을 보여주고 있습니다. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + eeiHXdHuZTo + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +## 블렌드 스페이스 애셋 디테일 + +Axis Settings (축 세팅) 및 Sample Pose (샘플 포즈) 정의가 블렌드 스페이스 구성에 있어 두 가지 핵심 요소이긴 하지만, **애셋 디테일** 패널에는 블렌드 스페이스 사용 방식을 더욱 세밀히 정의하기 위해 조절할 수 있는 다른 프로퍼티도 있습니다. + +### 입력 보간 + +이 섹션에서는 **Axis to Scale Animation** 을 정의할 수 있는데, 입력 보간이 있는 경우 애니메이션 속도 (스케일) 구동을 위한 축을 지정할 수 있으므로 유용합니다. +예를 들어 보행이동 애니메이션의 경우, 속력 축은 애니메이션 속도 (즉 스케일) 구동을 합니다. +적용 가능하지 않은 경우 이 값을 **None** (없음)으로 설정하거나, **Horizontal** (가로) 또는 **Vertical** (세로) 축으로 설정하면 됩니다. +이 옵션은 일반 블렌드 스페이스 애셋에만 사용 가능하며, 블렌드 스페이스 1D 애셋에는 사용할 수 없습니다. + +### 축 세팅 + +이 글 윗부분에 언급한 대로, 이 옵션을 통해 Horizontal 및 (일반 블렌드 스페이스의 경우 Vertical) Axis 프로퍼티를 정의하여 블렌드 스페이스를 구동시킵니다. + +[INCLUDE:#axissettings] + +[REGION:note] +그리드 분할 수나 한 축의 크기가 변경되는 경우, 기존 샘플은 가장 가까이 가능한 그리드 지점에 스냅시킵니다. +유효한 위치를 찾을 수 없는 것들은 유효하지 않은 것으로 마킹하여 그리드에서 위치를 수동 조절할 수 있도록 빨갛게 그립니다. +[/REGION] + + +### 애니메이션 + +이 섹션에는 미리보기 관련 옵션과 아울러 정보성 프로퍼티가 들어있습니다. 이 애셋에 할당된 스켈레탈 애셋은 무엇인가 하는 것들입니다. + +|애니메이션|| +|---|---| +|**Preview Pose Asset**| 프리뷰 포즈 애셋 - 이 애셋을 미리볼 때 사용할 기본 스켈레탈 메시입니다 (블렌드 스페이스 애셋을 열 때만 적용됩니다). | +|**Skeleton**| 스켈레톤 - 이 애셋을 재생시킬 수 있는 스켈레톤에 대한 포인터입니다. | +|**Parent Asset**| 부모 애셋 - 설정하면 매핑 테이블에 콘텐츠를 추가할 수 있습니다. | +|**Asset Mapping Table**| 애셋 매핑 테이블 - 부모 애셋이 설정되면, 이 애셋에 연관된 매핑을 정의할 수 있습니다. | +|**Asset User Data**| 애셋 유저 데이터 - 이 애셋에 연관된 유저 데이터 배열을 저장합니다. | + +### 샘플 보간 + +이 섹션에서는 본 단위 또는 포즈 단위 샘플 포즈 사이 보간을 부드럽게 해줄 수 있습니다. + +|샘플 보간|| +|---|---| +|**Per Bone Blend**| 본 단위 블렌드 - 본 단위 타겟 웨이트 보간을 정의합니다. 정의된 각 본 세팅마다 다른 속도로 블렌드 인 됩니다.| +|**Target Weight Interpolation Speed Per Sec**| 초당 타겟 웨이트 보간 속도 - 타겟 샘플이 설정되면, 그 타겟에 얼마나 빨리 도달할지 결정하며 블렌딩 개선이 가능합니다. | + +### 애니메이션 노티파이 + +이 섹션에서는 블렌드 스페이스에서 발동시킬 [애니메이션 노티파이](Engine/Animation/Sequences/Notifies) 를 결정하는 모드를 정의합니다. + +노티파이 트리거 모드는 다음과 같습니다: + +* **All Animations** - 모든 노티파이 이벤트가 발동됩니다. +* **Highest Weighted Animation** - 최고 웨이트 애니메이션 - 가중치가 가장 높은 애니메이션에서만 노티파이 이벤트가 발동됩니다. +* **None** - 어떤 애니메이션에서도 노티파이 이벤트가 발동되지 않습니다. + +### 메타 데이터 + +이 섹션에서는 커스텀 메타데이터를 애니메이션 애셋에 할당할 수 있습니다. `GetMetaData` 함수로 이에 대한 쿼리가 가능합니다. + +### 썸네일 + +이 섹션에서는 +**콘텐츠 브라우저** 에서 나타나는 애셋 썸네일 안의 시점을 조절할 수 있습니다. + diff --git a/Engine/Documentation/Source/Engine/Animation/Blendspaces/Overview/BlendspaceOverview.INT.udn b/Engine/Documentation/Source/Engine/Animation/Blendspaces/Overview/BlendspaceOverview.INT.udn index 60bd0ec026db..9778a41d43c3 100644 --- a/Engine/Documentation/Source/Engine/Animation/Blendspaces/Overview/BlendspaceOverview.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/Blendspaces/Overview/BlendspaceOverview.INT.udn @@ -1,18 +1,21 @@ -Availability:Docs -Title: Blend Spaces Overview +Availability: Docs Crumbs: %ROOT%, Engine, Engine/Animation +Title: Blend Spaces Overview Description:Describes how Blend Space assets are used and the different types of Blend Space assets. +Type: Overview +SkillLevel: Intermediate +Version: 4.16 +Parent: Engine/Animation +Order: 1 +tags:Animation +tags:Animation Blueprint +tags:Blend Space +topic-image:blendspacetopic.png Related: Engine\Animation\AnimHowTo\BlendSpace Related: Engine/Animation/Blendspaces/Editor Related: Engine/Animation/Blendspaces/UserGuide Related: Engine/Animation/StateMachines Related: Engine/Animation/AnimBlueprints -version: 4.15 -type:overview -topic-image:blendspacetopic.png -tags:Animation -tags:Animation Blueprint -tags:Blend Space [TOC (start:2 end:2)] @@ -45,15 +48,21 @@ As an example, take the typical blending between directional run animations and the direction and speed of the movement of the player. [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -HzgiW2mZomU -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + WhfIvH1Uxpg + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] In Unreal Engine 3, this was performed using the directional blending node in combination with a speed @@ -81,15 +90,21 @@ An example use case for a Blend Space 1D would be when you have a character that If the character cannot sidestep or move in multiple directions, a Blend Space 1D could be used to blend from an Idle to a Walk and ultimately Run based on a single **Speed** value (as shown in the example below). [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -2g_IxGNE0T4 -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + KMl7-qkgs9g + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] [REGION:note] diff --git a/Engine/Documentation/Source/Engine/Animation/Blendspaces/Overview/BlendspaceOverview.JPN.udn b/Engine/Documentation/Source/Engine/Animation/Blendspaces/Overview/BlendspaceOverview.JPN.udn index 68e43c072a06..e18150b7481e 100644 --- a/Engine/Documentation/Source/Engine/Animation/Blendspaces/Overview/BlendspaceOverview.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/Blendspaces/Overview/BlendspaceOverview.JPN.udn @@ -1,98 +1,117 @@ -INTSourceChangelist:0 +INTSourceChangelist:3477699 Availability:Docs -Title: Blend Spaces Overview Crumbs: %ROOT%, Engine, Engine/Animation -Description:Describes how Blend Space assets are used and the different types of Blend Space assets. -Related: Engine\Animation\AnimHowTo\BlendSpace -Related: Engine/Animation/Blendspaces/Editor -Related: Engine/Animation/Blendspaces/UserGuide -Related: Engine/Animation/StateMachines -Related: Engine/Animation/AnimBlueprints -version: 4.15 -type:overview -topic-image:blendspacetopic.png +Title:ブレンドスペースの概要 +Description:Blend Space アセットの使用方法とその様々なタイプについての説明 +Type:Overview +SkillLevel:Intermediate +Version:4.16 +Parent:Engine/Animation +Order:1 tags:Animation tags:Animation Blueprint tags:Blend Space +topic-image:blendspacetopic.png +Related:Engine\Animation\AnimHowTo\BlendSpace +Related:Engine/Animation/Blendspaces/Editor +Related:Engine/Animation/Blendspaces +Related:Engine/Animation/StateMachines +Related:Engine/Animation/AnimBlueprints [TOC (start:2 end:2)] -The goal of a **Blend Space** is to reduce the need for creating individual, hard-coded nodes for blending -animations with an asset that performs blending based on specific properties or conditions instead. By allowing the animator or programmer to specify -the inputs, the animations, and how the inputs are used to blend between animations, virtually any -type of blending can be performed using the generic Blend Space. +**ブレンドスペース** の目的は、特定のプロパティや条件に基づいたブレンディングを行うアセットを代わりに使うことで、 +個別にハードコード化したノードを作成する必要性を減らすことです。アニメーターやプログラマーが入力、アニメーション、およびアニメーション間でブレンドするための入力値の使用を指定できるようにすることで、 +事実上、どのようなタイプのブレンドも +汎用ブレンドスペースを使用して実行することができます。 -This is completely contrary to how AnimTrees in Unreal Engine 3 handled the same tasks. -Any complex blending required the creation of a new node to handle that blending. -Blend Spaces are completely generic allowing the factors that determine the blending to be specified on each individual Blend Space. -Each Blend Space has inputs that simply take in values. -These values can be calculated during the update cycle of an [Animation Blueprint](Engine\Animation\AnimBlueprints) (via the **EventGraph**), -driven by gameplay code, or any other means (as seen in the example chart below). This makes them extremely flexible and puts the power into -the hands of the person creating the AnimGraph to blend animations in any way they see fit. +UE3 で AnimTree を使って同じタスクを処理していた方法とは正反対です。 +複雑なブレンドを処理するには、それを行う新規ノードを作成する必要があります。 +ブレンドスペースは完全に汎用的です。各ブレンドスペースで指定するブレンドを決める係数を有効にします。 +各ブレンドスペースには値を取る入力があります。 +これらの値は [Animation ブループリント](Engine\Animation\AnimBlueprints) (**EventGraph** 経由) の更新サイクル中に計算され、 +ゲームプレイ コードやその他の方法で操作されます (以下の図参照)。これは柔軟性が高く、AnimGraph の作成者は +アニメーショがを適切に見えるようにブレンドすることができます。 ![Input Flow](bs_flow.png) [REGION:caption] -Above, the Event Graph, Gameplay Code or other factor drives each of the variables that in turn determines which pose in the Blend Space to use as the final pose. +上の図では、イベントグラフ、ゲームプレイ コード、その他のファクタがそれぞれの変数を操作して、最終ポーズとしてブレンドスペースのどのポーズを使用するかを決めます。 [/REGION] -## Blend Space +## ブレンドスペース -You can think of a Blend Space like a 2D graph with each input value along one axis and animations plotted -on the graph at various points. The blended animation is calculated by blending between the animations -on the graph based on the location designated by the current input values. -As an example, take the typical blending between directional run animations and an idle animation based on -the direction and speed of the movement of the player. +ブレンドスペースは 2D グラフのようなものと捉えることができます。 +ひとつの軸に沿った各入力値とグラフの様々な点に描画されているアニメーションがあります。ブレンドされたアニメーションは、現在の入力値で指定される位置に基づき +グラフ上のアニメーション間をブレンドすることで計算されます。 +例として、プレイヤーの動きの方向と速さに基づいた「方向性のある走りアニメーション」と「待機アニメーション」 +を考えます。 [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -HzgiW2mZomU -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + WhfIvH1Uxpg + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] -In Unreal Engine 3, this was performed using the directional blending node in combination with a speed -blending node. Each of these nodes was hard-coded to only do that specific blend. The values used to -perform the blending were hidden away in the code, so no modifications could be made to tweak the blend -except by a programmer; and if you modified the value in the code, it affected every instance of the node -in every AnimTree making use of it. This is far from ideal. +アンリアル エンジン 3 では、SpeedBlending ノードと一緒に +DirectionalBlending ノードを使用することによってこのブレンドを実行していました。こうした各ノードは、この特定のブレンドを行うためだけにハード コーディングされていました。ブレンドを行うために使われた値は、 +コードでは隠されています。そのため、プログラマ以外はブレンドを微調整する修正を加えることはできません。 +コード内の値を修正したら、それを使用するすべての AnimTree でノードのあらゆるインスタンスに +影響を与えます。これは理想とは程遠い方法です。 -With Blend Spaces, this same blend can be performed using a single Blend Space. -The direction (which is indicated in the horizontal yellow box below) and speed (indicated in the vertical yellow box below) of the player would be values passed to the Blend Space as inputs. -The animations (white diamonds below) would be set up to blend appropriately based on the values of these inputs resulting in the final pose you see (green diamond below) in-game. +ブレンドスペースを使用すれば、単一のブレンドスペースで同様のブレンドを実行することができます。 +プレイヤーの方向 (以下の横方向の黄色いボックス) と速度 (以下の縦方向の黄色いボックス) は、ブレンドスペースに入力として渡される値です。 +アニメーション (以下の白のダイヤ) は、こうした入力値に基づき適切にブレンドするようにセットアップされます。その結果、インゲームで見る (以下の緑のダイヤ) 最終ポーズになります。 ![](BlendSpaceDirection.png)(w:720) -Below, our **AnimGraph** implements the Blend Space to which we can adjust our inputs (in this case **Speed**) to drive the blending. +以下では、**AnimGraph** がブレンドを操作するために入力 (この場合、**Speed**) を調整できるブレンドスペースを実装しています。 ![](AnimGraphBlendSpace.png) -Just as in the previewer, as we adjust our input values we alter and drive the blending in our Blend Space. +プレビューアと同様に、入力値を調整するに従い、ブレンドスペースでのブレンディングが変更、操作されます。 ## Blend Space 1D -Blend Spaces can also be created in a one-dimensional format, known as a **Blend Space 1D**. These can blend between any number of poses or animations but do so based on a single input value. An example that we use is to make a character lean when sprinting. We have two poses, one leaning left and one leaning right, and use an input driven by how much the player is turning the character while sprinting. By blending into the additive leaning poses, we can give the running animation a bit more life as the character seems to lean into hard turns. +ブレンドスペースは、**Blend Space 1D** という 1D 形式でも作成できます。ブレンドスペースでは、ポーズやアニメーションをいくつでもブレンドできますが、単一の入力値に基づき、ブレンドしてください。 +Blend Space 1D の使用例としては、移動方向を自動的に向くキャラクターが考えられます。 +キャラクターが道から外れたり、複数方向に移動できない場合、単一の **Speed** 値に基づき (以下の例のように)、Blend Space 1D を使って Idle から Walk に、最終的に Run させるようにブレンドすることができます。 [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -2g_IxGNE0T4 -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + KMl7-qkgs9g + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] [REGION:note] -Aside from having only one axis instead of two, a Blend Space 1D is exactly the same as a standard two-axis Blend Space. +2 軸ではなく 1 軸だけを持つ以外は、Blend Space 1D は標準の2 軸のブレンドスペースと全く同じです。 [/REGION] + + diff --git a/Engine/Documentation/Source/Engine/Animation/Blendspaces/Overview/BlendspaceOverview.KOR.udn b/Engine/Documentation/Source/Engine/Animation/Blendspaces/Overview/BlendspaceOverview.KOR.udn new file mode 100644 index 000000000000..81601cf751b1 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Animation/Blendspaces/Overview/BlendspaceOverview.KOR.udn @@ -0,0 +1,114 @@ +INTSourceChangelist:3441237 +Availability:Docs +Title: 블렌드 스페이스 개요 +Crumbs: %ROOT%, Engine, Engine/Animation +Description:블렌드 스페이스 애셋 사용 방법 및 여러가지 블렌드 스페이스 애셋 유형에 대한 설명입니다. +Related: Engine\Animation\AnimHowTo\BlendSpace +Related: Engine/Animation/Blendspaces/Editor +Related: Engine/Animation/Blendspaces/UserGuide +Related: Engine/Animation/StateMachines +Related: Engine/Animation/AnimBlueprints +version: 4.15 +type:overview +topic-image:blendspacetopic.png +tags:Animation +tags:Animation Blueprint +tags:Blend Space + +[TOC (start:2 end:2)] + +**Blend Space** (블렌드 스페이스)의 목적은 애니메이션 블렌딩을 위해 개별 하드코딩 노드를 만들기보다는, +특정 프로퍼티 또는 조건에 따라 블렌딩을 수행하는 애셋으로 대체하기 위한 것입니다. 애니메이터 또는 프로그래머가 +입력, 애니메이션, 애니메이션 사이 블렌딩을 위한 입력 사용 방식을 지정할 수 있도록 함으로써, +사실상 어떤 유형의 블렌딩도 일반 블렌드 스페이스를 사용하여 할 수 있습니다. + +이는 언리얼 엔진 3 의 애님 트리가 같은 작업을 처리했던 것과는 완전히 상반되는 것입니다. +복잡한 블렌딩은 새로운 노드 생성을 통해 블렌딩 처리를 해줘야 했습니다. +블렌드 스페이스는 완벽히 범용이라 블렌딩을 결정하는 요소가 각각의 블렌드 스페이스에서 지정되도록 할 수 있습니다. +각 블렌드 스페이스에는 단순히 값을 받는 입력이 있습니다. +이 값은 [애니메이션 블루프린트](Engine\Animation\AnimBlueprints) (의 **이벤트 그래프** 를 통한) 업데이트 사이클 도중, 게임플레이 코드 구동, +기타 (아래 차트와 같은) 다른 수단으로도 계산 가능합니다. 이로써 매우 유연한 시스템이 가능하며, +사람이 애님 그래프를 만들어 원하는 대로 애니메이션 블렌딩을 할 수 있도록 해줍니다. + +![Input Flow](bs_flow.png) + +[REGION:caption] +위에서 이벤트 그래프나 게임플레이 코드 또는 기타 요소가 각각의 변수들을 구동시켜 블렌드 스페이스의 어떤 포즈를 최종 포즈로 사용할 것인지 결정합니다. +[/REGION] + + +## 블렌드 스페이스 + +블렌드 스페이스는 한 축에 각각의 입력 값과, 그래프 상의 다양한 지점에 애니메이션이 위치해 있는 2D 그래프로 +생각해 볼 수 있습니다. 블렌딩된 애니메이션은 현재 입력 값으로 나타낸 위치에 따라 그래프 상의 +애니메이션 사이 블렌딩을 통해 계산합니다. +플레이어의 이동 속력과 방향에 따라 방향 달리기 애니메이션과 대기 애니메이션을 블렌딩하는 +전형적인 예를 들어봅니다. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + WhfIvH1Uxpg + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +언리얼 엔진 3 에서는, 방향 블렌딩 노드에 속력 블렌딩 노드를 조합하는 식으로 가능했습니다. +이 노드 각각은 하드 코딩되어 해당 블렌딩 작업만 할 수 있었습니다. 블렌딩에 사용된 +값은 코드에 숨겨져 있으므로, 프로그래머가 아니면 블렌딩 트윅을 위한 변경 작업이 불가능했습니다. +그리고 코드에서 값을 변경했다 하더라도, 그것을 활용하는 모든 애님 트리의 해당 노드 +모든 인스턴스에 영향을 끼쳤습니다. 이상적인 것과는 거리가 멀지요. + +블렌드 스페이스로는, 이와 같은 블렌딩을 하나의 블렌드 스페이스를 사용하여 이뤄낼 수 있습니다. +플레이어의 (아래에 가로 노랑 박스로 나타난) 방향 및 (아래에 세로 노랑 박스로 나타난) 속력이 블렌드 스페이스에 입력으로 전달되는 값이 됩니다. +(아래 하양 다이아몬드인) 애니메이션은 이 입력 값에 따라 적절히 블렌딩되도록 구성되어 게임 내 (아래 초록 다이아몬드인) 최종 포즈로 나타납니다. + +![](BlendSpaceDirection.png)(w:720) + +아래에서 우리 **애님 그래프** 에서는 블렌드 스페이스를 구현, 이를 통해 블렌딩을 구동시키는 입력 (이 경우 **속력**) 을 조절할 수 있습니다. + +![](AnimGraphBlendSpace.png) + +프리뷰어에서와 마찬가지로, 입력 값을 조절하면 블렌드 스페이스의 블렌딩이 변경 및 구동됩니다. + +## 블렌드 스페이스 1D + +블렌드 스페이스는 일차원 포맷으로도 만들 수 있는데, 이를 **Blend Space 1D** (블렌드 스페이스 1D)라 합니다. 이는 포즈나 애니메이션을 몇 개든 블렌딩할 수 있으나, 단일 입력값에 따라 이루어집니다. +블렌드 스페이스 1D 의 사용 예라면, 캐릭터의 이동 방향에 맞춰 자동으로 회전을 설정하도록 하는 경우를 들 수 있습니다. +캐릭터가 횡이동 또는 여러 방향으로 이동할 수 없다면, 블렌드 스페이스 1D 를 사용하여 (아래에서 보이듯이) 하나의 **Speed** 값에 따라 걷기에서 달리기로 블렌딩시킬 수 있습니다. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + KMl7-qkgs9g + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +[REGION:note] +축이 둘이 아닌 하나라는 점만 제외하면, 블렌드 스페이스 1D 는 표준 2 축 블렌드 스페이스와 똑같습니다. +[/REGION] + + + + diff --git a/Engine/Documentation/Source/Engine/Animation/Blendspaces/UserGuide/BlendspaceUserGuide.INT.udn b/Engine/Documentation/Source/Engine/Animation/Blendspaces/UserGuide/BlendspaceUserGuide.INT.udn index 6f947c4701bf..1f556fa3cf98 100644 --- a/Engine/Documentation/Source/Engine/Animation/Blendspaces/UserGuide/BlendspaceUserGuide.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/Blendspaces/UserGuide/BlendspaceUserGuide.INT.udn @@ -1,17 +1,22 @@ -Availability:Public -Title: Using Blend Spaces +Availability: Docs Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Blendspaces +Title: Using Blend Spaces Description:Describes Blend Spaces are used within Animation Blueprints resulting in an output pose. +Type: Overview +SkillLevel: Beginner +Version: 4.16 +Parent: Engine/Animation/Blendspaces +Order: 1 +tags:Animation +tags:Animation Blueprint +tags:Blend Space +topic-image:userguidetopic.png Related: Engine\Animation\AnimHowTo\BlendSpace Related: Engine/Animation/StateMachines Related: Engine/Animation/AnimBlueprints Related: Engine/Animation/AnimBlueprints/AnimGraph -version: 4.15 -type:overview -topic-image:userguidetopic.png -tags:Animation -tags:Animation Blueprint -tags:Blend Space + +[TOC(start:2 end:2)] [EXCERPT:Intro] Blend Spaces are used by placing nodes in the **AnimGraphs** of [Animation Blueprints](Engine/Animation/AnimBlueprints) which take in value data to drive the blending of animations and the final animation pose. @@ -21,9 +26,6 @@ Blend Spaces are used by placing nodes in the **AnimGraphs** of [Animation Bluep For a full walk-through of setting up a Blend Space for locomotion blending, see the [](Engine\Animation\AnimHowTo\BlendSpace) how-to page. [/REGION] - -[TOC(start:2)] - ## Adding Blend Space Nodes Blend Space nodes provide access to the sample parameter data and output pose of the Blend Space. @@ -34,22 +36,22 @@ Blend Space nodes provide access to the sample parameter data and output pose of ![](SelectBlendSpace.png) -1. **Left-click** on it and drag the mouse into the **AnimGraph**. +1. Left-click on it and drag the mouse into the **AnimGraph**. ![](DragDropBlendSpace.png)(w:720) -1. Release the **Left Mouse Button** to place the Blend Space node in the graph. +1. Release the **Left Mouse Button** to place the **Blend Space** node in the graph. ![](BlendSpaceNodeAdded.png) **To place a Blend Space node using the context menu:** -1. **Right-click** in the **AnimGraph** and expand **Blend Spaces** and select the Blend Space you want to sample. +1. Right-click in the **AnimGraph** and expand **Blend Spaces** and select the **Blend Space** you want to sample. ![](AnimationContextMenu.png) -1. The Blend Space node is placed in the graph. +1. The **Blend Space** node is placed in the graph. ![](BlendSpaceNodeAdded.png) @@ -80,3 +82,4 @@ Or, it can be wired to any other input pin that accepts an animation pose as an ![Output Pose - Blend](bs_output_blend.png) + diff --git a/Engine/Documentation/Source/Engine/Animation/Blendspaces/UserGuide/BlendspaceUserGuide.JPN.udn b/Engine/Documentation/Source/Engine/Animation/Blendspaces/UserGuide/BlendspaceUserGuide.JPN.udn index 8c25b7af2522..f1190ac7e6b0 100644 --- a/Engine/Documentation/Source/Engine/Animation/Blendspaces/UserGuide/BlendspaceUserGuide.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/Blendspaces/UserGuide/BlendspaceUserGuide.JPN.udn @@ -1,93 +1,86 @@ -INTSourceChangelist:2663375 -Availability:Public -Title:Blend Space の使用方法 +INTSourceChangelist:3477699 +Availability:Docs Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Blendspaces -Description:Animation ブループリントの Blend Space を使用してアニメーション ポーズのデータを入力しサンプルを出力するためのガイド -version: 4.9 - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Animation/Blendspaces/UserGuide:title%](Engine/Animation/Blendspaces/Using.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Animation/Blendspaces/UserGuide:title% - [/PARAM] - [PARAM:description] - %Engine/Animation/Blendspaces/UserGuide:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Animation/Blendspaces/UserGuide] - [/PARAM] -[/OBJECT] -[/VAR] - -[TOC(start:2)] +Title:ブレンドスペースの使用方法 +Description:Animation ブループリント内でブレンドスペースを使って出力ポーズを作ります。 +Type:Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Animation/Blendspaces +Order:1 +tags:Animation +tags:Animation Blueprint +tags:Blend Space +topic-image:userguidetopic.png +Related:Engine\Animation\AnimHowTo\BlendSpace +Related:Engine/Animation/StateMachines +Related:Engine/Animation/AnimBlueprints +Related:Engine/Animation/AnimBlueprints/AnimGraph +[TOC(start:2 end:2)] [EXCERPT:Intro] -Blendspace は Animation ブループリントの _AnimGraphs_ にノードを設置して使用します。これらのノードは、最終的にブレンドしたポーズを Blend Space が作成するために使うアニメーションを操作するための値を受け取ります。 +ブレンドスペースは、[Animation ブループリント](Engine/Animation/AnimBlueprints) の **AnimGraphs** にノードを配置して使用します。Animation ブループリントは、アニメーションのブレンドと最終アニメーション ポーズを操作する値のデータを取り込みます。 [/EXCERPT:Intro] +[REGION:note] +ロコモーションのブレンド用にブレンドスペースをセットアップする手順の説明については、[](Engine\Animation\AnimHowTo\BlendSpace) の操作ガイドをご覧ください。 +[/REGION] + ##Blend Space ノードの追加 Blendspace ノードは、サンプルのパラメータ データへのアクセスと Blendspace のポーズの出力をします。 -ドラッグ&ドロップ操作で BlendSpace ノードを設置する +**ドラッグ&ドロップを使用して BlendSpace ノードを配置する** -1. **ペルソナ** の **アセット ブラウザ** で、サンプル化したい Blend Space を 探します。 +1. **Animation ブループリント** の [](Engine/Animation/AnimBlueprints/AnimGraph) で、**アセット ブラウザ** でサンプリングするブレンドスペースを探します。 ![](SelectBlendSpace.png) -1. その上で **左クリック** をして、マウスを **AnimGraph** へドラッグします。 +1. その上で左クリックをして、マウスを AnimGraph** へドラッグします。 ![](DragDropBlendSpace.png)(w:720) -1. **マウスの左ボタン** をリリースして、BlendSpace ノードを設置します。 +1. グラフ内で **マウスの左ボタン** をリリースして、**BlendSpace** ノードを配置します。 ![](BlendSpaceNodeAdded.png) **コンテキスト メニューを使用して BlendSpace ノードを設置する** -1. **AnimGraph** を **右クリック** をして、**Animation** を展開して、互換性のある全てのBlend Space をリスト表示します。 +1. **AnimGraph** で右クリックして、**Blend Spaces (ブレンドスペース)** を展開し、サンプリングする **ブレンドスペース** を選択します。 ![](AnimationContextMenu.png) -1. サンプル化したい Blend Space をクリックします。 - - ![](BlendSpaceContextSelection.png) - -1. BlendSpace ノードが設置されました。 +1. **BlendSpace** ノードがグラフに配置されました。 ![](BlendSpaceNodeAdded.png) -##データを入力する +## サンプリングのパラメータ -アニメーションのブレンドを実行するために、Blend Space はサンプル パラメータに渡されたデータに依存します。それぞれの BlendSpace ノードには、それぞれのサンプル パラメータに対する入力データ ピンがあります。他のノードからの変数もしくは出力をワイヤーで接続して、BlendSpace へ必要なデータを渡すことができます。 +アニメーションのブレンドを実行するために、Blend Space はサンプル パラメータに渡されたデータに依存します。 +それぞれの BlendSpace ノードには、それぞれのサンプル パラメータに対する入力データ ピンがあります。これは、[](Engine\Animation\Blendspaces\Editor) プロセス中に作成されます。 +他のノードからの変数もしくは出力をこうしたピンに接続して、BlendSpace へ必要なデータを渡し、サンプル ポーズのブレンドを操作することができます。 ![Variable Input Data](bs_input_variables.png) -[REGION:note] -BlendSpace の編集に使用できる入力ピンは現在 2 つまでに制限されています。3 つ目の入力ピンは使用できません。 -[/REGION] +Blend Space に渡される値は、通常は **EventGraph** での更新サイクル中に計算された変数、またはゲームプレイコードで計算された変数です。 -Blend Space に渡される値は、通常は **EventGraph** での更新サイクル中に計算された変数、またはゲームプレイコードで計算された変数です。以下は、Animation ブループリントの **EventGraph** で計算された Direction 変数と Speed 変数の例です。 - -[REGION:fullwidth] ![Variable Input Data - Update Cycle](bs_input_calc.png) + +[REGION:caption] +上の図は、Animation ブループリントの **EventGraph** で計算された Direction 変数と Speed 変数の例です。 [/REGION] ## 出力ポーズ -最も簡単なケースでは、Blend Space ノードの **Pose** を出力するピンを、 **AnimGraph** で **Result** ノードの **Pose** 入力ピンへワイヤーを伸ばすことができます。 +最も簡単なケースでは、Blend Space ノードの **Pose** を出力するピンを、 **AnimGraph** で **Result** ノードの **Pose** 入力ピンに接続します。 ![Output Pose - Result](bs_output_result.png) -より複雑なアニメーション チェーンが必要とされる場合、アニメーション ポーズを入力として受け取る他の入力ピンと線で結ぶことも出来ます。 +より複雑なアニメーション チェーンが必要とされる場合、アニメーション ポーズを入力として受け取る他の入力ピンに接続することもできます。 ![Output Pose - Blend](bs_output_blend.png) + + diff --git a/Engine/Documentation/Source/Engine/Animation/Blendspaces/UserGuide/BlendspaceUserGuide.KOR.udn b/Engine/Documentation/Source/Engine/Animation/Blendspaces/UserGuide/BlendspaceUserGuide.KOR.udn index 6cd709d5b2dd..7e3011c699a4 100644 --- a/Engine/Documentation/Source/Engine/Animation/Blendspaces/UserGuide/BlendspaceUserGuide.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/Blendspaces/UserGuide/BlendspaceUserGuide.KOR.udn @@ -1,44 +1,37 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3358386 Availability:Public Title: 블렌드 스페이스 사용하기 Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Blendspaces -Description:애니메이션 블루프린트 애셋에서 블렌드 스페이스를 사용하여 데이터를 입력하고 애니메이션 포즈 출력 샘플을 뽑는 법 안내서입니다. -version: 4.9 - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Animation/Blendspaces/UserGuide:title%](Engine/Animation/Blendspaces/Using.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Animation/Blendspaces/UserGuide:title% - [/PARAM] - [PARAM:description] - %Engine/Animation/Blendspaces/UserGuide:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Animation/Blendspaces/UserGuide] - [/PARAM] -[/OBJECT] -[/VAR] - -[TOC(start:2)] - +Description:Describes Blend Spaces are used within Animation Blueprints resulting in an output pose. +Related: Engine\Animation\AnimHowTo\BlendSpace +Related: Engine/Animation/StateMachines +Related: Engine/Animation/AnimBlueprints +Related: Engine/Animation/AnimBlueprints/AnimGraph +version: 4.15 +type:overview +topic-image:userguidetopic.png +tags:Animation +tags:Animation Blueprint +tags:Blend Space [EXCERPT:Intro] -Blend Space (블렌드 스페이스)는 애니메이션 블루프린트의 AnimGraph (애님 그래프)에 노드를 배치하는 방식으로 사용됩니다. 이 노드는 블렌드 스페이스가 최종 블렌딩 포즈를 만드는 데 사용되는 애니메이션을 결정하는 데이터를 받습니다. +Blend Space (블렌드 스페이스)는 [애니메이션 블루프린트](Engine/Animation/AnimBlueprints) 의 AnimGraph (애님 그래프)에 노드를 배치하는 방식으로 사용됩니다. 이 노드는 값 데이터를 받아 애니메이션 블렌딩 및 최종 애니메이션 포즈를 구동합니다. [/EXCERPT:Intro] +[REGION:note] +보행이동 블렌딩용 블렌드 스페이스 구성 안내는 [](Engine\Animation\AnimHowTo\BlendSpace) 문서를 참고하세요. +[/REGION] + + +[TOC(start:2)] + ## 블렌드 스페이스 노드 추가하기 블렌드 스페이스 노드는 샘플 파라미터 데이터에 대한 접근과 블렌드 스페이스의 포즈 출력을 제공합니다. **드래그 앤 드롭으로 블렌드 스페이스 노드 놓기:** -1. 애님블루프린트 에디터에서, 샘플링하려는 블렌드 스페이스를 **애셋 브라우저** 에서 찾습니다. +1. **애니메이션 블루프린트** 의 [](Engine/Animation/AnimBlueprints/AnimGraph) 내 **애셋 브라우저** 에서 샘플링하려는 블렌드 스페이스를 찾습니다. ![](SelectBlendSpace.png) @@ -46,40 +39,36 @@ Blend Space (블렌드 스페이스)는 애니메이션 블루프린트의 AnimG ![](DragDropBlendSpace.png)(w:720) -1. 왼쪽 마우스 버튼을 놓아 블렌드 스페이스를 놓습니다. +1. 왼쪽 마우스 버튼을 놓아 그래프에 블렌드 스페이스를 놓습니다. ![](BlendSpaceNodeAdded.png) **맥락 메뉴로 블렌드 스페이스 노드 놓기:** -1. 애님그래프에 우클릭한 후 **Animation** 을 펼쳐 호환 블렌드 스페이스 목록을 전부 확인합니다. +1. **애님 그래프** 에 **우클릭** 하고 **블렌드 스페이스** 를 펼쳐 샘플링하고자 하는 블렌드 스페이스를 선택합니다. ![](AnimationContextMenu.png) -1. 샘플링하려는 블렌드 스페이스에 클릭합니다. - - ![](BlendSpaceContextSelection.png) - -1. 블렌드 스페이스 노드가 놓입니다. +1. 그래프에 블렌드 스페이스 노드가 배치됩니다. ![](BlendSpaceNodeAdded.png) -## 데이터 입력하기 +## 파라미터 샘플링 -블렌드 스페이스는 샘플 파라미터에 전달되는 데이터에 의존하여 애니메이션 블렌딩을 합니다. 각 블렌드 스페이스 노드에는 각 샘플 파라미터에 대한 입력 데이터 핀이 있습니다. 다른 노드에서의 변수나 출력을 이 핀에 연결하여 블렌드 스페이스에 필요한 데이터를 전해줄 수 있습니다. +블렌드 스페이스는 샘플 파라미터에 전달되는 데이터에 의존하여 애니메이션 블렌딩을 합니다. +각 블렌드 스페이스 노드에는 [](Engine\Animation\Blendspaces\Editor) 프로세스 도중 생성되는 각 샘플 파라미터에 대한 입력 데이터 핀이 있습니다. +다른 노드에서의 변수나 출력을 이 핀에 연결하여 블렌드 스페이스에 필요한 데이터를 전해주고 샘플 포즈 블렌딩을 구동시킬 수 있습니다. -![변수 입력 데이터](bs_input_variables.png) +![Variable Input Data](bs_input_variables.png) -[REGION:note] -블렌드 스페이스 편집은 현재 사용할 수 있는 입력이 두 개로 제한되어 있어서, 셋째 입력 핀은 사용되지 않습니다. -[/REGION] +블렌드 스페이스로 전달되는 값은 보통 이벤트그래프의 업데이트 사이클 도중이나 게임플레이 코드를 통해 계산되는 변수입니다. -블렌드 스페이스로 전달되는 값은 보통 이벤트그래프의 업데이트 사이클 도중이나 게임플레이 코드를 통해 계산되는 변수입니다. 애니메이션 블루프린트의 이벤트그래프 안에서 계산되고 있는 Direction 과 Speed 변수 예제는 아래와 같습니다. - -[REGION:fullwidth] ![Variable Input Data - Update Cycle](bs_input_calc.png) + +[REGION:caption] +애니메이션 블루프린트의 **이벤트 그래프** 안에서 계산되고 있는 Direction 과 Speed 변수 예제는 위와 같습니다. [/REGION] ## 출력 포즈 diff --git a/Engine/Documentation/Source/Engine/Animation/CharacterSetupOverview/CharacterSetupOverview.INT.udn b/Engine/Documentation/Source/Engine/Animation/CharacterSetupOverview/CharacterSetupOverview.INT.udn index b0b30634228e..939135a36644 100644 --- a/Engine/Documentation/Source/Engine/Animation/CharacterSetupOverview/CharacterSetupOverview.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/CharacterSetupOverview/CharacterSetupOverview.INT.udn @@ -11,6 +11,7 @@ Related: Engine/Animation/AnimBlueprints/EventGraph Related: Engine/Animation/StateMachines Related: Gameplay/AI version: 4.9 +topic-image:SettingUpACharacter_topic.png [REGION:fullwidth] ![](Character.png) diff --git a/Engine/Documentation/Source/Engine/Animation/CharacterSetupOverview/CharacterSetupOverview.JPN.udn b/Engine/Documentation/Source/Engine/Animation/CharacterSetupOverview/CharacterSetupOverview.JPN.udn index 59323489ad54..756313a1d55b 100644 --- a/Engine/Documentation/Source/Engine/Animation/CharacterSetupOverview/CharacterSetupOverview.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/CharacterSetupOverview/CharacterSetupOverview.JPN.udn @@ -1,16 +1,18 @@ -Availability:Public -Title:キャラクターの設定 +INTSourceChangelist:3467293 +Availability:Public +Title:キャラクターのセットアップ Crumbs: %ROOT%, Engine, Engine/Animation Description:UE4 で基本的なキャラクターやスケルタルメッシュをセットアップする方法の概要。 -Related: Engine/Content/FBX/Animations -Related: Engine/Content/Types/SkeletalMeshes -Related: Engine/Animation/PhysicallyDrivenAnimation -Related: Engine/Content/Tools/MayaRiggingTool -Related: Engine/Animation/AnimBlueprints -Related: Engine/Animation/AnimBlueprints/EventGraph -Related: Engine/Animation/StateMachines -Related: Gameplay/AI +Related:Engine/Content/FBX/Animations +Related:Engine/Content/Types/SkeletalMeshes +Related:Engine/Animation/PhysicallyDrivenAnimation +Related:Engine/Content/Tools/MayaRiggingTool +Related:Engine/Animation/AnimBlueprints +Related:Engine/Animation/AnimBlueprints/EventGraph +Related:Engine/Animation/StateMachines +Related:Gameplay/AI version:4.9 +topic-image:SettingUpACharacter_topic.png [REGION:fullwidth] ![](Character.png) @@ -20,10 +22,10 @@ version:4.9 -ゲームのプロジェクトやジャンルが何であれ、ある時点でアニメートされたキャラクターを自分の環境で動かす必要が生じることでしょう。これは、プレイヤーが制御するキャラクターであったり、何らかの方法でワールドとインタラクションする AI 駆動のエンティティであったりします。とにかく、ワールドで適切にアニメートできるように、こうしたキャラクターをセットアップする方法を理解する必要があります。このドキュメントの目的は、そうした方法の概要を示すことにあり、個々の詳細については専門的ドキュメントとサンプルをご紹介します。今回は、何らかの方法でプレイヤーが制御可能なキャラクターを作成することを想定します。 +ゲームのプロジェクトやジャンルが何であれ、どこかの時点で背景を動き回るアニメートされたキャラクターが必要になるでしょう。これは、プレイヤーが制御するキャラクターだったり、何らかの方法でワールドとインタラクションする AI 駆動のエンティティの場合があります。とにかく、ワールドで適切にアニメートできるように、こうしたキャラクターをセットアップする方法を理解する必要があります。このドキュメントの目的は、そうした方法の概要を示すことです。個々の詳細については専門的ドキュメントとサンプルをご紹介します。ここでは、プレイヤーが何らかの制御をするキャラクターを作ります。 [REGION:note] -このドキュメント全体を通して、ブループリントで実行可能な様々なスクリプト処理を参照します。ブループリントで行えることは、C++ でも可能です。したがって、ブループリントのビジュアル スクリプト処理にとらわれる必要はありません。このドキュメントの最後のセクションには、C++ とブループリントの両方のセットアップを示すコンテンツ サンプルへの参照を掲載します。 +このドキュメントでは、ブループリントを使って可能な様々なスクリプティング操作を参照します。ブループリントで可能なことは、C++ でも可能です。ブループリント ビジュアル スクリプティングだけを使用することにこだわる必要はありません。最後のセクションでは、C++ とブループリントの両方のセットアップを示すコンテンツ サンプルへの参照を掲載します。 [/REGION] [REGION:tip] @@ -36,9 +38,9 @@ Playable Owen Character の例が、セクション 1.10 の [アニメーショ 以下は、UE4 でキャラクターをセットアップするための主なワークフローです。 1. 3ds Max や Maya などのサードパーティーのデジタル コンテンツ クリエーション (DCC) パッケージを使用してアセット (スケルタルメッシュ) やアニメーションを作成します。 -1. スケルタルメッシュやアニメーションを UE 4 にインポートします。新規スケルタルメッシュに対して新規スケルトン アセットを作成する、または同一または類似のスケルタルメッシュに対して既存のスケルトン アセットを再利用します。 -1. プレイヤーからの入力を処理するために PlayerController スクリプトまたはブループリントを作成します。 -1. キャラクターやポーンのスクリプト、またはブループリントを作成してキャラクターの実際の動き (骨格アニメーションではなく) の入力と制御をパースします。 +1. スケルタルメッシュやアニメーションを UE4 にインポートします。新規スケルタルメッシュに対して新規スケルトン アセットを作成する、または同一または類似のスケルタルメッシュに対して既存のスケルトン アセットを再利用します。 +1. プレイヤーからの入力を処理するには、PlayerController スクリプトまたはブループリントを作成します。 +1. キャラクターやポーンのスクリプト、またはブループリントを作成して入力をパースして、キャラクターの実際の動き (骨格アニメーションではなく) を制御します。 1. キャラクターの Animation ブループリントを構築します。 1. カスタムの PlayerController とその他のカスタム スクリプト アセットを利用した GameMode スクリプトまたはブループリントを作成します。 1. ゲームをプレイしてください。 @@ -49,27 +51,27 @@ Playable Owen Character の例が、セクション 1.10 の [アニメーショ ![](ArtAssets.png)(w:600) -多くの点でアート アセットを作成することはキャラクター開発工程で最も困難な部分になることでしょう。一般的に、アンリアル エンジンに実際に触れる以前に、デザイン、モデリング、表面処理、リグ構築、アニメーションにかなりの時間を費やす必要があります。キャラクターのデザインやアニメーションの微妙な感覚の違いまではお伝えできませんが、こうした工程を支援するツールは実際に用意してあります。 +色々な意味で、アート アセット作成は、キャラクターの制作プロセスで最も難しい部分です。一般的に、アンリアル エンジンに実際に触れる以前に、デザイン、モデリング、表面処理、リグ構築、アニメーションにかなりの時間を費やす必要があります。キャラクターのデザインやアニメーションの微妙な感覚の違いまではお伝えできませんが、こうした工程を支援するツールは実際に用意してあります。 -### Maya リギング ツール +### Maya のリグ構築ツール -エピック ゲームズ社内では、アニメーション アーティストの多くが、Maya を使用してキャラクターをアニメートしています。そのため、我々のチームはリグ工程を単純化する高度なリグ構築ツールを開発し、数時間かかっていた作業を数分に減らしました。 +エピック ゲームズ社内では、アニメーション アーティストの多くが、Maya を使用してキャラクターをアニメートしています。そのため、リグ プロセスを簡素化する高度なリグ構築ツールを開発して、数時間かかっていたものを数分まで時間短縮しました。 [INCLUDE:Engine/Content/Tools/MayaRiggingTool#intro] -詳細は [](Engine/Content\Tools\MayaRiggingTool) のドキュメントを参照してください。 +詳細は、[](Engine/Content\Tools\MayaRiggingTool) ドキュメントをご覧ください。 -##スケルタル メッシュをインポートする +##スケルタルメッシュをインポートする ![](CharacterViewport.png)(w:400) [INCLUDE:Engine/Content/FBX#intro] -詳細は [](Engine/Content\FBX) と[](Engine/Content\Types\SkeletalMeshes) のドキュメントを参照してください。 +詳細は [](Engine/Content\FBX) と [](Engine/Content\Types\SkeletalMeshes) のドキュメントをご覧ください。 -スケルタルメッシュを UE4 に適切にインポートすることは、アニメートしたキャラクターを作成するうえで不可欠な手順です。アンリアルにはインポート プロセスを高速化するための様々なオプションを備えた堅牢なインポート システムがあります。 +スケルタルメッシュを UE4 に適切にインポートすることは、アニメートしたキャラクターを作成するうえで重要なステップです。アンリアル エンジンには、インポート プロセスを高速化する様々なオプションを持つ堅牢なインポート システムがあります。 FBX ファイルのインポートに関する詳細は [](Engine/Content\FBX\ImportOptions) をご覧ください。 @@ -77,40 +79,40 @@ FBX ファイルのインポートに関する詳細は [](Engine/Content\FBX\Im ![](PlayerController.png) -Player Controller はプレイヤーからの入力をパースし、キャラクターを動かすイベントにすることを主な目的とする特殊なタイプのスクリプトまたはブループリントです。たとえば、コントローラ上のアナログ スティックを上方向に動かすことによって、画面上でキャラクターを前方向に押し出すために最終的に使用されるイベントを発生させるように制御できます。 +Player Controller はプレイヤーからの入力をパースし、キャラクターを動かすイベントにすることを主な目的とする特殊なタイプのスクリプトまたはブループリントです。例えば、コントローラーのアナログ スティックを上方に動かすとイベントを発生させて、それがキャラクターを画面上で前進させるように制御します。 PlayerController はアンリアル内に既に存在するクラスです。エディタでは、PlayerController を親クラスとして新規ブループリントを作成できます。その後、これを使用してプレイヤーからの入力で発生する独自のイベントをセットアップできます。 たとえば、カスタムのブループリント、PlayerController では、エディタ内で新規プロジェクトを開始し(**File > New Project**)、**Blueprint Top Down** テンプレートをチェックアウトします。ブループリント ベースのテンプレートはすべて何らかの PlayerController (デフォルトの Player Controller または Player Controller Blueprint) を含みます。しかし、Player Controller を使用したカスタム アプリケーションを見たい場合は、**Blueprint Top Down** テンプレートが最も簡単です。 -新規プロジェクト内では、**クラスビューア** のフィルタをオフにして、**クラスビューア** で PlayerController を検索することができます。このアセットを **ダブルクリック** するとアセットが開き、自分のセットアップを見ることができます。 +新規プロジェクト内では、**クラスビューア** のフィルタをオフにして、**クラスビューア** で PlayerController を検索することができます。このアセットを **ダブルクリック** するとアセットが開き、ご自分のセットアップを見ることができます。 -新規プロジェクトを作成し(**File > New Project** の順序で)、**C++ Top Down** テンプレートを選択することで、PlayerController を C++ スクリプトで見ることもできます。 +新規プロジェクトを作成し (**File > New Project** の順序で)、**C++ Top Down** テンプレートを選択することで、PlayerController を C++ スクリプトで見ることもできます。 ## Pawn または Character ブループリントを作成する ![](CharacterBP.png)(w:600) -PlayerController をセットアップしたら、システムはプレイヤーからの入力を処理する用意が整います。しかし、こうした入力を画面上でキャラクターを動かすことができるものに変換する必要があります。つまり、こうした入力をアクションに変換する (すなわちパースする) 必要があります。ここで、Pawn クラスまたは Character クラスが関わってきます。 +PlayerController をセットアップしたら、システムはプレイヤーからの入力を処理する用意が整います。しかし、こうした入力を画面上でキャラクターを動かすことができるものに変換する必要があります。つまり、こうした入力をアクションに変換する (すなわちパースする) 必要があります。ここで Pawn クラスまたは Character クラスが関わってきます。 -### ポーンまたはキャラクターを選択する +### Pawn または Character を選択する -ここでは以下の 2 つのクラスについて説明します。Pawn と Character の 2 つです。この 2 つは両方とも、プレイヤーまたはインゲームの AI によって制御されるゲーム内のエンティティに対して使用されます。主な違いは、Character クラスは、Pawn クラスの拡張であり、プレイヤーの物理面、特定メッシュのサポート、プレイ可能なインゲームのキャラクターを作成する際に必要な処理の一般的なタイプを追加します。今回は、Character クラスを使用します。シーン周囲でたとえば AI によって動かす必要がある単純なエレメントでは、一般的に Pawn の使用で対処できます。 +ここでは Pawn または Character の 2 つのクラスがあります。この 2 つは両方とも、プレイヤーまたはインゲームの AI によって制御されるゲーム内のエンティティに対して使用されます。主な違いは、Character クラスは、Pawn クラスの拡張であり、プレイヤーの物理面、特定メッシュのサポート、プレイ可能なインゲームのキャラクターを作成する際に必要な処理の一般的なタイプを追加します。ここでは、Character クラスを使用します。AI によってシーン内を動くようにする単純なエレメントでは、一般的にポーンを使用する必要はありません。 ### Character クラスのセットアップ ![](CharacterBPGraph.png)(w:800) -Character クラスは PlayerController からトリガーされるイベントで開始し、スクリプト (ブループリントのビジュアル スクリプト処理を含む) を使用し、こうした入力で実際に何を行うか、キャラクターを制御するためにどのように入力を使用するかを制御します。たとえば、PlayerController がコントローラー上のアナログ スティックを上方向に移動する基本イベントを作成します。Character クラスはそのイベントを受け取り、それを使用してキャラクターを前方向に動かすことに関与します。 +Character クラスは PlayerController からトリガーされるイベントで開始し、スクリプト (ブループリントのビジュアル スクリプト処理を含む) を使用し、こうした入力で実際に何を行うか、キャラクターを制御するためにどのように入力を使用するかを制御します。例えば、PlayerController はコントローラー上でアナログ スティックを上方向に動かす基本的なイベントを作成する場合、Character クラスがそのイベントを受け取り、それを使ってキャラクターを前方向に動かします。 -Character クラスは、ゲームプレイ中にプレイヤーが見るものの基本となるスケルタルメッシュへの参照も保持します。一人称視点のゲームの場合、これは多くの場合、単に宙に浮いているアームですが、フルボディが背景に適切にシャドウをおとす必要があればボディ全体の場合もあります。三人称視点のゲームの場合、メッシュはキャラクターを表すスケルタルメッシュになります。 +Character クラスは、ゲームプレイ中にプレイヤーが目にする物の基本となるスケルタルメッシュへの参照も保持します。一人称視点のゲームの場合、これは多くの場合、単に宙に浮いているアームですが、フルボディが背景に適切にシャドウをおとす必要があればボディ全体の場合もあります。三人称視点のゲームの場合、メッシュはキャラクターを表現するスケルタルメッシュになります。 -キャラクターの動きは一般的に物理形状 (通常はカプセル) に何らかの動きを適用して処理されます。この動きは MovementMode とも一致します。これはキャラクターが何を行っているか (ウォーキング、ランニング、落下、水泳など) を追跡するために使用する列挙型変数です。 この情報は、スケルタルメッシュで何のアニメーションが再生されるかを操作するために後で使用されます。 +キャラクターの動きは一般的に何らかの動きを物理形状 (通常はカプセル) に適用することによって処理されます。この動きは MovementMode とも一致します。これはキャラクターが何をしているかを追跡するために使用する数値です (すなわち、歩く、走る、落下する、泳ぐなど)。この情報はスケルタルメッシュでどのアニメーションを再生するかを操作するために使われます。 カスタムのブループリント Character クラスの場合、新規プロジェクトをエディタ内で開始し (**File > New Project**)、次に、First Person または Third Person のいずれかの Blueprint テンプレートを選択します。すべてのブループリント ベースのテンプレートには、何らかのキャラクターが含まれます。しかし、First Person または Third Person のいずれかのブループリント テンプレートをお勧めしています。これは、全体的に単純であることと、こうしたジャンルが一般的に使用されているためです。 -新規プロジェクト内では、**クラスビューア** で Character を検索し、ゲーム フォルダ内では、ブループリントでフィルタリングできます。このアセットを **ダブルクリック** するとアセットが開き、自分のセットアップを見ることができます。 +新規プロジェクト内で、**クラスビューア** で Character を検索し、ゲーム フォルダ内で、ブループリントでフィルタリングできます。このアセットを **ダブルクリック** するとアセットが開き、ご自分のセットアップを見ることができます。 新規プロジェクトを作成し(**File > New Project**)、First Person Code テンプレートまたはThird Person Code テンプレートを選択することで、Character を C++ スクリプトで見ることもできます。 @@ -119,7 +121,7 @@ Character クラスは、ゲームプレイ中にプレイヤーが見るもの ![](AnimBP.png)(w:600) -アニメーションをキャラクターと連携させるほとんどの煩雑な作業を Animation ブループリントで行います。 +アニメーションをキャラクターと連携させるほとんどの煩雑な作業は Animation ブループリントで行います。 Skeletal Mesh アクタがワールドでどのように動くかを Character ブループリントで定義したら、Animation ブループリントでこうした動き (速度など) に基づいて特定のアニメーションの割り当てを開始できます。 @@ -139,15 +141,15 @@ Animation ブループリントは、キャラクターのセットアップで ![](GameMode.png) -GameMode は、ゲームを定義するために使用する特殊タイプのクラスです。一般的に、ゲームの必須クラスがどのようなものになるかを定義するために使用するプロパティを単に集めたものになります。セットアップする主なプロパティは以下のようになります。 +GameMode はゲームを定義するために使う特殊なクラスです。一般的に、ゲームの必須クラスがどのようなものになるかを定義するために使用するプロパティを単に集めたものになります。以下はセットアップする主なプロパティです。 -* **Default Pawn Class** - これは、インゲームのキャラクターに対してセットアップする Character クラスを保持します。 -* **HUD Class** - 作成された特殊なヘッドアップ ディスプレイ (HUD) を含みますが、本ドキュメントでは取り上げません。 -* **PlayerController Class** - インゲームのキャラクターに対してセットアップしたカスタムの PlayerController を保持します。 +* **Default Pawn Class** - インゲームのキャラクターに対してセットアップする Character クラスを保持します。 +* **HUD Class** - これは作成される特殊なヘッドアップ ディスプレイ (HUD) ですが、このドキュメントでは扱いません。 +* **PlayerController Class** - インゲームのキャラクターでセットアップしたカスタムの PlayerController を保持します。 * **Spectator Class** - アクションを見ているだけのスペクテーター (観戦者) すなわち受動的プレイヤーを制御するために使用する特殊なクラスを保持します。これらは本ドキュメントでは取り上げません。 * **Replay Spectator Class** - 再生中にスペクテーター (観戦者) を制御するために使用する特殊なクラスを保持します。これらは本ドキュメントでは取り上げません。 -* **Game State Class** - このクラスは、ゲームをどのようにプレイするかについての特殊なルールやセットアップを制御しますが、本ドキュメントでは扱いません。 -* **Player State Class** - このクラスでは関連するプレイヤー情報をすべてのクライアントにレプリケートするための特殊なルールがあれば定義します。 +* **Game State Class** - ゲームをどのようにプレイするかに関する特殊なルールやセットアップを制御しますが、本ドキュメントでは取り上げません。 +* **Player State Class** - 関連するプレイヤー情報をすべてのクライアントに複製するための特殊なルールを定義します。 キャラクターをテストするには、最低限デフォルトの Pawn クラスと PlayerController クラスのプロパティをセットアップする必要があります。 @@ -157,24 +159,24 @@ GameMode は、ゲームを定義するために使用する特殊タイプの GameMode を設定したら、カスタムのキャラクターとプレイできるようにする最後のステップでは、現在のレベルが GameMode を使用していることを確認します。この確認は、 **[World Settings]** タブを使用して行います。このタブは、メイン ツールバーの上にある **[Settings]** ボタンからアクセスできます。 - **[World Settings]** 内で **GameMode Override** を自分の GameMode のクラス名に設定したことを確認します。確認したら、新しいキャラクターを保存し、テストする用意が整います。 +**[World Settings]** 内で **GameMode Override** を自分の GameMode のクラス名に設定したことを確認します。確認したら、新しいキャラクターを保存し、テストする用意が整います。 ![](GameModeSettings.png) -##概要 +## 概要 -セットアップ、バックアップのフローの流れを要約すると以下のようになります。 +セットアップのフローの概要は以下のとおりです。 -* レベルのワールド設定を使用して、どの GameMode を使用するかを設定します。 -* GameMode では、どの Pawn (Character) クラスとどの PlayerController クラスでゲームをプレイする必要があるかを指定します。 -* Character クラス +* Level の World Settings を使って、どの GameMode を使用するかを設定します。 +* GameMode はどの Pawn (Character) クラスおよびどの PlayerController クラスがゲームをプレイするために必要であるかを指定します。 +* Character クラス: * FBX 経由でインポートしたスケルタルメッシュを含むようにします。 * PlayerController クラスからのデータを取り込み、動き (アニメーションではありません) に変換します。 * どの Animation ブループリントを使用してスケルタル アニメーションを動かすかを Mesh コンポーネント内に保存します。 * Animation ブループリント - * Character クラスから Event Graph にデータを取り込みます。 - * そのデータを使用して、ステート マシン、ブレンド スペース、その他のアセットを操作します。 + * Character クラスのデータをイベントグラフに取り込みます。 + * こうしたデータを使ってステートマシン、ブレンドスペース、その他のアセットを操作します。 * こうしたアセットは、アニメーション シーケンス (FBX ファイルからスケルタル アニメーション データ) を使用してキャラクターをアニメートします。 * Animation ブループリントの最終結果がスケルタルメッシュに適用されます。インゲームのキャラクターがアニメートするのを見ることができるようになります。 @@ -194,9 +196,9 @@ GameMode を設定したら、カスタムのキャラクターとプレイで アンリアル エンジンで新規プロジェクトを作成する場合 (**File > New Project**)、テンプレートを選択するオプションがあります。これらは実質上、独自の GameMode、Character ブループリント、 Animation ブループリント、およびこのドキュメントで取り上げたあらゆるアセットを使用します。単純かつ明確にするために、First Person (一人称視点) または Third Person (三人称視点) のテンプレートを確認することを強くお勧めします。 -こうしたテンプレートはコード形式またはブループリント形式の両方で入手可能であることにご注意ください。これは、慣れ親しんでいる方法で開発することを選択できるようにしたものです。プログラマーならば、おそらく Code テンプレートを使用するでしょう。どちらかというとアーティスティックな開発者の場合は、Blueprint テンプレートを利用する方が快適でしょう。この 2 つは相互排他的ではありません。新しい Blueprint クラスを Code Template のプロジェクトに追加したり、コードのクラスを Blueprint テンプレートのプロジェクトに追加することができます。 +こうした各テンプレートは、コード形式またはブループリント形式で利用することができます。これは、慣れ親しんでいる方法で開発することを選択できるようにしたものです。プログラマーならば、おそらく Code テンプレートを使用するでしょう。アーティスティックなデベロッパーならば、Blueprint テンプレートが使いやすいかもしれません。この 2 つは相互排他的ではありません。新しい Blueprint クラスを Code Template のプロジェクトに追加したり、コードのクラスを Blueprint テンプレートのプロジェクトに追加することができます。 -### Content Examples +### コンテンツ サンプル [REGION:fullwidth] ![](AnimationCE.png) diff --git a/Engine/Documentation/Source/Engine/Animation/CharacterSetupOverview/CharacterSetupOverview.KOR.udn b/Engine/Documentation/Source/Engine/Animation/CharacterSetupOverview/CharacterSetupOverview.KOR.udn index eccfb88d32f6..1f767ca4308a 100644 --- a/Engine/Documentation/Source/Engine/Animation/CharacterSetupOverview/CharacterSetupOverview.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/CharacterSetupOverview/CharacterSetupOverview.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3467293 Availability:Public Title: 캐릭터 셋업 개요 Crumbs: %ROOT%, Engine, Engine/Animation @@ -12,6 +12,7 @@ Related: Engine/Animation/AnimBlueprints/EventGraph Related: Engine/Animation/StateMachines Related: Gameplay/AI version: 4.9 +topic-image:SettingUpACharacter_topic.png [REGION:fullwidth] ![](Character.png) diff --git a/Engine/Documentation/Source/Engine/Animation/IKSetups/IKSetups.INT.udn b/Engine/Documentation/Source/Engine/Animation/IKSetups/IKSetups.INT.udn index 74070a26752e..beb169abd926 100644 --- a/Engine/Documentation/Source/Engine/Animation/IKSetups/IKSetups.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/IKSetups/IKSetups.INT.udn @@ -9,7 +9,7 @@ Related: Engine/Content/Tools/MayaRiggingTool Related: Engine/Animation/AnimBlueprints Related: Engine/Animation/AnimBlueprints/EventGraph version: 4.9 - +topic-image:IKSetups_topic.png [REGION:fullwidth] ![](IKWithWithout.png) diff --git a/Engine/Documentation/Source/Engine/Animation/IKSetups/IKSetups.JPN.udn b/Engine/Documentation/Source/Engine/Animation/IKSetups/IKSetups.JPN.udn index 867a78ffe5d6..9e82e315e36f 100644 --- a/Engine/Documentation/Source/Engine/Animation/IKSetups/IKSetups.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/IKSetups/IKSetups.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:2663461 +INTSourceChangelist:3467293 Availability:Public Title:IK 設定 Crumbs: %ROOT%, Engine, Engine/Animation @@ -9,21 +9,21 @@ Related:Engine/Animation/PhysicallyDrivenAnimation Related:Engine/Content/Tools/MayaRiggingTool Related:Engine/Animation/AnimBlueprints Related:Engine/Animation/AnimBlueprints/EventGraph -version: 4.9 - +version:4.9 +topic-image:IKSetups_topic.png [REGION:fullwidth] ![](IKWithWithout.png) [/REGION] [REGION:caption] -左側のキャラクターは IK 設定を使用していません。中央のキャラクターは、小さな衝突オブジェクト上で足をしっかり立たせた状態を維持するために IK を使用してます。右側のキャラクターは、移動するブロックに当たるとキャラクターのパンチ アニメーションが止まるように IK を使用しています。 +左側のキャラクターは IK 設定を使用していません。中央のキャラクターは、小さな衝突オブジェクト上で足をしっかり立たせた状態を維持するために IK を使用しています。右側のキャラクターは、移動するブロックに当たるとキャラクターのパンチ アニメーションが止まるように IK を使用しています。 [/REGION] -**IK** (**インバース キネマティクス**) は、ジョイントを直接回転させるのではなく、終了エフェクタの位置からジョイント回転を処理していきます。実際には、ユーザーがエフェクタ位置を選び、その位置にできるだけ最終ジョイントが近づくように IK ソリューションが回転を解決していきます。グラウンド上でキャラクターをしっかり両足で立たせるために使用しますが、その他にも様々な形でワールドと確実なインタラクションを生み出すことができます。 +**IK** (**インバース キネマティクス**) は、ジョイントを直接回転させるのではなく、終了エフェクタの位置からジョイント回転を処理していきます。実際には、ユーザーがエフェクタ位置と IK ソリューションを指定し、その位置にできるだけ最終ジョイントが近づくように回転を解決していきます。不均等なグラウンド上でキャラクターをしっかり両足で立たせるために使用しますが、その他にも様々な形でワールドとリアルなインタラクションを生み出すことができます。 アンリアル エンジンでは、腕や脚に理想的な 2 Bone IK システムを採用しています。 @@ -32,11 +32,11 @@ IK を頭と足に適用した例を、セクション 1.8 の [アニメーシ [/REGION] -## IK (インバース キネマティクス) 設定とFK (フォワード キネマティクス) 設定 +## IK (インバース キネマティクス) と FK (フォワード キネマティクス) IK の内容および使用方法について既にご存知の場合は、このセクションを飛ばしてください! -アンリアルでアニメート化されたスケルトンのほとんどは、キャラクターのボーンあるいはスケルタル メッシュに直接回転データを与えて操作します。これを _フォワード キネマティクス_ 、あるいは、ジョイントやボーンを直接回転させる方法だと考えてください。その概念を表すと、こうなります。 +アンリアルでアニメート化されたスケルトンのほとんどは、キャラクターのボーンあるいはスケルタル メッシュに直接回転データを与えて操作します。これをフォワード キネマティクス、あるいは、ジョイントやボーンを直接回転させる方法だと考えてください。その概念を表すと、こうなります。 [REGION:raw] ![](diagram_FK.png)(w:600) @@ -48,7 +48,7 @@ IK (インバース キネマティクス) は、その名の通り、逆向き ![](diagramIK.png)(w:600) [/REGION] -UE4 では、キャラクターやスケルタル メッシュの動きがごく自然な反応に見えるように、IK を使って既存のアニメーションをオーバーライドすることが可能です。 +UE4 では、キャラクターやスケルタル メッシュの動きがごく自然な反応に見えるように、IK を使って既存のアニメーションをオーバーライドしたり、改善することが可能です。 ## IK の設定 @@ -58,7 +58,7 @@ IK では通常、異なる複数の位置に設定が必要になります。 1. エフェクタ位置を処理するための設定。この設定は、ポーンや Character ブループリントで行われることが多いです。 -1. ポーンまたはキャラクターからエフェクタ位置を受け取るための Animation ブループリントのイベントグラフ内の設定。これは IK ソルバ のための設定です。 +1. ポーンまたはキャラクターからエフェクタ位置を受け取るための Animation ブループリントのイベントグラフ内の設定。これは IK ソルバのための設定です。 1. キャラクターの Animation ブループリントの Anim Graph 内の 2-Bone IK ノードの設定。 @@ -72,7 +72,7 @@ IK では通常、異なる複数の位置に設定が必要になります。 最初の例では、平坦でないグラウンド上でキャラクターの足を立たせやすくするために、キャラクターに行うシンプルな IK 設定の概要を説明します。 [REGION:note] -コンテンツ サンプル プロジェクトで例をご覧頂けます。Animation.umap という名前のマップを開いて、例 1.8 を見てください。 +Content Examples プロジェクトで例をご覧頂けます。Animation.umap という名前のマップを開いて、例 1.8 を見てください。 [/REGION] ### Pawn または Character ブループリントの設定 @@ -130,7 +130,7 @@ Character ブループリントのコンストラクション スクリプトは ここがイベント グラフのベース レベルです。画像をクリックして拡大表示、または **右クリック** して名前を付けて保存します。 [/REGION] -この結果、ゲームの各ティックの間、下方向のトレースが実施され、平坦でないグラウンドの原因となっている構成要素を特定する重要ポイントを探します。見つかると、そのポイントまでの距離が IK オフセットとして格納され、後に Animation ブループリントで使用されます。 +この結果、ゲームの各ティックの間、下方向のトレースが実施され、グラウンドの平坦でない部分を特定する衝撃点を探します。見つかると、そのポイントまでの距離が IK オフセットとして格納され、後に Animation ブループリントで使用されます。 ![](IKTrace.png) [REGION:caption] @@ -145,11 +145,11 @@ Character ブループリントのコンストラクション スクリプトは Animation ブループリントについて、まず最初にイベント グラフについて説明します。一般的に、 Animation ブループリントのイベント グラフの主な目的は、 Character または Pawn ブループリントのような他のソースからデータを受け取り、それらを AnimGraph で使用できる変数に変換することです。 -#### イベント グラフ +#### イベントグラフ ここでは、まず最初に現在のポーンを取得し、設定が全て完了している特定のポーンを基礎とするクラスへ確実にキャストします。これにより、 Pawn ブループリントの特定のインスタンスとの直接通信、および変数に格納されたデータの読み取りが可能になります。 -Pawn ブループリントに格納された IK オフセットデータを使って、後に IK エフェクタが使用する位置ベクターを生成することができます。 +Pawn ブループリントに格納された IK オフセットデータを使って、後で IK エフェクタが使用する位置ベクターを生成することができます。 [REGION:fullwidth] @@ -165,13 +165,13 @@ Pawn ブループリントに格納された IK オフセットデータを使 #### AnimGraph -AnimGraph はここまでに組み合わせた情報で設定を完了させ、それを使ってキャラクター用に作成された既存のアニメーションを更新します。この例では AnimGraph はたった 1 つのアニメーションしか再生しないので、非常にシンプルです。ほとんど場合、Play JumpingJacks ノードは他のノードに好きなだけ置き換えて、希望するモーションを作成します。 +AnimGraph はここまでに組み合わせた情報で設定を完了させ、それを使ってキャラクター用に作成された既存のアニメーションを更新します。この例では AnimGraph はたった 1 つのアニメーションしか再生しないので、非常にシンプルです。ほとんどの場合、Play JumpingJacks ノードは他のノードに好きなだけ置き換えて、希望するモーションを作成します。 現在の空間をローカルからコンポーネントに切り替える部分が重要です。キャラクター上で再生される全てのアニメーションは、ローカル空間で行われます。ローカルでの変換は階層内の各ボーンの親に相対するので、この方法が一番早く計算を実行できます。ただし、 2 Bone IK の適用などのボーン操作は、Root ボーンと相対するコンポーネント空間で行わなければなりません。 -このため、ローカルからコンポーネントへデータを切り替える際には、データが IK 計算を実施するのに十分な長さである必要があります。同時に Final Animation Pose ノードはローカル空間のデータのみを受け取るので、 IK が適用されると再変換しなければなりません。 +このため、IK 計算を実施するのに十分な時間、ローカルからコンポーネントへデータを切り替える必要があります。同時に Final Animation Pose ノードはローカル空間のデータのみを受け取るので、 IK が適用されると再変換しなければなりません。 -アニメーションの空間についての詳細は、 [](Engine/Basics/CoordinateSpace) をご覧ください。 +アニメーションの座標空間についての詳細は、 [](Engine/Basics/CoordinateSpace) をご覧ください。 [REGION:fullwidth] diff --git a/Engine/Documentation/Source/Engine/Animation/IKSetups/IKSetups.KOR.udn b/Engine/Documentation/Source/Engine/Animation/IKSetups/IKSetups.KOR.udn index 6a04009fb873..62870db75712 100644 --- a/Engine/Documentation/Source/Engine/Animation/IKSetups/IKSetups.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/IKSetups/IKSetups.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3467293 Availability:Public Title: IK 셋업 Crumbs: %ROOT%, Engine, Engine/Animation @@ -10,7 +10,7 @@ Related: Engine/Content/Tools/MayaRiggingTool Related: Engine/Animation/AnimBlueprints Related: Engine/Animation/AnimBlueprints/EventGraph version: 4.9 - +topic-image:IKSetups_topic.png [REGION:fullwidth] ![](IKWithWithout.png) diff --git a/Engine/Documentation/Source/Engine/Animation/NodeReference/AnimationNodes.INT.udn b/Engine/Documentation/Source/Engine/Animation/NodeReference/AnimationNodes.INT.udn index 9697dcf6c4a9..75ee048b1a87 100644 --- a/Engine/Documentation/Source/Engine/Animation/NodeReference/AnimationNodes.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/NodeReference/AnimationNodes.INT.udn @@ -3,6 +3,7 @@ Title: Animation Node Reference Crumbs: %ROOT%, Engine, Engine/Animation Description:Descriptions of the various animation nodes available for use in Animation Blueprints. version: 4.9 +topic-image:AnimationgNodeReference_topic.png [EXCERPT:Intro] Animation Blueprints make use of various nodes within their graphs to perform operations on input diff --git a/Engine/Documentation/Source/Engine/Animation/NodeReference/AnimationNodes.JPN.udn b/Engine/Documentation/Source/Engine/Animation/NodeReference/AnimationNodes.JPN.udn index 92fd2849bf36..91a052dfde35 100644 --- a/Engine/Documentation/Source/Engine/Animation/NodeReference/AnimationNodes.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/NodeReference/AnimationNodes.JPN.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:3114699 +INTSourceChangelist:3467293 Availability:Public Title:Animation ノードの参照 Crumbs: %ROOT%, Engine, Engine/Animation Description:Animation ブループリントに使用できる各種 Animation ノードの説明 version:4.9 +topic-image:AnimationgNodeReference_topic.png [EXCERPT:Intro] Animation ブループリントは、ブレンディング、直接的な骨格操作など、入力ポーズのオペレーションを実行するために、 diff --git a/Engine/Documentation/Source/Engine/Animation/NodeReference/AnimationNodes.KOR.udn b/Engine/Documentation/Source/Engine/Animation/NodeReference/AnimationNodes.KOR.udn index 77a6871e3e82..bfa4758f8bce 100644 --- a/Engine/Documentation/Source/Engine/Animation/NodeReference/AnimationNodes.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/NodeReference/AnimationNodes.KOR.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:3114699 +INTSourceChangelist:3467293 Availability:Public Title: 애니메이션 노드 참고서 Crumbs: %ROOT%, Engine, Engine/Animation Description:애니메이션 블루프린트에서 사용할 수 있는 여러가지 애니메이션 노드에 대한 설명입니다. version: 4.9 +topic-image:AnimationgNodeReference_topic.png [EXCERPT:Intro] _AnimationBlueprint_ (애니메이션 블루프린트)는 여러가지 노드를 활용하여 그래프 안의 입력 포즈에 블렌딩, diff --git a/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/AnimDynamics/AnimDynamics.KOR.udn b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/AnimDynamics/AnimDynamics.KOR.udn index e54c627578aa..7601d1e02197 100644 --- a/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/AnimDynamics/AnimDynamics.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/AnimDynamics/AnimDynamics.KOR.udn @@ -41,7 +41,7 @@ version: 4.12 **AnimDynamics** (애님 다이내믹스) 노드는 스켈레탈 메시 애셋에 물리 기반 이차 애니메이션을 내는 데 사용할 수 있는 작은 솔버입니다. -캐릭터에 목걸이, 팔찌, 팩, 와이어, 헤어, 클로쓰 등 캐릭터의 움직임에 따라 튕기는 아이템이 있는 경우, 이 노드로 그 움직임을 낼 수 있습니다. +캐릭터에 목걸이, 팔찌, 팩, 와이어, 헤어, 클로스 등 캐릭터의 움직임에 따라 튕기는 아이템이 있는 경우, 이 노드로 그 움직임을 낼 수 있습니다. 애님 다이내믹스는 LOD 나 기타 애니메이션 세팅과 함께 켜고 끌 수 있는 초경량 구현입니다. 이에 대한 처리는 [**애님 그래프**](Engine/Animation/AnimBlueprints/AnimGraph) 에서의 애니메이션 처리 도중 일어납니다. 단순하고 빠른 솔버로 만들어졌기에, 솔버가 추정하는 것이 몇 가지 있다는 점을 알아두는 것이 좋습니다. diff --git a/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/LookAt/LookAt.INT.udn b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/LookAt/LookAt.INT.udn index 0d6d57c392eb..890d0ad4d2db 100644 --- a/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/LookAt/LookAt.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/LookAt/LookAt.INT.udn @@ -1,68 +1,48 @@ -Availability:Public -Title:Look At +Availability: Docs Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/NodeReference, Engine/Animation/NodeReference/SkeletalControls -Description:Describes the how the Look At control can be used to specify a bone to trace or follow another bone. -version: 4.12 - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine\Animation\NodeReference\SkeletalControls\LookAt:title%](Engine\Animation\NodeReference\SkeletalControls\LookAt\LookAtnode.png) - [/PARAM] - [PARAM:title] - %Engine\Animation\NodeReference\SkeletalControls\LookAt:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine\Animation\NodeReference\SkeletalControls\LookAt] - [/PARAM] - [PARAM:description] - %Engine\Animation\NodeReference\SkeletalControls\LookAt:description% - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine\Animation\NodeReference\SkeletalControls\LookAt:title%](Engine\Animation\NodeReference\SkeletalControls\LookAt\LookAtnode.png) - [/PARAM] - [PARAM:title] - %Engine\Animation\NodeReference\SkeletalControls\LookAt:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine\Animation\NodeReference\SkeletalControls\LookAt] - [/PARAM] - [PARAM:description] - %Engine\Animation\NodeReference\SkeletalControls\LookAt:description% - [/PARAM] -[/OBJECT] -[/VAR] - +Title:Look At +Description:Describes how the Look At control can be used to specify a bone to trace or follow another bone. +Type: Reference +version: 4.16 +Parent: Engine/Animation/NodeReference/SkeletalControls +Order: 1 +tags:Animation +tags:Skeletal Controls +tags:Animation Graph +topic-image:LookAtnode.png +Related: Engine/Animation/NodeReference/SkeletalControls +Related: Engine/Animation/AnimBlueprints/AnimGraph +Related: Engine/Animation/StateMachines +Related: Engine/Animation/AnimBlueprints + The **Look At** Skeletal Control Node can be used to specify a Bone to trace or follow another Bone in the Skeleton. ![](LookAtnode.png) -Below, our character has two packs on their left side which use the **Look At** control node and are set to follow a foot bone. +Below, we set our character's Head bone to follow the location of their Hand bone. [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -85dUv_jvIi4 -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + FPfY1Nav1U0 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] -Inside the viewport, a yellow debug line is a visulalization tool to help see which **Look at Bone** the **Bone to Modify** is following. - -[REGION:note] -You may need to enlarge the video to see the debug line or try it out in the editor. -[/REGION] +This node enables you to also set whether or not to use a **Look at Location** offset relative to the specified **Look at Bone** as well as set **Look at Clamp** values, **Interpolation Type** and **Interpolation Time** values. +The visualization tools enable you to see the **Bone to Modify**, the **Look at Bone**, clamp angles, target location and interpolation values inside the viewport. | Property | Description | @@ -70,17 +50,17 @@ You may need to enlarge the video to see the debug line or try it out in the edi | [REGION:tablesection]**Skeletal Control**[/REGION] || | **Bone to Modify** | Name of the Bone to control. This is the main Bone chain to modify from. | | **Look at Axis** | Which axis to align to look at point. | +| **In Local Space** | Whether or not to use Local or World Space. | | **Use Look Up Axis** | Whether or not to use look up axis. | -| **Look Up Axis** | Look up axis in local space. | -| **Look at Clamp** | Look at Clamp value in degrees. If your **Look at axis** is Z, only X, Y degree of clamp will be used. | +| **Look Up Axis** | Which axis to align to look up. | +| **Look at Clamp** | Look at Clamp value in degrees. If your Look at axis is Z, only X, Y degree of clamp will be used. | | **Interpolation Type** | The interpolation method to use. | -| **Interpolation Time** | The time used during interpolation. | +| **Interpolation Time** | TIme used to get to target when interpolating (for example, a value of 3 will result in 3 seconds to get to the target location to look). | | **Interpolation Trigger Threshold** | The threshold in which to trigger interpolation. | -| **Enable Debug** | Whether or not to enable debug display. | | [REGION:tablesection]**Target**[/REGION] || -| **Look at Bone** | Target Bone to look at. You can't use **Look At Location** as an alternative as you'll get a delay on Bone location if you query directly. | +| **Look at Bone** | Target Bone to look at. You can't use Look At Location as an alternative as you'll get a delay on Bone location if you query directly. | | **Look at Socket** | Target Socket to look at. | -| **Look at Location** | Target location in world space if **Look At Bone** is empty. | +| **Look at Location** | Location to look at or offset applied when Look at Bone or Look at Socket are set. | | Pin | Description | @@ -92,3 +72,4 @@ You may need to enlarge the video to see the debug line or try it out in the edi **Look At** nodes are also affected by the **LOD Threshold** system introduced in 4.11. You can find the setting for this in the **Details Panel** for the **Look At** node. [INCLUDE:Engine/Animation/NodeReference/SkeletalControls#lodthresh] + diff --git a/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/LookAt/LookAt.JPN.udn b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/LookAt/LookAt.JPN.udn index 108f76c1fb0b..dc1bd23cdf5f 100644 --- a/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/LookAt/LookAt.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/LookAt/LookAt.JPN.udn @@ -1,69 +1,49 @@ -INTSourceChangelist:3060419 -Availability:Public -Title:Look At +INTSourceChangelist:3478246 +Availability:Docs Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/NodeReference, Engine/Animation/NodeReference/SkeletalControls -Description:Look At 制御を使用して、他のボーンに追随するボーンを指定することができます。 -version:4.12 - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine\Animation\NodeReference\SkeletalControls\LookAt:title%](Engine\Animation\NodeReference\SkeletalControls\LookAt\LookAtnode.png) - [/PARAM] - [PARAM:title] - %Engine\Animation\NodeReference\SkeletalControls\LookAt:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine\Animation\NodeReference\SkeletalControls\LookAt] - [/PARAM] - [PARAM:description] - %Engine\Animation\NodeReference\SkeletalControls\LookAt:description% - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine\Animation\NodeReference\SkeletalControls\LookAt:title%](Engine\Animation\NodeReference\SkeletalControls\LookAt\LookAtnode.png) - [/PARAM] - [PARAM:title] - %Engine\Animation\NodeReference\SkeletalControls\LookAt:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine\Animation\NodeReference\SkeletalControls\LookAt] - [/PARAM] - [PARAM:description] - %Engine\Animation\NodeReference\SkeletalControls\LookAt:description% - [/PARAM] -[/OBJECT] -[/VAR] - +Title:Look At +Description:Look At 制御を使用して、トレースするボーンまたは他のボーンに追随するボーンを指定することができます。 +Type:Reference +version:4.16 +Parent:Engine/Animation/NodeReference/SkeletalControls +Order:1 +tags:Animation +tags:Skeletal Controls +tags:Animation Graph +topic-image:LookAtnode.png +Related:Engine/Animation/NodeReference/SkeletalControls +Related:Engine/Animation/AnimBlueprints/AnimGraph +Related:Engine/Animation/StateMachines +Related:Engine/Animation/AnimBlueprints + **Look At** スケルタル コントロール ノードを使用して、スケルトンの他のボーンに追随するボーンを指定することができます。 ![](LookAtnode.png) -以下では、キャラクターの左側に 2 つのパックがあります。これらは **Look At** 制御ノードを使用しており、足のボーンに追随するように設定されています。 +以下ではキャラクターの Head (頭部) ボーンを Hand (手) ボーンの位置に追随するようにします。 [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -85dUv_jvIi4 -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + FPfY1Nav1U0 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] -ビューポート内で黄色のデバッグ ラインは、どの **Look at Bone** を、**Bone to Modify** が追随しているかを視覚化するツールです。 - -[REGION:note] -デバッグラインを確認するには映像を拡大するか、エディタで見る必要があるかもしれません。 -[/REGION] +指定した **Look at Bone** に相対的に **Look at Location** オフセットを使うかどうかを設定するとともに、**Look at Clamp** 値、**Interpolation Type** 値、**Interpolation Time** 値も設定します。 +このビジュアル化ツールは、ビューポート内で **Bone to Modify**、**Look at Bone**、クランプ角度、ターゲット位置、補間値を表示します。 | プロパティ | 説明 | @@ -71,17 +51,17 @@ version:4.12 | [REGION:tablesection]**スケルタル コントロール**[/REGION] || | **Bone To Modify** | 制御対象のボーンの名前です。修正をするメイン ボーン チェーンです。 | | **Look at Axis** | どの軸を注視点 (look at point) に合わせるかを指定します。 | +| **In Local Space** | ローカル空間またはワールド空間を使うかを指定します。 | | **Use Look Up Axis** | 上方の軸 (look up axis) を設定するかどうかを指定します。 | -| **Look Up Axis** | ローカル空間の look up 軸 | -| **Look at Clamp** | Look at Clamp 値、単位は角度。**look at 軸** が Z の場合、X、Y のクランプ角度だけが使用されます。 | +| **Look Up Axis** | どの軸を上方に合わせるかを指定します。 | +| **Look at Clamp** | Look at Clamp 値、単位は角度。look at 軸 が Z の場合、X、Y のクランプ角度だけが使用されます。 | | **Interpolation Type** | 使用する補間方法 | -| **Interpolation Time** | 補間中に使用される時間 | +| **Interpolation Time** | 補間時にターゲットに到達するために使う時間 (例、値 3 はlook at するターゲット位置に到達するのに 3 秒かかかります)。 | | **Interpolation Trigger Threshold** | 補間をトリガーする閾値 | -| **Enable Debug** | デバッグ表示を有効にするか、しないかを設定します。 | |[REGION:tablesection]**ターゲット**[/REGION] || -| **Look at Bone** | look at するターゲット ボーン。**Look At Location** を代わりに使用することはできません。直接クエリするとボーン位置に遅延が生じるからです。 | +| **Look at Bone** | look at するターゲット ボーン。Look At Location を代わりに使用することはできません。直接クエリするとボーン位置に遅延が生じるからです。 | | **Look at Socket** | look at するターゲット ソケット | -| **Look at Location** | **Look At Bone** が空の場合に、ワールド空間のターゲット位置 | +| **Look at Location** | Look at Bone または Look at Socket を設定している場合に、look at する、またはオフセットする位置。 | | ピン | 説明 | @@ -93,3 +73,4 @@ version:4.12 **Look At** ノードも 4.11 で導入された **LOD Threshold** システムの影響を受けます。**Look At** ノードの **[Details (詳細)]** パネルにこの設定が表示されます。 [INCLUDE:Engine/Animation/NodeReference/SkeletalControls#lodthresh] + diff --git a/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/LookAt/LookAt.KOR.udn b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/LookAt/LookAt.KOR.udn index 61a5a4ad0113..3262f526caeb 100644 --- a/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/LookAt/LookAt.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/LookAt/LookAt.KOR.udn @@ -1,69 +1,45 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3464851 Availability:Public Title:바라보기 Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/NodeReference, Engine/Animation/NodeReference/SkeletalControls Description:하나의 본이 다른 본을 바라보거나 따라가도록 하는 데 사용되는 Look At 콘트롤입니다. -version: 4.12 - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine\Animation\NodeReference\SkeletalControls\LookAt:title%](Engine\Animation\NodeReference\SkeletalControls\LookAt\LookAtnode.png) - [/PARAM] - [PARAM:title] - %Engine\Animation\NodeReference\SkeletalControls\LookAt:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine\Animation\NodeReference\SkeletalControls\LookAt] - [/PARAM] - [PARAM:description] - %Engine\Animation\NodeReference\SkeletalControls\LookAt:description% - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine\Animation\NodeReference\SkeletalControls\LookAt:title%](Engine\Animation\NodeReference\SkeletalControls\LookAt\LookAtnode.png) - [/PARAM] - [PARAM:title] - %Engine\Animation\NodeReference\SkeletalControls\LookAt:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine\Animation\NodeReference\SkeletalControls\LookAt] - [/PARAM] - [PARAM:description] - %Engine\Animation\NodeReference\SkeletalControls\LookAt:description% - [/PARAM] -[/OBJECT] -[/VAR] - - +version: 4.16 +Related: Engine/Animation/NodeReference/SkeletalControls +Related: Engine/Animation/AnimBlueprints/AnimGraph +Related: Engine/Animation/StateMachines +Related: Engine/Animation/AnimBlueprints +type:reference +topic-image:LookAtnode.png +tags:Animation +tags:Skeletal Controls +tags:Animation Graph **Look At** 스켈레탈 콘트롤 노드는 하나의 본이 스켈레톤 내 다른 본을 바라보거나 따르도록 하는 데 사용됩니다. ![](LookAtnode.png) -아래에서 우리 캐릭터 왼편에 있는 두 개의 팩은 **Look At** 콘트롤 노드를 사용하여 발 본을 따르도록 설정되어 있습니다. +아래는 캐릭터의 Head 본이 그 위치를 따르도록 설정한 것입니다. [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -85dUv_jvIi4 -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + FPfY1Nav1U0 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] -뷰포트 안의 노랑 디버그 선은 **Bone to Modify** 가 어느 **Look at Bone** 을 따르는지 확인하는 데 도움이 되는 시각화 도구입니다. - -[REGION:note] -디버그 선이 안보이는 경우 비디오를 확대시켜 보거나, 에디터에서 직접 시도해 보시기 바랍니다. -[/REGION] +이 노드를 통해 지정된 **Look at Bone** 을 기준으로 한 상대 **Look at Location** 오프셋 사용 여부는 물론, **Look at Clamp** 값 설정, **Interpolation Type** 및 **Interpolation Time** 값 설정도 가능합니다. +시각화 툴을 통해 뷰포트 안에서 **Bone to Modify**, **Look at Bone**, 클램프 각도, 타겟 위치, 보간 값 등을 확인할 수 있습니다. | 프로퍼티 | 설명 | @@ -71,17 +47,17 @@ version: 4.12 | [REGION:tablesection]**Skeletal Control** 스켈레탈 콘트롤[/REGION] || | **Bone to Modify** | 변경할 본 - 제어할 본 이름입니다. 이 본 체인에서 주로 변경하게 됩니다. | | **Look at Axis** | 바라보기 축 - 바라보기 지점에 정렬할 축입니다. | +| **In Local Space** | 로컬 스페이스에서 - 로컬 스페이스 또는 월드 스페이스 사용 여부입니다. | | **Use Look Up Axis** | 올려보기 축 사용 - 룩 업 축 사용 여부입니다. | -| **Look Up Axis** | 올려보기 축 - 로컬 스페이스의 올려보기 축입니다. | +| **Look Up Axis** | 룩 업 축 - 룩 업 기준 축입니다. | | **Look at Clamp** | 바라보기 클램프 - 각도 단위 바라보기 클램프(제한) 값입니다. **Look at axis** 가 Z 면, 클램프의 X, Y 각도만 사용됩니다. | | **Interpolation Type** | 보간 유형 - 사용할 보간 방식입니다. | | **Interpolation Time** | 보간 시간 - 보간 도중 사용할 시간입니다. | | **Interpolation Trigger Threshold** | 보간 발동 한계치 - 이 한계치가 넘어가면 보간이 발동됩니다. | -| **Enable Debug** | 디버그 활성화 - 디버그 표시 활성화 여부입니다. | | [REGION:tablesection]**Target** 타겟[/REGION] || | **Look at Bone** | 바라보기 본 - 바라볼 타겟 본입니다. 여기에 **Look At Location** 을 사용할 수는 없는데, 직접 쿼리를 하는 경우 본 위치를 구해오는 데 지연시간이 생기기 때문입니다. | | **Look at Socket** | 바라보기 소켓 - 바라볼 타겟 소켓입니다. | -| **Look at Location** | 바라보기 위치 - **Look At Bone** 이 비어있는 경우 월드 스페이스의 타겟 위치입니다. | +| **Look at Location** | 바라보기 위치 - Look at Bone 또는 Look at Socket 이 설정되었을 때 적용할 바라보기 또는 오프셋 위치입니다. | | 핀 | 설명 | @@ -93,3 +69,4 @@ version: 4.12 **Look At** 4.11 에 도입된 **LOD Threshold** (LOD 한계치) 시스템의 영향도 받습니다. 이 세팅은 **Look At** 노드의 **디테일 패널** 에서 찾아볼 수 있습니다. [INCLUDE:Engine/Animation/NodeReference/SkeletalControls#lodthresh] + diff --git a/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/ModifyCurve/ModifyCurve.CHN.udn b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/ModifyCurve/ModifyCurve.CHN.udn new file mode 100644 index 000000000000..a722d51b997b --- /dev/null +++ b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/ModifyCurve/ModifyCurve.CHN.udn @@ -0,0 +1,54 @@ +INTSourceChangelist:0 +Availability:Public +Title:Modify Curve +Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/NodeReference, Engine/Animation/NodeReference/SkeletalControls +Description:Describes the Modify Curve node which can be used to modify animation curves with arbitrary logic inside Animation Graphs. +Related: Engine/Animation/Sequences/Curves +Related: Engine/Animation/NodeReference/SkeletalControls +Related: Engine/Animation/AnimBlueprints +Related: Engine/Animation/AnimBlueprints/AnimGraph +Related: Engine/Animation/StateMachines +version: 4.15 +type:reference +topic-image:ModifyCurveNode.png +tags:Animation +tags:Animation Blueprint +tags:Animation Curves +tags:Skeletal Controls + + +The **Modify Curve** control can be used to expose [Animation Curve](Engine/Animation/Sequences/Curves) data which can be modified using arbitrary logic to enable more dynamically-driven animations. + +![](ModifyCurveNode.png) + +Below, the Modify Curve node is used to drive a curve called **Eye Glow Intensity** where the bear's eyes glow brighter over time. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + tYN-osmLeKE + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +Inside the [](Engine/Animation/AnimBlueprints/AnimGraph) of your [](Engine/Animation/AnimBlueprints), **Right-click** and search for and add the **Modify Curve** node + +Once added, **Right-click** on the node and select **Add Curve Pin** and any associated curves you wish to modify. + +![](AddCurvePin.png) + +Pins can be removed by **Right-clicking** on the node again and selecting **Remove Curve Pin** or by **Right-clicking** on the pin itself and selecting **Remove This Curve Pin**. + +With the exposed float pin, you can define any logic you wish to drive the value (the logic below adjusts the glow of our bear's eyes over time). + +![](CurveLogic.png) diff --git a/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/ModifyCurve/ModifyCurve.INT.udn b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/ModifyCurve/ModifyCurve.INT.udn new file mode 100644 index 000000000000..eb7506c5a5f0 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/ModifyCurve/ModifyCurve.INT.udn @@ -0,0 +1,64 @@ +Availability: Docs +Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/NodeReference, Engine/Animation/NodeReference/SkeletalControls +Title:Modify Curve +Description:Describes the Modify Curve node which can be used to modify animation curves with arbitrary logic inside Animation Graphs. +Type: Reference +Version: 4.16 +Parent: Engine/Animation/NodeReference/SkeletalControls +Order: 1 +tags:Animation +tags:Animation Blueprint +tags:Animation Curves +tags:Skeletal Controls +Related: Engine/Animation/Sequences/Curves +Related: Engine/Animation/NodeReference/SkeletalControls +Related: Engine/Animation/AnimBlueprints +Related: Engine/Animation/AnimBlueprints/AnimGraph +Related: Engine/Animation/StateMachines +topic-image:ModifyCurveNode.png + + + +The **Modify Curve** control can be used to expose [Animation Curve](Engine/Animation/Sequences/Curves) data which can be modified using arbitrary logic to enable more dynamically-driven animations. + +![](ModifyCurveNode.png) + +Below, the Modify Curve node is used to drive a curve we create called **Eye Glow Intensity** where the bear's eyes pulsate and glow over time. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + lU_hG0rIGLY + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +To add this node to the [](Engine/Animation/AnimBlueprints/AnimGraph) of your [](Engine/Animation/AnimBlueprints): + +1. Right-click in the **AnimGraph** and search for and add the **Modify Curve** node + +1. Once added, right-click on the node and select **Add Curve Pin** and any associated curves you wish to modify. + + ![](AddCurvePin.png) + +With the exposed float pin, you can define any logic you wish to drive the value (the logic below uses the Sin of Time multiplied by a coeffiect value to drive the Eye Glow Intensity). + +![](CurveLogic.png) + + +To remove pins from the Modify Curve node: + +* Right-click on the node again and select **Remove Curve Pin** or right-click on the pin itself and select **Remove This Curve Pin**. + + ![](RemovePin.png) + diff --git a/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/ModifyCurve/ModifyCurve.JPN.udn b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/ModifyCurve/ModifyCurve.JPN.udn new file mode 100644 index 000000000000..2d469aa776c2 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/ModifyCurve/ModifyCurve.JPN.udn @@ -0,0 +1,54 @@ +INTSourceChangelist:3447015 +Availability:Public +Title:Modify Curve +Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/NodeReference, Engine/Animation/NodeReference/SkeletalControls +Description:アニメーション グラフ内の任意のロジックでアニメーション カーブを修正するために使う Modify Curve ノードについて説明します。 +Related:Engine/Animation/Sequences +Related:Engine/Animation/NodeReference/SkeletalControls +Related:Engine/Animation/AnimBlueprints +Related:Engine/Animation/AnimBlueprints/AnimGraph +Related:Engine/Animation/StateMachines +version:4.15 +type:reference +topic-image:ModifyCurveNode.png +tags:Animation +tags:Animation Blueprint +tags:Animation Curves +tags:Skeletal Controls + + +**Modify Curve** 制御を使って、 [アニメーション カーブ](Engine/Animation/Sequences/Curves) データを公開し、任意のロジックを使って変更し、アニメーションをより動的に操作することができます。 + +![](ModifyCurveNode.png) + +以下では、Modify Curve ノードを使って、**Eye Glow Intensity** というカーブを操作し、時間経過に従い、クマの目が光るようにします。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + tYN-osmLeKE + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +[](Engine/Animation/AnimBlueprints) の [](Engine/Animation/AnimBlueprints/AnimGraph) で、**右クリック** して、**Modify Curve** ノードを探して追加します。 + +追加したらノード上で **右クリック** して、**Add Curve Pin** を選択し、変更する関連カーブを選択します。 + +![](AddCurvePin.png) + +ピンを取り除くには、再度ノード上で **右クリック** して、**[Remove Curve Pin]** を選択するか、ピンの上で **右クリック** して、**[Remove This Curve Pin]** を選択します。 + +公開された float ピンを使って、値を操作するためのロジックを定義することができます (以下のロジックでは時間経過に従いクマの目が光るのを調整しています)。 + +![](CurveLogic.png) diff --git a/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/ModifyCurve/ModifyCurve.KOR.udn b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/ModifyCurve/ModifyCurve.KOR.udn new file mode 100644 index 000000000000..11fc26b7c2b9 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/ModifyCurve/ModifyCurve.KOR.udn @@ -0,0 +1,59 @@ +INTSourceChangelist:0 +Availability:Public +Title:Modify Curve +Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/NodeReference, Engine/Animation/NodeReference/SkeletalControls +Description:Describes the Modify Curve node which can be used to modify animation curves with arbitrary logic inside Animation Graphs. +Related: Engine/Animation/Sequences/Curves +Related: Engine/Animation/NodeReference/SkeletalControls +Related: Engine/Animation/AnimBlueprints +Related: Engine/Animation/AnimBlueprints/AnimGraph +Related: Engine/Animation/StateMachines +version: 4.15 +type:reference +topic-image:ModifyCurveNode.png +tags:Animation +tags:Animation Blueprint +tags:Animation Curves +tags:Skeletal Controls + + +The **Modify Curve** control can be used to expose [Animation Curve](Engine/Animation/Sequences/Curves) data which can be modified using arbitrary logic to enable more dynamically-driven animations. + +![](ModifyCurveNode.png) + +Below, the Modify Curve node is used to drive a curve called **Eye Glow Intensity** where the bear's eyes glow brighter over time. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + tYN-osmLeKE + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +Inside the [](Engine/Animation/AnimBlueprints/AnimGraph) of your [](Engine/Animation/AnimBlueprints), **Right-click** and search for and add the **Modify Curve** node + +Once added, **Right-click** on the node and select **Add Curve Pin** and any associated curves you wish to modify. + +![](AddCurvePin.png) + +Pins can be removed by **Right-clicking** on the node again and selecting **Remove Curve Pin** or by **Right-clicking** on the pin itself and selecting **Remove This Curve Pin**. + +With the exposed float pin, you can define any logic you wish to drive the value (below logic is used to adjust the glow of our bear's eyes over time). + +![](CurveLogic.png) + + + + + diff --git a/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/RigidBody/RigidBody.CHN.udn b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/RigidBody/RigidBody.CHN.udn new file mode 100644 index 000000000000..f40e049c1fc0 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/RigidBody/RigidBody.CHN.udn @@ -0,0 +1,77 @@ +INTSourceChangelist:0 +Availability:Docs +Crumbs: %ROOT% +Title:Rigid Body +Description:Describes the Rigid Body node and how it can be used as a lightweight physics simulation inside Animation Blueprints. +Type:reference +Version: 4.16 +Parent:Engine/Animation/NodeReference/SkeletalControls +Order:1 +tags:Animation +tags:Animation Blueprint +tags:Skeletal Controls +topic-image:RigidBodyNode.png +Related: Engine/Physics/PhAT +Related: Engine/Physics/PhAT/Reference +Related: Engine/Animation/AnimBlueprints/AnimGraph +Related: Engine/Animation/NodeReference/Blend + +The **Rigid Body** Skeletal Control node can be used to create large amounts of physically-simulated characters using the high-performance **Immediate Mode** PhysX API. +The Rigid Body node (pictued below) can be added to the **AnimGraph** of your [](Engine/Animation/AnimBlueprints) and can even be used with any [](Engine/Animation/NodeReference/Blend/), enabling you to switch from a pose into a simulated physics state. +Characters using this simulation can also generate collision with static geometry in the world. + +![](RigidBodyNode.png) + +Using this node, several simulated characters below are able to respond to an impulse and switch from an idle into a physics simulated state. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + VaxxVsv0Fak + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +## Setup + +Before using this node, inside your [Physics Asset](Engine/Physics/PhAT) set the [](Engine/Physics/PhysicsBodies/) you want to simulate to **Simulated**. + +![](RigidBody_02.png) + +[REGION:caption] +Above we **Right-clicked** on our character's **Pelvis** bone and set all bodies below it to **Simulated** so our character fully simulates physics. +[/REGION] + +With your Physics Asset set up, inside the AnimGraph of your Animation Blueprint, add the Rigid Body node and the necessary logic to define when to use it. + +![](RigidBody_11.png) + +[REGION:caption] +Above the Rigid Body node is connected to a blend node that we switch to when the characters are affected by our impulse, causing them to simulate physics. +[/REGION] + +With the Rigid Body node selected, you can change properites that define how the node is used from the **Details** panel. + +![](RigidBody_12.png) + +| Property | Description | +| -------- | ----------- | +| **Override Physics Asset** | Physics asset to use. If empty, the Skeletal Mesh's default Physics Asset will be used. | +| **Override World Gravity** | Enables specification of a vector value to override gravity for this body. | +| **Overlap Channel** | The channel used to find static geometry to collide with. | +| **Component Space Simulation** | When true, simulation is done in component space. This means velocity is only inherited by animated bodies.| +| **Cached Bounds Scale** | Scale of cached bounds (versus actual bounds). Increasing this may improve performance, but overlaps may not work as well. A value of 1.0 effectively disables cached bounds. | +| **(As Pin) Alpha** | Shows the Alpha property as a pin on the node or in the Details panel. | +| **Alpha Scale Bias** | Set the Minimal and Maximal Influence values for the Alpha property. | + +[INCLUDE:Engine/Animation/NodeReference/SkeletalControls#lodthresh] diff --git a/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/RigidBody/RigidBody.INT.udn b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/RigidBody/RigidBody.INT.udn new file mode 100644 index 000000000000..13d2369d202d --- /dev/null +++ b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/RigidBody/RigidBody.INT.udn @@ -0,0 +1,76 @@ +Availability:Docs +Crumbs: %ROOT% +Title:Rigid Body +Description:Describes the Rigid Body node and how it can be used as a lightweight physics simulation inside Animation Blueprints. +Type:reference +Version: 4.16 +Parent:Engine/Animation/NodeReference/SkeletalControls +Order:1 +tags:Animation +tags:Animation Blueprint +tags:Skeletal Controls +topic-image:RigidBodyNode.png +Related: Engine/Physics/PhAT +Related: Engine/Physics/PhAT/Reference +Related: Engine/Animation/AnimBlueprints/AnimGraph +Related: Engine/Animation/NodeReference/Blend + +The **Rigid Body** Skeletal Control node can be used to create large amounts of physically-simulated characters using the high-performance **Immediate Mode** PhysX API. +The Rigid Body node (pictued below) can be added to the **AnimGraph** of your [](Engine/Animation/AnimBlueprints) and can even be used with any [](Engine/Animation/NodeReference/Blend/), enabling you to switch from a pose into a simulated physics state. +Characters using this simulation can also generate collision with static geometry in the world. + +![](RigidBodyNode.png) + +Using this node, several simulated characters below are able to respond to an impulse and switch from an idle into a physics simulated state. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + VaxxVsv0Fak + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +## Setup + +Before using this node, inside your [Physics Asset](Engine/Physics/PhAT) set the [](Engine/Physics/PhysicsBodies/) you want to simulate to **Simulated**. + +![](RigidBody_02.png) + +[REGION:caption] +Above we **Right-clicked** on our character's **Pelvis** bone and set all bodies below it to **Simulated** so our character fully simulates physics. +[/REGION] + +With your Physics Asset set up, inside the AnimGraph of your Animation Blueprint, add the Rigid Body node and the necessary logic to define when to use it. + +![](RigidBody_11.png) + +[REGION:caption] +Above the Rigid Body node is connected to a blend node that we switch to when the characters are affected by our impulse, causing them to simulate physics. +[/REGION] + +With the Rigid Body node selected, you can change properites that define how the node is used from the **Details** panel. + +![](RigidBody_12.png) + +| Property | Description | +| -------- | ----------- | +| **Override Physics Asset** | Physics asset to use. If empty, the Skeletal Mesh's default Physics Asset will be used. | +| **Override World Gravity** | Enables specification of a vector value to override gravity for this body. | +| **Overlap Channel** | The channel used to find static geometry to collide with. | +| **Component Space Simulation** | When true, simulation is done in component space. This means velocity is only inherited by animated bodies.| +| **Cached Bounds Scale** | Scale of cached bounds (versus actual bounds). Increasing this may improve performance, but overlaps may not work as well. A value of 1.0 effectively disables cached bounds. | +| **(As Pin) Alpha** | Shows the Alpha property as a pin on the node or in the Details panel. | +| **Alpha Scale Bias** | Set the Minimal and Maximal Influence values for the Alpha property. | + +[INCLUDE:Engine/Animation/NodeReference/SkeletalControls#lodthresh] diff --git a/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/RigidBody/RigidBody.JPN.udn b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/RigidBody/RigidBody.JPN.udn new file mode 100644 index 000000000000..f40e049c1fc0 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/RigidBody/RigidBody.JPN.udn @@ -0,0 +1,77 @@ +INTSourceChangelist:0 +Availability:Docs +Crumbs: %ROOT% +Title:Rigid Body +Description:Describes the Rigid Body node and how it can be used as a lightweight physics simulation inside Animation Blueprints. +Type:reference +Version: 4.16 +Parent:Engine/Animation/NodeReference/SkeletalControls +Order:1 +tags:Animation +tags:Animation Blueprint +tags:Skeletal Controls +topic-image:RigidBodyNode.png +Related: Engine/Physics/PhAT +Related: Engine/Physics/PhAT/Reference +Related: Engine/Animation/AnimBlueprints/AnimGraph +Related: Engine/Animation/NodeReference/Blend + +The **Rigid Body** Skeletal Control node can be used to create large amounts of physically-simulated characters using the high-performance **Immediate Mode** PhysX API. +The Rigid Body node (pictued below) can be added to the **AnimGraph** of your [](Engine/Animation/AnimBlueprints) and can even be used with any [](Engine/Animation/NodeReference/Blend/), enabling you to switch from a pose into a simulated physics state. +Characters using this simulation can also generate collision with static geometry in the world. + +![](RigidBodyNode.png) + +Using this node, several simulated characters below are able to respond to an impulse and switch from an idle into a physics simulated state. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + VaxxVsv0Fak + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +## Setup + +Before using this node, inside your [Physics Asset](Engine/Physics/PhAT) set the [](Engine/Physics/PhysicsBodies/) you want to simulate to **Simulated**. + +![](RigidBody_02.png) + +[REGION:caption] +Above we **Right-clicked** on our character's **Pelvis** bone and set all bodies below it to **Simulated** so our character fully simulates physics. +[/REGION] + +With your Physics Asset set up, inside the AnimGraph of your Animation Blueprint, add the Rigid Body node and the necessary logic to define when to use it. + +![](RigidBody_11.png) + +[REGION:caption] +Above the Rigid Body node is connected to a blend node that we switch to when the characters are affected by our impulse, causing them to simulate physics. +[/REGION] + +With the Rigid Body node selected, you can change properites that define how the node is used from the **Details** panel. + +![](RigidBody_12.png) + +| Property | Description | +| -------- | ----------- | +| **Override Physics Asset** | Physics asset to use. If empty, the Skeletal Mesh's default Physics Asset will be used. | +| **Override World Gravity** | Enables specification of a vector value to override gravity for this body. | +| **Overlap Channel** | The channel used to find static geometry to collide with. | +| **Component Space Simulation** | When true, simulation is done in component space. This means velocity is only inherited by animated bodies.| +| **Cached Bounds Scale** | Scale of cached bounds (versus actual bounds). Increasing this may improve performance, but overlaps may not work as well. A value of 1.0 effectively disables cached bounds. | +| **(As Pin) Alpha** | Shows the Alpha property as a pin on the node or in the Details panel. | +| **Alpha Scale Bias** | Set the Minimal and Maximal Influence values for the Alpha property. | + +[INCLUDE:Engine/Animation/NodeReference/SkeletalControls#lodthresh] diff --git a/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/RigidBody/RigidBody.KOR.udn b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/RigidBody/RigidBody.KOR.udn new file mode 100644 index 000000000000..f40e049c1fc0 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/RigidBody/RigidBody.KOR.udn @@ -0,0 +1,77 @@ +INTSourceChangelist:0 +Availability:Docs +Crumbs: %ROOT% +Title:Rigid Body +Description:Describes the Rigid Body node and how it can be used as a lightweight physics simulation inside Animation Blueprints. +Type:reference +Version: 4.16 +Parent:Engine/Animation/NodeReference/SkeletalControls +Order:1 +tags:Animation +tags:Animation Blueprint +tags:Skeletal Controls +topic-image:RigidBodyNode.png +Related: Engine/Physics/PhAT +Related: Engine/Physics/PhAT/Reference +Related: Engine/Animation/AnimBlueprints/AnimGraph +Related: Engine/Animation/NodeReference/Blend + +The **Rigid Body** Skeletal Control node can be used to create large amounts of physically-simulated characters using the high-performance **Immediate Mode** PhysX API. +The Rigid Body node (pictued below) can be added to the **AnimGraph** of your [](Engine/Animation/AnimBlueprints) and can even be used with any [](Engine/Animation/NodeReference/Blend/), enabling you to switch from a pose into a simulated physics state. +Characters using this simulation can also generate collision with static geometry in the world. + +![](RigidBodyNode.png) + +Using this node, several simulated characters below are able to respond to an impulse and switch from an idle into a physics simulated state. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + VaxxVsv0Fak + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +## Setup + +Before using this node, inside your [Physics Asset](Engine/Physics/PhAT) set the [](Engine/Physics/PhysicsBodies/) you want to simulate to **Simulated**. + +![](RigidBody_02.png) + +[REGION:caption] +Above we **Right-clicked** on our character's **Pelvis** bone and set all bodies below it to **Simulated** so our character fully simulates physics. +[/REGION] + +With your Physics Asset set up, inside the AnimGraph of your Animation Blueprint, add the Rigid Body node and the necessary logic to define when to use it. + +![](RigidBody_11.png) + +[REGION:caption] +Above the Rigid Body node is connected to a blend node that we switch to when the characters are affected by our impulse, causing them to simulate physics. +[/REGION] + +With the Rigid Body node selected, you can change properites that define how the node is used from the **Details** panel. + +![](RigidBody_12.png) + +| Property | Description | +| -------- | ----------- | +| **Override Physics Asset** | Physics asset to use. If empty, the Skeletal Mesh's default Physics Asset will be used. | +| **Override World Gravity** | Enables specification of a vector value to override gravity for this body. | +| **Overlap Channel** | The channel used to find static geometry to collide with. | +| **Component Space Simulation** | When true, simulation is done in component space. This means velocity is only inherited by animated bodies.| +| **Cached Bounds Scale** | Scale of cached bounds (versus actual bounds). Increasing this may improve performance, but overlaps may not work as well. A value of 1.0 effectively disables cached bounds. | +| **(As Pin) Alpha** | Shows the Alpha property as a pin on the node or in the Details panel. | +| **Alpha Scale Bias** | Set the Minimal and Maximal Influence values for the Alpha property. | + +[INCLUDE:Engine/Animation/NodeReference/SkeletalControls#lodthresh] diff --git a/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/SkeletalControls.INT.udn b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/SkeletalControls.INT.udn index 37543a11f2b4..d7f9539757f8 100644 --- a/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/SkeletalControls.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/SkeletalControls.INT.udn @@ -1,26 +1,29 @@ -Availability:Public +Availability: Docs +Crumbs: %ROOT% Title:Skeletal Controls -Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/NodeReference -Description:Animation nodes that allow for direct manipulation and applying solvers to the bones of the target Skeleton. -version: 4.12 +Description:Animation nodes that enable direct manipulation and applying solvers to the bones of the target Skelet +Type: Landing +Version: 4.16 +Parent: Engine/Animation/NodeReference +Order: 1 +Tags:Animation +Tags:Animation Blending +Tags:Skeletal Controls +topic-image:SkeletalControlTopicCompact.png [REGION:banner] ![Skeletal Control](skelcontrol_banner.png)(convert:false) [/REGION] [EXCERPT:Intro] -**SkeletalControls** (also called **SkelControls**) allow direct control of bones within a Skeleton. These can be -used within Animation Blueprints to control an individual bone, create IK chains, and more. This direct control of the -underlying Skeleton provides the ability to create procedural, dynamically-driven animation. The **Transform** of -one bone can be used to drive another or can be used to conform the feet of a character to the ground while -playing a generic walk animation. Any sort of modification can be used to tweak or completely override the bone -Transforms applied by AnimationSequences. +**Skeletal Controls** (also called **SkelControls**) enables direct control of bones within a [Skeleton](Engine/Animation/Skeleton) asset. These can be used within [Animation Blueprints](Engine/Animation/AnimBlueprints) to control an individual bone, create IK chains, and more. This direct control of the underlying Skeleton provides the ability to create procedural, dynamically-driven animation. The **Transform** of one bone can be used to drive another, or can be used to conform the feet of a character to the ground while +playing a walk animation. Any sort of modification can be used to tweak or completely override the bone transforms applied by [Animation Sequences](Engine/Animation/Sequences). [/EXCERPT:Intro] ## Common Pins and Properties -Some pins and properties are common to all SkeletalControls. These are described below. +While the properties available will largely based on the node itself, some pins and properties are common to all SkeletalControls which are outlined below. | Pin | Description | | --- | ----------- | @@ -35,7 +38,7 @@ Some pins and properties are common to all SkeletalControls. These are described | Property | Description | | --- | --- | -| **LOD Threshold** | This is the max Level of Detail (**LOD**) that this node is permitted to run on. For example: if you have LOD Threshold set to **2**, it will run until **LOD 2**, but disable itself once the component's LOD becomes **3**. | +| **LOD Threshold** | This is the max Level of Detail (LOD) that this node is permitted to run on. For example: if you have LOD Threshold set to 2, it will run until LOD 2, but disable itself once the component's LOD becomes 3. | [/EXCERPT] @@ -56,7 +59,7 @@ Below are links to additional pages with information about each of the Skeletal ![](%ROOT%/start_icon.png)(convert:false) [/PARAM] [PARAM:title] - Skeletal Control + Skeletal Controls [/PARAM] [PARAM:links] * [](Engine\Animation\NodeReference\SkeletalControls\AnimDynamics "%Engine\Animation\NodeReference\SkeletalControls\AnimDynamics:description%") @@ -65,12 +68,15 @@ Below are links to additional pages with information about each of the Skeletal * [](Engine\Animation\NodeReference\SkeletalControls\CopyBone "%Engine\Animation\NodeReference\SkeletalControls\CopyBone:description%") * [](Engine\Animation\NodeReference\SkeletalControls\HandIKRetargeting "%Engine\Animation\NodeReference\SkeletalControls\HandIKRetargeting:description%") * [](Engine\Animation\NodeReference\SkeletalControls\LookAt "%Engine\Animation\NodeReference\SkeletalControls\LookAt:description%") + * [](Engine\Animation\NodeReference\SkeletalControls\SplineIK "%Engine\Animation\NodeReference\SkeletalControls\SplineIK:description%") * [](Engine\Animation\NodeReference\SkeletalControls\SpringController "%Engine\Animation\NodeReference\SkeletalControls\SpringController:description%") + * [](Engine\Animation\NodeReference\SkeletalControls\ModifyCurve "%Engine\Animation\NodeReference\SkeletalControls\ModifyCurve:description%") * [](Engine\Animation\NodeReference\SkeletalControls\TransformBone "%Engine\Animation\NodeReference\SkeletalControls\TransformBone:description%") * [](Engine\Animation\NodeReference\SkeletalControls\TrailController "%Engine\Animation\NodeReference\SkeletalControls\TrailController:description%") * [](Engine\Animation\NodeReference\SkeletalControls\TwistCorrective "%Engine\Animation\NodeReference\SkeletalControls\TwistCorrective:description%") * [](Engine\Animation\NodeReference\SkeletalControls\TwoBoneIK "%Engine\Animation\NodeReference\SkeletalControls\TwoBoneIK:description%") - * [](Engine\Animation\NodeReference\SkeletalControls\ObserveBone "%Engine\Animation\NodeReference\SkeletalControls\ObserveBone:description%") + * [](Engine\Animation\NodeReference\SkeletalControls\ObserveBone "%Engine\Animation\NodeReference\SkeletalControls\ObserveBone:description%") + * [](Engine\Animation\NodeReference\SkeletalControls\RigidBody "%Engine\Animation\NodeReference\SkeletalControls\RigidBody:description%") [/PARAM] [/OBJECT] @@ -89,4 +95,4 @@ Below are links to additional pages with information about each of the Skeletal %Engine\Animation\NodeReference\SkeletalControls\TwoBoneIK:TopicCompact% %Engine\Animation\NodeReference\SkeletalControls\ObserveBone:TopicCompact% [/REGION] ---> \ No newline at end of file +--> diff --git a/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/SkeletalControls.JPN.udn b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/SkeletalControls.JPN.udn index 5f43b70f0a07..8d44fd0b86dd 100644 --- a/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/SkeletalControls.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/SkeletalControls.JPN.udn @@ -1,27 +1,30 @@ -INTSourceChangelist:3068762 -Availability:Public +INTSourceChangelist:3477876 +Availability:Docs +Crumbs: %ROOT% Title:スケルタル制御 -Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/NodeReference Description:ターゲット スケルトンのボーンを直接操作し、ソルバを適用できるアニメーション ノードについて説明します。 -version:4.12 +Type:Landing +Version:4.16 +Parent:Engine/Animation/NodeReference +Order:1 +Tags:Animation +Tags:Animation Blending +Tags:Skeletal Controls +topic-image:SkeletalControlTopicCompact.png [REGION:banner] ![Skeletal Control](skelcontrol_banner.png)(convert:false) [/REGION] [EXCERPT:Intro] -**SkeletalControls (スケルタル制御)** (**SkelControls** とも呼ばれます) を使用すると、スケルトン内のボーンを直接制御することができます。個々のボーンの制御、IK チェーンの作成などのために -Animation ブループリント内で使用します。下層スケルトンを直接制御することで、 -プロシージャルで動的に動くアニメーションを作成することができます。あるボーンの **トランスフォーム** を別のボーンを動かすために使用したり、 -通常の歩くアニメーションの再生中に、トレースを使用してキャラクターの足と地面を -同調させることができます。アニメーション シーケンスで適用したボーンのトランスフォームを微調整したり、 -完全にオーバーライドするために、どのような種類の修正でも使用できます。 +**SkeletalControls (スケルタル制御)** (**SkelControls** とも呼ばれます) を使用すると、[Skeleton](Engine/Animation/Skeleton) アセット内のボーンを直接制御することができます。[Animation ブループリント](Engine/Animation/AnimBlueprints) 内でスケルタル制御を使って、個々のボーンの制御、IK チェーンの作成などを行うことができます。基本となるスケルトンを直接制御することで、プロシージャルな動的に動くアニメーションを作成することができます。あるボーンの **トランスフォーム** を使って、他のボーンを操作したり、歩行アニメーションの再生中に、キャラクターの足と地面を +同調させることができます。何らかの変更を加えて [アニメーション シーケンス](Engine/Animation/Sequences) で適用したボーンのトランスフォームを微調整したり、完全にオーバーライドすることができます。 [/EXCERPT:Intro] ## 共通のピンとプロパティ -全てのスケルタル制御で以下のように共通のピンとプロパティがあります。 +利用可能なプロパティは主にノード自体によって決まりますが、以下のように一部のピンやプロパティはすべてのスケルタル制御で共通になっています。 | ピン | 説明 | | --- | ----------- | @@ -29,14 +32,14 @@ Animation ブループリント内で使用します。下層スケルトンを | **Component Pose** | トランスフォームさせる入力ポーズです。 | | **Alpha** | スケルタル制御で適用されるトランスフォームの重み付けを決定するためのアルファ値として使用する [0.0, 1.0] 範囲の浮動小数点値です。値 0.0 は入力ポーズに最大限の重み付けをし、値 1.0 は制御の計算をしたトランスフォームに対し最大限の重み付けをします。| | [REGION:tablesection]**出力ピン**[/REGION] || -| **Pose (Blank)** | トランスフォーム適用後の最終ポーズ | +| **Pose (Blank)** | トランスフォーム適用後の最終ポーズです。 | [EXCERPT:LODThresh] ![](perf.png) | プロパティ | 説明 | | --- | --- | -| **LOD Threshold** | このノードで実行が認められている最高 LOD (Level of Detail) (**LOD**) です。例えば、LOD Threshold を **2** に設定すると、**LOD 2** になるまでは実行しますが、コンポーネントの LOD が **3** になると無効になります。 | +| **LOD Threshold** | このノードで実行が認められている最高 LOD (Level of Detail) です。例えば、LOD Threshold を 2 に設定すると、LOD 2 になるまでは実行しますが、コンポーネントの LOD が 3 になると無効になります。 | [/EXCERPT] @@ -57,7 +60,7 @@ SpaceConversion (空間変換) ノードに関する詳細は、[](Engine/Animat ![](%ROOT%/start_icon.png)(convert:false) [/PARAM] [PARAM:title] - Skeletal Control + スケルタル制御 [/PARAM] [PARAM:links] * [](Engine\Animation\NodeReference\SkeletalControls\AnimDynamics "%Engine\Animation\NodeReference\SkeletalControls\AnimDynamics:description%") @@ -66,12 +69,15 @@ SpaceConversion (空間変換) ノードに関する詳細は、[](Engine/Animat * [](Engine\Animation\NodeReference\SkeletalControls\CopyBone "%Engine\Animation\NodeReference\SkeletalControls\CopyBone:description%") * [](Engine\Animation\NodeReference\SkeletalControls\HandIKRetargeting "%Engine\Animation\NodeReference\SkeletalControls\HandIKRetargeting:description%") * [](Engine\Animation\NodeReference\SkeletalControls\LookAt "%Engine\Animation\NodeReference\SkeletalControls\LookAt:description%") + * [](Engine\Animation\NodeReference\SkeletalControls\SplineIK "%Engine\Animation\NodeReference\SkeletalControls\SplineIK:description%") * [](Engine\Animation\NodeReference\SkeletalControls\SpringController "%Engine\Animation\NodeReference\SkeletalControls\SpringController:description%") + * [](Engine\Animation\NodeReference\SkeletalControls\ModifyCurve "%Engine\Animation\NodeReference\SkeletalControls\ModifyCurve:description%") * [](Engine\Animation\NodeReference\SkeletalControls\TransformBone "%Engine\Animation\NodeReference\SkeletalControls\TransformBone:description%") * [](Engine\Animation\NodeReference\SkeletalControls\TrailController "%Engine\Animation\NodeReference\SkeletalControls\TrailController:description%") * [](Engine\Animation\NodeReference\SkeletalControls\TwistCorrective "%Engine\Animation\NodeReference\SkeletalControls\TwistCorrective:description%") * [](Engine\Animation\NodeReference\SkeletalControls\TwoBoneIK "%Engine\Animation\NodeReference\SkeletalControls\TwoBoneIK:description%") - * [](Engine\Animation\NodeReference\SkeletalControls\ObserveBone "%Engine\Animation\NodeReference\SkeletalControls\ObserveBone:description%") + * [](Engine\Animation\NodeReference\SkeletalControls\ObserveBone "%Engine\Animation\NodeReference\SkeletalControls\ObserveBone:description%") + * [](Engine\Animation\NodeReference\SkeletalControls\RigidBody "%Engine\Animation\NodeReference\SkeletalControls\RigidBody:description%") [/PARAM] [/OBJECT] @@ -90,4 +96,4 @@ SpaceConversion (空間変換) ノードに関する詳細は、[](Engine/Animat %Engine\Animation\NodeReference\SkeletalControls\TwoBoneIK:TopicCompact% %Engine\Animation\NodeReference\SkeletalControls\ObserveBone:TopicCompact% [/REGION] ---> \ No newline at end of file +--> diff --git a/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/SkeletalControls.KOR.udn b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/SkeletalControls.KOR.udn index 1c692223afb4..d0555a501439 100644 --- a/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/SkeletalControls.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/SkeletalControls.KOR.udn @@ -1,21 +1,18 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3464851 Availability:Public Title:스켈레탈 콘트롤 Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/NodeReference -Description:타겟 스켈레톤의 본을 직접 조작하거나 솔버 적용이 가능한 애니메이션 노드입니다. -version: 4.12 +Description:타겟 스켈레톤의 본을 직접 조작하거나 솔버를 적용시킬 수 있는 애니메이션 노드입니다. +version: 4.16 +topic-image:Engine/Animation/Overview/SkeletonControlTopic.png [REGION:banner] ![Skeletal Control](skelcontrol_banner.png)(convert:false) [/REGION] [EXCERPT:Intro] -**_SkeletalControl_** (스켈레탈 콘트롤) (또는 _SkelControl_ (스켈 콘트롤))을 통해 스켈레톤에 있는 본을 직접 제어할 -수 있습니다. _Animation Blueprint_ (애니메이션 블루프린트) 안에서 사용되며, 개별 본 제어, IK 체인 생성 등의 작업에 쓰입니다. -내재된 _스켈레톤_ 에 대한 직접 제어할 수 있다는 것은, 절차적이고 동적으로 구동되는 애니메이션을 만들 수 있다는 -것입니다. 하나의 본에 대한 _Transform_ (트랜스폼) 작업이 다른 본을 움직일 수도 있고, 캐릭터에 일반적인 걷기 애니메이션을 -재생할 때 땅에 발을 일치시킬 수도 있습니다. _AnimationSequence_ (애니메이션 시퀀스)에 의해 적용된 -본 _트랜스폼_ 을 조정하거나 완전 덮어쓰는 데 있어 어떠한 종류의 변경도 가능합니다. +**SkeletalControl** (스켈레탈 콘트롤) (또는 SkelControl (스켈 콘트롤))을 통해 스켈레톤에 있는 본을 직접 제어할 수 있습니다. Animation Blueprint (애니메이션 블루프린트) 안에서 사용되며, 개별 본 제어, IK 체인 생성 등의 작업에 쓰입니다.내재된 스켈레톤에 대한 직접 제어할 수 있다는 것은, 절차적이고 동적으로 구동되는 애니메이션을 만들 수 있다는 것입니다. 하나의 본에 대한 Transform(트랜스폼) 작업이 다른 본을 움직일 수도 있고, 캐릭터에 걷기 애니메이션을 재생할 때 땅에 발을 일치시킬 수도 있습니다. +AnimationSequence (애니메이션 시퀀스)에 의해 적용된 본 트랜스폼을 조정하거나 완전 덮어쓰는 데 있어 어떠한 종류의 변경도 가능합니다. [/EXCERPT:Intro] @@ -36,7 +33,7 @@ version: 4.12 | 프로퍼티 | 설명 | | --- | --- | -| **LOD Threshold** | LOD 한계치 - 이 노드의 실행 대상이 될 수 있는 최대 레벨 오브 디테일 (**LOD**) 입니다. 예: LOD 한계치가 **2** 로 설정된 경우, **LOD 2** 까지만 실행되고, 컴포넌트의 LOD 가 **3** 이 되면 스스로 꺼집니다. | +| **LOD Threshold** | LOD 한계치 - 이 노드의 실행 대상이 될 수 있는 최대 레벨 오브 디테일 (LOD) 입니다. 예: LOD 한계치가 2 로 설정된 경우, LOD 2 까지만 실행되고, 컴포넌트의 LOD 가 3 이 되면 스스로 꺼집니다. | [/EXCERPT] @@ -66,7 +63,9 @@ version: 4.12 * [](Engine\Animation\NodeReference\SkeletalControls\CopyBone "%Engine\Animation\NodeReference\SkeletalControls\CopyBone:description%") * [](Engine\Animation\NodeReference\SkeletalControls\HandIKRetargeting "%Engine\Animation\NodeReference\SkeletalControls\HandIKRetargeting:description%") * [](Engine\Animation\NodeReference\SkeletalControls\LookAt "%Engine\Animation\NodeReference\SkeletalControls\LookAt:description%") + * [](Engine\Animation\NodeReference\SkeletalControls\SplineIK "%Engine\Animation\NodeReference\SkeletalControls\SplineIK:description%") * [](Engine\Animation\NodeReference\SkeletalControls\SpringController "%Engine\Animation\NodeReference\SkeletalControls\SpringController:description%") + * [](Engine\Animation\NodeReference\SkeletalControls\ModifyCurve "%Engine\Animation\NodeReference\SkeletalControls\ModifyCurve:description%") * [](Engine\Animation\NodeReference\SkeletalControls\TransformBone "%Engine\Animation\NodeReference\SkeletalControls\TransformBone:description%") * [](Engine\Animation\NodeReference\SkeletalControls\TrailController "%Engine\Animation\NodeReference\SkeletalControls\TrailController:description%") * [](Engine\Animation\NodeReference\SkeletalControls\TwistCorrective "%Engine\Animation\NodeReference\SkeletalControls\TwistCorrective:description%") diff --git a/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/SplineIK/SplineIK.CHN.udn b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/SplineIK/SplineIK.CHN.udn new file mode 100644 index 000000000000..6fe5eb4875e8 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/SplineIK/SplineIK.CHN.udn @@ -0,0 +1,80 @@ +INTSourceChangelist:0 +Availability:Public +Title:Spline IK +Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/NodeReference, Engine/Animation/NodeReference/SkeletalControls +Description:Describes how the Spline IK Solver node can be used for controlling character spines or bone chains within Animation Blueprints. +version: 4.16 +Related: Engine/Animation/NodeReference/SkeletalControls +Related: Engine/Animation/AnimBlueprints +Related: Engine/Animation/AnimBlueprints/AnimGraph +Related: Engine/BlueprintSplines +Related: Engine/Landscape/Editing/Splines +type:reference +topic-image:SplineIKnode.png +tags:Animation +tags:Skeletal Controls +tags:Animation Graph + +The **Spline IK** Skeletal Control Node can be used to specify a Bone to trace or follow another Bone in the Skeleton. + +![](SplineIKnode.png) + +Below, we add the Spline IK node to our Animation Blueprint to control the character's spine. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + FEth0mMla0I + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +The Spline IK control node constrains a chain of specified bones to a spline within an Animation Blueprint as **Control Points**. +Those Control Points can be driven by external values, with additional options for Roll and Twist (as well as Twist blending options). +See the table below for a full breakdown of the properties available for the Spline IK node. + +| Property | Description | +| -------- | ----------- | +| [REGION:tablesection]**Parameters**[/REGION] || +| **Start Bone** | Name of the root bone from which the spline extends.| +| **End Bone** | Name of the bone at the end of the spline chain (bones after this will not be altered by the controller). | +| **Bone Axis** | Axis of the controlled bone (i.e the direction of the spline) to use as the direction for the curve. | +| **Auto Calculate Spline** | Whether the number of points in the spline should be automatically generated. | +| **Point Count** | The number of points in the spline if we are not auto-calculating. | +| **(As Pin) Control Points** | Transforms applied to spline points. | +| **(As Pin) Roll** | Overall roll of the spline, applied on top of other rotations along the direction of the spline. | +| **(As Pin) Twist Start** | The twist of the start bone. Twist is interpolated along the spline according to Twist Blend. | +| **(As Pin) Twist End** | The twist of the end bone. Twist is interpolated along the spline according to Twist Blend. | +| **(As Pin) Stretch** | The maximum stretch allowed when fitting bones to the spline. 0.0 means bones do not stretch their length while 1.0 means bones stretch to the length of the spline.| +| **(As Pin) Offset** | The distance along the spline from the start from which bones are constrained. | +| [REGION:tablesection]**Twist Blend**[/REGION] || +| **Blend Option** | The type of [Animation Blending Mode](Engine/Animation/NonLinearBlends) used. | +| **Custom Curve** | Enables you to specify a Custom Blend option where you specify the curve. | +| **Blend Time** | The duration of the blend. | +| [REGION:tablesection]**Settings**[/REGION] || +| **Alpha** | Current strength of the skeletal control. | +| **Alpha Scale Bias** | Defines the minimum and maximum scale bais for the Alpha property. | +| [REGION:tablesection]**Performance**[/REGION] || +| **LOD Threshold** | Max LOD that this node is allowed to run. | + +The following table outlines the pins that are enabled by default on the Spline IK node. + +| Pin | Description | +| --- | ----------- | +| [REGION:tablesection]**Input Pins**[/REGION] || +| **Component Pose** | The incoming pose. | +| **Alpha** | The current strength of the control. | + +Any of the properties denoted with **(As pin)** can be exposed on the node by checking their corresponding checkbox. + + diff --git a/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/SplineIK/SplineIK.INT.udn b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/SplineIK/SplineIK.INT.udn new file mode 100644 index 000000000000..30fd4c351df1 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/SplineIK/SplineIK.INT.udn @@ -0,0 +1,80 @@ +Availability:Public +Title:Spline IK +Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/NodeReference, Engine/Animation/NodeReference/SkeletalControls +Description:Describes how the Spline IK Solver node can be used for controlling character spines or bone chains within Animation Blueprints. +version: 4.16 +Related: Engine/Animation/NodeReference/SkeletalControls +Related: Engine/Animation/AnimBlueprints +Related: Engine/Animation/AnimBlueprints/AnimGraph +Related: Engine/BlueprintSplines +Related: Engine/Landscape/Editing/Splines +type:reference +topic-image:SplineIKnode.png +tags:Animation +tags:Skeletal Controls +tags:Animation Graph + +The **Spline IK **control node constrains a chain of specified bones to a spline within an Animation Blueprint as **Control Points**. + +![](SplineIKnode.png) + +Control Points can be driven by external values, with additional options for **Roll** and **Twist** (as well as **Twist Blend** options). + +Below, we add the Spline IK node to our Animation Blueprint to control the character's spine. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + FEth0mMla0I + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +See the table below for a full breakdown of the properties available for the Spline IK node. + +| Property | Description | +| -------- | ----------- | +| [REGION:tablesection]**Parameters**[/REGION] || +| **Start Bone** | Name of the root bone from which the spline extends.| +| **End Bone** | Name of the bone at the end of the spline chain (bones after this will not be altered by the controller). | +| **Bone Axis** | Axis of the controlled bone (for example, the direction of the spline) to use as the direction for the curve. | +| **Auto Calculate Spline** | Whether the number of points in the spline should be automatically generated. | +| **Point Count** | The number of points in the spline if we are not auto-calculating. | +| **(As Pin) Control Points** | Transforms applied to spline points. | +| **(As Pin) Roll** | Overall roll of the spline, applied on top of other rotations along the direction of the spline. | +| **(As Pin) Twist Start** | The twist of the start bone. Twist is interpolated along the spline according to Twist Blend. | +| **(As Pin) Twist End** | The twist of the end bone. Twist is interpolated along the spline according to Twist Blend. | +| **(As Pin) Stretch** | The maximum stretch allowed when fitting bones to the spline. 0.0 means bones do not stretch their length while 1.0 means bones stretch to the length of the spline.| +| **(As Pin) Offset** | The distance along the spline from the start from which bones are constrained. | +| [REGION:tablesection]**Twist Blend**[/REGION] || +| **Blend Option** | The type of [Animation Blending Mode](Engine/Animation/NonLinearBlends) used. | +| **Custom Curve** | Enables you to specify a Custom Blend option where you specify the curve. | +| **Blend Time** | The duration of the blend. | +| [REGION:tablesection]**Settings**[/REGION] || +| **Alpha** | Current strength of the skeletal control. | +| **Alpha Scale Bias** | Defines the minimum and maximum scale bias for the Alpha property. | +| [REGION:tablesection]**Performance**[/REGION] || +| **LOD Threshold** | Max LOD that this node is allowed to run. | + +The following table outlines the pins that are enabled by default on the Spline IK node. + +| Pin | Description | +| --- | ----------- | +| [REGION:tablesection]**Input Pins**[/REGION] || +| **Component Pose** | The incoming pose. | +| **Alpha** | The current strength of the control. | + +Any of the properties denoted with **(As pin)** can be exposed on the node by checking their corresponding checkbox. + + + diff --git a/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/SplineIK/SplineIK.JPN.udn b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/SplineIK/SplineIK.JPN.udn new file mode 100644 index 000000000000..c03db29bc3ad --- /dev/null +++ b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/SplineIK/SplineIK.JPN.udn @@ -0,0 +1,81 @@ +INTSourceChangelist:3473466 +Availability:Public +Title:スプライン IK +Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/NodeReference, Engine/Animation/NodeReference/SkeletalControls +Description:Spline IK Solver ノードを使って、Animation ブループリント内でキャラクターの背骨やボーン チェーンを制御する方法を説明します。 +version:4.16 +Related:Engine/Animation/NodeReference/SkeletalControls +Related:Engine/Animation/AnimBlueprints +Related:Engine/Animation/AnimBlueprints/AnimGraph +Related:Engine/BlueprintSplines +Related:Engine/Landscape/Editing/Splines +type:reference +topic-image:SplineIKnode.png +tags:Animation +tags:Skeletal Controls +tags:Animation Graph + +**Spline IK** 制御ノードは、Animation ブループリント内で指定したボーンのチェーンを **制御点** として制約します。 + +![](SplineIKnode.png) + +制御点は外部の値によって操作可能であり、**Roll** と **Twist** (および **Twist Blend** オプション) の追加オプションがあります。 + +以下では、Animation ブループリントに Spline IK ノードを追加し、キャラクターの背骨を制御します。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + FEth0mMla0I + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +Spline IK ノードで利用可能なプロパティについては以下の表をご覧ください。 + +| プロパティ | 説明 | +| -------- | ----------- | +| [REGION:tablesection]**パラメータ**[/REGION] || +| **Start Bone** | スプラインがそこから延びるルート ボーン名。 | +| **End Bone** | スプライン チェーンの終端のボーン名 (これより後のボーンはコントローラーによって変更されません)。 | +| **Bone Axis** | カーブの方向として使う制御されたボーンの軸 (例、スプラインの方向)。 | +| **Auto Calculate Spline** | スプラインのポイント数を自動的に生成するかどうかです。 | +| **Point Count** | 自動計算していない場合に、スプラインのポイント数。 | +| **(As Pin) Control Points** | スプライン ポイントに適用されるトランスフォーム。 | +| **(As Pin) Roll** | スプラインの方向に沿った他の回転の上に適用されるスプラインの全体的なロール (進行軸回転)。 | +| **(As Pin) Twist Start** | 開始ボーンのツイスト。Twist Blend に従いスプラインに沿ってツイストが補間されます。 | +| **(As Pin) Twist End** | 終了ボーンのツイスト。Twist Blend に従いスプラインに沿ってツイストが補間されます。 | +| **(As Pin) Stretch** | スプラインにボーンを適合させる場合に最大限許容される伸縮です。0.0 はボーンの長さが伸縮しないことを表し、1.0 はボーンがスプラインの長さまで伸縮することを意味します。| +| **(As Pin) Offset** | ボーンの拘束が開始するボーンの開始点からのスプラインの距離です。 | +| [REGION:tablesection]**Twist Blend**[/REGION] || +| **Blend Option** | 使用する [Animation ブレンド モード](Engine/Animation/NonLinearBlends) のタイプ。 | +| **Custom Curve** | カーブを指定する Custom Blend オプションを有効にします。 | +| **Blend Time** | ブレンドの持続期間。 | +| [REGION:tablesection]**設定**[/REGION] || +| **Alpha** | 現在のスケルタル制御の強さです。 | +| **Alpha Scale Bias** | Alpha プロパティの最小/最大のスケール バイアスを定義します。 | +| [REGION:tablesection]**パフォーマンス**[/REGION] || +| **LOD Threshold** | このノードで実行が認められている最高 LOD (Level of Detail) (LOD) です。 | + +以下の表では、スプライン IK ノードでデフォルトで有効になっているピンについて概要を示します。 + +| ピン | 説明 | +| --- | ----------- | +| [REGION:tablesection]**入力ピン**[/REGION] || +| **Component Pose** | 入力されるポーズです。 | +| **Alpha** | 現在の制御の強さです。 | + +**(As pin)** が付いているプロパティは、対応するチェックボックスをチェックすることでノード上で公開することができます。 + + + diff --git a/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/SplineIK/SplineIK.KOR.udn b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/SplineIK/SplineIK.KOR.udn new file mode 100644 index 000000000000..07ec3e3c9717 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Animation/NodeReference/SkeletalControls/SplineIK/SplineIK.KOR.udn @@ -0,0 +1,79 @@ +INTSourceChangelist:3467075 +Availability:Public +Title:Spline IK +Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/NodeReference, Engine/Animation/NodeReference/SkeletalControls +Description:Spline IK Solver 노드를 사용하여 애니메이션 블루프린트 안에서 캐릭터의 척추 또는 본 체인을 제어하는 방법 설명서입니다. +version: 4.16 +Related: Engine/Animation/NodeReference/SkeletalControls +Related: Engine/Animation/AnimBlueprints +Related: Engine/Animation/AnimBlueprints/AnimGraph +Related: Engine/BlueprintSplines +Related: Engine/Landscape/Editing/Splines +type:reference +topic-image:SplineIKnode.png +tags:Animation +tags:Skeletal Controls +tags:Animation Graph + +**Spline IK** 컨트롤 노드는 애니메이션 블루프린트 내 스플라인에 지정된 본 체인을 제약(컨스트레인)시키는 노드입니다. 스플라인은 주로 Control Point (컨트롤 포인트)로 정의합니다. + +![](SplineIKnode.png) + +아래는 애니메이션 블루프린트에 Spline IK 노드를 추가하여 캐릭터의 척추를 제어하는 모습입니다. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + FEth0mMla0I + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +Spline IK 컨트롤 노드는 애니메이션 블루프린트 내 스플라인에 지정된 본 체인을 **Control Point** (컨트롤 포인트)로 제약(컨스트레인)시킵니다. +이 컨트롤 포인트는 외부 값에 롤이나 트위스트(는 물론 트위스트 블렌딩 옵션 포함) 부가 옵션을 붙여 구동시킬 수 있습니다. +Spline IK 노드에 사용할 수 있는 프로퍼티의 자세한 분석은 아래 표를 참고하세요. + +| 프로퍼티 | 설명 | +| -------- | ----------- | +| [REGION:tablesection]**Parameter (파라미터)**[/REGION] || +| **Start Bone** | 시작 본 - 스플라인 확장을 시작할 루트 본 이름입니다. | +| **End Bone** | 끝 본 - 스플라인 체인 끝 위치의 본 이름입니다 (이 다음의 본은 컨트롤러가 변경하지 않습니다). | +| **Bone Axis** | 본 축 - 커브의 방향으로 사용할 제어 본의 축(예: 스플라인 방향)입니다. | +| **Auto Calculate Spline** | 스플라인 자동 계산 - 스플라인의 포인트 수를 자동 생성할지 여부입니다. | +| **Point Count** | 포인트 수 - 자동 계산하지 않는 경우 스플라인의 포인트 수입니다. | +| **(As Pin) Control Points** | (핀으로) 컨트롤 포인트 - 스플라인 포인트에 적용되는 트랜스폼입니다. | +| **(As Pin) Roll** | (핀으로) 롤 - 스플라인의 전반적인 롤 값으로, 스플라인 방향을 따라 다른 로테이션 위에 적용됩니다. | +| **(As Pin) Twist Start** | (핀으로) 트위스트 시작 - 시작 본의 트위스트입니다. 스플라인 상에서 Twist Blend 에 따라 트위스트가 보간됩니다. | +| **(As Pin) Twist End** | (핀으로) 트위스트 끝 - 끝 본의 트위스트입니다. 스플라인 상에서 Twist Blend 에 따라 트위스트가 보간됩니다. | +| **(As Pin) Stretch** | (핀으로) 스트레치 - 본을 스플라인에 맞출 때의 최대 스트레치 허용치입니다. 0.0 은 본 길이 늘이기를 허용하지 않고, 1.0 은 스플라인 길이만큼 본 길이 늘이기를 허용합니다. | +| **(As Pin) Offset** | (핀으로) 오프셋 - 스플라인 시작부터 이만큼 거리까지 본을 제약시킵니다. | +| [REGION:tablesection]**Twist Blend (트위스트 블렌드)**[/REGION] || +| **Blend Option** | 블렌드 옵션 - 사용되는 [애니메이션 블렌딩 모드](Engine/Animation/NonLinearBlends) 유형입니다. | +| **Custom Curve** | 커스텀 커브 - 커브를 지정할 수 있는 Custom Blend 옵션을 활성화시킵니다. | +| **Blend Time** | 블렌드 시간 - 블렌딩 지속 시간입니다. | +| [REGION:tablesection]**Settings (세팅)**[/REGION] || +| **Alpha** | 알파 - 스켈레탈 컨트롤의 현재 세기입니다. | +| **Alpha Scale Bias** | 알파 스케일 바이어스 - Alpha 프로퍼티의 최소 최대 스케일 바이어스를 정합니다. | +| [REGION:tablesection]**Performance (퍼포먼스)**[/REGION] || +| **LOD Threshold** | LOD 한계치 - 최대 이 LOD 까지만 이 노드를 실행할 수 있습니다. | + +Spline IK 노드에 기본으로 활성화된 핀 개요는 다음 표와 같습니다. + +| 핀 | 설명 | +| --- | ----------- | +| [REGION:tablesection]**입력 핀**[/REGION] || +| **Component Pose** | 컴포넌트 포즈 - 입력 포즈입니다. | +| **Alpha** | 알파 - 컨트롤의 현재 세기입니다. | + +**(As pin)** 이라고 붙어있는 프로퍼티는 해당 박스를 체크하여 노드에서 노출시킬 수 있습니다. + diff --git a/Engine/Documentation/Source/Engine/Animation/NonLinearBlends/NonLinearBlends.INT.udn b/Engine/Documentation/Source/Engine/Animation/NonLinearBlends/NonLinearBlends.INT.udn index a112560f05a3..1e3b81587359 100644 --- a/Engine/Documentation/Source/Engine/Animation/NonLinearBlends/NonLinearBlends.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/NonLinearBlends/NonLinearBlends.INT.udn @@ -8,7 +8,7 @@ Related: Engine\Animation\StateMachines Related: Engine/UI/CurveEditor Related: Engine/Basics/Distributions Related: Engine/Animation/AnimMontage - +Topic-image:AnimationgBlendModes_topic.png **Animation Blend Modes** enable you to control the way meshes blend between Poses when transitioning from one State to another within a [**State Machine**](Engine\Animation\StateMachines). There are several different Blend Modes that you can choose from which can be set from the **Blend Settings** section of a **Transition Rule** in a State Machine (pictured below). diff --git a/Engine/Documentation/Source/Engine/Animation/NonLinearBlends/NonLinearBlends.JPN.udn b/Engine/Documentation/Source/Engine/Animation/NonLinearBlends/NonLinearBlends.JPN.udn index f3f851d96af2..af8181b78872 100644 --- a/Engine/Documentation/Source/Engine/Animation/NonLinearBlends/NonLinearBlends.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/NonLinearBlends/NonLinearBlends.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:2949987 +INTSourceChangelist:3467293 Availability:Public Title:Animation ブレンドモード Crumbs: %ROOT%, Engine, Engine/Animation @@ -9,7 +9,7 @@ Related:Engine\Animation\StateMachines Related:Engine/UI/CurveEditor Related:Engine/Basics/Distributions Related:Engine/Animation/AnimMontage - +Topic-image:AnimationgBlendModes_topic.png **Animation ブレンドモード** を使うと、[**ステートマシン**](Engine\Animation\StateMachines) 内であるステートから別のステートに遷移する場合にポーズ間でメッシュがブレンドする方法を制御することができます。 選択できるブレンドモードは複数あります。これは、ステートマシン (以下の図) の **[Transition Rule (遷移ルール)]** の **[Blend Settings]** から設定することができます。 diff --git a/Engine/Documentation/Source/Engine/Animation/NonLinearBlends/NonLinearBlends.KOR.udn b/Engine/Documentation/Source/Engine/Animation/NonLinearBlends/NonLinearBlends.KOR.udn index b8a5cac0b0ab..43f69ae9412f 100644 --- a/Engine/Documentation/Source/Engine/Animation/NonLinearBlends/NonLinearBlends.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/NonLinearBlends/NonLinearBlends.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3467293 Availability:Public Title:애니메이션 블렌드 모드 Crumbs: %ROOT%, Engine, Engine/Animation @@ -9,7 +9,7 @@ Related: Engine\Animation\StateMachines Related: Engine/UI/CurveEditor Related: Engine/Basics/Distributions Related: Engine/Animation/AnimMontage - +Topic-image:AnimationgBlendModes_topic.png **Animation Blend Modes** (애니메이션 블렌드 모드)로 [**스테이트 머신**](Engine\Animation\StateMachines) 내 한 상태에서 다른 상태로 전환할 때 메시의 포즈간 블렌딩 방식을 조절할 수 있습니다. 선택할 수 있는 블렌드 모드가 여러가지 있는데, 스테이트 머신 내 **Transition Rule** (트랜지션 룰)의 **Blend Settings** (블렌드 세팅) 섹션에서 설정할 수 있습니다. diff --git a/Engine/Documentation/Source/Engine/Animation/NonUniformScale/NonUniformScale.INT.udn b/Engine/Documentation/Source/Engine/Animation/NonUniformScale/NonUniformScale.INT.udn index cebe30f09158..154243398458 100644 --- a/Engine/Documentation/Source/Engine/Animation/NonUniformScale/NonUniformScale.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/NonUniformScale/NonUniformScale.INT.udn @@ -3,6 +3,7 @@ Title:Non-Uniform Scale Animation Crumbs: %ROOT%, Engine, Engine/Animation Description:Overview of how non-uniform scale animations can be used. version: 4.9 +topic-image:NonUniformScaleAnimation_topic.png The animation system in Unreal Engine 4 does support non-uniform scale animations. When importing an animation, if scale exists, it is automatically imported without the need for setting additional options. For memory conservation, the engine does not save scale for all animations and only saves it if the animation has a scale that is not 1. diff --git a/Engine/Documentation/Source/Engine/Animation/NonUniformScale/NonUniformScale.JPN.udn b/Engine/Documentation/Source/Engine/Animation/NonUniformScale/NonUniformScale.JPN.udn index 115bcd220d71..a2643a213c31 100644 --- a/Engine/Documentation/Source/Engine/Animation/NonUniformScale/NonUniformScale.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/NonUniformScale/NonUniformScale.JPN.udn @@ -1,12 +1,13 @@ -INTSourceChangelist:2666099 +INTSourceChangelist:3467293 Availability:Public Title:不均等なスケール アニメーション Crumbs: %ROOT%, Engine, Engine/Animation Description:不均等なスケール アニメーションの使用方法の概要 -version: 4.9 +version:4.9 +topic-image:NonUniformScaleAnimation_topic.png -アンリアル エンジン 4 のアニメーション システムは、不均等なスケール アニメーションをサポートしています。スケールが存在場合、アニメーションをインポートすると、追加オプションの設定をする必要なく自動的にインポートされます。メモリ保存のため、エンジンは全てのアニメーションのスケールを保存するわけではなく、アニメーションが 1 以外のスケールの場合にのみ保存します。 +アンリアル エンジン 4 のアニメーション システムは、不均等なスケール アニメーションをサポートしています。スケールが存在する場合、アニメーションをインポートすると、追加オプションの設定をする必要なく自動的にインポートされます。メモリ保存のため、エンジンは全てのアニメーションのスケールを保存するわけではなく、アニメーションが 1 以外のスケールの場合にのみ保存します。 例として、以下のビデオを参照してください。 diff --git a/Engine/Documentation/Source/Engine/Animation/NonUniformScale/NonUniformScale.KOR.udn b/Engine/Documentation/Source/Engine/Animation/NonUniformScale/NonUniformScale.KOR.udn index f0b39c4d0ed5..23c4f1420146 100644 --- a/Engine/Documentation/Source/Engine/Animation/NonUniformScale/NonUniformScale.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/NonUniformScale/NonUniformScale.KOR.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3467293 Availability:Public Title:비균등 스케일 애니메이션 Crumbs: %ROOT%, Engine, Engine/Animation Description:비균등 스케일 애니메이션 사용법에 대한 개요입니다. version: 4.9 +topic-image:NonUniformScaleAnimation_topic.png 언리얼 엔진 4 의 애니메이션 시스템에는 비균등(non-uniform) 스케일 애니메이션이 지원됩니다. 애니메이션을 임포트할 때 스케일이 존재하면 별도의 옵션을 설정할 필요 없이 자동으로 임포트됩니다. 메모리 보존 차원에서 엔진은 모든 애니메이션에 대한 스케일을 저장하지는 않으며, 스케일이 1 이 아닌 애니메이션에 대해서만 저장합니다. diff --git a/Engine/Documentation/Source/Engine/Animation/Optimization/FastPath/FastPath.INT.udn b/Engine/Documentation/Source/Engine/Animation/Optimization/FastPath/FastPath.INT.udn index dc7c240cd996..e924c8c23bca 100644 --- a/Engine/Documentation/Source/Engine/Animation/Optimization/FastPath/FastPath.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/Optimization/FastPath/FastPath.INT.udn @@ -3,6 +3,7 @@ Title: Animation Fast Path Optimization Crumbs: %ROOT%, Engine, Engine/Animation Description:Optimizations that can be applied to the structure of animation graphs to gain performance version: 4.11 +topic-image:AnimationFastPathOptimization_topic.png [EXCERPT:Intro] Animation Blueprints are very flexible ways of building animation systems. However the performance overheads diff --git a/Engine/Documentation/Source/Engine/Animation/Optimization/FastPath/FastPath.JPN.udn b/Engine/Documentation/Source/Engine/Animation/Optimization/FastPath/FastPath.JPN.udn index 1352ccdf667e..24db6aaa2b60 100644 --- a/Engine/Documentation/Source/Engine/Animation/Optimization/FastPath/FastPath.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/Optimization/FastPath/FastPath.JPN.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:2926677 +INTSourceChangelist:3467293 Availability:Public Title:アニメーションのファストパスによる最適化 Crumbs: %ROOT%, Engine, Engine/Animation Description:パフォーマンスを高めるためにアニメーション グラフの構造に適用できる最適化について説明します。 version:4.11 +topic-image:AnimationFastPathOptimization_topic.png [EXCERPT:Intro] Animation ブループリントはアニメーション システムを構築する非常にフレキシブルな方法です。ただし、ブループリント ベースのロジックの実行に伴うパフォーマンス オーバーヘッドは、 diff --git a/Engine/Documentation/Source/Engine/Animation/Optimization/FastPath/FastPath.KOR.udn b/Engine/Documentation/Source/Engine/Animation/Optimization/FastPath/FastPath.KOR.udn index 9686b6419b79..088abc8d2a4f 100644 --- a/Engine/Documentation/Source/Engine/Animation/Optimization/FastPath/FastPath.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/Optimization/FastPath/FastPath.KOR.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3467293 Availability:Public Title: 애니메이션 빠른 경로 최적화 Crumbs: %ROOT%, Engine, Engine/Animation Description:애니메이션 그래프 구조에 적용시켜 퍼포먼스를 향상시킬 수 있는 최적화입니다. version: 4.11 +topic-image:AnimationFastPathOptimization_topic.png [EXCERPT:Intro] 애니메이션 블루프린트는 매우 유연하게 애니메이션 시스템을 제작할 수 있는 도구입니다. 하지만 그래프가 diff --git a/Engine/Documentation/Source/Engine/Animation/Overview/AnimationOverview.INT.udn b/Engine/Documentation/Source/Engine/Animation/Overview/AnimationOverview.INT.udn index 3efab6f61ffb..ebb4a0412ebc 100644 --- a/Engine/Documentation/Source/Engine/Animation/Overview/AnimationOverview.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/Overview/AnimationOverview.INT.udn @@ -9,6 +9,7 @@ version: 4.14 type:overview topic-image:AnimationToolsTopic.png tags:Animation +tags:Getting Started [TOC(start:2 end:2)] @@ -27,113 +28,60 @@ The purpose of this document is to offer a high-level overview of UE4's animatio We will start by identifying the primary terms and concepts of UE4's animation system (click each header to view more documentation): (#Skeleton) -[OBJECT:IconSection] - [PARAM:icon] - ![](AnimationToolsTopic.png) - [/PARAM] - [PARAM:title] - [](Engine/Animation/Persona/Modes) - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/Animation/Persona/Modes#overview] - [/PARAM] -[/OBJECT] +### %Engine/Animation/Persona/Modes:title% -[OBJECT:IconSection] - [PARAM:icon] - ![](SkeletonTopic.png) - [/PARAM] - [PARAM:title] - [](Engine/Animation/Skeleton) - [/PARAM] - [PARAM:description] - A **Skeleton** is a hierarchy of bone locations and rotations used to deform a Skeletal Mesh. In UE4, Skeletons are abstracted from Skeletal Meshes in their own asset. This means that animations are applied to the Skeleton, rather than the Skeletal Mesh. By using the same Skeleton, multiple Skeletal Meshes can share animations. - [/PARAM] -[/OBJECT] +%Engine/Animation/Persona/Modes:topiccompact% -[OBJECT:IconSection] - [PARAM:icon] - ![](AnimationSeqTopic.png) - [/PARAM] - [PARAM:title] - [](Engine/Animation/Sequences) - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/Animation/Sequences#Intro] - [/PARAM] -[/OBJECT] +[INCLUDE:Engine/Animation/Persona/Modes#overview] -[OBJECT:IconSection] - [PARAM:icon] - ![](AnimNotifiesTopic.png) - [/PARAM] - [PARAM:title] - [](Engine/Animation/Sequences/Notifies) - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/Animation/Sequences/Notifies#Intro] - [/PARAM] -[/OBJECT] +### %Engine/Animation/Skeleton:title% -[OBJECT:IconSection] - [PARAM:icon] - ![](AnimationBlueprintTopic.png) - [/PARAM] - [PARAM:title] - [](Engine/Animation/AnimBlueprints) - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/Animation/AnimBlueprints#Intro] - [/PARAM] -[/OBJECT] +%Engine/Animation/Skeleton:topiccompact% -[OBJECT:IconSection] - [PARAM:icon] - ![](BlendSpaceTopic.png) - [/PARAM] - [PARAM:title] - [](Engine/Animation/Blendspaces) - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/Animation/Blendspaces#Intro] - [/PARAM] -[/OBJECT] +A **Skeleton** is a hierarchy of bone locations and rotations used to deform a Skeletal Mesh. In UE4, Skeletons are abstracted from Skeletal Meshes in their own asset. This means that animations are applied to the Skeleton, rather than the Skeletal Mesh. By using the same Skeleton, multiple Skeletal Meshes can share animations. -[OBJECT:IconSection] - [PARAM:icon] - ![](MontageTopic.png) - [/PARAM] - [PARAM:title] - [](Engine/Animation/AnimMontage) - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/Animation/AnimMontage#Intro] - [/PARAM] -[/OBJECT] +### %Engine/Animation/Sequences:title% -[OBJECT:IconSection] - [PARAM:icon] - ![](SkeletonControlTopic.png) - [/PARAM] - [PARAM:title] - [](Engine/Animation/NodeReference/SkeletalControls) - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/Animation/NodeReference/SkeletalControls#Intro] - [/PARAM] -[/OBJECT] +%Engine/Animation/Sequences:topiccompact% + +[INCLUDE:Engine/Animation/Sequences#Intro] + +### %Engine/Animation/Sequences/Notifies:title% + +%Engine/Animation/Sequences/Notifies:topiccompact% + +[INCLUDE:Engine/Animation/Sequences/Notifies#Intro] + +### %Engine/Animation/AnimBlueprints:title% + +%Engine/Animation/AnimBlueprints:topiccompact% + +[INCLUDE:Engine/Animation/AnimBlueprints#Intro] + +### %Engine/Animation/Blendspaces:title% + +%Engine/Animation/Blendspaces:topiccompact% + +[INCLUDE:Engine/Animation/Blendspaces#Intro] + +### %Engine/Animation/AnimMontage:title% + +%Engine/Animation/AnimMontage:topiccompact% + +[INCLUDE:Engine/Animation/AnimMontage#Intro] + +### %Engine/Animation/NodeReference/SkeletalControls:title% + +%Engine/Animation/NodeReference/SkeletalControls:topiccompact% + +[INCLUDE:Engine/Animation/NodeReference/SkeletalControls#Intro] + +### %Engine/Animation/StateMachines:title% + +%Engine/Animation/StateMachines:topiccompact% + +[INCLUDE:Engine/Animation/StateMachines#Intro] -[OBJECT:IconSection] - [PARAM:icon] - ![](StateMachineTopic.png) - [/PARAM] - [PARAM:title] - [](Engine/Animation/StateMachines) - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/Animation/StateMachines#overview] - [/PARAM] -[/OBJECT] [REGION:note] Examples of some of the animation features can also be found in the [Content Examples](https://docs.unrealengine.com/latest/INT/Resources/ContentExamples/) project available for free from the **Learn Tab** of the Epic Games Launcher. diff --git a/Engine/Documentation/Source/Engine/Animation/Overview/AnimationOverview.JPN.udn b/Engine/Documentation/Source/Engine/Animation/Overview/AnimationOverview.JPN.udn index 07abd9ded2dc..20d00a39ff88 100644 --- a/Engine/Documentation/Source/Engine/Animation/Overview/AnimationOverview.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/Overview/AnimationOverview.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3231203 +INTSourceChangelist:3429233 Availability:Public Title:アニメーション システムの概要 Crumbs: %ROOT%, Engine, Engine/Animation @@ -10,6 +10,7 @@ version:4.14 type:overview topic-image:AnimationToolsTopic.png tags:Animation +tags:Getting Started [TOC(start:2 end:2)] @@ -28,113 +29,60 @@ UE4 のアニメーション システムは、いくつかのアニメーショ まず、 UE4 のアニメーション システムの主な用語と概念について説明します (詳しい情報を見るには各ヘッダーをクリックします)。 (#Skeleton) -[OBJECT:IconSection] - [PARAM:icon] - ![](AnimationToolsTopic.png) - [/PARAM] - [PARAM:title] - [](Engine/Animation/Persona/Modes) - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/Animation/Persona/Modes#overview] - [/PARAM] -[/OBJECT] +### %Engine/Animation/Persona/Modes:title% -[OBJECT:IconSection] - [PARAM:icon] - ![](SkeletonTopic.png) - [/PARAM] - [PARAM:title] - [](Engine/Animation/Skeleton) - [/PARAM] - [PARAM:description] - **スケルトン** は、スケルタルメッシュを変形するために使用するボーンの位置と回転の階層です。UE4 では、スケルトンはその独自のアセットにあるスケルタルメッシュから抽出されます。つまり、アニメーションは、スケルタルメッシュではなくスケルトンに適用されます。同じスケルトンを使用することで、複数のスケルタルメッシュがアニメーションを共有できます。 - [/PARAM] -[/OBJECT] +%Engine/Animation/Persona/Modes:topiccompact% -[OBJECT:IconSection] - [PARAM:icon] - ![](AnimationSeqTopic.png) - [/PARAM] - [PARAM:title] - [](Engine/Animation/Sequences) - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/Animation/Sequences#Intro] - [/PARAM] -[/OBJECT] +[INCLUDE:Engine/Animation/Persona/Modes#overview] -[OBJECT:IconSection] - [PARAM:icon] - ![](AnimNotifiesTopic.png) - [/PARAM] - [PARAM:title] - [](Engine/Animation/Sequences/Notifies) - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/Animation/Sequences/Notifies#Intro] - [/PARAM] -[/OBJECT] +### %Engine/Animation/Skeleton:title% -[OBJECT:IconSection] - [PARAM:icon] - ![](AnimationBlueprintTopic.png) - [/PARAM] - [PARAM:title] - [](Engine/Animation/AnimBlueprints) - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/Animation/AnimBlueprints#Intro] - [/PARAM] -[/OBJECT] +%Engine/Animation/Skeleton:topiccompact% -[OBJECT:IconSection] - [PARAM:icon] - ![](BlendSpaceTopic.png) - [/PARAM] - [PARAM:title] - [](Engine/Animation/Blendspaces) - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/Animation/Blendspaces#Intro] - [/PARAM] -[/OBJECT] +**スケルトン** は、スケルタルメッシュを変形するために使用するボーンの位置と回転の階層です。UE4 では、スケルトンはその独自のアセットにあるスケルタルメッシュから抽出されます。つまり、アニメーションは、スケルタルメッシュではなくスケルトンに適用されます。同じスケルトンを使用することで、複数のスケルタルメッシュがアニメーションを共有できます。 -[OBJECT:IconSection] - [PARAM:icon] - ![](MontageTopic.png) - [/PARAM] - [PARAM:title] - [](Engine/Animation/AnimMontage) - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/Animation/AnimMontage#Intro] - [/PARAM] -[/OBJECT] +### %Engine/Animation/Sequences:title% -[OBJECT:IconSection] - [PARAM:icon] - ![](SkeletonControlTopic.png) - [/PARAM] - [PARAM:title] - [](Engine/Animation/NodeReference/SkeletalControls) - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/Animation/NodeReference/SkeletalControls#Intro] - [/PARAM] -[/OBJECT] +%Engine/Animation/Sequences:topiccompact% + +[INCLUDE:Engine/Animation/Sequences#Intro] + +### %Engine/Animation/Sequences/Notifies:title% + +%Engine/Animation/Sequences/Notifies:topiccompact% + +[INCLUDE:Engine/Animation/Sequences/Notifies#Intro] + +### %Engine/Animation/AnimBlueprints:title% + +%Engine/Animation/AnimBlueprints:topiccompact% + +[INCLUDE:Engine/Animation/AnimBlueprints#Intro] + +### %Engine/Animation/Blendspaces:title% + +%Engine/Animation/Blendspaces:topiccompact% + +[INCLUDE:Engine/Animation/Blendspaces#Intro] + +### %Engine/Animation/AnimMontage:title% + +%Engine/Animation/AnimMontage:topiccompact% + +[INCLUDE:Engine/Animation/AnimMontage#Intro] + +### %Engine/Animation/NodeReference/SkeletalControls:title% + +%Engine/Animation/NodeReference/SkeletalControls:topiccompact% + +[INCLUDE:Engine/Animation/NodeReference/SkeletalControls#Intro] + +### %Engine/Animation/StateMachines:title% + +%Engine/Animation/StateMachines:topiccompact% + +[INCLUDE:Engine/Animation/StateMachines#Intro] -[OBJECT:IconSection] - [PARAM:icon] - ![](StateMachineTopic.png) - [/PARAM] - [PARAM:title] - [](Engine/Animation/StateMachines) - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/Animation/StateMachines#overview] - [/PARAM] -[/OBJECT] [REGION:note] 一部のアニメーション機能は、エピック ゲームズのランチャーの **[Learn (ラーニング)] タブ** から無料で利用できる [コンテンツ サンプル](https://docs.unrealengine.com/latest/INT/Resources/ContentExamples/) プロジェクトにもあります。 diff --git a/Engine/Documentation/Source/Engine/Animation/Overview/AnimationOverview.KOR.udn b/Engine/Documentation/Source/Engine/Animation/Overview/AnimationOverview.KOR.udn index 1f986eca140a..9d021c6e4f07 100644 --- a/Engine/Documentation/Source/Engine/Animation/Overview/AnimationOverview.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/Overview/AnimationOverview.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3231203 +INTSourceChangelist:3429233 Availability:Public Title:애니메이션 시스템 개요 Crumbs: %ROOT%, Engine, Engine/Animation @@ -10,6 +10,7 @@ version: 4.14 type:overview topic-image:AnimationToolsTopic.png tags:Animation +tags:Getting Started [TOC(start:2 end:2)] @@ -28,116 +29,63 @@ tags:Animation 먼저 UE4 의 애니메이션 시스템에 대한 주요 용어와 개념을 알아보는 것으로 시작하겠습니다 (각 제목을 클릭하면 상세 문서를 확인할 수 있습니다): (#Skeleton) -[OBJECT:IconSection] - [PARAM:icon] - ![](AnimationToolsTopic.png) - [/PARAM] - [PARAM:title] - [](Engine/Animation/Persona/Modes) - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/Animation/Persona/Modes] - [/PARAM] -[/OBJECT] +### %Engine/Animation/Persona/Modes:title% -[OBJECT:IconSection] - [PARAM:icon] - ![](SkeletonTopic.png) - [/PARAM] - [PARAM:title] - [](Engine/Animation/Skeleton) - [/PARAM] - [PARAM:description] - **Skeleton** (스켈레톤) 이란 계층으로 나타낸 본의 위치와 회전값으로, 스켈레탈 메시의 변형(deform)에 사용됩니다. UE4 에서의 스켈레톤은 스켈레탈 메시에서 별도의 애셋으로 추출해 내었습니다. 즉 애니메이션은 스켈레탈 메시가 아니라 스켈레톤에 저장된다는 뜻입니다. 같은 스켈레톤을 사용하면 다수의 스켈레탈 메시에 애니메이션을 공유할 수 있습니다. - [/PARAM] -[/OBJECT] +%Engine/Animation/Persona/Modes:topiccompact% -[OBJECT:IconSection] - [PARAM:icon] - ![](AnimationSeqTopic.png) - [/PARAM] - [PARAM:title] - [](Engine/Animation/Sequences) - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/Animation/Sequences] - [/PARAM] -[/OBJECT] +[INCLUDE:Engine/Animation/Persona/Modes#overview] -[OBJECT:IconSection] - [PARAM:icon] - ![](AnimNotifiesTopic.png) - [/PARAM] - [PARAM:title] - [](Engine/Animation/Sequences/Notifies) - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/Animation/Sequences/Notifies#Intro] - [/PARAM] -[/OBJECT] +### %Engine/Animation/Skeleton:title% -[OBJECT:IconSection] - [PARAM:icon] - ![](AnimationBlueprintTopic.png) - [/PARAM] - [PARAM:title] - [](Engine/Animation/AnimBlueprints) - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/Animation/AnimBlueprints#Intro] - [/PARAM] -[/OBJECT] +%Engine/Animation/Skeleton:topiccompact% -[OBJECT:IconSection] - [PARAM:icon] - ![](BlendSpaceTopic.png) - [/PARAM] - [PARAM:title] - [](Engine/Animation/Blendspaces) - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/Animation/Blendspaces#Intro] - [/PARAM] -[/OBJECT] +**Skeleton** (스켈레톤) 이란 본의 위치와 회전값을 계층구조로 나타낸 것으로, 스켈레탈 메시의 변형(deform)에 사용됩니다. UE4 에서 스켈레톤은 스켈레탈 메시에서 추출하여 별도의 애셋으로 만들었습니다. 즉 애니메이션은 스켈레탈 메시가 아니라 스켈레톤에 저장된다는 뜻입니다. 같은 스켈레톤을 사용하면 한 애니메이션을 다수의 스켈레탈 메시에 공유할 수 있습니다. -[OBJECT:IconSection] - [PARAM:icon] - ![](MontageTopic.png) - [/PARAM] - [PARAM:title] - [](Engine/Animation/AnimMontage) - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/Animation/AnimMontage#Intro] - [/PARAM] -[/OBJECT] +### %Engine/Animation/Sequences:title% -[OBJECT:IconSection] - [PARAM:icon] - ![](SkeletonControlTopic.png) - [/PARAM] - [PARAM:title] - [](Engine/Animation/NodeReference/SkeletalControls) - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/Animation/NodeReference/SkeletalControls#Intro] - [/PARAM] -[/OBJECT] +%Engine/Animation/Sequences:topiccompact% + +[INCLUDE:Engine/Animation/Sequences#Intro] + +### %Engine/Animation/Sequences/Notifies:title% + +%Engine/Animation/Sequences/Notifies:topiccompact% + +[INCLUDE:Engine/Animation/Sequences/Notifies#Intro] + +### %Engine/Animation/AnimBlueprints:title% + +%Engine/Animation/AnimBlueprints:topiccompact% + +[INCLUDE:Engine/Animation/AnimBlueprints#Intro] + +### %Engine/Animation/Blendspaces:title% + +%Engine/Animation/Blendspaces:topiccompact% + +[INCLUDE:Engine/Animation/Blendspaces#Intro] + +### %Engine/Animation/AnimMontage:title% + +%Engine/Animation/AnimMontage:topiccompact% + +[INCLUDE:Engine/Animation/AnimMontage#Intro] + +### %Engine/Animation/NodeReference/SkeletalControls:title% + +%Engine/Animation/NodeReference/SkeletalControls:topiccompact% + +[INCLUDE:Engine/Animation/NodeReference/SkeletalControls#Intro] + +### %Engine/Animation/StateMachines:title% + +%Engine/Animation/StateMachines:topiccompact% + +[INCLUDE:Engine/Animation/StateMachines#Intro] -[OBJECT:IconSection] - [PARAM:icon] - ![](StateMachineTopic.png) - [/PARAM] - [PARAM:title] - [](Engine/Animation/StateMachines) - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/Animation/StateMachines#overview] - [/PARAM] -[/OBJECT] [REGION:note] -일부 애니메이션 기능에 대한 예제는 에픽 게임스 런처의 **학습 탭** 에서 무료로 받을 수 있는 [Content Examples](Resources/ContentExamples/) (콘텐츠 예제) 프로젝트에서도 확인할 수 있습니다. +일부 애니메이션 기능에 대한 예제는 에픽 게임즈 런처의 **학습 탭** 에서 무료로 받을 수 있는 [Content Examples](Resources/ContentExamples/) (콘텐츠 예제) 프로젝트에서도 확인할 수 있습니다. [/REGION] ## 시스템 분해도 diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/AnimCurves/AnimCurves.INT.udn b/Engine/Documentation/Source/Engine/Animation/Persona/AnimCurves/AnimCurves.INT.udn index 045c13ff1833..dd822cdfce65 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/AnimCurves/AnimCurves.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/AnimCurves/AnimCurves.INT.udn @@ -1,37 +1,24 @@ Availability:Public +Crumbs: Title:Anim Curves -Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Persona -Description:Describes actions available within the Anim Curves window -version: 4.14 -Related:Engine/Animation/Sequences/Curves/ - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Animation/Persona/Toolbar:title%](Engine/Animation/animation_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Animation/Persona/Toolbar:title% - [/PARAM] - [PARAM:description] - %Engine/Animation/Persona/Toolbar:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Animation/Persona/Toolbar] - [/PARAM] -[/OBJECT] -[/VAR] +Description:Describes actions available within the Anim Curves window. +Type:overview +SkillLevel:Intermediate +Version:4.16 +Parent:Engine/Animation/Sequences/Curves +Order: +Tags:Animation +Tags:Morph Target +Topic-image:AnimCurves_Topic.png +[TOC(start:2)] ![](AnimCurvesAlone.png) -The **Anim Curves** panel displays curve values for **Morph Target**, **Attribute**, and **Material** curves for your project. +The **Anim Curves** panel displays curve values for **Morph Target**, **Attribute**, and **Material** curves for the selected skeleton. You can delete and rename curves here, as well as preview curve data. You can filter the visible curves to show only active curves by clicking on **All Curves** to deselect it, which also enables you to filter by **Morph Target**, **Attribute**, and **Material** curves with checkboxes. -In addition, you can define [Material Curves](Engine/Animation/Sequences/Curves) which allow you to drive Material Parameters or Morph Curves (if Morph Targets exist within the associated animation). +In addition, you can define [Material Curves](Engine/Animation/Sequences/Curves) which enable you to drive Material Parameters or Morph Curves. To open the **Anim Curves** panel in either the **Skeleton Editor** or **Animation Editor**: @@ -88,3 +75,47 @@ This adds a curve to the current skeleton, but you will need to then add the cur If the curve is currently being used by any assets in your project, a confirmation window will appear warning you that the curves will be removed from those assets. 1. Click **Yes** to continue with the deletion, or **No** to cancel. + + +## Linking Curves to Bones + +You can link your Animation Curves to a specific bone in the Skeleton so that they can be culled out with the bone when changing Levels of Detail (LOD) for the Skeletal Mesh, which is +useful when setting up facial animations that aren't needed for lower LODs. This feature can also be used in conjunction with layer blending to prevent overriding curve values from the +incorrect layer. + +1. In the **Anim Curves** viewer window, select the curve that you want to link to a particular bone in your Skeleton. + + ![](AnimCurveViewer_CurveSelected.png)(w:400) + +1. With the curve selected, in the **Details** panel, click the **add** (**+**) button to add Connected Bone(s) elements. + + ![](DetailsPanel_AddConnectedBone.png)(w:400) + + Then use the dropdown next to the added bone, to select the bone you want to link to the curve. The list here will be populated based on the Skeleton's bone heirarchy. + + ![](DP_SelectBones.png)(w:400) + +1. Now that your curve is assigned to the bone(s) you've added to the Connected Bones, you can move the camera towards or away from the mesh to see the linked curves cull from view when the LOD of the mesh changes. + + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + V1SLxdRI8-4 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] + [/OBJECT] + + + + + diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/BasePoseManager/BasePoseManager.INT.udn b/Engine/Documentation/Source/Engine/Animation/Persona/BasePoseManager/BasePoseManager.INT.udn index 5fcacdb21f53..ce7880fa578e 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/BasePoseManager/BasePoseManager.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/BasePoseManager/BasePoseManager.INT.udn @@ -1,45 +1,38 @@ -Availability:Public -Title:Retarget Manager +Availability: Docs Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Persona -Description:Breaks down the Retarget Manager options within the Skeleton Editor.- -version: 4.14 -related: Engine\Animation\AnimHowTo\Retargeting -related: Engine/Animation/Skeleton - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Animation/Persona/AssetBrowser:title%](Engine/Animation/animation_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Animation/Persona/BasePoseManager:title% - [/PARAM] - [PARAM:description] - %Engine/Animation/Persona/BasePoseManager:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Animation/Persona/BasePoseManager] - [/PARAM] -[/OBJECT] -[/VAR] - -The **Retarget Manager** within the **Skeleton Editor** allows you to manage your retarget sources, set up rigs and define retarged base poses for use with [Animation Retargeting](Engine\Animation\AnimHowTo\Retargeting) for characters that do not share the same [Skeleton](Engine/Animation/Skeleton) asset. You can open the Retarget Manager from the Toolbar of the Skeleton Editor. +Title:Retarget Manager +Description:Breaks down the Retarget Manager options within the Skeleton Editor. +Type: Overview +SkillLevel: intermediate +Version: 4.16 +Parent: Engine/Animation/Persona +Order: 1 +Tags: Animation +Tags: Skeleton +Tags: Retargeting +topic-image:RetargetTopic.png +Related: Engine\Animation\AnimHowTo\Retargeting +Related: Engine/Animation/Skeleton +Related: Engine/Animation/Persona/Modes/Skeleton +Related: Engine/Animation/AnimPose +Related: Engine/Animation/Sequences [TOC(start:2 end:2)] +The **Retarget Manager** within the **Skeleton Editor** can be used to manage your retarget sources, set up rigs and define retargeted base poses for use with [Animation Retargeting](Engine\Animation\AnimHowTo\Retargeting). ## Manage Retarget Source -Since retargeting uses the Skeleton asset, and since the Skeleton has its original proportions defined by the Skeletal Mesh for which it was initially created, it follows that one-directional retargeting will work smoothly in most cases. However, there will often come times when you will have special animations that are built just for the variant versions. +Since retargeting uses a [Skeleton](Engine/Animation/Skeleton) asset and the Skeleton has its original proportions defined by the Skeletal Mesh for which it was initially created, it follows that one-directional retargeting will work smoothly in most cases. +However, there will often come times when you will have special animations that are built just for the variant versions. For example, suppose you have multiple characters that share the same Skeleton asset (a base character, a short character and a tall character) and you have a special animation that was created just for the tall version of the character. -If you imported this new "tall-only" animation in, you would still need to use the same Skeleton asset as before, which was created from the base version of the character. This will cause the new animation's proportions to be distorted. -The solution is to use the **Manage Retarget Source** option within the **Retarget Manager** which allows you to associate an Animation Sequence with the actual Skeletal Mesh for which it was designed. In this way, any problems of retargeting for special animations will be fixed. +If you imported this new tall-only animation in, you would still need to use the same Skeleton asset as before, which was created from the base version of the character. +This will cause the new animation's proportions to be distorted. +The solution is to use the **Manage Retarget Source** option within the **Retarget Manager** which allows you to associate an Animation Sequence with the actual Skeletal Mesh for which it was designed. +In this way, any problems of retargeting for special animations will be fixed. -Think of the **Mange Retarget Source** as a list of Skeletal Meshes that you can use to designate proportions. If you ever need a special animation for a retargeted Skeletal Mesh, you would need to make sure that the mesh was listed as a retarget source, steps for which are outlined below. +### Adding Retarget Sources 1. Inside the **Skeleton Editor**, from the **Toolbar** click the **Retarget Source Manager** button. @@ -49,17 +42,17 @@ Think of the **Mange Retarget Source** as a list of Skeletal Meshes that you can ![](AddSource.png) -1. Choose the Skeletal Mesh for which the special animation was created. +1. Choose the **Skeletal Mesh** for which the special animation was created. ![](SelectSkeletalMesh.png) - You should now see that Skeletal Mesh listed in the **Retarget Manager**. + You will now see that Skeletal Mesh listed in the **Retarget Manager**. ![](Created.png) -1. Open the special case Animation Sequence intented for your specific Skeletal Mesh. +1. Open the special case **Animation Sequence** intended for your specific **Skeletal Mesh**. -1. In the **Asset Details** panel, locate the **Animation** category and locate the **Retarget Source** property and choose your Skeletal Mesh from the dropdown menu. +1. In the **Asset Details** panel, locate the **Animation** category and locate the **Retarget Source** property and choose your **Skeletal Mesh** from the drop-down menu. ![](DropDownSelection.png) @@ -68,23 +61,24 @@ Think of the **Mange Retarget Source** as a list of Skeletal Meshes that you can ## Set up Rig +The middle section of the Retarget Manager allows you assign a **Rig** to the Skeleton which can be used to pass animation data to a different Skeleton that uses the same Rig. + ![](SetUpRig.png) -The middle section of the Retarget Manager allows you assign a **Rig** to the Skeleton which can be used to pass animation data to a different Skeleton that uses the same Rig. This process is needed in order to perform any animation retargeting for characters that use different Skeleton assets. -You can select the Rig to use from the **Select Rig** drop-down option where a **Humanoid** option is available which you will want to select for most characters (future engine updates may include the ability to create Rigs). +You can select the Rig to use from the **Select Rig** drop-down option where a **Humanoid** option is available which you will want to select for most characters. ![](HumanoidRig.png) Once you assign the Humanoid Rig, you will need to assign Bones from the Skeleton that correspond to the same (or similar) location as the Node on the Rig. -You can the drop-down menu for Node and manually assign the corresponding Bone from your Skeleton, or you can use the **Auto Mapping** feature located at the top of the menu. +You can use the drop-down menu for Node and manually assign the corresponding Bone from your Skeleton, or you can use the **Auto Mapping** feature located at the top of the menu. This will look through your Skeleton and attempt to find the best matching Bone for each Node on the Rig. The **Clear Mapping** button will wipe all the currently assigned Bones from their corresponding Node assignment while the **Show Advanced** button will allow you to assign additional Node/Bone correlations for things like finger digits, IK Bones or Twist Bones. Once you set up the Rig for your source Skeleton (or the Skeleton asset that drives the animation that you want to retarget to another character), you will need to go into the Skeleton of the target Skeleton and assign the same Rig and define the Bones in the new Skeleton that best match up with the Nodes on the Rig. [REGION:note] -Please see [](Engine\Animation\AnimHowTo\Retargeting) for a step-by-step guide on setting up a Rig to retaget animations between characters that use different Skeletons. +Please see [](Engine\Animation\AnimHowTo\Retargeting) for a step-by-step guide on setting up a Rig to retarget animations between characters that use different Skeletons. [/REGION] @@ -102,17 +96,35 @@ Our Source Skeleton (left) is in a A-Pose while our Target Skeleton is using an ![](TargetAnimation.png)(w:540)![](BadBasePose.png)(w:550) -Above we have our target animation on the left of a character holding a shotgun, however when we retarget the animation to our new character on the right (because they are using different base poses) the arm positioning is not correct. -We can fix this by Retargeting the Base Pose inside the **Retarget Manager** which allows us to define a retargeted Base Pose to use for animation retargeting purposes rather than using the characters normal Base pose. +Above we have our target animation on the left of a character holding a shotgun, however, when we retarget the animation to our new character on the right (because they are using different base poses) the arm positioning is not correct. +We can fix this by Retargeting the Base Pose inside the **Retarget Manager** which allows us to define a Retargeted Base Pose to use for animation retargeting purposes rather than using the characters normal Base Pose. -We can select the Bones in our character and rotate them (in this case the Left and Right Shoulders) so that our character is in an A-Pose, then we click **Save Pose**: +We can select bones in our character and rotate them (in this case the left and right shoulders) so that our character is in an A-Pose, then we click **Modify Pose**: ![](RetargetedBasePose.png) -Now when we go to retarget that animation, we will see the updated retargeted base pose: +In context menu, select **Use Current Pose**: + +![](UseCurrentPose.png) + +This will set the pose you define as the Retargeted Base Pose to use when performing any animation retargeting. + +Now when we go to retarget an animation, we will see the updated Retargeted Base Pose: ![](NewBasePose.png)(w:840) -And when we retarget animations for Skeletons that have more similar base poses, we get better looking results from the retargted animation: +When we retarget animations for Skeletons that have more similar Base Poses, we get better-looking results: -![](HoldingShotGun.png) \ No newline at end of file +![](HoldingShotGun.png) + +### Importing Retarget Base Pose from Pose Asset + +From the **Modify** context menu, you can also choose to import a pose from an animation [Pose Asset](Engine/Animation/AnimPose) to use as the Retargeted Base Pose. + +![](ImportPose.png) + +In the image above, after selecting which Pose Asset to use (1) the available poses will be displayed in the selection drop-down menu (2). +After selecting a pose from the Pose Asset to use, clicking the **Import** button (3) will update the mesh in the viewport to use the pose selected as the Retargeted Base Pose. +Below (left) our default pose is shown and (right) our Retargeted Base Pose selected from a pose within our Pose Asset is shown. + +![](DefaultPose.png)(w:540)![](NewRetargetPose.png)(w:540) diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/BasePoseManager/BasePoseManager.JPN.udn b/Engine/Documentation/Source/Engine/Animation/Persona/BasePoseManager/BasePoseManager.JPN.udn index 04555fe4b91f..a377fabae26b 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/BasePoseManager/BasePoseManager.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/BasePoseManager/BasePoseManager.JPN.udn @@ -1,46 +1,39 @@ -INTSourceChangelist:3209790 -Availability:Public -Title:リターゲット マネージャ +INTSourceChangelist:3484694 +Availability:Docs Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Persona +Title:リターゲット マネージャ Description:スケルトン エディタ内のリターゲット マネージャ オプションの内容について説明します。 -version:4.14 -related:Engine\Animation\AnimationRetargeting -related:Engine/Animation/Skeleton - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Animation/Persona/AssetBrowser:title%](Engine/Animation/animation_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Animation/Persona/BasePoseManager:title% - [/PARAM] - [PARAM:description] - %Engine/Animation/Persona/BasePoseManager:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Animation/Persona/BasePoseManager] - [/PARAM] -[/OBJECT] -[/VAR] - -**スケルトン エディタ** 内の **リターゲット マネージャ** では、リターゲット ソースの管理、リグの設定、同じ [スケルトン](Engine/Animation/Skeleton) アセットを共有しないキャラクターの [アニメーションのリターゲット](Engine\Animation\AnimHowTo\Retargeting) で使用するためのリターゲットのベース ポーズを定義します。スケルトン エディタのツールバーからリターゲット マネージャを開くことができます。 +Type:Overview +SkillLevel: intermediate +Version:4.16 +Parent:Engine/Animation/Persona +Order:1 +Tags:Animation +Tags:Skeleton +Tags:Retargeting +topic-image:RetargetTopic.png +Related:Engine\Animation\AnimationRetargeting +Related:Engine/Animation/Skeleton +Related:Engine/Animation/Persona/Modes/Skeleton +Related:Engine/Animation/AnimPose +Related:Engine/Animation/Sequences [TOC(start:2 end:2)] +**スケルトン エディタ** 内の **リターゲット マネージャ** では、リターゲット ソースの管理、リグの設定、[アニメーションのリターゲット](Engine\Animation\AnimHowTo\Retargeting) で使用するためのリターゲットのベース ポーズを定義します。 ## リターゲット ソースの管理 -リターゲットではスケルトン アセットを使用し、そのスケルトンに対して作成されたスケルタルメッシュによって定義されたオリジナルの比率を持ちます。そのため、ほとんどの場合、一方向のリターゲットはスムーズに機能します。ただし、その変更版のためだけに特別なアニメーションをビルドする場合がよくあります。 +リターゲットでは[Skeleton](Engine/Animation/Skeleton) アセットを使用し、そのスケルトンに対して作成されたスケルタルメッシュによって定義されたオリジナルの比率を持ちます。そのため、ほとんどの場合、一方向のリターゲットはスムーズに機能します。 +ただし、その変更版のためだけに特別なアニメーションをビルドする場合がよくあります。 例えば、同じスケルトン アセットを共有する複数のキャラクターがあるとします (ベース キャラクター、背の低いキャラクター、背の高いキャラクターなど)。ここでは、背の高いキャラクターに対して特別なアニメーションを作成したとします。 -新規に作成したこの「背が高い版限定」アニメーションをインポートする場合でも、ベースとなるキャラクターから作成された元のものと同じ Skeleton アセットを使用する必要があります。これにより、新規アニメーションの比率に歪みが生じます。 -この解決策としては、**[Retarget Manager]** 内の **[Manage Retarget Source (リターゲットのソース管理)]** オプションを使います。これにより、アニメーション シーケンスをそのためにデザインした実際のスケルタル メッシュに関連付けることができます。こうすることで、特別なアニメーションのリターゲットで発生する問題が解消されます。 +新規に作成したこの背が高い版限定アニメーションをインポートする場合でも、ベースとなるキャラクターから作成された元のものと同じ Skeleton アセットを使用する必要があります。 +これにより、新規アニメーションの比率に歪みが生じます。 +この解決策としては、**[Retarget Manager]** 内の **[Manage Retarget Source (リターゲットのソース管理)]** オプションを使います。これにより、アニメーション シーケンスをそのためにデザインした実際のスケルタル メッシュに関連付けることができます。 +こうすることで、特別なアニメーションのリターゲットで発生する問題が解消されます。 -**[Manage Retarget Source]** は、比率を指定するために使うスケルタル メッシュのリストだと考えてみてください。リターゲットしたスケルタル メッシュに特別なアニメーションが必要な場合は、そのメッシュがリターゲット ソースとしてリスト化されていることを確認する必要があります。以下はその手順です。 +### リターゲット ソースを追加する 1. **スケルトン エディタ** 内の **ツールバー** から **[Retarget Source Manager]** ボタンをクリックします。 @@ -50,7 +43,7 @@ related:Engine/Animation/Skeleton ![](AddSource.png) -1. 特別なアニメーションを作成したスケルタル メッシュを選びます。 +1. 特別なアニメーションを作成した **スケルタル メッシュ** を選びます。 ![](SelectSkeletalMesh.png) @@ -58,7 +51,7 @@ related:Engine/Animation/Skeleton ![](Created.png) -1. 特定のスケルタルメッシュ用の特別なアニメーション シーケンスを開きます。 +1. ご自分の特定の **スケルタルメッシュ** 用の特別な **アニメーション シーケンス** を開きます。 1. **[Asset Details (アセットの詳細)]** パネルで、 **[アニメーション]** カテゴリ、そして **[Retarget Source]** プロパティの順に見て、ドロップダウン メニューからスケルタルメッシュを選択します。 @@ -69,11 +62,12 @@ related:Engine/Animation/Skeleton ## リグのセットアップ +Retarget Manager の真ん中のセクションでは、スケルトンに **リグ** を割り当ててアニメーション データを同じリグを使う別のスケルトンに渡すことができます。 + ![](SetUpRig.png) -Retarget Manager の真ん中のセクションでは、スケルトンに **リグ** を割り当ててアニメーション データを同じリグを使う別のスケルトンに渡すことができます。 このプロセスは異なるスケルトン アセットを使うキャラクターのアニメーションのリターゲットを行うために必要です。 -**[Select Rig]** ドロップダウン オプションから使用するリグを選択することができます。このオプションにある **Humanoid** はほとんどのキャラクターで選択できます (エンジンの将来のアップデートでは、リグ作成機能を含む可能性があります)。 +**[Select Rig]** ドロップダウン オプションから使用するリグを選択することができます。このオプションにある **Humanoid** はほとんどのキャラクターで選択できます。 ![](HumanoidRig.png) @@ -106,14 +100,32 @@ Humanoid Rig を割り当てたら、リグのノードと同じ (または類 上の図ではショットガンを持っているキャラクターの横にターゲット アニメーションがあります。しかし、右側の新しいキャラクターにアニメーションをリターゲットする場合、(この 2 つは異なるベース ポーズを使用しているため) アームの位置決めが正しくありません。 これは **Retarget Manager** 内でベース ポーズをリターゲットすることで修正することができます。こうすることで、キャラクターの通常のベース ポーズを使用するのではなく、リターゲットしたベースポーズをアニメーションのリターゲット目的で使用することができます。 -キャラクターのボーンを選択し回転させて (この場合、左右の肩)、キャラクターを A-Pose にして **Save Pose** をクリックすることができます。 +キャラクターのボーンを選択し回転させて (この場合、左右の肩)、キャラクターを A-Pose にして **Modify Pose** をクリックします。 ![](RetargetedBasePose.png) -アニメーションのリターゲットに進むと、リターゲットされたベースポーズが更新されているのがわかります。 +コンテキスト メニューで **[Use Current Pose (現在のポーズを使用)]** を選択します。 + +![](UseCurrentPose.png) + +これで、定義したポーズを Retargeted Base Pose として設定し、アニメーションのリターゲットを行う場合に使用するようにします。 + +アニメーションのリターゲットに進むと、更新された Retargeted Base Pose になっているのがわかります。 ![](NewBasePose.png)(w:840) -さらに多くの類似のベース ポーズを持つスケルトンのアニメーションをリターゲットすると、リターゲットしたアニメーションの結果の見た目がよくなります。 +さらに多くの類似のベース ポーズを持つスケルトンのアニメーションをリターゲットすると、結果の見た目がよくなります。 -![](HoldingShotGun.png) \ No newline at end of file +![](HoldingShotGun.png) + +### Pose アセットから Retarget Base Pose をインポートする + +**Modify** コンテキスト メニューから、Retargeted Base Pose として使うアニメーションの [Pose アセット](Engine/Animation/AnimPose) のインポートを選択することもできます。 + +![](ImportPose.png) + +上の画像では、どの Pose アセットを使用するかを選択すると (1)、利用可能なポーズが選択ドロップダウン メニューに表示されるようになります (2)。 +使用する Pose アセットを選んだ後、**Import** ボタンをクリックすると (3)、選択したポーズを Retargeted Base Pose として使うようにビューポートでメッシュが更新されます。 +以下では、デフォルト ポーズと、Pose アセット内のポーズから選択された Retargeted Base Pose が表示されています。 + +![](DefaultPose.png)(w:540)![](NewRetargetPose.png)(w:540) diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/MeshDetails/MeshDetails.INT.udn b/Engine/Documentation/Source/Engine/Animation/Persona/MeshDetails/MeshDetails.INT.udn index e9b82776f330..1a5959c777e5 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/MeshDetails/MeshDetails.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/MeshDetails/MeshDetails.INT.udn @@ -7,14 +7,14 @@ Related: Engine/Rendering/Materials Related: Engine/Content/Types/StaticMeshes/HowTo/LODCollision Related: Resources/ContentExamples/Cloth Related: Engine/Content/FBX/SkeletalMeshes -version: 4.14 +version: 4.16 type:reference topic-image:SkeletalMeshAssetDetails.png tags:Animation tags:Skeletal Mesh tags:FBX Importing -[TOC (start:2)] +[TOC (start:2 end:2)] ![](MeshDetails.png)(w:940) @@ -33,7 +33,7 @@ Materials will appear inside of the Skeletal Mesh Editor under the **Materials** ![](MaterialsTable.png) -[REGION:note] +[REGION:tip] You can add **Material Slots**, which can be used to override an LOD's section (excluding the base LOD). [/REGION] @@ -73,7 +73,7 @@ Using the LOD Previewer, you can inspect the visual differences between LODs. Al [/PARAM] [/OBJECT] -You can also enable or disable shadow casting. +You can turn on/off casting shadows on a per element, per LOD basis (some areas might not require shadow casting). [OBJECT:ComparisonSlider] [PARAM:before] @@ -84,7 +84,37 @@ You can also enable or disable shadow casting. [/PARAM] [/OBJECT] -_You can turn on/off casting shadows on a per element, per LOD basis (some areas might not require shadow casting)._ +## Reduction Settings + +[REGION:warning] +These options require the use of Simplygon. For more information on LODs and Reduction settings, please see the [](Engine/Content/Types/StaticMeshes/LOD) page for more information. +[/REGION] + +In addition to the options outlined above, each generated LOD allows for defining the **Reduction Settings** for optimization. + +![](ReductionSettings.png) + +As of Unreal Engine 4.16, you can also bake a pose into an LOD using the **Bake Pose** reduction setting. This can be set to a single frame animation sequence which will be applied to the resulting LOD mesh. +This is useful when removing bones and still wanting to retain a pose, similar to the example video shown below. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 4vcmZwpzV74 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + ## Clothing @@ -97,7 +127,10 @@ Once you've imported your Apex file, you can adjust its [Physics Properties](Eng ![](OwenApexCloth.png) -_For example, this character has two Apex files associated with it; one for the character's tie, and the other for the character's coat._ +[REGION:caption] +For example, this character has two Apex files associated with it; one for the character's tie, and the other for the character's coat. +[/REGION] + ## Mesh @@ -148,22 +181,31 @@ To assign a Post Process Anim Blueprint, select the drop-down menu and specify y The example video illustrates how the Post Process Anim Blueprint is run during gameplay on a Skeletal Mesh. [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -uroFU3M_-C4 -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + uroFU3M_-C4 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] + If you have a more complex animation setup that uses multiple Animation Blueprints, you may need to include a **Sub-Graph Input** node to the Post Process Anim Blueprint. ![](SubGraphInput.png) -_This will allow you to get the pose information from a parent Animation Blueprint (if applicable) rather than using the Skeletal Mesh's base pose._ +[REGION:caption] +This will allow you to get the pose information from a parent Animation Blueprint (if applicable) rather than using the Skeletal Mesh's base pose. +[/REGION] ## Transform diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/MeshDetails/MeshDetails.JPN.udn b/Engine/Documentation/Source/Engine/Animation/Persona/MeshDetails/MeshDetails.JPN.udn index c1eb984ed427..a1cc43c41a03 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/MeshDetails/MeshDetails.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/MeshDetails/MeshDetails.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3273317 +INTSourceChangelist:3467891 Availability:Public Title:Skeletal Mesh アセットの詳細 Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Persona @@ -8,14 +8,14 @@ Related:Engine/Rendering/Materials Related:Engine/Content/Types/StaticMeshes/HowTo/LODCollision Related:Resources/ContentExamples/Cloth Related:Engine/Content/FBX/SkeletalMeshes -version:4.14 +version:4.16 type:reference topic-image:SkeletalMeshAssetDetails.png tags:Animation tags:Skeletal Mesh tags:FBX Importing -[TOC (start:2)] +[TOC (start:2 end:2)] ![](MeshDetails.png)(w:940) @@ -34,7 +34,7 @@ APEX Clothing を割り当てて調整したり、ラグドール タイプの ![](MaterialsTable.png) -[REGION:note] +[REGION:tip] LOD セクション (ベース LOD は除く) をオーバーライドするために使用可能な **マテリアル スロット** を追加することができます。 [/REGION] @@ -74,7 +74,7 @@ LOD プレビューアを使って、LOD 間の見た目の違いを確認でき [/PARAM] [/OBJECT] -シャドウ キャストを有効または無効にすることもできます。 +エレメント毎、LOD ベースでシャドウのキャストのオン、オフを切り替えることができます (一部のエリアではシャドウをキャストする必要がないかもしれません)。 [OBJECT:ComparisonSlider] [PARAM:before] @@ -85,7 +85,37 @@ LOD プレビューアを使って、LOD 間の見た目の違いを確認でき [/PARAM] [/OBJECT] -_エレメント毎、LOD ベースでシャドウのキャストのオン、オフを切り替えることができます (一部のエリアではシャドウをキャストする必要がないかもしれません)。_ +## 削減の設定 + +[REGION:warning] +こうしたオプションでは、Simplygon を使う必要があります。LOD と Reduction Settings (削減設定)の詳細については、 [](Engine/Content/Types/StaticMeshes/LOD) ページをご覧ください。 +[/REGION] + +上記のオプションに加えて、生成した各 LOD (Level of Detail) では最適化のために **Reduction Settings (削減設定)** を定義することができます。 + +![](ReductionSettings.png) + +アンリアル エンジン 4.16 時点では、**Bake Pose** 削減設定を使ってポーズを LOD にベイクすることもできます。この設定は、結果の LOD メッシュに適用される単一フレーム アニメーション シーケンスに対して設定することができます。 +以下の動画のようにボーンを削除してもポーズを維持したい場合、便利です。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 4vcmZwpzV74 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + ## クロス @@ -98,7 +128,10 @@ Apex ファイルをインポートしたら望ましい結果になるように ![](OwenApexCloth.png) -_例えば、キャラクターには 2 つの Apex ファイルが関連付けられています。ひとつはキャラクターのネクタイに、もうひとつはキャラクターのコートに関連付けられています。_ +[REGION:caption] +例えば、キャラクターには 2 つの Apex ファイルが関連付けられています。ひとつはキャラクターのネクタイに、もうひとつはキャラクターのコートに関連付けられています。 +[/REGION] + ## メッシュ @@ -149,22 +182,31 @@ Post Process Animation ブループリントを割り当てるには、ドロッ このサンプル映像では、ゲームプレイ中にスケルタルメッシュで Post Process Anim ブループリントがどのように機能するかを示しています。 [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -uroFU3M_-C4 -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + uroFU3M_-C4 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] + 複数の Animation ブループリントを使用する複雑なセットアップのアニメーションがある場合、Post Process Anim ブループリントに **Sub-Graph Input** ノードを含める必要があるかもしれません。 ![](SubGraphInput.png) -_これでスケルタルメッシュのベースポーズを使用するのではなく、親の Animation ブループリント (該当する場合) からポーズ情報を取得することができます。_ +[REGION:caption] +これでスケルタルメッシュのベースポーズを使用するのではなく、親の Animation ブループリント (該当する場合) からポーズ情報を取得することができます。 +[/REGION] ## トランスフォーム diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/MeshDetails/MeshDetails.KOR.udn b/Engine/Documentation/Source/Engine/Animation/Persona/MeshDetails/MeshDetails.KOR.udn index ded936c1ff70..c0e7231e3621 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/MeshDetails/MeshDetails.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/MeshDetails/MeshDetails.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3273317 +INTSourceChangelist:3467891 Availability:Public Title:스켈레탈 메시 애셋 디테일 Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Persona @@ -8,14 +8,14 @@ Related: Engine/Rendering/Materials Related: Engine/Content/Types/StaticMeshes/HowTo/LODCollision Related: Resources/ContentExamples/Cloth Related: Engine/Content/FBX/SkeletalMeshes -version: 4.14 +version: 4.16 type:reference topic-image:SkeletalMeshAssetDetails.png tags:Animation tags:Skeletal Mesh tags:FBX Importing -[TOC (start:2)] +[TOC (start:2 end:2)] ![](MeshDetails.png)(w:940) @@ -34,7 +34,7 @@ tags:FBX Importing ![](MaterialsTable.png) -[REGION:note] +[REGION:tip] **Material Slots** (머티리얼 슬롯) 을 추가하여, (베이스 LOD 를 제외한) LOD 섹션을 덮어쓸 수 있습니다. [/REGION] @@ -74,18 +74,48 @@ LOD 프리뷰어를 사용하면 LOD 사이의 시각적 차이를 조사할 수 [/PARAM] [/OBJECT] -그림자 드리우기를 켜고 끄는 것도 가능합니다. +그림자 드리우기를 켜고 끄는 것은 엘리먼터 단위로도, LOD 단위로도 가능합니다 (어떤 곳에서는 그림자를 드리울 필요가 없을 수 있기 때문입니다). [OBJECT:ComparisonSlider] [PARAM:before] - ![Cast Shadows On](castshadows1.png)(w:1000) + ![그림자 드리우기 켜기](castshadows1.png)(w:1000) [/PARAM] [PARAM:after] - ![Cast Shadows Off](castshadows2.png)(w:1000) + ![그림자 드리우기 끄기](castshadows2.png)(w:1000) [/PARAM] [/OBJECT] -그림자 드리우기를 켜고 끄는 것은 엘리먼터 단위로도, LOD 단위로도 가능합니다 (어떤 곳에서는 그림자를 드리울 필요가 없을 수 있기 때문입니다). +## 감소 세팅 + +[REGION:warning] +이 옵션은 Simplygon 을 사용합니다. LOD 및 감소 세팅 관련 자세한 정보는 [](Engine/Content/Types/StaticMeshes/LOD) 문서를 참고하세요. +[/REGION] + +위 개요의 옵션에 추가로, 생성되는 LOD 마다 최적화용 **Reduction Settings** (감소 세팅) 정의가 가능합니다. + +![](ReductionSettings.png) + +언리얼 엔진 4.16 이후, **Bake Pose** 감소 세팅으로 포즈를 LOD 에 구워 넣을 수 있습니다. 이 세팅을 단일 프레임 애니메이션 시퀀스로 설정하면 결과 LOD 메시에 적용됩니다. +아래 비디오와 비슷하게, 본을 제거한 이후에도 여전히 포즈를 유지하고자 할 때 좋습니다. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 4vcmZwpzV74 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + ## 클로딩 @@ -98,7 +128,10 @@ Apex 파일 임포트를 마쳤으면, [피직스 프로퍼티](Engine/Physics/P ![](OwenApexCloth.png) -_예를 들어 이 캐릭터에는 두 개의 Apex 파일이 연관되어 있는데, 하나는 캐릭터의 타이에, 다른 하나는 코트에 연관되어 있습니다._ +[REGION:caption] +예를 들어 이 캐릭터에는 두 개의 Apex 파일이 연관되어 있는데, 하나는 캐릭터의 타이에, 다른 하나는 코트에 연관되어 있습니다. +[/REGION] + ## 메시 @@ -149,22 +182,31 @@ GPU 비용은 캡슐의 수, 드리워지는 그림자에 영향받는 픽셀 아래 예제 비디오를 통해 스켈레탈 메시에서 게임플레이 도중 포스트 프로세스 애님 블루프린트 실행 방식을 확인할 수 있습니다. [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -uroFU3M_-C4 -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + uroFU3M_-C4 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] + 다수의 애니메이션 블루프린트를 사용하는 보다 복잡한 애니메이션 구성이 있는 경우, 포스트 프로세스 애님 블루프린트에 **Sub-Graph Input** 노드를 포함시켜 줘야 할 것입니다. ![](SubGraphInput.png) -_그러면 스켈레탈 메시의 베이스 포즈를 사용하기 보다는 (적용가능한 경우) 부모 애니메이션 블루프린트에서 포즈 정보를 구할 수 있을 것입니다._ +[REGION:caption] +그러면 스켈레탈 메시의 베이스 포즈를 사용하기 보다는 (적용가능한 경우) 부모 애니메이션 블루프린트에서 포즈 정보를 구할 수 있을 것입니다._ +[/REGION] ## 트랜스폼 diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Animation/Animation.INT.udn b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Animation/Animation.INT.udn index a24f952a6518..9c8e4b01fa5a 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Animation/Animation.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Animation/Animation.INT.udn @@ -1,30 +1,33 @@ -Availability: Public -Title:Animation Editor +Availability: Docs Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Persona, Engine/Animation/Persona/Modes +Title:Animation Editor Description:Highlights the core features of the Animation Editor in Unreal Engine 4. -version: 4.14 -type:landing -topic-image:animEditor_topic.png -Related: Engine\Animation\Persona\Modes\Skeleton -Related: Engine\Animation\Persona\Modes\Mesh -Related: Engine\Animation\Persona\Modes\Graph -Related: Engine/Content/FBX/Animations +Type: Landing +version: 4.16 +Parent: Engine/Animation/Persona/Modes +Order: 1 tags:Animation tags:Skeletal Mesh tags:FBX Importing +tags:Tools +topic-image:animEditor_topic.png + +[REGION:banner] +![](AnimationBanner.png) +[/REGION] + [EXCERPT:Overview] The **Animation Editor** provides easy access to the various animation-centric assets available for a Skeletal Mesh. In the Animation Editor, you can preview playback of animation assets such as Animation Sequences, Blend Spaces, Animation Montages, make edits to animation assets, add and edit curves for Material Parameters or Morph Targets as well as define Animation Notifies (events that occur during designated points in an animation). [/EXCERPT:Overview] -When opening any animation asset through the **Content Browser** (or Editor Toolbar), the Animation Editor will open: +Please refer to each section below for a breakdown of the Animation Editor user interface: [REGION:fullwidth] ![](AnimationModeWindow.png) [/REGION] -Please refer to each section below for a breakdown of the Animation Editor user interface: ## 1. Toolbar @@ -40,11 +43,13 @@ Docked next to the Asset Details is the [](Engine/Animation/Persona/SkeletonTree The [Viewport](Engine/Animation/Persona/Viewport) window allows you to preview playback of animation assets on your selected Skeletal Mesh and provides information about your assets. You can change lighting modes, show or hide the bones of your skeleton, adjust animation playback speeds, even set your Skeletal Mesh to automatically rotate around on a turntable allowing you view it from all angles. -## 4. Details +## 4. Details / Preview Scene Settings The [Details](Engine/UI/LevelEditor/Details) panel, which is similar to the Main Editor, is primarily used for modifying options that have been added while working in the **Asset Editor**. For example, when you add a notify to an Animation Sequence, clicking on the notify will populate the Details panel with options related to the notify. Adding a new section to an Animation Montage, you can modify the content of the section from the Details panel. +Also located in this section is a tab for [Preview Settings](Engine\Animation\Persona\PreviewSettings) which enable the ability to define the viewport settings such as the **Animation Mode** or **Animation** to use as a preview, switch **Skeletal Meshes** that are used for the preview, as well as viewport lighting and Post Process settings applied so you can preview your settings with various lighting applied. + ## 5. Asset Editor The [Asset Editor](Engine/Animation/Persona/AssetEditor) is a contextual editor that changes interface layout and options based on the type of animation asset opened. You can modify Anim Sequences, Blend Spaces, Anim Montages or any other animation asset inside this window as well as playback animations (or record new animations) from the toolbar located at the bottom. diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Animation/Animation.JPN.udn b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Animation/Animation.JPN.udn index 519e7c15a1a5..117ef15ea5fa 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Animation/Animation.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Animation/Animation.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3237313 +INTSourceChangelist:3429233 Availability:Public Title:アニメーション エディタ Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Persona, Engine/Animation/Persona/Modes @@ -13,6 +13,7 @@ Related:Engine/Content/FBX/Animations tags:Animation tags:Skeletal Mesh tags:FBX Importing +tags:Tools [EXCERPT:Overview] **アニメーション エディタ** では、スケルタルメッシュで利用できる様々なAnimation アセットに簡単にアクセスできます。 diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Animation/Animation.KOR.udn b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Animation/Animation.KOR.udn index 3f338aac2fa4..6849cbeb71df 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Animation/Animation.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Animation/Animation.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3237313 +INTSourceChangelist:3429233 Availability: Public Title:애니메이션 에디터 Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Persona, Engine/Animation/Persona/Modes @@ -13,6 +13,7 @@ Related: Engine/Content/FBX/Animations tags:Animation tags:Skeletal Mesh tags:FBX Importing +tags:Tools [EXCERPT:Overview] **애니메이션 에디터** 에서는 스켈레탈 메시에 사용할 수 있는 다양한 애니메이션 관련 애셋에 쉽게 접근할 수 있습니다. diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Graph/Graph.INT.udn b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Graph/Graph.INT.udn index aca0dcb7353c..c3be1f50e442 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Graph/Graph.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Graph/Graph.INT.udn @@ -12,6 +12,7 @@ type:landing topic-image:AnimGraphEditor_topic.png tags:Animation tags:Blueprints +tags:Tools [REGION:fullwidth] diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Graph/Graph.JPN.udn b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Graph/Graph.JPN.udn index fdabae15e15a..6b5ec7183d65 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Graph/Graph.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Graph/Graph.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3237313 +INTSourceChangelist:3481084 Availability:Public Title:Animation ブループリント エディタ Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Persona, Engine/Animation/Persona/Modes @@ -13,6 +13,7 @@ type:landing topic-image:AnimGraphEditor_topic.png tags:Animation tags:Blueprints +tags:Tools [REGION:fullwidth] diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Graph/Graph.KOR.udn b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Graph/Graph.KOR.udn index 279e3d907ea3..9b3c5d59db1a 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Graph/Graph.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Graph/Graph.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3237313 +INTSourceChangelist:3481084 Availability: Public Title:애님 블루프린트 에디터 Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Persona, Engine/Animation/Persona/Modes @@ -13,6 +13,7 @@ type:landing topic-image:AnimGraphEditor_topic.png tags:Animation tags:Blueprints +tags:Tools [REGION:fullwidth] diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Mesh/Mesh.INT.udn b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Mesh/Mesh.INT.udn index 70e7e3a88cdb..4829c11094c0 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Mesh/Mesh.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Mesh/Mesh.INT.udn @@ -1,17 +1,21 @@ -Availability: Public -Title:Skeletal Mesh Editor +Availability: Docs Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Persona, Engine/Animation/Persona/Modes +Title:Skeletal Mesh Editor Description:Highlights the core features of the Skeletal Mesh Editor in Unreal Engine 4. -version: 4.14 -Related: Engine\Animation\Persona\Modes\Skeleton -Related: Engine\Animation\Persona\Modes\Animation -Related: Engine\Animation\Persona\Modes\Graph -Related: Engine/Content/FBX/SkeletalMeshes -type:landing -topic-image:skelMeshEditor_topic.png +Type: Landing +version: 4.16 +Parent: Engine/Animation/Persona/Modes +Order: 1 tags:Animation tags:Skeletal Mesh tags:FBX Importing +tags:Tools +topic-image:skelMeshEditor_topic.png + +[REGION:banner] +![](SkeletalMeshEditorBanner.png) +[/REGION] + [EXCERPT:Overview] Whenever you open a **Skeletal Mesh** asset inside the **Content Browser** (or from the **Editor Toolbar**), the **Skeletal Mesh Editor** will open. @@ -20,11 +24,13 @@ This editor includes windows that can be found in some of the other Animation To [/EXCERPT:Overview] +Please refer to each section below for a breakdown of the Skeletal Mesh Editor user interface: + [REGION:fullwidth] ![](SkeletalMeshEditor.png) [/REGION] -Please refer to each section below for a breakdown of the Skeletal Mesh Editor user interface: + ## 1. Toolbar @@ -46,4 +52,6 @@ From the Viewport, you can also assign a preview animation for the Skeletal Mesh The Morph Target Preview tab lets you preview any [Morph Targets](Engine/Animation/Persona/MorphTargetPreviewer) (or Blend Shapes) available for the current Skeletal Mesh. +Also located in this section is a tab for [Preview Settings](Engine\Animation\Persona\PreviewSettings) which enable the ability to define the viewport settings such as the **Animation Mode** or **Animation** to use as a preview, switch **Skeletal Meshes** that are used for the preview, as well as viewport lighting and Post Process settings applied so you can preview your settings with various lighting applied. + diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Mesh/Mesh.JPN.udn b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Mesh/Mesh.JPN.udn index e2c0881e8e91..eb06a3fcc10a 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Mesh/Mesh.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Mesh/Mesh.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3237313 +INTSourceChangelist:3481084 Availability:Public Title:スケルタルメッシュ エディタ Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Persona, Engine/Animation/Persona/Modes @@ -13,6 +13,7 @@ topic-image:skelMeshEditor_topic.png tags:Animation tags:Skeletal Mesh tags:FBX Importing +tags:Tools [EXCERPT:Overview] **コンテンツ ブラウザ** 内で (または **エディタ ツールバー** から) **Skeletal Mesh** アセットを開くと 、**スケルタルメッシュ エディタ** が開きます。 diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Mesh/Mesh.KOR.udn b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Mesh/Mesh.KOR.udn index c2cf52fd041e..fb86d2d60c1f 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Mesh/Mesh.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Mesh/Mesh.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3237313 +INTSourceChangelist:3481084 Availability: Public Title: 스켈레탈 메시 에디터 Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Persona, Engine/Animation/Persona/Modes @@ -13,6 +13,7 @@ topic-image:skelMeshEditor_topic.png tags:Animation tags:Skeletal Mesh tags:FBX Importing +tags:Tools [EXCERPT:Overview] **콘텐츠 브라우저** (또는 **에디터 툴바**) 안에서 **스켈레탈 메시** 애셋을 열 때마다, **스켈레탈 메시 에디터** 가 열립니다. diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Modes.INT.udn b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Modes.INT.udn index 5a484a0e511a..04c1b0393fed 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Modes.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Modes.INT.udn @@ -13,6 +13,7 @@ tags:Animation tags:Skeleton Asset tags:Animation Blueprint tags:Skeletal Mesh +tags:Tools [EXCERPT:Overview] Creating animated characters in Unreal Engine 4 involves using several different Animation Tools (or Editors), each of which focus on different aspects of animation. diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Modes.JPN.udn b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Modes.JPN.udn index 6e54bde90738..e40567a6bc80 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Modes.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Modes.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3237313 +INTSourceChangelist:3429233 Availability:Public Title:アニメーション ツール Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Persona @@ -14,6 +14,7 @@ tags:Animation tags:Skeleton Asset tags:Animation Blueprint tags:Skeletal Mesh +tags:Tools [EXCERPT:Overview] UE4 でアニメートされたキャラクターを作成する場合、様々なアニメーション ツール (エディタ) を使用することになります。それぞれがアニメーションの異なる側面に重点を置いています。 diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Modes.KOR.udn b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Modes.KOR.udn index 7e4c8abd8cf3..a4de673a5da4 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Modes.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Modes.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3237313 +INTSourceChangelist:3429233 Availability: Public Title:애니메이션 툴 Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Persona @@ -14,6 +14,7 @@ tags:Animation tags:Skeleton Asset tags:Animation Blueprint tags:Skeletal Mesh +tags:Tools [EXCERPT:Overview] 언리얼 엔진 4 에서 애니메이션 캐릭터를 만들기 위해서는 여러가지 다양한 애니메이션 툴( 또는 에디터들)을 사용해야 하는데, 애니메이션의 특징에 따라 쓰이는 툴이 다릅니다. diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Skeleton/Skeleton.INT.udn b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Skeleton/Skeleton.INT.udn index 8cc0cfcdf8aa..4122359015c6 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Skeleton/Skeleton.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Skeleton/Skeleton.INT.udn @@ -1,17 +1,21 @@ -Availability: Public +Availability: Docs +Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Persona, Engine/Animation/Persona/Modes Title:Skeleton Editor -Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Persona Description:Highlights the core features of the Skeleton Editor in Unreal Engine 4. -version: 4.14 -Related: Engine\Animation\Persona\Modes\Mesh -Related: Engine\Animation\Persona\Modes\Animation -Related: Engine\Animation\Persona\Modes\Graph -Related: Engine/Content/FBX/SkeletalMeshes -type:landing -topic-image:skeletonEdtior_topic.png +Type: Landing +version: 4.16 +Parent: Engine/Animation/Persona/Modes +Order: 1 tags:Skeleton tags:Skeletal Mesh tags:Animation +tags:Tools +topic-image:skeletonEdtior_topic.png + +[REGION:banner] +![](BannerImage2.png) +[/REGION] + [EXCERPT:Overview] The **Skeleton Editor** is a tool used for working with [](Engine/Animation/Skeleton) inside Unreal Engine 4. @@ -20,12 +24,12 @@ In this editor, you can create [Skeletal Mesh Sockets](Engine/Content\Types\Skel It is in this editor where you can also set up your [](Engine/Animation/AnimationRetargeting) options and manage your retarget sources with the [Retarget Manager.](Engine/Animation/Persona/BasePoseManager/) [/EXCERPT:Overview] +Please refer to each section below for a breakdown of the Skeleton Editor user interface: + [REGION:fullwidth] ![](Persona_MODE_Skeleton_Large.png) [/REGION] -Please refer to each section below for a breakdown of the Skeleton Editor user interface: - ## 1. Toolbar The [Toolbar](Engine/Animation/Persona/Toolbar) inside the Skeleton Editor provides you with options for saving any changes made to your Skeleton or locating it in the Content Browser. @@ -41,27 +45,16 @@ The [](Engine/Animation/Persona/SkeletonTree) shows the skeletal hierarchy of th The [Viewport](Engine/Animation/Persona/Viewport) window allows you to preview the changes that you make and adjust socket positioning or preview any animation curves. From the Viewport, you can also assign a preview animation for the Skeletal Mesh to use, change lighting modes, show or hide the bones of your skeleton, adjust animation playback speeds, even set your Skeletal Mesh to automatically rotate around on a turntable allowing you view it from all angles. -## 4. Details +## 4. Details / Preview Settings The [Details](Engine/UI/LevelEditor/Details) panel, which is similar to the Main Editor, is primarily used for modifying the properties of added elements like Sockets. For example, when you add a Socket to the Skeleton, clicking on the Socket in the Skeleton Tree will populate the Details panel with options related to how the Socket functions. +Also located in this section is a tab for [Preview Settings](Engine\Animation\Persona\PreviewSettings) which enable the ability to define the viewport settings such as the **Animation Mode** or **Animation** to use as a preview, switch **Skeletal Meshes** that are used for the preview, as well as viewport lighting and Post Process settings applied so you can preview your settings with various lighting applied. + ## 5. Anim Curves / Animation Notifies The [Anim Curves](Engine/Animation/Persona/AnimCurves) viewer lets you preview any animation curves available for the current mesh in the Viewport. The [Animation Notifies](Engine/Animation/Persona/AnimationNotifies) window lets you modify your custom created Animation Notifies that are associated with the Skeleton asset. - - diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Skeleton/Skeleton.JPN.udn b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Skeleton/Skeleton.JPN.udn index f6646fc39695..f286055b2c0c 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Skeleton/Skeleton.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Skeleton/Skeleton.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3237313 +INTSourceChangelist:3429233 Availability:Public Title:スケルトン エディタ Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Persona @@ -13,6 +13,7 @@ topic-image:skeletonEdtior_topic.png tags:Skeleton tags:Skeletal Mesh tags:Animation +tags:Tools [EXCERPT:Overview] **スケルトン エディタ** は、UE4 内の [](Engine/Animation/Skeleton) で作業するために使うツールです。 diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Skeleton/Skeleton.KOR.udn b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Skeleton/Skeleton.KOR.udn index b45a126547ca..e25ffdd47ada 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Skeleton/Skeleton.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/Modes/Skeleton/Skeleton.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3237313 +INTSourceChangelist:3429233 Availability: Public Title:스켈레톤 에디터 Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Persona @@ -13,6 +13,7 @@ topic-image:skeletonEdtior_topic.png tags:Skeleton tags:Skeletal Mesh tags:Animation +tags:Tools [EXCERPT:Overview] **스켈레톤 에디터** 는 언리얼 엔진 4 안에서 [](Engine/Animation/Skeleton) 작업을 하는 데 사용되는 툴입니다. diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/MorphTargetPreviewer/MorphTargetPreviewer.CHN.udn b/Engine/Documentation/Source/Engine/Animation/Persona/MorphTargetPreviewer/MorphTargetPreviewer.CHN.udn index b2a33c5fcc5d..0b4b8be28bb0 100644 Binary files a/Engine/Documentation/Source/Engine/Animation/Persona/MorphTargetPreviewer/MorphTargetPreviewer.CHN.udn and b/Engine/Documentation/Source/Engine/Animation/Persona/MorphTargetPreviewer/MorphTargetPreviewer.CHN.udn differ diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/MorphTargetPreviewer/MorphTargetPreviewer.INT.udn b/Engine/Documentation/Source/Engine/Animation/Persona/MorphTargetPreviewer/MorphTargetPreviewer.INT.udn index 9ed173b52caa..acffef07a5db 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/MorphTargetPreviewer/MorphTargetPreviewer.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/MorphTargetPreviewer/MorphTargetPreviewer.INT.udn @@ -9,14 +9,12 @@ Related: Engine/Content/Types/StaticMeshes/MorphTargets Related: Resources/ContentExamples/MorphTargets version: 4.14 type:reference -topic-image:MorphTargetSmall.png tags:Animation tags:Morph Target tags:Skeletal Mesh tags:FBX Importing SkillLevel:Intermediate Parent:Engine/Animation/Persona -Order: [TOC (start:2)] diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/MorphTargetPreviewer/MorphTargetPreviewer.JPN.udn b/Engine/Documentation/Source/Engine/Animation/Persona/MorphTargetPreviewer/MorphTargetPreviewer.JPN.udn index cd9ae65c955d..6552fada4261 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/MorphTargetPreviewer/MorphTargetPreviewer.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/MorphTargetPreviewer/MorphTargetPreviewer.JPN.udn @@ -1,4 +1,5 @@ -Availability:Public +INTSourceChangelist:3429233 +Availability:Public Title:モーフ ターゲット プレビューア Crumbs: Description:アニメーション エディタで利用可能な編集モードのユーザーガイド @@ -9,14 +10,12 @@ Related:Engine/Content/Types/StaticMeshes/MorphTargets Related:Resources/ContentExamples/MorphTargets version:4.14 type:reference -topic-image:MorphTargetSmall.png tags:Animation tags:Morph Target tags:Skeletal Mesh tags:FBX Importing SkillLevel:Intermediate Parent:Engine/Animation/Persona -Order: [TOC (start:2)] diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/MorphTargetPreviewer/MorphTargetPreviewer.KOR.udn b/Engine/Documentation/Source/Engine/Animation/Persona/MorphTargetPreviewer/MorphTargetPreviewer.KOR.udn index 02a15a5dc934..88271c4a78d2 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/MorphTargetPreviewer/MorphTargetPreviewer.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/MorphTargetPreviewer/MorphTargetPreviewer.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3318533 +INTSourceChangelist:3429233 Availability:Public Title:모프 타겟 프리뷰어 Crumbs: @@ -10,14 +10,12 @@ Related: Engine/Content/Types/StaticMeshes/MorphTargets Related: Resources/ContentExamples/MorphTargets version: 4.14 type:reference -topic-image:MorphTargetSmall.png tags:Animation tags:Morph Target tags:Skeletal Mesh tags:FBX Importing SkillLevel:Intermediate Parent:Engine/Animation/Persona -Order: [TOC (start:2)] diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/PersonaEditor.INT.udn b/Engine/Documentation/Source/Engine/Animation/Persona/PersonaEditor.INT.udn index 90ffbfc60035..8e40de662438 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/PersonaEditor.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/PersonaEditor.INT.udn @@ -14,13 +14,42 @@ tags:Animation tags:Skeleton Asset tags:Animation Blueprint tags:Skeletal Mesh +tags:Tools type:landing [VAR:ModeSize]w:450 convert:false[/VAR] - +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] [REGION:asyncgif] ![](UpdatedPersonaWindowAnim.gif) [/REGION] +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +[REGION:asyncgif] +![](UpdatedPersonaWindowAnim_Mac.gif) +[/REGION] +[/PARAM] +[/OBJECT] + [EXCERPT:Intro] Unreal Engine 4 contains a four major tools for working with skeletal animations and **Skeletal Meshes**: The Skeleton Editor, the Skeletal Mesh Editor, the Animation Editor, and the Animation Blueprint Editor. Each of these are accessed by editing an associated asset or by using the four navigation buttons at the top of each animation editor. @@ -43,9 +72,33 @@ Before Unreal Engine version 4.14, the combined animation editor was known as ** ## Opening a Specific Animation Editor -[REGION:raw] -![](OpeningPersona.png) -[/REGION] +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](OpenPersona_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](OpenPersona_Mac.png) +[/PARAM] +[/OBJECT] Each animation editor can be opened from the **Content Browser** by **Double-clicking** on an asset that is associated with that editor: diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/PersonaEditor.JPN.udn b/Engine/Documentation/Source/Engine/Animation/Persona/PersonaEditor.JPN.udn index 619f13db7f60..e6b5b0772995 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/PersonaEditor.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/PersonaEditor.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3237313 +INTSourceChangelist:3481084 Availability:Public Title:アニメーション エディタ Crumbs: %ROOT%, Engine, Engine/Animation @@ -15,13 +15,42 @@ tags:Animation tags:Skeleton Asset tags:Animation Blueprint tags:Skeletal Mesh +tags:Tools type:landing [VAR:ModeSize]w:450 convert:false[/VAR] - +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] [REGION:asyncgif] ![](UpdatedPersonaWindowAnim.gif) [/REGION] +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +[REGION:asyncgif] +![](UpdatedPersonaWindowAnim_Mac.gif) +[/REGION] +[/PARAM] +[/OBJECT] + [EXCERPT:Intro] UE4 にはスケルタル アニメーションと **スケルタルメッシュ** で作業する場合に使う以下の 4 種類の主要ツールがあります。スケルトン エディタ、スケルタルメッシュ エディタ、アニメーション エディタ、アニメーション ブループリント エディタの 4 つです。各エディタにアクセスするには、関連するアセットを編集するか、各アニメーション エディタの上部にある 4 つのナビゲーション ボタンを使います。 @@ -44,9 +73,33 @@ UE4 にはスケルタル アニメーションと **スケルタルメッシュ ## 特定のアニメーション エディタを開く -[REGION:raw] -![](OpeningPersona.png) -[/REGION] +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](OpenPersona_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](OpenPersona_Mac.png) +[/PARAM] +[/OBJECT] 各アニメーション エディタは、**コンテンツ ブラウザ** でエディタと関連するアセットを **ダブルクリック** して開くことができます。 diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/PersonaEditor.KOR.udn b/Engine/Documentation/Source/Engine/Animation/Persona/PersonaEditor.KOR.udn index c026bddef061..88be4205dd82 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/PersonaEditor.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/PersonaEditor.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3237313 +INTSourceChangelist:3481084 Availability:Public Title:애니메이션 에디터 Crumbs: %ROOT%, Engine, Engine/Animation @@ -15,13 +15,42 @@ tags:Animation tags:Skeleton Asset tags:Animation Blueprint tags:Skeletal Mesh +tags:Tools type:landing [VAR:ModeSize]w:450 convert:false[/VAR] - +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] [REGION:asyncgif] ![](UpdatedPersonaWindowAnim.gif) [/REGION] +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +[REGION:asyncgif] +![](UpdatedPersonaWindowAnim_Mac.gif) +[/REGION] +[/PARAM] +[/OBJECT] + [EXCERPT:Intro] 언리얼 엔진 4 에는 스켈레탈 애니메이션 및 **스켈레탈 메시** 작업에 쓰이는 주요 툴이 네 가지 들어있는데, 스켈레톤 에디터, 스켈레탈 메시 에디터, 애니메이션 에디터, 애니메이션 블루프린트 에디터 입니다. 이들 각각은 할당된 애셋을 편집하거나 각 애니메이션 에디터 상단의 내비게이션 버튼 넷을 사용하여 접근할 수 있습니다. @@ -44,9 +73,33 @@ type:landing ## 특정 애니메이션 에디터 열기 -[REGION:raw] -![](OpeningPersona.png) -[/REGION] +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](OpenPersona_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](OpenPersona_Mac.png) +[/PARAM] +[/OBJECT] 각 애니메이션 에디터는 **콘텐츠 브라우저** 에서 해당 에디터에 연결된 애셋을 **더블클릭** 하는 것으로 열 수 있습니다: diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/PreviewSettings/PreviewSettings.CHN.udn b/Engine/Documentation/Source/Engine/Animation/Persona/PreviewSettings/PreviewSettings.CHN.udn new file mode 100644 index 000000000000..f7e37ddb1144 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Animation/Persona/PreviewSettings/PreviewSettings.CHN.udn @@ -0,0 +1,131 @@ +INTSourceChangelist:0 +Availability: Docs +Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Persona +Title:Preview Settings +Description:User guide for the Preview Settings panel inside the Animation Tools. +Type: Reference +version: 4.16 +Parent: Engine/Animation/Persona +Order: 1 +Tags: Animation +Tags: Viewport +topic-image:PreviewTopic.png +Related: Engine/Animation/AnimHowTo/PreviewingAnimations +Related: Engine/UI/MeshPreviewScene +Related: Engine/Rendering/PostProcessEffects +Related: Engine/Rendering/LightingAndShadows + +[TOC (start:2 end:2)] + +The **Preview Settings** enables you to quickly assess what your assets will look like in multiple environments and light scenarios without having to set up these scenes within your level. +Several different settings can be defined and applied from Skeletal Meshes to lighting and Post Process effects all within each of the [](Engine/Animation/Persona/Modes) inside the editor. + +## Animation + +This section is used to define the method in which to apply animation to the preview mesh. + +![](Animation.png) + +| Option | Description | +|-------|------| +| **Animation Mode** | The method by which the preview is animated (**Default**, **Reference Pose** or **Use Specific Animation**). | +| **Animation** | The preview animation to use. | + +## Mesh + +This section enables you to change the Skeletal Mesh used for previewing. + +![](Mesh.png) + +| Option | Description | +|-------|------| +| **Preview Mesh (Animation)** | The Skeletal Mesh to use for previewing. | + +## Additional Meshes + +This section enables you to include additional Skeletal Meshes (such as weapons, items or other objects) to the preview scene. + +![](PreviewMeshCollection.png) + +| Option | Description | +|-------|------| +| **Additional Meshes** | The Preview Mesh Collection to use as included meshes for previewing. | +| **Skeletal Meshes** | The Skeletal Mesh assets that are included in the specified Preview Mesh Collection. | + + +## Settings + +This section contains various settings that define the makeup of the viewport for previewing. + +![](Settings.png) + +| Option | Description | +|-------|------| +| **Profile Name** | Name to identify the profile. | +| **Shared Profile** | Whether or not this profile should be stored in the project.ini file. | +| **Directional Light Intensity** | Manually set the directional light intensity (0.0 - 20.0). | +| **Direction Light Color** | Manually set the directional light color. | +| **Sky Light Intensity** | Manually set the sky light intensity (0.0 - 20.0). | +| **Rotate Sky and Directional Lighting** | Toggle rotating of the sky and directional lighting. Press **K** and drag for manual rotating of Sky and **L** for Directional Lighting. | +| **Show Environment** | Toggle visibility of the environment sphere. | +| **Show Floor** | Toggle visibility of the floor mesh. | +| **Environment Cube Map** | Sets the environment cube map used for sky lighting and reflections. | +| **Post Processing Enabled** | Whether or not the Post Processing should influence the scene. | +| **Lighting Rig Rotation** | Current rotation value of the sky in degrees (0 - 360). | +| **Rotation Speed** | Speed at which the sky rotates when rotating is toggled. | + +Your settings can be saved as a **Profile** and you can add and switch between Profiles from the Profiles menu at the bottom of the window. + +![](ProfileOption.png) + +## Color Grading + +This section includes various **Color Grading** options for the viewport. + +![](ColorGrading.png) + +[REGION:note] +Please see [](Engine/Rendering/PostProcessEffects/ColorGrading) for more information. +[/REGION] + +## Lens + +This section includes the ability to apply various Post Processing effects to the viewport. + +![](LensOptions.png) + +[REGION:note] +Please see [](Engine/Rendering/PostProcessEffects) for more information. +[/REGION] + +## Rendering Features + +This section includes the ability to apply various lighting effects to the viewport. + +![](RenderingFeatures.png) + +[REGION:note] +Please see [](Engine/Rendering/LightingAndShadows) for more information. +[/REGION] + +## Tonemapper + +In this section, you can define various **Tone Mapping** functions. + +![](ToneMapper.png) + +[REGION:note] +Please see [Tone Mapping](Engine/Rendering/PostProcessEffects/ColorGrading) for more information. +[/REGION] + +## Mobile Tonemapper + +This section includes the ability to define **Tone Mapping** functions for mobile platforms. + +![](MobileToneMapper.png) + +[REGION:note] +Please see [](Platforms/Mobile/PostProcessEffects) for more information. +[/REGION] + + diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/PreviewSettings/PreviewSettings.INT.udn b/Engine/Documentation/Source/Engine/Animation/Persona/PreviewSettings/PreviewSettings.INT.udn new file mode 100644 index 000000000000..fd554121c276 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Animation/Persona/PreviewSettings/PreviewSettings.INT.udn @@ -0,0 +1,130 @@ +Availability: Docs +Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Persona +Title:Preview Settings +Description:User guide for the Preview Settings panel inside the Animation Tools. +Type: Reference +version: 4.16 +Parent: Engine/Animation/Persona +Order: 1 +Tags: Animation +Tags: Viewport +topic-image:PreviewTopic.png +Related: Engine/Animation/AnimHowTo/PreviewingAnimations +Related: Engine/UI/MeshPreviewScene +Related: Engine/Rendering/PostProcessEffects +Related: Engine/Rendering/LightingAndShadows + +[TOC (start:2 end:2)] + +The **Preview Settings** enables you to quickly assess what your assets will look like in multiple environments and light scenarios without having to set up these scenes within your level. +Several different settings can be defined and applied from Skeletal Meshes to lighting and Post Process effects all within each of the [](Engine/Animation/Persona/Modes) inside the editor. + +## Animation + +This section is used to define the method in which to apply animation to the preview mesh. + +![](Animation.png) + +| Option | Description | +|-------|------| +| **Animation Mode** | The method by which the preview is animated (**Default**, **Reference Pose** or **Use Specific Animation**). | +| **Animation** | The preview animation to use. | + +## Mesh + +This section enables you to change the Skeletal Mesh used for previewing. + +![](Mesh.png) + +| Option | Description | +|-------|------| +| **Preview Mesh (Animation)** | The Skeletal Mesh to use for previewing. | + +## Additional Meshes + +This section enables you to include additional Skeletal Meshes (such as weapons, items or other objects) to the preview scene. + +![](PreviewMeshCollection.png) + +| Option | Description | +|-------|------| +| **Additional Meshes** | The Preview Mesh Collection to use as included meshes for previewing. | +| **Skeletal Meshes** | The Skeletal Mesh assets that are included in the specified Preview Mesh Collection. | + + +## Settings + +This section contains various settings that define the makeup of the viewport for previewing. + +![](Settings.png) + +| Option | Description | +|-------|------| +| **Profile Name** | Name to identify the profile. | +| **Shared Profile** | Whether or not this profile should be stored in the project.ini file. | +| **Directional Light Intensity** | Manually set the directional light intensity (0.0 - 20.0). | +| **Direction Light Color** | Manually set the directional light color. | +| **Sky Light Intensity** | Manually set the sky light intensity (0.0 - 20.0). | +| **Rotate Sky and Directional Lighting** | Toggle rotating of the sky and directional lighting. Press **K** and drag for manual rotating of Sky and **L** for Directional Lighting. | +| **Show Environment** | Toggle visibility of the environment sphere. | +| **Show Floor** | Toggle visibility of the floor mesh. | +| **Environment Cube Map** | Sets the environment cube map used for sky lighting and reflections. | +| **Post Processing Enabled** | Whether or not the Post Processing should influence the scene. | +| **Lighting Rig Rotation** | Current rotation value of the sky in degrees (0 - 360). | +| **Rotation Speed** | Speed at which the sky rotates when rotating is toggled. | + +Your settings can be saved as a **Profile** and you can add and switch between Profiles from the Profiles menu at the bottom of the window. + +![](ProfileOption.png) + +## Color Grading + +This section includes various **Color Grading** options for the viewport. + +![](ColorGrading.png) + +[REGION:note] +Please see [](Engine/Rendering/PostProcessEffects/ColorGrading) for more information. +[/REGION] + +## Lens + +This section includes the ability to apply various Post Processing effects to the viewport. + +![](LensOptions.png) + +[REGION:note] +Please see [](Engine/Rendering/PostProcessEffects) for more information. +[/REGION] + +## Rendering Features + +This section includes the ability to apply various lighting effects to the viewport. + +![](RenderingFeatures.png) + +[REGION:note] +Please see [](Engine/Rendering/LightingAndShadows) for more information. +[/REGION] + +## Tonemapper + +In this section, you can define various **Tone Mapping** functions. + +![](ToneMapper.png) + +[REGION:note] +Please see [Tone Mapping](Engine/Rendering/PostProcessEffects/ColorGrading) for more information. +[/REGION] + +## Mobile Tonemapper + +This section includes the ability to define **Tone Mapping** functions for mobile platforms. + +![](MobileToneMapper.png) + +[REGION:note] +Please see [](Platforms/Mobile/PostProcessEffects) for more information. +[/REGION] + + diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/PreviewSettings/PreviewSettings.JPN.udn b/Engine/Documentation/Source/Engine/Animation/Persona/PreviewSettings/PreviewSettings.JPN.udn new file mode 100644 index 000000000000..f7e37ddb1144 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Animation/Persona/PreviewSettings/PreviewSettings.JPN.udn @@ -0,0 +1,131 @@ +INTSourceChangelist:0 +Availability: Docs +Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Persona +Title:Preview Settings +Description:User guide for the Preview Settings panel inside the Animation Tools. +Type: Reference +version: 4.16 +Parent: Engine/Animation/Persona +Order: 1 +Tags: Animation +Tags: Viewport +topic-image:PreviewTopic.png +Related: Engine/Animation/AnimHowTo/PreviewingAnimations +Related: Engine/UI/MeshPreviewScene +Related: Engine/Rendering/PostProcessEffects +Related: Engine/Rendering/LightingAndShadows + +[TOC (start:2 end:2)] + +The **Preview Settings** enables you to quickly assess what your assets will look like in multiple environments and light scenarios without having to set up these scenes within your level. +Several different settings can be defined and applied from Skeletal Meshes to lighting and Post Process effects all within each of the [](Engine/Animation/Persona/Modes) inside the editor. + +## Animation + +This section is used to define the method in which to apply animation to the preview mesh. + +![](Animation.png) + +| Option | Description | +|-------|------| +| **Animation Mode** | The method by which the preview is animated (**Default**, **Reference Pose** or **Use Specific Animation**). | +| **Animation** | The preview animation to use. | + +## Mesh + +This section enables you to change the Skeletal Mesh used for previewing. + +![](Mesh.png) + +| Option | Description | +|-------|------| +| **Preview Mesh (Animation)** | The Skeletal Mesh to use for previewing. | + +## Additional Meshes + +This section enables you to include additional Skeletal Meshes (such as weapons, items or other objects) to the preview scene. + +![](PreviewMeshCollection.png) + +| Option | Description | +|-------|------| +| **Additional Meshes** | The Preview Mesh Collection to use as included meshes for previewing. | +| **Skeletal Meshes** | The Skeletal Mesh assets that are included in the specified Preview Mesh Collection. | + + +## Settings + +This section contains various settings that define the makeup of the viewport for previewing. + +![](Settings.png) + +| Option | Description | +|-------|------| +| **Profile Name** | Name to identify the profile. | +| **Shared Profile** | Whether or not this profile should be stored in the project.ini file. | +| **Directional Light Intensity** | Manually set the directional light intensity (0.0 - 20.0). | +| **Direction Light Color** | Manually set the directional light color. | +| **Sky Light Intensity** | Manually set the sky light intensity (0.0 - 20.0). | +| **Rotate Sky and Directional Lighting** | Toggle rotating of the sky and directional lighting. Press **K** and drag for manual rotating of Sky and **L** for Directional Lighting. | +| **Show Environment** | Toggle visibility of the environment sphere. | +| **Show Floor** | Toggle visibility of the floor mesh. | +| **Environment Cube Map** | Sets the environment cube map used for sky lighting and reflections. | +| **Post Processing Enabled** | Whether or not the Post Processing should influence the scene. | +| **Lighting Rig Rotation** | Current rotation value of the sky in degrees (0 - 360). | +| **Rotation Speed** | Speed at which the sky rotates when rotating is toggled. | + +Your settings can be saved as a **Profile** and you can add and switch between Profiles from the Profiles menu at the bottom of the window. + +![](ProfileOption.png) + +## Color Grading + +This section includes various **Color Grading** options for the viewport. + +![](ColorGrading.png) + +[REGION:note] +Please see [](Engine/Rendering/PostProcessEffects/ColorGrading) for more information. +[/REGION] + +## Lens + +This section includes the ability to apply various Post Processing effects to the viewport. + +![](LensOptions.png) + +[REGION:note] +Please see [](Engine/Rendering/PostProcessEffects) for more information. +[/REGION] + +## Rendering Features + +This section includes the ability to apply various lighting effects to the viewport. + +![](RenderingFeatures.png) + +[REGION:note] +Please see [](Engine/Rendering/LightingAndShadows) for more information. +[/REGION] + +## Tonemapper + +In this section, you can define various **Tone Mapping** functions. + +![](ToneMapper.png) + +[REGION:note] +Please see [Tone Mapping](Engine/Rendering/PostProcessEffects/ColorGrading) for more information. +[/REGION] + +## Mobile Tonemapper + +This section includes the ability to define **Tone Mapping** functions for mobile platforms. + +![](MobileToneMapper.png) + +[REGION:note] +Please see [](Platforms/Mobile/PostProcessEffects) for more information. +[/REGION] + + diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/PreviewSettings/PreviewSettings.KOR.udn b/Engine/Documentation/Source/Engine/Animation/Persona/PreviewSettings/PreviewSettings.KOR.udn new file mode 100644 index 000000000000..f7e37ddb1144 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Animation/Persona/PreviewSettings/PreviewSettings.KOR.udn @@ -0,0 +1,131 @@ +INTSourceChangelist:0 +Availability: Docs +Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Persona +Title:Preview Settings +Description:User guide for the Preview Settings panel inside the Animation Tools. +Type: Reference +version: 4.16 +Parent: Engine/Animation/Persona +Order: 1 +Tags: Animation +Tags: Viewport +topic-image:PreviewTopic.png +Related: Engine/Animation/AnimHowTo/PreviewingAnimations +Related: Engine/UI/MeshPreviewScene +Related: Engine/Rendering/PostProcessEffects +Related: Engine/Rendering/LightingAndShadows + +[TOC (start:2 end:2)] + +The **Preview Settings** enables you to quickly assess what your assets will look like in multiple environments and light scenarios without having to set up these scenes within your level. +Several different settings can be defined and applied from Skeletal Meshes to lighting and Post Process effects all within each of the [](Engine/Animation/Persona/Modes) inside the editor. + +## Animation + +This section is used to define the method in which to apply animation to the preview mesh. + +![](Animation.png) + +| Option | Description | +|-------|------| +| **Animation Mode** | The method by which the preview is animated (**Default**, **Reference Pose** or **Use Specific Animation**). | +| **Animation** | The preview animation to use. | + +## Mesh + +This section enables you to change the Skeletal Mesh used for previewing. + +![](Mesh.png) + +| Option | Description | +|-------|------| +| **Preview Mesh (Animation)** | The Skeletal Mesh to use for previewing. | + +## Additional Meshes + +This section enables you to include additional Skeletal Meshes (such as weapons, items or other objects) to the preview scene. + +![](PreviewMeshCollection.png) + +| Option | Description | +|-------|------| +| **Additional Meshes** | The Preview Mesh Collection to use as included meshes for previewing. | +| **Skeletal Meshes** | The Skeletal Mesh assets that are included in the specified Preview Mesh Collection. | + + +## Settings + +This section contains various settings that define the makeup of the viewport for previewing. + +![](Settings.png) + +| Option | Description | +|-------|------| +| **Profile Name** | Name to identify the profile. | +| **Shared Profile** | Whether or not this profile should be stored in the project.ini file. | +| **Directional Light Intensity** | Manually set the directional light intensity (0.0 - 20.0). | +| **Direction Light Color** | Manually set the directional light color. | +| **Sky Light Intensity** | Manually set the sky light intensity (0.0 - 20.0). | +| **Rotate Sky and Directional Lighting** | Toggle rotating of the sky and directional lighting. Press **K** and drag for manual rotating of Sky and **L** for Directional Lighting. | +| **Show Environment** | Toggle visibility of the environment sphere. | +| **Show Floor** | Toggle visibility of the floor mesh. | +| **Environment Cube Map** | Sets the environment cube map used for sky lighting and reflections. | +| **Post Processing Enabled** | Whether or not the Post Processing should influence the scene. | +| **Lighting Rig Rotation** | Current rotation value of the sky in degrees (0 - 360). | +| **Rotation Speed** | Speed at which the sky rotates when rotating is toggled. | + +Your settings can be saved as a **Profile** and you can add and switch between Profiles from the Profiles menu at the bottom of the window. + +![](ProfileOption.png) + +## Color Grading + +This section includes various **Color Grading** options for the viewport. + +![](ColorGrading.png) + +[REGION:note] +Please see [](Engine/Rendering/PostProcessEffects/ColorGrading) for more information. +[/REGION] + +## Lens + +This section includes the ability to apply various Post Processing effects to the viewport. + +![](LensOptions.png) + +[REGION:note] +Please see [](Engine/Rendering/PostProcessEffects) for more information. +[/REGION] + +## Rendering Features + +This section includes the ability to apply various lighting effects to the viewport. + +![](RenderingFeatures.png) + +[REGION:note] +Please see [](Engine/Rendering/LightingAndShadows) for more information. +[/REGION] + +## Tonemapper + +In this section, you can define various **Tone Mapping** functions. + +![](ToneMapper.png) + +[REGION:note] +Please see [Tone Mapping](Engine/Rendering/PostProcessEffects/ColorGrading) for more information. +[/REGION] + +## Mobile Tonemapper + +This section includes the ability to define **Tone Mapping** functions for mobile platforms. + +![](MobileToneMapper.png) + +[REGION:note] +Please see [](Platforms/Mobile/PostProcessEffects) for more information. +[/REGION] + + diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/Toolbar/PersonaToolbar.INT.udn b/Engine/Documentation/Source/Engine/Animation/Persona/Toolbar/PersonaToolbar.INT.udn index 0d1082c9a6d8..364e18dcdaf8 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/Toolbar/PersonaToolbar.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/Toolbar/PersonaToolbar.INT.udn @@ -6,15 +6,15 @@ Related: Engine/Animation/Persona/Modes/Skeleton Related: Engine/Animation/Persona/Modes/Mesh Related: Engine/Animation/Persona/Modes/Animation Related: Engine/Animation/Persona/Modes/Graph -version: 4.14 +version: 4.16 type:reference topic-image:Engine/Animation/animation_topic.png tags:animation [EXCERPT:Overview] -Regardless of what Animation Tool you are working in, each Editor will feature a **Toolbar** which can be located at the top, however, the options on the Toolbar will vary based on the type of Editor you are currently working in. -The Toolbar is comprised of two main areas, the **Asset Toolbar** which contains several options related to the Editor you are working with and the **Editor Toolbar** which allows you to quickly switch between the different Animation Tool Editors. +Regardless of what Animation Tool you are working in, each Editor will feature a **Toolbar** which can be located at the top. However, the options on the Toolbar will vary based on the type of Editor you are currently working in. +The Toolbar is comprised of two main areas, the **Asset Toolbar** which contains several options related to the Editor you are working with and the **Editor Toolbar** which enables you to quickly switch between the different Animation Tool Editors. [/EXCERPT:Overview] @@ -36,9 +36,10 @@ The Skeleton Editor Toolbar is shown whenever you open [](Engine/Animation/Skele | ![](saveIcon.png) | Saves any changes made to the current Skeleton asset. | | ![](findincbIcon.png) | Opens the **Content Browser** and automatically navigates to the current Skeleton asset. | | ![](animnotifiesIcon.png) | Opens the [Anim Notifies](Engine/Animation/Persona/AnimationNotifies) window that displays all the custom Animation Notifies for the current Skeleton. | -| ![](retargetmanagerIcon.png) | Opens the [](Engine/Animation/Persona/BasePoseManager) which allows you to manage your retarget sources, set up rigs and define retarged base poses for use with Animation Retargeting. | -| ![](importmeshIcon.png) | Begins the [](Engine/Content/FBX/SkeletalMeshes) and allows you to import a new Skeletal Mesh for the current Skeleton. | -| ![](makestaticmeshIcon.png) | Allows you to create a **Static Mesh** out of the current preview pose. | +| ![](retargetmanagerIcon.png) | Opens the [](Engine/Animation/Persona/BasePoseManager) which enables you to manage your retarget sources, set up rigs and define retarged base poses for use with Animation Retargeting. | +| ![](importmeshIcon.png) | Begins the [](Engine/Content/FBX/SkeletalMeshes) and enables you to import a new Skeletal Mesh for the current Skeleton. | +| ![](PreviewMesh.png) | Set a new preview Skeletal Mesh for the current asset (stored per-animation or per-skeleton). | +| ![](makestaticmeshIcon.png) | Enables you to create a **Static Mesh** out of the current preview pose. | ### Skeletal Mesh Editor Toolbar @@ -50,8 +51,9 @@ The Skeletal Mesh Editor Toolbar is shown whenever you open a [Skeletal Mesh](En | ------- | ------------ | | ![](saveIcon.png) | Saves any changes made to the current Skeletal Mesh asset. | | ![](findincbIcon.png) | Opens the **Content Browser** and automatically navigates to the current Skeletal Mesh asset. | -| ![](reimportmeshIcon.png) | Allows you to reimport the current Skeletal Mesh and starts the FBX Import Process. | -| ![](makestaticmeshIcon.png) | Allows you to create a **Static Mesh** out of the current preview pose. | +| ![](reimportmeshIcon.png) | Enables you to reimport the current Skeletal Mesh and starts the FBX Import Process. | +| ![](SectionSelection.png) | Enables selecting Mesh Sections in the viewport (disables selecting bones using their physics shape). | +| ![](makestaticmeshIcon.png) | Enables you to create a **Static Mesh** out of the current preview pose. | ### Animation Editor Toolbar @@ -63,17 +65,20 @@ The Animation Editor Toolbar is shown whenever you open any animation assets (An | ------- | ------------ | | ![](saveIcon.png) | Saves any changes made to the current animation asset. | | ![](findincbIcon.png) | Opens the **Content Browser** and automatically navigates to the current animation asset. | -| ![](createassetIcon.png) | Allows you to create new animation assets based on the current Skeleton asset. | -| ![](compressionIcon.png) | Allows you to apply different [Compression](Engine/Animation/Sequences) settings to the animation (available for Animation Sequences). | -| ![](keyIcon.png) | Allows you to add the current Bone Transform of a selected Bone to an [Additive Layer Track.](Engine/Animation/AnimHowTo/LayerEditing) | +| ![](createassetIcon.png) | Create new animation assets (animations, anim assets, Blend Spaces or Aim Offsets). When creating animation, this can be based on the **Reference Pose**, **Current Pose** or Current Animation's **Animation Data** or **Preview Mesh**. When using the Preview Mesh, the created animation will include any additional animation data generated from a post-process graph assigned tot he Skeletal Mesh, such as Anim Dynamics for Physics Simulation. | +| ![](ReimportAnimation.png) | Reimport the current animation. | +| ![](compressionIcon.png) | Enables you to apply different [Compression](Engine/Animation/Sequences) settings to the animation (available for Animation Sequences). | +| ![](ExportAsset.png) | Export current animation source data or current animation playing on the current preview mesh (includes retargeting, post process graph or other settings applied to the preview mesh). | +| ![](keyIcon.png) | Enables you to add the current Bone Transform of a selected Bone to an [Additive Layer Track.](Engine/Animation/AnimHowTo/LayerEditing) | | ![](applyIcon.png) | Applies [Additive Layer Tracks](Engine/Animation/AnimHowTo/LayerEditing) to Runtime Animation Data. | -| ![](makestaticmeshIcon.png) | Allows you to create a **Static Mesh** out of the current preview pose. | +| ![](PreviewMesh.png) | Set a new preview Skeletal Mesh for the current asset (stored per-animation or per-skeleton). | +| ![](makestaticmeshIcon.png) | Enables you to create a **Static Mesh** out of the current preview pose. | ### Animation Blueprint Editor Toolbar ![](AnimBPToolbar.png) -The Animation Blueprint Editor Toolbar is shown whenever you open any [](Engine/Animation/AnimBlueprints) and allows you to Save, Find the Animation Blueprint in the Content Browser or create a Static Mesh from the current preview pose. +The Animation Blueprint Editor Toolbar is shown whenever you open any [](Engine/Animation/AnimBlueprints) and enables you to Save, Find the Animation Blueprint in the Content Browser or create a Static Mesh from the current preview pose. The rest of the options utilize the same functionality found in the normal **Blueprint Editor Toolbar**. [REGION:note] @@ -83,21 +88,21 @@ Please see the [Blueprint Editor Toolbar](Engine/Blueprints/Editor/UIComponents/ ## Editor Toolbar -Located along the right side of each editor toolbar is the **Editor Toolbar** which allows you to switch between each of the Animation Tool Editors. +Located along the right side of each editor toolbar is the **Editor Toolbar** which enables you to switch between each of the Animation Tool Editors. The currently open editor will be highlighted: - ![](skeletoneditoropen.png) + ![](SkeletonToolbar.png) - When clicking one of the other Editors, the new tab will open and the new editor will be highlighted: + When clicking one of the other Editors, the new tab will open, and the new editor will be highlighted: - ![](mesheditoropen.png) + ![](MeshToolbar.png) The **Animation Editor** includes an animation selection drop-down button next to the icon to quickly change the preview animation: ![](animationdropdownmenu.png) -An ** * ** symbol in the lower left corner of the icon indicates that the asset has changes that have not been saved. +A ** * (Asterisk) ** symbol in the lower left corner of the icon indicates that the asset has changes that have not been saved. ![](unsavedasset.png) @@ -108,3 +113,4 @@ For example, if you have imported a Skeletal Mesh and created a Skeleton, but ha ![](limitedtoolbar.png) Creating an Animation Blueprint with the associated Skeleton and importing animations linked to the Skeleton will allow you to access the other editors for that asset. + diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/Toolbar/PersonaToolbar.JPN.udn b/Engine/Documentation/Source/Engine/Animation/Persona/Toolbar/PersonaToolbar.JPN.udn index 3749479d7a8e..e2b92e04024a 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/Toolbar/PersonaToolbar.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/Toolbar/PersonaToolbar.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3227381 +INTSourceChangelist:3484556 Availability:Public Title:アニメーション ツールバー Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Persona @@ -7,7 +7,7 @@ Related:Engine/Animation/Persona/Modes/Skeleton Related:Engine/Animation/Persona/Modes/Mesh Related:Engine/Animation/Persona/Modes/Animation Related:Engine/Animation/Persona/Modes/Graph -version:4.14 +version:4.16 type:reference topic-image:Engine/Animation/animation_topic.png tags:animation @@ -39,6 +39,7 @@ tags:animation | ![](animnotifiesIcon.png) | 現在のスケルトンのすべてのカスタム アニメーション通知を表示する [Anim Notifies](Engine/Animation/Persona/AnimationNotifies) ウィンドウを開きます。 | | ![](retargetmanagerIcon.png) | [](Engine/Animation/Persona/BasePoseManager) を開きます。リターゲット ソースの管理、リグの設定、アニメーションのリターゲットで使用するためのリターゲットしたベース ポーズを定義することができます。 | | ![](importmeshIcon.png) | [](Engine/Content/FBX/SkeletalMeshes) を開始し、現在のスケルトンに対して新しいスケルタルメッシュをインポートすることができます。 | +| ![](PreviewMesh.png) | 現在のアセットに対して新しいプレビュー スケルタルメッシュを設定します (アニメーション毎またはスケルトン毎に保存)。 | | ![](makestaticmeshIcon.png) | 現在のプレビュー ポーズから **スタティックメッシュ** を作成することができます。 | ### スケルタルメッシュ エディタのツールバー @@ -52,6 +53,7 @@ tags:animation | ![](saveIcon.png) | 現在の Skeletal Mesh アセットに加えた変更を保存します。 | | ![](findincbIcon.png) | **コンテンツ ブラウザ** を開き、現在のSkeletal Mesh アセットに自動的に移動します。 | | ![](reimportmeshIcon.png) | 現在のスケルタルメッシュを再インポートし、FBX インポート プロセスを開始することができます。 | +| ![](SectionSelection.png) | ビューポートでメッシュ セクションを選択できるようにします (物理形状を使ってボーンの選択を無効にします)。 | | ![](makestaticmeshIcon.png) | 現在のプレビュー ポーズから **スタティックメッシュ** を作成することができます。 | ### アニメーション エディタのツールバー @@ -64,10 +66,13 @@ tags:animation | ------- | ------------ | | ![](saveIcon.png) | 現在の Animation アセットに加えた変更を保存します。 | | ![](findincbIcon.png) | **コンテンツ ブラウザ** を開き、現在の Animation アセットに自動的に移動します。 | -| ![](createassetIcon.png) | 現在の Skeleton アセットに基づき新規 Animation アセットを作成することができます。 | +| ![](createassetIcon.png) | 新規 Animation アセットを作成します (アニメーション、アニメーション アセット、ブレンドスペース、Aim Offset)。アニメーション作成時に **Reference Pose**、 **Current Pose**、または現在のアニメーションの **Animation Data** または **Preview Mesh** に基づきます。プレビュー メッシュを使用する場合、作成したアニメーションには、物理シミュレーションの Anim Dynamics など、スケルタルメッシュに割り当てられたポストプロセスのグラフから生成された追加のアニメーション データが含まれます。 | +| ![](ReimportAnimation.png) | 現在のアニメーションを再インポートします。 | | ![](compressionIcon.png) | 様々な [圧縮](Engine/Animation/Sequences) 設定をアニメーション (アニメーション シーケンスに対して利用可能) に適用することができます。 | +| ![](ExportAsset.png) | 現在のアニメーション ソース データまたは現在のプレビュー メッシュで再生している現在のアニメーションをエクスポートします (リターゲット、ポストプロセス グラフ、プレビュー メッシュに適用されるその他の設定を含む)。 | | ![](keyIcon.png) | 選択したボーンの現在のボーン トランスフォームを [加算レイヤー トラック](Engine/Animation/AnimHowTo/LayerEditing) に追加することができます。 | | ![](applyIcon.png) | [加算レイヤー トラック](Engine/Animation/AnimHowTo/LayerEditing) を Runtime Animation Data に適用します。 | +| ![](PreviewMesh.png) | 現在のアセットに対して新しいプレビュー スケルタルメッシュを設定します (アニメーション毎またはスケルトン毎に保存)。 | | ![](makestaticmeshIcon.png) | 現在のプレビュー ポーズから **スタティックメッシュ** を作成することができます。 | ### Animation ブループリント エディタのツールバー @@ -88,17 +93,17 @@ Animation ブループリント エディタのツールバーは [](Engine/Anim 現在開いているエディタがハイライトされます。 - ![](skeletoneditoropen.png) + ![](SkeletonToolbar.png) 他のエディタのひとつをクリックすると新しいタブが開き、新しいエディタがハイライトされます。 - ![](mesheditoropen.png) + ![](MeshToolbar.png) **アニメーション エディタ** には、アイコンの隣にアニメーション選択のドロップダウン ボタンがあります。これは、プレビュー アニメーションを迅速に変更するためのものです。 ![](animationdropdownmenu.png) -アイコンの左下隅にある ** * ** 記号は、そのアセットに保存されていない変更があることを表しています。 +アイコンの左下隅にある ** * (アスタリスク)** 記号は、そのアセットに保存されていない変更があることを表しています。 ![](unsavedasset.png) @@ -108,4 +113,5 @@ Animation ブループリント エディタのツールバーは [](Engine/Anim ![](limitedtoolbar.png) -関連スケルトンと共に Animation ブループリントを作成し、スケルトンにリンクされているアニメーションをインポートすると、そのアセットのために他のエディタにアクセスすることができます。 +関連スケルトンと共に Animation ブループリントを作成し、スケルトンにリンクされているアニメーションをインポートすると、そのアセットを他のエディタで利用することができます。 + diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/Toolbar/PersonaToolbar.KOR.udn b/Engine/Documentation/Source/Engine/Animation/Persona/Toolbar/PersonaToolbar.KOR.udn index 7c80fc8b1c7d..fe7e54319558 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/Toolbar/PersonaToolbar.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/Toolbar/PersonaToolbar.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3227381 +INTSourceChangelist:3462657 Availability:Public Title:애니메이션 툴바 Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Persona @@ -7,7 +7,7 @@ Related: Engine/Animation/Persona/Modes/Skeleton Related: Engine/Animation/Persona/Modes/Mesh Related: Engine/Animation/Persona/Modes/Animation Related: Engine/Animation/Persona/Modes/Graph -version: 4.14 +version: 4.16 type:reference topic-image:Engine/Animation/animation_topic.png tags:animation @@ -39,6 +39,7 @@ tags:animation | ![](animnotifiesIcon.png) | [애님 노티파이](Engine/Animation/Persona/AnimationNotifies) 창을 엽니다. 현재 스켈레톤에 대한 모든 커스텀 애니메이션 노티파이가 표시됩니다. | | ![](retargetmanagerIcon.png) | [](Engine/Animation/Persona/BasePoseManager) 창을 엽니다. 리타겟 소스 관리, 릭 구성, 애니메이션 리타게팅에 사용할 수 있는 리타겟 베이스 포즈 정의가 가능합니다. | | ![](importmeshIcon.png) | [](Engine/Content/FBX/SkeletalMeshes) 시작 및 현재 스켈레톤에 대한 스켈레탈 메시를 새로 임포트할 수 있습니다. | +| ![](PreviewMesh.png) | 현재 에셋에 사용할 (애니메이션마다 또는 스켈레톤마다 저장된) 프리뷰 스켈레탈 메시를 새로 설정합니다. | | ![](makestaticmeshIcon.png) | 현재 프리뷰 포즈에서 **스태틱 메시** 를 만들 수 있습니다. | ### 스켈레탈 메시 에디터 툴바 @@ -52,6 +53,7 @@ tags:animation | ![](saveIcon.png) | 현재 스켈레탈 메시 애셋에 가해진 변경사항을 저장합니다. | | ![](findincbIcon.png) | **콘텐츠 브라우저** 를 열고 현재 스켈레탈 메시 애셋 위치로 자동 이동합니다. | | ![](reimportmeshIcon.png) | 현재 스켈레탈 메시를 리임포트하고 FBX 임포트 프로세스 시작이 가능합니다. | +| ![](SectionSelection.png) | 뷰포트에서 메시 섹션 선택이 가능합니다 (피직스 모양으로 본을 선택하는 기능이 꺼집니다). | | ![](makestaticmeshIcon.png) | 현재 프리뷰 포즈에서 **스태틱 메시** 생성이 가능합니다. | ### 애니메이션 에디터 툴바 @@ -64,11 +66,14 @@ tags:animation | ------- | ------------ | | ![](saveIcon.png) | 현재 애니메이션 애셋에 가해진 변경사항을 저장합니다. | | ![](findincbIcon.png) | **콘텐츠 브라우저** 를 열어 현재 스켈레톤 애셋 위치로 자동 이동합니다. | -| ![](createassetIcon.png) | 현재 스켈레톤 애셋을 기반으로 애니메이션 애셋을 새로 만들 수 있습니다. | +| ![](createassetIcon.png) | 새 애니메이션 애셋(애니메이션, 애님 애셋, 블렌드 스페이스, 에임 오프셋 등)을 생성합니다. 애니메이션을 생성할 때, 이는 **레퍼런스 포즈**, **현재 포즈**, 또는 현재 애니메이션의 **애니메이션 데이터** 또는 **프리뷰 메시** 를 기준으로 생성할 수 있습니다. 프리뷰 메시를 사용할 때, 생성되는 애니메이션에는 애님 다이내믹스나 피직스 시뮬레이션처럼 그 스켈레탈 메시에 적용된 포스트 프로세스 그래프에서 생성된 부가 애니메이션 데이터도 포함됩니다. | +| ![](ReimportAnimation.png) | 현재 애니메이션을 리임포트합니다. | | ![](compressionIcon.png) | 애니메이션에 다양한 [압축](Engine/Animation/Sequences) 세팅을 적용할 수 있습니다 (애니메이션 시퀀스에 사용 가능). | +| ![](ExportAsset.png) | 현재 애니메이션 소스 데이터 또는 현재 프리뷰 메시에 재생되고 있는 애니메이션을 (리타게팅, 포스트 프로세스 그래프, 또는 프리뷰 메시에 적용된 기타 세팅을 포함해서) 익스포트합니다. | | ![](keyIcon.png) | 선택된 본의 현재 본 트랜스폼을 [애디티브 레이어 트랙](Engine/Animation/AnimHowTo/LayerEditing) 에 추가합니다. | | ![](applyIcon.png) | 런타임 애니메이션 데이터에 [애디티브 레이어 트랙](Engine/Animation/AnimHowTo/LayerEditing) 을 적용합니다. | -| ![](makestaticmeshIcon.png) | 현재 프리뷰 포즈에서 **스태틱 메시** 를 생성할 수 있습니다. | +| ![](PreviewMesh.png) | 현재 에셋에 사용할 (애니메이션마다 또는 스켈레톤마다 저장된) 프리뷰 스켈레탈 메시를 새로 설정합니다. | +| ![](makestaticmeshIcon.png) | 현재 프리뷰 포즈에서 **스태틱 메시** 를 만들 수 있습니다. | ### 애니메이션 블루프린트 에디터 툴바 @@ -88,11 +93,11 @@ tags:animation 현재 열린 에디터가 강조됩니다: - ![](skeletoneditoropen.png) + ![](SkeletonToolbar.png) 다른 에디터 중 하나를 클릭하면, 새로운 탭이 열리며 새로운 에디터가 강조됩니다: - ![](mesheditoropen.png) + ![](MeshToolbar.png) **애니메이션 에디터** 에는 아이콘 옆에 애니메이션 선택 드롭다운 버튼이 포함되어 있어, 프리뷰 애니메이션을 빠르게 변경할 수 있습니다: diff --git a/Engine/Documentation/Source/Engine/Animation/Persona/VirtualBones/VirtualBones.JPN.udn b/Engine/Documentation/Source/Engine/Animation/Persona/VirtualBones/VirtualBones.JPN.udn index 654c612ccc2b..ab9fd51ca79b 100644 --- a/Engine/Documentation/Source/Engine/Animation/Persona/VirtualBones/VirtualBones.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/Persona/VirtualBones/VirtualBones.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3323857 +INTSourceChangelist:3344913 Availability:Docs Title:仮想ボーン Crumbs: @@ -15,52 +15,62 @@ tags:Animations, Skeletal Mesh, Skeleton, Bones order: -
-![Virtual Bones](VirtualBones.png)(w:500) -
- -[アニメーション ツールのエディタ](Engine/Animation/Persona/Modes) すなわちスケルトン エディタやアニメーション エディタでは、メッシュのスケルトンに **Virtual Bone (仮想ボーン)** を追加することができます。 -これらは、IK や照準のターゲット ジョイントの階層の変更を可能にすることで、イタレーション時間の改善に役立ちます。この機能が追加される前は、 -エンジン外部のモデリング アプリケーションでアセットに仮想ボーンを追加してから、その後、すべてのアニメーションを再インポートし、 -含めた新規ジョイントでアニメーション データを修正しなければなりませんでした。 - -仮想ボーンはその性質上、スキンできませんが、スケルトン上の 2 つの既存ボーン間で拘束され、 -スケルトン上にある各アニメーションに対してデータを自動生成します。例えば、手の子となるジョイントを追加することはできますが、手の平ジョイントに拘束されます。このジョイントはその後、Animation ブループリントで - IK ターゲットや look at ターゲットなどのターゲットとして使用することができます。または、後で使用するために Anim ブループリントで修正することができます。この点がソケットと異なります。 - -[REGION:note] -仮想ボーンの詳細や実務上の使用については、 [Paragon で使われているアニメーション テクニック](https://youtu.be/1UOY-FMm-xo?list=PL-j8pRjjCYWENU4on8on7b0pEbrmwlzlM) -をご覧ください。Paragon では、仮想ボーンはコントローラーの参照フレームの再ターゲットまたは変更を簡単に行うために使用されています。また方向指定およびスロープワープにも -使用されています。 +[REGION:fullwidth raw] +![Virtual Bones](VirtualBones.png) [/REGION] +[アニメーション ツール](Engine/Animation/Persona/Modes)、すなわちスケルトン エディタ、アニメーション エディタでは、メッシュのスケルトンに **Virtual Bone (仮想ボーン)** を追加することができます。 +これらは、IK や照準のターゲット ジョイントの階層の変更を可能にすることで、イタレーション時間の改善に役立ちます。この機能が追加される前は、 +エンジン外部のモデリング アプリケーションでアセットに仮想ボーンを追加してから、その後、すべてのアニメーションを再インポートし、 +含まれる新規ジョイントでアニメーション データを修正しなければなりませんでした。 + +仮想ボーンはその性質上、スキンできませんが、スケルトン上の 2 つの既存ボーン間で拘束され、 +スケルトン上にある各アニメーションに対してデータを自動生成します。例えば、手の子となるジョイントを追加することはできますが、手の平ジョイントに拘束されます。ソケットとは異なり、このジョイントはその後、Animation ブループリントで +IK ターゲットや look at ターゲットなどのターゲットとして使用することができます。または、後で使用するために Anim ブループリントで修正することができます。 + +仮想ボーンの実際の使用に関する追加情報や提案、例えばリターゲットを簡単にする、コントローラーの参照フレームを変更するためにどのように使用するか、 +およびオリエンテーションやスロープのワープなどについても、詳細については Paragon トレーニング ストリームをご覧ください! + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 640 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 360 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + 1UOY-FMm-xo + [/PARAMLITERAL] +[/OBJECT] ## 仮想ボーンをスケルトンに追加する 仮想ボーンをスケルタルメッシュに追加するには、以下の手順に従います。 -1. **コンテンツ ブラウザ** で、スケルタルメッシュまたは Animation アセットを開きます。この例では、Third Person Template のキャラクターを使用しています。 +1. **コンテンツ ブラウザ** で、スケルタルメッシュまたは Animation アセットを開きます。 ![](CB_Skeleton.png)(w:350) -1. **アニメーション ツールのエディタ** (スケルタルまたはアニメーション) では、**Skeleton Tree** ウィンドウでジョイント階層から任意のボーンを選択します。右クリックして、コンテキスト メニューで **Add Virtual Bone** にマウスをかざします。 +1. **スケルタル エディタ** または **アニメーション エディタ** の **スケルトン ツリー** ウィンドウでジョイント階層から任意のボーンを選択します。右クリックして、コンテキスト メニューで **Add Virtual Bone** にマウスをかざします。 開いた **Pick Target Bone** ウィンドウでボーンを選択します。 [REGION:raw] ![](SelectVirtualBone.png)(w:850) [/REGION] -1. 仮想ボーンを追加したので、スケルトンの階層にリストされます。スケルトン ツリー ウィンドウでこれらの名前にはプレフィックス "VB" が付き、薄紫色で表示されます。 - [REGION:lightbox] - [![](VirtualBoneView.png)(w:550)](VirtualBoneView.png) - [/REGION] - [REGION:tip] - スケルトン エディタまたはアニメーション エディタのビューポートでボーンが見えない場合は、**Show** > **Bones** > **All Hierarchy** の順序で進み、スケルトンが常に表示されるようにします。ビューポートに常にすべてのボーンを表示したくない場合は、 - 必要に応じて他のオプションもあります。 - [/REGION] +仮想ボーンを追加したので、スケルトンの階層にリストされます。スケルトン ツリー ウィンドウでこれらの名前にはプレフィックス "VB" が付き、薄紫色で表示されます。 - アニメーション エディタで選択したジョイント間で仮想ボーンが拘束されて、アニメーションに合わせて更新されます。 +[REGION:lightbox] +[![](VirtualBoneView.png)(w:550)](VirtualBoneView.png) +[/REGION] - [REGION:asyncgif] - ![Virtual Bone](WalkAnim.gif)(w:350) - [/REGION] +[REGION:tip] +スケルトン エディタまたはアニメーション エディタのビューポートでボーンが見えない場合は、**Show** > **Bones** > **All Hierarchy** の順序で進み、スケルトンが常に表示されるようにします。ビューポートに常にすべてのボーンを表示したくない場合は、 +必要に応じて他のオプションもあります。 +[/REGION] + +アニメーション エディタで選択したジョイント間で仮想ボーンが拘束されて、アニメーションに合わせて更新されます。 + +[REGION:asyncgif] +![Virtual Bone](WalkAnim.gif)(w:350) +[/REGION] diff --git a/Engine/Documentation/Source/Engine/Animation/PhysicallyDrivenAnimation/PhysicallyBasedAnimation.INT.udn b/Engine/Documentation/Source/Engine/Animation/PhysicallyDrivenAnimation/PhysicallyBasedAnimation.INT.udn index 0ba206a3e0ac..d0910b4b31c5 100644 --- a/Engine/Documentation/Source/Engine/Animation/PhysicallyDrivenAnimation/PhysicallyBasedAnimation.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/PhysicallyDrivenAnimation/PhysicallyBasedAnimation.INT.udn @@ -8,6 +8,7 @@ Related: Engine/Animation/StateMachines Related: Gameplay/AI Related: Engine/Content/Tools/MayaRiggingTool version: 4.9 +topic-image:PhysicsBasedAnimation_topic.png [REGION:fullwidth] ![](PhysicsBlend.png) diff --git a/Engine/Documentation/Source/Engine/Animation/PhysicallyDrivenAnimation/PhysicallyBasedAnimation.JPN.udn b/Engine/Documentation/Source/Engine/Animation/PhysicallyDrivenAnimation/PhysicallyBasedAnimation.JPN.udn index a9bcb8e3d615..9e7fc3a3d3ba 100644 --- a/Engine/Documentation/Source/Engine/Animation/PhysicallyDrivenAnimation/PhysicallyBasedAnimation.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/PhysicallyDrivenAnimation/PhysicallyBasedAnimation.JPN.udn @@ -1,32 +1,33 @@ -INTSourceChangelist:2667891 +INTSourceChangelist:3467293 Availability:Public Title:物理ベースのアニメーション Crumbs: %ROOT%, Engine, Engine/Animation Description:物理ベースのアニメーションの結果をブレンドしてキャラクターを「ラグドール化」することができます。 -Related: Engine/Content/FBX/Animations -Related: Engine/Content/Types/SkeletalMeshes -Related: Engine/Animation/StateMachines -Related: Gameplay/AI -Related: Engine/Content/Tools/MayaRiggingTool +Related:Engine/Content/FBX/Animations +Related:Engine/Content/Types/SkeletalMeshes +Related:Engine/Animation/StateMachines +Related:Gameplay/AI +Related:Engine/Content/Tools/MayaRiggingTool version:4.9 +topic-image:PhysicsBasedAnimation_topic.png [REGION:fullwidth] ![](PhysicsBlend.png) -このドキュメントでは、物理駆動型のアニメーションをキャラクターとスケルタルメッシュに適用する方法について説明します。コンセプトは、シミュレーション結果を、キーフレーム アニメーションとブレンドし、「ラグドール」エフェクトを示す必要があるキャラクターが自然にシミュレーションされる感覚が得られるというものです。 +このドキュメントでは、物理駆動のアニメーションをキャラクターとスケルタルメッシュに適用する方法を説明します。コンセプトは、シミュレーション結果を、キーフレーム アニメーションとブレンドし、「ラグドール」エフェクトを示す必要があるキャラクターが自然にシミュレーションされる感覚が得られるというものです。 このコンセプトの実例は、[Content Examples](Resources\ContentExamples\Animation) プロジェクトにある PhysicalAnimation.umap という名前のマップ内にあります。このマップには、アニメーションが適用された一連のスケルタルメッシュがあります。各スケルタルメッシュで、何らかの方法でインタラクションすることも可能で、物理アニメーションが既存のモーションを引き継いでいることがわかります。 -いかなる形態であれスケルタルメッシュで物理を使用するには、そのメッシュで物理アセットをセットアップし、適用する必要があることにご注意ください。関連ドキュメント、[物理アセットツール(PhAT)](Engine/Physics\PhAT) を参照してください。 +いかなる形態であれスケルタルメッシュで物理を使用するには、そのメッシュで物理アセットをセットアップし、適用する必要があることにご注意ください。関連ドキュメント、[物理アセットツール (PhAT)](Engine/Physics\PhAT) を参照してください。 [REGION:note] この例では全体的に単純化するためにスケルタルメッシュを使用しています。キャラクターやポーンに同様の技術を適用できます。これは、この例で行うようなシンプルなブループリント アクタの Event Graph ではなく、Animation ブループリントの Event Graph 内で **Set All Bodies Simulate Physics** ノードと **Set All Bodies Below Physics Blend Weight** ノードを使用すれば可能です。 [/REGION] -## 設定 +## セットアップ 物理をキャラクターに適用するには多くの方法がありますが、ここの例では、いくつかの可能性だけを示します。この方法では、以下の 2 つの主要ツールが必要です。Set All Bodies Simulate Physics ノードと Set All Bodies Below Physics Blend Weight ノードの 2 つです。通常はキャラクターの Animation ブループリントの Event Graph 内に配置されます。 @@ -34,11 +35,11 @@ version:4.9 ### Set All Bodies Below Simulate Physics -Set All Bodies Below Simulate Physics ノードは、物理アセット ボディをスケルタルメッシュ上で再帰的にアクティベートし、任意のボーンで物理のシミュレーションを開始し、ボーン チェーンを再帰的に下方に移動します。たとえば、左鎖骨にシミュレーションを開始するように指示すると、スケルタル階層でそこから下方のすべてのボーンもシミュレーションし、足を引きずって歩いたり、ラグドールのアームになります。簡単に言うと、このノードは任意のボーンから物理シミュレーションを開始または停止するためのオン / オフのスイッチであると考えることができます。 +Set All Bodies Below Simulate Physics ノードは、物理アセット ボディをスケルタルメッシュ上で再帰的にアクティベートし、任意のボーンで物理のシミュレーションを開始し、ボーン チェーンを再帰的に下方に移動します。たとえば、左鎖骨にシミュレーションを開始するように指示すると、スケルタル階層でそこから下方のすべてのボーンもシミュレーションし、足を引きずって歩いたり、ラグドール化した腕になります。簡単に言うと、このノードは任意のボーンからの物理シミュレーションを開始または停止するオン / オフのスイッチと考えることができます。 ### Set All Bodies Below Physics Blend Weight -このノードは、アニメートされたスケルタルメッシュに対して物理アセットがどの程度影響を及ぼすかを制御します。値 1.0 で任意のボーンとその配下にあるすべてのボーンが完全に物理によって動作します。値 0.0 でスケルタルメッシュはオリジナルのキーフレーム アニメーションに戻ります。多くの場合、Physics Blend Weight 値をスムーズにアニメートできるように、このノードを各ティックで動作させます。 +このノードは、アニメートされたスケルタルメッシュに対して物理アセットがどの程度影響を及ぼすかを制御します。値 1.0 で、任意のボーンとそれより下のボーンは完全に物理駆動になります。値 0.0 で、スケルタルメッシュがオリジナルのキーフレーム アニメーションに戻ります。多くの場合、Physics Blend Weight 値をスムーズにアニメートできるように、このノードを各ティックで動作させます。 ## ヒットベースの作用の概要 @@ -51,7 +52,7 @@ Set All Bodies Below Simulate Physics ノードは、物理アセット ボデ * 作用が完了し、Physics Blend Weight が 0 に戻ったら、Set All Bodies Below Simulate Physics ノードを再度使用して、シミュレーションを停止します。 [REGION:note] -この技術の例は、Content Examples プロジェクト内の PhysicalAnimation.umap level の Example 1.2 にあります。 +Content Examples プロジェクト内にある PhysicalAnimation.umap level の Example 1.2 でこの技術の例をご覧いただくことができます。 [/REGION] diff --git a/Engine/Documentation/Source/Engine/Animation/PhysicallyDrivenAnimation/PhysicallyBasedAnimation.KOR.udn b/Engine/Documentation/Source/Engine/Animation/PhysicallyDrivenAnimation/PhysicallyBasedAnimation.KOR.udn index 09d45a12867e..ff405edf31f1 100644 --- a/Engine/Documentation/Source/Engine/Animation/PhysicallyDrivenAnimation/PhysicallyBasedAnimation.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/PhysicallyDrivenAnimation/PhysicallyBasedAnimation.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3467293 Availability:Public Title: 물리 기반 애니메이션 Crumbs: %ROOT%, Engine, Engine/Animation @@ -9,6 +9,7 @@ Related: Engine/Animation/StateMachines Related: Gameplay/AI Related: Engine/Content/Tools/MayaRiggingTool version: 4.9 +topic-image:PhysicsBasedAnimation_topic.png [REGION:fullwidth] ![](PhysicsBlend.png) diff --git a/Engine/Documentation/Source/Engine/Animation/PoseSnapshot/PoseSnapshot.CHN.udn b/Engine/Documentation/Source/Engine/Animation/PoseSnapshot/PoseSnapshot.CHN.udn new file mode 100644 index 000000000000..a7e24c317501 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Animation/PoseSnapshot/PoseSnapshot.CHN.udn @@ -0,0 +1,79 @@ +INTSourceChangelist:0 +Availability:Public +Title: Animation Pose Snapshot +Crumbs: %ROOT%, Engine, Engine/Animation +Description:Animation Pose Snapshots can capture a runtime Skeletal Mesh Pose inside a Blueprint and can be used for blending in or out of additional poses within an Animation Blueprint. +Related: Engine\Animation\AnimBlueprints +Related: Engine\Blueprints +Related: Engine/Animation/Persona/Modes/Graph +Related: Engine/Animation/AnimMontage +Related: Engine/Physics/PhAT +version: 4.15 +type:reference +SkillLevel: Intermediate +topic-image:posesnapshottopic.png +tags:Animation +tags:Animation Blueprint +tags:Blueprints +tags:Animation Blending + +When animating Skeletal Meshes, there may be instances when you want to apply and let physics take control of the mesh (such as a character entering a "rag-doll" state). +After physics has been applied, using the **Animation Pose Snapshot** feature, you can capture a Skeletal Mesh pose (storing all the Bone Transform data) within a [Blueprint](Engine\Blueprints) and retrieve it inside [](Engine\Animation\AnimBlueprints) enabling you to use the saved pose as a source to blend from (as seen in the example video below). + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 1BMOXpdfDjk + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +Above, our character enters a rag-doll state when we press a key and we use the **Pose Snapshot** node in our [Character Blueprint](Engine/Blueprints/UserGuide/Types/ClassBlueprint) to save off the pose of our Skeletal Mesh. +When we press another key, our character blends from that snapshot into and plays a "get up" [](Engine/Animation/AnimMontage) before resuming the normal locomotion state. +This grants us the ability to take whatever pose the character ends up in as a result of physics and generate a smooth blend from that pose into an animation of the character getting back to their feet. + +## Save Pose Snapshot + +In order to save your Skeletal Mesh's pose at runtime, inside your **Character Blueprint**, you will need access to the [Skeletal Mesh Component](Engine/Components/SkeletalMesh) and its **AnimInstance**. + +With these in place, you can call the **Save Pose Snapshot** node and enter the desired **Snapshot Name**: + +![](PoseSnapShotBlueprint.png) + +You can manually enter a name into the Snapshot Name field or create a variable to store the name. +The name you provide as the Snapshot Name **MUST** also be used when attempting to retrieve the Pose Snapshot inside your Animation Blueprint. + +[REGION:note] +When calling Save Pose Snapshot, the snapshot is taken at the current LOD. For example, if you took the snapshot at LOD1 and then used it at LOD0, any bones not in LOD1 will use the mesh's reference pose. +[/REGION] + +## Retrieve Pose Snapshot + +To retrieve a Pose Snapshot, inside the **AnimGraph** of your **Animation Blueprint**, **Right-click** and add the **Pose Snapshot** node and enter your **Snapshot Name**. + +![](PoseSnapShotAnimBPNode.png) + +Below is the graph for the sample use case of a character that is getting up from a rag-doll pose. + +![](PoseSnapShotAnimBP.png) + +Above, we have a [State Machine](Engine/Animation/StateMachines) called **Default** that drives our character's locomotion and use an AnimMontage in the **MySlot** node that plays an animation of our character getting up when called to play. +We use the [Blend Poses by bool](https://docs.unrealengine.com/latest/INT/Engine/Animation/NodeReference/Blend/#blendposesbybool) node to determine if our character has stopped moving, where if **True** we switch over to our Pose Snapshot. +If **False**, we blend from the Pose Snapshot into our slotted AnimMontage before continuing on with our normal Default State Machine. + + + + + + + diff --git a/Engine/Documentation/Source/Engine/Animation/PoseSnapshot/PoseSnapshot.INT.udn b/Engine/Documentation/Source/Engine/Animation/PoseSnapshot/PoseSnapshot.INT.udn new file mode 100644 index 000000000000..0af60e36ac62 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Animation/PoseSnapshot/PoseSnapshot.INT.udn @@ -0,0 +1,117 @@ +Availability: Docs +Crumbs: %ROOT%, Engine, Engine/Animation +Title: Animation Pose Snapshot +Description:Animation Pose Snapshots can capture a runtime Skeletal Mesh Pose inside a Blueprint and can be used for blending in or out of additional poses within an Animation Blueprint. +type:reference +version: 4.16 +Parent: Engine/Animation +Order: 1 +tags:Animation +tags:Animation Blueprint +tags:Blueprints +tags:Animation Blending +topic-image:topic-image:posesnapshottopic.png +Related: Engine\Animation\AnimBlueprints +Related: Engine\Blueprints +Related: Engine/Animation/Persona/Modes/Graph +Related: Engine/Animation/AnimMontage +Related: Engine/Physics/PhAT + +[TOC (start:2 end:2)] + +When animating Skeletal Meshes, there may be instances when you want to apply and let physics take control of the mesh (such as a character entering a rag-doll state). +After physics has been applied, using the **Animation Pose Snapshot** feature, you can capture a Skeletal Mesh pose (storing all the Bone Transform data) within a [Blueprint](Engine\Blueprints) and retrieve it inside [](Engine\Animation\AnimBlueprints) enabling you to use the saved pose as a source to blend from (as seen in the example video below). + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 1BMOXpdfDjk + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +Above, our character enters a rag-doll state when we press a key and we use the **Pose Snapshot** node in our [Character Blueprint](Engine/Blueprints/UserGuide/Types/ClassBlueprint) to save off the pose of our Skeletal Mesh. +When we press another key, our character blends from that snapshot into and plays a "get up" [](Engine/Animation/AnimMontage) before resuming the normal locomotion state. +This grants us the ability to take whatever pose the character ends up in as a result of physics and generate a smooth blend from that pose into an animation of the character getting back to their feet. + +## Save Pose Snapshot + +In order to save your Skeletal Mesh's pose at runtime, inside your **Character Blueprint**, you will need access to the [Skeletal Mesh Component](Engine/Components/SkeletalMesh) and its **Anim Instance**. + +![](PoseSnapShotBlueprint.png) + +With these in place, you can call the **Save Pose Snapshot** node and enter the desired **Snapshot Name**. +You can manually enter a name into the Snapshot Name field or create a variable to store the name. +The name you provide as the Snapshot Name **MUST** also be used when attempting to retrieve the Pose Snapshot inside your Animation Blueprint. + +[REGION:note] +When calling Save Pose Snapshot, the snapshot is taken at the current LOD. For example, if you took the snapshot at LOD1 and then used it at LOD0, any bones not in LOD1 will use the mesh's reference pose. +[/REGION] + +## Retrieve Pose Snapshot + +To retrieve a Pose Snapshot, inside the **AnimGraph** of your **Animation Blueprint**, right-click and add the **Pose Snapshot** node and enter your **Snapshot Name**. + +![](PoseSnapShotAnimBPNode.png) + +Below is the graph for the sample use case of a character that is getting up from a rag-doll pose. + +![](PoseSnapShotAnimBP.png) + +Above, we have a [State Machine](Engine/Animation/StateMachines) called **Default** that drives our character's locomotion and use an AnimMontage in the **MySlot** node that plays an animation of our character getting up when called to play. +We use the [Blend Poses by bool](https://docs.unrealengine.com/latest/INT/Engine/Animation/NodeReference/Blend/#blendposesbybool) node to determine if our character has stopped moving, where if **True** we switch over to our Pose Snapshot. +If **False**, we blend from the Pose Snapshot into our slotted AnimMontage before continuing on with our normal Default State Machine. + +## Snapshot Pose Function + +An alternative way of using the Pose Snapshot feature is by calling the **Snapshot Pose** function within Blueprint to save a snapshot to a **Pose Snapshot** variable. + +![](SnapshotPose.png) + +When using Snapshot Pose, you will need to provide a variable in which to save the snapshot to as shown above. + +Inside your AnimGraph once you have added the **Pose Snapshot** node, in the **Details** panel set the **Mode** to **Snapshot Pin** and check the **(As pin) Snapshot** option. + +![](PoseSnapshotDetails.png) + +This will expose a Pose Snapshot input pin on the node that you can pass in your desired snapshot variable. + +![](SnapshotPoseAnimGraph.png) + +## Additional Resources + +This feature can also be seen within the following Live Training Stream: + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + nkj6PAbGYtM + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + + + + + + diff --git a/Engine/Documentation/Source/Engine/Animation/PoseSnapshot/PoseSnapshot.JPN.udn b/Engine/Documentation/Source/Engine/Animation/PoseSnapshot/PoseSnapshot.JPN.udn new file mode 100644 index 000000000000..a2f48e0b96d2 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Animation/PoseSnapshot/PoseSnapshot.JPN.udn @@ -0,0 +1,99 @@ +INTSourceChangelist:3464925 +Availability:Public +Title:アニメーション ポーズのスナップショット +Crumbs: %ROOT%, Engine, Engine/Animation +Description:アニメーションのポーズのスナップショットでは実行時のスケルタルメッシュのポーズをブループリント内でキャプチャーして、Animation ブループリント内で追加ポーズをブレンドイン、ブレンドアウトすることができます。 +Related:Engine\Animation\AnimBlueprints +Related:Engine\Blueprints +Related:Engine/Animation/Persona/Modes/Graph +Related:Engine/Animation/AnimMontage +Related:Engine/Physics/PhAT +version:4.15 +type:reference +SkillLevel:Intermediate +topic-image:posesnapshottopic.png +tags:Animation +tags:Animation Blueprint +tags:Blueprints +tags:Animation Blending + +スケルタルメッシュをアニメートする場合、物理を適用してメッシュを制御することがあります (キャラクターが「ラグドール」状態になるなど)。 +物理を適用後、**[Animation Pose Snapshot (アニメーション ポーズのスナップショット)]** 機能を使って、スケルタルメッシュのポーズ (すべてのボーン トランスフォーム データを保存したもの) を [ブループリント](Engine\Blueprints) 内にキャプチャーして、[](Engine\Animation\AnimBlueprints) 内で取り出して、保存したポーズをブレンド元として使うことができます (以下の動画のように)。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 1BMOXpdfDjk + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +上の例では、キーを押すとキャラクターがラグドール状態になります。[Character ブループリント](Engine/Blueprints/UserGuide/Types/ClassBlueprint) で **Pose Snapshot** ノードを使用し、スケルタルメッシュのポーズを保存します。 +別のキーを押すと、キャラクターがスナップショットからブレンドし、"get up" [](Engine/Animation/AnimMontage) を再生してから通常のロコモーション ステートを再開します。 +これで物理の結果として最終的なキャラクターのポーズが何になっても、そのポーズからキャラクターが立ち上がるアニメーションに滑らかにブレンドできるようになります。 + +## Save Pose Snapshot + +スケルタルメッシュのポーズをランタイムに保存するには、**Character ブループリント** 内で [Skeltal Mesh コンポーネント](Engine/Components/SkeletalMesh) とその **AnimInstance** にアクセスする必要があります。 + +これらを配置した状態で、**Save Pose Snapshot** ノードを呼び出して必要な **Snapshot Name**: を入力します。 + +![](PoseSnapShotBlueprint.png) + +[Snapshot Name] 欄に名前を手動入力するか、名前を保存する変数を作成します。 +Snapshot Name として指定した名前は、Animation ブループリント内でPose Snapshot を取り出す場合にも **使用しなければなりません**。 + +[REGION:note] +Save Pose Snapshot を呼び出す場合、スナップショットは現在の LOD で撮られます。例えば、LOD1 でスナップショットを撮って、LOD0 で使用すると、LOD1 にないボーンはメッシュのリファレンス ポーズを使用します。 +[/REGION] + +## Pose Snapshot を取り出す + +Pose Snapshot を取り出すには、**Animation Blueprint** の **AnimGraph** 内で **右クリック** して、**Pose Snapshot** ノードを追加して **Snapshot Name** を入力します。 + +![](PoseSnapShotAnimBPNode.png) + +以下はラグドール ポーズから立ち上がるキャラクターのサンプル使用例のグラフです。 + +![](PoseSnapShotAnimBP.png) + +上の図では、キャラクターのロコモーションを操作する **Default** という [ステートマシン](Engine/Animation/StateMachines) で、 **MySlot** ノードで呼び出されるとキャラクターが立ち上がるアニメーションを再生する AnimMontage を使用します。 +[Blend Poses by bool](https://docs.unrealengine.com/latest/INT/Engine/Animation/NodeReference/Blend/#blendposesbybool) ノードを使って、キャラクターが移動を停止したかを判断し、**True** の場合は、Pose Snapshot に切り替えます。 +**False** の場合、Pose Snapshot からスロットに入れた AnimMontage にブレンドしてから、通常の Default State Machine を継続します。 + +## 追加のリソース + +この機能については、以下の Live Training Stream でもご覧いただけます。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + nkj6PAbGYtM + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + + + + + diff --git a/Engine/Documentation/Source/Engine/Animation/PoseSnapshot/PoseSnapshot.KOR.udn b/Engine/Documentation/Source/Engine/Animation/PoseSnapshot/PoseSnapshot.KOR.udn new file mode 100644 index 000000000000..746abf1633bb --- /dev/null +++ b/Engine/Documentation/Source/Engine/Animation/PoseSnapshot/PoseSnapshot.KOR.udn @@ -0,0 +1,98 @@ +INTSourceChangelist:3464925 +Availability:Public +Title: 애니메이션 포즈 스냅샷 +Crumbs: %ROOT%, Engine, Engine/Animation +Description:Animation Pose Snapshot, 애니메이션 포즈 스냅샷은 블루프린트에서 실행시간에 스켈레탈 메시 포즈를 캡처하여 애니메이션 블루프린트 내 다른 포즈로 블렌드 인 또는 아웃시키는 기능입니다. +Related: Engine\Animation\AnimBlueprints +Related: Engine\Blueprints +Related: Engine/Animation/Persona/Modes/Graph +Related: Engine/Animation/AnimMontage +Related: Engine/Physics/PhAT +version: 4.15 +type:reference +SkillLevel: Intermediate +topic-image:posesnapshottopic.png +tags:Animation +tags:Animation Blueprint +tags:Blueprints +tags:Animation Blending + +스켈레탈 메시 애니메이션을 적용할 때, 메시의 제어를 (캐릭터가 "래그돌" 상태에 들어가는 등) 피직스에 맡기고픈 경우가 있습니다. +피직스 적용 이후, **Animation Pose Snapshot** (애니메이션 포즈 스냅샷) 기능을 사용하면, 스켈레탈 메시 포즈를 캡처하여 (모든 본 트랜스폼 데이터를 포함해서) [블루프린트](Engine\Blueprints) 안에 저장하고 [](Engine\Animation\AnimBlueprints) 안에서 꺼내 쓰면 (아래 예제 비디오에서처럼) 저장된 포즈를 기준으로 블렌딩할 수 있게 됩니다. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 1BMOXpdfDjk + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +위에서는, 키를 누르면 캐릭터가 래그돌 상태에 들어가며 [캐릭터 블루프린트](Engine/Blueprints/UserGuide/Types/ClassBlueprint) 의 **Pose Snapshot** (포즈 스냅샷) 노드를 사용하여 스켈레탈 메시의 포즈를 저장합니다. +다른 키를 누르면, 캐릭터가 그 스냅샷에서 "get up" [](Engine/Animation/AnimMontage) 로 블렌딩된 뒤 원래 보행 상태로 돌아갑니다. +이렇게 하면 캐릭터에 피직스를 적용한 결과를 구해, 그 포즈에서 캐릭터 애니메이션의 원래 발 위치로 부드럽게 돌아가는 블렌딩을 얻을 수 있습니다. + +## 포즈 스냅샷 저장 + +스켈레탈 메시의 포즈를 런타임에 저장하기 위해서는, **캐릭터 블루프린트** 안에서, [Skeletal Mesh 컴포넌트](Engine/Components/SkeletalMesh) 와 그 **AnimInstance** 에 접근해야 합니다. + +그 상태에서 **Save Pose Snapshot** (포즈 스냅샷 저장) 노드를 호출하고 원하는 **Snapshot Name** (스냅샷 이름)을 입력하면 됩니다: + +![](PoseSnapShotBlueprint.png) + +Snapshot Name 칸에 직접 이름을 입력해도 되고, 이름 저장을 위한 변수를 만들어도 됩니다. +Snapshot Name 에 주는 이름은 **반드시** 애니메이션 블루프린트 안에서 포즈 스냅샷을 구할 때 사용하는 이름이어야 합니다. + +[REGION:note] +Save Pose Snapshot 을 호출할 때, 스냅샷은 현재 LOD 에서 찍습니다. 예를 들어 LOD1 에서 스냅샷을 찍은 다음 LOD0 에서 사용하면, LOD1 에 있지 않은 본은 메시의 레퍼런스 포즈를 사용할 것입니다. +[/REGION] + +## 포즈 스냅샷 구하기 + +포즈 스냅샷을 구하려면, **애니메이션 블루프린트** 의 **애님 그래프** 에서, **우클릭** 하고 **Pose Snapshot** 노드를 추가하고 **Snapshot Name** 을 입력합니다. + +![](PoseSnapShotAnimBPNode.png) + +아래는 래그돌 포즈에서 일어나는 캐릭터에 샘플로 사용한 예제 그래프입니다. + +![](PoseSnapShotAnimBP.png) + +위에서 **Default** 라는 [State Machine](Engine/Animation/StateMachines) 으로 캐릭터의 보행을 구동시키고 있으며, **MySlot** 노드에서 애님 몽타주를 사용하여 호출하면 캐릭터가 일어나는 애니메이션을 재생합니다. +[Blend Poses by bool](Engine/Animation/NodeReference/Blend) 노드를 사용하여 캐릭터가 이동을 멈췄는지 확인, **True** 면 포즈 스냅샷으로 전환합니다. +**False** 면 포즈 스냅샷에서 슬롯에 설정된 애님 몽타주로 블렌딩한 후 보통 디폴트 스테이트 머신을 이어갑니다. + +## 부가 자료 + +이 기능은 다음 라이브 트레이닝 스트림 방송에서도 확인할 수 있습니다: + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + nkj6PAbGYtM + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + + + + diff --git a/Engine/Documentation/Source/Engine/Animation/RetargetingDifferentSkeletons/RetargetingDifferentSkeletons.INT.udn b/Engine/Documentation/Source/Engine/Animation/RetargetingDifferentSkeletons/RetargetingDifferentSkeletons.INT.udn index e779ba49d526..fef72dc512e7 100644 --- a/Engine/Documentation/Source/Engine/Animation/RetargetingDifferentSkeletons/RetargetingDifferentSkeletons.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/RetargetingDifferentSkeletons/RetargetingDifferentSkeletons.INT.udn @@ -3,6 +3,7 @@ Title: Animation Retargeting (Different Skeletons) Crumbs: %ROOT%, Engine, Engine/Animation Description:Retargeting animations for use between different skeletons. Version: 4.9 +Topic-image:AnimRetargetingDiffSkeleton_topic.png [REGION:fullwidth] ![](Retarget1_1.jpg) diff --git a/Engine/Documentation/Source/Engine/Animation/RetargetingDifferentSkeletons/RetargetingDifferentSkeletons.JPN.udn b/Engine/Documentation/Source/Engine/Animation/RetargetingDifferentSkeletons/RetargetingDifferentSkeletons.JPN.udn index 0227bee6c6d7..d3bbcce51471 100644 --- a/Engine/Documentation/Source/Engine/Animation/RetargetingDifferentSkeletons/RetargetingDifferentSkeletons.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/RetargetingDifferentSkeletons/RetargetingDifferentSkeletons.JPN.udn @@ -1,9 +1,9 @@ -INTSourceChangelist:3285322 -Availability:Public +Availability:Public Title:アニメーション リターゲット(異なるスケルトン) Crumbs: %ROOT%, Engine, Engine/Animation Description:異なるスケルトン間で使用するためにアニメーションをリターゲットします。 Version:4.9 +Topic-image:AnimRetargetingDiffSkeleton_topic.png [REGION:fullwidth] ![](Retarget1_1.jpg) @@ -165,6 +165,7 @@ Animation Starter Pack には、いくつかのアニメーションが入って | **ball_r** | RightToeBase | | **thigh_twist_01_r** | RightUpLeg | あるスケルトンでもうひとつのスケルトンには含まれていない追加のボーンがある場合がありますが、これに対応するためにターゲット スケルトンで調整できるため、こうしたボーンは省略することができます。 + [REGION:note] IK のリターゲットはまだ開発途中であるため、この例では、Mixamo キャラクターの IK ボーンを **None** のままにすることもできます。 [/REGION] diff --git a/Engine/Documentation/Source/Engine/Animation/RetargetingDifferentSkeletons/RetargetingDifferentSkeletons.KOR.udn b/Engine/Documentation/Source/Engine/Animation/RetargetingDifferentSkeletons/RetargetingDifferentSkeletons.KOR.udn index 4a35c5d66ea2..8cdaa1b0a237 100644 --- a/Engine/Documentation/Source/Engine/Animation/RetargetingDifferentSkeletons/RetargetingDifferentSkeletons.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/RetargetingDifferentSkeletons/RetargetingDifferentSkeletons.KOR.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:3285322 +INTSourceChangelist:3467293 Availability:Public Title: 애니메이션 리타게팅 (다른 스켈레톤) Crumbs: %ROOT%, Engine, Engine/Animation Description:스켈레톤이 다른 경우에 사용하는 애니메이션 리타게팅 입니다. Version: 4.9 +Topic-image:AnimRetargetingDiffSkeleton_topic.png [REGION:fullwidth] ![](Retarget1_1.jpg) diff --git a/Engine/Documentation/Source/Engine/Animation/RootMotion/RootMotion.CHN.udn b/Engine/Documentation/Source/Engine/Animation/RootMotion/RootMotion.CHN.udn index 862b265b881b..a9f8bdbe4ba7 100644 --- a/Engine/Documentation/Source/Engine/Animation/RootMotion/RootMotion.CHN.udn +++ b/Engine/Documentation/Source/Engine/Animation/RootMotion/RootMotion.CHN.udn @@ -1,26 +1,25 @@ -INTSourceChangelist:100 +INTSourceChangelist:3467293 Availability:Public -Title: 根骨骼运动 +Title:根运动 Crumbs: %ROOT%, Engine, Engine/Animation -Description: 介绍了在虚幻引擎4中如何处理基于根骨骼的动画。 -Related: Engine/Content/FBX/Animations -Related: Engine/Content/Types/SkeletalMeshes -Related: Engine/Animation/PhysicallyDrivenAnimation -Related: Engine/Content/Tools/MayaRiggingTool -Related: Engine/Animation/AnimBlueprints -Related: Engine/Animation/AnimBlueprints/EventGraph -version: 4.9 +Description:了解基于根的动画在虚幻引擎 4 中的处理方式。 +Related:Engine/Content/FBX/Animations +Related:Engine/Content/Types/SkeletalMeshes +Related:Engine/Animation/PhysicallyDrivenAnimation +Related:Engine/Content/Tools/MayaRiggingTool +Related:Engine/Animation/AnimBlueprints +Related:Engine/Animation/AnimBlueprints/EventGraph +version:4.9 [TOC(start:2 end:2)] -一般,在游戏动画中,角色的碰撞胶囊体(或其他形状)在场景中是通过控制器来驱动的。然后,使用该胶囊体的数据来驱动动画。比如,如果一个胶囊体正在向前移动,那么系统知道要在角色上播放一个跑动或走动的动画,来呈现出角色正在靠自己的力量移动的效果。 -然而,这种类型的运动并不适合于所有情形。在某些情形中,使用复杂动画来实际地驱动碰撞胶囊体是有意义的,而反过来则不行。这就是在您的游戏中根骨骼运动处理变得至关重要的地方。 +通常而言,游戏动画中角色的碰撞胶囊体(或其他形状)由控制器通过场景来驱动。来自此胶囊体的数据则用于驱动动画。举例而言,如胶囊体向前移动,系统则会在角色上播放奔跑或行走动画,形成角色在利用自身能量前进的表象。然而,这类运动并不适用于所有情况。在一些情况下,复杂动画实际驱动碰撞胶囊体合乎逻辑,而且没有其他的方式可选。此时根运动对您的游戏就十分重要了。 -比如,设想下,如果网格物体受到玩家的特殊攻击后,预设置网格物体产生向前猛击的动画。如果所有角色动作都基于该玩家胶囊体,那么这样的动画将会使得角色迈到胶囊体的外面,从而丢失碰撞。一旦播放完动画,玩家又会滑回到它们的碰撞位置。这是有问题的,因为胶囊体一般会被作为所有计算的中心。超出胶囊体之外的角色将会穿过几何体,不能对它们的环境做出适当的反应。另外,在动画结束时滑回到它们的胶囊体是不真实的。 +举例而言,试想玩家发动特殊攻击,其中网格体已预设置向前冲的动画。如果所有角色动画均基于玩家胶囊体,那么此类动画将导致角色脱离胶囊体,失去实际碰撞。动画播放后,玩家可能会滑回其碰撞位置。这便会导致问题出现,因为胶囊体通常用作所有计算的中心。脱离胶囊体的角色将穿过几何体,无法和环境形成正确交互。此外,在动画的结尾滑回胶囊体也会显得十分不真实。 -对于这个概念的初学者来说,可能不能仅通过阅读一段介绍就能明白正确的根骨骼运动的重要性。下面,我们有个角色,它执行了预先设置好的攻击动画,向前猛击,然后向下抡动锤子。请注意,角色的向前移动的动画不是在游戏中处理的,是美术师那样设计的。 +对于刚接收到这个概念的用户而言,只通过阅读说明来理解根运动的重要性并非易事。下方视频中的角色正在执行一次预设动画的攻击——前冲并猛砸大锤。需要注意的是——角色向前移动的动画并非由游戏处理,而是由动画师所设计。 [OBJECT:EmbeddedVideo] [PARAMLITERAL:width] @@ -34,230 +33,263 @@ TKAcNubFOH8 [/PARAMLITERAL] [/OBJECT] + [REGION:tip] -See the [Animation Content Examples](Resources\ContentExamples\Animation) page under section 1.9 for another example of Root Motion. +在 [动画内容示例](Resources\ContentExamples\Animation) 页面的第 1.9 部分可查看根运动的另一个实例。 [/REGION] -[REGION:note] -根骨骼运动处理需要应用 **AnimMontage** 。如果您稍微熟悉一点这个资源,那么将是有用的。请参照 [AnimMontage documentation](Engine/Animation/AnimMontage)文档获得详细信息。 + +## 什么是根运动? + +简单而言,根运动就是骨架根骨骼基础动画的角色运动。多数游戏内动画均通过循环处理,其中角色的根仍为静止状态。情况并非固定如此,然而上例中便是如此的情况。如要处理这个问题,需要将根的运动从角色上移开,并将其应用到角色的胶囊体。这便是 UE4 中根运动的核心作用。 + +[REGION:warning] +为正确使用根运动,必须要注意的是角色的根骨骼应该处于原点(0,0,0 且不带旋转),因为这将使系统从动画运动(角色)中分离出物理运动(胶囊体)。 [/REGION] -## 什么是根骨骼运动? -简单地讲,根骨骼运动是指角色基于骨架根骨骼动画的运动。大部分游戏中的动画都是通过循环处理的,在这里角色的根骨骼仍然是固定的。但正如我们在上面的例子中所看到的,并不总是这样的情形。要想处理这个问题,我们需要去除角色的根骨骼的运动,而是将将它应用到角色胶囊体上。这是UE4中根骨骼运动的精髓。 - -您可以在动画编辑器中可视化地查看动画的根骨骼的运动。只需简单地打开包含正在移动的根骨骼的任何动画,在视口中选择 **Show(显示) > Bones(骨骼)** 。您将注意到红色的线代表角色的根骨骼运动。这解释了动画的根骨骼运动。 +回放中可看到动画的根运动。打开根骨骼运动的动画,在视口中选择 **Show > Bones**。如尚未在动画属性中选择 **Enable Root Motion**,角色的根移动时便会出现一条红线。这条线展示了动画的根运动。 [REGION:fullwidth] ![](RootMotionBone.png) [/REGION] -一旦我们将该动画应用给AnimMontage(动画蒙太奇)(稍后将在本文中处理的东西),我们将可以启用Root Motion Translation(根骨骼平移)和Rotation(旋转)。完成这个处理后,角色的根骨骼将不会再从它的原始位置开始移动。在该图片中,我们已经在角色上启用了Root Motion(根骨骼运动)。注意,我们处在和上面的图片一样的框架中,但是角色的位置发生了改变。 +启用根运动后,这条红线便会消失。而角色便会移动到恰当的位置。这是因为角色的根不再从其原始位置进行移动。此图中,我们已在角色启用根运动。注意我们现在处于和上图中同一帧,但角色的位置并未发生变化。 [REGION:fullwidth] ![](RootMotionAppliedBone.png) [/REGION] - -那么,这是什么意思哪? 由于系统正在考虑角色动画的根骨骼运动,所以稍后就可以将那个同样的运动重新应用给角色的碰撞胶囊体。这意味着,角色仍然可以具有动画设计师期望的完全一致的运动效果,但是它也可以在游戏中对碰撞、其他物理及游戏事件做出正确的反应。在下面的部分中,我们将看到这个额处理的运作效果。 +那这意味着什么呢?系统把角色动画的根运动计算在内后,则可将相同运动重新应用到角色的碰撞胶囊体。这意味着动画师设置的动作将完全得到保留,但同时也会正确地响应游戏中的碰撞和其他物理&游戏进程事件。我们将在下一部分看到实际操作。 -(#EnablingRootMotion) -## 启用 Root Motion +## 启用根运动 -Root Motion can be enabled inside the **Anim Asset Details** panel of **Persona** for your [Animation Sequence](Engine\Animation\Sequences). +可在 **Animation Editor** 的 **Asset Details** 面板中启用 [动画序列](Engine\Animation\Sequences) 的根运动。 ![](RootMotion.png) [REGION:warning] -Early versions of the engine (Versions previous to 4.5) required the use of an [Animation Montage](https://docs.unrealengine.com/latest/INT/Engine/Animation/AnimMontage/index.html) to define Root Motion. Since version 4.6, Root Motion is now handled per Animation Sequence and can be toggled on/off in the animation's properties in Persona. -For networked games however, Root Motion still requires the use of an Animation Montage, see [Root Motion from Montages Only](#rootmotionfrommontagesonly) below. +早期引擎版本(4.5 之前版本)需要使用 [动画蒙太奇](https://docs.unrealengine.com/latest/INT/Engine/Animation/AnimMontage/index.html) 来定义根动画。从 4.6 版本开始,根运动的处理基于每个动画序列,可在 Persona 的动画属性开启/关闭。 +然而对网络游戏而言,根运动仍然需要使用动画蒙太奇,请查阅下方 [Root Motion from Montages Only](#rootmotionfrommontagesonly) 部分。 [/REGION] -While defining if Root Motion is enabled in done inside the Animation Sequence, you will still need to determine how that sequence is handled inside of an [Animation Blueprint]( Engine/Animation/AnimBlueprints). There are several different ways in which you can handle Root Motion within Animation Blueprints. You can define this through the **Root Motion Mode** drop down menu inside the Anim Blueprint Editor inside Persona. +虽然是在动画序列中定义根运动是否启用,但仍然需要确定 [动画蓝图]( Engine/Animation/AnimBlueprints) 中序列的处理方式。在动画蓝图中有处理根运动的多个方式。可通过 **Anim Blueprint Editor** 的 **Details** 面板中的 **Root Motion Mode** 下拉菜单进行定义。 ![](RootMotionMode.png) -[REGION:note] -Make sure that you are setting this inside the **Edit Defaults** tab and not the **Edit Preview**. -[/REGION] +这些选项如下: -The options are as follows: - -| **Property** | **Description** | +| **属性** | **描述** | | --- | --- | -| **No Root Motion Extraction** | Root Motion is left as is (applied to the root bone). | -| **Ignore Root Motion** | Root Motion is extracted (and removed from the root bone), but not applied to the character. | -| **Root Motion from Everything** | See Below. | -| **Root Motion from Montages Only** | See Below. | +| **No Root Motion Extraction** | 根运动保留不变(应用至根骨骼)。| +| **Ignore Root Motion** | 根运动已被提取(并从根骨骼移除),但未应用到角色。| +| **Root Motion from Everything** | 见下文。| +| **Root Motion from Montages Only** | 见下文。| ### Root Motion from Everything -When this option is set as the Root Motion Mode, each animation asset (AnimSequence, Blendspace, AnimMontage, etc.) that contributes to the final character pose has its Root Motion extracted (if it has been set as containing Root Motion). Each piece of extracted Root Motion is blended based on the weight of the source assets contributing to the pose. +此选项被设为 Root Motion Mode 后,组成角色最终动作的每个动画资源(AnimSequence、Blendspace、AnimMontage 等)的根运动均会被提取(前提是角色动作已设为包含根运动)。被提取的根运动的每个块基于组成动作的源资源权重进行混合。 -For example: +例如: ![](FromEverything.png) -In the image above, the Root Motion of **Jog_Loop_Fwd_RM** and **Jog_Loop_Right_RM** would each be blended together with a weight of 0.5. The resulting animation in this case is a character running diagonally forwards and right across a map. +上图中,**Jog_Loop_Fwd_RM** 和 **Jog_Loop_Right_RM** 的根运动将以各 0.5 的权重混合在一起。此设置下的动画效果是角色将斜对角超前奔跑,穿过地图。 ### Root Motion from Montages Only -This method is intended for network games which is the reason for its more restricted functionally. Because **Root Motion from Everything** is designed to be unrestricted, it is recommended that it only be used in games where animation isn't replicated over a network. - -## 运作中的根骨骼运动 - -下面详细介绍了没有处理根骨骼动画导致的问题以及根骨骼运动对您的动画的好处。我们将使用上面的向前猛冲动画。 - -### 没有根骨骼运动 - -没有根骨骼运动,该动画将会使得角色脱离它的胶囊体,正如下面所示。注意,出现了难看的迅速返回到胶囊体位置处的情形。这之所以发生是因为,一旦该完成播放该动画,角色控制器就会把它拉回到它的原始位置处。 - -[REGION:lightbox] -[![](HammerSlamStatic_NoRootMotion.png)](HammerSlam_NoRootMotion.gif) -[/REGION] - -**点击进行播放** - -### 为什么角色同胶囊体分离是糟糕的情形 - -在这个实例中,快速回退问题不是唯一要解决的问题。因为角色离开了碰撞包围框,它穿过了世界中的对象,打破了整体的连续性。在这个示例中,我们可以看到角色的攻击行为使得它穿过了墙壁,然后又跳了回来。 - - -[REGION:lightbox] -[![](HammerSlamStatic_NoRootMotion_Wall.png)](HammerSlam_NoRootMotion_Wall.gif) -[/REGION] - -**点击进行播放** - -### 根骨骼运动处理如何解决这个问题 - -一旦您的动画设置为使用根骨骼运动,那么动画师临时设置的运动就变成了该胶囊体的驱动力。这使得我们可以继续从动画的结束处继续播放。您可以看到,我们第二次触发攻击时,我们从新的位置处开始的。当然,我们首先要转个身,以便我们不会脱离相机。 +此方法用于功能更为受限的网络游戏。**Root Motion from Everything** 的理念便是不受限制,因此只建议将其用在动画不通过网络进行复制的游戏中。 -[REGION:lightbox] -[![](HammerSlamStatic_RootMotion_NoWall.png)](HammerSlam_RootMotion.gif) -[/REGION] +## 根运动实操 -**点击进行播放** +以下详解不处理根运动导致的问题,以及根运动对动画的益处。我们将使用下方所示的前冲动画 + +### 无根运动 + +如果没有根运动,动画则会使角色脱离胶囊体,如下方视频所示。可以明显注意到角色弹回胶囊体位置。出现此情况的原因是动画播放完成后,角色控制器将把角色拉回其原点。 + +[OBJECT:EmbeddedVideo] +[PARAMLITERAL:width] +640 +[/PARAMLITERAL] +[PARAMLITERAL:height] +360 +[/PARAMLITERAL] +[PARAMLITERAL:videoid] +Xu2bVQ4pg8M +[/PARAMLITERAL] +[/OBJECT] -### 根骨骼运动和物理 +### 为何胶囊体分离十分糟糕 -由于胶囊体保持同步,这意味着物理碰撞仍然可以使用,从而我们就解决了角色穿透墙壁的问题,同时缓解了角色需要快速返回到胶囊位置处的问题。在下面的图片中,动画使用了Root Motion(根骨骼运动),这使得胶囊体和角色可以保持同步,从而使得角色和墙壁产生碰撞,而不是穿过墙壁。 +而此情况下需要解决的还不仅是弹回一个问题。因为角色正在离开碰撞形态,它将穿透世界场景中的物体,并打破整体连贯性。在此例中,我们可看到角色的攻击使他穿过墙壁,然后弹回。 -您将会注意到,这并不是非常完美,因为角色的弯腰动画使它在某种程度上穿过了墙壁。然而,这个可以通过处理墙壁或角色上的碰撞体积来解决。较重要的一点是,胶囊体和运动保持同步,从而防止角色径直穿过墙壁又必须立即返回的情形。 -[REGION:lightbox] -[![](HammerSlamStatic_RootMotion.png)](HammerAnimation_RootMotion_Wall.gif) -[/REGION] +[OBJECT:EmbeddedVideo] +[PARAMLITERAL:width] +640 +[/PARAMLITERAL] +[PARAMLITERAL:height] +360 +[/PARAMLITERAL] +[PARAMLITERAL:videoid] +ov9pyx4MAOo +[/PARAMLITERAL] +[/OBJECT] -**点击进行播放** + +### 根运动处理如何解决问题 + +设置动画使用根运动后,动画师设置的动作将暂时成为胶囊体的驱动力。这使得动画到达终点后继续播放。现在可以看到第二次触发攻击动作后将从新位置开始。当然,需要调转第一个动作,摄像机便不会离开原处。 - -## 设置根骨骼运动 - -[REGION:note] -根骨骼运动处理需要应用 **AnimMontage** 。如果您稍微熟悉一点这个资源,那么将是有用的。请参照 [AnimMontage documentation](Engine/Animation/AnimMontage)文档获得详细信息。 -[/REGION] +[OBJECT:EmbeddedVideo] +[PARAMLITERAL:width] +640 +[/PARAMLITERAL] +[PARAMLITERAL:height] +360 +[/PARAMLITERAL] +[PARAMLITERAL:videoid] +PWB_mqjz3iA +[/PARAMLITERAL] +[/OBJECT] -在UE4中设置根骨骼运动非常简单。从较高的层次讲,这个过程包括: +### 根运动和物理 -1. 将需要根骨骼控制的动画分配给一个AnimMontage资源。 -1. 在那个AnimMontage中,确保命名包含该运动的插槽。 -1. 同时在AnimMontage,确保选中 **Enable Root Motion Translation** 和 **Enable Root Motion Rotation** 属性。 -1. 在动画图表中,确保动画连入通过一个 **Slot(插槽)** 节点,且将给Slot节点分配和AnimMontage的插槽一样的名称。 -1. 在动画蓝图的事件图表中播放您的AnimMontage。 +胶囊体继续跟随后,就意味着仍然可以使用物理碰撞,角色穿过墙壁的问题已经得到解决,并缓解角色弹回胶囊体位置的问题。下图中的动画使用根运动,将带动胶囊体,使角色和墙壁发生碰撞,而不是从中穿过。 -在本文档中,我们将介绍如何设置上面的示例来应用根骨骼运动。 +您会发现这并不完美,因为角色的混合动画将导致其轻微穿过墙壁。然而对墙壁或角色上的碰撞体积域进行调整即可轻松处理此问题。重要的是胶囊体与运动保持一致,防止角色穿过墙壁并弹回。 -### 设置概述 +[OBJECT:EmbeddedVideo] +[PARAMLITERAL:width] +640 +[/PARAMLITERAL] +[PARAMLITERAL:height] +360 +[/PARAMLITERAL] +[PARAMLITERAL:videoid] +YuD29-Xr7Oc +[/PARAMLITERAL] +[/OBJECT] -对于初学者来说,我们简单地有一个基本的第三人称角色。这个角色实际上是第三人称角色模板的衍生物,该模板可以在UE4的项目模板中找到。唯一的特殊添加物是我们将设置一种特殊情形,在这里,按下R键将播放我们抡锤子的动画。没有代码来将它变成一次攻击,它不施加伤害。它仅是我们播放需要根骨骼运动的动画的一种方法。 - -有很多种进行这种设置的方法,我们将概述介绍一种方法,然后主要针对设置Root Motion(根骨骼运动)。 - -我们的设置从自定义的GameMode蓝图、PlayerController蓝图、角色蓝图及动画蓝图开始。我们使用一个蓝图接口来将一个事件从角色发送到动画蓝图中。这里是具体的详细介绍: - -* **GameMode(游戏模式)** - 决定Controller 和Pawn类,分别是我们的自定义的PlayerController和角色蓝图。 -* **PlayerController(玩家控制器)** - 仅设置几个属性。这和第三人称模板中包含的玩家控制器一样。 -* **Character(角色)** - 这里我们设置静态网格物体组件、相机及输入处理。 -* **Animation Blueprint(动画蓝图)** - 该项处理我们角色动画的状态。 -* **BlueprintInterface(蓝图接口)** - 用于将一个事件从我们的角色蓝图发送到动画蓝图中。这是我们触发AnimMontage的方法。 +在根运动中,角色的物理状态将纳入计算。举例而言,如果角色物理为行走或倒下,则 Z 轴根运动将被无视,将应用重力。角色将倒下、走下斜坡或走上台阶。如角色物理为飞行,则会应用完整根运动并无视重力。 + + - \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Animation/RootMotion/RootMotion.INT.udn b/Engine/Documentation/Source/Engine/Animation/RootMotion/RootMotion.INT.udn index b4bd53e5b3c3..e8f281cdb192 100644 --- a/Engine/Documentation/Source/Engine/Animation/RootMotion/RootMotion.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/RootMotion/RootMotion.INT.udn @@ -9,6 +9,7 @@ Related: Engine/Content/Tools/MayaRiggingTool Related: Engine/Animation/AnimBlueprints Related: Engine/Animation/AnimBlueprints/EventGraph version: 4.9 +topic-image:RootMotion_topic.png [TOC(start:2 end:2)] diff --git a/Engine/Documentation/Source/Engine/Animation/RootMotion/RootMotion.JPN.udn b/Engine/Documentation/Source/Engine/Animation/RootMotion/RootMotion.JPN.udn index 27a3493c2a22..6e4a35c987ee 100644 --- a/Engine/Documentation/Source/Engine/Animation/RootMotion/RootMotion.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/RootMotion/RootMotion.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3206317 +INTSourceChangelist:3467293 Availability:Public Title:ルート モーション Crumbs: %ROOT%, Engine, Engine/Animation @@ -10,6 +10,7 @@ Related:Engine/Content/Tools/MayaRiggingTool Related:Engine/Animation/AnimBlueprints Related:Engine/Animation/AnimBlueprints/EventGraph version:4.9 +topic-image:RootMotion_topic.png [TOC(start:2 end:2)] diff --git a/Engine/Documentation/Source/Engine/Animation/RootMotion/RootMotion.KOR.udn b/Engine/Documentation/Source/Engine/Animation/RootMotion/RootMotion.KOR.udn index a2c95be32b30..cd07c595f1d6 100644 --- a/Engine/Documentation/Source/Engine/Animation/RootMotion/RootMotion.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/RootMotion/RootMotion.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3206317 +INTSourceChangelist:3467293 Availability:Public Title:루트 모션 Crumbs: %ROOT%, Engine, Engine/Animation @@ -10,6 +10,7 @@ Related: Engine/Content/Tools/MayaRiggingTool Related: Engine/Animation/AnimBlueprints Related: Engine/Animation/AnimBlueprints/EventGraph version: 4.9 +topic-image:RootMotion_topic.png [TOC(start:2 end:2)] diff --git a/Engine/Documentation/Source/Engine/Animation/Sequences/AnimationSequences.INT.udn b/Engine/Documentation/Source/Engine/Animation/Sequences/AnimationSequences.INT.udn index ab654882fd0a..eea7d35ad777 100644 --- a/Engine/Documentation/Source/Engine/Animation/Sequences/AnimationSequences.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/Sequences/AnimationSequences.INT.udn @@ -9,26 +9,9 @@ Related: Engine/Animation/StateMachines Related: Gameplay/AI Related: Engine/Content/Tools/MayaRiggingTool version: 4.14 +tags:Assets +topic-image:Engine/Animation/Overview/AnimationSeqTopic.png -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Animation/Sequences:title%](Engine/Animation/animation_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Animation/Sequences:title% - [/PARAM] - [PARAM:description] - %Engine/Animation/Sequences:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Animation/Sequences] - [/PARAM] -[/OBJECT] -[/VAR] [TOC(start:2 end:2)] diff --git a/Engine/Documentation/Source/Engine/Animation/Sequences/AnimationSequences.JPN.udn b/Engine/Documentation/Source/Engine/Animation/Sequences/AnimationSequences.JPN.udn index f1945ca7b47b..3d7df049ed00 100644 --- a/Engine/Documentation/Source/Engine/Animation/Sequences/AnimationSequences.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/Sequences/AnimationSequences.JPN.udn @@ -1,8 +1,8 @@ -INTSourceChangelist:3219745 +INTSourceChangelist:3429233 Availability:Public Title:アニメーション シーケンス Crumbs: %ROOT%, Engine, Engine/Animation -Description:単一のアニメーションを構成するすべての変形データを含む個々のアセット +Description:単一のアニメーションを構成するすべてのトランスフォーム データを含む個々のアセット Related:Engine/Content/FBX/Animations Related:Engine/Content/Types/SkeletalMeshes Related:Engine/Animation/PhysicallyDrivenAnimation @@ -10,26 +10,9 @@ Related:Engine/Animation/StateMachines Related:Gameplay/AI Related:Engine/Content/Tools/MayaRiggingTool version:4.14 +tags:Assets +topic-image:Engine/Animation/Overview/AnimationSeqTopic.png -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Animation/Sequences:title%](Engine/Animation/animation_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Animation/Sequences:title% - [/PARAM] - [PARAM:description] - %Engine/Animation/Sequences:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Animation/Sequences] - [/PARAM] -[/OBJECT] -[/VAR] [TOC(start:2 end:2)] diff --git a/Engine/Documentation/Source/Engine/Animation/Sequences/AnimationSequences.KOR.udn b/Engine/Documentation/Source/Engine/Animation/Sequences/AnimationSequences.KOR.udn index 86f4a72452a0..a5fb11e0c4a5 100644 --- a/Engine/Documentation/Source/Engine/Animation/Sequences/AnimationSequences.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/Sequences/AnimationSequences.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3219745 +INTSourceChangelist:3429233 Availability:Public Title:애니메이션 시퀀스 Crumbs: %ROOT%, Engine, Engine/Animation @@ -10,26 +10,9 @@ Related: Engine/Animation/StateMachines Related: Gameplay/AI Related: Engine/Content/Tools/MayaRiggingTool version: 4.14 +tags:Assets +topic-image:Engine/Animation/Overview/AnimationSeqTopic.png -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Animation/Sequences:title%](Engine/Animation/animation_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Animation/Sequences:title% - [/PARAM] - [PARAM:description] - %Engine/Animation/Sequences:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Animation/Sequences] - [/PARAM] -[/OBJECT] -[/VAR] [TOC(start:2 end:2)] @@ -169,7 +152,7 @@ Qo4hH0h9ZZA [REGION:note] 루트 모션 관련해서, 네트워킹 게임에 루트 모션의 리플리케이션 필요 여부 등 고려해야 할 상황이 몇 가지 있습니다. 루트 모션의 리플리케이션이 필요한 경우, [애니메이션 몽타주](Engine\Animation\AnimMontage) 를 사용해야 할 것입니다. -자세한 정보는 [루트 모션 켜기](Engine\Animation\RootMotion#enablingrootmotion) 문서를 참고하세요. +자세한 정보는 [루트 모션 켜기](Engine\Animation\RootMotion) 문서를 참고하세요. [/REGION] ### 임포트 세팅 diff --git a/Engine/Documentation/Source/Engine/Animation/Sequences/Notifies/AnimNotifies.INT.udn b/Engine/Documentation/Source/Engine/Animation/Sequences/Notifies/AnimNotifies.INT.udn index a69da03e55d1..1217bf641aae 100644 --- a/Engine/Documentation/Source/Engine/Animation/Sequences/Notifies/AnimNotifies.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/Sequences/Notifies/AnimNotifies.INT.udn @@ -7,6 +7,7 @@ Related: Engine/Animation/Sequences/Editor Related: Engine/Animation/AnimMontage Related: Engine/Animation Related: Engine/Animation/AnimHowTo +topic-image:Engine/Animation/Overview/AnimNotifiesTopic.png [VAR:Topic] [OBJECT:Topic] diff --git a/Engine/Documentation/Source/Engine/Animation/Sequences/Notifies/AnimNotifies.JPN.udn b/Engine/Documentation/Source/Engine/Animation/Sequences/Notifies/AnimNotifies.JPN.udn index ec058f1e0a36..04946f208c38 100644 --- a/Engine/Documentation/Source/Engine/Animation/Sequences/Notifies/AnimNotifies.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/Sequences/Notifies/AnimNotifies.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:2720152 +INTSourceChangelist:3429233 Availability:Public Title:アニメーション通知 Crumbs: %ROOT%, Engine, Engine/Animation, Engine/Animation/Sequences @@ -8,6 +8,7 @@ Related:Engine/Animation/Sequences/Editor Related:Engine/Animation/AnimMontage Related:Engine/Animation Related:Engine/Animation/AnimHowTo +topic-image:Engine/Animation/Overview/AnimNotifiesTopic.png [VAR:Topic] [OBJECT:Topic] @@ -81,7 +82,7 @@ Play Particle Effect 通知は、挙動の制御に Animation ブループリン | **プロパティ** | **説明** | | --- | --- | | **Attach Name** | サウンド エフェクトのスポーン ポイントとして使用するスケルタルメッシュのソケットまたはボーンを含みます。 | -| **Volume Multiplier** | このスケーリング乗数は、サウンド エフェクトのボリュームに適用されます。| +| **Volume Multiplier** | このスケーリング乗数は、サウンド エフェクトのボリュームに適用されます。 | | **Pitch Multiplier** | このスケーリング乗数は、サウンド エフェクトのピッチに適用されます。 | | **Follow** | チェックを入れると、スタティックメッシュが動くにつれて、サウンド エフェクトのソースが追随します。チェックを入れないと、サウンドはスポーンされた場所に留まります。 | | **Notify Color** | 通知バーの通知のカラーを変更します。| @@ -104,7 +105,7 @@ Play Particle Effect 通知は、挙動の制御に Animation ブループリン **AnimNotifyStates** (**Notify States**) は、上記の標準的な通知のように機能し、start、tick、end の3 種類のイベントがあります。これらは簡単に開始し、通知が開始、終了する瞬間に発行し、その中にある **イベントグラフ** はアニメーションで時間がくると発生します。end event に到達するまで、アニメーションがアップデートされるたびにティックが発生します。標準の通知との違いは、NotifyStates は、自己完結型の [ブループリント](Engine/Blueprints) であるという点です。 -Notify State (通知ステート) の作成は、アニメーションの **通知トラック** で **右クリック** して通常の通知を追加するのと同じ方法で行うことができます (通知ステートは 、[ネイティブ通知ステート](#ネイティブ通知ステート) と同じですが、アニメーション中に発生させる必要があるどのようなロジックでも提供できるカスタム ブループリントです) 。 +Notify State (通知ステート) の作成は、アニメーションの **通知トラック** で **右クリック** して **Add Notify State...** を選択するのと同じ方法で行うことができます (通知ステートは、[ネイティブ通知ステート](#ネイティブ通知ステート) と同じですが、アニメーション中に発生させる必要があるどのようなロジックでも提供できるカスタム ブループリントです) 。 [REGION:note] カスタム通知を使用するには、まず AnimNotifyState クラスの [Blueprint クラスを作成](Engine/Blueprints/UserGuide/Types/ClassBlueprint/Creation) しなければなりません。 @@ -134,21 +135,21 @@ _Notify Tick のオーバーライド_ | **ピン** | **説明** | | --- | ----------- | -| **Mesh Comp** | この AnimNotifyState をトリガーしているアニメーション シーケンスまたはモンタージュのスケルタルメッシュのコンポーネントです。 | -| **Anim Seq** | この AnimNotifyState をトリガーしている特定のアニメーション シーケンスです。 | -| **Frame Delta Time** | Received Notify Tick 関数にのみ存在し、アニメーションの最終アップデートからの時間を表します。 | +| **Mesh Comp** | AnimNotifyStateをトリガーするアニメーション シーケンスまたはモンタージュの Skeletal Mesh コンポーネントです。 | +| **Anim Seq** | AnimNotifyStateをトリガーする特定のアニメーション シーケンスです。 | +| **Frame Delta Time** | Received Notify Tick 関数でのみ。アニメーションの最終更新からの時間がわかります。 | [REGION:note] -現在、ブループリント内で AnimNotifyState の長さを取得する方法はありません。 +ブループリント内で AnimNotifyState の長さを取り出す手段は現在ありません。 [/REGION] -### 規則 +### ルール * 必ず NotifyBegin Eventで開始するようになっています。 * 必ず NotifyEnd Eventで終了するようになっています。 * 必ず NotifyBegin と NotifyEnd のイベントの間に NotifyTick をラップするようになっています。 * 異なる AnimNotifies (normal または state) 間の順序は保証されません。2 つの AnimNotifyStates を隣同士に入れると、最初の AnimNotifyStates が、次の AnimNotifyStates が開始するまでに終了することは保証されません。これは、他の通知に依存していない個別のアクションにのみ使用してください。 -* 負の再生速度をサポートしています。それでも NotifyBegin が最初に呼ばれ、NotifyEnd が最後に呼ばれます。 +* 負の再生速度がサポートされます。それでも NotifyBegin が最初に呼ばれ、NotifyEnd が最後に呼ばれます。 ### 順序とロジック @@ -164,7 +165,7 @@ Notify State を追加することを選択する際に、2 つある **Native N ### Timed Particle Effects -Timed Particle Effect (時限式パーティクルエフェクト) は、**Play Particle Effect(パーティクルエフェクト再生)** 通知と非常に似ています。両方とも、アニメーションの任意のポイントでパーティクル エフェクトを再生できるからです。この 2 つの違いは、Timed Particle Effect では、通知そのものの内部でエフェクトの長さを定義できるという点です。 +Timed Particle Effect (時限式パーティクルエフェクト) は、**Play Particle Effect (パーティクルエフェクト再生)** 通知と非常に似ています。両方とも、アニメーションの任意のポイントでパーティクル エフェクトを再生できるからです。この 2 つの違いは、Timed Particle Effect では、通知そのものの内部でエフェクトの長さを定義できるという点です。 ![](TimedParticleEffect.png) @@ -176,7 +177,7 @@ Animation Trails (または略して **AnimTrail**) は、シーン内で移動 AnimTrail エミッタを使用するには、以下を行う必要があります。 1. AnimTrail タイプのデータを含む [パーティクル システム](Engine/Rendering/ParticleSystems) を作成します。 -1. **Trail** タイプの通知ステートを作成しアニメーションに追加します。 +2. **Trail** タイプの通知ステートを作成しアニメーションに追加します。 [REGION:banner] ![](StateMachineImage.png) diff --git a/Engine/Documentation/Source/Engine/Animation/StateMachines/StateMachines.JPN.udn b/Engine/Documentation/Source/Engine/Animation/StateMachines/StateMachines.JPN.udn index ef4c71ba1272..fe824ed6f670 100644 --- a/Engine/Documentation/Source/Engine/Animation/StateMachines/StateMachines.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/StateMachines/StateMachines.JPN.udn @@ -1,30 +1,12 @@ -Availability:Public +INTSourceChangelist:3429233 +Availability:Public Title:ステートマシン Crumbs: %ROOT%, Engine, Engine/Animation Description:ステートマシンは、ステートの変化過程で発生するブレンドを完全制御しながら、スケルタル アニメーションをさまざまなステートへ分割します version:4.12 +tags:Assets +topic-image:Engine/Animation/Overview/StateMachineTopic.png - [REGION:banner] ![](StateMachineImage.png) diff --git a/Engine/Documentation/Source/Engine/Animation/StateMachines/StateMachines.KOR.udn b/Engine/Documentation/Source/Engine/Animation/StateMachines/StateMachines.KOR.udn index 43dfbae24f63..3660b09f89de 100644 --- a/Engine/Documentation/Source/Engine/Animation/StateMachines/StateMachines.KOR.udn +++ b/Engine/Documentation/Source/Engine/Animation/StateMachines/StateMachines.KOR.udn @@ -1,31 +1,12 @@ -INTSourceChangelist:3231087 +INTSourceChangelist:3429233 Availability:Public Title: 스테이트 머신 Crumbs: %ROOT%, Engine, Engine/Animation Description:State Machine, 스테이트 머신으로 스켈레탈 애니메이션을 여러 상태별로 나누어, 상태 전환시 일어나는 블렌딩을 완벽히 제어할 수 있습니다. version: 4.12 +tags:Assets +topic-image:Engine/Animation/Overview/StateMachineTopic.png - [REGION:banner] ![](StateMachineImage.png) diff --git a/Engine/Documentation/Source/Engine/Animation/SyncGroups/SyncGroups.INT.udn b/Engine/Documentation/Source/Engine/Animation/SyncGroups/SyncGroups.INT.udn index 5c7a424ccd1c..0754ad8f65e9 100644 --- a/Engine/Documentation/Source/Engine/Animation/SyncGroups/SyncGroups.INT.udn +++ b/Engine/Documentation/Source/Engine/Animation/SyncGroups/SyncGroups.INT.udn @@ -3,7 +3,7 @@ Title: Sync Groups Crumbs: %ROOT%, Engine, Engine/Animation Description:Sync Groups allow you to maintain the synchronization of animations of different lengths. version: 4.9 - +topic-image:SyncGroups_topic.png [EXCERPT:Intro] **Sync Groups** are to keep related animations that may have different lengths synchronized. For example, you may have a walk cycle and a run cycle that you would like to blend together so that the character can smoothly accelerate or decelerate. But what if these animations were different lengths, such as the walk being significantly longer than the run? In such a case, directly blending from one to the other would have unnatural results, an unsightly "beat" as the foot animation switches. diff --git a/Engine/Documentation/Source/Engine/Animation/SyncGroups/SyncGroups.JPN.udn b/Engine/Documentation/Source/Engine/Animation/SyncGroups/SyncGroups.JPN.udn index e84f147ee904..f54bce60db95 100644 --- a/Engine/Documentation/Source/Engine/Animation/SyncGroups/SyncGroups.JPN.udn +++ b/Engine/Documentation/Source/Engine/Animation/SyncGroups/SyncGroups.JPN.udn @@ -1,19 +1,20 @@ -Availability:Public +INTSourceChangelist:3467293 +Availability:Public Title:Sync Group Crumbs: %ROOT%, Engine, Engine/Animation Description:Sync Group は、異なる長さのアニメーションの同期の維持を可能にします。 version:4.9 - +topic-image:SyncGroups_topic.png [EXCERPT:Intro] -**Sync Group** は、異なる長さを持つ関連アニメーションを同期し続けます。例えば、歩きサイクルと走りサイクルをブレンドさせて、キャラクターを滑らかに加速または減速させる場合があります。ただし、これらのアニメーションが異なる長さだったらどうなるでしょうか?例えば、歩行は走行よりもかなり時間がかかります。そのような場合、あるワールドをもう 1 つのワールドに直接ブレンドすると、足のアニメーションの切り替え時にビートが醜く、不自然な結果が生じることになります。 +**Sync Group** は、異なる長さを持つ関連アニメーションを同期し続けます。例えば、歩きサイクルと走りサイクルをブレンドさせて、キャラクターを滑らかに加速または減速させる場合があります。ただし、これらのアニメーションが異なる長さだったらどうなるでしょうか?例えば、歩行が走行よりもかなり長い時間かかる場合はどうでしょう?そのような場合、あるものをもう 1 つのものに直接ブレンドすると、足のアニメーションの切り替え時に見栄えの悪いビートが生じて、不自然な結果が生じることになります。 Sync Group は、主要なアニメーション ノード 1 つをリーダーにし、関連するその他全てのアニメーションは単に時間の長さが一致するようにスケールすることで、この問題を解消します。通常、リーダーはブレンド ウェイトが一番大きいノードになります。ウェイトがブレンドされ、フォロワーのウェイトがリーダーのウェイトより重くなったら、このフォロワーがリーダーとなります。このように、2 つのアニメーションが共に円滑に機能して、1 つのモーションから次のモーションへシームレスに遷移します。 ただし、アニメーションの時間は変更しているので、アニメーションに対しある程度の考慮が必要です。例えば、異なる歩きサイクルと走りサイクルをブレンドさせた例では、アニメーションは動き始めと終わりが必ず同じ足になるようにすると思います。こういった標準を早めに作成しておくと、全てのブレンドをもっとスムーズにできるようになります! [/EXCERPT:Intro] -###グループの役割:リーダーとフォロワー +###グループのロール:リーダーとフォロワー Sync Group は、 1 つのアニメーションがリーダーとなり、その他は全てフォロワーとなるグループ ロールの概念で機能します。 @@ -29,9 +30,9 @@ Sync Group は、 1 つのアニメーションがリーダーとなり、その |[INCLUDE:#runanimation]| Sync Group 名 WalkRun に設定された元のサイズの走行アニメーションです。 | |[INCLUDE:#walkanimation]| Sync Group 名 _WalkRun_ に設定された元のサイズの歩行アニメーションです。 | |[INCLUDE:#walkanimationscaled] | このインスタンスでは、走行アニメーションのブレンド ウェイトが歩行アニメーションより重くなります。これらは同じ Sync グループなので、歩行アニメーションが走行アニメーションの長さに一致するように短縮されます。| -|[INCLUDE:#runanimationscaled]| ここで、歩行アニメーションのブレンド ウェイトの方が重たくなります。この結果、走行アニメーションは走行の長さに一致するように拡大されます。 +|[INCLUDE:#runanimationscaled]| ここで、歩行アニメーションのブレンド ウェイトの方が重たくなります。この結果、走行アニメーションは歩行の長さに一致するように拡大されます。 | - diff --git a/Engine/Documentation/Source/Engine/Audio/SoundCues/NodeReference/SoundCueReference.KOR.udn b/Engine/Documentation/Source/Engine/Audio/SoundCues/NodeReference/SoundCueReference.KOR.udn index 3a25d3d0e3ff..4759dae0730e 100644 --- a/Engine/Documentation/Source/Engine/Audio/SoundCues/NodeReference/SoundCueReference.KOR.udn +++ b/Engine/Documentation/Source/Engine/Audio/SoundCues/NodeReference/SoundCueReference.KOR.udn @@ -1,9 +1,13 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429236 Availability: Public Title: 사운드큐 참고서 Crumbs: %ROOT%, Engine, Engine/Audio Description:사운드큐와 그 프로퍼티에서 사용할 수 있는 노드에 대한 참고서입니다. version: 4.9 +Parent:Engine/Audio +type:reference +order:6 + [TOC (start:2)] diff --git a/Engine/Documentation/Source/Engine/Audio/WAV/WAV.INT.udn b/Engine/Documentation/Source/Engine/Audio/WAV/WAV.INT.udn index a6d9aecabba0..ee2a81b3d27e 100644 --- a/Engine/Documentation/Source/Engine/Audio/WAV/WAV.INT.udn +++ b/Engine/Documentation/Source/Engine/Audio/WAV/WAV.INT.udn @@ -3,45 +3,10 @@ Title: Audio Files Crumbs: %ROOT%, Engine, Engine/Audio Description:The basic requirements for getting sound files into Unreal Engine 4. version: 4.9 +parent:Engine/Audio +type:reference +order:3 -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Audio/WAV:title%](Engine/Audio/audio_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/audio_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Audio/WAV:title% - [/PARAM] - [PARAM:description] - %Engine/Audio/WAV:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Audio/WAV] - [/PARAM] -[/OBJECT] -[/VAR] -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Audio/WAV:title%](Engine/Audio/audio_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/audio_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Audio/WAV:title% - [/PARAM] - [PARAM:description] - %Engine/Audio/WAV:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Audio/WAV] - [/PARAM] -[/OBJECT] -[/VAR] [REGION:banner] ![Audio](audio_landing_banner.png) diff --git a/Engine/Documentation/Source/Engine/Audio/WAV/WAV.JPN.udn b/Engine/Documentation/Source/Engine/Audio/WAV/WAV.JPN.udn index 913073e8c324..083aa38f21ed 100644 --- a/Engine/Documentation/Source/Engine/Audio/WAV/WAV.JPN.udn +++ b/Engine/Documentation/Source/Engine/Audio/WAV/WAV.JPN.udn @@ -1,48 +1,13 @@ -INTSourceChangelist:2895618 +INTSourceChangelist:3429236 Availability:Public Title:オーディオ ファイル Crumbs: %ROOT%, Engine, Engine/Audio Description:サウンド ファイルをアンリアル エンジン 4 に取り込むための基本要件。 version:4.9 +parent:Engine/Audio +type:reference +order:3 -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Audio/WAV:title%](Engine/Audio/audio_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/audio_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Audio/WAV:title% - [/PARAM] - [PARAM:description] - %Engine/Audio/WAV:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Audio/WAV] - [/PARAM] -[/OBJECT] -[/VAR] -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Audio/WAV:title%](Engine/Audio/audio_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/audio_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Audio/WAV:title% - [/PARAM] - [PARAM:description] - %Engine/Audio/WAV:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Audio/WAV] - [/PARAM] -[/OBJECT] -[/VAR] [REGION:banner] ![Audio](audio_landing_banner.png) @@ -55,7 +20,7 @@ version:4.9 ![](WAV_TitleIcon.png)(w:200 convert:false) [/PARAM] [PARAM:description] - アンリアル エンジン 4 (UE4) のオーディオ システムには、ゲーム内のサウンドを望ましいものにするツールと機能があります。これはすべてオーディオ ソース ファイルから始まります。Mono またはステレオ ファイルとして、UE4 に迅速にインポートし、作品をさらに生き生きとしたものにします。以下は、オーディオ コンテンツの基本要件とクイック インポート ガイドです。 + アンリアル エンジン 4 (UE4) のオーディオ システムには、ゲーム内のサウンドを望ましいものにするツールと機能があります。これはすべてオーディオ ソース ファイルから始まります。Mono またはステレオ ファイルとして、UE4 に迅速にインポートし、作品をさらに生き生きとしたものにします。以下はオーディオ コンテンツの基本要件とインポートのクイック ガイドです。 [/PARAM] [/OBJECT] @@ -66,17 +31,17 @@ version:4.9 現在のエンジンは、任意のサンプルレートによる非圧縮のリトルエンディアン 16 ビット wave ファイルのインポートをサポートしています (ただし、44100 Hz または22050 Hz のサンプルレートを推奨)。 | --- | --- | -| 仕様| PCM、ADPCM、DVI ADPCM | -| フォーマット | .WAV | -| ビットレート | 16 | +| 規格 | PCM, ADPCM, DVI ADPCM | +| 形式 | .wav | +| ビット レート | 16 | | スピーカー チャンネル | Mono、Stereo、2.1、4.1、 5.1、6.1、 7.1 | -標準のサウンド ファクトリでインポートすると、再生のためのサウンドキューによって参照可能なシンプルなサウンドノード ウェーブを生み出します。これらのサウンドは、モノラルあるいはステレオのいずれかです。特別な命名規則でインポートすると、マルチチャンネル (例、5.1 など) サウンドが可能となります。すべてのプラットフォームで 8 チャンネルまでのサウンドの圧縮が可能ですが、これらを効率的に再生できるプラットフォームは限られます。パッケージの保存プロセスでは、プラットフォームのネイティブのフォーマットに変換するために必要なすべての作業を行います。スピーカーの厳密なマッピングはないため、チャンネルの番号により、どのチャンネルがどのスピーカーで再生されるかが推測されます (下の表を参照)。 +標準のサウンド ファクトリでインポートすると、再生のためのサウンドキューによって参照可能なシンプルなサウンドノード ウェーブを生み出します。こうしたサウンドは Mono または Stereo になります。特別な命名規則でインポートすると、マルチチャンネル (例、5.1 など) サウンドが可能となります。すべてのプラットフォームで 8 チャンネルまでのサウンドの圧縮が可能ですが、これらを効率的に再生できるプラットフォームは限られます。パッケージの保存プロセスでは、プラットフォームのネイティブのフォーマットに変換するために必要なすべての作業を行います。スピーカーの厳密なマッピングはないため、チャンネルの番号により、どのチャンネルがどのスピーカーで再生されるかが推測されます (下の表を参照)。 [EXCERPT:multiChannelExtensionTable] [REGION:raw] -| | Extension | 4.0 | 5.1 | 6.1 | 7.1 | +| | 拡張子 | 4.0 | 5.1 | 6.1 | 7.1 | | --- | --- | --- | --- | --- | --- | | **FrontLeft** | _fl | ✓ | ✓ | ✓ | ✓ | | **FrontRight** | _fr | ✓ | ✓ | ✓ | ✓ | @@ -93,7 +58,7 @@ version:4.9 -圧縮設定を微調整することにより、すべてのプラットフォームに対して同品質を保つことができます。数多くのサウンドをテストした結果、弊社のミュージシャンは 40 のXMA 品質が0.15 の ogg vorbis 品質と同等であると判断しました。 +圧縮設定を微調整することにより、すべてのプラットフォームに対して同品質を保つことができます。多くのサウンドをテスト後、弊社の音楽担当が XMA 品質の 40 が Ogg Vorbis 品質の 0.15 と同等であると判断しました。 ### 単一ファイルのインポート -**コンテンツ ブラウザ** から以下の操作を行います。 +**コンテンツ ブラウザ** で以下の操作を行います。 1. コンテンツ ブラウザで **[Import (インポート)]** ボタンをクリックします (以下の図参照)。 ![](ImportButton_UI.png) -1. インポートする「.WAV」ファイルを選択します。 +1. インポートする WAV ファイルを選択します。 -もしくは、 +または -1. Windows のファイル エクスプローラ ウィンドウからサウンド ファイルを選択します。 -1. ファイルをクリックして、UE4 の **コンテンツ ブラウザ** へドラッグします。 +1. Windows のファイル エクスプローラー ウィンドウからサウンド ファイルを選択します。 +1. ファイルをクリックして、**コンテンツ ブラウザ** へドラッグします。 -### マルチチャンネルのインポート +### マルチチャンネル インポート -**コンテンツ ブラウザ** から以下の操作を行います。 +**コンテンツ ブラウザ** で以下の操作を行います。 1. コンテンツ ブラウザで **[Import (インポート)]** ボタンをクリックします (以下の図参照)。 ![](ImportButton_UI.png) -1. 適切な命名規則が設けられたファイルを選択します。これらのファイルは次のようなサウンドアセットになります。"Surround_fl.wav"、 "Surround_fr.wav"、 "Surround_sl.wav"、 "Surround_sr.wav" -1. 「Surround」と呼ばれる 4 つのチャンネルアセットを作成します。 +1. 適切な命名規則が設けられたファイルを選択します。これらのファイルは次のようなサウンドアセットになります。"Surround_fl.wav", "Surround_fr.wav", "Surround_sl.wav", "Surround_sr.wav". +1. "Surround" と呼ばれる 4 チャンネル アセットを作成します。 -もしくは、 +または 1. Windows のファイル エクスプローラ ウィンドウからすべてのサウンドファイルを選択します。 -1. ファイルをクリックして、UE4 の **コンテンツ ブラウザ** へドラッグします。 +1. ファイルをクリックして、**コンテンツ ブラウザ** へドラッグします。 [/EXCERPT:wav01] diff --git a/Engine/Documentation/Source/Engine/Audio/WAV/WAV.KOR.udn b/Engine/Documentation/Source/Engine/Audio/WAV/WAV.KOR.udn index 3e05676d0aa0..3605caceb828 100644 --- a/Engine/Documentation/Source/Engine/Audio/WAV/WAV.KOR.udn +++ b/Engine/Documentation/Source/Engine/Audio/WAV/WAV.KOR.udn @@ -1,51 +1,16 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429236 Availability: Public Title: 오디오 파일 Crumbs: %ROOT%, Engine, Engine/Audio Description:언리얼 엔진 4 에 사운드 파일을 들여오기 위한 기본 요건입니다. version: 4.9 +parent:Engine/Audio +type:reference +order:3 -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Audio/WAV:title%](Engine/Audio/audio_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/audio_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Audio/WAV:title% - [/PARAM] - [PARAM:description] - %Engine/Audio/WAV:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Audio/WAV] - [/PARAM] -[/OBJECT] -[/VAR] -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Audio/WAV:title%](Engine/Audio/audio_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/audio_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Audio/WAV:title% - [/PARAM] - [PARAM:description] - %Engine/Audio/WAV:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Audio/WAV] - [/PARAM] -[/OBJECT] -[/VAR] [REGION:banner] -![Audio](audio_landing_banner.png) +![오디오](audio_landing_banner.png) [/REGION] [TOC (start:2 end:3)] diff --git a/Engine/Documentation/Source/Engine/Basics/AssetsAndPackages/AssetsAndPackages.INT.udn b/Engine/Documentation/Source/Engine/Basics/AssetsAndPackages/AssetsAndPackages.INT.udn index 8839d21eb5d3..676b867980f8 100644 --- a/Engine/Documentation/Source/Engine/Basics/AssetsAndPackages/AssetsAndPackages.INT.udn +++ b/Engine/Documentation/Source/Engine/Basics/AssetsAndPackages/AssetsAndPackages.INT.udn @@ -3,26 +3,11 @@ Title: Assets and Packages Crumbs: %ROOT%, Engine Description:Overview of the asset and package system used in Unreal Engine 4. version: 4.9 +topic-image:Engine/Content/content_topic.png +Parent:Engine +type:overview +order:22 -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Basics/AssetsAndPackages:title%](Engine/Content/content_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Basics/AssetsAndPackages:title% - [/PARAM] - [PARAM:description] - %Engine/Basics/AssetsAndPackages:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Basics/AssetsAndPackages] - [/PARAM] -[/OBJECT] -[/VAR] [TOC (start:2 end:3)] diff --git a/Engine/Documentation/Source/Engine/Basics/AssetsAndPackages/AssetsAndPackages.KOR.udn b/Engine/Documentation/Source/Engine/Basics/AssetsAndPackages/AssetsAndPackages.KOR.udn index e8665f11e6ca..adcd5f6f4004 100644 --- a/Engine/Documentation/Source/Engine/Basics/AssetsAndPackages/AssetsAndPackages.KOR.udn +++ b/Engine/Documentation/Source/Engine/Basics/AssetsAndPackages/AssetsAndPackages.KOR.udn @@ -1,29 +1,14 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3454520 Availability:Public Title: 애셋과 패키지 Crumbs: %ROOT%, Engine Description:언리얼 엔진 4 에 사용되는 애셋과 패키지 시스템에 대한 개요입니다. version: 4.9 +topic-image:Engine/Content/content_topic.png +Parent:Engine +type:overview +order:22 -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Basics/AssetsAndPackages:title%](Engine/Content/content_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Basics/AssetsAndPackages:title% - [/PARAM] - [PARAM:description] - %Engine/Basics/AssetsAndPackages:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Basics/AssetsAndPackages] - [/PARAM] -[/OBJECT] -[/VAR] [TOC (start:2 end:3)] diff --git a/Engine/Documentation/Source/Engine/Basics/CoordinateSpace/CoordinateSpace.INT.udn b/Engine/Documentation/Source/Engine/Basics/CoordinateSpace/CoordinateSpace.INT.udn index 8847651c53eb..e31c499e86c1 100644 --- a/Engine/Documentation/Source/Engine/Basics/CoordinateSpace/CoordinateSpace.INT.udn +++ b/Engine/Documentation/Source/Engine/Basics/CoordinateSpace/CoordinateSpace.INT.udn @@ -3,6 +3,9 @@ Title:Coordinate Space Terminology Crumbs:%ROOT%, Programming, Programming/Rendering Description:Explanations of the various coordinate spaces used in Unreal Engine. version: 4.9 +Parent:Engine +type:overview +order:23 ## Spaces diff --git a/Engine/Documentation/Source/Engine/Basics/CoordinateSpace/CoordinateSpace.KOR.udn b/Engine/Documentation/Source/Engine/Basics/CoordinateSpace/CoordinateSpace.KOR.udn index 6434e481c1ea..83ba53fdf74e 100644 --- a/Engine/Documentation/Source/Engine/Basics/CoordinateSpace/CoordinateSpace.KOR.udn +++ b/Engine/Documentation/Source/Engine/Basics/CoordinateSpace/CoordinateSpace.KOR.udn @@ -1,9 +1,12 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3454520 Availability:Public Title:좌표계 용어집 Crumbs:%ROOT%, Programming, Programming/Rendering Description:언리얼 엔진에서 사용되는 여러 좌표계에 대한 설명입니다. version: 4.9 +Parent:Engine +type:overview +order:23 ## 스페이스 diff --git a/Engine/Documentation/Source/Engine/Basics/DerivedDataCache/DerivedDataCache.INT.udn b/Engine/Documentation/Source/Engine/Basics/DerivedDataCache/DerivedDataCache.INT.udn index 8d6cf7fa5da0..9e911692b946 100644 --- a/Engine/Documentation/Source/Engine/Basics/DerivedDataCache/DerivedDataCache.INT.udn +++ b/Engine/Documentation/Source/Engine/Basics/DerivedDataCache/DerivedDataCache.INT.udn @@ -3,6 +3,9 @@ Title:Derived Data Cache Crumbs:%ROOT%, Engine Description: Overview of the Derived Data Cache and the storage of assets in formats used by UE4 and its target platforms. version: 4.9 +Parent:Engine +type:overview +order:24 The **Derived Data Cache** (DDC) stores versions of assets in the formats used by the engine and its target platforms, as opposed to the source formats artists create that are imported into the editor diff --git a/Engine/Documentation/Source/Engine/Basics/DerivedDataCache/DerivedDataCache.KOR.udn b/Engine/Documentation/Source/Engine/Basics/DerivedDataCache/DerivedDataCache.KOR.udn index d64a178656e3..c18228dccd51 100644 --- a/Engine/Documentation/Source/Engine/Basics/DerivedDataCache/DerivedDataCache.KOR.udn +++ b/Engine/Documentation/Source/Engine/Basics/DerivedDataCache/DerivedDataCache.KOR.udn @@ -1,9 +1,12 @@ -INTSourceChangelist:3343618 +INTSourceChangelist:3454520 Availability:Public Title:파생 데이터 캐시 Crumbs:%ROOT%, Engine Description: Derived Data Cache 및 UE4 와 그 타겟 플랫폼에서 사용되는 포맷의 애셋 저장에 대한 개요입니다. version: 4.9 +Parent:Engine +type:overview +order:24 **Derived Data Cache** (DDC, 파생 데이터 캐시)는 여러 버전의 애셋을 엔진과 그 타겟 플랫폼에서 사용되는 포맷으로 저장하는 기능입니다. 아티스트가 만들어서 에디터로 임포트하여 .uasset 파일로 @@ -25,7 +28,7 @@ version: 4.9 것이 더 빠르기에 시간 낭비가 되고 맙니다. [/REGION] -공유 DDC 구성을 위해서는, 게임의 DefaultEngine.ini 에서 (에픽 게임스 런처의 바이너리 버전을 사용하는지 소스 컴파일 버전을 사용하는지에 따라) `[InstalledDerivedDataBackendGraph]` 또는 `[DerivedDataBackendGraph]` 섹션을 선언하여 +공유 DDC 구성을 위해서는, 게임의 DefaultEngine.ini 에서 (에픽 게임즈 런처의 바이너리 버전을 사용하는지 소스 컴파일 버전을 사용하는지에 따라) `[InstalledDerivedDataBackendGraph]` 또는 `[DerivedDataBackendGraph]` 섹션을 선언하여 그에 대한 경로를 덮어씁니다. 이 섹션은 원래 BaseEngine.ini 에 선언되며, 기본적으로 에픽의 내부 DDC 공유 경로로 설정되어 있습니다. 다른 네트워크 공유 경로로 설정하려면 이 섹션을 다시 선언하고 경로를 (Path=\\mystudio.net\DDC 식으로) 바꿔 주어야 합니다. diff --git a/Engine/Documentation/Source/Engine/Basics/DirectoryStructure/DirectoryStructure.INT.udn b/Engine/Documentation/Source/Engine/Basics/DirectoryStructure/DirectoryStructure.INT.udn index 7d1fc80de7dd..e7cfd5ac2734 100644 --- a/Engine/Documentation/Source/Engine/Basics/DirectoryStructure/DirectoryStructure.INT.udn +++ b/Engine/Documentation/Source/Engine/Basics/DirectoryStructure/DirectoryStructure.INT.udn @@ -3,6 +3,9 @@ Title:Directory Structure Crumbs: %ROOT%, Engine Description:Overview of the directories that make up the engine and game projects. version: 4.9 +Parent:Engine +type:overview +order:25 [TOC(start:2)] diff --git a/Engine/Documentation/Source/Engine/Basics/DirectoryStructure/DirectoryStructure.KOR.udn b/Engine/Documentation/Source/Engine/Basics/DirectoryStructure/DirectoryStructure.KOR.udn index 4b2d88c54e88..ae25db3903d7 100644 --- a/Engine/Documentation/Source/Engine/Basics/DirectoryStructure/DirectoryStructure.KOR.udn +++ b/Engine/Documentation/Source/Engine/Basics/DirectoryStructure/DirectoryStructure.KOR.udn @@ -1,9 +1,12 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3454520 Availability:Public Title:디렉토리 구조 Crumbs: %ROOT%, Engine Description:엔진과 게임 프로젝트를 구성하는 디렉토리 구조에 대한 개요입니다. version: 4.9 +Parent:Engine +type:overview +order:25 [TOC(start:2)] diff --git a/Engine/Documentation/Source/Engine/Basics/Distributions/Distributions.INT.udn b/Engine/Documentation/Source/Engine/Basics/Distributions/Distributions.INT.udn index e2d5363308a9..7fc0e58e0909 100644 --- a/Engine/Documentation/Source/Engine/Basics/Distributions/Distributions.INT.udn +++ b/Engine/Documentation/Source/Engine/Basics/Distributions/Distributions.INT.udn @@ -3,12 +3,13 @@ Title: Distributions Crumbs: %ROOT%, Engine Description:Data types that provide flexibility by allowing for constant values, random values within a range, values interpolated along a curve, and values driven by parameters. version: 4.9 +Parent:Engine +type:overview +order:26 [TOC (start:2 end:3)] - - **Distributions** are a group of data types that provide flexibility by allowing for constant values, random values within a range, values interpolated along a curve, and values driven by parameters. These are generally used in properties of Particle Systems and nodes within SoundCues. [REGION:note] diff --git a/Engine/Documentation/Source/Engine/Basics/Distributions/Distributions.KOR.udn b/Engine/Documentation/Source/Engine/Basics/Distributions/Distributions.KOR.udn index d3288683bc43..e8b5bef4f756 100644 --- a/Engine/Documentation/Source/Engine/Basics/Distributions/Distributions.KOR.udn +++ b/Engine/Documentation/Source/Engine/Basics/Distributions/Distributions.KOR.udn @@ -1,15 +1,16 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3454520 Availability: Public Title: 분포 (Distributions) Crumbs: %ROOT%, Engine Description:상수값, 일정 범위 내 난수값, 곡선을 따라 보간되는 값, 파라미터로 구동되는 값 등의 유연성이 제공되는 데이터 유형입니다. version: 4.9 +Parent:Engine +type:overview +order:26 [TOC (start:2 end:3)] - - 분포(distribution)란 상수 값, 범위 내 임의의 값, 커브를 따라 보간되는 값, 파라미터에 물려주는 값 등 데이터 유연함을 더해주는 유형 그룹을 말합니다. 보통 파티클 시스템과 사운드큐에서 노드의 프로퍼티에 사용됩니다. [REGION:note] diff --git a/Engine/Documentation/Source/Engine/Basics/Projects/Packaging/PackagingProjects.INT.udn b/Engine/Documentation/Source/Engine/Basics/Projects/Packaging/PackagingProjects.INT.udn index 3707a5cb0ecc..a2ca45d89063 100644 --- a/Engine/Documentation/Source/Engine/Basics/Projects/Packaging/PackagingProjects.INT.udn +++ b/Engine/Documentation/Source/Engine/Basics/Projects/Packaging/PackagingProjects.INT.udn @@ -36,13 +36,37 @@ To set the Game Default Map click on **Edit > Project Settings > Maps & Modes** ![](Project_Settings_MapsNModes.png) - - ## Creating Packages To package a project for a specific platform, click on **File > Package Project > [PlatformName]** in the Editor's main menu: +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] ![](packaging_menu.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](packaging_menu_Mac.png) +[/PARAM] +[/OBJECT] You will be presented with a dialog for selecting the target directory. If packaging completes successfully, this directory will then contain the packaged project. @@ -122,9 +146,48 @@ Clicking **File > Package Project > Packaging Settings...** or **Edit > Project [/PUBLISH:Licensee] - ## Content Cooking As a developer, when iterating over new or modified game content, you may not always want to go through the lengthy process of packaging everything into the staging directory and then running it from there. It is therefore possible to only cook the content for a particular target platform without packaging it by clicking **File > Cook Content > [PlatformName]**. Please note that this feature will update the content in your project's local developer workspace, and it will not copy out any assets to the staging directory. You can run your game directly from your local developer workspace for fast iteration. + + +## Optimizing Load Times + +Short loading times are essential for open-world games, but are valuable in every type of game. The Unreal Engine provides several methods to optimize your project's loading time during the packaging process. Here are some recommended practices to descrease the loading time in your games. For information on how to package your project, see the [](Engine/Deployment) section. + +### Using the Event Driven Loader (EDL) and the Asyncronous Loading Thread (ALT) + +* The **Asynchronous Loading Thread** (ALT) is turned off by default, but can be turned on in the Project Settings menu under the Engine - Streaming section. For modified engines, some tweaks may be needed, but in general, ALT should double the speed of loading, including games with "up-front" loading times and games that constantly stream data. The ALT works by running serialization and post-loading code concurrently on two separate threads, and as a result, it adds the requirement that `UObject` class constructors, `PostInitProperties` functions, and `Serialize` functions in your game code must be thread-safe. When activated, ALT doubles loading speed. For further information about using asynchronous loading methods (in C++), see the [](Programming\Assets\AsyncLoading) page. + +* The **Event-Driven Loader** is activated by default, but can be deactivated in the Project Settings menu under the Engine - Streaming section. For most projects, the EDL will cut load times in half. The EDL is stable and can be back-ported to older versions of the Unreal Engine, or can be tweaked for modified or customized engine versions. + +![](EngineStreamingSettings.png) + +### Compress your .pak file. + +* To use .pak file compression in your project, open Project Settings and find the Packaging section. In that section, open the advanced part of the Packaging heading and check the box labeled "Create compressed cooked packages" that appears. + +* Most platforms don't provide automatic compression, and compressing your .pak files will generally decrease loading times, but there are a few special cases to consider: + +| Platform | Recommendation | +| -- | -- | +| Sony PlayStation 4 | Compressing the .pak file will be redundant with the compression automatically applied to every PlayStation 4 title, and will actually result in longer load times without decreased file size. It is therefore not advised to compress .pak files for PlayStation 4 releases. | +| Nintendo Switch | Compressed .pak files on the Switch will sometimes load more slowly due to the processor time it takes to decompress the data, but will sometimes load faster from compressed files. The recommendation for Switch titles is to test out the load times with each individual title and make a case-by-case decision. | +| Microsoft XBoxOne | Files on this platform are compressed automatically, but the system will recognize that a compressed .pak file does not benefit from additional compression. As a result, the system will leave the compressed .pak file as-is, instead of applying compression to it. Ultimately, compressing the .pak file for an XBoxOne release has no significant impact on the final product. | +| Steam | Steam compresses files while they are being downloaded by users, so initial download times will not be affected by your game's .pak file being compressed. However, Steam's differential patch system will generally work better with uncompressed files. Compressed .pak files save space on the customer's system, but will take longer to download when patching. | + +![Project Settings - Compress Pak option](Project_Settings_PakCompression.png) +[REGION:caption]Check this box to enable compression in your .pak files.[/REGION] + +### Order your .pak file. + +* A well-ordered .pak file is critical to reducing load times. To assist with ordering your .pak file optimally, the Unreal Engine provides a set of tools to discover the order in which your data assets are needed, and build faster-loading packages. Conceptually, this process is similar to profile-guided optimization. Follow this method to order our .pak file: + +1. Build and run the packaged game with the "-fileopenlog" command-line option, which causes the engine to log the order in which it opens files. +1. Exercise all major areas of the game. Load every level, every playable character, every weapon, every vehicle, and so on. Once everything has been loaded, quit the game. +1. There will be a file in your deployed game called `GameOpenOrder.log` that contains the information needed to optimize your .pak file order. For example, on Windows builds, the file will be found in `WindowsNoEditor/(YourGame)/Build/WindowsNoEditor/FileOpenOrder/`. Copy this file to your development directory under the `/Build/WindowsNoEditor/FileOpenOrder/` path. +1. With the log file in place, rebuild the .pak file. This and all future .pak files produced will use the file order indicated in the log file. + +* In a production environment, the log file should be checked into source control and updated periodically with the results of new "-fileopenlog" runs, including a final run when the game is ready to ship. diff --git a/Engine/Documentation/Source/Engine/Basics/Projects/Packaging/PackagingProjects.JPN.udn b/Engine/Documentation/Source/Engine/Basics/Projects/Packaging/PackagingProjects.JPN.udn index 79140e60d50f..b21a0917feee 100644 --- a/Engine/Documentation/Source/Engine/Basics/Projects/Packaging/PackagingProjects.JPN.udn +++ b/Engine/Documentation/Source/Engine/Basics/Projects/Packaging/PackagingProjects.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3336763 +INTSourceChangelist:3481084 Availability:Public Title:プロジェクトのパッケージ化 Crumbs: @@ -14,7 +14,7 @@ parent:Engine/Basics/Projects アンリアル プロジェクトをユーザーへ配布する前に適切にパッケージ化処理をしなくてはいけません。パッケージ化処理することで全コードとコンテンツを最新に保ち、対象プラットフォームで実行可能な適切なフォーマットになるようにします。 [/EXCERPT:Intro] -パッケージ化処理中は複数の手順を実行します。プロジェクトがカスタム ソースコードで記述されている場合、まず最初にコードをコンパイルします。そして、全ての必須コンテンツを対象プラットフォームで利用できるフォーマットに変換 (いわゆるコンテンツのクック) しなくてはいけません。それが終わるとコンパイル済みのコードとクックされたコンテンツは、Windows インストーラーのような配布可能なファイル一式へまとめられます。 +パッケージ化処理中は複数のステップが実行されます。プロジェクトがカスタム ソースコードで記述されている場合、まず最初にこのコードをコンパイルします。そして、全ての必須コンテンツを対象プラットフォームで利用できるフォーマットに変換 (いわゆるコンテンツのクック) しなくてはいけません。それが終わるとコンパイル済みのコードとクックされたコンテンツは、Windows インストーラーのような配布可能なファイル一式へまとめられます。 メインの **[File]** メニューに、サブメニューを含んだ **[Package Project]** オプションがあります。サブメニューには、パッケージ化処理の対象プラットフォームがすべて表示されます。パッケージ化処理の目的は、単一マップではなくゲーム全体をテストすること、または @@ -22,7 +22,7 @@ parent:Engine/Basics/Projects Android プラットフォームに関しては、複数の選択肢があります。詳細は、Android Texture Formats のページを参照してください。 -パッケージ化処理前に設定する **Advanced** オプションもいくつかあります。 +パッケージ化処理前に設定する **[Advanced]** オプションもいくつかあります。 プラットフォームを選択すると、ゲームにコードが含まれる場合、エディタはゲームをコンパイル、ゲームデータ全てをクック、そしてコンテンツをパッケージ化処理します。プロジェクトに Starter Content が含まれると処理速度が低下します。 もしくは、たくさんのテスト / 仮のコンテンツやマップを作成した場合も処理速度が低下します。 @@ -30,18 +30,16 @@ Android プラットフォームに関しては、複数の選択肢がありま ## ゲームのデフォルト マップの設定 -ゲームをパッケージ化する前に、まずパッケージ化されたゲームの開始時に読み込まれる **Game Default Map** を設定する必要があります。マップを設定せずに、ブランク オブジェクトを使用している場合は、パッケージ化されたゲームの開始時に黒い画面しか表示されません。First Person や Third Person などのテンプレート マップのひとつを使用した場合は、開始時にマップが読み込まれます。 +ゲームをパッケージ化する前に、まずパッケージ化されたゲームの開始時に読み込まれる **Game Default Map** を設定する必要があります。マップを設定せずに、空のプロジェクトを使用している場合は、パッケージ化されたゲームの開始時に黒い画面しか表示されません。First Person や Third Person などのテンプレート マップのひとつを使用した場合は、開始時にマップが読み込まれます。 ゲームのデフォルト マップを設定するには、エディタのメイン メニューで **[Edit > Project Settings > Maps & Modes]** の順に選択してクリックします。 ![](Project_Settings_MapsNModes.png) - - ## パッケージの作成 -特定のプラットフォームを対象にプロジェクトをパッケージ化するには、エディタのメインメニューで **[File > Package Project]** の順に選択してプラットフォーム名をクリックします。 +特定のプラットフォームを対象にプロジェクトをパッケージ化するには、エディタのメインメニューで **[File > Package Project > プラットフォーム名]** の順にクリックします。 ![](packaging_menu.png) @@ -51,7 +49,7 @@ Android プラットフォームに関しては、複数の選択肢がありま ![](progress.png) -このステータス インジケータには現在アクティブなパッケージ化処理を中止する **[Cancel]** ボタンがあります。また **[Show Log]** リンクをクリックすることにより、拡張した出力ログ情報を表示させることもできます。パッケージ化処理が成功しなかった場合など、問題を突き止める際に出力ログは有益です。 +このステータス インジケータには現在アクティブなパッケージ化処理を中止する **[Cancel]** ボタンがあります。また **[Show Log]** リンクをクリックすることにより、拡張した出力ログ情報を表示させることもできます。この出力ログの情報は、パッケージ処理が成功しなかった場合などの原因調査に役立ちます。 ![](log.png) @@ -67,7 +65,7 @@ Android プラットフォームに関しては、複数の選択肢がありま パッケージ化処理を行う時には、出力用のディレクトリを選択しました。パッケージ化処理が正常に完了すると、パッケージ化されたゲームはプラットフォーム専用のサブディレクトリに入ります。例えば、 TappyChicken/Final を選択した場合、iOS ビルドは TappyChicken/Final/IOS に、 Android ビルドは TappyChicken/Final/Android に入ります。選択したサブディレクトリへ移動すると、パッケージ化済みのゲームがプラットフォームに適したフォーマットで見つかります。 -Android の場合、「.apk」、「.obb」、「.bat」のファイルがあります (デバイスにゲームをインストールするために「.bat」ファイルを実行します)。IOS プラットフォームの場合、「.ipa」ファイルがあります。このファイルは、iTunes または Xcode 経由でインストールします。 +Android の場合、「.apk」、「.obb」、「.bat」のファイルがあります (デバイスにゲームをインストールするには「.bat」ファイルを実行します)。IOS プラットフォームの場合、「.ipa」ファイルがあります。このファイルは、iTunes または Xcode 経由でインストールします。 作成されるファイルの数や種類は対象プラットフォームによって異なります。以下の画像は Windows 向けプロジェクトの出力例です。 ![](results.png) @@ -109,12 +107,12 @@ Android の場合、.apk を署名するキーを作成し、「SigningConfig.xm | オプション | 説明 | | ------ | ----------- | -| Build Configuration | コードベースのプロジェクトをコンパイルするビルドのコンフィギュレーションです。デバッグ作業には [Debug] を選択、他の大半のプロジェクトは最小限のデバッグ サポートを選択、より優れたパフォーマンスには [Development] を選択、そして最終出荷用ビルドには [Shipping] を選択します。 | +| Build Configuration | コードベースのプロジェクトをコンパイルするビルドのコンフィギュレーションです。デバッグ作業には [Debug] を選択、他の大半のプロジェクトで最小限のデバッグ サポートで、より優れたパフォーマンスには [Development] を選択、そして最終出荷用ビルドには [Shipping] を選択します。 | | Staging Directory | パッケージ化したビルドを格納するディレクトリです。ターゲット ディレクトリの選択時に別のディレクトリを選択すると、このオプションは自動的に更新されます。 | -| Full Rebuild |全コードをコンパイルするか否かを設定します。無効な場合、修正されたコードのみがコンパイルされます。これによりパッケージ処理が迅速化する場合があります。出荷ビルドは、ビルド漏れや古いコンテンツを含まないためにも常にフルの再ビルドを実行してください。このオプションはデフォルト設定で有効です。 | +| Full Rebuild | 全コードをコンパイルするか否かを設定します。無効な場合、修正されたコードのみがコンパイルされます。これによりパッケージ処理が迅速化する場合があります。出荷ビルドは、ビルド漏れや古いコンテンツを含まないためにも常にフルの再ビルドを実行してください。このオプションはデフォルト設定で有効です。 | | Use Pak File | 個々のファイルまたは単一パッケージとしてプロジェクトのアセットをパッケージ化するか否かを設定します。有効な場合、各ファイル全てをコピーする代わりに、全アセットを単一「.pak」ファイルに格納します。プロジェクトにたくさんのアセットファイルがある場合、「.pak」ファイルを使用した方が配布が容易になる場合があります。多くのファイルを移動する必要がないからです。このオプションはデフォルト設定で有効です。 | | Generate Chunks | インストールのストリーミングで使用可能な .pak ファイルのチャンクを生成するかどうかを設定します。| -| Build Http Chunk Install Data | HTTP チャンク インストーラ向けにデータを生成するかどうかを設定します。これにより、ランタイムにインストールするようにウェブサーバー上にデータをホストすることができます。 | +| Build Http Chunk Install Data | HTTP チャンク インストーラ向けにデータを生成するかどうかを設定します。これにより、ランタイムにインストールするようにウェブ サーバー上にデータをホストすることができます。 | | Http Chunk Install Data Directory | データをビルドするディレクトリです。 | | Http Chunk Install Data Version | HTTP チャンク インストール データのバージョン名です。 | | Include Prerequisites | 再配布可能なオペレーティング システムのコンポーネントなど、パッケージ化したゲームの前提条件を含むかどうかを指定します。 | @@ -123,9 +121,48 @@ Android の場合、.apk を署名するキーを作成し、「SigningConfig.xm [/PUBLISH:Licensee] - ## コンテンツのクック デベロッパーとして新規または修正したゲーム コンテンツをイタレーションする時に、まずステージン グディレクトリへ全てをパッケージ化し、その後そこから実行するという冗長な処理を行いたくない場合もあることでしょう。そのような場合、[ **File > Cook Content **] の順に選択して [プラットフォーム名] をクリックして、パッケージ化せずに特定のターゲット プラットフォームのコンテンツのみをクックすることも可能です。 この機能は、プロジェクトのローカルのデベロッパーのワークスペースにあるコンテンツを更新し、ステージング ディレクトリへアセットをコピーしません。イタレーションを迅速に行うために、ローカルのデベロッパー ワークスペースから直接ゲームを実行することができます。 + + +## ロード時間を最適化する + +オープン ワールドのゲームではロード時間が短いことが不可欠ですが、あらゆるタイプのゲームでもこれは価値があります。アンリアル エンジンでは、パッケージ化処理中のプロジェクトのロード時間を最適化する方法がいくつかあります。ゲームのロード時間を短縮する推奨方法を以下に示します。プロジェクトのパッケージ方法については、[](Engine/Deployment) セクションをご覧ください。 + +### Event Driven Loader (EDL) と Asyncronous Loading Thread (ALT) を使用する + +* **Asynchronous Loading Thread** (ALT) はデフォルトでオフになっていますが、 [Project Settings] メニューの [Engine - Streaming] セクションでオンにすることができます。修正したエンジンでは一部微調整が必要になるかもしれませんが、一般的に ALT はロードの速度を 2 倍速くします。これには事前のロード時間があるゲームと絶えずデータをストリーミングするゲームを含みます。ALT はシリアライズとポスト ローディング コードを 2 つの別個のスレッドで同時に実行することで機能します。その結果、ゲーム コード内の `UObject` クラス コンストラクタ、 `PostInitProperties` 関数、および `Serialize` 関数がスレッドセーフでなければならないという要件が加わります。アクティベートすると、ALT によってローディング速度が 2 倍速くなります。非同期ローディング (C++) の使用に関する情報は、[](Programming\Assets\AsyncLoading) のページをご覧ください。 + +* **Event-Driven Loader** はデフォルトでオンになっていますが、 [Project Settings] メニューの [Engine - Streaming] セクションでオフにすることができます。ほとんどのプロジェクトで EDL はロード時間を半分に短縮します。EDL は安定していてアンリアル エンジンの古いバージョンに移植することができます。または改良、カスタマイズしたエンジン バージョン向けに微調整することができます。 + +![](EngineStreamingSettings.png) + +### .pak ファイルの圧縮 + +* プロジェクトで .pak ファイルの圧縮を使うには、 [Project Settings (プロジェクト設定)] を開いて [Packaging (パッケージ化)] セクションを探します。このセクションで、 [Packaging] の見出しの advanced (詳細) 部分を開いて、表示される [Create compressed cooked packages (圧縮されたクック ページの作成) ] のチェックボックスにチェックを入れます。 + +* ほとんどのプラットフォームには自動圧縮機能はなく、.pak ファイルを圧縮するとロード時間が一般的に短縮しますが、以下のように考慮すべき特殊なケースがあります。 + +| プラットフォーム | 推奨 | +| -- | -- | +| Sony PlayStation 4 | .pak ファイルを圧縮することは、PlayStation 4 のすべてのタイトルで自動的に適用される圧縮と重複し、実際にはファイル サイズは減らずにロード時間が長くなってしまいます。従って、PlayStation 4 向けのリリースでは、.pak ファイルの圧縮はお勧めしません。 | +| Nintendo Switch | Switch 上の圧縮した .pak ファイルのロードは時間がかかることがあります。これは、データ解凍に時間がかかるためですが、圧縮ファイルから高速にロードすることもあります。Switch 向けタイトルでは、個々のタイトルでロード時間をテストし、ケースバイケースで決定を下すことをお勧めします。 | +| Microsoft XBoxOne | Microsoft の XBoxOne プラットフォームのファイルは自動的に圧縮されますが、圧縮した .pak ファイルをさらに圧縮してもメリットがないことをシステムは認識します。その結果、システムは圧縮を適用するのではなく、圧縮 .pak ファイルをそのままにします。最終的に、XBoxOne リリース向けに .pak ファイルを圧縮しても、最終製品に大きな影響はありません。 | +| Steam | Steam ではユーザーがダウンロードしているときにファイルを圧縮します。そのため、ダウンロード時間は圧縮されているゲームの .pak ファイルによる影響を受けません。ただし、Steam の差分パッチ システムの方が圧縮されていないファイルではうまく機能します。圧縮 .pak ファイルはカスタマーのシステムの空間を節約しますが、パッチの場合はダウンロード時間が長くなります。 | + +![Project Settings - Compress Pak option](Project_Settings_PakCompression.png) +[REGION:caption] .pak ファイルの圧縮を有効にするには、このボックスにチェックを入れます。[/REGION] + +### .pak ファイルを順序付けする + +* .pak ファイルを適切に順序付けすることは、ロード時間を短縮するうえで重要です。.pak ファイルを最適に順序付けするために、アンリアル エンジンにはデータ アセットを必要とする順序を見つけるツール一式があり、高速にロードするパッケージをビルドします。概念上はこのプロセスはプロファイルによる最適化に似ています。.pak ファイルを順序付けするには以下の手順に従います。 + +1. パッケージ化したゲームを "-fileopenlog" コマンドライン オプションを使ってビルドし実行します。このオプションは、エンジンにファイルを開く順序を記録させます。 +1. ゲームのすべての主要エリアに対して行ないます。すべてのレベル、プレイ可能なキャラクター、武器、ビークルなどをロードします。すべてがロードされたら、ゲームを終了します。 +1. デプロイしたゲームに `GameOpenOrder.log` というファイルがあります。これには .pak ファイルの順序を最適化するために必要な情報があります。例えば、Windows のビルドでは、このファイルは `WindowsNoEditor/(YourGame)/Build/WindowsNoEditor/FileOpenOrder/` にあります。このファイルを `/Build/WindowsNoEditor/FileOpenOrder/` パスの development ディレクトリにコピーします。 +1. ログ ファイルができたら、.pak ファイルを再ビルドします。これと今後生成される.pak ファイルはログ ファイルに示されているファイルの順序を使用します。 + +* 本番環境では、ログ ファイルはソース コントロールにチェックインされ、新しい "-fileopenlog" の実行結果を使って定期的に更新されます。これには、ゲームの出荷準備が整った最終実行が含まれます。 diff --git a/Engine/Documentation/Source/Engine/Basics/Projects/Packaging/PackagingProjects.KOR.udn b/Engine/Documentation/Source/Engine/Basics/Projects/Packaging/PackagingProjects.KOR.udn index 9d084b302a9e..5cd20842cfa5 100644 --- a/Engine/Documentation/Source/Engine/Basics/Projects/Packaging/PackagingProjects.KOR.udn +++ b/Engine/Documentation/Source/Engine/Basics/Projects/Packaging/PackagingProjects.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3336763 +INTSourceChangelist:3481084 Availability:Public Title:프로젝트 패키징 Crumbs: @@ -37,13 +37,37 @@ parent:Engine/Basics/Projects ![](Project_Settings_MapsNModes.png) - - ## 패키지 만들기 프로젝트를 특정 플랫폼용 패키지로 만들려면, 에디터의 메인 메뉴에서 **파일 > 프로젝트 패키지 > [플랫폼 이름]** 을 선택합니다. +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] ![](packaging_menu.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](packaging_menu_Mac.png) +[/PARAM] +[/OBJECT] 타겟 디렉토리를 선택하라는 대화창이 뜹니다. 패키징이 성공적으로 끝나면, 그 디렉토리에 패키징된 프로젝트가 들어갑니다. @@ -123,9 +147,48 @@ iOS 에서는 애플의 개발자 웹사이트에서 배포 Certificate 와 Mobi [/PUBLISH:Licensee] - ## 콘텐츠 쿠킹 개발자로서 새 게임이나 변경된 게임에 대한 반복작업을 할 때, 모든 것을 스테이징 디렉토리에 패키징하여 넣은 다음 거기서 그것을 실행하는 지루한 프로세스 전체를 항상 반복하고 싶지는 않을 것입니다. 그래서 **파일 > 콘텐츠 쿠킹 > [플랫폼 이름]** 을 선택하면 패키징 없이 특정 타겟 플랫폼용 콘텐츠만 쿠킹하는 것도 가능합니다. 이 기능은 프로젝트의 로컬 디벨로퍼 워크스페이스에 있는 콘텐츠를 업데이트할 뿐, 스테이징 디렉토리에 애셋을 복사하지는 않는다는 점 유념해 주시기 바랍니다. 로컬 디벨로퍼 워크스페이스에서 게임을 바로 실행하여 빠른 반복작업을 할 수 있습니다. + + +## 로드 시간 최적화 + +로드 시간을 짧게 하는 것은 오픈 월드 게임에 필수지만, 어떤 게임에도 좋은 일입니다. 언리얼 엔진에서는 패키지 프로세스 도중 프로젝트 로드 시간을 최적화시키는 메소드를 다수 제공하고 있습니다. 게임 로드 시간을 줄이는 실전적인 방법을 몇 가지 소개합니다. 프로젝트 패키지를 만드는 방법에 대해서는, [](Engine/Deployment) 문서를 참고하세요. + +### 이벤트 주도형 로더 (EDL) 및 비동기 로딩 스레드 (ALT) 사용 + +* **Asynchronous Loading Thread** (ALT, 비동기 로딩 스레드)는 기본으로 꺼져있는 옵션이지만, 프로젝트 세팅 - 엔진 - Streaming (스트리밍)에서 켤 수 있습니다. 엔진에 변경을 가한 경우 약간의 미세 조정이 필요할 수 있지만, 일반적으로 ALT 는 게임의 "최초" (up-front) 로드 시간과 지속적인 데이터 스트리밍 시간을 포함한 전반적인 로드 시간을 배가시켜 줍니다. ALT 작동 방식은 시리얼라이즈와 포스트 로딩 코드를 두 개의 별도 스레드에 동시 실행시키는 방식으로 작동하므로, 그에 따라 게임 코드의 `UObject` 클래스 생성자, `PostInitProperties` 함수, `Serialize` 함수는 반드시 스레드 안전성을 확보(thread-safe)해야 합니다. 이 ALT 기능이 가동되면 로드 속도는 두 배가 됩니다. 비동기 로딩 메소드 (C++) 사용 관련 상세 정보는 [](Programming\Assets\AsyncLoading) 문서를 참고하세요. + +* **Event-Driven Loader** (이벤트 주도형 로더)는 기본적으로 켜져있지만, 프로젝트 세팅 - 엔진 - Streaming (스트리밍) 섹션에서 끌 수 있습니다. 대부분의 프로젝트의 경우 EDL 을 사용하면 로드 시간이 절반으로 줄어듭니다. EDL 은 안정적이며 언리얼 엔진 구버전에 하위 포팅, 또는 수정 및 커스터마이징된 엔진 버전에 맞게 미세 조정 가능합니다. + +![](EngineStreamingSettings.png) + +### .pak 파일 압축 + +* 프로젝트에 .pak 파일 압축을 사용하려면, 프로젝트 세팅 - Packing (패키징) 섹션을 찾습니다. 거기서 Packaging (패키징) 제목줄의 고급 옵션 부분을 열면 나타나는 Create compressed cooked packages (압축 쿠킹 패키지 생성) 옵션을 체크합니다. + +* 대부분의 플랫폼에서는 자동 압축을 제공하지 않기에, .pak 파일을 압축하면 일반적으로 로드 시간이 단축되지만, 고려해야 할 상황이 몇 가지 있습니다: + +| 플랫폼 | 추천 | +| -- | -- | +| Sony PlayStation 4 | 모든 PlayStation4 타이틀에 자동 적용되는 압축과 .pak 파일 압축은 중복되어 사실상 파일 크기가 줄어드는 혜택 없이 압축 작업만 중복하게 됩니다. 그러므로 PlayStation 4 릴리즈의 경우 .pak 파일 압축은 하지 않는 것이 좋습니다. | +| Nintendo Switch | 압축된 파일 로드가 더 빠를 수도 있지만, 데이터 압축을 푸는 데 걸리는 시간이 더 오래 걸릴 수도 있습니다. Switch 타이틀의 경우 타이틀 별로 직접 테스트해 보고 결정하는 것이 좋습니다. | +| Microsoft XBoxOne | 자동 압축되지만, 시스템에서는 압축된 .pak 파일이 추가 압축 혜택을 받지 못한다고 인식을 할 것입니다. 그에 따라 시스템에서는 압축된 .pak 파일을 다시 압축하지 않고 있는 그대로 놔둡니다. 결국 XBoxOne 릴리즈용 .pak 파일은 압축을 해도 최종 제품에 심각한 영향을 끼치지 않습니다. | +| Steam | 사용자가 다운로드하는 도중 파일을 압축하므로, 다운로드 시간은 압축중인 게임의 .pak 파일에 영향받지 않습니다. 하지만 미압축 파일의 경우 Steam 의 차등 패치 시스템이 나을 것입니다. 압축된 .pak 파일은 소비자 시스템의 디스크 공간을 절약해 주지만, 패치할 때 다운로드 시간은 길어집니다. | + +![Project Settings - Compress Pak 옵션](Project_Settings_PakCompression.png) +[REGION:caption]이 박스를 체크하면 .pak 파일의 압축을 켤 수 있습니다.[/REGION] + +### .pak 파일 순서 + +* 로드 시간 단축을 위해서는 .pak 파일 순서를 잘 지정하는 것이 중요합니다. .pak 파일 최적의 순서를 지정하는 데 도움을 드리기 위해, 언리얼 엔진에서는 데이터 애셋의 필요 순서를 알아내어 더욱 빠른 로딩 패키지를 제작하기 위한 툴 세트가 제공됩니다. 개념적으로, 이 프로세스는 프로파일 주도형 최적화와 비슷합니다. .pak 파일 순서 지정 방법은 다음과 같습니다: + +1. -fileopenlog 명령줄 옵션으로 패키지 게임을 빌드하고 실행시켜, 엔진이 파일을 여는 순서를 기록하도록 하는 것입니다. +1. 게임 주요 영역을 전부 확인하세요. 모든 레벨, 모든 플레이가능 캐릭터, 모든 무기, 모든 비히클 등을 로드하세요. 모든 것이 로드했으면, 게임을 종료합니다. +1. 디플로이된 게임에 보면 .pak 파일 순서 최적화에 필요한 정보가 들어있는 `GameOpenOrder.log` 라는 파일이 있습니다. 예를 들어 윈도우 빌드의 경우, 이 파일은 `WindowsNoEditor/(YourGame)/Build/WindowsNoEditor/FileOpenOrder/` 에 있습니다. 이 파일을 `/Build/WindowsNoEditor/FileOpenOrder/` 아래 개발 디렉토리에 복사하세요. +1. 로그 파일을 배치하고, .pak 파일을 리빌드합니다. 그러면 이번 것과 앞으로 생성되는 모든 .pak 파일은 로그 파일에 나타난 파일 순서를 사용할 것입니다. + +* 프로덕션 환경에서는, 이 로그 파일을 소스 콘트롤에 체크 인 하고, 주기적으로 -fileopenlog 를 붙여 실행한 뒤 주기적으로 업데이트해 주는 것은 물론, 게임 발매 준비가 되면 마지막으로 한 번 더 실행시킨 뒤 포함시켜 줘야 할 것입니다. \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Basics/Projects/UnrealGameProjects.KOR.udn b/Engine/Documentation/Source/Engine/Basics/Projects/UnrealGameProjects.KOR.udn index 6669aa82a36f..aa6de2422590 100644 --- a/Engine/Documentation/Source/Engine/Basics/Projects/UnrealGameProjects.KOR.udn +++ b/Engine/Documentation/Source/Engine/Basics/Projects/UnrealGameProjects.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3454520 Availability:Public Title:언리얼 게임 프로젝트 Crumbs: %ROOT%, Engine diff --git a/Engine/Documentation/Source/Engine/Basics/Redirectors/Redirectors.INT.udn b/Engine/Documentation/Source/Engine/Basics/Redirectors/Redirectors.INT.udn index 7dac4b0dac6f..d1089010f89f 100644 --- a/Engine/Documentation/Source/Engine/Basics/Redirectors/Redirectors.INT.udn +++ b/Engine/Documentation/Source/Engine/Basics/Redirectors/Redirectors.INT.udn @@ -3,16 +3,26 @@ Title:Redirectors Crumbs:%ROOT%, Engine Description:Objects that are placed in packages to redirect references to moved assets to their current locations. version: 4.9 +Parent:Engine +type:overview +order:27 + [TOC (start:2 end:3)] - - Moving or renaming an asset in UE4 leaves a **Redirector** in its old location. This is so that packages that are not currently loaded, but reference this asset, will know where to find it in its new location. Choosing a naming system early on and sticking with it will avoid many of the problems experienced with Redirectors. +## Fixup Redirector From Editor -## FixupRedirects Commandlet +To see redirectors in the editor enable the Show Redirectors filter in the content browser. Then, right click a redirector and select Fixup. This will resave all packages that point to the redirector, and will delete the redirector if it was able to resave all things referencing it. -Be sure to run the FixupRedirects commandlet on a regular basis. On previous projects, our Level Designers ran this commandlet on all packages every two weeks. It will clean up as much as it can (so it does not require that everyone check in every package). + +## ResavePackages Commandlet + +The ResavePackages commandlet can be run with the -FixupRedirectors option to try and fixup all redirectors in your project. Here's an example command line: + + UE4Editor.exe -run=ResavePackages -fixupredirects -autocheckout -projectonly -unattended + +This version of the command line would be run by a user on their local machine. It will check out all files that need to be fixed up, and the user needs to submit them. -autocheckin can be used by an automated process and it will also check the files in for you. ## Gotchas @@ -20,7 +30,7 @@ Be sure to run the FixupRedirects commandlet on a regular basis. On previous pro ### Renaming -If you create an object, rename it, and then create a new object with the same name as the original, an error will occur. This is because a Redirector was created when the first object was renamed, and a Redirector and a resource cannot have the same name. To solve this, try the FixupRedirects commandlet. +If you create an object, rename it, and then create a new object with the same name as the original, an error will occur. This is because a Redirector was created when the first object was renamed, and a Redirector and a resource cannot have the same name. ### Dangling Redirector @@ -42,7 +52,7 @@ There are a few known issues with Redirectors that can be reproduced as follows: * The redirector that was created for the first rename will be destroyed, but a new one will be created at B. As a result, A will not be able to be deleted because it is being referenced. -Running the FixupRedirects commandlet before deleting should solve these problems. +Fixing redirectors from the editor or SavePackages before deleting should solve these problems. diff --git a/Engine/Documentation/Source/Engine/Basics/Redirectors/Redirectors.KOR.udn b/Engine/Documentation/Source/Engine/Basics/Redirectors/Redirectors.KOR.udn index c80b1990d6d9..8a9d91d4abbb 100644 --- a/Engine/Documentation/Source/Engine/Basics/Redirectors/Redirectors.KOR.udn +++ b/Engine/Documentation/Source/Engine/Basics/Redirectors/Redirectors.KOR.udn @@ -1,13 +1,15 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3454520 Availability: Public Title:리디렉터 (Redirector) Crumbs:%ROOT%, Engine Description:패키지에 놓아 이동된 애셋을 가리키던 레퍼런스를 현재 위치로 고쳐주는 오브젝트 입니다. version: 4.9 +Parent:Engine +type:overview +order:27 + [TOC (start:2 end:3)] - - 언리얼 에디터에서 애셋을 이동하거나 이름을 바꾸면 원래의 장소에 **Redirector** (리디렉터)가 남습니다. 이를 통해 현재 로드되지는 않았지만 이 애셋을 참조하는 패키지가 그 애셋의 새 위치를 알게 됩니다. 작명 규칙을 조기에 정해두고 이를 고수하면 Redirector 로 인한 많은 문제점들을 예방할 수 있습니다. diff --git a/Engine/Documentation/Source/Engine/Basics/Screenshots/Screenshots.INT.udn b/Engine/Documentation/Source/Engine/Basics/Screenshots/Screenshots.INT.udn index ad04514ad64f..395944d724db 100644 --- a/Engine/Documentation/Source/Engine/Basics/Screenshots/Screenshots.INT.udn +++ b/Engine/Documentation/Source/Engine/Basics/Screenshots/Screenshots.INT.udn @@ -3,10 +3,13 @@ Title:Taking Screenshots Crumbs:%ROOT%, Engine Description:Guide to taking in-game screenshots of environments and gameplay. version: 4.9 +Parent:Engine +type:overview +order:28 +topic-image:TakingScreenshots_Topic.png + [TOC (start:2 end:3)] - - Unreal Engine 4 (UE4) offers users a multitude of different ways of taking in-game screenshots of your project. This document will not only cover which tools are available for taking screenshots in UE4 but also how you can use the tools. diff --git a/Engine/Documentation/Source/Engine/Basics/Screenshots/Screenshots.KOR.udn b/Engine/Documentation/Source/Engine/Basics/Screenshots/Screenshots.KOR.udn index 8578f629989e..b1733f7d38b1 100644 --- a/Engine/Documentation/Source/Engine/Basics/Screenshots/Screenshots.KOR.udn +++ b/Engine/Documentation/Source/Engine/Basics/Screenshots/Screenshots.KOR.udn @@ -1,13 +1,16 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3467293 Availability: Public Title:스크린샷 찍기 Crumbs:%ROOT%, Engine Description:게임내 배경과 게임플레이 스크린샷 찍는 법 안내입니다. version: 4.9 +Parent:Engine +type:overview +order:28 +topic-image:TakingScreenshots_Topic.png + [TOC (start:2 end:3)] - - 언리얼 엔진 4 (UE4) 는 사용자에게 언리얼 엔진 게임 프로젝트의 게임내 스크린샷을 찍기 위한 여러가지 다양한 방법을 제공합니다. 이 문서에서는 UE4 에서 스크린샷을 찍는 데 사용할 수 있는 툴뿐 아니라 그 사용법까지도 다뤄 보겠습니다. diff --git a/Engine/Documentation/Source/Engine/Basics/SourceControl/SourceControlLandingPage.INT.udn b/Engine/Documentation/Source/Engine/Basics/SourceControl/SourceControlLandingPage.INT.udn index 000996b926ff..a9afc4520a31 100644 --- a/Engine/Documentation/Source/Engine/Basics/SourceControl/SourceControlLandingPage.INT.udn +++ b/Engine/Documentation/Source/Engine/Basics/SourceControl/SourceControlLandingPage.INT.udn @@ -3,6 +3,9 @@ Title: Collaboration in Unreal Engine 4 Crumbs: %ROOT%, Engine Description: How to setup Perforce or SVN so that you can share assets with other on your team. version: 4.9 +parent:Engine +type:overview +order:29 Unreal Engine 4 comes with two fully-integrated methods that allow people to work together on their projects using version control software like Perforce and SVN. Version control allows users on your team to share assets and code with one another, as well as providing a backup and history of changes so any files can diff --git a/Engine/Documentation/Source/Engine/Basics/SourceControl/SourceControlLandingPage.KOR.udn b/Engine/Documentation/Source/Engine/Basics/SourceControl/SourceControlLandingPage.KOR.udn index 13fa7082535d..9695f532cd8b 100644 --- a/Engine/Documentation/Source/Engine/Basics/SourceControl/SourceControlLandingPage.KOR.udn +++ b/Engine/Documentation/Source/Engine/Basics/SourceControl/SourceControlLandingPage.KOR.udn @@ -1,9 +1,12 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3454520 Availability: Public Title: 언리얼 엔진 4 에서의 협업 Crumbs: %ROOT%, Engine Description: 팀 내 다른 사람들과 애셋을 공유할 수 있도록 Perforce 또는 SVN 을 구성하는 방법입니다. version: 4.9 +parent:Engine +type:overview +order:29 언리얼 엔진 4 에는 다른 사람들과 함께 프로젝트 작업이 가능하도록 하기 위해 Perforce 나 SVN 같은 버전 콘트롤 소프트웨어를 사용하는 두 가지 완전 통합 방법이 포함되어 있습니다. 버전 콘트롤 소프트웨어를 통해 팀 내 사용자간에 애셋과 코드 공유가 가능할 뿐만 아니라, 백업이나 변경내역을 통해 어떤 파일이든 문제가 생긴 경우 diff --git a/Engine/Documentation/Source/Engine/BlueprintSplines/Reference/SplineEditorTool/SplineEditorToolReference.KOR.udn b/Engine/Documentation/Source/Engine/BlueprintSplines/Reference/SplineEditorTool/SplineEditorToolReference.KOR.udn index a62d43602c3b..75d975adf977 100644 --- a/Engine/Documentation/Source/Engine/BlueprintSplines/Reference/SplineEditorTool/SplineEditorToolReference.KOR.udn +++ b/Engine/Documentation/Source/Engine/BlueprintSplines/Reference/SplineEditorTool/SplineEditorToolReference.KOR.udn @@ -135,6 +135,7 @@ tags:Splines | **Add Spline Point Here** || 여기에 스플라인 포인트 추가 - 커서 위치에 스플라인 포인트를 새로 추가합니다. | | **Reset to Default** || 기본으로 리셋 - 스플라인을 아키타입 기본으로 리셋시킵니다. | | **Visualize Roll and Scale** || 롤 및 스케일 시각화 - 에디터에 스플라인의 롤 및 스케일 시각화 여부를 결정합니다. | -| **Allow Discontinous Splines** | 비연속 스플라인 허용 - 시각화에서 **Arrive** (도착) 및 **Leave** (출발) 탄젠트의 별도 설정 여부를 결정합니다. | +| **Allow Discontinous Splines** || 비연속 스플라인 허용 - 시각화에서 **Arrive** (도착) 및 **Leave** (출발) 탄젠트의 별도 설정 여부를 결정합니다. | [/REGION] + diff --git a/Engine/Documentation/Source/Engine/BlueprintSplines/SplinesLanding.JPN.udn b/Engine/Documentation/Source/Engine/BlueprintSplines/SplinesLanding.JPN.udn index 5dd9aba5232a..216f2e80a811 100644 --- a/Engine/Documentation/Source/Engine/BlueprintSplines/SplinesLanding.JPN.udn +++ b/Engine/Documentation/Source/Engine/BlueprintSplines/SplinesLanding.JPN.udn @@ -1,11 +1,11 @@ -INTSourceChangelist:3155346 +INTSourceChangelist:3178047 Availability:Public Title:ブループリント スプライン Crumbs: %ROOT%, Engine Description:ブループリント スプラインとスプライン メッシュ コンポーネントのランディング ページ Navigation:topic parent:Engine -order:10 +order:14 social-image:Engine/BlueprintSplines/Overview/BPSC_1.png related:Engine/Landscape/Editing/Splines/ version:4.13 diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/ActorReference/ActorReference.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/ActorReference/ActorReference.JPN.udn index 03c16936a859..5d46db90b643 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/ActorReference/ActorReference.JPN.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/ActorReference/ActorReference.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3035989 +INTSourceChangelist:3244370 Availability:Public Title:アクタ リファレンスの設定と取得 Crumbs: %ROOT%, Engine, Engine\Blueprints, Engine\Blueprints\BP_HowTo @@ -6,10 +6,11 @@ Description:アクタ リファレンスを使って、様々なアクタをレ Related:Gameplay/HowTo/ReferenceAssets/Blueprints version:4.9 skilllevel:Intermediate -type:howto +type:how-to parent:Engine/Blueprints/BP_HowTo order:1 tags:Data Types +tags:Blueprints [INCLUDE:Gameplay\HowTo\ReferenceAssets#referenceoverview] @@ -42,7 +43,7 @@ tags:Data Types ここで、リファレンスはレベル内の **アクタ** タイプと **オブジェクト** になるように指定します。 -1. 変数に「**TargetActor**」と名前を付けて、 **[Editable (編集可能)]** にチェックを入れます。 +1. 変数に「**TargetActor**」と名前を付けて、**[Editable (編集可能)]** にチェックを入れます。 ![](5NameVariable.png) @@ -100,7 +101,7 @@ tags:Data Types ![](11ActorSelected.png) -1. アクタを選ぶと、 **Target Actor** 変数が **[Details (詳細)]** パネルで選択されたアクタに更新されます。 +1. アクタを選ぶと、**Target Actor** 変数が **[Details (詳細)]** パネルで選択されたアクタに更新されます。 ![](13ActorSelected.png) diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/BasicUsage/BasicUsage.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/BasicUsage/BasicUsage.JPN.udn index def1113db193..223f01e7c8f4 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/BasicUsage/BasicUsage.JPN.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/BasicUsage/BasicUsage.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:2975314 +INTSourceChangelist:3244370 Availability:Public Title:ブループリントの基本ユーザーガイド Crumbs: %ROOT%, Engine, Engine\Blueprints, Engine\Blueprints\BP_HowTo @@ -11,6 +11,7 @@ Related:Gameplay Version:4.9 Parent:Engine/Blueprints/Anatomy Tags:Class Blueprints +tags:Blueprints [TOC(start:2 end:2)] @@ -94,19 +95,19 @@ Tags:Class Blueprints @@ -151,7 +152,7 @@ Tags:Class Blueprints * 追加のノードベースのアクションとショートカットに関する情報は、 [](Engine/Blueprints/UserGuide/CheatSheet) をご覧ください。 -## 変数を作成する +## 変数の作成手順 [INCLUDE:Engine/Blueprints/UserGuide/Variables#intro] diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/Casting/Casting.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/Casting/Casting.JPN.udn index 466eacf45338..307d7fb8d933 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/Casting/Casting.JPN.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/Casting/Casting.JPN.udn @@ -1,28 +1,30 @@ -INTSourceChangelist:2968923 +INTSourceChangelist:3244370 Availability:Public -Title:ブループリント キャスティングのサンプル +Title:Blueprint Casting の例 Crumbs: %ROOT%, Engine, Engine\Blueprints, Engine\Blueprints\BP_HowTo -Description:ブループリント キャスティングを使って、1 つのブループリントから複数のブループリント通信してみましょう。 +Description:Blueprint Casting を使って、1 つのブループリントから複数のブループリントに通信してみましょう。 Related:Engine/Blueprints/UserGuide/CastNodes Related:Engine/Blueprints/UserGuide/BlueprintCommsUsage Related:Engine/Blueprints/UserGuide skilllevel:Advanced version:4.9 -Parent:Engine/Blueprints -tags:Handling Objects and Actors +Parent:Engine/Blueprints/HowTo +type:how-to +tags:Data Types +tags:Blueprints order:3 -ブループリント キャスティングを使って異なるブループリントと通信して情報を共有する方法を説明します。このサンプルでは、プレイヤーはオブジェクトを撃ち、ヒットするたびにオブジェクトを小さくすることができます。そして、オブジェクトはヒットのたびに Character ブループリントに通知し、プレイヤーの移動速度を加速します。 +このガイドでは、Blueprint Casting を使って異なるブループリントと通信して情報を共有する方法を説明します。プレイヤーはオブジェクトを撃ち、ヒットした分だけオブジェクトを小さくすることができます。そして、オブジェクトはヒットされるたびに Character ブループリントに通知し、プレイヤーの移動速度を加速します。 [REGION:note] -このガイドでは、**Starter Content** を有効にした状態で **Blueprint First Person** テンプレートを使用します。 +このガイドでは、**スターターコンテンツ** を有効にした状態で **Blueprint First Person** テンプレートを使用します。 [/REGION] 1. **ビューポート** で、**EditorCube** メッシュのひとつ選択し、次に **[Details (詳細)]** パネルの **[Blueprint/Add Script (ブループリント/スクリプトを追加)]** ボタンをクリックします。 ![](Casting1.png) -1. 表示された確認ウィンドウで名前を LargeCube_Blueprint に変更し、**[Ok]** をクリックして名前変更を確定してブループリントを作成します。 +1. 表示された確認ウィンドウで名前を「LargeCube_Blueprint」に変更し、**[Ok]** をクリックして名前変更を確定してブループリントを作成します。 1. **コンテンツ ブラウザ** の **Content/FirstPersonBP/Blueprints** で **FirstPersonProjectile** ブループリントを開きます。 @@ -34,7 +36,7 @@ order:3 ![](Casting3.png)(w:800) - **Event Hit** ノード上で、**Other** ピンはヒットした別のアクタを参照します。**Cast To** ノードを使うと、これが本当にヒットした別のアクタである **LargeCube_Blueprint** なのかを確認しています。そうである場合、それにアクセスしてブループリント内のイベントや関数を実行したり、その中にある変数を変更したり、あるいはブループリント内のコンポーネントのプロパティを変更することができます。 + **Event Hit** ノード上で、**Other** ピンはヒットした別のアクタを参照します。**Cast To** ノードを使うと、実はヒットした別のアクタである **LargeCube_Blueprint** かどうかを確認します。そうである場合、それにアクセスしてブループリント内のイベントや関数を実行したり、その中にある変数を変更したり、あるいはブループリント内のコンポーネントのプロパティを変更することができます。 1. **As Large Cube Blueprint** ピンを引き出して **Get Static Mesh Component** 、次に **Set World Scale 3D** に接続します。 @@ -42,7 +44,7 @@ order:3 **Add Impulse at Location** に接続したら、Large Cube Blueprint へキャストし、その中の Static Mesh Component (実際の Cube) を取得し、それに対して新しく World Scale 3D の値を設定します。今、New Scale は 0 に設定されていますが、ヒットするたびに Large Cube Blueprint のサイズを小さくしていきます。 -1. **Static Mesh Component** を引き出して、 **Get World Scale** を使い、 **Vector * Float** ピン (**0.5** に設定) へ接続し、次に **New Scale** へつなぎます。 +1. **Static Mesh Component** を引き出して、**Get World Scale** を使い、**Vector * Float** ピン (**0.5** に設定) へ接続し、次に **New Scale** へつなぎます。 ![](Casting5.png) @@ -84,7 +86,7 @@ order:3 _画像をクリックしてフルサイズで表示_ - ここでは分かりやすいように **Reroute Nodes** を使ってワイヤーのフローを調整しますが、接続は同じにしてください。 + ここでは分かりやすいように **Reroute ノード** を使ってワイヤーのフローを調整しますが、接続は同じにしてください。 1. **[Compile]** と **[Save]** をクリックしたら **[Play]** ボタンをクリックしてエディタで再生します。 @@ -102,4 +104,4 @@ order:3 Large Cube ブループリントを撃つたびに小さくなり、キャラクターの移動が速くなります。 - **キャスティング** とユースケースの詳細については、以下の **Related Topics** セクションを参照してください。 + **Casting** とユースケースの詳細については、以下の **Related Topics** セクションを参照してください。 diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/CollapsingGraphs/CollapsingGraphs.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/CollapsingGraphs/CollapsingGraphs.JPN.udn index 5a7946fbb967..f3e034683700 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/CollapsingGraphs/CollapsingGraphs.JPN.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/CollapsingGraphs/CollapsingGraphs.JPN.udn @@ -1,6 +1,6 @@ -INTSourceChangelist:2679264 +INTSourceChangelist:3244370 Availability:Public -Title:グラフを折りたたむ +Title:グラフを折り畳む Crumbs: %ROOT%, Engine, Engine\Blueprints, Engine\Blueprints\BP_HowTo Description:ノードを折り畳んで新しいグラフ、関数、またはマクロにします。 Related:Engine/Blueprints/UserGuide @@ -9,8 +9,9 @@ Related:Engine/Blueprints/UserGuide/Macros version:4.9 skilllevel:Beginner parent:Engine/Blueprints/BP_HowTo -type:howto +type:how-to order:4 +tags:Blueprints このページでは、**ブループリント** グラフを折り畳んで、単一のノード、**関数** または **マクロ** にするいくつかの方法について説明します。こうすることで、大きなグラフをリンク付けされたグラフに統合して整理します。 @@ -30,7 +31,7 @@ order:4 ![](Collapse2.png)(w:740) - **Control + 左クリック** して選択したものに追加したり、選択したものを減らすこともできます。 + **[Control] と左クリック** で選択した内容へのノードの追加や削除が可能です。 1. 折り畳みたいノードがあれば、選択したノードを **右クリック** して、**[Collapse Nodes (ノードを折り畳む)]** を選択します。 @@ -44,7 +45,7 @@ order:4 ![](Collapse5.png) -1. **Collapsed Graph** を **ダブルクリック** すると、新規グラフが選択したノードと共に開きます。 +1. **[Collapsed Graph]** を **ダブルクリック** すると、新規グラフが選択したノードと共に開きます。 ![](Collapse6.png)(w:740) @@ -77,7 +78,7 @@ order:4 ![](CollapseFunction1.png)(w:700) -1. 新規 **関数** が作成されます。これは **F2** を押して **MyBlueprint** ウィンドウから名前を変更できます。 +1. 新規 **関数** が作成されます。これは **F2** を押して **[MyBlueprint]** ウィンドウから名前を変更できます。 ![](CollapseFunction2.png) diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/ConnectingNodes/ConnectingNodes.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/ConnectingNodes/ConnectingNodes.JPN.udn index 01a04e18f311..55f6f68f7c98 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/ConnectingNodes/ConnectingNodes.JPN.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/ConnectingNodes/ConnectingNodes.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:2974295 +INTSourceChangelist:3244370 Availability:Public Title:ノードを接続する Crumbs: %ROOT%, Engine, Engine\Blueprints, Engine\Blueprints\Scripting @@ -11,6 +11,7 @@ version:4.9 skilllevel:Beginner parent:Engine/Blueprints/Scripting tags:Execution Flow +tags:Blueprints order:5 このページでは、ブループリントのグラフでノードを接続する様々な方法について説明します。 @@ -35,7 +36,7 @@ order:5 ![](ColorCoded.png) -2 つの異なるタイプのピンを接続できる場合もありますが、その場合は **Conversion Node** が作成されます。 +2 つの異なるタイプのピンを接続できる場合もありますが、その場合は **Conversion ノード** が作成されます。 ![](ConversionNode1.png) diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/Debugging/Debugging.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/Debugging/Debugging.JPN.udn index a0acf0f389ac..78f66030be9f 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/Debugging/Debugging.JPN.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/Debugging/Debugging.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:2968923 +INTSourceChangelist:3244370 Availability:Public Title:ブループリントのデバッグのサンプル Crumbs: %ROOT%, Engine, Engine\Blueprints, Engine\Blueprints\Workflow @@ -8,6 +8,7 @@ Related:Engine/Blueprints version:4.9 parent:Engine/Blueprints/Workflow order:6 +tags:Blueprints [TOC(start:2)] @@ -62,7 +63,7 @@ UtS3wgltYgg ブレークポイントのオン、オフを切り替えるためには、**右クリック** する代わりに、選択したノード上で **F9** キーを押すこともできます。 [/REGION] -ブレークポイントをノードに追加した時は、ノードの左上隅に赤色の円が表示されます。 +ブレークポイントがノードに追加されると、ノードの左上隅に赤色の円が表示されます。 ![](DebugHowTo4.png) @@ -92,7 +93,7 @@ UtS3wgltYgg ノードにブレークポイントを配置すると、スクリプトを前方向にたどるプロセスを開始し、現在の実行フローの終わりに到達すると自動的にゲームプレイに戻ります。 [/REGION] -デバッグの一般的なワークフローは、ノードにブレークポイントを追加し、**[Step]** を使用してスクリプトをたどり、どこに問題があるかを特定するというものです。後ろ方向に進むことはできません。ブレークポイントを配置する場合はこれを念頭においてください。ブレークポイントは、問題への繋がりが分かるよううに、発生場所の前後に配置するようにします。 +デバッグの一般的なワークフローは、ノードにブレークポイントを追加し、**Step** を使用してスクリプトをたどり、どこに問題があるかを特定するというものです。後ろ方向に進むことはできません。ブレークポイントを配置する場合はこれを念頭においてください。ブレークポイントは、問題への繋がりが分かるよううに、発生場所の前後に配置するようにします。 ## ウォッチ値 @@ -121,7 +122,7 @@ UtS3wgltYgg エディタで再生していないときは、ブループリント デバッガーは割り当てられたウォッチ値やブレークポイントがあれば表示します (以下の黄色いボックス)。 -![](DebugHowTo4.png) +![](DebugHowTo14.png) 複数のブループリントを [Blueprint Debugger] タブに追加することができます。これは、**Shift** キーを押しながらシーンのアクタをクリックすることで行います。 diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/DirectBlueprintComs/DirectBlueprintComs.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/DirectBlueprintComs/DirectBlueprintComs.JPN.udn index 99f2ec32e05e..f3aa496f6064 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/DirectBlueprintComs/DirectBlueprintComs.JPN.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/DirectBlueprintComs/DirectBlueprintComs.JPN.udn @@ -1,4 +1,5 @@ -Availability:Public +INTSourceChangelist:3244370 +Availability:Public Title:ダイレクト ブループリント通信 Crumbs: %ROOT%, Engine, Engine\Blueprints, Engine\Blueprints\BP_HowTo Description:別のブループリントと直接データをやりとりする方法 @@ -7,16 +8,17 @@ Related:Engine/Blueprints/UserGuide/BlueprintCommsUsage Related:Engine/Blueprints/UserGuide version:4.9 skilllevel:Advanced +tags:Blueprints このページでは、[ダイレクト ブループリント通信](Engine/Blueprints/UserGuide/BlueprintComms) を使用して 2 つのブループリント間で行う直接通信やデータの受け渡し方法を説明します。 -この例では、プレイヤーはボックス経由で渡して通信しパーティクルエフェクトをアクティベートすることができます。 +このサンプルでは、プレイヤーはボックス経由で受け渡しおよび通信、パーティクル エフェクトのアクティベートができます。 [REGION:note] このガイドでは、**スターターコンテンツ** を有効にした状態で **Blueprint Third Person** テンプレートを使用します。 [/REGION] -1. **コンテンツ ブラウザ** で、「 **Content/StarterContent/Shapes** 」フォルダを開きます。 +1. **コンテンツ ブラウザ** で、「**Content/StarterContent/Shapes**」フォルダを開きます。 1. **Shape_Cube** を **右クリック** し、**[Asset Actions (アセット アクション)]** から **[Create Blueprint Using This... (これを使用してブループリントを作成...)]** を選択します。 @@ -26,7 +28,7 @@ skilllevel:Advanced 1. Shape_Cube ブループリントで左上にある **[Components]** の **[Static Mesh]** を選択します。 -1. **[Details (詳細)]** パネルで、 **[Collision Presets (コリジョン プリセット)]** を **OverlapOnlyPawn** に設定します。 +1. **[Details (詳細)]** パネルで、**[Collision Presets (コリジョン プリセット)]** を **[OverlapOnlyPawn]** に設定します。 ![](DirectCom2.png) @@ -60,7 +62,7 @@ skilllevel:Advanced ![](DirectCom5.png)(w:720) -1. **コンテンツブラウザ** の **Content/StarterContent/Blueprints** で、 **Blueprint_Effect_Fire** ブループリントを開きます。 +1. **コンテンツブラウザ** の **Content/StarterContent/Blueprints** で、**Blueprint_Effect_Fire** ブループリントを開きます。 1. **[Components]** ウィンドウの **[P_Fire]** をクリックし、次に **[Details (詳細)]** パネルの **[Auto Activate (自動アクティベート)]** のチェックを外します。 @@ -77,7 +79,7 @@ skilllevel:Advanced ここで通信相手にしたい Blueprint_Effect_Fire ブループリントのインスタンスをレベル内で指定します。レベル内に Blueprint_Effect_Fire ブループリントのインスタンスが複数配置されている場合は、それぞれのインスタンスがドロップダウン メニューに表示されるので、通信相手の **Target Blueprint** のインスタンスを示すことができます。 [REGION:tip] - **スポイト** アイコンをクリックすれば、ドロップダウン メニューを使わなくてもレベル内の **Target Bluperint** のインスタンスを選択することができます。指定した変数タイプに基づいたブループリントしかターゲットとして選択できないのでご注意ください。 + **スポイト** アイコンをクリックすれば、ドロップダウン メニューを使わなくてもレベル内の **Target Bluperint**z のインスタンスを選択することができます。指定した変数タイプに基づいたブループリントしかターゲットとして選択できないのでご注意ください。 [/REGION] 1. **[Play (プレイ)]** ボタンをクリックしてエディタで再生し、キャラクターがボックスを走利抜けるテストをします。 diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/EventDispatcher/EventDispatcher.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/EventDispatcher/EventDispatcher.JPN.udn index 4cd6db2ab7c0..22fd4a649606 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/EventDispatcher/EventDispatcher.JPN.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/EventDispatcher/EventDispatcher.JPN.udn @@ -1,6 +1,6 @@ -INTSourceChangelist:2680673 +INTSourceChangelist:3244370 Availability:Public -Title:イベントディスパッチャー +Title:イベント ディスパッチャー Crumbs: %ROOT%, Engine, Engine\Blueprints, Engine\Blueprints\BP_HowTo Description:あるブループリントで呼び出されたイベントが別のブループリントでイベントを実行するサンプルです。 Related:Engine/Blueprints/UserGuide/EventDispatcher @@ -8,32 +8,33 @@ Related:Engine/Blueprints/UserGuide/BlueprintCommsUsage Related:Engine/Blueprints/UserGuide version:4.9 skilllevel:Advanced +tags:Blueprints -[イベントディスパッチャー](Engine/Blueprints/UserGuide/EventDispatcher) が呼び出されると、イベントを実装したブループリントや、イベントディスパッチャーに結びついているイベントが設定されたブループリントも呼び出し時に実行されます。つまり、イベントディスパッチャーが呼び出されると、結びついているイベントも呼び出されて、1 つのソースから複数のイベントを一度に実行することができます。 +[イベントディスパッチャー](Engine/Blueprints/UserGuide/EventDispatcher) が呼び出されると、イベントディスパッチャーに結合されたイベントを持つブループリントもイベント ディスパッチャーの呼び出し時に実行されます。つまり、イベントディスパッチャーが呼び出されると、これに結合されたイベントも呼び出されて、1 つのソースから複数のイベントを一度に実行することができます。 -このページは、イベントディスパッチャーの設定方法およびイベントとイベントディスパッチャーをバインドする方法を紹介します。 +イベントディスパッチャーおよびイベントをこのイベントディスパッチャーへ結合するための設定方法を説明します。 このサンプルでは、プレイヤーはキーを押して、炎のパーティクル エフェクトを茂みの中でスポーンさせることができます。 [REGION:note] -このガイドでは、**Starter Content** を有効にした状態で **Blueprint Third Person** テンプレートを使用します。 +このガイドでは、**スターターコンテンツ** を有効にした状態で **Blueprint Third Person** テンプレートを使用します。 [/REGION] -1. **コンテンツ ブラウザ** の「 **Content/ThirdPersonBP/Blueprints** 」フォルダで **ThirdPersonCharacter** ブループリントを開きます。 +1. **コンテンツ ブラウザ** の**「Content/ThirdPersonBP/Blueprints」** フォルダで **ThirdPersonCharacter** ブループリントを開きます。 ![](EventD_1.png) -1. **[My Blueprint]** ウィンドウで、 **[Add Event Dispatcher (イベントディスパッチャーを追加)]** ボタンをクリックして「 **StartFire** 」と名付けます。 +1. **[My Blueprint]** ウィンドウで、 **[Add Event Dispatcher (イベントディスパッチャーを追加)]** ボタンをクリックして **「StartFire」** と名付けます。 ![](EventD_2.png) -1. グラフ ウィンドウを **右クリック** して、 **F** キーイベント を追加します。 +1. グラフ ウィンドウを **右クリック** して **F** Key Event を追加します。 1. **StartFire** イベントディスパッチャーをグラフへドラッグして **[Call]** を選択します。 ![](EventD_3.png) -1. **F** キーイベントを **Call StartFire** イベントディスパッチャーへ接続します。 +1. **F** Key Event を **Call StartFire** イベントディスパッチャーへ接続します。 ![](EventD_4.png) @@ -45,18 +46,18 @@ skilllevel:Advanced ![](EventD_5.png)(w:820) -1. メイン ツールバー で **[Blueprints]** ボタンをクリックして、次に **[Open Level Blueprint (Level ブループリントを開く)]** を選択します。 +1. メイン ツールバー で **[ブループリント]** ボタンをクリックして、次に **[Open Level Blueprint (Level ブループリントを開く)]** を選択します。 ![](EventD_6.png) -1. グラフ内で **右クリック** し、**Create a Reference to SM_Bush ]** ノードを選択します。 +1. グラフ内で **右クリック** し、**[Create a Reference to SM_Bush (SM_Bush へのリファレンスを作成)]** ノードを選択します。 ![](EventD_7.png) ここでレベル内の SM_Bush へのリファレンスを取得します。 [REGION:note] - 上図のようなノードが表示されない場合は、レベル内で **SM_Bush** を選択してから、もう一度行ってください。 + 上図のようなノードが表示されない場合は、レベル内で **SM_Bush** を選択して、再度行ってください。 [/REGION] 1. グラフ内を **右クリック** して、**Event Begin Play** ノードと **Get Player Character** ノードを追加します。 @@ -75,15 +76,15 @@ skilllevel:Advanced ![](EventD_9.png) - これにより、 **Bind Event** ノードと **Custom Event** ノードの 2 つノードが作成されます。Character ブループリントでイベントディスパッチャーが呼び出されるたびに、このイベントをバインドしているので、Custom Event および Custom Event に結合しているすべてのものも実行されます。イベントディスパッチャーに結合しているイベントが設定されたブループリントもすべて実行されます。 + これにより、 **Bind Event** ノードと **カスタム イベント** ノードの 2 つノードが作成されます。このイベントを結合しているので、Character ブループリントでイベントディスパッチャーが呼び出されるたびに、カスタム イベントおよびカスタム イベントに結合しているすべてのイベントも実行されます。イベントディスパッチャーに結合しているイベントが設定されたブループリントもすべて実行されます。 -1. **Custom Event** を引き出して、**Spawn Actor from Class** ノードを追加します (**Class** は **Blueprint_Effect_Fire** に設定)。 +1. **カスタム イベント** を引き出して、**Spawn Actor from Class** ノードを追加します (**Class** は **Blueprint_Effect_Fire** に設定)。 1. **SM_Bush** を **Get Actor Transform** へ引き出して、Spawn Actor ノードの **Spawn Transform** として使います。 ![](EventD_10.png) - ノードがすべて接続すると、このようになります。 + すべてのノードを接続すると、このようになります。 1. **[Compile]** をクリックして、Level ブループリントを閉じて、**Play** をクリックしてエディタで再生します。 diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/1/WorkingWithMaps_1.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/1/WorkingWithMaps_1.CHN.udn new file mode 100644 index 000000000000..759d5153238e --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/1/WorkingWithMaps_1.CHN.udn @@ -0,0 +1,182 @@ +INTSourceChangelist:0 +Availability:Docs +Title:1 - Required Setup +Description:Setting up your project to work with Blueprint Maps. +Crumbs:%ROOT% +Parent:Engine/Blueprints/BP_HowTo/WorkingWithMaps +Version: 4.15 +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithMaps +Order:1 + +[nav] + +Before you can start working with Blueprint Maps, you'll have to set up your project to display the container's contents. + +1. From the **Unreal Project Browser**, select the **New Project** tab, choose the **First Person** Blueprint project, and name your project `ExampleMapProject`. + + [REGION:lightbox] + [![](Step1_1.png)(w:600)](Step1_1.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Before creating your new project, please make sure that the project matches the following settings: + + [REGION:lightbox] + [![](Step1_1Note.png)(w:600)](Step1_1Note.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Double-click the **Blueprint** folder from the project's **Content Browser**. + + [REGION:lightbox] + [![](Step1_2.png)(w:600)](Step1_2.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. From the **Content Browser**, go ahead and click the **Add New** button, hovering your mouse cursor over the **Blueprint Class**, which is located under the **Create Basic Asset** pop-up menu. + + [REGION:lightbox] + [![](Step1_3.png)(w:600)](Step1_3.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After the **Pick Parent Class** menu opens, click the **All Classes** arrow to search for the **TextRender Actor** Blueprint Class. + + ![](Step1_4.png) + +1. Enter `TexRenderActor` in the **Search Bar**, selecting the **TextRenderActor** Blueprint Class before clicking the **Select** button. + + ![](Step1_5.png) + +1. At this point, you should have a new **TextRender Actor** located in your project's **Content Browser**. Go ahead and name the new Actor `DisplayMap`. + + [REGION:lightbox] + [![](Step1_6.png)(w:600)](Step1_6.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, drag the `DisplayMap` TextRender Actor into Unreal Editor's **Perspective (3D) Viewport**. + + [REGION:lightbox] + [![](Step1_7.png)(w:600)](Step1_7.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. With the **DisplayMap** TextRender Actor selected, click the **+ Add Component** button (located in the **Details** panel), and enter `Box Collision` into the **Search Bar**. + + [REGION:lightbox] + [![](Step1_8.png)(w:600)](Step1_8.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After adding the **Box Collision Component** to the TextRender Actor, name the new Component, `Trigger Box`. + + [REGION:lightbox] + [![](Step1_9.png)(w:600)](Step1_9.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, select the TextRender Component to view the Actor's **Transform** in the **Details** panel. + + [REGION:lightbox] + [![](Step1_10.png)(w:600)](Step1_10.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Update the **Display Map** Actor's **Transform** to reflect the following values: + + [REGION:lightbox] + [![](Step1_11.png)(w:600)](Step1_11.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, change the **Display Map** Actor's **Horizontal Alignment** to be **Center** aligned (rather than **Left** aligned, which is the default **Horizontal Alignment** value). + + [REGION:lightbox] + [![](Step1_12.png)(w:600)](Step1_12.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Currently, the **Trigger Box** Component is **Hidden in Game**. Go ahead and clear the **Hidden in Game** check box (located in the **Rendering** menu of the **Details** panel) so that you can view the **Box Collision** Component in-game. + + [REGION:lightbox] + [![](Step1_13.png)(w:600)](Step1_13.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + Having the ability to view **Box Collision** Components in-game is a great way to debug any potential issues with the underlying logic driving a triggered event. + [/REGION] + +1. If you enter PIE (or Play in Editor) mode, you'll notice that your projectiles will have a collision response to the **Display Map** collision box. Currently, we only want the **Display Map** collision response to trigger an event that allows us to display the contents of your Map containers. To do this, go to the **Collision** menu (located in the **Details** panel), click the **Collision Presets** drop-down list box, and select the **Custom...** option. + + [REGION:lightbox] + [![](Step1_14.png)(w:600)](Step1_14.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Finally, update the **Collision Presets** to reflect the following values: + + [REGION:lightbox] + [![](Step1_15.png)(w:600)](Step1_15.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +## End Result + +[REGION:lightbox] + [![](Step1_EndResult.png)(w:600)](Step1_EndResult.png) +[/REGION] + +[REGION:caption] +Click for full image. +[/REGION] + +By now, you've created a new project, having also set up a new TextRender Actor, which will display the contents of a Blueprint Map container that you'll create, edit, and display in the next step. + +[nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/1/WorkingWithMaps_1.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/1/WorkingWithMaps_1.INT.udn new file mode 100644 index 000000000000..ba82863d4894 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/1/WorkingWithMaps_1.INT.udn @@ -0,0 +1,151 @@ +Availability:Docs +Title:1 - Required Setup +Description:Setting up your project to work with Blueprint Maps. +Crumbs:%ROOT% +Parent:Engine/Blueprints/BP_HowTo/WorkingWithMaps +Version: 4.15 +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithMaps +Order:1 + +[nav] + +Before you can start working with Blueprint Maps, you'll have to set up your project to display the container's contents. + +1. From the **Unreal Project Browser**, select the **New Project** tab, choose the **First Person** Blueprint project, and name your project `ExampleMapProject`. + + [REGION:lightbox] + [![](Step1_1.png)(w:600)](Step1_1.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Before creating your new project, please make sure that the project matches the following settings: + + [REGION:lightbox] + [![](Step1_1Note.png)(w:600)](Step1_1Note.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Double-click the **Blueprint** folder from the project's **Content Browser**. + + [REGION:lightbox] + [![](Step1_2.png)(w:600)](Step1_2.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. From the **Content Browser**, go ahead and click the **Add New** button, hovering your mouse cursor over the **Blueprint Class**, which is located under the **Create Basic Asset** pop-up menu. + + [REGION:lightbox] + [![](Step1_3.png)(w:600)](Step1_3.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After the **Pick Parent Class** menu opens, click the **All Classes** arrow to search for the **TextRender Actor** Blueprint Class. + + ![](Step1_4.png) + +1. Enter `TexRenderActor` in the **Search Bar**, selecting the **TextRenderActor** Blueprint Class before clicking the **Select** button. + + ![](Step1_5.png) + +1. At this point, you should have a new **TextRender Actor** located in your project's **Content Browser**. Go ahead and name the new Actor `DisplayMap`. + + [REGION:lightbox] + [![](Step1_6.png)(w:600)](Step1_6.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, drag the `DisplayMap` TextRender Actor into Unreal Editor's **Perspective (3D) Viewport**. + + [REGION:lightbox] + [![](Step1_7.png)(w:600)](Step1_7.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. With the **DisplayMap** TextRender Actor selected, click the **+ Add Component** button (located in the **Details** panel), and enter `Box Collision` into the **Search Bar**. + + [REGION:lightbox] + [![](Step1_8.png)(w:600)](Step1_8.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After adding the **Box Collision Component** to the TextRender Actor, name the new Component, `Trigger Box`. + + [REGION:lightbox] + [![](Step1_9.png)(w:600)](Step1_9.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, select the TextRender Component to view the Actor's **Transform** in the **Details** panel. + + [REGION:lightbox] + [![](Step1_10.png)(w:600)](Step1_10.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Update the **Display Map** Actor's **Transform** to reflect the following values: + + ![](Step1_11.png) + +1. Now, change the **Display Map** Actor's **Horizontal Alignment** to be **Center** aligned (rather than **Left** aligned, which is the default **Horizontal Alignment** value). + + ![](Step1_12.png) + +1. Currently, the **Trigger Box** Component is **Hidden in Game**. Go ahead and clear the **Hidden in Game** check box (located in the **Rendering** menu of the **Details** panel) so that you can view the **Box Collision** Component in-game. + + ![](Step1_13.png) + + [REGION:note] + Having the ability to view **Box Collision** Components in-game is a great way to debug any potential issues with the underlying logic driving a triggered event. + [/REGION] + +1. If you enter PIE (or Play in Editor) mode, you'll notice that your projectiles will have a collision response to the **Display Map** collision box. Currently, we only want the **Display Map** collision response to trigger an event that allows us to display the contents of your Map containers. To do this, go to the **Collision** menu (located in the **Details** panel), click the **Collision Presets** drop-down list box, and select the **Custom...** option. + + ![](Step1_14.png) + +1. Finally, update the **Collision Presets** to reflect the following values: + + ![](Step1_15.png) + +## End Result + +[REGION:lightbox] + [![](Step1_EndResult.png)(w:600)](Step1_EndResult.png) +[/REGION] + +[REGION:caption] +Click for full image. +[/REGION] + +By now, you've created a new project, having also set up a new TextRender Actor, which will display the contents of a Blueprint Map container that you'll create, edit, and display in the next step. + +[nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/1/WorkingWithMaps_1.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/1/WorkingWithMaps_1.JPN.udn new file mode 100644 index 000000000000..74f78462f1f8 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/1/WorkingWithMaps_1.JPN.udn @@ -0,0 +1,152 @@ +INTSourceChangelist:3413824 +Availability:Docs +Title:1 - 必要な設定を行う +Description:Blueprint Map を使用するためのプロジェクト設定 +Crumbs:%ROOT% +Parent:Engine/Blueprints/BP_HowTo/WorkingWithMaps +Version:4.15 +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithMaps +Order:1 + +[nav] + +Blueprint Map を使用する前に、コンテナのコンテンツが表示されるようにプロジェクトを設定する必要があります。 + +1. **アンリアル プロジェクト ブラウザ** で **[New Project (新規プロジェクト)]** タブから **First Person** ブループリント プロジェクトを選択し、プロジェクトに「`ExampleMapProject`」と名前を付けます。 + + [REGION:lightbox] + [![](Step1_1.png)(w:600)](Step1_1.png) + [/REGION] + [REGION:caption] + + クリックしてフルサイズで表示 + [/REGION] + +1. 新規プロジェクトを作成する前に、プロジェクトが以下の設定になっているか確認してください。 + + [REGION:lightbox] + [![](Step1_1Note.png)(w:600)](Step1_1Note.png) + [/REGION] + [REGION:caption] + + クリックしてフルサイズで表示 + [/REGION] + +1. プロジェクトの **コンテンツ ブラウザ** から **「Blueprint」** フォルダをダブルクリックします。 + + [REGION:lightbox] + [![](Step1_2.png)(w:600)](Step1_2.png) + [/REGION] + [REGION:caption] + + クリックしてフルサイズで表示 + [/REGION] + +1. **コンテンツ ブラウザ** で**[Add New (新規追加)]** ボタンをクリックして **[Create Basic Asset (基本アセットを作成)]** ポップアップ メニュー配下の **[Blueprint Class]** にカーソルを当てます。 + + [REGION:lightbox] + [![](Step1_3.png)(w:600)](Step1_3.png) + [/REGION] + [REGION:caption] + + クリックしてフルサイズで表示 + [/REGION] + +1. **[Pick Parent Class (親クラスを選択)]** メニューが開いたら、**TextRender Actor** ブループリント クラスを検索するために **[All Classes]** の矢印をクリックします。 + + ![](Step1_4.png) + +1. **検索バー** に「`TexRenderActor`」と入力し **TextRenderActor** ブループリント クラスを選択して **[Select]** ボタンをクリックします。 + + ![](Step1_5.png) + +1. ここで、プロジェクトの **コンテンツ ブラウザ ** には新規作成した **TextRender Actor** が入っています。この新規アクタに「`DisplayMap`」と名前を付けます。 + + [REGION:lightbox] + [![](Step1_6.png)(w:600)](Step1_6.png) + [/REGION] + [REGION:caption] + + クリックしてフルサイズで表示 + [/REGION] + +1. `DisplayMap` TextRender アクタをアンリアル エディタの **Perspective (3D) Viewport** にドラッグします。 + + [REGION:lightbox] + [![](Step1_7.png)(w:600)](Step1_7.png) + [/REGION] + [REGION:caption] + + クリックしてフルサイズで表示 + [/REGION] + +1. **DisplayMap** TextRender アクタを選択したら、**[+ Add Component]** ボタン (**[Details (詳細)]** パネル) をクリックして **検索バー** に「`Box Collision`」と入力します。 + + [REGION:lightbox] + [![](Step1_8.png)(w:600)](Step1_8.png) + [/REGION] + [REGION:caption] + + クリックしてフルサイズで表示 + [/REGION] + +1. **Box Collision Component** を TextRender アクタに追加したら、新規コンポーネントに「`Trigger Box`」と名前を付けます。 + + [REGION:lightbox] + [![](Step1_9.png)(w:600)](Step1_9.png) + [/REGION] + [REGION:caption] + + クリックしてフルサイズで表示 + [/REGION] + +1. 次に TextRender コンポーネントを選択して、**[Details (詳細)]** パネルでアクタの **Transform** を表示します。 + + [REGION:lightbox] + [![](Step1_10.png)(w:600)](Step1_10.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Display Map** アクタの **[Transform]** を更新して、以下の値に反映させます。 + + ![](Step1_11.png) + +1. 次に、**Display Map** アクタの **[Horizontal Alignment (水平方法の配置)]** を **[Center (中央)]** 揃え (**Horizonal Alignment** のデフォルト値は **[Left (左)]** 揃えです)。 + + ![](Step1_12.png) + +1. 現在 **Trigger Box** コンポーネントは **Hidden in Game** にあります。(**[Details (詳細)]** パネルの **[Rendering]** メニュー) の **[Hidden in Game]** チェックボックスのチェックを外せば **Box Collision** コンポーネントをインゲームで表示することができます。 + + ![](Step1_13.png) + + [REGION:note] + **Box Collision** コンポーネントをインゲームで表示できると、トリガー済みイベントを操作する基本ロジックが原因の可能性のある問題のデバッグに便利です。 + [/REGION] + +1. PIE (Play in Editor) モードの場合、発射物は **Display Map** コリジョン ボックスに対してコリジョン反応をします。Map コンテナのコンテンツ表示を可能にするイベントをトリガーするための **Display Map** コリジョン ボックスが必要です。そのためには、(**[Details (詳細)]** パネル) の **[Collision]** メニューの **[Collision Presets]** ドロップダウン リスト ボックスをクリックし、**[Custom...]** オプションを選択します。 + + ![](Step1_14.png) + +1. 最後に **Collision Presets** を更新して、以下の値に反映させます。 + + ![](Step1_15.png) + +## 結果 + +[REGION:lightbox] + [![](Step1_EndResult.png)(w:600)](Step1_EndResult.png) +[/REGION] + +[REGION:caption] +クリックしてフルサイズで表示 +[/REGION] + +このステップでは、新規プロジェクトを作成し、新規 TextRender アクタも設定しました。これにより、次のステップで作成、編集、表示する Blueprint Map コンテナのコンテンツが表示されます。 + +[nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/1/WorkingWithMaps_1.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/1/WorkingWithMaps_1.KOR.udn new file mode 100644 index 000000000000..86545947a715 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/1/WorkingWithMaps_1.KOR.udn @@ -0,0 +1,152 @@ +INTSourceChangelist:3413824 +Availability:Docs +Title:1 - 필수 구성 +Description:블루프린트 맵 작업을 위한 프로젝트 구성 안내입니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/BP_HowTo/WorkingWithMaps +Version: 4.15 +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithMaps +Order:1 + +[nav] + +블루프린트 Map (맵) 작업을 시작하기에 앞서, 컨테이너의 내용을 표시하도록 프로젝트 구성을 해 줘야 합니다. + +1. **언리얼 프로젝트 브라우저** 에서 **새 프로젝트** 탭을 선택하고 **일인칭** 블루프린트 프로젝트를 선택한 뒤, 프로젝트 이름을 `ExampleMapProject` 라 합니다. + + [REGION:lightbox] + [![](Step1_1.png)(w:600)](Step1_1.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. 새 프로젝트를 만들기 전, 프로젝트 세팅이 다음과 같은지 확인해 주세요: + + [REGION:lightbox] + [![](Step1_1Note.png)(w:600)](Step1_1Note.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. 프로젝트의 **콘텐츠 브라우저** 에서 **Blueprint** 폴더를 더블클릭합니다. + + [REGION:lightbox] + [![](Step1_2.png)(w:600)](Step1_2.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. **콘텐츠 브라우저** 에서 **신규 추가** 버튼을 클릭하고 마우스 커서를 **블루프린트 클래스** 위에 올립니다. **기본 애셋 생성** 팝업 메뉴 아래 있습니다. + + [REGION:lightbox] + [![](Step1_3.png)(w:600)](Step1_3.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. **부모 클래스 선택** 메뉴가 열리면 **모든 클래스** 화살표를 클릭하고 **TextRender Actor** 블루프린트 클래스를 검색합니다. + + ![](Step1_4.png) + +1. **검색창** 에 `TexRenderActor` 라 입력하고, **TextRenderActor** 블루프린트 클래스를 선택한 뒤 **Select** (선택) 버튼을 클릭합니다. + + ![](Step1_5.png) + +1. 이제 프로젝트의 **콘텐츠 브라우저** 에 **TextRender Actor** 가 생겼을 것입니다. 새 액터 이름을 `DisplayMap` 이라 합니다. + + [REGION:lightbox] + [![](Step1_6.png)(w:600)](Step1_6.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. `DisplayMap` TextRender Actor 를 언리얼 에디터의 **원근 (3D) 뷰포트** 에 끌어 놓습니다. + + [REGION:lightbox] + [![](Step1_7.png)(w:600)](Step1_7.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. **DisplayMap** TextRender Actor 를 선택한 채 (**디테일** 패널에 위치한) **+ 컴포넌트 추가** 버튼을 클릭하고, **검색창** 에 `Box Collision` 이라 입력합니다. + + [REGION:lightbox] + [![](Step1_8.png)(w:600)](Step1_8.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. **Box Collision Component** 를 TextRender Actor 에 추가한 후, 새 컴포넌트 이름을 `Trigger Box` 라 합니다. + + [REGION:lightbox] + [![](Step1_9.png)(w:600)](Step1_9.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. 이제 TextRender Component 를 선택하고 **디테일** 패널에서 액터의 **트랜스폼** 을 확인합니다. + + [REGION:lightbox] + [![](Step1_10.png)(w:600)](Step1_10.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. **Display Map** 액터의 **트랜스폼** 값을 다음과 같이 업데이트합니다: + + ![](Step1_11.png) + +1. 이제 **Display Map** 액터의 **Horizontal Alignment** (가로 정렬)을 (기본값인 **Left** (왼쪽) 정렬에서) **Center** (가운데) 정렬로 변경합니다. + + ![](Step1_12.png) + +1. 현재 **Trigger Box** 컴포넌트는 **Hidden in Game** (게임에서 숨겨진) 상태입니다. **디테일** 패널의 **Rendering** 메뉴 아래 있는 **Hidden in Game** 박스 체크를 해제하면 **Box Collision** 컴포넌트를 게임 내에서 볼 수 있습니다. + + ![](Step1_13.png) + + [REGION:note] + 게임 내에서 **Box Collision** 컴포넌트를 볼 수 있으면 트리거 이벤트를 구동시키는 내부 로직 관련해서 생길 수 있는 문제 디버깅에 아주 좋습니다. + [/REGION] + +1. PIE (에디터에서 플레이) 모드에 들어가 보면, 프로젝타일에 **Display Map** 콜리전 박스에 대한 콜리전 반응이 있는 것이 보일 것입니다. 현재는 **Display Map** 콜리전 반응만 맵 컨테이너 내용을 표시해 주는 이벤트를 발동하도록 하고 싶습니다. 그러기 위해서는 **디테일** 패널의 **Collision** 메뉴에서 **콜리전 프리셋** 드롭다운 리스트 박스를 클릭한 뒤 **Custom...** 옵션을 선택합니다. + + ![](Step1_14.png) + +1. 마지막으로, **콜리전 프리셋** 값을 다음과 같이 업데이트합니다: + + ![](Step1_15.png) + +## 최종 결과 + +[REGION:lightbox] + [![](Step1_EndResult.png)(w:600)](Step1_EndResult.png) +[/REGION] + +[REGION:caption] +클릭하면 이미지 원본을 확인합니다. +[/REGION] + +이제 새 프로젝트를 생성하고, 새 TextRender Actor 구성을 마쳤습니다. 여기에 블루프린트 맵 컨테이너 내용이 표시될텐데, 다음 단계에서는 이를 생성, 편집, 표시해 보도록 하겠습니다. + +[nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/2/WorkingWithMaps_2.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/2/WorkingWithMaps_2.CHN.udn new file mode 100644 index 000000000000..8feb8080ce09 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/2/WorkingWithMaps_2.CHN.udn @@ -0,0 +1,444 @@ +INTSourceChangelist:0 +Availability:Docs +Title:2 - Creating and Displaying a Blueprint Map +Description:Setting up a Blueprint Map container so that so that you can display its contents in-game. +Crumbs: +Parent:Engine/Blueprints/BP_HowTo/WorkingWithMaps +Version: 4.15 +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithMaps +Order:2 + +[nav] + +Now that you've set up a **TextRender** actor in your newly created project, you're ready to create a Blueprint Map container, the contents of which you'll display in-game. + +1. From your project's **Content Browser**, double-click the **Display Set** TextRender Actor to open its Blueprint **Event Graph**. + + [REGION:lightbox] + [![](Step2_1.png)(w:600)](Step2_1.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. If you see the following screen, go ahead and click the **Open Full Blueprint Editor** link to get started. + + [REGION:lightbox] + [![](Step2_2.png)(w:600)](Step2_2.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + +1. You should see the **Display Set** TextRender Actor Blueprint **Event Graph**, where you'll be able to add a Blueprint Map and its display logic. + + [REGION:lightbox] + [![](Step2_3.png)(w:600)](Step2_3.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + + If you don't see the aforementioned screen, go ahead and click the **Event Graph** tab to open the Actor's Blueprint Event Graph Editor. + + [REGION:lightbox] + [![](Step2_3Note.png)(w:600)](Step2_3Note.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [/REGION] + +1. Now is the time to create a Blueprint Map container, where you'll sore some key-value pairs that you'll display later on. To create a new Blueprint Map, click the **+ Add New** button (located in the **My Blueprint** panel) and select **Variable** from the drop-down list. + + [REGION:lightbox] + [![](Step2_4.png)(w:600)](Step2_4.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Name your new variable, `Instruction Map`. + + [REGION:lightbox] + [![](Step2_5.png)(w:600)](Step2_5.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Click the variable's **pin type** button, which is located next to the variable's name. + + [REGION:lightbox] + [![](Step2_6.png)(w:600)](Step2_6.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, select the **Integer** variable type from the drop-down list. + + [REGION:lightbox] + [![](Step2_7.png)(w:600)](Step2_7.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Click the variable's **container type** button, which is located next to the **Variable Type** drop-down list in the **Details** panel. + + [REGION:lightbox] + [![](Step2_8.png)(w:600)](Step2_8.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Select the **Map** container type from the drop-down list. + + [REGION:lightbox] + [![](Step2_9.png)(w:600)](Step2_9.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, it's time to define our Map's key-value property types. Currently, the key is an **Integer** type, which is the desired property type. The value type, however, isn't a **String** variable type, though. To change the value from being an **Integer** to being a **String**, go ahead and click on the value property type drop down list. + + [REGION:lightbox] + [![](Step2_10.png)(w:600)](Step2_10.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Select **String** from the drop down list. + + [REGION:lightbox] + [![](Step2_11.png)(w:600)](Step2_11.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. At this point, you have a key-value pair that is of **Integer** and **String** types (respectively). Also, the Blueprint Graph reminds you that you need to compile the Blueprint in order to the define the items that you're going to store inside of the container. Go ahead and click the **Compile** button to get started. + + [REGION:lightbox] + [![](Step2_12.png)(w:600)](Step2_12.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + Compiling the Blueprint replaces the container's **Default Value** message with an interface, enabling you to populate your container with key-value pairs, wherein the Map's keys are Integers and the values are Strings. + [/REGION] + +1. If you already haven't done so, go ahead and click the **Save** button to save all of the work that you've done so far. + + [REGION:lightbox] + [![](Step2_13.png)(w:600)](Step2_13.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + In general, it's always a good practice to save early, and save often. + [/REGION] + +1. Click the **+** (Adds Element) button (located in the **Default Value** menu of the **Details** panel) to add a new key-value pair to the newly defined **Instruction Map** container. + + [REGION:lightbox] + [![](Step2_14.png)(w:600)](Step2_14.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Define your container's new key-value pair, defining the key as `1`, and defining the value as `WASD to run`. + + [REGION:lightbox] + [![](Step2_15.png)(w:600)](Step2_15.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Repeat the previous two steps, making sure to fill your **Instruction Map** container with the following key-value pairs: + + [REGION:lightbox] + [![](Step2_16.png)(w:600)](Step2_16.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +## Scripting the Logic + +Before you can display the contents of your newly created Blueprint Map, you'll need to write the necessary logic. + +1. Now that you've defined your container, go ahead and drag the **Instruction Map** variable into the Blueprint Event Graph. + + [REGION:lightbox] + [![](Step2_17.png)(w:600)](Step2_17.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Select **Get** from the **Instruction Map** drop-down list. + + [REGION:lightbox] + [![](Step2_18.png)(w:600)](Step2_18.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Drag off the **Instruction Map** node and add the **Find** node from the **Map Utilities** interface. + + [REGION:lightbox] + [![](Step2_19.png)(w:600)](Step2_19.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + There are several ways to get values from a Map. For this part of the tutorial, we'll go ahead and increment an integer key to display the associated values contained in the **Instruction Map**. + [/REGION] + +1. With the aforementioned note in mind, go ahead and click the **+ Add New** button, selecting **Variable** from the drop-down list. + + [REGION:lightbox] + [![](Step2_20.png)(w:600)](Step2_20.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Makes sure to set the variable's type to an **Integer** type, giving it the name, `Key`. + + [REGION:lightbox] + [![](Step2_21.png)(w:600)](Step2_21.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After you've declared and defined your new **Integer** variable, drag **Key** into the Blueprint Event Graph, and select **Get** from the drop-down list. + + [REGION:lightbox] + [![](Step2_22.png)(w:600)](Step2_22.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Drag off the **Key** node, search for, and add the **IncrementInt** node. + + [REGION:lightbox] + [![](Step2_23.png)(w:600)](Step2_23.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, go ahead and connect the **IncrementInt** node to the **Find** node. + + [REGION:lightbox] + [![](Step2_24.png)(w:600)](Step2_24.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + For the purposes of this tutorial, you're going to use a time function to increment the **Key** variable. + [/REGION] + +1. Drag off the **Event Tick** node, search for, and add the **Delay** node. + + [REGION:lightbox] + [![](Step2_25.png)(w:600)](Step2_25.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After you've set the delay duration to **2** seconds, connect the **Delay** node to the **IncrementInt** node. + + [REGION:lightbox] + [![](Step2_26.png)(w:600)](Step2_26.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Go ahead and drag off the **Event BeginPlay** node, search for, and connect to the **Branch** node. + + [REGION:lightbox] + [![](Step2_27.png)(w:600)](Step2_27.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Connect the **IncrementInt** node to the **Branch** node. + + [REGION:lightbox] + [![](Step2_28.png)(w:600)](Step2_28.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, connect the **Boolean** return value belonging to the **Find** node to the **Branch** node's **Condition** pin. + + [REGION:lightbox] + [![](Step2_29.png)(w:600)](Step2_29.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + If the **Find** node successfully locates the item in the Map, the node returns true. Otherwise, if the **Find** node returns false, there is no item contained in the Map that uses the provided key. + [/REGION] + +1. Drag off the **Branch** node's **True** pin, search for, and connect to the **Set Text(TextRender)** node. + + [REGION:lightbox] + [![](Step2_30.png)(w:600)](Step2_30.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + This branch of your logic means that if there are valid key-value pairs in the container, go ahead and display the container's associated value(s). + [/REGION] + +1. To display your container's values in-game, connect the **Find** node's return **Value** pin to the **Set Text** node's **Value** pin. + + [REGION:lightbox] + [![](Step2_31.png)(w:600)](Step2_31.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, drag off the **Branch** node's **False** pin, search for, and connect the **Set Text(TextRender)** node. + + [REGION:lightbox] + [![](Step2_32.png)(w:600)](Step2_32.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + This branch of your logic means that if there are no valid key-value pairs in the container, go ahead and display something else. + [/REGION] + +1. Drag off the **Branch** node's **Value** pin, search for, and connect to the **ToText(string)** node. + + [REGION:lightbox] + [![](Step2_33.png)(w:600)](Step2_33.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, define the string to read, `Now, shoot the blocks!`. + + [REGION:lightbox] + [![](Step2_34.png)(w:600)](Step2_34.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After inspecting your completed script, go ahead and click the **Compile** button before going back to the Editor's **Viewport** interface. + + [REGION:lightbox] + [![](Step2_35.png)(w:600)](Step2_35.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. From the Editor's **Viewport** interface, click the **Play** button to see your newly implemented script at work. + + [REGION:lightbox] + [![](Step2_36.png)(w:600)](Step2_36.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +## End Result + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 960 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 540 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + DcskFd9UhlA + [/PARAMLITERAL] +[/OBJECT] + +At this point in the guide, you've defined a new Blueprint Map, filled the container with key-value pairs, and displayed the values with +some basic logic that you created in your **TextRender** Actor's Blueprint Event Graph. If you want to learn how to perform a slightly +more advanced operation, please continue onto the next step, where you'll learn how to **Add** a key-value pair to a Map, subsequently +displaying the Map's values. + +[nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/2/WorkingWithMaps_2.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/2/WorkingWithMaps_2.INT.udn new file mode 100644 index 000000000000..0fec8e9edce1 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/2/WorkingWithMaps_2.INT.udn @@ -0,0 +1,376 @@ +Availability:Docs +Title:2 - Creating and Displaying a Blueprint Map +Description:Setting up a Blueprint Map container so that so that you can display its contents in-game. +Crumbs:%ROOT% +Parent:Engine/Blueprints/BP_HowTo/WorkingWithMaps +Version: 4.15 +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithMaps +Order:2 + +[nav] + +Now that you've set up a **TextRender** actor in your newly created project, you're ready to create a Blueprint Map container, the contents of which you'll display in-game. + +1. From your project's **Content Browser**, double-click the **Display Set** TextRender Actor to open its Blueprint **Event Graph**. + + [REGION:lightbox] + [![](Step2_1.png)(w:600)](Step2_1.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. If you see the following screen, go ahead and click the **Open Full Blueprint Editor** link to get started. + + [REGION:lightbox] + [![](Step2_2.png)(w:600)](Step2_2.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. You should see the **Display Set** TextRender Actor Blueprint **Event Graph**, where you'll be able to add a Blueprint Map and its display logic. + + [REGION:lightbox] + [![](Step2_3.png)(w:600)](Step2_3.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + + If you don't see the aforementioned screen, go ahead and click the **Event Graph** tab to open the Actor's Blueprint Event Graph Editor. + + [REGION:lightbox] + [![](Step2_3Note.png)(w:600)](Step2_3Note.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [/REGION] + +1. Now is the time to create a Blueprint Map container, where you'll store some key-value pairs that you'll display later on. To create a new Blueprint Map, click the **+ Add New** button (located in the **My Blueprint** panel) and select **Variable** from the drop-down list. + + ![](Step2_4.png) + +1. Name your new variable, `Instruction Map`. + + ![](Step2_5.png) + +1. Click the variable's **pin type** button, which is located next to the variable's name. + + ![](Step2_6.png) + +1. Now, select the **Integer** variable type from the drop-down list. + + ![](Step2_7.png) + +1. Click the variable's **container type** button, which is located next to the **Variable Type** drop-down list in the **Details** panel. + + ![](Step2_8.png) + +1. Select the **Map** container type from the drop-down list. + + ![](Step2_9.png) + +1. Now, it's time to define our Map's key-value property types. Currently, the key is an **Integer** type, which is the desired property type. The value type, however, isn't a **String** variable type, though. To change the value from being an **Integer** to being a **String**, go ahead and click on the value property type drop down list. + + ![](Step2_10.png) + +1. Select **String** from the drop down list. + + ![](Step2_11.png) + +1. At this point, you have a key-value pair that is of **Integer** and **String** types (respectively). Also, the Blueprint Graph reminds you that you need to compile the Blueprint in order to the define the items that you're going to store inside of the container. Go ahead and click the **Compile** button to get started. + + [REGION:lightbox] + [![](Step2_12.png)(w:600)](Step2_12.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + Compiling the Blueprint replaces the container's **Default Value** message with an interface, enabling you to populate your container with key-value pairs, wherein the Map's keys are Integers and the values are Strings. + [/REGION] + +1. If you already haven't done so, go ahead and click the **Save** button to save all of the work that you've done so far. + + [REGION:lightbox] + [![](Step2_13.png)(w:600)](Step2_13.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + In general, it's always a good practice to save early, and save often. + [/REGION] + +1. Click the **+** (Adds Element) button (located in the **Default Value** menu of the **Details** panel) to add a new key-value pair to the newly defined **Instruction Map** container. + + [REGION:lightbox] + [![](Step2_14.png)(w:600)](Step2_14.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Define your container's new key-value pair, defining the key as `1`, and defining the value as `WASD to run`. + + ![](Step2_15.png) + +1. Repeat the previous two steps, making sure to fill your **Instruction Map** container with the following key-value pairs: + + ![](Step2_16.png) + +## Scripting the Logic + +Before you can display the contents of your newly created Blueprint Map, you'll need to write the necessary logic. + +1. Now that you've defined your container, go ahead and drag the **Instruction Map** variable into the Blueprint Event Graph. + + [REGION:lightbox] + [![](Step2_17.png)(w:600)](Step2_17.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Select **Get** from the **Instruction Map** drop-down list. + + [REGION:lightbox] + [![](Step2_18.png)(w:600)](Step2_18.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Drag off the **Instruction Map** node and add the **Find** node from the **Map Utilities** interface. + + [REGION:lightbox] + [![](Step2_19.png)(w:600)](Step2_19.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + There are several ways to get values from a Map. For this part of the tutorial, we'll go ahead and increment an integer key to display the associated values contained in the **Instruction Map**. + [/REGION] + +1. With the aforementioned note in mind, go ahead and click the **+ Add New** button, selecting **Variable** from the drop-down list. + + ![](Step2_20.png) + +1. Makes sure to set the variable's type to an **Integer** type, giving it the name, `Key`. + + ![](Step2_21.png) + +1. After you've declared and defined your new **Integer** variable, drag **Key** into the Blueprint Event Graph, and select **Get** from the drop-down list. + + [REGION:lightbox] + [![](Step2_22.png)(w:600)](Step2_22.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Drag off the **Key** node, search for, and add the **IncrementInt** node. + + [REGION:lightbox] + [![](Step2_23.png)(w:600)](Step2_23.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, go ahead and connect the **IncrementInt** node to the **Find** node. + + [REGION:lightbox] + [![](Step2_24.png)(w:600)](Step2_24.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + For the purposes of this tutorial, you're going to use a time function to increment the **Key** variable. + [/REGION] + +1. Drag off the **Event Tick** node, search for, and add the **Delay** node. + + [REGION:lightbox] + [![](Step2_25.png)(w:600)](Step2_25.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After you've set the delay duration to **2** seconds, connect the **Delay** node to the **IncrementInt** node. + + [REGION:lightbox] + [![](Step2_26.png)(w:600)](Step2_26.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Go ahead and drag off the **Event BeginPlay** node, search for, and connect to the **Branch** node. + + [REGION:lightbox] + [![](Step2_27.png)(w:600)](Step2_27.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Connect the **IncrementInt** node to the **Branch** node. + + [REGION:lightbox] + [![](Step2_28.png)(w:600)](Step2_28.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, connect the **Boolean** return value belonging to the **Find** node to the **Branch** node's **Condition** pin. + + [REGION:lightbox] + [![](Step2_29.png)(w:600)](Step2_29.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + If the **Find** node successfully locates the item in the Map, the node returns true. Otherwise, if the **Find** node returns false, there is no item contained in the Map that uses the provided key. + [/REGION] + +1. Drag off the **Branch** node's **True** pin, search for, and connect to the **Set Text(TextRender)** node. + + [REGION:lightbox] + [![](Step2_30.png)(w:600)](Step2_30.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + This branch of your logic means that if there are valid key-value pairs in the container, go ahead and display the container's associated value(s). + [/REGION] + +1. To display your container's values in-game, connect the **Find** node's return **Value** pin to the **Set Text** node's **Value** pin. + + [REGION:lightbox] + [![](Step2_31.png)(w:600)](Step2_31.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, drag off the **Branch** node's **False** pin, search for, and connect the **Set Text(TextRender)** node. + + [REGION:lightbox] + [![](Step2_32.png)(w:600)](Step2_32.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + This branch of your logic means that if there are no valid key-value pairs in the container, go ahead and display something else. + [/REGION] + +1. Drag off the **Branch** node's **Value** pin, search for, and connect to the **ToText(string)** node. + + [REGION:lightbox] + [![](Step2_33.png)(w:600)](Step2_33.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, define the string to read, `Now, shoot the blocks!`. + + [REGION:lightbox] + [![](Step2_34.png)(w:600)](Step2_34.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After inspecting your completed script, go ahead and click the **Compile** button before going back to the Editor's **Viewport** interface. + + [REGION:lightbox] + [![](Step2_35.png)(w:600)](Step2_35.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. From the Editor's **Viewport** interface, click the **Play** button to see your newly implemented script at work. + + [REGION:lightbox] + [![](Step2_36.png)(w:600)](Step2_36.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +## End Result + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + DcskFd9UhlA + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +At this point in the guide, you've defined a new Blueprint Map, filled the container with key-value pairs, and displayed the values with +some basic logic that you created in your **TextRender** Actor's Blueprint Event Graph. If you want to learn how to perform a slightly +more advanced operation, please continue onto the next step, where you'll learn how to **Add** a key-value pair to a Map, subsequently +displaying the Map's values. + +[nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/2/WorkingWithMaps_2.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/2/WorkingWithMaps_2.JPN.udn new file mode 100644 index 000000000000..6c27823bf8b8 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/2/WorkingWithMaps_2.JPN.udn @@ -0,0 +1,377 @@ +INTSourceChangelist:3413824 +Availability:Docs +Title:2 - Blueprint Map の作成および表示 +Description:コンテンツをインゲームで表示するための Blueprint Map の設定方法 +Crumbs:%ROOT% +Parent:Engine/Blueprints/BP_HowTo/WorkingWithMaps +Version:4.15 +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithMaps +Order:2 + +[nav] + +新規作成したプロジェクトに **TextRender** アクタを設定したので、次は Blueprint Map コンテナを作成し、それをインゲームで表示してみましょう。 + +1. プロジェクトの **コンテンツ ブラウザ** から **Display Set** TextRender アクタをダブルクリックして、ブループリント **イベントグラフ** を開きます。 + + [REGION:lightbox] + [![](Step2_1.png)(w:600)](Step2_1.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 以下の画面が表示されたら、**[Open Full Blueprint Editor]** リンクをクリックして開始します。 + + [REGION:lightbox] + [![](Step2_2.png)(w:600)](Step2_2.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Display Set** TextRender アクタ ブループリントの **イベントグラフ** が表示されます。ここで Blueprint Map と表示ロジックを追加することができます。 + + [REGION:lightbox] + [![](Step2_3.png)(w:600)](Step2_3.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + + [REGION:note] + + 上記画面が表示されない場合、**[Event Graph]** タブをクリックしてアクタのブループリント イベントグラフ エディタを開きます。 + + [REGION:lightbox] + [![](Step2_3Note.png)(w:600)](Step2_3Note.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + + [/REGION] + +1. 次に、後で表示するキー / 値のペアを格納する Blueprint Map コンテナを作成します。新規の Blueprint Map を作成するには、(**[My Blueprint]** パネルの **[+ Add New]** ボタンをクリックしてドロップダウン リストから **[Variable (変数)]** を選択します。 + + ![](Step2_4.png) + +1. 新しい変数に「`Instruction Map`」と名前を付けます。 + + ![](Step2_5.png) + +1. その変数の横にある **ピン タイプ** のボタンをクリックします。 + + ![](Step2_6.png) + +1. 次にドロップダウン リストから変数タイプの **Integer** を選択します。 + + ![](Step2_7.png) + +1. **[Details (詳細)]** パネルの **[Variable Type]** ドロップダウン リストの横にある、その変数の **コンテナ タイプ** ボタンをクリックします。 + + ![](Step2_8.png) + +1. 次にドロップダウン リストから **Map** コンテナ タイプを選択します。 + + ![](Step2_9.png) + +1. 次に、Map のキー値のプロパティ タイプを定義します。今、キーは選択した通りの **Integer** 型になっています。しかし、値は **String** 変数型ではありません。値を **Integer** から **String** へ変更するには、値のプロパティ タイプのドロップダウン リストをクリックします。 + + ![](Step2_10.png) + +1. ドロップダウン リストから **[String]** を選択します。 + + ![](Step2_11.png) + +1. この時点で、**Integer** 型のキーと **String** 型の値のペアができあがりました。また、コンテナ内に格納するアイテムを定義する前にブループリントのコンパイルをするようにをブループリント グラフから警告されます。**[Compile]** ボタンをクリックしてコンパイルを開始します。 + + [REGION:lightbox] + [![](Step2_12.png)(w:600)](Step2_12.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + + [REGION:note] + ブループリントをコンパイルすると、コンテナの **[Default Value]** メッセージがインターフェースになり、Map のキーが Interger 型で値が String 型のキー / 値のペアをコンテナに追加することができます。 + [/REGION] + +1. ここまでの作業を保存していない場合は、**[Save]** ボタンをクリックしてすべての作業を保存してください。 + + [REGION:lightbox] + [![](Step2_13.png)(w:600)](Step2_13.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + + [REGION:note] + 一般的に、保存は早めに、そしてこまめに行うのがグッドプラクティスです。 + [/REGION] + +1. (**[Details (詳細)]** パネルの**[Default Value]** メニューにある) **[+]** (エレメントを追加) ボタンをクリックして、キー / 値のペアを新たに定義した **Instruction Map** コンテナに追加します。 + + [REGION:lightbox] + [![](Step2_14.png)(w:600)](Step2_14.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. コンテナに追加したキー / 値のペアのキーを「`1`」、値を「`WASD to run`」に定義します。 + + ![](Step2_15.png) + +1. この 2 ステップを繰り返して、**Instruction Map** コンテナに以下のキー / 値のペアが入っていることを確認してください。 + + ![](Step2_16.png) + +## ロジックのスクリプト処理 + +新規に作成した Blueprint Map のコンテンツを表示する前に、必要なロジックを書き込む必要があります。 + +1. コンテナを定義したので、**Instruction Map** 変数をブループリント イベントグラフにドラッグします。 + + [REGION:lightbox] + [![](Step2_17.png)(w:600)](Step2_17.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Instruction Map** ドロップダウン リストから **Get** を選択します。 + + [REGION:lightbox] + [![](Step2_18.png)(w:600)](Step2_18.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Instruction Map** ノードを引き出して **Map Utilities** インターフェースから **Find** ノードを追加します。 + + [REGION:lightbox] + [![](Step2_19.png)(w:600)](Step2_19.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + + [REGION:note] + Map から値を取得する方法はいくつかあります。このステップでは、**Instruction Map** に含まれる関連付けられた値を表示するために integer 型のキーをインクリメントします。 + [/REGION] + +1. 前述の注意を念頭に置いて、**[+ Add New]** ボタンをクリックし、ドロップダウン リストから **[Variable]** を選択します。 + + ![](Step2_20.png) + +1. 新しい変数の型を **Integer** に設定し、「`Key`」と名前を付けます。 + + ![](Step2_21.png) + +1. **Integer** 変数の宣言と定義が完了したら、**Key** をブループリント イベントグラフにドラッグして、ドロップダウン リストから **[Get]** を選択します。 + + [REGION:lightbox] + [![](Step2_22.png)(w:600)](Step2_22.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Key** ノードをドラッグして **IncrementInt** ノードを検索および追加します。 + + [REGION:lightbox] + [![](Step2_23.png)(w:600)](Step2_23.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 次に **IncrementInt** ノードを **Find** ノードに接続します。 + + [REGION:lightbox] + [![](Step2_24.png)(w:600)](Step2_24.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + + [REGION:note] + このチュートリアルの目的に合わせて、タイマー関数を使用して **Key** 変数をインクリメントします。 + [/REGION] + +1. **Event Tick** ノードを引き出して、**Delay** ノードを検索および追加します。 + + [REGION:lightbox] + [![](Step2_25.png)(w:600)](Step2_25.png) + [/REGION] + [REGION:caption] + + クリックしてフルサイズで表示 + [/REGION] + +1. 遅延時間を **2** 秒に設定し、**Delay** ノードを **IncrementInt** ノードに接続します。 + + [REGION:lightbox] + [![](Step2_26.png)(w:600)](Step2_26.png) + [/REGION] + [REGION:caption] + + クリックしてフルサイズで表示 + [/REGION] + +1. **Event BeginPlay** ノードを引き出して **Branch** ノードを検索し接続します。 + + [REGION:lightbox] + [![](Step2_27.png)(w:600)](Step2_27.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 次に **IncrementInt** ノードを **Branch** ノードに接続します。 + + [REGION:lightbox] + [![](Step2_28.png)(w:600)](Step2_28.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 次に **Find** ノードの **Boolean** 型の戻り値を **Branch** ノードの **Condition** ピンに接続します。 + + [REGION:lightbox] + [![](Step2_29.png)(w:600)](Step2_29.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + + [REGION:note] + Map 内でアイテムを見つけると **Find** ノードは true を返します。Map 内に指定されたキーを使っているアイテムが存在しない場合、**Find** ノードは false を返します。 | + [/REGION] + +1. **Branch** ノードの **True** ピンを引き出して、**Set Text(TextRender)** ノードを検索し接続します。 + + [REGION:lightbox] + [![](Step2_30.png)(w:600)](Step2_30.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + + [REGION:note] + この部分は、コンテナに有効なキー / 値のペアがあれば、コンテナに関連づいた値を表示するというロジックです。 + [/REGION] + +1. コンテナの値をインゲームで表示するには、**Find** ノードの **Value** ピンを **Set Text** ノードの **Value** ピンに接続します。 + + [REGION:lightbox] + [![](Step2_31.png)(w:600)](Step2_31.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Branch** ノードの **False** ピンを引き出して、**Set Text(TextRender)** ノードを検索し接続します。 + + [REGION:lightbox] + [![](Step2_32.png)(w:600)](Step2_32.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + + [REGION:note] + この部分は、コンテナに有効なキー / 値のペアがなければ、何か別のものを表示するというロジックです。 + [/REGION] + +1. **Branch** ノードの **Value** ピンを引き出して、**ToText(string)** ノードを検索し接続します。 + + [REGION:lightbox] + [![](Step2_33.png)(w:600)](Step2_33.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 次に、「`Now, shoot the blocks!`」を読み込むように文字列を定義します。 + + [REGION:lightbox] + [![](Step2_34.png)(w:600)](Step2_34.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 完成したスクリプトを確認したら、エディタの **Viewport** インターフェースに戻る前に **[Compile]** ボタンをクリックします。 + + [REGION:lightbox] + [![](Step2_35.png)(w:600)](Step2_35.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. エディタの **Viewport** インターフェースで、**[Play]** ボタンをクリックして新しく実装したスクリプトの動きを確認します。 + + [REGION:lightbox] + [![](Step2_36.png)(w:600)](Step2_36.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +## 結果 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + DcskFd9UhlA + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +このステップでは、新規作成した Blueprint Map を定義し、キー / 値のペアを追加し、 +**TextRender** アクタのブループリント イベントグラフで作成したロジックのいくつかを使ってそれらの値を表示しました。もう少し高度な操作を学習したい場合は次のステップへ進んでください。 +キー / 値のペアを Map に **追加** して、 +最終的に Map の値として表示する方法を説明します。 + +[nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/2/WorkingWithMaps_2.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/2/WorkingWithMaps_2.KOR.udn new file mode 100644 index 000000000000..23a3e052f89b --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/2/WorkingWithMaps_2.KOR.udn @@ -0,0 +1,377 @@ +INTSourceChangelist:3413824 +Availability:Docs +Title:2 - 블루프린트 맵 생성 및 표시 +Description:게임 내에서 블루프린트 맵 컨테이너 내용을 표시하도록 구성합니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/BP_HowTo/WorkingWithMaps +Version: 4.15 +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithMaps +Order:2 + +[nav] + +새로 생성된 프로젝트에서 **TextRender** 액터 구성을 마쳤으니, 블루프린트 맵 컨테이너 생성 준비가 다 되었습니다. 이제 그 내용을 게임 내에서 표시하도록 하겠습니다. + +1. 프로젝트의 **콘텐츠 브라우저** 에서 **Display Set** TextRender Actor 를 더블클릭하여 그 블루프린트 **이벤트 그래프** 를 엽니다. + + [REGION:lightbox] + [![](Step2_1.png)(w:600)](Step2_1.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. 다음 화면이 보이면 **Open Full Blueprint Editor** (풀 블루프린트 에디터 열기) 링크를 클릭하여 시작합니다. + + [REGION:lightbox] + [![](Step2_2.png)(w:600)](Step2_2.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. **Display Set** TextRender Actor 블루프린트 **이벤트 그래프** 가 보일텐데, 여기서 블루프린트 맵 및 그 표시 로직을 추가할 수 있습니다. + + [REGION:lightbox] + [![](Step2_3.png)(w:600)](Step2_3.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + + [REGION:note] + + 앞서 말한 화면이 보이지 않는 경우, **이벤트 그래프** 탭을 클릭하면 액터의 블루프린트 이벤트 그래프 에디터가 열립니다. + + [REGION:lightbox] + [![](Step2_3Note.png)(w:600)](Step2_3Note.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + + [/REGION] + +1. 이제 블루프린트 맵 컨테이너를 만들 차례입니다. 나중에 표시할 키-값 짝이 바로 이 곳에 저장됩니다. 새 블루프린트 맵을 만들려면, (**내 블루프린트** 패널에 위치한** **+ 신규 추가** 버튼을 클릭하고 드롭다운 목록에서 **Variable** (변수)를 선택합니다. + + ![](Step2_4.png) + +1. 새 변수 이름은 `Instruction Map` 이라 합니다. + + ![](Step2_5.png) + +1. 변수의 **핀 유형** 버튼을 클릭합니다. 변수 이름 옆에 있습니다. + + ![](Step2_6.png) + +1. 드롭다운 목록에서 **Integer** 변수 유형을 선택합니다. + + ![](Step2_7.png) + +1. 변수의 **컨테이너 유형** 버튼을 클릭합니다. **디테일** 패널의 **Variable Type** (변수 유형) 드롭다운 리스트 옆에 있습니다. + + ![](Step2_8.png) + +1. 드롭다운 리스트에서 **Map** (맵) 컨테이너 유형을 선택합니다. + + ![](Step2_9.png) + +1. 맵의 키-값 프로퍼티 유형을 정의할 차례입니다. 현재 키는 **Interger** 로 바람직한 프로퍼티 유형입니다. 하지만 값 유형은 **String** 유형힙니다. 값을 **Integer** 에서 **String** 으로 변경하려면, 값 프로퍼티 유형 드롭다운 리스트에서 선택해 주면 됩니다. + + ![](Step2_10.png) + +1. 드롭다운 리스트에서 **String** 을 선택합니다. + + ![](Step2_11.png) + +1. 이제 **Integer** 와 **String** 유형( 각각)의 키-값이 생겼습니다. 또한, 블루프린트 그래프에서는 블루프린트를 컴파일해야 컨테이너 안에 저장하려는 아이템을 정의할 수 있다고 알려줍니다. 계속해서 **컴파일** 버튼을 클릭하여 시작합니다. + + [REGION:lightbox] + [![](Step2_12.png)(w:600)](Step2_12.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + + [REGION:note] + 블루프린트를 컴파일하면 인터페이스가 있는 컨테이너의 **Default Value** 메시지를 대체시켜, 컨테이너를 키-값 짝으로 채울 수 있습니다. 여기서 맵의 키는 Integer, 값은 String 입니다. + [/REGION] + +1. 아직 저장하지 않았으면 **저장** 버튼을 눌러 지금까지 작업 내용을 저장합니다. + + [REGION:lightbox] + [![](Step2_13.png)(w:600)](Step2_13.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + + [REGION:note] + 일반적으로, 항상 일찍 자주 저장하는 습관을 들이는 것이 좋습니다. + [/REGION] + +1. (**디테일** 패널의 **Default Value** 메뉴에 있는) **+** (엘리먼트 추가) 버튼을 클릭하여 새로 정의된 **Instruction Map** 컨테이너에 키-값 짝을 새로 추가합니다. + + [REGION:lightbox] + [![](Step2_14.png)(w:600)](Step2_14.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. 컨테이너의 새로운 키-값 짝을 정의합니다. 키는 `1` 로, 값은 `WASD to run` 으로 정의합니다. + + ![](Step2_15.png) + +1. 전의 두 단계를 반복하여, **Instruction Map** 컨테이너를 다음 키-값 짝으로 채웁니다: + + ![](Step2_16.png) + +## 로직 스크립트 작성 + +새로 만든 블루프린트 맵 내용을 표시하기에 앞서, 필요한 로직을 작성해 줘야 합니다. + +1. 컨테이너 정의를 마쳤으니, **Instruction Map** 변수를 끌어 블루프린트 이벤트 그래프에 놓습니다. + + [REGION:lightbox] + [![](Step2_17.png)(w:600)](Step2_17.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. **Instruction Map** 드롭다운 리스트에서 **Get** 을 선택합니다. + + [REGION:lightbox] + [![](Step2_18.png)(w:600)](Step2_18.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. **Instruction Map** 노드를 끌어 놓고 **Map Utilities** 인터페이스에서 **Find** 노드를 추가합니다. + + [REGION:lightbox] + [![](Step2_19.png)(w:600)](Step2_19.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + + [REGION:note] + 맵에서 값을 구하는 방법은 여러가지입니다. 이 튜토리얼에서는 정수 키 값을 증가시켜 **Instruction Map** 에 들어있는 할당 값을 표시하도록 하겠습니다. + [/REGION] + +1. 앞서 말씀드린 내용을 염두에 두고, **+ 신규 추가** 버튼을 클릭, 드롭다운 리스트에서 **Variable** (변수)를 선택합니다. + + ![](Step2_20.png) + +1. 변수 유형은 **Integer** 유형으로 설정하고, 이름은 `Key` 라 합니다. + + ![](Step2_21.png) + +1. 새로운 **Integer** 변수를 선언하고 정의한 이후, **Key** 를 끌어 블루프린트 이벤트 그래프에 놓은 뒤 드롭다운 리스트에서 **Get** 을 선택합니다. + + [REGION:lightbox] + [![](Step2_22.png)(w:600)](Step2_22.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. **Key** 노드를 끌어 놓고 **IncrementInt** 노드를 검색하여 추가합니다. + + [REGION:lightbox] + [![](Step2_23.png)(w:600)](Step2_23.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. 이제 **IncrementInt** 노드를 **Find** 노드에 연결합니다. + + [REGION:lightbox] + [![](Step2_24.png)(w:600)](Step2_24.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + + [REGION:note] + 이 튜토리얼 목적 상 타임 함수를 사용하여 **Key** 값을 증가시키도록 하겠습니다. + [/REGION] + +1. **Event Tick** 노드를 끌어 놓고, **Delay** 노드를 검색 추가합니다. + + [REGION:lightbox] + [![](Step2_25.png)(w:600)](Step2_25.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. 딜레이를 **2** 초로 설정한 뒤 **Delay** 노드를 **IncrementInt** 노드에 연결합니다. + + [REGION:lightbox] + [![](Step2_26.png)(w:600)](Step2_26.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. **Event BeginPlay** 노드를 끌어 놓고, **Branch** 노드를 검색 추가하여 연결합니다. + + [REGION:lightbox] + [![](Step2_27.png)(w:600)](Step2_27.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. **IncrementInt** 노드를 **Branch** 노드에 연결합니다. + + [REGION:lightbox] + [![](Step2_28.png)(w:600)](Step2_28.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. **Find** 노드에 속하는 **Boolean** 반환 값을 **Branch** 노드의 **Condition** 핀에 연결합니다. + + [REGION:lightbox] + [![](Step2_29.png)(w:600)](Step2_29.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + + [REGION:note] + **Find** 노드가 맵의 아이템을 찾는 데 성공하면, 노드는 true 를 반환합니다. 아니라면 **Find** 노드가 false 를 반환하는 경우, 맵에 제공된 키를 사용하는 아이템이 들어있지 않은 것입니다. + [/REGION] + +1. **Branch** 노드의 **True** 핀을 끌어놓고, **Set Text(TextRender)** 노드를 검색 추가 후 연결합니다. + + [REGION:lightbox] + [![](Step2_30.png)(w:600)](Step2_30.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + + [REGION:note] + 이 로직 브랜치는 컨테이너에 유효한 키-값 짝이 있는 경우 컨테이너에 할당된 값을 표시하도록 하는 것입니다. + [/REGION] + +1. 게임 내 컨테이너 값을 표시하려면, **Find** 노드의 Return Value 를 **Set Text** 노드의 **Value** 핀에 연결합니다. + + [REGION:lightbox] + [![](Step2_31.png)(w:600)](Step2_31.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. 이제 **Branch** 노드의 **False** 핀을 끌어 놓고, **Set Text(TextRender)** 노드를 검색 추가 후 연결합니다. + + [REGION:lightbox] + [![](Step2_32.png)(w:600)](Step2_32.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + + [REGION:note] + 이 로직 브랜치는 컨테이너에 유효한 키-값 짝이 없으면, 다른 것을 표시하도록 합니다. + [/REGION] + +1. **Branch** 노드의 **Value** 핀을 끌어 놓고, **ToText(string)** 노드를 검색 추가 후 연결합니다. + + [REGION:lightbox] + [![](Step2_33.png)(w:600)](Step2_33.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. 이제 읽어올 스트링을 정의합니다: `Now, shoot the blocks!`. + + [REGION:lightbox] + [![](Step2_34.png)(w:600)](Step2_34.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. 완성된 스크립트를 살펴본 후, **컴파일** 버튼을 누르고서 에디터의 **뷰포트** 인터페이스로 돌아갑니다. + + [REGION:lightbox] + [![](Step2_35.png)(w:600)](Step2_35.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. 에디터의 **뷰포트** 인터페이스에서 **플레이** 버튼을 클릭하여 새로 구현한 스크립트 작동을 확인합니다. + + [REGION:lightbox] + [![](Step2_36.png)(w:600)](Step2_36.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +## 최종 결과 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + DcskFd9UhlA + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +이제 새 블루프린트 맵을 정의했고, 컨테이너를 키-값 짝으로 채웠고, **TextRender** Actor 의 +블루프린트 이벤트 그래프에 만든 기본적인 로직으로 값을 표시했습니다. 약간 더 고급 작업 방법을 +배우려면, 다음 단계에서 맵에 키-값 짝을 추가하는 법, 이어서 +맵의 값을 표시하는 법을 살펴봅시다. + +[nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/3/WorkingWithMaps_3.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/3/WorkingWithMaps_3.CHN.udn new file mode 100644 index 000000000000..8fba512733b7 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/3/WorkingWithMaps_3.CHN.udn @@ -0,0 +1,459 @@ +INTSourceChangelist:0 +Availability:Docs +Title:3 - Adding Keys and Values to a Map +Description:Adding key-value pairs to a Blueprint Map, ultimately displaying the Map's keys and associated values. +Crumbs: +Parent:Engine/Blueprints/BP_HowTo/WorkingWithMaps +Version: 4.15 +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithMaps +Order:3 + +By now, you have a **TextRender** Actor displaying the associated values of a Blueprint Map that you defined in the previous step. +In this step, you'll learn how to **Add** a key-value pair to a Map, subsequently displaying the Map's keys and +associated values. + +[nav] + +1. From your project's **Content Browser**, double-click the **Display Map** TextRender Actor to open its Blueprint **Event Graph**. + + [REGION:lightbox] + [![](Step3_1.png)(w:600)](Step3_1.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. You should see the **Display Map** TextRender Actor Blueprint **Event Graph**, where you'll be able to add a new Blueprint Map, which you'll be able to **Add** a new key-value pair to, ultimately displaying the Map's keys and associated values to the **Viewport**. + + [REGION:lightbox] + [![](Step3_2.png)(w:600)](Step3_2.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. At this point in the tutorial, you'll want to create a new Blueprint Map container for the upcoming **Add** operation. Go ahead and right-click on the **Instruction Map** variable and select **Duplicate** from the drop-down list to create a new Blueprint Map variable, naming it `Weapon Inventory Map`. + + [REGION:lightbox] + [![](Step3_3.png)(w:600)](Step3_3.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Please make sure that the new Map container matches the following properties, where the key is a String and the value is an Integer: + + ![](Step3_4.png) + + [REGION:note] + For illustrative purposes, you're creating a weapon inventory Blueprint Map container, where the key is the weapon name and the value is how much ammunication is available for the weapon. + [/REGION] + +1. If you select your new Blueprint Map, the **Default Value** message should be visible. + + [REGION:lightbox] + [![](Step3_5.png)(w:600)](Step3_5.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Go ahead and click the **Compile** button. + + [REGION:lightbox] + [![](Step3_6.png)(w:600)](Step3_6.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After compiling the Blueprint, you should see the **Default Value** disappear, making way for a default key-value pair. + + [REGION:lightbox] + [![](Step3_7.png)(w:600)](Step3_7.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. At this point, the editor should also emit the following warning: + + [REGION:lightbox] + [![](Step3_8.png)(w:600)](Step3_8.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + UE4 emits this warning because you're duplicating **Instruction Map**, which is a Blueprint map having an Integer-String key-value property, to create a **Weapon Inventory Map**, which is a Blueprint Map having a String-Integer key-value property. + During the duplication process, the engine parses key-value pairs belonging to **Instruction Map**, attempting to copy them into the key-value pairs for **Weapon Inventory Map**, which is undesired behavior. + [/REGION] + +1. Go ahead and fill your new **Weapon Inventory Map** container with the following key-value pairs: + + [REGION:lightbox] + [![](Step3_9.png)(w:600)](Step3_9.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, click the **Compile** button. + + [REGION:lightbox] + [![](Step3_10.png)(w:600)](Step3_10.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After filling the **Weapon Inventory Map** container with the appropriately typed key-value pairs, satisfying the new Blueprint Map's key-value property requirements, you should see the warning disappear. + + [REGION:lightbox] + [![](Step3_11.png)(w:600)](Step3_11.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Before you can add new logic to the existing Blueprint Event Graph, go ahead and drag the **Weapon Inventory Map** variable into the Blueprint. + + [REGION:lightbox] + [![](Step3_12.png)(w:600)](Step3_12.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +## Scripting the Logic + +1. To get started with building your new logic, drag off the **Weapon Inventory Map** node and add the **Keys** node from the **Map Utilities** interface. + + [REGION:lightbox] + [![](Step3_13.png)(w:600)](Step3_13.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + The **Keys** node will output an Array of all keys that are present in your **Weapon Inventory Map**. + [/REGION] + +1. Drag off the **Array** output pin belonging to the **Keys** node, search for, and add the **ForEachLoop** node. + + [REGION:lightbox] + [![](Step3_14.png)(w:600)](Step3_14.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, drag off the **Array Element** pin belonging to the **ForEachLoop** node, search for, and add the **Print String** node. + + [REGION:lightbox] + [![](Step3_15.png)(w:600)](Step3_15.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Right-click in the Blueprint Graph to open the **Context Menu**, where you'll search for and add **Event ActorBeginOverlap**. + + [REGION:lightbox] + [![](Step3_16.png)(w:600)](Step3_16.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Drag off the **Other Actor** pin of the **Event ActorBeginOverlap** node, search for, and add the **Cast To FirstPersonProjectile** node. + + [REGION:lightbox] + [![](Step3_17.png)(w:600)](Step3_17.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, connect the **Cast To FirstPersonProjectile** node to the **Keys** node. + + [REGION:lightbox] + [![](Step3_18.png)(w:600)](Step3_18.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +### Displaying your Map's Keys + +At this point, if you enter Play in Editor (PIE) mode, you'll be able to fire a projectile at the collision box for your **Display Map** Text Render Actor, where you'll be able to display an Array of keys that are contained in your **Weapon Inventory Map**. + +[REGION:lightbox] + [![](Step3_DisplayingKeys.png)(w:600)](Step3_DisplayingKeys.png) +[/REGION] + +[REGION:caption] + Click for full image. +[/REGION] + +## Finishing the Script + +1. Now's the time to add a new key-value pair to your container. To do this, go ahead and drag the **Weapon Inventory Map** variable into the Blueprint. + + [REGION:lightbox] + [![](Step3_19.png)(w:600)](Step3_19.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Drag off the **Weapon Inventory Map** variable, adding the **Add** node from the **Map Utilities** interface. + + [REGION:lightbox] + [![](Step3_20.png)(w:600)](Step3_20.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, define the key-value pair that you'd like to add, defining `Weapon 6` as the key and `60` as the value. + + [REGION:lightbox] + [![](Step3_21.png)(w:600)](Step3_21.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Drag off the **Add** node's **Boolean Return Value** pin, search for, and add the **Branch** node. + + [REGION:lightbox] + [![](Step3_22.png)(w:600)](Step3_22.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Before you can set up the additional display logic, showing your added key, you'll need to drag the **Weapon Inventory Map** variable into the Blueprint. + + [REGION:lightbox] + [![](Step3_23.png)(w:600)](Step3_23.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, drag off the **Weapon Inventory Map** variable, adding the **Keys** node from the **Map Utilities** interface. + + [REGION:lightbox] + [![](Step3_24.png)(w:600)](Step3_24.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Drag off the **Array** output pin belonging to the **Keys** node, search for, and add the **ForEachLoop** node. + + [REGION:lightbox] + [![](Step3_25.png)(w:600)](Step3_25.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, drag off the **Array Element** pin belonging to the **ForEachLoop** node, search for, and add the **Print String** node. + + [REGION:lightbox] + [![](Step3_26.png)(w:600)](Step3_26.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Click on the **Text Color** box to open the **Color Picker** menu. + + [REGION:lightbox] + [![](Step3_27.png)(w:600)](Step3_27.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Go ahead and set the color to the following values: + + ![](Step3_28.png) + +1. Again, before you can set up more display logic, showing your added value, you'll need to drag the **Weapon Inventory Map** variable into the Blueprint. + + [REGION:lightbox] + [![](Step3_29.png)(w:600)](Step3_29.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, drag off the **Weapon Inventory Map** variable, adding the **Values** node from the **Map Utilities** interface. + + [REGION:lightbox] + [![](Step3_30.png)(w:600)](Step3_30.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Drag off the **Array** output pin belonging to the **Values** node, search for, and add the **ForEachLoop** node. + + [REGION:lightbox] + [![](Step3_31.png)(w:600)](Step3_31.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, drag off the **Execute Output** pin belonging to the **ForEachLoop** node, search for, and add the **Print String** node. + + [REGION:lightbox] + [![](Step3_32.png)(w:600)](Step3_32.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Drag off the **Array Element** pin belonging to the **ForEachLoop** node, connecting it to the **In String** pin belonging to the **Print String** node. + + [REGION:lightbox] + [![](Step3_33.png)(w:600)](Step3_33.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Click on the **Text Color** box to open the **Color Picker** menu. + + [REGION:lightbox] + [![](Step3_34.png)(w:600)](Step3_34.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Go ahead and set the color to the following values: + + ![](Step3_35.png) + +1. Connect the **Branch** node's **True** pin to the **Keys** node. + + [REGION:lightbox] + [![](Step3_36.png)(w:600)](Step3_36.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, connect the **Branch** node's **False** pin to the **Values** node. + + [REGION:lightbox] + [![](Step3_37.png)(w:600)](Step3_37.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. To complete the script's logic, go ahead and connect the **Cast Failed** pin of the **Cast To FirstPersonProjectile** node to the **Add** node. + + [REGION:lightbox] + [![](Step3_38.png)(w:600)](Step3_38.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After inspecting your completed script, go ahead and click the **Compile** button. + + [REGION:lightbox] + [![](Step3_39.png)(w:600)](Step3_39.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Finally, click the **Save** button before going back to the Editor's **Viewport** interface. + + [REGION:lightbox] + [![](Step3_40.png)(w:600)](Step3_40.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. From the Editor's **Viewport** interface, click the **Play** button to see the updated script at work. + + [REGION:lightbox] + [![](Step3_41.png)(w:600)](Step3_41.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +## End Result + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 960 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 540 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + SJbsl6g7UME + [/PARAMLITERAL] +[/OBJECT] + +As you can see from the video, when you initially fire a **First Person Projectile** the **Display Map** TextRender Actor's collision box, you'll see the original five keys being printed to the **Viewport**. +Then, when you walk through the collision box, you'll see the new key being added, subsequently being printed. After backing out of the collision box, go ahead and fire another **First Person Projectile** to confirm +the newly added key. Finally, when you walk through the collision box for a second time, you'll see all of the values being printed. + +[nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/3/WorkingWithMaps_3.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/3/WorkingWithMaps_3.INT.udn new file mode 100644 index 000000000000..523aa2b424d2 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/3/WorkingWithMaps_3.INT.udn @@ -0,0 +1,459 @@ +Availability:Docs +Title:3 - Adding Keys and Values to a Map +Description:Adding key-value pairs to a Blueprint Map, ultimately displaying the Map's keys and associated values. +Crumbs:%ROOT% +Parent:Engine/Blueprints/BP_HowTo/WorkingWithMaps +Version: 4.15 +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithMaps +Order:3 + +By now, you have a **TextRender** Actor displaying the associated values of a Blueprint Map that you defined in the previous step. +In this step, you'll learn how to **Add** a key-value pair to a Map, subsequently displaying the Map's keys and +associated values. + +[nav] + +1. From your project's **Content Browser**, double-click the **Display Map** TextRender Actor to open its Blueprint **Event Graph**. + + [REGION:lightbox] + [![](Step3_1.png)(w:600)](Step3_1.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. You should see the **Display Map** TextRender Actor Blueprint **Event Graph**, where you'll be able to add a new Blueprint Map, which you'll be able to **Add** a new key-value pair to, ultimately displaying the Map's keys and associated values to the **Viewport**. + + [REGION:lightbox] + [![](Step3_2.png)(w:600)](Step3_2.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. At this point in the tutorial, you'll want to create a new Blueprint Map container for the upcoming **Add** operation. Go ahead and right-click on the **Instruction Map** variable and select **Duplicate** from the drop-down list to create a new Blueprint Map variable, naming it `Weapon Inventory Map`. + + ![](Step3_3.png) + +1. Please make sure that the new Map container matches the following properties, where the key is a String and the value is an Integer: + + ![](Step3_4.png) + + [REGION:note] + For illustrative purposes, you're creating a weapon inventory Blueprint Map container, where the key is the weapon name and the value is how much ammunication is available for the weapon. + [/REGION] + +1. If you select your new Blueprint Map, the **Default Value** message, saying `Please compile the blueprint`, should be visible. + + [REGION:lightbox] + [![](Step3_5.png)(w:600)](Step3_5.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Go ahead and click the **Compile** button. + + [REGION:lightbox] + [![](Step3_6.png)(w:600)](Step3_6.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After compiling the Blueprint, you should see the **Default Value** disappear, making way for a default key-value pair. + + [REGION:lightbox] + [![](Step3_7.png)(w:600)](Step3_7.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. At this point, the editor should also emit the following warning: + + [REGION:lightbox] + [![](Step3_8.png)(w:600)](Step3_8.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + UE4 emits this warning because you're duplicating **Instruction Map**, which is a Blueprint map having an Integer-String key-value property, to create a **Weapon Inventory Map**, which is a Blueprint Map having a String-Integer key-value property. + During the duplication process, the engine parses key-value pairs belonging to **Instruction Map**, attempting to copy them into the key-value pairs for **Weapon Inventory Map**, which is undesired behavior. + [REGION:lightbox] + [![](Step3_8Note.png)(w:600)](Step3_8Note.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + [/REGION] + +1. Go ahead and fill your new **Weapon Inventory Map** container with the following key-value pairs: + + ![](Step3_9.png) + +1. Now, click the **Compile** button. + + [REGION:lightbox] + [![](Step3_10.png)(w:600)](Step3_10.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After filling the **Weapon Inventory Map** container with the appropriately typed key-value pairs, satisfying the new Blueprint Map's key-value property requirements, you should see the warning disappear. + + [REGION:lightbox] + [![](Step3_11.png)(w:600)](Step3_11.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Before you can add new logic to the existing Blueprint Event Graph, go ahead and drag the **Weapon Inventory Map** variable into the Blueprint. + + [REGION:lightbox] + [![](Step3_12.png)(w:600)](Step3_12.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +## Scripting the Logic + +1. To get started with building your new logic, drag off the **Weapon Inventory Map** node and add the **Keys** node from the **Map Utilities** interface. + + [REGION:lightbox] + [![](Step3_13.png)(w:600)](Step3_13.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + The **Keys** node will output an Array of all keys that are present in your **Weapon Inventory Map**. + [/REGION] + +1. Drag off the **Array** output pin belonging to the **Keys** node, search for, and add the **ForEachLoop** node. + + [REGION:lightbox] + [![](Step3_14.png)(w:600)](Step3_14.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, drag off the **Array Element** pin belonging to the **ForEachLoop** node, search for, and add the **Print String** node. + + [REGION:lightbox] + [![](Step3_15.png)(w:600)](Step3_15.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Right-click in the Blueprint Graph to open the **Context Menu**, where you'll search for and add **Event ActorBeginOverlap**. + + [REGION:lightbox] + [![](Step3_16.png)(w:600)](Step3_16.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Drag off the **Other Actor** pin of the **Event ActorBeginOverlap** node, search for, and add the **Cast To FirstPersonProjectile** node. + + [REGION:lightbox] + [![](Step3_17.png)(w:600)](Step3_17.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, connect the **Cast To FirstPersonProjectile** node to the **Keys** node. + + [REGION:lightbox] + [![](Step3_18.png)(w:600)](Step3_18.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +### Displaying your Map's Keys + +At this point, if you enter Play in Editor (PIE) mode, you'll be able to fire a projectile at the collision box for your **Display Map** Text Render Actor, where you'll be able to display an Array of keys that are contained in your **Weapon Inventory Map**. + +[REGION:lightbox] + [![](Step3_DisplayingKeys.png)(w:600)](Step3_DisplayingKeys.png) +[/REGION] + +[REGION:caption] + Click for full image. +[/REGION] + +## Finishing the Script + +1. Now's the time to add a new key-value pair to your container. To do this, go ahead and drag the **Weapon Inventory Map** variable into the Blueprint. + + [REGION:lightbox] + [![](Step3_19.png)(w:600)](Step3_19.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Drag off the **Weapon Inventory Map** variable, adding the **Add** node from the **Map Utilities** interface. + + [REGION:lightbox] + [![](Step3_20.png)(w:600)](Step3_20.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, define the key-value pair that you'd like to add, defining `Weapon 6` as the key and `60` as the value. + + [REGION:lightbox] + [![](Step3_21.png)(w:600)](Step3_21.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Drag off the **Add** node's **Boolean Return Value** pin, search for, and add the **Branch** node. + + [REGION:lightbox] + [![](Step3_22.png)(w:600)](Step3_22.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Before you can set up the additional display logic, showing your added key, you'll need to drag the **Weapon Inventory Map** variable into the Blueprint. + + [REGION:lightbox] + [![](Step3_23.png)(w:600)](Step3_23.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, drag off the **Weapon Inventory Map** variable, adding the **Keys** node from the **Map Utilities** interface. + + [REGION:lightbox] + [![](Step3_24.png)(w:600)](Step3_24.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Drag off the **Array** output pin belonging to the **Keys** node, search for, and add the **ForEachLoop** node. + + [REGION:lightbox] + [![](Step3_25.png)(w:600)](Step3_25.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, drag off the **Array Element** pin belonging to the **ForEachLoop** node, search for, and add the **Print String** node. + + [REGION:lightbox] + [![](Step3_26.png)(w:600)](Step3_26.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Click on the **Text Color** box to open the **Color Picker** menu. + + [REGION:lightbox] + [![](Step3_27.png)(w:600)](Step3_27.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Go ahead and set the color to the following values: + + ![](Step3_28.png) + +1. Again, before you can set up more display logic, showing your added value, you'll need to drag the **Weapon Inventory Map** variable into the Blueprint. + + [REGION:lightbox] + [![](Step3_29.png)(w:600)](Step3_29.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, drag off the **Weapon Inventory Map** variable, adding the **Values** node from the **Map Utilities** interface. + + [REGION:lightbox] + [![](Step3_30.png)(w:600)](Step3_30.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Drag off the **Array** output pin belonging to the **Values** node, search for, and add the **ForEachLoop** node. + + [REGION:lightbox] + [![](Step3_31.png)(w:600)](Step3_31.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, drag off the **Execute Output** pin belonging to the **ForEachLoop** node, search for, and add the **Print String** node. + + [REGION:lightbox] + [![](Step3_32.png)(w:600)](Step3_32.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Drag off the **Array Element** pin belonging to the **ForEachLoop** node, connecting it to the **In String** pin belonging to the **Print String** node. + + [REGION:lightbox] + [![](Step3_33.png)(w:600)](Step3_33.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Click on the **Text Color** box to open the **Color Picker** menu. + + [REGION:lightbox] + [![](Step3_34.png)(w:600)](Step3_34.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Go ahead and set the color to the following values: + + ![](Step3_35.png) + +1. Connect the **Branch** node's **True** pin to the **Keys** node. + + [REGION:lightbox] + [![](Step3_36.png)(w:600)](Step3_36.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, connect the **Branch** node's **False** pin to the **Values** node. + + [REGION:lightbox] + [![](Step3_37.png)(w:600)](Step3_37.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. To complete the script's logic, go ahead and connect the **Cast Failed** pin of the **Cast To FirstPersonProjectile** node to the **Add** node. + + [REGION:lightbox] + [![](Step3_38.png)(w:600)](Step3_38.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After inspecting your completed script, go ahead and click the **Compile** button. + + [REGION:lightbox] + [![](Step3_39.png)(w:600)](Step3_39.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Finally, click the **Save** button before going back to the Editor's **Viewport** interface. + + [REGION:lightbox] + [![](Step3_40.png)(w:600)](Step3_40.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. From the Editor's **Viewport** interface, click the **Play** button to see the updated script at work. + + [REGION:lightbox] + [![](Step3_41.png)(w:600)](Step3_41.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +## End Result + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + SJbsl6g7UME + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +As you can see from the video, when you initially fire a **First Person Projectile** the **Display Map** TextRender Actor's collision box, you'll see the original five keys being printed to the **Viewport**. +Then, when you walk through the collision box, you'll see the new key being added, subsequently being printed. After backing out of the collision box, go ahead and fire another **First Person Projectile** to confirm +the newly added key. Finally, when you walk through the collision box for a second time, you'll see all of the values being printed. + +[nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/3/WorkingWithMaps_3.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/3/WorkingWithMaps_3.JPN.udn new file mode 100644 index 000000000000..15f87e16448b --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/3/WorkingWithMaps_3.JPN.udn @@ -0,0 +1,461 @@ +INTSourceChangelist:3413824 +Availability:Docs +Title:3 - キーと値を Map に追加する +Description:キー / 値のペアを Blueprint Map に追加して、最終的に Map のキーおよび関連づいている値を表示する +Crumbs:%ROOT% +Parent:Engine/Blueprints/BP_HowTo/WorkingWithMaps +Version:4.15 +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithMaps +Order:3 + +前のステップでは **TextRender** アクタが Blueprint Map の関連付けられた値を表示するように定義をしました。 +このステップでは、キー / 値のペアを Map に **追加** して、 +Map のキーと関連付けられた値を結果として表示する方法を説明します。 + +[nav] + +1. プロジェクトの **コンテンツ ブラウザ** から **Display Map** TextRender アクタをダブルクリックして、ブループリント **イベントグラフ** を開きます。 + + [REGION:lightbox] + [![](Step3_1.png)(w:600)](Step3_1.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Display Map** TextRender アクタのブループリント **イベントグラフ** が表示されます。ここで、新しくキー / 値のペアを **追加** して、最終的に Map のキーと関連付けられた値を **ビューポート** に表示します。 + + [REGION:lightbox] + [![](Step3_2.png)(w:600)](Step3_2.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. ここで、これから使う **Add** 演算用に Blueprint Map コンテナを新規作成する必要があります。**Instruction Map** 変数を右クリックしてドロップダウン リストから **[Duplicate]** を選択し、新規の Blueprint Map 変数を作成し、「`Weapon Inventory Map`」と名前を付けます。 + + ![](Step3_3.png) + +1. 新規作成した Map コンテナが以下のプロパティと一致するようにしてください。キーは String 型、値は Integer 型です + + ![](Step3_4.png) + + [REGION:note] + 説明のため、武器名をキー、その武器が使用できる銃弾数を値にして、Weapon Inventory Blueprint Map コンテナを作成します。 + [/REGION] + +1. その Blueprint Map を選択すると「`Please compile the blueprint`(ブループリントをコンパイルしてください)」という **[Default Value]** メッセージが表示されます。 + + [REGION:lightbox] + [![](Step3_5.png)(w:600)](Step3_5.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **[Compile]** ボタンをクリックします。 + + [REGION:lightbox] + [![](Step3_6.png)(w:600)](Step3_6.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. ブループリントのコンパイルを完了すると **Default Value** メッセージが消えて今度はデフォルトのキー / 値のペアが表示されます。 + + [REGION:lightbox] + [![](Step3_7.png)(w:600)](Step3_7.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. ここでエディタは以下の警告も出します。 + + [REGION:lightbox] + [![](Step3_8.png)(w:600)](Step3_8.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + + [REGION:note] + + キーと値のプロパティがそれぞれ Integer-String 型の Blueprint マップである **Weapon Inventory Map** を作成するために、キーと値のプロパティがそれぞれ Integer-String 型の Blueprint マップを複製したため、UE4 がこの警告を出しました。 + 複製中、エンジンは、**Weapon Inventory Map** のキー / 値のペアへそれらをコピーしようとして、**Instruction Map** に属するキー / 値のペアをパースし、それが警告の原因のビヘイビアとなりました。 + [REGION:lightbox] + [![](Step3_8Note.png)(w:600)](Step3_8Note.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + [/REGION] + +1. 次のキー / 値のペアを **Weapon Inventory Map** コンテナに入力します。 + + ![](Step3_9.png) + +1. **[Compile]** ボタンをクリックします。 + + [REGION:lightbox] + [![](Step3_10.png)(w:600)](Step3_10.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Weapon Inventory Map** コンテナにキー / 値のペアを正しく入力し、新しい Blueprint マップのキー / 値のプロパティ要件を満たすと、警告が消えます。 + + [REGION:lightbox] + [![](Step3_11.png)(w:600)](Step3_11.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 新規ロジックを既存のブループリント イベントグラフに追加する前に、**Weapon Inventory Map** 変数をブループリントにドラッグします。 + + [REGION:lightbox] + [![](Step3_12.png)(w:600)](Step3_12.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +## ロジックのスクリプト処理 + +1. 新規ロジックをビルドするには、**Weapon Inventory Map** ノードを引き出して **Map Utilities** インターフェースから **Keys** ノードを追加します。 + + [REGION:lightbox] + [![](Step3_13.png)(w:600)](Step3_13.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + + [REGION:note] + **Keys** ノードは、**Weapon Inventory Map** に存在するすべてのキーの Array を出力します。 + [/REGION] + +1. **Keys** ノードに属する **To Array** 出力を引き出して **ForEachLoop** ノードを探して追加します。 + + [REGION:lightbox] + [![](Step3_14.png)(w:600)](Step3_14.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **ForEachLoop** ノードに属する **Array Element** ピンを引き出して **Print String** ノードを探して追加します。 + + [REGION:lightbox] + [![](Step3_15.png)(w:600)](Step3_15.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. ブループリント グラフ内を右クリックして **コンテキスト メニュー** を開き、**Event ActorBeginOverlap** を探して追加します。 + + [REGION:lightbox] + [![](Step3_16.png)(w:600)](Step3_16.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Event ActorBeginOverlap** ノードから **Other Actor** ピンを引き出して、**Cast To FirstPersonProjectile** ノードを探して追加します。 + + [REGION:lightbox] + [![](Step3_17.png)(w:600)](Step3_17.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Cast To FirstPersonProjectile** ノードを **Keys** ノードに接続します。 + + [REGION:lightbox] + [![](Step3_18.png)(w:600)](Step3_18.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +### マップのキーを表示する + +この時点で Play in Editor (PIE) モードになっていると、**Display Map** Text Render Actor のコリジョン ボックスへ発射物を発砲し、**Weapon Inventory Map** に含まれるキーの Array を表示することができます。 + +[REGION:lightbox] + [![](Step3_DisplayingKeys.png)(w:600)](Step3_DisplayingKeys.png) +[/REGION] + +[REGION:caption] + クリックしてフルサイズで表示 +[/REGION] + +## スクリプト処理を終了する + +1. いよいよキー / 値のペアをコンテナに追加します。**Weapon Inventory Map** 変数をブループリントにドラッグします。 + + [REGION:lightbox] + [![](Step3_19.png)(w:600)](Step3_19.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Weapon Inventory Map** 変数を引き出して、**Map Utilities** インターフェースから **Add** ノードを追加します。 + + [REGION:lightbox] + [![](Step3_20.png)(w:600)](Step3_20.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. ここで追加したいキー / 値のペアを定義します。キーを `Weapon 6`、値を `60` に定義します。 + + [REGION:lightbox] + [![](Step3_21.png)(w:600)](Step3_21.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Add** ノードの **Boolean Return Value** ピンを引き出して、**Branch** ノードを探して追加します。 + + [REGION:lightbox] + [![](Step3_22.png)(w:600)](Step3_22.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 追加したキーを表示する表示ロジックを設定する前に、**Weapon Inventory Map** 変数をブループリントにドラッグする必要があります。 + + [REGION:lightbox] + [![](Step3_23.png)(w:600)](Step3_23.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Weapon Inventory Map** 変数を引き出して、**Map Utilities** インターフェースから **Keys** ノードを追加します。 + + [REGION:lightbox] + [![](Step3_24.png)(w:600)](Step3_24.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Keys** ノードに属する **To Array** 出力を引き出して **ForEachLoop** ノードを探して追加します。 + + [REGION:lightbox] + [![](Step3_25.png)(w:600)](Step3_25.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **ForEachLoop** ノードに属する **Array Element** ピンを引き出して **Print String** ノードを探して追加します。 + + [REGION:lightbox] + [![](Step3_26.png)(w:600)](Step3_26.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **[Text Color]** ボックスをクリックして **[Color Picker]** メニューを開きます。 + + [REGION:lightbox] + [![](Step3_27.png)(w:600)](Step3_27.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 色を以下の値に設定します。 + + ![](Step3_28.png) + +1. 追加した値を表示する表示ロジックも設定しますが、やはりその前に **Weapon Inventory Map** 変数をブループリントにドラッグする必要があります。 + + [REGION:lightbox] + [![](Step3_29.png)(w:600)](Step3_29.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Weapon Inventory Map** 変数を引き出して、**Map Utilities** インターフェースから **Values** ノードを追加します。 + + [REGION:lightbox] + [![](Step3_30.png)(w:600)](Step3_30.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Values** ノードに属する **To Array** 出力を引き出して **ForEachLoop** ノードを探して追加します。 + + [REGION:lightbox] + [![](Step3_31.png)(w:600)](Step3_31.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **ForEachLoop** ノードに属する **Execute Output** ピンを引き出して **Print String** ノードを探して追加します。 + + [REGION:lightbox] + [![](Step3_32.png)(w:600)](Step3_32.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **ForEachLoop** ノードに属する **Array Element** ピンを引き出して **Print String** ノードに属する **In String** に接続します。 + + [REGION:lightbox] + [![](Step3_33.png)(w:600)](Step3_33.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **[Text Color]** ボックスをクリックして **[Color Picker]** メニューを開きます。 + + [REGION:lightbox] + [![](Step3_34.png)(w:600)](Step3_34.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 色を以下の値に設定します。 + + ![](Step3_35.png) + +1. **Branch** ノードの **True** ピンを **Keys** に接続します。 + + [REGION:lightbox] + [![](Step3_36.png)(w:600)](Step3_36.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 次に **Branch** ノードの **False** ピンを **Values** に接続します。 + + [REGION:lightbox] + [![](Step3_37.png)(w:600)](Step3_37.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Cast To FirstPersonProjectile** ノードの **Cast Failed** ピンを **Add** ノードに接続すれば、スクリプトのロジックが完成します。 + + [REGION:lightbox] + [![](Step3_38.png)(w:600)](Step3_38.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 完成したスクリプトを確認したら、**[Compile]** ボタンをクリックします。 + + [REGION:lightbox] + [![](Step3_39.png)(w:600)](Step3_39.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 最後に、完成したスクリプト全体を確認したら、エディタの **Viewport** インターフェースに戻る前に **[Save]** ボタンをクリックします。 + + [REGION:lightbox] + [![](Step3_40.png)(w:600)](Step3_40.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. エディタの **Viewport** インターフェースで、**[Play]** ボタンをクリックして更新されたスクリプトの動きを確認します。 + + [REGION:lightbox] + [![](Step3_41.png)(w:600)](Step3_41.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +## 結果 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + SJbsl6g7UME + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +動画を見ると分かりますが、**First Person Projectile** が **Display Set** TextRender Actor のコリジョン ボックスに発射されると、元の 5 つのキーが **Viewport** に出力されます。 +コリジョン ボックスを通り抜ける時に、キーが追加され、その後で出力されます。コリジョン ボックスを後ろに動かす前に、もう 1 回 **First Person Projectile** を発射して、 +キーが新しく追加されたか確認します。2 回目にコリジョン ボックスを通り抜ける時、すべての値の出力が確認できます。 + +[nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/3/WorkingWithMaps_3.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/3/WorkingWithMaps_3.KOR.udn new file mode 100644 index 000000000000..a32294eb40bf --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/3/WorkingWithMaps_3.KOR.udn @@ -0,0 +1,460 @@ +INTSourceChangelist:3413824 +Availability:Docs +Title:3 - 맵에 키 및 값 추가 +Description:블루프린트 맵에 키-값 짝을 추가하고, 최종적으로 맵의 키와 할당된 값을 표시합니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/BP_HowTo/WorkingWithMaps +Version: 4.15 +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithMaps +Order:3 + +이제 예전 단계에서 정의한 블루프린트 맵에 할당된 값을 표시하는 **TextRender** Actor 가 있을 것입니다. +이번 단계에서는, 맵에 키-값 짝을 **추가** 하는 방법, 이어서 맵의 키와 할당된 값을 표시하는 +방법을 살펴보겠습니다. + +[nav] + +1. 프로젝트의 **콘텐츠 브라우저** 에서 **Display Map** TextRender Actor 에 더블클릭하여 블루프린트 **이벤트 그래프** 를 엽니다. + + [REGION:lightbox] + [![](Step3_1.png)(w:600)](Step3_1.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. **Display Map** TextRender Actor 블루프린트 **이벤트 그래프** 가 보일 것입니다. 여기서 새 블루프린트 맵을 추가하고, 새로운 키-값 짝을 **추가** 한 뒤, 최종적으로 맵의 키와 할당된 값을 **뷰포트** 에 표시할 수 있습니다. + + [REGION:lightbox] + [![](Step3_2.png)(w:600)](Step3_2.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. 튜토리얼 이 시점에서 곧 하려는 **Add** 연산에 쓸 블루프린트 맵 컨테이너를 새로 만들어줄 것입니다. **Instruction Map** 변수에 우클릭하고 드롭다운 목록에서 **복제** 를 선택하여 새 블루프린트 맵 변수를 생성하고, 이름을 `Weapon Inventory Map` 이라 합니다. + + ![](Step3_3.png) + +1. 새 맵 컨테이너의 프로퍼티가 다음과 같은지 확인합니다. 키는 String, 값은 Integer 입니다: + + ![](Step3_4.png) + + [REGION:note] + 데모 목적 상 무기 인벤토리 블루프린트 맵 컨테이너를 만들고, 여기서 키는 무기 이름이며 값은 그 무기에 쓸 수 있는 탄환 수입니다. + [/REGION] + +1. 새 블루프린트 맵을 선택하면, **Default Value** 메시지가 보일 것입니다. + + [REGION:lightbox] + [![](Step3_5.png)(w:600)](Step3_5.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. 계속해서 **컴파일** 버튼을 클릭합니다. + + [REGION:lightbox] + [![](Step3_6.png)(w:600)](Step3_6.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. 블루프린트 컴파일 후 **Default Value** 가 사라져 기본 키-값에 자리를 내어주는 것이 보일 것입니다. + + [REGION:lightbox] + [![](Step3_7.png)(w:600)](Step3_7.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. 이제 에디터에 다음과 같은 경고가 날 것입니다: + + [REGION:lightbox] + [![](Step3_8.png)(w:600)](Step3_8.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + + [REGION:note] + UE4 에서 이 경고를 내는 이유는 **Instruction Map** 을 복제했기 때문인데, 이는 Integer-String 키-값 프로퍼티를 갖는 블루프린트 맵으로 String-Integer 키-값 짝을 갖는 **Weapon Inventory Map** 을 만들려 했기 때문입니다. + 복제 과정에서 엔진은 **Instruction Map** 에 속하는 키-값 짝을 분석한 뒤 **Weapon Inventory Map** 에 맞는 키-값 짝으로 복사해 넣으려 시도하는데, 바람직하지 않은 작동방식입니다. + [REGION:lightbox] + [![](Step3_8Note.png)(w:600)](Step3_8Note.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + [/REGION] + +1. 새로운 **Weapon Inventory Map** 컨테이너를 다음 키-값 짝으로 채웁니다: + + ![](Step3_9.png) + +1. 이제 **컴파일** 버튼을 클릭합니다. + + [REGION:lightbox] + [![](Step3_10.png)(w:600)](Step3_10.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. **Weapon Inventory Map** 컨테이너를 적합한 유형의 키-값 짝으로 채우고, 새로운 블루프린트 맵의 키-값 짝 요건을 만족시킨 후에는 경고가 사라지는 것이 보일 것입니다. + + [REGION:lightbox] + [![](Step3_11.png)(w:600)](Step3_11.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. 기존 블루프린트 이벤트 그래프에 새 로직을 추가하기에 앞서, **Weapon Inventory Map** 변수를 블루프린트에 끌어 놓습니다. + + [REGION:lightbox] + [![](Step3_12.png)(w:600)](Step3_12.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +## 로직 스크립트 작성 + +1. 새 로직 작성을 시작하려면, **Weapon Inventory Map** 노드를 끌어 놓고 **Map Utilities** 인터페이스에서 **Keys** 노드를 추가합니다. + + [REGION:lightbox] + [![](Step3_13.png)(w:600)](Step3_13.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + + [REGION:note] + **Keys** 노드는 **Weapon Inventory Map** 에 존재하는 모든 키 배열을 출력합니다. + [/REGION] + +1. **Keys** 노드에 속하는 **Array** 출력 핀을 끌어 놓고, **ForEachLoop** 노드를 검색 추가합니다. + + [REGION:lightbox] + [![](Step3_14.png)(w:600)](Step3_14.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. 이제 **ForEachLoop** 노드에 속하는 **Array Element** 핀을 끌어 놓고 **Print String** 노드를 검색 추가합니다. + + [REGION:lightbox] + [![](Step3_15.png)(w:600)](Step3_15.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. 블루프린트 그래프에 우클릭하여 **맥락 메뉴** 를 띄우고 **Event ActorBeginOverlap** 을 검색 추가합니다. + + [REGION:lightbox] + [![](Step3_16.png)(w:600)](Step3_16.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. **Event ActorBeginOverlap** 노드의 **Other Actor** 핀을 끌어 놓고 **Cast To FirstPersonProjectile** 노드를 검색 추가합니다. + + [REGION:lightbox] + [![](Step3_17.png)(w:600)](Step3_17.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. **Cast To FirstPersonProjectile** 노드를 **Keys** 노드에 연결합니다. + + [REGION:lightbox] + [![](Step3_18.png)(w:600)](Step3_18.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +### 맵의 키 표시 + +이제 에디터에서 플레이(PIE) 모드에 들어가면 **Display Map** Text Render Actor 의 콜리전 박스에 프로젝타일을 발사할 수 있을 것입니다. 이 액터에서 **Weapon Inventory Map** 에 들어있는 키 배열을 표시할 수 있습니다. + +[REGION:lightbox] + [![](Step3_DisplayingKeys.png)(w:600)](Step3_DisplayingKeys.png) +[/REGION] + +[REGION:caption] + 클릭하면 이미지 원본을 확인합니다. +[/REGION] + +## 스크립트 마무리 + +1. 컨테이너에 새로운 키-값 짝을 추가할 차례입니다. **Weapon Inventory Map** 변수를 블루프린트에 끌어 놓습니다. + + [REGION:lightbox] + [![](Step3_19.png)(w:600)](Step3_19.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. **Weapon Inventory Map** 변수를 끌어 놓고 **Map Utilities** 인터페이스의 **Add** 노드를 추가합니다. + + [REGION:lightbox] + [![](Step3_20.png)(w:600)](Step3_20.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. 이제 추가하고자 하는 키-값 짝을 정의합니다. 키에는 `Weapon 6`, 값에는 `60` 입니다. + + [REGION:lightbox] + [![](Step3_21.png)(w:600)](Step3_21.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. **Add** 노드의 **Boolean Return Value** 핀을 끌어 놓고 **Branch** 노드를 검색 추가합니다. + + [REGION:lightbox] + [![](Step3_22.png)(w:600)](Step3_22.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. 추가된 키를 표시하는 부가 표시 로직 구성에 앞서, **Weapon Inventory Map** 변수를 블루프린트에 끌어놓아야 합니다. + + [REGION:lightbox] + [![](Step3_23.png)(w:600)](Step3_23.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. 이제 **Weapon Inventory Map** 변수를 끌어 놓고 **Map Utilities** 인터페이스에서 **Keys** 노드를 추가합니다. + + [REGION:lightbox] + [![](Step3_24.png)(w:600)](Step3_24.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. **Keys** 노드에 속하는 **Array** 출력 핀을 끌어놓고, **ForEachLoop** 노드를 추가합니다. + + [REGION:lightbox] + [![](Step3_25.png)(w:600)](Step3_25.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. **ForEachLoop** 노드에 속하는 **Array Element** 핀을 끌어 놓고, **Print String** 노드를 검색 추가합니다. + + [REGION:lightbox] + [![](Step3_26.png)(w:600)](Step3_26.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. **Text Color** 를 클릭하여 **색 선택기** 메뉴를 엽니다. + + [REGION:lightbox] + [![](Step3_27.png)(w:600)](Step3_27.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. 색을 다음 값으로 설정합니다: + + ![](Step3_28.png) + +1. 여기서도 추가한 값을 표시하는 표시 로직을 구성하기에 앞서, **Weapon Inventory Map** 변수를 블루프린트에 끌어 놓아야 합니다. + + [REGION:lightbox] + [![](Step3_29.png)(w:600)](Step3_29.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. 이제 **Weapon Inventory Map** 변수를 끌어 놓고, **Map Utilities** 인터페이스에서 **Values** 노드를 추가합니다. + + [REGION:lightbox] + [![](Step3_30.png)(w:600)](Step3_30.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. **Values** 노드에 속하는 **Array** 출력을 끌어 놓고, **ForEachLoop** 노드를 검색 추가합니다. + + [REGION:lightbox] + [![](Step3_31.png)(w:600)](Step3_31.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. **ForEachLoop** 노드에 속하는 **Execute Output** 핀을 끌어 놓고, **Print String** 노드를 검색 추가합니다. + + [REGION:lightbox] + [![](Step3_32.png)(w:600)](Step3_32.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. **ForEachLoop** 노드에 속하는 **Array Element** 핀을 끌어 놓고, **Print String** 노드에 속하는 **In String** 핀에 연결합니다. + + [REGION:lightbox] + [![](Step3_33.png)(w:600)](Step3_33.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. **Text Color** 박스를 클릭하여 **색 선택기** 메뉴를 엽니다. + + [REGION:lightbox] + [![](Step3_34.png)(w:600)](Step3_34.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. 색을 다음 값으로 설정합니다: + + ![](Step3_35.png) + +1. **Branch** 노드의 **True** 핀을 **Keys** 노드에 연결합니다. + + [REGION:lightbox] + [![](Step3_36.png)(w:600)](Step3_36.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. **Branch** 노드의 **False** 핀을 **Values** 노드에 연결합니다. + + [REGION:lightbox] + [![](Step3_37.png)(w:600)](Step3_37.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. 스크립트의 로직을 완성을 위해, **Cast To FirstPersonProjectile** 노드의 **Cast Failed** 핀을 **Add** 노드에 연결합니다. + + [REGION:lightbox] + [![](Step3_38.png)(w:600)](Step3_38.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. 완성된 스크립트를 살펴본 후, **컴파일** 버튼을 클릭합니다. + + [REGION:lightbox] + [![](Step3_39.png)(w:600)](Step3_39.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. 마지막으로 **저장** 버튼을 누른 뒤 에디터의 **뷰포트** 인터페이스로 돌아갑니다. + + [REGION:lightbox] + [![](Step3_40.png)(w:600)](Step3_40.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. 에디터의 **뷰포트** 인터페이스에서 **플레이** 버튼을 클릭하여 업데이트된 스크립트가 작동하는 것을 확인해 봅니다. + + [REGION:lightbox] + [![](Step3_41.png)(w:600)](Step3_41.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +## 최종 결과 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + SJbsl6g7UME + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +비디오에서 볼 수 있듯이, **Display Map** TextRender Actor 의 콜리전 박스인 **First Person Projectile** 을 처음 발사하면, **뷰포트** 에 처음 다섯 개의 키가 출력되는 것이 보일 것입니다. +그리고 콜리전 박스를 통과해 걸어가면, 새로운 키가 추가되고 곧이어 출력되는 것이 보일 것입니다. 콜리전 박스를 빠져 나온 뒤 다시 **First Person Projectile** 을 발사해 보면 +새로 추가된 키를 확인할 수 있습니다. 마지막으로 콜리전 박스를 두 번째 걸어서 통과하면, 모든 값이 출력되는 것을 확인할 수 있습니다. + +[nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/WorkingWithMaps.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/WorkingWithMaps.CHN.udn new file mode 100644 index 000000000000..20bddfd096c4 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/WorkingWithMaps.CHN.udn @@ -0,0 +1,51 @@ +INTSourceChangelist:0 +Availability:Docs +Title:Working with Maps +Description:Learn how to work with Maps in Blueprints. +Crumbs:%ROOT% +Parent:Engine/Blueprints/Scripting +Order:3 +Version: 4.15 +Tags:Blueprint Map +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithMaps +Topic-image:workingWithMaps_topicImage.png + +[REGION:imagetable] +![](workingWithMaps_topicBanner.png) +_At the end of this tutorial, you'll gain experience working with Maps on Unreal Engine 4 (UE4)._ +[/REGION] + +After [](Engine/Blueprints/UserGuide/Arrays), there's a good reason why Blueprint Maps are so popular. They support efficient lookups and retrievals of values with the use of associated keys. + +## Goal + +This guide teaches you how to set up and work with a Blueprint Map. + +## Objectives + +After working through this tutorial, you'll know the following: + +* How to create and edit Maps in the Blueprint scripting environment. +* How to query and display items being contained in a Blueprint Map. +* How to perform basic operations on Blueprint Maps. + +[OBJECT:TopicList] + [PARAM:icon] + ![](%ROOT%/build_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + Steps + [/PARAM] + [PARAM:description] + [/PARAM] + [PARAM:links] + [DIR(output:"checkpoint" parent:"Engine/Blueprints/BP_HowTo/WorkingWithMaps" org:"hierarchy")] + [/PARAM] +[/OBJECT] + +[REGION:call_to_action] + [Click to Start](Engine/Blueprints/BP_HowTo/WorkingWithMaps/1 "%Engine/Blueprints/BP_HowTo/WorkingWithMaps/1:title%") +[/REGION] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/WorkingWithMaps.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/WorkingWithMaps.INT.udn new file mode 100644 index 000000000000..6e6355182ea9 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/WorkingWithMaps.INT.udn @@ -0,0 +1,51 @@ +Availability:Docs +Title:Working with Maps +Description:Learn how to work with Maps in Blueprints. +Crumbs:%ROOT% +Parent:Engine/Blueprints/Scripting +Order:3 +Version: 4.15 +Tags:Blueprint Map +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithMaps +Topic-image:workingWithMaps_topicImage.png +Related:Programming/UnrealArchitecture/TMap + +[REGION:imagetable] +![](workingWithMaps_topicBanner.png) +_At the end of this tutorial, you'll gain experience working with Maps on Unreal Engine 4 (UE4)._ +[/REGION] + +After [](Engine/Blueprints/UserGuide/Arrays), there's a good reason why Blueprint Maps are so popular. They support efficient lookups and retrievals of values with the use of associated keys. + +## Goal + +This guide teaches you how to set up and work with a Blueprint Map. + +## Objectives + +After working through this tutorial, you'll know the following: + +* How to create and edit Maps in the Blueprint scripting environment. +* How to query and display items being contained in a Blueprint Map. +* How to perform basic operations on Blueprint Maps. + +[OBJECT:TopicList] + [PARAM:icon] + ![](%ROOT%/build_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + Steps + [/PARAM] + [PARAM:description] + [/PARAM] + [PARAM:links] + [DIR(output:"checkpoint" parent:"Engine/Blueprints/BP_HowTo/WorkingWithMaps" org:"hierarchy")] + [/PARAM] +[/OBJECT] + +[REGION:call_to_action] + [Click to Start](Engine/Blueprints/BP_HowTo/WorkingWithMaps/1 "%Engine/Blueprints/BP_HowTo/WorkingWithMaps/1:title%") +[/REGION] diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/WorkingWithMaps.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/WorkingWithMaps.JPN.udn new file mode 100644 index 000000000000..52d13a4cb579 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/WorkingWithMaps.JPN.udn @@ -0,0 +1,52 @@ +INTSourceChangelist:3413824 +Availability:Docs +Title:Map を使用して作業する +Description:ブループリントでの Map の使用方法 +Crumbs:%ROOT% +Parent:Engine/Blueprints/Scripting +Order:3 +Version:4.15 +Tags:Blueprint Map +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithMaps +Topic-image:workingWithMaps_topicImage.png +Related:Programming/UnrealArchitecture/TMap + +[REGION:imagetable] +![](workingWithMaps_topicBanner.png) +_このチュートリアルを通して、アンリアル エンジン 4 (UE4) で実際に Map を使った作業を経験できます。_ +[/REGION] + +Blueprint Map は [](Engine/Blueprints/UserGuide/Arrays) に次いで人気が高いですが、それにはちゃんとした理由があります。関連付けられたキーを使って、効率の良い値の検索と抽出をサポートしているからです。 + +## 目標 + +このガイドでは、Blueprint Map を使った設定および作業方法を説明します。 + +## 目的 + +このチュートリアルでは、以下の習得を目指します。 + +* ブループリント スクリプト処理環境での Map の作成および編集方法 +* Blueprint Map に含まれているアイテムのクエリおよび表示方法 +* Blueprint Map の基本的な操作方法 + +[OBJECT:TopicList] + [PARAM:icon] + ![](%ROOT%/build_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + ステップ + [/PARAM] + [PARAM:description] + [/PARAM] + [PARAM:links] + [DIR(output:"checkpoint" parent:"Engine/Blueprints/BP_HowTo/WorkingWithMaps" org:"hierarchy")] + [/PARAM] +[/OBJECT] + +[REGION:call_to_action] + [クリックして開始](Engine/Blueprints/BP_HowTo/WorkingWithMaps/1 "%Engine/Blueprints/BP_HowTo/WorkingWithMaps/1:title%") +[/REGION] diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/WorkingWithMaps.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/WorkingWithMaps.KOR.udn new file mode 100644 index 000000000000..096d1418d13e --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithMaps/WorkingWithMaps.KOR.udn @@ -0,0 +1,52 @@ +INTSourceChangelist:3413824 +Availability:Docs +Title:맵 작업 +Description:블루프린트에서 Map, 맵 작업 방법을 배워봅니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/Scripting +Order:3 +Version: 4.15 +Tags:Blueprint Map +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithMaps +Topic-image:workingWithMaps_topicImage.png +Related:Programming/UnrealArchitecture/TMap + +[REGION:imagetable] +![](workingWithMaps_topicBanner.png) +_이 튜토리얼을 통해 언리얼 엔진 4 (UE4) 의 Map (맵) 작업 경험을 쌓을 수 있습니다._ +[/REGION] + +[](Engine/Blueprints/UserGuide/Arrays) 이후 블루프린트 맵이 인기를 끈 데는 다 이유가 있습니다. 할당된 키로 효율적인 값 검색 및 구하기를 지원하기 때문입니다. + +## 목적 + +블루프린트 맵 구성 및 작업 방법을 안내해 드립니다. + +## 목표 + +이 튜토리얼에서 습득할 수 있는 지식은 다음과 같습니다: + +* 블루프린트 스크립트 환경에서 맵 생성 및 편집 방법. +* 블루프린트 맵에 들어있는 아이템 질의 및 표시 방법. +* 블루프린트 맵에 대한 기본적인 연산 수행 방법. + +[OBJECT:TopicList] + [PARAM:icon] + ![](%ROOT%/build_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + 단계 + [/PARAM] + [PARAM:description] + [/PARAM] + [PARAM:links] + [DIR(output:"checkpoint" parent:"Engine/Blueprints/BP_HowTo/WorkingWithMaps" org:"hierarchy")] + [/PARAM] +[/OBJECT] + +[REGION:call_to_action] + [클릭하면 시작합니다.](Engine/Blueprints/BP_HowTo/WorkingWithMaps/1 "%Engine/Blueprints/BP_HowTo/WorkingWithMaps/1:title%") +[/REGION] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/1/WorkingWithSets_1.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/1/WorkingWithSets_1.CHN.udn new file mode 100644 index 000000000000..4d9254909d3c --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/1/WorkingWithSets_1.CHN.udn @@ -0,0 +1,182 @@ +INTSourceChangelist:0 +Availability:Docs +Title:1 - Required Setup +Description:Setting up your project to work with Blueprint Sets. +Crumbs: +Parent:Engine/Blueprints/BP_HowTo/WorkingWithSets +Version: 4.15 +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithSets +Order:1 + +[nav] + +Before you can start working with Blueprint Sets, you'll have to set up your project to display the container's contents. + +1. From the **Unreal Project Browser**, select the **New Project** tab, choose the **First Person** Blueprint project, and name your project, `ExampleSetProject`. + + [REGION:lightbox] + [![](Step1_1.png)(w:600)](Step1_1.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Before creating your new project, please make sure that the project matches the following settings: + + [REGION:lightbox] + [![](Step1_1Note.png)(w:600)](Step1_1Note.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Double-click the **Blueprints** folder from the project's **Content Browser**. + + [REGION:lightbox] + [![](Step1_2.png)(w:600)](Step1_2.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. From the **Content Browser**, go ahead and click the **Add New** button, hovering your mouse curser over the **Blueprint Class**, which is located under the **Create Basic Asset** pop-up menu. + + [REGION:lightbox] + [![](Step1_3.png)(w:600)](Step1_3.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After the **Pick Parent Class** menu opens, click the **All Classes** arrow to search for the **TextRender Actor** Blueprint Class. + + ![](Step1_4.png) + +1. Enter `TextRenderActor` in the **Search Bar**, selecting the **TextRenderActor** Blueprint Class before clicking the **Select** button. + + ![](Step1_5.png) + +1. At this point, you should have a new **TextRender Actor** located in your project's **Content Browser**. Go ahead and name the new Actor `DisplaySet`. + + [REGION:lightbox] + [![](Step1_6.png)(w:600)](Step1_6.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, drag the `DisplaySet` TextRender Actor into Unreal Editor's **Perspective (3D) Viewport**. + + [REGION:lightbox] + [![](Step1_7.png)(w:600)](Step1_7.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. With the **DisplaySet** TextRender Actor selected, click the **+ Add Component** button (located in the **Details** panel), and enter `Box Collision` into the **Search Bar**. + + [REGION:lightbox] + [![](Step1_8.png)(w:600)](Step1_8.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After adding the **Box Collision Component** to the TextRender Actor, name the new Component, `Trigger Box`. + + [REGION:lightbox] + [![](Step1_9.png)(w:600)](Step1_9.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, select the TextRender Component to view the Actor's **Transform** in the **Details** panel. + + [REGION:lightbox] + [![](Step1_10.png)(w:600)](Step1_10.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Update the **Display Set** Actor's **Transform** to reflect the following values: + + [REGION:lightbox] + [![](Step1_11.png)(w:600)](Step1_11.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, change the **Display Set** Actor's **Horizontal Alignment** to be **Center** aligned (rather than **Left** aligned, which is the default **Horizonal Alignment** value). + + [REGION:lightbox] + [![](Step1_12.png)(w:600)](Step1_12.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Currently, the **Trigger Box** Component is **Hidden in Game**. Go ahead and clear the **Hidden in Game** check box (located in the **Rendering** menu of the **Details** panel) so that you can view the **Box Collision** Component in-game. + + [REGION:lightbox] + [![](Step1_13.png)(w:600)](Step1_13.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + Having the ability to view **Box Collision** Components in-game is a great way to debug any potential issues with the underlying logic driving a triggered event. + [/REGION] + +1. If you enter PIE (or Play in Editor) mode, you'll notice that your projectiles will have a collision response to the **Display Set** collision box. Currently, we only want the **Display Set** collision box to trigger an event that allows us to display the contents of your Set containers. To do this, go to the **Collision** menu (located in the **Details** panel), click the **Collision Presets** drop-down list box, and select the **Custom...** option. + + [REGION:lightbox] + [![](Step1_14.png)(w:600)](Step1_14.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Finally, update the **Collision Presets** to reflect the following values: + + [REGION:lightbox] + [![](Step1_15.png)(w:600)](Step1_15.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +## End Result + +[REGION:lightbox] + [![](Step1_EndResult.png)(w:600)](Step1_EndResult.png) +[/REGION] + +[REGION:caption] +Click for full image. +[/REGION] + +By now, you've created a new project, having also set up a new TextRender Actor, which will display the contents of a Blueprint Set container that you'll create, edit, and display in the next step. + +[nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/1/WorkingWithSets_1.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/1/WorkingWithSets_1.INT.udn new file mode 100644 index 000000000000..2cb9cee14d95 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/1/WorkingWithSets_1.INT.udn @@ -0,0 +1,151 @@ +Availability:Docs +Title:1 - Required Setup +Description:Setting up your project to work with Blueprint Sets. +Crumbs:%ROOT% +Parent:Engine/Blueprints/BP_HowTo/WorkingWithSets +Version: 4.15 +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithSets +Order:1 + +[nav] + +Before you can start working with Blueprint Sets, you'll have to set up your project to display the container's contents. + +1. From the **Unreal Project Browser**, select the **New Project** tab, choose the **First Person** Blueprint project, and name your project, `ExampleSetProject`. + + [REGION:lightbox] + [![](Step1_1.png)(w:600)](Step1_1.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Before creating your new project, please make sure that the project matches the following settings: + + [REGION:lightbox] + [![](Step1_1Note.png)(w:600)](Step1_1Note.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Double-click the **Blueprints** folder from the project's **Content Browser**. + + [REGION:lightbox] + [![](Step1_2.png)(w:600)](Step1_2.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. From the **Content Browser**, go ahead and click the **Add New** button, hovering your mouse curser over the **Blueprint Class**, which is located under the **Create Basic Asset** pop-up menu. + + [REGION:lightbox] + [![](Step1_3.png)(w:600)](Step1_3.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After the **Pick Parent Class** menu opens, click the **All Classes** arrow to search for the **TextRender Actor** Blueprint Class. + + ![](Step1_4.png) + +1. Enter `TextRenderActor` in the **Search Bar**, selecting the **TextRenderActor** Blueprint Class before clicking the **Select** button. + + ![](Step1_5.png) + +1. At this point, you should have a new **TextRender Actor** located in your project's **Content Browser**. Go ahead and name the new Actor `DisplaySet`. + + [REGION:lightbox] + [![](Step1_6.png)(w:600)](Step1_6.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, drag the `DisplaySet` TextRender Actor into Unreal Editor's **Perspective (3D) Viewport**. + + [REGION:lightbox] + [![](Step1_7.png)(w:600)](Step1_7.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. With the **DisplaySet** TextRender Actor selected, click the **+ Add Component** button (located in the **Details** panel), and enter `Box Collision` into the **Search Bar**. + + [REGION:lightbox] + [![](Step1_8.png)(w:600)](Step1_8.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After adding the **Box Collision Component** to the TextRender Actor, name the new Component, `Trigger Box`. + + [REGION:lightbox] + [![](Step1_9.png)(w:600)](Step1_9.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, select the TextRender Component to view the Actor's **Transform** in the **Details** panel. + + [REGION:lightbox] + [![](Step1_10.png)(w:600)](Step1_10.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Update the **Display Set** Actor's **Transform** to reflect the following values: + + ![](Step1_11.png) + +1. Now, change the **Display Set** Actor's **Horizontal Alignment** to be **Center** aligned (rather than **Left** aligned, which is the default **Horizonal Alignment** value). + + ![](Step1_12.png) + +1. Currently, the **Trigger Box** Component is **Hidden in Game**. Go ahead and clear the **Hidden in Game** check box (located in the **Rendering** menu of the **Details** panel) so that you can view the **Box Collision** Component in-game. + + ![](Step1_13.png) + + [REGION:note] + Having the ability to view **Box Collision** Components in-game is a great way to debug any potential issues with the underlying logic driving a triggered event. + [/REGION] + +1. If you enter PIE (or Play in Editor) mode, you'll notice that your projectiles will have a collision response to the **Display Set** collision box. Currently, we only want the **Display Set** collision box to trigger an event that allows us to display the contents of your Set containers. To do this, go to the **Collision** menu (located in the **Details** panel), click the **Collision Presets** drop-down list box, and select the **Custom...** option. + + ![](Step1_14.png) + +1. Finally, update the **Collision Presets** to reflect the following values: + + ![](Step1_15.png) + +## End Result + +[REGION:lightbox] + [![](Step1_EndResult.png)(w:600)](Step1_EndResult.png) +[/REGION] + +[REGION:caption] +Click for full image. +[/REGION] + +By now, you've created a new project, having also set up a new TextRender Actor, which will display the contents of a Blueprint Set container that you'll create, edit, and display in the next step. + +[nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/1/WorkingWithSets_1.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/1/WorkingWithSets_1.JPN.udn new file mode 100644 index 000000000000..27666941749a --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/1/WorkingWithSets_1.JPN.udn @@ -0,0 +1,152 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:1 - 必要な設定を行う +Description:Blueprint Set を使用するためのプロジェクト設定 +Crumbs:%ROOT% +Parent:Engine/Blueprints/BP_HowTo/WorkingWithSets +Version:4.15 +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithSets +Order:1 + +[nav] + +Blueprint Set を使用する前に、コンテナのコンテンツが表示されるようにプロジェクトを設定する必要があります。 + +1. **アンリアル プロジェクト ブラウザ** で **[New Project (新規プロジェクト)]** タブから **First Person** ブループリント プロジェクトを選択し、プロジェクトに「`ExampleSetProject`」と名前を付けます。 + + [REGION:lightbox] + [![](Step1_1.png)(w:600)](Step1_1.png) + [/REGION] + [REGION:caption] + + クリックしてフルサイズで表示 + [/REGION] + +1. 新規プロジェクトを作成する前に、プロジェクトが以下の設定になっているか確認してください。 + + [REGION:lightbox] + [![](Step1_1Note.png)(w:600)](Step1_1Note.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. プロジェクトの **コンテンツ ブラウザ** から **「Blueprints」** フォルダをダブルクリックします。 + + [REGION:lightbox] + [![](Step1_2.png)(w:600)](Step1_2.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **コンテンツ ブラウザ** で**[Add New (新規追加)]** ボタンをクリックして **[Create Basic Asset (基本アセットを作成)]** ポップアップ メニュー配下の **[Blueprint Class]** にカーソルを当てます。 + + [REGION:lightbox] + [![](Step1_3.png)(w:600)](Step1_3.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **[Pick Parent Class (親クラスを選択)]** メニューが開いたら、**TextRender Actor** ブループリント クラスを検索するために **[All Classes]** の矢印をクリックします。 + + ![](Step1_4.png) + +1. **検索バー** に「`TextRenderActor`」と入力し **TextRenderActor** ブループリント クラスを選択して **[Select]** ボタンをクリックします。 + + ![](Step1_5.png) + +1. ここで、プロジェクトの **コンテンツ ブラウザ ** には新規作成した **TextRender Actor** が入っています。この新規アクタに「DisplaySet`」と名前を付けます。 + + [REGION:lightbox] + [![](Step1_6.png)(w:600)](Step1_6.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. `DisplaySet` TextRender アクタをアンリアル エディタの **Perspective (3D) Viewport** にドラッグします。 + + [REGION:lightbox] + [![](Step1_7.png)(w:600)](Step1_7.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **DisplaySet** TextRender アクタを選択したら、**[+ Add Component]** ボタン (**[Details (詳細)]** パネル) をクリックして **検索バー** に「`Box Collision`」と入力します。 + + [REGION:lightbox] + [![](Step1_8.png)(w:600)](Step1_8.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Box Collision Component** を TextRender アクタに追加したら、新規コンポーネントに「`Trigger Box`」と名前を付けます。 + + [REGION:lightbox] + [![](Step1_9.png)(w:600)](Step1_9.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 次に TextRender コンポーネントを選択して、**[Details (詳細)]** パネルでアクタの **Transform** を表示します。 + + [REGION:lightbox] + [![](Step1_10.png)(w:600)](Step1_10.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Display Set** アクタの **[Transform]** を更新して、以下の値に反映させます。 + + ![](Step1_11.png) + +1. 次に、**Display Set** アクタの **[Horizontal Alignment (水平方法の配置)]** を **[Center (中央)]** 揃え (**Horizonal Alignment** のデフォルト値は **[Left (左)]** 揃えです)。 + + ![](Step1_12.png) + +1. 現在 **Trigger Box** コンポーネントは **Hidden in Game** にあります。 (**[Details (詳細)]** パネルの **[Rendering]** メニュー) の **[Hidden in Game]** チェックボックスのチェックを外せば **Box Collision** コンポーネントをインゲームで表示することができます。 + + ![](Step1_13.png) + + [REGION:note] + **Box Collision** コンポーネントをインゲームで表示できると、トリガー済みイベントを操作する基本ロジックが原因の可能性のある問題のデバッグに便利です。 + [/REGION] + +1. PIE (Play in Editor) モードの場合、発射物は **Display Set** コリジョン ボックスに対してコリジョン反応をします。Set コンテナのコンテンツ表示を可能にするイベントをトリガーするための **Display Set** コリジョン ボックスが必要です。そのためには、(**[Details (詳細)]** パネル) の **[Collision]** メニューの **[Collision Presets]** ドロップダウン リスト ボックスをクリックし、**[Custom...]** オプションを選択します。 + + ![](Step1_14.png) + +1. 最後に **Collision Presets** を更新して、以下の値に反映させます。 + + ![](Step1_15.png) + +## 結果 + +[REGION:lightbox] + [![](Step1_EndResult.png)(w:600)](Step1_EndResult.png) +[/REGION] + +[REGION:caption] +クリックしてフルサイズで表示 +[/REGION] + +このステップでは、新規プロジェクトを作成し、新規 TextRender アクタも設定しました。これにより、次のステップで作成、編集、表示する Blueprint Set コンテナのコンテンツが表示されます。 + +[nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/1/WorkingWithSets_1.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/1/WorkingWithSets_1.KOR.udn new file mode 100644 index 000000000000..7cd456539d7c --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/1/WorkingWithSets_1.KOR.udn @@ -0,0 +1,152 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:1 - 필수 셋업 +Description:블루프린트 세트 작업을 위한 프로젝트 셋업입니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/BP_HowTo/WorkingWithSets +Version: 4.15 +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithSets +Order:1 + +[nav] + +블루프린트 세트 작업을 시작하기에 앞서, 컨테이너에 내용을 표시하도록 프로젝트 셋업을 해야 합니다. + +1. **언리얼 프로젝트 브라우저** 에서 **새 프로젝트** 탭을 선택하고, **일인칭** 블루프린트 프로젝트를 선택한 뒤 프로젝트 이름을 `ExampleSetProject` 라 합니다. + + [REGION:lightbox] + [![](Step1_1.png)(w:600)](Step1_1.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 새 프로젝트를 만들기 전, 세팅이 다음과 같이 되어있는지 확인하세요: + + [REGION:lightbox] + [![](Step1_1Note.png)(w:600)](Step1_1Note.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 프로젝트의 **콘텐츠 브라우저** 에서 **Blueprints** 폴더를 더블클릭합니다. + + [REGION:lightbox] + [![](Step1_2.png)(w:600)](Step1_2.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **콘텐츠 브라우저** 에서 **신규 추가** 버튼을 클릭하고 커서를 **블루프린트 클래스** 위에 올립니다. **기본 애셋 생성** 팝업 메뉴 아래 있습니다. + + [REGION:lightbox] + [![](Step1_3.png)(w:600)](Step1_3.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **부모 클래스 선택** 메뉴가 열리면, **모든 클래스** 화살표를 클릭하여 **TextRender Actor** 블루프린트 클래스를 검색합니다. + + ![](Step1_4.png) + +1. **검색창** 에 `TextRenderActor` 라 입력하여 **TextRenderActor** 블루프린트트 클래스를 선택한 뒤 **선택** 버튼을 누릅니다. + + ![](Step1_5.png) + +1. 이제, 프로젝트의 **콘텐츠 브라우저** 에 **TextRender Actor** 가 생겨 있을 것입니다. 새 액터 이름은 `DisplaySet` 입니다. + + [REGION:lightbox] + [![](Step1_6.png)(w:600)](Step1_6.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 이제 `DisplaySet` TextRender Actor 를 언리얼 에디터의 **원근 (3D) 뷰포트**. + + [REGION:lightbox] + [![](Step1_7.png)(w:600)](Step1_7.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **DisplaySet** TextRender Actor 를 선택한 채 **디테일** 패널에 있는 **+ 컴포넌트 추가** 버튼을 누른 뒤, **검색창** 에 `Box Collision` 이라 입력합니다. + + [REGION:lightbox] + [![](Step1_8.png)(w:600)](Step1_8.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. TextRender Actor 에 **Box Collision Component** 를 추가하고, 이름을 `Trigger Box` 라 합니다. + + [REGION:lightbox] + [![](Step1_9.png)(w:600)](Step1_9.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 이제 TextRender Component 를 선택하고 **디테일** 패널에서 액터의 **트랜스폼** 을 확인합니다. + + [REGION:lightbox] + [![](Step1_10.png)(w:600)](Step1_10.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **Display Set** 액터의 **트랜스폼** 값을 다음과 같이 변경합니다: + + ![](Step1_11.png) + +1. 이제 **Display Set** 액터의 **Horizontal Alignment** 를 (기본값인 **Left** 가 아닌) **Center** 정렬로 변경합니다. + + ![](Step1_12.png) + +1. 현재 **Trigger Box** 컴포넌트는 **Hidden in Game** (게임에서 숨겨진) 상태입니다. **디테일** 패널의 **렌더링** 메뉴에 위치한 **Hidden in Game** 박스 체크를 해제하면 게임내에서 **Box Collision** 컴포넌트를 확인할 수 있습니다. + + ![](Step1_13.png) + + [REGION:note] + 게임내에서 **Box Collision** 컴포넌트를 확인할 수 있으면 트리거되는 이벤트를 구동시키는 하부 로직 관련 발생할 수 있는 문제를 디버깅하기에 매우 좋습니다. + [/REGION] + +1. PIE (에디터에서 플레이) 모드에 들어가면, 프로젝타일이 **Display Set** 콜리전 박스에 콜리전 반응이 있는 것이 보입니다. 현재 **Display Set** 콜리전 박스만 세트 컨테이너 내용을 표시할 수 있는 이벤트를 발동시킬 수 있도록 하고 싶습니다. 그러기 위해서는 **디테일** 패널의 **Collision** 메뉴에서 **콜리전 프리셋** 드롭다운 리스트 박스를 클릭하고, **Custom...** 옵션을 선택합니다. + + ![](Step1_14.png) + +1. 마지막으로 **콜리전 프리셋** 을 다음과 같이 변경합니다: + + ![](Step1_15.png) + +## 최종 결과 + +[REGION:lightbox] + [![](Step1_EndResult.png)(w:600)](Step1_EndResult.png) +[/REGION] + +[REGION:caption] +클릭하면 원본 이미지를 확인합니다. +[/REGION] + +지금까지 새 프로젝트를 생성하여 블루프린트 세트 컨테이너 내용을 표시할 TextRender Actor 셋업 작업을 마쳤으니, 다음 단계에서는 이 액터를 생성, 편집, 표시해 보도록 하겠습니다. + +[nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/2/WorkingWithSets_2.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/2/WorkingWithSets_2.CHN.udn new file mode 100644 index 000000000000..2860bc1110bb --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/2/WorkingWithSets_2.CHN.udn @@ -0,0 +1,381 @@ +INTSourceChangelist:0 +Availability:Docs +Title:2 - Creating and Displaying a Blueprint Set +Description:Setting up a Blueprint Set container so that you can display its contents in-game. +Crumbs: +Parent:Engine/Blueprints/BP_HowTo/WorkingWithSets +Version: 4.15 +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithSets +Order:2 + +[nav] + +Now that you've set up a **TextRender** actor in your newly created project, you're ready to create a Blueprint Set container, the contents of which you'll display in-game. + +1. From your project's **Content Browser**, double-click the **Display Set** TextRender Actor to open its Blueprint **Event Graph**. + + [REGION:lightbox] + [![](Step2_1.png)(w:600)](Step2_1.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. If you see the following screen, go ahead and click the **Open Full Blueprint Editor** link to get started. + + [REGION:lightbox] + [![](Step2_2.png)(w:600)](Step2_2.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. You should see the **Display Set** TextRender Actor Blueprint **Event Graph**, where you'll be able to add a Blueprint Set and its diplay logic. + + [REGION:lightbox] + [![](Step2_3.png)(w:600)](Step2_3.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + + If you don't see the aforementioned screen, go ahead and click the **Event Graph** tab to open the Actor's Blueprint Event Graph Editor. + + [REGION:lightbox] + [![](Step2_3Note.png)(w:600)](Step2_3Note.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [/REGION] + +1. Now is the time to create a Blueprint Set container, where you'll store some items that you'll display later on. To create a new Blueprint Set, click the **+ Add New** button (located in the **My Blueprint** panel) and select **Variable** from the drop-down list. + + [REGION:lightbox] + [![](Step2_4.png)(w:600)](Step2_4.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Name your new variable, `Instruction Set`. + + [REGION:lightbox] + [![](Step2_5.png)(w:600)](Step2_5.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Click the variable's **pin type** button, which is located next to the variable's name. + + [REGION:lightbox] + [![](Step2_6.png)(w:600)](Step2_6.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, select the **String** variable type from the drop-down list. + + [REGION:lightbox] + [![](Step2_7.png)(w:600)](Step2_7.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Click the variable's **container type** button, which is located next to the **Variable Type** drop-down list in the **Details** panel. + + [REGION:lightbox] + [![](Step2_8.png)(w:600)](Step2_8.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, select the **Set** container type from the drop-down list. + + [REGION:lightbox] + [![](Step2_9.png)(w:600)](Step2_9.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. At this point, the Blueprint Graph reminds you that you need to compile the Blueprint in order to define the items that you're going to store inside of the container. Go ahead and click the **Compile** button to get started. + + [REGION:lightbox] + [![](Step2_10.png)(w:600)](Step2_10.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + Compiling the Blueprint replaces the container's **Default Value** message with an interface, enabling you to populate your container with unique items (or elements) of String type. + [/REGION] + +1. If you already haven't done so, go ahead and click the **Save** button to save all of the work that you've done so far. + + [REGION:lightbox] + [![](Step2_11.png)(w:600)](Step2_11.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:tip] + In general, it's always a good practice to save early, and save often. + [/REGION] + +1. Click the **+** (Adds Element) button (located in the **Default Value** menu of the **Details** panel) to add a String type item to your newly defined **Instruction Set** container. + + [REGION:lightbox] + [![](Step2_12.png)(w:600)](Step2_12.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Define your container's new item, defining the item as `Click`. + + [REGION:lightbox] + [![](Step2_13.png)(w:600)](Step2_13.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Repeat the previous two steps, making sure to fill your **Instruction Set** container with the following items: + + [REGION:lightbox] + [![](Step2_14.png)(w:600)](Step2_14.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +## Scripting the Logic + +Before you can display the contents of your newly created Blueprint Set, you'll need to write the necessary logic. + +1. Now that you've defined your container, go ahead and drag the **Instruction Set** variable into the Blueprint Event Graph. + + [REGION:lightbox] + [![](Step2_15.png)(w:600)](Step2_15.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Select **Get** from the **Instruction Set** drown-down list. + + [REGION:lightbox] + [![](Step2_16.png)(w:600)](Step2_16.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Drag off the **Instruction Set** node and add the **To Array** node from the **Set Utilities** interface. + + [REGION:lightbox] + [![](Step2_17.png)(w:600)](Step2_17.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Go ahead and drag off the **To Array** node, connecting it to a **Get** node. + + [REGION:lightbox] + [![](Step2_18.png)(w:600)](Step2_18.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + There are several ways to get items from a Set. One way is to query the Set with a specific key and another way is to iterate through the items in a set. For this part in the tutorial, we'll go ahead and use a counter variable to iterate our way through the **Instruction Set**. + [/REGION] + +1. With the aforementioned note in mind, go ahead and click the **+ Add New** button, selecting **Variable** from the drop-down list. + + [REGION:lightbox] + [![](Step2_19.png)(w:600)](Step2_19.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Make sure to set the new variable's type to an **Integer** type, giving it the name, `Counter`. + + [REGION:lightbox] + [![](Step2_20.png)(w:600)](Step2_20.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After you've declared and defined your counter variable, drag **Counter** into the Blueprint Event Graph, and select **Get** from the drop-down list. + + [REGION:lightbox] + [![](Step2_21.png)(w:600)](Step2_21.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Drag off the **Counter** node, search for, and add the **IncrementInt** node. + + [REGION:lightbox] + [![](Step2_22.png)(w:600)](Step2_22.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, go ahead and connect the **IncrementInt** node to the **Get** node. + + [REGION:lightbox] + [![](Step2_23.png)(w:600)](Step2_23.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + For the purposes of this tutorial, you're going to use a timer function to increment the **Counter** variable. + [/REGION] + +1. Drag off the **Event Tick** node, search for, and add the **Delay** node. + + [REGION:lightbox] + [![](Step2_24.png)(w:600)](Step2_24.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After you've set the delay duration to **2** seconds, connect the **Delay** node to the **IncrementInt** node. + + [REGION:lightbox] + [![](Step2_25.png)(w:600)](Step2_25.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Go ahead and connect the **Event BeginPlay** node to the **To Array** node. + + [REGION:lightbox] + [![](Step2_26.png)(w:600)](Step2_26.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. At this point, you're ready to drag off the **To Array** node to search for, and connect the **Set Text** node in order to display your container's contents in-game. + + [REGION:lightbox] + [![](Step2_27.png)(w:600)](Step2_27.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Connect the **Get** node to the **Value** pin (located in the **Set Text** node). + + [REGION:lightbox] + [![](Step2_28.png)(w:600)](Step2_28.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, go ahead and connect the **Increment** node to the **Set Text** node. + + [REGION:lightbox] + [![](Step2_29.png)(w:600)](Step2_29.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After inspecting your completed script, go ahead and click the **Compile** button before going back to the Editor's **Viewport** interface. + + [REGION:lightbox] + [![](Step2_30.png)(w:600)](Step2_30.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. From the Editor's **Viewport** interface, click the **Play** button to see your newly implemented script at work. + + [REGION:lightbox] + [![](Step2_31.png)(w:600)](Step2_31.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +## End Result + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 960 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 540 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + BdDdQhDveIY + [/PARAMLITERAL] +[/OBJECT] + +At this point in the guide, you've defined a new Blueprint Set, filled the container with items, and displayed them with +some basic logic that you created in your **TextRender** Actor's Blueprint Event Graph. If you want to learn how to perform a +slightly more advanced operation, please continue onto the next step, where you'll learn how to perform an **Intersection** of +two Blueprint Sets. + +[nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/2/WorkingWithSets_2.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/2/WorkingWithSets_2.INT.udn new file mode 100644 index 000000000000..273b694e4379 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/2/WorkingWithSets_2.INT.udn @@ -0,0 +1,374 @@ +Availability:Docs +Title:2 - Creating and Displaying a Blueprint Set +Description:Setting up a Blueprint Set container so that you can display its contents in-game. +Crumbs:%ROOT% +Parent:Engine/Blueprints/BP_HowTo/WorkingWithSets +Version: 4.15 +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithSets +Order:2 + +[nav] + +Now that you've set up a **TextRender** actor in your newly created project, you're ready to create a Blueprint Set container, the contents of which you'll display in-game. + +1. From your project's **Content Browser**, double-click the **Display Set** TextRender Actor to open its Blueprint **Event Graph**. + + [REGION:lightbox] + [![](Step2_1.png)(w:600)](Step2_1.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. If you see the following screen, go ahead and click the **Open Full Blueprint Editor** link to get started. + + [REGION:lightbox] + [![](Step2_2.png)(w:600)](Step2_2.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. You should see the **Display Set** TextRender Actor Blueprint **Event Graph**, where you'll be able to add a Blueprint Set and its diplay logic. + + [REGION:lightbox] + [![](Step2_3.png)(w:600)](Step2_3.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + + If you don't see the aforementioned screen, go ahead and click the **Event Graph** tab to open the Actor's Blueprint Event Graph Editor. + + [REGION:lightbox] + [![](Step2_3Note.png)(w:600)](Step2_3Note.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [/REGION] + +1. Now is the time to create a Blueprint Set container, where you'll store some items that you'll display later on. To create a new Blueprint Set, click the **+ Add New** button (located in the **My Blueprint** panel) and select **Variable** from the drop-down list. + + [REGION:lightbox] + [![](Step2_4.png)(w:600)](Step2_4.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Name your new variable, `Instruction Set`. + + [REGION:lightbox] + [![](Step2_5.png)(w:600)](Step2_5.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Click the variable's **pin type** button, which is located next to the variable's name. + + [REGION:lightbox] + [![](Step2_6.png)(w:600)](Step2_6.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, select the **String** variable type from the drop-down list. + + [REGION:lightbox] + [![](Step2_7.png)(w:600)](Step2_7.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Click the variable's **container type** button, which is located next to the **Variable Type** drop-down list in the **Details** panel. + + [REGION:lightbox] + [![](Step2_8.png)(w:600)](Step2_8.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, select the **Set** container type from the drop-down list. + + [REGION:lightbox] + [![](Step2_9.png)(w:600)](Step2_9.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. At this point, the Blueprint Graph reminds you that you need to compile the Blueprint in order to define the items that you're going to store inside of the container. Go ahead and click the **Compile** button to get started. + + [REGION:lightbox] + [![](Step2_10.png)(w:600)](Step2_10.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + Compiling the Blueprint replaces the container's **Default Value** message with an interface, enabling you to populate your container with unique items (or elements) of String type. + [/REGION] + +1. If you already haven't done so, go ahead and click the **Save** button to save all of the work that you've done so far. + + [REGION:lightbox] + [![](Step2_11.png)(w:600)](Step2_11.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:tip] + In general, it's always a good practice to save early, and save often. + [/REGION] + +1. Click the **+** (Adds Element) button (located in the **Default Value** menu of the **Details** panel) to add a String type item to your newly defined **Instruction Set** container. + + [REGION:lightbox] + [![](Step2_12.png)(w:600)](Step2_12.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Define your container's new item, defining the item as `Click`. + + ![](Step2_13.png) + +1. Repeat the previous two steps, making sure to fill your **Instruction Set** container with the following items: + + ![](Step2_14.png) + +## Scripting the Logic + +Before you can display the contents of your newly created Blueprint Set, you'll need to write the necessary logic. + +1. Now that you've defined your container, go ahead and drag the **Instruction Set** variable into the Blueprint Event Graph. + + [REGION:lightbox] + [![](Step2_15.png)(w:600)](Step2_15.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Select **Get** from the **Instruction Set** drown-down list. + + [REGION:lightbox] + [![](Step2_16.png)(w:600)](Step2_16.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Drag off the **Instruction Set** node and add the **To Array** node from the **Set Utilities** interface. + + [REGION:lightbox] + [![](Step2_17.png)(w:600)](Step2_17.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Go ahead and drag off the **To Array** node, connecting it to a **Get** node. + + [REGION:lightbox] + [![](Step2_18.png)(w:600)](Step2_18.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + There are several ways to get items from a Set. One way is to query the Set with a specific key and another way is to iterate through the items in a set. For this part in the tutorial, we'll go ahead and use a counter variable to iterate our way through the **Instruction Set**. + [/REGION] + +1. With the aforementioned note in mind, go ahead and click the **+ Add New** button, selecting **Variable** from the drop-down list. + + [REGION:lightbox] + [![](Step2_19.png)(w:600)](Step2_19.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Make sure to set the new variable's type to an **Integer** type, giving it the name, `Counter`. + + [REGION:lightbox] + [![](Step2_20.png)(w:600)](Step2_20.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After you've declared and defined your counter variable, drag **Counter** into the Blueprint Event Graph, and select **Get** from the drop-down list. + + [REGION:lightbox] + [![](Step2_21.png)(w:600)](Step2_21.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Drag off the **Counter** node, search for, and add the **IncrementInt** node. + + [REGION:lightbox] + [![](Step2_22.png)(w:600)](Step2_22.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, go ahead and connect the **IncrementInt** node to the **Get** node. + + [REGION:lightbox] + [![](Step2_23.png)(w:600)](Step2_23.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + For the purposes of this tutorial, you're going to use a timer function to increment the **Counter** variable. + [/REGION] + +1. Drag off the **Event Tick** node, search for, and add the **Delay** node. + + [REGION:lightbox] + [![](Step2_24.png)(w:600)](Step2_24.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After you've set the delay duration to **2** seconds, connect the **Delay** node to the **IncrementInt** node. + + [REGION:lightbox] + [![](Step2_25.png)(w:600)](Step2_25.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Go ahead and connect the **Event BeginPlay** node to the **To Array** node. + + [REGION:lightbox] + [![](Step2_26.png)(w:600)](Step2_26.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. At this point, you're ready to drag off the **To Array** node to search for, and connect the **Set Text** node in order to display your container's contents in-game. + + [REGION:lightbox] + [![](Step2_27.png)(w:600)](Step2_27.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Connect the **Get** node to the **Value** pin (located in the **Set Text** node). + + [REGION:lightbox] + [![](Step2_28.png)(w:600)](Step2_28.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, go ahead and connect the **Increment** node to the **Set Text** node. + + [REGION:lightbox] + [![](Step2_29.png)(w:600)](Step2_29.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After inspecting your completed script, go ahead and click the **Compile** button before going back to the Editor's **Viewport** interface. + + [REGION:lightbox] + [![](Step2_30.png)(w:600)](Step2_30.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. From the Editor's **Viewport** interface, click the **Play** button to see your newly implemented script at work. + + [REGION:lightbox] + [![](Step2_31.png)(w:600)](Step2_31.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +## End Result + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + BdDdQhDveIY + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +At this point in the guide, you've defined a new Blueprint Set, filled the container with items, and displayed them with +some basic logic that you created in your **TextRender** Actor's Blueprint Event Graph. If you want to learn how to perform a +slightly more advanced operation, please continue onto the next step, where you'll learn how to perform an **Intersection** of +two Blueprint Sets. + +[nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/2/WorkingWithSets_2.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/2/WorkingWithSets_2.JPN.udn new file mode 100644 index 000000000000..39b9448a4d51 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/2/WorkingWithSets_2.JPN.udn @@ -0,0 +1,375 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:2 - Blueprint Set の作成および表示 +Description:コンテンツをインゲームで表示するための Blueprint Set の設定方法 +Crumbs:%ROOT% +Parent:Engine/Blueprints/BP_HowTo/WorkingWithSets +Version:4.15 +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithSets +Order:2 + +[nav] + +新規作成したプロジェクトに **TextRender** アクタを設定したので、次は Blueprint Set コンテナを作成し、それをインゲームで表示してみましょう。 + +1. プロジェクトの **[コンテンツ ブラウザ]** で **[Display Set]** TextRender アクタをダブルクリックしてブループリントの **イベントグラフ** を開きます。 + + [REGION:lightbox] + [![](Step2_1.png)(w:600)](Step2_1.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 以下の画面が表示されたら、**[Open Full Blueprint Editor]** リンクをクリックして開始します。 + + [REGION:lightbox] + [![](Step2_2.png)(w:600)](Step2_2.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Display Set** TextRender アクタ ブループリントの **イベントグラフ** が表示されます。ここで Blueprint Set と表示ロジックを追加することができます。 + + [REGION:lightbox] + [![](Step2_3.png)(w:600)](Step2_3.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + + [REGION:note] + + 上記画面が表示されない場合、**[Event Graph]** タブをクリックしてアクタのブループリント イベントグラフ エディタを開きます。 + + [REGION:lightbox] + [![](Step2_3Note.png)(w:600)](Step2_3Note.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + + [/REGION] + +1. 次に、後で表示するアイテムを格納する Blueprint Set コンテナを作成します。新規の Blueprint Set を作成するには、(**[My Blueprint]** パネルの **[+ Add New]** ボタンをクリックしてドロップダウン リストから **[Variable (変数)]** を選択します。 + + [REGION:lightbox] + [![](Step2_4.png)(w:600)](Step2_4.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 新しい変数に「`Instruction Set`」と名前を付けます。 + + [REGION:lightbox] + [![](Step2_5.png)(w:600)](Step2_5.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. その変数の横にある **ピン タイプ** のボタンをクリックします。 + + [REGION:lightbox] + [![](Step2_6.png)(w:600)](Step2_6.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 次にドロップダウン リストから変数タイプの **String** を選択します。 + + [REGION:lightbox] + [![](Step2_7.png)(w:600)](Step2_7.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **[Details (詳細)]** パネルの **[Variable Type]** ドロップダウン リストの横にある、その変数の **コンテナ タイプ** ボタンをクリックします。 + + [REGION:lightbox] + [![](Step2_8.png)(w:600)](Step2_8.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 次にドロップダウン リストから **Set** コンテナ タイプを選択します。 + + [REGION:lightbox] + [![](Step2_9.png)(w:600)](Step2_9.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. この時点で、コンテナ内に格納するアイテムを定義するためにはブループリントのコンパイルが必要であることをブループリント グラフが念押しします。**[Compile]** ボタンをクリックしてコンパイルを開始します。 + + [REGION:lightbox] + [![](Step2_10.png)(w:600)](Step2_10.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + + [REGION:note] + ブループリントをコンパイルすると、コンテナの **[Default Value]** メッセージがインターフェースになり、コンテナに String 型のユニークなアイテム (またはエレメント) を追加することができます。 + [/REGION] + +1. ここまでの作業を保存していない場合は、**[Save]** ボタンをクリックしてすべての作業を保存してください。 + + [REGION:lightbox] + [![](Step2_11.png)(w:600)](Step2_11.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + + [REGION:tip] + 一般的に、保存は早めに、そしてこまめに行うのがグッドプラクティスです。 + [/REGION] + +1. (**[Details (詳細)]** パネルの**[Default Value]** メニューにある) **[+]** (エレメントを追加) ボタンをクリックして、String 型アイテムを新しく定義した **Instruction Set** コンテナに追加します。 + + [REGION:lightbox] + [![](Step2_12.png)(w:600)](Step2_12.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. コンテナの新規アイテムを「`Click`」に定義します。 + + ![](Step2_13.png) + +1. この 2 ステップを繰り返して、**Instruction Set** コンテナに以下のアイテムが入っていることを確認してください。 + + ![](Step2_14.png) + +## ロジックのスクリプト処理 + +新規に作成した Blueprint Set のコンテンツを表示する前に、必要なロジックを書き込む必要があります。 + +1. コンテナを定義したので、**Instruction Set** 変数をブループリント イベントグラフにドラッグします。 + + [REGION:lightbox] + [![](Step2_15.png)(w:600)](Step2_15.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Instruction Set** ドロップダウン リストから **Get** を選択します。 + + [REGION:lightbox] + [![](Step2_16.png)(w:600)](Step2_16.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Instruction Set** ノードを引き出して **Set Utilities** インターフェースから **To Array** ノードを追加します。 + + [REGION:lightbox] + [![](Step2_17.png)(w:600)](Step2_17.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **To Array** ノードを引き出して **Get** ノードに接続します。 + + [REGION:lightbox] + [![](Step2_18.png)(w:600)](Step2_18.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + + [REGION:note] + Set からアイテムを取得する方法はいくつかあります。特定のキーを使って Set をクエリする方法、そしてセット内のアイテムによってイタレートする方法です。今は、カウンタ変数を使って、**Instruction Set** のイタレートを行います。 + [/REGION] + +1. 前述の注意を念頭に置いて、**[+ Add New]** ボタンをクリックし、ドロップダウン リストから **[Variable]** を選択します。 + + [REGION:lightbox] + [![](Step2_19.png)(w:600)](Step2_19.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 新しい変数の型を **Integer** に設定し、「`Counter`」と名前を付けます。 + + [REGION:lightbox] + [![](Step2_20.png)(w:600)](Step2_20.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. カウンタ変数の宣言と定義が完了したら、**Counter** をブループリント イベントグラフにドラッグして、ドロップダウン リストから **[Get]** を選択します。 + + [REGION:lightbox] + [![](Step2_21.png)(w:600)](Step2_21.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Counter** ノードをドラッグして **IncrementInt** ノードを検索および追加します。 + + [REGION:lightbox] + [![](Step2_22.png)(w:600)](Step2_22.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 次に **IncrementInt** ノードを **Get** ノードに接続します。 + + [REGION:lightbox] + [![](Step2_23.png)(w:600)](Step2_23.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + + [REGION:note] + このチュートリアルの目的に合わせて、タイマー関数を使用して **Counter** 変数をインクリメントします。 + [/REGION] + +1. **Event Tick** ノードを引き出して、**Delay** ノードを検索および追加します。 + + [REGION:lightbox] + [![](Step2_24.png)(w:600)](Step2_24.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 遅延時間を **2** 秒に設定し、**Delay** ノードを **IncrementInt** ノードに接続します。 + + [REGION:lightbox] + [![](Step2_25.png)(w:600)](Step2_25.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Event BeginPlay** ノードを **To Array** ノードに接続します。 + + [REGION:lightbox] + [![](Step2_26.png)(w:600)](Step2_26.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. この時点で **To Array** ノードを引き出して **Set Text** ノードを検索および接続して、コンテナのコンテンツをインゲームで表示します。 + + [REGION:lightbox] + [![](Step2_27.png)(w:600)](Step2_27.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Get** ノードを (**Set Text** ノードの) **Value** ピンに接続します。 + + [REGION:lightbox] + [![](Step2_28.png)(w:600)](Step2_28.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 次に **IncrementInt** ノードを **Set Text** ノードに接続します。 + + [REGION:lightbox] + [![](Step2_29.png)(w:600)](Step2_29.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 完成したスクリプト全体を確認したら、エディタの **Viewport** インターフェースに戻る前に **[Compile]** ボタンをクリックします。 + + [REGION:lightbox] + [![](Step2_30.png)(w:600)](Step2_30.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. エディタの **Viewport** インターフェースで、**[Play]** ボタンをクリックして新しく実装したスクリプトの動きを確認します。 + + [REGION:lightbox] + [![](Step2_31.png)(w:600)](Step2_31.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +## 結果 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + BdDdQhDveIY + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +このステップでは、新規作成した Blueprint Set を定義し、アイテムを追加し、 +**TextRender** アクタのブループリント イベントグラフで作成したロジックのいくつかを使ってそれらのアイテムを表示しました。もう少し高度な操作を学習したい場合は、 +このまま次のステップへ進んでください。 +2 つの Blueprint Set の **Intersection** の実行方法を説明します。 + +[nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/2/WorkingWithSets_2.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/2/WorkingWithSets_2.KOR.udn new file mode 100644 index 000000000000..fa2435340017 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/2/WorkingWithSets_2.KOR.udn @@ -0,0 +1,375 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:2 - 블루프린트 세트 생성 및 표시 +Description:블루프린트 세트 컨테이너의 내용을 게임내에서 표시할 수 있도록 셋업합니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/BP_HowTo/WorkingWithSets +Version: 4.15 +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithSets +Order:2 + +[nav] + +새로 생성된 프로젝트에 **TextRender** 액터 셋업을 마쳤으니, 블루프린트 세트 컨테이너를 만들어 게임내에서 그 내용을 표시할 준비가 되었습니다. + +1. 프로젝트의 **콘텐츠 브라우저** 에서 **Display Set** TextRender 액터를 더블클릭하여 블루프린트 **이벤트 그래프** 를 엽니다. + + [REGION:lightbox] + [![](Step2_1.png)(w:600)](Step2_1.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 다음 화면이 보이면, **풀 블루프린트 에디터 열기** 링크를 클릭하여 시작합니다. + + [REGION:lightbox] + [![](Step2_2.png)(w:600)](Step2_2.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **Display Set** TextRender 액터 블루프린트 **이벤트 그래프** 가 보일 것입니다. 여기서 블루프린트 세트와 그 표시 로직을 추가할 수 있을 것입니다. + + [REGION:lightbox] + [![](Step2_3.png)(w:600)](Step2_3.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + + [REGION:note] + + 앞서 말한 화면이 보이지 않는 경우, **이벤트 그래프** 탭을 클릭하여 액터의 블루프린트 이벤트 그래프 에디터를 엽니다. + + [REGION:lightbox] + [![](Step2_3Note.png)(w:600)](Step2_3Note.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + + [/REGION] + +1. 이제 블루프린트 세트 컨테이너를 만들 차례입니다. 여기에 나중에 표시할 아이템을 저장합니다. 블루프린트 세트를 새로 만들려면, **내 블루프린트** 패널의 **+ 신규 추가** 버튼을 클릭하고, 드롭다운 리스트에서 **변수** 를 선택합니다. + + [REGION:lightbox] + [![](Step2_4.png)(w:600)](Step2_4.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 새 변수 이름은 `Instruction Set` 라 합니다. + + [REGION:lightbox] + [![](Step2_5.png)(w:600)](Step2_5.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 변수의 **핀 유형** 버튼을 클릭합니다. 변수 이름 옆에 있습니다. + + [REGION:lightbox] + [![](Step2_6.png)(w:600)](Step2_6.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 드롭다운 리스트에서 **String** 변수 유형을 선택합니다. + + [REGION:lightbox] + [![](Step2_7.png)(w:600)](Step2_7.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 변수의 **컨테이너 유형** 버튼을 클릭합니다. **디테일** 패널의 **변수 유형** 드롭다운 리스트 옆에 있습니다. + + [REGION:lightbox] + [![](Step2_8.png)(w:600)](Step2_8.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 드롭다운 리스트에서 **세트** 컨테이너 유형을 선택합니다. + + [REGION:lightbox] + [![](Step2_9.png)(w:600)](Step2_9.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 이제 블루프린트 그래프에서 블루프린트를 컴파일해야 컨테이너 안에 저장하려는 아이템을 정의할 수 있다고 알려줍니다. 계속해서 **컴파일** 버튼을 눌러 시작합니다. + + [REGION:lightbox] + [![](Step2_10.png)(w:600)](Step2_10.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + + [REGION:note] + 블루프린트를 컴파일하면 컨테이너의 **Default Value** 메시지가 인터페이스로 대체되어, 컨테이너를 String 유형 고유 아이템( 또는 엘리먼트)로 채울 수 있습니다. + [/REGION] + +1. 아직 저장하지 않은 경우 **저장** 버튼을 눌러 지금까지 작업 내용을 저장합니다. + + [REGION:lightbox] + [![](Step2_11.png)(w:600)](Step2_11.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + + [REGION:tip] + 일반적으로 일찍 자주 저장하는 습관을 들이는 것이 좋습니다. + [/REGION] + +1. **디테일** 패널의 **Default Value** 메뉴에 위치한 **+** (엘리먼트 추가) 버튼을 클릭하여 새로 정의된 **Instruction Set** 컨테이너에 String 유형 아이템을 추가합니다. + + [REGION:lightbox] + [![](Step2_12.png)(w:600)](Step2_12.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 컨테이너의 새 아이템을 `Click` 으로 정의합니다. + + ![](Step2_13.png) + +1. 기존 두 단계를 반복합니다. **Instruction Set** 컨테이너를 다음 아이템으로 채웁니다: + + ![](Step2_14.png) + +## 로직 스크립트 작성 + +새로 생성한 블루프린트 세트 내용을 표시하기에 앞서, 필수 로직을 작성해야 합니다. + +1. 컨테이너를 정의했으니, **Instruction Set** 변수를 블루프린트 이벤트 그래프에 끌어 놓습니다. + + [REGION:lightbox] + [![](Step2_15.png)(w:600)](Step2_15.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **Instruction Set** 드롭다운 리스트에서 **Get** 을 선택합니다. + + [REGION:lightbox] + [![](Step2_16.png)(w:600)](Step2_16.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **Instruction Set** 노드를 끌어놓고 **Set Utilities** 인터페이스에서 **To Array** 노드를 추가합니다. + + [REGION:lightbox] + [![](Step2_17.png)(w:600)](Step2_17.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **To Array** 노드를 끌어 놓고 **Get** 노드에 연결합니다. + + [REGION:lightbox] + [![](Step2_18.png)(w:600)](Step2_18.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + + [REGION:note] + 세트에서 아이템을 구할 수 있는 방법은 여러가지 있습니다. 한 가지는 세트에 키를 지정하여 쿼리를 하는 것이고, 다른 하나는 세트의 아이템을 대상으로 반복처리하는 것입니다. 여기서는 카운터 변수를 사용하여 **Instruction Set** 를 대상으로 반복처리하도록 하겠습니다. + [/REGION] + +1. 앞서 말씀드린 점을 염두에 두고, **+ 신규 추가** 버튼을 클릭하고, 드롭다운 리스트에서 **변수** 를 선택합니다. + + [REGION:lightbox] + [![](Step2_19.png)(w:600)](Step2_19.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 새 변수의 유형을 **Integer** 유형으로 설정하고 이름을 `Counter` 라 합니다. + + [REGION:lightbox] + [![](Step2_20.png)(w:600)](Step2_20.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 카운터 변수를 선언하고 정의한 후, **Counter** 를 블루프린트 이벤트 그래프에 끌어 놓고, 드롭다운 목록에서 **Get** 을 선택합니다. + + [REGION:lightbox] + [![](Step2_21.png)(w:600)](Step2_21.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **Counter** 노드를 끌어 놓고, **IncrementInt** 노드를 검색 추가합니다. + + [REGION:lightbox] + [![](Step2_22.png)(w:600)](Step2_22.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **IncrementInt** 노드를 **Get** 노드에 연결합니다. + + [REGION:lightbox] + [![](Step2_23.png)(w:600)](Step2_23.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + + [REGION:note] + 여기서는 타이머 함수를 사용하여 **Counter** 변수를 증가시키도록 하겠습니다. + [/REGION] + +1. **Event Tick** 노드를 끌어 놓고 **Delay** 노드를 검색 추가합니다. + + [REGION:lightbox] + [![](Step2_24.png)(w:600)](Step2_24.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 딜레이 기간을 **2** 초로 설정한 이후, **Delay** 노드를 **IncrementInt** 노드에 연결합니다. + + [REGION:lightbox] + [![](Step2_25.png)(w:600)](Step2_25.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **Event BeginPlay** 노드를 **To Array** 노드에 연결합니다. + + [REGION:lightbox] + [![](Step2_26.png)(w:600)](Step2_26.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 이제 **To Array** 노드를 끌어놓고 **Set Text** 노드를 검색 추가하여 게임내에서 컨테이너 내용을 표시할 준비가 되었습니다. + + [REGION:lightbox] + [![](Step2_27.png)(w:600)](Step2_27.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **Get** 노드를 **Set Text** 노드에 위치한 **Value** 핀에 연결합니다. + + [REGION:lightbox] + [![](Step2_28.png)(w:600)](Step2_28.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **Increment** 노드를 **Set Text** 노드에 연결합니다. + + [REGION:lightbox] + [![](Step2_29.png)(w:600)](Step2_29.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 완성된 스크립트를 살펴본 후 **컴파일** 버튼을 누르고 에디터의 **뷰포트** 인터페이스로 돌아갑니다. + + [REGION:lightbox] + [![](Step2_30.png)(w:600)](Step2_30.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 에디터의 **뷰포트** 인터페이스에서 **플레이** 버튼을 클릭하여 새로 구현한 스크립트가 작동되는 것을 확인합니다. + + [REGION:lightbox] + [![](Step2_31.png)(w:600)](Step2_31.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +## 최종 결과 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + BdDdQhDveIY + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +현재 새 블루프린트 세트를 정의했고, 컨테이너에 아이템을 채웠으며, **TextRender** 액터의 블루프린트 +이벤트 그래프에 만든 기본적인 로직으로 표시하도록 했습니다. 약간 더 고급 작업 방식에 대한 정보는 +다음 단계에서 두 블루프린트 세트의 **Intersection** (교집합) 연산 방법을 +참고하시기 바랍니다. + +[nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/3/WorkingWithSets_3.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/3/WorkingWithSets_3.CHN.udn new file mode 100644 index 000000000000..93a6b7b5c796 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/3/WorkingWithSets_3.CHN.udn @@ -0,0 +1,318 @@ +INTSourceChangelist:0 +Availability:Docs +Title:3 - Performing an Intersection of Blueprint Sets +Description:Intersecting two Blueprint Sets, ultimately showing the Resultant Set. +Crumbs: +Parent:Engine/Blueprints/BP_HowTo/WorkingWithSets +Version: 4.15 +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithSets +Order:3 + +[nav] + +By now, you should have a **TextRender** Actor displaying the contents of a Blueprint Set that you defined in the previous step. +In this step, you're going to learn how to perform an **Intersection** of two Blueprint Sets, ultimately printing the result of +the Intersection in the game's **Viewport**. + +1. From your project's **Content Browser**, double-click the **Display Set** TextRender Actor to open its Blueprint **Event Graph**. + + [REGION:lightbox] + [![](Step3_1.png)(w:600)](Step3_1.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. You should see the **Display Set** TextRender Actor Blueprint **Event Graph**, where you'll be able to add a new Blueprint Set to **Intersect** with the existing **Instruction Set**, ultimately displaying a resultant Set to the **Viewport**. + + [REGION:lightbox] + [![](Step3_2.png)(w:600)](Step3_2.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. At this point in the tutorial, you'll want to create a couple of Blueprint Set containers for the upcoming Intersection. Go ahead and right-click on the **Instruction Set** variable and select **Duplicate** from the drop-down list to create two new Blueprint Set variables, naming them `Shorter Instruction Set` and `Resultant Instruction Set`. + + [REGION:lightbox] + [![](Step3_3.png)(w:600)](Step3_3.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + Performing an Intersection on two Sets (typically) involves a Resultant Set, which will contain only those items that are common to both Sets + [/REGION] + +1. You should now have two new Blueprint Set variables, which you duplicated from the existing **Instruction Set** variable. You should also notice that if you select one of your new Blueprint Sets (for example, **Resultant Instruction Set**), the **Default Value** message should be visible. + + [REGION:lightbox] + [![](Step3_4.png)(w:600)](Step3_4.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Go ahead and click the **Compile** button. + + [REGION:lightbox] + [![](Step3_5.png)(w:600)](Step3_5.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After compiling your Blueprint, you should see the **Default Value** message disappear, making way for some existing elements. As you know, you performed a duplication of the existing **Instruction Set** variable to create two new variables, thereby duplicating the elements that were originally contained in the original Blueprint Set into the newly created containers. + + [REGION:lightbox] + [![](Step3_6.png)(w:600)](Step3_6.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. To clear the **Resultant Instruction Set**, go ahead and click the **Removes all items** button located in the **Default Value** menu. + + [REGION:lightbox] + [![](Step3_7.png)(w:600)](Step3_7.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, clear the items (or elements) from the **Shorter Instruction Set** as well. + + [REGION:lightbox] + [![](Step3_8.png)(w:600)](Step3_8.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Before you can add new logic to the existing Blueprint Event Graph, go ahead and drag the **Shorter Instruction Set** and **Instruction Set** variables into the Blueprint. + + [REGION:lightbox] + [![](Step3_9.png)(w:600)](Step3_9.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +## Scripting the Logic + +1. To get started with building your new logic, drag off the **Shorter Instruction Set** node and add the **Intersection** node from the **Set Utilities** interface. + + [REGION:lightbox] + [![](Step3_10.png)(w:600)](Step3_10.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, connect the **Instruction Set** node to the **Intersection** node. + + [REGION:lightbox] + [![](Step3_11.png)(w:600)](Step3_11.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Right-click in the Blueprint Graph to open the **Context Menu**, where you'll search for and add **Event ActorBeginOverlap**. + + [REGION:lightbox] + [![](Step3_12.png)(w:600)](Step3_12.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Drag off the **Other Actor** pin of the **Event ActorBeginOverlap** node, search for, and add the **Cast To FirstPersonProjectile** node. + + [REGION:lightbox] + [![](Step3_13.png)(w:600)](Step3_13.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, connect the **Cast To FirstPersonProjectile** node to the **Intersection** node. + + [REGION:lightbox] + [![](Step3_14.png)(w:600)](Step3_14.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + Basically, this means that if the First Person Projectile successfully collides with this Actor's collision box, call the **Intersection** node. + [/REGION] + +1. After the **Intersection** node performs its operation on the **Shorter Instruction Set** and the **Instruction Set**, you'll want to store the results in the **Resultant Instruction Set** container. To do this, go ahead and drag off the **Intersection** node and add the **Set Resultant Instruction Set** + + [REGION:lightbox] + [![](Step3_15.png)(w:600)](Step3_15.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Drag off the **Set Resultant Instruction Set** node and add the **To Array** node from the **Set Utilities** interface. + + [REGION:lightbox] + [![](Step3_16.png)(w:600)](Step3_16.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. To iterate through the Array's elements, go ahead and drag off the **To Array** node and add the **ForEachLoop** node. + + [REGION:lightbox] + [![](Step3_17.png)(w:600)](Step3_17.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Connect the **To Array Node** with the **ForEachLoop** node. + + [REGION:lightbox] + [![](Step3_18.png)(w:600)](Step3_18.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, you're ready to print the intersection's results to the **Viewport**. To do this, drag off the **Array Element** pin of the **ForEachLoop** node, search for, and add the **Print String** node. + + [REGION:lightbox] + [![](Step3_19.png)(w:600)](Step3_19.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Connect the **ForEachLoop** node to the **Print String** node. + + [REGION:lightbox] + [![](Step3_20.png)(w:600)](Step3_20.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. At this point, you're ready to determine what the **Resultant Instruction Set** will contain. Let's say, for this example, that you want the **Resultant Instruction Set** variable to only contain `Click`, `Left`, `Mouse`, and `Button`. The first thing you'll want to do, is to perform the intersection on paper: + + | ------------------- | --------------------------- | -------------------------------------------- | + | **Instruction Set** | **Shorter Instruction Set** | **Resultant Instruction Set (A ∩ B)** | + | `Click` | `Click` | `Click` | + | `the` | `Left` | `Left` | + | `Left` | `Mouse` | `Mouse` | + | `Mouse` | `Button` | `Button` | + | `Button` | | | + | `and` | | | + | `Fire` | | | + + [REGION:note] + As you can see from the paper-study you just performed, items common to both **Instruction Set** and **Shorter Instruction Set** are stored in the **Resultant Set** container. Whenever you're performing logical operations on Sets, it's good practice to perform the operation on paper (or a whiteboard) before scripting the logic into your Blueprint Graphs. + [/REGION] + +1. Now that you know what items you want to store in the **Shorter Instruction Set** container, go ahead and select **Shorter Instruction Set** to inspect the container's contents. + + [REGION:lightbox] + [![](Step3_21.png)(w:600)](Step3_21.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + As you can see from the highlighted image, **Shorter Instruction Set** is currently empty. At this time, if you were to perform an intersection of **Shorter Instruction Set** with **Instruction Set**, the **Resultant Instruction Set** container would be empty. + [/REGION] + +1. Go ahead and fill the **Shorter Instruction Set** container with the following elements: + + [REGION:lightbox] + [![](Step3_22.png)(w:600)](Step3_22.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After inspecting your completed script, go ahead and click the **Compile** button. + + [REGION:lightbox] + [![](Step3_23.png)(w:600)](Step3_23.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Finally, click the **Save** button before going back to the Editor's **Viewport** interface. + + [REGION:lightbox] + [![](Step3_24.png)(w:600)](Step3_24.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. From the Editor's **Viewport** interface, click the **Play** button to see the updated script at work. + + [REGION:lightbox] + [![](Step3_25.png)(w:600)](Step3_25.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +## End Result + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 960 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 540 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + 1lK1w-Qssu0 + [/PARAMLITERAL] +[/OBJECT] + +As you can see from the video, when a First Person Projectile collides with the **Display Set** collision box, the contents of **Resultant Instruction Set** are printed to the **Viewport**. +Looking at the printed items, you'll notice that the items contained in **Resultant Instruction Set** are not in any predictable order, which is a property of Blueprint Sets. If you want to learn +how to perform another Set operation, check out the next step. + +[nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/3/WorkingWithSets_3.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/3/WorkingWithSets_3.INT.udn new file mode 100644 index 000000000000..92237a9617ba --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/3/WorkingWithSets_3.INT.udn @@ -0,0 +1,309 @@ +Availability:Docs +Title:3 - Performing an Intersection of Blueprint Sets +Description:Intersecting two Blueprint Sets, ultimately showing the Resultant Set. +Crumbs:%ROOT% +Parent:Engine/Blueprints/BP_HowTo/WorkingWithSets +Version: 4.15 +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithSets +Order:3 + +[nav] + +By now, you should have a **TextRender** Actor displaying the contents of a Blueprint Set that you defined in the previous step. +In this step, you're going to learn how to perform an **Intersection** of two Blueprint Sets, ultimately printing the result of +the Intersection in the game's **Viewport**. + +1. From your project's **Content Browser**, double-click the **Display Set** TextRender Actor to open its Blueprint **Event Graph**. + + [REGION:lightbox] + [![](Step3_1.png)(w:600)](Step3_1.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. You should see the **Display Set** TextRender Actor Blueprint **Event Graph**, where you'll be able to add a new Blueprint Set to **Intersect** with the existing **Instruction Set**, ultimately displaying a resultant Set to the **Viewport**. + + [REGION:lightbox] + [![](Step3_2.png)(w:600)](Step3_2.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. At this point in the tutorial, you'll want to create a couple of Blueprint Set containers for the upcoming Intersection. Go ahead and right-click on the **Instruction Set** variable and select **Duplicate** from the drop-down list to create two new Blueprint Set variables, naming them `Shorter Instruction Set` and `Resultant Instruction Set`. + + ![](Step3_3.png) + + [REGION:note] + Performing an Intersection on two Sets (typically) involves a Resultant Set, which will contain only those items that are common to both Sets + [/REGION] + +1. You should now have two new Blueprint Set variables, which you duplicated from the existing **Instruction Set** variable. You should also notice that if you select one of your new Blueprint Sets (for example, **Resultant Instruction Set**), the **Default Value** message, saying `Please compile the blueprint`, should be visible. + + [REGION:lightbox] + [![](Step3_4.png)(w:600)](Step3_4.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Go ahead and click the **Compile** button. + + [REGION:lightbox] + [![](Step3_5.png)(w:600)](Step3_5.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After compiling your Blueprint, you should see the **Default Value** message disappear, making way for some existing elements. As you know, you performed a duplication of the existing **Instruction Set** variable to create two new variables, thereby duplicating the elements that were originally contained in the original Blueprint Set into the newly created containers. + + ![](Step3_6.png) + + [REGION:note] + Please note that you can create new variables without having to duplicate existing variables. + [/REGION] + +1. To clear the **Resultant Instruction Set**, go ahead and click the **Removes all items** button located in the **Default Value** menu. + + [REGION:lightbox] + [![](Step3_7.png)(w:600)](Step3_7.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, clear the items (or elements) from the **Shorter Instruction Set**. + + [REGION:lightbox] + [![](Step3_8.png)(w:600)](Step3_8.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Before you can add new logic to the existing Blueprint Event Graph, go ahead and drag the **Shorter Instruction Set** and **Instruction Set** variables into the Blueprint. + + [REGION:lightbox] + [![](Step3_9.png)(w:600)](Step3_9.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +## Scripting the Logic + +1. To get started with building your new logic, drag off the **Shorter Instruction Set** node and add the **Intersection** node from the **Set Utilities** interface. + + [REGION:lightbox] + [![](Step3_10.png)(w:600)](Step3_10.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, connect the **Instruction Set** node to the **Intersection** node. + + [REGION:lightbox] + [![](Step3_11.png)(w:600)](Step3_11.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Right-click in the Blueprint Graph to open the **Context Menu**, where you'll search for and add **Event ActorBeginOverlap**. + + [REGION:lightbox] + [![](Step3_12.png)(w:600)](Step3_12.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Drag off the **Other Actor** pin of the **Event ActorBeginOverlap** node, search for, and add the **Cast To FirstPersonProjectile** node. + + [REGION:lightbox] + [![](Step3_13.png)(w:600)](Step3_13.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, connect the **Cast To FirstPersonProjectile** node to the **Intersection** node. + + [REGION:lightbox] + [![](Step3_14.png)(w:600)](Step3_14.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + Basically, this means that if the First Person Projectile successfully collides with this Actor's collision box, call the **Intersection** node. + [/REGION] + +1. After the **Intersection** node performs its operation on the **Shorter Instruction Set** and the **Instruction Set**, you'll want to store the results in the **Resultant Instruction Set** container. To do this, go ahead and drag off the **Intersection** node and add the **Set Resultant Instruction Set** + + [REGION:lightbox] + [![](Step3_15.png)(w:600)](Step3_15.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Drag off the **Set Resultant Instruction Set** node and add the **To Array** node from the **Set Utilities** interface. + + [REGION:lightbox] + [![](Step3_16.png)(w:600)](Step3_16.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. To iterate through the Array's elements, go ahead and drag off the **To Array** node and add the **ForEachLoop** node. + + [REGION:lightbox] + [![](Step3_17.png)(w:600)](Step3_17.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Connect the **To Array Node** with the **ForEachLoop** node. + + [REGION:lightbox] + [![](Step3_18.png)(w:600)](Step3_18.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, you're ready to print the intersection's results to the **Viewport**. To do this, drag off the **Array Element** pin of the **ForEachLoop** node, search for, and add the **Print String** node. + + [REGION:lightbox] + [![](Step3_19.png)(w:600)](Step3_19.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Connect the **ForEachLoop** node to the **Print String** node. + + [REGION:lightbox] + [![](Step3_20.png)(w:600)](Step3_20.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. At this point, you're ready to determine what the **Resultant Instruction Set** will contain. Let's say, for this example, that you want the **Resultant Instruction Set** variable to only contain `Click`, `Left`, `Mouse`, and `Button`. The first thing you'll want to do, is to perform the intersection on paper: + + | ------------------- | --------------------------- | -------------------------------------------- | + | **Instruction Set** | **Shorter Instruction Set** | **Resultant Instruction Set (A ∩ B)** | + | `Click` | `Click` | `Click` | + | `the` | `Left` | `Left` | + | `Left` | `Mouse` | `Mouse` | + | `Mouse` | `Button` | `Button` | + | `Button` | | | + | `and` | | | + | `Fire` | | | + + [REGION:note] + As you can see from the paper-study you just performed, items common to both **Instruction Set** and **Shorter Instruction Set** are stored in the **Resultant Set** container. Whenever you're performing logical operations on Sets, it's good practice to perform the operation on paper (or a whiteboard) before scripting the logic into your Blueprint Graphs. + [/REGION] + +1. Now that you know what items you want to store in the **Shorter Instruction Set** container, go ahead and select **Shorter Instruction Set** to inspect the container's contents. + + [REGION:lightbox] + [![](Step3_21.png)(w:600)](Step3_21.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + As you can see from the highlighted image, **Shorter Instruction Set** is currently empty. At this time, if you were to perform an intersection of **Shorter Instruction Set** with **Instruction Set**, the **Resultant Instruction Set** container would be empty. + [/REGION] + +1. Go ahead and fill the **Shorter Instruction Set** container with the following elements: + + ![](Step3_22.png) + +1. After inspecting your completed script, go ahead and click the **Compile** button. + + [REGION:lightbox] + [![](Step3_23.png)(w:600)](Step3_23.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Finally, click the **Save** button before going back to the Editor's **Viewport** interface. + + [REGION:lightbox] + [![](Step3_24.png)(w:600)](Step3_24.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. From the Editor's **Viewport** interface, click the **Play** button to see the updated script at work. + + [REGION:lightbox] + [![](Step3_25.png)(w:600)](Step3_25.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +## End Result + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 1lK1w-Qssu0 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +As you can see from the video, when a First Person Projectile collides with the **Display Set** collision box, the contents of **Resultant Instruction Set** are printed to the **Viewport**. +Looking at the printed items, you'll notice that the items contained in **Resultant Instruction Set** are not in any predictable order, which is a property of Blueprint Sets. Check out the +next step to learn how to perform a **Union** of two Blueprint Sets. + +[nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/3/WorkingWithSets_3.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/3/WorkingWithSets_3.JPN.udn new file mode 100644 index 000000000000..a37cc8d7e026 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/3/WorkingWithSets_3.JPN.udn @@ -0,0 +1,310 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:3 - Blueprint Set の Intersection を実行する +Description:2 つの Blueprint Set で Intersect を実行し、Resultant Set で結果を表示する方法 +Crumbs:%ROOT% +Parent:Engine/Blueprints/BP_HowTo/WorkingWithSets +Version:4.15 +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithSets +Order:3 + +[nav] + +前のステップでは **TextRender** アクタが Blueprint Set のコンテンツを表示するように定義をしました。 +このステップでは、2 つの Blueprint Set の **Intersection** を実行し、 +ゲームの **Viewport** に その Intersection の結果を出力します。 + +1. プロジェクトの **コンテンツ ブラウザ** から **Display Set** TextRender アクタをダブルクリックして、ブループリント **イベントグラフ** を開きます。 + + [REGION:lightbox] + [![](Step3_1.png)(w:600)](Step3_1.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Display Set** TextRender アクタのブループリント **イベントグラフ** が表示されます。ここで、既存の **Instruction Set** を使って新規の Blueprint Set を **Intersect** に追加して、最後に Resultant Set を **ビューポート** に表示します。 + + [REGION:lightbox] + [![](Step3_2.png)(w:600)](Step3_2.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. ここで、これから使う Intersection 用に Blueprint Set コンテナをいくつか作成する必要があります。**Instruction Set** 変数を右クリックしてドロップダウン リストから **[Duplicate]** を選択し、新規の Blueprint Set 変数を 2 つ作成して、それぞれに「`Shorter Instruction Set`」と「`Resultant Instruction Set`」と名前を付けます。 + + ![](Step3_3.png) + + [REGION:note] + 2 つの Set (一般的に) で Intersection を実行すると、2 つの Set に共通するアイテムのみが含まる Resultant Set が発生します。 + [/REGION] + +1. 今、既存の **Instruction Set** 変数から複製した、新しい Blueprint Set 変数が 2 つあります。新しい Blueprints Set のいずれか (例えば **Resultant Instruction Set**) を選択すると、「`Please compile the blueprint`(ブループリントをコンパイルしてください)」という **Default Value** メッセージが可視化されます。 + + [REGION:lightbox] + [![](Step3_4.png)(w:600)](Step3_4.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **[Compile]** ボタンをクリックします。 + + [REGION:lightbox] + [![](Step3_5.png)(w:600)](Step3_5.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. ブループリントのコンパイルを完了すると **Default Value** メッセージが消えて、既存エレメントが表示されます。ご存じのように、この 2 つの新しい変数は、既存の **Instruction Set** 変数を複製して作成されたので、複製元の Blueprint Set に入っていたエレメントが新規に作成されたコンテナに複製されています。 + + ![](Step3_6.png) + + [REGION:note] + 既存変数を複製せずに新規変数の作成ができることに注目してください。 + [/REGION] + +1. **Resultant Instruction Set** をクリアするには、**[Default Value]** メニューにある **Removes all items** ボタンをクリックします。 + + [REGION:lightbox] + [![](Step3_7.png)(w:600)](Step3_7.png) + [/REGION] + [REGION:caption] + + クリックしてフルサイズで表示 + [/REGION] + +1. **Shorter Instruction Set** からアイテム (またはエレメント) をクリアします。 + + [REGION:lightbox] + [![](Step3_8.png)(w:600)](Step3_8.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 新規ロジックを既存のブループリント イベントグラフに追加する前に、**Shorter Instruction Set** 変数と **Instruction Set** 変数をブループリントにドラッグします。 + + [REGION:lightbox] + [![](Step3_9.png)(w:600)](Step3_9.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +## ロジックのスクリプト処理 + +1. 新規ロジックをビルドするには、**Shorter Instruction Set** ノードを引き出して **Set Utilities** インターフェースから **Intersection** ノードを追加します。 + + [REGION:lightbox] + [![](Step3_10.png)(w:600)](Step3_10.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Instruction Set** ノードを **Intersection** ノードに接続します。 + + [REGION:lightbox] + [![](Step3_11.png)(w:600)](Step3_11.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. ブループリント グラフ内を右クリックして **コンテキスト メニュー** を開き、**Event ActorBeginOverlap** の検索と追加を行います。 + + [REGION:lightbox] + [![](Step3_12.png)(w:600)](Step3_12.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Event ActorBeginOverlap** ノードから **Other Actor** ピンを引き出して、**Cast To FirstPersonProjectile** ノードの検索と追加を行います。 + + [REGION:lightbox] + [![](Step3_13.png)(w:600)](Step3_13.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Cast To FirstPersonProjectile** ノードを **Intersection** ノードに接続します。 + + [REGION:lightbox] + [![](Step3_14.png)(w:600)](Step3_14.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + + [REGION:note] + 基本的に、First Person Projectile がこのアクタのコリジョン ボックスと問題なく衝突すれば **Intersection** ノードを呼び出すことになります。 + [/REGION] + +1. **Intersection** ノードが **Shorter Instruction Set** と **Instruction Set** 上で演算を実行した後、その結果を **Resultant Instruction Set** コンテナに格納します。**Intersection** ノードを引き出して **Set Resultant Instruction Set** を追加します。 + + [REGION:lightbox] + [![](Step3_15.png)(w:600)](Step3_15.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Set Resultant Instruction Set** ノードを引き出して **Set Utilities** インターフェースから **To Array** ノードを追加します。 + + [REGION:lightbox] + [![](Step3_16.png)(w:600)](Step3_16.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. Array のエレメントでイタレートするためには、**To Array** ノードを引き出して **ForEachLoop** ノードに追加します。 + + [REGION:lightbox] + [![](Step3_17.png)(w:600)](Step3_17.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **To Array ノード** と **ForEachLoop** ノードを接続します。 + + [REGION:lightbox] + [![](Step3_18.png)(w:600)](Step3_18.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. これで、Intersection の結果を **Viewport** に出力することができます。**ForEachLoop** ノードの **Array Element** ピンを引き出して、**Print String** ノードの検索と追加を行います。 + + [REGION:lightbox] + [![](Step3_19.png)(w:600)](Step3_19.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **ForEachLoop** ノードを **Print String** ノードに接続します。 + + [REGION:lightbox] + [![](Step3_20.png)(w:600)](Step3_20.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. この段階で **Resultant Instruction Set** に何を入れるか決めることができます。例えば、**Resultant Instruction Set** 変数に `Click`、`Left`、`Mouse`、`Button` のみを含むようにしてみましょう。まず最初に、紙で Intersection を実行してみます。 + + | ------------------- | --------------------------- | -------------------------------------------- | + | **Instruction Set** | **Shorter Instruction Set** | **Resultant Instruction Set (A ∩ B)** | + | `Click` | `Click` | `Click` | + | `the` | `Left` | `Left` | + | `Left` | `Mouse` | `Mouse` | + | `Mouse` | `Button` | `Button` | + | `Button` | | | + | `and` | | | + | `Fire` | | | + + [REGION:note] + たった今行った紙面での実行で分かるように、**Instruction Set** と **Shorter Instruction Set** の両方に共通したアイテムは **Resultant Set** コンテナに格納されます。ロジック演算を Set で実行する場合のぐっとプラクティスは、まず演算を紙 (またはホワイトボード) に書き出してみてから、ブループリント グラフでロジックのスクリプト処理をすることです。 + [/REGION] + +1. **Shorter Instruction Set** コンテナに格納するアイテムを決めたら、**Shorter Instruction Set** を選択してコンテナのコンテンツを調べます。 + + [REGION:lightbox] + [![](Step3_21.png)(w:600)](Step3_21.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + + [REGION:note] + 画像の黄色枠を見ると分かりますが、**Shorter Instruction Set** は現在空です。この状態で **Instruction Set** を使って **Shorter Instruction Set** を実行すると **Resultant Instruction Set** コンテナは空になります。 + [/REGION] + +1. 次のエレメントを **Shorter Instruction Set** コンテナに入力します。 + + ![](Step3_22.png) + +1. 完成したスクリプトを確認したら、**[Compile]** ボタンをクリックします。 + + [REGION:lightbox] + [![](Step3_23.png)(w:600)](Step3_23.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 最後に、完成したスクリプト全体を確認したら、エディタの **Viewport** インターフェースに戻る前に **[Save]** ボタンをクリックします。 + + [REGION:lightbox] + [![](Step3_24.png)(w:600)](Step3_24.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. エディタの **Viewport** インターフェースで、**[Play]** ボタンをクリックして更新されたスクリプトの動きを確認します。 + + [REGION:lightbox] + [![](Step3_25.png)(w:600)](Step3_25.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +## 結果 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 1lK1w-Qssu0 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +動画を見ると分かりますが、First Person Projectile が **Display Set** コリジョン ボックスと衝突すると、**Resultant Instruction Set** のコンテンツが **Viewport** に出力されます。 +出力されたアイテムを見ると **Resultant Instruction Set** の中にあるアイテムの順序は予測できません。これは Blueprint Set の属性です。次のステップで、 +2 つの Blueprint Set で**Union** を実行する方法を説明します。 + +[nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/3/WorkingWithSets_3.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/3/WorkingWithSets_3.KOR.udn new file mode 100644 index 000000000000..c1395c3ae77f --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/3/WorkingWithSets_3.KOR.udn @@ -0,0 +1,310 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:3 - 블루프린트 세트 교집합 연산 +Description:두 블루프린트 세트의 교집합 연산을 한 뒤 결과 세트를 표시합니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/BP_HowTo/WorkingWithSets +Version: 4.15 +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithSets +Order:3 + +[nav] + +이제 예전 단계에서 정의한 블루프린트 세트의 내용을 표시하는 **TextRender** 액터가 있을 것입니다. +여기서는 두 블루프린트 세트의 **Intersection** (교집합) 연산을 한 뒤 그 결과를 +게임 **뷰포트** 에 출력하는 법을 알아보겠습니다. + +1. 프로젝트의 **콘텐츠 브라우저** 에서 **Display Set** TextRender Actor 를 더블클릭하여 블루프린트 **이벤트 그래프** 를 엽니다. + + [REGION:lightbox] + [![](Step3_1.png)(w:600)](Step3_1.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **Display Set** TextRender 액터 블루프린트 **이벤트 그래프** 가 보일 것입니다. 여기서 새 블루프린트 세트를 추가하여 기존 **Instruction Set** 와 **Intersect** (교집합) 연산을 하고, 그 결과 세트를 **뷰포트** 에 표시하도록 하겠습니다. + + [REGION:lightbox] + [![](Step3_2.png)(w:600)](Step3_2.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 이 시점에서 교집합 연산을 위한 블루프린트 세트 컨테이너가 두 개 있어야 할 것입니다. **Instruction Set** 변수에 우클릭하고 드롭다운 리스트에서 **복제** 를 선택하여 블루프린트 세트 변수를 두 개 새로 만듭니다. 이름은 `Shorter Instruction Set` 와 `Resultant Instruction Set` 라 짓습니다. + + ![](Step3_3.png) + + [REGION:note] + (보통) 두 세트에 교집합 연산을 하면 Resultant Set 가 나오는데, 두 세트 모두에 공통인 아이템만 들어있게 됩니다. + [/REGION] + +1. 이제 기존 **Instruction Set** 에서 복제한 새로운 블루프린트 세트 변수가 두 개 생겼을 것입니다. 새 블루프린트 세트 중 하나(, 예로 **Resultant Instruction Set**) 를 선택하면 **Default Value** 메시지가 보일 것입니다. + + [REGION:lightbox] + [![](Step3_4.png)(w:600)](Step3_4.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **컴파일** 버튼을 클릭합니다. + + [REGION:lightbox] + [![](Step3_5.png)(w:600)](Step3_5.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 블루프린트를 컴파일한 후, **Default Value** 메시지가 사라져 기존 엘리먼트에 공간을 내주는 것이 보일 것입니다. 아시다시피 기존 **Instruction Set** 변수를 복제하여 변수를 둘 새로 만들었으므로, 원본 블루프린트 세트에 들어있는 엘리먼트가 새로 생성된 컨테이너에 복제된 것입니다. + + ![](Step3_6.png) + + [REGION:note] + 참고로 기존 변수를 복제하지 않고도 새 변수를 만들 수 있습니다. + [/REGION] + +1. **Resultant Instruction Set** 를 비우기 위해 **Default Value** 메뉴에 위치한 **Removes all items** (모든 아이템 제거) 버튼을 클릭합니다. + + [REGION:lightbox] + [![](Step3_7.png)(w:600)](Step3_7.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **Shorter Instruction Set** 에서도 모든 아이템( 또는 엘리먼트들)을 비웁니다. + + [REGION:lightbox] + [![](Step3_8.png)(w:600)](Step3_8.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 기존 블루프린트 이벤트 그래프에 새로운 로직을 추가하기에 앞서, **Shorter Instruction Set** 와 **Instruction Set** 변수를 끌어 블루프린트에 놓습니다. + + [REGION:lightbox] + [![](Step3_9.png)(w:600)](Step3_9.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +## 로직 스크립트 작성 + +1. 새로운 로직 작성을 시작하기 위해, **Shorter Instruction Set** 노드를 끌어 놓고 **Set Utilities** 인터페이스에서 **Intersection** 노드를 추가합니다. + + [REGION:lightbox] + [![](Step3_10.png)(w:600)](Step3_10.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **Instruction Set** 노드를 **Intersection** 노드에 연결합니다. + + [REGION:lightbox] + [![](Step3_11.png)(w:600)](Step3_11.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 블루프린트 그래프에 우클릭하여 **맥락 메뉴** 를 열고, **Event ActorBeginOverlap** 을 검색 추가합니다. + + [REGION:lightbox] + [![](Step3_12.png)(w:600)](Step3_12.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **Event ActorBeginOverlap** 노드의 **Other Actor** 핀을 끌어 놓고 **Cast To FirstPersonProjectile** 노드를 검색 추가합니다. + + [REGION:lightbox] + [![](Step3_13.png)(w:600)](Step3_13.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **Cast To FirstPersonProjectile** 노드를 **Intersection** 노드에 연결합니다. + + [REGION:lightbox] + [![](Step3_14.png)(w:600)](Step3_14.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + + [REGION:note] + 기본적으로 First Person Projectile 가 이 액터의 콜리전 박스에 성공적으로 충돌하면, **Intersection** 노드를 호출하라는 뜻입니다. + [/REGION] + +1. **Intersection** 노드가 **Shorter Instruction Set** 와 **Instruction Set** 에 대한 연산을 수행한 이후, 그 결과를 **Resultant Instruction Set** 컨테이너에 저장하려 합니다. 그러기 위해 **Intersection** 노드를 끌어 놓고 **Set Resultant Instruction Set** 를 추가합니다. + + [REGION:lightbox] + [![](Step3_15.png)(w:600)](Step3_15.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **Set Resultant Instruction Set** 노드를 끌어 놓고 **Set Utilities** 인터페이스에서 **To Array** 노드를 추가합니다. + + [REGION:lightbox] + [![](Step3_16.png)(w:600)](Step3_16.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 배열의 엘리먼트를 대상으로 반복처리하기 위해, **To Array** 노드를 끌어 놓고 **ForEachLoop** 노드를 추가합니다. + + [REGION:lightbox] + [![](Step3_17.png)(w:600)](Step3_17.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **To Array Node** 노드를 **ForEachLoop** 노드와 연결합니다. + + [REGION:lightbox] + [![](Step3_18.png)(w:600)](Step3_18.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 이제 교집합 결과를 **뷰포트** 에 출력할 준비가 되었습니다. **ForEachLoop** 노드의 **Array Element** 핀을 끌어 놓고, **Print String** 노드를 검색 추가합니다. + + [REGION:lightbox] + [![](Step3_19.png)(w:600)](Step3_19.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **ForEachLoop** 노드를 **Print String** 노드에 연결합니다. + + [REGION:lightbox] + [![](Step3_20.png)(w:600)](Step3_20.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 이제 **Resultant Instruction Set** 에 무엇을 저장할지 결정할 준비가 되었습니다. 예를 들어 **Resultant Instruction Set** 변수에 `Click`, `Left`, `Mouse`, `Button` 만 들어가기를 원한다 칩시다. 교집합 연산을 종이에 먼저 써 보면 이렇습니다: + + | ------------------- | --------------------------- | -------------------------------------------- | + | **Instruction Set** | **Shorter Instruction Set** | **Resultant Instruction Set (A ∩ B)** | + | `Click` | `Click` | `Click` | + | `the` | `Left` | `Left` | + | `Left` | `Mouse` | `Mouse` | + | `Mouse` | `Button` | `Button` | + | `Button` | | | + | `and` | | | + | `Fire` | | | + + [REGION:note] + 방금 종이에 쓴 내용에서 알 수 있듯이, **Instruction Set** 와 **Shorter Instruction Set** 양쪽에 공통인 아이템이 **Resultant Set** 컨테이너에 저장됩니다. 세트에 논리 연산을 수행할 때마다, 종이(나 화이트보드)에 연산을 먼저 해 보고 블루프린트 그래프에 로직 스크립트를 작성하는 습관을 들이는 것이 좋습니다. + [/REGION] + +1. **Shorter Instruction Set** 컨테이너에 저장하려는 아이템이 무엇인지 알았으니, **Shorter Instruction Set** 를 선택하여 컨테이너의 내용을 조사합니다. + + [REGION:lightbox] + [![](Step3_21.png)(w:600)](Step3_21.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + + [REGION:note] + 강조된 이미지에서 보시듯이, **Shorter Instruction Set** 는 현재 공백입니다. 이 시점에서, **Shorter Instruction Set** 와 **Instruction Set** 에 **Intersection** 연산을 한다면, **Resultant Instruction Set** 컨테이너는 공백이 될 것입니다. + [/REGION] + +1. **Shorter Instruction Set** 컨테이너를 다음 엘리먼트로 채웁니다: + + ![](Step3_22.png) + +1. 완성된 스크립트를 살펴본 후 **컴파일** 버튼을 클릭합니다. + + [REGION:lightbox] + [![](Step3_23.png)(w:600)](Step3_23.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 마지막으로 **저장** 버튼을 누르고 에디터의 **뷰포트** 인터페이스로 돌아갑니다. + + [REGION:lightbox] + [![](Step3_24.png)(w:600)](Step3_24.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 에디터의 **뷰포트** 인터페이스에서 **플레이** 버튼을 클릭하여 업데이트된 스크립트가 작동하는 모습을 확인합니다. + + [REGION:lightbox] + [![](Step3_25.png)(w:600)](Step3_25.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +## 최종 결과 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 1lK1w-Qssu0 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +비디오에서 보시듯이 First Person Projectile 이 **Display Set** 콜리전 박스와 충돌하면, **Resultant Instruction Set** 내용이 **뷰포트** 에 출력됩니다. +출력된 아이템을 살펴보면, **Resultant Instruction Set** 에 들어있는 아이템의 순서를 예측할 수가 없는 것을 알 수 있는데, 블루프린트 세트의 특성입니다. **Union** (합집합) 연산 방법은 +다음 단계를 확인해 보세요. + +[nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/4/WorkingWithSets_4.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/4/WorkingWithSets_4.CHN.udn new file mode 100644 index 000000000000..dc0e9e8476eb --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/4/WorkingWithSets_4.CHN.udn @@ -0,0 +1,244 @@ +INTSourceChangelist:0 +Availability:Docs +Title:4 - Performing a Union of Blueprint Sets +Description:Performing the Union of two Blueprint Sets, ultimately printing the result. +Crumbs: +Parent:Engine/Blueprints/BP_HowTo/WorkingWithSets +Version: 4.15 +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithSets +Order:4 + +[nav] + +In this step, the final one of this tutorial, you'll learn how to perform a **Union** of two Blueprint Sets, ultimately printing the result of the Union in the game's **Viewport**. + +1. From your project's **Content Browser**, double-click the **Display Set** TextRender Actor to open its Blueprint **Event Graph**. + + [REGION:lightbox] + [![](Step4_1.png)(w:600)](Step4_1.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. At this point in the tutorial, you'll want to create a new Blueprint Set container for the upcoming Union. Go ahead and right-click on the **Shorter Instruction Set** Variable and select **Duplicate** from the drop-down list to create a new Blueprint Set variable, naming it `Longer Instruction Set`. + + [REGION:lightbox] + [![](Step4_2.png)(w:600)](Step4_2.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, go ahead and click the **Compile** button. + + [REGION:lightbox] + [![](Step4_3.png)(w:600)](Step4_3.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Click the **Removes all items** button to clear all of the items from the **Longer Instruction Set**. + + [REGION:lightbox] + [![](Step4_4.png)(w:600)](Step4_4.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Add the following items to your new **Longer Instruction Set** container: + + [REGION:lightbox] + [![](Step4_5.png)(w:600)](Step4_5.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Drag the **Longer Instruction Set** and the **Instruction Set** variables into the Blueprint Graph. + + [REGION:lightbox] + [![](Step4_6.png)(w:600)](Step4_6.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +## Scripting the Logic + +1. To get started with building your new logic, drag off the **Longer Instruction Set** and add the **Union** node from the **Set Utilities** interface. + + [REGION:lightbox] + [![](Step4_7.png)(w:600)](Step4_7.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Connect the **Instruction Set** node to the **Union** node. + + [REGION:lightbox] + [![](Step4_8.png)(w:600)](Step4_8.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Connect the **Cast Failed** pin of the **Cast To FirstPersonProjectile** node to the **Union** node. + + [REGION:lightbox] + [![](Step4_9.png)(w:600)](Step4_9.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, drag off the **Union** node, search for, and add the **To Array** node. + + [REGION:lightbox] + [![](Step4_10.png)(w:600)](Step4_10.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Drag off the **To Array** node, search for, and add the **ForEachLoop** node. + + [REGION:lightbox] + [![](Step4_11.png)(w:600)](Step4_11.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Connect the **To Array** node to the **ForEachLoop** node. + + [REGION:lightbox] + [![](Step4_12.png)(w:600)](Step4_12.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, you're ready to print the union's results to the **Viewport**. To do this, drag off the **Array Element** pin of the **ForEachLoop** node, search for, and add the **Print String** node. + + [REGION:lightbox] + [![](Step4_13.png)(w:600)](Step4_13.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Connect the **ForEachLoop** node to the **Print String** node. + + [REGION:lightbox] + [![](Step4_14.png)(w:600)](Step4_14.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Because you already have a debug message being printed, you'll want to change the color of the text being printed to the **Viewport**. To do this, go ahead and click the menu expansion arrow, which is located at the bottom of the **Print String** node. + + [REGION:lightbox] + [![](Step4_15.png)(w:600)](Step4_15.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Click on the **Text Color** box to open the **Color Picker** menu. + + [REGION:lightbox] + [![](Step4_16.png)(w:600)](Step4_16.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Go ahead and set the color to the following values: + + ![](Step4_17.png) + +1. Now, go ahead and click the **Compile** button. + + [REGION:lightbox] + [![](Step4_18.png)(w:600)](Step4_18.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After expecting your completed script, go ahead and click the **Save** button before returning to the Editor's **Viewport** interface. + + [REGION:lightbox] + [![](Step4_19.png)(w:600)](Step4_19.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. From the Editor's **Viewport** interface, click the **Play** button to see the updated script at work. + + [REGION:lightbox] + [![](Step4_20.png)(w:600)](Step4_20.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +## End Result + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 960 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 540 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + 3PevHZoBX3E + [/PARAMLITERAL] +[/OBJECT] + +As you can see from the video, when the First Person Character collides with the **Display Set** collision box, the result of the **Union** is printed to the **Viewport**. +Again, looking at the printed items, you'll notice that the items are not in any predictable order, which is a property of Blueprint Sets. As a final reminder, if you performed +a Union operation of both Blueprint Sets on paper, you would have come up with the following result: + +| ------------------- | --------------------------- | -------------------------------------------- | +| **Instruction Set** | **Longer Instruction Set** | **Resultant Output (A ∪ B)** | +| `Click` | `your` | `Click` | +| `the` | `Gun` | `the` | +| `Left` | | `Left` | +| `Mouse` | | `Mouse` | +| `Button` | | `Button` | +| `and` | | `and` | +| `Fire` | | `Fire` | +| | | `your` | +| | | `Gun` | + +[nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/4/WorkingWithSets_4.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/4/WorkingWithSets_4.INT.udn new file mode 100644 index 000000000000..da2e771d3b6f --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/4/WorkingWithSets_4.INT.udn @@ -0,0 +1,237 @@ +Availability:Docs +Title:4 - Performing a Union of Blueprint Sets +Description:Performing the Union of two Blueprint Sets, ultimately printing the result. +Crumbs:%ROOT% +Parent:Engine/Blueprints/BP_HowTo/WorkingWithSets +Version: 4.15 +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithSets +Order:4 + +[nav] + +In this step, the final one of this tutorial, you'll learn how to perform a **Union** of two Blueprint Sets, ultimately printing the result of the Union in the game's **Viewport**. + +1. From your project's **Content Browser**, double-click the **Display Set** TextRender Actor to open its Blueprint **Event Graph**. + + [REGION:lightbox] + [![](Step4_1.png)(w:600)](Step4_1.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. At this point in the tutorial, you'll want to create a new Blueprint Set container for the upcoming Union. Go ahead and right-click on the **Shorter Instruction Set** Variable and select **Duplicate** from the drop-down list to create a new Blueprint Set variable, naming it `Longer Instruction Set`. + + ![](Step4_2.png) + +1. Now, go ahead and click the **Compile** button. + + [REGION:lightbox] + [![](Step4_3.png)(w:600)](Step4_3.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Click the **Removes all items** button to clear all of the items from the **Longer Instruction Set**. + + [REGION:lightbox] + [![](Step4_4.png)(w:600)](Step4_4.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Add the following items to your new **Longer Instruction Set** container: + + ![](Step4_5.png) + +1. Drag the **Longer Instruction Set** and the **Instruction Set** variables into the Blueprint Graph. + + [REGION:lightbox] + [![](Step4_6.png)(w:600)](Step4_6.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +## Scripting the Logic + +1. To get started with building your new logic, drag off the **Longer Instruction Set** and add the **Union** node from the **Set Utilities** interface. + + [REGION:lightbox] + [![](Step4_7.png)(w:600)](Step4_7.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Connect the **Instruction Set** node to the **Union** node. + + [REGION:lightbox] + [![](Step4_8.png)(w:600)](Step4_8.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Connect the **Cast Failed** pin of the **Cast To FirstPersonProjectile** node to the **Union** node. + + [REGION:lightbox] + [![](Step4_9.png)(w:600)](Step4_9.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, drag off the **Union** node, search for, and add the **To Array** node. + + [REGION:lightbox] + [![](Step4_10.png)(w:600)](Step4_10.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Drag off the **To Array** node, search for, and add the **ForEachLoop** node. + + [REGION:lightbox] + [![](Step4_11.png)(w:600)](Step4_11.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Connect the **To Array** node to the **ForEachLoop** node. + + [REGION:lightbox] + [![](Step4_12.png)(w:600)](Step4_12.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, you're ready to print the union's results to the **Viewport**. To do this, drag off the **Array Element** pin of the **ForEachLoop** node, search for, and add the **Print String** node. + + [REGION:lightbox] + [![](Step4_13.png)(w:600)](Step4_13.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Connect the **ForEachLoop** node to the **Print String** node. + + [REGION:lightbox] + [![](Step4_14.png)(w:600)](Step4_14.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Because you already have a debug message being printed, you'll want to change the color of the text being printed to the **Viewport**. To do this, go ahead and click the menu expansion arrow, which is located at the bottom of the **Print String** node. + + [REGION:lightbox] + [![](Step4_15.png)(w:600)](Step4_15.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Click on the **Text Color** box to open the **Color Picker** menu. + + [REGION:lightbox] + [![](Step4_16.png)(w:600)](Step4_16.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Go ahead and set the color to the following values: + + ![](Step4_17.png) + +1. Now, go ahead and click the **Compile** button. + + [REGION:lightbox] + [![](Step4_18.png)(w:600)](Step4_18.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After expecting your completed script, go ahead and click the **Save** button before returning to the Editor's **Viewport** interface. + + [REGION:lightbox] + [![](Step4_19.png)(w:600)](Step4_19.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. From the Editor's **Viewport** interface, click the **Play** button to see the updated script at work. + + [REGION:lightbox] + [![](Step4_20.png)(w:600)](Step4_20.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +## End Result + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 3PevHZoBX3E + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +As you can see from the video, when the First Person Character collides with the **Display Set** collision box, the result of the **Union** is printed to the **Viewport**. +Again, looking at the printed items, you'll notice that the items are not in any predictable order, which is a property of Blueprint Sets. As a final reminder, if you performed +a Union operation of both Blueprint Sets on paper, you would have come up with the following result: + +| ------------------- | --------------------------- | -------------------------------------------- | +| **Instruction Set** | **Longer Instruction Set** | **Resultant Output (A ∪ B)** | +| `Click` | `your` | `Click` | +| `the` | `Gun` | `the` | +| `Left` | | `Left` | +| `Mouse` | | `Mouse` | +| `Button` | | `Button` | +| `and` | | `and` | +| `Fire` | | `Fire` | +| | | `your` | +| | | `Gun` | + +[nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/4/WorkingWithSets_4.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/4/WorkingWithSets_4.JPN.udn new file mode 100644 index 000000000000..1ff6f3d504da --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/4/WorkingWithSets_4.JPN.udn @@ -0,0 +1,238 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:4 - Blueprint Set の Union を実行する +Description:2 つの Blueprint Set で Union を実行し、最終的に Resultant Set で表示する方法 +Crumbs:%ROOT% +Parent:Engine/Blueprints/BP_HowTo/WorkingWithSets +Version:4.15 +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithSets +Order:4 + +[nav] + +チュートリアルの最後のステップです。2 つの Blueprint Set の **Union** を実行し、最終的にゲームの **ビューポート** に出力します。 + +1. プロジェクトの **コンテンツ ブラウザ** から **Display Set** TextRender アクタをダブルクリックして、ブループリント **イベントグラフ** を開きます。 + + [REGION:lightbox] + [![](Step4_1.png)(w:600)](Step4_1.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. この時点で、これから Unon で使用する Blueprint Set コンテナをいくつか作成する必要があります。**Shorter Instruction Set** 変数を右クリックしてドロップダウン リストから **[Duplicate]** を選択し、新規の Blueprint Set 変数を作成し、「`Longer Instruction Set`」とと名前を付けます。 + + ![](Step4_2.png) + +1. **[Compile]** ボタンをクリックします。 + + [REGION:lightbox] + [![](Step4_3.png)(w:600)](Step4_3.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **[Removes all items (すべてのアイテムを除去する)]** ボタンをクリックして **Longer Instruction Set** からすべてのアイテムをクリアします。 + + [REGION:lightbox] + [![](Step4_4.png)(w:600)](Step4_4.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 以下のアイテムを新規に作成した **Longer Instruction Set** コンテナに追加します。 + + ![](Step4_5.png) + +1. **Longer Instruction Set** 変数と **Instruction Set** 変数をブループリント グラフにドラッグします。 + + [REGION:lightbox] + [![](Step4_6.png)(w:600)](Step4_6.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +## ロジックのスクリプト処理 + +1. 新規ロジックをビルドするには、**Longer Instruction Set** ノードを引き出して **Set Utilities** インターフェースから **Union** ノードを追加します。 + + [REGION:lightbox] + [![](Step4_7.png)(w:600)](Step4_7.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Instruction Set** ノードを **Union** ノードに接続します。 + + [REGION:lightbox] + [![](Step4_8.png)(w:600)](Step4_8.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Cast To FirstPersonProjectile** ノードの **Cast Failed** を **Union** ノードに接続します。 + + [REGION:lightbox] + [![](Step4_9.png)(w:600)](Step4_9.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **Union** ノードを引き出して **To Array** ノードを探して追加します。 + + [REGION:lightbox] + [![](Step4_10.png)(w:600)](Step4_10.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **To Array** ノードを引き出して **ForEachLoop** ノードを探して追加します。 + + [REGION:lightbox] + [![](Step4_11.png)(w:600)](Step4_11.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **To Array** ノード と **ForEachLoop** ノードを接続します。 + + [REGION:lightbox] + [![](Step4_12.png)(w:600)](Step4_12.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. これで、Union の結果を **Viewport** に出力することができます。**ForEachLoop** ノードの **Array Element** ピンを引き出して、**Print String** ノードを探して追加します。 + + [REGION:lightbox] + [![](Step4_13.png)(w:600)](Step4_13.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **ForEachLoop** ノードを **Print String** ノードに接続します。 + + [REGION:lightbox] + [![](Step4_14.png)(w:600)](Step4_14.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. デバッグ メッセージが出力されているので、**ビューポート** へ出力されるテキストの色を変更することができます。**Print String** ノードの下にある矢印をクリックしてメニューを展開します。 + + [REGION:lightbox] + [![](Step4_15.png)(w:600)](Step4_15.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **[Text Color]** ボックスをクリックして **[Color Picker]** メニューを開きます。 + + [REGION:lightbox] + [![](Step4_16.png)(w:600)](Step4_16.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 色を以下の値に設定します。 + + ![](Step4_17.png) + +1. **[Compile]** ボタンをクリックします。 + + [REGION:lightbox] + [![](Step4_18.png)(w:600)](Step4_18.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 完成したスクリプトを確認したら、エディタの **Viewport** インターフェースに戻る前に **[Save]** ボタンをクリックします。 + + [REGION:lightbox] + [![](Step4_19.png)(w:600)](Step4_19.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. エディタの **Viewport** インターフェースで、**[Play]** ボタンをクリックして更新されたスクリプトの動きを確認します。 + + [REGION:lightbox] + [![](Step4_20.png)(w:600)](Step4_20.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +## 結果 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 3PevHZoBX3E + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +動画を見ると分かりますが、First Person Character が **Display Set** コリジョン ボックスと衝突すると、**Union** のコンテンツが **Viewport** に出力されます。 +出力されたアイテムを見ると、ここでもまたアイテムの順序は予測できないことが分かります。これは Blueprint Set の属性です。最後の念を押しておきますが、 +2 つの Blueprint Set の Union 演算を紙面で行うと、以下のような結果になります。 + +| ------------------- | --------------------------- | -------------------------------------------- | +| **Instruction Set** | **Longer Instruction Set** | **Resultant Output (A ∪ B)** | +| `Click` | `your` | `Click` | +| `the` | `Gun` | `the` | +| `Left` | | `Left` | +| `Mouse` | | `Mouse` | +| `Button` | | `Button` | +| `and` | | `and` | +| `Fire` | | `Fire` | +| | | `your` | +| | | `Gun` | + +[nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/4/WorkingWithSets_4.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/4/WorkingWithSets_4.KOR.udn new file mode 100644 index 000000000000..2585c0fe58e6 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/4/WorkingWithSets_4.KOR.udn @@ -0,0 +1,238 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:4 - 블루프린트 세트 합집합 +Description:두 블루프린트 세트의 Union, 합집합 연한 후 결과를 출력해 봅니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/BP_HowTo/WorkingWithSets +Version: 4.15 +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithSets +Order:4 + +[nav] + +이 최종 단계에서는 두 블루프린트 세트의 **Union** (합집합) 연산 후 그 결과를 게임 뷰포트에 출력해 보겠습니다. + +1. 프로젝트의 **콘텐츠 브라우저** 에서 **Display Set** TextRender Actor 에 클릭하여 블루프린트 **이벤트 그래프** 를 엽니다. + + [REGION:lightbox] + [![](Step4_1.png)(w:600)](Step4_1.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 이 시점에서 합집합에 쓸 새로운 블루프린트 세트 컨테이너가 필요합니다. **Shorter Instruction Set** 변수에 우클릭하고 드롭다운 리스트에서 **복제** 를 선택하여 블루프린트 세트 변수를 새로 만들고, 이름을 `Longer Instruction Set` 라 합니다. + + ![](Step4_2.png) + +1. **컴파일** 버튼을 클릭합니다. + + [REGION:lightbox] + [![](Step4_3.png)(w:600)](Step4_3.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **Removes all items** (모든 아이템 제거) 버튼을 클릭하여 **Longer Instruction Set** 에서 모든 아이템을 지웁니다. + + [REGION:lightbox] + [![](Step4_4.png)(w:600)](Step4_4.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 새로운 **Longer Instruction Set** 컨테이너에 다음 아이템을 추가합니다: + + ![](Step4_5.png) + +1. **Longer Instruction Set** 와 **Instruction Set** 변수를 블루프린트 그래프에 끌어 놓습니다. + + [REGION:lightbox] + [![](Step4_6.png)(w:600)](Step4_6.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +## 로직 스크립트 작성 + +1. 새 로직 작성 시작은 **Longer Instruction Set** 를 끌어 놓고 **Set Utilities** 인터페이스에서 **Union** (합집합) 노드를 추가합니다. + + [REGION:lightbox] + [![](Step4_7.png)(w:600)](Step4_7.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **Instruction Set** 노드를 **Union** 노드에 연결합니다. + + [REGION:lightbox] + [![](Step4_8.png)(w:600)](Step4_8.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **Cast To FirstPersonProjectile** 노드의 **Cast Failed** 핀을 **Union** 노드에 연결합니다. + + [REGION:lightbox] + [![](Step4_9.png)(w:600)](Step4_9.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 이제 **Union** 노드를 끌어 놓고, **To Array** 노드를 검색 추가합니다. + + [REGION:lightbox] + [![](Step4_10.png)(w:600)](Step4_10.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **To Array** 노드를 끌어 놓고 **ForEachLoop** 노드를 검색 추가합니다. + + [REGION:lightbox] + [![](Step4_11.png)(w:600)](Step4_11.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **To Array** 노드를 **ForEachLoop** 노드에 연결합니다. + + [REGION:lightbox] + [![](Step4_12.png)(w:600)](Step4_12.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 합집합 결과를 **뷰포트** 에 출력할 준비가 되었습니다. **ForEachLoop** 노드의 **Array Element** 핀을 끌어 놓고 **Print String** 노드를 검색 추가합니다. + + [REGION:lightbox] + [![](Step4_13.png)(w:600)](Step4_13.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **ForEachLoop** 노드를 **Print String** 노드에 연결합니다. + + [REGION:lightbox] + [![](Step4_14.png)(w:600)](Step4_14.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 이미 디버그 메시지가 출력되는 것이 있으므로, **뷰포트** 에 출력되는 텍스트 색을 변경하는 것이 좋습니다. **Print String** 노드 하단의 메뉴 확장 화살표를 클릭합니다. + + [REGION:lightbox] + [![](Step4_15.png)(w:600)](Step4_15.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **Text Color** 박스를 클릭하여 **색 선택기** 메뉴를 엽니다. + + [REGION:lightbox] + [![](Step4_16.png)(w:600)](Step4_16.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 색을 다음 값으로 설정합니다: + + ![](Step4_17.png) + +1. **컴파일** 버튼을 클릭합니다. + + [REGION:lightbox] + [![](Step4_18.png)(w:600)](Step4_18.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 완성된 스크립트를 살펴본 후, **저장** 버튼을 누르고 에디터의 **뷰포트** 인터페이스로 돌아갑니다. + + [REGION:lightbox] + [![](Step4_19.png)(w:600)](Step4_19.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 에디터의 **뷰포트** 인터페이스에서 **플레이** 버튼을 클릭하여 업데이트한 스크립트가 작동되는 모습을 확인합니다. + + [REGION:lightbox] + [![](Step4_20.png)(w:600)](Step4_20.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +## 최종 결과 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 3PevHZoBX3E + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +위 비디오에서 보시듯이, First Person Character 가 **Display Set** 콜리전 박스와 충돌하면, **Union** 결과가 뷰포트에 출력됩니다. +여기서도 출력된 아이템을 살펴보면, 예측되는 순서로 나타나지 않는 것이 보이는데, 이는 블루프린트 세트의 속성입니다. +마지막으로 양쪽 블루프린트 세트의 합집합 연산을 종이에 해 보면, 다음과 같은 결과가 날 것입니다: + +| ------------------- | --------------------------- | -------------------------------------------- | +| **Instruction Set** | **Longer Instruction Set** | **Resultant Output (A ∪ B)** | +| `Click` | `your` | `Click` | +| `the` | `Gun` | `the` | +| `Left` | | `Left` | +| `Mouse` | | `Mouse` | +| `Button` | | `Button` | +| `and` | | `and` | +| `Fire` | | `Fire` | +| | | `your` | +| | | `Gun` | + +[nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/WorkingWithSets.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/WorkingWithSets.CHN.udn new file mode 100644 index 000000000000..27d88edfb963 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/WorkingWithSets.CHN.udn @@ -0,0 +1,56 @@ +INTSourceChangelist:0 +Availability:Docs +Title:Working with Sets +Description:Learn how to work with Sets in Blueprints. +Crumbs:%ROOT% +Parent:Engine/Blueprints/Scripting +Order:3 +Version: 4.15 +Tags:Blueprint Set +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithSets +Topic-image:workingWithSets_topicImage.png + +![](workingWithSets_topicBanner.png) +[REGION:caption] +At the end of this tutorial, you'll gain some experience working with Sets in Unreal Engine 4 (UE4). +[/REGION] + +More often than not, [](Engine/Blueprints/UserGuide/Arrays) are the container-of-choice for most design scenarios. Arrays, being an ordered list of items where duplicates +are allowed, offer developers a container that is both ordered and flexible. There are times though, when developers, working with pools of +items, aren't worried with the order of each item belonging to the pools, rather, they might be concerned with the uniqueness of the items +belonging to the pools that they're drawing data from. + +This is where a **Blueprint Set** might help. + +## Goal + +This guide teaches you how to set up and work with a Blueprint Set. + +## Objectives + +After working through this tutorial, you'll know the following: + +* How to create and edit Sets in the Blueprint scripting environment. +* How to query and display items being contained in a Blueprint Set. +* How to perform some basic operations on Blueprint Sets, including Intersections and Unions. + +[OBJECT:TopicList] + [PARAM:icon] + ![](%ROOT%/build_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + Steps + [/PARAM] + [PARAM:description] + [/PARAM] + [PARAM:links] + [DIR(output:"checkpoint" parent:"Engine/Blueprints/BP_HowTo/WorkingWithSets" org:"hierarchy")] + [/PARAM] +[/OBJECT] + +[REGION:call_to_action] + [Click to Start](Engine/Blueprints/BP_HowTo/WorkingWithSets/1 "%Engine/Blueprints/BP_HowTo/WorkingWithSets/1:title%") +[/REGION] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/WorkingWithSets.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/WorkingWithSets.INT.udn new file mode 100644 index 000000000000..a57ea40100fb --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/WorkingWithSets.INT.udn @@ -0,0 +1,56 @@ +Availability:Docs +Title:Working with Sets +Description:Learn how to work with Sets in Blueprints. +Crumbs:%ROOT% +Parent:Engine/Blueprints/Scripting +Order:3 +Version: 4.15 +Tags:Blueprint Set +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithSets +Topic-image:workingWithSets_topicImage.png +Related:Programming/UnrealArchitecture/TSet + +![](workingWithSets_topicBanner.png) +[REGION:caption] +At the end of this tutorial, you'll gain some experience working with Sets in Unreal Engine 4 (UE4). +[/REGION] + +More often than not, [](Engine/Blueprints/UserGuide/Arrays) are the container-of-choice for most design scenarios. Arrays, being an ordered list of items where duplicates +are allowed, offer developers a container that is both ordered and flexible. There are times though, when developers, working with pools of +items, aren't worried with the order of each item belonging to the pools, rather, they might be concerned with the uniqueness of the items +belonging to the pools that they're drawing data from. + +This is where a **Blueprint Set** might help. + +## Goal + +This guide teaches you how to set up and work with a Blueprint Set. + +## Objectives + +After working through this tutorial, you'll know the following: + +* How to create and edit Sets in the Blueprint scripting environment. +* How to query and display items being contained in a Blueprint Set. +* How to perform some basic operations on Blueprint Sets, including Intersections and Unions. + +[OBJECT:TopicList] + [PARAM:icon] + ![](%ROOT%/build_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + Steps + [/PARAM] + [PARAM:description] + [/PARAM] + [PARAM:links] + [DIR(output:"checkpoint" parent:"Engine/Blueprints/BP_HowTo/WorkingWithSets" org:"hierarchy")] + [/PARAM] +[/OBJECT] + +[REGION:call_to_action] + [Click to Start](Engine/Blueprints/BP_HowTo/WorkingWithSets/1 "%Engine/Blueprints/BP_HowTo/WorkingWithSets/1:title%") +[/REGION] diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/WorkingWithSets.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/WorkingWithSets.JPN.udn new file mode 100644 index 000000000000..86862fb66d6d --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/WorkingWithSets.JPN.udn @@ -0,0 +1,57 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:Set を使用して作業する +Description:ブループリントでの Set の使用方法 +Crumbs:%ROOT% +Parent:Engine/Blueprints/Scripting +Order:3 +Version:4.15 +Tags:Blueprint Set +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithSets +Topic-image:workingWithSets_topicImage.png +Related:Programming/UnrealArchitecture/TSet + +![](workingWithSets_topicBanner.png) +[REGION:caption] +このチュートリアルを通して、アンリアル エンジン 4 (UE4) で実際に Set を使った作業を経験できます。 +[/REGION] + +しばしば、[](Engine/Blueprints/UserGuide/Arrays) はほどんどのデザイン シナリオで選択されるコンテナです。Array は、複製可能なアイテムの順序付きリストです。 +デベロッパーにとって、整理されて分かりやすい、柔軟なコンテナです。しかしながら、アイテムをプールして作業するデベロッパーが気になることは、 +アイテムのプール内での個々の順序ではなく、 +データを書き出すプール中のアイテムのユニーク性です。 + +このような場合に **Blueprint Set** を使うと便利です。 + +## 目標 + +このガイドでは、Blueprint Set を使った設定および作業方法を説明します。 + +## 目的 + +このチュートリアルでは、以下の習得を目指します。 + +* ブループリント スクリプト処理環境での Set の作成および編集方法 +* Blueprint Set に含まれているアイテムのクエリおよび表示方法 +* Blueprint Set の基本的な操作方法 (Intersection と Union を含む) + +[OBJECT:TopicList] + [PARAM:icon] + ![](%ROOT%/build_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + ステップ + [/PARAM] + [PARAM:description] + [/PARAM] + [PARAM:links] + [DIR(output:"checkpoint" parent:"Engine/Blueprints/BP_HowTo/WorkingWithSets" org:"hierarchy")] + [/PARAM] +[/OBJECT] + +[REGION:call_to_action] + [クリックして開始](Engine/Blueprints/BP_HowTo/WorkingWithSets/1 "%Engine/Blueprints/BP_HowTo/WorkingWithSets/1:title%") +[/REGION] diff --git a/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/WorkingWithSets.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/WorkingWithSets.KOR.udn new file mode 100644 index 000000000000..dd6989175c56 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/BP_HowTo/WorkingWithSets/WorkingWithSets.KOR.udn @@ -0,0 +1,57 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:세트 작업 +Description:블루프린트에서 Set, 세트 작업 방법을 배워봅니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/Scripting +Order:3 +Version: 4.15 +Tags:Blueprint Set +Tags:Blueprints +Type:how-to +Skilllevel:Advanced +Checkpoint:HowToWorkWithSets +Topic-image:workingWithSets_topicImage.png +Related:Programming/UnrealArchitecture/TSet + +![](workingWithSets_topicBanner.png) +[REGION:caption] +이 튜토리얼을 통해 언리얼 엔진 4 (UE4) 의 Set (세트) 작업 경험을 쌓을 수 있습니다. +[/REGION] + +대개 [](Engine/Blueprints/UserGuide/Arrays) 은 대부분의 디자인 상황에 쓰이는 컨테이너입니다. +배열은 아이템이 순서대로 저장되며 중복 아이템도 허용되므로, 순서가 필요한 유연한 컨테이너 역할을 합니다. +하지만 어떤 아이템 풀을 대상으로 작업할 때, 풀에 속하는 각 아이템의 순서와는 상관 없이, +데이터를 뽑아 오는 풀에 그 아이템이 속하는지 고유성만 확인하면 될 때가 있습니다. + +그럴 때 **Blueprint Set** (블루프린트 세트)가 도움이 됩니다. + +## 목적 + +블루프린트 세트 구성 및 작업 방법을 안내해 드립니다. + +## 목표 + +이 튜토리얼에서 습득할 수 있는 지식은 다음과 같습니다: + +* 블루프린트 스크립팅 환경에서 세트 생성 및 편집 방법. +* 블루프린트 세트에 들어있는 아이템 질의 및 표시 방법. +* 블루프린트 세트에 대한 교집합 및 합집합과 같은 기본적인 연산 수행 방법. + +[OBJECT:TopicList] + [PARAM:icon] + ![](%ROOT%/build_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + 단계 + [/PARAM] + [PARAM:description] + [/PARAM] + [PARAM:links] + [DIR(output:"checkpoint" parent:"Engine/Blueprints/BP_HowTo/WorkingWithSets" org:"hierarchy")] + [/PARAM] +[/OBJECT] + +[REGION:call_to_action] + [클릭하면 시작합니다.](Engine/Blueprints/BP_HowTo/WorkingWithSets/1 "%Engine/Blueprints/BP_HowTo/WorkingWithSets/1:title%") +[/REGION] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/Blueprints.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/Blueprints.INT.udn index 92de7185456b..b20ce676e377 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/Blueprints.INT.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/Blueprints.INT.udn @@ -193,7 +193,7 @@ Blueprint-specific markup available in Unreal Engine's C++ implementation enable [/OBJECT] [/REGION] -[DIR(output:"listbutton" parent:"Engine/Blueprints" type:"overview" org:"hierarchy")] +[DIR(output:"topic" parent:"Engine/Blueprints" type:"overview" org:"hierarchy")] diff --git a/Engine/Documentation/Source/Engine/Blueprints/HowTo/BPHT_7/BPHT_7.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/HowTo/BPHT_7/BPHT_7.JPN.udn index a6a9b2917f4d..e62290c1e5a8 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/HowTo/BPHT_7/BPHT_7.JPN.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/HowTo/BPHT_7/BPHT_7.JPN.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:2686221 +INTSourceChangelist:3244370 Availability:Public Title:7.応用編 Crumbs: %ROOT%, Engine, Engine/Blueprints, Engine/Blueprints/HowTo Description:最後のステップでは、このプロジェクトの次のレベルへ進めるためのサンプル、および追加ドキュメントへのリンクを紹介します。 -Version:4.9 +version:4.9 +tags:Blueprints [VAR:Steps] @@ -42,7 +43,7 @@ yut5Feu1KxI * レベルに、スポーン ポイントをあと 2 つ追加する (角、またはプレイヤーの左右)。 * HUD に、プレイヤーが一発目でヒットした数を追跡するためのカテゴリを追加する。 -本ガイドおよびエディタ全般に渡り取り扱ったトピックスに関しては、 [アンリアル エディタのマニュアル](Engine) をご覧ください。 +本ガイドおよびエディタ全般に渡り取り扱ったトピックスに関しては、アンリアル エディタのマニュアル](Engine) をご覧ください。 このガイドのトピックに関連した情報は以下の通りです。 @@ -54,7 +55,7 @@ yut5Feu1KxI * キャスト に関する詳細は、[キャスト](Engine/Blueprints/UserGuide/CastNodes) をご覧ください。 -* Unreal Motion Graphics (UMG) での HUD エレメントの作成については、[アンリアル モーション グラフィック (UMG)](Engine/UMG) をご覧ください。 +* Unreal Motion Graphics (UMG) での HUD エレメントの作成については、[UMG UI デザイナ](Engine/UMG) をご覧ください。 %Steps% diff --git a/Engine/Documentation/Source/Engine/Blueprints/HowTo/BlueprintHowTo.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/HowTo/BlueprintHowTo.JPN.udn index f54d339d2d0e..d1a5210bf7be 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/HowTo/BlueprintHowTo.JPN.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/HowTo/BlueprintHowTo.JPN.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:2735872 +INTSourceChangelist:3244370 Availability:Public Title:ブループリント通信プロジェクト Crumbs: %ROOT%, Engine, Engine/Blueprints Description:様々なブループリント通信方法を使って作成されたサンプル プロジェクト version:4.9 +tags:Blueprints [VAR:Topic] [OBJECT:Topic] @@ -44,7 +45,7 @@ version:4.9 [/OBJECT] [/VAR] -**ブループリント通信プロジェクト** では、シンプルな射撃スタイルのゲームを作成します。プロジェクトではレベルからキャラクターへの通信方法に加えて、キャラクター情報の HUD への渡し方を学びます。プロジェクトの終了時には、以下のようなものが出来上がります。 +この **ブループリント通信プロジェクト** では、シンプルな射撃スタイルのゲームを作成します。プロジェクトではレベルからキャラクターへの通信方法に加えて、キャラクター情報の HUD への渡し方を学びます。プロジェクトの終了時には、以下のようなものが出来上がります。 [OBJECT:EmbeddedVideo] [PARAMLITERAL:width] diff --git a/Engine/Documentation/Source/Engine/Blueprints/Overview/BlueprintOverview.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/Overview/BlueprintOverview.JPN.udn index 12aa708ece83..a0ea715f5549 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/Overview/BlueprintOverview.JPN.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/Overview/BlueprintOverview.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3041817 +INTSourceChangelist:3244370 Availability:Public Title:ブループリントの概要 Crumbs: %ROOT%, Engine, Engine/Blueprints @@ -6,6 +6,7 @@ Description:ブループリントの概要のページは、ブループリン version:4.9 parent:Engine/Blueprints order:2 +tags:Blueprints [VAR:Topic] @@ -53,15 +54,15 @@ order:2 [INCLUDE:Engine/Blueprints/GettingStarted/#Intro] つまり、ブループリントがアンリアル スクリプトに取って替わるということでしょうか?どちらとも言えません。 -昔はアンリアル スクリプトを使用したゲームプレイ プログラミングやその他すべてのゲームプレイ要素は、今もまだ C++ 言語で処理することができます。同時に、ブループリントはアンリアル・スクリプトの代替ではないものの、 +過去にアンリアル スクリプトを使用したゲームプレイ プログラミングやその他すべてのゲームプレイ要素は、今でも C++ 言語で処理することができます。同時に、ブループリントはアンリアル・スクリプトの代替ではないものの、 アンリアル スクリプトで処理していた以下の目的のほとんどを達成することができます。 * クラスの拡張 * デフォルト プロパティの格納および修正 * クラスのサブ オブジェクト (例えばコンポーネント) のインスタンス化の管理 -ブループリントを作成する便利な関数やプロパティ一式をエクスポーズするベースクラスをゲームプレイ プログラマーが設定できるようになることが期待されます。 -これらのベースクラスは使用はもちろん、その後拡張することもできます。 +ゲームプレイ プログラマーは、自分達が設定したベースクラスで作成したブループリントで使用および拡張できる便利な関数とプロパティを +公開できるようになることが期待されます。 [EXCERPT:GameplayEquivalents] 下表は、ネイティブコードと _ブループリント_ の比較だけでなく、エンジンの前のバージョンからの推移しやすいように、 @@ -118,7 +119,7 @@ _ブループリント_ にエクスポーズされた全ての機能を実行 ## ブループリントの仕組み ブループリントの機能はさまざまな要素で定義します。その中にはデフォルトで存在する機能もあれば、 -必要に応じて追加する機能もあります。これらの機能により、コンポーネントの定義、初期化の実行、 +必要な時に追加できる機能もあります。これらの機能により、コンポーネントの定義、初期化の実行、 設定操作、イベントへの対応、操作の構造化およびモジュール化、 プロパティの定義などが可能になります。 @@ -139,7 +140,7 @@ _ブループリント_ にエクスポーズされた全ての機能を実行 [INCLUDE:Engine/Blueprints/UserGuide/Functions#Intro] -###変数 +### 変数 [INCLUDE:Engine/Blueprints/UserGuide/Variables#Intro] @@ -148,11 +149,11 @@ _ブループリント_ にエクスポーズされた全ての機能を実行 diff --git a/Engine/Documentation/Source/Engine/Blueprints/QuickStart/1/BPQS_1.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/QuickStart/1/BPQS_1.JPN.udn index c6808db98faf..cae40dea6b73 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/QuickStart/1/BPQS_1.JPN.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/QuickStart/1/BPQS_1.JPN.udn @@ -1,12 +1,13 @@ -INTSourceChangelist:2914104 +INTSourceChangelist:3244370 Availability:Public -Title:1.必要なプロジェクト設定 +Title:1.必要なプロジェクトを設定する Crumbs:%ROOT%, Engine, Engine/Blueprints, Engine/Blueprints/QuickStart Description:ゲームプロジェクトの開始に Side Scroller Blueprint テンプレートを使用する version:4.9 parent:Engine/Blueprints/QuickStart order:1 type:multi-step +tags:Blueprints [NAV] @@ -17,16 +18,16 @@ type:multi-step 1. **[New Project (新規プロジェクト)]** ウィザードの **[Blueprint]** タブから **Side Scroller** テンプレートを選択します。 -1. スケーラビリティと品質設定は自分の設定に一番合うものにして構いませんが、**スターター コンテンツ** は必ず入れるようにしてください。 +1. スケーラビリティと品質は一番合うものに設定できますが、**スターター コンテンツ** だけは必ず入れるようにしてください。 [REGION:note] - どの設定が良いのか分からない場合は、[プロジェクト設定](Engine/Basics/Projects/Browser#プロジェクト設定) セクションをご覧ください。 + どの設定にすれば良いか分からない場合は、[プロジェクト設定](Engine/Basics/Projects/Browser#プロジェクト設定) セクションをご覧ください。 [/REGION] 1. プロジェクトに名前を付けて、**[Create Project (プロジェクトを作成)]** ボタンをクリックして作成します。 -プロジェクトを開始できるサイドスクローラーレベルが表示されるはずです。 +プロジェクトを開始するサイドスクローラーレベルが表示されます。 ![](Step1End.png) diff --git a/Engine/Documentation/Source/Engine/Blueprints/QuickStart/6/BPQS_6.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/QuickStart/6/BPQS_6.JPN.udn index fd9f4bafaf8f..0b1fb405cf6f 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/QuickStart/6/BPQS_6.JPN.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/QuickStart/6/BPQS_6.JPN.udn @@ -1,22 +1,23 @@ -INTSourceChangelist:2735872 +INTSourceChangelist:3244370 Availability:Public -Title:6.キャラクターの起動 -Crumbs:%ROOT%, Engine, Engine/Blueprints, Engine/Blueprints/QuickStart +Title:6. キャラクターを起動する +Crumbs: %ROOT%, Engine, Engine/Blueprints Description:Launch Character ノードで実際に起動するビヘイビアを設定する version:4.9 parent:Engine/Blueprints/QuickStart order:6 type:multi-step +tags:Blueprints [VAR:Steps] [OBJECT:Navigation] [PARAM:previous] - [右の手順](Engine/Blueprints/QuickStart/5 "%Engine/Blueprints/QuickStart/5:title%") + [前の手順](Engine/Blueprints/QuickStart/5 "%Engine/Blueprints/QuickStart/5:title%") [/PARAM] [PARAM:current] [/PARAM] [PARAM:home] - [クイックスタートのホーム画面](Engine/Blueprints/QuickStart) + Engine/Blueprints/QuickStart [/PARAM] [PARAM:next] [次の手順](Engine/Blueprints/QuickStart/7 "%Engine/Blueprints/QuickStart/7:title%") @@ -29,26 +30,26 @@ type:multi-step --- アンリアルのジャンプ台 (Launchpad) は **Launch Character** という関数を使用すると機能します。**Launch Character** 関数は、キャラクターの現在のベロシティに指定したベロシティを追加して、 -キャラクターを好きな方向へ飛ばすことができるようになります。この設定はキャラクターのみに機能します。ポーン (アバター) が必ずキャラクター (人間そっくりのアバター) になるように設定してください。 +キャラクターを好きな方向へ飛ばせるようにします。この設定はキャラクターのみ有効です。必ずポーン (アバター) をキャラクター (人間そっくりのアバター) になるように設定してください。 -設定はキャストで行います。キャスティングはユーザー入力を別タイプの入力に変換します。これにより特定タイプのみに有効な特殊な機能へアクセスができるようになります。入力タイプがこの特定タイプに基づいている場合は -成功します。 +設定はキャストで行います。キャスティングはユーザー入力を別タイプの入力に変換します。これにより特定タイプのみに有効な特殊機能へのアクセスが可能になります。入力タイプがこの特定タイプに基づいていれば +正常にキャストされます。 -後に追加できるその他の特別なビヘイビアに加えて、レベルに配置できるのはアクタだけです。つまりレベル内にあるすべてのものに対してリファレンスを取得して、これを **アクタ** にキャストすることができます。 -結果は成功します。ただし、すべてのポーンがゲーム内でキャラクターを表現するわけではないので、何かを **ポーン** にキャストしても成功しない場合もあります。 +後から追加が可能な特殊ビヘイビアも含めて、レベルに配置できるものはすべてアクタです。つまり、レベル内にあるすべてのものに対してリファレンスを取得して、 +これを **アクタ** にキャストすることができます。ただし、ポーンは必ずしもゲーム内でキャラクターを表現するわけではないので、**ポーン** にキャストできない場合もあります。 1. **Get Player Pawn** の **Return Value** ピンを引き出します。 -1. 検索ボックスに「Cast」と入力して、コンテキストメニューから **[Cast to Character (キャラクターにキャスト)]** を選択します。 +1. 検索ボックスに「Cast」と入力して、コンテキスト メニューから **[Cast to Character (キャラクターにキャスト)]** を選択します。 ![](CasttoCharacterMenu.png) 1. **Cast** ノードの **As Character** ピンを引き出します。 -1. 検索ボックスに「Launch」と入力して、コンテキストメニューから **[Launch Character (キャラクターを起動)]** を選択します。 +1. 検索ボックスに「Launch」と入力して、コンテキスト メニューから **[Launch Character (キャラクターを起動)]** を選択します。 ![](LaunchWired.png) [REGION:note] - キャストを成功させるための出力実行ピンが **Launch Character** の入力実行ピンと自動的に接続することに注目してください。 + 正常にキャストするための出力実行ピンが **Launch Character** の入力実行ピンと自動接続することに注目してください。 [/REGION] 1. **Launch Character** ノードの Z フィールドに「3000」と入力します。 @@ -58,7 +59,7 @@ type:multi-step ここでツールバーのボタンで **コンパイル** と **保存** を行って、ブループリント エディタを閉じます。 -1. **コンテンツブラウザ** からいくつかのジャンプ台をレベルへドラッグします。 +1. **コンテンツ ブラウザ** からジャンプ台をいくつかレベルへドラッグします。 ![](MultipleLaunchpads.png) diff --git a/Engine/Documentation/Source/Engine/Blueprints/Scripting/Scripting.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/Scripting/Scripting.INT.udn index e509581f4acd..5a9a9e456de9 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/Scripting/Scripting.INT.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/Scripting/Scripting.INT.udn @@ -74,6 +74,20 @@ Arrays and structures are collections of multiple data types. They are available [DIR(output:"listbutton" parent:"Engine/Blueprints/Scripting" tags:"Arrays and Structures")] diff --git a/Engine/Documentation/Source/Engine/Blueprints/Scripting/Scripting.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/Scripting/Scripting.JPN.udn index e06a6c23e11c..7fb21571866e 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/Scripting/Scripting.JPN.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/Scripting/Scripting.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3244370 +INTSourceChangelist:3393423 Availability:Public Title:スクリプト処理の基礎 Crumbs: %ROOT%, Engine, Engine/Blueprints @@ -46,9 +46,9 @@ tags:Blueprints [/OBJECT] [/VAR] -ブループリントは、スクリプト処理言語をビジュアル化して表示します。そうすると、通常スクリプト処理言語を書く場合に伴う、データ タイプ変数、配列、構造体など数々のニュアンスが共有できます。 -ブループリントでは各ノードは明確な線形実行が必要であるにもかかわらず、実行フローは典型的なスクリプト処理言語のように機能します。以下のページでは、様々な変数タイプ、それらの使い方、グラフ内のノードの実行に関して -詳しく説明しています。 +ブループリントは、スクリプト処理言語を可視化して表示します。可視化することで、データ タイプ変数、配列、構造体など標準的なスクリプト処理言語のニュアンスを幅広く共有することができます。 +ブループリントは、各ノードを明確に線形実行しなければなりませんが、実行フローは典型的なスクリプト処理言語のように機能します。それでは、様々な変数タイプ、それらの使い方、グラフ内のノードの実行に関して +詳しく説明していきます。 ## 変数 @@ -75,6 +75,20 @@ tags:Blueprints [DIR(output:"listbutton" parent:"Engine/Blueprints/Scripting" tags:"Arrays and Structures")] diff --git a/Engine/Documentation/Source/Engine/Blueprints/Scripting/Scripting.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/Scripting/Scripting.KOR.udn index bef32453a6e2..6a3e8dd2eea4 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/Scripting/Scripting.KOR.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/Scripting/Scripting.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3244370 +INTSourceChangelist:3393423 Availability:Public Title: 기본 스크립팅 Crumbs: %ROOT%, Engine, Engine/Blueprints @@ -75,6 +75,20 @@ tags:Blueprints [DIR(output:"listbutton" parent:"Engine/Blueprints/Scripting" tags:"Arrays and Structures")] diff --git a/Engine/Documentation/Source/Engine/Blueprints/TechnicalGuide/NativizingBlueprints/Advanced/AdvancedNativeBlueprints.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/TechnicalGuide/NativizingBlueprints/Advanced/AdvancedNativeBlueprints.INT.udn index 376cad36ce19..aa303f389964 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/TechnicalGuide/NativizingBlueprints/Advanced/AdvancedNativeBlueprints.INT.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/TechnicalGuide/NativizingBlueprints/Advanced/AdvancedNativeBlueprints.INT.udn @@ -1,10 +1,10 @@ Availability:Public Title:Advanced Blueprint Nativization -Crumbs: +Crumbs:%ROOT% Description:Technical guide for programmers exposing gameplay elements to Blueprints. Related: Engine/Blueprints/TechnicalGuide/NativizingBlueprints Parent: Engine/Blueprints/TechnicalGuide -Version:4.15 +Version:4.16 type:reference tags:Blueprints SkillLevel:Advanced @@ -40,8 +40,7 @@ the following implementations aren't supported: ## Technical Details -Nativizing Blueprints should work with Visual Studio 2013 and Visual Studio 2015; however, Visual Studio 2015 is strongly recommended because it was developed -to handle large projects. If you encounter a compiler or linker error (such as LNK1000 or LNK1248), try reducing the amount of nativized Blueprints from your project, +If you encounter a compiler or linker error (such as LNK1000 or LNK1248), try reducing the amount of nativized Blueprints from your project, by excluding Blueprint types, or specific Blueprints, in the `DefaultEngine.ini` configuration settings file. For more information about excluding Blueprints from nativization, refer to our [](Engine/Blueprints/TechnicalGuide/NativizingBlueprints) documentation. diff --git a/Engine/Documentation/Source/Engine/Blueprints/TechnicalGuide/NativizingBlueprints/Advanced/AdvancedNativeBlueprints.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/TechnicalGuide/NativizingBlueprints/Advanced/AdvancedNativeBlueprints.JPN.udn index 7a6c4a703c77..74bff89ef697 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/TechnicalGuide/NativizingBlueprints/Advanced/AdvancedNativeBlueprints.JPN.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/TechnicalGuide/NativizingBlueprints/Advanced/AdvancedNativeBlueprints.JPN.udn @@ -1,11 +1,11 @@ -INTSourceChangelist:3336767 +INTSourceChangelist:3426963 Availability:Public Title:高度なブループリントのネイティブ化 -Crumbs: +Crumbs:%ROOT% Description:ゲームプレイ要素をブループリントに公開するテクニカル ガイド (ゲームプレイ プログラマー向け) Related:Engine/Blueprints/TechnicalGuide/NativizingBlueprints Parent:Engine/Blueprints/TechnicalGuide -Version:4.15 +Version:4.16 type:reference tags:Blueprints SkillLevel:Advanced @@ -41,8 +41,7 @@ Unreal Automation ツールでのビルド中にコマンドラインからブ ## 技術的な詳細 -ブループリントのネイティブ化は Visual Studio 2013 と Visual Studio 2015 で使用できますが、 -大規模プロジェクトに対応可能な 2015 を推奨します。コンパイル エラーまたはリンク エラー (LNK1000 や LNK1248) になった場合、ブループリント タイプまたは特定のブループリントを `DefaultEngine.ini` 設定ファイルから排除して、 +コンパイル エラーまたはリンク エラー (LNK1000 や LNK1248) になった場合、ブループリント タイプまたは特定のブループリントを `DefaultEngine.ini` 設定ファイルから排除して、 プロジェクトでネイティブ化したブループリント数を減らしてみてください。ブループリントを変換対象から除外する方法は、 [](Engine/Blueprints/TechnicalGuide/NativizingBlueprints) を参照してください。 diff --git a/Engine/Documentation/Source/Engine/Blueprints/TechnicalGuide/NativizingBlueprints/Advanced/AdvancedNativeBlueprints.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/TechnicalGuide/NativizingBlueprints/Advanced/AdvancedNativeBlueprints.KOR.udn index 8043cfe7d46d..ab257a1d2d82 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/TechnicalGuide/NativizingBlueprints/Advanced/AdvancedNativeBlueprints.KOR.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/TechnicalGuide/NativizingBlueprints/Advanced/AdvancedNativeBlueprints.KOR.udn @@ -1,11 +1,11 @@ -INTSourceChangelist:3336767 +INTSourceChangelist:3426963 Availability:Public Title:블루프린트 네이티브화 고급 -Crumbs: +Crumbs:%ROOT% Description:블루프린트에 게임플레이 요소를 노출시키는 게임플레이 프로그래머를 위한 기술 안내서입니다. Related: Engine/Blueprints/TechnicalGuide/NativizingBlueprints Parent: Engine/Blueprints/TechnicalGuide -Version:4.15 +Version:4.16 type:reference tags:Blueprints SkillLevel:Advanced @@ -41,7 +41,6 @@ prereq:Engine/Blueprints/TechnicalGuide/NativizingBlueprints ## 기술적 세부사항 -블루프린트 네이티브화는 Visual Studio 2013 에서도 Visual Studio 2015 에서도 작동은 하지만, 큰 규모의 프로젝트 처리를 위해 개발된 Visual Studio 2015 를 추천합니다. 컴파일러 또는 링커 (LNK1000 또는 LNK1248 같은) 오류가 발생하면, `DefaultEngine.ini` 환경설정 파일에서 블루프린트 유형 또는 특정 블루프린트들을 제외시켜 프로젝트에서 네이티브화되는 블루프린트 양을 줄여 보시기 바랍니다. 블루프린트를 네이티브화 대상에서 제외시키는 방법 관련 상세 정보는 [](Engine/Blueprints/TechnicalGuide/NativizingBlueprints) 문서를 참고하세요. diff --git a/Engine/Documentation/Source/Engine/Blueprints/TechnicalGuide/NativizingBlueprints/NativizingBlueprints.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/TechnicalGuide/NativizingBlueprints/NativizingBlueprints.INT.udn index d4673497e216..149827925ab3 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/TechnicalGuide/NativizingBlueprints/NativizingBlueprints.INT.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/TechnicalGuide/NativizingBlueprints/NativizingBlueprints.INT.udn @@ -9,13 +9,14 @@ tags:Blueprints Skilllevel:Intermediate Related: Engine/Blueprints/TechnicalGuide/NativizingBlueprints/Advanced social-image:social_bp_nativization.png +topic-image:NativizingBlueprints_topic.png [TOC(start:1 end:4)] -When teams script gameplay with Blueprints, they're creating new UClasses without having to write or compile native C++ (CPP) code. As a result, Blueprints work well for game teams -that don't have the technical expertise of native CPP programmers. The reason that non-programmers can work strictly with Blueprints, is because Blueprint nodes run in -a virtual machine (VM), enabling them to call native CPP functions. Unfortunately, relying on a VM that translates Blueprints into native CPP code comes at a cost; and as you can imagine, -translating Blueprint nodes into native CPP functions can potentially slow your game's performance per frame. +When teams script gameplay with Blueprints, they're creating new UClasses without having to write or compile native C++ code. As a result, Blueprints work well for game teams +that don't have the technical expertise of native C++ programmers. The reason that non-programmers can work strictly with Blueprints, is because Blueprint nodes run in +a virtual machine (VM), enabling them to call native C++ functions. Unfortunately, relying on a VM that translates Blueprints into native C++ code comes at a cost; and as you can imagine, +translating Blueprint nodes into native C++ functions can potentially slow your game's performance per frame. When the cost of running Blueprints in a VM isn't noticeable, the VM overhead can be an acceptable cost to bear; however, there are times when you'll want your game to run as fast as possible (especially, when you're shipping to devices that have limited hardware capabilities). This is where Unreal Engine's Blueprint Nativization tool can help. @@ -26,9 +27,9 @@ Here at Epic, we've successfully used Blueprint Nativization while developing ou ##Reducing VM Overhead -The main goal of Blueprint Nativization is to reduce VM overhead in the runtime version of your project by generating native CPP code from your project's Blueprints. In general, all -of the Blueprint Classes are replaced by the newly generated native CPP classes that will then be compiled with the project during the [cooking process](Engine/Deployment/Cooking). -Although you'll be able to read the translated CPP code from a text editor, you'll notice that the code isn't formatted to be reusable (or generated to be "reader friendly"). +The main goal of Blueprint Nativization is to reduce VM overhead in the runtime version of your project by generating native C++ code from your project's Blueprints. In general, all +of the Blueprint Classes are replaced by the newly generated native C++ classes that will then be compiled with the project during the [cooking process](Engine/Deployment/Cooking). +Although you'll be able to read the translated C++ code from a text editor, you'll notice that the code isn't formatted to be reusable (or generated to be "reader friendly"). [OBJECT:ComparisonSlider] [PARAM:before] @@ -84,12 +85,12 @@ Unreal Automation Tool (UAT) will nativize the following supported Blueprint ass * User Defined Enums [REGION:note] -At this time, Level Blueprints and Blueprint Macros aren't supported by the Blueprint Nativization tool, and won't be converted into native CPP code. +At this time, Level Blueprints and Blueprint Macros aren't supported by the Blueprint Nativization tool, and won't be converted into native C++ code. [/REGION] ###Excluding Blueprints from Conversion -When the Blueprint Nativization tool converts Blueprint nodes to native CPP code, the resulting executable is compiled with additional machine instructions, +When the Blueprint Nativization tool converts Blueprint nodes to native C++ code, the resulting executable is compiled with additional machine instructions, dependencies, and embedded metadata to support the conversion. [REGION:warning] diff --git a/Engine/Documentation/Source/Engine/Blueprints/TechnicalGuide/NativizingBlueprints/NativizingBlueprints.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/TechnicalGuide/NativizingBlueprints/NativizingBlueprints.JPN.udn index 976bce3322d0..8d76c3397dd8 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/TechnicalGuide/NativizingBlueprints/NativizingBlueprints.JPN.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/TechnicalGuide/NativizingBlueprints/NativizingBlueprints.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3324139 +INTSourceChangelist:3467293 Availability:Public Title:ブループリントのネイティブ化 Crumbs: @@ -10,26 +10,27 @@ tags:Blueprints Skilllevel:Intermediate Related:Engine/Blueprints/TechnicalGuide/NativizingBlueprints/Advanced social-image:social_bp_nativization.png +topic-image:NativizingBlueprints_topic.png [TOC(start:1 end:4)] -ブループリントでゲームプレイをスクリプト化する時、ネイティブ C++ (CPP) コードを書いたりコンパイルをせずにチームは UClasses を新規作成できます。ネイティブ CPP プログラマーの専門知識がなくても使えるので、 -ブループリントはチームで重宝されています。プログラマー以外の人がブループリントがうまく使いこなせる理由は、 -ブループリントが仮想マシン (VM) で、ネイティブ CPP 関数の呼び出しが可能だからです。残念なことに、VM はブループリントをネイティブ CPP コードに変換するため、使用すると負荷がかかります。 -そうすると、想像できると思いますが、Blueprint ノードからネイティブ CPP 関数への変換はフレームあたりのゲーム パフォーマンスを落としてしまう可能性があります。 +ゲームプレイのスクリプトを作成する場合、ブループリントを使えばネイティブ C++ コードの書き出しやコンパイルをせずに UClasses を作成することが可能です。つまり、ネイティブ CPP プログラマーのような専門知識がなくても使えるので、 +ブループリントはゲーム開発を行うチームに最適です。ブループリントは仮想マシン (VM) であり、ネイティブ CPP 関数の呼び出しが可能なため、 +プログラマー以外の人でも問題なく使いこなせることができるのです。ただ残念なことに、ブループリントをネイティブ C++ コードに変換する VM に依存するため負荷がかかります。 +従って、Blueprint ノードからネイティブ C++ 関数への変換はフレームあたりのゲーム パフォーマンスに影響が出ることはご想像の通りです。 -ブループリントの実行負荷が VM では気にならない程度であれば VM オーバーヘッドは許容範囲ですが、 -ゲームの実行速度をできるだけ速くしたいは (特にハードウェア性能に制限があるデバイスを出荷する時)、アンリアル エンジンの Blueprint Nativization ツールが役に立ちます。 +ブループリントの実行負荷が VM で気にならない程度であれば VM オーバーヘッドは許容範囲となりますが、 +ゲームの実行速度をできるだけ速くするためには (特にハードウェア性能に制限があるデバイスを出荷する時)、アンリアル エンジンの Blueprint Nativization ツールが役に立ちます。 [REGION:note] -エピックでは、新しい VR タイトル [Robo Recall](https://www.epicgames.com/roborecall/en-US/home) の開発においてこの Blueprint Nativization ツールが大活躍しました。 +この Blueprint Nativization ツールは、エピックの新しい VR タイトル [Robo Recall](https://www.epicgames.com/roborecall/en-US/home) の開発において大活躍しました。 [/REGION] -##VM オーバーヘッドの削減 +##VM オーバーヘッドを削減する -Blueprint Nativization の主な目的は、プロジェクトのブループリントからネイティブ CPP コードを生成して、プロジェクトのランタイムでの VM オーバーヘッドを削減することです。一般的に、 -Blueprint クラスはすべて、新しく生成された CPP クラスに置き換えられ、[クック処理](Engine/Deployment/Cooking) 中にプロジェクトにコンパイルされます。 -テキスト エディタから変換した CPP コードは読み取り可能ですが、コードのフォーマットは再利用目的はフォーマット化されていません (または「読みやすい」ようには作成されていません)。 +Blueprint Nativization の主な目的は、プロジェクトのブループリントからネイティブ C++ コードを生成して、プロジェクトのランタイムでの VM オーバーヘッドを削減することです。一般的に、 +Blueprint クラスはすべて、新しく生成された C++ クラスに置き換えられ、[クック処理](Engine/Deployment/Cooking) 中にプロジェクトにコンパイルされます。 +テキスト エディタから変換した C++ コードは読み取り可能ですが、コードは再利用可能なように (または「読みやすい」ように) はフォーマット化されていません。 [OBJECT:ComparisonSlider] [PARAM:before] @@ -42,10 +43,10 @@ Blueprint クラスはすべて、新しく生成された CPP クラスに置 _Player Character プループリントとネイティブ化されたコードの比較です。_ -このページで、プロジェクトのブループリントのネイティブ化を始めましょう。ブループリント専用プロジェクトであれば理解しやすいです。まず始めに、 +このページで、プロジェクトのブループリントのネイティブ化を行います。ブループリントのみプロジェクトであれば理解しやすいタスクです。まず始めに、 Blueprint Nativization の有効無効を切り替えるユーザー インターフェース (UI) を探しましょう。 -##Blueprint Nativization を無効にする +## ブループリントのネイティブ化を有効にする プロジェクトを初めて作成する時、Blueprint Nativization はデフォルトで無効になっています。Blueprint Nativization 設定は、 アンリアル エディタの **[Project Settings (プロジェクト設定)]** メニューの左欄で**[Packaging]** を選択し、**[Project - Packaging]** メニューの **[Blueprints]** ドロップダウン メニューの中にあります。 @@ -74,7 +75,7 @@ Blueprint Nativization の有効無効を切り替えるユーザー インタ ![](BPNativization_InclusiveUI.png)(w:900) **[Inclusive]** ネイティブ化メソッドが選択されると、 -アンリアル エンジン ツール (UAT) は[パッケージ化プロセス](Engine/Basics/Projects/Packaging) 中にサポート対象の以下の Blueprint アセットをネイティブ化します。これは重要なことです。 +アンリアル エンジン ツール (UAT) は[パッケージ化プロセス](Engine/Basics/Projects/Packaging) 中にサポート対象の以下の Blueprint アセットをネイティブ化することに注目してください。 * Blueprint クラス * ブループリント関数ライブラリ @@ -85,12 +86,12 @@ Blueprint Nativization の有効無効を切り替えるユーザー インタ * ユーザー定義の Enum [REGION:note] -この時、Level ブループリントと Bluepint マクロは Blueprint Nativization ツールのサポート対象外なので、ネイティブ CPP コードには変換されません。 +この時、Level ブループリントと Bluepint マクロは Blueprint Nativization ツールのサポート対象外なので、ネイティブ C++ コードには変換されません。 [/REGION] ### ブループリントを変換対象から除外する -Blueprint Nativization ツールが Blueprint ノードをネイティブ CPP コードに変換すると、 +Blueprint Nativization ツールが Blueprint ノードをネイティブ C++ コードに変換すると、 出来上がった実行ファイルには、変換をサポートするための端末命令、依存、埋め込みメタデータが追加されます。 [REGION:warning] @@ -108,7 +109,7 @@ Blueprint Nativization ツールが Blueprint ノードをネイティブ CPP ![](DefaultEngineINI.png)(w:900) -Blueprint アセットはパッケージ化の処理中にネイティブ化されることに注意してください。これはとても重要です。従って、クック処理する Blueprint アセットあるいはマップを何も指定しないと、 +Blueprint アセットは、パッケージ化プロセスの一部としてクックされる場合のみネイティブ化されることに注意してくだださい。従って、クック処理する Blueprint アセットあるいはマップを何も指定しないと、 アンリアル エンジンは **Content** ディレクトリの中にあるすべてのものをクックします。**Inclusive** メソッドを選択して、使っていない Blueprint がネイティブ化されていたら、 **[Exclusive]** Blueprint Nativization Method を選択した方がよいかもしれません。 @@ -131,10 +132,10 @@ Blueprint アセットはパッケージ化の処理中にネイティブ化さ * ループの最適化が必要なブループリント * 複雑な演算処理を実行するブループリント -###ネイティブ化するブループリントの選択 +###ネイティブ化するブループリントを選択する [REGION:note] -Blueprint アセットを含むプロジェクトを作っていない場合、いずれかのプロジェクト テンプレートを使用して新規作成してください。ここでは図説に便利な +Blueprint アセットを含むプロジェクトを作っていない場合、いずれかのプロジェクト テンプレートを使用して新規作成してください。ここでは説明しやすいように **Puzzle** Project テンプレートを使用しています。 [/REGION] @@ -188,7 +189,6 @@ Blueprint アセットを含むプロジェクトを作っていない場合、 [REGION:caption] クリックしてフルサイズで表示 - [/REGION] この配列には、ネイティブ化を明示的に選択できる Blueprint アセットのリストが入ります。 @@ -254,7 +254,11 @@ Blueprint アセットを含むプロジェクトを作っていない場合、 クリックしてフルサイズで表示 [/REGION] -これで **Exclusive** Blueprint Nativization Method を使ったプロジェクトのクックとパッケージ化処理の準備ができました。 +これで **Exclusive** Blueprint Nativization Method を使ったプロジェクトのクックとパッケージ化処理の準備ができました。 + +[REGION:note] +ネイティブ化するブループリントをビルドするために必要なすべてのサポート対象の依存性もネイティブのためにフラグ付けされることに注目してください。 +[/REGION] ##ネイティブ コードの場所 @@ -274,6 +278,6 @@ Blueprint アセットを含むプロジェクトを作っていない場合、 クリックしてフルサイズで表示 [/REGION] -このフラグは、コマンド ラインからプロジェクトをビルド / クックできる上級ユーザー向けです (サーバー側のビルド エンジニアなど)。**[Project Settings]** メニューでネイティブ化が有効になっている時にこのフラグも有効にすると、 -コマンドラインからネイティブ化フラグを使用してビルド / クックを行わないと基本的には警告が出されます。コマンドラインからネイティブ化スイッチを使う方法は、 +このフラグは、コマンド ラインからプロジェクトをビルド / クックできる上級ユーザー向けです (サーバー側のビルド エンジニアなど)。**[Project Settings]** メニューでネイティブ化を有効にしている間にこのフラグを有効にすると、 +コマンドラインからネイティブ化フラグを使用せずにビルド / クックを実行した時に通常は警告が出されます。コマンドラインからネイティブ化スイッチを使用する方法については、 [](Engine/Blueprints/TechnicalGuide/NativizingBlueprints/Advanced) を参照してください。 \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/TechnicalGuide/NativizingBlueprints/NativizingBlueprints.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/TechnicalGuide/NativizingBlueprints/NativizingBlueprints.KOR.udn index 00ab42403255..420184529a11 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/TechnicalGuide/NativizingBlueprints/NativizingBlueprints.KOR.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/TechnicalGuide/NativizingBlueprints/NativizingBlueprints.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3336767 +INTSourceChangelist:3467293 Availability:Public Title:블루프린트 네이티브화 Crumbs: @@ -10,26 +10,27 @@ tags:Blueprints Skilllevel:Intermediate Related: Engine/Blueprints/TechnicalGuide/NativizingBlueprints/Advanced social-image:social_bp_nativization.png +topic-image:NativizingBlueprints_topic.png [TOC(start:1 end:4)] -팀이 블루프린트로 게임플레이 스크립트를 짜면, 네이티브 C++ (CPP) 코드 작성이나 컴파일할 필요 없이 UClass 를 새로 만들어 줍니다. 그 결과 블루프린트 작업은 네이티브 CPP 프로그래머 -기술 지식이 없는 게임 팀에 적합한 방식입니다. 프로그래머가 아닌 사람이 블루프린트로만 작업할 수 있는 이유는, 블루프린트 노드는 가상 머신(VM)에서 실행되어 -네이티브 CPP 함수 호출을 가능하게 해주기 때문입니다. 아쉽게도 블루프린트를 네이티브 CPP 코드로 변환하는 VM 은 비용이 발생합니다. -상상하시듯 블루프린트 노드를 네이티브 CPP 함수로 변환하는 것은 게임의 프레임당 퍼포먼스를 낮출 소지가 있습니다. +팀이 블루프린트로 게임플레이 스크립트를 짜면, 네이티브 C++ (C++) 코드 작성이나 컴파일할 필요 없이 UClass 를 새로 만들어 줍니다. 그로 인해 네이티브 C++ 프로그래머 기술 지식이 없는 +게임 팀에게는 블루프린트가 적합합니다. 프로그래머가 아닌 사람도 블루프린트만 가지고 작업이 가능한 이유는, 블루프린트 노드는 가상 머신(VM)에서 실행되어 +네이티브 C++ 함수를 호출할 수 있기 때문입니다. 그러나 아쉽게도 블루프린트를 네이티브 C++ 코드로 변환해 주는 VM 에는 비용이 발생합니다. +그렇기 때문에 상상하시듯, 블루프린트 노드를 네이티브 C++ 함수로 변환하는 것은 게임의 프레임당 퍼포먼스를 낮출 소지가 있습니다. -VM 에서 블루프린트를 실행하는 비용이 눈에 띄지 않을 때는, VM 비용을 안고갈 수도 있지만, 게임을 가급적 빠른 속도로 실행시켜야 할 때가 있습니다 +VM 에서 블루프린트를 실행하는 비용이 크지 않을 때는 VM 비용을 안고갈 수도 있지만, 아주 약간의 게임 퍼포먼스도 아쉬울 때가 있습니다 (하드웨어 성능이 제한된 디바이스에 출시할 때는 특히나 그렇습니다). 그럴 때 언리얼 엔진의 Blueprint Nativization (블루프린트 네이티브화) 툴이 도움이 됩니다. [REGION:note] -에픽에서는 저희 VR 신작 타이틀 [Robo Recall](https://www.epicgames.com/roborecall/en-US/home) 개발에 블루프린트 네이티트화를 성공적으로 활용했습니다. +에픽에서는 저희 VR 신작 타이틀 [Robo Recall](https://www.epicgames.com/roborecall/en-US/home) 개발에 블루프린트 네이티브화를 성공적으로 활용했습니다. [/REGION] ##VM 비용 감소 -블루프린트 네이티브화의 주 목적은 프로젝트의 블루프린트에서 네이티브 CPP 코드를 생성하여 프로젝트의 런타임 버전에서 발생하는 VM 비용을 줄이는 것입니다. -일반적으로 모든 블루프린트 클래스를 새로 생성되는 네이티브 CPP 클래스로 대체한 뒤 [쿠킹 프로세스](Engine/Deployment/Cooking) 도중 컴파일하는 것입니다. -변환된 CPP 코드를 텍스트 에디터에서 읽을 수는 있지만, 코드 포맷이 재사용 가능하지는 (또는 사람이 읽기 좋게 생성되어 있지는) 않음을 알 수 있습니다. +블루프린트 네이티브화의 주 목적은 프로젝트의 블루프린트에서 네이티브 C++ 코드를 생성하여 프로젝트의 런타임 버전에서 발생하는 VM 비용을 줄이는 것입니다. +일반적으로 모든 블루프린트 클래스를 새로 생성되는 네이티브 C++ 클래스로 대체한 뒤 [쿠킹 프로세스](Engine/Deployment/Cooking) 도중 컴파일하는 것입니다. +변환된 C++ 코드를 텍스트 에디터에서 읽을 수는 있지만, 코드 포맷이 재사용 가능하지는 (또는 사람이 읽기 좋게 생성되어 있지는) 않음을 알 수 있습니다. [OBJECT:ComparisonSlider] [PARAM:before] @@ -85,12 +86,12 @@ Unreal Automation Tool (UAT) 는 다음과 같은 지원 블루프린트 애셋 * User Defined Enums 사용자 정의 Enum [REGION:note] -현재 레벨 블루프린트와 블루프린트 매크로는 블루프린트 네이티브화 툴에 지원되지 않아, 네이티브 CPP 코드로 변환되지 않습니다. +현재 레벨 블루프린트와 블루프린트 매크로는 블루프린트 네이티브화 툴에 지원되지 않아, 네이티브 C++ 코드로 변환되지 않습니다. [/REGION] ###변환에서 블루프린트 제외 -블루프린트 네이티브화 툴이 블루프린트 노드를 네이티브 CPP 코드로 변환하면, 그 지원을 위해 추가적인 머신 인스트럭션, 종속성, 임베디드 메타데이터를 포함시켜 결과 실행파일을 +블루프린트 네이티브화 툴이 블루프린트 노드를 네이티브 C++ 코드로 변환하면, 그 지원을 위해 추가적인 머신 인스트럭션, 종속성, 임베디드 메타데이터를 포함시켜 결과 실행파일을 컴파일합니다. [REGION:warning] @@ -118,14 +119,14 @@ Unreal Automation Tool (UAT) 는 다음과 같은 지원 블루프린트 애셋 ![](BPNativization_ExclusiveUI.png)(w:900) -어플리케이션 실행을 위한 대상 하드웨어 용량 이상으로 커질 리 없는 작은 프로젝트에는 **포괄적** 메소드를 써도 괜찮지만, **배타적** 블루프린트 네이티브화 메소드를 선택했을 때의 +어플리케이션 실행을 위한 타겟 하드웨어 용량 이상으로 커질 리 없는 작은 프로젝트에는 **포괄적** 메소드를 써도 괜찮지만, **배타적** 블루프린트 네이티브화 메소드를 선택했을 때의 장점이 여러가지 있는데, 그 중 몇 가지는 다음과 같습니다: * 실행파일 최종 크기가 제한됩니다. * 미사용 블루프린트 애셋이 변환되는 것을 능동적으로 막을 수 있습니다. * 변환할 블루프린트를 명시적으로 선택할 수 있습니다. -일반적으로 계산 비용이 비싼 블루프린트를 배타적으로 네이티브화하는 것을 추천하는데, 다음과 같습니다 (여기에만 국한되는 것은 아닙니다): +일반적으로는 계산 비용이 비싼 블루프린트를 배타적으로 네이티브화하는 것을 추천하는데, 그 경우는 다음과 같습니다 (여기에만 국한되는 것은 아닙니다): * 노드가 많은 블루프린트. * 최적화된 루프를 요하는 블루프린트. diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Add/Add.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Add/Add.CHN.udn new file mode 100644 index 000000000000..a5509b3c99f1 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Add/Add.CHN.udn @@ -0,0 +1,38 @@ +INTSourceChangelist:0 +Availability:Docs +Title:Add +Description:Adds a key-value pair to a Map. +Crumbs: +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:1 +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_AddNode.png) + +The **Add** node adds a key and a value (key-value pair) to a Map, thereby increasing the length of the Map. When adding a key-value pair to a Map, the node checks whether the added key is equal to an existing key in the Map. +If the new key is equal to a key that's already in the Map, the existing value associated with the key will be overwritten with the new value. After this node has completed its operation, the key is guaranteed to be associated +with its vcorresponding value until a subsequent mutation of the Map. + +##Inputs + +| Pin Location | Name | Description | +| ---------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Map_AddNode_1.png) | (In) Exec | Input execution pin. | +| ![](Map_AddNode_2.png) | Target Map | The Map that you want to add a new key-value pair to. | +| ![](Map_AddNode_3.png) | Key | The key being used to lookup a value in the Map. [REGION:note]If the same key already exists, the existing value associated with the key will be overwritten.[/REGION] | +| ![](Map_AddNode_4.png) | Value | The value being stored in the Map for subsequent retrieval. | + +##Outputs + +| Pin Location | Name | Description | +| ---------------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Map_AddNode_5.png) | (Out) Exec | Output execution pin. | +| ![](Map_AddNode_6.png) | Boolean Return Value | If the value was added, the node returns true. Otherwise, if the key was already present, resulting in its associated value being overwrittent, the node returns false. | + +##Example Usage + +![](Map_AddUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Add/Add.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Add/Add.INT.udn new file mode 100644 index 000000000000..b129b9db9ccc --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Add/Add.INT.udn @@ -0,0 +1,37 @@ +Availability:Docs +Title:Add +Description:Adds a key-value pair to a Map. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:1 +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_AddNode.png) + +The **Add** node adds a key and a value (key-value pair) to a Map, thereby increasing the length of the Map. When adding a key-value pair to a Map, the node checks whether the added key is equal to an existing key in the Map. +If the new key is equal to a key that's already in the Map, the existing value associated with the key will be overwritten with the new value. After this node has completed its operation, the key is guaranteed to be associated +with its corresponding value until a subsequent mutation of the Map. + +##Inputs + +| Pin Location | Name | Description | +| ---------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Map_AddNode_1.png) | (In) Exec | Input execution pin. | +| ![](Map_AddNode_2.png) | Target Map | The Map that you want to add a new key-value pair to. | +| ![](Map_AddNode_3.png) | Key | The key being used to lookup a value in the Map. [REGION:note]If the same key already exists, the existing value associated with the key will be overwritten.[/REGION] | +| ![](Map_AddNode_4.png) | Value | The value being stored in the Map for subsequent retrieval. | + +##Outputs + +| Pin Location | Name | Description | +| ---------------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Map_AddNode_5.png) | (Out) Exec | Output execution pin. | +| ![](Map_AddNode_6.png) | Boolean Return Value | If the value was added, the node returns true. Otherwise, if the key was already present, resulting in its associated value being overwritten, the node returns false. | + +##Example Usage + +![](Map_AddUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Add/Add.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Add/Add.JPN.udn new file mode 100644 index 000000000000..043b290412e5 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Add/Add.JPN.udn @@ -0,0 +1,38 @@ +INTSourceChangelist:3413824 +Availability:Docs +Title:Add +Description:キー / 値のペアを Map に追加する +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:1 +Version:4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_AddNode.png) + +**Add** ノードはキー / 値のペアを Map に追加します。これにより、Map が長くなります。キー / 値のペアを Map に追加すると、Map の既存アイテムの中に追加されたキーと同じものが存在するかどうかを Add ノードがチェックします。 +追加されたキーと同じものが既に Map 内にある場合、このキーに関連付いている値は新しい値に上書きされます。Add ノードが処理を完了すると、 +次回 Map の変更時までキーは相対値に関連づけられることが保証されます。 + +##入力 + +| ピンの位置 | 名前 | 説明 | +| ---------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Map_AddNode_1.png) | (In) Exec | 入力実行ピンです。 | +| ![](Map_AddNode_2.png) | Target Map | 新規キー / 値のペアの追加先にする Map です。 | +| ![](Map_AddNode_3.png) | Key | Map 内での検索に使うキーです。[REGION:note]既に存在する場合、その値は上書きされます。[/REGION] | +| ![](Map_AddNode_4.png) | Value | その後の検索用に Map 内に格納されている値です。 | + +##出力 + +| ピンの位置 | 名前 | 説明 | +| ---------------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Map_AddNode_5.png) | (Out) Exec | 出力実行ピンです。 | +| ![](Map_AddNode_6.png) | Boolean Return Value | 値が追加されるとノードは true を返します。キーが既に存在している場合、関連付いている値は上書きされ、ノードは false を返します。 | + +##使用例 + +![](Map_AddUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Add/Add.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Add/Add.KOR.udn new file mode 100644 index 000000000000..b1c740199d56 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Add/Add.KOR.udn @@ -0,0 +1,38 @@ +INTSourceChangelist:3413824 +Availability:Docs +Title:Add +Description:맵에 키-값 짝을 추가합니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:1 +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_AddNode.png) + +**Add** 노드는 Map (맵)에 키와 값 (키-값 짝)을 추가하여, 맵의 길이가 늘어납니다. 맵에 키-값 짝을 추가할 때, 노드는 추가된 키가 맵의 기존 키와 같은지 검사합니다. +새로운 키가 이미 맵에 있는 키와 같은 경우, 기존 키에 할당된 값은 새로운 값으로 덮어씁니다. 이 노드가 연산을 완료한 이후, 맵에 대한 변이(mutation)가 발생할 때까지 키에는 +올바른 값 할당이 보장됩니다. + +##입력 + +| 핀 위치 | 이름 | 설명 | +| ---------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Map_AddNode_1.png) | (In) Exec | 입력 실행 핀입니다. | +| ![](Map_AddNode_2.png) | Target Map | 새로운 키-값 짝을 추가하고자 하는 맵입니다. | +| ![](Map_AddNode_3.png) | Key | 맵의 값 룩업에 사용되고 있는 키입니다. [REGION:note]같은 키가 이미 존재하면, 그 키에 할당된 기존 값은 덮어씁니다.[/REGION] | +| ![](Map_AddNode_4.png) | Value | 나중에 값을 구해올 수 있도록 맵에 저장된 값입니다. | + +##출력 + +| 핀 위치 | 이름 | 설명 | +| ---------------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Map_AddNode_5.png) | (Out) Exec | 출력 실행 핀입니다. | +| ![](Map_AddNode_6.png) | Boolean Return Value | 값이 추가되면, 노드는 true 를 반환합니다. 아니면 키가 이미 존재하는 경우, 할당된 값을 덮어쓰고 노드는 false 를 반환합니다. | + +##사용 예 + +![](Map_AddUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Clear/Clear.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Clear/Clear.CHN.udn new file mode 100644 index 000000000000..c3daace6ac8b --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Clear/Clear.CHN.udn @@ -0,0 +1,33 @@ +INTSourceChangelist:0 +Availability:Docs +Title:Clear +Description:Clears a Map of all entries. +Crumbs: +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:2 +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_ClearNode.png) + +The **Clear** node removes all of the key-value pairs from a given Map, removing all of the Map's contents. Subsequently, the Map's length will be reset to zero. + +##Inputs + +| Pin Location | Name | Description | +| ------------------------ | ----------- | -------------------------------------------- | +| ![](Map_ClearNode_1.png) | (In) Exec | Input execution pin. | +| ![](Map_ClearNode_2.png) | Target Map | The Map that you want to clear entries from. | + +##Outputs + +| Pin Location | Name | Description | +| ------------------------ | ----------- | --------------------- | +| ![](Map_ClearNode_3.png) | (Out) Exec | Output execution pin. | + +##Example Usage + +![](Map_ClearUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Clear/Clear.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Clear/Clear.INT.udn new file mode 100644 index 000000000000..0e19c64a51bb --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Clear/Clear.INT.udn @@ -0,0 +1,32 @@ +Availability:Docs +Title:Clear +Description:Clears a Map of all entries. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:2 +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_ClearNode.png) + +The **Clear** node removes all of the key-value pairs from a given Map, removing all of the Map's contents. Subsequently, the Map's length will be reset to zero. + +##Inputs + +| Pin Location | Name | Description | +| ------------------------ | ----------- | -------------------------------------------- | +| ![](Map_ClearNode_1.png) | (In) Exec | Input execution pin. | +| ![](Map_ClearNode_2.png) | Target Map | The Map that you want to clear entries from. | + +##Outputs + +| Pin Location | Name | Description | +| ------------------------ | ----------- | --------------------- | +| ![](Map_ClearNode_3.png) | (Out) Exec | Output execution pin. | + +##Example Usage + +![](Map_ClearUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Clear/Clear.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Clear/Clear.JPN.udn new file mode 100644 index 000000000000..47e15326e820 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Clear/Clear.JPN.udn @@ -0,0 +1,33 @@ +INTSourceChangelist:3413824 +Availability:Docs +Title:Clear +Description:Map 内のすべてのエントリをクリアする +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:2 +Version:4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_ClearNode.png) + +**Clear** ノードは、Map からすべてのキー / 値のペアのコンテンツを削除して、Map のコンテンツをすべて除去します。結果、Map の長さはゼロにリセットされます。 + +##入力 + +| ピンの位置 | 名前 | 説明 | +| ------------------------ | ----------- | -------------------------------------------- | +| ![](Map_ClearNode_1.png) | (In) Exec | 入力実行ピンです。 | +| ![](Map_ClearNode_2.png) | Target Map | エントリをクリアする Map です。| + +##出力 + +| ピンの位置 | 名前 | 説明 | +| ------------------------ | ----------- | --------------------- | +| ![](Map_ClearNode_3.png) | (Out) Exec | 出力実行ピンです。| + +##使用例 + +![](Map_ClearUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Clear/Clear.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Clear/Clear.KOR.udn new file mode 100644 index 000000000000..1ef634862c0a --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Clear/Clear.KOR.udn @@ -0,0 +1,33 @@ +INTSourceChangelist:3413824 +Availability:Docs +Title:Clear +Description:맵의 모든 항목을 지웁니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:2 +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_ClearNode.png) + +**Clear** (지우기) 노드는 주어진 맵에서 모든 키-값 짝을 제거하여, 맵의 모든 내용을 없앱니다. 그에 따라 맵의 길이는 0 으로 리셋됩니다. + +##입력 + +| 핀 위치 | 이름 | 설명 | +| ------------------------ | ----------- | -------------------------------------------- | +| ![](Map_ClearNode_1.png) | (In) Exec | 입력 실행 핀입니다. | +| ![](Map_ClearNode_2.png) | Target Map | 항목을 삭제하고자 하는 맵입니다.| + +##출력 + +| 핀 위치 | 이름 | 설명 | +| ------------------------ | ----------- | --------------------- | +| ![](Map_ClearNode_3.png) | (Out) Exec | 출력 실행 핀입니다. | + +##사용 예 + +![](Map_ClearUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Contains/Contains.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Contains/Contains.CHN.udn new file mode 100644 index 000000000000..80e441228041 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Contains/Contains.CHN.udn @@ -0,0 +1,33 @@ +INTSourceChangelist:0 +Availability:Docs +Title:Contains +Description:This node checks to see if a key exists in a provided Map. +Crumbs: +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:3 +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_ContainsNode.png) + +The **Contains** node, using a provided key, searches a Map for an associated item, returning true if the Map contains the item, confirming the key's existence. + +##Inputs + +| Pin Location | Name | Description | +| --------------------------- | ------------- | ----------------------------------------- | +| ![](Map_ContainsNode_1.png) | Target Map | The Map that you want to search. | +| ![](Map_ContainsNode_2.png) | Key | The key that you're using for the search. | + +##Outputs + +| Pin Location | Name | Description | +| --------------------------- | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Map_ContainsNode_3.png) | Boolean Return Value | If the node finds the item in the Map, the node returns true. Otherwise, if the node returns false, there is no item contained in the Map that uses the provided key. | + +##Example Usage + +![](Map_ContainsUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Contains/Contains.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Contains/Contains.INT.udn new file mode 100644 index 000000000000..d7a27c17fdba --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Contains/Contains.INT.udn @@ -0,0 +1,32 @@ +Availability:Docs +Title:Contains +Description:This node checks to see if a key exists in a provided Map. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:3 +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_ContainsNode.png) + +The **Contains** node, using a provided key, searches a Map for an associated item, returning true if the Map contains the item, confirming the key's existence. + +##Inputs + +| Pin Location | Name | Description | +| --------------------------- | ------------- | ----------------------------------------- | +| ![](Map_ContainsNode_1.png) | Target Map | The Map that you want to search. | +| ![](Map_ContainsNode_2.png) | Key | The key that you're using for the search. | + +##Outputs + +| Pin Location | Name | Description | +| --------------------------- | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Map_ContainsNode_3.png) | Boolean Return Value | If the node finds the item in the Map, the node returns true. Otherwise, if the node returns false, there is no item contained in the Map that uses the provided key. | + +##Example Usage + +![](Map_ContainsUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Contains/Contains.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Contains/Contains.JPN.udn new file mode 100644 index 000000000000..bbbfd9817066 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Contains/Contains.JPN.udn @@ -0,0 +1,33 @@ +INTSourceChangelist:3413824 +Availability:Docs +Title:Contains +Description:指定された Map に既にキーが存在するかどうかをチェックするノードです。 +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:3 +Version:4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_ContainsNode.png) + +**Contains** ノードは、指定されたキーを使って Map に関連付けられたアイテムを検索します。Map にアイテムが存在すれば、キーの存在を確認して、true を返します。 + +##入力 + +| ピンの位置 | 名前 | 説明 | +| --------------------------- | ------------- | ----------------------------------------- | +| ![](Map_ContainsNode_1.png) | Target Map | 検索対象の Map です。| +| ![](Map_ContainsNode_2.png) | Key | 検索に使用するキーです。 | + +##出力 + +| ピンの位置 | 名前 | 説明 | +| --------------------------- | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Map_ContainsNode_3.png) | Boolean Return Value | ノードが Map 内でアイテムを見つけると true を返します。Map 内に指定されたキーを使っているアイテムが存在しない場合、ノードは false を返します。 | + +##使用例 + +![](Map_ContainsUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Contains/Contains.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Contains/Contains.KOR.udn new file mode 100644 index 000000000000..618aee80741c --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Contains/Contains.KOR.udn @@ -0,0 +1,33 @@ +INTSourceChangelist:3413824 +Availability:Docs +Title:Contains +Description:제공된 맵에 키가 존재하는지 확인하는 노드입니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:3 +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_ContainsNode.png) + +**Contains** 노드는 제공된 키를 사용하여 맵에 할당된 아이템을 검색, 맵에 그 아이템이 있으면 true 를 반환하여 키의 존재를 확인합니다. + +##입력 + +| 핀 위치 | 이름 | 설명 | +| --------------------------- | ------------- | ----------------------------------------- | +| ![](Map_ContainsNode_1.png) | Target Map | 검색하고자 하는 맵입니다. | +| ![](Map_ContainsNode_2.png) | Key | 검색에 사용하려는 키입니다. | + +##Outputs + +| 핀 위치 | 이름 | 설명 | +| --------------------------- | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Map_ContainsNode_3.png) | Boolean Return Value | 노드가 맵에서 아이템을 찾으면, true 를 반환합니다. 찾지 못하면 노드는 false 를 반환, 제공된 키를 사용하는 아이템이 맵에 없음을 나타냅니다. | + +##사용 예 + +![](Map_ContainsUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Find/Find.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Find/Find.CHN.udn new file mode 100644 index 000000000000..e3bf80c1fbe7 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Find/Find.CHN.udn @@ -0,0 +1,34 @@ +INTSourceChangelist:0 +Availability:Docs +Title:Find +Description:Find the value associated with a provided key. +Crumbs: +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:4 +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_FindNode.png) + +The **Find** node, having been provided a key, searches a Map for your item, returning true if the Map contains the item, and subsequently returning the value if the item is found. + +##Inputs + +| Pin Location | Name | Description | +| ----------------------- | ------------- | ----------------------------------------- | +| ![](Map_FindNode_1.png) | Target Map | The Map that you want to search. | +| ![](Map_FindNode_2.png) | Item to Find | The key that you're using for the search. | + +##Outputs + +| Pin Location | Name | Description | +| ----------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Map_FindNode_3.png) | Value | This is the value associated with the key being used for the search. [REGION:note]If the key wasn't found in the Map, a default value will be constructed and returned.[/REGION] | +| ![](Map_FindNode_3.png) | Boolean Return Value | If the node finds the item in the Map, the node returns true. Otherwise, if the node returns false, there is no item contained in the Map that uses the provided key. | + +##Example Usage + +![](Map_FindUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Find/Find.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Find/Find.INT.udn new file mode 100644 index 000000000000..939eb746fedb --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Find/Find.INT.udn @@ -0,0 +1,33 @@ +Availability:Docs +Title:Find +Description:Find the value associated with a provided key. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:4 +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_FindNode.png) + +The **Find** node, having been provided a key, searches a Map for your item, returning true if the Map contains the item, and subsequently returning the value if the item is found. + +##Inputs + +| Pin Location | Name | Description | +| ----------------------- | ------------- | ----------------------------------------- | +| ![](Map_FindNode_1.png) | Target Map | The Map that you want to search. | +| ![](Map_FindNode_2.png) | Item to Find | The key that you're using for the search. | + +##Outputs + +| Pin Location | Name | Description | +| ----------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Map_FindNode_3.png) | Value | This is the value associated with the key being used for the search. [REGION:note]If the key wasn't found in the Map, a default value will be constructed and returned.[/REGION] | +| ![](Map_FindNode_3.png) | Boolean Return Value | If the node finds the item in the Map, the node returns true. Otherwise, if the node returns false, there is no item contained in the Map that uses the provided key. | + +##Example Usage + +![](Map_FindUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Find/Find.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Find/Find.JPN.udn new file mode 100644 index 000000000000..2b26fe61201e --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Find/Find.JPN.udn @@ -0,0 +1,34 @@ +INTSourceChangelist:3413824 +Availability:Docs +Title:Find +Description:与えられたキーに関連付けられた値を見つける +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:4 +Version:4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_FindNode.png) + +**Find** ノードは、指定されたキーを使って Map 内のアイテムを検索します。Map にアイテムが存在すれば true を返し、アイテムが存在する場合は続けて値を返します。 + +##入力 + +| ピンの位置 | 名前 | 説明 | +| ----------------------- | ------------- | ----------------------------------------- | +| ![](Map_FindNode_1.png) | Target Map | 検索対象の Map です。| +| ![](Map_FindNode_2.png) | Item to Find | 検索に使用するキーです。 | + +##出力 + +| ピンの位置 | 名前 | 説明 | +| ----------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Map_FindNode_3.png) | Value | 検索に使用しているキーに関連付けれた値です。[REGION:note]Map でキーた見つからない場合は、デフォルト値が作成されて返されます。[/REGION] | +| ![](Map_FindNode_3.png) | Boolean Return Value | ノードが Map 内でアイテムを見つけると true を返します。指定されたキーを使っている Map 内にアイテムが存在しない場合、ノードは false を返します。 | + +##使用例 + +![](Map_FindUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Find/Find.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Find/Find.KOR.udn new file mode 100644 index 000000000000..e6e26f7cfd9a --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Find/Find.KOR.udn @@ -0,0 +1,34 @@ +INTSourceChangelist:3413824 +Availability:Docs +Title:Find +Description:제공된 키에 할당된 값을 찾습니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:4 +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_FindNode.png) + +**Find** 노드는 키를 제공받아 맵에서 아이템을 검색한 뒤, 맵에 그 아이템이 있으면 true 를 반환하고, 잇따라 아이템을 찾았으면 값을 반환합니다. + +##입력 + +| 핀 위치 | 이름 | 설명 | +| ----------------------- | ------------- | ----------------------------------------- | +| ![](Map_FindNode_1.png) | Target Map | 검색하고자 하는 맵입니다. | +| ![](Map_FindNode_2.png) | Item to Find | 검색에 사용중인 키입니다. | + +##출력 + +| 핀 위치 | 이름 | 설명 | +| ----------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Map_FindNode_3.png) | Value | 검색에 사용되고 있는 카에 할당된 값입니다. [REGION:note]맵에서 키를 찾지 못한 경우, 기본 값을 생성하여 반환합니다.[/REGION] | +| ![](Map_FindNode_3.png) | Boolean Return Value | 노드가 맵에서 아이템을 찾으면 노드는 true 를 반환합니다. 찾지 못하면 노드는 false 를 반환, 맵에 제공된 키를 사용하는 아이템이 들어있지 않습니다.| + +##사용 예 + +![](Map_FindUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Keys/Keys.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Keys/Keys.CHN.udn new file mode 100644 index 000000000000..464c31790ebe --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Keys/Keys.CHN.udn @@ -0,0 +1,34 @@ +INTSourceChangelist:0 +Availability:Docs +Title:Keys +Description:Outputs an Array of all keys present in the Map. +Crumbs: +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:5 +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_KeysNode.png) + +The **Keys** node outputs an Array of all keys that are present in a given Map. + +##Inputs + +| Pin Location | Name | Description | +| ----------------------- | ----------- | ------------------------------------- | +| ![](Map_KeysNode_1.png) | (In) Exec | Input execution pin. | +| ![](Map_KeysNode_2.png) | Target Map | The Map to get an Array of keys from. | + +##Outputs + +| Pin Location | Name | Description | +| ------------------------ | ----------- | ------------------------------------------------------------- | +| ![](Map_KeysNode_3.png) | (Out) Exec | Output execution pin. | +| ![](Map_KeysNode_4.png) | Array | An output Array, containing all of the keys found in the Map. | + +##Example Usage + +![](Map_KeysUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Keys/Keys.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Keys/Keys.INT.udn new file mode 100644 index 000000000000..7ee6d9263592 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Keys/Keys.INT.udn @@ -0,0 +1,33 @@ +Availability:Docs +Title:Keys +Description:Outputs an Array of all keys present in the Map. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:5 +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_KeysNode.png) + +The **Keys** node outputs an Array of all keys that are present in a given Map. + +##Inputs + +| Pin Location | Name | Description | +| ----------------------- | ----------- | ------------------------------------- | +| ![](Map_KeysNode_1.png) | (In) Exec | Input execution pin. | +| ![](Map_KeysNode_2.png) | Target Map | The Map to get an Array of keys from. | + +##Outputs + +| Pin Location | Name | Description | +| ------------------------ | ----------- | ------------------------------------------------------------- | +| ![](Map_KeysNode_3.png) | (Out) Exec | Output execution pin. | +| ![](Map_KeysNode_4.png) | Array | An output Array, containing all of the keys found in the Map. | + +##Example Usage + +![](Map_KeysUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Keys/Keys.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Keys/Keys.JPN.udn new file mode 100644 index 000000000000..fe34106ea715 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Keys/Keys.JPN.udn @@ -0,0 +1,34 @@ +INTSourceChangelist:3413824 +Availability:Docs +Title:Keys +Description:Map に存在するすべてのキーの Array を出力する +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:5 +Version:4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_KeysNode.png) + +**Keys** ノードは、指定された Map に存在するすべてのキーの Array を出力します。 + +##入力 + +| ピンの位置 | 名前 | 説明 | +| ----------------------- | ----------- | ------------------------------------- | +| ![](Map_KeysNode_1.png) | (In) Exec | 入力実行ピンです。 | +| ![](Map_KeysNode_2.png) | Target Map | The Map to get an Array of keys from. | + +##出力 + +| ピンの位置 | 名前 | 説明 | +| ------------------------ | ----------- | ------------------------------------------------------------- | +| ![](Map_KeysNode_3.png) | (Out) Exec | 出力実行ピンです。 | +| ![](Map_KeysNode_4.png) | Array | Map 内で見つかったすべてのキーを含む出力 Array です。 | + +##使用例 + +![](Map_KeysUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Keys/Keys.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Keys/Keys.KOR.udn new file mode 100644 index 000000000000..ffbe4ba7130a --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Keys/Keys.KOR.udn @@ -0,0 +1,34 @@ +INTSourceChangelist:3413824 +Availability:Docs +Title:Keys +Description:맵에 존재하는 모든 키 배열을 출력합니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:5 +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_KeysNode.png) + +**Keys** 노드는 주어진 맵에 존재하는 모든 키 배열을 출력합니다. + +##입력 + +| 핀 위치 | 이름 | 설명 | +| ----------------------- | ----------- | ------------------------------------- | +| ![](Map_KeysNode_1.png) | (In) Exec | 입력 실행 핀입니다. | +| ![](Map_KeysNode_2.png) | Target Map | 키 배열을 구해 올 맵입니다. | + +##출력 + +| 핀 위치 | 이름 | 설명 | +| ------------------------ | ----------- | ------------------------------------------------------------- | +| ![](Map_KeysNode_3.png) | (Out) Exec | 실행 핀을 출력합니다. | +| ![](Map_KeysNode_4.png) | Array | 출력 배열로, 맵에서 찾을 수 있는 모든 키가 들어있습니다. | + +##사용 예 + +![](Map_KeysUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Length/Length.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Length/Length.CHN.udn new file mode 100644 index 000000000000..8fee702edf65 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Length/Length.CHN.udn @@ -0,0 +1,32 @@ +INTSourceChangelist:0 +Availability:Docs +Title:Length +Description:Determines the number of entries in a provided Map. +Crumbs: +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:6 +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_LengthNode.png) + +The **Length** node gets the number of entries in a given Map. + +##Inputs + +| Pin Location | Name | Description | +| ------------------------- | ----------- | ------------------------------------------- | +| ![](Map_LengthNode_1.png) | Target Set | The Map that you want to get the length of. | + +##Outputs + +| Pin Location | Name | Description | +| ------------------------- | --------------------- | -------------------------------------------------------------------------------------------------------- | +| ![](Map_LengthNode_2.png) | Integer Return Value | The length of the Map. In other words, the length is the number of entries that were counted in the Map. | + +##Example Usage + +![](Map_LengthUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Length/Length.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Length/Length.INT.udn new file mode 100644 index 000000000000..ef6813eeb061 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Length/Length.INT.udn @@ -0,0 +1,31 @@ +Availability:Docs +Title:Length +Description:Determines the number of entries in a provided Map. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:6 +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_LengthNode.png) + +The **Length** node gets the number of entries in a given Map. + +##Inputs + +| Pin Location | Name | Description | +| ------------------------- | ----------- | ------------------------------------------- | +| ![](Map_LengthNode_1.png) | Target Set | The Map that you want to get the length of. | + +##Outputs + +| Pin Location | Name | Description | +| ------------------------- | --------------------- | -------------------------------------------------------------------------------------------------------- | +| ![](Map_LengthNode_2.png) | Integer Return Value | The length of the Map. In other words, the length is the number of entries that were counted in the Map. | + +##Example Usage + +![](Map_LengthUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Length/Length.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Length/Length.JPN.udn new file mode 100644 index 000000000000..65c9da3d8c7e --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Length/Length.JPN.udn @@ -0,0 +1,32 @@ +INTSourceChangelist:3413824 +Availability:Docs +Title:Length +Description:指定された Map 内のエントリ数を決定します。 +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:6 +Version:4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_LengthNode.png) + +**Length** ノードは指定された Map のエントリ数を取得します。 + +##入力 + +| ピンの位置 | 名前 | 説明 | +| ------------------------- | ----------- | ------------------------------------------- | +| ![](Map_LengthNode_1.png) | Target Set | 長さを取得したい Set です。 | + +##出力 + +| ピンの位置 | 名前 | 説明 | +| ------------------------- | --------------------- | -------------------------------------------------------------------------------------------------------- | +| ![](Map_LengthNode_2.png) | Integer Return Value | その Map の長さです。別の言い方をすると、長さとはその Map の中に含まれているエントリ数です。 + +##使用例 + +![](Map_LengthUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Length/Length.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Length/Length.KOR.udn new file mode 100644 index 000000000000..7b74b82e147e --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Length/Length.KOR.udn @@ -0,0 +1,32 @@ +INTSourceChangelist:3413824 +Availability:Docs +Title:Length +Description:제공된 맵의 항목 수를 결정합니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:6 +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_LengthNode.png) + +**Length** 노드는 주어진 맵의 항목 수를 구합니다. + +##입력 + +| 핀 위치 | 이름 | 설명 | +| ------------------------- | ----------- | ------------------------------------------- | +| ![](Map_LengthNode_1.png) | Target Set | 길이를 구하고자 하는 맵입니다. | + +##출력 + +| 핀 위치 | 이름 | 설명 | +| ------------------------- | --------------------- | -------------------------------------------------------------------------------------------------------- | +| ![](Map_LengthNode_2.png) | Integer Return Value | 맵의 길이입니다. 다른 말로 길이란 맵에 있는 항목 수를 말합니다. | + +##사용 예 + +![](Map_LengthUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/MapNodes.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/MapNodes.CHN.udn new file mode 100644 index 000000000000..dd470ecb0eef --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/MapNodes.CHN.udn @@ -0,0 +1,26 @@ +INTSourceChangelist:0 +Availability:Docs +Title:Blueprint Map Nodes +Description:An overview of the node interface when working with Blueprint Maps. +Crumbs:%ROOT% +Parent:Engine/Blueprints/Scripting +Order:2 +Version: 4.15 +Tags:Blueprint Map +Tags:Blueprints +Type:reference + +A Map's node interface provides the following functionality for developers working in Blueprints: adding keys and their associated values (key-value pairs) to a +Map, removing items from a Map, clearing Maps, looking up keys and values contained in a Map, and checking a Map's length. +The following guide provides additional information about the various nodes that make-up Blueprint Sets in Unreal Engine 4 (UE4). + +| Node | Description | +| -------------------------------------------------------------- | -------------------------------------------------------------------- | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Add)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Add:description% | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Clear)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Clear:description% | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Contains)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Contains:description% | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Find)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Find:description% | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Keys)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Keys:description% | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Length)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Length:description% | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Remove)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Remove:description% | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Values)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Values:description% | diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/MapNodes.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/MapNodes.INT.udn new file mode 100644 index 000000000000..0eefd8015fe2 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/MapNodes.INT.udn @@ -0,0 +1,27 @@ +Availability:Docs +Title:Blueprint Map Nodes +Description:An overview of the node interface when working with Blueprint Maps. +Crumbs:%ROOT% +Parent:Engine/Blueprints/Scripting +Order:2 +Version: 4.15 +Tags:Blueprint Map +Tags:Blueprints +Type:reference +Related:Programming/UnrealArchitecture/TMap + +A Map's node interface provides the following functionality for developers working in Blueprints: adding keys and their associated values (key-value pairs) to a +Map, removing items from a Map, clearing Maps, looking up keys and values contained in a Map, and checking a Map's length. +The following guide provides additional information about the various nodes that make-up Blueprint Sets in Unreal Engine 4 (UE4). + +| Node | Description | +| -------------------------------------------------------------- | -------------------------------------------------------------------- | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Add)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Add:description% | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Clear)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Clear:description% | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Contains)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Contains:description% | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Find)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Find:description% | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Keys)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Keys:description% | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Length)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Length:description% | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Remove)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Remove:description% | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Values)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Values:description% | + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/MapNodes.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/MapNodes.JPN.udn new file mode 100644 index 000000000000..0c390dbdf4cc --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/MapNodes.JPN.udn @@ -0,0 +1,28 @@ +INTSourceChangelist:3413824 +Availability:Docs +Title:Blueprint Map ノード +Description:Blueprint Map を使った作業時のノード インターフェースの概要 +Crumbs:%ROOT% +Parent:Engine/Blueprints/Scripting +Order:2 +Version:4.15 +tags:Blueprint Map +Tags:Blueprints +Type:reference +Related:Programming/UnrealArchitecture/TMap + +Map のノード インターフェースにより、デベロッパーはブループリントの作業中に、 +キー / 関連付けられた値 (キー / 値のペア) の Map への追加、Map のクリア、Map 内に存在するキーと値の検索、Map の長さの確認といった操作が可能になります。 +以下のガイドでは、アンリアル エンジン 4 (UE4) の Blueprint Set を構築する各種ノードの詳細を説明しています。 + +| ノード | 説明 | +| -------------------------------------------------------------- | -------------------------------------------------------------------- | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Add)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Add:description% | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Clear)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Clear:description% | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Contains)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Contains:description% | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Find)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Find:description% | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Keys)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Keys:description% | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Length)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Length:description% | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Remove)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Remove:description% | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Values)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Values:description% | + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/MapNodes.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/MapNodes.KOR.udn new file mode 100644 index 000000000000..b9d2ed21a33b --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/MapNodes.KOR.udn @@ -0,0 +1,28 @@ +INTSourceChangelist:3413824 +Availability:Docs +Title:블루프린트 맵 노드 +Description:블루프린트 맵 작업 시의 노드 인터페이스 개요입니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/Scripting +Order:2 +Version: 4.15 +Tags:Blueprint Map +Tags:Blueprints +Type:reference +Related:Programming/UnrealArchitecture/TMap + +맵의 노드 인터페이스는 블루프린트 작업을 하는 개발자들에게 다음과 같은 함수 기능을 제공합니다: +맵에 키 및 그에 할당된 값 (키-값 짝) 추가, 맵에서 아이템 제거, 맵 비우기, 맵에 들어있는 키 및 값 검색, 맵 길이 확인 등입니다. +다음은 언리얼 엔진 4 (UE4) 의 블루프린트 세트를 이루는 여러가지 노드 관련 부가 정보 안내서입니다. + +| 노드 | 설명 | +| -------------------------------------------------------------- | -------------------------------------------------------------------- | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Add)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Add:description% | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Clear)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Clear:description% | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Contains)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Contains:description% | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Find)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Find:description% | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Keys)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Keys:description% | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Length)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Length:description% | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Remove)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Remove:description% | +| **[](Engine/Blueprints/UserGuide/Maps/MapNodes/Values)** | %Engine/Blueprints/UserGuide/Maps/MapNodes/Values:description% | + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Remove/Remove.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Remove/Remove.CHN.udn new file mode 100644 index 000000000000..5b8add62ec50 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Remove/Remove.CHN.udn @@ -0,0 +1,36 @@ +INTSourceChangelist:0 +Availability:Docs +Title:Remove +Description:Removes a key-value pair from a Map. +Crumbs: +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:7 +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_RemoveNode.png) + +The **Remove** node removes a key-value pair from a Map, thereby decreasing the length of the Map. When removing a key-value pair from a Map, the node checks whether the key is in the Map. +If the key isn't in the Map, the key-value pair won't be removed. + +##Inputs + +| Pin Location | Name | Description | +| ------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Map_RemoveNode_1.png) | (In) Exec | Input execution pin. | +| ![](Map_RemoveNode_2.png) | Target Map | The Map that you want to remove the key-value pair from. | +| ![](Map_RemoveNode_3.png) | Key | The key being used to lookup a value in the Map. [REGION:note]Before a key-value pair can be removed, the key must be contained in the Map.[/REGION] | + +##Outputs + +| Pin Location | Name | Description | +| ---------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ | +| ![](Map_RemoveNode_4.png) | (Out) Exec | Output execution pin. | +| ![](Map_RemoveNode_5.png) | Boolean Return Value | If the key-value pair was removed, the node returns true. Otherwise, if there are no values in the Map using the provided key, the node returns false. | + +##Example Usage + +![](Map_RemoveUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Remove/Remove.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Remove/Remove.INT.udn new file mode 100644 index 000000000000..dd3504485d95 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Remove/Remove.INT.udn @@ -0,0 +1,35 @@ +Availability:Docs +Title:Remove +Description:Removes a key-value pair from a Map. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:7 +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_RemoveNode.png) + +The **Remove** node removes a key-value pair from a Map, thereby decreasing the length of the Map. When removing a key-value pair from a Map, the node checks whether the key is in the Map. +If the key isn't in the Map, the key-value pair won't be removed. + +##Inputs + +| Pin Location | Name | Description | +| ------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Map_RemoveNode_1.png) | (In) Exec | Input execution pin. | +| ![](Map_RemoveNode_2.png) | Target Map | The Map that you want to remove the key-value pair from. | +| ![](Map_RemoveNode_3.png) | Key | The key being used to lookup a value in the Map. [REGION:note]Before a key-value pair can be removed, the key must be contained in the Map.[/REGION] | + +##Outputs + +| Pin Location | Name | Description | +| ---------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ | +| ![](Map_RemoveNode_4.png) | (Out) Exec | Output execution pin. | +| ![](Map_RemoveNode_5.png) | Boolean Return Value | If the key-value pair was removed, the node returns true. Otherwise, if there are no values in the Map using the provided key, the node returns false. | + +##Example Usage + +![](Map_RemoveUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Remove/Remove.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Remove/Remove.JPN.udn new file mode 100644 index 000000000000..7c70afeb8ed9 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Remove/Remove.JPN.udn @@ -0,0 +1,36 @@ +INTSourceChangelist:3413824 +Availability:Docs +Title:Remove +Description:キー / 値のペアを Map から除去する +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +order:7 +Version:4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_RemoveNode.png) + +**Remove** ノードは Map からキー / 値のペアを除去します。これにより、Map の長さが短くなります。キー / 値のペアを Map から除去する時、そのキーが Map に存在するかどうかを Remove ノードがチェックします。 +キーが Map 内になければ、そのキー / 値のペアは除去されません。 + +##入力 + +| ピンの位置 | 名前 | 説明 | +| ------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Map_RemoveNode_1.png) | (In) Exec | 入力実行ピンです。 | +| ![](Map_RemoveNode_2.png) | Target Map | キー / 値のペアを除去する Map です。 | +| ![](Map_RemoveNode_3.png) | Key | Map 内での検索に使うキーです。[REGION:note]キー / 値のペアを除去するには、キーが Map に含まれていなければなりません。[/REGION] | + +##出力 + +| ピンの位置 | 名前 | 説明 | +| ---------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ | +| ![](Map_RemoveNode_4.png) | (Out) Exec | 出力実行ピンです。 | +| ![](Map_RemoveNode_5.png) | Boolean Return Value | キー / 値のペアが除去されると、ノードは true を返します。指定されたキーを使っている値が Map に存在しなければ、ノードは false を返します。 | + +##使用例 + +![](Map_RemoveUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Remove/Remove.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Remove/Remove.KOR.udn new file mode 100644 index 000000000000..2eada6d9318c --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Remove/Remove.KOR.udn @@ -0,0 +1,36 @@ +INTSourceChangelist:3413824 +Availability:Docs +Title:Remove +Description:맵에서 주어진 키-값 짝을 제거합니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:7 +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_RemoveNode.png) + +**Remove** 노드는 맵에서 키-값 짝을 제거, 맵의 길이를 줄입니다. 맵에서 키-값 짝을 제거할 때, 노드는 키가 맵에 있는지 검사합니다. +키가 맵에 있지 않으면, 그 키-값 짝은 제거되지 않습니다. + +##입력 + +| 핀 위치 | 이름 | 설명 | +| ------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Map_RemoveNode_1.png) | (In) Exec | 입력 실행 핀입니다. | +| ![](Map_RemoveNode_2.png) | Target Map | 이 맵에서 키-값 짝을 제거합니다. | +| ![](Map_RemoveNode_3.png) | Key | 맵의 값 룩업에 사용되는 키입니다. [REGION:note]키-값 짝 제거를 위해서는, 키가 맵에 들어있어야 합니다.[/REGION] | + +##출력 + +| 핀 위치 | 이름 | 설명 | +| ---------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ | +| ![](Map_RemoveNode_4.png) | (Out) Exec | 출력 실행 핀입니다. | +| ![](Map_RemoveNode_5.png) | Boolean Return Value | 키-값 짝이 제거되면, 노드는 true 를 반환합니다. 그렇지 않은 경우, 맵에 제공된 키를 사용하는 값이 없으면 노드는 false 를 반환합니다. | + +##사용 예 + +![](Map_RemoveUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Values/Values.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Values/Values.CHN.udn new file mode 100644 index 000000000000..5c29161e1527 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Values/Values.CHN.udn @@ -0,0 +1,34 @@ +INTSourceChangelist:0 +Availability:Docs +Title:Values +Description:Outputs an array of all values present in the Map. +Crumbs: +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:8 +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_ValuesNode.png) + +The **Values** node outputs an Array of all values that are present in a given Map. + +##Inputs + +| Pin Location | Name | Description | +| ------------------------- | ------------- | --------------------------------------- | +| ![](Map_ValuesNode_1.png) | (In) Exec | Input execution pin. | +| ![](Map_ValuesNode_2.png) | Target Map | The Map to get an Array of values from. | + +##Outputs + +| Pin Location | Name | Description | +| -------------------------- | ----------- | --------------------------------------------------------------- | +| ![](Map_ValuesNode_3.png) | (Out) Exec | Output execution pin. | +| ![](Map_ValuesNode_4.png) | Array | An output Array, containing all of the values found in the Map. | + +##Example Usage + +![](Map_ValuesUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Values/Values.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Values/Values.INT.udn new file mode 100644 index 000000000000..673c575a3b05 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Values/Values.INT.udn @@ -0,0 +1,33 @@ +Availability:Docs +Title:Values +Description:Outputs an array of all values present in the Map. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:8 +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_ValuesNode.png) + +The **Values** node outputs an Array of all values that are present in a given Map. + +##Inputs + +| Pin Location | Name | Description | +| ------------------------- | ------------- | --------------------------------------- | +| ![](Map_ValuesNode_1.png) | (In) Exec | Input execution pin. | +| ![](Map_ValuesNode_2.png) | Target Map | The Map to get an Array of values from. | + +##Outputs + +| Pin Location | Name | Description | +| -------------------------- | ----------- | --------------------------------------------------------------- | +| ![](Map_ValuesNode_3.png) | (Out) Exec | Output execution pin. | +| ![](Map_ValuesNode_4.png) | Array | An output Array, containing all of the values found in the Map. | + +##Example Usage + +![](Map_ValuesUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Values/Values.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Values/Values.JPN.udn new file mode 100644 index 000000000000..f33f9cb8af44 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Values/Values.JPN.udn @@ -0,0 +1,34 @@ +INTSourceChangelist:3413824 +Availability:Docs +Title:Values +Description:Map に存在するすべての値の Array を出力する +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:8 +Version:4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_ValuesNode.png) + +**Values** ノードは、指定された Map に存在するすべての値の Array を出力します。 + +##入力 + +| ピンの位置 | 名前 | 説明 | +| ------------------------- | ------------- | --------------------------------------- | +| ![](Map_ValuesNode_1.png) | (In) Exec | 入力実行ピンです。 | +| ![](Map_ValuesNode_2.png) | Target Map | 値の Array の取得元となる Map です。 | + +##出力 + +| ピンの位置 | 名前 | 詳細 | +| -------------------------- | ----------- | --------------------------------------------------------------- | +| ![](Map_ValuesNode_3.png) | (Out) Exec | 出力実行ピンです。 | +| ![](Map_ValuesNode_4.png) | Array | Map 内で見つかったすべての値を含む出力 Array です。 | + +##使用例 + +![](Map_ValuesUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Values/Values.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Values/Values.KOR.udn new file mode 100644 index 000000000000..c8f0637d2709 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/MapNodes/Values/Values.KOR.udn @@ -0,0 +1,34 @@ +INTSourceChangelist:3413824 +Availability:Docs +Title:Values +Description:맵에 존재하는 모든 값 배열을 출력합니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Maps/MapNodes +Order:8 +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Map_ValuesNode.png) + +**Values** 노드는 주어진 맵에 존재하는 모든 값 배열을 출력합니다. + +##입력 + +| 핀 위치 | 이름 | 설명 | +| ------------------------- | ------------- | --------------------------------------- | +| ![](Map_ValuesNode_1.png) | (In) Exec | 입력 실행 핀입니다. | +| ![](Map_ValuesNode_2.png) | Target Map | 이 맵에서 값 배열을 구합니다. | + +##출력 + +| 핀 위치 | 이름 | 설명 | +| -------------------------- | ----------- | --------------------------------------------------------------- | +| ![](Map_ValuesNode_3.png) | (Out) Exec | 출력 실행 핀입니다. | +| ![](Map_ValuesNode_4.png) | Array | 출력 배열로, 맵에서 찾은 모든 값이 들어갑니다. | + +##사용 예 + +![](Map_ValuesUsage.png) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/Maps.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/Maps.CHN.udn new file mode 100644 index 000000000000..5c9c80db4f74 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/Maps.CHN.udn @@ -0,0 +1,202 @@ +INTSourceChangelist:0 +Availability:Docs +Title:Blueprint Maps +Description:Creating and editing Map containers, an advanced container type, in Blueprints, including an overview of this container's properties. +Crumbs:%ROOT% +Parent:Engine/Blueprints/Scripting +Order:1 +version: 4.15 +tags:Blueprint Map +tags:Blueprints +topic-image:maps_topicImage.png +SkillLevel:Advanced + +[TOC(start:1 end:2)] + +[REGION:banner] +![](maps_topicBanner.png) +[/REGION] + +With the release of Unreal Engine, version 4.15, the **Map** container type has been added to the [Blueprint Application Programming Interface (API)](https://docs.unrealengine.com/latest/INT/BlueprintAPI/) in Unreal Engine 4 (UE4). +If you're unfamiliar with the term "container"; think of a storage box, where you label items and place them inside of the box for immediate (or later) use. If you've used Arrays to store and work with collections of items, you've +already started using Blueprint containers in UE4. For example, when using Arrays to store items for later use, the item's label is its place in the array. Maps are similar to arrays in that they both use a label to indicate where +the item is located in the container, however, labels for Maps are different from those used for Arrays. When using Arrays, the label is the item's sequential index in the container, whereas, when using Maps, the label is a key that's +associated with the item in the container. Having the ability to associate items in a container with their respective keys, enables developers to harness Maps in creative ways, making Maps a great addition to the Blueprint API. + +Blueprint Maps are a wonderful addition to the Blueprint API because, after Arrays, they're a popular container in UE4. The reason that Maps are so popular is due to the fact that developers can efficiently lookup and retrieve items +with the use of associated keys. Much like Arrays and Sets, Blueprint Maps have a variety of uses when developing a game. + +As you read through this page, you'll learn how to create and edit Blueprint Maps. You'll also learn about the properties of Maps, which are being included to help you get the most out of using Maps in your game projects. + +[REGION:note] + +For illustrative purposes, we're using a **Blank Blueprint Project** (with highlighted settings) to show you how to create and edit Blueprint Maps. + +[REGION:lightbox] + [![](sampleProject.png)(w:370)](sampleProject.png) +[/REGION] + +[REGION:caption] +Click for full image. +[/REGION] + +[/REGION] + +## Creating Maps + +To create a new Blueprint Map, follow these steps. + +1. If you don't have a Blueprint Class to work from, go ahead and **Add** a new Blueprint Class to your project. + + [REGION:lightbox] + [![](creatingMaps_Step1.png)(w:600)](creatingMaps_Step1.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, select **Actor** from the list of classes being shown in the **Pick Parent Class** menu. + + ![](creatingMaps_Step2.png) + +1. After naming your Actor class, go ahead and open the newly created Actor class by double-clicking on the Actor, which is located inside of the **Content Browser**. + + [REGION:lightbox] + [![](creatingMaps_Step3.png)(w:600)](creatingMaps_Step3.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. To begin editing the Actor's Blueprint script, select the **Event Graph** tab. + + [REGION:lightbox] + [![](creatingMaps_Step4.png)(w:600)](creatingMaps_Step4.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. With the Actor's **Event Graph** open, hover your mouse cursor over the **Variables** submenu to reveal the **+ Variable** button. + + [REGION:lightbox] + [![](creatingMaps_Step5.png)(w:600)](creatingMaps_Step5.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, create a new **String** variable, naming it `MyStringIntegerMap`. + + [REGION:lightbox] + [![](creatingMaps_Step6.png)(w:600)](creatingMaps_Step6.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + Although the variable's name may seem a bit pedantic, it's worthwhile to note that the variable name, specifically `MyStringIntegerMap`, informs you that your Map will have a String-type key associated with an Integer-type value. + [/REGION] + +1. Currently, `MyStringIntegerMap` is a single **String** variable. To begin turning `MyStringIntegerMap` into **Map** container, click on the **Variable Type** button, which is on the right side of the **Variable Type** label inside of the Actor's **Details Panel**. + + [REGION:lightbox] + [![](creatingMaps_Step7.png)(w:600)](creatingMaps_Step7.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. At this point, a drop down menu will appear, showing you four container options. Select the following option to convert `MyStringIntegerMap` into a Blueprint Map: + + ![](creatingMaps_Step8.png) + +Go ahead and inspect the **Variable Type** for `MyStringIntegerMap`, verifying that the Map's key-type is a **String**, and that the value-type is an **Integer**. + +![](creatingMaps_Step9.png) + +## Editing Maps + +Before you can edit a newly created Map, you'll need to compile the Blueprint encapsulating the Map variable container. + +[REGION:lightbox] + [![](creatingMaps_Step10.png)(w:600)](creatingMaps_Step10.png) +[/REGION] + +[REGION:caption] +Click for full image. +[/REGION] + +1. To edit `MyStringIntegerMap`, click the Blueprint's **Compile** button. + + [REGION:lightbox] + [![](creatingMaps_Step11.png)(w:600)](creatingMaps_Step11.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After compiling the Blueprint, you'll notice that the Map's **Default Value** (located in the **Details** panel) shows that `MyStringIntegerMap` is empty. + + [REGION:lightbox] + [![](creatingMaps_Step12.png)(w:600)](creatingMaps_Step12.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. To add a new key-value pair to `MyStringIntegerMap`, click the **+** button, located next to **0 Map elements** in the **Default Value** menu of the **Details** panel. + + ![](creatingMaps_Step13.png) + +1. Go ahead and click the **+** button once again. + + ![](creatingMaps_Step14.png) + + [REGION:warning] + Unreal Editor will emit a warning if you try to add a key to the Blueprint Map before updating a new key-value pair's default key. + ![](Step14_Warning.png) + [/REGION] + +1. Add three key-value pairs to `MyStringIntegerMap`, matching them with the following image: + + ![](creatingMaps_Step15.png) + +1. Now, add one more key-value pair, naming the key `Banana`. + + ![](creatingMaps_Step16.png) + + [REGION:warning] + Unreal Editor will emit a warning if you try to add a duplicate key into a Blueprint Map. Although duplicate values are allowed, you cannot have duplicate keys. + ![](Step16_Warning.png) + [/REGION] + +1. With the aforementioned warning in mind, go ahead and name the fourth key `Date`, setting its value to 2. + +![](creatingMaps_Step17.png) + +Excellent work! You've just created a new Blueprint Map, having added and edited four key-value pairs. + + + +## Container Properties + +If you want to get started with using Blueprint Map containers in UE4, please refer to the following property list. + +* Keys in a Map must be unique. +* All keys in a Map must be defined (initialized). +* Currently, only single key-value pairs are supported in Blueprint Maps. +* Adding, removing, and finding values, using their associated keys in a Map, are fast operations. +* Currently, Map values are immutable, which means that they cannot be modified after they have been created. +* Although key-types may differ from value-types, all keys and values in a Map are homogeneous (of the same type). In other words, if a particular Map's key is specified as a String-type with its value specified as an Integer-type, then all subsequent keys will be Strings, and all subsequent values will be Integers. + +Now that you know how to create and edit Map containers in Blueprints, check out the [](Engine/Blueprints/UserGuide/Maps/MapNodes) reference guide to learn more about the Blueprint Map Node Interface. \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/Maps.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/Maps.INT.udn new file mode 100644 index 000000000000..2d9e27feb625 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/Maps.INT.udn @@ -0,0 +1,202 @@ +Availability:Docs +Title:Blueprint Maps +Description:Creating and editing Map containers, an advanced container type, in Blueprints, including an overview of this container's properties. +Crumbs:%ROOT% +Parent:Engine/Blueprints/Scripting +Order:1 +version: 4.15 +tags:Blueprint Map +tags:Blueprints +topic-image:maps_topicImage.png +SkillLevel:Advanced +Related:Programming/UnrealArchitecture/TMap + +[TOC(start:1 end:2)] + +[REGION:banner] +![](maps_topicBanner.png) +[/REGION] + +With the release of Unreal Engine, version 4.15, the **Map** container type has been added to the [Blueprint Application Programming Interface (API)](https://docs.unrealengine.com/latest/INT/BlueprintAPI/) in Unreal Engine 4 (UE4). +If you're unfamiliar with the term "container"; think of a storage box, where you label items and place them inside of the box for immediate (or later) use. If you've used Arrays to store and work with collections of items, you've +already started using Blueprint containers in UE4. For example, when using Arrays to store items for later use, the item's label is its place in the array. Maps are similar to arrays in that they both use a label to indicate where +the item is located in the container, however, labels for Maps are different from those used for Arrays. When using Arrays, the label is the item's sequential index in the container, whereas, when using Maps, the label is a key that's +associated with the item in the container. Having the ability to associate items in a container with their respective keys, enables developers to harness Maps in creative ways, making Maps a great addition to the Blueprint API. + +Blueprint Maps are a wonderful addition to the Blueprint API because, after Arrays, they're a popular container in UE4. The reason that Maps are so popular is due to the fact that developers can efficiently lookup and retrieve items +with the use of associated keys. Much like Arrays and Sets, Blueprint Maps have a variety of uses when developing a game. + +As you read through this page, you'll learn how to create and edit Blueprint Maps. You'll also learn about the properties of Maps, which are being included to help you get the most out of using Maps in your game projects. + +[REGION:note] + +For illustrative purposes, we're using a **Blank Blueprint Project** (with highlighted settings) to show you how to create and edit Blueprint Maps. + +[REGION:lightbox] + [![](sampleProject.png)(w:370)](sampleProject.png) +[/REGION] + +[REGION:caption] +Click for full image. +[/REGION] + +[/REGION] + +## Creating Maps + +To create a new Blueprint Map, follow these steps. + +1. If you don't have a Blueprint Class to work from, go ahead and **Add** a new Blueprint Class to your project. + + [REGION:lightbox] + [![](creatingMaps_Step1.png)(w:600)](creatingMaps_Step1.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, select **Actor** from the list of classes being shown in the **Pick Parent Class** menu. + + ![](creatingMaps_Step2.png) + +1. After naming your Actor class, go ahead and open the newly created Actor class by double-clicking on the Actor, which is located inside of the **Content Browser**. + + [REGION:lightbox] + [![](creatingMaps_Step3.png)(w:600)](creatingMaps_Step3.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. To begin editing the Actor's Blueprint script, select the **Event Graph** tab. + + [REGION:lightbox] + [![](creatingMaps_Step4.png)(w:600)](creatingMaps_Step4.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. With the Actor's **Event Graph** open, hover your mouse cursor over the **Variables** submenu to reveal the **+ Variable** button. + + [REGION:lightbox] + [![](creatingMaps_Step5.png)(w:600)](creatingMaps_Step5.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, create a new **String** variable, naming it `MyStringIntegerMap`. + + [REGION:lightbox] + [![](creatingMaps_Step6.png)(w:600)](creatingMaps_Step6.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [REGION:note] + Although the variable's name may seem a bit pedantic, it's worthwhile to note that the variable name, specifically `MyStringIntegerMap`, informs you that your Map will have a String-type key associated with an Integer-type value. + [/REGION] + +1. Currently, `MyStringIntegerMap` is a single **String** variable. To begin turning `MyStringIntegerMap` into **Map** container, click on the **Variable Type** button, which is on the right side of the **Variable Type** label inside of the Actor's **Details** panel. + + [REGION:lightbox] + [![](creatingMaps_Step7.png)(w:600)](creatingMaps_Step7.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. At this point, a drop down menu will appear, showing you four container options. Select the following option to convert `MyStringIntegerMap` into a Blueprint Map: + + ![](creatingMaps_Step8.png) + +Go ahead and inspect the **Variable Type** for `MyStringIntegerMap`, verifying that the Map's key-type is a **String**, and that the value-type is an **Integer**. + +![](creatingMaps_Step9.png) + +## Editing Maps + +Before you can edit a newly created Map, you'll need to compile the Blueprint encapsulating the Map variable container. + +[REGION:lightbox] + [![](creatingMaps_Step10.png)(w:600)](creatingMaps_Step10.png) +[/REGION] + +[REGION:caption] +Click for full image. +[/REGION] + +1. To edit `MyStringIntegerMap`, click the Blueprint's **Compile** button. + + [REGION:lightbox] + [![](creatingMaps_Step11.png)(w:600)](creatingMaps_Step11.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After compiling the Blueprint, you'll notice that the Map's **Default Value** (located in the **Details** panel) shows that `MyStringIntegerMap` is empty. + + [REGION:lightbox] + [![](creatingMaps_Step12.png)(w:600)](creatingMaps_Step12.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. To add a new key-value pair to `MyStringIntegerMap`, click the **+** button, located next to **0 Map elements** in the **Default Value** menu of the **Details** panel. + + ![](creatingMaps_Step13.png) + +1. Go ahead and click the **+** button once again. + + ![](creatingMaps_Step14.png) + + [REGION:warning] + Unreal Editor will emit a warning if you try to add a key to the Blueprint Map before updating a new key-value pair's default key. + ![](Step14_Warning.png) + [/REGION] + +1. Add three key-value pairs to `MyStringIntegerMap`, matching them with the following image: + + ![](creatingMaps_Step15.png) + +1. Now, add one more key-value pair, naming the key `Banana`. + + ![](creatingMaps_Step16.png) + + [REGION:warning] + Unreal Editor will emit a warning if you try to add a duplicate key into a Blueprint Map. Although duplicate values are allowed, you cannot have duplicate keys. + ![](Step16_Warning.png) + [/REGION] + +1. With the aforementioned warning in mind, go ahead and name the fourth key `Date`, setting its value to 2. + +![](creatingMaps_Step17.png) + +Excellent work! You've just created a new Blueprint Map, having added and edited four key-value pairs. + + + +## Container Properties + +If you want to get started with using Blueprint Map containers in UE4, please refer to the following property list. + +* Keys in a Map must be unique. +* All keys in a Map must be defined (initialized). +* Currently, only single key-value pairs are supported in Blueprint Maps. +* Adding, removing, and finding values, using their associated keys in a Map, are fast operations. +* Currently, Map values are immutable, which means that they cannot be modified after they have been created. +* Although key-types may differ from value-types, all keys and values in a Map are homogeneous (of the same type). In other words, if a particular Map's key is specified as a String-type with its value specified as an Integer-type, then all subsequent keys will be Strings, and all subsequent values will be Integers. + +Now that you know how to create and edit Map containers in Blueprints, check out the [](Engine/Blueprints/UserGuide/Maps/MapNodes) reference guide to learn more about the Blueprint Map Node Interface. \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/Maps.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/Maps.JPN.udn new file mode 100644 index 000000000000..9ba991c87fba --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/Maps.JPN.udn @@ -0,0 +1,203 @@ +INTSourceChangelist:3413824 +Availability:Docs +Title:Blueprint Maps +Description:ブループリントの高度なコンテナ タイプの Map コンテナの作成と編集、およびコンテナのプロパティの概要 +Crumbs:%ROOT% +Parent:Engine/Blueprints/Scripting +Order:1 +version:4.15 +tags:Blueprint Map +tags:Blueprints +topic-image:maps_topicImage.png +SkillLevel:Advanced +Related:Programming/UnrealArchitecture/TMap + +[TOC(start:1 end:2)] + +[REGION:banner] +![](maps_topicBanner.png) +[/REGION] + +アンリアル エンジン 4.15 がリリースされ、**Map** コンテナ タイプがアンリアル エンジン 4 (UE4) の [Blueprint Application Programming Interface (API)](https://docs.unrealengine.com/latest/INT/BlueprintAPI/) に追加されました。 +コンテナという用語を知らない場合、アイテムにラベル付けをして、すぐに (または後で) 使うために入れて置くストレージ ボックスだと考えてください。Arrays を使って格納してアイテムのコレクションを使って作業したことがあれば、 +UE4 の Blueprint コンテナを既に使っています。例えば、Array を使って後で使うアイテムを格納する場合、そのアイテムのラベルは配列内の位置になります。ラベルを使ってコンテナ内のアイテム位置を示す点で Map は Array と似ていますが、 +Map のラベルは Array で使用するラベルとは異なります。Array を使う場合、ラベルはコンテナのアイテムのシーケンス インデックスですが、 +Map の場合、ラベルはコンテナのアイテムと関連づいたキーとなります。それぞれのキーを使ってコンテナ内のアイテムを関連づけが可能なので、デベロッパーはクリエイティブな方法で Map を活用することができ、Map の追加でブループリント API のは一層パワフルになります。 + +Blueprint Maps は Array の次に UE4 では人気のあるコンテナなので、Blueprint API との相性は抜群です。デベロッパーは関連付けられたキーを使って、効率的にアイテムの検索と抽出ができるため、 +Map はとても人気があります。Array と Set と非常によくにて、Blueprint Map もゲーム開発において様々な用途があります。 + +本ページでは、Blueprint Map の作成および編集方法を学習します。プロジェクトで Map の最大限の活用に役立てるために、Map のプロパティについても説明します。 + +[REGION:note] + +図説の便宜上、**Blank Blueprint Project** (下図の黄色枠部分) を使ってBlueprint Map の作成および編集方法の説明を行います。 + +[REGION:lightbox] + [![](sampleProject.png)(w:370)](sampleProject.png) +[/REGION] + +[REGION:caption] +クリックしてフルサイズで表示 +[/REGION] + +[/REGION] + +## Map の作成 + +Blueprint Map を新規作成するには、以下の操作を行います。 + +1. 作業用 Blueprint クラスがまだない場合は、Blueprint クラスをプロジェクトに **追加** してください。 + + [REGION:lightbox] + [![](creatingMaps_Step1.png)(w:600)](creatingMaps_Step1.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **[Pick Parent Class (親クラスを選択)]** メニューに表示されているクラスリストから **[Actor]** を選択します。 + + ![](creatingMaps_Step2.png) + +1. Actor クラスに名前を付けたら、**コンテンツ ブラウザ** 内でそのアクタをダブルクリックして開きます。 + + [REGION:lightbox] + [![](creatingMaps_Step3.png)(w:600)](creatingMaps_Step3.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. そのアクタのブループリント スクリプトの編集を始めるために **[Event Graph]** タブを選択します。 + + [REGION:lightbox] + [![](creatingMaps_Step4.png)(w:600)](creatingMaps_Step4.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. アクタの **Event Graph** を開いたら、**[Variables (変数)]** サブメニュー上にカーソルをあてて **[+ Variable]** ボタンを表示させます。 + + [REGION:lightbox] + [![](creatingMaps_Step5.png)(w:600)](creatingMaps_Step5.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 次に **String** 変数を作成し、`MyStringIntegerMap` と名前を付けます。 + + [REGION:lightbox] + [![](creatingMaps_Step6.png)(w:600)](creatingMaps_Step6.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + + [REGION:note] + 変数名はやや杓子定規的な感じがしますが、変数名の `MyStringIntegerMap` の場合、Map が Integer 型の値と関連付けられた String 型キーを持つことを説明している点に注目する価値はあります。 + [/REGION] + +1. いま、`MyStringIntegerMap` は単一の **String** 変数の状態です。`MyStringIntegerMap` を **Map** コンテナに変換するには、アクタの **[Details (詳細)]** パネルの **Variable Type** ラベルの右側にある**[Variable Type (変数タイプ)] ボタンをクリックします。 + + [REGION:lightbox] + [![](creatingMaps_Step7.png)(w:600)](creatingMaps_Step7.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. ここでドロップダウン メニューの中に 4 つのコンテナ オプションが表示されます。次のオプションを選択して `MyStringIntegerMap` を Blueprint Map に変換します。 + + ![](creatingMaps_Step8.png) + +`MyStringIntegerMap` の **Variable Type** を見て、Map のキーは **String**、値は **Integer** であることを確認してください。 + +![](creatingMaps_Step9.png) + +## Map の編集 + +新規作成された Map を編集する前に、Map 変数コンテナをカプセル化するブループリントをコンパイルしなければなりません。 + +[REGION:lightbox] + [![](creatingMaps_Step10.png)(w:600)](creatingMaps_Step10.png) +[/REGION] + +[REGION:caption] +クリックしてフルサイズで表示 +[/REGION] + +1. `MyStringIntegerMap を編集するには、ブループリントの **[Compile]** ボタンをクリックします。 + + [REGION:lightbox] + [![](creatingMaps_Step11.png)(w:600)](creatingMaps_Step11.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. ブループリントをコンパイルすると、Map の **[Default Value (デフォルト値)]** (**[Details (詳細)]** パネル内) に `MyStringIntegerMap` が空であることが表示されます。 + + [REGION:lightbox] + [![](creatingMaps_Step12.png)(w:600)](creatingMaps_Step12.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. キー/ 値のペアを `MyStringIntegerMap` に追加するには、**[Details (詳細)]** パネルの **[Default Value (デフォルト値)]** メニューの **[0 Map elements]** の横にある**[+]** ボタンをクリックします。 + + ![](creatingMaps_Step13.png) + +1. **[+]** ボタンをもう一度押してください。 + + ![](creatingMaps_Step14.png) + + [REGION:warning] + キー / 値のペアのデフォルト キーを更新せずにキーを Blueprint Map に追加しようとすると、アンリアル エディタが警告を出します。 + ![](Step14_Warning.png) + [/REGION] + +1. 以下の画像と同じになるように、値 / キーのペアを 3 つ `MyStringIntegerMap` に追加します。 + + ![](creatingMaps_Step15.png) + +1. さらにキー/ 値のペアをもう 1 つ追加して、名前を `Banana` と付けます。 + + ![](creatingMaps_Step16.png) + + [REGION:warning] + 重複したキーを Blueprint Map に追加しようとすると、アンリアル エディタが警告を出します。値の重複が許されても、キーは重複できません。 + ![](Step16_Warning.png) + [/REGION] + +1. 上記の警告を念頭に置いて、4 つ目のキーに `Date` という名前を付けて、値を 2 に設定してください。 + +![](creatingMaps_Step17.png) + +よく出来ました!これで 4 つ目のキー / 値を追加および編集した Blueprint Map が新規作成されました。 + + + +## コンテナのプロパティ + +UE4 で Blueprint Map コンテナを使って作業を開始する場合は、以下のプロパティ一覧を参照してください。 + +* Map のキーはユニークでなければなりません。 +* Map のすべてのキーは定義 (初期化) されていなければなりません。 +* 現在、Blueprint Map では、キー / 値のペアは 1 つだけしかサポートしていません。 +* Map 内で関連づけられたキーを使った値のの追加、削除、検索は高速演算です。 +* 現在、Map 値は変更不可能です。つまり、作成後の変更は不可能です。 +* キー型は値型とは異なる場合がありますが、Map 内のすべてのキーと値は同じ (同じ型) です。別の言い方をすると、特定の Map のキーが Integer 型に指定された値をもつ String 型と指定された場合、後続のすべてのキーは String 型になり、後続のすべての値は Integer になります。 + +本ページではブループリントでの Map の作成および編集方法を学習しました。Blueprint Map ノード インターフェースの詳細は、[](Engine/Blueprints/UserGuide/Maps/MapNodes) リファレンス ガイドを参照してください。 \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/Maps.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/Maps.KOR.udn new file mode 100644 index 000000000000..89705328599a --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Maps/Maps.KOR.udn @@ -0,0 +1,203 @@ +INTSourceChangelist:3413824 +Availability:Docs +Title:블루프린트 맵 +Description:블루프린트의 고급 컨테이너 유형인 Map, 맵 컨테이너 생성 및 편집 방법을 포함해서 이 컨테이너의 프로퍼티 개요입니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/Scripting +Order:1 +version: 4.15 +tags:Blueprint Map +tags:Blueprints +topic-image:maps_topicImage.png +SkillLevel:Advanced +Related:Programming/UnrealArchitecture/TMap + +[TOC(start:1 end:2)] + +[REGION:banner] +![](maps_topicBanner.png) +[/REGION] + +언리얼 엔진 4.15 버전 릴리즈 이후 언리얼 엔진 4 (UE4) 의 [Blueprint Application Programming Interface (API)](https://docs.unrealengine.com/latest/INT/BlueprintAPI/) 에 **Map** (맵) 컨테이너 유형이 추가되었습니다. +"컨테이너" 라는 용어는, 보관 상자같은 것에 아이템 라벨을 붙인 뒤 박스 안에 넣어두고 바로 (아니면 나중에) 사용하는 것을 말합니다. 배열을 사용하여 아이템 콜렉션을 저장 및 작업을 해 봤다면, +이미 UE4 에서 블루프린트 컨테이너 사용을 해 본 것입니다. 예를 들어 배열로 나중에 사용할 아이템을 저장하면 아이템의 라벨은 배열에 있는 것입니다. 맵이나 배열이나 둘 다 라벨을 사용하여 아이템이 컨테이너 어디에 있는지 나타내지만, +맵의 라벨은 배열의 라벨과 다릅니다. 배열을 사용하면 라벨은 아이템의 컨테이너 내 순차 인덱스를 말하는 반면, 맵을 사용하면 라벨은 컨테이너의 아이템에 할당된 키를 말합니다. +맵은 컨테이너의 아이템과 각자의 키를 할당할 수 있는 기능 덕에 창의적인 활용이 가능하여, 블루프린트 API 의 유용한 기능이 됩니다. + +블루프린트 맵은 블루프린트 API 의 멋진 추가 기능입니다. 배열 이후로 UE4 의 인기있는 컨테이너 역할을 하기 때문입니다. 맵의 인기가 그렇게 좋은 이유는, 개발자들이 할당된 키를 사용하여 효율적으로 아이템을 찾아보고 구해올 +수 있다는 사실 때문입니다. 배열이나 세트와 마찬가지로 블루프린트 맵 역시 게임 개발 시 활용도가 높습니다. + +이 글을 통해 블루프린트 맵 생성 몇 편집 방법에 대해 배우게 될 것입니다. 블루프린트 맵의 프로퍼티에 대한 설명 역시 게임 프로젝트에 맵을 최대한 활용하는 데 +도움이 될 것입니다. + +[REGION:note] + +데모 목적 상 (아래 세팅을 적용한) **공백 블루프린트 프로젝트** 를 사용하여 블루프린트 맵 생성 및 편집 방법을 보여드리고 있습니다. + +[REGION:lightbox] + [![](sampleProject.png)(w:370)](sampleProject.png) +[/REGION] + +[REGION:caption] +클릭하면 원본 이미지를 확인합니다. +[/REGION] + +[/REGION] + +## 맵 생성 + +블루프린트 맵을 새로 생성하는 방법은 다음과 같습니다. + +1. 작업할 블루프린트 클래스가 없는 경우, **신규 추가** 버튼으로 새 블루프린트 클래스를 프로젝트에 추가합니다. + + [REGION:lightbox] + [![](creatingMaps_Step1.png)(w:600)](creatingMaps_Step1.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 이제 **부모 클래스 선택** 메뉴에 표시되는 클래스 목록에서 **Actor** 를 선택합니다. + + ![](creatingMaps_Step2.png) + +1. 액터 클래스 이름을 지은 후, 계속해서 **콘텐츠 브라우저** 안에 새로 생성된 액터 클래스를 더블 클릭하여 엽니다. + + [REGION:lightbox] + [![](creatingMaps_Step3.png)(w:600)](creatingMaps_Step3.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 액터의 블루프린트 스크립트 편집을 시작하려면, **이벤트 그래프** 탭을 선택합니다. + + [REGION:lightbox] + [![](creatingMaps_Step4.png)(w:600)](creatingMaps_Step4.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 액터의 **이벤트 그래프** 가 열린 상태로 마우스 커서를 **변수** 서브메뉴에 올리면 **+ 변수** 버튼이 드러납니다. + + [REGION:lightbox] + [![](creatingMaps_Step5.png)(w:600)](creatingMaps_Step5.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 새로운 **String** 변수를 생성하고 이름을 `MyStringSet` 라 합니다. + + [REGION:lightbox] + [![](creatingMaps_Step6.png)(w:600)](creatingMaps_Step6.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + + [REGION:note] + 변수 이름이 약간 규칙에 얽매이는 것 같아 보일 수는 있지만, `MyStringIntegerMap` 과 같은 식으로 변수 이름을 지어 놓으면 맵은 스트링 유형의 키에 인티저 유형 값이 할당된다는 정보를 줄 수 있습니다. + [/REGION] + +1. 현재 `MyStringSet` 은 단일 **String** 변수입니다. `MyStringSet` 를 **Set** 컨테이너로 변환하려면, 액터의 **디테일 패널** 내 **Variable Type** (변수 유형) 라벨 오른편에 위치한 **Variable Type** (변수 유형) 버튼을 클릭합니다. + + [REGION:lightbox] + [![](creatingMaps_Step7.png)(w:600)](creatingMaps_Step7.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 나타나는 드롭다운 메뉴에 네 가지 컨테이너 옵션이 표시됩니다. **{ }** 옵션을 선택하면 `MyStringIntegerMap` 가 블루프린트 맵으로 변환됩니다. + + ![](creatingMaps_Step8.png) + +계속해서 `MyStringIntegerMap` 의 **Variable Type** 을 조사하여 맵의 키 유형이 **String** 인지, 값 유형이 **Integer** 인지 확인합니다. + +![](creatingMaps_Step9.png) + +## 세트 편집 + +새로 생성된 맵 편집을 하려면, Map 변수 컨테이너를 캡슐화시킨 블루프린트를 컴파일해야 합니다. + +[REGION:lightbox] + [![](creatingMaps_Step10.png)(w:600)](creatingMaps_Step10.png) +[/REGION] + +[REGION:caption] +클릭하면 원본 이미지를 확인합니다. +[/REGION] + +1. `MyStringIntegerMap` 를 편집하려면, 블루프린트의 **컴파일** 버튼을 클릭합니다. + + [REGION:lightbox] + [![](creatingMaps_Step11.png)(w:600)](creatingMaps_Step11.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 블루프린트를 컴파일한 이후 Map 의 (**디테일** 패널에 위치한) **Default Value** (기본 값)에 `MyStringIntegerMap` 이 공백임을 알 수 있습니다. + + [REGION:lightbox] + [![](creatingMaps_Step12.png)(w:600)](creatingMaps_Step12.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 새로운 String 엘리먼트를 `MyStringIntegerMap` 에 추가하려면, **디테일** 패널 **Default Value** 메뉴의 **0 Set elements** 옆에 위치한 **+** 버튼을 클릭합니다. + + ![](creatingMaps_Step13.png) + +1. 계속해서 **+** 버튼을 다시 한 번 누릅니다. + + ![](creatingMaps_Step14.png) + + [REGION:warning] + 새로운 엘리먼트의 기본 값을 업데이트하기 전 블루프린트 맵에 엘리먼트를 추가하려 하면 언리얼 에디터에서 경고가 날 것입니다. + ![](Step14_Warning.png) + [/REGION] + +1. `MyStringIntegerMap` 에 키-값 짝을 셋 추가하고, 다음 그림과 같이 맞춥니다. + + ![](creatingMaps_Step15.png) + +1. 이제 키-값 짝을 하나 더 추가하고, 키 이름을 `Banana` 라 합니다. + + ![](creatingMaps_Step16.png) + + [REGION:warning] + 블루프린트 맵에 중복 키를 추가하려 하면 언리얼 에디터 경고가 납니다. 중복 값이 허용은 되지만, 중복 키는 안됩니다. + ![](Step16_Warning.png) + [/REGION] + +1. 앞서 말한 경고를 염두에 두고, 계속해서 네 번째 키 `Date`, 그 값은 2 로 설정합니다. + +![](creatingMaps_Step17.png) + +잘 하셨습니다! 지금까지 새로운 블루프린트 맵을 새로 만들고 키-값 짝을 넷 추가 및 편집했습니다. + + +## 컨테이너 프로퍼티 + +UE4 에서 블루프린트 Map 사용을 시작하려면 다음 프로퍼티 목록을 참고하세요. + +* 맵의 키는 고유해야 합니다. +* 맵의 모든 키는 정의(초기화)되어야 합니다. +* 현재 블루프린트 맵에는 단일 키-값 짝만 지원됩니다. +* 맵에 할당된 키를 사용한 값 추가, 제거, 검색 작업은 빠릅니다. +* 현재 맵 값은 변경불가(immutable)합니다. 생성한 후에는 변경할 수 없다는 뜻입니다. +* 키 유형은 값 유형과 다를 수 있지만, 한 맵의 모든 키는 성질(유형)이 같아야 합니다. 다른 말로 특정 맵의 키가 스트링 유형, 그 값은 인티저 유형으로 지정된 경우, 잇따르는 모든 키 역시 스트링, 값은 인티저가 될 것입니다. + +블루프린트에서 맵을 생성 및 편집하는 법을 배웠으니, [](Engine/Blueprints/UserGuide/Maps/MapNodes) 참고서에서 블루프린트 Map 노드 인터페이스에 대해 더욱 자세히 배워보실 수 있습니다. diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/PatchingNodes/MobilePatchUtilities.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/PatchingNodes/MobilePatchUtilities.CHN.udn index 94ccadf3f7f3..555fa497ed14 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/PatchingNodes/MobilePatchUtilities.CHN.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/PatchingNodes/MobilePatchUtilities.CHN.udn @@ -1,107 +1,95 @@ -INTSourceChangelist:0 -Availability:Docs -Title:Mobile Patch Utility Nodes -Crumbs: %ROOT%, Engine, Engine/Blueprints, Engine/Blueprints/UserGuide -Description:Describes the different kinds of Mobile Patch Utility Blueprint nodes. -Related: Engine/Blueprints -Related: Platforms/Mobile -Related: Platforms/Mobile/MobilePackagingWizard -version: 4.14 +INTSourceChangelist:3339919 +Availability:Public +Title:移动补丁工具节点 +Crumbs: +Description:介绍不同类型的移动补丁工具蓝图节点。 +Related:Engine/Blueprints +Related:Platforms/Mobile +Related:Platforms/Mobile/MobilePackagingWizard +version:4.14 Parent:Engine/Blueprints type:overview +tags:Blueprints +skilllevel:Intermediate +topic-image:Patching_Topic.png [TOC (start:2 end:2)] -After using the [](Platforms/Mobile/MobilePackagingWizard) to create a small initial download for your mobile project, you also need to be able to provide the rest of your project in downloadable chunks to the user. -The new Mobile Patch Utilities Blueprint library contains all the functionality required to allow a mobile game to download and install game content and patches from a cloud website instead of being -distributed as part of the initial download from the App Store. There is functionality to determine if updated game content is available, initiate the download, track progress, handle any errors, and -finally install the content paks that are downloaded successfully. Functionality to check for sufficient storage space and WiFi connectivity is also available, so you can warn the user in such cases. -Both Android and iOS are supported. +使用 [](Platforms/Mobile/MobilePackagingWizard) 为移动项目创建小型初始下载后,还需要以可下载数据块的方式将项目的剩余内容提供给用户。全新的移动补丁工具蓝图库包含移动游戏从云端网站下载并安装游戏内容和补丁(而非从 App Store 上进行初始下载)的所有必备功能。这些功能可确定是否有更新游戏内容、开始下载、跟踪进程、处理错误,并在最后安装成功下载的内容包。此外还包含检查存储空间和 WiFi 连接的功能,以便在这些情况下提醒用户。支持 Android 和 iOS。 [REGION:tip] -To show these functions in context with each other, example setups are presented here. -If a function or event in the Blueprint graph examples isn't listed in a table below, then it is a custom node you would need to create in your own project as well. +为展示这些函数之间的上下文关系,此处展示设置范例。 +如蓝图图表范例中的函数或事件未列于下表中,则需要为您自己的项目创建自定义节点。 [/REGION] -## Working with Pending Content +## 使用待定内容 [REGION:lightbox] [![](Patching_1.png)(convert:false)](Patching_1.png) [/REGION] -This is the first stage of the patching process. When patching is initiated, either from a level load or a user action, content needs to be requested from the remote server using the **Request Content** node. -In this example, the install directory is saved off in a variable, but it could also be passed through as function inputs. The **Content To Install** is also saved into a variable for reuse later. -When the content request is complete, different events will be executed depending on whether the request succeeded or failed. Custom events are used as inputs for the **Request Content** function. -The **Check Download Space** function shown here is calling a custom event that starts off the next set of patching logic. +这是补丁流程的第一步。补丁开始时,需要使用 **Request Content** 节点从远程服务器请求内容(通过关卡加载或用户行为)。在此例中,安装目录保存在一个变量中,但其也可作为函数输入进行传递。**Content To Install** 同样保存在一个变量中,以便之后使用。内容请求完成后,将请求的成功或失败执行不同事件。自定义事件用作 **Request Content** 函数的输入。此处显示的 **Check Download Space** 函数将调用一个自定义事件,开始补丁逻辑的下一套内容。 -| Node | Description | +| 节点 | 描述 | | --- | --- | -| Request Content | Attempts to download a manifest file using the specified manifest URL. On success, it will return an object that represents the remote content. This object can be queried for additional information, like total content size, download size, etc. The user can choose to download and install remote content. | +| Request Content | 尝试使用特定的 manifest URL 下载一个 manifest 文件。成功后,它将返回一个代表远程内容的对象。可查询此对象的更多信息,如内容总大小、下载大小,等等。用户可选择下载并安装远程内容。| [REGION:lightbox] [![](Patching_2.png)(convert:false)](Patching_2.png) [/REGION] -After requesting the remote content succeeds, the next step is to verify that there is enough space for the download using the **Get Required Disk Space** node and comparing the result to the result from **Get Disk Free Space**. -If the required disk space is less than the disk free space, then a custom event is called to start the download. +请求远程内容成功后,下一步是使用 **Get Required Disk Space** 节点确保有足够空间进行下载,并将结果与 **Get Disk Free Space** 的结果进行对比。如所需的磁盘空间小于剩余磁盘空间,则调用自定义事件开始下载。 -| Node | Description | +| 节点 | 描述 | | --- | --- | -| Get Disk Free Space | Gets the disk free space in megabytes where content is installed (or will be installed). | -| Get Required Disk Space | Gets the required disk space in megabytes for this content installation. | +| Get Disk Free Space | 获取内容安装(或即将进行安装)路径的剩余磁盘空间(以 MB 为单位)。| +| Get Required Disk Space | 获取此内容安装所需的磁盘空间(以 MB 为单位)。| [REGION:lightbox] [![](Patching_3.png)(convert:false)](Patching_3.png) [/REGION] -Although there is a lot going on in this graph, the only Mobile Patch Utility function is **Start Install**, which actually attempts to download and install the remote content. Just like **Request Content**, **Start Install** has -event parameters for success and failure. If the install succeeds, the **Mount Content** custom event is used to trigger the final stage of the patching process. Another custom event, **Display Download State** is fired off here -with a timer. Using the timer and the **Update Download State** function, the download state can be shown to the user at regular intervals. More on that logic is in the next Blueprint graph. +虽然此图表中有大量内容,但唯一的移动补丁工具函数是 **Start Install**,它将尝试下载并安装远程内容。和 **Request Content** 一样,**Start Install** 拥有成功和失败的事件参数。如安装成功,则使用 **Mount Content** 自定义事件触发补丁流程的最终部分。此时将触发另一个带定时器的自定义事件 **Mount Content**。使用定时器和 **Update Download State** 函数,下载状态可以固定间隔向用户展示。此逻辑的更多内容在下一个蓝图图表中。 -| Node | Description | +| 节点 | 描述 | | --- | --- | -| Start Install | Attempts to download and install remote content. The user can choose to mount the installed content into the game. | +| Start Install | 尝试下载并安装远程内容。用户可选择将安装内容装入游戏中。| [REGION:lightbox] ![](Patching_4.png) [/REGION] -While the **Display Download State** custom event is connected to a **Format Text** node here, this could also be the stage of the patching process where you fill a progress bar on the UI, or other methods of -displaying progress to the user. Here, the outputs of **Get Download Size**, **Get Download Speed**, **Get Download Status Text**, **Get Install Progress**, and **Get Total Downloaded Size** nodes are -put together in a simple text block to present to the user. This script is called at regular intervals with the timer, but does not call back to any of the other example graphs. +**Display Download State** 自定义事件连接到 **Format Text** 节点,用户可在补丁流程的这个阶段中在 UI(用户界面)上填入进度条,或显示进度的其他方法。**Get Download Size**、**Get Download Speed**、**Get Download Status Text**、**Get Install Progress** 和 **Get Total Downloaded Size** 节点的输出在此组合为一个简单文本段,向用户呈现。此脚本随定时器以固定间隔调用,但并不回叫到任何其他范例图表。 -| Node | Description | +| 节点 | 描述 | | --- | --- | -| Get Download Size | Gets the total download size for this content installation. | -| Get Download Speed | Gets the current download speed in megabytes per second. Valid during installation. | -| Get Download Status Text | Gets the current installation status text. Valid during installation. | -| Get Install Progress | Gets the current installation progress. The result is between 0 and 1 for known progress, or less than 0 for unknown progress. | -| Get Total Downloaded Size | Gets the total downloaded size in megabytes. Valid during installation. | +| Get Download Size | 获取此安装内容的总下载大小。| +| Get Download Speed | 获取当前的下载速度(以 MB/秒为单位)安装中有效。| +| Get Download Status Text | 获取当前的安装状态文本。安装中有效。| +| Get Install Progress | 获取当前的安装进度。已知进度的结果在 0 和 1 之间,未知进度的结果小于 0。| +| Get Total Downloaded Size | 获取已下载的总大小(以 MB 为单位)。安装中有效。| -## Working with Installed Content +## 使用安装内容 [REGION:lightbox] ![](Patching_5.png) [/REGION] -The last stage of the patching process is to mount the content. We are using the stored **Install Directory** variable from the first Blueprint graph, but this could again be passed through as a function input. -The **Get Installed Content** node is used to look up the content from that directory, and then the **Mount** function mounts it into the game. Unlike **Request Content** and **Start Install**, **Mount** -does not have success and failure event callbacks. +补丁流程的最后阶段是装入内容。我们使用的是第一个蓝图图表容纳的 **Install Directory** 变量,但这也可作为函数输入进行传递。**Get Installed Content** 节点用于从目录中寻找内容,然后 **Mount** 函数将把内容装入游戏。与 **Request Content** 和 **Start Install** 不同的是,**Mount** 没有成功和失败的事件回调。 -| Node | Description | +| 节点 | 描述 | | --- | --- | -| Get Installed Content | Gets the installed content. This will return a non-null object if there is installed content in the specified directory. The user can choose to mount installed content into the game. | -| Mount | Mounts installed content. | +| Get Installed Content | 获取安装的内容。如指定目录中有安装内容,此节点将返回一个非空对象。用户可选择将安装内容装入游戏。| +| Mount | 装入安装内容。| -## Other Mobile Patching Functions +## 其他移动补丁函数 -The above graphs are a simple example of how to set up patching on a mobile device, but there are other, more complex, behaviors you could set up as well. For example, you could have your game warn users when they don't have -an active wi fi connection, or provide different content for iOS and Android devices. For these use cases and others, the below functions would be useful additions to your Blueprints. +上方的图表是如何在移动设备上设置补丁的简单范例,但也能设置其他复杂行为。例如可设置游戏在无可用 WiFi 连接时提醒用户,或为 iOS 和 Android 设备提供不同内容。针对这些以及其他使用情况,将以下函数添加到蓝图将有所帮助。 -| Node | Description | +| 节点 | 描述 | | --- | --- | -| Get Active Device Profile Name | Gets the name of currently selected device profile name. | -| Get Installed Content Size | Gets the installed content size in megabytes | -| Get Supported Platform Names | Gets the list of supported platform names on this device. Example: Android_ETC2, Android_ASTC | -| Has Active Wi Fi Connection | Returns whether or not a WiFi connection is currently available. | - \ No newline at end of file +| Get Active Device Profile Name | 获取当前选中的设备配置文件命名。| +| Get Installed Content Size | 获取安装内容的大小(以 MB 为单位)| +| Get Supported Platform Names | 获取此设备上支持平台名的列表。范例:Android_ETC2, Android_ASTC | +| Has Active WiFi Connection | 返回当前是否存在可用 WiFi 连接。| + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Add/Add.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Add/Add.CHN.udn new file mode 100644 index 000000000000..c09e7c90d849 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Add/Add.CHN.udn @@ -0,0 +1,37 @@ +INTSourceChangelist:0 +Availability:Docs +Title:Add +Description:Adds an item to a Set. +Crumbs: +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order:1 +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_AddNode.png) + +The **Add** node adds an item to a Set, thereby increasing the length of the Set. When adding an item to a Set, the node checks whether the added item is equal to an existing item in the Set. +If the new item is equal to an item that's already in the Set, the new item won't be added. + +##Inputs + +| Pin Location | Name | Description | +| ---------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Set_AddNode_1.png) | (In) Exec | Input execution pin. | +| ![](Set_AddNode_2.png) | Target Set | The Set that you want to add a new item to. | +| ![](Set_AddNode_3.png) | New Item | The item that you want to add to the Set. [REGION:note]The new item needs to be unique from existing items that are contained in the Set.[/REGION] | + +##Outputs + +| Pin Location | Name | Description | +| ---------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| ![](Set_AddNode_4.png) | (Out) Exec | Output execution pin. | +| ![](Set_AddNode_5.png) | Boolean Return Value | If an equivalent item was present, the node returns false. Otherwise, if the new item was successfully added to the Set, this node returns true. | + +##Example Usage + +![](Set_AddUsage.png) + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Add/Add.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Add/Add.INT.udn new file mode 100644 index 000000000000..8eedd43f4df2 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Add/Add.INT.udn @@ -0,0 +1,36 @@ +Availability:Docs +Title:Add +Description:Adds an item to a Set. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order:1 +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_AddNode.png) + +The **Add** node adds an item to a Set, thereby increasing the length of the Set. When adding an item to a Set, the node checks whether the added item is equal to an existing item in the Set. +If the new item is equal to an item that's already in the Set, the new item won't be added. + +##Inputs + +| Pin Location | Name | Description | +| ---------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Set_AddNode_1.png) | (In) Exec | Input execution pin. | +| ![](Set_AddNode_2.png) | Target Set | The Set that you want to add a new item to. | +| ![](Set_AddNode_3.png) | New Item | The item that you want to add to the Set. [REGION:note]The new item needs to be unique from existing items that are contained in the Set.[/REGION] | + +##Outputs + +| Pin Location | Name | Description | +| ---------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| ![](Set_AddNode_4.png) | (Out) Exec | Output execution pin. | +| ![](Set_AddNode_5.png) | Boolean Return Value | If an equivalent item was present, the node returns false. Otherwise, if the new item was successfully added to the Set, this node returns true. | + +##Example Usage + +![](Set_AddUsage.png) + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Add/Add.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Add/Add.JPN.udn new file mode 100644 index 000000000000..6a8f30b95afa --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Add/Add.JPN.udn @@ -0,0 +1,37 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:Add +Description:アイテムを Set に追加する +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order:1 +Version:4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_AddNode.png) + +**Add** ノードはアイテムを Set に追加します。これにより、Set の長さが増加します。アイテムを Set に追加すると、追加されたアイテムは Set 内の既存アイテムと同じかどうかをこのノードがチェックします。 +新規アイテムが Set 内の既存アイテムと同じであれば、この新規アイテムは追加されません。 + +##入力 + +| ピンの位置 | 名前 | 説明 | +| ---------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Set_AddNode_1.png) | (In) Exec | 入力実行ピン | +| ![](Set_AddNode_2.png) | Target Set | 新規アイテムの追加先にしたい Set | +| ![](Set_AddNode_3.png) | New Item | Set に追加したいアイテム。[REGION:note]新規アイテムは Set に含まれている既存アイテムとは異なる必要があります。[/REGION] | + +##出力 + +| ピンの位置 | 名前 | 説明 | +| ---------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| ![](Set_AddNode_4.png) | (Out) Exec | 出力実行ピン | +| ![](Set_AddNode_5.png) | Boolean Return Value | 同じノードが存在すると、このノードは false を返します。新規アイテムが正常に Set に追加されると、このノードは true を返します。 | + +##使用例 + +![](Set_AddUsage.png) + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Add/Add.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Add/Add.KOR.udn new file mode 100644 index 000000000000..f1169cc52347 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Add/Add.KOR.udn @@ -0,0 +1,37 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:Add +Description:세트에 아이템을 추가합니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order:1 +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_AddNode.png) + +**Add** 노드는 세트에 아이템을 추가, 세트 길이를 늘립니다. 세트에 아이템을 추가할 때, 노드는 추가된 아이템이 세트의 기존 아이템과 같은지 검사합니다. +새로운 아이템이 세트에 이미 있는 아이템과 같은 경우, 새로운 아이템은 추가되지 않습니다. + +##입력 + +| 핀 위치 | 이름 | 설명 | +| ---------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Set_AddNode_1.png) | (In) Exec | 입력 실행 핀입니다. | +| ![](Set_AddNode_2.png) | Target Set | 이 세트에 새로운 아이템을 추가합니다. | +| ![](Set_AddNode_3.png) | New Item | 세트에 추가하려는 아이템입니다. [REGION:note]새로운 아이템은 세트에 들어있는 기존 아이템과 구분되는 고유한 것이어야 합니다.[/REGION] | + +##출력 + +| 핀 위치 | 이름 | 설명 | +| ---------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| ![](Set_AddNode_4.png) | (Out) Exec | 출력 실행 핀입니다. | +| ![](Set_AddNode_5.png) | Boolean Return Value | 동등한 아이템이 존재한 경우, 노드는 false 를 반환합니다. 존재하지 않은 경우, 새 아이템이 세트에 성공적으로 추가되면 true 를 반환합니다. | + +##사용 예 + +![](Set_AddUsage.png) + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/AddItems/AddItems.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/AddItems/AddItems.CHN.udn new file mode 100644 index 000000000000..534d5a8e2654 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/AddItems/AddItems.CHN.udn @@ -0,0 +1,36 @@ +INTSourceChangelist:0 +Availability:Docs +Title:Add Items +Description:Adds items from a specified Array to a Set. +Crumbs: +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_AddItemsNode.png) + +The **Add Items** node copies items from an Array into a Set, thereby increasing the length of the Set. When adding items to a Set, the node checks whether the added items are equal to existing items in the Set. +If a new item from the Array is equal to an item that's already in the Set, the new item won't be added; conversely, unique items from the Array will be added to the Set. + +##Inputs + +| Pin Location | Name | Description | +| --------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Set_AddItemsNode_1.png) | (In) Exec | Input execution pin. | +| ![](Set_AddItemsNode_2.png) | Target Set | The Set that you want to add items to. | +| ![](Set_AddItemsNode_3.png) | New Items | An Array of items that you want to add to the Set. [REGION:note]New items need to be unique from existing items that are contained in the Set.[/REGION] | + +##Outputs + +| Pin Location | Name | Description | +| --------------------------- | ----------- | --------------------- | +| ![](Set_AddItemsNode_4.png) | (Out) Exec | Output execution pin. | + +##Example Usage + +![](Set_AddItemsUsage.png) + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/AddItems/AddItems.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/AddItems/AddItems.INT.udn new file mode 100644 index 000000000000..0821d33b245f --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/AddItems/AddItems.INT.udn @@ -0,0 +1,35 @@ +Availability:Docs +Title:Add Items +Description:Adds items from a specified Array to a Set. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_AddItemsNode.png) + +The **Add Items** node copies items from an Array into a Set, thereby increasing the length of the Set. When adding items to a Set, the node checks whether the added items are equal to existing items in the Set. +If a new item from the Array is equal to an item that's already in the Set, the new item won't be added; conversely, unique items from the Array will be added to the Set. + +##Inputs + +| Pin Location | Name | Description | +| --------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Set_AddItemsNode_1.png) | (In) Exec | Input execution pin. | +| ![](Set_AddItemsNode_2.png) | Target Set | The Set that you want to add items to. | +| ![](Set_AddItemsNode_3.png) | New Items | An Array of items that you want to add to the Set. [REGION:note]New items need to be unique from existing items that are contained in the Set.[/REGION] | + +##Outputs + +| Pin Location | Name | Description | +| --------------------------- | ----------- | --------------------- | +| ![](Set_AddItemsNode_4.png) | (Out) Exec | Output execution pin. | + +##Example Usage + +![](Set_AddItemsUsage.png) + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/AddItems/AddItems.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/AddItems/AddItems.JPN.udn new file mode 100644 index 000000000000..2b2cdf0315bc --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/AddItems/AddItems.JPN.udn @@ -0,0 +1,36 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:アイテムを追加する +Description:特定の Array からアイテムを Set に追加する方法 +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version:4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_AddItemsNode.png) + +**Add Items** ノードは、アイテムを Array から Set へコピーします。これにより、Set の長さが増加します。アイテムを Set に追加すると、追加されたアイテムは Set 内の既存アイテムと同じかどうかをこのノードがチェックします。 +Array からの新規アイテムが Set 内の既存アイテムと同じであれば、この新規アイテムは追加されません。逆に、Array からのアイテムがユニークであれば Set に追加されます。 + +##入力 + +| ピンの位置 | 名前 | 説明 | +| --------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Set_AddItemsNode_1.png) | (In) Exec | 入力実行ピンです。 | +| ![](Set_AddItemsNode_2.png) | Target Set | アイテムの追加先にしたい Set です。 | +| ![](Set_AddItemsNode_3.png) | New Items | Set に追加したいアイテムの Array です。[REGION:note]新規アイテムは Set に含まれている既存アイテムとは異なる必要があります。[/REGION] | + +##出力 + +| ピンの位置 | 名前 | 説明 | +| --------------------------- | ----------- | --------------------- | +| ![](Set_AddItemsNode_4.png) | (Out) Exec | 出力実行ピンです。 | + +##使用例 + +![](Set_AddItemsUsage.png) + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/AddItems/AddItems.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/AddItems/AddItems.KOR.udn new file mode 100644 index 000000000000..dd4245a0c3e9 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/AddItems/AddItems.KOR.udn @@ -0,0 +1,36 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:Add Items +Description:지정된 배열의 아이템을 세트에 추가합니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_AddItemsNode.png) + +**Add Items** 노드는 배열에서 아이템을 복사하여, 세트 길이를 늘립니다. 세트에 아이템을 추가할 때, 노드는 추가된 아이템이 세트의 기존 아이템과 같은지 검사합니다. +배열의 새 아이템이 세트에 이미 있는 아이템과 같은 경우, 새 아이템은 추가되지 않습니다. 역으로, 배열의 고유 아이템이 세트에 추가됩니다. + +##입력 + +| 핀 위치 | 이름 | 설명 | +| --------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Set_AddItemsNode_1.png) | (In) Exec | 입력 실행 핀입니다. | +| ![](Set_AddItemsNode_2.png) | Target Set | 이 세트에 아이템을 추가합니다. | +| ![](Set_AddItemsNode_3.png) | New Items | 세트에 추가하고자 하는 아이템 배열입니다. [REGION:note]새 아이템은 세트에 들어있는 기존 아이템과 다른 고유한 것이어야 합니다.[/REGION] | + +##출력 + +| 핀 위치 | 이름 | 설명 | +| --------------------------- | ----------- | --------------------- | +| ![](Set_AddItemsNode_4.png) | (Out) Exec | 출력 실행 핀입니다. | + +##사용 예 + +![](Set_AddItemsUsage.png) + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Clear/Clear.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Clear/Clear.CHN.udn new file mode 100644 index 000000000000..50319b69fb16 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Clear/Clear.CHN.udn @@ -0,0 +1,33 @@ +INTSourceChangelist:0 +Availability:Docs +Title:Clear +Description:Clears all items from a Set. +Crumbs: +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_ClearNode.png) + +The **Clear** node removes all of the items from a given Set, removing all of the Set's contents. Subsequently, the Set's length will be reset to zero. + +##Inputs + +| Pin Location | Name | Description | +| ------------------------ | ----------- | ------------------------------------------ | +| ![](Set_ClearNode_1.png) | (In) Exec | Input execution pin. | +| ![](Set_ClearNode_2.png) | Target Set | The Set that you want to clear items from. | + +##Outputs + +| Pin Location | Name | Description | +| ------------------------ | ----------- | --------------------- | +| ![](Set_ClearNode_3.png) | (Out) Exec | Output execution pin. | + +##Example Usage + +![](Set_ClearUsage.png) diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Clear/Clear.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Clear/Clear.INT.udn new file mode 100644 index 000000000000..7d165b3b7426 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Clear/Clear.INT.udn @@ -0,0 +1,32 @@ +Availability:Docs +Title:Clear +Description:Clears all items from a Set. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_ClearNode.png) + +The **Clear** node removes all of the items from a given Set, removing all of the Set's contents. Subsequently, the Set's length will be reset to zero. + +##Inputs + +| Pin Location | Name | Description | +| ------------------------ | ----------- | ------------------------------------------ | +| ![](Set_ClearNode_1.png) | (In) Exec | Input execution pin. | +| ![](Set_ClearNode_2.png) | Target Set | The Set that you want to clear items from. | + +##Outputs + +| Pin Location | Name | Description | +| ------------------------ | ----------- | --------------------- | +| ![](Set_ClearNode_3.png) | (Out) Exec | Output execution pin. | + +##Example Usage + +![](Set_ClearUsage.png) diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Clear/Clear.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Clear/Clear.JPN.udn new file mode 100644 index 000000000000..9886c0694abe --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Clear/Clear.JPN.udn @@ -0,0 +1,33 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:Clear +Description:Set からすべてのアイテムをクリアする +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version:4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_ClearNode.png) + +**Clear** ノードは、Set のコンテンツのすべてを削除して、所定の Set からすべてのアイテムを除去します。結果、Set の長さはゼロにリセットされます。 + +##入力 + +| ピンの位置 | 名前 | 説明 | +| ------------------------ | ----------- | ------------------------------------------ | +| ![](Set_ClearNode_1.png) | (In) Exec | 入力実行ピンです。 | +| ![](Set_ClearNode_2.png) | Target Set | クリアしたいアイテムが入っている Set です。 | + +##出力 + +| ピンの位置 | 名前 | 説明 | +| ------------------------ | ----------- | --------------------- | +| ![](Set_ClearNode_3.png) | (Out) Exec | 出力実行ピンです。 | + +##使用例 + +![](Set_ClearUsage.png) diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Clear/Clear.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Clear/Clear.KOR.udn new file mode 100644 index 000000000000..0ca0f657c467 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Clear/Clear.KOR.udn @@ -0,0 +1,33 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:Clear +Description:세트의 모든 아이템을 지웁니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_ClearNode.png) + +**Clear** 노드는 주어진 세트에서 모든 아이템을 제거, 세트의 내용물을 전부 지웁니다. 그에 따라 세트의 길이는 0 으로 리셋됩니다. + +##입력 + +| 핀 위치 | 이름 | 설명 | +| ------------------------ | ----------- | ------------------------------------------ | +| ![](Set_ClearNode_1.png) | (In) Exec | 입력 실행 핀입니다. | +| ![](Set_ClearNode_2.png) | Target Set | 이 세트의 아이템을 지웁니다. | + +##출력 + +| 핀 위치 | 이름 | 설명 | +| ------------------------ | ----------- | --------------------- | +| ![](Set_ClearNode_3.png) | (Out) Exec | 출력 실행 핀입니다. | + +##사용 예 + +![](Set_ClearUsage.png) diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/ContainsItem/ContainsItem.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/ContainsItem/ContainsItem.CHN.udn new file mode 100644 index 000000000000..87d7a2bb794e --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/ContainsItem/ContainsItem.CHN.udn @@ -0,0 +1,34 @@ +INTSourceChangelist:0 +Availability:Docs +Title:Contains Item +Description:Checks to see if a Set contains an item. +Crumbs: +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_ContainsNode.png) + +The **Contains Item** node searches a Set for your item, returning true if the Set contains the item. + +##Inputs + +| Pin Location | Name | Description | +| --------------------------- | ------------- | --------------------------------- | +| ![](Set_ContainsNode_1.png) | Target Set | The Set that you want to search. | +| ![](Set_ContainsNode_2.png) | Item to Find | The item that you're looking for. | + +##Outputs + +| Pin Location | Name | Description | +| --------------------------- | --------------------- | ------------------------------------------------------------- | +| ![](Set_ContainsNode_3.png) | Boolean Return Value | If the node finds the item in the Set, the node returns true. | + +##Example Usage + +![](Set_ContainsUsage.png) + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/ContainsItem/ContainsItem.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/ContainsItem/ContainsItem.INT.udn new file mode 100644 index 000000000000..3972c9fbc8fa --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/ContainsItem/ContainsItem.INT.udn @@ -0,0 +1,33 @@ +Availability:Docs +Title:Contains Item +Description:Checks to see if a Set contains an item. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_ContainsNode.png) + +The **Contains Item** node searches a Set for your item, returning true if the Set contains the item. + +##Inputs + +| Pin Location | Name | Description | +| --------------------------- | ------------- | --------------------------------- | +| ![](Set_ContainsNode_1.png) | Target Set | The Set that you want to search. | +| ![](Set_ContainsNode_2.png) | Item to Find | The item that you're looking for. | + +##Outputs + +| Pin Location | Name | Description | +| --------------------------- | --------------------- | ------------------------------------------------------------- | +| ![](Set_ContainsNode_3.png) | Boolean Return Value | If the node finds the item in the Set, the node returns true. | + +##Example Usage + +![](Set_ContainsUsage.png) + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/ContainsItem/ContainsItem.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/ContainsItem/ContainsItem.JPN.udn new file mode 100644 index 000000000000..97aaf8bc866a --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/ContainsItem/ContainsItem.JPN.udn @@ -0,0 +1,34 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:Contains Item +Description:Set にアイテムが含まれているかチェックする +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version:4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_ContainsNode.png) + +**Contains Item** ノードは Set でアイテムの検索をします。その Set にアイテムが入っていれば true を返します。 + +##入力 + +| ピンの位置 | 名前 | 説明 | +| --------------------------- | ------------- | --------------------------------- | +| ![](Set_ContainsNode_1.png) | Target Set | 検索先の Set です。 | +| ![](Set_ContainsNode_2.png) | Item to Find | 検索したいアイテムです。 | + +##出力 + +| ピンの位置 | 名前 | 説明 | +| --------------------------- | --------------------- | ------------------------------------------------------------- | +| ![](Set_ContainsNode_3.png) | Boolean Return Value | ノードが Set 内でアイテムを見つけると true を返します。 | + +##使用例 + +![](Set_ContainsUsage.png) + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/ContainsItem/ContainsItem.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/ContainsItem/ContainsItem.KOR.udn new file mode 100644 index 000000000000..950dc64f60b3 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/ContainsItem/ContainsItem.KOR.udn @@ -0,0 +1,34 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:Contains Item +Description:세트에 아이템이 들어있는지 검사합니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_ContainsNode.png) + +**Contains Item** 노드는 세트에서 아이템을 검색, 세트에 그 아이템이 있으면 true 를 반환합니다. + +##입력 + +| 핀 위치 | 이름 | 설명 | +| --------------------------- | ------------- | --------------------------------- | +| ![](Set_ContainsNode_1.png) | Target Set | 이 세트에서 검색합니다. | +| ![](Set_ContainsNode_2.png) | Item to Find | 찾고자 하는 아이템입니다. | + +##출력 + +| 핀 위치 | 이름 | 설명 | +| --------------------------- | --------------------- | ------------------------------------------------------------- | +| ![](Set_ContainsNode_3.png) | Boolean Return Value | 노드가 세트에서 아이템을 찾으면, 노드는 true 를 반환합니다. | + +##사용 예 + +![](Set_ContainsUsage.png) + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Difference/Difference.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Difference/Difference.CHN.udn new file mode 100644 index 000000000000..e225136cb795 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Difference/Difference.CHN.udn @@ -0,0 +1,58 @@ +INTSourceChangelist:0 +Availability:Docs +Title:Difference +Description:Takes the relative difference of two Sets, assigning the difference to a resultant Set. +Crumbs: +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_DifferenceNode.png) + +The **Difference** node takes the relative difference of items found in two Sets, assigning the difference to a Resultant Set, with the result containing all items found in Set A but not found in Set B. +It's important to note that the relative difference between two Sets is not a commutative operation, which means that if you want to preserve the elements in Set A, you'll want to pin Set A to the to pin, +making Set A the first parameter of the Difference operation. Visually, the difference between Set A and Set B looks like the following diagram, where Set A contains all of the items that are being preserved. + +![](Set_DifferenceDiagram.png) + +For illustrative purposes, let's say that you have two string type Sets, Set A and Set B, both of which are defined below. + + Set A = {"Item 1", "Item 2", "Item 3", "Item 4", "Item 5"} + Set B = {"Item 4", "Item 5", "Item 6", "Item 7", "Item 8"} + +The following table shows you the result, which contains the relative difference between Set A and Set B (symbolically represented as **A \ B**). + +| --------- | --------- | ------------------------- | +| **Set A** | **Set B** | **Resultant Set (A \ B)** | +| `Item 1` | `Item 4` | `Item 1` | +| `Item 2` | `Item 5` | `Item 2` | +| `Item 3` | `Item 6` | `Item 3` | +| `Item 4` | `Item 7` | | +| `Item 5` | `Item 8` | | + +##Inputs + +| Pin Location | Name | Description | +| ----------------------------- | ----------- | ----------------------------------------------- | +| ![](Set_DifferenceNode_1.png) | (In) Exec | Input execution pin. | +| ![](Set_DifferenceNode_2.png) | A | Set A is the starting Set. | +| ![](Set_DifferenceNode_3.png) | B | Set B is the Set of items to remove from Set A. | + +##Outputs + +| Pin Location | Name | Description | +| ----------------------------- | ----------- | -------------------------------------------------------------------------- | +| ![](Set_DifferenceNode_4.png) | (Out) Exec | Output execution pin. | +| ![](Set_DifferenceNode_5.png) | Result | The Set containing all of the items in Set A, which aren't found in Set B. | + +##Example Usage + +![](Set_DifferenceUsage.png) + +####Footnote + +Symbolically, this operation is represented as A \ B = { x | x ∈ A ∧ x ∉ B }, wherein this node is performing a logical AND operation between elements in Set A and elements not in Set B. \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Difference/Difference.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Difference/Difference.INT.udn new file mode 100644 index 000000000000..a3f90627a7f1 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Difference/Difference.INT.udn @@ -0,0 +1,59 @@ +Availability:Docs +Title:Difference +Description:Takes the relative difference of two Sets, assigning the difference to a resultant Set. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_DifferenceNode.png) + +The **Difference** node takes the relative difference of items found in two Sets, assigning the difference to a Resultant Set, with the result containing all items found in Set A but not found in Set B. +It's important to note that the relative difference between two Sets is not a commutative operation. Visually, the difference between Set A and Set B looks like the following diagram, where Set A contains +all of the items that are being preserved. + +[REGION:raw] +![](Set_DifferenceDiagram.png) +[/REGION] + +For illustrative purposes, let's say that you have two string type Sets, Set A and Set B, both of which are defined below. + + Set A = {"Item 1", "Item 2", "Item 3", "Item 4", "Item 5"} + Set B = {"Item 4", "Item 5", "Item 6", "Item 7", "Item 8"} + +The following table shows you the result, which contains the relative difference between Set A and Set B (symbolically represented as **A \ B**). + +| --------- | --------- | ------------------------- | +| **Set A** | **Set B** | **Resultant Set (A \ B)** | +| `Item 1` | `Item 4` | `Item 1` | +| `Item 2` | `Item 5` | `Item 2` | +| `Item 3` | `Item 6` | `Item 3` | +| `Item 4` | `Item 7` | | +| `Item 5` | `Item 8` | | + +##Inputs + +| Pin Location | Name | Description | +| ----------------------------- | ----------- | ----------------------------------------------- | +| ![](Set_DifferenceNode_1.png) | (In) Exec | Input execution pin. | +| ![](Set_DifferenceNode_2.png) | A | Set A is the starting Set. | +| ![](Set_DifferenceNode_3.png) | B | Set B is the Set of items to remove from Set A. | + +##Outputs + +| Pin Location | Name | Description | +| ----------------------------- | ----------- | -------------------------------------------------------------------------- | +| ![](Set_DifferenceNode_4.png) | (Out) Exec | Output execution pin. | +| ![](Set_DifferenceNode_5.png) | Result | The Set containing all of the items in Set A, which aren't found in Set B. | + +##Example Usage + +![](Set_DifferenceUsage.png) + +####Footnote + +Symbolically, this operation is represented as A \ B = { x | x ∈ A ∧ x ∉ B }, wherein this node is performing a logical AND operation between elements in Set A and elements not in Set B. \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Difference/Difference.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Difference/Difference.JPN.udn new file mode 100644 index 000000000000..2701761e0ed9 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Difference/Difference.JPN.udn @@ -0,0 +1,60 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:Difference +Description:2 つの Set の相対差を取り、それを Resultant Set に割り当てる +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version:4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_DifferenceNode.png) + +**Difference** ノードは 2 つの Set に含まれるアイテムの相対差を取り、その差を Resultant Set に割り当てて、Set A にあって Set B にはないすべてのアイテムが入るようにします。 +2 つの Set の相対差は可換演算でないことに注意することが重要です。Set A が維持しているアイテムをすべて含んでいる場合、 +Set A と Set B の差を図で表すと以下のようになります。 + +[REGION:raw] +![](Set_DifferenceDiagram.png) +[/REGION] + +解説しやすいように、それぞれ以下のように定義される Set A と Set B という 2 つのストリング型があるとしましょう。 + + Set A = {"Item 1", "Item 2", "Item 3", "Item 4", "Item 5"} + Set B = {"Item 4", "Item 5", "Item 6", "Item 7", "Item 8"} + +は以下の表は、Set A and Set B の相対差が含まれる結果を表します (記号で表すと **A \ B**)。 + +| --------- | --------- | ------------------------- | +| **Set A** | **Set B** | **Resultant Set (A \ B)** | +| `Item 1` | `Item 4` | `Item 1` | +| `Item 2` | `Item 5` | `Item 2` | +| `Item 3` | `Item 6` | `Item 3` | +| `Item 4` | `Item 7` | | +| `Item 5` | `Item 8` | | + +##入力 + +| ピンの位置 | 名前 | 説明 | +| ----------------------------- | ----------- | ----------------------------------------------- | +| ![](Set_DifferenceNode_1.png) | (In) Exec | 入力実行ピンです。 | +| ![](Set_DifferenceNode_2.png) | A | Set A が比較元です。 | +| ![](Set_DifferenceNode_3.png) | B | Set B は Set A から削除するアイテムの Set です。 | + +##出力 + +| ピンの位置 | 名前 | 説明 | +| ----------------------------- | ----------- | -------------------------------------------------------------------------- | +| ![](Set_DifferenceNode_4.png) | (Out) Exec | 出力実行ピンです。 | +| ![](Set_DifferenceNode_5.png) | Result | Set B には含まれていない Set A のすべてのアイテムが含まれる Set です。 | + +##使用例 + +![](Set_DifferenceUsage.png) + +####補足説明 + +この演算を記号で表すと A \ B = { x | x ∈ A ∧ x ∉ B } となり、このノードは、Set A のエレメントと Set B にはないエレメントの間で論理 AND 演算を実行します。 \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Difference/Difference.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Difference/Difference.KOR.udn new file mode 100644 index 000000000000..8bef791a38b9 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Difference/Difference.KOR.udn @@ -0,0 +1,60 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:Difference +Description:두 세트의 상대적 차이를 구해, 그 차이를 결과 세트에 할당합니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_DifferenceNode.png) + +**Difference** 노드는 두 세트에서 찾은 아이템의 상대적 차이를 구해, Resultant Set 에 할당합니다. 이 결과 세트에는 Set A 에는 있지만 Set B 에는 없는 모든 아이템이 포함됩니다. +한 가지 중요한 점은, 두 세트의 상대적 차이는 가환 연산이 아니라는 점입니다. 시각적으로 Set A 와 Set B 사이 차이점은 다음 도표와 같아 보이는데, +Set A 에 보존되는 모든 아이템이 들어있는 것입니다. + +[REGION:raw] +![](Set_DifferenceDiagram.png) +[/REGION] + +설명을 위해 아래와 같이 정의된 스트링 유형 Set A 와 Set B 두 세트가 있다 칩시다. + + Set A = {"Item 1", "Item 2", "Item 3", "Item 4", "Item 5"} + Set B = {"Item 4", "Item 5", "Item 6", "Item 7", "Item 8"} + +다음 표에서 결과를 확인할 수 있는데, Set A 와 Set B 사이 상대적 차이를 나타냅니다 (심볼로는 **A \ B** 로 나타냅니다). + +| --------- | --------- | ------------------------- | +| **Set A** | **Set B** | **Resultant Set (A \ B)** | +| `Item 1` | `Item 4` | `Item 1` | +| `Item 2` | `Item 5` | `Item 2` | +| `Item 3` | `Item 6` | `Item 3` | +| `Item 4` | `Item 7` | | +| `Item 5` | `Item 8` | | + +##입력 + +| 핀 위치 | 이름 | 설명 | +| ----------------------------- | ----------- | ----------------------------------------------- | +| ![](Set_DifferenceNode_1.png) | (In) Exec | 입력 실행 핀입니다. | +| ![](Set_DifferenceNode_2.png) | A | Set A 는 시작 세트입니다. | +| ![](Set_DifferenceNode_3.png) | B | Set B 는 Set A 에서 제거할 아이템 세트입니다. | + +##출력 + +| 핀 위치 | 이름 | 설명 | +| ----------------------------- | ----------- | -------------------------------------------------------------------------- | +| ![](Set_DifferenceNode_4.png) | (Out) Exec | 출력 실행 핀입니다. | +| ![](Set_DifferenceNode_5.png) | Result | Set A 에는 있지만 Set B 에는 없는 모든 아이템이 들어있는 세트입니다. | + +##사용 예 + +![](Set_DifferenceUsage.png) + +####사족 + +이 연산을 심볼로 나타내면 A \ B = { x | x ∈ A ∧ x ∉ B } 인데, 이 노드는 Set A 에 있는 엘리먼트와 Set B 에 없는 엘리먼트 사이에 논리 AND 연산을 하고 있는 것입니다. \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Intersection/Intersection.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Intersection/Intersection.CHN.udn new file mode 100644 index 000000000000..87f2d55c49ee --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Intersection/Intersection.CHN.udn @@ -0,0 +1,61 @@ +INTSourceChangelist:0 +Availability:Docs +Title:Intersection +Description:Takes the intersection of two Sets, assigning the intersection to a resultant Set. +Crumbs: +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_IntersectionNode.png) + +The **Intersection** node takes the intersection of items found in two Sets, assigning the intersection to a Resultant Set, with the result containing items in Set A that also belong to Set B. +Visually, the intersection of Set A and Set B looks like the following diagram, where the intersection of Set A and Set B contains only those items that are common to both Sets. + +![](Set_IntersectionDiagram.png) + +For illustrative purposes, let's say that you have two string type Sets, Set A and Set B, both of which are defined below. + + Set A = {"Item 1", "Item 2", "Item 3", "Item 4", "Item 5"} + Set B = {"Item 4", "Item 5", "Item 6", "Item 7", "Item 8"} + +The following table shows you the result, which contains the intersection of Set A and Set B (symbolically represented as **A ∩ B**). + +| --------- | --------- | -------------------------------- | +| **Set A** | **Set B** | **Resultant Set (A ∩ B)** | +| `Item 1` | `Item 4` | `Item 4` | +| `Item 2` | `Item 5` | `Item 5` | +| `Item 3` | `Item 6` | | +| `Item 4` | `Item 7` | | +| `Item 5` | `Item 8` | | + +[REGION:note] +When intersecting a Set with an Empty Set, use the [](Engine/Blueprints/UserGuide/Sets/SetNodes/Clear) node. +[/REGION] + +##Inputs + +| Pin Location | Name | Description | +| ------------------------------- | ----------- | --------------------------- | +| ![](Set_IntersectionNode_1.png) | (In) Exec | Input execution pin. | +| ![](Set_IntersectionNode_2.png) | A | One Set to intersect. | +| ![](Set_IntersectionNode_3.png) | B | The other Set to intersect. | + +##Outputs + +| Pin Location | Name | Description | +| ------------------------------- | ----------- | ---------------------------------------------- | +| ![](Set_IntersectionNode_4.png) | (Out) Exec | Output execution pin. | +| ![](Set_IntersectionNode_5.png) | Result | The Set containing the resultant intersection. | + +##Example Usage + +![](Set_IntersectionUsage.png) + +#### Footnote + +Symbolically, this operation is represented as A ∩ B = { x | x ∈ A ∧ x ∈ B }, wherein this node is performing a logical AND operation between elements in Set A and elements in Set B. \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Intersection/Intersection.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Intersection/Intersection.INT.udn new file mode 100644 index 000000000000..f571ef499f2c --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Intersection/Intersection.INT.udn @@ -0,0 +1,62 @@ +Availability:Docs +Title:Intersection +Description:Takes the intersection of two Sets, assigning the intersection to a resultant Set. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_IntersectionNode.png) + +The **Intersection** node takes the intersection of items found in two Sets, assigning the intersection to a Resultant Set, with the result containing items in Set A that also belong to Set B. +Visually, the intersection of Set A and Set B looks like the following diagram, where the intersection of Set A and Set B contains only those items that are common to both Sets. + +[REGION:raw] +![](Set_IntersectionDiagram.png) +[/REGION] + +For illustrative purposes, let's say that you have two string type Sets, Set A and Set B, both of which are defined below. + + Set A = {"Item 1", "Item 2", "Item 3", "Item 4", "Item 5"} + Set B = {"Item 4", "Item 5", "Item 6", "Item 7", "Item 8"} + +The following table shows you the result, which contains the intersection of Set A and Set B (symbolically represented as **A ∩ B**). + +| --------- | --------- | -------------------------------- | +| **Set A** | **Set B** | **Resultant Set (A ∩ B)** | +| `Item 1` | `Item 4` | `Item 4` | +| `Item 2` | `Item 5` | `Item 5` | +| `Item 3` | `Item 6` | | +| `Item 4` | `Item 7` | | +| `Item 5` | `Item 8` | | + +[REGION:note] +When intersecting a Set with an Empty Set, use the [](Engine/Blueprints/UserGuide/Sets/SetNodes/Clear) node. +[/REGION] + +##Inputs + +| Pin Location | Name | Description | +| ------------------------------- | ----------- | --------------------------- | +| ![](Set_IntersectionNode_1.png) | (In) Exec | Input execution pin. | +| ![](Set_IntersectionNode_2.png) | A | One Set to intersect. | +| ![](Set_IntersectionNode_3.png) | B | The other Set to intersect. | + +##Outputs + +| Pin Location | Name | Description | +| ------------------------------- | ----------- | ---------------------------------------------- | +| ![](Set_IntersectionNode_4.png) | (Out) Exec | Output execution pin. | +| ![](Set_IntersectionNode_5.png) | Result | The Set containing the resultant intersection. | + +##Example Usage + +![](Set_IntersectionUsage.png) + +#### Footnote + +Symbolically, this operation is represented as A ∩ B = { x | x ∈ A ∧ x ∈ B }, wherein this node is performing a logical AND operation between elements in Set A and elements in Set B. \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Intersection/Intersection.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Intersection/Intersection.JPN.udn new file mode 100644 index 000000000000..9f364b119874 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Intersection/Intersection.JPN.udn @@ -0,0 +1,63 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:Intersection +Description:2 つの Set の共通部分を取り、それを Resultant Set に割り当てる +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version:4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_IntersectionNode.png) + +**Intersection** ノードは 2 つの Set に含まれるアイテムの交通部分を取り、その差を Resultant Set に割り当てて、Set A に含まれていて Set B にも含まれているアイテムが入るようにします。 +Set A と Set B の共通部分を図で表すと以下のようになります。この場合、Set A と Set B の共通部分は両方の Set に共通するアイテムのみ含まれます。 + +[REGION:raw] +![](Set_IntersectionDiagram.png) +[/REGION] + +解説しやすいように、それぞれ以下のように定義される Set A と Set B という 2 つのストリング型があるとしましょう。 + + Set A = {"Item 1", "Item 2", "Item 3", "Item 4", "Item 5"} + Set B = {"Item 4", "Item 5", "Item 6", "Item 7", "Item 8"} + +は以下の表は、Set A and Set B の共通部分が含まれる結果を表します (記号で表すと **A ∩ B**)。 + +| --------- | --------- | -------------------------------- | +| **Set A** | **Set B** | **Resultant Set (A ∩ B)** | +| `Item 1` | `Item 4` | `Item 4` | +| `Item 2` | `Item 5` | `Item 5` | +| `Item 3` | `Item 6` | | +| `Item 4` | `Item 7` | | +| `Item 5` | `Item 8` | | + +[REGION:note] +Set に Empty Set との共通部分を持たせるには、[](Engine/Blueprints/UserGuide/Sets/SetNodes/Clear) ノードを使います。 +[/REGION] + +##入力 + +| ピンの位置 | 名前 | 説明 | +| ------------------------------- | ----------- | --------------------------- | +| ![](Set_IntersectionNode_1.png) | (In) Exec | 入力実行ピンです。 | +| ![](Set_IntersectionNode_2.png) | A | 共通部分をなす一方の Set です。 | +| ![](Set_IntersectionNode_3.png) | B | 共通部分をなすもう一方の Set です。 | + +##出力 + +| ピンの位置 | 名前 | 説明 | +| ------------------------------- | ----------- | ---------------------------------------------- | +| ![](Set_IntersectionNode_4.png) | (Out) Exec | 出力実行ピンです。 | +| ![](Set_IntersectionNode_5.png) | Result | 共通部分の結果を含む Set です。 | + +##使用例 + +![](Set_IntersectionUsage.png) + +####補足説明 + +この演算を記号で表すと A ∩ B = { x | x ∈ A ∧ x ∈ B } となり、このノードは、Set A のエレメントと Set B のエレメントの間で論理 AND 演算を実行します。 \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Intersection/Intersection.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Intersection/Intersection.KOR.udn new file mode 100644 index 000000000000..57a01959a5a7 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Intersection/Intersection.KOR.udn @@ -0,0 +1,63 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:Intersection +Description:두 세트의 교집합을 구해 결과 세트에 할당합니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_IntersectionNode.png) + +**Intersection** 노드는 두 세트에 있는 아이템 교집합을 구하여 Resultant Set 에 할당합니다. Set A 에 속하면서 Set B 에도 속하는 아이템을 말합니다. +Set A 와 Set B 의 교집합을 시각적으로 나타내면 다음 도표와 같으며, Set A 와 Set B 의 교집합에는 양쪽 세트에 공통인 아이템만 들어있습니다. + +[REGION:raw] +![](Set_IntersectionDiagram.png) +[/REGION] + +예시를 위해 두 개의 스트링 유형 세트 Set A 와 Set B 가 있는데, 아래와 같이 정의되어 있습니다. + + Set A = {"Item 1", "Item 2", "Item 3", "Item 4", "Item 5"} + Set B = {"Item 4", "Item 5", "Item 6", "Item 7", "Item 8"} + +그 결과는 다음 표와 같습니다. Set A 와 Set B 의 교집합입니다 (심볼로는 **A ∩ B** 로 나타냅니다). + +| --------- | --------- | -------------------------------- | +| **Set A** | **Set B** | **Resultant Set (A ∩ B)** | +| `Item 1` | `Item 4` | `Item 4` | +| `Item 2` | `Item 5` | `Item 5` | +| `Item 3` | `Item 6` | | +| `Item 4` | `Item 7` | | +| `Item 5` | `Item 8` | | + +[REGION:note] +공백 세트로 교집합을 구할 때는, [](Engine/Blueprints/UserGuide/Sets/SetNodes/Clear) 노드를 사용하세요. +[/REGION] + +##입력 + +| 핀 위치 | 이름 | 설명 | +| ------------------------------- | ----------- | --------------------------- | +| ![](Set_IntersectionNode_1.png) | (In) Exec | 입력 실행 핀입니다. | +| ![](Set_IntersectionNode_2.png) | A | 교집합 한 쪽입니다. | +| ![](Set_IntersectionNode_3.png) | B | 교집합 다른 쪽입니다. | + +##출력 + +| 핀 위치 | 이름 | 설명 | +| ------------------------------- | ----------- | ---------------------------------------------- | +| ![](Set_IntersectionNode_4.png) | (Out) Exec | 출력 실행 핀입니다. | +| ![](Set_IntersectionNode_5.png) | Result | 결과 교집합이 들어있는 세트입니다. | + +##사용 예 + +![](Set_IntersectionUsage.png) + +#### 사족 + +이 연산을 심볼로 표시하면 A ∩ B = { x | x ∈ A ∧ x ∈ B } 인데, 이 노드는 Set A 의 엘리먼트와 Set B 의 엘리먼트에 대해 논리 AND 연산을 수행하는 것입니다. \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Length/Length.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Length/Length.CHN.udn new file mode 100644 index 000000000000..13e5f1a59003 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Length/Length.CHN.udn @@ -0,0 +1,33 @@ +INTSourceChangelist:0 +Availability:Docs +Title:Length +Description:Gets the number of items (length) in a Set. +Crumbs: +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_LengthNode.png) + +The **Length** node gets the number of items in a given Set. + +##Inputs + +| Pin Location | Name | Description | +| ------------------------- | ----------- | ------------------------------------------- | +| ![](Set_LengthNode_1.png) | Target Set | The Set that you want to get the length of. | + +##Outputs + +| Pin Location | Name | Description | +| ------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------ | +| ![](Set_LengthNode_2.png) | Integer Return Value | The length of the Set. In other words, the length is the number of items that were counted in the Set. | + +##Example Usage + +![](Set_LengthUsage.png) + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Length/Length.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Length/Length.INT.udn new file mode 100644 index 000000000000..4c07489c4dd6 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Length/Length.INT.udn @@ -0,0 +1,32 @@ +Availability:Docs +Title:Length +Description:Gets the number of items (length) in a Set. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_LengthNode.png) + +The **Length** node gets the number of items in a given Set. + +##Inputs + +| Pin Location | Name | Description | +| ------------------------- | ----------- | ------------------------------------------- | +| ![](Set_LengthNode_1.png) | Target Set | The Set that you want to get the length of. | + +##Outputs + +| Pin Location | Name | Description | +| ------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------ | +| ![](Set_LengthNode_2.png) | Integer Return Value | The length of the Set. In other words, the length is the number of items that were counted in the Set. | + +##Example Usage + +![](Set_LengthUsage.png) + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Length/Length.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Length/Length.JPN.udn new file mode 100644 index 000000000000..c9d4f2c55b73 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Length/Length.JPN.udn @@ -0,0 +1,33 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:Length +Description:Set のアイテム数 (長さ) を取得する +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version:4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_LengthNode.png) + +**Length** ノードは所定の Set のアイテム数を取得します。 + +##入力 + +| ピンの位置 | 名前 | 説明 | +| ------------------------- | ----------- | ------------------------------------------- | +| ![](Set_LengthNode_1.png) | Target Set | 長さを取得したい Set です。 | + +##出力 + +| ピンの位置 | 名前 | 説明 | +| ------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------ | +| ![](Set_LengthNode_2.png) | Integer Return Value | その Set の長さです。長さは別の言い方をすると、その Set の中に含まれているアイテム数です。 + +##使用例 + +![](Set_LengthUsage.png) + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Length/Length.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Length/Length.KOR.udn new file mode 100644 index 000000000000..a062fa453e40 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Length/Length.KOR.udn @@ -0,0 +1,33 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:Length +Description:세트의 아이템 수, 즉 길이를 구합니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_LengthNode.png) + +**Length** 노드는 주어진 세트의 아이템 수를 구합니다. + +##입력 + +| 핀 위치 | 이름 | 설명 | +| ------------------------- | ----------- | ------------------------------------------- | +| ![](Set_LengthNode_1.png) | Target Set | 길이를 구하고자 하는 세트입니다. | + +##출력 + +| 핀 위치 | 이름 | 설명 | +| ------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------ | +| ![](Set_LengthNode_2.png) | 세트 길이입니다. 다른 말로 길이란 세트에서 셀 수 있는 아이템의 수입니다.| + +##사용 예 + +![](Set_LengthUsage.png) + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Remove/Remove.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Remove/Remove.CHN.udn new file mode 100644 index 000000000000..db9c83c26ee1 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Remove/Remove.CHN.udn @@ -0,0 +1,37 @@ +INTSourceChangelist:0 +Availability:Docs +Title:Remove +Description:Removes an item from a Set. +Crumbs: +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_RemoveNode.png) + +The **Remove** node removes an item from a Set, thereby decreasing the length of the Set. When removing an item from a Set, the node checks whether the item is in the Set. +If the item isn't in the Set, the item won't be removed. + +##Inputs + +| Pin Location | Name | Description | +| ------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------- | +| ![](Set_RemoveNode_1.png) | (In) Exec | Input execution pin. | +| ![](Set_RemoveNode_2.png) | Target Set | The Set that you want to remove the item from. | +| ![](Set_RemoveNode_3.png) | New Item | The item that you want to remove from the Set. [REGION:note]Before an item can be removed from a Set, it must exist.[/REGION] | + +##Outputs + +| Pin Location | Name | Description | +| ------------------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| ![](Set_RemoveNode_4.png) | (Out) Exec | Output execution pin. | +| ![](Set_RemoveNode_5.png) | Boolean Return Value | If the item was removed, this node returns true. Otherwise, if an equivalent item wasn't found in the set, this node returns false. | + +##Example Usage + +![](Set_RemoveUsage.png) + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Remove/Remove.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Remove/Remove.INT.udn new file mode 100644 index 000000000000..0861df0aef93 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Remove/Remove.INT.udn @@ -0,0 +1,36 @@ +Availability:Docs +Title:Remove +Description:Removes an item from a Set. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_RemoveNode.png) + +The **Remove** node removes an item from a Set, thereby decreasing the length of the Set. When removing an item from a Set, the node checks whether the item is in the Set. +If the item isn't in the Set, the item won't be removed. + +##Inputs + +| Pin Location | Name | Description | +| ------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------- | +| ![](Set_RemoveNode_1.png) | (In) Exec | Input execution pin. | +| ![](Set_RemoveNode_2.png) | Target Set | The Set that you want to remove the item from. | +| ![](Set_RemoveNode_3.png) | New Item | The item that you want to remove from the Set. [REGION:note]Before an item can be removed from a Set, it must exist.[/REGION] | + +##Outputs + +| Pin Location | Name | Description | +| ------------------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| ![](Set_RemoveNode_4.png) | (Out) Exec | Output execution pin. | +| ![](Set_RemoveNode_5.png) | Boolean Return Value | If the item was removed, this node returns true. Otherwise, if an equivalent item wasn't found in the set, this node returns false. | + +##Example Usage + +![](Set_RemoveUsage.png) + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Remove/Remove.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Remove/Remove.JPN.udn new file mode 100644 index 000000000000..f43e23b4f182 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Remove/Remove.JPN.udn @@ -0,0 +1,37 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:Remove +Description:Set からアイテムを除去する +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version:4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_RemoveNode.png) + +**Remove** ノードは Set からアイテムを除去します。これにより、Set の長さが減少します。アイテムを Set から除去する時に、そのアイテムが Set 内にあるかチェックします。 +Set 内になければ、とのアイテムは除去されません。 + +##入力 + +| ピンの位置 | 名前 | 説明 | +| ------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------- | +| ![](Set_RemoveNode_1.png) | (In) Exec | 入力実行ピンです。 | +| ![](Set_RemoveNode_2.png) | Target Set | 除去したいアイテムが入っている Set です。 | +| ![](Set_RemoveNode_3.png) | New Item | Set から除去したいアイテムです。[REGION:note]Set から除去する前に、終了していなければなりません。[/REGION] | + +##出力 + +| ピンの位置 | 名前 | 説明 | +| ------------------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| ![](Set_RemoveNode_4.png) | (Out) Exec | 出力実行ピンです。 | +| ![](Set_RemoveNode_5.png) | Boolean Return Value | アイテムが Set から削除されると true を返します。Set 内に同じアイテムが見つからない場合、False を返します。 | + +##使用例 + +![](Set_RemoveUsage.png) + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Remove/Remove.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Remove/Remove.KOR.udn new file mode 100644 index 000000000000..b091d2ce73d0 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Remove/Remove.KOR.udn @@ -0,0 +1,37 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:Remove +Description:세트에서 아이템을 제거합니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_RemoveNode.png) + +**Remove** 노드는 세트에서 아이템을 제거하여, 세트 길이를 줄입니다. 세트에서 아이템을 제거하면, 노드는 세트에 아이템이 있는지 검사합니다. +아이템이 세트에 있지 않으면, 아이템은 제거되지 않습니다. + +##입력 + +| 핀 위치 | 이름 | 설명 | +| ------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------- | +| ![](Set_RemoveNode_1.png) | (In) Exec | 입력 실행 핀입니다.| +| ![](Set_RemoveNode_2.png) | Target Set | 이 세트에서 아이템을 제거합니다. | +| ![](Set_RemoveNode_3.png) | New Item | 세트에서 제거하고자 하는 아이템입니다. [REGION:note]세트에서 아이템을 제거하려면, 반드시 존재해야 합니다.[/REGION] | + +##출력 + +| 핀 위치 | 이름 | 설명 | +| ------------------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| ![](Set_RemoveNode_4.png) | (Out) Exec | 출력 실행 핀입니다. | +| ![](Set_RemoveNode_5.png) | Boolean Return Value | 아이템이 제거되면, 이 노드는 true 를 반환합니다. 그렇지 않은 경우, 동등한 아이템을 세트에서 찾지 못한 경우, 이 노드는 false 를 반환합니다. | + +##사용 예 + +![](Set_RemoveUsage.png) + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/RemoveItems/RemoveItems.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/RemoveItems/RemoveItems.CHN.udn new file mode 100644 index 000000000000..b45f85f2d1fc --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/RemoveItems/RemoveItems.CHN.udn @@ -0,0 +1,36 @@ +INTSourceChangelist:0 +Availability:Docs +Title:Remove Items +Description:Removes items specified in an Array from a Set. +Crumbs: +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_RemoveItemsNode.png) + +The **Remove Items** node removes Array items from a Set, thereby decreasing the length of the Set. When removing items from a Set, the node checks whether the items are equal to existing items in the Set. +If an item from the Array is equal to an item that's already in the Set, the item will be removed. + +##Inputs + +| Pin Location | Name | Description | +| ------------------------------ | ----------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Set_RemoveItemsNode_1.png) | (In) Exec | Input execution pin. | +| ![](Set_RemoveItemsNode_2.png) | Target Set | The Set that you want to remove items from. | +| ![](Set_RemoveItemsNode_3.png) | New Items | An Array of items that you want to remove from the Set. [REGION:note]Before an item can be removed from a Set, it must exist.[/REGION] | + +##Outputs + +| Pin Location | Name | Description | +| ------------------------------ | ----------- | --------------------- | +| ![](Set_RemoveItemsNode_4.png) | (Out) Exec | Output execution pin. | + +##Example Usage + +![](Set_RemoveItemsUsage.png) + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/RemoveItems/RemoveItems.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/RemoveItems/RemoveItems.INT.udn new file mode 100644 index 000000000000..c48e497999ce --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/RemoveItems/RemoveItems.INT.udn @@ -0,0 +1,35 @@ +Availability:Docs +Title:Remove Items +Description:Removes items specified in an Array from a Set. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_RemoveItemsNode.png) + +The **Remove Items** node removes Array items from a Set, thereby decreasing the length of the Set. When removing items from a Set, the node checks whether the items are equal to existing items in the Set. +If an item from the Array is equal to an item that's already in the Set, the item will be removed. + +##Inputs + +| Pin Location | Name | Description | +| ------------------------------ | ----------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Set_RemoveItemsNode_1.png) | (In) Exec | Input execution pin. | +| ![](Set_RemoveItemsNode_2.png) | Target Set | The Set that you want to remove items from. | +| ![](Set_RemoveItemsNode_3.png) | New Items | An Array of items that you want to remove from the Set. [REGION:note]Before an item can be removed from a Set, it must exist.[/REGION] | + +##Outputs + +| Pin Location | Name | Description | +| ------------------------------ | ----------- | --------------------- | +| ![](Set_RemoveItemsNode_4.png) | (Out) Exec | Output execution pin. | + +##Example Usage + +![](Set_RemoveItemsUsage.png) + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/RemoveItems/RemoveItems.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/RemoveItems/RemoveItems.JPN.udn new file mode 100644 index 000000000000..58cdc42a4e47 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/RemoveItems/RemoveItems.JPN.udn @@ -0,0 +1,36 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:アイテムを除去する +Description:Array で指定したアイテムを Set から除去する +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version:4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_RemoveItemsNode.png) + +**Remove Items** ノードは Array アイテムを Set からアイテムを除去します。これにより、Set の長さが減少します。Set からアイテムを除去する時に、そのアイテムが Set 内の既存アイテムと同じかどうかをチェックします。 +Array からの新規アイテムが Set 内の既存アイテムと同じであれば、このアイテムは除去されます。 + +##入力 + +| ピンの位置 | 名前 | 説明 | +| ------------------------------ | ----------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Set_RemoveItemsNode_1.png) | (In) Exec | 入力実行ピンです。 | +| ![](Set_RemoveItemsNode_2.png) | Target Set | 除去したいアイテムが入っている Set です。 | +| ![](Set_RemoveItemsNode_3.png) | New Items | Set から除去したいアイテムの Array です。[REGION:note]Set から除去する前に、終了していなければなりません。[/REGION] | + +##出力 + +| ピンの位置 | 名前 | 説明 | +| ------------------------------ | ----------- | --------------------- | +| ![](Set_RemoveItemsNode_4.png) | (Out) Exec | 出力実行ピンです。 | + +##使用例 + +![](Set_RemoveItemsUsage.png) + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/RemoveItems/RemoveItems.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/RemoveItems/RemoveItems.KOR.udn new file mode 100644 index 000000000000..e5d163afeb2e --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/RemoveItems/RemoveItems.KOR.udn @@ -0,0 +1,36 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:Remove Items +Description:세트에서 배열에 지정된 아이템을 제거합니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_RemoveItemsNode.png) + +**Remove Items** 노드는 세트에서 배열 아이템을 제거, 세트의 길이를 줄입니다. 세트에서 아이템을 제거하면, 노드는 그 아이템이 세트의 기존 아이템과 동일한지 검사합니다. +배열의 아이템이 세트에 이미 있는 아이템과 같으면, 그 아이템을 제거합니다. + +##입력 + +| 핀 위치 | 이름 | 설명 | +| ------------------------------ | ----------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Set_RemoveItemsNode_1.png) | (In) Exec | 입력 실행 핀입니다. | +| ![](Set_RemoveItemsNode_2.png) | Target Set | 이 세트에서 아이템을 제거합니다. | +| ![](Set_RemoveItemsNode_3.png) | New Items | 세트에서 제거하고자 하는 아이템 배열입니다. [REGION:note]세트에 존재하는 아이템만 제거할 수 있습니다.[/REGION] | + +##출력 + +| 핀 위치 | 이름 | 설명 | +| ------------------------------ | ----------- | --------------------- | +| ![](Set_RemoveItemsNode_4.png) | (Out) Exec | 출력 실행 핀입니다. | + +##사용 예 + +![](Set_RemoveItemsUsage.png) + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/SetNodes.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/SetNodes.CHN.udn new file mode 100644 index 000000000000..a8867b81f68c --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/SetNodes.CHN.udn @@ -0,0 +1,29 @@ +INTSourceChangelist:0 +Availability:Docs +Title:Blueprint Set Nodes +Description:An overview of the node interface when working with Blueprint Sets. +Crumbs:%ROOT% +Parent:Engine/Blueprints/Scripting +Order:2 +Version: 4.15 +Tags:Blueprint Set +Tags:Blueprints +Type:reference + +A Set's node interface provides the following functionality for developers working in Blueprints: adding items to a +Set, removing items from a Set, clearing Sets, looking up items contained in a Set, and checking a Set's length. +The following guide provides additional information about the various nodes that make-up Blueprint Sets in Unreal Engine 4 (UE4). + +| Node | Description | +| -------------------------------------------------------------- | -------------------------------------------------------------------- | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/Add)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/Add:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/AddItems)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/AddItems:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/Clear)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/Clear:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/ContainsItem)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/ContainsItem:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/Difference)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/Difference:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/Intersection)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/Intersection:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/Length)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/Length:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/Remove)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/Remove:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/RemoveItems)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/RemoveItems:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/ToArray)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/ToArray:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/Union)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/Union:description% | \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/SetNodes.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/SetNodes.INT.udn new file mode 100644 index 000000000000..eb9923431c4c --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/SetNodes.INT.udn @@ -0,0 +1,29 @@ +Availability:Docs +Title:Blueprint Set Nodes +Description:An overview of the node interface when working with Blueprint Sets. +Crumbs:%ROOT% +Parent:Engine/Blueprints/Scripting +Order:2 +Version: 4.15 +Tags:Blueprint Set +Tags:Blueprints +Type:reference +Related:Programming/UnrealArchitecture/TSet + +A Set's node interface provides the following functionality for developers working in Blueprints: adding items to a +Set, removing items from a Set, clearing Sets, looking up items contained in a Set, and checking a Set's length. +The following guide provides additional information about the various nodes that make-up Blueprint Sets in Unreal Engine 4 (UE4). + +| Node | Description | +| -------------------------------------------------------------- | -------------------------------------------------------------------- | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/Add)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/Add:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/AddItems)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/AddItems:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/Clear)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/Clear:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/ContainsItem)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/ContainsItem:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/Difference)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/Difference:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/Intersection)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/Intersection:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/Length)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/Length:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/Remove)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/Remove:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/RemoveItems)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/RemoveItems:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/ToArray)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/ToArray:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/Union)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/Union:description% | diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/SetNodes.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/SetNodes.JPN.udn new file mode 100644 index 000000000000..776647ce0133 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/SetNodes.JPN.udn @@ -0,0 +1,30 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:Blueprint Set ノード +Description:Blueprint Set を使った作業時のノード インターフェースの概要 +Crumbs:%ROOT% +Parent:Engine/Blueprints/Scripting +Order:2 +Version:4.15 +Tags:Blueprint Set +Tags:Blueprints +Type:reference +Related:Programming/UnrealArchitecture/TSet + +Set のノード インターフェースにより、ブループリントで作業するデベロッパーは、 +Set へのアイテムの追加、Set のクリア、Set に格納されたアイテムの検索、Set の長さチェック機能が使えるようになりまうs。 +以下のガイドでは、アンリアル エンジン 4 (UE4) の Blueprint Set を構築する各種ノードの詳細を説明しています。 + +| ノード | 説明 | +| -------------------------------------------------------------- | -------------------------------------------------------------------- | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/Add)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/Add:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/AddItems)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/AddItems:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/Clear)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/Clear:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/ContainsItem)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/ContainsItem:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/Difference)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/Difference:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/Intersection)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/Intersection:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/Length)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/Length:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/Remove)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/Remove:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/RemoveItems)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/RemoveItems:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/ToArray)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/ToArray:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/Union)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/Union:description% | diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/SetNodes.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/SetNodes.KOR.udn new file mode 100644 index 000000000000..6703d64df01d --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/SetNodes.KOR.udn @@ -0,0 +1,30 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:블루프린트 세트 노드 +Description:블루프린트 Set, 세트 노드 작업 시의 노드 인터페이스 개요입니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/Scripting +Order:2 +Version: 4.15 +Tags:Blueprint Set +Tags:Blueprints +Type:reference +Related:Programming/UnrealArchitecture/TSet + +Set (세트) 노드 인터페이스는 블루프린트 작업을 하는 개발자들을 위해 다음과 같은 함수 기능을 제공합니다: 세트에 아이템 추가, +세트에서 아이템 제거, 세트 비우기, 세트에 들어있는 아이템 룩업(찾아보기), 세트의 길이 확인 입니다. +다음은 언리얼 엔진 4 (UE4) 에서 블루프린트 세트를 이루는 여러가지 노드에 대한 부가 설명서입니다. + +| 노드 | 설명 | +| -------------------------------------------------------------- | -------------------------------------------------------------------- | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/Add)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/Add:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/AddItems)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/AddItems:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/Clear)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/Clear:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/ContainsItem)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/ContainsItem:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/Difference)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/Difference:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/Intersection)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/Intersection:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/Length)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/Length:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/Remove)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/Remove:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/RemoveItems)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/RemoveItems:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/ToArray)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/ToArray:description% | +| **[](Engine/Blueprints/UserGuide/Sets/SetNodes/Union)** | %Engine/Blueprints/UserGuide/Sets/SetNodes/Union:description% | \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/ToArray/ToArray.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/ToArray/ToArray.CHN.udn new file mode 100644 index 000000000000..cfd23343e547 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/ToArray/ToArray.CHN.udn @@ -0,0 +1,35 @@ +INTSourceChangelist:0 +Availability:Docs +Title:To Array +Description:Copies a Set into an Array. +Crumbs: +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_ToArrayNode.png) + +The **To Array** node copies a Set's items into an Array container, ostensibly converting the Set into an Array. + +##Inputs + +| Pin Location | Name | Description | +| -------------------------- | ----------- | --------------------------------------------------------------| +| ![](Set_ToArrayNode_1.png) | (In) Exec | Input execution pin. | +| ![](Set_ToArrayNode_2.png) | Set | The Set containing items that you want to copy into an Array. | + +##Outputs + +| Pin Location | Name | Description | +| -------------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Set_ToArrayNode_3.png) | (Out) Exec | Output execution pin. | +| ![](Set_ToArrayNode_4.png) | Result (Array) | An Array containing copied items from the input Set. [REGION:note]Items contained in a Set are unordered, which means that when items are copied from a Set into an Array, the items are not guaranteed to be in a specified order.[/REGION] | + +##Example Usage + +![](Set_ToArrayUsage.png) + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/ToArray/ToArray.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/ToArray/ToArray.INT.udn new file mode 100644 index 000000000000..120ad7739104 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/ToArray/ToArray.INT.udn @@ -0,0 +1,34 @@ +Availability:Docs +Title:To Array +Description:Copies a Set into an Array. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_ToArrayNode.png) + +The **To Array** node copies a Set's items into an Array container, ostensibly converting the Set into an Array. + +##Inputs + +| Pin Location | Name | Description | +| -------------------------- | ----------- | --------------------------------------------------------------| +| ![](Set_ToArrayNode_1.png) | (In) Exec | Input execution pin. | +| ![](Set_ToArrayNode_2.png) | Set | The Set containing items that you want to copy into an Array. | + +##Outputs + +| Pin Location | Name | Description | +| -------------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Set_ToArrayNode_3.png) | (Out) Exec | Output execution pin. | +| ![](Set_ToArrayNode_4.png) | Result (Array) | An Array containing copied items from the input Set. [REGION:note]Items contained in a Set are unordered, which means that when items are copied from a Set into an Array, the items are not guaranteed to be in a specified order.[/REGION] | + +##Example Usage + +![](Set_ToArrayUsage.png) + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/ToArray/ToArray.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/ToArray/ToArray.JPN.udn new file mode 100644 index 000000000000..ef37bf6f628b --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/ToArray/ToArray.JPN.udn @@ -0,0 +1,35 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:To Array +Description:Set を Array にコピーする +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version:4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_ToArrayNode.png) + +**To Array** ノードは Set のアイテムを Array コンテナへコピーします。表面上は Set を Array へ変換します。 + +##入力 + +| ピンの位置 | 名前 | 説明 | +| -------------------------- | ----------- | --------------------------------------------------------------| +| ![](Set_ToArrayNode_1.png) | (In) Exec | 入力実行ピンです。 | +| ![](Set_ToArrayNode_2.png) | Set | Array にコピーしたいアイテムが含まれている Set です。 | + +##出力 + +| ピンの位置 | 名前 | 説明 | +| -------------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Set_ToArrayNode_3.png) | (Out) Exec | 出力実行ピンです。 | +| ![](Set_ToArrayNode_4.png) | Result (Array) | 入力 Set からコピーされたアイテムが含まれる Array です。[REGION:note]Set に含まれるアイテムには順序付けされません。つまり、Set から Array にコピーされたアイテムが特定の順序になる保証はありません。[/REGION] | + +##使用例 + +![](Set_ToArrayUsage.png) + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/ToArray/ToArray.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/ToArray/ToArray.KOR.udn new file mode 100644 index 000000000000..d1310b86e32e --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/ToArray/ToArray.KOR.udn @@ -0,0 +1,35 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:To Array +Description:세트를 배열에 복사해 넣습니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_ToArrayNode.png) + +**To Array** 노드는 세트의 아이템을 배열 컨테이너에 복사, 표면상 세트를 배열로 변환합니다. + +##입력 + +| 핀 위치 | 이름 | 설명 | +| -------------------------- | ----------- | --------------------------------------------------------------| +| ![](Set_ToArrayNode_1.png) | (In) Exec | 입력 실행 핀입니다. | +| ![](Set_ToArrayNode_2.png) | Set | 배열에 복사해 넣고자 하는 아이템이 들어있는 세트입니다. | + +##출력 + +| 핀 위치 | 이름 | 설명 | +| -------------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ![](Set_ToArrayNode_3.png) | (Out) Exec | 출력 실행 핀입니다. | +| ![](Set_ToArrayNode_4.png) | Result (Array) | 입력 세트에서 복사해 온 아이템이 들어있는 배열입니다. [REGION:note]세트에 들어있는 아이템은 순서가 없습니다. 즉 세트에서 배열로 아이템을 복사할 때, 순서가 유지된다는 보장이 없다는 뜻입니다.[/REGION] | + +##사용 예 + +![](Set_ToArrayUsage.png) + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Union/Union.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Union/Union.CHN.udn new file mode 100644 index 000000000000..d2a1d1c5cf9d --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Union/Union.CHN.udn @@ -0,0 +1,64 @@ +INTSourceChangelist:0 +Availability:Docs +Title:Union +Description:Performs a union of two Sets, assigning the union to a resultant Set. +Crumbs: +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_UnionNode.png) + +The **Union** node takes the union of items found in two Sets, assigning the union to a Resultant Set, with the result containing items found in both Set A and Set B. +Visually, the intersection of Set A and Set B looks like the following diagram, where the intersection of Set A and Set B contains items that are common to both Sets. + +![](Set_UnionDiagram.png) + +For illustrative purposes, let's say that you have two string type Sets, Set A and Set B, both of which are defined below. + + Set A = {"Item 1", "Item 2", "Item 3", "Item 4", "Item 5"} + Set B = {"Item 4", "Item 5", "Item 6", "Item 7", "Item 8"} + +The following table shows you the result, which contains the union of Set A and Set B (symbolically represented as **A ∪ B**). + +| --------- | --------- | -------------------------------- | +| **Set A** | **Set B** | **Resultant Set (A ∪ B)** | +| `Item 1` | `Item 4` | `Item 1` | +| `Item 2` | `Item 5` | `Item 2` | +| `Item 3` | `Item 6` | `Item 3` | +| `Item 4` | `Item 7` | `Item 4` | +| `Item 5` | `Item 8` | `Item 5` | +| | | `Item 6` | +| | | `Item 7` | +| | | `Item 8` | + +[REGION:note] +A Set is a collection of unique items, which means that duplicate items will be eliminated from the Resultant Set. +[/REGION] + +##Inputs + +| Pin Location | Name | Description | +| ------------------------ | ----------- | ----------------------- | +| ![](Set_UnionNode_1.png) | (In) Exec | Input execution pin. | +| ![](Set_UnionNode_2.png) | A | One Set to union. | +| ![](Set_UnionNode_3.png) | B | The other Set to union. | + +##Outputs + +| Pin Location | Name | Description | +| ------------------------ | ----------- | --------------------------------------- | +| ![](Set_UnionNode_4.png) | (Out) Exec | Output execution pin. | +| ![](Set_UnionNode_5.png) | Result | The Set containing the resultant union. | + +##Example Usage + +![](Set_UnionUsage.png) + +#### Footnote + +Symbolically, this operation is represented as A ∪ B = { x | x ∈ A ∨ x ∈ B }, wherein this node is performing a logical OR operation between elements in Set A and elements in Set B. \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Union/Union.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Union/Union.INT.udn new file mode 100644 index 000000000000..01dfc3e82211 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Union/Union.INT.udn @@ -0,0 +1,65 @@ +Availability:Docs +Title:Union +Description:Performs a union of two Sets, assigning the union to a resultant Set. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_UnionNode.png) + +The **Union** node takes the union of items found in two Sets, assigning the union to a Resultant Set, with the result containing items found in both Set A and Set B. +Visually, the intersection of Set A and Set B looks like the following diagram, where the intersection of Set A and Set B contains items that are common to both Sets. + +[REGION:raw] +![](Set_UnionDiagram.png) +[/REGION] + +For illustrative purposes, let's say that you have two string type Sets, Set A and Set B, both of which are defined below. + + Set A = {"Item 1", "Item 2", "Item 3", "Item 4", "Item 5"} + Set B = {"Item 4", "Item 5", "Item 6", "Item 7", "Item 8"} + +The following table shows you the result, which contains the union of Set A and Set B (symbolically represented as **A ∪ B**). + +| --------- | --------- | -------------------------------- | +| **Set A** | **Set B** | **Resultant Set (A ∪ B)** | +| `Item 1` | `Item 4` | `Item 1` | +| `Item 2` | `Item 5` | `Item 2` | +| `Item 3` | `Item 6` | `Item 3` | +| `Item 4` | `Item 7` | `Item 4` | +| `Item 5` | `Item 8` | `Item 5` | +| | | `Item 6` | +| | | `Item 7` | +| | | `Item 8` | + +[REGION:note] +A Set is a collection of unique items, which means that duplicate items will be eliminated from the Resultant Set. +[/REGION] + +##Inputs + +| Pin Location | Name | Description | +| ------------------------ | ----------- | ----------------------- | +| ![](Set_UnionNode_1.png) | (In) Exec | Input execution pin. | +| ![](Set_UnionNode_2.png) | A | One Set to union. | +| ![](Set_UnionNode_3.png) | B | The other Set to union. | + +##Outputs + +| Pin Location | Name | Description | +| ------------------------ | ----------- | --------------------------------------- | +| ![](Set_UnionNode_4.png) | (Out) Exec | Output execution pin. | +| ![](Set_UnionNode_5.png) | Result | The Set containing the resultant union. | + +##Example Usage + +![](Set_UnionUsage.png) + +#### Footnote + +Symbolically, this operation is represented as A ∪ B = { x | x ∈ A ∨ x ∈ B }, wherein this node is performing a logical OR operation between elements in Set A and elements in Set B. \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Union/Union.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Union/Union.JPN.udn new file mode 100644 index 000000000000..eb807596d6be --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Union/Union.JPN.udn @@ -0,0 +1,66 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:Union +Description:2 つの Set の合併を実行し、その和集合を Resultant Set に割り当てます。 +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version:4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_UnionNode.png) + +**Union** ノードは 2 つの Set に含まれるアイテムをすべて集め、その和集合を Resultant Set に割り当てて、結果が Set A と Set B の両方に属するアイテムとなるようにします。 +Set A と Set B の共通部分を図で表すと以下のようになります。この場合、Set A と Set B の共通部分は両方の Set に共通するアイテムです。 + +[REGION:raw] +![](Set_UnionDiagram.png) +[/REGION] + +解説しやすいように、Set A と Set B という 2 つのストリング型をそれぞれ以下のように定義します。 + + Set A = {"Item 1", "Item 2", "Item 3", "Item 4", "Item 5"} + Set B = {"Item 4", "Item 5", "Item 6", "Item 7", "Item 8"} + +は以下の表は、Set A and Set B の和集合が含まれる結果を表します (記号で表すと **A ∪ B**)。 + +| --------- | --------- | -------------------------------- | +| **Set A** | **Set B** | **Resultant Set (A ∪ B)** | +| `Item 1` | `Item 4` | `Item 1` | +| `Item 2` | `Item 5` | `Item 2` | +| `Item 3` | `Item 6` | `Item 3` | +| `Item 4` | `Item 7` | `Item 4` | +| `Item 5` | `Item 8` | `Item 5` | +| | | `Item 6` | +| | | `Item 7` | +| | | `Item 8` | + +[REGION:note] +Set はユニークなアイテムのコレクションです。つまり、重複アイテムは Resultant Set から取り除かれます。 +[/REGION] + +##入力 + +| ピンの位置 | 名前 | 説明 | +| ------------------------ | ----------- | ----------------------- | +| ![](Set_UnionNode_1.png) | (In) Exec | 入力実行ピンです。 | +| ![](Set_UnionNode_2.png) | A | 和集合の一方の Set です。 | +| ![](Set_UnionNode_3.png) | B | 和集合のもう一方の Set です。 | + +##出力 + +| ピンの位置 | 名前 | 説明 | +| ------------------------ | ----------- | --------------------------------------- | +| ![](Set_UnionNode_4.png) | (Out) Exec | 出力実行ピンです。 | +| ![](Set_UnionNode_5.png) | Result | 和集合の結果を含む Set です。 | + +##使用例 + +![](Set_UnionUsage.png) + +#### 補足説明 + +この演算を記号で表すと A ∪ B = { x | x ∈ A ∨ x ∈ B } となり、このノードは、Set A のエレメントと Set B のエレメントの間で論理 OR 演算を実行します。 \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Union/Union.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Union/Union.KOR.udn new file mode 100644 index 000000000000..0dbe5abe574e --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/SetNodes/Union/Union.KOR.udn @@ -0,0 +1,66 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:Union +Description:두 세트의 합집합을 구해 결과 세트에 할당합니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/UserGuide/Sets/SetNodes +Order: +Version: 4.15 +Tags:Blueprints +Type:reference + +[TOC(start:1 end:2)] + +![](Set_UnionNode.png) + +**Union** 노드는 두 세트의 아이템 합집합을 구하여 Resultant Set 에 할당합니다. Set A 또는 Set B 에 있는 아이템을 말합니다. +시각적으로 Set A 와 Set B 의 합집합은 다음과 같습니다. Set A 와 Set B 의 합집합은 두 집합 중 한 곳에 있는 아이템을 모은 것입니다. + +[REGION:raw] +![](Set_UnionDiagram.png) +[/REGION] + +예시를 위해 스트링 유형 세트 Set A 와 Set B 가 다음과 같이 정의되어 있다 칩시다. + + Set A = {"Item 1", "Item 2", "Item 3", "Item 4", "Item 5"} + Set B = {"Item 4", "Item 5", "Item 6", "Item 7", "Item 8"} + +결과는 다음 표와 같습니다. Set A 와 Set B 의 합집합입니다. (심볼로는 **A ∪ B** 로 표시합니다). + +| --------- | --------- | -------------------------------- | +| **Set A** | **Set B** | **Resultant Set (A ∪ B)** | +| `Item 1` | `Item 4` | `Item 1` | +| `Item 2` | `Item 5` | `Item 2` | +| `Item 3` | `Item 6` | `Item 3` | +| `Item 4` | `Item 7` | `Item 4` | +| `Item 5` | `Item 8` | `Item 5` | +| | | `Item 6` | +| | | `Item 7` | +| | | `Item 8` | + +[REGION:note] +A Set 는 고유 아이템 집합으로, Resultant Set 에서 중복 아이템은 제거된다는 뜻입니다. +[/REGION] + +##입력 + +| 핀 위치 | 이름 | 설명 | +| ------------------------ | ----------- | ----------------------- | +| ![](Set_UnionNode_1.png) | (In) Exec | 입력 실행 핀입니다. | +| ![](Set_UnionNode_2.png) | A | 합집합 한 쪽입니다. | +| ![](Set_UnionNode_3.png) | B | 합집합 다른 쪽입니다. | + +##출력 + +| 핀 위치 | 이름 | 설명 | +| ------------------------ | ----------- | --------------------------------------- | +| ![](Set_UnionNode_4.png) | (Out) Exec | 출력 실행 핀입니다. | +| ![](Set_UnionNode_5.png) | Result | 결과 합집합입니다. | + +##사용 예 + +![](Set_UnionUsage.png) + +#### 사족 + +이 연산을 심볼로 표시하면 A ∪ B = { x | x ∈ A ∨ x ∈ B } 입니다. 이 노드는 Set A 의 엘리먼트와 Set B 엘리먼트에 대한 논리 OR 연산을 수행합니다. \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/Sets.CHN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/Sets.CHN.udn new file mode 100644 index 000000000000..73b6939e428d --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/Sets.CHN.udn @@ -0,0 +1,201 @@ +INTSourceChangelist:0 +Availability:Docs +Title:Blueprint Sets +Description:Creating and editing Set containers, an advanced container type, in Blueprints, including an overview of this container's properties. +Crumbs:%ROOT% +Parent:Engine/Blueprints/Scripting +Order:1 +Version: 4.15 +Tags:Blueprint Set +Tags:Blueprints +topic-image:sets_topicImage.png +Skilllevel:Advanced + +[TOC(start:1 end:2)] + +[REGION:banner] +![](sets_topicBanner.png) +[/REGION] + +With the release of Unreal Engine, version 4.15, the **Set** container type has been added to the [Blueprint Application Programming Interface (API)](https://docs.unrealengine.com/latest/INT/BlueprintAPI/) in Unreal Engine 4 (UE4). +If you're unfamiliar with the term "container"; think of a storage box, where you label items and place them inside of the box for immediate (or later) use. If you've used Arrays to store and work with collections of items, you've +already started using Blueprint containers in UE4. For example, when using Arrays to store items for later use, the item's label is its place in the array; however, when using Sets, the label is the item itself. This makes Sets a +powerful addition to the Blueprint API. + +Blueprint Sets are an exciting addition to the Blueprint API because they support efficient lookups and retrieval with keys, where a key is an item itself. The Set's +characteristic, where an item's key is the item itself, means that Sets allow developers to efficiently add, find, and remove items located in the container. +Depending on your game, Sets can be used to ignore commonly used words in dialogue, or they can be used to store unique inventory items. Clearly, there are +many potential use cases when working with Sets; however, before you can harness the power of Sets in your game, you'll need to learn how to properly use them in UE4. + +As you read through this page, you'll learn how to create and edit Blueprint Sets. You'll also learn about the properties of Blueprint Sets, which are being included to help you get the most out of using +Sets in your game projects. + +[REGION:note] + +For illustrative purposes, we're using a **Blank Blueprint Project** (with highlighted settings) to show you how to create and edit Blueprint Sets. + +[REGION:lightbox] + [![](sampleProject.png)(w:370)](sampleProject.png) +[/REGION] + +[REGION:caption] +Click for full image. +[/REGION] + +[/REGION] + +## Creating Sets + +To create a new Blueprint Set, follow these steps. + +1. If you don't have a Blueprint Class to work from, go ahead and **Add** a new Blueprint Class to your project. + + [REGION:lightbox] + [![](creatingSets_Step1.png)(w:600)](creatingSets_Step1.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, select **Actor** from the list of classes being shown in the **Pick Parent Class** menu. + + ![](creatingSets_Step2.png) + +1. After naming your Actor class, go ahead and open the newly created Actor class by double-clicking on the Actor, which is located inside of the **Content Browser**. + + [REGION:lightbox] + [![](creatingSets_Step3.png)(w:600)](creatingSets_Step3.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. To begin editing the Actor's Blueprint script, select the **Event Graph** tab. + + [REGION:lightbox] + [![](creatingSets_Step4.png)(w:600)](creatingSets_Step4.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. With the Actor's **Event Graph** open, hover your mouse cursor over the **Variables** submenu to reveal the **+ Variable** button. + + [REGION:lightbox] + [![](creatingSets_Step5.png)(w:600)](creatingSets_Step5.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, create a new **String** variable, naming it `MyStringSet`. + + [REGION:lightbox] + [![](creatingSets_Step6.png)(w:600)](creatingSets_Step6.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Currently, `MyStringSet` is a single **String** variable. To begin turning `MyStringSet` into a **Set** container, click on the **Variable Type** button, which is on the right side of the **Variable Type** label inside of the Actor's **Details Panel**. + + [REGION:lightbox] + [![](creatingSets_Step7.png)(w:600)](creatingSets_Step7.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. At this point, a drop down menu will appear, showing you four container options. Select the **{ }** option to convert `MyStringSet` into a Blueprint Set. + + ![](creatingSets_Step8.png) + +Excellent work, you've just created a new String Set container (named `MyStringSet`). + +![](creatingSets_Step9.png) + +## Editing Sets + +Before you can edit a newly created Set, you'll need to compile the Blueprint encapsulating the Set variable container. + +[REGION:lightbox] +[![](creatingSets_Step10.png)(w:600)](creatingSets_Step10.png) +[/REGION] + +[REGION:caption] +Click for full image. +[/REGION] + +1. To edit `MyStringSet`, click the Blueprint's **Compile** button. + + [REGION:lightbox] + [![](creatingSets_Step11.png)(w:600)](creatingSets_Step11.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After compiling the Blueprint, you'll notice that the Set's **Default Value** (located in the **Details** panel) shows that `MyStringSet` is empty. + + [REGION:lightbox] + [![](creatingSets_Step12.png)(w:600)](creatingSets_Step12.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. To add a new String element to `MyStringSet`, click the **+** button, located next to **0 Set elements** in the **Default Value** menu of the **Details** panel. + + ![](creatingSets_Step13.png) + +1. Go ahead and click the **+** button once again. + + ![](creatingSets_Step14.png) + + [REGION:warning] + Unreal Editor will emit a warning if you try to add an element to a Blueprint Set before updating a new element's default value. + ![](Step14_Warning.png) + [/REGION] + +1. Add three elements to `MyStringSet`, naming them `Apple`, `Banana`, and `Cherry`. + + ![](creatingSets_Step15.png) + +1. Now, add one more element, naming it `Banana`. + + ![](creatingSets_Step16.png) + + [REGION:warning] + Unreal Editor will emit a warning if you try to add a new element with the same value as an existing element. + + ![](Step16_Warning.png) + [/REGION] + +1. With the aforementioned warning in mind, go ahead and name the fourth element `Date`. + +Well done! You've just created a new Blueprint Set, having added and edited four elements. + +![](creatingSets_Step17.png) + +## Container Properties + +If you want to get started with using Blueprint Set containers in UE4, please refer to the following property list. + +* Items (or elements) in a Set must be unique. +* All items in a Set must be defined (initialized). +* Under-the-hood, items stored in a Set are unordered. +* All items in a Set are homogeneous (of the same type). +* Adding, removing, and finding items in a Set are fast operations. +* The value of an item in a Set is also the key being used to find it. +* Currently, Blueprint Sets are immutable, which means that they cannot be modified after they are created. + +Now that you know how to create and edit Set containers in Blueprints, check out the [](Engine/Blueprints/UserGuide/Sets/SetNodes) reference guide to learn more about the Blueprint Set Node Interface. + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/Sets.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/Sets.INT.udn new file mode 100644 index 000000000000..775208617304 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/Sets.INT.udn @@ -0,0 +1,201 @@ +Availability:Docs +Title:Blueprint Sets +Description:Creating and editing Set containers, an advanced container type, in Blueprints, including an overview of this container's properties. +Crumbs:%ROOT% +Parent:Engine/Blueprints/Scripting +Order:1 +Version: 4.15 +Tags:Blueprint Set +Tags:Blueprints +topic-image:sets_topicImage.png +Skilllevel:Advanced +Related:Programming/UnrealArchitecture/TSet + +[TOC(start:1 end:2)] + +[REGION:banner] +![](sets_topicBanner.png) +[/REGION] + +With the release of Unreal Engine, version 4.15, the **Set** container type has been added to the [Blueprint Application Programming Interface (API)](https://docs.unrealengine.com/latest/INT/BlueprintAPI/) in Unreal Engine 4 (UE4). +If you're unfamiliar with the term "container"; think of a storage box, where you label items and place them inside of the box for immediate (or later) use. If you've used Arrays to store and work with collections of items, you've +already started using Blueprint containers in UE4. For example, when using Arrays to store items for later use, the item's label is its place in the array; however, when using Sets, the label is the item itself. This makes Sets a +powerful addition to the Blueprint API. + +Blueprint Sets are an exciting addition to the Blueprint API because they support efficient lookups and retrieval with keys, where a key is an item itself. The Set's +characteristic, where an item's key is the item itself, means that Sets enable developers to efficiently add, find, and remove items located in the container. +Depending on your game, Sets can be used to ignore commonly used words in dialogue, or they can be used to store unique inventory items. Clearly, there are +many potential use cases when working with Sets; however, before you can harness the power of Sets in your game, you'll need to learn how to properly use them in UE4. + +As you read through this page, you'll learn how to create and edit Blueprint Sets. You'll also learn about the properties of Blueprint Sets, which are being included to help you get the most out of using +Sets in your game projects. + +[REGION:note] + +For illustrative purposes, we're using a **Blank Blueprint Project** (with highlighted settings) to show you how to create and edit Blueprint Sets. + +[REGION:lightbox] + [![](sampleProject.png)(w:370)](sampleProject.png) +[/REGION] + +[REGION:caption] +Click for full image. +[/REGION] + +[/REGION] + +## Creating Sets + +To create a new Blueprint Set, follow these steps. + +1. If you don't have a Blueprint Class to work from, go ahead and **Add** a new Blueprint Class to your project. + + [REGION:lightbox] + [![](creatingSets_Step1.png)(w:600)](creatingSets_Step1.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, select **Actor** from the list of classes being shown in the **Pick Parent Class** menu. + + ![](creatingSets_Step2.png) + +1. After naming your Actor class, go ahead and open the newly created Actor class by double-clicking on the Actor, which is located inside of the **Content Browser**. + + [REGION:lightbox] + [![](creatingSets_Step3.png)(w:600)](creatingSets_Step3.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. To begin editing the Actor's Blueprint script, select the **Event Graph** tab. + + [REGION:lightbox] + [![](creatingSets_Step4.png)(w:600)](creatingSets_Step4.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. With the Actor's **Event Graph** open, hover your mouse cursor over the **Variables** submenu to reveal the **+ Variable** button. + + [REGION:lightbox] + [![](creatingSets_Step5.png)(w:600)](creatingSets_Step5.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Now, create a new **String** variable, naming it `MyStringSet`. + + [REGION:lightbox] + [![](creatingSets_Step6.png)(w:600)](creatingSets_Step6.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. Currently, `MyStringSet` is a single **String** variable. To begin turning `MyStringSet` into a **Set** container, click on the **Variable Type** button, which is on the right side of the **Variable Type** label inside of the Actor's **Details** panel. + + [REGION:lightbox] + [![](creatingSets_Step7.png)(w:600)](creatingSets_Step7.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. At this point, a drop down menu will appear, showing you four container options. Select the **{ }** option to convert `MyStringSet` into a Blueprint Set. + + ![](creatingSets_Step8.png) + +Excellent work, you've just created a new String Set container (named `MyStringSet`). + +![](creatingSets_Step9.png) + +## Editing Sets + +Before you can edit a newly created Set, you'll need to compile the Blueprint encapsulating the Set variable container. + +[REGION:lightbox] +[![](creatingSets_Step10.png)(w:600)](creatingSets_Step10.png) +[/REGION] + +[REGION:caption] +Click for full image. +[/REGION] + +1. To edit `MyStringSet`, click the Blueprint's **Compile** button. + + [REGION:lightbox] + [![](creatingSets_Step11.png)(w:600)](creatingSets_Step11.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. After compiling the Blueprint, you'll notice that the Set's **Default Value** (located in the **Details** panel) shows that `MyStringSet` is empty. + + [REGION:lightbox] + [![](creatingSets_Step12.png)(w:600)](creatingSets_Step12.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + +1. To add a new String element to `MyStringSet`, click the **+** button, located next to **0 Set elements** in the **Default Value** menu of the **Details** panel. + + ![](creatingSets_Step13.png) + +1. Go ahead and click the **+** button once again. + + ![](creatingSets_Step14.png) + + [REGION:warning] + Unreal Editor will emit a warning if you try to add an element to a Blueprint Set before updating a new element's default value. + ![](Step14_Warning.png) + [/REGION] + +1. Add three elements to `MyStringSet`, naming them `Apple`, `Banana`, and `Cherry`. + + ![](creatingSets_Step15.png) + +1. Now, add one more element, naming it `Banana`. + + ![](creatingSets_Step16.png) + + [REGION:warning] + Unreal Editor will emit a warning if you try to add a new element with the same value as an existing element. + + ![](Step16_Warning.png) + [/REGION] + +1. With the aforementioned warning in mind, go ahead and name the fourth element `Date`. + +Well done! You've just created a new Blueprint Set, having added and edited four elements. + +![](creatingSets_Step17.png) + +## Container Properties + +If you want to get started with using Blueprint Set containers in UE4, please refer to the following property list. + +* Items (or elements) in a Set must be unique. +* All items in a Set must be defined (initialized). +* Under-the-hood, items stored in a Set are unordered. +* All items in a Set are homogeneous (of the same type). +* Adding, removing, and finding items in a Set are fast operations. +* The value of an item in a Set is also the key being used to find it. +* Currently, Blueprint Sets are immutable, which means that they cannot be modified after they are created. + +Now that you know how to create and edit Set containers in Blueprints, check out the [](Engine/Blueprints/UserGuide/Sets/SetNodes) reference guide to learn more about the Blueprint Set Node Interface. + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/Sets.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/Sets.JPN.udn new file mode 100644 index 000000000000..bee2af657b84 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/Sets.JPN.udn @@ -0,0 +1,202 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:Blueprint Sets +Description:ブループリントの高度なコンテナ タイプの Set コンテナの作成と編集、およびコンテナのプロパティの概要 +Crumbs:%ROOT% +Parent:Engine/Blueprints/Scripting +Order:1 +Version:4.15 +Tags:Blueprint Set +Tags:Blueprints +topic-image:sets_topicImage.png +Skilllevel:Advanced +Related:Programming/UnrealArchitecture/TSet + +[TOC(start:1 end:2)] + +[REGION:banner] +![](sets_topicBanner.png) +[/REGION] + +アンリアル エンジン 4.15 がリリースされ、**Set** コンテナ タイプがアンリアル エンジン 4 (UE4) の [Blueprint Application Programming Interface (API)](https://docs.unrealengine.com/latest/INT/BlueprintAPI/) に追加されました。 +コンテナという用語を知らない場合、アイテムにラベル付けをして、すぐに (または後で) 使うために入れて置くストレージ ボックスだと考えてください。Arrays を使って格納してアイテムのコレクションを使って作業したことがあれば、 +UE4 の Blueprint コンテナを既に使っています。例えば、Arrays を使って後で使うアイテムを格納する場合、そのアイテムのラベルは配列内の位置になります。しかし、Sets を使うとラベルはアイテムそのものになります。これにより、 +Set は Blueprint API をさらにパワフルにします。 + +Blueprint Set は、キーがアイテムそのものなので、キーを使って効率的にルックアップと抽出ができるようになり、Blueprint API がますます面白くなります。Set にはアイテムのキーがアイテムそのものという特性があるので、 +Set によってデベロッパーはコンテナに置かれているアイテムを効率的に追加、検索、除去できるようになります。 +ゲームによっては、ダイアログでよく使用される単語を無視したり、ユニークなインベントリ アイテムの格納にも使用することができます。明らかに、Set には多くのユースケースの可能性がありますが、 +ゲームで Set のパワーを大いに活用する前に、UE4 で正しく使う方法を学習する必要があります。 + +本ページでは、Blueprint Set の作成および編集方法を学習します。プロジェクトで Set の最大限の活用に役立てるために、 +Blueprint Set のプロパティの説明も含まれています。 + +[REGION:note] + +図説の便宜上、**Blank Blueprint Project** (下図の黄色枠部分) を使ってBlueprint Set の作成および編集方法の説明を行います。 + +[REGION:lightbox] + [![](sampleProject.png)(w:370)](sampleProject.png) +[/REGION] + +[REGION:caption] +クリックしてフルサイズで表示 +[/REGION] + +[/REGION] + +## Set の作成 + +Blueprint Set を新規作成するには、以下の操作を行います。 + +1. 作業用 Blueprint クラスがまだない場合は、Blueprint クラスをプロジェクトに **追加** してください。 + + [REGION:lightbox] + [![](creatingSets_Step1.png)(w:600)](creatingSets_Step1.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **[Pick Parent Class (親クラスを選択)]** メニューに表示されているクラスリストから **[Actor]** を選択します。 + + ![](creatingSets_Step2.png) + +1. Actor クラスに名前を付けたら、**コンテンツ ブラウザ** 内でそのアクタをダブルクリックして開きます。 + + [REGION:lightbox] + [![](creatingSets_Step3.png)(w:600)](creatingSets_Step3.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. そのアクタのブループリント スクリプトの編集を始めるために **[Event Graph]** タブを選択します。 + + [REGION:lightbox] + [![](creatingSets_Step4.png)(w:600)](creatingSets_Step4.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. アクタの **Event Graph** を開いたら、**[Variables (変数)]** サブメニュー上にカーソルをあてて **[+ Variable]** ボタンを表示させます。 + + [REGION:lightbox] + [![](creatingSets_Step5.png)(w:600)](creatingSets_Step5.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. 次に **String** 変数を作成し、`MyStringSet` と名前を付けます。 + + [REGION:lightbox] + [![](creatingSets_Step6.png)(w:600)](creatingSets_Step6.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. いま、`MyStringSet` は単一の **String** 変数の状態です。`MyStringSet` を **Set** コンテナに変換するには、アクタの **[Details (詳細)] パネル** の **Variable Type** ラベルの右側にある**[Variable Type (変数タイプ)] ボタンをクリックします。 + + [REGION:lightbox] + [![](creatingSets_Step7.png)(w:600)](creatingSets_Step7.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. ここでドロップダウン メニューの中に 4 つのコンテナ オプションが表示されます。**{ }** オプションを選択して `MyStringSet` を Blueprint Set に変換します。 + + ![](creatingSets_Step8.png) + +これで、String Set コンテナ (名前は `MyStringSet`) が新規作成されました。 + +![](creatingSets_Step9.png) + +## Set の編集 + +新規作成された Set を編集する前に、Set 変数コンテナをカプセル化するブループリントをコンパイルしなければなりません。 + +[REGION:lightbox] +[![](creatingSets_Step10.png)(w:600)](creatingSets_Step10.png) +[/REGION] + +[REGION:caption] +クリックしてフルサイズで表示 +[/REGION] + +1. `MyStringSet` を編集するには、ブループリントの **[Compile]** ボタンをクリックします。 + + [REGION:lightbox] + [![](creatingSets_Step11.png)(w:600)](creatingSets_Step11.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. ブループリントをコンパイルすると、Set の **[Default Value (デフォルト値)]** (**[Details (詳細)]** パネル内) に `MyStringSet` が空であることが表示されます。 + + [REGION:lightbox] + [![](creatingSets_Step12.png)(w:600)](creatingSets_Step12.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. String エレメントを `MyStringSet` に追加するには、**[Details (詳細)]** パネルの **[Default Value (デフォルト値)]** メニューの **0 Set elements** の横にある**[+]** ボタンをクリックします。 + + ![](creatingSets_Step13.png) + +1. **[+]** ボタンをもう一度押してください。 + + ![](creatingSets_Step14.png) + + [REGION:warning] + 新規エレメントのデフォルト値を更新せずにエレメントをブループリントに追加しようとすると、アンリアル エディタが警告を出します。 + ![](Step14_Warning.png) + [/REGION] + +1. 3 つのエレメントを `MyStringSet` に追加して、それぞれの名前を `Apple`、`Banana`、`Cherry` とします。 + + ![](creatingSets_Step15.png) + +1. 次にもう 1 つエレメントを追加して、名前を `Banana` と付けます。 + + ![](creatingSets_Step16.png) + + [REGION:warning] + 既存するエレメントと同じ値をもつ新規エレメントを追加しようとすると、アンリアル エディタが警告を出します。 + + ![](Step16_Warning.png) + [/REGION] + +1. 上記の警告を念頭に置いて、4 つ目のエレメントに `Date` という名前を付けてください。 + +よくできました!これで 4 つ目のエレメントを追加編集した Blueprint Set が新規作成されました。 + +![](creatingSets_Step17.png) + +## コンテナのプロパティ + +UE4 で Blueprint Set コンテナを使って作業を開始する場合は、以下のプロパティ一覧を参照してください。 + +* Set 内のアイテム (またはエレメント) はユニークでなければなりません。 +* All items in a Set 内のすべてのアイテムは定義 (または初期化) されていなければなりません。 +* Set 内に格納されたアイテムには順序付けされません。 +* Set 内のすべてのアイテムは同一 (同じタイプ) になります。 +* Set 内のアイテムの追加、削除、検索は高速演算です。 +* Set 内のアイテムの値は検索に使用するキーでもあります。 +* 現在、Blueprint Set は変更不可能です。つまり、作成後の変更は不可能です。 + +本ページではブループリントでの Set の作成および編集方法を学習しました。Blueprint Set ノード インターフェースの詳細は、[](Engine/Blueprints/UserGuide/Sets/SetNodes) リファレンス ガイドを参照してください。 + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/Sets.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/Sets.KOR.udn new file mode 100644 index 000000000000..b8b8f7246fd2 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Sets/Sets.KOR.udn @@ -0,0 +1,202 @@ +INTSourceChangelist:3413822 +Availability:Docs +Title:블루프린트 Set +Description:블루프린트의 고급 컨테이너 유형인 Set 컨테이너의 생성 및 편집, 그리고 프로퍼티 개요입니다. +Crumbs:%ROOT% +Parent:Engine/Blueprints/Scripting +Order:1 +Version: 4.15 +Tags:Blueprint Set +Tags:Blueprints +topic-image:sets_topicImage.png +Skilllevel:Advanced +Related:Programming/UnrealArchitecture/TSet + +[TOC(start:1 end:2)] + +[REGION:banner] +![](sets_topicBanner.png) +[/REGION] + +언리얼 엔진 4.15 버전 릴리즈 이후 UE4 의 [Blueprint Application Programming Interface (API)](https://docs.unrealengine.com/latest/INT/BlueprintAPI/) 에 **Set** (세트) 컨테이너 유형이 추가되었습니다. +"컨테이너" 라는 용어는, 보관 상자같은 것에 아이템 라벨을 붙인 뒤 박스 안에 넣어두고 바로 (아니면 나중에) 사용하는 것을 말합니다. 배열을 사용하여 아이템 콜렉션을 저장 및 작업을 해 봤다면, +이미 UE4 에서 블루프린트 컨테이너 사용을 해 본 것입니다. 예를 들어 배열로 나중에 사용할 아이템을 저장하면 아이템의 라벨은 배열에 있는 것이지만, 세트를 사용하면 라벨이 아이템 자체가 되는 것입니다. 세트로 인해 +블루프린트 API 가 강력해 지는 것입니다. + +블루프린트 세트는 블루프린트 API 추가 기능 중 흥미로운 것인데, 키를 통한 효율적인 룩업 및 값 구하기를 지원하기 때문입니다. 여기서 키가 곧 아이템 자체 세트의 특징 덕에, +개발자들은 컨테이너에 위치한 아이템을 효율적으로 추가, 검색, 제거할 수 있습니다. +게임에 따라 세트는 대화에 흔히 사용되는 단어를 무시하거나, 독특한 인벤토리 아이템을 저장하는 데도 사용할 수 있습니다. 명확히, +세트로 작업할 수 있는 예는 많이 있지만, 게임에 세트의 막강한 힘을 활용하기 전 UE4 에서 제대로 사용하기 위해 배워야 할 것들이 있습니다. + +이 글을 통해 블루프린트 세트 생성 몇 편집 방법에 대해 배우게 될 것입니다. 블루프린트 세트의 프로퍼티에 대한 설명 역시 게임 프로젝트에 세트를 최대한 활용하는 데 +도움이 될 것입니다. + +[REGION:note] + +데모 목적 상 (아래 세팅을 적용한) **공백 블루프린트 프로젝트** 를 사용하여 블루프린트 세트 생성 및 편집 방법을 보여드리고 있습니다. + +[REGION:lightbox] + [![](sampleProject.png)(w:370)](sampleProject.png) +[/REGION] + +[REGION:caption] +클릭하면 원본 이미지를 확인합니다. +[/REGION] + +[/REGION] + +## 세트 생성 + +블루프린트 세트를 새로 생성하는 방법은 다음과 같습니다. + +1. 작업할 블루프린트 클래스가 없는 경우, **신규 추가** 버튼으로 새 블루프린트 클래스를 프로젝트에 추가합니다. + + [REGION:lightbox] + [![](creatingSets_Step1.png)(w:600)](creatingSets_Step1.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 이제 **부모 클래스 선택** 메뉴에 표시되는 클래스 목록에서 **Actor** 를 선택합니다. + + ![](creatingSets_Step2.png) + +1. 액터 클래스 이름을 지은 후, 계속해서 **콘텐츠 브라우저** 안에 새로 생성된 액터 클래스를 더블 클릭하여 엽니다. + + [REGION:lightbox] + [![](creatingSets_Step3.png)(w:600)](creatingSets_Step3.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 액터의 블루프린트 스크립트 편집을 시작하려면, **이벤트 그래프** 탭을 선택합니다. + + [REGION:lightbox] + [![](creatingSets_Step4.png)(w:600)](creatingSets_Step4.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 액터의 **이벤트 그래프** 가 열린 상태로 마우스 커서를 **변수** 서브메뉴에 올리면 **+ 변수** 버튼이 드러납니다. + + [REGION:lightbox] + [![](creatingSets_Step5.png)(w:600)](creatingSets_Step5.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 새로운 **String** 변수를 생성하고 이름을 `MyStringSet` 라 합니다. + + [REGION:lightbox] + [![](creatingSets_Step6.png)(w:600)](creatingSets_Step6.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 현재 `MyStringSet` 은 단일 **String** 변수입니다. `MyStringSet` 를 **Set** 컨테이너로 변환하려면, 액터의 **디테일 패널** 내 **Variable Type** (변수 유형) 라벨 오른편에 위치한 **Variable Type** (변수 유형) 버튼을 클릭합니다. + + [REGION:lightbox] + [![](creatingSets_Step7.png)(w:600)](creatingSets_Step7.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 나타나는 드롭다운 메뉴에 네 가지 컨테이너 옵션이 표시됩니다. **{ }** 옵션을 선택하면 `MyStringSet` 가 블루프린트 세트로 변환됩니다. + + ![](creatingSets_Step8.png) + +좋습니다, 이제 막 새로운 String Set 컨테이너를 만들었습니다 (이름은 `MyStringSet`). + +![](creatingSets_Step9.png) + +## 세트 편집 + +새로 생성된 세트 편집을 하려면, Set 변수 컨테이너를 캡슐화시킨 블루프린트를 컴파일해야 합니다. + +[REGION:lightbox] +[![](creatingSets_Step10.png)(w:600)](creatingSets_Step10.png) +[/REGION] + +[REGION:caption] +클릭하면 원본 이미지를 확인합니다. +[/REGION] + +1. `MyStringSet` 를 편집하려면, 블루프린트의 **컴파일** 버튼을 클릭합니다. + + [REGION:lightbox] + [![](creatingSets_Step11.png)(w:600)](creatingSets_Step11.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 블루프린트를 컴파일한 이후 Set 의 (**디테일** 패널에 위치한) **Default Value** (기본 값)에 `MyStringSet` 이 공백임을 알 수 있습니다. + + [REGION:lightbox] + [![](creatingSets_Step12.png)(w:600)](creatingSets_Step12.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 새로운 String 엘리먼트를 `MyStringSet` 에 추가하려면, **디테일** 패널 **Default Value** 메뉴의 **0 Set elements** 옆에 위치한 **+** 버튼을 클릭합니다. + + ![](creatingSets_Step13.png) + +1. 계속해서 **+** 버튼을 다시 한 번 누릅니다. + + ![](creatingSets_Step14.png) + + [REGION:warning] + 새로운 엘리먼트의 기본 값을 업데이트하기 전 블루프린트 Set 에 엘리먼트를 추가하려 하면 언리얼 에디터에서 경고가 날 것입니다. + ![](Step14_Warning.png) + [/REGION] + +1. `MyStringSet` 에 엘리먼트를 셋 추가하고, 이름을 `Apple`, `Banana`, `Cherry` 라 합니다. + + ![](creatingSets_Step15.png) + +1. 이제 엘리먼트를 하나 더 추가하고, 이름을 `Banana` 라 합니다. + + ![](creatingSets_Step16.png) + + [REGION:warning] + 기존 값과 같은 값으로 새 엘리먼트를 추가하려 하면 언리얼 에디터에서 경고가 날 것입니다. + + ![](Step16_Warning.png) + [/REGION] + +1. 앞서 말한 경고를 염두에 두고, 계속해서 네 번째 엘리먼트 `Date` 를 추가합니다. + +잘 하셨습니다! 이제 새로운 블루프린트 Set 를 추가하고, 엘리먼트 넷을 추가 및 편집했습니다. + +![](creatingSets_Step17.png) + +## 컨테이너 프로퍼티 + +UE4 에서 블루프린트 Set 사용을 시작하려면 다음 프로퍼티 목록을 참고하세요. + +* 세트의 아이템( 또는 엘리먼트)는 고유해야 합니다. +* 세트의 모든 항목은 정의(초기화)되어야 합니다 . +* 내부적으로 세트에 저장된 아이템은 순서가 없습니다. +* 세트의 모든 아이템은 동질성입(유형이 동일합)니다. +* 세트의 아이템 추가, 제거, 검색 작업은 빠릅니다. +* 세트의 아이템 값은 검색에 사용되는 키이기도 합니다. +* 현재 블루프린트 세트는 변경불가(immutable)합니다. 생성한 후에는 변경할 수 없다는 뜻입니다. + +블루프린트에서 세트를 생성 및 편집하는 법을 배웠으니, [](Engine/Blueprints/UserGuide/Sets/SetNodes) 참고서에서 블루프린트 Set 노드 인터페이스에 대해 더욱 자세히 배워보실 수 있습니다. + diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Timelines/Timelines.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Timelines/Timelines.INT.udn index 443bdf14a6f6..fc6e370468fe 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Timelines/Timelines.INT.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Timelines/Timelines.INT.udn @@ -6,6 +6,7 @@ version: 4.9 Parent:Engine/Blueprints type:overview tags:Blueprints +topic-image:timeline_topic.png ![k2_timeline_demo.png](k2_timeline_demo.png) diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Timelines/Timelines.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Timelines/Timelines.JPN.udn index b5a439d33d12..736cdbe1746d 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Timelines/Timelines.JPN.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Timelines/Timelines.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3244370 +INTSourceChangelist:3467293 Availability:Public Title:Timelines ノード Crumbs: %ROOT%, Engine, Engine/Blueprints, Engine/Blueprints/UserGuide @@ -7,6 +7,7 @@ version:4.9 Parent:Engine/Blueprints type:overview tags:Blueprints +topic-image:timeline_topic.png ![k2_timeline_demo.png](k2_timeline_demo.png) diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Timelines/Timelines.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Timelines/Timelines.KOR.udn index 03320d7d2b6b..995072cf5efd 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Timelines/Timelines.KOR.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Timelines/Timelines.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3244370 +INTSourceChangelist:3467293 Availability:Public Title: 타임라인 Crumbs: %ROOT%, Engine, Engine/Blueprints, Engine/Blueprints/UserGuide @@ -7,6 +7,7 @@ version: 4.9 Parent:Engine/Blueprints type:overview tags:Blueprints +topic-image:timeline_topic.png ![k2_timeline_demo.png](k2_timeline_demo.png) diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Variables/Bitmask/Bitmask.INT.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Variables/Bitmask/Bitmask.INT.udn index 731ebc617d69..84f55fad530a 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Variables/Bitmask/Bitmask.INT.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Variables/Bitmask/Bitmask.INT.udn @@ -7,6 +7,7 @@ skilllevel:Intermediate Parent:Engine/Blueprints type:overview tags:Blueprints +Topic-image:BitmaskBlueprintVariables_topic.png [TOC (start:2)] diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Variables/Bitmask/Bitmask.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Variables/Bitmask/Bitmask.JPN.udn index e143ab340306..ab49d23e7b09 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Variables/Bitmask/Bitmask.JPN.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Variables/Bitmask/Bitmask.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3244370 +INTSourceChangelist:3467293 Availability:Public Title:Bitmask ブループリント変数 Crumbs: %ROOT%, Engine, Engine/Blueprints, Engine/Blueprints/Scripting @@ -8,6 +8,7 @@ skilllevel:Intermediate Parent:Engine/Blueprints type:overview tags:Blueprints +Topic-image:BitmaskBlueprintVariables_topic.png [TOC (start:2)] @@ -19,7 +20,7 @@ tags:Blueprints **ブループリント エディタ** で _ブループリント クラス_ を使っていれば、すべての Integer 変数を bitmask として作成および宣言することができます。 1. _ブループリント enum エディタ_ で **[Bitmask Flags]** 属性をオンに切り替えて、 -ビットフラグ enum である_Blueprint Enumeration_ を作成します。`BitmaskEnum=` メタデータを使って C++ で設定された、既存のビットフラグ enum 型も使用できます。メタデータ +ビットフラグ enum である _Blueprint Enumeration_ を作成します。`BitmaskEnum=` メタデータを使って C++ で設定された、既存のビットフラグ enum 型も使用できます。 ![image alt text](image_4.png) @@ -29,7 +30,7 @@ tags:Blueprints C++ コードの `Bitmask` メタデータに相当します。 -1. **[Details (詳細)]** パネルの **[Bitmask Enum]** ドロップダウン メニューから_Blueprint Enumeration_ (または既存のビットフラグ enum) を選択します。 +1. **[Details (詳細)]** パネルの **[Bitmask Enum]** ドロップダウン メニューから _Blueprint Enumeration_ (または既存のビットフラグ enum) を選択します。 ![image alt text](image_5.png) diff --git a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Variables/Bitmask/Bitmask.KOR.udn b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Variables/Bitmask/Bitmask.KOR.udn index 6b40eeb96b8d..c99ada62e765 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Variables/Bitmask/Bitmask.KOR.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/UserGuide/Variables/Bitmask/Bitmask.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3244370 +INTSourceChangelist:3467293 Availability:Public Title:비트마스크 블루프린트 변수 Crumbs: %ROOT%, Engine, Engine/Blueprints, Engine/Blueprints/Scripting @@ -8,6 +8,7 @@ skilllevel:Intermediate Parent:Engine/Blueprints type:overview tags:Blueprints +Topic-image:BitmaskBlueprintVariables_topic.png [TOC (start:2)] diff --git a/Engine/Documentation/Source/Engine/Blueprints/Workflow/Workflow.JPN.udn b/Engine/Documentation/Source/Engine/Blueprints/Workflow/Workflow.JPN.udn index 00d1f888153e..d964ebb8b017 100644 --- a/Engine/Documentation/Source/Engine/Blueprints/Workflow/Workflow.JPN.udn +++ b/Engine/Documentation/Source/Engine/Blueprints/Workflow/Workflow.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3042570 +INTSourceChangelist:3244370 Availability:Public Title:Blueprint Workflow ツール Crumbs: %ROOT%, Engine, Engine/Blueprints @@ -6,6 +6,7 @@ Description:コメント付けおよびブレークポイントなどのツー version:4.9 parent:Engine/Blueprints order:3 +tags:Blueprints [VAR:Topic] [OBJECT:Topic] @@ -47,7 +48,7 @@ order:3 [/VAR] -ブループリントで作業する際に、グラフへのコメント付け、プロジェクト内のすべてのブループリント対象の検索、ブレークポイントによるシステムのデバッグという主要ツールを使用することができます。 +ブループリントの作業では、グラフへのコメント追加、プロジェクト内のすべてのブループリントの検索、ブレークポイントによるシステムのデバッグという主要ツールを使うことができます。 [DIR(output:"listbutton" parent:"Engine/Blueprints/Workflow")] diff --git a/Engine/Documentation/Source/Engine/Components/Components.INT.udn b/Engine/Documentation/Source/Engine/Components/Components.INT.udn index 6a277264f56e..a2c20c4c0fb9 100644 --- a/Engine/Documentation/Source/Engine/Components/Components.INT.udn +++ b/Engine/Documentation/Source/Engine/Components/Components.INT.udn @@ -5,40 +5,8 @@ Description: A compendium of the different types of Components designed to be us version: 4.9 parent:Engine/Editor order:6 - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![](components_topic.png) - [/PARAM] - [PARAM:title] - %Engine\Components:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine\Components] - [/PARAM] - [PARAM:description] - %Engine\Components:description% - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![](components_topic.png) - [/PARAM] - [PARAM:title] - %Engine\Components:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine\Components] - [/PARAM] - [PARAM:description] - %Engine\Components:description% - [/PARAM] -[/OBJECT] -[/VAR] +type:landing +topic-image:components_topic.png [INCLUDE:Shared\Glossary\C#glossary_component] @@ -65,24 +33,7 @@ Without Component instancing, all Component variables would need to be declared There are several different types of Components that can be added to an Actor, refer to the links below for more information: -[OBJECT:TopicButtonList] - [PARAM:links] - * [](Engine\Components\AI "%Engine\Components\AI:description%") - * [](Engine\Components\Audio "%Engine\Components\Audio:description%") - * [](Engine\Components\Camera "%Engine\Components\Camera:description%") - * [](Engine\Components\Lights "%Engine\Components\Lights:description%") - * [](Engine\Components\Movement "%Engine\Components\Movement:description%") - * [](Engine/Components/Navigation "%Engine/Components/Navigation:description%") - * [](Engine\Components\Paper2D "%Engine\Components\Paper2D:description%") - * [](Engine\Components\Physics "%Engine\Components\Physics:description%") - * [](Engine\Components\Rendering "%Engine\Components\Rendering:description%") - * [](Engine\Components\Shapes "%Engine\Components\Shapes:description%") - * [](Engine\Components\SkeletalMesh "%Engine\Components\SkeletalMesh:description%") - * [](Engine\Components\StaticMesh "%Engine\Components\StaticMesh:description%") - * [](Engine\Components\Utility "%Engine\Components\Utility:description%") - * [](Engine\Components\Widget "%Engine\Components\Widget:description%") - [/PARAM] -[/OBJECT] +[DIR(output:"topic" parent:"Engine/Components" org:"hierarchy" end:"1")] [REGION:note] You can also refer to the [Components](https://docs.unrealengine.com/latest/INT/API/Runtime/Engine/Components/index.html) section of the [Unreal Engine API Reference](https://docs.unrealengine.com/latest/INT/API/index.html) for additional Components. diff --git a/Engine/Documentation/Source/Engine/Components/Components.JPN.udn b/Engine/Documentation/Source/Engine/Components/Components.JPN.udn index dedf58e99d66..7a0d03e8060f 100644 --- a/Engine/Documentation/Source/Engine/Components/Components.JPN.udn +++ b/Engine/Documentation/Source/Engine/Components/Components.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429239 Availability:Public Title:コンポーネント Crumbs:%ROOT%, Engine @@ -6,40 +6,8 @@ Description:Description:アクタ内のサブオブジェクトとして使用 version:4.9 parent:Engine/Editor order:6 - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![](components_topic.png) - [/PARAM] - [PARAM:title] - %Engine\Components:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine\Components] - [/PARAM] - [PARAM:description] - %Engine\Components:description% - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![](components_topic.png) - [/PARAM] - [PARAM:title] - %Engine\Components:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine\Components] - [/PARAM] - [PARAM:description] - %Engine\Components:description% - [/PARAM] -[/OBJECT] -[/VAR] +type:landing +topic-image:components_topic.png [INCLUDE:Shared\Glossary\C#glossary_component] @@ -66,24 +34,7 @@ order:6 多様なコンポーネントをアクタへ追加することができます。詳細は以下のリンクを参照してください。 -[OBJECT:TopicButtonList] - [PARAM:links] - * [](Engine\Components\AI "%Engine\Components\AI:description%") - * [](Engine\Components\Audio "%Engine\Components\Audio:description%") - * [](Engine\Components\Camera "%Engine\Components\Camera:description%") - * [](Engine\Components\Lights "%Engine\Components\Lights:description%") - * [](Engine\Components\Movement "%Engine\Components\Movement:description%") - * [](Engine/Components/Navigation "%Engine/Components/Navigation:description%") - * [](Engine\Components\Paper2D "%Engine\Components\Paper2D:description%") - * [](Engine\Components\Physics "%Engine\Components\Physics:description%") - * [](Engine\Components\Rendering "%Engine\Components\Rendering:description%") - * [](Engine\Components\Shapes "%Engine\Components\Shapes:description%") - * [](Engine\Components\SkeletalMesh "%Engine\Components\SkeletalMesh:description%") - * [](Engine\Components\StaticMesh "%Engine\Components\StaticMesh:description%") - * [](Engine\Components\Utility "%Engine\Components\Utility:description%") - * [](Engine\Components\Widget "%Engine\Components\Widget:description%") - [/PARAM] -[/OBJECT] +[DIR(output:"topic" parent:"Engine/Components" org:"hierarchy" end:"1")] [REGION:note] 上記以外のコンポーネントについては、 [アンリアル エンジンAPI リファレンス](https://docs.unrealengine.com/latest/INT/API/index.html) の [コンポーネント](https://docs.unrealengine.com/latest/INT/API/Runtime/Engine/Components/index.html) セクションをご覧いただくこともできます。 diff --git a/Engine/Documentation/Source/Engine/Components/Components.KOR.udn b/Engine/Documentation/Source/Engine/Components/Components.KOR.udn index ede6cdd349d2..7d7bbf3d5af9 100644 --- a/Engine/Documentation/Source/Engine/Components/Components.KOR.udn +++ b/Engine/Documentation/Source/Engine/Components/Components.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429239 Availability:Public Title:컴포넌트 Crumbs:%ROOT%, Engine @@ -6,40 +6,8 @@ Description:Component, 컴포넌트란 액터 안에 서브 오브젝트로 사 version: 4.9 parent:Engine/Editor order:6 - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![](components_topic.png) - [/PARAM] - [PARAM:title] - %Engine\Components:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine\Components] - [/PARAM] - [PARAM:description] - %Engine\Components:description% - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![](components_topic.png) - [/PARAM] - [PARAM:title] - %Engine\Components:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine\Components] - [/PARAM] - [PARAM:description] - %Engine\Components:description% - [/PARAM] -[/OBJECT] -[/VAR] +type:landing +topic-image:components_topic.png [INCLUDE:Shared\Glossary\C#glossary_component] @@ -66,24 +34,7 @@ order:6 액터에 추가할 수 있는 컴포넌트 유형은 여러가지 있으며, 자세한 정보는 아래 링크를 참고하세요: -[OBJECT:TopicButtonList] - [PARAM:links] - * [](Engine\Components\AI "%Engine\Components\AI:description%") - * [](Engine\Components\Audio "%Engine\Components\Audio:description%") - * [](Engine\Components\Camera "%Engine\Components\Camera:description%") - * [](Engine\Components\Lights "%Engine\Components\Lights:description%") - * [](Engine\Components\Movement "%Engine\Components\Movement:description%") - * [](Engine/Components/Navigation "%Engine/Components/Navigation:description%") - * [](Engine\Components\Paper2D "%Engine\Components\Paper2D:description%") - * [](Engine\Components\Physics "%Engine\Components\Physics:description%") - * [](Engine\Components\Rendering "%Engine\Components\Rendering:description%") - * [](Engine\Components\Shapes "%Engine\Components\Shapes:description%") - * [](Engine\Components\SkeletalMesh "%Engine\Components\SkeletalMesh:description%") - * [](Engine\Components\StaticMesh "%Engine\Components\StaticMesh:description%") - * [](Engine\Components\Utility "%Engine\Components\Utility:description%") - * [](Engine\Components\Widget "%Engine\Components\Widget:description%") - [/PARAM] -[/OBJECT] +[DIR(output:"topic" parent:"Engine/Components" org:"hierarchy" end:"1")] [REGION:note] 다른 컴포넌트에 대한 정보는 [Unreal Engine API Reference](https://docs.unrealengine.com/latest/INT/API/index.html) 의 [Components](https://docs.unrealengine.com/latest/INT/API/Runtime/Engine/Components/index.html) 섹션을 참고하세요. diff --git a/Engine/Documentation/Source/Engine/Components/Haptic/HapticComponents.JPN.udn b/Engine/Documentation/Source/Engine/Components/Haptic/HapticComponents.JPN.udn index 5f501184af8c..c09584758f21 100644 --- a/Engine/Documentation/Source/Engine/Components/Haptic/HapticComponents.JPN.udn +++ b/Engine/Documentation/Source/Engine/Components/Haptic/HapticComponents.JPN.udn @@ -1,17 +1,17 @@ -INTSourceChangelist:0 +INTSourceChangelist:3340410 Availability:Documents -Title:Haptic Components +Title:Haptic コンポーネント Crumbs:%ROOT%, Engine, Engine/Components -Description:Description of the Force Feedback Component is provided. -Related: Gameplay/ForceFeedback -version: 4.15 +Description:Force Feedback コンポーネントの説明 +Related:Gameplay/ForceFeedback +version:4.15 -The **Force Feedback Component** gives any **Actor** in the world the ability to act as a source of [Force Feedback](Gameplay/ForceFeedback). +**Force Feedback コンポーネント** は、ワールドの **Actor** に、 [フォース フィードバック](Gameplay/ForceFeedback) のソースになる機能を与えます。 -## Force Feedback Component +## Force Feedback コンポーネント [EXCERPT:WhatIsForceFeedbackComponent] -The Force Feedback Component expands on the standard force feedback implementation by adding the concept of attenuation based on relative location in the world. Like sound or light, the intensity of the force experienced by the player will change with the player's distance from the source, according to a data-defined attenuation setting. The addition of attenuation makes it easy to create effects like explosions that feel more powerful at close range, trains that shake the ground with greater strength when the player is standing right next to the tracks, or even a character's "sixth sense" when passing close by to an object of interest. +Force Feedback コンポーネントは、標準のフォース フィードバック実装を、ワールドでの相対位置に基づいた減衰の概念を加えて拡張したものです。サウンドや光のように、プレイヤーが感じる力の強さはプレイヤーがソースからどれくらい離れているかによってデータで定義されている減衰設定に従い変化します。減衰を加えることで、近い範囲にいるほど迫力がある爆発、プレイヤーが線路の近くに立っていると地面を大きく振動させる電車、あるいは関心のあるオブジェクトの近くを通るときのキャラクターが感じる第六感などのエフェクトを作るのが簡単になります。 [/EXCERPT:WhatIsForceFeedbackComponent] -For usage information, including detail on Force Feedback assets, please see the [Force Feedback page](Gameplay/ForceFeedback). +Force Feedback アセットの詳細を含む使用に関する情報は、 [ForceFeedback のページ](Gameplay/ForceFeedback) をご覧ください。 diff --git a/Engine/Documentation/Source/Engine/Components/Rendering/CableComponent/CableComponent.CHN.udn b/Engine/Documentation/Source/Engine/Components/Rendering/CableComponent/CableComponent.CHN.udn index bcf151ca2cf4..55b5212fed59 100644 --- a/Engine/Documentation/Source/Engine/Components/Rendering/CableComponent/CableComponent.CHN.udn +++ b/Engine/Documentation/Source/Engine/Components/Rendering/CableComponent/CableComponent.CHN.udn @@ -1,94 +1,218 @@ -INTSourceChangelist:0 +INTSourceChangelist:3375296 Availability:Public -Title:Cable Component -Crumbs:%ROOT%, Engine -Description: A break down of the Cable Component. -version: 4.15 -parent:Engine/Editor +Title:缆绳组件(Cable Component) +Crumbs:%ROOT% +Description:缆绳组件详解。 +version:4.15 +parent:Engine/Components/Rendering +order: +type:overview +tags:Components +tags:Rendering +SkillLevel:Advanced ![](CC_InGame.png) [TOC(start:1 end:2)] -Having the ability to cheaply add cables, ropes or chains that can sway back and forth as if being gently blown by the wind can add a nice bit of life to your Unreal Engine 4 (UE4) projects. In the following document, we will take a look at how you can use the Cable component plugin to create, setup and control how the cables look, react and even collided with objects in your levels. +以较低的开销添加来回晃荡的缆绳、绳索或链条(类似被风吹动的效果)后,虚幻引擎 4(UE4)项目中便会拥有更加生动的效果。在以下文档中,我们将了解如何使用 **缆绳组件(Cable Component)** 插件创建、设置和控制缆绳的外观、响应,甚至使其和关卡中的物体发生碰撞。 -## Simulation & Rendering +## 模拟和渲染 -To perform the actual cable simulation, a technique very well known to game development called **Verlet Integration** is used. The idea is to represent the cable as a series of particles, with **distance constraints** between them. The particles at the ends are **fixed** and move with whatever they are attached to. The ones in the middle are **free** and fall under gravity. Each step, you update the velocity and position of each particle, and then move them to satisfy the constraints. The **stiffness** of the cable is controlled by the number of times we iterate to enforce the constraints, each step. +实际执行缆绳模拟的是游戏开发界十分著名的技术 **韦尔莱算法(Verlet Integration)**。这种算法的概念是用一系列粒子代表缆绳,而粒子与粒子之间则拥有 **距离约束**。两端的粒子为 **固定**,随附着的物体进行移动。中间的粒子则为 **自由**,随重力而下垂。每一步均会更新每个粒子的速度和位置,并移动粒子满足约束。缆绳的 **刚性** 由迭代执行约束(每步)的次数而定。 [REGION:lightbox] [![](CC_ParticleRope.png)(w:600)](CC_ParticleRope.png) [/REGION] [REGION:caption] -Click for full image. +点击查看全图。 [/REGION] -Now that there is a nice chain of connected particles bouncing around, they now need to be rendered. To render the cable, a new class called **FCableSceneProxy** was created to represent the render of the cable. Then at each from the new particles positions from the simulation (which is done on the main thread inside TickComponent) are passed to this proxy via the **SendRenderDynamicData_Concurrent** function. Next, on the render thread, the update is locked, and then index and vertex buffers are updated to make a **tube** mesh. For each vertex on this tube mesh, we need to calculate a position, a Texture UV and three Tangent Basis vectors. When doing this, **X** will point along the cable, **Z** will point straight out from the cable (the normal) and **Y** is perpendicular to **X** and **Z**. These properties have been exposed to the components giving you the ability to control the number of sides, radius if the tube and how many times the UV's can title along the cable. +拥有完善的相连粒子链后,即可对其进行渲染。渲染缆绳时将创建一个名为 **FCableSceneProxy** 的类,代表缆绳的渲染。模拟粒子位置(在主线程上的 TickComponent 中执行)的每个端将通过 **SendRenderDynamicData_Concurrent** 函数传至此代理。接下来,更新将锁定在渲染线程上,之后将更新索引和顶点缓存,因此形成一个 **管道** 模型。我们需要对此管道模型上的每个顶点计算一个位置、一个纹理 UV 和三个切线基础矢量。执行此操作时,**X** 的朝向沿缆绳,**Z** 的朝向从缆绳(法线)向外,而 **Y** 则与 **X** 和 **Z** 垂直。这些属性已经对组件公开,以便用户控制面的数量,管道的半径,以及 UV 沿缆绳进行平铺的次数。 [REGION:lightbox] [![](CC_RenderingGeo.png)(w:600)](CC_RenderingGeo.png) [/REGION] [REGION:caption] -Click for full image. +点击查看全图。 [/REGION] -## Enabling the Plug-in +## 启用插件 -By default, the Cable Component plugin should be enabled. However, if it is not, you can enable it by first going to the main toolbar and selecting **Edit** > **Plugins**. Then from the plugins list, go to **Rendering** and make sure the **Cable Component** has a checkmark in the box next to **Enabled**. +缆绳组件插件默认启用。如未启用,可在主工具栏中选择 **Edit** > **Plugins**。然后在插件列表中选择 **Rendering**,将 **Cable Component** 的 **Enabled** 勾选框勾选。 [REGION:lightbox] [![](CC_PluginEnable.png)(w:505)](CC_PluginEnable.png) [/REGION] [REGION:caption] -Click for full image. +点击查看全图。 [/REGION] -## Using the Cable Component +## 使用缆绳组件 -To use the Cable Component in your Blueprints you will need to do the following: +可以两种不同方式将缆绳组件添加到项目关卡。在以下部分,我们将说明为项目关卡添加缆绳的两种不同方法。 -1. First, create a new Blueprint called **BP_Cable** and make sure that it uses **Actor** as the parent class. +### 从 Modes 面板中使用缆绳组件 + +如从 Modes 面板中使用缆绳组件,需要执行以下操作: + +1. 首先确保 **Modes** 面板为显示状态,然后在 **Search Classes** 框中输入 `Cable`。 + + ![](CC_Find_In_Modes.png) + +1. 如要将缆绳 Actor 添加到世界场景,点击 Modes 面板中的缆绳 Actor 并将其拖入关卡。 + + [REGION:lightbox] + [![](CC_Add_CC_From_Modes.png)(w:700)](CC_Add_CC_From_Modes.png) + [/REGION] + + [REGION:caption] + 点击查看全图。 + [/REGION] + +1. 现在便可放置、旋转和缩放缆绳 Actor,使其满足关卡的需求。 + + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 640 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 360 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + 8sAwYlKV_ao + [/PARAMLITERAL] + [/OBJECT] + +### 在蓝图中使用缆绳组件 + +如要在蓝图中使用缆绳组件,需要执行以下操作: + +1. 首先新建一个名为 **BP_Cable** 的蓝图,使其以 **Actor** 用作父类。 ![](CC_MakeNewBP.png) -1. Next, from the **Components** section of the BP_Cable Blueprint, click on the **Add Component** button and then locate the **Cable** component in the list. When located, click on it to add it to the Components list. +1. 然后从 BP_Cable 蓝图的 **Components** 部分点击 **Add Component** 按钮,然后在列表中找到 **Cable** 组件。找到组件后,点击将其添加至组件列表。 ![](CC_Add_CC.png) -1. With the Cable Component now added, select the **Cable** component in the components list so that you can adjust its properties via the **Details** panel. +1. 添加缆绳组件后,在组件列表中选择 **Cable** 组件,以便通过 **Details** 面板调整其属性。将其他设置保留为默认,然后编译并保存蓝图。 ![](CC_Cable_Options.png) -1. Check both the **Enable Stiffness** and **Enable Collision** options so that the cable will have some stiffness and collide with the world and then press the **Compile** button. + [region:note] + 取消勾选缆绳组件 Details 面板中的 **Attach Start** 或 **Attach End** 选项即可使缆绳的任意一头下坠。此操作可在游戏运行时进行,以匹配效果。 + [/region] + +1. 在 **Content Browser** 中找到缆绳蓝图,然后将其拖入关卡。放置后,即可使用移动和旋转工具根据需求调整位置。 + + [REGION:lightbox] + [![](CC_Add_BP_CC.png)(w:700)](CC_Add_BP_CC.png) + [/REGION] + + [REGION:caption] + 点击查看全图。 + [/REGION] + +## 在缆绳末端附加物体 + +可在缆绳的任意一端附加物体,使其沿缆绳晃动。需要执行以下步骤在 UE4 中实现此功能: + +1. 首先需要添加一个 **缆绳 Actor** 和一个 **静态网格体** 到关卡中。 + + [REGION:lightbox] + [![](CC_Add_CC_And_SM.png)(w:500)](CC_Add_CC_And_SM.png) + [/REGION] + + [REGION:caption] + 点击查看全图。 + [/REGION] + + [region:note] + 必须将附加到末端的静态网格体的 **Mobility** 设为 **Moveable**。 + [/region] + +1. 在 World Outliner 中找到需要附加到缆绳 Actor 末端的静态网格体,然后将其拖至缆绳 Actor 的上方。执行此操作后将显示以下输入窗口。 + + [REGION:lightbox] + [![](CC_Attach_To_End.png)(w:500)](CC_Attach_To_End.png) + [/REGION] + + [REGION:caption] + 点击查看全图。 + [/REGION] + +1. 选择 **Cable End** 选项,即可在视口中看到静态网格体附着到缆绳 Actor 的末端。 + + [OBJECT:ComparisonSlider] + [PARAM:before] + ![Before](CC_Attach_Before.png) + [/PARAM] + [PARAM:after] + ![After](CC_Attach_After.png) + [/PARAM] + [/OBJECT] + +1. 在关卡中选中缆绳 Actor。然后在 **Details** 面板的 **Cable** 部分中,取消勾选 **Attach End** 框。 + + [REGION:lightbox] + [![](CC_Remove_ATE.png)(w:300)](CC_Remove_ATE.png) + [/REGION] + + [REGION:caption] + 点击查看全图。 + [/REGION] + + [region:note] + 注意:**Attach Start** 和 **Attach End** 选项并非将缆绳附加到 Actor 的唯一方法。也可指定一个用作附着点的套接字。 + [/region] + +1. 执行此操作后,缆绳便能在视口中自由回荡。 + + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 640 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 360 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + 3auyPSMCGcE + [/PARAMLITERAL] + [/OBJECT] + + [region:note] + 注意:可在运行时开启/关闭 **Attach Start** 和 **Attach End** 布尔,制造出一些有趣的效果。 + [/region] + +## 碰撞和刚性 + +[region:warning] +启用碰撞和刚性将极大增加缆绳 Actor 的开销。建议只在以下情况下启用:缆绳和世界场景中的物体发生碰撞,或需要为缆绳赋予刚性获得更佳效果。如无此类需求,则最好将这些选项禁用,以节约性能。 +[/region] + +缆绳组件拥有让缆绳和世界场景发生碰撞的选项,控制缆绳的刚度。为启用此功能,请按以下步骤操作。 + +1. 首先,在缆绳组件 Details 面板的 Cable 部分下按下白色小三角形显示高级卷栏选项。 + + ![](CC_Advanced_Options.png) + +1. 勾选 **Enable Stiffness** 和 **Enable Collision** 选项启用这些功能。 [REGION:lightbox] [![](CC_Added_CC.png)(w:700)](CC_Added_CC.png) [/REGION] [REGION:caption] - Click for full image. + 点击查看全图。 [/REGION] - [region:note] - You will need to press the small white triangle to expand the advanced rollout option to see and use these features. - [/region] - -1. Drag the BP_Cable Blueprint from the Content Browser into your level and position it so that the cable will collide with an object that has been placed in the level. - - [REGION:lightbox] - [![](CC_Add_CC_To_Level.png)(w:700)](CC_Add_CC_To_Level.png) - [/REGION] - - [REGION:caption] - Click for full image. - [/REGION] - -1. Select the BP_Cable Blueprint that was placed in the level and drag it around. While doing this, you should notice that the cable will collide with any mesh that it touches like in the video below. +1. 现在,移动缆绳 Actor 或物体与缆绳 Actor 发生碰撞时,缆绳将和接触到的物体发生碰撞。 [OBJECT:EmbeddedVideo] [PARAMLITERAL:width] @@ -102,60 +226,53 @@ To use the Cable Component in your Blueprints you will need to do the following: [/PARAMLITERAL] [/OBJECT] - [region:note] - To make either side of the cable fall un-check the **Attach Start** or **Attach End** option the Details panel of the Cable Component. - [/region] +## 属性详解 -## Property Breakdown - -The following table breaks down of what each of the properties on the Cable component does: +下表详细说明了缆绳组件上的每个属性: #### Cable ![](CC_Cable_Properties.png) +| 属性名称 | 描述| |-------------|----------------| -|**Property Name**| **Description**| -|Attach Start| Should we fix the start to something, or leave it free. If false, component transform is just used for initial location of the start of cable.| -|Attach End|Should we fix the end to something (using AttachEndTo and EndLocation), or leave it free. If false, AttachEndTo and EndLocation are just used for initial location of end of cable.| -|Attach End To| Actor or Component that the defines the end position of the cable.| -|Component Property| Name of component property to attach the cable to.| -|Attach End To Socket Name| Socket name on the AttachEndTo component to attach to.| -|End Location| End location of cable, relative to AttachEndTo (or AttachEndToSocketName) if specified, otherwise relative to cable component.| -|Cable Length| Rest length of the cable.| -|Num Segments| How many segments the cable has.| -|Solver Iterations| The number of solver iterations controls how 'stiff' the cable is.| -|Substep Time| Controls the simulation substep time for the cable.| -|Enable Stiffness| Add stiffness constraints to cable.| -|Enable Collision| EXPERIMENTAL. Perform sweeps for each cable particle, each substep, to avoid collisions with the world. Uses the Collision Preset on the component to determine what is collided with.This greatly increases the cost of the cable simulation.| +|**Attach Start**| 修复到物体的头端,或放任不管。如为 false,组件变形只用于缆绳头端的初始位置。| +|**Attach End**| 修复到物体的末端(使用 AttachEndTo 和 EndLocation),或放任不管。如为 false,AttachEndTo 和 EndLocation 只用于缆绳末端的初始位置。| +|**Attach End To**| 定义缆绳最终位置的 Actor 或组件。| +|**Component Property**| 附加缆绳的组件属性的命名。| +|**Attach End To Socket Name**| 进行附加的 AttachEndTo 组件上的套接字命名。| +|**End Location**| 缆绳的最终位置,如经指定则相对于 AttachEndTo(或 AttachEndToSocketName),否则则相对于缆绳组件。| +|**Cable Length**| 缆绳的静止长度。| +|**Num Segments**| 缆绳拥有的分段数量。| +|**Solver Iterations**| 解算器迭代的数量,控制缆绳的刚度。| +|**Substep Time**| 控制缆绳的模拟分步时间。 +|**Enable Stiffness**| 为缆绳添加刚性约束。| +|**Enable Collision**| 在每个分步为每个缆绳粒子执行清扫,避免与世界场景发生碰撞。使用组件上的 Collision Preset 决定碰撞的对象。这会极大提高缆绳模拟的开销。[REGION:note]这在当前版本中仍为实验性功能。[/REGION]| ### Cable Forces ![](CC_CableForces_Properties.png) +| 属性名称 | 描述| |-------------|----------------| -|**Property Name**| **Description**| -|Cable Forces|Force vector (world space) applied to all particles in cable.| -|Cable Gravity Scale|Scaling applied to world gravity affecting this cable.| +|**Cable Forces**|应用到缆绳中所有粒子的力矢量(世界空间)。| +|**Cable Gravity Scale**|应用到此缆绳的世界重力比例。| ### Cable Rendering ![](CC_CableRendering_Options.png) +| 属性名称 | 描述| |-------------|----------------| -|**Property Name**| **Description**| -|Cable Width|How wide the cable geometry is.| -|Num Sides|Number of sides of the cable geometry.| -|Tile Material|How many times to repeat the material along the length of the cable.| +|**Cable Width**|缆绳几何体的宽度。| +|**Num Sides**|缆绳几何体的面数。| +|**Tile Material**|沿缆绳长重复材质的次数。| +## 额外参考 -## Reference +以下部分为外部参考,可在此获得缆绳组件的更多灵感。阅读以下 Thomas Jakobsen 的文章,了解 **韦尔莱算法** 的更多详情。 -The following section contains links to various reference documents where you can read more about the papers used to power the cable components. - -* To read more about **Verlet Integration** check out the following paper from Thomas Jakobsen. - - * [http://graphics.cs.cmu.edu/nsp/course/15-869/2006/papers/jakobsen.htm](http://graphics.cs.cmu.edu/nsp/course/15-869/2006/papers/jakobsen.htm) +* [http://graphics.cs.cmu.edu/nsp/course/15-869/2006/papers/jakobsen.htm](http://graphics.cs.cmu.edu/nsp/course/15-869/2006/papers/jakobsen.htm) diff --git a/Engine/Documentation/Source/Engine/Components/Rendering/CableComponent/CableComponent.INT.udn b/Engine/Documentation/Source/Engine/Components/Rendering/CableComponent/CableComponent.INT.udn index 0d11e087b424..76746cd7c7e9 100644 --- a/Engine/Documentation/Source/Engine/Components/Rendering/CableComponent/CableComponent.INT.udn +++ b/Engine/Documentation/Source/Engine/Components/Rendering/CableComponent/CableComponent.INT.udn @@ -1,20 +1,25 @@ Availability:Public Title:Cable Component -Crumbs:%ROOT%, Engine +Crumbs:%ROOT% Description: A breakdown of the Cable Component. version: 4.15 -parent:Engine/Editor +parent:Engine/Components/Rendering +order: +type:overview +tags:Components +tags:Rendering +SkillLevel:Advanced ![](CC_InGame.png) [TOC(start:1 end:2)] -Having the ability to cheaply add cables, ropes or chains that can sway back and forth as if being gently blown by the wind can add a nice bit of life to your Unreal Engine 4 (UE4) projects. In the following document, we will take a look at how you can use the Cable component plugin to create, setup and control how the cables look, react and even collided with objects in your levels. +Having the ability to cheaply add cables, ropes, or chains that can sway back and forth as if being gently blown by the wind can add a nice bit of life to your Unreal Engine 4 (UE4) projects. In the following document, we will take a look at how you can use the **Cable Component** plugin to create, setup and control how the cables look, react and even collide with objects in your levels. -## Simulation & Rendering +## Simulation and Rendering -To perform the actual cable simulation, a technique very well known to game development called **Verlet Integration** is used. The idea is to represent the cable as a series of particles, with **distance constraints** between them. The particles at the ends are **fixed** and move with whatever they are attached to. The ones in the middle are **free** and fall under gravity. Each step, you update the velocity and position of each particle, and then move them to satisfy the constraints. The **stiffness** of the cable is controlled by the number of times we iterate to enforce the constraints, each step. +To perform the actual cable simulation, a technique called **Verlet Integration**, which is well known in game development. The idea is to represent the cable as a series of particles, with **distance constraints** between them. The particles at the ends are **fixed**, moving with whatever they are attached to. The ones in the middle are **free**, falling with gravity. For each step, you update the velocity and position of each particle, and then move them to satisfy the constraints. The **stiffness** of the cable is controlled by the number of times we iterate to enforce the constraints (each step). [REGION:lightbox] [![](CC_ParticleRope.png)(w:600)](CC_ParticleRope.png) @@ -24,7 +29,7 @@ To perform the actual cable simulation, a technique very well known to game deve Click for full image. [/REGION] -Now that there is a nice chain of connected particles bouncing around, they now need to be rendered. To render the cable, a new class called **FCableSceneProxy** was created to represent the render of the cable. Then at each from the new particles positions from the simulation (which is done on the main thread inside TickComponent) are passed to this proxy via the **SendRenderDynamicData_Concurrent** function. Next, on the render thread, the update is locked, and then index and vertex buffers are updated to make a **tube** mesh. For each vertex on this tube mesh, we need to calculate a position, a Texture UV, and three Tangent Basis vectors. When doing this, **X** will point along the cable, **Z** will point straight out from the cable (the normal) and **Y** is perpendicular to **X** and **Z**. These properties have been exposed to, the components giving you the ability to control the number of sides, radius if the tube and how many times the UV's can title along the cable. +Now that there is a nice chain of connected particles bouncing around, they need to be rendered. To render a cable, a class called **FCableSceneProxy** was created to represent the render of the cable. Each end of the Sim particles' positions (done on the main thread, inside of TickComponent) are then passed to this proxy via the **SendRenderDynamicData_Concurrent** function. Next, update is locked on the render thread, and then the index and vertex buffers are updated, thereby making a **tube** mesh. For each vertex on this tube mesh, we need to calculate a position, a Texture UV, and three Tangent Basis vectors. When doing this, **X** will point along the cable, **Z** will point straight out from the cable (the normal) and **Y** is perpendicular to **X** and **Z**. These properties have been exposed to the components, giving you the ability to control the number of sides, the radius of the tube, and how many times the UVs can tile along the cable. [REGION:lightbox] [![](CC_RenderingGeo.png)(w:600)](CC_RenderingGeo.png) @@ -37,7 +42,7 @@ Click for full image. ## Enabling the Plug-in -By default, the Cable Component plugin should be enabled. However, if it is not, you can enable it by first going to the main toolbar and selecting **Edit** > **Plugins**. Then from the plugins list, go to **Rendering** and make sure the **Cable Component** has a checkmark in the box next to **Enabled**. +By default, the Cable Component plugin should be enabled. However, if it is not, you can enable it by first going to the main toolbar and selecting **Edit** > **Plugins**. Then, from the plugins list, go to **Rendering** and make sure the **Cable Component** has a checkmark in the box next to **Enabled**. [REGION:lightbox] [![](CC_PluginEnable.png)(w:505)](CC_PluginEnable.png) @@ -49,14 +54,13 @@ Click for full image. ## Using the Cable Component - -You can Cable Components to your projects levels in two different ways. In the following section, we will go over the two different ways that you can add cables to your projects levels. +You can add Cable Components to your projects levels in two different ways. In the following section, we will go over the two different ways that you can add cables to your project's levels. ### Using Cable Components from the Modes Pannel To use the Cable Component from the Modes Panel, you will need to do the following: -1. First, make sure that the **Modes** panel is visible and then in the **Search Classes** box, input the word **Cable**. +1. First, make sure that the **Modes** panel is visible, and then in the **Search Classes** box, input the word `Cable`. ![](CC_Find_In_Modes.png) @@ -70,7 +74,7 @@ To use the Cable Component from the Modes Panel, you will need to do the followi Click for full image. [/REGION] -1. You can now position, rotate and scale the Cable Actor so that it fits the needs of your level. +1. You can now position, rotate, and scale the Cable Actor so that it fits the needs of your level. [OBJECT:EmbeddedVideo] [PARAMLITERAL:width] @@ -96,15 +100,15 @@ To use the Cable Component in your Blueprints, you will need to do the following ![](CC_Add_CC.png) -1. With the Cable Component now added, select the **Cable** component in the components list so that you can adjust its properties via the **Details** panel. For now, leave everything as the default and make sure to Compile and Save your Blueprint. +1. With the Cable Component now added, select the **Cable** component in the components list, so that you can adjust its properties via the **Details** panel. For now, leave everything as the default and make sure to Compile and Save your Blueprint. ![](CC_Cable_Options.png) [region:note] - To make either side of the cable fall un-check the **Attach Start** or **Attach End** option the Details panel of the Cable Component. This can also be toggled while the game is running to go along with effects. + To make either side of the cable fall, un-check the **Attach Start** or **Attach End** option the Details panel of the Cable Component. This can also be toggled while the game is running to go along with effects. [/region] -1. Locate your Cable Blueprint in the Content Browser and then drag it into the level. Once placed you can use the move and rotate tools to position it to your needs. +1. Locate your Cable Blueprint in the **Content Browser**, and then drag it into the level. Once placed, you can use the move and rotate tools to position it as needed. [REGION:lightbox] [![](CC_Add_BP_CC.png)(w:700)](CC_Add_BP_CC.png) @@ -116,9 +120,9 @@ To use the Cable Component in your Blueprints, you will need to do the following ## Attaching Objects to the Cable ends -You can also attach objects to either end of the cable so that the objects will swing along with the cable. To accomplish this in your UE4 projects all you need to do the following: +You can also attach objects to either end of the cable so that the objects will swing along with the cable. To accomplish this in your UE4 projects, all you need to do is the following: -1. You will first need to add a Cable Actor and a Static Mesh to the level. +1. You will first need to add a **Cable Actor** and a **Static Mesh** to the level. [REGION:lightbox] [![](CC_Add_CC_And_SM.png)(w:500)](CC_Add_CC_And_SM.png) @@ -132,7 +136,7 @@ You can also attach objects to either end of the cable so that the objects will Make sure that the Static Mesh that you are attaching to the end has its **Mobility** set to **Moveable**. [/region] -1. Locate the Static Mesh you want to attach to the end of the Cable Actor in the World Outliner and then drag it on top of the Cable Actor. After doing this, the following input window will be displayed. +1. Locate the Static Mesh you want to attach to the end of the Cable Actor in the World Outliner, and then drag it on top of the Cable Actor. After doing this, the following input window will be displayed. [REGION:lightbox] [![](CC_Attach_To_End.png)(w:500)](CC_Attach_To_End.png) @@ -153,7 +157,7 @@ You can also attach objects to either end of the cable so that the objects will [/PARAM] [/OBJECT] -1. Now select the Cable Actor in the level. Then in the **Details** panel under the **Cable** section, uncheck the **Attach End** box. +1. Now, select the Cable Actor in the level. Then, in the **Details** panel under the **Cable** section, uncheck the **Attach End** box. [REGION:lightbox] [![](CC_Remove_ATE.png)(w:300)](CC_Remove_ATE.png) @@ -185,15 +189,14 @@ You can also attach objects to either end of the cable so that the objects will Note that you can dynamically toggle the **Attach Start** and **Attach End** bools at run time, which can make for some interesting effects. [/region] -## Collision & Stiffness - -The Cable Component does have the option to have the cable collide with the world and also control how stiff the cable is. To enable this functionality, you will need to do the following: - +## Collision and Stiffness [region:warning] -Enabling Collision and Stiffness will greatly increase the cost of the Cable Actor. Only enable these features if the cable has to collide with something in the world or if the cable needs some stiffness to help make the effect look better. If none of that is needed, it is best to keep these options disabled to save performance. +Enabling Collision and Stiffness will greatly increase the cost of the Cable Actor. Only enable these features if the cable has to collide with something in the world, or if the cable needs some stiffness to help make the effect look better. If none of that is needed, it is best to keep these options disabled to save performance. [/region] +The Cable Component does have the option to have the cable collide with the world, controlling how stiff the cable is. To enable this functionality, you will need to do the following: + 1. First, in the Details of the Cable Component under the Cable section, press the small white triangle to expose the advanced rollout option. ![](CC_Advanced_Options.png) @@ -208,7 +211,7 @@ Enabling Collision and Stiffness will greatly increase the cost of the Cable Act Click for full image. [/REGION] -1. Now when you move the Cable Actor around or if an object collides with the Cable Actor the cable should collide with the object that it comes in contact with. +1. Now, when you move the Cable Actor around, or if an object collides with, the Cable Actor the cable should collide with the object that it comes in contact with. [OBJECT:EmbeddedVideo] [PARAMLITERAL:width] @@ -224,54 +227,51 @@ Enabling Collision and Stiffness will greatly increase the cost of the Cable Act ## Property Breakdown -The following table breaks down of what each of the properties on the Cable component does: +The following table breaks down each of the properties on the Cable Component: #### Cable ![](CC_Cable_Properties.png) +|Property Name| Description| |-------------|----------------| -|**Property Name**| **Description**| -|Attach Start| Should we fix the start to something, or leave it free. If false, component transform is just used for initial location of the start of cable.| -|Attach End|Should we fix the end to something (using AttachEndTo and EndLocation), or leave it free. If false, AttachEndTo and EndLocation are just used for initial location of end of cable.| -|Attach End To| Actor or Component that the defines the end position of the cable.| -|Component Property| Name of component property to attach the cable to.| -|Attach End To Socket Name| Socket name on the AttachEndTo component to attach to.| -|End Location| End location of cable, relative to AttachEndTo (or AttachEndToSocketName) if specified, otherwise relative to cable component.| -|Cable Length| Rest length of the cable.| -|Num Segments| How many segments the cable has.| -|Solver Iterations| The number of solver iterations controls how 'stiff' the cable is.| -|Substep Time| Controls the simulation substep time for the cable.| -|Enable Stiffness| Add stiffness constraints to cable.| -|Enable Collision| EXPERIMENTAL. Perform sweeps for each cable particle, each substep, to avoid collisions with the world. Uses the Collision Preset on the component to determine what is collided with.This greatly increases the cost of the cable simulation.| +|**Attach Start**| Should we fix the start to something, or leave it free. If false, component transform is just used for initial location of the start of cable.| +|**Attach End**|Should we fix the end to something (using AttachEndTo and EndLocation), or leave it free. If false, AttachEndTo and EndLocation are just used for initial location of end of cable.| +|**Attach End To**| Actor or Component that defines the end position of the cable.| +|**Component Property**| Name of component property to attach the cable to.| +|**Attach End To Socket Name**| Socket name on the AttachEndTo component to attach to.| +|**End Location**| End location of cable, relative to AttachEndTo (or AttachEndToSocketName) if specified, otherwise relative to cable component.| +|**Cable Length**| Rest length of the cable.| +|**Num Segments**| How many segments the cable has.| +|**Solver Iterations**| The number of solver iterations controls how 'stiff' the cable is.| +|**Substep Time**| Controls the simulation substep time for the cable.| +|**Enable Stiffness**| Add stiffness constraints to cable.| +|**Enable Collision**| Perform sweeps for each cable particle at each substep, to avoid collisions with the world. Uses the Collision Preset on the component to determine what is collided with.This greatly increases the cost of the cable simulation. [REGION:note]This is currently Experimental.[/REGION]| ### Cable Forces ![](CC_CableForces_Properties.png) +|Property Name| Description| |-------------|----------------| -|**Property Name**| **Description**| -|Cable Forces|Force vector (world space) applied to all particles in cable.| -|Cable Gravity Scale|Scaling applied to world gravity affecting this cable.| +|**Cable Forces**|Force vector (world space) applied to all particles in cable.| +|**Cable Gravity Scale**|Scaling applied to world gravity affecting this cable.| ### Cable Rendering ![](CC_CableRendering_Options.png) +|Property Name| Description| |-------------|----------------| -|**Property Name**| **Description**| -|Cable Width|How wide the cable geometry is.| -|Num Sides|Number of sides of the cable geometry.| -|Tile Material|How many times to repeat the material along the length of the cable.| +|**Cable Width**|How wide the cable geometry is.| +|**Num Sides**|Number of sides of the cable geometry.| +|**Tile Material**|How many times to repeat the material along the length of the cable.| +## Additional Reference -## Reference +The following section sends you to an external reference, where you can read more about the inspriration behind cable components. To read more about **Verlet Integration**, check out the following paper from Thomas Jakobsen: -The following section contains links to various reference documents where you can read more about the papers used to power the cable components. - -* To read more about **Verlet Integration** check out the following paper from Thomas Jakobsen. - - * [http://graphics.cs.cmu.edu/nsp/course/15-869/2006/papers/jakobsen.htm](http://graphics.cs.cmu.edu/nsp/course/15-869/2006/papers/jakobsen.htm) +* [http://graphics.cs.cmu.edu/nsp/course/15-869/2006/papers/jakobsen.htm](http://graphics.cs.cmu.edu/nsp/course/15-869/2006/papers/jakobsen.htm) diff --git a/Engine/Documentation/Source/Engine/Components/Rendering/CableComponent/CableComponent.JPN.udn b/Engine/Documentation/Source/Engine/Components/Rendering/CableComponent/CableComponent.JPN.udn index df120c926eae..c07b8ccd5b5d 100644 --- a/Engine/Documentation/Source/Engine/Components/Rendering/CableComponent/CableComponent.JPN.udn +++ b/Engine/Documentation/Source/Engine/Components/Rendering/CableComponent/CableComponent.JPN.udn @@ -1,159 +1,278 @@ -INTSourceChangelist:0 +INTSourceChangelist:3375296 Availability:Public -Title:Cable Component -Crumbs:%ROOT%, Engine -Description: A break down of the Cable Component. -version: 4.15 -parent:Engine/Editor +Title:Cable コンポーネント +Crumbs:%ROOT% +Description:Cable コンポーネントの説明 +version:4.15 +parent:Engine/Components/Rendering +order: +type:overview +tags:Components +tags:Rendering +SkillLevel:Advanced ![](CC_InGame.png) [TOC(start:1 end:2)] -Having the ability to cheaply add cables, ropes or chains that can sway back and forth as if being gently blown by the wind can add a nice bit of life to your Unreal Engine 4 (UE4) projects. In the following document we will take a look at how you can use the Cable component plugin to create, setup and control how the cables look, react and even collided with objects in your levels. +低負荷でそっと風に吹かれて揺れるケーブル、ロープ、チェーンを追加する機能を使うと、UE4 プロジェクトが生き生きとしたものになります。以下では、**Cable コンポーネント** プラグインを使って、ケーブルの外観を作成、セットアップ、制御し、レベル内のオブジェクトに反応し、衝突させる方法について説明します。 -## Simulation & Rendering +## シミュレーションとレンダリング -To perform the actual cable simulation a technique very well know to game development called **Verlet Integration** is used. The idea is to represent the cable as a series of particles, with **distance constraints** between them. The particles at the ends are **fixed** and move with whatever they are attached to. The ones in the middle are **free** and fall under gravity. Each step, you update the velocity and position of each particle, and then move them to satisfy the constraints. The **stiffness** of the cable is controlled by the number of times we iterate to enforce the constraints, each step. +実際のケーブルのシミュレーションには、ゲーム制作で知られている **Verlet Integration (ベレの方法)** という技術を使います。これはケーブルを **距離のコンストレイント** を間に持つ一連のパーティクルとして表す考え方です。最後のパーティクルは **固定** され、アタッチされている任意のものと一緒に動きます。間にあるものは **自由** であり、重力で落ちていきます。各ステップで、各パーティクルのベロシティと位置を更新し、コンストレイントに従い移動します。ケーブルの **剛性** は、コンストレイント (各ステップ) を強化するためのイタレーションの回数でコントロールします。 [REGION:lightbox] [![](CC_ParticleRope.png)(w:600)](CC_ParticleRope.png) [/REGION] [REGION:caption] -Click for full image. +クリックしてフルサイズで表示 [/REGION] -Now that there is a nice chain of connected particles bouncing around, they now need to be rendered. To render the cable a new class called **FCableSceneProxy** was created to represent the render of the cable. Then at each from the new particles positions from the simulation (which is done on the main thread inside TickComponent) are passed to this proxy via the **SendRenderDynamicData_Concurrent** function. Next on the render thread the update is locked and then index and vertex buffers are updated to make a **tube** mesh. For each vertex on this tube mesh we need to calculate a position, a Texture UVm and three Tangent Basis vectors. When doing this, **X** will point along the cable, **Z** will point straight out from the cable (the normal) and **Y** is perpendicular to **X** and **Z**. These properties have been exposed on the components giving you the ability to control the number of sides, radius if the tube and how many times the UV's can title along the cable. +チェーン状になった一連のパーティクルがバウンスします。これをレンダリングする必要があります。ケーブルをレンダリングするために、**FCableSceneProxy** というクラスが作成されて、ケーブルのレンダリングをします。Sim パーティクルの位置の各端は (TickComponent 内のメイン スレッドで行われる)、**SendRenderDynamicData_Concurrent** 関数経由でこのプロキシに渡されます。次に、更新はレンダリング スレッドで自動追跡され、次にインデックスと頂点バッファが更新されます。その結果、**tube** メッシュが作られます。このチューブ メッシュの各頂点で、位置、テクスチャ UV、および 3 つのタンジェントベースのベクターを計算する必要があります。これを行う場合、**X** はケーブルに沿ってポイントし、**Z** はケーブルから真っ直ぐポイントし (法線)、**Y** は **X** と **Z** に対して垂直になります。こうしたプロパティはコンポーネントに公開されて、面の数、チューブの半径、およびケーブルにそって UV が何回タイリングされるかを制御する機能があります。 [REGION:lightbox] [![](CC_RenderingGeo.png)(w:600)](CC_RenderingGeo.png) [/REGION] [REGION:caption] -Click for full image. +クリックしてフルサイズで表示 [/REGION] -## Enabling the Plug-in +## プラグインを有効にする -By default the cable component plugin should be enabled. However if it is not you can enable it by first going to the main toolbar and selecting **Edit** > **Plugins**. Then from the plugins list, go to **Rendering** and make sure the **Cable Component** has a checkmark in the box next to **Enabled**. +Cable コンポーネントのプラグインはデフォルトで有効になっています。有効になっていない場合は、メイン ツールバーで、**[Edit]** > **[Plugins]** の順に選択します。次にプラグインのリストから、**[Rendering]** に進み、**[Cable Component]** の **[Enabled]** の隣にあるボックスにチェックを入れるようにします。 [REGION:lightbox] [![](CC_PluginEnable.png)(w:505)](CC_PluginEnable.png) [/REGION] [REGION:caption] -Click for full image. +クリックしてフルサイズで表示 [/REGION] -## Using the Cable Component +## Cable コンポーネントを使用する -To use the cable component in your Blueprints you will need to do the following: +プロジェクトのレベルに Cable コンポーネントを追加するには、2 種類の方法があります。次のセクションでは、こうした方法について説明します。 -1. First, create a new Blueprint called **BP_Cable** and make sure that it uses **Actor** as the parent class. +### モード パネルから Cable コンポーネントを使用する - ![](CC_MakeNewBP.png) +[Modes (モード)] パネルから Cable コンポーネントを使用するには、以下の手順に従います。 -1. Next from the **Components** section of the BP_Cable Blueprint, click on the **Add Component** button and then locate the **Cable** component in the list. When located, click on it to add it to the Components list. +1. **[Modes]** パネルが表示されていることを確認し、 **クラスの検索** ボックスで、`Cable` という言葉を入力します。 - ![](CC_Add_CC.png) + ![](CC_Find_In_Modes.png) -1. With the Cable Component now added, select the **Cable** component in the components list so that you can adjust its properties via the **Details** pannel. +1. Cable アクタをワールドに追加するには、[Modes] パネル で Cable アクタをクリックし、それをレベルにドラッグします。 - ![](CC_Cable_Options.png) + [REGION:lightbox] + [![](CC_Add_CC_From_Modes.png)(w:700)](CC_Add_CC_From_Modes.png) + [/REGION] -1. Check both the **Enable Stiffness** and **Enable Collision** options so that the cable will have some stiffness and collide with the world and the press the **Compile** button. + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] - [REGION:lightbox] - [![](CC_Added_CC.png)(w:700)](CC_Added_CC.png) - [/REGION] +1. Cable アクタを配置、回転、スケーリングしてレベルのニーズに合わせます。 - [REGION:caption] - Click for full image. - [/REGION] + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 640 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 360 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + 8sAwYlKV_ao + [/PARAMLITERAL] + [/OBJECT] - [region:note] - You will need to press the small white triangle to expand the additional options to see and use these features. - [/region] +### ブループリントで Cable コンポーネントを使用する -1. Drag the BP_Cable Blueprint from the Content Browser into your level and position it so that the cable will collide with an object that has been placed in the level. +ブループリントで Cable コンポーネントを使用するには、以下の手順に従います。 - [REGION:lightbox] - [![](CC_Add_CC_To_Level.png)(w:700)](CC_Add_CC_To_Level.png) - [/REGION] +1. まず、**BP_Cable** という新規ブループリントを作成します。このブループリントで **Actor** を親クラスとして使うようにします。 - [REGION:caption] - Click for full image. - [/REGION] + ![](CC_MakeNewBP.png) -1. Select the BP_Cable Blueprint that was placed in the level and drag it around. While doing this you should notice that the cable will collide with any mesh that it touches like in the video below. +1. 次に、BP_Cable ブループリントの **[Components]** セクションから、**[Add Component]** ボタンをクリックして、リストで **Cable** コンポーネントを探します。コンポーネントが見つかったら、クリックしてコンポーネント リストに追加します。 - [OBJECT:EmbeddedVideo] - [PARAMLITERAL:width] - 640 - [/PARAMLITERAL] - [PARAMLITERAL:height] - 360 - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - e18Kr8v-nNI - [/PARAMLITERAL] - [/OBJECT] + ![](CC_Add_CC.png) -## Property Breakdown +1. Cable コンポーネントが追加された状態で、コンポーネント リストで **Cable** コンポーネントを選択し、**[Details]** パネルでプロパティを調整できるようにします。現時点ではすべてをデフォルトのままにして、必ずブループリントをコンパイルおよび保存するようにしてください。 -The following table breaks down of what each of the properties on the Cable component does: + ![](CC_Cable_Options.png) + + [region:note] + ケーブルのいずれかの端が落ちるようにするには、ケーブル コンポーネントの [Details ] パネルで、**[Attach Start]** または ** [Attach End]** のいずれかのオプションのチェックを外します。これはゲーム実行中もエフェクトに合わせて切り替えることができます。 + [/region] + +1. **コンテンツ ブラウザ** で Cable ブループリントを見つけてレベルにドラッグします。配置したら、必要に応じて移動ツールや回転ツールを使って配置します。 + + [REGION:lightbox] + [![](CC_Add_BP_CC.png)(w:700)](CC_Add_BP_CC.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +## ケーブル終端にオブジェクトをアタッチする + +ケーブルのいずれかの端にオブジェクトをアタッチして、ケーブルと一緒にオブジェクトをスイングさせることもできます。UE4 プロジェクトでこの操作を行うには、以下の手順を行うだけです。 + +1. まず **Cable アクタ** と **Static Mesh** をレベルに追加する必要があります。 + + [REGION:lightbox] + [![](CC_Add_CC_And_SM.png)(w:500)](CC_Add_CC_And_SM.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + + [region:note] + 端にアタッチするスタティックメッシュの **[Mobility]** を **[Moveable]** に設定するようにします。 + [/region] + +1. ワールド アウトライナーで Cable アクタの端にアタッチするスタティックメッシュを探して、それを Cable アクタの上にドラッグします。これを行うと、次のような入力ウィンドウが表示されます。 + + [REGION:lightbox] + [![](CC_Attach_To_End.png)(w:500)](CC_Attach_To_End.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **[Cable End]** オプションを選ぶと、ビューポートでスタティックメッシュが Cable アクタの端にスナップしているのがわかります。 + + [OBJECT:ComparisonSlider] + [PARAM:before] + ![Before](CC_Attach_Before.png) + [/PARAM] + [PARAM:after] + ![After](CC_Attach_After.png) + [/PARAM] + [/OBJECT] + +1. レベルで Cable アクタを選択します。次に **[Details]** パネルの **[Cable]** セクションで **[Attach End]** ボックスのチェックを外します。 + + [REGION:lightbox] + [![](CC_Remove_ATE.png)(w:300)](CC_Remove_ATE.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + + [region:note] + ケーブルをアクタにアタッチするには、**Attach Start** と **Attach End** のオプション以外も使用することができます。アタッチメント ポイントとして使用可能なソケットを指定することもできます。 + [/region] + +1. これを行うと、ビューポートでケーブルは自由にスイングするようになります。 + + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 640 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 360 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + 3auyPSMCGcE + [/PARAMLITERAL] + [/OBJECT] + + [region:note] + ランタイムに **Attach Start** と **Attach End** のブールを動的に切り替えることができます。そうすることで面白いエフェクトを作ることができます。 + [/region] + +## コリジョンと剛性 + +[region:warning] +コリジョンと剛性を有効にすると、Cable アクタの負荷が大幅に増えます。ケーブルがワールドで何かと衝突しなければならない場合や、エフェクトの見た目をよくするために剛性が必要な場合に限り、こうした機能を有効にしてください。こうした機能が不要ならば、パフォーマンスを上げるために無効にするとよいでしょう。 +[/region] + +Cable コンポーネントには、ケーブルがどれくらい剛性を持っているかを制御しながら、ワールドでケーブルを衝突させるオプションがあります。この機能を有効にするには、以下の手順を行います。 + +1. まず、Cable コンポーネントの [Details] の [Cable] セクションで、小さな白いトライアングルを押して詳細オプションを展開します。 + + ![](CC_Advanced_Options.png) + +1. **[Enable Stiffness]** と **[Enable Collision]** の両方のオプションにチェックを入れて有効にします。 + + [REGION:lightbox] + [![](CC_Added_CC.png)(w:700)](CC_Added_CC.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. Cable アクタを動かす、またはオブジェクトが衝突すると、Cable アクタすなわちケーブルが接触するオブジェクトと衝突します。 + + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 640 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 360 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + e18Kr8v-nNI + [/PARAMLITERAL] + [/OBJECT] + +## プロパティの内容 + +以下の表は、Cable コンポーネントのプロパティを示したものです。 #### Cable ![](CC_Cable_Properties.png) +|プロパティ名| 説明| |-------------|----------------| -|**Property Name**| **Description**| -|Attach Start| Should we fix the start to something, or leave it free. If false, component transform is just used for initial location of the start of cable.| -|Attach End|Should we fix the end to something (using AttachEndTo and EndLocation), or leave it free. If false, AttachEndTo and EndLocation are just used for initial location of end of cable.| -|Attach End To| Actor or Component that the defines the end position of the cable.| -|Component Property| Name of component property to use.| -|Attach End To Socket Name| Socket name on the AttachEndTo component to attach to.| -|End Location| End location of cable, relative to AttachEndTo (or AttachEndToSocketName) if specified, otherwise relative to cable component.| -|Cable Length| Rest length of the cable.| -|Num Segments| How many segments the cable has.| -|Solver Iterations| The number of solver iterations controls how 'stiff' the cable is.| -|Substep Time| Controls the simulation substep time for the cable.| -|Enable Stiffness| Add stiffness constraints to cable.| -|Enable Collision| EXPERIMENTAL. Perform sweeps for each cable particle, each substep, to avoid collisions with the world. Uses the Collision Preset on the component to determine what is collided with.This greatly increases the cost of the cable simulation.| +|**Attach Start**| ケーブルの始端を何かに修正するか、フリーのままにします。false の場合、コンポーネントのトランスフォームは、ケーブルの始まりの初期位置として使用されます。| +|**Attach End**| ケーブルの終端を何かに修正するか (AttachEndTo および EndLocation を使って)、フリーのままにします。false の場合、AttachEndTo と EndLocation がケーブル終端の初期位置に使われます。| +|**Attach End To**| ケーブルの終わりの位置を定義するアクタまたはコンポーネントです。| +|**Component Property**| ケーブルをアタッチするコンポーネントのプロパティ名です。| +|**Attach End To Socket Name**| アタッチする AttachEndTo コンポーネントのソケットの名前です。| +|**End Location**| ケーブルの終端。指定した場合は、AttachEndTo (または AttachEndToSocketName) に相対的で、そうでなければ Cable コンポーネントに相対的になります。| +|**Cable Length**| 静止したケーブルの長さです。| +|**Num Segments**| ケーブルがいくつセグメントを持っているかです。| +|**Solver Iterations**| ケーブルがどれくらい剛性を持つかを制御するソルバー イタレーションの数です。| +|**Substep Time**| ケーブルのシミュレーション サブステップの時間を制御します。| +|**Enable Stiffness**| 剛性コンストレイントをケーブルに追加します。| +|**Enable Collision**| 各サブステップで各ケーブル パーティクルをスイープし、ワールドとのコリジョンを回避します。このコンポーネントで Collision Preset を使って何を衝突させるかを決めます。これによりケーブルのシミュレーションの負荷が大幅に高くなります。[REGION:note]これは現在、実験的な機能です。[/REGION]| ### Cable Forces ![](CC_CableForces_Properties.png) +|プロパティ名| 説明| |-------------|----------------| -|**Property Name**| **Description**| -|Cable Forces|Force vector (world space) applied to all particles in cable.| -|Cable Gravity Scale|Scaling applied to world gravity affecting this cable.| +|**Cable Forces**|ケーブルのすべてのパーティクルに適用される Force ベクター (ワールド空間) です。| +|**Cable Gravity Scale**|このケーブルに影響を与えるワールドの重力に適用されるスケーリングです。| -### Cable Rendering +### ケーブルのレンダリング ![](CC_CableRendering_Options.png) +|プロパティ名| 説明| |-------------|----------------| -|**Property Name**| **Description**| -|Cable Width|How wide the cable geometry is.| -|Num Sides|Number of sides of the cable geometry.| -|Tile Material|How many times to repeat the material along the length of the cable.| +|**Cable Width**|ケーブル ジオメトリがどれくらいの幅であるかです。| +|**Num Sides**|ケーブル ジオメトリの面の数です。| +|**Tile Material**|ケーブルの長手方向に沿ってマテリアルを何回繰り返すかです。| +## 追加のリファレンス +以下は、Cable コンポーネントに関する詳しい情報が記載されている外部リファレンスです。**Verlet Integration (ベレの方法)** については、Thomas Jakobsen 氏による以下のドキュメントをご覧ください。 - -## Reference - -The following section contains links to various references docs where you can read more about the papers used to power the cable components. - -* To read more about **Verlet Integration** check out the following paper from Thomas Jakobsen. - - * [http://graphics.cs.cmu.edu/nsp/course/15-869/2006/papers/jakobsen.htm](http://graphics.cs.cmu.edu/nsp/course/15-869/2006/papers/jakobsen.htm) +* [http://graphics.cs.cmu.edu/nsp/course/15-869/2006/papers/jakobsen.htm](http://graphics.cs.cmu.edu/nsp/course/15-869/2006/papers/jakobsen.htm) diff --git a/Engine/Documentation/Source/Engine/Components/Rendering/CableComponent/CableComponent.KOR.udn b/Engine/Documentation/Source/Engine/Components/Rendering/CableComponent/CableComponent.KOR.udn index 71ccbc0d3cde..339fac42f1ee 100644 --- a/Engine/Documentation/Source/Engine/Components/Rendering/CableComponent/CableComponent.KOR.udn +++ b/Engine/Documentation/Source/Engine/Components/Rendering/CableComponent/CableComponent.KOR.udn @@ -1,19 +1,24 @@ -INTSourceChangelist:3352412 +INTSourceChangelist:3375296 Availability:Public Title:케이블 컴포넌트 -Crumbs:%ROOT%, Engine +Crumbs:%ROOT% Description: 케이블 컴포넌트에 대한 분석입니다. version: 4.15 -parent:Engine/Editor +parent:Engine/Components/Rendering +order: +type:overview +tags:Components +tags:Rendering +SkillLevel:Advanced ![](CC_InGame.png) [TOC(start:1 end:2)] -바람에 앞뒤로 흔들리는 듯한 케이블, 밧줄, 체인을 저렴한 비용으로 추가할 수 있다면 언리얼 엔진 4 (UE4) 프로젝트에 멋지게 생동감을 불어넣을 수 있을 것입니다. 여기서는 Cable Component (케이블 컴포넌트) 플러그인을 사용하여 레벨의 오브젝트에 반응하고 심지어 충돌도 하는 케이블을 만들고 구성하여 제어하는 법을 알아보겠습니다. +바람에 앞뒤로 흔들리는 듯한 케이블, 밧줄, 체인을 저렴한 비용으로 추가할 수 있다면 언리얼 엔진 4 (UE4) 프로젝트에 멋지게 생동감을 불어넣을 수 있을 것입니다. 여기서는 **Cable Component** (케이블 컴포넌트) 플러그인을 사용하여 레벨의 오브젝트에 반응하고 심지어 충돌도 하는 케이블을 만들고 구성하여 제어하는 법을 알아보겠습니다. -## 시뮬레이션 & 렌더링 +## 시뮬레이션 및 렌더링 실제 케이블 시뮬레이션을 위해 게임 개발에는 아주 잘 알려진 **Verlet Integration** 이라는 기법이 사용됩니다. 케이블을 **distance constraints** (거리 제약)을 사이에 둔 파티클 시리즈로 표현한다는 개념입니다. 끝부분의 파티클은 **fixed** (고정)되어 붙은 것과 함께 움직입니다. 중간의 것들은 **free** (자유)롭게 중력의 영향을 받습니다. 각 단계마다, 각 파티클의 속도와 위치를 업데이트한 뒤, 제약에 만족하도록 이동시킵니다. 케이블 **stiffness** (강성)은 각 단계마다 제약 강화를 위한 반복처리 횟수로 제어합니다. @@ -50,6 +55,42 @@ parent:Engine/Editor ## 케이블 컴포넌트 사용 +프로젝트의 레벨에 케이블 컴포넌트를 추가하는 방법은 두 가지인데, 여기서는 그에 대해 알아보겠습니다. + +### 모드 패널에서 케이블 컴포넌트 사용 + +모드 패널에서 Cable 컴포넌트를 사용하는 방법은 다음과 같습니다: + +1. 먼저 **모드** 패널이 보이는지 확인한 뒤, **클래스 검색** 창에 `Cable` 이라 입력합니다. + + ![](CC_Find_In_Modes.png) + +1. 월드에 Cable 액터를 추가하려면, 모드 패널에서 Cable 액터를 클릭한 뒤 레벨에 끌어놓으면 됩니다. + + [REGION:lightbox] + [![](CC_Add_CC_From_Modes.png)(w:700)](CC_Add_CC_From_Modes.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. 이제 Cable 액터가 레벨에 맞게끔 이동, 회전, 스케일을 조절하면 됩니다. + + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 640 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 360 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + 8sAwYlKV_ao + [/PARAMLITERAL] + [/OBJECT] + +### 블루프린트에서 케이블 컴포넌트 사용 + 블루프린트에서 케이블 컴포넌트를 사용하는 방법은 다음과 같습니다: 1. 먼저 **BP_Cable** 이라는 블루프린트를 새로 만들고 **Actor** 를 부모 클래스로 사용하는지 확인합니다. @@ -60,35 +101,118 @@ parent:Engine/Editor ![](CC_Add_CC.png) -1. 케이블 컴포넌트를 추가한 뒤 컴포넌트 목록에서 **Cable** 컴포넌트를 선택하면 **디테일** 패널에서 프로퍼티를 조정할 수 있습니다. +1. 케이블 컴포넌트를 추가한 뒤 컴포넌트 목록에서 **Cable** 컴포넌트를 선택하면 **디테일** 패널에서 프로퍼티를 조정할 수 있습니다. 현재로서는, 모두 기본값으로 놔두고 블루프린트를 컴파일 및 저장합니다. ![](CC_Cable_Options.png) -1. **Enable Stiffness** 및 **Enable Collision** 옵션 양쪽 다 체크하여 케이블에 강성을 주고 월드와 충돌하도록 한 뒤, **컴파일** 버튼을 누릅니다. + [region:note] + 케이블 한 쪽 끝이 떨어지도록 하려면, 케이블 컴포넌트의 디테일 패널에서 **Attach Start** 또는 **Attach End** 옵션 체크를 해제하면 됩니다. 이펙트와 어울리도록 게임 실행 도중 토글시킬 수도 있습니다. + [/region] + +1. **콘텐츠 브라우저** 에서 케이블 블루프린트를 찾은 뒤, 레벨에 끌어 놓습니다. 배치했으면, 이동 및 회전 툴로 위치를 잡습니다. + + [REGION:lightbox] + [![](CC_Add_BP_CC.png)(w:700)](CC_Add_BP_CC.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +## 케이블 끝에 오브젝트 붙이기 + +케이블 한 쪽 끝에 오브젝트를 붙여 케이블과 같이 흔들리도록 할 수도 있습니다. UE4 프로젝트에서 그러한 효과를 내는 방법은 다음과 같습니다: + +1. 먼저 레벨에 **Cable** 액터와 **스태틱 메시** 를 추가해 줘야 합니다. + + [REGION:lightbox] + [![](CC_Add_CC_And_SM.png)(w:500)](CC_Add_CC_And_SM.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + + [region:note] + 끝에 붙이려는 스태틱 메시의 **모빌리티** 가 **무버블** 로 되어있는지 확인합니다. + [/region] + +1. 월드 아웃라이너에서 케이블 액터 끝에 붙이고자 하는 스태틱 메시를 찾은 뒤, 케이블 액터 위에 끌어 놓습니다. 그렇게 하고나면 다음과 같은 입력 창이 뜹니다. + + [REGION:lightbox] + [![](CC_Attach_To_End.png)(w:500)](CC_Attach_To_End.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + +1. **Cable End** 옵션을 선택하고, 뷰포트에 보면 스태틱 메시가 케이블 액터 끝에 붙어있는 것이 보일 것입니다. + + [OBJECT:ComparisonSlider] + [PARAM:before] + ![Before](CC_Attach_Before.png) + [/PARAM] + [PARAM:after] + ![After](CC_Attach_After.png) + [/PARAM] + [/OBJECT] + +1. 이제 레벨의 케이블 액터를 선택합니다. 그리고 **디테일** 패널에서 **Cable** 섹션 아래 **Attach End** 박스 체크를 해제합니다. + + [REGION:lightbox] + [![](CC_Remove_ATE.png)(w:300)](CC_Remove_ATE.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + + [region:note] + 참고로 **Attach Start** 및 **Attach End** 옵션으로만 케이블을 액터에 붙일 수 있는 것은 아닙니다. 소켓을 지정하여 붙이는 지점으로 사용할 수도 있습니다. + [/region] + +1. 그러면 뷰포트에 케이블이 자유롭게 흔들릴 것입니다. + + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 640 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 360 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + 3auyPSMCGcE + [/PARAMLITERAL] + [/OBJECT] + + [region:note] + **Attach Start** 및 **Attach End** 불리언은 런타임에 동적으로 토글시켜 재미난 효과를 만들 수 있습니다. + [/region] + +## 콜리전 및 강성 + +[region:warning] +Collision (콜리전) 및 Stiffness (강성) 옵션을 켜면 케이블 액터 비용이 크게 상승합니다. 케이블이 월드의 무언가와 충돌해야 하는 경우, 또는 케이블에 강성을 줘서 이펙트를 개선시킬 필요가 있는 경우에만 켜주시기 바랍니다. 그럴 필요가 없으면 이 옵션은 꺼 두는 것이 퍼포먼스에 좋습니다. +[/region] + +케이블 컴포넌트에 케이블이 월드와 충돌하도록 하는 옵션과 케이블 강성을 조절하는 옵션이 있습니다. 이 기능을 켜는 방법은 다음과 같습니다: + +1. 먼저 케이블 컴포넌트의 디테일 패널에서 Cable 섹션 아래 작은 흰색 삼각형을 눌러 고급 옵션을 펼칩니다. + + ![](CC_Advanced_Options.png) + +1. **Enable Stiffness** 및 **Enable Collision** 옵션 둘 다 체크하여 이 기능을 켭니다. [REGION:lightbox] [![](CC_Added_CC.png)(w:700)](CC_Added_CC.png) [/REGION] [REGION:caption] - Click for full image. + 클릭하면 원본 이미지를 확인합니다. [/REGION] - [region:note] - 작은 흰색 삼각형을 눌러 고급 옵션을 펼쳐야 이 기능을 확인하고 사용할 수 있을 것입니다. - [/region] - -1. 콘텐츠 브라우저에서 BP_Cable 블루프린트를 끌어 레벨에 놓은 뒤 케이블이 레벨에 배치된 오브젝트와 충돌하도록 위치를 잡습니다. - - [REGION:lightbox] - [![](CC_Add_CC_To_Level.png)(w:700)](CC_Add_CC_To_Level.png) - [/REGION] - - [REGION:caption] - Click for full image. - [/REGION] - -1. 레벨에 배치된 BP_Cable 블루프린트를 선택하고 끌어봅니다. 아래 비디오처럼 끌려다니는 케이블이 닿은 메시와 충돌하는 것이 보일 것입니다. +1. 이제 케이블 액터를 움직이거나 오브젝트와 충돌할 때, 케이블 액터가 접촉한 오브젝트와 충돌할 것입니다. [OBJECT:EmbeddedVideo] [PARAMLITERAL:width] @@ -102,20 +226,16 @@ parent:Engine/Editor [/PARAMLITERAL] [/OBJECT] - [region:note] - 케이블 한쪽 끝이 떨어지게 만들려면, 케이블 컴포넌트의 디테일 패널에서 **Attach Start** 또는 **Attach End** 옵션 체크를 해제하면 됩니다. - [/region] - ## 프로퍼티 분석 -케이블 컴포넌트의 각 프로퍼티가 하는 역할에 대한 분석은 다음 표와 같습니다: +케이블 컴포넌트에 있는 각 프로퍼티에 대한 분석 표입니다: -### Cable +#### Cable ![](CC_Cable_Properties.png) +|프로퍼티 이름| 설명| |-------------|----------------| -|**프로퍼티 이름**| **설명**| |Attach Start| 붙이기 시작 - 시작 부분을 무언가에 고정시킬지 자유롭게 놔둘지 입니다. false 면, 초기 케이블 시작 위치는 그냥 컴포넌트 트랜스폼을 사용합니다. | |Attach End|붙이기 끝 - 끝 부분을 (AttachEndTo 와 EndLocation 을 사용하여) 무언가에 고정시킬지 자유롭게 놔둘지 입니다. false 면 초기 케이블 끝 위치는 그냥 AttachEndTo 와 EndLocation 을 사용합니다. | |Attach End To| 끝 붙이기 - 케이블 끝 위치를 정의하는 액터 또는 컴포넌트입니다. | @@ -127,14 +247,14 @@ parent:Engine/Editor |Solver Iterations| 솔버 반복처리 수 - 케이블 강성을 나타내는 솔버 반복처리 횟수입니다. | |Substep Time| 서브스텝 시간 - 케이블의 시뮬레이션 서브스텝 시간을 제어합니다. | |Enable Stiffness| 강성 활성화 - 케이블에 강성 제약을 추가합니다. | -|Enable Collision| 콜리전 활성화 - 실험단계 입니다. 각 케이블 파티클, 각 서브스텝 마다 스윕 검사를 실시하여 월드와의 충돌을 피합니다. 컴포넌트에 콜리전 프리셋을 사용하여 콜리전 대상을 결정합니다. 케이블 시뮬레이션 비용이 크게 늘어납니다. | +|Enable Collision| 콜리전 활성화 - 각 케이블 파티클, 각 서브스텝 마다 스윕 검사를 실시하여 월드와의 충돌을 피합니다. 컴포넌트에 콜리전 프리셋을 사용하여 콜리전 대상을 결정합니다. 케이블 시뮬레이션 비용이 크게 늘어납니다. [REGION:note]현재 실험단계 기능입니다.[/REGION]| ### Cable Forces ![](CC_CableForces_Properties.png) +|프로퍼티 이름| 설명| |-------------|----------------| -|**프로퍼티 이름**| **설명**| |Cable Forces|케이블 포스 - 케이블의 모든 파티클게 적용되는 (월드 스페이스) 포스 벡터입니다. | |Cable Gravity Scale|케이블 중력 스케일 - 이 케이블에 영향을 끼치는 월드 중력에 적용되는 스케일입니다. | @@ -142,20 +262,17 @@ parent:Engine/Editor ![](CC_CableRendering_Options.png) +|프로퍼티 이름| 설명| |-------------|----------------| -|**프로퍼티 이름**| **설명**| |Cable Width|케이블 폭 - 케이블 지오메트리 폭입니다. | |Num Sides|면 수 - 케이블 지오메트리 면 수입니다. | |Tile Material|타일 머티리얼 - 케이블 길이상에서 머티리얼을 몇 번이나 반복시킬지 입니다. | +## 추가 자료 -## 참고서 +케이블 컴포넌트 내부적인 작동방식 관련해서 보다 자세히 알아보실 수 있는 외부 참고자료입니다. **Verlet Integration**관련 자세히 알아보려면, Thomas Jakobsen 의 다음 논문을 확인하세요: -케이블 컴포넌트의 기반이 되는 논문에 대해 자세히 알아볼 수 있는 여러가지 참고 문헌에 대한 링크입니다. - -* **Verlet Integration** 관련 자세한 내용은 Thomas Jakobsen 의 논문을 참고하세요. - - * [http://graphics.cs.cmu.edu/nsp/course/15-869/2006/papers/jakobsen.htm](http://graphics.cs.cmu.edu/nsp/course/15-869/2006/papers/jakobsen.htm) +* [http://graphics.cs.cmu.edu/nsp/course/15-869/2006/papers/jakobsen.htm](http://graphics.cs.cmu.edu/nsp/course/15-869/2006/papers/jakobsen.htm) diff --git a/Engine/Documentation/Source/Engine/Components/Rendering/RenderingComponents.JPN.udn b/Engine/Documentation/Source/Engine/Components/Rendering/RenderingComponents.JPN.udn index 96f650e78769..4a34609265c4 100644 --- a/Engine/Documentation/Source/Engine/Components/Rendering/RenderingComponents.JPN.udn +++ b/Engine/Documentation/Source/Engine/Components/Rendering/RenderingComponents.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3350015 Availability:Public Title:Rendering コンポーネント Crumbs:%ROOT%, Engine, Engine/Components @@ -46,13 +46,10 @@ Version:4.9 ## Cable コンポーネント -**Cable コンポーネント** を使用すると、2 つのコンポーネント間のケーブルをレンダリングしながら 2 つのコンポーネントを合わせてアタッチすることができます。ケーブル上で、マテリアルを割り当て、ケーブルがどのように表示されるかに影響を与えるパラメータを定義することができます。 +**Cable コンポーネント** を使用すると、2 つのコンポーネント間のケーブルをレンダリングしながら 2 つのコンポーネントをアタッチすることができます。ケーブル上で、マテリアルを割り当て、ケーブルがどのように表示されるかに影響を与えるパラメータを定義することができます。Cable コンポーネントの詳しい使用方法については、以下のリンクをご覧ください。 -このタイプのコンポーネントの使用例としては、ロープや、プレイヤー キャラクターがぶら下がることができる何かが必要である場合が考えられます。スクリプトで、ひとつのポイントを固定位置にアタッチし、もうひとつのポイントをプレイヤー キャラクターにアタッチすると、キャラクターはロープにぶら下がり揺れます。以下では、銃からケーブルを撃ち込むことができるファースト パーソン キャラクターを使用して、それを衝撃位置にアタッチし、フックガン (grappling gun) のようなものを作ります。 +* [Cable コンポーネントのユーザー ガイド](Engine\Components\Rendering\CableComponent\) -![](cable.png)(w:440) - -この単純なビジュアル要素は、物体を接続するワイヤーをあらわすものなどに使用することもできます。 ## Custom Mesh コンポーネント diff --git a/Engine/Documentation/Source/Engine/Components/Utility/UtilityComponents.JPN.udn b/Engine/Documentation/Source/Engine/Components/Utility/UtilityComponents.JPN.udn index 915b18b68592..0fb069caa205 100644 --- a/Engine/Documentation/Source/Engine/Components/Utility/UtilityComponents.JPN.udn +++ b/Engine/Documentation/Source/Engine/Components/Utility/UtilityComponents.JPN.udn @@ -1,26 +1,64 @@ -INTSourceChangelist:3317795 +INTSourceChangelist:3351045 Availability:Public Title:Utility コンポーネント -Crumbs:%ROOT%, Engine, Engine/Components -Description:ユーティリティ ベースのコンポーネントについて説明します。 +Crumbs: +Description:ユーティリティ ベースのコンポーネントとその使用方法について説明します。 Related:Engine/Blueprints/UserGuide/Components +parent:Engine/Components +order: +tags:Components +type:overview SkillLevel:Beginner Version:4.14 -[TOC (start:2 end:2)] +[TOC (start:1 end:4)] ## ApplicationLifecycle コンポーネント **ApplicationLifecycle コンポーネント** は、アプリケーションのステート (起動、停止、終了など) について OS (オペレーティング システム) から通知を受け取る処理をします。 +## Platform Events コンポーネント + +**PlatformEvent コンポーネント** はプラットフォーム固有の OS 情報やイベントに基づきイベントをポーリングし、受け取る機能があります。現在、このコンポーネントはコンバーチブル ノートパソコンをサポートし、プラットフォームがコンバーチブル ノートパソコンかどうかの情報とそのステート (ノートパソコン モードかタブレット モード) を示します。こうした関数を絶えずポーリングせずにプラットフォームがステートを変更したかを知るために、ステート変更があった場合にコード (またはブループリント) を通知する目的でバインドできるデリゲートもあります。 + ## Child Actor コンポーネント **ChildActor コンポーネント** は、登録時にアクタをスポーンして、登録削除時にアクタを破壊するコンポーネントです。 -ChildActor コンポーネントは、C++ クラスまたは Blueprint アセットを与えることによってスポーンされるアクタを指定します。クラスまたはアセットを選択すると、**Child Actor Template** 入力フィールドが表示されます。この入力フィールドを展開して、ブループリントで宣言されたパブリック変数を含む、指定された子アクタやそのコンポーネントのエクスポーズされ、編集可能な入力フィールドを編集することができます。 +ChildActor コンポーネントは、C++ クラスまたは Blueprint アセットを与えてスポーンされるアクタを指定します。クラスまたはアセットを選択すると、**Child Actor Template** 入力フィールドが表示されます。この入力フィールドを展開して、ブループリントで宣言されているパブリック変数を含む、指定された子アクタやそのコンポーネントのエクスポーズされ、編集可能な入力フィールドを編集することができます。 ![](ChildActorTemplate.png) ##Scene コンポーネント -**Scene コンポーネント** はトランスフォームを持ち、アタッチメント機能をサポートしていますが、レンダリングやコリジョンの機能はありません。他のものをオフセットするために階層で「ダミー」コンポーネントとして役立ちます。 +**Scene コンポーネント** はトランスフォームを持ち、アタッチメント機能をサポートしていますが、レンダリングやコリジョンの機能はありません。他のものをオフセットするために階層で「ダミー」コンポーネントとして役立ちます。または、すべての子コンポーネントがひとつのものであるかのように子コンポーネントとインタラクションするのにも役立ちます。例えば、それらを移動または回転させたり、すべてを可視または不可視にしたり、親子付け解除したりすることができます。Scene コンポーネントを整理ツールとして過度に使用しないことが重要です。それぞれが所有しているアクタをスポーンするために時間とメモリを使うからです。 + +### Arrow コンポーネント + +**Arrow コンポーネント** は、Scene コンポーネントの一種で、ラインで描画される単純な矢印で、向いている方向を表します。Arrow コンポーネントはソケットの位置や方向などのデバッグに特に便利です。ゲーム内のクロス、手持ちまたはアタッチされているオブジェクト、発射物がスポーンされる銃口などで有用です。デフォルトで、こうしたコンポーネントはエディタ内だけで可視になります。インゲームで見たい場合は、Arrow コンポーネントの **[Details]** パネルで `Hidden in Game` チェックボックスのチェックを外してください。 + +![](HiddenInGame_Checkbox.png) + +以下の画像では、Arrow コンポーネントが UE4 のマネキンの index_03_r ボーンにアタッチされています。このボーンは右手の人差し指の末端の関節にあり、2 番めの節に向かってポイントします。キャラクターの指先がどこをポイントしているかを示したい場合はレーザービーム コンポーネントをアタッチします。若干オフセットし、180 度回転するソケットを追加し、アタッチします。レーザー コンポーネントをアタッチする場合、ボーンからオフセットする必要があることを理解してください。 + +![](ArrowComponent.png) + +## Spline コンポーネント + +**Spline コンポーネント** は、レベル内でスプラインを描画します。これは電車、背景のキャラクター、カメラなどの動いているキャラクターのパスを指定する際に特に役立ちます。レベルに配置すると Spline コンポーネントを持つアクタは、近い場所にあるもうひとつのポイントと接続され、コンポーネントの位置でポイントを示します。ラインを右クリックしてその場所に新規ポイントを追加することができます。また、ポイントをクリックして取り除いたり (それが唯一のポイントでない限り)、複製したり、そこからスプラインの次のポイントに続くカーブを変更することができます。複製を使うと、現在のポイントと同じ場所にある新規ポイントを作りますが、ライン上でその後ろにあるとみなされます。スプラインのポイントはレベル内で標準の移動と回転のツールを使って自由に操作することができます。コンポーネントの **[Details]** パネルには `Duration` というフィールドもあります。これは、スプラインをクエリーするための範囲値として機能します。 + +![](Spline_Duration.png) + +スプラインをクエリーするには主に以下の 3 種類の方法があります。 +* ポイント インデックス。この場合、スプラインは長さ方向に沿ってユーザーが配置した任意のポイントの位置や回転などの情報をクエリーすることができます。 +* 距離。この場合、スプラインは設定された距離を移動後、スプラインの回転フォワード ベクターなどの情報をクエリーすることができます。 +* 時間。この場合、スプラインの長さはユーザーが入力した `Duration` 値に置き換えられ、任意の" time" 値でスプラインについての距離、位置、回転の情報をクエリーすることができます。この 3 番めの方法はスプラインで定義されるトラックに沿って移動するカメラのような固定オブジェクトの場合に特に便利です。デザイナーやプログラマーは、カメラの位置と回転について、カメラがスプラインに沿ってどれくらいの距離を移動しているかに基づきクエリーすればよいからです。 +duration を 1.0 に設定し補間のアルファ値を指定することでスプラインに沿って簡単に補間またはブレンドすることができます。 + +次の画像では、Spline コンポーネントを使ってプレイヤーがどこに行くかを示すヒント マーカーを動かしています。 + +![](SplineComponent.png) + +[REGION:note] +Spline コンポーネントで作成したスプラインは、複数のパスにフォークしたり、ループや孤立したポイントは含みません。スプラインは常に単一のパスであり、各スプライン ポイントは一回だけ含まれます。 +[/REGION] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Deployment/Patching/Patching.KOR.udn b/Engine/Documentation/Source/Engine/Deployment/Patching/Patching.KOR.udn index 6fcf2b195ff8..062b243584d6 100644 --- a/Engine/Documentation/Source/Engine/Deployment/Patching/Patching.KOR.udn +++ b/Engine/Documentation/Source/Engine/Deployment/Patching/Patching.KOR.udn @@ -18,7 +18,7 @@ skilllevel: Advanced [/REGION] 기존에 릴리즈한 프로젝트에 대한 패치는 버전 릴리즈를 통해 가능합니다. 염두에 둘 것은: -* 릴리즈 당시 시리얼라이제이션 코드 패쓰를 록 다운 시킵니다. +* 릴리즈 당시 시리얼라이제이션 코드 패스를 록 다운 시킵니다. * 릴리즈된 쿠킹 콘텐츠를 유지합니다. UnrealPak 툴에서 이를 통해 패치 패키지 파일에 넣을 패키지를 결정하기 때문입니다. * 실행시간에 두 pak 파일 모두 마운팅하되, 패치 파일의 우선순위를 높게 하여 그 안의 콘텐츠가 먼저 로드되도록 합니다. diff --git a/Engine/Documentation/Source/Engine/Editor/VR/ActivateVRMode/ActivateVRMode.CHN.udn b/Engine/Documentation/Source/Engine/Editor/VR/ActivateVRMode/ActivateVRMode.CHN.udn index c87982487312..c8b2f1b1af1b 100644 --- a/Engine/Documentation/Source/Engine/Editor/VR/ActivateVRMode/ActivateVRMode.CHN.udn +++ b/Engine/Documentation/Source/Engine/Editor/VR/ActivateVRMode/ActivateVRMode.CHN.udn @@ -1,49 +1,20 @@ -INTSourceChangelist:2950818 +INTSourceChangelist:3350329 Title:启动 VR 模式 Description:学习如何在虚幻编辑器中启用 VR 模式 Crumbs: Availability: public parent:Engine/Editor/VR -type: howto -order:2 +type:how-to +order:1 tags:VR -tags:准备开始 -version:4.11 +tags:Getting Started +version:4.15 skilllevel: intermediate +topic-image:activate_topic.png -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Editor/VR/ActivateVRMode:title%](Engine/Editor/VR/ActivateVRMode/activate_topic.png) - [/PARAM] - [PARAM:title] - %Engine/Editor/VR/ActivateVRMode:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Editor/VR/ActivateVRMode] - [/PARAM] - [PARAM:description] - %Engine/Editor/VR/ActivateVRMode:description% - [/PARAM] -[/OBJECT] -[/VAR] +[TOC(start:1 end:4)] -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Editor/VR/ActivateVRMode:title%](Engine/Editor/VR/ActivateVRMode/activate_topic.png) - [/PARAM] - [PARAM:title] - %Engine/Editor/VR/ActivateVRMode:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Editor/VR/ActivateVRMode] - [/PARAM] - [PARAM:description] - %Engine/Editor/VR/ActivateVRMode:description% - [/PARAM] -[/OBJECT] -[/VAR] +从虚幻引擎 4.12 版本开始,引擎版本已包含VR(虚拟现实)编辑模式,可通过 Epic Games Launcher 进行访问。也可从 [GitHub](Engine/Editor/VR/Setup) 获取最新版本。 [EXCERPT:main] @@ -51,7 +22,7 @@ skilllevel: intermediate ![](vr_map_template.png) -1. 在 Editor Preferences(**Edit > Editor Preferences**)中,选择 **Experimental** 类目,然后选中 **Enable VR Editing**。 +1. 在 **Editor Preferences** 菜单(**Edit > Editor Preferences**)中,选择 **Experimental** 类目,然后选中 **Enable VR Editing**。 1. 点击编辑器主工具栏上的 **VR** 按钮即可启动 VR 模式。如果追踪空间已正确校正,您会看到一个漂浮的教程窗口,以及部分帮助说明。 @@ -62,6 +33,53 @@ skilllevel: intermediate [/REGION] 1. 如需使用此教程,将控制器放置在需要阅读的部分上,按下扳机键即可打开此部分。 -随时按下 Home 键均可返回此菜单,可选择其他部分进行阅读。 +随时按下 **Home** 键均可返回主教程菜单,选择其他部分进行阅读。 [/EXCERPT:main] + +## 自动 VR 编辑模式 + +从 4.13 版本开始,用户可自动进入 VR 编辑模式。只要编辑器在前台中且编辑器已启用,用户带上头戴显示器后便会自动进入 VR 编辑模式。取下头戴显示器后则会离开 VR 编辑模式。 + +[OBJECT:EmbeddedVideo] +[PARAMLITERAL:width] +640 +[/PARAMLITERAL] +[PARAMLITERAL:height] +360 +[/PARAMLITERAL] +[PARAMLITERAL:videoid] +cZJmh881FCo +[/PARAMLITERAL] +[/OBJECT] + +### 启用或禁用 VR 编辑模式自动进入 + +1. 在 **Edit** 菜单中点击 **Editor Preferences** 查看虚幻编辑器选项。 + + ![](EditorPref.png) +1. 在 **General** 标题下选择 **Experimental** 部分,找到包含 VR 编辑器选项的 **VR** 类目。 + + ![](ExperimentalVR.png) +1. 开启/关闭 **Enable VR Mode Auto-Entry** 选项和禁用或启用自动进入功能。 + + ![](AutoEntryMenu_Highlight.png) + + +## VR 编辑器教程窗口 + +从 4.14 版本开始,每次进入 VR 编辑模式开始新会话时用户可以启用或禁用 VR 编辑器教程窗口的显示。 + +![](VRTutorialWindow.png)(w:500) + +###启用或禁用 VR 编辑器内含教程窗口 + +1. 在 **Edit** 菜单中点击 **Editor Preferences** 查看虚幻编辑器选项。 + + ![](EditorPref.png) +1. 在 **General** 标题下选择 **Experimental** 部分,找到包含 VR 编辑器选项的 **VR** 类目。 + + ![](ExperimentalVR.png) +1. 开启/关闭 **Always Show VR Tutorial at Start** 选项禁用或启用 VR 教程窗口。 + + ![](InEditorTutorial.png) diff --git a/Engine/Documentation/Source/Engine/Editor/VR/ActorInteraction/ActorInteraction.KOR.udn b/Engine/Documentation/Source/Engine/Editor/VR/ActorInteraction/ActorInteraction.KOR.udn index a455ece91cb0..56e42c45b42d 100644 --- a/Engine/Documentation/Source/Engine/Editor/VR/ActorInteraction/ActorInteraction.KOR.udn +++ b/Engine/Documentation/Source/Engine/Editor/VR/ActorInteraction/ActorInteraction.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3350329 +INTSourceChangelist:3360829 Title: VR 모드에서 액터 작업 Description: VR 모드에서 작업시 액터 배치, 트랜스폼, 변경 방법을 배워봅니다. Crumbs: @@ -8,11 +8,10 @@ type:how-to order: 4 tags: VR tags: Level Editing -version: 4.11 +version: 4.15 skilllevel: intermediate topic-image:actorinteraction.png prereq:Engine/Editor/VR/ActivateVRMode -prereq:Engine/Editor/VR/Setup [TOC(start:1 end:4)] diff --git a/Engine/Documentation/Source/Engine/Editor/VR/Controls/VREditorControls.KOR.udn b/Engine/Documentation/Source/Engine/Editor/VR/Controls/VREditorControls.KOR.udn index 41923863bf16..ee3658015468 100644 --- a/Engine/Documentation/Source/Engine/Editor/VR/Controls/VREditorControls.KOR.udn +++ b/Engine/Documentation/Source/Engine/Editor/VR/Controls/VREditorControls.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3351610 +INTSourceChangelist:3360829 Availability: Public Title: VR 에디터 조작법 Description: VR 모드에서 월드 제작 작업시 사용되는 여러가지 조작법과 상호작용 방식에 대해 배워봅니다. @@ -11,7 +11,6 @@ version: 4.15 skilllevel: intermediate topic-image:vreditor_controls.png prereq:Engine/Editor/VR/ActivateVRMode -prereq:Engine/Editor/VR/Setup [TOC(start:1 end:4)] diff --git a/Engine/Documentation/Source/Engine/Editor/VR/EditorUI/EditorUIVR.KOR.udn b/Engine/Documentation/Source/Engine/Editor/VR/EditorUI/EditorUIVR.KOR.udn index 5b0881228615..cb296d6a65d2 100644 --- a/Engine/Documentation/Source/Engine/Editor/VR/EditorUI/EditorUIVR.KOR.udn +++ b/Engine/Documentation/Source/Engine/Editor/VR/EditorUI/EditorUIVR.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3350329 +INTSourceChangelist:3360829 Title: VR 모드에서의 에디터 창 Description: VR 모드 작업시 에디터 패널과 창을 띄우고 작업하는 방법입니다. Crumbs: @@ -7,11 +7,11 @@ parent: Engine/Editor/VR type: reference order: 5 tags: VR -version: 4.13 +version: 4.15 skilllevel: intermediate topic-image:editorui_topic.png prereq:Engine/Editor/VR/ActivateVRMode -prereq:Engine/Editor/VR/Setup + [TOC(start:1 end:4)] diff --git a/Engine/Documentation/Source/Engine/Editor/VR/GDC2017/VREditorGDC2017.CHN.udn b/Engine/Documentation/Source/Engine/Editor/VR/GDC2017/VREditorGDC2017.CHN.udn index 849b4c2ab6cc..1582a09b2aeb 100644 --- a/Engine/Documentation/Source/Engine/Editor/VR/GDC2017/VREditorGDC2017.CHN.udn +++ b/Engine/Documentation/Source/Engine/Editor/VR/GDC2017/VREditorGDC2017.CHN.udn @@ -1,240 +1,247 @@ -INTSourceChangelist:0 -Availability:Docs -Title: VR & Mesh Editor GDC 2017 Features Preview +INTSourceChangelist:3350329 +Availability:Public +Title: GDC 2017 VR 和网格体编辑器功能前瞻 Crumbs: -Description: +Description: 预览部分在 GDC 2017 展出的 VR 和网格体编辑器功能。 Parent:Engine/Editor/VR +type: reference +order: 1000 +topic-image:gdp_topic.png reference-image:snapping.gif reference-image:vr_contentBrowser.gif reference-image:vr_contextOption.gif reference-image:vr_radialMenu.gif +prereq:Engine/Editor/VR/ActivateVRMode +prereq:Engine/Editor/VR/Setup + +[TOC(start:1 end:4)] -We are so excited about the latest additions to the VR Editor and Mesh Editor, we couldn't wait to get it into your hands! So, we have made the GDC 2017 Features Branch available in an experimental build through GitHub! This builds contains all of the VR Editor and Mesh Editor features demonstrated at the **State of Unreal** keynote at the 2017 Game Developers Conference. +VR 编辑器和网格体编辑器的最新更新让人激动万分,我们已经迫不及待把它们送到您手中!因此我们通过 GitHub 发布了一个内带 GDC 2017 功能分支的实验性版本!此版本包含 GDC 2017 **State of Unreal** 主题演讲中展示的所有 VR 编辑器和网格体编辑器。 ![image alt text](image_0.gif)(h:320) ![](poly_extrude.png)(h:320) ![](poly_extrude_subd.png)(h:320) [REGION:note] -The VR Editor and Mesh Editor are experimental features. For this particular release, features were tested exclusively on Windows, so there may be complications compiling for Mac or Linux. +VR 编辑器和网格体编辑器为实验性功能。此特殊版本中的功能只针对 Windows 进行了测试,因此针对 Mac 或 Linux 进行编译时可能出现问题。 [/REGION] -## Major Features +## 主要功能 -* Mesh Editor Mode enables manipulating Static Meshes within Unreal Editor, including using subdivision surfaces! -* The Sequencer non-linear editing tool is now available in VR Mode -* Redesigned Radial Menu with context sensitive actions -* Smart Snapping allows for quickly and accurately placing objects relative to other assets in the level -* Ability to save Static Mesh changes made during Simulate Mode +* 网格体编辑器模式(Mesh Editor Mode)在虚幻编辑器中启用了静态网格体的操作,包括细分表面的使用! +* Sequencer 非线性编辑工具现在 VR 模式中可用 +* 用上下文相关的操作重新设计了圆形菜单 +* Smart Snapping 可快速而准确地相对于关卡中的其他资源放置物体 +* 可保存在模拟模式中进行的静态网格体修改 -## Downloading the Dev-Geometry GDC 2017 Features Branch +## 下载 Dev-Geometry GDC 2017 功能分支 -To download the Dev-Geometry GDC 2017 Features Branch: +下载 Dev-Geometry GDC 2017 功能分支的步骤: -1. [Associated your GitHub account with your EpicID](https://www.unrealengine.com/ue4-on-github). +1. [将 GitHub 账户与 Epic ID 关联](https://www.unrealengine.com/ue4-on-github)。 -1. Download the build from our GitHub repository: [Dev-Geometry](https://github.com/EpicGames/UnrealEngine/tree/dev-geometry) +1. 从 GitHub 元库下载版本: [Dev-Geometry](https://github.com/EpicGames/UnrealEngine/tree/dev-geometry) -1. [Compile](Programming/Development/BuildingUnrealEngine) and [run Unreal Editor](GettingStarted/RunningUnrealEngine). +1. [编译](Programming/Development/BuildingUnrealEngine) 并 [运行虚幻编辑器](GettingStarted/RunningUnrealEngine)。 -## Mesh Editor +## 网格体编辑器 -The **Mesh Editor** mode is a new geometry editing toolset designed to enable designers to quickly create and modify Static Mesh geometry in the Level Editor viewport. In addition to a low-poly toolset, Mesh Editor mode adds the ability to work with subdivision surfaces, enabling artists and designers to create smooth, organic surfaces directly in Unreal Editor. +**网格体编辑器(Mesh Editor)** 模式是一个全新几何体编辑工具集。其设计理念是便于设计师在关卡编辑器视口中快速创建和修改静态网格体几何体。除一个低多边形工具集外,网格体编辑器模式还添加了使用细分表面的功能,便于美术师和设计师直接在虚幻编辑器中创建平滑的有机表面。 ![](poly_extrude.png) ![](poly_extrude_subd.png) [REGION:note] -The Mesh Editor mode is an extremely early access feature. +网格体编辑器模式的功能尚在早期开发中。 [/REGION] -To edit a mesh using the Mesh Editor mode: +使用网格体编辑器模式编辑网格体的方法: -1. In the **Modes** panel, select the **Mesh Editor** mode. +1. 在 **Modes** 面板中选中 **Mesh Editor** 模式。 -1. Choose an editing mode depending on what elements - Vertices, Edges, Polygons, All - of the mesh you want to edit. +1. 根据需要编辑的网格体元素选择编辑模式——顶点、边缘、多边形等。 -1. Select a mesh in the viewport. The elements corresponding to the mode highlight when the cursor is over them. +1. 在视口中选择一个网格体。鼠标悬停在与模式相关的元素上时将高亮显示。 -1. Select an element to edit it. +1. 选择一个元素进行编辑。 -### Selection Modes +### 选择模式 -#### Vertices +#### 顶点 -The **Vertices** selection mode limits editing to vertices of the mesh. +**Vertices** 选择模式限制对网格体顶点的编辑。 ![](vert_mode.png)(w:400) -### Vertex Tools +### 顶点工具 [REGION:imagetable] | ![](vert_move.png)(w:295) | ![](vert_extend.png)(w:295) | | --- | --- | -| Move | Extend | +| 移动 | 延展 | [/REGION] -#### Edges +#### 边缘 -The **Edges** selection mode limits editing to edges of the mesh. +**Edges** 选择模式限制对网格体边缘的编辑。 ![](edge_mode.png)(w:400) -### Edge Tools +### 边缘工具 [REGION:imagetable] | ![](edge_move.png)(w:235) | ![](edge_split.png)(w:235) | ![](edge_split_drag.png)(w:235) | ![](edge_loop.png)(w:235) | ![](edge_extend.png)(w:235) | | --- | --- | --- | --- | --- | -| Move | Split | Split and Drag Vert | Add Loop | Extend | +| 移动 | 分解 | 分解并拖动顶点 | 添加循环 | 延展 | [/REGION] -#### Polygons +#### 多边形 -The **Polygon** selection mode limits editing to polygon faces of the mesh. +**Polygon** 选择模式限制对网格体多边形面的编辑。 ![](poly_mode.png)(w:400) -### Polygon Tools +### 多边形工具 [REGION:imagetable] | ![](poly_move.png)(w:295) | ![](poly_extrude.png)(w:295) | ![](poly_inset.png)(w:295) | ![](poly_bevel.png)(w:295) | --- | --- | --- | --- | -| Move | Extrude | Inset | Bevel | +| 移动 | 挤出 | 嵌入 | 斜切 | [/REGION] #### Any -The **Any** selection mode changes to match the selected element - Vertex, Edge, Polygon, etc. This is essentially a free editing mode that enables you to quickly jump between the other modes just by selecting a different type of element. +**Any** 选择模式进行修改,匹配选中的元素——顶点、边缘、多边形等。这实际上是一个自由编辑模式,选择不同类型的元素即可在其他模式之间快速切换。 [REGION:imagetable] | ![](vert_mode.png)(w:295) | ![](edge_mode.png)(w:295) | ![](poly_mode.png)(w:295) | --- | --- | --- | -| Vertices | Edges | Polygons | +| 顶点 | 边缘 | 多边形 | [/REGION] -### Source vs Instance +### 源与实例 -Mesh editing can be done on a per-instance basis, which only affects the mesh of the placed Actor in the level; or editing can be applied directly to the source mesh asset, propagating changes you make to all instances of that mesh asset. By default, editing is applied to the source mesh asset. To enable per-instance editing, press the **Per Instance** button in the Mesh Editor mode panel. +网格体编辑可以每个实例为基础,只影响关卡中所放置 Actor 的网格体;或将编辑直接应用到源网格体资源,将执行的修改传播到该网格体资源的所有实例。编辑默认应用到源网格体资源。在网格体编辑器模式面板中按下 **Per Instance** 即可启用每个实例的编辑。 ![](per_instance.png) -### Subdivision Surfaces +### 细分表面 -Add or Remove Subdivisions from any of the four submodes +四个子模式中添加或移除细分。 -#### Subdivision Levels +#### 细分关卡 [REGION:imagetable] | ![](mesh_subd_0.png)(w:295) | ![](mesh_subd_1.png)(w:295) | ![](mesh_subd_2.png)(w:295) | ![](mesh_subd_3.png)(w:295) | | --- | --- | --- | --- | -| Original | SubD Level 1 | SubD Level 2 | SubD Level 3 | +| 原始 | 细分关卡 1 | 细分关卡 2 | 细分关卡 3 | [/REGION] -#### Editing Tools with Subdivision Surfaces +#### 带细分表面的编辑工具 -The editing tools always act on the elements of the low-poly mesh, and the subdivision is applied on top of those edits. +编辑工具固定作用于低多边形网格体的元素,细分则应用到这些编辑之上。 [REGION:imagetable] | ![](poly_inset.png)(w:295) | ![](poly_extrude.png)(w:295) | ![](poly_inset_subd.png)(w:295) | ![](poly_extrude_subd.png)(w:295) | | --- | --- | --- | --- | -| Inset | Extrude | Inset w/ SubD | Extrude w/ SubD | +| 嵌入 | 挤出 | 带细分嵌入 | 带细分挤出 | [/REGION] -#### Corner Sharpness +#### 角落锐度 -Corner sharpness enables you to control how closely the subdivision surface follows the low-poly mesh at specific locations, which provides the ability to create hard edges on subdivision surfaces. +通过角度锐度可以控制细分表面对特定位置低多边形网格体的遵照程度,可在细分表面上创建硬边缘。 [REGION:imagetable] -| Vertex Sharpness ||| +| 顶点锐度 ||| | --- | --- | --- | | ![](vert_sharp_0.png)(w:295) | ![](vert_sharp_1.png)(w:295) | ![](vert_sharp_2.png)(w:295) -| Soft | Sharper | Sharpest | +| 钝 | 较锐 | 极锐 | [/REGION] [REGION:imagetable] -| Edge Sharpness ||| +| 边缘锐度 ||| | --- | --- | --- | | ![](edge_sharp_0.png)(w:295) | ![](edge_sharp_1.png)(w:295) | ![](edge_sharp_2.png)(w:295) -| Soft | Sharper | Sharpest | +| 钝 | 较锐 | 极锐 | [/REGION] -## VR Editor Controls +## VR 编辑器控制 -VR Mode is enabled by default in this build, and you can enter with the hotkey (**Alt + ~**) or via the button on the Level Editor Toolbar. In addition, auto-entry will take you into VR Mode when the Oculus or Vive Headset is on. +VR 模式在此版本中默认启用,可通过热键(**Alt + ~**)或关卡编辑器工具栏上的按钮进入。此外,Oculus 或 Vive 头戴显示器开启后将自动进入 VR 模式。 -[REGION:note]Auto-entry can be enabled or disabled in the **Editor Preferences** under **Experimental > VR Editor**.[/REGION] +[REGION:note]可在 **Experimental > VR Editor** 下的 **Editor Preferences** 中启用或禁用自动进入。[/REGION] -Controllers are now Asynchronous on both Vive and Oculus. The left controller is used for access to menus and options, while the right controller is used to select and manipulate items. +现版本中 Vive 和 Oculus 的控制器均为异步。左控制器用于访问菜单和选项,而右控制器用于选择和操作物品。 ![](controllers.png)(w:640) -Teleportation no longer grays out the world and automatically resets the World Scale back to 1:1. +传送不再使世界场景变灰,并自动将世界比例重设回 1:1。 -Half-trigger press options have been removed. Interacting with the world is now done via full trigger presses. +半按扳机选项已移除。和世界场景的互动现在通过扳机全按实现。 -**OCULUS ONLY**: A "hard reset / Panic Button" has been added. Clicking in the left thumbstick will perform the following actions at once: +**仅针对 OCULUS**:已添加一个“强行重置/恐慌按钮”。点击左操纵杆将同时执行以下操作: -* Deselect all selected items -* Close all open windows / Asset Editors -* Cancel Simulate -* Place the user in Actor / Selection Mode +* 取消选择所有选中的物品 +* 关闭所有打开的窗口/资源编辑器 +* 取消模拟 +* 把用户放置在 Actor/选择模式中 -Options to Undo/Redo have been assigned to the right thumbstick/touchpad. +撤销/重新执行的选项已指定到右操纵杆/触控板。 [REGION:simpletable] -| Command | Action | +| 命令 | 操作 | | --- | --- | -| Undo | Press left on the thumbstick/touchpad | -| Redo | Press right on the thumbstick/touchpad | +| **撤销** | 在操纵杆/触控板上按左 | +| **重新执行** | 在操纵杆/触控板上按右 | [/REGION] -Options to quickly place an asset currently selected in the Content Browser have been assigned to the right thumbstick / touchpad. This functionality is also present in Simulate mode. +快速放置当前在 Content Browser 中选中资源的选项已指定到右操作杆/触控板。此功能在模拟模式中同样存在。 -With an asset selected in the Content Browser: +在 Content Browser 中选中资源后: [REGION:simpletable] -| Platform | Action | +| 平台 | 操作 | | --- | --- | -| **Oculus** | Press and hold Up on the right thumbstick. Click in the world with the right trigger. | -| **Vive** | Click and hold Up on the right touchpad. Click in the world with the right trigger. | +| **Oculus** | 按下并长按右操作杆的上键。用右扳机键在世界场景中点击。| +| **Vive** | 点击并按住右触控板的上。用右扳机键在世界场景中点击。| [/REGION] -Transformation Gizmos have been updated for consistency with Desktop Editor. +变形小工具已更新与桌面编辑器一致。 -Rotation Gizmo now has an indicator for the asset's original position. +此版本中旋转小工具拥有资源原始位置的指示器。 -## Editor Windows +## 编辑器窗口 -Windows are no longer docked to the Controller when opened. Instead, they open slightly offset from the left controller. The Close button is now nested beside the interaction bar underneath each window +窗口打开后将不会和控制器形成对接。现在窗口将稍微偏离左控制器。关闭按钮现处于每个窗口下方的交互条旁。 -When opening a window, if you keep the trigger depressed, you will see a preview of where the window will be placed. +打开窗口时,如果一直按下扳机键,将会看到窗口放置之处的预览。 [REGION:asyncgif] ![](vr_contentBrowser.gif)(w:322) [/REGION] [REGION:note] -The **Toggle All UI** option has been removed. +**Toggle All UI** 选项已被移除。 [/REGION] -## Radial Menu +## 圆形菜单 -The new Radial Menu provides a redesigned interface that enables the user to quickly reach all functions of VR Mode, including the Modes Panels, Asset Editors, Simulate and Play in VR, consolidating the functionality of the old Radial Menu and the Quick Menu into one intuitive user interface. +全新的圆形菜单拥有新设计的界面,可帮助用户快捷地访问 VR 模式中的所有功能,包括模式面板、资源编辑器、在 VR 中模拟和游戏,将旧圆形菜单和快捷菜单中的功能整合到一个直观的用户界面中。 [REGION:asyncgif] ![](vr_radialMenu.gif)(w:388) [/REGION] -**To open the Radial Menu:** +**打开圆形菜单:** [REGION:simpletable] -| Platform | Action | +| 平台 | 操作 | | --- | --- | -| **Oculus** | Interact with the left thumbstick | -| **Vive** | Interact with the left touchpad | +| **Oculus** | I用作操作杆进行互动 | +| **Vive** | I用作触控板进行互动 | [/REGION] -A context-sensitive option has been added to the Radial Main Menu. This menu option offers quick access to additional features available within different tools. +一个上下文相关的选项已添加到圆形主菜单。此菜单选项可快速访问不同工具中可用的额外功能。 [REGION:asyncgif] ![](vr_contextOption.gif)(w:344) diff --git a/Engine/Documentation/Source/Engine/Editor/VR/QuickSelect/QuickSelectMenu.KOR.udn b/Engine/Documentation/Source/Engine/Editor/VR/QuickSelect/QuickSelectMenu.KOR.udn index fa5763db5276..e8e5453d3d3f 100644 --- a/Engine/Documentation/Source/Engine/Editor/VR/QuickSelect/QuickSelectMenu.KOR.udn +++ b/Engine/Documentation/Source/Engine/Editor/VR/QuickSelect/QuickSelectMenu.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3350329 +INTSourceChangelist:3360829 Title: 빠른 선택 메뉴 Description: 빠른 선택 메뉴로 VR 모드에서 에디터 패널과 창을 쉽게 접근할 수 있습니다. Crumbs: @@ -11,7 +11,7 @@ version: 4.15 skilllevel: intermediate topic-image:quickselect_topic.png prereq:Engine/Editor/VR/ActivateVRMode -prereq:Engine/Editor/VR/Setup + [TOC(start:1 end:4)] diff --git a/Engine/Documentation/Source/Engine/Editor/VR/RadialMenu/RadialMenu.KOR.udn b/Engine/Documentation/Source/Engine/Editor/VR/RadialMenu/RadialMenu.KOR.udn index 85a70bc8beb6..c00a7d69eb94 100644 --- a/Engine/Documentation/Source/Engine/Editor/VR/RadialMenu/RadialMenu.KOR.udn +++ b/Engine/Documentation/Source/Engine/Editor/VR/RadialMenu/RadialMenu.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3350329 +INTSourceChangelist:3360829 Title: 원형 메뉴 Description: Radial menu, 원형 메뉴는 VR 모드에서 복사/붙여넣기, 되돌리기처럼 자주 사용되는 기능을 쉽게 접할 수 있도록 해줍니다. Crumbs: @@ -11,7 +11,7 @@ version: 4.15 skilllevel: intermediate topic-image:radialmenu.png prereq:Engine/Editor/VR/ActivateVRMode -prereq:Engine/Editor/VR/Setup + [TOC(start:1 end:4)] diff --git a/Engine/Documentation/Source/Engine/Editor/VR/Setup/VREditorEditorSetup.CHN.udn b/Engine/Documentation/Source/Engine/Editor/VR/Setup/VREditorEditorSetup.CHN.udn index 2ca1729bfb8d..418ce23ff5cd 100644 --- a/Engine/Documentation/Source/Engine/Editor/VR/Setup/VREditorEditorSetup.CHN.udn +++ b/Engine/Documentation/Source/Engine/Editor/VR/Setup/VREditorEditorSetup.CHN.udn @@ -1,49 +1,18 @@ -INTSourceChangelist:2939982 +INTSourceChangelist:3360829 Title:从 GitHub 设置 VR 编辑器 Description:从 GitHub 下载并配置虚幻引擎 VR 编辑器预览 Crumbs: Availability: public parent:Engine/Editor/VR -type: howto -order:1 -tags:VR -tags:GitHub -version:4.11 +type:how-to +order: 2 +tags: VR +tags: GitHub +version: 4.15 skilllevel: intermediate +topic-image:vreditor_setup.png -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Editor/VR/Setup:title%](Engine/Editor/VR/Setup/vreditor_setup.png) - [/PARAM] - [PARAM:title] - %Engine/Editor/VR/Setup:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Editor/VR/Setup] - [/PARAM] - [PARAM:description] - %Engine/Editor/VR/Setup:description% - [/PARAM] -[/OBJECT] -[/VAR] -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Editor/VR/Setup:title%](Engine/Editor/VR/Setup/vreditor_setup.png) - [/PARAM] - [PARAM:title] - %Engine/Editor/VR/Setup:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Editor/VR/Setup] - [/PARAM] - [PARAM:description] - %Engine/Editor/VR/Setup:description% - [/PARAM] -[/OBJECT] -[/VAR] [EXCERPT:main] diff --git a/Engine/Documentation/Source/Engine/Editor/VR/Setup/VREditorEditorSetup.KOR.udn b/Engine/Documentation/Source/Engine/Editor/VR/Setup/VREditorEditorSetup.KOR.udn index 40d5c3c5f475..8158bc86954f 100644 --- a/Engine/Documentation/Source/Engine/Editor/VR/Setup/VREditorEditorSetup.KOR.udn +++ b/Engine/Documentation/Source/Engine/Editor/VR/Setup/VREditorEditorSetup.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3350329 +INTSourceChangelist:3360829 Title: GitHub 에서 VR 에디터 구성 Description: GitHub 에서 언리얼 엔진 VR 에디터 프리뷰 버전을 다운로드하고 구성하는 방법입니다. Crumbs: @@ -8,7 +8,7 @@ type:how-to order: 2 tags: VR tags: GitHub -version: 4.11 +version: 4.15 skilllevel: intermediate topic-image:vreditor_setup.png diff --git a/Engine/Documentation/Source/Engine/Editor/VR/UniversalGizmo/UniversalGizmo.KOR.udn b/Engine/Documentation/Source/Engine/Editor/VR/UniversalGizmo/UniversalGizmo.KOR.udn index e8dd9e30fa37..58b8904da19c 100644 --- a/Engine/Documentation/Source/Engine/Editor/VR/UniversalGizmo/UniversalGizmo.KOR.udn +++ b/Engine/Documentation/Source/Engine/Editor/VR/UniversalGizmo/UniversalGizmo.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3350329 +INTSourceChangelist:3360829 Title: VR 에서의 액터 트랜스폼 Description: VR 에서 액터 이동, 회전, 스케일 조절에 사용되는 트랜스폼 위젯입니다. Crumbs: @@ -7,11 +7,11 @@ parent: Engine/Editor/VR type: reference order: 4 tags: VR -version: 4.13 +version: 4.15 skilllevel: intermediate topic-image:universalgizmo_topic.png prereq:Engine/Editor/VR/ActivateVRMode -prereq:Engine/Editor/VR/Setup + [TOC(start:1 end:4)] diff --git a/Engine/Documentation/Source/Engine/Editor/VR/VREditor.KOR.udn b/Engine/Documentation/Source/Engine/Editor/VR/VREditor.KOR.udn index 92ab62b2197e..0832ff9b3fe6 100644 --- a/Engine/Documentation/Source/Engine/Editor/VR/VREditor.KOR.udn +++ b/Engine/Documentation/Source/Engine/Editor/VR/VREditor.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3350329 +INTSourceChangelist:3360829 Title: 언리얼 엔진 VR 에디터 Description: 에디터 툴세트의 모든 기능을 VR 에 특화된 방식으로 사용하여, 가상현실 안에서 가상현실 월드를 제작합니다. Crumbs: @@ -7,7 +7,7 @@ parent:Engine/Editor type:overview order:10 tags:VR -version:4.12 +version:4.15 skilllevel:intermediate social-image:vreditor_social.png diff --git a/Engine/Documentation/Source/Engine/Editor/VR/WorldInteraction/WorldInteraction.KOR.udn b/Engine/Documentation/Source/Engine/Editor/VR/WorldInteraction/WorldInteraction.KOR.udn index 7e1537551ba4..ddf44d31b183 100644 --- a/Engine/Documentation/Source/Engine/Editor/VR/WorldInteraction/WorldInteraction.KOR.udn +++ b/Engine/Documentation/Source/Engine/Editor/VR/WorldInteraction/WorldInteraction.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3350329 +INTSourceChangelist:3360829 Title: VR 모드에서 월드 이동 Description: VR 모드 작업이 월드를 이동하는 방법을 배워봅니다. Crumbs: @@ -8,11 +8,11 @@ type:how-to order: 3 tags: VR tags: Level Editing -version: 4.11 +version: 4.15 skilllevel: intermediate topic-image:worldinteraction.png prereq:Engine/Editor/VR/ActivateVRMode -prereq:Engine/Editor/VR/Setup + [TOC(start:1 end:4)] diff --git a/Engine/Documentation/Source/Engine/Engine.INT.udn b/Engine/Documentation/Source/Engine/Engine.INT.udn index 1c43eaf2d6b8..7961fd1ea8c9 100644 --- a/Engine/Documentation/Source/Engine/Engine.INT.udn +++ b/Engine/Documentation/Source/Engine/Engine.INT.udn @@ -9,7 +9,10 @@ topic-image:Engine/Rendering/rendering_topic.png topic-icon:%ROOT%/docs_icon.png type:landing +## Unreal Engine Basics -## Browse Topics +[DIR(end:"1" output:"topiccompact" parent:"Engine" path:"Engine/Basics")] -[DIR(end:"1" output:"topiccompact" parent:"Engine")] +## Systems and Features + +[DIR(end:"1" output:"topiccompact" parent:"Engine" path:"!Engine/Basics")] diff --git a/Engine/Documentation/Source/Engine/Engine.KOR.udn b/Engine/Documentation/Source/Engine/Engine.KOR.udn index 79c1cd1e70fa..14f595b92f9b 100644 --- a/Engine/Documentation/Source/Engine/Engine.KOR.udn +++ b/Engine/Documentation/Source/Engine/Engine.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3151855 +INTSourceChangelist:3454520 Availability:Public Title: 엔진 기능 Crumbs: %ROOT% @@ -10,7 +10,10 @@ topic-image:Engine/Rendering/rendering_topic.png topic-icon:%ROOT%/docs_icon.png type:landing +## 언리얼 엔진 기초 -## 주제별 탐색 +[DIR(end:"1" output:"topiccompact" parent:"Engine" path:"Engine/Basics")] -[DIR(end:"1" output:"topiccompact" parent:"Engine")] +## 시스템 및 기능 + +[DIR(end:"1" output:"topiccompact" parent:"Engine" path:"!Engine/Basics")] diff --git a/Engine/Documentation/Source/Engine/Foliage/Foliage.INT.udn b/Engine/Documentation/Source/Engine/Foliage/Foliage.INT.udn index 0e458fe44ac1..78e5418f4125 100644 --- a/Engine/Documentation/Source/Engine/Foliage/Foliage.INT.udn +++ b/Engine/Documentation/Source/Engine/Foliage/Foliage.INT.udn @@ -336,21 +336,105 @@ In Order to use the Foliage Painting mode, your level must contain either a Land 1. Once FT_Box is opened, expand the **Mesh** and **Scalability** sections. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] [REGION:lightbox] - [![](Foliage_Scalability_02.png)(w:405 h:223)](Foliage_Scalability_02.png) + [![](Foliage_Scalability_02_Windows.png)(w:405)](Foliage_Scalability_02_Windows.png) [/REGION] + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + [REGION:lightbox] + [![](Foliage_Scalability_02_Mac.png)(w:405)](Foliage_Scalability_02_Mac.png) + [/REGION] + [/PARAM] + [/OBJECT] 1. In the **Content Browser** select a Static Mesh (for this example we are using the **Shape_Cube** that comes with the Starter Content). In the FT_Box Foliage Type, under the **Mesh** section, drag the **Shape_Cube** from the Content Browser to the **Mesh** option. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] [REGION:lightbox] - [![](Foliage_Scalability_03.png)(w:405 h:223)](Foliage_Scalability_03.png) + [![](Foliage_Scalability_03_Windows.png)(w:405)](Foliage_Scalability_03_Windows.png) [/REGION] + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + [REGION:lightbox] + [![](Foliage_Scalability_03_Mac.png)(w:405)](Foliage_Scalability_03_Mac.png) + [/REGION] + [/PARAM] + [/OBJECT] 1. In the **Scalability** section of the FT_Box Foliage Type, click on the box that is next to **Enable Density Scaling** to allow the Scalability System access to this Static Mesh. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] [REGION:lightbox] - [![](Foliage_Scalability_04.png)(w:405 h:223)](Foliage_Scalability_04.png) + [![](Foliage_Scalability_04_Windows.png)(w:405)](Foliage_Scalability_04_Windows.png) [/REGION] + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + [REGION:lightbox] + [![](Foliage_Scalability_04_Mac.png)(w:405)](Foliage_Scalability_04_Mac.png) + [/REGION] + [/PARAM] + [/OBJECT] [region:note] The **Enable Density Scaling** option should typically only be **enabled** for detail foliage without collision such as small rocks and bushes. It should be **disabled** for Foliage Types with collision such as trees as the collision for removed instances will continue to exist in the game. diff --git a/Engine/Documentation/Source/Engine/Foliage/Foliage.JPN.udn b/Engine/Documentation/Source/Engine/Foliage/Foliage.JPN.udn index dd5b11a63f46..65097c0f35ad 100644 --- a/Engine/Documentation/Source/Engine/Foliage/Foliage.JPN.udn +++ b/Engine/Documentation/Source/Engine/Foliage/Foliage.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3260884 +INTSourceChangelist:3481084 Availability:Public Title:フォリッジ インスタンス化メッシュ Crumbs:%ROOT%, Engine @@ -56,7 +56,7 @@ order:11 [EXCERPT:Intro] -フォリッジ システムによって、ランドスケープ アクタ、他のスタティックメッシュ アクタ、BSP ジオメトリ上でスタティックメッシュをすばやくペイントまたは消去することができるようになります。 +フォリッジ システムは、ランドスケープ アクタ、他のスタティックメッシュ アクタ、BSP ジオメトリ上でスタティックメッシュの迅速なペイントまたは消去を可能にします。 これらのメッシュは、ハードウェア インスタンシングを使用してレンダリングされるバッチに自動的に統合されます。つまり、1 回のドローコールで多数のインスタンスのレンダリングが可能になります。 [/EXCERPT:Intro] @@ -104,11 +104,11 @@ Foliage ツールを使用するには、アンリアル エディタの左上 ###メッシュ リストでフォリッジ メッシュを選択する -メッシュ リストのフォリッジ メッシュは、リストのメッシュにマウスを当てて四角の左上のチェックマーク ボックスにチェックを入れる、または外すことで、有効と無効の切り替えができます。 +メッシュ リストにあるフォリッジ メッシュは、リストのメッシュにマウスを当てて左上のチェックマーク ボックスのチェックによって、有効と無効の切り替えができます。 ![](Foliage_Selecting_Meshes.png) -メッシュ リストでそれらをクリックしても、フォリッジ メッシュを選択することができます。 +メッシュ リストでクリックしても、フォリッジ メッシュを選択することができます。 選択するとボックスがオレンジで囲まれて、以下のオプション パネルで各種プロパティの調整が可能になります。 [REGION:lightbox] @@ -337,21 +337,105 @@ Foliage Painting モードを使用するには、レベルにコリジョンが 1. FT_Box が開いたら、**[Mesh]** セクションと **[Scalability]** セクションを展開します。 + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] [REGION:lightbox] - [![](Foliage_Scalability_02.png)(w:405 h:223)](Foliage_Scalability_02.png) + [![](Foliage_Scalability_02_Windows.png)(w:405)](Foliage_Scalability_02_Windows.png) [/REGION] + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + [REGION:lightbox] + [![](Foliage_Scalability_02_Mac.png)(w:405)](Foliage_Scalability_02_Mac.png) + [/REGION] + [/PARAM] + [/OBJECT] 1. **[コンテンツ ブラウザ]** からスタティック メッシュを選びます (このサンプルではスターター コンテンツに入っている **Shape_Cube** を使います)。次に [FT_Box Foliage Type] の **[Mesh]** セクションで、コンテンツ ブラウザから **[Shape_Cube]** を **[Mesh]** オプションへドラッグします。 + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] [REGION:lightbox] - [![](Foliage_Scalability_03.png)(w:405 h:223)](Foliage_Scalability_03.png) + [![](Foliage_Scalability_03_Windows.png)(w:405)](Foliage_Scalability_03_Windows.png) [/REGION] + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + [REGION:lightbox] + [![](Foliage_Scalability_03_Mac.png)(w:405)](Foliage_Scalability_03_Mac.png) + [/REGION] + [/PARAM] + [/OBJECT] 1. [FT_Box] フォリッジ タイプの **[Scalability]** セクションで、**[Enable Density Scaling (密度のスケールを有効にする)]** の横のボックスをクリックすると、Scalability System がこのスタティックメッシュにアクセスすることができます。 + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] [REGION:lightbox] - [![](Foliage_Scalability_04.png)(w:405 h:223)](Foliage_Scalability_04.png) + [![](Foliage_Scalability_04_Windows.png)(w:405)](Foliage_Scalability_04_Windows.png) [/REGION] + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + [REGION:lightbox] + [![](Foliage_Scalability_04_Mac.png)(w:405)](Foliage_Scalability_04_Mac.png) + [/REGION] + [/PARAM] + [/OBJECT] [region:note] **[Enable Density Scaling (密度のスケールを有効にする)]** オプションは、通常は岩や低木などのコリジョンを持たない「詳細な」フォリッジに対してのみ **有効** にされます。インスタンスを除去してもコリジョンはゲーム中ずっと有効のままなので、コリジョンをもつ木などのフォリッジには **無効** にしておきます。 diff --git a/Engine/Documentation/Source/Engine/Foliage/Foliage.KOR.udn b/Engine/Documentation/Source/Engine/Foliage/Foliage.KOR.udn index 4487bf41e30d..2031290ea826 100644 --- a/Engine/Documentation/Source/Engine/Foliage/Foliage.KOR.udn +++ b/Engine/Documentation/Source/Engine/Foliage/Foliage.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3260884 +INTSourceChangelist:3481084 Availability: Public Title:폴리지, 인스턴싱된 메시 Crumbs:%ROOT%, Engine @@ -337,21 +337,105 @@ order:11 1. FT_Box 가 열리면, **Mesh** 와 **Scalability** 섹션을 엽니다. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] [REGION:lightbox] - [![](Foliage_Scalability_02.png)(w:405 h:223)](Foliage_Scalability_02.png) + [![](Foliage_Scalability_02_Windows.png)(w:405)](Foliage_Scalability_02_Windows.png) [/REGION] + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + [REGION:lightbox] + [![](Foliage_Scalability_02_Mac.png)(w:405)](Foliage_Scalability_02_Mac.png) + [/REGION] + [/PARAM] + [/OBJECT] 1. **콘텐츠 브라우저** 에서 스태틱 메시를 선택합니다 (이 예제에서는 시작용 콘텐츠에 포함된 **Shape_Cube** 를 사용합니다). FT_Box 폴리지 타입의 **Mesh** 섹션에서, 콘텐츠 브라우저의 **Shape_Cube** 를 끌어 **Mesh** 옵션에 놓습니다. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] [REGION:lightbox] - [![](Foliage_Scalability_03.png)(w:405 h:223)](Foliage_Scalability_03.png) + [![](Foliage_Scalability_03_Windows.png)(w:405)](Foliage_Scalability_03_Windows.png) [/REGION] + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + [REGION:lightbox] + [![](Foliage_Scalability_03_Mac.png)(w:405)](Foliage_Scalability_03_Mac.png) + [/REGION] + [/PARAM] + [/OBJECT] 1. FT_Box 폴리지 타입의 **Scalability** 섹션에서, **Enable Density Scaling** (밀도 스케일 허용) 옆의 박스를 클릭하면 엔진 퀄리티(Scalability) 시스템이 이 스태틱 메시에 접근하도록 허용합니다. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] [REGION:lightbox] - [![](Foliage_Scalability_04.png)(w:405 h:223)](Foliage_Scalability_04.png) + [![](Foliage_Scalability_04_Windows.png)(w:405)](Foliage_Scalability_04_Windows.png) [/REGION] + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + [REGION:lightbox] + [![](Foliage_Scalability_04_Mac.png)(w:405)](Foliage_Scalability_04_Mac.png) + [/REGION] + [/PARAM] + [/OBJECT] [region:note] **Enable Density Scaling** 옵션은 전형적으로 작은 돌이나 덤불처럼 콜리전이 없는 디테일 폴리지에만 켜야 합니다. 나무와 같이 콜리전이 있는 폴리지 타입에 켜면 인스턴스를 제거한 경우 콜리전만 게임에 남아있기 때문입니다. diff --git a/Engine/Documentation/Source/Engine/HLOD/HLODLanding.INT.udn b/Engine/Documentation/Source/Engine/HLOD/HLODLanding.INT.udn index 25f37be17357..922a90c1fde4 100644 --- a/Engine/Documentation/Source/Engine/HLOD/HLODLanding.INT.udn +++ b/Engine/Documentation/Source/Engine/HLOD/HLODLanding.INT.udn @@ -12,7 +12,7 @@ social-image:HLOD_social.png ![](HLOD_header.png) -**Hierarchical Level of Detail** meshes (HLODs) have been developed as a way to increase performance and keep the quality bar high for projects using Unreal Engine 4.11 or later. HLODs can replace multiple **Static Mesh Actors** with single, combined **Static Mesh Actor** at long view distances. This helps reduce the number of **Actors** that need to be rendered for the scene, increasing performance by lowering the number of draw calls per frame. +[INCLUDE:Shared/Editor/HLOD#main] ## Starting Out diff --git a/Engine/Documentation/Source/Engine/HLOD/HLODLanding.JPN.udn b/Engine/Documentation/Source/Engine/HLOD/HLODLanding.JPN.udn index f632abdc45e1..c61e33d5ded2 100644 --- a/Engine/Documentation/Source/Engine/HLOD/HLODLanding.JPN.udn +++ b/Engine/Documentation/Source/Engine/HLOD/HLODLanding.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3224908 +INTSourceChangelist:3409833 title:HLOD (Hierarchical Level of Detail) Description:UE4 のHLOD システムのランディング ページです。 crumbs: @@ -13,7 +13,7 @@ social-image:HLOD_social.png ![](HLOD_header.png) -**Hierarchical Level of Detail (HLOD)** メッシュは、アンリアル エンジン 4.11 以降を使うプロジェクトのパフォーマンスを高め、クオリティを高く保つために開発されました。HLOD は、表示距離が遠い場合に複数の **Static Mesh アクタ** を、単一に結合された **Static Mesh アクタ** に置き換えることができます。HLOD を使うと、シーンに対してレンダリングする必要がある **アクタ** 数を減らし、1 フレームあたりのドローコール数を少なくしてパフォーマンスを高めることができます。 +[INCLUDE:Shared/Editor/HLOD#main] ## はじめよう diff --git a/Engine/Documentation/Source/Engine/HLOD/HLODLanding.KOR.udn b/Engine/Documentation/Source/Engine/HLOD/HLODLanding.KOR.udn index 3f933ca531ac..ca14d855c843 100644 --- a/Engine/Documentation/Source/Engine/HLOD/HLODLanding.KOR.udn +++ b/Engine/Documentation/Source/Engine/HLOD/HLODLanding.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3224908 +INTSourceChangelist:3409833 title:계층형 레벨 오브 디테일 description:언리얼 엔진 4 의 계층형 레벨 오브 디테일 시스템 첫 페이지입니다. crumbs: @@ -13,7 +13,7 @@ social-image:HLOD_social.png ![](HLOD_header.png) -**Hierarchical Level of Detail** (계층형 레벨 오브 디테일) 메시(HLOD)는 퍼포먼스를 향상시키면서도 퀄리티 기준을 높게 유지할 수 있도록 하기 위한 방편으로 개발된 것으로, 언리얼 엔진 4.11 이상에서 지원됩니다. HLOD 는 다수의 **스태틱 메시 액터** 를 원거리에서 봤을 때 하나의 **스태틱 메시 액터** 로 합치는 기법입니다. 이를 통해 씬에 렌더링해야 하는 **액터** 수를 줄여, 프레임 당 드로 콜 수를 낮춰 퍼포먼스를 향상시키는 데 도움이 됩니다. +[INCLUDE:Shared/Editor/HLOD#main] ## 시작하기 diff --git a/Engine/Documentation/Source/Engine/Landscape/Creation/Creation.JPN.udn b/Engine/Documentation/Source/Engine/Landscape/Creation/Creation.JPN.udn index 132c66ebdf32..7e57adcab2e3 100644 --- a/Engine/Documentation/Source/Engine/Landscape/Creation/Creation.JPN.udn +++ b/Engine/Documentation/Source/Engine/Landscape/Creation/Creation.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3053927 +INTSourceChangelist:3347993 Availability:Public Title:ランドスケープの作成 Crumbs: %ROOT%, Engine, Engine/Landscape @@ -53,8 +53,8 @@ order:2 ランドスケープ システムはフレキシブルであるため、以下のいずれかの方法を用いてランドスケープを作成することができます。 * エンジン内の Landscape ツールを用いて新規ランドスケープ高さマップをゼロから作成できます。 -* アンリアル エディタもしくは外部ツールであらかじめ作成されたランドスケープの高さマップのインポートが可能です。高さマップのインポートの操作の詳しい情報については、 - [カスタムの高さマップとレイヤーを作成する](Engine/Landscape/Custom) のドキュメントをご覧ください。 +* アンリアル エディタもしくは外部ツールであらかじめ作成されたランドスケープの高さマップのインポートが可能です。高さマップのインポートの操作の詳しい情報については、[カスタムの高さマップとレイヤーを作成する](Engine/Landscape/Custom) のドキュメントをご覧ください。 +* ランドスケープのインポート用フォーマットの作成方法については、[](Engine/Landscape/Creation/Plugin) をご覧ください。 [REGION:note] 動作中のランドスケープのサンプルは、 [](Resources\ContentExamples\Landscapes) を参照してください。 @@ -91,7 +91,7 @@ Landscape Manage モードでは、新規ランドスケープを作成したり ## Landscape ツールを使用したランドスケープの新規作成 -全く新しくランドスケープの作成は、Landscape ツールの **[Manage (管理)]** タブの **[New Landscape (新規ランドスケープ)]** セクションで行います。 +ランドスケープの新規作成は、Landscape ツールの **[Manage (管理)]** タブの **[New Landscape (新規ランドスケープ)]** セクションで行います。 ![Landscape_Create_Section.png](Landscape_Create_Section.png)(convert:false) @@ -99,13 +99,13 @@ Landscape Manage モードでは、新規ランドスケープを作成したり |---|---| |**Create New:** | ツール内から新規にランドスケープ高さマップを作成します。 | | **Import from File:** | 外部プログラムで作成されたランドスケープ高さマップをインポートすることができます。 -|**Material:**| マテリアルをランドスケープに割り当てることができます。 | +|**Material:**| マテリアルをランドスケープに割り当てることができます。| |**Location:**| ランドスケープが配置されるワールド内の位置を設定することができます。 |**Rotation:**| ワールド内でのランドスケープの回転を設定することができます。 |**Scale:**| ワールド内のランドスケープのスケーリングを設定することができます。 -|**Section Size:**| LOD とカリングのために使用します。小さなセクションでは、ランドスケープはアグレッシブに LOD (Level of Detail) セクションにしますが、CPU 負荷は高くなります。サイズを大きくすればコンポーネント数を減らすことができ、CPU 負荷も低くなります。ランドスケープを大きくしたい場合は大きめのセクション サイズを使用する必要があります。小さなセクション サイズでランドスケープをスケールアップすると CPU の負荷が高くなりすぎるからです。 -|**Section Per Component**| ランドスケープ LOD に役立ちます。各セクションがランドスケープ LOD の基本単位となります。1 つのコンポーネントは 2 x 2 セクションとなるので、1 つのコンポーネントで 4 種類の LOD を一度にレンダリングできるようになります。セクション サイズが大きければ、CPU 計算時間も短縮されます。しかし、ランドスケープが多くの頂点を一度にレンダリングするという問題が生じるかもしれません。これは、非常に広い領域のランドスケープを使用する場合に発生しやすくなります。こうした問題は、ハードウェア制約のため、ドローコールの量に制限があるモバイル デバイスの場合にさらに悪化します。| -|**Number of Components**|セクション サイズと共に、ランドスケープのサイズを設定します。この値は、32 x 32 が上限です。各コンポーネントはそれに付随する CPU 負荷を生じ、この上限を超えるとランドスケープのパフォーマンスで問題が生じることがあります。| +|**Section Size:**| LOD とカリングのために使用します。小さなセクションでは、ランドスケープは積極的に LOD (Level of Detail) セクションにしますが、CPU 負荷は高くなります。サイズを大きくすればコンポーネント数を減らすことができ、CPU 負荷も低くなります。ランドスケープを大きくしたい場合は大きめのセクション サイズを使用する必要があります。小さなセクション サイズでランドスケープをスケールアップすると CPU の負荷が高くなりすぎるからです。 +|**Section Per Component**| ランドスケープ LOD に役立ちます。各セクションがランドスケープ LOD の基本単位となります。1 つのコンポーネントは 2 x 2 セクションとなるので、1 つのコンポーネントで 4 種類の LOD を一度にレンダリングできるようになります。セクション サイズが大きければ、CPU 計算時間も短縮されます。しかし、ランドスケープが多くの頂点を一度にレンダリングするという問題が生じるかもしれません。これは、非常に広い領域のランドスケープを使用する場合に特に発生します。こうした問題は、ハードウェア制約のため、ドローコールの量に制限があるモバイル デバイスの場合にさらに悪化します。| +|**Number of Components**|セクション サイズと共に、ランドスケープのサイズを設定します。この値は、32 x 32 が上限です。各コンポーネントはそれに付随する CPU 負荷を生じ、この上限を超えるとランドスケープのパフォーマンスに問題が生じることがあります。| |**Overall Resolution:**| ランドスケープが使用している頂点数です。| |**Total Components**:| ランドスケープに作成されるコンポーネント数の合計です。| |**Fill World**:| ランドスケープを可能な限り大きくします。| @@ -135,7 +135,7 @@ Landscape Manage モードでは、新規ランドスケープを作成したり ![](Landscape_In-Editor_Preview.png) [REGION:tip] -通常のアクタ同様にランドスケープ アクタを移動、回転、スケーリングできます。プレビュー ランドスケープのエッジをドラッグすれば、ランドスケープを空間に合うサイズに簡単に変更もできます。 +通常のアクタ同様にランドスケープ アクタを移動、回転、スケーリングできます。また、プレビュー ランドスケープのエッジをドラッグすれば、ランドスケープのサイズを空間に合わせて簡単に変更できます。 [OBJECT:EmbeddedVideo] [PARAMLITERAL:width] 640 @@ -155,7 +155,7 @@ og7fnKaqYdI ![](Landscape_Assign_Material.png) [REGION:note] -ランドスケープ マテリアルに関する詳細は、 [](Engine/Landscape\Materials) をご覧ください。 +Landscape マテリアルに関する詳細は、[Landscape マテリアル](Engine/Landscape\Materials) をご覧ください。 [/REGION] 新規ランドスケープの作成準備ができたら、Landscape ツール ウィンドウの右下隅の **[Create (作成)]** ボタンをクリックします。ランドスケープがフラット プレーンとしてビューポートに表示されます。マテリアルが割り当てられると、適用されたマテリアルが表示されます。マテリアルを選択しなかった場合は、レベル エディタのデフォルト マテリアルが適用されて表示されます。 @@ -172,11 +172,3 @@ og7fnKaqYdI ![Landscape_NewTerrain.png](Landscape_NewTerrain.png)(w:600) 新規ランドスケープが作成されると、[スカルプト](Engine/Landscape/Editing/SculptMode) または [ペイント](Engine/Landscape/Editing/PaintMode) を自由に開始できます。 - - - - - - - - diff --git a/Engine/Documentation/Source/Engine/Landscape/Creation/Plugin/Plugin.CHN.udn b/Engine/Documentation/Source/Engine/Landscape/Creation/Plugin/Plugin.CHN.udn index ecffa39086e1..8fd79a7b7316 100644 --- a/Engine/Documentation/Source/Engine/Landscape/Creation/Plugin/Plugin.CHN.udn +++ b/Engine/Documentation/Source/Engine/Landscape/Creation/Plugin/Plugin.CHN.udn @@ -1,29 +1,29 @@ -INTSourceChangelist:0 -Availability: Public -Title:Creating Custom Landscape Importers +INTSourceChangelist:3347993 +Availability:Public +Title:创建自定义地形导入器 Crumbs: %ROOT%, Engine, Engine/Landscape, Engine/Landscape/Creation -Description:Guide to creating new Landscape import formats via plugin. -version: 4.15 +Description:通过插件新建地形导入格式的指南。 +version:4.15 parent:Engine/Landscape -Creating your own heightmap and weightmap formats for importing landscape data is accomplished by writing a plugin. The plugin will add your new format to the engine, as well as importing the data from your files. +可通过编写插件创建自定义导入地形数据的高度图和权重图格式。插件将把新格式添加到引擎,并从文件导入数据。 -### Writing A Custom Importer +### 编写自定义导入器 -* In order to create new importers, your plugin should create instances of objects implementing `ILandscapeHeightmapFileFormat` and `ILandscapeWeightmapFileFormat`, and register those objects with `ILandscapeEditorModulemodule::RegisterHeightmapFileFormat` and `ILandscapeEditorModulemodule::RegisterWeightmapFileFormat`, respectively. +* 为新建导入器,插件应创建对象实例实现 `ILandscapeHeightmapFileFormat` 和 `ILandscapeWeightmapFileFormat`,并相应以 `ILandscapeEditorModulemodule::RegisterHeightmapFileFormat` 和 `ILandscapeEditorModulemodule::RegisterWeightmapFileFormat` 注册这些对象。 -* Implementing the `ILandscapeHeightmapFileFormat` interface in a plugin requires overriding the following functions: -1. **const FLandscapeFileTypeInfo& GetInfo() const**: Returns type information indicating which file types this class handles, and whether or not exporting is supported. -1. **FLandscapeHeightmapInfo Validate(const TCHAR* HeightmapFilename) const** - Validates the named file, or rejects it and returns an error code and message. -1. **FLandscapeHeightmapImportData Import(const TCHAR* HeightmapFilename, FLandscapeFileResolution ExpectedResolution) const** - Actually imports the file. -1. **void Export(const TCHAR* HeightmapFilename, TArrayView Data, FLandscapeFileResolution DataResolution, FVector Scale) const** - Exports the file, if this format supports exporting (see the return value from `GetInfo`). This is the only function that doesn't need to be overridden in order to compile. However, if it is called without being overridden, it will call `check`. -1. **(Destructor)** - Classes that implement this interface should use a virtual destructor, as they will be deleted via a pointer to the interface class. +* 在函数中实现 `ILandscapeHeightmapFileFormat` 接口需要覆盖以下函数: +1. **const FLandscapeFileTypeInfo& GetInfo() const**:返回类型信息说明该类处理的文件类型,以及是否支持导出。 +1. **FLandscapeHeightmapInfo Validate(const TCHAR* HeightmapFilename) const** - 验证命名文件,或将其驳回并返回一个错误代码和消息。 +1. **FLandscapeHeightmapImportData Import(const TCHAR* HeightmapFilename, FLandscapeFileResolution ExpectedResolution) const** - 实际导入文件。 +1. **void Export(const TCHAR* HeightmapFilename, TArrayView Data, FLandscapeFileResolution DataResolution, FVector Scale) const** - 如该格式支持导出,则导出文件(查看来自 `GetInfo` 的返回值)。为进行编译,这是唯一一个不需要被覆盖的函数。然而,如它在未被覆盖的情况下覆盖,它将调用 `check`。 +1. **(Destructor)** - 实现此接口的类应该使用虚拟析构函数,因为他们将通过指向接口类的指针进行删除。 -* Implementing the `ILandscapeHeightmapFileFormat` interface is nearly identical, with only minor differences in some return types: -1. **const FLandscapeFileTypeInfo& GetInfo() const** - Returns type information indicating which file types this class handles, and whether or not exporting is supported. -1. **FLandscapeWeightmapInfo Validate(const TCHAR* WeightmapFilename) const** - Validates the named file, or rejects it and returns an error code and message. -1. **FLandscapeWeightmapImportData Import(const TCHAR* WeightmapFilename, FLandscapeFileResolution ExpectedResolution) const** - Actually imports the file. -1. **void Export(const TCHAR* WeightmapFilename, TArrayView Data, FLandscapeFileResolution DataResolution, FVector Scale) const** - Exports the file, if this format supports exporting (see the return value from `GetInfo`). This is the only function that doesn't need to be overridden in order to compile. However, if it is called without being overridden, it will call `check`. -1. **(Destructor)** - Classes that implement this interface should use a virtual destructor, as they will be deleted via a pointer to the interface class. +* 实现 `ILandscapeHeightmapFileFormat` 接口几乎相同,只在部分返回类型上有细微差别: +1. **const FLandscapeFileTypeInfo& GetInfo() const** - 返回类型信息说明该类处理的文件类型,以及是否支持导出。 +1. **FLandscapeWeightmapInfo Validate(const TCHAR* WeightmapFilename) const** - 验证命名文件,或将其驳回并返回一个错误代码和消息。 +1. **FLandscapeWeightmapImportData Import(const TCHAR* WeightmapFilename, FLandscapeFileResolution ExpectedResolution) const** - 实际导入文件。 +1. **void Export(const TCHAR* WeightmapFilename, TArrayView Data, FLandscapeFileResolution DataResolution, FVector Scale) const** - 如该格式支持导出,则导出文件(查看来自 `GetInfo` 的返回值)。为进行编译,这是唯一一个不需要被覆盖的函数。然而,如它在未被覆盖的情况下覆盖,它将调用 `check`。 +1. **(Destructor)** - 实现此接口的类应该使用虚拟析构函数,因为他们将通过指向接口类的指针进行删除。 -* For further information and examples, you can see the interfaces in `LandscapeFileFormatInterfaces.h`, the .PNG implementations in `LandscapeFileFormatPng.cpp` and `LandscapeFileFormatPng.h` , and the .RAW implementations in `LandscapeFileFormatRaw.cpp` and `LandscapeFileFormatRaw.h`. All of this code is in the LandscapeEditor module in the engine. +* 可查看 `LandscapeFileFormatInterfaces.h` 中的接口、`LandscapeFileFormatPng.cpp` 和 `LandscapeFileFormatPng.h` 中的 .PNG 实现,以及 `LandscapeFileFormatRaw.cpp` 和 `LandscapeFileFormatRaw.h` 中的 .RAW 实现,了解更多信息和范例。所有代码均在引擎的 LandscapeEditor 模块中。 diff --git a/Engine/Documentation/Source/Engine/Landscape/Creation/Plugin/Plugin.INT.udn b/Engine/Documentation/Source/Engine/Landscape/Creation/Plugin/Plugin.INT.udn index 0a6256648c81..5e236c118b29 100644 --- a/Engine/Documentation/Source/Engine/Landscape/Creation/Plugin/Plugin.INT.udn +++ b/Engine/Documentation/Source/Engine/Landscape/Creation/Plugin/Plugin.INT.udn @@ -4,6 +4,8 @@ Crumbs: %ROOT%, Engine, Engine/Landscape, Engine/Landscape/Creation Description:Guide to creating new Landscape import formats via plugin. version: 4.15 parent:Engine/Landscape +topic-image:CreatingCustomLandscapeImporters_topic.png +order:8 Creating your own heightmap and weightmap formats for importing landscape data is accomplished by writing a plugin. The plugin will add your new format to the engine, as well as importing the data from your files. diff --git a/Engine/Documentation/Source/Engine/Landscape/Creation/Plugin/Plugin.JPN.udn b/Engine/Documentation/Source/Engine/Landscape/Creation/Plugin/Plugin.JPN.udn index 0f358547188d..3c89fd9d5ee5 100644 --- a/Engine/Documentation/Source/Engine/Landscape/Creation/Plugin/Plugin.JPN.udn +++ b/Engine/Documentation/Source/Engine/Landscape/Creation/Plugin/Plugin.JPN.udn @@ -1,10 +1,12 @@ -INTSourceChangelist:3347993 +INTSourceChangelist:3480877 Availability:Public Title:カスタム ランドスケープ インポータの作成 Crumbs: %ROOT%, Engine, Engine/Landscape, Engine/Landscape/Creation Description:ランドスケープ インポート フォーマットをプラグインで新規作成する方法 version:4.15 parent:Engine/Landscape +topic-image:CreatingCustomLandscapeImporters_topic.png +order:8 プラグインを書き出して、ランドスケープ データのインポート用に独自のハイトマップおよびウェイトマップを作成することができます。プラグインによって、ファイルからデータがインポートされるだけでなく、エンジンに新規フォーマットが追加されます。 diff --git a/Engine/Documentation/Source/Engine/Landscape/Creation/Plugin/Plugin.KOR.udn b/Engine/Documentation/Source/Engine/Landscape/Creation/Plugin/Plugin.KOR.udn index eee3ca001521..8079cb44aed1 100644 --- a/Engine/Documentation/Source/Engine/Landscape/Creation/Plugin/Plugin.KOR.udn +++ b/Engine/Documentation/Source/Engine/Landscape/Creation/Plugin/Plugin.KOR.udn @@ -1,10 +1,12 @@ -INTSourceChangelist:3347993 +INTSourceChangelist:3480877 Availability: Public Title:커스텀 랜드스케이프 임포터 제작 Crumbs: %ROOT%, Engine, Engine/Landscape, Engine/Landscape/Creation Description:플러그인을 통한 새로운 랜드스케이프 임포트 포맷을 만드는 방법 안내입니다. version: 4.15 parent:Engine/Landscape +topic-image:CreatingCustomLandscapeImporters_topic.png +order:8 랜드스케이프 데이터 임포트를 위한 별도의 하이트맵 및 웨이트맵 제작은 플러그인을 만드는 것으로 가능합니다. 플러그인은 엔진에 새로운 포맷을 추가해 줄 뿐만 아니라, 파일에서도 데이터를 임포트할 수 있습니다. diff --git a/Engine/Documentation/Source/Engine/Landscape/Custom/CreatingCustomHeightmapsAndLayers.JPN.udn b/Engine/Documentation/Source/Engine/Landscape/Custom/CreatingCustomHeightmapsAndLayers.JPN.udn index 416d5e98db05..661afaf37135 100644 --- a/Engine/Documentation/Source/Engine/Landscape/Custom/CreatingCustomHeightmapsAndLayers.JPN.udn +++ b/Engine/Documentation/Source/Engine/Landscape/Custom/CreatingCustomHeightmapsAndLayers.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3318475 +INTSourceChangelist:3347993 Availability:Public Title:カスタム仕様の高さマップとレイヤーの作成および使用方法 Crumbs: @@ -14,13 +14,13 @@ related:Engine/Landscape/Creation [TOC(start:2 end:3)] -ランドスケープで必要とされる高さマップとレイヤーの中には、その両方を外部プログラムで作成しなければならないものがあります。 -アンリアル エンジン (UE4) はこのワークフローのスタイルに対応しています。このガイドでは、このようなワークフローを使う場合の注意点を説明します。 +ランドスケープでは、必要な高さマップとレイヤーの両方を外部プログラムで作成しなければならない場合があります。 +アンリアル エンジン (UE4) はこのスタイルのワークフローに対応しています。本ガイドにおいてワークフローの使用上の注意点を説明します。 ![](Landscape_Example_Image.png) [REGION:note] -このガイドはかなり高度な内容になりますので、Landscape ツールを初めて使う場合はまず [ランドスケープの概要](Engine/Landscape/Editing) をお読みください。 +本ガイドはかなり高度な内容になりますので、Landscape ツールを初めて使う場合はまず [ランドスケープの概要](Engine/Landscape/Editing) をお読みください。 [/REGION] ## レイヤー @@ -57,19 +57,19 @@ related:Engine/Landscape/Creation ### レイヤのインポート -外部のアプリケーションで作成されたレイヤをインポートするプロセスはシンプルですが、以下の設定を行うことで、問題なく作業を行うことができます。 +外部アプリケーションで作成されたレイヤーのインポート プロセスはシンプルです。正常に作業を実行するために、まず以下の設定を確実に行います。 -1. 作業するランドスケープがあることをまず確認してください。ない場合は、ここで 1 つ作成してください。 +1. 作業するランドスケープがあるか、まず確認してください。ない場合は、1 つ作成してください。 -1. 作成したランドスケープ用に新規マテリアルを作成する必要があります。例として非常に簡単なマテリアルを作成しますが、必要に応じて簡単に拡張することができます。設定する必要のあるマテリアルは、このような感じです。 +1. 作成したランドスケープ用に新規マテリアルを作成する必要があります。このガイドでは非常に簡単なマテリアルをサンプルとして作成します。必要に応じて簡単に拡張することができます。設定する必要のあるマテリアルは、このような感じです。 ![](Landscape_Simple_Shader.png) -1. マテリアルを作成したら、それを Landscape アクタに適用します。このような感じになります。 +1. 作成したマテリアルを Landscape アクタに適用します。このような感じになります。 ![](Landscape_Applied_Material.png) -1. マテリアルを適用したまま **Layer Info** を Landscape アクタに追加します。レイヤーごとに **レイヤー情報** オブジェクトを追加します。例えば 3 つ追加してみると、**Layer Info** オブジェクトについては、[ペイント モード](Engine/Landscape/Editing/PaintMode) の [Layer Info Objects (レイヤー情報オブジェクト)](Engine/Landscape/Editing/PaintMode#LayerInfOobjects(レイヤー情報オブジェクト)) セクションを参照してください。 +1. マテリアルを適用したら、次は **Layer Info** を Landscape アクタに追加します。レイヤーごとに **Layer Info** オブジェクトを追加します。ここでは 3 つ追加してみます。**Layer Info** オブジェクトについては、[ペイント モード](Engine/Landscape/Editing/PaintMode) の [Layer Info Objects (レイヤー情報オブジェクト)](Engine/Landscape/Editing/PaintMode#LayerInfOobjects(レイヤー情報オブジェクト)) セクションを参照してください。 ![](Landscape_Create_Layer.png) @@ -77,7 +77,7 @@ related:Engine/Landscape/Creation ![](Landscape_Target_Layers.png) -1. では、レイヤーをインポートします。手順は、レイヤーのインポート先となる Target Layer を **右クリック** してから、表示されたダイアログ ボックスからインポートしたいレイヤーを選択するだけです。 +1. では、レイヤーをインポートします。レイヤーをインポートする Target Layer を **右クリック** します。そして表示されたダイアログ ボックスからインポートしたいレイヤーを選択します。これだけです。 ![](Landscape_Import_Layer_Option.png) @@ -86,11 +86,11 @@ related:Engine/Landscape/Creation ![](Landscape_Layer_Import_Error.png) この問題を解決するには、インポート先の **ランドスケープ** レイヤーの大きさを決める必要があります。方法は、対象とする **ターゲット レイヤー** を右クリックしてレイヤーをエクスポートし、ポップアップ表示されるダイアログ ボックスから **[Export (エクスポート)]** を選択します。 - そうすると、レイヤー ファイルを PC 上のどこかに保存するようにメッセージが出ます。ファイルを保存したら、それを開いてレイヤーのサイズを決定することができます。 + そうすると、レイヤー ファイルを PC 上のどこかに保存するようにメッセージが出ます。ファイルを保存したら、そのファイルを開けばレイヤーのサイズを決定することができます。 ## 高さマップ -外部ツールを使用してベース高さマップを作成してアンリアル内で作業をすると、ランドスケープ作成プロセスが迅速化するのでお勧めです。このベース高さマップは、後でアンリアル エディタ内の編集ツールを使って、インポート、クリーン アップ、修正、ランドスケープのカスタム、ワールドや希望するゲームプレイへのフィットが可能です。 +ベースとなる高さマップを外部ツールで作成してからアンリアルで作業をすると、ランドスケープ作成プロセスがスピードアップするのでお勧めです。このベースとなる高さマップは、アンリアル エディタ内の編集ツールを使って、インポート、クリーン アップ、修正、ランドスケープのカスタム、ワールドや希望するゲームプレイへのフィットを後で行うことができます。 ### 高さマップの形式 @@ -125,7 +125,6 @@ related:Engine/Landscape/Creation PC 上に高さマップを保存したら Landscape ツールの中で使ってみましょう。 1. Landscape ツールを開いたら、[Manage モード](Engine/Landscape/Editing/ManageMode) を開きます。 - ![](Landscape_Open_Manage_Mode.png) 1. **[Import from File (ファイルからインポート)]** のオプションを選択します。 @@ -136,7 +135,7 @@ PC 上に高さマップを保存したら Landscape ツールの中で使って ![](Engine\Landscape\Creation\Landscape_Import_Section_Button.png) -1. 完了したら、**[Import]** ボタンを押して、高さマップを元にランドスケープを新規作成します。 +1. 完了したら、**[Import]** ボタンを押して、高さマップをベースにしてランドスケープを新規作成します。 ![](Landscape_Press_Import.png) @@ -148,25 +147,4 @@ PC 上に高さマップを保存したら Landscape ツールの中で使って ![](Engine\Landscape\Creation\Landscape_Import_Heightmap_Finsh.png) -インポートしたばかりの高さマップを元に、作業用のランドスケープが新規作成されました。 - - -## カスタム インポーターの書き出し - -* インポーターを新規作成するためには、プラグインが `ILandscapeHeightmapFileFormat` および `ILandscapeWeightmapFileFormat` を実装するオブジェクトのインスタンスを作成し、これらのオブジェクトをそれぞれ `ILandscapeEditorModulemodule::RegisterHeightmapFileFormat`、`ILandscapeEditorModulemodule::RegisterWeightmapFileFormat` で登録する必要があります。 - -* プラグインの `ILandscapeHeightmapFileFormat` インターフェースが次の関数をオーバーライドすることが必要です。 -1. **const FLandscapeFileTypeInfo& GetInfo() const**:このクラスを処理するファイル タイプ、そしてエクスポート処理のサポート有無を示す型の情報を返します。 -1. **FLandscapeHeightmapInfo Validate(const TCHAR* HeightmapFilename) const** - 名前のついたファイルを承認、またはエラーコードとメッセージをつけて却下します -1. **FLandscapeHeightmapImportData Import(const TCHAR* HeightmapFilename, FLandscapeFileResolution ExpectedResolution) const** - 実際にファイルをインポートします。 -1. **void Export(const TCHAR* HeightmapFilename, TArrayView Data, FLandscapeFileResolution DataResolution, FVector Scale) const** - エクスポートできる形式であれば、エクスポートします (`GetInfo` からの戻り値を参照)。コンパイルにオーバーライドを必要としない唯一の関数です。ただし、オーバーライドされずに呼び出されると、`check` を呼び出します。 -1. **(Destructor)** - このインターフェースを実装するクラスは、インターフェース クラスへのポインタによって削除されるので、仮想ディストラクタを使用します。 - -* 戻り値の型が若干違いますが、`ILandscapeHeightmapFileFormat` インターフェースを実装している状態とほぼ同じです。 -1. **const FLandscapeFileTypeInfo& GetInfo() const** - このクラスを処理するファイル タイプがどれか、そしてエクスポート処理をサポートしているかどうかを表示する型情報を返します。 -1. **FLandscapeWeightmapInfo Validate(const TCHAR* WeightmapFilename) const** - 名前のついたファイルを承認、またはエラーコードとメッセージをつけて却下します -1. **FLandscapeWeightmapImportData Import(const TCHAR* WeightmapFilename, FLandscapeFileResolution ExpectedResolution) const** - 実際にファイルをインポートします。 -1. **void Export(const TCHAR* WeightmapFilename, TArrayView Data, FLandscapeFileResolution DataResolution, FVector Scale) const** - エクスポートできる形式であれば、エクスポートします (`GetInfo` からの戻り値を参照)。コンパイルにオーバーライドを必要としない唯一の関数です。ただし、オーバーライドされずに呼び出されると、`check` を呼び出します。 -1. **(Destructor)** - このインターフェースを実装するクラスは、インターフェース クラスへのポインタによって削除されるので、仮想ディストラクタを使用します。 - -* 詳細とサンプルについては、`LandscapeFileFormatInterfaces.h` のインターフェース、 in `LandscapeFileFormatPng.cpp1` と `LandscapeFileFormatPng.h` の.PNG 実装、`LandscapeFileFormatRaw.cpp` と `LandscapeFileFormatRaw.h` の .RAW 実装をご覧ください。このコードはすべて、エンジンの LandscapeEditor モジュールに入っています。 +インポートした高さマップをベースに、作業用のランドスケープが新規作成されました。 diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/CopyPaste/CopyAndPasteRegion.CHN.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/CopyPaste/CopyAndPasteRegion.CHN.udn new file mode 100644 index 000000000000..b270b80895c7 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/CopyPaste/CopyAndPasteRegion.CHN.udn @@ -0,0 +1,107 @@ +INTSourceChangelist:0 +Availability: Public +Crumbs: %ROOT% +Title: Copy and Paste Region +Description: This is an overview of the Copy and Paste Region tool. +Type: Reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:11 +Tags:Landscape +tags:region +Topic-image:CopyPaste_Topic.png + +[TOC(start:2 end:2)] + + +The **Copy/Paste** tool will copy the height data from one area of a Landscape to another area through the use of the gizmos. You can also import existing +heightmap data that can be pasted into the Landscape or export selected regions of your height data as it's own heightmap .raw file for use in an external +program. + + +## Using the Copy/Paste Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 2ICAxrLsH60 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 40 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + + +In this demonstration, the gizmo is manually scaled to copy a region and then paste it in another location, and then the Region Selection is used to paint an area the gizmo can automatically scaled +to fit so that it can be copy and pasted to another location. + +### Copy/Paste Gizmo + +The Gizmo is used to capture the Landscape's height data that can then be used. This enables you to easily move parts of your Landscape, import height data from an existing heightmap, or to export +your height data to a heightmap file that can be used with an external program, like World Machine. + +[REGION:imagetable] +| ![](gizmo1.png)(w:370) | ![](gizmo2.png)(w:370) | ![](gizmo3.png)(w:370) | +| --- | --- | --- | +|||| +[/REGION] + +In these examples, the gizmo bounds have been scaled around a painted region that is to be captured, then the gizmo is positioned to another part of the Landscape, and, lastly, it's pasted onto the existing Landscape. + +To learn how to use the gizmo, you can read about the [gizmo tool](Engine/Landscape/Editing/Gizmos/) here. + + +## Tool Settings + +[REGION:imagetable] +| ![Copy/Paste Tool](Landscape_CopyPaste.png)(h:75) | ![](RegionCopyAndPasteToolProperties.png)(h:250) | +| --- | --- | +||| +[/REGION] + + +| **Property** | **Description** | +| ------------ | --------------- | +| **Copy Data to Gizmo** | Copies the data within the gizmo bounds to the gizmo taking into account any masking from the selected regions. | +| **Fit Gizmo to Selected Regions** | Positions and resizes the gizmo so that it completely encompasses all region selections. | +| **Fit Height Values to Gizmo** | Scales the data in the gizmo to fit the gizmo's Z-size. | +| **Clear Gizmo Data** | Clears the gizmo of any copied data. | +| **Tool Strength** | Strength of the tool. If you're using a pen/tablet with pressure-sensing, the pressure used affects the strength of the tool. | +| **Paste Mode** | Whether the past will only raise, only lower, or both raise and lower. [INCLUDE:#pastemode] | +| **Gizmo Copy/Paste All Layers** | If set, copies and pastes all layers. Otherwise, it will only copy and paste the layer selected in the targets panel. | +| **Snap Gizmo to Landscape Grid** | Makes sure the gizmo is snapped perfectly to the Landscape so that the sample points line up, which makes copy and pastes less blurry. Irrelevant if gizmo is scaled. | +| **Use Smooth Gizmo Brush** | Smooth the edges of the gizmo data into the Landscape. Without this, the edges of the pasted data will be sharp. | +| [REGION:tablesection] Advanced [/REGION] || +| **Gizmo Import/Export** | The available options that can be used when importing or exporting the selected region's heightmap. [INCLUDE:#importexport] | + + + + \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/CopyPaste/CopyAndPasteRegion.INT.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/CopyPaste/CopyAndPasteRegion.INT.udn new file mode 100644 index 000000000000..c058fb2dd68a --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/CopyPaste/CopyAndPasteRegion.INT.udn @@ -0,0 +1,106 @@ +Availability: Public +Crumbs: %ROOT% +Title: Copy and Paste Region +Description: This is an overview of the Copy and Paste Region tool. +Type: Reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:11 +Tags:Landscape +tags:region +Topic-image:CopyPaste_Topic.png + +[TOC(start:2 end:2)] + + +The **Copy/Paste** tool will copy the height data from one area of a Landscape to another area through the use of the gizmos. You can also import existing +heightmap data that can be pasted into the Landscape or export selected regions of your height data as it's own heightmap .raw file for use in an external +program. + + +## Using the Copy/Paste Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 2ICAxrLsH60 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 40 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + + +In this demonstration, the gizmo is manually scaled to copy a region and then paste it in another location, and then the Region Selection is used to paint an area the gizmo can automatically scaled +to fit so that it can be copy and pasted to another location. + +### Copy/Paste Gizmo + +The Gizmo is used to capture the Landscape's height data that can then be used. This enables you to easily move parts of your Landscape, import height data from an existing heightmap, or to export +your height data to a heightmap file that can be used with an external program, like World Machine. + +[REGION:imagetable] +| ![](gizmo1.png)(w:370) | ![](gizmo2.png)(w:370) | ![](gizmo3.png)(w:370) | +| --- | --- | --- | +|||| +[/REGION] + +In these examples, the gizmo bounds have been scaled around a painted region that is to be captured, then the gizmo is positioned to another part of the Landscape, and, lastly, it's pasted onto the existing Landscape. + +To learn how to use the gizmo, you can read about the [gizmo tool](Engine/Landscape/Editing/Gizmos/) here. + + +## Tool Settings + +[REGION:imagetable] +| ![Copy/Paste Tool](Landscape_CopyPaste.png)(h:75) | ![](RegionCopyAndPasteToolProperties.png)(h:250) | +| --- | --- | +||| +[/REGION] + + +| **Property** | **Description** | +| ------------ | --------------- | +| **Copy Data to Gizmo** | Copies the data within the gizmo bounds to the gizmo taking into account any masking from the selected regions. | +| **Fit Gizmo to Selected Regions** | Positions and resizes the gizmo so that it completely encompasses all region selections. | +| **Fit Height Values to Gizmo** | Scales the data in the gizmo to fit the gizmo's Z-size. | +| **Clear Gizmo Data** | Clears the gizmo of any copied data. | +| **Tool Strength** | Strength of the tool. If you're using a pen/tablet with pressure-sensing, the pressure used affects the strength of the tool. | +| **Paste Mode** | Whether the past will only raise, only lower, or both raise and lower. [INCLUDE:#pastemode] | +| **Gizmo Copy/Paste All Layers** | If set, copies and pastes all layers. Otherwise, it will only copy and paste the layer selected in the targets panel. | +| **Snap Gizmo to Landscape Grid** | Makes sure the gizmo is snapped perfectly to the Landscape so that the sample points line up, which makes copy and pastes less blurry. Irrelevant if gizmo is scaled. | +| **Use Smooth Gizmo Brush** | Smooth the edges of the gizmo data into the Landscape. Without this, the edges of the pasted data will be sharp. | +| [REGION:tablesection] Advanced [/REGION] || +| **Gizmo Import/Export** | The available options that can be used when importing or exporting the selected region's heightmap. [INCLUDE:#importexport] | + + + + \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/CopyPaste/CopyAndPasteRegion.JPN.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/CopyPaste/CopyAndPasteRegion.JPN.udn new file mode 100644 index 000000000000..b270b80895c7 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/CopyPaste/CopyAndPasteRegion.JPN.udn @@ -0,0 +1,107 @@ +INTSourceChangelist:0 +Availability: Public +Crumbs: %ROOT% +Title: Copy and Paste Region +Description: This is an overview of the Copy and Paste Region tool. +Type: Reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:11 +Tags:Landscape +tags:region +Topic-image:CopyPaste_Topic.png + +[TOC(start:2 end:2)] + + +The **Copy/Paste** tool will copy the height data from one area of a Landscape to another area through the use of the gizmos. You can also import existing +heightmap data that can be pasted into the Landscape or export selected regions of your height data as it's own heightmap .raw file for use in an external +program. + + +## Using the Copy/Paste Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 2ICAxrLsH60 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 40 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + + +In this demonstration, the gizmo is manually scaled to copy a region and then paste it in another location, and then the Region Selection is used to paint an area the gizmo can automatically scaled +to fit so that it can be copy and pasted to another location. + +### Copy/Paste Gizmo + +The Gizmo is used to capture the Landscape's height data that can then be used. This enables you to easily move parts of your Landscape, import height data from an existing heightmap, or to export +your height data to a heightmap file that can be used with an external program, like World Machine. + +[REGION:imagetable] +| ![](gizmo1.png)(w:370) | ![](gizmo2.png)(w:370) | ![](gizmo3.png)(w:370) | +| --- | --- | --- | +|||| +[/REGION] + +In these examples, the gizmo bounds have been scaled around a painted region that is to be captured, then the gizmo is positioned to another part of the Landscape, and, lastly, it's pasted onto the existing Landscape. + +To learn how to use the gizmo, you can read about the [gizmo tool](Engine/Landscape/Editing/Gizmos/) here. + + +## Tool Settings + +[REGION:imagetable] +| ![Copy/Paste Tool](Landscape_CopyPaste.png)(h:75) | ![](RegionCopyAndPasteToolProperties.png)(h:250) | +| --- | --- | +||| +[/REGION] + + +| **Property** | **Description** | +| ------------ | --------------- | +| **Copy Data to Gizmo** | Copies the data within the gizmo bounds to the gizmo taking into account any masking from the selected regions. | +| **Fit Gizmo to Selected Regions** | Positions and resizes the gizmo so that it completely encompasses all region selections. | +| **Fit Height Values to Gizmo** | Scales the data in the gizmo to fit the gizmo's Z-size. | +| **Clear Gizmo Data** | Clears the gizmo of any copied data. | +| **Tool Strength** | Strength of the tool. If you're using a pen/tablet with pressure-sensing, the pressure used affects the strength of the tool. | +| **Paste Mode** | Whether the past will only raise, only lower, or both raise and lower. [INCLUDE:#pastemode] | +| **Gizmo Copy/Paste All Layers** | If set, copies and pastes all layers. Otherwise, it will only copy and paste the layer selected in the targets panel. | +| **Snap Gizmo to Landscape Grid** | Makes sure the gizmo is snapped perfectly to the Landscape so that the sample points line up, which makes copy and pastes less blurry. Irrelevant if gizmo is scaled. | +| **Use Smooth Gizmo Brush** | Smooth the edges of the gizmo data into the Landscape. Without this, the edges of the pasted data will be sharp. | +| [REGION:tablesection] Advanced [/REGION] || +| **Gizmo Import/Export** | The available options that can be used when importing or exporting the selected region's heightmap. [INCLUDE:#importexport] | + + + + \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/CopyPaste/CopyAndPasteRegion.KOR.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/CopyPaste/CopyAndPasteRegion.KOR.udn new file mode 100644 index 000000000000..b270b80895c7 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/CopyPaste/CopyAndPasteRegion.KOR.udn @@ -0,0 +1,107 @@ +INTSourceChangelist:0 +Availability: Public +Crumbs: %ROOT% +Title: Copy and Paste Region +Description: This is an overview of the Copy and Paste Region tool. +Type: Reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:11 +Tags:Landscape +tags:region +Topic-image:CopyPaste_Topic.png + +[TOC(start:2 end:2)] + + +The **Copy/Paste** tool will copy the height data from one area of a Landscape to another area through the use of the gizmos. You can also import existing +heightmap data that can be pasted into the Landscape or export selected regions of your height data as it's own heightmap .raw file for use in an external +program. + + +## Using the Copy/Paste Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 2ICAxrLsH60 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 40 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + + +In this demonstration, the gizmo is manually scaled to copy a region and then paste it in another location, and then the Region Selection is used to paint an area the gizmo can automatically scaled +to fit so that it can be copy and pasted to another location. + +### Copy/Paste Gizmo + +The Gizmo is used to capture the Landscape's height data that can then be used. This enables you to easily move parts of your Landscape, import height data from an existing heightmap, or to export +your height data to a heightmap file that can be used with an external program, like World Machine. + +[REGION:imagetable] +| ![](gizmo1.png)(w:370) | ![](gizmo2.png)(w:370) | ![](gizmo3.png)(w:370) | +| --- | --- | --- | +|||| +[/REGION] + +In these examples, the gizmo bounds have been scaled around a painted region that is to be captured, then the gizmo is positioned to another part of the Landscape, and, lastly, it's pasted onto the existing Landscape. + +To learn how to use the gizmo, you can read about the [gizmo tool](Engine/Landscape/Editing/Gizmos/) here. + + +## Tool Settings + +[REGION:imagetable] +| ![Copy/Paste Tool](Landscape_CopyPaste.png)(h:75) | ![](RegionCopyAndPasteToolProperties.png)(h:250) | +| --- | --- | +||| +[/REGION] + + +| **Property** | **Description** | +| ------------ | --------------- | +| **Copy Data to Gizmo** | Copies the data within the gizmo bounds to the gizmo taking into account any masking from the selected regions. | +| **Fit Gizmo to Selected Regions** | Positions and resizes the gizmo so that it completely encompasses all region selections. | +| **Fit Height Values to Gizmo** | Scales the data in the gizmo to fit the gizmo's Z-size. | +| **Clear Gizmo Data** | Clears the gizmo of any copied data. | +| **Tool Strength** | Strength of the tool. If you're using a pen/tablet with pressure-sensing, the pressure used affects the strength of the tool. | +| **Paste Mode** | Whether the past will only raise, only lower, or both raise and lower. [INCLUDE:#pastemode] | +| **Gizmo Copy/Paste All Layers** | If set, copies and pastes all layers. Otherwise, it will only copy and paste the layer selected in the targets panel. | +| **Snap Gizmo to Landscape Grid** | Makes sure the gizmo is snapped perfectly to the Landscape so that the sample points line up, which makes copy and pastes less blurry. Irrelevant if gizmo is scaled. | +| **Use Smooth Gizmo Brush** | Smooth the edges of the gizmo data into the Landscape. Without this, the edges of the pasted data will be sharp. | +| [REGION:tablesection] Advanced [/REGION] || +| **Gizmo Import/Export** | The available options that can be used when importing or exporting the selected region's heightmap. [INCLUDE:#importexport] | + + + + \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Erosion/Erosion.CHN.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Erosion/Erosion.CHN.udn new file mode 100644 index 000000000000..336533e96736 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Erosion/Erosion.CHN.udn @@ -0,0 +1,95 @@ +INTSourceChangelist:0 +Availability: Public +Crumbs: %ROOT% +Title: Erosion +Description: This is an overview of the Erosion painting tool. +Type: Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:5 +Tags:Landscape +Topic-image:Erosion_Topic.png + +[TOC(start:2 end:2)] + + +The **Erosion** tool uses a thermal erosion simulation to adjust the height of the Landscape heightmap. This simulates the transfer of soil from higher elevations to lower elevations. The +larger the difference in elevation, the more erosion will occur. This tool also applies a noise effect on top of the erosion, if desired, to provide a more natural random appearance. + + +## Using the Erosion Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + bBehSLFnJ7Q + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 49 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +In this example, the Erosion tool is being used on the front and back sides of the mountain face. On the front side, the incline is not as steep, so the surface is not eroded as quickly with the +settings being used. However, on the back side, the incline is much steeper and erodes much more quickly. + + +Use the following controls to Sculpt with Erosion for your Landscape heightmap: + +| **Controls** | **Operation** | +| --- | --- | +| **Left Mouse Button** | Applies erosion values that raises, lowers, or does both to the the heightmap. | + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before](Erosion1.png)(w:750) + [/PARAM] + [PARAM:after] + ![After](Erosion2.png)(w:750) + [/PARAM] +[/OBJECT] + +In this example, Erosion uses noise painted onto the hillside to raise or lower the surface giving it variations in different heights based on the strength and various property values used to drive +the erosion being applied. + + +## Tool Settings + +[REGION:imagetable] +| ![Erosion Tool](Landscape_Erosion.png)(h:75) | ![](ErosionToolProperties.png)(h:170) | +| --- | --- | +||| +[/REGION] + +| **Property** | **Description** | +| ------------ | --------------- | +| **Tool Strength** | Controls how much effect each brush stroke has. | +| **Threshold** | The minimum height difference necessary for the erosion effects to be applied. Smaller values will result in more erosion being applied. | +| **Surface Thickness** | The thickness of the surface for the layer weight erosion effect. | +| **Iterations** | The number of iterations performed. Larger values result in more levels of erosion. | +| **Noise Mode** | Whether to apply noise to raise or lower the heightmap, or do both. [INCLUDE:#noise] | +| **Noise Scale** | The size of the noise filter used. The noise filter is related to position and scale, which means if you do not change **Noise Scale**, the same filter is applied to the same position many times. | + + + + + + diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Erosion/Erosion.INT.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Erosion/Erosion.INT.udn new file mode 100644 index 000000000000..50b3a26317e9 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Erosion/Erosion.INT.udn @@ -0,0 +1,94 @@ +Availability: Public +Crumbs: %ROOT% +Title: Erosion +Description: This is an overview of the Erosion painting tool. +Type: Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:5 +Tags:Landscape +Topic-image:Erosion_Topic.png + +[TOC(start:2 end:2)] + + +The **Erosion** tool uses a thermal erosion simulation to adjust the height of the Landscape heightmap. This simulates the transfer of soil from higher elevations to lower elevations. The +larger the difference in elevation, the more erosion will occur. This tool also applies a noise effect on top of the erosion, if desired, to provide a more natural random appearance. + + +## Using the Erosion Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + bBehSLFnJ7Q + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 49 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +In this example, the Erosion tool is being used on the front and back sides of the mountain face. On the front side, the incline is not as steep, so the surface is not eroded as quickly with the +settings being used. However, on the back side, the incline is much steeper and erodes much more quickly. + + +Use the following controls to Sculpt with Erosion for your Landscape heightmap: + +| **Controls** | **Operation** | +| --- | --- | +| **Left Mouse Button** | Applies erosion values that raises, lowers, or does both to the the heightmap. | + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before](Erosion1.png)(w:750) + [/PARAM] + [PARAM:after] + ![After](Erosion2.png)(w:750) + [/PARAM] +[/OBJECT] + +In this example, Erosion uses noise painted onto the hillside to raise or lower the surface giving it variations in different heights based on the strength and various property values used to drive +the erosion being applied. + + +## Tool Settings + +[REGION:imagetable] +| ![Erosion Tool](Landscape_Erosion.png)(h:75) | ![](ErosionToolProperties.png)(h:170) | +| --- | --- | +||| +[/REGION] + +| **Property** | **Description** | +| ------------ | --------------- | +| **Tool Strength** | Controls how much effect each brush stroke has. | +| **Threshold** | The minimum height difference necessary for the erosion effects to be applied. Smaller values will result in more erosion being applied. | +| **Surface Thickness** | The thickness of the surface for the layer weight erosion effect. | +| **Iterations** | The number of iterations performed. Larger values result in more levels of erosion. | +| **Noise Mode** | Whether to apply noise to raise or lower the heightmap, or do both. [INCLUDE:#noise] | +| **Noise Scale** | The size of the noise filter used. The noise filter is related to position and scale, which means if you do not change **Noise Scale**, the same filter is applied to the same position many times. | + + + + + + diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Erosion/Erosion.JPN.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Erosion/Erosion.JPN.udn new file mode 100644 index 000000000000..2fc9d95ca0eb --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Erosion/Erosion.JPN.udn @@ -0,0 +1,95 @@ +INTSourceChangelist:3482403 +Availability:Public +Crumbs: %ROOT% +Title:Erosion +Description:Erosion ペイント ツールの概要です。 +Type:Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:5 +Tags:Landscape +Topic-image:Erosion_Topic.png + +[TOC(start:2 end:2)] + + +**Erosion** ツールは、ランドスケープ ハイトマップの高さを調整するために熱による浸食シミュレーションを使用します。高度が高いところから低いところまでの土壌の動きをシミュレートします。高低差が大きくなると、 +浸食も大きくなります。外観に自然なランダムさが出るように、必要に応じて、浸食の他にノイズ エフェクトをツールに適用することができます。 + + +## Erosion ツールの使用方法 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + bBehSLFnJ7Q + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 49 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +この例では、Erosion ツールは山の正面と裏側の表面に適用されています。正面の傾斜はそれほど急ではないので、 +適用する設定では、表面の侵食はそれほど速くはなりません。ただし、裏側は傾斜が急なので、かなり速く侵食します。 + + +ランドスケープ ハイトマップでの侵食によるスカルプトでは、以下の調節ができます。 + +| **操作** | **処理内容** | +| --- | --- | +| **左マウスボタン** | 侵食値の上げ下げ、またはその両方をハイトマップに適用します。 | + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before](Erosion1.png)(w:750) + [/PARAM] + [PARAM:after] + ![After](Erosion2.png)(w:750) + [/PARAM] +[/OBJECT] + +この例では、浸食は丘の斜面にペイントされたノイズを使ってサーフェスに高低差を出しています。 +強度と各種プロパティ値を使って適用中の侵食を調整して、様々な高さを出しています。 + + +## ツール設定 + +[REGION:imagetable] +| ![Erosion Tool](Landscape_Erosion.png)(h:75) | ![](ErosionToolProperties.png)(h:170) | +| --- | --- | +||| +[/REGION] + +| **プロパティ** | **説明** | +| ------------ | --------------- | +| **Tool Strength** | 1 回のブラシ ストロークの強度を調節します。 | +| **Threshold** | 浸食エフェクトの適用に必要な最低限の高低差です。この値が小さいほど、適用される浸食エフェクトが増加します。 | +| **Surface Thickness** | レイヤーのウェイトの浸食エフェクトに使用するサーフェスの厚みです。 | +| **Iterations** | 実行されるイタレーション数です。この値が大きくなるほど、浸食が大きくなります。 | +| **Noise Mode** | ノイズを適用した高さマップの上げ下げ、あるいはその両方の適用を設定します。 [INCLUDE:#noise] | +| **Noise Scale** | 使用するノイズ フィルターの大きさです。ノイズ フィルターは、位置とスケールに関係します。したがって、**Noise Scale** に変更がない限り、同じフィルターが同じ位置に何度も適用されます。 | + + + + + + diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Erosion/Erosion.KOR.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Erosion/Erosion.KOR.udn new file mode 100644 index 000000000000..336533e96736 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Erosion/Erosion.KOR.udn @@ -0,0 +1,95 @@ +INTSourceChangelist:0 +Availability: Public +Crumbs: %ROOT% +Title: Erosion +Description: This is an overview of the Erosion painting tool. +Type: Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:5 +Tags:Landscape +Topic-image:Erosion_Topic.png + +[TOC(start:2 end:2)] + + +The **Erosion** tool uses a thermal erosion simulation to adjust the height of the Landscape heightmap. This simulates the transfer of soil from higher elevations to lower elevations. The +larger the difference in elevation, the more erosion will occur. This tool also applies a noise effect on top of the erosion, if desired, to provide a more natural random appearance. + + +## Using the Erosion Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + bBehSLFnJ7Q + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 49 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +In this example, the Erosion tool is being used on the front and back sides of the mountain face. On the front side, the incline is not as steep, so the surface is not eroded as quickly with the +settings being used. However, on the back side, the incline is much steeper and erodes much more quickly. + + +Use the following controls to Sculpt with Erosion for your Landscape heightmap: + +| **Controls** | **Operation** | +| --- | --- | +| **Left Mouse Button** | Applies erosion values that raises, lowers, or does both to the the heightmap. | + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before](Erosion1.png)(w:750) + [/PARAM] + [PARAM:after] + ![After](Erosion2.png)(w:750) + [/PARAM] +[/OBJECT] + +In this example, Erosion uses noise painted onto the hillside to raise or lower the surface giving it variations in different heights based on the strength and various property values used to drive +the erosion being applied. + + +## Tool Settings + +[REGION:imagetable] +| ![Erosion Tool](Landscape_Erosion.png)(h:75) | ![](ErosionToolProperties.png)(h:170) | +| --- | --- | +||| +[/REGION] + +| **Property** | **Description** | +| ------------ | --------------- | +| **Tool Strength** | Controls how much effect each brush stroke has. | +| **Threshold** | The minimum height difference necessary for the erosion effects to be applied. Smaller values will result in more erosion being applied. | +| **Surface Thickness** | The thickness of the surface for the layer weight erosion effect. | +| **Iterations** | The number of iterations performed. Larger values result in more levels of erosion. | +| **Noise Mode** | Whether to apply noise to raise or lower the heightmap, or do both. [INCLUDE:#noise] | +| **Noise Scale** | The size of the noise filter used. The noise filter is related to position and scale, which means if you do not change **Noise Scale**, the same filter is applied to the same position many times. | + + + + + + diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Flatten/Flatten.CHN.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Flatten/Flatten.CHN.udn new file mode 100644 index 000000000000..61e8fc195d65 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Flatten/Flatten.CHN.udn @@ -0,0 +1,90 @@ +INTSourceChangelist:0 +Availability: Public +Crumbs: %ROOT% +Title: Flatten +Description: This is an overview of the Flatten painting tool. +Type: Reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:3 +Tags:Landscape +Topic-image:Flatten_topic.png + +[TOC(start:2 end:2)] + +The **Flatten** tool pushes or pulls all other parts of the heightmap to the level that is currently under the mouse when activated. This can raise or lower the surrounding +heightmap values to be the same value. + +## Using the Flatten Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 3amWaEH13V8 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 47 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +In this example, the Flatten tool is being used in the middle of the hillside to flatten out areas at the point where the mouse click was initiated. As long as the mouse is held down, the height value +that was detected is used along any surface to raise or lower (depending on your tool settings) to that height. + + +Use the following controls to sculpt your Landscape heightmap: + +| **Controls** | **Operation** | +| --- | --- | +| **Left Mouse Button** | Flattens or levels by both raising and lowering or individually raising and lowering the heightmap. | + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before Flattening](FlattenBefore.png)(w:750) + [/PARAM] + [PARAM:after] + ![After Flattening](FlattenAfter.png)(w:750) + [/PARAM] +[/OBJECT] + +The brush strength determines the amount of Flattening that can happen when using the Flatten tool. + +## Tool Settings + +[REGION:imagetable] +| ![Flatten Tool](Landscape_FlattenTool.png) | ![](FlattenToolProperties.png)(h:185) | +| --- | --- | +||| +[/REGION] + + +| **Property** | **Description** | +| ------------ | --------------- | +| **Flatten Target** | Sets the target height toward which to flatten. | +| **Tool Strength** | Controls how much smoothing occurs with each brush stroke has. | +| **Flatten Mode** | Determines whether the tool will raise or lower the heightmap section under the brush. [INCLUDE:#flattenmode] | +| **Use Slope Flatten** | If checked, flattens along the Landscape's existing slope instead of flattening toward a horizontal plane. | +| **Pick Value Per Apply** | If checked, constantly selects new values to flatten toward, instead of only using the first clicked point. | +| [REGION:tablesection] Advanced [/REGION] || +| **Show Preview Grid** | When Flatten Target is enabled, you can enable this option to show a preview grid for the flatten target height. | + + + + diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Flatten/Flatten.INT.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Flatten/Flatten.INT.udn new file mode 100644 index 000000000000..5dc94bc526cc --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Flatten/Flatten.INT.udn @@ -0,0 +1,89 @@ +Availability: Public +Crumbs: %ROOT% +Title: Flatten +Description: This is an overview of the Flatten painting tool. +Type: Reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:3 +Tags:Landscape +Topic-image:Flatten_topic.png + +[TOC(start:2 end:2)] + +The **Flatten** tool pushes or pulls all other parts of the heightmap to the level that is currently under the mouse when activated. This can raise or lower the surrounding +heightmap values to be the same value. + +## Using the Flatten Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 3amWaEH13V8 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 47 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +In this example, the Flatten tool is being used in the middle of the hillside to flatten out areas at the point where the mouse click was initiated. As long as the mouse is held down, the height value +that was detected is used along any surface to raise or lower (depending on your tool settings) to that height. + + +Use the following controls to sculpt your Landscape heightmap: + +| **Controls** | **Operation** | +| --- | --- | +| **Left Mouse Button** | Flattens or levels by both raising and lowering or individually raising and lowering the heightmap. | + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before Flattening](FlattenBefore.png)(w:750) + [/PARAM] + [PARAM:after] + ![After Flattening](FlattenAfter.png)(w:750) + [/PARAM] +[/OBJECT] + +The brush strength determines the amount of Flattening that can happen when using the Flatten tool. + +## Tool Settings + +[REGION:imagetable] +| ![Flatten Tool](Landscape_FlattenTool.png) | ![](FlattenToolProperties.png)(h:185) | +| --- | --- | +||| +[/REGION] + + +| **Property** | **Description** | +| ------------ | --------------- | +| **Flatten Target** | Sets the target height toward which to flatten. | +| **Tool Strength** | Controls how much smoothing occurs with each brush stroke has. | +| **Flatten Mode** | Determines whether the tool will raise or lower the heightmap section under the brush. [INCLUDE:#flattenmode] | +| **Use Slope Flatten** | If checked, flattens along the Landscape's existing slope instead of flattening toward a horizontal plane. | +| **Pick Value Per Apply** | If checked, constantly selects new values to flatten toward, instead of only using the first clicked point. | +| [REGION:tablesection] Advanced [/REGION] || +| **Show Preview Grid** | When Flatten Target is enabled, you can enable this option to show a preview grid for the flatten target height. | + + + + diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Flatten/Flatten.JPN.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Flatten/Flatten.JPN.udn new file mode 100644 index 000000000000..bccd3844295f --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Flatten/Flatten.JPN.udn @@ -0,0 +1,90 @@ +INTSourceChangelist:3482403 +Availability:Public +Crumbs: %ROOT% +Title:Flatten +Description:Flatten ペイント ツールの概要です。 +Type:Reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:3 +Tags:Landscape +Topic-image:Flatten_topic.png + +[TOC(start:2 end:2)] + +**Flatten** ツールは、クリックしたカーソルが置かれたランドスケープのレベルまで、ランドスケープの上げ下げを行います。周囲のハイトマップ値を上げ下げして、 +同じ値にすることができます。 + +## Flatten ツールの使用方法 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 3amWaEH13V8 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 47 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +この例では丘の斜面の中央に Flatten ツールを適用して、マウスでクリックした領域を平坦化しています。マウスを押している間、 +ハイト値がずっとサーフェスに使用されます。 + + +以下の制御を使って、ランドスケープ ハイトマップを生成します。 + +| **操作** | **処理内容** | +| --- | --- | +| **マウスの左ボタン** | ハイトマップを上げる、下げる、またはその両方の操作をして平坦化 (均一化) します。 | + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before Flattening](FlattenBefore.png)(w:750) + [/PARAM] + [PARAM:after] + ![After Flattening](FlattenAfter.png)(w:750) + [/PARAM] +[/OBJECT] + +Flatten ツールを使う場合、ブラシの強度で平坦化する面積が決まります。 + +## ツール設定 + +[REGION:imagetable] +| ![Flatten Tool](Landscape_FlattenTool.png) | ![](FlattenToolProperties.png)(h:185) | +| --- | --- | +||| +[/REGION] + + +| **プロパティ** | **説明** | +| ------------ | --------------- | +| **Flatten Target** | 平坦化ターゲットの高さを設定します。 | +| **Total Strength** | 1 回のブラシ ストロークによるスムージング加減を調節します。 | +| **Flatten Mode** | ブラシより下にあるハイト マップ セクションの上げ下げを設定します。[INCLUDE:#flattenmode] | +| **Use Slope Flatten** | チェックが入っていると、水平の平面に向かって平坦化せずにランドスケープの既存スロープに沿って平坦化します。 | +| **Pick Value Per Apply** | チェックが入っていると、最初にクリックした点のみの使用ではなく、常に新しい値を選んで平坦化します。 | +|[REGION:tablesection]高度なプロパティ[/REGION]|| +| **Show Preview Grid** | Flatten Target が有効の場合、平坦化ターゲットの高さに対してプレビュー グリッドを表示するオプションです。| + + + + diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Flatten/Flatten.KOR.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Flatten/Flatten.KOR.udn new file mode 100644 index 000000000000..61e8fc195d65 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Flatten/Flatten.KOR.udn @@ -0,0 +1,90 @@ +INTSourceChangelist:0 +Availability: Public +Crumbs: %ROOT% +Title: Flatten +Description: This is an overview of the Flatten painting tool. +Type: Reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:3 +Tags:Landscape +Topic-image:Flatten_topic.png + +[TOC(start:2 end:2)] + +The **Flatten** tool pushes or pulls all other parts of the heightmap to the level that is currently under the mouse when activated. This can raise or lower the surrounding +heightmap values to be the same value. + +## Using the Flatten Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 3amWaEH13V8 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 47 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +In this example, the Flatten tool is being used in the middle of the hillside to flatten out areas at the point where the mouse click was initiated. As long as the mouse is held down, the height value +that was detected is used along any surface to raise or lower (depending on your tool settings) to that height. + + +Use the following controls to sculpt your Landscape heightmap: + +| **Controls** | **Operation** | +| --- | --- | +| **Left Mouse Button** | Flattens or levels by both raising and lowering or individually raising and lowering the heightmap. | + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before Flattening](FlattenBefore.png)(w:750) + [/PARAM] + [PARAM:after] + ![After Flattening](FlattenAfter.png)(w:750) + [/PARAM] +[/OBJECT] + +The brush strength determines the amount of Flattening that can happen when using the Flatten tool. + +## Tool Settings + +[REGION:imagetable] +| ![Flatten Tool](Landscape_FlattenTool.png) | ![](FlattenToolProperties.png)(h:185) | +| --- | --- | +||| +[/REGION] + + +| **Property** | **Description** | +| ------------ | --------------- | +| **Flatten Target** | Sets the target height toward which to flatten. | +| **Tool Strength** | Controls how much smoothing occurs with each brush stroke has. | +| **Flatten Mode** | Determines whether the tool will raise or lower the heightmap section under the brush. [INCLUDE:#flattenmode] | +| **Use Slope Flatten** | If checked, flattens along the Landscape's existing slope instead of flattening toward a horizontal plane. | +| **Pick Value Per Apply** | If checked, constantly selects new values to flatten toward, instead of only using the first clicked point. | +| [REGION:tablesection] Advanced [/REGION] || +| **Show Preview Grid** | When Flatten Target is enabled, you can enable this option to show a preview grid for the flatten target height. | + + + + diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/HydroErosion/HydroErosion.CHN.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/HydroErosion/HydroErosion.CHN.udn new file mode 100644 index 000000000000..a4fbef625b44 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/HydroErosion/HydroErosion.CHN.udn @@ -0,0 +1,88 @@ +INTSourceChangelist:0 +Availability: Public +Crumbs: %ROOT% +Title: Hydro-Erosion +Description: This is an overview of the Hydro-Erosion painting tool. +Type: Reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:6 +Tags:Landscape +Topic-image:HydroErosion_topic.png + +[TOC(start:2 end:2)] + +The **Hydro Erosion** tool uses a hydraulic erosion simulation (erosion from water) to adjust the height of the Landscape heightmap. A noise filter is used to determine where the initial rain is +distributed for the simulation. Then the simulation is calculated to determine water flow from the initial rain as well as dissolving, water transfer, and evaporation. The result of the calculation +provides the actual value used to lower the heightmap. + +## Using the Hydro Erosion Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + -aPvHFmju8Y + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 49 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +In this example, the Hydro Erosion tool has been used to paint rain erosion onto the surface of the hillside. This makes it appear that parts of the Landscape have eroded away over time as rain +has fallen. The tool settings can enable the amount of rain and areas that it affects to help define the look. + +Use the following controls to Sculpt with Hydro Erosion for your Landscape heightmap: + +| **Controls** | **Operation** | +| --- | --- | +| **Left Mouse Button** | A noise filter is used to erode parts of the heightmap. | + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before](Hydro1.png)(w:750) + [/PARAM] + [PARAM:after] + ![After](Hydro2.png)(w:750) + [/PARAM] +[/OBJECT] + +In this example, as Hydro Erosion is used to paint onto the Landscape the heightmap runs a simulation that treats the heightmap as if rain has eroded away its surface over time. This can +create interesting looks and crevices to the Landscape. + + +## Tool Settings + +[REGION:imagetable] +| ![Hydro Erosion Tool](Landscape_HydroErosion.png)(h:75) | ![](HydroErosionToolProperties.png)(h:200) | +| --- | --- | +||| +[/REGION] + +| **Property** | **Description** | +| ------------ | --------------- | +| **Tool Strength** | Controls how much effect each brush stroke has. | +| **Rain Amount** | The amount of rain to apply to the surface. Larger values will result in more erosion. | +| **Sediment Cap.** | The amount of sediment that the water can carry. Larger values will result in more erosion. | +| **Iterations** | The number of iterations performed. Larger values result in more levels of erosion. | +| **Initial Rain Distribution** | Whether rain is applied randomly or to the entire area. [INCLUDE:#raindist] | +| **Rain Dist Scale** | The size of the noise filter for applying initial rain to the surface. The noise filter is related to position and scale, which means if you do not change **Rain Dist. Scale**, the same filter is applied to the same position many times. | +| **Detail Smooth** | If checked, performs a detail-preserving smoothing to the erosion effect using the specified detail-smoothing value. Larger detail-smoothing values remove more details, while smaller values preserve more details. | + + \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/HydroErosion/HydroErosion.INT.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/HydroErosion/HydroErosion.INT.udn new file mode 100644 index 000000000000..11bbb2778c2d --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/HydroErosion/HydroErosion.INT.udn @@ -0,0 +1,87 @@ +Availability: Public +Crumbs: %ROOT% +Title: Hydro-Erosion +Description: This is an overview of the Hydro-Erosion painting tool. +Type: Reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:6 +Tags:Landscape +Topic-image:HydroErosion_topic.png + +[TOC(start:2 end:2)] + +The **Hydro Erosion** tool uses a hydraulic erosion simulation (erosion from water) to adjust the height of the Landscape heightmap. A noise filter is used to determine where the initial rain is +distributed for the simulation. Then the simulation is calculated to determine water flow from the initial rain as well as dissolving, water transfer, and evaporation. The result of the calculation +provides the actual value used to lower the heightmap. + +## Using the Hydro Erosion Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + -aPvHFmju8Y + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 49 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +In this example, the Hydro Erosion tool has been used to paint rain erosion onto the surface of the hillside. This makes it appear that parts of the Landscape have eroded away over time as rain +has fallen. The tool settings can enable the amount of rain and areas that it affects to help define the look. + +Use the following controls to Sculpt with Hydro Erosion for your Landscape heightmap: + +| **Controls** | **Operation** | +| --- | --- | +| **Left Mouse Button** | A noise filter is used to erode parts of the heightmap. | + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before](Hydro1.png)(w:750) + [/PARAM] + [PARAM:after] + ![After](Hydro2.png)(w:750) + [/PARAM] +[/OBJECT] + +In this example, as Hydro Erosion is used to paint onto the Landscape the heightmap runs a simulation that treats the heightmap as if rain has eroded away its surface over time. This can +create interesting looks and crevices to the Landscape. + + +## Tool Settings + +[REGION:imagetable] +| ![Hydro Erosion Tool](Landscape_HydroErosion.png)(h:75) | ![](HydroErosionToolProperties.png)(h:200) | +| --- | --- | +||| +[/REGION] + +| **Property** | **Description** | +| ------------ | --------------- | +| **Tool Strength** | Controls how much effect each brush stroke has. | +| **Rain Amount** | The amount of rain to apply to the surface. Larger values will result in more erosion. | +| **Sediment Cap.** | The amount of sediment that the water can carry. Larger values will result in more erosion. | +| **Iterations** | The number of iterations performed. Larger values result in more levels of erosion. | +| **Initial Rain Distribution** | Whether rain is applied randomly or to the entire area. [INCLUDE:#raindist] | +| **Rain Dist Scale** | The size of the noise filter for applying initial rain to the surface. The noise filter is related to position and scale, which means if you do not change **Rain Dist. Scale**, the same filter is applied to the same position many times. | +| **Detail Smooth** | If checked, performs a detail-preserving smoothing to the erosion effect using the specified detail-smoothing value. Larger detail-smoothing values remove more details, while smaller values preserve more details. | + + \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/HydroErosion/HydroErosion.JPN.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/HydroErosion/HydroErosion.JPN.udn new file mode 100644 index 000000000000..176bad901460 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/HydroErosion/HydroErosion.JPN.udn @@ -0,0 +1,88 @@ +INTSourceChangelist:3482403 +Availability:Public +Crumbs: %ROOT% +Title:Hydro-Erosion +Description:Hydro-Erosion ペイント ツールの概要です。 +Type:Reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:6 +Tags:Landscape +Topic-image:HydroErosion_topic.png + +[TOC(start:2 end:2)] + +**Hydro Erosion** ツールは水による浸食のシミュレーションを行うことで、ランドスケープ ハイトマップの高さを調節します。ノイズ フィルターは、 +降り始めの雨分布のシミュレーションに使用します。その後、降り始めの雨、雨の消滅、水の移動から蒸発までの水のフローを決定するためにシミュレーションを計算します。その計算結果が、 +ハイト マップを下げる実際の値となります。 + +## Hydro Erosion ツールの使用方法 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + -aPvHFmju8Y + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 49 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +この例では、Hydro Erosion ツールを使って丘の斜面のサーフェス上に雨の侵食をペイントしています。雨が降り続くと、 +ランドスケープが侵食されていくように見せます。ツール設定の雨量と侵食面積を変更して、侵食の外見を調節します。 + +以下の制御を使用して、ランドスケープ ハイトマップに水による浸食の地形を生成します。 + +| **操作** | **処理内容** | +| --- | --- | +| **マウスの左ボタン** | ノイズ フィルタを使って、ハイトマップを部分的に侵食します。 | + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before](Hydro1.png)(w:750) + [/PARAM] + [PARAM:after] + ![After](Hydro2.png)(w:750) + [/PARAM] +[/OBJECT] + +この例では、Hydro Erosion ツールをランドスケープ上に適用すると、時間と共にまるで雨がサーフェスを侵食しているかのようにハイトマップを処理するシミュレーションが実行されます。ランドスケープに裂け目が生成され、 +凹凸のある形状になります。 + + +## ツール設定 + +[REGION:imagetable] +| ![Hydro Erosion Tool](Landscape_HydroErosion.png)(h:75) | ![](HydroErosionToolProperties.png)(h:200) | +| --- | --- | +||| +[/REGION] + +| **プロパティ** | **説明** | +| ------------ | --------------- | +| **Tool Strength** | 1 回のブラシ ストロークの強度を調節します。 | +| **Rain Amount** | サーフェスへ適用するための雨量です。値が高ければ高いほど、侵食は大きくなります。 | +| **Sediment Cap.** | 水に流される堆積物の量です。値が高ければ高いほど、侵食は大きくなります。 | +| **Iterations** | 実行されるイタレーション数です。値が高くなるほど、浸食レベルがあがります。 | +| **Initial Rain Distribution** | 雨をランダムに降らせるか、領域全体に降らせるかを設定します。 [INCLUDE:#raindist] | +| **Rain Dist Scale** | 降り始めの雨をサーフェスへ適用するノイズ フィルターの大きさです。ノイズ フィルターは位置とスケールに結びつくので、**Rain Dist. Scale** を変えない限り、同じフィルターが同じ位置に繰り返し適用されます。 | +| **Detail Smooth** | このオプションがチェックされると、指定した詳細スムージング値を使って、詳細度を維持したままのスムージングを侵食エフェクトに対して実行します。詳細スムージング値が大きくなると詳細度が下がり、詳細スムージング値が小さくなると詳細度が保たれます。 | + + \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/HydroErosion/HydroErosion.KOR.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/HydroErosion/HydroErosion.KOR.udn new file mode 100644 index 000000000000..a4fbef625b44 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/HydroErosion/HydroErosion.KOR.udn @@ -0,0 +1,88 @@ +INTSourceChangelist:0 +Availability: Public +Crumbs: %ROOT% +Title: Hydro-Erosion +Description: This is an overview of the Hydro-Erosion painting tool. +Type: Reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:6 +Tags:Landscape +Topic-image:HydroErosion_topic.png + +[TOC(start:2 end:2)] + +The **Hydro Erosion** tool uses a hydraulic erosion simulation (erosion from water) to adjust the height of the Landscape heightmap. A noise filter is used to determine where the initial rain is +distributed for the simulation. Then the simulation is calculated to determine water flow from the initial rain as well as dissolving, water transfer, and evaporation. The result of the calculation +provides the actual value used to lower the heightmap. + +## Using the Hydro Erosion Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + -aPvHFmju8Y + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 49 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +In this example, the Hydro Erosion tool has been used to paint rain erosion onto the surface of the hillside. This makes it appear that parts of the Landscape have eroded away over time as rain +has fallen. The tool settings can enable the amount of rain and areas that it affects to help define the look. + +Use the following controls to Sculpt with Hydro Erosion for your Landscape heightmap: + +| **Controls** | **Operation** | +| --- | --- | +| **Left Mouse Button** | A noise filter is used to erode parts of the heightmap. | + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before](Hydro1.png)(w:750) + [/PARAM] + [PARAM:after] + ![After](Hydro2.png)(w:750) + [/PARAM] +[/OBJECT] + +In this example, as Hydro Erosion is used to paint onto the Landscape the heightmap runs a simulation that treats the heightmap as if rain has eroded away its surface over time. This can +create interesting looks and crevices to the Landscape. + + +## Tool Settings + +[REGION:imagetable] +| ![Hydro Erosion Tool](Landscape_HydroErosion.png)(h:75) | ![](HydroErosionToolProperties.png)(h:200) | +| --- | --- | +||| +[/REGION] + +| **Property** | **Description** | +| ------------ | --------------- | +| **Tool Strength** | Controls how much effect each brush stroke has. | +| **Rain Amount** | The amount of rain to apply to the surface. Larger values will result in more erosion. | +| **Sediment Cap.** | The amount of sediment that the water can carry. Larger values will result in more erosion. | +| **Iterations** | The number of iterations performed. Larger values result in more levels of erosion. | +| **Initial Rain Distribution** | Whether rain is applied randomly or to the entire area. [INCLUDE:#raindist] | +| **Rain Dist Scale** | The size of the noise filter for applying initial rain to the surface. The noise filter is related to position and scale, which means if you do not change **Rain Dist. Scale**, the same filter is applied to the same position many times. | +| **Detail Smooth** | If checked, performs a detail-preserving smoothing to the erosion effect using the specified detail-smoothing value. Larger detail-smoothing values remove more details, while smaller values preserve more details. | + + \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Mirror/Mirror.CHN.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Mirror/Mirror.CHN.udn new file mode 100644 index 000000000000..e6f5242e2778 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Mirror/Mirror.CHN.udn @@ -0,0 +1,72 @@ +INTSourceChangelist:0 +Availability: Public +Crumbs: %ROOT% +Title: Mirror +Description: This is an overview of the Mirror tool. +Type:reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:12 +Tags:Landscape +tags:region +Topic-image:Mirror_topic.png + +[TOC(start:2 end:2)] + +The **Mirror** tool enables you to mirror or rotate the existing Landscape heightmap geometry along the X or Y axis. + +## Using the Mirror Tool + +1. In the Landscape tool, in **Sculpt** mode, select the **Mirror** tool. + + ![Mirror Tool](2.png)(w:417) + +1. Use the **Operation** drop-down selection to choose the axis and mirroring method you would like to use for your selected landscape. The directional arrow indicates which side of the landscape geometry will be mirrored on. + + ![](Mirror_Settings.png)(w:417) + +1. If necessary, adjust the **Mirror Point** values for the mirror plane or Left-click and drag the directional arrow on mirror plane into the position you want to mirror. + + [REGION:note] + Only the currently selected **Operation** axis will be used for the **Mirror Point**. For example, if the Operation method is "-X to +X" the X axis is the only active Mirror Point that will be affected. + [/REGION] + ![](Mirror_1.png)(w:500) + +1. Once you are satisfied with your edits, you can hit the **Apply** button to see the results. + + ![](Mirror_3.png)(w:500) + + You now have a landscape with mirrored geometry. + +### Mirror Smoothing Width + +If the edge seams from mirroring your landscape look unnatural or too sharp in contrast after you apply your changes you can use **CTRL + Z** to undo your last action. Then you should adjust the **Smoothing Width** so that these +edge vertices that are merged are softened. + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Smoothing Width Before](Mirror_SmoothingWidth_2.png)(w:500) + [/PARAM] + [PARAM:after] + ![Smoothing Width After](Mirror_SmoothingWidth_1.png)(w:500) + [/PARAM] +[/OBJECT] + +In this example, the left image has no smoothing applied after the Landscape is mirrored, whereas the right is using a value of 10 to smooth the mirrored edges and reduce the harshness of the seam. + +## Tool Settings + +[REGION:imagetable] +| ![Mirror Tool](Landscape_Mirror.png) | ![](RegionMirrorToolProperties.png)(h:125) | +| --- | --- | +||| +[/REGION] + + +| **Property** | **Description** | +| ------------ | --------------- | +| **Mirror Point** | This sets the location of the mirror plane. This will default to the center of the selected Landscape and in most cases will not normally need to be changed. | +| **Operation** | The type of mirroring operation to perform. For example, -X to +X will copy and flip the -X half of the Landscape onto the +X half. | +| **Recenter** | This button places the mirror plane back at the center of the selected Landscape. | +| **Smoothing Width** | This will set the number of vertices on either side of the mirror plane to smooth over reducing sharp contrasting angles for mirrored sides. | + diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Mirror/Mirror.INT.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Mirror/Mirror.INT.udn new file mode 100644 index 000000000000..027fc3d86156 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Mirror/Mirror.INT.udn @@ -0,0 +1,71 @@ +Availability: Public +Crumbs: %ROOT% +Title: Mirror +Description: This is an overview of the Mirror tool. +Type:reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:12 +Tags:Landscape +tags:region +Topic-image:Mirror_topic.png + +[TOC(start:2 end:2)] + +The **Mirror** tool enables you to mirror or rotate the existing Landscape heightmap geometry along the X or Y axis. + +## Using the Mirror Tool + +1. In the Landscape tool, in **Sculpt** mode, select the **Mirror** tool. + + ![Mirror Tool](2.png)(w:417) + +1. Use the **Operation** drop-down selection to choose the axis and mirroring method you would like to use for your selected landscape. The directional arrow indicates which side of the landscape geometry will be mirrored on. + + ![](Mirror_Settings.png)(w:417) + +1. If necessary, adjust the **Mirror Point** values for the mirror plane or Left-click and drag the directional arrow on mirror plane into the position you want to mirror. + + [REGION:note] + Only the currently selected **Operation** axis will be used for the **Mirror Point**. For example, if the Operation method is "-X to +X" the X axis is the only active Mirror Point that will be affected. + [/REGION] + ![](Mirror_1.png)(w:500) + +1. Once you are satisfied with your edits, you can hit the **Apply** button to see the results. + + ![](Mirror_3.png)(w:500) + + You now have a landscape with mirrored geometry. + +### Mirror Smoothing Width + +If the edge seams from mirroring your landscape look unnatural or too sharp in contrast after you apply your changes you can use **CTRL + Z** to undo your last action. Then you should adjust the **Smoothing Width** so that these +edge vertices that are merged are softened. + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Smoothing Width Before](Mirror_SmoothingWidth_2.png)(w:500) + [/PARAM] + [PARAM:after] + ![Smoothing Width After](Mirror_SmoothingWidth_1.png)(w:500) + [/PARAM] +[/OBJECT] + +In this example, the left image has no smoothing applied after the Landscape is mirrored, whereas the right is using a value of 10 to smooth the mirrored edges and reduce the harshness of the seam. + +## Tool Settings + +[REGION:imagetable] +| ![Mirror Tool](Landscape_Mirror.png) | ![](RegionMirrorToolProperties.png)(h:125) | +| --- | --- | +||| +[/REGION] + + +| **Property** | **Description** | +| ------------ | --------------- | +| **Mirror Point** | This sets the location of the mirror plane. This will default to the center of the selected Landscape and in most cases will not normally need to be changed. | +| **Operation** | The type of mirroring operation to perform. For example, -X to +X will copy and flip the -X half of the Landscape onto the +X half. | +| **Recenter** | This button places the mirror plane back at the center of the selected Landscape. | +| **Smoothing Width** | This will set the number of vertices on either side of the mirror plane to smooth over reducing sharp contrasting angles for mirrored sides. | + diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Mirror/Mirror.JPN.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Mirror/Mirror.JPN.udn new file mode 100644 index 000000000000..0defa5c904b0 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Mirror/Mirror.JPN.udn @@ -0,0 +1,72 @@ +INTSourceChangelist:3482403 +Availability:Public +Crumbs: %ROOT% +Title:Mirror +Description:Mirror ツールの概要です。 +Type:reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +order:12 +Tags:Landscape +tags:region +Topic-image:Mirror_topic.png + +[TOC(start:2 end:2)] + +**Mirror** ツールは、既存のランドスケープ ハイトマップ ジオメトリを X 軸 / Y 軸に沿ってミラーリングまたは回転させます。 + +## Mirror ツールの使用方法 + +1. ランドスケープ ツールの **Sculpt** モードで **Mirror** ツールを選びます。 + + ![Mirror Tool](2.png)(w:417) + +1. **[Operation]** ドロップダウンから、ランドスケープに適用したい軸およびミラーリング メソッドを選択します。矢印は、ランドスケープのどちら側をミラーするのかを表しています。 + + ![](Mirror_Settings.png)(w:417) + +1. 必要に応じて、ミラー平面に対して **Mirror Point** 値を調節する、もしくはミラー平面上の矢印を左クリックしてミラーリングする位置にドラッグします。 + + [REGION:note] + 選択した **[Opetarion]** 軸は **Mirror Point** に使用されます。例えば [Operation] メソッドが "-X to +X" の場合、影響されるアクティブなミラーポイントは X 軸のみになります。 + [/REGION] + ![](Mirror_1.png)(w:500) + +1. これで良ければ **[Apply]** ボタンを押して結果を確認します。 + + ![](Mirror_3.png)(w:500) + + ジオメトリをミラーリングしたランドスケープが完成しました。 + +### Smoothing Width + +変更を反映させると、ランドスケープのミラーリングでエッジの継ぎ目が不自然または鋭すぎる場合は、**CTRL + Z** を使って最後の操作をアンドゥすることができます。**Smoothing Width** を調節すると、 +マージされるこれらのエッジ頂点がソフトになります。 + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Smoothing Width Before](Mirror_SmoothingWidth_2.png)(w:500) + [/PARAM] + [PARAM:after] + ![Smoothing Width After](Mirror_SmoothingWidth_1.png)(w:500) + [/PARAM] +[/OBJECT] + +この例では、左の画像はランドスケープのミラーリング後にスムージングを適用していません。一方、右の画像はミラーリングしたエッジを値 10 で滑らかにして、継ぎ目の粗さを減らしています。 + +## ツール設定 + +[REGION:imagetable] +| ![Mirror Tool](Landscape_Mirror.png) | ![](RegionMirrorToolProperties.png)(h:125) | +| --- | --- | +||| +[/REGION] + + +| **プロパティ** | **説明** | +| ------------ | --------------- | +| **Mirror Point** | ミラー平面の位置を設定します。選択したランドスケープの中央がデフォルトで、通常は変更する必要はありません。 | +| **Operation** | 実行するミラーリング操作の種類です。例えば、[-X to +X] はランドスケープの -X 側をコピーして +X 側にフリップします。 | +| **Recenter** |ミラー平面を選択したランドスケープの中央に戻すボタンです。。 | +| **Smoothing Width** | ミラー平面のいずれかの側の頂点数を設定して、ミラーリングされた側の鋭い対比角を滑らかにします。 | + diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Mirror/Mirror.KOR.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Mirror/Mirror.KOR.udn new file mode 100644 index 000000000000..e6f5242e2778 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Mirror/Mirror.KOR.udn @@ -0,0 +1,72 @@ +INTSourceChangelist:0 +Availability: Public +Crumbs: %ROOT% +Title: Mirror +Description: This is an overview of the Mirror tool. +Type:reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:12 +Tags:Landscape +tags:region +Topic-image:Mirror_topic.png + +[TOC(start:2 end:2)] + +The **Mirror** tool enables you to mirror or rotate the existing Landscape heightmap geometry along the X or Y axis. + +## Using the Mirror Tool + +1. In the Landscape tool, in **Sculpt** mode, select the **Mirror** tool. + + ![Mirror Tool](2.png)(w:417) + +1. Use the **Operation** drop-down selection to choose the axis and mirroring method you would like to use for your selected landscape. The directional arrow indicates which side of the landscape geometry will be mirrored on. + + ![](Mirror_Settings.png)(w:417) + +1. If necessary, adjust the **Mirror Point** values for the mirror plane or Left-click and drag the directional arrow on mirror plane into the position you want to mirror. + + [REGION:note] + Only the currently selected **Operation** axis will be used for the **Mirror Point**. For example, if the Operation method is "-X to +X" the X axis is the only active Mirror Point that will be affected. + [/REGION] + ![](Mirror_1.png)(w:500) + +1. Once you are satisfied with your edits, you can hit the **Apply** button to see the results. + + ![](Mirror_3.png)(w:500) + + You now have a landscape with mirrored geometry. + +### Mirror Smoothing Width + +If the edge seams from mirroring your landscape look unnatural or too sharp in contrast after you apply your changes you can use **CTRL + Z** to undo your last action. Then you should adjust the **Smoothing Width** so that these +edge vertices that are merged are softened. + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Smoothing Width Before](Mirror_SmoothingWidth_2.png)(w:500) + [/PARAM] + [PARAM:after] + ![Smoothing Width After](Mirror_SmoothingWidth_1.png)(w:500) + [/PARAM] +[/OBJECT] + +In this example, the left image has no smoothing applied after the Landscape is mirrored, whereas the right is using a value of 10 to smooth the mirrored edges and reduce the harshness of the seam. + +## Tool Settings + +[REGION:imagetable] +| ![Mirror Tool](Landscape_Mirror.png) | ![](RegionMirrorToolProperties.png)(h:125) | +| --- | --- | +||| +[/REGION] + + +| **Property** | **Description** | +| ------------ | --------------- | +| **Mirror Point** | This sets the location of the mirror plane. This will default to the center of the selected Landscape and in most cases will not normally need to be changed. | +| **Operation** | The type of mirroring operation to perform. For example, -X to +X will copy and flip the -X half of the Landscape onto the +X half. | +| **Recenter** | This button places the mirror plane back at the center of the selected Landscape. | +| **Smoothing Width** | This will set the number of vertices on either side of the mirror plane to smooth over reducing sharp contrasting angles for mirrored sides. | + diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Noise/Noise.CHN.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Noise/Noise.CHN.udn new file mode 100644 index 000000000000..9b4e2ef05c76 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Noise/Noise.CHN.udn @@ -0,0 +1,88 @@ +INTSourceChangelist:0 +Availability: Public +Crumbs: %ROOT% +Title: Noise +Description: This is an overview of the Noise painting tool. +Type: Reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:7 +Tags:Landscape +Topic-image:Noise_topic.png + +[TOC(start:2 end:2)] + +The **Noise** tool applies a noise filter to produce variations in the surface of the Landscape heightmap. + + +## Using the Noise Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 0S5y-2FNRpA + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 49 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +In this example, the Noise tool is used to paint on the Landscape, similarly to how Sculpt would be used, and in doing so variations are painted around this area that raise and lower the heightmap based +on the tool settings. This enable you to paint grande or subtle variations into your Landscape. + +Use the following controls to Sculpt with Noise for your Landscape heightmap: + +| **Controls** | **Operation** | +| --- | --- | +| **Left Mouse Button** | Heightens or increases the heightmap or selected layer's weight. | + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before](Noise1.png)(w:750) + [/PARAM] + [PARAM:after] + ![After](Noise2.png)(w:750) + [/PARAM] +[/OBJECT] + +In this example, Noise has been painted onto the smooth Landscape surface giving it variations in different heights based on the strength and property values used. + +## Tool Settings + +[REGION:imagetable] +| ![Noise Tool](Landscape_Noise.png)(h:75) | ![](NoiseToolProperties.png)(h:185) | +| --- | --- | +||| +[/REGION] + + +| **Property** | **Description** | +| ------------ | --------------- | +| **Tool Strength** | Controls how much effect each brush stroke has. | +| **Use Target Value** | If checked, blends the values of the noise being applied toward a target value. | +| **Noise Mode** | Determines whether to apply all noise effects, only the noise effects that result in raising the heightmap, or only the noise effects that result in lowering the heightmap. [INCLUDE:#noise] | +| **Noise Scale** | The size of the perlin noise filter used. The noise filter is related to position and scale, which means if you do not change **Noise Scale**, the same filter is applied to the same position many times. | + + +The brush strength determines the amount of raising or lowering that can happen when using the Noise tool. + + \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Noise/Noise.INT.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Noise/Noise.INT.udn new file mode 100644 index 000000000000..b68141170739 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Noise/Noise.INT.udn @@ -0,0 +1,87 @@ +Availability: Public +Crumbs: %ROOT% +Title: Noise +Description: This is an overview of the Noise painting tool. +Type: Reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:7 +Tags:Landscape +Topic-image:Noise_topic.png + +[TOC(start:2 end:2)] + +The **Noise** tool applies a noise filter to produce variations in the surface of the Landscape heightmap. + + +## Using the Noise Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 0S5y-2FNRpA + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 49 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +In this example, the Noise tool is used to paint on the Landscape, similarly to how Sculpt would be used, and in doing so variations are painted around this area that raise and lower the heightmap based +on the tool settings. This enable you to paint grande or subtle variations into your Landscape. + +Use the following controls to Sculpt with Noise for your Landscape heightmap: + +| **Controls** | **Operation** | +| --- | --- | +| **Left Mouse Button** | Heightens or increases the heightmap or selected layer's weight. | + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before](Noise1.png)(w:750) + [/PARAM] + [PARAM:after] + ![After](Noise2.png)(w:750) + [/PARAM] +[/OBJECT] + +In this example, Noise has been painted onto the smooth Landscape surface giving it variations in different heights based on the strength and property values used. + +## Tool Settings + +[REGION:imagetable] +| ![Noise Tool](Landscape_Noise.png)(h:75) | ![](NoiseToolProperties.png)(h:185) | +| --- | --- | +||| +[/REGION] + + +| **Property** | **Description** | +| ------------ | --------------- | +| **Tool Strength** | Controls how much effect each brush stroke has. | +| **Use Target Value** | If checked, blends the values of the noise being applied toward a target value. | +| **Noise Mode** | Determines whether to apply all noise effects, only the noise effects that result in raising the heightmap, or only the noise effects that result in lowering the heightmap. [INCLUDE:#noise] | +| **Noise Scale** | The size of the perlin noise filter used. The noise filter is related to position and scale, which means if you do not change **Noise Scale**, the same filter is applied to the same position many times. | + + +The brush strength determines the amount of raising or lowering that can happen when using the Noise tool. + + \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Noise/Noise.JPN.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Noise/Noise.JPN.udn new file mode 100644 index 000000000000..5c6bdc436c29 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Noise/Noise.JPN.udn @@ -0,0 +1,88 @@ +INTSourceChangelist:3482403 +Availability:Public +Crumbs: %ROOT% +Title:Noise +Description:Noise ペイント ツールの概要です。 +Type:Reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:7 +Tags:Landscape +Topic-image:Noise_topic.png + +[TOC(start:2 end:2)] + +**Noise** ツールは、ノイズ フィルターを適用して、ランドスケープ ハイトマップのサーフェスに多様性を生成します。 + + +## Noise ツールの使用方法 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 0S5y-2FNRpA + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 49 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +この例では、Noise ツールを Sculpt と同じ要領でランドスケープ上のペイントに使用しています。 +そうすると、ハイトマップこの領域周辺に、ツール設定に基づいたハイトマップに高低差を付けて多様な地形がペイントされます。ランドスケープに大きな、あるいは微妙な変化を付けることができます。 + +ランドスケープ ハイトマップでのノイズによるスカルプトでは、以下の調節ができます。 + +| **操作** | **処理内容** | +| --- | --- | +| **マウスの左ボタン** | ハイトマップを上げる、または選択したレイヤーのウェイトを増やします。 + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before](Noise1.png)(w:750) + [/PARAM] + [PARAM:after] + ![After](Noise2.png)(w:750) + [/PARAM] +[/OBJECT] + +この例では、ノイズを滑らかなランドスケープのサーフェスにペイントし、強度とプロパティ値を調節して高低差を出しています。 + +## ツール設定 + +[REGION:imagetable] +| ![Noise Tool](Landscape_Noise.png)(h:75) | ![](NoiseToolProperties.png)(h:185) | +| --- | --- | +||| +[/REGION] + + +| **プロパティ** | **説明** | +| ------------ | --------------- | +| **Tool Strength** | 1 回のブラシ ストロークの強度を調節します。 | +| **Use Target Value** | チェックが入っていると、適用されているノイズの値をターゲット値に適用します。 | +| **Noise Mode** | 適用するのは、全てのノイズ エフェクトか、ハイトマップを上げるノイズ エフェクトのみか、それともハイトマップを下げるノイズ エフェクトのみかを判断します。 [INCLUDE:#noise] | +| **Noise Scale** | 使用するパーリン ノイズ フィルターの大きさです。ノイズ フィルターは、位置とスケールに関係します。したがって、**Noise Scale** に変更がない限り、同じフィルターが同じ位置に何度も適用されます。 | + + +Noise ツールを使う場合、ブラシの強度で高さ / 低さが決まります。 + + \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Noise/Noise.KOR.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Noise/Noise.KOR.udn new file mode 100644 index 000000000000..9b4e2ef05c76 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Noise/Noise.KOR.udn @@ -0,0 +1,88 @@ +INTSourceChangelist:0 +Availability: Public +Crumbs: %ROOT% +Title: Noise +Description: This is an overview of the Noise painting tool. +Type: Reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:7 +Tags:Landscape +Topic-image:Noise_topic.png + +[TOC(start:2 end:2)] + +The **Noise** tool applies a noise filter to produce variations in the surface of the Landscape heightmap. + + +## Using the Noise Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 0S5y-2FNRpA + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 49 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +In this example, the Noise tool is used to paint on the Landscape, similarly to how Sculpt would be used, and in doing so variations are painted around this area that raise and lower the heightmap based +on the tool settings. This enable you to paint grande or subtle variations into your Landscape. + +Use the following controls to Sculpt with Noise for your Landscape heightmap: + +| **Controls** | **Operation** | +| --- | --- | +| **Left Mouse Button** | Heightens or increases the heightmap or selected layer's weight. | + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before](Noise1.png)(w:750) + [/PARAM] + [PARAM:after] + ![After](Noise2.png)(w:750) + [/PARAM] +[/OBJECT] + +In this example, Noise has been painted onto the smooth Landscape surface giving it variations in different heights based on the strength and property values used. + +## Tool Settings + +[REGION:imagetable] +| ![Noise Tool](Landscape_Noise.png)(h:75) | ![](NoiseToolProperties.png)(h:185) | +| --- | --- | +||| +[/REGION] + + +| **Property** | **Description** | +| ------------ | --------------- | +| **Tool Strength** | Controls how much effect each brush stroke has. | +| **Use Target Value** | If checked, blends the values of the noise being applied toward a target value. | +| **Noise Mode** | Determines whether to apply all noise effects, only the noise effects that result in raising the heightmap, or only the noise effects that result in lowering the heightmap. [INCLUDE:#noise] | +| **Noise Scale** | The size of the perlin noise filter used. The noise filter is related to position and scale, which means if you do not change **Noise Scale**, the same filter is applied to the same position many times. | + + +The brush strength determines the amount of raising or lowering that can happen when using the Noise tool. + + \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Ramp/Ramp.CHN.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Ramp/Ramp.CHN.udn new file mode 100644 index 000000000000..46b478810bc6 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Ramp/Ramp.CHN.udn @@ -0,0 +1,78 @@ +INTSourceChangelist:0 +Availability: Public +Crumbs: %ROOT% +Title: Ramp +Description: This is an overview of the Ramp painting tool. +Type: Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:4 +Tags:Landscape +Topic-image:Ramp_topic.png + +[TOC(start:2 end:2)] + +The **Ramp** tool enables you to select two locations on your Landscape and create a flat ramp between the two points, with a falloff you specify for the sides. + + +## Using the Ramp Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 1x0eN4Fib34 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 46 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + + +1. In the Landscape tool, in the **Sculpt** mode, select the **Ramp** tool. + + ![](RampSelection.png)(w:400) + +1. In the viewport on your Landscape, **Left-click** and drag or simply Left-click in two different places to mark the beginning and end points of the ramp. + + ![](1.png)(w:500) + + [REGION:tip] + If you change your mind about adding a ramp after starting to set the beginning and end points, you can click **Reset** to clear them. + [/REGION] + +1. Select either marker and adjust its position. In this case, it has been moved along the Z-axis above the Landscape surface. + + ![](2.png)(w:500) + +1. When you're satisfied with the position, click the **Add Ramp** button in the Tool Settings to create the ramp. + + ![](3.png)(w:400) + + Now, you'll have a ramp that has been sculpted into your heightmap. + + ![](4.png)(w:500) + + +## Tool Settings + +[REGION:imagetable] +| ![Ramp Tool](Landscape_Ramp.png)(h:75) | ![](RampToolProperties.png)(h:120) | +| --- | --- | +||| +[/REGION] + + +| **Property** | **Description** | +| ------------ | --------------- | +| **Ramp Width** | Sets the width of the ramp. | +| **Side Falloff** | Sets the edge falloff on the sides of the ramp where it merges inot the rest of the landscape. This falloff gives a softness to the edge flow on these sides. A setting of **0** means no falloff; a setting of **1** means all falloff and no flat surface for the ramp. | + diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Ramp/Ramp.INT.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Ramp/Ramp.INT.udn new file mode 100644 index 000000000000..b9d54e01cf63 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Ramp/Ramp.INT.udn @@ -0,0 +1,77 @@ +Availability: Public +Crumbs: %ROOT% +Title: Ramp +Description: This is an overview of the Ramp painting tool. +Type: Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:4 +Tags:Landscape +Topic-image:Ramp_topic.png + +[TOC(start:2 end:2)] + +The **Ramp** tool enables you to select two locations on your Landscape and create a flat ramp between the two points, with a falloff you specify for the sides. + + +## Using the Ramp Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 1x0eN4Fib34 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 46 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + + +1. In the Landscape tool, in the **Sculpt** mode, select the **Ramp** tool. + + ![](RampSelection.png)(w:400) + +1. In the viewport on your Landscape, **Left-click** and drag or simply Left-click in two different places to mark the beginning and end points of the ramp. + + ![](1.png)(w:500) + + [REGION:tip] + If you change your mind about adding a ramp after starting to set the beginning and end points, you can click **Reset** to clear them. + [/REGION] + +1. Select either marker and adjust its position. In this case, it has been moved along the Z-axis above the Landscape surface. + + ![](2.png)(w:500) + +1. When you're satisfied with the position, click the **Add Ramp** button in the Tool Settings to create the ramp. + + ![](3.png)(w:400) + + Now, you'll have a ramp that has been sculpted into your heightmap. + + ![](4.png)(w:500) + + +## Tool Settings + +[REGION:imagetable] +| ![Ramp Tool](Landscape_Ramp.png)(h:75) | ![](RampToolProperties.png)(h:120) | +| --- | --- | +||| +[/REGION] + + +| **Property** | **Description** | +| ------------ | --------------- | +| **Ramp Width** | Sets the width of the ramp. | +| **Side Falloff** | Sets the edge falloff on the sides of the ramp where it merges inot the rest of the landscape. This falloff gives a softness to the edge flow on these sides. A setting of **0** means no falloff; a setting of **1** means all falloff and no flat surface for the ramp. | + diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Ramp/Ramp.JPN.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Ramp/Ramp.JPN.udn new file mode 100644 index 000000000000..72dcb290cb65 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Ramp/Ramp.JPN.udn @@ -0,0 +1,78 @@ +INTSourceChangelist:3482403 +Availability:Public +Crumbs: %ROOT% +Title:Ramp +Description:Ramp ペイント ツールの概要です。 +Type:Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:4 +Tags:Landscape +Topic-image:Ramp_topic.png + +[TOC(start:2 end:2)] + +**Ramp** ツールにより、ランドスケープ上で 2 つの位置を選び、側面にフォールオフを指定して、それらの間に平面の傾斜を作成することができます。 + + +## Ramp ツールの使用方法 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 1x0eN4Fib34 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 46 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + + +1. Landscape ツールの **Sculpt** モードで、**Ramp** ツールを選択します。 + + ![](RampSelection.png)(w:400) + +1. ランドスケープのビューポートで、**左クリック** してドラッグ、または異なる 2 つの位置を左クリックして、傾斜の開始ポイントと終了ポイントに印をつけます。 + + ![](1.png)(w:500) + + [REGION:tip] + 開始および終了ポイントの設定途中で傾斜の追加を中止する場合は **[Reset (リセット)]** をクリックしてクリアします。 + [/REGION] + +1. いずれかの印を選択して、位置を調節します。このケースでは、ランドスケープ サーフェス上で Z 軸に平行に移動しています。 + + ![](2.png)(w:500) + +1. 位置が調節できたら、[Tool Settings (ツール設定)] の **[Add Ramp (傾斜を追加)]** ボタンを押します。 + + ![](3.png)(w:400) + + これで、ハイトマップに傾斜が生成されました。 + + ![](4.png)(w:500) + + +## ツール設定 + +[REGION:imagetable] +| ![Ramp Tool](Landscape_Ramp.png)(h:75) | ![](RampToolProperties.png)(h:120) | +| --- | --- | +||| +[/REGION] + + +| **プロパティ** | **説明** | +| ------------ | --------------- | +| **Ramp Width** | 傾斜の幅を設定します。 | +| **Side Falloff** | 傾斜の側面にフォールオフを設定し、そこがランドスケープの残りの部分にマージされます。フォールオフにより、傾斜側面のエッジ フローがソフトな印象になります。**0** を設定するとフォールオフなし、**1** を設定するとすべてフォールオフで平面の傾斜はなし、ということになります。 | + diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Ramp/Ramp.KOR.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Ramp/Ramp.KOR.udn new file mode 100644 index 000000000000..46b478810bc6 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Ramp/Ramp.KOR.udn @@ -0,0 +1,78 @@ +INTSourceChangelist:0 +Availability: Public +Crumbs: %ROOT% +Title: Ramp +Description: This is an overview of the Ramp painting tool. +Type: Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:4 +Tags:Landscape +Topic-image:Ramp_topic.png + +[TOC(start:2 end:2)] + +The **Ramp** tool enables you to select two locations on your Landscape and create a flat ramp between the two points, with a falloff you specify for the sides. + + +## Using the Ramp Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 1x0eN4Fib34 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 46 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + + +1. In the Landscape tool, in the **Sculpt** mode, select the **Ramp** tool. + + ![](RampSelection.png)(w:400) + +1. In the viewport on your Landscape, **Left-click** and drag or simply Left-click in two different places to mark the beginning and end points of the ramp. + + ![](1.png)(w:500) + + [REGION:tip] + If you change your mind about adding a ramp after starting to set the beginning and end points, you can click **Reset** to clear them. + [/REGION] + +1. Select either marker and adjust its position. In this case, it has been moved along the Z-axis above the Landscape surface. + + ![](2.png)(w:500) + +1. When you're satisfied with the position, click the **Add Ramp** button in the Tool Settings to create the ramp. + + ![](3.png)(w:400) + + Now, you'll have a ramp that has been sculpted into your heightmap. + + ![](4.png)(w:500) + + +## Tool Settings + +[REGION:imagetable] +| ![Ramp Tool](Landscape_Ramp.png)(h:75) | ![](RampToolProperties.png)(h:120) | +| --- | --- | +||| +[/REGION] + + +| **Property** | **Description** | +| ------------ | --------------- | +| **Ramp Width** | Sets the width of the ramp. | +| **Side Falloff** | Sets the edge falloff on the sides of the ramp where it merges inot the rest of the landscape. This falloff gives a softness to the edge flow on these sides. A setting of **0** means no falloff; a setting of **1** means all falloff and no flat surface for the ramp. | + diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/RegionSelection/RegionSelection.CHN.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/RegionSelection/RegionSelection.CHN.udn new file mode 100644 index 000000000000..686104d2a461 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/RegionSelection/RegionSelection.CHN.udn @@ -0,0 +1,76 @@ +INTSourceChangelist:0 +Availability: Public +Crumbs: %ROOT% +Title: Region Selection +Description: This is an overview of the Region Selection tool. +Type: reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:10 +Tags:Landscape +tags:region +Topic-image:RegionSelection_topic.png + +[TOC(start:2 end:2)] + +The **Region Selection** tool selects regions of the Landscape using the current brush settings and the tool strength to be used to fit a Landscape [gizmo](Engine\Landscape\Editing\Gizmos) to a +specific area or to act as a mask for copying data to, or pasting data from, a gizmo. + +## Using the Region Selection Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + hbWfSsZzmiY + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 44 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +In this example, the Region Selection tool has been used to paint an area of the Landscape using the default positive method, then switching to the negative mask method that enables you to paint areas that +don't want to include, and finally showing the Use Region As Mask section that captures the entirety of a Landscape component that is painted rather than just areas within it. + +Use the following controls to paint areas that can be used for selection by doing the following: + +| **Controls** | **Operation** | +| --- | --- | +| **Left Mouse Button** | Adds to the selected region. | +| **Shift + Left Mouse Button** | Removes from the selected region. | + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Without Selection](Selection1.png)(w:750) + [/PARAM] + [PARAM:after] + ![With Selection](Selection2.png)(w:750) + [/PARAM] +[/OBJECT] + +In this example, an area has been painted for selection that can then be used for masking layers or with the Copy/Paste tool. + +## Tool Settings + +[REGION:imagetable] +| ![](Landscape_RegionSelect.png)(h:75) | ![](RegionSelectionToolProperties.png)(h:135) | +| --- | --- | +||| +[/REGION] + +| **Property** | **Description** | +| ------------ | --------------- | +| **Clear Region Selection** | Clears the current selected region(s). | +| **Tool Strength** | Controls how much effect each brush stroke has. | +| **Use Region as Mask** | When checked, the region selection acts as a mask with the active area being comprised of the selected region. | +| ![](regionselection.png)(w:640) || +| **Negative Mask** | When checked, and when **Use Region as Mask** is also checked, the region selection acts as a mask, but the active area is comprised of the unselected region. | +| ![region_mask_negative.jpg](regionselectionnegative.png)(w:640) || + diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/RegionSelection/RegionSelection.INT.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/RegionSelection/RegionSelection.INT.udn new file mode 100644 index 000000000000..d35413d2e2a6 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/RegionSelection/RegionSelection.INT.udn @@ -0,0 +1,75 @@ +Availability: Public +Crumbs: %ROOT% +Title: Region Selection +Description: This is an overview of the Region Selection tool. +Type: reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:10 +Tags:Landscape +tags:region +Topic-image:RegionSelection_topic.png + +[TOC(start:2 end:2)] + +The **Region Selection** tool selects regions of the Landscape using the current brush settings and the tool strength to be used to fit a Landscape [gizmo](Engine\Landscape\Editing\Gizmos) to a +specific area or to act as a mask for copying data to, or pasting data from, a gizmo. + +## Using the Region Selection Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + hbWfSsZzmiY + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 44 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +In this example, the Region Selection tool has been used to paint an area of the Landscape using the default positive method, then switching to the negative mask method that enables you to paint areas that +don't want to include, and finally showing the Use Region As Mask section that captures the entirety of a Landscape component that is painted rather than just areas within it. + +Use the following controls to paint areas that can be used for selection by doing the following: + +| **Controls** | **Operation** | +| --- | --- | +| **Left Mouse Button** | Adds to the selected region. | +| **Shift + Left Mouse Button** | Removes from the selected region. | + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Without Selection](Selection1.png)(w:750) + [/PARAM] + [PARAM:after] + ![With Selection](Selection2.png)(w:750) + [/PARAM] +[/OBJECT] + +In this example, an area has been painted for selection that can then be used for masking layers or with the Copy/Paste tool. + +## Tool Settings + +[REGION:imagetable] +| ![](Landscape_RegionSelect.png)(h:75) | ![](RegionSelectionToolProperties.png)(h:135) | +| --- | --- | +||| +[/REGION] + +| **Property** | **Description** | +| ------------ | --------------- | +| **Clear Region Selection** | Clears the current selected region(s). | +| **Tool Strength** | Controls how much effect each brush stroke has. | +| **Use Region as Mask** | When checked, the region selection acts as a mask with the active area being comprised of the selected region. | +| ![](regionselection.png)(w:640) || +| **Negative Mask** | When checked, and when **Use Region as Mask** is also checked, the region selection acts as a mask, but the active area is comprised of the unselected region. | +| ![region_mask_negative.jpg](regionselectionnegative.png)(w:640) || + diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/RegionSelection/RegionSelection.JPN.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/RegionSelection/RegionSelection.JPN.udn new file mode 100644 index 000000000000..5f94639308b1 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/RegionSelection/RegionSelection.JPN.udn @@ -0,0 +1,76 @@ +INTSourceChangelist:3482403 +Availability:Public +Crumbs: %ROOT% +Title:Region Selection +Description:Region Selection ツールの概要です。 +Type: reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:10 +Tags:Landscape +tags:region +Topic-image:RegionSelection_topic.png + +[TOC(start:2 end:2)] + +**Region Selection** ツールは、現在のブラシ設定とツールの強度を使ってランドスケープのリージョンを選択することで、ランドスケープ [ギズモ](Engine\Landscape\Editing\Gizmos) を特定のエリアにフィットさせるだけでなく、 +ギズモへデータをコピーするマスクや、ギズモからデータをペーストするマスクとしても使用することができます。 + +## Region Selection ツールの使用方法 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + hbWfSsZzmiY + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 44 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +この例では、Region Selection ツールを使ってランドスケープをペイントしています。まずデフォルトの Positive Mask 使った後で、インクルードしたくない領域をペイントする Negafive Mask を使い、 +最後に、含まれている領域だけではなくペイントされた Landscape コンポーネント全体をキャプチャする [Use Region As Mask] セクションを表示しています。 + +選択範囲のペイントには、以下の制御を使用します。 + +| **操作** | **処理内容** | +| --- | --- | +| **マウスの左ボタン** | 選択したリージョンへ追加します。 | +| **Shift + マウスの左ボタン** | 選択したリージョンから削除します。 | + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Without Selection](Selection1.png)(w:750) + [/PARAM] + [PARAM:after] + ![With Selection](Selection2.png)(w:750) + [/PARAM] +[/OBJECT] + +この例では、レイヤーをマスクするため、または Copy/Paste ツールと使用するための選択用にペイントされています。 + +## ツール設定 + +[REGION:imagetable] +| ![](Landscape_RegionSelect.png)(h:75) | ![](RegionSelectionToolProperties.png)(h:135) | +| --- | --- | +||| +[/REGION] + +| **プロパティ** | **説明** | +| ------------ | --------------- | +| **Clear Region Selection** | 現在選択中のリージョンを解除します。 | +| **Tool Strength** | 1 回のブラシ ストロークの強度を調節します。 | +| **Use Region as Mask** | チェックが入っている場合は、選択されたリージョンを構成しているアクティブな領域が選択領域がマスクとして機能します。 +| ![](regionselection.png)(w:640) || +| **Negative Mask** | **Use Region as Mask** と共にチェックが入っている場合は、リージョン選択はマスクとしての役割をしますが、アクティブな領域は選択されていないリージョンで構成されています。 +| ![region_mask_negative.jpg](regionselectionnegative.png)(w:640) || + diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/RegionSelection/RegionSelection.KOR.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/RegionSelection/RegionSelection.KOR.udn new file mode 100644 index 000000000000..686104d2a461 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/RegionSelection/RegionSelection.KOR.udn @@ -0,0 +1,76 @@ +INTSourceChangelist:0 +Availability: Public +Crumbs: %ROOT% +Title: Region Selection +Description: This is an overview of the Region Selection tool. +Type: reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:10 +Tags:Landscape +tags:region +Topic-image:RegionSelection_topic.png + +[TOC(start:2 end:2)] + +The **Region Selection** tool selects regions of the Landscape using the current brush settings and the tool strength to be used to fit a Landscape [gizmo](Engine\Landscape\Editing\Gizmos) to a +specific area or to act as a mask for copying data to, or pasting data from, a gizmo. + +## Using the Region Selection Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + hbWfSsZzmiY + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 44 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +In this example, the Region Selection tool has been used to paint an area of the Landscape using the default positive method, then switching to the negative mask method that enables you to paint areas that +don't want to include, and finally showing the Use Region As Mask section that captures the entirety of a Landscape component that is painted rather than just areas within it. + +Use the following controls to paint areas that can be used for selection by doing the following: + +| **Controls** | **Operation** | +| --- | --- | +| **Left Mouse Button** | Adds to the selected region. | +| **Shift + Left Mouse Button** | Removes from the selected region. | + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Without Selection](Selection1.png)(w:750) + [/PARAM] + [PARAM:after] + ![With Selection](Selection2.png)(w:750) + [/PARAM] +[/OBJECT] + +In this example, an area has been painted for selection that can then be used for masking layers or with the Copy/Paste tool. + +## Tool Settings + +[REGION:imagetable] +| ![](Landscape_RegionSelect.png)(h:75) | ![](RegionSelectionToolProperties.png)(h:135) | +| --- | --- | +||| +[/REGION] + +| **Property** | **Description** | +| ------------ | --------------- | +| **Clear Region Selection** | Clears the current selected region(s). | +| **Tool Strength** | Controls how much effect each brush stroke has. | +| **Use Region as Mask** | When checked, the region selection acts as a mask with the active area being comprised of the selected region. | +| ![](regionselection.png)(w:640) || +| **Negative Mask** | When checked, and when **Use Region as Mask** is also checked, the region selection acts as a mask, but the active area is comprised of the unselected region. | +| ![region_mask_negative.jpg](regionselectionnegative.png)(w:640) || + diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Retopologize/Retopologize.CHN.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Retopologize/Retopologize.CHN.udn new file mode 100644 index 000000000000..e232059d1d8e --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Retopologize/Retopologize.CHN.udn @@ -0,0 +1,92 @@ +INTSourceChangelist:0 +Availability: Public +Crumbs: %ROOT% +Title: Retopologize +Description: This is an overview of the Retopologize painting tool. +Type: reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:8 +Tags:Landscape +Topic-image:Retopo_topic.png + +[TOC(start:2 end:2)] + +The **Retopologize** tool automatically adjusts Landscape vertices with an X/Y offset map to improve vertex density in areas that need it, like steep cliffs. This allows for reduced texture stretching in +these types of areas by spreading the vertices into these areas that are less dense. + +[REGION:note] +An X/Y offset map will make the Landscape slower to render and paint on with other tools, so only use the Retopologize tool if needed. +[/REGION] + + +## Using the Retopologize Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + o4dVt1tGJt4 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 46 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +In this example, we have a steep incline that was created by flattening an area, however, it left these vertical areas with fewer Landscape vertices spread across the surface which caused the textures to +appear stretched and some jagged artifacts around the edges of the flattened area. By using the Retopologize tool the surrounding vertices have been pulled and redistributed without significantly altering the +work that was done to make the flattened area. This reduces the stretching and jagged edges that appear. + +Use the following controls to paint an X/Y offset map to retopologize your Landscape heightmap: + +| **Controls** | **Operation** | +| --- | --- | +| **Left Mouse Button** | Heightens or increases the heightmap or selected layer's weight. | + +[REGION:imagetable] +| [INCLUDE:#lit] | [INCLUDE:#wireframe] | +| ---- | ---- | +| Retopologize Lit View | Retopologize Wireframe View | +[/REGION] + +In these comparison examples, you can see how the texture stretching has been reduced in these sharp inclines for the lit view and with the wireframe view you can see how the vertices have been redistributed +to be more evenly spaced in these steep inclines. + + + +### Tool Settings + +![Retopologize Tool](Landscape_Retopologize.png) + +There are no tool settings specific to Retopologize that can be adjusted. Simply select the tool from the selection and paint the areas in your Landscape that need to have their vertex density redistributed. diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Retopologize/Retopologize.INT.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Retopologize/Retopologize.INT.udn new file mode 100644 index 000000000000..5cc2e5f33b7c --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Retopologize/Retopologize.INT.udn @@ -0,0 +1,91 @@ +Availability: Public +Crumbs: %ROOT% +Title: Retopologize +Description: This is an overview of the Retopologize painting tool. +Type: reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:8 +Tags:Landscape +Topic-image:Retopo_topic.png + +[TOC(start:2 end:2)] + +The **Retopologize** tool automatically adjusts Landscape vertices with an X/Y offset map to improve vertex density in areas that need it, like steep cliffs. This allows for reduced texture stretching in +these types of areas by spreading the vertices into these areas that are less dense. + +[REGION:note] +An X/Y offset map will make the Landscape slower to render and paint on with other tools, so only use the Retopologize tool if needed. +[/REGION] + + +## Using the Retopologize Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + o4dVt1tGJt4 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 46 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +In this example, we have a steep incline that was created by flattening an area, however, it left these vertical areas with fewer Landscape vertices spread across the surface which caused the textures to +appear stretched and some jagged artifacts around the edges of the flattened area. By using the Retopologize tool the surrounding vertices have been pulled and redistributed without significantly altering the +work that was done to make the flattened area. This reduces the stretching and jagged edges that appear. + +Use the following controls to paint an X/Y offset map to retopologize your Landscape heightmap: + +| **Controls** | **Operation** | +| --- | --- | +| **Left Mouse Button** | Heightens or increases the heightmap or selected layer's weight. | + +[REGION:imagetable] +| [INCLUDE:#lit] | [INCLUDE:#wireframe] | +| ---- | ---- | +| Retopologize Lit View | Retopologize Wireframe View | +[/REGION] + +In these comparison examples, you can see how the texture stretching has been reduced in these sharp inclines for the lit view and with the wireframe view you can see how the vertices have been redistributed +to be more evenly spaced in these steep inclines. + + + +### Tool Settings + +![Retopologize Tool](Landscape_Retopologize.png) + +There are no tool settings specific to Retopologize that can be adjusted. Simply select the tool from the selection and paint the areas in your Landscape that need to have their vertex density redistributed. diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Retopologize/Retopologize.JPN.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Retopologize/Retopologize.JPN.udn new file mode 100644 index 000000000000..8c0ff86ce81e --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Retopologize/Retopologize.JPN.udn @@ -0,0 +1,92 @@ +INTSourceChangelist:3482403 +Availability:Public +Crumbs: %ROOT% +Title:Retopologize +Description:Retopologize ペイント ツールの概要です。 +Type: reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:8 +Tags:Landscape +Topic-image:Retopo_topic.png + +[TOC(start:2 end:2)] + +**Retopologize** ツールは、ランドスケープの頂点を X/Y オフセット マップで自動調整し、がん壁など調整が必要な領域の頂点密度を改善します。低密度の領域で頂点が散らばることによって +発生するテクスチャの伸縮を抑えます。 + +[REGION:note] +X/Y オフセット マップは、他のツールによるレンダリングやペイントのパフォーマンスに影響するので、Retopologize ツールは必要な場合のみ使用します。 +[/REGION] + + +## Retopologize ツールの使用方法 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + o4dVt1tGJt4 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 46 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +この例では、領域を平坦化して急傾斜が作成されていますが、これらの頂点領域ではサーフェス上にランドスケープ頂点がほとんど散らばっていないため、 +平坦化された領域のエッジ周辺のテクスチャが伸縮したり、粗削りのアーティファクトが発生します。Retopologize ツールを使うと、完了した作業に大きな変更を加えることなく、 +周囲の頂点を集めて再分配し、平坦化した領域を作ります。これにより、伸縮あるいは粗削りになったエッジを和らげます。 + +以下の制御を使っ X/Y オフセット マップをペイントして、ランドスケープ ハイトマップのリトポロジー処理を行います。 + +| **操作** | **処理内容** | +| --- | --- | +| **マウスの左ボタン** | ハイトマップを上げる、または選択したレイヤーのウェイトを増やします。 + +[REGION:imagetable] +| [INCLUDE:#lit] | [INCLUDE:#wireframe] | +| ---- | ---- | +| リット ビューをリトポロジー処理 | ワイヤーフレーム ビューをリトポロジー処理 | +[/REGION] + +上の比較を見ると、リット ビューではテクスチャの伸縮が急傾斜の部分で緩和されていることが分かります。 +ワイヤーフレーム ビューでは、急傾斜の部分で頂点が等間隔で再分布されていることが分かります。 + + + +### ツール設定 + +![Retopologize Tool](Landscape_Retopologize.png) + +Retopologize のみを調整するツール設定はありません。選択からツールを選択し、ランドスケープで頂点密度の再分布が必要な領域をペイントします。 diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Retopologize/Retopologize.KOR.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Retopologize/Retopologize.KOR.udn new file mode 100644 index 000000000000..e232059d1d8e --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Retopologize/Retopologize.KOR.udn @@ -0,0 +1,92 @@ +INTSourceChangelist:0 +Availability: Public +Crumbs: %ROOT% +Title: Retopologize +Description: This is an overview of the Retopologize painting tool. +Type: reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:8 +Tags:Landscape +Topic-image:Retopo_topic.png + +[TOC(start:2 end:2)] + +The **Retopologize** tool automatically adjusts Landscape vertices with an X/Y offset map to improve vertex density in areas that need it, like steep cliffs. This allows for reduced texture stretching in +these types of areas by spreading the vertices into these areas that are less dense. + +[REGION:note] +An X/Y offset map will make the Landscape slower to render and paint on with other tools, so only use the Retopologize tool if needed. +[/REGION] + + +## Using the Retopologize Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + o4dVt1tGJt4 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 46 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +In this example, we have a steep incline that was created by flattening an area, however, it left these vertical areas with fewer Landscape vertices spread across the surface which caused the textures to +appear stretched and some jagged artifacts around the edges of the flattened area. By using the Retopologize tool the surrounding vertices have been pulled and redistributed without significantly altering the +work that was done to make the flattened area. This reduces the stretching and jagged edges that appear. + +Use the following controls to paint an X/Y offset map to retopologize your Landscape heightmap: + +| **Controls** | **Operation** | +| --- | --- | +| **Left Mouse Button** | Heightens or increases the heightmap or selected layer's weight. | + +[REGION:imagetable] +| [INCLUDE:#lit] | [INCLUDE:#wireframe] | +| ---- | ---- | +| Retopologize Lit View | Retopologize Wireframe View | +[/REGION] + +In these comparison examples, you can see how the texture stretching has been reduced in these sharp inclines for the lit view and with the wireframe view you can see how the vertices have been redistributed +to be more evenly spaced in these steep inclines. + + + +### Tool Settings + +![Retopologize Tool](Landscape_Retopologize.png) + +There are no tool settings specific to Retopologize that can be adjusted. Simply select the tool from the selection and paint the areas in your Landscape that need to have their vertex density redistributed. diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Sculpt/Sculpt.CHN.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Sculpt/Sculpt.CHN.udn new file mode 100644 index 000000000000..e77f17b2b3b2 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Sculpt/Sculpt.CHN.udn @@ -0,0 +1,63 @@ +INTSourceChangelist:0 +Availability: Public +Crumbs: %ROOT% +Title: Sculpt +Description: This is an overview of the Sculpt painting tool. +Type: Reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:1 +Tags:Landscape +Topic-image:Landscape_Sculpt_topic.png + +[TOC(start:2 end:2)] + +The **Sculpt** tool enables you to raise and lower the height of the Landscape heightmap in the shape of the currently selected brush and falloff. + +## Using the Sculpt Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + HjZBhUsKa3s + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 47 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +In this example, the Sculpt tool applies height values to raise or lower the height data for the Landscape. Simply clicking and applying movement over the region you want to paint +will adjust the values based on the tool settings used. + +Use the following controls to sculpt your Landscape heightmap: + +| **Controls** | **Operation** | +| --- | --- | +| **Left Mouse Button** | Heightens or increases the heightmap or selected layer's weight. | +| **Shift + Left Mouse Button** | Lowers or decreases the heightmap or selected layer's weight. | + + +## Tool Settings + +[REGION:imagetable] +| ![Sculpt Tool](Landscape_Sculpt.png)(h:75) | ![](SculptToolProperties.png)(h:75) | +| --- | --- | +||| +[/REGION] + + +| **Property** | **Description** | +| ------------ | --------------- | +| **Tool Strength** | Controls how much effect each brush stroke has. If you're using a pen/tablet with pressure-sensing used, this will affect the strength of the tool. | +| **Use Target Value** | Enables a target value that the tools blend toward with each brush stroke. | + +The brush strength determines the amount of raising or lowering that can happen when using the Sculpting tool. + diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Sculpt/Sculpt.INT.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Sculpt/Sculpt.INT.udn new file mode 100644 index 000000000000..116a0f615a65 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Sculpt/Sculpt.INT.udn @@ -0,0 +1,62 @@ +Availability: Public +Crumbs: %ROOT% +Title: Sculpt +Description: This is an overview of the Sculpt painting tool. +Type: Reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:1 +Tags:Landscape +Topic-image:Landscape_Sculpt_topic.png + +[TOC(start:2 end:2)] + +The **Sculpt** tool enables you to raise and lower the height of the Landscape heightmap in the shape of the currently selected brush and falloff. + +## Using the Sculpt Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + HjZBhUsKa3s + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 47 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +In this example, the Sculpt tool applies height values to raise or lower the height data for the Landscape. Simply clicking and applying movement over the region you want to paint +will adjust the values based on the tool settings used. + +Use the following controls to sculpt your Landscape heightmap: + +| **Controls** | **Operation** | +| --- | --- | +| **Left Mouse Button** | Heightens or increases the heightmap or selected layer's weight. | +| **Shift + Left Mouse Button** | Lowers or decreases the heightmap or selected layer's weight. | + + +## Tool Settings + +[REGION:imagetable] +| ![Sculpt Tool](Landscape_Sculpt.png)(h:75) | ![](SculptToolProperties.png)(h:75) | +| --- | --- | +||| +[/REGION] + + +| **Property** | **Description** | +| ------------ | --------------- | +| **Tool Strength** | Controls how much effect each brush stroke has. If you're using a pen/tablet with pressure-sensing used, this will affect the strength of the tool. | +| **Use Target Value** | Enables a target value that the tools blend toward with each brush stroke. | + +The brush strength determines the amount of raising or lowering that can happen when using the Sculpting tool. + diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Sculpt/Sculpt.JPN.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Sculpt/Sculpt.JPN.udn new file mode 100644 index 000000000000..5e125ba930f1 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Sculpt/Sculpt.JPN.udn @@ -0,0 +1,63 @@ +INTSourceChangelist:3482403 +Availability:Public +Crumbs: %ROOT% +Title:Sculpt +Description:Sculpt ペイント ツールの概要です。 +Type:Reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:1 +Tags:Landscape +Topic-image:Landscape_Sculpt_topic.png + +[TOC(start:2 end:2)] + +**Sculpt** ツールは、選択中のブラシとフォールオフという形でランドスケープの高さの上げ下げをします。 + +## Sculpt ツールの使用方法 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + HjZBhUsKa3s + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 47 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +この例では、Sculpt ツールはハイト値を適用して、ランドスケープのハイト データの上げ下げをしています。ペイントしたいリージョンの上をクリックして移動させると、 +ツール設定に基づいて値が調整されます。 + +以下の制御を使って、ランドスケープ ハイトマップを生成します。 + +| **操作** | **処理内容** | +| --- | --- | +| **マウスの左ボタン** | ハイトマップを上げる、または選択したレイヤーのウェイトを増やします。 +| **Shift + マウスの左ボタン** | 高さマップまたは選択したレイヤーのウエイトを下げる、または減らします。 | + + +## ツール設定 + +[REGION:imagetable] +| ![Sculpt Tool](Landscape_Sculpt.png)(h:75) | ![](SculptToolProperties.png)(h:75) | +| --- | --- | +||| +[/REGION] + + +| **プロパティ** | **説明** | +| ------------ | --------------- | +| **Tool Strength** | 1 回のブラシ ストロークの強度を調節します。圧力センサーのペン / タブレットを使う場合、ツールの強度に影響します。 | +| **Use Target Value** | ブラシ ストロークごとにツールがブレンドするターゲット値を有効にします。 | + +Sculpting ツールを使う場合、ブラシの強度で高さ / 低さが決まります。 + diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Sculpt/Sculpt.KOR.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Sculpt/Sculpt.KOR.udn new file mode 100644 index 000000000000..e77f17b2b3b2 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Sculpt/Sculpt.KOR.udn @@ -0,0 +1,63 @@ +INTSourceChangelist:0 +Availability: Public +Crumbs: %ROOT% +Title: Sculpt +Description: This is an overview of the Sculpt painting tool. +Type: Reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:1 +Tags:Landscape +Topic-image:Landscape_Sculpt_topic.png + +[TOC(start:2 end:2)] + +The **Sculpt** tool enables you to raise and lower the height of the Landscape heightmap in the shape of the currently selected brush and falloff. + +## Using the Sculpt Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + HjZBhUsKa3s + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 47 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +In this example, the Sculpt tool applies height values to raise or lower the height data for the Landscape. Simply clicking and applying movement over the region you want to paint +will adjust the values based on the tool settings used. + +Use the following controls to sculpt your Landscape heightmap: + +| **Controls** | **Operation** | +| --- | --- | +| **Left Mouse Button** | Heightens or increases the heightmap or selected layer's weight. | +| **Shift + Left Mouse Button** | Lowers or decreases the heightmap or selected layer's weight. | + + +## Tool Settings + +[REGION:imagetable] +| ![Sculpt Tool](Landscape_Sculpt.png)(h:75) | ![](SculptToolProperties.png)(h:75) | +| --- | --- | +||| +[/REGION] + + +| **Property** | **Description** | +| ------------ | --------------- | +| **Tool Strength** | Controls how much effect each brush stroke has. If you're using a pen/tablet with pressure-sensing used, this will affect the strength of the tool. | +| **Use Target Value** | Enables a target value that the tools blend toward with each brush stroke. | + +The brush strength determines the amount of raising or lowering that can happen when using the Sculpting tool. + diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/SculptMode.INT.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/SculptMode.INT.udn index 4bc962c18cee..73ea99f58352 100644 --- a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/SculptMode.INT.udn +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/SculptMode.INT.udn @@ -1,315 +1,77 @@ Availability: Public -Title:Sculpt Mode -Crumbs: %ROOT%, Engine, Engine/Landscape, Engine/Landscape/Editing -Description:Guide to the Landscape tool's Sculpt mode. -version: 4.9 - -[VAR:Topic] -[OBJECT:Topiccompact] - [PARAM:image] - ![%Engine/Landscape/Editing/SculptMode:title%](Landscape_Sculpt_topic.png) - [/PARAM] - [PARAM:icon] - ![Landscape Icon](%ROOT%/landscape_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Landscape/Editing/SculptMode:title% - [/PARAM] - [PARAM:description] - %Engine/Landscape/Editing/SculptMode:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Landscape/Editing/SculptMode] - [/PARAM] -[/OBJECT] -[/VAR] - +Crumbs: %ROOT% +Title: Sculpt Mode +Description: Guide to the Landscape tool's Sculpt mode. +Type: Landing +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Landscape/Editing +Related:Engine/Landscape/Editing/Brushes +Related:Engine/Landscape/UI +Order: +Tags:Landscape +topic-image:Landscape_Sculpt_topic.png [TOC(start:2 end:3)] -The process of sculpting a Landscape involves using one or more tools that modify the underlying heightmap. These tools range from the simple Sculpt tool to other tools that use complex algorithms to apply interesting effects to the heightmap, such as erosion. Each tool has a set of properties that determine how the tool affects the Landscape. +The process of sculpting a Landscape involves using one or more tools that modify the underlying heightmap. These tools range from the simple Sculpt tool that paints +height values using a brush and strength scale to many other tools that use complex algorithms to apply interesting effects to the heightmap, such as erosion. Each +tool has a set of properties that determines how the tool affects the Landscape. -[REGION:tip] -Landscape Paint Mode also works in the VR Editor. For the controls for using Landscape in VR, see the [](Engine/Editor/VR/Controls). +![](SculptTools_Overview.png)(w:900) + +## Tool Workflow + +Once you've [created your Landscape](Engine/Landscape/Creation), you will have access to the other features of the Landscape tool, like Sculpting by selecting the **Sculpt** mode button. + +![](SelectSculptMode.png)(w:325) + +Once selected, the Sculpt tool options will become available for choosing the type of sculpting tool along with the [brush style and falloff type](engine/landscape/editing/brushes) you'd like to use to apply their effects using strokes to your landscape heightmap. + +[REGION:raw] +![](SculptToolSelection.png)(w:450) [/REGION] +With your Sculpting tool selected, you can now use the following controls to start sculpting your landscape: -The currently selected tool determines the operation that will be performed on the Landscape. The tools use [brushes](Engine\Landscape\Editing\Brushes) to apply their effects using strokes. +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + I_EzqWISGFI + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] | **Common Controls** | **Operation** | | --- | --- | -| **Left Mouse Button** | Performs a stroke that applies the selected tool's effects to the heightmap. | +| **Left Mouse Button** | Performs a stroke that applies an additive application of the selected tool's effects to the heightmap. | +| **Left Mouse Button + Shift** | Performs a stroke that applies a subtractive application of the selected tool's effects to the heightmap. | | **Ctrl + Z** | Undoes last stroke. | | **Ctrl + Y** | Redoes last undone stroke. | For a quick reference guide to the Landscape tool's various modes, tools, and brushes, see [](Engine/Landscape/UI). + ## Sculpting Tools -You can use the Sculpting Tools to modify the shape of your Landscape in various ways. +The **Sculpting Tools** enable you to modify the shape of your Landscape in various ways. Explore the different sculpting selections available below: -### Sculpt - -![Sculpt Tool](Landscape_Sculpt.png) - -The **Sculpt** tool increases or decreases the heightmap height in the shape of the currently selected brush and falloff. - -| **Alternate Controls** | **Operation** | -| --- | --- | -| **Left Mouse Button** | Heightens or increases the heightmap or selected layer's weight. | -| **Shift + Left Mouse Button** | Lowers or decreases the heightmap or selected layer's weight. | - -**Options:** - -| **Option** | **Description** | -| --- | --- | -| **Tool Strength** | Controls how much effect each brush stroke has. | - -The brush strength determines the amount of raising or lowering. - - -### Smooth - -![Smooth Tool](Landscape_Smooth.png) - -The **Smooth** tool smooths the heightmap. The strength determines the amount of smoothing. - -**Heightmap Smoothing** - -![Landscape_Smooth_Before.jpg](Landscape_Smooth_Before.jpg)(w:900 h:325) - -![Landscape_Smooth_After_HighDetail.jpg](Landscape_Smooth_After_HighDetail.jpg)(w:900 h:325) - -| **Option** | **Description** | -| --- | --- | -| **Tool Strength** | Controls how much smoothing occurs with each brush stroke has. | -| **Filter Kernel Scale** | Sets the scale multiplier for the smoothing filter kernel. | -| **Detail Smooth** | If checked, performs a detail-preserving smoothing using the specified detail-smoothing value. Larger-detail smoothing values remove more details, while smaller values preserve more details. [INCLUDE:#DetailSmooth] | - - - - -### Flatten - -![Flatten Tool](Landscape_FlattenTool.png) - -The **Flatten** tool flattens the Landscape to the level of the Landscape under the mouse cursor when you first activate the tool. - -![Landscape_Original.jpg](Landscape_Original.jpg)(w:900 h:325) - -![Landscape_Flatten.jpg](Landscape_Flatten.jpg)(w:900 h:325) - -| **Option** | **Description** | -| --- | --- | -| **Tool Strength** | Controls how much smoothing occurs with each brush stroke has. | -| **Flatten Mode** | Determines whether the tool will raise or lower the heightmap section under the brush. | -| **Use Slope Flatten** | If checked, flattens along the Landscape's existing slope instead of flattening toward a horizontal plane. | -| **Pick Value Per Apply** | If checked, constantly selects new values to flatten toward, instead of only using the first clicked point. | -| **Flatten Target** | Sets the target height toward which to flatten. | - - -### Ramp - -![Ramp Tool](Landscape_Ramp.png) - -The **Ramp** tool enables you to select two locations on your Landscape and create a flat ramp between them, with a falloff you specify on the sides. - -**To add a ramp to your Landscape:** - -1. **Ctrl + Left-click** in two locations to mark the beginning and end points of the ramp. - - ![Ramp Setup](Landscape_RampSetup.png)(w:700) - -1. If necessary, adjust the options you want for the ramp's width and falloff. - - ![Ramp Settings](Landscape_RampSettings.png) - -1. Click **Add Ramp** to create the ramp. - - ![Add Ramp](Landscape_RampAdd.png) - - ![Ramp Added](Landscape_RampAddedSprites.png)(w:700) - -![Ramp Tool Before](Landscape_RampBefore4.png)(w:900) - -![Ramp Tool After](Landscape_RampAddedNoSprites.png)(w:900) - - -[REGION:tip] -If you change your mind about adding a ramp after starting to set the beginning and end points, you can click **Reset** to clear them. -[/REGION] - -| **Option** | **Description** | -| --- | --- | -| **Ramp Width** | Sets the width of the ramp. | -| **Side Falloff** | Sets the falloff on the sides of the ramp, where it merges into the rest of the Landscape. A setting of **0** means no falloff; a setting of **1** means all falloff and no flat ramp. | - - -### Erosion - -![Erosion Tool](Landscape_Erosion.png) - -The **Erosion** tool uses a thermal erosion simulation to adjust the height of the heightmap. This simulates the transfer of soil from higher elevations to lower elevations. The larger the difference in elevation, the more erosion will occur. This tool also applies a noise effect on top of the erosion, if desired, to provide a more natural random appearance. - - -![Landscape_Original.jpg](Landscape_Original.jpg)(w:900 h:325) - -![Landscape_Thermal_Erosion.jpg](Landscape_Thermal_Erosion.jpg)(w:900 h:325) - -| **Option** | **Description** | -| --- | --- | -| **Tool Strength** | Controls how much effect each brush stroke has. | -| **Threshold** | The minimum height difference necessary for the erosion effects to be applied. Smaller values will result in more erosion being applied. | -| **Surface Thickness** | The thickness of the surface for the layer weight erosion effect. | -| **Iterations** | The number of iterations performed. Larger values result in more levels of erosion. | -| **Noise Mode** | Whether to apply noise to raise or lower the heightmap, or do both. | -| **Noise Scale** | The size of the noise filter used. The noise filter is related to position and scale, which means if you do not change **Noise Scale**, the same filter is applied to the same position many times. | -| ![](Erosion_New.jpg)(w:900 h:325) || - - - -### Hydro Erosion - -![Hydro Erosion Tool](Landscape_HydroErosion.png) - -The **Hydro Erosion** tool uses a hydraulic erosion simulation, i.e. erosion from water, to adjust the height of the heightmap. A noise filter is used to determine where the initial rain is distributed. Then the simulation is calculated to determine water flow from that initial rain as well as dissolving, water transfer, and evaporation. The result of that calculation provides the actual value used to lower the heightmap. - -![Landscape_Original.jpg](Landscape_Original.jpg)(w:900 h:325) - -![Landscape_Hydraulic_Erosion.jpg](Landscape_Hydraulic_Erosion.jpg)(w:900 h:325) - -| **Option** | **Description** | -| --- | --- | -| **Tool Strength** | Controls how much effect each brush stroke has. | -| **Rain Amount** | The amount of rain to apply to the surface. Larger values will result in more erosion. | -| **Sediment Cap.** | The amount of sediment that the water can carry. Larger values will result in more erosion. | -| **Iterations** | The number of iterations performed. Larger values result in more levels of erosion. | -| **Initial Rain Distribution** | Whether rain is applied only where the noise filter is positive, or to the entire area. | -| ![](Hydro_Erosion.jpg)(w:900 h:325) || -| **Rain Dist Scale** | The size of the noise filter for applying initial rain to the surface. The noise filter is related to position and scale, which means if you do not change **Rain Dist. Scale**, the same filter is applied to the same position many times. | -| **Detail Smooth** | If checked, performs a detail-preserving smoothing to the erosion effect using the specified detail-smoothing value. Larger detail-smoothing values remove more details, while smaller values preserve more details. | - - - -### Noise - -![Noise Tool](Landscape_Noise.png) - -The **Noise** tool applies a noise filter to the heightmap or layer weight. The strength determines the amount of noise. - -| **Option** | **Description** | -| --- | --- | -| **Tool Strength** | Controls how much effect each brush stroke has. | -| **Use Target Value** | If checked, blends the values of the noise being applied toward a target value. | -| **Noise Mode** | Determines whether to apply all noise effects, only the noise effects that result in raising the heightmap, or only the noise effects that result in lowering the heightmap. | -| ![](Noise.jpg)(w:900 h:325) || -| **Noise Scale** | The size of the perlin noise filter used. The noise filter is related to position and scale, which means if you do not change **Noise Scale**, the same filter is applied to the same position many times. | - - -### Retopologize - -![Retopologize Tool](Landscape_Retopologize.png) - -The **Retopologize** tool automatically adjusts Landscape vertices with an X/Y offset map to improve vertex density on cliffs, reducing texture stretching. - -[REGION:note] -An X/Y offset map makes the Landscape slower to render and paint on with other tools, so only use the Retopologize tool if needed. -[/REGION] - - -### Visibility - -![Visibility Tool](Landscape_Visibility.png) - -The **Visibility** tool enables you to create holes in your Landscape, such as for caves. - -| **Alternate Controls** | **Operation** | -| --- | --- | -| **Shift + Left-click** | Removes the visibility mask, making the Landscape components visible again. | - -#### Using Opacity Masking to Create a Hole - -[EXCERPT:LandscapeHole] -Although you can use the sculpting tools to create vertical holes in your Landscape, you may find that you also want to create horizontal ones, such as for caves. You can do so by using opacity masking to "paint" away the visibility of a section of your Landscape with the Visibility tool. -[/EXCERPT:LandscapeHole] - -In order to paint away the visibility of a section of your Landscape, you must set up the Landscape Material correctly. For information about setting up a Landscape Hole Material, see [Landscape Hole Materials](Engine\Landscape\Materials\#LandscapeHoleMaterials). - -[REGION:note] -If you use the Visibility tool without having a Landscape Hole Material assigned, the Visibility tool will remove the Material layers applied to the selected sections, but will not create a hole in the Landscape itself. -[/REGION] - -After you have set up your Landscape Hole Material, you can use the painting tools to create a hole in your Landscape. - -**To create a Landscape hole:** - -1. Make sure you have a **Landscape Hole Material** assigned to your Landscape. - - ![](Engine/Landscape/Materials/Landscape_HoleSettings.png) - -1. In the Landscape tool, in **Sculpt** mode, select the **Visibility** tool. - - ![Visibility Tool](Landscape_Visibility.png) - -1. Find the location on your Landscape where you want to create a hole. - - ![](Landscape_MountainNoCave.png)(w:640) - -1. Adjust the brush size and falloff appropriately. - - ![](Landscape_MountainCaveMask.png)(w:640) - -1. **Left-click** to create the hole and **Shift + Left-click** to erase a hole that was created. - - ![](Landscape_MountainHole.png)(w:640) - - You can now fit Static Mesh Actors in the hole in the Landscape to create a cave. - - [REGION:note] - To test out the collision of the new hole using Play In Editor (PIE), you may have to switch from Landscape mode to Place mode. - [/REGION] +[DIR(output:"topiccompact" parent:"Engine/Landscape/Editing/SculptMode" org:"hierarchy" tags:"landscape" tags:"!region" end:"1")] (#RegionTools) ## Region Tools -You can use the Region tools to perform actions on specific regions of the Landscape. +The **Region Tools** enable you to perform actions on specific regions of the Landscape. Explore the different Region options available below: - -### Region Selection - -![Region Selection Tool](Landscape_RegionSelect.png) - -The **Region Selection** tool selects regions of the Landscape using the current brush settings and tool strength to be used to fit a Landscape [gizmo](Engine\Landscape\Editing\Gizmos) to a specific area or to act as a mask for copying data to, or pasting data from, a gizmo. - -![region_selection.jpg](region_selection.jpg)(w:640 h:322) - -| **Controls** | **Operation** | -| --- | --- | -| **Left Mouse Button** | Adds to the selected region. | -| **Shift + Left Mouse Button** | Removes from the selected region. | - -| **Option** | **Description** | -| --- | --- | -| **Clear Region Selection** | Clears the current selected region(s). | -| **Tool Strength** | Controls how much effect each brush stroke has. | -| **Use Region as Mask** | When checked, the region selection acts as a mask with the active area being comprised of the selected region. | -| ![region_mask.jpg](region_mask.jpg)(w:640 h:322) || -| **Negative Mask** | When checked, and when **Use Region as Mask** is also checked, the region selection acts as a mask, but the active area is comprised of the unselected region. | -| ![region_mask_negative.jpg](region_mask_negative.jpg)(w:640 h:322) || - - -(#RegionCopy) -### Copy/Paste - -![Copy/Paste Tool](Landscape_CopyPaste.png) - -You can use this tool to copy height data from one area of a Landscape to another through the use of [](Engine/Landscape\Editing\Gizmos). You can also import and export Gizmo data. - -[INCLUDE:Engine/Landscape#landscape002] +[DIR(output:"topiccompact" parent:"Engine/Landscape/Editing/SculptMode" org:"hierarchy" tags:"landscape" tags:"region" end:"1")] diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/SculptMode.KOR.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/SculptMode.KOR.udn index 2bec7adf2132..88da46581323 100644 --- a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/SculptMode.KOR.udn +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/SculptMode.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3260884 +INTSourceChangelist:3473556 Availability: Public Title:조각 모드 Crumbs: %ROOT%, Engine, Engine/Landscape, Engine/Landscape/Editing @@ -313,4 +313,55 @@ Region Selection (리전 선택) 툴은 현재 브러시 세팅을 사용하여 이 툴을 사용해서 랜드스케이프 한 영역의 높이 데이터를 [](Engine/Landscape\Editing\Gizmos) 사용을 통해 다른 랜드스케이프로 복사할 수 있습니다. 기즈모 데이터를 임포트 / 익스포트할 수도 있습니다. +### 미러 + +![Mirror Tool](Landscape_Mirror.png) + +**Mirror** (미러) 툴은 선택된 랜드스케이프를 X 또는 Y 축 기준으로 미러링 또는 회전시킵니다. + +[REGION:simpletable] +| 옵션 | 설명 | +| --- | --- | +| **Mirror Point** | 미러링 지점 - 미러링 면의 위치를 설정합니다. 기본적으로 선택된 랜드스케이프의 중앙이 되며, 대부분의 경우 바꿀 필요가 없습니다. | +| **Operation** | 연산 - 수행할 미러링 연산 유형입니다. 예를 들어 -X 에서 +X 는 랜드스케이프의 -X 절반을 복사하여 +X 로 뒤집습니다. | +| **Recenter** | 중앙 재설정 - 이 버튼은 미러링 면을 선택된 랜드스케이프 중심으로 다시 설정합니다. | +| **Smoothing Width** | 스무딩 폭 - 미러링 면 한 쪽의 버텍스에 스무딩을 적용할 버텍스 수를 설정합니다. 미러링된 면의 날카로운 대비 각도 감소 효과가 있습니다. | +[/REGION] + +**랜드스케이프 미러링 방법:** + +1. 랜드스케이프 툴의 **조각** 모드에서 **Mirror** (미러) 툴을 선택합니다. + + ![미러 툴](Landscape_Mirror.png) + +1. **Operation** (연산) 드롭다운으로 선택된 랜드스케이프에 사용할 미러링 메소드와 축을 선택합니다. 방향 화살표를 통해 랜드스케이프 지오메트리의 어느 면에 미러링이 적용될지 알 수 있습니다. + + ![](Mirror_Settings.png)(w:417) + +1. 필요한 경우, 미러링 면의 **Mirror Point** (미러링 지점) 값을 조절하거나, 미러링 면의 방향 화살표를 좌클릭하고 미러링하고자 하는 위치로 끌어 놓습니다. + + [REGION:note] + **미러링 지점** 에는 현재 선택된 **연산** 축만 사용됩니다. 예를 들어, 연산 메소드가 "-X 에서 +X" 인 경우, X 축만 활성 미러링 포인트로 영향받습니다. + [/REGION] + ![](Mirror_1.png)(w:500) + +1. 편집한 내용이 마음에 들면 **적용** 버튼을 눌러 결과를 확인합니다. + + ![](Mirror_3.png)(w:500) + + 미러링된 지오메트리가 있는 랜드스케이프가 생겼습니다. + +[REGION:tip] +변경사항을 적용한 이후 랜드스케이프 미러링의 에지 이음새가 부자연스럽거나 대비선이 너무 뚜렷한 경우, **Ctrl + Z** 로 지난 동작을 되돌립니다. 그리고 **Smoothing Width** (스무딩 폭)을 조절하여 이 병합 부분의 에지 버텍스를 +부드럽게 만듭니다. 아래 예제의 왼쪽 이미지에는 스무딩이 없는 반면, 오른쪽 이미지에는 10 의 값을 주어 병합 부분의 에지를 부드럽게 만든 것입니다. + +[REGION:lightbox] +[![](Mirror_SmoothingWidth.png)(w:500)](Mirror_SmoothingWidth.png) +[/REGION] +_클릭하면 이미지 원본을 확인합니다._ + +[/REGION] + + + [INCLUDE:Engine/Landscape#landscape002] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Smooth/Smooth.CHN.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Smooth/Smooth.CHN.udn new file mode 100644 index 000000000000..fc0eca767bea --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Smooth/Smooth.CHN.udn @@ -0,0 +1,68 @@ +INTSourceChangelist:0 +Availability: Public +Crumbs: %ROOT% +Title: Smooth +Description: This is an overview of the Smooth painting tool. +Type: Reference +Parent:Engine/Landscape/Editing/SculptMode +Order:2 +Tags:Landscape +Topic-image:Smooth_topic.png + +[TOC(start:2 end:2)] + +The **Smooth** tool will soften the heightmaps painted values to give it a smoother flow and appearance by getting rid of jagged artifacts that can sometimes happen after using the Sculpting or Erosion tools. + +## Using the Smooth Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + z2Kvc2K7u3g + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 46 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +In this example, the Smooth tool is used to soften some of the harder edge artifacts that can happen when using the various Landscape tools. + +Use the following controls to sculpt your Landscape heightmap: + +| **Controls** | **Operation** | +| --- | --- | +| **Left Mouse Button** | Smoothens and softens the heightmap or selected layer's weight. | + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before Smoothing](SmoothBefore.png)(w:750) + [/PARAM] + [PARAM:after] + ![After Smoothing](SmoothAfter.png)(w:750) + [/PARAM] +[/OBJECT] + +The brush strength determines the amount of smoothing that can happen when using the Smooth tool. + +## Tool Settings + +[REGION:imagetable] +| ![](Landscape_Smooth.png)(h:75) | ![](SmoothToolProperties.png)(h:105) | +| --- | --- | +||| +[/REGION] + + +| **Property** | **Description** | +| ------------ | --------------- | +| **Tool Strength** | Controls how much smoothing occurs with each brush stroke. | +| **Filter Kernel Scale** | Sets the scale multiplier for the smoothing filter kernel for the radius that smoothing will be performed over. Higher values smooth out bigger details, while lower values only smooth out smaller details. | +| **Detail Smooth** | If checked, performs a detail-preserving smoothing using the specified detail-smoothing value. Larger-detail smoothing values remove more details, while smaller values preserve more details. | diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Smooth/Smooth.INT.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Smooth/Smooth.INT.udn new file mode 100644 index 000000000000..5c843c98fe67 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Smooth/Smooth.INT.udn @@ -0,0 +1,67 @@ +Availability: Public +Crumbs: %ROOT% +Title: Smooth +Description: This is an overview of the Smooth painting tool. +Type: Reference +Parent:Engine/Landscape/Editing/SculptMode +Order:2 +Tags:Landscape +Topic-image:Smooth_topic.png + +[TOC(start:2 end:2)] + +The **Smooth** tool will soften the heightmaps painted values to give it a smoother flow and appearance by getting rid of jagged artifacts that can sometimes happen after using the Sculpting or Erosion tools. + +## Using the Smooth Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + z2Kvc2K7u3g + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 46 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +In this example, the Smooth tool is used to soften some of the harder edge artifacts that can happen when using the various Landscape tools. + +Use the following controls to sculpt your Landscape heightmap: + +| **Controls** | **Operation** | +| --- | --- | +| **Left Mouse Button** | Smoothens and softens the heightmap or selected layer's weight. | + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before Smoothing](SmoothBefore.png)(w:750) + [/PARAM] + [PARAM:after] + ![After Smoothing](SmoothAfter.png)(w:750) + [/PARAM] +[/OBJECT] + +The brush strength determines the amount of smoothing that can happen when using the Smooth tool. + +## Tool Settings + +[REGION:imagetable] +| ![](Landscape_Smooth.png)(h:75) | ![](SmoothToolProperties.png)(h:105) | +| --- | --- | +||| +[/REGION] + + +| **Property** | **Description** | +| ------------ | --------------- | +| **Tool Strength** | Controls how much smoothing occurs with each brush stroke. | +| **Filter Kernel Scale** | Sets the scale multiplier for the smoothing filter kernel for the radius that smoothing will be performed over. Higher values smooth out bigger details, while lower values only smooth out smaller details. | +| **Detail Smooth** | If checked, performs a detail-preserving smoothing using the specified detail-smoothing value. Larger-detail smoothing values remove more details, while smaller values preserve more details. | diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Smooth/Smooth.JPN.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Smooth/Smooth.JPN.udn new file mode 100644 index 000000000000..87cd7135f418 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Smooth/Smooth.JPN.udn @@ -0,0 +1,68 @@ +INTSourceChangelist:3482403 +Availability:Public +Crumbs: %ROOT% +Title:Smooth +Description:Smooth ペイント ツールの概要です。 +Type:Reference +Parent:Engine/Landscape/Editing/SculptMode +Order:2 +Tags:Landscape +Topic-image:Smooth_topic.png + +[TOC(start:2 end:2)] + +**Smooth** ツールを使うと、Sculpting ツールや Erosion ツールの使用後にたまに発生するギザギザのアーティファクトを取り除いて、ハイトマップ ペイント値をソフトにしてフローと外見をスムーズにします。 + +## Smooth ツールの使用方法 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + z2Kvc2K7u3g + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 46 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +この例では、Smooth ツールを使って、各種 Landscape ツールを使用すると発生するハードなエッジ アーティファクトをソフトにしています。 + +以下の制御を使って、ランドスケープ ハイトマップを生成します。 + +| **操作** | **処理内容** | +| --- | --- | +| **マウスの左ボタン** | ハイトマップまたは選択したレイヤーをスムーズ / ソフトにします。 + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before Smoothing](SmoothBefore.png)(w:750) + [/PARAM] + [PARAM:after] + ![After Smoothing](SmoothAfter.png)(w:750) + [/PARAM] +[/OBJECT] + +Smooth ツールを使う場合、ブラシの強度でスムーズ度が決まります。 + +## ツール設定 + +[REGION:imagetable] +| ![](Landscape_Smooth.png)(h:75) | ![](SmoothToolProperties.png)(h:105) | +| --- | --- | +||| +[/REGION] + + +| **プロパティ** | **説明** | +| ------------ | --------------- | +| **Total Strength** | 1 回のブラシ ストロークによるスムージング加減を調節します。 | +| **Filter Kernel Scale** | スムージングが実行される半径のスムージング フィルター カーネルに対しスケール乗数を設定します。値が高いほど大きな詳細をスムーズにし、値が低いほど小さな詳細をスムーズにします。 | +| **Detail Smooth** | このオプションがチェックされると、指定した詳細スムージング値を使用して、詳細を維持したままのスムージングを実行します。スムージング値が小さいほど詳細度が保たれ、値が大きいほど詳細が取り除かれます。 | diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Smooth/Smooth.KOR.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Smooth/Smooth.KOR.udn new file mode 100644 index 000000000000..fc0eca767bea --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Smooth/Smooth.KOR.udn @@ -0,0 +1,68 @@ +INTSourceChangelist:0 +Availability: Public +Crumbs: %ROOT% +Title: Smooth +Description: This is an overview of the Smooth painting tool. +Type: Reference +Parent:Engine/Landscape/Editing/SculptMode +Order:2 +Tags:Landscape +Topic-image:Smooth_topic.png + +[TOC(start:2 end:2)] + +The **Smooth** tool will soften the heightmaps painted values to give it a smoother flow and appearance by getting rid of jagged artifacts that can sometimes happen after using the Sculpting or Erosion tools. + +## Using the Smooth Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + z2Kvc2K7u3g + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 46 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +In this example, the Smooth tool is used to soften some of the harder edge artifacts that can happen when using the various Landscape tools. + +Use the following controls to sculpt your Landscape heightmap: + +| **Controls** | **Operation** | +| --- | --- | +| **Left Mouse Button** | Smoothens and softens the heightmap or selected layer's weight. | + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before Smoothing](SmoothBefore.png)(w:750) + [/PARAM] + [PARAM:after] + ![After Smoothing](SmoothAfter.png)(w:750) + [/PARAM] +[/OBJECT] + +The brush strength determines the amount of smoothing that can happen when using the Smooth tool. + +## Tool Settings + +[REGION:imagetable] +| ![](Landscape_Smooth.png)(h:75) | ![](SmoothToolProperties.png)(h:105) | +| --- | --- | +||| +[/REGION] + + +| **Property** | **Description** | +| ------------ | --------------- | +| **Tool Strength** | Controls how much smoothing occurs with each brush stroke. | +| **Filter Kernel Scale** | Sets the scale multiplier for the smoothing filter kernel for the radius that smoothing will be performed over. Higher values smooth out bigger details, while lower values only smooth out smaller details. | +| **Detail Smooth** | If checked, performs a detail-preserving smoothing using the specified detail-smoothing value. Larger-detail smoothing values remove more details, while smaller values preserve more details. | diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Visibility/Visibility.CHN.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Visibility/Visibility.CHN.udn new file mode 100644 index 000000000000..40581e34df02 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Visibility/Visibility.CHN.udn @@ -0,0 +1,131 @@ +INTSourceChangelist:0 +Availability: Public +Crumbs: %ROOT% +Title: Visibility +Description: This is an overview of the Visibility painting tool. +Type: Reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:9 +Tags:Landscape +Topic-image:Visibility_topic.png + +[TOC(start:2 end:2)] + +The **Visibility** tool enables you to mask out (create holes) in parts of your Landscape, for areas such as caves. + +## Using the Visibility Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + IU5RneVZzL0 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 44 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +In this example, the Visibility tool is used with a Landscape Material that has been setup to use a Landscape Visibility Mask. This enables parts of the Landscape to be painted invisible or +visible so that you can add in caves with additional Static Mesh Actors. This demonstration shows painting the invisibility and then repainting the visibility. + +Use the following controls to paint masked or to unmask areas of visibility for your Landscape: + +| **Controls** | **Operation** | +| --- | --- | +| **Left-Click** | Adds the visibility mask, making the Landscape invisible. | +| **Shift + Left-click** | Removes the visibility mask, making the Landscape components visible again. | + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before](Visibility1.png)(w:750) + [/PARAM] + [PARAM:after] + ![After](Visibility2.png)(w:750) + [/PARAM] +[/OBJECT] + +In this example, the Landscape Hole Material has been used to paint invisible (or masked out) areas for the Landscape. When painting masked out areas, you only get an on or off +state, so there is no way to have a transitional gradient from fully masked to unmasked. + + +### Using Opacity Mask to Create a Hole + +[EXCERPT:LandscapeHole] +Although you can use the sculpting tools to create a vertical holes in your Landscape, you may find that you also want to create horizontal ones, such as ones for caves. You can +do so by using opacity masking to "paint" away the visibility of a section of your Landscape with the Visibility tool. +[/EXCERPT:LandscapeHole] + +In order to paint away the visibility of a section of your Landscape, you must set up the Landscape Material correctly using a Landscape Hole Material. +For information about setting this up properly, you can read about [Landscape Hole Materials](Engine/Landscape/Materials/#LandscapeHoleMaterials) here. + +[REGION:note] +If you use the Visibility tool without having a Landscape Hole Material assigned, the Visibility tool will remove the Material layers applied to the selected sections, +but will not create a hole in the Landscape itself. +[/REGION] + +After you have set up your Landscape Hole Material, you can use the painting tools to create a hole in your Landscape. + +**To create a Landscape hole:** + +1. Make sure you have a **Landscape Hole Material** assigned to your Landscape. + + ![](LSHole_Details.png) + +1. In the Landscape tool, in **Sculpt** mode, select the **Visibility** tool. + + ![Visibility Tool](SelectVisibilityTool.png) + +1. Find the location on your Landscape where you want to create a hole. + + ![](Landscape_MountainNoCave.png)(w:640) + +1. Adjust the brush size to the size you want to use. + + ![](Landscape_MountainCaveMask.png)(w:640) + +1. **Left-click** to create the hole and **Shift + Left-click** to erase a hole that was created. + + ![](Landscape_MountainHole.png)(w:640) + + You can now fit Static Mesh Actors in the hole in the Landscape to create a cave. + + [REGION:note] + To test out the collision of the new hole using Play In Editor (PIE), you may have to switch from **Landscape** mode to **Place** mode. + [/REGION] + +## Tool Settings + +![Visibility Tool](Landscape_Visibility.png)(h:75) + +There are no tool settings specific to Visibility that can be adjusted in this section. Follow the steps to setup a proper Landscape Hole Material (detailed above) and use the paint to controls +to draw in your masked areas. + +If you do not have a **Landscape Hole Material** assigned to your Landscape, you will see the following warning in Visibility tool panel under **Target Layers**: + +![](VisibilityToolWarning.png)(w:400) + + + + + + + + + + + + + + + + + diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Visibility/Visibility.INT.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Visibility/Visibility.INT.udn new file mode 100644 index 000000000000..769549e4a06c --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Visibility/Visibility.INT.udn @@ -0,0 +1,130 @@ +Availability: Public +Crumbs: %ROOT% +Title: Visibility +Description: This is an overview of the Visibility painting tool. +Type: Reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:9 +Tags:Landscape +Topic-image:Visibility_topic.png + +[TOC(start:2 end:2)] + +The **Visibility** tool enables you to mask out (create holes) in parts of your Landscape, for areas such as caves. + +## Using the Visibility Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + IU5RneVZzL0 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 44 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +In this example, the Visibility tool is used with a Landscape Material that has been setup to use a Landscape Visibility Mask. This enables parts of the Landscape to be painted invisible or +visible so that you can add in caves with additional Static Mesh Actors. This demonstration shows painting the invisibility and then repainting the visibility. + +Use the following controls to paint masked or to unmask areas of visibility for your Landscape: + +| **Controls** | **Operation** | +| --- | --- | +| **Left-Click** | Adds the visibility mask, making the Landscape invisible. | +| **Shift + Left-click** | Removes the visibility mask, making the Landscape components visible again. | + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before](Visibility1.png)(w:750) + [/PARAM] + [PARAM:after] + ![After](Visibility2.png)(w:750) + [/PARAM] +[/OBJECT] + +In this example, the Landscape Hole Material has been used to paint invisible (or masked out) areas for the Landscape. When painting masked out areas, you only get an on or off +state, so there is no way to have a transitional gradient from fully masked to unmasked. + + +### Using Opacity Mask to Create a Hole + +[EXCERPT:LandscapeHole] +Although you can use the sculpting tools to create a vertical holes in your Landscape, you may find that you also want to create horizontal ones, such as ones for caves. You can +do so by using opacity masking to "paint" away the visibility of a section of your Landscape with the Visibility tool. +[/EXCERPT:LandscapeHole] + +In order to paint away the visibility of a section of your Landscape, you must set up the Landscape Material correctly using a Landscape Hole Material. +For information about setting this up properly, you can read about [Landscape Hole Materials](Engine/Landscape/Materials/#LandscapeHoleMaterials) here. + +[REGION:note] +If you use the Visibility tool without having a Landscape Hole Material assigned, the Visibility tool will remove the Material layers applied to the selected sections, +but will not create a hole in the Landscape itself. +[/REGION] + +After you have set up your Landscape Hole Material, you can use the painting tools to create a hole in your Landscape. + +**To create a Landscape hole:** + +1. Make sure you have a **Landscape Hole Material** assigned to your Landscape. + + ![](LSHole_Details.png) + +1. In the Landscape tool, in **Sculpt** mode, select the **Visibility** tool. + + ![Visibility Tool](SelectVisibilityTool.png) + +1. Find the location on your Landscape where you want to create a hole. + + ![](Landscape_MountainNoCave.png)(w:640) + +1. Adjust the brush size to the size you want to use. + + ![](Landscape_MountainCaveMask.png)(w:640) + +1. **Left-click** to create the hole and **Shift + Left-click** to erase a hole that was created. + + ![](Landscape_MountainHole.png)(w:640) + + You can now fit Static Mesh Actors in the hole in the Landscape to create a cave. + + [REGION:note] + To test out the collision of the new hole using Play In Editor (PIE), you may have to switch from **Landscape** mode to **Place** mode. + [/REGION] + +## Tool Settings + +![Visibility Tool](Landscape_Visibility.png)(h:75) + +There are no tool settings specific to Visibility that can be adjusted in this section. Follow the steps to setup a proper Landscape Hole Material (detailed above) and use the paint to controls +to draw in your masked areas. + +If you do not have a **Landscape Hole Material** assigned to your Landscape, you will see the following warning in Visibility tool panel under **Target Layers**: + +![](VisibilityToolWarning.png)(w:400) + + + + + + + + + + + + + + + + + diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Visibility/Visibility.JPN.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Visibility/Visibility.JPN.udn new file mode 100644 index 000000000000..f59ab7f4c1f2 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Visibility/Visibility.JPN.udn @@ -0,0 +1,131 @@ +INTSourceChangelist:3482403 +Availability:Public +Crumbs: %ROOT% +Title:Visibility +Description:Visibility ペイント ツールの概要です。 +Type:Reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:9 +Tags:Landscape +Topic-image:Visibility_topic.png + +[TOC(start:2 end:2)] + +**Visibility** ツールは、洞窟などランドスケープをマスクアウト (穴を作成) します。 + +## Visibility ツールの使用方法 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + IU5RneVZzL0 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 44 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +この例では、Landscape Visibility Mask を使うように設定された Landscape マテリアルと一緒に Visibility ツールを使用しています。この方法により、ペイントでランドスケープを可視/不可視にして、 +洞窟にスタティックメッシュ アクタの追加が可能になります。このデモでは、ペイントで不可視にしてから、再度ペイントで可視化しています。 + +ランドスケープ ハイトマップでのノイズによるスカルプトでは、以下の調節ができます。 + +| **操作** | **処理内容** | +| --- | --- | +| **Left-Click** | 可視性マスクを追加して、ランドスケープを可視化します。 | +| **Shift + マウスの左ボタン** | 可視性マスクは、ランドスケープ コンポーネントを再度表示させます。 | + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before](Visibility1.png)(w:750) + [/PARAM] + [PARAM:after] + ![After](Visibility2.png)(w:750) + [/PARAM] +[/OBJECT] + +この例では、Landscape Hole マテリアルを使用して、ランドスケープの見えない (マスクアウトした) 領域をペイントしています。マスクアウトした領域のペイントは、オンかオフのいずれかです。 +完全にマスクされた状態と完全にマスクされていない状態の間のグラディエントは一切ありません。 + + +### オパシティ マスクを使って穴を作成する + +[EXCERPT:LandscapeHole] +Sculpt ツールはランドスケープに垂直方向の穴の作成ができますが、洞窟などの場合は穴を水平方向に作成しなければなりません。そのような場合に Visibility ツールは、 +ランドスケープの可視化ペイントをオパシティ マスクを使って取り除きます。 +[/EXCERPT:LandscapeHole] + +ランドスケープの可視化ペイントを取り除くためには、Landscape Hole マテリアルを使って Landscape マテリアルを正しく設定する必要があります。 +正しく設定するには、[Landscape Hole マテリアル](Engine/Landscape/Materials/#LandscapeHoleマテリアル) をご覧ください。 + +[REGION:note] +Landscape Hole マテリアルを割り当てずに Visibility ツールを使用すると、Visibility ツールは選択したセクションに適用されているマテリアル レイヤーを取り除きますが、 +ランドスケープそのものに穴は作成しません。 +[/REGION] + +Landscape Hole マテリアルを設定したら、ペイント ツールを使ってランドスケープに穴を作成することができます。 + +**ランドスケープに穴を作成する方法** + +1. **Landscape Hole** マテリアルがランドスケープに割り当てられていることを確認します。 + + ![](LSHole_Details.png) + +1. Landscape ツールの **Sculpt** モードで **Visibility** ツールを選びます。 + + ![Visibility Tool](SelectVisibilityTool.png) + +1. ランドスケープで穴を作成する位置を探します。 + + ![](Landscape_MountainNoCave.png)(w:640) + +1. ブラシ サイズを調節します。 + + ![](Landscape_MountainCaveMask.png)(w:640) + +1. **左クリック** で穴を作成、**Shift + 左クリック** で作成した穴を消去します。 + + ![](Landscape_MountainHole.png)(w:640) + + あとは、ランドスケープの穴にスタティック メッシュ アクタをフィットさせれば洞窟の完成です。 + + [REGION:note] + Play In Editor (PIE) を使用して新規の穴のコリジョンをテストするために、**Landscape** モードから **Place** モードに切り替える必要のある場合があります。 + [/REGION] + +## ツール設定 + +![Visibility Tool](Landscape_Visibility.png)(h:75) + +Visibility のみを調整するツール設定はありません。Landscape Hole マテリアルを正しく設定し (上記参照)、 +マスクされた領域でペイントを調節して描画します。 + +**Landscape Hole マテリアル** がランドスケープに割り当てられていないと、**Target Layers** の下の [Vibility tool] パネルに以下の警告が表示されます。 + +![](VisibilityToolWarning.png)(w:400) + + + + + + + + + + + + + + + + + diff --git a/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Visibility/Visibility.KOR.udn b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Visibility/Visibility.KOR.udn new file mode 100644 index 000000000000..40581e34df02 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Landscape/Editing/SculptMode/Visibility/Visibility.KOR.udn @@ -0,0 +1,131 @@ +INTSourceChangelist:0 +Availability: Public +Crumbs: %ROOT% +Title: Visibility +Description: This is an overview of the Visibility painting tool. +Type: Reference +Version:4.16 +Parent:Engine/Landscape/Editing/SculptMode +Order:9 +Tags:Landscape +Topic-image:Visibility_topic.png + +[TOC(start:2 end:2)] + +The **Visibility** tool enables you to mask out (create holes) in parts of your Landscape, for areas such as caves. + +## Using the Visibility Tool + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + IU5RneVZzL0 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 44 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +In this example, the Visibility tool is used with a Landscape Material that has been setup to use a Landscape Visibility Mask. This enables parts of the Landscape to be painted invisible or +visible so that you can add in caves with additional Static Mesh Actors. This demonstration shows painting the invisibility and then repainting the visibility. + +Use the following controls to paint masked or to unmask areas of visibility for your Landscape: + +| **Controls** | **Operation** | +| --- | --- | +| **Left-Click** | Adds the visibility mask, making the Landscape invisible. | +| **Shift + Left-click** | Removes the visibility mask, making the Landscape components visible again. | + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before](Visibility1.png)(w:750) + [/PARAM] + [PARAM:after] + ![After](Visibility2.png)(w:750) + [/PARAM] +[/OBJECT] + +In this example, the Landscape Hole Material has been used to paint invisible (or masked out) areas for the Landscape. When painting masked out areas, you only get an on or off +state, so there is no way to have a transitional gradient from fully masked to unmasked. + + +### Using Opacity Mask to Create a Hole + +[EXCERPT:LandscapeHole] +Although you can use the sculpting tools to create a vertical holes in your Landscape, you may find that you also want to create horizontal ones, such as ones for caves. You can +do so by using opacity masking to "paint" away the visibility of a section of your Landscape with the Visibility tool. +[/EXCERPT:LandscapeHole] + +In order to paint away the visibility of a section of your Landscape, you must set up the Landscape Material correctly using a Landscape Hole Material. +For information about setting this up properly, you can read about [Landscape Hole Materials](Engine/Landscape/Materials/#LandscapeHoleMaterials) here. + +[REGION:note] +If you use the Visibility tool without having a Landscape Hole Material assigned, the Visibility tool will remove the Material layers applied to the selected sections, +but will not create a hole in the Landscape itself. +[/REGION] + +After you have set up your Landscape Hole Material, you can use the painting tools to create a hole in your Landscape. + +**To create a Landscape hole:** + +1. Make sure you have a **Landscape Hole Material** assigned to your Landscape. + + ![](LSHole_Details.png) + +1. In the Landscape tool, in **Sculpt** mode, select the **Visibility** tool. + + ![Visibility Tool](SelectVisibilityTool.png) + +1. Find the location on your Landscape where you want to create a hole. + + ![](Landscape_MountainNoCave.png)(w:640) + +1. Adjust the brush size to the size you want to use. + + ![](Landscape_MountainCaveMask.png)(w:640) + +1. **Left-click** to create the hole and **Shift + Left-click** to erase a hole that was created. + + ![](Landscape_MountainHole.png)(w:640) + + You can now fit Static Mesh Actors in the hole in the Landscape to create a cave. + + [REGION:note] + To test out the collision of the new hole using Play In Editor (PIE), you may have to switch from **Landscape** mode to **Place** mode. + [/REGION] + +## Tool Settings + +![Visibility Tool](Landscape_Visibility.png)(h:75) + +There are no tool settings specific to Visibility that can be adjusted in this section. Follow the steps to setup a proper Landscape Hole Material (detailed above) and use the paint to controls +to draw in your masked areas. + +If you do not have a **Landscape Hole Material** assigned to your Landscape, you will see the following warning in Visibility tool panel under **Target Layers**: + +![](VisibilityToolWarning.png)(w:400) + + + + + + + + + + + + + + + + + diff --git a/Engine/Documentation/Source/Engine/Landscape/Landscape.INT.udn b/Engine/Documentation/Source/Engine/Landscape/Landscape.INT.udn index db7a8ab5f2cc..e049a131da26 100644 --- a/Engine/Documentation/Source/Engine/Landscape/Landscape.INT.udn +++ b/Engine/Documentation/Source/Engine/Landscape/Landscape.INT.udn @@ -5,46 +5,7 @@ Description:Landscape system for creating terrain for large, open, outdoor envir version: 4.9 parent:Engine order:10 - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Landscape:title%](Engine/Landscape/landscape_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/landscape_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Landscape:title% - [/PARAM] - [PARAM:description] - %Engine/Landscape:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Landscape] - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Landscape:title%](Engine/Landscape/landscape_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/landscape_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Landscape:title% - [/PARAM] - [PARAM:description] - %Engine/Landscape:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Landscape] - [/PARAM] -[/OBJECT] -[/VAR] +topic-image:landscape_topic.png [REGION:banner] ![Landscape](landscape_landing_banner.png) @@ -52,7 +13,7 @@ order:10 [EXCERPT:landscape002] -[DIR(output:"topiccompact" parent:"Engine/Landscape")] +[DIR(output:"topiccompact" parent:"Engine/Landscape" org:"hierarchy" end:"1")] [/EXCERPT:landscape002] diff --git a/Engine/Documentation/Source/Engine/Landscape/Landscape.JPN.udn b/Engine/Documentation/Source/Engine/Landscape/Landscape.JPN.udn index 8793fe02e6ed..5dae76954653 100644 --- a/Engine/Documentation/Source/Engine/Landscape/Landscape.JPN.udn +++ b/Engine/Documentation/Source/Engine/Landscape/Landscape.JPN.udn @@ -1,11 +1,11 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3260884 Availability:Public Title:ランドスケープの屋外テレイン Crumbs:%ROOT%, Engine Description:広大で開放的なアウトドア環境を作成するテレインシステム version:4.9 parent:Engine -order:8 +order:10 [VAR:Topic] [OBJECT:Topic] diff --git a/Engine/Documentation/Source/Engine/Landscape/Landscape.KOR.udn b/Engine/Documentation/Source/Engine/Landscape/Landscape.KOR.udn index 49f4682991a3..33f9268373e4 100644 --- a/Engine/Documentation/Source/Engine/Landscape/Landscape.KOR.udn +++ b/Engine/Documentation/Source/Engine/Landscape/Landscape.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3260884 +INTSourceChangelist:3429242 Availability: Public Title:랜드스케이프 야외 지형 Crumbs:%ROOT%, Engine @@ -6,46 +6,7 @@ Description:Landscape, 랜드스케이프는 드넓은 개방형 야외 환경 version: 4.9 parent:Engine order:10 - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Landscape:title%](Engine/Landscape/landscape_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/landscape_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Landscape:title% - [/PARAM] - [PARAM:description] - %Engine/Landscape:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Landscape] - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Landscape:title%](Engine/Landscape/landscape_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/landscape_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Landscape:title% - [/PARAM] - [PARAM:description] - %Engine/Landscape:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Landscape] - [/PARAM] -[/OBJECT] -[/VAR] +topic-image:landscape_topic.png [REGION:banner] ![Landscape](landscape_landing_banner.png) @@ -53,7 +14,7 @@ order:10 [EXCERPT:landscape002] -[DIR(output:"topiccompact" parent:"Engine/Landscape")] +[DIR(output:"topiccompact" parent:"Engine/Landscape" org:"hierarchy" end:"1")] [/EXCERPT:landscape002] diff --git a/Engine/Documentation/Source/Engine/Landscape/Materials/Materials.JPN.udn b/Engine/Documentation/Source/Engine/Landscape/Materials/Materials.JPN.udn index d85266364350..84181c7c49e7 100644 --- a/Engine/Documentation/Source/Engine/Landscape/Materials/Materials.JPN.udn +++ b/Engine/Documentation/Source/Engine/Landscape/Materials/Materials.JPN.udn @@ -1,5 +1,4 @@ -INTSourceChangelist:3106713 -Availability:Public +Availability:Public Title:ランドスケープ マテリアル Crumbs: %ROOT%, Engine, Engine/Landscape Description:ランドスケープ テレインで作業するためのマテリアルを設定 @@ -24,7 +23,7 @@ topic-image:landscape_materials_topic.png マテリアル エディタの中に、ランドスケープ システムで使える 6 つの特別なノードがあると思います。これらのノードはすべて **コンテキスト** メニューまたは Landscape カテゴリの **[Palette (パレット)]** メニューにあります。 -**コンテキストメニュー** +** コンテキスト メニュー** ![Material Editor Context Menu](Landscape_Mat_Context.png) @@ -50,7 +49,7 @@ topic-image:landscape_materials_topic.png |番号| プロパティ | 説明 | |------------| -------- | ----------- | |1:| **Layers** | ノードに含まれるレイヤーのリストです。プラス アイコン (![Plus Sign](icon_Landscape_PlusSign.png)) をクリックすればレイヤーを追加できます。 | -|2:| **Layer Name** | レイヤーにつけるユニークな名前です。**Layer Name (レイヤー名)** はランドスケープの [Paint モード](Engine\Landscape\Editing\PaintMode\#Layer(レイヤー)) で使用されるレイヤー名に対応します。| +|2:| **Layer Name** | レイヤーにつけるユニークな名前です。**Layer Name (レイヤー名)** はランドスケープの [Paint モード](Engine\Landscape\Editing\PaintMode\#レイヤー) で使用されるレイヤー名に対応します。| |3:| **Blend Type (ブレンドタイプ)** | **LB_AlphaBlend**** 、 **LB_HeightBlend** 、または **LB_WeightBlend.** です。これについては、後ほどこのページで説明します。| |4:| **Preview Weight** | マテリアル エディタ内でブレンドをプレビューするための、レイヤーのウェイト値として使用されます。| |5:| **Const Layer Input** | テクスチャを使用したくない場合、数値をカラーで提供します。問題がある場合、レイヤーのデバッグのために主に使われます。| @@ -192,7 +191,7 @@ LandscapeVisibilityMask ノードのプロパティは、 **[Details (詳細)]** **[Parameter Name (パラメータ名)]** に入力すると、ノード自体が更新されます。
![](Landscape_Layer_Weight_Named_Layer.png) -1. マテリアルに入れたい各レイヤーに 1 つずつ付くまで **LandscapeLayerWeight** ノードを追加していきます。この例では、**LandscapeLayerWeight** ノードを 2 つ使っていきます。 +1. マテリアルに入れたい各レイヤーに 1 つずつ付くまで **LandscapeLayerWeight** ノードを追加していきます。この例では、 **LandscapeLayerWeight** ノードを 2 つ使っていきます。 1. **Texture Samples** または他のマテリアル ネットワーク表現式を **LandscapeLayerWeight** ノードに追加して接続します。 @@ -218,13 +217,13 @@ LandscapeVisibilityMask ノードのプロパティは、 **[Details (詳細)]** **LandscapeLayerBlend ノードの使用方法:** 1. マテリアル エディタで LandscapeLayerBlend を追加します。 - ![](Landscape_LayerBlend_Material_Example_00.png) -1. **[Details (詳細)]** パネルで、 **Layers** の隣のプラス アイコン ![Plus Sign](Shared/Icons/icon_PlusSymbol_12x.png) をクリックしてレイヤーを追加します。 +1. **[Details (詳細)]** パネルで、 **Layers** の隣のプラス アイコン ![Plus Sign](Shared/Icons/icon_PlusSymbol_12x.png) をクリックしてレイヤーを追加します。 ![](Landscape_LayerBlend_Material_Example_01.png) + 1. レイヤーを展開してプロパティを表示します。 ![Layer Properties](Landscape_Mat_LayerBlendDetails.png) diff --git a/Engine/Documentation/Source/Engine/Landscape/UI/InterfaceReference.INT.udn b/Engine/Documentation/Source/Engine/Landscape/UI/InterfaceReference.INT.udn index 45c03d610cc7..d9b4d612c25c 100644 --- a/Engine/Documentation/Source/Engine/Landscape/UI/InterfaceReference.INT.udn +++ b/Engine/Documentation/Source/Engine/Landscape/UI/InterfaceReference.INT.udn @@ -145,6 +145,10 @@ This document contains references to all of the icons for the **Landscape** syst ![](Engine/Landscape\icon_Landscape_Tool_Copy_40x.png)(convert:false) | **Copy/Paste** | Copy and Paste allows you to copy terrain data from one area of the Landscape and paste it to another area of the Landscape. You can even save out the copy paste data to use in other Landscapes. | [/VAR] +[VAR:MirrorTool] +![](Engine/Landscape\icon_Mirror_Tool_40x.png)(convert:false) | **Mirror Tool** | This tool enables you to copy one side of a landscape to the other side so that you can easily mirror or rotate the landscape geometry. | +[/VAR] + [VAR:NewLand] ![](Engine/Landscape\icon_Landscape_New_Landscape_40x.png)(convert:false) | **New Landscape** | Creates a new Landscape using the parameters in the New Landscape category. | [/VAR] @@ -208,6 +212,7 @@ This document contains references to all of the icons for the **Landscape** syst %Ind% %VisTool% %Ind% %SelectTool% %Ind% %CopyTool% +%Ind% %MirrorTool% [/REGION] [/EXCERPT:LSREF002] diff --git a/Engine/Documentation/Source/Engine/Landscape/UI/InterfaceReference.KOR.udn b/Engine/Documentation/Source/Engine/Landscape/UI/InterfaceReference.KOR.udn index 7cdb50890ecd..59d4198b653a 100644 --- a/Engine/Documentation/Source/Engine/Landscape/UI/InterfaceReference.KOR.udn +++ b/Engine/Documentation/Source/Engine/Landscape/UI/InterfaceReference.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3473556 Availability: Public Title:랜드스케이프 UI 참고서 Crumbs:%ROOT%, Engine, Engine/Landscape @@ -146,6 +146,10 @@ order:4 ![](Engine/Landscape\icon_Landscape_Tool_Copy_40x.png)(convert:false) | **Copy/Paste** | 복사/붙여넣기 - 랜드스케이프 한 영역에서 터레인 데이터를 복사하여 다른 영역에 붙여넣을 수 있습니다. 복사/붙여넣기 데이터를 다른 랜드스케이프에서 사용할 수 있도록 저장하는 것도 가능합니다. | [/VAR] +[VAR:MirrorTool] +![](Engine/Landscape\icon_Mirror_Tool_40x.png)(convert:false) | **Mirror Tool** | 미러 툴 - 랜드스케이프 한 쪽 면을 다른 쪽으로 복사하여 랜드스케이프 지오메트리를 쉽게 미러링 또는 회전시킬 수 있도록 해주는 툴입니다. | +[/VAR] + [VAR:NewLand] ![](Engine/Landscape\icon_Landscape_New_Landscape_40x.png)(convert:false) | **New Landscape** | 새 랜드스케이프 - New Landscape (새 랜드스케이프) 카테고리의 파라미터를 사용하여 랜드스케이프를 새로 만듭니다. | [/VAR] @@ -209,6 +213,7 @@ order:4 %Ind% %VisTool% %Ind% %SelectTool% %Ind% %CopyTool% +%Ind% %MirrorTool% [/REGION] [/EXCERPT:LSREF002] diff --git a/Engine/Documentation/Source/Engine/LevelStreaming/StreamingVolumes/StreamingVolumes.INT.udn b/Engine/Documentation/Source/Engine/LevelStreaming/StreamingVolumes/StreamingVolumes.INT.udn index d951d5d8900f..ff0ee88d6a1d 100644 --- a/Engine/Documentation/Source/Engine/LevelStreaming/StreamingVolumes/StreamingVolumes.INT.udn +++ b/Engine/Documentation/Source/Engine/LevelStreaming/StreamingVolumes/StreamingVolumes.INT.udn @@ -12,6 +12,19 @@ tags:Level Streaming [INCLUDE:Engine/Actors/Volumes#lsv] +You can adjust how a Level Streaming Volume handles level streaming by adjusting the properties from the **Details** panel, pictured below. + +![](levelstreamingvolume.png) + +For more on Level Streaming Volumes, see [](Engine/LevelStreaming/StreamingVolumes). + +|Property| Description | +| ------- | ------------ | +| **Streaming Levels** | Displays the levels affected by the volume. | +| **Editor Pre Vis Only** | Determines if the streaming volume should only be used for editor streaming level previs. | +| **Disabled** | If true, the streaming volume is ignored by the streaming volume code.
Also used to either disable a Level Streaming Volume without disassociating it from the level, or to toggle the control of a level's streaming between Blueprints and Volume Streaming. | +| **Streaming Usage** | Determines what the volume is used for, e.g. whether to control loading, loading and visibility, or just visibility (blocking on load). | + ## Associating Streaming Volumes With Levels Volume-based level streaming works as follows: each streaming Level can have associated with it a set of Level Streaming Volumes. Each frame, the engine iterates over diff --git a/Engine/Documentation/Source/Engine/LevelStreaming/StreamingVolumes/StreamingVolumes.JPN.udn b/Engine/Documentation/Source/Engine/LevelStreaming/StreamingVolumes/StreamingVolumes.JPN.udn index f7bcc13a13a2..025d04fd0d1b 100644 --- a/Engine/Documentation/Source/Engine/LevelStreaming/StreamingVolumes/StreamingVolumes.JPN.udn +++ b/Engine/Documentation/Source/Engine/LevelStreaming/StreamingVolumes/StreamingVolumes.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3379420 Availability:Public Title:レベル ストリーミング ボリューム Crumbs: @@ -13,6 +13,19 @@ tags:Level Streaming [INCLUDE:Engine/Actors/Volumes#lsv] +以下の画像のように、**[Details (詳細)]** パネルからプロパティを調整すれば、Level Streaming Volume のレベル ストリーミング処理方法を調整できます。 + +![](levelstreamingvolume.png) + +Level Streaming Volumes については [](Engine/LevelStreaming/StreamingVolumes) を参照してください。 + +| プロパティ | 説明 | +| ------- | ------------ | +| **Streaming Levels** | ボリュームの影響を受けるレベルを表示します。 | +| **Editor Pre Vis Only** | ストリーミング ボリュームをエディタ ストリーミング レベルのプレビズ用にのみ使用するかを判断します。 | +| **Disabled** | true の場合、ストリーミング ボリュームはストリーミング ボリューム コードで無視されます。
レベルから切り離さないで Level Streaming Volume を無効化するか、または Blueprints と Volume Streaming 間でのレベルのストリーミングの切り替えのためにも使用されます。| +| **Streaming Usage** | ボリュームを何に使うのか、ロードの制御、ロードと可視性または可視性のみなのか (ロード時にブロック) などを判断します。 | + ## Streaming Volume とレベルの関連づけ ボリューム ベースのレベル ストリーミングは、以下のように使用します。各ストリーミング レベルは Level Streaming Volume と関連づけることができます。フレームごとに、エンジンは各レベルをイタレートし、 diff --git a/Engine/Documentation/Source/Engine/LevelStreaming/StreamingVolumes/StreamingVolumes.KOR.udn b/Engine/Documentation/Source/Engine/LevelStreaming/StreamingVolumes/StreamingVolumes.KOR.udn index c9c750fe788d..884bc0b96ee8 100644 --- a/Engine/Documentation/Source/Engine/LevelStreaming/StreamingVolumes/StreamingVolumes.KOR.udn +++ b/Engine/Documentation/Source/Engine/LevelStreaming/StreamingVolumes/StreamingVolumes.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3379420 Availability: Public Title:레벨 스트리밍 볼륨 Crumbs: @@ -13,6 +13,19 @@ tags:Level Streaming [INCLUDE:Engine/Actors/Volumes#lsv] +아래 그림처럼 **디테일** 패널에서 프로퍼티를 조절하여 Level Streaming Volume (레벨 스트리밍 볼륨)의 레벨 스트리밍 처리 방식을 조절할 수 있습니다. + +![](levelstreamingvolume.png) + +레벨 스트리밍 볼륨 관련 자세한 내용은 [](Engine/LevelStreaming/StreamingVolumes) 문서를 참고하세요. + +| 프로퍼티 | 설명 | +| ------- | ------------ | +| **Streaming Levels** | 스트리밍 레벨 - 볼륨에 영향받는 레벨을 표시합니다. | +| **Editor Pre Vis Only** | 에디터 미리보기 전용 - 스트리밍 볼륨이 에디터 스트리밍 레벨 미리보기 전용인지 나타냅니다. | +| **Disabled** | 비활성화 - true 면 이 스트리밍 볼륨은 스트리밍 볼륨 코드에서 무시됩니다.
레벨 스트리밍 볼륨을 레벨에서 연결 해제하지 않고 비활성화시키거나, 레벨의 스트리밍 제어를 블루프린트 / 볼륨 스트리밍 토글 전환할 때도 사용됩니다. | +| **Streaming Usage** | 스트리밍 용도 - 볼륨을 어디에 사용하는지 결정합니다. 예: 로드 제어, 로드 및 표시여부, 표시여부만 (로드시 블록). | + ## 스트리밍 볼륨에 레벨 연결 볼륨 기반 레벨 스트리밍 작동방식은 다음과 같습니다: 각 스트리밍 레벨은 일정한 세트의 레벨 스트리밍 볼륨을 연결할 수 있습니다. diff --git a/Engine/Documentation/Source/Engine/Levels/HowTo/WorkWithLevelAssets/WorkWithLevelAssets.INT.udn b/Engine/Documentation/Source/Engine/Levels/HowTo/WorkWithLevelAssets/WorkWithLevelAssets.INT.udn index ffaf5e4759b1..d6eaa6c0ec0e 100644 --- a/Engine/Documentation/Source/Engine/Levels/HowTo/WorkWithLevelAssets/WorkWithLevelAssets.INT.udn +++ b/Engine/Documentation/Source/Engine/Levels/HowTo/WorkWithLevelAssets/WorkWithLevelAssets.INT.udn @@ -59,18 +59,96 @@ like Blueprint Classes, Materials, or Particle Systems. However, because Levels 1. Open the **File** menu. - ![](Level_File_New_Level.jpg) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](FileMenu_Windows.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](FileMenu_Mac.png) + [/PARAM] + [/OBJECT] 1. Select **New Level**. - ![](Level_Create_New_Level.jpg) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](NewLevel_Windows.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](NewLevel_Mac.png) + [/PARAM] + [/OBJECT] [Region:tip] You can also create new levels by using the keyboard shortcut **Ctrl + N**. [/region] When **New Level** is selected, you will be presented with a pop-up box displaying the different templates you can base your new Level on. - ![](NewLevel.png) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](NewLevelWindow_Windows.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](NewLevelWindow_Mac.png) + [/PARAM] + [/OBJECT] * **Default:** This will give you a new level with a basic setup that includes a player start, a light, a sky dome, and other various Actors you need for a level to work correctly. * **VR-Basic:** This will give you a new level with Actors to interact with designed to guide you in learning the VR Editor controls. @@ -99,16 +177,94 @@ You can also save your current persistent level and/or sublevels through the [Le 1. Open the **File** menu. - ![](Level_File_New_Level.png) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](FileMenu_Windows.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](FileMenu_Mac.png) + [/PARAM] + [/OBJECT] 1. Select **Save**. - ![](Level_Save_Level.jpg) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](SaveLevel_Windows.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](SaveLevel_Mac.png) + [/PARAM] + [/OBJECT] 1. Pick a location and name for the new Level and click **Save** in the **Save Level As** window that appears. This is the same menu you would see if you selected **Save As...** from the file menu or used the **Ctrl+Shift+S** keyboard shortcut. - ![](SaveLevelAs.png) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](SaveAs_Windows.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](SaveAs_Mac.png) + [/PARAM] + [/OBJECT] @@ -118,11 +274,63 @@ You can open Levels by double-clicking on the Level asset in the **Content Brows 1. Open the **File** menu. - ![](Level_File_New_Level.png) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](FileMenu_Windows.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](FileMenu_Mac.png) + [/PARAM] + [/OBJECT] 1. Select **Open Level**. - ![](Level_Open_New_Level.jpg) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](OpenLevel_Windows.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](OpenLevel_Mac.png) + [/PARAM] + [/OBJECT] [Region:tip] You can also open levels by using the keyboard shortcut **Ctrl + O**. @@ -130,7 +338,33 @@ You can open Levels by double-clicking on the Level asset in the **Content Brows 1. Select a level from the **Open Level** window that appears, then click on **Open**. - ![](AvailableLevels.png) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](OpenLevelMenu_Windows.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](OpenLevelMenu_Mac.png) + [/PARAM] + [/OBJECT] diff --git a/Engine/Documentation/Source/Engine/Levels/HowTo/WorkWithLevelAssets/WorkWithLevelAssets.KOR.udn b/Engine/Documentation/Source/Engine/Levels/HowTo/WorkWithLevelAssets/WorkWithLevelAssets.KOR.udn index 6d0bf05752d4..70611b58d605 100644 --- a/Engine/Documentation/Source/Engine/Levels/HowTo/WorkWithLevelAssets/WorkWithLevelAssets.KOR.udn +++ b/Engine/Documentation/Source/Engine/Levels/HowTo/WorkWithLevelAssets/WorkWithLevelAssets.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3150518 +INTSourceChangelist:3481084 Availability: Public Title:레벨 애셋 작업 Crumbs: %ROOT%, Engine @@ -60,18 +60,96 @@ order:1 1. **파일** 메뉴를 엽니다. - ![](Level_File_New_Level.jpg) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](FileMenu_Windows.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](FileMenu_Mac.png) + [/PARAM] + [/OBJECT] 1. **새 레벨** 을 선택합니다. - ![](Level_Create_New_Level.jpg) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](NewLevel_Windows.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](NewLevel_Mac.png) + [/PARAM] + [/OBJECT] [Region:tip] 키보드 단축키 **Ctrl + N** 으로도 새로운 레벨을 만들 수 있습니다. [/region] **새 레벨** 을 선택하면 뜨는 창에서 여러가지 템플릿 중 어느 것을 기반으로 새로운 레벨을 만들 것인지 선택할 수 있습니다. - ![](NewLevel.png) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](NewLevelWindow_Windows.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](NewLevelWindow_Mac.png) + [/PARAM] + [/OBJECT] * **Default** (기본): 플레이어 스타트, 라이트, 스카이 돔, 그 외 레벨의 정상 작동을 위해 필요한 여러가지 액터가 들어있는 기본 구성 레벨을 새로 만들 수 있습니다. * **VR-Basic** (VR-기본): VR 에디터 조작법 학습용 액터가 들어있는 새 레벨입니다. @@ -100,16 +178,94 @@ order:1 1. **파일** 메뉴를 엽니다. - ![](Level_File_New_Level.png) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](FileMenu_Windows.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](FileMenu_Mac.png) + [/PARAM] + [/OBJECT] 1. **저장** 을 선택합니다. - ![](Level_Save_Level.jpg) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](SaveLevel_Windows.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](SaveLevel_Mac.png) + [/PARAM] + [/OBJECT] 1. **다른 이름으로 저장** 창에서 새 레벨을 저장할 위치와 이름을 선택한 뒤 **저장** 을 클릭합니다. 파일 메뉴의 **다른 이름으로 저장...** 또는 키보드 단축키 **Ctrl+Shift+S** 키를 누르면 뜨는 것과 같은 메뉴입니다. - ![](SaveLevelAs.png) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](SaveAs_Windows.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](SaveAs_Mac.png) + [/PARAM] + [/OBJECT] @@ -119,11 +275,63 @@ order:1 1. **파일** 메뉴를 엽니다. - ![](Level_File_New_Level.png) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](FileMenu_Windows.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](FileMenu_Mac.png) + [/PARAM] + [/OBJECT] 1. **레벨 열기** 를 선택합니다. - ![](Level_Open_New_Level.jpg) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](OpenLevel_Windows.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](OpenLevel_Mac.png) + [/PARAM] + [/OBJECT] [Region:tip] 키보드 단축키 **Ctrl + O** 로도 레벨을 열 수 있습니다. @@ -131,7 +339,34 @@ order:1 1. 뜨는 **레벨 열기** 창에서 레벨을 선택한 뒤, **열기** 를 클릭합니다. - ![](AvailableLevels.png) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](OpenLevelMenu_Windows.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](OpenLevelMenu_Mac.png) + [/PARAM] + [/OBJECT] + diff --git a/Engine/Documentation/Source/Engine/Levels/LevelsWindow/LevelsWindow.INT.udn b/Engine/Documentation/Source/Engine/Levels/LevelsWindow/LevelsWindow.INT.udn index 45eb6ab97b0e..0db246fc4f71 100644 --- a/Engine/Documentation/Source/Engine/Levels/LevelsWindow/LevelsWindow.INT.udn +++ b/Engine/Documentation/Source/Engine/Levels/LevelsWindow/LevelsWindow.INT.udn @@ -50,7 +50,33 @@ order:2 Levels are managed with the **Levels** window. You can access the **Levels** window through the **Windows** menu. -![](WindowLevels.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](w:500)(LevelsMenu_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](w:500)(LevelsMenu_Mac.png) +[/PARAM] +[/OBJECT] You will always have a **Persistent Level**, and you can have one or more sublevels that are always loaded or are streamed in with Level Streaming Volumes, Blueprints, or C++ code. The **Levels** window shows all of these levels, enabling you to change which level is current (indicated in bold blue text), save one or more levels, and access Level Blueprints. @@ -84,7 +110,33 @@ Adding a new sublevel makes it the current Level, so if you want to continue wor 1. Select your Level to add in the **Open Level** dialog, then click on **Open**. - ![](SunTempleStreaming_Select.png) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](AddExisting_Windows.png)(w:700) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](AddExisting_Mac.png)(w:700) + [/PARAM] + [/OBJECT] ### Creating an Empty Sublevel @@ -94,7 +146,33 @@ Adding a new sublevel makes it the current Level, so if you want to continue wor 1. Select a save location and a name for your Level, then click on **Save**. - ![](Engine/Levels/HowTo/WorkWithLevelAssets/SaveLevelAs.png)(w:400) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](SaveAs_Windows.png)(w:700) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](SaveAs_Mac.png)(w:700) + [/PARAM] + [/OBJECT] The new Level will be added as a sublevel of your current persistent Level, and it will also be made the current Level for working in the Viewport. @@ -111,7 +189,33 @@ from the original. 1. Select a save location and a name for your Level, then click on **Save**. - ![](Engine/Levels/HowTo/WorkWithLevelAssets/SaveLevelAs.png)(w:500) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](SaveAs_Windows.png)(w:700) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](SaveAs_Mac.png)(w:700) + [/PARAM] + [/OBJECT] All your selected Actors will be removed from their original Level and added to the new one, which will be added as a sublevel of your current persistent Level and made the current Level for working in the Viewport. @@ -142,12 +246,64 @@ To set Level Streaming Volumes, you need to open the **Level Details** for your No additional details are visible for persistent Levels, although there is a dropdown menu you can use to change to another Level. -![](LevelDetails_Persistent.png)(w:500) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](LevelDetailsPersistent_Windows.png)(w:700) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](LevelDetailsPersistent_Mac.png)(w:700) +[/PARAM] +[/OBJECT] For sublevels, you can set the Level's offset **Position** and **Rotation**, as well as the **Streaming Volumes** to use and the debug **Level Color**. Advanced settings like the [minimum time between unload requests](Engine/LevelStreaming/StreamingVolumes#addinghysteresistounloadingrequests) to improve performance are also accessible here. -![](LevelDetails_Streaming.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](LevelDetailsStreaming_Windows.png)(w:700) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](LevelDetailsStreaming_Mac.png)(w:700) +[/PARAM] +[/OBJECT] ## Visualizing Sublevels diff --git a/Engine/Documentation/Source/Engine/Levels/LevelsWindow/LevelsWindow.KOR.udn b/Engine/Documentation/Source/Engine/Levels/LevelsWindow/LevelsWindow.KOR.udn index beb0de876d72..f9d4bdca6129 100644 --- a/Engine/Documentation/Source/Engine/Levels/LevelsWindow/LevelsWindow.KOR.udn +++ b/Engine/Documentation/Source/Engine/Levels/LevelsWindow/LevelsWindow.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3481084 Availability: Public Title:다수의 레벨 관리 Description:레벨 창으로 퍼시스턴트 레벨과 서브 레벨을 관리하는 법입니다. @@ -51,7 +51,33 @@ order:2 레벨은 **레벨** 창을 통해 관리합니다. **레벨** 창은 **창** 메뉴를 통해 열 수 있습니다. -![](WindowLevels.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](w:500)(LevelsMenu_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](w:500)(LevelsMenu_Mac.png) +[/PARAM] +[/OBJECT] 항상 하나의 **Persistent Level** (지속 레벨, 퍼시스턴트 레벨)이 있으며, 항상 로드되거나 레벨 스트리밍 볼륨, 블루프린트, C++ 코드를 통해 스트림 인 가능한 서브 레벨 하나 이상으로 구성됩니다. **레벨** 창에는 이 레벨이 전부 표시되어, (두꺼운 파랑 글씨로 표시된) 현재 레벨 설정을 변경하거나, 하나 이상의 레벨을 저장하거나, 레벨 블루프린트에 접근할 수 있습니다. @@ -85,7 +111,33 @@ order:2 1. **레벨 열기** 대화창에서 추가할 레벨을 선택한 뒤, **열기** 를 클릭합니다. - ![](SunTempleStreaming_Select.png) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](AddExisting_Windows.png)(w:700) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](AddExisting_Mac.png)(w:700) + [/PARAM] + [/OBJECT] ### 공백 서브레벨 생성 @@ -95,7 +147,33 @@ order:2 1. 레벨의 저장 위치와 이름을 선택한 뒤, **저장** 을 클릭합니다. - ![](Engine/Levels/HowTo/WorkWithLevelAssets/SaveLevelAs.png)(w:400) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](SaveAs_Windows.png)(w:700) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](SaveAs_Mac.png)(w:700) + [/PARAM] + [/OBJECT] 새로운 레벨이 현재 퍼시스턴트 레벨의 서브레벨로 추가되며, 뷰포트에 현재 작업 레벨로도 설정됩니다. @@ -112,7 +190,33 @@ order:2 1. 레벨의 저장 위치와 이름을 선택한 뒤, **저장** 을 클릭합니다. - ![](Engine/Levels/HowTo/WorkWithLevelAssets/SaveLevelAs.png)(w:500) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](SaveAs_Windows.png)(w:700) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](SaveAs_Mac.png)(w:700) + [/PARAM] + [/OBJECT] 선택된 액터 전부 원본 레벨에서 제거되어 새로운 레벨에 추가되며, 해당 레벨은 현재 퍼시스턴트 레벨의 서브레벨로 추가됨과 동시에 뷰포트 현재 작업 레벨로 설정됩니다. @@ -143,11 +247,63 @@ order:2 퍼시스턴트 레벨에 대해 추가적인 세부 정보가 보이지 않으나, 드롭다운 메뉴를 통해 다른 레벨로 변경할 수 있습니다. -![](LevelDetails_Persistent.png)(w:500) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](LevelDetailsPersistent_Windows.png)(w:700) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](LevelDetailsPersistent_Mac.png)(w:700) +[/PARAM] +[/OBJECT] 서브레벨의 경우, 레벨의 오프셋 **위치** 및 **회전** 과 아울러 사용할 **스트리밍 볼륨** 을 설정하고 **레벨 컬러** 디버깅을 할 수 있습니다. [언로드 재요청 최소 간격](Engine/LevelStreaming/StreamingVolumes) 처럼 퍼포먼스 향상을 위한 고급 세팅 역시 여기서 접근 가능합니다. -![](LevelDetails_Streaming.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](LevelDetailsStreaming_Windows.png)(w:700) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](LevelDetailsStreaming_Mac.png)(w:700) +[/PARAM] +[/OBJECT] ## 서브레벨 시각화 @@ -161,3 +317,4 @@ order:2 **게임 모드** 로 껐다켰다 할 수 있습니다. ![](LevelColorOn.png) + diff --git a/Engine/Documentation/Source/Engine/Matinee/UI/MatineeInterface.JPN.udn b/Engine/Documentation/Source/Engine/Matinee/UI/MatineeInterface.JPN.udn index 5fee2cf91298..a019e75faae5 100644 --- a/Engine/Documentation/Source/Engine/Matinee/UI/MatineeInterface.JPN.udn +++ b/Engine/Documentation/Source/Engine/Matinee/UI/MatineeInterface.JPN.udn @@ -1,8 +1,7 @@ -INTSourceChangelist:3108692 -Availability:Public +Availability:Public Title:マチネ エディタのリファレンス Crumbs:%ROOT%, Engine, Engine/Matinee -Description:マチネのユーザーインターフェース (UI) の説明 +Description:マチネのユーザー インターフェースの説明 Version:4.9 SkillLevel:Beginner diff --git a/Engine/Documentation/Source/Engine/Matinee/UI/MatineeInterface.KOR.udn b/Engine/Documentation/Source/Engine/Matinee/UI/MatineeInterface.KOR.udn index 4a349d3cb70d..061f2d5b979b 100644 --- a/Engine/Documentation/Source/Engine/Matinee/UI/MatineeInterface.KOR.udn +++ b/Engine/Documentation/Source/Engine/Matinee/UI/MatineeInterface.KOR.udn @@ -60,8 +60,8 @@ SkillLevel: Beginner | **섹션 지우기** | 루프 섹션에 포함된 시퀀스 부분을 지웁니다. | | **섹션 내 선택** | 루프 섹션 내에 포함된 키를 전부 선택합니다. | | **키 감소** | 현재 선택된 트랙에 있는 키의 양을 줄입니다. 외부 어플로 편집해서 바라는 애니메이션에 필요치 않은 중복 키가 약간 있을 수 있는 트랙에 좋을 수 있습니다. 상세 내용은 [키 감소](Engine/Matinee\UserGuide#키감소) 부분을 참고하십시오. | -| **패쓰 빌드 위치로 저장** | 패쓰 빌드시 사용할 이동 액터의 위치와 현재 시간을 저장합니다. | -| **패쓰 빌드 위치로 점프** | 저장된 패쓰 빌드 위치로 시간 커서를 이동시킵니다. | +| **패스 빌드 위치로 저장** | 패스 빌드시 사용할 이동 액터의 위치와 현재 시간을 저장합니다. | +| **패스 빌드 위치로 점프** | 저장된 패스 빌드 위치로 시간 커서를 이동시킵니다. | | **에디터 개인설정** | 언리얼 에디터의 작동방식과 기능에 대한 환경설정이 가능합니다. 언리얼 에디터의 **편집** 메뉴에 있는 **에디터 개인설정** 옵션과 같은 옵션이 제공됩니다. | | **프로젝트 세팅** | 현재 프로젝트에 대한 세팅을 변경할 수 있습니다. 언리얼 에디터의 **편집** 메뉴에 있는 **프로젝트 세팅** 과 같은 옵션이 제공됩니다. | diff --git a/Engine/Documentation/Source/Engine/MediaFramework/HowTo/MediaPlaylists/UsingMediaPlaylists.JPN.udn b/Engine/Documentation/Source/Engine/MediaFramework/HowTo/MediaPlaylists/UsingMediaPlaylists.JPN.udn index 4727bc23b0bf..c90f2af8952a 100644 --- a/Engine/Documentation/Source/Engine/MediaFramework/HowTo/MediaPlaylists/UsingMediaPlaylists.JPN.udn +++ b/Engine/Documentation/Source/Engine/MediaFramework/HowTo/MediaPlaylists/UsingMediaPlaylists.JPN.udn @@ -1,101 +1,19 @@ -INTSourceChangeList:3108692 +INTSourceChangelist:3336096 Availability:Public Title:Media Playlists の使用方法 Crumbs:%ROOT%, Engine Description:複数の Media Source アセットを再生するための Media Playlist の使い方の例 -Version:4.13 +Version:4.15 SkillLevel:Intermediate parent:Engine/MediaFramework order:3 checkpoint: editorqs Related:Engine\MediaFramework -一連のビデオを特定の順番で再生したい、または特定のビデオシリーズのビデオにプレイヤーのアクセスを許可したい場合は、 +アンリアル エンジンでメディア アセットで作業している時に、一連のビデオを特定の順番で再生したい、または特定のビデオシリーズのビデオにプレイヤーのアクセスを許可するには、 予め定義した順序が割り当てられた **Media Source** アセットを示す **Media Playlist** アセットを使って行います。 -この操作ガイドでは、Media Playlist の作成およびプレイヤーに各アセットを順番に再生、もしくはキーを押して、プレイリスト内の特定のアセットにプレイヤーがアクセスできるようにします。 - -[REGION:note] -ここでは **Starter Content Enabled (スターター コンテンツを有効にした状態)** で **Blueprint Third Person Template** プロジェクトを使います。 -再生するプレイリストを追加するコンピュータ上に [サポートされているビデオ ファイル](Engine\MediaFramework\TechReference) がいくつか必要です。お持ちのビデオを使用するか、あるいは **右クリック** して [ビデオ サンプル 1](Infiltrator Demo.mp4) および [ビデオ サンプル 2](SampleVideo.mp4) をダウンロードします。 -[/REGION] - - -## ステップ - -1. **[コンテンツ ブラウザ]** の **[Sources Panel]** を展開したら、**[Content]** に **「Movies」** という名前のフォルダを新規作成します。 - - ![](Playlist_00.png) - -1. **「Movies」** フォルダを **右クリック** して **[Show in Explorer (エクスプローラーで表示)]** を選択して、そのフォルダnビデオを置きます。プロジェクトの **「Content/Movies」** フォルダにビデオファイルを置くと、ビデオが確実に正しくパックされます。 - - ![](Playlist_01.png) - -1. **File Media Source** アセットを 2 つ作成し (名前は **Video_01** と **Video_02**) **ファイル パス** をそれぞれのビデオに指定します。 - - ![](Playlist_02.png) - -1. **MyPlaylist** という名前の **Media Playlist** アセットをコンテンツ ブラウザ内に作成します。 - - ![](Playlist_03.png) - -1. **MyPlaylist** でそれぞれの **File Media Source** を **ダブルクリック** してプレイリストに追加します。あるいは、**+** ボタンでも空のエレメントを追加して、ソース メディアの割り当てが可能です。この例では **File Media Source** アセットを使っていますが、**Stream Media Source** アセットもプレイリストに入れることができます。 - - ![](Playlist_04.png) - -1. **VideoPlayer** という名前の **Media Player** アセットを作成します。 - - ![](Playlist_05.png) - -1. **[Create Media Player(Media Player を作成)]** ウィンドウの **[Audio output SoundWave asset]** と **[Video output Media Texture asset]** にチェックを入れます。再生する必要のあるこの Media Player アセットにリンクしている Media Sound Wave と Media Texture アセットを自動的に作成します。 - - ![](Playlist_06.png) - - ![](Playlist_07.png) - -1. **[コンテンツ ブラウザ]** の **[StarterContent/Shapes]** で、**Shape_Plane** をレベルにドラッグします。 - - ![](Playlist_09.png) - -1. **Translate (W)**、**Rotation (E)**、**Scale (R)** ツールを使って、スタティックメッシュのサイズと位置を自由に調節します。 - -1. **[Ctrl]** を押しながら、**Sound Wave** アセットと **Media Texture** アセットを両方選択して、レベル内の **スタティックメッシュ** 上にリリースします。すると **マテリアル** が自動作成され、スタティックメッシュに適用されます。 - - ![](Playlist_10.png) - -1. メイン ツールバー で **[Blueprint]** ボタンをクリックして、**[Open Level Blueprint]** を選択します。 - - ![](Playlist_11.png) - -1. **「Media Player」** という名前の **Media Player Reference** タイプの **変数** を追加し、**VideoPlayer** Media Player アセットに設定します。**Default Value** を代入するには、その前に **コンパイル** する必要があります。 - - ![](Playlist_12.png) - -1. **イベントグラフ** 内を **ダブルクリック** して **1 Keyboard Event**、**2 Keyboard Event**、**3 Keyboard Event** を追加します。 - - ![](Playlist_13.png) - -1. **Ctrl** を押したまま **Media Player** 変数にドラッグしたら引き出して、**Open Playlist Index** を使い、**InPlaylist** を **[MyPlaylist]** に設定します。 - - ![](Playlist_14.png) - -1. **Index** が **1** に設定された **2 Keyboard Event** に **Open Playlist**を使い、**3 Keyboard Event** には **Open Playlist** を使います。 - - ![](Playlist_15.png) - -1. **Level ブループリント**を閉じて、**[Play]** ボタンをクリックしてレベルで再生します。 - - -## 最終結果 - -エディタでプレイする場合、ビデオ再生はレベルがロードされてもすぐには始まりません。プレイヤーが **1** キーを押すと、プレイリストで最初のビデオのプレイが始まります。 -**2** キーを押すと、プレイリストで 2 つ目のビデオの再生に飛びます。**3** を押すと、プレイリストの最初からビデオを開いてプレイします。それは index 0 のプレイリストを開くことと同じです。 - -**Media Player** アセットは **Play on Open** に設定されているので、open playlist 関数が呼び出されると各ビデオのプレイが始まる仕組みになっています。 -再生が急に始まらないように Media Source を開くには、Media Player アセット内の [Play on Open] オプションのチェックを外して、**Play** 関数を使って open Media Source アセットをプレイします。 - -**Next** 関数 (プレイリストの次のアイテムを選択) および **Previous** 関数 (プレイリストの前のアイテムを選択) を使って、開いているプレイリストを移動することができます。 -Media Player には有効にすると、次のソースが開かれる際にプレイリストからランダムにアイテムを選択する **Shuffle** というプロパティもあります。(Previous と Next のアイテムにも影響します)。 +この操作ガイドでは、以下の動画のように Media Playlist の作成およびプレイヤーに各アセットを再生、もしくはキーを押してプレイリスト内の特定のアセットにプレイヤーがアクセスできるようにします。 [OBJECT:EmbeddedVideo] [PARAMLITERAL:width] @@ -108,3 +26,114 @@ Media Player には有効にすると、次のソースが開かれる際にプ kjbgHVnQxBI [/PARAMLITERAL] [/OBJECT] + + +## ステップ + +[REGION:note] +ここでは **Starter Content Enabled (スターター コンテンツを有効にした状態)** で **Blueprint Third Person Template** プロジェクトを使います。 +再生するプレイリストを追加するコンピュータ上に [サポートされているビデオ ファイル](Engine\MediaFramework\TechReference) がいくつか必要です。 +お持ちのビデオを使用するか、あるいは **右クリック** して [ビデオ サンプル 1](Infiltrator Demo.mp4) および [ビデオ サンプル 2](SampleVideo.mp4) をダウンロードします。 +[/REGION] + +1. **[コンテンツ ブラウザ]** の **[Sources Panel]** を展開したら、**[Content]** に **「Movies」** という名前のフォルダを新規作成します。 + + ![](Playlist_00.png) + +1. **「Movies」** フォルダを **右クリック** して **[Show in Explorer (エクスプローラーで表示)]** を選択して、そのフォルダnビデオを置きます。 + + ![](Playlist_01.png) + + [REGION:note] + プロジェクトの **「Content/Movies」** フォルダにビデオファイルを置くと、ビデオが確実に正しくパックされます。 + [/REGION] + +1. **File Media Source** アセットを 2 つ作成し (名前は **Video_01** と **Video_02**) **ファイル パス** をそれぞれのビデオに指定します。 + + ![](Playlist_02.png) + +1. **MyPlaylist** という名前の **Media Playlist** アセットをコンテンツ ブラウザ内に作成します。 + + ![](Playlist_03.png) + +1. **MyPlaylist** でそれぞれの **File Media Source** を **ダブルクリック** してプレイリストに追加します。 + + ![](Playlist_04.png) + + あるいは、**+** ボタンでも空のエレメントを追加して、ソース メディアの割り当てが可能です。この例では **File Media Source** アセットを使っていますが、**Stream Media Source** アセットもプレイリストに入れることができます。 + +1. **VideoPlayer** という名前の **Media Player** アセットを作成します。 + + ![](Playlist_05.png) + +1. **[Create Media Player(Media Player を作成)]** ウィンドウの **[Audio output SoundWave asset]** と **[Video output Media Texture asset]** にチェックを入れます。 + + ![](Playlist_06.png) + + 再生する必要のあるこの Media Player アセットにリンクしている Media Sound Wave と Media Texture アセットを自動的に作成します。 + + ![](Playlist_07.png) + +1. **[コンテンツ ブラウザ]** の **[StarterContent/Shapes]** で、**Shape_Plane** をレベルにドラッグします。 + + ![](Playlist_09.png) + +1. **Translate (W)**、**Rotation (E)**、**Scale (R)** ツールを使って、スタティックメッシュのサイズと位置を自由に調節します。 + +1. **[Ctrl]** を押しながら、**Sound Wave** アセットと **Media Texture** アセットを両方選択して、レベル内の **スタティックメッシュ** 上にリリースします。 + + ![](Playlist_10.png) + + すると **マテリアル** が自動作成され、スタティックメッシュに適用されます。 + +1. メイン ツールバー で **[Blueprint]** ボタンをクリックして、**[Open Level Blueprint]** を選択します。 + + ![](Playlist_11.png) + +1. **「Media Player」** という名前の **Media Player Reference** タイプの **変数** を追加し、**VideoPlayer** Media Player アセットに設定します。 + + ![](Playlist_12.png) + + [REGION:note] + **Default Value** を代入する前に **コンパイル** する必要があります。 + [/REGION] + +1. **イベントグラフ** 内を **ダブルクリック** して **1 Keyboard Event**、**2 Keyboard Event**、**3 Keyboard Event** を追加します。 + + ![](Playlist_13.png) + +1. **Ctrl** を押したまま **Media Player** 変数にドラッグしたら引き出して、**Open Playlist Index** を使い、**InPlaylist** を **[MyPlaylist]** に設定します。 + + ![](Playlist_14.png) + +1. **Index** が **1** に設定された **2 Keyboard Event** に **Open Playlist** を使い、**3 Keyboard Event** には **Open Playlist** を使います。 + + ![](Playlist_15.png) + +1. **Level ブループリント**を閉じて、**[Play]** ボタンをクリックしてレベルで再生します。 + + +## 最終結果 + +[OBJECT:EmbeddedVideo] +[PARAMLITERAL:width] +640 +[/PARAMLITERAL] +[PARAMLITERAL:height] +360 +[/PARAMLITERAL] +[PARAMLITERAL:videoid] +kjbgHVnQxBI +[/PARAMLITERAL] +[/OBJECT] + + +エディタでプレイする場合、ビデオ再生はレベルがロードされてもすぐには始まりません。プレイヤーが **1** キーを押すと、プレイリストで最初のビデオのプレイが始まります。 +**2** キーを押すと、プレイリストで 2 つ目のビデオの再生に飛びます。**3** を押すと、プレイリストの最初からビデオを開いてプレイします。それは index 0 のプレイリストを開くことと同じです。 + +**Media Player** アセットは **Play on Open** に設定されているので、open playlist 関数が呼び出されると各ビデオのプレイが始まる仕組みになっています。 +再生が急に始まらないように Media Source を開くには、Media Player アセット内の [Play on Open] オプションのチェックを外して、**Play** 関数を使って open Media Source アセットをプレイします。 + +**Next** 関数 (プレイリストの次のアイテムを選択) および **Previous** 関数 (プレイリストの前のアイテムを選択) を使って、開いているプレイリストを移動することができます。 +Media Player には有効にすると、次のソースが開かれる際にプレイリストからランダムにアイテムを選択する **Shuffle** というプロパティもあります。(Previous と Next のアイテムにも影響します)。 + diff --git a/Engine/Documentation/Source/Engine/MediaFramework/TechReference/MF_TechRef.JPN.udn b/Engine/Documentation/Source/Engine/MediaFramework/TechReference/MF_TechRef.JPN.udn index 9a42972c5d0c..b6de1496e4e2 100644 --- a/Engine/Documentation/Source/Engine/MediaFramework/TechReference/MF_TechRef.JPN.udn +++ b/Engine/Documentation/Source/Engine/MediaFramework/TechReference/MF_TechRef.JPN.udn @@ -51,7 +51,7 @@ Windows Media Foundation (WMF) は Windows プラットフォーム上で標準 ただし、メディア ファイルのデコードと再生のために特定のコーデックを必要としないユーザーもいるという意味です。 これまで、アンリアル エンジンは、すべての人がメディアを同じように処理加工するように WMF についているデフォルトのコーデックのみをサポートしてきましたが、 -ゲームを出荷したいメディアやや専用のメディア エンコーダに異なるエンコード メソッドを使いたいことが多々あると思います (例えば、必要なエンコーダーを提供するインストーラーを付けてゲームを出荷する)。 +ゲームを出荷したいメディアや専用のメディア エンコーダに異なるエンコード メソッドを使いたいことが多々あると思います (例えば、必要なエンコーダーを提供するインストーラーを付けてゲームを出荷する)。 **[Project Settings (プロジェクト設定)]** の **[Plugins]** セクションから **WMF Media** 用に標準外のコーデックを有効にすることができます。 diff --git a/Engine/Documentation/Source/Engine/Paper2D/Paper2D.INT.udn b/Engine/Documentation/Source/Engine/Paper2D/Paper2D.INT.udn index 33c218dab5d6..80bd9f9ffc5a 100644 --- a/Engine/Documentation/Source/Engine/Paper2D/Paper2D.INT.udn +++ b/Engine/Documentation/Source/Engine/Paper2D/Paper2D.INT.udn @@ -3,39 +3,30 @@ Title: Paper 2D Crumbs: %ROOT%, Engine Description:Paper 2D is a sprite-based system for creating 2D and 2D/3D hybrid games entirely within Unreal Engine 4. Version: 4.9 +Parent:Engine +type:landing +order:21 +Topic-image:Paper2D_Topic.png [REGION:banner] ![](paper2d_banner.png) [/REGION] - + **Paper 2D** in Unreal Engine 4 (UE4) is a sprite-based system for creating 2D and 2D/3D hybrid games entirely within the editor. At the core of Paper 2D are **Sprites** (which are a Texture Mapped Planar Mesh and associated Material). You can edit Sprites inside UE4 with the **Sprite Editor** and create sprite-based animations with **Flipbooks** (which animate a series of Sprites sequentially by using key frames and specifying a duration in frames to display them). Refer to each section below for more information and the **Paper 2D** map inside the **Content Examples** project for additional examples: -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/project_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - Paper 2D topics - [/PARAM] - [PARAM:links] - * [](Engine/Paper2D/Sprites "%Engine/Paper2D/Sprites:description%") - * [](Engine/Paper2D/Sprites/Editor "%Engine/Paper2D/Sprites/Editor:description%") - * [](Engine/Paper2D/Sprites/RenderGeometry "%Engine/Paper2D/Sprites/RenderGeometry:description%") - * [](Engine\Paper2D\Sprites\Collision "%Engine\Paper2D\Sprites\Collision:description%") - * [](Engine\Paper2D\Flipbooks"%Engine\Paper2D\Flipbooks:description%") - * [](Engine/Paper2D/Flipbooks/Editor "%Engine/Paper2D/Flipbooks/Editor:description%") - * [](Engine\Paper2D\Flipbooks\Components "%Engine\Paper2D\Flipbooks\Components:description%") - * [](Engine\Paper2D\HowTo "%Engine\Paper2D\HowTo:description%") - * [](Engine\Paper2D\TileMaps"%Engine\Paper2D\TileMaps:description%") - * [](Engine\Paper2D\Importing"%Engine\Paper2D\Importing:description%") - * [](Resources/ContentExamples/Paper2D "%Resources/ContentExamples/Paper2D:description%") - * [Paper 2D Video Tutorials](https://docs.unrealengine.com/latest/INT/Videos/index.html?category=2D) - [/PARAM] -[/OBJECT] - - +## Starting Out + +[DIR(output:"topic" parent:"Engine/Paper2D" org:"hierarchy" path:"!Engine/Paper2D/HowTo")] + +## Guides + +[DIR(output:"fancy" parent:"Engine/Paper2D/HowTo" org:"hierarchy")] + +## Video Series + +[DIR(output:"playlist" type:"playlist" tags:"2D")] diff --git a/Engine/Documentation/Source/Engine/Paper2D/Paper2D.JPN.udn b/Engine/Documentation/Source/Engine/Paper2D/Paper2D.JPN.udn index 4812933b87f8..7e7926e06118 100644 --- a/Engine/Documentation/Source/Engine/Paper2D/Paper2D.JPN.udn +++ b/Engine/Documentation/Source/Engine/Paper2D/Paper2D.JPN.udn @@ -1,42 +1,33 @@ -INTSourceChangelist:2746166 +INTSourceChangelist:3467293 Availability:Public Title:Paper 2D Crumbs: %ROOT%, Engine Description:Paper 2D は 2D および 2D/3D のハイブリッドなゲームをアンリアル エンジン 4 で作成するためのスプライト ベースのシステムです。 Version:4.9 +Parent:Engine +type:landing +order:21 +Topic-image:Paper2D_Topic.png [REGION:banner] ![](paper2d_banner.png) [/REGION] - + アンリアル エンジン 4 (UE4) の **Paper 2D** は、2D および 2D/3D のハイブリッドなゲームを完全にエディタ内で作成するためのスプライト ベースのシステムです。Paper 2D の中心部は **スプライト** です (Texture Mapped Planar Mesh と関連するマテリアルになります)。**スプライト エディタ** を使って UE4 内でスプライトを編集し、 **Flipbooks** を使ってスプライト ベースのアニメーション (キーフレームを使って一連のスプライトを順番にアニメートし、フレーム単位で継続時間を指定してそれらを表示) を作成することが可能です。 詳細およびサンプルについては、 **コンテンツ サンプル** プロジェクトの **Paper 2D** マップを参照してください。 -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/project_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - Paper 2D topics - [/PARAM] - [PARAM:links] - * [](Engine/Paper2D/Sprites "%Engine/Paper2D/Sprites:description%") - * [](Engine/Paper2D/Sprites/Editor "%Engine/Paper2D/Sprites/Editor:description%") - * [](Engine/Paper2D/Sprites/RenderGeometry "%Engine/Paper2D/Sprites/RenderGeometry:description%") - * [](Engine\Paper2D\Sprites\Collision "%Engine\Paper2D\Sprites\Collision:description%") - * [](Engine\Paper2D\Flipbooks"%Engine\Paper2D\Flipbooks:description%") - * [](Engine/Paper2D/Flipbooks/Editor "%Engine/Paper2D/Flipbooks/Editor:description%") - * [](Engine\Paper2D\Flipbooks\Components "%Engine\Paper2D\Flipbooks\Components:description%") - * [](Engine\Paper2D\HowTo "%Engine\Paper2D\HowTo:description%") - * [](Engine\Paper2D\TileMaps"%Engine\Paper2D\TileMaps:description%") - * [](Engine\Paper2D\Importing"%Engine\Paper2D\Importing:description%") - * [](Resources/ContentExamples/Paper2D "%Resources/ContentExamples/Paper2D:description%") - * [Paper 2D 動画チュートリアル](https://docs.unrealengine.com/latest/INT/Videos/index.html?category=2D) - [/PARAM] -[/OBJECT] - - +## はじめよう + +[DIR(output:"topic" parent:"Engine/Paper2D" org:"hierarchy" path:"!Engine/Paper2D/HowTo")] + +## ガイド + +[DIR(output:"fancy" parent:"Engine/Paper2D/HowTo" org:"hierarchy")] + +## 動画チュートリアル + +[DIR(output:"playlist" type:"playlist" tags:"2D")] diff --git a/Engine/Documentation/Source/Engine/Paper2D/Paper2D.KOR.udn b/Engine/Documentation/Source/Engine/Paper2D/Paper2D.KOR.udn index a56fd0c7f2b5..6c074d3b1a31 100644 --- a/Engine/Documentation/Source/Engine/Paper2D/Paper2D.KOR.udn +++ b/Engine/Documentation/Source/Engine/Paper2D/Paper2D.KOR.udn @@ -1,42 +1,33 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3467293 Availability:Public Title: 페이퍼 2D Crumbs: %ROOT%, Engine Description:Paper 2D 는 언리얼 엔진 4 안에서만 2D 및 2D/3D 혼합 게임 제작용 스프라이트 기반 시스템입니다. Version: 4.9 +Parent:Engine +type:landing +order:21 +Topic-image:Paper2D_Topic.png [REGION:banner] ![](paper2d_banner.png) [/REGION] - + 언리얼 엔진 4 (UE4)의 **Paper 2D**, 페이퍼 2D 는 에디터 안에서만 2D 및 2D/3D 혼합 게임 제작용 스프라이트 기반 시스템입니다. 페이퍼 2D 의 핵심에는 (텍스처 매핑된 평면 메시에 머티리얼이 할당된) **스프라이트** 가 있습니다. **스프라이트 에디터** 로 UE4 안에서 스프라이트를 편집하고, (키 프레임을 사용하고, 프레임 단위로 표시 기간을 지정하여 스프라이트 시리즈에 순차적으로 애니메이션을 적용하는) **플립북** 으로 스프라이트 기반 애니메이션을 만들 수도 있습니다. 자세한 정보는 아래 각 부분을, 추가적인 예제는 **콘텐츠 예제** 프로젝트 안의 **페이퍼 2D** 맵을 참고하세요: -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/project_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - 페이퍼 2D 토픽 - [/PARAM] - [PARAM:links] - * [](Engine/Paper2D/Sprites "%Engine/Paper2D/Sprites:description%") - * [](Engine/Paper2D/Sprites/Editor "%Engine/Paper2D/Sprites/Editor:description%") - * [](Engine/Paper2D/Sprites/RenderGeometry "%Engine/Paper2D/Sprites/RenderGeometry:description%") - * [](Engine\Paper2D\Sprites\Collision "%Engine\Paper2D\Sprites\Collision:description%") - * [](Engine\Paper2D\Flipbooks"%Engine\Paper2D\Flipbooks:description%") - * [](Engine/Paper2D/Flipbooks/Editor "%Engine/Paper2D/Flipbooks/Editor:description%") - * [](Engine\Paper2D\Flipbooks\Components "%Engine\Paper2D\Flipbooks\Components:description%") - * [](Engine\Paper2D\HowTo "%Engine\Paper2D\HowTo:description%") - * [](Engine\Paper2D\TileMaps"%Engine\Paper2D\TileMaps:description%") - * [](Engine\Paper2D\Importing"%Engine\Paper2D\Importing:description%") - * [](Resources/ContentExamples/Paper2D "%Resources/ContentExamples/Paper2D:description%") - * [페이퍼 2D 비디오 튜토리얼](https://docs.unrealengine.com/latest/INT/Videos/index.html?category=2D) - [/PARAM] -[/OBJECT] - - +## 시작하기 + +[DIR(output:"topic" parent:"Engine/Paper2D" org:"hierarchy" path:"!Engine/Paper2D/HowTo")] + +## 안내서 + +[DIR(output:"fancy" parent:"Engine/Paper2D/HowTo" org:"hierarchy")] + +## 비디오 시리즈 + +[DIR(output:"playlist" type:"playlist" tags:"2D")] diff --git a/Engine/Documentation/Source/Engine/Performance/ForwardRenderer/ForwardRenderer.JPN.udn b/Engine/Documentation/Source/Engine/Performance/ForwardRenderer/ForwardRenderer.JPN.udn index 4ec38de18b68..a65df0312748 100644 --- a/Engine/Documentation/Source/Engine/Performance/ForwardRenderer/ForwardRenderer.JPN.udn +++ b/Engine/Documentation/Source/Engine/Performance/ForwardRenderer/ForwardRenderer.JPN.udn @@ -1,11 +1,11 @@ -INTSourceChangelist:3322543 +INTSourceChangelist:3372845 Availability:Public Title:VR でフォワード レンダリングを使用する Crumbs: Description:フォワード レンダリングを使用して VR パフォーマンスを高める方法 type: overview version:4.14 -Parent:Engine/Performance +parent:Engine/Performance tags:Performance and Profiling tags:Rendering tags:VR @@ -59,9 +59,9 @@ Multisample Anti-Aliasing (MSAA) を使用するには以下の操作を行い ![](EnableMSAA.png) フォワード レンダリングは、マルチサンプル アンチエイリアシング (MSAA) とテンポラル アンチエイリアシング (TAA) の両方をサポートしていますが、ジオメトリ エイリアシングとスペキュラ エイリアシングの両方を除去するため、ほとんどのケースで TAA が好まれます。 -ただし VR では、ヘッド トラッキングでサブピクセルが絶えず移動することで、不必要なぼやけが発生するので、MSAA を選ぶ方が正解かもしれません。 -MSAA を使用するプロジェクトでは、スペキュラ エイリアシングを軽減するためのコンテンツをビルドした方が良いかもしれません。 -さらに、**Normal to Roughness** 機能で詳細な法線マップからスペキュラ エイリアシングを削減し、スタティックメッシュ用の自動 LOD 生成機能により遠くのメッシュの形状を平坦にして、小さなトライアングルからのエイリアシングを削減できます。 +ただし VR では、ヘッド トラッキングでサブピクセルが絶えず移動するため不必要なぼやけが発生するので、MSAA が正しい選択かもしれません。 +MSAA を使用するプロジェクトでは、スペキュラ エイリアシングを軽減するためのコンテンツのビルドをお勧めします。 +さらに、**Normal to Roughness** 機能を使うと、詳細な法線マップからスペキュラ エイリアシングを削減し、スタティックメッシュ用の自動 LOD 生成機能により遠くのメッシュの形状を平坦にして、小さなトライアングルからのエイリアシングを削減できます。 我々のテスト結果では、TAA の代わりに MSAA を使った場合、GPU フレームが約 25% 増加しました (値はコンテンツによって変わります)。 @@ -77,16 +77,16 @@ MSAA を使用するプロジェクトでは、スペキュラ エイリアシ [/OBJECT] [REGION:note] -コンソール変数 `r.MSAACount` を使って、ピクセルごとに計算する MSAA サンプル数を調節できます。 -`r.MSAACount 1` を代入すると Temporal AA を使用する設定に戻ります。アンチエイリアシング メソッドとの切り替えが簡単になります。 +コンソール変数 `r.MSAACount` を使って、ピクセルごとに計算する MSAA サンプル数を調節し、`r.MSAACount 1` で MSAA を無効にできます。 +`r.MSAACount 0` を代入すると Temporal AA を使用する設定に戻ります。アンチエイリアシング メソッドとの切り替えが簡単になります。 [/REGION] ## パフォーマンスと機能 -ディファード レンダラからフォワード レンダラへ切り替により、プロジェクトのパフォーマンスが改善させる場合があります。 +ディファード レンダラからフォワード レンダラへ切り替により、プロジェクトのパフォーマンスが改善する場合があります。 -コンテンツによっては、ディファード レンダリングよりもフォワードレンダリングの方が速い場合があります。ほとんどのパフォーマンスは、マテリアルごとに無効化できる機能によって改善されます。 -デフォルトでは、マテリアルが高品質の反射を選択していない限り、最も近い反射キャプチャのみがパララックスなしで適用され、Height Fog (高さフォグ) は頂点ごとに計算され、それを有効にするマテリアルのみに Planar Reflection が適用されます。 +コンテンツによっては、ディファード レンダリングよりもフォワード レンダリングの方が速い場合があります。ほとんどのパフォーマンスは、マテリアルごとに機能を無効にすると改善します。 +マテリアルが高品質の反射を選択していない限り、最も近い反射キャプチャのみがデフォルトでパララックスなしで適用されます。また、Height Fog (高さフォグ) は頂点ごとに計算され、それを有効にするマテリアルのみに Planar Reflection が適用されます。 ![](ForwardShading.png) @@ -94,7 +94,7 @@ MSAA を使用するプロジェクトでは、スペキュラ エイリアシ ![](ExampleImage.png) -フォワード レンダラは、ライトと反射キャプチャを視界外のスペースグリッドへカリングを行うことで処理します。その後で、フォワード パスの各ピクセルがライトと反射キャプチャをイタレートし、影響を与えてマテリアルを共有します。 +フォワード レンダラは、ライトと反射キャプチャを視界外のスペースグリッドへのカリング処理で行われます。その後で、フォワード パスの各ピクセルが影響を与えているライトと反射キャプチャをイタレートして、マテリアルを共有します。 Stationary light (固定ライト) の動的シャドウは予め計算されて、スクリーン空間シャドウ マスクのチャンネルにパックされ、オーバーラップする 4 つの Stationary light (固定ライト) 限界部分を強化します。 ディファード レンダラからフォワード レンダラへ切り替えた時には、アンリアル エンジンの [](Engine/Performance) ツールを使ってゲームのパフォーマンスを必ず評価してください。 @@ -138,7 +138,7 @@ Stationary light (固定ライト) の動的シャドウは予め計算されて * Atmospheric Fog では MSAA をまだ正しく処理しません。 * Height Fog の場合、Vertex Fogging を使えばこの問題を回避できます (フォワード シェーディングを有効にするとデフォルトで有効になります)。 * つまり、Forward BasePass で計算されてから正しくアンチエイリアシングを行います。 - * Atmosphere は解決したシーン深度の Deferred Pass でまだ計算されるので、正しいアンチエイリアシングが行えません (今後のアップデートで解決したいと思っています)。 + * Atmosphere の計算には、分解処理されたシーン深度の Deferred Pass がまだ使われるので、正しいアンチエイリアシングが行えません (今後のアップデートで解決したいと思っています)。 diff --git a/Engine/Documentation/Source/Engine/Performance/ForwardRenderer/ForwardRenderer.KOR.udn b/Engine/Documentation/Source/Engine/Performance/ForwardRenderer/ForwardRenderer.KOR.udn index 0a7d29ce632d..ce685cfc6d9a 100644 --- a/Engine/Documentation/Source/Engine/Performance/ForwardRenderer/ForwardRenderer.KOR.udn +++ b/Engine/Documentation/Source/Engine/Performance/ForwardRenderer/ForwardRenderer.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3322543 +INTSourceChangelist:3372845 Availability:Public Title: VR 용 포워드 셰이딩 렌더러 Crumbs: @@ -77,8 +77,8 @@ MSAA 를 사용하는 프로젝트는 MSAA 를 사용하여 콘텐츠를 만들 [/OBJECT] [REGION:note] -`r.MSAACount` 콘솔 변수를 사용하여 모든 픽셀마다 MSAA 샘플을 몇이나 계산할지 조절할 수 있습니다. -`r.MSAACount 1` 은 템포럴 AA 를 사용하도록 하므로, 안티앨리어싱 메소드를 편하게 전환할 수 있습니다. +`r.MSAACount` 콘솔 변수를 사용하여 모든 픽셀마다 MSAA 샘플을 몇이나 계산할지 조절할 수 있습니다. `r.MSAACount 1` 는 MSAA 를 끕니다. +`r.MSAACount 0` 은 템포럴 AA 를 사용하도록 하므로, 안티앨리어싱 메소드를 편하게 전환할 수 있습니다. [/REGION] ## 퍼포먼스 및 기능 diff --git a/Engine/Documentation/Source/Engine/Performance/PerformanceProfiling.JPN.udn b/Engine/Documentation/Source/Engine/Performance/PerformanceProfiling.JPN.udn index 19a139644daa..5a27b328b941 100644 --- a/Engine/Documentation/Source/Engine/Performance/PerformanceProfiling.JPN.udn +++ b/Engine/Documentation/Source/Engine/Performance/PerformanceProfiling.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:2956400 +INTSourceChangelist:3178047 Availability:Public Title:パフォーマンスおよびプロファイリング Crumbs: %ROOT%, Engine @@ -6,7 +6,8 @@ Description:パフォーマンス問題の特定および修正方法 Navigation:topic version:4.9 parent:Engine -order:13 +order:17 +tags:Performance and Profiling [VAR:Topic] [OBJECT:Topic] diff --git a/Engine/Documentation/Source/Engine/Performance/Profiler/Profiler.KOR.udn b/Engine/Documentation/Source/Engine/Performance/Profiler/Profiler.KOR.udn index b7ff750821ba..ad83b5005300 100644 --- a/Engine/Documentation/Source/Engine/Performance/Profiler/Profiler.KOR.udn +++ b/Engine/Documentation/Source/Engine/Performance/Profiler/Profiler.KOR.udn @@ -182,7 +182,7 @@ _**오디오** 에 대한 윗 그림에서, 그룹에 11 항목이 있으며, | ![](EG_Icon_HistoryBack.png) | 액션 히스토리 뒤로 버튼입니다.| | ![](EG_Icon_HistoryForward.png) | 액션 히스토리 앞으로 버튼입니다. | | ![](EG_Icon_HistoryMenu.png) | 액션 히스토리 메뉴를 표시합니다. | -| ![](EG_Icon_HotPath.png) | 포함 시간에 따라 선택된 이벤트에 대한 핫 패쓰(hot path)를 펼쳐, 포함 시간 내림차순으로 소팅합니다 (퍼포먼스가 가장 비싼 경로입니다). | +| ![](EG_Icon_HotPath.png) | 포함 시간에 따라 선택된 이벤트에 대한 핫 패스(hot path)를 펼쳐, 포함 시간 내림차순으로 소팅합니다 (퍼포먼스가 가장 비싼 경로입니다). | ### 함수 디테일 **함수 디테일** 에는 사용자가 선택한 함수/이벤트와 선택된 함수/이벤트를 실행하는 함수 호출 사이의 관계를 표시합니다. 이러한 관계는 백분율 값에 맞도록 스케일 적용된 버튼을 사용하여 표시됩니다. @@ -225,7 +225,7 @@ _**오디오** 에 대한 윗 그림에서, 그룹에 11 항목이 있으며, | ![](EG_Menu_Icon_CollapseSelection.png)(w:28) | **선택 접음** - 선택된 이벤트와 자손을 접습니다. | | ![](EG_Menu_Icon_ExpandThread.png)(w:28) | **스레드 펼침** - 선택된 스레드와 자손을 펼칩니다. | | ![](EG_Menu_Icon_CollapseThread.png)(w:28) | **스레드 접음** - 선택된 스레드와 자손을 접습니다. | -| ![](EG_Menu_Icon_ExpandHotPath.png)(w:28) | **핫 패쓰 펼침** - 선택된 이벤트에 대해, 포함 시간을 기반으로 한 핫 패쓰를 펼치고, 포함 시간 내림차순을 적용합니다 (가장 퍼포먼스가 비싼 경로입니다). | +| ![](EG_Menu_Icon_ExpandHotPath.png)(w:28) | **핫 패스 펼침** - 선택된 이벤트에 대해, 포함 시간을 기반으로 한 핫 패스를 펼치고, 포함 시간 내림차순을 적용합니다 (가장 퍼포먼스가 비싼 경로입니다). | | ![](EG_Menu_Icon_HierarchicalView.png)(w:28) | **계층 뷰로 표시** - 계층 뷰로 전환하고 선택된 이벤트를 펼칩니다. | | ![](EG_Menu_Icon_FlatInclusiveView.png)(w:28) | **일반 포함 뷰로 표시** - 일반 포함 뷰로 전환하고 포함 시간 내림차순을 적용합니다. | | ![](EG_Menu_Icon_FlatInclusiveView2.png)(w:28) | **일반 포함 합침으로 표시** - 일반 합침 뷰로 전환하고 포함 시간 내림차순을 적용합니다. | diff --git a/Engine/Documentation/Source/Engine/Performance/ReducingPackageSize/ReducingPackageSize.INT.udn b/Engine/Documentation/Source/Engine/Performance/ReducingPackageSize/ReducingPackageSize.INT.udn index ddc0a11c9fbb..a2696eb3c86d 100644 --- a/Engine/Documentation/Source/Engine/Performance/ReducingPackageSize/ReducingPackageSize.INT.udn +++ b/Engine/Documentation/Source/Engine/Performance/ReducingPackageSize/ReducingPackageSize.INT.udn @@ -58,7 +58,33 @@ To turn on package compression, you need to do the following in the UE4 Editor. 1. First, open up the project's settings by going to the Main Toolbar and selecting the **Edit** option, then selecting **Project Settings**. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](T_Project_Settings_Menu.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](T_Project_Settings_Menu_Mac.png) + [/PARAM] + [/OBJECT] 1. Under the Project section, click on the **Packaging** section to show the options for how the project will be packaged. @@ -81,7 +107,33 @@ To set which level (or levels) should be used for this type of interaction, you 1. First, on the **Main Toolbar** go to **Edit** > **Project Settings**. - ![](T_Project_Settings.png) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](T_Project_Settings_Menu.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](T_Project_Settings_Menu_Mac.png) + [/PARAM] + [/OBJECT] 1. Then, under **Project** in the **Maps & Modes** section look for the **Default Maps** section. @@ -102,7 +154,33 @@ If you do not specify which maps should be cooked then all maps will be cooked i 1. First, open up the project's settings by going to the **Main Toolbar** and selecting **Edit** > **Project Settings**. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](T_Project_Settings_Menu.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](T_Project_Settings_Menu_Mac.png) + [/PARAM] + [/OBJECT] 1. Then, under **Project** in the **Packaging** section look for the **Packaging** option. @@ -149,13 +227,65 @@ You can find the Cooked folder by going to **(ProjectName)\Saved\Cooked** and th Please note that you will only be able to see the content in the **Cooked** folder after you complete your first cook. [/region] +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] ![](T_Cooked_Content_Folder.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](T_Cooked_Content_Folder_Mac.png) +[/PARAM] +[/OBJECT] The image below shows the Texture folder from the Match 3 sample game. The content in the folder has been sorted by size, so it is easier to see what assets are the biggest. Once the biggest assets have been determined, you can then examine the assets inside of UE4 to see if in fact they can be reduced in size without sacrificing the integrity of the asset. +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] ![](T_Cooked_Content.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](T_Cooked_Content_Mac.png) +[/PARAM] +[/OBJECT] ## Development VS Shipping Build Size When trying to figure out the final size your project will be, keep in mind that the Development version of your project will be slightly larger than your Shipping build size. @@ -175,7 +305,33 @@ When you do try and delete something from your project, the **Delete Assets** me This is the preferred method of deleting objects in UE4 and should be used over just simply deleting/removing the assets from their location in the content folder. [/region] -![](T_Delete_Menu.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](DeleteAssets_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](DeleteAssets_Mac.png) +[/PARAM] +[/OBJECT] The Delete Assets menu will inform you if the asset you are trying to delete is referenced by another asset. If it is not referenced, you can simply delete it, however if it is referenced by other assets, you can use the **Replace References** option to replace the reference to that asset to another asset that is supposed to be packaged in your project. @@ -193,7 +349,33 @@ To disable a plug-in inside of UE4, you need to do the following: 1. First, open up the Plug-ins Manager by going to the **Main Toolbar** and clicking on the **Window** option and then selecting the **Plug-in** option. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](T_Open_Plugins_Browser.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](T_Open_Plugins_Browser_Mac.png) + [/PARAM] + [/OBJECT] 1. From the Plug-in Browser, select the different sections and disable any plug-ins you are not using by un-checking the check mark box next to **Enabled**. When you have disabled all the plug-ins, you will need to re-start the UE4 Editor and then make sure to re-package your project. @@ -216,13 +398,65 @@ Projects can have multiple Black List files for Debug, Development, Test, and Sh You can even have different Black List files for each platform your project supports like one for Android, one for iOS, ect. Here is an example of what the Black List files would look like for Tappy Chicken on Android. +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] ![](T_Blacklist_Packages.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](T_Blacklist_Packages_Mac.png) +[/PARAM] +[/OBJECT] Here is an example from Tappy Chicken where the cooker is told to not include the following files when the game is cooked and packaged. * **Blacklist Text File Location & Name:** TappyChicken/Build/Android/**PakBlacklist-Shipping.txt**: + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](T_Black_List.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](T_Black_List_Mac.png) + [/PARAM] + [/OBJECT] The first three entries should be safe for any project, but there may be cases were the **AssetRegistry.bin** is needed at runtime (depending on your project). It is highly recommended that you thoroughly test to ensure that the content you are removing will not negatively impact your project. diff --git a/Engine/Documentation/Source/Engine/Performance/ReducingPackageSize/ReducingPackageSize.JPN.udn b/Engine/Documentation/Source/Engine/Performance/ReducingPackageSize/ReducingPackageSize.JPN.udn index 856387dafb1a..0685b7994f35 100644 --- a/Engine/Documentation/Source/Engine/Performance/ReducingPackageSize/ReducingPackageSize.JPN.udn +++ b/Engine/Documentation/Source/Engine/Performance/ReducingPackageSize/ReducingPackageSize.JPN.udn @@ -1,8 +1,8 @@ -INTSourceChangelist:3097732 +INTSourceChangelist:3108692 Availability:Public -Title:パッケージングしたゲームのサイズを減らす +Title:パッケージ化したゲームのサイズを小さくする方法 Crumbs: %ROOT%, Engine, Engine/Performance -Description:パッケージングしたゲームのサイズを減らす方法。 +Description:パッケージ化したゲームのサイズを小さくする Skilllevel:Intermediate Version:4.12 Related:Platforms/Android/ReducingAPKSize @@ -44,20 +44,20 @@ Parent:Engine/Performance [TOC(start:2 end:3)] -UE4 プロジェクトがどのタイププラットフォームをターゲットにしていても、パッケージングしたゲームのサイズを減らすことは難しいです。 -次のガイドでは、プロジェクトの最終版のパッケージのサイズを UE4 エディタに備わっているツール以外は使わずに、できる限り小さくするために役立つステップを説明します。 +UE4 プロジェクトの場合、ターゲットがどのプラットフォームであれ、パッケージ化したゲームのサイズを小さくすることは難しいです。 +本ぺーにでは、UE4 エディタに備わっているツール以外は使わずに、製品版プロジェクトの APK パッケージ サイズをできる限り小さくするために役立つステップを説明します。 [EXCERPT:main] -## 空のプロジェクトを新規作成する -初めて Android ベースのモバイル プロジェクトで作業する時に、作業するベースとして既存のプロジェクトを使ったり、Starter Content が入っているプロジェクトを新規作成したくなると思います。 -これは **やってはいけません**。そうではなくて、完全に新しく空の C++ あるいは ブループリント ベースのプロジェクトを作成し、[Migration Tool](Engine/Content/Browser/UserGuide/Migrate) を使って使用したいコンテンツを入れます。 -こうすることで、必要とするコンテンツのみをプロジェクトに入れることができます。 +## ブランクのプロジェクトを新規作成する +Android ベースのモバイル プロジェクトで初めて作業する時に、既存プロジェクトをベースに使ったり、Starter Content が入ったプロジェクトを新規作成したくなると思います。 +これを **しないでください**。そうではなく、完全に新しいブランクの C++ あるいは ブループリント ベースのプロジェクトを作成し、[Migration Tool](Engine/Content/Browser/UserGuide/Migrate) で使用するコンテンツのみを入れてください。 +この方法で、必要なコンテンツのみをプロジェクトに入れることができます。 ## クック済みのコンテンツを圧縮する -APK パッケージ サイズを簡単かつ素早く小さくする方法は、パック処理中に APK パッケージを圧縮するように UE4 に指示することです。 +APK パッケージ サイズを簡単かつ迅速に小さくする方法は、パッケージ化処理中に APK パッケージを圧縮するように UE4 に指示することです。 UE4 エディタで以下の操作をして、パッケージ圧縮を有効にします。 -1. まず、メインツールバーからプロジェクト設定を開いて、**[Edit (編集)]** オプション、次に **[Project Settings (プロジェクト設定)]** を選択します。 +1. まず、メインツール バーからプロジェクト設定を開いて、**[Edit (編集)]** オプション、次に **[Project Settings (プロジェクト設定)]** を選択します。 ![](T_Project_Settings_Menu.png) @@ -73,12 +73,12 @@ UE4 エディタで以下の操作をして、パッケージ圧縮を有効に ![](T_Enable_Comp_Packages.png) -[Create compressed cooked packages] にチェックを入れずにゲームをパッケージングすると、有効にして再度パッケージングした場合に比べて、遥かにサイズが大きいことが分かります。 -実際に **[Create compressed cooked packages]** を有効にすると、APK パッケージ サイズが 50% にまで減ることも珍しくはありません。 +[Create compressed cooked packages] にチェックを入れずにゲームをパッケージ化すると、有効にして再度パッケージ化した場合に比べて、遥かにサイズが大きくなります。 +実際に **[Create compressed cooked packages]** を有効にすると、APK サイズが 50% まで小さくなります。 ## プロジェクトのレベルを設定する -デフォルトでロードするレベルやレベル トランジションで使用するレベルなど、プロジェクト オプションの設定が適切でないことをうっかり見過ごすと APK パッケージ サイズが大きくなってしまいます。 -このタイプのインタラクションに使用するレベル (複数可) を設定は以下の手順で行います。 +デフォルトでロードするレベルやレベル トランジションで使用するレベルなど、不適切なプロジェクト オプション設定のままにしておくと APK パッケージ サイズが大きくなってしまいます。 +このタイプのインタラクションに使用するレベル (複数可) の設定は以下の手順で行います。 1. まず **メイン ツールバー** で **[Edit (編集)]** > **[Project Settings (プロジェクト設定)]** を選択します。 @@ -94,14 +94,14 @@ UE4 エディタで以下の操作をして、パッケージ圧縮を有効に 1. このプロセスを繰り返して、それぞれ必要なマップ タイプにレベルを設定します。 -## パッケージ対象とそうでないコンテンツの選択 -プロジェクト設定の [Packaging] セクションで、コンテンツをゲームにパッケージするかどうかの指定ができます。この操作を行うには、以下の手順に従います。 +## パッケージ化するコンテンツを指定する +プロジェクト設定の [Packaging] セクションで、ゲームにパッケージ化するコンテンツの指定ができます。この操作を行うには、以下の手順に従います。 [region:warning] -クック対象のマップを特に指定しないと、テスティング マップを含むすべてのマップがクックされます。クック対象のマップを指定し忘れると、パッケージ化したゲームは必要以上に大きくなってしまいます。 +クック対象のマップを特に指定しない場合、テスティング マップを含むすべてのマップがクックされます。つまり、クック対象のマップを指定し忘れると、パッケージ化したゲームは必要以上に大きくなってしまいます。 [/region] -1. まず、メインツールバーからプロジェクト設定を開いて、**[Edit (編集)]** > **[Project Settings (プロジェクト設定)]** を選択します。 +1. まず、メイン ツールバーからプロジェクト設定を開いて、**[Edit (編集)]** > **[Project Settings (プロジェクト設定)]** を選択します。 ![](T_Project_Settings_Menu.png) @@ -113,19 +113,19 @@ UE4 エディタで以下の操作をして、パッケージ圧縮を有効に ![](Advanced_Packing_Section.png) -1. [Advanced Packaging] オプションを **[Cook everything in the project content directory(ignore list of maps below)(プロジェクト コンテンツ ディレクト内をすべてクックする)]** のチェックボックスが見えるまで下方向にスクロールします。このオプションで、プロジェクトにパッケージするコンテンツとマップを指定できます。 +1. [Advanced Packaging] オプションを **[Cook everything in the project content directory(ignore list of maps below)(プロジェクト コンテンツ ディレクト内をすべてクックする)]** のチェックボックスが見えるまで下方向にスクロールします。このオプションで、プロジェクトにパッケージ化するコンテンツとマップを指定できます。 ![](Advanced_Packing_Options.png) -1. エントリを新規作成するために使いたいオプションの横の白いプラス記号をクリックして、アイテムを追加 / 削除します。 +1. エントリを新規作成するために使用するオプションの横の白いプラス記号をクリックして、アイテムを追加 / 削除します。 ![](Add_New_Item.png) -1. 新規作成されたエントリの横の小さな白い 3 つの点をクリックして表示されたウィンドウで、ビルドする / ビルドしないアセットを選択します。 +1. 新規作成されたエントリの横の小さな白い 3 つの点をクリックして表示されたウィンドウで、ビルドへアセットの追加 / 削除を選択します。 ![](Select_Items_To_Cook.png) -1. アセットを選択すると、エントリ ボックスにアセットが保存されているプロジェクトのフォルダへのリンクが含まれます。 +1. アセットを選択すると、エントリ ボックスにアセットが保存されているプロジェクトのフォルダへのリンクが挿入されます。 ![](Selected_Item_Location.png) @@ -133,13 +133,13 @@ UE4 エディタで以下の操作をして、パッケージ圧縮を有効に |--------------|------------| |Cook everything in the project content directory(ignore list of maps below.|プロジェクト コンテンツ ディレクトリ内のすべてをクックします。| |Cook only maps(this only affects cook all).|マップのみクックします (cookall フラグのみ影響します)。| -|Create compressed cooked packages.|圧縮してクックしてパッケージを作成します (デプロイ サイズが小さくなります)。| +|Create compressed cooked packages.|圧縮されたクック済みパッケージを作成します (デプロイ サイズが小さくなります)。| |Do not include editor content in this package may cause game to crash / error if you are using this content|エディタ コンテンツのクックをスキップします。| |List of maps to include in a packaged build|コマンドラインで何も他のマップリストが指定されていない場合にインクルードするマップのリストです。| -|Additional Asset Directories to Cook|プロジェクト内から参照されているかどうかにかからわずに .uasset ファイルを含むディレクトリです。注意:これらのパスはプロジェクトの Content ディレクトリに対応しています。| +|Additional Asset Directories to Cook|プロジェクト内から参照されているかどうかにかからわずに .uasset ファイルを含むディレクトリです。注記:これらのパスはプロジェクトの Content ディレクトリに対応しています。| |Directories to never cook|絶対にクックされないディレクトリです。| |Additional Non-Asset Directories to Package.|.pak ファイルに常に追加されるファイルを含むディレクトリです ( .pak ファイルを使わないと個々のファイルでコピーされます)。UFS (Unreal File System) file IO API 経由で手書きのコードでロードする追加ファイルをステージします。注意: これらのパスはプロジェクトの Content ディレクトリに対応しています。| -|Additional Non-Asset Directories to Copy.|プロジェクトをパッケージする際、必ずコピーされるファイルを含むディレクトリですが、.pak ファイルの一部とはみなされません。内部ファイル IO を実行するサードパーティ ライブラリなどの UFS (Unreal File System) file IO API 経由で手書きのコードによってロードした追加フィアルのステージに使います。注意:これらのパスはプロジェクトの Content ディレクトリに対応しています。 | +|Additional Non-Asset Directories to Copy.|プロジェクトのパッケージ化で、必ずコピーされるファイルを含むディレクトリですが、.pak ファイルの一部とはみなされません。内部ファイル IO を実行するサードパーティ ライブラリなどの UFS (Unreal File System) file IO API 経由で手書きのコードによってロードした追加ファイルのステージに使います。注意:これらのパスはプロジェクトの Content ディレクトリに対応しています。 | ## クックするコンテンツを確認する @@ -154,21 +154,21 @@ UE4 エディタで以下の操作をして、パッケージ圧縮を有効に 下の画像は Match 3 サンプル ゲームのテクスチャ フォルダです。 フォルダのコンテンツはサイズでソートされているので、最大のアセットがすぐに分かります。 -最大のアセットが決まったら、UE4 の中のそのアセットが実際アセットの統合性に影響を与えずにサイズの縮小が可能かどうかを検討します。 +最大のアセットが分かったら、UE4 内のアセットの統合性に影響を与えずに、そのアセットのサイズの縮小が可能かどうかを検討します。 ![](T_Cooked_Content.png) ## 開発 VS シッピング ビルド サイズ -最終的なサイズを計算する場合、プロジェクトの開発バージョンはシッピング ビルド サイズよりも若干大きくなることを念頭に置いておいてください。 -Medieval Match のサンプル ゲームでは、開発ビルドとシッピング ビルドのサイズの差は約 14 パーセント です。 -ただし、要求事項はプロジェクトによって異なるので、プロジェクトを異なる 2 つのビルド タイプで保存した場合の差は 14 パーセント以下にも以上にもなる場合があります。 +最終的なサイズを計算する場合、プロジェクトは開発バージョンの方がシッピング ビルド サイズよりも若干大きくなることを念頭に置いておいてください。 +Medieval Match のサンプル ゲームでは、開発ビルドとシッピング ビルドのサイズの差は約 14 パーセントです。 +ただし、プロジェクトによって要件は異なるので、開発ビルドとシッピング ビルドで保存されたプロジェクトのサイズの差は、14 パーセント以外になる可能性はあります。 -## デバイス別のテクスチャ LOD +## デバイス単位のテクスチャ LOD アンリアル エンジン 4.8 のリリースにより、デバイスごとに使用する LOD サイズを指定できるようになりました。 詳しい情報については、[モバイル プラットフォーム用のテクスチャ ガイドライン](Engine/Rendering/Materials/Editor/Interface) ページをご覧ください。 -##使用しないコンテンツを取り除く -ストア マーケット用にパッケージングする最終段階になったら、まず最初に使わないコンテンツあるいはテスティング コンテンツをコンテンツ ブラウザで選択して削除して取り除きます。 +## 使用しないコンテンツを取り除く +ストア用にパッケージ化する最終段階になったら、まず最初に使わないコンテンツあるいはテスティング コンテンツをコンテンツ ブラウザで選択して削除します。 削除したいコンテンツをまず選択したら、キーボードの **[Delete (削除)]** キーを押すか、右クリックメニューの [Delete (削除)] オプションを使用します。 プロジェクトから何かを削除した場合は、**[Delete Assets (アセットを削除)]** メニューが以下の画像のように表示されます。 @@ -178,18 +178,18 @@ Medieval Match のサンプル ゲームでは、開発ビルドとシッピン ![](T_Delete_Menu.png) -[Delete Assets (アセットを削除)] メニューには、削除対象のアセットが別のアセットから参照されているかを表示します。 -参照されていない場合はそのまま削除できますが、別のアセットが参照している場合は、**[Replace References (リファレンスを置き換える)]** オプションを使ってそのアセットへの参照を別のアセットへ置き換えることができます。 +[Delete Assets (アセットを削除)] メニューには、削除対象のアセットが他のアセットから参照されていることが伝えられます。 +参照されていない場合はそのまま削除できますが、他のアセットから参照されている場合は、**[Replace References (リファレンスを置き換える)]** オプションを使ってそのアセットへの参照を別のアセットへ置き換えることができます。 -##使用しないプラグインを取り除く -使用しないプラグインを無効にしておくのも、不必要なコンテンツとコードをプロジェクトの最終的な APK パッケージ ファイルの中に入らないようにする方法です。 +## 使用しないプラグインを取り除く +使用しないプラグインを無効にしておくと、プロジェクトの製品版 APK ファイルに不必要なコンテンツとコードが含まれなくなります。 プラグインの中には、基本アセットとコードの特定のセットが正しく機能しなければいけない場合があるためです。 -プラグインが無効にされていない場合、プラグインが動作するために必要なアセットとコードはプロジェクトから取り除かれます。 -この操作は、大きいテクスチャのサイズを縮小するほどの効果はありませんが、プロジェクトのサイズを 100 MB まで下げることができます。 +プラグインが無効にされていない場合、プラグインが動作するために必要なアセットとコードはプロジェクトに残ります。 +この操作は、大きいテクスチャ サイズを縮小できるほどの効果はありませんが、プロジェクト サイズを 100 MB まで下げることができます。 UE4 のプラグインを無効にするには、以下の操作を行います。 [region:note] - プロジェクト全体をテストして、無効にしたプラグインがプロジェクトの機能性を妨げないようにしてください。 + プロジェクト全体をテストして、無効にしたプラグインによってプロジェクトの機能性が損なわれないようにしてください。 [/region] 1. まず、プラグイン マネージャの **メイン ツールバー** から **[Window]** オプションをクリックして **[Plug-in]** オプションを選択します。 @@ -197,7 +197,7 @@ UE4 のプラグインを無効にするには、以下の操作を行います ![](T_Open_Plugins_Browser.png) 1. [Plug-in] ブラウザから異なるセクションを選択して、使用しないプラグイン横にある **[Enabled (有効にする)]** というボックスのチェックを外して無効にします。 - すべてのプラグインを無効にした場合は、UE4 エディタを再起動して、それからプロジェクトを再度パッケージングするようにしてください。 + すべてのプラグインを無効にするにあh、UE4 エディタを再起動して、それからプロジェクトを再度パッケージ化してください。 [OBJECT:EmbeddedVideo] [PARAMLITERAL:width] @@ -212,14 +212,14 @@ UE4 のプラグインを無効にするには、以下の操作を行います [/OBJECT] ## ブラックリストをパッケージングする -アンリアル エンジン 4.9 以降のバージョンでは、プロジェクト **Build/Platform/(Target Platform Folder)** ディレクトリの中にテキスト ファイルを置くことにより、ファイル パスを部分的または完全にプロジェクトにパッケージングしないようにクッカーに指示することができるようになりました。 -プロジェクトにはデバッグ、開発、シッピング ビルド用の Black List ファイルを複数置くことが可能なので、好きなプロジェクト データを含むことができます。 +アンリアル エンジン 4.9 以降では、プロジェクト **Build/Platform/(Target Platform Folder)** ディレクトリの中にテキスト ファイルを置くことにより、ファイル パスを部分的または完全にプロジェクトにパッケージ化しないようにクッカーに指示することができるようになりました。 +プロジェクトにはデバッグ、開発、シッピング ビルド用の Black List ファイルを複数置くことが可能なので、好きなプロジェクト データを入れることができます。 Android 用と iOS 用など、プロジェクトがサポートするプラットフォームに対して、異なるブラックリストを作ることも可能です。 Android の Tappy Chicken 用の Black List ファイルはこのような感じになります。 ![](T_Blacklist_Packages.png) -ゲームがクックおよびパッケージングされている場合、以下のファイルを含まないようにクッカーに指示する場合、Tappy Chicken はこのようになります。 +ゲームがクックおよびパッケージ化されている場合、以下のファイルを含まないようにクッカーに指示すると、Tappy Chicken はこのようになります。 * **Blacklist Text File Location & Name:** TappyChicken/Build/Android/**PakBlacklist-Shipping.txt**: @@ -227,7 +227,7 @@ Android の Tappy Chicken 用の Black List ファイルはこのような感じ 最初の 3 つのエントリはどのプロジェクトでも問題ありませんが、(プロジェクトによっては) ライタイム時に **AssetRegistry.bin** が必要になる場合があります。 削除中のコンテンツがプロジェクトに悪い影響を与えないことを確認するために、一通りテストしておくことを強くお勧めします。 -すべてのプロジェクト レベルを開いて、エラーや警告もなく正しくロードされていることを確認する方法が一番簡単で分かりやすいです。 +すべてのプロジェクト レベルを開いて、エラーや警告もなく正しくロードされていることを確認する方法が一番簡単かつ明確です。 それでも問題が生じ、原因が分からない場合は、Logcat でエラーを確認します。 ## Max Dynamic Point Lights @@ -237,14 +237,14 @@ UE 4.9 のリリースでは、動的ライト用に生成されたシェーダ ![](Max_Dyn_Point_Lights.png) -この機能を完全に無効にするためには **Max Dynamic Point Lights** を **4** から **0** に設定し、要求されたら UE4 エディタを再起動します。 +この機能を完全に無効にするためには **[Max Dynamic Point Lights]** を **「4」** から **「0」** に設定し、要求されたら UE4 エディタを再起動します。 ![](Max_Dyn_Point_Lights_To_0.png) -プロジェクトのサイズおよびマテリアルの使用数によって、保存可能容量は数 MB からその数倍にまで変化します。 +プロジェクト サイズおよび使用マテリアル数によって、保存可能容量は数 MB からその数倍にまで変動します。 例えばデフォルトの Third Person Template を使用すれば、Max Dynamic Point Lights を有効にした場合と完全に無効にした場合の保存容量を確認することができます。 -| ステート| パッケージングされたゲーム サイズ| 保存容量| +| ステート| パッケージ化されたゲーム サイズ| 保存容量| | ---------| ------| -----| |ON|54.3 MB|0| |OFF| 53.2 MB| 1.1 MB| diff --git a/Engine/Documentation/Source/Engine/Physics/Cloth/Overview/ClothOverview.CHN.udn b/Engine/Documentation/Source/Engine/Physics/Cloth/Overview/ClothOverview.CHN.udn new file mode 100644 index 000000000000..44d4ed69d9b9 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Cloth/Overview/ClothOverview.CHN.udn @@ -0,0 +1,190 @@ +INTSourceChangelist:0 +Availability:Public +Crumbs: +Title:Clothing Tool Overview +Description:An overview of Cloth creation using in-editor tools in Unreal Engine 4. +Type:Overview +SkillLevel:Intermediate +Version:4.16 +Parent:Engine/Physics +Order:1 +Tags:Cloth +Tags:Physics +reference-image:SectionSelection.gif +reference-image:PaintingCloth.gif +Topic-image:Clothing_Topic.png + + + +[REGION:warning] +This is an experimental feature and may change in later versions. In order to use this tool, you must first enable it in the Editor Preferences. You can do this by doing to the main menu > **Edit** > **Editor Preferences** > **Experimental** > and +enabling the checkbox next to **Clothing Tool**. +[/REGION] + +[TOC(start:2 end:2)] + +In Unreal Engine, version 4.16, APEX Cloth has now been replaced with the NVIDIA's NvCloth solver. This is a low-level clothing solver that is responsible for the particle simulation that runs +clothing. This clothing solver allows integrations to be lightweight and very extensible because we now have direct access to this data. Unlike APEX Clothing, which is a sophisticated SDK that +is a one-stop shop for clothing simulation that handles both the simulation and the render. + +![](OverviewImage.png)(w:900) + +With the Clothing Tools now available within the Editor, the workflow has been redefined to enable developers to work directly in Unreal Engine to author their content without the need for +external dependencies. + +[REGION:imagetable] +| [INCLUDE:#oldworkflow] | [INCLUDE:#newworkflow] | +| --- | --- | +| Old Cloth Workflow | New Cloth Workflow | +| [INCLUDE:#clickimage] | [INCLUDE:#clickimage] | +[/REGION] + +With the "Old" workflow using APEX Cloth, you were required to develop all your assets outside of Unreal using an external program (NVIDIA's Clothing Tool) or DCC Plugins that require specific +software (3DS Max/Maya) to author this content. Only during the final stage of development would you bring your authored content into Unreal and assign it to your mesh. This meant that if you had +to correct anything you would have to go back to your program and re-author the content outside of the Editor. + +The "New" workflow enables you to create your content once and then do all the creation editing of the clothing directly inside of Unreal. This makes the creation and iteration of testing content +that much quicker, and you also avoid any disconnects between where the content was created versus where it's being used by being able to see all of your edits for your clothing simulation +happening in real-time and as they will appear in your game. + + +## Creating a Cloth Section Asset + +To create a new Cloth asset, follow these steps. + +1. Click the **Section Selection** button in the main toolbar. This will enable you to select the different Material Elements of your Skeletal Mesh. + + [REGION:asyncgif] + ![](SectionSelection.gif)(w:500) + [/REGION] +1. With your section selected, you can right-click anywhere on the highlighted element to bring up the **Cloth Asset** options menu. + + ![](ClothAssetContextMenu.png)(w:450) + +1. Hover over **Create Cloth Asset from Selection** and then fill in the following areas. + + ![](CreateClothContextMenu.png)(w:350) + + * **Asset Name** - Give your asset a name so that you can easily find locate it later. + * **Remove from Mesh** - If you've got a separate mesh piece of geometry you want to be associated as cloth, you can enable this option. If not, you can leave this unchecked. + * **Physics Asset** - If this cloth asset is for a character, use its Physics Asset here to get proper collision for the cloth simulation. + +1. Once you've set the information from the previous step you can click the **Create** button. + + ![](CreateClothButton.png)(w:350) + +## Assigning a Cloth Section Asset + +To assign a Cloth asset to a section, follow these steps. + +1. With your section element selected, you can right-click anywhere on the highlighted element to bring up the **Cloth Asset** options menu. Then hover over **Apply Clothing Asset** and +select from the available clothing assets to apply. This will associate the Cloth asset you created with this Material Element geometry. + + ![](ClothSectionAssignment.png)(w:450) + +## Painting Cloth Weights + +To begin painting your cloth weights, follow these steps. + +1. Go to the main menu and select **Window**, then locate and click **Cloth Paint**. This will open the Cloth Paint panel where you can click the **Enable Paint Tools** button to access +the various options for painting cloth weights to onto your geometry. + + ![](ClothPanelEnabled.png)(w:350) + +1. To start painting, select your assigned Cloth Asset from the **Assets** window. + + ![](HighlightClothAsset.png)(w:550) + +1. In the Cloth Painting section, set a **Paint Value** and then left-click and drag the brush across the surface of your clothing geometry you've selected. + + [REGION:asyncgif] + ![](PaintingCloth.gif)(w:500) + [/REGION] + + [REGION:note] + If you've used the APEX Clothing Tools for 3DS Max or Maya, or similar painting tools in general, the controls should feel familiar. + [/REGION] + +### Paint Tool Methods + +The **Paint Tool** selection enables you to choose the way you can paint your cloth weights; using a brush or a gradient. + +#### Brush + +The **Brush** tool enables you to manually paint weight values directly to your cloth. + +![](BrushTools.png)(w:350) + +To paint your weight values, set a **Paint Value** and left-click and drag the mouse over the cloth geometry. + +![](Paint_Brush.png)(w:500) + + +#### Gradient + +The **Gradient** tool enables you to set weight values that will be painted between the selected points. Between these selected points a gradient will be painted that increases from the +**Gradient Start Value** to the **Gradient End Value**. + +![](GradientTools.png)(w:350) + +To paint your weight values, first set the **Gradient Start Value** and the **Gradient End Value**. Then, left-click and drag along your cloth mesh to paint the start value, which is represented +by a green color over the painted vertices. Once you've done that, press the **Enter** (Return) key to switch and paint the end value, which is now represented by a red color that is painted over +the vertices. + +Once you're finished painting your gradient values, press the **Enter** (Return) key again and you will see a gradient painted similarly too the example below. + +![](Paint_Gradient.png)(w:500) + + + +[REGION:note] +Alternatively, if you'd prefer to use a Brush while painting your gradient start and end points you can enable the option **Use Regular Brush for Gradient**. Then in the Brush section, use the **Radius** tool to set your brushes radius. +[/REGION] + + + +## Assigning Cloth Assets to their Materials + +To assign Cloth assets to the Material Element of your Skeletal Mesh, follow these steps. + +1. Navigate to the **Asset Details** panel and locate the **Clothing** section. This is where you'll find your available Cloth assets that can be assigned. You can adjust the various properties of your cloth +by expanding the **Clothing Properties**. + + ![](AssetDetailsCloth.png)(w:350) +1. In the **LOD** section, locate the **Material Element** you used to paint your cloth weights to. Use the **Clothing** drop-down selection to pick from the available cloth assets. + + ![](AssignClothToMaterial.png)(w:350) + + [REGION:note] + Clothing Assets should only be assigned to the Material Elements that has had a clothing asset created and painted for it to use. + [/REGION] + + + + + + + + \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Cloth/Overview/ClothOverview.INT.udn b/Engine/Documentation/Source/Engine/Physics/Cloth/Overview/ClothOverview.INT.udn new file mode 100644 index 000000000000..476bbba36b32 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Cloth/Overview/ClothOverview.INT.udn @@ -0,0 +1,192 @@ +Availability:Public +Crumbs: +Title:Clothing Tool Overview +Description:An overview of Cloth creation using in-editor tools in Unreal Engine 4. +Type:Overview +SkillLevel:Intermediate +Version:4.16 +Parent:Engine/Physics +Order:1 +Tags:Cloth +Tags:Physics +reference-image:SectionSelection.gif +reference-image:PaintingCloth.gif +Topic-image:Clothing_Topic.png + + + +[REGION:warning] +This is an experimental feature and may change in later versions. In order to use this tool, you must first enable it in the Editor Preferences. You can do this by doing to the main menu > **Edit** > **Editor Preferences** > **Experimental** > and +enabling the checkbox next to **Clothing Tool**. +[/REGION] + +[TOC(start:2 end:2)] + +In Unreal Engine, version 4.16, APEX Cloth has now been replaced with the NVIDIA's NvCloth solver. This is a low-level clothing solver that is responsible for the particle simulation that runs +clothing. This clothing solver allows integrations to be lightweight and very extensible because we now have direct access to this data. Unlike APEX Clothing, which is a sophisticated SDK that +is a one-stop shop for clothing simulation that handles both the simulation and the render. + +![](OverviewImage.png)(w:1200) + +1. **Section Selection -** Use this to select the Material IDs that will be used for painting cloth onto. +1. **Cloth Paint Tab -** This section includes all the necessary tools and properties you can use when painting clothing. + +With the Clothing Tools now available within the Editor, the workflow has been redefined to enable developers to work directly in Unreal Engine to author their content without the need for +external dependencies. + +[REGION:imagetable] +| [INCLUDE:#oldworkflow] | [INCLUDE:#newworkflow] | +| --- | --- | +| Old Cloth Workflow | New Cloth Workflow | +| [INCLUDE:#clickimage] | [INCLUDE:#clickimage] | +[/REGION] + +With the "Old" workflow using APEX Cloth, you were required to develop all your assets outside of Unreal using an external program (NVIDIA's Clothing Tool) or DCC Plugins that require specific +software (3DS Max/Maya) to author this content. Only during the final stage of development would you bring your authored content into Unreal and assign it to your mesh. This meant that if you had +to correct anything you would have to go back to your program and re-author the content outside of the Editor. + +The "New" workflow enables you to create your content once and then do all the creation editing of the clothing directly inside of Unreal. This makes the creation and iteration of testing content +that much quicker, and you also avoid any disconnects between where the content was created versus where it's being used by being able to see all of your edits for your clothing simulation +happening in real-time and as they will appear in your game. + + +## Creating a Cloth Section Asset + +To create a new Cloth asset, follow these steps. + +1. Click the **Section Selection** button in the main toolbar. This will enable you to select the different Material Elements of your Skeletal Mesh. + + [REGION:asyncgif] + ![](SectionSelection.gif)(w:500) + [/REGION] +1. With your section selected, you can right-click anywhere on the highlighted element to bring up the **Cloth Asset** options menu. + + ![](ClothAssetContextMenu.png)(w:450) + +1. Hover over **Create Cloth Asset from Selection** and then fill in the following areas. + + ![](CreateClothContextMenu.png)(w:350) + + * **Asset Name** - Give your asset a name so that you can easily find locate it later. + * **Remove from Mesh** - If you've got a separate mesh piece of geometry you want to be associated as cloth, you can enable this option. If not, you can leave this unchecked. + * **Physics Asset** - If this cloth asset is for a character, use its Physics Asset here to get proper collision for the cloth simulation. + +1. Once you've set the information from the previous step you can click the **Create** button. + + ![](CreateClothButton.png)(w:350) + +## Assigning a Cloth Section Asset + +To assign a Cloth asset to a section, follow these steps. + +1. With your section element selected, you can right-click anywhere on the highlighted element to bring up the **Cloth Asset** options menu. Then hover over **Apply Clothing Asset** and +select from the available clothing assets to apply. This will associate the Cloth asset you created with this Material Element geometry. + + ![](ClothSectionAssignment.png)(w:450) + +## Painting Cloth Weights + +To begin painting your cloth weights, follow these steps. + +1. Go to the main menu and select **Window**, then locate and click **Cloth Paint**. This will open the Cloth Paint panel where you can click the **Enable Paint Tools** button to access +the various options for painting cloth weights to onto your geometry. + + ![](ClothPanelEnabled.png)(w:350) + +1. To start painting, select your assigned Cloth Asset from the **Assets** window. + + ![](HighlightClothAsset.png)(w:550) + +1. In the Cloth Painting section, set a **Paint Value** and then left-click and drag the brush across the surface of your clothing geometry you've selected. + + [REGION:asyncgif] + ![](PaintingCloth.gif)(w:500) + [/REGION] + + [REGION:note] + If you've used the APEX Clothing Tools for 3DS Max or Maya, or similar painting tools in general, the controls should feel familiar. + [/REGION] + +### Paint Tool Methods + +The **Paint Tool** selection enables you to choose the way you can paint your cloth weights; using a brush or a gradient. + +#### Brush + +The **Brush** tool enables you to manually paint weight values directly to your cloth. + +![](BrushTools.png)(w:350) + +To paint your weight values, set a **Paint Value** and left-click and drag the mouse over the cloth geometry. + +![](Paint_Brush.png)(w:500) + + +#### Gradient + +The **Gradient** tool enables you to set weight values that will be painted between the selected points. Between these selected points a gradient will be painted that increases from the +**Gradient Start Value** to the **Gradient End Value**. + +![](GradientTools.png)(w:350) + +To paint your weight values, first set the **Gradient Start Value** and the **Gradient End Value**. Then, left-click and drag along your cloth mesh to paint the start value, which is represented +by a green color over the painted vertices. Once you've done that, press the **Enter** (Return) key to switch and paint the end value, which is now represented by a red color that is painted over +the vertices. + +Once you're finished painting your gradient values, press the **Enter** (Return) key again and you will see a gradient painted similarly to the example below. + +![](Paint_Gradient.png)(w:500) + + + +[REGION:note] +Alternatively, if you'd prefer to use a Brush while painting your gradient start and end points you can enable the option **Use Regular Brush for Gradient**. Then in the Brush section, use the **Radius** tool to set your brushes radius. +[/REGION] + + + +## Assigning Cloth Assets to their Materials + +To assign Cloth assets to the Material Element of your Skeletal Mesh, follow these steps. + +1. Navigate to the **Asset Details** panel and locate the **Clothing** section. This is where you'll find your available Cloth assets that can be assigned. You can adjust the various properties of your cloth +by expanding the **Clothing Properties**. + + ![](AssetDetailsCloth.png)(w:350) +1. In the **LOD** section, locate the **Material Element** you used to paint your cloth weights too. Use the **Clothing** drop-down selection to pick from the available cloth assets. + + ![](AssignClothToMaterial.png)(w:350) + + [REGION:note] + Clothing Assets should only be assigned to the Material Elements that has had a clothing asset created and painted for it to use. + [/REGION] + + + + + + + + \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Cloth/Overview/ClothOverview.JPN.udn b/Engine/Documentation/Source/Engine/Physics/Cloth/Overview/ClothOverview.JPN.udn new file mode 100644 index 000000000000..a550a8b7caf7 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Cloth/Overview/ClothOverview.JPN.udn @@ -0,0 +1,193 @@ +INTSourceChangelist:3473461 +Availability:Public +Crumbs: +Title:クロス ツールの概要 +Description:UE4 のインエディタ ツールを使ったクロス作成の概要 +Type:Overview +SkillLevel:Intermediate +Version:4.16 +Parent:Engine/Physics +Order:1 +Tags:Cloth +Tags:Physics +reference-image:SectionSelection.gif +reference-image:PaintingCloth.gif +Topic-image:Clothing_Topic.png + + + +[REGION:warning] +これは実験的機能であり、将来のバージョンで変更される可能性があります。このツールを使用するには、最初に [Editor Preferences (エディタの環境設定)] で有効にする必要があります。これはメイン メニューで、 **Edit** > **Editor Preferences** > **Experimental** > の順に進み、 +**[Clothing Tool]** ツールの隣のチェックボックスを有効にして行います。 +[/REGION] + +[TOC(start:2 end:2)] + +アンリアル エンジンのバージョン 4.16 では APEX Cloth がNVIDIA の NvCloth ソルバーと置き換わりました。これはローレベルのクロス (布) ソルバーであり、クロスを実行するパーティクル シミュレーションを +行います。このクロス ソルバーの統合は軽量であり、データへの直接アクセスが可能なため拡張性が高くなっています。シミュレーションとレンダリングの両方を処理するオールインワンの SDK である +APEX Clothing とは異なります。 + +![](OverviewImage.png)(w:1200) + +1. **[Section Selection (セクション選択)] -** クロスをペイントするために使う Material ID を選択します。 +1. **[Cloth Paint] タブ -** クロスをペイントする場合に必要なツールやプロパティがすべてあります。 + +エディタでクロス ツールを利用できるようになり、ワークフローが再定義されました。直接アンリアル エンジンで作業して、外部ツールに依存せずに +コンテンツをオーサリングできるようになりました。 + +[REGION:imagetable] +| [INCLUDE:#oldworkflow] | [INCLUDE:#newworkflow] | +| --- | --- | +| クロスの旧ワークフロー | クロスの新規ワークフロー | +| [INCLUDE:#clickimage] | [INCLUDE:#clickimage] | +[/REGION] + +APEX Cloth を用いた「旧」ワークフローでは、外部プログラム (NVIDIA のクロス ツール) を使ってアンリアル外部ですべてのアセットを作成するか、特定のソフトウェア (3DS Max/Maya) を必要とする DCC プラグインを使う +必要がありました。開発の最終段階でのみ、オーサリングしたコンテンツをアンリアル エンジンに取り込んで、メッシュに割り当てます。つまり、何かを変更する必要があれば、 +プログラムに戻り、エディタ外部でコンテンツを再オーサリングしなければなりませんでした。 + +「新規」ワークフローでは、コンテンツを作成したら、すべてのクロスの作成、編集を直接アンリアル エンジン内で行います。これにより、コンテンツの作成およびテストするコンテンツのイタレーションが迅速になり、 +クロス シミュレーションがゲームのようにリアルタイムで起こり、編集がすべて見えることで、 +コンテンツの作成場所と使用場所との間でずれがなくなります。 + + +## Cloth Section アセットを作成する + +新規 Cloth アセットを作成するには、以下の操作を行います。 + +1. メイン ツールバーで、**[Section Selection (セクション選択)]** ボタンをクリックします。これでスケルタルメッシュの様々なマテリアル エレメントを選択することができます。 + [REGION:asyncgif] + + ![](SectionSelection.gif)(w:500) + [/REGION] +1. セクションを選択した状態で、ハイライトしたエレメント上で右クリックして **[Cloth Asset]** オプション メニューを表示させます。 + + ![](ClothAssetContextMenu.png)(w:450) + +1. **[Create Cloth Asset from Selection (選択したものから Cloth アセットを作成)]** にマウスをかざして、以下のエリアに情報を入力します。 + + ![](CreateClothContextMenu.png)(w:350) + + * **Asset Name** - 後で簡単に見つけられるようにアセットに名前を付けてください。 + * **Remove from Mesh** - クロスとして関連付けたい別個のジオメトリのメッシュの構成要素があれば、このオプションを有効にします。そうでなければ、チェックを入れずにこのままにします。 + * **Physics Asset** - Cloth アセットがキャラクター用ならば、その Physics アセットを使ってクロス シミュレーションに適切なコリジョンが生じるようにします。 + +1. 前のステップで情報を設定したら、**[Create]** ボタンをクリックします。 + + ![](CreateClothButton.png)(w:350) + +## Cloth Section アセットを割り当てる + +セクションに Cloth アセットを割り当てるには以下の手順に従います。 + +1. セクション エレメントを選択した状態で、ハイライトしたエレメント上で右クリックして **[Cloth Asset]** オプション メニューを表示させます。**[Apply Clothing Asset (Clothing アセットを適用)]** にマウスをかざして、適用する利用可能な +Cloth アセットを選択します。これにより作成した Cloth アセットをこのマテリアル エレメント ジオメトリに関連付けます。 + + ![](ClothSectionAssignment.png)(w:450) + +## クロスのウェイトをペイントする + +クロスのウェイトのペイントを開始するには、以下のステップに従います。 + +1. メイン メニューに進み、**[Window]** を選択し、**[Cloth Paint]** を探してクリックします。クロスのペイント パネルが開きます。このパネルで、**[Enable Paint Tools]** ボタンをクリックすると、 +クロスのウェイトをジオメトリにペイントするための様々なオプションを利用することができます。 + + ![](ClothPanelEnabled.png)(w:350) + +1. ペイントを開始するには、割り当てた Cloth アセットを **[Assets]** ウィンドウから選択します。 + + ![](HighlightClothAsset.png)(w:550) + +1. Cloth Painting セクションで、**[Paint Value]** を設定します。次に左クリックして、選択したクロス ジオメトリのサーフェス上をブラシでドラッグします。 + + [REGION:asyncgif] + ![](PaintingCloth.gif)(w:500) + [/REGION] + + [REGION:note] + 3DS Max または Maya で APEX クロス ツールや一般的な類似ペイント ツールを使ったことがあれば、こうした操作に馴染みがあるはずです。 + [/REGION] + +### Paint ツールのメソッド + +**Paint Tool** の選択では、ブラシあるいはグラデーションを使ってクロスのウェイトのペイント方法を選ぶことができます。 + +#### ブラシ + +**Brush** ツールは、手動でウェイト値を直接クロスにペイントすることができます。 + +![](BrushTools.png)(w:350) + +ウェイト値をペイントするには、 **[Paint Value]** を設定し、左クリックしてクロスのジオメトリ上をマウスオーバーします。 + +![](Paint_Brush.png)(w:500) + + +#### グラデーション + +**[Gradient]** ツールを使って、選択したポイント間でペイントするウェイト値を設定することができます。こうした選択ポイント間で、**[Gradient Start Value (グラデーションの開始値)]** から **[Gradient End Value (グラデーション終了値)]** に値が増えていく +グラデーションをペイントします。 + +![](GradientTools.png)(w:350) + +ウェイト値をペイントするには、最初に **[Gradient Start Value]** と **[Gradient End Value]** を設定します。次に左クリックしてクロスのメッシュに沿ってドラッグして開始値をペイントします。 +これは緑色で表示されます。このように行ったら、**Enter** (Return) キーを押して切り替えて終了値をペイントします。 +これは頂点上にペイントされる赤色で表示されます。 + +グラデーション値のペイント終了後、再度 **Enter** (Return) キーを押すと以下の例のようにペイントされたグラデーションが表示されます。 + +![](Paint_Gradient.png)(w:500) + + + +[REGION:note] +または、グラデーションの開始ポイントと終了ポイントでブラシを使用する場合、**[Use Regular Brush for Gradient]** のオプションを有効にすることができます。次にブラシ セクションで、**Radius** ツールを使ってブラシの半径を設定します。 +[/REGION] + + + +## Cloth アセットをマテリアルに割り当てる + +Cloth アセットをスケルタルメッシュのマテリアル エレメントに割り当てるには、以下の手順に従います。 + +1. **[Asset Details]** パネルに移動して **[Clothing]** セクションを見つけます。ここで割り当てることのできる Cloth アセットを探します。クロスの様々なプロパティを調整するには、 +**[Clothing Properties]** を展開します。 + + ![](AssetDetailsCloth.png)(w:350) +1. **[LOD]** セクションでクロスのウェイトのペイントにも使った **Material Element (マテリアル エレメント)** を探します。**[Clothing]** のドロップダウンの選択肢を使って利用可能な Cloth アセットの中から選択します。 + + ![](AssignClothToMaterial.png)(w:350) + + [REGION:note] + Clothing アセットは、マテリアル エレメントが使用するために作成され、ペイントされた Clothing アセットを持つマテリアル エレメントだけに割り当てられます。 + [/REGION] + + + + + + + + \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Cloth/Overview/ClothOverview.KOR.udn b/Engine/Documentation/Source/Engine/Physics/Cloth/Overview/ClothOverview.KOR.udn new file mode 100644 index 000000000000..5cdcf94fa875 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Cloth/Overview/ClothOverview.KOR.udn @@ -0,0 +1,193 @@ +INTSourceChangelist:3473461 +Availability:Public +Crumbs: +Title:클로딩 툴 개요 +Description:언리얼 엔진 4 에디터 내장 툴을 사용해서 클로스를 만드는 방법 개요입니다. +Type:Overview +SkillLevel:Intermediate +Version:4.16 +Parent:Engine/Physics +Order:1 +Tags:Cloth +Tags:Physics +reference-image:SectionSelection.gif +reference-image:PaintingCloth.gif +Topic-image:Clothing_Topic.png + + + +[REGION:warning] +이 기능은 실험단계 기능이라 앞으로 변경될 수 있습니다. 이 툴을 사용하려면, 먼저 에디터 개인설정에서 활성화시켜야 합니다. 메인 메뉴 > **편집** > **에디터 개인설정** > **실험단계** 에서 +**Clothing Tool** (클로딩 툴) 옆의 박스를 체크하시면 됩니다. +[/REGION] + +[TOC(start:2 end:2)] + +언리얼 엔진 4.16 버전에서 APEX Cloth 가 NVIDIA 의 NvCloth 솔버로 대체되었습니다. 클로딩을 실행시키는 파티클 시뮬레이션을 담당하는 로우 레벨 클로딩 솔버입니다. +이 클로딩 솔버를 통해 그 데이터에 직접 접근할 수 있게 되어 매우 가볍고 확장성 높은 통합이 가능해졌습니다. APEX Clothing 과는 달리 세련된 SDK 가 포함되어 있어 +시뮬레이션과 렌더 양쪽을 담당하는 클로딩 시뮬레이션 원스탑 센터 역할을 할 것입니다. + +![](OverviewImage.png)(w:1200) + +1. **Section Selection -** (섹션 선택) 클로스 페인트 작업을 할 때 사용할 머티리얼 ID 를 선택하는 데 사용됩니다. +1. **Cloth Paint Tab -** (클로스 페인트 탭) 이 섹션에는 클로딩을 페인트할 때 사용할 수 있는 필수 툴과 프로퍼티가 전부 들어있습니다. + +이제 에디터 안에서 클로딩 툴을 사용할 수 있게 되어, 언리얼 엔진 개발자들은 외부 프로그램에 의존할 필요 없이 엔진 안에서 바로 작업할 수 있도록 +새로운 작업방식을 정의할 수 있게 되었습니다. + +[REGION:imagetable] +| [INCLUDE:#oldworkflow] | [INCLUDE:#newworkflow] | +| --- | --- | +| 예전 클로스 작업방식 | 새로운 클로스 작업방식 | +| [INCLUDE:#clickimage] | [INCLUDE:#clickimage] | +[/REGION] + +APEX Cloth 를 사용하는 "예전" 작업방식에서는, 언리얼 외부에서 (NVIDIA 의 Clothing Tool 같은) 외부 프로그램이나 (3DS Max/Maya 같은) 특정 소프트웨어가 필요한 DCC 플러그인을 사용해서 +모든 콘텐츠를 제작해야 했습니다. 개발 최종 단계에서나 제작한 콘텐츠를 언리얼로 가져와 메시에 할당하는 것이지요. 즉 뭔가 수정해야 할 것이 있으면 +원래 프로그램으로 돌아가 에디터 외부에서 콘텐츠를 다시 제작해야 했다는 뜻입니다. + +"새로운" 작업방식에서는 콘텐츠를 한 번 만든 이후 클로딩 관련 편집 작업을 전부 언리얼 안에서 할 수 있게 되었습니다. 콘텐츠의 생성이나 테스트 반복작업이 그만큼 빨라질 뿐만 아니라, +클로딩 시뮬레이션 편집 내용을 게임에서 실시간 확인 가능하므로 +콘텐츠 제작 시점과 사용 시점에서 달라지는 현상을 방지할 수 있습니다. + + +## 클로스 섹션 애셋 생성 + +Cloth(클로스) 애셋을 새로 생성하는 방법은 다음과 같습니다. + +1. 메인 툴바의 **섹션 선택** 버튼을 클릭합니다. 스켈레탈 메시에 다른 머티리얼 엘리먼트를 선택할 수 있습니다. + + [REGION:asyncgif] + ![](SectionSelection.gif)(w:500) + [/REGION] +1. 섹션을 선택한 채, 강조된 엘리먼트에 우클릭하면 **클로스 애셋** 옵션 메뉴가 뜹니다. + + ![](ClothAssetContextMenu.png)(w:450) + +1. **Create Cloth Asset from Selection** (선택에서 클로스 애셋 생성)을 선택한 뒤 다음 부분을 채웁니다. + + ![](CreateClothContextMenu.png)(w:350) + + * **Asset Name** 애셋 이름 - 나중에 쉽게 찾을 수 있도록 애셋이 이름을 짓습니다. + * **Remove from Mesh** 메시에서 제거 - 클로스에 할당하려는 별도의 지오메트리 메시 조각이 있는 경우, 이 옵션을 켜면 됩니다. 없으면 빈 박스로 놔둬도 됩니다. + * **Physics Asset** 피직스 애셋 - 이 클로스 애셋이 캐릭터용인 경우, 그 피직스 애셋을 사용하여 클로스 시뮬레이션에 적합한 콜리전을 구합니다. + +1. 예전 단계의 정보를 설정했으면, **생성** 버튼을 클릭합니다. + + ![](CreateClothButton.png)(w:350) + +## 클로스 섹션 애셋 할당 + +섹션에 클로스 애셋을 할당하는 방법은 다음과 같습니다. + +1. 섹션 엘리먼트를 선택한 채, 강조된 엘리먼트 아무데나 우클릭하면 **클로스 애셋** 옵션 메뉴를 띄울 수 있습니다. 그런 다음 **클로딩 애셋 적용** 에 커서를 올리고 +클로딩 애셋을 선택하면 적용합니다. 그러면 생성한 클로스 애셋을 이 머티리얼 엘리먼트 지오메트리에 할당합니다. + + ![](ClothSectionAssignment.png)(w:450) + +## 클로스 웨이트 페인트 + +클로스 웨이트 페인트 방법은 다음과 같습니다. + +1. 메인 메뉴로 가 **창** 을 선택한 뒤, **Cloth Paint** (클로스 페인트)를 찾아 클릭합니다. 그러면 클로스 페인트 패널이 열리며, 여기서 **Enable Paint Tools** (페인트 툴 활성화) 버튼을 클릭하면 +지오메트리에 클로스 웨이트 페인트를 위한 여러가지 옵션을 접할 수 있습니다. + + ![](ClothPanelEnabled.png)(w:350) + +1. 페인트를 시작하려면, **애셋** 창에서 할당된 클로스 애셋을 선택합니다. + + ![](HighlightClothAsset.png)(w:550) + +1. 클로스 페인팅 섹션에서 **Paint Value** (페인트 값)을 설정한 뒤 브러시를 선택한 클로딩 지오메트리 표면에 클릭 드래그합니다. + + [REGION:asyncgif] + ![](PaintingCloth.gif)(w:500) + [/REGION] + + [REGION:note] + 3DS Max 또는 Maya, 아니면 비슷한 범용 페인팅 툴을 사용한 적이 있으시다면, 조작법이 익숙하실 것입니다. + [/REGION] + +### 페인트 툴 메소드 + +**페인트 툴** 선택에서는 클로스 웨이트 페인트 방법을 브러시 또는 그레디언트 중에서 선택할 수 있습니다. + +#### 브러시 + +**브러시** 툴로 클로스에 웨이트 값을 수동으로 직접 칠할 수 있습니다. + +![](BrushTools.png)(w:350) + +웨이트 값을 칠하기 위해서는, **Paint Value** 를 설정하고 클로스 지오메트리 위에 마우스를 좌클릭 드래그합니다. + +![](Paint_Brush.png)(w:500) + + +#### 그레디언트 + +**그레디언트** 툴은 선택된 지점 사이에 웨이트 값을 설정할 수 있습니다. 이 선택 지점 사이에는 +**Gradient Start Value** 에서 **Gradient End Value** 까지 점차 증가하는 그레디언트가 칠해집니다. + +![](GradientTools.png)(w:350) + +웨이트 값 페인트를 위해서는, 먼저 **Gradient Start Value** 와 **Gradient End Value** 를 설정합니다. 그리고 클로스 메시를 좌클릭 드래그하여 시작 값을 칠하면, +버텍스 위에 초록색으로 표시됩니다. 그 후 **Enter** (리턴) 키를 치면 끝 값으로 전환되어 칠할 수 있으며, 이제 버텍스 위에 빨강색으로 +표시됩니다. + +그레디언트 값 페인트를 마치고 **Enter** (리턴) 키를 다시 한 번 치면 아래 예제와 같이 그레디언트가 칠해진 것을 볼 수 있습니다. + +![](Paint_Gradient.png)(w:500) + + + +[REGION:note] +다른 방법으로는, 그레디언트 시작 및 끝 지점을 칠할 때 브러시를 사용하고자 하는 경우 **Use Regular Brush for Gradient** (그레디언트에 일반 브러시 사용) 옵션을 켜면 됩니다. 그리고 브러시 섹션에서 **Radius** (반경) 툴을 사용하여 브러시 반경을 설정하면 됩니다. +[/REGION] + + + +## 머티리얼에 클로스 애셋 할당 + +스켈레탈 메시의 머티리얼 엘리먼트에 클로스 애셋을 할당하는 방법은 다음과 같습니다. + +1. **애셋 디테일** 패널로 이동하여 **Clothing** (클로딩) 섹션을 찾습니다. 여기서 할당할 수 있는 클로스 애셋을 찾을 수 있습니다. 그리고 **Clothing Properties** 를 펼쳐 +클로스의 여러 프로퍼티를 조절할 수 있습니다. + + ![](AssetDetailsCloth.png)(w:350) +1. **LOD** 섹션에서도 클로스 웨이트 페인트에 사용한 **Material Element** (머티리얼 엘리먼트)를 찾습니다. **Clothing** (클로딩) 드롭다운 선택을 사용하여 가능한 클로스 애셋 중에서 선택합니다. + + ![](AssignClothToMaterial.png)(w:350) + + [REGION:note] + 클로딩 애셋은 전용으로 클로딩 애셋을 만들어 페인트해 둔 머티리얼 엘리먼트에만 할당해야 합니다. + [/REGION] + + + + + + + + \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Cloth/Reference/ClothReference.CHN.udn b/Engine/Documentation/Source/Engine/Physics/Cloth/Reference/ClothReference.CHN.udn new file mode 100644 index 000000000000..c523916f029a --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Cloth/Reference/ClothReference.CHN.udn @@ -0,0 +1,397 @@ +INTSourceChangelist:0 +Availability: Docs +Crumbs: +Title: Cloth Properties Reference +Description: A reference page for the available properties used with Cloth asset configuration. +Type:reference +Version:4.16 +Parent:Engine/Physics +Related:Engine/Physics/Cloth/Overview +Order:2 +Tags:Physics +Tags:Cloth + + + +[OBJECT:modulesectionexpanded] + [PARAMLITERAL:id] + Cloth2 + [/PARAMLITERAL] + [PARAM:heading] + Section Selection + [/PARAM] + [PARAM:content] + %C2% + [/PARAM] +[/OBJECT] + +[VAR:C2] + +[REGION:raw] +![](SectionSelectionMenu.png) +[/REGION] + +The **Section Selection** enables you to select specific Material Elements of your mesh in the Skeletal Mesh Editor's viewport. In this mode, you are able to create, assign, and remove any +cloth assets for this mesh. + +[REGION:simpletable] +| Property | Description | +| --- | --- | +| Apply Clothing Asset | Select an available clothing asset to apply to the selected section. | +| Remove Clothing Asset | Remove the currently assigned clothing asset. | +| Create Clothing Asset from Section | Create a clothing asset from the selected section. [INCLUDE:#createclothsection] | +[/REGION] + +[/VAR] + + + + + +[OBJECT:modulesectionexpanded] + [PARAMLITERAL:id] + Cloth1 + [/PARAMLITERAL] + [PARAM:heading] + Cloth Paint + [/PARAM] + [PARAM:content] + %C1% + [/PARAM] +[/OBJECT] + +[VAR:C1] + +![](ClothPaintPanel.png) + +The **Cloth Paint** properties enable you to define how you paint weights on the cloth asset you've selected. These weights determine how the **Cloth Configuration Properties** use +these values to applie cloth simulations to your mesh. + + +[REGION:simpletable] +| Property | Description | +| --- | --- | +| Enable Paint Tools | This enables the tools needed to paint your cloth values. | +| [REGION:tablesection] Assets [/REGION] || +| Asset LOD | Selection box for the available levels of detail (LOD) where you can paint or create a mask. | +| New Mask | Enables you to create a mask for the selected asset and available level of detail. | +| [REGION:tablesection] Mask [/REGION] || +| Mask Context Menu | Available options for the asset mask. | +| Set Target | Selects the available targets that you can apply the mask to. [INCLUDE:#settarget] | +| Move Up | Moves the mask selection up in the Mask list. | +| Move Down | Moves the mask selection down in the Mask list. | +| Delete | Removes the selected mask from the list. | +| Apply | Applies the mask to the physical mesh. | +| [REGION:tablesection] Brush [/REGION] || +| Radius | Sets the radius that will be used for the painting brush. | +| Strength | Sets the strength of the rush when painting between 0 - 1, with 0 being off and 1 being fully on. | +| Falloff | Sets the amount of falloff around the edge of the brush to apply between 0 - 1, with 0 being no falloff and 1 being a lot of falloff. | +| Enable Brush Flow | Enables the continuous 'flow' where paint is applied from the brush every tick. | +| Ignore Back-Facing | Whether the back-facing triangles should be ignored. | +| [REGION:tablesection] View [/REGION] || +| Color View Mode | Selection used to display the Vertex Colors view modes. [INCLUDE:#colorview] | +| [REGION:tablesection] Cloth Painting [/REGION] || +| Painting Property | Sets the current clothing property which should be visualized and painted. [INCLUDE:#paintingproperty]| +| Paint Tool | Select which type of paint tool to use. [INCLUDE:#brush] [INCLUDE:#gradient]| +[/REGION] + +[/VAR] + + + + + + + + + + +[OBJECT:modulesectionexpanded] + [PARAMLITERAL:id] + Cloth3 + [/PARAMLITERAL] + [PARAM:heading] + Cloth Configuration Properties + [/PARAM] + [PARAM:content] + %C3% + [/PARAM] +[/OBJECT] + +[VAR:C3] + + +![](ClothingProperties.png) + +In the **Asset Details** panel under the **Clothing** section, you can define the various properties of your clothing that is assigned to the mesh's Material Elements. These properties +define how your cloth will react so that you can have different types of cloth that act like silk, burlap, rubber, etc. + +[REGION:simpletable] +| Property | Description | +| --- | --- | +| [REGION:tablesection] Mesh Clothing Assets [/REGION] || +| Name | The name given to the the created or imported Cloth asset. | +| Details | Specific details about the cloth asset, such as the number of vertices simulating, fixed vertices, bones, etc. | +| [REGION:tablesection] Cloth Config [/REGION] || +| Wind Method | A selection for how wind should be processed. [INLCUDE:#windmethod] | +| Vertical Constraint Config | Constraint data used for vertical constraints. [INCLUDE:#constrconfig] | +| Horizontal Constraint Config | Constraint data used for horizontal constraints. [INCLUDE:#constrconfig] | +| Bend Constraint Config | Constraint data used for bend constraints. [INCLUDE:#constrconfig] | +| Shear Constraint Config | Constraint data used for shear constraints. [INCLUDE:#constrconfig] | +| Self Collision Radius | Size of the self collision spheres centered on each vertice. | +| Self Collision Stiffness | The stiffness of the spring force that will resolve self collisions. | +| Damping | The damping of particle motions per-axis (XYZ). | +| Friction | The friction of the surface when colliding. | +| Wind Drag Coefficient | Drag coefficient for wind calculations. Higher values mean that wind has more lateral effect on the cloth. | +| Wind Lift Coefficient | Lift coefficient for wind calculations. Higher values make cloth rise easier in the wind. | +| Linear Drag | Drag that is applied to linear particle movement per-axis (XYZ). | +| Angular Drag | Drag that is applied to angular particle movement. Higher values should limit material bending (per-axis XYZ). | +| Linear Inertia Scale | Scale for linear particle inertia. This controls how much movement should translate to linear motion per-axis (XYZ). | +| Angular Inertia Scale | Scale for angular particle inertia. This controls how much movement should translate to angular motion per-axis (XYZ). | +| Centrifugal Inertia Scale | Scale for centrifugal inertia. This controls how much movement should translate to angular motion per-axis (XYZ). | +| Solver Frequency | The frequency of the position solver. Lower values will lead to stretchier, bouncier cloth. | +| Stiffness Frequency | The frequency stiffness calculation. Lower values will degrade stiffness of constraints. | +| Gravity Scale | The scale of gravity's effect on particles. | +| Tether Stiffness | The scale for stiffness of particle tethers between each other. | +| Tether Limit | The scale for the limit of particle tethers. This controls how far they can separate. | +| Collision Thickness | This adjusts the thickness of the cloth, used to adjust collisions. | +| [REGION:tablesection] Import [/REGION] || +| Imported File Path | If using APEX Cloth (.apx/apb) assets from an imported file, this will be the original file location path. | +[/REGION] + + +[/VAR] + + + + + + + + + + + + +Availability: Public +Title:Physics Simulation +Crumbs: %ROOT%, Engine +Description:Subsystem used to calculate collision and simulate physical actors. +Version: 4.16 +parent:Engine +order:8 + +[VAR:Topic] +[OBJECT:Topic] + [PARAM:image] + ![%Engine/Physics:title%](Engine/Physics/physics_topic.png) + [/PARAM] + [PARAM:icon] + ![](%ROOT%/physics_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + %Engine/Physics:title% + [/PARAM] + [PARAM:description] + %Engine/Physics:description% + [/PARAM] + [PARAM:path] + [RELATIVE:Engine/Physics] + [/PARAM] +[/OBJECT] +[/VAR] +[VAR:TopicCompact] +[OBJECT:TopicCompact] + [PARAM:image] + ![%Engine/Physics:title%](Engine/Physics/physics_topic.png) + [/PARAM] + [PARAM:icon] + ![](%ROOT%/physics_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + %Engine/Physics:title% + [/PARAM] + [PARAM:description] + %Engine/Physics:description% + [/PARAM] + [PARAM:path] + [RELATIVE:Engine/Physics] + [/PARAM] +[/OBJECT] +[/VAR] + + +[REGION:banner] +![Physics](physics_landing_banner.png) +[/REGION] + +[EXCERPT:Intro] +Unreal Engine 4 uses the PhysX 3.3 physics engine to drive its physical simulation calculations and perform all collision calculations. PhysX provides the ability to perform accurate collision detection as well as simulate physical interactions between objects within the world. Having physics in your game will help improve the immersion value of every scene, as it helps players believe that they are interacting with the scene and that the scene is responding back in some way or another. +[/EXCERPT:Intro] + +[OBJECT:TopicButtonList] + [PARAM:icon] + ![](%ROOT%/start_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + Essentials + [/PARAM] + [PARAM:links] + * [Collision Responses](Engine/Physics/Collision "%Engine/Physics/Collision:description%") + * [Collision Reference](Engine/Physics/Collision/Reference "%Engine/Physics/Collision/Reference:description%") + * [Physics Constraints User Guide](Engine/Physics/Constraints/ConstraintsUserGuide "%Engine/Physics/Constraints/ConstraintsUserGuide:description%") + * [](Engine/Physics/Constraints/ConstraintsBlueprints "%Engine/Physics/Constraints/ConstraintsBlueprints:description%") + * [](Engine/Physics/Constraints/ConstraintsReference "%Engine/Physics/Constraints/ConstraintsReference:description%") + * [](Engine/Physics/Tracing "%Engine/Physics/Tracing:description%") + * [Damping and Friction](Engine/Physics/Constraints/DampingAndFriction "%Engine/Physics/Constraints/DampingAndFriction:description%") + [/PARAM] +[/OBJECT] + +[OBJECT:TopicButtonList] + [PARAM:icon] + ![](%ROOT%/vehicle_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + Clothing Tools + [/PARAM] + [PARAM:links] + * [Clothing Tool Overview](Engine/Physics/Cloth/Overview "%Engine/Physics/Cloth/Overview:description%") + [/PARAM] +[/OBJECT] + +[OBJECT:TopicButtonList] + [PARAM:icon] + ![](%ROOT%/vehicle_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + Vehicles + [/PARAM] + [PARAM:links] + * [Vehicle User Guide](Engine/Physics/Vehicles/VehicleUserGuide "%Engine/Physics/Vehicles/VehicleUserGuide:description%") + * [Vehicle Content Creation Guide](Engine/Physics/Vehicles/VehcileContentCreation "%Engine/Physics/Vehicles/VehcileContentCreation:description%") + * [Advanced Vehicle Template](Engine/Physics/Vehicles/DoubleWishboneVehicle "%Engine/Physics/Vehicles/DoubleWishboneVehicle:description%") + * [Vehicle API Reference](API:AWheeledVehicle) + [/PARAM] +[/OBJECT] + +[OBJECT:TopicButtonList] + [PARAM:icon] + ![](%ROOT%/content_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + Content Creation + [/PARAM] + [PARAM:links] + * [Physics Bodies](Engine/Physics/PhysicsBodies "%Engine/Physics/PhysicsBodies:description%") + * [Complex Vs. Simple Collision](Engine/Physics/SimpleVsComplex "%Engine/Physics/SimpleVsComplex:description%") + * [Physical Materials](Engine/Physics/PhysicalMaterials "%Engine/Physics/PhysicalMaterials:description%") + * [PhAT User Guide and Reference](Engine/Physics/PhAT "%Engine/Physics/PhAT:description%") + [/PARAM] +[/OBJECT] + +[OBJECT:TopicButtonList] + [PARAM:icon] + ![](%ROOT%/related_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + Related Links + [/PARAM] + [PARAM:links] + * [Static Mesh Editor](Engine/Content/Types/StaticMeshes/Editor "%Engine/Physics/PhAT:description%") + * [FBX Pipeline: Static Meshes](Engine/Content/FBX/StaticMeshes "%Engine/Physics/PhAT:description%") + [/PARAM] +[/OBJECT] + + + + + + diff --git a/Engine/Documentation/Source/Engine/Physics/Cloth/Reference/ClothReference.INT.udn b/Engine/Documentation/Source/Engine/Physics/Cloth/Reference/ClothReference.INT.udn new file mode 100644 index 000000000000..b7be5f8a352d --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Cloth/Reference/ClothReference.INT.udn @@ -0,0 +1,396 @@ +Availability: Docs +Crumbs: +Title: Cloth Properties Reference +Description: A reference page for the available properties used with Cloth asset configuration. +Type:reference +Version:4.16 +Parent:Engine/Physics +Related:Engine/Physics/Cloth/Overview +Order:2 +Tags:Physics +Tags:Cloth + + + +[OBJECT:modulesectionexpanded] + [PARAMLITERAL:id] + Cloth2 + [/PARAMLITERAL] + [PARAM:heading] + Section Selection + [/PARAM] + [PARAM:content] + %C2% + [/PARAM] +[/OBJECT] + +[VAR:C2] + +[REGION:raw] +![](SectionSelectionMenu.png) +[/REGION] + +The **Section Selection** enables you to select specific Material Elements of your mesh in the Skeletal Mesh Editor's viewport. In this mode, you are able to create, assign, and remove any +cloth assets for this mesh. + +[REGION:simpletable] +| Property | Description | +| --- | --- | +| Apply Clothing Asset | Select an available clothing asset to apply to the selected section. | +| Remove Clothing Asset | Remove the currently assigned clothing asset. | +| Create Clothing Asset from Section | Create a clothing asset from the selected section. [INCLUDE:#createclothsection] | +[/REGION] + +[/VAR] + + + + + +[OBJECT:modulesectionexpanded] + [PARAMLITERAL:id] + Cloth1 + [/PARAMLITERAL] + [PARAM:heading] + Cloth Paint + [/PARAM] + [PARAM:content] + %C1% + [/PARAM] +[/OBJECT] + +[VAR:C1] + +![](ClothPaintPanel.png) + +The **Cloth Paint** properties enable you to define how you paint weights on the cloth asset you've selected. These weights determine how the **Cloth Configuration Properties** use +these values to applie cloth simulations to your mesh. + + +[REGION:simpletable] +| Property | Description | +| --- | --- | +| Enable Paint Tools | This enables the tools needed to paint your cloth values. | +| [REGION:tablesection] Assets [/REGION] || +| Asset LOD | Selection box for the available levels of detail (LOD) where you can paint or create a mask. | +| New Mask | Enables you to create a mask for the selected asset and available level of detail. | +| [REGION:tablesection] Mask [/REGION] || +| Mask Context Menu | Available options for the asset mask. | +| Set Target | Selects the available targets that you can apply the mask to. [INCLUDE:#settarget] | +| Move Up | Moves the mask selection up in the Mask list. | +| Move Down | Moves the mask selection down in the Mask list. | +| Delete | Removes the selected mask from the list. | +| Apply | Applies the mask to the physical mesh. | +| [REGION:tablesection] Brush [/REGION] || +| Radius | Sets the radius that will be used for the painting brush. | +| Strength | Sets the strength of the rush when painting between 0 - 1, with 0 being off and 1 being fully on. | +| Falloff | Sets the amount of falloff around the edge of the brush to apply between 0 - 1, with 0 being no falloff and 1 being a lot of falloff. | +| Enable Brush Flow | Enables the continuous 'flow' where paint is applied from the brush every tick. | +| Ignore Back-Facing | Whether the back-facing triangles should be ignored. | +| [REGION:tablesection] View [/REGION] || +| Color View Mode | Selection used to display the Vertex Colors view modes. [INCLUDE:#colorview] | +| [REGION:tablesection] Cloth Painting [/REGION] || +| Painting Property | Sets the current clothing property which should be visualized and painted. [INCLUDE:#paintingproperty]| +| Paint Tool | Select which type of paint tool to use. [INCLUDE:#brush] [INCLUDE:#gradient]| +[/REGION] + +[/VAR] + + + + + + + + + + +[OBJECT:modulesectionexpanded] + [PARAMLITERAL:id] + Cloth3 + [/PARAMLITERAL] + [PARAM:heading] + Cloth Configuration Properties + [/PARAM] + [PARAM:content] + %C3% + [/PARAM] +[/OBJECT] + +[VAR:C3] + + +![](ClothingProperties.png) + +In the **Asset Details** panel under the **Clothing** section, you can define the various properties of your clothing that is assigned to the mesh's Material Elements. These properties +define how your cloth will react so that you can have different types of cloth that act like silk, burlap, rubber, etc. + +[REGION:simpletable] +| Property | Description | +| --- | --- | +| [REGION:tablesection] Mesh Clothing Assets [/REGION] || +| Name | The name given to the the created or imported Cloth asset. | +| Details | Specific details about the cloth asset, such as the number of vertices simulating, fixed vertices, bones, etc. | +| [REGION:tablesection] Cloth Config [/REGION] || +| Wind Method | A selection for how wind should be processed. [INLCUDE:#windmethod] | +| Vertical Constraint Config | Constraint data used for vertical constraints. [INCLUDE:#constrconfig] | +| Horizontal Constraint Config | Constraint data used for horizontal constraints. [INCLUDE:#constrconfig] | +| Bend Constraint Config | Constraint data used for bend constraints. [INCLUDE:#constrconfig] | +| Shear Constraint Config | Constraint data used for shear constraints. [INCLUDE:#constrconfig] | +| Self Collision Radius | Size of the self collision spheres centered on each vertice. | +| Self Collision Stiffness | The stiffness of the spring force that will resolve self collisions. | +| Damping | The damping of particle motions per-axis (XYZ). | +| Friction | The friction of the surface when colliding. | +| Wind Drag Coefficient | Drag coefficient for wind calculations. Higher values mean that wind has more lateral effect on the cloth. | +| Wind Lift Coefficient | Lift coefficient for wind calculations. Higher values make cloth rise easier in the wind. | +| Linear Drag | Drag that is applied to linear particle movement per-axis (XYZ). | +| Angular Drag | Drag that is applied to angular particle movement. Higher values should limit material bending (per-axis XYZ). | +| Linear Inertia Scale | Scale for linear particle inertia. This controls how much movement should translate to linear motion per-axis (XYZ). | +| Angular Inertia Scale | Scale for angular particle inertia. This controls how much movement should translate to angular motion per-axis (XYZ). | +| Centrifugal Inertia Scale | Scale for centrifugal inertia. This controls how much movement should translate to angular motion per-axis (XYZ). | +| Solver Frequency | The frequency of the position solver. Lower values will lead to stretchier, bouncier cloth. | +| Stiffness Frequency | The frequency stiffness calculation. Lower values will degrade stiffness of constraints. | +| Gravity Scale | The scale of gravity's effect on particles. | +| Tether Stiffness | The scale for stiffness of particle tethers between each other. | +| Tether Limit | The scale for the limit of particle tethers. This controls how far they can separate. | +| Collision Thickness | This adjusts the thickness of the cloth, used to adjust collisions. | +| [REGION:tablesection] Import [/REGION] || +| Imported File Path | If using APEX Cloth (.apx/apb) assets from an imported file, this will be the original file location path. | +[/REGION] + + +[/VAR] + + + + + + + + + + + + +Availability: Public +Title:Physics Simulation +Crumbs: %ROOT%, Engine +Description:Subsystem used to calculate collision and simulate physical actors. +Version: 4.16 +parent:Engine +order:8 + +[VAR:Topic] +[OBJECT:Topic] + [PARAM:image] + ![%Engine/Physics:title%](Engine/Physics/physics_topic.png) + [/PARAM] + [PARAM:icon] + ![](%ROOT%/physics_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + %Engine/Physics:title% + [/PARAM] + [PARAM:description] + %Engine/Physics:description% + [/PARAM] + [PARAM:path] + [RELATIVE:Engine/Physics] + [/PARAM] +[/OBJECT] +[/VAR] +[VAR:TopicCompact] +[OBJECT:TopicCompact] + [PARAM:image] + ![%Engine/Physics:title%](Engine/Physics/physics_topic.png) + [/PARAM] + [PARAM:icon] + ![](%ROOT%/physics_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + %Engine/Physics:title% + [/PARAM] + [PARAM:description] + %Engine/Physics:description% + [/PARAM] + [PARAM:path] + [RELATIVE:Engine/Physics] + [/PARAM] +[/OBJECT] +[/VAR] + + +[REGION:banner] +![Physics](physics_landing_banner.png) +[/REGION] + +[EXCERPT:Intro] +Unreal Engine 4 uses the PhysX 3.3 physics engine to drive its physical simulation calculations and perform all collision calculations. PhysX provides the ability to perform accurate collision detection as well as simulate physical interactions between objects within the world. Having physics in your game will help improve the immersion value of every scene, as it helps players believe that they are interacting with the scene and that the scene is responding back in some way or another. +[/EXCERPT:Intro] + +[OBJECT:TopicButtonList] + [PARAM:icon] + ![](%ROOT%/start_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + Essentials + [/PARAM] + [PARAM:links] + * [Collision Responses](Engine/Physics/Collision "%Engine/Physics/Collision:description%") + * [Collision Reference](Engine/Physics/Collision/Reference "%Engine/Physics/Collision/Reference:description%") + * [Physics Constraints User Guide](Engine/Physics/Constraints/ConstraintsUserGuide "%Engine/Physics/Constraints/ConstraintsUserGuide:description%") + * [](Engine/Physics/Constraints/ConstraintsBlueprints "%Engine/Physics/Constraints/ConstraintsBlueprints:description%") + * [](Engine/Physics/Constraints/ConstraintsReference "%Engine/Physics/Constraints/ConstraintsReference:description%") + * [](Engine/Physics/Tracing "%Engine/Physics/Tracing:description%") + * [Damping and Friction](Engine/Physics/Constraints/DampingAndFriction "%Engine/Physics/Constraints/DampingAndFriction:description%") + [/PARAM] +[/OBJECT] + +[OBJECT:TopicButtonList] + [PARAM:icon] + ![](%ROOT%/vehicle_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + Clothing Tools + [/PARAM] + [PARAM:links] + * [Clothing Tool Overview](Engine/Physics/Cloth/Overview "%Engine/Physics/Cloth/Overview:description%") + [/PARAM] +[/OBJECT] + +[OBJECT:TopicButtonList] + [PARAM:icon] + ![](%ROOT%/vehicle_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + Vehicles + [/PARAM] + [PARAM:links] + * [Vehicle User Guide](Engine/Physics/Vehicles/VehicleUserGuide "%Engine/Physics/Vehicles/VehicleUserGuide:description%") + * [Vehicle Content Creation Guide](Engine/Physics/Vehicles/VehcileContentCreation "%Engine/Physics/Vehicles/VehcileContentCreation:description%") + * [Advanced Vehicle Template](Engine/Physics/Vehicles/DoubleWishboneVehicle "%Engine/Physics/Vehicles/DoubleWishboneVehicle:description%") + * [Vehicle API Reference](API:AWheeledVehicle) + [/PARAM] +[/OBJECT] + +[OBJECT:TopicButtonList] + [PARAM:icon] + ![](%ROOT%/content_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + Content Creation + [/PARAM] + [PARAM:links] + * [Physics Bodies](Engine/Physics/PhysicsBodies "%Engine/Physics/PhysicsBodies:description%") + * [Complex Vs. Simple Collision](Engine/Physics/SimpleVsComplex "%Engine/Physics/SimpleVsComplex:description%") + * [Physical Materials](Engine/Physics/PhysicalMaterials "%Engine/Physics/PhysicalMaterials:description%") + * [PhAT User Guide and Reference](Engine/Physics/PhAT "%Engine/Physics/PhAT:description%") + [/PARAM] +[/OBJECT] + +[OBJECT:TopicButtonList] + [PARAM:icon] + ![](%ROOT%/related_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + Related Links + [/PARAM] + [PARAM:links] + * [Static Mesh Editor](Engine/Content/Types/StaticMeshes/Editor "%Engine/Physics/PhAT:description%") + * [FBX Pipeline: Static Meshes](Engine/Content/FBX/StaticMeshes "%Engine/Physics/PhAT:description%") + [/PARAM] +[/OBJECT] + + + + + + diff --git a/Engine/Documentation/Source/Engine/Physics/Cloth/Reference/ClothReference.JPN.udn b/Engine/Documentation/Source/Engine/Physics/Cloth/Reference/ClothReference.JPN.udn new file mode 100644 index 000000000000..c523916f029a --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Cloth/Reference/ClothReference.JPN.udn @@ -0,0 +1,397 @@ +INTSourceChangelist:0 +Availability: Docs +Crumbs: +Title: Cloth Properties Reference +Description: A reference page for the available properties used with Cloth asset configuration. +Type:reference +Version:4.16 +Parent:Engine/Physics +Related:Engine/Physics/Cloth/Overview +Order:2 +Tags:Physics +Tags:Cloth + + + +[OBJECT:modulesectionexpanded] + [PARAMLITERAL:id] + Cloth2 + [/PARAMLITERAL] + [PARAM:heading] + Section Selection + [/PARAM] + [PARAM:content] + %C2% + [/PARAM] +[/OBJECT] + +[VAR:C2] + +[REGION:raw] +![](SectionSelectionMenu.png) +[/REGION] + +The **Section Selection** enables you to select specific Material Elements of your mesh in the Skeletal Mesh Editor's viewport. In this mode, you are able to create, assign, and remove any +cloth assets for this mesh. + +[REGION:simpletable] +| Property | Description | +| --- | --- | +| Apply Clothing Asset | Select an available clothing asset to apply to the selected section. | +| Remove Clothing Asset | Remove the currently assigned clothing asset. | +| Create Clothing Asset from Section | Create a clothing asset from the selected section. [INCLUDE:#createclothsection] | +[/REGION] + +[/VAR] + + + + + +[OBJECT:modulesectionexpanded] + [PARAMLITERAL:id] + Cloth1 + [/PARAMLITERAL] + [PARAM:heading] + Cloth Paint + [/PARAM] + [PARAM:content] + %C1% + [/PARAM] +[/OBJECT] + +[VAR:C1] + +![](ClothPaintPanel.png) + +The **Cloth Paint** properties enable you to define how you paint weights on the cloth asset you've selected. These weights determine how the **Cloth Configuration Properties** use +these values to applie cloth simulations to your mesh. + + +[REGION:simpletable] +| Property | Description | +| --- | --- | +| Enable Paint Tools | This enables the tools needed to paint your cloth values. | +| [REGION:tablesection] Assets [/REGION] || +| Asset LOD | Selection box for the available levels of detail (LOD) where you can paint or create a mask. | +| New Mask | Enables you to create a mask for the selected asset and available level of detail. | +| [REGION:tablesection] Mask [/REGION] || +| Mask Context Menu | Available options for the asset mask. | +| Set Target | Selects the available targets that you can apply the mask to. [INCLUDE:#settarget] | +| Move Up | Moves the mask selection up in the Mask list. | +| Move Down | Moves the mask selection down in the Mask list. | +| Delete | Removes the selected mask from the list. | +| Apply | Applies the mask to the physical mesh. | +| [REGION:tablesection] Brush [/REGION] || +| Radius | Sets the radius that will be used for the painting brush. | +| Strength | Sets the strength of the rush when painting between 0 - 1, with 0 being off and 1 being fully on. | +| Falloff | Sets the amount of falloff around the edge of the brush to apply between 0 - 1, with 0 being no falloff and 1 being a lot of falloff. | +| Enable Brush Flow | Enables the continuous 'flow' where paint is applied from the brush every tick. | +| Ignore Back-Facing | Whether the back-facing triangles should be ignored. | +| [REGION:tablesection] View [/REGION] || +| Color View Mode | Selection used to display the Vertex Colors view modes. [INCLUDE:#colorview] | +| [REGION:tablesection] Cloth Painting [/REGION] || +| Painting Property | Sets the current clothing property which should be visualized and painted. [INCLUDE:#paintingproperty]| +| Paint Tool | Select which type of paint tool to use. [INCLUDE:#brush] [INCLUDE:#gradient]| +[/REGION] + +[/VAR] + + + + + + + + + + +[OBJECT:modulesectionexpanded] + [PARAMLITERAL:id] + Cloth3 + [/PARAMLITERAL] + [PARAM:heading] + Cloth Configuration Properties + [/PARAM] + [PARAM:content] + %C3% + [/PARAM] +[/OBJECT] + +[VAR:C3] + + +![](ClothingProperties.png) + +In the **Asset Details** panel under the **Clothing** section, you can define the various properties of your clothing that is assigned to the mesh's Material Elements. These properties +define how your cloth will react so that you can have different types of cloth that act like silk, burlap, rubber, etc. + +[REGION:simpletable] +| Property | Description | +| --- | --- | +| [REGION:tablesection] Mesh Clothing Assets [/REGION] || +| Name | The name given to the the created or imported Cloth asset. | +| Details | Specific details about the cloth asset, such as the number of vertices simulating, fixed vertices, bones, etc. | +| [REGION:tablesection] Cloth Config [/REGION] || +| Wind Method | A selection for how wind should be processed. [INLCUDE:#windmethod] | +| Vertical Constraint Config | Constraint data used for vertical constraints. [INCLUDE:#constrconfig] | +| Horizontal Constraint Config | Constraint data used for horizontal constraints. [INCLUDE:#constrconfig] | +| Bend Constraint Config | Constraint data used for bend constraints. [INCLUDE:#constrconfig] | +| Shear Constraint Config | Constraint data used for shear constraints. [INCLUDE:#constrconfig] | +| Self Collision Radius | Size of the self collision spheres centered on each vertice. | +| Self Collision Stiffness | The stiffness of the spring force that will resolve self collisions. | +| Damping | The damping of particle motions per-axis (XYZ). | +| Friction | The friction of the surface when colliding. | +| Wind Drag Coefficient | Drag coefficient for wind calculations. Higher values mean that wind has more lateral effect on the cloth. | +| Wind Lift Coefficient | Lift coefficient for wind calculations. Higher values make cloth rise easier in the wind. | +| Linear Drag | Drag that is applied to linear particle movement per-axis (XYZ). | +| Angular Drag | Drag that is applied to angular particle movement. Higher values should limit material bending (per-axis XYZ). | +| Linear Inertia Scale | Scale for linear particle inertia. This controls how much movement should translate to linear motion per-axis (XYZ). | +| Angular Inertia Scale | Scale for angular particle inertia. This controls how much movement should translate to angular motion per-axis (XYZ). | +| Centrifugal Inertia Scale | Scale for centrifugal inertia. This controls how much movement should translate to angular motion per-axis (XYZ). | +| Solver Frequency | The frequency of the position solver. Lower values will lead to stretchier, bouncier cloth. | +| Stiffness Frequency | The frequency stiffness calculation. Lower values will degrade stiffness of constraints. | +| Gravity Scale | The scale of gravity's effect on particles. | +| Tether Stiffness | The scale for stiffness of particle tethers between each other. | +| Tether Limit | The scale for the limit of particle tethers. This controls how far they can separate. | +| Collision Thickness | This adjusts the thickness of the cloth, used to adjust collisions. | +| [REGION:tablesection] Import [/REGION] || +| Imported File Path | If using APEX Cloth (.apx/apb) assets from an imported file, this will be the original file location path. | +[/REGION] + + +[/VAR] + + + + + + + + + + + + +Availability: Public +Title:Physics Simulation +Crumbs: %ROOT%, Engine +Description:Subsystem used to calculate collision and simulate physical actors. +Version: 4.16 +parent:Engine +order:8 + +[VAR:Topic] +[OBJECT:Topic] + [PARAM:image] + ![%Engine/Physics:title%](Engine/Physics/physics_topic.png) + [/PARAM] + [PARAM:icon] + ![](%ROOT%/physics_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + %Engine/Physics:title% + [/PARAM] + [PARAM:description] + %Engine/Physics:description% + [/PARAM] + [PARAM:path] + [RELATIVE:Engine/Physics] + [/PARAM] +[/OBJECT] +[/VAR] +[VAR:TopicCompact] +[OBJECT:TopicCompact] + [PARAM:image] + ![%Engine/Physics:title%](Engine/Physics/physics_topic.png) + [/PARAM] + [PARAM:icon] + ![](%ROOT%/physics_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + %Engine/Physics:title% + [/PARAM] + [PARAM:description] + %Engine/Physics:description% + [/PARAM] + [PARAM:path] + [RELATIVE:Engine/Physics] + [/PARAM] +[/OBJECT] +[/VAR] + + +[REGION:banner] +![Physics](physics_landing_banner.png) +[/REGION] + +[EXCERPT:Intro] +Unreal Engine 4 uses the PhysX 3.3 physics engine to drive its physical simulation calculations and perform all collision calculations. PhysX provides the ability to perform accurate collision detection as well as simulate physical interactions between objects within the world. Having physics in your game will help improve the immersion value of every scene, as it helps players believe that they are interacting with the scene and that the scene is responding back in some way or another. +[/EXCERPT:Intro] + +[OBJECT:TopicButtonList] + [PARAM:icon] + ![](%ROOT%/start_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + Essentials + [/PARAM] + [PARAM:links] + * [Collision Responses](Engine/Physics/Collision "%Engine/Physics/Collision:description%") + * [Collision Reference](Engine/Physics/Collision/Reference "%Engine/Physics/Collision/Reference:description%") + * [Physics Constraints User Guide](Engine/Physics/Constraints/ConstraintsUserGuide "%Engine/Physics/Constraints/ConstraintsUserGuide:description%") + * [](Engine/Physics/Constraints/ConstraintsBlueprints "%Engine/Physics/Constraints/ConstraintsBlueprints:description%") + * [](Engine/Physics/Constraints/ConstraintsReference "%Engine/Physics/Constraints/ConstraintsReference:description%") + * [](Engine/Physics/Tracing "%Engine/Physics/Tracing:description%") + * [Damping and Friction](Engine/Physics/Constraints/DampingAndFriction "%Engine/Physics/Constraints/DampingAndFriction:description%") + [/PARAM] +[/OBJECT] + +[OBJECT:TopicButtonList] + [PARAM:icon] + ![](%ROOT%/vehicle_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + Clothing Tools + [/PARAM] + [PARAM:links] + * [Clothing Tool Overview](Engine/Physics/Cloth/Overview "%Engine/Physics/Cloth/Overview:description%") + [/PARAM] +[/OBJECT] + +[OBJECT:TopicButtonList] + [PARAM:icon] + ![](%ROOT%/vehicle_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + Vehicles + [/PARAM] + [PARAM:links] + * [Vehicle User Guide](Engine/Physics/Vehicles/VehicleUserGuide "%Engine/Physics/Vehicles/VehicleUserGuide:description%") + * [Vehicle Content Creation Guide](Engine/Physics/Vehicles/VehcileContentCreation "%Engine/Physics/Vehicles/VehcileContentCreation:description%") + * [Advanced Vehicle Template](Engine/Physics/Vehicles/DoubleWishboneVehicle "%Engine/Physics/Vehicles/DoubleWishboneVehicle:description%") + * [Vehicle API Reference](API:AWheeledVehicle) + [/PARAM] +[/OBJECT] + +[OBJECT:TopicButtonList] + [PARAM:icon] + ![](%ROOT%/content_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + Content Creation + [/PARAM] + [PARAM:links] + * [Physics Bodies](Engine/Physics/PhysicsBodies "%Engine/Physics/PhysicsBodies:description%") + * [Complex Vs. Simple Collision](Engine/Physics/SimpleVsComplex "%Engine/Physics/SimpleVsComplex:description%") + * [Physical Materials](Engine/Physics/PhysicalMaterials "%Engine/Physics/PhysicalMaterials:description%") + * [PhAT User Guide and Reference](Engine/Physics/PhAT "%Engine/Physics/PhAT:description%") + [/PARAM] +[/OBJECT] + +[OBJECT:TopicButtonList] + [PARAM:icon] + ![](%ROOT%/related_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + Related Links + [/PARAM] + [PARAM:links] + * [Static Mesh Editor](Engine/Content/Types/StaticMeshes/Editor "%Engine/Physics/PhAT:description%") + * [FBX Pipeline: Static Meshes](Engine/Content/FBX/StaticMeshes "%Engine/Physics/PhAT:description%") + [/PARAM] +[/OBJECT] + + + + + + diff --git a/Engine/Documentation/Source/Engine/Physics/Cloth/Reference/ClothReference.KOR.udn b/Engine/Documentation/Source/Engine/Physics/Cloth/Reference/ClothReference.KOR.udn new file mode 100644 index 000000000000..c523916f029a --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Cloth/Reference/ClothReference.KOR.udn @@ -0,0 +1,397 @@ +INTSourceChangelist:0 +Availability: Docs +Crumbs: +Title: Cloth Properties Reference +Description: A reference page for the available properties used with Cloth asset configuration. +Type:reference +Version:4.16 +Parent:Engine/Physics +Related:Engine/Physics/Cloth/Overview +Order:2 +Tags:Physics +Tags:Cloth + + + +[OBJECT:modulesectionexpanded] + [PARAMLITERAL:id] + Cloth2 + [/PARAMLITERAL] + [PARAM:heading] + Section Selection + [/PARAM] + [PARAM:content] + %C2% + [/PARAM] +[/OBJECT] + +[VAR:C2] + +[REGION:raw] +![](SectionSelectionMenu.png) +[/REGION] + +The **Section Selection** enables you to select specific Material Elements of your mesh in the Skeletal Mesh Editor's viewport. In this mode, you are able to create, assign, and remove any +cloth assets for this mesh. + +[REGION:simpletable] +| Property | Description | +| --- | --- | +| Apply Clothing Asset | Select an available clothing asset to apply to the selected section. | +| Remove Clothing Asset | Remove the currently assigned clothing asset. | +| Create Clothing Asset from Section | Create a clothing asset from the selected section. [INCLUDE:#createclothsection] | +[/REGION] + +[/VAR] + + + + + +[OBJECT:modulesectionexpanded] + [PARAMLITERAL:id] + Cloth1 + [/PARAMLITERAL] + [PARAM:heading] + Cloth Paint + [/PARAM] + [PARAM:content] + %C1% + [/PARAM] +[/OBJECT] + +[VAR:C1] + +![](ClothPaintPanel.png) + +The **Cloth Paint** properties enable you to define how you paint weights on the cloth asset you've selected. These weights determine how the **Cloth Configuration Properties** use +these values to applie cloth simulations to your mesh. + + +[REGION:simpletable] +| Property | Description | +| --- | --- | +| Enable Paint Tools | This enables the tools needed to paint your cloth values. | +| [REGION:tablesection] Assets [/REGION] || +| Asset LOD | Selection box for the available levels of detail (LOD) where you can paint or create a mask. | +| New Mask | Enables you to create a mask for the selected asset and available level of detail. | +| [REGION:tablesection] Mask [/REGION] || +| Mask Context Menu | Available options for the asset mask. | +| Set Target | Selects the available targets that you can apply the mask to. [INCLUDE:#settarget] | +| Move Up | Moves the mask selection up in the Mask list. | +| Move Down | Moves the mask selection down in the Mask list. | +| Delete | Removes the selected mask from the list. | +| Apply | Applies the mask to the physical mesh. | +| [REGION:tablesection] Brush [/REGION] || +| Radius | Sets the radius that will be used for the painting brush. | +| Strength | Sets the strength of the rush when painting between 0 - 1, with 0 being off and 1 being fully on. | +| Falloff | Sets the amount of falloff around the edge of the brush to apply between 0 - 1, with 0 being no falloff and 1 being a lot of falloff. | +| Enable Brush Flow | Enables the continuous 'flow' where paint is applied from the brush every tick. | +| Ignore Back-Facing | Whether the back-facing triangles should be ignored. | +| [REGION:tablesection] View [/REGION] || +| Color View Mode | Selection used to display the Vertex Colors view modes. [INCLUDE:#colorview] | +| [REGION:tablesection] Cloth Painting [/REGION] || +| Painting Property | Sets the current clothing property which should be visualized and painted. [INCLUDE:#paintingproperty]| +| Paint Tool | Select which type of paint tool to use. [INCLUDE:#brush] [INCLUDE:#gradient]| +[/REGION] + +[/VAR] + + + + + + + + + + +[OBJECT:modulesectionexpanded] + [PARAMLITERAL:id] + Cloth3 + [/PARAMLITERAL] + [PARAM:heading] + Cloth Configuration Properties + [/PARAM] + [PARAM:content] + %C3% + [/PARAM] +[/OBJECT] + +[VAR:C3] + + +![](ClothingProperties.png) + +In the **Asset Details** panel under the **Clothing** section, you can define the various properties of your clothing that is assigned to the mesh's Material Elements. These properties +define how your cloth will react so that you can have different types of cloth that act like silk, burlap, rubber, etc. + +[REGION:simpletable] +| Property | Description | +| --- | --- | +| [REGION:tablesection] Mesh Clothing Assets [/REGION] || +| Name | The name given to the the created or imported Cloth asset. | +| Details | Specific details about the cloth asset, such as the number of vertices simulating, fixed vertices, bones, etc. | +| [REGION:tablesection] Cloth Config [/REGION] || +| Wind Method | A selection for how wind should be processed. [INLCUDE:#windmethod] | +| Vertical Constraint Config | Constraint data used for vertical constraints. [INCLUDE:#constrconfig] | +| Horizontal Constraint Config | Constraint data used for horizontal constraints. [INCLUDE:#constrconfig] | +| Bend Constraint Config | Constraint data used for bend constraints. [INCLUDE:#constrconfig] | +| Shear Constraint Config | Constraint data used for shear constraints. [INCLUDE:#constrconfig] | +| Self Collision Radius | Size of the self collision spheres centered on each vertice. | +| Self Collision Stiffness | The stiffness of the spring force that will resolve self collisions. | +| Damping | The damping of particle motions per-axis (XYZ). | +| Friction | The friction of the surface when colliding. | +| Wind Drag Coefficient | Drag coefficient for wind calculations. Higher values mean that wind has more lateral effect on the cloth. | +| Wind Lift Coefficient | Lift coefficient for wind calculations. Higher values make cloth rise easier in the wind. | +| Linear Drag | Drag that is applied to linear particle movement per-axis (XYZ). | +| Angular Drag | Drag that is applied to angular particle movement. Higher values should limit material bending (per-axis XYZ). | +| Linear Inertia Scale | Scale for linear particle inertia. This controls how much movement should translate to linear motion per-axis (XYZ). | +| Angular Inertia Scale | Scale for angular particle inertia. This controls how much movement should translate to angular motion per-axis (XYZ). | +| Centrifugal Inertia Scale | Scale for centrifugal inertia. This controls how much movement should translate to angular motion per-axis (XYZ). | +| Solver Frequency | The frequency of the position solver. Lower values will lead to stretchier, bouncier cloth. | +| Stiffness Frequency | The frequency stiffness calculation. Lower values will degrade stiffness of constraints. | +| Gravity Scale | The scale of gravity's effect on particles. | +| Tether Stiffness | The scale for stiffness of particle tethers between each other. | +| Tether Limit | The scale for the limit of particle tethers. This controls how far they can separate. | +| Collision Thickness | This adjusts the thickness of the cloth, used to adjust collisions. | +| [REGION:tablesection] Import [/REGION] || +| Imported File Path | If using APEX Cloth (.apx/apb) assets from an imported file, this will be the original file location path. | +[/REGION] + + +[/VAR] + + + + + + + + + + + + +Availability: Public +Title:Physics Simulation +Crumbs: %ROOT%, Engine +Description:Subsystem used to calculate collision and simulate physical actors. +Version: 4.16 +parent:Engine +order:8 + +[VAR:Topic] +[OBJECT:Topic] + [PARAM:image] + ![%Engine/Physics:title%](Engine/Physics/physics_topic.png) + [/PARAM] + [PARAM:icon] + ![](%ROOT%/physics_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + %Engine/Physics:title% + [/PARAM] + [PARAM:description] + %Engine/Physics:description% + [/PARAM] + [PARAM:path] + [RELATIVE:Engine/Physics] + [/PARAM] +[/OBJECT] +[/VAR] +[VAR:TopicCompact] +[OBJECT:TopicCompact] + [PARAM:image] + ![%Engine/Physics:title%](Engine/Physics/physics_topic.png) + [/PARAM] + [PARAM:icon] + ![](%ROOT%/physics_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + %Engine/Physics:title% + [/PARAM] + [PARAM:description] + %Engine/Physics:description% + [/PARAM] + [PARAM:path] + [RELATIVE:Engine/Physics] + [/PARAM] +[/OBJECT] +[/VAR] + + +[REGION:banner] +![Physics](physics_landing_banner.png) +[/REGION] + +[EXCERPT:Intro] +Unreal Engine 4 uses the PhysX 3.3 physics engine to drive its physical simulation calculations and perform all collision calculations. PhysX provides the ability to perform accurate collision detection as well as simulate physical interactions between objects within the world. Having physics in your game will help improve the immersion value of every scene, as it helps players believe that they are interacting with the scene and that the scene is responding back in some way or another. +[/EXCERPT:Intro] + +[OBJECT:TopicButtonList] + [PARAM:icon] + ![](%ROOT%/start_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + Essentials + [/PARAM] + [PARAM:links] + * [Collision Responses](Engine/Physics/Collision "%Engine/Physics/Collision:description%") + * [Collision Reference](Engine/Physics/Collision/Reference "%Engine/Physics/Collision/Reference:description%") + * [Physics Constraints User Guide](Engine/Physics/Constraints/ConstraintsUserGuide "%Engine/Physics/Constraints/ConstraintsUserGuide:description%") + * [](Engine/Physics/Constraints/ConstraintsBlueprints "%Engine/Physics/Constraints/ConstraintsBlueprints:description%") + * [](Engine/Physics/Constraints/ConstraintsReference "%Engine/Physics/Constraints/ConstraintsReference:description%") + * [](Engine/Physics/Tracing "%Engine/Physics/Tracing:description%") + * [Damping and Friction](Engine/Physics/Constraints/DampingAndFriction "%Engine/Physics/Constraints/DampingAndFriction:description%") + [/PARAM] +[/OBJECT] + +[OBJECT:TopicButtonList] + [PARAM:icon] + ![](%ROOT%/vehicle_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + Clothing Tools + [/PARAM] + [PARAM:links] + * [Clothing Tool Overview](Engine/Physics/Cloth/Overview "%Engine/Physics/Cloth/Overview:description%") + [/PARAM] +[/OBJECT] + +[OBJECT:TopicButtonList] + [PARAM:icon] + ![](%ROOT%/vehicle_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + Vehicles + [/PARAM] + [PARAM:links] + * [Vehicle User Guide](Engine/Physics/Vehicles/VehicleUserGuide "%Engine/Physics/Vehicles/VehicleUserGuide:description%") + * [Vehicle Content Creation Guide](Engine/Physics/Vehicles/VehcileContentCreation "%Engine/Physics/Vehicles/VehcileContentCreation:description%") + * [Advanced Vehicle Template](Engine/Physics/Vehicles/DoubleWishboneVehicle "%Engine/Physics/Vehicles/DoubleWishboneVehicle:description%") + * [Vehicle API Reference](API:AWheeledVehicle) + [/PARAM] +[/OBJECT] + +[OBJECT:TopicButtonList] + [PARAM:icon] + ![](%ROOT%/content_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + Content Creation + [/PARAM] + [PARAM:links] + * [Physics Bodies](Engine/Physics/PhysicsBodies "%Engine/Physics/PhysicsBodies:description%") + * [Complex Vs. Simple Collision](Engine/Physics/SimpleVsComplex "%Engine/Physics/SimpleVsComplex:description%") + * [Physical Materials](Engine/Physics/PhysicalMaterials "%Engine/Physics/PhysicalMaterials:description%") + * [PhAT User Guide and Reference](Engine/Physics/PhAT "%Engine/Physics/PhAT:description%") + [/PARAM] +[/OBJECT] + +[OBJECT:TopicButtonList] + [PARAM:icon] + ![](%ROOT%/related_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + Related Links + [/PARAM] + [PARAM:links] + * [Static Mesh Editor](Engine/Content/Types/StaticMeshes/Editor "%Engine/Physics/PhAT:description%") + * [FBX Pipeline: Static Meshes](Engine/Content/FBX/StaticMeshes "%Engine/Physics/PhAT:description%") + [/PARAM] +[/OBJECT] + + + + + + diff --git a/Engine/Documentation/Source/Engine/Physics/Collision/Reference/Reference.INT.udn b/Engine/Documentation/Source/Engine/Physics/Collision/Reference/Reference.INT.udn index d4be16c91cab..829c4f718a90 100644 --- a/Engine/Documentation/Source/Engine/Physics/Collision/Reference/Reference.INT.udn +++ b/Engine/Documentation/Source/Engine/Physics/Collision/Reference/Reference.INT.udn @@ -32,17 +32,9 @@ Below are the properties for the Collision Presets, a sub-category in the Collis ![](collProp.png)(convert:false) -[OBJECT:modulesectionexpanded] - [PARAMLITERAL:id] - coll - [/PARAMLITERAL] - [PARAM:heading] - Collision Presets - [/PARAM] - [PARAM:content] - %p2% - [/PARAM] -[/OBJECT] +### Collision Presets + +%p2% [VAR:p2] diff --git a/Engine/Documentation/Source/Engine/Physics/Collision/Reference/Reference.JPN.udn b/Engine/Documentation/Source/Engine/Physics/Collision/Reference/Reference.JPN.udn index 4644687fbc8c..2ff42b2670e2 100644 --- a/Engine/Documentation/Source/Engine/Physics/Collision/Reference/Reference.JPN.udn +++ b/Engine/Documentation/Source/Engine/Physics/Collision/Reference/Reference.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:2994597 +NTSourceChangelist:3418529 Availability:Public Title:コリジョン反応の参照 Crumbs: %ROOT%, Engine, Engine/Physics, Engine/Physics/Collision @@ -27,23 +27,15 @@ Version:4.9 Collision Properties カテゴリの Collision Presets/Collision Response には非常に多くのプロパティがありますので、分かりやすいように分類しました。 -##プロパティ +## プロパティ 以下は、物理ボディ (BodyInstances) の Collision プロパティのサブ カテゴリの Collision Presets のプロパティです。 ![](collProp.png)(convert:false) -[OBJECT:modulesectionexpanded] - [PARAMLITERAL:id] - coll - [/PARAMLITERAL] - [PARAM:heading] - Collision Presets - [/PARAM] - [PARAM:content] - %p2% - [/PARAM] -[/OBJECT] +### コリジョンのプリセット + +%p2% [VAR:p2] @@ -93,7 +85,7 @@ Collision Properties カテゴリの Collision Presets/Collision Response には | プロパティ | %spacer2% | 説明 | | --- | :---: | :--- | | **Visibility** || 可視性全般をテストするチャンネルです。 | -| **Camera** || カメラから何かをトラックする場合に通常使います。 | +| **Camera** || カメラから何かをトレースする場合に通常使います。 | [/REGION] [/EXCERPT] @@ -116,7 +108,7 @@ Collision Properties カテゴリの Collision Presets/Collision Response には [EXCERPT:colPre] -デフォルトのコリジョン プロファイル、および [Project **Settings (プロジェクト設定)]** -> **[Engine]** -> **[Collision]** -> **[Preset]** (カスタム コリジョン プロファイルは []() を参照) で作成したものがすべてここに表示されます。 +デフォルトのコリジョン プロファイル、および [Project **Settings (プロジェクト設定)]** -> **[Engine]** -> **[Collision]** -> **[Preset]** (カスタム コリジョン プロファイルの作成は []() を参照) で作成したものがすべてここに表示されます。 [REGION:raw] | プロパティ | %spacer2% | 説明 | @@ -125,21 +117,21 @@ Collision Properties カテゴリの Collision Presets/Collision Response には | **Custom...** || このインスタンスに対してすべてのカスタム コリジョンの設定値を設定します。 | | **NoCollision** || コリジョンはありません。 | | **BlockAll** || デフォルトですべてのアクタをブロックする WorldStatic オブジェクトです。すべての新規カスタム チャネルは独自のデフォルト反応を使います。 | -| **OverlapAll** || デフォルトですべてのアクタをブロックする WorldStatic オブジェクトです。すべての新規カスタム チャネルは独自のデフォルト反応を使います。 | +| **OverlapAll** || デフォルトですべてのアクタをオーバーラップする WorldStatic オブジェクトです。すべての新規カスタム チャネルは独自のデフォルト反応を使います。 | | **BlockAllDynamic** || デフォルトですべてのアクタをブロックする WorldDynamic オブジェクトです。すべての新規カスタム チャネルは独自のデフォルト反応を使います。 | -| **OverlapAllDynamic** || デフォルトですべてのアクタをブロックする WorldDynamic オブジェクトです。すべての新規カスタム チャネルは独自のデフォルト反応を使います。 | -| **IngoreOnlyPawn** || ポーンとビークルを無視する WorldDynamic オブジェクトです。他のすべてのチャネルはデフォルトに設定されます。 | -| **OverlapOnlyPawn** || ポーン、カメラ、ビークルにオーバーラップする WorldDynamic オブジェクトです。他のすべてのチャネルはデフォルトに設定されます。 | +| **OverlapAllDynamic** || デフォルトですべてのアクタをオーバーラップする WorldDynamic オブジェクトです。すべての新規カスタム チャネルは独自のデフォルト反応を使います。 | +| **IngoreOnlyPawn** || ポーンとビークルを無視する WorldDynamic オブジェクトです。他のすべてのチャンネルはデフォルトに設定されます。 | +| **OverlapOnlyPawn** || ポーン、カメラ、ビークルにオーバーラップする WorldDynamic オブジェクトです。他のすべてのチャンネルはデフォルトに設定されます。 | | **Pawn** || ポーン オブジェクトです。すべてのプレイ可能なキャラクタや AI のカプセルに使用することができます。 | | **Spectator** || WorldStatic 以外のすべてのアクタを無視する Pawn オブジェクトです。 | -| **CharacterMesh** || キャラクター メッシュに使用する Pawn オブジェクトです。他のすべてのチャネルはデフォルトに設定されます。 | +| **CharacterMesh** || キャラクター メッシュに使用する Pawn オブジェクトです。他のすべてのチャンネルはデフォルトに設定されます。 | | **PhysicsActor** || シミュレーション中のアクタです。 | | **Destructible** || 被破壊アクタです。 | | **InvisibleWall** || 目に見えない WorldStatic オブジェクトです。 | -| **InvisibleWallDynamic** || 目に見える WorldDynamic オブジェクトです。 | -| **Trigger** || トリガに使われる WorldDynamic オブジェクトです。他のすべてのチャネルはデフォルトに設定されます。 | -| **Ragdoll** || シミュレーション中の Skeletal Mesh コンポーネントです。他のすべてのチャネルはデフォルトに設定されます。 | -| **Vehicle** || Vehicle、WorldStatic、WorldDynamic をブロックするVehicle オブジェクトです。他のすべてのチャネルはデフォルトに設定されます。 | +| **InvisibleWallDynamic** || 目に見えない WorldDynamic オブジェクトです。 | +| **Trigger** || トリガーに使われる WorldDynamic オブジェクトです。他のすべてのチャンネルはデフォルトに設定されます。 | +| **Ragdoll** || シミュレーション中の Skeletal Mesh コンポーネントです。他のすべてのチャンネルはデフォルトに設定されます。 | +| **Vehicle** || Vehicle、WorldStatic、WorldDynamic をブロックするVehicle オブジェクトです。他のすべてのチャンネルはデフォルトに設定されます。 | | **UI** || デフォルトですべてのアクタとオーバーラップする WorldStatic オブジェクトです。すべての新規カスタム チャネルは独自のデフォルト反応を使います。 | [/REGION] [/EXCERPT] @@ -148,15 +140,15 @@ Collision Properties カテゴリの Collision Presets/Collision Response には [EXCERPT:colEn] -[Collision Enabled (コリジョンを有効にする)] と、以下の 4 種類のステータスになります。 +[Collision Enabled (コリジョンを有効にする)] と、以下の 4 種類のステートが可能になります。 [REGION:raw] | プロパティ | %spacer2% | 説明 | | --- | :---: | :--- | | **No Collision** || このボディは物理エンジンでは表示されません。空間クエリ (レイキャスト、スウィープ、オーバーラップ) やシミュレーション (剛体ボディ、コンストレイント) には使用できません。移動オブジェクトの場合は特に最高のパフォーマンスが得られる設定です。 | -| **Query Only** || このボディは空間クエリ (レイキャスト、スウィープ、オーバーラップ) のみに使用されます。シミュレーション (剛体ボディ、コンストレイント) には使用できません。キャラクターの移動と物理シミュレーションの必要のないオブジェクトに使うと便利な設定です。物理シミュレーション ツリー内のデータを減らすとパフォーマンスが良くな場合もあります。 | -| **Physics Only** || このボディは物理シミュレーション (剛体ボディ、コンストレイント) のみに使用されます。空間クエリ (レイキャスト、スウィープ、オーバーラップ) には使用できません。ボーンの検出ごとに必要ではないキャラクター上の副次的な動きのシミュレーションに使うと便利な設定です。クエリ ツリー内のデータを減らすとパフォーマンスが良くな場合もあります。 | -| **Collision Enabled** || 空間クエリ (レイキャスト、スウィープ、オーバーラップ) にもシミュレーション (剛体ボディ、コンストレイント) にも使用できません。 | +| **Query Only** || このボディは空間クエリ (レイキャスト、スウィープ、オーバーラップ) のみに使用されます。シミュレーション (剛体ボディ、コンストレイント) には使用できません。キャラクターの移動と物理シミュレーションの必要のないオブジェクトに使うと便利な設定です。物理シミュレーション ツリー内のデータを減らすとパフォーマンスが良くなる場合もあります。 | +| **Physics Only** || このボディは物理シミュレーション (剛体ボディ、コンストレイント) のみに使用されます。空間クエリ (レイキャスト、スウィープ、オーバーラップ) には使用できません。ボーンごとの検出が不要なキャラクター上の副次的な動きのシミュレーションに使うと便利な設定です。クエリ ツリー内のデータを減らすとパフォーマンスが良くなる場合もあります。 | +| **Collision Enabled** || 空間クエリ (レイキャスト、スウィープ、オーバーラップ) にもシミュレーション (剛体ボディ、コンストレイント) にも使用できます。 | [/REGION] [/EXCERPT] @@ -171,7 +163,7 @@ Collision Properties カテゴリの Collision Presets/Collision Response には | --- | :---: | :--- | | **WorldStatic** || 移動しないすべてのアクタに使用します。Static Mesh アクタは、おそらく WorldStatic タイプを持っているであろうアクタの代表例です。 | | **WorldDynamic** || WorldDynamic は、アニメーション、コード、キネマティクスの影響を受けて移動するアクタ タイプに使用します。WorldDynamic アクタの代表例は、エレベータとドアです。 | -| **Pawn** || エンティティを制御するすべてのプレイヤーには Pawn タイプがあります。プレイヤーのキャラクターは、Pawn オブジェクトのタイプを受け取るアクタの代表例です。 | +| **Pawn** ||プレイヤーが制御するエンティティは Pawn タイプを持ちます。プレイヤーのキャラクターは、Pawn オブジェクトのタイプを受け取るアクタの代表例です。 | | **PhysicsBody** || 物理シミュレーションによって移動するアクタです。 | | **Vehicle** || ビークルはこのタイプをデフォルトで受け取ります。 | | **Destructible** || 被破壊メッシュはデフォルトでこのタイプを受け取ります。 | diff --git a/Engine/Documentation/Source/Engine/Physics/Collision/Reference/Reference.KOR.udn b/Engine/Documentation/Source/Engine/Physics/Collision/Reference/Reference.KOR.udn index 496d53b55327..799db2cac84b 100644 --- a/Engine/Documentation/Source/Engine/Physics/Collision/Reference/Reference.KOR.udn +++ b/Engine/Documentation/Source/Engine/Physics/Collision/Reference/Reference.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3418529 Availability: Public Title:콜리전 반응 참고서 Crumbs: %ROOT%, Engine, Engine/Physics, Engine/Physics/Collision @@ -33,17 +33,9 @@ Collision Properties (콜리전 프로퍼티) 카테고리의 Collision Presets( ![](collProp.png)(convert:false) -[OBJECT:modulesectionexpanded] - [PARAMLITERAL:id] - coll - [/PARAMLITERAL] - [PARAM:heading] - Collision Presets (콜리전 프리셋) - [/PARAM] - [PARAM:content] - %p2% - [/PARAM] -[/OBJECT] +### 콜리전 프리셋 + +%p2% [VAR:p2] diff --git a/Engine/Documentation/Source/Engine/Physics/PhAT/HowTo/HowTo.KOR.udn b/Engine/Documentation/Source/Engine/Physics/PhAT/HowTo/HowTo.KOR.udn index 7ca772156836..974b76f56721 100644 --- a/Engine/Documentation/Source/Engine/Physics/PhAT/HowTo/HowTo.KOR.udn +++ b/Engine/Documentation/Source/Engine/Physics/PhAT/HowTo/HowTo.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3149430 +INTSourceChangelist:3459053 Availability: Public Title:피직스 애셋 툴 비법 첫 페이지 Crumbs: %ROOT%, Engine, Engine/Physics, Engine/Physics/PhAT diff --git a/Engine/Documentation/Source/Engine/Physics/PhAT/HowTo/KinematicWithSimulatedParents/KinematicWithSimulatedParents.CHN.udn b/Engine/Documentation/Source/Engine/Physics/PhAT/HowTo/KinematicWithSimulatedParents/KinematicWithSimulatedParents.CHN.udn new file mode 100644 index 000000000000..63bab964fcba --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/PhAT/HowTo/KinematicWithSimulatedParents/KinematicWithSimulatedParents.CHN.udn @@ -0,0 +1,152 @@ +INTSourceChangelist:0 +Availability: Public +Title:Using Kinematic Bodies with Simulated Parents +Crumbs: %ROOT%, Engine +Description:This how-to covers setting up kinematic physics bodies with simulated parents. +parent:Engine/Physics/PhAT/HowTo +order:1 +Version: 4.16 +skilllevel:Intermediate +topic-image:KinematicHowTo_04.png +checkpoint: editorqs +Related: Engine/Physics/PhAT +Related: Engine/Physics/PhAT/Reference +type:how-to +tags:Physics +tags:Kinematic +tags:PhAT + +The [](Engine/Physics/PhAT) provides several different ways in which you can simulate physics bodies including the ability to have kinematic physics bodies with simulated parents. +This enables you to define child bodies that can be driven by animation data while the parents of those bodies are driven by physics simulation data. +This can be useful if you have a character hanging from a ledge playing a hanging idle or traversing across a ledge but what them to react to impulses like falling rocks or other debris and generate a physics based reaction. + +In this How-to, we use kinematic bodies with simulated parents to generate the effect of a character hanging from a ledge while the rest of the body is simulated with physics. + +![](EndResultImage.png) + +## Steps + +[REGION:note] +For this guide, we are using the **Blueprint Third Person Template** project with **Starter Content** enabled. +[/REGION] + +1. In your project in the **Content/Mannequin/Character/Mesh** folder, open the **SK_Mannequin_PhysicsAsset**. + + ![](KinematicHowTo_01.png) + +1. In the **Hierarchy** window, click the **All Bones** drop-down and change it to **Bones With Bodies**. + + ![](KinematicHowTo_02.png) + + This will filter the hierarchy to only show bones with bodies and make it easier to select the bones you want to manipulate. + +1. In the hierarchy list, hold **Ctrl** and select both the **hand_l** and **hand_r** bones, then in the **Details** panel, change the **Physics Type** to **Kinematic**. + + ![](KinematicHowTo_03.png) + + By setting these bones to Kinematic, they will not simulate physics and will follow any animation data. + + Alternatively, you can **Right-click** bones in the hierarchy list and set their **Physics Type** from the roll-out menu. + + ![](KinematicHowTo_04.png) + + This option enables you to set the **Physics Type** property for children bodies below the current bone. + +1. Click on an empty space within the viewport to deselect all bones, then in the **Details** panel, change the **Physics Update Mode** to **Component Transform is Kinematic**. + + ![](KinematicHowTo_05.png) + + This option determines whether the simulation of the root body updates component transform or is kinematic. + +1. From the toolbar, click the **Simulate** button. + + ![](KinematicHowTo_06.png) + + The character in the viewport will slump over and appear to be hanging by their hands. + + ![](KinematicHowTo_07.png) + +1. From the toolbar, click the **Animation** selection icon, then select the **ThirdPersonJump_Loop** animation. + + ![](KinematicHowTo_08.png) + + The hands (because they are set to kinematic) will follow the animation data contained within the ThirdPersonJump_Loop motion. + + ![](KinematicHowTo_09.png) + +1. From the Main Editor window, drag the **SK_Mannequin_PhysicsAsset** into the level and in the **Details** panel, set **Physics Transform Update Mode** to **Component Transform is Kinematic**. + + ![](KinematicHowTo_10.png) + +1. Select the **SkeletalMeshComponent**, then change **Animation Mode** to **Use Animation Asset** and **Anim to Play** to **ThirdPersonJump_Loop**. + + ![](KinematicHowTo_11.png) + +1. Click the **Play** button from the toolbar to play in the editor. + +## End Result + +Below we've placed the character near a ledge when we run and bump into it, it reacts to physics while the hands appear slightly fixed. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 9IrH75GvdU8 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +While the animation we used above not ideal, below we apply the same concept to an animation of a character hanging and traversing a ledge. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 7SB3IrnWOjw + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +The arms and head are set to Kinematic (denoted below with Gold Boxes) while the rest is being simulated. + +![](ExampleSetup.png) + + + + + + + + + + + + + + + + + + + + + diff --git a/Engine/Documentation/Source/Engine/Physics/PhAT/HowTo/KinematicWithSimulatedParents/KinematicWithSimulatedParents.INT.udn b/Engine/Documentation/Source/Engine/Physics/PhAT/HowTo/KinematicWithSimulatedParents/KinematicWithSimulatedParents.INT.udn new file mode 100644 index 000000000000..dfd6dd34ad2b --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/PhAT/HowTo/KinematicWithSimulatedParents/KinematicWithSimulatedParents.INT.udn @@ -0,0 +1,151 @@ +Availability: Public +Title:Using Kinematic Bodies with Simulated Parents +Crumbs: %ROOT%, Engine +Description:This how-to covers setting up kinematic physics bodies with simulated parents. +parent:Engine/Physics/PhAT/HowTo +order:1 +Version: 4.16 +skilllevel:Intermediate +topic-image:KinematicHowTo_04.png +checkpoint: editorqs +Related: Engine/Physics/PhAT +Related: Engine/Physics/PhAT/Reference +type:how-to +tags:Physics +tags:Kinematic +tags:PhAT + +The [](Engine/Physics/PhAT) provides several different ways in which you can simulate physics bodies including the ability to have kinematic physics bodies with simulated parents. +This enables you to define child bodies that can be driven by animation data while the parents of those bodies are driven by physics simulation data. +This can be useful if you have a character hanging from a ledge playing a hanging idle or traversing across a ledge but want them to react to impulses like falling rocks or other debris and generate a physics based reaction. + +In this How-to, we use kinematic bodies with simulated parents to generate the effect of a character hanging from a ledge while the rest of the body is simulated with physics. + +![](EndResultImage.png) + +## Steps + +[REGION:note] +For this guide, we are using the **Blueprint Third Person Template** project with **Starter Content** enabled. +[/REGION] + +1. In your project in the **Content/Mannequin/Character/Mesh** folder, open the **SK_Mannequin_PhysicsAsset**. + + ![](KinematicHowTo_01.png) + +1. In the **Hierarchy** window, click the **All Bones** drop-down and change it to **Bones With Bodies**. + + ![](KinematicHowTo_02.png) + + This will filter the hierarchy to only show bones with bodies and make it easier to select the bones you want to manipulate. + +1. In the hierarchy list, hold **Ctrl** and select both the **hand_l** and **hand_r** bones, then in the **Details** panel, change the **Physics Type** to **Kinematic**. + + ![](KinematicHowTo_03.png) + + By setting these bones to Kinematic, they will not simulate physics and will follow any animation data. + + Alternatively, you can **Right-click** bones in the hierarchy list and set their **Physics Type** from the roll-out menu. + + ![](KinematicHowTo_04.png) + + This option enables you to set the **Physics Type** property for children bodies below the current bone. + +1. Click on an empty space within the viewport to deselect all bones, then in the **Details** panel, change the **Physics Update Mode** to **Component Transform is Kinematic**. + + ![](KinematicHowTo_05.png) + + This option determines whether the simulation of the root body updates component transform or is kinematic. + +1. From the toolbar, click the **Simulate** button. + + ![](KinematicHowTo_06.png) + + The character in the viewport will slump over and appear to be hanging by their hands. + + ![](KinematicHowTo_07.png) + +1. From the toolbar, click the **Animation** selection icon, then select the **ThirdPersonJump_Loop** animation. + + ![](KinematicHowTo_08.png) + + The hands (because they are set to kinematic) will follow the animation data contained within the ThirdPersonJump_Loop motion. + + ![](KinematicHowTo_09.png) + +1. From the Main Editor window, drag the **SK_Mannequin_PhysicsAsset** into the level and in the **Details** panel, set **Physics Transform Update Mode** to **Component Transform is Kinematic**. + + ![](KinematicHowTo_10.png) + +1. Select the **SkeletalMeshComponent**, then change **Animation Mode** to **Use Animation Asset** and **Anim to Play** to **ThirdPersonJump_Loop**. + + ![](KinematicHowTo_11.png) + +1. Click the **Play** button from the toolbar to play in the editor. + +## End Result + +Below we've placed the character near a ledge when we run and bump into it, it reacts to physics while the hands appear slightly fixed. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 9IrH75GvdU8 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +While the animation we used above not ideal, below we apply the same concept to an animation of a character hanging and traversing a ledge. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 7SB3IrnWOjw + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +The arms and head are set to Kinematic (denoted below with Gold Boxes) while the rest is being simulated. + +![](ExampleSetup.png) + + + + + + + + + + + + + + + + + + + + + diff --git a/Engine/Documentation/Source/Engine/Physics/PhAT/HowTo/KinematicWithSimulatedParents/KinematicWithSimulatedParents.JPN.udn b/Engine/Documentation/Source/Engine/Physics/PhAT/HowTo/KinematicWithSimulatedParents/KinematicWithSimulatedParents.JPN.udn new file mode 100644 index 000000000000..63bab964fcba --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/PhAT/HowTo/KinematicWithSimulatedParents/KinematicWithSimulatedParents.JPN.udn @@ -0,0 +1,152 @@ +INTSourceChangelist:0 +Availability: Public +Title:Using Kinematic Bodies with Simulated Parents +Crumbs: %ROOT%, Engine +Description:This how-to covers setting up kinematic physics bodies with simulated parents. +parent:Engine/Physics/PhAT/HowTo +order:1 +Version: 4.16 +skilllevel:Intermediate +topic-image:KinematicHowTo_04.png +checkpoint: editorqs +Related: Engine/Physics/PhAT +Related: Engine/Physics/PhAT/Reference +type:how-to +tags:Physics +tags:Kinematic +tags:PhAT + +The [](Engine/Physics/PhAT) provides several different ways in which you can simulate physics bodies including the ability to have kinematic physics bodies with simulated parents. +This enables you to define child bodies that can be driven by animation data while the parents of those bodies are driven by physics simulation data. +This can be useful if you have a character hanging from a ledge playing a hanging idle or traversing across a ledge but what them to react to impulses like falling rocks or other debris and generate a physics based reaction. + +In this How-to, we use kinematic bodies with simulated parents to generate the effect of a character hanging from a ledge while the rest of the body is simulated with physics. + +![](EndResultImage.png) + +## Steps + +[REGION:note] +For this guide, we are using the **Blueprint Third Person Template** project with **Starter Content** enabled. +[/REGION] + +1. In your project in the **Content/Mannequin/Character/Mesh** folder, open the **SK_Mannequin_PhysicsAsset**. + + ![](KinematicHowTo_01.png) + +1. In the **Hierarchy** window, click the **All Bones** drop-down and change it to **Bones With Bodies**. + + ![](KinematicHowTo_02.png) + + This will filter the hierarchy to only show bones with bodies and make it easier to select the bones you want to manipulate. + +1. In the hierarchy list, hold **Ctrl** and select both the **hand_l** and **hand_r** bones, then in the **Details** panel, change the **Physics Type** to **Kinematic**. + + ![](KinematicHowTo_03.png) + + By setting these bones to Kinematic, they will not simulate physics and will follow any animation data. + + Alternatively, you can **Right-click** bones in the hierarchy list and set their **Physics Type** from the roll-out menu. + + ![](KinematicHowTo_04.png) + + This option enables you to set the **Physics Type** property for children bodies below the current bone. + +1. Click on an empty space within the viewport to deselect all bones, then in the **Details** panel, change the **Physics Update Mode** to **Component Transform is Kinematic**. + + ![](KinematicHowTo_05.png) + + This option determines whether the simulation of the root body updates component transform or is kinematic. + +1. From the toolbar, click the **Simulate** button. + + ![](KinematicHowTo_06.png) + + The character in the viewport will slump over and appear to be hanging by their hands. + + ![](KinematicHowTo_07.png) + +1. From the toolbar, click the **Animation** selection icon, then select the **ThirdPersonJump_Loop** animation. + + ![](KinematicHowTo_08.png) + + The hands (because they are set to kinematic) will follow the animation data contained within the ThirdPersonJump_Loop motion. + + ![](KinematicHowTo_09.png) + +1. From the Main Editor window, drag the **SK_Mannequin_PhysicsAsset** into the level and in the **Details** panel, set **Physics Transform Update Mode** to **Component Transform is Kinematic**. + + ![](KinematicHowTo_10.png) + +1. Select the **SkeletalMeshComponent**, then change **Animation Mode** to **Use Animation Asset** and **Anim to Play** to **ThirdPersonJump_Loop**. + + ![](KinematicHowTo_11.png) + +1. Click the **Play** button from the toolbar to play in the editor. + +## End Result + +Below we've placed the character near a ledge when we run and bump into it, it reacts to physics while the hands appear slightly fixed. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 9IrH75GvdU8 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +While the animation we used above not ideal, below we apply the same concept to an animation of a character hanging and traversing a ledge. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 7SB3IrnWOjw + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +The arms and head are set to Kinematic (denoted below with Gold Boxes) while the rest is being simulated. + +![](ExampleSetup.png) + + + + + + + + + + + + + + + + + + + + + diff --git a/Engine/Documentation/Source/Engine/Physics/PhAT/HowTo/KinematicWithSimulatedParents/KinematicWithSimulatedParents.KOR.udn b/Engine/Documentation/Source/Engine/Physics/PhAT/HowTo/KinematicWithSimulatedParents/KinematicWithSimulatedParents.KOR.udn new file mode 100644 index 000000000000..d8a6bb376aee --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/PhAT/HowTo/KinematicWithSimulatedParents/KinematicWithSimulatedParents.KOR.udn @@ -0,0 +1,151 @@ +INTSourceChangelist:3467926 +Availability: Public +Title:시뮬레이션 부모가 있는 키네마틱 바디 사용법 +Crumbs: %ROOT%, Engine +Description:시뮬레이션 부모가 있는 키네마틱 피직스 바디 셋업 안내입니다. +parent:Engine/Physics/PhAT/HowTo +order:1 +Version: 4.16 +skilllevel:Intermediate +topic-image:KinematicHowTo_04.png +checkpoint: editorqs +Related: Engine/Physics/PhAT +Related: Engine/Physics/PhAT/Reference +type:how-to +tags:Physics +tags:Kinematic +tags:PhAT + +[](Engine/Physics/PhAT) 에는 시뮬레이션 부모가 있는 키네마틱 피직스 바디를 만드는 기능을 포함해서, 피직스 바디 시뮬레이션을 위한 여러가지 다양한 방법이 제공됩니다. +자손 바디는 애니메이션 데이터로, 부모 바디는 피직스 시뮬레이션 데이터로 구동시키는 구성이 가능합니다. +턱에 매달린 캐릭터에 hanging idle 애니메이션을 재생하거나 턱을 따라 이동하는 와중에, 떨어지는 바위나 잔해같은 것의 충격에 반응하여 물리 기반 반응을 만들 수 있습니다. + +여기서는 시뮬레이션 바디가 있는 키네마틱 바디를 사용하여 턱에 걸린 상태에서도 나머지 바디는 물리 시뮬레이션이 적용되는 캐릭터 효과를 만들어 보도록 하겠습니다. + +![](EndResultImage.png) + +## 단계 + +[REGION:note] +여기서는 **블루프린트 삼인칭 템플릿** 프로젝트에 **시작용 콘텐츠** 를 포함시켜 사용하고 있습니다. +[/REGION] + +1. 프로젝트의 **Content/Mannequin/Character/Mesh** 폴더에서 **SK_Mannequin_PhysicsAsset** 을 엽니다. + + ![](KinematicHowTo_01.png) + +1. **계층구조** 창에서 **All Bones** (모든 본) 드롭다운을 클릭한 뒤 **Bones With Bodies** (바디가 있는 본)으로 변경합니다. + + ![](KinematicHowTo_02.png) + + 그러면 계층구조 창에 바디가 있는 본만 표시되어 조작하려는 본을 선택하기가 쉬워집니다. + +1. 계층구조 목록에서 **Ctrl** 을 누르고 **hand_l** 과 **hand_r** 본을 둘 다 선택한 뒤, **디테일** 패널에서 **Physics Type** 을 **Kinematic** 으로 변경합니다. + + ![](KinematicHowTo_03.png) + + 이 본을 키네마틱으로 설정하면, 피직스 시뮬레이션이 아닌 애니메이션 데이터를 따릅니다. + + 또는, 계층구조 목록에서 본을 **우클릭** 하면 펼쳐지는 메뉴에서 그 **Physics Type** 을 설정해도 됩니다. + + ![](KinematicHowTo_04.png) + + 이 옵션은 현재 본 아래 자손 바디의 **Physics Type** 프로퍼티를 설정해 줍니다. + +1. 뷰포트 빈 공간에 클릭하여 모든 본 선택을 해제한 뒤, **디테일** 패널에서 **Physics Update Mode** (피직스 업데이트 모드)를 **Component Transform is Kinematic** (컴포넌트 트랜스폼은 키네마틱)으로 설정합니다. + + ![](KinematicHowTo_05.png) + + 이 옵션은 루트 바디의 시뮬레이션이 컴포넌트 트랜스폼을 업데이트할지 키네마틱인지 결정합니다. + +1. 툴바에서 **시뮬레이트** 버튼을 클릭합니다. + + ![](KinematicHowTo_06.png) + + 뷰포트의 캐릭터가 주저앉으면서 손으로 매달린 듯이 보일 것입니다. + + ![](KinematicHowTo_07.png) + +1. 툴바에서, **애니메이션** 선택 아이콘을 클릭한 뒤, **ThirdPersonJump_Loop** 애니메이션을 선택합니다. + + ![](KinematicHowTo_08.png) + + 손은 (키메나틱으로 설정되어 있으므로) ThirdPersonJump_Loop 모션에 들어있는 애니메이션 데이터를 따를 것입니다. + + ![](KinematicHowTo_09.png) + +1. 메인 에디터 창에서 **SK_Mannequin_PhysicsAsset** 을 끌어 레벨에 놓고, **디테일** 패널에서 **Physics Transform Update Mode** (피직스 트랜스폼 업데이트 모드)를 **Component Transform is Kinematic** (컴포넌트 트랜스폼은 키네마틱)으로 설정합니다. + + ![](KinematicHowTo_10.png) + +1. **SkeletalMeshComponent** 를 선택한 뒤, **Animation Mode** (애니메이션 모드)를 **Use Animation Asset** (애니메이션 애셋)으로, **Anim to Play** (재생할 애님)을 **ThirdPersonJump_Loop** 로 설정합니다. + + ![](KinematicHowTo_11.png) + +1. 툴바의 **플레이** 를 클릭하여 에디터에서 플레이합니다. + +## 최종 결과 + +아래는 턱 근처에 캐릭터를 배치해 두고 달려가 부딛히면 물리 반응을 하면서 손이 살짝 수정되는 것을 볼 수 있습니다. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 9IrH75GvdU8 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +위에 사용한 애니메이션이 이상적이지 않은 반면, 같은 개념을 턱에 매달려 이동하는 캐릭터 애니메이션에 적용한 것이 아래입니다. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 7SB3IrnWOjw + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +팔과 머리는 키네마틱으로 (아래 금색 박스 부분) 설정된 반면, 나머지는 시뮬레이션이 적용됩니다. + +![](ExampleSetup.png) + + + + + + + + + + + + + + + + + + + + diff --git a/Engine/Documentation/Source/Engine/Physics/PhAT/Reference/Properties.INT.udn b/Engine/Documentation/Source/Engine/Physics/PhAT/Reference/Properties.INT.udn index 2df69cbdd2d2..28ef7447785f 100644 --- a/Engine/Documentation/Source/Engine/Physics/PhAT/Reference/Properties.INT.udn +++ b/Engine/Documentation/Source/Engine/Physics/PhAT/Reference/Properties.INT.udn @@ -116,7 +116,7 @@ When the Physics Asset Tool is in Body Mode and a Physics Body is selected, the | **Linear Damping** | "Drag" force added to reduce linear movement. | | **Angular Damping** | "Drag" force added to reduce angular movement. | | **Enable Gravity** | If object should have the force of gravity applied. | -| **Physics Type** | If this is set to **Unfixed** it will use physics. If this is set to **Fixed** it will use kinematic. **Default** will inherit from **OwnerComponent**'s behavior. | +| **Physics Type** | If this is set to **Simulated** it will use physics. If this is set to **Kinematic** it will use kinematic. **Default** will inherit from **OwnerComponent**'s behavior. | | **Double Sided Geometry** | If true, the physics triangle mesh will use double sided faces when doing scene queries. Thsi is useful for planes and single sided meshes that need traces to work on both sides. | | **Simple Collision Physical Material** | The **Physical Material** to use for simple collision on this body. | [/REGION] diff --git a/Engine/Documentation/Source/Engine/Physics/PhAT/Reference/Properties.KOR.udn b/Engine/Documentation/Source/Engine/Physics/PhAT/Reference/Properties.KOR.udn index 464fe61655b3..f003116829cd 100644 --- a/Engine/Documentation/Source/Engine/Physics/PhAT/Reference/Properties.KOR.udn +++ b/Engine/Documentation/Source/Engine/Physics/PhAT/Reference/Properties.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3255748 +INTSourceChangelist:3459053 Availability: Public Title:피직스 애셋 프로퍼티 참고서 Crumbs: %ROOT%, Engine, Engine/Physics, Engine/Physics/PhAT @@ -117,7 +117,7 @@ SkillLevel: Beginner | **Linear Damping** | 직선 제동 - 직선 운동을 감소시키기 위해 더할 인력입니다. | | **Angular Damping** | 각 제동 - 각 운동을 감소시키기 위해 더할 인력입니다. | | **Enable Gravity** | 중력 켜기 - 오브젝트에 중력을 적용시킵니다. | -| **Physics Type** | 피직스 유형 - **Unfixed** 로 설정되면 피직스를 사용합니다. **Fixed** 로 설정되면 키네마틱을 사용합니다. **Default** 는 **OwnerComponent** 작동방식을 상속합니다. | +| **Physics Type** | 피직스 유형 - **Simulated** 로 설정되면 피직스를 사용합니다. **Kinematic** 으로 설정되면 키네마틱을 사용합니다. **Default** 는 **OwnerComponent** 작동방식을 상속합니다. | | **Double Sided Geometry** | 양면 지오메트리 - true 면 피직스 트라이앵글 메시는 씬 쿼리를 할 때 양면을 사용합니다. 양쪽 면에 통하는 트레이스가 필요한 단면 메시 또는 면에 좋습니다. | | **Simple Collision Physical Material** | 단순 콜리전 피지컬 머티리얼 - 이 바디의 단순 콜리전에 사용할 **피지컬 머티리얼** 입니다. | [/REGION] diff --git a/Engine/Documentation/Source/Engine/Physics/Physics.INT.udn b/Engine/Documentation/Source/Engine/Physics/Physics.INT.udn index f5910fd11d0c..e52178c2f26f 100644 --- a/Engine/Documentation/Source/Engine/Physics/Physics.INT.udn +++ b/Engine/Documentation/Source/Engine/Physics/Physics.INT.udn @@ -2,8 +2,10 @@ Availability: Public Title:Physics Simulation Crumbs: %ROOT%, Engine Description:Subsystem used to calculate collision and simulate physical actors. -Version: 4.9 +Version: 4.16 +Type:landing parent:Engine +tags:Physics order:8 [VAR:Topic] @@ -72,6 +74,18 @@ Unreal Engine 4 uses the PhysX 3.3 physics engine to drive its physical simulati [/PARAM] [/OBJECT] +[OBJECT:TopicButtonList] + [PARAM:icon] + ![](%ROOT%/vehicle_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + Clothing Tools + [/PARAM] + [PARAM:links] + * [Clothing Tool Overview](Engine/Physics/Cloth/Overview "%Engine/Physics/Cloth/Overview:description%") + [/PARAM] +[/OBJECT] + [OBJECT:TopicButtonList] [PARAM:icon] ![](%ROOT%/vehicle_icon.png)(convert:false) @@ -82,6 +96,7 @@ Unreal Engine 4 uses the PhysX 3.3 physics engine to drive its physical simulati [PARAM:links] * [Vehicle User Guide](Engine/Physics/Vehicles/VehicleUserGuide "%Engine/Physics/Vehicles/VehicleUserGuide:description%") * [Vehicle Content Creation Guide](Engine/Physics/Vehicles/VehcileContentCreation "%Engine/Physics/Vehicles/VehcileContentCreation:description%") + * [Simple Wheeled Vehicle Movement Component](Engine/Physics/Vehicles/SimpleWheeledVehicleMovementComponent "%Engine/Physics/Vehicles/SimpleWheeledVehicleMovementComponent:description%") * [Advanced Vehicle Template](Engine/Physics/Vehicles/DoubleWishboneVehicle "%Engine/Physics/Vehicles/DoubleWishboneVehicle:description%") * [Vehicle API Reference](API:AWheeledVehicle) [/PARAM] diff --git a/Engine/Documentation/Source/Engine/Physics/Physics.JPN.udn b/Engine/Documentation/Source/Engine/Physics/Physics.JPN.udn index 6fb1a44572aa..b37c641c9ddc 100644 --- a/Engine/Documentation/Source/Engine/Physics/Physics.JPN.udn +++ b/Engine/Documentation/Source/Engine/Physics/Physics.JPN.udn @@ -1,9 +1,9 @@ -INTSourceChangelist:3317470 +INTSourceChangelist:3454591 Availability:Public Title:物理のシミュレーション Crumbs: %ROOT%, Engine Description:コリジョンを計算し、物理アクタをシミュレートするために使用するシステム -Version:4.9 +Version:4.16 parent:Engine order:8 @@ -83,8 +83,9 @@ order:8 [PARAM:links] * [ビークル ユーザー ガイド](Engine/Physics/Vehicles/VehicleUserGuide "%Engine/Physics/Vehicles/VehicleUserGuide:description%") * [ビークル コンテンツ作成ガイド](Engine/Physics/Vehicles/VehcileContentCreation "%Engine/Physics/Vehicles/VehcileContentCreation:description%") + * [シンプルな車輪付きビークルの移動コンポーネント](Engine/Physics/Vehicles/SimpleWheeledVehicleMovementComponent "%Engine/Physics/Vehicles/SimpleWheeledVehicleMovementComponent:description%") * [高度なビークル テンプレート](Engine/Physics/Vehicles/DoubleWishboneVehicle "%Engine/Physics/Vehicles/DoubleWishboneVehicle:description%") - * [Vehicle API Reference](API:AWheeledVehicle) + * [ビークルの API リファレンス](API:AWheeledVehicle) [/PARAM] [/OBJECT] diff --git a/Engine/Documentation/Source/Engine/Physics/Physics.KOR.udn b/Engine/Documentation/Source/Engine/Physics/Physics.KOR.udn index f5fcacee79d2..9284ae89d6dd 100644 --- a/Engine/Documentation/Source/Engine/Physics/Physics.KOR.udn +++ b/Engine/Documentation/Source/Engine/Physics/Physics.KOR.udn @@ -1,10 +1,12 @@ -INTSourceChangelist:3317470 +INTSourceChangelist:3469699 Availability: Public Title:피직스 시뮬레이션 Crumbs: %ROOT%, Engine Description:피지컬 액터의 시뮬레이션과 콜리전 계산에 사용되는 서브시스템 입니다. -Version: 4.9 +Version: 4.16 +Type:landing parent:Engine +tags:Physics order:8 [VAR:Topic] @@ -73,6 +75,18 @@ order:8 [/PARAM] [/OBJECT] +[OBJECT:TopicButtonList] + [PARAM:icon] + ![](%ROOT%/vehicle_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + 클로딩 툴 + [/PARAM] + [PARAM:links] + * [](Engine/Physics/Cloth/Overview "%Engine/Physics/Cloth/Overview:description%") + [/PARAM] +[/OBJECT] + [OBJECT:TopicButtonList] [PARAM:icon] ![](%ROOT%/vehicle_icon.png)(convert:false) @@ -83,6 +97,7 @@ order:8 [PARAM:links] * [](Engine/Physics/Vehicles/VehicleUserGuide "%Engine/Physics/Vehicles/VehicleUserGuide:description%") * [](Engine/Physics/Vehicles/VehcileContentCreation "%Engine/Physics/Vehicles/VehcileContentCreation:description%") + * [](Engine/Physics/Vehicles/SimpleWheeledVehicleMovementComponent "%Engine/Physics/Vehicles/SimpleWheeledVehicleMovementComponent:description%") * [](Engine/Physics/Vehicles/DoubleWishboneVehicle "%Engine/Physics/Vehicles/DoubleWishboneVehicle:description%") * [Vehicle API Reference](API:AWheeledVehicle) [/PARAM] diff --git a/Engine/Documentation/Source/Engine/Physics/PhysicsBodies/Reference/PhysicsBodiesRef.CHN.udn b/Engine/Documentation/Source/Engine/Physics/PhysicsBodies/Reference/PhysicsBodiesRef.CHN.udn index f7be9f2b2970..f5afe9f51e0d 100644 --- a/Engine/Documentation/Source/Engine/Physics/PhysicsBodies/Reference/PhysicsBodiesRef.CHN.udn +++ b/Engine/Documentation/Source/Engine/Physics/PhysicsBodies/Reference/PhysicsBodiesRef.CHN.udn @@ -1,16 +1,16 @@ -INTSourceChangelist:0 -Availability: Public -Title:Physics Bodies Reference +INTSourceChangelist:3262203 +Availability:Public +Title:物理形体参考 Crumbs: %ROOT% -Description:Physics Body, or Body Instance, property reference. +Description:物理形体、或形体实例、属性参考。 topic-image:Engine/Physics/physics_topic.png -This page contains a reference listing of properties in the Physics and Collision categories of properties. If you are looking for reference on Collision Responses or Collision Presets please see: [](Engine/Physics/Collision/Reference). +本页参考列出了属性下 Physics and Collision 类目中的所有属性。如需了解碰撞响应或碰撞预设的参考,请查阅[碰撞响应](Engine/Physics/Collision/Reference)。 -## Properties +## 属性 -Below are the properties for Physics Bodies (Body Instances) separated by major category. +以下是按主要类目区分的物理形体(形体实例)属性。 [EXCERPT:PropPhysicsCat] [OBJECT:modulesectionexpanded] @@ -30,17 +30,17 @@ Below are the properties for Physics Bodies (Body Instances) separated by major ![](physicsProps.png) [REGION:raw] -| Property | %spacer% | Description | -| --- | :---: | :--- | +| 属性 | %spacer% | 描述 | +| --- | :---:| :--- | | **Simulate Physics** || [TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"BodyInstance:bSimulatePhysics" output:"block")] | -| **Mass in KG** || Mass of the body in KG. | +| **Mass in KG** || 形体的质量按千克计。| | **Angular Damping** || [TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"BodyInstance:AngularDamping" output:"block")] | | **Linear Damping** || [TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"BodyInstance:LinearDamping" output:"block")] | | **Enable Gravity** || [TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"BodyInstance:bEnableGravity" output:"block")] | -|[REGION:tablesection]**Constraints**[/REGION]||| +|[REGION:tablesection]**约束**[/REGION]||| | **Lock Position** || [INCLUDE:#lockpos] | | **Lock Rotation** || [INCLUDE:#lockrot] | -| **Mode** || [INCLUDE:#mode] | +| **模式** || [INCLUDE:#mode] | [/REGION] ### Advanced @@ -48,8 +48,8 @@ Below are the properties for Physics Bodies (Body Instances) separated by major ![](physicsPropsAdv.png) [REGION:raw] -| Property | %spacer% | Description | -| --- | :---: | :--- | +| 属性 | %spacer% | 描述 | +| --- | :---:| :--- | | **Auto Weld** || [TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"BodyInstance:bAutoWeld" output:"block")] | | **Start Awake** ||[TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"BodyInstance:bStartAwake" output:"block")] | | **Center Of Mass Offset** ||[TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"BodyInstance:COMNudge" output:"block")] | @@ -59,7 +59,7 @@ Below are the properties for Physics Bodies (Body Instances) separated by major | **Override Max Depenetration Velocity** ||[TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"BodyInstance:bOverrideMaxDepenetrationVelocity" output:"block")] | | **Max Depenetration Velocity** ||[TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"BodyInstance:MaxDepenetrationVelocity" output:"block")] | | **Override Walkable Slope on Instance** ||[TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"BodyInstance:bOverrideWalkableSlopeOnInstance" output:"block")] | -| **Walkable Slope Override** || [TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"BodySetup:WalkableSlopeOverride" output:"block")] See the **[](Engine/Physics/WalkableSlope)** documentation for usage information. | +| **Walkable Slope Override** || [TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"BodySetup:WalkableSlopeOverride" output:"block")] 查阅 **[](Engine/Physics/WalkableSlope)** 文档中的使用信息。| | **Walkable Slope Behavior** || [TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"WalkableSlopeOverride:WalkableSlopeBehavior" output:"block")] | | **Walkable Slope Angle** || [TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"WalkableSlopeOverride:WalkableSlopeAngle" output:"block")] | | **Sleep Family** || [TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"BodyInstance:SleepFamily" output:"block")] | @@ -89,12 +89,12 @@ Below are the properties for Physics Bodies (Body Instances) separated by major ![](collisionProps.png) [REGION:raw] -| Property | %spacer% | Description | -| --- | :---: | :--- | +| 属性 | %spacer% | 描述 | +| --- | :---:| :--- | | **Simulation Generates Hit Events** || [TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"BodyInstance:bNotifyRigidBodyCollision" output:"block")] | | **Phys Material Override** || [TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"BodyInstance:PhysMaterialOverride" output:"block")] | | **Generate Overlap Events** || [TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"PrimitiveComponent:bGenerateOverlapEvents" output:"block")] | -| **Collision Responses** || See the **[](Engine/Physics/Collision/Reference)** documentation for more information. | +| **Collision Responses** || 查阅 **[](Engine/Physics/Collision/Reference)** 文档中的详细内容。| [/REGION] ### Advanced @@ -102,15 +102,15 @@ Below are the properties for Physics Bodies (Body Instances) separated by major ![](collisionPropsAdv.png) [REGION:raw] -| Property | %spacer% | Description | -| --- | :---: | :--- | +| 属性 | %spacer% | 描述 | +| --- | :---:| :--- | | **Use CCD** || [TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"BodyInstance:bUseCCD" output:"block")] | | **Always Create Physics State** || [TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"PrimitiveComponent:bAlwaysCreatePhysicsState" output:"block")] | | **Multi Body Overlap** || [TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"PrimitiveComponent:bMultiBodyOverlap" output:"block")] | | **Check Async Scene On Move** || [TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"PrimitiveComponent:bCheckAsyncSceneOnMove" output:"block")] | | **Trace Complex On Move** || [TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"PrimitiveComponent:bTraceComplexOnMove" output:"block")] | | **Return Material On Move** || [TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"PrimitiveComponent:bReturnMaterialOnMove" output:"block")] | -| **Can Ever Affect Navigation** || Whether this component can potentially influence navigation | +| **Can Ever Affect Navigation** || 确定该组件是否对导航存在潜在影响 | [/REGION] @@ -126,7 +126,7 @@ Below are the properties for Physics Bodies (Body Instances) separated by major [TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"BodyInstance:bLockTranslation" output:"block")] [REGION:simpletable] -| Property | Description | +| 属性 | 描述 | | --- | :--- | | **Lock X Translation** | [TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"BodyInstance:bLockXTranslation" output:"block")] | | **Lock Y Translation** | [TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"BodyInstance:bLockYTranslation" output:"block")] | @@ -139,7 +139,7 @@ Below are the properties for Physics Bodies (Body Instances) separated by major [TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"BodyInstance:bLockRotation" output:"block")] [REGION:simpletable] -| Property | Description | +| 属性 | 描述 | | --- | :--- | | **Lock X Rotation** | [TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"BodyInstance:bLockXRotation" output:"block")] | | **Lock Y Rotation** | [TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"BodyInstance:bLockYRotation" output:"block")] | @@ -152,15 +152,15 @@ Below are the properties for Physics Bodies (Body Instances) separated by major [TEXT(type:"tooltip" namespace:"UObjectToolTips" key:"BodyInstance:DOFMode" output:"block")] [REGION:simpletable] -| Property | Description | +| 属性 | 描述 | | --- | :--- | -| **Default** | Inherits the degrees of freedom from the project settings. | -| **Six DOF** | Specifies which axis to freeze rotation and movement along. | -| **YZPlane** | Allows 2D movement along the Y-Z plane. | -| **XZPlane** | Allows 2D movement along the X-Z plane. | -| **XYPlane** | Allows 2D movement along the X-Y plane. | -| **Custom Plane** | Allows 2D movement along the plane of a given normal. | -| **None** | No constraints. | +| **Default** | 从项目设置继承自由度。| +| **Six DOF** | 指定冻结旋转和运动所沿的轴。| +| **YZPlane** |允许沿 Y-Z 面的 2D 运动。| +| **XZPlane** | 允许沿 X-Z 面的 2D 运动。| +| **XYPlane** | 允许沿 X-Y 面的 2D 运动。| +| **Custom Plane** | 允许沿特定法线面的 2D 运动。| +| **None** | 无约束。| [/REGION] [/EXCERPT] ---> \ No newline at end of file +--> diff --git a/Engine/Documentation/Source/Engine/Physics/Tracing/Tracing.INT.udn b/Engine/Documentation/Source/Engine/Physics/Tracing/Tracing.INT.udn index 2659ec43e12e..1ad35844a4eb 100644 --- a/Engine/Documentation/Source/Engine/Physics/Tracing/Tracing.INT.udn +++ b/Engine/Documentation/Source/Engine/Physics/Tracing/Tracing.INT.udn @@ -1,7 +1,7 @@ Availability: Public -Title:Traces (Raycasts) +Title:Traces with Raycasts Crumbs: -Description:The landing page for Physics Traces (Raycasts). +Description:The landing page for Physics Traces. version: 4.14 Parent:Engine/Physics type:landing diff --git a/Engine/Documentation/Source/Engine/Physics/Tracing/Tracing.JPN.udn b/Engine/Documentation/Source/Engine/Physics/Tracing/Tracing.JPN.udn index 8c0cdeb381db..a0694bda6859 100644 --- a/Engine/Documentation/Source/Engine/Physics/Tracing/Tracing.JPN.udn +++ b/Engine/Documentation/Source/Engine/Physics/Tracing/Tracing.JPN.udn @@ -1,8 +1,8 @@ -INTSourceChangelist:3317466 +INTSourceChangelist:3429244 Availability:Public -Title:トレース(レイキャスト) -Crumbs: %ROOT% -Description:物理のトレース(レイキャスト)のランディング ページ +Title:レイキャストによるトレース +Crumbs: +Description:物理のトレースのランディング ページ version:4.14 Parent:Engine/Physics type:landing @@ -10,19 +10,21 @@ order:4 tags:Physics tags:Tracing tags:Raycast +tags:Gameplay topic-image:trace_topic.png social-image:trace_social.png ![](traceTop.png)(convert:false) -ゲーム中にプレイヤー キャラクターが何かを見ているかどうかを判断したい状況があるかもしれません。見た場合には、何らかの方法でゲーム ステートを変更します (例えば、プレイヤーがそれを見ると強調表示するなど)。あるいは、敵にプレイヤー キャラクターが見えているのかどうかを判断したい状況があります。見えている場合は、何らかの方法でプレイヤー キャラクターへの射撃または交戦を開始します。レイキャスト (またはトレース) を使って両方のシナリオを実現することができます。 2 点間のジオメトリを探知する見えない光線を放ち、ジオメトリにヒットすれば何をヒットしたかを返して、それに対して何かをすることができます。 +ゲーム中にプレイヤー キャラクターが何かを見ているかどうかを判断したい状況があるかもしれません。見た場合には、何らかの方法でゲーム ステートを変更します (例えば、プレイヤーがそれを見ると強調表示するなど)。あるいは、敵にプレイヤー キャラクターが見えているのかどうかを判断したい状況があります。見えている場合は、何らかの方法でプレイヤー キャラクターへの射撃または交戦を開始します。**トレース** ( **レイキャスト**) を使って両方のシナリオを実現することができます。 2 点間のジオメトリを探知する見えない光線を放ち、ジオメトリにヒットすれば何をヒットしたかを返して、それに対して何かをすることができます。 -トレース実行時に利用できるオプションがいくつかあります。オブジェクト ヒットを返されるとオブジェクトとのコリジョンをチェックするためにトレースを実行したり、またはオブジェクトが指定した Trace Channel に反応するように設定された場合のみ (Collision Settings (コリジョン設定) で設定可能)、オブジェクト ヒットがヒット情報を返すように Trace Channel でトレースを実行することができます。 +トレース実行時に利用できる様々なオプションがあります。オブジェクト ヒットを返されるとオブジェクトとのコリジョンをチェックするためにトレースを実行したり、またはオブジェクトが指定した Trace Channel に反応するように設定された場合のみ (Collision Settings (コリジョン設定) で設定可能)、オブジェクト ヒットがヒット情報を返すように Trace Channel でトレースを実行することができます。 オブジェクトまたは Trace Channel でトレースを実行する他に、 Single ヒットまたは Multi ヒットを探知するためにトレースを実行することができます。 Single Trace は、トレースからひとつのヒット結果を返し、 Multi Trace は複数のヒット結果を返します。トレースを使えば、使用する光線のタイプ、すなわち直線、ボックス、カプセル、球体を指定することができます。 ## トピックス -ブループリントを使ったレイキャストについては、以下を参照してください。 +ブループリントを使ったレイキャストについては、以下のリンクを参照してください。 -[DIR(output:"topic" parent:"Engine/Physics/Tracing" org:"hierarchy" end:"1")] +%Engine/Physics/Tracing/Overview:topic% +%Engine/Physics/Tracing/HowTo:topic% \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Tracing/Tracing.KOR.udn b/Engine/Documentation/Source/Engine/Physics/Tracing/Tracing.KOR.udn index 8870bd3c7232..b73081ab24f3 100644 --- a/Engine/Documentation/Source/Engine/Physics/Tracing/Tracing.KOR.udn +++ b/Engine/Documentation/Source/Engine/Physics/Tracing/Tracing.KOR.udn @@ -1,8 +1,8 @@ -INTSourceChangelist:3346514 +INTSourceChangelist:3429244 Availability: Public -Title:트레이스, 레이캐스트 +Title:레이캐스트와 트레이스 Crumbs: -Description:피직스 트레이스, 또는 레이캐스트 홈 페이지입니다. +Description:피직스 트레이스 홈 페이지입니다. version: 4.14 Parent:Engine/Physics type:landing diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/SimpleWheeledVehicleMovementComponent/SimpleWheeledVehicleMovementComponent.CHN.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/SimpleWheeledVehicleMovementComponent/SimpleWheeledVehicleMovementComponent.CHN.udn new file mode 100644 index 000000000000..305bb3599db1 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/SimpleWheeledVehicleMovementComponent/SimpleWheeledVehicleMovementComponent.CHN.udn @@ -0,0 +1,95 @@ +INTSourceChangelist:0 +Availability:Docs +Title:Simple Wheeled Vehicle Movement Component +Crumbs: +Description:The Unreal Engine 4 Blueprint Vehicles User Guide for SimpleWheeledVehicleMovement Component. +Parent: Engine/Vehicles/ +type:how-to +prereq: Engine/Physics/Vehicles/VehicleUserGuide +Version: 4.15 +SkillLevel: Advanced +tags: vehicles + +The **SimpleWheeledVehicleMovement** component provides wheel suspension and tire friction without the complexities of engine or drivetrain simulation. Instead, it +lets you easily apply torque to individual tires for components inheriting from Wheeled Vehicle Movement component, which can give you vehicle-like movement +to arbitrary components without having to rely on the Wheeled Vehicle Actor class. + +In order to setup and use SimpleWheeledVehicleMovement component, you will first need to complete the following steps outlined in the [Vehicle User Guide](Engine/Physics/Vehicles/VehicleUserGuide). +Use these steps to make sure your vehicle is setup properly before proceeding: + +* [Creating the Wheel Blueprints](https://docs.unrealengine.com/latest/INT/Engine/Physics/Vehicles/VehicleUserGuide/#creatingthewheelblueprints) +* [Creating the TireType Data Asset](https://docs.unrealengine.com/latest/INT/Engine/Physics/Vehicles/VehicleUserGuide/#creatingthetiretypedataasset) +* [Creating the Animation Blueprint](https://docs.unrealengine.com/latest/INT/Engine/Physics/Vehicles/VehicleUserGuide/#creatingtheanimationblueprint) +* [Editing the Animation Blueprint](https://docs.unrealengine.com/latest/INT/Engine/Physics/Vehicles/VehicleUserGuide/#editingtheanimationblueprint) + +### Creating a Simple Wheeled Vehicle Blueprints + +To create a new Simple Wheeled Vehicle Blueprint, in the **Content Browser** click the **Add New** button, navigate to and click on **Blueprint Class**, and finally, select **Pawn** from the options in the Pick Parent Class window. + +[REGION:raw] +![](SimpleWheel_CreatePawnBP.png)(w:850) +[/REGION] + + +### Editing the Simple Wheeled Vehicle Blueprint + +Now that we've created a Simple Wheeled Vehicle Blueprint, we can start to set up our simple vehicle movement. So, if your vehicle mesh is ready and you have already setup your wheels, then you will be able to +apply vehicle-like properties to arbitrary objects that do not require the drive-train or simulation of a normal vehicle. + +Double-click your **SimpleWheeledVehicle Blueprint** from your Content Browser to bring up the Blueprint Editor. + +1. In the **Components** window, use the **Add Component** button and add a **Skeletal Mesh** component. + + [REGION:raw] + ![](SimpleVehicle_AddSkelComp.png)(w:850) + [/REGION] + + Then click and drag the **Skeletal Mesh** component onto the **DefaultSceneRoot** component. This will make it the root for this Blueprint. + + [REGION:raw] + ![](SimpleVehicle_SkelSceneRoot.png)(w:650) + [/REGION] + +1. With your Skeletal Mesh component selected, set the **Anim Class** to your vehicle's Animation Blueprint and then assign your Skeletal Mesh. + + [REGION:raw] + ![](SimpleVehicle_AssignAnimBP.png)(w:850) + [/REGION] + +1. Return to the **Components** window and add **SimpleWheeledVehicleMovement** component. + + [REGION:raw] + ![](SimpleVehicle_AddSWComp.png)(w:850) + [/REGION] + +1. With the SimpleWheeledVehicleMovement component selected, in the **Vehicle Setup** section click the down arrow to expand **Wheel Setups** and then click the **+** to add your wheels. + +1. For each wheel (0-3): + + * Set the **Wheel Class** to one of the wheel Blueprints you created. + * Set the **Bone Name** to the name of the joint that should be controlled by the wheel. + + [REGION:raw] + ![](wheelsSetup.png) + [/REGION] + [REGION:caption] + The Bone Name in the above image is specific to this Skeletal Mesh. + [/REGION] + + The order you assigned the wheels has no bearing on if it is a front or rear wheel, only the Bone Name and Wheel Class have any effect. + + [REGION:tip] + If you need more than 4 wheels, you can click the "**+**" icon next to the **Wheel Setups** property to add more. + [/REGION] + +At this point, assuming your vehicle is not substantially larger than a minivan, the default values will be a good starting point to start testing. + + +### Applying Torque to Wheels + +In order for your simple vehicle to move, you'll need to apply torque to the individual tires that you want to move. You can do this by pulling off your +SimpleWheeledVehicleMovement component and using **Set Drive Torque**. Use the **Drive Torque** value to set how much torque and the **Wheel Index** to +assign a wheel that will have the torque applied to. The Wheel Index corresponds to the index number in the Wheel Setups section of the SimpleWheeledVehicleMovement's Details Panel. + + +![](SimpleVehicle_SetDriveTorque.png)(w:650) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/SimpleWheeledVehicleMovementComponent/SimpleWheeledVehicleMovementComponent.INT.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/SimpleWheeledVehicleMovementComponent/SimpleWheeledVehicleMovementComponent.INT.udn new file mode 100644 index 000000000000..d7aae03f6917 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/SimpleWheeledVehicleMovementComponent/SimpleWheeledVehicleMovementComponent.INT.udn @@ -0,0 +1,94 @@ +Availability:Public +Title:Simple Wheeled Vehicle Movement Component +Crumbs: +Description:The Unreal Engine 4 Blueprint Vehicles User Guide for SimpleWheeledVehicleMovement Component. +Parent: Engine/Vehicles/ +type:how-to +prereq: Engine/Physics/Vehicles/VehicleUserGuide +Version: 4.15 +SkillLevel: Advanced +tags: vehicles + +The **SimpleWheeledVehicleMovement** component provides wheel suspension and tire friction without the complexities of engine or drivetrain simulation. Instead, it +lets you easily apply torque to individual tires for components inheriting from Wheeled Vehicle Movement component, which can give you vehicle-like movement +to arbitrary components without having to rely on the Wheeled Vehicle Actor class. + +In order to setup and use SimpleWheeledVehicleMovement component, you will first need to complete the following steps outlined in the [Vehicle User Guide](Engine/Physics/Vehicles/VehicleUserGuide). +Use these steps to make sure your vehicle is setup properly before proceeding: + +* [Creating the Wheel Blueprints](https://docs.unrealengine.com/latest/INT/Engine/Physics/Vehicles/VehicleUserGuide/#creatingthewheelblueprints) +* [Creating the TireType Data Asset](https://docs.unrealengine.com/latest/INT/Engine/Physics/Vehicles/VehicleUserGuide/#creatingthetiretypedataasset) +* [Creating the Animation Blueprint](https://docs.unrealengine.com/latest/INT/Engine/Physics/Vehicles/VehicleUserGuide/#creatingtheanimationblueprint) +* [Editing the Animation Blueprint](https://docs.unrealengine.com/latest/INT/Engine/Physics/Vehicles/VehicleUserGuide/#editingtheanimationblueprint) + +### Creating a Simple Wheeled Vehicle Blueprints + +To create a new Simple Wheeled Vehicle Blueprint, in the **Content Browser** click the **Add New** button, navigate to and click on **Blueprint Class**, and finally, select **Pawn** from the options in the Pick Parent Class window. + +[REGION:raw] +![](SimpleWheel_CreatePawnBP.png)(w:850) +[/REGION] + + +### Editing the Simple Wheeled Vehicle Blueprint + +Now that we've created a Simple Wheeled Vehicle Blueprint, we can start to set up our simple vehicle movement. So, if your vehicle mesh is ready and you have already setup your wheels, then you will be able to +apply vehicle-like properties to arbitrary objects that do not require the drive-train or simulation of a normal vehicle. + +Double-click your **SimpleWheeledVehicle Blueprint** from your Content Browser to bring up the Blueprint Editor. + +1. In the **Components** window, use the **Add Component** button and add a **Skeletal Mesh** component. + + [REGION:raw] + ![](SimpleVehicle_AddSkelComp.png)(w:850) + [/REGION] + + Then click and drag the **Skeletal Mesh** component onto the **DefaultSceneRoot** component. This will make it the root for this Blueprint. + + [REGION:raw] + ![](SimpleVehicle_SkelSceneRoot.png)(w:650) + [/REGION] + +1. With your Skeletal Mesh component selected, set the **Anim Class** to your vehicle's Animation Blueprint and then assign your Skeletal Mesh. + + [REGION:raw] + ![](SimpleVehicle_AssignAnimBP.png)(w:850) + [/REGION] + +1. Return to the **Components** window and add **SimpleWheeledVehicleMovement** component. + + [REGION:raw] + ![](SimpleVehicle_AddSWComp.png)(w:850) + [/REGION] + +1. With the SimpleWheeledVehicleMovement component selected, in the **Vehicle Setup** section click the down arrow to expand **Wheel Setups** and then click the **+** to add your wheels. + +1. For each wheel (0-3): + + * Set the **Wheel Class** to one of the wheel Blueprints you created. + * Set the **Bone Name** to the name of the joint that should be controlled by the wheel. + + [REGION:raw] + ![](wheelsSetup.png) + [/REGION] + [REGION:caption] + The Bone Name in the above image is specific to this Skeletal Mesh. + [/REGION] + + The order you assigned the wheels has no bearing on if it is a front or rear wheel, only the Bone Name and Wheel Class have any effect. + + [REGION:tip] + If you need more than 4 wheels, you can click the "**+**" icon next to the **Wheel Setups** property to add more. + [/REGION] + +At this point, assuming your vehicle is not substantially larger than a minivan, the default values will be a good starting point to start testing. + + +### Applying Torque to Wheels + +In order for your simple vehicle to move, you'll need to apply torque to the individual tires that you want to move. You can do this by pulling off your +SimpleWheeledVehicleMovement component and using **Set Drive Torque**. Use the **Drive Torque** value to set how much torque and the **Wheel Index** to +assign a wheel that will have the torque applied to. The Wheel Index corresponds to the index number in the Wheel Setups section of the SimpleWheeledVehicleMovement's Details Panel. + + +![](SimpleVehicle_SetDriveTorque.png)(w:650) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/SimpleWheeledVehicleMovementComponent/SimpleWheeledVehicleMovementComponent.JPN.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/SimpleWheeledVehicleMovementComponent/SimpleWheeledVehicleMovementComponent.JPN.udn new file mode 100644 index 000000000000..4762e16be07d --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/SimpleWheeledVehicleMovementComponent/SimpleWheeledVehicleMovementComponent.JPN.udn @@ -0,0 +1,93 @@ +INTSourceChangelist:3469385 +Availability:Public +Title:Simple Wheeled Vehicle Movement コンポーネント +Crumbs: +Description:SimpleWheeledVehicleMovement コンポーネントのブループリントのビークル ユーザー ガイド。 +Parent:Engine/Vehicles/ +type:how-to +prereq:Engine/Physics/Vehicles/VehicleUserGuide +Version:4.15 +SkillLevel:Advanced +tags: vehicles + +**Simple Wheeled Vehicle Movement** コンポーネントは、複雑なエンジンやドライブトレインのシミュレーションなしで、ホイールのサスペンションとタイヤの摩擦を表現します。代わりに +このコンポーネントは Wheeled Vehicle Movement コンポーネントから継承したコンポーネントの個々のタイヤに簡単にトルクを適用します。 +これで、ビークルのような動きを、Wheeled Vehicle Actor クラスに依存する必要なく、任意のコンポーネントに適用することができます。 + +SimpleWheeledVehicleMovement コンポーネントをセットアップして使用するためには、まず [ビークルのユーザー ガイド](Engine/Physics/Vehicles/VehicleUserGuide) に記載されている以下のステップを完了する必要があります。 +こうしたステップを使ってビークルをセットアップしてから、先の手順に進んでください。 + +* [Wheel ブループリントを作成する](https://docs.unrealengine.com/latest/INT/Engine/Physics/Vehicles/VehicleUserGuide/#creatingthewheelblueprints) +* [TireTypeData アセットを作成する](https://docs.unrealengine.com/latest/INT/Engine/Physics/Vehicles/VehicleUserGuide/#creatingthetiretypedataasset) +* [Animation ブループリントを作成する](https://docs.unrealengine.com/latest/INT/Engine/Physics/Vehicles/VehicleUserGuide/#creatingtheanimationblueprint) +* [Animation ブループリントを編集する](http://www.newegg.com/Product/Product.aspx?Item=N82E16814487129) + +### Simple Wheeled Vehicle ブループリントを作成する + +新規で Simple Wheeled Vehicle ブループリントを作成するには、**コンテンツ ブラウザ** で **[Add New]** ボタンをクリックし、**[Blueprint Class]** に移動してクリックし、最後に [Pick Parent Class] ウィンドウにあるオプションから **Pawn** を選択します。 + +[REGION:raw] +![](SimpleWheel_CreatePawnBP.png)(w:850) +[/REGION] + + +### Simple Wheeled Vehicle ブループリントを編集する + +Simple Wheeled Vehicle ブループリントを作成したので、シンプルなビークルの動きをセットアップします。ビークルのメッシュの準備ができていて、車輪をセットアップ済みの場合、 +ビークルのようなプロパティを、通常のビークルのドライブ トレインやシミュレーションを必要としない任意のオブジェクトに適用することができます。 + +コンテンツ ブラウザから **SimpleWheeledVehicle ブループリント** をダブルクリックして、ブループリント エディタを表示します。 + +1. **[Components]** ウィンドウで **[Add Component]** ボタンを使用して、 **Skeletal Mesh** コンポーネントを追加します。 + + [REGION:raw] + ![](SimpleVehicle_AddSkelComp.png)(w:850) + [/REGION] + **Skeletal Mesh** コンポーネントをクリックして **DefaultSceneRoot** コンポーネントにドラッグします。これが、このブループリントのルートになります。 + [REGION:raw] + ![](SimpleVehicle_SkelSceneRoot.png)(w:650) + [/REGION] + +1. Skeletal Mesh コンポーネントを選択した状態で、**Anim Class** をビークルの Animation ブループリントに適用し、スケルタルメッシュを割り当てます。 + + [REGION:raw] + ![](SimpleVehicle_AssignAnimBP.png)(w:850) + [/REGION] + +1. **[Components]** ウィンドウに戻り、**SimpleWheeledVehicleMovement** コンポーネントを追加します。 + + [REGION:raw] + ![](SimpleVehicle_AddSWComp.png)(w:850) + [/REGION] + +1. SimpleWheeledVehicleMovement コンポーネントを選択した状態で、**Vehicle Setup** セクションで、下向きの矢印をクリックし、**Wheel Setups** を展開します。次に、**+** をクリックして車輪を追加します。 + +1. 各車輪 (0-3) について以下のようにします。 + + * 作成した車輪のブループリントの 1 つに **Wheel Class** を設定します。 + * 車輪が制御するジョイント名に **[Bone Name (ボーン名)]** を設定します。 + + [REGION:raw] + ![](wheelsSetup.png) + [/REGION] + [REGION:caption] + 上の画像の Bone Name は、このスケルタルメッシュ固有のものです。 + [/REGION] + + 車輪を割り当てた順序は、前輪であるか後輪であるかに関係なく、[Bone Name (ボーン名)] と [Wheel Class (車輪のクラス)] だけが影響を与えます。 + + [REGION:tip] + 4 つよりも多く車輪が必要な場合、**Wheel Setups** プロパティの隣にある "**+**" アイコンをクリックして車輪を追加できます。 + [/REGION] + +この時点で、ビークルがミニバンよりも大幅に大きくないことを前提に、まずデフォルト値でテストするとよいでしょう。 + + +### 車輪にトルクを適用する + +ビークルが動くためには、動かしたい個々のタイヤにトルクを適用する必要があります。これを行うには、 +SimpleWheeledVehicleMovement コンポーネントを引き出して、**Set Drive Torque** を使用します。**Drive Torque** 値を使って、車輪にどれくらいのトルクを適用するか、 +トルクを適用する車輪に割り当てる **Wheel Index** を設定します。Wheel Index は、SimpleWheeledVehicleMovement の [Details (詳細)] パネルの Wheel Setups セクションのインデックス番号に対応します。 + + +![](SimpleVehicle_SetDriveTorque.png)(w:650) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/SimpleWheeledVehicleMovementComponent/SimpleWheeledVehicleMovementComponent.KOR.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/SimpleWheeledVehicleMovementComponent/SimpleWheeledVehicleMovementComponent.KOR.udn new file mode 100644 index 000000000000..3ea38475f005 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/SimpleWheeledVehicleMovementComponent/SimpleWheeledVehicleMovementComponent.KOR.udn @@ -0,0 +1,95 @@ +INTSourceChangelist:0 +Availability:Public +Title:Simple Wheeled Vehicle Movement Component +Crumbs: +Description:The Unreal Engine 4 Blueprint Vehicles User Guide for SimpleWheeledVehicleMovement Component. +Parent: Engine/Vehicles/ +type:how-to +prereq: Engine/Physics/Vehicles/VehicleUserGuide +Version: 4.15 +SkillLevel: Advanced +tags: vehicles + +The **SimpleWheeledVehicleMovement** component provides wheel suspension and tire friction without the complexities of engine or drivetrain simulation. Instead, it +lets you easily apply torque to individual tires for components inheriting from Wheeled Vehicle Movement component, which can give you vehicle-like movement +to arbitrary components without having to rely on the Wheeled Vehicle Actor class. + +In order to setup and use SimpleWheeledVehicleMovement component, you will first need to complete the following steps outlined in the [Vehicle User Guide](Engine/Physics/Vehicles/VehicleUserGuide). +Use these steps to make sure your vehicle is setup properly before proceeding: + +* [Creating the Wheel Blueprints](https://docs.unrealengine.com/latest/INT/Engine/Physics/Vehicles/VehicleUserGuide/#creatingthewheelblueprints) +* [Creating the TireType Data Asset](https://docs.unrealengine.com/latest/INT/Engine/Physics/Vehicles/VehicleUserGuide/#creatingthetiretypedataasset) +* [Creating the Animation Blueprint](https://docs.unrealengine.com/latest/INT/Engine/Physics/Vehicles/VehicleUserGuide/#creatingtheanimationblueprint) +* [Editing the Animation Blueprint](https://docs.unrealengine.com/latest/INT/Engine/Physics/Vehicles/VehicleUserGuide/#editingtheanimationblueprint) + +### Creating a Simple Wheeled Vehicle Blueprints + +To create a new Simple Wheeled Vehicle Blueprint, in the **Content Browser** click the **Add New** button, navigate to and click on **Blueprint Class**, and finally, select **Pawn** from the options in the Pick Parent Class window. + +[REGION:raw] +![](SimpleWheel_CreatePawnBP.png)(w:850) +[/REGION] + + +### Editing the Simple Wheeled Vehicle Blueprint + +Now that we've created a Simple Wheeled Vehicle Blueprint, we can start to set up our simple vehicle movement. So, if your vehicle mesh is ready and you have already setup your wheels, then you will be able to +apply vehicle-like properties to arbitrary objects that do not require the drive-train or simulation of a normal vehicle. + +Double-click your **SimpleWheeledVehicle Blueprint** from your Content Browser to bring up the Blueprint Editor. + +1. In the **Components** window, use the **Add Component** button and add a **Skeletal Mesh** component. + + [REGION:raw] + ![](SimpleVehicle_AddSkelComp.png)(w:850) + [/REGION] + + Then click and drag the **Skeletal Mesh** component onto the **DefaultSceneRoot** component. This will make it the root for this Blueprint. + + [REGION:raw] + ![](SimpleVehicle_SkelSceneRoot.png)(w:650) + [/REGION] + +1. With your Skeletal Mesh component selected, set the **Anim Class** to your vehicle's Animation Blueprint and then assign your Skeletal Mesh. + + [REGION:raw] + ![](SimpleVehicle_AssignAnimBP.png)(w:850) + [/REGION] + +1. Return to the **Components** window and add **SimpleWheeledVehicleMovement** component. + + [REGION:raw] + ![](SimpleVehicle_AddSWComp.png)(w:850) + [/REGION] + +1. With the SimpleWheeledVehicleMovement component selected, in the **Vehicle Setup** section click the down arrow to expand **Wheel Setups** and then click the **+** to add your wheels. + +1. For each wheel (0-3): + + * Set the **Wheel Class** to one of the wheel Blueprints you created. + * Set the **Bone Name** to the name of the joint that should be controlled by the wheel. + + [REGION:raw] + ![](wheelsSetup.png) + [/REGION] + [REGION:caption] + The Bone Name in the above image is specific to this Skeletal Mesh. + [/REGION] + + The order you assigned the wheels has no bearing on if it is a front or rear wheel, only the Bone Name and Wheel Class have any effect. + + [REGION:tip] + If you need more than 4 wheels, you can click the "**+**" icon next to the **Wheel Setups** property to add more. + [/REGION] + +At this point, assuming your vehicle is not substantially larger than a minivan, the default values will be a good starting point to start testing. + + +### Applying Torque to Wheels + +In order for your simple vehicle to move, you'll need to apply torque to the individual tires that you want to move. You can do this by pulling off your +SimpleWheeledVehicleMovement component and using **Set Drive Torque**. Use the **Drive Torque** value to set how much torque and the **Wheel Index** to +assign a wheel that will have the torque applied to. The Wheel Index corresponds to the index number in the Wheel Setups section of the SimpleWheeledVehicleMovement's Details Panel. + + +![](SimpleVehicle_SetDriveTorque.png)(w:650) \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleCenterOfMass/VehicleCenterOfMass.CHN.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleCenterOfMass/VehicleCenterOfMass.CHN.udn new file mode 100644 index 000000000000..3ab41897b72d --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleCenterOfMass/VehicleCenterOfMass.CHN.udn @@ -0,0 +1,84 @@ +INTSourceChangelist:0 +Availability: Docs +Title: Vehicle Center of Mass +Crumbs:%ROOT% +Description: An overview of how Center of Mass works with Vehicles. +Type: Reference +Parent: Engine/Physics/Vehicles/ +Order: +Version: 4.15 +Tags: Vehicles + +[TOC (start:1)] + +Weight distribution of a vehicle is important to its control, as it affects a variety of its characteristics, like handling, acceleration, and traction. Different vehicle types will require different weight distributions depending on their intended use. For the purposes of game development, these characteristics can also define what style of game you are making, whether that is an arcade-style racer, a simulation, or even a hybrid of the two. Altering **Center of Mass** enables you to change the weight distribution of your vehicle. + +In games, the primary use of Center of Mass is for vehicles, but it can also be used for large Physics Bodies encapsulating an irregular shape. In your +[Physics Asset](Engine/Physics/PhAT), you will often use one large Physics Body to define the majority of the Mass for the vehicle (or large object). The +Center of Mass will be generated at the center of this Physics Body, which can make the vehicle handle oddly, so you can adjust the Center of Mass to +account for where the mass of the vehicle is really located. + +[![](CenterOfMass.png)(w:400)](CenterOfmass.png) + +##Understeering versus Oversteering + +Depending on where the Center of Mass is located, you can shift it to be predominantly front-heavy, causing the vehicle to have a tendency toward **understeering** (not turning enough when going around corners), or to be predominantly rear-heavy, causing it to tend toward **oversteering** (turning more sharply than intended). In most cases, it is ideal to find a neutral balance for your Center of Mass so that the vehicle is more easily controlled. + +[REGION:imagetable] +| ![Understeer](Understeering.png)(w:450) | ![Oversteer](Oversteering.png)(w:450) | +| --- | --- | +| Understeer | Oversteer | +[/REGION] + +Also, when you consider where to place the Center of Mass, it is worth noting that this choice can have an effect on how your vehicle handles in the air. In this example, the Center of Mass has been lowered and moved closer to the rear of the car. Since it's low to the ground and can get to high speed quickly, the lower rear Center of Mass helps to stabilize the car, especially with jumps! + +[REGION:imagetable] +| [INCLUDE:#originalCoM] | [INCLUDE:#adjustedCoM] | +| --- | --- | +| Center of Mass: X: 0, Y: 0, Z: 0 | Center of Mass: X: -25, Y: 0, Z: -10 | +[/REGION] + + + +## Debugging Center of Mass + +To help you debug mass properties and inertia tensors associated with physics objects while in the Level Editor, you can enable the `Show` flag by going to **Show** > **Advanced** > **Mass Properties**. + +[REGION:imagetable] +| ![](VehicleCoM1.png)(w:500) | ![](VehicleCoM2.png)(w:500) | +| --- | --- | +| CoM: X: 0, Y: 0, Z: 0 | CoM: X: -25, Y: 0, Z: -10 | +[/REGION] + +The thickness of each axis indicates the moment of inertia magnitude along that axis. + + diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleCenterOfMass/VehicleCenterOfMass.INT.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleCenterOfMass/VehicleCenterOfMass.INT.udn index 12c63ae89037..7ed3edb446a5 100644 --- a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleCenterOfMass/VehicleCenterOfMass.INT.udn +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleCenterOfMass/VehicleCenterOfMass.INT.udn @@ -1,33 +1,47 @@ -Availability: Docs -Title: Vehicle Center of Mass Crumbs:%ROOT% +Title: Vehicle Center of Mass Description: An overview of how Center of Mass works with Vehicles. +Availability:public Type: Reference +Version: 4.15 Parent: Engine/Physics/Vehicles/ Order: -Version: 4.15 Tags: Vehicles -SkillLevel: Beginner -Weight distribution of a vehicle is important to its control, as it affects a variety of its characteristics, like handling, acceleration, and traction. Different vehicle types will require different weight distributions depending on their intended use. For the purposes of game development, these characteristics can also define what style of game you’re making, whether that is an arcade-style racer, a simulation, or even a hybrid of the two. Altering **Center of Mass** enables you to change weight distribution of the vehicle. +[TOC (start:1)] -In games, the primary use of Center of Mass is for vehicles, but it can also be used for large Physics Bodies that encompass an irregular shape. In your -[Physics Asset](Engine/Physics/PhAT), you will often use one large Physics Body to define the majority of the Mass for the vehicle or large object. The +Weight distribution of a vehicle is important to its control, as it affects a variety of its characteristics, like handling, acceleration, and traction. Different vehicle types will require different weight distributions depending on their intended use. For the purposes of game development, these characteristics can also define what style of game you are making, whether that is an arcade-style racer, a simulation, or even a hybrid of the two. Altering **Center of Mass** enables you to change the weight distribution of your vehicle. + +In games, the primary use of Center of Mass is for vehicles, but it can also be used for large Physics Bodies encapsulating an irregular shape. In your +[Physics Asset](Engine/Physics/PhAT), you will often use one large Physics Body to define the majority of the Mass for the vehicle (or large object). The Center of Mass will be generated at the center of this Physics Body, which can make the vehicle handle oddly, so you can adjust the Center of Mass to account for where the mass of the vehicle is really located. -[![](CenterOfMass.png)(w:400)](CenterOfmass.png) +[![](CenterofMass.png)(w:400)](CenterofMass.png) -Depending on where the Center of Mass is located for your vehicle, you can shift it to be predominantly front-heavy, causing the vehicle to have a tendency toward **understeering** (not turning enough when going around corners), or to be predominantly rear-heavy, causing it to tend toward **oversteering** (turning more sharply than intended). In most cases, it is ideal to find a neutral balance for your center of mass so that the vehicle is more easily controlled. +##Understeering versus Oversteering +Depending on where the Center of Mass is located, you can shift it to be predominantly front-heavy, causing the vehicle to have a tendency toward **understeering** (not turning enough when going around corners), or to be predominantly rear-heavy, causing it to tend toward **oversteering** (turning more sharply than intended). In most cases, it is ideal to find a neutral balance for your Center of Mass so that the vehicle is more easily controlled. + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Understeering](Understeering.png)(w:500) + [/PARAM] + [PARAM:after] + ![Oversteering](Oversteering.png)(w:500) + [/PARAM] +[/OBJECT] + + -Also, when you consider where to place the Center of Mass, it is worth noting that this choice can even have an effect on how your vehicle handles in the air. In this example, the Center of Mass has been lowered and moved closer to the rear of the car. Since it's low to the ground and can get to high speed quickly, the lower rear center of mass helps stabilize the car, especially with jumps! +Also, when you consider where to place the Center of Mass, it is worth noting that this choice can have an effect on how your vehicle handles in the air. In this example, the Center of Mass has been lowered and moved closer to the rear of the car. Since it's low to the ground and can get to high speed quickly, the lower rear Center of Mass helps to stabilize the car, especially with jumps! [REGION:imagetable] | [INCLUDE:#originalCoM] | [INCLUDE:#adjustedCoM] | @@ -68,13 +82,16 @@ Also, when you consider where to place the Center of Mass, it is worth noting th ## Debugging Center of Mass -To help you better debug mass properties and inertia tensors associated with physics objects while in the Level Editor, you can enable the showflag by going to **Show** > **Advanced** > **Mass Properties**. +To help you debug mass properties and inertia tensors associated with physics objects while in the Level Editor, you can enable the `Show` flag by going to **Show** > **Advanced** > **Mass Properties**. -[REGION:imagetable] -| ![](VehicleCoM1.png)(w:500) | ![](VehicleCoM2.png)(w:500) | -| --- | --- | -| CoM: X: 0, Y: 0, Z: 0 | CoM: X: -25, Y: 0, Z: -10 | -[/REGION] +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Center of Mass: X: 0, Y: 0, Z: 0](VehicleCoM1.png)(w:500) + [/PARAM] + [PARAM:after] + ![Center of Mass: X: -25, Y: 0, Z: -10](VehicleCoM2.png)(w:500) + [/PARAM] +[/OBJECT] The thickness of each axis indicates the moment of inertia magnitude along that axis. diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleCenterOfMass/VehicleCenterOfMass.JPN.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleCenterOfMass/VehicleCenterOfMass.JPN.udn index 01eb94cc5e15..4c52971f1e38 100644 --- a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleCenterOfMass/VehicleCenterOfMass.JPN.udn +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleCenterOfMass/VehicleCenterOfMass.JPN.udn @@ -1,45 +1,53 @@ -INTSourceChangelist:0 -Availability: Docs -Title: Vehicle Center of Mass -Description: An overview of how Center of Mass works with Vehicles. -Type: Reference -Parent: Engine/Physics/Vehicles/ +INTSourceChangelist:3469385 +Crumbs:%ROOT% +Title:ビークルの重心 +Description:重心がビークルに及ぼす作用の概要 +Availability:public +Type:Reference +Version:4.15 +Parent:Engine/Physics/Vehicles/ Order: -Version: 4.15 -Tags: Vehicles -SkillLevel: Beginner +Tags:Vehicles -Weight distribution of a vehicle is important to its control by affecting a variety of its characteristics, like handling, acceleration, and traction. -Different vehicle types will require different weight distributions depending on their intended use. For the purposes of game development, these characteristics -can also define what style of game you’re making, whether that is an arcade-style racer, a simulation, or even a hybrid of the two. **Center of Mass**, in real -life and simulated ones, enables you to shift part of this control in handling, acceleration, and traction based on the weight distribution of the vehicle. +[TOC (start:1)] -In games, the primary use of Center of Mass is for vehicles, but it can also be used for large Physics Bodies that encompass an irregular shape. In your -[Physics Asset](Engine/Physics/PhAT), you will often use one large Physics Body to define the majority of the Mass for the vehicle or large object. The -Center of Mass will be generated at the center of this Physics Body, which can make the vehicle handle oddly, so you can adjust the Center of Mass to -account for where the mass of the vehicle is really located. +ビークルのウェイト分布は、制御上重要です。ハンドリング、加速、トラクションなどの様々な特性に影響を及ぼすからです。ビークルの種類が違うと、用途に応じて異なる重心分布が必要になります。ゲーム制作では、こうした特性によって制作しているゲームのスタイルが決まります。アーケード スタイルのレーシング ゲーム、シミュレーター、またはこの 2 つを組み合わせたものなどがあります。**Center of Mass (重心)** を変更すると、ビークルのウェイト分布を変更することができます。 -[![](CenterOfMass.png)(w:400)](CenterOfmass.png) +ゲームでは、重心の主な用途はビークルですが、不規則な形状を囲む大きな物理ボディに対しても使用することができます。[Physics アセット](Engine/Physics/PhAT) では、 +ひとつの大きな物理ボディを使って、ビークル (または大きなオブジェクト) の質量の大部分を定義することが多いでしょう。重心は +こうした物理ボディの中心で生成されますが、ビークルの操作が不自然になることがあります。そのため、ビークルの質量が実際にある場所を考慮して +重心を調整します。 -Depending on where the Center of Mass is located for your vehicle, you can shift it to be predominantly front-heavy where the vehicle will have a tendency to -**understeer** causing it to not turn enough when going around corners, or the vehicle can be rear-heavy causing it to **oversteer** where it will -turn more sharply than intended. In most cases, it is ideal to find a neutral balance for your center of mass so that the vehicle is more easily controlled. +[![](CenterofMass.png)(w:400)](CenterofMass.png) +##アンダーステアリングとオーバーステアリング + +重心の位置に応じて、主に前側を重くするようにシフトし、ビークルが **アンダーステアリング** (コーナーを回るときに十分に曲がらない) 傾向を持つようにしたり、主に後部側を重くするようにして、**オーバーステアリング** (意図したよりも曲がる) 傾向になるようにします。ほとんどの場合、ビークルの制御が簡単になるように重心のニュートラル バランスを見つけるのが理想です。 + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Understeering](Understeering.png)(w:500) + [/PARAM] + [PARAM:after] + ![Oversteering](Oversteering.png)(w:500) + [/PARAM] +[/OBJECT] + + -Also, when you consider where to place the Center of Mass, it can have an effect on how your vehicle handles in the air. In this example, the Center of Mass has been -lowered and moved closer to the rear of the car. Since it's low to the ground and can get to high speed quickly, the lower rear center of mass helps stabilize the car, especially -with jumps! +重心をどこに置くかを検討する場合、ビークルが宙に浮いたときの処理に影響を及ぼすことを覚えておいてください。この例では重心は低くなっていて車の後部に近くなっています。地面から低いため、簡単に高速になり、重心が後部の低い場所にあるということは車を安定させます。特にジャンプの場合はそうです。 [REGION:imagetable] | [INCLUDE:#originalCoM] | [INCLUDE:#adjustedCoM] | | --- | --- | -| blah | blah2| +| 重心:X:0, Y:0, Z:0 | 重心:X: -25, Y:0, Z: -10 | [/REGION] -## Debugging Center of Mass +## 重心のデバッグ -To help you better debug mass properties and inertia tensor associated with physics object while in the Level Editor, you can enable the showflag -by going to **Show** > **Advanced** > **Mass Properties**. +レベル エディタで物理オブジェクトに関連する質量のプロパティと慣性テンソルをデバッグするために **[Show** > **Advanced** > **Mass Properties]** の順に進んで `Show` フラグを有効にします。 -[REGION:imagetable] -| ![](VehicleCoM1.png)(w:500) | ![](VehicleCoM2.png)(w:500) | -| --- | --- | -| CoM: X: 0, Y: 0, Z: 0 | CoM: X: -25, Y: 0, Z: -10 | -[/REGION] +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Center of Mass: X: 0, Y: 0, Z: 0](VehicleCoM1.png)(w:500) + [/PARAM] + [PARAM:after] + ![Center of Mass: X: -25, Y: 0, Z: -10](VehicleCoM2.png)(w:500) + [/PARAM] +[/OBJECT] -The thickness of each axis indicates the moment of inertia magnitude along that axis. +各軸の太さは軸に沿った慣性モーメントの大きさを示しています。 diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleCenterOfMass/VehicleCenterOfMass.KOR.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleCenterOfMass/VehicleCenterOfMass.KOR.udn new file mode 100644 index 000000000000..eae6fef03c28 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleCenterOfMass/VehicleCenterOfMass.KOR.udn @@ -0,0 +1,99 @@ +INTSourceChangelist:3469385 +Crumbs:%ROOT% +Title: 비히클 질량 중심 +Description: 비히클 관련 Center of Mass, 질량 중심의 작동방식 개요입니다. +Availability:public +Type: Reference +Version: 4.15 +Parent: Engine/Physics/Vehicles/ +Order: +Tags: Vehicles + + +[TOC (start:1)] + +비히클의 무게 배분(weight distribution)은 핸들링, 가속, 견인과 같은 다양한 특성에 영향을 끼치므로 조작에 있어 중요한 부분입니다. 사용 용도에 따라 각기 다른 비히클 유형마다 각기 다른 무게 배분이 필요합니다. 게임 개발 목적상 이러한 특성은 어떤 스타일의 게임을 만드는가를 정의하기도 합니다. 아케이드 스타일의 레이싱 게임인지, 시뮬레이션인지, 아니면 그 둘의 하이브리드가 될 수도 있습니다. **Center of Mass** (질량 중심)을 바꾸면 비히클의 무게 배분을 변경할 수 있습니다. + +게임에서 질량 중심의 주 용도는 비히클 용이지만, 일정치 않은 모양을 캡슐화시킨 큰 피직스 바디에도 사용할 수 있습니다. +[피직스 애셋](Engine/Physics/PhAT) 에서 종종 큰 피직스 바디 하나를 사용하여 비히클( 또는 큰 오브젝트)의 질량 대부분을 정의하게 됩니다. +질량 중심은 이 피직스 바디의 중앙에 생성되므로, 비히클 핸들링이 이상해질 수가 있기에 비히클의 질량이 실제 있는 곳에 오도록 +질량 중심을 조절하면 됩니다. + +[![](CenterofMass.png)(w:400)](CenterofMass.png) + +##언더스티어링 vs 오버스티어링 + +질량 중심의 위치에 따라 비히클 중심을 대개 전방에 두어 **언더스티어링** (코너를 돌 때 불충분한 회전) 경향을 띄도록 만들 수도 있고, 후방에 두어 **오버스티어링** (의도한 것보다 날카로운 회전) 경향을 띄도록 만들 수도 있습니다. 대부분의 경우, 비히클의 보다 쉬운 제어를 위해 질량 중심의 중립 균형 위치를 찾는 것이 이상적입니다. + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![언더스티어링](Understeering.png)(w:500) + [/PARAM] + [PARAM:after] + ![오버스티어링](Oversteering.png)(w:500) + [/PARAM] +[/OBJECT] + + + +또 질량 중심 배치 위치를 고려할 때, 비히클이 공중에 있을 때에도 영향을 준다는 점 언급해 둘 가치가 있겠습니다. 이 예제에서는 질량 중심을 낮춘 뒤 차량 배후 가까이 이동시켰습니다. 땅에 낮게 붙어 있어 빠른 고속 도달이 가능하므로, 질량 중심을 차량 낮은 배후 위치에 설정하면 특히나 점프할 때 안정화에 도움이 됩니다! + +[REGION:imagetable] +| [INCLUDE:#originalCoM] | [INCLUDE:#adjustedCoM] | +| --- | --- | +| 질량 중심: X: 0, Y: 0, Z: 0 | 질량 중심: X: -25, Y: 0, Z: -10 | +[/REGION] + + + +## 질량 중심 디버깅 + +레벨 에디터의 **Show** (표시) > **Advanced** (고급) > **Mass Properties** (질량 프로퍼티)에서 `표시` 플래그를 켜면 피직스 오브젝트에 관련된 질량 프로퍼티 및 관성 텐서 디버깅에 도움이 됩니다. + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![질량 중심: X: 0, Y: 0, Z: 0](VehicleCoM1.png)(w:500) + [/PARAM] + [PARAM:after] + ![질량 중심: X: -25, Y: 0, Z: -10](VehicleCoM2.png)(w:500) + [/PARAM] +[/OBJECT] + +각 축의 두께는 해당 축의 관성 모멘트 크기를 나타냅니다. + + diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/1/VehicleProjectSetup.CHN.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/1/VehicleProjectSetup.CHN.udn new file mode 100644 index 000000000000..8730c65d9865 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/1/VehicleProjectSetup.CHN.udn @@ -0,0 +1,37 @@ +INTSourceChangelist:0 +Availability: Public +crumbs:%ROOT% +Title: 1 - Required Project Setup +Description: Creating a new project with the specifications we need. +Type:how-to +SkillLevel: Advanced +Version: 4.15 +Parent: Engine/Physics/Vehicles/VehicleUserGuide +checkpoint:vehicleuserguideHT +Order:1 +Tags: Vehicles + + + + +[Nav] + +For this guide, we'll use a Blank Template project, however, tread with caution if you use an existing project or one of the other template projects because in later steps of this +guide you may run into conflicts with some parts that are already setup or setup differently than intended by this guide. + +## Steps + +1. Open **Unreal Engine** from the Launcher. The [Project Browser](Engine/Basics/Projects/Browser) will appear. + +1. Click on the **New Project** tab and then under the **Blueprint** tab, select **Blank** so that you have a clean starting point. You won't need Starter Content, so you can make sure that is set to **No Starter Content**. We'll need a to enter a project name, so we'll use "QuickStart". We can now click **Create Project** and get started. + + [![](CreateProject.png)](CreateProject.png) + +The **Unreal Editor** will now open our new project. + +[REGION:raw] +![](BlankProject.png)(w:800) +[/REGION] + + +[Nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/1/VehicleProjectSetup.INT.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/1/VehicleProjectSetup.INT.udn new file mode 100644 index 000000000000..fbbbc7f79661 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/1/VehicleProjectSetup.INT.udn @@ -0,0 +1,36 @@ +Availability: Public +crumbs:%ROOT% +Title: 1 - Required Project Setup +Description: Creating a new project with the specifications we need. +Type:how-to +SkillLevel: Advanced +Version: 4.15 +Parent: Engine/Physics/Vehicles/VehicleUserGuide +checkpoint:vehicleuserguideHT +Order:1 +Tags: Vehicles + + + + +[Nav] + +For this guide, we'll use a Blank Template project, however, tread with caution if you use an existing project or one of the other template projects because in later steps of this +guide you may run into conflicts with some parts that are already setup or setup differently than intended by this guide. + +## Steps + +1. Open **Unreal Engine** from the Launcher. The [Project Browser](Engine/Basics/Projects/Browser) will appear. + +1. Click on the **New Project** tab and then under the **Blueprint** tab, select **Blank** so that you have a clean starting point. You won't need Starter Content, so you can make sure that is set to **No Starter Content**. We'll need a to enter a project name, so we'll use "QuickStart". We can now click **Create Project** and get started. + + [![](CreateProject.png)](CreateProject.png) + +The **Unreal Editor** will now open our new project. + +[REGION:raw] +![](BlankProject.png)(w:800) +[/REGION] + + +[Nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/1/VehicleProjectSetup.JPN.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/1/VehicleProjectSetup.JPN.udn new file mode 100644 index 000000000000..63b538e985c1 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/1/VehicleProjectSetup.JPN.udn @@ -0,0 +1,37 @@ +INTSourceChangelist:3400712 +Availability:Public +crumbs:%ROOT% +Title:1 - 必要なプロジェクト設定 +Description:必要な内容を指定して新規プロジェクトを作成します。 +Type:how-to +SkillLevel:Advanced +Version:4.15 +Parent:Engine/Physics/Vehicles/VehicleUserGuide +checkpoint:vehicleuserguideHT +Order:1 +Tags:Vehicles + + + + +[Nav] + +このガイドでは Blank Template プロジェクトを使用しますが、既存のプロジェクトや他のテンプレートのプロジェクトを使う場合は注意してください。このガイドの後の方のステップの内容と合わなくなるかもしれません。 +既にご自分でセットアップが済んでいたり、本ガイドで意図しているものとは違うものをセットアップしている可能性があるからです。 + +## ステップ + +1. ランチャーから **アンリアル エンジン** を開きます。[Project Browser](Engine/Basics/Projects/Browser) が表示されます。 + +1. **[New Project]** タブをクリックして、**[Blueprint (ブループリント)]** タブから **Blank** を選んで何もない状態から開始します。Starter Content は不要なため、**[No Starter Content]** に設定するようにしてください。プロジェクト名を入力する必要があるので、ここでは「QuickStart」とします。**[Create Project (プロジェクトを作成)]** をクリックすると開始します。 + + [![](CreateProject.png)](CreateProject.png) + +**アンリアル エディタ** が新規プロジェクトを開きます。 + +[REGION:raw] +![](BlankProject.png)(w:800) +[/REGION] + + +[Nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/1/VehicleProjectSetup.KOR.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/1/VehicleProjectSetup.KOR.udn new file mode 100644 index 000000000000..3c474a6d8961 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/1/VehicleProjectSetup.KOR.udn @@ -0,0 +1,37 @@ +INTSourceChangelist:3400712 +Availability: Public +crumbs:%ROOT% +Title: 1 - 필수 프로젝트 셋업 +Description: 필요에 맞는 새 프로젝트를 만듭니다. +Type:how-to +SkillLevel: Advanced +Version: 4.15 +Parent: Engine/Physics/Vehicles/VehicleUserGuide +checkpoint:vehicleuserguideHT +Order:1 +Tags: Vehicles + + + + +[Nav] + +여기서는 공백 템플릿 프로젝트를 사용하지만, 기존 프로젝트를 사용하거나 다른 템플릿 프로젝트를 사용하는 경우, 나중에 여기서 의도한 셋업과 다르게 되어 있는 경우 충돌이 나는 부분이 +생길 수 있으므로 주의해야 합니다. + +## 단계 + +1. 런처에서 **언리얼 엔진** 을 엽니다. [프로젝트 브라우저](Engine/Basics/Projects/Browser) 가 나타납니다. + +1. **블루프린트** 탭 아래 **새 프로젝트** 탭을 클릭하고, **공백** 을 선택하여 깨끗한 상태에서 시작합니다. 시작용 콘텐츠는 필요치 않으니, **시작용 콘텐츠 없음** 으로 설정합니다. 프로젝트 이름을 입력해야 하므로, QuickStart 라 하겠습니다. 이제 **프로젝트 생성** 을 클릭하여 시작하면 됩니다. + + [![](CreateProject.png)](CreateProject.png) + +이제 **언리얼 에디터** 에 새 프로젝트가 열립니다. + +[REGION:raw] +![](BlankProject.png)(w:800) +[/REGION] + + +[Nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/2/CreatingWheelBP.CHN.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/2/CreatingWheelBP.CHN.udn new file mode 100644 index 000000000000..067bc4121086 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/2/CreatingWheelBP.CHN.udn @@ -0,0 +1,112 @@ +INTSourceChangelist:0 +Availability: Public +crumbs: +Title: 1 - Create a TireConfig Data Asset and Wheel Blueprint +Description: In this part of the guide, we'll create the TireConfig Data Assets that we can use with our Wheel Blueprints for the Vehicle. +Type: Multi-step +SkillLevel: Advanced +Version: 4.15 +Parent: Engine/Physics/Vehicles/VehicleUserGuide +checkpoint:vehicleuserguideHT +Order:1 +Tags: Vehicles + +[Nav] + +[TOC(start:2 end:2)] + +In this first step to creating our own vehicle, we have two parts that go together to make up the wheels for our vehicle; the TireConfig Data Asset and the Wheel Blueprint class. We'll start by first +creating the TireConfig Data Asset and then move on to create the Wheel Blueprint that houses a bunch of properties for our wheels and where the TireConfig data is assigned to. + + +Follow along with the steps below to get started creating your TireConfig data and then using that with a Wheel Blueprint. + +## Tire Config Data Asset + +The **TireConfig Data Asset** is used to control **Friction Scale**. This value not only affects the raw friction of the wheel but also scales the values for how difficult (or easy) it is for the +wheel to slide while in a hard turn. There is also the additional option of **Tire Friction Scales** which enables you to specify a specific Friction Scale to different Physical Material types. + +![](tires02.png) + +### Create your TireConfig Data Asset + +1. In the **Content Browser** click the **Add New** Button, then hover over **Miscellaneous** and then select **Data Asset** from the Context Menu. +1. In the **Pick Data Asset Class** window, select **TireConfg** to create this type of Data Asset. +1. In your **Content Browser** the new asset will be created. Make sure to give it a recognizable name so you can easily locate it later. + +[REGION:raw] +![](newDataAsset.png)(convert:false) +[/REGION] + +[REGION:warning] +In the Pick Data Asset Class window, you may notice that there is also a **TireType** Data Asset class. This is a deprecated function and is only used when upgrading older projects to 4.15 or a later version. +You should not have any reason to use this data asset type if using Unreal Engine 4.15 or later. +[/REGION] + + +## Wheel Blueprints + +In most cases, you will have at least two wheel types; a wheel that is affected by steering and one that is not. Also, this may be the case for having differently sized wheels for the front or the back, in +which case you have full control over setting the differing radii, mass, width, handbrake effect, suspension, and many other properties to give your vehicle the handling you desire. + +[REGION:lightbox] +[![](WheelBlueprintDetailsPanel.png)(h:400)](WheelBlueprintDetailsPanel.png) +[/REGION] +[REGION:caption] +_Click the image for full size view._ +[/REGION] + +### Create your Wheel Blueprint + +1. In the **Content Browser** click the **Add New** button, then select **Blueprint Class** from the menu. +1. In the **Pick Parent Class** window, under **All Classes** search for "wheel" and then select **VehicleWheel**. +1. In your **Content Browser** the new Blueprint asset will be created. Make sure to give it a recognizable name so you can easily locate it later. +1. **Optional** - Repeat these steps again so that you have a **front** and **rear** wheel type. + +[REGION:raw] +![](newWheels.png)(convert:false) +[/REGION] + +### Editing the Wheel Blueprint + +Now that you've got your Wheel Blueprint(s), open them in the Blueprint Editor, and you'll see all the available options to edito your wheels! + +There are five properties that we need to initially change for each wheel, as the rest of them will change how the vehicle performs and should be tweaked later as you start to test out your vehicle in your +own game. + +* **Shape Radius** +* **Shape Width** +* **Affected by Handbrake (usually restricted to the rear wheels)** +* **Steer Angle (usually only the front wheels)** + +![](wheelProps.png) + +[REGION:note] +The properties here are set to match the Buggy from Vehicle Game. If you're using your own Skeletal Mesh you may need to use different values for the **Shape Radius** and **Shape Width**. +[/REGION] + +Now, under the **Tire** section, you can assign the Tire Config Data Asset that you initially created using the **Tire Config** selection box. + +[REGION:raw] +![](TireConfig.png) +[/REGION] + +## End Result + +At this point, you've set up your Tire Config Data Asset that is used to control how much the tires slide on any surface and setup the Wheel Blueprint that can be used to specify all the different +properties of your wheel. In the next step, we'll continue creating the assets we need that make up our vehicle by creating the Animation Blueprint that handles all the necessary animation information +for our vehicle, like spinning tires, steering, suspension, etc. + + +[Nav] + + + + + + + + + + + diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/2/CreatingWheelBP.INT.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/2/CreatingWheelBP.INT.udn new file mode 100644 index 000000000000..93862b44f522 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/2/CreatingWheelBP.INT.udn @@ -0,0 +1,109 @@ +Availability: Public +crumbs:%ROOT% +Title: 2 - Creating a TireConfig Data Asset and Wheel Blueprint +Description: In this step, we'll create the TireConfig Data Assets that we can use with our Wheel Blueprints for our Vehicle. +Type:how-to +SkillLevel: Advanced +Version: 4.15 +Parent: Engine/Physics/Vehicles/VehicleUserGuide +checkpoint:vehicleuserguideHT +Order:2 +Tags: Vehicles + + + +[Nav] + +In this first step to creating our own vehicle, we have two parts that go together to make up the wheels for the vehicle; the TireConfig Data Asset and the Wheel Blueprint class. We'll start by first +creating the TireConfig Data Asset and then move on to create the Wheel Blueprint that houses properties for our wheels, including where the TireConfig data is assigned to. + +Follow along with the steps below to get started creating your TireConfig data and then using that with a Wheel Blueprint. + +## Tire Config Data Asset + +The **TireConfig Data Asset** is used to control **Friction Scale**. This value not only affects the raw friction of the wheel but also scales the values for how difficult (or easy) it is for the +wheel to slide while in a hard turn. There is also the additional option of **Tire Friction Scales**, which enables you to specify a specific Friction Scale to different Physical Material types. + +![](tires02.png) + +### Create your TireConfig Data Asset + +1. In the **Content Browser**, click the **Add New** Button, then hover over **Miscellaneous** and then select **Data Asset** from the Context Menu. +1. In the **Pick Data Asset Class** window, select **TireConfg** to create this type of Data Asset. +1. The new asset will be created in your **Content Browser**. Make sure to give it a recognizable name so you can easily locate it later. + +[REGION:raw] +![](newDataAsset.png)(convert:false) +[/REGION] + +[REGION:warning] +In the Pick Data Asset Class window, you may notice that there is also a **TireType** Data Asset class. This is a deprecated function and is only used when upgrading older projects to Unreal Engine, version 4.15 (or a later version). +You should not have any reason to use this data asset type if using Unreal Engine, version 4.15 (or later). +[/REGION] + +## Wheel Blueprints + +In most cases, you will have at least two wheel types; a wheel that is affected by steering and one that is not. Also, this may be the case for having differently sized wheels for the front or the back, in +which case, you have full control over setting the differing radii, mass, width, handbrake effect, suspension, and many other properties to give your vehicle the handling you desire. + +[REGION:lightbox] +[![](WheelBlueprintDetailsPanel.png)(h:400)](WheelBlueprintDetailsPanel.png) +[/REGION] +[REGION:caption] +_Click the image for full size view._ +[/REGION] + +### Create your Wheel Blueprint + +1. In the **Content Browser**, click the **Add New** button, then select **Blueprint Class** from the menu. +1. In the **Pick Parent Class** window, under **All Classes**, search for "wheel" and then select **VehicleWheel**. +1. The new asset will be created in your **Content Browser**. Make sure to give it a recognizable name so that you can easily locate it later. +1. **Optional** - Repeat these steps again so that you have a **front** and **rear** wheel type. + +[REGION:raw] +![](newWheels.png)(convert:false) +[/REGION] + +### Editing the Wheel Blueprint + +Now that you've got your Wheel Blueprint(s), open them in the Blueprint Editor, where you'll see all the available options to edit your wheels! + +There are five properties that we need to initially change for each wheel, as the rest of them will change how the vehicle performs (and should be tweaked later) as you start to test out the vehicle in your +own game. + +* **Shape Radius** +* **Shape Width** +* **Affected by Handbrake (usually restricted to the rear wheels)** +* **Steer Angle (usually only the front wheels)** + +![](wheelProps.png) + +[REGION:note] +The properties here are set to match the Buggy from Vehicle Game. If you're using your own Skeletal Mesh, you may need to use different values for the **Shape Radius** and **Shape Width**. +[/REGION] + +Now, under the **Tire** section, you can assign the Tire Config Data Asset that you initially created using the **Tire Config** selection box. + +[REGION:raw] +![](TireConfig.png) +[/REGION] + +## End Result + +At this point, you've set up your Tire Config Data Asset, which is used to control how much the tires slide on any surface, having set up the Wheel Blueprint that can be used to specify all of the different +properties for your wheel. In the next step, you'll continue creating the assets you need, which make up our vehicle ,by creating the Animation Blueprint that handles all of the necessary animation information +for our vehicle (such as spinning tires, steering, suspension, etc). + + +[Nav] + + + + + + + + + + + diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/2/CreatingWheelBP.JPN.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/2/CreatingWheelBP.JPN.udn new file mode 100644 index 000000000000..9719e1003340 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/2/CreatingWheelBP.JPN.udn @@ -0,0 +1,110 @@ +INTSourceChangelist:3400712 +Availability:Public +crumbs:%ROOT% +Title:2 - TireConfig Data アセットと Wheel ブループリントを作成する +Description:ビークルの Wheel ブループリントと合わせて使用できる TireConfig Data アセットを作成します。 +Type:how-to +SkillLevel:Advanced +Version:4.15 +Parent:Engine/Physics/Vehicles/VehicleUserGuide +checkpoint:vehicleuserguideHT +Order:2 +Tags:Vehicles + + + +[Nav] + +ビークルを作成するこの最初のステップでは、ビークルの車輪を構成する 2 つのパーツ、TireConfig Data アセットと Wheel Blueprint クラスを作成します。まず、 +TireConfig Data アセットを作成します。次に TireConfig データを割り当てる場所など車輪のプロパティを収容する Wheel ブループリントを作成します。 + +以下の手順に従い、TireConfig データの作成を開始し、それを Wheel ブループリントで使用します。 + +## Tire Config Data アセット + +**TireConfig Data アセット** を使って **Friction Scale** を制御します。この値は、車輪の未加工の摩擦力に影響を与えるだけでなく、 +きついカーブで車輪がどれくらいスライドしづらいか (またはスライドしやすいか) についてもスケーリングします。**Tire Friction Scales** というオプションもあります。これは、特定の Friction Scale を様々な Physical Material タイプに指定することができます。 + +![](tires02.png) + +### TireConfig Data アセットの作成 + +1. **コンテンツ ブラウザ** で、 **[Add New (新規追加)]** ボタンをクリックします。次に **Miscellaneous** にマウスをかざして、コンテキスト メニューから **Data Asset** を選択します。 +1. **[Pick Data Asset Class]** ウィンドウで、**TireConfg** を選択してこのタイプの Data Asset を作成します。 +1. **コンテンツ ブラウザ** に新規アセットが作成されます。後で簡単に見つけられるようにわかりやすい名前を付けてください。 + +[REGION:raw] +![](newDataAsset.png)(convert:false) +[/REGION] + +[REGION:warning] +[Pick Data Asset Class] ウィンドウに、**TireType** Data Asset クラスもあるかもしれません。これは非推奨の関数であり、古いオブジェクトをアンリアル エンジン 4.15 以降のバージョンにアップグレードする場合に限り使用します。 +アンリアル エンジン 4.15 以降のバージョンを使用している場合は、このデータ アセット タイプを使用する理由はありません。 +[/REGION] + +## Wheel ブループリント + +ほとんどの場合、少なくとも 2 種類の車輪があります。ステアリングの影響を受ける車輪と影響を受けない車輪です。また、前輪と後輪でサイズが異なる車輪を持つことがあります。 +この場合、半径、質量、幅、ハンドブレーキのエフェクト、サスペンションなど多くのプロパティを十分に制御する設定があります。 + +[REGION:lightbox] +[![](WheelBlueprintDetailsPanel.png)(h:400)](WheelBlueprintDetailsPanel.png) +[/REGION] +[REGION:caption] +_画像をクリックしてフルサイズで表示_ +[/REGION] + +### Wheel ブループリントの作成 + +1. **コンテンツ ブラウザ** で、 **[Add New (新規追加)]** ボタンをクリックします。次にメニューから **[Blueprint Class]** を選択します。 +1. **[Pick Parent Class]** ウィンドウで "wheel" に対する **全クラス** 検索で **[VehicleWheel]** を選択します。 +1. **コンテンツ ブラウザ** に新規アセットが作成されます。後で簡単に見つけられるようにわかりやすい名前を付けてください。 +1. **オプション** - 上記のステップを繰り返して **front** と **rear** wheel を用意します。 + +[REGION:raw] +![](newWheels.png)(convert:false) +[/REGION] + +### Wheel ブループリントを編集する + +Wheel ブループリントが用意できたので、Blueprint エディタで開きます。車輪を編集するために利用可能なオプションがすべて表示されます。 + +各車輪について最初に変更すべきプロパティが 5 つあります。それ以外のものはゲームでビークルをテストするとビークルの動作に影響を与えます + (後で微調整してください) 。 + +* **Shape Radius** (形状の半径) +* **Shape Width** (形状の幅) +* **Affected by Handbrake** (ハンドブレーキによる影響。通常は、後輪に限定) +* **Steer Angle** (ステアリング角、通常は前輪のみ) + +![](wheelProps.png) + +[REGION:note] +こうしたプロパティは Vehicle Game の Buggy と同じように設定されます。独自のスケルタルメッシュを使用する場合は、**Shape Radius** と **Shape Width** に別の値を使用する必要があるかもしれません。 +[/REGION] + +**[Tire]** セクションで、**Tire Config** 選択ボックスを使って、最初に作成した Tire Config Data Asset を割り当てることができます。 + +[REGION:raw] +![](TireConfig.png) +[/REGION] + +## 最終結果 + +ここまでで車輪の様々なプロパティを指定するために使用できる Wheel ブループリントをセットアップし、Tire Config Data アセットをセットアップしました。 +これは、タイヤがサーフェス上をどの程度スライドするかを制御するために使用することができます。次のステップでは、ビークルを構成する必要なアセットの作成を続けます。ビークルで必要なすべてのアニメーション情報 (タイヤのスピン、ステアリング、サスペンションなど) を処理する +Animation ブループリントを作成します。 + + +[Nav] + + + + + + + + + + + diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/2/CreatingWheelBP.KOR.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/2/CreatingWheelBP.KOR.udn new file mode 100644 index 000000000000..51a04f01b75b --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/2/CreatingWheelBP.KOR.udn @@ -0,0 +1,110 @@ +INTSourceChangelist:3400712 +Availability: Public +crumbs:%ROOT% +Title: 2 - TireConfig 데이터 애셋 및 휠 블루프린트 생성 +Description: 비히클용 휠 블루프린트에 사용할 수 있는 TireConfig 데이터 애셋을 만들어 봅니다. +Type:how-to +SkillLevel: Advanced +Version: 4.15 +Parent: Engine/Physics/Vehicles/VehicleUserGuide +checkpoint:vehicleuserguideHT +Order:2 +Tags: Vehicles + + + +[Nav] + +이번 비히클 제작 첫 단계에서는, 두 부분을 조립하여 비히클의 휠을 만듭니다. 바로 TireConfig 데이터 애셋과 휠 블루프린트 클래스입니다. 먼저 +TireConfig 데이터 애셋을 만든 뒤 휠의 프로퍼티가 들어있는 휠 블루프린트를 만들겠습니다. 이 블루프린트에는 TireConfig 데이터가 할당됩니다. + +TireConfig 데이터를 만들고 휠 블루프린트에 사용하는 방법은 다음과 같습니다. + +## Tire Config 데이터 애셋 + +**TireConfig Data Asset** 은 **Friction Scale** (마찰 스케일) 제어에 사용됩니다. 이 값은 휠의 순수 마찰에 영향을 줄 뿐 아니라 하드 턴 도중 휠이 얼마나 잘 (또는 안) 미끄러지도록 하는 값의 스케일을 조절하기도 합니다. +**Tire Friction Scales** (타이어 마찰 스케일) 에는 부가 옵션이 있어, 특정 마찰 스케일을 다양한 피지컬 머티리얼 유형으로 지정할 수 있습니다. + +![](tires02.png) + +### TireConfig 데이터 애셋 생성 + +1. **콘텐츠 브라우저** 에서 **신규 추가** 버튼을 클릭한 뒤, 맥락 메뉴에서 **기타** 아래 **데이터 애셋** 을 선택합니다. +1. **데이터 애셋 클래스 선택** 창에서 **TireConfig** 을 선택하여 이 유형의 데이터 애셋을 만듭니다. +1. **콘텐츠 브라우저** 에 새로운 애셋이 생깁니다. 나중에 쉽게 찾을 수 있도록 알아보기 좋은 이름을 지어주세요. + +[REGION:raw] +![](newDataAsset.png)(convert:false) +[/REGION] + +[REGION:warning] +데이터 애셋 클래스 선택 창에는 **TireType** 데이터 애셋 클래스도 있는 것이 보일 수 있습니다. 이는 폐기된 함수로, 예전 프로젝트를 언리얼 엔진 4.15 (이상) 버전으로 업그레이드할 때만 사용됩니다. +언리얼 엔진 4.15 (이상) 버전을 사용한다면 이 데이터 애셋 유형을 사용할 이유는 없습니다. +[/REGION] + +## 휠 블루프린트 + +대부분의 경우 최소 두 개의 휠 유형이 있습니다. 스티어링에 영향받는 휠이 있고, 받지 않는 휠이 있습니다. +또한, 앞 또는 뒤 휠 크기가 다른 경우가 될 수 있습니다. 그럴 때는 다양한 반경, 질량, 폭, 핸드브레이크 효과, 서스펜션, 기타 여러가지 속성으로 비히클에 원하는 핸들링 느낌을 낼 수 있습니다. + +[REGION:lightbox] +[![](WheelBlueprintDetailsPanel.png)(h:400)](WheelBlueprintDetailsPanel.png) +[/REGION] +[REGION:caption] +_클릭하면 이미지 원본을 확인합니다._ +[/REGION] + +### 휠 블루프린트 생성 + +1. **콘텐츠 브라우저** 에서 **신규 추가** 버튼을 클릭한 뒤, 메뉴에서 **블루프린트 클래스** 를 선택합니다. +1. **부모 클래스 선택** 창에서 **모든 클래스** 아래 wheel 을 검색한 뒤 **VehicleWheel** 을 선택합니다. +1. **콘텐츠 브라우저** 에 새 애셋이 생성됩니다. 나중에 쉽게 찾을 수 있도록 알아보기 쉬운 이름을 지어주세요. +1. **옵션** - 위 단계를 반복하여 **front** 와 **rear** 휠 유형을 만드세요. + +[REGION:raw] +![](newWheels.png)(convert:false) +[/REGION] + +### 휠 블루프린트 편집 + +휠 블루프린트가 생겼으니, 블루프린트 에디터에서 열어보면 휠 편집에 쓸 수 있는 모든 옵션이 보일 것입니다! + +각 휠마다 변경해야 하는 초기 프로퍼티가 다섯 있고, 나머지는 비히클 작동 방식을 변경하는 것이기에 나중에 실제 게임에서 테스트해 보며 조정해 줘야 할 수 +있습니다. + +* **Shape Radius** 셰이프 반경 +* **Shape Width** 셰이프 폭 +* **Affected by Handbrake (usually restricted to the rear wheels)** 핸드브레이크에 영향받음 (보통 뒷바퀴에만 제한) +* **Steer Angle (usually only the front wheels)** 스티어 각도 (보통 앞바퀴만) + +![](wheelProps.png) + +[REGION:note] +여기 프로퍼티는 비히클 게임의 버기에 일치하도록 설정되어 있습니다. 별도의 스켈레탈 메시를 사용하는 경우, **Shape Radius** 와 **Shape Width** 에 다른 값을 사용해야 할 수 있습니다. +[/REGION] + +이제 **Tire** 섹션 아래, **Tire Config** 선택 박스를 사용하여 처음에 만든 Tire Config 데이터 애셋을 할당할 수 있습니다. + +[REGION:raw] +![](TireConfig.png) +[/REGION] + +## 최종 결과 + +이 시점에서 타이어가 표면에 얼마만큼 미끄러지나 조절하는 데 사용되는 Tire Config 데이터 애셋 구성과, 휠에 각기 다른 프로퍼티를 지정하는 데 사용할 수 있는 휠 블루프린트 구성도 마쳤습니다. +다음 단계에서는 계속해서 비히클을 만드는 데 필요한 애셋을 제작할텐데, 애니메이션 블루프린트를 만들어 비히클에 필요한 (타이어 회전, 스티어링, 서스펜션 등의) +필수 애니메이션 정보를 전부 처리하도록 하겠습니다. + + +[Nav] + + + + + + + + + + + diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/3/CreatingAnimBP.CHN.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/3/CreatingAnimBP.CHN.udn new file mode 100644 index 000000000000..d7ca43fdc525 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/3/CreatingAnimBP.CHN.udn @@ -0,0 +1,79 @@ +INTSourceChangelist:0 +Availability: Public +crumbs: +Title: 2 - Creating a Vehicle Animation Blueprint +Description: In this step we will create the Animation Blueprint that controls our vehicles animations. +Type: Multi-step +SkillLevel: Advanced +Version: 4.15 +Parent: Engine/Physics/Vehicles/VehicleUserGuide +checkpoint:vehicleuserguideHT +Order:2 +Tags: Vehicles + + + +[Nav] + +[TOC(start:2 end:2)] + +At this point, you've created the TireConfig Data Asset and your Wheel Blueprint(s) that we'll use later with the Vehicle Blueprint. In this step, we'll continue to ready our content by +creating an Animation Blueprint that drives all of our animation needs for the wheels on the vehicle! + +## Animation Blueprints + +The Animation Blueprint will be used to specifically control the animation of our Vehicle Skeletal Mesh so that it has animations specific to a vehicle, like spinning tires, suspension, +handbrakes, and steering. To offload a lot of the work in creating animations for these types of things you can use the **Wheel Handler** node to easily drive these types of animations. + +### Wheel Handler Node + +Where the Animation Blueprint is used to get and control our animations for the vehicle, more specifically, the **Wheel Handler** node makes controlling all these animations for the vehicle +fairly easy with little to no additional setup! It just grabs the necessary information from the wheels (How fast is it spinning? Is it affected by the Handbrake? What are the suspension +settings for this wheel?) and translates that to animation on the bone the wheel is associated with. + +![](wheelHandler02.png) + + +## Creating the Animation Blueprint + +1. In the **Content Browser** click the **Add New** button, then hover over **Animation** and then select **Animation Blueprint** from the menu list. +1. In the **Create Animation Blueprint** window, locate and select **your** Skeleton from the list that is for your vehicle. Then click **OK**. + + [REGION:tip] + Alternatively, you can create an Animation Blueprint directly from your Skeletal Mesh by selecting it in the Content Browser and from the context menu select **Create** > **Anim Blueprint**. + [/REGION] + + [REGION:raw] + ![](newAnimBP.png)(convert:false) + [/REGION] + +1. Now that you've got an Animation Blueprint to work from, you can open it from the Content Browser and in the **Anim Graph** you'll want to start by bringing up the +context menu and then search for the **Mesh Space Ref Pose** node and select it from the list to create it. + + [REGION:raw] + ![](meshSpace.png) + [/REGION] + +1. Next, right-click in the **Anim Graph** again to bring up the context menu and then search for the **Wheel Handler** node and select it from the list to create it. + + [REGION:raw] + ![](wheelHandler01.png) + [/REGION] + +1. Now connect the nodes so that your Anim Graph looks like this one. + +![](animBPanimGraph.png) + +1. **Optional** If you have additional struts or other suspension needs, like the Buggy from Vehicle Game, you will need to additional nodes in your Animation Graph to handle the joints that +affect those polygons. In the Buggy from Vehicle Game the extra joints are used to control the axle connections to the wheels. These are driven by a simple **Look At** node, which given the +wheel joints will be driven by the Wheel Handler node and the Look At nodes will make sure the suspension stays attached to the wheels. + +![](fullVehGameAnimBP.png)(w:850) + + +## End Result + +That's it for setting up the Animation Blueprint! The **Component to Local** conversion node will be created automatically and the Animation Blueprint will now drive the wheels of the vehicle. +Continue on to the next step to learn how to create your Vehicle Blueprint that brings all the previous steps together! + +[Nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/3/CreatingAnimBP.INT.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/3/CreatingAnimBP.INT.udn new file mode 100644 index 000000000000..895f7cd46fc4 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/3/CreatingAnimBP.INT.udn @@ -0,0 +1,83 @@ +Availability: Public +crumbs:%ROOT% +Title: 3 - Creating a Vehicle Animation Blueprint +Description: In this step, we will create the Animation Blueprint that controls our vehicles animations. +Type:how-to +SkillLevel: Advanced +Version: 4.15 +Parent: Engine/Physics/Vehicles/VehicleUserGuide +checkpoint:vehicleuserguideHT +Order:3 +Tags: Vehicles + +[Nav] + +At this point, you've created the TireConfig Data Asset and your Wheel Blueprint(s), which you'll use later with the Vehicle Blueprint. In this step, you'll continue to ready your content by +creating an Animation Blueprint that drives all of your animation needs for the wheels on the vehicle. + +## Animation Blueprints + +The Animation Blueprint will be used to control the animation of our Vehicle Skeletal Mesh so that it has animations specific to a vehicle, like spinning tires, suspension, +handbrakes, and steering. To offload a lot of the work in creating animations for these types of things, you can use the **Wheel Handler** node to drive these types of animations. + +### Wheel Handler Node + +Where the Animation Blueprint is used to get and control animations for the vehicle, more specifically, the **Wheel Handler** node makes controlling all of the animations for the vehicle +fairly easy with little to no additional setup. It simply grabs the necessary information from the wheels (How fast is it spinning? Is it affected by the Handbrake? What are the suspension +settings for this wheel?) and translates the query results to an animation on the bone that the wheel is associated with. + +![](wheelHandler02.png) + +## Creating the Animation Blueprint + +1. In the **Content Browser**, click the **Add New** button, then hover over **Animation**, selecting **Animation Blueprint** from the menu list. + +1. In the **Create Animation Blueprint** window, locate and select **your** Skeleton from your vehicle's list. Then click **OK**. + + [REGION:tip] + Alternatively, you can create an Animation Blueprint directly from your Skeletal Mesh by selecting it in the **Content Browser**, where you'll be able to select **Create** > **Anim Blueprint**. + [/REGION] + + [REGION:raw] + ![](newAnimBP.png)(convert:false) + [/REGION] + +1. Now that you've got an Animation Blueprint to work from, you can open it from the **Content Browser** by selecting and double-clicking it. From the main toolbar select **Class Settings** and then in the **Details** panel +set the **Parent Class** to **VehicleAnimInstance**. + + [REGION:raw] + ![](AnimBPParentClass.png)(w:725) + [/REGION] + + [REGION:warning] + If this is not properly set to the right **Parent Class**, you will not have access to nodes needed later in this guide. + [/REGION] + +1. In the **Anim Graph**, you'll want to start by right-clicking to bring up the context menu and then searching for the **Mesh Space Ref Pose** node. Select it from the list to create it in place. + + [REGION:raw] + ![](meshSpace.png) + [/REGION] + +1. Next, right-click in the **Anim Graph** to bring up the context menu and then search for the **Wheel Handler**, selecting it from the list to create it. + + [REGION:raw] + ![](wheelHandler01.png) + [/REGION] + +1. Now, connect the nodes so that your **Anim Graph** looks like this one. + + ![](animBPanimGraph.png) + +1. Optionally, if you have additional struts or other suspension needs (like the Buggy from Vehicle Game) you will need additional nodes in your Animation Graph to handle the joints that +affect those polygons. In the Buggy, from Vehicle Game, the extra joints are used to control the axle connections to the wheels. These are driven by a simple **Look At** node, which, when given the +wheel joints, will be driven by the **Wheel Handler** node and the **Look At** nodes will make sure the suspension stays attached to the wheels. + + ![](fullVehGameAnimBP.png)(w:850) + +## End Result + +You've finished setting up the Animation Blueprint! The **Component to Local** conversion node will be created automatically and the Animation Blueprint will now drive the wheels of the vehicle. +Continue on to the next step to learn how to create a Vehicle Blueprint that brings all of the previous steps together. + +[Nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/3/CreatingAnimBP.JPN.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/3/CreatingAnimBP.JPN.udn new file mode 100644 index 000000000000..e9783b3857b0 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/3/CreatingAnimBP.JPN.udn @@ -0,0 +1,84 @@ +INTSourceChangelist:3469520 +Availability:Public +crumbs:%ROOT% +Title:3 - Vehicle Animation ブループリントを作成する +Description:このステップでは、ビークルのアニメーションを制御する Animation ブループリントを作成します。 +Type:how-to +SkillLevel:Advanced +Version:4.15 +Parent:Engine/Physics/Vehicles/VehicleUserGuide +checkpoint:vehicleuserguideHT +Order:3 +Tags:Vehicles + +[Nav] + +ここまでで、TireConfig Data アセットと Wheel ブループリントを作成しました。これは、後で Vehicle ブループリントと合わせて使用します。このステップでは、ビークルの車輪で必要なすべてのアニメーションを操作する +Animation ブループリントを作成します。 + +## Animation ブループリント + +Animation ブループリントを使って Vehicle のスケルタルメッシュのアニメーションを制御して、タイヤのスピン、サスペンション、ハンドブレーキ、ステアリングなどの +ビークル固有のアニメーションを持つようにします。こうしたアニメーション作成のための作業の負担を減らすために、**Wheel Handler** ノードを使ってアニメーションを操作することができます。 + +### Wheel Handler ノード + +Animation ブループリントを使ってビークルのアニメーションを取得して制御する場合、**Wheel Handler** ノードが非常に簡単に追加の作業をほとんど必要とせずに、 +ビークルのすべてのアニメーションを制御します。車輪から必要な情報を集めます(どれくらい速くスピンするか、ハンドブレーキの影響を受けるか、車輪のサスペンション設定など)。 +その結果を車輪が関連付けられているボーンのアニメーションに変換します。 + +![](wheelHandler02.png) + +## Animation ブループリントを作成する + +1. **コンテンツ ブラウザ** で、 **[Add New (新規追加)]** ボタンをクリックします。次に **Animation** にマウスをかざして、メニュー リストから **[Animation Blueprint]** を選択します。 + +1. **[Create Animation Blueprint]** ウィンドウでビークル リストから **ご自分の ** スケルトンを選択します。**[Ok]** をクリックします。 + + [REGION:tip] + または、スケルタルメッシュから直接 Animation ブループリントを作成することもできます。これを行うには、**コンテンツ ブラウザ** で、**Create** > **Anim Blueprint** の順に選択します。 + [/REGION] + + [REGION:raw] + ![](newAnimBP.png)(convert:false) + [/REGION] + +1. 作業する Animation ブループリントが用意できたので、それを **コンテンツ ブラウザ** で選択して、ダブルクリックして開きます。メイン ツールバーで **[Class Settings]** を選択し **[Details]** パネルで +**[Parent Class]** を **[VehicleAnimInstance]** に設定します。 + [REGION:raw] + + ![](AnimBPParentClass.png)(w:725) + [/REGION] + + [REGION:warning] + 適切な **[Parent Class (親クラス)]** に設定しないと、後でこのガイドで必要になるノードを利用できません。 + [/REGION] + +1. **Anim Graph** で右クリックしてコンテキスト メニューを呼び出し、**Mesh Space Ref Pose** ノードを検索します。それを、リストから選択して作成します。 + + [REGION:raw] + ![](meshSpace.png) + [/REGION] + +1. 次に **Anim Graph** で右クリックしてコンテキスト メニューを呼び出し、**Wheel Handler** を検索し、リストから選択し、作成します。 + + [REGION:raw] + ![](wheelHandler01.png) + [/REGION] + +1. 以下のように **Anim Graph** のノードを接続してください。 + + ![](animBPanimGraph.png) + +1. オプションでストラットの追加や他のサスペンションのニーズがあれば (Vehicle Game の Buggy のようなもの)、Animation Graph でこうしたポリゴンに影響を与えるジョイントを処理する +追加のノードが必要になります。Vehicle Game の Buggy では、こうした追加のジョイントは車輪へのアクセルの接続を制御するために使います。こうしたジョイントは単純な **Look At** ノードによって動きますが、車輪のジョイントが与えられると、 +**Wheel Handler** ノードによって操作され、**Look At** ノードによって、サスペンションが車輪に確実にアタッチされる状態を保つようにします。 + + ![](fullVehGameAnimBP.png)(w:850) + +## 最終結果 + +これで Animation ブループリントのセットアップが終了しました!**Component to Local** 変換ノードが自動的に作成されて、Animation ブループリントがビークルの車輪を操作します。 +次のステップで、これまで作成したものをまとめる Vehicle ブループリントの作成方法を説明します。 + +[Nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/3/CreatingAnimBP.KOR.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/3/CreatingAnimBP.KOR.udn new file mode 100644 index 000000000000..30e985bdd8f0 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/3/CreatingAnimBP.KOR.udn @@ -0,0 +1,84 @@ +INTSourceChangelist:3469520 +Availability: Public +crumbs:%ROOT% +Title: 3 - 비히클 애니메이션 블루프린트 +Description: 여기서는 비히클 애니메이션을 제어하는 애니메이션 블루프린트를 만듭니다. +Type:how-to +SkillLevel: Advanced +Version: 4.15 +Parent: Engine/Physics/Vehicles/VehicleUserGuide +checkpoint:vehicleuserguideHT +Order:3 +Tags: Vehicles + +[Nav] + +이 시점에서 TireConfig 데이터 애셋과 휠 블루프린트를 만들어 두었으니, 나중에 비히클 블루프린트에서 사용하겠습니다. 여기서는 계속해서 콘텐츠 준비 작업을 하겠습니다. +비히클의 휠에 필요한 애니메이션 전부를 구동시키는 애니메이션 블루프린트 제작 작업입니다. + +## 애니메이션 블루프린트 + +애니메이션 블루프린트는 비히클 스켈레탈 메시의 애니메이션 제어에 사용되며, 타이어 회전, 서스펜션, 핸드브레이크, 스티어링 등 비히클 전용 애니메이션을 만들 수 있습니다. +이와 같은 것들에 대한 애니메이션 제작 작업을 다수 줄이기 위해, **Wheel Handler** 노드를 사용하여 이러한 유형의 애니메이션을 구동시켜 주면 됩니다. + +### Wheel Handler 노드 + +애니메이션 블루프린트가 비히클의 애니메이션을 구하고 제어하는 데 사용되는 곳, 보다 구체적으로 **Wheel Handler** 노드는 추가 구성 작업을 거의 하지 않고도 꽤나 쉽게 모든 비히클 애니메이션을 +제어할 수 있습니다. 단순히 휠에서 필수 정보(얼마나 빨리 회전하는가? 핸드브레이크에 영향받는가? 이 휠의 서스펜션 세팅은 어떠한가?)를 구해온 뒤, +그 쿼리 결과를 휠이 할당된 본의 애니메이션으로 전환합니다. + +![](wheelHandler02.png) + +## 애니메이션 블루프린트 생성 + +1. **콘텐츠 브라우저** 에서 **신규 추가** 버튼을 클릭한 뒤 **애니메이션** 위에 커서를 올리면 나오는 메뉴 목록에서 **애니메이션 블루프린트** 를 선택합니다. + +1. **애니메이션 블루프린트 생성** 창의 비히클 목록에서 **자신의** 스켈레톤을 찾아 선택합니다. 그리고 **OK** 를 클릭합니다. + + [REGION:tip] + 다른 방법으로는, **콘텐츠 브라우저** 에서 스켈레탈 메시를 바로 선택하고 **생성** > **애님 블루프린트** 를 선택하여 애니메이션 블루프린트를 바로 만들 수도 있습니다. + [/REGION] + + [REGION:raw] + ![](newAnimBP.png)(convert:false) + [/REGION] + +1. 작업할 애니메이션 블루프린트가 생겼으면, **콘텐츠 브라우저** 에서 선택하고 더블클릭하는 것으로 열 수 있습니다. 메인 툴바에서 **클래스 세팅** 을 선택한 뒤 **디테일** 패널에서 +**Parent Class** (부모 클래스)를 **VehicleAnimInstance** 로 설정하면 됩니다. + + [REGION:raw] + ![](AnimBPParentClass.png)(w:725) + [/REGION] + + [REGION:warning] + 올바른 **Parent Class** 에 설정하지 않으면, 나중에 필요한 노드에 접근할 수 없게 됩니다. + [/REGION] + +1. **애님 그래프** 에서 우클릭으로 맥락 메뉴를 띄운 뒤 **Mesh Space Ref Pose** 노드를 검색하는 것으로 시작합니다. 리스트에서 선택하면 그 자리에 생성됩니다. + + [REGION:raw] + ![](meshSpace.png) + [/REGION] + +1. 다음, **애님 그래프** 에 우클릭하여 맥락 메뉴를 띄우고 **Whell Handler** 를 검색하여 선택하면 생성됩니다. + + [REGION:raw] + ![](wheelHandler01.png) + [/REGION] + +1. 이제 **애님 그래프** 가 다음과 같아 보이도록 노드를 연결합니다. + + ![](animBPanimGraph.png) + +1. 옵션으로, (비히클 게임의 버기처럼) 지지대나 다른 서스펜션이 추가로 필요한 경우 애니메이션 그래프에서 노드를 추가하여 그 폴리곤에 영향을 주는 조인트 처리를 해 줘야 합니다. +비히클 게임의 버기의 경우, 부가 조인트를 사용하여 휠에 연결되는 차축 제어를 하고 있습니다. 이는 단순한 **Look At** 노드로 구동되는데, 휠 조인트를 주면 +**Wheel Handler** 노드로 구동시키고 **Look At** 노드는 서스펜션이 휠에 계속 붙어있도록 해줍니다. + + ![](fullVehGameAnimBP.png)(w:850) + +## 최종 결과 + +애니메이션 블루프린트 구성 작업이 완료되었습니다! **Component to Local** 변환 노드가 자동 생성되어 이제 애니메이션 블루프린트가 비히클의 휠을 구동시킬 것입니다. +계속해서 다음 단계에서는 예전 단계의 모든 것들을 조립하는 비히클 블루프린트를 만드는 법을 알아보겠습니다. + +[Nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/4/CreatingVehicleBP.CHN.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/4/CreatingVehicleBP.CHN.udn new file mode 100644 index 000000000000..a4c9a8cac3cb --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/4/CreatingVehicleBP.CHN.udn @@ -0,0 +1,88 @@ +INTSourceChangelist:0 +Availability: Public +crumbs: +Title: 3 - Creating a Vehicle Blueprint +Description: In this step, we'll create the Vehicle Blueprint where we create and setup a functional vehicle. +Type: Multi-step +SkillLevel: Advanced +Version: 4.15 +Parent: Engine/Physics/Vehicles/VehicleUserGuide +checkpoint:vehicleuserguideHT +Order:3 +Tags: Vehicles + + +[Nav] + +By now, you've created a few different assets (TireConfig Data Assets, Wheel Blueprints, and an Animation Blueprint) that we need to bring together to create a fully functional vehicle in Unreal Engine 4. +In this step, we'll create the Vehicle Blueprint and use those previous assets we created and setup! + + +## Creating and Editing the Vehicle Blueprint + +1. In the **Content Browser** click the **Add New** button, then select **Blueprint Class** from the menu. +1. In the **Pick Parent Class** window, under **All Classes** search for "wheel" and then select **WheeledVehicle**. +1. In your **Content Browser** the new Blueprint asset will be created. Make sure to give it a recognizable name so you can easily locate it later. + + [REGION:raw] + ![](newVehicle.png)(convert:false) + [/REGION] + +1. From the Content Browser, select and open your newly created Vehicle Blueprint. + + ![](MyVehicleBP.png)(w:775) + +1. Click on the **Skeletal Mesh Component** named **Mesh** from the **Components Window**. Then in its **Details** panel, set the **Skeletal Mesh** selection box to your vehicle's own Skeletal Mesh asset. + + ![](ComponentsWindow.png) + +1. Set the **Anim Blueprint Generated Class** to your vehicle's Animation Blueprint that we created in the Step 2 of this guide. + + [REGION:raw] + ![](AnimBPandSkelMesh.png) + [/REGION] + +1. Go back to the **Components** window and select the **Add Component** button and select a **Camera Component** + + [REGION:raw] + ![](addCamera.png) + [/REGION] + +1. Use the Viewport in the Blueprint Editor to position the Camera where you would like it to be relative to your vehicle. In the image below, it is positioned behind, slightly raised, and tilted down towards the vehicle. + + ![](cameraPlacement.png) + +1. With the **Camera** component still selected, in the **Details** panel under **Camera Settings** disable the option for **Use Pawn Control Rotation**. This will lock the camera to its view direction rather than that of the Player +Controller. + + ![](cameraControllerOff.png) + +1. Next, select the **Vehicle Movement Component** in the Components window. + + ![](ComponentsWindow2.png) + + In the **Details** panel under the **Vehicle Setup** section, expand the arrow next to **Wheel Setups** and for each wheel (0-3) set the following: + + * Set the **Wheel Class** to the Wheel Blueprint(s) you created. + * Set the **Bone Name** to the name of the joint that should be controlled by the wheel. + + [REGION:raw] + ![](wheelsSetup.png) + [/REGION] + + _The **Bone Name** in the above image is specific to this skeletal mesh. If you're using the Vehicle from Vehicle Game, you can use these specific Bone Names._ + + The order you assign wheels has no bearing on if it is a front or a rear wheel, only the **Bone Name** and **Wheel Class** have any effect. For organizational purposes, it's best to do them in + keep the wheels (front and rear) together. + + [REGION:note] + If you need more than 4 wheels, you can click the "**+**" icon next to the **Wheel Setups** property to add more. + [/REGION] + + +## End Result + +At this point, assuming your vehicle is not substantially larger than a minivan, the default values will be a good starting point for you to move on to the next step in this guide where we'll setup the +inputs and controls to properly test out the vehicle. + +[Nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/4/CreatingVehicleBP.INT.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/4/CreatingVehicleBP.INT.udn new file mode 100644 index 000000000000..e111095851b1 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/4/CreatingVehicleBP.INT.udn @@ -0,0 +1,81 @@ +Availability: Public +crumbs:%ROOT% +Title: 4 - Creating a Vehicle Blueprint +Description: In this step, we'll create the Vehicle Blueprint where we create and setup a functional vehicle. +Type:how-to +SkillLevel: Advanced +Version: 4.15 +Parent: Engine/Physics/Vehicles/VehicleUserGuide +checkpoint:vehicleuserguideHT +Order:4 +Tags: Vehicles + +[Nav] + +By now, you've created a few different assets (TireConfig Data Assets, Wheel Blueprints, and an Animation Blueprint), which you need to bring together to create a fully functional vehicle in Unreal Engine 4 (UE4). +In this step, you'll create the Vehicle Blueprint, using those assets that were previously created and set up. + +## Creating and Editing the Vehicle Blueprint + +1. In the **Content Browser**, click the **Add New** button, then select **Blueprint Class** from the menu. +1. In the **Pick Parent Class** window, under **All Classes**, search for "wheel" and then select **WheeledVehicle**. +1. In your **Content Browser**, the new Blueprint asset will be created. Make sure to give it a recognizable name so that you can easily locate it later. + + [REGION:raw] + ![](newVehicle.png)(convert:false) + [/REGION] + +1. From the Content Browser, select and open your newly created Vehicle Blueprint. + + ![](MyVehicleBP.png)(w:775) + +1. Click on the **Skeletal Mesh Component** named **Mesh** from the **Components Window**. Then, in its **Details** panel, set the **Skeletal Mesh** selection box to your vehicle's own Skeletal Mesh asset. + + ![](ComponentsWindow.png) + +1. Set the **Anim Blueprint Generated Class** to your vehicle's Animation Blueprint that we created in Step 2 of this guide. + + [REGION:raw] + ![](AnimBPandSkelMesh.png) + [/REGION] + +1. Go back to the **Components** window and select the **Add Component** button and select a **Camera Component** + + [REGION:raw] + ![](addCamera.png) + [/REGION] + +1. Use the Viewport in the Blueprint Editor to position the Camera where you would like it to be relative to your vehicle. In the image below, it is positioned behind, slightly raised, and tilted down towards the vehicle. + + ![](cameraPlacement.png) + +1. With the **Camera** component still selected (in the **Details** panel under **Camera Settings**), disable the option for **Use Pawn Control Rotation**. This will lock the camera to its view direction (rather than that of the Player Controller). + + ![](cameraControllerOff.png) + +1. Next, select the **Vehicle Movement Component** in the Components window. + + ![](ComponentsWindow2.png) + + In the **Details** panel under the **Vehicle Setup** section, expand the arrow next to **Wheel Setups** and for each wheel (0-3) set the following: + + * Set the **Wheel Class** to the Wheel Blueprint(s) you created. + * Set the **Bone Name** to the name of the joint that should be controlled by the wheel. + + [REGION:raw] + ![](wheelsSetup.png) + [/REGION] + + _The **Bone Name** in the above image is specific to this skeletal mesh. If you're using the Vehicle from Vehicle Game, you can use these Bone Names._ + + The order you assign wheels has no bearing on if it is a front or a rear wheel, only the **Bone Name** and **Wheel Class** have any effect. For organizational purposes, it's best to keep the wheels (front and rear) together. + + [REGION:note] + If you need more than 4 wheels, you can click the "**+**" icon next to the **Wheel Setups** property to add more. + [/REGION] + +## End Result + +At this point, assuming your vehicle is not substantially larger than a minivan, the default values will be a good starting point for you to move on to the next step in this guide, where you'll setup the inputs and controls to properly test the vehicle. + +[Nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/4/CreatingVehicleBP.JPN.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/4/CreatingVehicleBP.JPN.udn new file mode 100644 index 000000000000..6654fa352dd2 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/4/CreatingVehicleBP.JPN.udn @@ -0,0 +1,82 @@ +INTSourceChangelist:3400712 +Availability:Public +crumbs:%ROOT% +Title:4 - Vehicle ブループリントを作成する +Description:このステップでは、動作するビークルを作成し、セットアップする Vehicle ブループリントを作成します。 +Type:how-to +SkillLevel:Advanced +Version:4.15 +Parent:Engine/Physics/Vehicles/VehicleUserGuide +checkpoint:vehicleuserguideHT +Order:4 +Tags:Vehicles + +[Nav] + +ここまでで、数種類のアセットを作成しました (TireConfig Data アセット、 Wheel ブループリントおよび Animation ブループリント)。これをまとめてアンリアル エンジン 4 で動作するビークルを作成します。 +このステップでは以前作成し、セットアップしたアセットを使って Vehicle ブループリントを作成します。 + +## Vehicle ブループリントの作成と編集 + +1. **コンテンツ ブラウザ** で、 **[Add New (新規追加)]** ボタンをクリックします。次にメニューから **[Blueprint Class]** を選択します。 +1. **[Pick Parent Class]** ウィンドウで "wheel" に対する **全クラス** 検索で **[WheeledVehicle]** を選択します。 +1. **コンテンツ ブラウザ** に新規 Blueprint アセットが作成されます。後で簡単に見つけられるようにわかりやすい名前を付けてください。 + + [REGION:raw] + ![](newVehicle.png)(convert:false) + [/REGION] + +1. コンテンツ ブラウザで、新規作成した Vehicle ブループリントを選択して開きます。 + + ![](MyVehicleBP.png)(w:775) + +1. **[Components Window]** で **Mesh** という名前の **Skeletal Mesh コンポーネント** 上でクリックします。次に **[Details]** パネルで、**[Skeletal Mesh]** 選択ボックスをビークルの独自の Skeletal Mesh アセットに設定します。 + + ![](ComponentsWindow.png) + +1. **Anim Blueprint Generated Class** をこのガイドのステップ 2 で作成したビークルの Animation ブループリントに設定します。 + + [REGION:raw] + ![](AnimBPandSkelMesh.png) + [/REGION] + +1. **[Components]** ウィンドウに戻り、**[Add Component]** ボタンを選択して、 **Camera コンポーネント** を選択します。 + + [REGION:raw] + ![](addCamera.png) + [/REGION] + +1. ブループリント エディタのビューポートを使ってビークルに対して必要な場所にカメラを配置します。以下の画像では、カメラはビークルの後ろの少し上側に配置され、ビークルに向かって下方に傾いています。 + + ![](cameraPlacement.png) + +1. **Camera** コンポーネントを選択した状態で (**[Details]** パネルの **[Camera Settings]** で)、**[Use Pawn Control Rotation]** のオプションを無効にします。これにより、カメラを (プレイヤー コントローラの方向ではなく) 視線方向にロックします。 + + ![](cameraControllerOff.png) + +1. 次に [Components] ウィンドウで **[Vehicle Movement Component]** を選択します。 + + ![](ComponentsWindow2.png) + + **[Details]** パネルの **[Vehicle Setup]** セクションで **[Wheel Setups]** の隣の矢印を展開します。各車輪 (0-3) について以下のように設定します。 + + * 作成した Wheel ブループリントに **Wheel Class** を設定します。 + * 車輪が制御するジョイント名に **[Bone Name (ボーン名)]** を設定します。 + + [REGION:raw] + ![](wheelsSetup.png) + [/REGION] + + _上の画像の **Bone Name** は、このスケルタルメッシュ固有のものです。Vehicle Game の Vehicle を使用している場合、このような Bone Names を使用することができます。_ + + 車輪を割り当てた順序は、前輪であるか後輪であるかに関係なく、**[Bone Name (ボーン名)]** と **[Wheel Class (車輪のクラス)]** だけが影響を与えます。整理の目的上、車輪 (前輪、後輪) を一緒にまとめておくとよいでしょう。 + + [REGION:note] + 4 つよりも多く車輪が必要な場合、**Wheel Setups** プロパティの隣にある "**+**" アイコンをクリックして車輪を追加できます。 + [/REGION] + +## 最終結果 + +この時点で、ビークルがミニバンよりも大幅に大きくないことを前提に、まずデフォルト値を使用するとよいでしょう。次のステップで、ビークルを適切にテストするために入力と制御をセットアップします。 + +[Nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/4/CreatingVehicleBP.KOR.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/4/CreatingVehicleBP.KOR.udn new file mode 100644 index 000000000000..412033e8df38 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/4/CreatingVehicleBP.KOR.udn @@ -0,0 +1,82 @@ +INTSourceChangelist:3400712 +Availability: Public +crumbs:%ROOT% +Title: 4 - 비히클 블루프린트 제작 +Description: 비히클 블루프린트를 만들어 실제 작동하는 비히클을 만들고 구성해 봅니다. +Type:how-to +SkillLevel: Advanced +Version: 4.15 +Parent: Engine/Physics/Vehicles/VehicleUserGuide +checkpoint:vehicleuserguideHT +Order:4 +Tags: Vehicles + +[Nav] + +지금까지 여러가지 다양한 애셋(TireConfig 데이터 애셋, 휠 블루프린트, 애니메이션 블루프린트)들을 만들었는데, 이들을 조립해야 언리얼 엔진 4 (UE4) 에서 정상 작동하는 비히클을 만들 수 있습니다. +여기서는 기존에 생성 및 구성해 둔 애셋들을 사용하여 비히클 블루프린트를 만들어 보겠습니다. + +## 비히클 블루프린트 생성 및 편집 + +1. **콘텐츠 브라우저** 에서 **신규 추가** 버튼을 클릭한 뒤 메뉴에서 **블루프린트 클래스** 를 선택합니다. +1. **부모 클래스 선택** 창에서 **모든 클래스** 아래 wheel 을 검색한 뒤 **WheeledVehicle** 을 선택합니다. +1. **콘텐츠 브라우저** 에 새 블루프린트 애셋이 생성됩니다. 나중에 쉽게 찾을 수 있도록 알아보기 쉬운 이름을 지어주세요. + + [REGION:raw] + ![](newVehicle.png)(convert:false) + [/REGION] + +1. 콘텐츠 브라우저에서 새로 만든 비히클 블루프린트를 선택하여 엽니다. + + ![](MyVehicleBP.png)(w:775) + +1. **컴포넌트 창** 에서 **Mesh** 라는 이름의 **Skeletal Mesh Component** 를 클릭합니다. 그리고 **디테일** 패널에서 **Skeletal Mesh** 선택 박스를 자체 스켈레탈 메시 애셋으로 설정합니다. + + ![](ComponentsWindow.png) + +1. **Anim Blueprint Generated Class** 를 이 안내서 2 단계에 생성한 비히클의 애니메이션 블루프린트로 설정합니다. + + [REGION:raw] + ![](AnimBPandSkelMesh.png) + [/REGION] + +1. **컴포넌트** 창으로 돌아가 **컴포넌트 추가** 버튼을 선택한 뒤 **Camera Component** 를 선택합니다. + + [REGION:raw] + ![](addCamera.png) + [/REGION] + +1. 블루프린트 에디터의 뷰포트에서 비히클을 기준으로 카메라가 있었으면 하는 위치를 잡습니다. 아래 그림에서는 약간 뒤쪽에서 들어올리고, 비히클 쪽으로 살짝 기울였습니다. + + ![](cameraPlacement.png) + +1. **Camera** 컴포넌트를 여전히 선택한 채 (**디테일** 패널의 **Camera Settings** 아래) **Use Pawn Control Rotation** 옵션을 끕니다. 카메라를 (플레이어 컨트롤러 방향이 아닌) 뷰 방향으로 고정시킵니다. + + ![](cameraControllerOff.png) + +1. 다음, 컴포넌트 창에서 **Vehicle Movement Component** 를 선택합니다. + + ![](ComponentsWindow2.png) + + **디테일** 패널의 **Vehicle Setup** 섹션 아래, **Wheel Setups** 옆의 화살표를 펼친 뒤 각 (0-3) 휠에 대해 다음과 같이 설정합니다: + + * **Wheel Class** 는 앞서 만든 휠 블루프린트로 설정합니다. + * **Bone Name** 은 휠이 제어할 조인트 이름으로 설정합니다. + + [REGION:raw] + ![](wheelsSetup.png) + [/REGION] + + _위 그림의 **Bone Name** 은 이 스켈레탈 메시 전용입니다. 비히클 게임의 비히클을 사용한다면, 이 Bone Name 을 사용하면 됩니다._ + + 휠 할당 순서는 앞바퀴인지 뒷바퀴인지와는 상관 없으며, **Bone Name** 과 **Wheel Class** 만 영향을 줍니다. 정리 목적 상, 앞뒷바퀴 둘씩 같이 묶는 것이 좋습니다. + + [REGION:note] + 휠이 4 개 이상 필요한 경우, **Wheel Setups** 프로퍼티 옆 **+** 아이콘을 클릭하여 추가하면 됩니다. + [/REGION] + +## 최종 결과 + +이 시점에서, 비히클이 미니밴보다 엄청 크지 않다 가정한다면, 이 안내서 다음 단계부터 비히클을 제대로 테스트하기 위해 입력 및 컨트롤 구성을 할 때 기본값에서부터 시작하면 좋을 것입니다. + +[Nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/5/TestingFunctionality.CHN.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/5/TestingFunctionality.CHN.udn new file mode 100644 index 000000000000..d7156a1b61eb --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/5/TestingFunctionality.CHN.udn @@ -0,0 +1,84 @@ +INTSourceChangelist:0 +Availability: Public +crumbs: +Title: 4 - Setting up and Testing Functionality +Description: In this step, we'll setup functionality to control our vehicle! +Type: Multi-step +SkillLevel: Advanced +Version: 4.15 +Parent: Engine/Physics/Vehicles/VehicleUserGuide +checkpoint:vehicleuserguideHT +Order:4 +Tags: Vehicles + + + +[Nav] + +[TOC(start:2 end:2)] + +By now, you've done everything you need to do to have a fully functional vehicle by creating the Wheel, Animation, and Vehicle Blueprints in Unreal Engine 4, except to be able to control it in your game! +In this step, we'll show you how to setup the necessary axis mappings and binding so that you can drive the vehicle around and fully test its capabilities. + +Because there are a few ways to go about setting up the vehicle for testing and assuming that you did start with a blank project template, all of the inputs will need to be added to control +the vehicle. If you started with an existing template, some or all of these axis mappings and bindings may already be available for you in your project. + + + +## Setting Up The Controls + +1. Go to the Main Menu and select **Edit** > **Project Settings** to open the Project Settings window. Then under the **Engine** section in the side panel, select **Input**. + + [REGION:raw] + ![](input.png) + [/REGION] + +1. In the Bindings, setup the following controls if you do not currently have them listed. If you do have them listed, it would be wise to double-check that they are setup like the ones +listed here so that you know your vehicle will work correctly. + + 1. **Add** an **Axis Mapping**, by clicking the "**+**" sign next to the Axis Mappings property + 1. **Expand** the Axis Mappings + 1. **Rename** the Axis Mapping from "None" to **Forward** + 1. **Click** the "**+**" next to the **Forward** Axis Mapping + 1. **Expand** the **Forward** Axis Mapping + 1. **Set** the first "None" to "**W**" + 1. **Set** the second "None" to "**S**" + 1. **Set** the Scale of the "**S**" mapping to "-1.0" + 1. **Add** another **Axis Mapping**, by clicking the "**+**" sign next to the Axis Mappings property + 1. **Rename** the new Axis Mapping from "None" to **Right** + 1. **Expand** the **Right** Axis Mapping + 1. **Set** the first "None" to "**D**" + 1. **Set** the second "None" to "**A**" + 1. **Set** the Scale of the "**A**" mapping to "-1.0" + 1. Then **add** an **Action Mapping**, by clicking the "**+**" sign next to the Action Mappings property, for: + 1. **Expand** the **Action Mappings** property + 1. **Rename** the new Action Mapping from "None" to "**Handbrake**" + 1. **Expand** the **Handbrake** Action Mapping + 1. **Set** the "None" to "**Space Bar**" + +1. Now that you've got the controls setup, you'll need to actually do something with them. So open up the Vehicle Blueprint that you created in previous step (Step 3) and locate the +Event Graph where you'll be able to call theses Axis and Action events that you created in the Project Settins' Input section. + + ![](MyVehicleBP.png)(w:669) + +1. In the Event Graph, for the throttle setup create the following: + + ![](throttleBP.png) + +1. In the Event Graph, for steering setup the following: + + ![](steeringBP.png) + +1. In the Event Graph, for the handbrake setup the following: + + ![](handbrakeBP.png) + + + +## End Result + +Now with these Input Events added you have a fully functional vehicle that can take input movement! In the next and final step, we'll setup a new Game Mode that uses our Vehicle pawn as the +default pawn when we launch a game. + + +[Nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/5/TestingFunctionality.INT.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/5/TestingFunctionality.INT.udn new file mode 100644 index 000000000000..118d91617266 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/5/TestingFunctionality.INT.udn @@ -0,0 +1,85 @@ +Availability: Public +crumbs:%ROOT% +Title: 5 - Setting up and Testing Functionality +Description: In this step, we'll setup functionality to control our vehicle. +Type:how-to +SkillLevel: Advanced +Version: 4.15 +Parent: Engine/Physics/Vehicles/VehicleUserGuide +checkpoint:vehicleuserguideHT +Order:5 +Tags: Vehicles + +[Nav] + +By now, you've done everything you need to do to have a fully functional vehicle by creating the Wheel, Animation, and Vehicle Blueprints in Unreal Engine 4, except to be able to control it in your game! +In this step, we'll show you how to set up the necessary axis mappings and bindings so that you can drive the vehicle around and fully test its capabilities. + +Because there are a few ways to go about setting up the vehicle for testing, and assuming that you started with a blank project template, all of the inputs will need to be added to control +the vehicle. If you started with an existing template, some (or all) of these axis mappings and bindings may already be available for you in your project. + +## Setting Up The Controls + +1. Go to the Main Menu and select **Edit** > **Project Settings** to open the Project Settings window. Then, under the **Engine** section in the side panel, select **Input**. + + ![](input.png)(w:950) + +1. In the Bindings menu, set up the following controls (if you do not currently have them listed). If you do have them listed, it would be wise to double-check that they are set up like the ones listed here, so that you know your vehicle will work correctly. + + 1. First, we'll setup an **Action Mappings** by clicking the **+** sign next to the Action Mappings property. + + ![](1TF.png) + + 1. **Rename** the Action Mapping from "NewActionMapping_0" to **Handbrake**. Then, expand this property to use the selection box to change the key value from "None" to **Space Bar**. + + ![](2TF.png) + + 1. Next, we'll setup the **Axis Mappings** by clicking the **+** sign next to the Axis Mappings property. Repeat this so that you have two Axis Mappings, like this: + + ![](3TF.png) + + 1. **Rename** the first Axis Mapping from "NewAxisMapping_0" to **Forward**. Then do the same for the second and rename it from "NewAxisMapping_1" to **Right**. + + ![](4TF.png) + + 1. **Expand** the **Forward** Axis Mapping and then click the **+** sign once so that you have two Axis Mappings listed under "Forward". Then set the first "None" to use the **W** key for input. Set the second "None" to use the **S** key. + + ![](5TF.png) + + 1. Next to the **S** key input under the **Forward** Axis Mapping, change the **Scale** value to be **-1**. + + ![](6TF.png) + + 1. **Expand** the **Right** Axis Mapping and then click the **+** sign once so that you have two Axis Mappings listed under "Right". Then set the first "None" to use the **D** key for input. Set the second "None" to use the **A** key. + + ![](7TF.png) + + 1. Next to the **A** key input under the **Right** Axis Mapping, change the **Scale** value to be **-1**. + + ![](8TF.png) + + Once you're done setting the Action and Axis Mappings, your Bindings should look like this: + + ![](SetupInputs.png) + +1. Now that you've got the controls set up, you'll need to actually do something with them. So, open up the **Vehicle Blueprint** that you created and locate the **Event Graph**, where you'll be able to call these Axis and Action events that you created in the Project Settings Input section. + + ![](MyVehicleBP.png)(w:669) + +1. In the Event Graph, for the throttle setup create the following: + + ![](throttleBP.png) + +1. In the Event Graph, for steering setup the following: + + ![](steeringBP.png) + +1. In the Event Graph, for the handbrake setup the following: + + ![](handbrakeBP.png) + +## End Result + +Now with these Input Events added you have a fully functional vehicle that can take input movement! In the next and final step, you'll set up a new Game Mode that uses your Vehicle pawn as the default pawn when you launch a game. + +[Nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/5/TestingFunctionality.JPN.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/5/TestingFunctionality.JPN.udn new file mode 100644 index 000000000000..d1330e0b90c3 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/5/TestingFunctionality.JPN.udn @@ -0,0 +1,86 @@ +INTSourceChangelist:3400712 +Availability:Public +crumbs:%ROOT% +Title:5 - 機能をセットアップし、テストする +Description:このステップでは、ビークルを制御する機能をセットアップします。 +Type:how-to +SkillLevel:Advanced +Version:4.15 +Parent:Engine/Physics/Vehicles/VehicleUserGuide +checkpoint:vehicleuserguideHT +Order:5 +Tags:Vehicles + +[Nav] + +ここまでで、UE4 で車輪、アニメーション、Vehicle ブループリントを作成して十分に機能するビークルにするために必要なことをすべて行ってきました。残っているのは、ゲーム内で制御できるようにすることです。 +このステップでは、必要な軸マッピングとバインディングをセットアップする方法を説明し、ビークルを操作し、その機能を十分にテストできるようにします。 + +テスト目的でビークルをセットアップするにはいくつかの方法があり、ブランク プロジェクトのテンプレートで始めたことを前提としてビークルをコントロールするには、 +すべての入力を追加する必要があります。既存のテンプレートで始めた場合は、こうした軸マッピングの一部 (またはすべて) およびバインディングはすでにプロジェクトで利用可能な場合があります。 + +## 制御をセットアップする + +1. メイン メニューから **[Edit]** > **[Project Settings]** を選択して [Project Settings] ウィンドウを開きます。サイド パネルの **[Engine]** セクションから **Input (入力)** を選択します。 + + ![](input.png)(w:950) + +1. [Bindings ] メニューで、以下の制御をセットアップします (現在、リストされていない場合)。リストされていたら、ビークルが正しく動作するように、ここでリストされているものと同様であるかを確認するとよいでしょう。 + + 1. 最初に、 [Action Mappings (アクション マッピング)] プロパティの隣にある **+** 記号をクリックして、**Action Mapping** をセットアップします。 + + ![](1TF.png) + + 1. Action マッピング名を "NewActionMapping_0" から **Handbrake** に **名前変更** します。次にこのプロパティを展開して選択ボックスを使ってキー値を "None" から **Space Bar** に変更します。 + + ![](2TF.png) + + 1. 次に、 [Axis Mappings (軸マッピング)] プロパティの隣にある **+** 記号をクリックして、Axis Mapping をセットアップします。以下のように Axis Mapping が 2 つになるようにこのプロセスを繰り返します。 + + ![](3TF.png) + + 1. 最初の Axis Mapping を "NewAxisMapping_0" から **Forward** に **名前変更** します。次に 2 つめについても同じことを行い、"NewAxisMapping_1" から **Right** に名前変更します。 + + ![](4TF.png) + + 1. **Forward** Axis Mapping を **展開** します。次に **+** 記号を一回クリックして、"Forward" の下に Axis Mapping が 2 つあるようにします。1 つめの "None" を入力で **W** キーを使うように設定します。2 つめの"None" を **S** キーを使うように設定します。 + + ![](5TF.png) + + 1. **Forward** Axis Mapping の **S** キー入力の隣の **Scale** 値を **-1** に変更します。 + + ![](6TF.png) + + 1. **Right** Axis Mapping を **展開** します。次に **+** 記号を一回クリックして、"Right" の下に Axis Mapping が 2 つあるようにします。1 つめの "None" を入力で **D** キーを使うように設定します。2 つめの"None" を **A** キーを使うように設定します。 + + ![](7TF.png) + + 1. **Right** Axis Mapping の **A** キー入力の隣の **Scale** 値を **-1** に変更します。 + + ![](8TF.png) + + Action Mapping と Axis Mapping を設定すると、バインディングは以下のようになります。 + + ![](SetupInputs.png) + +1. これで、制御のセットアップが終了しました。これを使って実際に何かをやってみる必要があります。作成した **Vehicle ブループリント** を開き、**Event Graph** を探します。ここで、[Project Settings Input] セクションで作成した Axis event および Action event を呼び出すことができます。 + + ![](MyVehicleBP.png)(w:669) + +1. Event Graph でスロットルのセットアップに関して以下のように作成します。 + + ![](throttleBP.png) + +1. Event Graph でステアリングのセットアップに関して以下のように作成します。 + + ![](steeringBP.png) + +1. Event Graph でハンドブレーキのセットアップに関して以下のように作成します。 + + ![](handbrakeBP.png) + +## 最終結果 + +Input Event を追加した状態で、入力の動きを取り込む十分に機能するビークルが用意できました。次の最終ステップでは、ゲーム起動時にビークルのポーンをデフォルトのポーンとして使用する新規 Game Mode をセットアップします。 + +[Nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/5/TestingFunctionality.KOR.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/5/TestingFunctionality.KOR.udn new file mode 100644 index 000000000000..29a5adc79831 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/5/TestingFunctionality.KOR.udn @@ -0,0 +1,86 @@ +INTSourceChangelist:3400712 +Availability: Public +crumbs:%ROOT% +Title: 5 - 함수 기능 셋업 및 테스트 +Description: 비히클 제어를 위한 함수 기능을 셋업해 보겠습니다. +Type:how-to +SkillLevel: Advanced +Version: 4.15 +Parent: Engine/Physics/Vehicles/VehicleUserGuide +checkpoint:vehicleuserguideHT +Order:5 +Tags: Vehicles + +[Nav] + +이제, 언리얼 엔진 4 의 휠, 애니메이션, 비히클 블루프린트를 만들었으니, 완벽 작동하는 비히클을 만들 준비가 전부 되었습니다. 이제 남은 것은 게임에서 실제로 제어하는 것입니다! +이번 단계에서는, 비히클을 운전하고 성능을 테스트하기 위해 필요한 축 매핑과 바인딩 셋업 방법을 보여드리겠습니다. + +비히클 테스트 셋업 방법은 여러가지인데, 공백 프로젝트 템플릿으로 시작했다 가정한다면, 모든 입력을 추가해 줘야 비히클 제어가 가능합니다. +기존 템플릿으로 시작했다면, 이들 축 매핑 및 바인딩 중 일부( 또는 전부)는 이미 프로젝트에서 사용할 수 있을 수도 있습니다. + +## 컨트롤 셋업 + +1. 메인 메뉴의 **편집** > **프로젝트 세팅** 으로 프로젝트 세팅 창을 엽니다. 사이드 패널의 **Engine** (엔진) 섹션에서 **Input** (입력)을 선택합니다. + + ![](input.png)(w:950) + +1. 바인딩 메뉴에서, (현재 나열되어 있지 않은 경우) 컨트롤을 다음과 같이 셋업합니다. 나열되어 있지 않으면 여기 나온 대로 셋업되어 있는지 다시 한 번 확인하는 것이 비히클 정상 작동에 좋습니다. + + 1. 먼저 Action Mappings (액션 매핑) 프로퍼티 옆의 **+** 부호를 클릭하여 **액션 매핑** 셋업을 해주겠습니다. + + ![](1TF.png) + + 1. 액션 매핑 이름을 NewActionMapping_0 에서 **Handbrake** 로 변경합니다. 그리고 이 프로퍼티를 펼친 뒤 선택 박스를 사용하여 키 값을 None (없음)에서 **Space Bar** (스페이스 바)로 변경합니다. + + ![](2TF.png) + + 1. 다음, Axis Mappings (축 매핑) 프로퍼티 옆 **+** 부호를 클릭하여 **축 매핑** 셋업을 해주겠습니다. 두 개의 축 매핑에 대해 다음과 같이 반복해 줍니다: + + ![](3TF.png) + + 1. 첫 축 매핑 이름을 NewAxisMapping_0 에서 **Forward** 로 변경합니다. 두 번째 것에 대해서도 똑같이 이름을 NewAxisMapping_1 에서 **Right** 로 변경합니다. + + ![](4TF.png) + + 1. **Forward** 축 매핑을 펼친 뒤 **+** 부호를 한 번 클릭하여 Forward 아래 두 개의 축 매핑이 오도록 합니다. 그리고 첫 번째 None 이 **W** 키를 입력으로 사용하도록 설정합니다. 두 번째 None 은 **S** 키를 사용하도록 설정합니다. + + ![](5TF.png) + + 1. **Forward** 축 매핑 아래 **S** 키 입력 옆 **Scale** 값을 **-1** 로 설정합니다. + + ![](6TF.png) + + 1. **Right** 축 매핑을 펼치고 **+** 를 한 번 클릭하여 Right 아래 두 개의 축 매핑이 오도록 합니다. 그리고 첫 번째 None 은 **D** 키로, 두 번째는 **A** 키로 설정합니다. + + ![](7TF.png) + + 1. **Right** 축 매핑 아래 **A** 키 입력 옆 **Scale** 값을 **-1** 로 변경합니다. + + ![](8TF.png) + + 액션 및 축 매핑 설정이 완료되었으면, 바인딩은 다음과 같을 것입니다: + + ![](SetupInputs.png) + +1. 컨트롤 셋업이 되었으니, 이제 실제로 무언가 작업을 해야 합니다. 앞서 만든 **비히클 블루프린트** 를 열고 **이벤트 그래프** 를 찾습니다. 여기서 프로젝트 세팅의 입력 섹션에서 만든 축 및 액션 이벤트 호출이 가능할 것입니다. + + ![](MyVehicleBP.png)(w:669) + +1. 이벤트 그래프에서, 스로틀 셋업은 다음과 같습니다: + + ![](throttleBP.png) + +1. 이벤트 그래프에서, 스티어링 셋업은 다음과 같습니다: + + ![](steeringBP.png) + +1. 이벤트 그래프에서, 핸드 브레이크 셋업은 다음과 같습니다: + + ![](handbrakeBP.png) + +## 최종 결과 + +입력 이벤트를 추가했으니 이제 입력 이동을 받는 정상 작동 비히클이 생겼습니다! 다음 마지막 단계에서는, 게임을 실행하면 비히클 폰을 기본 폰으로 사용하는 게임 모드를 새로 셋업하겠습니다. + +[Nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/6/VehicleNewGameMode.CHN.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/6/VehicleNewGameMode.CHN.udn new file mode 100644 index 000000000000..19e565aed300 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/6/VehicleNewGameMode.CHN.udn @@ -0,0 +1,76 @@ +INTSourceChangelist:0 +Availability: Public +crumbs: +Title: 5 - Setting up a New Game Mode +Description: In this step, we'll setup a new Game Mode to spawn our Vehicle! +Type: Multi-step +SkillLevel: Advanced +Version: 4.15 +Parent: Engine/Physics/Vehicles/VehicleUserGuide +checkpoint:vehicleuserguideHT +Order:5 +Tags: Vehicles + + +[Nav] + +In the previous step we finished setting up our Vehicle Blueprint and assigned all the controls we need to make it work properly. In this last step, we'll finish by setting up a new Game Mode that +is uses our Vehicle Blueprint as the Default Pawn for the game. + +[REGION:note] +If you did not use a blank project template when starting this guide you may find that you already have a Game Mode assigned that conflicts with the one we're creating in this step. Use the steps below +to create a new Game Mode so that you can spawn in the vehicle you've created throughout this guide. +[/REGION] + +## Creating a New Game Mode + +1. In the **Content Browser** click the **Add New** button and select **Blueprint Class** from the menu list. +1. In the **Pick Parent Class** window, select **Game Mode Base** and then click the **Select** button to create the Game Mode Blueprint. + + [REGION:raw] + ![](newGameMode.png) + [/REGION] + +1. In the **Content Browser**, double-click to open the new Game Mode Blueprint so that you can edit it. In the **Details** under **Classes** next to **Default Pawn Class**, use the drop-down selection to choose +**Your Vehicle Blueprint** that you created in Step 3. + + [REGION:raw] + ![](defaultPawnClass.png) + [/REGION] + + Aftering doing this you can click **Save** and then **Close** this window. + +1. In the Main Viewport window in the **World Settings** tab under the **Game Mode** section set **GameMode Override** to **Your Game Mode Blueprint**. + + [REGION:raw] + ![](setGameMode.png) + [/REGION] + + + +## End Result + +[REGION:raw] +![](Play.png) +[/REGION] + +Congratulations! Now, when you Play in Editor (PIE) you should automatically spawn in with your very own vehicle that you created! You've learned everything you need to create your own working +vehicles in UE4. As you worked your way through this guide, you learned: + +✓ How to configure a TireConfig Data Asset. +✓ How to configure a Wheel Blueprint for your Font and Rear wheels. +✓ How to setup an Animation Blueprint specifically for a Vehicle. +✓ How to configure your Vehicle Blueprint with your Skeletal Mesh, Animation Blueprint, and Wheel Blueprint(s). +✓ How to configure your Axis Mappings and Bindings to control your Vehicle. +✓ How to create and assign a new Game Mode to spawn your vehicle. + +## Getting Started with Vehicle in Unreal Engine + +For additional resources with Vehicles you can take a look at the following pages: + +* [Vehicle Content Creation](Engine/Physics/Vehicles/VehcileContentCreation) +* [Vehicle Center of Mass](Engine\Physics\Vehicles\VehicleCenterOfMass) +* [How to Build a Double Wishbone Suspension Vehicle](Engine/Physics/Vehicles/DoubleWishboneVehicle) +* [Simple Wheeled Vehicle Movement Component](Engine\Physics\Vehicles\SimpleWheeledVehicleMovementComponent) + +[Nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/6/VehicleNewGameMode.INT.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/6/VehicleNewGameMode.INT.udn new file mode 100644 index 000000000000..c4b134dcca9f --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/6/VehicleNewGameMode.INT.udn @@ -0,0 +1,68 @@ +Availability: Public +crumbs:%ROOT% +Title: 6 - Setting up a New Game Mode +Description: In this step, you'll setup a new Game Mode to spawn our Vehicle. +Type:how-to +SkillLevel: Advanced +Version: 4.15 +Parent: Engine/Physics/Vehicles/VehicleUserGuide +checkpoint:vehicleuserguideHT +Order:6 +Tags: Vehicles + +[Nav] + +In the previous step, you finished setting up our Vehicle Blueprint and assigned all of the controls that you need to make it work properly. In this last step, you'll finish by setting up a new Game Mode that uses your own Vehicle Blueprint as the Default Pawn for the game. + +[REGION:note] +If you did not use a Blank Project Template when starting this guide you may find that you already have a Game Mode assigned that conflicts with the one you'll create in this step. Use the steps below to create a new Game Mode so that you can spawn in the vehicle you've created throughout this guide. +[/REGION] + +## Creating a New Game Mode + +1. In the **Content Browser**, click the **Add New** button and select **Blueprint Class** from the menu list. +1. In the **Pick Parent Class** window, select **Game Mode Base**, and then click the **Select** button to create the Game Mode Blueprint. + + [REGION:raw] + ![](newGameMode.png) + [/REGION] + +1. In the **Content Browser**, double-click to open the new Game Mode Blueprint so that you can edit it. In the **Details** under **Classes**, next to **Default Pawn Class**, use the drop-down selection to choose **Your Vehicle Blueprint** (which you created in Step 3). + + [REGION:raw] + ![](defaultPawnClass.png) + [/REGION] + + Aftering doing this, you can click **Save** and then **Close** this window. + +1. In the Main Viewport window, in the **World Settings** tab under the **Game Mode** section, set **GameMode Override** to **Your Game Mode Blueprint**. + + [REGION:raw] + ![](setGameMode.png) + [/REGION] + +## End Result + +[REGION:raw] +![](Play.png) +[/REGION] + +Congratulations! Now, when you Play in Editor (PIE) you should automatically spawn in with your very own vehicle that you created. You've learned everything you need to create your own working +vehicles in UE4. As you worked your way through this guide, you learned: + +✓ How to configure a TireConfig Data Asset. +✓ How to configure a Wheel Blueprint for your Font and Rear wheels. +✓ How to setup an Animation Blueprint specifically for a Vehicle. +✓ How to configure your Vehicle Blueprint with your Skeletal Mesh, Animation Blueprint, and Wheel Blueprint(s). +✓ How to configure your Axis Mappings and Bindings to control your Vehicle. +✓ How to create and assign a new Game Mode to spawn your vehicle. + +## Getting Started with Vehicle in Unreal Engine + +For additional resources with Vehicles you can take a look at the following pages: + +* [Vehicle Content Creation](Engine/Physics/Vehicles/VehcileContentCreation) +* [How to Build a Double Wishbone Suspension Vehicle](Engine/Physics/Vehicles/DoubleWishboneVehicle) +* [Vehicle Center of Mass](Engine\Physics\Vehicles\VehicleCenterOfMass) + +[Nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/6/VehicleNewGameMode.JPN.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/6/VehicleNewGameMode.JPN.udn new file mode 100644 index 000000000000..00ccdc397903 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/6/VehicleNewGameMode.JPN.udn @@ -0,0 +1,69 @@ +INTSourceChangelist:3400712 +Availability:Public +crumbs:%ROOT% +Title:6 - 新規 Game Mode を設定する +Description:このステップでは、ビークルをスポーンするための Game Mode をセットアップします。 +Type:how-to +SkillLevel:Advanced +Version:4.15 +Parent:Engine/Physics/Vehicles/VehicleUserGuide +checkpoint:vehicleuserguideHT +Order:6 +Tags:Vehicles + +[Nav] + +前のステップでは、Vehicle ブループリントのセットアップを終了し、適切に機能するために必要なすべての制御を割り当てました。この最後のステップでは、Vehicle ブループリントをゲームのデフォルト ポーンとして使用する新規 Game Mode をセットアップします。 + +[REGION:note] +このガイドを開始するときに、Blank Project Template を使わなかった場合、既に Game Mode が割り当てられていて、このステップで作成するものとコンフリクトすることがあります。以下のステップを使って新規 Game Mode を作成し、このガイドを通して作成したビークルでスポーンできるようにします。 +[/REGION] + +## 新規 Game Mode を作成する + +1. **コンテンツ ブラウザ** で **[Add New]** ボタンをクリックして、メニュー リストから **[Blueprint Class]** を選択します。 +1. **[Pick Parent Class]** ウィンドウで、**[Game Mode Base]** を選択します。次に **[Select]** ボタンをクリックして Game Mode ブループリントを作成します。 + [REGION:raw] + + ![](newGameMode.png) + [/REGION] + +1. **コンテンツ ブラウザ** で Game Mode ブループリントをダブルクリックして開いて編集できるようにします。**[Details]** の **[Classes]** で、**[Default Pawn Class]** の隣で、ドロップダウンの選択肢から **Vehicle Blueprint** (ステップ 3 で作成したもの) を選択します。 + + [REGION:raw] + ![](defaultPawnClass.png) + [/REGION] + + これを行うと、**[Save]** をクリックして、このウィンドウを **[Close]** できるようになります。 + +1. メイン ビューポート ウィンドウの **[World Settings]** タブの **[Game Mode]** セクションで、**[GameMode Override]** をご自分の **[Game Mode Blueprint]** に設定します。 + + [REGION:raw] + ![](setGameMode.png) + [/REGION] + +## 最終結果 + +[REGION:raw] +![](Play.png) +[/REGION] + +これで終わりです! エディタでプレイする (PIE) と、作成したビークルが自動的にスポーンされます。ここまでで UE4 で機能するビークルを作成するために必要なことについて +学習しました。このガイドで学んだ内容は以下の通りです。 + +✓ TireConfig Data アセットの設定方法 +✓ 前輪と後輪に対して Wheel ブループリントを設定する方法 +✓ ビークル用に Animation ブループリントをセットアップする方法 +✓ スケルタルメッシュ、Animation ブループリント、および Wheel ブループリントを使って Vehicle ブループリントを設定する方法 +✓ 軸マッピングとバインディングを設定してビークルを制御する方法 +✓ 新しい Game Mode を作成し割り当ててビークルをスポーンする方法 + +## アンリアル エンジンでビークルの作業を開始する + +ビークルに関するその他の情報については、以下のページをご覧ください。 + +* [ビークルのコンテンツ作成](Engine/Physics/Vehicles/VehcileContentCreation) +* [ダブルウィッシュボーン式サスペンション ビークルのビルド方法](Engine/Physics/Vehicles/DoubleWishboneVehicle) +* [ビークルの重心](Engine\Physics\Vehicles\VehicleCenterOfMass) + +[Nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/6/VehicleNewGameMode.KOR.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/6/VehicleNewGameMode.KOR.udn new file mode 100644 index 000000000000..2a2b96af0841 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/6/VehicleNewGameMode.KOR.udn @@ -0,0 +1,69 @@ +INTSourceChangelist:3400712 +Availability: Public +crumbs:%ROOT% +Title: 6 - 새 게임 모드 구성 +Description: 비히클 스폰을 위한 새 게임 모드를 구성합니다! +Type:how-to +SkillLevel: Advanced +Version: 4.15 +Parent: Engine/Physics/Vehicles/VehicleUserGuide +checkpoint:vehicleuserguideHT +Order:6 +Tags: Vehicles + +[Nav] + +예전 단계에서, 비히클 블루프린트 구성 및 정상 작동을 위해 필요한 모든 컨트롤 할당 작업을 마쳤습니다. 이번 마지막 단계에서는 우리 비히클 블루프린트를 게임의 기본 폰으로 사용하도록 새 Game Mode (게임 모드)를 구성해 보겠습니다. + +[REGION:note] +이 안내서를 시작할 때 공백 프로젝트 템플릿을 사용하지 않았다면, 이미 할당된 게임 모드가 있어 이번 단계에서 만들려는 것과 충돌이 일어납니다. 게임 모드를 새로 만들어 지금까지 만든 비히클을 스폰하는 방법은 아래와 같습니다. +[/REGION] + +## 새 게임 모드 생성 + +1. **콘텐츠 브라우저** 에서 **신규 추가** 버튼을 클릭하고 메뉴 목록에서 **블루프린트 클래스** 를 선택합니다. +1. **부모 클래스 선택** 창에서 **Game Mode Base** 를 선택한 뒤 **선택** 버튼을 눌러 게임 모드 블루프린트를 만듭니다. + + [REGION:raw] + ![](newGameMode.png) + [/REGION] + +1. **콘텐프 브라우저** 에서 새로 만든 게임 모드 블루프린트를 더블클릭하여 편집할 수 있도록 합니다. **디테일** 에서 **Classes** 아래 **Default Pawn Class** 옆, 드롭다운 선택 버튼을 사용하여 (3 단계에서 만든) **Your Vehicle Blueprint** 를 선택합니다. + + [REGION:raw] + ![](defaultPawnClass.png) + [/REGION] + + 그 후 **저장** 한 뒤 이 창을 **닫습니다**. + +1. 메인 뷰포트 창에서, **월드 세팅** 탭의 **Game Mode** 섹션 아래 **GameMode Override** (게임모드 오버라이드)를 **Your Game Mode Blueprint** 로 설정합니다. + + [REGION:raw] + ![](setGameMode.png) + [/REGION] + +## 최종 결과 + +[REGION:raw] +![](Play.png) +[/REGION] + +축하합니다! 이제 에디터에서 플레이(PIE)해 보면 직접 만든 바로 그 비히클이 자동 스폰되는 것이 보일 것입니다. UE4 에서 제대로 된 비히클을 만드는 데 필요한 것들은 모두 배우셨습니다. +그 내용은 다음과 같습니다: + +✓ TireConfig 데이터 애셋 환경설정 방법. +✓ 앞뒷바퀴에 대한 휠 블루프린트 구성 방법. +✓ 비히클 전용 애니메이션 블루프린트 구성 방법. +✓ 스켈레탈 메시, 애니메이션 블루프린트, 휠 블루프린트로 비히클 블루프린트를 구성하는 방법. +✓ 비히클 제어를 위한 축 및 바인딩 매핑 구성 방법. +✓ 비히클 스폰을 위해 새 게임 모드 생성 및 할당 방법. + +## 언리얼 엔진에서 비히클 시작하기 + +비히클 관련 부가 자료는 다음과 같습니다: + +* [](Engine/Physics/Vehicles/VehcileContentCreation) +* [](Engine/Physics/Vehicles/DoubleWishboneVehicle) +* [](Engine\Physics\Vehicles\VehicleCenterOfMass) + +[Nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/VehicleIntro.INT.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/VehicleIntro.INT.udn index fca4149299bc..284513bec751 100644 --- a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/VehicleIntro.INT.udn +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/VehicleIntro.INT.udn @@ -1,336 +1,88 @@ -Availability:Public -Title:Vehicles User Guide -Crumbs:%ROOT% -Description:The Unreal Engine 4 Blueprint Vehicles User Guide. -Navigation:topic -Version: 4.9 -SkillLevel: Advanced +Availability: Public +crumbs:%ROOT% +Title: Vehicle User Guide +Description: The Unreal Engine 4 Blueprint Vehicle User Guide. +Type:how-to +SkillLevel:Advanced +Version:4.15 +Parent:Engine/Physics/Vehicles +Prereq:Engine/Physics/Vehicles/VehcileContentCreation +Order:1 +checkpoint:vehicleuserguideHT +Tags:Vehicles +topic-image:Vechicle_Topic.png -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Programming/Gameplay/Framework/Vehicle:title%](vehicle_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Programming/Gameplay/Framework/Vehicle:title% - [/PARAM] - [PARAM:description] - %Programming/Gameplay/Framework/Vehicle:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Programming/Gameplay/Framework/Vehicle] - [/PARAM] + + + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 640 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 360 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + pYelGtIMQpk + [/PARAMLITERAL] [/OBJECT] -[/VAR] -[TOC(start:2 end:3)] +At the end of this guide, you'll have a fully functional vehicle that you can use in your own game projects. +## Goal +In this guide, we'll cover the creation of a vehicle using the **Wheeled Vehicle** Blueprint class in a new blank project. This guide will take you through the process of creating all the necessary +in-editor items you need to have a functional vehicle but assumes you have your own **Skeletal Mesh** and a **Physics Asset** ready to go. At the end of this guide, you should have a fully functional +vehicle similar to the one from the Vehicle Game or the Vehicle Template. -This document will cover the creation of a vehicle using the **Wheeled Vehicle** Blueprint class, in a blank project. The process will take you through the creation of all the -necessary in-editor items, but assumes you have a **Skeletal Mesh** and a **Physics Asset** for your vehicle ready to go. +[REGION:note] +If you need information on getting a vehicle Skeletal Mesh and a Physics Asset into the engine, please see the [Vehicle Content Guide](Engine/Physics/Vehicles/VehcileContentCreation). +Alternatively, you can work out of the **Vehicle Template** or the **Vehicle Game** project to have access to a pre-built Skeletal Mesh and Physics Asset. +The **Vehicle Template** is in the **New Project** menu of the **Unreal Project Browser**, and the **Vehicle Game** is on the **Learn** tab of the **Epic Games Launcher**. +[/REGION] -If you need information on getting a vehicle Skeletal Mesh and Physics Asset into the engine, please see the [Vehicle Content Guide](Engine/Physics/Vehicles/VehcileContentCreation). -Alternatively, you can work out of the **Vehicle Template** or **Vehicle Game** to have access to a prebuilt Skeletal Mesh and Physics Asset. +## Objective +During the course of this tutorial you will create the key components that make up a Vehicle in Unreal Engine 4 (UE4). Some of this requires assets that you create outside of UE4, while the majority +of the components will be created right inside of the Editor! -## Content - -A vehicle in Unreal Engine 4 is composed of a number of assets: +This is the individual assets that make up the Vehicle we'll construct: * A Skeletal Mesh * A Physics Asset * An Animation Blueprint * A Vehicle Blueprint * One or more Wheel Blueprints. -* A TireType Data Asset +* A TireConfig Data Asset [REGION:raw] ![](overview.png)(convert:false) [/REGION] -[REGION:note] -This document will cover the Blueprint setup required to make a functioning vehicle in Unreal Engine 4, and assumes you already have a vehicle asset to work with. See the -[](Engine/Physics/Vehicles/VehcileContentCreation) for more information on setting up the Skeletal Mesh and Physics Asset. +By the end of this guide you'll know how to setup each of these asset types and how they work together to bring your vehicles to life! + +* How to configure a TireConfig Data Asset +* How to configure a Wheel Blueprint for your Font and Rear wheels. +* How to setup an Animation Blueprint specifically for a Vehicle. +* How to configure your Vehicle Blueprint with your Skeletal Mesh, Animation Blueprint, and Wheel Blueprint(s). +* How to configure your Axis Mappings and Bindings to control your Vehicle. +* How to create and assign a new Game Mode to spawn your vehicle. + +[OBJECT:TopicList] + [PARAM:icon] + ![](%ROOT%/build_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + Steps + [/PARAM] + [PARAM:description] + [/PARAM] + [PARAM:links] + [DIR(output:"checkpoint" parent:"Engine/Physics/Vehicles/VehicleUserGuide" org:"hierarchy")] + [/PARAM] +[/OBJECT] + +[REGION:call_to_action] + [Click to Start](Engine/Physics/Vehicles/VehicleUserGuide/1 "%Engine/Physics/Vehicles/VehicleUserGuide/1:title%") [/REGION] -## Creating the Vehicle Blueprint - -To create a new **Vehicle Blueprint**: in the **Content Browser** click **Add New** button -> **Blueprint** -> search for "vehicle" and click **WheeledVehicle** from the list. - -[REGION:raw] -![](newVehicle.png)(convert:false) -[/REGION] - -## Creating the Wheel Blueprints - -To create a new **Wheel Blueprint**: in the **Content Browser** click **Add New** button -> **Blueprint** -> search for "wheel" and click **VehicleWheel** from the list. Repeat -this at least once so you have a front and rear wheel type. - -[REGION:raw] -![](newWheels.png)(convert:false) -[/REGION] - -In most cases, you will have at least two wheel types: A wheel that is affected by steering, and one that is not. Also you can set differing radii, mass, width, handbrake effect, -suspension, and many other properties to give your vehicle the handling you desire. - - -## Creating the TireType Data Asset - -To create a new **TireType Data Asset**: in the **Content Browser** click **Add New** button -> **Misc** -> **Data Asset** -> choose **TireType** -> click the **Select** button. - -[REGION:raw] -![](newDataAsset.png)(convert:false) -[/REGION] - -[EXCERPT:frictionScale] -The **TireType Data Asset** only has a single value: **Friction Scale**. This value not only affects the raw friction of the wheel, but also scales the values for how difficult -(or easy) it is for a wheel to slide while in a hard turn. -[/EXCERPT:frictionScale] - -There is a property slot on the **VehicleWheel** Blueprint type for the **TireType Data Asset**. - -## Creating the Animation Blueprint - -To create a new **Animation Blueprint**: in the **Content Browser** click **Add New** button -> **Animation** -> **Animation Blueprint** -> choose the **Skeleton** from the list -that is for your vehicle -> choose **VehicleAnimInstance** -> click the **Ok** button. - -[REGION:raw] -![](newAnimBP.png)(convert:false) -[/REGION] - - -## Editing the Animation Blueprint - -**Double-click** the **Animation Blueprint** from the **Content Browser** to edit the vehicle Animation Blueprint in Persona. The **Anim Graph** for a vehicle has been greatly -simplified for the 4.2 release: - -1. **Right-click** in the **Anim Graph**, from the context menu search for the **Mesh Space Ref Pose** node, and select it to create it. - - [REGION:raw] - ![](meshSpace.png) - [/REGION] - -1. **Right-click** in the **Anim Graph**, from the context menu search for the **Wheel Handler** node, and select it to create it. - - [REGION:raw] - ![](wheelHandler01.png) - [/REGION] - -1. Connect the **Mesh Space Ref Pose** node to the **Wheel Handler** node -1. Connect the **Wheel Handler** node to the **Final Animation Pose** node - - -![](animBPPreAnimGraph.png) - -That is it! The **Component to Local** conversion node will be created automatically, and the Animation Blueprint will now drive the wheels of the vehicle. - -![](animBPanimGraph.png) - -### The Wheel Handler Node - -![](wheelHandler02.png) - -The **Wheel Handler** node handles all the animation needs of your wheels: spinning, steering, handbrake, and suspension. There is no additional setup, it just grabs all the -necessary information from the wheels (How fast is it spinning? Can it steer? Is it affected by the Handbrake? What are the suspension settings for this wheel?) and translates that -to animation on the bone the wheel is associated with. - -Now, if you have additional struts and other suspension needs, you will need additional nodes in your Anim Graph to handle the joints that affect those polygons. The Vehicle from -Vehicle Game has a few extra joints that control the axel connections to the wheels. These are driven by simple **Look At** nodes: - -![](fullVehGameAnimBP.png) - -The additional nodes in the Vehicle Game's Vehicle Anim Graph simply cause the strut joints point at the wheel joints. Given the wheel joints will be driven by the Wheel Handler -Node, and the **Look At** nodes will make sure the suspension stays attached to the wheels. - -## Editing the Tires Data Asset - -**Double-click** the **TireType Data Asset** from the **Content Browser**. - -![](tires02.png) - -[INCLUDE:#frictionscale] - - -## Editing the Wheels Blueprints - -**Double-click** the **Wheel Blueprint** from the **Content Browser** to bring up the Blueprint Editor. - - -1. Switch the Blueprint Editor to Defaults Editing mode: - - ![](defaultsMode.png) - -1. The properties that initially need to be set are: - - * Shape Radius - * Shape Width - * Affected by Handbrake (usually restricted to the rear wheels) - * Steer Angle (usually only the front wheels) - - [REGION:raw] - ![](wheelProps.png) - [/REGION] - -1. Finally, you will need to set your Tire Type. - - [REGION:raw] - ![](tireType.png) - [/REGION] - - -These are the 5 things you will need to change for each wheel. The rest of the properties change the way your vehicle will perform, and can be tweaked as you start testing your -vehicle. - -## Editing the Vehicle Blueprint - -This is really where the vehicle starts to come together. If your art is ready, and you have setup your wheels, then you will be able to fashion a working vehicle at this point. - -**Double-click** the **Vehicle Blueprint** from the **Content Browser** to bring up the Blueprint Editor. - -1. Click on the **Skeletal Mesh Component's** called "Mesh" and in its **Details** panel, set the **Skeletal Mesh** property to your vehicle's Skeletal Mesh asset. - - ![](componentsMode.png) - -1. **Set** the **Anim Blueprint Generated Class** to your vehicles Animation Blueprint. - - [REGION:raw] - ![](AnimBPandSkelMesh.png) - [/REGION] - -1. Return to the **Components** panel and add a **Camera Component**. - - [REGION:raw] - ![](addCamera.png) - [/REGION] - -1. **Position** this Camera Component where you like. In the image below, it is positioned behind the vehicle. - - ![](cameraPlacement.png) - -1. Disable **Camera Settings** -> **Use Controller View Rotation**, this will lock the camera to its view direction, rather than that of the Player Controller. - - ![](cameraControllerOff.png) - -1. Select the **Vehicle Movement Component** and in the **Vehicle Setup** category, expand **Wheel Setups**. - - ![](defaultsMode.png) - -1. For each wheel (0-3): - 1. **Set** the **Wheel Class** to one of the wheel Blueprints you created. - 1. **Set** the **Bone Name** to the name of the joint that should be controlled by the wheel. - - [REGION:raw] - ![](wheelsSetup.png) - [/REGION] - - _The **Bone Name** in the above image is specific to this skeletal mesh._ - - The order you assign wheels has no bearing on if it is a front or a rear wheel, only the **Bone Name** and **Wheel Class** have any affect. - - [REGION:note] - If you need more than 4 wheels, you can click the "**+**" icon next to the **Wheel Setups** property to add more. - [/REGION] - -At this point, assuming your vehicle is not substantially larger than a minivan, the default values will be a good starting point for you to start testing. - - -## Testing - -There are a few ways to setup the vehicle for testing, and some steps will be dependent on which template you started with. - -1. Controls - - [REGION:raw] - ![](input.png) - [/REGION] - - 1. **Project Settings** -> **Input** - 1. **Add** an **Axis Mapping**, by clicking the "**+**" sign next to the Axis Mappings property - 1. **Expand** the Axis Mappings - 1. **Rename** the Axis Mapping from "None" to **Forward** - 1. **Click** the "**+**" next to the **Forward** Axis Mapping - 1. **Expand** the **Forward** Axis Mapping - 1. **Set** the first "None" to "**W**" - 1. **Set** the second "None" to "**S**" - 1. **Set** the Scale of the "**S**" mapping to "-1.0" - 1. **Add** another **Axis Mapping**, by clicking the "**+**" sign next to the Axis Mappings property - 1. **Rename** the new Axis Mapping from "None" to **Right** - 1. **Expand** the **Right** Axis Mapping - 1. **Set** the first "None" to "**D**" - 1. **Set** the second "None" to "**A**" - 1. **Set** the Scale of the "**A**" mapping to "-1.0" - 1. Then **add** an **Action Mapping**, by clicking the "**+**" sign next to the Action Mappings property, for: - 1. **Expand** the **Action Mappings** property - 1. **Rename** the new Action Mapping from "None" to "**Handbrake**" - 1. **Expand** the **Handbrake** Action Mapping - 1. **Set** the "None" to "**Space Bar**" -1. New Game Mode - 1. Create new Game Mode Blueprint. - - [REGION:raw] - ![](newGameMode.png) - [/REGION] - - 1. **Double-click** your new Game Mode Blueprint to edit it. - - 1. **Game Mode** Category -> **Default Pawn Class** -> **change** "None" to your **Vehicle Blueprint**. - - [REGION:raw] - ![](defaultPawnClass.png) - [/REGION] - -1. **World Settings** -> **Game Mode** -> set **GameMode Override** to "Your Game Mode". - - [REGION:raw] - ![](setGameMode.png) - [/REGION] - -1. In your vehicle's Blueprint, you can then call on the Axis and Action events you created in the **Project Settings Input** category. - 1. **Edit** your Vehicle Blueprint, and open the **Event Graph**. - - ![](graphMode.png) - - 1. Throttle - - ![](throttleBP.png) - - 1. Steering - - ![](steeringBP.png) - - 1. Handbrake - - ![](handbrakeBP.png) - -1. Player Start - * If you do not have a **Player Start** Actor in the world, you can either add one to your map using the **Modes Panel** -> **Placement Mode** -> **Basic** -> then clicking and - dragging a **Player Start** into the world. - - [REGION:raw] - ![](playerStart.png) - [/REGION] - - Alternatively you can set Play in Editor to play from the current camera location. -1. Finally, with everything setup, you are now ready to use **Play in Editor** to test your vehicle. - - [REGION:raw] - ![](Play.png) - [/REGION] - - Given the Axis and Action Bindings you setup above, **W** will increase your throttle, **S** will apply the brakes, **A** will turn left, **D** will turn right, and - **Space Bar** will apply the Handbrake. - - - - - - - - - - - diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/VehicleIntro.JPN.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/VehicleIntro.JPN.udn index 1229be217658..c8fa0dd58004 100644 --- a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/VehicleIntro.JPN.udn +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/VehicleIntro.JPN.udn @@ -1,337 +1,89 @@ -INTSourceChangelist:2752762 +INTSourceChangelist:3453053 Availability:Public -Title:ビークル ユーザー ガイド -Crumbs:%ROOT% -Description:アンリアル エンジン 4 のブループリントのビークル ユーザー ガイド -Navigation:topic -Version:4.9 +crumbs:%ROOT% +Title:ビークルのユーザーガイド +Description:UE4 のブループリントのビークルのユーザーガイド +Type:how-to SkillLevel:Advanced +Version:4.15 +Parent:Engine/Physics/Vehicles +Prereq:Engine/Physics/Vehicles/VehcileContentCreation +Order:1 +checkpoint:vehicleuserguideHT +Tags:Vehicles +topic-image:Vechicle_Topic.png -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Programming/Gameplay/Framework/Vehicle:title%](vehicle_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Programming/Gameplay/Framework/Vehicle:title% - [/PARAM] - [PARAM:description] - %Programming/Gameplay/Framework/Vehicle:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Programming/Gameplay/Framework/Vehicle] - [/PARAM] + + + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 640 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 360 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + pYelGtIMQpk + [/PARAMLITERAL] [/OBJECT] -[/VAR] -[TOC(start:2 end:3)] +このガイドを終えると、ゲーム プロジェクトで使用可能な十分機能するビークルが出来上がります。 +## ゴール +このガイドでは、新規ブランク プロジェクトで **Wheeled Vehicle** Blueprint クラスを使用したビークル作成について説明します。このガイドでは、ビークルを機能させるために必要なすべてのインエディタのアイテムを作成する方法を説明しますが、 +ご自身で **スケルタルメッシュ** と **Physics アセット** を用意してあることを前提とします。このガイドを終えると、 Vehicle Game や Vehicle Template にあるもののように +十分機能するビークルが出来上がります。 -このドキュメントでは、ブランク プロジェクトで、**Wheeled Vehicle** ブループリント クラスを使用したビークルの作成について説明します。このプロセスでは、必要なすべてのインエディタのアイテムを作成する方法を説明しますが、 -ご自身のビークルの スケルタルメッシュ と 物理アセット を用意してあることを前提とします。 +[REGION:note] +ビークルのスケルタルメッシュと Physics アセットをアンリアル エンジンで用意するための情報が必要な場合は、[ビークルのコンテンツ ガイド] (Engine/Physics/Vehicles/VehcileContentCreation) をご覧ください。 +他の方法としては、**Vehicle Template** または **Vehicle Game** プロジェクトで作業して、プリビルドされたスケルタルメッシュと Physics アセットを利用できます。 +**Vehicle Template** は、**Unreal Project Browser** の **[New Project]** メニューにあります。**Vehicle Game** は **Epic Games Launcher** の **[Learn]** タブにあります。 +[/REGION] -ビークルのスケルタルメッシュと物理アセットをエンジンに用意する情報が必要な場合は、[ビークルのコンテンツ ガイド] (Engine/Physics/Vehicles/VehcileContentCreation) をご覧ください。 -他の方法としては、**Vehicle Template** または **Vehicle Game** で作業して、プリビルドされたスケルタルメッシュと物理アセットを利用できます。 +## 目的 +このチュートリアルでは、UE4 のビークルを構成する主なコンポーネントを作成します。その一部は UE4 の外部で作成したアセットを必要としますが、ほとんどのコンポーネントは +エディタ内で作成できます。 -## コンテンツ +以下は、これから作成するビークルを構成するアセットです。 -アンリアル エンジン 4 のビークルは、以下のような数多くのアセットから構成されます。 - -* スケルタル メッシュ -* 物理アセット +* スケルタルメッシュ +* Physics アセット * Animation ブループリント * Vehicle ブループリント -* 1 つ以上の Wheel のブループリント -* TireType のデータアセット +* ひとつ以上の Wheel ブループリント +* TireConfig Data アセット [REGION:raw] ![](overview.png)(convert:false) [/REGION] -[REGION:note] -このドキュメントでは、アンリアル エンジン 4 で機能するビークルを作るために必要なブループリントのセットアップについて説明します。ただし、作業するビークル アセットを既にご用意いただいていることを前提とします。詳細は -ビークルの スケルタルメッシュ と 物理アセット をセットアップする情報については、以下をご覧ください。[ビークルのコンテンツ ガイド] (Engine/Physics/Vehicles/VehcileContentCreation) +このガイドを終えると、こうしたアセットをセットアップし、それがどのように機能してビークルを生き生きと動かすかがわかるようになるでしょう。 + +* TireConfig Data アセットの設定方法 +* 前輪と後輪に対して Wheel ブループリントを設定する方法 +* 特にビークル用に Animation ブループリントをセットアップする方法 +* スケルタルメッシュ、Animation ブループリント、および Wheel ブループリントを使って Vehicle ブループリントを設定する方法 +* 軸マッピングとバインディングを設定してビークルを制御する方法 +* 新しい Game Mode を作成し割り当ててビークルをスポーンする方法 + +[OBJECT:TopicList] + [PARAM:icon] + ![](%ROOT%/build_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + ステップ + [/PARAM] + [PARAM:description] + [/PARAM] + [PARAM:links] + [DIR(output:"checkpoint" parent:"Engine/Physics/Vehicles/VehicleUserGuide" org:"hierarchy")] + [/PARAM] +[/OBJECT] + +[REGION:call_to_action] + [クリックして開始](Engine/Physics/Vehicles/VehicleUserGuide/1 "%Engine/Physics/Vehicles/VehicleUserGuide/1:title%") [/REGION] -## Vehicle のブループリントを作成する - -新規 **Vehicle ブループリント** を作成するには、**[コンテンツ ブラウザ]** の **[New (新規)]** ボタン -> **[Blueprint]** -> [vehicle (ビークル)] を検索し、次に、リストの **[WheeledVehicle]** をクリックします。 - -[REGION:raw] -![](newVehicle.png)(convert:false) -[/REGION] - -## Wheel ブループリントを作成する - -**Vehicle ブループリント** を作成するには、**[コンテンツ ブラウザ]** の **[New (新規)]** ボタン -> **[Blueprint]** -> [vehicle (ビークル)] を検索し、次にリストの **[WheeledVehicle]** をクリックします。上記手順を最低 1 回繰り返すと、 -前輪と後輪のタイプができます。 - -[REGION:raw] -![](newWheels.png)(convert:false) -[/REGION] - -車輪の種類は、最低でも 2 種類選ぶことが多いです。ステアリングの影響を受ける車輪と影響を受けない車輪の 2 種類です。また、異なる半径、質量、幅、ハンドブレーキの効果、サスペンションや他の多くのプロパティを設定し、 -必要とするハンドリングをビークルに設定します。 - - -## TireType のデータアセットを作成する - -**コンテンツ ブラウザ** で新規 **TireType のデータアセット** を作成するには、以下の順序で選択します。**[Add New (新規追加)]** ボタン-> **[Misc (その他)]** -> **[Data Asset (データアセット)]** -> **[TireType]** を選択し **[Select (選択)]** ボタンをクリックします。 - -[REGION:raw] -![](newDataAsset.png)(convert:false) -[/REGION] - -[EXCERPT:frictionScale] -**TireType のデータアセット** には、次の 1 つの値だけがあります。**Friction Scale** です。この値は、車輪の未加工の摩擦力に影響を与えるだけでなく、 -きついカーブで車輪がどれくらいスライドしづらいか (またはスライドしやすいか) についてもスケーリングします。 -[/EXCERPT:frictionScale] - -**TireType データアセット** には、**VehicleWheel** ブループリントのプロパティ スロットがあります。 - -## Animation ブループリントを作成する - -新規 **Animation ブループリント** を作成するには、**[コンテンツ ブラウザ]** で **[New (新規)]** ボタン -> **[Animation]** -> **[Animation ブループリント]** を選択し、 -ビークルのリストから **[Skeleton]** そして **VehicleAnimInstance** を選択したら [Ok] ボタンをクリックします。 - -[REGION:raw] -![](newAnimBP.png)(convert:false) -[/REGION] - - -## Animation ブループリントを編集する - -**[コンテンツ ブラウザ]** から **[Animation ブループリント]** を **ダブルクリック** して、ペルソナでビークルの Animation ブループリントを編集します。ビークルの **Anim Graph** は、 -4.2 リリースでは非常に単純化されています。 - -1. コンテキスト メニューから、**[Anim Graph]** で **右クリック** して、**Mesh Space Ref Pose** ノードを検索し、それを選択し、作成します。 - - [REGION:raw] - ![](meshSpace.png) - [/REGION] - -1. コンテキスト メニューから、**[Anim Graph]** で **右クリック** して、**Wheel Handler** ノードを検索し、それを選択し、作成します。 - - [REGION:raw] - ![](wheelHandler01.png) - [/REGION] - -1. **Mesh Space Ref Pose** ノードを **Wheel Handler** ノードに接続します。 -1. **Wheel Handler** ノードを **Final Animation Pose** ノードに接続します。 - - -![](animBPPreAnimGraph.png) - -完了です ! **Component to Local** 変換ノードが自動的に作成され、Animation ブループリントがビークルの車輪を動かします。 - -![](animBPanimGraph.png) - -### Wheel Handler ノード - -![](wheelHandler02.png) - -**Wheel Handler** ノードは、スピン、ステアリング、ハンドブレーキ、サスペンションの車輪のすべてのアニメーションのニーズを処理します。新たにセットアップするものはなく、 -単に車輪から必要な情報 (どれくらい速くスピンするか、操縦できるか?ハンドブレーキの影響を受けるか?車輪のサスペンション設定はどうなっているか?) を集め、 -それを車輪が関連づけられているボーンのアニメーションに変換します。 - -追加のストラットやその他のサスペンションが必要であれば、ポリゴンに影響を与えるジョイントを処理するためのノードを Anim Graph に追加する必要があります。カメラから遠ざかるにつれてメッシュの影響が制限されます。 -ビークル ゲームのビークルには、いくつかのエクストラ ジョイントがあります。こうしたジョイントは単純な **Look At** ノードによって動きます。 - -![](fullVehGameAnimBP.png) - -ビークル ゲームのビークルの Anim Graph は単にストラット ジョイントが車輪ジョイントをポイントするようにします。車輪ジョイントが Wheel Handler Node で動き、 -**Look At** ノードによって、サスペンションが車輪に確実にアタッチされる状態を保つようにすることを前提とします。 - -## タイヤのデータアセットを編集する - -**コンテンツ ブラウザ** から **TireType Data Asset** を **ダブルクリック** します。 - -![](tires02.png) - -[INCLUDE:#frictionscale] - - -## Wheel ブループリントを編集する - -**コンテンツ ブラウザ** から **Wheel Blueprint** を **ダブルクリック** して、ブループリント エディタ を表示します。 - - -1. ブループリント エディタをデフォルトの編集モードに切り替えます。 - - ![](defaultsMode.png) - -1. 以下は最初に設定すべきプロパティです。 - - * Shape Radius - * Shape Width - * Affected by Handbrake (通常は後輪に制限) - * Steer Angle (通常、前輪のみ) - - [REGION:raw] - ![](wheelProps.png) - [/REGION] - -1. 最後に、Tire Type を設定する必要があります。 - - [REGION:raw] - ![](tireType.png) - [/REGION] - - -上記 5 つのプロパティを、各車輪に対して変更する必要があります。それ以外のプロパティは、ビークルの動き方を変えるものであり、 -ビークルのテストを開始後に微調整できます。 - -## Vehicle のブループリントを編集する - -ここから、実際にビークルが一体化されていきます。アートの準備が整い、車輪をセットアップしたら、この時点で動作するビークルを形作ることができます。 - -**コンテンツ ブラウザ** から **Vehicle ブループリント** を **ダブルクリック** して、ブループリント エディタを表示します。 - -1. 「Mesh」 という **Skeletal Mesh コンポーネント** で、 **Skeletal Mesh** プロパティをビークルの Skeletal Mesh アセットに設定します。 - - ![](componentsMode.png) - -1. **Anim Blueprint Generated クラス** をビークルの Animation ブループリントに設定します。 - - [REGION:raw] - ![](AnimBPandSkelMesh.png) - [/REGION] - -1. **Components モード** のまま、**Camera コンポーネント** を追加します。 - - [REGION:raw] - ![](addCamera.png) - [/REGION] - -1. お好みの位置にカメラを **配置** します。以下の画像では、カメラはビークルの後ろにあります。 - - ![](cameraPlacement.png) - -1. 以下の順序で、**[Camera Settings (カメラ設定)]** -> **[Use Controller View Rotation (コントローラー ビュー回転を使用)]** を無効にします。これにより、カメラをプレイヤー コントローラの方向ではなく視線方向にロックします。 - - ![](cameraControllerOff.png) - -1. **Vehicle Movement コンポーネント** の **[Vehicle Setup (ビークル設定)]** カテゴリで **[Wheel Setups (車輪の設定)]** を展開します。 - - ![](defaultsMode.png) - -1. 各車輪 (0-3) に対して以下を設定します。 - 1. 作成した車輪のブループリントの 1 つに **[Wheel Class (車輪のクラス)]** を **設定** します。 - 1. 車輪が制御するジョイント名に **[Bone Name (ボーン名)]** を **設定** します。 - - [REGION:raw] - ![](wheelsSetup.png) - [/REGION] - - _上記画像の **ボーン名** は、このスケルタルメッシュ固有のものです。_ - - 車輪を割り当てた順序は、前輪であるか後輪であるかに関係なく、**[Bone Name (ボーン名)]** と **[Wheel Class (車輪のクラス)}** だけが影響を与えます。 - - [REGION:note] - 4 つ以上の車輪が必要な場合、**Wheel Setups** プロパティの隣にある "**+**" アイコンをクリックして車輪を追加できます。 - [/REGION] - -この時点では、ビークルがミニバンよりもはるかに大きなものではないことを前提とし、テストを開始するにはデフォルト値が最適な開始点になるでしょう。 - - -## テスト - -テストのためにビークルをセットアップするには、2、3 の方法があります。いくつかの手順は、どのテンプレートで開始したかによって変わります。 - -1. コントロール - - [REGION:raw] - ![](input.png) - [/REGION] - - 1. **[Project Settings (プロジェクト設定)]** -> **[Input (入力)]** - 1. **Axis Mappings** プロパティの隣にある "**+**" 記号をクリックして、Axis Mappings を **追加** します。 - 1. 軸マッピングを **展開** します。 - 1. 軸マッピングを "None" から **Forward** に **名前変更** します。 - 1. **Forward** 軸マッピングの隣にある "**+**" 記号を **クリック** します。 - 1. **Forward** 軸マッピングを **展開** します。 - 1. 1 つ目の "None" を "**W**" に **設定** します。 - 1. 2 つ目の"None" を "**S**" に **設定** します。 - 1. "**S**" マッピングのスケールを "-1.0" に **設定** します。 - 1. **Axis Mappings** プロパティの隣にある "**+**" 記号をクリックして、Axis Mappings プロパティにもう 1 つ追加します。 - 1. 新しい軸マッピングを "None" から **Right** に **名前変更** します。 - 1. **Right** 軸マッピングを **展開** します。 - 1. 1 つ目の "None" を "**D**" に **設定** します。 - 1. 2 つ目の"None" を "**A**" に **設定** します。 - 1. "**A**" マッピングのスケールを "-1.0" に **設定** します。 - 1. **Action Mappings** プロパティの隣にある "**+**" 記号をクリックして、Action マッピングを追加します。 - 1. **Action Mappings** プロパティを **展開** します。 - 1. 新しい Action マッピング名を "None" から **Handbrake** に **変更** します。 - 1. **Handbrake** アクション マッピングを **展開** します。 - 1. "None" を "**Space Bar**" に **設定** します。 -1. 新規ゲームモード - 1. 新規ゲームモードのブループリントを作成します。 - - [REGION:raw] - ![](newGameMode.png) - [/REGION] - - 1. 新規ゲームモードのブループリントを編集するには **ダブルクリック** します。 - - 1. **[Game Mode]** カテゴリ-> **[Default Pawn Class]** -> の順序で選択し、"None" をご自身の **ビークル ブループリント** に変更してください。 - - [REGION:raw] - ![](defaultPawnClass.png) - [/REGION] - -1. **[World Settings (ワールド設定)]** -> **[Game Mode]** -> **[Gamemode Override (ゲームモードをオーバーライド)]** をご自身のゲームモードに設定します。 - - [REGION:raw] - ![](setGameMode.png) - [/REGION] - -1. Vehicle ブループリントで、**[Project Settings Input]** カテゴリで作成した Axis Event と Action Event を呼び出すことができます。 - 1. Vehicle ブループリントを **編集** し、**Event Graph** に切り替えます。 - - ![](graphMode.png) - - 1. スロットル - - ![](throttleBP.png) - - 1. ステアリング - - ![](steeringBP.png) - - 1. ハンドブレーキ - - ![](handbrakeBP.png) - -1. プレイヤースタート - * ワールドに **Player Start** アクタがない場合、以下の順序で選択してマップに追加することができます。 - **[Modes Panel]** -> **[Placement Mode]** -> **[Basic]** -> 次に、[Player Start] をクリックしてワールドにドラッグします。 - - [REGION:raw] - ![](playerStart.png) - [/REGION] - - または現在のカメラ位置からプレイするために PIE (Play in Editor) を設定することもできます。 -1. 最後に、すべてをセットアップした状態で、**Play in Editor** を使用してビークルをテストする準備が整いました。 - - [REGION:raw] - ![](Play.png) - [/REGION] - - 上記で設定した軸と Axis と Action Bindings を前提に、**W** はスロットルを強め、**S** はブレーキを適用し、**A** は左折、**D** は右折、 - **Space Bar** はハンドブレーキを適用します。 - - - - - - - - - - - diff --git a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/VehicleIntro.KOR.udn b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/VehicleIntro.KOR.udn index a9786fb662fe..4d7e3d1f7d76 100644 --- a/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/VehicleIntro.KOR.udn +++ b/Engine/Documentation/Source/Engine/Physics/Vehicles/VehicleUserGuide/VehicleIntro.KOR.udn @@ -1,336 +1,89 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3453053 Availability:Public Title:비히클 사용 안내서 -Crumbs:%ROOT% +crumbs:%ROOT% Description:언리얼 엔진 4 블루프린트 비히클 사용 안내서입니다. -Navigation:topic -Version: 4.9 +Type:how-to SkillLevel: Advanced +Version:4.15 +Parent:Engine/Physics/Vehicles +Prereq:Engine/Physics/Vehicles/VehcileContentCreation +Order:1 +checkpoint:vehicleuserguideHT +Tags:Vehicles +topic-image:Vechicle_Topic.png -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Programming/Gameplay/Framework/Vehicle:title%](vehicle_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/content_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Programming/Gameplay/Framework/Vehicle:title% - [/PARAM] - [PARAM:description] - %Programming/Gameplay/Framework/Vehicle:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Programming/Gameplay/Framework/Vehicle] - [/PARAM] + + + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 640 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 360 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + pYelGtIMQpk + [/PARAMLITERAL] [/OBJECT] -[/VAR] -[TOC(start:2 end:3)] +이 글을 마칠 즈음이면 다른 게임 프로젝트에서도 사용할 수 있을 만큼 완벽히 동작하는 비히클이 완성되어 있을 것입니다! +## 목적 +여기서는 새로운 공백 프로젝트에서 **Wheeled Vehicle** 블루프린트 클래스를 사용하여 비히클을 만드는 법을 다루겠습니다. 정상 작동하는 비히클을 만드는 데 필요한 +모든 에디터내 아이템 제작 프로세스를 안내해 드리겠지만, 별도의 **스켈레탈 메시** 와 **피직스 애셋** 이 준비되어 있다 가정합니다. 이 글을 마칠 즈음이면 +비히클 게임 또는 비히클 템플릿에 있는 것과 비슷한 정상 작동 비히클이 완성되어 있을 것입니다. -빈 프로젝트에서 **Wheeled Vehicle** 블루프린트 클래스를 사용하여 블루프린트를 만드는 방법에 대해 다루는 문서입니다. 이 프로세스를 통해 에디터내 필수 항목 전체를 생성해 보지만, -비히클에 쓸 **스켈레탈 메시** 와 **피직스 애셋** 은 갖고있다 가정합니다. - +[REGION:note] 비히클 **스켈레탈 메시** 와 **피직스 애셋** 을 엔진에 임포트하는 법에 대한 정보가 필요하다면, [](Engine/Physics/Vehicles/VehcileContentCreation) 문서를 참고하세요. -또는 **비히클 템플릿** 이나 **비히클 게임** 을 통해 미리 만들어진 **스켈레탈 메시** 나 **피직스 애셋** 에서 작업할 수도 있습니다. +또는 **비히클 템플릿** 이나 **비히클 게임** 프로젝트를 통해 미리 만들어진 **스켈레탈 메시** 나 **피직스 애셋** 에서 작업할 수도 있습니다. +**비히클 템플릿** 은 **언리얼 프로젝트 브라우저** 의 **새 프로젝트** 메뉴에 있으며, **비히클 게임** 은 **에픽 게임스 런처** 의 **학습** 탭에 있습니다. +[/REGION] +## 목표 -## 콘텐츠 +이 튜토리얼 전반에 걸쳐 언리얼 엔진 4 (UE4) 의 비히클을 이루는 핵심 컴포넌트를 생성하게 됩니다. 이 중 일부는 UE4 외부에서 애셋을 만들어야 하는 반면 컴포넌트 대부분은 +에디터 안에서 바로 만들 수 있습니다! -언리얼 엔진 4 의 비히클은 다수의 애셋으로 구성되어 있습니다: +우리가 만들 비히클을 이루는 애셋을 개별 단위로 나누어 보면 이렇습니다: * **스켈레탈 메시** 하나. * **피직스 애셋** 하나. * **애니메이션 블루프린트** 하나. * Vehicle (비히클) 블루프린트 하나. * Wheel (휠) 블루프린트 하나 이상. -* TireType (타이어 타입) **데이터 애셋** 하나. +* TireConfig **데이터 애셋** 하나. [REGION:raw] ![](overview.png)(convert:false) [/REGION] -[REGION:note] -이 문서에서는 언리얼 엔진 4 에서 작동하는 비히클을 만드는 데 필요한 블루프린트 셋업에 대해 다루며, 이미 작업할 비히클 애셋이 있다고 가정합니다. -**스켈레탈 메시** 와 **피직스 애셋** 셋업 관련 상세 정보는 [](Engine/Physics/Vehicles/VehcileContentCreation) 문서를 참고하시기 바랍니다. +이 글을 마칠 즈음이면 이들 애셋 유형 각각을 구성하는 방법과, 비히클에 생동감을 불어넣기 위한 조합 방법을 확인할 수 있을 것입니다! + +* TireConfig 데이터 애셋 환경설정 방법 +* 앞/뒤 휠에 대한 휠 블루프린트 환경설정 방법 +* 비히클 전용 애니메이션 블루프린트 구성 방법 +* 스켈레탈 메시, 애니메이션 블루프린트, 휠 블루프린트로 비히클 블루프린트 환경설정 방법 +* 축 매핑 및 바인딩으로 비히클 제어 방법 +* 비히클 스폰을 위한 새 게임 모드 생성 및 할당 방법 + +[OBJECT:TopicList] + [PARAM:icon] + ![](%ROOT%/build_icon.png)(convert:false) + [/PARAM] + [PARAM:title] + 단계 + [/PARAM] + [PARAM:description] + [/PARAM] + [PARAM:links] + [DIR(output:"checkpoint" parent:"Engine/Physics/Vehicles/VehicleUserGuide" org:"hierarchy")] + [/PARAM] +[/OBJECT] + +[REGION:call_to_action] + [클릭하면 시작합니다.](Engine/Physics/Vehicles/VehicleUserGuide/1 "%Engine/Physics/Vehicles/VehicleUserGuide/1:title%") [/REGION] -## 비히클 블루프린트 만들기 - -**비히클 블루프린트** 를 새로 만들려면, **콘텐츠 브라우저** 에서 **신규 추가** -> **블루프린트** 버튼을 누른 다음 "vehicle" 을 검색하여 리스트에서 **WheeledVehicle** 을 클릭합니다. - -[REGION:raw] -![](newVehicle.png)(convert:false) -[/REGION] - -## 휠 블루프린트 만들기 - -**휠 블루프린트** 를 새로 만들려면, **콘텐츠 브라우저** 에서 **추가** -> **블루프린트** 버튼을 누른 다음 "wheel" 을 검색하여 리스트에서 **VehicleWheel** 을 선택합니다. -앞바퀴와 뒷바퀴 유형을 만들려면 이 작업을 최소 한 번 더 반복해 줍니다. - -[REGION:raw] -![](newWheels.png)(convert:false) -[/REGION] - -대부분의 경우 바퀴 유형은 스티어링에 영향받는 것과 받지 않는 것, 최소 두 가지일 것입니다. 또한 반경, 질량, 폭, 핸드브레이크 이펙트, -서스펜션, 기타 프로퍼티를 설정하여 비히클에 원하는 핸들링 감을 낼 수 있습니다. - - -## TireType 데이터 애셋 만들기 - -**TypeType 데이터 애셋** 을 새로 만들려면, **콘텐츠 브라우저** 에서 **신규 추가** -> **기타** -> **데이터 애셋** -> **TireType** 선택 -> **선택** 버튼을 클릭합니다. - -[REGION:raw] -![](newDataAsset.png)(convert:false) -[/REGION] - -[EXCERPT:frictionScale] -**TireType 데이터 애셋** 에는 값이 **Friction Scale** (마찰 스케일) 하나뿐입니다. 이 값은 바퀴의 원래 마찰에 영향을 끼칠 뿐만 아니라, 급선회(hard turn)시 바퀴가 얼마나 안 -(또는 잘) 미끄러지는지 결정하는 값에 대한 스케일을 조절하기도 합니다. -[/EXCERPT:frictionScale] - -**VehicleWheel** 블루프린트 유형에 **TireType 데이터 애셋** 에 대한 프로퍼티 슬롯이 있습니다. - -## 애니메이션 블루프린트 만들기 - -**애니메이션 블루프린트** 를 새로 만들려면, **콘텐츠 브라우저** 에서 **신규 추가** -> **애니메이션** -> 목록에서 비히클에 대한 **스켈레톤** 선택 -> **Ok** 버튼을 누릅니다. - -[REGION:raw] -![](newAnimBP.png)(convert:false) -[/REGION] - - -## 애니메이션 블루프린트 편집하기 - -**콘텐츠 브라우저** 에서 **애니메이션 블루프린트** 를 더블클릭하면 페르소나에서 비히클 애니메이션 블루프린트를 편집할 수 있습니다. 비히클에 대한 **애님 그래프** 가 -4.2 릴리즈에서 크게 단순화되었습니다: - -1. **애님 그래프** 에 우클릭하고, 맥락 메뉴에서 **Mesh Space Ref Pose** 노드를 검색한 다음 선택하여 생성합니다. - - [REGION:raw] - ![](meshSpace.png) - [/REGION] - -1. **애님 그래프** 에 우클릭하고, 맥락 메뉴에서 **Whell Handler** 노드를 검색한 다음 선택하여 생성합니다. - - [REGION:raw] - ![](wheelHandler01.png) - [/REGION] - -1. **Mesh Space Ref Pose** 노드를 **Wheel Handler** 노드에 연결합니다. -1. **Wheel Handler** 노드를 **Final Animation Pose** 노드에 연결합니다. - - -![](animBPPreAnimGraph.png) - -그러면 끝! **Component to Local** 변환 노드는 자동 생성되며, 이제 애니메이션 블루프린트가 비히클의 바퀴를 구동시킵니다. - -![](animBPanimGraph.png) - -### Wheel Handler 노드 - -![](wheelHandler02.png) - -**Wheel Handler** 노드는 휠에 필요한 모든 애니메이션: 스핀, 스티어, 핸드브레이크, 서스펜션을 처리해 줍니다. 추가적인 셋업은 없으며, -그냥 휠에서 필수 정보를 (스핀은 얼마나 빠른지, 스티어링은 가능한지, 핸드브레이크에 영향받는지, 이 휠에 대한 서스펜션 세팅은 어떠한지) -전부 뽑아 휠이 연결되어 있는 본의 애니메이션으로 전환합니다. - -여기서 별도의 받침대(strut)나 서스펜션이 추가로 필요한 경우, 해당 폴리곤에 영향을 끼치는 조인트 처리를 위한 노드를 애님 그래프에 추가해 줘야 합니다. -비히클 게임의 비히클에는 휠에 대한 악셀 연결을 제어하는 조인트가 추가로 몇 개 더 있습니다. 이들은 단순한 **Look At** 노드로 구동됩니다: - -![](fullVehGameAnimBP.png) - -비히클 게임의 비히클 애님 그래프에 추가되어 있는 노드는 단순히 받침대 조인트가 휠 조인트를 가리키도록 하기 위함입니다. 휠 조인트가 Wheel Handler -노드로 구동된다고 할 때, **Look At** 노드는 서스펜션이 휠에 확실히 붙어있도록 해 줍니다. - -## TireType 데이터 애셋 편집하기 - -**콘텐츠 브라우저** 에서 **TireType 데이터 애셋** 을 더블클릭합니다. - -![](tires02.png) - -[INCLUDE:#frictionscale] - - -## 휠 블루프린트 편집하기 - -**콘텐츠 브라우저** 에서 **휠 블루프린트** 를 더블클릭하여 **블루프린트 에디터** 를 띄웁니다. - - -1. 블루프린트 에디터를 디폴트 편집 모드로 전환합니다: - - ![](defaultsMode.png) - -1. 초기 설정이 필요한 프로퍼티는 다음과 같습니다: - - * Shape Radius - 셰이프 반경 - * Shape Width - 셰이프 폭 - * Affected by Handbrake - 핸드브레이크에 영향받음 (보통 뒤쪽 휠에 한정됨) - * Steer Angle - 스티어 각도 (보통 앞쪽 휠만) - - [REGION:raw] - ![](wheelProps.png) - [/REGION] - -1. 마지막으로 '타이어 타입'을 설정해 줘야 합니다. - - [REGION:raw] - ![](tireType.png) - [/REGION] - - -각 휠마다 바꿔줘야 하는 것이 다섯 가지 있습니다. 나머지 프로퍼티는 비히클 작동 방식에 변화를 주며, 비히클 테스트를 시작하면서 미세조정 -가능합니다. - -## 비히클 블루프린트 편집하기 - -이 곳에서 비히클이 실제로 조립되기 시작합니다. 아트가 준비되고 휠 셋업이 완료되었다면, 이제 정상 작동하는 비히클을 만들어낼 수 있을 것입니다. - -**콘텐츠 브라우저** 에서 **비히클 블루프린트** 를 더블클릭하여 **블루프린트 에디터** 를 띄웁니다. - -1. "Mesh" 라는 **스켈레탈 메시 컴포넌트** 를 클릭하고 그 디테일 패널에서, **스켈레탈 메시** 프로퍼티를 비히클에 쓸 스켈레탈 메시 애셋으로 설정합니다. - - ![](componentsMode.png) - -1. **Anim Blueprint Generated Class** (애님 블루프린트 생성 클래스)를 비히클 애니메이션 블루프린트로 설정합니다. - - [REGION:raw] - ![](AnimBPandSkelMesh.png) - [/REGION] - -1. **컴포넌트** 패널로 돌아가 **카메라 컴포넌트** 를 추가합니다. - - [REGION:raw] - ![](addCamera.png) - [/REGION] - -1. 이 카메라 컴포넌트 위치는 원하는대로 잡습니다. 아래 그림에서는, 비히클 뒤에 놨습니다. - - ![](cameraPlacement.png) - -1. **Camera Settings** (카메라 세팅) -> **Use Controller View Rotation** (콘트롤러 뷰 로테이션 사용) 옵션을 끕니다. 그러면 카메라를 플레이어 콘트롤러 방향이 아닌 카메라의 시야 방향으로 고정시킵니다. - - ![](cameraControllerOff.png) - -1. **Vehicle Movement Component** (비히클 무브먼트 컴포넌트)를 선택하고 **Vehicle Setup** (비히클 셋업) 카테고리의 **Wheel Setups** (휠 셋업)을 펼칩니다. - - ![](defaultsMode.png) - -1. 각 (0-3 번) 휠에 대해: - 1. **Wheel Class** (휠 클래스)를 이미 만들어 둔 휠 블루프린트 중 하나로 설정합니다. - 1. **Bone Name** (본 이름)을 휠의 제어를 받는 조인트 이름으로 설정합니다. - - [REGION:raw] - ![](wheelsSetup.png) - [/REGION] - - _위 그림에서 **Bone Name** 은 이 스켈레탈 메시에 한정된 것입니다._ - - 휠을 할당하는 순서는 앞 휠이든 뒷 휠이든 관계가 없으며, **Bone Name** 과 **Wheel Class** 만 영향을 끼칩니다. - - [REGION:note] - 휠이 네 개 이상 필요한 경우, **Wheel Setups** 프로퍼티 옆의 "**+**" 아이콘을 클릭하여 추가할 수 있습니다. - [/REGION] - -이쯤에서 미니밴보다 너무 크기 않은 비히클이라 가정하고 기본값을 넣어 주면 테스트를 시작하기 좋은 지점이 됩니다. - - -## 테스팅 - -테스트용 비히클 셋업 방법은 몇 가지 있으며, 몇몇 셋업은 처음 시작한 템플릿에 따라 달라집니다. - -1. 콘트롤 - - [REGION:raw] - ![](input.png) - [/REGION] - - 1. **Project Settings** (프로젝트 세팅) -> **Input** (입력) - 1. **Axis Mapping** (축 매핑)을 추가합니다. **Axis Mappings** 프로퍼티 옆의 "**+**" 부호를 클릭하면 됩니다. - 1. Axis Mappings 를 펼칩니다. - 1. 축 매핑 이름을 **Forward** 로 변경합니다. - 1. **Forward** 축 매핑 옆의 "**+**" 부호를 클릭합니다. - 1. **Forward** 축 매핑을 펼칩니다. - 1. 첫 번째 "None" 을 "**W**" 로 설정합니다. - 1. 두 번째 "None" 을 "**S**" 로 설정합니다. - 1. "**S**" 매핑의 Scale 을 "-1.0" 으로 설정합니다. - 1. **축 매핑** 을 하나 더 추가합니다. **Axis Mappings** (축 매핑) 프로퍼티 옆의 "**+**" 부호를 클릭하면 됩니다. - 1. 새로운 축 매핑 이름을 **Right** 로 변경합니다. - 1. **Right** 축 매핑을 펼칩니다. - 1. 첫 번째 "None" 을 "**D**" 로 설정합니다. - 1. 두 번째 "None" 을 "**A**" 로 설정합니다. - 1. "**A**" 매핑의 스케일을 "-1.0" 으로 설정합니다. - 1. 그리고 **Action Mapping** (액션 매핑)을 추가합니다. Action Mappings 프로퍼티 옆의 "**+**" 부호를 클릭하면 됩니다. - 1. **Action Mappings** 프로퍼티를 펼칩니다. - 1. 액션 매핑 이름을 "**Handbrake**" 로 변경합니다. - 1. **Handbrake** 액션 매핑을 펼칩니다. - 1. "None" 을 "**Space Bar**" 로 설정합니다. -1. 새 게임 모드 - 1. 게임 모드 블루프린트를 새로 만듭니다. - - [REGION:raw] - ![](newGameMode.png) - [/REGION] - - 1. 새로 만든 게임 모드 블루프린트를 더블클릭하여 편집합니다. - - 1. **Game Mode** 카테고리 -> **Default Pawn Class** -> "None" 을 만들어둔 비히클 블루프린트로 변경합니다. - - [REGION:raw] - ![](defaultPawnClass.png) - [/REGION] - -1. **월드 세팅** -> **Game Mode** -> **GameMode Override** 를 만들어둔 게임 모드로 설정합니다. - - [REGION:raw] - ![](setGameMode.png) - [/REGION] - -1. 이제 비히클의 블루프린트에서, **Project Settings Input** 카테고리에 생성한 축 및 액션 이벤트상에서 호출할 수 있습니다. - 1. 비히클 블루프린트를 편집, **이벤트 그래프** 를 엽니다. - - ![](graphMode.png) - - 1. 스로틀 - - ![](throttleBP.png) - - 1. 스티어링 - - ![](steeringBP.png) - - 1. 핸드브레이크 - - ![](handbrakeBP.png) - -1. 플레이어 스타트 - * 월드에 **Player Start** (플레이어 스타트) 액터가 없는 경우, **모드 패널** -> **배치 모드** -> **기본** -> **Player Start** (플레이어 스타트)를 끌어 - 월드에 놓으면 됩니다. - - [REGION:raw] - ![](playerStart.png) - [/REGION] - - 또는 현재 카메라 위치에서 '에디터에서 플레이' 기능으로 플레이해도 됩니다. -1. 마지막으로 모든 것의 셋업을 마치면, **에디터에서 플레이** 기능으로 비히클 테스트가 가능합니다. - - [REGION:raw] - ![](Play.png) - [/REGION] - - 위의 축 및 액션 바인딩 셋업 상태에서, **W** 는 액셀러레이터, **S** 는 브레이크, **A** 는 좌회전, **D** 는 우회전, - **Space Bar** 는 핸드브레이크입니다. - - - - - - - - - - - diff --git a/Engine/Documentation/Source/Engine/Plugins/Ansel/Testing/AnselTesting.KOR.udn b/Engine/Documentation/Source/Engine/Plugins/Ansel/Testing/AnselTesting.KOR.udn index 28b5f9d8538e..197a55c6f33e 100644 --- a/Engine/Documentation/Source/Engine/Plugins/Ansel/Testing/AnselTesting.KOR.udn +++ b/Engine/Documentation/Source/Engine/Plugins/Ansel/Testing/AnselTesting.KOR.udn @@ -52,12 +52,12 @@ topic-image:Ansel_Testing_Topic.png | W | 왼쪽 아날로그 스틱 위 | 카메라를 앞으로 이동합니다. | | A | 왼쪽 조이스틱 왼쪽 | 카메라를 왼쪽으로 이동합니다. | | S | 왼쪽 조이스틱 아래 | 카메라를 뒤로 이동합니다. | -| D | 왼쪽 조이스틱 오른쪽 - 카메라를 오른쪽으로 이동합니다 | +| D | 왼쪽 조이스틱 오른쪽 | 카메라를 오른쪽으로 이동합니다 | | X | 왼쪽 트리거 | 카메라를 위로 이동합니다. | | Y | 오른쪽 트리거 | 카메라를 아래로 이동합니다. | | Shift (유지) | 오른쪽 아날로그 스틱 (누름) | 카메라 이동 속도를 가속합니다. | | [REGION:tablesection]카메라 이동[/REGION] ||| -| 좌클릭 + 마우스 이동 | 오른쪽 아날로그 스틱 - 카메라를 회전시킵니다 (yaw, pitch) | +| 좌클릭 + 마우스 이동 | 오른쪽 아날로그 스틱 | 카메라를 회전시킵니다 (yaw, pitch) | diff --git a/Engine/Documentation/Source/Engine/QuickStart/1/LDQS_1.INT.udn b/Engine/Documentation/Source/Engine/QuickStart/1/LDQS_1.INT.udn index 770533cfbcd8..b05445d26bdc 100644 --- a/Engine/Documentation/Source/Engine/QuickStart/1/LDQS_1.INT.udn +++ b/Engine/Documentation/Source/Engine/QuickStart/1/LDQS_1.INT.udn @@ -37,7 +37,33 @@ After completing this step, you will have a Template that you can build onto for 1. Click the **New Project** tab and select the **Blank** Blueprint Template, enter a Save Location and Name, then click **Create Project**. - ![](ProjectBrowser1.png)(w:720) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](NewProject_Windows.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](NewProject_Mac.png) + [/PARAM] + [/OBJECT] The **New Project** tab is where you can create new projects based off several different template types while the **Projects** tab contains any previously created projects or samples that you have downloaded. @@ -46,7 +72,33 @@ After completing this step, you will have a Template that you can build onto for After creating your project, once the Unreal Editor has finished loading, you will be presented with the Main Editor Interface as shown below. +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] ![](ExampleLevel.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](ExampleLevel_Mac.png) +[/PARAM] +[/OBJECT] In the next step, we will cover the basic controls for navigating the **Viewports** inside the Unreal Editor. diff --git a/Engine/Documentation/Source/Engine/QuickStart/1/LDQS_1.KOR.udn b/Engine/Documentation/Source/Engine/QuickStart/1/LDQS_1.KOR.udn index 53ecf86c225b..c340fc3983b8 100644 --- a/Engine/Documentation/Source/Engine/QuickStart/1/LDQS_1.KOR.udn +++ b/Engine/Documentation/Source/Engine/QuickStart/1/LDQS_1.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3481084 Availability: Public Title:1. 필수 구성 Crumbs:%ROOT%, GettingStarted, Engine/QuickStart @@ -38,7 +38,33 @@ checkpoint: editorqs 1. **새 프로젝트** 탭을 클릭한 다음 **공백** 블루프린트 템플릿을 선택하고, 저장 위치와 이름을 입력한 뒤, **프로젝트 생성** 을 클릭합니다. - ![](ProjectBrowser1.png)(w:720) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](NewProject_Windows.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](NewProject_Mac.png) + [/PARAM] + [/OBJECT] **새 프로젝트** 탭에서는 여러가지 템플릿 유형을 기반으로 새 프로젝트를 생성할 수 있는 반면, **프로젝트** 탭에는 기존에 생성된 프로젝트 또는 다운로드한 샘플이 표시됩니다. @@ -47,8 +73,35 @@ checkpoint: editorqs 프로젝트 생성 이후, 언리얼 에디터 로딩이 끝나면 메인 에디터 인터페이스가 아래와 같이 표시될 것입니다. +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] ![](ExampleLevel.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](ExampleLevel_Mac.png) +[/PARAM] +[/OBJECT] 다음 단계에서는 언리얼 에디터 안에서의 기본적인 뷰포트 조작법을 다루도록 하겠습니다. %Steps% + diff --git a/Engine/Documentation/Source/Engine/QuickStart/3/LDQS_3.INT.udn b/Engine/Documentation/Source/Engine/QuickStart/3/LDQS_3.INT.udn index 3d49ee425d14..70f152a6e55b 100644 --- a/Engine/Documentation/Source/Engine/QuickStart/3/LDQS_3.INT.udn +++ b/Engine/Documentation/Source/Engine/QuickStart/3/LDQS_3.INT.udn @@ -34,11 +34,63 @@ While there are several different ways in which you can create a new Level, we w 1. Inside the Unreal Editor, click the **File Menu** option then select **New Level...**. - ![](ContentBrowserLevel.png) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](FileMenu_Windows.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](FileMenu_Mac.png) + [/PARAM] + [/OBJECT] This will open the **New Level** dialog window: - ![](level_new.png)(w:550) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](NewLevel_Windows.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](NewLevel_Mac.png) + [/PARAM] + [/OBJECT] Above the **Default** level includes some of the commonly used assets for constructing levels, there is also a **VR-Basic** level which includes some assets for constructing levels with the VR Editor and **Empty Level** is a completely blank level with no assets. For the purposes of this guide we are going to start from scratch with a completely blank slate. diff --git a/Engine/Documentation/Source/Engine/QuickStart/3/LDQS_3.KOR.udn b/Engine/Documentation/Source/Engine/QuickStart/3/LDQS_3.KOR.udn index d5fb39cc5826..c7aac5586cf9 100644 --- a/Engine/Documentation/Source/Engine/QuickStart/3/LDQS_3.KOR.udn +++ b/Engine/Documentation/Source/Engine/QuickStart/3/LDQS_3.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3481084 Availability: Public Title:3 - 새 레벨 생성 Crumbs:%ROOT%, GettingStarted, Engine/QuickStart @@ -35,11 +35,63 @@ checkpoint: editorqs 1. 언리얼 에디터 안에서, **파일 메뉴** 옵션을 선택한 다음 **새 레벨...** 을 선택합니다. - ![](ContentBrowserLevel.png) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](FileMenu_Windows.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](FileMenu_Mac.png) + [/PARAM] + [/OBJECT] 그러면 **새 레벨** 대화창이 열립니다. - ![](level_new.png)(w:550) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](NewLevel_Windows.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](NewLevel_Mac.png) + [/PARAM] + [/OBJECT] 위의 **디폴트** 레벨에는 레벨 제작시 흔히 사용되는 애셋이 약간 포함되어 있고, **VR-Basic** 레벨에는 VR 에디터로 레벨을 제작할 때 쓰이는 애셋이 포함되어 있으며, **공백 레벨** 은 애셋 없이 완전히 비어있는 레벨입니다. 이 가이드의 목적상 완전히 비어있는 레벨에서 시작하도록 하겠습니다. diff --git a/Engine/Documentation/Source/Engine/QuickStart/4/LDQS_4.CHN.udn b/Engine/Documentation/Source/Engine/QuickStart/4/LDQS_4.CHN.udn index ebb89f9a4956..54d0d6cc0cb9 100644 --- a/Engine/Documentation/Source/Engine/QuickStart/4/LDQS_4.CHN.udn +++ b/Engine/Documentation/Source/Engine/QuickStart/4/LDQS_4.CHN.udn @@ -1,4 +1,5 @@ -Availability: Public +INTSourceChangelist:0 +Availability: Public Title:4. 放置Actor Crumbs:%ROOT%, GettingStarted, Engine/QuickStart Description:放置及操作Actor是构建任何关卡的基础。 @@ -79,7 +80,7 @@ Description:放置及操作Actor是构建任何关卡的基础。 ![](rotateStart.png) -1. 在 **模式面板** 中,切换到 **Volumes(视觉效果)** 类别。 +1. 在 **模式面板** 中,切换到 **Volumes** 类别。 1. 放置一个 **Lightmass Importance Volume(Lightmass 重要体积)** 到关卡中。 [REGION:raw] diff --git a/Engine/Documentation/Source/Engine/QuickStart/EditorQuickStart.JPN.udn b/Engine/Documentation/Source/Engine/QuickStart/EditorQuickStart.JPN.udn index 32d20f8bb8ae..375c12cbf854 100644 --- a/Engine/Documentation/Source/Engine/QuickStart/EditorQuickStart.JPN.udn +++ b/Engine/Documentation/Source/Engine/QuickStart/EditorQuickStart.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:2744014 +INTSourceChangelist:3367473 Availability:Public Title:レベル デザイナー向けクイックスタート Crumbs: %ROOT%, GettingStarted @@ -10,6 +10,7 @@ Version:4.9 parent:Engine/Editor order:1 checkpoint: editorqs +type:quick start [VAR:Topic] [OBJECT:Topic] @@ -47,7 +48,7 @@ checkpoint: editorqs ![](Finished.png) -_このガイドを終える頃には、上図のような部屋が出来上がります。_ +_このガイドを完了すると、上図のような部屋が作成されます。_ ## 目標 @@ -55,7 +56,7 @@ _このガイドを終える頃には、上図のような部屋が出来上が ## 目的 -このチュートリアルでは、以下の習得を目指します。 +このチュートリアルでは以下を習得します。 * ビューポートのナビゲーション方法 * 新規レベルの作成方法 @@ -77,5 +78,5 @@ _このガイドを終える頃には、上図のような部屋が出来上が [/OBJECT] [REGION:call_to_action] - [クイックスタートへ](Engine/QuickStart/1 "%Engine/QuickStart/1:title%") + [クリックしてスタート](Engine/QuickStart/1 "%Engine/QuickStart/1:title%") [/REGION] diff --git a/Engine/Documentation/Source/Engine/QuickStart/EditorQuickStart.KOR.udn b/Engine/Documentation/Source/Engine/QuickStart/EditorQuickStart.KOR.udn index addcfc010604..7306d7167c60 100644 --- a/Engine/Documentation/Source/Engine/QuickStart/EditorQuickStart.KOR.udn +++ b/Engine/Documentation/Source/Engine/QuickStart/EditorQuickStart.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3367473 Availability:Public Title: 레벨 디자이너 퀵스타트 가이드 Crumbs: %ROOT%, GettingStarted @@ -10,6 +10,7 @@ Version: 4.9 parent:Engine/Editor order:1 checkpoint: editorqs +type:quick start [VAR:Topic] [OBJECT:Topic] diff --git a/Engine/Documentation/Source/Engine/Rendering/HDRDisplayOutput/HDRDispalyOutput.CHN.udn b/Engine/Documentation/Source/Engine/Rendering/HDRDisplayOutput/HDRDispalyOutput.CHN.udn new file mode 100644 index 000000000000..129b412aed0f --- /dev/null +++ b/Engine/Documentation/Source/Engine/Rendering/HDRDisplayOutput/HDRDispalyOutput.CHN.udn @@ -0,0 +1,134 @@ +INTSourceChangelist:0 +Availability: Docs +Crumbs: +Title: High Dynamic Range Display Output +Description: Overview for HDR Display Output and available options. +Type: Overview +SkillLevel: Intermediate +Version: 4.15 +Parent: Engine/Rendering/ +Order: +Tags: Rendering + + + +In Unreal Engine 4, you can now output to High Dynamic Range (HDR) displays taking advantage of features such as higher contrast and wider color gamut! The goal here is to give the displayed images the +characteristics that are more like natural light conditions experienced in the "real world". This is part of the move to the **Academy Color Encoding System** (ACES) standard that is a pipeline to ensure +consistent color is preserved across multiple formats and displays, and also as a way to _future-proof_ the source material used without having to adjust it for another medium. + +[REGION:fullwidth raw] +![](LDR_HDRcomparison.jpg) +[/REGION] +[REGION:caption] +_These are simulated images and are for demonstration purposes only since it is impossible to convey HDR difference on an LDR screen._ +[/REGION] + +with the current implementation, the full processing of the rendered scene is handled through what is known as the **ACES Viewing Transform**. This process works by using scene-referred and display-referred images. + +* **Scene-referred** images maintain the original _linear light_ values of the source materials without limiting the exposure range. +* **Display-referred** is the final image transformed into the color space of the display being used. + +By using this pipeline, the original source files do not have to be edited each time they are used with a different display in order to guarantee correct coloring. Instead, the display being output to maps it to the +correct color space. + +The ACES Viewing Transform, more specifically, works in the following order in the viewing pipeline: + +* **Look Modification Transform (LMT)** - This part of the process takes the ACES color-encoded image that has had a creative "look" (color grading and correction) applied to it and then outputs the images rendered with +ACES in combination with the Reference Rendering Transform (RRT) and an Output Device Transform (ODT). +* **Reference Rendering Transform (RRT)** - Then, this part takes the scene-referred color values and converts them to display-referred. In this process, it enables the rendered images to not rely on a specific display +and, instead, can ensure a larger gamut and dynamic range that is correct for the specific display it's being output to, including ones that have yet to be created. +* **Output Device Transform (ODT)** - Finally, this takes the HDR Data output of the RRT to then match it with the different devices and color spaces they can display. Because of this, each target requires its own +ODT to be matched against (eg Rec709, Rec2020, DCI-P3, etc.). + + +## Enabling HDR Output + +You can enable HDR output at runtime by toggling the console variables or by using the **GameUserSettings** node in Blueprints. + +![](HDRGameUserSettings.png)(w:800) + +The **GameUserSettings** controls will automatically clamp to the closest available match for the current output device and set all flags accordingly. Alternatively, you can use the following console variables to enable +and change the available options for the HDR device and color gamut output need. + +[REGION:simpletable] +| Console Variable | Description | +| --- | --- | +| `r.HDR.EnableHDROutput` | When set to 1, this recreates the swap-chain and enables HDR output. | +| `r.HDR.Display.OutputDevice` | This is the device format of the output display [INCLUDE:#deviceOuptut] | +| `r.HDR.Display.ColorGamut` | This is the color gamut of the output display. [INCLUDE:#colorGamut] | +[/REGION] + + + +Once you've setup the Blueprint or C++ call for GameUserSettings, you can run any cooked project, use the command line argument `-game mode`, use Standalone game mode, or Play-in-Editor (PIE) in a new window using +exclusive fullscreen (press **Alt** + **Enter** or use the command `fullscreen`). Using borderless windowed or windowed mode will not currently work for HDR output. + + +### Low Dynamic Range (LDR) UI support in HDR + +[REGION:note] +This feature is experimental and may change in a future release. +[/REGION] + +There is support for bringing Low Dynamic Range (LDR) + +When HDR output has been enabled your User Interface (UI) may not look correct. We've added experimental support for LDR UI composition for this reason. It attempts to match the +LDR look as closely as possible, although, it's recommended to boost the UI slightly to avoid looking washed out next to the vibrancy of the main scene. + +To do this, you can use the following console variables: + +[REGION:simpletable] +| Console Variable | Description | +| --- | --- | +| `r.HDR.UI.CompositeMode` | When set to 1, this enables HDR UI composition, which attempts to preserve LDR visuals and blending. | +| `r.HDR.UI.Level` | This adjusts the brightness of the composited UI. It is recommended to use a value of 1.5 or 2. | +[/REGION] + + +## HDR Hardware and Setup Considerations + +With the many different types of displays and TVs that are available, along with console and PC considerations, you may find that you need to use a specific piece of hardware or change a setting to get +HDR output to work properly. The following are some things to consider when you're running through your setup process: + +* Make sure that your system is connected to the HDR display using a high-speed HDMI 2.0 cable so that you can take advantage of the transfers speeds. (HDMI 1.4 may work, but may have issues displaying the content.) +Not all HDMI ports may accept HDMI 2.0 and HDR. Refer to your display's manual if you're unsure. +* Ensure that the TV port is HDR enabled. Sometimes this may be listed in your TV or display settings as "HDMI Deep Color" or "Enhanced Format." Refer to your display's manual if you're unsure. +* With some consoles, like the PS4, you may need to disable the system setting for **Enable HDCP** for HDR output to work properly. +* For some displays, you may need to adjust display settings to get the correct output. + * With NVIDIA GPUs, use the NVIDIA Control Panel and adjust the display resolution Output Color Format to use **RGB** and the Output Color Depth to use **10-bit** or **12-bit**. + +## Notes and Limitations + +* By default, the film-mapping curve is disabled during HDR output due to poor compatibility with LDR controls. +* Currently, only paths for 1000-nit and 2000-nit display outputs are implemented. +* D3D11 restrictions limit HDR output to exclusive fullscreen support only. With D3D12 support in Windows 10, this can likely be extended to enable individual viewports for HDR Output. The implementation on Mac currently supports this, already. + +## Reference Material + +* [http://www.oscars.org/science-technology/sci-tech-projects/aces](http://www.oscars.org/science-technology/sci-tech-projects/aces) +* [http://www.oscars.org/science-technology/aces/aces-documentation](http://www.oscars.org/science-technology/aces/aces-documentation) + + + diff --git a/Engine/Documentation/Source/Engine/Rendering/HDRDisplayOutput/HDRDispalyOutput.INT.udn b/Engine/Documentation/Source/Engine/Rendering/HDRDisplayOutput/HDRDispalyOutput.INT.udn index 1f5cfa8c0987..7a3e013d7bbb 100644 --- a/Engine/Documentation/Source/Engine/Rendering/HDRDisplayOutput/HDRDispalyOutput.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/HDRDisplayOutput/HDRDispalyOutput.INT.udn @@ -1,28 +1,39 @@ -Availability: Docs +Availability:Public Crumbs: Title: High Dynamic Range Display Output Description: Overview for HDR Display Output and available options. -Type: Overview +Type:overview +Type:landing SkillLevel: Intermediate -Version: 4.15 +Version: 4.16 Parent: Engine/Rendering/ -Order: +Order:28 Tags: Rendering +Topic-image:HDRDisplayOutput_Topic.png +Social-image:HDRDisplayOutput_Social.png +[TOC(start:2)] In Unreal Engine 4, you can now output to High Dynamic Range (HDR) displays taking advantage of features such as higher contrast and wider color gamut! The goal here is to give the displayed images the characteristics that are more like natural light conditions experienced in the "real world". This is part of the move to the **Academy Color Encoding System** (ACES) standard that is a pipeline to ensure consistent color is preserved across multiple formats and displays, and also as a way to _future-proof_ the source material used without having to adjust it for another medium. -[REGION:fullwidth raw] -![](LDR_HDRcomparison.jpg) +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Low Dynamic Range (LDR) ](LDR.png)(w:700) + [/PARAM] + [PARAM:after] + ![High Dynamic Range (HDR) ](HDR.png)(w:700) + [/PARAM] +[/OBJECT] +[REGION:caption] [/REGION] [REGION:caption] -_These are simulated images and are for demonstration purposes only since it is impossible to convey HDR difference on an LDR screen._ +This example is simulated and purely for demonstration purposes only. It is impossible to convey HDR differences on an LDR screen. [/REGION] -with the current implementation, the full processing of the rendered scene is handled through what is known as the **ACES Viewing Transform**. This process works by using scene-referred and display-referred images. +With the current implementation, the full processing of the rendered scene is handled through what is known as the **ACES Viewing Transform**. This process works by using scene-referred and display-referred images. * **Scene-referred** images maintain the original _linear light_ values of the source materials without limiting the exposure range. * **Display-referred** is the final image transformed into the color space of the display being used. @@ -30,7 +41,7 @@ with the current implementation, the full processing of the rendered scene is ha By using this pipeline, the original source files do not have to be edited each time they are used with a different display in order to guarantee correct coloring. Instead, the display being output to maps it to the correct color space. -The ACES Viewing Transform, more specifically, works in the following order in the viewing pipeline: +The ACES Viewing Transform works in the following order in the viewing pipeline: * **Look Modification Transform (LMT)** - This part of the process takes the ACES color-encoded image that has had a creative "look" (color grading and correction) applied to it and then outputs the images rendered with ACES in combination with the Reference Rendering Transform (RRT) and an Output Device Transform (ODT). @@ -39,6 +50,9 @@ and, instead, can ensure a larger gamut and dynamic range that is correct for th * **Output Device Transform (ODT)** - Finally, this takes the HDR Data output of the RRT to then match it with the different devices and color spaces they can display. Because of this, each target requires its own ODT to be matched against (eg Rec709, Rec2020, DCI-P3, etc.). +[REGION:note] +For additional information on the ACES Viewing Transform, you can download the PDF documentation from the [ACES GitHub](https://github.com/ampas/aces-dev/tree/master/documents) page or follow the links in the Reference Material section of this page. +[/REGION] ## Enabling HDR Output @@ -46,53 +60,55 @@ You can enable HDR output at runtime by toggling the console variables or by usi ![](HDRGameUserSettings.png)(w:800) -The **GameUserSettings** controls will automatically clamp to the closest available match for the current output device and set all flags accordingly. Alternatively, you can use the following console variables to enable -and change the available options for the HDR device and color gamut output need. +The Game User Settings controls will automatically clamp to the closest available match for the current output device and set all flags accordingly. Alternatively, you can use the following console variables to enable +and change the available options for the HDR device and color gamut output needed. [REGION:simpletable] | Console Variable | Description | | --- | --- | -| `r.HDR.EnableHDROutput` | When set to 1, this recreates the swap-chain and enables HDR output. | -| `r.HDR.Display.OutputDevice` | This is the device format of the output display [INCLUDE:#deviceOuptut] | -| `r.HDR.Display.ColorGamut` | This is the color gamut of the output display. [INCLUDE:#colorGamut] | +| **r.HDR.EnableHDROutput** | When set to 1, this recreates the swap-chain and enables HDR output. | +| **r.HDR.Display.OutputDevice** | This is the device format of the output display [INCLUDE:#deviceOuptut] | +| **r.HDR.Display.ColorGamut** | This is the color gamut of the output display. [INCLUDE:#colorGamut] | [/REGION] Once you've setup the Blueprint or C++ call for GameUserSettings, you can run any cooked project, use the command line argument `-game mode`, use Standalone game mode, or Play-in-Editor (PIE) in a new window using -exclusive fullscreen (press **Alt** + **Enter** or use the command `fullscreen`). Using borderless windowed or windowed mode will not currently work for HDR output. +exclusive fullscreen (press **Alt** + **Enter** or use the command `fullscreen` from the console window). + +[REGION:note] +Using borderless window or windowed mode will not currently work for HDR output. +[/REGION] ### Low Dynamic Range (LDR) UI support in HDR -[REGION:note] -This feature is experimental and may change in a future release. +[REGION:warning] +This particular feature is experimental and may change in a future release. [/REGION] -There is support for bringing Low Dynamic Range (LDR) - When HDR output has been enabled your User Interface (UI) may not look correct. We've added experimental support for LDR UI composition for this reason. It attempts to match the LDR look as closely as possible, although, it's recommended to boost the UI slightly to avoid looking washed out next to the vibrancy of the main scene. @@ -101,8 +117,8 @@ To do this, you can use the following console variables: [REGION:simpletable] | Console Variable | Description | | --- | --- | -| `r.HDR.UI.CompositeMode` | When set to 1, this enables HDR UI composition, which attempts to preserve LDR visuals and blending. | -| `r.HDR.UI.Level` | This adjusts the brightness of the composited UI. It is recommended to use a value of 1.5 or 2. | +| **r.HDR.UI.CompositeMode** | When set to 1, this enables HDR UI composition, which attempts to preserve LDR visuals and blending. | +| **r.HDR.UI.Level** | This adjusts the brightness of the composited UI. It is recommended to use a value of 1.5 or 2. | [/REGION] @@ -116,7 +132,14 @@ Not all HDMI ports may accept HDMI 2.0 and HDR. Refer to your display's manual i * Ensure that the TV port is HDR enabled. Sometimes this may be listed in your TV or display settings as "HDMI Deep Color" or "Enhanced Format." Refer to your display's manual if you're unsure. * With some consoles, like the PS4, you may need to disable the system setting for **Enable HDCP** for HDR output to work properly. * For some displays, you may need to adjust display settings to get the correct output. - * With NVIDIA GPUs, use the NVIDIA Control Panel and adjust the display resolution Output Color Format to use **RGB** and the Output Color Depth to use **10-bit** or **12-bit**. + * With NVIDIA GPUs, use the NVIDIA Control Panel and adjust the display resolution Output Color Format to use **RGB** and the Output Color Depth to use **10-bit** or **12-bit**. Depending on your + hardware you may only have certain options available. Refer to your display's manual if you're unsure. + [REGION:lightbox] + [![](NVControlPanel.png)(w:400)](NVControlPanel.png) + [/REGION] + [REGION:caption] + _Click image for full size view._ + [/REGION] ## Notes and Limitations @@ -126,8 +149,5 @@ Not all HDMI ports may accept HDMI 2.0 and HDR. Refer to your display's manual i ## Reference Material -* [http://www.oscars.org/science-technology/sci-tech-projects/aces](http://www.oscars.org/science-technology/sci-tech-projects/aces) -* [http://www.oscars.org/science-technology/aces/aces-documentation](http://www.oscars.org/science-technology/aces/aces-documentation) - - - +* ["ACES." Oscars.org | Academy of Motion Picture Arts and Sciences. N.p., 06 Feb. 2017. Web. 05 June 2017.](http://www.oscars.org/science-technology/sci-tech-projects/aces) +* ["Aces Documentation." Oscars.org | Academy of Motion Picture Arts and Sciences. N.p., 26 Sept. 2016. Web. 05 June 2017.](http://www.oscars.org/science-technology/aces/aces-documentation) diff --git a/Engine/Documentation/Source/Engine/Rendering/HDRDisplayOutput/HDRDispalyOutput.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/HDRDisplayOutput/HDRDispalyOutput.JPN.udn index 129b412aed0f..1dd460370e97 100644 --- a/Engine/Documentation/Source/Engine/Rendering/HDRDisplayOutput/HDRDispalyOutput.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/HDRDisplayOutput/HDRDispalyOutput.JPN.udn @@ -1,70 +1,89 @@ -INTSourceChangelist:0 -Availability: Docs +INTSourceChangelist:3387247 +Availability:Docs Crumbs: -Title: High Dynamic Range Display Output -Description: Overview for HDR Display Output and available options. -Type: Overview -SkillLevel: Intermediate -Version: 4.15 -Parent: Engine/Rendering/ +Title:High Dynamic Range 対応ディスプレイへの出力 +Description:High Dynamic Range 対応ディスプレイへの出力およびオプションの概要 +Type:Overview +SkillLevel:Intermediate +Version:4.15 +Parent:Engine/Rendering/ Order: -Tags: Rendering +Tags:Rendering -In Unreal Engine 4, you can now output to High Dynamic Range (HDR) displays taking advantage of features such as higher contrast and wider color gamut! The goal here is to give the displayed images the -characteristics that are more like natural light conditions experienced in the "real world". This is part of the move to the **Academy Color Encoding System** (ACES) standard that is a pipeline to ensure -consistent color is preserved across multiple formats and displays, and also as a way to _future-proof_ the source material used without having to adjust it for another medium. +高いコントラストと幅広い色域などの機能を使って、アンリアル エンジン 4 で High Dynamic Range (HDR) 対応ディスプレイへ出力できるようになりました。表示された画像に +「現実世界」で体感する自然光の状態ような特性を出すことが目標です。これは、複数のフォーマットとディスプレイ上で、確実に色に整合性を持たせるパイプラインである **Academy Color Encoding System** (ACES) スタンダードへの動きの表れでもあり、 +他の媒体用に色を調節せずに使用されたソース マテリアルが _古くならない_ ようにする手段でもあります。 +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Low Dynamic Range (LDR) ](LDR.png)(w:700) + [/PARAM] + [PARAM:after] + ![High Dynamic Range (HDR) ](HDR.png)(w:700) + [/PARAM] +[/OBJECT] + +[REGION:note] +LDR スクリーンでは HDR の違いを表現できないので、デモ用にシミュレーションした画像です。 +[/REGION] + + + + +現在の実装では、レンダリングされたシーンの処理は、いわゆる **ACES Viewing Transform** がすべて行っています。処理の工程では、シーン基準画像とディスプレイ基準画像が使用されます。 + +* **シーン リファード (Scene-referred)** 画像は、露出範囲を制限することなくソース マテリアルのオリジナル _リニア ライト_ 値を維持します。 +* **ディスプレイ リファード (Display-referred)** 画像は、使用中のディスプレイのカラースペースへ変換される最終画像です。 + +このパイプラインを使用すると、ディスプレイを変えるたびにオリジナルのソース ファイルを編集しなくても必ず正しい色合いがでます。代わりに、出力先のディスプレイが +正しい色空間にマップします。 + +厳密に言えば、ACES Viewing Transform は、表示パイプラインで以下の順序で機能します。 + +* **Look Modification Transform (LMT)** - クリエイティブな "外見" (カラー グレーディングおよび補正) を適用した ACES カラー エンコード画像を受け取り、 +Reference Rendering Transform (RRT) および Output Device Transform (ODT) と組み合わせて ACES でレンダリングされた画像を出力します。 +* **Reference Rendering Transform (RRT)** - 次に、シーン リファード画像のカラー値を受け取り、それをディスプレイ リファード画像に変換します。この処理では、レンダリングされた画像を特定のディスプレイだけに依存しないようにします。 +そして、出力先の指定されたディスプレイに合わせて、広めの範囲とダイナミックレンジが保証されます。 +* **Output Device Transform (ODT)** - 最後に、RPT の HDR Data 出力を受け取り、各種デバイスと色空間に一致させます。このため、各ターゲットはそれぞれの ODT を一致させる必要があります +(Rec709、Rec2020、DCI-P3 など)。 + +[REGION:note] +ACES Viewing Transform の追加情報については、[ACES GitHub](https://github.com/ampas/aces-dev/tree/master/documents) から PDF ドキュメントをダウンロードすることができます。または、本ページの『リファレンス』セクションをご覧ください。 [/REGION] -with the current implementation, the full processing of the rendered scene is handled through what is known as the **ACES Viewing Transform**. This process works by using scene-referred and display-referred images. +## HDR Output を有効にする -* **Scene-referred** images maintain the original _linear light_ values of the source materials without limiting the exposure range. -* **Display-referred** is the final image transformed into the color space of the display being used. - -By using this pipeline, the original source files do not have to be edited each time they are used with a different display in order to guarantee correct coloring. Instead, the display being output to maps it to the -correct color space. - -The ACES Viewing Transform, more specifically, works in the following order in the viewing pipeline: - -* **Look Modification Transform (LMT)** - This part of the process takes the ACES color-encoded image that has had a creative "look" (color grading and correction) applied to it and then outputs the images rendered with -ACES in combination with the Reference Rendering Transform (RRT) and an Output Device Transform (ODT). -* **Reference Rendering Transform (RRT)** - Then, this part takes the scene-referred color values and converts them to display-referred. In this process, it enables the rendered images to not rely on a specific display -and, instead, can ensure a larger gamut and dynamic range that is correct for the specific display it's being output to, including ones that have yet to be created. -* **Output Device Transform (ODT)** - Finally, this takes the HDR Data output of the RRT to then match it with the different devices and color spaces they can display. Because of this, each target requires its own -ODT to be matched against (eg Rec709, Rec2020, DCI-P3, etc.). - - -## Enabling HDR Output - -You can enable HDR output at runtime by toggling the console variables or by using the **GameUserSettings** node in Blueprints. +HDR 出力はランタイム時にコンソール変数を切り替えるか、ブループリントの **GameUserSettings** ノードを使って有効にします。 ![](HDRGameUserSettings.png)(w:800) -The **GameUserSettings** controls will automatically clamp to the closest available match for the current output device and set all flags accordingly. Alternatively, you can use the following console variables to enable -and change the available options for the HDR device and color gamut output need. +**GameUserSettings** コントロールは、利用できる最も近くの出力デバイスと一致するように自動的にクランプし、すべてのフラグもそれに合わせて設定します。もしくは、以下のコンソール変数でも、 +HDR デバイスおよび必要なカラー範囲出力のオプションの有効化や変更ができます。 [REGION:simpletable] -| Console Variable | Description | +| コンソール変数 | 説明 | | --- | --- | -| `r.HDR.EnableHDROutput` | When set to 1, this recreates the swap-chain and enables HDR output. | -| `r.HDR.Display.OutputDevice` | This is the device format of the output display [INCLUDE:#deviceOuptut] | -| `r.HDR.Display.ColorGamut` | This is the color gamut of the output display. [INCLUDE:#colorGamut] | +| `r.HDR.EnableHDROutput` | 1 に設定するとスワップ チェーンを作成し、HDR 出力が有効になります。| +| `r.HDR.Display.OutputDevice` | 出力ディスプレイのデバイス フォーマットです [INCLUDE:#deviceOuptut] | +| `r.HDR.Display.ColorGamut` | 出力ディスプレイの色域です。 [INCLUDE:#colorGamut] | [/REGION] -Once you've setup the Blueprint or C++ call for GameUserSettings, you can run any cooked project, use the command line argument `-game mode`, use Standalone game mode, or Play-in-Editor (PIE) in a new window using -exclusive fullscreen (press **Alt** + **Enter** or use the command `fullscreen`). Using borderless windowed or windowed mode will not currently work for HDR output. - - -### Low Dynamic Range (LDR) UI support in HDR +GameUserSettings のブループリントまたは C++ コールを設定したら、クック済みのプロジェクトの実行、コマンドライン引数 `-game mode`、Standalone ゲームモードの使用、 +あるいは排他的全画面 (**[Alt]** + **[Enter]** またはコマンド `fullscreen` を押します) での Play-in-Editor (PIE) の使用が可能になります。 [REGION:note] -This feature is experimental and may change in a future release. +現在のところ、縁なしウィンドウあるいはウィンドウ モードは HDR 出力には機能しません。 [/REGION] -There is support for bringing Low Dynamic Range (LDR) -When HDR output has been enabled your User Interface (UI) may not look correct. We've added experimental support for LDR UI composition for this reason. It attempts to match the -LDR look as closely as possible, although, it's recommended to boost the UI slightly to avoid looking washed out next to the vibrancy of the main scene. +### HDR での Low Dynamic Range (LDR) UI サポート -To do this, you can use the following console variables: +[REGION:note] +この機能は実験的なものであり、今後のリリースにおいて変更される可能性があります。 +[/REGION] + +HDR 出力が有効にされていると、ユーザーインターフェース (UI) が正しく表示されないことがあります。このため、LDR UI コンポジションに実験的サポートを追加しました。LDR の見た目をできる限りマッチさせるようにします。 +ただし、メインシーンの活気の影に埋もれてしまわないように UI の強化を推奨します。 + +以下のコンソール変数を使って行います。 [REGION:simpletable] -| Console Variable | Description | +| コンソール変数 | 説明 | | --- | --- | -| `r.HDR.UI.CompositeMode` | When set to 1, this enables HDR UI composition, which attempts to preserve LDR visuals and blending. | -| `r.HDR.UI.Level` | This adjusts the brightness of the composited UI. It is recommended to use a value of 1.5 or 2. | +| `r.HDR.UI.CompositeMode` | 1 に設定すると HDR UI コンポジションが有効になり、LDR のビジュアルとブレンドを維持しようとします。 | +| `r.HDR.UI.Level` | 合成した UI の輝度を調整します。使用する値は 1.5 または 2 をお勧めします。 | [/REGION] -## HDR Hardware and Setup Considerations +## HDR ハードウェアおよびセットアップに関する考慮事項 -With the many different types of displays and TVs that are available, along with console and PC considerations, you may find that you need to use a specific piece of hardware or change a setting to get -HDR output to work properly. The following are some things to consider when you're running through your setup process: +ディスプレイやテレビとして利用できる様々な種類がありますが、コンソールや PC の考慮事項と同様に、 +特定のハードウェア部品の使用や HDR 出力を正しく動かすための設定変更が必要になります。以下は、設定を行う際の考慮事項です。 -* Make sure that your system is connected to the HDR display using a high-speed HDMI 2.0 cable so that you can take advantage of the transfers speeds. (HDMI 1.4 may work, but may have issues displaying the content.) -Not all HDMI ports may accept HDMI 2.0 and HDR. Refer to your display's manual if you're unsure. -* Ensure that the TV port is HDR enabled. Sometimes this may be listed in your TV or display settings as "HDMI Deep Color" or "Enhanced Format." Refer to your display's manual if you're unsure. -* With some consoles, like the PS4, you may need to disable the system setting for **Enable HDCP** for HDR output to work properly. -* For some displays, you may need to adjust display settings to get the correct output. - * With NVIDIA GPUs, use the NVIDIA Control Panel and adjust the display resolution Output Color Format to use **RGB** and the Output Color Depth to use **10-bit** or **12-bit**. +* 転送速度を速めるために、お使いの HDR ディスプレイが高速 HDMI 2.0 ケーブルで接続されていることを確認してください。(HDMI 1.4 も使用できますが、コンテンツの表示に問題が生じる可能性があります。) +すべての HDMI ポートが HDMI 2.0 および HDR に対応しているわけではありません。ディスプレイの取扱説明書で今一度ご確認ください。 +* TV ポートの HDR は必ず有効にしてください。テレビまたはディスプレイ設定の中に "HDMI Deep Color" や "Enhanced Format" として表示されていることがあります。ディスプレイの取扱説明書で今一度ご確認ください。 +* PS4 など、コンソールによっては HDR 出力を正しく機能させるために **Enable HDCP** を無効にしなければいけない場合があります。 +* ディスプレイによっては、正しく出力するためにディスプレイ設定の調節が必要な場合があります。 + * NVIDIA GPU の場合は、NVIDIA コントロール パネルで、ディスプレイ解像度の Output Color Format を **RGB** に、Output Color Depth は **10-bit** または **12-bit** に設定します。ハードウェアによっては、 + 使用できるオプションが限れている場合があります。ディスプレイの取扱説明書で今一度ご確認ください。 + [REGION:lightbox] + [![](NVControlPanel.png)(w:400)](NVControlPanel.png) + [/REGION] + [REGION:caption] + _画像をクリックしてフルサイズで表示_ + [/REGION] -## Notes and Limitations +## 注意事項と考慮事項 -* By default, the film-mapping curve is disabled during HDR output due to poor compatibility with LDR controls. -* Currently, only paths for 1000-nit and 2000-nit display outputs are implemented. -* D3D11 restrictions limit HDR output to exclusive fullscreen support only. With D3D12 support in Windows 10, this can likely be extended to enable individual viewports for HDR Output. The implementation on Mac currently supports this, already. +* フィルム マップ カーブは LDR コントロールとの相性が悪いため、HDR 出力中はデフォルトで無効されています。 +* 現在実装されているパスは、1000-nit および 2000-nit ディスプレイ出力用のみです。 +* D3D11 の場合は、HDR への出力が排他的全画面のみに制限されています。D3D12 がサポートされている Windows 10 では、おそらく HDR 出力の個々のビューポートを有効にできるように拡張されると思われます。Mac では既に実装はサポートされています。 -## Reference Material +## リファレンス * [http://www.oscars.org/science-technology/sci-tech-projects/aces](http://www.oscars.org/science-technology/sci-tech-projects/aces) * [http://www.oscars.org/science-technology/aces/aces-documentation](http://www.oscars.org/science-technology/aces/aces-documentation) diff --git a/Engine/Documentation/Source/Engine/Rendering/HDRDisplayOutput/HDRDispalyOutput.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/HDRDisplayOutput/HDRDispalyOutput.KOR.udn new file mode 100644 index 000000000000..f774d15cf66c --- /dev/null +++ b/Engine/Documentation/Source/Engine/Rendering/HDRDisplayOutput/HDRDispalyOutput.KOR.udn @@ -0,0 +1,162 @@ +INTSourceChangelist:3387247 +Availability: Docs +Crumbs: +Title: 하이 다이내믹 레인지 디스플레이 출력 +Description: HDR Display Output 및 그 옵션에 대한 개요입니다. +Type: Overview +SkillLevel: Intermediate +Version: 4.15 +Parent: Engine/Rendering/ +Order: +Tags: Rendering + + + +언리얼 엔진 4 에서는 이제 더욱 높은 대비값과 폭넓은 색 공간(color gamut)을 활용할 수 있는 하이 다이내믹 레인지 (HDR) 디스플레이로 출력할 수 있습니다. 이 글의 목표는 디스플레이되는 이미지에 +"현실 세계"에서 느낄 수 있는 보다 자연스러운 라이팅 조건과 같은 특성을 낼 수 있도록 하는 것입니다. 이는 **Academy Color Encoding System** (ACES) 표준으로 넘어가기 위한 과정 중의 하나로, 이를 통해 +여러 포맷과 디스플레이에 걸쳐 일관된 색 보존이 가능하며, 소스 머티리얼을 별다른 수정 없이 다른 미디어에도 사용할 수 있도록 하는 미래 경쟁력 확보 차원의 방편이기도 합니다. + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![로우 다이내믹 레인지 (LDR) ](LDR.png)(w:700) + [/PARAM] + [PARAM:after] + ![다이 다이내믹 레인지 (HDR) ](HDR.png)(w:700) + [/PARAM] +[/OBJECT] + +[REGION:note] +이미지는 시뮬레이션이며, 순전히 데모용입니다. LDR 화면에 HDR 차이를 나타내는 것은 불가능하기 때문입니다. +[/REGION] + + + + +현재 구현을 통해서는, 렌더링된 씬의 전체 처리는 **ACES Viewing Transform** 이라 알려진 방식을 통해 처리합니다. 이 프로세스 작동방식은 씬 참조 이미지와 디스플레이 참조 이미지를 사용하는 것입니다. + +* **Scene-referred** (씬 참조) 이미지는 노출 범위 제한 없이 소스 머티리얼의 원본 _리니어 라이트_ 값을 유지합니다. +* **Display-referred** (디스플레이 참조) 이미지는 사용중인 디스플레이의 컬러 스페이스로 변형된 최종 이미지입니다. + +이 파이프라인을 사용하면, 다른 디스플레이를 사용할 때마다 올바른 컬러 스페이스를 사용하도록 원본 소스 파일을 매번 수정할 필요가 없습니다. 대신 출력중인 디스플레이가 올바른 컬러 스페이스에 +매핑되도록 해주면 됩니다. + +보다 구체적으로 ACES Viewing Transform 은 뷰 파이프라인에서 다음과 같은 방식으로 작동합니다: + +* **Look Modification Transform (LMT)** - 프로세스 이 부분은 창의적 "외형" (컬러 그레이딩 및 보정)을 적용시킨 ACES 컬러 인코딩된 이미지를 받은 뒤, ACES 로 렌더링된 이미지를 출력합니다. 여기에는 Reference Rendering Transform (RRT) 와 Output Device Transform (ODT) 가 조합됩니다. +* **Reference Rendering Transform (RRT)** - 그리고서 이 부분은 씬 참조 컬러 값을 받아 디스플레이 참조 값으로 변환합니다. 이 과정에서 렌더링된 이미지가 특정 디스플레이에만 의존하도록 하는 대신, +아직 생성되지 않은 디스플레이를 포함해서 출력 대상 디스플레이에 맞도록 더 큰 색 공간과 다이내믹 레인지를 갖도록 합니다. +* **Output Device Transform (ODT)** - 마지막으로 이 단계에서는 RRT 의 HDR 데이터 출력을 받은 뒤 다양한 디바이스와 거기서 디스플레이 가능한 컬러 스페이스에 일치시킵니다. 이 때문에, 각 타겟은 +일치시킬 별도의 ODT 가 필요합니다 (예: Rec709, Rec2020, DCI-P3, 등). + +[REGION:note] +ACES Viewing Transform 관련 부가 정보는 [ACES GitHub](https://github.com/ampas/aces-dev/tree/master/documents) 에서 PDF 문서를 다운로드해 보시거나, 이 글의 참고 자료 부분에 있는 링크를 따라가시기 바랍니다. +[/REGION] + +## HDR 출력 활성화 + +HDR 출력은 런타임에 콘솔 변수 토글 또는 블루프린트의 **GameUserSettings** 노드를 통해 활성화시킬 수 있습니다. + +![](HDRGameUserSettings.png)(w:800) + +**GameUserSettings** 컨트롤은 현재 출력 디바이스에 맞는 가장 가까운 값으로 자동 클램프시키고 모든 플래그도 적절히 설정해 줍니다. 다른 방법으로는, 다음 콘솔 변수를 통해 HDR 디바이스와 필요한 색 공간 출력에 맞는 +옵션을 활성화시키고 변경해도 됩니다. + +[REGION:simpletable] +| 콘솔 변수 | 설명 | +| --- | --- | +| `r.HDR.EnableHDROutput` | 1 로 설정하면, 스왑 체인을 재생성하고 HDR 출력을 활성화시킵니다. | +| `r.HDR.Display.OutputDevice` | 출력 디스플레이의 디바이스 포맷입니다. [INCLUDE:#deviceOuptut] | +| `r.HDR.Display.ColorGamut` | 출력 디스플레이의 색 공간입니다. [INCLUDE:#colorGamut] | +[/REGION] + + + +GameUserSettings 에 대한 블루프린트 또는 C++ 호출을 구성한 이후에는, 쿠킹된 프로젝트 실행, 명령줄 인수 `-game mode` 사용, 독립형 게임 모드 사용, 새 창에서 독점 전체화면 에디터에서 플레이 (PIE) +등을 실행하면 됩니다 (**Alt** + **Enter** 또는 `fullscreen` 명령 사용). + +[REGION:note] +테두리 없는 창 또는 창 모드는 현재 HDR 출력에 작동하지 않습니다. +[/REGION] + + +### HDR 에서 로우 다이내믹 레인지 (LDR) UI 지원 + +[REGION:note] +이 기능은 실험단계 기능으며, 앞으로 변경될 수 있습니다. +[/REGION] + +HDR 출력이 활성화되면 유저 인터페이스(UI)가 올바르게 보이지 않을 수 있습니다. 그래서 LDR UI 합성을 위한 실험단계 기능 지원을 추가했습니다. +LDR 모양에 가급적 비슷하게 일치하도록 시도하기는 하지만, 메인 씬의 활기로 인해 탈색되어 보이는 현상을 방지하기 위해서는 UI 를 약간 증폭시켜 주는 것이 좋습니다. + +그 방법은 다음 콘솔 변수를 사용하면 됩니다: + +[REGION:simpletable] +| 콘솔 변수 | 설명 | +| --- | --- | +| `r.HDR.UI.CompositeMode` | 1 로 설정하면 HDR UI 합성을 활성화시켜, LDR 비주얼과 블렌딩 보존을 시도합니다. | +| `r.HDR.UI.Level` | 합성된 UI 밝기를 조절합니다. 1.5 나 2 정도 값을 추천합니다. | +[/REGION] + + +## HDR 하드웨어 및 셋업 고려사항 + +여러가지 다양한 디스플레이 및 TV 유형에다 콘솔 및 PC 고려사항과 맞물려서 생각해 보면, HDR 출력의 정상 작동을 위해서는 세팅을 변경하거나 특정 하드웨어 부품을 사용해야 할 수도 있습니다. +다음은 셋업 프로세스를 거치는 도중 고려할 것들 몇 가지입니다. + +* 빠른 전송 속도를 위해서는 시스템과 HDR 디스플레이가 고속 HDMI 2.0 케이블로 연결되어있는지 확인합니다 (HDMI 1.4 도 작동은 합니다만, 콘텐츠 표시에 문제가 있을 수 있습니다). +모든 HDMI 포트가 HDMI 2.0 및 HDR 을 받지 않을 수도 있습니다. +확실치 않으면 디스플레이 매뉴얼을 참고하세요. +* TV 포트가 HDR 활성화된 것인지 확인하세요. 가끔 TV 나 디스플레이 세팅에 "HDMI Deep Color" 또는 "Enhanced Format" 이라고 표시되어 있을 수 있습니다. 확실치 않으면 디스플레이 매뉴얼을 참고하세요. +* PS4 와 같은 몇몇 콘솔에서는 HDR 출력의 정상 작동을 위해서는 **Enable HDCP** 시스템 세팅을 꺼줘야 할 수도 있습니다. +* 일부 디스플레이의 경우, 올바른 출력을 위해서는 디스플레이 세팅을 조정해야 할 수 있습니다. + * NVIDIA GPU 의 경우 NVIDIA Control Panel 을 사용하여 디스플레이 해상도 Output Color Format 이 **RGB** 를 사용하고, Output Color Depth 가 **10-bit** 또는 **12-bit** 를 사용하도록 조절하세요. 하드웨어에 따라 + 사용할 수 없는 옵션이 있을 수 있습니다. 확실치 않은 경우 디스플레이 매뉴얼을 참고하세요. + [REGION:lightbox] + [![](NVControlPanel.png)(w:400)](NVControlPanel.png) + [/REGION] + [REGION:caption] + _클릭하면 원본 이미지를 확인합니다._ + [/REGION] + +## 참고 및 한계 + +* 기본적으로 필름 매핑 커브는 LDR 컨트롤의 조악한 호환성으로 인해 HDR 출력 도중에는 비활성화됩니다. +* 현재 1000-nit 및 2000-nit 디스플레이 출력에 대한 패스만 구현되어 있습니다. +* D3D11 제약으로 인해 HDR 출력은 전체화면 전용으로만 제한됩니다. 윈도우 10 의 D3D12 지원을 통해 이 부분은 HDR 출력에 개별 뷰포트가 가능하도록 확장될 수도 있습니다. Mac 에서는 현재 이미 이 구현이 지원되고 있습니다. + +## 참고 자료 + +* [http://www.oscars.org/science-technology/sci-tech-projects/aces](http://www.oscars.org/science-technology/sci-tech-projects/aces) +* [http://www.oscars.org/science-technology/aces/aces-documentation](http://www.oscars.org/science-technology/aces/aces-documentation) + + + diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/CapsuleShadowsLanding.INT.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/CapsuleShadowsLanding.INT.udn index de301ff99273..943c353c20e4 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/CapsuleShadowsLanding.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/CapsuleShadowsLanding.INT.udn @@ -1,13 +1,14 @@ -availability:docs +availability:Public title: Capsule Shadows description:Landing page for Capsule Shadows in Unreal Engine 4 crumbs: version:4.15 -parent:Engine/Rendering/LightingAndShadows/ +parent:Engine/Rendering/LightingAndShadows order: related: Engine/Rendering/LightingAndShadows/DistanceFields/HowTo/DFHT_4 type:landing tags: Lighting +topic-image:CapsuleShadows_Topic.png [REGION:fullwidth raw] ![CapsuleShadowsBanner](CapsuleShadowsBanner.png) diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/CapsuleShadowsLanding.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/CapsuleShadowsLanding.JPN.udn index baa862563af8..de697ba3323d 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/CapsuleShadowsLanding.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/CapsuleShadowsLanding.JPN.udn @@ -1,14 +1,15 @@ -INTSourceChangelist:3348703 -availability:docs +INTSourceChangelist:3455313 +availability:Public title:カプセル シャドウ description:アンリアル エンジン 4 のカプセル シャドウのランディング ページです。 crumbs: -version:4.15 -parent:Engine/Rendering/LightingAndShadows/ +Version:4.15 +parent:Engine/Rendering/LightingAndShadows order: related:Engine/Rendering/LightingAndShadows/DistanceFields/HowTo/DFHT_4 type:landing tags:Lighting +topic-image:CapsuleShadows_Topic.png [REGION:fullwidth raw] ![CapsuleShadowsBanner](CapsuleShadowsBanner.png) diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/CapsuleShadowsLanding.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/CapsuleShadowsLanding.KOR.udn index cc901936bf7d..8c0dd537ddec 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/CapsuleShadowsLanding.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/CapsuleShadowsLanding.KOR.udn @@ -1,14 +1,15 @@ -INTSourceChangelist:3348703 -availability:docs +INTSourceChangelist:3455313 +availability:Public title: 캡슐 섀도 description:언리얼 엔진 4 의 캡슐 섀도 홈 페이지입니다. crumbs: version:4.15 -parent:Engine/Rendering/LightingAndShadows/ +parent:Engine/Rendering/LightingAndShadows order: related: Engine/Rendering/LightingAndShadows/DistanceFields/HowTo/DFHT_4 type:landing tags: Lighting +topic-image:CapsuleShadows_Topic.png [REGION:fullwidth raw] ![CapsuleShadowsBanner](CapsuleShadowsBanner.png) diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/Overview/CapsuleShadowsOverview.INT.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/Overview/CapsuleShadowsOverview.INT.udn index 9ffc61962f08..b73b6ffb7282 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/Overview/CapsuleShadowsOverview.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/Overview/CapsuleShadowsOverview.INT.udn @@ -1,4 +1,4 @@ -Availability: Docs +Availability:Public Title: Capsule Shadows Overview Crumbs: Description: An overview of Capsules Shadows used in Unreal Engine 4. diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/Overview/CapsuleShadowsOverview.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/Overview/CapsuleShadowsOverview.JPN.udn index 24c9a73725d5..eb6825509aad 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/Overview/CapsuleShadowsOverview.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/Overview/CapsuleShadowsOverview.JPN.udn @@ -1,5 +1,5 @@ -INTSourceChangelist:3348703 -Availability:Docs +INTSourceChangelist:3454749 +Availability:Public Title:カプセル シャドウの概要 Crumbs: Description:アンリアル エンジン 4 のカプセルシャドウの概要を説明します。 @@ -136,7 +136,7 @@ Capsule Indirect Shadow を有効にすると、キャラクターは領域に #### Source Radius -指向性ライトの Light Source Angle の機能と同様、Stationary のスポットライトおよびポイントライトの **Source Radius** もキャラクターにソフト シャドウを付けるために使用します。Source Radius を大きくすると、投影元から遠いサーフェスになるほどライトが柔らかくなります。 +指向性ライトの Light Source Angle の機能と同様、Stationary (固定) のスポットライトおよびポイントライトの **Source Radius** もキャラクターにソフト シャドウを付けるために使用します。Source Radius を大きくすると、投影元から遠いサーフェスになるほどライトが柔らかくなります。 [REGION:imagetable] | ![](CS_SR1.png)(w:400) | ![](CS_SR2.png)(w:400) | @@ -166,10 +166,10 @@ Capsule Indirect Shadow を有効にすると、キャラクターは領域に ## 制限事項 -* 演算シェーターによるタイル処理ディファード処理を実行するため DirectX 11 が必要です。 +* 演算シェーダーによるタイル処理ディファード処理を実行するため DirectX 11 が必要です。 * 自己シャドウイングによるアーティファクトが任意のメッシュ形状に対して発生する可能性があります。 * Spheres と Sphylls のみカプセル描写を使用できます。 -* カプセルシャドウがソフトになりすぎてアンビエント オクルージョンになった場合、シャドウイングの中にアーティファクトがハードラインの原因になっています。 +* カプセルシャドウがソフトすぎてアンビエント オクルージョンになってしまう場合、ハードラインの原因となるアーティファクトがシャドウイングの中にあります。 diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/Overview/CapsuleShadowsOverview.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/Overview/CapsuleShadowsOverview.KOR.udn index 8bc8d74e236d..2b49e88c9ab5 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/Overview/CapsuleShadowsOverview.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/Overview/CapsuleShadowsOverview.KOR.udn @@ -1,5 +1,5 @@ -INTSourceChangelist:3348703 -Availability: Docs +INTSourceChangelist:3454749 +Availability:Public Title: 캡슐 섀도 개요 Crumbs: Description: 언리얼 엔진 4 에 사용되는 캡슐 섀도 개요입니다. diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/1/CSQS_1.INT.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/1/CSQS_1.INT.udn index cb343cfb78fd..a9bde096c101 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/1/CSQS_1.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/1/CSQS_1.INT.udn @@ -1,4 +1,4 @@ -Availability:Docs +Availability:Public Title:1 - Required Setup Crumbs: Description: In this step we will use the Project Browser to create a New Project. diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/1/CSQS_1.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/1/CSQS_1.JPN.udn index 022074716d4e..5578fa4bc02a 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/1/CSQS_1.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/1/CSQS_1.JPN.udn @@ -1,5 +1,5 @@ -INTSourceChangelist:3348703 -Availability:Docs +INTSourceChangelist:3454749 +Availability:Public Title:1 - 必要な設定 Crumbs: Description:プロジェクト ブラウザを使って新規プロジェクトを作成してみましょう。 @@ -13,7 +13,7 @@ tags:Lighting [Nav] -まず最初に、このガイドでの作業で使用する新規プロジェクトを作成する必要があります。 +まず最初に、このガイドの作業で使用する新規プロジェクトを作成する必要があります。 以降のステップでは、アンリアル エンジン 4 のプロジェクト ブラウザを使ってプロジェクトを作成していきます。このステップを終えると、 今後のプロジェクトにビルドできるテンプレートが完成します。 @@ -28,7 +28,7 @@ tags:Lighting ## 結果 プロジェクト作成後、アンリアル エディタでの取り込みが完了すると、以下のメイン エディタ インターフェースが表示されます。コンテンツ ブラウザの中には、 -次からのステップで使用する Blueprint Third Person Template の各種フォルダが入っています。 +次からのステップで使用する Blueprint Third Person テンプレート用の各種フォルダが入っています。 [REGION:lightbox] [![](LoadedProject.png)(w:800)](LoadedProject.png) diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/1/CSQS_1.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/1/CSQS_1.KOR.udn index 1393852536de..13b6b0b7e226 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/1/CSQS_1.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/1/CSQS_1.KOR.udn @@ -1,5 +1,5 @@ -INTSourceChangelist:3348703 -Availability:Docs +INTSourceChangelist:3454749 +Availability:Public Title:1 - 필수 구성 Crumbs: Description: 이번 단계에서는 프로젝트 브라우저를 사용하여 새 프로젝트를 생성합니다. diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/2/CSQS_2.INT.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/2/CSQS_2.INT.udn index 3d8207e3f535..a6e8ee771d62 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/2/CSQS_2.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/2/CSQS_2.INT.udn @@ -1,4 +1,4 @@ -Availability:Docs +Availability:public Title:2 - Your Character - Creating a Shadow Physics Asset Crumbs: Description:In this step we will create a new Physics Asset for our Skeletal Mesh that will be used for shadow representation of our character. diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/2/CSQS_2.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/2/CSQS_2.JPN.udn index 361221e7e5ef..4d364e3eecd1 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/2/CSQS_2.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/2/CSQS_2.JPN.udn @@ -1,5 +1,5 @@ -INTSourceChangelist:3348703 -Availability:Docs +INTSourceChangelist:3454749 +Availability:public Title:2 - キャラクターの作成 - シャドウ物理アセット Crumbs: Description:このステップでは、キャラクターの影の表現に使うスケルタルメッシュ用の物理アセットを新規作成します。 @@ -21,7 +21,7 @@ tags:Lighting ## ステップ 1. **コンテンツ ブラウザ** のフォルダ階層を使って **「Mannequin」** > **「Character」** > **「Mesh」** フォルダを開きます。**「SK_Mannequin」** という名前のアセットがあります。選択して右クリックし、 -コンテクストメニューを表示させます。そして、**[Create]** > **[Physics Asset]** > **[Create]** の順に選択していきます。 +コンテキスト メニューを表示させます。そして、**[Create]** > **[Physics Asset]** > **[Create]** の順に選択していきます。 [REGION:raw] ![](ContextMenuCreatePA.png)(w:960) @@ -40,7 +40,7 @@ tags:Lighting ![](PA_Character.png)(w:500) 1. ここからのステップはオプションです。先へ進む前に、ここでひとまず、新規作成した物理アセットに名前を付けておきましょう。ここで一旦 PhAT ウィンドウを最小化して **コンテンツ ブラウザ** に戻ると、 -「Mannequin > Mesh」 フォルダの中に物理アセットが新規作成されています。後で分かりやすいように名前を付けておきます (「SPA_Mannequin」が良いと思います)。名前を付け終わったら、PhAT ウィンドウを最大化します。 +**「Mesh」** フォルダの中に SK_Mannequin 用の物理アセットが新規作成されています。後で分かるような名前を付けておきます (「SPA_Mannequin」が良いと思います)。名前を付けたら、PhAT ウィンドウを最大化します。 ![](CB_SPA_Mannequin.png)(w:390) @@ -48,7 +48,7 @@ tags:Lighting 精度をあげます。カプセルを調整および削除するにあたり、以下の事に注意してください。 * 手、腕、トルソや首用の複数のカプセルなど不要なカプセルを取り除いて、ボディ数を制限します。 - * 足のカプセルは、キャラクターが地上にいるように見せるために非常に重要で、精度を上げるために後からの調整が必要な場合があります。 + * 足のカプセルは、キャラクターの接地感を出すために非常に重要です。後から調整して精度を高める場合があります。 * シャドウにギャップが生じないように、ジョイント間のカプセルは少しだけオーバーラップさせます。 * このクイックスタートでは腕のカプセルは必要ありませんので、削除することができます。 diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/2/CSQS_2.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/2/CSQS_2.KOR.udn index 062c73087181..09e06fc6fc10 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/2/CSQS_2.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/2/CSQS_2.KOR.udn @@ -1,5 +1,5 @@ -INTSourceChangelist:3348703 -Availability:Docs +INTSourceChangelist:3454749 +Availability:Public Title:2 - 캐릭터 - 섀도 피직스 애셋 생성 Crumbs: Description:이번 단계에서는 캐릭터의 그림자 표현으로 사용할 스켈레탈 메시의 피직스 애셋을 새로 만들어 보겠습니다. diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/3/CSQS_3.INT.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/3/CSQS_3.INT.udn index 0fac1de65f70..2d9f4067687c 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/3/CSQS_3.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/3/CSQS_3.INT.udn @@ -1,4 +1,4 @@ -Availability:Docs +Availability:Public Title:3 - Your Character - Assigning the Physics Asset Crumbs: Description:In this step we will assign our newly created Physics Asset to our Skeletal Mesh Character. diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/3/CSQS_3.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/3/CSQS_3.JPN.udn index ae4f90827e0e..1834576f91df 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/3/CSQS_3.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/3/CSQS_3.JPN.udn @@ -1,5 +1,5 @@ -INTSourceChangelist:3348703 -Availability:Docs +INTSourceChangelist:3454749 +Availability:Public Title:3 - キャラクターの作成 - 物理アセットを割り当てる Crumbs: Description:このステップでは、この新しい物理アセットをスケルタルメッシュ キャラクターに割り当てます。 @@ -19,7 +19,7 @@ tags:Lighting ## ステップ -1. **コンテンツ ブラウザ** の中にフォルダ階層を使って **「Mannequin」** > **「Mesh」** フォルダを開きます。**SK_Mannequin** アセットを選択しダブルクリックして開きます。 +1. **コンテンツ ブラウザ** の中にフォルダ階層を使って **[Mannequin]** > **「Mesh」** フォルダを開きます。**SK_Mannequin** アセットを選択しダブルクリックして開きます。 ![](CB_Mannequin.png)(w:400) diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/3/CSQS_3.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/3/CSQS_3.KOR.udn index a4e9469dde77..6de09e745bd9 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/3/CSQS_3.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/3/CSQS_3.KOR.udn @@ -1,5 +1,5 @@ -INTSourceChangelist:3348703 -Availability:Docs +INTSourceChangelist:3454749 +Availability:Public Title:3 - 캐릭터 - 피직스 애셋 할당 Crumbs: Description:이번 단계에서는 새로 만든 피직스 애셋을 스켈레탈 메시 캐릭터에 할당하겠습니다. diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/4/CSQS_4.INT.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/4/CSQS_4.INT.udn index 2432f3dccaef..225766a0bf36 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/4/CSQS_4.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/4/CSQS_4.INT.udn @@ -1,4 +1,4 @@ -Availability:docs +Availability:Public Title:4 - Your Level - Enabling Capsule Shadows For Your Character Crumbs: Description:In this step we create a second shot for our example cinematic. diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/4/CSQS_4.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/4/CSQS_4.JPN.udn index 7112a8b525f7..646436825722 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/4/CSQS_4.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/4/CSQS_4.JPN.udn @@ -1,5 +1,5 @@ -INTSourceChangelist:3348703 -Availability:docs +INTSourceChangelist:3454749 +Availability:Public Title:4 - レベル内のキャラクター用カプセル シャドウの有効化 Crumbs: Description:サンプル シネマティックスの 2 つめのショットを作成します。 diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/4/CSQS_4.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/4/CSQS_4.KOR.udn index 06b6394a4305..7146f790d7c1 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/4/CSQS_4.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/4/CSQS_4.KOR.udn @@ -1,5 +1,5 @@ -INTSourceChangelist:3348703 -Availability:docs +INTSourceChangelist:3454749 +Availability:Public Title:4 - 레벨 - 캐릭터에 캡슐 섀도 켜기 Crumbs: Description:이번 단계에서는 캐릭터에 캡슐 섀도 옵션을 켜는 방법을 알아봅니다. diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/5/CSQS_5.INT.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/5/CSQS_5.INT.udn index ff1ca2a6a899..dbc7c5368cb0 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/5/CSQS_5.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/5/CSQS_5.INT.udn @@ -1,4 +1,4 @@ -Availability:Docs +Availability:Public Title:5 - On Your Own! Crumbs: Description: This step offers some additional things to try with your sample scene and links to more documentation. diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/5/CSQS_5.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/5/CSQS_5.JPN.udn index 26d25110cb21..aafa7014a4ff 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/5/CSQS_5.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/5/CSQS_5.JPN.udn @@ -1,5 +1,5 @@ -INTSourceChangelist:3348703 -Availability:Docs +INTSourceChangelist:3454749 +Availability:Public Title:5 - 応用編 Crumbs: Description:サンプル シーンを使っていくつかの作業を試してみましょう。追加情報へのリンクも示します。 @@ -25,6 +25,6 @@ tags:Lighting * カプセルシャドウに関する詳細は、[カプセルシャドウの概要](Engine/Rendering/LightingAndShadows/CapsuleShadows/Overview) ページをご覧ください。 * 物理アセット ツールのプロパティに関する情報は、[物理セットツール (PhAT)](https://docs.unrealengine.com/latest/INT/Engine/Physics/PhAT/) を参照してください。 -* ライティングに関する情報は、[背景のライティング(https://docs.unrealengine.com/latest/INT/Engine/Rendering/LightingAndShadows/) を参照してください。 +* ライティングに関する情報は、[背景のライティング](https://docs.unrealengine.com/latest/INT/Engine/Rendering/LightingAndShadows/) を参照してください。 [Nav] diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/5/CSQS_5.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/5/CSQS_5.KOR.udn index 451ea3e14a4e..86153f4d902e 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/5/CSQS_5.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/5/CSQS_5.KOR.udn @@ -1,5 +1,5 @@ -INTSourceChangelist:3348703 -Availability:Docs +INTSourceChangelist:3454749 +Availability:Public Title:5 - 직접 해보기! Crumbs: Description: 이번 단계에서는 샘플 신으로 해볼 수 있는 추가 작업을 몇 가지 제안해 드리고, 자세한 문서 링크를 제공해 드립니다. diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/CSQuickStart.INT.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/CSQuickStart.INT.udn index 5669d37e2c00..dd4dffeb7c2c 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/CSQuickStart.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/CSQuickStart.INT.udn @@ -1,4 +1,4 @@ -Availability:Docs +Availability:Public Title: Capsule Shadows Quick Start Crumbs: Description:A guide to quickly get up and running with the Sequencer Editor in Unreal Engine 4. diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/CSQuickStart.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/CSQuickStart.JPN.udn index 61cc6ee50f33..3b313f95e698 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/CSQuickStart.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/CSQuickStart.JPN.udn @@ -1,5 +1,5 @@ -INTSourceChangelist:3348703 -Availability:Docs +INTSourceChangelist:3454749 +Availability:Public Title:カプセル シャドウ クイック スタート Crumbs: Description:UE4 でシーケンサー エディタの作業を開始するためのガイドです。 @@ -19,8 +19,8 @@ SkillLevel:Intermediate ## 目標 -このガイドは、UE4 で物理アセットを用いてキャラクターをカプセルで表現し、また様々に照らされるゲーム背景のキャラクターにカプセル シャドウを有効にするための基礎が -早く学習できるようにしています。 +このガイドは、UE4 で物理アセットを用いてキャラクターをカプセルで表現し、また様々に照らされるゲーム背景においてキャラクターにカプセル シャドウを有効にするための基礎を +速く習得できるように作成されています。 ## 目的 diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/CSQuickStart.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/CSQuickStart.KOR.udn index d31c72b2570a..89c56e5a114a 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/CSQuickStart.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/CapsuleShadows/QuickStart/CSQuickStart.KOR.udn @@ -1,5 +1,5 @@ -INTSourceChangelist:3348703 -Availability:Docs +INTSourceChangelist:3454749 +Availability:Public Title: 캡슐 섀도 퀵스타트 Crumbs: Description:캡슐 섀도를 빠르게 사용할 수 있는 방법을 안내해 드립니다. diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/DistanceFields/HowTo/DFHT_1/DFHT_1.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/DistanceFields/HowTo/DFHT_1/DFHT_1.JPN.udn index 6278257bdbbb..dc21df631b72 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/DistanceFields/HowTo/DFHT_1/DFHT_1.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/DistanceFields/HowTo/DFHT_1/DFHT_1.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3340382 +INTSourceChangelist:3351628 Availability:Docs Crumbs: Title:RayTraced Distance Field Soft Shadows @@ -6,7 +6,7 @@ Description:RayTraced Distance Field Soft Shadows の設定および使用方法 Related:Engine/Rendering/LightingandShadows/DistanceFieldAmbientOcclusion Related:Engine/Rendering/LightingandShadows/RayTracedDistanceFieldShadowing SkillLevel:Intermediate -Type:how to +Type:how-to Parent:Engine/Rendering/LightingAndShadows/DistanceFields/HowTo Order: Tags:Lighting @@ -21,12 +21,9 @@ Version:4.15 -ゲーム開発をしていると、広大なオープン ワールドでは事前計算されたライティングがまったく使い物にならず、 -動的ライティングしか効率的に使えない状況になる場合があります。**Ray Traced Distance Field Soft Shadows** (略して **ディスタンス フィールド シャドウ**) は、 -指向性ライトを使った通常のカスケード シャドウ マップ (CSM) よりも遠い場所でのシャドウイングを可能にします。オープン ワールド ゲームまたはビュー ディスタンスが単に遠い場合に、ディスタンス フィールド シャドウは CSM ディスタンスよりも長く効率的なシャドウイングを可能にします。このメソッドは、エピック ゲームズ ランチャーの [Learn] タブからダウンロード可能な -オープン ワールド デモ "A Boy and His Kite" でふんだんに使用されています。 +ゲーム開発をしていると、広大なオープン ワールドで事前計算されたライティングがまったく使い物ににならなかったり、ターゲット システムのリソースに厳しすぎる場合、そのシーンには動的ライティングを使うことが最善の策だと感じることがあります。**Ray Traced Distance Field Soft Shadows** (**Distance Field Shadows** とも呼ばれる) は、**指向性ライト** による通常の **Cascaded Shadow Maps** (CSM) よりも遠い距離でのシャドウイングを可能にします。オープン ワールド ゲームまたはビュー ディスタンスが一般的に遠い場合に、ディスタンス フィールド シャドウは CSM ディスタンスよりも長く効率的なシャドウイングを可能にします。このメソッドは、オープン ワールド デモ "A Boy and His Kite" (エピック ゲームズのランチャーの Learn タブからダウンロード可能) でふんだんに使用されています。 -このガイドでは、ライトタイプに合わせてディスタンス フィールド シャドウを有効にする方法およびそれらで使うことができる各種設定について説明します。 +このガイドでは、ライトタイプに合わせて Distance Field Shadows を有効にする方法およびそれらで使うことができる各種設定について説明します。 ## ステップ @@ -40,7 +37,7 @@ Version:4.15 ![](ModesPanelLights.png)(w:400) [REGION:note] - ディスタンス フィールド シャドウを有効にする方法は、すべての Light アクタ共通です。ガイドの中で、これらのライトタイプそれぞれの特有のプロパティを補足説明します。 + Distance Field Shadows を有効にする方法は、すべての Light アクタ共通です。ガイドの中で、これらのライトタイプそれぞれの特有のプロパティを補足説明します。 [/REGION] 1. Light アクタを選択したら、そのアクタの **[Details (詳細)]** パネルを開いて **[Mobility]** を **[Movable]** に設定します。 @@ -54,28 +51,24 @@ Version:4.15 |---|---| | 指向性ライト | スポット/ポイントライト | [/Region] - [REGION:note] + このオプションがグレーアウトになっている場合は、ライトが **[Movable]** 設定になっていること、プロジェクト設定で **[Generate Mesh Distance Fields]** のオプションが有効になっていることを確認してください。 [/REGION] - 1. この設定をオンにしたライトに対して、ディスタンス フィールド シャドウが有効にされました。コンテンツ ブラウザからいくつかスタティックメッシュをドラッグして、ゲームでディスタンス フィールド シャドウが機能するか確認します。 +1. この設定をオンにしたライトに対して、Distance Field Shadows が有効にされました。コンテンツ ブラウザからいくつかスタティックメッシュをドラッグして、ゲームでディスタンス フィールド シャドウが機能するか確認します。 [REGION:tip] - 指向性ライトを使う場合、**Dynamic Shadow Distance Moveable Light** スライダーを **「0」** に設定しておくと便利です。こうすると、カスケード シャドウ マップ (CSM) が無効になるので、 - メッシュのディスタンス フィールド シャドウのみが表示されます。**[Show (表示)]** > **[Visualize (可視化)]** > **[Mesh Distance Fields]** を選択してメイン ビューポートで有効にできるメッシュ ディスタンス フィールドに対するビジュアル化モードの使用、 - さらにはシーンのテストおよび隠れているディスタンス フィールド問題の診断にも便利です。 + 指向性ライトを使う場合、**Dynamic Shadow Distance Moveable Light** スライダーを **「0」** に設定しておくと便利です。こうすると、CMS シャドウ が無効になるので、メッシュの Distance Field Shadow だけを表示されます。[Show (表示)] > [Visualize (可視化)] > [Mesh Distance Fields] を選択してメッシュ ディスタンス フィールドの可視化モードをメイン ビューポートで有効にして使用する場合以外にも、シーンのテストおよびディスタンス フィールドに潜んでいる問題の診断に便利です。 [/REGION] - ## 光源設定 -**指向性ライト**、**スポットライト**、**ポイントライト** は、それぞれ利用できるオプションが異なります。調節可能な設定内容、および -ディスタンス フィールド シャドウへの使用方法は以下の通りです。 +指向性ライト、スポットライト、ポイントライト は、それぞれ利用できるオプションが異なります。Distance Field Shadows への調節および使用方法は以下の通りです。 ### 指向性ライト -ディスタンス フィールド シャドウがオンにされている **指向性** ライトでは、以下の設定が使用できます。 +Distance Field Shadows を有効にした指向性ライトでは、以下の設定が使用できます。 ![Distance Field Shadow Settings](DirectionalLightSettings.png) @@ -85,17 +78,17 @@ Version:4.15 | [REGION:tablesection]Light[/REGION] || | Light Source Angle | 光源の角度です。ディスタンス フィールドあるいはカプセル シャドウを使った動的シャドウイング メソッドでソフトエリア シャドウをサポートするために使用します。 | | [REGION:tablesection]Distance Field Shadows[/REGION] || -| DistanceField Shadow Distance | ディスタンス フィールド シャドウの一番遠い距離です。ディスタンス フィールド シャドウは、この値と CMS シャドウ用 **Dynamic Shadow Distance Movable Light** の間の距離をカバーします。 | -| RayTraced DistanceField Shadows | 光源のディスタンス フィールド シャドウをオンにします。 | -| Distance Field Trace Distance | シャドウがキャスト可能な距離をワールド単位で設定します。値が大きいほどシーンに対するシャドウ負荷が高くなります。 | -| Ray Start Offset Depth Scale | カメラが遠ざかるにつれて受影面からオフセットするレイトレース シャドウの大きさを調節します。非常に大きなスタティック メッシュの低解像ディスタンス フィールドからのセルフ シャドウのアーティファクトを隠すのに便利です。 | +| DistanceField Shadow Distance | ディスタンス フィールド シャドウイングが可能な最長距離です。Distance Field Shadows は、この値と CMS シャドウ用 **Dynamic Shadow Distance Movable Light** の間の距離をカバーします。 | +| RayTraced DistanceField Shadows | 光源の Distance Field Shadows をオンにします。 | +| Distance Field Trace Distance | シャドウがシャドウ キャスターからキャスト可能な距離をワールド単位で設定します。値が大きいほどシーンに対するシャドウ負荷が高くなります。 | +| Ray Start Offset Depth Scale | カメラが遠ざかるにつれて受影面からオフセットするレイトレース シャドウの大きさを調節します。非常に大きなスタティック メッシュの低解像ディスタンス フィールドからのセルフ シャドウのアーティファクトを隠すために使用します。 | [/REGION] -#### カスケード シャドウ マップとディスタンス フィールド シャドウの違い +#### Cascaded Shadow Maps と Distance Field Shadows の違い -この例では、指向性ライト上でのカスケード シャドウ マップとディスタンス フィールド シャドウの違いについて説明します。CSM シャドウの方は高品質ですが、ビュー ディスタンスが大きいと使用できません。 -一方、ディスタンス フィールドは、さらに遠くまで効率的にシャドウを表現することが可能です。指向性ライトでは両方のメソッドを使用して、カメラの近くにあるオブジェクトの CSM シャドウイングに対してトレードオフできる距離を見つけて、 -CSM ディスタンスより遠くのオブジェクトにディスタンス フィールド シャドウを使うと良いでしょう。 +Cascaded Shadow Maps は高品質ですが、ビュー ディスタンスが大きいと使用できません。 +一方、Distance Field Shadows はより遠くまで効率的にシャドウを表現することができますが、質はメッシュ ディスタンス フィールドの解像度次第になります。カメラの近くにあるオブジェクトの CSM シャドウイングに対してトレードオフできる距離を見つけてから、 +Distance Field Shadows を使って遠くにシャドウイングを行うと良いでしょう。 [OBJECT:ComparisonSlider] [PARAM:before] @@ -108,12 +101,9 @@ CSM ディスタンスより遠くのオブジェクトにディスタンス フ #### Light Source Angle (光源の角度) -指向性ライトの **Light Source Angle** は、ライトの回転角と入力値に基づいてシャドウを鮮明にしたり柔らかくしたりします。この設定はディスタンス フィールドとカプセル シャドウでのみ機能し、 -シャドウが簡単にはぼけない従来の動的シャドウでは機能しません。 - -この例では、Light Source Angle は 0 に設定されているので、シャドウは非常に鮮明に表現されています。 -一方、デフォルト値の 1 を使用すると、シャドウは照射面に沿って広がって柔らかくなります。 +指向性ライトの **Light Source Angle** は、ライトの回転角と入力値に基づいてシャドウを鮮明にしたり柔らかくしたりします。この設定は Distance Fields と Capsule Shadows でのみ機能し、シャドウが簡単にはぼけない従来の動的シャドウでは機能しません。 +Light Source Angle は 0 に設定されているので、シャドウは非常に鮮明に表現されています。一方、値を高くすると、シャドウは照射面に沿って広がって柔らかくなります。 [OBJECT:ComparisonSlider] [PARAM:before] @@ -127,11 +117,10 @@ CSM ディスタンスより遠くのオブジェクトにディスタンス フ #### Distance Field Trace Distance (ディスタンス フィールド トレース ディスタンス) -**Distance Field Trace Distance** は、シャドウキャスターに対するシャドウイングのレイキャスト距離を調節します。トレース距離の値を下げると、シャドウはソースからそのポイントより先へは描画されないので、 -シーンへのシャドウ キャスト負荷が小さくなります。ただし、カメラ ビューからのシャドウ ディスタンスはこのトレース距離では変わらないので、**Distance Field Shadow Distance** で調節します。 +**Distance Field Trace Distance** は、シャドウ キャスターに対するシャドウイングのレイキャスト距離を調節します。トレース距離の値を下げると、シャドウはソースからそのポイントより先へは描画されないので、 +シーンへのシャドウ キャスト負荷が小さくなります。ただし、カメラ ビューからのシャドウ ディスタンスはこのトレース距離では変わらないので、**Distance Field Shadow Distance** で調節することを覚えておいてください。 -この例では、木は Mesh Distance Field を使ってグラウンドに沿ってシャドウをキャストしています。1500 単位という低めのトレース距離、およびデフォルト値 10000 を使った場合、 -ご覧のように木の影は、照射面から 1500 単位以上離れている木の頂点をキャプチャしていません。 +この例では、木は Mesh Distance Field を使ってグラウンドに沿ってシャドウをキャストしています。木の影は 1500 単位以上離れている照射面からキャストされるため、1500 単位のトレース距離 (デフォルト値は 10000) では最上部の枝と葉をキャプチャしません。 [OBJECT:ComparisonSlider] [PARAM:before] @@ -144,7 +133,7 @@ CSM ディスタンスより遠くのオブジェクトにディスタンス フ ### ポイント / スポットライト - **スポット** ライトおよび **ポイント** ライトは、[Distance Field Shadows] をオンにすると以下の設定が使用できます。 +**スポット** ライトおよび **ポイント** ライトは、[Distance Field Shadows] をオンにすると以下の設定が使用できます。 ![](PointSpotLightSettings.png) @@ -154,13 +143,13 @@ CSM ディスタンスより遠くのオブジェクトにディスタンス フ | [REGION:tablesection]Light[/REGION] || | Source Radius | 光源の球体のサイズとして使います。値が大きくなると、半暗部が大きくなりますが、パフォーマンスの負荷も高くなります。 | | [REGION:tablesection]Distance Field Shadows[/REGION] || -| RayTraced DistanceField Shadows | レイ トレース ディスタンス フィールド エリア シャドウを使用するかどうか設定します。 | +| RayTraced DistanceField Shadows | RayTraced DistanceField Shadows を使用するかどうか設定します。 | | Ray Start Offset Depth Scale | カメラが遠ざかるにつれて受影面からオフセットするレイトレース シャドウの大きさを調節します。非常に大きなスタティック メッシュの低解像ディスタンス フィールドからのセルフ シャドウのアーティファクトを隠すのに便利です。 | [/REGION] -#### 従来のシャドウ マップとディスタンス フィールド シャドウの違い +#### 従来のシャドウ マップと Distance Field Shadows の違い -この例では、ポイントライトからのデフォルト シャドウがディスタンス フィールド シャドウに比べてかなり鮮明なので、ライトの **Source Radius** で調節してシャドウを柔らかくします。 +スポットライトとポイントライトのシャドウマップは CSM シャドウと同様に非常に質の良い詳細なシャドウを作成します。一方、Distance Field Shadows はライトの **Source Radius** を使ってシャドウのシャープさを調節します。 [OBJECT:ComparisonSlider] [PARAM:before] @@ -173,10 +162,9 @@ CSM ディスタンスより遠くのオブジェクトにディスタンス フ ### Source Radius -**Source Radius** は指向性ライトの Light Source Angle と同じく、光源そのものの大きさを調節してエリア シャドウを柔らかくするために使用します。 +**Source Radius** は指向性ライトの Light Source Angle と同じく、光源そのものの大きさを調節してエリア シャドウをソフトにします。 -この例では、**Source Radius** を調節してシャドウを鮮明にしたり柔らかくします。 -半径を小さくするとシャドウが鮮明に、半径を大きくするとシャドウ キャスターからの距離が伸びてシャドウが柔らかくなります。 +値を低くするとシャドウはライトの減衰半径全体でシャープになり、値を高くするとシャドウはシャドウ キャスターから広がるにつれてソフトになります。 [OBJECT:ComparisonSlider] [PARAM:before] @@ -190,7 +178,7 @@ CSM ディスタンスより遠くのオブジェクトにディスタンス フ ### Ray Start Offset Depth Scale 場合によっては、低解像度のディスタンス フィールドあるいは複雑なジオメトリによって、自己シャドウイングによるアーティファクトが生じることがあります。メッシュの **Distance Field Resolution** の調節でオフセットできる場合もありますが、 -必要とされるボリューム テクスチャを生成することで高い負荷をかけたくはありません。その代りにカメラが遠ざかるにつれて、**Ray Start Offset Depth Scale** を使って受影面からのシャドウに対する光線の開始位置を調節することができます。 +ボリューム テクスチャを生成する必要があるため、高い負荷が発生します。そこで、**Ray Start Offset Depth Scale** を代わりに使用すれば、カメラが遠ざかる時に受影面からのシャドウに対する光線の開始位置を調節することができます。 [OBJECT:ComparisonSlider] [PARAM:before] @@ -204,8 +192,8 @@ CSM ディスタンスより遠くのオブジェクトにディスタンス フ ## 結果 -レベル内の様々なライト タイプのディスタンス フィールド シャドウを有効にして、それらの各種設定の調節方法を確認したので、 -ディスタンス フィールドを使ってこれらのコンセプトを独自のレベルとゲームに適用することができます。 +レベル内の様々な種類のライトの Distance Fields Shadows を有効にして、それらの各種設定の調節方法を説明しました。 +Distance Fields を使ってこれらのコンセプトを自分のレベルとゲームに活用してください。 diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/LightingAndShadows.INT.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/LightingAndShadows.INT.udn index a12a9b822b70..0013e66e262e 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/LightingAndShadows.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/LightingAndShadows.INT.udn @@ -80,12 +80,14 @@ type:landing %Engine/Rendering/LightingAndShadows/DistanceFieldAmbientOcclusion:Topic% %Engine/Rendering/LightingAndShadows/RayTracedDistanceFieldShadowing:Topic% %Engine/Rendering/LightingAndShadows/ContactShadows:Topic% +%Engine/Rendering/LightingAndShadows/CapsuleShadows:Topic% [/REGION] ## General [REGION:topics third] +%Engine/Rendering/LightingAndShadows/VolumetricFog:Topic% %Engine/Rendering/LightingAndShadows/AmbientOcclusion:Topic% %Engine/Rendering/LightingAndShadows/LightShafts:Topic% %Engine/Rendering/LightingAndShadows/AmbientCubemap:Topic% diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/LightingAndShadows.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/LightingAndShadows.JPN.udn index 79ca6c627685..834c3a25a247 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/LightingAndShadows.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/LightingAndShadows.JPN.udn @@ -1,8 +1,8 @@ -INTSourceChangelist:3275207 +INTSourceChangelist:3455315 Availability:Public Title:背景のライティング Crumbs: %ROOT%, Engine -Description:ライティングとシャドウイング ジオメトリの使用、グローバル イルミネーションの使用、リフレクションの設定 +Description:ライティングとシャドウイング ジオメトリの使用方法、グローバル イルミネーションの使用方法、リフレクションの設定方法 Navigation:topic Related:Engine/Rendering/ParticleSystems/ParticleLights Version:4.9 @@ -81,12 +81,14 @@ type:landing %Engine/Rendering/LightingAndShadows/DistanceFieldAmbientOcclusion:Topic% %Engine/Rendering/LightingAndShadows/RayTracedDistanceFieldShadowing:Topic% %Engine/Rendering/LightingAndShadows/ContactShadows:Topic% +%Engine/Rendering/LightingAndShadows/CapsuleShadows:Topic% [/REGION] ## 全般 [REGION:topics third] +%Engine/Rendering/LightingAndShadows/VolumetricFog:Topic% %Engine/Rendering/LightingAndShadows/AmbientOcclusion:Topic% %Engine/Rendering/LightingAndShadows/LightShafts:Topic% %Engine/Rendering/LightingAndShadows/AmbientCubemap:Topic% diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/LightingAndShadows.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/LightingAndShadows.KOR.udn index 1f58f5076474..165dced52c58 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/LightingAndShadows.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/LightingAndShadows.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3275207 +INTSourceChangelist:3455315 Availability:Public Title: 환경 라이팅 Crumbs: %ROOT%, Engine @@ -81,12 +81,14 @@ type:landing %Engine/Rendering/LightingAndShadows/DistanceFieldAmbientOcclusion:Topic% %Engine/Rendering/LightingAndShadows/RayTracedDistanceFieldShadowing:Topic% %Engine/Rendering/LightingAndShadows/ContactShadows:Topic% +%Engine/Rendering/LightingAndShadows/CapsuleShadows:Topic% [/REGION] ## 일반 [REGION:topics third] +%Engine/Rendering/LightingAndShadows/VolumetricFog:Topic% %Engine/Rendering/LightingAndShadows/AmbientOcclusion:Topic% %Engine/Rendering/LightingAndShadows/LightShafts:Topic% %Engine/Rendering/LightingAndShadows/AmbientCubemap:Topic% diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/Shadows/Shadows.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/Shadows/Shadows.JPN.udn index 7dedbb209e3c..57859d78cd38 100644 --- a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/Shadows/Shadows.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/Shadows/Shadows.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:2685246 +INTSourceChangelist:3108692 Availability:Public Title:シャドウ キャスティング Crumbs: %ROOT%, Engine, Engine/Rendering/LightingAndShadows @@ -69,7 +69,7 @@ _Stationary Lights (固定ライト) に照らされた右のキャラクター [INCLUDE:Engine/Rendering/LightingAndShadows/LightMobility/StationaryLights#CascadedShadowMaps] -## 固定ライトシャドウ +## Stationary Light (固定ライト) Shadows [INCLUDE:Engine/Rendering/LightingAndShadows/LightMobility/StationaryLights#StationaryShadows] @@ -80,8 +80,8 @@ _Stationary Lights (固定ライト) に照らされた右のキャラクター 平均すると可動の動的シャドウ キャスティング ライトは最も負荷がかかります。 -## シャドウのプレビュー -ライティングをアンビルドするような方法で静的ライトや固定ライトを編集する場合、**[Preview Shadowing (シャドウイングをプレビュー)]** を有効にして、ライティングを再ビルドした場合にシャドウがどのように見えるかを把握することができます。 +## Preview Shadows +ライティングをアンビルドするような方法で Static Lithg (静的ライト) やStationary Light (固定ライト) を編集する場合、**[Preview Shadowing (シャドウイングをプレビュー)]** を有効にして、ライティングを再ビルドした場合にシャドウがどのように見えるかを把握することができます。 こうしたシャドウは事前に存在していたシャドウと区別するために、以下のようにエディタで「Preview」というテキスト付きで表示されます。 @@ -95,11 +95,11 @@ _Stationary Lights (固定ライト) に照らされた右のキャラクター ![](BuiltShadows.png)(w:480) -ビューポートの **Show/Visualize** メニューで **[Preview Shadows Indicator (シャドウ インジケータのプレビュー)]** オプションのチェックを外すことでプレビュー シャドウを無効にすることができます。 +ビューポートの **[Show/Visualize]** メニューで **[Preview Shadows Indicator (シャドウ インジケータのプレビュー)]** オプションのチェックを外すことでプレビュー シャドウを無効にすることができます。 [REGION:note] -テキスト投影のライト関数マテリアルの微調整は、_Engine/EditorMaterials/PreviewShadowIndicator_ をご覧ください。 +このテキストを投影するためのライト関数マテリアルの調整方法については、 _Engine/EditorMaterials/PreviewShadowIndicator_ をご覧ください。 [/REGION] ## 全シャドウの融合 diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/VolumetricFog/VolumetricFog.CHN.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/VolumetricFog/VolumetricFog.CHN.udn new file mode 100644 index 000000000000..8c9af5398b8c --- /dev/null +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/VolumetricFog/VolumetricFog.CHN.udn @@ -0,0 +1,130 @@ +INTSourceChangelist:0 +Availability:Public +Crumbs: +Title:Volumetric Fog +Description: An overview of the Volumetric Fog features available when using Exponential Height Fog. +Type:Overview +Version:4.16 +Parent:Engine/Rendering/LightingAndShadows +Order: +Tags:Rendering +Tags:Lighting +Topic-Image:VolumetricFog_Topic.png +Social-Image:VolumetricFog_Social.png + + +With Unreal Engine, version 4.16, we now have support for Volumetric Fog. This method computes participating media density and lighting at every point in the camera frustum, so we can +support varying densities and any number of lights affecting the fog. + +[REGION:fullwidth raw] +![](VolumetricFog.png)(w:1339) +[/REGION] + +## Global Controls + +To control Volumetric Fog, you can adjust the properties in your Exponential Height Fog and on each light to control the light's contribution amount. + +### Exponential Height Fog + +Volumetric Fog controls can be found in the Exponential Height Fog component under the **Volumetric Fog** section. The exponential height distribution provides a global density for Volumetric Fog. + +![](VolumetricFogProperties.png) + +| Property | Description | +| --- | --- | +| Scattering Distribution | This determines how directional the volumetric scattering is; a value of 0, means light scatters equally in all directions, while a value close to 1 causes scattering predominantly in the direction of the light (you have to be looking at the light to see its scattering). | +| Albedo | This is the overall reflectiveness of the participating media. Clouds, fog, and mist, which are based on water particles, have an Albedo close to 1. | +| Extinction Scale | Controls how much the participating media blocks light. | +| View Distance | The distance from the camera over which Volumetric Fog will be computed. There are a limited number of Z slices in the volume texture, so pushing out the View Distance will increase under-sampling artifacts near the camera. | +| Override Light Colors with Fog Inscattering Colors | When enabled, uses the **Fog Inscattering Color**, **Directional Inscattering Color**, and **Inscattering Texture** properties to override the light color with Volumetric Fog. | + +### Lights + +Each light's contribution amount to the scene and whether it shadows the fog can be controlled using the following properties. + +![](VolumetricFogLightProperties.png) + +| Property | Description | +| --- | --- | +| Volumetric Scattering Intensity | Controls how much this light will contribute to the Volumetric Fog. When set to 0 there is no contribution. | +| Cast Volumetric Shadow | Whether to cast a volumetric shadow for lights contributing to Volumetric Fog. When enabled, Point and Spot lights are ~3x more expensive than non-shadow casting lights. | + + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Volumetric Scattering Intensity: 1 (Default)](VolumetricFogEnabled.png)(w:800) + [/PARAM] + [PARAM:after] + ![Volumetric Scattering Intensity: 0 ](VolumetricFogDisabled.png)(w:800) + [/PARAM] +[/OBJECT] + +In this example, the Spot light's contribution to the Volumetric Fog has been disabled by setting the **Volumetric Scattering Intensity** to 0. + +## Local Controls + +Materials using the **Volume** domain describe Albedo, Emissive, and Extinction for a given point in space. Albedo is in the range [0-1] while Emissive and Extinction are world space densities with +any value greater than 0. + + +![](VolumetricFogParticleMaterial.png)(w:700) +[REGION:caption] +This is an example of the simplest Volume material for a Particle System. +[/REGION] + +[REGION:note] +Volume materials currently only work on particles and only positions inside of the particle radius are valid, which is usually handled by a SphereMask. +[/REGION] + +Placing a single Particle System with the material causes a sphere of density to be added to the Volumetric Fog. The effect is fully 3D with no billboards involved. + +![](VF_ParticleInGame.png)(w:700) + +Taking this approach a step further, you could use multiple spherical fog particle with noise from textures to limit fog to a certain area of your scene. + +## Temporal Reprojection + +The volume textures used by Volumetric Fog are relatively low-resolution and aligned to the camera frustum. Volumetric Fog uses a heavy temporal reprojection filter with a different sub-voxel jitter +each frame to smooth out the aliasing. As a side-effect, fast-changing lights like flashlights and muzzle flashes leave lighting trails. Disable the contribution of these lights by setting +**Volumetric Scattering Intensity** set to 0. + +## Performance + +The GPU cost of Volumetric Fog is primarily controlled by the volume texture resolution, which is set from the Engine Shadow Scalability level. Volumetric Fog costs 1ms on PlayStation 4 at High Settings, +and 3ms on an Nvidia 970 GTX on Epic settings, which has 8x more voxels to operate on. + +* Particles using **Volume** domain can add a significant GPU cost, depending on their 3D overdraw and instruction count. Use the console command `profilegpu` to inspect this cost. +* Point and Spot Lights that have **Cast Volumetric Shadow** enabled cost ~3x more than unshadowed Point and Spot Lights. + +## Currently Supported Features + +This list comprises the currently supported features of Volumetric Fog: +* A single Directional Light, with shadowing from Cascaded Shadow Maps or static shadowing, with a Light Function. +* Any number of Point and Spot Lights, with dynamic or static shadowing if **Cast Volumetric Shadowing** is enabled. +* A single Skylight, with shadowing from Distance Field Ambient Occlusion, if enabled. +* Particle Lights, if **Volumetric Scattering Intensity** is greater than 0. + +Also, translucency is properly affected by Volumetric Fog, depending on its position in the scene. By default, translucency computes fog at vertices, so water planes with low tessellation can +introduce artifacts. These materials can be set to compute fogging per-pixel to solve this with **Compute Fog Per-Pixel** enabled in the Material Details. + +## Known Issues & Common Questions + +The following features are **not yet supported** while using Volumetric Fog: +* Precomputed Global Illumination. +* Shadowing of Stationary Skylights. +* IES profiles and Light Functions on Point and Spot Lights. +* Shadowing from Ray Traced Distance Field Shadows. +* Shadowing from Volumetric Fog itself. +* Source Radius on Point and Spot lights. +* Some settings in the Exponential Height Fog, like Fog Cutoff Distance, Start Distance, and Fog Max Opacity. + +Below are some common questions/issues that may arise when using Volumetric Fog. + +* **How can one achieve stronger light shafts without heavy global fog?** + * When the global density of fog is increased you get denser fog, so you only notice light shafts (shadows of light) if the fog is dense enough to have everything heavily fogged. There are two ways to go about having stronger light shafts without heavy fog: + * Keep the global fog density low, but use a higher **Volumetric Scattering Intensity** for the Directional Light. Also, adjust the **Scattering Distritbution** to near **0.9** in your Exponential Height Fog actor. + * Keep the global fog density low, but increase it in certain areas with Volume particles. +* **Can Exponential Height Fog and Volumetric Fog be used at the same time?** + * Right now, Volumetric Fog replaces **Fog Inscattering Color** within the Volumetric Fog **View Distance**. Because Volumetric Fog is physically-based and Exponential Height Fog is not, it's impossible to match these precisely in the distance. This means that some settings in the Exponential Height Fog will have no effect on Volumetric Fog. +* **Can Volumetric Fog's center be decoupled from the camera, which would be ideal for top-down games?** + * Not currently, though, a standalone volume would be ideal for this. However, it's hard to integrate them with translucency efficiently. diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/VolumetricFog/VolumetricFog.INT.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/VolumetricFog/VolumetricFog.INT.udn new file mode 100644 index 000000000000..c64f3eb7ef0d --- /dev/null +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/VolumetricFog/VolumetricFog.INT.udn @@ -0,0 +1,135 @@ +Availability:Public +Crumbs:%ROOT% +Title:Volumetric Fog +Description: An overview of the Volumetric Fog features available when using Exponential Height Fog. +Type:Overview +Version:4.16 +Parent:Engine/Rendering/LightingAndShadows +Order: +Tags:Rendering +Tags:Lighting +Topic-Image:VolumetricFog_Topic.png +Social-Image:VolumetricFog_Social.png +SkillLevel:Advanced + +[TOC(start:1 end:2)] + +With Unreal Engine, version 4.16, we now have support for Volumetric Fog. This method computes participating media density and lighting at every point in the camera frustum, so that we can +support varying densities and any number of lights affecting the fog. + +[REGION:fullwidth raw] +![](VolumetricFog.png)(w:1339) +[/REGION] + +## Global Controls + +To control Volumetric Fog, you can adjust the properties in your **Exponential Height Fog** and on each **Light** to control the Light's contribution amount. + +### Exponential Height Fog + +Volumetric Fog controls can be found in the Exponential Height Fog component under the **Volumetric Fog** section. The exponential height distribution provides a global density for Volumetric Fog. + +![](VolumetricFogProperties.png) + +| Property | Description | +| --- | --- | +| **Scattering Distribution** | This determines how directional the volumetric scattering is; a value of 0, means light scatters equally in all directions, while a value close to 1 causes scattering, predominantly in the direction of the light (you have to be looking at the light to see its scattering). | +| **Albedo** | This is the overall reflectiveness of the participating media. Clouds, fog, and mist, which are based on water particles, have an Albedo close to 1. | +| **Extinction Scale** | Controls how much the participating media blocks light. | +| **View Distance** | The distance from the camera over which Volumetric Fog will be computed. There are a limited number of Z slices in the volume texture, so pushing out the View Distance will increase under-sampling artifacts near the camera. | +| **Override Light Colors with Fog Inscattering Colors** | When enabled, uses the **Fog Inscattering Color**, **Directional Inscattering Color**, and **Inscattering Texture** properties to override the light color with Volumetric Fog. | + +### Lights + +Each Light's contribution amount to the scene (and whether it shadows the fog) can be controlled with the following properties. + +![](VolumetricFogLightProperties.png) + +| Property | Description | +| --- | --- | +| **Volumetric Scattering Intensity** | Controls how much this light will contribute to the Volumetric Fog. When set to 0, there is no contribution. | +| **Cast Volumetric Shadow** | Toggles whether or not to cast a volumetric shadow for lights contributing to Volumetric Fog. When enabled, Point and Spot Lights are approximately three times more expensive than non-shadow casting lights. | + + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Volumetric Scattering Intensity: 1 (Default)](VolumetricFogEnabled.png)(w:800) + [/PARAM] + [PARAM:after] + ![Volumetric Scattering Intensity: 0 ](VolumetricFogDisabled.png)(w:800) + [/PARAM] +[/OBJECT] + +In this example, the Spot Light's contribution to the Volumetric Fog has been disabled by setting the **Volumetric Scattering Intensity** to 0. + +## Local Controls + +Materials using the **Volume** domain describe Albedo, Emissive, and Extinction for a given point in space. Albedo is in the range [0-1], while Emissive and Extinction are world space densities with +any value greater than 0. + + +![](VolumetricFogParticleMaterial.png)(w:700) +[REGION:caption] +This is an example of the simplest Volume material for a Particle System. +[/REGION] + +[REGION:note] +Volume materials currently only work on particles and only positions inside of the particle radius are valid, which is usually handled by a SphereMask. +[/REGION] + +Placing a single Particle System with the material causes a sphere of density to be added to the Volumetric Fog. The effect is fully three dimensional (3D) with no billboards involved. + +![](VF_ParticleInGame.png)(w:700) + +Taking this approach a step further, you could use multiple spherical fog particle with noise from textures to limit fog to a certain area of your scene. + +## Temporal Reprojection + +The volume textures (voxels) used by Volumetric Fog are relatively low-resolution and aligned to the camera frustum. Volumetric Fog uses a heavy temporal reprojection filter with a different sub-voxel jitter +per frame to smooth out the aliasing. As a side-effect, fast-changing lights, like flashlights and muzzle flashes, leave lighting trails. Disable the contribution of these lights by setting +**Volumetric Scattering Intensity** set to 0. + +## Performance + +The GPU cost of Volumetric Fog is primarily controlled by the volume texture resolution, which is set from the Engine Shadow Scalability level. Volumetric Fog costs 1 millisecond on PlayStation 4 at High Settings, +and 3 milliseconds on an Nvidia 970 GTX on Epic settings, which has eight times more voxels to operate on. + +* Particles using **Volume** domain can add a significant GPU cost, depending on their 3D overdraw and instruction count. Use the console command `profilegpu` to inspect this cost. +* Point and Spot Lights that have **Cast Volumetric Shadow** enabled, cost approximately three times more than unshadowed Point and Spot Lights. + +## Currently Supported Features + +This list comprises the currently supported features of Volumetric Fog: + +* A single Directional Light, with shadowing from Cascaded Shadow Maps or static shadowing, with a Light Function. +* Any number of Point and Spot Lights, with dynamic or static shadowing (if **Cast Volumetric Shadowing** is enabled). +* A single Skylight, with shadowing from Distance Field Ambient Occlusion (if enabled). +* Particle Lights (if **Volumetric Scattering Intensity** is greater than 0). + +Also, translucency is properly affected by Volumetric Fog, depending on its position in the scene. By default, translucency computes fog at vertices, so water planes with low tessellation can +introduce artifacts. These materials can be set to compute fogging per-pixel to solve this with **Compute Fog Per-Pixel** enabled in the Material Details. + +## Known Issues + +The following features are **not yet supported** while using Volumetric Fog: + +* Precomputed Global Illumination. +* Shadowing of Stationary Skylights. +* IES profiles and Light Functions on Point and Spot Lights. +* Shadowing from Ray Traced Distance Field Shadows. +* Shadowing from Volumetric Fog (itself). +* Source Radius on Point and Spot Lights. +* Some settings in the Exponential Height Fog, like Fog Cutoff Distance, Start Distance, and Fog Max Opacity. + +### Common Questions + +Below are some common questions or issues that may arise when using Volumetric Fog. + +* **How can one achieve stronger light shafts without heavy global fog?** + * When the global density of fog is increased, you get denser fog, so you only notice light shafts (shadows of light) if the fog is dense enough to have everything heavily fogged. There are two ways to go about having stronger light shafts without heavy fog: + 1. Keep the global fog density low, but use a higher **Volumetric Scattering Intensity** for the Directional Light. Also, adjust the **Scattering Distritbution** to nearly **0.9** in your Exponential Height Fog Actor. + 1. Keep the global fog density low, but increase it in certain areas with Volume particles. +* **Can Exponential Height Fog and Volumetric Fog be used at the same time?** + * At this time, Volumetric Fog replaces **Fog Inscattering Color** within the Volumetric Fog **View Distance**. Because Volumetric Fog is physically-based and Exponential Height Fog is not, it's impossible to precisely match these in the distance. This means that some settings in the Exponential Height Fog will have no effect on Volumetric Fog. +* **Can the Volumetric Fog's center be decoupled from the camera? This would be ideal for top-down games...** + * Not currently, though, a standalone volume would be ideal for this. However, it's hard to integrate them with translucency efficiently. diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/VolumetricFog/VolumetricFog.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/VolumetricFog/VolumetricFog.JPN.udn new file mode 100644 index 000000000000..12f731e82a71 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/VolumetricFog/VolumetricFog.JPN.udn @@ -0,0 +1,136 @@ +INTSourceChangelist:3458296 +Availability:Public +Crumbs:%ROOT% +Title:Volumetric Fog +Description:指数関数的高さフォグ (Exponential Height Fog) の Volumetric Fog 機能の概要 +Type:Overview +Version:4.16 +Parent:Engine/Rendering/LightingAndShadows +Order: +Tags:Rendering +Tags:Lighting +Topic-Image:VolumetricFog_Topic.png +Social-Image:VolumetricFog_Social.png +SkillLevel:Advanced + +[TOC(start:1 end:2)] + +アンリアル エンジン 4.16 で Volumetric Fog がサポートされるようになりました。このメソッドは、カメラ錐台のすべてのポイントでメディア密度とライティングを計算し、 +密度とライト数を調整してフォグに効果を与えます。 + +[REGION:fullwidth raw] +![](VolumetricFog.png)(w:1339) +[/REGION] + +## グローバル コントロール + +Volumetric Fog を制御するには、**Exponential Height Fog** と各 **ライト** を調節してライトの効果量を制御します。 + +### 指数関数的高さフォグ (Exponential Height Fog) + +Volumetric Fog の調節機能は **[Volumetric Fog]** セクションの [Exponential Height Fog] コンポーネントにあります。Exponential Height を使用すると Volumetric Fog にグローバル密度を加えることができます。 + +![](VolumetricFogProperties.png) + +| プロパティ | 説明 | +| --- | --- | +| **Scattering Distribution** | ボリュメトリック スキャタリングに与える指向性を設定します。値が 0 の場合、ライトはすべての方向に均等に拡散し、1 に近づくにつれて主にライトの方向に拡散します (拡散を確認するためにはライトを見ていなければなりません)。 | +| **Albedo** | 加えているメディアの全体的な反射性です。水のパーティクルがベースになっている雲、フォグ、もやの場合、Albedo は 1 に近づきます。 | +| **Extinction Scale** | 加えるメディアでブロックするライトの量を制御します。 | +| **View Distance** | Volumetric Fog の計算対象となるカメラからの距離です。ボリューム テクスチャには限られた数の Z スライスがあるので、View Distance を押し出すとカメラ付近でアンダーサンプリング アーティファクトが増加します。 | +| **Override Light Colors with Fog Inscattering Colors** | 有効の場合、**Fog Inscattering Color**、**Directional Inscattering Color**、**Inscattering Texture** プロパティを使って Volumetric Fog でライト カラーをオーバーライドします。 | + +### ライトの調節 + +ライトがシーンへ及ぼす効果量 (およびフォグへのシャドウイング有無) を以下のプロパティで調節することができます。 + +![](VolumetricFogLightProperties.png) + +| プロパティ | 説明 | +| --- | --- | +| **Volumetric Scattering Intensity** | Volumetric Fog へのライトの量を制御します。0 にすると、まったく影響しません。 | +| **Cast Volumetric Shadow** | Volumetric Fog に影響を及ぼすライトへのボリュメトリック シャドウのキャスト有無を切り替えます。有効にすると、ポイントライトとスポットライトの負荷は、シャドウへのキャストなしの場合の約 3 倍になります。 | + + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Volumetric Scattering Intensity: 1 (Default)](VolumetricFogEnabled.png)(w:800) + [/PARAM] + [PARAM:after] + ![Volumetric Scattering Intensity: 0 ](VolumetricFogDisabled.png)(w:800) + [/PARAM] +[/OBJECT] + +この例では、**[Volumetric Scattering Intensity]** を 0 にして Volumetric Fog に対するスポットライトの効果を無効にしています。 + +## ローカル コントロール + +**Volume** ドメインを使うマテリアルは、空間の任意のポイントでの Albedo、Emissive、Extinction を表現します。Emissive と Extinction は 0 より大きいすべての値がワールド空間密度となりますが、 +Albedo の範囲は [0-1] です。 + + +![](VolumetricFogParticleMaterial.png)(w:700) +[REGION:caption] +これは、最もシンプルなパーティクル システムの Volumen マテリアルのサンプルです。 +[/REGION] + +[REGION:note] +Volume マテリアルは現在パーティクル上でのみ機能し、パーティクル半径内部の位置でのみ有効です。これは通常 SphereMask によって処理されます。 +[/REGION] + +単一のパーティクル システムをマテリアルで配置すると、密度の球体が Volumetric Fog に追加されます。エフェクトはビルボードは一切含まれない、完全な 3D です。 + +![](VF_ParticleInGame.png)(w:700) + +その次のステップとして、テクスチャからのノイズのある複数の球体フォグ パーティクルを使用して、フォグをシーンの所定の場所に制限することができます。 + +## Temporal Reprojection + +Volumetric Fog に使用されるボリューム テクスチャ (voxels) はかなり低解像で、カメラ錐体にそって並びます。Volumetric Fog は、フレームごとにサブボクセル ジッターが異なる +負荷の高いテンポラル リプロジェクション フィルタを使用します。懐中電灯や火光のような高速で変化するライトは、副次的提供としてライティング トレイルが残ってしまいます。これらのライトの効果を無効にするには、 +**[Volumetric Scattering Intensity]** を「0」に設定します。 + +## パフォーマンス + +Volumetric Fog の GPU 負荷は主にボリューム テクスチャ解像度によって制御されます。これは Engine Shadow Scalability レベルから設定します。Volumetric Fog の負荷は、High Settings にした PlayStation 4 で 1 ミリ秒、 +Epic 設定の Nvidia 970 GTX で 3 ミリ秒で、ボクセルは 8 倍になります。 + +* **Volume** ドメインを使っているパーティクルは、3D オーバードロー と命令数によってはかなり高い GPU 負荷を追加する場合があります。負荷を調べるには、コンソールコマンドの `profilegpu` を使います。 +* ポイントライトとスポットライトの **Cast Volumetric Shadow** を有効すると、シャドウがない場合と比べて約 3 倍の負荷がかかります。 + +## 現在サポート対象の機能 + +Volumetric Fog が現在サポートする機能は以下のとおりです。 + +* カスケード シャドウ マップからのシャドウイングまたは静的シャドウイング、もしくは Light 関数のある単一の指向性ライト。 +* 動的または静的シャドウイングが付いた任意の数のポイントライトおよびスポットライト (**Cast Volumetric Shadowing** が有効の場合)。 +* ディスタンス フィールド アンビエント オクルージョン (有効の場合) からのシャドウイングが付いた単一のスカイライト。 +* パーティクル ライト (**Volumetric Scattering Intensity** が 0 より大きい場合)。 + +さらに、シーンの位置に合わせて、透過性も Volumetric Fog によって正しく反映されます。デフォルトでは、透過性は頂点でフォグを計算するため、 +テセレーションの低い水の面ではアーティファクトが発生する可能性があります。[Material Details] で **[Compute Fog Per-Pixel]** を有効にして、フォグ処理をピクセル単位で計算する設定にすると、この問題は解決されます。 + +## 既知の問題 + +以下は、Volumetric Fog の使用中は **サポートされない機能** です。 + +* 事前計算されたグローバル イルミネーション +* Stationary Skylight (固定スカイライト) のシャドウイング +* ポイントライトおよびスポットライト上での IES プロファイルと Light 関数 +* レイトレース ディスタンス フィールドシャドウからのシャドウイング +* Volumetric Fog (そのもの) からのシャドウイング +* ポイントライトとスポットライト上での Source Radius +* Fog Cutoff Distance、Start Distance、Fog Max Opacity など、 Exponential Height Fog のいくつかの設定 + +### 一般的な質問 + +以下は、Volumetric Fog の使用に関する一般的な質問 / 問題点です。 + +* **グローバル フォグの密度を上げずにライト シャフトを強める方法はありますか?** + * フォグのグローバル密度が増加するとフォグの密度も増加します。従って、フォグがかかるに十分な場合、ライト シャフト (ライトのシャドウ) のみに注目します。フォグ密度を上げずにライト シャフトを強める方法は 2 通りあります。 + 1. グローバル フォグ密度は低いままにして、指向性ライトの **Volumetric Scattering Intensity** を高くします。さらに、Exponential Height Fog アクタの **[Scattering Distritbution]** を **0.9** に近づけます。 + 1. グローバル フォグ密度は低くしたまま、Volume パーティクルを使ってある領域の密度を高くします。 +* **Exponential Height Fog と Volumetric Fog は同時に使用できますか?** + * 現在、Volumetric Fog は Volumetric Fog **[View Distance]** の **[Fog Inscattering Color]** の役目をします。Volumetric Fog は物理ベースですが Exponential Height Fog はそうでないため、両者を遠方でぴったり一致させることは不可能です。つまり、Exponential Height Fog 設定の中には Volumetric Fog では効果のないものもあるということです。 +* **トップダウン ゲームで使いやすくするために、Volumetric Fog の中心をカメラから切り離すことはできますか? + * 今はできませんが、スタンドアローン ボリュームを使うと良いと思います。ただし、透過性と効率よく統合するのは難しいです。 diff --git a/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/VolumetricFog/VolumetricFog.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/VolumetricFog/VolumetricFog.KOR.udn new file mode 100644 index 000000000000..cf5c1fefe8d3 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Rendering/LightingAndShadows/VolumetricFog/VolumetricFog.KOR.udn @@ -0,0 +1,137 @@ +INTSourceChangelist:3458296 +Availability:Public +Crumbs:%ROOT% +Title:볼류메트릭 포그 +Description: 익스포넨셜 하이트 포그를 사용할 때 쓸 수 있는 Volumetric Fog, 볼류메트릭 포그 기능에 대한 개요입니다. +Type:Overview +Version:4.16 +Parent:Engine/Rendering/LightingAndShadows +Order: +Tags:Rendering +Tags:Lighting +Topic-Image:VolumetricFog_Topic.png +Social-Image:VolumetricFog_Social.png +SkillLevel:Advanced + +[TOC(start:1 end:2)] + +언리얼 엔진 4.16 버전 이후 Volumetric Fog (볼류메트릭 포그)가 지원됩니다. 이 메소드는 카메라 프러스텀 내 모든 지점에서 (안개나 물과 같은) 빛 전파 관여 매체의 밀도와 라이팅을 계산하므로, +다양한 밀도의 포그가 지원되며, 라이트가 몇 개든 그 포그에 영향을 줄 수 있습니다. + +[REGION:fullwidth raw] +![](VolumetricFog.png)(w:1339) +[/REGION] + +## 글로벌 컨트롤 + +볼류메트릭 포그 컨트롤은, **익스포넨셜 하이트 포그** 와 각 **라이트** 의 프로퍼티를 조절하여 그 라이트가 기여하는 양을 제어할 수 있습니다. + +### 익스포넨셜 하이트 포그 + +볼류메트릭 포그 컨트롤은 Exponential Height Fog 컴포넌트의 **Volumetric Fog** 섹션 아래에서 찾을 수 있습니다. 익스포넨셜 하이트 분포는 볼류메트릭 포그의 전체 밀도 값을 줍니다. + +![](VolumetricFogProperties.png) + +| 프로퍼티 | 설명 | +| --- | --- | +| **Scattering Distribution** | 산란 분포 - 볼류메트릭 스캐터(체적 산란) 방향성을 결정합니다. 0 이면 빛이 모든 방향으로 동등하게 퍼지는 반면, 1 에 가까울 수록 주로 라이트 방향쪽으로 산란이 일어납니다 (라이트를 바라보고 있어야 산란이 보입니다). | +| **Albedo** | 알베도 - 빛 전파 관여 매체의 전체적인 반사성입니다. 구름, 안개 등은 물 입자를 기반으로 한 것이라, 알베도가 1 에 가깝습니다. | +| **Extinction Scale** | 소멸 스케일 - 빛 전파 관여 매체가 빛을 차단하는 양을 조절합니다. | +| **View Distance** | 가시 거리 - 카메라에서 이 거리까지 볼류메트릭 포그 계산을 합니다. 볼륨 텍스처에는 제한된 수의 Z 조각이 있어, 이 가시 거리를 높이면 카메라 근처 언더 샘플링 부작용이 늘어납니다. | +| **Override Light Colors with Fog Inscattering Colors** | 포그 내부산란 색으로 라이트 색 덮어쓰기 - 켜면 **Fog Inscattering Color**, **Directional Inscattering Color**, **Inscattering Texture** 프로퍼티를 사용하여 볼류메트릭 포그의 라이트 색을 덮어씁니다. | + +### 라이트 + +각 라이트가 씬에 기여하는 정도(와 포그에 그림자를 드리울지 여부)를 제어할 수 있는 프로퍼티입니다. + +![](VolumetricFogLightProperties.png) + +| 프로퍼티 | 설명 | +| --- | --- | +| **Volumetric Scattering Intensity** | 볼류메트릭 스캐터링 세기 - 이 라이트가 볼류메트릭 포그에 얼마만큼 기여하는지를 제어합니다. 0 이면 기여하지 않습니다. | +| **Cast Volumetric Shadow** | 볼류메트릭 섀도우 드리우기 - 볼류메트릭 포그에 기여하는 라이트에 대해 볼류메트릭 섀도우를 드리울지 말지 결정합니다. 켜면, 포인트 / 스포트 라이트 비용이 그림자를 드리우지 않을 때보다 약 세 배 높아집니다. | + + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Volumetric Scattering Intensity: 1 (Default)](VolumetricFogEnabled.png)(w:800) + [/PARAM] + [PARAM:after] + ![Volumetric Scattering Intensity: 0 ](VolumetricFogDisabled.png)(w:800) + [/PARAM] +[/OBJECT] + +이 예제에서는, **Volumetric Scattering Intensity** 를 0 으로 설정하여 스포트 라이트가 볼류메트릭 포그에 기여하지 못하도록 하고 있습니다. + +## 로컬 컨트롤 + +**Volume** 영역을 사용하는 머티리얼은 공간의 한 점에서 알베도, 이미시브(발광), 익스팅션(소멸)을 나타냅니다. 알베도 범위는 [0-1] 인 반면, 이미시브와 익스팅션은 0 보다 큰 값으로 +월드 스페이스 밀도를 나타냅니다. + + +![](VolumetricFogParticleMaterial.png)(w:700) +[REGION:caption] +파티클 시스템의 가당 간단한 볼륨 머티리얼 예제입니다. +[/REGION] + +[REGION:note] +볼륨 머티리얼은 현재 파티클에서만 작동하며 파티클 반경 내의 위치만 유효한데, 보통 SphereMask 로 처리됩니다. +[/REGION] + +이 머티리얼을 가진 파티클 시스템을 하나 배치하면 볼류메트릭 포그에 밀도 구체가 추가됩니다. 빌보드 없이도 완벽한 삼차원(3D) 효과를 냅니다. + +![](VF_ParticleInGame.png)(w:700) + +이 접근법에서 한 단계 더 나아가, 텍스처에서 노이즈를 받는 스페리컬 포그 파티클을 여러 개 사용하는 씩으로 씬의 특정 영역에 포그를 제한시킬 수 있습니다. + +## 템포럴 리프로젝션 + +볼류메트릭 포그에 사용되는 볼륨 텍스처(복셀)는 비교적 저해상도이며 카메라 프러스텀에 정렬됩니다. 볼류메트릭 포그는 프레임마다 서브 복셀 지터링이 각기 다른 무거운 템포럴 리프로젝션 필터를 사용하여 계단현상을 부드럽게 만듭니다. +부가 효과로 손전등이나 총구 섬광처럼 빠르게 변하는 라이트에 자취가 남게 됩니다. **Volumetric Scattering Intensity** 를 0 으로 설정하면 +이러한 라이트 기여 부분을 끌 수 있습니다. + +## 퍼포먼스 + +볼류메트릭 포그의 GPU 비용은 엔진 퀄리티(Scalability) 섀도우 부분에서 설정되는 볼륨 텍스처 해상도에 크게 좌우됩니다. 볼류메트릭 포그 비용은 PlayStation 4 에서 높음으로 설정한 경우 1 밀리초, +Nvidia 970 GTX 에서 에픽으로 설정한 경우 3 밀리초인데, 연산 대상 복셀이 8 배나 많은 것입니다. + +* **Volume** 영역을 사용하는 파티클은 그 3D 오버드로 및 인스트럭션 수에 따라 GPU 비용이 크게 추가될 수 있습니다. 이 비용을 조사하려면 `profilegpu` 명령을 사용하세요. +* 포인트 및 스포트 라이트 중 **Cast Volumetric Shadow** (볼류메트릭 섀도우 드리우기) 옵션이 켜진 것은, 드리우지 않는 것보다 비용이 약 세 배 더 듭니다. + +## 현재 지원되는 기능 + +볼류메트릭 포그에 현재 지원되는 기능 목록입니다: + +* 단일 디렉셔널 라이트, 캐스케이드 섀도우 맵 또는 스태틱 섀도우, 라이트 함수 포함. +* 다수의 포인트 및 스포트 라이트, (**Cast Volumetric Shadowing** 옵션이 켜진 경우) 다이내믹 또는 스태틱 섀도우 포함. +* 단일 스카이 라이트, 디스턴스 필드 앰비언트 오클루전(이 켜진 경우) 섀도우 포함. +* 파티클 라이트 (**Volumetric Scattering Intensity** 값이 0 보다 큰 경우). + +볼류메트릭 포그는 씬에서 그 위치에 따라 반투명에도 제대로 영향을 줍니다. 기본적으로 반투명은 버텍스 위치의 포그를 계산하므로, 테셀레이션이 낮은 물 표면에서는 부작용이 생길 수 있습니다. +이러한 머티리얼은 픽셀 단위로 포그 계산을 하도록 설정하여 문제를 해결할 수 있는데, +머티리얼 디테일에서 **Compute Fog Per-Pixel** 옵션을 켜면 됩니다. + +## 알려진 문제점 + +볼류메트릭 포그에 **아직 지원되지 않는** 기능은 다음과 같습니다: + +* 프리컴퓨티드 글로벌 일루미네이션. +* 스테이셔너리 스카이라이트의 그림자. +* 포인트 및 스포트 라이트 상의 IES 프로파일 및 라이트 함수. +* 레이 트레이스드 디스턴스 필드 섀도우에서의 그림자. +* 볼류메트릭 포그( 자체)에서의 그림자. +* 포인트 및 스포트 라이트 상의 소스 반경. +* 익스포넨셜 하이트 포그의 일부 세팅: Fog Cutoff Distance, Start Distance, Fog Max Opacity. + +### 잦은 질문 + +볼류메트릭 포그를 사용할 때 자주 발생할 수 있는 이슈 또는 질문은 다음과 같습니다. + +* **전체 포그를 무겁게 하지 않고 강한 라이트 섀프트를 낼 수 있는 방법이 있나요?** + * 포그 전체 밀도를 높이면 포그가 짙어지며, 전부 무겁게 깔릴 만큼 포그가 짙어야지만 라이트 섀프트(빛의 그림자)가 보이게 됩니다. 포그를 무겁게 하지 않고도 강한 라이트 섀프트를 만드는 방법은 두 가지 있습니다: + 1. 글로벌 포그 밀도는 낮게 유지하면서, 디렉셔널 라이트의 **Volumetric Scattering Intensity** (볼류메트릭 스캐터링 세기)를 높입니다. 또 익스포넨셜 하이트 포그 액터의 **Scattering Distritbution** (산란 분포)를 거의 **0.9** 정도로 조절합니다. + 1. 전체 포그 밀도는 낮게 유지하면서, 특정 영역만 볼륨 파티클로 높입니다. +* **익스포넨셜 하이트 포그와 볼류메트릭 포그를 동시에 사용할 수 있나요?** + * 현재 볼류메트릭 포그는 볼류메트릭 포그 **View Distance** (가시 거리) 내 **Fog Inscattering Color** (포그 내부산란 색)을 대체합니다. 볼류메트릭 포그는 물리 기반이고 익스포넨셜 하이트 포그는 그렇지 않기 때문에 원거리의 색을 정확히 일치시키는 것은 불가능합니다. 즉 익스포넨셜 하이트 포그의 일부 세팅은 볼류메트릭 포그에 영향이 없을 것이라는 뜻입니다. +* **볼류메트릭 포그의 중심을 카메라와 분리시킬 수 있나요? 내려다 보는 게임에서는 좋을텐데...** + * 현재는 안됩니다만, 독립형 볼륨이 있으면 좋겠지요. 그렇다 해도 반투명과 효율적으로 통합시키기는 힘듭니다. diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/Editor/Interface/MaterialEditorInterface.INT.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/Editor/Interface/MaterialEditorInterface.INT.udn index 0b31b5c2c51f..63c591c67002 100644 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/Editor/Interface/MaterialEditorInterface.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/Editor/Interface/MaterialEditorInterface.INT.udn @@ -12,7 +12,33 @@ tags:Materials The Material Editor UI consists of a menu bar, a toolbar, and, by default, four open panels. -![](UpdatedUI.jpg) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](MaterialEditor_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](MaterialEditor_Mac.png) +[/PARAM] +[/OBJECT] 1. [Menu Bar](#MenuBar) - Lists the menu options for the current Material. 1. [Toolbar](#Toolbar) - Contains tools that you can use to work with your Material. diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/Editor/Interface/MaterialEditorInterface.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/Editor/Interface/MaterialEditorInterface.JPN.udn index 5459cae62c6e..4be3af759321 100644 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/Editor/Interface/MaterialEditorInterface.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/Editor/Interface/MaterialEditorInterface.JPN.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:2735872 +INTSourceChangelist:3481084 Availability:Public -Title: マテリアル エディタ UI +Title:マテリアル エディタ UI Crumbs: %ROOT%, Engine, Engine/Rendering/Materials, Engine/Rendering/Materials/Editor Description:マテリアル エディタ UI のユーザーガイド Version:4.9 +tags:Materials [TOC(start:2)] @@ -12,7 +13,33 @@ Version:4.9 マテリアルエディタ UI は、メニューバー、ツールバー、そしてデフォルト設定では 4 つのオープンパネルで構成されています。 -![](UpdatedUI.jpg) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](MaterialEditor_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](MaterialEditor_Mac.png) +[/PARAM] +[/OBJECT] 1. [メニューバー](#メニューバー) - 現在のマテリアルのメニューオプションをリスト表示します。 1. [ツールバー](#ツールバー) - マテリアルの作業に使用するツールを収容しています。 @@ -21,12 +48,12 @@ Version:4.9 1. [グラフパネル](#グラフパネル) - マテリアルのシェーダー命令を作成するマテリアル式と関数ノードを表示します。 1. [パレットパネル](#パレットパネル) - 利用可能なマテリアル式と関数ノード全てをリスト表示します。 [REGION:note] -HLSL コードパネルもありますが、デフォルトでは非表示になっています。このパネルを表示するには、**[Window]** メニューで **[HLSLコード]** をクリックします。詳細は、[HLSLコードパネル](#HLSLコードパネル) を参照してください。 +HLSL コードパネルもありますが、デフォルトでは非表示になっています。このパネルを表示するには、**[Window]** メニューで **[HLSL Code]** をクリックします。詳細は、[HLSLコードパネル](#HLSLコードパネル) を参照してください。 [/REGION] [INCLUDE:Shared/Editors/Common/EditorMenuItems#UITabTips] -##メニューバー +## メニューバー ### ファイル @@ -68,13 +95,13 @@ HLSL コードパネルもありますが、デフォルトでは非表示にな | --- | --- | | [Include:Shared/Editors/Common/EditorToolbarItems/#ToolbarSaveIcon] | [Include:Shared/Editors/Common/EditorToolbarItems/#ToolbarSaveDescription] | | [Include:Shared/Editors/Common/EditorToolbarItems/#ToolbarCBIcon] | [Include:Shared/Editors/Common/EditorToolbarItems/#ToolbarCBDescription] | -| ![toolbar_apply.png](toolbar_apply.png)| マテリアルエディタで行った変更を、オリジナルのマテリアルとワールドでこのマテリアルを使用している箇所へ適用します。| +| ![toolbar_apply.png](toolbar_apply.png)| ツールバー上の [Apply] ボタンでマテリアルエディタで行った変更を、オリジナルのマテリアルとワールドでこのマテリアルを使用している箇所へ適用します。 | |![toolbar_search.png](Material_Toolbar_Button_Search.png) | 現在のマテリアルの表現式とコメントを検索します。 | | ![toolbar_home.png](toolbar_home.png)| ベースのマテリアル ノードを **[Graph (グラフ)]** パネルの中央に置きます。 | | ![toolbar_clean.png](toolbar_clean.png)| マテリアルと接続していないマテリアルノードを全て削除します。| | ![toolbar_show.png](toolbar_show.png)| 何にも接続していないマテリアルノードを表示または非表示にします。| -| ![toolbar_live_nodes.png](Engine/Rendering/Materials/Editor/toolbar_live_nodes.png)| 有効になると、それぞれのマテリアルノードのマテリアルをリアルタイムで更新します。マテリアルエディタのパフォーマンスを高速にするためにこのオプションを無効にします。[Live Nodes and Live Update](Engine/Rendering/Materials/Editor/#ライブノードとライブアップデート) セクションも参照してください。| -| ![toolbar_live_update.png](Engine/Rendering/Materials/Editor/toolbar_live_update.png)|有効になると、ノードが追加、削除、接続、非接続、またはプロパティ値に変更があるたびに全ての副次式のシェーダーがコンパイルされます。マテリアルエディタのパフォーマンスを高速にするためにこのオプションを無効にします。[Live Nodes and Live Update](Engine/Rendering/Materials/Editor/#ライブノードとライブアップデート) セクションも参照してください。| +| ![toolbar_live_nodes.png](Engine/Rendering/Materials/Editor/toolbar_live_nodes.png)| 有効になると、それぞれのマテリアルノードのマテリアルをリアルタイムで更新します。マテリアルエディタのパフォーマンスを高速にするためにこのオプションを無効にします。[Live Preview、Live Nodes、Live Update](Engine/Rendering/Materials/Editor/#LivePreview、LiveNodes、LiveUpdate) セクションも参照してください。| +| ![toolbar_live_update.png](Engine/Rendering/Materials/Editor/toolbar_live_update.png)|有効になると、ノードが追加、削除、接続、非接続、またはプロパティ値に変更があるたびに全ての副次式のシェーダーがコンパイルされます。マテリアルエディタのパフォーマンスを高速にするためにこのオプションを無効にします。[Live Preview、Live Nodes、Live Update](Engine/Rendering/Materials/Editor/#LivePreview、LiveNodes、LiveUpdate) セクションも参照してください。| | ![toolbar_stats.png](Engine/Rendering/Materials/Editor/toolbar_stats.png)| **[Graph (グラフ)]** パネルにマテリアル統計値を表示または非表示にします。 | | ![toobar_release_stats](Material_Toolbar_Button_Release_Stats.png)| 統計情報の報告に使用するリリースまたは開発シェーダーを切り替えます。 | | ![toolbar_built_in_stats](Material_Toolbar_Button_Built_In_Stats.png)| 空のマテリアルの統計情報の表示を切り替えます。グラフでコスト変更の特定に役立ちます。| @@ -115,7 +142,7 @@ HLSL コードパネルもありますが、デフォルトでは非表示にな このパネルは、現在選択されているマテリアル式と関数ノード全てのプロパティ ウィンドウを収容しています。ノードが何も選択されていない場合、 編集中のプロパティが表示されます。 -全マテリアルプロパティの説明は、 [](Engine/Rendering/Materials/MaterialProperties) +すべてのマテリアル プロパティの説明は、[](Engine/Rendering/Materials/MaterialProperties) を参照してください。 ## グラフ パネル @@ -127,7 +154,7 @@ HLSL コードパネルもありますが、デフォルトでは非表示にな ![Material Editor Material Node](MaterialEditor_MaterialNode.png) -ベースとなるマテリアル ノードの各種入力に関する詳細は、 [](Engine/Rendering/Materials\MaterialInputs) を +ベースとなるマテリアル ノードの各種入力に関する詳細は、[](Engine/Rendering/Materials\MaterialInputs) を 参照してください。 ## パレット パネル @@ -146,7 +173,7 @@ HLSL コードパネルもありますが、デフォルトでは非表示にな ![](StatsPanel.jpg) -マテリアルで使用されているシェーダー インストラクション数だけでなく、[コンパイラーエラー](Engine/Rendering/Materials/Editor/#コンパイラエラー) もこのパネルに表示されます。シェーダー インストラクション数が少ないほど、マテリアルの処理コストが低下します。ベースとなる +マテリアルで使用されているシェーダー インストラクション数だけでなく、[コンパイル エラー](Engine/Rendering/Materials/Editor/#コンパイルエラー) もこのパネルに表示されます。シェーダー インストラクション数が少ないほど、マテリアルの処理コストが低下します。ベースとなる マテリアルノードに接続していないマテリアル式ノードは、 マテリアルのインストラクション数 (コスト) にはカウントされません。 @@ -167,7 +194,7 @@ HLSL コードパネルもありますが、デフォルトでは非表示にな ## グラフ制御 マテリアルエディタの制御です。アンリアルエディタの別のツール制御とほとんどの場合一致します。例えば、 -マテリアル式グラフをその他とリンクしたオブジェクトエディタのようにナビゲートしたり、マテリアルプレビューメッシュをその他のメッシュツールのように +マテリアル式グラフをその他とリンクしたオブジェクト エディタのようにナビゲートしたり、マテリアル プレビュー メッシュをその他のメッシュ ツールのように 位置づけたりすることができます。 @@ -186,10 +213,10 @@ HLSL コードパネルもありますが、デフォルトでは非表示にな | **コネクターをマウスの左ボタンでドラッグ** | 接続を作成します (コネクタを解放) | | **接続からマウスの左ボタンをドラッグ** | 接続を移動します (同一タイプのコネクタを解放) | | **Shift + コネクタの上でマウスの左ボタンをクリック** | コネクタに印をつけます。印をつけたコネクタにアクションをもう一度実行すると、2 つのコネクタ間に接続が作成されます。距離が離れているノード間の接続を最も速く作成する方法です。 | -| **背景でマウスの右ボタンをクリック** | **[New Expression]*** メニューを開きます | +| **背景でマウスの右ボタンをクリック** | **[New Expression]** メニューを開きます | | **オブジェクトで右マウスボタンをクリック** | **[Object (オブジェクト)]** メニューを開きます | | **コネクタでマウスの右ボタンをクリック** | **[Object (オブジェクト)]** メニューを開きます | -| **Alt + コネクタでマウスの左ボタンをクリック** | コネクターの接続全てを切断します | +| **Alt + コネクタでマウスの左ボタンをクリック** | コネクタのすべての接続を切断します | ### キーボードの操作 @@ -204,7 +231,7 @@ HLSL コードパネルもありますが、デフォルトでは非表示にな | **Ctrl + Y** | やり直し | | **Ctrl + Z** | 元に戻す | | **Delete** | 選択対象を削除します。 | -| **Spacebar** | マテリアル表現式のプレビューを強制的に全て更新します | +| **Spacebar** | マテリアル表現式のプレビューをすべて強制的に更新します | | **Enter** | (クリックして「適用」と同じです) | diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/Editor/Interface/MaterialEditorInterface.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/Editor/Interface/MaterialEditorInterface.KOR.udn index c32a659fb182..3ef7cda3ae7b 100644 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/Editor/Interface/MaterialEditorInterface.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/Editor/Interface/MaterialEditorInterface.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3242329 +INTSourceChangelist:3481084 Availability: Public Title:머티리얼 에디터 UI Crumbs: %ROOT%, Engine, Engine/Rendering/Materials, Engine/Rendering/Materials/Editor @@ -13,7 +13,33 @@ tags:Materials 머티리얼 에디터 UI 는 메뉴바, 툴바, 그리고 기본적으로 네 개의 열린 패널로 구성됩니다. -![](UpdatedUI.jpg) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](MaterialEditor_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](MaterialEditor_Mac.png) +[/PARAM] +[/OBJECT] 1. [메뉴 바](#메뉴바) - 현재 머티리얼에 대한 메뉴 옵션이 나열됩니다. 1. [툴바](#툴바) - 머티리얼 작업시 사용할 수 있는 툴이 들어있습니다. diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/Editor/MaterialEditor.INT.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/Editor/MaterialEditor.INT.udn index 7b1fd6f74ae1..933631c4900d 100644 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/Editor/MaterialEditor.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/Editor/MaterialEditor.INT.udn @@ -2,8 +2,10 @@ Availability: Public Title:Material Editor Reference Crumbs: %ROOT%, Engine, Engine/Rendering/Materials Description:Guide to using the Material Editor for creating shaders. -Version: 4.9 +Version: 4.16 parent:Engine/Rendering/Materials +related:Engine/Rendering/Materials/ExpressionReference +related:Engine/Rendering/Materials/Editor/Interface topic-image:Engine/Rendering/Materials/MatEditorUserGuideTopic.png type:reference order:2 @@ -13,162 +15,275 @@ tags:Materials [TOC(start:2)] - - [EXCERPT:Intro] -The **Material Editor** provides the ability to create shaders to be applied to geometry using a node-based graph interface. +The **Material Editor** is a node-based graph interface that enables you to create shaders that can be applied to your geometry, such as Static and Skeletal Meshes, or with other systems such +as Cascade to create interesting materials. [/EXCERPT:Intro] -This document describes how to use the Unreal Editor's Material Editor. For a description of what the various material expressions -do, see the [Materials Compendium](Engine/Rendering/Materials/ExpressionReference). +Throughout this page, you'll learn about some of the functions you can perform along with general good practices to follow while using the Material Editor, such as using the Comment boxes to +call out what a specific section of your material network is doing, using reroute nodes to clean up the pin wires making your network easier to read, what do when you get errors +in the material statistics window and more. -[PUBLISH:Licensee] -For an explanation of how to create new material expressions, see [](Programming/Rendering/MaterialExpressions). -[/PUBLISH:Licensee] - -For more information about the Material Editor UI, see [](Engine/Rendering/Materials\Editor\Interface). ## Opening the Material Editor -The Material Editor can be opened by **double-clicking** any Material asset or through the **right-click** context menu of a Material -asset in the Content Browser. Either of these will open up that particular Material in the Material Editor for editing. +The Material Editor can be opened by **double-clicking** any Material asset or through the **right-click** context menu of a Material asset in the Content Browser. When performing +either of these operations, that particular Material will open in the Material Editor for editing . -The Material Editor is also opened whenever you create a new Material in the Content Browser, which is done either by **right-clicking** -and choosing New Material from the context menu, or clicking the **Add New** button at the top of the **Content Browser** and choosing -**Material** from the drop-down list. +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 0kQDssI8fkI + [/PARAMLITERAL] + [PARAMLITERAL:width] + 75 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] ## Commenting Material Expression Networks -Comments are a great way to document what your Material is doing, making it easier for you and others to understand -what is going on within a complicated material graph. There are two ways to add comments to your Materials: by adding text to -the **Desc** property of individual nodes or by placing nodes within a Comment object frame. +Using Comments are a great way to document what your Material is doing, making it easier for you and others to understand what is going on within a complicated material graph. -### Using the Desc Property +There are two ways you can add comments to your Materials; by adding text to the individual node using the **Desc** property or its comment bubble (...) as you +hover over a material node, or by using a comment box to encapsulate a larger section of your material graph. -Every material expression node contains a **Desc** property, available in the **Details** panel. This property exists as a -way for artists to add an explicit description of what a specific node is doing. Simply add text into the **Desc** property -field in the **Details** panel and the text will appear in a text bubble just above the current node. +### Adding Descriptions to Individual Nodes -![descpropertycomment.png](descpropertycomment.png) +Every material node contains a **Desc** property that is available through its **Details** panel. This property exists as a way for artists to add an explicit description +of what a specific node is doing. When this property is used, the text will appear in the text bubble as you hover over the node. + +You can add text descriptions to your nodes by doing the following: + +* Select it from your material graph and then from the **Details** panel, locate the **Desc** property to enter your text into. +* Hover your mouse cursor over the node and click on the **Text Bubble** (...) to enter your description. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + mIWQv65M3gU + [/PARAMLITERAL] + [PARAMLITERAL:width] + 75 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + + + +Additionally, if you'd like the comment to always be visible, you can click the **Push Pin** button in the text bubble for it to remain visible and not minimize when you are no longer +hovering over the node. ### Using Comments -Comments are another way to make descriptive notes about what certain parts of your material network are doing. Creating -them will allow you to stretch a frame around a group of multiple nodes, making this a perfect way to describe entire -sections of a network, rather than using the **Desc** property to describe a single node at a time. +Comments are another way to make descriptive notes about what certain parts of your material network are doing. Creating them will enable you to stretch a comment box around a group +of multiple nodes, making this a perfect way to describe entire sections of a network rather than using the **Desc** property to describe individual nodes. -You can create a Comment at any time by pressing **C** while hovering the mouse over the Graph. You can also **right-click** in -any blank area of the Graph and choose **Add Comment** from the context menu. +The comments are displayed as banners of text along the top of the comment box. This text will not scale with the graph's zoom level, so even when zoomed far away, you will still +be able to read the comment descriptions. -The comments themselves are displayed as banners of text along the top of the comment box. This text will not scale -with the Graph's zoom level, so even when zoomed far away, you will still be able to read the description. +To create a Comment Box you can do the following: + +* Press the **C** keyboard shortcut while the mouse is over the Material Graph. If you have any nodes selected in your graph, the comment box will scale to encompass the selection. +* You can right-click and use the Material Graph context menu to select **New Comment** and add a comment box. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + DKvPmoak4H8 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 75 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +Some additional things you can do with your comment box is: + +* Any nodes that are captured within the comment box can be moved by dragging on the group comment text, thus moving any nodes with it. the frame can be resized by dragging on the edges of the comment box to add additional nodes. +* Colors of the comment box can be adjusted for those more visually inclined. You can use the **Details** panel to set the **Comment Color** property using the color wheel to pick a color or entering a specific RGB value. +* You can also rename your comments by double-clicking on the comment text banner, or by selecting the comment box and then modifying the **Text** property from the **Details** panel. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + WEaPA92brTk + [/PARAMLITERAL] + [PARAMLITERAL:width] + 75 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] -![Comments.png](Comments.png) -Nodes within a comment frame can be moved by dragging on the group comment text. The frame can be resized by dragging on -the edges of the comment box. Any nodes inside a group comment will be moved with the -frame, so you can resize an existing frame to include new nodes. -Comments can be renamed by selecting the comment and then modifying the **Text** property using the property window. (#LiveNodesAndLiveUpdate) -## Live Nodes and Live Update +## Live Preview, Live Nodes, and Live Update -![toolbar_live_nodes.png](toolbar_live_nodes.png)![toolbar_live_update.png](toolbar_live_update.png) +[REGION:raw] +![](ToolbarLiveButtons.png)(w:800) +[/REGION] -When making changes to a network, it can be useful to get immediate feedback from each change in realtime. The Material Editor -offers two features in the Graph to give you instantaneous feedback for your network: Live Nodes and Live Update. -The difference between these two options may not be apparent at first. **Live Nodes** allows for any constant changes that the nodes -make - due to such expressions as Panners - to playback in real time. +When making changes to a network, it can be useful to get immediate feedback from each change in realtime. The Material Editor offers two features that can be enabled to give you +instantaneous feedback for your network; **Live Preview**, **Live Nodes** and **Live Update**. -**Live Update**, on the other hand, allows for each node within the network to have its shader recompiled whenever a change is made. -These changes include creation of new nodes, deletion of nodes, node connections and disconnections, and changes in properties. -This recompilation is necessary so that the material preview drawn at that node is up to date. However, recompiling these -intermediate shaders can be time-consuming, especially if your Material contains many nodes. If you are experiencing long wait -times after every change, you may want to deactivate the Live Update option. +The difference between these options may not seem apparent at first but they each perform a specific task for viewing your material in realtime. -As an example, consider the example below, in which we have a panning texture of an awesome rocket hull being multiplied by a -vector parameter, which is supplying color. +* **Live Preview -** This option allows for any changes to update automatically in the Material Preview window in realtime without having to use the **Save** or **Apply** buttons. +* **Live Node -** This option allows for any constant changes that the nodes make, such as material expressions for Panners, so that they playback in realtime inside the graph. +* **Live Update -** This option allows for each node within the network to have its shader recompiled whenever a change is made. These changes include creation of new nodes, deletion of nodes, node connections and disconnections, and changes in properties. This recompilation is necessary so that the Material Preview drawn at that node is up to date. However, recompiling these intermediate shaders can be time-consuming, especially if your Material contains a large network. If you're experiencing long wait times after every change, you may want to deactivate the Live Update option. + +As an example, consider the example below, in which we have a panning texture of an awesome rocket hull being multiplied by a vector parameter, which is supplying color. ![LiveNodesLiveUpdate.png](LiveNodesLiveUpdate.png) -* In this example, activating *Live Nodes* would cause the rocket texture to pan in realtime in the node's preview thumbnail. -If *Live Nodes* was deactivated, the texture would remain stationary even though the Panner was telling it to move. You may, however, -notice small updates as you move your mouse around the Graph area. -* If you changed the color from cyan to purple, you would only see the change if *Live Update* was active. With *Live Update* off, -the change in color would not be visible on the nodes, even though the color property was indeed changed. +* In this example, activating **Live Nodes** would cause the rocket texture to pan in realtime in the node's preview thumbnail in the graph. If **Live Nodes** were deactivated, the texture would remain stationary even though the Panner was telling it to move. You may, however, notice small updates as you move your mouse around the graph area. +* If you were to change the color from cyan to purple, you would only see the change if **Live Update** were enabled. With Live Update disabled, the change in color would not be visible on the nodes even though the color property was indeed changed. +As an example, consider the example below, in which we have a panning texture of an awesome rocket hull being multiplied by a +vector parameter, which is supplying color. - -When _Live Update_ is deactivated, you can force-update all previews manually by hitting the Spacebar. Fast iteration can be achieved -by disabling _Live Update_ and then pressing the spacebar whenever you would like to view your changes. +[REGION:tip] +Also, when **Live Update** is deactivated, you can force-update all previews manually by hitting **Spacebar**. Fast iteration can be achieved by disabling **Live Update** and then pressing +spacebar whenever you would like to view your changes. +[/REGION] (#CompilerErrors) +## Reroute Nodes +![](RerouteNode.png)(w:600) + +When making complex Materials, sometimes your shader networks can become difficult to read or make sense of as the connection wires overlap or criss-cross large portions of your material network +to connect to different inputs. **Reroute** nodes enable you to easily organize and clean up your shader network without impacting performance or adding to the instruction count since these are +purely visual. + +To add **Reroute** nodes in the Material Editor, you can do the following: + +* From the right-click **Context Menu** or the **Material Palette** under the **Utility** category you can drag in the **Add Reroute Node**. + ![](AddRerouteNodeCM.png)(w:600) +* **Double-click** on a connection wire to **insert** a new Reroute node inline. + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + v1KgtZMBQDs + [/PARAMLITERAL] + [PARAMLITERAL:width] + 75 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] + [/OBJECT] ## Compiler Errors +Each time a change is made to the material network, the Material must be compiled to see the changes. If any required inputs of an expression within the network have no connections or are +being passed the wrong type of data, a compiler error will occur. -Each time a change is made to the material network, the Material must be compiled. If any required inputs of an expression within -the network have no connections or are being passed the wrong type of data, a compiler error will occur. These errors are displayed -in the [Graph Panel](Engine/Rendering/Materials/Editor/Interface/#GraphPanel). +These types of errors are indicated in two places. -Compiler errors let you know a problem exists and what that problem is by providing information about the type of expression -that they occurred on and a description of the error. +* The node that is throwing the error will display "ERROR!" along its bottom. +* The **Stats** window will display the error that is being thrown causing the Material to fail to compile. If your Stats window is not opened, you can open it by going to **Window** > **Stats**. + +Compiler errors let you know that a problem exists and what that problem is by providing information about the type of node expression they occurred on and the description of the error. ![error_highlight.png](error_highlight.png) - +[REGION:caption] +In this image, the MakeMaterialAttributes node is throwing an error with the Normal input property, as indicated by the Stats window in the lower portion. +[/REGION] (#ExpressionSearch) -## Material Expression Search +## Material Graph Search -The search functionality in the Material Editor allows you to quickly find any nodes (including comments) within the material -network that contain a specific piece of text in their description or certain other properties specific to individual types -of expressions. This makes it easy to add identifying keywords to nodes and jump to them at a later time without hunting through -the network of expressions haphazardly. +The search functionality in the Material Editor enables you to quickly find any nodes (including comments) within the material network that contain a specific piece of text in their +description or certain other properties specific to individual types of nodes. This makes it easy to add identifying keywords to nodes and jump to them at a later time without sifting +through the network of nodes in your graph haphazardly. -Typing a full or partial keyword into the search box will perform a search against the properties of the expressions present -in the **Graph** panel. The currently selected result will be brought into view and highlighted. +You can open this tab by going to **Window** > **Find Results**. -![search_highlight.png](search_highlight.png) +Typing a full or partial keyword into the search box will perform a search against the properties of the nodes present within you your material graph. The currently selected result will be +brought into view and highlighted. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + OlJzlgWI2ig + [/PARAMLITERAL] + [PARAMLITERAL:width] + 75 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] -[REGION:note] -The search is case-insensitive. -[/REGION] Searches are performed against the following property values: -| **Expression Type** | **Searched Properties** | +| **Searched Properties** | **Expression Type** | | --- | --- | -| _All_ | Desc | -| _Texture Sample_ | Texture | -| _Parameters_ | ParamName | -| _Comment_ | Text | -| _FontSample_ | Font | -| _MaterialFunctionCall_ | MaterialFunction | +| **Desc** | All Nodes | +| **Texture** | Texture Sample | +| **ParamName** | Parameters | +| **Text** | Comment | +| **Font** | Font Sample | +| **Material Function** | MaterialFunctionCall | -Searches can also be performed for specific types of expressions by using the `NAME=` switch with your search. For -example, to find all texture samplers, you could use the following search: - - NAME=texture - -When a new match is clicked in the **Search** panel, it will be brought into view in the **Graph** tab if it -is not already visible. - -To clear a search, simply press the ![search_clear_button.png](search_clear_button.png) button. - - +Searches can also be performed for specific types of expressions by using the `NAME=` switch with your search. For example, to find all texture samples, you could use +the following search: + NAME=texture +When a new match is clicked in the **Search** panel, it will be brought into view in the graph table if it is not already visible. +To clear a search, simply press the **Clear** (X) button. diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/Editor/MaterialEditor.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/Editor/MaterialEditor.JPN.udn index 62a7e83e853c..7d774f3a0bb1 100644 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/Editor/MaterialEditor.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/Editor/MaterialEditor.JPN.udn @@ -1,10 +1,12 @@ -INTSourceChangelist:3242329 +INTSourceChangelist:3476123 Availability:Public Title:マテリアル エディタのリファレンス Crumbs: %ROOT%, Engine, Engine/Rendering/Materials Description:シェーダー作成のためにマテリアル エディタを使用するためのガイド -Version:4.9 +Version:4.16 parent:Engine/Rendering/Materials +related:Engine/Rendering/Materials/ExpressionReference +related:Engine/Rendering/Materials/Editor/Interface topic-image:Engine/Rendering/Materials/MatEditorUserGuideTopic.png type:reference order:2 @@ -14,162 +16,275 @@ tags:Materials [TOC(start:2)] - - [EXCERPT:Intro] -**マテリアル エディタ** には、ノードベースのグラフ インターフェイスを使用してジオメトリに適用するシェーダーを作成する機能があります。 +**Material Editor** には、ノードベースのグラフ インターフェイスを使用してスタティックメッシュやスケルタルメッシュといったジオメトリに適用するシェーダーを作成したり、 +カスケードなど他のシステムを使って魅力的なマテリアルを作成することができます。 [/EXCERPT:Intro] -このドキュメントではアンリアル エディタのマテリアル エディタの使用法を説明します。各種マテリアル式の説明は、 -[マテリアルの概要](Engine/Rendering/Materials/ExpressionReference) を参照してください。 +このページでは、マテリアル エディタを使いながら一般的なグッドプラクティスに従って実行できる関数のいくつかを学習します。 +例えば、コメントボックスを使ってマテリアル ネットワークの特定のセクションの処理を呼び出したり、 +リルート ノードを使ってピン ワイヤーを整理してネットワークを見やすくしてマテリアル統計情報ウィンドウに表示されたエラーへの対応が分かりやすくします。 -[PUBLISH:Licensee] -新しいマテリアル式の作成方法の説明に関しては、[](Programming/Rendering/MaterialExpressions) を参照してください。 -[/PUBLISH:Licensee] - -マテリアル エディタの UI に関する詳細は、 [](Engine/Rendering/Materials\Editor\Interface) を参照してください。 ## マテリアル エディタを開く -マテリアル エディタを開くには、いずれかのマテリアル アセットを **ダブルクリック**、 -もしくはコンテンツ ブラウザ 内のマテリアル アセットのコンテキスト メニューを **右クリック** します。いずれかの操作で、マテリアル エディタで特定のマテリアルが編集のために開きます。 +マテリアル エディタを開くには、いずれかのマテリアル アセットを **ダブルクリック** するか、コンテンツ ブラウザのマテリアルのコンテキスト メニューを **右クリック** します。いずれかの操作で、 +マテリアル エディタで特定のマテリアルが編集のために開きます。 -また、マテリアル エディタは、コンテンツ ブラウザで新規マテリアルを作成する時にいつでも、以下のいずれかの方法で開くこともできます。 -**右クリック** してコンテキスト メニューから新規マテリアルを選択する、または **コンテンツ ブラウザ** の上部にある **[Add New (新規)]** ボタンをクリックして、 -ドロップダウン リストから、**[Material (マテリアル)]** を選択します。 +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 0kQDssI8fkI + [/PARAMLITERAL] + [PARAMLITERAL:width] + 75 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] ## マテリアル式のネットワークにコメントを入れる -コメントはマテリアルが何を行っているかを文書化する素晴らしい方法です。複雑なマテリアル グラフ内で何が行われているかについて、 -自分だけでなく他の人も理解しやすくなります。マテリアルにコメントを入れる方法は以下の 2 通りあります。 -各ノードの **Desc** プロパティでテキストを追加するか、コメント オブジェクトのフレーム内にノードを配置します。 +コメントはマテリアルが何を行っているかを文書化する素晴らしい方法です。複雑なマテリアル グラフ内で何が行われているかについて、誰が見ても理解しやすくします。 -### Desc プロパティを使用する +マテリアルにコメントを入れる方法は以下の 2 通りあります。各ノードの **Desc** プロパティまたはマテリアル ノード上にマウスを当てると表示される吹き出しコメント (...) を使ってでテキストを追加するか、 +コメント ボックスを使ってマテリアル グラフの大きなセクションをカプセル化します。 -各マテリアル式ノードには、**[Desc]**プロパティがあり、**[Details (詳細)]** パネルで利用できます。このプロパティは、 -特定のノードが何を行っているかについての明確な説明をアーティストが追加できる手段として存在します。**[Details (詳細)]** パネルで **Desc** プロパティ入力フィールドにテキストを追加します。 -**[Details (詳細)]** パネルで **Desc** プロパティ入力フィールドにテキストを追加します。 +### 各ノードに説明を追加する -![descpropertycomment.png](descpropertycomment.png) +各マテリアル式ノードには、**[Details (詳細)]** パネルの中に **[Desc]** プロパティがあります。特定のノードの機能について、 +アーティストは明確な説明を追加することができます。このプロパティを使うと、ノード上にマウスを当てるとテキストの吹き出しが表示されます。 + +ノードにテキストの説明を追加するには、以下の操作を行います。 + +* マテリアル グラフからノードを選択し、**[Details]** パネルでテキストを追加したい **Desc** プロパティを探します。 +* ノード上にマウスを当てて **テキストの吹き出し** (...) をクリックして説明を入れます。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + mIWQv65M3gU + [/PARAMLITERAL] + [PARAMLITERAL:width] + 75 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + + + +さらに、コメントを常に表示するには、テキストの吹き出し **[Push Pin]** ボタンをクリックして表示したままにします。 +カーソルが離れても、最小化されなくなります。 ### コメントを使用する -コメントは、マテリアル ネットワーク部分での実行内容の説明メモをつくるもう 1 つの方法です。コメントを作成することで、 -複数ノードのグループ周辺でフレームを伸縮し、 -**[Desc]** プロパティを使用して一回に 1 つのノードを説明するのではなく、ネットワークのセクション全体を説明する最適な方法になります。 +コメントを使って、マテリアル ネットワーク部分での実行内容の説明メモを作成することもできます。コメントの作成により、複数ノードのグループ周辺でフレームを伸縮し、 +**Desc** プロパティを使って使用して 1 つずつノードを説明するのではなく、ネットワークのセクション全体の説明に最も適しています。 -グラフにマウスをかざしながら、**C** キーを押しすことで、いつでもコメントを作成できます。また、グラフのブランク エリアで **右クリック** し、 -**[Add Commene (新規コメント)]** を選択することでもコメントを作成できます。 +コメント自体は、コメントボックスの上部に沿ったテキストのバナーとして表示されます。このテキストはグラフのズーム レベルではスケールしないので、 +遠く離れてズームしても説明を読むことができます。 -コメント自体は、コメントボックスの上部にそってテキストのバナーとして表示されます。このテキストは、グラフのズームレベルに合わせてスケーリングされません。 -そのため、遠く離れてズームされても、その説明を読むことができます。 +コメントボックスを作成するには、以下の操作を行います。 + +* マテリアル グラフにマウスをかざしながらキーボードの **C** を押します。グラフで選んだノードはどれも、コメントボックスがスケールして選択範囲を調節できます。 +* マテリアル グラフのコンテキスト メニューを右クリックして **[New Comment]** を選択してコメントボックスを追加することができます。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + DKvPmoak4H8 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 75 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +コメントボックスを使って以下のこともできます。 + +* コメント フレーム内のノードは、グループ コメント テキスト上でドラッグして移動できます。グループ コメント内のノードは、フレームと共に移動します。コメントボックスの端をドラッグしてフレームのサイズ調整して、ノードの追加ができます。 +* 視覚効果を強めたい場合に、コメントボックスの色を変えることができます。**[Details]** パネルで、カラーホイールで色を選択するか、RGB 値を指定して **Comment Color** プロパティを設定することができます。 +コメント テキスト バナーをダブルクリックするか、**[Details]** パネルから **Text** プロパティを修正することで、コメント名を変更することもできます。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + WEaPA92brTk + [/PARAMLITERAL] + [PARAMLITERAL:width] + 75 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] -![Comments.png](Comments.png) -コメント フレーム内のノードは、グループ コメント テキスト上でドラッグして移動できます。フレームは、コメントボックスの端を -ドラッグするとサイズ調整できます。グループ コメント内のノードは、フレームと共に移動します。 -そのため、既存のフレームに新しいノードを含むようにリサイズできます。 -コメントの名前を変更するには、コメントを選択し、[プロパティ] ウィンドウを使用して **Text** プロパティを修正します。 (#LiveNodesAndLiveUpdate) -## Live Nodes と Live Update +## Live Preview、Live Nodes、Live Update -![toolbar_live_nodes.png](toolbar_live_nodes.png)![toolbar_live_update.png](toolbar_live_update.png) +[REGION:raw] +![](ToolbarLiveButtons.png)(w:800) +[/REGION] -ネットワークに変更を加える場合、各変更のフィードバックをリアルタイムで直ちに得ることが有用な場合があります。マテリアル エディタでは、 -グラフに次の 2 つの機能があり、ユーザーのネットワークについて即時にフィードバックします。その機能は、Live Nodes と Live Update です。 -この 2 つのオプションの違いは、最初はわかりずらいかもしれません。**Live Nodes** は、たとえば Panner などの式によって -リアルタイムで再生するためにノードが行う一定の変化を可能にします。 +ネットワークに変更を加える場合、各変更のフィードバックをリアルタイムで直ちに得ることが有用な場合があります。マテリアル エディタは、ネットワークに即時フィードバックできる 2 つの機能を提供します。 +**Live Preview**、**Live Nodes**、**Live Update** です。 -これに対して **Live Update** では、変更が加えられるたびにネットワーク内の各ノードがそのシェーダーをリコンパイルします。 -こうした変更には、新規ノードの作成、ノードの削除、ノードの接続、ノードの非接続、プロパティの変更などがあります。 -ノードに対して描かれたマテリアル プレビューが最新のものになるように、この再コンパイルが必要です。ただし、これらの再コンパイルには -非常に時間がかかる場合があります。特に、マテリアルに多くのノードが含まれる場合は時間がかかります。変更するたびにそのようなことが起こったら、 -Live Update オプションは無効にしたくなることがあるかもしれません。 +これらのオプションは一見するとあまり変わらないように見えますが、マテリアルをリアルタイムで表示する特別なタスクを実行します。 -たとえば、以下の例を考えてみます。 -ベクター パラメータによって乗算処理される素晴らしいロケットの外部構造のパニング テクスチャで、カラーを供給しています。 +* **Live Preview -** **[Save]** や **[Apply]** ボタンを使わずに、[Material Preview] ウィンドウにリアルタイムに自動更新をするための変更を可能にします。 +* **Live Node -** グラフ内でリアルタイムで再生するように、Panner の表現式などノードが行う一定の変化を可能にします。 +* **Live Update -** 変更が加えられるたびにネットワーク内の各ノードがそのシェーダーをリコンパイルします。こうした変更には、新規ノードの作成、ノードの削除、ノードの接続、ノードの非接続、プロパティの変更などがあります。ノードに対して描かれたマテリアル プレビューが最新のものになるように、この再コンパイルが必要です。ただし、これらの再コンパイルには非常に時間がかかる場合があります。特に、マテリアルに含まれるネットワークが大きい場合は時間がかかります。変更するたびにこのような事が起これば、Live Update オプションを非アクティブにしたくなると思います。 + +例として、見事なロケットのハルのテクスチャをベクター パラメータで乗算処理して色付けをする例を考え見ましょう。 ![LiveNodesLiveUpdate.png](LiveNodesLiveUpdate.png) -* この例では、*Live Nodes* をアクティベートすると、そのノードのプレビュー サムネイルでロケットのテクスチャがリアルタイムでパンします。 -*Live Nodes* を非アクティブにすると、Panner が移動を指示してもテクスチャは静止したまま残ります。しかし、 -グラフ領域周辺でマウスを動かすと若干更新されていることに気づくかもしれません。 -* シアンから紫にカラーを変更すると、*Live Update* がアクティブな場合のみその変更がわかります。*Live Update* がオフの場合、 -カラー プロパティが実際に変更されても、ノード上でカラーの変更は不可視になります。 +* この例では、**Live Nodes** をアクティベートすると、グラフ内のそのノードのプレビュー サムネイルでロケットのテクスチャがリアルタイムでパンします。**Live Nodes** を非アクティブにすると、Panner が移動を指示してもテクスチャは静止したまま残ります。ただし、グラフ領域周辺でマウスを動かすと若干更新されていることに気づくかもしれません。 +* シアンから紫にカラーを変更すると、**Live Update** がアクティブな場合のみ、その変更がわかります。Live Update を無効にすると、カラー プロパティが実際に変更されても、ノード上では色の変更は可視化されません。 +例として、 +見事なロケットのハルのテクスチャをベクター パラメータで乗算処理して色付けをする例を考え見ましょう。 - -_Live Update_ が非アクティブな場合、「スペースバー」を押してすべてのプレビューを手動で更新できます。_Live Update_ を無効にし、変更を表示したい場合にいつでも「スペースバー」を押せば、 -高速イタレーションを実現できます。 +[REGION:tip] +**Live Update** が非アクティブな場合、**スペースバー** を押してすべてのプレビューを手動で更新できます。**Live Update** を無効にし、変更を表示したい時に「スペースバー」を押せば、 +高速イタレーションを実現できます。 +[/REGION] (#CompilerErrors) +## Reroute ノード +![](RerouteNode.png)(w:600) + +複雑なマテリアルを作成する場合、接続ワイヤーが重なったり、マテリアル ネットワークの大部分が交差すると、 +シェーダー ネットワークの読み取りや理解がしずらくなることがあります。**Reroute** ノードは、純粋に視覚化されているので、パフォーマンスに影響を与えたり、パフォーマンスを下げたり命令数を追加したりせずに、 +シェーダー ネットワークの整理整頓を簡単に行うことができます。 + +マテリアル エディタに Reroute ノードを追加するには、以下の手順を行います。 + +* **コンテンツ メニュー** あるいは **マテリアル パレット** を右クリックして **[Utility]** カテゴリで **Add Reroute Node** へドラッグすることができます。 + ![](AddRerouteNodeCM.png)(w:600) +* 接続スプラインを **ダブルクリック** して、新規の Reroute ノードをインラインに **挿入** します。 + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + v1KgtZMBQDs + [/PARAMLITERAL] + [PARAMLITERAL:width] + 75 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] + [/OBJECT] ## コンパイル エラー +マテリアル ネットワークに変更が加えられるたびに、マテリアルを変更を確認するためにコンパイルしなければなりません。ネットワーク内の表現式で必要な入力が接続されていないか、 +誤ったタイプのデータを渡されると、コンパイラ エラーが発生します。 -マテリアル ネットワークに変更が加えられるたびに、マテリアルをコンパイルしなければなりません。ネットワーク内の式の必須インプットが、コネクションを持たないか、 -誤ったタイプのデータを渡されると、コンパイラ エラーが発生します。こうしたエラーは -[グラフパネル](Engine/Rendering/Materials/Editor/Interface/#グラフパネル ) に表示されます。 +このタイプのエラーは 2 つのフェーズを示します。 -コンパイラ エラーは、エラーが発生した式のタイプと説明についての情報を提供することで、 -問題の存在、またそれが何であるかを知らせてくれます。 +* エラーが発生しているノードの下に "ERROR!" と表示されます。 +* **[Stats]** ウィンドウに、マテリアルのコンパイルの失敗の原因となっているエラーが表示されます。[Stats] ウィンドウが開かない場合は、**[Window]** > **[Stats]** から開くことができます。 + +コンパイラ エラーは、エラーが発生した式のタイプと説明についての情報を提供することで、発生場所と内容を知らせます ![error_highlight.png](error_highlight.png) - +[REGION:caption] +この画像では、ウィンドウ下部の [Stat] ウィンドウで表示されいるように、MakeMaterialAttributes ノードの Normal 入力プロパティがエラーを出しています。 +[/REGION] (#ExpressionSearch) -## マテリアル式の検索 +## マテリアル グラフの検索 -マテリアル エディタの検索機能では、マテリアル ネットワーク内のノード (コメントも含む) を迅速に見つけることができます。 -説明に特定のテキストや、各タイプに特有のプロパティを含むノードを -見つけることができます。これにより、ノードを特定するキーワードを追加し、後でそこにジャンプできるようになります。 -ネットワークを隅から隅まであくせくして捜さなくて済むようになります。 +マテリアル エディタの検索機能では、説明に特定のテキストや、 +各タイプに特有のプロパティを含むノードが含まれるマテリアル ネットワーク内のノード (コメントも含む) を迅速に見つけることができます。これにより、ノードを特定するキーワードを追加し、グラフ内のノード ネットワーク経由で、 +後でそこにジャンプできるようになります。 -検索ボックスにキーワード全体またはキーワードの一部を入力すると、 -**[Graph (グラフ)]** パネルにある式のプロパティに対して検索が実行されます。現在選択中の結果がビューに表示され、ハイライトされます。 +このタブは、**[Window]** > **[Stats]** から開くことができます。 -![search_highlight.png](search_highlight.png) +検索ボックスにキーワード全体またはキーワードの一部を入力すると、マテリアル グラフ内に存在するノードのプロパティに対して検索を行います。現在選択中の結果がビューに表示され、 +ハイライトされます。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + OlJzlgWI2ig + [/PARAMLITERAL] + [PARAMLITERAL:width] + 75 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] -[REGION:note] -この検索では、大文字・小文字は区別されません。 -[/REGION] 検索は以下のプロパティ値に対して実行されます。 -| **式のタイプ** | **検索されるプロパティ** | +| **検索されるプロパティ** | **式のタイプ** | | --- | --- | -| _All_ | Desc | -| _Texture Sample_ | Texture | -| _Parameters_ | ParamName | -| _Comment_ | Text | -| _FontSample_ | Font | -| _MaterialFunctionCall_ | MaterialFunction | +| **Desc** | すべてのノード | +| **Texture** | テクスチャ サンプル | +| **ParamName** | パラメータ | +| **Text** | コメント | +| **Font** | フォント サンプル | +| **Material Function** | MaterialFunctionCall | -検索で、`NAME=` スイッチを使用することで、特定タイプの式に対する検索を行うことができます。例えば、 -すべてのテクスチャ サンプリングを見つけるには、以下の検索を使用します。 - - NAME=texture - -**[Search (検索)]** パネルで新しい検索結果をクリックすると、まだ表示されていない場合は、 -**[Graph (グラフ)]** タブに表示されます。 - -検索ワードをクリアするには ![search_clear_button.png](search_clear_button.png) ボタンを押します。 - - +検索で、`NAME=` スイッチを使用することで、特定タイプの式に対する検索を行うことができます。例えば、すべてのテクスチャ サンプリングを見つけるには、 +以下の検索を使用します。 + NAME=texture +**[Search (検索)]** パネルで新しい検索結果をクリックすると、まだ表示されていない場合は表示されるようになります。 +検索ワードをクリアするには **[Clear]** (X) ボタンを押します。 diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/ExpressionReference/Atmosphere/Atmosphere.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/ExpressionReference/Atmosphere/Atmosphere.JPN.udn index 2209862d78ef..0901a9f051a5 100644 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/ExpressionReference/Atmosphere/Atmosphere.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/ExpressionReference/Atmosphere/Atmosphere.JPN.udn @@ -1,4 +1,5 @@ -INTSourceChangelist:3242329Availability:Public +INTSourceChangelist:3242329 +Availability:Public Title:Atmosphere 表現式 Crumbs: %ROOT%, Engine, Engine/Rendering/Materials, Engine/Rendering/Materials/ExpressionReference Description:霧やその他の大気レベル効果に影響を与える表現式 diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/ExpressionReference/Math/MathExpressions.INT.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/ExpressionReference/Math/MathExpressions.INT.udn index 2a9abf1c5eef..953e2cf1f5cd 100644 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/ExpressionReference/Math/MathExpressions.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/ExpressionReference/Math/MathExpressions.INT.udn @@ -44,6 +44,104 @@ The **Add** expression takes two inputs, adds them together and outputs the resu [INCLUDE:Engine/Rendering/Materials/ExpressionReference/VectorOps#AppendVector] +## ArcSine + +[REGION:lightbox] +[![](MEN_ArcSine.png)(w:469)](MEN_ArcSine.png) +[/REGION] + +[REGION:caption] +Click for full image. +[/REGION] + +The **Arcsine** expression outputs the inverse sine function. This is an expensive operation that is not reflected by the instruction count. + +## ArcSineFast + +[REGION:lightbox] +[![](MEN_ArcSineFast.png)(w:469)](MEN_ArcSineFast.png) +[/REGION] + +[REGION:caption] +Click for full image. +[/REGION] + +The **ArcsineFast** expression outputs the approximate inverse sine function. Input must be between -1 and 1. + +## ArcCosine + +[REGION:lightbox] +[![](MEN_ArcCosine.png)(w:469)](MEN_ArcCosine.png) +[/REGION] + +[REGION:caption] +Click for full image. +[/REGION] + +The **Arccosine** expression outputs the inverse cosine function. This is an expensive operation that is not reflected by the instruction count. + +## ArcCosineFast + +[REGION:lightbox] +[![](MEN_ArcCosineFast.png)(w:469)](MEN_ArcCosineFast.png) +[/REGION] + +[REGION:caption] +Click for full image. +[/REGION] + + +The **ArccosineFast** expression outputs the approximate inverse cosine function. Input must be between -1 and 1. + +## ArcTangent + +[REGION:lightbox] +[![](MEN_ArcTangent.png)(w:469)](MEN_ArcTangent.png) +[/REGION] + +[REGION:caption] +Click for full image. +[/REGION] + +The **Arctangent** expression outputs the inverse tangent function. This is an expensive operation that is not reflected by the instruction count. + +## ArcTragnetFast + +[REGION:lightbox] +[![](MEN_ArcTangentFast.png)(w:469)](MEN_ArcTangentFast.png) +[/REGION] + +[REGION:caption] +Click for full image. +[/REGION] + +The **ArctangentFast** expression outputs the approximate inverse tangent function. + +## ArcTangent2 + +[REGION:lightbox] +[![](MEN_ArcTangent2.png)(w:469)](MEN_ArcTangent2.png) +[/REGION] + +[REGION:caption] +Click for full image. +[/REGION] + + +The **Arctangent2** expression uses inverse tangent of x / y where input signs are used to determine quadrant. This is an expensive operation that is not reflected by the instruction count. + +## ArcrTangent2Fast + +[REGION:lightbox] +[![](MEN_ArcTangent2Fast.png)(w:469)](MEN_ArcTangent2Fast.png) +[/REGION] + +[REGION:caption] +Click for full image. +[/REGION] + +The **Arctangent2Fast** expression is an approximate inverse tangent of X / Y where input signs are used to determine quadrant. + ## Ceil The **Ceil** expression takes in value(s), rounds them **up** to the next integer, and outputs the result. See also [Floor](#Floor) and [Frac](#Frac). @@ -241,8 +339,6 @@ In the example above, A is "0" and B is "1"; therefore, "0" (black) is the resul | **B** | Takes in the second value(s) to compare. | - - ## Multiply The **Multiply** expression takes two inputs, multiplies them together, and outputs the result. Similar to Photoshop's multiply layer blend. Multiplication happens per channel, meaning that the R channel of the first is multiplied by the R channel of the second; the G chanWnel of the first is multiplied by the G channel of the second, and so on. Both inputs must have the same number of values unless one of the values is a single float value. @@ -319,6 +415,33 @@ The **Power** expression takes two inputs, raises Base to the Exp power, and out ![PowerExample.png](PowerExample.png) +## Round + +The **Round** expression rounds the value up to the next whole number if the fractional part is greater than or equal to half, else rounds down. + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before Round](RoundExample_00.png)(w:1100) + [/PARAM] + [PARAM:after] + ![After Round](RoundExample_01.png) + [/PARAM] +[/OBJECT] + +**Examples:** +* A value of 1.1 will be Round down to a value of 1. +* A value of 1.4 will be Round down to a value of 1. +* A value of 1.5 will be Round up to a value of 2. +* A value of 1.85 will be Round up to a value of 2. + +## Saturate + +The **Saturate** node clamps the value between 0 and 1. The instruction cost of Saturate is almost free on most modern graphics hardware. + +![](SaturateExample_00.png) + +**Example Usage:** This node should be used whenever you need to clamp an output or input value between 0 and 1. + ## Sine The **Sine** expression outputs the value of a Sine wave over the input range of [0, 1] and the output range of [-1, 1], both repeating. The difference between this and the output of the [Cosine](#Cosine) expression is the output waveform is offset by one-quarter of the period, meaning that `Cos(X)` is equal to `Sin(X + 0.25)`. Most commonly, this is used to output a continuous oscillating waveform by connecting a [Time](Engine/Rendering/Materials/ExpressionReference/Constant#Time) expression to its input, but it can also be used to create ripples in worldspace or screenspace, or any other application where a continuous, smooth cycle is needed. A visual representation of the wave is shown below, scaled to the [0, 1] output range: @@ -363,3 +486,34 @@ The **Subtract** node takes in two inputs, subtracts the second input from the f ![SubtractExample.png](SubtractExample.png)(w:900) +## Tangent + +[REGION:lightbox] +[![](MEN_Tangent.png)(w:469)](MEN_Tangent.png) +[/REGION] + +[REGION:caption] +Click for full image. +[/REGION] + +The **Tangent** node outputs the tangent of the specified value. + +## Truncate + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before Truncate](TruncateExample_00.png)(w:1100) + [/PARAM] + [PARAM:after] + ![After Truncate](TruncateExample_01.png) + [/PARAM] +[/OBJECT] + + +The **Truncate** node truncates a value by discarding the fractional part while leaving the whole number untouched. + +**Examples:** +* A value of 1.1 will be Truncated to a value of 1. +* A value of 1.4 will be Truncated to a value of 1. +* A value of 2.5 will be Truncated to a value of 2. +* A value of 3.1 will be Truncated to a value of 3. \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/ExpressionReference/Math/MathExpressions.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/ExpressionReference/Math/MathExpressions.JPN.udn index 306822c00599..784114b3ad84 100644 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/ExpressionReference/Math/MathExpressions.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/ExpressionReference/Math/MathExpressions.JPN.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:2929391 +INTSourceChangelist:3409695 Availability:Public Title:Math 表現式 Crumbs: %ROOT%, Engine, Engine/Rendering/Materials, Engine/Rendering/Materials/ExpressionReference -Description:1 つ以上の入力で様々な数学的操作を行うための表現式。 +Description:1 つ以上の入力で様々な数学演算を行うための表現式。 Version:4.9 +tags:Materials [EXCERPT:TOC] [TOC(start:2)] @@ -11,30 +12,30 @@ Version:4.9 ## Abs -**Abs** は、数学用語「absolute value」 (絶対値) の略語です。Abs 表現式は絶対値、符号なしの値、または受け取った入力値を出力します。Abs によりマイナス符号を取り去って、負の数が正の数に変えられます。正の数と 0 に変化はありません。 +**Abs** は、数学用語「absolute value」 (絶対値) の略語です。Abs 表現式は絶対値、符号なしの値、または受け取った入力値を出力します。つまり、基本的にマイナス符号を取り除くことで負の数を正の数に変えます。正の数と 0 の場合は変化しません。 -**例: ** -0.7 の Abs は 0.7 、 -1.0 の Abs は 1.0 、 1.0 の Abs は 1.0 です。 +**例:** -0.7 の Abs は 0.7 、-1.0 の Abs は 1.0、1.0 の Abs は 1.0 です。 -**使用例:** Abs は、通常 [DotProduct](#DotProduct) と併用されます。DotProduct (ドット積) は、 -1..0..1 の順番で値が始まる一方、 DotProduct の Abs は、 1..0..1 の順番となります。 +**使用例:** Abs は、通常 [DotProduct](#DotProduct) と併用されます。DotProduct (ドット積) は、-1..0..1 の順番で値が始まる一方、DotProduct の Abs は、1..0..1 の順番となります。 ![AbsExample.png](AbsExample.png) -##Add +## Add -**Add** 表現式は、 2 つの入力値を受け取り、 2 つを足して結果を出力します。この加法演算はチャンネル毎に実行されます。つまり、 R チャンネルへの入力が加算され、 G チャンネルが加算され、そして B チャンネルが加算されるなどのようになります。入力の片方が単一の Constant 値でない限り、両入力は同数のチャンネル数を持っていなくてはいけません。Constant は入力数に関係なくベクターに加法できます。 +**Add** 表現式は、2 つの入力値を受け取り、2 つを足して結果を出力します。この加法演算はチャンネル毎に実行されます。つまり、R チャンネルへの入力が加算され、G チャンネルが加算され、そして B チャンネルが加算されるなどのようになります。入力の片方が単一の Constant 値でない限り、両入力は同数のチャンネル数を持っていなくてはいけません。Constant は入力数に関係なくベクターに加法できます。 | アイテム | 説明 | | -------- | ----------- | | [REGION:tablesection]プロパティ[/REGION] || -| **Const A** | 加算する値を受け取ります。A入力が未使用時のみ使用されます。| +| **Const A** | 加算する値を受け取ります。A 入力が未使用時のみ使用されます。| | **Const B** | 加算される値を受け取ります。B 入力が未使用時のみ使用されます。 | -| [REGION:tablesection]入力値[/REGION] || +| [REGION:tablesection]入力[/REGION] || | **A** | 加算する値を受け取ります。 | | **B** | 加算される値を受け取ります。 | -**例: ** 0.2 と 0.4 の Add は 0.6 、 (0.2,-0.4,0.6) と (0.1,0.5,1.0) の Add は (0.3,0.1,1.6) 、 (0.2,-0.4,0.6) と 1.0 の Add は (1.2,0.6,1.6) となります。 +**例:** 0.2 と 0.4 の Add は 0.6 、 (0.2,-0.4,0.6) と (0.1,0.5,1.0) の Add は (0.3,0.1,1.6) 、 (0.2,-0.4,0.6) と 1.0 の Add は (1.2,0.6,1.6) となります。 **使用例:** Add はカラーを明るくまたは暗くする際、もしくは UV テクスチャ座標をオフセットする際にしばし使用します。 @@ -44,18 +45,116 @@ Version:4.9 [INCLUDE:Engine/Rendering/Materials/ExpressionReference/VectorOps#AppendVector] +## ArcSine + +[REGION:lightbox] +[![](MEN_ArcSine.png)(w:469)](MEN_ArcSine.png) +[/REGION] + +[REGION:caption] +クリックしてフルサイズで表示 +[/REGION] + +**Arcsine** は、逆正弦 (アークサイン) 関数を出力します。負荷が大きく、命令数に影響されない関数です。 + +## ArcSineFast + +[REGION:lightbox] +[![](MEN_ArcSineFast.png)(w:469)](MEN_ArcSineFast.png) +[/REGION] + +[REGION:caption] +クリックしてフルサイズで表示 +[/REGION] + +**ArcsineFast** は、近似の逆正弦 (アークサイン) 関数を出力します。入力値は -1 から 1 の間でなければなりません。 + +## ArcCosine + +[REGION:lightbox] +[![](MEN_ArcCosine.png)(w:469)](MEN_ArcCosine.png) +[/REGION] + +[REGION:caption] +クリックしてフルサイズで表示 +[/REGION] + +**Arccosine** は逆余弦 (アークコサイン) 関数を出力します。負荷が大きく、命令数に影響されない関数です。 + +## ArcCosineFast + +[REGION:lightbox] +[![](MEN_ArcCosineFast.png)(w:469)](MEN_ArcCosineFast.png) +[/REGION] + +[REGION:caption] +クリックしてフルサイズで表示 +[/REGION] + + +**Arccosine** は近似の逆余弦 (アークコサイン) 関数を出力します。入力値は -1 から 1 の間でなければなりません。 + +## ArcTangent + +[REGION:lightbox] +[![](MEN_ArcTangent.png)(w:469)](MEN_ArcTangent.png) +[/REGION] + +[REGION:caption] +クリックしてフルサイズで表示 +[/REGION] + +**Arctangent** は逆正接 (アークタンジェント) 関数を出力します。負荷が大きく、命令数に影響されない関数です。 + +## ArcTragnetFast + +[REGION:lightbox] +[![](MEN_ArcTangentFast.png)(w:469)](MEN_ArcTangentFast.png) +[/REGION] + +[REGION:caption] +クリックしてフルサイズで表示 +[/REGION] + +**Arctangent** は近似の逆正接 (アークタンジェント) を計算します。 + +## ArcTangent2 + +[REGION:lightbox] +[![](MEN_ArcTangent2.png)(w:469)](MEN_ArcTangent2.png) +[/REGION] + +[REGION:caption] +クリックしてフルサイズで表示 +[/REGION] + + +**Arctangent2** は、入力の符号を使用して、x / y の逆タンジェントを計算することで、四分円を決定します。負荷が大きく、命令数に影響されない関数です。 + +## ArcrTangent2Fast + +[REGION:lightbox] +[![](MEN_ArcTangent2Fast.png)(w:469)](MEN_ArcTangent2Fast.png) +[/REGION] + +[REGION:caption] +クリックしてフルサイズで表示 +[/REGION] + +**Arctangent2Fast** は、入力の符号を使用して、X / Y の近似の逆タンジェントを計算することで、四分円を決定します。 + ## Ceil **Ceil** 表現式は、値を受け取り、一番近い整数へ **切り上げて** 結果を出力します。[Floor](#Floor) と [Frac](#Frac) も参照してください。 -**例: ** 0.2 の Ceil は 1.0 、 (0.2,1.6) の Ceil は (1.0,2.0) となります。 +**例:** 0.2 の Ceil は 1.0 (0.2,1.6) の Ceil は (1.0,2.0) となります。 ![CeilExample.png](CeilExample.png)(w:900) ## Clamp -**Clamp** 表現式は、最小値と最大値が定義された指定範囲で受け取った値を制限します。0.0 の最小値と 0.5 の最大値は、結果値が決して 0.0 より小さく、および 0.5 より大きくならないことを意味します。 +Clamp 表現式は、最小値と最大値が定義された指定範囲に受け取った値を制限します。0.0 の最小値と 0.5 の最大値は、結果値が決して 0.0 より小さく、および 0.5 より大きくならないことを意味します。 | アイテム | 説明 | | -------- | ----------- | @@ -63,12 +162,12 @@ Version:4.9 | **Clamp Mode** | 使用する Clamp のタイプを選択します。CMODE_Clamp は範囲の両端値をクランプします。CMODE_ClampMin と CMODE_ClampMax は、範囲内のそれぞれ対象となる値のみをクランプします。 | **Min Default** | クランプに使用する最小値を受け取ります。最小値の入力が未使用時のみ使用されます。 | | **Max Default** | クランプに使用する最大値を受け取ります。最大値の入力が未使用時のみ使用されます。 | -| [REGION:tablesection]入力値[/REGION] || +| [REGION:tablesection]入力[/REGION] || | **Min** | クランプに使用する最少値を受け取ります。 | | **Max** | クランプに使用する最大値を受け取ります。 | -**例: ** Min0.0 と Max1.0 で 0.3 をクランプすると、結果は 0.3 になります。 Min0.0 と Max1.0 を 1.3 をクランプすると結果は 1.0 になります。 +**例:** (0.0) から (1.0) の入力範囲を Min 0.0 と Maxx 1.0 で 0.3 をクランプすると、結果は 0.3 になり、Min0.0 と Max1.0 で 1.3 をクランプすると結果は 1.0 になります。 ![ClampExample.png](ClampExample.png)(w:900) @@ -78,14 +177,14 @@ Version:4.9 ## Cosine -**Cosine** 表現式は、[0, 1] の範囲に正弦波の値を繰り返し出力します。この関数は、[Time](Engine/Rendering/Materials/ExpressionReference/Constant#Time) 式と入力値を関連付けして継続的な振動の波形を出力することでよく知られています。出力値は -1 と 1 の周期を行ったり来たりします。波形を視覚的に表現したものが以下となります。 +**Cosine** 表現式は、[0, 1] の入力範囲および [-1, 1] の出力範囲に正弦波の値を繰り返し計算します。この関数は、[Time](Engine/Rendering/Materials/ExpressionReference/Constant#Time) 式と入力値を関連付けして継続的な振動の波形を出力することでよく知られていますが、ワールド スペースやスクリーン スペース、また継続した滑らかな円が必要なその他のアプリケーションでさざ波の作成に使用することもできます。波形を視覚的に表現したものが以下となります。出力範囲は [0, 1] に調整しています。 ![CosineWave.png](CosineWave.png) | アイテム | 説明 | | -------- | ----------- | | [REGION:tablesection]プロパティ[/REGION] || -| **Period** | 合成振動の周期を特定します。つまり、これによって 1 つの振動が発生するまでの時間が分かります。| +| **Period** | 結果として得られる振動の周期を特定します。つまり、これによって 1 つの振動が発生するまでの時間が分かります。| **使用例:** この表現式は振動効果が必要な際にいつでも便利です。振動の速度と振幅は、時間入力 (速度) または出力 (振幅) を乗算することにより、動的に簡単な制御が可能です。 @@ -98,11 +197,11 @@ Version:4.9 [EXCERPT:CrossProduct] ## CrossProduct -**CrossProduct** 表現式は、 3 チャンネルのベクター値の 2 つの入力値の外積を計算し、結果として 3 チャンネルのベクター値を出力します。空間に 2 つのライン (またはベクター) が与えられ、外積は両方の入力に対して垂直なライン (またはベクター) となります。 +**CrossProduct** 表現式は、3 チャンネルのベクター値の 2 つの入力値の外積を計算し、結果として 3 チャンネルのベクター値を計算します。空間に 2 つのライン (またはベクター) が与えられ、外積は両方の入力に対して垂直なライン (またはベクター) となります。 | アイテム | 説明 | | -------- | ----------- | -| [REGION:tablesection]入力値[/REGION] || +| [REGION:tablesection]入力[/REGION] || | **A** | 3チャンネルのベクター値を受け取ります。 | | **B** | 3チャンネルのベクター値を受け取ります。 | @@ -116,19 +215,19 @@ Version:4.9 ## Divide -Divide 表現式は、 2 つの入力値を受け取り、 1 番目の値を 2 番目の値で割った結果を出力します。除算はチャンネルごとに計算されます。つまり、最初の R チャンネルが 2 番目のチャンネルによって、最初の G チャンネルが 2 番目のチャンネルによって除算される形です。約数が単精度浮動小数点値でない限り、両方の入力値は同数でなくてはいけません。 _ゼロ除算は絶対に行わないでください。_ +Divide 表現式は、2 つの入力値を受け取り、1 番目の値を 2 番目の値で割った結果を出力します。除算はチャンネルごとに計算されます。つまり、最初の R チャンネルが 2 番目のチャンネルによって、最初の G チャンネルが 2 番目のチャンネルによって除算される形です。約数が single float 値でない限り、両方の入力値は同等でなければなりmさえん。どのチャンネルにおいてもゼロで割るとチャンネルにローカル ハードウェアの "無限" インプリメンテーションが含まれる結果になり、通常は非常に大きい正の値になります。 | アイテム | 説明 | | -------- | ----------- | | [REGION:tablesection]プロパティ[/REGION] || | **Const A** | 除算される値、被除数を受け取ります。A 入力が未使用時のみ使用されます。| | **Const B** | 除算する値、約数を受け取ります。B 入力が未使用時のみ使用されます。| -| [REGION:tablesection]入力値[/REGION] || +| [REGION:tablesection]入力[/REGION] || | **A** | 除算される値、被除数を受け取ります。 | | **B** | 除算する値、約数を受け取ります。 | -**例: ** A=(1.0,0.5,-0.4) と B=(2.0,2.0,4.0) の Divide の結果は (0.5,0.25,-0.1) となります。 +**例:** A=(1.0) と B=(5.0) を持つ Divide を使うと (0.2) を出力して、暗いグレーとなります。 ![DivideExample.png](DivideExample.png) @@ -136,13 +235,13 @@ Divide 表現式は、 2 つの入力値を受け取り、 1 番目の値を 2 [EXCERPT:DotProduct] ## DotProduct -**DotProduct** 表現式は、dot product (内積)、もしくはその他に投影されたあるベクターの長さを計算します。この計算は、フォールオフの計算に頻繁に使用される技術です。DotProduct は、両方のベクター入力値に同数のチャンネル数を必要とします。 +**DotProduct** 表現式は、別のベクターに投影された 1 つのベクターの長さ、もしくは大きさを乗じた 2 つのベクター間のコサインである dot product (内積) を計算します。この計算は、フォールオフの計算に頻繁に使用される技術です。DotProduct は、両方のベクター入力値に同等のチャンネル数を必要とします。 | アイテム | 説明 | | -------- | ----------- | -| [REGION:tablesection]入力値[/REGION] || +| [REGION:tablesection]入力[/REGION] || | **A** | 任意の長さの値またはベクターを受け取ります。 | -| **B** | 任意の長さの値またはベクターを受け取ります。 | +| **B** | **A** と同じ長さの値またはベクターを受け取ります。 | ![DotProductExample.png](DotProductExample.png)(w:900) @@ -153,37 +252,37 @@ Divide 表現式は、 2 つの入力値を受け取り、 1 番目の値を 2 **Floor** 表現式は、値を受け取り前の整数へ **切り下げて** 結果を出力します。[Ceil](#Ceil) と [Frac](#Frac) も参照してください。 -**例: ** 0.2 の Floor は 0.0 、 (0.2,1.6) の Floor は (0.0, 1.0) です。 +**例:** 0.2 の Floor は 0.0 、 (0.2,1.6) の Floor は (0.0, 1.0) です。 ![FloorExample.png](FloorExample.png)(w:900) ## FMod -**FMod** 表現式は、 2 つの入力値を除算した後の浮動小数点値余りを返します。 +**FMod** 表現式は、2 つの入力値を除算した後の浮動小数点値余りを返します。被除数 (入力 "A") はどの値でも構いませんが、被除数が負の場合は結果も負になります。約数 (2 つ目のインプット) をゼロにするとゼロでの除算を意味することになるので使えませんが、約数は正であっても負であっても結果に影響しません。一般的なユースケースでは、最大値まで明るいマテリアルを作成し、次のフレームで急に最小値に戻し、最大値へ上昇する結果となります。 ![FModExample.png](FModExample.png) -この例では、 FMod 式は 1 秒おきに 0 から 1 へ増える繰り返しの値を返します。1 へ到達すると、値は 0 へ戻り、これを無期限に繰り返します。 +この例では、FMod が 0 から 1 への UV 進捗を受け取り、それを変換して緑チャンネルの X 軸で 0.2 UV ごとに周期を繰り返されるようにします。 ## Frac -**Frac** 表現式は、値を受け取り、受け取った値の小数部分を出力します。[Ceil](#Ceil) と [Floor](#Floor) も参照してください。 +**Frac** 表現式は、値を受け取り、受け取った値の端数部分を出力します。言い換えると、入力値が "X" の場合、結果は "X - X の Floor" です。出力値は 0 から 1 です。下限は含みますが、上限は含みません。[Ceil](#Ceil) と [Floor](#Floor) も参照してください。 -**例: ** 0.2 の Franc は 0.2 、 (0.0,1.6) の Fran は (0.0, 0.6) です。 +**例:** (0.2) の Franc は (0.2) です。(-0.2) の ranc は (0.8) です。(0.0,1.6,1.0) の ranc は (0.0,0.6,0.0) です。 ![FracExample.png](FracExample.png)(w:900) -この例では、Franc ノードは一連の繰り返しとなる 0 - 1 数列へ時間を変更しています。カラーを緑から赤へフェード (Lerp を通じて) させて、緑へ戻り、これを無期限に繰り返します。 +この例では、Franc ノードは一連の繰り返しとなる 0 - 1 数列へ時間を変更しています。カラーを緑から赤へフェード (Lerp を通じて) させて、緑へ戻り、これを無限に繰り返します。 [EXCERPT:If] ## If -**If** 表現式は、 2 つの入力値を比較し、比較結果に基づいて他の 3 つの値のうち 1 つを渡します。比較される 2 つの入力値は単精度浮動小数点でなければいけません。 +**If** 表現式は、2 つの入力値を比較し、比較結果に基づいて他の 3 つの値のうち 1 つを渡します。比較される 2 つの入力値は単精度浮動小数点でなければいけません。 | アイテム | 説明 | | -------- | ----------- | -| [REGION:tablesection]入力値[/REGION] || +| [REGION:tablesection]入力[/REGION] || | **A** | 単精度浮動小数点を受け取ります。 | | **B** | 単精度浮動小数点を受け取ります。 | | **A > B** | A の値が B の値より大きい時、値を受け取り出力します。 | @@ -203,61 +302,59 @@ Divide 表現式は、 2 つの入力値を受け取り、 1 番目の値を 2 ## Max -**Max** 表現式は 2 つの入力を取り込み、この 2 つの最大値を出力します。 +**Max** 表現式は 2 つの入力を取り込み、高い方の値を出力します。 このノードは Photoshop の Lighten に似ています。 ![](MaxExample.png)(w:720) -上記の表現式では、A は「0」で B は「1」なので「1」(白) が結果となるベースカラーになります。 +上記の表現式では、A は "0" で B は "1" なので、ベースカラーは "1" (白) になります。 | アイテム | 説明 | | -------- | ----------- | | [REGION:tablesection]プロパティ[/REGION] || | **Const A** | 最初の値を受け取ります。A 入力値が未使用の場合のみ使用されます。| | **Const B** | 2 番目の値を受け取ります。B 入力値が未使用の場合のみ使用されます。| -| [REGION:tablesection]入力値[/REGION] || +| [REGION:tablesection]入力[/REGION] || | **A** | 比較する最初の値を受け取ります。 | | **B** | 比較する 2 番目の値を受け取ります。 | ## Min -**Min** 表現式は 2 つの入力を取り込み、この 2 つの最小値を取ります。 +**Min** 表現式は 2 つの入力を取り込み、低い方の値を出力します。 このノードは Photoshop の Darken に似ています。 ![](MinExample.png)(w:720) -上記の表現式では、A は「0」で B は「1」なので「0」(黒) が結果となるベースカラーになります。 +上記の表現式では、A は "0" で B は "1" なので、ベースカラーは "0" (黒) になります。 | アイテム | 説明 | | -------- | ----------- | | [REGION:tablesection]プロパティ[/REGION] || | **Const A** | 最初の値を受け取ります。A 入力値が未使用の場合のみ使用されます。| | **Const B** | 2 番目の値を受け取ります。B 入力値が未使用の場合のみ使用されます。| -| [REGION:tablesection]入力値[/REGION] || +| [REGION:tablesection]入力[/REGION] || | **A** | 比較する最初の値を受け取ります。 | | **B** | 比較する 2 番目の値を受け取ります。 | - - ## Multiply -**Multiply** 表現式は、 2 つの入力値を受け取り、その入力値を掛け合わせて結果を出力します。Photoshop のレイヤーのブレンドモードの乗算に似た機能です。乗算はチャンネルごとに計算されます。つまり最初の R チャンネルが 2 番目の値と掛けられ、最初の G チャンネルが 2 番目の値と掛けられる形になります。片方の値が単精度浮動小数点値でない限り、同数の入力値でなくてはいけません。 +**Multiply** 表現式は、 2 つの入力値を受け取り、その入力値を掛け合わせて結果を出力します。Photoshop のレイヤーのブレンドモードの乗算に似た機能です。乗算はチャンネルごとに計算されます。つまり最初の R チャンネルを 2 番目の R チャンネルと掛け、最初の G チャンネルを 2 番目の G チャンネルと掛けます。片方の値が single float 値でない限り、両方の入力は同等の入力値でなくてはいけません。 | アイテム | 説明 | | -------- | ----------- | | [REGION:tablesection]プロパティ[/REGION] || | **Const A** | 乗算する最初の値を受け取ります。A 入力値が未使用の場合のみ使用されます。| | **Const B** | 乗算する 2 番目の値を受け取ります。B 入力値が未使用の場合のみ使用されます。| -| [REGION:tablesection]入力値[/REGION] || +| [REGION:tablesection]入力[/REGION] || | **A** | 乗算する最初の値を受け取ります。 | | **B** | 乗算する 2 番目の値を受け取ります。 | -UE4 のマテリアルは [0,1] に制限されていないことを忘れないでください!カラー / 値が 1 より大きい場合、Multiply 表現式は実際にカラーを明るくします。 +UE4 のマテリアルは [0,1] には制限されないことを忘れないでください!カラー / 値が 1 より大きい場合、Multiply 表現式は実際にカラーを明るくします。 **例:** 0.4 と 0.5 の Multiply は 0.2 、 (0.2、-0.4、0.6) と (0.0、2.0、1.0) の Multiply は (0.0、-0.8、0.6) 、 (0.2、-0.4、0.6) と 0.5 の Multiply は (0.1、-0.2、0.3) となります。 @@ -269,9 +366,18 @@ UE4 のマテリアルは [0,1] に制限されていないことを忘れない [EXCERPT:Normalize] ## Normalize -**Normalize** 表現式は、入力の標準値を計算して出力します。これは入力値の各コンポーネントが、ベクターの L-2 ノルム (長さ) で割られることを意味します。 +**Normalize** 表現式は、入力の標準値を計算して出力します。ノーマライズされたベクター ("単位ベクター" とも呼ばれます) の全長は 1.0 です。つまり、入力値の各コンポーネントをベクターの大きさ (長さ) で割ることを意味します。 -![NormalizeExample.png](NormalizeExample.png)(w:900) +**例:** Normalize で (0,2,0) あるいは (0,0.2,0) をパスすると、(0,1,0) が出力されます。Normalize で (0,1,-1) をパスすると (0, 0.707, -0.707) が出力されます。すべてのベクターがゼロの場合は特別なケースとなり、変化しません。 + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Normalized Input Vector](NormalizeExample.png)(w:900) + [/PARAM] + [PARAM:after] + ![Non-Normalized Input Vector](NormalizeExample2.png)(w:900) + [/PARAM] +[/OBJECT] [REGION:note] Normal マテリアル出力値に接続された表現式は、標準化する必要はありません。 @@ -281,7 +387,7 @@ Normal マテリアル出力値に接続された表現式は、標準化する ## OneMinus -**OneMinus** 表現式は、入力値を受け取り、'1 からその値を引いて' 出力します。演算はチャンネルごとに実行されます。 +**OneMinus** は、入力値 "X" を受け取り、"X - 1" の値を出力します。演算はチャンネルごとに実行されます。 **例:** 0.4 の OneMinus は 0.6、 (0.2、0.5、1.0) の OneMinus は (0.8、0.5、0.0) 、 (0.0、-0.4、1.6) の OneMinus は (1.0、1.4、-0.6) になります。 @@ -292,65 +398,123 @@ Normal マテリアル出力値に接続された表現式は、標準化する ## Power -**Power** 表現式は、2 つの入力値を受け取り、Base を Exp 乗の累乗をして結果を出力します。言い換えると、Base がその値によって Exp 回乗算されます。 +**Power** は、2 つの入力値を受け取り、Base を Exp 乗の累乗をして結果を出力します。言い換えると、Base がその値によって Exp 回乗算されます。 | アイテム | 説明 | | -------- | ----------- | | [REGION:tablesection]プロパティ[/REGION] || | **Const Exponent** | 指数値を受け取ります。Exp 入力値が未使用の場合のみ使用されます。| -| [REGION:tablesection]入力値[/REGION] || +| [REGION:tablesection]入力[/REGION] || | **Base** | ベース値を受け取ります。 | | **Exp** | 指数値を受け取ります。 | **例:** Base0.5 の Exp2.0 乗は 0.25 になります。 -**使用例:** Power に渡すカラーが [0,1] の場合、Power は明るい色のみが残るコントラスト調整として動作します。 +**使用例:** Power に渡すカラーが [0,1] の場合、Power は非常に明るい値はわずかに下がり、暗めの値は大幅に減少するように、コントラスト調整のような動作をします。 ![PowerExample.png](PowerExample.png) +## Round + +**Round** は端数部分が半分以上の場合、その値を次の整数へ値を四捨五入します。半分以下の場合は切り捨てます。 + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before Round](RoundExample_00.png)(w:1100) + [/PARAM] + [PARAM:after] + ![After Round](RoundExample_01.png) + [/PARAM] +[/OBJECT] + +**例:** +* 1.1 は四捨五入すると 1 となります。 +* 1.4 は四捨五入すると 1 となります。 +* 1.5 は四捨五入すると 2 となります。 +* 1.85 は四捨五入すると 2 となります。 + +## Saturate + +The **Saturate** ノードは値を 0 と 1 の間にクランプします。最新のグラフィックス ハードウェアの多くの場合、Saturate は命令負荷がほとんどありません。 + +![](SaturateExample_00.png) + +**使用例:** このノードは、入力値もしくは出力値を 0 と 1 の間にクランプする必要がある場合に使用します。 + ## Sine -**Sine** 表現式は、[0, 1] の範囲に正弦波の値を繰り返し出力します。この関数は、[Time](Engine/Rendering/Materials/ExpressionReference/Constant#Time) 式と入力値を関連付けして継続的な振動の波形を出力することでよく知られています。出力値は -1 と 1 の周期を行ったり来たりします。この表現式の結果と [Cosine](#Cosine) 表現式の出力値の違いは、出力波形がほぼ半分にオフセットされることです。波形を視覚的に表現したものが以下となります。 +**Sine** 表現式は、[0, 1] の入力範囲および [-1, 1] の出力範囲に正弦波の値を繰り返し出力します。この表現式の結果と [Cosine](#Cosine) 表現式の出力値の違いは、出力波形が1/4 にオフセットされる、つまり `Cos(X)` は `Sin(X + 0.25)` に等しくなります。この関数は、[Time](Engine/Rendering/Materials/ExpressionReference/Constant#Time) 式と入力値を関連付けして継続的な振動の波形を出力することでよく知られていますが、ワールド スペースやスクリーン スペース、また継続した滑らかな円が必要なその他のアプリケーションでさざ波の作成に使用することもできます。波形を視覚的に表現したものが以下となります。出力範囲は [0, 1] に調整しています。 ![SineWave.png](SineWave.png) | アイテム | 説明 | | -------- | ----------- | | [REGION:tablesection]プロパティ[/REGION] || -| **Period** | 合成振動の周期を特定します。つまり、これによって 1 つの振動が発生するまでの時間が分かります。| +| **Period** | 結果として得られる振動の周期を特定します。つまり、これによって 1 つの振動が発生するまでの時間が分かります。| -**使用例:** この表現式は振動効果が必要な際にいつでも便利です。振動の速度と振幅は、時間入力 (速度) または出力 (振幅) を乗算することにより、動的に簡単な制御が可能です。 +**使用例:** この表現式は振動効果が必要な場合に役立ちます。振動の速度と振幅は、時間入力 (速度) または出力 (振幅) を乗算することにより、動的に簡単な制御が可能です。 ![SineExample.png](SineExample.png) ## SquareRoot -**SquareRoot** 表現式は入力値の平方根を出力します。SquareRoot は、単精度浮動小数点入力値のみ演算することが出来ます。 +**SquareRoot** 表現式は入力値の平方根を出力します。ベクターに適用する場合、各コンポーネントは個々に処理されます。 ![SqrtExample.png](SqrtExample.png)(w:900) ## Subtract -**Subtract** ノードは 2 つの入力値を受け取り、最初の入力値から 2 番目の値を減算し差分を出力します。減算はチャンネルごとに実行されます。つまり、 2 番目の入力の R チャンネルが最初の入力値から減算され、 2 番目の入力の G チャンネルから最初の入力値が減算される、といった具合です。2 番目の入力値が単精度浮動小数点値でない限り、両入力値は同数のチャンネルを持たなくてはいけません。定数は、ベクターのさまざまな入力値から減算されます。 +**Subtract** ノードは 2 つの入力値を受け取り、最初の入力値から 2 番目の値を減算し差分を出力します。減算はチャンネルごとに実行されます。つまり、 2 番目の入力の R チャンネルが最初の入力値から減算され、 2 番目の入力の G チャンネルから最初の入力値が減算される、といった具合です。2 番目の入力値が単一の定数値でない限り、両入力値は同数のチャンネルを持たなくてはいけません。定数は、ベクターのさまざまな入力値から減算されます。 | アイテム | 説明 | | -------- | ----------- | | [REGION:tablesection]プロパティ[/REGION] || | **Const A** | 被減数の値を受け取ります。A 入力値が未使用の場合のみ使用されます。| | **Const B** | 減数される値を受け取ります。B 入力値が未使用の場合のみ使用されます。| -| [REGION:tablesection]入力値[/REGION] || +| [REGION:tablesection]入力[/REGION] || | **A** | 被減数の値を受け取ります。 | | **B** | 減数される値を受け取ります。 -**例:b** 0.5 から 0.2 を減算すると 0.3 、 (0.2、-0.4、0.6) から (0.1、0.1、1.0) を減算すると、 (0.1、-0.5、-0.4) 、 (0.2、0.4、1.0) から 0.2 を減算すると (0.0、0.2、0.8) になります。 +**例:** 0.5 から 0.2 を減算すると 0.3 、 (0.2、-0.4、0.6) から (0.1、0.1、1.0) を減算すると、 (0.1、-0.5、-0.4) 、 (0.2、0.4、1.0) から 0.2 を減算すると (0.0、0.2、0.8) になります。 **使用例:** Subtract は、濃いカラーやオフセット UV に使用出来ます。 ![SubtractExample.png](SubtractExample.png)(w:900) +## Tangent + +[REGION:lightbox] +[![](MEN_Tangent.png)(w:469)](MEN_Tangent.png) +[/REGION] + +[REGION:caption] +クリックしてフルサイズで表示 +[/REGION] + +**Tangent** ノードは指定した値のタンジェントを出力します。 + +## Truncate + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before Truncate](TruncateExample_00.png)(w:1100) + [/PARAM] + [PARAM:after] + ![After Truncate](TruncateExample_01.png) + [/PARAM] +[/OBJECT] + + +**Truncate** ノードは、整数部分は変更せずに端数部分を削除して、値を切り捨てます。 + +**例:** +* 1.1 は切り捨てると 1 になります。 +* 1.4 は切り捨てると 1 になります。 +* 2.5 は切り捨てると 2 になります。 +* 3.1 は切り捨てると 3 になります。 \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/ExpressionReference/Math/MathExpressions.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/ExpressionReference/Math/MathExpressions.KOR.udn index 92fe567dfe0f..55608af8fd3d 100644 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/ExpressionReference/Math/MathExpressions.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/ExpressionReference/Math/MathExpressions.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3355715 +INTSourceChangelist:3409695 Availability:Public Title:Math 표현식 Crumbs: %ROOT%, Engine, Engine/Rendering/Materials, Engine/Rendering/Materials/ExpressionReference @@ -45,6 +45,104 @@ Add 표현식은 두 입력을 받아 더한 다음 결과를 출력합니다. [INCLUDE:Engine/Rendering/Materials/ExpressionReference/VectorOps#AppendVector] +## ArcSine + +[REGION:lightbox] +[![](MEN_ArcSine.png)(w:469)](MEN_ArcSine.png) +[/REGION] + +[REGION:caption] +클릭하면 이미지 원본을 확인합니다. +[/REGION] + +**Arcsine** (아크사인) 표현식은 사인 함수의 역을 출력합니다. 인스트럭션 카운트에는 반영되지 않는 비싼 연산입니다. + +## ArcSineFast + +[REGION:lightbox] +[![](MEN_ArcSineFast.png)(w:469)](MEN_ArcSineFast.png) +[/REGION] + +[REGION:caption] +클릭하면 이미지 원본을 확인합니다. +[/REGION] + +**ArcsineFast** (빠른 아크사인) 표현식은 사인 함수의 역 추정 버전을 출력합니다. 입력 값은 -1 에서 1 범위여야 합니다. + +## ArcCosine + +[REGION:lightbox] +[![](MEN_ArcCosine.png)(w:469)](MEN_ArcCosine.png) +[/REGION] + +[REGION:caption] +클릭하면 이미지 원본을 확인합니다. +[/REGION] + +**Arccosine** (아크 코사인) 표현식은 코사인 함수의 역을 출력합니다. 인스트럭션 카운트에는 반영되지 않는 비싼 연산입니다. + +## ArcCosineFast + +[REGION:lightbox] +[![](MEN_ArcCosineFast.png)(w:469)](MEN_ArcCosineFast.png) +[/REGION] + +[REGION:caption] +클릭하면 이미지 원본을 확인합니다. +[/REGION] + + +**ArccosineFast** (빠른 아크 코사인) 표현식은 역 코사인 함수의 추정 버전을 출력합니다. 입력 범위는 -1 에서 1 사이여야 합니다. + +## ArcTangent + +[REGION:lightbox] +[![](MEN_ArcTangent.png)(w:469)](MEN_ArcTangent.png) +[/REGION] + +[REGION:caption] +클릭하면 이미지 원본을 확인합니다. +[/REGION] + +**Arctangent** (아크 탄젠트) 표현식은 탄젠트 함수의 역을 출력합니다. 인스트럭션 카운트에 반영되지 않는 비싼 연산입니다. + +## ArcTragnetFast + +[REGION:lightbox] +[![](MEN_ArcTangentFast.png)(w:469)](MEN_ArcTangentFast.png) +[/REGION] + +[REGION:caption] +클릭하면 이미지 원본을 확인합니다. +[/REGION] + +**ArctangentFast** 표현식은 역 탄젠트 함수의 추정 버전을 출력합니다. + +## ArcTangent2 + +[REGION:lightbox] +[![](MEN_ArcTangent2.png)(w:469)](MEN_ArcTangent2.png) +[/REGION] + +[REGION:caption] +클릭하면 이미지 원본을 확인합니다. +[/REGION] + + +**Arctangent2** (아크 탄젠트 2) 표현식은 입력 부호로 사분면을 결정하는 x / y 의 역 탄젠트를 사용합니다. 인스트럭션 카운트에 반영되지 않는 비싼 연산입니다. + +## ArcrTangent2Fast + +[REGION:lightbox] +[![](MEN_ArcTangent2Fast.png)(w:469)](MEN_ArcTangent2Fast.png) +[/REGION] + +[REGION:caption] +클릭하면 이미지 원본을 확인합니다. +[/REGION] + +**Arctangent2Fast** 표현식은 입력 부호로 사분면을 결정하는 X / Y 의 역 탄젠트 추정입니다. + ## Ceil Ceil (천정) 표현식은 값을 받아 소수점을 무조건 **올려** 더 큰 정수로 만든 결과를 출력합니다. [Floor](#Floor) 와 [Frac](#Frac) 도 참고하세요. @@ -242,8 +340,6 @@ Min (최소) 표현식은 입력을 둘 받은 다음 그 중 낮은 것을 출 | **B** | 비교할 두 번째 값을 받습니다. | - - ## Multiply Multiply (곱하기) 표현식은 두 입력을 받아 서로 곱한 다음 결과를 출력합니다. 포포토샵의 멀티플라이 레이어 블렌드와 유사합니다. 곱하기는 채널별로 이루어집니다. 즉 첫째의 R은 둘째의 R로, 첫째의 G는 둘째의 G로 곱하는 식입니다. 둘 중 하나가 단일 실수값이 아닌 다음에야 두 입력은 채널 수가 같아야 합니다. @@ -320,6 +416,33 @@ Power (거듭제곱) 표현식은 입력 둘을 받아서, Base(밑)을 Exp(지 ![PowerExample.png](PowerExample.png) +## Round + +**Round** (반올림) 표현식은 소수점이 .5 이상이면 다음 정수로 반올림을, 미만이면 내립니다. + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Round 전](RoundExample_00.png)(w:1100) + [/PARAM] + [PARAM:after] + ![Round 후](RoundExample_01.png) + [/PARAM] +[/OBJECT] + +**예:** +* 1.1 의 Round 는 1 입니다. +* 1.4 의 Round 는 1 입니다. +* 1.5 의 Round 는 2 입니다. +* 1.85 의 Round 는 2 입니다. + +## Saturate + +**Saturate** (포화) 노드는 값을 0 에서 1 범위로 클램프(제한)시킵니다. Saturate 인스트럭션 비용은 최근 그래픽 하드웨어에서는 거의 무료입니다. + +![](SaturateExample_00.png) + +**사용 예:** 출력이나 입력 값을 0 에서 1 사이 범위로 제한시키고자 할 때 사용하면 됩니다. + ## Sine **Sine** (사인) 표현식은 [0, 1] 입력 범위와 [-1, 1] 출력 범위에 걸쳐 둘 다 반복되는 사인 곡선 값을 출력합니다. [Cosine](#Cosine) 표현식 출력과의 차이는 파형에 주기의 1/4 만큼 오프셋이 적용되어 있습니다. `Cos(X)` 는 `Sin(X + 0.25)` 와 같다는 뜻입니다. 아주 흔하게, 입력에 [Time](Engine/Rendering/Materials/ExpressionReference/Constant#Time) 표현식을 입력하여 연속 진동 파형을 출력하는데 사용되지만, 월드스페이스 또는 스크린스페이스에서 물결을 만들 때나, 연속적인 부드러운 사이클이 필요한 경우에도 사용 가능합니다. 파형의 시각적 표현은 아래와 같으며, [0, 1] 출력 범위로 스케일을 조절한 것입니다: @@ -364,3 +487,34 @@ Subtract (빼기) 표현식은 두 입력을 받아 첫째에서 둘째를 뺀 ![SubtractExample.png](SubtractExample.png)(w:900) +## Tangent + +[REGION:lightbox] +[![](MEN_Tangent.png)(w:469)](MEN_Tangent.png) +[/REGION] + +[REGION:caption] +클릭하면 이미지 원본을 확인합니다. +[/REGION] + +**Tangent** (탄젠트) 노드는 지정된 값의 탄젠트를 출력합니다. + +## Truncate + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Truncate 전](TruncateExample_00.png)(w:1100) + [/PARAM] + [PARAM:after] + ![Truncate 후](TruncateExample_01.png) + [/PARAM] +[/OBJECT] + + +**Truncate** (버림) 노드는 값의 정수 부분만 남기고 소수점 부분은 버립니다. + +**예제:** +* 1.1 의 Truncate 는 1 입니다. +* 1.4 의 Truncate 는 1 입니다. +* 2.5 의 Truncate 는 2 입니다. +* 3.1 의 Truncate 는 3 입니다. \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/ExpressionReference/Utility/UtilityExpressions.INT.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/ExpressionReference/Utility/UtilityExpressions.INT.udn index db4423b47776..d453e94d2f7d 100644 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/ExpressionReference/Utility/UtilityExpressions.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/ExpressionReference/Utility/UtilityExpressions.INT.udn @@ -1,316 +1,31 @@ -Availability:Public -Title:Utility Expressions -Crumbs: %ROOT%, Engine, Engine/Rendering/Materials, Engine/Rendering/Materials/ExpressionReference +Availability: Public +Crumbs: %ROOT% +Title: Utility Expressions Description:Expressions that perform various utility operations on one or more inputs. -Version: 4.9 -tags:Materials +Type: Reference +Version:4.16 +Parent:Engine/Rendering/Materials/ExpressionReference +Order: +Tags:Materials +Topic-image:Utility_topic.png + [EXCERPT:TOC] -[TOC(start:2)] +[TOC(start:2 end:2)] [/EXCERPT:TOC] -## BlackBody +In this page, you'll find the available Utility Expressions that enable you to input values to affect Material's output value, like for example, using the GIReplace node will Replace an objects +indirect bounce color with a given value you input, or LinearInterpolate will blend between two inputs using an alpha value to control how much. -The **BlackBody** expression simulates the effects of [black body radiation](http://en.wikipedia.org/wiki/Black-body_radiation) within your Material. The user inputs a temperature (in Kelvin) and the resulting color and intensity can be used to drive Base Color and Emissive values to get a physically accurate result. +There are many others that enable you to control your Materials that you can look at the examples below to learn more about. -[REGION:fullwidth] -![](BlackBody.png) -[/REGION] - -## BumpOffset - -[EXCERPT:BumpOffset] -**BumpOffset** is the Unreal Engine 4 term for what is commonly known as 'Parallax Mapping'. The Bump Offset expression allows a material to give the illusion of depth without the need for additional geometry. BumpOffset materials use a grayscale _heightmap_ to give depth information. The brighter the value in the heightmap, the more 'popped out' the material will be; these areas will parallax (shift) as a camera moves across the surface. Darker areas in the heightmap are 'further away' and will shift the least. -[/EXCERPT:BumpOffset] - - -| Item | Description | -| -------- | ----------- | -| [REGION:tablesection]Properties[/REGION] || -| **HeightRatio** | Multiplier for the depth taken from the _heightmap_. The larger the value, the more extreme the depth will be. Typical values range from 0.02 to 0.1. | -| **ReferencePlane** | Specifies the approximate height in texture space to apply the effect. A value of 0 will appear to distort the texture completely off the surface, whereas a value of 0.5 (the default) means that some of the surface will pop off while some areas will be sunken in. | -| [REGION:tablesection]Inputs[/REGION] || -| **Coordinate** | Takes in base texture coordinates to be modified by the expression. | -| **Height** | Takes in the texture (or a value) to be used as the heightmap. | -| **HeightRatioInput** | Multiplier for the depth taken from the _heightmap_. The larger the value, the more extreme the depth will be. Typical values range from 0.02 to 0.1. If used, this input supersedes any value in the Height Ratio property. | - -[REGION:fullwidth] -![BumpOffsetExample.png](BumpOffsetExample.png) -[/REGION] - -## ConstantBiasScale - -The **ConstantBiasScale** expression takes an input value, adds a bias value to it, and then multiplies it by a scaling factor outputting the result. So for example, to convert input data from [-1,1] to [0,1] you would use a bias of 1.0 and a scale of 0.5. - -| Item | Description | -| -------- | ----------- | -| [REGION:tablesection]Properties[/REGION] || -| **Bias** | Specifies the value to be added to the input. | -| **Scale** | Specifies the multiplier for the biased result. | - - -![ConstantBiasScaleExample.png](ConstantBiasScaleExample.png) - - -## DDX - -The **DDX** expression exposes DDX derivative calculation, a GPU hardware feature used in pixel shader calculation. - -## DDY - -The **DDY** expression exposes DDX derivative calculation, a GPU hardware feature used in pixel shader calculation. - -[INCLUDE:Engine/Rendering/Materials/ExpressionReference/Depth#DepthFade] - - -## DepthOfFieldFunction - -The **Depth of Field Function** expression is designed to give artists control over what happens to a Material when it is being blurred by Depth of Field. It outputs a value between 0-1 such that 0 represents "in focus" and 1 represents "completely blurred." This is useful for interpolating between sharp and blurry versions of a texture, for instance. The Depth input allows for the existing results from the scene's Depth of Field calculations to be overridden by other calculations. - -[OBJECT:ComparisonSlider] - [PARAM:before] - ![Blended Colors](DepthOfFieldFunction_Color.png)(w:350) - [/PARAM] - [PARAM:after] - ![Blending regular and blurred textures](DepthOfFieldFunction_Texture.png)(w:350) - [/PARAM] -[/OBJECT] - -[REGION:lightbox] -[![](DepthOfFieldFunctionNetwork.png)(w:300)](DepthOfFieldFunctionNetwork.png) -[/REGION] -[REGION:caption] -Network sample (Click for full size) -[/REGION] - -[EXCERPT:Desaturation] -## Desaturation - -The **Desaturation** expression desaturates its input, or converts the colors of its input into shades of gray, based a certain percentage. - -| Item | Description | -| -------- | ----------- | -| [REGION:tablesection]Properties[/REGION] || -| **Luminance Factors** | Specifies the amount that each channel contributes to the desaturated color. This is what controls that green is brighter than red which is brighter than blue when desaturated. | -| [REGION:tablesection]Inputs[/REGION] || -| **Fraction** | Specifies the amount of desaturation to apply to the input. Percent can range from 0.0 (fully desaturated) to 1.0 (full original color, no desaturation). | - - -![DesaturationExample.png](DesaturationExample.png) - -[REGION:note] -**Programmers:** Define desaturated color `D`, input color `I` and luminance factor `L`. The output will be `O = (1-Percent)*(D.dot(I)) + Percent*I` -[/REGION] -[/EXCERPT:Desaturation] - - -[EXCERPT:Distance] -## Distance - -The **Distance** expression computes the (Euclidian) distance between two points/colors/positions/vectors and outputs the resulting value. This works on one, two, three and four component vectors, but both inputs to the expression must have the same number of channels. - -| Item | Description | -| -------- | ----------- | -| [REGION:tablesection]Inputs[/REGION] || -| **A** | Takes in a value or vector of any length. | -| **B** | Takes in a value or vector of any length. | - -[REGION:fullwidth] -![DistanceExample.png](DistanceExample.png) -[/REGION] - -**Pseudo code:** - - Result = length(A - B) - -**Low level HLSL code:** - - float Result = sqrt(dot(A-B, A-B)) - -[/EXCERPT:Distance] - - - -[EXCERPT:FeatureLevelSwitch] -## FeatureLevelSwitch - -The **Feature Level Switch** node allows you to make simplified materials for lower powered devices. - -**Example Usage**: You might have a material with 10 textures overlapping and complex math, but just a single static texture for mobile (feature level ES2). - -| Item | Description | -| -------- | ----------- | -| [REGION:tablesection]Inputs[/REGION] || -| **Default** | The default Feature Level. | -| **ES2** | Feature Level defined by the core capabilities of OpenGL ES2. | -| **ES3.1** | Feature Level defined by the capabilities of Metal-level devices. | -| **SM4** | Feature Level defined by the core capabilities of DX10 Shader Model 4. | -| **SM5** | Feature Level defined by the core capabilities of DX11 Shader Model 5. | - -[/EXCERPT:FeatureLevelSwitch] - - - -## Fresnel - -The **Fresnel** expression calculates a falloff based on the dot product of the surface normal and the direction to the camera. When the surface normal points directly at the camera, a value of 0 is output. When the surface normal is perpendicular to the camera, a value of 1 is output. The result is clamped to [0,1] so you do not have any negative color in the center. - -| Item | Description | -| -------- | ----------- | -| [REGION:tablesection]Properties[/REGION] || -| **Exponent** | Specifies the how quickly the output value falls off. Larger values mean tighter or quicker falloff. | -| **Base Reflect Fraction** | Specifies the fraction of specular reflection the surface is viewed from straight on. A value of 1 effectively disables the Fresnel effect. | -| [REGION:tablesection]Inputs[/REGION] || -| **ExponentIn** | Specifies the how quickly the output value falls off. Larger values mean tighter or quicker falloff. If used, value will always supersede the Exponent property value. | -| **Base Reflect Fraction** | Specifies the fraction of specular reflection the surface is viewed from straight on. A value of 1 effectively disables the Fresnel effect. If used, value will always supersede the Exponent property value. | -| **Normal** | Takes in a three-channel vector value representing the normal of the surface, in world space. To see the results of a normal map applied to the surface of the Fresnel object, connect the normal map to the Normal input of the material, then connect a (PixelNormalWS)[Engine/Rendering/Materials/ExpressionReference/Vector#PixelNormalWS] expression to this input on the Fresnel. If no normal is specified, the tangent normal of the mesh is used. | - - -![FresnelExample.png](FresnelExample.png) - - -[EXCERPT:GIReplace] -## GIReplace - -**GIReplace** allows artists to specify a different, usually simpler, expression chain when the material is being used for GI. - -**Example Usage**: Lightmass static GI and LPV dynamic GI use it. - -| Item | Description | -| -------- | ----------- | -| [REGION:tablesection]Inputs[/REGION] || -| **Default** | The default GI. | -| **StaticIndirect** | Used for baked indirect lighting. | -| **DynamicIndirect** | Used for dynamic indirect lighting. | - -[INCLUDE:Engine\Rendering\LightingAndShadows\LightPropagationVolumes#gireplaceexample] - - -[/EXCERPT:GIReplace] - - - - -## LightmassReplace - -The **LightmassReplace** expression simply passes through the Realtime input when compiling the material for normal rendering purposes, and passes through the Lightmass input when exporting the material to Lightmass for global illumination. This is useful to work around material expressions that the exported version cannot handle correctly, for example WorldPosition. - -| Item | Description | -| -------- | ----------- | -| [REGION:tablesection]Inputs[/REGION] || -| **Realtime** | Takes in the value(s) to pass through for normal rendering. | -| **Lightmass** | Takes in the value(s) to pass through when exporting the material to Lightmass. | - - -[EXCERPT:LinearInterpolate] -## LinearInterpolate - -The **LinearInterpolate** expression blends between two input value(s) based on a third input value used as a mask. This can be thought of as a mask to define transitions between two textures, like a layer mask in Photoshop. The intensity of the mask Alpha determines the ratio of color to take from the two input values. If Alpha is 0.0/black, the first input is used. If Alpha is 1.0/white, the second input is used. If Alpha is grey (somewhere between 0.0 and 1.0), the output is a blend between the two inputs. Keep in mind that the blend happens per channel. So, if Alpha is an RGB color, Alpha's red channel value defines the blend between A and B's red channels **independently** of Alpha's green channel, which defines the blend between A and B's green channels. - -| Item | Description | -| -------- | ----------- | -| [REGION:tablesection]Properties[/REGION] || -| **Const A** | The value mapped to black (0.0). Only used if the A input is unconnected. | -| **Const B** | The value mapped to white (1.0). Only used if the B input is unconnected. | -| **Const Alpha** | Takes in the value to use as the mask alpha. Only used if the Alpha input is unconnected. | -| [REGION:tablesection]Inputs[/REGION] || -| **A** | Takes in the value(s) mapped to black (0.0). | -| **B** | Takes in the value(s) mapped to white (1.0). | -| **Alpha** | Takes in the value to use as the mask alpha. | - - -**Programmers:** LinearInterpolate does a per-channel lerp between A and B based on the parametric value Alpha. - -![LerpExample.png](LerpExample.png)(w:900) -[/EXCERPT:LinearInterpolate] - - -## Noise - -The **Noise** expression creates a procedural noise field, giving you control over how it is generated. - -| Item | Description | -| -------- | ----------- | -| [REGION:tablesection]Properties[/REGION] || -| **Scale** | Changes the overall size of the noise cells. Lower numbers make the noise bigger. | -| **Quality** | A look/performance setting. Lower values are faster but may look worse, higher values are slower but may look better. | -| **Function** | [INCLUDE:#NoiseFunctions] | -| **Turbulence** | Whether to use an absolute value when combining noise levels, results in a veined or billowy look. | -| **Levels** | How many different levels of noise at different scales to combine, multiplies the computational cost by the number of levels. | -| **Output Min** | The lowest value output by the noise calculation. | -| **Output Max** | The highest value output by the noise calculation. | -| **Level Scale** | Controls the scale of individual levels when using multiple levels of noise. This defaults to 2 so each level is twice the frequency at half the magnitude. | -| **Tiling** | For noise functions that support it, allows noise to tile. This is more expensive, but useful when baking noise into a seamless wrapping texture. | -| **Repeat Size** | When tiling, how often should the noise repeat. | -|| [REGION:tablesection]Inputs[/REGION] || -| **Position** | Allows the texture size to be adjusted via a 3D vector. | -| **FilterWidth** | In effect, controls how much blur will be applied to the noise texture. | - -![NoiseExample.png](NoiseExample.png) - - -## Vector Noise - -[INCLUDE:Engine\Rendering\Materials\ExpressionReference\Vector#VectorNoiseTest] - -## QualitySwitch - -The **QualitySwitch** expression allows for the use of different expression networks based on the engine is switched between quality levels, such as using lower quality on lower-end devices. - -| Item | Description | -| -------- | ----------- | -| [REGION:tablesection]Inputs[/REGION] || -| Default | This input is used for networks designed for default visual quality. | -| Low | This input is used for networks designed for lower visual quality. | -| High | This input is used for networks designed for higher visual quality. | - -[EXCERPT:RotateAboutAxis] -## RotateAboutAxis - -The **RotateAboutAxis** expression rotates a three-channel vector input given the rotation axis, a point on the axis, and the angle to rotate. It is useful for animations using WorldPositionOffset that have better quality than simple shears. - -| Item | Description | -| -------- | ----------- | -| [REGION:tablesection]Inputs[/REGION] || -| **NormalizedRotationAxis** | Takes in a normalized (0-1) vector which represents the axis about which the object will rotate. | -| **RotationAngle** | The angle of rotation. A value of 1 equals a full 360-degree rotation. -| **PivotPoint** | Takes in the three-channel vector representing the pivot point about which the object will rotate. | -| **Position** | Takes in the three-channel vector representing the position of the object. When the RotateAboutAxis expression is created, a WorldPosition expression is automatically created and connected to this input. | - -[REGION:fullwidth] -![RotateAboutAxisExample.png](RotateAboutAxisExample.png) -[/REGION] -In the above example, the preview plane would appear to spin on its vertical axis. - -[/EXCERPT:RotateAboutAxis] - - -## SphereMask - -The **SphereMask** expression outputs a mask value based on a distance calculation. If one input is the position of a point and the other input is the center of a sphere with some radius, the mask value is 0 outside and 1 inside with some transition area. This works on one, two, three, and four component vectors - -| Item | Description | -| -------- | ----------- | -| [REGION:tablesection]Properties[/REGION] || -| **Attenuation Radius** | Specifies the radius to use for the distance calculation. | -| **Hardness Percent** | Specifies the transition area size. This works like the Photoshop brush hardness value. 0 means the transition is hard, 100 means the transition area is maximal(soft). | -| [REGION:tablesection]Inputs[/REGION] || -| **A** | Takes in the value representing the position of the point to check. | -| **B** | Takes in the value representing the center of the sphere. | - -[REGION:fullwidth] -![SphereMaskExample.png](SphereMaskExample.png) -[/REGION] - -In this example, the preview object will smoothly fade to black as the camera exceeds 256 units away from it. +## A - H [EXCERPT:AntialiasedTextureMask] - - -## AntialiasedTextureMask +### AntialiasedTextureMask The **AntialiasedTextureMask** expression allows you to create a material using a soft (anti-aliased) transition mask. The mask can be used to blend between two complex material properties or to fade out an alpha blended material (works well with SoftMasked). Simply specify a texture with the mask specified in one channel (red, green, blue, or alpha), set the used channel in the expression and specify the comparison value. Assuming the channel stores a grayscale value in the range 0=black to 1=white the comparison function defines if the resulting mask should be 0 or 1. This expression is a parameter, allowing the **Texture** property to be overridden by child MaterialInstances. @@ -343,32 +58,189 @@ The technique works best in magnification and with blurred input content. Compre [/EXCERPT:AntialiasedTextureMask] -## DistanceToNearestSurface -The **Distance To Nearest Surface** Material Expression node allows Materials to sample any point in the levels Global Distance Field. -This Material Expression works by outputting the signed distance in world space units from the distance field to the nearest occluders in the scene. + + + +### BlackBody + +The **BlackBody** expression simulates the effects of [black body radiation](http://en.wikipedia.org/wiki/Black-body_radiation) within your Material. The user inputs a temperature (in Kelvin) and the resulting color and intensity can be used to drive Base Color and Emissive values to get a physically accurate result. + +[REGION:fullwidth] +![](BlackBody.png) +[/REGION] + + + + +### BumpOffset + +[EXCERPT:BumpOffset] +**BumpOffset** is the Unreal Engine 4 term for what is commonly known as 'Parallax Mapping'. The Bump Offset expression allows a material to give the illusion of depth without the need for additional geometry. BumpOffset materials use a grayscale _heightmap_ to give depth information. The brighter the value in the heightmap, the more 'popped out' the material will be; these areas will parallax (shift) as a camera moves across the surface. Darker areas in the heightmap are 'further away' and will shift the least. +[/EXCERPT:BumpOffset] -[region:note] -**Generate Mesh Distance Fields** must be enabled in **Project Settings** under **Rendering** for this expression to work correctly. -[/region] | Item | Description | | -------- | ----------- | -| **Position** | Defaults to current World Position if nothing is input. | +| [REGION:tablesection]Properties[/REGION] || +| **HeightRatio** | Multiplier for the depth taken from the _heightmap_. The larger the value, the more extreme the depth will be. Typical values range from 0.02 to 0.1. | +| **ReferencePlane** | Specifies the approximate height in texture space to apply the effect. A value of 0 will appear to distort the texture completely off the surface, whereas a value of 0.5 (the default) means that some of the surface will pop off while some areas will be sunken in. | +| [REGION:tablesection]Inputs[/REGION] || +| **Coordinate** | Takes in base texture coordinates to be modified by the expression. | +| **Height** | Takes in the texture (or a value) to be used as the heightmap. | +| **HeightRatioInput** | Multiplier for the depth taken from the _heightmap_. The larger the value, the more extreme the depth will be. Typical values range from 0.02 to 0.1. If used, this input supersedes any value in the Height Ratio property. | -Here is an example of the **Distance To Nearest Surface** Material Expression in action. +[REGION:fullwidth] +![BumpOffsetExample.png](BumpOffsetExample.png) +[/REGION] -[Region:lightbox] -[![](DistanceNearSurface_01.png)(w:960)](DistanceNearSurface_01.png) -[/Region] + -![](DistanceNearSurface_02.png)(w:550) -In this example the Distance To Nearest Surface was fed into the Opacity input on a Material and that Material was applied to a Static Mesh plane that was placed just above the levels floor. -What the Distance To Nearest Surface is doing is telling the Material to only color areas red were the Static Meshes plane will start to intersect other Static Meshes placed in the scene. +### ConstantBiasScale -## DistanceFieldGradient +The **ConstantBiasScale** expression takes an input value, adds a bias value to it, and then multiplies it by a scaling factor outputting the result. So for example, to convert input data from [-1,1] to [0,1] you would use a bias of 1.0 and a scale of 0.5. + +| Item | Description | +| -------- | ----------- | +| [REGION:tablesection]Properties[/REGION] || +| **Bias** | Specifies the value to be added to the input. | +| **Scale** | Specifies the multiplier for the biased result. | + + +![ConstantBiasScaleExample.png](ConstantBiasScaleExample.png) + + + + + +### DDX + +The **DDX** expression exposes DDX derivative calculation, a GPU hardware feature used in pixel shader calculation. + + + + + +### DDY + +The **DDY** expression exposes DDX derivative calculation, a GPU hardware feature used in pixel shader calculation. + + + + + +### DepthFade + +The **DepthFade** expression is used to hide unsightly seams that take place when translucent objects intersect with opaque ones. + +| Item | Description | +| -------- | ----------- | +| [REGION:tablesection]Properties[/REGION] || +| **Fade Distance** | World space distance over which the fade should take place. This is used if the FadeDistance input is unconnected. | +| [REGION:tablesection]Inputs[/REGION] || +| **Opacity** | Takes in the existing opacity for the object prior to the depth fade. | +| **FadeDistance** | World space distance over which the fade should take place. | + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Before Depth Fade](Engine\Rendering\Materials\ExpressionReference\Depth\DepthFade0.png)(w:340) + [/PARAM] + [PARAM:after] + ![After Depth Fade](Engine\Rendering\Materials\ExpressionReference\Depth\DepthFade1.png)(w:340) + [/PARAM] +[/OBJECT] + +[REGION:lightbox] +[![](Engine\Rendering\Materials\ExpressionReference\Depth\DepthFadeNetwork.png)(h:340)](Engine\Rendering\Materials\ExpressionReference\Depth\DepthFadeNetwork.png) +[/REGION] +[REGION:caption] +Click image for full size view. +[/REGION] + + + + + +### DepthOfFieldFunction + +The **Depth of Field Function** expression is designed to give artists control over what happens to a Material when it is being blurred by Depth of Field. It outputs a value between 0-1 such that 0 represents "in focus" and 1 represents "completely blurred." This is useful for interpolating between sharp and blurry versions of a texture, for instance. The Depth input allows for the existing results from the scene's Depth of Field calculations to be overridden by other calculations. + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Blended Colors](DepthOfFieldFunction_Color.png)(w:350) + [/PARAM] + [PARAM:after] + ![Blending regular and blurred textures](DepthOfFieldFunction_Texture.png)(w:350) + [/PARAM] +[/OBJECT] + +[REGION:lightbox] +[![](DepthOfFieldFunctionNetwork.png)(w:350)](DepthOfFieldFunctionNetwork.png) +[/REGION] +[REGION:caption] +Click image for full size view. +[/REGION] + + + + + +[EXCERPT:Desaturation] +### Desaturation + +The **Desaturation** expression desaturates its input, or converts the colors of its input into shades of gray, based a certain percentage. + +| Item | Description | +| -------- | ----------- | +| [REGION:tablesection]Properties[/REGION] || +| **Luminance Factors** | Specifies the amount that each channel contributes to the desaturated color. This is what controls that green is brighter than red which is brighter than blue when desaturated. | +| [REGION:tablesection]Inputs[/REGION] || +| **Fraction** | Specifies the amount of desaturation to apply to the input. Percent can range from 0.0 (fully desaturated) to 1.0 (full original color, no desaturation). | + + +![DesaturationExample.png](DesaturationExample.png) + +[REGION:note] +**Programmers:** Define desaturated color `D`, input color `I` and luminance factor `L`. The output will be `O = (1-Percent)*(D.dot(I)) + Percent*I` +[/REGION] +[/EXCERPT:Desaturation] + + + + + +[EXCERPT:Distance] +### Distance + +The **Distance** expression computes the (Euclidian) distance between two points/colors/positions/vectors and outputs the resulting value. This works on one, two, three and four component vectors, but both inputs to the expression must have the same number of channels. + +| Item | Description | +| -------- | ----------- | +| [REGION:tablesection]Inputs[/REGION] || +| **A** | Takes in a value or vector of any length. | +| **B** | Takes in a value or vector of any length. | + +[REGION:fullwidth] +![DistanceExample.png](DistanceExample.png) +[/REGION] + +**Pseudo code:** + + Result = length(A - B) + +**Low level HLSL code:** + + float Result = sqrt(dot(A-B, A-B)) + +[/EXCERPT:Distance] + + + + + +### DistanceFieldGradient The **DistanceFieldGradient** Material Expression node, when normalized, outputs the X,Y,Z direction an object would move with in the distance field. This makes the Distance Field Gradient Material Expression node well-suited for Materials that need to simulate the flow of liquids. @@ -389,6 +261,9 @@ The Mask Channel Parameter was added to allow for easier RGB channel switching w [Region:lightbox] [![](DistanceFieldGradient_Material.png)](DistanceFieldGradient_Material.png) [/Region] +[REGION:caption] +Click image for full size view. +[/REGION] Here is an example of the DistanceFieldGradient in action. The image below shows what data the DistanceFieldGradient will use when the various RGB are enabled. @@ -396,6 +271,9 @@ The image below shows what data the DistanceFieldGradient will use when the vari [Region:lightbox] [![](DistanceFieldGradient_Example.png)(w:960)](DistanceFieldGradient_Example.png) [/Region] +[REGION:caption] +Click image for full size view. +[/REGION] +### DistanceToNearestSurface + +The **Distance To Nearest Surface** Material Expression node allows Materials to sample any point in the levels Global Distance Field. +This Material Expression works by outputting the signed distance in world space units from the distance field to the nearest occluders in the scene. + +[region:note] +**Generate Mesh Distance Fields** must be enabled in **Project Settings** under **Rendering** for this expression to work correctly. +[/region] + +| Item | Description | +| -------- | ----------- | +| **Position** | Defaults to current World Position if nothing is input. | + +Here is an example of the **Distance To Nearest Surface** Material Expression in action. + + +[Region:lightbox] +[![](DistanceNearSurface_01.png)(w:960)](DistanceNearSurface_01.png) +[/Region] +[REGION:caption] +Click image for full size view. +[/REGION] + +![](DistanceNearSurface_02.png)(w:550) + +In this example the Distance To Nearest Surface was fed into the Opacity input on a Material and that Material was applied to a Static Mesh plane that was placed just above the levels floor. +What the Distance To Nearest Surface is doing is telling the Material to only color areas red were the Static Meshes plane will start to intersect other Static Meshes placed in the scene. + + + + + +[EXCERPT:FeatureLevelSwitch] +### FeatureLevelSwitch + +The **Feature Level Switch** node allows you to make simplified materials for lower powered devices. + +**Example Usage**: You might have a material with 10 textures overlapping and complex math, but just a single static texture for mobile (feature level ES2). + +| Item | Description | +| -------- | ----------- | +| [REGION:tablesection]Inputs[/REGION] || +| **Default** | The default Feature Level. | +| **ES2** | Feature Level defined by the core capabilities of OpenGL ES2. | +| **ES3.1** | Feature Level defined by the capabilities of Metal-level devices. | +| **SM4** | Feature Level defined by the core capabilities of DX10 Shader Model 4. | +| **SM5** | Feature Level defined by the core capabilities of DX11 Shader Model 5. | + +[/EXCERPT:FeatureLevelSwitch] + + + + + +### Fresnel + +The **Fresnel** expression calculates a falloff based on the dot product of the surface normal and the direction to the camera. When the surface normal points directly at the camera, a value of 0 is output. When the surface normal is perpendicular to the camera, a value of 1 is output. The result is clamped to [0,1] so you do not have any negative color in the center. + +| Item | Description | +| -------- | ----------- | +| [REGION:tablesection]Properties[/REGION] || +| **Exponent** | Specifies the how quickly the output value falls off. Larger values mean tighter or quicker falloff. | +| **Base Reflect Fraction** | Specifies the fraction of specular reflection the surface is viewed from straight on. A value of 1 effectively disables the Fresnel effect. | +| [REGION:tablesection]Inputs[/REGION] || +| **ExponentIn** | Specifies the how quickly the output value falls off. Larger values mean tighter or quicker falloff. If used, value will always supersede the Exponent property value. | +| **Base Reflect Fraction** | Specifies the fraction of specular reflection the surface is viewed from straight on. A value of 1 effectively disables the Fresnel effect. If used, value will always supersede the Exponent property value. | +| **Normal** | Takes in a three-channel vector value representing the normal of the surface, in world space. To see the results of a normal map applied to the surface of the Fresnel object, connect the normal map to the Normal input of the material, then connect a (PixelNormalWS)[Engine/Rendering/Materials/ExpressionReference/Vector#PixelNormalWS] expression to this input on the Fresnel. If no normal is specified, the tangent normal of the mesh is used. | + + +![FresnelExample.png](FresnelExample.png) + + + + + +[EXCERPT:GIReplace] +### GIReplace + +**GIReplace** allows artists to specify a different, usually simpler, expression chain when the material is being used for GI. + +**Example Usage**: Lightmass static GI and LPV dynamic GI use it. + +| Item | Description | +| -------- | ----------- | +| [REGION:tablesection]Inputs[/REGION] || +| **Default** | The default GI. | +| **StaticIndirect** | Used for baked indirect lighting. | +| **DynamicIndirect** | Used for dynamic indirect lighting. | + +[INCLUDE:Engine\Rendering\LightingAndShadows\LightPropagationVolumes#gireplaceexample] + + +[/EXCERPT:GIReplace] + + + + + +## I - P + + + + + +### LightmassReplace + +The **LightmassReplace** expression simply passes through the Realtime input when compiling the material for normal rendering purposes, and passes through the Lightmass input when exporting the material to Lightmass for global illumination. This is useful to work around material expressions that the exported version cannot handle correctly, for example WorldPosition. + +| Item | Description | +| -------- | ----------- | +| [REGION:tablesection]Inputs[/REGION] || +| **Realtime** | Takes in the value(s) to pass through for normal rendering. | +| **Lightmass** | Takes in the value(s) to pass through when exporting the material to Lightmass. | + + + + + +[EXCERPT:LinearInterpolate] +### LinearInterpolate + +The **LinearInterpolate** expression blends between two input value(s) based on a third input value used as a mask. This can be thought of as a mask to define transitions between two textures, like a layer mask in Photoshop. The intensity of the mask Alpha determines the ratio of color to take from the two input values. If Alpha is 0.0/black, the first input is used. If Alpha is 1.0/white, the second input is used. If Alpha is grey (somewhere between 0.0 and 1.0), the output is a blend between the two inputs. Keep in mind that the blend happens per channel. So, if Alpha is an RGB color, Alpha's red channel value defines the blend between A and B's red channels **independently** of Alpha's green channel, which defines the blend between A and B's green channels. + +| Item | Description | +| -------- | ----------- | +| [REGION:tablesection]Properties[/REGION] || +| **Const A** | The value mapped to black (0.0). Only used if the A input is unconnected. | +| **Const B** | The value mapped to white (1.0). Only used if the B input is unconnected. | +| **Const Alpha** | Takes in the value to use as the mask alpha. Only used if the Alpha input is unconnected. | +| [REGION:tablesection]Inputs[/REGION] || +| **A** | Takes in the value(s) mapped to black (0.0). | +| **B** | Takes in the value(s) mapped to white (1.0). | +| **Alpha** | Takes in the value to use as the mask alpha. | + + +**Programmers:** LinearInterpolate does a per-channel lerp between A and B based on the parametric value Alpha. + +![LerpExample.png](LerpExample.png)(w:900) +[/EXCERPT:LinearInterpolate] + + + + + +### Noise + +The **Noise** expression creates a procedural noise field, giving you control over how it is generated. + +| Item | Description | +| -------- | ----------- | +| [REGION:tablesection]Properties[/REGION] || +| **Scale** | Changes the overall size of the noise cells. Lower numbers make the noise bigger. | +| **Quality** | A look/performance setting. Lower values are faster but may look worse, higher values are slower but may look better. | +| **Function** | [INCLUDE:#NoiseFunctions] | +| **Turbulence** | Whether to use an absolute value when combining noise levels, results in a veined or billowy look. | +| **Levels** | How many different levels of noise at different scales to combine, multiplies the computational cost by the number of levels. | +| **Output Min** | The lowest value output by the noise calculation. | +| **Output Max** | The highest value output by the noise calculation. | +| **Level Scale** | Controls the scale of individual levels when using multiple levels of noise. This defaults to 2 so each level is twice the frequency at half the magnitude. | +| **Tiling** | For noise functions that support it, allows noise to tile. This is more expensive, but useful when baking noise into a seamless wrapping texture. | +| **Repeat Size** | When tiling, how often should the noise repeat. | +|| [REGION:tablesection]Inputs[/REGION] || +| **Position** | Allows the texture size to be adjusted via a 3D vector. | +| **FilterWidth** | In effect, controls how much blur will be applied to the noise texture. | + +![NoiseExample.png](NoiseExample.png) + + + + + +### Previous Frame Switch + +The **Previous Frame Switch** Material Expression enables you to support complex [vertex animations](Engine/Animation/Tools/VertexAnimationTool/) implemented in your materials to generate correct motion vectors so that they can work correctly with Temporal AA and Motion Blur. + +Materials that are only a function of time already work without modification, however, they cannot account for other variables, such as Material Parameters, that can affect the animation. The Previous Frame Switch Material Expression enables Artists to solve these types of problem manually by tracking how these parameters change, for instance, in Blueprints, where they can manually provide expressions for motion vector generation that is caused by changes in World Position Offset between frames. + +[REGION:note] +**Accurate Velocities from Vertex Deformations** must be enabled in the **Project Settings** under **Rendering** for this expression to work correctly. +[/REGION] + +| Item | Description | +| -------- | ----------- | +| Current Frame | Directional Vector used as the starting position reference. | +| Previous Frame | Directional Vector used as the XYZ reference for the amount of blur to add. | + +Here is an example using **Previous Frame Switch** Material Expression in a Material. + +![](PreviousFrameSwitch.png)(w:900) + +In this example, the Previous Frame Switch is using a constant value to control the directional blur through a Multiply node. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + YbjqiNZr4K4 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 50 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +In this example, you can see how this is being used in Epic's own games, like Fortnite, to control the motion blur with a Vertex Animation that assembles on screen. +The animation on the right is using Previous Frame Switch to add some motion blur, while the animation on the left is not. + + + + + +## Q - Z + + + + + +### QualitySwitch + +The **QualitySwitch** expression allows for the use of different expression networks based on the engine is switched between quality levels, such as using lower quality on lower-end devices. + +| Item | Description | +| -------- | ----------- | +| [REGION:tablesection]Inputs[/REGION] || +| Default | This input is used for networks designed for default visual quality. | +| Low | This input is used for networks designed for lower visual quality. | +| High | This input is used for networks designed for higher visual quality. | + + + + + +[EXCERPT:RotateAboutAxis] +### RotateAboutAxis + +The **RotateAboutAxis** expression rotates a three-channel vector input given the rotation axis, a point on the axis, and the angle to rotate. It is useful for animations using WorldPositionOffset that have better quality than simple shears. + +| Item | Description | +| -------- | ----------- | +| [REGION:tablesection]Inputs[/REGION] || +| **NormalizedRotationAxis** | Takes in a normalized (0-1) vector which represents the axis about which the object will rotate. | +| **RotationAngle** | The angle of rotation. A value of 1 equals a full 360-degree rotation. +| **PivotPoint** | Takes in the three-channel vector representing the pivot point about which the object will rotate. | +| **Position** | Takes in the three-channel vector representing the position of the object. When the RotateAboutAxis expression is created, a WorldPosition expression is automatically created and connected to this input. | + +[REGION:fullwidth] +![RotateAboutAxisExample.png](RotateAboutAxisExample.png) +[/REGION] + +In the above example, the preview plane would appear to spin on its vertical axis. + +[/EXCERPT:RotateAboutAxis] + + + + + +### SphereMask + +The **SphereMask** expression outputs a mask value based on a distance calculation. If one input is the position of a point and the other input is the center of a sphere with some radius, the mask value is 0 outside and 1 inside with some transition area. This works on one, two, three, and four component vectors + +| Item | Description | +| -------- | ----------- | +| [REGION:tablesection]Properties[/REGION] || +| **Attenuation Radius** | Specifies the radius to use for the distance calculation. | +| **Hardness Percent** | Specifies the transition area size. This works like the Photoshop brush hardness value. 0 means the transition is hard, 100 means the transition area is maximal(soft). | +| [REGION:tablesection]Inputs[/REGION] || +| **A** | Takes in the value representing the position of the point to check. | +| **B** | Takes in the value representing the center of the sphere. | + +[REGION:fullwidth] +![SphereMaskExample.png](SphereMaskExample.png) +[/REGION] +[REGION:caption] In this example, the preview object will smoothly fade to black as the camera exceeds 256 units away from it. [/REGION] + + + + + +### Vector Noise + +[INCLUDE:Engine\Rendering\Materials\ExpressionReference\Vector#VectorNoiseTest] + + - ## Object Bounds The **Object Bounds** expression outputs the size of the object in each axis. If used as color, the X, Y, and Z axes correspond to R, G, and B, respectively. @@ -116,6 +131,78 @@ In this example, PixelNormalWS is fed into Base Color. Notice how the normal map [/EXCERPT:PixelNormalWS] + + +## Pre-Skinned Local Normal + +The **Pre-Skinned Local Normals** Vector Expression outputs a three-channel vector value representing the local surface normal for Skeletal and Static Meshes. This enables you to achieve locally-aligned tri-planar +materials and mesh aligned effects in your materials. + +In this example, the material is using a tri-planar texture aligned to the mesh's local surface normal. + +[REGION:lightbox] +[![](PreSkinnedTriPlanarSetup.png)(w:700)](PreSkinnedTriPlanarSetup.png) +[/REGION] +[REGION:caption] +_Click image for larger size._ +[/REGION] + +[REGION:imagetable] +| [INCLUDE:#LocalNormal1] | [INCLUDE:#LocalNormal2] | +| --- | --- | +| Tri-Planar Pre-Skinned Local Normal Vector Expression | Tri-Planar Material | +[/REGION] + + + +## Pre-Skinned Local Position + +The **Pre-Skinned Local Position** Vector Expression outputs a three-channel vector value that gives access to a Skeletal Mesh’s default pose position data for use in +per-vertex outputs. This enables you to have localized effects on an animated character. This vector expression can also be used with Static Meshes, which will return +the standard local position. + +[REGION:lightbox] +[![](PreSkinnedLocalPos.png)(w:500)](PreSkinnedLocalPos.png) +[/REGION] +[REGION:caption] +_Click image for larger size._ +[/REGION] + +In this example, the Skeletal Mesh's default pose is used for mapping versus the default UV mapping on the right. + +[REGION:imagetable] +| [INCLUDE:#LocalPos1] | [INCLUDE:#LocalPos2] | +| --- | --- | +| Pre-Skinned Local Position Vector Expression | Skeletal Mesh's Default UV Layout | +[/REGION] + + + + ## ReflectionVectorWS The **ReflectionVectorWS** expression is similar in spirit to [CameraVectorWS](#CameraVectorWS), but it outputs a three-channel vector value representing the camera direction reflected across the surface normal. @@ -146,15 +233,15 @@ In the example above, the preview sphere would seem to scale up and down with si [EXCERPT:VectorNoiseTest] ![](Vector_Noise_Example.png) -The Vector Noise Material expression adds several more 3D or 4D vector noise results to use in your Materials. Due to the run-time expense of these functions, it is recommended that once a look is developed with them, all or part of the computation be baked into a Texture using the [Draw Material to Render Target Blueprint](Engine\Rendering\RenderTargets\BlueprintRenderTargets) feature introduced in Unreal Engine 4.13 and later. These Material graph Expressions allow procedural looks to be developed in engine on final assets, providing an alternative to creating procedurally generated Textures with an external tool to apply to assets in UE4. Inside of the Vector Noise Material Expression, you will find the following Vector Noise types. +The Vector Noise Material expression adds several more 3D or 4D vector noise results to use in your Materials. Due to the run-time expense of these functions, it is recommended that once a look is developed with them, all or part of the computation be baked into a Texture using the [Draw Material to Render Target Blueprint](Engine\Rendering\RenderTargets\BlueprintRenderTargets) feature introduced in Unreal Engine 4.13 and later. These Material graph Expressions allow procedural looks to be developed in the engine on final assets, providing an alternative to creating procedurally generated Textures with an external tool to apply to assets in UE4. Inside of the Vector Noise Material Expression, you will find the following Vector Noise types. |Image|Item|Description| |-----|--------|---------------| -|![](Cellnoise.png)(w:128)|Cellnoise|Returns a random color for each cell in a 3D grid (i.e. from the mathematical floor operation applied to the node input). The results are always consistent for a given position, so can provide a reliable way to add randomness to a Material. This Vector Noise function is extremely cheap to compute, so it is not necessary to bake it into a Texture for performance.| -|![](VectorNoise.png)(w:128)|Perlin 3D Noise|Returns a random color for each cell in a 3D grid (i.e. from the mathematical floor operation applied to the node input). The results are always consistent for a given position, so can provide a reliable way to add randomness to a Material. This Vector Noise function is extremely cheap to compute, so it is not necessary to bake it into a Texture for performance.| -|![](GradientNoise.png)(w:128)|Perlin Gradient|Computes the analytical 3D gradient of a scalar Perlin Simplex Noise. The output is four channels, where the first three (RGB) are the gradient, and the fourth (A) is the scalar noise. This noise type is useful for bumps on a surface or for flow maps.| -|![](CurlNoise.png)(w:128)|Perlin Gradient|Computes the analytical 3D curl of a vector Perlin Simplex Noise (aka Curl Noise). The output is a 3D signed curl vector and is useful for fluid or particle flow.| -|![](VoronoiNoise.png)(w:128)|Voronoi|Computes the same Voronoi noise as the scalar Noise material node. The scalar Voronoi noise scatters seed points in 3D space and returns the distance to the closest one. The Vector Noise version returns the location of the closest seed point in RGB, and the distance to it in A. Especially coupled with Cellnoise, this can allow some randomized behavior per Voronoi cell.| +|![](Cellnoise.png)(w:128)|**Cellnoise** | Returns a random color for each cell in a 3D grid (i.e. from the mathematical floor operation applied to the node input). The results are always consistent for a given position, so can provide a reliable way to add randomness to a Material. This Vector Noise function is extremely cheap to compute, so it is not necessary to bake it into a Texture for performance.| +|![](VectorNoise.png)(w:128)|**Perlin 3D Noise** | Returns a random color for each cell in a 3D grid (i.e. from the mathematical floor operation applied to the node input). The results are always consistent for a given position, so can provide a reliable way to add randomness to a Material. This Vector Noise function is extremely cheap to compute, so it is not necessary to bake it into a Texture for performance.| +|![](GradientNoise.png)(w:128)|**Perlin Gradient** | Computes the analytical 3D gradient of a scalar Perlin Simplex Noise. The output is four channels, where the first three (RGB) are the gradient, and the fourth (A) is the scalar noise. This noise type is useful for bumps on a surface or for flow maps.| +|![](CurlNoise.png)(w:128)|**Perlin Gradient** | Computes the analytical 3D curl of a vector Perlin Simplex Noise (aka Curl Noise). The output is a 3D signed curl vector and is useful for fluid or particle flow.| +|![](VoronoiNoise.png)(w:128)|**Voronoi** | Computes the same Voronoi noise as the scalar Noise material node. The scalar Voronoi noise scatters seed points in 3D space and returns the distance to the closest one. The Vector Noise version returns the location of the closest seed point in RGB, and the distance to it in A. Especially coupled with Cellnoise, this can allow some randomized behavior per Voronoi cell.| Below is a simple stone bed material using the distance component of the Vector Noise / Voronoi to modulate some surface bumps and blend in moss in the cracks, and the seed position together with Vector Noise / Cellnoise to change the color and bump height per rock. @@ -164,23 +251,23 @@ The derivative-based operations Perlin Curl and Perlin Gradient can be added tog |Item|Description| |-----|-----------| -|Prepare3DDeriv|Uses positions offset in a tetrahedral pattern to compute 3D derivatives. Evaluate the same 3D function at each offset position produced by this function, then feed the resulting values into Compute3DDeriv.| -|Compute3DDeriv|Uses positions offset in a tetrahedral pattern to compute 3D derivatives. Use with Prepare3DDeriv.| -|GradFrom3DDeriv|Computes 3D gradient vector from result of Prepare3DDeriv/Compute3DDeriv.| -|CurlFrom3DDeriv|Computes curl of at 3D vector field from result of Prepare3DDeriv/Compute3DDeriv.| +| **Prepare3DDeriv** | Uses positions offset in a tetrahedral pattern to compute 3D derivatives. Evaluate the same 3D function at each offset position produced by this function, then feed the resulting values into Compute3DDeriv.| +| **Compute3DDeriv** | Uses positions offset in a tetrahedral pattern to compute 3D derivatives. Use with Prepare3DDeriv.| +| **GradFrom3DDeriv** | Computes 3D gradient vector from result of Prepare3DDeriv/Compute3DDeriv.| +| **CurlFrom3DDeriv** | Computes curl of a 3D vector field from result of Prepare3DDeriv/Compute3DDeriv.| [region:note] These helper Material Functions use four evaluations of the base expression spaced in a tetrahedral pattern to approximate these derivative-based operations. [/region] -Below you will find descriptions for the various noise functions you will find in the Vector Noise Material Expression. +Below you will find descriptions of the various noise functions you will find in the Vector Noise Material Expression. | Item | Description | | -------- | ----------- | | [REGION:tablesection]Properties[/REGION] || | **Function** | [INCLUDE:#VectorNoiseFunctions] | | **Quality** | A look/performance setting. Lower values are faster but may look worse, higher values are slower but may look better. | -| **Tiling** | For noise functions that support it, allows noise to tile. This is more expensive, but useful when baking noise into a seamless wrapping texture. | +| **Tiling** | For noise functions that support it this allows noise to tile. This is more expensive, but useful when baking noise into a seamless wrapping texture. | | **Tile Size** | When tiling, how often should the noise repeat. For Perlin noise variants, the Tile Size must be a multiple of three. | || [REGION:tablesection]Inputs[/REGION] || | **Position** | Allows the texture size to be adjusted via a 3D vector. | @@ -219,21 +306,10 @@ Below you will find descriptions for the various noise functions you will find i |Function| Description| |---------|-----------| -| Cellnoise | Random color for each integer grid cell in 3D space. About 10 instructions. | -| Perlin 3D Noise | Computational Perlin noise with 3D output, each channel output ranges from -1 to 1. About 83 instructions if only the red channel is used, 125 instructions if all three channels are used| -| Perlin Gradient | Computes the gradient of a Perlin noise function. RGB output contains the gradient vector, A is the scalar noise. About 106 instructions. | -| Perlin Curl | Computes a 3D curl noise. Output is the mathematical curl of Perlin 3D Noise. About 162 instructions. | -| Voronoi | The same algorithm and instruction counts as the Voronoi function in the *Noise* expression, but RGB is the location of the closest seed point in each Voronoi cell, and A is the distance to that seed point. | +| **Cellnoise** | Random color for each integer grid cell in 3D space. About 10 instructions. | +| **Perlin 3D Noise** | Computational Perlin noise with 3D output, each channel output ranges from -1 to 1. About 83 instructions if only the red channel is used, 125 instructions if all three channels are used| +| **Perlin Gradient** | Computes the gradient of a Perlin noise function. RGB output contains the gradient vector, A is the scalar noise. About 106 instructions. | +| **Perlin Curl** | Computes a 3D curl noise. The output is the mathematical curl of Perlin 3D Noise. About 162 instructions. | +| **Voronoi** | The same algorithm and instruction counts as the Voronoi function in the *Noise* expression, but RGB is the location of the closest seed point in each Voronoi cell, and A is the distance to that seed point. | [/EXCERPT] --> - - - - - - - - - - - diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/ExpressionReference/Vector/VectorExpressions.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/ExpressionReference/Vector/VectorExpressions.JPN.udn index a7087728ae72..1eac6f43e306 100644 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/ExpressionReference/Vector/VectorExpressions.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/ExpressionReference/Vector/VectorExpressions.JPN.udn @@ -1,14 +1,31 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3474197 Availability:Public -Title:ベクター表現式 -Crumbs: %ROOT%, Engine, Engine/Rendering/Materials, Engine/Rendering/Materials/ExpressionReference +Crumbs: %ROOT% +Title:Vector 表現式 Description:位置や法線などのベクター値を出力する表現式 -Version:4.9 +Type:Reference +Version:4.16 +Parent:Engine/Rendering/Materials +reference-image:PreSkinnedTriPlanar.gif +reference-image:TriPlanarMaterial.gif +reference-image:PS_LocalPositionMaterial.gif +reference-image:PS_DefaultMaterial.gif +Order: +Tags:Materials +topic-image:VectorExpression_Topic.png + + [EXCERPT:TOC] [TOC(start:2)] [/EXCERPT:TOC] + +このページでは、RGBA にマップされたベクター値を出力する利用可能な Vector 表現式を紹介します。これらは、キャラクターが指定エリアに入った時にマテリアルがキャラクターの色に反応あるいは色を変形するためのワールド空間でのオブジェクトの位置の取得など、 +マテリアルの作成のための様々なエフェクトに使うことができます。空間のローカル スタイル マテリアル エフェクトを制御する表現式は +他にもあります。 + + [EXCERPT:ActorPositionWS] ## ActorPositionWS @@ -35,9 +52,9 @@ CameraWorldPosition 表現式は、ワールド空間のカメラ位置を表す ## CameraVectorWS -CameraVector 表現式はサーフェスに対するカメラ方向を表す 3 つのチャンネルのベクター値を出力します。つまり、ピクセルからカメラへの方向を表します。 +**CameraVector** 表現式は、サーフェスに対するカメラ方向、つまり、ピクセルからカメラへの方向を表す 3 つのチャンネルのベクター値を出力します。 -**使用例:** CameraVector は、CameraVector と ComponentMask を接続して環境マップの偽造や、テクスチャ座標として CameraVector の X、Y チャンネルを使用します。 +**使用例:** CameraVector は多くの場合、CameraVector を ComponentMask に接続して疑似的な環境マップに使用し、テクスチャ座標として CameraVector のX チャンネルと Y チャンネルを使用します。 [REGION:fullwidth] ![CameraVectorWSExample.png](CameraVectorWSExample.png) @@ -55,12 +72,12 @@ CameraVector 表現式はサーフェスに対するカメラ方向を表す 3 ## LightVector [REGION:warning] -**ライティング計算は現在保留となっているため、この表現式はアンリアル・エンジン 4 で将来的にサポートの保証がありません。** +ライティングの演算はディファードで行われるため、この表現式は非推奨です。 [/REGION:warning] - ## Object Bounds **Object Bounds** 表現式は、各軸のオブジェクトのサイズを出力します。カラーとして使用すると、X 軸、Y 軸、および Z 軸はそれぞれ R、G、および B に対応します。 @@ -83,7 +99,7 @@ LightVector 表現式はサーフェスに対するライト方向を表す 3 ## ObjectOrientation -**ObjectOrientation** 表現式は、オブジェクトのワールド空間の Up ベクターを出力します。言い換えると、オブジェクトのローカルの正の z 軸はこの方向を指しています。 +**ObjectOrientation** 表現式は、オブジェクトのワールド空間の Up ベクターを出力します。言い換えると、オブジェクトのローカルの正の z 軸はこの方向を向いています。 ![ObjectOrientationExample.png](ObjectOrientationExample.png) [/EXCERPT:ObjectOrientation] @@ -93,7 +109,7 @@ LightVector 表現式はサーフェスに対するライト方向を表す 3 ## ObjectPositionWS -**ObjectPositionWS** 表現式は、オブジェクト範囲のワールド空間の中心位置を出力します。フォーリッジに球状のライティングを作成するなどの場合に便利です。 +**ObjectPositionWS** 表現式は、オブジェクト範囲のワールド空間の中心位置を出力します。例えば、フォリッジに球状のライティングを作成する際に便利です。 ![](WorldPositionWSScene.png)(w:450) ![](WorldPositionNetwork.png)(h:349) @@ -107,7 +123,7 @@ LightVector 表現式はサーフェスに対するライト方向を表す 3 [EXCERPT:PixelNormalWS] ## PixelNormalWS -**PixelNormalWS** 表現式は、現在の法線をベースに対面しているピクセルの方向を表すベクターデータを出力します。 +**PixelNormalWS** 表現式は、現法線に基づきピクセルが向いている方向を表すベクターデータを出力します。 ![PixelNormalWSExample.png](PixelNormalWSExample.png) @@ -116,6 +132,78 @@ LightVector 表現式はサーフェスに対するライト方向を表す 3 [/EXCERPT:PixelNormalWS] + + +## Pre-Skinned Local Normal + +**Pre-Skinned Local Normals** ベクター表現式は、スケルタルおよびスタティックメッシュのローカル サーフェス法線を表現する 3 つのチャンネル ベクター値を出力します。これにより、ローカルで位置合わせした 3 面マテリアルを使って +スケルタルメッシュに自動 UV マッピングなどのエフェクトを適用できるようになりました。 + +この例では、マテリアルはメッシュのローカル サーフェス法線に合わせた 3 面テクスチャを使っています。 + +[REGION:lightbox] +[![](PreSkinnedTriPlanarSetup.png)(w:700)](PreSkinnedTriPlanarSetup.png) +[/REGION] +[REGION:caption] +_画像をクリックしてフルサイズで表示_ +[/REGION] + +[REGION:imagetable] +| [INCLUDE:#LocalNormal1] | [INCLUDE:#LocalNormal2] | +| --- | --- | +| Tri-Planar Pre-Skinned Local Normal Vector Expression | Tri-Planar Material | +[/REGION] + + + +## Pre-Skinned Local Position + +**Pre-Skinned Local Position** ベクター表現式は、頂点ごとの出力に使用するスケルタルメッシュのデフォルト ポーズ位置データにアクセスできるように、 +3 チャンネル ベクター値を出力します。これにより、アニメートしたキャラクター上で局所的なエフェクトが可能になります。スタティックメッシュと使用することも可能で、 +標準ローカル位置を返します。 + +[REGION:lightbox] +[![](PreSkinnedLocalPos.png)(w:500)](PreSkinnedLocalPos.png) +[/REGION] +[REGION:caption] +_画像をクリックしてフルサイズで表示_ +[/REGION] + +この例では、スケルタルメッシュのデフォルト ポーズが、マッピングおよびデフォルト UV マッピング (右) に使用されています。 + +[REGION:imagetable] +| [INCLUDE:#LocalPos1] | [INCLUDE:#LocalPos2] | +| --- | --- | +| Pre-Skinned Local Position Vector Expression | Skeletal Mesh's Default UV Layout | +[/REGION] + + + + ## ReflectionVectorWS **ReflectionVectorWS** 表現式は [CameraVectorWS](#CameraVectorWS) と類似した性質をもっていますが、サーフェス法線上に反射するカメラ方向を表す 3 つのチャンネルのベクター値を出力します。 @@ -141,3 +229,88 @@ LightVector 表現式はサーフェスに対するライト方向を表す 3 [/EXCERPT:VertexNormalWS] +## Vector Noise + +[EXCERPT:VectorNoiseTest] +![](Vector_Noise_Example.png) + +Vector Noise マテリアル表現式は、マテリアル内で使用する 3D あるいは 4D ベクター ノイズ結果をさらに追加します。これらの関数はランタイムに負荷がかかるため、外見が決定した後は 4.13 以降で導入された [Draw Material to Render Target Blueprint](Engine\Rendering\RenderTargets\BlueprintRenderTargets) 機能を使って計算のすべてまたは一部をテクスチャにベイクすることをお勧めします。こうしたマテリアル グラフ表現式を使うと、最終アセットでエンジン内でプロシージャルな見た目を決めることができます。外部ツールを使ってプロシージャルに生成したテクスチャを作成し、UE4 のアセットへ適用する代替方法になります。以下は、Vector Noise マテリアル表現式に含まれるタイプです。 + +|画像|アイテム|説明| +|-----|--------|---------------| +|![](Cellnoise.png)(w:128)|**Cellnoise** | 3D グリッドの各セルに対してランダムな色を戻します (すなわち、ノード入力に適用される数学的フロア演算から)。結果は常に任意の位置に対して一貫性があるため、高い信頼性でマテリアルにランダム性を加えることができます。この Vector Noise 関数の演算の負荷は非常に低いものです。そのため、パフォーマンス上の理由でテクスチャにベイクする必要はありません。| +|![](VectorNoise.png)(w:128)|**Perlin 3D Noise** | 3D グリッドの各セルに対してランダムな色を戻します (すなわち、ノード入力に適用される数学的フロア演算から)。結果は常に任意の位置に対して一貫性があるため、高い信頼性でマテリアルにランダム性を加えることができます。この Vector Noise 関数の演算の負荷は非常に低いものです。そのため、パフォーマンス上の理由でテクスチャにベイクする必要はありません。| +|![](GradientNoise.png)(w:128)|**Perlin Gradient** | スカラー Perlin Simplex Noise の解析的 3D 勾配を計算します。出力は 4 チャンネルです。この場合、最初から 3 つめ (RGB) までは勾配であり、4 つめが (A) スカラー ノイズになります。サーフェス上のバンプとフローマップに適しているノイズ タイプです。| +|![](CurlNoise.png)(w:128)|**Perlin Gradient** | ベクター Perlin Simplex Noise (いわゆる Curl Noise ) の解析的 3D カールを計算します。出力は 3D signed curl vector で、液体やパーティクルのフローに適しています。| +|![](VoronoiNoise.png)(w:128)|**Voronoi** | スカラー Noise マテリアルノードと同じ Voronoi ノイズを計算します。スカラー Voronoi ノイズは 3D 空間でシード ポイントを分散し、最も近いものからの距離を戻します。Vector Noise のバージョンは RGB で最も近いシード ポイントの位置を戻し、A でそれに対する距離を戻します。特に Cellnoise と併用すると、ボロノイのセル単位でビヘイビアを一部ランダム化することができます。| + +以下は、Vector Noise / Voronoi の距離コンポーネントを使って、サーフェスのバンプやクラックの苔のブレンドを調整したシンプルな地面の石のマテリアルです。シードの位置と Vector Noise / Cellnoise を合わせて石毎に色やバンプの高さを変えています。 + +![](Stone_Example.png) + +Perlin Curl と Perlin Gradient は微分係数ベースの演算なので、オクターブでまとめて追加することができます。より複雑な式の微分係数については、表現式の結果の勾配を計算する必要があります。これを行うには、計算する表現式をマテリアル関数に配置し、以下のヘルパー ノードと併用します。 + +|項目|説明| +|-----|-----------| +| **Prepare3DDeriv** | 四面体パターンの位置オフセットを使用して、3D 微分係数を計算します。この関数で生成されたそれぞれのオフセット位置で同じ 3D 関数を評価してから、結果値を Compute3DDeriv に渡します。| +| **Compute3DDeriv** | 四面体パターンの位置オフセットを使用して、3D 微分係数を計算します。Prepare3DDeriv と併用します。| +| **GradFrom3DDeriv** | Prepare3DDeriv/Compute3DDeriv の結果から 3D グラディエント ベクターを計算します。| +| **CurlFrom3DDeriv** | Prepare3DDeriv/Compute3DDeriv の結果から 3D ベクター フィールドのカールを計算します。| + +[region:note] +これらのヘルパー マテリアル関数は、四面体パターンに配置された式をベースにした 4 つの評価を用いて、微分係数ベースの演算を近似します。 +[/region] + +以下は、Vector Noise マテリアル式で使用される各種ノイズ関数と説明です。 + +| アイテム | 説明 | +| -------- | ----------- | +| [REGION:tablesection]プロパティ[/REGION] || +| **Function** | [INCLUDE:#VectorNoiseFunctions] | +| **Quality** | 外観、パフォーマンスを設定します。値が低いと処理は速くなりますが外観が悪くなります。値が高いと処理は遅くなりますが外観が良くなります。 | +| **Tiling** | ノイズのタイル処理を可能にします。負荷が高くなりますが、ノイズをシームレスにラップするテクスチャにベイクする場合に便利です。 | +| **Tile Size** | タイリング処理でのノイズ繰り返し数です。Perlin ノイズ変数の場合、Tile Size は 3 の乗数でなければなりません。 | +|| [REGION:tablesection]入力値[/REGION] || +| **Position** | 3D ベクターを介してテクスチャ サイズを調整できます。 | + +* **Cell Noise** マテリアル サンプル: + [REGION:lightbox] + [![](Engine\Rendering\Materials\ExpressionReference\Utility\Cellnoise.png)(w:504)](Engine\Rendering\Materials\ExpressionReference\Utility\Cellnoise.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +* **Perlin Gradient** マテリアル サンプル: + [REGION:lightbox] + [![](Engine\Rendering\Materials\ExpressionReference\Utility\PerlinGradient.png)(w:504)](Engine\Rendering\Materials\ExpressionReference\Utility\PerlinGradient.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +* **Voronoi** マテリアル サンプル: + [REGION:lightbox] + [![](Engine\Rendering\Materials\ExpressionReference\Utility\Voronoi.png)(w:504)](Engine\Rendering\Materials\ExpressionReference\Utility\Voronoi.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +[/EXCERPT:VectorNoiseTest] + + diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/ExpressionReference/VectorOps/VectorOpExpressions.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/ExpressionReference/VectorOps/VectorOpExpressions.JPN.udn index a7132d78a417..5fdfd601dae6 100644 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/ExpressionReference/VectorOps/VectorOpExpressions.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/ExpressionReference/VectorOps/VectorOpExpressions.JPN.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:2690274 +INTSourceChangelist:3354806 Availability:Public Title:Vector Operation 表現式 Crumbs: %ROOT%, Engine, Engine/Rendering/Materials, Engine/Rendering/Materials/ExpressionReference Description:ベクター入力値の演算を実行する表現式 Version:4.9 +tags:Materials [EXCERPT:TOC] [TOC(start:2)] @@ -12,16 +13,16 @@ Version:4.9 [EXCERPT:AppendVector] ## AppendVector -**AppendVector** 表現式は、オリジナルよりも多いチャンネルでベクターを作成するために、チャンネルの結合を有効にします。例えば、 2 つの個別の [Constants](Engine/Rendering/Materials/ExpressionReference/Constant#Constant) 値を受け取り、2チャンネルの [Constant2Vector](Engine/Rendering/Materials/ExpressionReference/Constant#Constant2Vector) 値を作成するためにこれらをアペンドします。単一テクスチャ内でチャンネルの再順序付けをしたり、複数のグレースケールテクスチャを 1 つの RGB カラーテクスチャに結合する際に実用的です。 +**AppendVector** 表現式は、チャンネルを結合して、オリジナルよりも多いチャンネルでベクターを作成することができます。例えば、 2 つの個別の [Constants](Engine/Rendering/Materials/ExpressionReference/Constant#Constant) 値を受け取り、2チャンネルの [Constant2Vector](Engine/Rendering/Materials/ExpressionReference/Constant#Constant2Vector) 値を作成するためにこれらをアペンドします。単一テクスチャ内でチャンネルの再順序付けをしたり、複数のグレースケール テクスチャを 1 つの RGB カラーテクスチャに結合する際に役立ちます。 | アイテム | 説明 | | -------- | ----------- | -| [REGION:tablesection]入力値[/REGION] || +| [REGION:tablesection]入力[/REGION] || | **A** | 追加する値を受け取ります。 | | **B** | 追加される値を受け取ります。 | -**例:** 0.2 と 0.4 のアペンドは、 (0.2、0.4) 、(0.2、0.4) と (1.6) のアペンドは (0.2、0.4、1.6) です。 +**例:** 0.2 と 0.4 のアペンドは、 (0.2、0.4) 、(0.2、0.4) と (1.0) のアペンドは (0.2、0.4) です。 ![AppendVectorExample.png](AppendVectorExample.png) @@ -31,7 +32,7 @@ Version:4.9 [EXCERPT:ComponentMask] ## ComponentMask -**ComponentMask** 表現式は、入力値から出力へ渡すためのチャンネル (R、G、B および / もしくは A) の特定サブセットの選択を有効にします。入力に存在しないチャンネルを通過する場合、入力値が単一の定数値でない限りエラーが生じます。その場合、単一値が各チャンネルを通過します。値が通過するチャンネルとして現在選択されたチャンネルは、表現式のタイトルバーに表示されます。 +**ComponentMask** 表現式は、入力値から出力へ渡すためのチャンネル (R、G、B および / もしくは A) の特定サブセットの選択を有効にします。入力に存在しないチャンネルを通過しようとすると、入力値が単一の定数値でない限りエラーが生じます。その場合、単一値が各チャンネルを通過します。値が通過するチャンネルとして現在選択されたチャンネルは、表現式のタイトルバーに表示されます。 | アイテム | 説明 | | -------- | ----------- | @@ -42,7 +43,7 @@ Version:4.9 | **A** | チェックされると、アルファ (4 番目の) チャンネルの入力値が出力へ渡されます。 | -**例:** ComponentMask ノードに (0.2、0.8、1.4) の値を入力し、 R と B チャンネルにチェックを入れた状態は、 (0.2、1.4) を出力します。 +**例:** ComponentMask に (0.2,0.4,1.0) を入力すると G チャンネルから (0.4) が出力されます。これをカラー ベクターで使うと 40% 明るいグレースケール値として表示されます。 [REGION:fullwidth] ![ComponentMaskExample.png](ComponentMaskExample.png) @@ -56,11 +57,11 @@ Version:4.9 ## DeriveNormalZ -**DeriveNormalZ** 表現式は、 X と Y コンポーネントが入力されてタンジェント空間法線の Z コンポーネントを派生し、結果として 3 チャンネルのタンジェント空間法線を出力します。Z は、「Z = sqrt(1 - (x * x + y * y))」として演算されます。 +**DeriveNormalZ** 表現式は、 X と Y コンポーネントが入力されてタンジェント空間法線の Z コンポーネントを派生し、結果として 3 チャンネルのタンジェント空間法線を出力します。Z は、「Z = sqrt(1 - (x \* x + y \* y));」として演算されます。 | アイテム | 説明 | | -------- | ----------- | -| [REGION:tablesection]入力値[/REGION] || +| [REGION:tablesection]入力[/REGION] || | **InXY** | 2 チャンネルベクター値の形式でタンジェント空間法線の X と Y コンポーネントを受け取ります。 | @@ -77,13 +78,13 @@ Version:4.9 **Transform** 表現式は、3 チャンネル ベクター値をある参照座標系から別の系に変換します。 -デフォルト設定で、マテリアルの全てのシェーダー計算はタンジェント空間で実行されます。ベクター定数、カメラベクター、ライトベクターなどは、マテリアルで使用される前に全てタンジェント空間へ変換されます。Transform 表現式は、これらのベクターをタンジェント空間からワールド空間、ローカル空間、またはビュー空間の座標系への変換を可能にします。また、ワールド空間とローカル空間ベクターをその他の参照座標系への変換も可能にします。 +デフォルト設定で、マテリアルの全てのシェーダー計算はタンジェント空間で実行されます。ベクター定数、カメラ ベクター、ライト ベクターなどは、マテリアルで使用される前に全てタンジェント空間へ変換されます。Transform 表現式は、これらのベクターをタンジェント空間からワールド空間、ローカル空間、またはビュー空間の座標系への変換を可能にします。また、ワールド空間ベクターとローカル空間ベクターを他の参照座標系への変換も可能にします。 | アイテム | 説明 | | -------- | ----------- | | [REGION:tablesection]プロパティ[/REGION] || -| **Source** | 変換するベクターのソースとなる現座標システムを指定します。以下のいずれかになります。ワールド、ローカル、またはタンジェント。 | -| **Destination** | 変換するベクターの送り先となる現座標システムを指定します。以下のいずれかになります。ワールド、ビュー、ローカル、またはタンジェント。 | +| **Source** | 変換するベクターのソースとなる現在の座標システムを指定します。ワールド、ローカル、またはタンジェントのいずれかになります。 | +| **Destination** | 変換するベクターの送り先となる現在の座標システムを指定します。ワールド、ビュー、ローカル、またはタンジェントのいずれかになります。 | Transform ノードは、ミラー化された UV を構成するため、例えば、キャラクターの右端のみに影響を及ぼすハイライトなどを有効にします。 @@ -124,5 +125,5 @@ Transform ノードは、キューブマップのサンプリングに使用す オリジンから離れたワールドポジションの派生に使用すると、主要な精密性に問題が発生するためこのノードは廃止される予定です。代わりに WorldPosition ノードを使用してください。 [/REGION] -**TransformPosition** 表現式は、スクリーン空間から式の TransformType 変数で指定された変換先へ、どんなポジションの変換も有効にします。現時点では、ワールド空間への変換のみをサポートしています。この表現式は、マテリアルのワールド空間座標の取得に使用します。ワールド空間を可視化するには、エミッシブへ直接接続します。 +**TransformPosition** 表現式は、スクリーン スペースから式の TransformType 変数で指定された変換先へ、どんなポジションの変換も有効にします。現時点では、ワールド空間への変換のみをサポートしています。この表現式は、マテリアルのワールド空間座標の取得に使用します。ワールド空間を可視化するには、エミッシブへ直接接続します。 diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/Functions/Reference/PivotPainter/PivotPainter.INT.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/Functions/Reference/PivotPainter/PivotPainter.INT.udn index 95cf42520be1..a445b6dfe806 100644 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/Functions/Reference/PivotPainter/PivotPainter.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/Functions/Reference/PivotPainter/PivotPainter.INT.udn @@ -1,9 +1,13 @@ Availability: Public -title:Pivot Painter +title:Pivot Painter Material Functions Crumbs: %ROOT%, Engine, Engine/Rendering/Materials, Engine/Rendering/Materials/Functions Description:Functions designed to allow utilization of the Pivot Painter MAXScript. Version: 4.9 +Parent:Engine/Rendering/Materials/Functions/Reference +Related:Engine/Content/Tools/PivotPainter +Topic-Image:PivotPainterMF_Topic.png tags:Materials +tags:Pivot Painter [TOC (start:2 end:3)] @@ -29,11 +33,13 @@ Although the data provided by Pivot Painter can be utilized without these functi ## Pivot Painter Functions -The following is a list of all the functions underneath the Pivot Painter category. +The following is a list of all the functions underneath the Pivot Painter category. + +These functions are used to process and organize world position and angle information stored in the model's UVs by the Pivot Painter MAXScript. ### PivotPainter_HierarchyData -Processes and organizes world position and angle information stored in the model's UVs by the Pivot Painter MAXScript. This particular function is specifically designed to work with object hierarchies. +This particular function is specifically designed to work with object hierarchies. | Item | Description | | -------- | -------- | @@ -59,7 +65,7 @@ Processes and organizes world position and angle information stored in the model ### PivotPainter_PerObjectData -Processes and organizes world position and angle information stored in the model's UVs by the Pivot Painter MAXScript. This particular function is designed to work on a per-object basis. +This particular function is designed to work on a per-object basis. | Item | Description | | -------- | -------- | @@ -75,7 +81,7 @@ Processes and organizes world position and angle information stored in the model ### PivotPainter_PerObjectFoliageData -Processes and organizes world position and angle information stored in the model's UVs by the Pivot Painter MAXScript. This function is designed to work specifically with individual foliage objects. +This function is designed to work specifically with individual foliage objects. | Item | Description | @@ -101,7 +107,7 @@ Processes and organizes world position and angle information stored in the model ### PivotPainter_TreeData -Processes and organizes world position and angle information stored in the model's UVs by the Pivot Painter script. The outputs starting with *tree* process the model's UV information as it would be stored by the Pivot Painter MAXScript. The outputs starting with *Leaf* process the UV information as it would be stored by the per-object pivot painting section of the script. +The outputs starting with *tree* process the model's UV information as it would be stored by the Pivot Painter MAXScript. The outputs starting with *Leaf* process the UV information as it would be stored by the per-object pivot painting section of the script. | Item | Description | | -------- | -------- | diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/Functions/Reference/PivotPainter/PivotPainter.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/Functions/Reference/PivotPainter/PivotPainter.JPN.udn index 8a83bb0271ab..3194a3b58557 100644 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/Functions/Reference/PivotPainter/PivotPainter.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/Functions/Reference/PivotPainter/PivotPainter.JPN.udn @@ -1,9 +1,14 @@ -INTSourceChangelist:2729971 +INTSourceChangelist:3471591 Availability:Public -title:Pivot Painter(軸ペインター) +title:Pivot Painter マテリアル関数 Crumbs: %ROOT%, Engine, Engine/Rendering/Materials, Engine/Rendering/Materials/Functions Description:Pivot Painter MAXScript を使うために作成された機能 Version:4.9 +Parent:Engine/Rendering/Materials/Functions/Reference +Related:Engine/Content/Tools/PivotPainter +Topic-Image:PivotPainterMF_Topic.png +tags:Materials +tags:Pivot Painter [TOC (start:2 end:3)] @@ -29,20 +34,22 @@ Pivot Painter が提供するデータは、これらの関数を使わなくて ## Pivot Painter 関数 -以下は Pivot Painter カテゴリに属する全関数のリストです。 +以下は Pivot Painter カテゴリに属する全関数のリストです。 + +これらの関数は、Pivot Painter MAXScript によりモデルの UV に格納されているワールド位置およびアングルに関する情報の処理と整理を行います。 ### PivotPainter_HierarchyData -Pivot Painter MAXScript によりモデルの UV に格納されているワールド位置と角度情報の処理と整理を行います。この特別な関数はオブジェクト階層と機能するように特別に作成されています。 +オブジェクト階層と機能する特殊な関数です。 | アイテム | 説明 | | -------- | -------- | | [REGION:tablesection]入力値[/REGION] || | **Max Dist for Parent Piv (Scalar)** | アセットのペイント中は MAXScript 「Max Dist for Parent Piv」のスピナーで使用された値と一致しなければなりません。 | |[REGION:tablesection]出力値[/REGION] || -| **Parent Piv Position** | ワールド空間における各親の回転軸情報を返します。子供は自分がアタッチされている親の回転軸情報を返します。 | +| **Parent Piv Position** | ワールド空間の親の回転軸情報を返します。子供は自分がアタッチされている親の回転軸情報を返します。 | | **Parent X Axis Vector** | 親の X 軸方向を向いている標準化されたベクターを返します。 | -| **Child Piv Position** | 各子供に対するワールド内での回転位置情報を返します。親は値 (0,0,0) を返します。| +| **Child Piv Position** | それぞれの子のワールド内での回転位置情報を返します。親は値 (0,0,0) を返します。| | **Child X-Axis Vector** | 親の回転軸方向を向いているノーマライズ化されたベクターを返します。| | **Object Pivot Point** | オブジェクトの回転軸の位置です。 | | **Object Orientation** | オブジェクトの方向です。 | @@ -59,7 +66,7 @@ Pivot Painter MAXScript によりモデルの UV に格納されているワー ### PivotPainter_PerObjectData -Pivot Painter MAXScript によりモデルの UV に格納されているワールド位置と角度情報の処理と整理を行います。この特別な関数はオブジェクト別に機能するように特別に作成されています。 +オブジェクト別に機能する特殊な関数です。 | アイテム | 説明 | | -------- | -------- | @@ -75,18 +82,18 @@ Pivot Painter MAXScript によりモデルの UV に格納されているワー ### PivotPainter_PerObjectFoliageData -Pivot Painter MAXScript によりモデルの UV に格納されているワールド位置と角度情報の処理と整理を行います。この関数は個別のフォリッジ オブジェクトと特別に機能するように作成されました。 +個別のフォリッジ オブジェクトとのみ機能する関数です。 | アイテム | 説明 | | -------- | -------- | | [REGION:tablesection]入力値[/REGION] || | **Wind Vector (Vector4)** | 風の方向と大きさに使う入力ベクターを受け取ります。 | -| **Optimized for Foliage Placement (StaticBool)** | 「Optimize for Foliage Placement」オプションにチェックを付けてPivot Painter を使用してメッシュを処理した場合は *true* に設定されています。デフォルトは *false* です。| -| **Optimized Vector (Vector3)** | エレメントの回転軸として使用するローカルベクターを入力します。*Optimized for Foliage Placement* 入力が *true* に設定されている場合のみ実行可能です。| +| **Optimized for Foliage Placement (StaticBool)** | [Optimize for Foliage Placement (フォリッジの配置を最適化)] オプションにチェックを付けてPivot Painter を使用してメッシュを処理した場合は *true* に設定されています。デフォルトは *false* です。| +| **Optimized Vector (Vector3)** | エレメントの回転軸として使用するローカル ベクターを入力します。*Optimized for Foliage Placement* 入力が *true* に設定されている場合のみ実行可能です。| |[REGION:tablesection]出力値[/REGION] || | **Piv Position** | ワールド空間における各エレメントの回転軸情報を返します。| -| **Element Rot Axis** | RotateAboutAxis ノードで使用される枝の回転軸を返します。葉は同じ情報を返します。注記:ローカルからワールド空間へ枝の X 軸に沿ってベクターを変形すると角度が見つかります。すると、風向きと変形されたベクターの間の外積が見つかります。 +| **Element Rot Axis** | RotateAboutAxis ノードで使用される枝の回転軸を返します。葉は同じ情報を返します。注意:ローカルからワールド空間へ枝の X 軸に沿ってベクターを変形すると角度が見つかります。すると、風向きと変形されたベクターの間の外積が見つかります。| | **Element X-Axis** | 回転軸からメッシュの平均的な中心に向かって、エレメントの X 軸方向を向いている標準化されたベクターを返します。回転軸からメッシュの平均的な中心に向かいます。 | | **Random Value Per Element** | 0-1 の範囲でエレメントごとにランダムな値を返します。| | **Custom Alpha Values** | モデルの頂点アルファ チャネルに格納されているカスタム フォールオフ値を返します。| @@ -101,31 +108,31 @@ Pivot Painter MAXScript によりモデルの UV に格納されているワー ### PivotPainter_TreeData -Pivot Painter スクリプトによりモデルの UV に格納されているワールド位置と角度情報の処理と整理を行います。*tree* で始まる出力ではモデルの UV 情報が処理され、Pivot Painter MAXScript で格納されます。*Leaf* で始まる出力では UV 情報が処理され、スクリプトのオブジェクトごとの pivot painting セクションによって格納されます。 +*tree* で始まる出力ではモデルの UV 情報が処理され、Pivot Painter MAXScript で格納されます。*Leaf* で始まる出力では UV 情報が処理され、スクリプトのオブジェクトごとの pivot painting セクションによって格納されます。 | アイテム | 説明 | | -------- | -------- | | [REGION:tablesection]入力値[/REGION] || | **WindVector (Vector3)** | 風が吹くことになる方向です。| -| **Max Dist for Parent Piv (Scalar)** | アセットのペイント中は MAXScript 「Max Dist for Parent Piv」の最大スピナーで使用された値と一致しなければなりません。 | +| **Max Dist for Parent Piv (Scalar)** | アセットのペイント中は MAXScript "Max Dist for Parent Piv" の最大スピナーで使用された値と一致しなければなりません。 | |[REGION:tablesection]出力値[/REGION] || | **Piv Position** | ワールド空間における各枝の回転軸情報を返します。葉は自分がアタッチされている枝の回転軸情報を返します。| -| **Branch Wind Rot Axis** | RotateAboutAxis ノードで使用される枝の回転軸を返します。葉は同じ情報を返します。注記:ローカルからワールド空間へ枝の X 軸に沿ってベクターを変形すると角度が見つかります。すると、風向きと変形されたベクターの間の外積が見つかります。 +| **Branch Wind Rot Axis** | RotateAboutAxis ノードで使用される枝の回転軸を返します。葉は同じ情報を返します。注意:ローカルからワールド空間へ枝の X 軸に沿ってベクターをトランスフォームすると、アングルが分かります。そうすると、風向きとトランスフォームしたベクター間の外積が見つかります。| | **Branch X-Axis Vector** | 枝の X 軸方向を向いている標準化されたベクターを返します。 カスタム ベクター算出に必要ない限り、フォリッジ アニメーションには通常必要ありません。 | | **Branch Flow Grad** | 風の吹いている方向にグラディエント値を返します。 | | **Branch Flow Grad 90 Deg** | 風に対して 90 度の角度でワールド空間を横切るグラディエント値を返します。| | **Leaf Piv Position** | 各葉のワールド内での回転位置情報を返します。枝は値 (0,0,0) を返します。 -| **Leaf Rot Axis** | RotateAboutAxis ノードで使用される葉の回転軸を返します。枝は (0,0,0) を返します。注記:ローカルからワールド空間へ葉の X 軸に沿ってベクターを変形すると角度が分かります。すると、風向きと変形されたベクターの間の外積が見つかります。 +| **Leaf Rot Axis** | RotateAboutAxis ノードで使用される葉の回転軸を返します。枝は (0,0,0) を返します。注意:ローカルからワールド空間へ葉の X 軸に沿ってベクターを変形すると角度が分かります。そうすると、風向きとトランスフォームしたベクター間の外積が見つかります。| | **Leaf X-Axis Vector** | 枝の X 軸方向を向いている標準化されたベクターを返します。 カスタム ベクター算出に必要ない限り、フォリッジ アニメーションには通常必要ありません。 | -| **Leaf Mask** | 葉に使う白いマスクテクスチャを返します。枝は全て黒です。 | +| **Leaf Mask** | 葉に使う白いマスク テクスチャを返します。枝は全て黒です。 | | **Leaf Flow Grad** | 風の吹いている方向のグラディエント値を返します。 | **Leaf Flow Grad 90 Deg** | 風に対して 90 度の角度でワールド空間を横切るグラディエント値を返します。| | **Object Pivot Point** | オブジェクトの回転軸の位置を返します。| | **Object Orientation** | オブジェクトの方向を返します。| | **オブジェクト回転軸** | オブジェクトの回転軸を返します。| -| **Object Orientation** | オブジェクトのスケールを返します。| -| **Object Flow Grad** |ワールド空間のオブジェクトレベルで風のベクター値と揃っているグラディエントです。| -| **Object Flow Grad 90 deg** |ワールド空間のオブジェクトレベルで風のベクター値と揃っているグラディエントです。| +| **Object Scale** | オブジェクトのスケールを返します。| +| **Object Flow Grad** | ワールド空間のオブジェクトレベルで風のベクター値と揃っているグラディエントです。| +| **Object Flow Grad 90 deg** | ワールド空間のオブジェクトレベルで風のベクター値と揃っているグラディエントです。| | **WindStrength** | 風の強さを返します。風のベクター値の強度は風のベクター値から 0 へ距離を計算して割り出します。 | | **Normalized Wind Vector** | 0-1 の間の大きさで標準化された風のベクター値を返します。| | **WindSpeed** | 時間を乗算した風の速度です。| diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/Functions/Reference/PivotPainter2/PivotPainter2.CHN.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/Functions/Reference/PivotPainter2/PivotPainter2.CHN.udn new file mode 100644 index 000000000000..4a74c11ca9fe --- /dev/null +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/Functions/Reference/PivotPainter2/PivotPainter2.CHN.udn @@ -0,0 +1,184 @@ +INTSourceChangelist:0 +Availability:Public +Crumbs:%ROOT% +Title:Pivot Painter 2 Material Functions +Description: Material Functions designed to enable utilization of the Pivot Painter 2 MAXScript in an Unreal shader network. +Type:reference +Version:4.16 +Parent:Engine/Rendering/Materials/Functions/Reference +Related:Engine/Content/Tools/PivotPainter2 +Related:Engine/Content/Tools/PivotPainter2/Reference +Order:1 +Topic-image:PivotPainter2MF_Topic.png +Social-image:PP2MaterialFunction_Social.png +Tags:Script +Tags:Pivot Painter +Tags:Materials + + +[TOC (start:2 end:3)] + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 840 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 560 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + Kcqm89nu0tw + [/PARAMLITERAL] +[/OBJECT] + +Pivot Painter 2 Material Functions enable you to tap into and decode useful model information stored by Pivot Painter 2 MAXScript using textures. Each texture output by the MAXScript can be referenced +directly in a Material but without applying the proper steps after sampling the texture the values would be incorrect. These Material Functions found in this page make it easy to quickly decode +the texture information. + +A lot of the Material Functions included in this page will enable you to use the Pivot Painter 2 pivot and rotational information to do specific effects via your Material, however, one of +the greater benefits of Pivot Painter 2 is its ease of use with the provided sample shader for foliage; **PivotPainter2FoliageShader**. This specific Material Function enables you to +quickly setup your model and its Pivot Painter 2 generated textures with your foliage to quickly create wind and turbulence without having to create your own Material network. + + + + +## Pivot Painter 2 Functions + +The following is a list of all the functions related to Pivot Painter 2. + + +### PivotPainter2FoliageShader + +![](PP2_FoliageShader.png) + +This Material Function contains texture and numeric parameters that should be altered to fit your particular asset. + +Also, for this particular function, it is suggested that you create a Material Instance, where the Material Function's parameters will be accessible to make changes to your Pivot Painter 2 shader. + +[REGION:lightbox] +[![](PP2FoliageShaderMaterialInstanceParams.png)(w:300)](PP2FoliageShaderMaterialInstanceParams.png) +[/REGION] +[REGION:caption] +_Click image for full size view._ +[/REGION] + + +[REGION:raw] +| Item | Description | +| -------- | -------- | +|[REGION:tablesection]Inputs[/REGION] || +| **Material Attributes** | Make sure that you are using tangent space normals within your material and that the **Use Tangent Space Normals** option is unchecked. The normals will be transformed to world space internally. | +| **Pivot Painter Texture Coordinate** | Takes an input to reference which texture coordinate UV is being used. | +|[REGION:tablesection]Outputs[/REGION] || +| **Final Material with World Space Normals** | This output material attribute replaces the input material attribute's world position offset and normal output if **Animate Level "X" Normals** is enabled in the Material Instance. [REGION:note] Updating the model's normals is fairly expensive and can be done selectively. [/REGION]| +| **Modified World Space Normal Component** | This output returns the modified asset normals by itself. | +| **World Position Offset Component** | This output returns the new world position offset values. | +[/REGION] + + + +### ms_PivotPainter2_CalculateMeshElementIndex + +![](PP2_CalculateMeshElementIndex.png) + +This Material Function pulls the model's Element ID from the model's UVs. + +[REGION:raw] +| Item | Description | +| -------- | -------- | +|[REGION:tablesection]Inputs[/REGION] || +| **Data Texture Dimensions** | Use the texture property node to gather the texture's dimensions. | +| **Pivot Painter UV Coordinates** | Pulls the model elements element ID from the model's UVs. | +|[REGION:tablesection]Outputs[/REGION] || +| **Index** | This output pulls the model element ID from the model's UVs. | +[/REGION] + + + +### ms_PivotPainter2_Decode8BitAlphaAxisExtent + +![](PP2_Decode8bitAlphaAxisExtent.png) + +This Material Function rescales 8-bit axis extent texture data information from Pivot Painter 2 MAXScript into world space data. + +[REGION:raw] +| Item | Description | +| -------- | -------- | +|[REGION:tablesection]Inputs[/REGION] || +| **8 Bit Alpha Extent Value** | Insert a Pivot Painter 2 alpha texture component from a texture with an 8-bit alpha extent value. This can be generated by selecting the appropriate option from the alpha output drop-down option in the Pivot Painter 2 MAXScript under the Render Options. | +|[REGION:tablesection]Outputs[/REGION] || +| **Rescaled Extent** | The output value represents the chosen models' length along a given axis starting at the object's pivot points. The return value can represent values between 8 to 2048 in increments of 8. | +[/REGION] + + + +### ms_PivotPainter2_DecodeAxisVector + +![](PP2_DecodeAxisVector.png) + +This Material Function transforms Pivot Painter 2's local space vector information into world space vectors. + +[REGION:raw] +| Item | Description | +| -------- | -------- | +|[REGION:tablesection]Inputs[/REGION] || +| **Axis Vector RGB** | Input RGB vector information from a Pivot Painter 2 texture that output those values. | +|[REGION:tablesection]Outputs[/REGION] || +| **Result** | The input axis vector information has now been transformed to world space. | +[/REGION] + + + +### ms_PivotPainter2_DecodePosition + +![](PP2_DecodePosition.png) + +This Material Function transforms Pivot Painter 2's local space information into world position information. + +[REGION:raw] +| Item | Description | +| -------- | -------- | +|[REGION:tablesection]Inputs[/REGION] || +|** Position RGB** | Insert the RGB values of a texture that contain Pivot Painter 2 **Pivot Position (16-bit)** data. | +|[REGION:tablesection]Outputs[/REGION] || +| **Result** | The output value is the world space location of each model's pivot point position as it was captured by Pivot Painter 2. | +[/REGION] + +### ms_PivotPainter2_ReturnParentTextureInfo + +![](PP2_ReturnParentTextureInfo.png) + +This Material Function reads a parent sub-object's texture data using Pivot Painter 2's **Parent Index (Integer as Float)** texture data. + +[REGION:raw] +| Item | Description | +| -------- | -------- | +|[REGION:tablesection]Inputs[/REGION] || +| **Parent Index As Float** | This input assumes that the data is in float form. If you're reading from a parent index "int as float" texture, first decode the asset using the Material Function **ms_PivotPainter2_UnpackIntegerAsFloat**. | +| **Texture Dimensions** | The current dimensions of the texture. | +| **Current Index** | Providing this value is only necessary if you would like to determine if this asset is a child of another component. | +|[REGION:tablesection]Outputs[/REGION] || +| **Parent UVs** | This outputs the UV coordinates for the element's parent element pixel location. | +| **Is Child?** | This returns 1 if the object is a child of another object. It returns 0 otherwise. This requires that the current index to be entered in the **Current Index** input. The current index can be found by using **ms_PivotPainter2_CalculateMeshElementIndex** if you are referencing your textures using the model's UVs. | +[/REGION] + + +### ms_PivotPainter2_UnpackIntegerAsFloat + +![](PP2_UnpackIntegerAsFloat.png) + +This Material Function decodes Pivot Painter 2's **Integer as Float** texture data. + +[REGION:raw] +| Item | Description | +| -------- | -------- | +|[REGION:tablesection]Inputs[/REGION] || +| **Integer as Float** | This decodes the integer data for conversion to float data. | +|[REGION:tablesection]Outputs[/REGION] || +| **Result** | This outputs Pivot Painter integer as float data. | +[/REGION] + + + + + + diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/Functions/Reference/PivotPainter2/PivotPainter2.INT.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/Functions/Reference/PivotPainter2/PivotPainter2.INT.udn new file mode 100644 index 000000000000..9b9b3dcd49a8 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/Functions/Reference/PivotPainter2/PivotPainter2.INT.udn @@ -0,0 +1,183 @@ +Availability:Public +Crumbs:%ROOT% +Title:Pivot Painter 2 Material Functions +Description: Material Functions designed to enable utilization of the Pivot Painter 2 MAXScript in an Unreal shader network. +Type:reference +Version:4.16 +Parent:Engine/Rendering/Materials/Functions/Reference +Related:Engine/Content/Tools/PivotPainter2 +Related:Engine/Content/Tools/PivotPainter2/Reference +Order:1 +Topic-image:PivotPainter2MF_Topic.png +Social-image:PP2MaterialFunction_Social.png +Tags:Script +Tags:Pivot Painter +Tags:Materials + + +[TOC (start:2 end:3)] + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 840 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 560 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + Kcqm89nu0tw + [/PARAMLITERAL] +[/OBJECT] + +Pivot Painter 2 Material Functions enable you to tap into and decode useful model information stored by Pivot Painter 2 MAXScript using textures. Each texture output by the MAXScript can be referenced +directly in a Material but without applying the proper steps after sampling the texture the values would be incorrect. These Material Functions found in this page make it easy to quickly decode +the texture information. + +A lot of the Material Functions included in this page will enable you to use the Pivot Painter 2 pivot and rotational information to do specific effects via your Material, however, one of +the greater benefits of Pivot Painter 2 is its ease of use with the provided sample shader for foliage; **PivotPainter2FoliageShader**. This specific Material Function enables you to +quickly setup your model and its Pivot Painter 2 generated textures with your foliage to quickly create wind and turbulence without having to create your own Material network. + + + + +## Pivot Painter 2 Functions + +The following is a list of all the functions related to Pivot Painter 2. + + +### PivotPainter2FoliageShader + +![](PP2_FoliageShader.png) + +This Material Function contains texture and numeric parameters that should be altered to fit your particular asset. + +Also, for this particular function, it is suggested that you create a Material Instance, where the Material Function's parameters will be accessible to make changes to your Pivot Painter 2 shader. + +[REGION:lightbox] +[![](PP2FoliageShaderMaterialInstanceParams.png)(w:300)](PP2FoliageShaderMaterialInstanceParams.png) +[/REGION] +[REGION:caption] +_Click image for full size view._ +[/REGION] + + +[REGION:raw] +| Item | Description | +| -------- | -------- | +|[REGION:tablesection]Inputs[/REGION] || +| **Material Attributes** | Make sure that you are using tangent space normals within your material and that the **Use Tangent Space Normals** option is unchecked. The normals will be transformed to world space internally. | +| **Pivot Painter Texture Coordinate** | Takes an input to reference which texture coordinate UV is being used. | +|[REGION:tablesection]Outputs[/REGION] || +| **Final Material with World Space Normals** | This output material attribute replaces the input material attribute's world position offset and normal output if **Animate Level "X" Normals** is enabled in the Material Instance. [REGION:note] Updating the model's normals is fairly expensive and can be done selectively. [/REGION]| +| **Modified World Space Normal Component** | This output returns the modified asset normals by itself. | +| **World Position Offset Component** | This output returns the new world position offset values. | +[/REGION] + + + +### ms_PivotPainter2_CalculateMeshElementIndex + +![](PP2_CalculateMeshElementIndex.png) + +This Material Function pulls the model's Element ID from the model's UVs. + +[REGION:raw] +| Item | Description | +| -------- | -------- | +|[REGION:tablesection]Inputs[/REGION] || +| **Data Texture Dimensions** | Use the texture property node to gather the texture's dimensions. | +| **Pivot Painter UV Coordinates** | Pulls the model elements element ID from the model's UVs. | +|[REGION:tablesection]Outputs[/REGION] || +| **Index** | This output pulls the model element ID from the model's UVs. | +[/REGION] + + + +### ms_PivotPainter2_Decode8BitAlphaAxisExtent + +![](PP2_Decode8bitAlphaAxisExtent.png) + +This Material Function rescales 8-bit axis extent texture data information from Pivot Painter 2 MAXScript into world space data. + +[REGION:raw] +| Item | Description | +| -------- | -------- | +|[REGION:tablesection]Inputs[/REGION] || +| **8 Bit Alpha Extent Value** | Insert a Pivot Painter 2 alpha texture component from a texture with an 8-bit alpha extent value. This can be generated by selecting the appropriate option from the alpha output drop-down option in the Pivot Painter 2 MAXScript under the Render Options. | +|[REGION:tablesection]Outputs[/REGION] || +| **Rescaled Extent** | The output value represents the chosen models' length along a given axis starting at the object's pivot points. The return value can represent values between 8 to 2048 in increments of 8. | +[/REGION] + + + +### ms_PivotPainter2_DecodeAxisVector + +![](PP2_DecodeAxisVector.png) + +This Material Function transforms Pivot Painter 2's local space vector information into world space vectors. + +[REGION:raw] +| Item | Description | +| -------- | -------- | +|[REGION:tablesection]Inputs[/REGION] || +| **Axis Vector RGB** | Input RGB vector information from a Pivot Painter 2 texture that output those values. | +|[REGION:tablesection]Outputs[/REGION] || +| **Result** | The input axis vector information has now been transformed to world space. | +[/REGION] + + + +### ms_PivotPainter2_DecodePosition + +![](PP2_DecodePosition.png) + +This Material Function transforms Pivot Painter 2's local space information into world position information. + +[REGION:raw] +| Item | Description | +| -------- | -------- | +|[REGION:tablesection]Inputs[/REGION] || +|** Position RGB** | Insert the RGB values of a texture that contain Pivot Painter 2 **Pivot Position (16-bit)** data. | +|[REGION:tablesection]Outputs[/REGION] || +| **Result** | The output value is the world space location of each model's pivot point position as it was captured by Pivot Painter 2. | +[/REGION] + +### ms_PivotPainter2_ReturnParentTextureInfo + +![](PP2_ReturnParentTextureInfo.png) + +This Material Function reads a parent sub-object's texture data using Pivot Painter 2's **Parent Index (Integer as Float)** texture data. + +[REGION:raw] +| Item | Description | +| -------- | -------- | +|[REGION:tablesection]Inputs[/REGION] || +| **Parent Index As Float** | This input assumes that the data is in float form. If you're reading from a parent index "int as float" texture, first decode the asset using the Material Function **ms_PivotPainter2_UnpackIntegerAsFloat**. | +| **Texture Dimensions** | The current dimensions of the texture. | +| **Current Index** | Providing this value is only necessary if you would like to determine if this asset is a child of another component. | +|[REGION:tablesection]Outputs[/REGION] || +| **Parent UVs** | This outputs the UV coordinates for the element's parent element pixel location. | +| **Is Child?** | This returns 1 if the object is a child of another object. It returns 0 otherwise. This requires that the current index to be entered in the **Current Index** input. The current index can be found by using **ms_PivotPainter2_CalculateMeshElementIndex** if you are referencing your textures using the model's UVs. | +[/REGION] + + +### ms_PivotPainter2_UnpackIntegerAsFloat + +![](PP2_UnpackIntegerAsFloat.png) + +This Material Function decodes Pivot Painter 2's **Integer as Float** texture data. + +[REGION:raw] +| Item | Description | +| -------- | -------- | +|[REGION:tablesection]Inputs[/REGION] || +| **Integer as Float** | This decodes the integer data for conversion to float data. | +|[REGION:tablesection]Outputs[/REGION] || +| **Result** | This outputs Pivot Painter integer as float data. | +[/REGION] + + + + + + diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/Functions/Reference/PivotPainter2/PivotPainter2.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/Functions/Reference/PivotPainter2/PivotPainter2.JPN.udn new file mode 100644 index 000000000000..1d9751a51a77 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/Functions/Reference/PivotPainter2/PivotPainter2.JPN.udn @@ -0,0 +1,184 @@ +INTSourceChangelist:3472589 +Availability:Public +Crumbs:%ROOT% +Title:Pivot Painter 2 マテリアル関数 +Description:マテリアル関数は、アンリアル シェーダー ネットワークでの Pivot Painter 2 MAXScript の使用を可能にします。 +Type:reference +Version:4.16 +Parent:Engine/Rendering/Materials/Functions/Reference +Related:Engine/Content/Tools/PivotPainter2 +Related:Engine/Content/Tools/PivotPainter2/Reference +Order:1 +Topic-image:PivotPainter2MF_Topic.png +Social-image:PP2MaterialFunction_Social.png +Tags:Script +Tags:Pivot Painter +Tags:Materials + + +[TOC (start:2 end:3)] + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 840 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 560 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + Kcqm89nu0tw + [/PARAMLITERAL] +[/OBJECT] + +Pivot Painter 2 マテリアル関数は、Pivot Painter 2 MAXScript に格納されている便利なモデル情報のテキストによる利用およびデコードを可能にします。MAXScript で出力された各テキストはマテリアル内での直接参照が可能です。 +ただし、テクスチャのサンプリング後に正しいステップが適用されないと、正確な値は出ません。このページでは、テクスチャ情報を速く簡単にデコードできる +マテリアル関数を紹介します。 + +以下のマテリアル関数のほとんどは、Pivot Painter 2 ピボットと回転情報を使って、マテリアルを使って指定したエフェクトを実行します。 +Pivot Painter 2 の長所の 1 つは、フォリッジ用に提供されているサンプル シェーダー **PivotPainter2FoliageShader** が使いやすいことです。この特別な関数は、モデルを迅速にセットアップし、 +専用のネットワークを作成しなくても、モデルの Pivot Painter 2 がフォリッジを使って生成したテクスチャを使って、風と揺れを簡単に作成することができます。 + + + + +## Pivot Painter 2 関数 + +以下は Pivot Painter 2 に関係するすべての関数です。 + + +### PivotPainter2FoliageShader + +![](PP2_FoliageShader.png) + +このマテリアル関数には、特定のアセットにフィットするように変更されたテクスチャおよび数値のパラメータが含まれています。 + +この関数の場合、マテリアル インスタンスを作成することを推奨します。マテリアル関数のパラメータにアクセスして Pivot Painter 2 シェーダーの変更ができます。 + +[REGION:lightbox] +[![](PP2FoliageShaderMaterialInstanceParams.png)(w:300)](PP2FoliageShaderMaterialInstanceParams.png) +[/REGION] +[REGION:caption] +_画像をクリックしてフルサイズで表示_ +[/REGION] + + +[REGION:raw] +| アイテム | 説明 | +| -------- | -------- | +| [REGION:tablesection]入力値[/REGION] || +| **Material Attributes** | マテリアル内でタンジェント空間を使用していること、**Use Tangent Space Normals** 出力のチェックが外れていることを確認してください。法線は最初にワールド空間へ変換されます。 | +| **Pivot Painter Texture Coordinate** | テクスチャ座標 UV が使用されているリファレンスへの入力を受け取ります。 | +|[REGION:tablesection]出力値[/REGION] || +| **Final Material with World Space Normals** | マテリアル インスタンスで **[Animate Level "X" Normals]** が有効の場合、入力マテリアルのワールド位置オフセットと法線出力となる属性です。[REGION:note] モデルの法線のアップデートはかなり負荷が高いので、必要性を慎重に検討してください。 [/REGION]| +| **Modified World Space Normal Component** | それ自体が修正したアセット法線を出力します。 | +| **World Position Offset Component** | 新規のワールド位置オフセット値を出力します。 | +[/REGION] + + + +### ms_PivotPainter2_CalculateMeshElementIndex + +![](PP2_CalculateMeshElementIndex.png) + +このマテリアル関数はモデの UV からモデルのエレメント ID を引き出します。 + +[REGION:raw] +| アイテム | 説明 | +| -------- | -------- | +| [REGION:tablesection]入力値[/REGION] || +| **Data Texture Dimensions** | テクスチャ プロパティ ノードを使ってテクスチャのディメンションを集めます。 | +| **Pivot Painter UV Coordinates** | モデルの UV からモデル エレメント ID を引き出します。 | +|[REGION:tablesection]出力値[/REGION] || +| **Index** | モデルの UV からモデル エレメント ID を引き出す出力です。 | +[/REGION] + + + +### ms_PivotPainter2_Decode8BitAlphaAxisExtent + +![](PP2_Decode8bitAlphaAxisExtent.png) + +8 ビットの軸拡張テクスチャ データ情報を Pivot Painter 2 MAXScript からワールド空間データへ再スケールします。 + +[REGION:raw] +| アイテム | 説明 | +| -------- | -------- | +| [REGION:tablesection]入力値[/REGION] || +| **8 Bit Alpha Extent Value** | テクスチャから 8 ビットのアルファ拡張値で Pivot Painter 2 アルファ テクスチャ コンポーネントを挿入します。[Render] オプションにある [Pivot Painter 2] のアルファ出力ドロップダウン オプションから適切なオプションを選択すると生成できます。 | +|[REGION:tablesection]出力値[/REGION] || +| **Rescaled Extent** | 出力値は、オブジェクトの回転軸で開始している軸に平行の選択したモデルの長さを表します。戻り値は 8 から 2048 の間で 8 単位で表すことができます。 | +[/REGION] + + + +### ms_PivotPainter2_DecodeAxisVector + +![](PP2_DecodeAxisVector.png) + +このマテリアル関数は Pivot Painter 2 のローカル空間ベクター情報をワールド空間ベクターに変換します。 + +[REGION:raw] +| アイテム | 説明 | +| -------- | -------- | +| [REGION:tablesection]入力値[/REGION] || +| **Axis Vector RGB** | これらの値を出力する Pivot Painter 2 テクスチャからの RGB ベクター情報を入力します。 | +|[REGION:tablesection]出力値[/REGION] || +| **Result** | 入力軸ベクター情報がワールド空間に変換されました。 | +[/REGION] + + + +### ms_PivotPainter2_DecodePosition + +![](PP2_DecodePosition.png) + +このマテリアル関数は Pivot Painter 2 のローカル空間情報をワールド位置情報に変換します。 + +[REGION:raw] +| アイテム | 説明 | +| -------- | -------- | +| [REGION:tablesection]入力値[/REGION] || +|** Position RGB** | Pivot Painter 2 **Pivot Position (16-bit)** データを含むテクスチャの RGB 値を挿入します。 | +|[REGION:tablesection]出力値[/REGION] || +| **Result** | 出力値は、Pivot Painter 2 によるキャプチャ時の各モデルの軸ポイント位置のワールド空間位置です。 | +[/REGION] + +### ms_PivotPainter2_ReturnParentTextureInfo + +![](PP2_ReturnParentTextureInfo.png) + +このマテリアル関数は、Pivot Painter 2 の **Parent Index (Integer as Float)** テクスチャ データを使って親のサブ オブジェクトのテクスチャ データを読み取ります。 + +[REGION:raw] +| アイテム | 説明 | +| -------- | -------- | +| [REGION:tablesection]入力値[/REGION] || +| **Parent Index As Float** | この入力は、データが float 形式であることを前提とします。親インデックス "int as float" テクスチャから読み取る場合は、まずマテリアル関数 **ms_PivotPainter2_UnpackIntegerAsFloat** を使ってアセットをデコードします。 | +| **Texture Dimensions** | テクスチャの現在のディメンションです。 | +| **Current Index** | アセットが別のコポーネントの子かどうかを判断する場合のみこの値が必要となります。 | +|[REGION:tablesection]出力値[/REGION] || +| **Parent UVs** | エレメントの親エレメント ピクセル位置の UV 座標を出力します。 | +| **Is Child?** | 別のオブジェクトの子の場合は 1 を返します。そうでない場合は 0 を返します。これには、**Current Index** 入力に現在のインデックスを入力する必要があります。モデルの UV でテクスチャ参照している場合、現在のインデックスは **ms_PivotPainter2_CalculateMeshElementIndex** で検索することができます。 | +[/REGION] + + +### ms_PivotPainter2_UnpackIntegerAsFloat + +![](PP2_UnpackIntegerAsFloat.png) + +このマテリアル関数は、Pivot Painter 2 の **Integer as Float** テクスチャ データをデコードします。 + +[REGION:raw] +| アイテム | 説明 | +| -------- | -------- | +| [REGION:tablesection]入力値[/REGION] || +| **Integer as Float** | float 型データへ変換するために integer 型データをデコードします。 | +|[REGION:tablesection]出力値[/REGION] || +| **Result** | float 型データとして Pivot Painter integer を出力します。 | +[/REGION] + + + + + + diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/Functions/Reference/PivotPainter2/PivotPainter2.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/Functions/Reference/PivotPainter2/PivotPainter2.KOR.udn new file mode 100644 index 000000000000..4a74c11ca9fe --- /dev/null +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/Functions/Reference/PivotPainter2/PivotPainter2.KOR.udn @@ -0,0 +1,184 @@ +INTSourceChangelist:0 +Availability:Public +Crumbs:%ROOT% +Title:Pivot Painter 2 Material Functions +Description: Material Functions designed to enable utilization of the Pivot Painter 2 MAXScript in an Unreal shader network. +Type:reference +Version:4.16 +Parent:Engine/Rendering/Materials/Functions/Reference +Related:Engine/Content/Tools/PivotPainter2 +Related:Engine/Content/Tools/PivotPainter2/Reference +Order:1 +Topic-image:PivotPainter2MF_Topic.png +Social-image:PP2MaterialFunction_Social.png +Tags:Script +Tags:Pivot Painter +Tags:Materials + + +[TOC (start:2 end:3)] + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 840 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 560 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + Kcqm89nu0tw + [/PARAMLITERAL] +[/OBJECT] + +Pivot Painter 2 Material Functions enable you to tap into and decode useful model information stored by Pivot Painter 2 MAXScript using textures. Each texture output by the MAXScript can be referenced +directly in a Material but without applying the proper steps after sampling the texture the values would be incorrect. These Material Functions found in this page make it easy to quickly decode +the texture information. + +A lot of the Material Functions included in this page will enable you to use the Pivot Painter 2 pivot and rotational information to do specific effects via your Material, however, one of +the greater benefits of Pivot Painter 2 is its ease of use with the provided sample shader for foliage; **PivotPainter2FoliageShader**. This specific Material Function enables you to +quickly setup your model and its Pivot Painter 2 generated textures with your foliage to quickly create wind and turbulence without having to create your own Material network. + + + + +## Pivot Painter 2 Functions + +The following is a list of all the functions related to Pivot Painter 2. + + +### PivotPainter2FoliageShader + +![](PP2_FoliageShader.png) + +This Material Function contains texture and numeric parameters that should be altered to fit your particular asset. + +Also, for this particular function, it is suggested that you create a Material Instance, where the Material Function's parameters will be accessible to make changes to your Pivot Painter 2 shader. + +[REGION:lightbox] +[![](PP2FoliageShaderMaterialInstanceParams.png)(w:300)](PP2FoliageShaderMaterialInstanceParams.png) +[/REGION] +[REGION:caption] +_Click image for full size view._ +[/REGION] + + +[REGION:raw] +| Item | Description | +| -------- | -------- | +|[REGION:tablesection]Inputs[/REGION] || +| **Material Attributes** | Make sure that you are using tangent space normals within your material and that the **Use Tangent Space Normals** option is unchecked. The normals will be transformed to world space internally. | +| **Pivot Painter Texture Coordinate** | Takes an input to reference which texture coordinate UV is being used. | +|[REGION:tablesection]Outputs[/REGION] || +| **Final Material with World Space Normals** | This output material attribute replaces the input material attribute's world position offset and normal output if **Animate Level "X" Normals** is enabled in the Material Instance. [REGION:note] Updating the model's normals is fairly expensive and can be done selectively. [/REGION]| +| **Modified World Space Normal Component** | This output returns the modified asset normals by itself. | +| **World Position Offset Component** | This output returns the new world position offset values. | +[/REGION] + + + +### ms_PivotPainter2_CalculateMeshElementIndex + +![](PP2_CalculateMeshElementIndex.png) + +This Material Function pulls the model's Element ID from the model's UVs. + +[REGION:raw] +| Item | Description | +| -------- | -------- | +|[REGION:tablesection]Inputs[/REGION] || +| **Data Texture Dimensions** | Use the texture property node to gather the texture's dimensions. | +| **Pivot Painter UV Coordinates** | Pulls the model elements element ID from the model's UVs. | +|[REGION:tablesection]Outputs[/REGION] || +| **Index** | This output pulls the model element ID from the model's UVs. | +[/REGION] + + + +### ms_PivotPainter2_Decode8BitAlphaAxisExtent + +![](PP2_Decode8bitAlphaAxisExtent.png) + +This Material Function rescales 8-bit axis extent texture data information from Pivot Painter 2 MAXScript into world space data. + +[REGION:raw] +| Item | Description | +| -------- | -------- | +|[REGION:tablesection]Inputs[/REGION] || +| **8 Bit Alpha Extent Value** | Insert a Pivot Painter 2 alpha texture component from a texture with an 8-bit alpha extent value. This can be generated by selecting the appropriate option from the alpha output drop-down option in the Pivot Painter 2 MAXScript under the Render Options. | +|[REGION:tablesection]Outputs[/REGION] || +| **Rescaled Extent** | The output value represents the chosen models' length along a given axis starting at the object's pivot points. The return value can represent values between 8 to 2048 in increments of 8. | +[/REGION] + + + +### ms_PivotPainter2_DecodeAxisVector + +![](PP2_DecodeAxisVector.png) + +This Material Function transforms Pivot Painter 2's local space vector information into world space vectors. + +[REGION:raw] +| Item | Description | +| -------- | -------- | +|[REGION:tablesection]Inputs[/REGION] || +| **Axis Vector RGB** | Input RGB vector information from a Pivot Painter 2 texture that output those values. | +|[REGION:tablesection]Outputs[/REGION] || +| **Result** | The input axis vector information has now been transformed to world space. | +[/REGION] + + + +### ms_PivotPainter2_DecodePosition + +![](PP2_DecodePosition.png) + +This Material Function transforms Pivot Painter 2's local space information into world position information. + +[REGION:raw] +| Item | Description | +| -------- | -------- | +|[REGION:tablesection]Inputs[/REGION] || +|** Position RGB** | Insert the RGB values of a texture that contain Pivot Painter 2 **Pivot Position (16-bit)** data. | +|[REGION:tablesection]Outputs[/REGION] || +| **Result** | The output value is the world space location of each model's pivot point position as it was captured by Pivot Painter 2. | +[/REGION] + +### ms_PivotPainter2_ReturnParentTextureInfo + +![](PP2_ReturnParentTextureInfo.png) + +This Material Function reads a parent sub-object's texture data using Pivot Painter 2's **Parent Index (Integer as Float)** texture data. + +[REGION:raw] +| Item | Description | +| -------- | -------- | +|[REGION:tablesection]Inputs[/REGION] || +| **Parent Index As Float** | This input assumes that the data is in float form. If you're reading from a parent index "int as float" texture, first decode the asset using the Material Function **ms_PivotPainter2_UnpackIntegerAsFloat**. | +| **Texture Dimensions** | The current dimensions of the texture. | +| **Current Index** | Providing this value is only necessary if you would like to determine if this asset is a child of another component. | +|[REGION:tablesection]Outputs[/REGION] || +| **Parent UVs** | This outputs the UV coordinates for the element's parent element pixel location. | +| **Is Child?** | This returns 1 if the object is a child of another object. It returns 0 otherwise. This requires that the current index to be entered in the **Current Index** input. The current index can be found by using **ms_PivotPainter2_CalculateMeshElementIndex** if you are referencing your textures using the model's UVs. | +[/REGION] + + +### ms_PivotPainter2_UnpackIntegerAsFloat + +![](PP2_UnpackIntegerAsFloat.png) + +This Material Function decodes Pivot Painter 2's **Integer as Float** texture data. + +[REGION:raw] +| Item | Description | +| -------- | -------- | +|[REGION:tablesection]Inputs[/REGION] || +| **Integer as Float** | This decodes the integer data for conversion to float data. | +|[REGION:tablesection]Outputs[/REGION] || +| **Result** | This outputs Pivot Painter integer as float data. | +[/REGION] + + + + + + diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/HowTo/MaterialHowTo.INT.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/HowTo/MaterialHowTo.INT.udn index 3a9dace27cc6..164dcc582319 100644 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/HowTo/MaterialHowTo.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/HowTo/MaterialHowTo.INT.udn @@ -7,7 +7,7 @@ prereq: Engine/Rendering/Materials/MaterialInputs prereq: Engine/Rendering/Materials/Editor prereq: Engine/Rendering/Materials/IntroductionToMaterials prereq: Engine/Rendering/Materials/MaterialProperties -Version: 4.9 +Version: 4.15 parent:Engine/Rendering/Materials order:3 type:landing diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/HowTo/MaterialHowTo.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/HowTo/MaterialHowTo.JPN.udn index a430ed6f1018..e4ed5155b99d 100644 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/HowTo/MaterialHowTo.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/HowTo/MaterialHowTo.JPN.udn @@ -1,41 +1,26 @@ -INTSourceChangelist:2690368 +INTSourceChangelist:3377213 Availability:Public -Title:マテリアル - 操作ガイド +Title:マテリアルの操作ガイド Crumbs: %ROOT%, Engine, Engine/Rendering/Materials -Description:UE4 でマテリアル エディタの様々な機能を使用するための操作ガイド -Related:Engine/Rendering/Materials/Editor/Interface -Related:Engine/Rendering/Materials/MaterialInputs -Related:Engine/Rendering/Materials/Editor -Related:Engine/Rendering/Materials/IntroductionToMaterials -Related:Engine/Rendering/Materials/MaterialProperties -Version:4.9 +Description:UE4 マテリアル エディタの様々な特性を使いこなすためのガイド +prereq:Engine/Rendering/Materials/Editor/Interface +prereq:Engine/Rendering/Materials/MaterialInputs +prereq:Engine/Rendering/Materials/Editor +prereq:Engine/Rendering/Materials/IntroductionToMaterials +prereq:Engine/Rendering/Materials/MaterialProperties +Version:4.15 +parent:Engine/Rendering/Materials +order:3 +type:landing +topic-image:Materail_How_To.png +tags:Materials -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Rendering/Materials/HowTo:title%](%ROOT%/Engine/Rendering/Materials/HowTo/Materail_How_To.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/light_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Rendering/Materials/HowTo:title% - [/PARAM] - [PARAM:description] - %Engine/Rendering/Materials/HowTo:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Rendering/Materials/HowTo] - [/PARAM] -[/OBJECT] -[/VAR] +![](materials_howto.png) - - -以下の操作ガイドでは、UE4 のマテリアル エディタを十分に活用する方法について説明します。 +プロジェクトにおけるマテリアルの作成および使用に役立つ幅広いトピックを 1 つずつ説明しします。 + +## はじめよう +[DIR(output:"fancy" parent:"Engine/Rendering/Materials/HowTo" skill_level:"Beginner")] + +## マテリアル応用編 + +[DIR(output:"fancy" parent:"Engine/Rendering/Materials/HowTo" skill_level:"Intermediate")] + +## まとめ + +[DIR(output:"fancy" parent:"Engine/Rendering/Materials/HowTo" skill_level:"Advanced")] + + \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/HowTo/MaterialHowTo.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/HowTo/MaterialHowTo.KOR.udn index a82986c99724..c1c82eeb8251 100644 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/HowTo/MaterialHowTo.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/HowTo/MaterialHowTo.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3242329 +INTSourceChangelist:3377213 Availability: Public Title:머티리얼 - 비법 Crumbs: %ROOT%, Engine, Engine/Rendering/Materials @@ -8,7 +8,7 @@ prereq: Engine/Rendering/Materials/MaterialInputs prereq: Engine/Rendering/Materials/Editor prereq: Engine/Rendering/Materials/IntroductionToMaterials prereq: Engine/Rendering/Materials/MaterialProperties -Version: 4.9 +Version: 4.15 parent:Engine/Rendering/Materials order:3 type:landing diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/HowTo/MeshDecals/MeshDecals.INT.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/HowTo/MeshDecals/MeshDecals.INT.udn deleted file mode 100644 index 781e7450a896..000000000000 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/HowTo/MeshDecals/MeshDecals.INT.udn +++ /dev/null @@ -1,166 +0,0 @@ -Availability:Docs -Title: Using Mesh Decals -Description: This how to will cover setting up and using Mesh Decals. -Crumbs: -parent: Engine/Rendering/Materials/HowTo -type: reference -tags:Materials -version:4.15 -skilllevel:intermediate - -[TOC (start:2 end:4)] - - -Unreal Engine 4 now has support for Mesh Decals which enables you to use the properties of Deferred Decals on separate surface geometry -for added detail to your Static and Skeletal Meshes. Because Deferred Decals rely on projection, you are limited to mostly planar surface -details that shear and distort when not aligned with the surface it’s projecting onto. Mesh Decals afford you decals that do not follow -a simple projection and instead can be used with geometry that wraps around edges, used with spline meshes, and enhance the look of your characters. - - -## Mesh Decal VS Masked Material - -Mesh Decals are a mix of translucent blend mode and deferred decals in that they do not render to depth but do update the GBuffer or -DBuffer after the opaque geometry has been rendered. In contrast to using a masked material, there is no cost for EarlyZ pass, you don't get shadows or -proper occlusion, but with the trade-off, you get the soft transitions in the material. - -Mesh Decals provide several differences to Deferred Decal Actors that you should be aware of: - -* There are fewer draw calls since large Deferred Decals often do front and back facing draw calls. -* It's quite faster since there are fewer pixels covered and flat back facing decals cover 0 pixels. -* You have the ability to do more complex projections since you can use a custom UV. -* You have the ability to have properly normal mapped decals wrapping around surfaces or stretching along splines. - -[OBJECT:ComparisonSlider] - [PARAM:before] - ![ Mesh Decal ](MeshDecal.png)(w:400) - [/PARAM] - [PARAM:after] - ![ Masked Material ](MaskedMaterial.png)(w:400) - [/PARAM] -[/OBJECT] - - -## Authoring Content - -Authoring content for use as Mesh Decal geometry is in-line with any model creation. Since this geometry will not rely on projection like a Deferred Decal Actor, the geometry -needs only to stay in front of the surface you want to affect. With this in mind, the decal geometry should "hug" the underlying surface, but it does not have to match it -very closely because there is already a small depth bias that is hard-coded to account for this small offset. Also, using a bit of geometry that feathers out from the decal can be good -to create the soft transitions for the decal that you cannot attain with a masked material. - -
-[REGION:imagetable] -| ![](MeshDecalAuthoring.png)(h:450) | ![](MeshDecalAuthoringComposite.png)(h:450) | -| --- | --- | -| Base Mesh and Decal Geometry (Isolated) | Composited Mesh | -[/REGION] -
- -Another thing to keep in mind when developing your content is that Mesh Decals can be a challenge with Levels of Detail (LOD) or long view distances when there is limited depth buffer -precision because geometry will intersect or not match up as intended. However, you can either change the mesh to account for this in most cases or you can use World Position Offset in -your material to adjust the offset without having to return to your modeling application. - -![](Offset.png)(w:500) - -[OBJECT:ComparisonSlider] - [PARAM:before] - ![ Offset Value: 0 ](2_Offset.png)(w:500) - [/PARAM] - [PARAM:after] - ![ Offset Value: -0.6 ](1_Offset.png)(w:500) - [/PARAM] -[/OBJECT] - -In this example, the decal geometry is close enough to the base mesh that the depth cannot account the offset. Using a small negative offset value pushes the geometry out just enough that it -doesn't intersect with the underlying geometry. - -## Limitations - -* There is no artist specified sort order. -* Tangent Space support is not yet implemented. -* Shader Overdraw/Overdraw functionality is missing. -* There is no easily adjustable DepthBias. Currently, you have to use an offset in the mesh from the surface it's above, or control with World Position Offset in the Material. -* Sort by depth to avoid artifacts when there are many layers overlapping. -* Material Editor Preview is not visible. -* Material Editor does not currently show the correct instructions count since it assumes base pass usage. -* DBuffer and non-DBuffer use the same container. -* Parallel Rendering isn't yet hooked up. There are some CPU savings if this feature is used extensively. - -## Using Mesh Decal Materials - -In the following steps, we will enable Dbuffer Decals for our project so that we can take advantage of lighting features for our decal material and we'll create a basic -Deferred Decal Material that can be applied to our Static Mesh. - -### Required Files - -In order to follow along with this How-To, you will need to download, extract, and then import to UE4 the following FBX and Texture files. If you are unfamiliar with how to do this please -check out [How to Import Static Meshes Guide](Engine/Content/ImportingContent/ImportingMeshes) and [How to Import Texture Guide](Engine/Content/ImportingContent/ImportingTextures) for more -information about how to go about doing this. - -**[Required Textures Download](MeshDecalAssets.zip)** (Right - Click Save as) - - -### Enabling DBuffer Decals for your Project - -1. In the **Edit** menu, click on **Project Settings** to view the Unreal Editor options. - - ![](ProjectSettingsMenu.png)(w:250) -1. Under the **Engine** heading, select the **Rendering** section and locate the **Lighting** category that contains various Lighting options. - - [REGION:lightbox] - [![](ProjectSettings.png)(w:700)](ProjectSettings.png) - [/REGION] -1. Now, you can toggle the **DBuffer Decals** option to use lighting features with your Deferred Decals. - - ![](EnableDBufferDecal.png)(w:350) - -1. Before you'll be able to use this feature, you'll first need to **Restart the Editor**. - - ![](RestartTheEditor.png)(w:550) - - -### Creating a Basic Deferred Decal - -1. In the **Content Browser**, select the **Add New** button and choose the option for **Material** to create a new Material. Make sure you give your Material a name that will be easy to locate later. -For the purpose of this how-to, I have named mine "M_MeshDecal." - - ![](AddNewMaterial.png)(w:300) - -1. Now, select your **Material** and double-click it to open it. Once the Material Editor opens, start by setting the following attributes in the **Details** panel so that it can be used as a Deferred Decal. - - * **Material Domain:** Deferred Decal - * **Blend Mode:** Translucent - * **Decal Blend Mode:** DBuffer Translucent Color, Normal, Roughness - -1. Next, you'll need to setup your material using the textures in the **Required Files** section of this page. There are three textures in the .zip file that we will need for this step; a diffuse, mask, and normal texture. -Once you've imported these textures, select them from the **Content Browser** and drag them into the Material Editor Graph. - - ![](MaterialGraph1.png)(w:400) - - Now, plug in the outputs of the Texture Sample nodes into their corresponding inputs on the Main Material node. For the Mask texture,"T_MeshDecalDamage_M", be sure to use the **Blue Channel** output when - plugging into the Opacity Mask input. This will make sure the blue values in the texture are used as the maskfor what should be visible. - - ![](MaterialGraph2.png)(w:400) -1. Right-click in the Material Graph and type in "Constant" or hold down the "1" key and click in the graph to add a **Constant** value node. Plug this into your **Roughness** input and give it a default value of **0.7**. - - ![](MaterialGraph3.png)(w:400) -1. Before finishing up, we'll need a way to control the offset of the decal geometry from the base mesh to prevent or lessen any artifacts that can occur due to depth precision. Add the following nodes to your Material Graph -and plug the output of the **Multiply** node into the **World Position Offset** input of the Main Material node. - - ![](MaterialGraph4.png)(w:400) - - Once you've done this, you're Material Graph should look similar to this: - - [REGION:lightbox] - [![](FinalMaterialGraph.png)(w:400)](FinalMaterialGraph.png) - [/REGION] -1. With your Deferred Decal Material complete, place the Static Mesh "SM_MeshDecal", which is included in the Required Files .zip, into your level and apply the Material **M_MeshDecal** to Element 0 -of the Static Mesh's Material slots. For the Base Mesh's Material you can assign any material or even just a basic color to Element 1 for the purposes of this demonstration. You should now have something -that looks similar to our example below. - - ![](MeshDecal.png)(w:400) - - -## End Result - -Now that you've set up and seen how to create your own Materials to use with a Mesh Decal, you should be confident in authoring your own assets in your modeling applications and creating your own Materials that take -full advantage of lighting for use with Mesh Decals applied. diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/HowTo/MeshDecals/MeshDecals.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/HowTo/MeshDecals/MeshDecals.JPN.udn deleted file mode 100644 index 7c5ab2407a17..000000000000 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/HowTo/MeshDecals/MeshDecals.JPN.udn +++ /dev/null @@ -1,167 +0,0 @@ -INTSourceChangelist:3346002 -Availability:Docs -Title:メッシュ デカールの使用方法 -Description:メッシュ デカールの設定方法および使用方法について説明します。 -Crumbs: -parent:Engine/Rendering/Materials/HowTo -type: reference -tags:Materials -version:4.15 -skilllevel:intermediate - -[TOC (start:2 end:4)] - - -アンリアル エンジン 4 でメッシュ デカールがサポートされるようになりました。 -これにより、スタティクメッシュおよびスケルタルメッシュに追加した詳細に対して、別のサーフェス ジオメトリ上でディファード デカールのプロパティが使用できます。ディファード デカールはプロジェクションに依存するので、 -投影先のサーフェスにそろっていない場合は、シアおよび変形が生じる平面サーフェイスの詳細にほぼ限られます。メッシュ デカールは、シンプルなプロジェクションを追わずに -エッジの周囲をラップするジオメトリやスプライン メッシュと一緒に使用し、キャラクターの外見を美しくすることができます。 - - -## メッシュ デカールとマスク付きマテリアル - -メッシュ デカールは、透過ブレンド モードとディファード デカールを混ぜたものです。 -不透明なジオメトリがレンダリングされた後、深部まではレンダリングせず、GBuffer または DBuffer の更新を行います。マスク付きマテリアルの使用とは対照的に、EarlyZ pass の負荷はかからず、 -シャドウあるいは適切なオクルージョンは得ませんが、その代わりマテリアルがソフトに変形します。 - -メッシュ デカールは、Deferred Decal アクタとは以下の点で異なります。 - -* 大きいディファード デカールは、正面向きと後ろ向きの描画コールをするので、描画コールは少なくなります。 -* カバーするピクセルも減り、背面が平らなデカールはピクセルを全くカバーしないので、かなり速くなります。 -* カスタム仕様の UV を使用するので、より複雑なプロジェクションの実行が可能になります。 -* サーフェスの周りをラップしたり、スプラインに沿って伸び、正しく法線マップ化されたデカールが作成できます。 - -[OBJECT:ComparisonSlider] - [PARAM:before] - ![ Mesh Decal ](MeshDecal.png)(w:400) - [/PARAM] - [PARAM:after] - ![ Masked Material ](MaskedMaterial.png)(w:400) - [/PARAM] -[/OBJECT] - - -## コンテンツのオーサリング - -コンテンツをメッシュ デカール ジオメトリとして使用するオーサリングは、すべてのモデル作成と一致しています。このジオメトリはディファード デカール アクタのようにプロジェクションに依存はしないので、 -ジオメトリは影響を与えたいサーフェスの正面にさえあれば良いです。このことを踏まえた上で、この小さなオフセットの主な原因となる小さな深度バイアスが既にあるので、 -デカール ジオメトリは下層のサーフェスには合わせますが、そこまでぴったり一致する必要はありません。さらに、デカールの境界をぼかすジオメトリを少し使うと、 -マスク付きマテリアルでは実現できないデカール用の柔らかいトランジションを作成することができます。 - -
-[REGION:imagetable] -| ![](MeshDecalAuthoring.png)(h:450) | ![](MeshDecalAuthoringComposite.png)(h:450) | -| --- | --- | -| 基本メッシュとデカール ジオメトリ (個々) | 合成したメッシュ | -[/REGION] -
- -ジオメトリは交差してしまったり、思い通りにぴったりには一致しないため、深度バッファ精度には限度があります。 -従って、メッシュ デカールは LOD あるいは長い表示距離が難しいということも覚えておくと良いでしょう。ただしほとんどの場合は、メッシュを変更すれば解決しますし、 -マテリアルに World Position Offset を使えばモデリング アプリケーションに戻らずにオフセットの調節ができます。 - -![](Offset.png)(w:500) - -[OBJECT:ComparisonSlider] - [PARAM:before] - ![ Offset Value: 0 ](2_Offset.png)(w:500) - [/PARAM] - [PARAM:after] - ![ Offset Value: -0.6 ](1_Offset.png)(w:500) - [/PARAM] -[/OBJECT] - -この例では、デカール ジオメトリは、基本メッシュに近すぎて、深度がオフセットを考慮できません。小さな負のオフセット値を使うと、ジオメトリを十分押し出すので、 -下層のジオメトリと交わりません。 - -## 制限事項 - -* アーティストはソート順序を指定しません。 -* タンジェント空間はまだサポートされていません。 -* Shader Overdraw/Overdraw 機能がついていません。 -* 深度バイアスの調整が簡単ではありません。現在、上にあるサーフェスからメッシュのオフセットを使用するか、マテリアルの World Position Offset で調整しなければなりません。 -* レイヤー オーバーラップが多い場合は、アーティファクトを避けるために深度でソートします。 -* マテリアル エディタ プレビューは表示されません。 -* マテリアル エディタはベース パスの使用を前提としているので、正しい命令数は表示しません。 -* DBuffer も non-DBuffer も同じコンテナを使用します。 -* 並列レンダリングはまだ組み込まれていません。この機能を広範囲に使用すると CPU 負荷を若干抑えることができます。 - -## メッシュ デカール マテリアルの使用方法 - -デカール マテリアルにライティング機能を使って、スタティックメッシュに適用できる基本的なディファード デカール マテリアルが作成できるように -プロジェクト用に Dbuffer Decal を有効にするには、以下の手順に従います。 - -### 必要なファイル - -操作ガイドに従って作業するために、まず以下の FBX およびテクスチャ ファイルをダウンロード、展開して UE4 にインポートしてください。操作方法がよく分からない場合は、 -[スタティックメッシュのインポート方法](Engine/Content/ImportingContent/ImportingMeshes) and [テクスチャのインポート方法](Engine/Content/ImportingContent/ImportingTextures) で -詳細を確認してください。 - -**[必要なテクスチャをダウンロード](MeshDecalAssets.zip)** (右クリックして [Save as (名前を付けて保存)] をクリック) - - -### プロジェクトで DBuffer Decals を有効にする - -1. **[Edit (編集)]** メニューで **[Project Settings (プロジェクト設定)]** をクリックして [Unreal Editor] オプションを表示します。 - - ![](ProjectSettingsMenu.png)(w:250) -1. 見出し **[Engine]** の下の **[Rendering]** セクションを選択し、各種ライティング オプションのある **[Lighting]** カテゴリを展開します。 - - [REGION:lightbox] - [![](ProjectSettings.png)(w:700)](ProjectSettings.png) - [/REGION] -1. 次に **[DBuffer Decals]** オプションを Deferred Decals でライティング機能を使用するように切り替えます。 - ![](EnableDBufferDecal.png)(w:350) - - 1. この機能を使えるようにするには、まず **エディタを再起動** する必要があります。 - - ![](RestartTheEditor.png)(w:550) - - - -### 基本のディファード デカールを作成する - -1. **コンテンツ ブラウザ** で **[Add New (新規追加)]** ボタンを選択し、**[Material]** のオプションを選択して、マテリアルを新規作成します。マテリアルには、後で場所が分かりやすいような名前を付けるようにしてください。 -ここでは学習内容を踏まえて、「M_MeshDecal」という名前を付けておきました。 - - ![](AddNewMaterial.png)(w:300) - -1. **Material** を選択し、ダブルクリックして開きます。マテリアル エディタを開いて、Deferred Decal で使えるように **[Details (詳細)]** パネルの以下の属性の設定から開始します。 - - * **Material Domain:** Deferred Decal - * **Blend Mode:** Translucent - * **Decal Blend Mode:** DBuffer Translucent Color, Normal, Roughness - -1. 次に、このページの **[Required Files]** セクションのテクスチャを使って、マテリアルを設定する必要があります。そのステップに必要なディフューズ、マスク、法線テクスチャの 3 つのテクスチャが入っている .zip ファイルがあります。 -両方のテクスチャをインポートしたら、これらを **コンテンツ ブラウザ** へドラッグして、マテリアル エディタ グラフへドロップします。 - - ![](MaterialGraph1.png)(w:400) - - 最後に MS_VertexAnimationTools_MorphTargets マテリアル関数の出力を Main Material ノードの関連する入力値に接続します。Mask テクスチャ "T_MeshDecalDamage_M" の場合は、 - Opacity Mask 入力に挿し込んだ時は **Blue Channel** 出力を使うようにしてください。これにより、テクスチャの中の青の値が表示されるべき maskfor として確実に使用されるようになります。 - ![](MaterialGraph2.png)(w:400) - -1. マテリアル グラフ内をクリックして「Constant」と入力するか、"1" キーを長押ししてグラフ内をクリックすると **Constant** 値ノードが追加されます。これを **Roughness** 入力に接続し、デフォルト値を **0.7** にします。 - - ![](MaterialGraph3.png)(w:400) -1. 仕上げ前に、深度精度が原因のアーティファクトを防ぐ、または減らすためにデカール ジオメトリのオフセットを基本メッシュから調節する方法が必要になります。以下のノードをマテリアル グラフに追加して、 -**Multiply** ノードの出力をメイン マテリアル ノードの **World Position Offset** 入力に接続します。 - - ![](MaterialGraph4.png)(w:400) - - マテリアル グラフはこのような感じになっているはずです。 - - [REGION:lightbox] - [![](FinalMaterialGraph.png)(w:400)](FinalMaterialGraph.png) - [/REGION] -1. ディファード デカール マテリアルが完了したので、Required Files .zip の中のスタティックメッシュ "SM_MeshDecal" をレベルに配置して、Material **M_MeshDecal** を -スタティックメッシュのマテリアル スロットの Element 0 に適用します。基本メッシュのマテリアルの場合は、デモ目的で、すべてのマテリアルもしくは基本色を Element 1 に割り当てることができます。以下の例のように -なるはずです。 - - ![](MeshDecal.png)(w:400) - - -## 結果 - -メッシュ デカールと使用する独自のマテリアルの設定および作成方法を説明したので、 -モデリング アプリケーションで自分のアセットをオーサリングし、適用されたメッシュ デカールを使うためにライティングを存分に利用したマテリアルの作成に自信を持てるはずです。 diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/HowTo/MeshDecals/MeshDecals.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/HowTo/MeshDecals/MeshDecals.KOR.udn deleted file mode 100644 index 94be154fe8e0..000000000000 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/HowTo/MeshDecals/MeshDecals.KOR.udn +++ /dev/null @@ -1,167 +0,0 @@ -INTSourceChangelist:3346002 -Availability:Docs -Title: 메시 데칼 사용법 -Description: 메시 데칼 구성 및 사용법 안내입니다. -Crumbs: -parent: Engine/Rendering/Materials/HowTo -type: reference -tags:Materials -version:4.15 -skilllevel:intermediate - -[TOC (start:2 end:4)] - - -언리얼 엔진 4 에는 이제 Mesh Decal (메시 데칼)이 지원되어 별도의 표면 지오메트리에 디퍼드 데칼 프로퍼티를 사용할 수 있어 -스태틱 / 스켈레탈 메시에 디테일을 추가할 수 있습니다. 디퍼드 데칼은 투영에 의존하므로, 투영 대상 표면에 일치하지 않으면 잘리고 뒤틀리는 -평면 표면 디테일에 거의 제한됩니다. 메시 데칼은 단순 투영을 따르지 않는 데칼을 제공해 주는 대신 -에지를 감싸는 지오메트리나 스플라인 메시와 함께 사용할 수 있으며, 캐릭터의 외형을 강화시켜 줍니다. - - -## 메시 데칼 VS 마스크드 머티리얼 - -메시 데칼은 뎁스 렌더링은 하지 않지만 불투명 지오메트리 렌더 후 GBuffer 와 DBuffer 업데이트를 한다는 점에서 반투명 블렌드 모드와 디퍼드 데칼을 섞은 것입니다. -마스크드 머티리얼을 사용한 것과 비교하면, EarlyZ 패스 비용이 없고, 그림자나 적절한 오클루전도 없지만, -그에 대한 균형으로 머티리얼에 부드러운 전환이 가능합니다. - -메시 데칼은 Deffered Decal Actor (디퍼드 데칼 액터)에 비해 주의해야 할 차이점이 몇 가지 있습니다: - -* 커다란 디퍼드 데칼은 종종 앞면과 뒷면 드로 콜을 하므로 드로 콜 수가 적습니다. -* 커버되는 픽셀 수가 적고 평평한 뒷면 데칼은 0 픽셀을 커버하므로 꽤 빠릅니다. -* 커스텀 UV 를 사용할 수 있어 보다 복잡한 투영이 가능합니다. -* 스플라인 상에 늘어나거나 표면을 감싸도록 제대로 노멀 매핑된 데칼을 가질 수 있습니다. - -[OBJECT:ComparisonSlider] - [PARAM:before] - ![ 메시 데칼 ](MeshDecal.png)(w:400) - [/PARAM] - [PARAM:after] - ![ 머스크드 머티리얼 ](MaskedMaterial.png)(w:400) - [/PARAM] -[/OBJECT] - - -## 콘텐츠 제작 - -메시 데칼 지오메트리로 사용할 콘텐츠를 제작하는 것은 모델 생성과 밀접한 관계가 있습니다. 이 지오메트리는 디퍼드 데칼 액터처럼 투영에 의존하지 않으므로, 지오메트리는 -영향을 주고자 하는 표면 앞에만 있으면 됩니다. 이 점을 염두에 두고, 데칼 지오메트리는 아래 놓인 표면을 "hug"해야 하지만, 매우 근접하게 일치할 필요는 없습니다. -이런 작은 오프셋을 위해 이미 약간의 뎁스 바이어스가 하드코딩되어 있기 때문입니다. 또한, 데칼에서 점차 사라지는 지오메트리를 약간 사용하면 -마스크드 머티리얼로는 얻을 수 없는 데칼의 부드러운 전환 효과를 내는 데 좋습니다. - -
-[REGION:imagetable] -| ![](MeshDecalAuthoring.png)(h:450) | ![](MeshDecalAuthoringComposite.png)(h:450) | -| --- | --- | -| 베이스 메시 및 데칼 지오메트리 (고립) | 합성 메시 | -[/REGION] -
- -또 한가지 콘텐츠 개발시 염두에 두어야 할 점은, 메시 데칼은 뎁스 버퍼 정밀도 제한으로 인해 레벨 오브 디테일(LOD)이나 원거리에서 볼 때 문제가 될 수 있습니다. -지오메트리가 교차하거나 의도대로 일치하지 않기 때문입니다. 하지만 대부분의 경우 메시가 이 부분을 고려하도록 변경하거나, 머티리얼의 월드 포지션 오프셋을 사용하여 오프셋을 조절하면 -모델링 프로그램으로 돌아가 별도의 작업을 하지 않아도 됩니다. - -![](Offset.png)(w:500) - -[OBJECT:ComparisonSlider] - [PARAM:before] - ![ 오프셋 값: 0 ](2_Offset.png)(w:500) - [/PARAM] - [PARAM:after] - ![ 오프셋 값: -0.6 ](1_Offset.png)(w:500) - [/PARAM] -[/OBJECT] - -이 예제에서, 뎁스가 오프셋을 처리하지 못하는 베이스 메시에 데칼 지오메트리가 충분히 가까이 있습니다. 작은 음수 오프셋 값을 사용하면 아래 있는 지오메트리와 교차하지 않을 만큼 지오메트리를 -약간 밀어줍니다. - -## 한계점 - -* 소트 순서를 아티스트가 지정할 수 없습니다. -* 탄젠트 스페이스 지원이 아직 구현되지 않았습니다. -* Shader Overdraw/Overdraw 함수 기능이 빠져있습니다. -* 쉽게 조절 가능한 DepthBias 가 없습니다. 현재 메시 위의 표면에서 메시의 오프셋을 사용하거나, 머티리얼의 월드 포지션 오프셋으로 제어해야 합니다. -* 다수의 레이어가 겹치는 경우 뎁스로 소트하여 부작용을 피합니다. -* 머티리얼 에디터 프리뷰가 보이지 않습니다. -* 머티리얼 에디터에 현재 올바른 인스트럭션 수가 표시되지 않습니다. 베이스 패스 사용량을 추정하기 때문입니다. -* DBuffer 및 non-DBuffer 가 같은 컨테이너를 사용합니다. -* 병렬 렌더링이 아직 후킹되지 않았습니다. 이 기능을 적극 활용하면 CPU 가 약간 절약됩니다. - -## 메시 데칼 머티리얼 사용 - -여기서는 프로젝트에 DBuffer Decal 옵션을 켜 데칼 머티리얼에 라이팅 기능 혜택을 활용하고 스태틱 메시에 적용할 수 있는 -기본적인 디퍼드 데칼 머티리얼을 만들어 보겠습니다. - -### 필수 파일 - -이 안내서를 따라하기 위해서는 다음 FBX 및 텍스처 파일을 다운로드하고 압축을 푼 뒤 UE4 에 임포트해야 합니다. -그 방법이 익숙치 않은 경우 [](Engine/Content/ImportingContent/ImportingMeshes) 및 [](Engine/Content/ImportingContent/ImportingTextures) 문서를 -참고하세요. - -**[필수 텍스처 다운로드](MeshDecalAssets.zip)** (우클릭 - 다른 이름으로 저장) - - -### 프로젝트에 DBuffer Decals 켜기 - -1. **편집** 메뉴에서 **프로젝트 세팅** 을 선택하여 언리얼 에디터 옵션을 엽니다. - - ![](ProjectSettingsMenu.png)(w:250) -1. **엔진** 제목줄 아래 **Rendering** 섹션에서 **Lighting** 카테고리를 보면 다양한 Lighting 옵션이 있습니다. - - [REGION:lightbox] - [![](ProjectSettings.png)(w:700)](ProjectSettings.png) - [/REGION] -1. 여기서 **DBuffer Decals** 옵션을 체크하면 디퍼드 데칼과 함께 라이팅 기능을 사용할 수 있습니다. - - ![](EnableDBufferDecal.png)(w:350) - -1. 이 기능을 사용하기 위해서는 먼저 **에디터를 재시작** 해야 합니다. - - ![](RestartTheEditor.png)(w:550) - - -### 기본 디퍼드 데칼 제작 - -1. **콘텐츠 브라우저** 에서 **신규 추가** 버튼을 선택하고 **머티리얼** 옵션을 선택하여 새 머티리얼을 만듭니다. 나중에 쉽게 찾을 수 있도록 머티리얼에 이름을 지어주세요. -여기서는 M_MeshDecal 로 했습니다. - - ![](AddNewMaterial.png)(w:300) - -1. 이제 **머티리얼** 을 선택하고 더블클릭하여 엽니다. 머티리얼 에디터가 열리면 디퍼드 데칼로 사용할 수 있도록 **디테일** 패널에 다음 어트리뷰트 설정부터 합니다. - - * **Material Domain:** Deferred Decal - * **Blend Mode:** Translucent - * **Decal Blend Mode:** DBuffer Translucent Color, Normal, Roughness - -1. 다음, 이 페이지의 **필수 파일** 섹션의 텍스처를 사용하여 머티리얼 구성을 해야 합니다. .zip 파일에 있는 디퓨즈, 마스크, 노멀 세 개의 텍스처가 필요합니다. -이 텍스처 임포트를 완료했으면, **콘텐츠 브라우저** 에서 선택한 뒤 머티리얼 에디터 그래프에 끌어 놓습니다. - - ![](MaterialGraph1.png)(w:400) - - 이제 Texture Sample 노드의 출력을 메인 머티리얼 노드의 해당 입력에 연결합니다. 마스크 텍스처 T_MeshDecalDamage_M 의 경우 오파시티 마스크 입력에 연결할 때 **Blue Channel** 출력을 - 사용하도록 합니다. 그래야 보이는 것에 대한 마스크로 텍스처의 파랑 값을 사용합니다. - - ![](MaterialGraph2.png)(w:400) -1. 머티리얼 그래프에 우클릭한 후 Constant 라 입력하거나, "1" 키를 누르고 그래프를 클릭하여 **Constant** 노드를 추가합니다. 이것을 **러프니스** 입력에 연결하고 기본값을 **0.7** 로 설정합니다. - - ![](MaterialGraph3.png)(w:400) -1. 마무리하기 전 베이스 메시에서 데칼 지오메트리의 오프셋 또는 뎁스 정밀도로 인해 발생할 수 있는 부작용을 제어할 수 있는 방법이 필요합니다. 머티리얼 그래프에 다음 노드를 추가하고 -**Multiply** 노드의 출력을 메인 머티리얼 노드의 **월드 포지션 오프셋** 입력에 연결합니다. - - ![](MaterialGraph4.png)(w:400) - - 완료했으면 머티리얼 그래프는 다음과 같을 것입니다: - - [REGION:lightbox] - [![](FinalMaterialGraph.png)(w:400)](FinalMaterialGraph.png) - [/REGION] -1. 디퍼드 데칼 머티리얼이 완료되었으면, 필수 파일 .zip 에 포함된 SM_MeshDecal 스태틱 메시를 레벨에 배치한 뒤 스태틱 메시의 머티리얼 슬롯 중 엘리먼트 0 에 **M_MeshDecal** 머티리얼을 적용합니다. -베이스 메시의 머티리얼의 경우 엘리먼트 1 에 아무 머티리얼 또는 이 데모 목적 상 그냥 기본 컬러를 연결해도 됩니다. 아래 예제와 비슷한 것이 -생겨있을 것입니다. - - ![](MeshDecal.png)(w:400) - - -## 최종 결과 - -메시 데칼과 사용할 자체 머티리얼을 만들어 구성하는 법을 배우셨으니, 이제 모델링 어플리케이션에서 별도의 애셋을 만든 뒤 메시 데칼을 적용하고도 라이팅 장점을 최대한 활용하는 자체 머티리얼을 -제작하실 수 있을 것입니다. diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/IntroductionToMaterials/IntroductionToMaterials.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/IntroductionToMaterials/IntroductionToMaterials.JPN.udn index 8219d2a1d398..65ada66075bb 100644 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/IntroductionToMaterials/IntroductionToMaterials.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/IntroductionToMaterials/IntroductionToMaterials.JPN.udn @@ -1,5 +1,4 @@ -INTSourceChangelist:3304580 -Availability:Public +Availability:Public Title:マテリアルの基本概念 Crumbs: %ROOT%, Engine, Engine/Rendering/Materials Description:UE4 のマテリアルとその機能に関する入門書 diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/LightingModels/SubSurfaceProfile/SSSProfileLightingModel.INT.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/LightingModels/SubSurfaceProfile/SSSProfileLightingModel.INT.udn index 4e2bb7127c91..4fd986e09241 100644 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/LightingModels/SubSurfaceProfile/SSSProfileLightingModel.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/LightingModels/SubSurfaceProfile/SSSProfileLightingModel.INT.udn @@ -1,6 +1,6 @@ Availability:Public Title:Subsurface Profile Shading Model -Crumbs: %ROOT%, Engine, Engine/Rendering/Materials +Crumbs: %ROOT% Description:Description and technical details of the Subsurface Profile shading model available in Materials. Version: 4.9 parent:Engine/Rendering/Materials/LightingModels @@ -8,59 +8,36 @@ order:1 topic-image:sss_profile_topic.png type:overview tags:Materials +SkillLevel:Intermediate +[TOC(start:2 end:3)] -[TOC(start:2)] - -Unreal Engine 4 (UE4) now offers a shading method specifically for rendering realistic skin or wax surfaces called **Subsurface Profile**. -The Subsurface Profile shading method is similar to the Subsurface method, but with a key difference in how it renders: Subsurface Profile is based in **screen space**. This is because screen space rendering is more effective at displaying the subtle subsurface effects seen in human skin, where backscattering is a secondary effect only seen in few cases, such as ears. - - -The following document will cover what Subsurface Profiles are and how you can use them in your work. +Unreal Engine 4 (UE4) now offers a specific shading method for rendering realistic skin or wax surfaces, which is called **Subsurface Profile** shading. +The Subsurface Profile shading method is similar to the Subsurface method, but with a fundamental difference in how it renders: Subsurface Profile is based in **screen space**. This is because screen space rendering is a more effective to display the subtle subsurface effects seen in human skin, where backscattering is a secondary effect only seen in few cases, such as ears. In the following document will cover what Subsurface Profiles are and how you can use them in your work. [OBJECT:ComparisonSlider] - [PARAM:before] - ![Not using SubsurfaceProfile](Results_1.png)(w:700 convert:false) - [/PARAM] - [PARAM:after] - ![Using SubsurfaceProfile](Results_2.png)(w:700 convert:false) - [/PARAM] + [PARAM:before] + ![Not using SubsurfaceProfile](Results_1.png)(w:700 convert:false) + [/PARAM] + [PARAM:after] + ![Using SubsurfaceProfile](Results_2.png)(w:700 convert:false) + [/PARAM] [/OBJECT] - - [Region:note] -Special thanks to Lee Perry-Smith and his company [Infinite Realities] (http://ir-ltd.net ) for providing the 3D scanned head model and assistance. +Special thanks to Lee Perry-Smith and his company [Infinite Realities] (http://ir-ltd.net ) for their assistance with this documentation, also for providing the 3D scanned head model. [/region] - ## What is a Subsurface Profile -Subsurface Scattering Profile data can be created, shared, and saved in the **Content Browser**. The data is intended to be authored by artists, and controls the distance the light in the Subsurface should scatter, the color of the Subsurface, and the falloff color of the light once it has exited the object. This data can then be applied to a Subsurface Material. Subsurface Profile data can also be tweaked interactively, meaning that you do not need to re-compile the material to see the results of edits. - - - - - - +The Subsurface Scattering Profile data is an asset that can be created, shared, and saved in the **Content Browser**. The data is intended to be authored by artists and controls the distance the light in the Subsurface should scatter, the color of the Subsurface, and the falloff color of the light once it has exited the object. This data can then be applied to a Subsurface Material. Subsurface Profile data can also be tweaked interactively, meaning that you do not need to re-compile the material to see the results of edits. ## Enabling, Creating, and Using a Subsurface Profile -To use a Subsurface Profile in a Material, you must first set the Material to use a Subsurface Profile by setting the **Shading Model** to **Subsurface Profile** in the **Details** panel of the Material. You can override the Subsurface Profile that is used with the **Subsurface Profile** input. +There are many different ways of using Sub Surface profiles in UE4. In the following section, we will take a look at each of these ways. +### Creating A Subsurface Profile -[REGION:tip] -The default settings for the Subsurface Profile are close to Caucasian skin. Please note that this is just one component to realistic looking skin. _Always make sure the base color of your texture fits to your Subsurface scattering profile._ -[/REGION] - -![Enable SubsurfaceProfile](1.png) - - -The Subsurface Profile can also be overridden in a Material Instance. To do this, you first need to open the Material Instance that you wish to change. Then, in the **Details** section of the Material Instance, enable **Override Subsurface Profile** and then supply the Subsurface profile you want to use in the **Subsurface Profile** input. - -![](6.png) - -To create a Subsurface Profile, first **Right-Click** inside of the **Content Browser**. Then select the ** Materials & Textures** option and select the **Subsurface Profile** option. - +To create a Subsurface Profile, first Right-click inside of the **Content Browser**. Then select the ** Materials & Textures** option and then select the **Subsurface Profile** option. ![Create SubsurfaceProfile](2.png) [region:note] @@ -68,57 +45,93 @@ If no SubsurfaceProfile is specified, it uses the default, which is Caucasian hu [/region] -You can edit Subsurface Profiles by **Double-Clicking** on them with the **Left Mouse Button** in the **Content Browser** to open it up. +You can edit Subsurface Profiles by Double-clicking on them with the **Left Mouse Button** in the **Content Browser** to open it up. Once open, you can adjust the individual properties of the Subsurface Scattering Profile by either inputting a number using the keyboard or by using the **Left Mouse Button** to **Click** on the color bar to expose the color picker. - -![Tweak SubsurfaceProfile](3.png) - -* ** Scatter Radius:** The distance in world space units to perform the scatter. - -* ** Subsurface Color:** The Subsurface Color can be used as a weight for the Subsurface effect. Black means there is no Subsurface scattering. White means all lighting is entering the material and gets scattered around. A non-grayscale value gives more control over what color contributions are entering the surface, resulting in a more complex looking shading. +### Enabling Subsurface Profile +To use a Subsurface Profile in a Material, you must first enable it by setting the Materials **Shading Model** to **Subsurface Profile** in the **Details** panel of the Material. Once enabled, you can override the default Subsurface Profile that is used by inputting a new one into the **Subsurface Profile** input. +[REGION:tip] +The default settings for the Subsurface Profile are close to the Caucasian skin type. Please note that this is just one component to getting a realistic looking skin. _Always make sure the base color of your texture fits your Subsurface scattering profile._ +[/REGION] +![Enable SubsurfaceProfile](1.png) +The Subsurface Profile can also be overridden in a Material Instance. To do this go the **Details** pannel of the Material Instance and enable the **Override Subsurface Profile**. Once enabled, supply the Subsurface profile you want to use in the **Subsurface Profile** input. -* **Falloff Color:** The Falloff Color defines the material scattering color once the light has entered the material. You should avoid using a vivid color here if you want to get a more complex shading variation over area where you see the scattering. +![](6.png) [region:note] -Remember that the whole computation is energy-conserving, so it is not possible to create light through scattering. +Remember that the whole computation is energy-conserving, so it is not possible to create additional light through scattering. [/region] +## Material Input Channels + +The Screen Space Subsurface shading profile does not differ much from the Lit shading mode, with the main difference being that the Metallic input has been repurposed and is not available to be used. + +**Base Color Input:** The Base Color input is used as usual for Diffuse lighting. There is no extra Subsurface Scattering color as the Screen Space Subsurface Scatter is not supposed to change color or brightness, it is just redistributing the lighting to nearby pixels. +So, if a material should scatter in a specific color, it needs to be expressed as part of the Base Color. +The Base Color should be the final color as if the material is viewed from a large distance where the scattering cannot be distinguished from diffuse lighting. + +[REGION:note] +Human skin is a thin layer that blocks a certain amount and color of light, and it covers vibrant, red-colored flesh below its surface. The visible scatter distance for light-colored human skin is about 1.2 CM. +[/region] + +**Metallic Input:** The Metallic input channel is not available when using a Subsurface Profile because the GBuffer space for the Metallic input has been repurposed to accommodate the Subsurface Profile data. + +**Opacity Input:** The Opacity input channel is used to mask the Subsurface scattering contribution. +It works by using a value in the 0 to 1 range to allow for smooth transitions between different areas of Subsurface scattering intensity, where 0 is no scattering, and 1 is full scattering. + + +To better control where the Subsurface scattering is stronger or weaker, it is best to use a mask texture. +Areas in the mask Texture that have values closer to 1, or white, will have the strongest Subsurface scattering effect while areas that are closer to 0, or black, will have less of an effect. +Adjusting the Subsurface Color will help to compensate if areas get too dark. Remember that using brighter colors results in more Subsurface scattering. + +Here you can see how the mask can be used to render two surface types with one material. Note that the transition is soft and not limited to triangle borders. + +[REGION:lightbox] +[![](4.png)(w:920 convert:false)](4.png) +[/REGION] +[REGION:caption] +Click for full image. +[/REGION] + ## Full-Resolution Skin Shading UE4 supports full-resolution skin shading for the Subsurface Profile shading model. This provides high-fidelity lighting for surface details, such as pores and wrinkles. + [OBJECT:ComparisonSlider] - [PARAM:before] - ![Checkboard Rendered Skin Layout](FRSH_Checkboard.png) - [/PARAM] - [PARAM:after] - ![Full Resolution Skin](FRSH_FullResolution.png) - [/PARAM] + [PARAM:before] + ![Checkboard Rendered Skin Layout](FRSH_Checkboard_Zoom.png) + [/PARAM] + [PARAM:after] + ![Full Resolution Skin](FRSH_FullResolution_Zoom.png) + [/PARAM] [/OBJECT] -[OBJECT:ComparisonSlider] - [PARAM:before] - ![Checkboard Rendered Skin Layout](FRSH_Checkboard_Zoom.png) - [/PARAM] - [PARAM:after] - ![Full Resolution Skin](FRSH_FullResolution_Zoom.png) - [/PARAM] -[/OBJECT] - -Previously, lighting on skin was represented using a checkerboard pattern, where half the pixels used only Diffuse lighting and the other half used Specular lighting. The lighting was recombined during a final Subsurface profile fullscreen pass. That approach gave good results for Subsurface lighting (which is low-frequency by nature), but it could result in lower-fidelity lighting for surface details. With the new approach, every pixel contains Diffuse and Specular lighting information, packed into an RGBA encoding. This allows us to reconstruct full-resolution lighting during the final Subsurface profile fullscreen pass, giving better results for surface details and more stable behavior with Temporal Antialiasing. +Previously, lighting on the skin was represented using a checkerboard pattern, where half the pixels used only Diffuse lighting and the other half used Specular lighting. The lighting was recombined during a final Subsurface profile fullscreen pass. That approach gave good results for Subsurface lighting (which is low-frequency by nature), but it could result in lower-fidelity lighting for surface details. With the new approach, every pixel contains Diffuse and Specular lighting information, packed into an RGBA encoding. This allows us to reconstruct full-resolution lighting during the final Subsurface profile fullscreen pass, giving better results for surface details and more stable behavior with Temporal Antialiasing. ### Compatibility -Full-resolution skin shading requires at least a 64-bit scene color format with a full alpha channel. The default FloatRGBA scene color format works fine, but 32-bit representations such as FloatRGB are not supported. If the scene color format is not compatible with full resolution skin, we fall back to checkerboard-based lighting. -This behaviour can be overridden using the **r.SSS.Checkerboard** console variable. The possible values for this are: -* 0: Checkerboard disabled (full resolution) -* 1: Checkerboard enabled (old behavior) -* 2: Automatic (default) - Full resolution lighting will be used if the scene color pixelformat supports it +Full-resolution skin shading requires at least a 64-bit scene color format with a full alpha channel. The default FloatRGBA Scene Color format works fine, but 32-bit representations such as FloatRGB are not supported. If the scene color format is not compatible with full resolution skin, we fall back to checkerboard-based lighting. + +This behavior can be overridden using the **r.SSS.Checkerboard** console variable. The possible values for this are: + +|Property Name| Value|Description| +|-------------|------------|------| +|**r.SSS.Checkerboard**|0|Checkerboard disabled| +|**r.SSS.Checkerboard**|1|Checkerboard enabled (old behavior)| +|**r.SSS.Checkerboard**|2|Automatic (default) - Full resolution lighting will be used if the scene color pixel format supports it.| ### Limitations @@ -127,54 +140,23 @@ It * Metallic Materials * Emissive Materials -These features will work, but you may notice differences in output compared to checkerboard due to the packed RGBA diffuse/specular encoding. It is possible to work around some issues when authoring materials by setting the **Opacity** to **0** in areas where skin shading is not desirable. Pixels with an Opacity of zero are treated as default lit for the purposes of shading. +These features will work, but you may notice differences in output compared to checkerboard due to the packed RGBA diffuse/specular encoding. It is possible to work around some issues when authoring materials by setting the **Opacity** to **0** in areas where skin shading is not desirable. Pixels with an Opacity of zero are treated as default lit for shading. [region:note] -Masking non-opaque pixels in this way is also worthwhile for performance reasons, since these pixels are bypassed by the Subsurface Postprocess. +Masking non-opaque pixels in this way is also worthwhile for performance reasons since these pixels are bypassed by the Subsurface Postprocess. [/region] ### Performance Considerations -If your title has a 64-bit scene color format, full-resolution Subsurface lighting will typically be faster than checkerboard due to the reduced number of Texture fetches. However, if your title has a 32-bit scene color, the performance gain from the reduced Texture bandwidth will likely outweigh the benefits (although this is hardware dependent). - -## Material Input Channels - -The Screen Space Subsurface shading profile does not differ much from the Lit shading mode, with the main difference being that the Metallic input has been repurposed and is not available to be used. - -**Base Color Input:** The Base Color input is used as usual for Diffuse lighting. There is no extra Subsurface Scattering color as the Screen Space Subsurface scatter is not supposed to change color or brightness, it is just redistributing the lighting to nearby pixels. -So, if a material should scatter in a specific color, it needs to be expressed as part of the Base Color. -The Base Color should be the final color as if the material is viewed from a large distance where the scattering cannot be distinguished from diffuse lighting. - -[REGION:note] -Human skin is a thin layer that blocks a certain amount and color of light, and it covers vibrant, red-colored flesh below its surface. The visible scatter distance in light-colored human skin is about 1.2 cm. - -[/region] - -**Metallic Input:** The Metallic input channel is not available when using a Subsurface Profile because the GBuffer space for the Metallic input has been repurposed to accommodate the Subsurface Profile data. - -**Opacity Input:** The Opacity input channel is used to mask the Subsurface scattering contribution. -It works by using a value in the 0 to 1 range to allow for smooth transitions between different areas of Subsurface scattering intensity, where 0 is no scattering and 1 is full scattering. - - -In order to better control where the Subsurface scattering is stronger or weaker, it is best to use a mask texture. -Areas in the mask texture that have values closer to 1, or white, will have the strongest Subsurface scattering effect while areas that are closer to 0, or black, will have less of an effect. -Adjusting the Subsurface Color will help to compensate if areas get too dark. Remember that using brighter colors results in more Subsurface scattering. - -Here you can see how the mask can be used to render two surface types with one material. Note that the transition is soft and not limited to triangle borders. - -[REGION:lightbox] -[![](4.png)(w:920 convert:false)](4.png) -[/REGION] - - +If your title has a 64-bit scene color format, full-resolution Subsurface lighting will typically be faster than checkerboard due to the reduced number of Texture fetches. However, if your title has a 32-bit scene color, the performance gain from the reduced Texture bandwidth will likely outweigh the benefits (although this is hardware dependent). ## Technical Details -At the moment, the Subsurface scattering profile shading model does not differ much from Lit (Lambert diffuse, GGX for specular, no Metallic). Most of the effect happens in a post process after all lighting has been computed. +Currently, e Subsurface scattering profile shading model does not differ much from Lit (Lambert diffuse, GGX for specular, no Metallic). Most of the effect happens in a post process after all lighting has been computed. [REGION:note] -The Subsurface scattering profile is based on work from [Jorge Jimenez](http://www.iryoku.com/). Make sure to check out his webpage for many useful tips on how to make your 3D images look more realistic. +The Subsurface scattering profile is based on work from [Jorge Jimenez](http://www.iryoku.com/). Make sure to check out his web page for useful tips on how to make your 3D images look more realistic. [/REGION] We separate the non-specular (non-view dependent) lighting contributions to support a specular on top of Subsurface Material and down sample for better performance. @@ -182,27 +164,33 @@ Similar to a Gaussian blur, we filter the image with a two-pass (assuming a sepa The filter kernel depends on the Subsurface scattering profile which is stored in the GBuffer (Max 255 active profiles per scene). The kernel has colored weights and specific sample positions which can be scaled in the profile (defined in units/cm). In the final step, we recombine the scattered light contribution with the full resolution image. To separate the view-dependent and non-view-dependent lighting, we store a weighting value in the scene color alpha channel. -This approximation requires a 64 bit render target (see r.SceneColorFormat) and this approximation works for most cases. +This approximation requires a 64-bit render target (see r.SceneColorFormat), and this approximation works for most cases. -It successfully takes out the specular but you get a more desaturated non view dependent color for those specular pixels. This can be improved by using two 32-bit render targets for all lighting passes. That has the same memory bandwidth but on some hardware this might be slower. This might be something we want to change (added code complexity). +It successfully takes out the specular, but you get a more desaturated on view dependent color for those specular pixels. This can be improved by using two 32-bit render targets for all lighting passes. That has the same memory bandwidth, but on some hardware, this might be slower. This might be something we want to change (added code complexity). Here we have an example where the Specular was removed before the blurring was applied. Notice how the Specular reflection is crisp and smooth in the end image (image on the far right). This is the effect we wanted to achieve. [REGION:lightbox] [![](Good_Combination.png)(w:920 convert:false)](Good_Combination.png) [/REGION] +[REGION:caption] +Click for full image. +[/REGION] Here we have an example where the Specular was not removed before the blurring was applied. Notice how the Specular reflection is dull and looks a bit stretched in the end image (image on the far right). This is not the correct way to render this effect. [REGION:lightbox] [![](Bad_Combination.png)(w:920 convert:false)](Bad_Combination.png) [/REGION] +[REGION:caption] +Click for full image. +[/REGION] ## Scalability and Console Commands There are some scaling and performance console commands that you can use to help you get a good trade off between high quality visuals and better performance. -**r.SSS.Scale**: Can be used to scale the effect for quick experiments. Setting this to **0** will disable the effect. Setting numbers higher than 0 will increase the effect which can be seen in the image sequence below. +**r.SSS.Scale**: Can be used to scale the effect for quick experiments. Setting this to **0** will disable the effect. Setting numbers higher than 0 will increase the effect that can be seen in the image sequence below. [INCLUDE:Engine\Rendering\Materials\LightingModels\SubSurfaceProfile\#SSRScale] @@ -210,12 +198,12 @@ There are some scaling and performance console commands that you can use to help **r.SSS.SampleSet**: Sets the number of samples used. Decreasing this will cause the effect to run faster. However, this will mean that the effect will have a lower quality, and rendering artifacts could show up. [OBJECT:ComparisonSlider] - [PARAM:before] - ![r.SSS.SampleSet = 0](RSampleSet_Off.png) - [/PARAM] - [PARAM:after] - ![r.SSS.SampleSet = 1](RSampleSet_On.png) - [/PARAM] + [PARAM:before] + ![r.SSS.SampleSet = 0](RSampleSet_Off.png) + [/PARAM] + [PARAM:after] + ![r.SSS.SampleSet = 1](RSampleSet_On.png) + [/PARAM] [/OBJECT] The following image shows a bit more of the internals of the system. This view can be enabled using **ShowFlag.VisualizeSSS 1**. @@ -223,16 +211,27 @@ The following image shows a bit more of the internals of the system. This view c [REGION:lightbox] [![](5.png)(w:920 convert:false)](5.png) [/REGION] +[REGION:caption] +Click for full image. +[/REGION] While the Subsurface scattering profile shading model is a step forward when it comes to rendering skin, there are some limitations in what it can do. _Please note that as this system becomes more and more polished, this list could change._ * The feature does not work in the non-deferred (mobile) rendering mode. -* Setting a large screen scatter radius will show banding artifacts in extreme lighting conditions. +* Setting a large screen to scatter radius will show banding artifacts in extreme lighting conditions. * Currently, there is no backscatter of light. -* Currently, a grey outline appears when SSS Materials are occluded by non-SSS Materials. +* Currently, a gray outline appears when non-SSS Materials occlude SSS Materials. +## Subsurface Profile Property Referance +![Tweak SubsurfaceProfile](3.png) + +|Property Name| Description| +|-------------|------------| +|**Scatter Radius:**|The distance in world space units to perform the scatter.| +|**Subsurface Color:**|The Subsurface Color can be used as a weight for the Subsurface effect. Black means there is no Subsurface scattering. White means all lighting is entering the material and gets scattered around. A non-grayscale value gives more control over what color contributions are entering the surface, resulting in a more complex looking shading. | +|**Falloff Color**|The Falloff Color defines the material scattering color once the light has entered the material. You should avoid using a vivid color here if you want to get a more complex shading variation over the area where you see the scattering.| ## Special Thanks @@ -240,37 +239,34 @@ _Please note that as this system becomes more and more polished, this list could Special thanks to Lee Perry-Smith and his company [Infinite Realities](http://ir-ltd.net) for providing the head model and assistance. Also a very special thanks to [Jorge Jimenez](http://www.iryoku.com/) for releasing his implementation as this feature is based on his work. - - - diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/LightingModels/SubSurfaceProfile/SSSProfileLightingModel.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/LightingModels/SubSurfaceProfile/SSSProfileLightingModel.JPN.udn index e4fd481487f5..90b80a65c623 100644 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/LightingModels/SubSurfaceProfile/SSSProfileLightingModel.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/LightingModels/SubSurfaceProfile/SSSProfileLightingModel.JPN.udn @@ -1,124 +1,160 @@ -Availability:Public +INTSourceChangelist:3462330 +Availability:Public Title:サブサーフェス プロファイルのシェーディング モデル -Crumbs: %ROOT%, Engine, Engine/Rendering/Materials +Crumbs: %ROOT% Description:マテリアルで利用可能なサブサーフェス プロファイルのシェーディング モデルの説明と技術的な詳細。 Version:4.9 +parent:Engine/Rendering/Materials/LightingModels +order:1 +topic-image:sss_profile_topic.png +type:overview +tags:Materials +SkillLevel:Intermediate -[TOC(start:2)] +[TOC(start:2 end:3)] - - -リアルに見える人間の皮膚をレンダリングする機能は、最近のビデオ ゲーム エンジンでは必須です。このニーズに応えるために現在、アンリアル エンジン 4 (UE4) では、**サブサーフェス プロファイル** と呼ばれる皮膚やワックスのようなサーフェス用のシェーディング方法を提供しています。 -サブサーフェス プロファイルのシェーディング モデルは、サブサーフェス シェーディング モデルと類似のプロパティがあります。主な違いはどのようにレンダリングを行うかにあります。 -サブサーフェス プロファイルでは、これは人間の皮膚に見られる繊細なサブサーフェス エフェクトをよりよく表示しやすくする、スクリーン空間に基づいたレンダリング手法を採用しています。これにより、背面散乱が二次的なエフェクトとして耳などに稀に表れることがあります。 -以下のドキュメントでは、サブサーフェス プロファイルがどのようなものであるか、各自の作業でどのように使用できるかについて説明します。 +アンリアル エンジン 4 (UE4) は、**Subsurface Profile (サブサーフェス プロファイル)** と呼ばれる皮膚やワックスのようなサーフェス用のシェーディング方法を提供しています。 +サブサーフェス プロファイル シェーディイング メソッドは サブサーフェス メソッドと似ていますが、レンダリングの方法が基本的に異なります。サブサーフェス プロファイルは **スクリーン スペース** をベースにしています。スクリーン スペース レンダリングは人間の皮膚に見られる繊細なサブサーフェス エフェクトの表示により効果的である一方で、背面散乱が二次的なエフェクトとして耳などに表れることが稀にあります。以下のドキュメントでは、サブサーフェス プロファイルがどのようなものであるか、各自の作業でどのように使用できるかについて説明します。 [OBJECT:ComparisonSlider] - [PARAM:before] - ![Not using SubsurfaceProfile](Results_1.png)(w:700 convert:false) - [/PARAM] - [PARAM:after] - ![Using SubsurfaceProfile](Results_2.png)(w:700 convert:false) - [/PARAM] + [PARAM:before] + ![Not using SubsurfaceProfile](Results_1.png)(w:700 convert:false) + [/PARAM] + [PARAM:after] + ![Using SubsurfaceProfile](Results_2.png)(w:700 convert:false) + [/PARAM] [/OBJECT] - - [Region:note] -3D スキャン ヘッドモデルの提供とご支援いただいた Lee Perry-Smith 氏と彼の会社 [Infinite Realities] (http://ir-ltd.net ) に深く感謝いたします。 +文書の作成および3D スキャン ヘッドモデル提供にご協力いただいた Lee Perry-Smith 氏および Perry-Smith 氏の [Infinite Realities] (http://ir-ltd.net ) に深く感謝いたします。 [/region] +## サブサーフェス プロファイルの概要 -## サブサーフェス プロファイルとは? - -サブサーフェス スキャタリング プロファイルは、サブサーフェス スキャタリングがどのようにレンダリングされるかに関する情報を格納します。 -他のアクタと同様に **コンテンツ ブラウザ** で作成、共有、および格納できます。 -サブサーフェス スキャタリング プロファイルは、サブサーフェスでライトが散乱する距離、サブサーフェスの色、オブジェクトから出た後のライトのフォールオフ カラーなどアーティストが操作するデータを設定することで機能します。 -このデータをサブサーフェス マテリアルに適用して、サブサーフェスの見え方に影響を与えることができます。 -サブサーフェス プロファイルは、インタラクティブに微調整することもできます。つまり、編集結果を確認するためにマテリアルを再コンパイルする必要はありません。 - - - +サブサーフェス スキャタリング データは、**コンテンツ ブラウザ** での作成、共有、保存が可能なアセットです。データはアーティストによって作成され、サブサーフェスでライトが散乱する距離、サブサーフェスの色、オブジェクトから出た後のライトのフォールオフ カラーなどを調節します。このデータをサブサーフェス マテリアルに適用することができます。サブサーフェス プロファイル データは、インタラクティブに微調整することもできます。つまり、編集結果を確認するためにマテリアルを再コンパイルする必要はありません。 ## サブサーフェス プロファイルの有効化、作成および使用 -マテリアルでサブサーフェス プロファイルを使用するには、最初にマテリアルの **[Details (詳細)]** パネルで **Shading Model** を **Subsurface Profile** に設定して、マテリアルがサブサーフェス プロファイルを使用できるようにします。 -また、**Subsurface Profile** 入力で別のサブサーフェス プロファイルを入力してマテリアルが使用するサブサーフェス プロファイルをオーバーライドすることもできます。 +サブサーフェス プロファイルは UE4 で様々な使用方法があります。次のセクションで 1 つずつ説明していきます。 + +### サブサーフェス プロファイルの作成 + +サブサーフェス プロファイルを作成するには、まず **コンテンツ ブラウザ** 内を **右クリック** します。**[Materials & Textures]** オプション、そして **[Subsurface Profile]** オプションを選択します。 +![Create SubsurfaceProfile](2.png) + +[region:note] +サブサーフェス プロファイルを指定しないと、白色人種の皮膚であるデフォルトのサブサーフェス プロファイルが使用されます。 +[/region] + + +サブサーフェス プロファイルを編集するには、 **コンテンツ ブラウザ** で **マウスの左ボタン** でダブルクリックして開きます。 +一度開くと、サブサーフェス スキャタリング プロファイルの各プロパティを調整できます。これは、キーボードを使用して数字を入力するか、**マウスの左ボタン** でカラーバーを **クリック** してカラーピッカーに入れます。 + +### サブサーフェス プロファイルを有効にする +マテリアルでサブサーフェス プロファイルを使用するには、最初にマテリアルの **[Details (詳細)]** パネルでマテリアルの **[Shading Model]** を **[Subsurface Profile]** に設定して有効にします。有効にすると、**Subsurface Profile** 入力に新しく追加することで、使用しているデフォルトのサブサーフェス プロファイルをオーバーライドすることができます。 + [REGION:tip] -サブサーフェス プロファイルのデフォルト設定は白色人種の皮膚に近いものです。これは、リアルに見える皮膚のひとつのコンポーネントにすぎないことに注意してください。 _テクスチャのベースカラーがサブサーフェス スキャタリング プロファイルに合うように常に確認してください。_ +サブサーフェス プロファイルのデフォルト設定は白色人種の皮膚のタイプに近いです。これは、リアルに見える皮膚のひとつのコンポーネントにすぎないことに注意してください。_テクスチャのベースカラーがサブサーフェス スキャタリング プロファイルに合うように常に確認してください。_ [/REGION] ![Enable SubsurfaceProfile](1.png) -サブサーフェス プロファイルは、マテリアル インスタンスでもオーバーライドできます。これを行うには、まず変更対象のマテリアル インスタンスを開く必要があります。 -次にマテリアル インスタンスの **[Details (詳細)]** セクションで **[Override Subsurface Profile (サーフェスプロファイルをオーバーライド)]** を有効にして、**Subsurface Profile** 入力で使用するサブサーフェス プロファイルを入れます。 +サブサーフェス プロファイルは、マテリアル インスタンスでもオーバーライドできます。操作方法は、Material Instance の **[Details (詳細)]** パネルで **[Override Subsurface Profile]** を有効にします。有効にしたら、使用するサブサーフェス プロファイルを **[Subsurface Profile]** で指定します。 ![](6.png) -サブサーフェス プロファイルを作成するには、まず **コンテンツ ブラウザ** 内で **右クリック** します。**[Materials & Textures]** オプション、そして **[Subsurface Profile]** オプションを選択します。 - -![Create SubsurfaceProfile](2.png) - [region:note] -サブサーフェス プロファイルを指定しないと、白色人種の皮膚であるデフォルトのサブサーフェス プロファイルを使用します。 -[/region] - - -サブサーフェス プロファイルを編集するには、**コンテンツ ブラウザ** で **マウスの左ボタン** を **ダブルクリック** して開きます。 -一度開くと、サブサーフェス スキャタリング プロファイルの各プロパティを調整できます。これは、キーボードを使用して数字を入力するか、**マウスの左ボタン** を使用してカラーバー上で **クリック** してカラーピッカーに入れます。 - - -![Tweak SubsurfaceProfile](3.png) - -* ** Scatter Radius: ** スキャタリングを行うワールド空間単位における距離です。 - -* ** Subsurface Color: ** サブサーフェス カラーの色は、サブサーフェス エフェクトのウェイトとして使用できます。黒はサブサーフェス スキャタリングがないことを意味します。 -白はすべてのライティングがマテリアルに入り、周囲に散乱することを意味します。非グレイスケール値は、 -どの色の寄与がサーフェスに入ってきて、より複雑な外観のシェーディングになるかをさらに制御します。 - -* **Falloff Color: ** フォールオフ カラーは、ライトがマテリアルに入った後のマテリアルのスキャタリング カラーを定義します。 -スキャタリングが見えるエリアでシェーディングがより複雑に変化するようにしたければ、ここでは鮮明な色を使用しないようにします。 - -[region:note] - 計算全体ではエネルギーを節約しているため、スキャタリングでさらに多くのライトは作れないことを覚えておいてください (旧/他のサブサーフェス方式とは異なります)。 +計算全体ではエネルギーを節約しているため、スキャタリングでライトの追加作成はできないことを覚えておいてください。 [/region] - - ## マテリアル入力チャンネル -スクリーン空間のサブサーフェス シェーディング プロファイルは、lit (ライティング有り) のシェーディング モードとあまり違いがありません。主な違いは、メタリック入力が再利用され、使用できないことです。 +スクリーン スペースのサブサーフェス シェーディング プロファイルは、lit (ライティング有り) のシェーディング モードとあまり違いがありません。主な違いは、メタリック入力が再利用され、使用できないことです。 -**ベースカラーの入力:** ベースカラーの入力は通常通りディフューズ ライティングに使用します。スクリーン空間サブサーフェス スキャタリングは、色や明るさの変更は前提としておらず、近くのピクセルにライティングを再分配するだけです。そのため、追加のサブサーフェス スキャタリング カラーはありません。 +**ベースカラーの入力:** ベースカラーの入力は通常通りディフューズ ライティングに使用します。スクリーン スペース サブサーフェス スキャタリングは、色や明るさの変更は前提としておらず、近くのピクセルにライティングを再分配するだけです。そのため、追加のサブサーフェス スキャタリング カラーはありません。 従って、マテリアルが特定のカラーでスキャタリングする場合、ベースカラーの一部として表現する必要があります。 ベースカラーは、スキャタリングとディフューズ ライティングとの区別ができないような相当離れた場所からマテリアルを見たかのような最終的なカラーにします。 [REGION:note] - 人間の皮膚は薄い淡いレイヤーとして、サーフェスの下ではより鮮やかな赤色で表示され、デフォルト カラーはこのように見えます。人間の皮膚の可視のスキャタリング距離は約 1.2 cm です。これはサブサーフェス プロファイルのデフォルト値でもあります。 +人間の皮膚は、ライトの量と色をある程度ブロックする薄いレイヤーで、赤みを帯びた肉を覆います。ライトで色付けされた人間の皮膚の可視のスキャタリング距離は約 1.2 cm です。 [/region] **メタリック入力:** メタリック入力チャンネルは、サブサーフェス プロファイルを使用する場合は利用できません。メタリック入力の GBuffer 空間はサブサーフェス プロファイル データに対応するように再利用されているからです。 **オパシティ入力:** オパシティ入力チャンネルは、サブサーフェス スキャタリングの寄与をマスクするために使用します。 -0 から 1 の範囲の値を使用すると、サブサーフェス スキャタリングの強度が異なりエリアの間で滑らかなトランジションを実現します。 -例えば、値 0 をオパシティ入力に入れると、サブサーフェス スキャタリングは無効になります。 -値 1 を入れると、サブサーフェス スキャタリングが最大限表示されます。 -サブサーフェス スキャタリングがどこで強くなるか、弱くなるかの制御を適切に行うために、マスク テクスチャを使用するのが最適です。 -1 により近い値すなわち白のマスク テクスチャのエリアでは、最強のサブサーフェス スキャタリング エフェクトになります。一方、 0 により近い値すなわち黒のマスク テクスチャのエリアでは、エフェクトは弱くなります。 -サブサーフェス カラーを調整すると、暗すぎるエリアがあれば補正します。より明るい色を使用するとサブサーフェス スキャタリングは増えることを覚えておいてください。 +0 がスキャタリングなし、1 はフル スキャタリングの場合、0 から 1 の範囲の値を使用すると、サブサーフェス スキャタリング強度が異なるエリア間のトランジションをスムーズにすることができます。 -ここでは、マスクを使用して1 つのマテリアルで 2 つのサーフェス タイプを どのようにレンダリングするかがわかります。トランジションはソフトでトライアングルの境界に制限されていないことに注意してください。 + +サブサーフェス スキャタリングの強弱位置をうまく調整するためには、マスク テクスチャの使用が便利です。 +1 により近い値すなわち白のマスク テクスチャのエリアでは、最強のサブサーフェス スキャタリング エフェクトになります。一方、0 により近い値すなわち黒のマスク テクスチャのエリアでは、エフェクトは弱くなります。 +暗すぎるエリアはサブサーフェス カラーを調整して補正します。使用する色を明るくするほど、サブサーフェス スキャタリングが増えることを覚えておいてください。 + +以下の画像を見ると、1 つのマテリアルで 2 つのサーフェス タイプをレンダリングするためのマスクの使い方が分かります。トランジションはソフトでトライアングルの境界に制限されていないことに注意してください。 [REGION:lightbox] [![](4.png)(w:920 convert:false)](4.png) [/REGION] +[REGION:caption] +クリックしてフルサイズで表示 +[/REGION] +## フル解像度スキンシェーディング +UE4 がサブサーフェス プロファイル シェーディング モデルでフル解像度のスキンシェーディングをサポートするようになりました。毛穴やしわなどのサーフェスの詳細に対して忠実度の高いライティングを実現します。 + + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Checkboard Rendered Skin Layout](FRSH_Checkboard_Zoom.png) + [/PARAM] + [PARAM:after] + ![Full Resolution Skin](FRSH_FullResolution_Zoom.png) + [/PARAM] +[/OBJECT] + +これまでは皮膚へのライティングはチェッカーボード パターンを使って表していました。この場合、ピクセルの半分はディフューズ ライティングで、残りの半分は スペキュラ ライティングになっています。こうしたライティングは最終的なサブサーフェス プロファイルのフルスクリーン パス中に再結合されます。このようなアプローチは、サブサーフェス ライティングに良い結果をもたらしますが (性質上、低周波)、サーフェスの詳細部分ではライティングの忠実度が低くなることがあります。新しいアプローチを使うと、すべてのピクセルにディフューズとスペキュラのライティング情報が含まれ、RGBA にエンコードされます。これにより、最終的なサブサーフェス プロファイルのフルスクリーン パス中にフル解像度のライティングを再構築して、サーフェスの詳細で良い結果が得られ、テンポラル アンチエイリアスで安定したビヘイビアを示すようになります。 + +### 互換性 + +互換性 フル解像度のスキンシェーディングでは、フルアルファ チャンネルで最低 64 ビットのシーン カラー形式を必要とします。デフォルトの FloatRGBA シーン カラー フォーマットはうまく機能しますが、FloatRGB などの 32 ビットの表現はサポートされていません。シーン カラー フォーマットがフル解像度のスキンと互換性がない場合は、チェッカーボード ベースのライティングに戻ります。 + +このビヘイビアは **r.SSS.Checkerboard **コンソール変数を使ってオーバーライドすることができます。これに対する値は以下の通りです。 + +|プロパティ名| 値|説明| +|-------------|------------|------| +|**r.SSS.Checkerboard**|0|チェッカーボード無効| +|**r.SSS.Checkerboard**|1|チェッカーボード有効 (従来のビヘイビア)| +|**r.SSS.Checkerboard**|2|自動 (デフォルト) - シーン カラーのピクセル フォーマットがサポートしていれば、フル解像度のライティングを使用| + +### 制限事項 + +フル解像度のスキンシェーディングは近似値であることを覚えておいてください。ほとんどの場合うまく機能しますが、マテリアルの一部の機能ではエンコードの方式が原因で問題が生じることがあります。特に、 + +* メタリック マテリアル +* エミッシブ マテリアル + +これらは機能するものの、チェッカーボードと比べると出力の違いに気付くかもしれません。これは、RGBA のディフューズ / スペキュラのエンコードが一緒になっていることが原因です。マテリアルをオーサリングする際に、スキンシェーディングが望ましくない場所で **オパシティ** を **0** に設定することで特定の問題を回避できます。オパシティ 0 のピクセルは、シェーディングのためにデフォルトの lit (ライティング有り) として扱われます。 + +[region:note] +不透明でないピクセルをこうしたやり方でマスクするのもパフォーマンス上、意味があります。こうしたピクセルはサブサーフェスのポストプロセスでバイパスされるからです。 +[/region] + +### パフォーマンスへの配慮 + +制作しているタイトルが 64 ビットのシーン カラー フォーマットの場合は、テクスチャ フェッチ数が減るため、フル解像度のサブサーフェス ライティングの方がチェッカーボードよりも処理が速くなります。ただし、タイトルが 32 ビットのシーン カラーの場合、削減されたテクスチャの帯域幅によって得られるパフォーマンス ゲインの方が、そのメリットを上回るでしょう (ハードウェアに依存)。 ## 技術的な詳細 -現時点では、サブサーフェス スキャタリング プロファイルのシェーディング モデルは Lit (ライティング有り) (ランバート ディフューズ、スペキュラーの GGX、メタリックなし) とあまり変わりがありません。 - ほとんどの素晴らしい機能は、すべてのライティングが計算された後のポスト プロセスで実現します。 +現時点では、サブサーフェス スキャタリング プロファイルのシェーディング モデルは Lit (ライティング有り) (ランバート ディフューズ、スペキュラーの GGX、メタリックなし) とあまり変わりがありません。素晴らしい機能のほとんどは、すべてのライティングが計算された後のポスト プロセスで実現します。 + [REGION:note] サブサーフェス スキャタリング プロファイルは、[Jorge Jimenez 氏](http://www.iryoku.com/) の成果に基づいたものです。彼のウェブページで 3D 画像をよりリアルに見せるための役立つヒントをご覧ください。 @@ -128,55 +164,112 @@ Version:4.9 ガウスぼかしと同様に、画像を 2 パス (分割可能なカーネルと想定) のポストプロセスでフィルタリングします。 フィルターのカーネルはサブサーフェス スキャタリング プロファイルに依存し、これは、GBuffer (シーン毎に最高 255 アクティブ プロファイル) に格納されています。 カーネルは色付けされたウェイトと特定のサンプル位置を持ち、プロファイルでスケーリングできます (cm 単位で定義)。 -最終段階で散乱光の寄与をフル解像度の画像と再結合します。このビューと、非視点依存のライティングを分けるために、シーンカラーのアルファチャンネルにウェイト付けの条件を格納します。 +最終段階で散乱光の寄与をフル解像度の画像と再結合します。視点依存のライティングと非視点依存のライティングを分けるために、シーンカラーのアルファチャンネルにウェイト付けの条件を格納します。 この近似では、64 ビットのレンダリング ターゲット (r.SceneColorFormat を参照) を必要とし、ほとんどの場合で機能します。 これはスペキュラ (鏡面反射色) をうまく取り除きますが、スペキュラ ピクセルは彩度が減じられた非視点依存のカラーになります。これは、すべてのライティング パスに 2 つの 32 ビットのレンダリング ターゲットを使用することで改善できます。同じメモリ帯域幅を持ちますが、一部のハードウェアでは遅くなることがあります。これは変更対象です (コードの複雑度を追加)。 -ここでは、ブラー適用前にスペキュラ(鏡面反射色) を取り除いた例をとりあげます。最終画像 (右端の画像) でスペキュラ反射が鮮明で滑らかなのがわかります。これが目標とするエフェクトです。 +ここでは、ブラー適用前にスペキュラ (鏡面反射色) を取り除いた例をとりあげます。最終画像 (右端の画像) でスペキュラ反射が鮮明で滑らかなのがわかります。これが目標とするエフェクトです。 [REGION:lightbox] [![](Good_Combination.png)(w:920 convert:false)](Good_Combination.png) [/REGION] +[REGION:caption] +クリックしてフルサイズで表示 +[/REGION] -ここでは、ブラー適用前にスペキュラ (鏡面反射色) が取り除かれなかった例をとりあげます。最終画像 (右端の画像) でスペキュラ反射に光沢がなく伸縮しているのがわかります。これは、このエフェクトをレンダリングする正しいやり方ではありません。 +ここでは、ブラー適用前にスペキュラ (鏡面反射色) が取り除かれなかった例をとりあげます。最終画像 (右端の画像) でスペキュラ反射に光沢がなく伸縮しているのがわかります。これは、このエフェクトの正しいレンダリング方法ではありません。 [REGION:lightbox] [![](Bad_Combination.png)(w:920 convert:false)](Bad_Combination.png) [/REGION] +[REGION:caption] +クリックしてフルサイズで表示 +[/REGION] ## スケーラビリティとコンソール コマンド 高品質なビジュアルと高いパフォーマンスとの間で適切なトレードオフを得るために使用できるスケーリングとパフォーマンスのコンソール コマンドがあります。 -**r.SSS.Scale**:ポストプロセスのパスを無効化、または簡単な実験のためにエフェクトをスケーリングすることができます。 +**r.SSS.Scale**:ポストプロセス パスの無効化、または簡単な実験用のエフェクトのスケーリングが行えます。これを **0** にするとエフェクトが無効になります。0 より大きい値に設定すると、以下の画像シーケンスのようにエフェクトが増加します。 -**r.SSS.SampleSet**:エフェクトの実行を速くするように使用するサンプルを減らすことができます。しかし、これはエフェクトが低品質になるか、レンダリングのアーティファクトが表示される可能性があることを意味します。 +[INCLUDE:Engine\Rendering\Materials\LightingModels\SubSurfaceProfile\#SSRScale] + + +**r.SSS.SampleSet**:サンプル使用数を設定します。この数を減らすとエフェクトの実行速度が速くなります。しかし、これはエフェクトが低品質になるか、レンダリングのアーティファクトが表示される可能性があることを意味します。 + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![r.SSS.SampleSet = 0](RSampleSet_Off.png) + [/PARAM] + [PARAM:after] + ![r.SSS.SampleSet = 1](RSampleSet_On.png) + [/PARAM] +[/OBJECT] 以下の画像は、システム内部を表しています。このビューは、**ShowFlag.VisualizeSSS 1** を使用して有効になります。 [REGION:lightbox] [![](5.png)(w:920 convert:false)](5.png) [/REGION] +[REGION:caption] +クリックしてフルサイズで表示 +[/REGION] サブサーフェス スキャタリング プロファイルのシェーディング モデルは、皮膚のレンダリングに関しては一歩進んだものですが、行えることにはいくつかの制限があります。 - _このシステムはますます進歩していくため、このリストは変更の可能性があることにご注意ください。_ +_このシステムはますます進歩していくため、このリストは変更の可能性があることにご注意ください。_ * この機能は非ディファード (モバイル) レンダリング モードでは動作しません。 * 大きな画面でスキャタリング半径を設定すると、極端なライティング条件ではバンディングアーティファクトが表示されるかもしれません。 * 現在、ライトのバックスキャタリングはありません。 -* 現在、SSS マテリアルが非 SSS マテリアルによってオクルードされる場合、グレイのアウトラインが発生します。 +* 現在、non-SSS Materials が SSS Material をオクルードするとグレイのアウトラインが表示されます。 +## Subsurface Profile プロパティのリファレンス +![Tweak SubsurfaceProfile](3.png) + +|プロパティ名| 説明| +|-------------|------------| +|**Scatter Radius:**|スキャタリングを行うワールド スペース単位の距離です。| +|**Subsurface Color:**|サブサーフェス エフェクトのウェイトとして使用できます。黒はサブサーフェス スキャタリングがないことを意味します。白はすべてのライティングがマテリアルに入り、周囲に散乱することを意味します。非グレイスケール値は、どの色の寄与がサーフェスに入ってきて、より複雑な外観のシェーディングになるかをさらに制御します。 | +|**Falloff Color**|フォールオフ カラーは、ライトがマテリアルに入った後のマテリアルのスキャタリング カラーを定義します。スキャタリングが見えるエリアでシェーディングがより複雑に変化するようにしたければ、ここでは鮮明な色を使用しないようにします。| ## 謝辞 -ヘッドモデルの提供とご支援いただいた Lee Perry-Smith 氏と彼の会社 [Infinite Realities](http://ir-ltd.net) に深く感謝いたします。 +ヘッドモデルの提供とご支援いただいた Lee Perry-Smith 氏と Perry-Smith 氏の [Infinite Realities] (http://ir-ltd.net ) に深く感謝いたします。 また、この機能のもとになった実装をリリースいただいた [Jorge Jimenez 氏](http://www.iryoku.com/) にも深く感謝いたします。 - - - + diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/MaterialsAndTextures.INT.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/MaterialsAndTextures.INT.udn index 3de574cae067..385ce23d8de8 100644 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/MaterialsAndTextures.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/MaterialsAndTextures.INT.udn @@ -3,7 +3,7 @@ Title:Materials Crumbs: %ROOT%, Engine Description:Controlling the appearance of surfaces in the world using shaders. Navigation:topic -Version:4.9 +Version:4.15 parent:Engine/Rendering order:2 type:landing diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/MaterialsAndTextures.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/MaterialsAndTextures.JPN.udn index 5d1b8391310f..52162787f975 100644 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/MaterialsAndTextures.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/MaterialsAndTextures.JPN.udn @@ -1,10 +1,10 @@ -INTSourceChangelist:3155346 +INTSourceChangelist:3481084 Availability:Public -Title:Materials +Title:マテリアル Crumbs: %ROOT%, Engine -Description:シェーダを使ったワールド内のサーフェスの外観の調節 +Description:シェーダを使ってワールド内のサーフェスの外観を調節する Navigation:topic -Version:4.9 +Version:4.15 parent:Engine/Rendering order:2 type:landing diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/MaterialsAndTextures.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/MaterialsAndTextures.KOR.udn index ea8eb529ccfc..4e6ab0b26a39 100644 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/MaterialsAndTextures.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/MaterialsAndTextures.KOR.udn @@ -1,10 +1,10 @@ -INTSourceChangelist:3155346 +INTSourceChangelist:3481084 Availability:Public Title:머티리얼 Crumbs: %ROOT%, Engine Description:셰이더를 활용하여 월드의 표면 외형을 제어하는 방법입니다. Navigation:topic -Version:4.9 +Version:4.15 parent:Engine/Rendering order:2 type:landing diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/HowTo/MeshDecals/MeshDecals.CHN.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/MeshDecals/MeshDecals.CHN.udn similarity index 100% rename from Engine/Documentation/Source/Engine/Rendering/Materials/HowTo/MeshDecals/MeshDecals.CHN.udn rename to Engine/Documentation/Source/Engine/Rendering/Materials/MeshDecals/MeshDecals.CHN.udn diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/MeshDecals/MeshDecals.INT.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/MeshDecals/MeshDecals.INT.udn new file mode 100644 index 000000000000..32e441b181f3 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/MeshDecals/MeshDecals.INT.udn @@ -0,0 +1,99 @@ +Availability:Public +Title: Mesh Decals Overview +Description: This is an overview of the Mesh Decals feature in Unreal Engine 4. +Crumbs: +parent: Engine/Rendering/Materials +Related:Engine/Rendering/Materials/howto/MeshDecals +order: 14 +type:overview +version:4.15 +Topic-image: MeshDecalTopic.png +tags:Materials +tags: Decals + +[TOC (start:2 end:2)] + +Unreal Engine 4 now has support for **Mesh Decals**, enabling you to use the properties of Deferred Decals on separate surface geometry +for added detail to your Static and Skeletal Meshes. Because Deferred Decals rely on projection, you are limited to mostly planar surface +details that shear and distort when not aligned with the surface it’s projecting onto. Mesh Decals afford you decals that do not follow a +simple projection and instead can be used with geometry that wraps around edges, being used with spline meshes, ultimately enhancing the +look of your characters. + + + +## Mesh Decal versus Masked Material + +Mesh Decals are a mix of translucent blend mode and deferred decals in that they do not render to depth but do update the GBuffer or DBuffer +after the opaque geometry has been rendered. In contrast to using a masked material, there is no cost for EarlyZ pass, you don't get shadows +or proper occlusion, but with the trade-off, you get the soft transitions in the material. + +Mesh Decals provide several differences to Deferred Decal Actors that you should be aware of: + +* Since large Deferred Decals often do front and back facing draw calls, there are fewer draw calls. +* Since there are fewer pixels covered and flat back facing decals cover 0 pixels, it's quite faster. +* Since you can use a custom UV, You have the ability to do more complex projections. +* You have the ability to have properly normal mapped decals wrapping around surfaces (or stretching along splines). + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![ Mesh Decal ](MeshDecal.png)(w:400) + [/PARAM] + [PARAM:after] + ![ Masked Material ](MaskedMaterial.png)(w:400) + [/PARAM] +[/OBJECT] + +## Authoring Content + +Authoring content for use as Mesh Decal geometry is in line with any model creation. Since this geometry will not rely on projection (like a Deferred Decal Actor), the geometry +needs only to stay in front of the surface you want to affect. With this in mind, the decal geometry should "hug" the underlying surface, but it does not have to match it very closely +because there is already a small depth bias applied to account for this small offset. Also, using a bit of geometry that feathers out from the decal can be good to create the soft transitions +for the decal, which is something you cannot attain with a masked material. + + +
+[REGION:imagetable] +| ![](MeshDecalAuthoring.png)(h:450) | ![](MeshDecalAuthoringComposite.png)(h:450) | +| --- | --- | +| Base Mesh and Decal Geometry (Isolated) | Composited Mesh | +[/REGION] +
+ +Another thing to keep in mind when developing your content, is that Mesh Decals can be a challenge with Levels of Detail (LOD), or long view distances when there is limited depth buffer +precision, because geometry will intersect (or not match-up) as intended. However, you can either change the mesh to account for this (in most cases), or you can use **World Position Offset** in +your material to adjust the offset without having to return to your modeling application. + +![](Offset.png)(w:500) + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![ Offset Value: 0 ](2_Offset.png)(w:500) + [/PARAM] + [PARAM:after] + ![ Offset Value: -0.6 ](1_Offset.png)(w:500) + [/PARAM] +[/OBJECT] + +In this example, the decal geometry is close enough to the base mesh, such that the depth cannot account for the offset. Using a small negative offset value pushes the geometry out just enough so that it +does not intersect with the underlying geometry. + +## Notes + +* DBuffer and non-DBuffer use the same container. +* Sort by depth to avoid artifacts when there are many layers overlapping. +* Parallel Rendering isn't yet hooked up. There are some CPU savings if this feature is used extensively. + +## Limitations + +* Material Editor Preview is not visible. +* There is no artist specified sort order. +* Tangent Space support is not yet implemented. +* Shader Overdraw/Overdraw functionality is missing. +* Since it assumes base pass usage, the Material Editor does not currently show the correct instructions count. +* There is no easily adjustable DepthBias. Currently, you have to use an offset in the mesh from the surface it's above, or control with World Position Offset in the Material. + + diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/MeshDecals/MeshDecals.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/MeshDecals/MeshDecals.JPN.udn new file mode 100644 index 000000000000..2f21353d42c8 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/MeshDecals/MeshDecals.JPN.udn @@ -0,0 +1,100 @@ +INTSourceChangelist:3455346 +Availability:Public +Title:メッシュ デカールの概要 +Description:アンリアル エンジン 4 のメッシュ デカール機能の概要を説明します。 +Crumbs: +parent:Engine/Rendering/Materials +Related:Engine/Rendering/Materials/howto/MeshDecals +order:14 +type:overview +version:4.15 +Topic-image:MeshDecalTopic.png +tags:Materials +tags:Decals + +[TOC (start:2 end:2)] + +アンリアル エンジン 4 で **メッシュ デカール** がサポートされるようになりました。 +これにより、スタティクメッシュおよびスケルタルメッシュに追加した詳細に対して、別のサーフェス ジオメトリ上でディファード デカールのプロパティが使用できます。ディファード デカールはプロジェクションに依存するので、 +投影先のサーフェスと一致しない時にシアおよび変形が生じる平面サーフェイス ディティールにほぼ限定されます。メッシュ デカールは、シンプルなプロジェクションを追わずに +エッジの周囲をラップするジオメトリやスプライン メッシュと一緒に使用し、 +キャラクターの外見を美しくします。 + + + +## メッシュ デカールとマスク付きマテリアルの比較 + +メッシュ デカールは、透過ブレンド モードとディファード デカールを混ぜたものです。 +不透明なジオメトリがレンダリングされた後、深部まではレンダリングせず、GBuffer または DBuffer の更新を行います。マスク付きマテリアルの使用とは対照的に、EarlyZ pass の負荷がなく、 +シャドウあるいは適切なオクルージョンは得ませんが、その代わりマテリアルがソフトに変形します。 + +メッシュ デカールは、Deferred Decal アクタとは以下の点で異なります。 + +* 大きいディファード デカールの場合、正面向きと後ろ向きの描画コールをするので、描画コール数が減ります。 +* カバーするピクセルも減り、デカールの背面が平らな場合はカバーするピクセルがないのでかなり速くなります。 +* カスタム仕様の UV も使用できるので、より複雑なプロジェクションの実行が可能になります。 +* 正しく法線マップ化したデカールをサーフェスの周りにラップする (またはスプラインに沿って伸ばす) ことができます。 + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![ Mesh Decal ](MeshDecal.png)(w:400) + [/PARAM] + [PARAM:after] + ![ Masked Material ](MaskedMaterial.png)(w:400) + [/PARAM] +[/OBJECT] + +## コンテンツのオーサリング + +コンテンツをメッシュ デカール ジオメトリとして使用するオーサリングは、すべてのモデル作成と一致しています。このジオメトリは (ディファード デカール アクタとは違って) プロジェクションに依存はしないので、 +ジオメトリは影響を与えたいサーフェスの正面にあるだけで良いです。このことを踏まえた上で、この小さなオフセットの主要要因となる小さな深度バイアスが既にあるので、 +デカール ジオメトリは下層のサーフェスには合わせますが、そこまでぴったり一致する必要はありません。さらに、デカールの境界をぼかすジオメトリを少し使うと、 +マスク付きマテリアルでは実現できないデカール用の柔らかいトランジションを作成することができます。 + + +
+[REGION:imagetable] +| ![](MeshDecalAuthoring.png)(h:450) | ![](MeshDecalAuthoringComposite.png)(h:450) | +| --- | --- | +| 基本メッシュとデカール ジオメトリ (個々) | 合成したメッシュ | +[/REGION] +
+ +ジオメトリには深度バッファ精度に限度があるため、 +メッシュ デカールでの LOD あるいは長距離表示は難しいということも覚えておくと良いでしょう。ただしほとんどの場合は、メッシュを変更すれば解決しますし、 +マテリアルに **World Position Offset** を使えばモデリング アプリケーションに戻らずにオフセットの調節ができます。 + +![](Offset.png)(w:500) + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![ Offset Value: 0 ](2_Offset.png)(w:500) + [/PARAM] + [PARAM:after] + ![ Offset Value: -0.6 ](1_Offset.png)(w:500) + [/PARAM] +[/OBJECT] + +この例では、デカール ジオメトリは、基本メッシュに近すぎて、深度がオフセットを考慮できません。小さな負のオフセット値を使うと、ジオメトリを十分押し出すので、 +下層のジオメトリと交わりません。 + +## 注記 + +* DBuffer も non-DBuffer も同じコンテナを使用します。 +* レイヤー オーバーラップが多い場合は、アーティファクトを避けるために深度でソートします。 +* 並列レンダリングはまだ組み込まれていません。この機能を広範囲に使用すると CPU 負荷を若干抑えることができます。 + +## 制限事項 + +* マテリアル エディタ プレビューは表示されません。 +* アーティストはソート順序を指定しません。 +* タンジェント空間はまだサポートされていません。 +* Shader Overdraw/Overdraw 機能がついていません。 +* マテリアル エディタはベース パスの使用を前提としているので、正しい命令数は表示しません。 +* 深度バイアスの調整が簡単ではありません。現在、上にあるサーフェスからメッシュのオフセットを使用するか、マテリアルの World Position Offset で調整しなければなりません。 + + diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/MeshDecals/MeshDecals.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/MeshDecals/MeshDecals.KOR.udn new file mode 100644 index 000000000000..adfbc209e4dd --- /dev/null +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/MeshDecals/MeshDecals.KOR.udn @@ -0,0 +1,100 @@ +INTSourceChangelist:3455346 +Availability:Public +Title: 메시 데칼 개요 +Description: 메시 데칼에 대한 개요입니다. +Crumbs: +parent: Engine/Rendering/Materials +Related:Engine/Rendering/Materials/howto/MeshDecals +order: 14 +type:overview +version:4.15 +Topic-image: MeshDecalTopic.png +tags:Materials +tags: Decals + +[TOC (start:2 end:2)] + +언리얼 엔진 4 에는 이제 Mesh Decal (메시 데칼)이 지원되어 별도의 표면 지오메트리에 디퍼드 데칼 프로퍼티를 사용할 수 있어 +스태틱 / 스켈레탈 메시에 디테일을 추가할 수 있습니다. 디퍼드 데칼은 투영에 의존하므로, 투영 대상 표면에 일치하지 않으면 잘리고 뒤틀리는 +평면 표면 디테일에 거의 제한됩니다. 메시 데칼은 단순 투영을 따르지 않는 데칼을 제공해 주는 대신 +에지를 감싸는 지오메트리나 스플라인 메시와 함께 사용할 수 있으며, +캐릭터의 외형을 강화시켜 줍니다. + + + +## 메시 데칼 VS 마스크드 머티리얼 + +메시 데칼은 뎁스 렌더링은 하지 않지만 불투명 지오메트리 렌더 후 GBuffer 와 DBuffer 업데이트를 한다는 점에서 반투명 블렌드 모드와 디퍼드 데칼을 섞은 것입니다. +마스크드 머티리얼을 사용한 것과 비교하면, EarlyZ 패스 비용이 없고, 그림자나 적절한 오클루전도 없지만, +그에 대한 균형으로 머티리얼에 부드러운 전환이 가능합니다. + +메시 데칼은 Deffered Decal Actor (디퍼드 데칼 액터)에 비해 주의해야 할 차이점이 몇 가지 있습니다: + +* 커다란 디퍼드 데칼은 종종 앞면과 뒷면 드로 콜을 하므로 드로 콜 수가 적습니다. +* 커버되는 픽셀 수가 적고 평평한 뒷면 데칼은 0 픽셀을 커버하므로 꽤 빠릅니다. +* 커스텀 UV 를 사용할 수 있어 보다 복잡한 투영이 가능합니다. +* 스플라인 상에 늘어나거나 표면을 감싸도록 제대로 노멀 매핑된 데칼을 가질 수 있습니다. + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![ 메시 데칼 ](MeshDecal.png)(w:400) + [/PARAM] + [PARAM:after] + ![ 머스크드 머티리얼 ](MaskedMaterial.png)(w:400) + [/PARAM] +[/OBJECT] + +## 콘텐츠 제작 + +메시 데칼 지오메트리로 사용할 콘텐츠를 제작하는 것은 모델 생성과 밀접한 관계가 있습니다. 이 지오메트리는 디퍼드 데칼 액터처럼 투영에 의존하지 않으므로, 지오메트리는 +영향을 주고자 하는 표면 앞에만 있으면 됩니다. 이 점을 염두에 두고, 데칼 지오메트리는 아래 놓인 표면을 "hug"해야 하지만, 매우 근접하게 일치할 필요는 없습니다. +이런 작은 오프셋을 위해 이미 약간의 뎁스 바이어스가 하드코딩되어 있기 때문입니다. 또한, 데칼에서 점차 사라지는 지오메트리를 약간 사용하면 +마스크드 머티리얼로는 얻을 수 없는 데칼의 부드러운 전환 효과를 내는 데 좋습니다. + + +
+[REGION:imagetable] +| ![](MeshDecalAuthoring.png)(h:450) | ![](MeshDecalAuthoringComposite.png)(h:450) | +| --- | --- | +| 베이스 메시 및 데칼 지오메트리 (고립) | 합성 메시 | +[/REGION] +
+ +또 한가지 콘텐츠 개발시 염두에 두어야 할 점은, 메시 데칼은 뎁스 버퍼 정밀도 제한으로 인해 레벨 오브 디테일(LOD)이나 원거리에서 볼 때 문제가 될 수 있습니다. +지오메트리가 교차하거나 의도대로 일치하지 않기 때문입니다. 하지만 대부분의 경우 메시가 이 부분을 고려하도록 변경하거나, 머티리얼의 월드 포지션 오프셋을 사용하여 오프셋을 조절하면 +모델링 프로그램으로 돌아가 별도의 작업을 하지 않아도 됩니다. + +![](Offset.png)(w:500) + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![ 오프셋 값: 0 ](2_Offset.png)(w:500) + [/PARAM] + [PARAM:after] + ![ 오프셋 값: -0.6 ](1_Offset.png)(w:500) + [/PARAM] +[/OBJECT] + +이 예제에서, 뎁스가 오프셋을 처리하지 못하는 베이스 메시에 데칼 지오메트리가 충분히 가까이 있습니다. 작은 음수 오프셋 값을 사용하면 아래 있는 지오메트리와 교차하지 않을 만큼 지오메트리를 +약간 밀어줍니다. + +## 주 + +* DBuffer 및 non-DBuffer 는 같은 컨테이너를 사용합니다. +* 겹치는 레이어가 여럿 있을 때 부작용을 피하기 위해 깊이로 소트합니다. +* Parallel Rendering (병렬 렌더링)이 아직 후크되지 않았습니다. 이 기능을 적극 활용하면 CPU 비용이 약간 절약됩니다. + +## 한계점 + +* 머티리얼 에디터 프리뷰가 보이지 않습니다. +* 소트 순서를 아티스트가 지정할 수 없습니다. +* 탄젠트 스페이스 지원이 아직 구현되지 않았습니다. +* Shader Overdraw/Overdraw 함수 기능이 빠져있습니다. +* 머티리얼 에디터에 현재 올바른 인스트럭션 수가 표시되지 않습니다. 베이스 패스 사용량을 추정하기 때문입니다. +* 쉽게 조절 가능한 DepthBias 가 없습니다. 현재 메시 위의 표면에서 메시의 오프셋을 사용하거나, 머티리얼의 월드 포지션 오프셋으로 제어해야 합니다. + + diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/PixelNormalOffset/RefractionPixelNormalOffset.CHN.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/PixelNormalOffset/RefractionPixelNormalOffset.CHN.udn index bd01420eaf92..aa713575ea9d 100644 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/PixelNormalOffset/RefractionPixelNormalOffset.CHN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/PixelNormalOffset/RefractionPixelNormalOffset.CHN.udn @@ -1,46 +1,54 @@ -INTSourceChangelist:0 -Availability: Docs -Title:Refraction Mode: Pixel Normal Offset -Crumbs: %ROOT%, Engine, Engine/Rendering/Materials -Description:How to use the Refraction mode for Pixel Normal Offset in your Materials. -Related: Engine/REndering/Materials/HowTo/Refraction -Version: 4.13 -SkillLevel: Intermediate +INTSourceChangelist:3378497 +Availability:Public +Title:折射模式:像素法线偏移 +Crumbs: +Description:材质中像素法线偏移折射模式总览。 +Related:Engine/Rendering/Materials +Related:Engine/Rendering/Materials/HowTo/Refraction +Version:4.14 +SkillLevel:Intermediate +Parent:Engine/Rendering/Materials +Order:13 +type:overview +tags:Materials +topic-image:PNO_Topic.png + +[TOC(start:2 end:2)] + +在虚幻引擎 4 的当前版本中,我们使用了折射的非物理模型 **像素法线偏移(Pixel Normal Offset)**。内嵌代码使用 **Index of Refraction** 的折射物理模型,以光线在媒介之间的折射方式为基础,可能导致大量穿帮(因为场景颜色在屏幕外读取)。可用于玻璃罐之类的小型物体(效果不甚明显),但在平面上存在问题。**像素法线偏移(Pixel Normal Offset)** 可为水面之类的大型平面启用折射,此处常量偏移不会从远离屏幕之外之处进行读取。它以顶点法线作为参考,然后通过逐像素法线和顶点法线之间的差别计算折射偏移,使这些平面不会移位。 + +## 折射的物理和非物理模型 + +在下方的对比中,**Index of Refraction** 物理模型的折射模式和 **Pixel Normal Offset** 的非物理模型展示了材质中 +法线读取方式的差异。 + +[REGION:note] +可阅读 [使用折射](Engine/Rendering/Materials/HowTo/Refraction) 页面,了解折射物理模型的更多内容,以及如何结合材质使用。 +[/REGION] + +[REGION:imagetable] +| [INCLUDE:#IORWithoutNormals] | [INCLUDE:#PNOWithoutNormals] | +| ![](RefractionSettingIOR.png)(w:400) | ![](RefractionSettingPNO.png)(w:400) | +|---|---| +| 折射物理模型:无法线贴图 Index of Refraction| 折射非物理模型:无法线贴图 Pixel Normal Offset | +[/REGION] + +在此处对比 **Index of Refraction** 模式和 **Pixel Normal Offset** 模式(不从屏幕过远的地方进行读取)后,即可发现图像出现移位。**Index of Refraction** 无需法线贴图插入材质即可使用;而 **Pixel Normal Offset** 没有法线贴图则无法获得折射。 -[TOC(start:2 end:3)] +[REGION:imagetable] +| [INCLUDE:#IORWithNormals] | [INCLUDE:#PNOWithNormals] | +| ![](RefractionSettingIOR.png)(w:400) | ![](RefractionSettingPNO.png)(w:400) | +|---|---| +| 带法线贴图的物理模型 | 带法线贴图的非物理模型 | +[/REGION] +添加法线贴图到材质时,大于 1 的折射值插入 Refraction 输入;使用 **Pixel Normal Offset** 后法线将沿表面平移。 +然而您会注意到使用 **Index of Refraction** 后仍然会从屏幕外读取偏移,对使用折射的平面而言并非理想效果。 +## 最终结果 -The Refraction in Unreal Engine 4 is based on how light rays refract as they are transferred between mediums with different Indices of Refraction that acts as a physical model -for refraction, which can have unforeseen artifacts for large surfaces. In Unreal Engine 4.13 and higher, you now can select a non-physical refraction model that uses the vertex -normal as a reference and then computes the difference to have better results for large surfaces, like water or glass panes. - - -## Steps - -To use the Refraction Mode for Pixel Offset Normal select the main material inputs node then in the Detail's panel use the drop-down selection for Refraction Mode to select between the -built-in **Index of Refraction** or the **Pixel Normal Offset** model. - -1. Select the **Main Material Node** and in the **Detail's** panel scroll down to the section named **Refraction**. Use the drop-down next to **Refraction Mode** to choose -between the Index of Refraction and Pixel Normal Offset. - - ![](RefractionSettingsSelection.png)(w:350) - - Select **Pixel Normal Offset**. - - ![](RefractionSettingPNO.png)(w:350) - -2. In the Material Graph, use the following setup to control the amount of refraction for your material. Use a **Scalar Parameter** plugged into the **Lerp's** input **B** to -control the amount of refraction. - - [REGION:lightbox] - [![](RefractionInput.png)(w:350)](RefractionInput.png) - [/REGION] - _You can use a constant value or a Lerp node to get a nice variation between the surface detail and defined Index of Refraction._ - -By using a Scalar Parameter that can be dynamically adjusted, the [Index of Refraction](https://docs.unrealengine.com/latest/INT/Engine/Rendering/Materials/HowTo/Refraction/#indexofrefractionorior) -can easily be controlled like the example here that uses a sliding range between 1.0 and 10.0. +在此例中,折射量在值 1.0(完全无折射)到 2.0 之间调整,使用 **Pixel Normal Offset** 时沿表面形成一些折射而不使图像发生移位。 [OBJECT:EmbeddedVideo] [PARAMLITERAL:width] @@ -50,48 +58,37 @@ can easily be controlled like the example here that uses a sliding range between 360 [/PARAMLITERAL] [PARAMLITERAL:videoid] - 6UnuWlr0C5Y + H8FGf4iZdn0 [/PARAMLITERAL] [/OBJECT] -## Key Benefits -The benefit of using the Refraction Mode for Pixel Normal Offset can instantly be seen when using large flat surfaces where refraction is used since it is not going to read from outside -the scene. This provides a leap in quality for fluid water surfaces over the built-in model that is really good for smaller objects, like glassware. -![](2_Ref1.5_Default.png)(w:640) -[REGION:caption] -_Index of Refraction model with artist defined value of 1.5_ + diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/PixelNormalOffset/RefractionPixelNormalOffset.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/PixelNormalOffset/RefractionPixelNormalOffset.JPN.udn index dcc98cc17afc..6522dfd15c92 100644 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/PixelNormalOffset/RefractionPixelNormalOffset.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/PixelNormalOffset/RefractionPixelNormalOffset.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3340108 +INTSourceChangelist:3378497 Availability:Public Title:Refraction モード:Pixel Normal Offset Crumbs: @@ -7,8 +7,8 @@ Related:Engine/Rendering/Materials Related:Engine/Rendering/Materials/HowTo/Refraction Version:4.14 SkillLevel:Intermediate -parent:Engine/Rendering/Materials -order:13 +Parent:Engine/Rendering/Materials +Order:13 type:overview tags:Materials topic-image:PNO_Topic.png diff --git a/Engine/Documentation/Source/Engine/Rendering/Materials/PixelNormalOffset/RefractionPixelNormalOffset.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/Materials/PixelNormalOffset/RefractionPixelNormalOffset.KOR.udn index 6eb24db0b263..eb6d4c841c39 100644 --- a/Engine/Documentation/Source/Engine/Rendering/Materials/PixelNormalOffset/RefractionPixelNormalOffset.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/Materials/PixelNormalOffset/RefractionPixelNormalOffset.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3340108 +INTSourceChangelist:3378497 Availability: Public Title:굴절 모드: 픽셀 노멀 오프셋 Crumbs: diff --git a/Engine/Documentation/Source/Engine/Rendering/Nvidia/NVAftermath/NvidiaAftermath.CHN.udn b/Engine/Documentation/Source/Engine/Rendering/Nvidia/NVAftermath/NvidiaAftermath.CHN.udn new file mode 100644 index 000000000000..07bf4f82f6c0 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Rendering/Nvidia/NVAftermath/NvidiaAftermath.CHN.udn @@ -0,0 +1,26 @@ +INTSourceChangelist:0 +Availability:Docs +Crumbs: +Title: NVIDIA Aftermath +Description: Integration of Nvidia's Aftermath technology that enabls post-mortem GPU crash analysis on NVIDIA GeForce based GPUs. +Type:Overview +Version:4.15 +Parent:Engine/Nvidia +Order:1 +topic-image:Aftermath_Topic.png +Tags:Nvidia + + +[REGION:fullwidth raw] +![](Aftermath_Banner.png)(w:900) +[/REGION] + +As of version 4.15.2, Unreal Engine supports Nvidia's **Aftermath** C++ library for Windows-based developers, which provides additional data from Nvidia GeForce-based GPUs after a crash occurs. +This data contains crucial information about what the GPU was doing when the crash occurred, enabling you to track down what's happening with the GPU in your own projects. + +Aftermath is a lightweight tool that is unobtrusive and reduces the performance footprint needed by some debugging tools. In fact, it's lightweight enough that it can even ship with finished +games to provide the data you need from your customers' machines. Aftermath enables programmers to insert markers into their code that assist in tracking the root causes of crashes. This is +now being used in the Unreal Engine Editor to track down and fix reported or captured issues. + +For additional information and how to use it in your own project, visit [Nvidia's Aftermath documentation](https://developer.nvidia.com/nvidia-aftermath) page. + diff --git a/Engine/Documentation/Source/Engine/Rendering/Nvidia/NVAftermath/NvidiaAftermath.INT.udn b/Engine/Documentation/Source/Engine/Rendering/Nvidia/NVAftermath/NvidiaAftermath.INT.udn new file mode 100644 index 000000000000..c2ed329c9c53 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Rendering/Nvidia/NVAftermath/NvidiaAftermath.INT.udn @@ -0,0 +1,25 @@ +Availability:Docs +Crumbs: +Title: NVIDIA Aftermath +Description: Integration of Nvidia's Aftermath technology that enabls post-mortem GPU crash analysis on NVIDIA GeForce based GPUs. +Type:Overview +Version:4.15 +Parent:Engine/Nvidia +Order:1 +topic-image:Aftermath_Topic.png +Tags:Nvidia + + +[REGION:fullwidth raw] +![](Aftermath_Banner.png)(w:900) +[/REGION] + +As of version 4.15.2, Unreal Engine supports Nvidia's **Aftermath** C++ library for Windows-based developers, which provides additional data from Nvidia GeForce-based GPUs after a crash occurs. +This data contains crucial information about what the GPU was doing when the crash occurred, enabling you to track down what's happening with the GPU in your own projects. + +Aftermath is a lightweight tool that is unobtrusive and reduces the performance footprint needed by some debugging tools. In fact, it's lightweight enough that it can even ship with finished +games to provide the data you need from your customers' machines. Aftermath enables programmers to insert markers into their code that assist in tracking the root causes of crashes. This is +now being used in the Unreal Engine Editor to track down and fix reported or captured issues. + +For additional information and how to use it in your own project, visit [Nvidia's Aftermath documentation](https://developer.nvidia.com/nvidia-aftermath) page. + diff --git a/Engine/Documentation/Source/Engine/Rendering/Nvidia/NVAftermath/NvidiaAftermath.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/Nvidia/NVAftermath/NvidiaAftermath.JPN.udn new file mode 100644 index 000000000000..73628a5d33f0 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Rendering/Nvidia/NVAftermath/NvidiaAftermath.JPN.udn @@ -0,0 +1,26 @@ +INTSourceChangelist:3435012 +Availability:Docs +Crumbs: +Title:NVIDIA Aftermath +Description:NVIDIA GeForce GPU に対するクラッシュ発生後の分析を可能にする Nvidia Aftermath 技術の統合 +Type:Overview +Version:4.15 +Parent:Engine/Nvidia +Order:1 +topic-image:Aftermath_Topic.png +Tags:Nvidia + + +[REGION:fullwidth raw] +![](Aftermath_Banner.png)(w:900) +[/REGION] + +アンリアル エンジン 4.15.2 では、Windows 使用のデベロッパー向けに Nvidia の **Aftermath** C++ ライブラリをサポートしています。これにより、クラッシュ発生後に Nvidia GeForce-based GPUwhich からの追加データを提供します。 +このデータにはクラッシュ時に GPU が何を行っていたかという重要な情報が含まれ、プロジェクトの GPU に起きている問題の追跡が可能になります。 + +Aftermath は、他のデバッグツールに比べてパフォーマンス使用料が控えめで負荷の少ないツールです。完成品のゲームと一緒に出荷して、 +カスタマーのマシンから必要なデータの追加が可能なほど低負荷です。Aftermath は、プログラマーがクラッシュの主要因の追跡を支援するマーカーをコードに挿入できるようにします。Aftermath は現在アンリアル エンジン エディタにおいて、 +問題の追跡し、レポートあるいは発見された問題を修正のために使用されています。 + +詳細およびプロジェクトでの使用方法に関しては、[Nvidia's Aftermath documentation](https://developer.nvidia.com/nvidia-aftermath) ページをご覧ください。 + diff --git a/Engine/Documentation/Source/Engine/Rendering/Nvidia/NVAftermath/NvidiaAftermath.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/Nvidia/NVAftermath/NvidiaAftermath.KOR.udn new file mode 100644 index 000000000000..07bf4f82f6c0 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Rendering/Nvidia/NVAftermath/NvidiaAftermath.KOR.udn @@ -0,0 +1,26 @@ +INTSourceChangelist:0 +Availability:Docs +Crumbs: +Title: NVIDIA Aftermath +Description: Integration of Nvidia's Aftermath technology that enabls post-mortem GPU crash analysis on NVIDIA GeForce based GPUs. +Type:Overview +Version:4.15 +Parent:Engine/Nvidia +Order:1 +topic-image:Aftermath_Topic.png +Tags:Nvidia + + +[REGION:fullwidth raw] +![](Aftermath_Banner.png)(w:900) +[/REGION] + +As of version 4.15.2, Unreal Engine supports Nvidia's **Aftermath** C++ library for Windows-based developers, which provides additional data from Nvidia GeForce-based GPUs after a crash occurs. +This data contains crucial information about what the GPU was doing when the crash occurred, enabling you to track down what's happening with the GPU in your own projects. + +Aftermath is a lightweight tool that is unobtrusive and reduces the performance footprint needed by some debugging tools. In fact, it's lightweight enough that it can even ship with finished +games to provide the data you need from your customers' machines. Aftermath enables programmers to insert markers into their code that assist in tracking the root causes of crashes. This is +now being used in the Unreal Engine Editor to track down and fix reported or captured issues. + +For additional information and how to use it in your own project, visit [Nvidia's Aftermath documentation](https://developer.nvidia.com/nvidia-aftermath) page. + diff --git a/Engine/Documentation/Source/Engine/Rendering/Nvidia/NVAlternateFrameRendering/NvidiaAlternateFrameRendering.CHN.udn b/Engine/Documentation/Source/Engine/Rendering/Nvidia/NVAlternateFrameRendering/NvidiaAlternateFrameRendering.CHN.udn new file mode 100644 index 000000000000..ae8ed23bcdff --- /dev/null +++ b/Engine/Documentation/Source/Engine/Rendering/Nvidia/NVAlternateFrameRendering/NvidiaAlternateFrameRendering.CHN.udn @@ -0,0 +1,46 @@ +INTSourceChangelist:0 +Availability:Docs +Crumbs: +Title: NVIDIA SLI Alternate Frame Rendering +Description: Integration of Nvidia's Alternate Frame Rendering technology that enables support for games using SLI. +Type:Overview +Version:4.15 +Parent:Engine/Nvidia +Order:1 +topic-image:AFR_topic.png +Tags:Nvidia + + +[REGION:fullwidth raw] +![](AFR_Banner.png) +[/REGION] + + +As of version 4.15, Unreal Engine supports NVIDIA's **Alternate Frame Rendering** (AFR) for packaged games running on NVIDIA SLI configurations. AFR works by alternating frames between the linked +GPUs; one frame is rendered by GPU 1, then the next frame is rendered by GPU 2, then back to GPU 1, and so on. By using multiple GPUs on a single monitor, its output can increase in image quality +and performance! + +With AFR, the largest improvement in performance comes from the renderer copying inter-frame dependencies between GPUs as early as possible. Developers who intend to use AFR will still need to +work directly with NVIDIA to test their games and to have it automatically switch over to use the Alternating Frame Rendering functionality where appropriate. + +For additional details, you can read NVIDIA's documentation on their [SLI modes, specifically Alternate Frame Rendering](https://docs.nvidia.com/gameworks/content/technologies/desktop/sli.htm) here. + +## Force Enabling AFR + +For some applications, the NVIDIA Control Panel enables you to add a program for which the SLI Rendering mode will have AFR forcibly enabled. To do this, follow these steps: + +1. Open the **NVIDIA Control Panel** from your task tray, then navigate to **Manage 3D Settings**. +1. Click on the **Program Settings** tab, then under **Select a program to cumstomize** use the drop-down to select a program to add. +1. Next to the option for **SLI Rendering Mode**, you can select **Force Alternate Frame Rendering**. + +![](AFRSetting.jpg) + +[REGION:note] +This feature is not guaranteed to improve the quality or performance of your application. It is not intended for use with the Unreal Engine 4 Editor. Talking directly with NVIDIA to set up this +functionality with their own driver is highly recommended. +[/REGION] + + + + + diff --git a/Engine/Documentation/Source/Engine/Rendering/Nvidia/NVAlternateFrameRendering/NvidiaAlternateFrameRendering.INT.udn b/Engine/Documentation/Source/Engine/Rendering/Nvidia/NVAlternateFrameRendering/NvidiaAlternateFrameRendering.INT.udn new file mode 100644 index 000000000000..4a342b34866f --- /dev/null +++ b/Engine/Documentation/Source/Engine/Rendering/Nvidia/NVAlternateFrameRendering/NvidiaAlternateFrameRendering.INT.udn @@ -0,0 +1,45 @@ +Availability:Docs +Crumbs: +Title: NVIDIA SLI Alternate Frame Rendering +Description: Integration of Nvidia's Alternate Frame Rendering technology that enables support for games using SLI. +Type:Overview +Version:4.15 +Parent:Engine/Nvidia +Order:1 +topic-image:AFR_topic.png +Tags:Nvidia + + +[REGION:fullwidth raw] +![](AFR_Banner.png) +[/REGION] + + +As of version 4.15, Unreal Engine supports NVIDIA's **Alternate Frame Rendering** (AFR) for packaged games running on NVIDIA SLI configurations. AFR works by alternating frames between the linked +GPUs; one frame is rendered by GPU 1, then the next frame is rendered by GPU 2, then back to GPU 1, and so on. By using multiple GPUs on a single monitor, its output can increase in image quality +and performance! + +With AFR, the largest improvement in performance comes from the renderer copying inter-frame dependencies between GPUs as early as possible. Developers who intend to use AFR will still need to +work directly with NVIDIA to test their games and to have it automatically switch over to use the Alternating Frame Rendering functionality where appropriate. + +For additional details, you can read NVIDIA's documentation on their [SLI modes, specifically Alternate Frame Rendering](https://docs.nvidia.com/gameworks/content/technologies/desktop/sli.htm) here. + +## Force Enabling AFR + +For some applications, the NVIDIA Control Panel enables you to add a program for which the SLI Rendering mode will have AFR forcibly enabled. To do this, follow these steps: + +1. Open the **NVIDIA Control Panel** from your task tray, then navigate to **Manage 3D Settings**. +1. Click on the **Program Settings** tab, then under **Select a program to cumstomize** use the drop-down to select a program to add. +1. Next to the option for **SLI Rendering Mode**, you can select **Force Alternate Frame Rendering**. + +![](AFRSetting.jpg) + +[REGION:note] +This feature is not guaranteed to improve the quality or performance of your application. It is not intended for use with the Unreal Engine 4 Editor. Talking directly with NVIDIA to set up this +functionality with their own driver is highly recommended. +[/REGION] + + + + + diff --git a/Engine/Documentation/Source/Engine/Rendering/Nvidia/NVAlternateFrameRendering/NvidiaAlternateFrameRendering.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/Nvidia/NVAlternateFrameRendering/NvidiaAlternateFrameRendering.JPN.udn new file mode 100644 index 000000000000..d62404f53747 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Rendering/Nvidia/NVAlternateFrameRendering/NvidiaAlternateFrameRendering.JPN.udn @@ -0,0 +1,46 @@ +INTSourceChangelist:3435012 +Availability:Docs +Crumbs: +Title:NVIDIA SLI Alternate Frame Rendering +Description:SLI を使用するゲームのサポートを可能にする Nvidia Alternate Frame Rendering 機能 +Type:Overview +Version:4.15 +Parent:Engine/Nvidia +Order:1 +topic-image:AFR_topic.png +Tags:Nvidia + + +[REGION:fullwidth raw] +![](AFR_Banner.png) +[/REGION] + + +アンリアル エンジン 4.15 では、NVIDIA SLI コンフィギュレーションでパッケージ化されたゲームを実行するための NVIDIA **Alternate Frame Rendering** (AFR) がサポートされています。AFR は結びついた GPU 間でフレームを交互に変える、 +つまり 1 つのフレームを GPU 1、次のフレームは GPU 2、その次はまたは GPU 1 を使ってレンダリングをすることにより動作します。単一のモニタ上で複数の GPU を使用すると、 +画質とパフォーマンスが向上します! + +AFR によってパフォーマンスで最も改善される点は、レンダラが GPU 間でフレーム間の依存性を可能な限り早くコピーすることです。AFR を使用する場合、デベロッパーは NVIDIA を直接使ってゲームをテストし、 +必要に応じて Alternating Frame Rendering 機能へ自動的に切り替わるようにする必要があります。 + +詳細に関下は、NVIDIA のドキュメント [SLI modes, specifically Alternate Frame Rendering](https://docs.nvidia.com/gameworks/content/technologies/desktop/sli.htm) をご覧ください。 + +## AFR を強制的に有効にする方法 + +アプリケーションの中には、NVIDIA コントロール パネルでプログラムを追加できる場合があります。以下の手順で行います。 + +1. タスク トレイから **[NVIDIA Control Panel]** を開いて、**[Manage 3D Settings]** を開きます。 +1. **[Program Settings]** タブをクリックして **[Select a program to cumstomize]** の下のドロップダウンから追加するプログラムを選択します。 +1. **[SLI Rendering Mode]** オプションの横にある **[Force Alternate Frame Rendering]** を選択します。 + +![](AFRSetting.jpg) + +[REGION:note] +この機能はアプリケーションの品質もしくはパフォーマンスの改善を保証するものではありません。アンリアル エンジン 4 エディタによる使用を意図していません。NVIDIA のドライバーでこの機能を設定する場合は、 +直接 NVIDIA に問い合わせることを強くお勧めします。 +[/REGION] + + + + + diff --git a/Engine/Documentation/Source/Engine/Rendering/Nvidia/NVAlternateFrameRendering/NvidiaAlternateFrameRendering.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/Nvidia/NVAlternateFrameRendering/NvidiaAlternateFrameRendering.KOR.udn new file mode 100644 index 000000000000..ae8ed23bcdff --- /dev/null +++ b/Engine/Documentation/Source/Engine/Rendering/Nvidia/NVAlternateFrameRendering/NvidiaAlternateFrameRendering.KOR.udn @@ -0,0 +1,46 @@ +INTSourceChangelist:0 +Availability:Docs +Crumbs: +Title: NVIDIA SLI Alternate Frame Rendering +Description: Integration of Nvidia's Alternate Frame Rendering technology that enables support for games using SLI. +Type:Overview +Version:4.15 +Parent:Engine/Nvidia +Order:1 +topic-image:AFR_topic.png +Tags:Nvidia + + +[REGION:fullwidth raw] +![](AFR_Banner.png) +[/REGION] + + +As of version 4.15, Unreal Engine supports NVIDIA's **Alternate Frame Rendering** (AFR) for packaged games running on NVIDIA SLI configurations. AFR works by alternating frames between the linked +GPUs; one frame is rendered by GPU 1, then the next frame is rendered by GPU 2, then back to GPU 1, and so on. By using multiple GPUs on a single monitor, its output can increase in image quality +and performance! + +With AFR, the largest improvement in performance comes from the renderer copying inter-frame dependencies between GPUs as early as possible. Developers who intend to use AFR will still need to +work directly with NVIDIA to test their games and to have it automatically switch over to use the Alternating Frame Rendering functionality where appropriate. + +For additional details, you can read NVIDIA's documentation on their [SLI modes, specifically Alternate Frame Rendering](https://docs.nvidia.com/gameworks/content/technologies/desktop/sli.htm) here. + +## Force Enabling AFR + +For some applications, the NVIDIA Control Panel enables you to add a program for which the SLI Rendering mode will have AFR forcibly enabled. To do this, follow these steps: + +1. Open the **NVIDIA Control Panel** from your task tray, then navigate to **Manage 3D Settings**. +1. Click on the **Program Settings** tab, then under **Select a program to cumstomize** use the drop-down to select a program to add. +1. Next to the option for **SLI Rendering Mode**, you can select **Force Alternate Frame Rendering**. + +![](AFRSetting.jpg) + +[REGION:note] +This feature is not guaranteed to improve the quality or performance of your application. It is not intended for use with the Unreal Engine 4 Editor. Talking directly with NVIDIA to set up this +functionality with their own driver is highly recommended. +[/REGION] + + + + + diff --git a/Engine/Documentation/Source/Engine/Rendering/Nvidia/Nvidia.CHN.udn b/Engine/Documentation/Source/Engine/Rendering/Nvidia/Nvidia.CHN.udn new file mode 100644 index 000000000000..b37138ce48f2 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Rendering/Nvidia/Nvidia.CHN.udn @@ -0,0 +1,24 @@ +INTSourceChangelist:0 +Availability:Docs +Title:NVIDIA Feature Support +Description: Integrated and supported technologies from NVIDIA for use with your games. +Crumbs: +Parent:Engine/Rendering +Order:101 +type:landing +version:4.16 +topic-image:NVIDIA_logo_Topic.png + + +[REGION:raw] +![](nvidia_logo_horizontal.png)(w:700) +[/REGION] + + +Here you will find the integrated technologies and relevant information from NVIDIA for use with your games. + + +%Engine\Nvidia\NVAlternateFrameRendering:Topic% +%Engine\Nvidia\NVAftermath:Topic% + + diff --git a/Engine/Documentation/Source/Engine/Rendering/Nvidia/Nvidia.INT.udn b/Engine/Documentation/Source/Engine/Rendering/Nvidia/Nvidia.INT.udn new file mode 100644 index 000000000000..a0f0ae722a1e --- /dev/null +++ b/Engine/Documentation/Source/Engine/Rendering/Nvidia/Nvidia.INT.udn @@ -0,0 +1,23 @@ +Availability:Docs +Title:NVIDIA Feature Support +Description: Integrated and supported technologies from NVIDIA for use with your games. +Crumbs: +Parent:Engine/Rendering +Order:101 +type:landing +version:4.16 +topic-image:NVIDIA_logo_Topic.png + + +[REGION:raw] +![](nvidia_logo_horizontal.png)(w:700) +[/REGION] + + +Here you will find the integrated technologies and relevant information from NVIDIA for use with your games. + + +%Engine\Nvidia\NVAlternateFrameRendering:Topic% +%Engine\Nvidia\NVAftermath:Topic% + + diff --git a/Engine/Documentation/Source/Engine/Rendering/Nvidia/Nvidia.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/Nvidia/Nvidia.JPN.udn new file mode 100644 index 000000000000..3b7782fa4357 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Rendering/Nvidia/Nvidia.JPN.udn @@ -0,0 +1,24 @@ +INTSourceChangelist:3435012 +Availability:Docs +Title:NVIDIA 機能のサポート +Description:使用する NVIDIA 技術の統合およびサポート +Crumbs: +Parent:Engine/Rendering +Order:101 +type:landing +version:4.16 +topic-image:NVIDIA_logo_Topic.png + + +[REGION:raw] +![](nvidia_logo_horizontal.png)(w:700) +[/REGION] + + +ゲームで使用できる NVIDIA の統合技術と関連情報です。 + + +%Engine\Nvidia\NVAlternateFrameRendering:Topic% +%Engine\Nvidia\NVAftermath:Topic% + + diff --git a/Engine/Documentation/Source/Engine/Rendering/Nvidia/Nvidia.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/Nvidia/Nvidia.KOR.udn new file mode 100644 index 000000000000..1452d3ba3634 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Rendering/Nvidia/Nvidia.KOR.udn @@ -0,0 +1,24 @@ +INTSourceChangelist:3435012 +Availability:Docs +Title:NVIDIA 피처 지원 +Description: 게임에서 사용하기 위한 NVIDIA 테크놀로지 통합 및 지원 사항입니다. +Crumbs: +Parent:Engine/Rendering +Order:101 +type:landing +version:4.16 +topic-image:NVIDIA_logo_Topic.png + + +[REGION:raw] +![](nvidia_logo_horizontal.png)(w:700) +[/REGION] + + +게임에서 사용하기 위한 NVIDIA 통합 테크놀로지 및 관련 정보를 찾아볼 수 있는 페이지입니다. + + +%Engine\Nvidia\NVAlternateFrameRendering:Topic% +%Engine\Nvidia\NVAftermath:Topic% + + diff --git a/Engine/Documentation/Source/Engine/Rendering/Overview/RenderingOverview.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/Overview/RenderingOverview.KOR.udn index a8eb90201045..36a7361e2b67 100644 --- a/Engine/Documentation/Source/Engine/Rendering/Overview/RenderingOverview.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/Overview/RenderingOverview.KOR.udn @@ -58,16 +58,16 @@ tags:Rendering ## 디퍼드 셰이딩 -언리얼 엔진 3 에서 사용되던 포워드(바로바로 처리하는) 라이팅 방법과는 달리, 언리얼 엔진 4 의 모든 라이트는 디퍼드(비슷한 종류의 패스를 모아 한꺼번에 처리하는) 방식으로 적용됩니다. 머티리얼은 그 특성을 GBuffer 에 쓰고, 라이팅 패스에서는 픽셀별로 머티리얼 프로퍼티를 읽어들여 라이팅을 처리합니다. +언리얼 엔진 3 에서 사용되던 포워드(바로바로 처리하는) 라이팅 방법과는 달리, 언리얼 엔진 4 의 모든 라이트는 디퍼드(비슷한 종류의 패스(pass)를 모아 한꺼번에 처리하는) 방식으로 적용됩니다. 머티리얼은 그 특성을 GBuffer 에 쓰고, 라이팅 패스에서는 픽셀별로 머티리얼 프로퍼티를 읽어들여 라이팅을 처리합니다. -## 라이팅 패쓰 +## 라이팅 패스 -UE4 에는 세 가지의 라이팅 패쓰가 있습니다: - * **완전 다이내믹** - [무버블 라이트](Engine/Rendering/LightingAndShadows/LightMobility/DynamicLights) +UE4 에는 세 가지의 라이팅 패스가 있습니다: + * **전체 다이내믹** - [무버블 라이트](Engine/Rendering/LightingAndShadows/LightMobility/DynamicLights) * **부분 스태틱** - [스테이셔너리 라이트](Engine/Rendering/LightingAndShadows/LightMobility/StationaryLights) - * **완전 스태틱** - [스태틱 라이트](Engine/Rendering/LightingAndShadows/LightMobility/StaticLights) + * **전체 스태틱** - [스태틱 라이트](Engine/Rendering/LightingAndShadows/LightMobility/StaticLights) - 이들 각각은 퀄리티, 퍼포먼스, 게임내 변경 여부가 각기 다른 툴입니다. 각 게임마다 적합한 패쓰를 선택하면 됩니다. + 이들 각각은 퀄리티, 퍼포먼스, 게임내 변경 여부가 각기 다른 툴입니다. 각 게임마다 적합한 패스를 선택하면 됩니다. ## 라이팅된 반투명 diff --git a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Cascade/CascadeEditor.INT.udn b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Cascade/CascadeEditor.INT.udn index 37ac6d1d1a03..443975ad0d46 100644 --- a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Cascade/CascadeEditor.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Cascade/CascadeEditor.INT.udn @@ -4,6 +4,10 @@ Crumbs: %ROOT%, Engine, Engine/Rendering/ParticleSystems Description:An overview of the Cascade Editor's UI, breaking down each key area. Version: 4.9 tags:Particles +parent:Engine/Rendering/ParticleSystems +order:2 +type:reference +topic-image:cascade_topic.png [VAR:Topic] [OBJECT:Topic] diff --git a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Cascade/CascadeEditor.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Cascade/CascadeEditor.JPN.udn index 95299bc38a30..71cd1126cbb0 100644 --- a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Cascade/CascadeEditor.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Cascade/CascadeEditor.JPN.udn @@ -1,10 +1,14 @@ -INTSourceChangelist:3243860 +INTSourceChangelist:3429247 Availability:Public Title:カスケード パーティクル エディタのリファレンス Crumbs: %ROOT%, Engine, Engine/Rendering/ParticleSystems Description:カスケード エディタの各 UI の概説 Version:4.9 tags:Particles +parent:Engine/Rendering/ParticleSystems +order:2 +type:reference +topic-image:cascade_topic.png [VAR:Topic] [OBJECT:Topic] @@ -32,7 +36,7 @@ tags:Particles -## カスケードを開く +## カスケードの開き方 カスケード パーティクル エディタは、いずれかのパーティクル システム アセットをダブルクリック、もしくは **コンテンツブラウザ** 内のパーティクル システム アセットのコンテキスト メニューを右クリックして開きます。カスケード内の特定のパーティクル システムの編集が可能になります。 @@ -50,7 +54,7 @@ tags:Particles 1. [ビューポート パネル](#ビューポートパネル) - 現在のパーティクル システムを表示します (そのシステムにあるすべてのエミッタを含みます)。_Sim_ ツールバーのオプション設定のシミュレーション速度で制御します。 1. [Emitters パネル](#Emittersパネル) -現在のパーティクル システム内にあるすべてのエミッタのリストと、これらのエミッタ内のすべてのモジュールのリストがあります。 1. [詳細パネル](#詳細パネル) -現在のパーティクル システム、パーティクル エミッタ、パーティクル モジュールを表示したり、修正できます。 -1. [カーブ エディタ](#カーブエディタ) -このグラフ エディタでは、相対時間または絶対時間のいずれかで修正されているプロパティが表示されます。グラフ エディタにはモジュールが追加されるので、表示コントロールがあります (このドキュメントの後半で説明します)。 +1. [カーブ エディタ](#カーブエディタ) - 相対時間または絶対時間のいずれかで修正されたプロパティを表示するグラフ エディタです。グラフ エディタにはモジュールが追加と、表示を調節できます (このドキュメントの後半で説明します)。 @@ -64,7 +68,7 @@ tags:Particles | ------- | ----------- | | [REGION:tablesection]**ロードと保存**[/REGION] || | **Save** | 現在のパーティクル システムのアセットを保存します。| -| **Save All** | 全てのアセットを保存します。| +| **Save All** | すべてのアセットを保存します。| | **Choose Files to Save** | アセットの保存オプションを付けてダイアログを開きます。 | | [REGION:tablesection]**アプリケーション**[/REGION] || | **Switch Project** | 使用可能なすべてのゲーム プロジェクトを切り替えます。 | @@ -91,7 +95,7 @@ tags:Particles | コマンド | 説明 | | ------- | ----------- | -| [REGION:tablesection]**Asset Editor TabsEditor Tabs**[/REGION] || +| [REGION:tablesection]**アセット エディタ TabsEditor タブ**[/REGION] || | **Viewport** | [ビューポートパネル] (#ビューポートパネル) タブを開きます。このタブには、結果として得られるパーティクル システムが表示されます。 | | **Emitters** | [エミッタ リスト](#Emittersパネル) タブを開きます。このタブで、各種エミッタをパーティクル システムに追加できます。 | | **Details** | [詳細パネル](#詳細パネル) タブを開きます。このタブで、各パーティクル モジュールのプロパティを編集できます。| @@ -119,17 +123,17 @@ tags:Particles | ![Cascade_Toolbar_Redo.png](Cascade_Toolbar_Redo.png)| **Redo** | 直前の元に戻した操作をやり直します。**Ctrl + Y** を使用しても同じ操作を行うことができます。。 | | ![Cascade_Toolbar_Thumbnail.png](Cascade_Toolbar_Thumbnail.png)| **Save Thumbnail Image** | コンテンツ ブラウザのパーティクル システムのサムネイルとして、ビューポート ペインのカメラからビューポートを保存します。 | |![](Cascade_Toolbar_Bounds.png)|**Toggle Bounds**| ビューポート ペインで、パーティクル システムの現在の境界の表示を切り替えます。| -|![](Cascade_Toolbar_BoundsOptions.png)|**Bounds Options**| クリックすると、GPU スプライトパーティクル システムに対する固定の境界をセットアップできます。固定された境界が GPU スプライト パーティクルの移動可能距離を制限します。| +|![](Cascade_Toolbar_BoundsOptions.png)|**Bounds Options**| クリックすると、GPU スプライトパーティクル システムに対して固定の境界をセットアップできます。固定された境界が GPU スプライト パーティクルの移動可能距離を制限します。| |![](Cascade_Toolbar_OriginAxis.png)|**Toggle Origin Axis**| パーティクル ビューポート ウィンドウで、原点軸の表示、非表示を切り替えます。 | | ![Cascade_Toolbar_RegenLOD.png](Cascade_Toolbar_RegenLOD.png)| **Regenerate lowest LOD duplicating highest** | 最高 LOD を複製して最低 LOD を再生成します。 | -| ![Cascade_Toolbar_RegenLODPer.png](Cascade_Toolbar_RegenLODPer.png)| **Regenerate lowest LOD** | 最高 LOD の値のプリセットしたパーセント値を使用して、最低 LOD を再生成します。 | +| ![Cascade_Toolbar_RegenLODPer.png](Cascade_Toolbar_RegenLODPer.png)| **Regenerate lowest LOD** | 最高 LOD 値の設定済みパーセントである値を使って最低 LOD を再生成します。 | | ![Cascade_Toolbar_HighestLOD.png](Cascade_Toolbar_HighestLOD.png)| **Jump to Highest LOD Level** | 最高 LOD をロードします。 | | ![Cascade_Toolbar_AddLOD_Before.png](Cascade_Toolbar_AddLOD_Before.png)| **Add LOD before current** | 現在ロードした LOD の直前に新しい LOD を追加します。 | | ![Cascade_Toolbar_AddLOD_After.png](Cascade_Toolbar_AddLOD_After.png)| **Add LOD after current** | 現在ロードした LOD の直後に新しい LODを追加します。 | | ![Cascade_Toolbar_LowerLOD.png](Cascade_Toolbar_LowerLOD.png)| **Jump to Lower LOD Level** | 次に低い LOD をロードします。 | | ![Cascade_Toolbar_LowestLOD.png](Cascade_Toolbar_LowestLOD.png)| **Jump to Lowest LOD Level** |最低 LOD をロードします。 | | ![Cascade_Toolbar_DeleteLOD.png](Cascade_Toolbar_DeleteLOD.png)| **Delete LOD** | 現在ロードした LOD を削除します。 | -| ![Cascade_Toolbar_CurrentLOD.png](Cascade_Toolbar_CurrentLOD.png)| **Current LOD Slider** | プレビューしたい現在の LOD を選択できます。値を手入力、もしくはマウスをドラッグして数字を編集します。 +| ![Cascade_Toolbar_CurrentLOD.png](Cascade_Toolbar_CurrentLOD.png)| **Current LOD Slider** | プレビューする LOD を選択できます。値を手入力、もしくはマウスをドラッグして数字を編集します。 @@ -164,7 +168,7 @@ tags:Particles ![ViewMenu.png](ViewMenu.png) -[View (表示)] メニューでは、ビューポート ペインの様々な診断と可視化機能を表示、非表示にすることができます。[View (表示)] メニューには以下のオプションが含まれます。 +[View (表示)] メニューでは、ビューポート ペインの様々な診断と可視化機能の表 / 非表示が可能になります。[View (表示)] メニューには以下のオプションが含まれます。 | アイテム | 説明 | @@ -218,13 +222,13 @@ tags:Particles ###### Unlit (ライティング無し) -[Unlit] ビューモードでは、ライティングまたはポストプロセスなしのパーティクルの結果が表示されます。 +[Unlit] ビューモードでは、ライティングまたはポストプロセスなしのパーティクルが表示されます。 ![Unlit.png](Unlit.png) ###### Lit (ライティング有り) -[Unlit] ビューモードでは、ライティングまたはポストプロセスなしのパーティクルの結果が表示されます。 +[Lit] ビューモードでは、ライティングまたはポストプロセスが付いたパーティクルが表示されます。 ![Lit.png](Lit.png) @@ -268,11 +272,11 @@ Shader Complexity (シェーダの複雑度) では、特定のシェーダに ![EmitterList.png](EmitterList.png)(w:700) -**[Emitters]** パネルには、カスケードで現在開いているパーティクル システム内の各パーティクル エミッタがあります。ユーザーは、パーティクル システムの外観と挙動を制御する様々なパーティクル モジュールをここで追加、選択、作業を行います。 +**[Emitters]** パネルには、カスケードで現在開いているパーティクル システム内の各パーティクル エミッタがあります。ユーザーは、パーティクル システムの外観とビヘイビアを制御する様々なパーティクル モジュールをここで追加、選択、作業を行います。 エミッタ リストには、現在のパーティクル システム内のすべてのエミッタが横方向に配置されています。パーティクル システムあたりのエミッタ数に制限はなく、エフェクト全体でそれぞれが別々の側面を処理するのが一般的です。 -1 カラムで 1 つのパーティクル エミッタを表します。上部にエミッタブロック、その下に任意の数のモジュールブロックが表示されます。エミッタ ブロックには、エミッタの名前、タイプなどのエミッタの主要なプロパティが含まれます。その下にあるモジュールは、それぞれパーティクルの動作の様々な側面を制御します。 +1 カラムにつきパーティクル エミッタ 1 つを表します。上部にエミッタブロック、その下に任意の数のモジュールブロックが表示されます。エミッタ ブロックには、エミッタの名前、タイプなどのエミッタの主要なプロパティが含まれます。その下にあるモジュールは、それぞれパーティクルの動作の様々な側面を制御します。 エミッタ リストのインターフェイスは、比較的簡単なものですが、右マウスボタンからアクセスできるコンテキスト依存のメニューもあります。 @@ -390,7 +394,7 @@ Shader Complexity (シェーダの複雑度) では、特定のシェーダに カスケード インターフェイスには、標準のアンリアル エディタの [Curve Editor (カーブ エディタ)] ウィンドウが含まれます。このウィンドウで、ユーザーはパーティクルの寿命中またはエミッタの寿命中に変更すべき値も調整が可能です。つまり、時間の経過に伴い変化する値を定義します。カーブ エディタ内でプロパティを (一般的にパーティクル モジュール内から) 編集可能にするには、そのプロパティはカーブを利用する DistributionFloatConstantCurve などの Distribution タイプでなければなりません。Distributions (ディストリビューション) の操作については、[ディストリビューションのセクション](Engine/Basics/Distributions) を参照してください。 -詳細は [カーブ エディタのユーザーガイド](Engine/UI/CurveEditor) ドキュメントを参照してください。 +詳細は [カーブ エディタのユーザーガイド](Engine/UI/CurveEditor) ドキュメントを参照してください。 [REGION:note] カーブ エディタにモジュールを追加するには、モジュールの左側に表示される緑色のボックスをクリックしてください。グラフ エディタに表示されるモジュールの色は、モジュール作成時にランダムに決定されます。色を変更するには、各モジュールの [Property] ウィンドウの Module Editor Color プロパティを開いて行います。 @@ -425,7 +429,7 @@ Shader Complexity (シェーダの複雑度) では、特定のシェーダに グラフエディタで点を作成するには、目的の値に対するスプラインを **Ctrl + 左クリック** します。一番簡単な方法は、前述のチェックボックスを使い他のモジュールをすべてオフにすることです。すべてのモジュールは、時間 0 の単一キーとしてゼロの位置から開始します。タイムライン内でスプラインの任意の位置を **Ctrl + 左クリック** すると、そこに点が作成されます。この点は自由自在にドラッグできますが、既に述べたようにスプラインがベクトル (XYZ) を表す場合は、そのベクトルの 3 つのキーすべての時間が移動するのに対し、値は変動しません。 -キーポイントを **右クリック** するとメニューが表示され、そこでキーポイントの時間と値を手動で入力することができます。キーがカラーカーブ内にある場合は、カラーピッカーを使って色を選択できます。 +キーポイントを **右クリック** して表示されるメニューに、キーポイントの時間と値を手動で入力することができます。キーがカラーカーブ内にある場合は、カラーピッカーを使って色を選択できます。 モジュールが ColorOverLife の場合、描かれるスプラインはその時点の色を反映しますが、点はそのスプラインの特定のチャネルを反映する色で描かれます。 @@ -456,9 +460,9 @@ Shader Complexity (シェーダの複雑度) では、特定のシェーダに ディストリビューション (Distribution) は特殊なデータ型であり、非常に専門的な方法で数を定めるように設計されています。パーティクル モジュール内で利用可能な主要プロパティのほとんどは、割り当てられたディストリビューションを持ちます。こうしたディストリビューションは、プロパティが単一の値、範囲を持つ、またはカーブに沿って補間されるものとして定義する場合があります。 -使用するディストリビューションのタイプは、プロパティに基づき変わります。例として、すべてのパーティクルのライフタイムを 5 秒にしたい場合、 _DistributionFloatConstant_ のディストリビューションでは、単一の値を保持できます。しかし、パーティクルのライフタイムを 2 秒から 5 秒の間のランダムな値にしたい場合、 そうした範囲を指定できる DistributionFloatUniform に切り替えます。 +使用するディストリビューションのタイプは、プロパティに基づき変わります。例として、すべてのパーティクルのライフタイムを 5 秒にするには、_DistributionFloatConstant_ のディストリビューションで単一の値を保持することができます。パーティクルのライフタイムを 2 秒から 5 秒の間のランダムな値にするのであれば、そうした範囲の指定が可能な _DistributionFloatUniform_ に切り替えます。 -新規ユーザーにとっては、最初は分布はわかりずらいと感じるかもしれません。しかし、パーティクル システム内で様々なプロパティを扱ううえで分布がもたらす自由度の高さをすぐに実感するでしょう。詳細は [ディストリビューションのリファレンス](Engine/Basics/Distributions) ページを参照してください。 +新規ユーザーはディストリビューションが最初は複雑に感じるかもしれません。しかし、パーティクル システム内で各種プロパティの使用によって自由度が増す事にすぐ気が付くでしょう。詳細は [ディストリビューションのリファレンス](Engine/Basics/Distributions) ページを参照してください。 (#PartileSystemLODs) diff --git a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Cascade/CascadeEditor.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Cascade/CascadeEditor.KOR.udn index 253dc9cbcf39..677942ee7e87 100644 --- a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Cascade/CascadeEditor.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Cascade/CascadeEditor.KOR.udn @@ -1,10 +1,14 @@ -INTSourceChangelist:3243860 +INTSourceChangelist:3429247 Availability: Public Title:캐스케이드 파티클 에디터 참고서 Crumbs: %ROOT%, Engine, Engine/Rendering/ParticleSystems Description:캐스케이드 에디터의 UI 를 핵심 영역별로 나눠 보는 개요입니다. Version: 4.9 tags:Particles +parent:Engine/Rendering/ParticleSystems +order:2 +type:reference +topic-image:cascade_topic.png [VAR:Topic] [OBJECT:Topic] diff --git a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/LODs/LODs.INT.udn b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/LODs/LODs.INT.udn index 3f6319b7f1f1..bc1f6ef6e79d 100644 --- a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/LODs/LODs.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/LODs/LODs.INT.udn @@ -4,6 +4,7 @@ Crumbs: %ROOT%, Engine, Engine/Rendering/ParticleSystems Description:GPU-simulation of particles that allows for hundreds of thousands of particles at any time. Version: 4.9 tags:Particles +topic-image:ParticleSystemLOD_topic.png [TOC(start:2 end:3)] diff --git a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/LODs/LODs.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/LODs/LODs.JPN.udn index c00bccf84dba..705ed59ddacd 100644 --- a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/LODs/LODs.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/LODs/LODs.JPN.udn @@ -1,14 +1,15 @@ -INTSourceChangelist:3243860 +INTSourceChangelist:3467293 Availability:Public Title:パーティクル システムの詳細度 (LOD) Crumbs: %ROOT%, Engine, Engine/Rendering/ParticleSystems Description:膨大な数のパーティクルに対しいつでも実施可能な GPU シミュレーション Version:4.9 tags:Particles +topic-image:ParticleSystemLOD_topic.png [TOC(start:2 end:3)] -詳細度 (LOD) を使うと、エフェクト アーティストはプレイヤーの範囲に合わせてスクリーン空間を最も効率よく使用するパーティクル エフェクトを作成することができます。キャンプ ファイアーのパーティクル システムを考えてください。次のようなエミッタが含まれています。 +LOD を使うと、エフェクト アーティストはプレイヤーの範囲に合わせてスクリーン スペースを最も効率よく使用するパーティクル エフェクトを作成することができます。キャンプ ファイアーのパーティクル システムを考えてください。次のようなエミッタが含まれています。 * 炎心 * 外炎 @@ -17,16 +18,16 @@ tags:Particles * 一層以上の煙 -お持ちのシステムは間近ではこのように見えると思います。 +詳細表示するとこのようなものが表示されます。 ![FireEffect_Close.png](FireEffect_Close.png) -ただし、プレイヤーが遠ざかっていくと、占有するスクリーン空間は以下のように激減します。 +ただし、プレイヤーが遠ざかっていくと、スクリーン スペースは以下のように小さくなります。 ![FireEffect_Distant.png](FireEffect_Distant.png) -このようなケースでは、燃えさしなど、パーティクル システムのアスペクトがレンダリングには小さすぎる (ピクセルより小さい) 場合があります。しかしながら、このようなパーティクルも計算や処理はまだ可能です。そこで LOD の出番です。LOD はパーティクル システムを距離に合わせて簡素化することが可能なので、プレイヤーがエフェクトを効果的に認識するには遠すぎる状態になると、システム内のエミッタとモジュールは設定を終了、または完全にオフにすることができます。 +これは、燃えさしなどパーティクル システムのアスペクトがレンダリングには小さすぎる (ピクセルより小さい) ためです。しかしながら、このようなパーティクルでも計算や処理は可能です。そこで LOD の出番です。LOD はパーティクル システムを距離に合わせて簡素化することが可能なので、プレイヤーがエフェクトを効果的に認識するには遠すぎる状態になると、システム内のエミッタとモジュールは設定を終了、または完全にオフにすることができます。 本ドキュメントでは、詳細度 (LOD) に関して、インゲームでの使用方法に加えてお使いのパーティクル システムでの作成方法について記述します。 @@ -40,7 +41,7 @@ tags:Particles ![Cascade_Toolbar.png](Cascade_Toolbar.png) -以下が各コントロールの内訳です。 +各コントロールの詳細です。 | **ボタン** | **名前** | **説明** | diff --git a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/LODs/LODs.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/LODs/LODs.KOR.udn index daabd3792a2e..a4e45c0e1601 100644 --- a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/LODs/LODs.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/LODs/LODs.KOR.udn @@ -1,10 +1,11 @@ -INTSourceChangelist:3243860 +INTSourceChangelist:3467293 Availability:Public Title: 파티클 시스템 레벨 오브 디테일 (LOD) Crumbs: %ROOT%, Engine, Engine/Rendering/ParticleSystems Description:언제든지 십만 단위의 파티클이 가능한 GPU 파티클 시뮬레이션 입니다. Version: 4.9 tags:Particles +topic-image:ParticleSystemLOD_topic.png [TOC(start:2 end:3)] diff --git a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Optimization/Optimization.INT.udn b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Optimization/Optimization.INT.udn index 6b0113e67d5a..a88b3e90b835 100644 --- a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Optimization/Optimization.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Optimization/Optimization.INT.udn @@ -4,6 +4,7 @@ Crumbs: %ROOT%, Engine, Engine/Rendering/ParticleSystems Description:Solving performance issues by optimizing Particle Systems. Version: 4.9 tags:Particles +topic-image:VFXOptimization_topic.png [TOC (start:2 end:3)] diff --git a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Optimization/Optimization.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Optimization/Optimization.JPN.udn index c17b2eb443c3..e7868cdd4ca9 100644 --- a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Optimization/Optimization.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Optimization/Optimization.JPN.udn @@ -1,22 +1,23 @@ -INTSourceChangelist:3243860 +INTSourceChangelist:3467293 Availability:Public Title:VFX 最適化ガイド Crumbs: %ROOT%, Engine, Engine/Rendering/ParticleSystems Description:パーティクル システムの最適化によるパフォーマンス問題の解決方法 Version:4.9 tags:Particles +topic-image:VFXOptimization_topic.png [TOC (start:2 end:3)] -このドキュメントは、カスケード、マテリアルエディタ、マチネ、一般的なエフェクトに関連したパフォーマンス問題に関する知識があることを前提としています。パフォーマンス問題を解決する方法は複数あります。このドキュメントでは、利用可能なツールを使ってこれらの問題を解決するために、Epic のエフェクトチームが取っている方法の概略を説明します。 +このドキュメントは、カスケード、マテリアルエディタ、マチネ、一般的なエフェクトに関連したパフォーマンス問題に関する知識があることを前提としています。パフォーマンス問題には複数の解決方法があります。このドキュメントでは、Epic のエフェクトチームが利用可能なツールで行ったこれらの問題の解決方法を概説します。 ## エフェクト パフォーマンスを低下させる一般的な原因 -$ **Overdraw (オーバードロー)** :パーティクルが覆うスクリーン空間の量、および、それらのパーティクルに関する命令数です。オーバードロー = ピクセルシェーダーの負荷 = レイヤー数 × 影響を受ける平均ピクセル数(GPU) -$ **Tick Time (ティック時間)** :ゲームスレッドが、すべてのパーティクルシステムを更新するのに要する時間です。(ゲーム スレッド) -$ **Draw Calls (描画コール)** :GPU のために準備するステート設定です。(レンダリング スレッド) -$ **Bounds Calculation (境界計算)** :エフェクトの境界を更新するのに要する時間です。この境界は、カメラの視錘台に基づいてビジビリティを決定するために使用されるものです。(エフェクトの境界が見えるか?) +$ **Overdraw (オーバードロー)** :パーティクルが覆うスクリーン スペースの面積、およびそれらのパーティクルに関する命令数です。オーバードロー = ピクセルシェーダーの負荷 = レイヤー数 × 影響を受ける平均ピクセル数(GPU) +$ **Tick Time (ティック時間)** :ゲームスレッドによるすべてのパーティクルシステムの更新に要する時間です。(ゲーム スレッド) +$ **Draw Calls (描画コール)** :GPU 用のステート設定です。(レンダリング スレッド) +$ **Bounds Calculation (境界計算)** :カメラの視錘台に基づいたビジビリティ決定に使用されるエフェクト境界の更新に要する時間です。(エフェクト結合境界が見えるか?) これらの主要な問題には、問題発生の原因となる下位の問題が多数含まれます。通常、下位の問題それぞれについて、パフォーマンス問題を処理するためのツールが用意されています。 @@ -24,7 +25,7 @@ $ **Bounds Calculation (境界計算)** :エフェクトの境界を更新する ##エフェクト パフォーマンスのためのコアシステム $ **GPU** :スクリーン上にピクセルを描画するのに要する時間です。(オーバードロー) -$ **Game Thread (ゲームスレッド)** :そのパーティクル システム ビヘイビアの更新にかかる時間です。(ティック時間) +$ **Game Thread (ゲームスレッド)** :そのパーティクル システム ビヘイビアの更新に要する時間です。(ティック時間) $ **Render Thread (レンダリングスレッド)** :パーティクル ジオメトリおよび関連する描画コールをパック化するために要する時間です。(描画コール) ## パフォーマンスへの配慮 @@ -69,10 +70,10 @@ $ **Render Thread (レンダリングスレッド)** :パーティクル ジオ [PARAM:description] [/PARAM] [PARAM:links] - * [VFX の最適化、ビジュアル エフェクトとパフォーマンスのバランスをとる](Engine/Rendering/ParticleSystems/Optimization/Balance) + * [VFX の最適化、ビジュアル エフェクトとパフォーマンス間のバランス](Engine/Rendering/ParticleSystems/Optimization/Balance) * [VFX 最適化の中心的な概念](Engine/Rendering/ParticleSystems/Optimization/Concepts) - * [VFX の最適化、結果を得る](Engine/Rendering/ParticleSystems/Optimization/Results) - * [VFX の最適化、分割画面](Engine/Rendering/ParticleSystems/Optimization/SplitScreen) + * [VFX の最適化:結果表示](Engine/Rendering/ParticleSystems/Optimization/Results) + * [VFX の最適化:分割画面](Engine/Rendering/ParticleSystems/Optimization/SplitScreen) [/PARAM] [/OBJECT] diff --git a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Optimization/Optimization.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Optimization/Optimization.KOR.udn index 430b7870458a..77bbf04c4d60 100644 --- a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Optimization/Optimization.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Optimization/Optimization.KOR.udn @@ -1,10 +1,11 @@ -INTSourceChangelist:3243860 +INTSourceChangelist:3467293 Availability: Public Title:VFX 최적화 안내서 Crumbs: %ROOT%, Engine, Engine/Rendering/ParticleSystems Description:파티클 시스템 최적화를 통한 퍼포먼스 문제 해결하기 입니다. Version: 4.9 tags:Particles +topic-image:VFXOptimization_topic.png [TOC (start:2 end:3)] diff --git a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Overview/KeyConcepts.INT.udn b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Overview/KeyConcepts.INT.udn index 1df62c643a80..2f5ac6951aef 100644 --- a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Overview/KeyConcepts.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Overview/KeyConcepts.INT.udn @@ -4,6 +4,12 @@ Crumbs: %ROOT%, Engine, Engine/Rendering/ParticleSystems Description:Critical concepts for working with particles in Unreal and the Cascade particle editor. Version: 4.9 tags:Particles +tags:Getting Started +parent:Engine/Rendering/ParticleSystems +order:1 +type:overview +topic-image:Engine/Rendering/ParticleSystems/particles_topic.png + [TOC(start:2 end:3)] diff --git a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Overview/KeyConcepts.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Overview/KeyConcepts.JPN.udn index 901fc8b510fb..0f5c52022411 100644 --- a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Overview/KeyConcepts.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Overview/KeyConcepts.JPN.udn @@ -1,13 +1,20 @@ -INTSourceChangelist:2743189 +INTSourceChangelist:3429247 Availability:Public Title:キー パーティクルのコンセプト Crumbs: %ROOT%, Engine, Engine/Rendering/ParticleSystems Description:アンリアル エディタおよびカスケード パーティクル エディタにおいてパーティクルを操作するための非常に重要な概念 Version:4.9 +tags:Particles +tags:Getting Started +parent:Engine/Rendering/ParticleSystems +order:1 +type:overview +topic-image:Engine/Rendering/ParticleSystems/particles_topic.png + [TOC(start:2 end:3)] -**パーティクル システム** と **カスケード** は _パーティクル システム_ エディタで、非常に柔軟でパワフルです。しかし、実際の作業に着手する前に、重要な概念をしっかり理解しておく必要があります。本ドキュメントの目的は、ユーザーインターフェースのニュアンスやパーティクル エフェクト作成の詳細を避ける代わりに、パーティクル システムのこうした特性がどのように機能するのか体感してもらいながら主要な概念を紹介することです。 +**パーティクル システム** と **カスケード** は _パーティクル システム_ エディタで、非常に柔軟でパワフルです。しかし、実際の作業に着手する前に、重要な概念をしっかり理解しておく必要があります。本ドキュメントの目的は、ユーザーインターフェースの微妙な違いやパーティクル エフェクト作成の詳細には触れずに、パーティクル システムのこうした特性がどのように機能するのかを体感してもらいながら主要な概念を紹介することです。 ## パーティクル エフェクトへのモジュール式アプローチ @@ -15,9 +22,9 @@ Version:4.9 一方カスケードでは、パーティクル システムは _必要最小限の_ プロパティやいくつかの動作のモジュールのみで起動します。 -それぞれのモジュールはパーティクルの動作の特定の特性を表しており、カラー、生成や移動、スケーリング位置など、その動作を制御するプロパティのみを保有します。ユーザーはモジュールの追加や削除による調整でき、調整結果がパーティクルの動作として定義されます。必要な動作のモジュールのみ追加するので、不要なプロパティのために無駄な計算をする必要がありません。 +それぞれのモジュールはパーティクルの動作の特定の特性を表しており、カラー、生成や移動、スケーリング位置など、その動作を制御するプロパティのみを保有します。ユーザーはモジュールの追加や削除による調整ができ、調整結果がパーティクルの動作として定義されます。必要な動作のモジュールのみ追加するので、不要なプロパティのために無駄な計算をする必要がありません。 -特に、モジュールは、追加、削除、コピー、さらにはパーティクル システム内のエミッターからのインスタンス化までもが簡単に行えるので、利用可能なモジュールに慣れてしまえば、複雑なステップも簡単にこなせます。 +特に、モジュールは、追加、削除、コピー、さらにはパーティクル システム内のエミッタからのインスタンス化までもが簡単に行えるので、利用可能なモジュールに慣れてしまえば、複雑なステップも簡単にこなせます。 @@ -40,10 +47,10 @@ Version:4.9 [REGION:note] - *Required* と *Spawn* モジュールは永続的で、エミッターから削除することはできません。ただし、他のすべてのモジュールは自由自在に削除することができます。 + *Required* と *Spawn* モジュールは永続的で、エミッタから削除することはできません。ただし、他のすべてのモジュールは自由自在に削除することができます。 [/REGION] ### モジュールのカテゴリ -パーティクル エミッターには様々なモジュールを追加することができます。混乱しないように、モジュールをカテゴリに分類しました。以下になります。 +パーティクル エミッタには様々なモジュールを追加することができます。混乱しないように、モジュールをカテゴリに分類しました。以下になります。 | カテゴリ | 説明 | | --- | --- | @@ -67,15 +74,15 @@ Version:4.9 | **Camera** | カメラ空間でのパーティクルの動きを制御するモジュールで、ユーザーはカメラに近づけたり遠ざけたりすることができます。| | **Collision** | パーティクルとジオメトリ間のコリジョンの処理方法を制御するモジュールです。 | | **Color** | パーティクルのカラーに影響するモジュールです。 | -| **Event** | パーティクル イベントのトリガを制御するモジュールで、各種インゲーム レスポンスを順番に返すことができます。 | +| **Event** | パーティクル イベントのトリガーを制御するモジュールで、各種インゲーム レスポンスを順番に返すことができます。 | | **Kill** | パーティクルの削除を管理するモジュールです。 | | **Lifetime** | パーティクルの存在期間を制御するモジュールです。 | | **Light** | パーティクルのライトを管理するモジュールです。 | -| **Location** | エミッター アクタの位置と相対してパーティクルが生成される場所を制御するモジュールです。 | +| **Location** | エミッタ アクタの位置と相対してパーティクルが生成される場所を制御するモジュールです。 | | **Material** | パーティクル自体に適用されるマテリアルを制御するモジュールです。 | | **Orbit** | 画面空間の軌道上での動作を可能にし、エフェクトへモーションを追加するモジュールです。 | | **Orientation** | パーティクルの回転軸のロックを可能にするモジュールです。 | -| **Parameter** | ブループリントや Matinee など外部ソース経由でのパラメータ化や制御が可能なモジュールです。 | +| **Parameter** | ブループリントやマチネなど外部ソース経由でのパラメータ化や制御が可能なモジュールです。 | | **Rotation** | パーティクルの回転を制御するモジュールです。 | | **RotationRate** | スピンなど、回転速度の変更を管理するモジュールです。 | | **Size** | パーティクルのスケールを管理するモジュールです。 | @@ -84,9 +91,9 @@ Version:4.9 | **Velocity** | 各パーティクルの速度を制御するモジュールです。 | -個別のパーティクル モジュールに関する詳細については、 [パーティクル モジュールのリファレンス](Engine/Rendering/ParticleSystems/Reference/) を必ず確認してください。 +個別のパーティクル モジュールに関する詳細については、[パーティクル モジュール リファレンス](Engine/Rendering/ParticleSystems/Reference/) を必ず確認してください。 -### Initial モジュールとOver Life モジュール +### Initial vs.Over Life パーティクル モジュールで作業する時にしっかり覚えておいて頂きたい重要な概念が 2 つあります。1 つが *initial* プロパティで、もう 1 つが *over life* または *per life* プロパティです。 @@ -100,7 +107,7 @@ Version:4.9 プロパティを時間経過と共に変化するディストリビューション タイプに変更すると、モジュールによって「相対時間」を用いるものと、「絶対時間」を用いるものがあります (ディストリビューションについては下記を参照)。 -* 基本的に、絶対時間は含まれているエミッターの時間です。エミッターに 2 秒のループが 3 回設定されている場合、そのエミッター内のモジュールには、絶対時間が 0 から 2 秒まで 3 回実行されます。 +* 基本的に、絶対時間は含まれているエミッタの時間です。エミッタに 2 秒のループが 3 回設定されている場合、そのエミッタ内のモジュールには、絶対時間が 0 から 2 秒まで 3 回実行されます。 * 相対時間は、各パーティクルの存続期間を示す 0 から 1 までの時間です。 @@ -109,32 +116,32 @@ Version:4.9 -## エミッター、パーティクル システム、エミッター アクタ +## エミッタ、パーティクル システム、エミッタ アクタ -カスケードを使ってパーティクル エフェクトを作成する場合、1 つのオブジェクトと他のオブジェクトとの関係性を覚えておくことが重要です。本ドキュメントでは既にモジュールの概念について説明しましたが、モジュールはパーティクル エフェクト全体を構成する 1 コンポーネントにすぎません。つまり、パーティクル システムのコンポーネントは、モジュール、 エミッター、パーティクル システム、エミッター アクタ となります。それぞれのコンポーネントの相関は、以下のように覚えると確実です。 +カスケードを使ってパーティクル エフェクトを作成する場合、1 つのオブジェクトと他のオブジェクトとの関係性を覚えておくことが重要です。本ドキュメントでは既にモジュールの概念について説明しましたが、モジュールはパーティクル エフェクト全体を構成する 1 コンポーネントにすぎません。つまり、パーティクル システムのコンポーネントは、モジュール、 エミッタ、パーティクル システム、エミッタ アクタ となります。それぞれのコンポーネントの相関は、以下のように覚えると確実です。 * **モジュール** はパーティクルの動作を定義し、場所は・・・にあります。 -* **エミッター** は、エフェクト用の特定のパーティクル タイプを放出するために使用し、数に制限なく・・・に置くことができます。 +* **エミッタ** は、エフェクト用の特定のパーティクル タイプを放出するために使用し、数に制限なく・・・に置くことができます。 * **パーティクル システム** は、**コンテンツ ブラウザ** で利用できるアセットで、・・・から順々に参照することができます。 -* **エミッター アクタ** は、レベル内に存在する配置可能なオブジェクトで、シーン内でのパーティクルの使用場所、使用方法を制御します。 +* **エミッタ アクタ** は、レベル内に存在する配置可能なオブジェクトで、シーン内でのパーティクルの使用場所、使用方法を制御します。 ## パーティクルの計算 -パーティクル システムで作業する場合、計算順序に注意することが重要です。カスケード エミッター リスト領域の各カラムには別のエミッターが表示され、カラムの各ブロックには別のモジュールが表示されます。計算は以下の順序で実施されます。 +パーティクル システムで作業する場合、計算順序に注意することが重要です。カスケード エミッタ リスト領域の各カラムには別のエミッタが表示され、カラムの各ブロックには別のモジュールが表示されます。計算は以下の順序で実施されます。 -* エミッターは、エミッターリストの左から右へ計算されます。 +* エミッタは、エミッタ リストの左から右へ計算されます。 * モジュールは、スタックの上から下へ計算されます。 -## エミッター タイプ +## エミッタ タイプ -パーティクルを使って作成したいエフェクト タイプの種類が幅広いように、エミッター タイプにも様々な種類が利用できるので、まさに必要とするタイプを作成した場合に便利です。利用可能なエミッター タイプは以下の通りです。 +パーティクルを使って作成したいエフェクト タイプの種類が幅広いように、エミッタ タイプにも様々な種類が利用できるので、まさに必要とするタイプを作成した場合に便利です。利用可能なエミッタ タイプは以下の通りです。 -タイプに関係なく、エミッターはすべて、最初はスプライト エミッターであることに注意してください。後から各種エミッター *Type Data* モジュールをエミッターに追加して別のタイプに変更します。 +タイプに関係なく、エミッタはすべて、最初はスプライト エミッタであることに注意してください。後から各種エミッタ *Type Data* モジュールをエミッタに追加して別のタイプに変更します。 -* **Sprite Emitters** - 最も基本的なエミッター タイプで、一番よく使用されます。パーティクルは、常にカメラ方向を向く多角形スプライト (2 つのポリゴンをもつカード) として放出されます。煙、火、その他幅広いエフェクトに便利です。 +* **Sprite Emitters** - 最も基本的なエミッタ タイプで、一番よく使用されます。パーティクルは、常にカメラ方向を向く多角形スプライト (2 つのポリゴンをもつカード) として放出されます。煙、炎、他の幅広いエフェクトで役立ちます。 * **AnimTrail Data** - アニメートされたスケルトンのソケットからトレイルを作成するために使用します。 @@ -142,19 +149,19 @@ Version:4.9 * **GPU Sprites** - 実行時間の計算の大部分が GPU に渡される特別なパーティクル タイプです。これにより、数千から *数十万* の CPU パーティクルをもつ莫大な数のパーティクルが起動されます。数はターゲット システムの GPU のタイプにより異なります。 -* **Mesh Data** - 一連のスプライトを放出する代わりに、多角形メッシュを放出するタイプのエミッターです。岩崩れ、残骸などのエフェクトにうってつけです。 +* **Mesh Data** - 一連のスプライトを放出する代わりに、多角形メッシュを放出するタイプのエミッタです。岩崩れ、残骸などのエフェクトに最適です。 -* **Ribbon Data** - 端から端まで適用するパーティクルのストリングを生成して、移動するエミッターの後をトレイルするリボンの形成します。 +* **Ribbon Data** - 端から端まで適用するパーティクルのストリングを生成して、移動するエミッタの後をトレイルするリボンの形成します。 -利用可能なエミッターのタイプに関しては、 [エミッタのタイプのページ](Engine/Rendering/ParticleSystems/Reference) をご覧ください。 +利用可能なエミッタのタイプに関しては、 [エミッタのタイプのページ](Engine/Rendering/ParticleSystems/Reference) をご覧ください。 ## パラメータ パーティクル システムの特性はそのすべてを事前に定義できるわけではありません。時として、パーティクル システムの動作の中に実行時の制御や変更が必要な部分もあります。例えば、魔法がかけられた時、消費した魔力の量に応じてカラーを変える魔法エフェクトも作成できます。この場合、パーティクル システムにパラメータを追加する必要があります。 -*parameter* は、ブループリント、Matinee、マテリアル、その他さまざまなソースなどの他のシステムとのデータのやり取りが可能なプロパティのタイプです。カスケードでは、どんなプロパティにもパラメータを割り当てることができるので、パーティクル システム外からプロパティを制御することが可能です。 +*parameter* は、ブループリント、マチネ、マテリアル、その他さまざまなソースなどの他のシステムとのデータのやり取りが可能なプロパティのタイプです。カスケードでは、どんなプロパティにもパラメータを割り当てることができるので、パーティクル システム外からプロパティを制御することが可能です。 例えば、炎のエフェクトに対してスポーン レートを制御するパラメータを設定することで、プレイヤーは実行時に放出される炎の量を増減できるようになります。 @@ -162,7 +169,7 @@ Version:4.9 カスケードでは、パラメータの作成方法として、通常 Distributions (ディストリビューション)、つまりプロパティ内のデータを処理する方法を使用します。Distributions の概要については以下の [ディストリビューション](#Distributions(ディストリビューション))、または [ディストリビューションのページ](Engine/Basics/Distributions) の詳細をご覧ください。 -## Lit パーティクル +## Lit (ライティング有り) パーティクル パーティクル システムでライトを受け取る設定ができますが、特別な設定が必要です。 @@ -170,10 +177,10 @@ Lit パーティクルの設定方法: 1. マテリアルが unlit 以外のシェーディング モデルを使用していることを確認してください。DefaultLit を使用すると、法線マップ、スペキュラリティ (鏡面反射性)などへアクセスできます。 -1. カスケードの LODSettings (モジュールおよびエミッターが何も選択されていないと表示される LOD プロパティの中にあります) には、bLit と呼ばれる LOD 別のフラグがあります。このフラグを必ず選択してください。このフラグはカスケード内でしか更新することができません。 +1. カスケードの LODSettings (モジュールおよびエミッタが何も選択されていないと表示される LOD プロパティの中にあります) には、bLit と呼ばれる LOD 別のフラグがあります。このフラグを必ず選択してください。このフラグはカスケード内でしか更新することができません。 -この手順に従えば、ご自分のパーティクルが lit としてゲーム中に表示されるはずです。これらはエミッター基点から光を発しているので、ワールド内で基点を動かして光源が変わるか確認する、または動的ライトをそばでスポーンしてみてください。 +この手順に従えば、ご自分のパーティクルが lit としてゲーム中に表示されるはずです。これらはエミッタ基点から光を発しているので、ワールド内で基点を動かして光源が変わるか確認する、または動的ライトをそばでスポーンしてみてください。 ##詳細度 (LOD) @@ -182,7 +189,7 @@ Lit パーティクルの設定方法: 例えば、キャンプ ファイアーのパーティクル システムを考えてください。近くで見ると、燃えさしと火花が煙の中へ立ち上っていくのが見えます。しかしながら、数百メートル離れて見ると、その燃えさしが小さすぎてモニターや画面はレンダリングすらできません。ではなぜ計算をするのでしょうか? -ここで詳細度 (LOD) が関わってきます。パーティクル システムが自動的に簡素化するカスタム距離範囲を LOD システムで設定できます。各範囲ではもう 1 つ LOD が構成されます。プロパティ値の低いものから非アクティブのモジュール、非アクティブのエミッターという順序で簡素化されていきます。上記のキャンプファイアーの例で言えば、プレイヤーが遠すぎて見えなくなったら、エフェクト全体に火花を追加したエミッターを完全に非アクティブにするのが理想的です。 +ここで詳細度 (LOD) が関わってきます。パーティクル システムが自動的に簡素化するカスタム距離範囲を LOD システムで設定できます。各範囲ではもう 1 つ LOD が構成されます。プロパティ値の低いものから非アクティブのモジュール、非アクティブのエミッタという順序で簡素化されていきます。上記のキャンプファイアーの例で言えば、プレイヤーが遠すぎて見えなくなったら、エフェクト全体に火花を追加したエミッタを完全に非アクティブにするのが理想的です。 パーティクル システムでは好きなだけ LOD を構成し、各 LOD の範囲を手動で制御できます。 diff --git a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Overview/KeyConcepts.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Overview/KeyConcepts.KOR.udn index c29fa26f6962..062265af5821 100644 --- a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Overview/KeyConcepts.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Overview/KeyConcepts.KOR.udn @@ -1,10 +1,16 @@ -INTSourceChangelist:3243860 +INTSourceChangelist:3429247 Availability:Public Title: 핵심 파티클 개념 Crumbs: %ROOT%, Engine, Engine/Rendering/ParticleSystems Description:언리얼 내에서 그리고 캐스케이드 파티클 에디터에서 파티클 작업을 할 때의 핵심 개념입니다. Version: 4.9 tags:Particles +tags:Getting Started +parent:Engine/Rendering/ParticleSystems +order:1 +type:overview +topic-image:Engine/Rendering/ParticleSystems/particles_topic.png + [TOC(start:2 end:3)] diff --git a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/ParticleLights/ParticleLights.INT.udn b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/ParticleLights/ParticleLights.INT.udn index 6a66cab95dcb..52e06e9ea45c 100644 --- a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/ParticleLights/ParticleLights.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/ParticleLights/ParticleLights.INT.udn @@ -4,45 +4,10 @@ Crumbs: %ROOT%, Engine, Engine/Rendering/LightingAndShadows Description:Particle Lights are another weapon in the VFX artist's arsenal. Version: 4.9 tags:Particles - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Rendering/ParticleSystems/ParticleLights:title%](particleLights_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/light_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Rendering/ParticleSystems/ParticleLights:title% - [/PARAM] - [PARAM:description] - %Engine/Rendering/ParticleSystems/ParticleLights:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Rendering/ParticleSystems/ParticleLights] - [/PARAM] -[/OBJECT] -[/VAR] -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Rendering/ParticleSystems/ParticleLights:title%](particleLights_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/light_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Rendering/ParticleSystems/ParticleLights:title% - [/PARAM] - [PARAM:description] - %Engine/Rendering/ParticleSystems/ParticleLights:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Rendering/ParticleSystems/ParticleLights] - [/PARAM] -[/OBJECT] -[/VAR] +parent:Engine/Rendering/ParticleSystems +order:6 +type:overview +topic-image:particleLights_topic.png [TOC(start:2 end:2)] diff --git a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/ParticleLights/ParticleLights.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/ParticleLights/ParticleLights.JPN.udn index 46edcf32c377..e0ae1a6ad67a 100644 --- a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/ParticleLights/ParticleLights.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/ParticleLights/ParticleLights.JPN.udn @@ -1,62 +1,28 @@ -INTSourceChangelist:2737439 +INTSourceChangelist:3429247 Availability:Public Title:パーティクル ライト Crumbs: %ROOT%, Engine, Engine/Rendering/LightingAndShadows -Description:パーティクル ライトは VFX アーティストの保管庫にあるもう 1 つの武器です。 +Description:パーティクル ライトは VFX アーティストの必殺技の 1 つです。 Version:4.9 - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Rendering/ParticleSystems/ParticleLights:title%](particleLights_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/light_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Rendering/ParticleSystems/ParticleLights:title% - [/PARAM] - [PARAM:description] - %Engine/Rendering/ParticleSystems/ParticleLights:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Rendering/ParticleSystems/ParticleLights] - [/PARAM] -[/OBJECT] -[/VAR] -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Rendering/ParticleSystems/ParticleLights:title%](particleLights_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/light_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Rendering/ParticleSystems/ParticleLights:title% - [/PARAM] - [PARAM:description] - %Engine/Rendering/ParticleSystems/ParticleLights:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Rendering/ParticleSystems/ParticleLights] - [/PARAM] -[/OBJECT] -[/VAR] +tags:Particles +parent:Engine/Rendering/ParticleSystems +order:6 +type:overview +topic-image:particleLights_topic.png [TOC(start:2 end:2)] [EXCERPT:PL001] -_CPU Particle Emitters_ は **カスケード** の **Particle Light Module** を追加して、それぞれのパーティクルに適用されたライトでレンダリングするために作成することができます。ライトを十分にエミットして周りの環境より目立たせる火花や花火などのエフェクトに便利です。 +_CPU パーティクル エミッタ_ は **カスケード** の **Particle Light Module** を追加して、それぞれのパーティクルに適用したライトでレンダリングするために作成します。周囲より目立つだけのライトをエミットする、火花や花火などのエフェクトに便利です。 [/EXCERPT:PL001] -## 準備全般 +## 使用前の準備 -パーティクル ライトのパフォーマンス負荷はほぼ完全と言っていいほど、画面上で発生するオーバードローの量に依存しています。オーバードローは、ライト数 X 影響を受けるピクセル数です。 +パーティクル ライトのパフォーマンス負荷はほぼ完全と言っていいほど、画面上で発生するオーバードローの量に依存しています。オーバードローは、ライト数 x 影響を受けるピクセル数です。 -パーティクル ライトを設定する際には、大きいパーティクル ライトは少なく、小さいパーティクル ライトを多くするのが一般的な戦略です。パーティクル ライトの負荷はあっという間に手に負えなくなるので、 _ProfileGPU_ コンソール コマンドで調整およびプロファイルすることが重要です。負荷は _ライト_ の下に表示されます。 +パーティクル ライトを設定するコツは、大きいパーティクル ライトを少なくし、小さいパーティクル ライトを多くすることです。パーティクル ライトの負荷は一気に膨れ上がるので、_ProfileGPU_ コンソール コマンドで調整およびプロファイルすることが重要です。負荷は _[Lights]_ で確認できます。 -[OBJECT:EmbeddedVideo]  +[OBJECT:EmbeddedVideo] [PARAMLITERAL:width] 640 [/PARAMLITERAL] @@ -80,15 +46,15 @@ nyGqpilZe08 [/PARAMLITERAL] [/OBJECT] -パーティクル ライト エミッタのみを使って上のアニメーションをした静止画像がこちらです。 +上の画像をパーティクル ライト エミッタのみでアニメーションをした静止画像が以下の 2 つです。 ![](PL_system_01_still.png)(h:407) ![](PL_system_02_still.png)(h:407) -最初の画像では、パーティクル ライトは既にソリッドなパーティクル システムである火花や炎により物理感を出すためのアクセントに使用されています。さらに、パーティクル ライトはどの瞬間でもほとんど存在しません。2 つ目の画像では、ライトはボリュームと位置をシステムに追加しますが、エフェクト効果を出すためにかなり多くのパーティクル (200 以上) を使用します。 +最初の画像では、パーティクル ライトは既にソリッドなっているパーティクル システムのアクセントとして使用し、火花や花火にさらに物理間を出しています。さらに、パーティクル ライトが存在する瞬間はほとんどありません。2 つ目の画像ではライトがボリュームと位置を追加しています。エフェクト効果を出すために大量のパーティクル (200 以上) を使用します。 ## 使用方法 -ライトをパーティクル システムに追加する方法は単刀直入です。 +ライトをパーティクル システムに追加する方法は、非常に分かりやすいです。 1. カスケードでパーティクル システムを開きます。 1. エミッタへライトを配置する位置でエミッタを **右クリック** をします。 @@ -96,30 +62,30 @@ nyGqpilZe08 [REGION:lightbox] [![](PL_addLightModule.png)(w:830)](PL_addLightModule.png) [/REGION] -1. 最高のライトモジュールを新規に設定します。 +1. 新規 Light モジュールを設定します。 [REGION:lightbox] [![](PL_lightModuleAdded.png)(w:830)](PL_lightModuleAdded.png) [/REGION] [REGION:note] -注記: **Light** モジュールは CPU パーティクル上のみで使用できます。 GPU パーティクルはどれもこのモジュールとは機能しません。GPU エミッタへモジュールを追加してもシステムを壊すようなことはありませんが、実際には何も起こらずリストのモジュール上に巨大な赤い _X_ マークが表示されます。 +注記: **Light** モジュールは CPU パーティクル上のみで使用できます。このモジュールとは機能する GPU パーティクルはありません。GPU エミッタへモジュールを追加してもシステムを壊すようなことはありませんが、実際には何も起こらずリストのモジュール上に巨大な赤い _X_ マークが表示されます。 [/REGION] -###プロパティ +### プロパティ ![](PL_lightModuleProperties.png) | プロパティ | 説明 | | -------- | ----------- | | Use Inverse Squared Falloff | 有効になると、ライトの半径に基づいてより現実味のあるフォールオフとするために **Light Exponent** は無視されます。 | -| **Affects Translucency** | 有効になると、それぞれのパーティクル ライトは lit 透過に影響します。煙を通過するロケットのエミッシブ トレイルに便利です。このプロパティは、レンダリングされるそれぞれのパーティクルに対してかなりの負荷がかかるので、この設定を有効にするパーティクルは少なめにすることを推奨します。 | +| **Affects Translucency** | 有効になると、それぞれのパーティクル ライトは lit 透過に影響します。煙を通過するロケットのエミッシブ トレイルに便利です。このプロパティはレンダリング対象のパーティクルにかなりの負荷をかけるので、この設定を有効にするパーティクルは少なくすることを推奨します。 | | **Preview Light Radius** | **[Preview]** ウィンドウに球体のワイヤーフレームでライトの半径を表示します。 | -| Spawn Fraction | ライトをアタッチするパーティクルの割合を定義します。値が 1.0 だと全てのパーティクル、値が 0.5 だとパーティクルの 50 %、値が 0.1 だと 10 %のパーティクルの割合になります。これを使って最適化時の負荷を減らします。 | +| Spawn Fraction | ライトをアタッチするパーティクルの割合を定義します。値が 1.0 だとパーティクル全体、値が 0.5 だとパーティクルの 50 %、値が 0.1 だとパーティクルの 10 % になります。これを使って最適化処理の負荷を減らします。 | | **Color Scale Over Life** | Radius Scale 同様に、パーティクルの色に基づいてライトの色をオフセットするために、ここで入力した値でライトの色を乗算します。 | -| **Brightness Over Life** | ライフタイムを通じてライトの輝度の変更を有効にします。 | +| **Brightness Over Life** | ライフタイム中、ライトの輝度の変更を有効にします。 | | **Radius Scale** | パーティクルのサイズに基づいてライトの範囲を定義する乗数です。X 軸上で値 1 でスケーリングされたパーティクルは **Radius Scale** と同等の半径になりますが、 X 軸上で値 10 でスケーリングされたパーティクルは **Radius Scale** の半径の 10 倍になります。 | -| **Light Exponent** | **Use Inverse Squared Falloff** を無効にすると、このプロパティがライトのフォールオフを制御します。大きい数値は、ライトがライトの半径に近づくにつれてより緩やかなフォールオフとなるのに対して、数値が小さくなるとライトの半径付近でライトが突然落下します。 | +| **Light Exponent** | **Use Inverse Squared Falloff** を無効にすると、ライトのフォールオフを制御します。数値が大きくなるとライトがライトの半径に近づくにつれてフォールオフが緩やかになり、数値が小さくなるとライトの半径付近でライトが突然落ちます。 | diff --git a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/ParticleLights/ParticleLights.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/ParticleLights/ParticleLights.KOR.udn index 4443f115c1b1..7470fc5f451f 100644 --- a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/ParticleLights/ParticleLights.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/ParticleLights/ParticleLights.KOR.udn @@ -1,49 +1,14 @@ -INTSourceChangelist:3243860 +INTSourceChangelist:3429247 Availability:Public Title:파티클 라이트 Crumbs: %ROOT%, Engine, Engine/Rendering/LightingAndShadows Description:VFX 아티스트에게 있어서 또하나의 무기, 파티클 라이트입니다. Version: 4.9 tags:Particles - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Rendering/ParticleSystems/ParticleLights:title%](particleLights_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/light_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Rendering/ParticleSystems/ParticleLights:title% - [/PARAM] - [PARAM:description] - %Engine/Rendering/ParticleSystems/ParticleLights:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Rendering/ParticleSystems/ParticleLights] - [/PARAM] -[/OBJECT] -[/VAR] -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Rendering/ParticleSystems/ParticleLights:title%](particleLights_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/light_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Rendering/ParticleSystems/ParticleLights:title% - [/PARAM] - [PARAM:description] - %Engine/Rendering/ParticleSystems/ParticleLights:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Rendering/ParticleSystems/ParticleLights] - [/PARAM] -[/OBJECT] -[/VAR] +parent:Engine/Rendering/ParticleSystems +order:6 +type:overview +topic-image:particleLights_topic.png [TOC(start:2 end:2)] diff --git a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/ParticleSystems.INT.udn b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/ParticleSystems.INT.udn index 80cf3ff41c0b..ce69eb2b3b0f 100644 --- a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/ParticleSystems.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/ParticleSystems.INT.udn @@ -8,6 +8,8 @@ parent:Engine/Rendering order:4 type:landing tags:Particles +related:Engine/Basics/Distributions +related:Engine/Rendering/Materials/Editor [VAR:Topic] [OBJECT:Topic] @@ -61,91 +63,19 @@ Unreal's Particle Systems are edited via **Cascade**, a fully integrated and mod Particle systems are also very closely related to the various materials and textures applied to each particle. The primary job of the particle system itself is to control the behavior of the particles, while the specific look and feel of the particle system as a whole is often controlled by way of materials. As such, we have included a shortcut to the material documentation below. -[REGION:topics third] -[OBJECT:Topic] - [PARAM:image] - ![](Engine/Rendering/ParticleSystems/particles_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/start_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Rendering/ParticleSystems/Overview:title% - [/PARAM] - [PARAM:description] - %Engine/Rendering/ParticleSystems/Overview:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Rendering/ParticleSystems/Overview] - [/PARAM] -[/OBJECT] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Rendering/ParticleSystems/Cascade:title%](Engine/Rendering/ParticleSystems/Cascade/cascade_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Rendering/ParticleSystems/Cascade:title% - [/PARAM] - [PARAM:description] - %Engine/Rendering/ParticleSystems/Cascade:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Rendering/ParticleSystems/Cascade] - [/PARAM] -[/OBJECT] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Rendering/ParticleSystems/Reference:title%](Engine/Rendering/ParticleSystems/Reference/particlereference_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/reference_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Rendering/ParticleSystems/Reference:title% - [/PARAM] - [PARAM:description] - %Engine/Rendering/ParticleSystems/Reference:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Rendering/ParticleSystems/Reference] - [/PARAM] -[/OBJECT] -[/REGION] +## Starting Out + +[DIR(output:"topic" parent:"Engine/Rendering/ParticleSystems" end:"1" org:"hierarchy" tags:"Getting Started")] + +## Guides + +[DIR(output:"topic" parent:"Engine/Rendering/ParticleSystems" end:"1" org:"hierarchy" type:"!reference" tags:"!Getting Started")] + +## Reference + +[DIR(output:"topic" parent:"Engine/Rendering/ParticleSystems" end:"1" org:"hierarchy" type:"reference")] -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/tech_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - Particle Topics - [/PARAM] - [PARAM:description] - [/PARAM] - [PARAM:links] - * [](Engine/Rendering/ParticleSystems/UserGuide "%Engine/Rendering/ParticleSystems/UserGuide:Description%") - * [](Engine/Rendering/ParticleSystems/LODs "%Engine/Rendering/ParticleSystems/LODs:Description%") - * [](Engine/Rendering/ParticleSystems/ParticleLights "%Engine/Rendering/ParticleSystems/ParticleLights:Description%") - [/PARAM] -[/OBJECT] -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/tech_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - Related Topics - [/PARAM] - [PARAM:description] - [/PARAM] - [PARAM:links] - * [](Engine/Basics/Distributions "%Engine/Basics/Distributions:Description%") - * [](Engine/Rendering/Materials/Editor "%Engine/Rendering/Materials/Editor:Description%") - * [](Engine/Rendering/ParticleSystems/Optimization "%Engine/Rendering/ParticleSystems/Optimization:Description%") - [/PARAM] -[/OBJECT] diff --git a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/ParticleSystems.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/ParticleSystems.JPN.udn index 022a27d74899..eae79e573cb1 100644 --- a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/ParticleSystems.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/ParticleSystems.JPN.udn @@ -1,10 +1,16 @@ -INTSourceChangelist:2735872 +INTSourceChangelist:3429245 Availability:Public Title:カスケード パーティクル システム -Crumbs: %ROOT%, Engine, Engine/Rendering -Description:ワールドでエフェクトの作成に使用するエミッタを格納したアセット +crumbs:%ROOT%, Engine, Engine/Rendering +Description:ワールドでエフェクトの作成に使用するエミッタを含んだアセット Version:4.9 SkillLevel:Beginner +parent:Engine/Rendering +order:4 +type:landing +tags:Particles +related:Engine/Basics/Distributions +related:Engine/Rendering/Materials/Editor [VAR:Topic] [OBJECT:Topic] @@ -54,95 +60,23 @@ SkillLevel:Beginner アンリアルエンジンは非常にパワフルでロバストなパーティクルシステムを搭載しています。アーティストは、煙、スパーク、炎など多岐に渡る衝撃的なビジュアルエフェクトで、はるかに複雑で異世界の例を作成することができます。 [/EXCERPT:Intro] -アンリアルのパーティクルシステムは **カスケード** で編集します。カスケードは完全統合型の、モジュラー パーティクルエフェクト エディタです。カスケードは、最も複雑なエフェクトさえも迅速かつ簡単に作成して、リアルタイムなフィードバックとモジュラーエフェクト編集を提供します。 +アンリアルのパーティクルシステムは **カスケード** で編集します。カスケードは完全統合型の、モジュラー パーティクルエフェクト エディタです。カスケード は、最も複雑なエフェクトさえも迅速かつ簡単に作成して、リアルタイムなフィードバックとモジュラーエフェクト編集を提供します。 パーティクルシステムは、各パーティクルに適用したさまざまなマテリアルやテクスチャとも密接に関係しています。パーティクルシステムの主な機能は、全体のパーティクルシステムのある固有の外観や印象をしばしマテリアルでコントロールする一方で、パーティクルの挙動をコントロールすることです。例として、マテリアルに関するドキュメントへのショートカットを以下に示します。 -[REGION:topics third] -[OBJECT:Topic] - [PARAM:image] - ![](Engine/Rendering/ParticleSystems/particles_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/start_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Rendering/ParticleSystems/Overview:title% - [/PARAM] - [PARAM:description] - %Engine/Rendering/ParticleSystems/Overview:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Rendering/ParticleSystems/Overview] - [/PARAM] -[/OBJECT] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Rendering/ParticleSystems/Cascade:title%](Engine/Rendering/ParticleSystems/Cascade/cascade_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Rendering/ParticleSystems/Cascade:title% - [/PARAM] - [PARAM:description] - %Engine/Rendering/ParticleSystems/Cascade:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Rendering/ParticleSystems/Cascade] - [/PARAM] -[/OBJECT] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Rendering/ParticleSystems/Reference:title%](Engine/Rendering/ParticleSystems/Reference/particlereference_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/reference_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Rendering/ParticleSystems/Reference:title% - [/PARAM] - [PARAM:description] - %Engine/Rendering/ParticleSystems/Reference:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Rendering/ParticleSystems/Reference] - [/PARAM] -[/OBJECT] -[/REGION] +## はじめよう + +[DIR(output:"topic" parent:"Engine/Rendering/ParticleSystems" end:"1" org:"hierarchy" tags:"Getting Started")] + +## ガイド + +[DIR(output:"topic" parent:"Engine/Rendering/ParticleSystems" end:"1" org:"hierarchy" type:"!reference" tags:"!Getting Started")] + +## リファレンス + +[DIR(output:"topic" parent:"Engine/Rendering/ParticleSystems" end:"1" org:"hierarchy" type:"reference")] -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/tech_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - パーティクル関連トピック - [/PARAM] - [PARAM:description] - [/PARAM] - [PARAM:links] - * [](Engine/Rendering/ParticleSystems/UserGuide "%Engine/Rendering/ParticleSystems/UserGuide:Description%") - * [](Engine/Rendering/ParticleSystems/LODs "%Engine/Rendering/ParticleSystems/LODs:Description%") - * [](Engine/Rendering/ParticleSystems/ParticleLights "%Engine/Rendering/ParticleSystems/ParticleLights:Description%") - [/PARAM] -[/OBJECT] -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/tech_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - Related Topics - [/PARAM] - [PARAM:description] - [/PARAM] - [PARAM:links] - * [](Engine/Basics/Distributions "%Engine/Basics/Distributions:Description%") - * [](Engine/Rendering/Materials/Editor "%Engine/Rendering/Materials/Editor:Description%") - * [](Engine/Rendering/ParticleSystems/Optimization "%Engine/Rendering/ParticleSystems/Optimization:Description%") - [/PARAM] -[/OBJECT] diff --git a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/ParticleSystems.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/ParticleSystems.KOR.udn index ad2ee6e86b83..8894f187acb8 100644 --- a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/ParticleSystems.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/ParticleSystems.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3243860 +INTSourceChangelist:3429245 Availability:Public Title: 파티클 시스템 Crumbs: %ROOT%, Engine, Engine/Rendering @@ -9,6 +9,8 @@ parent:Engine/Rendering order:4 type:landing tags:Particles +related:Engine/Basics/Distributions +related:Engine/Rendering/Materials/Editor [VAR:Topic] [OBJECT:Topic] @@ -62,91 +64,19 @@ tags:Particles 파티클 시스템은 각 파티클에 적용되는 여러가지 머티리얼이나 텍스처에도 밀접한 관련이 있습니다. 파티클 시스템 자체의 주요 임무는 파티클의 동작을 조절하는 것이고, 파티클 시스템 전체적인 외양과 느낌은 종종 머티리얼을 통해 조절됩니다. 그렇기에 머티리얼 관련 문서 링크도 포함시켜 뒀습니다. -[REGION:topics third] -[OBJECT:Topic] - [PARAM:image] - ![](Engine/Rendering/ParticleSystems/particles_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/start_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Rendering/ParticleSystems/Overview:title% - [/PARAM] - [PARAM:description] - %Engine/Rendering/ParticleSystems/Overview:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Rendering/ParticleSystems/Overview] - [/PARAM] -[/OBJECT] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Rendering/ParticleSystems/Cascade:title%](Engine/Rendering/ParticleSystems/Cascade/cascade_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Rendering/ParticleSystems/Cascade:title% - [/PARAM] - [PARAM:description] - %Engine/Rendering/ParticleSystems/Cascade:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Rendering/ParticleSystems/Cascade] - [/PARAM] -[/OBJECT] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Rendering/ParticleSystems/Reference:title%](Engine/Rendering/ParticleSystems/Reference/particlereference_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/reference_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Rendering/ParticleSystems/Reference:title% - [/PARAM] - [PARAM:description] - %Engine/Rendering/ParticleSystems/Reference:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Rendering/ParticleSystems/Reference] - [/PARAM] -[/OBJECT] -[/REGION] +## 시작하기 + +[DIR(output:"topic" parent:"Engine/Rendering/ParticleSystems" end:"1" org:"hierarchy" tags:"Getting Started")] + +## 안내서 + +[DIR(output:"topic" parent:"Engine/Rendering/ParticleSystems" end:"1" org:"hierarchy" type:"!reference" tags:"!Getting Started")] + +## 참고서 + +[DIR(output:"topic" parent:"Engine/Rendering/ParticleSystems" end:"1" org:"hierarchy" type:"reference")] -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/tech_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - 파티클 관련 - [/PARAM] - [PARAM:description] - [/PARAM] - [PARAM:links] - * [](Engine/Rendering/ParticleSystems/UserGuide "%Engine/Rendering/ParticleSystems/UserGuide:Description%") - * [](Engine/Rendering/ParticleSystems/LODs "%Engine/Rendering/ParticleSystems/LODs:Description%") - * [](Engine/Rendering/ParticleSystems/ParticleLights "%Engine/Rendering/ParticleSystems/ParticleLights:Description%") - [/PARAM] -[/OBJECT] -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/tech_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - 관련 글타래 - [/PARAM] - [PARAM:description] - [/PARAM] - [PARAM:links] - * [](Engine/Basics/Distributions "%Engine/Basics/Distributions:Description%") - * [](Engine/Rendering/Materials/Editor "%Engine/Rendering/Materials/Editor:Description%") - * [](Engine/Rendering/ParticleSystems/Optimization "%Engine/Rendering/ParticleSystems/Optimization:Description%") - [/PARAM] -[/OBJECT] diff --git a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Reference/Reference.INT.udn b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Reference/Reference.INT.udn index 8fb1b2afcf7f..7f57342f46dc 100644 --- a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Reference/Reference.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Reference/Reference.INT.udn @@ -4,7 +4,10 @@ Crumbs: %ROOT%, Engine, Engine/Rendering/ParticleSystems Description:Complete reference for Particle System type data and modules. Version: 4.9 tags:Particles - +parent:Engine/Rendering/ParticleSystems +order:3 +type:reference +topic-image:particlereference_topic.png ## Base Classes diff --git a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Reference/Reference.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Reference/Reference.JPN.udn index f55e4cb69822..c5cb0eb10763 100644 --- a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Reference/Reference.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Reference/Reference.JPN.udn @@ -1,10 +1,14 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429247 Availability:Public Title:パーティクル システムのリファレンス Crumbs: %ROOT%, Engine, Engine/Rendering/ParticleSystems Description:パーティクル システムのタイプデータおよびモジュール用リファレンスの完全版 Version:4.9 - +tags:Particles +parent:Engine/Rendering/ParticleSystems +order:3 +type:reference +topic-image:particlereference_topic.png ## 基本クラス diff --git a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Reference/Reference.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Reference/Reference.KOR.udn index 1f25750394a7..94a1c1370cb0 100644 --- a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Reference/Reference.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Reference/Reference.KOR.udn @@ -1,11 +1,14 @@ -INTSourceChangelist:3243860 +INTSourceChangelist:3429247 Availability: Public Title:파티클 시스템 참고서 Crumbs: %ROOT%, Engine, Engine/Rendering/ParticleSystems Description:전체 파티클 시스템과 모듈에 대한 참고서입니다. Version: 4.9 tags:Particles - +parent:Engine/Rendering/ParticleSystems +order:3 +type:reference +topic-image:particlereference_topic.png ## 베이스 클래스 diff --git a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Reference/TypeData/Beam/BeamTypeData.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Reference/TypeData/Beam/BeamTypeData.KOR.udn index 51cc57ea54ea..1735e7aa9c52 100644 --- a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Reference/TypeData/Beam/BeamTypeData.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/Reference/TypeData/Beam/BeamTypeData.KOR.udn @@ -49,7 +49,7 @@ coXs-CmI_v8 | **Render Geometry** | 지오메트리 렌더 - _True_ 면 빔의 실제 지오메트리가 렌더링됩니다. 다른 식으로는 트레일을 볼 수가 없기에 이 옵션은 보통 켜 둡니다. | | **Render Direct Line** | 직선 렌더 - _True_ 면 빔의 소스와 타겟 사이에 직선이 렌더링됩니다. 캐스케이드에서 버그잡이에 사용됩니다. | | **Render Lines** | 선 렌더 - _True_ 면 빔의 각 세그먼트마다 선이 렌더링됩니다. 캐스케이드에서 버그잡이에 사용됩니다. | -| **Render Tessellation** | 테셀레이션 렌더 - _True_ 면 소스와 타겟 사이 테셀레이션 패쓰로 렌더링됩니다. 캐스케이드에서의 버그잡이에 사용됩니다. | +| **Render Tessellation** | 테셀레이션 렌더 - _True_ 면 소스와 타겟 사이 테셀레이션 패스로 렌더링됩니다. 캐스케이드에서의 버그잡이에 사용됩니다. | diff --git a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/UserGuide/UserGuide.INT.udn b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/UserGuide/UserGuide.INT.udn index 9885c4123f3d..138ec4ecbb4d 100644 --- a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/UserGuide/UserGuide.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/UserGuide/UserGuide.INT.udn @@ -5,6 +5,7 @@ Description:The general usage of Particle Systems and Cascade. Version: 4.9 SkillLevel: Intermediate tags:Particles +topic-image:ParticleSystemUserGuide_topic.png [TOC(start:2 end:3)] diff --git a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/UserGuide/UserGuide.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/UserGuide/UserGuide.JPN.udn index e64d5f634b33..51e6a2dcda0c 100644 --- a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/UserGuide/UserGuide.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/UserGuide/UserGuide.JPN.udn @@ -1,14 +1,16 @@ -INTSourceChangelist:2750870 +INTSourceChangelist:3481084 Availability:Public Title:パーティクル システム ユーザーガイド Crumbs: %ROOT%, Engine, Engine/Rendering/ParticleSystems Description: パーティクル システムとカスケードの一般的な使用方法 Version:4.9 SkillLevel:Intermediate +tags:Particles +topic-image:ParticleSystemUserGuide_topic.png [TOC(start:2 end:3)] -このページでは、パーティクル システムとパーティクル システム エディタである **カスケード** を使った作業の最も一般的なワークフローについて説明していきます。さらに詳しいドキュメントは準備が整い次第リンクを提供いたします。 +このページでは、パーティクル システムとパーティクル システム エディタである **カスケード** を使った作業の最も一般的なワークフローについて説明していきます。詳細ドキュメントが整い次第、各文書へのリンクを追加します。 ## パーティクル システムの作成 @@ -24,7 +26,7 @@ SkillLevel:Intermediate [/PARAM] [/OBJECT] -**パーティクル システム** を作成するには、 **コンテンツ ブラウザ** 上の **[Add New (新規追加)]** ボタンを**左クリック** し **[Particle System]** を選択、あるいは **コンテンツ ブラウザ** の **[Asset View (アセットビュー)]** を**右クリック** し、コンテキスト メニューを使って [Particle System] を選択します。 +**パーティクル システム** を作成するには、**コンテンツ ブラウザ** 上の **[Add New (新規追加)]** ボタンを **クリック** し **[Particle System]** を選択、あるいは **コンテンツ ブラウザ** の **[Asset View (アセットビュー)]** を **右クリック** し、コンテキスト メニューを使って [Particle System] を選択します。 作成された新規パーティクル システムの名前は、新しい名前を入力できるようにハイライトされています。新しい名前を入力するか、別の部分をクリックすると、パーティクル システムのアイコンは [No Image] サムネイルで更新されます。アンリアル エンジン 4 のパーティクル エディタであるカスケードから、サムネイルの作成が可能になります。 @@ -42,7 +44,7 @@ SkillLevel:Intermediate ![](editSystem.png) [/REGION] -## エミッターの追加 +## エミッタの追加 [REGION:raw] [INCLUDE:Shared/Tutorials/InParticleSystemEditorTutorial#Stage2.1] @@ -50,16 +52,16 @@ SkillLevel:Intermediate -## エミッターの編集 +## エミッタの編集 -エミッターを **クリック** すると、**[Details (詳細)] パネル** にプロパティが表示されます。エミッターには僅かなプロパティがあるだけですが、中でも大きなものは **Name** 、 **Detail Mode** 、 **Medium Detail Spawn Rate Scale** です。 +エミッタを **クリック** すると、**[Details (詳細)] パネル** にプロパティが表示されます。エミッタのプロパティはわずかですが、特に重要なプロパティは **Name**、**Detail Mode**、**Medium Detail Spawn Rate Scale** です。 [REGION:raw] ![](emitterDetails.png) [/REGION] -## エミッターの記録 +## エミッタの記録 パーティクル システムでエミッタの順序を変更するには、エミッタを選んで **左矢印キー** と **右矢印キー** を使用します。 @@ -74,10 +76,10 @@ SkillLevel:Intermediate ![](solo.png) [/REGION] -**Solo Mode** は、自分で有効化した Solo Mode 以外の他の全てのパーティクル エミッターを無効にします (Solo Mode が有効にされているエミッターは他にはない前提とします)。こうすることで、そのエミッターだけのエフェクトを表示できるようになります。Solo Mode を 1 つのエミッター上で有効にすることで、別のエミッター上で Solo Mode が有効にされると、Solo Mode に設定されている他のエミッターと一緒にそれがプレビューに追加されます。つまり、特定のエミッターを組み合わせてプレビューすることができるのです。 +**Solo Mode** は、自分で有効化した Solo Mode 以外の他の全てのパーティクル エミッタを無効にします (Solo Mode が有効なエミッタは他にない前提)。こうすることで、そのエミッターだけのエフェクトを表示できるようになります。Solo Mode を 1 つのエミッタ上で有効にすることで、別のエミッター上で Solo Mode が有効にされると、Solo Mode に設定されている他のエミッタと一緒にそれがプレビューに追加されます。つまり、特定のエミッタを組み合わせてプレビューすることができるのです。 [REGION:note] -Solo Mode を有効にしたエミッターが別のエミッターでのイベントに応じてのみスポーンする場合、何もレンダリングされません。スポーン イベントのあるエミッターも Solo Mode を有効にしておく必要があります。 +Solo Mode が有効のエミッタが別のエミッタでのイベントに応じてスポーンのみする場合、レンダリングは一切されません。スポーン イベントのあるエミッタも Solo Mode を有効にしておく必要があります。 [/REGION] @@ -90,7 +92,7 @@ Solo Mode を有効にしたエミッターが別のエミッターでのイベ ![](Shared/Tutorials/InParticleSystemEditorTutorial/CascadeTutorial_Modules01.png) [/REGION] -個別のモジュールに関する詳細は、 [パーティクル システムのリファレンス](Engine/Rendering/ParticleSystems/Reference#モジュール) を参照してください。 +個別のモジュールに関する詳細は、[パーティクル システムのリファレンス](Engine/Rendering/ParticleSystems/Reference#モジュール) を参照してください。 @@ -103,15 +105,15 @@ Solo Mode を有効にしたエミッターが別のエミッターでのイベ ここで、簡単なフラグからディストリビューションを使用するプロパティ上の個々のキーの調整に至るまで、モジュールの全てのプロパティの調整ができます。 -## Distributions (ディストリビューション) +## Distributions -ディストリビューションは、パーティクルのライフタイムの間、値を調整できるようにします。 +Distributions (ディストリビューション) は、パーティクルのライフタイムにわたり値を調整できるようにします。 [REGION:raw] ![](Shared/Tutorials/InParticleSystemEditorTutorial/CascadeTutorial_Details03.png) [/REGION] -ディストリビューションは、データ型の集まりであり、定数値、一定範囲内のランダム値、カーブに沿って補間された値、パラメータによって動く値を使用できる柔軟性があります。 +ディストリビューションは、データ タイプのグループです。不変な値、ある範囲内にあるランダムな値、カーブに沿って補間された値、パラメータ主導の値が可能になり、柔軟性を与えます。 ディストリビューションの詳細については、 [ディストリビューション](Engine/Basics/Distributions) ドキュメント ページをご覧ください。 @@ -127,7 +129,7 @@ Solo Mode を有効にしたエミッターが別のエミッターでのイベ ![](Shared/Tutorials/InParticleSystemEditorTutorial/CascadeTutorial_Curves01.png) [/REGION] -カーブエディタの左側のセクションには、モジュールにおいて **Distributions** をサポートするプロパティがあります。 +カーブ エディタの左側のセクションには、モジュールで **ディストリビューション** をサポートするプロパティがあります。 [REGION:raw] ![](Shared/Tutorials/InParticleSystemEditorTutorial/CascadeTutorial_Curves02.png) @@ -149,18 +151,18 @@ Solo Mode を有効にしたエミッターが別のエミッターでのイベ ## Type Data -**TypeData** モジュールは、パーティクル エミッターの外観と機能を劇的に変える特殊なモジュールです。エミッターに適用することができる **TypeData** は 1 つだけです。また、エミッター スタックではそのエミッターと他のエミッターの間の黒い空間に表示されます。 +**TypeData** モジュールは、パーティクル エミッタの外観と機能を劇的に変える特殊なモジュールです。エミッタに適用することができる **TypeData** は 1 つだけです。また、エミッタ スタックではそのエミッタと他のエミッタの間の黒い空間に表示されます。 [REGION:raw] ![](typeData.png) [/REGION] -利用可能な TypeData モジュールに関する詳細は、 [パーティクル システムのリファレンス](Engine/Rendering/ParticleSystems/Reference#TypeDataモジュール) を参照してください。 +利用可能な TypeData モジュールに関する詳細は、[パーティクル システムのリファレンス](Engine/Rendering/ParticleSystems/Reference#TypeDataモジュール) を参照してください。 -## エミッターとモジュールの削除 +## エミッタとモジュールの削除 -エミッターまたはモジュールを削除するには、 **右クリック** して [Delete (削除)] オプションを選びます。エミッターの場合、**[Emitter]** 拡張メニューの中にあります。モジュールの場合はそこにあります。 +エミッタまたはモジュールを削除するには、 **右クリック** して [Delete (削除)] オプションを選びます。エミッタの場合、**[Emitter]** 拡張メニューの中にあります。モジュールの場合はそこにあります。 [REGION:raw] ![](deleteEmitter.png) @@ -170,13 +172,13 @@ Solo Mode を有効にしたエミッターが別のエミッターでのイベ -## 簡易 LOD 設定 +## クイック LOD セットアップ [REGION:note] -現在、 **GPU Particles** モジュールを使用している **パーティクル エミッター** は LOD を使うことができません。 +現在、**GPU Particles** モジュールを使用している **パーティクル エミッタ** は LOD を使うことができません。 [/REGION] -1. **[Add LOD (LOD を追加)]** ボタンを使って新しく LOD を追加します。一番高い LOD は LOD 0 です。ここで一番高いとは、「品質が一番高い」という意味です。 +1. **[Add LOD (LOD を追加)]** ボタンを使って新しい LOD を追加します。一番高い LOD は LOD 0 です。ここで一番高いとは、「品質が一番高い」という意味です。 * **[Add LOD Before (直前に LOD を追加)]** ![](AddLOD_After_button.png) ボタンを使って、現在の LOD と二番目に高い LOD の間に LOD を挿入します。 * **[Add LOD After (直後に LOD を追加)]** ![](AddLOD_Before_button.png) ボタンを使って、現在の LOD と二番目に低い LOD (存在する場合) の間に LOD を挿入します。 @@ -193,7 +195,7 @@ Solo Mode を有効にしたエミッターが別のエミッターでのイベ [![](LODDetails.png)(w:880)](LODDetails.png) [/REGION] - 1. エミッター リストの最後の黒い部分を **クリック** します。 + 1. エミッタ リストの最後の黒い部分を **クリック** します。 1. **[Details (詳細)]** パネルにそのパーティクル システム用の設定が表示されます。 1. パーティクル システムの各 LOD の距離設定はLOD カテゴリで変更できます。 diff --git a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/UserGuide/UserGuide.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/UserGuide/UserGuide.KOR.udn index 3fa838c3fc24..e24becff7320 100644 --- a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/UserGuide/UserGuide.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/UserGuide/UserGuide.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3243860 +INTSourceChangelist:3481084 Availability:Public Title: 파티클 시스템 사용 안내서 Crumbs: %ROOT%, Engine, Engine/Rendering/ParticleSystems @@ -6,6 +6,7 @@ Description:파티클 시스템과 캐스케이드의 일반적인 사용법입 Version: 4.9 SkillLevel: Intermediate tags:Particles +topic-image:ParticleSystemUserGuide_topic.png [TOC(start:2 end:3)] diff --git a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/VectorFields/VectorFields.INT.udn b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/VectorFields/VectorFields.INT.udn index e7ca29ca542b..b9d1639c5627 100644 --- a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/VectorFields/VectorFields.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/VectorFields/VectorFields.INT.udn @@ -4,6 +4,7 @@ Crumbs: %ROOT%, Engine, Engine/Rendering/ParticleSystems, Engine/Rendering/Parti Description:An overview of vector fields and how they work with GPU sprites. Version: 4.9 tags:Particles +topic-image:VectorFields_topic.png diff --git a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/VectorFields/VectorFields.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/VectorFields/VectorFields.JPN.udn index f99c83924ed0..5e1f94154591 100644 --- a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/VectorFields/VectorFields.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/VectorFields/VectorFields.JPN.udn @@ -1,9 +1,11 @@ -INTSourceChangelist:2750876 +INTSourceChangelist:3467293 Availability:Public Title:ベクター フィールド Crumbs: %ROOT%, Engine, Engine/Rendering/ParticleSystems, Engine/Rendering/ParticleSystems/Reference, Engine/Rendering/ParticleSystems/Reference/TypeData/GPUSprites Description:ベクター フィールドの概要とベクター フィールドと GPU スプライトとの連携方法 Version:4.9 +tags:Particles +topic-image:VectorFields_topic.png @@ -11,7 +13,7 @@ Version:4.9 効率性はさておき、GPU パーティクルの最も興味深い機能はベクター フィールドです。ベクター フィールドはベクトルの統一グリッドで、パーティクルの動作に影響を及ぼします。ベクターフィールドはアクタ (グローバル ベクター フィールド) としてワールドに配置され、その他のアクタ同様に移動、回転、そしてスケーリングされます。ベクター フィールドは、動的でいつでも移動させることができます。フィールドはカスケード (ローカル ベクター フィールド) 内に配置することも可能で、関連するエミッタに及ぼす影響を制限します。パーティクルがベクター フィールド範囲に突入すると、パーティクルの動作はフィールドに影響され、パーティクルがフィールド範囲を離れるにつれて影響度が薄れます。 -ベクター フィールドは、デフォルト設定でフィールド内のパーティクルへ影響力を与えます。ベクター フィールドには、「タイトネス」パラメータもあります。このパラメータは、パーティクルがフィールドのベクターを直接追跡する方法を制御します。タイトネスが 1 に設定されると、パーティクルはベクターのベロシティを直接フィールドから読み出し、フィールドを正確に追跡します。 +ベクター フィールドは、デフォルト設定でフィールド内のパーティクルへ影響力を与えます。ベクター フィールドには、正確さを制御するパラメータもあります。このパラメータは、パーティクルがフィールドのベクターを追跡する正確さを制御します。Tightness を 1 に設定すると、パーティクルはベクターのベロシティを直接フィールドから読み出し、フィールドを正確に追跡します。 スタティック ベクター フィールドは、ベクターのグリッドが絶対に変化しません。フィールドは Maya からエクスポートして、ボリューム テクスチャとしてインポートします。スタティック フィールドは負荷がほとんどかからず、特にフィールド自体の動作をアニメートすることによって興味深い動作をパーティクルに追加します。 @@ -19,13 +21,13 @@ Version:4.9 [/EXCERPT:VectorFields] -## グローバル ベクター フィールド +## Global Vector Fields -上述のように、**Global Vector Fields** はアクタとしてレベルに配置することができます。ただし、 **コンテンツ ブラウザ** からドラッグすることはできません。レベル内にベクター フィールドを設定するには、Vector Field Volume アクタを追加する必要があります。また、適切なベクター フィールド アセットを関連付ける必要があります。 +上述のように、**Global Vector Fields** はアクタとしてレベルに配置することができます。ただし、**コンテンツ ブラウザ** からドラッグすることはできません。レベル内にベクター フィールドを設定するには、Vector Field Volume アクタを追加する必要があります。また、適切なベクター フィールド アセットを関連付ける必要があります。 ### Vector Field Volume アクタ -**Vector Field Volume Actor** アクタは、従来型のボリュームとは異なります。作成するには、クラス ビューアのベクター フィールド ボリュームを見つけ、それをレベル内にドラッグ&ドロップします。その後、**コンテンツ ブラウザ** からアクタのプロパティ経由でベクター フィールドを割り当てます。一度追加されると、フィールドは位置決定、回転、スケーリングすることができます。 +**Vector Field Volume Actor** アクタは、従来型のボリュームとは異なります。作成するには、クラス ビューアのベクター フィールド ボリュームを見つけ、それをレベル内にドラッグ&ドロップします。その後、**コンテンツ ブラウザ** からアクタのプロパティ経由でベクター フィールドを割り当てます。追加されたフィールドは、配置、回転、スケールが可能になります。 ![](VFScaled.png)(w:460) @@ -41,9 +43,9 @@ Version:4.9 ## ローカル ベクター フィールド -グローバルに対応するフィールドとは対照的に **Local Vector Fields** は、パーティクル システム内に存在しワールド空間に配置されないベクター フィールドです。つまり、[Global Vector Fields](Engine/Rendering/ParticleSystems/Reference/Modules/VectorField) モジュールで全てのパーティクル システムに作用するグローバル ベクター フィールドとは異なり、ローカル ベクター フィールドは割り当てられたパーティクル エミッタのみに変化をもたらします。 +グローバルに対応するフィールドとは対照的に **Local Vector Fields** は、パーティクル システム内に存在しワールド スペースに配置されないベクター フィールドです。つまり、[Global Vector Fields モジュール](Engine/Rendering/ParticleSystems/Reference/Modules/VectorField) ですべてのパーティクル システムに影響するグローバル ベクター フィールドとは異なり、ローカル ベクター フィールドは割り当てられたパーティクル エミッタのみに変化をもたらします。 -ローカル ベクター フィールドは [Local Vector Field モジュール](Engine/Rendering/ParticleSystems/Reference/Modules/VectorField) を用いて追加されます。 +ローカル ベクター フィールドは [Local Vector Field モジュール](Engine/Rendering/ParticleSystems/Reference/Modules/VectorField) で追加されます。 ![](LocalVectorField.png)(w:460) diff --git a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/VectorFields/VectorFields.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/VectorFields/VectorFields.KOR.udn index b7ac459e8757..46ad4754042f 100644 --- a/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/VectorFields/VectorFields.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/ParticleSystems/VectorFields/VectorFields.KOR.udn @@ -1,10 +1,11 @@ -INTSourceChangelist:3243860 +INTSourceChangelist:3467293 Availability: Public Title:벡터 필드 Crumbs: %ROOT%, Engine, Engine/Rendering/ParticleSystems, Engine/Rendering/ParticleSystems/Reference, Engine/Rendering/ParticleSystems/Reference/TypeData/GPUSprites Description:벡터 필드에 대한 개요, GPU 스프라이트와 어떻게 작동하는가에 대한 문서입니다. Version: 4.9 tags:Particles +topic-image:VectorFields_topic.png diff --git a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/AntiAliasing/AntiAliasing.INT.udn b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/AntiAliasing/AntiAliasing.INT.udn index b3a2bfa594a9..011216030db3 100644 --- a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/AntiAliasing/AntiAliasing.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/AntiAliasing/AntiAliasing.INT.udn @@ -1,8 +1,14 @@ -Availability:Public -Title:Anti-Aliasing -Crumbs: %ROOT%, Engine, Engine/Rendering/PostProcessEffects -Description:Smoothing of jagged edges using the FXAA method. -Version: 4.9 +Availability: Public +Crumbs: %ROOT% +Title: Anti-Aliasing +Description: Smoothing of jagged edges using the FXAA method. +Type: Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Rendering/PostProcessEffects +Order:1 +Tags:Post Process +topic-image:AntiAliasing_Topic.png **Anti-Aliasing** (AA) refers to the smoothing of aliased, or jagged, lines when displayed on a computer monitor. diff --git a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/AntiAliasing/AntiAliasing.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/AntiAliasing/AntiAliasing.JPN.udn index 5ae348f01aa7..4c194946c045 100644 --- a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/AntiAliasing/AntiAliasing.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/AntiAliasing/AntiAliasing.JPN.udn @@ -1,12 +1,18 @@ -INTSourceChangelist:2685398 +INTSourceChangelist:3474032 Availability:Public -Title:アンチエイリアス -Crumbs: %ROOT%, Engine, Engine/Rendering/PostProcessEffects +Crumbs: %ROOT% +Title:アンチエイリアシング Description:FXAA 手法を使用してギザギザになった縁を滑らかにする処理 -Version:4.9 +Type:Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Rendering/PostProcessEffects +Order:1 +Tags:Post Process +topic-image:AntiAliasing_Topic.png -**アンチエイリアス** (AA) は、PC のモニターに表示されるエイリアス (ジャギー) またはギザギザになった線を滑らかに補整する処理のことです。 +**アンチエイリアス** (AA) は、PC のモニターに表示されるエイリアス (ジャギー) またはギザギザになった線を滑らかに補正する処理のことです。 [OBJECT:ComparisonSlider] [PARAM:before] @@ -17,7 +23,7 @@ Version:4.9 [/PARAM] [/OBJECT] -アンリアル・エンジン 4のアンチエイリアス処理は、FXAA を使用して後処理時に実行されます。FXAA は効果的な GPU MLAA 実装です。 +アンリアル・エンジン 4 のアンチエイリアス処理は、FXAA を使用して後処理時に実行されます。FXAA は効果的な GPU MLAA 実装です。 この手法によりほとんどのエイリアス アーティファクトが解決されますが、定期的に発生するエイリアスを完全に回避することは出来ません。 以下はその他の技術です。UE4 は、現状は エディター 3D プリミティブ (3D ギズモなど) とテンポラル アンチエイリアシングのいくつかに対してのみ MSAA をサポートしています。 diff --git a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/AntiAliasing/AntiAliasing.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/AntiAliasing/AntiAliasing.KOR.udn index 33b0eed70752..a0db7e24a570 100644 --- a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/AntiAliasing/AntiAliasing.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/AntiAliasing/AntiAliasing.KOR.udn @@ -1,9 +1,15 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3474032 Availability:Public +Crumbs: %ROOT% Title:안티-앨리어싱 -Crumbs: %ROOT%, Engine, Engine/Rendering/PostProcessEffects -Description:각진 선분을 FXAA 메소드를 사용해서 부드럽게 만드는 법입니다. -Version: 4.9 +Description:각진 에지를 부드럽게 만드는 FXAA 메소드입니다. +Type: Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Rendering/PostProcessEffects +Order:1 +Tags:Post Process +topic-image:AntiAliasing_Topic.png 안티 앨리어싱(Anti-Aliasing, AA) 이란 컴퓨터 모니터에 표시되는 선이 (중간 단계 없이) 0 이나 1 로 각지게 그려지는 것을 부드럽게 만들어 주는 현상을 말합니다. @@ -28,3 +34,4 @@ Version: 4.9 자세한 정보: [FXAA 백서](http://developer.download.nvidia.com/assets/gamedev/files/sdk/11/FXAA_WhitePaper.pdf) (외부 링크) + diff --git a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/AutomaticExposure/AutomaticExposure.INT.udn b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/AutomaticExposure/AutomaticExposure.INT.udn index 25a66032d662..68aa03b202b0 100644 --- a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/AutomaticExposure/AutomaticExposure.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/AutomaticExposure/AutomaticExposure.INT.udn @@ -1,8 +1,15 @@ -Availability:Public -Title:Eye Adaptation -Crumbs: %ROOT%, Engine, Engine/Rendering/PostProcessEffects -Description:Automatic adjustment of scene exposure to simulate eye adaptation from changes in brightness. -Version: 4.9 +Availability: Public +Crumbs: %ROOT% +Title: Eye Adaptation (Auto-Exposure) +Description: Automatic adjustment of scene exposure to simulate eye adaptation from changes in brightness. +Type: Overview +SkillLevel: Beginnner +Version:4.16 +Parent:Engine/Rendering/PostProcessEffects +Order:2 +Tags:Post Process +Topic-image:EyeAdap_Topic.png + [EXCERPT:EyeAdaptation_Desc] **Eye Adaptation**, or automatic exposure, causes the exposure of the scene to automatically adjust to recreate the effect experienced as human eyes adjust when going from a bright environment into a dark environment or vice versa. diff --git a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/AutomaticExposure/AutomaticExposure.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/AutomaticExposure/AutomaticExposure.JPN.udn index f39bd19ba944..baad18dc198b 100644 --- a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/AutomaticExposure/AutomaticExposure.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/AutomaticExposure/AutomaticExposure.JPN.udn @@ -1,12 +1,19 @@ -INTSourceChangelist:2685419 +INTSourceChangelist:3474032 Availability:Public -Title:自動露光 -Crumbs: %ROOT%, Engine, Engine/Rendering/PostProcessEffects +Crumbs: %ROOT% +Title:自動露光 (別名:明暗順応) Description:輝度の変更から視覚の順応をシミュレートするためにシーンの露出を自動調整します。 -Version:4.9 +Type:Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Rendering/PostProcessEffects +Order:2 +Tags:Post Process +Topic-image:EyeAdap_Topic.png + [EXCERPT:EyeAdaptation_Desc] -**自動露光**、または自動露出は、明るい環境から暗い環境へ、そして逆もまた同様に、人間の視覚が体験する効果を再現するために、シーンの露出を自動調整します。 +**自動露光**、または明暗順応は、明るい環境から暗い環境へそして逆もまた同様に、人間の視覚が体験する効果を再現するために、シーンの露出を自動的に調整します。 [/EXCERPT:EyeAdaptation_Desc] [REGION:fullwidth] @@ -15,13 +22,13 @@ Version:4.9 | プロパティ | 説明 | | -------- | ----------- | -| **Low Percent** | シーンカラーの輝度ヒストグラムから抽出した値へ視覚を順応させます。値はヒストグラムの低い方の割合を定義します。この割合はシーン輝度の平均値の検知に使用されます。明るい画像部分のクランプを避けたいため、暗い領域のほとんどの部分を無視するのが最良です。例えば、80 の値は暗部の 80 %を回避します。設定値は、 [0, 100] の範囲でなくてはいけません。70 から 80 の範囲の値で最高の結果を得られます。 -| **High Percent** | シーンカラーの輝度ヒストグラムから抽出した値へ視覚を順応させます。値はヒストグラムの高い方の割合を定義します。この割合はシーン輝度の平均値の検知に使用されます。いくつかの明るいピクセルがあっても問題ないため (大抵は太陽) 、数パーセント縮小させます。設定値は、[0, 100] の範囲でなくてはいけません。80 から 98 の範囲の値で最高の結果を得られます。| -| **Min Brightness** | この値は視覚が順応する範囲内の低い方の輝度を制限します。値は 0 より大きい数値および<= **EyeAdaptationMaxBrightness** であることが必須です。実際の値はコンテンツが使用している HDR 範囲で決定します。 -| **Max Brightness** | この値は視覚が順応する範囲内の低い方の輝度を制限します。値は 0 より大きい数値および>= **EyeAdaptationMinBrightness** であることが必須です。実際の値はコンテンツが使用している HDR 範囲で決定します。 -| **Speed Up** | 暗い環境から明るい環境へ暗順応が起こる速度です。 | +| **Low Percent** | シーンカラーの輝度ヒストグラムから抽出した値へ視覚を順応させます。値はヒストグラムの低い方の割合を定義します。この割合はシーン輝度の平均値の検知に使用されます。明るい画像部分のクランプを避けたいため、暗い領域のほとんどの部分を無視するのが最良です。例えば、80 の値は暗部の 80 %を回避します。設定値は、[0, 100] の範囲でなくてはいけません。70 から 80 の範囲の値で最高の結果を得られます。 +| **High Percent** | シーンカラーの輝度ヒストグラムから抽出した値へ視覚を順応させます。値はヒストグラムの高い方の割合を定義します。この割合はシーン輝度の平均値の検知に使用されます。いくつかの明るいピクセルがあっても問題ないため (大抵は太陽)、数パーセント縮小させます。設定値は、[0, 100] の範囲でなくてはいけません。80 から 98 の範囲の値で最高の結果を得られます。| +| **Min Brightness** | この値は視覚が順応する範囲内の低い方の輝度を制限します。値は 0 より大きい数値および <= **EyeAdaptationMaxBrightness** であることが必須です。実際の値はコンテンツが使用している HDR 範囲で決定します。 | +| **Max Brightness** | この値は視覚が順応する範囲内の低い方の輝度を制限します。値は 0 より大きい数値および >= **EyeAdaptationMinBrightness** であることが必須です。実際の値はコンテンツが使用している HDR 範囲で決定します。 | +| **Speed Up** | 暗い環境から明るい環境へ明順応が起こる速度です。 | | **Speed Down** | 明るい環境から暗い環境へ暗順応が起こる速度です。 | -| **Auto Exposure Bias** | 露出設定のバイアスを制御します。値は対数で表されています。 [INCLUDE:#ExposureOffset] つまり 1.5 などの小数値、または表示例の外側の値でも機能します。自動露光がアクティブな時、値は自動露出に加算されます。 | +| **Auto Exposure Bias** | 露光設定のバイアスを制御します。値は対数で表されています。 [INCLUDE:#ExposureOffset] つまり 1.5 などの小数値、または表示例の外側の値でも機能します。自動露光がアクティブな時、値は自動露出に加算されます。 | +## Bloom Convolution + +The Bloom **Convolution** effect enables you to add custom bloom kernel shapes with a texture that represent physically realistic bloom effects whereby the scattering +and diffraction of light within the camera or eye that give rise to bloom is modeled by a mathematical convolution of a source image with a kernel image. + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Convolution for Bloom: Enabled](FFTBloom_Enabled.png) + [/PARAM] + [PARAM:after] + ![Convolution for Bloom: Disabled](FFTBloom_disabled.png) + [/PARAM] +[/OBJECT] +[REGION:caption] +[/REGION] +[REGION:caption] +In this example, the bloom technique produces a continuum of responses ranging from star-like bursts to diffuse glowing regions. +[/REGION] + +The kernel represents the response of the optical device to a single point source in the center of the viewing field. Each pixel in the source contributes some of its brightness +to neighbors as prescribed by the kernel image. The brighter the source pixel the more visible the bloom it produces. Under the hood this energy conserving scatter is formulated +as a convolution operations and accelerated by use of a Fast Fourier Transform (FFT). + +[REGION:warning] +Bloom Convolution is designed for use with with in-game or offline cinematics or on high-end hardware, while the **_Standard_ bloom should be used for most game applications**. +In assessing the trade off, the _Standard_ bloom has a significant performance advantage but it is not conservative (it can result in an overall brightening of the image) +and it lacks the visual complexity of the Bloom Convolution. +[/REGION] + +To enable Bloom Convolution, navigate to the **Lens** section of the Post Process Volume and next to **Method** use the selection box to choose **Convolution**. + +![](ConvolutionBloomSettings.png)(w:450) + +[REGION:raw] +| Property | %spacer2% | Description | +| -------- | --------- | ----------- | +| **Convolution Kernel** || Use this to select the texture that defines the kernel. | +| [REGION:tablesection] Advanced Properties [/REGION] ||| +| **Convolution Scale** || This indicates the relative size of the Convolution Kernel image in units of the viewport, defaults to 1. Primarily used to decrease the size of the bloom. | +| **Convolution Center** || In UV coordinates, defaults to (1/2, 1/2). Ideally the Convolution Kernel image is a perfectly centered response to a brighter source, but generally small tweaks will be required. Offsets here will result in full offsets of the bloom image. | +| **Convolution Boost** || Boosts the intensity of select pixels prior to applying the convolution bloom filter. This consists of a minimum value, a maximum value and a multiplier. The brightness delta above the minimum value will be amplified by the multiplier. By default this boost is disabled and should be used with caution. | +| **Convolution Buffer** || Implicit buffer region as a fraction of screen size to insure the bloom does not wrap around the image. Increasing this value has adverse performance impact. | +[/REGION] + +### Kernel Image Best Practices + +The additional realism generated by the image-based convolution is the result of its ability to use a visually interesting, non-symmetric kernel images. When +creating your kernel images and setting them up for use with Bloom Convolution, there are a few things that you should keep in mind. + +* The kernel image should be fully present on the GPU and available at full resolution, otherwise a low resolution version of the kernel may be used and will result in serious +degradation of quality. To do this, set the following properties in the Texture Editor for the kernel image: + [INCLUDE:#cbtextureproperties] +* Bloom is a whole image filter, so with Convolution Bloom the hottest part of the image should be the considerably brighter than the rest of the image (.exr format works well for this), +otherwise the filter will have a strong blurring effect over the screen. +* The system expects the hottest point to be at the center of your kernel image, however, this can be adjusted by using the **Convolution Center** controls. +* A good bloom kernel structure should fill most of the kernel image. If you look at the default kernel image in Photoshop, you'll see that the radial lines that diverge from the center spread out +for a considerable amount of the image. + [OBJECT:ComparisonSlider] + [PARAM:before] + ![Kernel Image unaltered](KernelImage1.png)(w:400) + [/PARAM] + [PARAM:after] + ![Kernel Image adjusted for demonstration](KernelImage2.png)(w:400) + [/PARAM] + [/OBJECT] +* Large changes in the Convolution behavior should be done by changing the kernel image with minor tweaks done using the Bloom Convolution Advanced properties. + + + ## Bloom Dirt Mask -The **Bloom Dirt Mask** effect uses a texture to brighten up the bloom in some defined screen areas. This can be used to create a war camera look, more impressive HDR effect, or camera imperfections. +The **Bloom Dirt Mask** effect uses a texture to brighten up the bloom in some defined screen areas. This can be used to create a war camera look, more impressive HDR effect, or camera +imperfections. -| Property | Description | -| -------- | ----------- | -| **Dirt Mask** | The Texture2D to use as the mask. It is recommended that a non-power of two texture is used as it fits the screen size better and it avoids mip creation and streaming. A low resolution texture is often sufficient as dirt on the camera is likely to be out of focus and blurry anyway. The texture can be created with the Photoshop Lens blur. Chromatic aberration (color fringe) can improve the look. Beware of compression artifacts. This property cannot be blended. We plan to make this more dynamic and programmable through custom shaders. | -| **Dirt Mask Tint Color** | Used to darken or color tint the dirt mask texture. This can be used to tweak the dirt mask brightness and color. | -| **Dirt Mask Intensity** | Scales the color of the bloom dirt mask effect (linear). This property is used to tweak dirt mask brightness. | +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Dirt Mask Enabled](DirtMaskEnabled.png)(w:600) + [/PARAM] + [PARAM:after] + ![Dirt Mask Disabled](DirtMaskDisabled.png)(w:600) + [/PARAM] +[/OBJECT] +To enable Bloom Dirt Mask, navigate to the **Lens** section of the Post Process Volume and enable the option for **Dirt Mask Texture**. Use the Texture selection to apply the texture for your Dirt Mask. + +![](DirtMaskProperties.png)(w:450) + +[REGION:raw] +| Property | %spacer2% | Description | +| -------- | --------- | ----------- | +| **Dirt Mask Texture** || Use the selection box to assign a Texture2D to be used for your Dirt Mask. Keep in mind that this property cannot be blended with other Post Process Volumes. | +| **Dirt Mask Intensity** || Scales the color of the bloom dirt mask effect (linear). This property is used to tweak dirt mask brightness. | +| **Dirt Mask Tint Color** || Used to darken or color tint the dirt mask texture. This can be used to tweak the dirt mask brightness and color. | +[/REGION] + +### Dirt Mask Image Best Practices + +When creating your Dirt Mask textures and setting them up for use with Bloom Dirt Mask, there are a few things you should keep in mind. + +* The texture should be fully present on the GPU and available at the full resolution. To do this, set the following property in the Texture Editor: + [INCLUDE:#dirtmasktextureproperty] +* This Post Process property cannot be blended with other Post Process Volumes in your level. +* When constructing your Dirt Mask Texture, keep the following in mind: + [INCLUDE:#dirtmaskexample] + * It is recommended to use a non-power of two image size. This avoids Mip creation and streaming, so these should be set automatically, however, if you use a power of two texture size, you'll need to set these in the Texture Editor properties. + * You can use a low-resolution texture as this is usually sufficient to represent dirt or scratches on the camera and these are likely to be out of focus and blurry anyway. If you're getting compression artifacts you can try a higher resolution image. + * You can create the texture using Photoshop (or similar image editing software) using Lens blur. + * Use chromatic aberration (color fringe), in the texture, to help improve the look of the dirt mask. + + + + + +## Training Streams + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + SkJgopq-JQA + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] diff --git a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/Bloom/Bloom.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/Bloom/Bloom.KOR.udn index 051b7bfa5eea..06a31d5981b1 100644 --- a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/Bloom/Bloom.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/Bloom/Bloom.KOR.udn @@ -1,28 +1,47 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3474032 Availability:Public +Crumbs: Title:블룸 -Crumbs: %ROOT%, Engine, Engine/Rendering/PostProcessEffects Description:광륜을 통해 라이트처럼 밝은 오브젝트를 밝게 빛나게 만드는 글로우 이펙트입니다. -Version: 4.9 +Type:reference +Version:4.16 +Parent:Engine/Rendering/PostProcessEffects +Order:1 +Tags:Post Process +Topic-image:bloom_Topic.png + +[VAR:spacer]![](%ROOT%/spacer.png)(w:150 convert:false)[/VAR] +[VAR:spacer2]![](%ROOT%/spacer.png)(w:40 convert:false)[/VAR] + +[TOC(start:2 end:2)] + [EXCERPT:Bloom_Desc] -**Bloom** (블룸)이란 중간 정도의 렌더링 퍼포먼스 비용으로 이미지 렌더링에 사실감을 크게 더해줄 수 있는, 현실에서도 볼 수 있는 광학 현상입니다. 블룸 현상은 훨씬 어두운 배경에 있는 매우 밝은 물체를 맨눈으로 바라볼 때 목격할 수 있습니다. 그보다 밝아지면 (빛줄기나 렌즈 플레어같은) 다른 현상도 생길 수 있지만, 고전적인 블룸 효과에서는 다루지 않습니다. 보통 쓰는 (TV, TFT 등의) 디스플레이에서는 HDR(High Dynamic Range)이 지원되지 않기에, 너무 밝은 오브젝트는 렌더링할 수가 없습니다. 대신 빛이 필름에 내리쬐거나(필름 피하산란) 카메라 앞에 내리쬘 때(유윳빛 유리 필터) 눈에서 벌어지는 (망막 피하산란) 현상을 흉내냅니다. 그 효과가 물리적으로야 항상 옳지는 않겠지만, 오브젝트의 상대적 밝기를 살려주거나 화면에 표시되는 LDR(Low Dynamic Range) 이미지에 사실감을 더하는 데 도움이 될 수는 있습니다. +**Bloom** (블룸)이란 중간 정도의 렌더링 퍼포먼스 비용으로 이미지 렌더링에 사실감을 크게 더해줄 수 있는, 현실에서도 볼 수 있는 광학 현상입니다. +블룸 현상은 훨씬 어두운 배경에 있는 매우 밝은 물체를 맨눈으로 바라볼 때 목격할 수 있습니다. 그보다 밝아지면 (빛줄기나 렌즈 플레어같은) 다른 현상도 생길 수 있지만, +고전적인 블룸 효과에서는 다루지 않습니다. 보통 쓰는 (TV, TFT 등의) 디스플레이에서는 HDR(High Dynamic Range)이 지원되지 않기에, 너무 밝은 오브젝트는 렌더링할 수가 없습니다. +대신 빛이 필름에 내리쬐거나(필름 피하산란) 카메라 앞에 내리쬘 때(유윳빛 유리 필터) 눈에서 벌어지는 (망막 피하산란) 현상을 흉내냅니다. +그 효과가 물리적으로야 항상 옳지는 않겠지만, 오브젝트의 상대적 밝기를 살려주거나 화면에 표시되는 LDR(Low Dynamic Range) 이미지에 사실감을 더하는 데 도움이 될 수는 있습니다. [/EXCERPT:Bloom_Desc] [REGION:fullwidth] ![Bloom Effect](bloom.png) [/REGION] -블룸은 하나의 가우시안 블러(Gaussian blur)로 구현할 수 있습니다. 품질을 높이기 위해서는, 반경이 다른 가우시안 블러 여럿을 합칩니다. 퍼포먼스를 높이기 위해서는, 매우 넓은 블러를 훨씬 낮은 해상도로 합니다. UE3 에서는 1/4, 1/8, 1/16 해상도의 가우시안 블러 셋을 썼었습니다. 현재는 Blur1 부터 5 까지, 1/2 (Blur1) 에서 1/32 (Blur5) 해상도의 블러를 씁니다. 필요하다면 최대 해상도 블러용 Blur0 을 추가할 수도 있습니다. +블룸은 하나의 가우시안 블러(Gaussian blur)로 구현할 수 있습니다. 품질을 높이기 위해서는, 반경이 다른 가우시안 블러 여럿을 합칩니다. 퍼포먼스를 높이기 위해서는, 매우 넓은 +블러를 훨씬 낮은 해상도로 합니다. UE3 에서는 1/4, 1/8, 1/16 해상도의 가우시안 블러 셋을 썼었습니다. 현재는 Blur1 부터 5 까지, 1/2 (Blur1) 에서 1/32 (Blur5) 해상도의 블러를 씁니다. -제어할 수 있는 폭과 품질을 높이기 위해 블러를 합치는 방식을 다양화시킬 수 있습니다. 최적의 퍼포먼스를 위해서는, 고해상도 (낮은 번호) 블러는 좁게, 넓은 블러에는 주로 저해상도 (높은 번호) 블러를 사용해야 할 것입니다. +제어할 수 있는 폭과 품질을 높이기 위해 블러를 합치는 방식을 다양화시킬 수 있습니다. 최적의 퍼포먼스를 위해서는, 고해상도 (낮은 번호) 블러는 좁게, +넓은 블러에는 주로 저해상도 (높은 번호) 블러를 사용해야 할 것입니다. -| 프로퍼티 | 설명 | -| -------- | ---- | -| **Intensity** | 블룸 강도 - 전체 블룸 이펙트의 (선형) 색 스케일입니다. 시간에 따른 페이드 인이나 아웃, 어둡게 만드는 데 사용할 수 있습니다. [INCLUDE:#Intensity] | -| **Threshold** | 블룸 한계치 - 블룸을 적용하기 시작할 색의 휘도를 정의합니다. 한계치 이외에 색이 블룸에 부분적으로만 영향을 끼치는 (1 유닛 폭) 선형 부분이 있습니다. 씬의 모든 색이 블룸에 공헌하게 하려면, -1 볼륨을 사용해야 합니다. 일부 비현실적인 HDR 콘텐츠, 몽환적인 부분 트윅에 사용할 수 있습니다. [INCLUDE:#Threshold] | -| **#1/#2/#3/#4/#5 Tint** | 블룸 #1/#2/#3/#4/#5 색조 - 각 블룸의 밝기와 색을 변경합니다. 검정색을 사용한다고 그 패스가 빨라지지는 않지만, 가능은 합니다. | -| **#1/#2/#3/#4/#5 Size** | 블룸 #1/#2/#3/#4/#5 크기 - 화면 폭을 기준으로 한 백분율 크기입니다. 일정 수치로 제한됩니다. 큰 수치가 필요하다면 한 단계 낮은 해상도 (높은 번호) 블러를 대신 사용하세요. [INCLUDE:#Size] | +[REGION:raw] +| 프로퍼티 | %spacer2% | 설명 | +| -------- | --------- | ----------- | +| **Intensity** || 블룸 강도 - 전체 블룸 이펙트의 (선형) 색 스케일입니다. 시간에 따른 페이드 인이나 아웃, 어둡게 만드는 데 사용할 수 있습니다. [INCLUDE:#Intensity] | +| **Threshold** || 블룸 한계치 - 블룸을 적용하기 시작할 색의 휘도를 정의합니다. 한계치 이외에 색이 블룸에 부분적으로만 영향을 끼치는 (1 유닛 폭) 선형 부분이 있습니다. 씬의 모든 색이 블룸에 공헌하게 하려면, -1 볼륨을 사용해야 합니다. 일부 비현실적인 HDR 콘텐츠, 몽환적인 부분 트윅에 사용할 수 있습니다. [INCLUDE:#Threshold] | +| **#1/#2/#3/#4/#5 Tint** || 블룸 #1/#2/#3/#4/#5 색조 - 각 블룸의 밝기와 색을 변경합니다. 검정색을 사용한다고 그 패스가 빨라지지는 않지만, 가능은 합니다. | +| **#1/#2/#3/#4/#5 Size** || 블룸 #1/#2/#3/#4/#5 크기 - 화면 폭을 기준으로 한 백분율 크기입니다. 일정 수치로 제한됩니다. 큰 수치가 필요하다면 한 단계 낮은 해상도 (높은 번호) 블러를 대신 사용하세요. [INCLUDE:#Size] | +[/REGION] +## 블룸 컨볼루션 + +블룸 **Convolution** (컨볼루션)은 물리적으로 사실적인 블룸 이펙트를 표현하는 텍스처와 함께 커스텀 블룸 커널 모양을 추가할 수 있도록 해주는 이펙트로, +카메라나 눈 내부 빛의 산란이나 굴절이 블룸 효과를 일으킬 때 소스 이미지와 커널 이미지의 컨볼루션(합성곱) 수학 연산으로 모델링해 내는 기법입니다. + +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Convolution for Bloom: Enabled](FFTBloom_Enabled.png) + [/PARAM] + [PARAM:after] + ![Convolution for Bloom: Disabled](FFTBloom_disabled.png) + [/PARAM] +[/OBJECT] +[REGION:caption] +[/REGION] +[REGION:caption] +이 예제에서는 블룸 기법으로 별모양 광채에서부터 디퓨즈 글로우 구역에 이르기까지 다양한 반응 연속체 효과를 만들어내고 있습니다. +[/REGION] + +커널은 시야 중심의 단일 지점 소스에 대한 광학 기기의 반응을 나타냅니다. 그 소스의 각 픽셀은 그 밝기 일부를 커널 이미지에 미리 정해진 대로 인접 픽셀에 기여합니다. +소스 픽셀이 밝을 수록 거기서 만들어 내는 블룸도 더욱 잘 보이게 됩니다. 내부적으로 이러한 에너지 보존 산란 공식은 +컨볼루션(합성곱) 연산과 고속 푸리에 변환(Fast Fourier Transform, FFT) 가속으로 이루어집니다. + +[REGION:warning] +블룸 컨볼루션은 고사양 하드웨어에서의 게임내 또는 오프라인 시네마틱에 사용하도록 의도된 것이며, **대부분의 게임 어플리케이션에서는 표준 블룸을 사용해야 할 것입니다**. +득실을 따져보자면, _표준_ 블룸은 퍼포먼스가 크게 뛰어나지만 보존적이지 않(이미지가 전반적으로 밝아질 수 있)으며 +블룸 컨볼루션의 시작적인 복잡도를 따라가지는 못합니다. +[/REGION] + +블룸 컨볼루션을 켜려면, Post Process Volume 의 **Lens** 섹션에서 **Method** 옆 선택 박스에서 **Convolution** 을 선택합니다. + +![](ConvolutionBloomSettings.png)(w:450) + +[REGION:raw] +| 프로퍼티 | %spacer2% | 설명 | +| -------- | --------- | ----------- | +| **Convolution Kernel** || 컨볼루션 커널 - 커널을 정의하는 텍스처를 선택합니다. | +| [REGION:tablesection] 고급 프로퍼티 [/REGION] ||| +| **Convolution Scale** || 컨볼루션 스케일 - 컨볼루션 커널 이미지의 상대적 크기를 뷰포트 유닛 단위로 나타낸 것으로, 기본값은 1 입니다. 블룸 크기를 줄이는 데 주로 사용됩니다. | +| **Convolution Center** || 컨볼루션 중심 - UV 좌표로 기본값은 (�, �) 입니다. Convolution Kernel 이미지는 보다 밝은 소소에 대해 완벽히 중심 위치인 것이 이상적이지만, 일반적으로 약간의 트윅이 필요합니다. 여기서 오프셋은 블룸 이미지에 풀 오프셋을 주게 됩니다. | +| **Convolution Boost** || 컨볼루션 부스트 - 컨볼루션 블룸 필터 적용 전 선택 픽셀 밝기를 증폭시킵니다. 최소, 최대값과 배수로 이루어집니다. 최소값 이상의 밝기 델타에 배수만큼 증폭시킵니다. 기본적으로 이 부스트는 꺼져있으며, 조심해서 사용해야 합니다. | +| **Convolution Buffer** || 컨볼루션 버퍼 - 화면 크기의 일정 비율로 정하는 암묵적 버퍼 구역으로, 블룸이 이미지를 감싸지(wrap around) 않도록 하기 위함입니다. 이 값을 올리면 퍼포먼스에 안좋은 영향을 줍니다. | +[/REGION] + +### 커널 이미지 실전 사례 + +이미지 기반 컨볼루션으로 추가되는 사실적 느낌은 시각적으로 흥미로운 비대칭 커널 이미지를 사용할 수 있기 때문에 발생하는 결과입니다. +커널 이미지를 만들어 블룸 컨볼루션에 사용하도록 구성할 때, 몇 가지 염두에 두어야 할 점이 있습니다. + +* 커널 이미지는 GPU 에 온전히 존재해야 하며, 전체 해상도로 사용가능해야 합니다. 그렇지 않으면 커널 저해상도 버전이 사용되어 심각한 퀄리티 저하로 이어집니다. +텍스처 에디터에서 커널 이미지에 대해 다음과 같은 프로퍼티 설정을 해주면 됩니다: + [INCLUDE:#cbtextureproperties] +* 블룸은 전체 이미지 필터로, 컨볼루션 블룸은 이미지의 가장 핫한 부분을 나머지 부분보다 현저히 밝게 만들거나 (.exr 포맷이 여기에 좋습니다), +아니면 필터로 인해 화면에 강력한 블러 이펙트가 생길 것입니다. +* 시스템에서는 가장 핫한 지점이 커널 이미지 중심일 것으로 기대합니다만, **Convolution Center** 컨트롤로 제어할 수 있습니다. +* 블룸 커널 스트럭쳐가 괜찮으면 대부분의 커널 이미지를 채울 것입니다. Photoshop 에서 기본 커널 이미지를 살펴보면, 중심에서 이미지 상당 부분까지 뻗어나가는 방사선이 +보일 것입니다. + [OBJECT:ComparisonSlider] + [PARAM:before] + ![커널 이미지 원본](KernelImage1.png)(w:400) + [/PARAM] + [PARAM:after] + ![데모용 커널 이미지 변경](KernelImage2.png)(w:400) + [/PARAM] + [/OBJECT] +* 블룸 컨볼루션 고급 프로퍼티로 커널 이미지에 약간의 트윅 작업을 하는 것으로 컨볼루션 작동방식을 크게 바꿀 수 있을 것입니다. + + + ## 블룸 더트 마스크 -**Bloom Dirt Mask** (블룸 더트 마스크) 이펙트는 텍스처를 사용해서 일부 정의된 화면 영역의 블룸을 밝게 만드는 것을 말합니다. 전장의 카메라, 더욱 인상깊은 HDR 이펙트, 카메라 결함 등의 효과를 내는 데 사용할 수 있습니다. +**Bloom Dirt Mask** (블룸 더트 마스크) 이펙트는 텍스처를 사용해서 일부 정의된 화면 영역의 블룸을 밝게 만드는 것을 말합니다. 전장의 카메라, 더욱 인상깊은 HDR 이펙트, 카메라 결함 등의 효과를 내는 데 +사용할 수 있습니다. -| 프로퍼티 | 설명 | -| -------- | ---- | -| **Dirt Mask** | 블룸 더트 마스크 - 마스크로 사용할 Texture2D 입니다. 화면 측면에 더 잘 맞고 밉 생성과 스트리밍을 피하게 되므로 2 제곱이 아닌 텍스처를 사용하는 것이 좋습니다. 카메라에 붙은 먼지는 초점이 안맞아 흐려지게 마련이므로, 보통은 저해상도 텍스처로 충분합니다. 이 텍스처는 포토샵 렌즈 블러로 만들 수 있습니다. 색수차(Chromatic aberration, 또는 color fringe) 효과로 느낌을 살릴 수도 있습니다. 압축 부작용에 주의하세요. 이 프로퍼티는 블렌딩 불가능하며, 나중에 커스텀 셰이더를 통해 동적으로 프로그래밍 가능하도록 만들 계획입니다. | -| **Dirt Mask Tint Color** | 블룸 더트 마스크 색조 - 더트 마스크 텍스처에 색을 입히거나 어둡게 만듭니다. 더트 마스크 밝기와 색을 조정하는 데 사용할 수 있습니다.| -| **Dirt Mask Intensity** | 블룸 더트 마스크 강도 - 블룸 더트 마스크의 (선형) 색 스케일입니다. 이 프로퍼티는 더트 마스크의 밝기를 조정하는 데 사용됩니다. | +[OBJECT:ComparisonSlider] + [PARAM:before] + ![Dirt Mask Enabled](DirtMaskEnabled.png)(w:600) + [/PARAM] + [PARAM:after] + ![Dirt Mask Disabled](DirtMaskDisabled.png)(w:600) + [/PARAM] +[/OBJECT] + +Bloom Dirt Mask (블룸 더트 마스크)를 켜려면, Post Process Volume 의 **Lens** 섹션에서 **Dirt Mask Texture** 옵션을 켜면 됩니다. 텍스처 선택을 통해 더트 마스크에 텍스처를 적용하면 됩니다. + +![](DirtMaskProperties.png)(w:450) + +[REGION:raw] +| 프로퍼티 | %spacer2% | 설명 | +| -------- | --------- | ----------- | +| **Dirt Mask Texture** || 더트 마스크 텍스처 - 선택 박스로 더트 마스크에 사용할 Texture2D 를 할당합니다. 이 프로퍼티는 다른 Post Process Volume 과 블렌딩할 수 없다는 점 유념하세요. | +| **Dirt Mask Intensity** || 블룸 더트 마스크 강도 - 블룸 더트 마스크의 (선형) 색 스케일입니다. 이 프로퍼티는 더트 마스크의 밝기를 조정하는 데 사용됩니다. | +| **Dirt Mask Tint Color** || 블룸 더트 마스크 색조 - 더트 마스크 텍스처에 색을 입히거나 어둡게 만듭니다. 더트 마스크 밝기와 색을 조정하는 데 사용할 수 있습니다.| +[/REGION] +### 더트 마스크 이미지 실전 사례 + +더트 마스크 텍스처를 생성하여 블룸 더트 마스크에 사용하도록 구성할 때, 몇 가지 유념해야 하는 것이 있습니다. + +* 텍스처는 GPU 에 온전히 존재해야 하며 전체 해상도로 사용 가능해야 합니다. 그러기 위해서는 텍스처 에디터에서 다음 프로퍼티를 설정해 줍니다: + [INCLUDE:#dirtmasktextureproperty] +* 이 Post Process 프로퍼티는 레벨의 다른 Post Process Volume 과 블렌딩할 수 없습니다. +* 더트 마스크 텍스처 구성 시 유념해야 할 점은 다음과 같습니다: + [INCLUDE:#dirtmaskexample] + * 이미지 크기가 2 제곱이 아닌 것을 사용할 것을 추천합니다. 밉 생성과 스트리밍을 하지 않아 자동 설정될 것이지만, 2 제곱 크기 텍스처를 사용한다면 텍스처 에디터 프로퍼티에서 설정해 줘야 합니다. + * 저해상도 텍스처를 사용해도 되는데, 보통 카메라의 먼지나 긁힘을 표현하기에 충분할 뿐만 아니라, 어쨌든 초점을 흐려 뿌옇게 만들 것이기 때문입니다. 압축 부작용이 생기는 경우 더욱 높은 해상도의 이미지를 사용해 보면 됩니다. + * Photoshop (이나 기타 이미지 편집 소프트웨어)의 렌즈 블러를 사용하여 텍스처를 만들면 됩니다. + * 텍스처에 색수차(chromatic aberration, 컬러 프린지)를 사용하면 더트 마스크 느낌을 살리는 데 도움이 될 수 있습니다. + + + + + +## 교육 자료 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + SkJgopq-JQA + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] diff --git a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/ColorGrading/ColorGrading.INT.udn b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/ColorGrading/ColorGrading.INT.udn index 8150208d1ea5..076d4fba73b6 100644 --- a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/ColorGrading/ColorGrading.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/ColorGrading/ColorGrading.INT.udn @@ -1,8 +1,16 @@ -Availability:Public -Title:Color Grading -Crumbs: %ROOT%, Engine, Engine/Rendering/PostProcessEffects -Description:Tonemapping and color correction effects for adjusting scene colors. -Version: 4.9 +Availability: Public +Crumbs: %ROOT% +Title: Color Grading +Description: Tonemapping and color correction effects for adjusting scene colors. +Type: Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Rendering/PostProcessEffects +Order:4 +Tags:Post Process +Topic-image:ColorGrading_Topic.png + + Within the Unreal engine, the term **Color Grading** covers the Tone Mapping function (HDR to LDR transformation) and the further Color Correction (LDR color to screen color transformation). diff --git a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/ColorGrading/ColorGrading.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/ColorGrading/ColorGrading.KOR.udn index 2b65b92ef310..432b185d8f13 100644 --- a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/ColorGrading/ColorGrading.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/ColorGrading/ColorGrading.KOR.udn @@ -1,9 +1,17 @@ -INTSourceChangelist:3108692 -Availability:Public +INTSourceChangelist:3474032 +Availability: Public +Crumbs: %ROOT% Title:컬러 그레이딩 -Crumbs: %ROOT%, Engine, Engine/Rendering/PostProcessEffects Description:씬 컬러 조절을 위한 톤매핑과 색보정 이펙트입니다. -Version: 4.9 +Type: Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Rendering/PostProcessEffects +Order:4 +Tags:Post Process +Topic-image:ColorGrading_Topic.png + + 언리얼 엔진에서 용어 **컬러 그레이딩** (Color Grading) 은 *톤 매핑* (HDR to LDR 변형) 및 그에 따른 *색 보정* (LDR color to color 변형) 기능을 포함합니다. (HDR/LDR = High/Low Dynamic Range) diff --git a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/DepthOfField/DepthOfField.INT.udn b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/DepthOfField/DepthOfField.INT.udn index de4ceb206efb..430b8dccbf38 100644 --- a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/DepthOfField/DepthOfField.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/DepthOfField/DepthOfField.INT.udn @@ -1,8 +1,17 @@ -Availability:Public -Title:Depth of Field -Crumbs: %ROOT%, Engine, Engine/Rendering/PostProcessEffects -Description:Simulating focus by blurring the scene depending on depth. -Version: 4.9 +Availability: Public +Crumbs: %ROOT% +Title: Depth of Field +Description: Simulating focus by blurring the scene depending on depth. +Type: Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Rendering/PostProcessEffects +Order:5 +Tags:Post Process +Topic-image:DoF_topic.png + + + [REGION:fullwidth] ![Depth of Field](dof.png) diff --git a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/DepthOfField/DepthOfField.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/DepthOfField/DepthOfField.KOR.udn index 4fd252e363f6..ef7ed875fdd5 100644 --- a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/DepthOfField/DepthOfField.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/DepthOfField/DepthOfField.KOR.udn @@ -1,9 +1,18 @@ -INTSourceChangelist:3108692 -Availability:Public +INTSourceChangelist:3474032 +Availability: Public +Crumbs: %ROOT% Title:뎁스 오브 필드 -Crumbs: %ROOT%, Engine, Engine/Rendering/PostProcessEffects Description:깊이에 따라 씬을 흐리게 만드는 초점 효과 시뮬레이션입니다. -Version: 4.9 +Type: Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Rendering/PostProcessEffects +Order:5 +Tags:Post Process +Topic-image:DoF_topic.png + + + [REGION:fullwidth] ![Depth of Field](dof.png) diff --git a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/LensFlare/LensFlare.INT.udn b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/LensFlare/LensFlare.INT.udn index ff705fa5aeef..7e810bec8712 100644 --- a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/LensFlare/LensFlare.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/LensFlare/LensFlare.INT.udn @@ -1,8 +1,16 @@ -Availability:Public -Title:Lens Flare -Crumbs: %ROOT%, Engine, Engine/Rendering/PostProcessEffects -Description:Simulating scattered light from bright objects due to imperfections in camera lenses. -Version: 4.9 +Availability: Public +Crumbs: %ROOT% +Title: Lens Flare +Description: Simulating scattered light from bright objects due to imperfections in camera lenses. +Type: Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Rendering/PostProcessEffects +Order:6 +Tags:Post Process +Topic-image:LensFlare_Topic.png + + [REGION:fullwidth] ![Lens Flare](lens_flare.png)(w:1182) diff --git a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/LensFlare/LensFlare.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/LensFlare/LensFlare.KOR.udn index 521da430d685..7a034da1651a 100644 --- a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/LensFlare/LensFlare.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/LensFlare/LensFlare.KOR.udn @@ -1,9 +1,17 @@ -INTSourceChangelist:3108692 -Availability:Public +INTSourceChangelist:3474032 +Availability: Public +Crumbs: %ROOT% Title:렌즈 플레어 -Crumbs: %ROOT%, Engine, Engine/Rendering/PostProcessEffects Description:카메라 렌즈 결함으로 인해 밝은 오브젝트에서 빛이 산란되어 보이는 효과의 시뮬레이션 입니다. -Version: 4.9 +Type: Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Rendering/PostProcessEffects +Order:6 +Tags:Post Process +Topic-image:LensFlare_Topic.png + + [REGION:fullwidth] ![Lens Flare](lens_flare.png)(w:1182) diff --git a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/PaniniProjection/PaniniProjection.INT.udn b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/PaniniProjection/PaniniProjection.INT.udn index 5b059d1069e1..e189491a0c68 100644 --- a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/PaniniProjection/PaniniProjection.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/PaniniProjection/PaniniProjection.INT.udn @@ -1,8 +1,14 @@ -Availability:Public -Title:Panini projection -Crumbs: %ROOT%, Engine, Engine/Rendering/PostProcessEffects -Description:3D projection that fixes the perspective projection's geometric distortion on sides of the view having a wide FOV. - +Availability: Public +Crumbs: %ROOT% +Title: Panini Projection +Description: 3D projection that fixes the perspective projection's geometric distortion on sides of the view having a wide FOV. +Type: Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Rendering/PostProcessEffects +Order:7 +Tags:Post Process +Topic-image:PaniniProjection_Topic.png ## Configuration diff --git a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/PaniniProjection/PaniniProjection.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/PaniniProjection/PaniniProjection.KOR.udn index f46514712805..006e3c4d1a47 100644 --- a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/PaniniProjection/PaniniProjection.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/PaniniProjection/PaniniProjection.KOR.udn @@ -1,20 +1,26 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3474032 Availability:Public -Title:파니니 투사 -Crumbs: %ROOT%, Engine, Engine/Rendering/PostProcessEffects -Description:광각 FOV 뷰의 측면에 원근 투사의 지오메트리 왜곡 문제를 해결하는 3D 투사 방식입니다. - +Crumbs: %ROOT% +Title:파니니 투영 +Description:광각 FOV 뷰의 측면에 원근 투영의 지오메트리 왜곡 문제를 해결하는 3D 투영 방식입니다. +Type: Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Rendering/PostProcessEffects +Order:7 +Tags:Post Process +Topic-image:PaniniProjection_Topic.png ## 환경설정 -기본적으로 언리얼 엔진 4 는 원근 투사 방식을 사용합니다. 하지만 이러한 투사 모델은 광각 FOV 에서 작업시 +기본적으로 언리얼 엔진 4 는 원근 투영 방식을 사용합니다. 하지만 이러한 투영 모델은 광각 FOV 에서 작업시 지오메트리 왜곡이 생깁니다. FOV = 120 인 상태로 구체를 보면 다음과 같이 매우 눈에 띕니다. ![](qagame_fov120.png) -그래서 언리얼 엔진은 Panini Projection (파니니 투사)를 사용하여 이 문제 해결을 시도하는 옵션 포스트 프로세싱 패스를 -제공합니다. 이 포스트 프로세싱은, 원근 투사 대신 파니니 투사를 사용해서 렌더링되는 픽셀의 위치를 +그래서 언리얼 엔진은 Panini Projection (파니니 투영)을 사용하여 이 문제 해결을 시도하는 옵션 포스트 프로세싱 패스를 +제공합니다. 이 포스트 프로세싱은, 원근 투영 대신 파니니 투영으로 렌더링되는 픽셀의 위치를 원래 있어야 할 곳으로 변위시킨다는 개념입니다. 그 구성을 위해서는 r.Upscale.Panini.D 를 0 이상으로 설정해 주기만 하면 됩니다. 이 포스트 프로세스 이펙트는 Upscaling 패스에서 이루어집니다. 즉 이 패스는 r.ScreenPercentage != 100 또는 r.Upscale.Panini.D > 0 인 경우 사용된다는 뜻입니다. 이 파라미터를 더욱 자세히 이해하기 위해서는, @@ -30,7 +36,7 @@ r.Upscale.Panini.D > 0 이면 이펙트가 직접 강조됩니다. 하지만 이 ![](qagame_fov120_vertical_compression.png) 이 이펙트 작동방식을 보다 자세히 이해하기 이해서는, r.Upscale.ScreenFit 을 조정해보는 것도 도움이 됩니다. -한 가지 염두에 둘 것은, 끝에 있는 원근 투사 픽셀 중 일부는 화면 상하단 부근에서 +한 가지 염두에 둘 것은, 끝에 있는 원근 투영 픽셀 중 일부는 화면 상하단 부근에서 나타나지 않을 수 있습니다. ![](qagame_actual_effect.png) @@ -38,10 +44,10 @@ r.Upscale.Panini.D > 0 이면 이펙트가 직접 강조됩니다. 하지만 이 ## 직선 -파니니 투사는 선에 대해 여러가지가 보장됩니다. 우선 수직선은 r.Upscale.Panini.D 나 r.Upscale.Panini.S 값이 어떻든 +파니니 투영은 선에 대해 여러가지가 보장됩니다. 우선 수직선은 r.Upscale.Panini.D 나 r.Upscale.Panini.S 값이 어떻든 수직이 보장됩니다. 둘째, 화면 중앙을 가로지르는 선 역시 r.Upscale.Panini.S = 0 이면 r.Upscale.Panini.D 값이 어떻든 수직이 보장됩니다. 이러한 수학적 속성은 일인칭 슈팅 게임에 이상적입니다. -왜냐하면 화면 중앙을 향하는 무기의 파니니 투사는 +왜냐하면 화면 중앙을 향하는 무기의 파니니 투영은 중앙을 향한 직선이 유지될 것이기 때문입니다. ![](shootergame_fov120.png) @@ -51,7 +57,7 @@ r.Upscale.Panini.D > 0 이면 이펙트가 직접 강조됩니다. 하지만 이 ## 중앙 블러링 이 포스트 프로세싱 이펙트의 문제 한 가지는, r.Upscale.Panini.D 상승에 따라 화면 중앙에 -블러링 현상이 나타나기 시작한다는 점입니다. 파니니 투사를 업스케일 패스에 구현한 것도, +블러링 현상이 나타나기 시작한다는 점입니다. 파니니 투영을 업스케일 패스에 구현한 것도, 바로 이 현상에 대비하기 위해 선명화 필터를 적극 활용하기 위해서입니다. 하지만 이러한 문제를 고치기에는 순식간에 역부족이 될 수 있습니다. 그래서 그러한 문제 해결을 돕기 위해 r.ScreenPercentage 를 올려야 할 수도 있지만, 그렇게 되면 그려야 하는 픽셀 수가 @@ -61,9 +67,9 @@ r.ScreenPercentage 를 올려야 할 수도 있지만, 그렇게 되면 그려 ![](shootergame_fov120_panini_screen_percentage.png) -파니니 투사를 사용하는 또 한가지 방법은, 월드 포지션 오프셋을 출력하는 머티리얼 함수를 +파니니 투영을 사용하는 또 한가지 방법은, 월드 포지션 오프셋을 출력하는 머티리얼 함수를 머티리얼의 월드 포지션 오프셋 입력 핀에 연결시키는 방법을 통하는 것입니다. 이는 사실 -언리얼 토너먼트에서 원근 투사 왜곡 문제 해결을 위해 무기를 다른 FOV 로 렌더링하는 방법 +언리얼 토너먼트에서 원근 투영 왜곡 문제 해결을 위해 무기를 다른 FOV 로 렌더링하는 방법 대신 사용하는 것입니다. UT 의 GitHub 리포지터리를 살펴보는 것도 좋을 것입니다. diff --git a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/PostProcessEffects.INT.udn b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/PostProcessEffects.INT.udn index 5e8f1e263da8..63b61241ecb4 100644 --- a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/PostProcessEffects.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/PostProcessEffects.INT.udn @@ -3,10 +3,15 @@ Title: Post Process Effects Crumbs: %ROOT%, Engine Description:Effects applied to the whole rendered scene prior to being rendered. Navigation:topic -Version: 4.9 +Version: 4.15 parent:Engine/Rendering order:5 type:landing +tags:Rendering +Topic-image:ppe_topic.png + + + [VAR:Topic] [OBJECT:Topic] @@ -49,13 +54,31 @@ type:landing [/OBJECT] [/VAR] [REGION:banner] -![Post Process Effects](ppe_landing_banner.png) +![Post Process Effects](ppe_landing_banner1.png) [/REGION] [EXCERPT:Intro] Unreal Engine provides Post Process Effects to allow artists and designers to tweak the overall look and feel of the scene. Examples of elements and effects include bloom (HDR blooming effect on bright objects), ambient occlusion, and tone mapping. [/EXCERPT:Intro] +## Physically-Based Post Process + +As of Unreal Engine 4.15, the filmic tone mapper has been enabled by default matching the standards set by the [Academy Color Encoding System (ACES)](http://www.oscars.org/science-technology/sci-tech-projects/aces). +This enables the tone mapper in UE4 to easily target multiple display types, including High Dynamic Range (HDR) displays. The move to the ACES standard ensures consistent color is preserved across multiple +formats and displays, while also as a way to _future proof_ the source material used without having to adjust it for another medium. + +The filmic tone mapper provides these added benefits: + +* Matches the ACES standard for Television and Film. +* Additional Color Grading and White Balance control. +* Emissive colors bloom in a more physically correct way now. + +[REGION:warning] +The new filmic tone mapper will look different than the tone mapper in previous versions of UE4 for content you may have developed. To use the older tone mapper you can enter the following console command: + r.TonemapperFilm 0 +[/REGION] + + ## Post Process Volume The **PostProcessVolume** is a special type of volume that can be added to a level and, because Unreal Engine 4 does not make use of post processing chains, these volumes are currently the only way to manipulate post processing parameters. The new system is not complete and we will expose some programmability, but we want the common cases to be handled very well by the system. This makes it easier for artists/designers to use the system and for programmers to optimize it. @@ -73,7 +96,7 @@ The properties found in the PostProcessVolume are explained below: | **Blend Radius** | Distance in Unreal units around the volume at which blending with the volume's settings occurs. | **Blend Weight** | The amount of influence the volume's properties have. 0 is no effect; 1 is full effect. | **Enabled** | Whether the volume affects the post processing or not. If _true_, the volume's settings will be used for blending. -| **Unbound** | Whether the bounds of the volume are taken into account. If _true_, the volume affects the entire world, regardless of its bounds. If _false_, the volume only has effect within its bounds. +| **Unbound** | Whether the bounds of the volume are taken into account. If _true_, the volume affects the entire world, regardless of its bounds. If _false_, the volume only has an effect within its bounds. ### Post Process Settings @@ -84,6 +107,11 @@ For descriptions of each of the available settings, see the page for the corresp ## Effects +[DIR(output:"topiccompact" parent:"Engine/Rendering/PostProcessEffects" org:"hierarchy" tags:"Post Process" end:"1")] + + + diff --git a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/PostProcessEffects.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/PostProcessEffects.JPN.udn index 0032456c59a9..a3878d7f2a99 100644 --- a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/PostProcessEffects.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/PostProcessEffects.JPN.udn @@ -1,13 +1,17 @@ -INTSourceChangelist:3151855 +INTSourceChangelist:3471588 Availability:Public Title:ポストプロセス エフェクト Crumbs: %ROOT%, Engine -Description:レンダリングの前にレンダリングシーン全体に適用するエフェクト +Description:レンダリングする前にレンダリング シーン全体に適用するエフェクト Navigation:topic -Version:4.9 +Version:4.15 parent:Engine/Rendering order:5 type:landing +tags:Rendering + + + [VAR:Topic] [OBJECT:Topic] @@ -50,36 +54,54 @@ type:landing [/OBJECT] [/VAR] [REGION:banner] -![Post Process Effects](ppe_landing_banner.png) +![Post Process Effects](ppe_landing_banner1.png) [/REGION] [EXCERPT:Intro] -アンリアル・エンジンが提供するいくつかのポストプロセスのエフェクトにより、アーティストやデザイナーは、全体的な見た目やシーンの雰囲気の細かいチューニングが可能となります。ブルーム (明るいオブジェクトに対する HDR ブルーム エフェクト) 、アンビエントオクルージョン、トーンマッピングなどが、エレメントやエフェクトの例です。 +アンリアル・エンジンは、アーティストやデザイナーは、全体的な見た目やシーンの雰囲気の細かいチューニングを可能にするポストプロセス エフェクトが提供されています。ブルーム (明るいオブジェクトに対する HDR ブルーム エフェクト)、アンビエントオクルージョン、トーンマッピングなどが、エレメントやエフェクトの例です。 [/EXCERPT:Intro] +## 物理ベース ポストプロセス + +バージョン 4.15 では、[Academy Color Encoding System (ACES)](http://www.oscars.org/science-technology/sci-tech-projects/aces) による標準設定に合わせて映画的なトーン マッパがデフォルトで有効になっています。 +これにより、UE4 でトーン マッパを有効にして、High Dynamic Range (HDR) を始めとする複数の表示タイプを簡単にターゲットにすることができます。ACES に合わせることで、複数の形式および表示で色の整合性が保たれます。 +他の媒体用に色を調節せずに使用されたソース マテリアルが _古くならない_ ようにする手段でもあります。 + +映画的なトーン マッパには以下のような長所があります。 + +* テレビ / 映画用の ACES に一致 +* さらに多くのカラーグレーディングとホワイト バランス +* 物理的により正しい方法でのエミッシブ カラー ブルーム + +[REGION:warning] +新しい映画的なトーン マッパは、古いバージョンの UE4 で開発したコンテンツのトーン マッパとは異なって見えます。古いトーン マッパを使用するには、以下のコンソール コマンドを入力してください。 + r.TonemapperFilm 0 +[/REGION] + + ## Post Process Volume **PostProcessVolume** は、レベルへの追加が可能な特別なタイプのボリュームです。アンリアル・エンジン 4 はポストプロセスのチェーンを使用しないため、現時点ではこのボリュームがポストプロセスのパラメータをコントロールする唯一の方法です。新しいシステムはまだ完全ではなく、プログラムが可能であることを紹介していきますが、システムが共通のケースを確実に処理するようにしたいと考えています。システムの使用によりアーティストおよびデザイナーが抱える負担を軽減し、プログラマーはシステムを最大限に活かすことができます。 -アンリアル・エンジン 4 では、それぞれの PostProcessVolume が本質的に唯一のブレンドレイヤータイプです。その他のブレンドレイヤーは、ゲームコード (例、ヒット エフェクト) 、UI コード (例、一時停止メニュー) 、カメラ (例、vignette) 、またはマチネ (昔の映画のようなエフェクト) からもたらされます。エフェクトのブレンドを容易にするために、各レイヤーに重さを設定することができます。 +アンリアル・エンジン 4 では、それぞれの PostProcessVolume が本質的に唯一のブレンドレイヤータイプです。その他のブレンドレイヤーは、ゲームコード (例、ヒット エフェクト)、UI コード (例、一時停止メニュー)、カメラ (例、vignette)、またはマチネ (昔の映画のようなエフェクト) からもたらされます。エフェクトをブレンドを容易にするために、各レイヤーに重さを設定することができます。 -ブレンドは常に lerp (線形補間) で行い、有効なボリュームのみがブレンドされます。PostProcessVolume は、 **Unbound** プロパティがチェックされていない限り、カメラがボリューム範囲内にあるときのみ適用されます。 +ブレンドは常に lerp (線形補間) で行い、有効なボリュームのみがブレンドされます。PostProcessVolume は、**Unbound** プロパティがチェックされていない限り、カメラがボリューム範囲内にあるときのみ適用されます。 以下は PostProcessVolume に存在するプロパティです。 | プロパティ | 説明 | | -------- | ----------- | | **Settings** | ボリュームの [ポストプロセス設定](#ポストプロセス設定) です。ほとんどのプロパティの前にあるチェックボックスは、ボリュームのラインがボリュームの **Blend Weight** を使用してブレンドする条件を定義します。 -| **Priority** | 複数のボリュームをブレンドする順序を定義します。最優先度のボリュームがオーバーラップする、全てのボリュームに対して優先します。 +| **Priority** | 複数のボリュームをブレンドする順序を定義します。最優先度のボリュームがオーバーラップする、すべてのボリュームに対して優先します。 | **Blend Radius** | ボリューム周りの距離をアンリアル単位で表したものです。ボリュームの設定に基づいたブレンドが実行されます。 -| **Blend Weight** | ボリュームのプロパティが持つ影響力です。0 はエフェクトなし、 1 は最大のエフェクトを意味します。 +| **Blend Weight** | ボリュームのプロパティが持つ影響力です。0 はエフェクトなし、1 は最大のエフェクトを意味します。 | **Enabled** | ボリュームがポストプロセスに与える影響の有無です。_true_ の場合、ボリュームの設定がブレンドに使用されます。 | **Unbound** | ボリューム範囲が考慮されているかを表します。_true_ の場合、ボリュームは範囲に関係なくワールド全体に作用します。_false_ の場合、ボリュームは範囲内のみに作用します。 ### ポストプロセス設定 -ポストプロセス設定は、制御またはオーバーライドするさまざまなポストプロセス エフェクトの全プロパティです。これらのプロパティは UScene クラスで宣言します。**PostProcessVolume** は、 Settings プロパティに `FPostProcessSettings` の構造体を格納しています。このプロパティには全プロパティが格納され、ボリュームによってオーバーライドされます。 +ポストプロセス設定は、各種ポストプロセス エフェクトを制御またはオーバーライドするすべてのプロパティです。これらのプロパティは UScene クラスで宣言します。**PostProcessVolume** は、Settings プロパティに `FPostProcessSettings` の構造体を格納しています。このプロパティにすべてのプロパティが格納され、ボリュームによってオーバーライドされます。 有効設定のそれぞれの説明は、以下のエフェクトの対応ページを参照してください。 diff --git a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/PostProcessEffects.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/PostProcessEffects.KOR.udn index 4e5629e09815..3a5839e6fee1 100644 --- a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/PostProcessEffects.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/PostProcessEffects.KOR.udn @@ -1,13 +1,18 @@ -INTSourceChangelist:3151855 +INTSourceChangelist:3474032 Availability:Public Title: 포스트 프로세스 이펙트 Crumbs: %ROOT%, Engine Description:렌더링 직전의 전체 씬에 적용되는 이펙트입니다. Navigation:topic -Version: 4.9 +Version: 4.15 parent:Engine/Rendering order:5 type:landing +tags:Rendering +Topic-image:ppe_topic.png + + + [VAR:Topic] [OBJECT:Topic] @@ -50,13 +55,31 @@ type:landing [/OBJECT] [/VAR] [REGION:banner] -![Post Process Effects](ppe_landing_banner.png) +![Post Process Effects](ppe_landing_banner1.png) [/REGION] [EXCERPT:Intro] 언리얼 엔진은 아티스트나 디자이너가 씬의 전체적인 모양새와 느낌을 조정할 수 있도록 여러가지 포스트 프로세스를 제공하고 있습니다. 요소와 이펙트의 예제에는 블룸 (밝은 오브젝트의 HDR 뽀샤시 효과), 앰비언트 오클루전 (구석의 실감나는 음영), 톤 매핑 등이 있습니다. [/EXCERPT:Intro] +## 물리 기반 포스트 프로세스 + +언리얼 엔진 4.15 부로, [Academy Color Encoding System (ACES)](http://www.oscars.org/science-technology/sci-tech-projects/aces) 에서 설정한 표준에 맞추기 위해 필름 톤 매퍼가 기본 활성화되었습니다. +이로써 UE4 톤 매퍼는 하이 다이내믹 레인지(HDR) 디스플레이를 포함한 여러 디스플레이 유형을 쉽게 타겟으로 삼을 수 있게 되었습니다. ACES 표준으로의 전환은 여러 포맷이나 디스플레이에서도 일관된 색을 얻을 수 있을 뿐 아니라, +소스 머티리얼을 별다른 조정 없이 다른 매체에서도 사용할 수 있도록 해주는 미래 대비 역할을 하기도 합니다. + +그 외에도 필름 톤 매퍼의 장점은 다음과 같습니다: + +* 텔레비전 및 영화용 ACES 표준과 일치합니다. +* 추가적인 컬러 그레이딩 및 화이트 밸런스 컨트롤이 가능합니다. +* 이미시브 컬러 블룸이 보다 물리적으로 바른 방식으로 이루어집니다. + +[REGION:warning] +새로운 필름 톤 매퍼는 기존에 개발한 콘텐츠의 경우 UE4 기존 버전에서와 달라보일 것입니다. 예전 톤 매퍼를 사용하는 콘솔 명령은 다음과 같습니다: + r.TonemapperFilm 0 +[/REGION] + + ## 포스트 프로세스 볼륨 **PostProcessVolume** 은 레벨에 추가할 수 있는 특수한 종류의 볼륨으로, 언리얼 엔진 4 에서는 포스트 프로세싱 체인을 활용하지 않기 때문에, 포스트프로세싱 파라미터를 조작할 수 있는 유일한 방법은 현재 이 볼륨 뿐입니다. 새로운 시스템은 아직 완성 단계가 아니라 프로그래밍 여지를 남겨두고는 있지만, 일반적인 상황에서는 시스템을 통해 원활히 처리되도록 하려 하고 있습니다. 아티스트와 디자이너가 더욱 쉽게 사용하도록, 프로그래머가 더욱 잘 최적화하도록 하는 것입니다. @@ -85,6 +108,11 @@ PostProcessVolume 안에서 찾을 수 있는 프로퍼티에 대한 설명입 ## 이펙트 +[DIR(output:"topiccompact" parent:"Engine/Rendering/PostProcessEffects" org:"hierarchy" tags:"Post Process" end:"1")] + + + diff --git a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/PostProcessMaterials/PostProcessMaterials.INT.udn b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/PostProcessMaterials/PostProcessMaterials.INT.udn index c7657f77bc21..244bff349e35 100644 --- a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/PostProcessMaterials/PostProcessMaterials.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/PostProcessMaterials/PostProcessMaterials.INT.udn @@ -1,8 +1,15 @@ -Availability:Public -Title:Post Process Materials -Crumbs: %ROOT%, Engine, Engine/Rendering/PostProcessEffects -Description:How to author and blend custom Post Process passes with the material editor. -Version: 4.9 +Availability: Public +Crumbs: %ROOT% +Title: Post Process Materials +Description: How to author and blend custom Post Process passes with the material editor. +Type: Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Rendering/PostProcessEffects +Order:8 +Tags:Post Process +Topic-image:PPMaterials_Topic.png + ![](Teaser3.png) ![](Teaser0.png) diff --git a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/PostProcessMaterials/PostProcessMaterials.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/PostProcessMaterials/PostProcessMaterials.KOR.udn index 082cf85b06b0..d1e9d304abca 100644 --- a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/PostProcessMaterials/PostProcessMaterials.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/PostProcessMaterials/PostProcessMaterials.KOR.udn @@ -1,9 +1,16 @@ -INTSourceChangelist:3151927 -Availability:Public +INTSourceChangelist:3474032 +Availability: Public +Crumbs: %ROOT% Title:포스트 프로세스 머티리얼 -Crumbs: %ROOT%, Engine, Engine/Rendering/PostProcessEffects Description:포스트 프로세스 패스를 만들어 머티리얼 에디터에 블렌딩하는 법입니다. -Version: 4.9 +Type: Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Rendering/PostProcessEffects +Order:8 +Tags:Post Process +Topic-image:PPMaterials_Topic.png + ![](Teaser3.png) ![](Teaser0.png) @@ -169,7 +176,7 @@ Version: 4.9 GBuffer 는 (서브서피스/스페큘러 컬러, 러프니스 등의) 머티리얼과 (노멀, 뎁스 등의) 오브젝트 특성을 저장하는 텍스처 다수로 구성되어 있습니다. 셰이딩 (빛과 머티리얼의 상호작용) 계산을 위한 라이팅 없이요. 디퍼드 렌더러에서는 먼저 GBuffer 를 렌더링한 다음 모든 라이팅을 GBuffer 특성과 함께 (deffered, -나중에 몰아서) 계산합니다. UE4 가 (DirectX 11 또는 고사양 OpenGL) 디퍼드 셰이딩 패쓰를 사용한다면 포스트 프로세싱 도중 해당 버퍼들에 접근할 수 있습니다. +나중에 몰아서) 계산합니다. UE4 가 (DirectX 11 또는 고사양 OpenGL) 디퍼드 셰이딩 패스를 사용한다면 포스트 프로세싱 도중 해당 버퍼들에 접근할 수 있습니다. 안티-앨리어싱의 경우 이 작업이 약간 더 어려워 지는데, GBuffer 픽셀/텍셀과 출력 픽셀이 더이상 1:1 상관 관계에 있지 않기 때문입니다 (아래 섹션 참고). diff --git a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/SceneFringe/SceneFringe.INT.udn b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/SceneFringe/SceneFringe.INT.udn index 99ccb10a8ef0..60eb20e01758 100644 --- a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/SceneFringe/SceneFringe.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/SceneFringe/SceneFringe.INT.udn @@ -1,8 +1,15 @@ -Availability:Public -Title:Scene Fringe -Crumbs: %ROOT%, Engine, Engine/Rendering/PostProcessEffects -Description:Chromatic aberration effect that simulates the color shifts near the edges of real-world camera lenses. -Version: 4.9 +Availability: Public +Crumbs: %ROOT% +Title: Scene Fringe (Chromatic Aberration) +Description: Chromatic aberration effect that simulates the color shifts near the edges of real-world camera lenses. +Type: Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Rendering/PostProcessEffects +Order:9 +Tags:Post Process +Topic-image:SceneFringe_topic.png + [EXCERPT:SceneFringe_Desc] diff --git a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/SceneFringe/SceneFringe.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/SceneFringe/SceneFringe.KOR.udn index 5ce103d822c2..c51904aaea85 100644 --- a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/SceneFringe/SceneFringe.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/SceneFringe/SceneFringe.KOR.udn @@ -1,9 +1,16 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3474032 Availability:Public +Crumbs: %ROOT% Title:씬 프린지 (Scene Fringe) -Crumbs: %ROOT%, Engine, Engine/Rendering/PostProcessEffects Description:실제 카메라 렌즈의 가장자리 부근에서 색이 전환되는 것을 시뮬레이션하는 색수차 효과입니다. -Version: 4.9 +Type: Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Rendering/PostProcessEffects +Order:9 +Tags:Post Process +Topic-image:SceneFringe_topic.png + [EXCERPT:SceneFringe_Desc] diff --git a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/ScreenSpaceReflection/ScreenSpaceReflection.INT.udn b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/ScreenSpaceReflection/ScreenSpaceReflection.INT.udn index 02e8299560f3..415ed78213cb 100644 --- a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/ScreenSpaceReflection/ScreenSpaceReflection.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/ScreenSpaceReflection/ScreenSpaceReflection.INT.udn @@ -1,8 +1,15 @@ -Availability:Public -Title:Screen Space Reflection -Crumbs: %ROOT%, Engine, Engine/Rendering/PostProcessEffects -Description:Effect which alters the reflection that appear on the surface of materials. -Version: 4.9 +Availability: Public +Crumbs: %ROOT% +Title: Screen Space Reflections +Description: Effect which alters the reflection that appear on the surface of materials within scene view. +Type: Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Rendering/PostProcessEffects +Order:10 +Tags:Post Process +Topic-image:SSR_topic.png + [REGION:fullwidth] ![](GlossyScreenSpaceReflection.png) diff --git a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/ScreenSpaceReflection/ScreenSpaceReflection.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/ScreenSpaceReflection/ScreenSpaceReflection.KOR.udn index 07523d8132b1..db97d0691a8d 100644 --- a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/ScreenSpaceReflection/ScreenSpaceReflection.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/ScreenSpaceReflection/ScreenSpaceReflection.KOR.udn @@ -1,9 +1,16 @@ -INTSourceChangelist:3108692 -Availability:Public +INTSourceChangelist:3474032 +Availability: Public +Crumbs: %ROOT% Title:스크린 스페이스 리플렉션 -Crumbs: %ROOT%, Engine, Engine/Rendering/PostProcessEffects -Description:머티리얼 표면에 나타나는 리플렉션을 변경하는 이펙트입니다. -Version: 4.9 +Description:씬 뷰 안에서 머티리얼 표면에 나타나는 리플렉션을 변경하는 이펙트입니다. +Type: Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Rendering/PostProcessEffects +Order:10 +Tags:Post Process +Topic-image:SSR_topic.png + [REGION:fullwidth] ![](GlossyScreenSpaceReflection.png) diff --git a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/Vignette/Vignette.INT.udn b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/Vignette/Vignette.INT.udn index 90ec6f889aef..6cc3598bf4ec 100644 --- a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/Vignette/Vignette.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/Vignette/Vignette.INT.udn @@ -1,8 +1,16 @@ -Availability:Public -Title:Vignette -Crumbs: %ROOT%, Engine, Engine/Rendering/PostProcessEffects -Description:Effect causing the brightness of the to decrease as the distance from the viewport's center increases. -Version: 4.9 +Availability: Public +Crumbs: %ROOT% +Title: Vignette +Description: Effect causing the brightness of the to decrease as the distance from the viewport's center increases. +Type: Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Rendering/PostProcessEffects +Order:11 +Tags:Post Process +Topic-image:Vignette_topic.png + + [REGION:fullwidth] ![Vignette Effect](vignette.png) diff --git a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/Vignette/Vignette.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/Vignette/Vignette.KOR.udn index e59fd55b2087..483e06f598b7 100644 --- a/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/Vignette/Vignette.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/PostProcessEffects/Vignette/Vignette.KOR.udn @@ -1,9 +1,17 @@ -INTSourceChangelist:3200686 -Availability:Public -Title:비녜트 (Vignette) -Crumbs: %ROOT%, Engine, Engine/Rendering/PostProcessEffects -Description:뷰포트 중심에서부터의 거리가 멀어져감에 따라 밝기를 감소시키는 이펙트입니다. -Version: 4.9 +Availability: Public +Availability: Public +Crumbs: %ROOT% +Title: 비녜트 (Vignette) +Description: 뷰포트 중심에서부터의 거리가 멀어져감에 따라 밝기를 감소시키는 이펙트입니다. +Type: Overview +SkillLevel:Beginner +Version:4.16 +Parent:Engine/Rendering/PostProcessEffects +Order:11 +Tags:Post Process +Topic-image:Vignette_topic.png + + [REGION:fullwidth] ![Vignette Effect](vignette.png) diff --git a/Engine/Documentation/Source/Engine/Rendering/RenderTargets/BlueprintRenderTargets/HowTo/HeightFieldPainter/3/HFP3.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/RenderTargets/BlueprintRenderTargets/HowTo/HeightFieldPainter/3/HFP3.JPN.udn index 41f70175dd9f..53e24f7e0ea5 100644 --- a/Engine/Documentation/Source/Engine/Rendering/RenderTargets/BlueprintRenderTargets/HowTo/HeightFieldPainter/3/HFP3.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/RenderTargets/BlueprintRenderTargets/HowTo/HeightFieldPainter/3/HFP3.JPN.udn @@ -1,5 +1,5 @@ -INTSourceChangeList:3216146 -availability:docs +INTSourceChangeList:3259022 +availability:Public title:3.ブループリントの設定 description:Height Map Painter ブループリントの作成と設定方法の説明 crumbs:%ROOT%, Engine, Engine\Rendering\RenderTargets diff --git a/Engine/Documentation/Source/Engine/Rendering/RenderTargets/RenderTargets.INT.udn b/Engine/Documentation/Source/Engine/Rendering/RenderTargets/RenderTargets.INT.udn index c9e458f8dcc5..be40a798bff0 100644 --- a/Engine/Documentation/Source/Engine/Rendering/RenderTargets/RenderTargets.INT.udn +++ b/Engine/Documentation/Source/Engine/Rendering/RenderTargets/RenderTargets.INT.udn @@ -8,6 +8,7 @@ parent:Engine/Rendering order:7 Navigation:topic tags: Render Targets +topic-image:RenderTargets_topic.png ![](BlueprintRenderTarget.png) diff --git a/Engine/Documentation/Source/Engine/Rendering/RenderTargets/RenderTargets.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/RenderTargets/RenderTargets.JPN.udn index a5b88a4c1e02..a105db2ed399 100644 --- a/Engine/Documentation/Source/Engine/Rendering/RenderTargets/RenderTargets.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/RenderTargets/RenderTargets.JPN.udn @@ -1,6 +1,6 @@ -INTSourceChangelist:3264165 +INTSourceChangelist:3467293 availability:Public -title:Render Targets +title:レンダー ターゲット description:アンリアル エンジン 4 でのレンダー ターゲットの使用方法 crumbs:%ROOT%, Engine, Engine/Rendering version:4.13 @@ -9,6 +9,7 @@ parent:Engine/Rendering order:7 Navigation:topic tags:Render Targets +topic-image:RenderTargets_topic.png ![](BlueprintRenderTarget.png) diff --git a/Engine/Documentation/Source/Engine/Rendering/RenderTargets/RenderTargets.KOR.udn b/Engine/Documentation/Source/Engine/Rendering/RenderTargets/RenderTargets.KOR.udn index 4c9d7bb3f3b3..6f3419c97f04 100644 --- a/Engine/Documentation/Source/Engine/Rendering/RenderTargets/RenderTargets.KOR.udn +++ b/Engine/Documentation/Source/Engine/Rendering/RenderTargets/RenderTargets.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3264165 +INTSourceChangelist:3467293 availability:Public title: 렌더 타겟 description:언리얼 엔진 4 에서 렌더 타겟 사용하는 법입니다. @@ -9,6 +9,7 @@ parent:Engine/Rendering order:7 Navigation:topic tags: Render Targets +topic-image:RenderTargets_topic.png ![](BlueprintRenderTarget.png) diff --git a/Engine/Documentation/Source/Engine/Rendering/SceneCapture/SceneCaptureMobile/SceneCaptureMobile.JPN.udn b/Engine/Documentation/Source/Engine/Rendering/SceneCapture/SceneCaptureMobile/SceneCaptureMobile.JPN.udn index fbd4dd26e9de..5dc5be76c0a8 100644 --- a/Engine/Documentation/Source/Engine/Rendering/SceneCapture/SceneCaptureMobile/SceneCaptureMobile.JPN.udn +++ b/Engine/Documentation/Source/Engine/Rendering/SceneCapture/SceneCaptureMobile/SceneCaptureMobile.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3348720 +INTSourceChangelist:3350143 availability:Docs title:モバイル用 Scene Capture アクタ description:Scene Captures アクタをモバイル デバイスで使用する際の注意点 @@ -12,6 +12,20 @@ Navigation:topic topic-image:Scene_Capture_Mobile.png related:Resources/ContentExamples/Reflections/1_6 related:Resources/ContentExamples/Reflections/1_7 +tags:mobile +tags:rendering +tags:Daydream +tags:iOS +tags:Android +tags:User Interface +tags:UMG UI Designer +tags:Materials +prereq:Gameplay/HowTo/UsingCameras +prereq:Engine/Rendering/RenderTargets +prereq:Engine/UMG + + + モバイル デバイス向けプロジェクトで Scene Capture アクタを使用する場合、以下の点に注意して、モバイル デバイス上で Scene Capture アクタが最善のパフォーマンスで使用できることを確認してください。 diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/ActorSequence/ActorSequence.CHN.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/ActorSequence/ActorSequence.CHN.udn new file mode 100644 index 000000000000..29c5c7c3667f --- /dev/null +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/ActorSequence/ActorSequence.CHN.udn @@ -0,0 +1,208 @@ +INTSourceChangelist:0 +Availability: Public +Title:Using Embedded Sequencer Animations in Blueprints +Crumbs: %ROOT%, Engine, Engine/Sequencer, Engine/Sequencer/HowTo +Description:Describes how you can embed Sequences within Actor Blueprints using an Actor Sequence Component. +Version: 4.15 +SkillLevel: Advanced +parent:Engine/Sequencer/HowTo +order:1 +checkpoint: editorqs +Related: Engine/Sequencer/Overview +Related: Engine/Sequencer/ReferenceEditor +Related: Engine/Blueprints +tags:Sequencer +type:how-to + +[REGION:warning] +This is an experimental feature that is currently undergoing development. Some aspects may not work as expected or may change in future revisions. +[/REGION] + +When working with and creating [Sequences](Engine/Sequencer/Overview), there may be situations where you want to reuse the functionality of a Sequence in other places or instances. +With the **Actor Sequence Plugin** and **Actor Sequence Component**, it is possible to embed Sequences directly into an Actor [Blueprint](Engine/Blueprints). +This enables reuse of Sequences by binding the animations to the Blueprint instance and triggering them automatically or through the **Event Graph** of the Blueprint. +Additionally, you can add an Actor Sequence Component to any Actor in the world to add animations to a single instance of an Actor. + +In this how-to guide, you'll create a Blueprint with an embedded Sequence that animates and changes the color of a Spot Light over time. + +![](EndResult.png) + +The Blueprint can then be placed in any level or duplicated and the embedded Sequence will play automatically when called. + +## Steps + +[REGION:note] +For this how-to guide, we are using the **Blueprint Third Person Template** with **Starter Content** enabled. +[/REGION] + +1. With your project open, from the **Edit** menu select **Plugins**. + + ![](ActorSequence01.png) + +1. From the **Plugins** menu, under **Built-in**, enable the **Actor Sequence Editor** option and restart the editor when prompted. + + ![](ActorSequence02.png) + +1. Create a new **Blueprint** of the **Actor** type can call it **Light_BP**. + + ![](ActorSequence03.png) + +1. Inside the **Light_BP**, click **Add Component** and add a **Spot Light**. + + ![](ActorSequence04.png) + +1. In the **Details** panel for the **Spot Light**, change the **Rotation** value for **Y** to **-60**. + + ![](ActorSequence05.png) + + This will rotate and angle the light slightly downward in the viewport. + +1. Add another **Component** of the **Static Mesh** type, then in the **Details** panel set the mesh to **Floor_400x400** with its **Location** set to **-180x-180x-100**. + + ![](ActorSequence06.png) + + We will use this mesh as a temporary way to see the effects of our Sequence a little later in the guide and will delete it once we are done. + +1. Add another **Component** of the **Actor Sequence** type. + + ![](ActorSequence07.png) + +1. In the **Details** panel for the **Actor Sequence**, set **Loop Indefinitely**, **Random Start Time** and **Auto Play**, then click **Open in Tab**. + + ![](ActorSequence08.png) + + For this example we will automatically trigger and play the Sequence, however, you can also call this to play from the **Event Graph**. + +1. In the **Sequencer** tab, click **Add** then under **Component** select **SpotLight**. + + ![](ActorSequence09.png) + +1. On the **SpotLight** track, click the **Track** button and select **Transform**. + + ![](ActorSequence10.png) + +1. Click the **Track** button again for the **SpotLight** track and add the **Light Color** track. + + ![](ActorSequence11.png) + +1. For the **Transform** track under **Rotation**, click the **+** icon for the **Z** value to add a key of **0** at frame **0**. + + ![](ActorSequence12.png) + +1. Select the key that was added, then press the **4** key to change the interpolation type to **Linear**. + + ![](ActorSequence13.png) + + You can change the type of interpolation with the number keys or by **Right-clicking** on the keyframe and selecting your interpolation method. + +1. Add a key at **2.00** for the **Z** value of **Rotation** set to **-180.0** and change the interpolation to **Linear** by pressing **4** on the key. + + ![](ActorSequence14.png) + +1. Add a key at **4.00** for the **Z** value of **Rotation** set to **-360.0** and change the interpolation to **Linear** by pressing **4** on the key. + + ![](ActorSequence15.png) + + You can also move the red **End Marker** back to **4.00** so the Sequence ends where it began. + +1. For the **Light Color** track, click the **+** button to add a key at frame **0**. + + ![](ActorSequence16.png) + +1. Add a key at **1.00** for **Red** with a value of **0.0**. + + ![](ActorSequence17.png) + +1. Add a key at **2.00** for **Green** with a value of **0.0**. + + ![](ActorSequence18.png) + +1. Add keys at **3.00** for **Blue** with a value of **0.0**, and both **Red** and **Green** at **1.0**. + + ![](ActorSequence19.png) + +1. Add a key at **4.00** for **Blue** with a value of **1.0**. + + ![](ActorSequence20.png) + + This will cause the light to go from white to various colors before returning back to white at the end of the Sequence. + +1. In the **Components** window, select and **Delete* the **StaticMesh** floor. + + ![](ActorSequence21.png) + + Now that our light is set up, we no longer need this mesh as a way to preview the light in the viewport. + +1. In the Main Level Editor Viewport, select the floor, then while holding **Alt** drag up a copy of the floor to create a roof encapsulating the level. + + ![](ActorSequence22.png) + +1. From the **Content Browser**, drag and place instances of the **Light_BP** in the level (you can also press **E** and rotate them if desired). + + ![](ActorSequence23.png) + +1. From the **Build** drop-down menu, select **Build Lighting Only** to rebuild the lighting in the level. + + ![](ActorSequence24.png) + +1. Click the **Play** button to play in the editor. + +## End Result + +When you play in the level, you will see that the lights you placed start rotating and changing colors playing the embedded Sequence. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + bohLiPXTyMs + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +Since the Sequence is embedded withing the Actor Blueprint, it has no dependencies and can play in any level or can be duplicated without any issues. + +In our example we've set the Sequence to **Auto Play**, however, you can also use the **Event Graph** to script when the Sequence should Play. + +![](EventGraphPlayScript.png) + +Above, upon **Event BeginPlay** we have allowed the Actor to receive input from a **Player Controller**. +When the **P** key is pressed, we take the **Actor Sequence Component** and get the **Sequence Player** which allows us to make a call to the function **Play** to start playing the Sequence. +You can use any method you desire to make the call to the Play function if you prefer not to have the Sequence Auto Play upon level load. + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/ActorSequence/ActorSequence.INT.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/ActorSequence/ActorSequence.INT.udn new file mode 100644 index 000000000000..9f3b2a5d7169 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/ActorSequence/ActorSequence.INT.udn @@ -0,0 +1,217 @@ +Availability: Docs +Crumbs: %ROOT%, Engine, Engine/Sequencer, Engine/Sequencer/HowTo +Title:Using Embedded Sequencer Animations in Blueprints +Description:Describes how you can embed Sequences within Actor Blueprints using an Actor Sequence Component. +Type: how-to +SkillLevel: Advanced +Version: 4.16 +parent:Engine/Sequencer/HowTo +order:1 +tags:Sequencer +topic-image:ActorSequenceTopicCompact.png +Related: Engine/Sequencer/Overview +Related: Engine/Sequencer/ReferenceEditor +Related: Engine/Blueprints + + +[REGION:warning] +This is an experimental feature that is currently undergoing development. Some aspects may not work as expected or may change in future revisions. +[/REGION] + +When working with and creating [Sequences](Engine/Sequencer/Overview), there may be situations where you want to reuse the functionality of a Sequence in other places or instances. +With the **Actor Sequence Plugin** and **Actor Sequence Component**, it is possible to embed Sequences directly into an Actor [Blueprint](Engine/Blueprints). +This enables reuse of Sequences by binding the animations to the Blueprint instance and triggering them automatically or through the **Event Graph** of the Blueprint. +Additionally, you can add an Actor Sequence Component to any Actor in the world to add animations to a single instance of an Actor. + +In this how-to guide, you'll create a Blueprint with an embedded Sequence that animates and changes the color of a Spot Light over time. + +![](EndResult.png) + +The Blueprint can then be placed in any level or duplicated and the embedded Sequence will play automatically when called. + +## Steps + +[REGION:note] +For this how-to guide, we are using the **Blueprint Third Person Template** with **Starter Content** enabled. +[/REGION] + +1. With your project open, from the **Edit** menu select **Plugins**. + + ![](ActorSequence01.png) + +1. From the **Plugins** menu, under **Built-in**, enable the **Actor Sequence Editor** option and restart the editor when prompted. + + ![](ActorSequence02.png) + + [REGION:note] + You may see the **Experimental** confirmation dialog window when enabling the Actor Sequence Editor, click **Yes** to proceed. + [/REGION] + +1. Create a new **Blueprint** of the **Actor** type can call it **Light_BP**. + + ![](ActorSequence03.png) + +1. Inside the **Light_BP**, click **Add Component** and add a **Spot Light**. + + ![](ActorSequence04.png) + +1. In the **Details** panel for the **Spot Light**, change the **Rotation** value for **Y** to **-60**. + + ![](ActorSequence05.png) + + This will rotate and angle the light slightly downward in the viewport. + +1. Add another **Component** of the **Static Mesh** type, then in the **Details** panel set the mesh to **Floor_400x400** with its **Location** set to **-180 (X), -180 (Y), -100 (Z)**. + + ![](ActorSequence06.png) + + We will use this Floor Mesh to shine our Lights on and to see the effects of Sequencer driving the parameter changes. + +1. Add another **Component** of the **Actor Sequence** type. + + ![](ActorSequence07.png) + +1. In the **Details** panel for the **Actor Sequence**, set **Loop Indefinitely**, **Random Start Time** and **Auto Play**, then click **Open in Tab**. + + ![](ActorSequence08.png) + + After clicking **Open in Tab**, the **Sequencer Editor** will open within the Blueprint. + + ![](SequencerWindow.png) + + For this example we will automatically trigger and play the Sequence, however, you can also call this to play from the **Event Graph**. + +1. In the **Sequencer** tab, click **Add** then under **Component** select **SpotLight**. + + ![](ActorSequence09.png) + +1. On the **SpotLight** track, click the **Track** button and select **Transform**. + + ![](ActorSequence10.png) + +1. Click the **Track** button again for the **SpotLight** track and add the **Light Color** track. + + ![](ActorSequence11.png) + +1. For the **Transform** track under **Rotation**, click the **+** icon for the **Z** value to add a key of **0** at frame **0**. + + ![](ActorSequence12.png) + +1. Select the key that was added, then press the **4** key to change the interpolation type to **Linear**. + + ![](ActorSequence13.png) + + You can change the type of interpolation with the number keys or by right-clicking on the keyframe and selecting your interpolation method. + +1. Add a key at **2.00** for the **Z** value of **Rotation** set to **-180.0** and change the interpolation to **Linear** by pressing **4** on the key. + + ![](ActorSequence14.png) + +1. Add a key at **4.00** for the **Z** value of **Rotation** set to **-360.0** and change the interpolation to **Linear** by pressing **4** on the key. + + ![](ActorSequence15.png) + + You can also move the red **End Marker** back to **4.00** so the Sequence ends where it began. + +1. For the **Light Color** track, click the **+** button to add a key at frame **0**. + + ![](ActorSequence16.png) + +1. Add a key at **1.00** for **Red** with a value of **0.0**. + + ![](ActorSequence17.png) + +1. Add a key at **2.00** for **Green** with a value of **0.0**. + + ![](ActorSequence18.png) + +1. Add keys at **3.00** for **Blue** with a value of **0.0**, and both **Red** and **Green** at **1.0**. + + ![](ActorSequence19.png) + +1. Add a key at **4.00** for **Blue** with a value of **1.0**. + + ![](ActorSequence20.png) + + This will cause the light to go from white to various colors before returning back to white at the end of the Sequence. + +1. In the **Components** window, select and **Delete** the **StaticMesh** floor. + + ![](ActorSequence21.png) + + Now that our light is set up, we no longer need this mesh as a way to preview the light in the viewport. + +1. In the Main Level Editor Viewport, select the floor, then while holding **Alt** drag up a copy of the floor to create a roof encapsulating the level. + + ![](ActorSequence22.png) + +1. From the **Content Browser**, drag and place instances of the **Light_BP** in the level (you can also press **E** and rotate them if desired). + + ![](ActorSequence23.png) + +1. From the **Build** drop-down menu, select **Build Lighting Only** to rebuild the lighting in the level. + + ![](ActorSequence24.png) + +1. Click the **Play** button to play in the editor. + +## End Result + +When you play in the level, you will see that the lights you placed start rotating and changing colors playing the embedded Sequence. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + bohLiPXTyMs + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +Since the Sequence is embedded within the Actor Blueprint, it has no dependencies and can play in any level or can be duplicated without any issues. + +In our example we've set the Sequence to **Auto Play**, however, you can also use the **Event Graph** to script when the Sequence should Play. + +![](EventGraphPlayScript.png) + +Above, upon **Event BeginPlay** we have allowed the Actor to receive input from a **Player Controller**. +When the **P** key is pressed, we take the **Actor Sequence Component** and get the **Sequence Player** which allows us to make a call to the function **Play** to start playing the Sequence. +You can use any method you desire to make the call to the Play function if you prefer not to have the Sequence Auto Play upon level load. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/ActorSequence/ActorSequence.JPN.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/ActorSequence/ActorSequence.JPN.udn new file mode 100644 index 000000000000..2386e4cf8eae --- /dev/null +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/ActorSequence/ActorSequence.JPN.udn @@ -0,0 +1,218 @@ +INTSourceChangelist:3477716 +Availability:Docs +Crumbs: %ROOT%, Engine, Engine/Sequencer, Engine/Sequencer/HowTo +Title:ブループリントで埋め込んだシーケンサー アニメーションを使用する +Description:Actor Sequence コンポーネントを使って Actor ブループリント内にシーケンスを埋め込む方法を説明します。 +Type: how-to +SkillLevel:Advanced +Version:4.16 +parent:Engine/Sequencer/HowTo +order:1 +tags:Sequencer +topic-image:ActorSequenceTopicCompact.png +Related:Engine/Sequencer/Overview +Related:Engine/Sequencer/ReferenceEditor +Related:Engine/Blueprints + + +[REGION:warning] +これは現在、開発進行中の実験的な機能です。一部の機能は期待どおりに機能しなかったり、将来のリビジョンで変更される可能性があります。 +[/REGION] + +[シーケンス](Engine/Sequencer/Overview) で作業をしたり、シーケンスを作成する場合、シーケンスの機能を他の場所やインスタンスで再利用したい状況があるかもしれません。 +**[Actor Sequence Plugin]** と **[Actor Sequence Component]** を使って、シーケンスを直接 Actor [ブループリント](Engine/Blueprints) に埋め込むことができます。 +この機能により、アニメーションをブループリント インスタンスに結合して、自動的にトリガーするか、ブループリントの **イベントグラフ** でトリガーすることでシーケンスを再利用することができます。 +また、Actor Sequence コンポーネントをワールドの任意のアクタに追加して、アクタの単一のインスタンスにアニメーションを追加することもできます。 + +この操作ガイドでは、埋め込みシーケンスを持つブループリントを作成し、時間経過に伴いスポットライトの色をアニメートし、変化させます。 + +![](EndResult.png) + +このブループリントはどのレベルでも配置、複製が可能であり、埋め込みシーケンスは呼び出されると自動的に再生します。 + +## ステップ + +[REGION:note] +ここでは **Starter Content Enabled (スターター コンテンツを有効にした状態)** で **Blueprint Third Person Template** を使います。 +[/REGION] + +1. プロジェクトを開いた状態で **[Edit (編集)]** メニューから、 **[Plugins (プラグイン)]** を選択します。 + + ![](ActorSequence01.png) + +1. **[Plugins]** メニューの **[Built-in]** で、**[Actor Sequence Editor]** オプションを有効にし、プロンプトが表示されたらエディタを再起動します。 + + ![](ActorSequence02.png) + + [REGION:note] + Actor Sequence Editor を有効にすると **Experimental (実験的機能)** の確認ダイアログ ウィンドウが表示されます。先に進むには、**Yes** をクリックします。 + [/REGION] + +1. **Actor** タイプの新規 **ブループリント** を作成し、**Light_BP** と名前を付けます。 + + ![](ActorSequence03.png) + +1. **Light_BP** 内で、**[Add Component]** をクリックし、**[Spot Light]** を追加します。 + + ![](ActorSequence04.png) + +1. **Spot Light** の **[Details (詳細)]** パネルで **Y** の **[Rotation]** 値を、**-60** に変更します。 + + ![](ActorSequence05.png) + + これにより、ビューポート内でライトが回転し、若干下方向に傾きます。 + +1. **Static Mesh** タイプの別の **コンポーネント** を追加します。次に **[Details]** パネルで、**[Location]** を **-180 (X)、 -180 (Y)、 -100 (Z)** に設定したメッシュを **Floor_400x400** に設定します。 + + ![](ActorSequence06.png) + + この Floor Mesh を使ってライトを照らし、シーケンサーによってパラメータの変更を操作するエフェクトを確認します。 + +1. **Actor Sequence** タイプの別の **コンポーネント** を追加します。 + + ![](ActorSequence07.png) + +1. **[Actor Sequence]** の **[Details]** パネルで、**[Loop Indefinitely]**、 **[Random Start Time]**、および **[Auto Play]** を設定して **[Open in Tab]** をクリックします。 + + ![](ActorSequence08.png) + + **[Open in Tab]** をクリックすると、**[Sequencer Editor]** がブループリント内で開きます。 + + ![](SequencerWindow.png) + + この例では、シーケンスを自動的にトリガーし再生しますが、**イベントグラフ** から呼び出して再生することもできます。 + +1. **[Sequencer]** タブで、**[Add]** をクリックします。次に **[Component]** で **[SpotLight]** を選択します。 + + ![](ActorSequence09.png) + +1. **SpotLight** トラックで、**[Track]** ボタンをクリックし、**[Transform]** を選択します。 + + ![](ActorSequence10.png) + +1. **SpotLight** トラックで再度 **[Track]** ボタンを押して、**[Light Color]** トラックを追加します。 + + ![](ActorSequence11.png) + +1. **Transform** トラックの **Rotation** で、 **Z** 値の **+** アイコンをクリックし、フレーム **0** に キー **0** を追加します。 + + ![](ActorSequence12.png) + +1. 追加したキーを選択し、**4** キーを押して補間のタイプを **Linear** に変更します。 + + ![](ActorSequence13.png) + + 補間のタイプを変更するには、数字キーを使うか、該当するキーフレーム上で右クリックして、使用したい補間方法を選択します。 + +1. **-180.0** に設定されている **Rotation** の **Z** 値に対して **2.00** にキーを追加し、そのキーの上で **4** を押して補間のタイプを **Linear** に変更します。 + + ![](ActorSequence14.png) + +1. **-360.0** に設定されている **Rotation** の **Z** 値に対して **4.00** にキーを追加し、そのキーの上で **4** を押して補間のタイプを **Linear** に変更します。 + + ![](ActorSequence15.png) + + 赤色の **エンド マーカー** を **4.00** に戻して開始した場所でシーケンスが終わるようにすることもできます。 + +1. **Light Color** トラックの **[+]** ボタンをクリックして、フレーム **0** にキーを追加します。 + + ![](ActorSequence16.png) + +1. 値 **0.0** の **Red** に対して **1.00** にキーを追加します。 + + ![](ActorSequence17.png) + +1. 値 **0.0** の **Green** に対して **2.00** にキーを追加します。 + + ![](ActorSequence18.png) + +1. 値 **0.0** の **Blue** に対して **3.00** にキーを追加します。**Red** と **Green** は両方とも **1.0** にキーを追加します。 + + ![](ActorSequence19.png) + +1. 値 **1.0** の **Blue** に対して **4.00** にキーを追加します。 + + ![](ActorSequence20.png) + + 以上の操作により、ライトが白色から様々な色に変化してシーケンスの終わりに白色に戻ります。 + +1. **[Component]** ウィンドウで、**StaticMesh** フロアを選択して **[Delete (削除)]** します。 + + ![](ActorSequence21.png) + + ライトがセットアップできたので、ビューポートでライトをプレビューするためにこのメッシュを使う必要がなくなりました。 + +1. メイン レベル エディタ ビューポートで、このフロアを選択し、**Alt** キーを押しながら、フロアのコピーを上方向にドラッグして、レベルを覆うルーフを作ります。 + + ![](ActorSequence22.png) + +1. **コンテンツ ブラウザ** から、**Light_BP** のインスタンスをドラッグしてレベルに配置します (**E** キーを押して必要に応じて回転させることもできます)。 + + ![](ActorSequence23.png) + +1. **Build** ドロップダウン メニューから、**Build Lighting Only** を選択して、レベルでライティングを再ビルドします。 + + ![](ActorSequence24.png) + +1. **[Play (プレイ)]** ボタンをクリックして、エディタで再生します。 + +## 最終結果 + +レベルで再生すると、配置したライトが回転し始め色が変化し、埋め込んだシーケンスを再生します。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + bohLiPXTyMs + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +Actor ブループリント内でシーケンスが埋め込まれているため、依存関係はなく、どのレベルでも問題なく再生したり、複製することができます。 + +この例では、シーケンスを **Auto Play** に設定しましたが、**イベントグラフ** を使ってシーケンスをいつ再生するかをスクリプティングすることができます。 + +![](EventGraphPlayScript.png) + +上の図では、**Event BeginPlay** で、アクタが **Player Controller** からの入力を受け取ります。 +**P** キーを押すと、**Actor Sequence コンポーネント** を取り込み、**Sequence Player** を取得します。これにより、関数 **Play** を呼び出してシーケンスの再生を開始します。 +レベルのロード時に Sequence Auto Play を持たないようにしたい場合は、Play 関数を呼び出すための任意の方法を使うことができます。 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/ActorSequence/ActorSequence.KOR.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/ActorSequence/ActorSequence.KOR.udn new file mode 100644 index 000000000000..d2d9e049497b --- /dev/null +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/ActorSequence/ActorSequence.KOR.udn @@ -0,0 +1,215 @@ +INTSourceChangelist:3454405 +Availability: Public +Title:블루프린트에서 삽입된 시퀀서 애니메이션 사용 +Crumbs: %ROOT%, Engine, Engine/Sequencer, Engine/Sequencer/HowTo +Description:Actor Sequence 컴포넌트를 사용해서 액터 블루프린트 안에 시퀀스를 삽입하는 방법 설명서입니다. +Version: 4.15 +SkillLevel: Advanced +parent:Engine/Sequencer/HowTo +order:1 +checkpoint: editorqs +Related: Engine/Sequencer/Overview +Related: Engine/Sequencer/ReferenceEditor +Related: Engine/Blueprints +tags:Sequencer +type:how-to + +[REGION:warning] +이 기능은 현재 개발중인 실험단계 기능입니다. 일부분 예상대로 작동치 않거나 앞으로의 버전에서 변경될 수 있습니다. +[/REGION] + +[시퀀스](Engine/Sequencer/Overview) 작업 및 생성을 할 때, 다른 곳이나 인스턴스의 시퀀스 기능을 재사용하고 싶을 때가 있습니다. +**Actor Sequence Plugin** 과 **Actor Sequence Component** 가 있으면, 시퀀스를 액터 [블루프린트](Engine/Blueprints) 안에 바로 삽입하는 것이 가능합니다. +이렇게 하면 블루프린트 인스턴스에 애니메이션을 바인딩하한 뒤 자동으로 또는 블루프린트 **이벤트 그래프** 를 통해 발동시키는 방식으로 시퀀스를 재사용할 수 있습니다. +추가적으로, 월드의 아무 액터에나 Actor Sequence 컴포넌트를 추가하여 액터 단일 인스턴스에 애니메이션을 추가할 수 있습니다. + +여기서는 스포트 라이트의 컬러에 애니메이션을 주어 시간에 따라 변하게 만드는 시퀀스가 삽입된 블루프린트를 만들어 보겠습니다. + +![](EndResult.png) + +그 후 블루프린트를 아무 레벨에 배치하거나 복제하면, 호출했을 때 삽입된 시퀀스가 자동 재생될 것입니다. + +## 단계 + +[REGION:note] +여기서는 **블루프린트 삼인칭 템플릿** 에 **시작용 콘텐츠** 를 포함한 것을 사용하고 있습니다. +[/REGION] + +1. 프로젝트를 열고, **편집** 메뉴의 **플러그인** 을 선택합니다. + + ![](ActorSequence01.png) + +1. **플러그인** 메뉴에서 **Built-in** 아래 **Actor Sequence Editor** (액터 시퀀스 에디터) 옵션을 활성화시키고 확인창이 뜨면 에디터를 재시작합니다. + + ![](ActorSequence02.png) + + [REGION:note] + 액터 시퀀스 에디터를 활성화시킬 때 **실험단계** 확인 대화창이 보일텐데, **예** 를 눌러 계속합니다. + [/REGION] + +1. **Actor** 유형 **블루프린트** 를 새로 만들어 **Light_BP** 라 합니다. + + ![](ActorSequence03.png) + +1. **Light_BP** 안에서 **컴포넌트 추가** 를 클릭하고 **Spot Light** 를 추가합니다. + + ![](ActorSequence04.png) + +1. 그 **Spot Light** 의 **디테일** 패널에서 **회전** 의 **Y** 값을 **-60** 으로 변경합니다. + + ![](ActorSequence05.png) + + 그러면 라이트를 살짝 회전시켜 뷰포트 아래쪽을 향하도록 합니다. + +1. **Static Mesh** 유형 **컴포넌트** 를 하나 더 추가한 뒤, **디테일** 패널에서 메시를 **Floor_400x400**, **위치** 는 **-180 (X), -180 (Y), -100 (Z)** 로 설정합니다. + + ![](ActorSequence06.png) + + 이 Floor Mesh 에 라이트를 비추어 시퀀서 구동 파라미터 변화 효과를 확인하도록 하겠습니다. + +1. **Actor Sequence** 유형 **컴포넌트** 를 하나 더 추가합니다. + + ![](ActorSequence07.png) + +1. **Actor Sequence** 의 **디테일** 패널에서 **Loop Indefinitely** (무한 루프), **Random Start Time** (시작 시간 랜덤), **Auto Play** (자동 재생) 설정 후 **Open in Tab** (탭에서 열기)를 선택합니다. + + ![](ActorSequence08.png) + + **Open in Tab** (탭에서 열기)를 선택하면, **시퀀서 에디터** 가 블루프린트 안에 열립니다. + + ![](SequencerWindow.png) + + 이 예제에서는 시퀀서를 자동 발동시켜 재생하겠지만, **이벤트 그래프** 에서도 호출하여 재생할 수 있습니다. + +1. **시퀀서** 탭에서 **추가** 를 클릭한 뒤 **컴포넌트** 아래 **SpotLight** 를 선택합니다. + + ![](ActorSequence09.png) + +1. **SpotLight** 트랙에서 **Track** (트랙) 버튼을 클릭하고 **Transform** (트랜스폼)을 선택합니다. + + ![](ActorSequence10.png) + +1. **SpotLight** 트랙에 대해 **Track** (트랙) 버튼을 다시 클릭하고 **Light Color** 트랙을 추가합니다. + + ![](ActorSequence11.png) + +1. **Transform** 트랙에서 **회전** 아래 **Z** 값에 대한 **+** 아이콘을 클릭하여 **0** 프레임에 **0** 키를 추가합니다. + + ![](ActorSequence12.png) + +1. 추가된 키를 선택한 뒤, **4** 키를 눌러 보간 유형을 **Linear** (선형)으로 변경합니다. + + ![](ActorSequence13.png) + + 보간 유형 변경은 숫자 키 또는 키프레임에 **우클릭** 하고 보간 방법을 선택하면 됩니다. + +1. **Rotation** 의 **Z** 값에 대해 **2.00** 위치에 키를 추가하고 **-180.0** 으로 설정한 뒤, **4** 키를 눌러 **선형** 보간으로 변경합니다. + + ![](ActorSequence14.png) + +1. **Rotation** 의 **Z** 값에 대해 **4.00** 위치에 키를 추가하여 **-360.0** 으로 설정하고, **4** 키를 눌러 보간을 **선형** 으로 변경합니다. + + ![](ActorSequence15.png) + + 빨강 **End Marker** (끝 마커)를 **4.00** 으로 움직여 시퀀스가 시작한 곳에서 끝나도록 할 수도 있습니다. + +1. **Light Color** 트랙의 **+** 버튼을 클릭하여 **0** 프레임에 키를 추가합니다. + + ![](ActorSequence16.png) + +1. **Red** 의 **1.00** 위치에 키를 추가하여 값을 **0.0** 으로 합니다. + + ![](ActorSequence17.png) + +1. **Green** 의 **2.00** 위치에 키를 추가하여 값을 **0.0** 으로 합비다. + + ![](ActorSequence18.png) + +1. **Blue** 의 **3.00** 위치에 키를 추가하여 값을 **0.0** 으로, **Red** 와 **Green** 에도 **1.0** 위치에 키를 추가합니다. + + ![](ActorSequence19.png) + +1. **Blue** 의 **4.00** 위치에 값이 **1.0** 인 키를 추가합니다. + + ![](ActorSequence20.png) + + 이렇게 하면 라이트가 흰색에서 다양한 색으로 변한 다음 시퀀스 끝에서 다시 흰색으로 돌아갑니다. + +1. **컴포넌트** 창에서 **StaticMesh** 바닥을 선택하고 **삭제** 합니다. + + ![](ActorSequence21.png) + + 라이트 구성이 완료되었으니, 뷰포트에서 라이트 미리보기에 이 메시가 더이상 필요치 않습니다. + +1. 메인 레벨 에디터 뷰포트에서, 바닥을 선택한 뒤 **Alt** 키를 누른 상태에서 드래그하여 바닥 사본으로 레벨을 덮는 지붕을 만듭니다. + + ![](ActorSequence22.png) + +1. **콘텐츠 브라우저** 에서 레벨에 **Light_BP** 인스턴스를 끌어 배치합니다 (**E** 키를 눌러 회전시킬 수도 있습니다). + + ![](ActorSequence23.png) + +1. **빌드** 드롭다운 메뉴에서 **라이팅만 빌드** 를 선택하여 레벨의 라이팅을 리빌드합니다. + + ![](ActorSequence24.png) + +1. **플레이** 버튼을 클릭하여 에디터에서 플레이합니다. + +## 최종 결과 + +레벨에서 플레이해 보면, 배치한 라이트가 회전하기 시작하고 삽입 시퀀스를 재생하면서 색이 변하는 것이 보일 것입니다. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + bohLiPXTyMs + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +액터 블루프린트에 시퀀스를 삽입했으므로, 종속성이 없으며 어느 레벨에서도 재생할 수 있고 별다른 문제 없이 복제할 수도 있습니다. + +우리 예제에서는 시퀀스를 **Auto Play** (자동 재생)하도록 설정했지만, **이벤트 그래프** 를 사용하여 시퀀스를 언제 재생할지 스크립트를 짤 수도 있습니다. + +![](EventGraphPlayScript.png) + +위에서, **Event BeginPlay** 이후 액터가 **Player Controller** 에서 입력을 받을 수 있도록 했습니다. +**P** 키가 눌리면, **Actor Sequence 컴포넌트** 를 받아 **Sequence Player** 를 구하고, 시퀀스 재생 시작을 위한 **Play** 함수 호출을 할 수 있도록 해줍니다. +레벨 로드 시 시퀀스가 자동 재생되지 않도록 하기를 원하는 경우, Play 함수 호출은 어떤 식으로 해도 상관 없습니다. + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/AnimateDynamicObjects/AnimateDynamicObjects.CHN.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/AnimateDynamicObjects/AnimateDynamicObjects.CHN.udn index 6a5f2e5c255c..702401ff6086 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/HowTo/AnimateDynamicObjects/AnimateDynamicObjects.CHN.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/AnimateDynamicObjects/AnimateDynamicObjects.CHN.udn @@ -1,22 +1,22 @@ -INTSourceChangelist:0 -Availability: Public -Title:Animating Dynamic Objects at Runtime +INTSourceChangelist:3378719 +Availability:Public +Title:在运行时设置动态对象的动画 Crumbs: %ROOT%, Engine, Engine/Sequencer, Engine/Sequencer/HowTo -Description:This example illustrates how you can apply Sequences to dynamic objects at runtime that are different than the one the Sequence was authored with. -Version: 4.15 -SkillLevel: Advanced +Description:此例说明如何在运行时将序列应用到动态对象(此对象与序列中原始拥有的对象不同)。 +Version:4.15 +SkillLevel:Advanced parent:Engine/Sequencer/HowTo order:1 checkpoint: editorqs -Related: Engine/Sequencer/Overview -Related: Engine\Sequencer\ReferenceEditor\ +Related:Engine/Sequencer/Overview +Related:Engine\Sequencer\ReferenceEditor\ tags:Sequencer -When creating cinematics for gameplay purposes, there may be times when you want to animate an object that is dynamically spawned at runtime through Sequencer. -For instance, you create an animated object that moves along a path but that object is something that can be defined by the player. -With the help of [Blueprint Visual Scripting](Engine/Blueprints), you can expose binding identifiers from a Level Sequence using the **Get Sequence Bindings** node and override any of those bindings with your own. +针对游戏性目的创建动画时,有时需要对通过 Sequencer 在运行时动态生成的对象设置动画。 +举例而言,用户可创建一个带动画的对象沿路径移动,而该对象可由玩家定义。 +在 [蓝图可视化脚本](Engine/Blueprints) 的协助下,用户可使用 **Get Sequence Bindings** 节点从关卡序列公开绑定辨识符,并使用自有绑定覆盖这些绑定。 -In this example, we animate and move an object along a path and allow the player to change that object by pressing a button as seen below. +在此例中,我们将为一个对象设置动画,使其沿路径行进;按键后可变更此对象。详情见下方视频。 [OBJECT:EmbeddedVideo] [PARAMLITERAL:width] @@ -31,127 +31,127 @@ XdahqJz2cyM [/OBJECT] [REGION:note] -For this how-to, we are using the **Blueprint Third Person Template** project and with **Starter Content** enabled. +在此指南中,我们使用的是启用 **Starter Content** 的 **Blueprint Third Person Template** 项目,**Target Hardware** 和 **Project Settings** 为默认设置。 [/REGION] -## Steps +## 步骤 -1. In the **Content Browser**, create two new **Blueprints** based off the **Actor** class and name one **Cube_Blueprint** and the other **Sphere_Blueprint**. +1. 在 **Content Browser** 中以 **Actor** 类为基础新建两个 **蓝图** ,将一个命名为 **Cube_Blueprint**,另一个命名为 **Sphere_Blueprint**。 ![](DynamicAnim_01.png) - We will use the Cube Blueprint in our default Sequence but will swap in our Sphere Blueprint when the player presses a key. + 默认序列中使用的是立方体蓝图,而玩家按键后将切换为球体蓝图。 -1. Inside each Blueprint, add a **Static Mesh** component with one using a **Shape_Cube** mesh and the other using the **Shape_Sphere** mesh. +1. 在每个蓝图中添加一个 **Static Mesh** 组件,一个使用 **Shape_Cube** 模型,另一个使用 **Shape_Sphere** 模型。 ![](DynamicAnim_02.png) -1. From the **Modes** panel, drag an **Empty Actor** anywhere into the Level Viewport. +1. 在 **Modes** 面板中将一个 **Empty Actor** 拖入关卡视口中。 ![](DynamicAnim_03.png)(w:940) -1. From the **Main Toolbar**, click the **Cinematics** button and **Add Level Sequence**, then assign it any name. +1. 在 **主工具栏** 中点击 **Cinematics** 和 **Add Level Sequence** 按钮,然后为其指定任意命名。 ![](DynamicAnim_04.png) -1. In your sequence, with the **Empty Actor** in the level selected, click **Add** then **Add Actor** to add it to the sequence. +1. 在序列中,在关卡中选中 **Empty Actor** 后,先点击 **Add**,然后点击 **Add Actor** 将其添加到序列。 ![](DynamicAnim_05.png) -1. Add a **Transform** track for the **Empty Actor** and add a key at **0** for its initial position in the level. +1. 为 **Empty Actor** 添加一个 **Transform** 轨迹,在 **0** 处添加一个键,设为关卡中的初始位置。 ![](DynamicAnim_06.png) -1. Move the timeline to frame **50** then move the **Empty Actor** in the level and press **S** to add a new key at its new position. +1. 将时间轴移至第 **50** 帧,然后在关卡中移动 **Empty Actor**,然后在其新位置按下 **S** 新建一个键。 ![](DynamicAnim_07.png)(w:740) -1. Move the timeline to frame **100** then move the **Empty Actor** back to its starting position and press **S** to add a key at its ending transform. +1. 将时间轴移至第 **100** 帧,然后将 **Empty Actor** 移回至其初始位置,然后按下 **S** 在其最终变形处添加一个键。 ![](DynamicAnim_08.png)(w:740) - You can also press the **]** key inside Sequencer while at frame 100 to end the Sequence at this key. + 也可在 Sequencer 中的第 100 帧处按下 **]**,在此键处终止序列。 -1. Select your Level Sequence in the Level Viewport, then in the **Details** panel, set **Loop** to **Lopp Indefinitely**. +1. 在关卡视口中选中关卡序列,然后在 **Details** 面板中将 **Loop** 设为 **Loop Indefinitely**。 ![](DynamicAnim_09.png) -1. With your Level Sequence selected in the Level Viewport, from the **Main Toolbar**, select **Blueprints** and **Open Level Blueprint**. +1. 在关卡视口中选中关卡序列后,在 **主工具栏** 中选择 **Blueprints** 和 **Open Level Blueprint**。 ![](DynamicAnim_10.png) -1. **Right-click** in the graph and create a reference to your Level Sequence. +1. 在图表中 **点击右键**,创建一个对关卡序列的引用。 ![](DynamicAnim_10b.png) - In our case, we named our Level Sequence **Master**, however, your name may differ. + 在此例中我们将关卡序列命名为 **Master**,您可以使用其他命名。 -1. **Right-click** and add an **Event Begin Play** node, then drag off your Level Sequence reference and add a **Play (Sequence Player)** node. +1. **点击右键** 添加一个 **Event Begin Play** 节点,然后从关卡序列引用连出引线,添加一个 **Play (Sequence Player)** 节点。 ![](DynamicAnim_11.png) - Then connect the nodes as shown below. + 然后按下图所示连接节点。 ![](DynamicAnim_12.png) - This will automatically start playing our Sequence when we start the game. + 此设置将在游戏开始时播放序列。 -1. **Right-click** in the graph and add a **1** Keyboard Event and connect it to a **Flip Flop** node. +1. 在图表中 **点击右键**,添加一个 **1** 键盘事件并将其连接到一个 **Flip Flop** 节点。 ![](DynamicAnim_13.png) - When we press 1 the first time, we will change the Empty Actor to our Cube, when we press 1 again, we will change it to our Sphere. + 第一次按下 1 时,空白 Actor 将变为立方体;再次按下 1 时,立方体将变为球体。 -1. **Right-click** and create a **Spawn Actor From Class** node and set the class as **Cube Blueprint**. +1. **点击右键** 并创建一个 **Spawn Actor From Class** 节点,然后将类设为 **Cube Blueprint**。 -1. **Right-click** the **Return Value** and **Promote to Variable** called **Cube**, then drag off **Spawn Transform** and use **Make Transform**. +1. **右键点击** **Return Value**,然后 **Promote to Variable** 调用 **Cube**,然后从 **Spawn Transform** 连出引线并使用 **Make Transform**。 ![](DynamicAnim_14.png) - Here we are spawning our Cube Blueprint when 1 is pressed, storing it as a variable called Cube and giving it a default transform to spawn it at. + 在此处按下 1 时将生成立方体蓝图,将其保存为调用立方体的变量,然后为其赋予一个生成的默认变形。 -1. Off the **B** pin of the **Flip Flop** node, use **Spawn Actor from Class** (set to **Sphere Blueprint**), create a variable to store it and connect as shown below. +1. 从 **Flip Flop** 的 **B** 引脚连出引线,使用 **Spawn Actor from Class**(设为 **Sphere Blueprint**),创建一个变量进行保存,并以下图中的方式进行连接。 ![](DynamicAnim_15.png) - When we press 1 a second time, we are now creating and spawning in our Sphere Blueprint and storing it as a variable for use later. + 第二次按下 1 时,便会在球体蓝图中进行创建和生成,并将其保存为变量以便之后使用。 -1. **Right-click** in the graph and add the **Get Sequence Bindings** node and in the **Details** panel, point it to your Level Sequence. +1. 在图表中 **点击右键** 并添加 **Get Sequence Bindings** 节点,然后在 **Details** 面板中将其指向关卡序列。 ![](DynamicAnim_16.png) - This will allow us to access and override the contains within our Level Sequence through Blueprint Script. + 此设置将使用户能够通过蓝图脚本访问并覆盖关卡序列中包含的内容。 -1. **Right-click** in the graph and add the **Add Binding** node and connect the following nodes: +1. 在图表中 **点击右键** 并添加 **Add Binding** 节点,然后连接到以下节点: ![](DynamicAnim_17.png) - Above we have connected the reference to our Level Sequence as the **Target**, the **Get Sequence Bindings** node as the **Binding** and the variable we created for our spawned Cube as the **Actor**. - This will allow us to replace the Empty Actor (**Actor**) in our Level Sequence with the Actor we specify (our **Cube** that we spawn or our **Sphere**). The animation that was applied to the Empty Actor will also be applied to the Actor we set as part of the binding. + 上图中我们已将对关卡序列的引用连接为 **Target**、**Get Sequence Bindings** 节点连接为 **Binding**,而为生成立方体创建的变量连接为 **Actor**。 + 此设置使用户能用指定的 Actor(生成的 **立方体** 或 **球体**)替换关卡序列中的空白 Actor(**Actor**)。应用到空白 Actor 的动画也将被应用到设为绑定部分的 Actor。 -1. Repeat the previous step for the **Sphere** portion of script, replacing **Cube** with **Sphere** as the **Actor**. +1. 针对脚本的 **Sphere** 部分执行之前的步骤,用 **Sphere** 替代 **Cube** 作为 **Actor**。 ![](DynamicAnim_18.png) -1. Following the **Add Binding** node for the Cube portion of script, use the **Sphere** variable and perform an **? IsValid** check and **Destroy Actor** if valid. +1. 跟随脚本 Cube 部分的 **Add Binding** 节点,使用 **Sphere** 变量并执行一个 **?IsValid** 检查,如有效则执行 **Destroy Actor**。 ![](DynamicAnim_19.png) - This will destroy the Sphere when we spawn in the Cube. + 完成此设置后生成立方体时便会销毁球体。 -1. Repeat the previous step for the **Sphere** portion of script, using **? IsValid** on the **Cube** variable and **Destroy Actor** if valid. +1. 针对脚本的 **Sphere** 部分执行之前的步骤,使用 **Cube** 变量上的 **?IsValid** 检查,如有效则执行 **Destroy Actor**。 ![](DynamicAnim_20.png) - This will destroy the Cube when we spawn the Sphere. + 完成此设置后生成球体时便会销毁立方体。 -1. Play in the editor, then press the **1** key to cycle between our spawned Actors. +1. 在编辑器中进行游戏,然后按下 **1** 键在生成的 Actor 之间切换。 -## End Result +## 最终结果 -When we play in the editor and press the 1 key, our Empty Actor is replaced by a spawned Actor either the Cube or the Sphere but continues to use the animation we applied. +在编辑器中进行游戏并按下 1 键时,空白 Actor 将被生成的 Actor(立方体或球体)所替代,但继续使用应用的动画。 [OBJECT:EmbeddedVideo] [PARAMLITERAL:width] @@ -165,7 +165,7 @@ XdahqJz2cyM [/PARAMLITERAL] [/OBJECT] -You can also set and bind an array of Actors to a binding with the **Set Binding** node, **Reset Binding** for a particular binding or **Reset Bindings** for an entire Level Sequence. +可使用 **Set Binding** 节点设置并绑定一个 Actor 阵列到绑定,为一个特定绑定 **设置绑定(Set Binding)** 或为整个关卡序列 **重设绑定(Reset Binding)**。 ![](AdditionalFunctions.png) diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/AnimateDynamicObjects/AnimateDynamicObjects.INT.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/AnimateDynamicObjects/AnimateDynamicObjects.INT.udn index ca2806e721ab..f6ee69489ff3 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/HowTo/AnimateDynamicObjects/AnimateDynamicObjects.INT.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/AnimateDynamicObjects/AnimateDynamicObjects.INT.udn @@ -10,38 +10,30 @@ checkpoint: editorqs Related: Engine/Sequencer/Overview Related: Engine\Sequencer\ReferenceEditor\ tags:Sequencer +type:how-to When creating cinematics for gameplay purposes, there may be times when you want to animate an object that is dynamically spawned at runtime through Sequencer. -For instance, you create an animated object that moves along a path but that object is something that can be defined by the player. -With the help of [Blueprint Visual Scripting](Engine/Blueprints), you can expose binding identifiers from a Level Sequence using the **Get Sequence Bindings** node and override any of those bindings with your own. +For instance, you can create an animated object that moves along a path but that object is something which can be defined by the player. +With the help of [](Engine/Blueprints), you can expose binding identifiers from a Level Sequence using the **Get Sequence Bindings** node, and override any of those bindings with your own. -In this example, we animate and move an object along a path and allow the player to change that object by pressing a button as seen below. +In this example, we animate and move an object along a path, enabling the player to change that object by pressing a button. + +![](EndResult.png) -[OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -XdahqJz2cyM -[/PARAMLITERAL] -[/OBJECT] [REGION:note] -For this how-to, we are using the **Blueprint Third Person Template** project and with **Starter Content** enabled. +For this how-to guide, we are using the **Blueprint Third Person Template** project, enabling **Starter Content**, with default **Target Hardware** and **Project Settings**. [/REGION] ## Steps -1. In the **Content Browser**, create two new **Blueprints** based off the **Actor** class and name one **Cube_Blueprint** and the other **Sphere_Blueprint**. +1. In the **Content Browser**, create two new **Blueprints** based off of the **Actor** class and name one **Cube_Blueprint** and the other **Sphere_Blueprint**. ![](DynamicAnim_01.png) We will use the Cube Blueprint in our default Sequence but will swap in our Sphere Blueprint when the player presses a key. -1. Inside each Blueprint, add a **Static Mesh** component with one using a **Shape_Cube** mesh and the other using the **Shape_Sphere** mesh. +1. Inside each Blueprint, add a **Static Mesh** component with one using a **Shape_Cube** mesh, and the other using the **Shape_Sphere** mesh. ![](DynamicAnim_02.png) @@ -53,7 +45,7 @@ For this how-to, we are using the **Blueprint Third Person Template** project an ![](DynamicAnim_04.png) -1. In your sequence, with the **Empty Actor** in the level selected, click **Add** then **Add Actor** to add it to the sequence. +1. In your sequence, with the **Empty Actor** in the level selected, click **Add** and then **Add Actor** to add it to the sequence. ![](DynamicAnim_05.png) @@ -61,17 +53,17 @@ For this how-to, we are using the **Blueprint Third Person Template** project an ![](DynamicAnim_06.png) -1. Move the timeline to frame **50** then move the **Empty Actor** in the level and press **S** to add a new key at its new position. +1. Move the timeline to frame **50**, then move the **Empty Actor** in the level and press **S** to add a new key at its new position. ![](DynamicAnim_07.png)(w:740) -1. Move the timeline to frame **100** then move the **Empty Actor** back to its starting position and press **S** to add a key at its ending transform. +1. Move the timeline to frame **100**, then move the **Empty Actor** back to its starting position and press **S** to add a key at its ending transform. ![](DynamicAnim_08.png)(w:740) - You can also press the **]** key inside Sequencer while at frame 100 to end the Sequence at this key. + You can also press the **]** key inside of Sequencer while at frame 100 to end the Sequence at this key. -1. Select your Level Sequence in the Level Viewport, then in the **Details** panel, set **Loop** to **Lopp Indefinitely**. +1. Select your Level Sequence in the Level Viewport, then in the **Details** panel, set **Loop** to **Loop Indefinitely**. ![](DynamicAnim_09.png) @@ -79,66 +71,70 @@ For this how-to, we are using the **Blueprint Third Person Template** project an ![](DynamicAnim_10.png) -1. **Right-click** in the graph and create a reference to your Level Sequence. +1. Right-click in the graph and create a reference to your Level Sequence. ![](DynamicAnim_10b.png) In our case, we named our Level Sequence **Master**, however, your name may differ. -1. **Right-click** and add an **Event Begin Play** node, then drag off your Level Sequence reference and add a **Play (Sequence Player)** node. +1. Right-click and add an **Event Begin Play** node, then drag off your Level Sequence reference and add a **Play (Sequence Player)** node. ![](DynamicAnim_11.png) - Then connect the nodes as shown below. +1. Then connect the nodes as shown below. ![](DynamicAnim_12.png) This will automatically start playing our Sequence when we start the game. -1. **Right-click** in the graph and add a **1** Keyboard Event and connect it to a **Flip Flop** node. +1. Right-click in the graph and add a **1** Keyboard Event, connecting it to a **Flip Flop** node. ![](DynamicAnim_13.png) When we press 1 the first time, we will change the Empty Actor to our Cube, when we press 1 again, we will change it to our Sphere. -1. **Right-click** and create a **Spawn Actor From Class** node and set the class as **Cube Blueprint**. +1. Right-click and create a **Spawn Actor From Class** node and set the class as **Cube Blueprint**. -1. **Right-click** the **Return Value** and **Promote to Variable** called **Cube**, then drag off **Spawn Transform** and use **Make Transform**. + ![](DynamicAnim_13b.png) + +1. Right-click the **Return Value** and **Promote to Variable** called **Cube**, then drag off **Spawn Transform** and use **Make Transform**. ![](DynamicAnim_14.png) - Here we are spawning our Cube Blueprint when 1 is pressed, storing it as a variable called Cube and giving it a default transform to spawn it at. + We are spawning our Cube Blueprint when 1 is pressed, storing it as a variable called Cube, and giving it a default transform to spawn it at. 1. Off the **B** pin of the **Flip Flop** node, use **Spawn Actor from Class** (set to **Sphere Blueprint**), create a variable to store it and connect as shown below. ![](DynamicAnim_15.png) - When we press 1 a second time, we are now creating and spawning in our Sphere Blueprint and storing it as a variable for use later. + When we press **1** a second time, we are now creating and spawning in our Sphere Blueprint and storing it as a variable for use later. -1. **Right-click** in the graph and add the **Get Sequence Bindings** node and in the **Details** panel, point it to your Level Sequence. +1. Right-click in the graph to add the **Get Sequence Bindings** node, and in the **Details** panel, point it to your Level Sequence. ![](DynamicAnim_16.png) - This will allow us to access and override the contains within our Level Sequence through Blueprint Script. + This will allow us to access and override the content within our Level Sequence through Blueprint Script. -1. **Right-click** in the graph and add the **Add Binding** node and connect the following nodes: +1. Right-click in the graph and add the **Add Binding** node, connecting the following nodes: ![](DynamicAnim_17.png) - Above we have connected the reference to our Level Sequence as the **Target**, the **Get Sequence Bindings** node as the **Binding** and the variable we created for our spawned Cube as the **Actor**. + [REGION:note] + Now that we've connected the reference to our Level Sequence as the **Target**, the **Get Sequence Bindings** node as the **Binding**, and the variable we created for our spawned Cube as the **Actor**. This will allow us to replace the Empty Actor (**Actor**) in our Level Sequence with the Actor we specify (our **Cube** that we spawn or our **Sphere**). The animation that was applied to the Empty Actor will also be applied to the Actor we set as part of the binding. + [/REGION] 1. Repeat the previous step for the **Sphere** portion of script, replacing **Cube** with **Sphere** as the **Actor**. ![](DynamicAnim_18.png) -1. Following the **Add Binding** node for the Cube portion of script, use the **Sphere** variable and perform an **? IsValid** check and **Destroy Actor** if valid. +1. Following the **Add Binding** node for the Cube portion of script, use the **Sphere** variable and perform a **? IsValid** check and **Destroy Actor** (if valid). ![](DynamicAnim_19.png) This will destroy the Sphere when we spawn in the Cube. -1. Repeat the previous step for the **Sphere** portion of script, using **? IsValid** on the **Cube** variable and **Destroy Actor** if valid. +1. Repeat the previous step for the **Sphere** portion of script, using **? IsValid** on the **Cube** variable and **Destroy Actor** (if valid). ![](DynamicAnim_20.png) @@ -146,25 +142,29 @@ For this how-to, we are using the **Blueprint Third Person Template** project an 1. Play in the editor, then press the **1** key to cycle between our spawned Actors. - - ## End Result -When we play in the editor and press the 1 key, our Empty Actor is replaced by a spawned Actor either the Cube or the Sphere but continues to use the animation we applied. +When we play in the editor and press the 1 key, our Empty Actor is replaced by a spawned Actor with either the Cube or the Sphere, but continues to use the animation we applied. [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -XdahqJz2cyM -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + XdahqJz2cyM + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] -You can also set and bind an array of Actors to a binding with the **Set Binding** node, **Reset Binding** for a particular binding or **Reset Bindings** for an entire Level Sequence. +You can also set and bind an array of Actors to a binding with the **Set Binding** node. Additionally, you can use the **Reset Binding** node for a particular binding or the **Reset Bindings** node for an entire Level Sequence. ![](AdditionalFunctions.png) diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/AnimateDynamicObjects/AnimateDynamicObjects.JPN.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/AnimateDynamicObjects/AnimateDynamicObjects.JPN.udn index 1140612b7d1b..ac26261c38d5 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/HowTo/AnimateDynamicObjects/AnimateDynamicObjects.JPN.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/AnimateDynamicObjects/AnimateDynamicObjects.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3348041 +INTSourceChangelist:3439832 Availability:Public Title:ランタイムに動的オブジェクトをアニメートする Crumbs: %ROOT%, Engine, Engine/Sequencer, Engine/Sequencer/HowTo @@ -11,27 +11,19 @@ checkpoint: editorqs Related:Engine/Sequencer/Overview Related:Engine\Sequencer\ReferenceEditor\ tags:Sequencer +type:how-to ゲームプレイ目的でシネマティックスを作成する場合、ランタイムに動的にスポーンされるオブジェクトをシーケンサーでアニメートする必要が生じるかもしれません。 例えば、パスに沿って移動するアニメートしたオブジェクトを作成し、そのオブジェクトがプレイヤーによって定義可能なものであるとします。 -[ブループリント ビジュアル スクリプティング](Engine/Blueprints) で、**Get Sequence Bindings** ノードを使ってレベル シーケンスからバインディング識別子を公開し、こうしたバインディングを自分のものでオーバーライドすることができます。 +[](Engine/Blueprints) で、**Get Sequence Bindings** ノードを使ってレベル シーケンスからバインディング識別子を公開し、こうしたバインディングを自分のものでオーバーライドすることができます。 -この例では、以下のようにオブジェクトをアニメートしパスに沿って動かし、プレイヤーがボタンを押すことでオブジェクトを変更できるようにします。 +この例では、オブジェクトをアニメートしパスに沿って動かし、プレイヤーがボタンを押すことでオブジェクトを変更できるようにします。 + +![](EndResult.png) -[OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -XdahqJz2cyM -[/PARAMLITERAL] -[/OBJECT] [REGION:note] -ここでは **Starter Content Enabled (スターター コンテンツを有効にした状態)** で **Blueprint Third Person Template** プロジェクトを使います。 +この操作ガイドでは **Starter Content** を有効にした状態で、デフォルトの **Target Hardware** と **Project Settings** で**Blueprint Third Person Template** プロジェクトを使います。 [/REGION] ## ステップ @@ -80,31 +72,33 @@ XdahqJz2cyM ![](DynamicAnim_10.png) -1. グラフ内で **右クリック** して、レベル シーケンスへのリファレンスを作成します。 +1. グラフ内で 右クリック して、レベル シーケンスへのリファレンスを作成します。 ![](DynamicAnim_10b.png) この場合、レベル シーケンスに **Master** という名前を付けましたが、別の名前を付けることもできます。 -1. **右クリック** して、**Event Begin Play** ノードを追加します。次に、レベル シーケンスのリファレンスからドラッグして、**Play (Sequence Player)** ノードを追加します。 +1. 右クリック して、**Event Begin Play** ノードを追加します。次に、レベル シーケンスのリファレンスからドラッグして、**Play (Sequence Player)** ノードを追加します。 ![](DynamicAnim_11.png) - 以下のようにノードを接続します。 +1. 以下のようにノードを接続します。 ![](DynamicAnim_12.png) これでゲーム開始時にシーケンスが自動的に開始します。 -1. グラフ内で **右クリック** し、 **1** Keyboard Event を追加し、 **Flip Flop** ノードに接続します。 +1. グラフ内で右クリックし、 **1** Keyboard Event を追加し、 **Flip Flop** ノードに接続します。 ![](DynamicAnim_13.png) 初めて 1 を押すと、Empty Actor が Cube に変わります。再度 1 を押すと、Sphere に変わります。 -1. **右クリック** して、 **Spawn Actor from Class** ノードを作成し、クラスを **Cube Blueprint** として設定します。 +1. 右クリック して、 **Spawn Actor from Class** ノードを作成し、クラスを **Cube Blueprint** として設定します。 -1. **Return Value** を **右クリック** し、 **Cube** に **変数化** し、 **Spawn Transform** からドラッグして **Make Transform** を使用します。 + ![](DynamicAnim_13b.png) + +1. Return Value を **右クリック** し、 **Cube** に **変数化** し、 **Spawn Transform** からドラッグして **Make Transform** を使用します。 ![](DynamicAnim_14.png) @@ -114,32 +108,34 @@ XdahqJz2cyM ![](DynamicAnim_15.png) - さらに 1 を押すと、Sphere ブループリントを作成し、スポーンし、後で使用するために変数として格納します。 + さらに **1** を押すと、Sphere ブループリントを作成し、スポーンし、後で使用するために変数として格納します。 -1. グラフ内で **右クリック** し、 **Get Sequence Bindings** ノードを追加します。**[Details]** パネルでそれをレベル シーケンスにポイントします。 +1. グラフ内で右クリックし、 **Get Sequence Bindings** ノードを追加します。**[Details]** パネルでそれをレベル シーケンスにポイントします。 ![](DynamicAnim_16.png) - これでブループリント スクリプトを通してレベル シーケンス内のものにアクセスしオーバーライドすることができます。 + これでブループリント スクリプトを通してレベル シーケンス内のコンテンツにアクセスしオーバーライドすることができます。 -1. グラフ内で **右クリック** して、**Add Binding** ノードを追加し、以下のノードを接続します。 +1. グラフ内で 右クリック して、**Add Binding** ノードを追加し、以下のノードを接続します。 ![](DynamicAnim_17.png) - 上の図では、レベル シーケンスへのリファレンスを **Target** として接続し、**Get Sequence Bindings** ノードを **Binding** として接続しました。スポーンした Cube に対して作成した変数は **Actor** として接続しました。 + [REGION:note] + ここまでで、レベル シーケンスへのリファレンスを **Target** として接続し、**Get Sequence Bindings** ノードを **Binding** として接続しました。スポーンした Cube に対して作成した変数は **Actor** として接続しました。 これでレベル シーケンス内の Empty Actor (**Actor**) を指定したアクタに置換することができます (スポーンする **Cube** または **Sphere**)。Empty Actor に適用されたアニメーションも、バインディングの一部として設定したアクタに適用されます。 + [/REGION] 1. スクリプトの **Sphere** 部分に対して前のステップを繰り返し、 **Actor** として **Cube** を **Sphere** に置き換えます。 ![](DynamicAnim_18.png) -1. スクリプトの Cube 部分の **Add Binding** ノードの後に、**Sphere** 変数を使って、**?IsValid** チェックを行い、有効ならば **Destroy Actor** します。 +1. スクリプトの Cube 部分の **Add Binding** ノードの後に、**Sphere** 変数を使って、**?IsValid** チェックを行い、 (有効ならば) **Destroy Actor** します。 ![](DynamicAnim_19.png) これで Cube スポーン時に Sphere が破棄されます。 -1. スクリプトの **Sphere** 部分に対して前のステップを繰り返し、**Cube** 変数で **?IsValid** チェックを行い、有効ならば **Destroy Actor** します。 +1. スクリプトの **Sphere** 部分に対して前のステップを繰り返し、**Cube** 変数で **?IsValid** チェックを行い、 (有効ならば) **Destroy Actor** します。 ![](DynamicAnim_20.png) @@ -149,23 +145,27 @@ XdahqJz2cyM ## 最終結果 - - エディタで再生し、1 キーを押すと、Empty Actor が Cube または Sphere のいずれかのスポーンしたアクタに置き換わりますが、適用したアニメーションを使い続けます。 [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -XdahqJz2cyM -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + XdahqJz2cyM + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] -一連のアクタを設定、バインドし、**Set Binding** ノードを使ってバインディングし、特定のバインディングに対して **Reset Binding** したり、レベル シーケンス全体を **Reset Bindings** することもできます。 +一連のアクタを設定、バインドし、**Set Binding** ノードを使ってバインディングすることができます。特定のバインディングに対して **Reset Binding** ノードを使ったり、レベル シーケンス全体に対して **Reset Binding** ノードを使うこともできます。 ![](AdditionalFunctions.png) diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/AnimateDynamicObjects/AnimateDynamicObjects.KOR.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/AnimateDynamicObjects/AnimateDynamicObjects.KOR.udn index 69ffabf6baa5..9e9040535e18 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/HowTo/AnimateDynamicObjects/AnimateDynamicObjects.KOR.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/AnimateDynamicObjects/AnimateDynamicObjects.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3348041 +INTSourceChangelist:3439832 Availability: Public Title:런타임에 다이내믹 오브젝트 애니메이션 Crumbs: %ROOT%, Engine, Engine/Sequencer, Engine/Sequencer/HowTo @@ -11,27 +11,19 @@ checkpoint: editorqs Related: Engine/Sequencer/Overview Related: Engine\Sequencer\ReferenceEditor\ tags:Sequencer +type:how-to 게임플레이 용도로 시네마틱을 제작할 때, 시퀀서를 통해 런타임 동적 스폰되는 오브젝트에 애니메이션을 주고플 때가 있습니다. 예를 들어 경로를 따라 움직이는 애니메이션 오브젝트를 만드는데, 그 오브젝트를 플레이어가 정의할 수 있는 것입니다. [블루프린트 비주얼 스크립트](Engine/Blueprints) 덕에 **Get Sequence Bindings** 노드를 사용하여 레벨 시퀀스에서의 바인딩 식별자를 노출시키고 그 바인딩을 자신의 것으로 덮어쓸 수 있습니다. -이 예제에서는 길을 따라 오브젝트를 움직이고 애니메이션을 적용하며, 아래와 같이 플레이어가 버튼을 누르면 그 오브젝트를 바꿀 수 있습니다. +이 예제에서는 길을 따라 오브젝트를 움직이고 애니메이션을 적용하며, 플레이어가 버튼을 누르면 그 오브젝트를 바꿀 수 있습니다. + +![](EndResult.png) -[OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -XdahqJz2cyM -[/PARAMLITERAL] -[/OBJECT] [REGION:note] -여기서는 **블루프린트 삼인칭 템플릿** 프로젝트에 **시작용 콘텐츠** 를 포함시켜 사용하고 있습니다. +여기서는 **블루프린트 삼인칭 템플릿** 프로젝트에 **시작용 콘텐츠** 포함, 기본 **타겟 하드웨어** 및 **프로젝트 세팅** 을 사용하고 있습니다. [/REGION] ## 단계 @@ -72,7 +64,7 @@ XdahqJz2cyM 100 프레임에 있을 때 시퀀서 안에서 **]** 키를 눌러도 이 키에서 시퀀스를 종료시킬 수 있습니다. -1. 레벨 뷰포트에서 레벨 시퀀스를 선택한 후, **디테일** 패널에서 **Loop** 를 **Lopp Indefinitely** (무한 반복)으로 설정합니다. +1. 레벨 뷰포트에서 레벨 시퀀스를 선택한 후, **디테일** 패널에서 **Loop** 를 **Loop Indefinitely** (무한 루프)로 설정합니다. ![](DynamicAnim_09.png) @@ -104,6 +96,8 @@ XdahqJz2cyM 1. **우클릭** 후 **Spawn Actor From Class** 노드를 생성한 뒤 클래스를 **Cube Blueprint** 로 설정합니다. + ![](DynamicAnim_13b.png) + 1. **Return Value** 에 **우클릭** 하고 **변수로 승격** 시켜 **Cube** 라 한 뒤, **Spawn Transform** 을 끌어 놓고 **Make Transform** 을 사용합니다. ![](DynamicAnim_14.png) @@ -120,14 +114,16 @@ XdahqJz2cyM ![](DynamicAnim_16.png) - 그러면 블루프린트 스크립트를 통해 레벨 시퀀스 내용물에 접근하고 덮어쓸 수 있도록 해줍니다. + 그러면 블루프린트 스크립트를 통해 레벨 시퀀스 내 콘텐츠에 접근하고 덮어쓸 수 있도록 해줍니다. 1. 그래프에 **우클릭** 하고 **Add Binding** 노드를 추가한 뒤 다음 노드를 연결합니다: ![](DynamicAnim_17.png) + [REGION:note] 위에서 레벨 시퀀스로의 레퍼런스를 **Target** 으로, **Get Sequence Bindings** 노드를 **Binding** 으로, 스폰한 큐브에 대해 생성한 변수를 **Actor** 로 연결했습니다. 그러면 레벨 시퀀스의 공백 액터 (**Actor**) 를 지정한 (**Cube** 또는 **Sphere**) 액터로 대체할 수 있습니다. 공백 액터에 적용된 애니메이션 역시 바인딩 일부로 설정한 액터에 적용될 것입니다. + [/REGION] 1. 스크립트 **Sphere** 부분에 대한 예전 단계를 반복, **Cube** 를 **Sphere** 로 **Actor** 에 대체합니다. @@ -147,22 +143,26 @@ XdahqJz2cyM 1. 에디터에서 플레이한 뒤, **1** 키를 눌러 스폰되는 액터를 순환시킵니다. - - ## 최종 결과 에디터에서 플레이하고 1 키를 누르면, 공백 액터가 큐브 또는 구체로 스폰되는 액터로 대체되나, 적용한 애니메이션은 계속 유지됩니다. [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -XdahqJz2cyM -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + XdahqJz2cyM + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] **Set Binding** 노드로 바인딩에 액터 배열을 설정 및 바인딩할 수도, **Reset Binding** 으로 특정 바인딩 또는 **Reset Bindings** 로 전체 레벨 시퀀스 리셋도 가능합니다. diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/CharacterAnimation/CharacterAnimation.CHN.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/CharacterAnimation/CharacterAnimation.CHN.udn index 50b776095f15..c3af42f14b7f 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/HowTo/CharacterAnimation/CharacterAnimation.CHN.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/CharacterAnimation/CharacterAnimation.CHN.udn @@ -1,86 +1,91 @@ -INTSourceChangelist:2997698 +INTSourceChangelist:3439587 Availability:Public -Title:生成角色动画 -Crumbs:%ROOT%, Engine, Engine/Sequencer, Engine/Sequencer/HowTo -Description:说明如何在 Sequencer 中对骨骼网格 Actor 应用动画 -Version:4.12 +Title:动画和动画混合 +Crumbs: %ROOT%, Engine, Engine/Sequencer, Engine/Sequencer/HowTo +Description:说明如何在 Sequencer 中将动画应用到骨架网格体并混合动画。 +Version:4.15 SkillLevel:Intermediate parent:Engine/Sequencer/HowTo order:1 checkpoint: editorqs Related:Engine/Sequencer/Overview Related:Engine\Sequencer\ReferenceEditor\ +tags:Sequencer -在创建过场动画序列时,您有时可能希望让一个角色在场景中四处移动,或演出某些类型的动画。 -在 **Sequencer** 中要做到这一点,可以将骨骼网格 Actor 添加到关卡序列,然后添加一条动画子轨道,并指定您希望该 Actor 演出的动画。 -重复此过程,为 Actor 添加不同类型的演出动画,就能让您的角色在过场动画序列中栩栩如生! +创建影片序列时,有时可能需要角色在场景中四处移动,或者执行一些动画。 +在 **Sequencer** 实现这种效果的方法是为关卡序列添加一个骨架网格体 Actor,然后添加一个动画子轨迹,并指定 Actor 需要执行的动画。 +重复此流程,为 Actor 添加不同类型的动画,使影片序列中的角色活灵活现! -在本指南中我们将创建一个小场景,通过应用不同动画让其中的角色跳上跳下。 +我们将在此指南中创建一个小场景,其中的角色将以行走开始,然后混合到跳跃动画中。 ## 步骤 [REGION:note] -在本操作指南中,我们使用 **Blueprint Third Person Template** 项目,并 **启用了起步内容**。 +在此指南中,我们使用的是启用了 **Starter Content** 的 **Blueprint Third Person Template** 项目。 [/REGION] -1. 在项目打开的情况下,在关卡中选择 **ThirdPersonCharacter**,然后按 **Delete** 删除它。 +1. 点击项目中工具栏下的 **Cinematics** 按钮和 **Add Level Sequence**。 ![](CharacterAnim_01.png) - 这是您在运行此模板附带的游戏时使用的 **角色蓝图**,我们并不需要它。 - -1. 在 **内容浏览器** 中的 **Content/Mannequin/Character/Mesh** 下,将 **SK_Mannequin** 资产拖动到关卡视口中。 +1. 在 **Content Browser** 下的 **Content/Mannequin/Character/Mesh** 中,将 **SK_Mannequin** 拖入关卡。 ![](CharacterAnim_02.png) -1. 在 **工具栏** 中单击 **过场动画(Cinematics)**下拉选项,再选择 **添加关卡序列(Add Level Sequence)**。 +1. 保持 **SK_Mannequin** 的选中状态,点击 Sequencer 中的 **Add** 按钮将其添加到关卡序列。 ![](CharacterAnim_03.png) - 当系统提示时,为新的关卡序列选择保存名称和保存位置。 - -1. 在关卡中选择 **SK_Mannequin**。 - -1. 在 **Sequencer** 窗口中,单击 **添加(Add)**按钮并选择 **添加 Actor 到 Sequencer(Add Actor To Sequencer)**,然后选择 **添加 SK_Mannequin(Add SK_Mannequin)**。 +1. 点击新骨架网格体轨迹中的 **Animation** 按钮,指定 **ThirdPersonWalk** 动画。 ![](CharacterAnim_04.png) - 这会将一条用于 SK_Mannequin 的 **轨道** 添加到 Sequencer,然后我们可以用它操纵场景中的 Actor。 - - ![](CharacterAnim_04b.png) - -1. 在 **动画(Animation)**子轨道上单击 **+** 调出快捷菜单,然后选择 **ThirdPersonIdle**。 +1. 展开 **Animation**,然后将 **时间轴** 拖至第 **30** 帧处。 ![](CharacterAnim_05.png) - 选中 Actor 后,它会摆出闲散的姿态,动画将添加到动画轨道。 - - ![](CharacterAnim_05b.png) - -1. 选择 **动画(Animation)**轨道,然后 **左键单击** 时间轴标记将它拖动到闲散动画的结束处,按 **Enter**。 +1. 再次点击 **Animation** 按钮并添加 **ThirdPersonJump_Start** 动画。 ![](CharacterAnim_06.png) - 这将会在序列中的该时间点添加一个新的 **关键帧**,还会出现一个快捷菜单,您可在其中选择其他动画。 + 现在播放动画会发现两个动画之间存在跳动。 -1. 添加 **ThirdPersonJump_Start** 动画。 + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 640 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 360 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + oHjDpYPAdCo + [/PARAMLITERAL] + [/OBJECT] + + 添加动画时,可以使用加权值在多个动画之间进行混合。这就是处理动画之间跳动的方法。 + +1. 将下方的 **ThirdPersonJump_Start** 动画拖至行走动画下方,并回到序列的第 **25** 帧。 ![](CharacterAnim_07.png) - 在我们当前的设置下,在播放闲散动画后会继续播放开始跳跃动画。您可以将时间轴标记沿着时间轴前后拖动或按视口中的 **播放(Play)**按钮来播放我们当前的场景,预览这段动画。 - -1. 在跳跃开始动画结束时(选中动画轨道的情况下),按 **Enter** 并添加 **ThirdPersonJump_End**。 +1. 展开两个子动画轨迹并点击行走轨迹上的 **add key** 按钮,为跳跃开始动画的值设为 **1.0** 和 **0.0**。 ![](CharacterAnim_08.png) -1. 在跳跃结束动画结束时(选中动画轨道的情况下),按 **Enter** 并添加 **ThirdPersonIdle** 动画。 + 这将关闭跳跃开始动画的播放,因其权重值为 0.0。 + +1. 拖至第 **30** 帧并分别在行走和跳跃动画上添加 **0.0** 和 **1.0** 的键。 ![](CharacterAnim_09.png) + 这将混入跳跃开始动画,混出行走动画。 + +1. 点击 **Preview Play** 按钮观看动画混合。 + ## 最终结果 -当您在视口中单击 **播放(Play)**按钮时,将看到角色跳上跳下。 +现在序列便包含骨架网格体和多个顺畅混合的动画,动画之间不会出现跳动。 [OBJECT:EmbeddedVideo] [PARAMLITERAL:width] @@ -90,44 +95,8 @@ Related:Engine\Sequencer\ReferenceEditor\ 360 [/PARAMLITERAL] [PARAMLITERAL:videoid] -FMZG4yGriqc +kVotxriT1Y4 [/PARAMLITERAL] [/OBJECT] -我们在上面看到了过场动画序列在编辑器中显示的效果。如果我们现在运行游戏,将不会看到任何内容,因为我们还没有向关卡序列本身发出开始播放的命令。 -与 **Matinee** Actor 类似,你可以在关卡中选择关卡序列,然后在 **细节(Details)**面板中选中 **自动播放(Auto Play)**复选框,使序列在加载关卡时播放。 - -![](CharacterAnim_10.png) - -在视频中,您也可以看到在 Sequencer 中是如何处理播放的。只有包含在 **片段边界** 内的内容(绿色和红色标记之间)才会播放。 -您可以拖动这些标记来扩大/缩小序列的边界,或者通过 **Sequencer** 选项,启用 **使播放范围保持在片段边界中(Keep Playback Range In Section Bounds)**选项(如下图所示)来确保播放范围包括所有内容。 - -![](CharacterAnim_11.png) - - - - - - - - - - - - - - - - - - - - - - - - - - - - +还可在此例基础上进行拓展:加入跳跃循环和跳跃结束动画,并将它们混入,使角色能够跳跃和落地。 diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/CharacterAnimation/CharacterAnimation.INT.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/CharacterAnimation/CharacterAnimation.INT.udn index e6e229b23a9a..2b92ef201187 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/HowTo/CharacterAnimation/CharacterAnimation.INT.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/CharacterAnimation/CharacterAnimation.INT.udn @@ -1,6 +1,6 @@ Availability: Public -Title:Animation and Animation Blending -Crumbs: +Title:Animation & Animation Blending +Crumbs: %ROOT%, Engine, Engine/Sequencer, Engine/Sequencer/HowTo Description:Illustrates how you can apply animation to a Skeletal Mesh Actor in Sequencer and blend animations. Version: 4.15 SkillLevel: Intermediate @@ -8,25 +8,22 @@ parent:Engine/Sequencer/HowTo order:1 checkpoint: editorqs Related: Engine/Sequencer/Overview -Related: Engine/Sequencer/ReferenceEditor +Related: Engine\Sequencer\ReferenceEditor\ tags:Sequencer -type:how-to -When creating cinematic sequences, there may be times where you want to have a character in your scene move around or perform some kind of animation. -In **Sequencer**, this can be done by adding a Skeletal Mesh Actor to a Level Sequence, then adding an Animation sub-track, and then specifying the animation that you want the Actor to perform. -Repeating this process and adding different kinds of animations for your Actor to perform is what can bring your characters to life in your cinematic sequences! +When creating cinematic sequences, there may be times where you want to have a character in your scene move around or perform some kind of animation. +In **Sequencer**, this can be done by adding a Skeletal Mesh Actor to a Level Sequence then adding an Animation sub-track and specifying the animation that you want the Actor to perform. +Repeating this process and adding different kinds of animations for your Actor to perform is what can bring your characters to life in your cinematic sequences! -In the following guide, you will create a small scene that starts with a character walking, then blending from walking into a jumping animation. - - +Here in this guide, we will create a small scene that has a character start out walking and blend from a walk into a jump animation. ## Steps [REGION:note] -For this guide, we are using the **Blueprint Third Person Template** project with **Starter Content Enabled**. +For this how-to, we are using the **Blueprint Third Person Template** project with **Starter Content Enabled**. [/REGION] -1. Inside your project, from the Main Toolbar, click the **Cinematics** button, and then click the **Add Level Sequence** button. +1. Inside your project, from the Main Toolbar, click the **Cinematics** button and **Add Level Sequence**. ![](CharacterAnim_01.png) @@ -38,7 +35,7 @@ For this guide, we are using the **Blueprint Third Person Template** project wit ![](CharacterAnim_03.png) -1. Click the **Animation** button on the new Skeletal Mesh Track and assign the **ThirdPersonWalk** Animation Sequence. +1. Click the **Animation** button on the new Skeletal Mesh Track and assign the **ThirdPersonWalk** animation. ![](CharacterAnim_04.png) @@ -64,9 +61,7 @@ For this guide, we are using the **Blueprint Third Person Template** project wit [/PARAMLITERAL] [/OBJECT] - [REGION:tip] When adding animations, you can use the weight value to blend between multiple animations, which is how we will address the pop between animations. - [/REGION] 1. Drag the **ThirdPersonJump_Start** animation below and under the walk animation, back to frame **25** of the sequence. @@ -76,23 +71,20 @@ For this guide, we are using the **Blueprint Third Person Template** project wit ![](CharacterAnim_08.png) - [REGION:note] - This will turn off the playback of the jump start animation since it's weighted value is `0.0`. - [/REGION] + This will effectively turn off the playback of the jump start animation since its weighted value is 0.0. -1. Scrub to frame **30** and add keys for both animations of **0.0** and **1.0** for the walk and jump animations respectively. +1. Scrub to frame **30** and add keys for both animations of **0.0** and **1.0** for the walk and jump animations, respectively. ![](CharacterAnim_09.png) - [REGION:note] - This will blend in the jump start animation and blend out the walk animation. - [/REGION] + This will effectively blend in the jump start animation and blend out the walk animation. + +1. Click the **Preview Play** button to see the animation blending. -1. Finally, click the **Preview Play** button to see the animation blending. ## End Result -Your sequence now includes a Skeletal Mesh with multiple animations of which blend together smoothly instead of popping between animations. +Your sequence now includes a Skeletal Mesh with multiple animations which blend together smoothly instead of popping between animations. [OBJECT:EmbeddedVideo] [PARAMLITERAL:width] @@ -106,33 +98,4 @@ kVotxriT1Y4 [/PARAMLITERAL] [/OBJECT] -If you want to continue working on this example, you can add the jump loop and jump end animations, blending them in so that the character jumps and lands. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +You could continue with this example by adding in the jump loop and jump end animations and blend them in so the character jumps and lands. diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/CharacterAnimation/CharacterAnimation.JPN.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/CharacterAnimation/CharacterAnimation.JPN.udn index 28989f30526f..5caf84bc96aa 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/HowTo/CharacterAnimation/CharacterAnimation.JPN.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/CharacterAnimation/CharacterAnimation.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3267838 +INTSourceChangelist:3439587 Availability:Public Title:アニメーションとアニメーションのブレンド Crumbs: %ROOT%, Engine, Engine/Sequencer, Engine/Sequencer/HowTo @@ -12,9 +12,9 @@ Related:Engine/Sequencer/Overview Related:Engine\Sequencer\ReferenceEditor\ tags:Sequencer -シネマティック シーケンスを作る場合、シーン内でキャラクターを動かしたり、何らかのアニメーションを実行させたいことがあるでしょう。 -**シーケンサー** では、Skeletal Mesh アクタをレベル シーケンスに追加してから、アニメーションのサブトラックを追加し、アクタに行わせたいアニメーションを指定することでこれを行うことができます。 -上記のプロセスを繰り返し、アクタに行わせたい様々なアニメーションを追加することでシネマティック シーケンスでキャラクターが生き生きとしたものになります。 +シネマティック シーケンスを作る場合、シーン内でキャラクターを動かしたり、何らかのアニメーションを実行させたいことがあるでしょう。 +**シーケンサー** では、Skeletal Mesh アクタをレベル シーケンスに追加してから、アニメーションのサブトラックを追加し、アクタに行わせたいアニメーションを指定することでこれを行うことができます。 +上記のプロセスを繰り返し、アクタに行わせたい様々なアニメーションを追加することでシネマティック シーケンスでキャラクターが生き生きとしたものになります。 このガイドでは、キャラクターが歩行を開始し、歩行からジャンプのアニメーションにブレンドする小さなシーンを作ります。 @@ -100,32 +100,3 @@ kVotxriT1Y4 [/OBJECT] このサンプルで作業を続けてアニメーションのジャンプ ループとジャンプ エンドを追加してブレンドし、キャラクターをジャンプさせて、着地させることができます。 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/CharacterAnimation/CharacterAnimation.KOR.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/CharacterAnimation/CharacterAnimation.KOR.udn index f0ef7c0671d9..530b3ae7c636 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/HowTo/CharacterAnimation/CharacterAnimation.KOR.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/CharacterAnimation/CharacterAnimation.KOR.udn @@ -1,6 +1,6 @@ -INTSourceChangelist:3267838 +INTSourceChangelist:3439587 Availability: Public -Title:애니메이션 & 애니메이션 블렌딩 +Title:애니메이션 및 애니메이션 블렌딩 Crumbs: %ROOT%, Engine, Engine/Sequencer, Engine/Sequencer/HowTo Description:시퀀서에서 스켈레탈 메시 액터에 애니메이션을 적용하고 애니메이션을 블렌딩하는 방법을 알아봅니다. Version: 4.15 @@ -21,7 +21,7 @@ tags:Sequencer ## 단계 [REGION:note] -여기서는 **블루프린트 삼인칭 템플릿** 프로젝트에 **시작용 콘텐츠** 포함시킨 것을 사용합니다. +여기서는 **블루프린트 삼인칭 템플릿** 프로젝트에 **시작용 콘텐츠** 를 포함한 것을 사용하고 있습니다. [/REGION] 1. 프로젝트 내 메인 툴바에서 **Cinematics** (시네마틱) 버튼을 클릭하고 **Add Level Sequence** (레벨 시퀀스 추가) 를 선택합니다. @@ -72,7 +72,7 @@ tags:Sequencer ![](CharacterAnim_08.png) - 그러면 점프 시작 애니메이션의 가중치 값은 0.0 이 되어 실제로는 재생이 꺼지는 효과가 납니다. + 그러면 점프 시작 애니메이션의 가중치 값은 0.0 이 되어 사실상 비활성화됩니다. 1. **30** 프레임으로 이동한 뒤 양쪽 애니메이션에 키를 추가합니다. 걷기 애니메이션에는 **0.0**, 점프 애니메이션에는 **1.0** 입니다. @@ -100,32 +100,3 @@ kVotxriT1Y4 [/OBJECT] 점프 루프와 점프 끝 애니메이션을 추가하고 캐릭터가 점프 후 착지하도록 블렌딩하는 식으로 이 예제를 확장해 볼 수도 있습니다. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/SequenceRecorder/SequenceRecorder.CHN.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/SequenceRecorder/SequenceRecorder.CHN.udn index e1ab2a2ac45b..87f59e8261e5 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/HowTo/SequenceRecorder/SequenceRecorder.CHN.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/SequenceRecorder/SequenceRecorder.CHN.udn @@ -1,61 +1,64 @@ -INTSourceChangelist:3007759 +INTSourceChangelist:3322057 Availability:Public -Title:记录游戏 -Crumbs:%ROOT%, Engine, Engine/Sequencer, Engine/Sequencer/HowTo -Description:用序列记录器记录您的游戏运行操作,并将该数据用于 Sequencer 中。 -Version:4.12 +Title:录制到 Sequencer +Crumbs: +Description:使用 Sequence Recorder 录制动作,然后在 Sequencer 中使用数据。 +Version:4.14 SkillLevel:Advanced parent:Engine/Sequencer/HowTo order:1 checkpoint: editorqs Related:Engine/Sequencer/Overview -Related:Engine\Sequencer\ReferenceEditor\ +Related:Engine/Sequencer/ReferenceEditor +tags:Sequencer +type:how-to -**序列记录器** 允许您在游戏运行中捕获指定的 Actor,然后将其另存为新的 **关卡序列**,并可在 **Sequencer** 中编辑。 -这对于快速捕获场景的内容很有用,因为您可以让一个可操纵的角色在游戏运行时执行一些操作,同时用序列记录器进行记录,然后将该数据输入 Sequencer 中,围绕它创建一段过场动画。 - -在这个示例中,我们将使用序列记录器记录我们的可操纵角色的运动,随后我们可以对其进行编辑。 +利用 **Sequence Recorder** 可捕捉关卡编辑或游戏进程中的特定 Actor,可另存为新的 **关卡序列**,并在 **Sequencer** 中进行编辑。 +这可用于快速捕捉场景中的内容。可选取一个可操作角色,在游戏进程中执行一些操作,同时使用 Sequence Recorder 进行录制,然后将数据导入 Sequencer,以此创建动画。 +在此例中,我们将使用 Sequence Recorder 记录可操作角色的动作,然后进行对其进行编辑。 ## 步骤 [REGION:note] -在本操作指南中,我们使用 **Blueprint Third Person Template** 项目,并 **启用了起步内容**。 +在此指南中,我们使用的是启用 **Starter Content** 的 **Blueprint Third Person Template** 项目。 [/REGION] -1. 从 **菜单栏(Menu Bar)**中的 **窗口(Window)**下方,选择 **序列记录器(Sequence Recorder)**。 +1. 在 **窗口** 下的 **菜单栏** 中选中 **Sequence Recorder**。 ![](RecorderStep1.png) - - “序列记录器”(Sequence Recorder)窗口将自动打开。 - **序列记录(Sequence Recording)** 下的一些选项可确定新关卡序列资产的保存方式及保存位置。 - 您可以选择记录产生的 Actor(例如粒子效果和其他角色等等),确定命名约定和保存位置,以及更改其他设置(例如记录持续时间或开始记录前的延迟)。 - -1. 在主编辑器工具栏中,单击 **运行(Play)**开始在编辑器会话中运行。 -1. 进入游戏后,按 **Shift+F1** 取得鼠标控制权。 + Sequence Recorder 窗口将自动打开。**Sequence Recording** 有多个选项,将决定新关卡序列资源的保存方式和路径。可选择记录生成的 Actor(如粒子效果、其他角色等),确定命名规则和保存路径,并变更其他设置(如录制时长或开始录制前的延迟)。 + +1. 在主编辑器工具栏中,点击 **Play** 按钮开始一个编辑器中进行游戏(PIE)会话。 -1. 在 **序列记录器(Sequence Recorder)**窗口上,单击 **添加(Add)**按钮。 +1. 在游戏中按下 **Shift+F1** 组合键进行鼠标控制。 + +1. 点击 **Sequence Recorder** 窗口上的 **Add** 按钮。 ![](SequenceRecorderAdd.png) -1. 单击新记录,然后对于 **要记录的 Actor(Actor to Record)**单击下拉菜单并选择 **ThirdPersonCharacter**。 +1. 点击新录制(为 **空**),然后点击 **Actor to Record** 的下拉菜单并选择 **ThirdPersonCharacter**。 ![](ActorToRecord.png) - 这是开始记录过程前我们指定哪个 Actor 是记录目标的位置。 + 开始录制进程前,我们在此处指定设为目标的 Actor,如上图所示更新 UI。 -1. 单击 **记录(Record)**按钮。 +1. 此外可选择录制音频并沿录制片段设置音频增益级。 + + ![](RecordAudio.png) + + 音频录制需要附带麦克风,将在开始录制序列时同时进行录制。 + +1. 点击 **Record** 按钮。4 秒后(受 Sequence Recording 部分下的 **Record Delay** 选项影响),录制进程开始。 ![](RecordStart.png) - 4 秒钟后(这是“序列记录”(Sequence Recording)部分的 **记录延迟(Record Delay)**选项所设定的),记录过程将开始。 - [REGION:note] - 单击 **记录(Record)**按钮时,还将记录列表中所有已设置为受追踪的 Actor。 + 点击 **Record** 按钮,列表中所有设为被追踪的 Actor 也将被录制。 [/REGION] -1. 使用 **WASD** 和 **空格** 键使角色移动和跳跃,完成后按 **ESC** 键。 +1. 使用 **WASD** 和**空格** 键移动角色并控制其跳跃,然后在完成时按下 **ESC**。 [OBJECT:EmbeddedVideo] [PARAMLITERAL:width] @@ -65,22 +68,17 @@ Related:Engine\Sequencer\ReferenceEditor\ 360 [/PARAMLITERAL] [PARAMLITERAL:videoid] - xo5JRkV3_nI + 9mZI75qBsx8 [/PARAMLITERAL] - [/OBJECT] + [/OBJECT] - 以上是我们记录的序列。但是,如果您的角色还能攻击或执行其他操作,您大可让其做出这些操作。 + 一个新文件夹将在 **Content Browser** 中被创建,其中包含与录制序列相关的资源。 -1. 在 **内容浏览器** 中将创建一个新的文件夹,其中包含与所记录序列相关的资产。 - - ![](RecordedAssets.png) - - 记录完成后,将创建一个包含过场动画数据的 **关卡序列** 资产以及包含动画数据的 **动画序列**。 - + ## 最终结果 -现在您可以打开 **RecordedSequence** 资产,并开始像编辑普通关卡序列一样进行编辑。 +可打开 **RecordedSequence** 资源进行编辑,方法和普通关卡序列并无区别。下方即是我们录制的序列,我们可为其添加镜头和 [镜头切换](Engine/Sequencer/HowTo/TracksCameraCut) 轨迹,构成多个角度、音乐、效果,或需要添加的任意内容。甚至我们还能将此序列作为 [镜头轨迹](Engine/Sequencer/HowTo/TracksShot) 的一部分嵌入其他序列中。 [OBJECT:EmbeddedVideo] [PARAMLITERAL:width] @@ -90,22 +88,28 @@ Related:Engine\Sequencer\ReferenceEditor\ 360 [/PARAMLITERAL] [PARAMLITERAL:videoid] -hR5zBjYO5Oc +1nFX_bpWfy0 [/PARAMLITERAL] [/OBJECT] -以上是我们记录的序列,我们可以在其中添加摄像机和 [**镜头切换**](Engine/Sequencer/HowTo/TracksCameraCut) 轨道,以提供多个角度、音乐、效果或者我们所需的任何内容。 -我们甚至可以将此序列作为 [**镜头轨道**] (Engine/Sequencer/HowTo/TracksShot) 的一部分嵌入到另一个序列中。 +除录制游戏进程外,还可指定一个需要录制的 Actor,录制关卡编辑中的操作。 +[OBJECT:EmbeddedVideo] +[PARAMLITERAL:width] +640 +[/PARAMLITERAL] +[PARAMLITERAL:height] +360 +[/PARAMLITERAL] +[PARAMLITERAL:videoid] +fMzumqLk7IQ +[/PARAMLITERAL] +[/OBJECT] +在上方的视频中,我们在关卡中放置了一个立方体,并指示 Sequence Recorder 对立方体进行录制。 +然后四处移动立方体,Sequence Recorder 将通过新建关卡序列中的关键帧捕捉输入的动作。 +回放关卡序列时,关卡序列中将创建一个新的立方体 Actor(作为可生成物),这是序列启动时为何存在第二个立方体的原因。 - - - - - - - - - - +[REGION:note] +仅限可在关卡编辑进行录制时设置关键帧、进行捕捉和录制的属性。 +[/REGION] diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/SequencerHowTo.INT.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/SequencerHowTo.INT.udn index 7265e9e663fe..675d7bca26d4 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/HowTo/SequencerHowTo.INT.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/SequencerHowTo.INT.udn @@ -3,7 +3,7 @@ Title: Sequencer - How To's Crumbs: %ROOT%, Engine, Engine\Sequencer Description:A How To Guide for creating cinematic sequences with the Sequencer Editor. Related: Engine\Sequencer -version: 4.11 +version: 4.15 tags:Sequencer @@ -27,6 +27,7 @@ Refer to the table below for more information and click each link to view its co [](FANCY:Engine\Sequencer\HowTo\TracksEvent "%Engine\Sequencer\HowTo\TracksEvent:description%") [](FANCY:Engine\Sequencer\HowTo\TracksShot "%Engine\Sequencer\HowTo\TracksShot:description%") [](FANCY:Engine\Sequencer\HowTo\TracksCameraCut "%Engine\Sequencer\HowTo\TracksCameraCut:description%") +[](FANCY:Engine\Sequencer\HowTo\TracksMaterialParameter "%Engine\Sequencer\HowTo\TracksMaterialParameter:description%") [](FANCY:Engine\Sequencer\HowTo\CameraRigCrane "%Engine\Sequencer\HowTo\CameraRigCrane:description%") [](FANCY:Engine\Sequencer\HowTo\CameraRigRail "%Engine\Sequencer\HowTo\CameraRigRail:description%") [](FANCY:Engine\Sequencer\HowTo\CineCameraActors "%Engine\Sequencer\HowTo\CineCameraActors:description%") @@ -39,6 +40,7 @@ Refer to the table below for more information and click each link to view its co ## Advanced [REGION:wrapper transparent] [](FANCY:Engine\Sequencer\HowTo\AnimateDynamicObjects "%Engine\Sequencer\HowTo\AnimateDynamicObjects:description%") +[](FANCY:Engine\Sequencer\HowTo\ActorSequence "%Engine\Sequencer\HowTo\ActorSequence:description%") [](FANCY:Engine\Sequencer\HowTo\TracksSub "%Engine\Sequencer\HowTo\TracksSub:description%") [](FANCY:Engine\Sequencer\HowTo\Spawnables "%Engine\Sequencer\HowTo\Spawnables:description%") [](FANCY:Engine\Sequencer\HowTo\SequenceRecorder "%Engine\Sequencer\HowTo\SequenceRecorder:description%") diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/SequencerHowTo.JPN.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/SequencerHowTo.JPN.udn index 2f64a0a02e3c..360728b75d2d 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/HowTo/SequencerHowTo.JPN.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/SequencerHowTo.JPN.udn @@ -1,10 +1,10 @@ -INTSourceChangelist:3348041 +INTSourceChangelist:3446912 Availability:Public Title:シーケンサーの操作ガイド Crumbs: %ROOT%, Engine, Engine\Sequencer Description:シーケンス エディタでシネマティックス シーケンスを作成するための操作ガイド Related:Engine\Sequencer -version:4.11 +version:4.15 tags:Sequencer @@ -28,6 +28,7 @@ tags:Sequencer [](FANCY:Engine\Sequencer\HowTo\TracksEvent "%Engine\Sequencer\HowTo\TracksEvent:description%") [](FANCY:Engine\Sequencer\HowTo\TracksShot "%Engine\Sequencer\HowTo\TracksShot:description%") [](FANCY:Engine\Sequencer\HowTo\TracksCameraCut "%Engine\Sequencer\HowTo\TracksCameraCut:description%") +[](FANCY:Engine\Sequencer\HowTo\TracksMaterialParameter "%Engine\Sequencer\HowTo\TracksMaterialParameter:description%") [](FANCY:Engine\Sequencer\HowTo\CameraRigCrane "%Engine\Sequencer\HowTo\CameraRigCrane:description%") [](FANCY:Engine\Sequencer\HowTo\CameraRigRail "%Engine\Sequencer\HowTo\CameraRigRail:description%") [](FANCY:Engine\Sequencer\HowTo\CineCameraActors "%Engine\Sequencer\HowTo\CineCameraActors:description%") @@ -40,6 +41,7 @@ tags:Sequencer ## Advanced [REGION:wrapper transparent] [](FANCY:Engine\Sequencer\HowTo\AnimateDynamicObjects "%Engine\Sequencer\HowTo\AnimateDynamicObjects:description%") +[](FANCY:Engine\Sequencer\HowTo\ActorSequence "%Engine\Sequencer\HowTo\ActorSequence:description%") [](FANCY:Engine\Sequencer\HowTo\TracksSub "%Engine\Sequencer\HowTo\TracksSub:description%") [](FANCY:Engine\Sequencer\HowTo\Spawnables "%Engine\Sequencer\HowTo\Spawnables:description%") [](FANCY:Engine\Sequencer\HowTo\SequenceRecorder "%Engine\Sequencer\HowTo\SequenceRecorder:description%") diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/SequencerHowTo.KOR.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/SequencerHowTo.KOR.udn index 8df622a8e38c..345febe1a363 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/HowTo/SequencerHowTo.KOR.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/SequencerHowTo.KOR.udn @@ -1,10 +1,10 @@ -INTSourceChangelist:3348041 +INTSourceChangelist:3446912 Availability: Public Title: 시퀀서 - 안내서 Crumbs: %ROOT%, Engine, Engine\Sequencer Description:시퀀서 에디터로 시네마틱 시퀀스를 제작하는 법에 대한 안내서입니다. Related: Engine\Sequencer -version: 4.11 +version: 4.15 tags:Sequencer @@ -28,6 +28,7 @@ tags:Sequencer [](FANCY:Engine\Sequencer\HowTo\TracksEvent "%Engine\Sequencer\HowTo\TracksEvent:description%") [](FANCY:Engine\Sequencer\HowTo\TracksShot "%Engine\Sequencer\HowTo\TracksShot:description%") [](FANCY:Engine\Sequencer\HowTo\TracksCameraCut "%Engine\Sequencer\HowTo\TracksCameraCut:description%") +[](FANCY:Engine\Sequencer\HowTo\TracksMaterialParameter "%Engine\Sequencer\HowTo\TracksMaterialParameter:description%") [](FANCY:Engine\Sequencer\HowTo\CameraRigCrane "%Engine\Sequencer\HowTo\CameraRigCrane:description%") [](FANCY:Engine\Sequencer\HowTo\CameraRigRail "%Engine\Sequencer\HowTo\CameraRigRail:description%") [](FANCY:Engine\Sequencer\HowTo\CineCameraActors "%Engine\Sequencer\HowTo\CineCameraActors:description%") @@ -40,6 +41,7 @@ tags:Sequencer ## 고급 [REGION:wrapper transparent] [](FANCY:Engine\Sequencer\HowTo\AnimateDynamicObjects "%Engine\Sequencer\HowTo\AnimateDynamicObjects:description%") +[](FANCY:Engine\Sequencer\HowTo\ActorSequence "%Engine\Sequencer\HowTo\ActorSequence:description%") [](FANCY:Engine\Sequencer\HowTo\TracksSub "%Engine\Sequencer\HowTo\TracksSub:description%") [](FANCY:Engine\Sequencer\HowTo\Spawnables "%Engine\Sequencer\HowTo\Spawnables:description%") [](FANCY:Engine\Sequencer\HowTo\SequenceRecorder "%Engine\Sequencer\HowTo\SequenceRecorder:description%") diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksAudio/Audio.INT.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksAudio/Audio.INT.udn index bba19da06b7c..42f193430133 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksAudio/Audio.INT.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksAudio/Audio.INT.udn @@ -10,82 +10,95 @@ checkpoint: editorqs Related: Engine/Sequencer/Overview Related: Engine\Sequencer\ReferenceEditor\ tags:Sequencer +type:how-to -Whether you are looking to score your cinematic with a musical track or want to add sound effects such as impact sounds, voice overs, or others, you'll need to do so with an **Audio Track** inside Sequencer. -Sequencer's Audio Track also allows you to adjust the Volume or Pitch of your audio assets at any point during your cinematic through keyframed value changes. -In this how-to, we add a music track to a sample scene and fade it in over time as well as adjust the pitch during the cinematic. +Whether you are looking to score your cinematic with a musical track, or whether you want to add sound effects (such as impact sounds and voice overs), you'll need to do it with an **Audio Track** inside of **Sequencer**. +Sequencer's Audio Track also enables you to adjust the Volume or Pitch of your audio assets at any point during your cinematic with keyframed value changes. + +In this how-to guide, you'll add a music track to a sample scene and fade it in over time (as well as adjust the pitch during the cinematic). + +![](EndResultImage.png) ## Steps [REGION:note] -For this how-to, we are using the **Blueprint Third Person Template** with **Starter Content** enabled. +For this how-to guide, we are using the **Blueprint Third Person Template** with **Starter Content** enabled. [/REGION] -1. From the Main Tool Bar click **Cinematics** and **Add Level Sequence**. +1. From the Main Tool Bar, click **Cinematics** and **Add Level Sequence**. ![](Audio01.png) -1. In the **Save Asset As** window, choose a save location and save name then click **Save**. +1. In the **Save Asset As** window, choose a save location and save name, then click **Save**. ![](Audio02.png) -1. In the **Level Sequence**, click the **Add** button then select **Audio Track**. +1. In the **Level Sequence**, click the **Add** button, and then select **Audio Track**. ![](Audio03.png) -1. On the **Audio Track**, click the **+** button then search for and add the **Starter_Music_Cue** asset. +1. On the **Audio Track**, click the **+** button, then search for and add the **Starter_Music_Cue** asset. ![](Audio04.png) - You can click the **Expand** icon to expand out and see your audio sub-tracks. + * You can click the **Expand** icon to expand out and see your audio sub-tracks. - ![](Audio05.png) + ![](Audio05.png) - You can add additional sub-tracks to the Audio Track by clicking the **+** button and can drag them along the timeline to reposition them where you want in your sequence. + * You can add additional sub-tracks to the Audio Track by clicking the **+** button. You can then drag the additional sub-tracks along the timeline to reposition them where you want in your sequence. - ![](Audio06.png) + ![](Audio06.png) 1. Expand the **Starter_Music_Cue** track, then change the **Volume** and **Pitch Multiplier** values to **0.0** and add keys for both. ![](Audio07.png) - This will turn the Volume to off and the Pitch to low. + [REGION:note] + This will turn the Volume to off, and set the Pitch to low. + [/REGION] -1. Scrub the Timeline marker ahead to frame **50**, change the **Volume** and **Pitch Multiplier** values to **1.0** and add keys for both. +1. Scrub the Timeline marker (ahead) to frame **50**, change the **Volume** and **Pitch Multiplier** values to **1.0**, and then add keys for both. ![](Audio08.png) - This will turn the Volume up to its default value (on) and the Pitch to its default value (not affecting the sound asset). + [REGION:note] + This will turn the Volume up to its default value (on), and the Pitch to its default value (not affecting the sound asset). + [/REGION] -1. You can delete sub-tracks within the Audio Track by clicking on them in the Timeline window, then pressing **Delete** or **Right-click** and **Delete**. +1. You can delete sub-tracks within the Audio Track by clicking on them in the Timeline window, and then pressing **Delete** (or **Right-click** and **Delete**). ![](Audio09.png) -1. Return the Timeline to **0** then click the **Play** button inside Sequencer to play your sequence. +1. Return the Timeline to **0**, then click the **Play** button inside of Sequencer to play your sequence. ![](Audio10.png) - ## End Result -When you play the Level Sequence, you will hear the audio fade in and the pitch adjusts as the sequence begins. +When you play the Level Sequence, you will hear the audio fade in, with the pitch adjusting as the sequence begins. [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -Tt_fKZnk8I4 -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + Tt_fKZnk8I4 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] -While this example is fairly simplified, you can add more keyframes to fade in/out audio at any point during your sequence or adjust the pitch of audio assets as desired. -Audio Tracks support either **Sound Cue** or **Sound Wave** assets and can be added by dragging-and-dropping from the **Content Browser** into a Level Sequence or by adding through the **Add** option of an Audio Track. - + +While this example is fairly simple, you can add more keyframes to fade in (or fade out) audio at any point during your sequence, or you can adjust the pitch of audio assets as you desire. +Audio Tracks support either **Sound Cue** or **Sound Wave** assets, which can be added by dragging-and-dropping from the **Content Browser** into a Level Sequence, or by adding through the **Add** option of an Audio Track. diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksAudio/Audio.JPN.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksAudio/Audio.JPN.udn index 9b756bb00769..adbeeefc2bec 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksAudio/Audio.JPN.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksAudio/Audio.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3266245 +INTSourceChangelist:3439744 Availability:Public Title:オーディオ トラックで作業する Crumbs: %ROOT%, Engine, Engine/Sequencer, Engine/Sequencer/HowTo @@ -11,11 +11,15 @@ checkpoint: editorqs Related:Engine/Sequencer/Overview Related:Engine\Sequencer\ReferenceEditor\ tags:Sequencer +type:how-to -音楽トラックでシネマティックスに音楽を加えたり、衝撃音などのサウンド エフェクト、ボイス オーバーなどを追加したい場合は、シーケンサー内の **オーディオ トラック** を使用します。 + +音楽トラックでシネマティックスに音楽を加えたり、サウンド エフェクト (衝撃音やボイス オーバーなど) を追加したい場合は、シーケンサー内の **オーディオ トラック** を使用します。 シーケンサーのオーディオ トラックでは、Audio アセットのボリュームやピッチをシネマティックスのどの時点であってもキーフレーム化した値を変更することで調整することができます。 -この操作ガイドでは、サンプル シーンに音楽トラックを追加し、時間の経過とともにフェードインさせたり、シネマティックス中にピッチを調整する方法を説明します。 +この操作ガイドでは、サンプル シーンに音楽トラックを追加し、時間の経過とともにフェードインさせる方法を説明します (シネマティックス中にピッチを調整する方法も説明します)。 + +![](EndResultImage.png) ## ステップ @@ -23,7 +27,7 @@ tags:Sequencer ここでは **Starter Content Enabled (スターター コンテンツを有効にした状態)** で **Blueprint Third Person Template** を使います。 [/REGION] -1. メイン ツールバーから **[Cinematics (シネマティックス)]** をクリックし、[Add Level Sequence (レベル シーケンスを追加)] をクリックします。 +1. メイン ツールバーから **[Cinematics (シネマティックス)]** をクリックし、**[Add Level Sequence (レベル シーケンスを追加)]** をクリックします。 ![](Audio01.png) @@ -39,27 +43,31 @@ tags:Sequencer ![](Audio04.png) - **[Expand]** アイコンをクリックして、展開してオーディオ サブトラックを見ることができます。 + * **[Expand]** アイコンをクリックして、展開してオーディオ サブトラックを見ることができます。 - ![](Audio05.png) + ![](Audio05.png) - **[+]** ボタンをクリックし、サブトラックをオーディオ トラックに追加することができます。それをタイムラインに沿ってドラッグして、シーケンス内で必要とする場所に再配置することができます。 + * **[+]** ボタンをクリックし、サブトラックをオーディオ トラックに追加することができます。それをタイムラインに沿ってドラッグして、シーケンス内で必要とする場所に再配置することができます。 - ![](Audio06.png) + ![](Audio06.png) 1. **Starter_Music_Cue** トラックを拡げます。次に、**[Volume]** と **[Pitch Multiplier]** の値を **0.0** に変更し、両方にキーを追加します。 ![](Audio07.png) + [REGION:note] これで、ボリュームがオフになり、ピッチが低になります。 + [/REGION] -1. タイムライン マーカーを **50** までスクラブします。**[Volume]** と **[Pitch Multiplier]** の値を **1.0** に変更し、両方に対してキーを追加します。 +1. タイムライン マーカーを **50** までスクラブします。**[Volume]** と **[Pitch Multiplier]** の値を **1.0** に変更してから、両方に対してキーを追加します。 ![](Audio08.png) + [REGION:note] これでボリュームがデフォルト値まで上がり、ピッチはそのデフォルト値になります (Sound アセットには影響を与えません)。 + [/REGION] -1. オーディオ トラック内のサブトラックを削除するには、Timeline ウィンドウ内でサブトラックをクリックして、 **[Delete]** を押すか、**右クリック** して **[Delete]** を選ぶと削除することができます。 +1. オーディオ トラック内のサブトラックを削除するには、Timeline ウィンドウ内でサブトラックをクリックして、 **[Delete]** を押す (または **右クリック** して **[Delete]** を選ぶ) と削除することができます。 ![](Audio09.png) @@ -67,23 +75,29 @@ tags:Sequencer ![](Audio10.png) - ## 最終結果 レベル シーケンスを再生する場合、シーケンスが開始するとオーディオがフェードインし、ピッチが調整されます。 [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -Tt_fKZnk8I4 -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + Tt_fKZnk8I4 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] + この例はかなり単純化されていますが、さらに多くのキーフレームを追加して、シーケンスのどの時点でもオーディオをフェードイン、フェードアウトさせたり、必要に応じて Audio アセットのピッチを調整することができます。 オーディオ トラックは、**Sound Cue** または **Sound Wave** のいずれかのアセットをサポートします。これは、**コンテンツ ブラウザ** からレベル シーケンスにドラッグ&ドロップするか、またはオーディオ トラックの **[Add (追加)]** オプションから追加することができます。 @@ -111,6 +125,5 @@ Tt_fKZnk8I4 - diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksAudio/Audio.KOR.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksAudio/Audio.KOR.udn index bf08d34fe778..f6f00fe0928b 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksAudio/Audio.KOR.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksAudio/Audio.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3266245 +INTSourceChangelist:3439744 Availability: Public Title:오디오 트랙 작업 Crumbs: %ROOT%, Engine, Engine/Sequencer, Engine/Sequencer/HowTo @@ -11,12 +11,16 @@ checkpoint: editorqs Related: Engine/Sequencer/Overview Related: Engine\Sequencer\ReferenceEditor\ tags:Sequencer +type:how-to -시네마틱에 배경 음악을 곁들이거나, 음성 더빙 등의 음향 효과를 추가하고자 하는 경우, 시퀀서에서 **Audio Track** (오디오 트랙)을 사용하면 됩니다. + +시네마틱에 배경 음악을 곁들이거나, (충격음 및 음성 더빙 등의) 음향 효과를 추가하고자 하는 경우, **시퀀서** 에서 **Audio Track** (오디오 트랙)을 사용하면 됩니다. 시퀀서의 오디오 트랙에서는 키프레임 설정된 값 변화를 통해 시네마틱 도중 언제든 오디오 애셋의 볼륨 및 피치 값을 조절할 수도 있습니다. 여기서는 샘플 씬에 뮤직 트랙을 추가하고 서서히 페이드 인 시키는 것은 물론 시네마틱 도중 피치 값을 조절해 보겠습니다. +![](EndResultImage.png) + ## 단계 [REGION:note] @@ -39,11 +43,11 @@ tags:Sequencer ![](Audio04.png) - **Expand** (확장) 아이콘을 클릭하여 오디오 서브 트랙을 펼쳐 확인할 수 있습니다. + * **Expand** (확장) 아이콘을 클릭하여 오디오 서브 트랙을 펼쳐 확인할 수 있습니다. ![](Audio05.png) - 오디오 트랙에서 **+** 버튼을 눌러 서브 트랙을 추가한 뒤 타임라인상에서 끌어 보며 시퀀스 내 위치를 재조정할 수 있습니다. + * 오디오 트랙에서 **+** 버튼을 눌러 서브 트랙을 추가한 뒤 타임라인상에서 끌어 보며 시퀀스 내 위치를 재조정할 수 있습니다. ![](Audio06.png) @@ -51,13 +55,17 @@ tags:Sequencer ![](Audio07.png) + [REGION:note] 그러면 볼륨을 끄고 피치를 낮춥니다. + [/REGION] -1. 타임라인 마커를 **50** 프레임 앞으로 문질러 이동시킨 뒤, **볼륨** 과 **피치 배수** 값을 **1.0** 으로 변경하고 둘에 대한 키를 추가합니다. +1. 타임라인 마커를 **50** 프레임(앞)으로 문질러 이동시킨 뒤, **볼륨** 과 **피치 배수** 값을 **1.0** 으로 변경하고 둘에 대한 키를 추가합니다. ![](Audio08.png) + [REGION:note] 그러면 볼륨을 기본값으로 높이고 (켜고) 피치를 기본값으로 (사운드 애셋에 영향을 주지 않도록) 되돌립니다. + [/REGION] 1. 오디오 트랙 내 서브 트랙의 삭제는 타임라인 창에서 서브 트랙을 클릭한 뒤 **Delete** 키 또는 **우클릭** 후 **Delete** (삭제)를 선택하면 됩니다. @@ -67,23 +75,29 @@ tags:Sequencer ![](Audio10.png) - ## 최종 결과 레벨 시퀀스를 재생하면, 시퀀스가 시작되면서 오디오가 페이드 인 되고 피치가 조정되는 것이 들릴 것입니다. [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -Tt_fKZnk8I4 -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + Tt_fKZnk8I4 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] + 이 예제는 꽤나 단순하지만, 키프레임을 추가하여 시퀀스 도중 언제든 원하는 대로 오디오 페이드 인/아웃 또는 피치 조정이 가능합니다. 오디오 트랙은 **사운드 큐** 또는 **사운드 웨이브** 애셋을 지원하며, **콘텐츠 브라우저** 에서 끌어 레벨 시퀀스에 놓거나, 오디오 트랙의 **추가** 옵션을 통해 추가시킬 수 있습니다. @@ -111,6 +125,5 @@ Tt_fKZnk8I4 - diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksEvent/Event.CHN.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksEvent/Event.CHN.udn index ff3157642d46..43c6b747f52d 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksEvent/Event.CHN.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksEvent/Event.CHN.udn @@ -1,116 +1,145 @@ -INTSourceChangelist:2998420 +INTSourceChangelist:3439709 Availability:Public -Title:调用定制事件 -Crumbs:%ROOT%, Engine, Engine/Sequencer, Engine/Sequencer/HowTo -Description:向您说明如何使用事件轨道在蓝图中调用定制事件和脚本。 -Version:4.12 +Title:使用自定义事件和结构体 +Crumbs:%ROOT% +Description:说明如何使用事件轨迹在蓝图中调用带自定义结构体的自定义事件进行使用。 +Version:4.15 SkillLevel:Intermediate parent:Engine/Sequencer/HowTo order:1 checkpoint: editorqs Related:Engine/Sequencer/Overview -Related:Engine\Sequencer\ReferenceEditor\ +Related:Engine/Sequencer/ReferenceEditor +tags:Sequencer +type:how-to -**事件轨道** 可用于在 [**关卡蓝图**](Engine/Blueprints/UserGuide/Types/LevelBlueprint) 中调用 [**定制事件**](Engine/Blueprints/UserGuide/Events/Custom) 和触发 [**蓝图脚本**](Engine/Blueprints)。 -一旦调用定制事件,还会执行所有与其关联的脚本,它们可根据您的需求用于任意数量的场景。 +**事件轨迹** 可用于调用 [自定义事件](Engine/Blueprints/UserGuide/Events/Custom),它能在 [关卡蓝图](Engine/Blueprints/UserGuide/Types/LevelBlueprint) 中发射 [蓝图脚本](Engine/Blueprints)。调用自定义事件后,为其附加的任意脚本也将被执行,可基于需求用于各种情况。使用事件轨迹并调用自定义事件时,也可传递您自己的自定义 [结构体](Engine/Blueprints/UserGuide/Variables/Structs),用于更新其中包含的变量。需要在关卡序列播放中更新其他变量时,它将十分实用。 -在本示例中我们将执行一个事件,它将用于在关卡中激活粒子效果。 +在此例中,我们将使用事件轨迹调用一个自定义结构体的自定义事件,用于在播放序列时移动关卡中的物体。 + + ![](EndResultImage.png) + +在以下指南中,按下键后关卡序列将播放,而每次皆会执行向上移动立方体的事件。 ## 步骤 [REGION:note] -在本操作指南中,我们使用 **Blueprint Third Person Template** 项目,并启用了 **起步内容**。 +在此指南中,我们使用的是启用了 **Starter Content** 的 **Blueprint Third Person Template** 项目。 [/REGION] -1. 在主工具栏中,单击 **过场动画(Cinematics)**按钮,然后单击 **添加关卡序列(Add Level Sequence)**。 +1. 在 **Content Browser** 的 **Content/StarterContent/Shapes** 中,将任意网格体拖入关卡。 ![](EventTrack1.png) - 当系统提示时选择一个保存位置并给关卡序列起个名称。 + 将网格体放置在关卡中任意位置。 -1. 在 Sequencer,中单击 **添加(Add)**按钮,并选择添加 **事件轨道(Event Track)**。 +1. 在网格体的 **Details** 面板中将其设为 **Movable**。 + + ![](EventTrack1b.png) + + 进行此设置后便可在游戏进程中移动网格体。 + +1. 点击 **Add New** 按钮。然后在 **Blueprints** 下选中 **Structure** 选项。 ![](EventTrack2.png) -1. 在该 **事件轨道** 上,将时间轴标记移动到 **75**,然后单击 **+** 号添加一个键。 +1. 输入名称 **MyStruct**,然后打开资源并添加一个名为 **MoveCube** 的 **Vector** 变量。 ![](EventTrack3.png) -1. **右键单击** 该键,然后在 **属性(Properties)**下面为 **值(Value)**输入名称 **MyEvent**。 + [REGION:note] + 此处的变量命名非常重要,因为它们将在以后起到参考指示的作用。 + [/REGION] + +1. 通过 **Cinematics** 按钮新增一个名为 **Master** 的 **关卡序列** 到关卡,然后在 **Sequencer** 中添加一个 **事件轨迹**。 ![](EventTrack4.png) - 您在此处提供的名称是您创建要调用的 **定制事件** 时 **必须** 使用的名称。 - -1. 在 **内容浏览器** 中的 **StarterContent/Particles** 下,将 **P_Explosion** 拖动到关卡中。 +1. 将时间轴移至第 **5** 帧并添加一个键,然后右键点击键将事件命名为 **LiftCube**。然后指定 **MyStruct** 并将 **Z 轴** 值设为 **100**。 ![](EventTrack5.png) -1. 选择 **P_Explosion** 资产后,在 **细节(Details)**面板中取消选中 **自动激活(Auto Activate)**选项。 + 到达序列中的这个关键帧时,我们将把网格体沿 Z 轴上移 100 个单位。 + +1. 移动时间轴到第 **10** 帧,然后按下 **]** 键让序列在第 10 帧处结束。 ![](EventTrack6.png) - 这将确保粒子效果不在关卡启动时播放。 - -1. 在仍然选中 **P_Explosion** 资产的情况下,在工具栏中单击 **蓝图(Blueprints)**按钮,然后选择 **打开关卡蓝图(Open Level Blueprint)**。 +1. 选中添加的网格体(以及关卡中的关卡序列),然后点击工具栏中的 **Blueprints** 按钮,最后选中 **Open Level Blueprint**。 ![](EventTrack7.png) -1. 在 **关卡蓝图(Level Blueprint)**中,**右键单击** 并选择 **创建对 P_Explosion 的引用(Create a Reference to P_Explosion)**。 +1. 在 **关卡蓝图** 中点击右键并搜索 **Reference**,然后选择 **Create References to 2 selected Actors**。 ![](EventTrack8.png) -1. 在图中再次 **右键单击**,然后就搜索并添加一个 **定制事件(Custom Event)**节点,将它命名为 **MyEvent**(与 **第 4 步** 中相同)。 +1. 在图表中点击右键并添加一个 **1** 键盘事件,然后从 **Master** 关卡序列连出引线,搜索并添加 **Set Playback Position** 节点。 ![](EventTrack9.png) - - [REGION:note] - 这必须是您在步骤 4 中输入的文本值。您可在节点上按 **F2** 键,以将其重命名。 - [/REGION] -1. **左键单击** **P_Explosion** 节点并拖出,然后搜索并添加 **激活 (ParticleSystemComponent)(Activate (ParticleSystemComponent))**节点。 + [REGION:note] + 它将用于开始播放时、发出播放函数调用前重设序列。 + [/REGION] + +1. 从添加的 **Sequence Player** 节点连出引线,然后使用 **Play** 节点,按下图所示进行连接。 ![](EventTrack10.png) -1. 将 **定制事件** 节点连接到 **激活** 节点,如下图所示。 +1. 在图表中点击右键并创建一个名为 **LiftCube** 的 **自定义事件**。 ![](EventTrack11.png) - 调用该事件时,它将激活(开启)我们放在关卡中的粒子效果。 + [REGION:warning] + 自定义事件的命名必须和在 **Event Name** 下为 Sequencer 中的键指定的命名相同(否则它将无法被调用)。 + [/REGION] -1. 在主编辑器窗口中,从 **全局大纲(World Outliner)**选择您的关卡序列,然后在 **细节(Details)**中启用 **自动播放(Auto Play)**。 +1. 在自定义事件的 **Details** 面板中,点击 **+** 按钮添加一个输入,将其命名设为 **MoveCube**、变量类型设为 **Vector**。 ![](EventTrack12.png) - 当我们在此关卡中播放时,此关卡序列将自动播放并触发效果。 + [REGION:warning] + 如未满足以下条件,则事件不会被调用: + * 输入命名必须和结构体中使用的命名相同。 + * 输入的数字必须和自定义结构体中定义的变量数相同。 + + 例如,如结构体中有 2 个变量,那么自定义事件必须拥有 2 个带正确变量名和类型的输入。 + [/REGION] + +1. 从网格体参考连出引线,搜索并使用 **AddActorLocalOffset** 节点。 -1. 在主工具栏中单击 **播放(Play)**按钮在编辑器中播放。 + ![](EventTrack13.png) + +1. 按下图所示,将 **MoveCube** 矢量引脚连至 **Delta Location** 引脚、**LiftCube** 可执行引脚连至 **AddActorLocalOffset** 节点。 + + ![](EventTrack14.png) + +1. 在主工具栏中点击 **Play** 按钮进入 Play in Editor(PIE)模式。 ## 最终结果 -在编辑器中播放几秒后,爆炸效果就会激活。 +在编辑器中进行游戏时,每次按下 **1** 键立方体都会沿 **Z** 轴移动。 + [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -krFTHenh9zw -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + wlLcUr8BXvY + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] -在上面的视频中,我们还展示了在 Sequencer 中单击 **播放(Play)**按钮时不会执行脚本。 -在播放关卡序列时,您无法预览在游戏运行中从事件轨道调用脚本事件。 - - - - - - +在此例中我们并未指定摄像机查看影片,而是使用 Sequencer 和蓝图执行已编辑脚本的序列。在项目中,带自定义事件和自定义结构体的事件轨迹可用于更新过场动画中的玩家信息(如玩家体力增加、获得新武器,或用户选择的其他游戏性相关的效果)。 diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksEvent/Event.INT.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksEvent/Event.INT.udn index 24c004696371..34d37cb63d0b 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksEvent/Event.INT.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksEvent/Event.INT.udn @@ -1,6 +1,6 @@ Availability: Public Title:Using Custom Events and Structs -Crumbs: +Crumbs:%ROOT% Description:Shows how you can use the Event Track to call Custom Events with Custom Structs for use in Blueprint. Version: 4.15 SkillLevel: Intermediate @@ -10,47 +10,38 @@ checkpoint: editorqs Related: Engine/Sequencer/Overview Related: Engine/Sequencer/ReferenceEditor tags:Sequencer +type:how-to -The **Event Track** can be used to call [Custom Events](Engine/Blueprints/UserGuide/Events/Custom) and fire off [Blueprint Script](Engine/Blueprints) inside the [Level Blueprint](Engine/Blueprints/UserGuide/Types/LevelBlueprint). -Once the Custom Event is called, any script attached to it will also be executed and can be used for any number of scenarios based on your needs. -When using the Event Track and calling a Custom Event, you can also pass through your own Custom [Struct](Engine/Blueprints/UserGuide/Variables/Structs) which can be used to update the variables contained within. +The **Event Track** can be used to call [Custom Events](Engine/Blueprints/UserGuide/Events/Custom), which fire off [Blueprint Scripts](Engine/Blueprints) inside of [Level Blueprints](Engine/Blueprints/UserGuide/Types/LevelBlueprint). +When the Custom Event is called, any script attached to it will also be executed and can be used for any number of scenarios based on your needs. +When using the Event Track and calling a Custom Event, you can also pass your own Custom [Struct](Engine/Blueprints/UserGuide/Variables/Structs), which can be used to update the variables contained therein. This can be useful in situations where you want to update other variables during the playback of a level sequence. In this example, we will use the Event Track to call a Custom Event with a Custom Struct that is used to move an object in the level when the sequence plays. -[OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -wlLcUr8BXvY -[/PARAMLITERAL] -[/OBJECT] + ![](EndResultImage.png) -In the example above, when we press a key, the level sequence plays and our event to move the cube upwards is executed each time. +In the following how-to guide, when we press a key, the level sequence plays, and our event to move the cube upwards is executed each time. ## Steps [REGION:note] -For this how-to, we are using the **Blueprint Third Person Template** project with **Starter Content** enabled. +For this how-to guide, we are using the **Blueprint Third Person Template** project with **Starter Content** enabled. [/REGION] 1. From the **Content Browser** under the **Content/StarterContent/Shapes** folder, drag any mesh into the level. ![](EventTrack1.png) - Position the mesh anywhere inside the level. + Position the mesh anywhere inside of the level. 1. In the **Details** panel for your mesh, set the mesh to **Movable**. ![](EventTrack1b.png) - This will allow us to move the mesh during gameplay. + This will enable us to move the mesh during gameplay. -1. Click the **Add New** button, then under **Blueprints**, select the **Structure** option. +1. Click the **Add New** button. Then, under **Blueprints**, select the **Structure** option. ![](EventTrack2.png) @@ -58,13 +49,15 @@ For this how-to, we are using the **Blueprint Third Person Template** project wi ![](EventTrack3.png) - Naming of your variables is important here as these names will need to be used when you want to reference them later. + [REGION:note] + The naming of your variables is important here because these names will need to be used when you want to reference them later. + [/REGION] -1. Add a new **Level Sequence** from the **Cinematics** button called **Master** to the level, then inside **Sequencer** add an **Event Track**. +1. Add a new **Level Sequence** from the **Cinematics** button called **Master** to the level, then inside **Sequencer**, add an **Event Track**. ![](EventTrack4.png) -1. Move the timeline to frame **5** and add a key, then **Right-click** the key and name the event **LiftCube**, assign **MyStruct** and set the **Z** value to **100**. +1. Move the timeline to frame **5** and add a key, then right-click the key and name the event **LiftCube**. Now, assign **MyStruct** and set the **Z** value to **100**. ![](EventTrack5.png) @@ -74,78 +67,83 @@ For this how-to, we are using the **Blueprint Third Person Template** project wi ![](EventTrack6.png) -1. Select your mesh that you added and the Level Sequence in the level, then click the **Blueprints** button from the toolbar and select **Open Level Blueprint**. +1. Select the mesh that you added (along with the Level Sequence in the level), and then click the **Blueprints** button from the toolbar, ultimately selecting **Open Level Blueprint**. ![](EventTrack7.png) -1. In the **Level Blueprint**, **Right-click** and search for **Reference** then select **Create Reference to 2 selected Actors**. +1. In the **Level Blueprint**, right-click and search for **Reference**, then select **Create References to 2 selected Actors**. ![](EventTrack8.png) -1. **Right-click** in the graph and add a **1** Keyboard Event, then drag off your **Master** Level Sequence and search for and add the **Set Playback Position** node. +1. Right-click in the graph and add a **1** Keyboard Event, then drag off your **Master** Level Sequence, searching for and adding the **Set Playback Position** node. ![](EventTrack9.png) - This will be used to reset our sequence whenever we start to play it before we actually issue a play function call. + [REGION:note] + This will be used to reset your sequence whenever you start to play it before issuing a play function call. + [/REGION] -1. Drag off the **Sequence Player** node that is added and use the **Play** node and connect as shown below. +1. Drag off the **Sequence Player** node being added, and use the **Play** node, connecting as shown below. ![](EventTrack10.png) -1. **Right-click** in the graph and create a **Custom Event** called **LiftCube**. +1. Right-click in the graph and create a **Custom Event** called **LiftCube**. ![](EventTrack11.png) [REGION:warning] - Your Custom Event name must be the same name that is specified under **Event Name** for your key in Sequencer or it will not get called. + Your Custom Event name must be the same name that is specified under **Event Name** for your key in Sequencer (or it will not get called). [/REGION] -1. In the **Details** panel for the Custom Event, click the **+** button to add an input and name it **MoveCube** with the variable type of **Vector**. +1. In the **Details** panel for the Custom Event, click the **+** button to add an input, naming it **MoveCube** with the variable type of **Vector**. ![](EventTrack12.png) [REGION:warning] - Your Input names must be the same names that are used in your Struct or the event will not get called. - Also, the number of inputs must match the number of variables defined in your custom struct or the event will not get called. - For example, if you struct has 2 variables in it, your Custom Event must have 2 inputs with the correct variable names and types. + The event will not be called if the following conditions aren't met: + * The Input names must be the same names that are used in your Struct. + * The number of inputs must match the number of variables defined in your custom struct. + + For example, if your struct has 2 variables in it, your Custom Event must have 2 inputs with the correct variable names and types. [/REGION] -1. Drag off your mesh reference and search for and use the **AddActorLocalOffset** node. +1. Drag off your mesh reference, search for and use the **AddActorLocalOffset** node. ![](EventTrack13.png) -1. Connect the **MoveCube** vector pin to the **Delta Location** pin and the **LiftCube** executable to the **AddActorLocalOffset** node as shown below. +1. Connect the **MoveCube** vector pin to the **Delta Location** pin, and the **LiftCube** executable pin to the **AddActorLocalOffset** node as shown below. ![](EventTrack14.png) -1. Click the **Play** button from the Main Toolbar to play in the editor. +1. Click the **Play** button from the Main Toolbar to enter Play in Editor (PIE) mode. ## End Result -When playing in the editor, each time you press the **1** key, the cube will move up along the **Z** axis. +When playing your game in the editor, each time you press the **1** key, the cube will move along the **Z** axis. + [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -wlLcUr8BXvY -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + wlLcUr8BXvY + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] -In this example we are not assigning a camera to view our cinematic from but instead are using Sequencer and Blueprint to perform scripted sequences. -In your projects, an Event Track with a Custom Event and Custom Struct can be used to update player information during a cutscene (such as the player receiving a health increase, new weapon, or other gameplay related effects of your choosing). - - - - - - - +In this example, we are not assigning a camera to view our cinematic from but instead are using Sequencer and Blueprint to perform scripted sequences. +In your projects, an Event Track with a Custom Event and Custom Struct can be used to update player information during a cutscene (such as the player +receiving a health increase, new weapon, or other gameplay related effects of your choosing). diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksEvent/Event.JPN.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksEvent/Event.JPN.udn index 7a44948bca55..68a46a6f7464 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksEvent/Event.JPN.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksEvent/Event.JPN.udn @@ -1,7 +1,7 @@ -INTSourceChangelist:3340363 +INTSourceChangelist:3439709 Availability:Public Title:カスタム イベントとカスタム構造体を使用する -Crumbs: %ROOT%, Engine, Engine/Sequencer, Engine/Sequencer/HowTo +Crumbs:%ROOT% Description:イベント トラックを使ってブループリントで使用するためにカスタム構造体を持ったカスタム イベントを呼び出す方法を説明します。 Version:4.15 SkillLevel:Intermediate @@ -9,34 +9,25 @@ parent:Engine/Sequencer/HowTo order:1 checkpoint: editorqs Related:Engine/Sequencer/Overview -Related:Engine\Sequencer\ReferenceEditor\ +Related:Engine/Sequencer/ReferenceEditor tags:Sequencer +type:how-to -**イベント トラック** を使用して [**カスタム イベント**](Engine/Blueprints/UserGuide/Events/Custom) を呼び出し、[**レベル ブループリント**](Engine/Blueprints/UserGuide/Types/LevelBlueprint) 内で [**ブループリント スクリプト**] (Engine/Blueprints) を実行します。 +**イベント トラック** を使って [カスタム イベント](Engine/Blueprints/UserGuide/Events/Custom) を呼び出すことができます。カスタム イベントは [Level ブループリント](Engine/Blueprints/UserGuide/Types/LevelBlueprint) 内の [ブループリント スクリプト](Engine/Blueprints) を実行します。 カスタム イベントが呼び出されると、それにアタッチされたスクリプトも実行され、ニーズに応じて任意の数のシナリオで使用することができます。 -イベント トラックを使用してカスタム イベントを呼び出す場合、その中の変数を更新するために使うカスタム [構造体](Engine/Blueprints/UserGuide/Variables/Structs) もパススルーすることができます。 +イベント トラックを使用してカスタム イベントを呼び出す場合、その中の変数を更新するために使うカスタム [構造体](Engine/Blueprints/UserGuide/Variables/Structs) も渡すことができます。 これはレベル シーケンスの再生中に他の変数を更新するような場合に便利です。 この例では、イベント トラックを使ってカスタム構造体を持つカスタム イベントを呼び出します。これは、シーケンス再生時にレベル内でオブジェクトを動かすために使用します。 -[OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -wlLcUr8BXvY -[/PARAMLITERAL] -[/OBJECT] + ![](EndResultImage.png) -上の例では、キーを押すと、レベル シーケンスが再生し、キューブを上方向に動かすイベントが毎回実行されます。 +上の操作ガイドでは、キーを押すと、レベル シーケンスが再生し、キューブを上方向に動かすイベントが毎回実行されます。 ## ステップ [REGION:note] -ここでは **Starter Content Enabled (スターター コンテンツを有効にした状態)** で **Blueprint Third Person Template** プロジェクトを使います。 +ここでは **Starter Content** を有効にした状態で **Blueprint Third Person Template** を使います。 [/REGION] 1. **コンテンツ ブラウザ** の、**Content/StarterContent/Shapes** フォルダで、任意のメッシュをレベルにドラッグします。 @@ -51,7 +42,7 @@ wlLcUr8BXvY これで、ゲームプレイ中にメッシュをお好きな位置に動かすことができます。 -1. **[Add New (新規追加)]** ボタンをクリックしたら **[Blueprints]** で **[Structure]** オプションを選択します。 +1. **[Add New]** ボタンをクリックします。**[Blueprints]** で **[Structure]** オプションを選択します。 ![](EventTrack2.png) @@ -59,13 +50,15 @@ wlLcUr8BXvY ![](EventTrack3.png) + [REGION:note] 変数の命名は重要です。後で参照する場合、こうした名前を使うことになるからです。 + [/REGION] 1. **[Cinematics]** ボタンから **Master** という新規 **レベル シーケンス** をレベルに追加します。**シーケンサー** 内で、**イベント トラック** を追加します。 ![](EventTrack4.png) -1. タイムラインをフレーム **5** まで動かし、キーを追加します。次に、 そのキーを **右クリック** し、イベントに **LiftCube** と名前を付け、 **MyStruct** を割り当て、 **Z** 値を **100** に設定します。 +1. タイムラインをフレーム **5** まで動かし、キーを追加します。次に、 そのキーを右クリック し、イベントに **LiftCube** と名前を付けます。**MyStruct** を割り当て、 **Z** 値を **100** に設定します。 ![](EventTrack5.png) @@ -75,30 +68,32 @@ wlLcUr8BXvY ![](EventTrack6.png) -1. 追加したメッシュとレベル シーケンスをレベルで選択し、ツールバーから **[Blueprints]** ボタンをクリックして、**[Open Level Blueprint]** をクリックします。 +1. 追加したメッシュを (レベルのレベル シーケンスと共に) 選択し、ツールバーから **[Blueprints]** ボタンをクリックして、**[Open Level Blueprint]** をクリックします。 ![](EventTrack7.png) -1. **Level ブループリント** で、**右クリック** して、 **[Reference]** を検索し、**[Create Reference to 2 selected Actors]** を選択します。 +1. **Level ブループリント** で、右クリックして、 **[Reference]** を検索し、**[Create References to 2 selected Actors]** を選択します。 ![](EventTrack8.png) -1. グラフ内を **右クリック** して、**1** Keyboard Event を追加して、**Master** レベル シーケンスからドラッグして、**Set Playback Position** ノードを検索して追加します。 +1. グラフ内を右クリックして、**1** Keyboard Event を追加して、**Master** レベル シーケンスからドラッグして、**Set Playback Position** ノードを検索して追加します。 ![](EventTrack9.png) - これは、再生を開始する度に実際に再生の関数呼び出しを発行する前に、シーケンスをリセットするために使用されます。 + [REGION:note] + これは、再生の関数呼び出しを発行する前に、再生を開始する度にシーケンスをリセットするために使用されます。 + [/REGION] -1. 追加した **Sequence Player** ノードから、 **Play** ノードを使用し、以下のように接続します。 +1. 追加した **Sequence Player** ノードからドラッグして、 **Play** ノードを使用し、以下のように接続します。 ![](EventTrack10.png) -1. グラフ内を **右クリック** して、 **LiftCube** と呼ばれる **カスタム イベント** を作成します。 +1. グラフ内を右クリックして、 **LiftCube** と呼ばれる **カスタム イベント** を作成します。 ![](EventTrack11.png) [REGION:warning] - カスタム イベント名は、シーケンサーのキーの **Event Name** で指定したものと同じ名前でなければなりません。そうしないと呼び出されません。 + カスタム イベント名は、シーケンサーのキーの **Event Name** で指定したものと同じ名前でなければなりません (そうしないと呼び出されません)。 [/REGION] 1. Custom Event の **[Details]** パネルで、 **+** ボタンをクリックして入力を追加し、**MoveCube** と名前を付け、変数の型は **Vector** にします。 @@ -106,8 +101,10 @@ wlLcUr8BXvY ![](EventTrack12.png) [REGION:warning] - 入力名は Struct (構造体) で使ったものと同じ名前でなければなりません。そうしないと、イベントは呼び出されません。 - さらに、入力数はカスタム構造体で定義した変数の数と一致しなければなりません。そうしないとイベントは呼び出されません。 + 以下の条件を満たさなければイベントは呼び出されません。 + * 入力名は Struct (構造体) で使ったものと同じ名前でなければなりません。 + * 入力数はカスタム構造体で定義した変数の数と一致しなければなりません。 + 例えば、構造体が 2 つの変数を持つ場合、カスタム イベントは正しい変数名と型を持つ 2 つの入力を持たなければなりません。 [/REGION] @@ -119,34 +116,35 @@ wlLcUr8BXvY ![](EventTrack14.png) -1. メイン ツールバーで **Play** ボタンをクリックしてエディタで再生します。 +1. メイン ツールバーで **Play** ボタンをクリックして Play in Editor (PIE) モードにします。 ## 最終結果 エディタで再生する場合、**1** キーを押すたびに、キューブが **Z** 軸に沿って上方向に移動します。 + [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -wlLcUr8BXvY -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + wlLcUr8BXvY + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] この例では、シネマティックスを見るためにカメラを割り当てていませんが、代わりにシーケンサーとブループリントを使ってスクリプティングしたシーケンスを実行しています。 -プロジェクトでは、カスタム イベントとカスタム構造体を持つイベント トラックを使ってカットシーン中にプレイヤー情報を更新することができます (プレイヤーが、ヘルスの増加、新しい武器、選択したその他のゲームプレイ関連のエフェクトを受け取るなど)。 - - - - - - - +プロジェクトでは、カスタム イベントとカスタム構造体を持つイベント トラックを使ってカットシーン中にプレイヤー情報を更新することができます + (プレイヤーが、ヘルスの増加、新しい武器、選択したその他のゲームプレイ関連のエフェクトを受け取るなど)。 diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksEvent/Event.KOR.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksEvent/Event.KOR.udn index 751cc057a07a..15d97eb79739 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksEvent/Event.KOR.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksEvent/Event.KOR.udn @@ -1,7 +1,7 @@ -INTSourceChangelist:3340363 +INTSourceChangelist:3439709 Availability: Public -Title:커스텀 이벤트 & 커스텀 구조체 -Crumbs: %ROOT%, Engine, Engine/Sequencer, Engine/Sequencer/HowTo +Title:커스텀 이벤트 및 커스텀 구조체 +Crumbs:%ROOT% Description:이벤트 트랙을 사용하여 블루프린트에서 사용할 커스텀 구조체를 가진 커스텀 이벤트 호출 방법을 보여드립니다. Version: 4.15 SkillLevel: Intermediate @@ -9,8 +9,9 @@ parent:Engine/Sequencer/HowTo order:1 checkpoint: editorqs Related: Engine/Sequencer/Overview -Related: Engine\Sequencer\ReferenceEditor\ +Related: Engine/Sequencer/ReferenceEditor tags:Sequencer +type:how-to **Event Track** (이벤트 트랙)은 [**레벨 블루프린트**](Engine/Blueprints/UserGuide/Types/LevelBlueprint) 안에서 [**커스텀 이벤트**](Engine/Blueprints/UserGuide/Events/Custom) 호출 및 [**블루프린트 스크립트**](Engine/Blueprints) 를 발동시키는 데 사용될 수 있습니다. 커스텀 이벤트가 호출되면, 거기에 붙은 스크립트 역시도 실행되며, 필요에 따라 어떤 경우의 수만큼도 사용 가능합니다. @@ -19,17 +20,7 @@ tags:Sequencer 이 예제에서는 이벤트 트랙을 사용하여 시퀀스 재생 시 레벨에서 오브젝트를 이동시키는 데 사용되는 커스텀 구조체 포함 커스텀 이벤트를 호출합니다. -[OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -wlLcUr8BXvY -[/PARAMLITERAL] -[/OBJECT] + ![](EndResultImage.png) 위 예제에서 키를 누르면 레벨 시퀀스가 재생되고 이벤트가 한 번 실행될 때마다 큐브가 위로 이동합니다. @@ -59,7 +50,9 @@ wlLcUr8BXvY ![](EventTrack3.png) + [REGION:note] 여기서 변수 이름이 중요한데, 나중에 이 이름을 사용하여 레퍼런스를 지정할 것이기 때문입니다. + [/REGION] 1. **시네마틱** 버튼에서 **Master** 라는 **레벨 시퀀스** 를 새로 추가한 뒤, **시퀀서** 안에서 **이벤트 트랙** 을 추가합니다. @@ -87,7 +80,9 @@ wlLcUr8BXvY ![](EventTrack9.png) + [REGION:note] 그러면 플레이를 시작할 때마다 시퀀스를 리셋시켜 실제 재생 함수 호출을 내릴 수 있습니다. + [/REGION] 1. 추가한 **Sequence Player** 노드를 끌어놓고 **Play** 노드를 사용하여 아래와 같이 연결합니다. @@ -106,8 +101,10 @@ wlLcUr8BXvY ![](EventTrack12.png) [REGION:warning] - 입력 이름이 구조체에 사용된 이름과 같아야 합니다. 그렇지 않으면 이벤트가 호출되지 않습니다. - 또한 입력 수가 커스텀 구조체에 정의된 변수 개수와 일치해야 합니다. 그렇지 않으면 이벤트는 호출되지 않습니다. + 이벤트 호출을 위한 조건은 다음과 같습니다: + * 입력 이름이 구조체에 사용된 이름과 같아야 합니다. + * 입력 수가 커스텀 구조체에 정의된 변수 개수와 일치해야 합니다. + 예를 들어, 구조체 안에 변수가 둘 있는 경우, Custom Event 역시 올바른 변수 이름과 유형의 입력이 둘 있어야 합니다. [/REGION] @@ -126,27 +123,28 @@ wlLcUr8BXvY 에디터에서 플레이하면, **1** 키를 누를 때마다 큐브가 **Z** 축으로 올라갈 것입니다. + [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -wlLcUr8BXvY -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + wlLcUr8BXvY + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] 이 예제에서는 시네마틱을 확인할 카메라를 할당하지 않은 대신 시퀀서와 블루프린트를 사용하여 스크립트 시퀀스를 수행하고 있습니다. -프로젝트에서는 커스텀 이벤트 및 커스텀 구조체와 함께 이벤트 트랙을 사용하여 컷씬 도중 (플레이어가 생명령 증가, 새 무기, 기타 게임플레이 관련 효과 등) 플레이어 정보를 업데이트할 수 있습니다. - - - - - - - +프로젝트에서는 커스텀 이벤트 및 커스텀 구조체와 함께 이벤트 트랙을 사용하여 컷씬 도중 (플레이어가 생명령 증가, 새 무기, 기타 게임플레이 관련 효과 등) +플레이어 정보를 업데이트할 수 있습니다. diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksMaterialParameter/MaterialParameterTrack.CHN.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksMaterialParameter/MaterialParameterTrack.CHN.udn new file mode 100644 index 000000000000..eb4bac38b267 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksMaterialParameter/MaterialParameterTrack.CHN.udn @@ -0,0 +1,154 @@ +INTSourceChangelist:0 +Availability: Public +Title: Animating Material Parameter Collections +Crumbs: %ROOT%, Engine, Engine/Sequencer, Engine/Sequencer/HowTo +Description:Describes how you can update Material Parameter Collections within Sequencer. +Version: 4.16 +SkillLevel: Intermediate +parent:Engine/Sequencer/HowTo +order:1 +topic-image: EndResult.png +checkpoint: editorqs +Related: Engine/Sequencer/Overview +Related: Engine/Rendering/Materials/ParameterCollections +Related: Engine/Rendering/Materials +tags:Sequencer +type:how-to + +Sequencer provides a special **Material Parameter Collection** track for working with and animating [](Engine/Rendering/Materials/ParameterCollections). +This is extremely useful if you have several Materials that you need to update as you no longer have to animate individual parameter values on each material instance in order to share animation. + +In this how-to guide, you'll create a Material Parameter Collection and update its values through Sequencer causing any Materials that use the collection to pulsate between colors. + +![](EndResult.png) + +## Steps + +[REGION:note] +For this how-to guide, we are using the **Blueprint Third Person Template** with **Starter Content** enabled. +[/REGION] + +1. With your project open, in the **Content/Mannequin/Character/Materials** folder, open the **M_UE4Man_Body** Material. + + ![](MPCTrack01.png) + +1. In the **Graph** select the **BodyColor** parameter, then in the **Details** panel, **Right-click** and **Copy** the **Default Value** under **Material Expression Vector Parameter**. + + ![](MPCTrack02.png) + + We are going to use this value as the Default Value in our Material Parameter Collection asset. + +1. From the **Content Browser**, click the **Add New** button and under **Materials & Textures** select **Material Parameter Collection** and call it **Sample_MPC**. + + ![](MPCTrack03.png) + +1. Inside **Sample_MPC**, add a **Vector Parameter** called **Example** and for the **Default Value**, **Right-click** and **Paste** the copied values. + + ![](MPCTrack04.png) + +1. Back in the **M_UE4Man_Body** Material, **Right-click** and add a **CollectionParameter** node with **Collection** set to **Sample_MPC** and **Parameter Name** set to **Example**. + + ![](MPCTrack05.png) + +1. Connect the **Example** Collection Parameter node to nodes marked **1** and **2** below. + + ![](MPCTrack06.png) + +1. From the Main Editor Toolbar, click the **Cinematics** button and select **Add Level Sequence** and choose a name and save location. + + ![](MPCTrack07.png) + +1. In the **Details** panel for the new sequence, check the **Auto Play** option and **Loop Indefinitely**. + + ![](MPCTrack08.png) + +1. In Sequencer, click the **Add** button and select **Material Parameter Collection Track** then **Sample_MPC**. + + ![](MPCTrack09.png) + + Any Material Parameter Collection assets you have created will be displayed in the roll-out window when choosing the Material Parameter Collection Track. + +1. On the **Sample_MPC** track, click the **Parameter** button and add the **Example** vector track. + + ![](MPCTrack10.png) + + This corresponds to parameter name defined within the Material Parameter Collection asset, any other defined parameters will be displayed from the drop-down menu. + +1. Scrub the timeline ahead to frame **75** then add keys for **Red (1.0)**, **Green (0.0)** and **Blue (0.0)**. + + ![](MPCTrack11.png) + +1. **Left-click** and drag a selection box around the keys at frame 0, then press **Ctrl+C** to copy them. + + ![](MPCTrack12.png) + +1. Scrub the timeline ahead to frame **150** then press **Ctrl+V** to paste the copied keys. + + ![](MPCTrack13.png) + + This will set the Material Parameter Collection back to its Default Value. + +1. From the Main Editor Toolbar, click the **Play** button to play in the editor. + + +## End Result + +When you play in the level, the character will continually pulsate between the default color and a red color. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 8PE6jCw7bhM + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +We only applied this to our playable character, however, any Materials that use the **Sample_MPC** Material Parameter Collection asset within their Material Graph will also be updated. +Below, we updated the **RampMaterial** (located in **Content/ThirdPerson/Meshes** folder) which is applied to the geometry in the level. + +![](MPCTrack14.png) + +As a result, they too are affected by our Material Parameter Collection Track within Sequencer and update accordingly. + +![](MPCTrack15.png) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksMaterialParameter/MaterialParameterTrack.INT.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksMaterialParameter/MaterialParameterTrack.INT.udn new file mode 100644 index 000000000000..d17b0e24f11e --- /dev/null +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksMaterialParameter/MaterialParameterTrack.INT.udn @@ -0,0 +1,167 @@ +Availability: Docs +Crumbs: %ROOT%, Engine, Engine/Sequencer, Engine/Sequencer/HowTo +Title: Animating Material Parameter Collections +Description:Describes how you can update Material Parameter Collections within Sequencer. +Type: how-to +SkillLevel: Intermediate +Version: 4.16 +Parent: Engine/Sequencer/HowTo +order:1 +tags:Sequencer +tags:Materials +tags:Material Parameter +topic-image: EndResult.png +Related: Engine/Rendering/Materials/ParameterCollections +Related: Engine/Rendering/Materials +Related: Engine/Sequencer/Overview + +**Sequencer** provides a special track for working with and animating [](Engine/Rendering/Materials/ParameterCollections) called the **Material Parameter Collection** track. +This is extremely useful if you have several **Materials** that you need to update as you no longer have to animate individual parameter values on each material instance in order to share animation updates. + +In this how-to guide, you'll use a Material Parameter Collection and Sequencer to dissolve and change the color of the environment around the player. + +![](EndResult.png) + +## Steps + +[REGION:note] +For this how-to guide, we are using the **Blueprint Third Person Template** with **Starter Content** enabled. +[/REGION] + +1. Right-click this [Example Texture](T_Dissolve.png) and **Save target as...**, then drag-and-drop it into your project's **Content Browser** to import it. + +1. In the **Content Browser**, click the **Add New** button then under **Materials & Textures**, create a **Material Parameter Collection** called **Sample_MPC**. + + ![](MPCTrack01.png) + +1. Inside **Sample_MPC**, add a **Scalar Parameter** called **DissolveValue** set to **1.0** and **Vector Parameter** called **ColorValue** with **RGB** all set to **0.18**. + + ![](MPCTrack02.png) + +1. Inside the Main Editor viewport, select one of the walls in the level then double-click on the **CubeMaterial** in the **Details** panel to open the **Material Editor**. + + ![](MPCTrack03.png) + +1. With the **CubeMaterial** node selected in the graph, in the **Details** panel, change the **Blend Mode** to **Masked**. + + ![](MPCTrack04.png) + +1. Right-click in the graph and add a **CollectionParameter** node, then in the **Details** panel for the node, assign **Sample_MPC** and **ColorValue**. + + ![](MPCTrack05.png) + +1. Add another **CollectionParameter** node set to **Sample_MPC** and **DissolveValue**, then connect the **ColorValue** to the **Base Color** on the **CubeMaterial** node. + + ![](MPCTrack06.png) + +1. Hold **T** and left-click in the graph to create a **Texture Sample**, then hold **1** and create two **Material Expression Constant** nodes. + +1. Set the **Texture Sample** node to use the example texture from Step 1 and set one of the **Constant** nodes default value to **1**. + + ![](MPCTrack07.png) + + This texture is what we will use as part of our dissolve. + +1. Add a **If** Math Expression, then connect the nodes as shown below to the **Opacity Mask** value on the **CubeMaterial** node and click **Apply** from the toolbar. + + ![](MPCTrack08.png) + + This will allow us to shift between no dissolve (a **DissolveValue** of 1) or completely dissolved (a **DissolveValue** of 0). + +1. From the Main Editor Toolbar, click the **Cinematics** button and **Add Level Sequence** and assign a name and save location. + + ![](MPCTrack09.png) + +1. In the **Details** panel for the new sequence, check the **Auto Play** option and **Loop Indefinitely** option. + + ![](MPCTrack10.png) + +1. Inside the **Sequencer Editor**, click the **Add** button and select **Material Parameter Collection Track** then **Sample_MPC**. + + ![](MPCTrack11.png) + +1. Click the **Parameter** button and add both the **DissolveValue** and **ColorValue** parameters. + + ![](MPCTrack12.png) + +1. Scrub the **Timeline Marker** ahead to **50** and add a key for **DissolveValue** set to **0** and **Blue** on the **ColorValue** to **1.0**. + + ![](MPCTrack13.png) + +1. Copy and Paste the keys from the previous step at **100** on the timeline, then at **150** set **DissolveValue** back to **1.0** and **Blue** back to **0.18**. + + ![](MPCTrack14.png) + + This will return the DissolveValue and ColorValues back to their default values. + +1. Select the stairs in the level, then open the **RampMaterial** in the **Details** panel to open the **Material Editor**. + + ![](MPCTrack15.png) + + The rest of the objects in the level use the Material above, to include them in the dissolve we will add the **CollectionParameter** setup to its Material Graph. + +1. With the **RampMaterial** node selected, in the **Details** panel, change the **Blend Mode** to **Masked**. + + ![](MPCTrack16.png) + +1. Copy and paste the graph setup used in the **CubeMaterial** into the **RampMaterial** as shown below then click **Apply** from the toolbar. + + ![](MPCTrack17.png) + +1. From the Main Editor Toolbar, click the **Play** button to play in the editor. + +## End Result + +When you play in the level, the environment around the player will shift from gray to purple and dissolve before returning back to normal and repeating the same process. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + V5Eq73oZVdw + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksMaterialParameter/MaterialParameterTrack.JPN.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksMaterialParameter/MaterialParameterTrack.JPN.udn new file mode 100644 index 000000000000..e6de23c7708c --- /dev/null +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksMaterialParameter/MaterialParameterTrack.JPN.udn @@ -0,0 +1,168 @@ +INTSourceChangelist:3478222 +Availability:Docs +Crumbs: %ROOT%, Engine, Engine/Sequencer, Engine/Sequencer/HowTo +Title:Material Parameter Collection をアニメートする +Description:シーケンサー内でマテリアル パラメータ コレクションをアニメートする方法を説明します。 +Type: how-to +SkillLevel:Intermediate +Version:4.16 +Parent:Engine/Sequencer/HowTo +order:1 +tags:Sequencer +tags:Materials +tags:Material Parameter +topic-image:EndResult.png +Related:Engine/Rendering/Materials/ParameterCollections +Related:Engine/Rendering/Materials +Related:Engine/Sequencer/Overview + +**シーケンサー** には、[](Engine/Rendering/Materials/ParameterCollections) で作業しアニメートするための特別な Material Parameter Collection (マテリアル パラメータ コレクション) トラックがあります。 +更新する必要がある **マテリアル** がいくつかある場合、これは非常に便利です。アニメーションの更新を共有するために各マテリアル インスタンスで個々のパラメータ値をアニメートする必要がなくなるからです。 + +この操作ガイドでは、Material Parameter Collection とシーケンサーを使って、プレイヤー周囲の色をディゾルブし、変更します。 + +![](EndResult.png) + +## ステップ + +[REGION:note] +ここでは **Starter Content Enabled (スターター コンテンツを有効にした状態)** で **Blueprint Third Person Template** を使います。 +[/REGION] + +1. この [サンプル テクスチャ](T_Dissolve.png) を 右クリック し、**[Save target as...]** を選び、それをプロジェクトの **コンテンツ ブラウザ** にドラッグ&ドロップしてインポートします。 + +1. **コンテンツブラウザ** で、**[Add New (新規追加)]** ボタンをクリックして、 **[Materials & Textures]** で **[Material Parameter Collection]** を作成し、**Sample_MPC** と名前を付けます。 + + ![](MPCTrack01.png) + +1. **Sample_MPC** 内で **1.0** に設定された **DissolveValue** という **Scalar Parameter** を追加し、**RGB** をすべて **0.18** に設定した **ColorValue** という **Vector Parameter** を追加します。 + + ![](MPCTrack02.png) + +1. メイン エディタのビューポート内でレベル内のウォールのひとつを選択します。次に **[Details]** パネルの **CubeMaterial** 上でダブルクリックし、 **マテリアル エディタ** を開きます。 + + ![](MPCTrack03.png) + +1. グラフ内で **CubeMaterial** ノードを選択した状態で **[Details]** パネルで、**Blend Mode** を **Masked** に変更します。 + + ![](MPCTrack04.png) + +1. グラフ内で 右クリック して、 **CollectionParameter** ノードを追加します。このノードの **[Details]** パネルで **Sample_MPC** と **ColorValue** を割り当てます。 + + ![](MPCTrack05.png) + +1. **Sample_MPC** と **DissolveValue** に設定された別の **CollectionParameter** ノードを追加します。次に、**ColorValue** を **CubeMaterial** ノードの **Base Color** に接続します。 + + ![](MPCTrack06.png) + +1. **T** を押したまま、グラフ内で左クリックして、**Texture Sample** を作成します。次に **1** を押したまま 2 つの **Material Expression Constant** ノードを作成します。 + +1. **Texture Sample** ノードをステップ 1 のサンプル テクスチャを使用するように設定し、**Constant** ノードのデフォルト値のひとつを **1** に設定します。 + + ![](MPCTrack07.png) + + このテクスチャはディゾルブの一部として使うものです。 + +1. **If** Math Expression を追加し、以下のように **CubeMaterial** ノードの **Opacity Mask** 値にノードを接続して、ツールバーの **[Apply]** をクリックします。 + + ![](MPCTrack08.png) + + これにより、ディゾルブなし (**DissolveValue** 1) または完全にディゾルブ (**DissolveValue** 0) との間でシフトすることができます。 + +1. メイン エディタ ツールバー から **[Cinematics (シネマティックス)]** ボタンをクリックし、**[Add Level Sequence (レベル シーケンスを追加)]** を選択し、名前と保存場所を選びます。 + + ![](MPCTrack09.png) + +1. 新しいシーケンスの **[Details (詳細)]** パネルで、**[Auto Play]** オプションと **[Loop Indefinitely]** オプションにチェックを入れます。 + + ![](MPCTrack10.png) + +1. **シーケンサー エディタ** 内で、 **[Add]** ボタンをクリックし、**[Material Parameter Collection Track]** を選択し、次に **[Sample_MPC]** を選択します。 + + ![](MPCTrack11.png) + +1. **[Parameter]** ボタンをクリックし、**DissolveValue** パラメータと **ColorValue** パラメータの両方を追加します。 + + ![](MPCTrack12.png) + +1. **タイムライン マーカー** を **50** にスクラブし、**0** に設定した **DissolveValue** のキーを追加し、**ColorValue** の **Blue** を **1.0** に設定します。 + + ![](MPCTrack13.png) + +1. 前のステップからのキーをタイムラインの **100** にコピー&ペーストして、**150** で **DissolveValue** を **1.0** に戻し、**Blue** を **0.18** に戻します。 + + ![](MPCTrack14.png) + + これで DissolveValue と ColorValues がデフォルト値に戻ります。 + +1. レベル内で階段を選択します。次に [Details] パネルの **RampMaterial** を開き、 **マテリアル エディタ** を開きます。 + + ![](MPCTrack15.png) + + レベルの残りのオブジェクトは上のマテリアルを使用し、これらをディゾルブに含めるために **CollectionParameter** セットアップをマテリアル グラフに追加します。 + +1. **RampMaterial** ノードを選択した状態で **[Details]** パネルで、**Blend Mode** を **Masked** に変更します。 + + ![](MPCTrack16.png) + +1. **CubeMaterial** で使用したグラフのセットアップを以下のように **RampMaterial** にコピー&ペーストします。次にツールバーの **[Apply]** を適用します。 + + ![](MPCTrack17.png) + +1. メイン エディタ ツールバーで **[Play]** ボタンをクリックしてエディタで再生します。 + +## 最終結果 + +レベルで再生すると、プレイヤー周囲の背景がグレーからパープルにシフトし、ディゾルブしてから通常に戻りリピートします。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + V5Eq73oZVdw + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksMaterialParameter/MaterialParameterTrack.KOR.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksMaterialParameter/MaterialParameterTrack.KOR.udn new file mode 100644 index 000000000000..c8b129f82368 --- /dev/null +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksMaterialParameter/MaterialParameterTrack.KOR.udn @@ -0,0 +1,164 @@ +INTSourceChangelist:3449210 +Availability: Public +Title: 머티리얼 파라미터 컬렉션 애니메이션 +Crumbs: %ROOT%, Engine, Engine/Sequencer, Engine/Sequencer/HowTo +Description:시퀀서 내 머티리얼 파라미터 컬렉션 업데이트 방법 안내입니다. +Version: 4.16 +SkillLevel: Intermediate +parent:Engine/Sequencer/HowTo +order:1 +topic-image: EndResult.png +checkpoint: editorqs +Related: Engine/Rendering/Materials/ParameterCollections +Related: Engine/Rendering/Materials +Related: Engine/Sequencer/Overview +tags:Sequencer +type:how-to + +시퀀서에는 [](Engine/Rendering/Materials/ParameterCollections) 작업 및 애니메이션을 위한 특수 **Material Parameter Collection** (머티리얼 파라미터 컬렉션) 트랙이 제공됩니다. +애니메이션 업데이트를 공유시키기 위해 각 머티리얼 인스턴스마다 개별 파라미터 값 애니메이션을 줄 필요 없이 다수의 머티리얼이 있는 경우에 매우 좋습니다. + +여기서는 머티리얼 파라미터 컬렉션 및 시퀀서를 사용하여 플레이어 주변 환경의 색을 분해하여 변화시키도록 하겠습니다. + +![](EndResult.png) + +## 단계 + +[REGION:note] +여기서는 **블루프린트 삼인칭 템플릿** 에 **시작용 콘텐츠** 를 포함시켜 사용하고 있습니다. +[/REGION] + +1. [예제 텍스처](T_Dissolve.png) 에 우클릭하고 **다른 이름으로 저장...** 한 뒤, 프로젝트의 **콘텐츠 브라우저** 에 드래그 앤 드롭 하여 임포트합니다. + +1. **콘텐츠 브라우저** 에서 **신규 추가** 버튼을 누르고 **머티리얼 & 텍스처** 아래 **머티리얼 파라미터 컬렉션** 을 선택하고 **Sample_MPC** 를 만듭니다. + + ![](MPCTrack01.png) + +1. **Sample_MPC** 안에서 **Scalar Parameter** 를 추가하여 **DissolveValue** 라 하고 **1.0** 으로 설정한 뒤, **Vector Parameter** 를 추가하여 **ColorValue** 라 하고 **RGB** 모두 **0.18** 로 설정합니다. + + ![](MPCTrack02.png) + +1. 메인 에디터 뷰포트 안에서, 레벨의 벽 하나를 선택한 뒤 **디테일** 패널의 **CubeMaterial** 에 **더블클릭** 하여 **머티리얼 에디터** 를 엽니다. + + ![](MPCTrack03.png) + +1. 그래프에서 **CubeMaterial** 노드를 선택한 채 **디테일** 패널에서 **Blend Mode** 를 **Masked** 로 변경합니다. + + ![](MPCTrack04.png) + +1. 그래프에 **우클릭** 하고 **CollectionParameter** 노드를 추가한 뒤, **디테일** 패널에서 **Sample_MPC** 와 **ColorValue** 를 할당합니다. + + ![](MPCTrack05.png) + +1. **CollectionParameter** 노드를 하나 더 추가한 뒤 **Sample_MPC** 와 **DissolveValue** 로 설정한 뒤, **ColorValue** 를 **CubeMaterial** 노드의 **베이스 컬러** 에 연결합니다. + + ![](MPCTrack06.png) + +1. **T** 를 누르고 그래프에 **좌클릭** 하여 **Texture Sample** 을 만든 뒤, **1** 을 누르고 **좌클릭** 하여 **Material Expression Constant** 노드를 둘 만듭니다. + +1. **Texture Sample** 노드가 1 단계의 예제 텍스처를 사용하도록 설정하고, **Constant** 노드 중 하나를 기본값 **1** 로 설정합니다. + + ![](MPCTrack07.png) + + 이 텍스처를 색 분해의 일부로 사용하겠습니다. + +1. **If** Math 표현식을 추가한 뒤, 아래와 같이 노드를 **CubeMaterial** 노드의 **오파시티 마스크** 값에 연결한 뒤 툴바의 **적용** 을 클릭합니다. + + ![](MPCTrack08.png) + + 이렇게 하면 분해가 없는 상태(**DissolveValue** 값 1)에서 완전히 분해된 상태(**DissolveValue** 값 0) 으로 전환됩니다. + +1. 메인 에디터 툴바에서 **시네마틱** 버튼을 클릭한 뒤, **레벨 시퀀스 추가** 를 선택하고 이름과 저장 위치를 지정합니다. + + ![](MPCTrack09.png) + +1. 새 시퀀스의 **디테일** 패널에서 **Auto Play** (자동 재생) 및 **Loop Indefinitely** (무반 루프) 옵션을 체크합니다. + + ![](MPCTrack10.png) + +1. **시퀀서 에디터** 안에서 **추가** 버튼을 클릭하고 **Material Parameter Collection Track** (머티리얼 파라미터 컬렉션 트랙)을 선택한 뒤 **Sample_MPC** 를 선택합니다. + + ![](MPCTrack11.png) + +1. **Parameter** (파라미터) 버튼을 클릭하고 **DissolveValue** 와 **ColorValue** 파라미터를 추가합니다. + + ![](MPCTrack12.png) + +1. **타임라인 마커** 를 **50** 까지 앞으로 이동하여 **DissolveValue** 에 대한 키를 추가하고 **0** 으로 설정, **ColorValue** 의 **Blue** 를 **1.0** 으로 설정합니다. + + ![](MPCTrack13.png) + +1. 예전 단계에서 타임라인 **100** 위치의 키를 복사하여 붙인 뒤, **150** 위치에서 **DissolveValue** 값을 다시 **1.0** 으로, **Blue** 를 다시 **0.18** 로 설정합니다. + + ![](MPCTrack14.png) + + 이렇게 하면 DissolveValue 와 ColorValues 가 기본값으로 돌아갑니다. + +1. 레벨의 계단을 선택하고, **디테일** 패널의 **RampMaterial** 을 **더블클릭** 하여 **머티리얼 에디터** 를 엽니다. + + ![](MPCTrack15.png) + + 레벨의 나머지 오브젝트는 위 머티리얼을 사용하는데, 분해에 포함시키기 위해 머티리얼 그래프에 **CollectionParameter** 셋업을 추가하겠습니다. + +1. **RampMaterial** 노드를 선택한 채 **디테일** 패널에서 **Blend Mode** 를 **Masked** 로 변경합니다. + + ![](MPCTrack16.png) + +1. **CubeMaterial** 에 사용된 그래프 셋업을 복사한 뒤 아래와 같이 **RampMaterial** 에 붙여넣고 툴바의 **적용** 을 클릭합니다. + + ![](MPCTrack17.png) + +1. 메인 에디터 툴바에서 **플레이** 버튼을 클릭하여 에디터에서 플레이합니다. + +## 최종 결과 + +레벨에서 플레이해 보면, 플레이어 주변 환경이 회색에서 보라색으로 전환되며 분해되다 원래대로 돌아가는 것을 반복합니다. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + V5Eq73oZVdw + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksShot/Shot.JPN.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksShot/Shot.JPN.udn index e086ca6cb012..5294b9805c6c 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksShot/Shot.JPN.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksShot/Shot.JPN.udn @@ -1,7 +1,7 @@ -INTSourceChangelist:3244012 +INTSourceChangelist:3372149 Availability:Public Title:ショットとテイクを作成する -Crumbs: %ROOT%, Engine, Engine/Sequencer, Engine/Sequencer/HowTo +Crumbs: Description:ショットを並び替えるノンリニア編集とテイクを使ったショットのバリエーションについて説明します。 Version:4.12 SkillLevel:Intermediate @@ -9,7 +9,7 @@ parent:Engine/Sequencer/HowTo order:1 checkpoint: editorqs Related:Engine/Sequencer/Overview -Related:Engine\Sequencer\ReferenceEditor\ +Related:Engine/Sequencer/ReferenceEditor tags:Sequencer 従来の映像エディタと同様に、**Shot (ショット) トラック** ではレベル シーケンスを追加、配置、再配置し、配置した順序で再生することができます。 diff --git a/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksShot/Shot.KOR.udn b/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksShot/Shot.KOR.udn index 92e3a9bf9342..0ce00af62102 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksShot/Shot.KOR.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/HowTo/TracksShot/Shot.KOR.udn @@ -1,6 +1,6 @@ -INTSourceChangelist:3244012 +INTSourceChangelist:3372149 Availability: Public -Title:샷 & 테이크 생성 +Title:샷 및 테이크 생성 Crumbs: %ROOT%, Engine, Engine/Sequencer, Engine/Sequencer/HowTo Description:샷, 그리고 그 변형인 테이크 배치를 통한 비선형 편집의 한 형태를 보여줍니다. Version: 4.12 @@ -9,7 +9,7 @@ parent:Engine/Sequencer/HowTo order:1 checkpoint: editorqs Related: Engine/Sequencer/Overview -Related: Engine\Sequencer\ReferenceEditor\ +Related: Engine/Sequencer/ReferenceEditor tags:Sequencer 전통적인 영화 에디터와 비슷하게, **Shot Track** (샷 트랙)을 사용하여 레벨 시퀀스를 추가, 배치, 조정하면 그 순서대로 재생시킬 수 있습니다. diff --git a/Engine/Documentation/Source/Engine/Sequencer/Overview/SequencerOverview.CHN.udn b/Engine/Documentation/Source/Engine/Sequencer/Overview/SequencerOverview.CHN.udn index 9f4803d10ebf..5c887353a5a3 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/Overview/SequencerOverview.CHN.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/Overview/SequencerOverview.CHN.udn @@ -1,250 +1,365 @@ -INTSourceChangelist:3009005 +INTSourceChangelist:3444205 Availability:Public -Title:Sequencer 概述 -Crumbs:%ROOT%, Engine -Description:Sequencer 是虚幻引擎 4 的多轨道编辑器,用于实时创建和预览过场动画序列。 +Title:Sequencer 总览 +Crumbs:%ROOT% +Description:Sequencer 是虚幻引擎 4 的多轨迹编辑器,用于实时创建和预览影片序列。 Navigation:topic parent:Engine/Sequencer -order:1 -Version:4.12 -Related:Engine\Sequencer\ReferenceEditor -Related:Engine\Sequencer\HowTo - -**Sequencer** 编辑器使用户能够通过类似于 [**Matinee**](Engine\Matinee\) 的专用多轨道编辑器创建游戏过场动画。 -通过创建 **关卡序列** 和添加 **轨道**,用户可以定义每条轨道的构成,而这些轨道将决定序列的内容。 -轨道可以包含动画(用于使角色动起来)、转换(在场景中移动摄像机等对象)、音频(用于包含音乐或音效),以及其他多种轨道类型。 +order:2 +Version:4.15 +Related:Engine/Sequencer/ReferenceEditor +Related:Engine/Sequencer/HowTo +tags:Sequencer +type:overview +tags:Getting Started +SkillLevel:Intermediate [TOC(start:2 end:2)] +借助 **Sequencer** 编辑器,用户可使用特殊的多轨迹编辑器创建游戏中的影片(与 [Matinee](Engine\Matinee\) 相似)。创建 **关卡序列** 并添加 **轨迹** 后,用户可定义每个轨迹的组成,决定场景的内容。估计可包含动画(让角色有动作)、变化(让物体在场景中移动)、音频(包含音乐或音效),以及数个其他轨迹类型。 + ## 创建关卡序列 -**关卡序列** 是过场动画场景的“容器”,必须先创建它们才能开始在 Sequencer 编辑器中工作。您可以从 **工具栏** 的 **过场动画(Cinematics)**下选择创建一个关卡序列,并将其直接放入关卡中,如下图所示。 +**关卡序列** 是影片场景的“容器”,必须创建后才能在 Sequencer Editor 中开始工作。您可以创建一个关卡序列并直接将其放置到关卡中,方法是从 **工具栏** 中的 **Cinematics** 下选择创建(如下图所示)。 ![](LevelSequence.png) -这会将它添加到关卡中,然后可以在关卡中选择它,用类似于 **Matinee Actor** 的 **细节(Details)**面板操纵其属性。在“细节”(Details)面板中(下图),您可以定义关卡序列是否在关卡启动时自动播放,序列的播放速率,序列是否应该循环播放,以及其他设置。 +它将被添加到关卡中,可对其进行选中,并通过 **Details** 面板调整其属性(和 **Matinee Actor** 相似)。在 Details 面板中(下图),可定义关卡序列是否在关卡开始后自动播放、序列播放速度、序列是否循环,以及其他设置。 ![](DetailsPanel.png) -与 Matinee 不同之处是,关卡序列是自包含的资产,您可以将一个关卡序列嵌入另一个关卡序列中。 -例如,您可以创建一个包含动画角色和摄像机的关卡序列作为一个场景,以其作为一段更大的过场动画序列的一部分。 +关卡序列和 Matinee 的区别在于关卡序列是自含式资源,可将关卡序列嵌入到另一个关卡序列中。 +举例而言,可以创建一个包含动画角色和镜头的关卡序列,将其作为一个场景。而这个场景又是另一个大型影片序列的一部分。 -创建关卡序列的第二种方法可在 **内容浏览器** 中执行:单击 **新增(Add New)**按钮,再选择 _动画(Animation)_下的 **关卡序列(Level Sequence)**。用这种方式创建的关卡序列资产是尚未显式地放入关卡中的。 +创建关卡序列的另一种方法:在 **Content Browser** 中点击 **Add New** 按钮,从 **Animation** 菜单中选择 **Level Sequence**。执行此操作可创建一个关卡序列资源,然后将其放置到关卡中。 ![](LevelSequence_B.png) +## 为 Sequencer 添加轨迹 -## 向 Sequencer 添加轨道 - -在创建关卡序列并打开 Sequencer 编辑器后,您可以开始创建过场动画。 +创建关卡序列后,对其执行双击,打开 Sequencer 编辑器,以便开始创建影片。 ![](BlankScene.png) [REGION:caption] -在上面我们创建了一个新的空关卡系列。 +上图为新建的空白关卡序列。 [/REGION] -您需要做的第一件事是添加 **轨道** 类型,可以从 **添加(Add)**下拉菜单进行操作。 +首先需要做的是添加一个 **Track** 类,可从下拉菜单的 **Add** 按钮进行操作。 ![](AddToSequencer.png) -在下拉菜单中,你将看到多种可以选择的轨道类型,以及添加 **Actor 到 Sequencer(Actor To Sequencer)**的功能。“Actor 到 Sequencer”(Actor To Sequencer)选项允许您将您当时在关卡中选择的任何 Actor 添加到 Sequencer,以便在场景中操纵它们。 +下拉菜单中有多个可选的轨迹类,以及 **Actor To Sequencer** 功能。Actor To Sequencer 选项可将在关卡中选中的 Actor 添加到 Sequencer,以便在场景中进行操作。 -通常,如果您要创建的过场动画中有角色、动物、怪物或任何类似的会做动作或移动的对象,您需要有它的骨骼网格,并且需要将网格添加到 Sequencer。 -在下面的示例中,我们在关卡中放入了一头熊的骨骼网格。选中它以后,我们在 Sequencer 中单击 **添加(Add)**按钮,然后选择 **Actor 到 Sequencer(Actor To Sequencer)**添加它,以便通过 Sequencer 编辑器控制它。 +通常而言,如果创建的影片中包含角色、动物、生物(或诸如此类)会做动作和移动的资源,则需要将其 [骨架网格体](Engine/Content/Types/SkeletalMeshes) 添加到 Sequencer。 +举例而言,在关卡中放置一个熊的骨架网格体(如下图所示)。选中熊之后,即可在 Sequencer 中点击 **Add** 按钮并选择 **Actor To Sequencer**,以便添加到 Sequencer 编辑器中并进行操控。 ![](AddBear.png)(w:640) -添加骨骼网格后,我们可以添加影响该骨骼网格的 **子轨道**。 +添加骨架网格体后,即可添加 **子轨迹** 影响骨架网格体。 ![](SkeletalMeshTracks.png) [REGION:caption] -根据您创建的轨道类型,有可能可以添加子轨道,并可以使用添加子轨道的功能。 +可基于创建的轨迹类型添加子轨迹,添加子轨迹的功能也随之可用。 [/REGION] -我们在下面选择动画子轨道,并为我们的骨骼网格熊指定一段要播放的动画。 +在下方的视频中,我们选中了动画子轨迹,并为熊的骨架网格体指定了动画进行播放。 [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -KoksbI7ZOTM -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + KoksbI7ZOTM + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] -##可占据项与可生成项 +## 可拥有项和可生成项 -Sequencer 与 Matinee 非常相似的一点是它使用了“可占据项”的概念,也就是说如果关卡中存在 Actor,Sequencer 将会占据它来应用您通过 Sequencer 对它作出的更改。 +Sequencer 和 Matinee 的相似度很高,两者均使用“可拥有项”的概念。意味着 Sequencer 将“拥有”关卡中的 Actor,以便对其应用用户通过 Sequencer 进行的修改。 +如实例中的熊所示(上方视频中),用户可在关卡中放置一个骨架网格体并将其添加到 Sequencer,然后可在 Sequencer 中添加与骨架网格体关联的动画轨迹并为其指定不同动画在场景中播放。 +在此例中,我们便“拥有”关卡中的骨架网格体,以便告知其行为。 -正如我们在上面的熊示例中所示,您可以在关卡中放置骨骼网格并添加到 Sequencer,然后在 Sequencer 中您可以向骨骼网格添加动画轨道,并为它指定在场景中要播放的不同动画。 -我们“占据”存在的骨骼网格是为了告诉它要做些什么。Sequencer 还包含另一种被称作“可生成项”的操作对象,也就是说如果我们要占据的对象不存在,Sequencer 会在接到指示时“生成”该对象并有权操纵它,还可定义其生命周期。 - -那么这有什么好处呢?我什么时候应该选择使用“可生成”的对象?因为 Sequencer 是生成该对象的主人,所以对象并不绑定到特定关卡。任何被视作可生成项的对象都可以在任何关卡中使用,因此您可以创建一个场景,让它在任何环境中发生,并在新的关卡中复用它,而不必重新创建。 +Sequencer 还包含另一种形式的操作,其被称为“可生成项”。意思是用户所拥有的物体尚不存在,因此 Sequencer 将“生成”物体(接受到指令时),并拥有决定其生命周期的权限。Sequencer 负责生成并拥有物体,因此物体不会绑定在特定的关卡上。被标记为“可生成”的内容可在任意关卡中使用,因此可以创建一个场景,使其在任意环境中发生,并在新关卡中重复使用(而无需进行重建)。 [REGION:note] -请参见 [创建可生成项](Engine\Sequencer\HowTo\Spawnables\) 了解更多信息。 +可在 [创建可生成项](Engine\Sequencer\HowTo\Spawnables\) 中查阅详细内容。 [/REGION] - ## 设置场景关键帧 -如果您熟悉外部动画工具,那么可能也熟悉使用关键帧驱动内容的概念。 -如果您不熟悉,那么简单说来,就是 Sequencer 允许您通过在时间轴上的所需点添加带有定义属性的 **键**(称为设置关键帧)来操纵你的内容。 -当在时间轴上到达这些键时,您在每个关键帧上定义的属性会更新,以反映您输入的值。 +如您熟知大多数动画工具,那便不会对使用关键帧驱动内容的概念感到陌生。在 Sequencer 中,用户可沿时间轴在所需的点上添加带有已定义属性的 **键**(称之为“设置关键帧”),从而对内容进行操作。到达时间轴上的键后,在每个关键帧处定义的属性将更新,反映出输入的值。 -以下样本场景演示通过为骨骼网格 Actor 的不同转换建立关键帧来添加移动的过程。 +下方的场景实例说明了对骨架网格体 Actor 的不同变形进行关键帧设置,从而完成动作动作添加的流程。 [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -dVDNJkQxlRk -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + dVDNJkQxlRk + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] [REGION:caption] -在上面的步骤中,我们已经为 **位置** 轨道的开始位置添加一个关键帧,并为结束位置添加了另一个关键帧。 +在上方视频的 **Location** 轨迹中,我们在开始位置添加了一个关键帧,然后在结束位置添加了另一个关键帧。 [/REGION] -要添加关键帧,您可选择轨道并按 **Enter** 键,或者单击各个轨道上的“添加关键帧”按钮。 +选中轨迹并按下 **Enter**,或按下每个轨迹上的“add Keyframe”按钮即可添加关键帧。 ![](KeyframeButton.png) -对于 Actor 的 **细节(Details)**面板中的部分属性,您可通过单击各属性旁边的“添加关键帧”按钮为其添加关键帧。 +点击每个属性旁边的“add Keyframe”按钮即可直接对 Actor **Details** 面板中的部分属性设置关键帧。 ![](KeyframeDetails.png) [REGION:caption] -在上图中,对于电影摄像机 Actor 的“当前焦距”(Current Focal Length)和“光圈”(Aperture)设置,显示了关键帧按钮。 +上图中黄线圈出的部分即为一个电影摄像机 Actor 的 Current Focal Length 和 Current Aperture 设置的关键帧按钮。 [/REGION] - - [REGION:tip] -选择包含关键帧的轨道后,您可以按 **,** 和 **.** 键在每个已放置的关键帧之间快速移动。 +轨迹包含选中的关键帧后,即可按下 **,**(逗号)和 **.**(句号)键在每个放置的关键帧之间快速移动。 [/REGION] +选中一个键(或多个键或分段)后,即可使用 **Transform Keys/Sections** 工具重新放置选项的位置并重新设置大小。 + +![](SelectionOption.png) + +按下 **Ctrl+M** 组合键即可打开 Transform Keys/Selection 工具。 + +这样便可对键/选项进行特定量的偏移,或按特定时间对键/选项进行缩放。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + Kd3CwzMwTLs + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] ### 播放范围 -Sequencer 将根据定义的开始和停止播放范围(下图的绿色/红色标记)播放您的场景。 +Sequencer 将基于定义的开始和结束播放范围(下方的绿色/红色标记处)播放场景。 ![](PlaybackRange.png) [REGION:caption] -在上图中,我们的内容包含两个在第 600 帧结束的镜头,但我们的序列延伸到第 1000 帧,这导致存在空白。 +上图中的内容包含两个镜头,在第 600 帧结束,但序列却延长到了第 1000 帧,因此便出现了“无效空白”。 [/REGION] -您可以拖动开始和停止播放标记来配合您的内容,也可选择一个选项,使您的内容保持在这些范围内。您可以在 Sequencer“选项”(Options)下拉菜单中找到该选项,启用 **使播放范围保持在片段边界中(Keep Playback Range In Section Bounds)**。 +可拖动 **开始** 和 **结束播放** 标记匹配内容长度,或通过选项设置将内容保持在范围之内。此选项在 **Sequencer Options** 下拉菜单中,名为 **Keep Playback Range In Section Bounds**。 ![](KeepInRange.png) -##专用视口 +从主关卡(以及镜头关卡)设置 [镜头轨迹](Engine\Sequencer\HowTo\TracksShot) 并查看序列时,我们将在相对时间对整个序列进行求值。下图中,播放范围的结尾有两个红色标记,第一个代表镜头的结尾(镜头关卡中),而第二个则代表主序列的结尾。此范例中的情况是 `Shot0020_001` 设为使用 50 帧,但我们将其设为在主关卡上使用 100 帧。 -Sequencer 允许您使用专用视口简化编辑过程。 +![](Evaluation_1.png) + +进入镜头中,第一个红色标记代表镜头在第 50 帧处结束,而第二个红色标记则代表主关卡上镜头的结束。 + +![](Evaluation_2.png) + +第 50 帧到第 100 帧为灰色,说明为解决长度不同的问题,可以将镜头关卡处被求值的帧量增加到 100,或在主序列关卡处将镜头的长度缩短到 50 帧。 + +## 特殊视口 + +Sequencer 的特殊视口可让编辑更加简易。 ![](SpecialViewports.png) -这些 [**过场动画视口**](Engine\Sequencer\HowTo\ViewportOptions) 可使您更好地了解场景外观,并可通过 **视口(Viewport)**选项按钮启用。 +这些 [动态视口](Engine\Sequencer\HowTo\ViewportOptions) 可更好地显示场景的效果,可通过 **Viewport** 选项按钮启用。 -##过场动画 Actor +## 影片 Actor -在 **过场动画(Cinematic)**下的 **模式(Modes)**面板中,有三个可用于操纵过场动画的过场动画 Actor。 +在 **Modes** 面板中的 **Cinematic** 菜单下,有三个可用于制作影片的影片 Actor。 ![](CineTools.png) -您可将其中任何过场动画 Actor 拖到关卡内,然后将其添加到 Sequencer,也可直接将其拖到 Sequencer 中(这将使其成为可生成项)。 +可将任意一个影片 Actor 拖入关卡,将其添加到 Sequencer;或将影片 Actor 拖入 Sequencer,使其成为一个可生成项。 ### 摄像机吊臂 -摄像机吊臂 Actor 可用来模拟传统电影摄制中类似于吊臂的摄像机移动。 +**摄像机吊臂** Actor 可用于模拟传统影片拍摄中的吊臂式摄像机运动。 ![](Crane.png)(w:480) -您可将一个摄像机附加到摄像机吊臂 Actor,然后通过 **细节(Details)**面板和 **吊臂控件(Crane Controls)**值来操纵吊臂移动。这些值可以影响吊臂倾斜角、吊臂旋角和吊臂长度。在 Sequencer 中可以为这些值建立关键帧,这将允许您在过场动画期间根据需要调整这些值。 +可将摄像机附加到摄像机吊臂 Actor,以便通过 **Details** 面板和 **Crane Controls** 值控制吊臂运动。这些数值会影响吊臂绕 X 轴的旋转、绕 Y 轴的旋转,以及吊臂长度。所有这些数值均可在 Sequencer 中设置关键帧,以便根据需求在影片中进行调整。 [REGION:note] -请参见 [创建可生成项](Engine\Sequencer\HowTo\Spawnables\) 了解更多信息。 +可在 [从摄像机吊臂进行拍摄](Engine\Sequencer\HowTo\CameraRigCrane) 中查阅详细内容。 [/REGION] -### 摄像机轨道 +### 摄像机导轨 -摄像机轨道 Actor 是基于样条的工具,您可将摄像机附加到此工具,以提供移动“路径”。 +**摄像机导轨** Actor是一个以样条为基础的工具,可将摄像机附加在其上,提供运动的“路径”。 ![](Rail.png)(w:480) -您可选择每个样条点并改变切线,以产生要让摄像机遵循的路径。附加到轨道的摄像机可以独立旋转,摄像机在轨道上所处的位置可通过 **细节(Details)**面板中的 **轨道上的当前位置(Current Position on Rail)**属性进行调整。可以为此值建立关键帧,这将允许您通过 Sequencer 来改变值。 +用户可选择每个样条点并调整切线,生成所需要的摄像机路径。附加到导轨的摄像机可独立旋转,轨道上的摄像机位置可通过 **Details** 面板的 **Current Position on Rail** 属性进行调整。也可对此值设置关键帧。 [REGION:note] -请参见 [创建可生成项](Engine\Sequencer\HowTo\Spawnables\) 了解更多信息。 +可在 [从摄像机导轨拍摄](Engine\Sequencer\HowTo\CameraRigRail) 中查阅详细内容。 [/REGION] ### 电影摄像机 Actor -电影摄像机 Actor 与默认摄像机 Actor 类似,但提供了更多摄像机设置。 +**电影摄像机 Actor** 与默认摄像机 Actor 类似。然而,其有额外的摄像机设置可用。 ![](CineCamera.png)(w:480) [REGION:caption] -上图显示电影摄像机 Actor(黑色摄像机)和默认摄像机 Actor(蓝色摄像机)。 +电影摄像机 Actor(黑色摄像机)和默认摄像机 Actor(蓝色摄像机)如上图所示。 [/REGION] -电影摄像机 Actor 提供了观看追踪(追踪 Actor)设置、菲林板设置(16:9 DSLR、超级 8mm 和 35mm VistaVision 等等)、镜头和聚焦设置以及当前光圈和焦距设置。虽然使用普通的摄像机 Actor 就可以获得不错的效果,但为了实现更强烈的过场动画感受并公开更多摄像机设置,建议您使用电影摄像机 Actor 来拍摄场景。 +电影摄像机 Actor 包含追踪跟拍设置(跟踪 Actor)、菲林板设置(16:9 DSLR、超级 8 毫米、35 毫米 VistaVision 等)、镜头和对焦设置,以及当前光圈和对焦距离。虽然使用普通摄像机 Actor 完全没问题,为达到更佳的影片感并利用更多摄像机设置,推荐您使用电影摄像机 Actor 拍摄场景。 [REGION:note] -请参见 [创建可生成项](Engine\Sequencer\HowTo\Spawnables\) 了解更多信息。 +可在 [使用电影摄像机 Actor](Engine\Sequencer\HowTo\CineCameraActors) 中查阅详细内容。 [/REGION] +## 序列录制 -##序列记录 - -有一个可用来缩短内容创建时间的工具是 **序列记录器**,它可记录游戏(或关卡序列)以生成新的关卡序列资产。 +使用 **Sequence Recorder** 录制游戏进程(或关卡序列)生成新关卡序列资源可有效缩短内容创建时间。 [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -mvCPXslVb8Y -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + mvCPXslVb8Y + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] -添加新记录,选择要记录的 Actor,然后单击“记录”(Record)以开始捕获。停止记录时将会创建新的关卡序列资产,您可将这些资产合并到现有的过场动画中,或者使用所记录的关卡序列中的片段来创建新序列。 + + +选择进行的录制的 Actor,点击 Record 开始采集即可添加新录制。停止录制时,新的关卡序列资源将被创建。您之后便可将它们合并到现有的影片中,或使用已加载关卡序列的片段创建新序列。 +您也可以使用外部麦克风录制与录制序列相匹配的音频,对序列均进行讲述(或在录制关卡编辑器操作时提供说明) [REGION:note] -请参见 [**记录游戏**](Engine/Sequencer/HowTo/SequenceRecorder) 了解更多信息。 +可在 [录制游戏进程](Engine/Sequencer/HowTo/SequenceRecorder) 中查阅详细内容。 [/REGION] -##渲染电影设置 +##渲染影片设置 -在 Sequencer 中,您可以通过 **渲染电影设置(Render Movie Settings)**选项选择将过场动画渲染为视频或图像序列。 +在 Sequencer 中,用户可通过 **Render Movie Settings** 选项将影片渲染为视频或图片序列。 ![](RenderMovie.png) -此选项将显示 **渲染电影设置(Render Movie Settings)**窗口,您可以用它定义如何渲染场景。 +可利用显示的 **Render Movie Settings** 窗口定义场景的渲染方式。 ![](CaptureMovie.png) -单击 **采集电影(Capture Movie)**可开始记录场景的采集过程。 +点击 **Capture Movie** 按钮即可开始场景的录制进程。 +### 自定义烧入内容 -## 工作流程考虑事项 +[INCLUDE:Engine/Sequencer/HowTo/BurnIns#intro] -对 Sequencer 编辑器的工作方式有了基本了解之后,您可以考虑使用该工具的方式,因为可以通过多种不同的方法来编写内容。无论您是在单个关卡序列中创建所有内容,使各个序列相互嵌套并使用主序列来控制所有这些序列,还是从使用主序列资产入手,Sequencer 都会提供多种可生成过场动画的方法。 +[REGION:note] +请查看 [](Engine/Sequencer/HowTo/BurnIns) 中使用烧入内容的详细指南。 +[/REGION] + +### 导入/导出 EDL + +[INCLUDE:Engine/Sequencer/HowTo/ImportExportEDLs#intro] + +导出 EDL 时,也可为每个镜头自动添加 **帧柄**,并指定需要添加的帧数。 + + ![](RenderMovieSequence.png) + +[REGION:note] +请查看 [](Engine/Sequencer/HowTo/ImportExportEDLs) 中使用 EDL 的详细指南。 +[/REGION] + +### 自定义渲染通道 + +如果需要将影片导出到不同渲染通道中,可从 **Render Movie Settings** 窗口进行操作。通过此窗口可以指定导出序列时使用的渲染通道。还可将 HDR(高动态范围)数据导出为 .exr 文件,并定义压缩和色域设置。 [REGION:note] -请参见 [**工作流程考虑事项**](Engine\Sequencer\Workflow\ToolUsage) 了解更多信息。 +可在 [](Engine\Sequencer\Workflow\CustomRenderPass) 中查阅详细内容。 [/REGION] + +## 蓝图中嵌入的序列 + +[REGION:warning] +这是尚处于开发阶段的实验性功能。一些方面可能无法正常使用,或会在未来版本中被修改。 +[/REGION] + +在 4.15 版本之后的引擎中,用户可以启用 **Actor 序列插件**,以便将 **Actor 序列组件** 添加到 **蓝图**。 +这样一来便可将序列直接嵌入 Actor 蓝图。将动画绑定到蓝图实例并自动触发或通过蓝图的 **事件图表** 触发,即可重复使用序列。 + +以下视频展示了使用聚光源和 Actor 序列组件创建的蓝图,为光线颜色设置动画并进行修改。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + bohLiPXTyMs + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +[REGION:note] +请查看 [](Engine\Sequencer\HowTo\ActorSequence) 中的详细指南。 +[/REGION] + + + + +## 工作流考量 + +基本理解 Sequencer 编辑器的工作原理后,即可考虑工作的使用方式(制作内容的方法不胜枚举)。使用 Sequencer 生成影片的方式多样,例如在单个关卡序列中创建所有内容、将序列嵌入到另一个序列并使用主序列对所有序列进行控制,或使用主序列资源开始。 + +[REGION:note] +可在 [工作流考量](Engine\Sequencer\Workflow\ToolUsage) 中查阅详细内容。 +[/REGION] + + diff --git a/Engine/Documentation/Source/Engine/Sequencer/Overview/SequencerOverview.INT.udn b/Engine/Documentation/Source/Engine/Sequencer/Overview/SequencerOverview.INT.udn index c4a8a524a54d..5c96acf42a3b 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/Overview/SequencerOverview.INT.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/Overview/SequencerOverview.INT.udn @@ -1,21 +1,23 @@ Availability:Public Title: Sequencer Overview -Crumbs: -Description:Sequencer is Unreal Engine 4's multi-track editor, used for creating and previewing cinematic sequences in real time. +Crumbs:%ROOT% +Description:Sequencer is Unreal Engine 4's multi-track editor, used for creating and previewing cinematic sequences in real-time. Navigation:topic parent:Engine/Sequencer -order:1 +order:2 Version: 4.15 Related: Engine/Sequencer/ReferenceEditor Related: Engine/Sequencer/HowTo tags:Sequencer type:overview +tags:Getting Started +SkillLevel:Intermediate [TOC(start:2 end:2)] -The **Sequencer** Editor gives users the ability to create in-game cinematics through a specialized multi-track editor (similar to [Matinee](Engine\Matinee\)). -By creating **Level Sequences** and adding **Tracks**, users can define the makeup of each Track, which will determine the content for the scene. -Tracks can consist of things like Animations (for animating a character), Transformations (moving things around in the scene), Audio (for including music or sound effects), as well as several other Track types. +The **Sequencer** Editor gives users the ability to create in-game cinematics with a specialized multi-track editor (similar to [Matinee](Engine\Matinee\)). +By creating **Level Sequences** and adding **Tracks**, users can define the make-up of each Track, which will determine the content for the scene. +Tracks can consist of things like Animations (for animating a character), Transformations (moving things around in the scene), Audio (for including music or sound effects), and several other Track types. ## Creating Level Sequences @@ -23,18 +25,17 @@ The **Level Sequence** is the "container" for your cinematic scenes, and must be ![](LevelSequence.png) -This will add it to the level, at which point it can be selected and its properties can be manipulated in the **Details** panel, similar to a **Matinee Actor**. In the Details panel (below), you can define whether the Level Sequence will automatically play upon level start, the Play Rate for the sequence, whether the sequence should loop, and other settings. +This will add it to the Level, at which point it can be selected, and its properties can be manipulated in the **Details** panel (similar to a **Matinee Actor**). In the Details panel (below), you can define whether the Level Sequence will automatically play upon Level start, the Play Rate for the sequence, whether the sequence should loop, and other settings. ![](DetailsPanel.png) How this differs from Matinee, is that Level Sequences are self-contained assets, and you can embed a Level Sequence within another Level Sequence. -For example, you can create a Level Sequence that has animated characters, cameras, etc. as one scene that is part of a larger cinematic sequence. +For example, you can create a Level Sequence that has animated characters and cameras as one scene that is part of a larger cinematic sequence. -An alternate method of creating Level Sequences can be performed in the **Content Browser** by clicking the **Add New** button and selecting **Level Sequence** under _Animation_. When doing so in this manner, you are creating the Level Sequence asset, but haven't placed it in a level. +An alternate method of creating Level Sequences can be performed in the **Content Browser** by clicking the **Add New** button, and selecting **Level Sequence** from the **Animation** menu. When doing this, you are creating the Level Sequence asset before placing it in a Level. ![](LevelSequence_B.png) - ## Adding Tracks to Sequencer After creating a Level Sequence, double-click on it to open the Sequencer Editor so that you can begin creating your cinematic. @@ -42,17 +43,17 @@ After creating a Level Sequence, double-click on it to open the Sequencer Editor ![](BlankScene.png) [REGION:caption] -Above, we have a newly-created, empty Level Sequence. +Above, we have a newly created, empty Level Sequence. [/REGION] The first thing you will need to do is add a **Track** type, which you can do from the **Add** button's drop-down menu. ![](AddToSequencer.png) -From the drop-down menu, you will see several Track types you can select from, as the ability to add an **Actor To Sequencer**. The Actor To Sequencer option will enable you to add any Actors that you have selected in your level at the time to Sequencer so that you can manipulate them during your scene. +From the drop-down menu, you will see several Track types you can select from, as the ability to add an **Actor To Sequencer**. The Actor To Sequencer option will enable you to add any Actors that you have selected in your Level (at the time) to Sequencer so that you can manipulate them during your scene. -Typically, if you are creating a cinematic that has characters, animals, creatures, or anything along those lines that will animate and move, you will have a [Skeletal Mesh](Engine/Content/Types/SkeletalMeshes) for it, which you will need to add to Sequencer. -For example, below, we have a Skeletal Mesh of a bear that we have placed in our level. With it selected, we can then click the **Add** button in Sequencer and choose **Actor To Sequencer** so that we can add it and control it through the Sequencer Editor. +Typically, if you are creating a cinematic that has characters, animals, creatures (or anything along those lines) that will animate and move, you will have a [Skeletal Mesh](Engine/Content/Types/SkeletalMeshes) for it, which you will need to add to Sequencer. +For example, we have a Skeletal Mesh of a bear that we have placed in our Level (below). With the bear selected, we can then click the **Add** button in Sequencer and choose **Actor To Sequencer** so that we can add it and control it in the Sequencer Editor. ![](AddBear.png)(w:640) @@ -67,92 +68,107 @@ Based on the type of Track you create, Sub-Tracks may be added and the ability t Below, we select the Animation Sub-Track and assign an Animation for our Skeletal Mesh Bear to play. [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -KoksbI7ZOTM -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + KoksbI7ZOTM + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] ## Possessables vs. Spawnables -Sequencer is very similar to Matinee in that it uses the concept of "possessables", meaning that an Actor exists in the level and Sequencer will take possession of it in order to apply changes you make to it via Sequencer. -As illustrated in our bear example above, you can place a Skeletal Mesh in the level and add it to Sequencer, then inside Sequencer, you can add an Animation Track associated with the Skeletal Mesh and assign different animations for it to play during your scene. -In this instance, we are "possessing" the Skeletal Mesh that exists in the level in order to tell it what to do. +Sequencer is very similar to Matinee, in that it uses the concept of "possessables", meaning that an Actor exists in the Level, and Sequencer will take possession of it in order to apply changes you make to it via Sequencer. +As illustrated in our bear example (above), you can place a Skeletal Mesh in the Level and add it to Sequencer, then inside Sequencer, you can add an Animation Track associated with the Skeletal Mesh and assign different animations for it to play during your scene. +In this example, we are "possessing" the Skeletal Mesh that exists in the Level in order to tell it what to do. -Sequencer also includes another form of manipulation, which is referred to as "spawnables", meaning that the object we are possessing does not yet exist, so Sequencer will "spawn" the object when told to, and will have authority over it to determine its lifecycle. Since Sequencer spawns and owns the object, the object is not bound to a particular level. Anything marked as "spawnable" can be used in any level, so you could create a scene and have it take place in any environment and reuse it in new levels without having to recreate it. +Sequencer also includes another form of manipulation, which is referred to as "spawnables", meaning that the object we are possessing does not yet exist, so Sequencer will "spawn" the object (when told to), and will have authority over it to determine its lifecycle. Since Sequencer spawns and owns the object, the object is not bound to a particular Level. Anything marked as "spawnable" can be used in any Level, so you could create a scene and have it take place in any environment, and reuse it in new Levels without having to recreate it. [REGION:note] Please see [Creating Spawnables](Engine\Sequencer\HowTo\Spawnables\) for more information. [/REGION] - ## Keyframing Scenes -If you are familiar with most animation tools, the concept of using Keyframes to drive content may be familiar to you. Sequencer allows you to manipulate your content by adding **Keys** (referred to as "Keyframing") with defined properties at desired points along a timeline. -Upon reaching those keys in the Timeline, the properties you have defined at each keyframe are updated to reflect the values you've entered. +If you are familiar with most animation tools, the concept of using Keyframes to drive content may be familiar to you. +Sequencer allows you to manipulate your content by adding **Keys** (referred to as "Keyframing") with defined properties at desired points along a timeline. +Upon reaching those Keys in the Timeline, the properties you have defined at each Keyframe are updated to reflect the values that you entered. -A sample scene below illustrates the process of adding movement by keyframing different transformations of a Skeletal Mesh Actor. +A sample scene (below) illustrates the process of adding movement by Keyframing different transformations of a Skeletal Mesh Actor. [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -dVDNJkQxlRk -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + dVDNJkQxlRk + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] [REGION:caption] -Above, we added a keyframe for the starting position, and another keyframe for the ending position, for the **Location** track. +For the **Location** track (above), we added a Keyframe for the starting position, and another Keyframe for the ending position. [/REGION] -You can add a keyframe by selecting a track and pressing **Enter**, or by clicking the "add keyframe" button on each track. +You can add a Keyframe by selecting a track and pressing **Enter**, or by clicking the "add Keyframe" button on each track. ![](KeyframeButton.png) -Some properties in the **Details** panel of an Actor can be keyframed directly by clicking the "add keyframe" button next to each property. +Some properties in the **Details** panel of an Actor can be Keyframed directly by clicking the "add Keyframe" button next to each property. ![](KeyframeDetails.png) [REGION:caption] -Above, keyframe buttons are shown for the Current Focal Length and Aperture settings of a Cine Camera Actor. +Above, Keyframe buttons are shown for the Current Focal Length and Aperture settings of a Cine Camera Actor. [/REGION] [REGION:tip] -With a Track containing Keyframes selected, you can press the **,** (comma) and **.** (period) keys to quickly move between each placed keyframe. +With a Track containing selected Keyframes, you can press the **,** (comma) and **.** (period) Keys to quickly move between each placed Keyframe. [/REGION] -With a key (or multiple keys or sections) selected, you can use the **Transform Keys/Sections** tools to reposition and rescale your selection. +With a Key (or with multiple Keys or sections) selected, you can use the **Transform Keys/Sections** tools to reposition and rescale your selection. ![](SelectionOption.png) -You can also open the Transform Keys/Selection tools by pressing **Ctrl+M**. +You can also open the Transform Keys/Selection tools by pressing the **Ctrl+M** Key combination. -This will allow you offset the keys/selection by a specified amount or the amount to scale the keys/section by the specified time. +This will allow you to offset the Keys/selection by a specified amount, or the amount to scale the Keys/section by a specified time. [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -890 -[/PARAMLITERAL] -[PARAMLITERAL:height] -196 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -Kd3CwzMwTLs -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + Kd3CwzMwTLs + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] - - - ### Playback Range Sequencer will play back your scenes based on the defined Start and Stop playback ranges (green/red markers below). @@ -160,26 +176,25 @@ Sequencer will play back your scenes based on the defined Start and Stop playbac ![](PlaybackRange.png) [REGION:caption] -Above, our content contains two shots which end at frame 600, but our sequence extends to frame 1000, resulting in dead space. +Above, our content contains two shots that end at frame 600, but our sequence extends to frame 1000, resulting in "dead space". [/REGION] -You can drag the **Start** and **Stop Playback** markers to fit your content, or there is an option that can be set which will keep your content within these ranges. You can find this option under the **Sequencer Options** drop-down menu, called **Keep Playback Range In Section Bounds**. +You can drag the **Start** and **Stop Playback** markers to fit your content, or there is an option which can be set that will keep your content within these ranges. You can find this option under the **Sequencer Options** drop-down menu, called **Keep Playback Range In Section Bounds**. ![](KeepInRange.png) -When working with [Shot Tracks](Engine\Sequencer\HowTo\TracksShot) and viewing sequences from the Master level as well as the Shot level, we evaluate the entire sequence at its relative time. -In the image below we have two red markers for the ending of playback ranges, the first denotes the end of the Shot (from the Shot level) while the second denotes the end of the Master Sequence. -What is happening in this example is that our Shot0020_001 is set to use 50 frames but we've set it to use 100 frames on the Master Level. +When working with [Shot Tracks](Engine\Sequencer\HowTo\TracksShot) and viewing sequences from the Master Level (as well as the Shot Level), we evaluate the entire sequence at its relative time. +In the image below, we have two red markers for the ending of playback ranges, the first denotes the end of the Shot (from the Shot Level), while the second denotes the end of the Master Sequence. +What is happening in this example is that our `Shot0020_001` is set to use 50 frames but we've set it to use 100 frames on the Master Level. ![](Evaluation_1.png) -If we dive into our Shot, the first red marker denotes the end of the Shot at frame 50, while the second red marker denotes the end of the Shot at the master level. +If we dive into our Shot, the first red marker denotes the end of the Shot at frame 50, while the second red marker denotes the end of the Shot at the master Level. ![](Evaluation_2.png) Frames 50 through 100 are grayed out to indicate that they are not being considered for evaluation. -To address the difference in length, we could increase the amount of frames being evaluated at the Shot level to 100 or at the Master Sequence level, we could reduce the length of the Shot to 50 frames. - +To address the difference in length, we could increase the amount of frames being evaluated at the Shot Level to 100, or at the Master Sequence Level, we could reduce the length of the Shot to 50 frames. ##Specialized Viewports @@ -187,15 +202,15 @@ Sequencer allows you to use specialized viewports to make the editing process ea ![](SpecialViewports.png) -These [Cinematic Viewports](Engine\Sequencer\HowTo\ViewportOptions) give a better idea of what the scene will look like, and can be enabled from the **Viewport** options button. +These [Cinematic Viewports](Engine\Sequencer\HowTo\ViewportOptions) give a better idea of what the scene will look like, and they can be enabled from the **Viewport** options button. ##Cinematic Actors -From the **Modes** panel, under **Cinematic**, there are three Cinematic Actors you can use for crafting your cinematics. +From the **Modes** panel, from the **Cinematic** menu, there are three Cinematic Actors that can be used for crafting cinematics. ![](CineTools.png) -You can drag any of these into your level then add it to Sequencer, or you can drag it into Sequencer (which will make it a Spawnable). +You can drag any of these Cinematic Actors into your Level, adding them to Sequencer, or you can drag a Cinematic Actor into Sequencer, which will make it a Spawnable. ### Camera Rig Crane @@ -203,7 +218,7 @@ The **Camera Rig Crane** Actor can be used to simulate crane-like camera movemen ![](Crane.png)(w:480) -You can attach a Camera to the Camera Rig Crane Actor, then manipulate the crane's movement through the **Details** panel and **Crane Controls** values. Those values can affect the Crane Pitch, Crane Yaw, and Crane Arm Length. These values can be keyframed within Sequencer, which will allow you to adjust them during your cinematics (as desired). +You can attach a Camera to the Camera Rig Crane Actor, which enables you to manipulate the crane's movement through the **Details** panel and **Crane Controls** values. Those values can affect the Crane Pitch, Crane Yaw, and Crane Arm Length. All of these values can be Keyframed within Sequencer, which will allow you to adjust them during your cinematics (as desired). [REGION:note] Please see [Shooting from a Camera Rig Crane](Engine\Sequencer\HowTo\CameraRigCrane) for more information. @@ -215,7 +230,7 @@ The **Camera Rig Rail** Actor is a spline based tool that a Camera can be attach ![](Rail.png)(w:480) -You can select each spline point and alter the tangents to produce the path you want your camera to follow. The camera that is attached to the rail can be rotated independently, and the camera's position on the rail can be adjusted with the **Current Position on Rail** property inside of the **Details** panel. This value can also be keyframed. +You can select each spline point and alter the tangents to produce the path that you want your camera to follow. The camera that is attached to the rail can be rotated independently, and the camera's position on the rail can be adjusted with the **Current Position on Rail** property inside of the **Details** panel. This value can also be Keyframed. [REGION:note] Please see [Shooting from a Camera Rig Rail](Engine\Sequencer\HowTo\CameraRigRail) for more information. @@ -237,25 +252,32 @@ The Cine Camera Actor includes settings for Look at Tracking (following an Actor Please see [Using Cine Camera Actors](Engine\Sequencer\HowTo\CineCameraActors) for more information. [/REGION] - ##Sequence Recording One tool you can use to narrow down your content creation time is to use the **Sequence Recorder** to record gameplay (or Level Sequences) in order to generate new Level Sequence assets. [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -mvCPXslVb8Y -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + mvCPXslVb8Y + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] -Add a new recording, pick an Actor to record, and click Record to start capturing. When stopping the recording, new Level Sequence assets will be created. You can then incorporate them into your existing cinematic, or you can use pieces from the recorded Level Sequence to create new sequences. -You can also record audio to go along with your recorded sequence from an external microphone, which will allow you to narrate your sequence, or provide instructions while recording level editor actions. + + +To add a new recording, pick an Actor to record, and click Record to start capturing. When stopping the recording, new Level Sequence assets will be created. You can then incorporate them into your existing cinematic, or you can use pieces from the recorded Level Sequence to create new sequences. +You can also record audio to go along with your recorded sequence from an external microphone, which will allow you to narrate your sequence (or provide instructions while recording Level Editor actions). [REGION:note] Please see [Recording Gameplay](Engine/Sequencer/HowTo/SequenceRecorder) for more information. @@ -285,7 +307,7 @@ Please see [](Engine/Sequencer/HowTo/BurnIns) for a step-by-step guide on using [INCLUDE:Engine/Sequencer/HowTo/ImportExportEDLs#intro] -As part of exporting an EDL (Edit Decision List), you can also add **Frame Handles** automatically to each of your shots, and specify the number of frames you'd like to add. +As part of exporting an EDL, you can also add **Frame Handles** automatically to each of your shots, and specify the number of frames you would like to add. ![](RenderMovieSequence.png) @@ -293,17 +315,51 @@ As part of exporting an EDL (Edit Decision List), you can also add **Frame Handl Please see [](Engine/Sequencer/HowTo/ImportExportEDLs) for a step-by-step guide on using EDLs. [/REGION] - ### Custom Render Passes If you are looking to export your cinematic in different render passes, you can do so from the **Render Movie Settings** window. -This will allow you to specify the render pass(es) to use when exporting your sequence. You can also export HDR (high dynamic-range) data as .exr files, and define compression and color gamut settings. +This will allow you to specify the render pass(es) to use when exporting your sequence. You can also export HDR (High Dynamic-Range) data as .exr files, and define compression and color gamut settings. [REGION:note] Please see [](Engine\Sequencer\Workflow\CustomRenderPass) for more information. [/REGION] +## Embedded Sequences in Blueprint + +[REGION:warning] +This is an experimental feature that is currently undergoing development. Some aspects may not work as expected or may change in future revisions. +[/REGION] + +As of engine version 4.15, you can enable the **Actor Sequence Plugin** which enables you to add **Actor Sequence Components** to **Blueprints**. +Doing so provides the ability to embed Sequences directly into an Actor Blueprint which enables reuse of Sequences by binding the animations to the Blueprint instance and triggering them automatically or through the **Event Graph** of the Blueprint. + +Below is an example of a Blueprint created with a Spot Light and Actor Sequence Component that animates and changes the color of the light. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + bohLiPXTyMs + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +[REGION:note] +Please see [](Engine\Sequencer\HowTo\ActorSequence) for a step-by-step guide. +[/REGION] + + + ## Workflow Considerations @@ -313,3 +369,4 @@ Once you have a basic understanding of how the Sequencer Editor works, you may w Please see [Workflow Considerations](Engine\Sequencer\Workflow\ToolUsage) for more information. [/REGION] + diff --git a/Engine/Documentation/Source/Engine/Sequencer/Overview/SequencerOverview.JPN.udn b/Engine/Documentation/Source/Engine/Sequencer/Overview/SequencerOverview.JPN.udn index 33dc1282b4c2..6b0bcb5a6fec 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/Overview/SequencerOverview.JPN.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/Overview/SequencerOverview.JPN.udn @@ -1,16 +1,18 @@ -INTSourceChangelist:3349969 +INTSourceChangelist:3444205 Availability:Public Title:シーケンサーの概要 -Crumbs: +Crumbs:%ROOT% Description:シーケンサーは UE4 のマルチトラック エディタです。シネマティックス シーケンスを作成し、リアルタイムでプレビューするために使用します。 Navigation:topic parent:Engine/Sequencer -order:1 +order:2 Version:4.15 Related:Engine/Sequencer/ReferenceEditor Related:Engine/Sequencer/HowTo tags:Sequencer type:overview +tags:Getting Started +SkillLevel:Intermediate [TOC(start:2 end:2)] @@ -24,18 +26,17 @@ type:overview ![](LevelSequence.png) -これでレベルにレベル シーケンスが追加され、選択可能になり、そのプロパティは **Matinee アクタ** 同様に、**[Details (詳細)]** パネルから操作することができます。[Details] パネル (以下) で、レベル シーケンスがレベル開始時に自動的にプレイするか、シーケンスのプレイ速度、シーケンスがループするか、およびその他の設定を定義することができます。 +これでレベルに追加され、選択可能になり、プロパティを **[Details]** パネルで操作できるようになります (**Matinee アクタ** と同様に)。[Details] パネル (以下) で、レベル シーケンスがレベル開始時に自動的にプレイするか、シーケンスのプレイ速度、シーケンスがループするか、およびその他の設定を定義することができます。 ![](DetailsPanel.png) マチネとの違いですが、レベル シーケンスは自己完結型のアセットであり、あるレベル シーケンスを別のレベル シーケンスに埋め込むことができます。 -例えば、アニメートしたキャラクター、カメラなどを持つレベル シーケンスを、大きなシネマティックス シーケンスの一部のシーンとして作成することができます。 +例えば、アニメートしたキャラクターとカメラを持つレベル シーケンスを、大きなシネマティックス シーケンスの一部のシーンとして作成することができます。 -レベル シーケンスを作成する別の方法として、**コンテンツ ブラウザ** で **[Add New]** ボタンをクリックして、 _Animation_ の **Level Sequence** を選択します。この方法で行うと、Level Sequence アセットを作成していますが、レベルに配置していません。 +レベル シーケンスを作成する別の方法として、**コンテンツ ブラウザ** で **[Add New]** ボタンをクリックして、**[Animation]** メニューから **[Level Sequence]** を選択します。これを行うと、レベルに配置する前に Level Sequence アセットを作成しています。 ![](LevelSequence_B.png) - ## シーケンサーにトラックを追加する レベル シーケンスを作成し、それをダブルクリックしてシーケンス エディタを開き、シネマティックスの作成を開始することができます。 @@ -53,7 +54,7 @@ type:overview ドロップダウン メニューに選択対象のトラックが数種類が、**アクタをシーケンサー** に追加する機能として表示されます。この [Actor To Sequencer] オプションではレベルで選択したアクタをシーケンサーに追加して、シーン中に操作できます。 通常、アニメートし、動くキャラクター、動物、クリーチャーなどを持つシネマティックスを作成している場合、 [スケルタルメッシュ](Engine/Content/Types/SkeletalMeshes) を持ちますが、これをシーケンサーに追加する必要があります。 -例えば、以下ではレベルに配置したクマのスケルタルメッシュがあります。それを選択した状態で、次にシーケンサーの **[Add]** ボタンをクリックし、**[Actor To Sequencer]** を選択し、それを追加し、シーケンサー エディタで制御できるようにします。 +例えば、以下ではレベルに配置したクマのスケルタルメッシュがあります。クマを選択した状態で、次にシーケンサーの **[Add]** ボタンをクリックし、**[Actor To Sequencer]** を選択し、それを追加し、シーケンサー エディタで制御できるようにします。 ![](AddBear.png)(w:640) @@ -68,15 +69,21 @@ type:overview 以下では、アニメーションのサブトラックを選択し、スケルタルメッシュのクマが再生するアニメーションを割り当てます。 [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -KoksbI7ZOTM -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + KoksbI7ZOTM + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] ## 所有可能なものとスポーン可能なもの @@ -91,31 +98,37 @@ KoksbI7ZOTM 詳細は、 [**Spawnables(スポーン可能なもの)を作成する**](Engine\Sequencer\HowTo\Spawnables\) をご覧ください。 [/REGION] - ## シーンのキーフレーム設定 -一般的なアニメーション ツールを使い慣れている場合、キーフレームを使ってコンテンツを操作する考え方は馴染みがあるものでしょう。シーケンサーでは、タイムラインに沿った必要なポイントにプロパティを定義した **キー** を追加して(キーフレーム設定) コンテンツを操作することができます。 +一般的なアニメーション ツールを使い慣れている場合、キーフレームを使ってコンテンツを操作する考え方は馴染みがあるものでしょう。 +シーケンサーでは、タイムラインに沿った必要なポイントにプロパティを定義した **キー** を追加して(キーフレーム設定) コンテンツを操作することができます。 タイムラインでこうしたキーに到達すると、各キーフレームで定義したプロパティが、入力した値を反映するように更新されます。 以下のサンプル シーンでは Skeletal Mesh アクタの様々なトランスフォームにキーフレームを作成して動きを追加するプロセスを示しています。 [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -dVDNJkQxlRk -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + dVDNJkQxlRk + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] [REGION:caption] 上の画面では、**Location** トラックの開始位置にキーフレームを追加し、終了位置にもキーフレームを追加しました。 [/REGION] -キーフレームを追加するにはトラックを選択し、**Enter** を押すか、各トラックのキーフレーム追加ボタンをクリックします。 +トラックを選択して **Enter** を押すか、各トラック上で [add Keyframe] ボタンをクリックしてキーフレームを追加することができます。 ![](KeyframeButton.png) @@ -128,32 +141,35 @@ dVDNJkQxlRk [/REGION] [REGION:tip] -キーフレームを含むトラックを選択した状態で、**,** (コンマ) キーと **.** (ピリオド) キーを押して配置したキーフレーム間を迅速に移動することができます。 +選択したキーフレームを含むトラックで、**,** (コンマ) キーと **.** (ピリオド) キーを押して配置したキーフレーム間を迅速に移動することができます。 [/REGION] キー (または複数のキーやセクション) を選択した状態で、**[Transform Keys/Sections]** ツールを使って選択したものを再配置したり、再スケーリングすることができます。 ![](SelectionOption.png) -**[Ctrl+M]** キーを押すことによっても、[Transform Keys/Selection] ツールを開くことができます。 +**[Ctrl+M]** キーの組み合わせを押すことによっても、[Transform Keys/Selection] ツールを開くことができます。 これにより、キー / 選択したものを指定した量でオフセット、または指定した時間でキー / 選択したものをスケーリングする量をオフセットすることができます。 [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -890 -[/PARAMLITERAL] -[PARAMLITERAL:height] -196 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -Kd3CwzMwTLs -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + Kd3CwzMwTLs + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] - - - ### 再生範囲 シーケンサーでは、定義されたスタートとストップの再生範囲に基づきシーンを再生します (以下の画面の緑/赤のマーカー)。 @@ -168,9 +184,9 @@ Kd3CwzMwTLs ![](KeepInRange.png) -[ショット トラック](Engine\Sequencer\HowTo\TracksShot) を使った作業とマスター レベルおよびショット レベルからシーケンスを見る場合、シーケンス全体をその相対時間で評価します。 +[ショット トラック](Engine\Sequencer\HowTo\TracksShot) を使った作業とマスター レベル (およびショット レベル) からシーケンスを見る場合、シーケンス全体をその相対時間で評価します。 以下の画像では、再生範囲の終了時に赤いマーカーが 2 つあります。ひとつめは、ショットの終わりを (Shot レベルから)、2 つめはマスター シーケンスの終わりを示しています。 -この例では、Shot0020_001 は 50 フレームを使用するように設定していますが、マスター レベルでは 100 フレームを使用するように設定しています。 +この例では、`Shot0020_001` は 50 フレームを使用するように設定していますが、マスター レベルでは 100 フレームを使用するように設定しています。 ![](Evaluation_1.png) @@ -181,7 +197,6 @@ Shot をよく見ると、ひとつめの赤いマーカーはフレーム 50 フレーム 50 から 100 まで評価対象ではないことを示すためグレイアウトされています。 長さの違いに対処するために、ショット レベルで評価されているフレームの量を 100 に増やすことができます。またはマスター シーケンス レベルで、ショットの長さを 50 に減らすことができます。 - ## 特殊なビューポート シーケンサーでは特殊なビューポートを使って編集プロセスをやりやすくすることができます。 @@ -192,11 +207,11 @@ Shot をよく見ると、ひとつめの赤いマーカーはフレーム 50 ##Cinematic アクタ -**[Cinematic]** の **[Modes]** パネルには、シネマティックスを作成するための 3 種類の Cinematic アクタがあります。 +**[Modes]** パネルの **[Cinematic]** のメニューには、シネマティックスを作成するための 3 種類の Cinematic アクタがあります。 ![](CineTools.png) -こうしたものをレベルにドラッグしてからシーケンサーに追加したり、シーケンサーにドラッグすることができます (これでスポーン可能なものになります)。 +こうした Cinematic アクタをレベルにドラッグしてシーケンサーに追加したり、シーケンサーにドラッグしてスポーン可能なものにすることができます。 ### Camera Rig Crane @@ -204,7 +219,7 @@ Shot をよく見ると、ひとつめの赤いマーカーはフレーム 50 ![](Crane.png)(w:480) -カメラを Camera Rig Crane アクタにアタッチし、クレーンの動きを **[Details]** パネルと **[Crane Controls]** の値で操作します。こうした値は、クレーンのピッチ、クレーンのヨー、クレーンのアームの長さに影響を与えます。値をシーケンサー内でキーフレームすることができます。これにより、シネマティックス中に (必要に応じて) 調整することができます。 +カメラを Camera Rig Crane アクタにアタッチすることで、クレーンの動きを **[Details]** パネルと **[Crane Controls]** の値で操作することができます。こうした値は、クレーンのピッチ、クレーンのヨー、クレーンのアームの長さに影響を与えます。こうしたすべての値をシーケンサー内でキーフレーム化することができます。これにより、シネマティックス中に (必要に応じて) 調整することができます。 [REGION:note] 詳細は [**CameraRigCrane から撮影する**](Engine\Sequencer\HowTo\CameraRigCrane) をご覧ください。 @@ -238,25 +253,32 @@ Cine Camera アクタには、Look at トラッキング (Actor に追随)、Fil 詳細は [**CineCamera アクタを使用する**](Engine\Sequencer\HowTo\CineCameraActors) をご覧ください。 [/REGION] - ## シーケンスの記録 コンテンツ作成時間を短縮できるツールとして、**シーケンス レコーダー** があります。これを使って新しい Level Sequence アセットを生成するためにゲームプレイ (またはレベル シーケンス) を記録します。 [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -mvCPXslVb8Y -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + mvCPXslVb8Y + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] -新しい記録を追加し、記録対象のアクタを選んで、Record をクリックしてキャプチャを開始します。記録を停止すると新しい Level Sequence アセットが作成されます。これを既存のシネマティックスに組み込んだり、記録したレベル シーケンスの一部を使って新しいシーケンスを作成することができます。 -記録したシーケンスにあわせて外部のマイクからオーディオを記録することもできます。これにより、シーケンスにナレーションを付けたり、レベル エディタのアクションを記録しながら指示を与えることができます。 + + +新しい記録を追加するために、記録対象のアクタを選んで、Record をクリックしてキャプチャを開始します。記録を停止すると新しい Level Sequence アセットが作成されます。これを既存のシネマティックスに組み込んだり、記録したレベル シーケンスの一部を使って新しいシーケンスを作成することができます。 +記録したシーケンスに合わせて外部のマイクロフォンからオーディオを記録することもできます。これにより、シーケンスにナレーションを付けることができます (またはレベル エディタのアクションを記録しながら指示をすることもできます)。 [REGION:note] 詳細は [**ゲームプレイを記録する**](Engine/Sequencer/HowTo/SequenceRecorder) をご覧ください。 @@ -286,7 +308,7 @@ burn-ins の使用についての手順を示したガイドについては、[] [INCLUDE:Engine/Sequencer/HowTo/ImportExportEDLs#intro] -EDL (Edit Decision List) のエクスポートの一部として、各ショットに自動的に **Frame Handles** を追加して、追加するフレーム数を指定することができます。 +EDL のエクスポートの一部として、各ショットに自動的に **Frame Handles** を追加して、追加するフレーム数を指定することができます。 ![](RenderMovieSequence.png) @@ -294,17 +316,51 @@ EDL (Edit Decision List) のエクスポートの一部として、各ショッ EDLs の使用についての手順を示したガイドについては、[](Engine/Sequencer/HowTo/ImportExportEDLs) をご覧ください。 [/REGION] - ### カスタム レンダー パス 異なるレンダー パスでシネマティックスのエクスポートをするには、**[Render Movie Settings]** ウィンドウから行うことができます。 -ここからシーケンスをエクスポートする場合に使うレンダー パスを指定することができます。HDR データを.exr ファイルとしてエクスポートして、圧縮と色域の設定を定義することができます。 +ここからシーケンスをエクスポートする場合に使うレンダー パスを指定することができます。HDR (High Dynamic-Range) データを.exr ファイルとしてエクスポートして、圧縮と色域の設定を定義することができます。 [REGION:note] 詳細は、 [](Engine\Sequencer\Workflow\CustomRenderPass) をご覧ください。 [/REGION] +## ブループリントの埋め込みシーケンス + +[REGION:warning] +これは現在、開発進行中の実験的な機能です。一部の機能は期待どおりに機能しなかったり、将来のリビジョンで変更される可能性があります。 +[/REGION] + +アンリアル エンジン 4.15 時点では、**Actor Sequence Plugin** を有効にして、**Actor Sequence コンポーネント** を **ブループリント** に追加することができます。 +この機能により、シーケンスを直接 Actor ブループリントに埋め込んで、シーケンスを再利用できるようにします。これは、アニメーションをブループリント インスタンスに結合して、自動的にトリガーするか、ブループリントの **イベントグラフ** でトリガーして行います。 + +以下は、スポットライトと Actor Sequence コンポーネントを使って作成したライトの色をアニメートし変更するブループリントの例です。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + bohLiPXTyMs + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +[REGION:note] +操作ガイドについては、 [](Engine\Sequencer\HowTo\ActorSequence) をご覧ください。 +[/REGION] + + + ## ワークフロー上の考慮事項 @@ -314,3 +370,4 @@ EDLs の使用についての手順を示したガイドについては、[](Eng 詳細は、 [**ワークフロー上の考慮事項**](Engine\Sequencer\Workflow\ToolUsage) をご覧ください。 [/REGION] + diff --git a/Engine/Documentation/Source/Engine/Sequencer/Overview/SequencerOverview.KOR.udn b/Engine/Documentation/Source/Engine/Sequencer/Overview/SequencerOverview.KOR.udn index ad18e7588f0e..b78ee6be2b2d 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/Overview/SequencerOverview.KOR.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/Overview/SequencerOverview.KOR.udn @@ -1,7 +1,7 @@ -INTSourceChangelist:3349969 +INTSourceChangelist:3410507 Availability:Public Title: 시퀀서 개요 -Crumbs: +Crumbs:%ROOT% Description:시퀀서란 언리얼 엔진 4 에서 시네마틱 시퀀스를 실시간 미리보면서 만드는 데 사용되는 멀티 트랙 에디터입니다. Navigation:topic parent:Engine/Sequencer @@ -11,6 +11,7 @@ Related: Engine/Sequencer/ReferenceEditor Related: Engine/Sequencer/HowTo tags:Sequencer type:overview +SkillLevel:Intermediate [TOC(start:2 end:2)] @@ -35,7 +36,6 @@ Sequencer (시퀀서)는 [**마티네**](Engine\Matinee\) 차기 버전으로, ![](LevelSequence_B.png) - ## 시퀀서에 트랙 추가 레벨 시퀀스를 만들고 더블클릭하여 시퀀스 에디터가 열렸으면, 시네마틱 제작을 시작하면 됩니다. @@ -91,7 +91,6 @@ KoksbI7ZOTM 자세한 정보는 [](Engine\Sequencer\HowTo\Spawnables\) 문서를 참고하세요. [/REGION] - ## 씬 키프레임 작업 다른 애니메이션 툴에 익숙한 분이라면, 키프레임을 사용하여 콘텐츠를 구동시킨다는 개념에도 익숙할 것입니다. 그렇지 않은 경우, 요약하자면 시퀀서에서는 ("키프레임" 이라는 작업을 통해) **키** 를 추가하고 타임라인 상의 원하는 위치에 정의된 프로퍼티대로 콘텐츠를 조작할 수 있습니다. @@ -112,7 +111,7 @@ dVDNJkQxlRk [/OBJECT] [REGION:caption] -위에서 시작 위치에 키프레임을 하나, 끝 위치에 **위치** 트랙 키프레임을 하나 추가했습니다. +위의 **Location** (위치) 트랙에 대해, 시작 위치에 키프레임을 하나, 끝 위치에 키프레임을 하나 추가했습니다. [/REGION] 키프레임 추가 방법은, 트랙을 선택하고 **Enter** 키를 치거나, 각 트랙에 있는 키프레임 추가 버튼을 클릭하면 됩니다. @@ -151,9 +150,6 @@ Kd3CwzMwTLs [/PARAMLITERAL] [/OBJECT] - - - ### 재생 범위 시퀀서는 정의된 시작 / 정지 재생 범위에 따라 (아래 초록/빨강 마커) 씬을 재생합니다. @@ -181,7 +177,6 @@ Kd3CwzMwTLs 50 에서 100 프레임까지 회색으로 탈색된 것은 평가되지 않는다는 것을 나타냅니다. 길이 차이에 대한 처리를 위해서는, 샷 레벨에서 평가되는 프레임 양을 100 으로 늘리거나, 마스터 시퀀스 레벨에서 샷의 길이를 50 프레임으로 줄이면 됩니다. - ##전문 뷰포트 시퀀서에서는 전문 뷰포트를 사용하여 편집 프로세스를 간편화시킬 수 있습니다. @@ -196,7 +191,7 @@ Kd3CwzMwTLs ![](CineTools.png) -이들 중 아무거나 레벨에 끌어 놓은 뒤 시퀀서에 추가하거나, 시퀀서에 바로 끌어 놓아도 (스포너블이) 됩니다. +이들 시네마틱 액터 중 아무거나 레벨에 끌어 놓은 뒤 시퀀서에 추가하거나, 시퀀서에 바로 끌어 놓아도 (스포너블이) 됩니다. ### 카메라 릭 크레인 @@ -238,7 +233,6 @@ Cine Camera (시네 카메라) 액터는 기본 카메라 액터와 비슷합니 자세한 정보는 [](Engine\Sequencer\HowTo\CineCameraActors) 문서를 참고하세요. [/REGION] - ##시퀀스 녹화 콘텐츠 제작 시간 단축에 도움이 되는 툴 한 가지는, **시퀀스 레코더** 로 게임플레이(나 레벨 시퀀스)를 녹화하여 새로운 레벨 시퀀스 애셋을 생성하는 것입니다. @@ -294,7 +288,6 @@ EDL (Edit Decision List, 편집 결정 목록) 익스포트 작업의 일부분 EDL 사용법 단계별 안내는 [](Engine/Sequencer/HowTo/ImportExportEDLs) 문서를 참고하세요. [/REGION] - ### 커스텀 렌더 패스 시네마틱을 다른 렌더 패스로 익스포트하려는 경우, **Render Movie Settings** (렌더 무비 세팅) 창에서 할 수 있습니다. diff --git a/Engine/Documentation/Source/Engine/Sequencer/QuickStart/SequencerQuickStart.INT.udn b/Engine/Documentation/Source/Engine/Sequencer/QuickStart/SequencerQuickStart.INT.udn index 3f0b8123ef8b..9a6e21417e7f 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/QuickStart/SequencerQuickStart.INT.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/QuickStart/SequencerQuickStart.INT.udn @@ -9,40 +9,8 @@ Version: 4.12 type:quick start checkpoint:sequencerqs tags:Sequencer - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![](sequencerQS_topic.png) - [/PARAM] - [PARAM:title] - %Engine/Sequencer/QuickStart:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Sequencer/QuickStart] - [/PARAM] - [PARAM:description] - %Engine/Sequencer/QuickStart:description% - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![](sequencerQS_topic.png) - [/PARAM] - [PARAM:title] - %Engine/Sequencer/QuickStart:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Sequencer/QuickStart] - [/PARAM] - [PARAM:description] - %Engine/Sequencer/QuickStart:description% - [/PARAM] -[/OBJECT] -[/VAR] +tags:Getting Started +topic-image:sequencerQS_topic.png [OBJECT:EmbeddedVideo] [PARAMLITERAL:width] diff --git a/Engine/Documentation/Source/Engine/Sequencer/QuickStart/SequencerQuickStart.JPN.udn b/Engine/Documentation/Source/Engine/Sequencer/QuickStart/SequencerQuickStart.JPN.udn index d16ce7b2e86f..453c5b362bec 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/QuickStart/SequencerQuickStart.JPN.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/QuickStart/SequencerQuickStart.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3244012 +INTSourceChangelist:3429249 Availability:Public Title:シーケンサー クイック スタート Crumbs: %ROOT%, Engine @@ -10,40 +10,8 @@ Version:4.12 type:quick start checkpoint:sequencerqs tags:Sequencer - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![](sequencerQS_topic.png) - [/PARAM] - [PARAM:title] - %Engine/Sequencer/QuickStart:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Sequencer/QuickStart] - [/PARAM] - [PARAM:description] - %Engine/Sequencer/QuickStart:description% - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![](sequencerQS_topic.png) - [/PARAM] - [PARAM:title] - %Engine/Sequencer/QuickStart:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Sequencer/QuickStart] - [/PARAM] - [PARAM:description] - %Engine/Sequencer/QuickStart:description% - [/PARAM] -[/OBJECT] -[/VAR] +tags:Getting Started +topic-image:sequencerQS_topic.png [OBJECT:EmbeddedVideo] [PARAMLITERAL:width] diff --git a/Engine/Documentation/Source/Engine/Sequencer/QuickStart/SequencerQuickStart.KOR.udn b/Engine/Documentation/Source/Engine/Sequencer/QuickStart/SequencerQuickStart.KOR.udn index 1a4dd46653b6..4d57262b2203 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/QuickStart/SequencerQuickStart.KOR.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/QuickStart/SequencerQuickStart.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3244012 +INTSourceChangelist:3429249 Availability:Public Title: 시퀀서 퀵스타트 Crumbs: %ROOT%, Engine @@ -10,40 +10,8 @@ Version: 4.12 type:quick start checkpoint:sequencerqs tags:Sequencer - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![](sequencerQS_topic.png) - [/PARAM] - [PARAM:title] - %Engine/Sequencer/QuickStart:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Sequencer/QuickStart] - [/PARAM] - [PARAM:description] - %Engine/Sequencer/QuickStart:description% - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![](sequencerQS_topic.png) - [/PARAM] - [PARAM:title] - %Engine/Sequencer/QuickStart:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Sequencer/QuickStart] - [/PARAM] - [PARAM:description] - %Engine/Sequencer/QuickStart:description% - [/PARAM] -[/OBJECT] -[/VAR] +tags:Getting Started +topic-image:sequencerQS_topic.png [OBJECT:EmbeddedVideo] [PARAMLITERAL:width] diff --git a/Engine/Documentation/Source/Engine/Sequencer/Sequencer.CHN.udn b/Engine/Documentation/Source/Engine/Sequencer/Sequencer.CHN.udn index d7e4bc5c4bb1..7a49fe3c5be8 100644 --- a/Engine/Documentation/Source/Engine/Sequencer/Sequencer.CHN.udn +++ b/Engine/Documentation/Source/Engine/Sequencer/Sequencer.CHN.udn @@ -1,92 +1,47 @@ -INTSourceChangelist:3013123 +INTSourceChangelist:3429248 Availability:Public Title:Sequencer 编辑器 -Crumbs:%ROOT%, Engine -Description:Sequencer 是虚幻引擎 4 的多轨道编辑器,用于实时创建和预览过场动画序列。 +Crumbs: %ROOT%, Engine +Description:Sequencer 是虚幻引擎 4 的多轨迹编辑器,用于实时创建和预览动画序列。 Navigation:topic parent:Engine -order:3 +order:4 +topic-image:sequencer_topic.png social-image:sequencer_social.png - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Engine/Sequencer:title%](Engine/Sequencer/sequencer_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/cine_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Sequencer:title% - [/PARAM] - [PARAM:description] - %Engine/Sequencer:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Sequencer] - [/PARAM] -[/OBJECT] -[/VAR] -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Engine/Sequencer:title%](Engine/Sequencer/sequencer_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/cine_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Engine/Sequencer:title% - [/PARAM] - [PARAM:description] - %Engine/Sequencer:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/Sequencer] - [/PARAM] -[/OBJECT] -[/VAR] +related:Engine/Matinee +tags:Sequencer [REGION:banner] ![](SequencerBanner.png)(convert:false) [/REGION] -**Sequencer** 编辑器是虚幻引擎 4 中的两个过场动画编辑工具之一。在 Sequencer 推出之前,制作过场动画的主要手段是在 [**Matinee**](Engine/Matinee) 编辑器中操作。 -与 Matinee 类似,Sequencer 使用了各种用于定义场景构成的专用 **轨道**。 -可以向 Sequencer 添加几条骨骼网格轨道,然后添加动画轨道使这些骨骼网格活动起来,再添加摄像机轨道和镜头切换轨道来提供在不同摄像机之间切换的视角,这样您就有了设置过场动画序列的基础。 +**Sequencer** 是虚幻引擎中的两大动画编辑工具之一。在 Sequencer 之前,编辑动画的主要手段是 [**Matinee**](Engine/Matinee) 编辑器。 +和 Matinee 相似,Sequencer 使用诸多特殊 **轨迹** 定义动画场的组成。 +为 Sequencer 添加一些骨架网格体轨迹,然后添加动画轨迹为骨架网格体设置动画,放入镜头轨迹和镜头切换轨迹构成镜头之间的透视和循环。这样便拥有了设置动画序列的基础。 -在本页您将找到有关 Sequencer 编辑器的不同方面的文档链接。 -如果您刚刚接触 Sequencer,建议您查看 **基础** 部分,其中包含 Sequencer 编辑器的大体概述,分别介绍 Sequencer 编辑器各组件的编辑器参考,以及包含多份操作指南的部分(其中都是关于如何用 Sequencer 执行某些任务的一次性页面)。 +此页面包含指向 Sequencer 编辑器各方面的文档链接。 +如您刚开始接触 Sequencer,推荐阅读 **概要** 部分。其中包括 Sequencer 编辑器的高阶总览、详解 Sequencer 编辑器组件的编辑器参考、帮助用户快速上手的快速入门指南、多个讲述如何利用 Sequencer 执行特定任务的单页指南,以及一个工作流提示章节。 + +可在 Epic Games Launcher 的 Learn 标签中下载的 Sequencer Subway 项目范例将为您展示如何使用虚幻引擎 4 的 Sequencer 编辑器创建电影级的动画序列。 + +## 开始 + +[DIR(output:"topic" parent:"Engine/Sequencer" org:"hierarchy" end:"1" tags:"Getting Started")] + +## 概要 + +[DIR(output:"topic" parent:"Engine/Sequencer" org:"hierarchy" tags:"!Getting Started" path:"!Engine/Sequencer/HowTo")] + +## 指南 + +[DIR(output:"fancy" parent:"Engine/Sequencer/HowTo" org:"hierarchy" skill_Level:"Beginner")] +[DIR(output:"fancy" parent:"Engine/Sequencer/HowTo" org:"hierarchy" skill_Level:"Intermediate")] +[DIR(output:"fancy" parent:"Engine/Sequencer/HowTo" org:"hierarchy" skill_Level:"Advanced")] -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/start_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - 基础 - [/PARAM] - [PARAM:links] - * [](Engine\Sequencer\Overview "%Engine\Sequencer\Overview:description%") - * [](Engine\Sequencer\ReferenceEditor "%Engine\Sequencer\ReferenceEditor:description%") - * [](Engine\Sequencer\QuickStart "%Engine\Sequencer\QuickStart:description%") - * [](Engine\Sequencer\HowTo "%Engine\Sequencer\HowTo:description%") - * [](Engine\Sequencer\Workflow\ "%Engine\Sequencer\Workflow:description%") - [/PARAM] -[/OBJECT] - -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/related_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - 相关链接 - [/PARAM] - [PARAM:links] - * [Matinee 编辑器](Engine/Matinee "%Engine/Matinee:description%") - [/PARAM] -[/OBJECT] +## 示例 +[DIR(output:"topiccompact" parent:"Resources/Showcases" tags:"Sequencer")] -### Decal Mask (デカールマスク) +### Decal Mask (デカールマスク) [REGION:fullwidth] ![](Buffer_DecalMask.png) [/REGION] -* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** +* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** **Decal Mask** モードは、ディファード デカールを受けることが可能なサーフェスを全て白で表示します。不可能なオブジェクトは黒で表示されます。 -### Diffuse Color (ディフューズ カラー) +### Diffuse Color (ディフューズ カラー) [REGION:fullwidth] ![](VM_DiffuseColor.png) [/REGION] -* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** +* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** **Diffuse Color** は基本色とマテリアルのアンビエントオクルージョン入力の結果を表示します。 @@ -313,7 +313,7 @@ not sure why it's in there [/REGION] -* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** +* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** **Shading Model** モードでは、シーンの各マテリアルの Shading Model プロパティの値が表示されます。 @@ -324,7 +324,7 @@ not sure why it's in there |**マテリアルの Shading Model**|**Default Lit**|**Unlit**|**Subsurface**|**Preintegrated Skin**| -### Material AO (マテリアル AO) +### Material AO (マテリアル AO) [OBJECT:ComparisonSlider] [PARAM:before] @@ -335,25 +335,25 @@ not sure why it's in there [/PARAM] [/OBJECT] -* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** +* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** **Material AO** visualization モードは、マテリアルの _Ambient Occlusion_ 入力に接続している全てのテクスチャリングまたは Material Expression ノードの結果を表示します。 -### Metallic (メタリック) +### Metallic (メタリック) [REGION:fullwidth] ![](Buffer_Metallic.png) [/REGION] -* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** +* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** **Metallic** visualization モードは、マテリアルの _Metallic_ 入力に接続している全てのテクスチャリングまたは Material Expression ノードの結果を表示します。 -注意:メタルには、 0 または 1 のメタリック値を使用し、その間の値にはなりません。レイヤー ブレンディングのために 0 と 1 の間の値が発生しますが、物理マテリアルは常にメタルかそうでないかになります。 +注意:メタルには、 0 または 1 のメタリック値を使用し、その間の値にはなりません。レイヤー ブレンディングのために 0 と 1 の間の値が発生しますが、物理マテリアルは常にメタルかそうでないかになります。 -### Opacity (オパシティ) +### Opacity (オパシティ) [OBJECT:ComparisonSlider] [PARAM:before] @@ -364,13 +364,13 @@ not sure why it's in there [/PARAM] [/OBJECT] -* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** +* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** **Opacity** visualization モードは、マテリアルの Opacity 入力に接続している全てのテクスチャリングまたは Material Expression ノードの結果を表示します。上図では、キャラクターのドレッドロック (髪) に若干透明性があるのが分かると思います。 Opacity ビューモードは Opacity の使用中に不透明なマテリアルのみを表示します。 Opacity によってどれくらい遠くにライトが差し込むかを制御するので、サブサーフェス スキャタリング マテリアルには重要です。 -### Roughness (ラフネス) +### Roughness (ラフネス) [REGION:fullwidth] @@ -378,24 +378,24 @@ Opacity ビューモードは Opacity の使用中に不透明なマテリアル [/REGION] -* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** +* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** -**Roughness** visualization モードは、マテリアルの Roughness 入力に接続している全てのテクスチャリングまたは Material Expression ノードの結果を表示します。様々なリフレクションが発生するところでラフネスが変化します。 +**Roughness** visualization モードは、マテリアルの Roughness 入力に接続している全てのテクスチャリングまたは Material Expression ノードの結果を表示します。様々な反射が発生するところでラフネスが変化します。 -### Scene Color (シーン カラー) +### Scene Color (シーン カラー) [REGION:fullwidth] ![](Buffer_SceneColor.png) [/REGION] -* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** +* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** **Scene Color** はポストプロセスが完了する前にシーンの結果を表示します。つまり、露出、ブルーム、色補正、アンチ エイリアスの前という意味です。上図では、露出が明るくされていないため、シーンが非常に暗く表示されています。 -### Scene Depth (シーン深度) +### Scene Depth (シーン深度) @@ -404,7 +404,7 @@ Opacity ビューモードは Opacity の使用中に不透明なマテリアル [/REGION] -* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** +* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** **Scene Depth** は白 (最も遠く) から黒 (最も近く) への一定のグラディエントでのシーン深度を表示します。 @@ -416,7 +416,7 @@ Opacity ビューモードは Opacity の使用中に不透明なマテリアル [/REGION] -* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** +* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** **Separate Translucency RGB** は、透過マテリアルであり、 Separate Translucency を使用しているすべてのマテリアルの色情報を表示します。 @@ -429,76 +429,76 @@ Opacity ビューモードは Opacity の使用中に不透明なマテリアル [/REGION] -* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** +* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** **Separate Translucency A** は、透過マテリアルであり、 Separate Translucency を使用しているすべてのマテリアルのアルファ情報のみを表示します。 -### Specular Color (スペキュラカラー) +### Specular Color (スペキュラカラー) [REGION:fullwidth] ![](Buffer_SpecColor.png) [/REGION] -* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** +* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** **スペキュラ カラー** はマテリアルのスペキュラ反射に使用される色を表示します。通常は、基本色とメタリックの値の組み合わせから推測されます。 -### Specular (スペキュラ) +### Specular (スペキュラ) [REGION:fullwidth] ![](buffer_Specular.png) [/REGION] -* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** +* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** **Specular** は、マテリアルの Specular 入力に接続された全てのテクスチャリングまたは Material Expression ノードの結果を表示します。 -### Subsurface Color (サブサーフェス カラー) +### Subsurface Color (サブサーフェス カラー) [REGION:fullwidth] ![](buffer_SubsurfColor.png) [/REGION] -* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** +* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** **Subsurface Color** は、マテリアルの Subsurface Color 入力に接続された全てのテクスチャリングまたは Material Expression ノードの結果を表示します。 -### World Normal (ワールド空間の法線) +### World Normal (ワールド空間の法線) [REGION:fullwidth] ![](buffer_WorldNormal.png) [/REGION] -* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** +* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** **World Normal** は不透明なサーフェスのワールド空間法線を表示します。 -### アンビエント オクルージョン (AO) +### アンビエント オクルージョン (AO) [REGION:fullwidth] ![](buffer_AO.png) [/REGION] -* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** +* ビューモードのホットキー:**なし (デフォルトでメニューのみ)** **Ambient Occlusion (AO)** はシーンで行われたアンビエント オクルージョンの計算結果を表示します。この計算はエンジンがサーフェスと法線マップに基づいて行っているので、マテリアルに適用される AO テクスチャとは別のものです。 ## Landscape Visualizers -### Normal +### Normal (法線) [REGION:fullwidth] ![](Landscape_Normal.png) [/REGION] -**Normal** Landscape visualization モードは、通常の lit ステートのランドスケープを表示します。 +**Normal** Landscape visualization モードは、正常な lit ステートのランドスケープを表示します。 ### LOD @@ -511,7 +511,7 @@ Opacity ビューモードは Opacity の使用中に不透明なマテリアル -### Layer Density (レイヤーの密度) +### Layer Density (レイヤーの密度) [REGION:fullwidth] ![](Landscape_LayerDensity.png) @@ -522,11 +522,11 @@ Opacity ビューモードは Opacity の使用中に不透明なマテリアル -## Exposure (露出) +## Exposure (露出) [REGION:fullwidth] [OBJECT:EmbeddedVideo] diff --git a/Engine/Documentation/Source/Engine/UI/MeshPreviewScene/MeshPreviewScene.INT.udn b/Engine/Documentation/Source/Engine/UI/MeshPreviewScene/MeshPreviewScene.INT.udn index 62ea2a7611fa..5eead8479c12 100644 --- a/Engine/Documentation/Source/Engine/UI/MeshPreviewScene/MeshPreviewScene.INT.udn +++ b/Engine/Documentation/Source/Engine/UI/MeshPreviewScene/MeshPreviewScene.INT.udn @@ -73,19 +73,19 @@ profiles that can be shared between the various editor windows. 1. Select a profile from the drop-down menu next to **Scene Profile Settings**. [REGION:lightbox] - [![](RemoveProfileSelection.png)(w:350)](ProfileSelection.png) + [![](RemoveProfileSelection.png)(w:350)](RemoveProfileSelection.png) [/REGION] 2. Click on the button for **Remove Profile** to permanently delete the currently selected profile. [REGION:lightbox] - [![](RemoveProfileButton.png)(w:350)](ProfileSelection.png) + [![](RemoveProfileButton.png)(w:350)](RemoveProfileButton.png) [/REGION] 3. You will now see that profile has been removed leaving only the default profile and any other previously set up profiles. [REGION:lightbox] - [![](RemoveProfileSelection1.png)(w:350)](ProfileSelection.png) + [![](RemoveProfileSelection1.png)(w:350)](RemoveProfileSelection1.png) [/REGION] diff --git a/Engine/Documentation/Source/Engine/UI/MeshPreviewScene/MeshPreviewScene.JPN.udn b/Engine/Documentation/Source/Engine/UI/MeshPreviewScene/MeshPreviewScene.JPN.udn index 226bd4ab1ae5..e0b7fecca3da 100644 --- a/Engine/Documentation/Source/Engine/UI/MeshPreviewScene/MeshPreviewScene.JPN.udn +++ b/Engine/Documentation/Source/Engine/UI/MeshPreviewScene/MeshPreviewScene.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3277768 +INTSourceChangelist:3482378 Availability:Public Title:メッシュのプレビュー シーン Crumbs: %ROOT%, Engine @@ -74,19 +74,19 @@ tags:User Interface 1. **[Scene Profile Settings]** のドロップダウン メニューからプロファイルを選択します。 [REGION:lightbox] - [![](RemoveProfileSelection.png)(w:350)](ProfileSelection.png) + [![](RemoveProfileSelection.png)(w:350)](RemoveProfileSelection.png) [/REGION] 1. 現在選択しているプロファイルを完全に削除するには、**[Remove Profile]** ボタンをクリックします。 [REGION:lightbox] - [![](RemoveProfileButton.png)(w:350)](ProfileSelection.png) + [![](RemoveProfileButton.png)(w:350)](RemoveProfileButton.png) [/REGION] 1. プロファイルが取り除かれて、デフォルト プロファイルと以前設定されたプロファイルがあればそれが残っているのがわかります。 [REGION:lightbox] - [![](RemoveProfileSelection1.png)(w:350)](ProfileSelection.png) + [![](RemoveProfileSelection1.png)(w:350)](RemoveProfileSelection1.png) [/REGION] diff --git a/Engine/Documentation/Source/Engine/UI/ProjectSettings/ProjectSettings.INT.udn b/Engine/Documentation/Source/Engine/UI/ProjectSettings/ProjectSettings.INT.udn index e903e246e74a..63a28458f7cd 100644 --- a/Engine/Documentation/Source/Engine/UI/ProjectSettings/ProjectSettings.INT.udn +++ b/Engine/Documentation/Source/Engine/UI/ProjectSettings/ProjectSettings.INT.udn @@ -44,7 +44,33 @@ Version: 4.9 [/VAR] [REGION:fullwidth] -![](project_settings.png) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](project_settings.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](project_settings_Mac.png) + [/PARAM] + [/OBJECT] [/REGION] [TOC (start:2)] diff --git a/Engine/Documentation/Source/Engine/UI/ProjectSettings/ProjectSettings.KOR.udn b/Engine/Documentation/Source/Engine/UI/ProjectSettings/ProjectSettings.KOR.udn index 8041460885a1..d1fa8cc14106 100644 --- a/Engine/Documentation/Source/Engine/UI/ProjectSettings/ProjectSettings.KOR.udn +++ b/Engine/Documentation/Source/Engine/UI/ProjectSettings/ProjectSettings.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3481084 Availability:Public Title:프로젝트 세팅 Crumbs:%ROOT%, Engine, Engine/UI @@ -45,7 +45,33 @@ Version: 4.9 [/VAR] [REGION:fullwidth] -![](project_settings.png) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](project_settings.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](project_settings_Mac.png) + [/PARAM] + [/OBJECT] [/REGION] [TOC (start:2)] diff --git a/Engine/Documentation/Source/Engine/UI/PropertyMatrix/PropertyMatrix.INT.udn b/Engine/Documentation/Source/Engine/UI/PropertyMatrix/PropertyMatrix.INT.udn index 49ccf4dc8800..91c7f3b1916f 100644 --- a/Engine/Documentation/Source/Engine/UI/PropertyMatrix/PropertyMatrix.INT.udn +++ b/Engine/Documentation/Source/Engine/UI/PropertyMatrix/PropertyMatrix.INT.udn @@ -44,7 +44,33 @@ Version: 4.9 [/VAR] [REGION:fullwidth] -![](property_matrix.png) +[OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](PropertyMatrix_Windows.png) + [/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](PropertyMatrix_Mac.png) + [/PARAM] +[/OBJECT] [/REGION] [EXCERPT:Intro] diff --git a/Engine/Documentation/Source/Engine/UI/PropertyMatrix/PropertyMatrix.KOR.udn b/Engine/Documentation/Source/Engine/UI/PropertyMatrix/PropertyMatrix.KOR.udn index 228f9f46641c..8d134a7c08c5 100644 --- a/Engine/Documentation/Source/Engine/UI/PropertyMatrix/PropertyMatrix.KOR.udn +++ b/Engine/Documentation/Source/Engine/UI/PropertyMatrix/PropertyMatrix.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3481084 Availability:Public Title:프로퍼티 매트릭스 Crumbs:%ROOT%, Engine, Engine/UI @@ -45,7 +45,33 @@ Version: 4.9 [/VAR] [REGION:fullwidth] -![](property_matrix.png) +[OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](PropertyMatrix_Windows.png) + [/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](PropertyMatrix_Mac.png) + [/PARAM] +[/OBJECT] [/REGION] [EXCERPT:Intro] diff --git a/Engine/Documentation/Source/Engine/UI/SourceControl/SourceControl.INT.udn b/Engine/Documentation/Source/Engine/UI/SourceControl/SourceControl.INT.udn index 34f426e3e81e..800b76a00d9c 100644 --- a/Engine/Documentation/Source/Engine/UI/SourceControl/SourceControl.INT.udn +++ b/Engine/Documentation/Source/Engine/UI/SourceControl/SourceControl.INT.udn @@ -1,28 +1,18 @@ Availability: Public Title:Source Control -Crumbs:%ROOT%, Engine, Engine/UI +Crumbs: %ROOT% Description:This document overviews the Source Control features. -Version: 4.9 - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![](SourceControlTopic.png) - [/PARAM] - [PARAM:title] - %Engine/UI/SourceControl:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/UI/SourceControl] - [/PARAM] -[/OBJECT] -[/VAR] +type:overview +skilllevel:Beginner +Version: 4.16 +parent:Engine/UI +order: +tags:User Interface +topic-image:SourceControlTopic.png [TOC(start:2)] - - -Unreal Editor supports source control, allowing teams to coordinate their game development and design efforts, as well as handling version control. +The Unreal Editor has built-in support for source control packages. Source control is used to manage changes over time to code and data, and enables teams to coordinate their game development efforts. [REGION:note] Perforce and SVN are supported by default. @@ -36,13 +26,13 @@ You can activate source control in one of two ways: ### Activating Source Control via Editor Preferences -You can activate source control via the editor's main Preferences window (**Edit > Editor Preferences > Loading & Saving**). +You can activate source control via the Editor Preferences window (**Edit > Editor Preferences > Loading & Saving**). ![SourceControlPreferences.png](SourceControlPreferences.png) | Item | Description | | --- | --- | -| **Automatically Checkout on Asset Modification** | When checked, this will automatically check out any asset that has been modified. | +| **Automatically Checkout on Asset Modification** | When checked, this will automatically check out any asset that has been modified. | | **Prompt for Checkout on Package Modification** | When checked, a prompt will appear when you make changes to a source controlled-package, asking if you would like to check out (lock) that package. | | **Add New Files when Modified** | This will add new files into source control when they are modified. | | **Use Global Settings** | Use global source control login settings, rather than per-project. Changing this will require you to login again. | @@ -50,7 +40,7 @@ You can activate source control via the editor's main Preferences window (**Edit ### Activating Source Control via the Content Browser -You can also activate Source Control in the **Content Browser**. To do so, **right-click** any asset or folder. At the bottom of the context menu, in the **Source Control** section, click **Connect to Source Control**. +You can also activate Source Control in the **Content Browser**. To do so, right-click any asset or folder. At the bottom of the context menu, in the **Source Control** section, click **Connect to Source Control**. ![Connect to Source Control](CB_SourceControl.png) @@ -58,17 +48,16 @@ This will open a log-in screen where you can select your source-control system a ![Source Control Login](CB_SourceControlLogin.png) -Enter the appropriate information, and click **Accept Settings**. After source control is activated, the display of the assets in the **Content Browser** will change to reflect their source-control status, and some source-control options will be included on the **right-click** context menu. +Enter the appropriate information, and click **Accept Settings**. After source control is activated, the display of the assets in the **Content Browser** will change to reflect their source-control status, and some source-control options will be included on the right-click context menu. ## Status Icons -The **Content Browser** will display special icons on the **upper-right corner** of assets to give the source control status. Below are the available icons and their meanings: - +The **Content Browser** will display special icons on the upper-right corner of assets to give the source control status. Below are the available icons and their meanings: [REGION:imagetable] -| ![CheckedOutByYou.png](CheckedOutByYou.png)(w:178) | ![CheckedOut.png](CheckedOut.png)(w:178) | ![MarkedForAdd.png](MarkedForAdd.png)(w:178) | ![notInDepot.png](notInDepot.png)(w:178) | ![NotHadRevision.png](NotHadRevision.png)(w:178) +| ![CheckedOutByYou.png](CheckedOutByYou.png)(w:178) | ![CheckedOut.png](CheckedOut.png)(w:178) | ![MarkedForAdd.png](MarkedForAdd.png)(w:178) | ![NotInDepot.png](NotInDepot.png)(w:178) | ![NotHeadRevision.png](NotHeadRevision.png)(w:178) | --- | --- | --- | --- | --- | | Checked out by you | Checked out by another user | Marked for add | Not in depot | Newer version of file exists in source control @@ -76,7 +65,7 @@ The **Content Browser** will display special icons on the **upper-right corner** ## Source Control Actions -While source control is active, the following context menu will be available when you **right-click** on an asset: +While source control is active, the following context menu will be available when you right-click on an asset: ![SourceControlMenu.png](SourceControlMenu.png) @@ -87,22 +76,30 @@ While source control is active, the following context menu will be available whe | **History** | Gives a revision history list of the selected asset, allowing you to see previous edits. | | **Diff Against Depot** | This allows you to check the asset against the version currently stored in the source control depot. | -## Checking Out and In +## Checking Out and Checking In -To check out an asset for editing, simply **right-click** it and choose **Check Out**. However, when checking back in, there is a certain protocol which must be followed. +To check out an asset for editing, simply right-click it and choose **Check Out**. When checking the asset back in, adhere to the following protocol: -* **Right-click** on the asset and choose **Check In**. A dialog will appear with a required changelist description for the check-in. +* Right-click on the asset and choose **Check In**. A dialog will appear with a required changelist description for the check-in. * Enter a description, which will be added to the asset's revision history. * Click **OK** when finished. - ![ChangelistDescription.png](ChangelistDescription.png) [REGION:note] - A changelist description is required, so the *OK* button will not be enabled until a description is entered. +A changelist description is required, so the **OK** button will not be enabled until a description is entered. [/REGION] +## Content Hot Reloading + +**Content Hot Reloading** is a new feature that the in-editor source control uses to reload content automatically when the content has been modified by source control operations. Currently, automatic reloading only works when performing source control operations via the in-editor source control integration, and any external changes won't trigger a reload. We intend to remove this requirement in a later engine version, so that external changes will also trigger hot reloads. + +Content Hot Reloading also provides the ability to reload an asset from its last saved state on command. This can be done by right-clicking the asset in the **Content Browser** and selecting the **Reload** option under the **Asset Actions** group. This can be extremely useful if you have unsaved changes to an asset that you wish to discard in order to revert back to the on-disk version. + +![ContentHotReload.png](ContentHotReload.png) + +[REGION:note]This feature currently carries the requirement that you have source control active for your project.[/REGION:note] ## Deactivating Source Control @@ -114,7 +111,5 @@ Only use this option if you are absolutely certain that you do not want to use s **To deactivate source control**: -1. In the upper-right corner of the Level Editor window, click the green, double-arrow icon (![](icon_SourceControl.png)). This brings up the **Source Control Login** screen. +1. In the upper-right corner of the Level Editor window, click the green double-arrow icon (![](icon_SourceControl.png)). This brings up the **Source Control Login** screen. 1. Click the **Run Without Source Control** button. The green icon in the Level Editor window changes to a red circle with a slash (![](icon_CB_SourceControlOff.png)), to indicate that source control is not being used. - - diff --git a/Engine/Documentation/Source/Engine/UI/SourceControl/SourceControl.JPN.udn b/Engine/Documentation/Source/Engine/UI/SourceControl/SourceControl.JPN.udn index c079faa81931..6a92e7292906 100644 --- a/Engine/Documentation/Source/Engine/UI/SourceControl/SourceControl.JPN.udn +++ b/Engine/Documentation/Source/Engine/UI/SourceControl/SourceControl.JPN.udn @@ -1,29 +1,19 @@ -INTSourceChangelist:3082411 +INTSourceChangelist:3477895 Availability:Public Title:ソースコントロール -Crumbs:%ROOT%, Engine, Engine/UI +Crumbs: %ROOT% Description:このドキュメントでは、ソースコントロール機能の概要を説明します。 -Version:4.9 - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![](SourceControlTopic.png) - [/PARAM] - [PARAM:title] - %Engine/UI/SourceControl:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Engine/UI/SourceControl] - [/PARAM] -[/OBJECT] -[/VAR] +type:overview +skilllevel:Beginner +Version:4.16 +parent:Engine/UI +order: +tags:User Interface +topic-image:SourceControlTopic.png [TOC(start:2)] - - -エディタでは、ソースコントロールをサポートしています。これにより、チームはゲーム開発、デザイン作業、バージョン管理を調整することができます。 +アンリアル エディタでは、ソース コントロール パッケージをビルトイン サポートしています。ソース コントロールは時間経過に伴うコードやデータの変更を管理するために使用します。チーム内でゲーム制作の作業を調整することができます。 [REGION:note] Perforce と SVN はデフォルトでサポートされています。 @@ -35,23 +25,23 @@ Version:4.9 * レベル エディタの **[Preferences]** ウィンドウで有効にする * **コンテンツ ブラウザ** -### エディタの環境設定でソースコントロールを有効にする +### Editor Preferences (エディタの環境設定) でソースコントロールを有効にする -エディタのメインの [Preferences] ウィンドウでソースコントロールを有効にできます (**Edit > Editor Preferences > Loading & Saving** の順序で)。 +エディタの [Preferences] ウィンドウでソースコントロールを有効にすることができます (**Edit > Editor Preferences > Loading & Saving** の順序で選択)。 ![SourceControlPreferences.png](SourceControlPreferences.png) | アイテム | 説明 | | --- | --- | | **Automatically Checkout on Asset Modification** | チェックを入れると、変更されたアセットがあれば自動的にチェックアウトします。 | -| **Prompt for Checkout on Package Modification** | チェックを入れると、ソースコントロールされたパッケージを変更する場合に、そのパッケージをチェックアウト (ロック) したいかを尋ねるプロンプトが表示されます。 | +| **Prompt for Checkout on Package Modification** | チェックを入れると、ソースコントロールされたパッケージを変更する場合に、そのパッケージをチェックアウト (ロック) するかを尋ねるプロンプトが表示されます。 | | **Add New Files when Modified** | ファイルが修正されると、その新規ファイルがソースコントロールへ追加されます。 | | **Use Global Settings** | プロジェクト毎ではなく、グローバルなソースコントロールのログイン設定を使用します。これを変更するには再度ログインする必要があります。 | | **Tool for diffing text** | テキスト ファイルを比較し差分を検出するために使うツールへのファイル パスを指定します。 | ### [コンテンツ ブラウザ] でソースコントロールを有効にする -**[コンテンツ ブラウザ]** でソースコントロールをアクティベートすることもできます。これを行うには、任意のアセットまたはフォルダで **右クリック** します。コンテキスト メニューの一番下の**[ソースコントロール]** セクションで**[ソースコントロールへ接続]** をクリックします。 +**[コンテンツ ブラウザ]** でソースコントロールをアクティベートすることもできます。これを行うには、任意のアセットまたはフォルダで右クリックします。コンテキスト メニューの一番下の**[ソースコントロール]** セクションで**[ソースコントロールへ接続]** をクリックします。 ![Connect to Source Control](CB_SourceControl.png) @@ -59,17 +49,16 @@ Version:4.9 ![Source Control Login](CB_SourceControlLogin.png) -適切な情報を入力して、**[Accept Settings]** をクリックします。ソースコントロールがアクティベートしたら、**[コンテンツ ブラウザ]** のアセット表示がソースコントロールのステータスを反映するように変更されます。いくつかのソースコントロールのオプションが **右クリック** のコンテキストメニューに含まれます。 +適切な情報を入力して、**[Accept Settings]** をクリックします。ソースコントロールがアクティベートしたら、**[コンテンツ ブラウザ]** のアセット表示がソースコントロールのステータスを反映するように変更されます。いくつかのソースコントロールのオプションが 右クリック のコンテキストメニューに含まれます。 ##ステータスのアイコン -**[コンテンツ ブラウザ]** には、ソースコントロールのステータスを示す特別なアイコンがアセットの **右上** に表示されます。以下は利用可能なアイコンとその意味を示したものです。 - +**[コンテンツ ブラウザ]** には、ソースコントロールのステータスを示す特別なアイコンがアセットの 右上 に表示されます。以下は利用可能なアイコンとその意味を示したものです。 [REGION:imagetable] -| ![CheckedOutByYou.png](CheckedOutByYou.png)(w:178) | ![CheckedOut.png](CheckedOut.png)(w:178) | ![MarkedForAdd.png](MarkedForAdd.png)(w:178) | ![notInDepot.png](notInDepot.png)(w:178) | ![NotHadRevision.png](NotHadRevision.png)(w:178) +| ![CheckedOutByYou.png](CheckedOutByYou.png)(w:178) | ![CheckedOut.png](CheckedOut.png)(w:178) | ![MarkedForAdd.png](MarkedForAdd.png)(w:178) | ![NotInDepot.png](NotInDepot.png)(w:178) | ![NotHeadRevision.png](NotHeadRevision.png)(w:178) | --- | --- | --- | --- | --- | | 自分がチェックアウト | 他のユーザーがチェックアウト | 追加するためにマーク付けされたもの | デポにありません | ソースコントロールに新しいバージョンのファイルがあります @@ -77,7 +66,7 @@ Version:4.9 ## ソースコントロールのアクション -ソースコントロールが有効である間は、アセット上で **右クリック** することにより、以下のコンテキスト メニューを利用できます。 +ソースコントロールが有効である間は、アセット上で右クリックすることにより、以下のコンテキスト メニューを利用できます。 ![SourceControlMenu.png](SourceControlMenu.png) @@ -88,34 +77,40 @@ Version:4.9 | **History** | 選択したアセットの改訂履歴リストが表示されます。過去の編集履歴を見ることができます。 | | **Diff Against Depot** | 現在、ソースコントロール デポに保存されているバージョンに対してアセットをチェックすることができます。 | -## チェックアウト・チェックイン +## チェックアウトとチェックイン -編集を行うためにアセットをチェックアウトするには、そのアセット上で **右クリック** して、**チェックアウト** を選択します。しかし、再度チェックインする場合は、必ず従うべき手順があります。 +編集を行うためにアセットをチェックアウトするには、そのアセット上で右クリックして、**チェックアウト** を選択します。アセットをチェックインして戻す場合、以下の手順に従います。 -* アセット上で **右クリック** し、**チェックイン** を選択します。チェックインについて必要なチェンジリストの説明欄を含むダイアログが表示されます。 +* アセット上で右クリックし、**チェックイン** を選択します。チェックインについて必要なチェンジリストの説明欄を含むダイアログが表示されます。 * 簡単な説明を入力します。これはアセットの改訂履歴に追加されます。 * 終了したら **[OK]** をクリックしてください - ![ChangelistDescription.png](ChangelistDescription.png) [REGION:note] - チェンジリストの説明は必須であるため、入力されるまで *OK* ボタンは有効になりません。 +チェンジリストの説明は必須であるため、入力されるまで **OK** ボタンは有効になりません。 [/REGION] +##コンテンツのホット リロード + +**Content Hot Reloading (コンテンツのホット リロード)** は、ソース コントロールの操作によってコンテンツに変更が加えられた場合に、インエディタのソース コントロールでコンテンツを自動的にリロードする新機能です。現在、この自動リロードはインエディタのソース管理の統合を使ってソース コントロール操作を行っている場合にのみ機能します。外部で変更を加えてもリロードはトリガーされません。今後のバージョンではこの要件をなくして、外部の変更によってもホットリロードがトリガーするようにするつもりです。 + +コンテンツのホットリロードでは、指示すると最後に保存した状態からアセットをリロードする機能もあります。これは **コンテンツ ブラウザ** でアセットを右クリックして、 **Asset Actions** グループで **Reload** オプションを選択して行うことができます。これは、アセットに対して保存していない変更があり、それを破棄してディスク上のバージョンに戻したい場合に非常に便利です。 + +![ContentHotReload.png](ContentHotReload.png) + +[REGION:note]現在、この機能はプロジェクトに対してアクティブなソース コントロールを行っていることを前提とします。[/REGION:note] ## ソースコントロールを非アクティブにする アクティブにした後に、ソースコントロールを非アクティブにしたい場合があるかもしれません。 [REGION:warning] -ソースコントロールを使用したくないことが確実である場合に限り、このオプションを使用してください。ソースコントロールを非アクティブにすると、ソースコントロール システムとコンテンツが同期しなくなり、変更を登録できなくなります。 +ソースコントロールを使用しないことが確実である場合に限り、このオプションを使用してください。ソースコントロールを非アクティブにすると、ソースコントロール システムとコンテンツが同期しなくなり、変更を登録できなくなります。 [/REGION] **ソースコントロールを非アクティブにするには** 以下の手順に従います。 -1. [Level Editor] ウィンドウの右上隅で、緑色の矢印が2 つあるアイコン (![](icon_SourceControl.png)) をクリックします。これで **Source Control Login** 画面が表示されます。 -1. **Run Without Source Control** ボタンをクリックします。レベル エディタ ウィンドウの緑色のアイコンが、斜線付きの赤い円 (![](icon_CB_SourceControlOff.png)) に変わります。この赤い円は、ソースコントロールが使用されていないことを表します。 - - +1. [Level Editor] ウィンドウの右上隅で、緑色の矢印が 2 つあるアイコン (![](icon_SourceControl.png)) をクリックします。これで **[Source Control Login]** 画面が表示されます。 +1. **[Run Without Source Control]** ボタンをクリックします。レベル エディタ ウィンドウの緑色のアイコンが、斜線付きの赤い円 (![](icon_CB_SourceControlOff.png)) に変わります。この赤い円は、ソースコントロールが使用されていないことを表します。 diff --git a/Engine/Documentation/Source/Engine/UI/SourceControl/SourceControl.KOR.udn b/Engine/Documentation/Source/Engine/UI/SourceControl/SourceControl.KOR.udn index 5c2aff3cfd41..e452c671d68b 100644 --- a/Engine/Documentation/Source/Engine/UI/SourceControl/SourceControl.KOR.udn +++ b/Engine/Documentation/Source/Engine/UI/SourceControl/SourceControl.KOR.udn @@ -1,9 +1,13 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3464910 Availability: Public Title:소스 콘트롤 -Crumbs:%ROOT%, Engine, Engine/UI +Crumbs: Description:소스 콘트롤 기능에 대한 개요서입니다. -Version: 4.9 +Version: 4.16 +parent:Engine/UI +type:overview +skilllevel:Beginner +tags:User Interface [VAR:TopicCompact] [OBJECT:TopicCompact] @@ -22,7 +26,6 @@ Version: 4.9 [TOC(start:2)] - 언리얼 에디터는 소스 콘트롤을 지원, 팀의 조직적인 게임 개발 및 디자인 작업을 지원함은 물론, 버전 관리도 해 줍니다. [REGION:note] @@ -67,7 +70,6 @@ Version: 4.9 콘텐츠 브라우저에는 애셋 **우측 상단에** 특수 아이콘으로 소스 콘트롤 상태를 표시합니다. 아래는 표시되는 아이콘과 그 의미입니다: - [REGION:imagetable] | ![CheckedOutByYou.png](CheckedOutByYou.png)(w:178) | ![CheckedOut.png](CheckedOut.png)(w:178) | ![MarkedForAdd.png](MarkedForAdd.png)(w:178) | ![notInDepot.png](notInDepot.png)(w:178) | ![NotHadRevision.png](NotHadRevision.png)(w:178) | --- | --- | --- | --- | --- | @@ -97,13 +99,21 @@ Version: 4.9 * 완료되면 **OK** 를 클릭합니다. - ![ChangelistDescription.png](ChangelistDescription.png) [REGION:note] Changelist 의 설명은 필수이므로, 입력하지 않으면 *OK* 버튼은 나타나지 않습니다. [/REGION] +## 콘텐츠 핫 리로드 + +**Content Hot Reloading** (콘텐츠 핫 리로드)는 소스 콘트롤 작업에 의해 콘텐츠가 변경되었을 때 에디터내 소스 콘트롤에서 콘텐츠를 자동으로 리로드해 주는 신기능입니다. 자동 리로드는 현재 에디터내 통합된 소스 콘트롤을 통해서 소스 콘트롤 작업을 할 때만 작동하며, 외부에서는 변경해도 리로드가 발동되지 않습니다. 앞으로의 엔진 버전에서는 이러한 요건을 제거하여 외부에서 변경해도 핫 리로드가 발동되도록 할 계획입니다. + +콘텐츠 핫 리로드는 명령이 있을 때 애셋의 지난 번 저장 상태에서 리로드하는 기능도 제공합니다. 콘텐츠 브라우저에서 애셋에 우클릭하고 "애셋 액션" 그룹 아래 "리로드" 옵션을 선택하면 됩니다. 애셋에 저장하지 않은 변경사항을 버리고 디스크에 있는 버전으로 되돌리고자 할 때 매우 유용합니다. + +![ContentHotReload.png](ContentHotReload.png) + +[REGION:note]이 기능은 현재 프로젝트에 소스 콘트롤이 활성화된 상태여야 합니다. 이러한 요건은 앞으로의 엔진 버전에서 제거될 예정입니다.[/REGION:note] ## 소스 콘트롤 비활성화 diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/Create3DWidgets/ActorSetup/ActorSetup.INT.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/Create3DWidgets/ActorSetup/ActorSetup.INT.udn index 7dd765502ac9..36d66649ee6c 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/Create3DWidgets/ActorSetup/ActorSetup.INT.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/Create3DWidgets/ActorSetup/ActorSetup.INT.udn @@ -2,6 +2,7 @@ Availability:Docs Title:2. Setting up the Actor Blueprint Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo, Engine\UMG\HowTo\Create3DWidgets Description:Here we use an Actor Blueprint with a Widget Component to display our Widget Blueprint in 3D world space. +Parent:Engine/UMG/HowTo/Create3DWidgets Related: Engine/UMG Related: Engine/UMG/UserGuide Related: Engine/Blueprints @@ -9,6 +10,7 @@ Version: 4.10 SkillLevel: Intermediate checkpoint: umg_create_3d_howto tags:UMG UI Designer +Order: 2 [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/Create3DWidgets/ActorSetup/ActorSetup.JPN.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/Create3DWidgets/ActorSetup/ActorSetup.JPN.udn index 40b5e9344ab3..8269a0fbf211 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/Create3DWidgets/ActorSetup/ActorSetup.JPN.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/Create3DWidgets/ActorSetup/ActorSetup.JPN.udn @@ -1,8 +1,8 @@ -INTSourceChangelist:3343833 -Availability:Docs +Availability:Docs Title:2.Actor ブループリントをセットアップする Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo, Engine\UMG\HowTo\Create3DWidgets Description:Actor ブループリントを Widget コンポーネントと合わせて使用して、Widget ブループリントを 3D ワールド空間で表示します。 +Parent:Engine/UMG/HowTo/Create3DWidgets Related:Engine/UMG Related:Engine/UMG/UserGuide Related:Engine/Blueprints @@ -10,6 +10,7 @@ Version:4.10 SkillLevel:Intermediate checkpoint: umg_create_3d_howto tags:UMG UI Designer +Order:2 [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/Create3DWidgets/ActorSetup/ActorSetup.KOR.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/Create3DWidgets/ActorSetup/ActorSetup.KOR.udn index c114df25cf12..8edfc57eedb3 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/Create3DWidgets/ActorSetup/ActorSetup.KOR.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/Create3DWidgets/ActorSetup/ActorSetup.KOR.udn @@ -1,8 +1,9 @@ -INTSourceChangelist:3343833 +INTSourceChangelist:3478014 Availability:Docs Title:2. 액터 블루프린트 구성 Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo, Engine\UMG\HowTo\Create3DWidgets Description:위젯 컴포넌트가 포함된 액터 블루프린트를 사용해서 위젯 블루프린트를 3D 월드 스페이스에 표시합니다. +Parent:Engine/UMG/HowTo/Create3DWidgets Related: Engine/UMG Related: Engine/UMG/UserGuide Related: Engine/Blueprints @@ -10,6 +11,7 @@ Version: 4.10 SkillLevel: Intermediate checkpoint: umg_create_3d_howto tags:UMG UI Designer +Order: 2 [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/Create3DWidgets/WidgetSetup/WidgetSetup.INT.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/Create3DWidgets/WidgetSetup/WidgetSetup.INT.udn index 13e4bee00a1c..45c8c53c027c 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/Create3DWidgets/WidgetSetup/WidgetSetup.INT.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/Create3DWidgets/WidgetSetup/WidgetSetup.INT.udn @@ -2,6 +2,7 @@ Availability:Docs Title:1. Setting up the Widget Blueprint Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo, Engine\UMG\HowTo\Create3DWidgets Description:Here we create the Widget Blueprint that we want to display in the 3D game world. +Parent:Engine/UMG/HowTo/Create3DWidgets Related: Engine/UMG Related: Engine/UMG/UserGuide Related: Engine/Blueprints @@ -9,6 +10,7 @@ Version: 4.10 SkillLevel: Intermediate checkpoint: umg_create_3d_howto tags:UMG UI Designer +Order: 1 [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/Create3DWidgets/WidgetSetup/WidgetSetup.JPN.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/Create3DWidgets/WidgetSetup/WidgetSetup.JPN.udn index f8ea6018bc2a..4014a7eafddd 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/Create3DWidgets/WidgetSetup/WidgetSetup.JPN.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/Create3DWidgets/WidgetSetup/WidgetSetup.JPN.udn @@ -1,8 +1,9 @@ -INTSourceChangelist:3343833 +INTSourceChangelist:3478014 Availability:Docs Title:1.Widget ブループリントの設定 Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo, Engine\UMG\HowTo\Create3DWidgets Description:3D ゲームワールドで表示する Widget ブループリントを作成します。 +Parent:Engine/UMG/HowTo/Create3DWidgets Related:Engine/UMG Related:Engine/UMG/UserGuide Related:Engine/Blueprints @@ -10,6 +11,7 @@ Version:4.10 SkillLevel:Intermediate checkpoint: umg_create_3d_howto tags:UMG UI Designer +Order:1 [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/Create3DWidgets/WidgetSetup/WidgetSetup.KOR.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/Create3DWidgets/WidgetSetup/WidgetSetup.KOR.udn index f4d176306912..891a22dcc428 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/Create3DWidgets/WidgetSetup/WidgetSetup.KOR.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/Create3DWidgets/WidgetSetup/WidgetSetup.KOR.udn @@ -1,8 +1,9 @@ -INTSourceChangelist:3343833 +INTSourceChangelist:3478014 Availability:Docs Title:1. 위젯 블루프린트 구성 Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo, Engine\UMG\HowTo\Create3DWidgets Description:3D 게임 월드에 표시할 위젯 블루프린트를 만듭니다. +Parent:Engine/UMG/HowTo/Create3DWidgets Related: Engine/UMG Related: Engine/UMG/UserGuide Related: Engine/Blueprints @@ -10,6 +11,7 @@ Version: 4.10 SkillLevel: Intermediate checkpoint: umg_create_3d_howto tags:UMG UI Designer +Order: 1 [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/DragAndDrop.INT.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/DragAndDrop.INT.udn index ef81eb96df3d..807896481b57 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/DragAndDrop.INT.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/DragAndDrop.INT.udn @@ -1,10 +1,19 @@ -Availability:Docs +Availability:Public Title:Creating Drag and Drop UI Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo Description:Shows how you can create drag and droppable UI widgets with UMG. Version: 4.15 SkillLevel: Intermediate +parent:Engine/UMG/HowTo +order:1 +checkpoint: editorqs +Related: Engine/UMG +Related: Engine/UMG/UserGuide tags:UMG UI Designer +tags:UI +type:how-to + + There may be instances in your project where you want your players to be able to interact with UI elements by dragging and dropping them onscreen. This could be to customize interface layouts (positioning health bars or unit frames) or interacting with gameplay systems like inventory screens (adding/removing items around). @@ -13,15 +22,21 @@ With UMG you can create these types of interactions with the **DragAndDropOperat In this example, we take a look at how a player can drag and reposition a health bar on screen with the Left Mouse Button. [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -kYkhxuJsVs4 -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + kYkhxuJsVs4 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] _At the end of this guide, you will have a UI widget that you can drag around inside the viewport and drop at a new location._ diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/DragAndDrop.JPN.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/DragAndDrop.JPN.udn index 7feb8190b38b..20ed9b0c6bf0 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/DragAndDrop.JPN.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/DragAndDrop.JPN.udn @@ -1,11 +1,20 @@ -INTSourceChangelist:3343774 -Availability:Docs +INTSourceChangelist:3452142 +Availability:Public Title:ドラッグ&ドロップの UI を作成する Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo Description:UMG を使って、ドラッグ、ドロップ可能な UI ウィジェットを作成する方法を説明します。 Version:4.15 SkillLevel:Intermediate +parent:Engine/UMG/HowTo +order:1 +checkpoint: editorqs +Related:Engine/UMG +Related:Engine/UMG/UserGuide tags:UMG UI Designer +tags:UI +type:how-to + + プロジェクトでプレイヤーが画面上で UI エレメントをドラッグ&ドロップできるようにしたい場合があるかもしれません。 これには、インターフェースのレイアウトをカスタマイズしたり (ヘルスバーやユニット フレームを配置)、インベントリ画面 (アイテムを追加したり、取り除いたりします) でゲームプレイ システムとインタラクションするなどが考えられます。 @@ -14,15 +23,21 @@ UMG を使って、**DragAndDropOperation** ノードを使ってこうしたタ この例では、プレイヤーが左マウスボタンを使って画面上のヘルスバーをドラッグして再配置する方法を示します。 [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -kYkhxuJsVs4 -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + kYkhxuJsVs4 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] _このガイドの最後まで進むと、ビューポート内でドラッグして、新しい場所にドロップできる UI ウィジェットを作成することができます。_ diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/DragAndDrop.KOR.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/DragAndDrop.KOR.udn index 48f3d54e2137..f372027d2d33 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/DragAndDrop.KOR.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/DragAndDrop.KOR.udn @@ -1,11 +1,20 @@ -INTSourceChangelist:3343774 -Availability:Docs +INTSourceChangelist:3452142 +Availability:Public Title:드래그 앤 드롭 UI 제작 Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo Description:UMG 로 드래그 앤 드롭 가능한 UI 위젯을 만드는 법을 보여드립니다. Version: 4.15 SkillLevel: Intermediate +parent:Engine/UMG/HowTo +order:1 +checkpoint: editorqs +Related: Engine/UMG +Related: Engine/UMG/UserGuide tags:UMG UI Designer +tags:UI +type:how-to + + 프로젝트에서 플레이어가 UI 엘리먼트를 화면상에서 드래그 앤 드롭으로 상호작용할 수 있도록 했으면 싶은 때가 있습니다. 인터페이스 레이아웃 커스터마이징 (헬스 바 또는 유닛 프레임 위치 이동) 또는 인벤토리 화면같은 게임플레이 시스템 상호작용 (아이템 추가/제거) 등이 될 수 있습니다. @@ -14,15 +23,21 @@ UMG 에서 **DragAndDropOperation** 노드로 이러한 상호작용 유형을 이 예제에서는 플레이어가 왼쪽 마우스 버튼으로 화면상의 헬스 바를 끌어 위치를 조정할 수 있도록 만드는 방법을 살펴봅니다. [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -kYkhxuJsVs4 -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + kYkhxuJsVs4 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] _이 가이드를 마칠 즈음엔 뷰포트 안에서 드래그하여 새 위치에 드롭할 수 있는 UI 위젯이 생길 것입니다._ @@ -49,3 +64,4 @@ _이 가이드를 마칠 즈음엔 뷰포트 안에서 드래그하여 새 위 [클릭하면 시작합니다.](Engine\UMG\HowTo\DragAndDrop\ProjectSetup "%Engine\UMG\HowTo\DragAndDrop\ProjectSetup:title%") [/REGION] + diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/FinishingUp/FinishingUp.INT.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/FinishingUp/FinishingUp.INT.udn index b34e2968e4f2..0f3708187722 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/FinishingUp/FinishingUp.INT.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/FinishingUp/FinishingUp.INT.udn @@ -1,11 +1,18 @@ -Availability: Docs +Availability: Public Title:5. Finishing Up Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo Description:We finish by configuring our drag widget, adding our Health Bar to our Main HUD for display and testing everything out. +SkillLevel: Intermediate +Version: 4.15 +parent:Engine/UMG/HowTo/DragAndDrop +order:5 +checkpoint: editorqs Related: Engine/UMG Related: Engine/UMG/UserGuide -SkillLevel: Intermediate tags:UMG UI Designer +tags:UI +type:how-to + [VAR:Steps] [OBJECT:Navigation] @@ -71,17 +78,24 @@ We then tell our Character Blueprint to add the **HUD** Widget Blueprint to the When you play in the Editor, you can **Left-click** and drag the health bar on screen then drop it in a new location. [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -kYkhxuJsVs4 -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + kYkhxuJsVs4 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] + This is just an example of the elements you will need to start the Drag and Drop process. Additional checking may be needed to ensure that players do not drag the widget outside of Safe Zones or potentially on top of other widgets. diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/FinishingUp/FinishingUp.JPN.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/FinishingUp/FinishingUp.JPN.udn index 265cf2629aac..9f088c132c0b 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/FinishingUp/FinishingUp.JPN.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/FinishingUp/FinishingUp.JPN.udn @@ -1,12 +1,19 @@ -INTSourceChangelist:3343774 -Availability:Docs +INTSourceChangelist:3478014 +Availability:Public Title:5.仕上げ Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo Description:ドラッグ ウィジェットを設定し、ヘルスバーをメインの HUD に追加して表示させ、すべてのものをテストします。 +SkillLevel:Intermediate +Version:4.15 +parent:Engine/UMG/HowTo/DragAndDrop +order:5 +checkpoint: editorqs Related:Engine/UMG Related:Engine/UMG/UserGuide -SkillLevel:Intermediate tags:UMG UI Designer +tags:UI +type:how-to + [VAR:Steps] [OBJECT:Navigation] @@ -72,19 +79,25 @@ tags:UMG UI Designer エディタでプレイする場合、**左クリック** して画面上のヘルスバーをドラッグして、新しい位置にドロップします。 [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -kYkhxuJsVs4 -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + kYkhxuJsVs4 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] -これは、ドラッグ&ドロップのプロセスを開始するために必要な要素の一例にすぎません。 +これは、ドラッグ&ドロップのプロセスを開始するために必要な要素の一例にすぎません。 プレイヤーがセーフゾーンの外側にウィジェットをドラッグしないように、または他のウィジェットの上に重ならないようにさらにチェックが必要になることがあります。 %Steps% diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/FinishingUp/FinishingUp.KOR.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/FinishingUp/FinishingUp.KOR.udn index 6b762ab1dd0a..e9b6e9824d33 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/FinishingUp/FinishingUp.KOR.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/FinishingUp/FinishingUp.KOR.udn @@ -1,12 +1,19 @@ -INTSourceChangelist:3343774 -Availability: Docs +INTSourceChangelist:3478014 +Availability: Public Title:5. 마무리 Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo Description:드래그 위젯 환경설정, 메인 HUD 에 표시 및 테스트용 Health Bar 를 추가하여 마무리하도록 합니다. +SkillLevel: Intermediate +Version: 4.15 +parent:Engine/UMG/HowTo/DragAndDrop +order:5 +checkpoint: editorqs Related: Engine/UMG Related: Engine/UMG/UserGuide -SkillLevel: Intermediate tags:UMG UI Designer +tags:UI +type:how-to + [VAR:Steps] [OBJECT:Navigation] @@ -72,17 +79,24 @@ tags:UMG UI Designer 에디터에서 플레이 후, 화면에서 Health Bar 를 **좌클릭** 드래그 후 새 위치에 드롭합니다. [OBJECT:EmbeddedVideo] -[PARAMLITERAL:width] -640 -[/PARAMLITERAL] -[PARAMLITERAL:height] -360 -[/PARAMLITERAL] -[PARAMLITERAL:videoid] -kYkhxuJsVs4 -[/PARAMLITERAL] + [PARAMLITERAL:videoid] + kYkhxuJsVs4 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] + 이는 드래그 앤 드롭 프로세스를 시작하는 데 필요한 엘리먼트 예제일 뿐입니다. 플레이어가 위젯을 세이프 존 외부 혹은 다른 위젯 위에 드래그하지는 않았나 추가적인 확인이 필요할 수 있습니다. diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/OnDragDetected/OnDragDetected.INT.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/OnDragDetected/OnDragDetected.INT.udn index 4107ff515e0d..eb628fbc1ffd 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/OnDragDetected/OnDragDetected.INT.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/OnDragDetected/OnDragDetected.INT.udn @@ -1,11 +1,18 @@ -Availability: Docs +Availability: Public Title:3. On Drag Detected Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo Description:In this step we set up what happens when drag is detected. +SkillLevel: Intermediate +Version: 4.15 +parent:Engine/UMG/HowTo/DragAndDrop +order:3 +checkpoint: editorqs Related: Engine/UMG Related: Engine/UMG/UserGuide -SkillLevel: Intermediate tags:UMG UI Designer +tags:UI +type:how-to + [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/OnDragDetected/OnDragDetected.JPN.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/OnDragDetected/OnDragDetected.JPN.udn index ef2a929d87fe..376546bf1ed1 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/OnDragDetected/OnDragDetected.JPN.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/OnDragDetected/OnDragDetected.JPN.udn @@ -1,12 +1,19 @@ -INTSourceChangelist:3343774 -Availability:Docs +INTSourceChangelist:3478014 +Availability:Public Title:3.On Drag Detected Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo Description:ドラッグが検知された場合に、何を起こるかを設定します。 +SkillLevel:Intermediate +Version:4.15 +parent:Engine/UMG/HowTo/DragAndDrop +order:3 +checkpoint: editorqs Related:Engine/UMG Related:Engine/UMG/UserGuide -SkillLevel:Intermediate tags:UMG UI Designer +tags:UI +type:how-to + [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/OnDragDetected/OnDragDetected.KOR.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/OnDragDetected/OnDragDetected.KOR.udn index e5533be80f69..345d1eb2c9f9 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/OnDragDetected/OnDragDetected.KOR.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/OnDragDetected/OnDragDetected.KOR.udn @@ -1,12 +1,19 @@ -INTSourceChangelist:3343774 -Availability: Docs +INTSourceChangelist:3478014 +Availability: Public Title:3. 드래그 감지 시 Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo Description:이번 단계에서는 드래그를 감지했을 때 어떤 일이 벌어질지 구성합니다. +SkillLevel: Intermediate +Version: 4.15 +parent:Engine/UMG/HowTo/DragAndDrop +order:3 +checkpoint: editorqs Related: Engine/UMG Related: Engine/UMG/UserGuide -SkillLevel: Intermediate tags:UMG UI Designer +tags:UI +type:how-to + [VAR:Steps] [OBJECT:Navigation] @@ -73,3 +80,4 @@ tags:UMG UI Designer %Steps% + diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/OnDrop/OnDrop.INT.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/OnDrop/OnDrop.INT.udn index f6d73b4a67b7..d956a71e935d 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/OnDrop/OnDrop.INT.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/OnDrop/OnDrop.INT.udn @@ -1,11 +1,18 @@ -Availability: Docs +Availability: Public Title:4. On Drop Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo Description:In this step, we configure what happens when the player drops the dragged widget. +SkillLevel: Intermediate +Version: 4.15 +parent:Engine/UMG/HowTo/DragAndDrop +order:4 +checkpoint: editorqs Related: Engine/UMG Related: Engine/UMG/UserGuide -SkillLevel: Intermediate tags:UMG UI Designer +tags:UI +type:how-to + [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/OnDrop/OnDrop.JPN.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/OnDrop/OnDrop.JPN.udn index 78b0a9d9bfc9..8eb3d28a985a 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/OnDrop/OnDrop.JPN.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/OnDrop/OnDrop.JPN.udn @@ -1,12 +1,19 @@ -INTSourceChangelist:3343774 -Availability:Docs +INTSourceChangelist:3478014 +Availability:Public Title:4.On Drop Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo Description:プレイヤーがドラッグしたウィジェットをドロップしたときに何がおこるかを設定します。 +SkillLevel:Intermediate +Version:4.15 +parent:Engine/UMG/HowTo/DragAndDrop +order:4 +checkpoint: editorqs Related:Engine/UMG Related:Engine/UMG/UserGuide -SkillLevel:Intermediate tags:UMG UI Designer +tags:UI +type:how-to + [VAR:Steps] [OBJECT:Navigation] @@ -74,7 +81,6 @@ tags:UMG UI Designer _フルサイズ表示するにはここをクリック_ **Remove DPIScale** のチェックを外して、**Return Value** のチェックボックスにチェックを入れています。[](Engine/UMG/UserGuide/DPIScaling) を取り除く必要はなく、この関数を処理したため true として戻します。 - このスクリプトでは、最初に既存の Health Bar ウィジェットを取り除いてから、Drag Offset に相対的に画面の新しい位置に再度追加しています。 HUD はドラッグしたウィジェットをドロップ処理するようにセットアップされて、ヘルスバーを表示させます。 diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/OnDrop/OnDrop.KOR.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/OnDrop/OnDrop.KOR.udn index d7905048b290..99f5e42940b1 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/OnDrop/OnDrop.KOR.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/OnDrop/OnDrop.KOR.udn @@ -1,12 +1,19 @@ -INTSourceChangelist:3343774 -Availability: Docs +INTSourceChangelist:3478014 +Availability: Public Title:4. 드롭 시 Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo Description:이번 단계에서는 플레이어 드래그중인 위젯을 드롭했을 때 벌어지는 일을 설정합니다. +SkillLevel: Intermediate +Version: 4.15 +parent:Engine/UMG/HowTo/DragAndDrop +order:4 +checkpoint: editorqs Related: Engine/UMG Related: Engine/UMG/UserGuide -SkillLevel: Intermediate tags:UMG UI Designer +tags:UI +type:how-to + [VAR:Steps] [OBJECT:Navigation] @@ -81,3 +88,4 @@ HUD 가 드래그중인 위젯 드롭을 처리하고 Health Bar 를 표시하 %Steps% + diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/ProjectSetup/ProjectSetup.INT.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/ProjectSetup/ProjectSetup.INT.udn index aeb5d9325734..fbaf2d8abbe2 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/ProjectSetup/ProjectSetup.INT.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/ProjectSetup/ProjectSetup.INT.udn @@ -1,9 +1,18 @@ -Availability: Docs +Availability: Public Title:1. Project Setup Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo Description:Here we create the assets that we'll need and our DragAndDropOperation Class. SkillLevel: Intermediate +Version: 4.15 +parent:Engine/UMG/HowTo/DragAndDrop +order:1 +checkpoint: editorqs +Related: Engine/UMG +Related: Engine/UMG/UserGuide tags:UMG UI Designer +tags:UI +type:how-to + [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/ProjectSetup/ProjectSetup.JPN.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/ProjectSetup/ProjectSetup.JPN.udn index 95cb66a96def..6ddd90e2722a 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/ProjectSetup/ProjectSetup.JPN.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/ProjectSetup/ProjectSetup.JPN.udn @@ -1,10 +1,19 @@ -INTSourceChangelist:3355771 -Availability:Docs +INTSourceChangelist:3478014 +Availability:Public Title:1.プロジェクト設定 Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo Description:必要なアセットと DragAndDropOperation クラスを作成します。 SkillLevel:Intermediate +Version:4.15 +parent:Engine/UMG/HowTo/DragAndDrop +order:1 +checkpoint: editorqs +Related:Engine/UMG +Related:Engine/UMG/UserGuide tags:UMG UI Designer +tags:UI +type:how-to + [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/ProjectSetup/ProjectSetup.KOR.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/ProjectSetup/ProjectSetup.KOR.udn index 1ad6795e3158..9be9785e66f8 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/ProjectSetup/ProjectSetup.KOR.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/ProjectSetup/ProjectSetup.KOR.udn @@ -1,10 +1,19 @@ -INTSourceChangelist:3355771 -Availability: Docs +INTSourceChangelist:3478014 +Availability: Public Title:1. 프로젝트 셋업 Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo Description:필수 애셋과 DragAndDropOperation 클래스를 만듭니다. SkillLevel: Intermediate +Version: 4.15 +parent:Engine/UMG/HowTo/DragAndDrop +order:1 +checkpoint: editorqs +Related: Engine/UMG +Related: Engine/UMG/UserGuide tags:UMG UI Designer +tags:UI +type:how-to + [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/WidgetSetup/WidgetSetup.INT.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/WidgetSetup/WidgetSetup.INT.udn index d2cecf662e43..83d6a583cc4e 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/WidgetSetup/WidgetSetup.INT.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/WidgetSetup/WidgetSetup.INT.udn @@ -1,9 +1,18 @@ -Availability: Docs +Availability: Public Title:2. Widget Setup Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo Description:In this step we script what happens when the Left Mouse Button is pressed. SkillLevel: Intermediate +Version: 4.15 +parent:Engine/UMG/HowTo/DragAndDrop +order:2 +checkpoint: editorqs +Related: Engine/UMG +Related: Engine/UMG/UserGuide tags:UMG UI Designer +tags:UI +type:how-to + [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/WidgetSetup/WidgetSetup.JPN.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/WidgetSetup/WidgetSetup.JPN.udn index b2a3a51ae7d0..a81e3d6f8650 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/WidgetSetup/WidgetSetup.JPN.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/WidgetSetup/WidgetSetup.JPN.udn @@ -1,10 +1,19 @@ -INTSourceChangelist:3343774 -Availability:Docs +INTSourceChangelist:3478014 +Availability:Public Title:2.ウィジェットのセットアップ Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo Description:左マウスボタンを押したときに何がおこるかをスクリプティングします。 SkillLevel:Intermediate +Version:4.15 +parent:Engine/UMG/HowTo/DragAndDrop +order:2 +checkpoint: editorqs +Related:Engine/UMG +Related:Engine/UMG/UserGuide tags:UMG UI Designer +tags:UI +type:how-to + [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/WidgetSetup/WidgetSetup.KOR.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/WidgetSetup/WidgetSetup.KOR.udn index cdf7c5f8b9ec..256699a973cb 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/WidgetSetup/WidgetSetup.KOR.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/DragAndDrop/WidgetSetup/WidgetSetup.KOR.udn @@ -1,10 +1,19 @@ -INTSourceChangelist:3343774 -Availability: Docs +INTSourceChangelist:3478014 +Availability: Public Title:2. 위젯 셋업 Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo Description:여기서는 왼쪽 마우스 버튼을 눌렀을 때 벌어지는 일에 대한 스크립트를 작성합니다. SkillLevel: Intermediate +Version: 4.15 +parent:Engine/UMG/HowTo/DragAndDrop +order:2 +checkpoint: editorqs +Related: Engine/UMG +Related: Engine/UMG/UserGuide tags:UMG UI Designer +tags:UI +type:how-to + [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/ActorSetup/ActorSetup.INT.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/ActorSetup/ActorSetup.INT.udn index f7d9a8540235..50dbdcda8e76 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/ActorSetup/ActorSetup.INT.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/ActorSetup/ActorSetup.INT.udn @@ -7,6 +7,7 @@ Related: Engine/UMG Related: Engine/UMG/UserGuide SkillLevel: Advanced tags:UMG UI Designer +Order: 3 [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/ActorSetup/ActorSetup.JPN.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/ActorSetup/ActorSetup.JPN.udn index 61eda027a0a4..fc6f2b72a46c 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/ActorSetup/ActorSetup.JPN.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/ActorSetup/ActorSetup.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3343902 +INTSourceChangelist:3376720 Availability:Public Title:3.アクタのセットアップとテスト Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo @@ -8,6 +8,7 @@ Related:Engine/UMG Related:Engine/UMG/UserGuide SkillLevel:Advanced tags:UMG UI Designer +Order:3 [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/ActorSetup/ActorSetup.KOR.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/ActorSetup/ActorSetup.KOR.udn index 5e7479c52f57..53a243d5a6d2 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/ActorSetup/ActorSetup.KOR.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/ActorSetup/ActorSetup.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3343902 +INTSourceChangelist:3376720 Availability: Public Title:3. 액터 구성 및 테스트 Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo @@ -8,6 +8,7 @@ Related: Engine/UMG Related: Engine/UMG/UserGuide SkillLevel: Advanced tags:UMG UI Designer +Order: 3 [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/CharacterSetup/CharacterSetup.INT.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/CharacterSetup/CharacterSetup.INT.udn index 5cd9fe1b733b..21331e3809c9 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/CharacterSetup/CharacterSetup.INT.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/CharacterSetup/CharacterSetup.INT.udn @@ -4,6 +4,7 @@ Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo Description:Here we add the Widget Interaction component to our character and create the other assets we will need. SkillLevel: Advanced tags:UMG UI Designer +Order: 1 [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/CharacterSetup/CharacterSetup.JPN.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/CharacterSetup/CharacterSetup.JPN.udn index e59a56c47d4d..9d3e88091670 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/CharacterSetup/CharacterSetup.JPN.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/CharacterSetup/CharacterSetup.JPN.udn @@ -1,10 +1,11 @@ -INTSourceChangelist:3343902 +INTSourceChangelist:3376720 Availability:Public Title:1.キャラクターのセットアップ Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo Description:Widget Interaction コンポーネントをキャラクターに追加して、必要となる他のアセットを作成します。 SkillLevel:Advanced tags:UMG UI Designer +Order:1 [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/CharacterSetup/CharacterSetup.KOR.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/CharacterSetup/CharacterSetup.KOR.udn index b29e4678d5d3..46283282a732 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/CharacterSetup/CharacterSetup.KOR.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/CharacterSetup/CharacterSetup.KOR.udn @@ -1,10 +1,11 @@ -INTSourceChangelist:3343902 +INTSourceChangelist:3376720 Availability: Public Title:1. 캐릭터 구성 Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo Description:여기서는 캐릭터에 Widget Interaction 컴포넌트를 추가하고 필요한 다른 애셋을 생성합니다. SkillLevel: Advanced tags:UMG UI Designer +Order: 1 [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/WidgetSetup/WidgetSetup.INT.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/WidgetSetup/WidgetSetup.INT.udn index 234a16d966b0..e982039f5da4 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/WidgetSetup/WidgetSetup.INT.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/WidgetSetup/WidgetSetup.INT.udn @@ -4,6 +4,7 @@ Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo Description:Here we create the keypad and keypad display widgets that will appear in the level. SkillLevel: Advanced tags:UMG UI Designer +Order: 2 [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/WidgetSetup/WidgetSetup.JPN.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/WidgetSetup/WidgetSetup.JPN.udn index 1ddc4fd6fad9..b92eeb58ad07 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/WidgetSetup/WidgetSetup.JPN.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/WidgetSetup/WidgetSetup.JPN.udn @@ -1,10 +1,11 @@ -INTSourceChangelist:3343902 +INTSourceChangelist:3376720 Availability:Public Title:2.Widget ブループリントの設定 Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo Description:レベルに現れるキーパッドとキーパッド表示ウィジェットを作成します。 SkillLevel:Advanced tags:UMG UI Designer +Order:2 [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/WidgetSetup/WidgetSetup.KOR.udn b/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/WidgetSetup/WidgetSetup.KOR.udn index b5108d6b7cc2..507b6a097933 100644 --- a/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/WidgetSetup/WidgetSetup.KOR.udn +++ b/Engine/Documentation/Source/Engine/UMG/HowTo/VirtualKeyboards/WidgetSetup/WidgetSetup.KOR.udn @@ -1,10 +1,11 @@ -INTSourceChangelist:3343902 +INTSourceChangelist:3376720 Availability: Public Title:2. 위젯 블루프린트 구성 Crumbs: %ROOT%, Engine, Engine/UMG, Engine/UMG/HowTo Description:여기서는 레벨에 표시할 키패드와 키패드 디스플레이 위젯을 생성합니다. SkillLevel: Advanced tags:UMG UI Designer +Order: 2 [VAR:Steps] [OBJECT:Navigation] diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Fonts.CHN.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Fonts.CHN.udn index 983861284856..25614f4cad72 100644 --- a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Fonts.CHN.udn +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Fonts.CHN.udn @@ -1,124 +1,28 @@ -INTSourceChangelist:2709429 -Availability:Public -Title:字体 +INTSourceChangelist:3399451 +Availability: Public Crumbs:%ROOT%, Engine, Engine/UMG, Engine/UMG/UserGuide -Description:导入字体的详细操作流程、如何使用字体编辑器以及如何在 UMG 中使用字体。 -Related:Engine/UMG -Related:Engine/UMG/UserGuide/WidgetBlueprints -Related:Engine/UMG/UserGuide/WidgetTypeReference -version:4.9 +Title: 字体 +Description: 字体相关页面的汇总页 +Type: Landing +Version:4.15 +Parent: Engine/UMG/UserGuide +Related: Engine/UMG +Related: Engine/UMG/UserGuide/WidgetBlueprints +Related: Engine/UMG/UserGuide/WidgetTypeReference +Order:1 +Tags: UMG UI Designer +Tags: Fonts -[TOC(start:2 end:2)] - -该页面介绍如何导入您自己的字体、使用 **字体编辑器** 以及 **虚幻动态图形 (UMG) UI 设计器** 中的字体。 - -## 字体资产 - -虚幻引擎 4 中的字体被列为 **字体** 资产,使用两种缓存方式:复合字体形式的 **运行时** 和早期的预计算 Font Atlas 方式 **离线**。可以在字体编辑器中打开字体资产来切换这两种方式(这样可以简单地将现有的字体资产从早期的方式转换成新的复合方式,而不需要替换它们)。 - -## 创建和导入字体 - -此部分介绍如何创建新字体资产,或者导入 TTF 或 OTF 文件来生成字体资产。 - -### 创建字体资产 - -要创建字体资产,请执行以下的步骤: - -1. 在 **内容浏览器** 中点击 **添加新内容** 按钮,然后在 **用户界面** 下选择 **字体** 选项。 - - ![](NewFont.png) - -1. 这将创建一个新的复合字体资产,并会提示您输入名称。 - - ![](NameFont.png) - -1. 输入名称后,会在资产上看到一个星号,表示该资产尚未保存。单击 **保存全部** 按钮保存资产,然后在出现的弹出菜单中确认保存。 - - ![](SaveFont.png) - - -[REGION:tip] -除了单击 **添加新内容** 按钮,您也可以 **右键单击** **内容浏览器** 中的空白处来访问上下文菜单。在上下文菜单中可以单击 **用户界面** 和 **字体** 选项来创建字体资产。不要忘了保存资产! +[REGION:fullwidth raw] +![](FontLandingBanner.png) [/REGION] -在编辑器中创建新字体资产时,将会创建一个空白复合字体资产,之后可以使用字体编辑器定义其参数。导入 TTF 或 OTF 文件时,会使用您所提供的字体示例生成一个新的复合字体资产(此时可以使用字体编辑器将其打开并定义额外的参数)。 - -### 导入字体 - -可以使用多种方法向编辑器中导入 TTF 或 OTF 文件。 - -第一种方法是单击 **内容浏览器** 中的 **导入** 按钮。 - -![](Import1.png) - -在出现的对话框中,导航至要导入的文件并单击它,再单击 **打开**。 - -![](Import2.png) - -这会使用您所选择的文件,将该文件作为复合字体资产添加到内容浏览器中。 - -![](Import3.png) - -也可以将 TTF 或 OTF 文件 **拖放** 到 **内容浏览器** 中以创建复合字体资产。 - -![](Import4.png) - -使用拖放方式时,也会使用您所选择的文件自动创建一个复合字体资产。 - -## 字体编辑器 - -在 **内容浏览器** 中 **双击** 字体资产时,会在 **字体编辑器** 窗口中打开该字体资产。 - -![](FontEditorWindow.png)(w:820) - -字体编辑器窗口的细分结构如下: - -1. **工具栏菜单** - 可以在该菜单中保存所做出的更改,查找 **内容浏览器** 中的资产,更改预览窗口的背景颜色 (4) 或更改预览窗口的前景颜色(文本颜色)。有用于更新或导出所做更改的选项,但这些选项仅可以在 **离线** 缓存模式下使用。 -1. **默认字体系列** - 可以在该窗口中指定该字体资产所使用的默认字体系列。可以添加特定字体样式的版本(例如正常、粗体、斜体、下划线等)或者在一个复合字体内包含一系列不同的字体样式。如果创建了空白的字体资产,则也可以在该窗口中指定一个字体。添加字体后,也可以定义该字体使用的提示算法。 -1. **子字体系列** - 可以在该窗口中指定该字体资产所使用的子字体系列。可以在此指定字符范围,如果输入的字符在该范围内,则可以指定使用默认字体以外的其他字体样式(当您想针对不同语言使用不同字体类型时就可以这样做)。 -1. **预览** - 该窗口中可以预览字体,并且提供用于输入示例文本的文本输入框。 -1. **细节** - 可以在该窗口中更改字体缓存类型、字体大小和字体名称(针对运行时)。 - * 如果您使用的是早期的方法,则仍可以在离线缓存模式下更改字体的参数。 - * 您也可以将现有的字体资产从 **离线** 转换成 **运行时**,而无需替换字体。 - -下面给出了一个字体资产示例。 - -[REGION:lightbox] -[![](ExampleFontLayout.png)(w:820)](ExampleFontLayout.png) -[/REGION] - -_点击查看全图。_ - -复合字体始终包含一个默认字体系列,也可能包含任意数量的子字体系列,它们应用于给定范围的字符。每个字体系列本身由任意数量的字体组成,可以根据这些字体的样式对它们进行命名。在运行时,会在字体系列内可用于该字符范围的字体中,确定出对每个字符最合适的字体,并加以使用。 - -如上图示例所示,日语文本属于日语字体系列的字符范围中,因此日文部分使用“Source Han Sans”绘制,而不是默认字体系列“Roboto”。子字体系列中的字体最好根据名称匹配选择,如对于正常、黑体和细体,但也可以随机应变地基于默认字体的属性进行匹配,如对于粗斜体(这将会自动选择粗体日语字体,因为该字体包含了粗体属性,是最佳匹配)。 - - -## UMG 中的字体 - -创建 [Widget Blueprint](Engine/UMG/UserGuide/WidgetBlueprints) 并放置了包含文本(如文本框或文本控件)的控件之后,在单击该控件并访问 **细节** 面板时,可以在 **外观** 下面看到 **字体** 选项。 - -![](UMGFonts1.png) - -默认情况下,引擎使用 **Roboto**,但可以单击下拉菜单并选择和使用任何已创建的复合字体资产来替换。 - -![](UMGFonts2.png) - -也可以从该菜单中创建一个复合字体,并指定新资产保存的位置(默认为空白,必须填写)。 - -选择复合字体后,可以在第二个下拉菜单从 **默认字体系列** 中选择要使用的字体。 - -![](UMGFonts3.png) - -也可以在输入框中指定字体的大小。 - -![](UMGFonts4.png) - -目前,UMG 仅支持 **运行时** 缓存的字体资产。另外,如果您指定了使用早期方式的字体,那么基于现有文件的字体设置并不会丢失,但是为了继续进行,您需要创建一个复合字体资产以便在 UMG 中使用自定义字体。 - - +**字体** 是一类可以和 Text Actor 一起使用的资源(尤其是和 [UMG UI Designer](Engine/UMG) 一起使用),在用户界面上增加更多的元素。 +下面这些页面会更详尽的解释什么是字体,如何在虚幻引擎 4 中使用字体。还有一个 How-To 的引导,用来说明如何导入、创建字体以及如何在 UMG 中使用字体。 +[DIR(output:"topiccompact" parent:"Engine/UMG/UserGuide/Fonts" org:"hierarchy" tags:"Fonts" end:"1")] +[DIR(output:"topiccompact" parent:"Engine/UMG/UserGuide/Fonts/HowTo" org:"hierarchy" tags:"Fonts" end:"1")] diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Fonts.INT.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Fonts.INT.udn index 525ce43000cf..c23e784e59f2 100644 --- a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Fonts.INT.udn +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Fonts.INT.udn @@ -1,275 +1,28 @@ -Availability:Public -Title: Fonts +Availability: Public Crumbs:%ROOT%, Engine, Engine/UMG, Engine/UMG/UserGuide -Description:Details the process of importing fonts, working with the Font Editor and using fonts in UMG. -Parent: Engine/UMG +Title: Fonts +Description: Landing page for all the documentation relating to Fonts. +Type: Landing +Version:4.15 +Parent: Engine/UMG/UserGuide Related: Engine/UMG Related: Engine/UMG/UserGuide/WidgetBlueprints Related: Engine/UMG/UserGuide/WidgetTypeReference -Version: 4.15 -tags:UMG UI Designer +Order:1 +Tags: UMG UI Designer +Tags: Fonts -[TOC(start:2 end:2)] - -This page covers how to import your own fonts, using the **Font Editor**, and fonts in the **Unreal Motion Graphics (UMG) UI Designer**. - -## Font Assets - -Fonts in Unreal Engine 4 are categorized as a **Font** asset and use two caching methods, **Runtime** which is in the form of a Composite Font or **Offline** which is the older -pre-computed Font Atlas method. You can switch between the two methods by opening up a Font asset in the Font Editor (this provides a simple way to convert existing Font assets -from the older method to the new composite method without having to replace them). - -## Font Face Assets - -The **Font Face** asset is created when you import a font and it stores the font data that can be referenced by the Font asset. This means that the same font data can be reused across -multiple Font assets or even with multiple typefaces within the asset, and ultimately reduces memory consumption. - -![](FontFaceWindow.png)(w:400) - -From the Font Face editor window you have access to the settings for **Hinting** and **Loading Policy**. - -[REGION:simpletable] -| Property | Description | -| --- |--- | -| Source File Name | The filename of the font face we were created from. This may not always exist on disk, as we may have previously loaded and cached the font data inside this asset. | -| Hinting | The hinting algorithm to use with the font face. [INCLUDE:#hinting] | -| Loading Policy | Enum controlling how this font face should be loaded at runtime. See the enum for more explanations of the options. [INCLUDE:#loadingpolicy]| +[REGION:fullwidth raw] +![](FontLandingBanner.png) [/REGION] - - - -## Upgrading Font Assets to 4.15 and Later - -Starting with Unreal Engine 4.15, Font assets have now been split into two separate assets; Font and Font Faces. Existing Font assets will upgrade their internal font data into -embedded Font Face assets during load, but will not automatically split them. You will have to do this by opening the Font Editor and selecting **Upgrade Data** under the **Default Font Family** list. -This will enable you to edit and share these assets with other Font assets that you've created. - -![](FontUpgradeData.png)(w:175) - -After you click **Upgrade Data**, you will be prompted to save the new Font Face asset. - - -## Font Editor - -When you **Double-click** on a Font asset in the **Content Browser**, it will open up inside the **Font Editor** window. - -![](FontEditorWindow.png)(w:820) - -A breakdown of the Font Editor Window is presented below: - -#### Toolbar Menu - -![](ToolbarMenu.png)(w:550) - -From this menu, you can save any changes you make, find the asset in the **Content Browser**, change the Background Color of the preview window (4) or -the Foreground Color (text color) in the preview window. There are options for Updating or Exporting changes made, however, these options are only available -within the **Offline** cache mode. - -#### Default Font Family - -![](DefaultFontFamily.png)(w:550) - -In this window, you can assign the Default Font Family for use with this Font asset. You can add versions of a particular Font style (for example Normal, -Bold, Italics, Underline, etc.) or have a collection of different Font styles as one Composite Font. If you have created a blank Font asset, you can assign -a font from inside this window as well. Once a Font has been added, you can also define the hinting algorithm used with the font. - -#### Sub-Font Family - -![](AddSubFontFamily.png)(h:50) - -In this window, when you click the **Add Sub-Font Family* button, you can assign the Sub-Font Family for this Font asset to use. - -[![](SubFontFamily.png)(w:550)](SubFontFamily.png) - -Here you can specify a Character Range and if a character entered falls within the range you can specify a different Font style -to use instead of the Default. This is useful for when you want to use different Font types for different languages. - - -#### Preview - -![](Preview.png)(w:550) - -This window allows you to preview your fonts and provides a text entry box for entering sample texts. - -##### Draw For Metrics - -[![](PreviewDrawFontMetrics.png)(w:550)](PreviewDrawFontMetrics.png) - -The **Draw Font Metrics** toggle will overlay the line height, glyph bounding boxes, and base-line as part of the preview. - -* **Base Line** - This is the line in which the text sits. -* **Line Bounds** - This is the bounding box created for the length of the given text string. -* **Grapheme Cluster Bounds** - This is the bounding box drawn around what is considered a logical character in a given language, and may be comprised of several glyphs (eg. a base character and accent glyph). -* **Glyph Bounds** - This is the bounding box drawn around the given glyph. - -#### Details - -![](Details.png)(w:500) - -In this window, you can change the Font Cache Type as well as change the Font Size and Font Name (for Runtime). -* If you are using the older method, you can still change the parameters for your Font while in Offline cache mode. -* You can also convert any existing Font assets from **Offline** to **Runtime** without having to replace them. - - -An example Font asset is provided below. - -[REGION:lightbox] -[![](ExampleFontLayout.png)(w:820)](ExampleFontLayout.png) -[/REGION] - -_Click image for a full view._ - -A Composite Font will always contain a Default Font Family, and may also contain any number of Sub-Font Families that should be used for a given range of characters. Each Font Family is itself made up of any number of Fonts that can be named based on their style. At runtime, the most suitable Font to use for each character based on the Fonts available in the Font Family for that character range is used. - -As seen in the example image above, the Japanese text falls within the character ranges of the Japanese font family and so is drawn using Source Han Sans rather than the Default Font Family Roboto. Fonts in a Sub-Font Family are preferably chosen by name match, as in the case of Regular, Bold, and Light, however can also fallback to matching based on the attributes of the Default Font, as is the case of Bold Italic (it automatically chose the Bold Japanese font because the font contained the Bold attribute, and was the best match). - - -## Creating & Importing Fonts - -This section illustrates how to create a new Font asset and the ways you can import TTF or OTF files to generate your Font Face and Font assets. - -### Creating Font Assets - -To create a Font asset, follow the steps below: - -1. Click the **Add New** button inside the **Content Browser**, then under **User Interface** select the **Font** option. - - [REGION:lightbox] - [![](NewFont.png)(h:500)](NewFont.png) - [/REGION] - [REGION:caption] - _Click image for full view._ - [/REGION] -1. A new Composite Font asset will be created, prompting you to give it a **Name**. - - ![](NameFont.png) - -1. Once you enter a name, you will notice an asterisk appears on the asset, this indicates that the asset has not be saved. Click the **Save All** button to save your asset, then confirm the save in the pop-up menu that appears to finish. - - ![](SaveFont.png) - - -[REGION:tip] -Instead of clicking the **Add New** button, you can instead **Right-click** in an empty space in the **Content Browser** to access the context menu. From there, you can click the **User Interface** and **Font** option to create a Font asset. Do not forget to save your assets! -[/REGION] - -When you create a new Font asset inside the Editor, it will create an empty Composite Font asset which you can then define its parameters using the Font Editor. When you import a TTF or OTF file, a new Font Face asset is created -and you have the option to automatically create a Composite Font asset using the font data you provided (at which point you can define additional parameters by opening it up in the Font Editor). - - -### Importing Fonts - -You can import either TTF or OTF files into the Editor, and you can do so in a number of different ways demonstrated below. - -##### Importing Using the Content Browser - -You can use the Content Browser's **Import** button to select your TTF or OTF font file. - -1. In the Content Browser, click the **Import** button. - - ![](Import1.png) -1. In the dialogue box that appears, navigate to the TFF or OTF font file you want to import and select it. Then, click **Open**. - - ![](Import2.png)(w:500) -1. After a moment, the **Font Face Import Options** will appear. - - ![](Import3.png)(w:500) - - Select **Yes** from the options listed to create your Font Face asset and your Composite Font asset in your Content Browser. - - ![](Import3a.png) - - -##### Importing Using Drag-and-drop - -You can **Drag-and-drop** a TTF or OTF file directly into the Content Browser to create your font assets. - -1. Navigate to the folder where you've stored your TTF or OTF file(s). Select and hold to drag one over the **Content Browser** to start the import process. - - ![](Import4.png)(w:650) -1. After a moment, the **Font Import Options** will appear. - - ![](Import3.png)(w:500) - - Select **Yes** from the options listed to create your Font Face asset and your Composite Font asset in your Content Browser. - - ![](Import3a.png) - - -#### Importing Using the Font Editor - -You can import and create Font Face assets directly from the Default Font Family list in the **Font Editor**. - -1. Open an existing **Font** asset or create a new one using the **Add New** button in the Content Browser. - - ![](Import5.png)(w:600) -1. Click the **Add Font** button to add a new font selection to the Default Font Family. - - ![](Import6.png)(w:500) -1. Select the **folder** button next to the selection dropdown. - - ![](Import7.png)(w:500) -1. In the dialogue box that appears, navigate to the TFF or OTF font file you want to import and select it. Then, click **Open**. - - ![](Import2.png)(w:500) -1. Next, the **Save Font Face** window will appear. Give your font a name and choose the save location in your game folder's hierarchy. Then, click **Save**. - - ![](Import8.png)(w:500) - - The Font Face asset can now be found in your folder hierarchy. - - ![](Import3a.png) - - -## Fonts in UMG - -Once you have created a [Widget Blueprint](Engine/UMG/UserGuide/WidgetBlueprints) and placed a Widget that contains Text (such as a Text Box or Text Widget), when clicking on it and accessing the **Details** panel, under **Appearance**, you will see a **Font** option. - -![](FontWithNewOptions.png) - -By default the Engine uses **Roboto**, however, if you click the drop-down menu, any Composite Font assets created can be selected and used instead. - -![](NewFontWithNewOptions.png) - -You can also choose to create a Composite Font from this menu and specify where the new asset should be saved (it will be blank by default and you will have to fill it out). - -Once you select your Composite Font, the second drop-down menu will allow you to select a font to use from the **Default Font Family**. - -![](FontStyleNewOptions.png) - -You can also specify the size of the font in the input box. - -![](FontSizeNewOptions.png) - -Currently, UMG only supports **Runtime** cached font assets. Also, if you have assigned fonts using the old method, none of your existing file based font settings will be lost, however going forward, you will need to create a Composite Font asset in order to use custom fonts with UMG. - -You can style your **Font** by [setting colors, Materials, and outline properties](Engine/UMG/UserGuide/Fonts/Materials), as well as by using shadows. - +A **Font** is an asset that can be used with Text Actors (especially with the [UMG UI Designer](Engine/UMG)) to add visual styling to customized user interfaces. The following +pages will cover, in more detail, what Fonts are, and how to use them in Unreal Engine 4. Additionally, you'll find some how-to guides, showing you how to import, create, and +use fonts within UMG. +[DIR(output:"topiccompact" parent:"Engine/UMG/UserGuide/Fonts" org:"hierarchy" tags:"Fonts" end:"1")] +[DIR(output:"topiccompact" parent:"Engine/UMG/UserGuide/Fonts/HowTo" org:"hierarchy" tags:"Fonts" end:"1")] diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Fonts.JPN.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Fonts.JPN.udn index dc81908f9033..6427a5ccda6a 100644 --- a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Fonts.JPN.udn +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Fonts.JPN.udn @@ -1,275 +1,29 @@ -INTSourceChangelist:3361457 +INTSourceChangelist:3399451 Availability:Public -Title:フォント Crumbs:%ROOT%, Engine, Engine/UMG, Engine/UMG/UserGuide -Description:フォントのインポート、フォント エディタでの作業、および UMG でフォントを使用するプロセスの詳細を説明します。 -Parent:Engine/UMG +Title:Fonts +Description:Description:フォントに関する全ドキュメントへのランディング ページです。 +Type:Landing +Version:4.15 +Parent:Engine/UMG/UserGuide Related:Engine/UMG Related:Engine/UMG/UserGuide/WidgetBlueprints Related:Engine/UMG/UserGuide/WidgetTypeReference -Version:4.15 -tags:UMG UI Designer +Order:1 +Tags:UMG UI Designer +Tags:Fonts -[TOC(start:2 end:2)] - -このページでは、独自のフォントのインポート、 **フォント エディタ** の使用、および **Unreal Motion Graphics (UMG) UI デザイナ** のフォントについて説明します。 - -## Font アセット - -UE4 のフォントは **Font** アセットとして分類され、 2 種類のキャッシング方法を使用します。**ランタイム** は、コンポジット フォントの形式をとります。**オフライン** は、 -事前計算された古いフォント アトラス方式です。フォント エディタで Font アセットを開くことで、この 2 つの方式を切り替えることができます (これは古い方式の既存のフォント アセットを置き換える必要なく -新しいコンポジット方式に変換する簡単な方法です)。 - -## Font Face アセット - -**Font Face** アセットは、フォント インポート時に作成され、Font アセットが参照できるフォント データを保存します。つまり、同じフォント データを複数のフォント アセットで再利用することができます。 -さらに、ひとつの Font アセット内で複数の書体を再利用することもできます。その結果、メモリ消費を減らします。 - -![](FontFaceWindow.png)(w:400) - -Font Face エディタ ウィンドウから、**[Hinting]** と **[Loading Policy]** の設定にアクセスすることができます。 - -[REGION:simpletable] -| プロパティ | 説明 | -| --- |--- | -| Source File Name | 書体の作成元のファイル名です。必ずしもディスク上にありません。フォント データを過去にロードして、このアセット内にキャッシュしたかもしれないからです。 | -| Hinting | 書体と合わせて使うヒント アルゴリズムです。 [INCLUDE:#hinting] | -| Loading Policy | ランタイムにこうした書体がどのようにロードされるかを制御する列挙型変数です。オプションの詳細説明については、列挙型変数をご覧ください。 [INCLUDE:#loadingpolicy]| +[REGION:fullwidth raw] +![](FontLandingBanner.png) [/REGION] - - - -## Font アセットを 4.15 以降にアップグレード - -アンリアル エンジン 4.15 から Font アセットは、Font と Font Faces という 2 つのアセットに分かれました。ロード中に既存の Font アセットはその内部フォントデータを、埋め込まれた Font Face アセットに自動的にアップグレードします。 -しかし、自動的にそれらを分割はしません。これを行うには、Font エディタを開き、**Default Font Family** リストで **Upgrade Data** を選択します。 -これらのアセットを編集したり、作成した他の Font アセットと共有できるようになります。 - -![](FontUpgradeData.png)(w:175) - -**[Upgrade Data]** をクリックすると、新しい Font Face アセットを保存するように促されます。 - - -## フォント エディタ - -**コンテンツ ブラウザ** で Font アセットを **ダブルクリック** すると、**フォント エディタ** ウィンドウ内でそのフォント アセットが開きます。 - -![](FontEditorWindow.png)(w:820) - -以下は Font Editor ウィンドウの各部を示したものです。 - -#### ツールバー メニュー - -![](ToolbarMenu.png)(w:550) - -加えた変更を保存し、**[コンテンツ ブラウザ]** でアセットを見つけ、プレビュー ウィンドウの背景色を変更したり、 -文字の表示色 (テキスト カラー) を変更することができます。加えた変更を更新またはエクスポートするオプションがあります。しかし、こうしたオプションは -**オフライン** キャッシュ モード内でのみ利用可能です。 - -#### デフォルト フォント ファミリー - -![](DefaultFontFamily.png)(w:550) - -このウィンドウでは Font アセットと合わせて使用するデフォルト フォント ファミリーを指定することができます。特定のフォント スタイルのバージョンを追加したり (例えば、標準、太字、イタリック、アンダーラインなど)、 -ひとつのコンポジット フォントとして様々なフォント スタイルのコレクションを持つことができます。ブランクの Font アセットを作成したらこのウィンドウ内からフォントを -指定することもできます。フォントを追加したらフォントと併用するヒンティング アルゴリズムを定義することができます。 - -#### サブ フォント ファミリー - -![](AddSubFontFamily.png)(h:50) - -このウィンドウでは、 **Add Sub-Font Family** ボタンをクリックすると、Font アセットが使用するサブフォント ファミリーを指定することができます。 - -[![](SubFontFamily.png)(w:550)](SubFontFamily.png) - -ここでは、文字範囲 (Character Range) を指定し、入力した文字がこの範囲に入ったらデフォルトの代わりに -別のフォント スタイルを指定することができます。これは異なる言語で様々なフォント タイプを使用したい場合に役立ちます。 - - -#### プレビュー - -![](Preview.png)(w:550) - -このウィンドウでは、フォントをプレビューすることが可能であり、サンプル テキストを入力するためのテキスト エントリ ボックスがあります。 - -##### Draw For Metrics - -[![](PreviewDrawFontMetrics.png)(w:550)](PreviewDrawFontMetrics.png) - -**Draw Font Metrics** を切り替えるとは、ラインの高さ、グリフのバウンディング ボックス、ベース ラインをプレビューでオーバーレイ表示します。 - -* **Base Line** - テキストが入るラインです。 -* **Line Bounds** - 任意のテキスト文字列の長さに対して作られたバウンディング ボックスです。 -* **Grapheme Cluster Bounds** - 任意の言語で論理文字とみなされる物の回りに描画されるバウンディング ボックスです。いくつかのグリフを含むことがあります (例、基本文字とアクセントのグリフ)。 -* **Glyph Bounds** - 任意のグリフ周囲に描画されるバウンディング ボックスです。 - -#### Details - -![](Details.png)(w:500) - -このウィンドウではフォント キャッシュ タイプ、フォント サイズ、フォント名 (ランタイム用) を変更することができます。 -* 古い方式を使用している場合は、オフライン キャッシュ モードでフォントのパラメータを変更することができます。 -* 既存のフォント アセットを置き換えることなく **オフライン** から **ランタイム** に変換できます。 - - -以下はフォント アセットの例です。 - -[REGION:lightbox] -[![](ExampleFontLayout.png)(w:820)](ExampleFontLayout.png) -[/REGION] - -_画像をクリックして全画面表示にします。_ - -コンポジット フォントには常にデフォルト フォント ファミリーが含まれます。任意の文字範囲で使用するサブフォント ファミリーをいくつでも含むことができます。各フォント ファミリー自体は、スタイルに基づいて命名できる任意の数のフォントから構成されます。ランタイムには、その文字範囲に対してフォント ファミリーで利用可能なフォントに基づき各文字に最適なフォントが使用されます。 - -上の画像でわかるように、日本語のテキストは日本語フォント ファミリーの文字範囲にあります。そのため、デフォルト フォント ファミリーの Roboto ではなく Source Han Sans を使用して描画されます。サブフォント ファミリーのフォントは Regular、Bold、および Light の場合と同様に名前の一致によって選択されるのが理想的です。しかし、Bold Italic のようにデフォルト フォントの属性に基づきマッチするようにフォールバックすることもできます (自動的に太字の日本語フォントが選択されます。このフォントには、太字属性が含まれており、最適マッチであったためです)。 - - -## フォントの作成とインポート - -このセクションでは、新規 Font アセットの作成方法、TTF ファイルまたは OTF ファイルをインポートして Font Face アセットと Font アセットを生成する方法について説明します。 - -### フォント アセットを作成する - -フォント アセットを作成するには、以下の手順に従います。 - -1. **コンテンツ ブラウザ** で、 **[Add New]** ボタンをクリックし、 **[User Interface (ユーザーインターフェース)]** で **[Font]** オプションをクリックします。 - - [REGION:lightbox] - [![](NewFont.png)(h:500)](NewFont.png) - [/REGION] - [REGION:caption] - _画像をクリックしてフルサイズで表示_ - [/REGION] -1. 新しい Composite Font アセットが作成されます。**名前** を付けるよう促されます。 - - ![](NameFont.png) - -1. 名前を入力したらアセットにアスタリスク記号が付いているのがわかります。これはアセットが保存されていないことを示します。**[Save All]** ボタンをクリックしてアセットを保存します。次に表示されるポップアップ メニューで保存を確認して終了します。 - - ![](SaveFont.png) - - -[REGION:tip] -**[Add New]** ボタンをクリックする代わりに **[コンテンツ ブラウザ]** の空きエリアで **右クリック** してコンテキスト メニューを呼び出すこともできます。そこから **[User Interface]** と **[Font]** オプションをクリックして Font アセットを作成します。アセットを必ず保存してください! -[/REGION] - -エディタで新規 Font アセットを作成すると、空のコンポジット フォント アセットが作成され、フォント エディタ を使用してそのパラメータを定義することができます。TTF ファイルまたは OTF ファイルをインポートする場合、新しい Font Face アセットが作成されます。 -指定したデータを使用して Composite Font アセットを自動的に作成するオプションがあります (この時点でフォント エディタを開いてパラメータを追加で定義することができます)。 - - -### フォントのインポート - -TTF ファイルまたは OTF ファイルをエディタにインポートすることができます。これを行うには以下のように様々な方法があります。 - -##### コンテンツ ブラウザを使ってインポートする - -コンテンツ ブラウザの **[Import]** ボタンを使って TTF または OTF のフォントファイルを選択することができます。 - -1. コンテンツ ブラウザで **[Import]** ボタンをクリックします。 - - ![](Import1.png) -1. 表示されるダイアログ ボックスでインポートする TFF または OTF のフォント ファイルに移動し、選択します。**[Open]** をクリックします。 - - ![](Import2.png)(w:500) -1. しばらくすると、**[Font Face Import Options]** が表示されます。 - - ![](Import3.png)(w:500) - - コンテンツ ブラウザで Font Face アセットと Composite Font アセットを作成するには、表示されているオプションから、**Yes** を選択します。 - - ![](Import3a.png) - -##### ドラッグ&ドロップを使用したインポート - -TTF ファイルまたは OTF ファイルをコンテンツ ブラウザに直接 **ドラッグ & ドロップ** し、フォント アセットを作成することもできます。 - -1. TTF ファイルまたは OTF ファイルを保存した場所に移動します。ファイルをひとつを選択して **コンテンツ ブラウザ** までドラッグしてインポート プロセスを開始します。 - - ![](Import4.png)(w:650) -1. しばらくすると、**Font Import Options** が表示されます。 - - ![](Import3.png)(w:500) - - コンテンツ ブラウザで Font Face アセットと Composite Font アセットを作成するには、表示されているオプションから、**Yes** を選択します。 - - ![](Import3a.png) - - -#### フォント エディタを使ってインポートする - -**Font Editor** の Default Font Family リストから Font Face アセットを直接インポートして作成することができます。 - -1. 既存の **Font** アセットを開くか、コンテンツ ブラウザの **[Add New (新規追加)]** ボタンを使用して、新しいアセットを作成します。 - - ![](Import5.png)(w:600) -1. デフォルトのフォント ファミリーに新しいフォントを追加するには、**[Add Font]** ボタンをクリックします。 - - ![](Import6.png)(w:500) -1. 選択のドロップダウンの隣にある **folder** ボタンを選択します。 - - ![](Import7.png)(w:500) -1. 表示されるダイアログ ボックスでインポートする TFF または OTF のフォント ファイルに移動し、選択します。**[Open]** をクリックします。 - - ![](Import2.png)(w:500) -1. 続いて **[Save Font Face]** ウィンドウが表示されます。フォントに名前を付けてゲーム フォルダの階層で保存場所を選択します。**[Save (保存)]** をクリックします。 - - ![](Import8.png)(w:500) - - これで Font Face アセットがフォルダの階層に入ります。 - - ![](Import3a.png) - - -## UMG のフォント - -[Widge ブループリント](Engine/UMG/UserGuide/WidgetBlueprints) を作成し、テキストを含むウィジェット (テキストボックスまたはテキスト ウィジェットなど) を配置後、それをクリックし、**[Details]** パネルにアクセスすると、**[Appearance]** に **[Font]** オプションがあります。 - -![](FontWithNewOptions.png) - -デフォルトでは、エンジンは **Roboto** を使用します。しかし、ドロップダウン メニューをクリックし、作成した任意のコンポジット フォント アセットを選択し、代わりに使用することができます。 - -![](NewFontWithNewOptions.png) - -このメニューからコンポジット フォントを作成し、新規アセットをどこに保存するかを指定することもできます (デフォルトでブランクになり、入力する必要があります)。 - -コンポジット フォントを選択したら、2 つめのドロップダウン メニューで使用するフォントを **[Default Font Family]** から選択できます。 - -![](FontStyleNewOptions.png) - -フォント サイズを入力ボックスで指定することもできます。 - -![](FontSizeNewOptions.png) - -現時点では UMG は **ランタイム** にキャッシュされるフォント アセットのみをサポートしています。古い方式を用いてフォントを割り当てた場合、既存のファイル ベースのフォント設定は失われません。しかし、UMG でカスタム フォントを使用するためには、いずれは Composite Font アセットを作成する必要があります。 - -[色、マテリアル、アウトラインのプロパティを設定](Engine/UMG/UserGuide/Fonts/Materials) したり、陰影をつけてフォントにスタイルを設定することができます。 - +**Font** は Text アクタ (特に [UMG UI デザイナ](Engine/UMG)) と共に使用できるアセットで、カスタマイズしたユーザー インターフェース向けに視覚的スタイルを加えることができます。以下のページでは、 +フォントとは何か、UE4 内での使用方法を詳しく説明します。さらに、UMG 内でフォントのインポート、作成、使用についての +操作ガイドがあります。 +[DIR(output:"topiccompact" parent:"Engine/UMG/UserGuide/Fonts" org:"hierarchy" tags:"Fonts" end:"1")] +[DIR(output:"topiccompact" parent:"Engine/UMG/UserGuide/Fonts/HowTo" org:"hierarchy" tags:"Fonts" end:"1")] diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Fonts.KOR.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Fonts.KOR.udn index ae84d7c03f7b..ae935e0aa1a2 100644 --- a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Fonts.KOR.udn +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Fonts.KOR.udn @@ -1,125 +1,29 @@ -INTSourceChangelist:3244089 +INTSourceChangelist:3399451 Availability:Public -Title: 폰트 Crumbs:%ROOT%, Engine, Engine/UMG, Engine/UMG/UserGuide -Description:폰트 임포트 프로세스, 폰트 에디터 작업 방법, UMG 에서 폰트 사용법 관련 자세한 내용입니다. +Title: 폰트 +Description:폰트 관련 모든 문서 첫 페이지입니다. +Type: Landing +Version:4.15 +Parent: Engine/UMG/UserGuide Related: Engine/UMG Related: Engine/UMG/UserGuide/WidgetBlueprints Related: Engine/UMG/UserGuide/WidgetTypeReference -Version: 4.14 -tags:UMG UI Designer +Order:1 +Tags: UMG UI Designer +Tags: Fonts -[TOC(start:2 end:2)] - -여기서는 별도의 폰트 임포트 방법, **폰트 에디터** 사용법, **언리얼 모션 그래픽 (UMG) UI 디자이너** 에서 폰트 사용법을 다룹니다. - -## 폰트 애셋 - -언리얼 엔진 4 의 폰트는 **Font** (폰트) 애셋으로 분류되어 있으며, 두 가지 캐싱 방식이 있습니다. **Runtime** (런타임)은 컴포짓 (합성) 폰트 방식, **Offline** (오프라인)은 구형 미리계산된 폰트 아틀라스 방식입니다. **폰트 에디터** 에서 폰트 애셋을 열어보는 것으로 두 방식을 전환할 수 있습니다 (그 덕에 간단하게 기존 폰트 애셋을 대체하지 않고도 구형 방식에서 새로운 컴포짓 방식으로 전환 가능합니다). - -## 폰트 생성 & 임포트 - -여기서는 새 폰트 애셋을 생성하고 TTF 또는 OTF 파일을 임포트하여 폰트 애셋을 생성하는 법을 알아보겠습니다. - -### 폰트 애셋 생성하기 - -폰트 애셋을 생성하는 방법은 다음과 같습니다: - -1. **콘텐츠 브라우저** 에서 **신규 추가** 버튼을 누른 다음 **유저 인터페이스** - **폰트** 옵션을 선택합니다. - - ![](NewFont.png) - -1. 컴포짓 폰트 애셋이 새로 생성되어, 이름을 지을 수 있습니다. - - ![](NameFont.png) - -1. 이름을 지으면 애셋에 별표가 보입니다. 저장되지 않은 애셋임을 나타냅니다. **모두 저장** 버튼을 눌러 애셋을 저장한 다음, 뜨는 팝업 창에서 저장을 확인하여 마무리합니다. - - ![](SaveFont.png) - - -[REGION:tip] -**신규 추가** 버튼을 누르는 대신 **콘텐츠 브라우저** 의 빈 곳에 **우클릭** 하여 맥락 메뉴를 통하는 방법도 있습니다. 거기서 **유저 인터페이스** - **폰트** 옵션을 클릭하면 폰트 애셋이 생성됩니다. 애셋 저장하는 것 잊지 마시구요! +[REGION:fullwidth raw] +![](FontLandingBanner.png) [/REGION] -에디터 안에서 새 폰트 애셋을 생성하면, 빈 컴포짓 폰트 애셋이 생성되며, **폰트 에디터** 를 사용하여 그 파라미터를 정의할 수 있습니다. TTF 또는 OTF 파일을 임포트하면 제공한 폰트 샘플을 사용하여 새로운 컴포짓 폰트 애셋이 생성됩니다 (여기서부터 **폰트 에디터** 에서 열어 부가 파라미터를 정의할 수 있습니다). - -### 폰트 임포트하기 - -TTF 나 OTF 파일을 에디터에 임포트할 수 있는데, 그 방법은 여러가지 입니다. - -첫 번째 방법은 **콘텐츠 브라우저** 에서 **임포트** 버튼을 클릭하는 것입니다. - -![](Import1.png) - -뜨는 대화상자에서 임포트할 파일을 탐색하여 선택한 다음 **열기** 를 클릭합니다. - -![](Import2.png) - -그러면 선택된 파일을 사용하여 **콘텐츠 브라우저** 에 컴포짓 폰트 애셋으로 파일이 추가됩니다. - -![](Import3.png) - -TTF 또는 OTF 파일을 끌어 **콘텐츠 브라우저** 에 놓는 방식으로도 컴포짓 폰트를 만들 수 있습니다. - -![](Import4.png) - -드래그 앤 드롭 방식을 사용하면, 선택된 파일을 사용하여 컴포짓 폰트 애셋도 자동 생성됩니다. - -## 폰트 에디터 - -**콘텐츠 브라우저** 에서 폰트 애셋에 **더블클릭** 하면 **폰트 에디터** 창에서 열립니다. - -![](FontEditorWindow.png)(w:820) - -폰트 에디터 창을 나눠보면 다음과 같습니다: - -1. **툴바 메뉴** - 이 메뉴에서는 변경내용 저장, **콘텐츠 브라우저** 에서 애셋 찾기, 미리보기 창(4)의 전경/배경색 변경이 가능합니다. 가해진 변경사항 업데이트 또는 익스포트 기능도 있는데, 이 옵션들은 **오프라인** 캐시 모드에서만 가능합니다. -1. **기본 폰트 패밀리** - 이 창에서는 이 폰트 애셋에 사용할 디폴트 폰트 패밀리를 할당할 수 있습니다. 특정 폰트 스타일의 여러가지 버전(예를 들어 보통, 두껍게, 이탤릭, 밑줄 등)을 추가하거나, 여러가지 폰트 스타일 모음을 하나의 컴포짓 폰트로 할 수도 있습니다. 빈 폰트 애셋을 생성했다면, 이 창 안에서 폰트를 할당할 수도 있습니다. 폰트가 추가되면, 그 폰트에 사용할 힌팅 알고리즘을 정의할 수도 있습니다. -1. **서브 폰트 패밀리** - 이 창에서는 이 폰트 애셋이 사용할 서브 폰트 패밀리를 할당할 수 있습니다. 여기서 **Character Range** (글자 범위)를 지정하고, 한 글자가 그 범위 안에 들었을 때 기본 스타일 이외의 다른 스타일을 적용하도록 지정할 수 있습니다 (다른 언어에 다른 폰트 유형을 사용하고자 할 때 좋습니다). -1. **프리뷰** - 이 창에는 폰트 미리보기와 샘플 텍스트 입력용 글상자가 제공됩니다. -1. **디테일** - 이 창에서는 **폰트 캐시 유형** 변경 및 (런타임 용) 폰트 크기나 폰트 이름을 변경할 수 있습니다. - * 구형 방식을 사용하는 경우, 여전히 **오프라인** 캐시 모드에 있을 때 폰트의 파라미터를 변경할 수 있습니다. - * 기존 폰트 애셋을 대체하지 않고도 **오프라인** 에서 **런타임** 으로 전환할 수도 있습니다. - -예제 폰트 애셋은 아래와 같습니다. - -[REGION:lightbox] -[![](ExampleFontLayout.png)(w:820)](ExampleFontLayout.png) -[/REGION] - -_이미지를 클릭하면 원래 크기로 봅니다._ - -컴포짓 폰트에는 항상 디폴트 폰트 패밀리가 들어있으며, 주어진 글자 범위에 대해 사용할 수 있는 서브 폰트 패밀리를 몇이든 포함 가능합니다. 각 폰트 패밀리 자체는 스타일에 따라 이름지을 수 있는 폰트 몇 개로든 구성됩니다. 런타임에 해당 글자 범위에 대한 폰트 패밀리에서 사용할 수 있는 폰트에 따라 각 글자에 사용하기 가장 적합한 폰트가 사용됩니다. - -위 예제 그림에서 확인할 수 있듯이, 일본어 텍스트가 일본어 폰트 패밀리 글자 범위에 해당하므로, 디폴트 폰트 패밀리인 Roboto 대신 Source Han Sans 를 사용해서 그립니다. 서브 폰트 패밀리의 폰트는 Regular, Bold, Light 처럼 이름이 일치되는 경우 선택될 수도 있고, Bold Italic 처럼 디폴트 폰트의 특성에 따라 일치되는 것으로 대체될 수도 있습니다 (폰트에 Bold 특성이 포함되어 있었고, 가장 일치가 잘 되어서 Bold Japanese 를 자동 선택했습니다). - - -## UMG 의 폰트 - -[위젯 블루프린트](Engine/UMG/UserGuide/WidgetBlueprints) 를 생성하고 (Text Box 나 Text Widget 처럼) Text 가 들어있는 위젯을 배치한 뒤, 그것을 클릭하고 **디테일** 패널에서 접근해 보면, **Appearance** 아래 **Font** option 가 보일 것입니다. - -![](FontWithNewOptions.png) - -엔진에서는 기본적으로 **Roboto** 를 사용하나, 드롭다운 메뉴를 클릭하면 미리 만들어둔 컴포짓 폰트 애셋을 선택하여 사용할 수도 있습니다. - -![](NewFontWithNewOptions.png) - -이 메뉴에서 컴포짓 폰트를 생성하여 새 애셋을 저장할 위치를 지정할 수도 있습니다 (기본적으로 비어있으며, 채워줘야 합니다). - -컴포짓 폰트를 선택하고 나면, 두 번째 드롭다운 메뉴를 통해 **디폴트 폰트 패밀리** 에서 사용할 폰트를 선택할 수 있습니다. - -![](FontStyleNewOptions.png) - -입력 상자에서 폰트 크기를 지정할 수도 있습니다. - -![](FontSizeNewOptions.png) - -현재 UMG 는 **런타임** 캐시 폰트 애셋만 지원합니다. 또한, 구형 방식을 사용하여 폰트를 할당한다 해도 기존 파일 기반 세팅을 잃게 되지는 않지만, 앞으로는 UMG 에서 커스텀 폰트를 사용하려면 컴포짓 폰트 애셋을 만들어야 합니다. - -[색, 머티리얼, 윤곽선 프로퍼티 설정](Engine/UMG/UserGuide/Fonts/Materials) 및 그림자를 사용해서 **폰트** 스타일을 잡을 수 있습니다. +**Font** (폰트)란 Text Actor (텍스트 액터, 특히 [UMG UI 디자이너](Engine/UMG)) 와 함께 사용할 수 있는 애셋으로, 커스텀 유저 인터페이스에 비주얼 스타일을 더할 수 있습니다. 여기서는 +폰트란 무엇이고, 언리얼 엔진 4 에서 어떻게 사용하는지에 대해 보다 자세히 살펴보겠습니다. 추가적으로 UMG 안에서 폰트를 임포트, 생성, 사용법 안내서를 +찾아보실 수도 있습니다. +[DIR(output:"topiccompact" parent:"Engine/UMG/UserGuide/Fonts" org:"hierarchy" tags:"Fonts" end:"1")] +[DIR(output:"topiccompact" parent:"Engine/UMG/UserGuide/Fonts/HowTo" org:"hierarchy" tags:"Fonts" end:"1")] diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/CreatingFonts/CreatingFonts.CHN.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/CreatingFonts/CreatingFonts.CHN.udn new file mode 100644 index 000000000000..8c109f95a922 --- /dev/null +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/CreatingFonts/CreatingFonts.CHN.udn @@ -0,0 +1,93 @@ +INTSourceChangelist:3403467 +Availability:Public +crumbs:%ROOT% +Title:创建并指定字体 +Description:此指南说明如何创建用于 UMG UI 设计器工具的字体资源。 +Type:how-to +SkillLevel:Beginner +Version:4.15 +Parent:Engine/UMG/UserGuide/Fonts/Howto +Related:Engine/UMG/UserGuide/Fonts +Related:Engine/UMG/UserGuide/Fonts/HowTo/ImportingFonts +Related:Engine/UMG/UserGuide/Fonts/HowTo/FontsWithUMG +Order:2 +Tags:UMG UI Designer +topic-image:CreatingFonts_Topic.png + +在此指南中,您将了解如何创建空白字体资源(可对其指定字体风格资源,或直接使用字体编辑器导入新 TTF 或 OTF 字体文件)。 + +![](CreatingFonts_Hero.png)(w:700) + + +## 步骤 + +根据以下步骤自建字体资源,然后学习如何使用字体编辑器指定一个字体风格资源。 + +[REGION:note] +在此指南中,我们使用的是 **Blank Template**,未加入 **Starter Content**、选择默认 **Target Hardware** 和 **Project Settings**。 +[/REGION] + + +### 创建字体资源 + +1. 点击 **Content Browser** 中的 **Add New** 按钮,然后选择 **User Interface** 下的 **Font** 选项。 + + [REGION:lightbox] + [![](NewFont.png)(h:500)](NewFont.png) + [/REGION] + [REGION:caption] + _点击图片查看全图。_ + [/REGION] + +1. 将新建一个合成字体资源,并弹出提示为其 **命名**。 + + ![](NameFont.png) + +1. 输入命名后,资源上将出现一个星号,说明资源尚未保存。点击 **Save All** 按钮保存资源,然后在弹出的菜单中确认保存。 + + ![](SaveFont.png) + +### 指定字体风格资源 + +1. 创建空白字体资源后,便需要指定使用的字体风格。双击字体在字体编辑器中打开执行此操作。 + + ![](FontEditorWindow.png)(w:700) + +1. 在字体编辑器中点击 **Add Font** 按钮新增一个字体槽。 + + ![](CB_Fonts.png)(w:381) + +1. 使用字体命名下方的下拉选择选中已导入项目的字体风格资源。 + + ![](AssignFontFace.png)(w:700) + + [REGION:note] + 如尚未拥有字体风格资源,可使用下拉选择框旁的文件夹图标寻找并导入您自己的 TrueType Font(TTF)或 OpenType Font(OTF)字体文件。 + [/REGION] + +## 最终结果 + +了解如何自建字体资源和使用字体编辑器指定导入的字体风格资源后,即可自建用于 UMG UI 设计器的字体资源。 + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/CreatingFonts/CreatingFonts.INT.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/CreatingFonts/CreatingFonts.INT.udn new file mode 100644 index 000000000000..1e68f2c97c12 --- /dev/null +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/CreatingFonts/CreatingFonts.INT.udn @@ -0,0 +1,92 @@ +Availability: Public +crumbs:%ROOT% +Title: Creating and Assigning Fonts +Description: This how-to will guide you through creating Font assets that can be used with the UMG UI designer tools. +Type:how-to +SkillLevel: Beginner +Version: 4.15 +Parent: Engine/UMG/UserGuide/Fonts/Howto +Related: Engine/UMG/UserGuide/Fonts +Related: Engine/UMG/UserGuide/Fonts/HowTo/ImportingFonts +Related: Engine/UMG/UserGuide/Fonts/HowTo/FontsWithUMG +Order:2 +Tags: UMG UI Designer +topic-image:CreatingFonts_Topic.png + +In this guide, you'll learn how to create an empty Font asset to which you can then assign a Font Face asset or import a new TTF or OTF font file directly using the Font Editor. + +![](CreatingFonts_Hero.png)(w:700) + + +## Steps + +Follow the steps below to create your own Font asset and then learn how to assign one of your Font Face assets using the Font Editor. + +[REGION:note] +For this how-to guide, we are using the **Blank Template** project, using no **Starter Content**, with default **Target Hardware** and **Project Settings**. +[/REGION] + + +### Creating a Font Asset + +1. Click the **Add New** button inside the **Content Browser**, then under **User Interface**, select the **Font** option. + + [REGION:lightbox] + [![](NewFont.png)(h:500)](NewFont.png) + [/REGION] + [REGION:caption] + _Click image for full view._ + [/REGION] + +1. A new Composite Font asset will be created, prompting you to give it a **Name**. + + ![](NameFont.png) + +1. Once you enter a name, you will notice an asterisk appears on the asset, this indicates that the asset has not be saved. Click the **Save All** button to save your asset, then confirm the save in the pop-up menu that appears. + + ![](SaveFont.png) + +### Assign a Font Face Asset + +1. Now that you've created your empty Font asset, you will have to assign your Font Face(s) to be used. To do this, double-click to open your Font in the Font Editor. + + ![](FontEditorWindow.png)(w:700) + +1. In the Font Editor, click on the **Add Font** button to add a new Font slot. + + ![](CB_Fonts.png)(w:381) + +1. Now, use the dropdown selection under the Font Name to select an existing Font Face asset that was already imported into your project. + + ![](AssignFontFace.png)(w:700) + + [REGION:note] + If you do not have any Font Face assets, you can use the Folder icon next to the dropdown selection box to navigate and import your own TrueType Font (TTF) or OpenType Font (OTF) font file. + [/REGION] + +## End Result + +Now that you've seen how to create your own Font assets and assign an already imported Font Face asset using the Font Editor, you should be able to create your own Font assets that can be used with the UMG UI Designer. + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/CreatingFonts/CreatingFonts.JPN.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/CreatingFonts/CreatingFonts.JPN.udn new file mode 100644 index 000000000000..8cd18c2c1b16 --- /dev/null +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/CreatingFonts/CreatingFonts.JPN.udn @@ -0,0 +1,93 @@ +INTSourceChangelist:3403467 +Availability:Public +crumbs:%ROOT% +Title:フォントを作成し、割り当てる +Description:UMG UI デザイナ ツールで使用できる Font アセットの作成について説明します。 +Type:how-to +SkillLevel:Beginner +Version:4.15 +Parent:Engine/UMG/UserGuide/Fonts/Howto +Related:Engine/UMG/UserGuide/Fonts +Related:Engine/UMG/UserGuide/Fonts/HowTo/ImportingFonts +Related:Engine/UMG/UserGuide/Fonts/HowTo/FontsWithUMG +Order:2 +Tags:UMG UI Designer +topic-image:CreatingFonts_Topic.png + +このガイドでは空の Font アセットを作成する方法について説明します。この Font アセットに Font Face アセットを割り当てたり、フォント エディタを使って新しい TTF または OTF のフォント ファイルを直接インポートすることができます。 + +![](CreatingFonts_Hero.png)(w:700) + + +## ステップ + +以下のステップに従い、Font アセットを作成します。次に、フォント エディタを使って Font Face アセットを割り当てる方法を学びます。 + +[REGION:note] +この操作ガイドでは **スターターコンテンツを含まない** を有効にした状態で、デフォルトの **Target Hardware** と **Project Settings** を使います。 +[/REGION] + + +### Font アセットを作成する + +1. **コンテンツ ブラウザ** で、 **[Add New]** ボタンをクリックし、 **[User Interface (ユーザーインターフェース)]** で **[Font]** オプションをクリックします。 + + [REGION:lightbox] + [![](NewFont.png)(h:500)](NewFont.png) + [/REGION] + [REGION:caption] + _画像をクリックしてフルサイズで表示_ + [/REGION] + +1. 新しい Composite Font アセットが作成されます。**名前** を付けるよう促されます。 + + ![](NameFont.png) + +1. 名前を入力したらアセットにアスタリスク記号が付いているのがわかります。これはアセットが保存されていないことを示します。**[Save All]** ボタンをクリックしてアセットを保存します。次に表示されるポップアップ メニューで保存を確認します。 + + ![](SaveFont.png) + +### Font Face アセットを割り当てる + +1. 空の Font アセットを作成したので、使用する Font Face を割り当てなければなりません。これを行うには、フォント エディタで Font をダブルクリックします。 + + ![](FontEditorWindow.png)(w:700) + +1. フォント エディタで新しいフォント スロットを追加するには、**[Add Font]** ボタンをクリックします。 + + ![](CB_Fonts.png)(w:381) + +1. Font Name のドロップダウン選択を使って、プロジェクトにインポート済みの既存の Font Face アセットを選択します。 + + ![](AssignFontFace.png)(w:700) + + [REGION:note] + Font Face アセットを何も持っていない場合は、ドロップダウン選択ボックスの隣にある Folder アイコンを使って TrueType Font (TTF) または OpenType Font (OTF) のフォント ファイルに移動してインポートしてください。 + [/REGION] + +## 最終結果 + +Font アセットの作成方法と、フォント エディタを使ってインポート済みの Font Face アセットに割り当てる方法について説明しました。これで UMG UI デザイナで使用できる Font アセットを作成できるはずです。 + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/CreatingFonts/CreatingFonts.KOR.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/CreatingFonts/CreatingFonts.KOR.udn new file mode 100644 index 000000000000..9372514d8a3c --- /dev/null +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/CreatingFonts/CreatingFonts.KOR.udn @@ -0,0 +1,93 @@ +INTSourceChangelist:3403467 +Availability: Public +crumbs:%ROOT% +Title: 폰트 생성 및 할당 +Description: UMG UI 디자이너 툴에 사용할 수 있는 폰트 애셋을 만드는 법을 안내해 드립니다. +Type:how-to +SkillLevel: Beginner +Version: 4.15 +Parent: Engine/UMG/UserGuide/Fonts/Howto +Related: Engine/UMG/UserGuide/Fonts +Related: Engine/UMG/UserGuide/Fonts/HowTo/ImportingFonts +Related: Engine/UMG/UserGuide/Fonts/HowTo/FontsWithUMG +Order:2 +Tags: UMG UI Designer +topic-image:CreatingFonts_Topic.png + +여기서는 공백 폰트 애셋을 만들어 폰트 페이스 애셋을 할당하거나, 폰트 에디터를 사용하여 새로운 TTF 또는 OTF 폰트 파일을 바로 임포트하는 법을 알아봅니다. + +![](CreatingFonts_Hero.png)(w:700) + + +## 단계 + +별도의 폰트 애셋을 만들고 폰트 에디터를 사용하여 폰트 페이스 애셋을 할당하는 법은 다음과 같습니다. + +[REGION:note] +여기서는 **공백 템플릿** 프로젝트에 **시작용 콘텐츠** 없음, **타겟 하드웨어** 와 **프로젝트 세팅** 은 기본으로 한 것을 사용합니다. +[/REGION] + + +### 폰트 애셋 생성 + +1. **콘텐츠 브라우저** 안에서 **신규 추가** 버튼을 클릭한 뒤, **유저 인터페이스** 아래 **폰트** 옵션을 선택합니다. + + [REGION:lightbox] + [![](NewFont.png)(h:500)](NewFont.png) + [/REGION] + [REGION:caption] + _클릭하면 이미지 원본을 확인합니다._ + [/REGION] + +1. 새로운 컴포짓 폰트 애셋이 생성되며, **이름** 을 지어야 합니다. + + ![](NameFont.png) + +1. 이름을 입력했으면 애셋에 별표 표시가 보이는데, 애셋이 저장되지 않았음을 나타냅니다. **모두 저장** 버튼을 눌러 애셋을 저장, 팝업 메뉴가 뜨면 저장을 확인합니다. + + ![](SaveFont.png) + +### 폰트 페이스 애셋 할당 + +1. 공백 폰트 애셋을 생성했으니, 사용할 폰트 페이스를 할당해 줘야 합니다. 폰트 에디터에서 폰트를 더블클릭하여 엽니다. + + ![](FontEditorWindow.png)(w:700) + +1. 폰트 에디터에서 **폰트 추가** 버튼을 클릭하여 새 폰트 슬롯을 추가합니다. + + ![](CB_Fonts.png)(w:381) + +1. 이제 Font Name (폰트 이름) 아래 선택 드롭다운으로 프로젝트에 이미 임포트해 둔 기존 폰트 페이스 애셋을 선택합니다. + + ![](AssignFontFace.png)(w:700) + + [REGION:note] + 폰트 페이스 애셋이 없는 경우, 선택 드롭다운 옆 폴더 아이콘을 누른 뒤 별도의 트루타입 폰트(TTF) 또는 오픈타입 폰트(OTF) 파일을 임포트합니다. + [/REGION] + +## 최종 결과 + +폰트 에디터를 사용하여 별도의 폰트 애셋을 만들고 이미 임포트된 폰트 페이스 애셋을 할당하는 법을 살펴봤으니, 이제 UMG UI 디자이너에 사용할 수 있는 별도의 폰트 애셋 제작이 가능하실 것입니다. + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/FontsHowToLanding.CHN.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/FontsHowToLanding.CHN.udn new file mode 100644 index 000000000000..304438e04b23 --- /dev/null +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/FontsHowToLanding.CHN.udn @@ -0,0 +1,34 @@ +INTSourceChangelist:3399451 +Availability:Public +Crumbs:%ROOT%, Engine, Engine/UMG, Engine/UMG/UserGuide +Title:字体指南 +Description:字体指南着陆页面。 +Type:Landing +Version:4.15 +Parent:Engine/UMG/UserGuide/Fonts +Related:Engine/UMG/UserGuide/Fonts +Related:Engine/UMG/UserGuide/WidgetBlueprints +Related:Engine/UMG/UserGuide/WidgetTypeReference +Order: +Tags:UMG UI Designer +Tags:Fonts +Topic-Image:FontHowTo_Topic.png + +以下指南将说明在项目中创建和使用字体的要点。 + +## 初级 + +[DIR(output:"fancy" parent:"Engine/UMG/UserGuide/Fonts/HowTo" skill_level:"Beginner")] + + + diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/FontsHowToLanding.INT.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/FontsHowToLanding.INT.udn new file mode 100644 index 000000000000..2ad385986025 --- /dev/null +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/FontsHowToLanding.INT.udn @@ -0,0 +1,33 @@ +Availability: Public +Crumbs:%ROOT%, Engine, Engine/UMG, Engine/UMG/UserGuide +Title: Fonts - How To's +Description: How-To landing page for Fonts. +Type: Landing +Version:4.15 +Parent: Engine/UMG/UserGuide/Fonts +Related: Engine/UMG/UserGuide/Fonts +Related: Engine/UMG/UserGuide/WidgetBlueprints +Related: Engine/UMG/UserGuide/WidgetTypeReference +Order: +Tags: UMG UI Designer +Tags: Fonts +Topic-Image:FontHowTo_Topic.png + +The Following guides walk you through topics designed to help you create and use Fonts in your projects. + +## Beginner + +[DIR(output:"fancy" parent:"Engine/UMG/UserGuide/Fonts/HowTo" skill_level:"Beginner")] + + + \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/FontsHowToLanding.JPN.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/FontsHowToLanding.JPN.udn new file mode 100644 index 000000000000..4bc9fd91203f --- /dev/null +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/FontsHowToLanding.JPN.udn @@ -0,0 +1,34 @@ +INTSourceChangelist:3399451 +Availability:Public +Crumbs:%ROOT%, Engine, Engine/UMG, Engine/UMG/UserGuide +Title:フォント - 操作ガイド +Description:フォント操作ガイドのランディング ページ +Type:Landing +Version:4.15 +Parent:Engine/UMG/UserGuide/Fonts +Related:Engine/UMG/UserGuide/Fonts +Related:Engine/UMG/UserGuide/WidgetBlueprints +Related:Engine/UMG/UserGuide/WidgetTypeReference +Order: +Tags:UMG UI Designer +Tags:Fonts +Topic-Image:FontHowTo_Topic.png + +プロジェクトにおけるフォントの作成および使用について説明します。 + +## Beginner + +[DIR(output:"fancy" parent:"Engine/UMG/UserGuide/Fonts/HowTo" skill_level:"Beginner")] + + + \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/FontsHowToLanding.KOR.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/FontsHowToLanding.KOR.udn new file mode 100644 index 000000000000..153b885baf9a --- /dev/null +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/FontsHowToLanding.KOR.udn @@ -0,0 +1,34 @@ +INTSourceChangelist:3399451 +Availability: Public +Crumbs:%ROOT%, Engine, Engine/UMG, Engine/UMG/UserGuide +Title: 폰트 안내서 +Description: 폰트 안내서 첫 페이지입니다. +Type: Landing +Version:4.15 +Parent: Engine/UMG/UserGuide/Fonts +Related: Engine/UMG/UserGuide/Fonts +Related: Engine/UMG/UserGuide/WidgetBlueprints +Related: Engine/UMG/UserGuide/WidgetTypeReference +Order: +Tags: UMG UI Designer +Tags: Fonts +Topic-Image:FontHowTo_Topic.png + +프로젝트에 쓸 폰트를 만들고 사용하는 데 도움이 되는 주제에 대한 안내입니다. + +## 초급 + +[DIR(output:"fancy" parent:"Engine/UMG/UserGuide/Fonts/HowTo" skill_level:"Beginner")] + + + \ No newline at end of file diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/FontsWithUMG/FontsWithUMG.CHN.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/FontsWithUMG/FontsWithUMG.CHN.udn new file mode 100644 index 000000000000..f21ed0dcc767 --- /dev/null +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/FontsWithUMG/FontsWithUMG.CHN.udn @@ -0,0 +1,77 @@ +INTSourceChangelist:3403467 +Availability:Public +crumbs:%ROOT% +Title:结合 UMG 使用字体 +Description:此指南说明如何结合 UMG UI 设计器工具使用字体。 +Type:how-to +SkillLevel:Beginner +Version:4.15 +Parent:Engine/UMG/UserGuide/Fonts/Howto +Related:Engine/UMG/UserGuide/Fonts +Related:Engine/UMG/UserGuide/Fonts/HowTo/ImportingFonts +Related:Engine/UMG/UserGuide/Fonts/HowTo/CreatingFonts +Related:Engine/UMG/UserGuide/WidgetBlueprints +Order:3 +Tags:UMG UI Designer +topic-image:FontsWithUMG_Topic.png + + +在此指南中,您将学习到如何在包含文本的控件蓝图中使用自建字体资源。 + +![](FontWithUMG_Hero.png)(w:700) + + +## 步骤 + +按以下步骤操作,学习如何对结合 UMG UI 设计器使用的自建字体进行指定。 + +[REGION:note] +在此指南中,我们使用的是 **Blank Template**,未加入 **Starter Content**、选择默认 **Target Hardware** 和 **Project Settings**。 +[/REGION] + +1. 在 Content Browser 中点击 **Add New** 按钮,鼠标悬停在 **User Interface** 上,然后点击 **Widget Blueprint** 选项新建一个 [控件蓝图](Engine/UMG/UserGuide/WidgetBlueprints)。此操作将新建一个控件蓝图。为其设置一个便于查找的命名。 + + ![](CreateWidgetBP.png)(w:275) + +1. 返回保存控件蓝图的 Content Browser,双击将其打开。在控件蓝图的调色板中,选中一个 **Text** 控件并将其拖到图表之上。然后选中角落将其放大。 + + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 640 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 360 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + 5GWSAIUZNaE + [/PARAMLITERAL] + [/OBJECT] + +1. 创建文本控件后,即可点击它访问 **Details** 面板,可在 **Appearance** 下的 **Font** 选项中修改字体类型、风格(常规、粗体、斜体等),以及大小。 + + ![](FontWithNewOptions.png)(w:900) + +1. 引擎默认使用 **Roboto** 字体。然而点击下拉菜单即可选择和使用创建的任意合成字体资源。 + + ![](NewFontWithNewOptions.png)(w:900) + + [REGION:note] + 也可在此菜单中创建一个合成字体并指定新资源的保存位置(默认为空,需要填入)。 + [/REGION] + +1. 选择合成字体后,可通过第二个下拉菜单从 **默认字体群** 中选择一个字体使用。 + + ![](FontStyleNewOptions.png) + + 也可在输入框中指定字体的大小。 + + ![](FontSizeNewOptions.png)(w:900) + +[REGION:note] +当前版本中 UMG 只支持 **Runtime** 缓存字体资源。此外,如果您已使用老方法指定字体,基于文件的现有字体设置不会丢失;但之后需要创建合成字体文件以便以 UMG 使用自定义字体。 +[/REGION] + +## 最终结果 + +在 UMG 中成功使用字体后,即可 [设置颜色、材质和外框属性](Engine/UMG/UserGuide/Fonts/Materials)(以及使用阴影),学习如何设置 **字体** 风格。 + diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/FontsWithUMG/FontsWithUMG.INT.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/FontsWithUMG/FontsWithUMG.INT.udn new file mode 100644 index 000000000000..83b7f11ef04b --- /dev/null +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/FontsWithUMG/FontsWithUMG.INT.udn @@ -0,0 +1,79 @@ +Availability: Public +crumbs:%ROOT% +Title: Using Fonts with UMG +Description: This how-to will guide you through using Fonts with the UMG UI designer tools. +Type:how-to +SkillLevel: Beginner +Version: 4.15 +Parent: Engine/UMG/UserGuide/Fonts/Howto +Related: Engine/UMG/UserGuide/Fonts +Related: Engine/UMG/UserGuide/Fonts/HowTo/ImportingFonts +Related: Engine/UMG/UserGuide/Fonts/HowTo/CreatingFonts +Related: Engine/UMG/UserGuide/WidgetBlueprints +Order:3 +Tags: UMG UI Designer +topic-image:FontsWithUMG_Topic.png + + +In this guide, you'll learn how to use your own Font assets in Widget Blueprints that contain Text. + +![](FontWithUMG_Hero.png)(w:700) + + +## Steps + +Follow the steps below to see how to assign your own Fonts to be used with the UMG UI Designer. + +[REGION:note] +For this how-to guide, we are using the **Blank Template** project, using no **Starter Content**, with default **Target Hardware** and **Project Settings**. +[/REGION] + +1. To create a new [Widget Blueprint](Engine/UMG/UserGuide/WidgetBlueprints), from the Content Browser click on the **Add New** button, then hover over **User Interface**, and then click on **Widget Blueprint** selection. This will create +a new Widget Blueprint. Make sure to give it a name that you can easily locate later. + + ![](CreateWidgetBP.png)(w:275) + +1. Go back to the Content Browser where you saved your Widget Blueprint and double-click on it to open it up. In the Widget Blueprint's Palette, select a **Text** widget and drag it onto the +graph. Then grab the corner and scale it to a larger size. + + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 640 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 360 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + 5GWSAIUZNaE + [/PARAMLITERAL] + [/OBJECT] + +1. Now that you've created your Text Widget, you can click on it and access the **Details** panel, under **Appearance**, you'll see a **Font** option where you can change the font type, it's styling (regular, bold, itallic, etc.), and its size. + + ![](FontWithNewOptions.png)(w:900) + +1. By default, the Engine uses the **Roboto** font, however, if you click the dropdown menu, any Composite Font assets created can be selected and used instead. + + ![](NewFontWithNewOptions.png)(w:900) + + [REGION:note] + You can also choose to create a Composite Font from this menu and specify where the new asset should be saved (it will be blank by default, requiring you to fill it out). + [/REGION] + +1. Once you select your Composite Font, the second dropdown menu will allow you to select a font to use from the **Default Font Family**. + + ![](FontStyleNewOptions.png) + + You can also specify the size of the font in the input box. + + ![](FontSizeNewOptions.png)(w:900) + +[REGION:note] +Currently, UMG only supports **Runtime** cached font assets. Also, if you have assigned fonts using the old method, none of your existing file-based font settings will be lost, however going forward, you will need to create +a Composite Font asset in order to use custom fonts with UMG. +[/REGION] + +## End Result + + Now that you've successfully used your fonts in UMG, you can head over to learn how to style your **Fonts** by [setting colors, Materials, and outline properties](Engine/UMG/UserGuide/Fonts/Materials) (as well as by using shadows). + diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/FontsWithUMG/FontsWithUMG.JPN.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/FontsWithUMG/FontsWithUMG.JPN.udn new file mode 100644 index 000000000000..0e0a8039db3c --- /dev/null +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/FontsWithUMG/FontsWithUMG.JPN.udn @@ -0,0 +1,80 @@ +INTSourceChangelist:3403467 +Availability:Public +crumbs:%ROOT% +Title:UMG でフォントを使用する +Description:UMG UI デザイナ ツールでの Font アセットの使用について説明します。 +Type:how-to +SkillLevel:Beginner +Version:4.15 +Parent:Engine/UMG/UserGuide/Fonts/Howto +Related:Engine/UMG/UserGuide/Fonts +Related:Engine/UMG/UserGuide/Fonts/HowTo/ImportingFonts +Related:Engine/UMG/UserGuide/Fonts/HowTo/CreatingFonts +Related:Engine/UMG/UserGuide/WidgetBlueprints +Order:3 +Tags:UMG UI Designer +topic-image:FontsWithUMG_Topic.png + + +このガイドでは Text を含む Widget ブループリントで Font アセットを使用する方法を説明します。 + +![](FontWithUMG_Hero.png)(w:700) + + +## ステップ + +以下のステップでは、ご自分のフォントを UMG UMG UI デザイナで使用するために割り当てる方法を説明します。 + +[REGION:note] +この操作ガイドでは **スターターコンテンツを含まない** を有効にした状態で、デフォルトの **Target Hardware** と **Project Settings** を使います。 +[/REGION] + +1. コンテンツ ブラウザで、新規 [Widget ブループリント](Engine/UMG/UserGuide/WidgetBlueprints) を作成するには、**[Add New (新規追加)]** ボタンをクリックします。次に **[ユーザーインターフェース (UI)]** にマウスをかざして、**[Widget ブループリント]** をクリックします。これで +新規 Widget ブループリントが作成されます。後で簡単に見つけられるようにわかりやすい名前を付けてください。 + + ![](CreateWidgetBP.png)(w:275) + +1. Widget ブループリントを保存したコンテンツ ブラウザに戻り、それをダブルクリックして開きます。Widget ブループリントのパレットで **Text** ウィジェットを選択し、グラフ上に +ドラッグします。次に角をつかみ、大きなサイズにスケーリングします。 + + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 640 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 360 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + 5GWSAIUZNaE + [/PARAMLITERAL] + [/OBJECT] + +1. ここまでで Text ウィジェットを作成しました。その上でクリックして、**[Details]** パネルを開くと、 **[Appearance]** に **[Font]** オプションがあります。ここで、フォントの種類、そのスタイル (通常、太字、斜体など) サイズを変更することができます。 + + ![](FontWithNewOptions.png)(w:900) + +1. デフォルトでは、エンジンは **Roboto** フォントを使用します。しかし、ドロップダウン メニューをクリックし、作成した任意の Composite Font アセットを選択し、代わりに使用することができます。 + + ![](NewFontWithNewOptions.png)(w:900) + + [REGION:note] + このメニューからコンポジット フォントを作成して、その新しいアセットの保存場所を指定することもできます (デフォルトではブランクであり、入力する必要があります)。 + [/REGION] + +1. コンポジット フォントを選択したら、2 つめのドロップダウン メニューで使用するフォントを **[Default Font Family]** から選択できます。 + + ![](FontStyleNewOptions.png) + + フォント サイズを入力ボックスで指定することもできます。 + + ![](FontSizeNewOptions.png)(w:900) + +[REGION:note] +現時点では UMG は **ランタイム** にキャッシュされるフォント アセットのみをサポートしています。古い方式を用いてフォントを割り当てた場合、既存のファイル ベースのフォント設定は失われません。 +しかし、UMG でカスタム フォントを使用するためには、いずれは Composite Font アセットを作成する必要があります。 +[/REGION] + +## 最終結果 + + ここまでで、UMG のフォントの使用について説明してきました。[色、マテリアル、アウトラインのプロパティを設定](Engine/UMG/UserGuide/Fonts/Materials) したり、 (陰影をつけて) フォントにスタイルを設定することができます。 + diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/FontsWithUMG/FontsWithUMG.KOR.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/FontsWithUMG/FontsWithUMG.KOR.udn new file mode 100644 index 000000000000..8dc793f9e0d1 --- /dev/null +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/FontsWithUMG/FontsWithUMG.KOR.udn @@ -0,0 +1,80 @@ +INTSourceChangelist:3403467 +Availability: Public +crumbs:%ROOT% +Title: UMG 에 폰트 사용 +Description: UMG UI 디자이너 툴에 폰트를 사용하는 방법 안내서입니다. +Type:how-to +SkillLevel: Beginner +Version: 4.15 +Parent: Engine/UMG/UserGuide/Fonts/Howto +Related: Engine/UMG/UserGuide/Fonts +Related: Engine/UMG/UserGuide/Fonts/HowTo/ImportingFonts +Related: Engine/UMG/UserGuide/Fonts/HowTo/CreatingFonts +Related: Engine/UMG/UserGuide/WidgetBlueprints +Order:3 +Tags: UMG UI Designer +topic-image:FontsWithUMG_Topic.png + + +여기서는 텍스트가 들어있는 위젯 블루프린트에서 별도의 폰트 애셋을 사용하는 법을 알아보겠습니다. + +![](FontWithUMG_Hero.png)(w:700) + + +## 단계 + +UMG UI 디자이너에서 사용할 폰트 애셋을 할당하는 방법은 다음과 같습니다. + +[REGION:note] +여기서는 **공백 템플릿** 프로젝트에 **시작용 콘텐츠** 없음, 기본 **타겟 하드웨어** 및 **프로젝트 세팅** 을 사용하고 있습니다. +[/REGION] + +1. 새 [위젯 블루프린트](Engine/UMG/UserGuide/WidgetBlueprints) 생성을 위해서는, 콘텐츠 브라우저에서 **신규 추가** 버튼을 클릭한 뒤, **유저 인터페이스** 에 커서를 올리고 **위젯 블루프린트** 를 선택합니다. +그러면 새 위젯 블루프린트가 생성됩니다. 나중에 쉽게 찾을 수 있도록 이름을 지어 주세요. + + ![](CreateWidgetBP.png)(w:275) + +1. 콘텐츠 브라우저의 위젯 블루프린트를 저장한 곳으로 돌아가 더블클릭하여 엽니다. 위젯 블루프린트의 팔레트 창에서 **Text** 위젯을 선택하고 그래프에 끌어 놓습니다. +그런 다음 구석을 잡아 끌어 크기를 키웁니다. + + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 640 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 360 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + 5GWSAIUZNaE + [/PARAMLITERAL] + [/OBJECT] + +1. Text 위젯을 생성했으니, 클릭해서 **디테일** 패널 **Appearance** 아래 폰트 유형, 스타일(일반, 두껍게, 이탤릭 등), 크기를 바꿀 수 있는 **Font** 옵션이 보입니다. + + ![](FontWithNewOptions.png)(w:900) + +1. 기본적으로 엔진에서는 **Roboto** 폰트를 사용합니다만, 드롭다운 메뉴를 클릭하면 만들어 둔 컴포짓 폰트 애셋을 선택하여 대신 사용할 수도 있습니다. + + ![](NewFontWithNewOptions.png)(w:900) + + [REGION:note] + 이 메뉴에서 컴포짓 폰트를 생성하고 새로운 애셋 저장 위치를 지정할 수도 있습니다 (기본값은 공백이므로 채워넣어야 합니다). + [/REGION] + +1. 컴포짓 폰트를 선택했으면, 두 번째 드롭다운 메뉴를 통해 **디폴트 폰트 패밀리** 의 폰트를 선택할 수 있습니다. + + ![](FontStyleNewOptions.png) + + 입력 박스에 폰트 크기를 지정할 수도 있습니다. + + ![](FontSizeNewOptions.png)(w:900) + +[REGION:note] +현재 UMG 는 **Runtime** 캐시 폰트 애셋만 지원합니다. 또한 예전 메소드를 사용한 폰트를 할당한 경우, 기존 파일 기반 폰트 세팅이 사라지지는 않지만, 앞으로는 UMG 에 커스텀 폰트를 사용하기 위해서는 +컴포짓 폰트 애셋을 생성해야 합니다. +[/REGION] + +## 최종 결과 + + UMG 에서 폰트를 사용하는 데 성공했으니, [색, 머티리얼, 윤곽선 프로퍼티 설정](Engine/UMG/UserGuide/Fonts/Materials) (및 음영 사용)과 같은 폰트 스타일 지정 방법도 참고해 보시기 바랍니다. + diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/ImportingFonts/ImportingFonts.CHN.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/ImportingFonts/ImportingFonts.CHN.udn new file mode 100644 index 000000000000..dee085c1c636 --- /dev/null +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/ImportingFonts/ImportingFonts.CHN.udn @@ -0,0 +1,103 @@ +INTSourceChangelist:3403467 +Availability:Public +crumbs: +Title:导入字体 +Description:此指南将说明如何将字体资源导入虚幻引擎 4 使用。 +Type:How-to +SkillLevel:Beginner +Version:4.15 +Parent:Engine/UMG/UserGuide/Fonts/Howto +Related:Engine/UMG/UserGuide/Fonts +Related:Engine/UMG/UserGuide/Fonts/HowTo/CreatingFonts +Related:Engine/UMG/UserGuide/Fonts/HowTo/FontsWithUMG +Order:1 +Tags:UMG UI Designer +topic-image:ImportingFonts_Topic.png + +此指南说明如何将自建字体文件导入虚幻引擎 4。 + +[REGION:raw] +![](ImportFonts_Hero.png)(w:800) +[/REGION] + +开始导入文件后,可在多种方法中进行选择,选择最适合您工作流程的方法。可选择的导入方法: + +* 使用 Content Browser 的 Import 按钮。 +* 拖放到 Content Browser 中 +* 使用字体编辑器 + +导入字体时还可以在 **TrueType Font**(TTF)和 **OpenType Font**(OTF)之间进行选择。选择最能满足您需求的导入方法和字体类型。 + +[REGION:note] +在此指南中,我们使用的是 **Blank Template**,未加入 **Starter Content**、选择默认 **Target Hardware** 和 **Project Settings**。 +[/REGION] + +## 使用 Content Browser + +可使用 Content Browser 的 **Import** 按钮选择 TTF 或 OTF 字体文件。 + +1. 在 Content Browser 中点击 **Import** 按钮。 + + ![](Import1.png) + +1. **Import** 对话框出现后,导航至需要导入的 TFF 或 OTF 字体文件并将其选中。然后点击 **Open**。 + + ![](Import2.png)(w:500) + +1. 稍后将出现 **Font Face Import Options** 对话。从列出的选项中选择 **Yes**,在 Content Browser 中创建字体风格资源和合成字体资源。 + + ![](Import3.png)(w:500) + +1. 现在即可在文件夹层级中找到字体风格资源。 + + ![](Import3a.png) + + +## 使用拖放 + +用户可将 TTF 或 OTF 文件直接 **拖放** 到 Content Browser 中创建字体资源。 + +1. 导航到保存 TTF 或 OTF 文件的文件夹。选择并长按将文件拖到 **Content Browser** 上开始导入进程。 + + ![](Import4.png)(w:650) + +1. 稍后将出现 **Font Import Options**。从列出的选项中选择 **Yes**,在 Content Browser 中创建字体风格资源和合成字体资源。 + + ![](Import3.png)(w:500) + +1. 现在即可在文件夹层级中找到字体风格资源。 + + ![](Import3a.png) + +## 使用字体编辑器 + +用户可直接从 **字体编辑器** 中的 [默认字体群](Engine/UMG/UserGuide/Fonts/Overview#defaultfontfamily) 列表导入并创建字体风格资源,无需先导入字体资源再对其进行指定。 + +1. 打开一个现有 **字体** 资源或使用 Content Browser 中的 **Add New** 按钮。 + + ![](Import5.png)(w:600) + +1. 点击 **Add Font** 按钮为 **默认字体群** 添加一个新的字体选项。 + + ![](Import6.png)(w:500) + +1. 选择选项下拉旁边的 **folder** 按钮。 + + ![](Import7.png)(w:500) + +1. **Import** 对话框出现后,导航至需要导入的 TFF 或 OTF 字体文件并将其选中。然后点击 **Open**。 + + ![](Import2.png)(w:500) + +1. 之后将出现 **Save Font Face** 窗口。为字体命名,在游戏文件夹层级中选择相同路径。然后点击 **Save**。 + + ![](Import8.png)(w:500) + +1. 现在即可在文件夹层级中找到字体风格资源。 + + ![](Import3a.png) + +## 最终结果 + +了解如何使用多种方法进行导入后,即可使用这些选项将自建字体文件导入游戏和项目。 + diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/ImportingFonts/ImportingFonts.INT.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/ImportingFonts/ImportingFonts.INT.udn new file mode 100644 index 000000000000..e08f19818e0a --- /dev/null +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/ImportingFonts/ImportingFonts.INT.udn @@ -0,0 +1,104 @@ +Availability: Public +crumbs: +Title: Importing Fonts +Description: This how-to will guide you through importing your Font assets for use in Unreal Engine 4. +Type: How-to +SkillLevel: Beginner +Version: 4.15 +Parent: Engine/UMG/UserGuide/Fonts/Howto +Related: Engine/UMG/UserGuide/Fonts +Related: Engine/UMG/UserGuide/Fonts/HowTo/CreatingFonts +Related: Engine/UMG/UserGuide/Fonts/HowTo/FontsWithUMG +Order:1 +Tags: UMG UI Designer +topic-image:ImportingFonts_Topic.png + +In this guide, you'll learn how to import your own Font files into Unreal Engine 4. + +[REGION:raw] +![](ImportFonts_Hero.png)(w:800) +[/REGION] + +When you start to import your Fonts, you can choose between several methods and choose the method that best fits your workflow. The available methods you can use to import are: + +* Using the Content Browser's Import button +* Drag-and-drop method into the Content Browser +* Using the Font Editor + +You also have the choice between **TrueType Font** (TTF) and **OpenType Font** (OTF) files when importing your fonts. Choose the import method and font type that best fits your needs. + + +[REGION:note] +For this how-to guide, we are using the **Blank Template** project, using no **Starter Content**, with default **Target Hardware** and **Project Settings**. +[/REGION] + +## Using the Content Browser + +You can use the Content Browser's **Import** button to select your TTF or OTF font file. + +1. In the Content Browser, click the **Import** button. + + ![](Import1.png) + +1. After the **Import** dialog box appears, navigate to the TFF or OTF font file you want to import and select it. Then, click **Open**. + + ![](Import2.png)(w:500) + +1. After a moment, the **Font Face Import Options** dialog will appear. Select **Yes** from the options listed to create your Font Face asset and your Composite Font asset in your Content Browser. + + ![](Import3.png)(w:500) + +1. The Font Face asset can now be found in your folder hierarchy. + + ![](Import3a.png) + + +## Using Drag-and-drop + +You can **Drag-and-drop** a TTF or OTF file directly into the Content Browser to create your font assets. + +1. Navigate to the folder where you've stored your TTF or OTF file(s). Select and hold to drag the file over the **Content Browser** to start the import process. + + ![](Import4.png)(w:650) + +1. After a moment, the **Font Import Options** will appear. Select **Yes** from the options listed to create your Font Face asset and your Composite Font asset in your Content Browser. + + ![](Import3.png)(w:500) + +1. The Font Face asset can now be found in your folder hierarchy. + + ![](Import3a.png) + +## Using the Font Editor + +You can import and create Font Face assets directly from the [Default Font Family](Engine/UMG/UserGuide/Fonts/Overview#defaultfontfamily) list in the **Font Editor** removing the need to +import a font asset first then assign it. + +1. Open an existing **Font** asset or create a new one using the **Add New** button in the Content Browser. + + ![](Import5.png)(w:600) + +1. Click the **Add Font** button to add a new font selection to the **Default Font Family**. + + ![](Import6.png)(w:500) + +1. Select the **folder** button next to the selection dropdown. + + ![](Import7.png)(w:500) + +1. After the **Import** dialog box appears, navigate to the TFF or OTF font file you want to import and select it. Then, click **Open**. + + ![](Import2.png)(w:500) + +1. Next, the **Save Font Face** window will appear. Give your font a name and choose the save location in your game folder's hierarchy. Then, click **Save**. + + ![](Import8.png)(w:500) + +1. The Font Face asset can now be found in your folder hierarchy. + + ![](Import3a.png) + +## End Result + +Now that you've seen how to import using the various methods, you should be able to import your own font files using any one of these options for use in your games and projects. + diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/ImportingFonts/ImportingFonts.JPN.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/ImportingFonts/ImportingFonts.JPN.udn new file mode 100644 index 000000000000..97e4d2ad15a6 --- /dev/null +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/ImportingFonts/ImportingFonts.JPN.udn @@ -0,0 +1,105 @@ +INTSourceChangelist:3403467 +Availability:Public +crumbs: +Title:フォントのインポート +Description:Font アセットをインポートして UE4 で使用する方法を説明します。 +Type:How-to +SkillLevel:Beginner +Version:4.15 +Parent:Engine/UMG/UserGuide/Fonts/Howto +Related:Engine/UMG/UserGuide/Fonts +Related:Engine/UMG/UserGuide/Fonts/HowTo/CreatingFonts +Related:Engine/UMG/UserGuide/Fonts/HowTo/FontsWithUMG +Order:1 +Tags:UMG UI Designer +topic-image:ImportingFonts_Topic.png + +このガイドではフォント ファイルを UE4 にインポートする方法を説明します。 + +[REGION:raw] +![](ImportFonts_Hero.png)(w:800) +[/REGION] + +フォントのインポートを開始する場合、複数の方法があるのでご自分のワークフローに最適なものから選んでください。インポートに使用できる方法は以下のとおりです。 + +* コンテンツ ブラウザのインポート ボタンを使う +* コンテンツ ブラウザにドラッグ&ドロップする +* フォント エディタを使用する + +フォント インポート時に、**TrueType Font** (TTF) ファイルと **OpenType Font** (OTF) ファイルの選択肢もあります。ニーズに応じて最適なインポート方法とフォントの種類を選んでください。 + + +[REGION:note] +この操作ガイドでは **スターターコンテンツを含まない** を有効にした状態で、デフォルトの **Target Hardware** と **Project Settings** を使います。 +[/REGION] + +## コンテンツ ブラウザを使用する + +コンテンツ ブラウザの **[Import]** ボタンを使って TTF または OTF のフォントファイルを選択することができます。 + +1. コンテンツ ブラウザ で **[Import]** ボタンをクリックします。 + + ![](Import1.png) + +1. **[Import]** ダイアログ ボックスが表示されたら、インポートする TFF または OTF のフォント ファイルに移動し、選択します。**[Open]** をクリックします。 + + ![](Import2.png)(w:500) + +1. しばらくすると、**[Font Face Import Options]** ダイアログが表示されます。コンテンツ ブラウザで Font Face アセットと Composite Font アセットを作成するには、表示されているオプションから、**Yes** を選択します。 + + ![](Import3.png)(w:500) + +1. これで Font Face アセットがフォルダの階層に入ります。 + +![](Import3a.png) + + +## ドラッグ&ドロップを使用する + +TTF ファイルまたは OTF ファイルをコンテンツ ブラウザに直接 **ドラッグ & ドロップ** し、フォント アセットを作成することもできます。 + +1. TTF ファイルまたは OTF ファイルを保存した場所に移動します。ファイルを選択して **コンテンツ ブラウザ** までドラッグしてインポート プロセスを開始します。 + + ![](Import4.png)(w:650) + +1. しばらくすると、**[Font Import Options]** が表示されます。コンテンツ ブラウザで Font Face アセットと Composite Font アセットを作成するには、表示されているオプションから、**Yes** を選択します。 + + ![](Import3.png)(w:500) + +1. これで Font Face アセットがフォルダの階層に入ります。 + + ![](Import3a.png) + +## フォント エディタを使用する + +**フォント エディタ** の [Default Font Family] (Engine/UMG/UserGuide/Fonts/Overview#defaultfontfamily) リストから Font Face アセットを直接インポートして作成することができます。 +これで、最初にフォント アセットをインポートしてから割り当てる必要がなくなります。 + +1. 既存の **Font** アセットを開くか、コンテンツ ブラウザの **[Add New (新規追加)]** ボタンを使用して、新しいアセットを作成します。 + + ![](Import5.png)(w:600) + +1. デフォルトのフォント ファミリーに新しいフォントを追加するには、**[Add Font]** ボタンをクリックします。 + + ![](Import6.png)(w:500) + +1. 選択のドロップダウンの隣にある **[folder]** ボタンを選択します。 + + ![](Import7.png)(w:500) + +1. **[Import]** ダイアログ ボックスが表示されたら、インポートする TFF または OTF のフォント ファイルに移動し、選択します。**[Open]** をクリックします。 + + ![](Import2.png)(w:500) + +1. 続いて **[Save Font Face]** ウィンドウが表示されます。フォントに名前を付けてゲーム フォルダの階層で保存場所を選択します。**[Save (保存)]** をクリックします。 + + ![](Import8.png)(w:500) + +1. これで Font Face アセットがフォルダの階層に入ります。 + + ![](Import3a.png) + +## 最終結果 + +様々な方法でフォント ファイルをインポートする方法を説明しました。ゲームやプロジェクトでこうした方法のいずれかを使用してください。 + diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/ImportingFonts/ImportingFonts.KOR.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/ImportingFonts/ImportingFonts.KOR.udn new file mode 100644 index 000000000000..40f9489f3707 --- /dev/null +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/HowTo/ImportingFonts/ImportingFonts.KOR.udn @@ -0,0 +1,104 @@ +INTSourceChangelist:3403467 +Availability: Public +crumbs: +Title: 폰트 임포트 +Description: 언리얼 엔진 4 에서 사용할 폰트 애셋을 임포트하는 방법을 안내해 드립니다. +Type: How-to +SkillLevel: Beginner +Version: 4.15 +Parent: Engine/UMG/UserGuide/Fonts/Howto +Related: Engine/UMG/UserGuide/Fonts +Related: Engine/UMG/UserGuide/Fonts/HowTo/CreatingFonts +Related: Engine/UMG/UserGuide/Fonts/HowTo/FontsWithUMG +Order:1 +Tags: UMG UI Designer +topic-image:ImportingFonts_Topic.png + +여기서는 언리얼 엔진 4 에 폰트 파일을 임포트하는 법을 배워봅니다. + +[REGION:raw] +![](ImportFonts_Hero.png)(w:800) +[/REGION] + +폰트 임포트를 시작할 때, 여러가지 메소드 중 작업방식에 가장 잘 맞는 메소드를 선택할 수 있습니다. 사용할 수 있는 임포트 메소드는 다음과 같습니다: + +* 콘텐츠 브라우저의 임포트 버튼 +* 콘텐츠 브라우저에 드래그 앤 드롭 +* 폰트 에디터 사용 + +또한 폰트 임포트 시 **TrueType Font** (TTF) 와 **OpenType Font** (OTF) 파일 중에서 선택할 수 있습니다. 필요에 따라 가장 적합한 임포트 메소드와 폰트 유형을 선택하세요. + + +[REGION:note] +여기서는 **공백 템플릿** 프로젝트에 **시작용 콘텐츠** 은 없으며, 기본 **타겟 하드웨어** 및 **프로젝트 세팅** 을 사용하고 있습니다. +[/REGION] + +## 콘텐츠 브라우저 사용 + +콘텐츠 브라우저의 **임포트** 버튼을 사용하여 TTF 또는 OTF 폰트 파일을 선택하면 됩니다. + +1. 콘텐츠 브라우저에서 **임포트** 버튼을 클릭합니다. + + ![](Import1.png) + +1. **임포트** 대화창이 뜨면, 임포트하고자 하는 TTF 또는 OTF 폰트 파일을 선택한 뒤 **열기** 를 클릭합니다. + + ![](Import2.png)(w:500) + +1. 잠시 후 **Font Face Import Options** (폰트 페이스 임포트 옵션) 대화창이 뜹니다. 나열된 옵션에서 **예** 를 선택하면 콘텐츠 브라우저에 폰트 페이스 애셋과 컴포짓 폰트 애셋이 생성됩니다. + + ![](Import3.png)(w:500) + +1. 이제 폴더 계층구조에서 폰트 페이스 애셋을 찾을 수 있습니다. + + ![](Import3a.png) + + +## 드래그 앤 드롭 사용 + +콘텐츠 브라우저에 TTF 또는 OTF 파일을 바로 드래그 앤 드롭하여 폰트 애셋을 만들 수 있습니다. + +1. TTF 또는 OTF 파일이 저장된 폴더로 이동합니다. 파일을 선택한 후 끌어 **콘텐츠 브라우저** 에 놓으면 임포트 프로세스가 시작됩니다. + + ![](Import4.png)(w:650) + +1. 잠시 후 **Font Import Options** (폰트 임포트 옵션)이 나타납니다. 나열된 옵션에서 **Yes** (예)를 선택하면 콘텐츠 브라우저에 폰트 페이스 애셋 및 컴포짓 폰트 애셋이 생성됩니다. + + ![](Import3.png)(w:500) + +1. 이제 폴더 계층구조에서 폰트 페이스 애셋을 찾을 수 있습니다. + + ![](Import3a.png) + +## 폰트 에디터 사용 + +**폰트 에디터** 의 [Default Font Family](Engine/UMG/UserGuide/Fonts/Overview) 리스트에서 폰트 페이스 애셋을 바로 임포트 및 생성 가능하므로 +먼저 폰트 애셋을 임포트한 뒤 할당해 줄 필요가 없습니다. + +1. 기존 **폰트** 애셋을 열거나 콘텐츠 브라우저의 **신규 추가** 버튼으로 새로 만듭니다. + + ![](Import5.png)(w:600) + +1. **폰트 추가** 버튼을 클릭하여 새로운 폰트 선택을 **디폴트 폰트 패밀리** 에 추가합니다. + + ![](Import6.png)(w:500) + +1. 선택 드롭다운 옆 **폴더** 버튼을 선택합니다. + + ![](Import7.png)(w:500) + +1. **임포트** 대화창이 뜨면, 임포트하고자 하는 TTF 또는 OTF 폰트 파일로 이동하여 선택한 뒤 **열기** 를 클릭합니다. + + ![](Import2.png)(w:500) + +1. 다음, **폰트 페이스 저장** 창이 뜹니다. 폰트에 이름을 짓고 게임 폴더 계층구조에 저장 위치를 선택한 뒤 **저장** 을 클릭합니다. + + ![](Import8.png)(w:500) + +1. 이제 폴더 계층구조에서 폰트 페이스 애셋을 찾을 수 있습니다. + + ![](Import3a.png) + +## 최종 결과 + +다양한 메소드를 통해 임포트하는 방법을 살펴봤으니, 이 방법 중 하나를 통해 직접 게임이나 프로젝트에 사용할 폰트 파일을 임포트할 수 있을 것입니다. diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Materials/FontMaterialsAndOutlines.INT.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Materials/FontMaterialsAndOutlines.INT.udn index e83ec7d4deb9..70c395c48127 100644 --- a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Materials/FontMaterialsAndOutlines.INT.udn +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Materials/FontMaterialsAndOutlines.INT.udn @@ -7,9 +7,13 @@ Related: Engine/UMG/UserGuide/Fonts Related: Engine/UMG/UserGuide/Styling Version: 4.14 Parent: Engine/UMG/UserGuide/Fonts -order: 1 +type: Overview +Skilllevel:Beginner +order: 2 tags: User Interface tags:UMG UI Designer +tags: Fonts +Topic-image:FontMaterials_Topic.png [TOC] diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Materials/FontMaterialsAndOutlines.JPN.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Materials/FontMaterialsAndOutlines.JPN.udn index 2a0e02ba9f60..96d19e0e8eb5 100644 --- a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Materials/FontMaterialsAndOutlines.JPN.udn +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Materials/FontMaterialsAndOutlines.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3244089 +INTSourceChangelist:3394420 Availability:Public Title:フォントのマテリアルとアウトライン Description:色、マテリアル、アウトラインを使って UMG にスタイルを適用する方法例を示します。 @@ -8,9 +8,13 @@ Related:Engine/UMG/UserGuide/Fonts Related:Engine/UMG/UserGuide/Styling Version:4.14 Parent:Engine/UMG/UserGuide/Fonts -order:1 +type:Overview +Skilllevel:Beginner +order:2 tags:User Interface tags:UMG UI Designer +tags:Fonts +Topic-image:FontMaterials_Topic.png [TOC] diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Materials/FontMaterialsAndOutlines.KOR.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Materials/FontMaterialsAndOutlines.KOR.udn index 2f5b51c99a49..d9dcf58df32b 100644 --- a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Materials/FontMaterialsAndOutlines.KOR.udn +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Materials/FontMaterialsAndOutlines.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3244089 +INTSourceChangelist:3394420 Availability:Public Title: 폰트 머티리얼 및 윤곽선 Description:색, 머티리얼, 윤곽선을 사용하여 UMG 폰트의 스타일을 잡는 방법에 대한 예제입니다. @@ -8,9 +8,13 @@ Related: Engine/UMG/UserGuide/Fonts Related: Engine/UMG/UserGuide/Styling Version: 4.14 Parent: Engine/UMG/UserGuide/Fonts -order: 1 +type: Overview +Skilllevel:Beginner +order: 2 tags: User Interface tags:UMG UI Designer +tags: Fonts +Topic-image:FontMaterials_Topic.png [TOC] diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Overview/FontsOverview.CHN.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Overview/FontsOverview.CHN.udn new file mode 100644 index 000000000000..334395236667 --- /dev/null +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Overview/FontsOverview.CHN.udn @@ -0,0 +1,159 @@ +INTSourceChangelist:3401632 +Availability:Public +Title:字体资源和编辑器 +Crumbs:%ROOT%, Engine, Engine/UMG, Engine/UMG/UserGuide +Description:详细说明字体风格和字体资源,以及字体编辑器的诸多功能。 +Parent:Engine/UMG/UserGuide/Fonts +Related:Engine/UMG +Related:Engine/UMG/UserGuide/Fonts/HowTo +Related:Engine/UMG/UserGuide/WidgetBlueprints +Related:Engine/UMG/UserGuide/WidgetTypeReference +Version:4.16 +type:overview +order:1 +tags:UMG UI Designer +Tags:Fonts +topic-image:FontOverview_Topic.png +SkillLevel:Beginner + +[TOC(start:2 end:2)] + +此页面包含可用于 **字体编辑器** 的 **字体** 和 **字体风格** 资源。 + +## 字体资源 + +虚幻引擎 4 中的字体被分类为 **字体** 资源,使用两种缓存方法:**Runtime** 的形式是合成字体;**Offline** 是更古老的预计算字体图谱法。在字体编辑器中打开字体资源后即可在两种方法之间切换(无需替换即可简单将现有字体资源从 Offline 转换到新合成方法)。 + +## 字体风格(Font Face)资源 + +导入字体时便会创建 **字体风格** 资源,它将保存可被字体资源引用的字体数据。这意味着相同的字体数据可在多个字体资源之间交替使用,甚至与资源中的多个字型共用,最终减少内存消耗。 + +![](FontFaceWindow.png)(w:600) + +打开字体风格资源时,可访问 **Hinting** 和 **Loading Policy** 的设置。 + +[REGION:simpletable] +| 属性 | 描述 | +| --- |--- | +| **Source File Name** | 所创建字体风格的文件名。这不会固定保存在磁盘中,因为我们之前可能已在此资源中加载和缓存字体数据。| +| **Hinting** | 字体风格所使用的微调算法。[INCLUDE:#hinting] | +| **Loading Policy** | 控制此字体风格运行时加载方式的枚举。查看枚举获得选项的更多解释。[INCLUDE:#loadingpolicy]| +| **Layout Method** | 此项将选择字体布局时所使用的方法。如字体出现裁剪或高度问题,可尝试对此项进行修改。[INCLUDE:#layoutmethod] | +[/REGION] + + + +## 将字体资源更新至 4.15 及更新版本 + +从虚幻引擎 4.15 版本开始,字体资源现已被拆分为两个单独的资源,字体和字体风格。现有的字体资源在加载中会更新其内部字体数据到内置的字体风格资源中,但不会对它们进行自动拆分。需要打开字体编辑器,在字体群里的条目下选择 **Upgrade Data**。此操作使用户能编辑这些资源,并与创建的其他字体资源共享这些资源。 + +![](FontUpgradeData.png)(w:175) + +点击 **Upgrade Data** 后,将弹出保存新字体风格资源的提示。 + + +## 字体编辑器 + +在 **Content Browser** 中双击字体资源后,它将在 **字体编辑器** 窗口中打开。 + +![](FontEditorWindow.png)(w:820) + +字体编辑器窗口详解如下: + +#### 工具栏菜单 + +![](ToolbarMenu.png)(w:550) + +可在此菜单中保存修改、在 **Content Browser** 中查找资源,在预览窗口中变更预览窗口(4)背景颜色或前景颜色(文本颜色)。有更新或导出正在进行修改的选项,然而这些选项只在 **离线** 缓存模式中可用。 + +(#defaultfontfamily) +#### 默认字体群 + +![](DefaultFontFamily.png)(w:550) + +用户可在此窗口中指定此字体资源使用的默认字体群。用户可添加特定字体风格的多个版本(如常规、粗体、斜体、下划线等),或将不同字体风格的合集设为一个合成字体。如已创建一个空白字体,则也可从此窗口中指定字体。 + +#### 子字体群 + +![](AddSubFontFamily.png)(h:50) + +在此窗口中点击 **Add Sub-Font Family** 按钮即可指定此字体资源所使用的子字体群。 + +[![](SubFontFamily.png)(w:550)](SubFontFamily.png) + +可在此处指定字符范围。进入此字符范围后将指定不同于默认字体的另一种字体。这在需要为不同语言使用不同字体类型时十分实用。 + + +#### 预览 + +![](Preview.png) + +此窗口可预览字体,并提供一个文本输入框以便输入范例文本。 + +#### Draw For Metrics + +![](PreviewDrawFontMetrics.png) + +**Draw Font Metrics** 将覆盖行高、字形边界框,和作为预览一部分的的基线。 + +* **Base Line** - 这是文本所处的线。 +* **Line Bounds** - 这是为给定文本字符串长度所创建的边界框。 +* **Grapheme Cluster Bounds** - 此边界框沿给定语言中的逻辑字符而绘制,可能由数个字形组成(例如一个基础字符和重音符号)。 +* **Glyph Bounds** - 这是沿给定字形绘制的边界框。 + +#### 详情 + +![](Details.png)(w:500) + +可在此创库中修改 Font Cache Type,以及 Font Size 和 Font Name(针对运行时)。 +* 如使用旧方法,在 Offline 缓存模式中仍然可以修改字体的参数。 +* 也可将现有字体资源从 **Offline** 转换为 **Runtime**,无需进行替换。 + +## 范例字体资源 + +范例字体资源显示如下。 + +[REGION:lightbox] +[![](ExampleFontLayout.png)(w:820)](ExampleFontLayout.png) +[/REGION] + +_点击查看全图。_ + +合成字体固定包含一个默认字体群,也可能包含任意数量用于给定字符范围的子字体群。每个字体群其自身由任意数量的字体风格组成(这些字体风格可基于其风格进行命名)。运行时每个字符将使用字体群中该字符范围最适合的字体(基于可用字体)。 + +如上图范例所示,日语文本属于日语字体群的字符范围中,因此使用源 Han Sans 进行绘制,而不以默认字体群(Roboto)进行绘制。子字体群中的字体优先按命名匹配选择。而常规体、粗体和细体也会基于默认字体的属性进行匹配,粗斜体同样如此(其自动选择日语粗体,因为字体包含加粗属性)。 + + + + diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Overview/FontsOverview.INT.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Overview/FontsOverview.INT.udn new file mode 100644 index 000000000000..6f9ab2bb5220 --- /dev/null +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Overview/FontsOverview.INT.udn @@ -0,0 +1,167 @@ +Availability:Public +Title: Font Asset and Editor +Crumbs:%ROOT%, Engine, Engine/UMG, Engine/UMG/UserGuide +Description: Details the Font Face and Font assets, along with covering the Font Editors various features. +Parent: Engine/UMG/UserGuide/Fonts +Related: Engine/UMG +Related: Engine/UMG/UserGuide/Fonts/HowTo +Related: Engine/UMG/UserGuide/WidgetBlueprints +Related: Engine/UMG/UserGuide/WidgetTypeReference +Version: 4.16 +type:overview +order: 1 +tags:UMG UI Designer +Tags: Fonts +topic-image:FontOverview_Topic.png +SkillLevel:Beginner + +[TOC(start:2 end:2)] + +This page covers the **Font** and **Font Face** asset types that can be used with the **Font Editor**. + +## Font Assets + +Fonts in Unreal Engine 4 are categorized as a **Font** asset and use two caching methods, **Runtime** which is in the form of a Composite Font or **Offline** which is the older +pre-computed Font Atlas method. You can switch between the two methods by opening up a Font asset in the Font Editor (this provides a simple way to convert existing Font assets +from Offline to the new composite method without having to replace them). + +## Font Face Assets + +The **Font Face** asset is created when you import a font and it stores the font data that can be referenced by the Font asset. This means that the same font data can be reused across +multiple Font assets or even with multiple typefaces within the asset, and ultimately reduces memory consumption. + +![](FontFaceWindow.png)(w:600) + +When you open your Font Face Asset, you have access to the settings for **Hinting** and **Loading Policy**. + +[REGION:simpletable] +| Property | Description | +| --- |--- | +| **Source File Name** | The filename of the font face we were created from. This may not always exist on disk, as we may have previously loaded and cached the font data inside this asset. | +| **Hinting** | The hinting algorithm to use with the font face. [INCLUDE:#hinting] | +| **Loading Policy** | Enum controlling how this font face should be loaded at runtime. See the enum for more explanations of the options. [INCLUDE:#loadingpolicy]| +| **Layout Method** | This selects the method to use when laying out the font. Try changing this if you notice clipping or height issues with your font. [INCLUDE:#layoutmethod] | +[/REGION] + + + +## Upgrading Font Assets to 4.15 and Later + +Starting with Unreal Engine 4.15, Font assets have now been split into two separate assets, Font and Font Faces. Existing Font assets will upgrade their internal font data into +embedded Font Face assets during load, but will not automatically split them. You will have to do this by opening the Font Editor and selecting **Upgrade Data** under the entries within your font families. +This will enable you to edit and share these assets with other Font assets that you've created. + +![](FontUpgradeData.png)(w:175) + +After you click **Upgrade Data**, you will be prompted to save the new Font Face asset. + + +## Font Editor + +When you double-click on a Font asset in the **Content Browser**, it will open up inside of the **Font Editor** window. + +![](FontEditorWindow.png)(w:820) + +A breakdown of the Font Editor Window is presented below: + +#### Toolbar Menu + +![](ToolbarMenu.png)(w:550) + +From this menu, you can save any changes you make, find the asset in the **Content Browser**, change the Background Color of the preview window (4) or +the Foreground Color (text color) in the preview window. There are options for Updating or Exporting changes being made, however, these options are only available +within the **Offline** cache mode. + +#### Default Font Family + +![](DefaultFontFamily.png)(w:550) + +In this window, you can assign the Default Font Family for use with this Font asset. You can add versions of a particular Font style (for example Normal, +Bold, Italics, Underline, etc.) or have a collection of different Font styles as one Composite Font. If you have created a blank Font asset, you can assign +a font from inside this window as well. + +#### Sub-Font Family + +![](AddSubFontFamily.png)(h:50) + +In this window, when you click the **Add Sub-Font Family** button, you can assign the Sub-Font Family for this Font asset to use. + +[![](SubFontFamily.png)(w:550)](SubFontFamily.png) + +Here, you can specify a Character Range, and if a character entered falls within the range, you can specify a different Font style +to use instead of the Default. This is useful for when you want to use different Font types for different languages. + + +#### Preview + +![](Preview.png) + +This window allows you to preview your fonts and provides a text entry box for entering sample texts. + +#### Draw For Metrics + +![](PreviewDrawFontMetrics.png) + +The **Draw Font Metrics** toggle will overlay the line height, glyph bounding boxes, and base-line as part of the preview. + +* **Base Line** - This is the line in which the text sits. +* **Line Bounds** - This is the bounding box created for the length of the given text string. +* **Grapheme Cluster Bounds** - This is the bounding box drawn around what is considered a logical character in a given language, and may be comprised of several glyphs (for example, a base character and accent glyph). +* **Glyph Bounds** - This is the bounding box drawn around the given glyph. + +#### Details + +![](Details.png)(w:500) + +In this window, you can change the Font Cache Type as well as change the Font Size and Font Name (for Runtime). +* If you are using the older method, you can still change the parameters for your Font while in Offline cache mode. +* You can also convert any existing Font assets from **Offline** to **Runtime** without having to replace them. + +## Example Font Asset + +An example Font asset is shown below. + +[REGION:lightbox] +[![](ExampleFontLayout.png)(w:820)](ExampleFontLayout.png) +[/REGION] + +_Click image for a full view._ + +A Composite Font will always contain a Default Font Family, and may also contain any number of Sub-Font Families that should be used for a given range of characters. Each Font Family is itself made up of any number of Font Faces that can be named based on their style. At runtime, the most suitable Font to use for each character (based on the Fonts available) in the Font Family for that character range is used. + +As seen in the example image above, the Japanese text falls within the character ranges of the Japanese font family, and therefore, is drawn using Source Han Sans rather than the Default Font Family (Roboto). Fonts in a Sub-Font Family are preferably chosen by name match, as in the case of Regular, Bold, and Light, however they can also fallback to matching based on the attributes of the Default Font, as is the case with Bold Italic (it automatically chose the Bold Japanese font because the font contained the Bold attribute). + + + + diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Overview/FontsOverview.JPN.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Overview/FontsOverview.JPN.udn new file mode 100644 index 000000000000..29d7ee3098fc --- /dev/null +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Overview/FontsOverview.JPN.udn @@ -0,0 +1,168 @@ +INTSourceChangelist:3401632 +Availability:Public +Title:Font アセット エディタ +Crumbs:%ROOT%, Engine, Engine/UMG, Engine/UMG/UserGuide +Description:フォント エディタの様々な機能と共に Font Face と Font のアセットについて詳しく説明します。 +Parent:Engine/UMG/UserGuide/Fonts +Related:Engine/UMG +Related:Engine/UMG/UserGuide/Fonts/Howto +Related:Engine/UMG/UserGuide/WidgetBlueprints +Related:Engine/UMG/UserGuide/WidgetTypeReference +Version:4.16 +type:overview +order:1 +tags:UMG UI Designer +Tags:Fonts +topic-image:FontOverview_Topic.png +SkillLevel:Beginner + +[TOC(start:2 end:2)] + +このページでは、**フォント エディタ** で使用できる **Font** と **Font Face** のアセットのタイプについて説明します。 + +## Font アセット + +UE4 のフォントは **Font** アセットとして分類され、 2 種類のキャッシング方法を使用します。**ランタイム** は、コンポジット フォントの形式をとります。**オフライン** は、 +事前計算された古いフォント アトラス方式です。フォント エディタで Font アセットを開くことで、この 2 つの方式を切り替えることができます (これはオフラインの既存のフォント アセットを置き換える必要なく +新しいコンポジット方式に変換する簡単な方法です)。 + +## Font Face アセット + +**Font Face** アセットは、フォント インポート時に作成され、Font アセットが参照できるフォント データを保存します。つまり、同じフォント データを複数のフォント アセットで再利用することができます。 +さらに、ひとつの Font アセット内で複数の書体を再利用することもできます。その結果、メモリ消費を減らします。 + +![](FontFaceWindow.png)(w:600) + +Font Face アセットを開くと、**[Hinting]** と **[Loading Policy]** の設定にアクセスすることができます。 + +[REGION:simpletable] +| プロパティ | 説明 | +| --- |--- | +| **Source File Name** | 書体の作成元のファイル名です。必ずしもディスク上にありません。フォント データを過去にロードして、このアセット内にキャッシュしたかもしれないからです。 | +| **Hinting** | 書体と合わせて使うヒント アルゴリズムです。 [INCLUDE:#hinting] | +| **Loading Policy** | ランタイムにこうした書体がどのようにロードされるかを制御する列挙型変数です。オプションの詳細説明については、列挙型変数をご覧ください。 [INCLUDE:#loadingpolicy]| +| **Layout Method** | フォントをレイアウトする場合に使う方法を選択します。フォントでクリッピングや高さの問題が生じたら、これを使ってみてください。[INCLUDE:#layoutmethod] | +[/REGION] + + + +## Font アセットを 4.15 以降にアップグレード + +アンリアル エンジン 4.15 から Font アセットは、Font と Font Faces という 2 つのアセットに分かれました。ロード中に既存の Font アセットはその内部フォントデータを、埋め込まれた Font Face アセットに自動的にアップグレードします。 +しかし、自動的にそれらを分割はしません。これを行うには、Font エディタを開き、フォント ファミリー内のエントリーで **Upgrade Data** を選択します。 +これらのアセットを編集したり、作成した他の Font アセットと共有できるようになります。 + +![](FontUpgradeData.png)(w:175) + +**[Upgrade Data]** をクリックすると、新しい Font Face アセットを保存するように促されます。 + + +## フォント エディタ + +**[コンテンツ ブラウザ]** でフォント アセットをダブルクリックすると、**フォント エディタ** ウィンドウ内でそのフォント アセットが開きます。 + +![](FontEditorWindow.png)(w:820) + +以下は Font Editor ウィンドウの各部を示したものです。 + +#### ツールバー メニュー + +![](ToolbarMenu.png)(w:550) + +加えた変更を保存し、**[コンテンツ ブラウザ]** でアセットを見つけ、プレビュー ウィンドウの背景色を変更したり、 +文字の表示色 (テキスト カラー) を変更することができます。加えられている変更を更新またはエクスポートするオプションがあります。しかし、こうしたオプションは +**オフライン** キャッシュ モード内でのみ利用可能です。 + +#### Default Font Family + +![](DefaultFontFamily.png)(w:550) + +このウィンドウでは Font アセットと合わせて使用するデフォルト フォント ファミリーを指定することができます。特定のフォント スタイルのバージョンを追加したり (例えば、標準、太字、イタリック、アンダーラインなど)、 +ひとつのコンポジット フォントとして様々なフォント スタイルのコレクションを持つことができます。ブランクの Font アセットを作成したらこのウィンドウ内からフォントを +指定することもできます。 + +#### Sub-Font Family + +![](AddSubFontFamily.png)(h:50) + +このウィンドウでは、 **[Add Sub-Font Family]** ボタンをクリックすると、Font アセットが使用するサブフォント ファミリーを指定することができます。 + +[![](SubFontFamily.png)(w:550)](SubFontFamily.png) + +ここでは、文字範囲 (Character Range) を指定し、入力した文字がこの範囲に入ったらデフォルトの代わりに +別のフォント スタイルを指定することができます。これは異なる言語で様々なフォント タイプを使用したい場合に役立ちます。 + + +#### Preview + +![](Preview.png) + +このウィンドウでは、フォントをプレビューすることが可能であり、サンプル テキストを入力するためのテキスト エントリ ボックスがあります。 + +#### Draw Font Metrics + +![](PreviewDrawFontMetrics.png) + +**Draw Font Metrics** を切り替えるとは、ラインの高さ、グリフのバウンディング ボックス、ベース ラインをプレビューでオーバーレイ表示します。 + +* **Base Line** - テキストが入るラインです。 +* **Line Bounds** - 任意のテキスト文字列の長さに対して作られたバウンディング ボックスです。 +* **Grapheme Cluster Bounds** - 任意の言語で論理文字とみなされる物の回りに描画されるバウンディング ボックスです。いくつかのグリフを含むことがあります (例、基本文字とアクセントのグリフ)。 +* **Glyph Bounds** - 任意のグリフ周囲に描画されるバウンディング ボックスです。 + +#### Details + +![](Details.png)(w:500) + +このウィンドウではフォント キャッシュ タイプ、フォント サイズ、フォント名 (ランタイム用) を変更することができます。 +* 古い方式を使用している場合は、オフライン キャッシュ モードでフォントのパラメータを変更することができます。 +* 既存のフォント アセットを置き換えることなく **オフライン** から **ランタイム** に変換できます。 + +## Font アセットの例 + +以下は Font アセットの例です。 + +[REGION:lightbox] +[![](ExampleFontLayout.png)(w:820)](ExampleFontLayout.png) +[/REGION] + +_画像をクリックして全画面表示にします。_ + +コンポジット フォントには常にデフォルト フォント ファミリーが含まれます。任意の文字範囲で使用するサブフォント ファミリーをいくつでも含むことができます。各フォント ファミリー自体は、スタイルに基づいて命名できる任意の数の Font Face から構成されます。ランタイムには、その文字範囲に対してフォント ファミリーで (利用可能なフォントに基づき) 各文字に最適なフォントが使用されます。 + +上の画像でわかるように、日本語のテキストは日本語フォント ファミリーの文字範囲にあります。そのため、デフォルト フォント ファミリー (Roboto) ではなく Source Han Sans を使用して描画されます。サブフォント ファミリーのフォントは Regular、Bold、および Light の場合と同様に名前の一致によって選択されるのが理想的です。しかし、Bold Italic のようにデフォルト フォントの属性に基づきマッチするようにフォールバックすることもできます (自動的に太字の日本語フォントが選択されます。このフォントには、太字属性が含まれていたからです)。 + + + + diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Overview/FontsOverview.KOR.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Overview/FontsOverview.KOR.udn new file mode 100644 index 000000000000..82dd96134a2a --- /dev/null +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/Fonts/Overview/FontsOverview.KOR.udn @@ -0,0 +1,168 @@ +INTSourceChangelist:3401632 +Availability:Public +Title: 폰트 애셋 및 에디터 +Crumbs:%ROOT%, Engine, Engine/UMG, Engine/UMG/UserGuide +Description: 폰트 페이스와 폰트 애셋, 폰트 에디터의 다양한 기능에 대해 다룹니다. +Parent: Engine/UMG/UserGuide/Fonts +Related: Engine/UMG +Related: Engine/UMG/UserGuide/Fonts/HowTo +Related: Engine/UMG/UserGuide/WidgetBlueprints +Related: Engine/UMG/UserGuide/WidgetTypeReference +Version: 4.16 +type:overview +order: 1 +tags:UMG UI Designer +Tags: Fonts +topic-image:FontOverview_Topic.png +SkillLevel:Beginner + +[TOC(start:2 end:2)] + +이 글에서는 **폰트 에디터** 에서 사용할 수 있는 **Font** (폰트) 및 **Font Face** (폰트 페이스) 애셋 유형에 대해 다룹니다. + +## 폰트 애셋 + +언리얼 엔진 4 의 폰트는 **Font** (폰트) 애셋으로 분류되며, 두 가지 캐시 메소드를 사용합니다. 하나는 **Runtime** (런타임)의 Composite Font (합성 폰트) 형태이며, 다른 하나는 **Offline** (오프라인)의 예전 미리 계산하는 Font Atlas (폰트 아틀라스) 메소드입니다. +폰트 에디터에서 폰트 애셋을 열어 두 메소드 사이 전환이 가능합니다 (기존 폰트 애셋을 대체할 필요 +없이 오프라인 메소드에서 새로운 합성 메소드로 간단히 전환할 수 있습니다). + +## 폰트 페이스 애셋 + +**Font Face** (폰트 페이스) 애셋은 폰트를 임포트할 때 생성되며, 폰트 애셋에서 레퍼런싱할 수 있는 폰트 데이터를 저장합니다. 즉 같은 폰트 데이터를 여러 폰트 애셋, +심지어 애셋 내 여러 타입 페이스에도 재사용하여 궁극적으로 메모리 사용량을 줄일 수 있다는 뜻입니다. + +![](FontFaceWindow.png)(w:600) + +폰트 페이스 애셋을 열면 **Hinting** (힌팅) 및 **Loading Policy** (로딩 정책) 세팅에 접근할 수 있습니다. + +[REGION:simpletable] +| 프로퍼티 | 설명 | +| --- |--- | +| **Source File Name** | 이 폰트 페이스를 기준으로 생성합니다. 항상 디스크에 존재하지는 않을 수 있는데, 기존에 이 애셋 안에 폰트 데이터를 로드하고 캐시했을 수 있기 때문입니다. | +| **Hinting** | 폰트 페이스에 사용할 힌팅 알고리즘입니다. [INCLUDE:#hinting] | +| **Loading Policy** | 런타임에 이 폰트 페이스를 어떻게 로드할지 결정하는 enum 입니다. 옵션 관련 자세한 설명은 enum 부분을 확인하세요. [INCLUDE:#loadingpolicy]| +| **Layout Method** | 폰트 레이아웃에 사용할 메소드를 선택합니다. 폰트가 잘리거나 높이 문제가 있는 경우 이 옵션을 변경해 보세요. [INCLUDE:#layoutmethod] | +[/REGION] + + + +## 폰트 애셋을 4.15 이후로 업그레이드 + +언리얼 엔진 4.15 이후 폰트 애셋은 Font (폰트)와 Font Face (폰트 페이스), 두 개의 애셋으로 분리되었습니다. 기존 폰트 애셋은 로드 도중 내부 폰트 데이터를 +삽입된 폰트 페이스 애셋으로 업그레이드하지만, 자동 분리하지는 않습니다. 폰트 에디터에서 폰트 패밀리 내 항목 아래에서 **Upgrade Data** (데이터 업그레이드)를 선택하여 +직접 해줘야 합니다. + +![](FontUpgradeData.png)(w:175) + +**데이터 업그레이드** 선택 후 새로운 폰트 페이스 애셋을 저장하겠냐고 묻습니다. + + +## 폰트 에디터 + +**콘텐츠 브라우저** 에서 폰트 애셋을 더블클릭하면, **폰트 에디터** 창 안에서 열립니다. + +![](FontEditorWindow.png)(w:820) + +폰트 에디터 창에 대한 분석은 아래와 같습니다: + +#### 툴바 메뉴 + +![](ToolbarMenu.png)(w:550) + +이 메뉴에서는, 변경 내용을 저장하거나, **콘텐츠 브라우저** 에서 애셋을 찾거나, 프리뷰 창(4)의 배경색을 변경하거나, +프리뷰 창의 전경(텍스트)색을 변경할 수 있습니다. 변경 사항을 업데이트 또는 익스포트하는 옵션이 있지만, 이 옵션은 +**Offline** (오프라인) 캐시 모드에서만 사용 가능합니다. + +#### 기본 폰트 패밀리 + +![](DefaultFontFamily.png)(w:550) + +이 창에서는, 이 폰트 애셋에 사용할 기본 폰트 패밀리를 지정할 수 있습니다. 특정 폰트 스타일 버전을 추가하거나 (예를 들어 Normal, +Bold, Italics, Underline, 등.) 각기 다른 폰트 스타일 모음을 하나의 Composite Font (합성 폰트)로 만들 수도 있습니다. 공백 폰트 애셋을 생성했다면, +이 창 안에서 폰트를 할당할 수도 있습니다. + +#### 서브 폰트 패밀리 + +![](AddSubFontFamily.png)(h:50) + +이 창에서 **Add Sub-Font Family** (서브 폰트 패밀리 추가) 버튼을 클릭하면, 이 폰트 애셋이 사용할 서브 폰트 패밀리를 할당할 수 있습니다. + +[![](SubFontFamily.png)(w:550)](SubFontFamily.png) + +여기서 Character Range (글자 범위)를 지정하고, 어느 한 글자가 이 범위 안에 들어가면 기본 이외 다른 폰트 스타일을 사용하도록 지정할 수 있습니다. +각기 다른 언어마다 다른 폰트 유형을 사용하고자 할 때 좋습니다. + + +#### 프리뷰 + +![](Preview.png) + +이 창에서는 폰트를 미리볼 수 있으며, 샘플 텍스트 입력을 위한 글상자가 제공됩니다. + +#### 폰트 메트릭스 그리기 + +![](PreviewDrawFontMetrics.png) + +**Draw Font Metrics** (폰트 메트릭스 그리기)는 프리뷰의 일부로 선 높이, 글리프 바운딩 박스, 베이스 라인 오버레이 표시를 토글합니다. + +* **Base Line** - 베이스 라인은 텍스트가 놓이는 기준 선입니다. +* **Line Bounds** - 라인 바운드는 주어진 텍스트 스트링 길이에 대해 생성된 바운딩 박스입니다. +* **Grapheme Cluster Bounds** - 그래핌 클러스터(문자소군) 바운드는 주어진 언어의 논리적 글자로 간주되는 것 주변에 그리는 바운딩 박스로, 다수의 글리프 조합이 가능합니다 (예를 들어 기본 글자에 액센트 글리프). +* **Glyph Bounds** - 주어진 글리프 주변에 그리는 바운딩 박스입니다. + +#### 디테일 + +![](Details.png)(w:500) + +이 창에서는, Font Cache Type (폰트 캐시 유형) 변경은 물론 (런타임에) Font Size (폰트 크기)와 Font Name (폰트 이름)을 바꿀 수 있습니다. +* 예전 메소드를 사용중인 경우, Offline (오프라인) 캐시 모드에 있을 때도 여전히 폰트 파라미터를 변경할 수 있습니다. +* 기존 폰트 애셋을 대체할 필요 없이 **Offline** (오프라인)에서 **Runtime** (런타임)으로 전환할 수도 있습니다. + +## 예제 폰트 애셋 + +예제 폰트 애셋은 아래와 같습니다. + +[REGION:lightbox] +[![](ExampleFontLayout.png)(w:820)](ExampleFontLayout.png) +[/REGION] + +_클릭하면 이미지 원본을 확인합니다._ + +Composite Font (합성 폰트)는 항상 Default Font Family (기본 폰트 패밀리)를 포함하며, 주어진 글자 범위에 사용할 Sub-Font Family (서브 폰트 패밀리)를 몇이든 포함할 수도 있습니다. 각 폰트 패밀리 자체는 폰트 페이스를 몇 개로든 구성할 수 있으며, 스타일에 따라 이름을 붙일 수 있습니다. 런타임에 해당 글자의 폰트 패밀리 중 (사용가능한 폰트에 따라) 각 글자에 가장 적합한 폰트가 사용됩니다. + +위 예제 이미지에서 보듯, 일본어 텍스트는 일본어 폰트 패밀리 글자 범위 안에 해당하므로, Default Font Family (Roboto) 가 아닌 Source Han Sans 로 그립니다. 서브 폰트 패밀리의 폰트는 Regular, Bold, Light 등 일치하는 이름에 따라 선택되지만, Bold Italic 처럼 Default Font 특성에 따라 맞추기도 합니다 (폰트에 Bold 특성에 포함되어 있어서 자동으로 Bold Japanese 를 선택했습니다). + + + + diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/WidgetTypeReference/BackgroundBlur/BackgroundBlur.CHN.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/WidgetTypeReference/BackgroundBlur/BackgroundBlur.CHN.udn index c1a84667bd1f..8d7fc9181c06 100644 --- a/Engine/Documentation/Source/Engine/UMG/UserGuide/WidgetTypeReference/BackgroundBlur/BackgroundBlur.CHN.udn +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/WidgetTypeReference/BackgroundBlur/BackgroundBlur.CHN.udn @@ -1,42 +1,45 @@ -INTSourceChangelist:0 +INTSourceChangelist:3372539 Availability:Public -Title: Background Blur -Crumbs:%ROOT%, Engine, Engine/UMG, Engine/UMG/UserGuide, Engine/UMG/UserGuide/WidgetTypeReference -Description: Describes how to use the Background Blur Widget to blur objects beneath a single child widget. -Related: Engine/UMG/UserGuide -version: 4.15 +Title:背景模糊控件 +Crumbs:%ROOT% +Description:说明如何使用背景模糊控件将单个子控件下面的物体模糊。 +Related:Engine/UMG/UserGuide +version:4.15 tags:UMG UI Designer +Parent:Engine/UMG/UserGuide/WidgetTypeReference +Order: +Type:reference [TOC(start:2 end:2)] -## Description +##描述 [EXCERPT:desc] -This widget can contain one child widget, providing an opportunity to surround it with adjustable padding and apply a post-process Gaussian blur to all content beneath the widget. +**背景模糊控件** 包含一个子控件,能用可调填充将其包围,并将后期处理高斯模糊应用到控件下方的全部内容。 [/EXCERPT:desc] -## Details +## 详情 -In the **Details** panel for a placed **Background Blur** widget, there are a couple of specific options that can be set that pertain to the Widget: +在放置的 **Background Blur** 控件的 **Details** 面板中,可对从属于控件的几个特定选项进行设置: ![](BackgroundBlur.png) -| Option | Description | +| 选项 | 描述 | | -------- | ----------- | -| **Apply Alpha to Blur** | When true, this will modulate the strength of the blur based on the widget alpha. | -| **Blur Strength** | How blurry the background is. Larger numbers mean more blurry but will result in larger runtime cost on the GPU. | -| **Low-Quality Fallback Brush** | An image to draw instead of applying a blur when Low-Quality Override mode is enabled. You can enable Low-Quality Mode for background blurs by setting the cvar `Slate.ForceBackgroundBlurLowQualityOverride` to **1**. This is usually done in the project's scalability settings. | -| **Blur Radius** | This is the number of pixels which will be weighted in each direction from any given pixel when computing the blur. A larger value is more costly but allows for stronger blurs. | +| **Apply Alpha to Blur** | 为 true 时,此项将基于控件透明度调制模糊强度。| +| **Blur Strength** | 背景的模糊强度。数值越大,模糊越强,GPU 的运行时开销越大。| +| **Low-Quality Fallback Brush** | 启用 Low-Quality Override 模式时绘制的图像(而不应用模糊)。将 cvar `Slate.ForceBackgroundBlurLowQualityOverride` 设为 **1** 即可启用背景模糊的低精度模式。这通常在项目的可延展性设置中进行。| +| **Blur Radius** | 计算模糊时,此项是从任意给定像素的每个方向进行加权的像素数量。数值越高,模糊越强,但开销越高。| -Each of the properties above can also be set or changed at runtime through Blueprint Script. +之前提及的每个属性也可在运行时通过蓝图脚本进行设置(或修改)。 ![](BackgroundBlurBP.png) -The ability to set other appearance settings such as Horizontal and Vertical Alignment as well as any padding around the widget can also be defined. +也可定义其他外观设置(如水平或垂直对齐)和围绕控件的包围。 -## Usage Example +## 使用范例 -In the example below, we use the Background Blur widget to highlight a menu when the game is paused, blurring out the background. +在下例中,游戏暂停时我们使用 Background Blur 组件高亮菜单,将背景模糊。 [OBJECT:EmbeddedVideo] [PARAMLITERAL:width] @@ -50,24 +53,24 @@ RUD047Z00bU [/PARAMLITERAL] [/OBJECT] -For this, we add the Blur Widget along with our simplified menu and use the **Blur Strength** value to determine the level of background blur applied. +针对这点,我们通过简化菜单增加了 Blur 控件,使用 **Blur Strength** 值确定应用的背景模糊强度。 ![](BlurWidgetDesigner.png) -On our Menu Widget Blueprint's Graph, we create some script to handle how our menu reacts to button clicks. +我们在菜单控件蓝图的图表上创建一个脚本,处理菜单对按键点击的响应。 ![](BlurWidgetGraph.png) -Above, when we construct the widget, we are turning on the Mouse Cursor. When the Resume button is pressed we hide the cursor, un-pause the game and remove the menu from being displayed. -When Quit is pressed, we simply quit the game. Inside our player character's Blueprint (below), we add some script to create and display the menu when a key is pressed, in this case whenever **P** is pressed, as well as pause the game. +我们在上方构建控件时打开了鼠标指针。按下 **Resume** 键时将隐藏指针、取消游戏暂停,并移除显示的菜单。 +按下 **Quit** 键后将退出游戏。在玩家角色的蓝图中(如下图所示)添加一个脚本,在发生按键时创建并显示菜单。在此情形下,**P** 按下时游戏将暂停,将显示菜单。 ![](CharacterBlueprint.png) -The result is the ability to pause the game and blur the background but keep our menu intact for players to interact with. +实现的结果是能够暂停游戏并模糊背景,使玩家能和完整的菜单进行交互。 ![](50_Blur.png) -We could also decrease the Blur Strength from 50 (above) down to 10 (below) to make the background slightly more visible. +也可将模糊强度(Blur Strength)从 50 降至 10,使背景可见度略微提高。 ![](10_Blur.png) diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/WidgetTypeReference/BackgroundBlur/BackgroundBlur.JPN.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/WidgetTypeReference/BackgroundBlur/BackgroundBlur.JPN.udn index e9e69009153a..1d8b77b78656 100644 --- a/Engine/Documentation/Source/Engine/UMG/UserGuide/WidgetTypeReference/BackgroundBlur/BackgroundBlur.JPN.udn +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/WidgetTypeReference/BackgroundBlur/BackgroundBlur.JPN.udn @@ -1,18 +1,21 @@ -INTSourceChangelist:3345453 +INTSourceChangelist:3372539 Availability:Public -Title:Background Blur -Crumbs:%ROOT%, Engine, Engine/UMG, Engine/UMG/UserGuide, Engine/UMG/UserGuide/WidgetTypeReference +Title:Background Blur ウィジェット +Crumbs:%ROOT% Description:単一の子ウィジェットの下にあるオブジェクトをぼかす Background Blur ウィジェットの使用方法を説明します。 Related:Engine/UMG/UserGuide version:4.15 tags:UMG UI Designer +Parent:Engine/UMG/UserGuide/WidgetTypeReference +Order: +Type:reference [TOC(start:2 end:2)] -## 説明 +##説明 [EXCERPT:desc] -このウィジェットには子ウィジェットをひとつ含めることが可能であり、調整可能なパディングで周囲を囲み、そのウィジェットの下のすべてのコンテンツにポストプロセスのガウス ブラーを適用することができます。 +**Background Blur ウィジェット** には子ウィジェットをひとつ含めることが可能であり、調整可能なパディングで周囲を囲み、そのウィジェットの下にあるすべてのコンテンツにポストプロセスのガウス ブラーを適用することができます。 [/EXCERPT:desc] ## 詳細 @@ -28,11 +31,11 @@ tags:UMG UI Designer | **Low-Quality Fallback Brush** | Low-Quality Override モードが有効な場合に、ぼかしを適用するかわりに描画する画像です。バックグラウンド ブラーの Low-Quality Mode を有効にするには、 cvar `Slate.ForceBackgroundBlurLowQualityOverride` を **1** に設定します。これは通常、プロジェクトの scalability (拡張性) の設定で行います。 | **Blur Radius** | ブラー計算時に任意のピクセルから各方向にウェイトをかけるピクセル数です。値が大きくなると負荷は高くなりますが、ぼかしは強くなります。 | -上記の各プロパティは、ブループリントのスクリプトでランタイムに設定または変更することもできます。 +前述の各プロパティは、ブループリントのスクリプトでランタイムに設定 (または変更) することもできます。 ![](BackgroundBlurBP.png) -Horizontal Alignment、 Vertical Alignment (水平方向、垂直方向のアライメント) や、ウィジェット周囲のパディングも定義することができます。 +他の外観を設定する機能 (水平方向、垂直方向のアライメント) や、ウィジェット周囲のパディングも定義することができます。 ## 使用例 @@ -50,7 +53,7 @@ RUD047Z00bU [/PARAMLITERAL] [/OBJECT] -ここでは、単純なメニューに Blur Widget を加えて、**Blur Strength** 値を使って適用するバックグラウンド ブラーのレベルを決めます。 +ここでは、単純なメニューに Blur Widget を加えて、**Blur Strength** 値を使って適用するバックグラウンド ブラーの強度を決めます。 ![](BlurWidgetDesigner.png) @@ -58,8 +61,8 @@ Menu Widget Blueprint のグラフでは、ボタンのクリックにメニュ ![](BlurWidgetGraph.png) -上の画面では、ウィジェットを構築する場合、マウス カーソルをオンにしています。Resume ボタンを押すとカーソルが非表示になり、ゲームの一時停止が解除され、表示されているメニューが取り除かれます。 -Quit を押すと、ゲームが終了します。プレイヤー キャラクターのブループリント (以下) で、キーが押されたときに、この場合、**P** が押されるたびに、メニューを作成、表示する、ゲームを一時停止するスクリプトを追加しました。 +上の画面では、ウィジェットを構築する場合、マウス カーソルをオンにしています。**Resume** ボタンを押すとカーソルが非表示になり、ゲームの一時停止が解除され、表示されているメニューが取り除かれます。 +**Quit** を押すと、ゲームが終了します。プレイヤー キャラクターのブループリント (以下) で、キーが押されたときに、メニューを作成、表示するスクリプトを追加しました。この場合、P が押されるたびに、メニューが表示されると、ゲームを一時停止します。 ![](CharacterBlueprint.png) diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/WidgetTypeReference/BackgroundBlur/BackgroundBlur.KOR.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/WidgetTypeReference/BackgroundBlur/BackgroundBlur.KOR.udn index 4d372dbd5f04..5dcc4d25997a 100644 --- a/Engine/Documentation/Source/Engine/UMG/UserGuide/WidgetTypeReference/BackgroundBlur/BackgroundBlur.KOR.udn +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/WidgetTypeReference/BackgroundBlur/BackgroundBlur.KOR.udn @@ -1,18 +1,21 @@ -INTSourceChangelist:3345453 +INTSourceChangelist:3372539 Availability:Public -Title: 백그라운드 블러 -Crumbs:%ROOT%, Engine, Engine/UMG, Engine/UMG/UserGuide, Engine/UMG/UserGuide/WidgetTypeReference +Title: 백그라운드 블러 위젯 +Crumbs:%ROOT% Description: Background Blur 위젯을 사용하여 단일 자손 위젯 아래 오브젝트에 블러를 적용하는 법입니다. Related: Engine/UMG/UserGuide version: 4.15 tags:UMG UI Designer +Parent:Engine/UMG/UserGuide/WidgetTypeReference +Order: +Type:reference [TOC(start:2 end:2)] ## 설명 [EXCERPT:desc] -이 위젯은 하나의 자손 위젯을 가질 수 있는데, 거기에 조절 가능한 패딩을 붙여 포스트 프로세스 가우시안 블러를 적용하여 위젯 아래 모든 콘텐츠에 블러를 적용할(뿌옇게 만들) 수 있습니다. +Background Blur (백그라운드 블러) 위젯은 하나의 자손 위젯을 가질 수 있는데, 거기에 조절 가능한 패딩을 붙여 포스트 프로세스 가우시안 블러를 적용하여 위젯 아래 모든 콘텐츠에 블러를 적용할(뿌옇게 만들) 수 있습니다. [/EXCERPT:desc] ## 디테일 @@ -59,7 +62,7 @@ RUD047Z00bU ![](BlurWidgetGraph.png) 위에서 위젯 생성 시, Mouse Cursor 를 켜고 있습니다. Resume 버튼이 눌리면 커서를 숨기고 게임을 재개한 뒤 메뉴 표시를 제거합니다. -Quit 이 눌리면 단순히 게임을 종료합니다. 플레이어 캐릭터의 블루프린트에서 (아래), 키가 눌리면 (여기서는 **P**) 메뉴를 표시하고 게임을 일시정지합니다. +Quit 버튼이 눌리면 단순히 게임을 종료합니다. 플레이어 캐릭터의 블루프린트에서 (아래), 키가 눌리면 (여기서는 **P**) 메뉴를 표시하고 게임을 일시정지합니다. ![](CharacterBlueprint.png) diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/WidgetTypeReference/WidgetTypeReference.JPN.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/WidgetTypeReference/WidgetTypeReference.JPN.udn index a6a874dfea24..f4debc87c2c6 100644 --- a/Engine/Documentation/Source/Engine/UMG/UserGuide/WidgetTypeReference/WidgetTypeReference.JPN.udn +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/WidgetTypeReference/WidgetTypeReference.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3345453 +INTSourceChangelist:3372539 Availability:Public Title:Widget タイプのリファレンス Crumbs:%ROOT%, Engine, Engine/UMG, Engine/UMG/UserGuide @@ -8,7 +8,7 @@ tags:UMG UI Designer [TOC(start:2 end:2)] -**Widget ブループリント エディタ** 内の **[Palette (パレット)]** ウィンドウには、4 種類の **Widget** のカテゴリがあります。各カテゴリ内には、様々な Widget があり、**ビジュアル デザイナ** にドラッグ&ドロップすることができます。こうしたウィジェットを組み合わせて、**[Designer (デザイナ)]** タブで UI の外観をレイアウトし、各ウィジェットの **[Details (詳細)]** パネルの設定と **[Graph (グラフ)]** タブの設定を通してウィジェットの機能を追加することができます。 +**Widget ブループリント エディタ** 内の **[Palette (パレット)]** ウィンドウには、いくつかの **Widget** のカテゴリがあります。各カテゴリ内には、様々な Widget があり、**ビジュアル デザイナ** にドラッグ&ドロップすることができます。こうしたウィジェットを組み合わせて、**[Designer (デザイナ)]** タブで UI の外観をレイアウトし、各ウィジェットの **[Details (詳細)]** パネルの設定と **[Graph (グラフ)]** タブの設定を通してウィジェットの機能を追加することができます。 以下は、**[Palette]** ウィンドウの Widget の種類を表しています。 @@ -29,7 +29,7 @@ tags:UMG UI Designer | **Button** | ボタンは単一の子であり、基本的なインタラクションを有効にするクリック可能なプリミティブ ウィジェットです。ボタン内に他のウィジェットを入れてより複雑な面白いクリック可能なエレメントを UI に作ることができます。 | | **Check Box** | 'unchecked'、 'checked'、'indeterminable' (未チェック、チェック済み、未確定) の切り替えた状態を表示できます。標準的なチェックボックス、またはトグルボタン、またはラジオボタンとしてこのチェックボックスを使用できます。 | | **Image** | UI にスレートブラシ、テクスチャ、スプライト、またはマテリアルを表示できるようにします。[REGION:note]レンダリング時にすべて同じレイヤーを共有しているのであれば、同じテクスチャ アトラスを構成しているスプライトはスレートと一緒にバッチ処理することができます。つまり、ドロー コール カウントの制限が厳しいプラットフォームでは、Paper2D スプライトをブラシの入力として使用すると UMG とスレート ウィジェットのレンダリングの効率は大幅に上がります。[/REGION] | -| [Named Slot](Engine\UMG\UserGuide\WidgetTypeReference\NamedSlot) | [INCLUDE:Engine\UMG\UserGuide\WidgetTypeReference\NamedSlot#desc] | +| [**Named Slot**](Engine\UMG\UserGuide\WidgetTypeReference\NamedSlot) | [INCLUDE:Engine\UMG\UserGuide\WidgetTypeReference\NamedSlot#desc] | | **Progress Bar** | 進捗バー ウィジェットは、進捗に合わせて満たされるシンプルなバーであり、経験値、ヘルス、ポイントなどの用途でいくつでも再スタイリングできます。 | | **Slider** | ハンドル付きのスライド バーを表示するシンプルなウィジェットです。 0-1 の間の値を制御できます。 | | **Text** | 画面上にテキストを表示する基本的な方法です。オプションや他の UI エレメントのテキストを記述するために使用できます。 | @@ -89,7 +89,7 @@ tags:UMG UI Designer | **Uniform Grid Panel** | 複数の子全体で利用可能な領域を均等に分割するパネルです。 | | **Vertical Box** | 縦方向ボックス (vertical box) ウィジェットは、子ウィジェットを自動的に垂直に配列するレイアウト パネルです。これはウィジェットを積み重ね、縦方向に並べるのに適しています。| | **Widget Switcher** | タブ コントロールのようなものですが、タブはなく、独自にタブを作成してこのウィジェット スイッチャーと組み合わせてタブ効果を得ることができます。最大限でもウィジェットは一度に 1 つだけ見えます。 | -| [Wrap Box](Engine\UMG\UserGuide\WidgetTypeReference\WrapBox) | [INCLUDE:Engine\UMG\UserGuide\WidgetTypeReference\WrapBox#desc] | +| [**Wrap Box**](Engine\UMG\UserGuide\WidgetTypeReference\WrapBox) | [INCLUDE:Engine\UMG\UserGuide\WidgetTypeReference\WrapBox#desc] | ## プリミティブ @@ -103,7 +103,7 @@ tags:UMG UI Designer | **Circular Throbber** | くるくると回る円で画像を表示するウィジェットです。 | | **Editable Text** | ボックスの背景なしのユーザー入力可能なテキスト欄です。編集可能なテキストは一行だけです。 | | **Editable Text (Multi-Line)** | Editable Text と似ていますが、一行ではなく複数行に対応しています。 | -| [Menu Anchor](Engine\UMG\UserGuide\WidgetTypeReference\MenuAnchor) | [INCLUDE:Engine\UMG\UserGuide\WidgetTypeReference\MenuAnchor#desc] | +| [**Menu Anchor**](Engine\UMG\UserGuide\WidgetTypeReference\MenuAnchor) | [INCLUDE:Engine\UMG\UserGuide\WidgetTypeReference\MenuAnchor#desc] | | **Native Widget Host** | 子スレート ウィジェットを 1 つ格納できるコンテナ ウィジェットです。UMG ウィジェット内部にネイティブ ウィジェットをネスティングすることだけが必要な場合に使用します。 | | **Spacer** |他のウィジェットとの間でカスタムのパディングをします。このスペーサーは、視覚的に表示されずゲーム内では見えません。| | **Throbber** | いくつかのズームする円を一列に表示するアニメートされた throbber ウィジェットです (例えば、ロード中であることを表すために使用できます)。 | @@ -117,7 +117,7 @@ UI ベースの特殊効果を生成するために使われるウィジェッ | オプション | 説明 | | -------- | ----------- | -| [Background Blur](Engine\UMG\UserGuide\WidgetTypeReference\BackgroundBlur) | [INCLUDE:Engine\UMG\UserGuide\WidgetTypeReference\BackgroundBlur#desc] | +| [**Background Blur**](Engine\UMG\UserGuide\WidgetTypeReference\BackgroundBlur) | [INCLUDE:Engine\UMG\UserGuide\WidgetTypeReference\BackgroundBlur#desc] | ## カテゴリなし @@ -148,7 +148,7 @@ User Created Widgets (ユーザー作成ウィジェット) は、別の Widget | オプション | 説明 | | -------- | ----------- | -| [Web Browser](Engine\UMG\UserGuide\WidgetTypeReference\WebBrowser) | [INCLUDE:Engine\UMG\UserGuide\WidgetTypeReference\WebBrowser#desc] | +| [**Web Browser**](Engine\UMG\UserGuide\WidgetTypeReference\WebBrowser) | [INCLUDE:Engine\UMG\UserGuide\WidgetTypeReference\WebBrowser#desc] | diff --git a/Engine/Documentation/Source/Engine/UMG/UserGuide/WidgetTypeReference/WidgetTypeReference.KOR.udn b/Engine/Documentation/Source/Engine/UMG/UserGuide/WidgetTypeReference/WidgetTypeReference.KOR.udn index c7865aded181..6c5bf9499fac 100644 --- a/Engine/Documentation/Source/Engine/UMG/UserGuide/WidgetTypeReference/WidgetTypeReference.KOR.udn +++ b/Engine/Documentation/Source/Engine/UMG/UserGuide/WidgetTypeReference/WidgetTypeReference.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3345453 +INTSourceChangelist:3372539 Availability:Public Title: 위젯 유형 참고서 Crumbs:%ROOT%, Engine, Engine/UMG, Engine/UMG/UserGuide @@ -29,7 +29,7 @@ tags:UMG UI Designer | **Button** | 버튼 - 단일 자손 클릭 가능 프리미티브 위젯으로, 기본적인 상호작용에 쓰입니다. 버튼 안에 다른 위젯을 배치하여 UI 에 좀 더 복잡하고 재미난 클릭가능 요소를 만들 수 있습니다. | | **Check Box** | 체크 박스 - 'unchecked' 체크해제 / 'checked' 체크됨 / 'indeterminable' 확인불가 세 가지 토글 상태를 표시할 수 있습니다. 체크 박스는 고전 체크 박스, 토글 버튼, 동글 버튼으로 사용할 수 있습니다. | | **Image** | 이미지 - 이미지 위젯으로 UI 에 슬레이트 브러시, 텍스처, 스프라이트, 머티리얼을 표시할 수 있습니다. [REGION:note]같은 텍스처 아틀라스에 들어있는 스프라이트는, 렌더링할 때 같은 레이어를 공유하는 경우 슬레이트에 일괄 배치시킬 수 있습니다. 즉 드로 콜 수 예산이 빠듯한 플랫폼에서는 Paper2D 스프라이트를 브러시 입력으로 사용하는 경우 UMG 와 슬레이트 위젯의 렌더링 효율이 크게 향상된다는 뜻입니다.[/REGION] | -| [Named Slot](Engine\UMG\UserGuide\WidgetTypeReference\NamedSlot) | 네임드 슬롯 - [INCLUDE:Engine\UMG\UserGuide\WidgetTypeReference\NamedSlot#desc] | +| [**Named Slot**](Engine\UMG\UserGuide\WidgetTypeReference\NamedSlot) | 네임드 슬롯 - [INCLUDE:Engine\UMG\UserGuide\WidgetTypeReference\NamedSlot#desc] | | **Progress Bar** | 진행상황 바 - 진행상황 바 위젯은 경험치, 생명력, 점수와 같은 여러가지 용도에 맞도록 스타일 조정이 가능한, 단순한 바 입니다. | | **Slider** | 슬라이더 - 0-1 사이 값 조절이 가능한 핸들이 있는 미닫이 바가 표시되는 단순 위젯입니다. | | **Text** | 텍스트 - 화면상에 텍스트를 표시하는 기본적인 방법으로, 옵션이나 기타 UI 요소에 대한 텍스트 설명에 사용할 수도 있습니다. | @@ -89,7 +89,7 @@ tags:UMG UI Designer | **Uniform Grid Panel** | 균등 그리드 패널 - 자손 모두와 남은 공간을 균등하게 나누는 패널입니다. | | **Vertical Box** | 세로 박스 - 자손 위젯이 자동으로 세로로 배치되도록 하는 위젯입니다. 위젯끼리 세로 정렬을 유지하면서 서로 쌓이도록 하는 데 좋습니다. | | **Widget Switcher** | 위젯 전환기 - 자체적으로 만들 수 있는 탭은 없으나 탭처럼 제어되는 것으로, 이와 함꼐 하여 탭 효과를 낼 수 있습니다. 한 번에 최대 하나의 위젯만 보입니다. | -| [Wrap Box](Engine\UMG\UserGuide\WidgetTypeReference\WrapBox) | 줄바꿈 박스 - [INCLUDE:Engine\UMG\UserGuide\WidgetTypeReference\WrapBox#desc] | +| [**Wrap Box**](Engine\UMG\UserGuide\WidgetTypeReference\WrapBox) | 줄바꿈 박스 - [INCLUDE:Engine\UMG\UserGuide\WidgetTypeReference\WrapBox#desc] | ## 프리미티브 @@ -103,7 +103,7 @@ tags:UMG UI Designer | **Circular Throbber** | 원형 트로버 - 회전하는 원형 이미지로 (주로 로드중임을) 나타내는 트로버 위젯입니다. | | **Editable Text** | 편집가능 텍스트 - 박스 배경 없이 사용자 입력이 가능한 글상자입니다. 편집가능 텍스트 한 줄만 지원합니다. | | **Editable Text (Multi-Line)** | 편집가능 텍스트 (여러줄) - **Editable Text** 와 비슷하나 한 줄이 아닌 여러줄 텍스트를 지원합니다. | -| [Menu Anchor](Engine\UMG\UserGuide\WidgetTypeReference\MenuAnchor) | 메뉴 앵커 - [INCLUDE:Engine\UMG\UserGuide\WidgetTypeReference\MenuAnchor#desc] | +| [**Menu Anchor**](Engine\UMG\UserGuide\WidgetTypeReference\MenuAnchor) | 메뉴 앵커 - [INCLUDE:Engine\UMG\UserGuide\WidgetTypeReference\MenuAnchor#desc] | | **Native Widget Host** | 네이티브 위젯 호스트 - 하나의 자손 슬레이트 위젯을 포함할 수 있는 컨테이너 위젯입니다. UMG 위젯 안에 네이티브 위젯을 중첩시키기만 하면 되는 경우에 사용합니다. | | **Spacer** | 스페이서 - 다른 위젯 사이에 임의의 여백을 제공해 주는 위젯입니다. 스페이서는 시각적 표시가 없어 게임에서 보이지 않습니다. | | **Throbber** | 트로버 - 연속해서 여러개 확대되는 원으로 보이는 애니메이션 트로버 위젯입니다 (주로 로딩중임을 나타낼 때 사용됩니다). | @@ -117,7 +117,7 @@ tags:UMG UI Designer | 옵션 | 설명 | | -------- | ----------- | -| [Background Blur](Engine\UMG\UserGuide\WidgetTypeReference\BackgroundBlur) | 배경 블러 - [INCLUDE:Engine\UMG\UserGuide\WidgetTypeReference\BackgroundBlur#desc] | +| [**Background Blur**](Engine\UMG\UserGuide\WidgetTypeReference\BackgroundBlur) | 배경 블러 - [INCLUDE:Engine\UMG\UserGuide\WidgetTypeReference\BackgroundBlur#desc] | ## 미분류 @@ -148,7 +148,7 @@ User Created Widget (사용자 생성 위젯)은 미리 생성해 둔 **위젯 | 옵션 | 설명 | | -------- | ----------- | -| [Web Browser](Engine\UMG\UserGuide\WidgetTypeReference\WebBrowser) | 웹 브라우저 - [INCLUDE:Engine\UMG\UserGuide\WidgetTypeReference\WebBrowser#desc] | +| [**Web Browser**](Engine\UMG\UserGuide\WidgetTypeReference\WebBrowser) | 웹 브라우저 - [INCLUDE:Engine\UMG\UserGuide\WidgetTypeReference\WebBrowser#desc] | diff --git a/Engine/Documentation/Source/Enterprise/Enterprise.INT.udn b/Engine/Documentation/Source/Enterprise/Enterprise.INT.udn index e322b7565ceb..f2e8d23f14c2 100644 --- a/Engine/Documentation/Source/Enterprise/Enterprise.INT.udn +++ b/Engine/Documentation/Source/Enterprise/Enterprise.INT.udn @@ -14,4 +14,4 @@ topic-icon:%ROOT%/enterprise_icon.png Unreal Engine and its real-time interaction and rendering capabilities are well-suited for a huge range of projects across all Enterprise applications, including automotive, aviation, architecture, consumer electronics and complex data visualization. -[DIR(output:"topic" org:"hierarchy" parent:"Enterprise")] +[DIR(output:"topic" org:"hierarchy" parent:"Enterprise" end:"1")] diff --git a/Engine/Documentation/Source/Enterprise/Enterprise.JPN.udn b/Engine/Documentation/Source/Enterprise/Enterprise.JPN.udn index 729f7e105519..567570701f18 100644 --- a/Engine/Documentation/Source/Enterprise/Enterprise.JPN.udn +++ b/Engine/Documentation/Source/Enterprise/Enterprise.JPN.udn @@ -1,4 +1,5 @@ -Availability:Public +INTSourceChangelist:3454523 +Availability:Public Title:エンタープライズ アプリケーション Description:アンリアル エンジンを自動車、航空、建築、コンシューマー エレクトロニクス、および複合データ ビジュアライゼーションのアプリケーションに使用します。 Crumbs:%ROOT%, @@ -14,4 +15,4 @@ topic-icon:%ROOT%/docs_icon.png アンリアル エンジンとそのリアルタイム インタラクション、レンダリング機能は多岐にわたるエンタープライズ アプリケーションの幅広いプロジェクトに適したものです。例えば、自動車、航空、建築、コンシューマー エレクトロニクス、および複合データ ビジュアリゼーションに適用できます。 -[DIR(output:"topic" org:"hierarchy" parent:"Enterprise")] +[DIR(output:"topic" org:"hierarchy" parent:"Enterprise" end:"1")] diff --git a/Engine/Documentation/Source/Enterprise/Enterprise.KOR.udn b/Engine/Documentation/Source/Enterprise/Enterprise.KOR.udn index 8538676325a2..e9c8c6abf5c9 100644 --- a/Engine/Documentation/Source/Enterprise/Enterprise.KOR.udn +++ b/Engine/Documentation/Source/Enterprise/Enterprise.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3112291 +INTSourceChangelist:3454523 Availability:Public Title: 엔터프라이즈 어플리케이션 Description:차량, 항공, 건축, 소비자 가전, 복합 데이터 시각화 어플리케이션에 사용되는 언리얼 엔진입니다. @@ -15,4 +15,4 @@ topic-icon:%ROOT%/enterprise_icon.png 언리얼 엔진과 그 실시간 상호작용 및 렌더링 기술은 차량, 항공, 건축, 소비자 가전, 복합 데이터 시각화와 같은 폭넓은 분야의 다양한 엔터프라이즈 어플리케이션에 쓰기에 적합합니다. -[DIR(output:"topic" org:"hierarchy" parent:"Enterprise")] +[DIR(output:"topic" org:"hierarchy" parent:"Enterprise" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/ClassCreation/CodeAndBlueprints/CodeAndBlueprints.JPN.udn b/Engine/Documentation/Source/Gameplay/ClassCreation/CodeAndBlueprints/CodeAndBlueprints.JPN.udn index 53a68df7851a..f748df5042f2 100644 --- a/Engine/Documentation/Source/Gameplay/ClassCreation/CodeAndBlueprints/CodeAndBlueprints.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/ClassCreation/CodeAndBlueprints/CodeAndBlueprints.JPN.udn @@ -1,8 +1,8 @@ -INTSourceChangelist:2710135 +INTSourceChangelist:3238697 Availability:Public Title:C++ とブループリント Crumbs: %ROOT%, Gameplay, Gameplay/ClassCreation -Description:ゲームプレイ プログラマ向けのアンリアル エンジン入門 +Description:ゲームプレイ プログラマ向けのアンリアル エンジン入門書 Version:4.9 C++ クラスをブループリントで拡張できます。プログラマーが、新しいゲームプレイ クラスをコードで作成し、それをレベル デザイナーがブループリントで設定および変更することができます。 @@ -10,10 +10,10 @@ C++ クラスがどのようにブループリント システムとインタラ ## クラス設定 -クラス設定の最初のセクションでは、[](Programming\Development\ManagingGameCode\CppClassWizard) を使用して「LightSwitchBoth」という名前のクラスを作成します。 +クラス設定の最初のセクションでは、[](Programming\Development\ManagingGameCode\CppClassWizard) を使用して LightSwitchBoth という名前のクラスを作成します。 -「LightSwitchBoth」クラスの大部分のコード設定は、[C++ Only LightSwitch example](Gameplay\ClassCreation\CodeOnly) のコードと類似しています。ブループリントで「LightSwitchCodeOnly」クラスの拡張が可能でも、 -そのクラスで作成されたコンポーネント、変数、関数は、ブループリント グラフにアクセスすることはできません。この例では、「LightSwitchBoth」クラスから派生するブループリントのテンプレートとして機能させる +LightSwitchBoth クラスの大部分のコード設定は、[C++ Only LightSwitch example](Gameplay\ClassCreation\CodeOnly) のコードと類似しています。ブループリントで LightSwitchCodeOnly クラスの拡張が可能でも、 +そのクラスで作成されたコンポーネント、変数、関数は、ブループリント グラフにアクセスすることはできません。この例では、 LightSwitchBoth クラスから派生するブループリントのテンプレートとして機能させる `UPROPERTY()`と`UFUNCTION()` 指定子について理解を深めていきます。 最初に、C++ Only LightSwitch の例で、LightSwitch コンポーネント、 Sphere コンポーネント、 DesiredIntensity 変数、そして OnOverlap 関数を作成するために @@ -22,15 +22,15 @@ C++ クラスがどのようにブループリント システムとインタラ ヘッダファイルは、以下の機能を追加するために、C++ Only LightSwitch から適用されます。 * PointLight コンポーネントと Sphereコンポーネントは BlueprintReadOnly です。**[My Blueprint]** タブの **[Switch Component]** カテゴリに表示されます。 -* OnOverlapBegin と OnOverlapEnd は BlueprintNativeEvents となりました。**[My Blueprint]** タブの **Switch Functions** カテゴリに表示されます。 -* DesiredIntensity はブループリントで読み出し/書き込み専用です。**[My Blueprint]** タブの **Switch Variables** カテゴリに表示されます。 +* OnOverlapBegin と OnOverlapEnd は BlueprintNativeEvent になりました。**[My Blueprint]** タブの **[Switch Functions]** カテゴリに表示されます。 +* DesiredIntensity は BlueprintReadWrite です。**[My Blueprint]** タブの **[Switch Variables]** カテゴリに表示されます。 * DesiredIntensity は VisibleAnywhere の代わりに EditAnywhere となりました。 [REGION:tip] -`UCLASS()`マクロには「ブループリントで利用可能」な指定子があります。このケースでは不要です。LightSwitchBoth は、ブループリントで利用可能なアクタから直接継承し、そのブループリントで利用可能な指定子が継承されるからです。 +`UCLASS()`マクロには `Blueprintable` な指定子があります。このケースでは不要です。LightSwitchBoth は、Blueprintable アクタから直接継承し、そのBlueprintable 指定子が継承されるからです。 [/REGION] -`UPROPERTY()` と `UFUNCTION()` マクロの追加の指定子で、「LightSwitchBoth」クラスのヘッダファイルは以下の通りです。 +`UPROPERTY()` マクロと `UFUNCTION()` マクロの指定子の追加で、LightSwitchBoth クラスのヘッダファイルは以下のようになります。 [REGION:codetitlebar] LightSwitchBoth.h @@ -51,32 +51,32 @@ LightSwitchBoth.h { GENERATED_BODY() public: - /** point light コンポーネント */ + /** point light component */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Switch Components") class UPointLightComponent* PointLight1; - /** sphere コンポーネント */ + /** sphere component */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Switch Components") class USphereComponent* Sphere1; ALightSwitchBoth(); - /** 何かが sphere コンポーネントに入ると呼び出されます。 */ + /** called when something enters the sphere component (何かが sphere コンポーネントに入ると呼び出されます。)*/ UFUNCTION(BlueprintNativeEvent, Category="Switch Functions") - void OnOverlapBegin(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult); - void OnOverlapBegin_Implementation(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult); + void OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult); + void OnOverlapBegin_Implementation(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult); - /** 何かが sphere コンポーネントを離れると呼び出されます。 */ + /** called when something leaves the sphere component (何かが sphere コンポーネントを離れると呼び出されます。) */ UFUNCTION(BlueprintNativeEvent, Category="Switch Functions") - void OnOverlapEnd(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex); + void OnOverlapEnd(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex); - void OnOverlapEnd_Implementation(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex); + void OnOverlapEnd_Implementation(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex); - /** light コンポーネントの可視性を切り替えます。*/ + /** Toggles the light component's visibility (light コンポーネントの可視性を切り替えます)*/ UFUNCTION() void ToggleLight(); - /** ライトの望ましい明るさ */ + /** the desired intensity for the light (ライトの望ましい明るさ) */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Switch Variables") float DesiredIntensity; @@ -110,13 +110,13 @@ LightSwitchBoth.cpp Sphere1 = CreateDefaultSubobject(this, TEXT("Sphere1")); Sphere1->InitSphereRadius(250.0f); - Sphere1->AttachParent = RootComponent; + Sphere1->SetupAttachment(RootComponent); - Sphere1->OnComponentBeginOverlap.AddDynamic(this, &ALightSwitchBoth::OnOverlapBegin); // このコンポーネントが何かとオーバーラップした場合の通知をセットアップします。 - Sphere1->OnComponentEndOverlap.AddDynamic(this, &ALightSwitchBoth::OnOverlapEnd); // このコンポーネントが何かとオーバーラップした場合の通知をセットアップします。 + Sphere1->OnComponentBeginOverlap.AddDynamic(this, &ALightSwitchBoth::OnOverlapBegin); // set up a notification for when this component overlaps something (このコンポーネントが何かとオーバーラップした場合の通知をセットアップします) + Sphere1->OnComponentEndOverlap.AddDynamic(this, &ALightSwitchBoth::OnOverlapEnd); // set up a notification for when this component overlaps something (このコンポーネントが何かとオーバーラップした場合の通知をセットアップします) } - void ALightSwitchBoth::OnOverlapBegin_Implementation(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult) + void ALightSwitchBoth::OnOverlapBegin_Implementation(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult) { if (OtherActor && (OtherActor != this) && OtherComp) { @@ -124,7 +124,7 @@ LightSwitchBoth.cpp } } - void ALightSwitchBoth::OnOverlapEnd_Implementation(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex) + void ALightSwitchBoth::OnOverlapEnd_Implementation(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex) { if (OtherActor && (OtherActor != this) && OtherComp) { @@ -138,35 +138,35 @@ LightSwitchBoth.cpp } -これがブランク オブジェクトに追加した最初のコード クラスである場合は、エディタを閉じて、Visual Studio または Xcode でプロジェクトをコンパイルした後に、エディタを開いてゲームモジュールが適切に作成されて再ロードされていることを確認するために、 - エディタを再び開きます。プロジェクトを開くために使用しているアンリアルエディタの実行ファイルと **Build Configuration** が同じバージョンである確認も重要となります。ビルド設定とプロジェクトのコンパイルに関する詳細は、 +これが空のプロジェクトに追加した最初のコード クラスである場合は、エディタを閉じて、Visual Studio または Xcode でプロジェクトをコンパイルした後に、エディタを開いてプロジェクトを再び開く必要があります。 + ゲームモジュールが適切に作成されて再ロードされていることを確認するためです。プロジェクトを開くために使用しているアンリアル エディタの実行ファイルのバージョンが **Build Configuration** と同じであることの確認も重要となります。ビルド設定とプロジェクトのコンパイルに関する詳細は、 [](Programming\Development\CompilingProjects) ページをご覧ください。 コードを既存の C++ プロジェクトに追加する場合は、ホットリロード機能を使用してエディタ内で新規コードをコンパイルすることができます。 この新規クラスをコンパイル後に、新規の [ブループリント クラス](Engine/Blueprints\UserGuide\Types\ClassBlueprint) を [作成](Engine/Blueprints\UserGuide\Types\ClassBlueprint\Creation) することができます。 -この場合、ブループリントの親クラスに「LightSwitchBoth」を選択して、名前を **LightSwitchBoth_BP** とします。 +この場合、ブループリントの親クラスに LightSwitchBoth を選択して、名前を **LightSwitchBoth_BP** とします。 ![](BPBoth_ParentClass.png) -C++ に追加した PointLight コンポーネントと Sphere コンポーネントも **ブループリントエディタ** の **[コンポーネント]** タブに表示されます。 +C++ に追加した PointLight コンポーネントと Sphere コンポーネントも **ブループリント エディタ** の **[コンポーネント]** タブに表示されます。 アイコンはダーク ブルーで表示されて、ネイティブ コンポーネントであること、親 LightSwitchBoth クラスから継承されたことを示します。単に **LightSwitchBoth_BP** ブループリントに追加された新規コンポーネントは、 -ライトブルーのアイコンで表示されます。**コンポーネント** タブを使用したコンポーネントの追加と配置についての詳しい情報は、[Components](Engine/Blueprints\UserGuide\Components) タブのドキュメントを参照してください。 +ライトブルーのアイコンになります。**[コンポーネント]** タブを使用したコンポーネントの追加と配置についての詳しい情報は、[Components](Engine/Blueprints\UserGuide\Components) タブのドキュメントを参照してください。 ![](Both_ComponentList.png) -**ブループリント エディタ** の **グラフ** パネル はブループリント編集の中心部分です。**グラフ** パネルでは、新しい [変数](Engine/Blueprints\UserGuide\Variables)、 -[関数](Engine/Blueprints\UserGuide\Functions) と [マクロ](Engine/Blueprints\UserGuide\Macros) を [](Engine/Blueprints\Editor/UIComponents\MyBlueprint) タブに追加することができます。ブループリント クラスに含まれている全ての [グラフ](Engine/Blueprints\UserGuide\Graphs) にも -アクセスできます。グラフには、デザイン タイムとゲームプレイ機能を作成するために [ノード](Engine/Blueprints\UserGuide\Nodes) が接続されています。こうした機能はクラスの変数、ゲームプレイ イベント、 -さらにアクタの周囲のものなどで操作されます。 +**ブループリント エディタ** の **[グラフ]** パネル はブループリント編集の中心部分です。**[グラフ]** パネルでは、新しい [変数](Engine/Blueprints\UserGuide\Variables)、 +[関数](Engine/Blueprints\UserGuide\Functions) と [マクロ](Engine/Blueprints\UserGuide\Macros) を [](Engine/Blueprints\Editor/UIComponents\MyBlueprint) タブで追加することができます。Blueprint クラスに含まれている全ての [グラフ](Engine/Blueprints\UserGuide\Graphs) にも +アクセスできます。グラフには、クラスの変数、gameplay event、さらにアクタの周囲のものなどで操作するデザイン タイムとゲームプレイ機能を作成するために + [ノード](Engine/Blueprints\UserGuide\Nodes) が接続されています。 -**[グラフ パネル]** の **[My Blueprint]** タブには、C++ コードで「LightSwitchBoth」クラスに追加した PointLight コンポーネントと Sphere コンポーネントが表示されます。これは`BlueprintReadOnly` 指定子によって表示されます。 -これらのコンポーネントのノードは、**[My Blueprint]** タブから名前をクリックしてグラフにドラッグすることで、グラフへ追加することができます。その後、こうしたノードを、可視性やライト色などの変数を変更するノードへ +**[グラフ]** パネルの **[My Blueprint]** タブには、C++ コードで LightSwitchBoth クラスに追加した PointLight コンポーネントと Sphere コンポーネントが表示されます。これは `BlueprintReadOnly` 指定子によって表示されます。 +これらのコンポーネントのノードは、**[My Blueprint]** タブから名前をクリックしてグラフにドラッグすることで、グラフに追加することができます。その後、こうしたノードを、可視性やライト色などの変数を変更するノードに 接続することができます。**[DesiredIntensity]** 変数は **[My Blueprint]** タブにも表示されます。コンポーネントではなく変数であるため、 `BlueprintReadWrite` 指定子を使用できます。つまり、ブループリント グラフに **DesiredIntensity** の値を get および set するノードの作成が可能です。使用に関する一般情報については [](Engine/Blueprints\Editor/UIComponents\MyBlueprint) のドキュメントを参照してください。 [REGION:tip] -親「LightSwitchBoth」クラスのコンポーネントと変数は、デフォルトで表示されない場合もあります。**[My Blueprint]** タブの下にある **[Show inherited variables(継承した変数を表示)]** チェックボックスにチェックを入れると、 +親の LightSwitchBoth クラスのコンポーネントと変数は、デフォルトで表示されない場合もあります。**[My Blueprint]** タブの下にある **[Show inherited variables(継承した変数を表示)]** チェックボックスにチェックを入れると、 親クラスから継承された変数が表示されます。 [/REGION] @@ -176,32 +176,32 @@ C++ に追加した PointLight コンポーネントと Sphere コンポーネ | ![](BP_Only_MyBlueprint.png) | ![](Both_MyBlueprint.png) | -LightSwitchBoth_BP クラスの挙動をセットアップするために使用するグラフが 2 つあります。1 つめのグラフは、[](Engine/Blueprints\UserGuide\UserConstructionScript) グラフで、特殊な Construction Script -イベントを含みます。Construction Script 設定無しの状態では、新規の LightSwitchBoth_BP アクタは、LightSwitchBoth コンストラクタのみを使用します。しかし、アクタがレベル内で移動した時と DesiredIntensity の変更時に、 +LightSwitchBoth_BP クラスの挙動をセットアップするために使用するグラフが 2 つあります。1 つめは、[](Engine/Blueprints\UserGuide\UserConstructionScript) グラフで、 +特殊な Construction Script event を含みます。Construction Script 設定無しの状態では、新規の LightSwitchBoth_BP アクタは、LightSwitchBoth コンストラクタのみを使用します。しかし、アクタがレベル内で移動した時と DesiredIntensity の変更時に、 Construction Script は実行されます。Construction Script を使用するということは、ブループリントに公開されたアクタ変数を簡単に変更することが可能であり、 変更がもたらす効果を直ぐに確認できることを意味します。 **LightSwitchBoth_BP** クラスで、**Construction Script** イベントは **Set Intensity** ノードと接続しています。 -そのため **Point Light 1** (PointLight コンポーネント) のBrightness (輝度) は、アクタの追加時、レベル内で移動時、または **[DesiredIntensity]** が変更された時に **DesiredIntensity** の値に設定されます。 +これは、 **Point Light 1** (PointLight コンポーネント) のBrightness (輝度) が、アクタの追加時、レベル内で移動時、または [DesiredIntensity] が変更された時に **DesiredIntensity** の値に設定されるようにするためです。 ![](Both_ConstructionScript.png) LightSwitch_BPOnly クラスでセットアップされたもうひとつのグラフは、[](Engine/Blueprints\UserGuide\EventGraph) です。イベントグラフの実行は、イベントから開始します。この場合、C++ 関数 `OnOverlap` が呼ばれると常に -**OnOverlap** イベントが実行されます。LightSwitchBoth ソース ファイルでは、デリゲートはアクタが Sphere コンポーネントへ入った時またはそこから離れた時に **OnOverlap** イベントが実行するように設定されています。 +OnOverlap event が実行されます。LightSwitchBoth ソース ファイルでは、デリゲートはアクタが Sphere コンポーネントへ入った時またはそこから離れた時に OnOverlap が実行するように設定されています。 - Sphere1->OnComponentBeginOverlap.AddDynamic(this, &ALightSwitchBoth::OnOverlapBegin); // このコンポーネントが何かとオーバーラップした場合の通知をセットアップします。 - Sphere1->OnComponentEndOverlap.AddDynamic(this, &ALightSwitchBoth::OnOverlapEnd); // このコンポーネントが何かとオーバーラップした場合の通知をセットアップします。 + Sphere1->OnComponentBeginOverlap.AddDynamic(this, &ALightSwitchBoth::OnOverlapBegin); // set up a notification for when this component overlaps something (このコンポーネントが何かとオーバーラップした場合の通知をセットアップします) + Sphere1->OnComponentEndOverlap.AddDynamic(this, &ALightSwitchBoth::OnOverlapEnd); // set up a notification for when this component overlaps something (このコンポーネントが何かとオーバーラップした場合の通知をセットアップします) -**OnOverlap** イベントノードは、**Set Light Color** ノードと接続されています。イベントが実行されると、常に PointLight コンポーネントのライト色をランダムな色にするように設定されています。これは、PointLight コンポーネントの可視性を切り替える、 +**OnOverlap** event ノードは、**Set Light Color** ノードと接続されています。イベントが実行されると、常に PointLight コンポーネントのライト色をランダムな色にするように設定されています。これは、PointLight コンポーネントの可視性を切り替える、 ソースファイルの `OnOverlap_Implementation` 関数をオーバーライドします。 -イベントおよびグラフでの作業に関する詳しい情報は、[](Engine/Blueprints\UserGuide\Events)、[](Engine/Blueprints\UserGuide\EventGraph)、および [グラフ パネル](Engine/Blueprints\Editor\Modes\GraphPanel) をご覧ください。 +イベントおよびグラフでの作業に関する詳しい情報は、[](Engine/Blueprints\UserGuide\Events)、[](Engine/Blueprints\UserGuide\EventGraph)、および [グラフ パネル](Engine/Blueprints\Editor\Modes\GraphPanel) のドキュメントをご覧ください。 ![](Both_EventGraph_2.png) -**DesiredIntensity** 変数は、LightSwitchBoth ヘッダファイルで EditAnywhere に設定されます。そのため、**ブループリント エディタ** のデフォルトで可視状態であり、**クラスのデフォルト** ボタンをクリックして、 [詳細] パネルでクラスのデフォルトを見て編集することができます。 -これは、クラスの各インスタンスに対して、変数の変更が可能であることも意味します。そのため、各アクタは独自の DesiredIntensity を保持することができます。DesiredIntensity は **ブループリントで読み出し/書き込み可能** でもあるため、これを **コンストラクション スクリプト** で使用すると、 -更新された時に **コンストラクション スクリプト** が再び実行されることになります。 +**DesiredIntensity** 変数は、LightSwitchBoth ヘッダファイルで EditAnywhere に設定されます。そのため、**ブループリント エディタ** のデフォルトで可視状態であり、**クラスのデフォルト** ボタンをクリックして、 [Details (詳細)] パネルでクラスのデフォルトを見て編集することができます。 +これは、クラスの各インスタンスに対して、変数の変更が可能であることも意味します。そのため、各アクタは独自の DesiredIntensity を保持することができます。DesiredIntensity は BlueprintReadWrite でもあるため、これをコンストラクション スクリプトで使用すると、 +更新された時にコンストラクション スクリプトが再び実行されることになります。 ![](Both_Defaults.png) @@ -209,4 +209,4 @@ LightSwitch_BPOnly クラスでセットアップされたもうひとつのグ ブループリントを **右クリック** して、**[Create New Blueprint Based on This]** を選択します。 ブループリント クラス、 LightSwitchBoth_BP は[](Engine/Content/Browser) にあり、そこからレベルにドラッグできます。[](Engine/UI/ClassViewer) にもあります。 -コンテンツ ブラウザ またはクラスビューアを使用したレベルへのアクタの配置については、[](Engine/Actors/Placement) のドキュメントを参照してください。 +コンテンツ ブラウザまたはクラスビューアを使用したレベルへのアクタの配置については、[](Engine/Actors/Placement) のドキュメントを参照してください。 diff --git a/Engine/Documentation/Source/Gameplay/ClassCreation/CodeOnly/CodeOnly.JPN.udn b/Engine/Documentation/Source/Gameplay/ClassCreation/CodeOnly/CodeOnly.JPN.udn index a1c3de83b1b8..d156b9d8bc8b 100644 --- a/Engine/Documentation/Source/Gameplay/ClassCreation/CodeOnly/CodeOnly.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/ClassCreation/CodeOnly/CodeOnly.JPN.udn @@ -1,15 +1,15 @@ -INTSourceChangelist:2796807 +INTSourceChangelist:3238697 Availability:Public Title:C++ Only Crumbs: %ROOT%, Gameplay, Gameplay/ClassCreation -Description:ゲームプレイ プログラマ向けのアンリアル エンジン入門 +Description:ゲームプレイ プログラマ向けのアンリアル エンジン入門書 Version:4.9 [](Programming\Development\ManagingGameCode\CppClassWizard ) を使用して、新規 C++ クラスをプロジェクトへ簡単に追加できます。新規クラスを派生させるクラスを選択した後に、 ウィザードが必要なヘッダファイルとソースファイルを設定します。これがプロジェクトに初めて追加したコードの場合、プロジェクトはコード プロジェクトに変換されます。コード プロジェクトは、 ソース コードを含むゲーム モジュールを作成します。これは、アンリアル エディタにゲーム モジュールが存在することを知らせ、Visual Studio または Xcode から C++ の変更を読み込むことができるようにします。マイナーなコード変更はエディタ内部でコンパイルすることができます。 -C++ コードのみを使用した「LightSwitch」クラスは LightSwitchCodeOnly と名付けられます。これについては以下で説明します。 +C++ コードのみを使用した LightSwitch クラスは LightSwitchCodeOnly と名付けられます。これについては以下で説明します。 ## クラス設定 @@ -24,10 +24,10 @@ C++ コードのみを使用した「LightSwitch」クラスは LightSwitchCodeO }; -**[C++ Class Wizard]** で作成されたクラス宣言は、自動的に `UCLASS()` マクロが前にきます。 +**C++ Class Wizard** で作成されたクラス宣言は、自動的に `UCLASS()` マクロが前にきます。 `UCLASS()` マクロはエンジンにクラスの存在を知らせます。また、エンジン内のクラスの動作を設定するために、キーワード指定子と併用することも出来ます。 -クラス宣言は、変数および/または関数宣言を格納します。これらはそれぞれ `UPROPERTY()` マクロと `UFUNCTION()` マクロがそれぞれ前にきます。 +クラス宣言は、変数および/または関数宣言を格納します。これらは `UPROPERTY()` マクロと `UFUNCTION()` マクロがそれぞれ前にきます。 こうしたマクロは `UCLASS()` マクロと似たような役割をします。コンポーネントは `UPROPERTY()` マクロでも設定されます。 `LightSwitchCodeOnly.h` ファイルでは、C++ は以下のように利用されます。 @@ -35,11 +35,11 @@ C++ コードのみを使用した「LightSwitch」クラスは LightSwitchCodeO つまりこれらのプロパティは LightSwitchCodeOnly アクタの **[Details (詳細)]** タブで見ることができます。 public: - /** point light コンポーネント*/ + /** point light component */ UPROPERTY(VisibleAnywhere, Category = "Switch Components") class UPointLightComponent* PointLight1; - /** sphere コンポーネント */ + /** sphere component */ UPROPERTY(VisibleAnywhere, Category = "Switch Components") class USphereComponent* Sphere1; * コンストラクタを宣言し、コンポーネントと変数に対してデフォルト値を設定できるようにします。: @@ -48,25 +48,25 @@ C++ コードのみを使用した「LightSwitch」クラスは LightSwitchCodeO * `OnOverlapBegin` と `OnOverlapEnd`を宣言します。こうした関数は別のアクタが Sphere コンポーネントに入るまたは離れる時に呼ばれます。これらは異なるシグネチャを持つことに注意してください。 - /** sphere コンポーネントに何かが入ると呼び出されます。 */ + /** called when something enters the sphere component (何かが sphere コンポーネントに入ると呼び出されます。)*/ UFUNCTION() - void OnOverlapBegin(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult); + void OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult); - /** sphere コンポーネントから何かが離れると呼び出されます。 */ + /** called when something leaves the sphere component (何かが sphere コンポーネントを離れると呼び出されます。) */ UFUNCTION() - void OnOverlapEnd(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex); + void OnOverlapEnd(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex); * `ToggleLight`は PointLightComponent の可視性を切り替える関数です。 - /** light コンポーネントの可視性を切り替えます。*/ + /** Toggles the light component's visibility (light コンポーネントの可視性を切り替えます)*/ UFUNCTION() void ToggleLight(); -* `DesiredBrightness` 変数を宣言して、`VisibleAnywhere` 指定子でどこにでも表示できるようにします。LightSwitchCodeOnly アクタの **[Details (詳細)]** タブで **[Switch Variables]** カテゴリに表示されます。 +* `DesiredIntensity` 変数を宣言して、`VisibleAnywhere` 指定子でどこにでも表示できるようにします。LightSwitchCodeOnly アクタの **[Details (詳細)]** タブで **[Switch Variables]** カテゴリに表示されます。 サブオブジェクトではない変数、例えばこの float 値などは、`VisibleAnywhere` 指定子によって変数が **[詳細]** タブに表示されるようにします。他にも使用可能なものとして、 `EditAnywhere` 指定子がありますが、 `DesiredIntensity` 変数はアクタがレベルへ追加された時のみ正しく使用されるため、変数は編集可能である必要はありません。 - /** ライトの望ましい強度 */ + /** the desired intensity for the light (ライトの望ましい明るさ) */ UPROPERTY(VisibleAnywhere, Category="Switch Variables") float DesiredIntensity; @@ -92,28 +92,28 @@ LightSwitchCodeOnly.h { GENERATED_BODY() public: - /** point light コンポーネント*/ + /** point light component */ UPROPERTY(VisibleAnywhere, Category = "Switch Components") class UPointLightComponent* PointLight1; - /** sphere コンポーネント */ + /** sphere component */ UPROPERTY(VisibleAnywhere, Category = "Switch Components") class USphereComponent* Sphere1; ALightSwitchCodeOnly(); - /** sphere コンポーネントに何かが入ると呼び出されます。 */ + /** called when something enters the sphere component (何かが sphere コンポーネントに入ると呼び出されます。)*/ UFUNCTION() - void OnOverlapBegin(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult); - /** sphere コンポーネントから何かが離れると呼び出されます。 */ + void OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult); + /** called when something leaves the sphere component (何かが sphere コンポーネントを離れると呼び出されます。) */ UFUNCTION() - void OnOverlapEnd(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex); + void OnOverlapEnd(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex); - /** light コンポーネントの可視性を切り替えます。*/ + /** Toggles the light component's visibility (light コンポーネントの可視性を切り替えます)*/ UFUNCTION() void ToggleLight(); - /** ライトの望ましい強度 */ + /** the desired intensity for the light (ライトの望ましい明るさ) */ UPROPERTY(VisibleAnywhere, Category = "Switch Variables") float DesiredIntensity; @@ -134,26 +134,26 @@ LightSwitchCodeOnly.h * `DesiredIntensity` 変数の値を 3000 に設定します。 DesiredIntensity = 3000.0f; -* PointLight コンポーネントを作成し、その変数を設定し (その強度を `DesiredIntensity` の値に設定することも含む)、そしてこれをルートコンポーネントとして利用します。 +* PointLight コンポーネントを作成し、その変数を設定し (その明るさを `DesiredIntensity` の値に設定することも含む)、それをルートコンポーネントにします。 PointLight1 = CreateDefaultSubobject(TEXT("PointLight1")); PointLight1->Intensity = DesiredIntensity; PointLight1->bVisible = true; RootComponent = PointLight1; -* Sphere コンポーネントの作成、変数の設定、そしてこれを PointLight コンポーネントにアタッチします。 +* Sphere コンポーネントを作成、変数を設定し、PointLight コンポーネントにアタッチします。 Sphere1 = CreateDefaultSubobject(TEXT("Sphere1")); Sphere1->InitSphereRadius(250.0f); - Sphere1->AttachParent = RootComponent; + Sphere1->SetupAttachment(RootComponent); * `OnOverlap` 関数をアクタが Sphere コンポーネントにオーバーラップした時、または Sphere コンポーネントから離れた時に呼ばれるデリゲートとして指定します。 - Sphere1->OnComponentBeginOverlap.AddDynamic(this, &ALightSwitchCodeOnly::OnOverlapBegin); // このコンポーネントが何かとオーバーラップした時の通知を設定します。 - Sphere1->OnComponentEndOverlap.AddDynamic(this, &ALightSwitchCodeOnly::OnOverlapEnd); // このコンポーネントが何かとオーバーラップした時の通知を設定します。 + Sphere1->OnComponentBeginOverlap.AddDynamic(this, &ALightSwitchCodeOnly::OnOverlapBegin); // set up a notification for when this component overlaps something (このコンポーネントが何かとオーバーラップした時の通知を設定します) + Sphere1->OnComponentEndOverlap.AddDynamic(this, &ALightSwitchCodeOnly::OnOverlapEnd); // set up a notification for when this component overlaps something (このコンポーネントが何かとオーバーラップした時の通知を設定します) -ソース ファイルにも、クラスのために宣言する関数を定義することができます。例えば、`LightSwitchCodeOnly.cpp` には、PointLight コンポーネントの可視性を切り替える `OnOverlapBegin` と `OnOverlapEnd` が実装されています。 -これは `ToggleLight` を呼び出すことで PointLightComponent の可視性を切り替えます。クラス コンストラクタと組み合わせるとソースファイルは以下のようになります。 +ソース ファイルにも、クラスのために宣言する関数を定義することができます。例えば、`LightSwitchCodeOnly.cpp` には、`ToggleLight` を呼び出すことでPointLight コンポーネントの可視性を切り替える `OnOverlapBegin` と `OnOverlapEnd` +が実装されています。クラス コンストラクタと組み合わせるとソースファイルは以下のようになります。 [REGION:codetitlebar] LightSwitchCodeOnly.cpp [/REGION:codetitlebar] @@ -174,14 +174,14 @@ LightSwitchCodeOnly.cpp Sphere1 = CreateDefaultSubobject(TEXT("Sphere1")); Sphere1->InitSphereRadius(250.0f); - Sphere1->AttachParent = RootComponent; + Sphere1->SetupAttachment(RootComponent); - Sphere1->OnComponentBeginOverlap.AddDynamic(this, &ALightSwitchCodeOnly::OnOverlapBegin); // このコンポーネントが何かとオーバーラップした時の通知を設定します。 - Sphere1->OnComponentEndOverlap.AddDynamic(this, &ALightSwitchCodeOnly::OnOverlapEnd); // このコンポーネントが何かとオーバーラップした時の通知を設定します。 + Sphere1->OnComponentBeginOverlap.AddDynamic(this, &ALightSwitchCodeOnly::OnOverlapBegin); // set up a notification for when this component overlaps something (このコンポーネントが何かとオーバーラップした時の通知を設定します) + Sphere1->OnComponentEndOverlap.AddDynamic(this, &ALightSwitchCodeOnly::OnOverlapEnd); // set up a notification for when this component overlaps something (このコンポーネントが何かとオーバーラップした時の通知を設定します) } - void ALightSwitchCodeOnly::OnOverlapBegin(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult) + void ALightSwitchCodeOnly::OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult) { if (OtherActor && (OtherActor != this) && OtherComp) { @@ -189,7 +189,7 @@ LightSwitchCodeOnly.cpp } } - void ALightSwitchCodeOnly::OnOverlapEnd(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex) + void ALightSwitchCodeOnly::OnOverlapEnd(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex) { if (OtherActor && (OtherActor != this) && OtherComp) { @@ -206,14 +206,14 @@ LightSwitchCodeOnly.cpp `BasicClasses.h` は、そのクラスがセットアップされたプロジェクト名を参照しています。 [/Region] -これがブランク オブジェクトに追加した最初のコード クラスである場合は、エディタを閉じて、Visual Studio または Xcode でプロジェクトをコンパイルした後に、 - エディタを開いてプロジェクトを再び開きゲームモジュールが適切に作成され再ロードされていることを確認します。プロジェクトを開くために使用しているアンリアル エディタの実行ファイルのバージョンが **Build Configuration** と同じであることの確認も重要となります。[](Programming\Development\CompilingProjects) のドキュメントで -Build Configuration とプロジェクトのコンパイルに関する情報を参照してください。 +これが空のプロジェクトに追加した最初のコード クラスである場合は、エディタを閉じて、Visual Studio または Xcode でプロジェクトをコンパイルした後に、エディタを開いてプロジェクトを再び開く必要があります。 + ゲームモジュールが適切に作成されて再ロードされていることを確認するためです。プロジェクトを開くために使用しているアンリアル エディタの実行ファイルのバージョンが **Build Configuration** と同じであることの確認も重要となります。ビルド設定とプロジェクトのコンパイルに関する詳細は、 +[](Programming\Development\CompilingProjects) ページをご覧ください。 コードを既存の C++ プロジェクトに追加する場合は、ホットリロード機能を使用してエディタ内で新規コードをコンパイルすることができます。 -C++ クラスは、C++ クラスに加えてブループリント クラスで拡張することができます。**[C++ Class Wizard]** の **[Show All Classes]** チェックボックスのチェックを入れた後、およびブループリント クラスの作成時に、 +C++ クラスは、C++ クラスに加えてブループリント クラスで拡張することができます。**C++ Class Wizard** の **Show All Classes** チェックボックスのチェックを入れた後、およびブループリント クラスの作成時に、 **[Pick Parent Class]** ウィンドウの **[Custom Classes]** セクションの **[Show All Classes]** にチェックを入れた後に表示されます。 -「LightSwitchCodeOnly」クラスは、[](Engine/UI/ClassViewer) に格納されて、ここからレベルへドラッグすることができます。クラスビューア を使用したレベルでのアクタの配置については、[](Engine/Actors/Placement) のドキュメントをご覧ください。 +「LightSwitchCodeOnly」クラスは、[](Engine/UI/ClassViewer) に格納されて、ここからレベルへドラッグすることができます。クラスビューアを使用したレベルでのアクタの配置については、[](Engine/Actors/Placement) のドキュメントをご覧ください。 diff --git a/Engine/Documentation/Source/Gameplay/DataDriven/DataDrivenGameplay.INT.udn b/Engine/Documentation/Source/Gameplay/DataDriven/DataDrivenGameplay.INT.udn index b120c8f395c4..097517aa6fef 100644 --- a/Engine/Documentation/Source/Gameplay/DataDriven/DataDrivenGameplay.INT.udn +++ b/Engine/Documentation/Source/Gameplay/DataDriven/DataDrivenGameplay.INT.udn @@ -1,10 +1,12 @@ Availability:Public Title: Data Driven Gameplay Elements -Crumbs:%ROOT%, Gameplay +Crumbs:%ROOT% Description:Driving gameplay elements using externally stored data. version: 4.9 +type:reference +tags:Gameplay -[TOC(start:2)] +[toc(start:2 end:2)] Data driven gameplay helps mitigate the amount of work and complexity involved, as well as providing the ability to visualize and parameterize data creation and progression, for games that have an extended diff --git a/Engine/Documentation/Source/Gameplay/DataDriven/DataDrivenGameplay.JPN.udn b/Engine/Documentation/Source/Gameplay/DataDriven/DataDrivenGameplay.JPN.udn index 9f5acc347365..5c6e8fbf1a74 100644 --- a/Engine/Documentation/Source/Gameplay/DataDriven/DataDrivenGameplay.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/DataDriven/DataDrivenGameplay.JPN.udn @@ -1,11 +1,13 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3401080 Availability:Public Title:データ駆動型のゲームプレイエレメント -Crumbs:%ROOT%, Gameplay +Crumbs:%ROOT% Description:外部に保存されたデータを使用するゲームプレイ エレメントの操作 version:4.9 +type:reference +tags:Gameplay -[TOC(start:2)] +[toc(start:2 end:2)] データ駆動型ゲームプレイは、一般的なボックス型ゲームの寿命をはるかに上回るゲームで、 プレイヤーのフィードバックに基づきデータの微調整やバランスを取る必要がある場合、 diff --git a/Engine/Documentation/Source/Gameplay/DataDriven/DataDrivenGameplay.KOR.udn b/Engine/Documentation/Source/Gameplay/DataDriven/DataDrivenGameplay.KOR.udn index 377716a05d9a..d86f75b3ecef 100644 --- a/Engine/Documentation/Source/Gameplay/DataDriven/DataDrivenGameplay.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/DataDriven/DataDrivenGameplay.KOR.udn @@ -1,11 +1,13 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3401080 Availability:Public Title: 데이터 주도형 게임플레이 요소 -Crumbs:%ROOT%, Gameplay +Crumbs:%ROOT% Description:외부 저장 데이터를 사용하여 게임플레이 요소를 구동시키는 법입니다. version: 4.9 +type:reference +tags:Gameplay -[TOC(start:2)] +[toc(start:2 end:2)] 데이터 주도형 게임플레이는 전형적인 패키지 게임보다 훨씬 수명이 긴 게임이나, 플레이어 피드백에 따라 데이터의 지속적인 트윅 및 밸런싱 작업이 필요한 게임에 관련된 diff --git a/Engine/Documentation/Source/Gameplay/ForceFeedback/ForceFeedback.INT.udn b/Engine/Documentation/Source/Gameplay/ForceFeedback/ForceFeedback.INT.udn index dd4e7899c052..4e50433aa40b 100644 --- a/Engine/Documentation/Source/Gameplay/ForceFeedback/ForceFeedback.INT.udn +++ b/Engine/Documentation/Source/Gameplay/ForceFeedback/ForceFeedback.INT.udn @@ -1,11 +1,16 @@ Availability:Public Title: Force Feedback and the Force Feedback Component -Crumbs:%ROOT%, Gameplay +Crumbs:%ROOT% Description: Using the vibration functionality of mobile devices and controllers to convey a force occuring in the game to the player. Parent:Gameplay +Order: Related: Engine/Blueprints/UserGuide/Components +Related: Engine/UI/CurveEditor +Related: Engine/Blueprints/UserGuide/Timelines/KeysAndCurves version: 4.15 - +type:overview +tags:Gameplay +topic-image: force_feedback_topic [VAR:Topic] [OBJECT:Topic] @@ -41,10 +46,10 @@ version: 4.15 [/OBJECT] [/VAR] -[TOC] +[toc(start:1 end:2)] [EXCERPT:WhatIsForceFeedback] -**Force Feedback** (sometimes referred to as rumble or haptic feedback) refers to the vibrating of a device or controller used in games to convey a force occuring in the game to the player. A simple example is when an explosion occurs in the game and force feedback is used to simulate the shockwave, which gives an additional dimension to the immersion. +Sometimes being called "rumble" or controller vibration, Force Feedback refers to the vibration of a device (such as gamepads or controllers), often being used in games to convey a force occurring in the game to the player. A simple example is when an explosion occurs in the game and force feedback is used to simulate the shockwave, which gives an additional dimension to a player's immersion. [/EXCERPT:WhatIsForceFeedback] Once implemented, Force Feedback will work on all platforms where it is supported. This includes iOS (as of 4.10), Android, and controllers. @@ -55,7 +60,13 @@ A **Force Feedback Effect Asset** contains the properties used to define a speci ![image alt text](image_0.png)(w:640 convert:false) -Each Force Feedback Effect can have multiple channels, each of which can play a diferent effect. For instance, one channel could play one large, long vibration on the right side of the controller while a second channel could play small, short bursts on the left side. The pattern of the effect for each channel is controlled by a curve. +Each Force Feedback Effect can have multiple channels, each of which can play a different effect. For instance, one channel could play a large, long vibration on the right side of the controller, while a second channel could play small, short bursts on the left side. The pattern of the effect for each channel is controlled by a curve. This curve can be edited here with right-click, or the internal curve editor can be opened by double-clicking in the curve's graph. + +![Internal Curve Editor](CurveEditor.png) + +[REGION:tip] +For information on Curves, Keys, creating external Curve Assets, and using the Curve Editor, check out the [](Engine/UI/CurveEditor/) and [](Engine/Blueprints/UserGuide/Timelines/KeysAndCurves/) pages. +[/REGION] The duration of the force feedback effect will be calculated automatically, based on the position of the last key in the curves for all channels. For example, if there are 3 channels and the last key in each is at 1.25, 1.5, and 1.75, then the duration for the overall effect will be 1.75. @@ -68,16 +79,20 @@ Each channel has the following properties that control how the effect for the ch | **Affects Left Large** | If true, the left large motor will be used to play the effect. | | **Affects Left Small** | If true, the left small motor will be used to play the effect. | | **Affects Right Large** | If true, the right large motor will be used to play the effect. | -| **Affects Right Large** | If true, the right small motor will be used to play the effect. | +| **Affects Right Small** | If true, the right small motor will be used to play the effect. | | **Curve** | A curve that controls the intensity of the effect over time. In other words, this defines the pattern of the vibration. Values above 0.5 will vibrate, while values below 0.5 will not vibrate. | ## Creating a Force Feedback Effect Asset Force Feedback Effect assets are created using the **Content Browser**: -1. In the **Content Browser**, click **Add New** and choose **Miscellaneous > Force Feedback Effect**. By default, the asset will have one channel, but you can add more. +1. In the **Content Browser**, click **Add New** and choose **Miscellaneous > Force Feedback Effect**, and open the asset you have just created. -1. Select whether the force feedback affects the left and/or right of the device, as well as whether it's large or small on either side. + ![](CreateForceFeedbackEffect.png) + +1. By default, the asset will have one channel but you can add more. For each channel, select the combination of the four outputs that the channel will affect. + + ![](FFChannels.png) 1. Hold **Shift** and click the **Left Mouse Button** on the curve to add one or more keys. @@ -86,22 +101,28 @@ Force Feedback Effect assets are created using the **Content Browser**: 1. Manipulate the keys by entering values directly or dragging them in the curve editor. [REGION:note] - Unlike in other curve editors, the keys can only be connected by straight lines. + To adjust the curves between the keys, right-click on the curve segment to change its curve function, then adjust the tangent lines as usual. [/REGION] ## Playing Force Feedback -### Directly To A Player +### Preview in Editor -Force Feedback is implemented in the base PlayerController class. You will need access to the local Player Controller in order to play the force feedback on the target device or controller. +You can preview your Force Feedback Effect in the editor by clicking the "play" button that appears in the middle of the Force Feedback Effect's icon when you mouse over it. -**Playing Force Feedback in Blueprints:** +![](PreviewForceFeedbackEffect.png) + +### Directly to a Player + +Force Feedback is implemented in the base `PlayerController` class. You will need access to the local Player Controller in order to play Force Feedback on the target device or controller. + +####Playing Force Feedback in Blueprints 1. Get a reference to your Player Controller, either with a **Get Player Controller** node or a saved reference. ![](effect_controller.png)(w:640) -1. Drag off of the output pin of the reference, then type _Play Force Feedback_ into the context menu and select **Client Play Force Feedback**. +1. Drag off of the output pin of the reference, then type `Play Force Feedback` into the context menu and select **Client Play Force Feedback**. ![](effect_play.png)(w:640) @@ -117,15 +138,15 @@ Force Feedback is implemented in the base PlayerController class. You will need ![](effect_looping.png)(w:640) -1. Optionally, set a tag for the effect. The tag allows you to stop the effect; if an effect with the same tag is already playing, it will be stopped and the new effect will play instead. +1. Optionally, set a unique name for the effect via the Tag field. This feature allows you to stop the effect; if an effect with the same name is already playing, it will be stopped and the new effect will play instead. ![](effect_tag.png)(w:640) -**Playing Force Feedback in C++:** +#### Playing Force Feedback in C++ -Call [](API:APlayerController::ClientPlayForceFeedback) on the local Player Controller, passing it the Force Feedback Effect to use as well as whether or not the effect should loop, and an optional tag for the effect. If a tag is provided, and another Force Feedback Effect with the same tag is played before the original effect ends, the original will be stopped immediately and the new effect will play instead. +Call `ClientPlayForceFeedback` on the local Player Controller, passing it the Force Feedback Effect to use as well as whether or not the effect should loop, and an optional name for the effect. If a name is provided, and another Force Feedback Effect with the same name is played before the original effect ends, the original will be stopped immediately and the new effect will play instead. -### At A World Location +### At a World Location To play a Force Feedback Effect that changes intensity based on distance from the observing player, place a **Force Feedback Component** in the world at the intended source of the effect. A Force Feedback component plays a Force Feedback Effect on command, but also has a physical location in the world. Like sound or light, the intensity of the force experienced by the player will change with the player's distance from the source, according to a data-defined attenuation setting. diff --git a/Engine/Documentation/Source/Gameplay/ForceFeedback/ForceFeedback.JPN.udn b/Engine/Documentation/Source/Gameplay/ForceFeedback/ForceFeedback.JPN.udn index 263dca1aa70f..c25fdc135468 100644 --- a/Engine/Documentation/Source/Gameplay/ForceFeedback/ForceFeedback.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/ForceFeedback/ForceFeedback.JPN.udn @@ -1,12 +1,17 @@ -INTSourceChangelist:3340410 +INTSourceChangelist:3411855 Availability:Public Title:フォース フィードバックと Force Feedback コンポーネント -Crumbs:%ROOT%, Gameplay +Crumbs:%ROOT% Description:モバイル デバイスとコントローラーのバイブレーション機能を使用して、ゲーム内で起こる力をプレイヤーに伝えます。 Parent:Gameplay +Order: Related:Engine/Blueprints/UserGuide/Components +Related:Engine/UI/CurveEditor +Related:Engine/Blueprints/UserGuide/Timelines/KeysAndCurves version:4.15 - +type:overview +tags:Gameplay +topic-image: force_feedback_topic [VAR:Topic] [OBJECT:Topic] @@ -42,10 +47,10 @@ version:4.15 [/OBJECT] [/VAR] -[TOC] +[toc(start:1 end:2)] [EXCERPT:WhatIsForceFeedback] -**フォースフィードバック** (振動フィードバックまたは触覚 (ハプティック) フィードバックともいう) とは、ゲーム内で起こる力をプレイヤーに伝えるためにゲームで使用するデバイスやコントローラーを振動させることをいいます。単純な例としては、ゲーム内で爆発が起きた場合にフォース フィードバックを使って衝撃波をシミュレートすることで、没入感に新たな奥行きを与えます。 +フォースフィードバック (振動またはコントローラーの振動ともいう) とは、デバイス (ゲームパッドやコントローラーなど) の振動を表します。多くの場合、ゲーム内で起こる力をプレイヤーに伝えるために使用されます。単純な例としては、ゲーム内で爆発が起きた場合にフォース フィードバックを使って衝撃波をシミュレートすることで、プレイヤーの没入感に新たな奥行きを与えます。 [/EXCERPT:WhatIsForceFeedback] 一度実装すると、フォースフィードバックはサポートされる全プラットフォームで機能します。これには、 iOS (4.10 時点)、Android、およびコントローラーが含まれます。 @@ -56,7 +61,13 @@ version:4.15 ![image alt text](image_0.png)(w:640 convert:false) -各フォースフィードバック エフェクトには、複数のチャンネルがあり、それぞれが異なるエフェクトを再生することができます。例えば、あるチャンネルではコントローラーの右側でひとつの大きな長い振動を再生します。一方、もうひとつのチャンネルでは、小さな短いバーストを左側で再生します。各チャンネルのエフェクトのパターンは、カーブによって制御されます。 +各フォースフィードバック エフェクトには、複数のチャンネルがあり、それぞれが異なるエフェクトを再生することができます。例えば、あるチャンネルではコントローラーの右側で大きな長い振動を再生します。一方、もうひとつのチャンネルでは、小さな短いバーストを左側で再生します。各チャンネルのエフェクトのパターンは、カーブによって制御されます。このカーブは右クリックで編集できます。またはカーブのグラフ内でダブルクリックすると内部のカーブを開くことができます。 + +![Internal Curve Editor](CurveEditor.png) + +[REGION:tip] +カーブ、キー、外部のカーブ アセットの作成、カーブ エディタの使用については、[](Engine/UI/CurveEditor/) および [](Engine/Blueprints/UserGuide/Timelines/KeysAndCurves/) のページをご覧ください。 +[/REGION] フォースフィードバック エフェクトの持続時間は、すべてのチャンネルのカーブの最後のキーの位置に基づき自動的に計算されます。例えば、3 つのチャンネルがあり、それぞれの最後のキーが 1.25、 1.5、 および 1.75 にあるとします。この場合、全体的なエフェクトの持続時間は 1.75 になります。 @@ -69,16 +80,20 @@ version:4.15 | **Affects Left Large** | true の場合、左側の大きなモーターを使用してエフェクトを再生します。 | | **Affects Left Small** | true の場合、左側の小さなモーターを使用してエフェクトを再生します。 | | **Affects Right Large** | true の場合、右側の大きなモーターを使用してエフェクトを再生します。 | -| **Affects Right Large** | true の場合、右側の小さなモーターを使用してエフェクトを再生します。 | +| **Affects RightSmall** | true の場合、右側の小さなモーターを使用してエフェクトを再生します。 | | **Curve** | 時間経過に伴いエフェクトの強度を制御するカーブです。つまり、振動のパターンを定義します。0.5 より大きいと振動し、0.5 より小さいと振動しません。 | ## Force Feedback Effect アセットの作成 Force Feedback Effect アセットは、以下のように **コンテンツ ブラウザ** を使用して作成します。 -1. **コンテンツ ブラウザ** で **[Add New (新規追加)]** をクリックして **Miscellaneous > Force Feedback Effect** の順に選択します。デフォルトでは、このアセットはひとつのチャンネルを持ちますが、さらに追加することができます。 +1. **コンテンツ ブラウザ** で **[Add New (新規追加)]** をクリックして **Miscellaneous > Force Feedback Effect** の順に選択し、作成したばかりのアセットを開きます。 -1. フォースフィードバックがデバイスの左および/または右に影響を及ぼすかを選択するとともに、いずれかの側で大きくなるか、または小さくなるかを選択します。 + ![](CreateForceFeedbackEffect.png) + +1. デフォルトでは、このアセットはひとつのチャンネルを持ちますが、さらに追加することができます。各チャンネルに対して、そのチャンネルが影響を及ぼす 4 つの出力の組み合わせを選択します。 + + ![](FFChannels.png) 1. **Shift** キーを押しながら、カーブ上で **左クリック** し、ひとつ以上のキーを追加します。 @@ -87,22 +102,28 @@ Force Feedback Effect アセットは、以下のように **コンテンツ ブ 1. カーブ エディタに直接値を入力するか、値をドラッグすることによりキーを操作します。 [REGION:note] - 他のカーブ エディタとは異なり、キーは直線でのみ接続することができます。 + キー間のカーブを調整するにはカーブのセグメント上で右クリックしてカーブの関数を変更してから通常どおりにタンジェントのラインを調整します。 [/REGION] ## フォースフィードバックの再生 +### エディタでプレビュー + +Force Feedback Effect のアイコンにマウスをかざすと表示される [プレイ] ボタンをクリックすると、フォース フィードバック エフェクトをエディタでプレビューすることができます。 + +![](PreviewForceFeedbackEffect.png) + ### プレイヤーに対して直接 -フォースフィードバックは、基本クラスの PlayerController で実装します。ターゲット デバイスやコントローラーでフォースフィードバックを再生するには、ローカルのプレイヤー コントローラーにアクセスする必要があります。 +フォースフィードバックは、基本クラスの `PlayerController` で実装します。ターゲット デバイスやコントローラーでフォースフィードバックを再生するには、ローカルのプレイヤー コントローラーにアクセスする必要があります。 -**ブループリントでフォースフィードバックを再生する手順は以下の通りです。** +####ブループリントでフォースフィードバックを再生する手順は以下の通りです。 1. プレイヤー コントローラーへの参照を、**Get Player Controller** ノードまたは保存した参照を用いて取得します。 ![](effect_controller.png)(w:640) -1. 参照の出力ピンをドラッグして、コンテキスト メニューに _Play Force Feedback_ と入力して **Client Play Force Feedback** を選択します。 +1. 参照の出力ピンをドラッグして、コンテキスト メニューに `Play Force Feedback` と入力して **Client Play Force Feedback** を選択します。 ![](effect_play.png)(w:640) @@ -118,15 +139,15 @@ Force Feedback Effect アセットは、以下のように **コンテンツ ブ ![](effect_looping.png)(w:640) -1. オプションで、このエフェクトにタグを設定します。タグを使用するとエフェクトを停止できます。同じタグを持つエフェクトが既に再生中であれば、停止させ、代わりに新しいエフェクトが再生されます。 +1. オプションで、Tag 欄を使ってこのエフェクトに一意の名前を付けます。この機能では、同じ名前を持つエフェクトが既に再生中であれば、停止させ、代わりに新しいエフェクトが再生されます。 ![](effect_tag.png)(w:640) -**C++ でフォースフィードバックを再生する手順は以下の通りです。** +####C++ でフォースフィードバックを再生する -ローカルのプレイヤー コントローラー上で [](API:APlayerController::ClientPlayForceFeedback) を呼び出し、使用するフォースフィードバック エフェクトを渡し、エフェクトがループすべきかどうか、およびオプションのタグも渡します。タグが指定されていて、オリジナルのエフェクトが終了する前に同じタグを持つ別のフォース フィードバック エフェクトが再生されていたら、オリジナルのエフェクトはただちに終了し、この新しいエフェクトが代わりに再生されます。 +ローカルのプレイヤー コントローラー上で `ClientPlayForceFeedback` を呼び出し、使用するフォースフィードバック エフェクトを渡し、エフェクトがループすべきかどうか、およびエフェクトのオプションの名前も渡します。名前が指定されていて、オリジナルのエフェクトが終了する前に同じ名前を持つ別のフォース フィードバック エフェクトが再生されると、オリジナルのエフェクトはただちに終了し、この新しいエフェクトが代わりに再生されます。 -### ワールドの位置で +### ワールドの位置 見ているプレイヤーからの距離に応じて強さが変化するフォース フィードバック エフェクトを再生するには、エフェクトのソースにしたい場所に **Force Feedback コンポーネント** を配置します。Force Feedback コンポーネントは、指示に従いフォース フィードバック エフェクトを再生しますが、ワールドで物理的位置も持ちます。サウンドや光のように、プレイヤーが感じる力の強さはプレイヤーがソースからどれくらい離れているかによってデータで定義されている減衰設定に従い変化します。 diff --git a/Engine/Documentation/Source/Gameplay/ForceFeedback/ForceFeedback.KOR.udn b/Engine/Documentation/Source/Gameplay/ForceFeedback/ForceFeedback.KOR.udn index cf50ae57e1b3..0c9fafa46d06 100644 --- a/Engine/Documentation/Source/Gameplay/ForceFeedback/ForceFeedback.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/ForceFeedback/ForceFeedback.KOR.udn @@ -1,12 +1,17 @@ -INTSourceChangelist:3340410 +INTSourceChangelist:3411855 Availability:Public Title: 포스 피드백 및 포스 피드백 컴포넌트 -Crumbs:%ROOT%, Gameplay -Description: 모바일 디바이스와 콘트롤러의 진동 기능을 사용하여 플레이어에게 게임의 포스를 전달하는 방법입니다. +Crumbs:%ROOT% +Description: 모바일 디바이스와 컨트롤러의 진동 기능을 사용하여 플레이어에게 게임의 포스를 전달하는 방법입니다. Parent:Gameplay +Order: Related: Engine/Blueprints/UserGuide/Components +Related: Engine/UI/CurveEditor +Related: Engine/Blueprints/UserGuide/Timelines/KeysAndCurves version: 4.15 - +type:overview +tags:Gameplay +topic-image: force_feedback_topic [VAR:Topic] [OBJECT:Topic] @@ -42,13 +47,13 @@ version: 4.15 [/OBJECT] [/VAR] -[TOC] +[toc(start:1 end:2)] [EXCERPT:WhatIsForceFeedback] -**Force Feedback** (가끔은 진동 또는 햅틱 피드백이라고도 하는 포스 피드백)은 게임에서 사용되는 디바이스 또는 콘트롤러의 진동을 통해 게임에서 일어나는 힘의 느낌을 플레이어에게 전달하는 것을 말합니다. 간단한 예제라면, 게임에서 폭발이 일어났을 때 포스 피드백을 사용하여 충격파 시뮬레이션을 하면, 한 층 더 높은 몰입감을 낼 수 있습니다. +**Force Feedback** (가끔은 "럼블" 또는 컨트롤러 진동이라고도 하는 포스 피드백)은 게임에서 사용되는 디바이스(게임패드나 컨트롤러)의 진동을 통해 게임에서 일어나는 힘의 느낌을 플레이어에게 전달하는 것을 말합니다. 간단한 예제라면, 게임에서 폭발이 일어났을 때 포스 피드백을 사용하여 충격파 시뮬레이션을 하면, 한 층 더 높은 몰입감을 낼 수 있습니다. [/EXCERPT:WhatIsForceFeedback] -구현하고 나면, 포스 피드백은 지원되는 모든 플랫폼에서 작동합니다. (4.10 이후로) iOS, 안드로이드, 콘트롤러가 포함됩니다. +구현하고 나면, 포스 피드백은 지원되는 모든 플랫폼에서 작동합니다. (4.10 이후로) iOS, 안드로이드, 컨트롤러가 포함됩니다. ## 포스 피드백 이펙트 애셋 @@ -56,7 +61,13 @@ version: 4.15 ![image alt text](image_0.png)(w:640 convert:false) -각 포스 피드백 이펙트는 여러 채널을 가질 수 있으며, 각 채널마다 각기 다른 이펙트를 재생할 수 있습니다. 예를 들어 한 채널에서는 콘트롤러 오른쪽에 크고 긴 진동을 내는 반면, 두 번째 채널에서는 왼쪽에 작고 짧은 파동을 재생할 수 있습니다. 각 채널의 이펙트 패턴은 커브에 의해 제어됩니다. +각 포스 피드백 이펙트는 여러 채널을 가질 수 있으며, 각 채널마다 각기 다른 이펙트를 재생할 수 있습니다. 예를 들어 한 채널에서는 컨트롤러 오른쪽에 크고 긴 진동을 내는 반면, 두 번째 채널에서는 왼쪽에 작고 짧은 파동을 재생할 수 있습니다. 각 채널의 이펙트 패턴은 커브에 의해 제어됩니다. 이 커브는 여기서 우클릭으로 편집할 수 있으며, 커브의 그래프에 더블클릭하여 내부 커브 에디터를 열 수도 있습니다. + +![내부 커브 에디터](CurveEditor.png) + +[REGION:tip] +커브, 키, 외부 커브 애셋 생성, 커브 에디터 사용법 관련 정보는 [](Engine/UI/CurveEditor/) 및 [](Engine/Blueprints/UserGuide/Timelines/KeysAndCurves/) 문서를 참고하세요. +[/REGION] 포스 피드백 이펙트 기간은, 모든 채널의 커브 내 마지막 키의 위치에 따라 자동 계산됩니다. 예를 들어 채널이 세 개 있고 각각의 마지막 키 위치가 1.25, 1.5, 1.75 인 경우, 전체 이펙트의 기간은 1.75 가 됩니다. @@ -76,9 +87,13 @@ version: 4.15 포스 피드백 이펙트 애셋은 **콘텐츠 브라우저** 에서 생성합니다: -1. **콘텐츠 브라우저** 에서 **신규 추가** - **기타 > 포스 피드백 이펙트** 를 선택하면 됩니다. 기본적으로 애셋에는 채널이 하나지만, 추가할 수 있습니다. +1. **콘텐츠 브라우저** 에서 **신규 추가** - **기타 > 포스 피드백 이펙트** 를 선택하고 방금 만든 애셋을 엽니다. -1. 포스 피드백이 디바이스의 왼쪽 및/또는 오른쪽 어디에 영향을 끼칠지와, 각각 큰 모터 또는 작은 모터를 사용할지 선택합니다. + ![](CreateForceFeedbackEffect.png) + +1. 기본적으로 애셋에는 채널이 하나지만 추가할 수 있습니다. 각 채널에 대해 채널이 영향을 주는 네 개의 출력 조합을 선택합니다. + + ![](FFChannels.png) 1. 커브에 **Shift** 키를 누르고 **좌클릭** 하면 키를 하나 이상 추가할 수 있습니다. @@ -87,22 +102,28 @@ version: 4.15 1. 값을 직접 입력하거나 커브 에디터에서 수정하여 키를 조정합니다. [REGION:note] - 다른 커브 에디터와는 달리, 여기서 키는 직선으로만 연결 가능합니다. + 키 사이 커브 조정을 위해서는, 커브 선분에 우클릭하여 커브 함수를 변경한 뒤, 평소처럼 탄젠트 라인을 조정합니다. [/REGION] ## 포스 피드백 재생 +### 에디터에서 프리뷰 + +포스 피드백 이펙트의 아이콘에 마우스 커서를 올리면 가운데 나타나는 "play" (재생) 버튼을 클릭하면 에디터에서 포스 피드백 이펙트를 미리볼 수 있습니다. + +![](PreviewForceFeedbackEffect.png) + ### 플레이어에 바로 -포스 피드백은 베이스 PlayerController 클래스에서 구현됩니다. 타겟 디바이스나 콘트롤러에서 포스 피드백을 재생하려면, 로컬 플레이어 콘트롤러에 접근할 수 있어야 합니다. +포스 피드백은 베이스 PlayerController 클래스에서 구현됩니다. 타겟 디바이스나 컨트롤러에서 포스 피드백을 재생하려면, 로컬 플레이어 컨트롤러에 접근할 수 있어야 합니다. -**블루프린트에서 포스 피드백 재생:** +####블루프린트에서 포스 피드백 재생 -1. 플레이어 콘트롤러로의 레퍼런스를 구합니다. **Get Player Controller** 노드나 저장된 노드면 됩니다. +1. 플레이어 컨트롤러로의 레퍼런스를 구합니다. **Get Player Controller** 노드나 저장된 노드면 됩니다. ![](effect_controller.png)(w:640) -1. 레퍼런스의 출력 핀을 끌어 놓은 다음, 맥락 메뉴에 _Play Force Feedback_ 이라 입력하고 **Client Play Force Feedback** 을 선택합니다. +1. 레퍼런스의 출력 핀을 끌어 놓은 다음, 맥락 메뉴에 `Play Force Feedback` 이라 입력하고 **Client Play Force Feedback** 을 선택합니다. ![](effect_play.png)(w:640) @@ -118,13 +139,13 @@ version: 4.15 ![](effect_looping.png)(w:640) -1. 옵션으로, 이펙트에 태그 설정 기능이 있습니다. 같은 태그의 이펙트가 이미 재생중인 경우, 먼저 것은 중지되고 새로운 이펙트가 대신 재생됩니다. +1. 옵션으로, Tag 칸을 통해 이펙트에 고유 이름을 설정합니다. 이 기능으로 이펙트 중지가 가능한데, 같은 태그의 이펙트가 이미 재생중인 경우, 먼저 것은 중지되고 새로운 이펙트가 대신 재생됩니다. ![](effect_tag.png)(w:640) -**C++ 에서 포스 피드백 재생:** +####C++ 에서 포스 피드백 재생 -로컬 플레이어 콘트롤러에서 [](API:APlayerController::ClientPlayForceFeedback) 를 호출하되, 사용할 포스 피드백 이펙트 뿐 아니라 이펙트의 루핑 여부, 태그 옵션까지도 전달해 줍니다. 태그가 제공되고, 원래 이펙트가 끝나기 전 태그가 같은 포스 피드백 이펙트가 추가 재생되면, 원본은 즉시 중지하고 새로운 이펙트를 대신 재생합니다. +로컬 플레이어 컨트롤러에서 `ClientPlayForceFeedback` 을 호출하되, 사용할 포스 피드백 이펙트 뿐 아니라 이펙트의 루핑 여부, 옵션으로 이름도 전달해 줍니다. 이름이 제공되고, 원래 이펙트가 끝나기 전 이름이 같은 포스 피드백 이펙트가 추가 재생되면, 원본은 즉시 중지하고 새로운 이펙트를 대신 재생합니다. ### 월드 위치에서 diff --git a/Engine/Documentation/Source/Gameplay/Framework/Camera/Camera.INT.udn b/Engine/Documentation/Source/Gameplay/Framework/Camera/Camera.INT.udn index a1c90684e919..e00f2b8a9783 100644 --- a/Engine/Documentation/Source/Gameplay/Framework/Camera/Camera.INT.udn +++ b/Engine/Documentation/Source/Gameplay/Framework/Camera/Camera.INT.udn @@ -3,10 +3,11 @@ Title:Camera Crumbs:%ROOT%, Gameplay, Gameplay/Framework Description:The Camera represents the player's point of view; how the player sees the world. Version: 4.9 -type:reference +type:overview parent:Gameplay/Framework -order:6 +order:5 tags:Gameplay Framework +topic-image:Gameplay/Framework/camera_lander.png The **Camera** represents the player's point of view; how the player sees the world. For this reason, cameras only have relevance to human-controlled players. The **PlayerController** specifies a camera class diff --git a/Engine/Documentation/Source/Gameplay/Framework/Camera/Camera.JPN.udn b/Engine/Documentation/Source/Gameplay/Framework/Camera/Camera.JPN.udn index ba502fefe852..1b36d0c1c62b 100644 --- a/Engine/Documentation/Source/Gameplay/Framework/Camera/Camera.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/Framework/Camera/Camera.JPN.udn @@ -1,13 +1,14 @@ -INTSourceChangelist:2735872 +INTSourceChangelist:3429254 Availability:Public Title:カメラ Crumbs:%ROOT%, Gameplay, Gameplay/Framework Description:カメラは、ワールドを見るプレーヤーの視点を表します。 Version:4.9 -type:reference +type:overview parent:Gameplay/Framework -order:6 +order:5 tags:Gameplay Framework +topic-image:Gameplay/Framework/camera_lander.png **Camera (カメラ)** は、プレーヤーがどのようにワールドを見ているのか、プレーヤーの視点を表します。従って カメラは人が制御するプレーヤーのみに関連性をもちます。**PlayerController** は Camera クラスを指定し、 @@ -34,11 +35,11 @@ CameraComponentで、カメラを [パースペクティブ] モードまたは ## PlayerCameraManager -**PlayerCameraManager** クラスは、カメラ マネージャーです。デフォルトでは、ビルトインされている動作により、ペンディングしているビューターゲットとコンソールのコマンドでトリガーされるデバッグカメラがブレンドされます。デフォルトでない場合は、カメラのビューポイントおよび +**PlayerCameraManager** クラスは、カメラ マネージャーです。デフォルトでは、ビルトインされている動作は、ペンディングしているビューターゲットとコンソールのコマンドでトリガーされるデバッグ用のカメラがブレンドされます。デフォルトでない場合は、カメラのビューポイントおよび 他の全てのカメラ設定をどうするかを ViewTarget にクエリーします。通常は PlayerCameraManager サブクラスは不要です。 自動ルールでは不十分な場合、ViewTarget を設定するルールを追加する以外は、PlayerCameraManager への変更はほとんど必要ありません。 -PlayerCameraManager のサブクラス化が必要で、これを C++コードではなくブループリントで行う場合、カメラのカスタム実装に `BlueprintUpdateCamera` 関数を使用します。この関数を使用する場合、 +PlayerCameraManager のサブクラス化が必要で、これを C++コードではなくブループリントで行う場合、カメラのカスタム実装に `BlueprintUpdateCamera` 関数を使用します。_絶対的_ トランスフォーム 戻り値を使用するために _true_ を返し、戻り値を無視するために _false_ を返します。 ### ViewTarget @@ -54,7 +55,7 @@ PlayerCameraManager はカメラのマネージメント中に 2 つのカメラ ゲーム固有のカメラ動作は、カメラの「responsibility chain (責任の連鎖) 」に沿ってどの時点でも提供することができます。これは、以下のクラスを通って一番上から下に流れてから、ALocalPlayer へ渡され、レンダリング、シーン表示、そして関連システムで終了します。 -### CameraComponent +### Camera コンポーネント ViewTarget が CameraActor または **CameraComponent** を含み bFindCameraComponentWhenViewTarget が _true_ に設定されているアクタである場合、 CameraComponent はカメラのプロパティに関する情報を提供します。すべてのポーンに設定することができる関連プロパティは、`bTakeCameraControlWhenPossessed` です。これにより、PlayerController に所有されるとポーンは自動的に ViewTarget になります。 diff --git a/Engine/Documentation/Source/Gameplay/Framework/Camera/Camera.KOR.udn b/Engine/Documentation/Source/Gameplay/Framework/Camera/Camera.KOR.udn index e043387af12b..e3960676a33d 100644 --- a/Engine/Documentation/Source/Gameplay/Framework/Camera/Camera.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/Framework/Camera/Camera.KOR.udn @@ -1,13 +1,14 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability:Public Title:카메라 Crumbs:%ROOT%, Gameplay, Gameplay/Framework Description:Camera, 카메라는 플레이어의 시점, 플레이어가 월드를 보는 방식을 나타냅니다. Version: 4.9 -type:reference +type:overview parent:Gameplay/Framework -order:6 +order:5 tags:Gameplay Framework +topic-image:Gameplay/Framework/camera_lander.png **Camera** (카메라)는 플레이어의 시점, 플레이어가 월드를 보는 방식을 나타냅니다. 그 이유로 카메라는 사람이 제어하는 플레이어에만 관련이 있습니다. **PlayerController** 는 카메라 클래스를 나타내며, diff --git a/Engine/Documentation/Source/Gameplay/Framework/Controller/Controller.INT.udn b/Engine/Documentation/Source/Gameplay/Framework/Controller/Controller.INT.udn index 8484b4572ce1..85ecefd10f5a 100644 --- a/Engine/Documentation/Source/Gameplay/Framework/Controller/Controller.INT.udn +++ b/Engine/Documentation/Source/Gameplay/Framework/Controller/Controller.INT.udn @@ -7,10 +7,11 @@ Related: Gameplay\Framework\Controller\AIController Related: Gameplay\Framework\Pawn Related: Gameplay\Framework\Pawn\Character Version: 4.9 -type:reference +type:overview parent:Gameplay/Framework order:4 tags:Gameplay Framework +topic-image:Gameplay/Framework/controller_lander.png [INCLUDE:Shared/Glossary/C/#Glossary_Controller_Class] diff --git a/Engine/Documentation/Source/Gameplay/Framework/Controller/Controller.JPN.udn b/Engine/Documentation/Source/Gameplay/Framework/Controller/Controller.JPN.udn index 02abcbe639ce..41066ae4e556 100644 --- a/Engine/Documentation/Source/Gameplay/Framework/Controller/Controller.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/Framework/Controller/Controller.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:2735872 +INTSourceChangelist:3429254 Availability:Public Title:Controller Crumbs:%ROOT%, Gameplay, Gameplay/Framework @@ -8,10 +8,11 @@ Related:Gameplay\Framework\Controller\AIController Related:Gameplay\Framework\Pawn Related:Gameplay\Framework\Pawn\Character Version:4.9 -type:reference +type:overview parent:Gameplay/Framework order:4 tags:Gameplay Framework +topic-image:Gameplay/Framework/controller_lander.png [INCLUDE:Shared/Glossary/C/#Glossary_Controller_Class] diff --git a/Engine/Documentation/Source/Gameplay/Framework/Controller/Controller.KOR.udn b/Engine/Documentation/Source/Gameplay/Framework/Controller/Controller.KOR.udn index 971144cf3833..4343d0903535 100644 --- a/Engine/Documentation/Source/Gameplay/Framework/Controller/Controller.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/Framework/Controller/Controller.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability:Public Title:콘트롤러 Crumbs:%ROOT%, Gameplay, Gameplay/Framework @@ -8,10 +8,11 @@ Related: Gameplay\Framework\Controller\AIController Related: Gameplay\Framework\Pawn Related: Gameplay\Framework\Pawn\Character Version: 4.9 -type:reference +type:overview parent:Gameplay/Framework order:4 tags:Gameplay Framework +topic-image:Gameplay/Framework/controller_lander.png [INCLUDE:Shared/Glossary/C/#Glossary_Controller_Class] diff --git a/Engine/Documentation/Source/Gameplay/Framework/GameFlow/GameFlow.INT.udn b/Engine/Documentation/Source/Gameplay/Framework/GameFlow/GameFlow.INT.udn index e5542409c495..29bb6b632356 100644 --- a/Engine/Documentation/Source/Gameplay/Framework/GameFlow/GameFlow.INT.udn +++ b/Engine/Documentation/Source/Gameplay/Framework/GameFlow/GameFlow.INT.udn @@ -3,10 +3,11 @@ Title:Game Flow Overview Crumbs:%ROOT%, Gameplay/Framework Description:The process of starting the engine and launching a game or play-in-editor session. Version: 4.12 -type:reference +type:overview parent:Gameplay/Framework -order:5 +order:1 tags:Gameplay Framework +topic-image:Gameplay/Framework/gameflow_lander.png This document explains the process of starting the engine and launching a game. There are two main paths shown here: the editor path, and the standalone path. The general order of events is to initialize the engine, create and initialize a **GameInstance**, then load a level, and finally start playing. However, there are differences between standalone and editor modes, both in terms of the exact order of some of the functions that are called, and in which functions are called. The flowchart below shows the two paths running in parallel until they converge at the start of the game. diff --git a/Engine/Documentation/Source/Gameplay/Framework/GameFlow/GameFlow.KOR.udn b/Engine/Documentation/Source/Gameplay/Framework/GameFlow/GameFlow.KOR.udn index 420d6cf7187a..e0fb681ce926 100644 --- a/Engine/Documentation/Source/Gameplay/Framework/GameFlow/GameFlow.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/Framework/GameFlow/GameFlow.KOR.udn @@ -1,13 +1,14 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability:Public Title:게임 흐름 개요 Crumbs:%ROOT%, Gameplay/Framework Description:엔진 시작 및 게임이나 에디터에서 플레이 세션을 실행시키는 프로세스입니다. Version: 4.12 -type:reference +type:overview parent:Gameplay/Framework -order:5 +order:1 tags:Gameplay Framework +topic-image:Gameplay/Framework/gameflow_lander.png 엔진 시작 및 게임 실행 프로세스에 대한 설명 문서입니다. 여기서 보여드리는 방법은 크게 두 가지, 에디터 방법과 독립형 방법입니다. 일반적인 이벤트 순서는, 엔진을 초기화시키고, **GameInstance** 를 생성 및 초기화한 뒤, 레벨을 로드하고, 마지막으로 플레이를 시작합니다. 하지만 독립형 모드와 에디터 모드 사이의 차이점이 있는데, 일부 함수가 호출되는 정확한 순서와, 어떤 함수가 호출되는지가 다릅니다. 아래 플로우 차트는 두 방법으로 병렬 실행했을 때 게임 시작 전 수렴할 때까지의 흐름을 보여줍니다. diff --git a/Engine/Documentation/Source/Gameplay/Framework/GameMode/GameMode.CHN.udn b/Engine/Documentation/Source/Gameplay/Framework/GameMode/GameMode.CHN.udn index e7e64c6d9e7c..d6a768585c14 100644 --- a/Engine/Documentation/Source/Gameplay/Framework/GameMode/GameMode.CHN.udn +++ b/Engine/Documentation/Source/Gameplay/Framework/GameMode/GameMode.CHN.udn @@ -1,88 +1,126 @@ -INTSourceChangelist:2735872 +INTSourceChangelist:3225556 Availability:Public -Title:GameMode 游戏模式 +Title:Game Mode 和 Game State Crumbs:%ROOT%, Gameplay/Framework -Description:GameMode 负责制定游戏规则。 -Version: 4.9 +Description:Game Mode 和 Game State 总览 +Version:4.14 type:reference parent:Gameplay/Framework order:5 tags:Gameplay Framework +Related:Gameplay/Framework/Controller/PlayerController -即使是最没有限制的游戏也以规则为基础,而这些规则构成一个游戏类型。在最基本的层面上,这些规则包括: +[TOC (start:2 end:2)] -*在场的玩家和观众数量,以及所允许的玩家和观众最大数量。 -*玩家如何进入游戏,可能包括生成地点和生成/重生行为。 -*是否可以暂停游戏,以及如何暂停游戏。 -*等级间的过渡,包括游戏是否应以电影模式开始。 +两个主要类负责处理进行中游戏的相关信息:**Game Mode** 和 **Game State**。 -虽然所有游戏类型都有某些共同的基本规则,但取决于你在开发的游戏类型,它们有无限种变化。熟悉的游戏类型包括第一人称射击游戏,如:《死亡竞赛》、《夺旗》和《终极悍将》——选择这些游戏类型往往是比赛设置过程中的菜单选项,因此它们非常明显。其它类型,如角色扮演冒险游戏或平台游戏可能有较少的变量,以及不太明显的游戏类型,但游戏类型仍设定游戏的条件。例如,可能会向玩家施加时间限制,当玩家达到某一阶段或击败一位“首领”人物时才能过关。更复杂的情况会是《地牢探索者》类型的游戏。在主世界中会有一个总体的游戏类型,它将留意游戏的进度和条件。在每个地牢中可能会有该地牢特定的游戏类型,从而使每个地牢都完全独特,并有自己的一套规则和目标。 +即使最开放的游戏也拥有基础规则,而这些规则构成了 **Game Mode**。在最基础的层面上,这些规则包括: -有两种主要的类来处理有关游戏类型的信息:GameMode 和 GameState。 +* 出现的玩家和观众数量,以及允许的玩家和观众最大数量。 +* 玩家进入游戏的方式,可包含选择生成地点和其他生成/重生成行为的规则。 +* 游戏是否可以暂停,以及如何处理游戏暂停。 +* 关卡之间的过渡,包括游戏是否以动画模式开场。 -## GameMode +基于规则的事件在游戏中发生,需要进行追踪并和所有玩家共享时,信息将通过 **Game State** 进行存储和同步。这些信息包括: +* 游戏已运行的时间(包括本地玩家加入前的运行时间)。 +* 每个个体玩家加入游戏的时间和玩家的当前状态。 +* 当前 Game Mode 的基类。 +* 游戏是否已开始。 -“AGameMode” 类定义所玩的游戏,并执行游戏规则。“AGameMode” 中的一些默认功能包括: +## Game Modes +特定的基础(如进行游戏所需要的玩家数量,或玩家加入游戏的方法)在多种类型的游戏中具有共通性。可根据开发的特定游戏进行无穷无尽的规则变化。无论规则如何,Game Modes 的任务都是定义和实现规则。Game Modes 当前常用的基类有两个。 -任何设定游戏规则的新函数或变量都应添加在 “AGameMode” 类的子类中。从玩家以什么库存道具开始,或有多少条命,到时间限制,以及结束游戏所需的分数都属于 GameMode。可以为游戏应包括的每个游戏类型创建 “AGameMode” 类的子类。一个游戏可以有任何数量的游戏类型,因此有任何数量的 “AGameMode” 类的子类;然而,在任何特定时间只可以使用一种游戏类型。每次通过 “UGameEngine::LoadMap()” 函数初始化一个游戏等级时都会实例化一个 GameMode Actor。该 Actor 定义的游戏类型将被用于该等级所持续的时间。 +4.14 版本中加入了 `AGameModeBase`,这是所有 Game Mode 的基类,是经典的 `AGameMode` 简化版本。`AGameMode` 是 4.14 版本之前的基类,仍然保留,功能 如旧,但现在是 `AGameModeBase` 的子类。由于其比赛状态概念的实现,`AGameMode` 更适用于标准游戏类型(如多人射击游戏)。`AGameModeBase` 简洁高效,是新代码项目中包含的全新默认游戏模式。 - +### AGameModeBase +所有 Game Mode 均为 `AGameModeBase` 的子类。而 `AGameModeBase` 包含大量可覆盖的基础功能。部分常见函数包括: -### 比赛状态 +| 函数/事件 | 目的 | +| --- | --- | +| `InitGame` | `InitGame` 事件在其他脚本之前调用(包括 `PreInitializeComponents`),由 `AGameModeBase` 使用,初始化参数并生成其助手类。 [REGION:note]它在任意 Actor 运行 `PreInitializeComponents` 前调用(包括 Game Mode 实例自身)。[/REGION:note]| +| `PreLogin` | 接受或拒绝尝试加入服务器的玩家。如它将 `ErrorMessage` 设为一个非空字符串,会导致 `Login` 函数失败。`PreLogin` 在 `Login` 前调用,Login 调用前可能需要大量时间,加入的玩家需要下载游戏内容时尤其如此。| +| `PostLogin` | 成功登录后调用。这是首个在 `PlayerController` 上安全调用复制函数之处。`OnPostLogin` 可在蓝图中实现,以添加额外的逻辑。| +| `HandleStartingNewPlayer` | 在 `PostLogin` 后或无缝游历后调用,可在蓝图中覆盖,修改新玩家身上发生的事件。它将默认创建一个玩家 pawn。| +| `RestartPlayer` | 调用开始生成一个玩家 pawn。如需要指定 Pawn 生成的地点,还可使用 `RestartPlayerAtPlayerStart` 和 `RestartPlayerAtTransform` 函数。`OnRestartPlayer` 可在蓝图中实现,在此函数完成后添加逻辑。| +| `SpawnDefaultPawnAtTransform` | 这实际生成玩家 Pawn,可在蓝图中覆盖。| +| `Logout` | 玩家离开游戏或被摧毁时调用。可实现 `OnLogout` 执行蓝图逻辑。| -GameMode 包含监测比赛状态或整体游戏流程的状态机。要查询当前状态,你可以使用 GetMatchState,或诸如 HasMatchStarted、IsMatchInProgress 和 HasMatchEnded 的包装器。以下是可能的比赛状态: +可针对游戏提供的每个比赛格式、任务类型或特殊区域创建 `AGameModeBase` 的子类。一款游戏可拥有任意数量的 Game Mode,因此也可拥有任意数量的 `AGameModeBase` 类子类;然而,给定时间上只能使用一个 Game Mode。每次关卡进行游戏实例化时 Game Mode Actor 将通过 `UGameEngine::LoadMap()` 函数进行实例化。 -* EnteringMap 是初始状态。Actors 尚未开始计数,并且世界尚未完全初始化。当一切都完全加载后会过渡到下个状态。 -* WaitingToStart 是下个状态,进入时调用 HandleMatchIsWaitingToStart。Actors 开始计数,但尚未生成玩家。如果 ReadyToStartMatch 返回_true_,或如果有人调用 StartMatch,则过渡到下个状态。 -* InProgress 是下个状态,进入时调用 HandleMatchHasStarted,进而调用所有 Actors的 BeginPlay。普通游戏正在进行中。如果 ReadyToEndMatch 返回 _true_,或如果有人调用 EndMatch,则过渡到下个状态。 -* WaitingPostMatch 是下个状态,进入时调用 HandleMatchHasEnded。Actors 仍在计数,但不接受新玩家。当地图转换开始时过渡到下个状态。 -* LeavingMap 是最后的状态,进入时调用 HandleLeavingMap。在转至新地图时比赛停留在该状态。 -* Aborted 是故障状态,从 AbortMatch 开始。当存在不可恢复的错误时设置成该状态。 +Game Mode 不会复制到加入多人游戏的远程客户端;它只存在于服务器上,因此本地客户端可看到之前使用过的留存 Game Mode 类(或蓝图);但无法访问实际的实例并检查其变量,确定游戏进程中已发生哪些变化。如玩家确实需要更新与当前 Game Mode 相关的信息,可将信息保存在一个 `AGameStateBase` Actor 上,轻松保持同步。`AGameStateBase` Actor 随 Game Mode 而创建,之后被复制到所有远程客户端。 -默认情况下,比赛状态几乎总为 InProgress。但个别游戏可以覆盖该行为,以构建有更复杂规则的多人游戏。 +### AGameMode -### GameMode 派生 Blueprints +`AGameMode` 是 `AGameModeBase` 的子类,拥有一些额外的功能支持多人游戏和旧行为。所有新建项目默认使用 `AGameModeBase`。如果需要此额外行为,可切换到从 `AGameMode` 进行继承。如从 `AGameMode` 进行继承,也可从 `AGameState` 继承游戏状态(其支持比赛状态机)。 -GameMode 是可制定蓝图的类。可以创建 GameMode 派生的 _Blueprints_,并用其作为项目或等级的默认游戏模式。 +`AGameMode` 包含一个跟踪比赛状态或整体游戏流程的状态机。可使用 `GetMatchState` 或 `HasMatchStarted`、`IsMatchInProgress` 和 `HasMatchEnded` 之类的封装器查询当前的状态。以下是可能的比赛状态: -GameMode 派生 Blueprints 可以设置以下默认值: -* 默认Pawn类 -* HUD类 -* 玩家控制器类 -* 观众类 -* 游戏状态类 -* 玩家状态类 +* `EnteringMap` 是初始状态。Actor 尚未进行 tick,世界场景尚未完整初始化。内容完整加载后将过渡到下个状态。 +* `WaitingToStart` 是下个状态,进入时将调用 `HandleMatchIsWaitingToStart`。Actor 正在进行 tick,但玩家尚未生成。如 `ReadyToStartMatch` 返回 _true_ 或 `StartMatch` 被调用,它将过渡到下个状态。 +* `InProgress` 是游戏主体所发生的状态。进入此状态时将调用 `HandleMatchHasStarted`,然后在所有 Actor 上调用 `BeginPlay`。此时,正常游戏进程已在进行中。`ReadyToEndMatch` 返回 _true_ 或调用 `EndMatch` 时比赛将过渡到下个状态。 +* `WaitingPostMatch` 是倒数第二个状态,进入时将调用 `HandleMatchHasEnded`。Actor 仍在 tick,但新玩家无法加入。地图转换开始时它将过渡到下个状态。 +* `LeavingMap` 是正常流程中的最后一个状态,进入时将调用 `HandleLeavingMap`。转换到新地图时比赛将保持在此状态中,进入新地图时将过渡回到 `EnteringMap`。 +* `Aborted` 是失败状态,调用 `AbortMatch` 可开始此状态。出现无法恢复的错误时将进行此设置。 +游戏状态将固定为 `InProgress`,因为这是调用 `BeginPlay`、actor 开始 tick 的状态。然而,个体游戏可能覆盖这些状态的行为,用更复杂的规则构建一个多人游戏,如在一款多人射击游戏中等待其他玩家加入时允许玩家在关卡中自由飞行。 -### 设置 GameMode +### Game Mode 蓝图 -有几种方法来设置某一等级的 GameMode,以下按照从最低优先级到最高优先级的顺序: +可创建派生自 Game Mode 类的蓝图,并将它们用作项目或关卡的默认 Game Mode。 -* 在 “DefaultGame.ini” 文件中的 “/Script/Engine.WorldSettings/” 部分设置 “GlobalDefaultGameMode” 项将为项目中的所有地图设置默认游戏模式。 +派生自 Game Mode 的蓝图可进行以下默认设置: +* 默认 [](Gameplay/Framework/Pawn) 类 +* HUD 类 +* [](Gameplay/Framework/Controller/PlayerController) 类 +* Spectator 类 +* Game State 类 +* Player State 类 - [/Script/Engine.WorldSettings] +此外,Game Mode 的蓝图十分实用,因为它们无需调整代码即可启用变量调整。因此可用于使单一 Game Mode 适用到多个不同关卡,无需使用硬编码资源引用或为每次调整请求工程支持和代码修改。 + +### 设置 Game Mode + +设置关卡的 Game Mode 有多种,此处的排序从优先级最低到最高: + +* 设置 `DefaultEngine.ini` 文件的 `/Script/EngineSettings.GameMapsSettings` 部分的 `GlobalDefaultGameMode` 输入将设置项目中所有地图的默认游戏模式。 + + [/Script/EngineSettings.GameMapsSettings] GlobalDefaultGameMode="/Script/MyGame.MyGameGameMode" GlobalDefaultServerGameMode="/Script/MyGame.MyGameGameMode" -* 要覆盖一个地图的项目设置,在编辑器的 **World Settings** 选项卡中设置 **GameMode Override**。 +* 在编辑器中 **World Settings** 标签下设置 **GameMode Override** 即可覆盖个体地图的项目设置。 ![](WorldSettings_GameMode.png) -* 符合一定规则的地址可以被传递给可执行文件,以强制游戏加载特定选项。使用“game”选项来设置游戏模式。查看 [](Programming/Basics/CommandLineArguments) 更多信息。 +* URL 可被传到可执行文件,强制游戏加载时带特定选项。使用 `game` 选项设置游戏模式。查看 [](Programming/Basics/CommandLineArguments) 中的详细内容。 UE4Editor.exe /Game/Maps/MyMap?game=MyGameMode -game -* 最后,可以在 “DefaultGame.ini” 文件的 “/Script/Engine.WorldSettings/” 部分设置地图前缀。这些前缀为有特定前缀的所有地图设置默认游戏模式。 +* 最后,可在 `DefaultEngine.ini` 文件的 `/Script/Engine.WorldSettings/` 部分中设置地图前缀(和 URL 法的别名)。这些前缀设置所有拥有特定前缀的地图的默认游戏模式。 - [/Script/Engine.WorldSettings] - +DefaultMapPrefixes=(Prefix="DM",GameMode="UTGame.UTDeathmatch") + [/Script/EngineSettings.GameMapsSettings] + +GameModeMapPrefixes=(Name="DM",GameMode="/Script/UnrealTournament.UTDMGameMode") + +GameModeClassAliases=(Name="DM",GameMode="/Script/UnrealTournament.UTDMGameMode") [REGION:note] -关于设置 **Game Mode** 的例子,请参阅 [设置游戏模式](Gameplay\HowTo\SettingUpAGameMode) 文档。 +请查阅 [设置 Game Mode] 文档中设置 Game Mode 的范例。 [/REGION] + +## Game State + +**Game State** 负责启用客户端监控游戏状态。从概念上而言,Game State 应该管理所有已连接客户端已知的信息(特定于 Game Mode 但不特定于任何个体玩家)。它能够追踪游戏层面的属性,如已连接玩家的列表、夺旗游戏中的团队得分、开放世界游戏中已完成的任务,等等。 + +Game State 并非追踪玩家特有内容(如夺旗比赛中特定玩家为团队获得的分数)的最佳之处,因为它们由 **Player State** 更清晰地处理。整体而言,GameState 应该追踪游戏进程中变化的属性。这些属性与所有人皆相关,且所有人可见。Game mode 只存在于服务器上,而 Game State 存在于服务器上且会被复制到所有客户端,保持所有已连接机器的游戏进程更新。 + +`AGameStateBase` 是基础实现,其部分默认功能包括: + +| 函数或变量 | 使用 | +| --- | --- | +| `GetServerWorldTimeSeconds` | 这是 `UWorld` 函数 `GetTimeSeconds` 的服务器版本,将在客户端和服务器上同步,因此该时间可用于复制,十分可靠。| +| `PlayerArray` | 这是所有 `APlayerState` 对象的阵列,对游戏中所有玩家执行操作时十分实用。| +| `HasBegunPlay` | 如 `BeginPlay` 函数在游戏中的 actor 上调用,则返回 true。| + +`AGameStateBase` 通常在 C++ 或蓝图中延展,包含用于使游戏中玩家知晓当前情况的额外变量和函数。进行的特定修改通常基于 Game State 的配对 Game Mode。Game Mode 自身也可将其默认 Game State 类覆盖为派生自 `AGameStateBase` 的任意 C++ 类或蓝图。 diff --git a/Engine/Documentation/Source/Gameplay/Framework/GameMode/GameMode.INT.udn b/Engine/Documentation/Source/Gameplay/Framework/GameMode/GameMode.INT.udn index 866928e34c66..109c7b1b5a76 100644 --- a/Engine/Documentation/Source/Gameplay/Framework/GameMode/GameMode.INT.udn +++ b/Engine/Documentation/Source/Gameplay/Framework/GameMode/GameMode.INT.udn @@ -3,11 +3,12 @@ Title: Game Mode and Game State Crumbs:%ROOT%, Gameplay/Framework Description: Overview of the Game Mode and Game State Version: 4.14 -type:reference +type:overview parent:Gameplay/Framework -order:5 +order:2 tags:Gameplay Framework Related:Gameplay/Framework/Controller/PlayerController +topic-image:Gameplay/Framework/gamemode_lander.png [TOC (start:2 end:2)] diff --git a/Engine/Documentation/Source/Gameplay/Framework/GameMode/GameMode.JPN.udn b/Engine/Documentation/Source/Gameplay/Framework/GameMode/GameMode.JPN.udn index 6df3c7e92eac..f09b8ca26e79 100644 --- a/Engine/Documentation/Source/Gameplay/Framework/GameMode/GameMode.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/Framework/GameMode/GameMode.JPN.udn @@ -1,14 +1,15 @@ -INTSourceChangelist:3225556 +INTSourceChangelist:3429254 Availability:Public Title:Game Mode と Game State Crumbs:%ROOT%, Gameplay/Framework Description:Game Mode と Game State の概要 Version:4.14 -type:reference +type:overview parent:Gameplay/Framework -order:5 +order:2 tags:Gameplay Framework Related:Gameplay/Framework/Controller/PlayerController +topic-image:Gameplay/Framework/gamemode_lander.png [TOC (start:2 end:2)] @@ -94,6 +95,7 @@ Game Mode から派生したブループリントに以下のデフォルト値 ![](WorldSettings_GameMode.png) + * ゲーム起動時にある特定のオプションを強制的に読み込ませるために URL を実行ファイルへ渡すことができます。ゲームモードの設定は `game` オプションを使用します。詳細は [](Programming/Basics/CommandLineArguments) を参照してください。 UE4Editor.exe /Game/Maps/MyMap?game=MyGameMode -game diff --git a/Engine/Documentation/Source/Gameplay/Framework/GameMode/GameMode.KOR.udn b/Engine/Documentation/Source/Gameplay/Framework/GameMode/GameMode.KOR.udn index 85331fa19b23..81cf01f8ac46 100644 --- a/Engine/Documentation/Source/Gameplay/Framework/GameMode/GameMode.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/Framework/GameMode/GameMode.KOR.udn @@ -1,14 +1,15 @@ -INTSourceChangelist:3225556 +INTSourceChangelist:3429254 Availability:Public Title:게임 모드와 게임 스테이트 Crumbs:%ROOT%, Gameplay/Framework Description: Game Mode, 게임 모드와 Game State, 게임 스테이트에 대한 개요입니다. Version: 4.14 -type:reference +type:overview parent:Gameplay/Framework -order:5 +order:2 tags:Gameplay Framework Related:Gameplay/Framework/Controller/PlayerController +topic-image:Gameplay/Framework/gamemode_lander.png [TOC (start:2 end:2)] diff --git a/Engine/Documentation/Source/Gameplay/Framework/GameState/GameState.CHN.udn b/Engine/Documentation/Source/Gameplay/Framework/GameState/GameState.CHN.udn deleted file mode 100644 index 1f1f4ba6116e..000000000000 --- a/Engine/Documentation/Source/Gameplay/Framework/GameState/GameState.CHN.udn +++ /dev/null @@ -1,11 +0,0 @@ -Availability:Public -Title:GameState 游戏状态 -Crumbs:%ROOT%, Gameplay/Framework -Description:GameState(游戏状态)负责监测客户端上游戏的状态。 - - -[OBJECT:Redirect] - [PARAM:link] - [](Gameplay/Framework/GameMode) - [/PARAM] -[/OBJECT] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/Framework/GameState/GameState.JPN.udn b/Engine/Documentation/Source/Gameplay/Framework/GameState/GameState.JPN.udn deleted file mode 100644 index 19479d48e681..000000000000 --- a/Engine/Documentation/Source/Gameplay/Framework/GameState/GameState.JPN.udn +++ /dev/null @@ -1,10 +0,0 @@ -Availability:Public -Title:GameState -Crumbs:%ROOT%, Gameplay/Framework -Description:GameState はクライアント上でゲーム ステートをモニタします。 - -[OBJECT:Redirect] - [PARAM:link] - [](Gameplay/Framework/GameMode) - [/PARAM] -[/OBJECT] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/Framework/GameState/GameState.KOR.udn b/Engine/Documentation/Source/Gameplay/Framework/GameState/GameState.KOR.udn deleted file mode 100644 index d9fbced7de6c..000000000000 --- a/Engine/Documentation/Source/Gameplay/Framework/GameState/GameState.KOR.udn +++ /dev/null @@ -1,10 +0,0 @@ -Availability:Public -Title:GameState -Crumbs:%ROOT%, Gameplay/Framework -Description:GameState 는 클라이언트의 게임 상태 모니터링을 담당합니다. - -[OBJECT:Redirect] - [PARAM:link] - [](Gameplay/Framework/GameMode) - [/PARAM] -[/OBJECT] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/Framework/GameplayFramework.INT.udn b/Engine/Documentation/Source/Gameplay/Framework/GameplayFramework.INT.udn index 2ac379b46a5e..0e861ffd77e2 100644 --- a/Engine/Documentation/Source/Gameplay/Framework/GameplayFramework.INT.udn +++ b/Engine/Documentation/Source/Gameplay/Framework/GameplayFramework.INT.udn @@ -29,92 +29,15 @@ to pages with overviews of each class and information about how they can be set ## Basic Framework Elements [EXCERPT:LandingBoxes] -[REGION:topics third] -[OBJECT:Topic] - [PARAM:image] - ![](gameflow_lander.png) - [/PARAM] - [PARAM:title] - %Gameplay/Framework/GameFlow:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Gameplay/Framework/GameFlow] - [/PARAM] - [PARAM:description] - %Gameplay/Framework/GameFlow:description% - [/PARAM] -[/OBJECT] -[OBJECT:Topic] - [PARAM:image] - ![](gamemode_lander.png) - [/PARAM] - [PARAM:title] - %Gameplay/Framework\GameMode:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Gameplay/Framework\GameMode] - [/PARAM] - [PARAM:description] - %Gameplay/Framework\GameMode:description% - [/PARAM] -[/OBJECT] -[OBJECT:Topic] - [PARAM:image] - ![](pawn_lander.png) - [/PARAM] - [PARAM:title] - Pawns - [/PARAM] - [PARAM:path] - [RELATIVE:Gameplay/Framework\Pawn] - [/PARAM] - [PARAM:description] - %Gameplay/Framework\Pawn:description% - [/PARAM] -[/OBJECT] -[OBJECT:Topic] - [PARAM:image] - ![](controller_lander.png) - [/PARAM] - [PARAM:title] - %Gameplay/Framework\Controller:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Gameplay/Framework\Controller] - [/PARAM] - [PARAM:description] - %Gameplay/Framework\Controller:description% - [/PARAM] -[/OBJECT] -[OBJECT:Topic] - [PARAM:image] - ![](camera_lander.png) - [/PARAM] - [PARAM:title] - %Gameplay/Framework\Camera:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Gameplay/Framework\Camera] - [/PARAM] - [PARAM:description] - %Gameplay/Framework\Camera:description% - [/PARAM] -[/OBJECT] -[OBJECT:Topic] - [PARAM:image] - ![](hud_lander.png) - [/PARAM] - [PARAM:title] - %Gameplay/Framework\UIAndHUD:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Gameplay/Framework\UIAndHUD] - [/PARAM] - [PARAM:description] - %Gameplay/Framework\UIAndHUD:description% - [/PARAM] -[/OBJECT] -[/REGION] +[DIR(output:"topic" parent:"Gameplay/Framework" org:"hierarchy" end:"1")] + [/EXCERPT:LandingBoxes] diff --git a/Engine/Documentation/Source/Gameplay/Framework/GameplayFramework.JPN.udn b/Engine/Documentation/Source/Gameplay/Framework/GameplayFramework.JPN.udn index 6246d9e3eb4c..1808af8fd4ed 100644 --- a/Engine/Documentation/Source/Gameplay/Framework/GameplayFramework.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/Framework/GameplayFramework.JPN.udn @@ -1,107 +1,44 @@ -INTSourceChangelist:2735872 +INTSourceChangelist:3429253 Availability:Public Title: ゲームプレイ フレームワーク Crumbs:%ROOT%, Gameplay -Description: ゲームルール、プレーヤー入力や制御、カメラ、ユーザー インターフェースなどのコア システム +Description:ゲームルール、プレーヤー入力や制御、カメラ、ユーザー インターフェースなどのコア システム Version:4.9 type:reference Parent:Gameplay order:1 tags:Gameplay Framework -ゲームフレームワークでは様々なピースがどのように連結するのか、わかりやすい例を見てみましょう。ウサギとカタツムリが競争するという、 -シンプルなコンセプトをイメージします。ゲームフレームワークのベースは GameMode です。**GameMode**はゲームのルールを設定します。 -ゴールラインを先に横切ったプレーヤーが勝者となる、といったルールです。また、プレーヤーのスポーンもします。 +ゲームフレームワークでは様々なピースがどのように連結するのかを、わかりやすい例で考えてみましょう。ウサギとカタツムリが競争するという、 +シンプルなコンセプトをイメージします。ゲームフレームワークのベースは GameMode です。**GameMode** はゲームのルールを設定します。 +例えば、ゴールラインを先に横切ったプレーヤーが勝者となる、といったルールです。また、プレイヤーのスポーンもします。 -プレーヤーは **PlayerController** で設定され、ポーンを所有できます。**コントローラー** はポーンを所有し動作のルールを設定でき、ポーンはゲームでプレーヤーを物理的に表現します。 -この例では、ポーンの数は、カタツムリ 1 つととウサギ 1 つで合計 2 つとなります。うさぎは実際は **キャラクター** で、走行やジャンプなどのビルトインされている動作機能をもつポーンの特別なサブクラスです。一方カタツムリは異なる動作のスタイルを持っており、 Pawn クラスから直接拡張することができます。 +プレイヤーは **PlayerController** で設定され、ポーンを所有できます。コントローラーはポーンを所有し動作のルールを設定でき、**ポーン** はゲームでプレイヤーを物理的に表現します。 +この例では、ポーンの数は、カタツムリ 1 つとウサギ 1 つで合計 2 つとなります。ウサギは実際は **キャラクター** で、走行やジャンプなどのビルトインされている動作機能をもつポーンの特別なサブクラスです。一方カタツムリは異なる動作のスタイルを持っており、 Pawn クラスから直接拡張することができます。 -ポーンは動作と他のゲームロジックに対するルールを持ちますが、機能はコントローラーに含むことができます。コントローラーは、人間のプレーヤーからの入力を受け取る PlayerController か、 -コンピューターに自動制御される AIController のいずれかになることができます。この例では、プレーヤーはカタツムリを制御するので、カタツムリのポーンは PlayerController に所有されます。うさぎは、うさぎの **キャラクター** を所有する **AIController** にすべて設定されている、 -止まる、ダッシュする、油断すべきタイミングのルールに従って AI に制御されます。人間のプレーヤーだけがカメラが提供するビューに気をつけるので、 +ポーンは動作と他のゲームロジックに対するルールを持ちますが、機能はコントローラーに含むこともできます。コントローラーは、人間のプレイヤーからの入力を受け取る PlayerController か、 +コンピューターに自動制御される AIController のいずれかになることができます。この例では、プレイヤーはカタツムリを制御するので、カタツムリのポーンは PlayerController に所有されます。ウサギは、ウサギの **キャラクター** を所有する **AIController** にすべて設定されている、 +止まる、ダッシュする、油断すべきタイミングのルールに従って AI に制御されます。人間のプレイヤーだけがカメラが提供するビューに気をつけるので、 カタツムリのポーンの中の CameraComponent 1 つだけが PlayerCamera に使用されます。 -ゲームプレイの間、プレーヤーの入力によりカタツムリはマップの周りを動き、HUD は 現在の首位およびレースの残り時間に関する情報を表示しながら、 -**Camera** から提供されるビュー上でオーバーレイされます。 +ゲームプレイの間、プレイヤーの入力によりカタツムリはマップの周りを動き、HUD は現在の首位およびレースの経過時間に関する情報を +**Camera** から提供されるビューにオーバーレイ表示します。 -基本的なフレームワーク エレメントおよび組み合わさり方の表については、[](Gameplay/Framework/QuickReference) を参照してください。あるいは、以下のリンクを使えば、 +基本的なフレームワーク エレメントおよび組み合わせ方の表については、[](Gameplay/Framework/QuickReference) を参照してください。あるいは、以下のリンクを使えば、 各クラスの概要およびブループリントや C++ での設定方法に関する情報が記載されたページに直接ジャンプすることができます。 ##基本的なフレームワーク要素 [EXCERPT:LandingBoxes] -[REGION:topics third] -[OBJECT:Topic] - [PARAM:image] - ![](gamemode_lander.png) - [/PARAM] - [PARAM:title] - %Gameplay/Framework\GameMode:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Gameplay/Framework\GameMode] - [/PARAM] - [PARAM:description] - %Gameplay/Framework\GameMode:description% - [/PARAM] -[/OBJECT] -[OBJECT:Topic] - [PARAM:image] - ![](pawn_lander.png) - [/PARAM] - [PARAM:title] - ポーン - [/PARAM] - [PARAM:path] - [RELATIVE:Gameplay/Framework\Pawn] - [/PARAM] - [PARAM:description] - %Gameplay/Framework\Pawn:description% - [/PARAM] -[/OBJECT] -[OBJECT:Topic] - [PARAM:image] - ![](controller_lander.png) - [/PARAM] - [PARAM:title] - %Gameplay/Framework\Controller:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Gameplay/Framework\Controller] - [/PARAM] - [PARAM:description] - %Gameplay/Framework\Controller:description% - [/PARAM] -[/OBJECT] -[OBJECT:Topic] - [PARAM:image] - ![](camera_lander.png) - [/PARAM] - [PARAM:title] - %Gameplay/Framework\Camera:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Gameplay/Framework\Camera] - [/PARAM] - [PARAM:description] - %Gameplay/Framework\Camera:description% - [/PARAM] -[/OBJECT] -[OBJECT:Topic] - [PARAM:image] - ![](hud_lander.png) - [/PARAM] - [PARAM:title] - %Gameplay/Framework\UIAndHUD:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Gameplay/Framework\UIAndHUD] - [/PARAM] - [PARAM:description] - %Gameplay/Framework\UIAndHUD:description% - [/PARAM] -[/OBJECT] -[/REGION] +[DIR(output:"topic" parent:"Gameplay/Framework" org:"hierarchy" end:"1")] + [/EXCERPT:LandingBoxes] diff --git a/Engine/Documentation/Source/Gameplay/Framework/GameplayFramework.KOR.udn b/Engine/Documentation/Source/Gameplay/Framework/GameplayFramework.KOR.udn index c40ee8ac5e31..692f8ef034db 100644 --- a/Engine/Documentation/Source/Gameplay/Framework/GameplayFramework.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/Framework/GameplayFramework.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429253 Availability:Public Title:게임플레이 프레임워크 Crumbs:%ROOT%, Gameplay @@ -30,92 +30,15 @@ PlayerCamera 에 사용될 것입니다. ## 기본 프레임워크 요소 [EXCERPT:LandingBoxes] -[REGION:topics third] -[OBJECT:Topic] - [PARAM:image] - ![](gameflow_lander.png) - [/PARAM] - [PARAM:title] - %Gameplay/Framework/GameFlow:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Gameplay/Framework/GameFlow] - [/PARAM] - [PARAM:description] - %Gameplay/Framework/GameFlow:description% - [/PARAM] -[/OBJECT] -[OBJECT:Topic] - [PARAM:image] - ![](gamemode_lander.png) - [/PARAM] - [PARAM:title] - %Gameplay/Framework\GameMode:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Gameplay/Framework\GameMode] - [/PARAM] - [PARAM:description] - %Gameplay/Framework\GameMode:description% - [/PARAM] -[/OBJECT] -[OBJECT:Topic] - [PARAM:image] - ![](pawn_lander.png) - [/PARAM] - [PARAM:title] - Pawns - [/PARAM] - [PARAM:path] - [RELATIVE:Gameplay/Framework\Pawn] - [/PARAM] - [PARAM:description] - %Gameplay/Framework\Pawn:description% - [/PARAM] -[/OBJECT] -[OBJECT:Topic] - [PARAM:image] - ![](controller_lander.png) - [/PARAM] - [PARAM:title] - %Gameplay/Framework\Controller:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Gameplay/Framework\Controller] - [/PARAM] - [PARAM:description] - %Gameplay/Framework\Controller:description% - [/PARAM] -[/OBJECT] -[OBJECT:Topic] - [PARAM:image] - ![](camera_lander.png) - [/PARAM] - [PARAM:title] - %Gameplay/Framework\Camera:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Gameplay/Framework\Camera] - [/PARAM] - [PARAM:description] - %Gameplay/Framework\Camera:description% - [/PARAM] -[/OBJECT] -[OBJECT:Topic] - [PARAM:image] - ![](hud_lander.png) - [/PARAM] - [PARAM:title] - %Gameplay/Framework\UIAndHUD:title% - [/PARAM] - [PARAM:path] - [RELATIVE:Gameplay/Framework\UIAndHUD] - [/PARAM] - [PARAM:description] - %Gameplay/Framework\UIAndHUD:description% - [/PARAM] -[/OBJECT] -[/REGION] +[DIR(output:"topic" parent:"Gameplay/Framework" org:"hierarchy" end:"1")] + [/EXCERPT:LandingBoxes] diff --git a/Engine/Documentation/Source/Gameplay/Framework/Pawn/Character/Character.INT.udn b/Engine/Documentation/Source/Gameplay/Framework/Pawn/Character/Character.INT.udn index c7474489bcb0..ec803475e8de 100644 --- a/Engine/Documentation/Source/Gameplay/Framework/Pawn/Character/Character.INT.udn +++ b/Engine/Documentation/Source/Gameplay/Framework/Pawn/Character/Character.INT.udn @@ -10,7 +10,7 @@ Related: Engine/Animation/CharacterSetupOverview Related: Gameplay/HowTo/CharacterMovement Version: 4.9 -With the addition of a `CharacterMovementComponent`, a `CapsuleComponent`, and a **Skeletal Mesh**, the **Pawn** class is extended into the highly-featured **Character** class. +With the addition of a `CharacterMovementComponent`, a `CapsuleComponent`, and a `SkeletalMeshComponent`, the [Pawn](Gameplay/Framework/Controller) class is extended into the highly-featured **Character** class. A Character is designed for a vertically-oriented player representation that can walk, run, jump, fly, and swim through the world. This class also contains implementations of basic networking and input models. diff --git a/Engine/Documentation/Source/Gameplay/Framework/Pawn/Character/Character.JPN.udn b/Engine/Documentation/Source/Gameplay/Framework/Pawn/Character/Character.JPN.udn index 5acd694fba1e..d587780d45e6 100644 --- a/Engine/Documentation/Source/Gameplay/Framework/Pawn/Character/Character.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/Framework/Pawn/Character/Character.JPN.udn @@ -1,8 +1,8 @@ -INTSourceChangelist:2699746 +INTSourceChangelist:3388780 Availability:Public Title:Character Crumbs:%ROOT%, Gameplay, Gameplay/Framework, Gameplay/Framework/Pawn -Description:キャラクターとは、デフォルト設定で基本的な二足歩行の動作機能を持つポーンです。 +Description:キャラクター とは、デフォルト設定で基本的な二足歩行の動作機能を持つポーンです。 Related:Gameplay/Framework/Pawn Related:Gameplay/Framework/Controller Related:Gameplay/Framework/GameMode @@ -11,12 +11,12 @@ Related:Engine/Animation/CharacterSetupOverview Related:Gameplay/HowTo/CharacterMovement Version:4.9 -`CharacterMovement コンポーネント`、 `Capsule コンポーネント`、および **Skeletal Mesh** が加わり、Pawn クラスは高度な機能を備えた **Character** クラスに拡張されました。 +`CharacterMovementComponent`、 `CapsuleComponent`、および `SkeletalMeshComponent` が加わり、[Pawn](Gameplay/Framework/Controller) クラスは高度な機能を備えた Character クラスに拡張されました。 Character は、ワールド内で歩行、走行、ジャンプ、飛行、水泳できる縦方向に表現したプレイヤー向けに設計されています。このクラスには、 基本的なネットワークの構築や入力モデルの実装も含まれます。 -### SkeletalMesh コンポーネント -Pawn とは異なり、Character にはスケルトンを使用する高度なアニメーションを有効にするための `SkeletalMesh コンポーネント` が含まれています。Character から派生したクラスへ他のスケルタルメッシュを追加できますが、 +### SkeletalMeshComponent +Pawn とは異なり、Character にはスケルトンを使用する高度なアニメーションを有効にするための `SkeletalMeshComponent` が含まれています。Character から派生したクラスへ他のスケルタルメッシュを追加できますが、 これが Character に関連付けられているメインのスケルタルメッシュになります。スケルタルメッシュに関する詳細は以下を参照してください。 [OBJECT:TopicButtonList] @@ -36,8 +36,8 @@ Pawn とは異なり、Character にはスケルトンを使用する高度な -### Capsule コンポーネント -`Capsule コンポーネント` は移動コリジョンに使用します。`CharacterMovement コンポーネント` の複雑なジオメトリを計算するために、Character クラスの Collision コンポーネントは垂直方向のカプセルであると仮定します。コリジョンに関する詳細については以下を参照してください。 +### CapsuleComponent +`CapsuleComponent` は移動コリジョンに使用します。`CharacterMovementComponent` の複雑なジオメトリを計算するために、Character クラスの Collision コンポーネントは垂直方向のカプセルであると仮定します。コリジョンに関する詳細については以下を参照してください。 [OBJECT:TopicButtonList] [PARAM:icon] @@ -54,11 +54,11 @@ Pawn とは異なり、Character にはスケルトンを使用する高度な [/PARAM] [/OBJECT] -### CharacterMovement コンポーネント -`CharacterMovement コンポーネント` は、歩行、走行、ジャンプ、飛行、落下、水泳によるアバターの移動を可能とするために剛体物理を使用しません。 -これは Character 特有のもので、その他のクラスには実装できません。`CharacterMovement コンポーネント` で設定可能なプロパティには、 +### CharacterMovementComponent +`CharacterMovementComponent` では、アバターは剛体物理を使用せずに、歩行、走行、ジャンプ、飛行、落下、水泳で移動することができます。 +これは Character 特有のもので、その他のクラスには実装できません。`CharacterMovementComponent` で設定可能なプロパティには、 落下や歩行時の摩擦力の値、大気、水中、陸地を移動中の速度、浮力、重力スケールが含まれ、こうした物理によって、キャラクターが物理オブジェクトに -影響を及ぼすことができるようにします。`CharacterMovement コンポーネント` はアニメーションに由来するルートモーション パラメータを含み、 +影響を及ぼすことができるようにします。`CharacterMovementComponent` はアニメーションに由来するルートモーション パラメータを含み、 ワールド空間で既に変換されて物理的な使用の準備が整っています。 --- diff --git a/Engine/Documentation/Source/Gameplay/Framework/Pawn/Character/Character.KOR.udn b/Engine/Documentation/Source/Gameplay/Framework/Pawn/Character/Character.KOR.udn index 784598ce52ac..a76f2a3968fa 100644 --- a/Engine/Documentation/Source/Gameplay/Framework/Pawn/Character/Character.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/Framework/Pawn/Character/Character.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3388780 Availability:Public Title:캐릭터 Crumbs:%ROOT%, Gameplay, Gameplay/Framework, Gameplay/Framework/Pawn @@ -12,7 +12,7 @@ Related: Gameplay/HowTo/CharacterMovement Version: 4.9 -`CharacterMovementComponent`, `CapsuleComponent`, **SkeletalMesh** 의 추가를 통해 Pawn 클래스는 매우 특징적인 Character (캐릭터) 클래스로 확장됩니다. +`CharacterMovementComponent`, `CapsuleComponent`,`SkeletalMeshComponent` 의 추가를 통해 [Pawn](Gameplay/Framework/Controller) 클래스는 고도로 특화된 Character (캐릭터) 클래스로 확장됩니다. 캐릭터는 월드에서 걷기, 달리기, 점프, 비행, 수영 등이 가능한 직립 플레이어를 표현하기 위해 디자인된 것입니다. 이 클래스에는 기본적인 네트워킹이나 인풋 모델 구현도 추가되어 있습니다. diff --git a/Engine/Documentation/Source/Gameplay/Framework/Pawn/Pawn.INT.udn b/Engine/Documentation/Source/Gameplay/Framework/Pawn/Pawn.INT.udn index 4d645032488f..51c373f8f083 100644 --- a/Engine/Documentation/Source/Gameplay/Framework/Pawn/Pawn.INT.udn +++ b/Engine/Documentation/Source/Gameplay/Framework/Pawn/Pawn.INT.udn @@ -6,10 +6,11 @@ Related: Gameplay/Framework\Pawn\Character Related: Gameplay/Framework/Controller Related: Gameplay/Framework/GameMode Version: 4.9 -type:reference +type:overview parent:Gameplay/Framework order:3 tags:Gameplay Framework +topic-image:Gameplay/Framework/pawn_lander.png ![](pawn_ball.png)(w:300) diff --git a/Engine/Documentation/Source/Gameplay/Framework/Pawn/Pawn.JPN.udn b/Engine/Documentation/Source/Gameplay/Framework/Pawn/Pawn.JPN.udn index a2156a26dd3f..b143c22242b5 100644 --- a/Engine/Documentation/Source/Gameplay/Framework/Pawn/Pawn.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/Framework/Pawn/Pawn.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:2735872 +INTSourceChangelist:3429254 Availability:Public Title:Pawn Crumbs:%ROOT%, Gameplay, Gameplay/Framework @@ -7,18 +7,19 @@ Related:Gameplay/Framework\Pawn\Character Related:Gameplay/Framework/Controller Related:Gameplay/Framework/GameMode Version:4.9 -type:reference +type:overview parent:Gameplay/Framework order:3 tags:Gameplay Framework +topic-image:Gameplay/Framework/pawn_lander.png ![](pawn_ball.png)(w:300) -**Pawn** クラスはプレイヤーまたは AI によって制御可能な、すべてのアクタのベースクラスです。ポーンは、ワールド内のプレイヤーまたは AI エンティティの物理的な実体です。 +**Pawn** クラスはプレイヤーまたは AI によって制御可能な、すべてのアクタの基本クラスです。ポーンは、ワールド内のプレイヤーまたは AI エンティティの物理的な実体です。 ポーンは、プレイヤーまたは AI エンティティの視覚的な表現のみならず、コリジョンや物理的インタラクションにおいて、これらのワールド内における相互作用方法を -決定します。ゲームの種類によっては、ゲーム内に表示されるメッシュまたはアバターが存在しないため、特定の状況下では混乱を招く場合もあります。いずれにせよ、 +決定します。これは、特定の状況下では混乱を招く場合もあります。ゲームの種類によっては、ゲーム内に表示されるプレイヤーのメッシュやアバターが存在しないためです。いずれにせよ、 Pawn はゲーム内のプレイヤーまたはエンティティの物理的な位置、回転を表します。[Character](Gameplay\Framework\Pawn\Character) は、歩行能力を持つ特別な種類のポーンです。 デフォルトで、[コントローラー](Gameplay/Framework/Controller) とポーンは 1 対 1 の関係です。つまり、各コントローラーは常にポーンを 1 つだけ管理します。また、ゲームプレイ中にスポーンされたポーンは @@ -39,7 +40,7 @@ DefaultPawn クラスには、ネイティブの _DefaultPawnMovementComponent_ ### DefaultPawnMovementComponent -_DefaultPawnMovementComponent_ には、無重力の飛行スタイルが設定されています。通常の _MovementComponent_ 変数の他に、`MaxSpeed` 、 `Acceleration` 、 `Deceleration` の浮動小数点値が含まれています。こうした 3 つの変数は、 +_DefaultPawnMovementComponent_ には、無重力の飛行スタイルが設定されています。通常の _MovementComponent_ 変数の他に、`MaxSpeed` 、 `Acceleration` 、 `Deceleration` の浮動小数点値が含まれています。これらは、 DefaultPawn から派生したブループリントでもアクセスが可能です。 ### Spectator Pawn diff --git a/Engine/Documentation/Source/Gameplay/Framework/Pawn/Pawn.KOR.udn b/Engine/Documentation/Source/Gameplay/Framework/Pawn/Pawn.KOR.udn index 71329d964961..77b78b0076ac 100644 --- a/Engine/Documentation/Source/Gameplay/Framework/Pawn/Pawn.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/Framework/Pawn/Pawn.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability:Public Title:폰 Crumbs:%ROOT%, Gameplay, Gameplay/Framework @@ -7,10 +7,11 @@ Related: Gameplay/Framework\Pawn\Character Related: Gameplay/Framework/Controller Related: Gameplay/Framework/GameMode Version: 4.9 -type:reference +type:overview parent:Gameplay/Framework order:3 tags:Gameplay Framework +topic-image:Gameplay/Framework/pawn_lander.png ![](pawn_ball.png)(w:300) diff --git a/Engine/Documentation/Source/Gameplay/Framework/QuickReference/QuickReference.CHN.udn b/Engine/Documentation/Source/Gameplay/Framework/QuickReference/QuickReference.CHN.udn index 89263f505a60..132a9edd2729 100644 --- a/Engine/Documentation/Source/Gameplay/Framework/QuickReference/QuickReference.CHN.udn +++ b/Engine/Documentation/Source/Gameplay/Framework/QuickReference/QuickReference.CHN.udn @@ -4,9 +4,9 @@ Title:游戏架构快速指南 Crumbs:%ROOT%, Gameplay, Gameplay/Framework Description:关于构成游戏架构的游戏规则、角色、控制器、用户界面等类的概述。 Version: 4.9 -type:reference +type:overview parent:Gameplay/Framework -order:2 +order:0 tags:Gameplay Framework 基本游戏类包括表示玩家、盟友、敌人的功能以及使用玩家输入或AI逻辑控制这些角色的功能。还有一些类用于为玩家创建 @@ -74,7 +74,7 @@ $ Camera(相机) : PlayerCameraManager是玩家的眼睛,管理玩家如 $ GameMode(游戏模式) : 游戏这个概念划分为两个类。[](Gameplay/Framework/GameMode)是游戏的定义,包括像游戏规则及获胜条件这样的内容。它仅存在于服务器上。它一般在游戏过程中不会有太多数据改变,并且它一定不应该具有客户端需要的临时数据。 -$ GameState(游戏状态) : [](Gameplay/Framework/GameState)包含了游戏状态,这包括像关联玩家的列表、分数、象棋游戏中的象棋位置或者在开放世界游戏中已经完成的任务列表。GameState存在于服务器和所有客户端上,可以自由地进行复制来保持同步。 +$ GameState(游戏状态) : [GameState](Gameplay/Framework/GameMode#GameState) 包含了游戏状态,这包括像关联玩家的列表、分数、象棋游戏中的象棋位置或者在开放世界游戏中已经完成的任务列表。GameState存在于服务器和所有客户端上,可以自由地进行复制来保持同步。 $ PlayerState(玩家状态) : PlayerState是游戏中的一个参与者的状态,比如人类玩家或者模拟人类玩家的机器人。作为游戏一部分存在的非人类玩家AI没有PlayerState。PlayerState中适合包含的示例数据有:玩家姓名、分数、像多人在线竞技场这样的比赛中的级别、或在夺旗模式游戏中玩家当前是否正占领旗帜。所有玩家的PlayerStates在所有机器上都存在(和PlayerControllers不同),并且可以自由地进行复制来保持同步。 diff --git a/Engine/Documentation/Source/Gameplay/Framework/QuickReference/QuickReference.INT.udn b/Engine/Documentation/Source/Gameplay/Framework/QuickReference/QuickReference.INT.udn index 13544999d20c..88ff1b6cf076 100644 --- a/Engine/Documentation/Source/Gameplay/Framework/QuickReference/QuickReference.INT.udn +++ b/Engine/Documentation/Source/Gameplay/Framework/QuickReference/QuickReference.INT.udn @@ -3,9 +3,9 @@ Title:Gameplay Framework Quick Reference Crumbs:%ROOT%, Gameplay, Gameplay/Framework Description:Short overview of classes for game rules, characters, controllers, user interfaces, etc., that make up the framework for the game. Version: 4.9 -type:reference +type:overview parent:Gameplay/Framework -order:2 +order:0 tags:Gameplay Framework The basic gameplay classes include functionality for representing players, allies, and enemies, as well as for controlling these avatars with player input or AI logic. There are also classes for creating @@ -15,90 +15,43 @@ These classes all create types of Actors, which can either be placed into your l -[OBJECT:IconSection] - [PARAM:icon] - ![](Gameplay/Framework/pawn_lander.png)(w:300) - [/PARAM] - [PARAM:title] - Representing Players, Friends, and Foes in the World - [/PARAM] - [PARAM:description] - **Pawn** - - A [](Gameplay/Framework/Pawn) is an Actor that can be an "agent" within the world. Pawns can be possessed by a Controller, they are set up to easily accept input, and they can do various and sundry other player-like things. Note that a Pawn is not assumed to be humanoid. +## Representing Players, Friends, and Foes in the World - **Character** - - A [](Gameplay/Framework/Pawn/Character) is a humanoid-style Pawn. It comes with a CapsuleComponent for collision and a CharacterMovementComponent by default. It can do basic human-like movement, it can replicate movement smoothly across the network, and it has some animation-related functionality. +![](Gameplay/Framework/pawn_lander.png)(w:300) - [/PARAM] -[/OBJECT] +||| +| --- | --- | +| **Pawn** | A [](Gameplay/Framework/Pawn) is an Actor that can be an "agent" within the world. Pawns can be possessed by a Controller, they are set up to easily accept input, and they can do various and sundry other player-like things. Note that a Pawn is not assumed to be humanoid. | +| **Character** | A [](Gameplay/Framework/Pawn/Character) is a humanoid-style Pawn. It comes with a CapsuleComponent for collision and a CharacterMovementComponent by default. It can do basic human-like movement, it can replicate movement smoothly across the network, and it has some animation-related functionality. | -[OBJECT:IconSection] - [PARAM:icon] - ![](Gameplay/Framework/controller_lander.png)(w:300) - [/PARAM] - [PARAM:title] - Controlling Pawns With Player Input or AI Logic - [/PARAM] - [PARAM:description] +## Controlling Pawns With Player Input or AI Logic + +![](Gameplay/Framework/controller_lander.png)(w:300) - **Controller** - - A [](Gameplay/Framework/Controller) is an Actor that is responsible for directing a Pawn. They typically come in 2 flavors, AIController and PlayerController. A controller can "possess" a Pawn to take control of it. +||| +| --- | --- | +| **Controller** | [](Gameplay/Framework/Controller) is an Actor that is responsible for directing a Pawn. They typically come in 2 flavors, AIController and PlayerController. A controller can "possess" a Pawn to take control of it. | +| **PlayerController** | A [](Gameplay/Framework/Controller/PlayerController) is the interface between the Pawn and the human player controlling it. The PlayerController essentially represents the human player's will. | +| **AIController** | An AIController is what it sounds like; a simulated "will" that can control a Pawn. | - **PlayerController** - - A [](Gameplay/Framework/Controller/PlayerController) is the interface between the Pawn and the human player controlling it. The PlayerController essentially represents the human player's will. +## Displaying Information to Players - **AIController** - - An AIController is what it sounds like; a simulated "will" that can control a Pawn. +![](Gameplay/Framework/camera_lander.png)(w:300) + +||| +| --- | --- | +| **HUD** | A [HUD](Gameplay/Framework/UIAndHUD) is a "heads-up display", or the 2D on-screen display that is common in many games. Think health, ammo, gun reticle, etc. Each PlayerController typically has one of these. | +| **Camera** | The PlayerCameraManager is the "eyeball" for a player and manages how it behaves. Each PlayerController typically has one of these as well. For more, see the [camera workflow](Gameplay/Framework/Camera) page. | - [/PARAM] -[/OBJECT] +## Setting and Tracking the Rules of the Game -[OBJECT:IconSection] - [PARAM:icon] - ![](Gameplay/Framework/camera_lander.png)(w:300) - [/PARAM] - [PARAM:title] - Displaying Information to Players - [/PARAM] - [PARAM:description] - **HUD** +![](Gameplay/Framework/hud_lander.png)(w:300) - A [HUD](Gameplay/Framework/UIAndHUD) is a "heads-up display", or the 2D on-screen display that is common in many games. Think health, ammo, gun reticle, etc. Each PlayerController typically has one of these. - - **Camera** - - The PlayerCameraManager is the "eyeball" for a player and manages how it behaves. Each PlayerController typically has one of these as well. For more, see the [camera workflow](Gameplay/Framework/Camera) page. - [/PARAM] -[/OBJECT] - -[OBJECT:IconSection] - [PARAM:icon] - ![](Gameplay/Framework/hud_lander.png)(w:300) - [/PARAM] - [PARAM:title] - Setting and Tracking the Rules of the Game - [/PARAM] - [PARAM:description] - - **GameMode** - - The concept of a "game" is split into 2 classes. The [](Gameplay/Framework/GameMode) is the definition of the game, including things like the game rules and win conditions. It only exists on the server. It typically should not have much data that changes during play, and it definitely should not have transient data that clients need to know about. - - **GameState** - - The [](Gameplay/Framework/GameState) contains the state of the game, which could include things like the list of connected players, the score, where the pieces are in a chess game, or the list of what missions you have completed in an open world game. The GameState exists on the server and all clients and can replicate freely to keep all machines up to date. - - **PlayerState** - - A **PlayerState** is the state of a participant in the game, such as a human player or a bot that is simulating a player. Non-player AI that exists as part of the game would not have a PlayerState. Example data that would be appropriate in a PlayerState include player name, score, in-match level for something like a MOBA, or whether the player is currently carrying the flag in a CTF game. PlayerStates for all players exist on all machines (unlike PlayerControllers) and can replicate freely to keep things in sync. - - [/PARAM] -[/OBJECT] +||| +| --- | --- | +| **GameMode** | The concept of a "game" is split into 2 classes. The [](Gameplay/Framework/GameMode) is the definition of the game, including things like the game rules and win conditions. It only exists on the server. It typically should not have much data that changes during play, and it definitely should not have transient data that clients need to know about. | +| **GameState** | The [GameState](Gameplay/Framework/GameMode#GameState) contains the state of the game, which could include things like the list of connected players, the score, where the pieces are in a chess game, or the list of what missions you have completed in an open world game. The GameState exists on the server and all clients and can replicate freely to keep all machines up to date. | +| **PlayerState** | A **PlayerState** is the state of a participant in the game, such as a human player or a bot that is simulating a player. Non-player AI that exists as part of the game would not have a PlayerState. Example data that would be appropriate in a PlayerState include player name, score, in-match level for something like a MOBA, or whether the player is currently carrying the flag in a CTF game. PlayerStates for all players exist on all machines (unlike PlayerControllers) and can replicate freely to keep things in sync. | ## Framework Class Relationships diff --git a/Engine/Documentation/Source/Gameplay/Framework/QuickReference/QuickReference.JPN.udn b/Engine/Documentation/Source/Gameplay/Framework/QuickReference/QuickReference.JPN.udn index 45e65ad5c253..a9f60ed45db7 100644 --- a/Engine/Documentation/Source/Gameplay/Framework/QuickReference/QuickReference.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/Framework/QuickReference/QuickReference.JPN.udn @@ -1,12 +1,12 @@ -INTSourceChangelist:2735872 +INTSourceChangelist:3429254 Availability:Public Title:ゲームプレイ フレームワークのクイック リファレンス Crumbs:%ROOT%, Gameplay, Gameplay/Framework Description:ゲームルール、キャラクター、コントローラー、ユーザーインターフェースなど、ゲームのフレームワークを構成するクラスの概略 Version:4.9 -type:reference +type:overview parent:Gameplay/Framework -order:2 +order:0 tags:Gameplay Framework 基本的なゲームプレイ クラスにはプレイヤー、味方、敵を表す機能に加えて、プレイヤー入力もしくは AI ロジックでこれらのアバターを制御する機能が含まれます。プレイヤー用のヘッドアップ ディスプレイや @@ -16,90 +16,43 @@ tags:Gameplay Framework -[OBJECT:IconSection] - [PARAM:icon] - ![](Gameplay/Framework/pawn_lander.png)(w:300) - [/PARAM] - [PARAM:title] - ワールドでプレイヤー、友達、敵を表現する - [/PARAM] - [PARAM:description] - **ポーン** +## ワールドでプレイヤー、友達、敵を表現する - [](Gameplay/Framework/Pawn) はワールドで「エージェント」となりうるアクタです。ポーンはコントローラで所有することが可能で、入力の受け取りを簡単に設定でき、他のプレイヤーのような様々なことが行えます。ポーンは人間の形を前提としていないことにご注意ください。 +![](Gameplay/Framework/pawn_lander.png)(w:300) - **キャラクター** +||| +| --- | --- | +| **Pawn** | [](Gameplay/Framework/Pawn) はワールドで「エージェント」となりうるアクタです。ポーンはコントローラで所有することが可能で、入力の受け取りを簡単に設定でき、他のプレイヤーのような様々なことが行えます。ポーンは人間の形を前提としていないことにご注意ください。 | +| **Character** | [](Gameplay/Framework/Pawn/Character) は人間の形をしたポーンです。コリジョン用の CapsuleComponent と CharacterMovementComponent がデフォルトで付いています。人間の基本動作が可能で、ネットワーク全体でスムーズに動きをレプリケートでき、アニメーション関連機能も付いています。 | - [](Gameplay/Framework/Pawn/Character) は人間の形をしたポーンです。コリジョン用の CapsuleComponent と CharacterMovementComponent がデフォルトで付いています。人間の基本動作が可能で、ネットワーク全体でスムーズに動きをレプリケートでき、アニメーション関連機能も付いています。 +## プレイヤー入力や AI ロジックでポーンを制御する - [/PARAM] -[/OBJECT] +![](Gameplay/Framework/controller_lander.png)(w:300) -[OBJECT:IconSection] - [PARAM:icon] - ![](Gameplay/Framework/controller_lander.png)(w:300) - [/PARAM] - [PARAM:title] - プレイヤー入力や AI ロジックでポーンを制御する - [/PARAM] - [PARAM:description] +||| +| --- | --- | +| **Controller** | [](Gameplay/Framework/Controller) はポーンに指示を出す役目のアクタです。通常、 AIController と PlayerController の 2 タイプがあります。コントローラはポーンを「所有」して制御することができます。 | +| **PlayerController** | [](Gameplay/Framework/Controller/PlayerController) は、ポーンと、それをコントロールする人プレーヤーとの間のインターフェースです。PlayerController は、基本的に人プレイヤーの意思を表します。 | +| **AIController** | AIController は、ポーンを制御することができるシミュレートされた「意思」のようなものです。 | - **コントローラー** +## プレイヤーに情報を表示する - [](Gameplay/Framework/Controller) はポーンに指示を出す役目のアクタです。通常、 AIController と PlayerController の 2 タイプがあります。コントローラはポーンを「所有」して制御することができます。 +![](Gameplay/Framework/camera_lander.png)(w:300) - **プレイヤー コントローラー** +||| +| --- | --- | +| **HUD** | [HUD](Gameplay/Framework/UIAndHUD) はヘッドアップ ディスプレイです。多くのゲームで一般的な 2D オンスクリーン ディスプレイです。Health 、 ammo 、 gun reticle 等と思ってください。各 PlayerController には、これらのいずれかが通常あります。 | +| **Camera** | PlayerCameraManager はプレイヤーの「眼球」で、挙動を管理します。各 PlayerController は、通常これらのいずれかを持ちます。詳細は、 [camera workflow](Gameplay/Framework/Camera) ページをご覧ください。 | - [](Gameplay/Framework/Controller/PlayerController) は、ポーンと、それをコントロールする人プレーヤーとの間のインターフェースです。PlayerController は、基本的に人プレイヤーの意思を表します。 +## ゲームのルールを設定しトラックする - **AIController** +![](Gameplay/Framework/hud_lander.png)(w:300) - AIController は、ポーンを制御することができるシミュレートされた「意思」のようなものです。 - - [/PARAM] -[/OBJECT] - -[OBJECT:IconSection] - [PARAM:icon] - ![](Gameplay/Framework/camera_lander.png)(w:300) - [/PARAM] - [PARAM:title] - プレイヤーに情報を表示する - [/PARAM] - [PARAM:description] - **HUD** - - [HUD](Gameplay/Framework/UIAndHUD) はヘッドアップ ディスプレイです。多くのゲームで一般的な 2D オンスクリーン ディスプレイです。Health 、 ammo 、 gun reticle 等と思ってください。各 PlayerController には、これらのいずれかが通常あります。 - - **カメラ** - - PlayerCameraManager はプレイヤーの「眼球」で、挙動を管理します。各 PlayerController は、通常これらのいずれかを持ちます。詳細は、 [camera workflow](Gameplay/Framework/Camera) ページをご覧ください。 - [/PARAM] -[/OBJECT] - -[OBJECT:IconSection] - [PARAM:icon] - ![](Gameplay/Framework/hud_lander.png)(w:300) - [/PARAM] - [PARAM:title] - ゲームのルールを設定しトラックする - [/PARAM] - [PARAM:description] - - **GameMode** - - 「ゲーム」のコンセプトは 2 つのクラスに分割されます。[](Gameplay/Framework/GameMode) は、ゲーム ルールや勝敗条件など含めたゲームの定義です。サーバー上にのみ存在します。通常はプレイ中に変更されるデータがあまりあってはならず、クライアントが知る必要のある一時的なデータは絶対にあってはいけません。 - - **GameState** - - [](Gameplay/Framework/GameState) はゲームのステートを含みます。接続されたプレイヤーのリスト、スコア、チェス ゲームの駒の位置、オープンなワールドゲームで完了したミッションのリストなどが含まれます。GameState はサーバーとすべてのクライアント上に存在し、自由にレプリケートして全てのマシンを最新の状態に保つことができます。 - - **PlayerState** - - **PlayerState** は、人プレーヤーやプレイヤーをシミュレートしているボットなどの、ゲームの参加者のステートです。ゲームの一部として存在する非プレイヤーの AI は PlayerState を持ちません。PlayerState として適切なデータの例には、プレイヤー名、スコア、MOBA などの場合のインマッチ レベル、CTF ゲームでプレイヤーが今フラグを持っているかどうか、などがあります。すべてのマシン上ですべてのプレイヤーに対して PlayerStates が存在し (PlayerControllers とは異なります) 、自由にレプリケートして同期することができます。 - - [/PARAM] -[/OBJECT] +||| +| --- | --- | +| **GameMode** | 「ゲーム」のコンセプトは 2 つのクラスに分割されます。[](Gameplay/Framework/GameMode) は、ゲーム ルールや勝敗条件など含めたゲームの定義です。サーバー上にのみ存在します。通常はプレイ中に変更されるデータがあまりあってはならず、クライアントが知る必要のある一時的なデータは絶対にあってはいけません。 | +| **GameState** | [GameState](Gameplay/Framework/GameMode#GameState) はゲームのステートを含みます。接続されたプレイヤーのリスト、スコア、チェス ゲームの駒の位置、オープンなワールドゲームで完了したミッションのリストなどが含まれます。GameState はサーバーとすべてのクライアント上に存在し、自由にレプリケートして全てのマシンを最新の状態に保つことができます。 | +| **PlayerState** | **PlayerState** は、人プレーヤーやプレイヤーをシミュレートしているボットなどの、ゲームの参加者のステートです。ゲームの一部として存在する非プレイヤーの AI は PlayerState を持ちません。PlayerState として適切なデータの例には、プレイヤー名、スコア、MOBA などの場合のインマッチ レベル、CTF ゲームでプレイヤーが今フラグを持っているかどうか、などがあります。すべてのマシン上ですべてのプレイヤーに対して PlayerStates が存在し (PlayerControllers とは異なります) 、自由にレプリケートして同期することができます。 | ## Framework クラスの関係 diff --git a/Engine/Documentation/Source/Gameplay/Framework/QuickReference/QuickReference.KOR.udn b/Engine/Documentation/Source/Gameplay/Framework/QuickReference/QuickReference.KOR.udn index 9ae06a07781e..7106bfb5da29 100644 --- a/Engine/Documentation/Source/Gameplay/Framework/QuickReference/QuickReference.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/Framework/QuickReference/QuickReference.KOR.udn @@ -1,12 +1,12 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability:Public Title:게임플레이 프레임워크 간단 참고서 Crumbs:%ROOT%, Gameplay, Gameplay/Framework Description:게임의 프레임워크를 이루는 게임 규칙, 캐릭터, 콘트롤러, 유저 인터페이스 등에 대한 클래스 간단 개요입니다. Version: 4.9 -type:reference +type:overview parent:Gameplay/Framework -order:2 +order:0 tags:Gameplay Framework 기본적인 게임플레이 클래스에는 플레이어, 아군, 적군에 대한 표현 및 그에 대한 아바타를 플레이어 입력이나 AI 로직으로 제어하는 데 대한 함수성이 포함되어 있습니다. 또한 @@ -16,90 +16,43 @@ tags:Gameplay Framework -[OBJECT:IconSection] - [PARAM:icon] - ![](Gameplay/Framework/pawn_lander.png)(w:300) - [/PARAM] - [PARAM:title] - 월드에 플레이어, 아군, 적군 표시 - [/PARAM] - [PARAM:description] - **Pawn** 폰 +## 월드에 플레이어, 아군, 적군 표시 + +![](Gameplay/Framework/pawn_lander.png)(w:300) - [](Gameplay/Framework/Pawn) 이란 월드의 대리인 역할을 하는 Actor 입니다. Pawn 은 Controller 에 의해 possess(빙의) 가능하며, 입력을 쉽게 받을 수 있도록 구성 가능하고, 여러가지 다양한 플레이어같은 동작을 할 수 있습니다. 참고로 Pawn 은 인간형이라 가정되지 않습니다. +||| +| --- | --- | +| **Pawn** | [](Gameplay/Framework/Pawn) 이란 월드의 대리인 역할을 하는 Actor 입니다. Pawn 은 Controller 에 의해 possess(빙의) 가능하며, 입력을 쉽게 받을 수 있도록 구성 가능하고, 여러가지 다양한 플레이어같은 동작을 할 수 있습니다. 참고로 Pawn 은 인간형이라 가정되지 않습니다. | +| **Character** | [](Gameplay/Framework/Pawn/Character) 는 인간형 Pawn 입니다. 기본적으로 콜리전에 쓸 CapsuleComponent 와 CharacterMovementComponent 가 들어있습니다. 기본적인 인간형 동작을 할 수 있으며, 네트워크를 통해 부드러운 이동 리플리케이션이 가능하고, 애니메이션 관련 함수성도 약간 있습니다. | - **Character** 캐릭터 - - [](Gameplay/Framework/Pawn/Character) 는 인간형 Pawn 입니다. 기본적으로 콜리전에 쓸 CapsuleComponent 와 CharacterMovementComponent 가 들어있습니다. 기본적인 인간형 동작을 할 수 있으며, 네트워크를 통해 부드러운 이동 리플리케이션이 가능하고, 애니메이션 관련 함수성도 약간 있습니다. - - [/PARAM] -[/OBJECT] - -[OBJECT:IconSection] - [PARAM:icon] - ![](Gameplay/Framework/controller_lander.png)(w:300) - [/PARAM] - [PARAM:title] - 플레이어 인풋 또는 AI 로직으로 폰 제어하기 - [/PARAM] - [PARAM:description] +## 플레이어 인풋 또는 AI 로직으로 폰 제어하기 - **Controller** - - [](Gameplay/Framework/Controller) 는 Pawn 에 대한 지시를 담당하는 Actor 입니다. 보통 두 가지 형태로 등장하는데, AIController 와 PlayerController 입니다. 콘트롤러는 Pawn 에 "possess"(빙의)되어 그 폰을 제어할 수 있습니다. +![](Gameplay/Framework/controller_lander.png)(w:300) + +||| +| --- | --- | +| **Controller** | [](Gameplay/Framework/Controller) 는 Pawn 에 대한 지시를 담당하는 Actor 입니다. 보통 두 가지 형태로 등장하는데, AIController 와 PlayerController 입니다. 콘트롤러는 Pawn 에 "possess"(빙의)되어 그 폰을 제어할 수 있습니다. | +| **PlayerController** | [](Gameplay/Framework/Controller\PlayerController) 는 Pawn 과 그것을 제어하는 사람 플레이어를 잇는 인터페이스입니다. PlayerController 는 본질적으로 사람 플레이어의 의지를 나타냅니다. | +| **AIController** | AIController 는 말 그대로 Pawn 을 제어하는 의지를 시뮬레이션으로 재현한 것입니다. | - **PlayerController** - - [](Gameplay/Framework/Controller\PlayerController) 는 Pawn 과 그것을 제어하는 사람 플레이어를 잇는 인터페이스입니다. PlayerController 는 본질적으로 사람 플레이어의 의지를 나타냅니다. +## 플레이어에게 정보 표시하기 - **AIController** +![](Gameplay/Framework/camera_lander.png)(w:300) - AIController 는 말 그대로 Pawn 을 제어하는 의지를 시뮬레이션으로 재현한 것입니다. +||| +| --- | --- | +| **HUD** | [HUD](Gameplay/Framework/UIAndHUD) 는 "Heads-Up Display" 의 준말이며, 여러 게임에서 볼 수 있는 머리 위에 뜨는 화면 표시기같은 것으로, 생명력, 탄환 수, 총 조준선 등이 표시됩니다. 각 PlayerController 에는 보통 이와 같은 것이 하나씩 있습니다. | +| **Camera** | PlayerCameraManager 는 플레이어의 "눈"을 나타내며, 그 동작을 관리합니다. 각 PlayerController 에는 보통 하나씩 있습니다. 자세한 것은 [](Gameplay/Framework/Camera) 문서를 참고하세요. | - [/PARAM] -[/OBJECT] +## 게임의 규칙 설정 및 기록하기 -[OBJECT:IconSection] - [PARAM:icon] - ![](Gameplay/Framework/camera_lander.png)(w:300) - [/PARAM] - [PARAM:title] - 플레이어에게 정보 표시하기 - [/PARAM] - [PARAM:description] - **HUD** +![](Gameplay/Framework/hud_lander.png)(w:300) - [HUD](Gameplay/Framework/UIAndHUD) 는 "Heads-Up Display" 의 준말이며, 여러 게임에서 볼 수 있는 머리 위에 뜨는 화면 표시기같은 것으로, 생명력, 탄환 수, 총 조준선 등이 표시됩니다. 각 PlayerController 에는 보통 이와 같은 것이 하나씩 있습니다. - - **Camera** 카메라 - - PlayerCameraManager 는 플레이어의 "눈"을 나타내며, 그 동작을 관리합니다. 각 PlayerController 에는 보통 하나씩 있습니다. 자세한 것은 [](Gameplay/Framework/Camera) 문서를 참고하세요. - [/PARAM] -[/OBJECT] - -[OBJECT:IconSection] - [PARAM:icon] - ![](Gameplay/Framework/hud_lander.png)(w:300) - [/PARAM] - [PARAM:title] - 게임의 규칙 설정 및 기록하기 - [/PARAM] - [PARAM:description] - - **GameMode** - - "게임" 이라는 것의 개념은 두 개의 클래스로 나뉩니다. [](Gameplay/Framework/GameMode) 는 게임의 규칙이나 승리 조건같은 것이 포함된 게임의 정의로, 서버에만 존재합니다. 보통은 플레이 도중 바뀌는 데이터는 많이 없어야 하며, 클라이언트에서 알아야 하는 트랜션트(휘발성) 데이터는 반드시 없어야 할 것입니다. - - **GameState** - - [](Gameplay/Framework/GameState) 에는 접속된 플레이어 목록, 점수, 체크 게임에서 말들의 위치, 오픈 월드 게임에서 완료한 퀘스트 목록 등과 같은 것이 포함될 수 있는 게임 상태가 포함됩니다. GameState 는 서버와 모든 클라이언트에 존재하며, 최신 상태 유지를 위해 자유롭게 리플리케이트 가능합니다. - - **PlayerState** - - 인간 플레이어 또는 플레이어인 척 하는 봇과 같은 게임 참여자의 상태를 말합니다. 게임의 일부로써 존재하는 플레이어가 아닌 AI 에는 PlayerState 가 없습니다. PlayerState 에 적합한 예제 데이터라면, 플레이어 이름, 점수, MOBA 게임류에서의 대전상대 레벨, CTF 게임에서 플레이어가 현재 깃발을 운반중인지 여부 등입니다. 모든 플레이어에 대한 PlayerState 는 (PlayerController 와는 달리) 모든 머신에 존재하며, 동기화 상태 유지를 위해 자유로이 리플리케이트 가능합니다. - - [/PARAM] -[/OBJECT] +||| +| --- | --- | +| **GameMode** | "게임" 이라는 것의 개념은 두 개의 클래스로 나뉩니다. [](Gameplay/Framework/GameMode) 는 게임의 규칙이나 승리 조건같은 것이 포함된 게임의 정의로, 서버에만 존재합니다. 보통은 플레이 도중 바뀌는 데이터는 많이 없어야 하며, 클라이언트에서 알아야 하는 트랜션트(휘발성) 데이터는 반드시 없어야 할 것입니다. | +| **GameState** | [GameState](Gameplay/Framework/GameMode) 에는 접속된 플레이어 목록, 점수, 체크 게임에서 말들의 위치, 오픈 월드 게임에서 완료한 퀘스트 목록 등과 같은 것이 포함될 수 있는 게임 상태가 포함됩니다. GameState 는 서버와 모든 클라이언트에 존재하며, 최신 상태 유지를 위해 자유롭게 리플리케이트 가능합니다. | +| **PlayerState** | 인간 플레이어 또는 플레이어인 척 하는 봇과 같은 게임 참여자의 상태를 말합니다. 게임의 일부로써 존재하는 플레이어가 아닌 AI 에는 PlayerState 가 없습니다. PlayerState 에 적합한 예제 데이터라면, 플레이어 이름, 점수, MOBA 게임류에서의 대전상대 레벨, CTF 게임에서 플레이어가 현재 깃발을 운반중인지 여부 등입니다. 모든 플레이어에 대한 PlayerState 는 (PlayerController 와는 달리) 모든 머신에 존재하며, 동기화 상태 유지를 위해 자유로이 리플리케이트 가능합니다. | ## 프레임워크 클래스 관계 diff --git a/Engine/Documentation/Source/Gameplay/Framework/UIAndHUD/UIAndHUD.INT.udn b/Engine/Documentation/Source/Gameplay/Framework/UIAndHUD/UIAndHUD.INT.udn index 206584fe2048..cbbe2b9a8811 100644 --- a/Engine/Documentation/Source/Gameplay/Framework/UIAndHUD/UIAndHUD.INT.udn +++ b/Engine/Documentation/Source/Gameplay/Framework/UIAndHUD/UIAndHUD.INT.udn @@ -3,6 +3,10 @@ Title:User Interfaces & HUDs Crumbs:%ROOT%, Gameplay, Gameplay/Framework Description:Guides and information for artists and programmers creating user interfaces such as menus and HUDs. Version: 4.9 +topic-image:Gameplay/Framework/hud_lander.png +parent:Gameplay/Framework +order:6 +type:overview -ゲームがとプレイヤーとどのようにコミュニケーションし、相互作用するかという問題は極めて重要です。**ユーザー インターフェース** (UI) と **ヘッドアップ ディスプレイ** (HUD) は、ゲームについての情報をプレイヤーに与えたり、場合によってはプレイヤーがゲームと相互に作用できるようにします。 +ゲームがプレイヤーとどのようにコミュニケーションし、相互作用するかという問題は極めて重要です。**ユーザー インターフェース** (UI) と **ヘッドアップ ディスプレイ** (HUD) は、ゲームについての情報をプレイヤーに与えたり、場合によってはプレイヤーがゲームと相互に作用できるようにします。 アンリアル エンジン 4 (UE4) には、UI と HUD を作成するためのいくつかの方法があります。`Canvas` クラスを使用すると、ローレベルでスクリーンに直接描画が可能になり、ワールド上にオーバーレイできます。 @@ -48,7 +52,7 @@ HUD とは、ゲームプレイ中にスクリーン上でオーバーレイ表 ## HUD -**HUD** は、スクリーン上にオーバーレイする要素を表示するための基本オブジェクトです。ゲーム内でユーザーがコントロールするすべてのプレイヤーは、各自で +**HUD** は、スクリーン上にオーバーレイされる要素を表示するための基本クラスです。ゲーム内でユーザーがコントロールするすべてのプレイヤーは、各自で `AHUD` クラスのインスタンスを持ち、それらは個々のビューポートに描画されます。分割スクリーンのマルチプレイヤー ゲームの場合、 複数のビューポートが同じスクリーンを共有しますが、各 HUD は各自のビューポートに描画します。使用する HUD のタイプやクラスは、 使用しているゲームタイプによって指定されます。 diff --git a/Engine/Documentation/Source/Gameplay/Framework/UIAndHUD/UIAndHUD.KOR.udn b/Engine/Documentation/Source/Gameplay/Framework/UIAndHUD/UIAndHUD.KOR.udn index 9047efaaf5c8..75da3a7a4b0b 100644 --- a/Engine/Documentation/Source/Gameplay/Framework/UIAndHUD/UIAndHUD.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/Framework/UIAndHUD/UIAndHUD.KOR.udn @@ -1,9 +1,13 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:유저 인터페이스와 HUD Crumbs:%ROOT%, Gameplay, Gameplay/Framework Description:메뉴와 HUD 같은 유저 인터페이스를 만드는 아티스트와 프로그래머를 위한 정보와 안내서입니다. Version: 4.9 +topic-image:Gameplay/Framework/hud_lander.png +parent:Gameplay/Framework +order:6 +type:overview -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/ActorInput" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/ActorInput/ActorInputOverview.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/ActorInput/ActorInputOverview.JPN.udn index b00c0433e65f..d84c533cf1ff 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/ActorInput/ActorInputOverview.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/ActorInput/ActorInputOverview.JPN.udn @@ -1,27 +1,21 @@ -INTSourceChangelist:2815879 +INTSourceChangelist:3429254 Availability:Public Title:アクタに入力を設定する操作手順 Crumbs: %ROOT%, Gameplay Description:UE4 でアクタに入力を設定するための操作ガイド Version:4.9 Parent:Gameplay -type:how-to +SkillLevel:Intermediate +type:overview order:9 ゲーム開発中に、レベル内のアクタにプレイヤーが何らかの **入力** をできるようにさせたい場合があります。例えば、プレイヤーが近づくと宝物箱が開くようにしたり、ライトのオンオフの切り替えができたり、あるいはプレイヤーがボタンを押すと、何らかの影響を与えるインタラクティブなオブジェクトが考えられます。 アクタに入力を設定すると、プレイヤー入力にそのアクタが反応する方法とタイミングをある程度制御できるようになります。詳細は、以下の **設定** セクションのリンクを参照してください。 -## セットアップ +## 実装ガイド -ブループリントを使用して **アクタに入力を設定する方法** については、以下のリンクを参照してください。 - -[REGION:buttonlist] -* [](Gameplay\HowTo\ActorInput\Blueprints) - -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/ActorInput" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/ActorInput/ActorInputOverview.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/ActorInput/ActorInputOverview.KOR.udn index 7c81999f041f..dc1d045fa2da 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/ActorInput/ActorInputOverview.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/ActorInput/ActorInputOverview.KOR.udn @@ -1,27 +1,21 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:액터에 입력 구성 Crumbs: %ROOT%, Gameplay Description:언리얼 엔진 4 에서 액터에 입력을 구성하는 비법 안내서입니다. Version: 4.9 Parent:Gameplay -type:how-to +SkillLevel: Intermediate +type:overview order:9 게임 개발시 플레이어가 레벨의 액터에 일정한 형태의 **입력** 이 가능하도록 하고 싶을 때가 있습니다. 예를 들어 플레이어가 다가가서 열 수 있도록 하고픈 보물상자라든가, 껐다 켰다 할 수 있는 라이트라든가, 기타 플레이어가 버튼을 눌러 어떤 식으로든 영향을 끼치고자 하는 상호작용형 오브젝트가 있을 수 있습니다. 액터에 입력을 구성하면 액터가 언제 어떻게 플레이어 입력에 반응하는지에 대한 일정 수준의 제어가 가능합니다. 자세한 정보는, 아래 **구성** 부분의 링크를 참고하세요. -## 구성 +## 구현 안내 -블루프린트를 사용한 **액터에 대한 입력 구성** 관련 상세 정보는 다음 링크를 참고하세요: - -[REGION:buttonlist] -* [](Gameplay\HowTo\ActorInput\Blueprints) - -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/ActorInput" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/ActorInput/Blueprints/ActorInput_BP.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/ActorInput/Blueprints/ActorInput_BP.INT.udn index 068fcf83651d..8f31ed14f54c 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/ActorInput/Blueprints/ActorInput_BP.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/ActorInput/Blueprints/ActorInput_BP.INT.udn @@ -3,6 +3,7 @@ Title:Setting Up Input on an Actor in Blueprints Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\ActorInput Description:A How To Guide for setting up input on an Actor in Blueprints. Version: 4.9 +type:how-to SkillLevel: Intermediate [TOC (start:2 end:2)] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/ActorInput/Blueprints/ActorInput_BP.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/ActorInput/Blueprints/ActorInput_BP.JPN.udn index a0ef93e030f2..5fae3f3e5184 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/ActorInput/Blueprints/ActorInput_BP.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/ActorInput/Blueprints/ActorInput_BP.JPN.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:2699852 +INTSourceChangelist:3429254 Availability:Public Title:ブループリントでアクタに入力を設定する操作手順 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\ActorInput Description:ブループリントでアクタに入力を設定するためのガイド Version:4.9 +type:how-to SkillLevel:Intermediate [TOC (start:2 end:2)] @@ -15,7 +16,7 @@ SkillLevel:Intermediate ## アクタの入力を有効にする - _この例では、**Blueprint First Person Template with Starter Content** を使用します。_ + _この例では、**スターターコンテンツを含む Blueprint First Person Template ** を使用します。_ 以下の方法で、アクタの入力を有効にします。 @@ -46,7 +47,7 @@ SkillLevel:Intermediate ![](input_2.png) -上記の例では、前述の方法でアクタの入力を有効にしてから、 **E** Key Event を追加しました。E キーが押されると、アクタへ入力を与えないように、画面に何らかのテキストを表示してアクタの入力を無効にします。 +上記の例では、前述の方法でアクタの入力を有効にしてから、 **E** Key Event を追加しました。**E** キーが押されると、アクタへ入力を与えないように、画面に何らかのテキストを表示してアクタの入力を無効にします。 **Enable Input** ノードと同様、 **Disable Input** ノードは **Target** と **Player Controller** を指定する必要があります。 @@ -75,7 +76,7 @@ SkillLevel:Intermediate ![](input_5.png) -1. **[Trigger]** を **右クリック** し、 **Add Event -> Add OnComponentEndOverla** を選びます。 +1. **[Trigger]** を **右クリック** し、 **[Add Event -> Add OnComponentEndOverla]** を選びます。 ![](input_5b.png) @@ -97,11 +98,11 @@ SkillLevel:Intermediate プレイヤーがトリガー領域に入る時のみ入力は有効になり、プレイヤーがトリガーを離れると無効になります。これにより、プレイヤーがワールドのどこからでもアクタに影響してしまうことを防ぎ、作成したトリガー領域の内部にいる場合のみに制限されます。 -1. **E** Key イベントを **右クリック** し **Print String** ノードに追加します。 +1. **E** Key Event を **右クリック** し **Print String** ノードに追加します。 ![](input_8.png) -1. **コンパイル** し **保存** してから、ブループリントを終了します(もし警告が表示されても、無視して次のステップへ進んでください)。 +1. **コンパイル** し **保存** してから、ブループリントを終了します (もし警告が表示されても、無視して次のステップへ進んでください)。 1. **Blueprint_CeilingLight** をレベルにドラッグし、 **[Play]** ボタンをクリックしてエディタで再生します。 diff --git a/Engine/Documentation/Source/Gameplay/HowTo/ActorInput/Blueprints/ActorInput_BP.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/ActorInput/Blueprints/ActorInput_BP.KOR.udn index 91a4e2672972..4070f35472be 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/ActorInput/Blueprints/ActorInput_BP.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/ActorInput/Blueprints/ActorInput_BP.KOR.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:블루프린트로 액터에 입력 구성 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\ActorInput Description:블루프린트로 액터에 입력을 구성하는 비법 안내서입니다. Version: 4.9 +type:how-to SkillLevel: Intermediate [TOC (start:2 end:2)] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/AddingComponents/Blueprints/Components_BP.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/AddingComponents/Blueprints/Components_BP.INT.udn index a59b0cea0a11..b08ae1c7301e 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/AddingComponents/Blueprints/Components_BP.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/AddingComponents/Blueprints/Components_BP.INT.udn @@ -4,6 +4,7 @@ Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\AddingComponents Description:A How To Guide for Adding Components in Blueprints. Version: 4.9 SkillLevel: Intermediate +type:how-to [TOC (start:2 end:2)] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/AddingComponents/Blueprints/Components_BP.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/AddingComponents/Blueprints/Components_BP.JPN.udn index 6e7da9973f66..10ad60acc418 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/AddingComponents/Blueprints/Components_BP.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/AddingComponents/Blueprints/Components_BP.JPN.udn @@ -1,10 +1,11 @@ -INTSourceChangelist:2699877 +INTSourceChangelist:3429254 Availability:Public Title:ブループリントにコンポーネントを追加する Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\AddingComponents Description:ブループリントにコンポーネントを追加するための操作ガイド Version:4.9 SkillLevel:Intermediate +type:how-to [TOC (start:2 end:2)] @@ -16,7 +17,7 @@ SkillLevel:Intermediate 以下は、Blueprint アクタにコンポーネントを追加するステップです。 -1. **コンテンツ ブラウザ** の **「StarterContent/Props」** フォルダの **SM_Bush** アセットを **右クリック** し、**Asset Actions** まで上方にスクロールし、**[Create Blueprint Using This...]** を選択します。 +1. **コンテンツ ブラウザ** の **「StarterContent/Props」** フォルダの **SM_Bush** アセットを **右クリック** し、**Asset Actions** までスクロールし、**[Create Blueprint Using This...]** を選択します。 ![](Components1.jpg) @@ -38,7 +39,7 @@ SkillLevel:Intermediate このウィンドウでコンポーネントをブループリントに追加できるようになります。この場合だと、炎とオーディオ エフェクトを追加できます。 -1. **[Audio]** をクリックして Audio コンポーネントを追加し、 **[Components]** ウィンドウの下に追加された **[Details]** ウィンドウに注目してください。 +1. **[Audio]** をクリックして Audio コンポーネントを追加すると、 **[Components]** ウィンドウの下の **[Details]** ウィンドウにデータが入ります。 ![](Components4.png) @@ -74,10 +75,10 @@ SkillLevel:Intermediate 茂みからは炎があがり、炎のオーディオ エフェクトが再生されていることが分かります。茂みから遠ざかるとオーディオは徐々に小さくなり、茂みに近づくと徐々に大きくなります。 -これで、3 つのコンポーネントで構成される Blueprint アクタが作成されました。レベル内に置いた茂みにオーディオと炎を付けることも可能ですが、それだと要素がバラバラになるので、 3 つのコンポーネントで構成されるブループリントを 1 つ作成した方が管理は遥かに楽になります。 +これで、3 つのコンポーネントで構成される Blueprint アクタが作成されました。レベルに茂みを配置し、茂みの中にオーディオを配置して、茂み内に炎を配置することも可能ですが、それだと要素がバラバラになるので、 3 つのコンポーネントで構成されるブループリントを 1 つ作成した方が管理は遥かに楽になります。 -## ブループリントのコンポーネントで作業する +## ブループリントでコンポーネントの作業をする ブループリント内の各コンポーネントはブループリント自体から、または外部のブループリントからのアクセスと修正が可能です。例えば、 Car ブループリントがあり、コンポーネントとして Engine ブループリントがあった場合、Engine ブループリント内の値を調整することにより Car が動作する方法を修正することができます。 @@ -85,7 +86,7 @@ SkillLevel:Intermediate ![](Components12.png) -これらのコンポーネントをひとつづつグラフ内に配置し、ブループリント スクリプトによるアクセスと修正が可能です (以下の例を参照)。 +これらのコンポーネントをひとつずつグラフ内に配置し、ブループリント スクリプトによるアクセスと修正が可能です (以下の例を参照)。 ![](Components13.png) @@ -94,7 +95,7 @@ SkillLevel:Intermediate ## 追加のリソース -ブループリントにコンポーネントを追加することに関係するコンセプトを、以下のリンクで参照することができます。 +ブループリントにコンポーネントを追加することに関する考え方を、以下のリンクで参照することができます。 * [ブループリント ユーザーガイド](Engine/Blueprints/UserGuide) * [ブループリントでコンポーネントを使用する](Engine/Blueprints/UserGuide/Components) diff --git a/Engine/Documentation/Source/Gameplay/HowTo/AddingComponents/Blueprints/Components_BP.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/AddingComponents/Blueprints/Components_BP.KOR.udn index 0f98026166c1..b016e5a1142c 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/AddingComponents/Blueprints/Components_BP.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/AddingComponents/Blueprints/Components_BP.KOR.udn @@ -1,10 +1,11 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:블루프린트에서 컴포넌트 추가 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\AddingComponents Description:블루프린트에서 컴포넌트를 추가하는 방법 안내입니다. Version: 4.9 SkillLevel: Intermediate +type:how-to [TOC (start:2 end:2)] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/AddingComponents/ComponentsOverview.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/AddingComponents/ComponentsOverview.INT.udn index 76a78eefa420..434df2ae5833 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/AddingComponents/ComponentsOverview.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/AddingComponents/ComponentsOverview.INT.udn @@ -4,21 +4,15 @@ Crumbs: %ROOT%, Gameplay Description:A How To Guide for Adding Components to Actors in Unreal Engine 4. Version: 4.9 Parent:Gameplay -type:how-to +SkillLevel: Intermediate +type:overview order:13 **Components** are a special type of **Object** designed to be used as sub-objects within **Actors**. These are generally used in situations where it is necessary to have easily swappable parts in order to change the behavior or functionality of some particular aspect of the owning Actor. For instance, a car is controlled and moves very differently from an aircraft, which is controlled and moves differently from a boat, etc.; yet all of these are vehicles that share other commonalities. By using a Component to handle the controls and movement, the same vehicle can easily be made to behave like any one of these specific types. -## Setup +## Implementation Guides -To learn more about **Adding Components to an Actor using Blueprints**, follow the link below: - -[REGION:buttonlist] -* [](Gameplay\HowTo\AddingComponents\Blueprints) - -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/AddingComponents" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/AddingComponents/ComponentsOverview.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/AddingComponents/ComponentsOverview.JPN.udn index 664ecb328048..dc27bdd071e6 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/AddingComponents/ComponentsOverview.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/AddingComponents/ComponentsOverview.JPN.udn @@ -1,25 +1,19 @@ -INTSourceChangelist:2815879 +INTSourceChangelist:3429254 Availability:Public Title:アクタにコンポーネントを追加する Crumbs: %ROOT%, Gameplay Description:UE4 でアクタにコンポーネントを追加するための操作ガイド Version:4.9 Parent:Gameplay -type:how-to +SkillLevel:Intermediate +type:overview order:13 -**コンポーネント** は、**アクタ** 内のサブオブジェクトとして使用するように設計された特殊な **オブジェクト** です。コンポーネントは、所有するアクタの特定の動作や機能を変更するために、簡単に取り替えられる部分が必要な状況で一般的に使用されます。例えば、車の制御や動きは飛行機とは異なり、飛行機の制御や動きは船とは異なります。しかし、これらはすべて他に共通点を持つ乗り物です。コンポーネントを使って制御や動きを処理することにより、いずれかの特定タイプと同様の動作をする乗り物を簡単に作成できます。 +**コンポーネント** は、**アクタ** 内のサブオブジェクトとして使用するように設計された特殊な **オブジェクト** です。コンポーネントは、所有するアクタの特定の動作や機能を変更するために、簡単に取り替えられる部分が必要な状況で一般的に使用されます。例えば、車の制御や動きは飛行機とは異なり、飛行機の制御や動きは船とは異なります。しかし、これらはすべて他に共通点を持つビークル (乗り物) です。コンポーネントを使って制御や動きを処理することにより、他のタイプと同様の動作をする乗り物を簡単に作成できます。 -## セットアップ +## 実装ガイド -ブループリントを使用して **アクタにコンポーネントを追加する方法** については、以下のリンクを参照してください。 - -[REGION:buttonlist] -* [](Gameplay\HowTo\AddingComponents\Blueprints) - -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/AddingComponents" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/AddingComponents/ComponentsOverview.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/AddingComponents/ComponentsOverview.KOR.udn index cf86f0cfcd68..b55e9a98b835 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/AddingComponents/ComponentsOverview.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/AddingComponents/ComponentsOverview.KOR.udn @@ -1,25 +1,19 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:액터에 코멘트 추가 Crumbs: %ROOT%, Gameplay Description:언리얼 엔진 4 에서 액터에 컴포넌트를 추가하는 비법 안내서입니다. Version: 4.9 Parent:Gameplay -type:how-to +SkillLevel: Intermediate +type:overview order:13 **Component**, 컴포넌트는 **액터** 안에서 하위 오브젝트로 사용하도록 디자인된 특수한 유형의 **오브젝트** 입니다. 일반적으로 액터 특정 부분의 작동방식이나 함수성을 쉽게 교환할 수 있는 부속처럼 만들고자 하는 상황에 사용됩니다. 예를 들어 차량의 제어 및 이동 방식은 비행기와는 매우 다르며, 보트 등과도 다릅니다. 하지만 이 모두는 탈것이라는 공통 속성이 있습니다. 컴포넌트를 사용하여 조작 및 이동 처리를 함으로써, 그 중 한 가지 유형처럼 작동하는 비히클을 쉽게 만들 수 있습니다. -## 구성 +## 구현 안내 -블루프린트를 사용하여 **액터에 컴포넌트를 추가하는** 법은 아래 링크를 참고하세요: - -[REGION:buttonlist] -* [](Gameplay\HowTo\AddingComponents\Blueprints) - -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/AddingComponents" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Crouch/Crouch_ABP.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Crouch/Crouch_ABP.INT.udn index 281cb3da5d94..29cf22570247 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Crouch/Crouch_ABP.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Crouch/Crouch_ABP.INT.udn @@ -3,25 +3,13 @@ Title:6. Animation Blueprint - Crouch States Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement, Gameplay\HowTo\CharacterMovement\Blueprints Description:Continuing on setting up the Animation Blueprint for our Character, in this section we set up the Crouch States. Version: 4.9 +Parent:Gameplay/HowTo/CharacterMovement/Blueprints SkillLevel:Advanced +type:how-to +type:multi-step +order:6 -[VAR:Steps] -[OBJECT:Navigation] - [PARAM:previous] - [Previous Step](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Walk "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Walk:title%") - [/PARAM] - [PARAM:current] - [/PARAM] - [PARAM:home] - [Character Movement Overview](Gameplay\HowTo\CharacterMovement\Blueprints) - [/PARAM] - [PARAM:next] - [Next Step](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jog "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jog:title%") - [/PARAM] -[/OBJECT] -[/VAR] - -%Steps% +[NAV] In this section, we continue working on the **Animation Blueprint** and the **State Machine** focusing on the **Crouch** states. @@ -96,4 +84,4 @@ In this section, we continue working on the **Animation Blueprint** and the **St 1. **Compile** and **Save** the Animation Blueprint. -%Steps% +[NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Crouch/Crouch_ABP.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Crouch/Crouch_ABP.JPN.udn index b77558305b47..d7e4ef5cb75e 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Crouch/Crouch_ABP.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Crouch/Crouch_ABP.JPN.udn @@ -1,25 +1,16 @@ -Availability:Public +INTSourceChangelist:3429254 +Availability:Public Title:6.Animationブループリント - Crouch ステート Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement, Gameplay\HowTo\CharacterMovement\Blueprints -Description:引き続きキャラクターに Animation ブループリントの設定を行います。このセクションでは Crouch States の設定をします。 +Description:引き続きキャラクターに Animation ブループリントの設定を行います。このセクションでは Crouch ステートの設定をします。 +Version:4.9 +Parent:Gameplay/HowTo/CharacterMovement/Blueprints +SkillLevel:Advanced +type:how-to +type:multi-step +order:6 -[VAR:Steps] -[OBJECT:Navigation] - [PARAM:previous] - [前のステップ](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Walk "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Walk:title%") - [/PARAM] - [PARAM:current] - [/PARAM] - [PARAM:home] - [キャラクターの移動の概要](Gameplay\HowTo\CharacterMovement\Blueprints) - [/PARAM] - [PARAM:next] - [次のステップ](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jog "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jog:title%") - [/PARAM] -[/OBJECT] -[/VAR] - -%Steps% +[NAV] 引き続き **Animation ブループリント** と **ステートマシン** を使って、このセクションでは **Crouch** ステートに焦点を当てていきます。 @@ -58,7 +49,7 @@ Description:引き続きキャラクターに Animation ブループリントの ここで、 Crouch Walk から Crouch Idle (および Crouch Idle から Crouch Walk) になる移行を設定します。Crouch Idle から Standing Idle (および Standing Idle から Crouch Idle) になる遷移を設定します。 - 必要であれば、遷移がスムーズになるように、グラフ上にノードを移動させることもできます。 + 必要であれば、遷移がスムーズになるように、グラフ上でノードを移動させることもできます。 1. **Idle_Rifle_Hip** から **Crouch_Idle_Rifle_Hip** への **遷移ルール** を開きます。 @@ -94,4 +85,4 @@ Description:引き続きキャラクターに Animation ブループリントの 1. Animation ブループリントを **コンパイル** し **保存** します。 -%Steps% \ No newline at end of file +[NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Crouch/Crouch_ABP.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Crouch/Crouch_ABP.KOR.udn index 887a8ef35b76..1a4782122f5f 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Crouch/Crouch_ABP.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Crouch/Crouch_ABP.KOR.udn @@ -1,28 +1,16 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:6. 애니메이션 블루프린트 - 웅크리기 상태 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement, Gameplay\HowTo\CharacterMovement\Blueprints Description:캐릭터의 애니메이션 블루프린트 구성을 계속해서, 이번에는 웅크리기 상태를 구성합니다. Version: 4.9 +Parent:Gameplay/HowTo/CharacterMovement/Blueprints SkillLevel:Advanced +type:how-to +type:multi-step +order:6 -[VAR:Steps] -[OBJECT:Navigation] - [PARAM:previous] - [예전 단계](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Walk "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Walk:title%") - [/PARAM] - [PARAM:current] - [/PARAM] - [PARAM:home] - [캐릭터 무브먼트 개요](Gameplay\HowTo\CharacterMovement\Blueprints) - [/PARAM] - [PARAM:next] - [다음 단계](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jog "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jog:title%") - [/PARAM] -[/OBJECT] -[/VAR] - -%Steps% +[NAV] 여기서는 **애니메이션 블루프린트** 와 **스테이트 머신** 작업을 이어 **Crouch** 웅크리기 상태에 초점을 맞춰보겠습니다. @@ -97,4 +85,4 @@ SkillLevel:Advanced 1. 애니메이션 블루프린트를 **컴파일** 하고 **저장** 합니다. -%Steps% \ No newline at end of file +[NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Jog/Jog_ABP.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Jog/Jog_ABP.INT.udn index 1ad0aa1697aa..f7e1cb76c53e 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Jog/Jog_ABP.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Jog/Jog_ABP.INT.udn @@ -3,25 +3,13 @@ Title:7. Animation Blueprint - Jog State Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement, Gameplay\HowTo\CharacterMovement\Blueprints Description:This section focuses on setting up the Jog States for our Character. Version: 4.9 +Parent:Gameplay/HowTo/CharacterMovement/Blueprints SkillLevel:Advanced +type:how-to +type:multi-step +order:7 -[VAR:Steps] -[OBJECT:Navigation] - [PARAM:previous] - [Previous Step](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Crouch "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Crouch:title%") - [/PARAM] - [PARAM:current] - [/PARAM] - [PARAM:home] - [Character Movement Overview](Gameplay\HowTo\CharacterMovement\Blueprints) - [/PARAM] - [PARAM:next] - [Next Step](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jump "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jump:title%") - [/PARAM] -[/OBJECT] -[/VAR] - -%Steps% +[NAV] Continuing in the **Animation Blueprint** and **State Machine**, this section we set up the **Jog** state and transitions to/from it. @@ -98,4 +86,4 @@ Continuing in the **Animation Blueprint** and **State Machine**, this section we 1. **Compile** and **Save** the Animation Blueprint. -%Steps% +[NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Jog/Jog_ABP.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Jog/Jog_ABP.JPN.udn index 067949196b17..5c99387a8cd1 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Jog/Jog_ABP.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Jog/Jog_ABP.JPN.udn @@ -1,27 +1,18 @@ -Availability:Public +INTSourceChangelist:3429254 +Availability:Public Title:7.Animation ブループリント - Jog ステート Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement, Gameplay\HowTo\CharacterMovement\Blueprints Description:このセクションではキャラクターの Jog ステートの設定に焦点を当てます。 +Version:4.9 +Parent:Gameplay/HowTo/CharacterMovement/Blueprints +SkillLevel:Advanced +type:how-to +type:multi-step +order:7 -[VAR:Steps] -[OBJECT:Navigation] - [PARAM:previous] - [前のステップ](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Crouch "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Crouch:title%") - [/PARAM] - [PARAM:current] - [/PARAM] - [PARAM:home] - [キャラクターの移動の概要](Gameplay\HowTo\CharacterMovement\Blueprints) - [/PARAM] - [PARAM:next] - [次のステップ](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jump "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jump:title%") - [/PARAM] -[/OBJECT] -[/VAR] +[NAV] -%Steps% - -引き続き **Animation ブループリント** と **ステートマシン** を使って、このセクションでは **Jog** ステートと遷移の設定を行います。 +引き続き **Animation ブループリント** と **ステートマシン** を使って、このセクションでは **Jog** ステートへの遷移、**Jog** ステートからの遷移の設定を行います。 1. ステートマシン グラフに戻って **アセットブラウザ** で **Jog_BS** をグラフにドラッグします。 @@ -37,19 +28,19 @@ Description:このセクションではキャラクターの Jog ステートの ![](AnimBP_Jog3.png) -1. **Crouch_Idle_Rifle_Hip** から **Jog_BS** への **遷移ルール** を開いて、以下のグラフを再度作成します。 +1. **Crouch_Idle_Rifle_Hip** から **Jog_BS** への **Transition Rule (遷移ルール)** を開いて、以下のグラフを再度作成します。 ![](AnimBP_Jog3b.png) Is Jogging が _True_ でプレイヤーの速度が 0 より大きい場合、 Jogging Blend Space になります。 -1. ステートマシン グラフに戻り、 **Jog_BS** から **Crouch_Idle_Rifle_Hip** への **遷移ルール** を開きます。 +1. ステートマシン グラフに戻り、 **Jog_BS** から **Crouch_Idle_Rifle_Hip** への **Transition Rule** を開きます。 -1. **遷移ルール** 内のグラフを以下のように作成します。 +1. **Transition Rule** 内のグラフを以下のように作成します。 ![](AnimBP_Jog3c.png) - ここで、プレイヤーが Jog ステートから Crouch ステート になれるようにします (走るのをやめたら Crouch に戻ります)。 + ここで、プレイヤーが Crouch ステートから Jog ステートになれるようにします (走るのをやめたら Crouch に戻ります)。 1. ステートマシン グラフに戻り **Crouch_BS** から **Jog_BS** へ、および **Jog_BS** から **Crouch_BS** への **遷移** を作成します。 @@ -96,4 +87,4 @@ Description:このセクションではキャラクターの Jog ステートの 1. Animation ブループリントを **コンパイル** し **保存** します。 -%Steps% \ No newline at end of file +[NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Jog/Jog_ABP.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Jog/Jog_ABP.KOR.udn index 8833a25b7408..2f00510e492c 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Jog/Jog_ABP.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Jog/Jog_ABP.KOR.udn @@ -1,28 +1,16 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:7. 애니메이션 블루프린트 - 조깅 상태 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement, Gameplay\HowTo\CharacterMovement\Blueprints Description:캐릭터의 조깅 상태 구성에 초점을 맞춥니다. Version: 4.9 +Parent:Gameplay/HowTo/CharacterMovement/Blueprints SkillLevel:Advanced +type:how-to +type:multi-step +order:7 -[VAR:Steps] -[OBJECT:Navigation] - [PARAM:previous] - [예전 단계](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Crouch "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Crouch:title%") - [/PARAM] - [PARAM:current] - [/PARAM] - [PARAM:home] - [캐릭터 무브먼트 개요](Gameplay\HowTo\CharacterMovement\Blueprints) - [/PARAM] - [PARAM:next] - [다음 단계](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jump "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jump:title%") - [/PARAM] -[/OBJECT] -[/VAR] - -%Steps% +[NAV] **애니메이션 블루프린트** 와 **스테이트 머신** 작업을 이어서, 여기서는 **Jog** (조깅) 상태와 거기서 나가고 들어오는 전환을 구성하겠습니다. @@ -99,4 +87,4 @@ SkillLevel:Advanced 1. 애니메이션 블루프린트를 **컴파일** 하고 **저장** 합니다. -%Steps% \ No newline at end of file +[NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Jump/Jump_ABP.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Jump/Jump_ABP.INT.udn index 19548996af75..65219cbd9b21 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Jump/Jump_ABP.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Jump/Jump_ABP.INT.udn @@ -3,25 +3,13 @@ Title:8. Animation Blueprint - Jump States Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement, Gameplay\HowTo\CharacterMovement\Blueprints Description:Moving on in our Animation Blueprint setup, here we set up the conditions for Jumping. Version: 4.9 +Parent:Gameplay/HowTo/CharacterMovement/Blueprints SkillLevel:Advanced +type:how-to +type:multi-step +order:8 -[VAR:Steps] -[OBJECT:Navigation] - [PARAM:previous] - [Previous Step](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jog "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jog:title%") - [/PARAM] - [PARAM:current] - [/PARAM] - [PARAM:home] - [Character Movement Overview](Gameplay\HowTo\CharacterMovement\Blueprints) - [/PARAM] - [PARAM:next] - [Next Step](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Prone "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Prone:title%") - [/PARAM] -[/OBJECT] -[/VAR] - -%Steps% +[NAV] Next, we configure the **Jump** states inside the **State Machine**. We are going to have two Jump states, one for when the player is standing still and presses the Jump key and another for when the player is moving (Jogging, Crouch Walking, or Walking). We will use two different animations, one for stationary and one for movement. @@ -87,4 +75,4 @@ Next, we configure the **Jump** states inside the **State Machine**. We are goin 1. **Compile** and **Save** the Animation Blueprint. -%Steps% +[NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Jump/Jump_ABP.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Jump/Jump_ABP.JPN.udn index fe9dd40f1833..a6239c601435 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Jump/Jump_ABP.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Jump/Jump_ABP.JPN.udn @@ -1,32 +1,20 @@ -INTSourceChangelist:2740691 +INTSourceChangelist:3429254 Availability:Public Title:8.Animation ブループリント - Jump ステート Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement, Gameplay\HowTo\CharacterMovement\Blueprints -Description:Animation ブループリントの設定です。ここではジャンプする条件を設定します。 +Description:Animation ブループリントを設定します。ここではジャンプする条件を設定します。 Version:4.9 +Parent:Gameplay/HowTo/CharacterMovement/Blueprints SkillLevel:Advanced +type:how-to +type:multi-step +order:8 -[VAR:Steps] -[OBJECT:Navigation] - [PARAM:previous] - [前のステップ](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jog "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jog:title%") - [/PARAM] - [PARAM:current] - [/PARAM] - [PARAM:home] - [キャラクターの移動の概要](Gameplay\HowTo\CharacterMovement\Blueprints) - [/PARAM] - [PARAM:next] - [次のステップ](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Prone "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Prone:title%") - [/PARAM] -[/OBJECT] -[/VAR] - -%Steps% +[NAV] **ステートマシン** 内で **Jump** ステートを設定します。2 種類の Jump ステートを設定します。 1 つは静止した状態から、もう 1 つはプレイヤーが移動中 (Jogging、Crouch Walking または Walking) に Jump キーを押します。静止と移動という、 2 つの異なるアニメーションを使います。 -1. ステートマシン グラフで、 **アセットブラウザ** から **Jump_From_Jog** をドラッグします。 +1. ステートマシン グラフで、 **アセットブラウザ** から **Jump_From_Jog** アニメーションをドラッグします。 ![](AnimBP_Jump1.png) @@ -38,7 +26,7 @@ SkillLevel:Advanced 1. ステートマシン グラフに戻り、 **Jump_From_Jog** から **Jog_BS** への **遷移ルール** を開きます。 -1. **遷移ルール** グラフで、 **TimeRemaining for 'Jump_From_Jog'** ノードを **右クリック** して追加します。 +1. **遷移ルール** グラフで、**右クリック** して **TimeRemaining for 'Jump_From_Jog'** ノードを追加します。 ![](AnimBP_Jump3.png) @@ -46,7 +34,7 @@ SkillLevel:Advanced ![](AnimBP_Jump4.png) - これにより、Jog アニメーションから Jump するまでの残り時間が確認でき、 0.1 以下の場合は Jump から Job Blend Space へ遷移させます。他のステートへ移行する前に Jump アニメーションを確実に終了させる便利な方法です。 + これにより、Jog アニメーションから Jump するまでの残り時間が確認でき、 0.1 以下の場合は Jump から Jog Blend Space へ遷移させます。他のステートへ遷移する前に Jump アニメーションを確実に終了させる便利な方法です。 1. ステートマシン グラフへ戻り、 **Walk_BS** と **Jump_From_Jog** 間の **遷移** を作成します。 @@ -62,7 +50,7 @@ SkillLevel:Advanced ![](AnimBP_Jump7.png) -1. ステートマシン グラフで、 **アセットブラウザ** から **Jump_From_Stand** をドラッグします。 +1. ステートマシン グラフで、 **アセットブラウザ** から **Jump_From_Stand** アニメーションをドラッグします。 ![](AnimBP_JumpStand1.png) @@ -76,7 +64,7 @@ SkillLevel:Advanced ![](AnimBP_JumpStand3.png) - プレイヤーが Jump キーを押したか、しゃがんでいないことを、ここで確認します。 + プレイヤーが Jump キーを押すとしゃがんでいないことを、ここで確認します。 1. ステートマシン グラフに戻り、 **Jump_From_Stand** から **Idle_Rifle_Hip** への **遷移ルール** を開きます。 @@ -88,4 +76,4 @@ SkillLevel:Advanced 1. Animation ブループリントを **コンパイル** し **保存** します。 -%Steps% +[NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Jump/Jump_ABP.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Jump/Jump_ABP.KOR.udn index 533ff36ce705..90dc76054d3b 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Jump/Jump_ABP.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Jump/Jump_ABP.KOR.udn @@ -1,28 +1,16 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:8. 애니메이션 블루프린트 - 점프 상태 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement, Gameplay\HowTo\CharacterMovement\Blueprints Description:애니메이션 블루프린트 셋업을 이어, 점프에 대한 조건을 구성해 줍니다. Version: 4.9 +Parent:Gameplay/HowTo/CharacterMovement/Blueprints SkillLevel:Advanced +type:how-to +type:multi-step +order:8 -[VAR:Steps] -[OBJECT:Navigation] - [PARAM:previous] - [예전 단계](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jog "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jog:title%") - [/PARAM] - [PARAM:current] - [/PARAM] - [PARAM:home] - [캐릭터 무브먼트 개요](Gameplay\HowTo\CharacterMovement\Blueprints) - [/PARAM] - [PARAM:next] - [다음 단계](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Prone "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Prone:title%") - [/PARAM] -[/OBJECT] -[/VAR] - -%Steps% +[NAV] 다음으로 **스테이트 머신** 안에서 **Jump** (점프) 상태를 구성하겠습니다. 두 가지 점프 상태를 만들텐데, 하나는 플레이어가 가만히 서있는 상태에서 점프 키를 눌렀을 때, 다른 하나는 플레이어가 움직이는 (조깅, 웅크려 걷기, 걷기) 상태에서 눌렀을 때 입니다. 애니메이션도 정지 상태와 이동 상태 두 가지를 사용하도록 하겠습니다. @@ -88,4 +76,4 @@ SkillLevel:Advanced 1. 애니메이션 블루프린트를 **컴파일** 하고 **저장** 합니다. -%Steps% +[NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Prone/Prone_ABP.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Prone/Prone_ABP.INT.udn index 104d96dc0d14..c72b773340aa 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Prone/Prone_ABP.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Prone/Prone_ABP.INT.udn @@ -3,24 +3,13 @@ Title:9. Animation Blueprint - Prone State Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement, Gameplay\HowTo\CharacterMovement\Blueprints Description:The final state to set up for our character is the Prone State which will complete our character. Version: 4.9 +Parent:Gameplay/HowTo/CharacterMovement/Blueprints SkillLevel:Advanced +type:how-to +type:multi-step +order:9 -[VAR:Steps] -[OBJECT:Navigation] - [PARAM:previous] - [Previous Step](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jump "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jump:title%") - [/PARAM] - [PARAM:current] - [/PARAM] - [PARAM:home] - [Character Movement Overview](Gameplay\HowTo\CharacterMovement\Blueprints) - [/PARAM] - [PARAM:next] - [/PARAM] -[/OBJECT] -[/VAR] - -%Steps% +[NAV] In this final section, we finish our **State Machine** by adding a **Prone** state along with the transition to/from it. @@ -112,66 +101,4 @@ You should now have a fully animated character that can move around your level i There are several other states that can be added to this State Machine (Death, Reload, etc.) or you could swap out the existing motions with your own. In either case, you should now have an understanding of how to set up Character Movement in **Blueprints**, define animation states with an **Animation Blueprint**, and how to blend animations through **Blend Spaces**. -%Steps% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +[NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Prone/Prone_ABP.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Prone/Prone_ABP.JPN.udn index adbf39b679d7..107b7c7d4ec3 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Prone/Prone_ABP.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Prone/Prone_ABP.JPN.udn @@ -1,24 +1,16 @@ -Availability:Public +INTSourceChangelist:3429254 +Availability:Public Title:9.Animation ブループリント - Prone ステート Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement, Gameplay\HowTo\CharacterMovement\Blueprints Description:キャラクターのステート設定の最後は Prone ステートです。これでキャラクターが完成します。 +Version:4.9 +Parent:Gameplay/HowTo/CharacterMovement/Blueprints +SkillLevel:Advanced +type:how-to +type:multi-step +order:9 -[VAR:Steps] -[OBJECT:Navigation] - [PARAM:previous] - [次のステップ](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jump "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jump:title%") - [/PARAM] - [PARAM:current] - [/PARAM] - [PARAM:home] - [キャラクターの移動の概要](Gameplay\HowTo\CharacterMovement\Blueprints) - [/PARAM] - [PARAM:next] - [/PARAM] -[/OBJECT] -[/VAR] - -%Steps% +[NAV] 最後のセクションでは、 **Prone** ステートおよびその移行を追加して **ステートマシン** を完了します。 @@ -26,29 +18,29 @@ Description:キャラクターのステート設定の最後は Prone ステー ![](AnimBP_StandToProne1.png) -1. **Idle_Rifle_Hip** から **Stand_To_Prone** への **遷移** を作成し、 **遷移ルール** をクリックします。 +1. **Idle_Rifle_Hip** から **Stand_To_Prone** への **移行** を作成し、 **移行ルール** をクリックします。 ![](AnimBP_StandToProne2.png) -1. **Idle_Rifle_Hip** から **Stand_To_Prone** への **遷移ルール** を開いて、以下のグラフを再度作成します。 +1. **Idle_Rifle_Hip** から **Stand_To_Prone** への **移行ルール** を開いて、以下のグラフを再度作成します。 ![](AnimBP_StandToProne3.png) -1. ステートマシン グラフで、 **アセットブラウザ** から **Prone_Idle** をドラッグします。 +1. ステートマシン グラフに戻り、 **アセットブラウザ** から **Prone_Idle** アニメーションをドラッグします。 ![](AnimBP_ProneIdle1.png) -1. **Stand_To_Prone** から **Prone_Idle** への **遷移** を作成します。 +1. **Stand_To_Prone** から **Prone_Idle** への **移行** を作成します。 -1. **Prone_To_Stand** アニメーションを **アセットブラウザ** からドラッグして **Prone_Idle** から **Prone_To_Stand** への **遷移** を作成します。 +1. **Prone_To_Stand** アニメーションを **アセットブラウザ** からドラッグして **Prone_Idle** から **Prone_To_Stand** への **移行** を作成します。 -1. **Prone_To_Stand** から **Idle_Rifle_Hip** への **遷移** を作成します。 +1. **Prone_To_Stand** から **Idle_Rifle_Hip** への **移行** を作成します。 -1. **Stand_To_Prone** から **Prone_Idle** への **遷移ルール** をクリックします。 +1. **Stand_To_Prone** から **Prone_Idle** への **移行ルール** をクリックします。 ![](AnimBP_ProneIdle2.png) -1. **遷移ルール** の **[Details (詳細)]** パネルで、 **BlendSetting** の **持続時間** を **0.0** に設定します。 +1. **移行ルール** の **[Details]** パネルで、 **BlendSetting** の **Duration (持続時間)** を **0.0** に設定します。 ![](AnimBP_StandToProne1b.png) @@ -60,7 +52,7 @@ Description:キャラクターのステート設定の最後は Prone ステー Prone がまだ _true_ になっているか、そして Idle Prone ステートになる前に Prone になったアニメーションが終了しているかどうかを確認します。 -1. ステートマシン グラフに戻り、 **Prone_Idle** から **Prone_To_Stand** への **遷移ルール** を開きます。 +1. ステートマシン グラフに戻り、 **Prone_Idle** から **Prone_To_Stand** への **移行ルール** を開きます。 ![](AnimBP_ProneIdle4.png) @@ -70,18 +62,20 @@ Description:キャラクターのステート設定の最後は Prone ステー Prone が _true_ でなくなっている場合、立った姿勢へ戻るシーケンスを開始します。 -1. **Prone_To_Stand** から **Idle_Rifle_Hip** への **遷移ルール** をクリックします。 +1. **Prone_To_Stand** から **Idle_Rifle_Hip** への **移行ルール** をクリックします。 ![](AnimBP_ProneToStand1.png) -1. **遷移ルール** の **[Details (詳細)]** パネルで、 **BlendSetting** の **持続時間** を **0.0** に設定します。 +1. **移行ルール** の **[Details]** パネルで、 **BlendSetting** の **Duration (持続時間)** を **0.0** に設定します。 ![](AnimBP_ProneToStand1b.png) -1. **Prone_To_Stand** から **Idle_Rifle_Hip** への **遷移ルール** を開き、以下のグラフを作成します。 +1. **Prone_To_Stand** から **Idle_Rifle_Hip** への **移行ルール** を開き、以下のグラフを作成します。 ![](AnimBP_ProneToStand2.png) + **==** ノードが false (チェックが外されている) に設定されていること、つまり **Prone** が true ではないようにします。 + 1. ステートマシン グラフ全体は、このような感じになっているはずです (設定によってノードの配置は異なります)。 [REGION:lightbox] @@ -92,24 +86,20 @@ Description:キャラクターのステート設定の最後は Prone ステー 1. Animation ブループリントを **コンパイル** し **保存** します。 -1. **コンテント ブラウザ** に戻り、「 **AnimStarterPack** 」フォルダ、次に **Prone_To_Stand** アニメーションを開きます。 +1. **コンテンツ ブラウザ** に戻り、「 **AnimStarterPack** 」フォルダ、次に **Prone_To_Stand** アニメーションを開きます。 1. **[Anim Asset Details]** ウィンドウで、 **[アニメーション]** セクションの **Rate Scale** 値を **1.4** に設定します。 ![](ProneToStand_Rate.png) - これにより、アニメーションの再生レートが若干速くなり、 Prone から Standing への遷移がスムーズに見えます。 + これにより、アニメーションの再生レートが若干速くなり、 Prone から Standing への移行がスムーズに見えます。 -1. **コンテンツブラウザ** とメイン ツールバーの **[Save (保存)]** ボタンをクリックして、セットとレベルを保存します。 +1. **コンテンツブラウザ** とメイン ツールバーの **[保存]** ボタンをクリックして、アセットとレベルを保存します。 1. **[Play (プレイ)]** ボタンをクリックして、エディタで再生します。 -完全にアニメートされ、レベル内で様々な動き方をするキャラクターが出来上がりました。歩く、しゃがんで歩く、小走り、 (静止姿勢あるいは移動姿勢からの) ジャンプ、Standing ステートあるいは Jogging ステートから Prone (前かがみ)、といった動きが可能です。 +完全にアニメートされ、レベル内で様々な動き方をするキャラクターが出来上がりました。歩く、しゃがんで歩く、小走り、 (静止姿勢あるいは移動姿勢からの) ジャンプ、Standing ステートあるいは Jogging ステートからProne (前かがみ)、といった動きが可能です。 このステートマシンにはまだ他のステート (デス (機能停止)、再ロードなど) の追加が可能ですし、既存の動きを独自のものにスワップアウトすることができます。いずれにしても、 **ブループリント** でのキャラクターの移動の設定方法、 **Animation ブループリント** を使ったアニメーション ステートの定義方法、**Blend Spaces** でのアニメーションのブレンド方法を理解できていることでしょう。 -%Steps% - - - - +[NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Prone/Prone_ABP.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Prone/Prone_ABP.KOR.udn index 4f36ecdd20ea..69784da4b6be 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Prone/Prone_ABP.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Prone/Prone_ABP.KOR.udn @@ -1,27 +1,16 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:9. 애니메이션 블루프린트 - 엎드리기 상태 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement, Gameplay\HowTo\CharacterMovement\Blueprints Description:캐릭터에 Prone, 엎드리기 상태를 구성하여 마무리합니다. Version: 4.9 +Parent:Gameplay/HowTo/CharacterMovement/Blueprints SkillLevel:Advanced +type:how-to +type:multi-step +order:9 -[VAR:Steps] -[OBJECT:Navigation] - [PARAM:previous] - [예전 단계](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jump "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jump:title%") - [/PARAM] - [PARAM:current] - [/PARAM] - [PARAM:home] - [캐릭터 무브먼트 개요](Gameplay\HowTo\CharacterMovement\Blueprints) - [/PARAM] - [PARAM:next] - [/PARAM] -[/OBJECT] -[/VAR] - -%Steps% +[NAV] 이번 최종회에서는 **Prone** 엎드리기 스테이트와 거기서 나가고/들어오는 트랜지션을 추가하는 것으로 **스테이트 머신** 을 마무리하겠습니다. @@ -113,66 +102,4 @@ SkillLevel:Advanced 이 스테이트 머신에 여러가지 (사망, 재장전 등) 상태를 추가할 수도 있고, 기존 모션을 자체 제작한 것으로 바꿀 수도 있습니다. 어느 경우든 이제 **블루프린트** 로 캐릭터 무브먼트를 구성하는 법, **애니메이션 블루프린트** 로 애니메이션 스테이트 정의하는 법, **블렌드 스페이스** 를 통해 애니메이션을 블렌딩하는 법이 이해가 가실 것이라 믿습니다. -%Steps% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +[NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Walk/Walk_ABP.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Walk/Walk_ABP.INT.udn index 48588e1af6f5..295c355ab931 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Walk/Walk_ABP.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Walk/Walk_ABP.INT.udn @@ -3,25 +3,13 @@ Title:5. Animation Blueprint - Idle and Walk States Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement, Gameplay\HowTo\CharacterMovement\Blueprints Description:Here in this step, we'll create the logic for Idle and Walking states for our character in our Animation Blueprint. Version: 4.9 +Parent:Gameplay/HowTo/CharacterMovement/Blueprints SkillLevel:Advanced +type:how-to +type:multi-step +order:5 -[VAR:Steps] -[OBJECT:Navigation] - [PARAM:previous] - [Previous Step](Gameplay\HowTo\CharacterMovement\Blueprints\BlendSpace "%Gameplay\HowTo\CharacterMovement\Blueprints\BlendSpace:title%") - [/PARAM] - [PARAM:current] - [/PARAM] - [PARAM:home] - [Character Movement Overview](Gameplay\HowTo\CharacterMovement\Blueprints) - [/PARAM] - [PARAM:next] - [Next Step](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Crouch "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Crouch:title%") - [/PARAM] -[/OBJECT] -[/VAR] - -%Steps% +[NAV] In this section, we will set up the **Animation Blueprint** that will determine what animations to play based on the actions that are taken in game by the player. We will then set up a **State Machine** and create an **Idle** and **Walk** state and set up the transition between each state. @@ -108,4 +96,4 @@ The steps below will show you how to set up the Animation Blueprint: 1. **Compile** and **Save** the Animation Blueprint. -%Steps% +[NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Walk/Walk_ABP.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Walk/Walk_ABP.JPN.udn index 70b044ae927d..eae755c0863a 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Walk/Walk_ABP.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Walk/Walk_ABP.JPN.udn @@ -1,28 +1,16 @@ -INTSourceChangelist:2740691 +INTSourceChangelist:3429254 Availability:Public Title:5.Animation ブループリント - Idle ステートと Walk ステート Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement, Gameplay\HowTo\CharacterMovement\Blueprints Description:このステップでは、Animation ブループリントでキャラクターの Idle ステートおよび Walking ステートのロジックを作成します。 Version:4.9 +Parent:Gameplay/HowTo/CharacterMovement/Blueprints SkillLevel:Advanced +type:how-to +type:multi-step +order:5 -[VAR:Steps] -[OBJECT:Navigation] - [PARAM:previous] - [前のステップ](Gameplay\HowTo\CharacterMovement\Blueprints\BlendSpace "%Gameplay\HowTo\CharacterMovement\Blueprints\BlendSpace:title%") - [/PARAM] - [PARAM:current] - [/PARAM] - [PARAM:home] - [キャラクターの移動の概要](Gameplay\HowTo\CharacterMovement\Blueprints) - [/PARAM] - [PARAM:next] - [次のステップ](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Crouch "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Crouch:title%") - [/PARAM] -[/OBJECT] -[/VAR] - -%Steps% +[NAV] このセクションでは、プレイヤーがゲーム内で取るアクションに合わせて、どのアニメーションを再生するかを判断する **Animation ブループリント** を設定します。その後で **ステートマシン** を設定し、 **Idle** と **Walk** ステートを作成し、両ステート間の遷移を設定します。 @@ -63,7 +51,6 @@ Animation ブループリントは以下の方法で設定します。 1. State Machine を **ダブルクリック** して開きます。 1. **Asset Browser** ウィンドウで、 **Idle** を探して **Idle_Rifle_Hip** アセットをグラフにドラッグします。 - ![](AnimBP_AnimGraph4.png) 1. **Entry** ノードを **Idle_Rifle_Hip** ノードに接続して、 **[Compile]** をクリックします。 @@ -109,4 +96,4 @@ Animation ブループリントは以下の方法で設定します。 1. Animation ブループリントを **コンパイル** し **保存** します。 -%Steps% +[NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Walk/Walk_ABP.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Walk/Walk_ABP.KOR.udn index 1b0910ada458..10de57bb7d73 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Walk/Walk_ABP.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/AnimBlueprint_Walk/Walk_ABP.KOR.udn @@ -1,28 +1,16 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:5. 애니메이션 블루프린트 - 대기 및 걷기 상태 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement, Gameplay\HowTo\CharacterMovement\Blueprints Description:이번 단계에서는 애니메이션 블루프린트에 캐릭터의 빈둥, 걷기 상태에 대한 로직을 만들어 주겠습니다. Version: 4.9 +Parent:Gameplay/HowTo/CharacterMovement/Blueprints SkillLevel:Advanced +type:how-to +type:multi-step +order:5 -[VAR:Steps] -[OBJECT:Navigation] - [PARAM:previous] - [예전 단계](Gameplay\HowTo\CharacterMovement\Blueprints\BlendSpace "%Gameplay\HowTo\CharacterMovement\Blueprints\BlendSpace:title%") - [/PARAM] - [PARAM:current] - [/PARAM] - [PARAM:home] - [캐릭터 무브먼트 개요](Gameplay\HowTo\CharacterMovement\Blueprints) - [/PARAM] - [PARAM:next] - [다음 단계](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Crouch "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Crouch:title%") - [/PARAM] -[/OBJECT] -[/VAR] - -%Steps% +[NAV] 여기서는 게임에서 플레이어가 취하는 동작에 따라 재생할 애니메이션을 결정하는 **애니메이션 블루프린트** 를 구성해 주겠습니다. 그런 다음 **스테이트 머신** 구성 후 **Idle** (대기) 및 **Walk** (걷기) 상태를 만든 다음 각 상태 트랜지션(전환) 구성을 해 주겠습니다. @@ -109,4 +97,4 @@ SkillLevel:Advanced 1. 애니메이션 블루프린트를 **컴파일** 및 **저장** 합니다. -%Steps% +[NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/BlendSpace/BlendSpaces.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/BlendSpace/BlendSpaces.INT.udn index 7e4ba785a9e3..6861ffcf4145 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/BlendSpace/BlendSpaces.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/BlendSpace/BlendSpaces.INT.udn @@ -3,25 +3,13 @@ Title:4. Creating Blend Spaces Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement, Gameplay\HowTo\CharacterMovement\Blueprints Description:In this step we are going to set up Blend Spaces for our movement states so we can blend between animations when moving in different directions. Version: 4.9 +Parent:Gameplay/HowTo/CharacterMovement/Blueprints SkillLevel: Advanced +type:how-to +type:multi-step +order:4 -[VAR:Steps] -[OBJECT:Navigation] - [PARAM:previous] - [Previous Step](Gameplay\HowTo\CharacterMovement\Blueprints\Setup_2 "%Gameplay\HowTo\CharacterMovement\Blueprints\Setup_2:title%") - [/PARAM] - [PARAM:current] - [/PARAM] - [PARAM:home] - [Character Movement Overview](Gameplay\HowTo\CharacterMovement\Blueprints) - [/PARAM] - [PARAM:next] - [Next Step](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Walk "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Walk:title%") - [/PARAM] -[/OBJECT] -[/VAR] - -%Steps% +[NAV] The next thing we will do to create movement for our character is to create **Blend Spaces** for each of our movement states (Walking, Jogging, and Crouch Walking). Blend Spaces are special assets that allow for blending of animations based on the values of two inputs. In our case, we will blend between forwards/backwards and left/right movement based on the character's movement Speed or Direction. @@ -120,5 +108,4 @@ The steps below will show you how to set up the movement Blend Spaces: 1. **Save** then close the **Crouch_BS** Blend Space window. -%Steps% - +[NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/BlendSpace/BlendSpaces.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/BlendSpace/BlendSpaces.JPN.udn index 133a5ff18167..ec1882855672 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/BlendSpace/BlendSpaces.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/BlendSpace/BlendSpaces.JPN.udn @@ -1,30 +1,18 @@ -INTSourceChangelist:2740691 +INTSourceChangelist:3429254 Availability:Public Title:4.ブレンド スペースの作成 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement, Gameplay\HowTo\CharacterMovement\Blueprints Description:このステップでは、違う方向に移動する時にアニメーション間でブレンドができるように、移動ステート用の Blend Spaces を設定します。 Version:4.9 +Parent:Gameplay/HowTo/CharacterMovement/Blueprints SkillLevel:Advanced +type:how-to +type:multi-step +order:4 -[VAR:Steps] -[OBJECT:Navigation] - [PARAM:previous] - [前のステップ](Gameplay\HowTo\CharacterMovement\Blueprints\Setup_2 "%Gameplay\HowTo\CharacterMovement\Blueprints\Setup_2:title%") - [/PARAM] - [PARAM:current] - [/PARAM] - [PARAM:home] - [キャラクターの移動の概要](Gameplay\HowTo\CharacterMovement\Blueprints) - [/PARAM] - [PARAM:next] - [次のステップ](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Walk "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Walk:title%") - [/PARAM] -[/OBJECT] -[/VAR] +[NAV] -%Steps% - -キャラクターに移動を作成するために、次は各移動ステート (Walking、Jogging、Crouch Walking) 用の **Blend Space** を作成します。ブレンド スペースは 2 つの入力値に基づいたアニメーションのブレンドを可能にする特殊なアセットです。ここでは、キャラクターの移動の速さと方向に合わせて、前後と左右をブレンドします。 +キャラクターを移動させるために、次は各移動ステート (Walking、Jogging、Crouch Walking) 用の **Blend Space** を作成します。ブレンド スペースは 2 つの入力値に基づいたアニメーションのブレンドを可能にする特殊なアセットです。ここでは、キャラクターの移動の速さと方向に合わせて、前後と左右をブレンドします。 [REGION:note] Blend Space に関する詳細は、 [](Engine/Animation/Blendspaces) のページを参照してください。 @@ -38,7 +26,7 @@ Blend Space に関する詳細は、 [](Engine/Animation/Blendspaces) のペー 1. **[Pick Skeleton]** ウィンドウで、スケルトン (**UE4_Mannequin_Skeleton**) を選び、アセットに「 **Walk_BS** 」という名前を付けます。 -1. **Walk_BS** ブレンドスペースを開き、 **[Parameters]** で、 **X Axis Label** を **Direction** に **Y Axis Label** を **Speed** に設定します。 +1. **Walk_BS** ブレンドスペースを開き、 **[Parameters]** の、 **X Axis Label** を **Direction** に、**Y Axis Label** を **Speed** に設定します。 1. **X Axis Range** を **-180** から **180** に、 **X Axis Divisions** を **4** に設定します。 @@ -100,7 +88,7 @@ Blend Space に関する詳細は、 [](Engine/Animation/Blendspaces) のペー 1. **[Asset] ウィンドウ** で、 **Jog** アニメーションを探します。 -1. Jog アニメーションをグリッド上の Walk アニメーション上にドラッグして、グリッド上で歩くアニメーションを走るアニメーションに変えます。 +1. Jog アニメーションをグリッド上の Walk ポイントにドラッグして、グリッド上で歩くアニメーションを走るアニメーションに変えます。 ![](Blendspace_10.png)(w:640) @@ -121,5 +109,4 @@ Blend Space に関する詳細は、 [](Engine/Animation/Blendspaces) のペー 1. **保存** してから [**Crouch_BS** Blend Space] ウィンドウを閉じます。 -%Steps% - +[NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/BlendSpace/BlendSpaces.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/BlendSpace/BlendSpaces.KOR.udn index ef3a5b0c8eb8..a465eb1129a3 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/BlendSpace/BlendSpaces.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/BlendSpace/BlendSpaces.KOR.udn @@ -1,28 +1,16 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:4. 블렌드 스페이스 만들기 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement, Gameplay\HowTo\CharacterMovement\Blueprints Description:이번 단계에서는 다양한 방향 이동시의 애니메이션 블렌딩이 가능하도록 이동 상태에 대한 블렌드 스페이스 구성을 해 보도록 하겠습니다. Version: 4.9 +Parent:Gameplay/HowTo/CharacterMovement/Blueprints SkillLevel: Advanced +type:how-to +type:multi-step +order:4 -[VAR:Steps] -[OBJECT:Navigation] - [PARAM:previous] - [예전 단계](Gameplay\HowTo\CharacterMovement\Blueprints\Setup_2 "%Gameplay\HowTo\CharacterMovement\Blueprints\Setup_2:title%") - [/PARAM] - [PARAM:current] - [/PARAM] - [PARAM:home] - [캐릭터 무브먼트 개요](Gameplay\HowTo\CharacterMovement\Blueprints) - [/PARAM] - [PARAM:next] - [다음 단계](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Walk "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Walk:title%") - [/PARAM] -[/OBJECT] -[/VAR] - -%Steps% +[NAV] 다음 우리 캐릭터의 동작을 만드는 데 해 줄 작업은, 각각의 동작 (걷기, 조깅, 웅크려 걷기) 상태에 대한 **블렌드 스페이스** 를 만드는 것입니다. 블렌드 스페이스란 두 입력값에 따라 애니메이션을 블렌딩할 수 있도록 해 주는 특수 애셋으로, 여기서는 캐릭터의 이동 속도와 방향에 따라 전방/후방 및 좌/우 동작을 블렌딩하도록 하겠습니다. @@ -121,5 +109,4 @@ SkillLevel: Advanced 1. **저장** 후 **Crouch_BS** 블렌드 스페이스 창을 닫습니다. -%Steps% - +[NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Input/Input.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Input/Input.INT.udn index 4e00257bbb06..ea2de1af0e0c 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Input/Input.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Input/Input.INT.udn @@ -3,25 +3,13 @@ Title:2. Input and the Game Mode Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement, Gameplay\HowTo\CharacterMovement\Blueprints Description:In this step we will set up the input to control our character as well as set our default pawn which is the playable character. Version: 4.9 +Parent:Gameplay/HowTo/CharacterMovement/Blueprints SkillLevel:Advanced +type:how-to +type:multi-step +order:2 -[VAR:Steps] -[OBJECT:Navigation] - [PARAM:previous] - [Previous Step](Gameplay\HowTo\CharacterMovement\Blueprints\Setup_1 "%Gameplay\HowTo\CharacterMovement\Blueprints\Setup_1:title%") - [/PARAM] - [PARAM:current] - [/PARAM] - [PARAM:home] - [Character Movement Overview](Gameplay\HowTo\CharacterMovement\Blueprints) - [/PARAM] - [PARAM:next] - [Next Step](Gameplay\HowTo\CharacterMovement\Blueprints\Setup_2 "%Gameplay\HowTo\CharacterMovement\Blueprints\Setup_2:title%") - [/PARAM] -[/OBJECT] -[/VAR] - -%Steps% +[NAV] Here we will set up the **Input** (Game Controls) to control the character and create a **Game Mode** which will use our character. @@ -71,5 +59,4 @@ Here we will set up the **Input** (Game Controls) to control the character and c 1. After setting both the Input and Game Mode settings, close the Project Settings Window. - -%Steps% +[NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Input/Input.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Input/Input.JPN.udn index 64eb4d4d68d7..82dae65c507f 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Input/Input.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Input/Input.JPN.udn @@ -1,30 +1,18 @@ -INTSourceChangelist:2740691 +INTSourceChangelist:3429254 Availability:Public Title:2.入力とゲームモード Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement, Gameplay\HowTo\CharacterMovement\Blueprints -Description:このステップでは、キャラクターの制御だけでなくプレイ可能なキャラクターとなるデフォルトのポーンの設定を行うための入力を設定します。 +Description:このステップでは、キャラクターを制御する入力とプレイ可能なキャラクターとなるデフォルトのポーンを設定します。 Version:4.9 +Parent:Gameplay/HowTo/CharacterMovement/Blueprints SkillLevel:Advanced +type:how-to +type:multi-step +order:2 -[VAR:Steps] -[OBJECT:Navigation] - [PARAM:previous] - [前のステップ](Gameplay\HowTo\CharacterMovement\Blueprints\Setup_1 "%Gameplay\HowTo\CharacterMovement\Blueprints\Setup_1:title%") - [/PARAM] - [PARAM:current] - [/PARAM] - [PARAM:home] - [キャラクターの移動の概要](Gameplay\HowTo\CharacterMovement\Blueprints) - [/PARAM] - [PARAM:next] - [次のステップ](Gameplay\HowTo\CharacterMovement\Blueprints\Setup_2 "%Gameplay\HowTo\CharacterMovement\Blueprints\Setup_2:title%") - [/PARAM] -[/OBJECT] -[/VAR] +[NAV] -%Steps% - -このページでは、キャラクターを制御し、キャラクターに使用する **ゲームモード** を作成するための **入力** (ゲーム制御) の設定を行います。 +このページでは、キャラクターを制御する **入力** (ゲーム制御) を設定し、キャラクターを使用する **ゲームモード** を作成します。 1. **コンテンツブラウザ** 内を **右クリック** して **Game Mode** クラスの **Blueprint クラス** を作成し、「 **MyGame** 」と名前を付けます。 @@ -32,13 +20,13 @@ SkillLevel:Advanced ![](SelectClassDefaults.png) -1. **[Details]** パネルの **[Classes]** で、 **Default Pawn Class** を **MyCharacter** ブループリントを使用する設定にします。 +1. **[Details]** パネルの **[Classes]** で、 **Default Pawn Class** が **MyCharacter** ブループリントを使用するように設定します。 ![](GameMode_1.png) 1. **コンパイル** し **保存** してから、ブループリントを閉じます。 -1. メインのエディタ ウィンドウの **メニュー バー** の **[Edit]** をクリックし **[Project Settings (プロジェクト設定)]** を選びます。 +1. メインのエディタ ウィンドウの **メニュー バー** の **[Edit]** をクリックし **[Project Settings]** を選びます。 1. プロジェクト設定で **[Engine]** セクションの **[Input]** をクリックします。 @@ -48,7 +36,7 @@ SkillLevel:Advanced ![](Input_1.png)(w:480) - 空の Bindings は上のようになっているはずです。 + 空の Bindings はこのようになっているはずです。 1. **Bindings** を以下のように設定します (**Scale** を **A** 、 **S** そして **Mouse Y** を **-1.0** に設定するようにしてください)。 @@ -62,15 +50,14 @@ SkillLevel:Advanced 1. Project Settings の **[Project]** セクションの **[Maps & Modes]** オプションをクリックします。 -1. Maps & Modes の **Default Modes** で、 **Default GameMode** に **MyGame** ゲームモードを設定します。 +1. Maps & Modes の **Default Modes** で、 **Default GameMode** が **MyGame** ゲームモードを使用するように設定します。 ![](GameMode_2.png) [REGION:note] - ゲームモード に関する詳細は、 [](Gameplay\HowTo\SettingUpAGameMode) を参照してください。 + ゲームモードに関する詳細は、 [](Gameplay\HowTo\SettingUpAGameMode) を参照してください。 [/REGION] -1. 入力とゲームモードの設定が完了したら、[Project Settings] ウィンドウを閉じます。 +1. 入力とゲームモードの設定が完了したら、[Project Settings] ウィンドウを終了します。 - -%Steps% +[NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Input/Input.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Input/Input.KOR.udn index 61be4cd3b54a..193a0d585051 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Input/Input.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Input/Input.KOR.udn @@ -1,28 +1,16 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:2. 입력 및 게임 모드 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement, Gameplay\HowTo\CharacterMovement\Blueprints Description:여기서는 우리 캐릭터 제어를 위한 입력 구성 및 조종할 수 있는 캐릭터인 디폴트 폰을 설정합니다. Version: 4.9 +Parent:Gameplay/HowTo/CharacterMovement/Blueprints SkillLevel:Advanced +type:how-to +type:multi-step +order:2 -[VAR:Steps] -[OBJECT:Navigation] - [PARAM:previous] - [예전 단계](Gameplay\HowTo\CharacterMovement\Blueprints\Setup_1 "%Gameplay\HowTo\CharacterMovement\Blueprints\Setup_1:title%") - [/PARAM] - [PARAM:current] - [/PARAM] - [PARAM:home] - [캐릭터 무브먼트 개요](Gameplay\HowTo\CharacterMovement\Blueprints) - [/PARAM] - [PARAM:next] - [다음 단계](Gameplay\HowTo\CharacterMovement\Blueprints\Setup_2 "%Gameplay\HowTo\CharacterMovement\Blueprints\Setup_2:title%") - [/PARAM] -[/OBJECT] -[/VAR] - -%Steps% +[NAV] 여기서는 **입력** (게임 콘트롤)을 구성하여 캐릭터를 제어하고 우리 캐릭터를 사용하는 **게임 모드** 를 만들도록 하겠습니다. @@ -72,5 +60,4 @@ SkillLevel:Advanced 1. 입력과 게임 모드 세팅 설정을 마친 이후에는, 프로젝트 세팅 창을 닫습니다. - -%Steps% +[NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Overview.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Overview.INT.udn index 922f79c87fba..59d3b7ae3fb9 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Overview.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Overview.INT.udn @@ -4,6 +4,8 @@ Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement Description:A How To Guide for Setting Up Character Movement in Blueprints. Version: 4.9 SkillLevel: Advanced +type:how-to +type:landing This "How To" series covers all the steps needed to create a fully playable and animated character through **Blueprints**. By the end of this How To series, you will have a character that can Walk, Run, Crouch and Crouch Walk, Go Prone, Jump from a stationary standing position, or Jump while moving. @@ -28,25 +30,10 @@ For this series, we are using the **Animation Starter Pack**, which is available To get started, follow the steps below. -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/build_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - Steps - [/PARAM] - [PARAM:description] - [/PARAM] - [PARAM:links] - * [](Gameplay\HowTo\CharacterMovement\Blueprints\Setup_1 "%Gameplay\HowTo\CharacterMovement\Blueprints\Setup_1:description%") - * [](Gameplay\HowTo\CharacterMovement\Blueprints\Input "%Gameplay\HowTo\CharacterMovement\Blueprints\Input:description%") - * [](Gameplay\HowTo\CharacterMovement\Blueprints\Setup_2 "%Gameplay\HowTo\CharacterMovement\Blueprints\Setup_2:description%") - * [](Gameplay\HowTo\CharacterMovement\Blueprints\BlendSpace "%Gameplay\HowTo\CharacterMovement\Blueprints\BlendSpace:description%") - * [](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Walk "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Walk:description%") - * [](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Crouch "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Crouch:description%") - * [](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jog "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jog:description%") - * [](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jump "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jump:description%") - * [](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Prone "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Prone\:description%") - [/PARAM] -[/OBJECT] +## Steps +[DIR(output:"checkpoint" parent:"Gameplay/HowTo/CharacterMovement/Blueprints")] + +[REGION:call_to_action] +[Click to Start](Gameplay/HowTo/CharacterMovement/Blueprints/Setup_1) +[/REGION] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Overview.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Overview.JPN.udn index 3f768e632d04..b4c3af67f37d 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Overview.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Overview.JPN.udn @@ -1,10 +1,12 @@ -INTSourceChangelist:2740691 +INTSourceChangelist:3429254 Availability:Public -Title:ブループリントにおけるキャラクター移動の設定方法 +Title:ブループリントでキャラクターの移動を設定する Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement Description:ブループリントにおいてキャラクター移動を設定するためのガイド Version:4.9 SkillLevel:Advanced +type:how-to +type:landing この「How To」シリーズでは、 **ブループリント** を使って完全にプレイ可能かつアニメートされたキャラクターを作成するために必要なすべてのステップを紹介していきます。シリーズの最後には、歩く、走る、しゃがむ、しゃがんで歩く、前かがみになる、静止した立ち姿勢または動作中からジャンプするといった動きが可能なキャラクターが出来上がります。 @@ -29,25 +31,10 @@ f5DQQWQ8GEY では、以下のステップから開始していきましょう。 -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/build_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - ステップ - [/PARAM] - [PARAM:description] - [/PARAM] - [PARAM:links] - * [](Gameplay\HowTo\CharacterMovement\Blueprints\Setup_1 "%Gameplay\HowTo\CharacterMovement\Blueprints\Setup_1:description%") - * [](Gameplay\HowTo\CharacterMovement\Blueprints\Input "%Gameplay\HowTo\CharacterMovement\Blueprints\Input:description%") - * [](Gameplay\HowTo\CharacterMovement\Blueprints\Setup_2 "%Gameplay\HowTo\CharacterMovement\Blueprints\Setup_2:description%") - * [](Gameplay\HowTo\CharacterMovement\Blueprints\BlendSpace "%Gameplay\HowTo\CharacterMovement\Blueprints\BlendSpace:description%") - * [](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Walk "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Walk:description%") - * [](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Crouch "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Crouch:description%") - * [](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jog "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jog:description%") - * [](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jump "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jump:description%") - * [](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Prone "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Prone\:description%") - [/PARAM] -[/OBJECT] +## ステップ +[DIR(output:"checkpoint" parent:"Gameplay/HowTo/CharacterMovement/Blueprints")] + +[REGION:call_to_action] +[クリックして開始](Gameplay/HowTo/CharacterMovement/Blueprints/Setup_1) +[/REGION] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Overview.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Overview.KOR.udn index c2bc424cd141..135ba3bbcd88 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Overview.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Overview.KOR.udn @@ -1,10 +1,12 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:블루프린트로 캐릭터 무브먼트 셋업 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement Description:블루프린트로 캐릭터 무브먼트를 셋업하는 비법 안내입니다. Version: 4.9 SkillLevel: Advanced +type:how-to +type:landing 여기서는 **블루프린트** 를 통해 제대로 플레이가능한 캐릭터를 만드는 데 필요한 방법을 알아보겠습니다. 이 비법 시리즈 마지막에서는 걷기, 달리기, 웅크리기, 웅크려 걷기, 엎드리기, 정지 자세에서 점프, 이동중 점프가 가능한 캐릭터가 생길 것입니다. @@ -27,27 +29,12 @@ f5DQQWQ8GEY ![](AnimationStartePack1.jpg) -시작을 위한 단계는 다음과 같습니다. +다음과 같이 시작합니다. -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/build_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - 단계 - [/PARAM] - [PARAM:description] - [/PARAM] - [PARAM:links] - * [](Gameplay\HowTo\CharacterMovement\Blueprints\Setup_1 "%Gameplay\HowTo\CharacterMovement\Blueprints\Setup_1:description%") - * [](Gameplay\HowTo\CharacterMovement\Blueprints\Input "%Gameplay\HowTo\CharacterMovement\Blueprints\Input:description%") - * [](Gameplay\HowTo\CharacterMovement\Blueprints\Setup_2 "%Gameplay\HowTo\CharacterMovement\Blueprints\Setup_2:description%") - * [](Gameplay\HowTo\CharacterMovement\Blueprints\BlendSpace "%Gameplay\HowTo\CharacterMovement\Blueprints\BlendSpace:description%") - * [](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Walk "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Walk:description%") - * [](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Crouch "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Crouch:description%") - * [](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jog "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jog:description%") - * [](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jump "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Jump:description%") - * [](Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Prone "%Gameplay\HowTo\CharacterMovement\Blueprints\AnimBlueprint_Prone\:description%") - [/PARAM] -[/OBJECT] +## 단계 +[DIR(output:"checkpoint" parent:"Gameplay/HowTo/CharacterMovement/Blueprints")] + +[REGION:call_to_action] +[클릭하면 시작합니다.](Gameplay/HowTo/CharacterMovement/Blueprints/Setup_1) +[/REGION] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Setup_1/Setup_1.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Setup_1/Setup_1.INT.udn index d54f45c62985..7af911903275 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Setup_1/Setup_1.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Setup_1/Setup_1.INT.udn @@ -4,23 +4,12 @@ Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement, Gameplay\HowTo\Chara Description:Here we will set up our character and create some assets that we will need later in this guide. Version: 4.9 SkillLevel: Advanced +Parent:Gameplay/HowTo/CharacterMovement/Blueprints +type:how-to +type:multi-step +order:1 -[VAR:Steps] -[OBJECT:Navigation] - [PARAM:previous] - [/PARAM] - [PARAM:current] - [/PARAM] - [PARAM:home] - [Character Movement Overview](Gameplay\HowTo\CharacterMovement\Blueprints\) - [/PARAM] - [PARAM:next] - [Next Step](Gameplay\HowTo\CharacterMovement\Blueprints\Input "%Gameplay\HowTo\CharacterMovement\Blueprints\Input\:title%") - [/PARAM] -[/OBJECT] -[/VAR] - -%Steps% +[NAV] To get started, we will create some assets that will be used by our character. First we will create an **Animation Blueprint** (we will populate it later in this series) which will be used to drive the animations of the character, then we will create our **Character Blueprint** which will hold the logic behind our character's actions and how it responds to input. @@ -96,5 +85,4 @@ For this project, we are using the **Blank** Project Template in order to start 1. **Compile** and **Save** then close the Blueprint. -%Steps% - +[NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Setup_1/Setup_1.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Setup_1/Setup_1.JPN.udn index de20a302cccc..7e754004243b 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Setup_1/Setup_1.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Setup_1/Setup_1.JPN.udn @@ -1,29 +1,18 @@ -INTSourceChangelist:2740691 +INTSourceChangelist:3429254 Availability:Public -Title:1.キャラクター設定 +Title:1.キャラクターのセットアップ Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement, Gameplay\HowTo\CharacterMovement\Blueprints -Description:キャラクターを設定し、このガイドで後に必要となるアセットを幾つか作成します。 +Description:キャラクターに設定を行い、このガイドで後に必要となるアセットを幾つか作成します。 Version:4.9 SkillLevel:Advanced +Parent:Gameplay/HowTo/CharacterMovement/Blueprints +type:how-to +type:multi-step +order:1 -[VAR:Steps] -[OBJECT:Navigation] - [PARAM:previous] - [/PARAM] - [PARAM:current] - [/PARAM] - [PARAM:home] - [キャラクター移動の概要](Gameplay\HowTo\CharacterMovement\Blueprints\) - [/PARAM] - [PARAM:next] - [次のステップ](Gameplay\HowTo\CharacterMovement\Blueprints\Input "%Gameplay\HowTo\CharacterMovement\Blueprints\Input\:title%") - [/PARAM] -[/OBJECT] -[/VAR] +[NAV] -%Steps% - -手始めに、キャラクターで使うアセットを幾つか作成します。まず最初にキャラクターのアニメーションを操作するための **Animation ブループリント** (このシリーズで後ほど実装していきます) を作成し、次にキャラクターのアクションや入力への反応方法のロジックを扱う **Character ブループリント** を作成します。 +手始めに、キャラクターで使うアセットを幾つか作成します。まず最初にキャラクターのアニメーションを操作するための **Animation ブループリント** (このシリーズで後ほど実装していきます) を作成し、次にキャラクターのアクションや入力への反応方法のロジックを司る **Character ブループリント** を作成します。 [REGION:note] このプロジェクトでは **Animation Starter Pack** を使用します。 **マーケットプレイス** から無料でご利用いただけます。Animation Starter Pack をダウンロードしたら、ランチャーの **[Add to project]** ボタンで既存プロジェクト (できれば新規のブランク プロジェクト) に追加します。これで、アセットを追加するプロジェクトを指定することができます。 @@ -47,7 +36,7 @@ SkillLevel:Advanced 1. 「 **MyCharacter** 」などの名前を付けて開きます。 -1. [Component] ウィンドウで、 **Mesh** コンポーネントをクリックします。 +1. **[Component]** ウィンドウで、 **Mesh** コンポーネントをクリックします。 ![](ClickMesh.png) @@ -87,15 +76,14 @@ SkillLevel:Advanced ![](Characters_7.png) - 好きな値に設定することができますが、適切な値を選んでください。 + お好きな値に設定することができますが、適切な値を選んでください。 1. **[MyBlueprint]** ウィンドウで **[Create Variable]** ボタンをクリックし、 **JogPressed** という **Bool** を作成します。 -1. 次の 4 つの **Bool** 変数を作成します。**CrouchPressed** 、 **PronePressed** 、 **JumpPressed** 、 **DisableMovement**。 +1. 次の 4 つの **Bool** 変数を作成します。**CrouchPressed** 、 **PronePressed** 、 **JumpPressed** 、 **DisableMovement** ![](Characters_8.png) 1. **コンパイル** し **保存** してから、ブループリントを閉じます。 -%Steps% - +[NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Setup_1/Setup_1.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Setup_1/Setup_1.KOR.udn index 76ce37bafd2f..8dffe71eecc5 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Setup_1/Setup_1.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Setup_1/Setup_1.KOR.udn @@ -1,27 +1,16 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:1. 캐릭터 셋업 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement, Gameplay\HowTo\CharacterMovement\Blueprints Description:여기서는 캐릭터를 셋업한 다음 가이드 후반에 필요해질 애셋을 만들어 주겠습니다. Version: 4.9 SkillLevel: Advanced +Parent:Gameplay/HowTo/CharacterMovement/Blueprints +type:how-to +type:multi-step +order:1 -[VAR:Steps] -[OBJECT:Navigation] - [PARAM:previous] - [/PARAM] - [PARAM:current] - [/PARAM] - [PARAM:home] - [캐릭터 무브먼트 개요](Gameplay\HowTo\CharacterMovement\Blueprints\) - [/PARAM] - [PARAM:next] - [다음 단계](Gameplay\HowTo\CharacterMovement\Blueprints\Input "%Gameplay\HowTo\CharacterMovement\Blueprints\Input\:title%") - [/PARAM] -[/OBJECT] -[/VAR] - -%Steps% +[NAV] 먼저 캐릭터에 사용할 애셋을 만들겠습니다. 우선 캐릭터의 애니메이션 구동에 사용할 **애니메이션 블루프린트** 를 만든 다음 (나중 시리즈에서 채우겠습니다), 캐릭터의 동작 배후 로직과 입력에 대한 캐릭터의 반응이 저장되는 **캐릭터 블루프린트** 를 만들겠습니다. @@ -97,5 +86,4 @@ SkillLevel: Advanced 1. **컴파일**, **저장** 후 블루프린트를 닫습니다. -%Steps% - +[NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Setup_2/Setup_2.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Setup_2/Setup_2.INT.udn index c7c1d810d7c8..00afd65bdb17 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Setup_2/Setup_2.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Setup_2/Setup_2.INT.udn @@ -3,25 +3,13 @@ Title:3. Finishing Character Setup Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement, Gameplay\HowTo\CharacterMovement\Blueprints Description:Here we will implement the script in our Character Blueprint to respond to our Input Mappings so the character moves. Version: 4.9 +Parent:Gameplay/HowTo/CharacterMovement/Blueprints SkillLevel: Advanced +type:how-to +type:multi-step +order:3 -[VAR:Steps] -[OBJECT:Navigation] - [PARAM:previous] - [Previous Step](Gameplay\HowTo\CharacterMovement\Blueprints\Input "%Gameplay\HowTo\CharacterMovement\Blueprints\Input:title%") - [/PARAM] - [PARAM:current] - [/PARAM] - [PARAM:home] - [Character Movement Overview](Gameplay\HowTo\CharacterMovement\Blueprints) - [/PARAM] - [PARAM:next] - [Next Step](Gameplay\HowTo\CharacterMovement\Blueprints\BlendSpace "%Gameplay\HowTo\CharacterMovement\Blueprints\BlendSpace:title%") - [/PARAM] -[/OBJECT] -[/VAR] - -%Steps% +[NAV] In this section, we will finish setting up the Character by implementing the scripts that control our Character based on Player Input. @@ -117,4 +105,4 @@ In this section, we will finish setting up the Character by implementing the scr We then set how high the character can jump based on whether or not they are moving by setting the **JumpZVelocity** to **365** (for a moving character) or **340** while we are stationary. In either case, we set **Jump Pressed** to _True_ and set **Jump Pressed** to _False_ when Jump is released. -%Steps% +[NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Setup_2/Setup_2.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Setup_2/Setup_2.JPN.udn index 6a9535be137d..ca1b0853317a 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Setup_2/Setup_2.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Setup_2/Setup_2.JPN.udn @@ -1,28 +1,16 @@ -INTSourceChangelist:2740691 +INTSourceChangelist:3429254 Availability:Public Title:3.キャラクター設定の完了 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement, Gameplay\HowTo\CharacterMovement\Blueprints Description:Input Mapping に反応してキャラクターが移動するようにブループリントでスクリプトを実行します。 Version:4.9 +Parent:Gameplay/HowTo/CharacterMovement/Blueprints SkillLevel:Advanced +type:how-to +type:multi-step +order:3 -[VAR:Steps] -[OBJECT:Navigation] - [PARAM:previous] - [前のステップ](Gameplay\HowTo\CharacterMovement\Blueprints\Input "%Gameplay\HowTo\CharacterMovement\Blueprints\Input:title%") - [/PARAM] - [PARAM:current] - [/PARAM] - [PARAM:home] - [キャラクターの移動の概要](Gameplay\HowTo\CharacterMovement\Blueprints) - [/PARAM] - [PARAM:next] - [次のステップ](Gameplay\HowTo\CharacterMovement\Blueprints\BlendSpace "%Gameplay\HowTo\CharacterMovement\Blueprints\BlendSpace:title%") - [/PARAM] -[/OBJECT] -[/VAR] - -%Steps% +[NAV] このセクションでは、プレイヤー入力に合わせてキャラクターを制御するスクリプトを実行して、キャラクター設定を完了させます。 @@ -30,11 +18,11 @@ SkillLevel:Advanced 1. グラフ内で **InputAxis MoveForward** Event と **InputAxis MoveRight** Event を **右クリック** して追加します。 -1. **Control** を押したまま **DisableMovement** 変数をドラッグし、各イベントの **Branch** の **Condition** に接続します。 +1. **Control** キーを押したまま **DisableMovement** 変数をドラッグし、各イベントの **Branch** の **Condition** に接続します。 1. 残りのノード ネットワークを以下のように設定します。 - [REGION:lightbox] + [![](Character_Movement.png)(w:720)](Character_Movement.png) [/REGION] @@ -50,11 +38,11 @@ SkillLevel:Advanced 1. グラフ内を **右クリック** して、 **InputAction Jog** Event を追加します。 -1. **[MyBlueprint]** ウィンドウで、 **[Show inherited variables]** チェックボックスをクリックし、**Control** を押しながら、 **CharacterMovement** をグラフへドラッグします。 +1. **[MyBlueprint]** ウィンドウで、 **[Show inherited variables]** チェックボックスをクリックし、**Control** キーを押しながら、 **CharacterMovement** をグラフへドラッグします。 ![](Character_JogA.png) -1. **Alt** を押しながら **Jog Pressed** 変数をドラッグしたら、 **Control** を押しながら **Crouch Pressed** 変数をドラッグします。 +1. **Alt** キーを押しながら **Jog Pressed** 変数をドラッグしたら、 **Control** キーを押しながら **Crouch Pressed** 変数をドラッグします。 1. 適切な **Set** ノードの "Jog Pressed" がチェックされるように、ノード ネットワークを以下のように設定します: @@ -69,7 +57,7 @@ SkillLevel:Advanced 1. グラフ内を **右クリック** して、 **InputAction Crouch** Eventを追加します。 -1. **Alt** を押しながら **Crouch Pressed** 変数をドラッグしたら、 **Control** を押しながら **Jog Pressed** 変数と **Prone Pressed** 変数をドラッグします。 +1. **Alt** キーを押しながら **Crouch Pressed** 変数をドラッグしたら、 **Control** キーを押しながら **Jog Pressed** 変数と **Prone Pressed** 変数をドラッグします。 1. 適切な **Set** ノードの "Crouch Pressed" がチェックされるように、ノード ネットワークを以下のように設定します。 @@ -84,9 +72,9 @@ SkillLevel:Advanced 1. グラフ内を **右クリック** して、 **InputAction Prone** Event を追加します。 -1. **Alt** を押しながら **Prone Pressed** 変数と **DisableMovement** 変数をドラッグします。 +1. **Alt** キーを押しながら **Prone Pressed** 変数と **DisableMovement** 変数をドラッグします。 -1. **Control** を押しながら、 **Crouch Pressed** 変数をドラッグします。 +1. **Control** キーを押しながら、 **Crouch Pressed** 変数をドラッグします。 1. 適切な **Set** ノードの "Prone Pressed" がチェックされるように、ノード ネットワークを以下のように設定します。 @@ -102,9 +90,9 @@ SkillLevel:Advanced 1. グラフ内を **右クリック** して、 **InputAction Jump** Event を追加し、 **[MyBlueprint]** ウィンドウから **CharacterMovement** をドラッグします。 -1. **Alt** を押しながら **Jump Pressed** 変数をドラッグしたら、 **Control** を押しながら **DisableMovement** 変数と **CrouchPressed** 変数をドラッグします。 +1. **Alt** キーを押しながら **Jump Pressed** 変数をドラッグしたら、 **Control** キーを押しながら **DisableMovement** 変数と **CrouchPressed** 変数をドラッグします。 -1. 適切な **Set** ノードの "Jump Pressed" がチェックされるように、ノード ネットワークを以下のように設定します。 +1. 適切な **Set** ノードの "Jump Pressed" をチェックするように、ノード ネットワークを以下のように設定します。 [REGION:lightbox] [![](Character_Jump.png)(w:720)](Character_Jump.png) @@ -112,9 +100,9 @@ SkillLevel:Advanced _画像をクリックしてフルサイズで表示_ - Jump スクリプトの場合は、まずステートが Prone か Crouched のいずれかになっているかを確認します。両方とも _true_ でなければ、 **CharacterMovement** コンポーネントを使って現在の速度を判断します。 0 より大きければ、移動していることになります。 + Jump スクリプトの場合は、まずステートが Prone か Crouched のいずれかになっているかを確認します。両方とも _true_ ではなければ、 **CharacterMovement** コンポーネントを使って現在の速度を判断します。 0 より大きければ、移動していることになります。 移動しているかどうかに応じて、まだ固定状態のうちに **JumpZVelocity** を **365** (キャラクターが移動している場合) または **340** に設定して、キャラクターがジャンプできる高さを設定します。どちらの場合も **Jump Pressed** は _True_ に設定し、 Jump が解除されると **Jump Pressed** を _False_ に設定します。 -%Steps% +[NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Setup_2/Setup_2.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Setup_2/Setup_2.KOR.udn index c30cea90871c..346ac6cef46c 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Setup_2/Setup_2.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/Blueprints/Setup_2/Setup_2.KOR.udn @@ -1,28 +1,16 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:3. 캐릭터 셋업 마무리 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\CharacterMovement, Gameplay\HowTo\CharacterMovement\Blueprints Description:여기서는 캐릭터 이동이 가능하도록 입력 매핑에 대한 반응을 캐릭터 블루프린트의 스크립트로 구현합니다. Version: 4.9 +Parent:Gameplay/HowTo/CharacterMovement/Blueprints SkillLevel: Advanced +type:how-to +type:multi-step +order:3 -[VAR:Steps] -[OBJECT:Navigation] - [PARAM:previous] - [예전 단계](Gameplay\HowTo\CharacterMovement\Blueprints\Input "%Gameplay\HowTo\CharacterMovement\Blueprints\Input:title%") - [/PARAM] - [PARAM:current] - [/PARAM] - [PARAM:home] - [캐릭터 무브먼트 개요](Gameplay\HowTo\CharacterMovement\Blueprints) - [/PARAM] - [PARAM:next] - [다음 단계](Gameplay\HowTo\CharacterMovement\Blueprints\BlendSpace "%Gameplay\HowTo\CharacterMovement\Blueprints\BlendSpace:title%") - [/PARAM] -[/OBJECT] -[/VAR] - -%Steps% +[NAV] 여기서는 플레이어 입력에 따라 캐릭터를 제어하는 스크립트를 구현하여 캐릭터 셋업을 마무리하도록 하겠습니다. @@ -118,4 +106,4 @@ SkillLevel: Advanced 그러면 이동중인지 여부에 따라 캐릭터의 점프 높이를 이동중인 경우 **JumpZVelocity** 를 **365** 로, 정지상태인 경우 **340** 으로 설정하면 됩니다. 어느 경우에도 **Jump Pressed** 를 _True_ 로 설정했다가, 점프가 끝나면 **Jump Pressed** 를 _False_ 로 설정합니다. -%Steps% \ No newline at end of file +[NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/CharacterMovementOverview.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/CharacterMovementOverview.INT.udn index 18f3548e52ad..4e2b902b3d97 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/CharacterMovementOverview.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/CharacterMovementOverview.INT.udn @@ -4,23 +4,17 @@ Crumbs: %ROOT%, Gameplay Description:A How To Guide for Setting Up a Character with Character Movement in Unreal Engine 4. Version: 4.9 Parent:Gameplay -type:how-to +SkillLevel: Intermediate +type:overview order:10 To create **Character Movement**, several parts are needed, each working together to produce the end result of a character moving around in your game. You will need a character, inputs for that character, how the character responds to inputs from a player, animations for the character moving, transitions to and from animations, and the logic behind the transitioning between animations. In this "How To" series, we intend to show you how you can set all this up from scratch in Blueprints where at the end of the series, you will have a playable character that exhibits different forms of Character Movement. -## Setup +## Implementation Guides -To learn more about **Setting up Character Movement in Blueprints**, follow the link below: - -[REGION:buttonlist] -* [](Gameplay\HowTo\CharacterMovement\Blueprints) - -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/CharacterMovement" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/CharacterMovementOverview.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/CharacterMovementOverview.JPN.udn index 97cd916c514e..a2d53ea6aa1f 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/CharacterMovementOverview.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/CharacterMovementOverview.JPN.udn @@ -1,27 +1,21 @@ -INTSourceChangelist:2815879 +INTSourceChangelist:3429254 Availability:Public Title:キャラクターの移動の設定方法 Crumbs: %ROOT%, Gameplay Description:UE4 でキャラクターに移動を設定するためのガイド Version:4.9 Parent:Gameplay -type:how-to +SkillLevel:Intermediate +type:overview order:10 -**キャラクターの移動** を作成するには、いくつかの構成要素が必要で、それらがお互いに作用することで、最終的にゲーム内でキャラクターが移動します。必要なものは、キャラクター、キャラクターへの入力、プレイヤーからの入力に対するキャラクターの反応方法、キャラクター移動用のアニメーション、アニメーション間の遷移、アニメーション間の遷移を成り立たせるロジック、です。 +**キャラクターの移動** を作成するには、いくつかの構成要素が必要で、それらが互いに作用することで、最終的にゲーム内でキャラクターが移動します。必要なものは、キャラクター、キャラクターへの入力、プレイヤーからの入力に対するキャラクターの反応方法、キャラクター移動用のアニメーション、アニメーション間の遷移、アニメーション間の遷移を成り立たせるロジックです。 -この「How To」シリーズでは、ブループリントで全ての設定をゼロから行う方法を紹介し、シリーズの最後には、様々な動き方を表現できるプレイ可能なキャラクターが完成します。 +このガイドでは、ブループリントで全ての設定をゼロから行う方法を紹介し、シリーズの最後には、様々な動き方を表現できるプレイ可能なキャラクターが完成します。 -## セットアップ +## 実装ガイド -**ブループリントでキャラクターの移動を設定する方法** については、以下を参照してください。 - -[REGION:buttonlist] -* [](Gameplay\HowTo\CharacterMovement\Blueprints) - -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/CharacterMovement" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/CharacterMovementOverview.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/CharacterMovementOverview.KOR.udn index 5b1371f43a02..ee7030d40273 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/CharacterMovementOverview.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/CharacterMovement/CharacterMovementOverview.KOR.udn @@ -1,27 +1,21 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:캐릭터 무브먼트 셋업 Crumbs: %ROOT%, Gameplay Description:언리얼 엔진 4 에서 캐릭터에 캐릭터 무브먼트를 구성하는 비법 안내입니다. Version: 4.9 Parent:Gameplay -type:how-to +SkillLevel: Intermediate +type:overview order:10 **Character Movement** (캐릭터 무브먼트, 동작)을 만들기 위해서는 여러 부속이 필요한데, 그 각각이 조합되어 게임을 돌아다니는 캐릭터가 탄생하게 됩니다. 캐릭터, 그 캐릭터에 대한 입력, 플레이어의 입력에 대한 그 캐릭터의 반응 방식, 캐릭터 이동에 대한 애니메이션, 애니메이션 사이의 전환, 애니메이션 사이 전환 배후의 로직 등이 필요할 것입니다. 이번 비법 시리즈에서는 블루프린트를 통해 이 모든 것들을 기초부터 구성해 나가는 법을 보여드리고자 하며, 시리즈 마지막에는 다양한 캐릭터 동작을 보여주는 플레이가능 캐릭터가 생길 것입니다. -## 구성 +## 구현 안내 -블루프린트로 **캐릭터 무브먼트** 를 구성하는 방법 관련 상세 정보는, 다음 링크를 참고하세요: - -[REGION:buttonlist] -* [](Gameplay\HowTo\CharacterMovement\Blueprints) - -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/CharacterMovement" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/FindingActors/Blueprints/FindingActors_BP.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/FindingActors/Blueprints/FindingActors_BP.INT.udn index dc4ad19220fd..69b756886a1f 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/FindingActors/Blueprints/FindingActors_BP.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/FindingActors/Blueprints/FindingActors_BP.INT.udn @@ -4,6 +4,7 @@ Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\FindingActors Description:A How To Guide for Finding Actors in Blueprints. Version: 4.9 SkillLevel: Intermediate +type:how-to [TOC (start:2 end:2)] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/FindingActors/Blueprints/FindingActors_BP.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/FindingActors/Blueprints/FindingActors_BP.JPN.udn index 1ed38aeab7cd..fa7d6d89b798 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/FindingActors/Blueprints/FindingActors_BP.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/FindingActors/Blueprints/FindingActors_BP.JPN.udn @@ -1,10 +1,11 @@ -INTSourceChangelist:2701189 +INTSourceChangelist:3429254 Availability:Public Title:ブループリントでアクタを検索する Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\FindingActors Description:ブループリントでアクタを検索するための操作ガイド Version:4.9 SkillLevel:Intermediate +type:how-to [TOC (start:2 end:2)] @@ -69,7 +70,7 @@ SkillLevel:Intermediate ## 特定のアクタを取得する -前のセクションで、 **Get All Actors of Class** ノードを使うと指定したクラスのアクタの配列が作成されることを理解できたと思います。このセクションでは、様々な基準に合わせて得た配列結果にフィルタを適用して、その配列から特定の複数のアクタを取得、あるいはアクタを 1 つだけ取得する方法を紹介します。 +前のセクションで、 **Get All Actors of Class** ノードを使うと、指定したクラスのアクタの配列が作成されることを理解できたと思います。このセクションでは、様々な基準に合わせて得た配列結果にフィルタを適用して、その配列から特定の複数のアクタを取得、あるいはアクタを 1 つだけ取得する方法を紹介します。 まずひとつめは、アクタで **タグ** を使う方法です。 @@ -103,7 +104,7 @@ SkillLevel:Intermediate ![](Actors12.png)(w:800) -1. **ForEachLoop** ピンの **Array Element** ピンを引き出して **P_Fire** と **Fire Audio** を get して、**Deactivate** ノードへ接続します。 +1. **ForEachLoop** ピンの **Array Element** ピンを引き出して **P_Fire** と **Fire Audio** を取得して、**Deactivate** ノードへ接続します。 [REGION:lightbox] [![](Actors13.png)(w:800)](Actors13.png) diff --git a/Engine/Documentation/Source/Gameplay/HowTo/FindingActors/Blueprints/FindingActors_BP.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/FindingActors/Blueprints/FindingActors_BP.KOR.udn index b096d61352a3..5ab9088b8954 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/FindingActors/Blueprints/FindingActors_BP.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/FindingActors/Blueprints/FindingActors_BP.KOR.udn @@ -1,10 +1,11 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:블루프린트에서 액터 검색 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\FindingActors Description:블루프린트에서 액터를 검색하는 비법 안내입니다. Version: 4.9 SkillLevel: Intermediate +type:how-to [TOC (start:2 end:2)] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/FindingActors/FindingActorsOverview.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/FindingActors/FindingActorsOverview.INT.udn index 059e22f61b46..d316715a0cf4 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/FindingActors/FindingActorsOverview.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/FindingActors/FindingActorsOverview.INT.udn @@ -4,7 +4,8 @@ Crumbs: %ROOT%, Gameplay Description:A How To Guide for Finding Actors in your Scenes in Unreal Engine 4. Version: 4.9 Parent:Gameplay -type:how-to +SkillLevel: Intermediate +type:overview order:11 Once you start constructing your game and its levels, you may find that locating an individual Actor in your scene may be difficult. It is not uncommon to have hundreds of Actors in your scene ranging from level set pieces or geometry, to NPCs or enemies, to interactable objects or pick-ups and locating one Actor out of all those is like the old saying of "looking for a needle in a haystack". @@ -23,17 +24,9 @@ Refer to the [](Engine/UI/LevelEditor/SceneOutliner) documentation for more info While finding an Actor in the Editor can be accomplished with the help of the World Outliner, how do you go about finding an Actor through Blueprints so that you may modify it in some way? This "How To" series will show you some ways in which you can search your scene for an Actor based on varying criteria at which point you can then access and modify it if you wish. +## Implementation Guides -## Setup - -To learn more about Finding Actors using Blueprints, use the link below: - -[REGION:buttonlist] -* [](Gameplay\HowTo\FindingActors\Blueprints) - -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/FindingActors" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/FindingActors/FindingActorsOverview.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/FindingActors/FindingActorsOverview.JPN.udn index 14bf4ea49a24..32b28f67326b 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/FindingActors/FindingActorsOverview.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/FindingActors/FindingActorsOverview.JPN.udn @@ -1,14 +1,15 @@ -INTSourceChangelist:2735882 +INTSourceChangelist:3429254 Availability:Public Title:アクタを検索する Crumbs: %ROOT%, Gameplay -Description:UE4 のシーン内でアクタを検索するための操作ガイド +Description:UE4 のシーン内でアクタを見つけるための操作ガイド Version:4.9 Parent:Gameplay -type:how-to +SkillLevel:Intermediate +type:overview order:11 -ゲームとレベルを構築し始めると、シーン内の個々のアクタを見つけることが難しく感じるかもしれません。レベルに設定されている構成要素やジオメトリから NPC、敵、インタラクション可能なオブジェクトやピックアップに至るまで、シーン内のアクタが数百に上ることは珍しくありません。これらの中からアクタ 1 つを探し出すのは、ことわざでいう「干し草の山の中にある一本の針を見つける (つまり無駄骨を折る) 」ようなものです。 +ゲームとレベルを構築し始めると、シーン内の個々のアクタを見つけることが難しく感じるかもしれません。レベルに設定されている構成要素やジオメトリから NPC、敵、インタラクション可能なオブジェクトやピックアップに至るまで、シーン内のアクタが数百に上ることは珍しくありません。これらの中からひとつのアクタを探し出すのは、ことわざでいう「干し草の山の中にある一本の針を見つける (つまり無駄骨を折る) 」ようなものです。 ただし、 **ワールド アウトライナー** を使って、シーン内のアクタの検索幅を狭めることはできます (以下の図参照)。 @@ -17,24 +18,16 @@ order:11 上図では、レベル内に配置されたすべてのアクタがワールド アウトライナー (右) に表示されます。ワールド アウトライナー内のアクタを 1 つクリックすると、レベル ビューポート内でも強調表示されます。**Actor (アクタ)** または **Type (種類)** のヘッダをクリックすれば、 **ワールド アウトライナー** をアクタ名またはアクタの種類でソートすることができます (Type Box の下向き矢印をクリックすると、サブ カテゴリを種類から別のフィルタへ変更することができます)。 [REGION:tip] -ワールド アウトライナーでアクタを選択した状態で、レベル ビューポート内をナビゲート中に **F** キーを押すと、選択中のアクタがフォーカスできる位置にカメラを移動します。 +ワールド アウトライナーでアクタを選択した状態で、レベル ビューポート内をナビゲート中に **F** キーを押すと、選択中のアクタが **フォーカス** できる位置にカメラを移動します。 [/REGION] シーン内でのアクタの配置については、 [](Engine/UI/LevelEditor/SceneOutliner) をご覧ください。 -エディタでのアクタ検索にはワールド アウトライナー使うことができますが、ブループリントでアクタを見つけて修正できるようにするにはどうすれば良いでしょうか?この「How to」シリーズでは、必要に応じてアクセスおよび修正できる様々な基準でシーン内のアクタ検索を行う方法を紹介します。 +エディタでのアクタ検索にはワールド アウトライナー使うことができますが、ブループリントでアクタを見つけて修正できるようにするにはどうすれば良いでしょうか? 以下のガイドでは、必要に応じてアクセスおよび修正できる様々な基準でシーン内のアクタ検索を行う方法を紹介します。 +## 実装ガイド -## セットアップ - -ブループリントを使用してアクタを検索する方法については、以下のリンクを参照してください。 - -[REGION:buttonlist] -* [](Gameplay\HowTo\FindingActors\Blueprints) - -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/FindingActors" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/FindingActors/FindingActorsOverview.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/FindingActors/FindingActorsOverview.KOR.udn index fa91d7108722..56ce5e9416f5 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/FindingActors/FindingActorsOverview.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/FindingActors/FindingActorsOverview.KOR.udn @@ -1,11 +1,12 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:액터 검색 Crumbs: %ROOT%, Gameplay Description:언리얼 엔진 4 에서 씬에 있는 액터를 검색하는 비법 안내입니다. Version: 4.9 Parent:Gameplay -type:how-to +SkillLevel: Intermediate +type:overview order:11 게임 제작을 시작하고 레벨을 만들다 보면, 씬에 있는 액터를 검색하기가 까다롭게 느껴질 때가 옵니다. 레벨 세트 조각이나 지오메트리에서부터 NPC 와 적, 조작 가능한 오브젝트나 픽업에 이르기까지 씬에 있는 액터가 수백개에 달하여 그 중 하나를 찾다 보면 "모래사장에서 바늘찾기" 같은 옛말이 떠오르게 마련입니다. @@ -24,17 +25,9 @@ order:11 **월드 아웃라이너** 의 도움으로 에디터에서 액터를 찾을 수는 있었다고 쳐도, **블루프린트** 를 통해 액터를 찾아 어떤 식으로든 변경을 하려면 어떻게 해야 할까요? 이 "비법" 시리즈에서는 다양한 범주에 따라 씬에서 액터를 검색하고 원한다면 접근하여 변경할 수도 있는 방법을 보여드리겠습니다. +## 구현 안내 -## 셋업 - -블루프린트를 사용한 **액터 검색** 관련 상세 정보는, 아래 링크를 참고하세요: - -[REGION:buttonlist] -* [](Gameplay\HowTo\FindingActors\Blueprints) - -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/FindingActors" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateActor/Blueprints/ReplicateActor_BP.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateActor/Blueprints/ReplicateActor_BP.INT.udn index f2c9c09d3fca..7f7efcda947c 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateActor/Blueprints/ReplicateActor_BP.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateActor/Blueprints/ReplicateActor_BP.INT.udn @@ -6,6 +6,7 @@ Related: Engine/Blueprints Related: Resources/ContentExamples/Networking Version: 4.9 SkillLevel: Advanced +type:how-to [TOC (start:2 end:2)] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateActor/Blueprints/ReplicateActor_BP.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateActor/Blueprints/ReplicateActor_BP.KOR.udn index e47fbb30c775..dd19a8a5ac84 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateActor/Blueprints/ReplicateActor_BP.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateActor/Blueprints/ReplicateActor_BP.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:블루프린트에서 액터 리플리케이트 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\Networking/ReplicateActor @@ -7,6 +7,7 @@ Related: Engine/Blueprints Related: Resources/ContentExamples/Networking Version: 4.9 SkillLevel: Advanced +type:how-to [TOC (start:2 end:2)] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateActor/ReplicateActorOverview.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateActor/ReplicateActorOverview.INT.udn index c6c265696864..1fb222733a98 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateActor/ReplicateActorOverview.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateActor/ReplicateActorOverview.INT.udn @@ -4,7 +4,8 @@ Crumbs: %ROOT%, Gameplay Description:Guide for Replicating Actors in Multiplayer Games. version: 4.9 Parent:Gameplay -type:how-to +SkillLevel: Advanced +type:overview order:15 The process of passing data or commands between Server and Clients is referred to as **Replication**, and Actor Replication is where the Server identifies and acknowledges if an Actor is set to use Replication or not. If the Actor is set to Replicate, the Server will tell the Client to create and maintain a Replicated copy of that Actor on the Client's machine. The Server always has the authoritative version of that Actor, while a Client (or multiple Clients) may have the approximate, replicated versions of that Actor. @@ -12,14 +13,9 @@ The process of passing data or commands between Server and Clients is referred t Options can be set to define how Replicated Actors behave on a Client, from whether or not to Replicate Movement (the location/rotation of the Actor) to setting its Network Relevancy (or when to send Replicated Data to the Client, as the Actor set to Replicate may or may not be relevant depending upon gameplay situations). -## Setup - -To learn more about Replicating Actors using Blueprints, follow the link below: - -[REGION:buttonlist] -* [](Gameplay\HowTo\Networking\ReplicateActor\Blueprints) -[/REGION] +## Implementation Guides +[DIR(output:"role" parent:"Gameplay/HowTo/Networking/ReplicateActor" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateActor/ReplicateActorOverview.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateActor/ReplicateActorOverview.JPN.udn index 1eb868ed5337..aee0ddf318eb 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateActor/ReplicateActorOverview.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateActor/ReplicateActorOverview.JPN.udn @@ -1,11 +1,12 @@ -INTSourceChangelist:2735882 +INTSourceChangelist:3429254 Availability:Public Title:アクタのレプリケート方法 Crumbs: %ROOT%, Gameplay Description:マルチプレイヤー ゲームでアクタをレプリケートするためのガイド version:4.9 Parent:Gameplay -type:how-to +SkillLevel:Advanced +type:overview order:15 サーバーとクライアント間でデータやコマンドを渡すプロセスは **レプリケーション** と呼ばれ、アクタのレプリケーションとは、アクタがレプリケーションを使用するかどうかをサーバーが特定し認識することです。アクタが Replicate に設定されていると、サーバーはクライアントに、クライアント側でそのアクタのレプリケートされたコピーを作成し保持するように伝えます。サーバーのアクタが常にそのアクタの正式版で、クライアント側 (複数可) のアクタはそのアクタのレプリケート版となります。 @@ -13,14 +14,9 @@ order:15 移動をレプリケート (アクタの位置 / 回転) するか否かの設定から、 ネットワークの関連性の設定 (レプリケートを設定されたアクタはゲームの状況によって関連性が変わるため、レプリケートされたデータをいつクライアントに渡すか) に至るまで、レプリケートされたアクタのクライアント側でのビヘイビアを設定することもできます。 -## セットアップ - -ブループリントでアクタをレプリケートする方法については、以下のリンクを参照してください。 - -[REGION:buttonlist] -* [](Gameplay\HowTo\Networking\ReplicateActor\Blueprints) -[/REGION] +## 実装ガイド +[DIR(output:"role" parent:"Gameplay/HowTo/Networking/ReplicateActor" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateActor/ReplicateActorOverview.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateActor/ReplicateActorOverview.KOR.udn index 02344ac97e44..555800fe1156 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateActor/ReplicateActorOverview.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateActor/ReplicateActorOverview.KOR.udn @@ -1,11 +1,12 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:액터 리플리케이트 비법 Crumbs: %ROOT%, Gameplay Description:멀티플레이어 게임에서의 액터 리플리케이션에 대한 안내입니다. version: 4.9 Parent:Gameplay -type:how-to +SkillLevel: Advanced +type:overview order:15 서버와 클라이언트 사이에서 데이터와 명령을 주고받는 프로세스를 일컬어 **Replication**, 리플리케이션이라 합니다 (역주: 복제라는 뜻이긴 합니다만, copy 나 duplicate 와의 혼동을 피하기 위해 그냥 영문을 그대로 음차하기로 했습니다). **액터 리플리케이션** 이라는 것은, 액터에 리플리케이션 설정이 되어있는지 아닌지 식별한 다음 승인하는 것입니다. 액터에 리플리케이트 설정이 되어 있다면, 서버는 클라이언트더러 클라이언트 머신에 그 액터의 복제된 사본을 만들어 유지하라 이르는 것이지요. 서버에는 항상 그 액터의 전권이 있는 원본이 있는 반면, 클라이언트(들)에는 그 액터를 추정해 낸 복사본이 있게 됩니다. @@ -13,14 +14,9 @@ order:15 옵션을 통해 리플리케이티드 액터가 클라이언트에서의 작동 방식을 설정할 수 있는데, **Replicate Movement** (액터의 위치/방향 복제) 여부에서부터 **Network Relevancy** (네트워크 연관성) 설정도 가능합니다 (다른 말로 리플리케이티드 데이터를 클라이언트에 전송하는 시점을 결정하는 것인데, 리플리케이트 설정이 된 액터가 게임플레이 상황에 따라 연관성이 있을 수도 없을 수도 있기 때문입니다). -## 구성 - -블루프린트를 사용한 **액터 리플리케이션** 관련 상세 정보는, 다음 링크를 참고하세요: - -[REGION:buttonlist] -* [](Gameplay\HowTo\Networking\ReplicateActor\Blueprints) -[/REGION] +## 구현 안내 +[DIR(output:"role" parent:"Gameplay/HowTo/Networking/ReplicateActor" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateFunction/Blueprints/ReplicateFunction_BP.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateFunction/Blueprints/ReplicateFunction_BP.INT.udn index b4c101cdcd71..61744b745260 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateFunction/Blueprints/ReplicateFunction_BP.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateFunction/Blueprints/ReplicateFunction_BP.INT.udn @@ -6,6 +6,7 @@ Related: Engine/Blueprints Related: Resources/ContentExamples/Networking Version: 4.9 SkillLevel: Advanced +type:how-to [TOC (start:2 end:2)] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateFunction/Blueprints/ReplicateFunction_BP.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateFunction/Blueprints/ReplicateFunction_BP.KOR.udn index 14536d074dfa..36de563b7288 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateFunction/Blueprints/ReplicateFunction_BP.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateFunction/Blueprints/ReplicateFunction_BP.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:블루프린트에서 함수 리플리케이트 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\Networking\ReplicateFunction @@ -7,6 +7,7 @@ Related: Engine/Blueprints Related: Resources/ContentExamples/Networking Version: 4.9 SkillLevel: Advanced +type:how-to [TOC (start:2 end:2)] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateFunction/ReplicateFunctionOverview.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateFunction/ReplicateFunctionOverview.INT.udn index c98e0a9d3f9a..6adeca0c5ec4 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateFunction/ReplicateFunctionOverview.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateFunction/ReplicateFunctionOverview.INT.udn @@ -4,7 +4,8 @@ Crumbs: %ROOT%, Gameplay Description:Guide for Replicating Functions in Multiplayer Games. Version: 4.9 Parent:Gameplay -type:how-to +SkillLevel: Advanced +type:overview order:16 **Function Replication** (Remote Procedure Calls or RPCs for short) are functions that are called locally, but executed remotely on another machine (separate from the machine performing the call). RPC functions can be very useful and allow either the Client or the Server to send messages to each other over a network connection. Replicated function calls can be set to either **Reliable** or **Unreliable** where Reliable calls are guaranteed to occur, while Unreliable calls may be dropped during heavy network traffic. Most Replicated Functions that handle cosmetic visuals are unreliable to avoid saturating the network. @@ -13,13 +14,9 @@ There are 3 primary types of Replicated Functions: **Multicast**, **Run on Serve Server and Client Replicated Functions have some restrictions, for one they can only be used on Actors that have a **Net Owner**. Actors have Net Owners if they are a Player Controller or owned by a Player Controller. For example, a Pawn possessed by a Player Controller can have Server or Client Replicated Functions executed upon it. -## Setup +## Implementation Guides -To learn how to set up Replicated Functions using Blueprints, follow the link below: - -[REGION:buttonlist] -* [](Gameplay\HowTo\Networking\ReplicateFunction\Blueprints) -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/Networking/ReplicateFunction" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateFunction/ReplicateFunctionOverview.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateFunction/ReplicateFunctionOverview.JPN.udn index c480469e3bf0..09f2a003578a 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateFunction/ReplicateFunctionOverview.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateFunction/ReplicateFunctionOverview.JPN.udn @@ -1,11 +1,12 @@ -INTSourceChangelist:2735882 +INTSourceChangelist:3429254 Availability:Public Title:関数をレプリケートする Crumbs: %ROOT%, Gameplay -Description:マルチプレイヤー ゲームで関数をレプリケートするガイド +Description:マルチプレイヤー ゲームで関数をレプリケートするガイド Version:4.9 Parent:Gameplay -type:how-to +SkillLevel:Advanced +type:overview order:16 **関数のレプリケーション** (Remote Procedure Calls、略して RPCs) は、ローカルで呼び出される関数ですが、別のマシンでリモートで実行されます (呼び出しを実行する側のマシンとは別)。RPC 関数は非常に便利で、クライアントまたはサーバーがネットワーク接続で互いにメッセージを送信できます。レプリケート関数の呼び出しは **Reliable (信頼できる)** もしくは **Unreliable (信頼できない)** のいずれかに設定することができ、信頼できるコールは発生が保証される一方、信頼できないコールはネットワーク トラフィックの渋滞の間に取り下げられます。表面上の外見を処理するレプリケート関数のほとんどは、ネットワーク サチュレーションを避けるためのものなので信頼できません。 @@ -14,13 +15,9 @@ order:16 サーバーおよびクライアント側でレプリケートされたレプリケート関数には、 **Net Owner** を持つアクタ上でしか使用することができないという制限があります。アクタがプレイヤー コントローラーの場合、もしくはプレイヤー コントローラーにより所有される場合、アクタにはネット オーナーがあります。例えば、プレイヤー コントローラにより所有されるポーンは、 サーバー側でのレプリケート関数またはクライアント側でのレプリケート関数を、その上で実行することができます。 -## セットアップ +## 実装ガイド -ブループリントを使ったレプリケート関数のセットアップ方法については、以下のリンクを参照してください。 - -[REGION:buttonlist] -* [](Gameplay\HowTo\Networking\ReplicateFunction\Blueprints) -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/Networking/ReplicateFunction" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateFunction/ReplicateFunctionOverview.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateFunction/ReplicateFunctionOverview.KOR.udn index 505a4b0e7ec3..c6662131b632 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateFunction/ReplicateFunctionOverview.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateFunction/ReplicateFunctionOverview.KOR.udn @@ -1,11 +1,12 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:함수 리플리케이트 Crumbs: %ROOT%, Gameplay Description:멀티플레이어 게임에서의 함수 리플리케이션 방법 안내서입니다. Version: 4.9 Parent:Gameplay -type:how-to +SkillLevel: Advanced +type:overview order:16 **함수 리플리케이션** (리모트 프로시져 콜, 줄여서 RPC)은 로컬에서 호출되지만 (호출을 실행하는 머신과는 별개로) 다른 머신에서 원격으로 실행되는 함수를 말합니다. RPC 함수는 매우 유용할 수 있으며, 클라이언트나 서버가 네트워크 접속을 통해 서로에게 메시지를 전송할 수 있도록 합니다. 리플리케이티드 함수 호출은 **Reliable** (신뢰성) 또는 **Unreliable** (비신뢰성) 설정이 가능한데, 신뢰성 호출은 반드시 실행이 보장되는 반면, 비신뢰성 호출은 네트워크 트래픽이 심한 경우 버려질 수 있습니다. 대부분의 장식성 비주얼 처리를 하는 리플리케이티드 함수는 네트워크 포화 상태를 피하기 위해 비신뢰성으로 처리됩니다. @@ -14,13 +15,9 @@ order:16 서버 및 클라이언트 리플리케이티드 함수에는 몇 가지 제약이 있는데, **넷 오너** 가 있는 액터에만 사용할 수 있습니다. 액터가 넷 오너를 갖는 경우는 플레이어 콘트롤러이거나, 플레이어 콘트롤러에 소유된 경우입니다. 예를 들어 플레이어 콘트롤러에 빙의된 폰은 거기서 서버 또는 클라이언트 리플리케이티드 함수를 실행시킬 수 있습니다. -## 구성 +## 구현 안내 -블루프린트를 사용한 **리플리케이티드 함수** 구성 방법은, 다음 링크를 참고하세요: - -[REGION:buttonlist] -* [](Gameplay\HowTo\Networking\ReplicateFunction\Blueprints) -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/Networking/ReplicateFunction" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateVariable/Blueprints/ReplicateVariable_BP.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateVariable/Blueprints/ReplicateVariable_BP.INT.udn index 4f39f4fc8db1..14fa128ff0ed 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateVariable/Blueprints/ReplicateVariable_BP.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateVariable/Blueprints/ReplicateVariable_BP.INT.udn @@ -6,6 +6,7 @@ Related: Engine/Blueprints Related: Resources/ContentExamples/Networking Version: 4.9 SkillLevel: Advanced +type:how-to [TOC (start:2 end:2)] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateVariable/Blueprints/ReplicateVariable_BP.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateVariable/Blueprints/ReplicateVariable_BP.KOR.udn index db20b1e18132..36b71ba563bb 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateVariable/Blueprints/ReplicateVariable_BP.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateVariable/Blueprints/ReplicateVariable_BP.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:블루프린트에서 변수 리플리케이트 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\Networking\ReplicateVariable @@ -7,6 +7,7 @@ Related: Engine/Blueprints Related: Resources/ContentExamples/Networking Version: 4.9 SkillLevel: Advanced +type:how-to [TOC (start:2 end:2)] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateVariable/ReplicateVariableOverview.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateVariable/ReplicateVariableOverview.INT.udn index b4eb2fa9a981..de4ff28838c6 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateVariable/ReplicateVariableOverview.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateVariable/ReplicateVariableOverview.INT.udn @@ -4,7 +4,8 @@ Crumbs: %ROOT%, Gameplay Description:Guide for Replicating Variables in Multiplayer Games. Version: 4.9 Parent:Gameplay -type:how-to +SkillLevel: Advanced +type:overview order:17 [EXCERPT:Overview] @@ -13,13 +14,9 @@ Just as [Actors](Gameplay\HowTo\Networking\ReplicateActor) and [Functions](Gamep You can set a variable to Replicated which means the variable produces a one-to-one copy of the variable that is replicated from the Server to Clients. Or you can use the RepNotify which does everything that Replicated does, but also provides a Function that is called that executes on both the Server and Client machines whenever the variable it is attached to updates. [/EXCERPT:Overview] -## Setup +## Implementation Guides -To learn how to set up Replicated Variables using Blueprints, follow the link below: - -[REGION:buttonlist] -* [](Gameplay\HowTo\Networking\ReplicateVariable\Blueprints) -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/Networking/ReplicateVariable" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateVariable/ReplicateVariableOverview.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateVariable/ReplicateVariableOverview.JPN.udn index 98d124c9e771..84287fb16ba7 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateVariable/ReplicateVariableOverview.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateVariable/ReplicateVariableOverview.JPN.udn @@ -1,26 +1,23 @@ -INTSourceChangelist:2735882 +INTSourceChangelist:3429254 Availability:Public Title:変数をレプリケートする Crumbs: %ROOT%, Gameplay Description:マルチプレイヤー ゲームで変数をレプリケーションするためのガイド Version:4.9 Parent:Gameplay -type:how-to +SkillLevel:Advanced +type:overview order:17 [EXCERPT:Overview] -[アクタ](Gameplay\HowTo\Networking\ReplicateActor) と同様に [関数](Gameplay\HowTo\Networking\ReplicateFunction) もネットワーク上でレプリケーション可能であり、**変数** も同様です。ゲームプレイに重要な変数だけを Network Authority (サーバー) 側で編集し、知っておく必要のある情報のみをリモートのマシン (クライアント) にレプリケートします。いつ変数が変更できるかは不正につながりうるためクライアントに定義させないようにします (例、ヘルス、弾薬、エクスペリエンスの値)。 +[アクタ](Gameplay\HowTo\Networking\ReplicateActor) と同様に [関数](Gameplay\HowTo\Networking\ReplicateFunction) もネットワーク上でレプリケーション可能であり、**変数** も同様です。ゲームプレイに重要な変数だけを Network Authority (サーバー) 側で編集し、知っておく必要のある情報のみをリモートのマシン (クライアント) にレプリケートします。いつ変数が変更できるかは不正につながりうるためクライアントに定義させないようにします (例、ヘルス、弾薬、経験値)。 -変数を Replicated に設定することができます。これは、サーバーからクライアントにレプリケートされる変数が 1 対 1 のコピーを作ることを意味します。または、RepNotify を使用することもできます。これは、 Replicated が行うことを何でも行いますが、それに加えてアタッチされている変数が更新されるたびに呼び出され、サーバーとクライアントの両方のマシンで実行する関数があります。 +変数を Replicated に設定することができます。つまり、この変数はサーバーからクライアントにレプリケートされる変数の 1 対 1 のコピーを作ります。または、RepNotify を使用することもできます。RepNotify は Replicated が行うことを何でも行うだけでなく、アタッチされている変数が更新されるたびに呼び出され、サーバーとクライアントの両方のマシンで実行する関数を提供します。 [/EXCERPT:Overview] -## セットアップ +## 実装ガイド -ブループリントを使った Replicated 変数のセットアップ方法については、以下のリンクを参照してください。 - -[REGION:buttonlist] -* [](Gameplay\HowTo\Networking\ReplicateVariable\Blueprints) -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/Networking/ReplicateVariable" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateVariable/ReplicateVariableOverview.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateVariable/ReplicateVariableOverview.KOR.udn index 7bf1373ec44b..259c0463071d 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateVariable/ReplicateVariableOverview.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/Networking/ReplicateVariable/ReplicateVariableOverview.KOR.udn @@ -1,11 +1,12 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:변수 리플리케이트 Crumbs: %ROOT%, Gameplay Description:멀티플레이어 게임에서 변수를 리플리케이트하는 방법 안내입니다. Version: 4.9 Parent:Gameplay -type:how-to +SkillLevel: Advanced +type:overview order:17 [EXCERPT:Overview] @@ -14,13 +15,9 @@ order:17 변수에 **Replicated** 설정을 하면, 그 변수는 서버에서 클라이언트로 리플리케이트되는 변수의 1:1 사본을 만든다는 뜻입니다. 또는 **RepNotify** 를 사용하면, **Replicated** 의 역할에 추가로 붙어있는 변수가 업데이트될 때마다 서버와 클라이언트 머신 양쪽에서 실행되는 함수가 제공되기도 합니다. [/EXCERPT:Overview] -## 구성 +## 구현 안내 -블루프린트를 사용한 **리플리케이티드 변수** 구성 방법에 대해서는, 다음 링크를 참고하세요: - -[REGION:buttonlist] -* [](Gameplay\HowTo\Networking\ReplicateVariable\Blueprints) -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/Networking/ReplicateVariable" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/Networking/TestMultiplayer/TestMultiplayer.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/Networking/TestMultiplayer/TestMultiplayer.INT.udn index e8acdb8f7d26..f733e8a9bd3b 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/Networking/TestMultiplayer/TestMultiplayer.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/Networking/TestMultiplayer/TestMultiplayer.INT.udn @@ -5,6 +5,7 @@ Description:Demonstrates how you can set up the Unreal Editor for testing multip Related: Resources/ContentExamples/Networking Version: 4.9 Parent:Gameplay +SkillLevel: Advanced type:how-to order:18 diff --git a/Engine/Documentation/Source/Gameplay/HowTo/Networking/TestMultiplayer/TestMultiplayer.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/Networking/TestMultiplayer/TestMultiplayer.JPN.udn index ced4c0646da1..14f9f60f86a3 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/Networking/TestMultiplayer/TestMultiplayer.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/Networking/TestMultiplayer/TestMultiplayer.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:2735882 +INTSourceChangelist:3429254 Availability:Public Title:マルチプレイヤー ゲームをテストする Crumbs: %ROOT%, Gameplay @@ -6,6 +6,7 @@ Description:マルチプレイヤー ゲームをテストするためにアン Related:Resources/ContentExamples/Networking Version:4.9 Parent:Gameplay +SkillLevel:Advanced type:how-to order:18 @@ -17,7 +18,7 @@ order:18 **プレイヤー数を増やすには:** -* **[Play]** ボタンの横にある下向きの矢印をクリックし、 **Number of Players** の値を入力します。 +* **[Play]** ボタンの横にある下向きの矢印をクリックし、 **[Number of Players]** の値を入力します。 [REGION:raw] ![](NumberOfPlayers.png) @@ -34,7 +35,7 @@ order:18 **サーバーのプレイ ウィンドウを調整するには:** -* **Play** ボタンの隣にある下向き矢印をクリックし、 **New Editor Window** を選択します。 +* **[Play]** ボタンの隣にある下向き矢印をクリックし、 **[New Editor Window]** を選択します。 [REGION:raw] ![](NewEditorWindow.png) @@ -48,17 +49,17 @@ order:18 **ウィンドウ サイズを調整するには:** -1. **Play** ボタンの隣にある下向き矢印をクリックし、 **Advanced Settings** を選択します。 +1. **[Play]** ボタンの隣にある下向き矢印をクリックし、 **[Advanced Settings]** を選択します。 [REGION:raw] ![](AdvancedSettings.png) [/REGION] -1. **Play in New Window** セクションでお好みのウィンドウ サイズに設定します。 +1. **[Play in New Window]** セクションでお好みのウィンドウ サイズに設定します。 ![](WindowSize.png) - **Play in New Window** サイズ オプションでは、作成されるウィンドウのサイズとデフォルト位置を設定することができます。いくつかのプリセット ウィンドウ サイズから選択するか、ウィンドウ サイズを手動入力できます (ここの例では 640x480 を指定しました)。作成されるウィンドウの **Left** と **Top** の位置を設定するか、**Always center window to screen (画面に対して常にウィンドウを中央に配置)** のチェックボックスをクリックします。 + **[Play in New Window]** サイズ オプションでは、作成されるウィンドウのサイズとデフォルト位置を設定することができます。いくつかのプリセット ウィンドウ サイズから選択するか、ウィンドウ サイズを手動入力できます (ここの例では 640x480 を指定しました)。作成されるウィンドウの **Left** と **Top** の位置を設定するか、**[Always center window to screen (画面に対して常にウィンドウを中央に配置)]** のチェックボックスをクリックします。 ウィンドウ サイズを入力後、エディタで再生すると新しい各ウィンドウは同じサイズになります。 @@ -68,11 +69,11 @@ order:18 ### マルチプレイヤー オプション -**Advanced Settings** 内では、以下のマルチプレイヤーのオプションを追加でセットアップできるセクションがあります。 +**[Advanced Settings]** 内では、以下のマルチプレイヤーのオプションを追加でセットアップできるセクションがあります。 ![](MultiplayerOptions.png) -| オプション| 説明 | +| オプション | 説明 | | -------- | ----------- | | **Number of Players** | 起動時にゲームでスポーンするプレイヤー数を定義します。エディタとリッスン サーバーはプレイヤーとしてカウントされますが、デディケイテッド サーバーはカウントされません。プレイヤーの残りの数はクライアントになります。 | | **Server Game Options** | ここで URL パラメータとしてサーバーに渡される追加オプションを指定することができます。 | @@ -86,7 +87,7 @@ order:18 ![](NoSingleProcess.png) -| オプション| 説明 | +| オプション | 説明 | | -------- | ----------- | | **Editor Multiplayer Mode** | Play In Editor で使用する NetMode です(**Play Offline**、**Play As Listen Server**、 または **Play As Client**)。| | **Command Line Arguments** | スタンドアロンのゲーム インスタンスに渡される追加のコマンドラインオプションを割り当てることができます。 | @@ -102,7 +103,7 @@ order:18 **デディケイテッド サーバーを実行するには:** -* **Play** ボタンの隣にある下向き矢印をクリックし、 **Run Dedicated Server** チェックボックスにチェックを入れます。 +* **[Play]** ボタンの隣にある下向き矢印をクリックし、 **[Run Dedicated Server]** チェックボックスにチェックを入れます。 [REGION:raw] ![](DedicatedServer.png) diff --git a/Engine/Documentation/Source/Gameplay/HowTo/Networking/TestMultiplayer/TestMultiplayer.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/Networking/TestMultiplayer/TestMultiplayer.KOR.udn index fa730db64bb5..f2088cbd0da5 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/Networking/TestMultiplayer/TestMultiplayer.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/Networking/TestMultiplayer/TestMultiplayer.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:멀티플레이어 테스트 Crumbs: %ROOT%, Gameplay @@ -6,6 +6,7 @@ Description:멀티플레이어 게임 테스트용으로 언리얼 에디터를 Related: Resources/ContentExamples/Networking Version: 4.9 Parent:Gameplay +SkillLevel: Advanced type:how-to order:18 diff --git a/Engine/Documentation/Source/Gameplay/HowTo/PossessPawns/Blueprints/GHT_4B.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/PossessPawns/Blueprints/GHT_4B.INT.udn index 7cd28afc01be..088abc1ac162 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/PossessPawns/Blueprints/GHT_4B.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/PossessPawns/Blueprints/GHT_4B.INT.udn @@ -4,6 +4,7 @@ Crumbs: %ROOT%, Gameplay, Gameplay/HowTo/PossessPawns Description:Illustrates using the Possess node in Blueprints to switch between and control multiple characters. Version: 4.8 SkillLevel: Intermediate +type:how-to Related: Engine/Blueprints Related: Gameplay/Framework/Pawn Related: Gameplay/Framework/Pawn/Character diff --git a/Engine/Documentation/Source/Gameplay/HowTo/PossessPawns/Blueprints/GHT_4B.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/PossessPawns/Blueprints/GHT_4B.JPN.udn index 9863002dfa22..88b9da9a8020 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/PossessPawns/Blueprints/GHT_4B.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/PossessPawns/Blueprints/GHT_4B.JPN.udn @@ -1,10 +1,11 @@ -INTSourceChangelist:2701420 +INTSourceChangelist:3429254 Availability:Public Title:ブループリントでポーンを所有する Crumbs: %ROOT%, Gameplay, Gameplay/HowTo/PossessPawns Description:ブループリントで Possess ノードを使って、複数のキャラクター間で切り替えて、制御する方法を説明します。 Version:4.8 SkillLevel:Intermediate +type:how-to Related:Engine/Blueprints Related:Gameplay/Framework/Pawn Related:Gameplay/Framework/Pawn/Character @@ -58,7 +59,6 @@ Related:Gameplay/Framework/Controller/PlayerController ![](Pawns7b.png)(w:640) これにより、プレイヤー コントローラーに対して、どのターゲット ポーンを所有し、制御するかを指示します。**Possess** 関数が呼び出されると、ポーンが現在制御されているかを自動的にチェックし、まずそれを **UnPossess (所有を解除)** してから、新しいポーンを所有しようとします。 - プレイヤーのポーンの制御を解除させて、例えばプレイ可能なキャラクターを直接制御しないステートのスペクテーター (観戦者) タイプにする場合には、 UnPossess 関数を使用することができます。 1. あと 2 つ **Possess** ノードを作成して、以下のように **1**、**2**、および **3** の Keyboard Event を接続します。 diff --git a/Engine/Documentation/Source/Gameplay/HowTo/PossessPawns/Blueprints/GHT_4B.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/PossessPawns/Blueprints/GHT_4B.KOR.udn index 2bfd18aaf892..b99b0114fea1 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/PossessPawns/Blueprints/GHT_4B.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/PossessPawns/Blueprints/GHT_4B.KOR.udn @@ -1,10 +1,11 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:블루프린트로 폰 빙의 Crumbs: %ROOT%, Gameplay, Gameplay/HowTo/PossessPawns Description:블루프린트로 Possess 노드를 사용하여 다수의 캐릭터를 제어하고 전환하는 법에 대한 설명입니다. Version: 4.8 SkillLevel: Intermediate +type:how-to Related: Engine/Blueprints Related: Gameplay/Framework/Pawn Related: Gameplay/Framework/Pawn/Character diff --git a/Engine/Documentation/Source/Gameplay/HowTo/PossessPawns/GHT_4_Overview.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/PossessPawns/GHT_4_Overview.INT.udn index 1169bbb17533..e4fc447fbbc3 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/PossessPawns/GHT_4_Overview.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/PossessPawns/GHT_4_Overview.INT.udn @@ -4,7 +4,8 @@ Crumbs: %ROOT%, Gameplay Description:A How To Guide for possessing different pawns in Unreal Engine 4. Version: 4.9 Parent:Gameplay -type:how-to +SkillLevel: Intermediate +type:overview order:3 If you want to switch between multiple Playable Characters in your game or you have a situation where you want a Character to enter and control a Vehicle (car, plane, tank, etc.) or other Pawn that has unique controls (like a mounted machine gun a player can control), you will want to take Possession of the Character or Pawn in order to pass input information to it. @@ -13,16 +14,9 @@ The **PlayerController** is what is responsible for directing a Pawn and Possess The link below in the Setup section will give you examples on Pawn Possession using Blueprints. -## Setup +## Implementation Guides -To learn more about Possessing Pawns using Blueprints, follow the link below: - -[REGION:buttonlist] -* [](Gameplay\HowTo\PossessPawns\Blueprints) -[PUBLISH:Docs] -* [](Gameplay\HowTo\PossessPawns\Code) -[/PUBLISH:Docs] -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/PossessPawns" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/PossessPawns/GHT_4_Overview.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/PossessPawns/GHT_4_Overview.JPN.udn index 4c4da214f81e..6e0fa9e96b5a 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/PossessPawns/GHT_4_Overview.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/PossessPawns/GHT_4_Overview.JPN.udn @@ -1,29 +1,23 @@ -INTSourceChangelist:2735882 +INTSourceChangelist:3429254 Availability:Public Title:ポーンを所有する Crumbs: %ROOT%, Gameplay Description:UE4 で様々なポーンを所有するための操作ガイド Version:4.9 Parent:Gameplay -type:how-to +SkillLevel:Intermediate +type:overview order:3 ゲーム内で複数のプレイ可能なキャラクター間で切り替えたり、キャラクターがビークルに入り、ビークル (車、飛行機、タンクなど) を制御する、または固有のコントロールを持つ他のポーン (プレイヤーが制御可能な装着されたマシンガンなど) を制御する状況など、入力情報を伝えるためにキャラクターやポーンを所有します。 **プレイヤー コントローラ** は、ポーンに指示を出すものであり、ポーンの所有には、プレイヤー コントローラを指定する必要があります。ポーン自体は人間の形をしたキャラクターである必要はありません。基本的な動きを適用し、プレイヤーが制御できるものであれば何でもかまいません。一方、キャラクターは、コリジョンを含み、人間のような基本的な動きを可能にする CharacterMovement コンポーネントをデフォルトで含むポーンの一形態です。 -以下のセットアップ セクションにあるリンクは、ブループリントを使用したポーン所有の例を示します。 +以下のリンク先のSetup セクションでは、ブループリントを使用したポーン所有の例を説明しています。 -## セットアップ +## 実装ガイド -ブループリントを使ったポーン所有については、以下を参照してください。 - -[REGION:buttonlist] -* [](Gameplay\HowTo\PossessPawns\Blueprints) - -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/PossessPawns" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/PossessPawns/GHT_4_Overview.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/PossessPawns/GHT_4_Overview.KOR.udn index 7e0e41e91cfd..cf07e5b1d40a 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/PossessPawns/GHT_4_Overview.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/PossessPawns/GHT_4_Overview.KOR.udn @@ -1,11 +1,12 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:폰 빙의 Crumbs: %ROOT%, Gameplay Description:언리얼 엔진 4 에서 다양한 폰을 빙의하는 비법 안내입니다. Version: 4.9 Parent:Gameplay -type:how-to +SkillLevel: Intermediate +type:overview order:3 게임의 여러 플레이가능 캐릭터를 전환하거나, 캐릭터가 (차량, 비행기, 탱크 등의) 비히클에 탑승하도록 하거나, 별도로 제어되는 다른 폰(플레이어가 제어할 수 있는 일체형 기관총같은 것)을 제어하도록 하려는 경우, 거기에 입력 정보를 전달하기 위해서는 그 **캐릭터** 또는 **폰** 을 **빙의** (Possess)하는 것이 좋을 것입니다. @@ -14,16 +15,9 @@ order:3 아래 **구성** 부분의 링크를 통해 블루프린트를 사용한 **폰 빙의** 예제를 참고할 수 있습니다. -## 구성 +## 구현 안내 -블루프린트를 사용한 **폰 빙의** 관련 상세 정보는, 아래 링크를 참고하세요: - -[REGION:buttonlist] -* [](Gameplay\HowTo\PossessPawns\Blueprints) -[PUBLISH:Docs] -* [](Gameplay\HowTo\PossessPawns\Code) -[/PUBLISH:Docs] -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/PossessPawns" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/ReferenceAssets/Blueprints/GHT_5B.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/ReferenceAssets/Blueprints/GHT_5B.INT.udn index 1040ab4a511f..122bf2b667cb 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/ReferenceAssets/Blueprints/GHT_5B.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/ReferenceAssets/Blueprints/GHT_5B.INT.udn @@ -4,6 +4,7 @@ Crumbs: %ROOT%, Gameplay, Gameplay/HowTo/ReferenceAssets Description:A How To Guide for referencing Actors in Blueprints. Version: 4.9 SkillLevel: Advanced +type:how-to [TOC (start:2)] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/ReferenceAssets/Blueprints/GHT_5B.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/ReferenceAssets/Blueprints/GHT_5B.KOR.udn index a7c1fb69d678..01ceda2617c0 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/ReferenceAssets/Blueprints/GHT_5B.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/ReferenceAssets/Blueprints/GHT_5B.KOR.udn @@ -1,10 +1,11 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:블루프린트에서 액터 레퍼런싱 Crumbs: %ROOT%, Gameplay, Gameplay/HowTo/ReferenceAssets Description:블루프린트에서 액터를 레퍼런싱하는 비법 안내서입니다. Version: 4.9 SkillLevel: Advanced +type:how-to [TOC (start:2)] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/ReferenceAssets/GHT_5_Overview.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/ReferenceAssets/GHT_5_Overview.INT.udn index fe43052b09c4..ba63b836fedf 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/ReferenceAssets/GHT_5_Overview.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/ReferenceAssets/GHT_5_Overview.INT.udn @@ -4,7 +4,8 @@ Crumbs: %ROOT%, Gameplay Description:A How To Guide for Referencing Actors in Unreal Engine 4. Version: 4.9 Parent:Gameplay -type:how-to +SkillLevel: Advanced +type:overview order:5 [EXCERPT:ReferenceOverview] @@ -17,16 +18,9 @@ Getting proper reference to an Actor is also important for communication between The link below in the Setup section will give you examples on How to Reference Actors using Blueprints. -## Setup +## Implementation Guides -To learn more about Referencing Actors using Blueprints, follow the link below: - -[REGION:buttonlist] -* [](Gameplay\HowTo\ReferenceAssets\Blueprints) -[PUBLISH:Docs] -* [](Gameplay\HowTo\ReferenceAssets\Code) -[/PUBLISH:Docs] -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/ReferenceAssets" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/ReferenceAssets/GHT_5_Overview.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/ReferenceAssets/GHT_5_Overview.JPN.udn index 03b7de34a764..2a405850eda8 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/ReferenceAssets/GHT_5_Overview.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/ReferenceAssets/GHT_5_Overview.JPN.udn @@ -1,11 +1,12 @@ -INTSourceChangelist:2735882 +INTSourceChangelist:3429254 Availability:Public Title:アクタを参照する Crumbs: %ROOT%, Gameplay Description:UE4 でアクタを参照するための操作ガイド Version:4.9 Parent:Gameplay -type:how-to +SkillLevel:Advanced +type:overview order:5 [EXCERPT:ReferenceOverview] @@ -16,18 +17,11 @@ order:5 アクタへの適切な参照を取得することは、アクタ間のやりとりでも重要です。参照を誤って指定するとやりとりに失敗して望ましくない結果を招くからです。 [/EXCERPT:ReferenceOverview] -[Setup] セクションの下の方にあるリンクで、ブループリントを使用してアクタを参照する方法を紹介しています。 +以下のリンクの [Setup] セクションで、ブループリントを使用してアクタを参照する方法を紹介しています。 -## セットアップ +## 実装ガイド -ブループリントでアクタを参照する方法については、以下を参照してください。 - -[REGION:buttonlist] -* [](Gameplay\HowTo\ReferenceAssets\Blueprints) - -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/ReferenceAssets" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/ReferenceAssets/GHT_5_Overview.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/ReferenceAssets/GHT_5_Overview.KOR.udn index 6d2961b8d91c..41a887492e3f 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/ReferenceAssets/GHT_5_Overview.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/ReferenceAssets/GHT_5_Overview.KOR.udn @@ -1,11 +1,12 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:액터 레퍼런싱 Crumbs: %ROOT%, Gameplay Description:언리얼 엔진 4 에서 액터를 레퍼런싱하는 방법 안내서입니다. Version: 4.9 Parent:Gameplay -type:how-to +SkillLevel: Advanced +type:overview order:5 [EXCERPT:ReferenceOverview] @@ -18,16 +19,9 @@ order:5 아래 **셋업** 부분의 링크에는 블루프린트를 사용한 **액터 레퍼런싱 방법** 에 대한 예제가 있습니다. -## 셋업 +## 구현 안내 -블루프린트를 사용한 **액터 레퍼런싱** 관련 상세 정보는, 다음 링크를 참고하세요: - -[REGION:buttonlist] -* [](Gameplay\HowTo\ReferenceAssets\Blueprints) -[PUBLISH:Docs] -* [](Gameplay\HowTo\ReferenceAssets\Code) -[/PUBLISH:Docs] -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/ReferenceAssets" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/RespawnPlayer/Blueprints/GHT_3B.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/RespawnPlayer/Blueprints/GHT_3B.INT.udn index eeed9963d3c1..65c5cd6f3a28 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/RespawnPlayer/Blueprints/GHT_3B.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/RespawnPlayer/Blueprints/GHT_3B.INT.udn @@ -4,6 +4,7 @@ Crumbs: %ROOT%, Gameplay, Gameplay/HowTo/RespawnPlayer Description:A How To Guide for respawning a player character through Blueprints in Unreal Engine 4. Version: 4.9 SkillLevel: Advanced +type:how-to [TOC (start:2)] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/RespawnPlayer/Blueprints/GHT_3B.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/RespawnPlayer/Blueprints/GHT_3B.JPN.udn index 859ab51ad926..4479201078f0 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/RespawnPlayer/Blueprints/GHT_3B.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/RespawnPlayer/Blueprints/GHT_3B.JPN.udn @@ -1,10 +1,11 @@ -INTSourceChangelist:2697187 +INTSourceChangelist:3429254 Availability:Public Title:ブループリントでプレイヤーをリスポーンするための操作ガイド Crumbs: %ROOT%, Gameplay, Gameplay/HowTo/RespawnPlayer Description:UE4 のブループリントでプレイヤー キャラクターをリスポーンするための操作ガイド Version:4.9 SkillLevel:Advanced +type:how-to [TOC (start:2)] @@ -60,7 +61,7 @@ _以下の手順は、**Blueprint Third Person Template** プロジェクトの ![](GHT3B_6.png) - ノードをメニューに表示するために **Context Sensitive** オプションのチェックを再度入れる必要があるかもしれません。 + ノードをメニューに表示するために **Context Sensitive** を再確認する必要があるかもしれません。 1. このカスタム イベントを **Cast To ThirdPersonCharacter** ノードに接続します。 @@ -72,7 +73,7 @@ _以下の手順は、**Blueprint Third Person Template** プロジェクトの _画像をクリックしてフルサイズで表示_ -1. **コンパイル** し **保存** してから、ブループリントを終了します。 +1. **コンパイル** し **保存** してから、ブループリントを閉じます。 1. **ThirdPersonCharacter** ブループリントを開き、グラフ内で **右クリック** し、**Event Begin Play** ノードを追加します。 diff --git a/Engine/Documentation/Source/Gameplay/HowTo/RespawnPlayer/Blueprints/GHT_3B.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/RespawnPlayer/Blueprints/GHT_3B.KOR.udn index c9f31e4c2cab..45558f96ed6c 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/RespawnPlayer/Blueprints/GHT_3B.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/RespawnPlayer/Blueprints/GHT_3B.KOR.udn @@ -1,10 +1,11 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:블루프린트로 플레이어 리스폰 Crumbs: %ROOT%, Gameplay, Gameplay/HowTo/RespawnPlayer Description:언리얼 엔진 4 에서 블루프린트를 통해 플레이어 캐릭터를 리스폰하는 비법 안내서입니다. Version: 4.9 SkillLevel: Advanced +type:how-to [TOC (start:2)] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/RespawnPlayer/GHT_3_Overview.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/RespawnPlayer/GHT_3_Overview.INT.udn index 0e405f155e8c..c4c5f8d8568b 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/RespawnPlayer/GHT_3_Overview.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/RespawnPlayer/GHT_3_Overview.INT.udn @@ -4,22 +4,15 @@ Crumbs: %ROOT%, Gameplay Description:A How To Guide for respawning player characters in Unreal Engine 4. Version: 4.9 Parent:Gameplay -type:how-to +SkillLevel: Advanced +type:overview order:2 In most games, there comes a time when the player character is killed and you want to respawn them in the world. In this How To guide, you will learn how to set up a simple respawn system for single player purposes. -## Setup - -To learn more about Respawning a Player using Blueprints, follow the link below: - -[REGION:buttonlist] -* [](Gameplay\HowTo\RespawnPlayer\Blueprints) -[PUBLISH:Docs] -* [](Gameplay\HowTo\RespawnPlayer\Code) -[/PUBLISH:Docs] -[/REGION] +## Implementation Guides +[DIR(output:"role" parent:"Gameplay/HowTo/RespawnPlayer" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/RespawnPlayer/GHT_3_Overview.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/RespawnPlayer/GHT_3_Overview.JPN.udn index c9db32d17c0d..3c53805e7530 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/RespawnPlayer/GHT_3_Overview.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/RespawnPlayer/GHT_3_Overview.JPN.udn @@ -1,25 +1,19 @@ -INTSourceChangelist:2735872 +INTSourceChangelist:3429254 Availability:Public -Title:プレイヤーを再スポーンするための操作ガイド +Title:プレイヤーを再スポーンする Crumbs: %ROOT%, Gameplay Description:UE4 でプレイヤー キャラクターを再スポーンするための操作ガイド +Version:4.9 +Parent:Gameplay +SkillLevel:Advanced +type:overview +order:2 +ほとんどのゲームでは、プレイヤー キャラクターがキルされ、ワールドに再スポーンするときがやってきます。この操作ガイドでは、シングル プレイヤー用途での簡単な再スポーン システムのセットアップ方法について説明します。 -## 概要 - -ほとんどのゲームでは、プレイヤー キャラクターがキルされ、ワールドに再スポーンするときがやってきます。この **操作ガイド** では、シングル プレイヤー用途での簡単な再スポーン システムのセットアップ方法について説明します。 - -## セットアップ - -ブループリントを使った **プレイヤーの再スポーン** については、以下をご覧ください。 - -[REGION:buttonlist] -* [](Gameplay\HowTo\RespawnPlayer\Blueprints) - -[/REGION] +## 実装ガイド +[DIR(output:"role" parent:"Gameplay/HowTo/RespawnPlayer" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/RespawnPlayer/GHT_3_Overview.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/RespawnPlayer/GHT_3_Overview.KOR.udn index 685cc2a9a795..56e7044294c7 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/RespawnPlayer/GHT_3_Overview.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/RespawnPlayer/GHT_3_Overview.KOR.udn @@ -1,26 +1,19 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:플레이어 리스폰 Crumbs: %ROOT%, Gameplay Description:언리얼 엔진 4 에서 플레이어 캐릭터를 리스폰하는 비법 안내입니다. Version: 4.9 Parent:Gameplay -type:how-to +SkillLevel: Advanced +type:overview order:2 대부분의 게임에서, 캐릭터가 죽고 월드에 리스폰시켜야 하는 때가 옵니다. 이 **비법** 안내에서는 싱글 플레이어용 간단한 리스폰 시스템을 구성하는 법을 배워보도록 하겠습니다. -## 구성 - -블루프린트를 사용한 **플레이어 리스폰** 관련 상세 정보는, 아래 링크를 참고하세요: - -[REGION:buttonlist] -* [](Gameplay\HowTo\RespawnPlayer\Blueprints) -[PUBLISH:Docs] -* [](Gameplay\HowTo\RespawnPlayer\Code) -[/PUBLISH:Docs] -[/REGION] +## 구현 안내 +[DIR(output:"role" parent:"Gameplay/HowTo/RespawnPlayer" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/SetUpInput/Blueprints/SetInput_BP.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/SetUpInput/Blueprints/SetInput_BP.INT.udn index d1aa3cfb3a87..ef6dffa6b8fe 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/SetUpInput/Blueprints/SetInput_BP.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/SetUpInput/Blueprints/SetInput_BP.INT.udn @@ -4,6 +4,7 @@ Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\SetUpInput Description:A How To Guide for Setting Up Inputs in Blueprints. Version: 4.9 SkillLevel: Intermediate +type:how-to [TOC (start:2 end:2)] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/SetUpInput/Blueprints/SetInput_BP.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/SetUpInput/Blueprints/SetInput_BP.JPN.udn index 2f770bd215b9..748f9427c36e 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/SetUpInput/Blueprints/SetInput_BP.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/SetUpInput/Blueprints/SetInput_BP.JPN.udn @@ -1,10 +1,11 @@ -INTSourceChangelist:2747903 +INTSourceChangelist:3429254 Availability:Public Title:ブループリントで入力をセットアップする操作手順 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\SetUpInput Description:ブループリントで入力をセットアップする操作手順 Version:4.9 SkillLevel:Intermediate +type:how-to [TOC (start:2 end:2)] @@ -43,8 +44,8 @@ _この例では、**Starter Content** を有効にした状態で **Blank** プ [REGION:raw] ![](Input2_3.png) [/REGION] - [REGION:note] + この **Spring Arm** コンポーネントは、子を親から固定距離に保とうとしますが、コリジョンがあると収縮し、コリジョンがないと戻ります。この場合の子は **カメラ** であり、サードパーソンの視点を持つようにします。 [/REGION] @@ -70,7 +71,7 @@ _この例では、**Starter Content** を有効にした状態で **Blank** プ ![](Input_6.png) -1. **コンパイル** し **保存** してから、ブループリントを閉じます。 +1. **コンパイル** し **保存** してから、ブループリントを閉じます。 ### ゲームモードを作成して単純なキャラクターを使用する @@ -88,17 +89,17 @@ _この例では、**Starter Content** を有効にした状態で **Blank** プ ![](Input2_9.png) -1. **コンパイル** し **保存** してから、ブループリントを閉じます。 +1. **コンパイル** し **保存** してから、ブループリントを閉じます。 -1. メインエディタ ウィンドウで、メニューバーから **[編集]** ボタンをクリックして **[Project Settings]** を選択します。 +1. メイン エディタ ウィンドウで、メニューバーから **[Edit (編集)]** ボタンをクリックして **[Project Settings]** を選択します。 ![](Input2_10.png) - プロジェクトに対して新規作成した **GameMode** を使用するように設定します。 + この新規作成した **GameMode** を使用するようにプロジェクトに対して指示します。 1. **[Project Settings]** で、**[Maps & Modes]** オプションをクリックします。 -1. **Maps & Modes** の **Default Modes** で、**Default GameMode** のドロップダウンをクリックして、**GameMode** を選択します。 +1. **[Maps & Modes]** の **[Default Modes]** で、**[Default GameMode]** のドロップダウンをクリックして、**GameMode** を選択します。 ![](Input2_11.png) @@ -119,8 +120,8 @@ _この例では、**Starter Content** を有効にした状態で **Blank** プ ここでは、各マッピングに名前を付け、そのマッピングに対する入力を割り当てます。**Scale** としてハイライトされている **スケール** 値を **-1.0** に設定するようにします。これは軸の値を合計するときにキーの値の乗数として機能します (逆方向にすることができます)。 + ## ブループリントでアクション / 軸のマッピングを実装する -## ブループリントでアクション / 軸のマッピングを実装する **Project Settings** で入力を作成すると、こうした入力を **ブループリント** 内から呼び出すことができます。このセクションでは単純なキャラクター (または独自のキャラクターを使用する場合はそのキャラクター) の入力設定を実装します。 @@ -170,7 +171,7 @@ _この例では、**Starter Content** を有効にした状態で **Blank** プ ![](Input2_21.png) -1. **Make Rot** ノードで **右クリック** して、**Break link to Break Rot (Yaw)** を選択します。 +1. **Make Rot** ノード上で **右クリック** して、**[Break link to Break Rot (Yaw)]** を選択します。 ![](Input2_22.png) @@ -188,7 +189,7 @@ _この例では、**Starter Content** を有効にした状態で **Blank** プ _シーケンスは上の画面のようになります。_ -1. **コンパイル** し **保存** してから、ブループリントを終了します。 +1. **コンパイル** し **保存** してから、ブループリントを終了します 1. エディタで再生します。 diff --git a/Engine/Documentation/Source/Gameplay/HowTo/SetUpInput/Blueprints/SetInput_BP.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/SetUpInput/Blueprints/SetInput_BP.KOR.udn index e97878e5be25..8e4042a69d54 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/SetUpInput/Blueprints/SetInput_BP.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/SetUpInput/Blueprints/SetInput_BP.KOR.udn @@ -1,10 +1,11 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:블루프린트 입력 구성 비법 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\SetUpInput Description:블루프린트에 입력을 구성하는 비법 안내입니다. Version: 4.9 SkillLevel: Intermediate +type:how-to [TOC (start:2 end:2)] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/SetUpInput/SetUpInputOverview.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/SetUpInput/SetUpInputOverview.INT.udn index fb1eae5b721f..7ebc1635ddbf 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/SetUpInput/SetUpInputOverview.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/SetUpInput/SetUpInputOverview.INT.udn @@ -4,7 +4,8 @@ Crumbs: %ROOT%, Gameplay Description:A How To Guide for Setting Up Inputs in Unreal Engine 4. Version: 4.9 Parent:Gameplay -type:how-to +SkillLevel: Intermediate +type:overview order:8 @@ -12,16 +13,9 @@ After you have imported or created your Character, Vehicle, or Flying Spaceship Once you have defined your Mappings, you can then bind them to behaviors in Blueprints or C++ (see the Setup section below). -## Setup +## Implementation Guides -To learn more about Setting Up Input using Blueprints, follow the link below: - -[REGION:buttonlist] -* [](Gameplay\HowTo\SetUpInput\Blueprints) -[PUBLISH:Docs] -* [](Gameplay\HowTo\SetUpInput\Code) -[/PUBLISH:Docs] -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/SetUpInput" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/SetUpInput/SetUpInputOverview.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/SetUpInput/SetUpInputOverview.JPN.udn index e8b323dca92f..fd8da7a60a04 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/SetUpInput/SetUpInputOverview.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/SetUpInput/SetUpInputOverview.JPN.udn @@ -1,28 +1,22 @@ -INTSourceChangelist:2735882 +INTSourceChangelist:3429254 Availability:Public Title:入力の設定 Crumbs: %ROOT%, Gameplay Description:UE4 で入力をセットアップする操作手順 Version:4.9 Parent:Gameplay -type:how-to +SkillLevel:Intermediate +type:overview order:8 -キャラクター、ビークル、宇宙船のアセットをインポートまたは作成したら、プレイヤーの入力にどのように反応するかを定義する必要があります。入力の定義は主にユーザー定義の **アクション マッピング** (キーの押下と解放用) と **軸マッピング** (連続範囲を持つ入力用) のバインディングで行われます。 +Character、 Vehicle、または Flying Spaceship のアセットをインポートまたは作成したら、プレイヤーの入力にどのように反応するかを定義する必要があります。入力の定義は主にユーザー定義の **アクション マッピング** (キーの押下と解放用) と **軸マッピング** (連続範囲を持つ入力用) のバインディングで行われます。 マッピングを定義したら、それらをブループリントまたは C++ のビヘイビアにバインドできます (以下のセットアップ セクションを参照)。 -## セットアップ +## 実装ガイド -ブループリントを使用した入力を設定する方法については、以下のリンクをご覧ください。 - -[REGION:buttonlist] -* [](Gameplay\HowTo\SetUpInput\Blueprints) - -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/SetUpInput" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/SetUpInput/SetUpInputOverview.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/SetUpInput/SetUpInputOverview.KOR.udn index 3fc40dd6ca1a..4db85bd10324 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/SetUpInput/SetUpInputOverview.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/SetUpInput/SetUpInputOverview.KOR.udn @@ -1,11 +1,12 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:입력 구성 Crumbs: %ROOT%, Gameplay Description:언리얼 엔진 4 에서 입력을 구성하는 비법 안내서입니다. Version: 4.9 Parent:Gameplay -type:how-to +SkillLevel: Intermediate +type:overview order:8 @@ -13,16 +14,9 @@ order:8 **매핑** 정의 이후에는 그 작동방식을 블루프린트나 C++ 에서 바인딩하면 됩니다 (아래 **구성** 부분 참고). -## 구성 +## 구현 안내 -블루프린트를 사용한 **입력 구성** 방법에 대해 자세히 알아보려면, 아래 링크를 참고하세요: - -[REGION:buttonlist] -* [](Gameplay\HowTo\SetUpInput\Blueprints) -[PUBLISH:Docs] -* [](Gameplay\HowTo\SetUpInput\Code) -[/PUBLISH:Docs] -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/SetUpInput" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/SettingUpAGameMode/Blueprints/GameMode_BP.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/SettingUpAGameMode/Blueprints/GameMode_BP.INT.udn index 5a26317c4146..a9ba69cdba92 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/SettingUpAGameMode/Blueprints/GameMode_BP.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/SettingUpAGameMode/Blueprints/GameMode_BP.INT.udn @@ -4,6 +4,7 @@ Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\SettingUpAGameMode Description:A How To Guide for Setting Up a Game Mode in Blueprints. Version: 4.14 SkillLevel: Advanced +type:how-to [TOC (start:2 end:2)] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/SettingUpAGameMode/Blueprints/GameMode_BP.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/SettingUpAGameMode/Blueprints/GameMode_BP.JPN.udn index fb1476451a28..387508efa010 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/SettingUpAGameMode/Blueprints/GameMode_BP.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/SettingUpAGameMode/Blueprints/GameMode_BP.JPN.udn @@ -1,10 +1,11 @@ -INTSourceChangelist:2697210 +INTSourceChangelist:3429254 Availability:Public Title:ブループリントでゲームモードをセットアップする操作手順 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\SettingUpAGameMode Description:ブループリントでゲームモードをセットアップする操作手順 -Version:4.9 +Version:4.14 SkillLevel:Advanced +type:how-to [TOC (start:2 end:2)] @@ -18,13 +19,13 @@ _以下の例では、**Blueprint Third Person Template** を使用しますが [INCLUDE:Engine/Blueprints/UserGuide/Types/ClassBlueprint/Creation#CreateBP1] -**[Pick Parent Class]** ウィンドウで、**Game Mode** クラスを選択します。 +**[Pick Parent Class]** ウィンドウで、**Game Mode Base** クラスを選択します。これは Game Mode の親クラスです。 ## Game Mode のデフォルトを編集する 1. Game Mode のデフォルトを開くには、そのブループリント上で **ダブル クリック** して **Class Defaults (クラスのデフォルト)** ![](Engine\Blueprints\UserGuide\Variables\classDefaults_button.png) ボタンをクリックし、**[詳細]** パネルでブループリント デフォルトを開きます。 -1. **ゲーム モード** には、ゲームのデフォルト設定として使用可能ないくつかのオプションがあります (デフォルトのキャラクター、HUD など)。 +1. **Game Mode** には、ゲームのデフォルト設定として使用可能ないくつかのオプションがあります (デフォルトのキャラクター、HUD など)。 ![](GameMode_5.png) @@ -53,7 +54,7 @@ _以下の例では、**Blueprint Third Person Template** を使用しますが これで、プロジェクトが読み込まれるたびに選択した **GameMode** が、**Default Game Mode** として割り当てられます。 -1. **Selected GameMode** の隣にある矢印をクリックすると、割り当てられた **GameMode** で使用する現在の設定が表示されます。 +1. **Selected GameMode** の隣にある矢印をクリックすると、割り当てられた **GameMode** が使用する現在の設定を見ることができます。 ![](GameMode_9.png) diff --git a/Engine/Documentation/Source/Gameplay/HowTo/SettingUpAGameMode/Blueprints/GameMode_BP.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/SettingUpAGameMode/Blueprints/GameMode_BP.KOR.udn index 64e2e519d984..aa796c126414 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/SettingUpAGameMode/Blueprints/GameMode_BP.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/SettingUpAGameMode/Blueprints/GameMode_BP.KOR.udn @@ -1,10 +1,11 @@ -INTSourceChangelist:3151861 +INTSourceChangelist:3429254 Availability: Public Title:블루프린트로 게임 모드 구성 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\SettingUpAGameMode Description:블루프린트로 게임 모드를 구성하는 비법 안내서입니다. Version: 4.14 SkillLevel: Advanced +type:how-to [TOC (start:2 end:2)] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/SettingUpAGameMode/GameModeOverview.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/SettingUpAGameMode/GameModeOverview.INT.udn index 851ea9a0b710..e77d8c488ae0 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/SettingUpAGameMode/GameModeOverview.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/SettingUpAGameMode/GameModeOverview.INT.udn @@ -4,24 +4,17 @@ Crumbs: %ROOT%, Gameplay Description:A How To Guide for Setting Up a Game Mode in Unreal Engine 4. Version: 4.9 Parent:Gameplay -type:how-to +SkillLevel: Advanced +type:overview order:7 The **GameMode** defines the game's set of rules. The rules can include how players join the game, game pausing, and level transition, as well as any game-specific behavior such as win conditions. The GameMode is set for each level, and GameModes can be reused in multiple levels. The link below in the Setup section will give you examples on How to Set Up a Game Mode using Blueprints. -## Setup - -To learn more about Setting Up a Game Mode using Blueprints, follow the link below: - -[REGION:buttonlist] -* [](Gameplay\HowTo\SettingUpAGameMode\Blueprints) -[PUBLISH:Docs] -* [](Gameplay\HowTo\SettingUpAGameMode\Code) -[/PUBLISH:Docs] -[/REGION] +## Implementation Guides +[DIR(output:"role" parent:"Gameplay/HowTo/SettingUpAGameMode" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/SettingUpAGameMode/GameModeOverview.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/SettingUpAGameMode/GameModeOverview.JPN.udn index a98d5fb299a3..2d1c80b119b3 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/SettingUpAGameMode/GameModeOverview.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/SettingUpAGameMode/GameModeOverview.JPN.udn @@ -1,28 +1,21 @@ -INTSourceChangelist:2735882 +INTSourceChangelist:3429254 Availability:Public Title:ゲームモードをセットアップする Crumbs: %ROOT%, Gameplay Description:UE4 でゲームモードをセットアップする操作手順 Version:4.9 Parent:Gameplay -type:how-to +SkillLevel:Advanced +type:overview order:7 **GameMode** は、ゲームのルール セットを定義します。このルールには、プレイヤーがどのようにゲームに参加するか、ゲームの一時停止、レベルの移行、および勝利条件などのゲーム固有の動作が含まれます。ゲーム モードは、各レベルに対して設定され、複数レベルで再利用できます。 以下のセットアップ セクションにあるリンク先では、ブループリントを使用したゲームモードのセットアップ方法の例を示します。 -## セットアップ - -ブループリントを使用したゲームモードの設定方法については、以下のリンクをご覧ください。 - -[REGION:buttonlist] -* [](Gameplay\HowTo\SettingUpAGameMode\Blueprints) - -[/REGION] +## 実装ガイド +[DIR(output:"role" parent:"Gameplay/HowTo/SettingUpAGameMode" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/SettingUpAGameMode/GameModeOverview.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/SettingUpAGameMode/GameModeOverview.KOR.udn index 2c43d6d5bc00..a4c9eb826d41 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/SettingUpAGameMode/GameModeOverview.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/SettingUpAGameMode/GameModeOverview.KOR.udn @@ -1,28 +1,21 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:게임 모드 구성 Crumbs: %ROOT%, Gameplay Description:언리얼 엔진 4 에서 게임 모드를 구성하는 비법 안내서입니다. Version: 4.9 Parent:Gameplay -type:how-to +SkillLevel: Advanced +type:overview order:7 **GameMode** (게임 모드)는 게임의 규칙 세트를 정의합니다. 그 규칙에는 플레이어의 게임 참가, 게임 일시정지, 레벨 전환 방식은 물론, 승리 조건과 같은 게임 전용 작동방식이 포함됩니다. GameMode 는 각 레벨별로 설정되며, 다수의 레벨에서 재사용 가능합니다. 아래 **구성** 부분의 링크를 통해 블루프린트를 사용해서 **게임 모드 구성 비법** 예제를 살펴볼 수 있습니다. -## 구성 - -블루프린트를 사용한 **게임 모드 구성** 방법 관련 상세 정보는, 아래 링크를 참고하세요: - -[REGION:buttonlist] -* [](Gameplay\HowTo\SettingUpAGameMode\Blueprints) -[PUBLISH:Docs] -* [](Gameplay\HowTo\SettingUpAGameMode\Code) -[/PUBLISH:Docs] -[/REGION] +## 구현 안내 +[DIR(output:"role" parent:"Gameplay/HowTo/SettingUpAGameMode" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/SpawnAndDestroyActors/Blueprints/GHT_1B.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/SpawnAndDestroyActors/Blueprints/GHT_1B.INT.udn index 794340f775df..e2cdbfd7ac7a 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/SpawnAndDestroyActors/Blueprints/GHT_1B.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/SpawnAndDestroyActors/Blueprints/GHT_1B.INT.udn @@ -4,6 +4,7 @@ Crumbs: %ROOT%, Gameplay, Gameplay/HowTo/SpawnAndDestroyActors Description:A How To Guide for Spawning/Destroying Actors through Blueprints in Unreal Engine 4. Version: 4.9 SkillLevel:Intermediate +type:how-to [TOC (start:2)] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/SpawnAndDestroyActors/Blueprints/GHT_1B.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/SpawnAndDestroyActors/Blueprints/GHT_1B.JPN.udn index 1759bd576ffa..830477bce4d1 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/SpawnAndDestroyActors/Blueprints/GHT_1B.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/SpawnAndDestroyActors/Blueprints/GHT_1B.JPN.udn @@ -1,10 +1,11 @@ -INTSourceChangelist:2705356 +INTSourceChangelist:3429254 Availability:Public Title:ブループリントでアクタをスポーン/ 破壊する方法 Crumbs: %ROOT%, Gameplay, Gameplay/HowTo/SpawnAndDestroyActors Description:UE4 のブループリントでアクタをスポーン / 破壊するための操作ガイド Version:4.9 SkillLevel:Intermediate +type:how-to [TOC (start:2)] @@ -172,6 +173,7 @@ Transform を手動で設定する方法およびアクタの Transform を参 Level ブループリントでスポーンされたアクタを破壊するには、以下の操作を行います。 1. エディタ内で任意のプロジェクトを一旦開き、 **[ブループリント]** ボタンと **Open Level Blueprint** をクリックします。 + [REGION:raw] ![](GHT1_1.png) [/REGION] @@ -208,7 +210,7 @@ Level ブループリントでスポーンされたアクタを破壊するに SpawnActor ノードを実行してアクタをスポーンすると、必要に応じたイベントの種類でアクタの破壊がトリガーされます。 -ブループリントを使った作業の詳細については、 [](Engine/Blueprints/UserGuide) を参照してください。 +ブループリント を使った作業の詳細については、 [](Engine/Blueprints/UserGuide) を参照してください。 diff --git a/Engine/Documentation/Source/Gameplay/HowTo/SpawnAndDestroyActors/Blueprints/GHT_1B.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/SpawnAndDestroyActors/Blueprints/GHT_1B.KOR.udn index 7cc00a4e1b49..350360310714 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/SpawnAndDestroyActors/Blueprints/GHT_1B.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/SpawnAndDestroyActors/Blueprints/GHT_1B.KOR.udn @@ -1,10 +1,11 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:블루프린트에서 액터 스폰/소멸 Crumbs: %ROOT%, Gameplay, Gameplay/HowTo/SpawnAndDestroyActors Description:언리얼 엔진 4 에서 블루프린트를 통해 액터를 스폰/소멸시키는 법에 대한 비법입니다. Version: 4.9 SkillLevel:Intermediate +type:how-to [TOC (start:2)] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/SpawnAndDestroyActors/GHT_1_Overview.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/SpawnAndDestroyActors/GHT_1_Overview.INT.udn index 115a92707beb..9bf405b76e4a 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/SpawnAndDestroyActors/GHT_1_Overview.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/SpawnAndDestroyActors/GHT_1_Overview.INT.udn @@ -4,22 +4,15 @@ Crumbs: %ROOT%, Gameplay Description:A How To Guide for Spawning Actors in Unreal Engine 4. Version: 4.9 Parent:Gameplay -type:how-to +type:overview order:1 -skilllevel:Beginner +SkillLevel:Intermediate Often times in your game you will find that you want to add items to your levels dynamically during gameplay, this is called Spawning an Actor. Items you want to spawn could be anything from other players or enemies to pick-ups such as Health, Weapons, or Rewards. On this page, you will find information regarding how to spawn an Actor through Blueprints. -## Setup +## Implementation Guides -To learn more about spawning/destroying Actors using Blueprints, follow the link below: - -[REGION:buttonlist] -* [](Gameplay\HowTo\SpawnAndDestroyActors\Blueprints) -[PUBLISH:Docs] -* [](Gameplay\HowTo\SpawnAndDestroyActors\Code) -[/PUBLISH:Docs] -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/SpawnAndDestroyActors" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/SpawnAndDestroyActors/GHT_1_Overview.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/SpawnAndDestroyActors/GHT_1_Overview.JPN.udn index 5106ebe74e7b..042bb250fff3 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/SpawnAndDestroyActors/GHT_1_Overview.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/SpawnAndDestroyActors/GHT_1_Overview.JPN.udn @@ -1,26 +1,19 @@ -INTSourceChangelist:2735872 +INTSourceChangelist:3429254 Availability:Public Title:アクタをスポーン/ 破壊する方法の概要 Crumbs: %ROOT%, Gameplay Description:UE4 でアクタをスポーン / 破壊するための操作ガイド Version:4.9 Parent:Gameplay -type:how-to +type:overview order:1 -skilllevel:Beginner +SkillLevel:Intermediate -ゲームプレイ中にアイテムを動的にレベルに追加したい場合がよくあります。これをアクタをスポーンするといいます。スポーンしたいアイテムは、他のプレイヤーや敵からヘルス値、武器、報酬などのピックアップに至るまで、何でも選ぶことができます。このページでは、ブループリントを使ってアクタをスポーンする方法を説明します。 +ゲームプレイ中にアイテムを動的にレベルに追加する場合がよくあります。これをアクタをスポーンするといいます。スポーンするアイテムは、他のプレイヤーや敵からヘルス値、武器、報酬などのピックアップに至るまで、何でも選ぶことができます。このページでは、ブループリントを使ってアクタをスポーンする方法を説明します。 -## セットアップ +## 実装ガイド -ブループリントで アクタをスポーン / 破壊する方法については、以下のリンクを参照してください。 - -[REGION:buttonlist] -* [](Gameplay\HowTo\SpawnAndDestroyActors\Blueprints) - -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/SpawnAndDestroyActors" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/SpawnAndDestroyActors/GHT_1_Overview.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/SpawnAndDestroyActors/GHT_1_Overview.KOR.udn index 9c86589ee40c..d1c7d2390483 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/SpawnAndDestroyActors/GHT_1_Overview.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/SpawnAndDestroyActors/GHT_1_Overview.KOR.udn @@ -1,26 +1,19 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:액터 스폰/소멸 개요 Crumbs: %ROOT%, Gameplay Description:언리얼 엔진 4 에서 액터를 스폰하는 비법 안내입니다. Version: 4.9 Parent:Gameplay -type:how-to +type:overview order:1 -skilllevel:Beginner +SkillLevel:Intermediate 종종 게임에서 게임플레이 도중 동적으로 레벨에 아이템을 추가시키고 싶을 때가 있습니다. 그런 것을 **액터** 를 **스폰** 시킨다고 합니다. 스폰하고자 하는 아이템은 다른 플레이어나 적에서부터 생명력, 무기, 보상과 같은 픽업이 될 수도 있습니다. 여기서는 **블루프린트** 를 통해 **액터** 를 스폰시키는 법에 대한 정보를 알아보겠습니다. -## 구성 +## 구현 안내 -블루프린트를 사용하여 액터를 스폰/소멸시키는 데 대한 정보는, 다음 링크를 참고하세요: - -[REGION:buttonlist] -* [](Gameplay\HowTo\SpawnAndDestroyActors\Blueprints) -[PUBLISH:Docs] -* [](Gameplay\HowTo\SpawnAndDestroyActors\Code) -[/PUBLISH:Docs] -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/SpawnAndDestroyActors" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/Blueprints/UseOnHit_BP.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/Blueprints/UseOnHit_BP.INT.udn index 9c954a713214..fb61a395c9ec 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/Blueprints/UseOnHit_BP.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/Blueprints/UseOnHit_BP.INT.udn @@ -6,6 +6,8 @@ Related: Engine/Blueprints Related: Engine/Blueprints/UserGuide/Events Related: Engine/Blueprints/UserGuide/CastNodes version: 4.9 +type:how-to +skilllevel:Intermediate On this page we will use the **OnComponentHit** and **Event Hit** [](Engine/Blueprints/UserGuide/Events) to apply damage to and fracture a Destructible Mesh as well as apply an impulse at the hit location to push the destructible, simulating the effects of being hit by a projectile and applying force at the hit location. diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/Blueprints/UseOnHit_BP.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/Blueprints/UseOnHit_BP.JPN.udn index db8263bb898c..24f7ac31e718 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/Blueprints/UseOnHit_BP.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/Blueprints/UseOnHit_BP.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:2711665 +INTSourceChangelist:3429254 Availability:Public Title:ブループリントで OnHit Event を使用する Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\UseOnHit @@ -7,9 +7,11 @@ Related:Engine/Blueprints Related:Engine/Blueprints/UserGuide/Events Related:Engine/Blueprints/UserGuide/CastNodes version:4.9 +type:how-to +skilllevel:Intermediate -このページでは **OnComponentHit** と **Event Hit** [](Engine/Blueprints/UserGuide/Events) を使って被破壊メッシュにダメージを与えて破砕します。また、ヒット位置に推進力を適用し被破壊物をプッシュして、発射物によってヒットされるエフェクトをシミュレーションし、ヒット位置に力を適用します。 +このページでは **OnComponentHit** と **Event Hit** の [](Engine/Blueprints/UserGuide/Events) を使って被破壊メッシュにダメージを与えて破砕します。また、ヒット位置に推進力を適用し被破壊物をプッシュして、発射物によってヒットされるエフェクトをシミュレーションし、ヒット位置に力を適用します。 [REGION:note] このチュートリアルでは **スターター コンテンツ** を有効にした状態で **Blueprint First Person** テンプレートを使用します。 @@ -53,7 +55,7 @@ version:4.9 ![](OnHit7.png) - ここでは **FirstPersonProjectile** という別のブループリントに [](Engine/Blueprints/UserGuide/CastNodes) します。被破壊メッシュをヒットする場合、実際には FirstPersonProjectile ブループリントがヒットするようにします。その場合、スクリプトを追加して、このメッシュを破砕して粉々にすることができます。そうでなければ何も行いません。 + ここでは **FirstPersonProjectile** という別のブループリントに対して [](Engine/Blueprints/UserGuide/CastNodes) を行います。被破壊メッシュをヒットする場合、実際には FirstPersonProjectile ブループリントがヒットするようにします。その場合、スクリプトを追加して、このメッシュを破砕して粉々にすることができます。そうでなければ何も行いません。 1. **Hit** ピンを引き出して、**Break Hit Result** ノードを追加します。 @@ -75,11 +77,11 @@ version:4.9 ノードをすべて接続すると、上のようなグラフになります。 -1. **コンパイル** し **保存** してから、ブループリントを閉じます。 +1. **コンパイル** し **保存** してから、ブループリントを終了します 1. **コンテンツ ブラウザ** からこのブループリントをレベルにドラッグします。 - ![](OnHit1.png) + ![](OnHit11.png) 1. エディタで再生するには、**Play** を押して、キューブで発射物を発射するには **左マウス** ボタンを使用します。 @@ -102,7 +104,7 @@ version:4.9 [REGION:lightbox] [![](OnHit12.png)](OnHit12.png) [/REGION] - _拡大表示するにはここをクリック_ + _拡大表示するにはここをクリック_ このブループリントのスクリプトは、ヒットされる物体が物理をシミュレーションするかをチェックします (ここではキューブのブループリントで true にしました)。物理をシミュレーションする場合、ヒットする位置で推進力を適用します (その量は、黄色のボックス内で定義されます。ここでは 50 に減らしました)。この値を調整して、ヒットが発生したときに適用される推進力の大きさを増減させることができます。 diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/Blueprints/UseOnHit_BP.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/Blueprints/UseOnHit_BP.KOR.udn index 3b7eaea1c122..1e85226d40ed 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/Blueprints/UseOnHit_BP.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/Blueprints/UseOnHit_BP.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:블루프린트에서 OnHit 이벤트 사용 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\UseOnHit @@ -7,6 +7,8 @@ Related: Engine/Blueprints Related: Engine/Blueprints/UserGuide/Events Related: Engine/Blueprints/UserGuide/CastNodes version: 4.9 +type:how-to +skilllevel:Intermediate 이 글에서는 **OnComponentHit** 와 **Event Hit** [이벤트](Engine/Blueprints/UserGuide/Events) 를 사용하여 대미지를 적용하고 디스트럭터블 메시를 부수고 적중 위치에 충격을 가해 디스트럭터블을 밀어내도록 하여, 발사체에 맞아 적중 위치에 힘을 가하는 효과를 시뮬레이션해 보겠습니다. diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/Code/UseOnHit_Code.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/Code/UseOnHit_Code.JPN.udn index a82b0f528709..0d3e57e70133 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/Code/UseOnHit_Code.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/Code/UseOnHit_Code.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:2395232 +INTSourceChangelist:3429254 Availability:Docs Title:コードでアクタに入力を設定する方法 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\ActorInput @@ -8,11 +8,11 @@ Description:コードでアクタに入力を設定するためのガイド ## 概要 -## アクタ入力を有効にする +## アクタの入力を有効にする -## アクタ入力を無効にする +## アクタの入力を無効にする -## 入力使用を有効 / 無効にする +## 入力の使用を有効/無効にする ### 入力の詳細 diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/Code/UseOnHit_Code.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/Code/UseOnHit_Code.KOR.udn index de4be157f057..9f31cc0326ac 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/Code/UseOnHit_Code.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/Code/UseOnHit_Code.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Docs Title:코드에서 액터에 입력 구성 비법 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\ActorInput diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/UseOnHit.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/UseOnHit.INT.udn index 2a104471f176..ec13bd54a882 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/UseOnHit.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/UseOnHit.INT.udn @@ -4,20 +4,16 @@ Crumbs: %ROOT%, Gameplay Description:A How To Guide to for using the OnHit Event in Blueprints or Code. version: 4.9 Parent:Gameplay -type:how-to +skilllevel:Intermediate +type:overview order:14 If you are creating a game that involves any kind of damage to a player, enemy, or object, chances are you will run into the situation where you need to determine if they were hit by something and if so, who hit them, where the impact point was, or other information regarding the hit detected. The OnHit Event will provide this information and much more when the collision occurs in which you can use the data to drive changes in your game be it affecting health, destroying an object, or other gameplay related actions. -## Setup - -To learn more about using the OnHit Event using Blueprints, follow the link below: - -[REGION:buttonlist] -* [](Gameplay\HowTo\UseOnHit\Blueprints) -[/REGION] +## Implementation Guides +[DIR(output:"role" parent:"Gameplay/HowTo/UseOnHit" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/UseOnHit.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/UseOnHit.JPN.udn index fc3aba9185fb..2b652bbc1e8d 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/UseOnHit.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/UseOnHit.JPN.udn @@ -1,24 +1,20 @@ -INTSourceChangelist:2735882 +INTSourceChangelist:3429254 Availability:Public -Title: OnHit Event を使用する +Title:OnHit Event を使用する Crumbs: %ROOT%, Gameplay Description:ブループリントまたはコードでOnHit Event を使用するための操作ガイド version:4.9 Parent:Gameplay -type:how-to +skilllevel:Intermediate +type:overview order:14 プレイヤー、敵、またはオブジェクトに対し何らかのダメージを与えるゲームを制作中であれば、何かにヒットされるのか、その場合実際何がヒットするのか、衝撃点、または検知されたヒットに関するその他の情報の判断が必要になるかもしれません。OnHit Event はコリジョン発生時にこうした情報を提供します。こうしたデータを使用してヘルスに及ぼす影響、オブジェクトの破壊、またはその他のゲームプレイ関連のアクションなどゲーム進行の変更を操作できます。 -## セットアップ - -ブループリントで OnHit Event を使用する方法については、以下のリンクを参照してください。 - -[REGION:buttonlist] -* [](Gameplay\HowTo\UseOnHit\Blueprints) -[/REGION] +## 実装ガイド +[DIR(output:"role" parent:"Gameplay/HowTo/UseOnHit" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/UseOnHit.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/UseOnHit.KOR.udn index cd58e14504d3..0f79e6541b19 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/UseOnHit.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UseOnHit/UseOnHit.KOR.udn @@ -1,24 +1,20 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:OnHit 이벤트 사용법 Crumbs: %ROOT%, Gameplay Description:블루프린트 또는 코드에서 OnHit 이벤트 사용 비법 안내입니다. version: 4.9 Parent:Gameplay -type:how-to +skilllevel:Intermediate +type:overview order:14 플레이어, 적, 또는 오브젝트에 어떤 유형의 대미지를 입히는 게임을 만드는 경우, 무언가에 맞았는지 결정한 다음 그렇다면 누가 때렸는지, 맞은 지점이 어디인지, 또는 그 타격 관련 기타 정보가 필요한 상황이 있을 수 있습니다. **OnHit** 이벤트로 그 정보가 제공되며, 콜리전 발생시 제공되는 훨씬 더 많은 데이터를 통해 게임에서 생명력 변경, 오브젝트 파괴, 기타 게임플레이 동작 등의 변화를 구동시킬 수 있습니다. -## 구성 - -블루프린트를 사용한 **OnHit Event** 사용법 관련 상세 정보는, 다음 링크를 참고하세요: - -[REGION:buttonlist] -* [](Gameplay\HowTo\UseOnHit\Blueprints) -[/REGION] +## 구현 안내 +[DIR(output:"role" parent:"Gameplay/HowTo/UseOnHit" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UseRaycasts/GHT_2_Overview.CHN.udn b/Engine/Documentation/Source/Gameplay/HowTo/UseRaycasts/GHT_2_Overview.CHN.udn index db6e46149756..4815f3ac2bfc 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UseRaycasts/GHT_2_Overview.CHN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UseRaycasts/GHT_2_Overview.CHN.udn @@ -1,25 +1,25 @@ -INTSourceChangelist:0 -Availability: Public -Title:Using Raycasts (Tracing) +INTSourceChangelist:3146289 +Availability:Public +Title:使用光线投射(追踪) Crumbs: %ROOT%, Gameplay -Description:A How To Guide for using Raycasts (Tracing) for gameplay purposes. -version: 4.9 +Description:将光线投射(追踪)用于游戏性的指南。 +version:4.9 Parent:Gameplay type:how-to order:4 -There may be instances in your game where you want to determine if the player character is looking at something, and if so, alter the game state in some way (for example, highlight something when a player looks at it). Or maybe you want to determine if an enemy can see the player character, and if so, start shooting or engaging them in some way. You can accomplish both scenarios by using Raycasts (or Tracing) to "shoot" out an invisible ray which will detect geometry between two points and if geometry is hit, return what was hit so that you may then do something with it. +游戏中可能存在这样的情况:需要确定玩家角色是否在看着某件物体;如是,则以某种方式调整游戏状态(例如在玩家看着某件物体时将其高亮显示)。或者需要确定敌人是否能看到玩家角色;如是,则开始射击或以其他方式攻击。使用光线投射(或追踪)可实现这两种情况——“发射”一道不可见的光线检测两点之间的几何体;如命中几何体,返回被击中的内容,以便对其进行操作。 -There are several different options available when running a Trace. You can run a Trace to check for collision with any Objects where any Objects hit are returned, or you can run a Trace by Trace Channel where any Objects hit will return hit information only if the Object is set to specifically respond to a specified Trace Channel (which can be set via Collision Settings). +运行追踪时有数个不同的可用选项。您可运行追踪,检查和任意目标发生的碰撞(命中的对象将被返回);或者按追踪通道运行追踪,只有在对象被设为响应特定的追踪通道时(可通过 Collision Settings 进行设置)命中的对象才返回命中信息。 -In addition to running traces by Objects or Trace Channel, you can run your Trace to detect Single hits or Multi hits, where a Single Trace returns only one a singular hit result and a Multi Trace returns multiple hits resulting from the Trace. With Traces, you can also specify the type of ray that is used: a straight line, a box, a capsule, or sphere. +除按对象或追踪通道运行追踪外,您还可运行追踪检测单次命中或多次命中,单次追踪只返回单次命中结果,多次追踪返回追踪造成的多次命中。也可通过追踪指定使用的光线类型:直线、方块、胶囊体或球体。 -## Setup +## 设置 -To learn more about Raycasts using Blueprints , follow the link below: +通过下方链接了解更多使用蓝图的光线追踪。 [REGION:buttonlist] -* [](Gameplay\HowTo\UseRaycasts\Blueprints) +* [](Engine/Physics/Tracing/HowTo) [PUBLISH:Docs] * [](Gameplay\HowTo\UseRaycasts\Code) * [](Gameplay/HowTo/UseRaycasts/UVCoordsFromTrace) diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UseRaycasts/GHT_2_Overview.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/UseRaycasts/GHT_2_Overview.INT.udn index 01e820536edb..bd6adf5b95a5 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UseRaycasts/GHT_2_Overview.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UseRaycasts/GHT_2_Overview.INT.udn @@ -18,7 +18,7 @@ In addition to running traces by Objects or Trace Channel, you can run your Trac To learn more about Raycasts using Blueprints , follow the link below: [REGION:buttonlist] -* [](Gameplay\HowTo\UseRaycasts\Blueprints) +* [](Engine/Physics/Tracing/HowTo) [PUBLISH:Docs] * [](Gameplay\HowTo\UseRaycasts\Code) * [](Gameplay/HowTo/UseRaycasts/UVCoordsFromTrace) diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UseRaycasts/GHT_2_Overview.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/UseRaycasts/GHT_2_Overview.KOR.udn index 711b95c9549b..4dbb984b05d4 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UseRaycasts/GHT_2_Overview.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UseRaycasts/GHT_2_Overview.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3146289 +INTSourceChangelist:3429254 Availability: Public Title:레이캐스트, 트레이스 사용법 Crumbs: %ROOT%, Gameplay @@ -19,7 +19,7 @@ order:4 블루프린트를 사용한 레이캐스트 관련 상세 정보는 다음과 같습니다: [REGION:buttonlist] -* [](Gameplay\HowTo\UseRaycasts\Blueprints) +* [](Engine/Physics/Tracing/HowTo) [PUBLISH:Docs] * [](Gameplay\HowTo\UseRaycasts\Code) * [](Gameplay/HowTo/UseRaycasts/UVCoordsFromTrace) diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UseTimers/Blueprints/UseTimers_BP.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/UseTimers/Blueprints/UseTimers_BP.INT.udn index ac3ecd27a2fa..e4aaee324063 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UseTimers/Blueprints/UseTimers_BP.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UseTimers/Blueprints/UseTimers_BP.INT.udn @@ -3,6 +3,8 @@ Title:Using Timers in Blueprints Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\UseTimers Description:A How To Guide for using timers in Blueprints. version: 4.9 +type:how-to +skilllevel:Intermediate [TOC (start:2 end:2)] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UseTimers/Blueprints/UseTimers_BP.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/UseTimers/Blueprints/UseTimers_BP.JPN.udn index 7fb2e2f2829d..6b2e5cf285a4 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UseTimers/Blueprints/UseTimers_BP.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UseTimers/Blueprints/UseTimers_BP.JPN.udn @@ -1,9 +1,11 @@ -INTSourceChangelist:2713187 +INTSourceChangelist:3429254 Availability:Public Title:ブループリントでタイマーを使用する Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\UseTimers Description:ブループリントでタイマーを使用するための操作ガイド version:4.9 +type:how-to +skilllevel:Intermediate [TOC (start:2 end:2)] @@ -79,7 +81,7 @@ version:4.9 ![](GHT6B_8b.png) -1. **コンパイル** し **保存** してから、ブループリントを閉じます +1. **コンパイル** し **保存** してから、ブループリントを終了します 1. **コンテンツ ブラウザ** で **Blueprint_Effect_Fire** ブループリントをレベルへドラッグします。 diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UseTimers/Blueprints/UseTimers_BP.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/UseTimers/Blueprints/UseTimers_BP.KOR.udn index 761c4574a4fb..b51414e1a3aa 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UseTimers/Blueprints/UseTimers_BP.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UseTimers/Blueprints/UseTimers_BP.KOR.udn @@ -1,9 +1,11 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:블루프린트에서 타이머 사용법 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\UseTimers Description:블루프린트에서 타이머를 사용하는 비법 안내입니다. version: 4.9 +type:how-to +skilllevel:Intermediate [TOC (start:2 end:2)] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UseTimers/UseTimersOverview.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/UseTimers/UseTimersOverview.INT.udn index 3de551e4565f..ba1224c87802 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UseTimers/UseTimersOverview.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UseTimers/UseTimersOverview.INT.udn @@ -4,24 +4,17 @@ Crumbs: %ROOT%, Gameplay Description:A How To Guide for Using Timers for Gameplay in Unreal Engine 4. version: 4.9 Parent:Gameplay -type:how-to +skilllevel:Intermediate +type:overview order:6 **Timers** in Unreal Engine 4 are a useful tool that can be used to perform an action once (or repeatedly) at specified intervals. Timers can be used to set actions to happen on a delay or over a period of time. For example, you may want to make the player invincible after obtaining a certain item and then revert after 10 seconds. Or, you may want to apply damage every second to a player that is standing in fire. Each of these scenarios can be accomplished with the use of Timers. The link below in the Setup section will give you examples on How to Use Timers using Blueprints. -## Setup - -To learn more about Using Timers using Blueprints, follow the link below: - -[REGION:buttonlist] -* [](Gameplay\HowTo\UseTimers\Blueprints) -[PUBLISH:Docs] -* [](Gameplay\HowTo\UseTimers\Code) -[/PUBLISH:Docs] -[/REGION] +## Implementation Guides +[DIR(output:"role" parent:"Gameplay/HowTo/UseTimers" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UseTimers/UseTimersOverview.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/UseTimers/UseTimersOverview.JPN.udn index 0b17aff04354..0f471acca108 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UseTimers/UseTimersOverview.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UseTimers/UseTimersOverview.JPN.udn @@ -1,28 +1,21 @@ -INTSourceChangelist:2735882 +INTSourceChangelist:3429254 Availability:Public Title:タイマーを使用する Crumbs: %ROOT%, Gameplay Description:UE4 でゲームプレイ用のタイマーを使用するための操作ガイド version:4.9 Parent:Gameplay -type:how-to +skilllevel:Intermediate +type:overview order:6 -UE4 の **タイマー** は、指定した間隔で 1 度 (または繰り返し) のアクションを実行することができる便利なツールです。タイマーは、アクションを遅らせて、もしくは所定の期間に渡って発生させる際に使用します。プレイヤーがあるアイテムを取得したその 10 秒後に、無敵キャラクターとなる例が挙げられます。あるいは、火の中に立っているプレイヤーに対して 1 秒ごとにダメージを与える場合もあります。タイマーを使って、これらのシナリオを実現することができます。 +UE4 の **タイマー** は、指定した間隔で 1 度 (または繰り返し) のアクションを実行することができる便利なツールです。タイマーは、アクションを遅らせたり、所定の期間に渡ってアクションを発生させる際に使用します。プレイヤーがあるアイテムを取得したその 10 秒後に、無敵キャラクターとなる例が挙げられます。あるいは、火の中に立っているプレイヤーに対して 1 秒ごとにダメージを与える場合もあります。タイマーを使って、これらのシナリオを実現することができます。 設定セクションの下の方にあるリンクで、ブループリントを使用したタイマーの使用例 を紹介しています。 -## セットアップ - -ブループリントでタイマーを使用する方法については、以下を参照してください。 - -[REGION:buttonlist] -* [](Gameplay\HowTo\UseTimers\Blueprints) - -[/REGION] +## 実装ガイド +[DIR(output:"role" parent:"Gameplay/HowTo/UseTimers" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UseTimers/UseTimersOverview.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/UseTimers/UseTimersOverview.KOR.udn index 71b075202104..aa187609aa9b 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UseTimers/UseTimersOverview.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UseTimers/UseTimersOverview.KOR.udn @@ -1,28 +1,21 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:타이머 사용법 Crumbs: %ROOT%, Gameplay Description:언리얼 엔진 4 에서 게임플레이에 쓰이는 타이머 사용 비법 안내입니다. version: 4.9 Parent:Gameplay -type:how-to +skilllevel:Intermediate +type:overview order:6 언리얼 엔진 4 의 **타이머** 는 일정한 기간에 한 번 (또는 반복해서) 동작을 수행하는 데 사용할 수 있는 유용한 도구입니다. **타이머** 설정해서 일정한 기간이 지나면, 또는 일정 기간에 걸쳐 수행되는 동작을 설정할 수 있습니다. 예를 들어 플레이어가 특정 아이템을 획득하면 무적이 되었다가 10 초가 지나면 원래대로 되돌아오도록 만들 수 있습니다. 아니면 플레이어가 불에 서 있는 동안 매 초마다 대미지를 적용하도록 할 수도 있습니다. 이 각각의 시나리오는 **타이머** 사용을 통해 이뤄낼 수 있습니다. 아래 **구성** 부분의 링크를 통해 블루프린트를 사용한 **타이머 사용 비법** 예제를 확인할 수 있습니다. -## 구성 - -블루프린트를 사용한 **타이머 사용법** 관련 상세 정보는, 다음 링크와 같습니다: - -[REGION:buttonlist] -* [](Gameplay\HowTo\UseTimers\Blueprints) -[PUBLISH:Docs] -* [](Gameplay\HowTo\UseTimers\Code) -[/PUBLISH:Docs] -[/REGION] +## 구현 안내 +[DIR(output:"role" parent:"Gameplay/HowTo/UseTimers" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/Blueprints/UsingCameras_BP.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/Blueprints/UsingCameras_BP.INT.udn index 56c1a23d568b..d4b8690b87b8 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/Blueprints/UsingCameras_BP.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/Blueprints/UsingCameras_BP.INT.udn @@ -8,6 +8,7 @@ Related: Engine/Matinee Related: Engine/Blueprints SkillLevel: Beginner Version: 4.9 +type:how-to In this How-to we take a look at creating a static (or fixed) camera angle that is used for a player's perspective during gameplay. Once completing this tutorial, you can take the process used here and apply it to your own game to set up a fixed perspective for a player to view your game from. diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/Blueprints/UsingCameras_BP.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/Blueprints/UsingCameras_BP.JPN.udn index 3488890ed110..739fcd3e43fc 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/Blueprints/UsingCameras_BP.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/Blueprints/UsingCameras_BP.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:2713275 +INTSourceChangelist:3429254 Availability:Public Title:スタティック カメラの使用 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\UsingCameras @@ -9,8 +9,9 @@ Related:Engine/Matinee Related:Engine/Blueprints SkillLevel:Beginner Version:4.9 +type:how-to -この操作ガイドでは、スタティック (すなわち固定) カメラ のアングルを作成します。このアングルは、ゲームプレイ中のプレイヤーの視点のために使用します。このチュートリアルを終了すると、ここで使用したプロセスを用いて、それをご自身の独自のゲームに適用して、プレイヤーからゲームを見る固定視点をセットアップすることができます。 +この操作ガイドでは、スタティック (すなわち固定) カメラのアングルを作成します。このアングルは、ゲームプレイ中のプレイヤーの視点のために使用します。このチュートリアルを終了すると、ここで使用したプロセスを用いて、それをご自身の独自のゲームに適用して、プレイヤーからゲームを見る固定視点をセットアップすることができます。 [REGION:note] ここでは **スターター コンテンツ** を有効にした状態で **Blueprint Third Person Template** プロジェクトを使います。 diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/Blueprints/UsingCameras_BP.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/Blueprints/UsingCameras_BP.KOR.udn index cf1d0b798906..403853689bcb 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/Blueprints/UsingCameras_BP.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/Blueprints/UsingCameras_BP.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:고정 카메라 사용법 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\UsingCameras @@ -9,6 +9,7 @@ Related: Engine/Matinee Related: Engine/Blueprints SkillLevel: Beginner Version: 4.9 +type:how-to 이번에는 게임플레이 도중 플레이어의 시점에 사용되는 스태틱 (고정) 카메라 앵글을 만드는 법을 살펴보겠습니다. 이 튜토리얼을 마치고나서는, 여기 사용된 프로세스를 가져다가 직접 제작중인 게임에 옮기는 것으로 플레이어에 고정 시야 구성을 해줄 수 있을 것입니다. diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/CameraComponents/CameraComponents_BP.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/CameraComponents/CameraComponents_BP.INT.udn index d86f64bc755a..7601e4a82543 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/CameraComponents/CameraComponents_BP.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/CameraComponents/CameraComponents_BP.INT.udn @@ -9,6 +9,7 @@ Related: Engine/Matinee Related: Engine/Blueprints SkillLevel: Beginner Version: 4.8 +type:how-to In this How-to we take a look at adding a **Camera** Component to a **Blueprint** which can be used to create third person perspectives for playable or non-playable characters in your levels. By the end of this tutorial you will have gone through the process of adding a Camera Component to a Character Blueprint and set up the ability to toggle between two different perspectives for a character. diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/CameraComponents/CameraComponents_BP.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/CameraComponents/CameraComponents_BP.JPN.udn index f35bed9fa770..bf4c29c3a96f 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/CameraComponents/CameraComponents_BP.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/CameraComponents/CameraComponents_BP.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:2615116 +INTSourceChangelist:3429254 Availability:Public Title:Camera コンポーネントの作業 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\UsingCameras @@ -10,6 +10,7 @@ Related:Engine/Matinee Related:Engine/Blueprints SkillLevel:Beginner Version:4.8 +type:how-to この操作ガイドでは、レベル内のプレイ可能な、あるいはプレイ不可能なキャラクターに対してサードパーソン視点を作るために使用する **Camera ** コンポーネントを **ブループリント** に追加する方法を説明します。このチュートリアルの最後まで進むと、Camera コンポーネントを Character ブループリントに追加し、二種類の視点間で切り替える機能をキャラクターに対してセットアップするプロセスを学ぶことになります。 diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/CameraComponents/CameraComponents_BP.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/CameraComponents/CameraComponents_BP.KOR.udn index 7b8b505ae148..b56f37fe4df2 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/CameraComponents/CameraComponents_BP.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/CameraComponents/CameraComponents_BP.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:카메라 컴포넌트 작업 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\UsingCameras @@ -10,6 +10,7 @@ Related: Engine/Matinee Related: Engine/Blueprints SkillLevel: Beginner Version: 4.8 +type:how-to 이번 비법에서는 **블루프린트** 에 **카메라** 컴포넌트를 추가, 삼인칭 캐릭터나 레벨의 플레이 불가 캐릭터의 시야를 만드는 법을 살펴보겠습니다. 이 튜토리얼이 끝날 무렵에는 캐릭터 블루프린트에 카메라 컴포넌트를 추가하는 방법과 캐릭터에 두 가지 시야 토글 기능을 구성하는 법을 살펴보도록 하겠습니다. diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/SpringArmComponents/SpringArm.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/SpringArmComponents/SpringArm.INT.udn index bd3271de63bd..1585c92daf80 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/SpringArmComponents/SpringArm.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/SpringArmComponents/SpringArm.INT.udn @@ -8,6 +8,7 @@ Related: Engine/Matinee Related: Engine/Blueprints SkillLevel: Beginner Version: 4.8 +type:how-to [REGION:warning] You can use your own character for this tutorial provided it has a **Camera** component assigned to it. If you do not have a character, it is recommended that you complete the [](Gameplay\HowTo\UsingCameras\CameraComponents) tutorial in order to create the basic character being used in this guide first. diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/SpringArmComponents/SpringArm.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/SpringArmComponents/SpringArm.JPN.udn index ecd8ca0d13a4..55fc1bf767aa 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/SpringArmComponents/SpringArm.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/SpringArmComponents/SpringArm.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:2617899 +INTSourceChangelist:3429254 Availability:Public Title:Spring Arm コンポーネントを使用する Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\UsingCameras @@ -9,16 +9,17 @@ Related:Engine/Matinee Related:Engine/Blueprints SkillLevel:Beginner Version:4.8 +type:how-to [REGION:warning] このチュートリアルでは **Camera** コンポーネントが割り当てられていることを前提に、皆さんの独自のキャラクターをご利用いただけます。キャラクターの用意がない場合は、まずこのガイドで使われている基本的なキャラクターを作成するために [](Gameplay\HowTo\UsingCameras\CameraComponents) チュートリアルを終わらせることをお勧めします。 [/REGION] -この操作ガイドでは、**Spring Arm** コンポーネントを追加し、それに **Camera** コンポーネントを親子付けし、カメラがゲームプレイの状況に応じて伸縮できるするようにします。通常、サードパーソン視点を作るために Camera コンポーネントをキャラクターに追加する場合も、Spring Arm を含めるようにし、レベルのジオメトリや他の物体によって邪魔される場合に、カメラがどのように状況を処理するかを自動的に制御したいでしょう。 +この操作ガイドでは、**Spring Arm** コンポーネントを追加し、それに **Camera** コンポーネントを親子付けし、カメラがゲームプレイの状況に応じて伸縮できるするようにします。通常、サードパーソン視点を作るために Camera コンポーネントをキャラクターに追加する場合、Spring Arm を含めるようにすると、レベルのジオメトリや他の物体によって邪魔される場合に、カメラがどのように状況を処理するかを自動的に制御することができます。 ![](springArm1.png) -レベル内の物体をカメラが貫通することを防がないことがあるかもしれませんが、Spring Arm の設定に応じて、邪魔されるようになったらカメラの位置を自動的に動かすことでその可能性を減らし、邪魔がなくなったらデフォルトの位置に戻ります。 +レベル内の物体をカメラが貫通することがあるかもしれませんが、Spring Arm の設定に応じて、邪魔があればカメラの位置を自動的に動かすことでその可能性を減らし、邪魔がなくなったらデフォルトの位置に戻ります。 1. [](Gameplay\HowTo\UsingCameras\CameraComponents) の操作から引き続き、 **Character ブループリント** を開きます。 @@ -42,13 +43,13 @@ Version:4.8 | **Camera Settings** | ピッチ (上下動)、ヨー (左右回転)、ロール (進行軸回転) を親から継承するか、 Pawn Control Rotation を使用するかを設定します | | **Lag** | カメラがターゲット位置に遅れるかどうか、およびラグに関連づいた設定です。 | -1. **Target Arm Length** を **100** に設定し、**Enabled Camera lag (カメラ ラグを有効)** にしました。 +1. **[Target Arm Length]** を **100** に設定し、**[Enabled Camera lag (カメラ ラグを有効)]** にしました。 ![](spring3.png) - これでデフォルト設定よりも短くなり、移動するときにカメラに若干のラグを加えます。 + これでデフォルト設定よりも短くなり、移動するときにカメラに若干遅らせます。 -1. **Compile** をクリックし、エディタで再生するには **Play** をクリックします。 +1. **[Compile]** をクリックし、**Play** をクリックしてエディタで再生します。 ## 最終結果 @@ -64,7 +65,7 @@ jjf9P6u052E [/PARAMLITERAL] [/OBJECT] -キャラクターを動かす場合、カメラがキャラクターの動きから若干遅れるのがわかります。壁の近くに移動し、カメラを回転させると、再配置しようとし、近くに移動します。障害物がないと、設定で指定したデフォルトの長さに戻ります。 +キャラクターを動かすと、カメラがキャラクターの動きから若干遅れるのがわかります。壁の近くに移動し、カメラを回転させると、再配置しようとし、近くに移動します。障害物がないと、設定で指定したデフォルトの長さに戻ります。 diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/SpringArmComponents/SpringArm.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/SpringArmComponents/SpringArm.KOR.udn index 2f48b57129b3..e5df303efa48 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/SpringArmComponents/SpringArm.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/SpringArmComponents/SpringArm.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:스프링 암 컴포넌트 사용법 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\UsingCameras @@ -9,6 +9,7 @@ Related: Engine/Matinee Related: Engine/Blueprints SkillLevel: Beginner Version: 4.8 +type:how-to [REGION:warning] 이 튜토리얼에는 **카메라** 컴포넌트가 할당된 것이면 어떤 캐릭터든 사용해도 좋습니다. 캐릭터가 없는 경우, 여기서 사용되는 기본 캐릭터 생성을 위해 [](Gameplay\HowTo\UsingCameras\CameraComponents) 튜토리얼 먼저 떼고 오실 것을 추천합니다. diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/SwitchingCameras/SwitchingCameras_BP.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/SwitchingCameras/SwitchingCameras_BP.INT.udn index 81f3291a21a7..7a95c33eb0fd 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/SwitchingCameras/SwitchingCameras_BP.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/SwitchingCameras/SwitchingCameras_BP.INT.udn @@ -8,6 +8,7 @@ Related: Engine/Matinee Related: Engine/Blueprints SkillLevel: Beginner Version: 4.8 +type:how-to In this How-to we add multiple **Camera** Actors to our level and switch between them as the player enters **Trigger** Volumes that we have placed in the level. After completing this tutorial, you will have the ability to set up your own multi-camera based game and define when each camera is used. diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/SwitchingCameras/SwitchingCameras_BP.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/SwitchingCameras/SwitchingCameras_BP.JPN.udn index acedf479bdee..53eb07c78ce1 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/SwitchingCameras/SwitchingCameras_BP.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/SwitchingCameras/SwitchingCameras_BP.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:2615116 +INTSourceChangelist:3429254 Availability:Public Title:複数の固定カメラ間で切り替える Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\UsingCameras @@ -9,6 +9,7 @@ Related:Engine/Matinee Related:Engine/Blueprints SkillLevel:Beginner Version:4.8 +type:how-to この操作ガイドでは、複数の **Camera** アクタをレベルに追加して、プレイヤーがレベルに配置された **Trigger** ボリュームに入るとアクタ間を切り替えます。このチュートリアルの最後まで進むと、ご自身で複数のカメラを使ったゲームをセットアップして、各カメラをいつ使用するかを定義できるようになります。 @@ -24,7 +25,7 @@ Version:4.8 [/REGION] _拡大表示するにはここをクリック_ - 使用するアングルが異なる 3 台のカメラを配置しました。 + 使用するアングルが異なる 3 台のカメラを配置しました。 1. **[Modes]** メニューの **Basic** で、配置したカメラの番号と一致する **Box Trigger** の番号をドラッグしてきます。 @@ -36,7 +37,7 @@ Version:4.8 カメラの変更をプレイヤーにトリガーさせたい場所へ **Box Trigger** を移動させます。 [REGION:tip] - Box Trigger を選択した状態で、**W** (平行移動モード), **E** (回転モード)、または **R** (スケーリング モード) を押して、アクタを操作して、必要な位置、回転、スケーリングになるようにします。詳細は、 [](GettingStarted/HowTo/ManipulatingActors) を参照してください。 + Box Trigger を選択した状態で、**W** (平行移動モード)、 **E** (回転モード)、または **R** (スケーリング モード) を押して、アクタを操作して、必要な位置、回転、スケーリングになるようにします。詳細は、 [](GettingStarted/HowTo/ManipulatingActors) を参照してください。 [/REGION] 1. それぞれのカメラを選んだ状態で、 **[Blueprints]** ボタンをクリックして **[Open Level Blueprint]** を選びます。 diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/SwitchingCameras/SwitchingCameras_BP.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/SwitchingCameras/SwitchingCameras_BP.KOR.udn index ad5252a7325f..013c28ad8409 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/SwitchingCameras/SwitchingCameras_BP.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/SwitchingCameras/SwitchingCameras_BP.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:여러 카메라 전환 Crumbs: %ROOT%, Gameplay, Gameplay\HowTo\UsingCameras @@ -9,6 +9,7 @@ Related: Engine/Matinee Related: Engine/Blueprints SkillLevel: Beginner Version: 4.8 +type:how-to 이번 비법에서는 레벨에 **카메라** 액터를 다수 추가한 뒤 플레이어가 레벨에 배치된 **Trigger Volume** 에 들어서면 그 카메라 액터를 전환하도록 하겠습니다. 이 튜토리얼을 마치고 나면, 직접 다중 카메라 기반 게임 구성 및 각 카메라 사용 시기를 정의할 수 있을 것입니다. diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/UsingCamerasOverview.INT.udn b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/UsingCamerasOverview.INT.udn index 3c04262dc811..41c8b7a727b1 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/UsingCamerasOverview.INT.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/UsingCamerasOverview.INT.udn @@ -4,7 +4,8 @@ Crumbs: %ROOT%, Gameplay Description:A How To Guide for Finding Actors in your Scenes in Unreal Engine 4. version: 4.9 Parent:Gameplay -type:how-to +skilllevel:Beginner +type:overview order:12 This "How To" series covers working with and placing **Cameras** in Unreal Engine 4. A Camera can be used by itself and placed directly into a level or it can be a part of a Blueprint (for instance to provide a perspective for the player when flying a plane, driving a car, or controlling a character). @@ -60,16 +61,9 @@ For information on using Cameras for cinematic purposes, refer to [](Engine/Mati Now that you have an understanding of how to place a Camera Actor in your level and some of the settings used to alter its look, the examples below provide some ways in which you can use Camera including how to use a Camera as a viewpoint for a player, how to use a Camera Component as part of a Blueprint, how to use a Spring Arm Component with a Camera Component (typically used for creating Third Person perspectives), as well as how to switch between Cameras during gameplay. -## Usage Examples +## Implementation Guides -Refer to each of the links below for step-by-step usage case examples. - -[REGION:buttonlist] -* [](Gameplay\HowTo\UsingCameras\Blueprints) -* [](Gameplay\HowTo\UsingCameras\SwitchingCameras) -* [](Gameplay\HowTo\UsingCameras\CameraComponents) -* [](Gameplay\HowTo\UsingCameras\SpringArmComponents) -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/UsingCameras" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/UsingCamerasOverview.JPN.udn b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/UsingCamerasOverview.JPN.udn index 025d22139060..1192e291d067 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/UsingCamerasOverview.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/UsingCamerasOverview.JPN.udn @@ -1,11 +1,12 @@ -INTSourceChangelist:2735882 +INTSourceChangelist:3429254 Availability:Public Title:カメラを使用する Crumbs: %ROOT%, Gameplay Description:UE4 のシーン内でアクタを見つけるための操作ガイド version:4.9 Parent:Gameplay -type:how-to +skilllevel:Beginner +type:overview order:12 この「How To」シリーズでは、UE4 の **カメラ** の操作および配置について説明します。カメラはそれ自体でも使用できますし、直接レベルに配置したり、ブループリントの一部とすることもできます (例えば、飛行機を飛ばしたり、車を運転したり、キャラクターを制御する時にプレイヤーのために視点を作成します)。 @@ -58,19 +59,12 @@ Camera アクタを探すには、検索バーを使うか、**All Classess** シネマティックス用にカメラを使う場合は、 [](Engine/Matinee/HowTo) ドキュメントと [Camera] セクションを参照してください。[](Resources/Showcases/MatineeFightScene) では、カットシーンのサンプル、それらの構築方法に関する素晴らしいリソースを紹介しています。 [/REGION] -レベル内に Camera アクタ を置く方法、外観を変更する設定に関して学びました。以下の使用例では、プレイヤー視点としてのカメラの使用方法、ブループリントの一部として Camera コンポーネントを使う方法、Camera コンポーネントと合わせて Spring Arm コンポーネントを使う方法 (サードパーソン視点の作成に使用することが多い) 、ゲームプレイ中にカメラ間で切り替える方法など、カメラ操作を学びます。 +レベル内に Camera アクタを置く方法、外観を変更する設定に関して学びました。以下の使用例では、プレイヤー視点としてのカメラの使用方法、ブループリントの一部として Camera コンポーネントを使う方法、Camera コンポーネントと合わせて Spring Arm コンポーネントを使う方法 (サードパーソン視点の作成に使用することが多い) 、ゲームプレイ中にカメラ間で切り替える方法など、カメラ操作を学びます。 -##使用例: +## 実装ガイド -使用例の操作手順については以下の各リンクを参照してください。 - -[REGION:buttonlist] -* [](Gameplay\HowTo\UsingCameras\Blueprints) -* [](Gameplay\HowTo\UsingCameras\SwitchingCameras) -* [](Gameplay\HowTo\UsingCameras\CameraComponents) -* [](Gameplay\HowTo\UsingCameras\CameraComponents) -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/UsingCameras" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/UsingCamerasOverview.KOR.udn b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/UsingCamerasOverview.KOR.udn index 432a2eb7057b..49cd935fa504 100644 --- a/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/UsingCamerasOverview.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/HowTo/UsingCameras/UsingCamerasOverview.KOR.udn @@ -1,11 +1,12 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3429254 Availability: Public Title:카메라 사용법 Crumbs: %ROOT%, Gameplay Description:언리얼 엔진 4 에서 씬에 있는 액터를 찾는 법에 대한 비법입니다. version: 4.9 Parent:Gameplay -type:how-to +skilllevel:Beginner +type:overview order:12 언리얼 엔진 4 의 **카메라** 작업 및 배치 방법에 대해 다루는 "비법" 시리즈입니다. **카메라** 는 레벨에 바로 배치하여 그 자체로 사용할 수고 있고, **블루프린트** 의 일부로 (비행기 조종이나 자동차 운전 및 캐릭터 제어시 플레이어의 시점을 제공해 준다든가 하는 용도로) 사용할 수도 있습니다. @@ -61,16 +62,9 @@ order:12 레벨에 **카메라 액터** 를 배치하는 법과 그 모양을 변경하는 법이 약간 이해가 되셨을 테니, 아래 **셋업** 섹션으로 가서 카메라 작업 방법 및 카메라를 플레이어 시점으로 활용하는 법, **블루프린트** 의 일부로써 **카메라 컴포넌트** 를 사용하는 법, (전형적으로 삼인칭 시점 제작에 쓰이는) **카메라 컴포넌트** 와 **스프링 암 컴포넌트** 사용법, 게임플레이 도중의 카메라 사이 전환법도 배워 보시기 바랍니다. -## 사용 예제 +## 구현 안내 -아래 각 링크에서 단계별 사용 예제를 참고하시기 바랍니다. - -[REGION:buttonlist] -* [](Gameplay\HowTo\UsingCameras\Blueprints) -* [](Gameplay\HowTo\UsingCameras\SwitchingCameras) -* [](Gameplay\HowTo\UsingCameras\CameraComponents) -* [](Gameplay\HowTo\UsingCameras\SpringArmComponents) -[/REGION] +[DIR(output:"role" parent:"Gameplay/HowTo/UsingCameras" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Gameplay/Input/Input.INT.udn b/Engine/Documentation/Source/Gameplay/Input/Input.INT.udn index dd3429a65f1b..e4b51de50518 100644 --- a/Engine/Documentation/Source/Gameplay/Input/Input.INT.udn +++ b/Engine/Documentation/Source/Gameplay/Input/Input.INT.udn @@ -1,22 +1,23 @@ Availability: Public Title:Input -Crumbs:%ROOT%, Gameplay +Crumbs:%ROOT% Description:The Input object is responsible for converting input from the player into data in a form Actors can understand and make use of. version: 4.15 skilllevel:Beginner Parent:Engine/Gameplay +order: type:overview +tags:Input +[TOC (start:2 end:4)] -The **PlayerInput** object is responsible for converting input from the player into data in a form that Actors, like PlayerControllers or Pawns, +The **PlayerInput** Object is responsible for converting input from the player into data that Actors (like PlayerControllers or Pawns) can understand and make use of. It is part of an input processing flow that translates hardware input from players into game events and movement with PlayerInput mappings and InputComponents. [REGION:note] For an example of setting up Input, refer to the [](Gameplay\HowTo\SetUpInput) documentation. [/REGION] -[TOC (start:2 end:4)] - ## Hardware Input Hardware input from a player is very straightforward. It most commonly includes key presses, mouse clicks or mouse movement, and controller button presses or joystick movement. Specialized input devices that don't conform to standard axis or button indices, or that have unusual input ranges, can be configured manually by using the [](Gameplay\Input\RawInput). @@ -44,7 +45,7 @@ is currently zero. This allows for smooth transitions in movement or other game ### Setting Input Mappings -Input mappings are stored in configuration files, but can be set easily through the Project Settings tab in the Level Editor. +Input mappings are stored in configuration files, and can be edited in the Input section of Project Settings. 1. In the Level Editor, select **Edit > Project Settings**. @@ -66,20 +67,18 @@ In this window, you can: [/EXCERPT:PlayerInput] ## InputComponent -InputComponents are most commonly present in Pawns and Controllers, although they can be set in other Actors and Level Scripts if desired. The InputComponent links the AxisMappings and ActionMappings in your +**InputComponents** are most commonly present in Pawns and Controllers, although they can be set in other Actors and Level Scripts if desired. The InputComponent links the AxisMappings and ActionMappings in your project to game actions, usually functions, set up either in C++ code or Blueprint graphs. The priority stack for input handling by InputComponents is as follows (highest priority first): -1. The Actor with the most-recently enabled "Accepts input" - this can be anything from a door to a pickup item. - 1. Input handling proceeds through all Actors with "Accepts input" enabled, from most-recently enabled to least-recently enabled. - +1. Actors with "Accepts input" enabled, from most-recently enabled to least-recently enabled. [REGION:tip] If you want a particular Actor to always be the first one considered for input handling, you can re-enable its "Accepts input" and it will be moved to the top of the stack. [/REGION:tip] -1. Controller -1. Level Script -1. Pawn +1. Controllers. +1. Level Script. +1. Pawns. If one InputComponent takes the input, it is not available further down the stack. diff --git a/Engine/Documentation/Source/Gameplay/Input/Input.JPN.udn b/Engine/Documentation/Source/Gameplay/Input/Input.JPN.udn index 7d66c6fa0f3a..7c6f3b8a9e7b 100644 --- a/Engine/Documentation/Source/Gameplay/Input/Input.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/Input/Input.JPN.udn @@ -1,22 +1,26 @@ -INTSourceChangelist:2711553 +INTSourceChangelist:3413921 Availability:Public Title:入力値 -Crumbs:%ROOT%, Gameplay +Crumbs:%ROOT% Description:プレイヤーからの入力値をアクタが使用できるデータ形式へ変換する入力オブジェクト。 -version:4.9 - - -**PlayerInput** オブジェクトは、プレイヤーからの入力をアクタが認識し、利用可能なデータ形式へ変換します。例えば PlayerController や Pawn などのアクタは、 -入力を認識してこれらを利用することができます。これは入力処理フローの一部で、プレイヤーからのハードウェア入力をゲームイベント、 PlayerInput マッピングや InputComponent を使用した動作へ変換します。 - -[REGION:note] -入力値の設定例は、 [](Gameplay\HowTo\SettingUpAGameMode) を参照してください。 -[/REGION] +version:4.15 +skilllevel:Beginner +Parent:Engine/Gameplay +order: +type:overview +tags:Input [TOC (start:2 end:4)] +**PlayerInput** オブジェクトは、プレイヤーからの入力をアクタ ( PlayerController や Pawn など) が認識可能で、 +利用可能なデータ形式へ変換します。これは入力処理フローの一部で、プレイヤーからのハードウェア入力をゲームイベント、 PlayerInput マッピングや InputComponent を使用した動作へ変換します。 + +[REGION:note] +入力値の設定例は、 [](Gameplay\HowTo\SetUpInput) のドキュメントを参照してください。 +[/REGION] + ## ハードウェアへの入力 -プレイヤーからのハードウェアへの入力は非常に単純です。キー入力、マウスクリックやマウス動作、そしてコントローラーボタン入力かジョイスティックによる入力が最も一般的です。 +プレイヤーからのハードウェアへの入力は非常に単純です。キー入力、マウスクリックやマウス動作、そしてコントローラーボタン入力かジョイスティックによる入力が最も一般的です。標準的な軸やボタンのインデックスに従わない特殊な入力デバイスや、通常の入力範囲を超えたものを持つ場合は、[](Gameplay\Input\RawInput) を使って手動で設定することができます。 ## PlayerInput (プレイヤー入力) @@ -26,12 +30,12 @@ PlayerInput (プレイヤー入力) はプレイヤー入力を管理する Play 「ActionMappings」と「AxisMappings」の両方で使用するハードウェアの入力定義は InputCoreTypes で設定します。 [EXCERPT:ActionMapping] -$ ActionMappings :後にイベント駆動の動作と結合する「フレンドリーネーム」へ、ディスクリート ボタンかキー入力をマッピングします。最終的な効果は、キー、マウスボタン、またはキーパッドボタンを押す (解放する) と、特定のゲーム動作が直接トリガーされます。 +$ ActionMappings :後にイベント駆動の動作と結合する「フレンドリーネーム」へ、ディスクリート ボタンかキー入力をマッピングします。最終的な効果は、キー、マウスボタン、またはキーパッドボタンを押す (解放する) と、特定のゲーム動作が直接トリガーされます。  [/EXCERPT:ActionMapping] [EXCERPT:AxisMapping] -$ AxisMappings :ゲーム内の移動など、後に継続的なゲーム動作と結合する「フレンドリーネーム」へ、キーボード、コントローラーまたはマウスの入力をマッピングします。AxisMapping でマッピングされた入力値は、たとえ入力値が 0 である報告のみの場合でも、 -継続的にポーリングされます。ActionMappings への入力でトリガーされる別個のゲームイベントではなく、移動や他のゲーム動作のスムーズな遷移を有効にします。 +$ AxisMappings :ゲーム内の移動など、後に継続的なゲーム動作と結合する「フレンドリーネーム」へ、キーボード、コントローラーまたはマウスの入力をマッピングします。AxisMapping でマッピングされた入力値は、単に入力値が現在 0 である旨の報告の場合でも、 +継続的にポーリングされます。ActionMapping への入力でトリガーされる別個のゲームイベントではなく、移動や他のゲーム動作のスムーズな遷移を有効にします。 [REGION:tip] ゲーム用コントローラーのジョイスティックなどのハードウェア軸は、「discrete 1 (ボタンを押した状態) 」または「0 (ボタンを押していない状態) 」入力ではなく、入力の度合いを感知します。つまり、わずかな入力や力強い入力でキャラクターを動かすことが可能で、その度合いによって @@ -41,7 +45,7 @@ $ AxisMappings :ゲーム内の移動など、後に継続的なゲーム動作 ### 入力マッピングの設定 -入力マッピングはコンフィギュレーション ファイルに格納されていますが、レベルエディタの [Project Settings] タブで簡単に設定できます。 +入力マッピングはコンフィギュレーション ファイルに格納されていますが、[Project Settings] の [Input] セクションで簡単に設定できます。 1. レベルエディタで、 **Edit > Project Settings** の順に選択します。 @@ -50,7 +54,7 @@ $ AxisMappings :ゲーム内の移動など、後に継続的なゲーム動作 1. 表示される **[Project Settings]** タブで **[Input]** をクリックします。 -このウィンドウで、以下の設定を行うことができます。 +このウィンドウで、以下の設定を行うことができます。 **(ハードウェア) 軸入力のプロパティの変更:** ![](AxisConfig.png) @@ -63,17 +67,15 @@ $ AxisMappings :ゲーム内の移動など、後に継続的なゲーム動作 [/EXCERPT:PlayerInput] ## InputComponent -InputComponent は通常ポーンやコントローラに作成されますが、必要に応じて別のアクタやレベル スクリプトに設定することも出来ます。InputComponent は、ユーザープロジェクトの AxisMapping と ActionMapping をゲームアクションとリンクさせます。 +**InputComponent** は通常ポーンやコントローラに作成されますが、必要に応じて別のアクタやレベル スクリプトに設定することも出来ます。InputComponent は、ユーザープロジェクトの AxisMapping と ActionMapping をゲームアクションとリンクさせます。 通常は関数として、C++ コードかブループリントグラフに設定します。 InputComponent による入力処理のプライオリティ スタックは、以下の通りです (優先順位の高い順から) -1. 直前に有効となった「Accepts input」を伴うアクタ。ドアからピックアップ アイテムまでさまざまです。 - 1. 入力処理は、「Accepts input」が有効となった全てのアクタを経由して、直前に有効となったものから最も長時間有効となっている順番で処理されます。 - +1. 「Accepts input」が有効となったアクタは、直前に有効となったものから最も長時間有効となっている順番で処理されます。 [REGION:tip] 入力処理で特定のアクタを常に優先したい場合、そのアクタの「Accepts input」を再び有効にして、スタックのトップに移動させることができます。 [/REGION:tip] -1. コントローラー +1. コントローラ 1. レベルスクリプト 1. ポーン @@ -89,16 +91,16 @@ InputComponent による入力処理のプライオリティ スタックは、 この例は、UE4 に同梱される First Person テンプレートからのものです。 -1. ハードウェアへの入力:プレイヤーが W を押します。 +1. **ハードウェアへの入力:** プレイヤーが W を押します。 1. **PlayerInput Mapping:** AxisMappingは W を値 1 のスケーリングで「MoveForward」へ変換します。 ![](AxisMappingW.png) -1. **InputComponent Priority Stack:** InputComponent のプライオリティ スタックを通過した「MoveForward」入力が最初に結合するものは、AFirstPersonBaseCodeCharacterクラス内にあります。このクラスは現在のプレイヤーのポーンであるため、その InputComponent は最後にチェックされます。 +1. **InputComponent Priority Stack:** InputComponent のプライオリティ スタックを通過した「MoveForward」入力が最初に結合するものは、AFirstPersonBaseCodeCharacter クラス内にあります。このクラスは現在のプレイヤーのポーンであるため、その InputComponent は最後にチェックされます。 void AFirstPersonBaseCodeCharacter::SetupPlayerInputComponent(class UInputComponent* InputComponent) { - // ゲームプレイのキーバインド設定 + // set up gameplay key bindings (ゲームプレイのキーバインド設定) check(InputComponent); ... InputComponent->BindAxis("MoveForward", this, &AFirstPersonBaseCodeCharacter::MoveForward); @@ -115,14 +117,14 @@ InputComponent による入力処理のプライオリティ スタックは、 { if ( (Controller != NULL) && (Value != 0.0f) ) { - // 前進方向の確認 + // find out which way is forward (前進方向の確認) FRotator Rotation = Controller->GetControlRotation(); - // 歩行または落下時のピッチ (上下動) の制限 + // Limit pitch when walking or falling (歩行または落下時のピッチ (上下動) の制限) if ( CharacterMovement->IsMovingOnGround() || CharacterMovement->IsFalling() ) { Rotation.Pitch = 0.0f; } - // その方向へもたらす動きを追加 + // add movement in that direction (その方向へ動きを追加) const FVector Direction = FRotationMatrix(Rotation).GetScaledAxis(EAxis::X); AddMovementInput(Direction, Value); } diff --git a/Engine/Documentation/Source/Gameplay/Input/Input.KOR.udn b/Engine/Documentation/Source/Gameplay/Input/Input.KOR.udn index a9b2e8cec74d..ce2cd8613a0d 100644 --- a/Engine/Documentation/Source/Gameplay/Input/Input.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/Input/Input.KOR.udn @@ -1,13 +1,16 @@ -INTSourceChangelist:3340402 +INTSourceChangelist:3413921 Availability: Public Title:입력 -Crumbs:%ROOT%, Gameplay +Crumbs:%ROOT% Description:Input 오브젝트는 플레이어로부터의 입력을 액터가 이해하고 활용할 수 있는 형태의 데이터로 변환하는 작업을 담당합니다. version: 4.15 skilllevel:Beginner Parent:Engine/Gameplay +order: type:overview +tags:Input +[TOC (start:2 end:4)] **PlayerInput** 오브젝트는 플레이어로부터 받은 입력을 PlyaerController 나 Pawn 같은 액터가 이해하고 활용할 수 있는 형태의 데이터로 변환하는 작업을 담당합니다. 이는 PlayerInput 매핑과 InputComponent 를 가지고 플레이어의 하드웨어 입력을 게임 이벤트와 동작으로 변환하는 입력 프로세스 흐름의 일부입니다. @@ -16,8 +19,6 @@ type:overview **입력** 셋업 예제는, [](Gameplay\HowTo\SetUpInput) 문서를 참고하세요. [/REGION] -[TOC (start:2 end:4)] - ## 하드웨어 입력 플레이어로부터의 하드웨어 입력은 매우 단순합니다. 가장 흔하게는 키 입력, 마우스 클릭, 마우스 이동, 콘트롤러 버튼 입력이나 조이스틱 이동 등이 포함됩니다. 표준 축 또는 버튼 인덱스가 아니거나 일반적이지 않은 입력 범위를 갖는 특수 입력 디바이스의 경우, [](Gameplay\Input\RawInput) 으로 수동 설정할 수 있습니다. @@ -45,7 +46,7 @@ $ AxisMappings : 키보드, 콘트롤러, 마우스 입력을 나중에 이동 ### 입력 매핑 설정 -입력 매핑은 환경설정 파일에 저장되나, 레벨 에디터의 프로젝트 세팅 탭을 통해 쉽게 설정 가능합니다. +입력 매핑은 환경설정 파일에 저장되며, 프로젝트 세팅의 입력(Input) 섹션에서 편집 가능합니다. 1. 레벨 에디터에서 **편집 > 프로젝트 세팅** 을 선택합니다. @@ -72,9 +73,7 @@ InputComponent 는 필요에 따라 다른 액터나 레벨 스크립트에서 InputComponent 가 처리하는 입력에 대한 우선권 스택은 다음과 같습니다 (높은 우선권 먼저): -1. 가장 최근 "Accepts input" (입력 받음) 활성화된 액터 - 문에서 픽업 아이템까지 어느것도 가능. - 1. 가장 최근에서부터 나중까지 "Accepts input" (입력 받음) 활성화된 모든 액터를 대상으로 입력 처리 진행 - +1. "Accepts input" 활성화된 액터, 가장 최근에서부터 나중 활성화된 순. [REGION:tip] 입력 처리에 있어 항상 특정 액터를 가장 처음 고려하도록 만들고 싶은 경우, "Accepts input" (입력 받음) 을 재활성화시키면 스택 최상단으로 올라갈 것입니다. [/REGION:tip] diff --git a/Engine/Documentation/Source/Gameplay/Input/RawInput/RawInput.INT.udn b/Engine/Documentation/Source/Gameplay/Input/RawInput/RawInput.INT.udn index 3b35f0208932..c0b063a4c91e 100644 --- a/Engine/Documentation/Source/Gameplay/Input/RawInput/RawInput.INT.udn +++ b/Engine/Documentation/Source/Gameplay/Input/RawInput/RawInput.INT.udn @@ -1,38 +1,60 @@ Availability:Docs Title:RawInput Plugin -Crumbs:%ROOT%, Gameplay, Gameplay/Input +Crumbs:%ROOT% Description: The RawInput plugin can read specific devices that don't conform to XInput standards. -version: 4.15 +version: 4.16 skilllevel:Intermediate Parent:Engine/Gameplay/Input +Order: type:overview +tags:Input -## RawInput Plugin +[TOC (start:2 end:4)] -The ***RawInput** plugin provides support for specific, user-defined devices that aren't properly handled by XInput, usually flight sticks and steering wheels. The buttons and axes of these input devices can be custom-mapped to gameplay inputs, including new inputs created by the plugin itself. +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + QMD-OQ2Q-dI + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] -### Enabling RawInput +The ***RawInput** plugin provides support for specific, user-defined devices that aren't properly handled by Microsoft's XInput API (Application Programming Interface), usually flight sticks and steering wheels. The buttons and axes of these input devices can be custom-mapped to gameplay inputs, including new inputs created by the plugin itself. + +## Enabling RawInput By default, the plugin is not enabled. It can be enabled from the **Plugins** menu, in the **Input Devices** section. ![RawInput plugin](RawInputPlugin.png) -Once the plugin is enabled, the **Raw Input** section will appear in the **Project Settings** menu. +After the plugin is enabled, the **Raw Input** section will appear in the **Project Settings** menu. ![RawInput location in Project Settings menu](RawInput.png) -### Configuring Devices +## Configuring Devices -Within this section, you can add new devices. Each device is identified by a vendor ID and a product ID, which are hexadecimal values that can be found in the device's driver properties. An array of axes (by default, eight) and buttons (by default, twelve) will be added to the controller's configuration. This provides the ability to map any of the controller's axes or buttons (indicated by the array index) to any **Unreal Engine** axis or key. The plugin provides eight new axes ("Generic USB Controller Axis 1" through "Generic USB Controller Axis 8") and twelve new buttons ("Generic USB Controller Button 1" through "Generic USB Controller Button 12"). Each axis and button can be enabled or disabled, and axes can also be inverted and offset. +Within this section, you can add new devices. Each device is identified by a vendor ID and a product ID, which are hexadecimal values that can be found in the device's driver properties. An array of axes (by default, eight) and buttons (by default, twelve) will be added to the controller's configuration. This provides the ability to map any of the controller's axes or buttons (indicated by the array index) to any **Unreal Engine** axis or key. The plugin provides eight new axes ("Generic USB Controller Axis 1" through "Generic USB Controller Axis 8") and twenty new buttons ("Generic USB Controller Button 1" through "Generic USB Controller Button 20"). Each axis and button can be enabled or disabled, and axes can also be inverted and offset. ![Windows Device Settings](WindowsSettings.png) -_Above, the Hardware ID information in Windows Control Panel (under Device Manager) for the Logitech G920. The Vendor ID is the four-character string following "VID\_" test (046D), and the Product ID is the four-character string following "PID\_" (C262). This information will be required when configuring the device in RawInput._ +[REGION:caption] +Above, you can see the Hardware ID information in Windows Control Panel (under Device Manager) for the Logitech G920. The Vendor ID is the four-character string following "VID\_" test (046D), and the Product ID is the four-character string following "PID\_" (C262). This information will be required when configuring the device in RawInput. +[/REGION] -### Example (Vehicle Templates) +## Example (Vehicle Templates) As an example, the Vehicle templates that ship with the **Unreal Engine** have been configured to work with the **Logitech G920**, a driving-game controller with a steering wheel and gas/brake pedals. -#### Configuring the Device in RawInput +### Configuring the Device in RawInput The steering wheel is reported by the driver as Axis 1, the brake is reported as Axis 3, and the gas pedal is reported as Axis 4. In the RawInput plugin settings, each input must be entered into the array at the corresponding axis from the device driver. That is, the steering wheel's data must be in array element 1, the brake's data must be in array element 3, and the gas pedal's data must be in array element 4. All other entries may be removed or marked as disabled. [REGION:note]Note that the array index of an input does not need to correspond to the "Generic USB Controller Axis" or "Generic USB Controller Input" value. For example, the brake is bound to "Generic USB Controller Axis 2" even though it is in array position 3. This is necessary to ensure that different controllers can be configured to work the same way, even if they use different input axes.[/REGION] @@ -41,10 +63,10 @@ The steering wheel is reported by the driver as Axis 1, the brake is reported as Because the device's output range doesn't match what we might expect from a standard controller, we will remap the input ranges. The wheel returns values from 0.0 (left) to 1.0 (right), but we want the input range to center on 0.0, so we will give it an offset of -0.5. The brake and gas pedals also return values from 0.0 to 1.0, but the device uses 0.0 to indicate that the pedal is pressed down, and 1.0 to indicate that the pedal is up, where our project expects the reverse. To make this adjustment, we set the axis values to be inverted, and then add a 1.0 offset. -#### Mapping our RawInput Axes to Input Bindings +### Mapping our RawInput Axes to Input Bindings ![Input settings](InputData.png) -We can then map the new axes to our game's input bindings. The wheel (on "Generic USB Controller Axis 1") is mapped to the range [-0.5, 0.5], but we want it to be more sensitive, so we can scale it up by a factor of 3.0. Similarly, the brake (on "Generic USB Controller Axis 2") needs to go in the negative direction, and should be more powerful than the gas pedal, so it will be scaled by -2.0. The gas pedal (on "Generic USB Controller Axis 3") requires no modification, and only needs to be added to the appropriate input binding. By using RawInput and adding these input bindings, we are able to support the Logitech G920 without needing any new input bindings or making any changes to our project's code or blueprints. +We can then map the new axes to our game's input bindings. The wheel (on "Generic USB Controller Axis 1") is mapped to the range [-0.5, 0.5], but we want it to be more sensitive, so we can scale it up by a factor of 3.0. Similarly, the brake (on "Generic USB Controller Axis 2") needs to go in the negative direction, and should be more powerful than the gas pedal, so it will be scaled by -2.0. The gas pedal (on "Generic USB Controller Axis 3") requires no modification, and only needs to be added to the appropriate input binding. By using RawInput and adding these input bindings, we are able to support the Logitech G920 without needing any new input bindings or making any changes to our project's code or Blueprints. [REGION:tip]This use of scaling provides a good argument for using the "Generic USB Controller" axes instead of configuring the device to the standard gamepad stick inputs.[/REGION] diff --git a/Engine/Documentation/Source/Gameplay/Input/RawInput/RawInput.JPN.udn b/Engine/Documentation/Source/Gameplay/Input/RawInput/RawInput.JPN.udn index f1cac5589947..27ca201b5a91 100644 --- a/Engine/Documentation/Source/Gameplay/Input/RawInput/RawInput.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/Input/RawInput/RawInput.JPN.udn @@ -1,51 +1,73 @@ -INTSourceChangelist:0 +INTSourceChangelist:3413921 Availability:Docs -Title:RawInput Plugin -Crumbs:%ROOT%, Gameplay, Gameplay/Input -Description: The RawInput plugin can read specific devices that don't conform to XInput standards. -version: 4.15 +Title:RawInput プラグイン +Crumbs:%ROOT% +Description:RawInput プラグインは、XInput に対応しない特定のデバイスを読み込むことができます。 +version:4.16 skilllevel:Intermediate Parent:Engine/Gameplay/Input +Order: type:overview +tags:Input -## RawInput Plugin +[TOC (start:2 end:4)] -The ***RawInput** plugin provides support for specific, user-defined devices that aren't properly handled by XInput, usually flight sticks and steering wheels. The buttons and axes of these input devices can be custom-mapped to gameplay inputs, including new inputs created by the plugin itself. +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + QMD-OQ2Q-dI + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] -### Enabling RawInput +***RawInput** プラグインは、通常、フライト スティックやハンドルなどの Microsoft の XInput API が適切に処理しない特定のユーザー定義のデバイスをサポートします。入力デバイスのボタンと軸は、プラグイン自体で作成された新規入力も含むゲームプレイ入力にカスタム マッピングすることができます。 -By default, the plugin is not enabled. It can be enabled from the **Plugins** menu, in the **Input Devices** section. +## RawInput を有効にする + +デフォルトでプラグインは無効になっています。**[Plugins]** メニューの **[Input Devices]** セクションで有効にすることができます。 ![RawInput plugin](RawInputPlugin.png) -Once the plugin is enabled, the **Raw Input** section will appear in the **Project Settings** menu. +プラグインが有効になったら、**[Project Settings]** メニューに **[Raw Input]** セクションが表示されます。 ![RawInput location in Project Settings menu](RawInput.png) -### Configuring Devices +## デバイスの設定 -Within this section, you can add new devices. Each device is identified by a vendor ID and a product ID, which are hexadecimal values that can be found in the device's driver properties. An array of axes (by default, eight) and buttons (by default, twelve) will be added to the controller's configuration. This provides the ability to map any of the controller's axes or buttons (indicated by the array index) to any **Unreal Engine** axis or key. The plugin provides eight new axes ("Generic USB Controller Axis 1" through "Generic USB Controller Axis 8") and twelve new buttons ("Generic USB Controller Button 1" through "Generic USB Controller Button 12"). Each axis and button can be enabled or disabled, and axes can also be inverted and offset. +このセクションでは新規デバイスを追加します。各デバイスはベンダー ID とプロダクト ID によって特定されます。これらは、16 進数値であり、デバイスのドライバーのプロパティにあります。軸 (デフォルトで 8) とボタン (デフォルトで 12) の配列がコントローラーの設定に加えられます。これにより、任意のコントローラーの軸やボタン (配列のインデックスで示されるもの) を **アンリアル エンジン** の軸やキーにマッピングすることができます。このプラグインには 8 個の新しい軸 ("Generic USB Controller Axis 1" から "Generic USB Controller Axis 8" まで) と 20 個の新しいボタン ("Generic USB Controller Button 1" から "Generic USB Controller Button 20" まで) があります。それぞれの軸やボタンを有効または無効にすることができます。軸も反転、オフセットすることができます。 ![Windows Device Settings](WindowsSettings.png) -_Above, the Hardware ID information in Windows Control Panel (under Device Manager) for the Logitech G920. The Vendor ID is the four-character string following "VID\_" test (046D), and the Product ID is the four-character string following "PID\_" (C262). This information will be required when configuring the device in RawInput._ +[REGION:caption] +上の図は、Logitech G920 の Windows のコントロール パネルのデバイス マネージャのハードウェア ID 情報です。Vendor ID は、 "VID\_" に続く 4 つの文字列です (046D) 。Product ID は "PID\_" に続く 4 つの文字列です(C262)。この情報は、RawInput でデバイスを設定する場合に必要になります。 +[/REGION] -### Example (Vehicle Templates) -As an example, the Vehicle templates that ship with the **Unreal Engine** have been configured to work with the **Logitech G920**, a driving-game controller with a steering wheel and gas/brake pedals. +## サンプル (Vehicle テンプレート) +例として、**アンリアル エンジン** に同梱される Vehicle テンプレートが **Logitech G920** で機能するように設定しました。Logitech G920 は、ハンドルとアクセル ペダルとブレーキ ペダルを備えたドライブ ゲーム コントローラーです。 -#### Configuring the Device in RawInput -The steering wheel is reported by the driver as Axis 1, the brake is reported as Axis 3, and the gas pedal is reported as Axis 4. In the RawInput plugin settings, each input must be entered into the array at the corresponding axis from the device driver. That is, the steering wheel's data must be in array element 1, the brake's data must be in array element 3, and the gas pedal's data must be in array element 4. All other entries may be removed or marked as disabled. +### RawInput でデバイスを設定する +ハンドルはデバイス ドライバーで Axis 1、ブレーキは Axis 3、アクセルは Axis 4 になります。RawInput プラグイン設定では、各入力はデバイス ドライバーからの対応する軸の配列に入力しなければなりません。つまりハンドルのデータは配列要素 1 に、ブレーキのデータは配列要素 3 にアクセル ペダルのデータは配列要素 4 に入れなければなりません。他のエントリは取り除くか、無効にします。 -[REGION:note]Note that the array index of an input does not need to correspond to the "Generic USB Controller Axis" or "Generic USB Controller Input" value. For example, the brake is bound to "Generic USB Controller Axis 2" even though it is in array position 3. This is necessary to ensure that different controllers can be configured to work the same way, even if they use different input axes.[/REGION] +[REGION:note]入力の配列インデックスは、"Generic USB Controller Axis" や "Generic USB Controller Input" の値に対応する必要はありません。例えば、ブレーキが配列の位置 3 にあっても、"Generic USB Controller Axis 2" にバインドされます。これは異なるコントローラーが異なる入力軸を使用している場合であっても同様に機能するように設定するうえで必要です。[/REGION] ![RawInput settings](RawInputData.png) -Because the device's output range doesn't match what we might expect from a standard controller, we will remap the input ranges. The wheel returns values from 0.0 (left) to 1.0 (right), but we want the input range to center on 0.0, so we will give it an offset of -0.5. The brake and gas pedals also return values from 0.0 to 1.0, but the device uses 0.0 to indicate that the pedal is pressed down, and 1.0 to indicate that the pedal is up, where our project expects the reverse. To make this adjustment, we set the axis values to be inverted, and then add a 1.0 offset. +デバイスの出力範囲は標準コントローラーで想定されるものとは一致しないため、入力範囲を再マッピングします。車輪が 0.0 (左) から 1.0 (右) の値を戻しますが、 0.0 を中心に入力範囲を設定します。そのため、オフセット -0.5 としました。ブレーキとアクセルも 0.0 から 1.0 の範囲の値を戻します。このデバイスは 0.0 を使用して、そのペダルが押されていることを示します。1.0 の値は、ペダルが上がっていることを示しますが、このプロジェクトでは逆を想定しています。この調整をするために、軸の値を反転するように設定し、1.0 のオフセットを追加します。 -#### Mapping our RawInput Axes to Input Bindings +### RawInput の軸を入力バインディングにマッピングする -![Input settings](InputData.png) +![Input settings](RawInputData.png) -We can then map the new axes to our game's input bindings. The wheel (on "Generic USB Controller Axis 1") is mapped to the range [-0.5, 0.5], but we want it to be more sensitive, so we can scale it up by a factor of 3.0. Similarly, the brake (on "Generic USB Controller Axis 2") needs to go in the negative direction, and should be more powerful than the gas pedal, so it will be scaled by -2.0. The gas pedal (on "Generic USB Controller Axis 3") requires no modification, and only needs to be added to the appropriate input binding. By using RawInput and adding these input bindings, we are able to support the Logitech G920 without needing any new input bindings or making any changes to our project's code or blueprints. +次に新しい軸をゲームの入力バインディングにマッピングします。車輪 ("Generic USB Controller Axis 1") は、範囲 [-0.5、0.5] にマッピングされますが、さらに感度を上げて、3.0 の係数でスケールアップできるようにします。同様にブレーキ ("Generic USB Controller Axis 2") を負の方向に行くようにし、アクセルよりも強力になるようにします。そのため、-2.0 でスケーリングされるようにします。アクセル ("Generic USB Controller Axis 3") は修正が不要です。適切な入力バインディングに追加するだけです。RawInput を使ってこうした入力バインディングを加えることで、新しい入力バインディングを必要とせずに、プロジェクトのコードまたはブループリントに変更を加えることなく、Logitech G920 をサポートします。 -[REGION:tip]This use of scaling provides a good argument for using the "Generic USB Controller" axes instead of configuring the device to the standard gamepad stick inputs.[/REGION] +[REGION:tip]デバイスを標準のゲームパッド スティック入力に設定する代わりに、このようなスケーリングを使うと "Generic USB Controller" 軸を使った適切な引数になります。[/REGION] diff --git a/Engine/Documentation/Source/Gameplay/Input/RawInput/RawInput.KOR.udn b/Engine/Documentation/Source/Gameplay/Input/RawInput/RawInput.KOR.udn index 8b8521d6d715..e8dfbc6310be 100644 --- a/Engine/Documentation/Source/Gameplay/Input/RawInput/RawInput.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/Input/RawInput/RawInput.KOR.udn @@ -1,18 +1,38 @@ -INTSourceChangelist:3340402 +INTSourceChangelist:3413921 Availability:Docs Title:RawInput 플러그인 -Crumbs:%ROOT%, Gameplay, Gameplay/Input +Crumbs:%ROOT% Description: RawInput 플러그인은 XInput 표준에 맞지 않는 디바이스에서 읽을 수 있습니다. -version: 4.15 +version: 4.16 skilllevel:Intermediate Parent:Engine/Gameplay/Input +Order: type:overview +tags:Input -## RawInput 플러그인 +[TOC (start:2 end:4)] -***RawInput** 플러그인은 XInput 으로 정상 처리되지 않는 사용자 정의 디바이스 지원을 위한 것으로, 보통 비행기 조종 스틱이나 운전대같은 것을 말합니다. 이러한 입력 디바이스의 버튼과 축은 게임플레이 입력으로 커스텀 매핑시킬 수 있으며, 여기에는 플러그인 자체에서 만든 새로운 입력이 포함됩니다. +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + QMD-OQ2Q-dI + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] -### RawInput 켜기 +***RawInput** 플러그인은 Microsoft 의 XInput API 로 정상 처리되지 않는 사용자 정의 디바이스 지원을 위한 것으로, 보통 비행기 조종 스틱이나 운전대같은 것을 말합니다. 이러한 입력 디바이스의 버튼과 축은 게임플레이 입력으로 커스텀 매핑시킬 수 있으며, 여기에는 플러그인 자체에서 만든 새로운 입력이 포함됩니다. + +## RawInput 켜기 기본적으로 플러그인은 켜져있지 않습니다. **플러그인** 메뉴의 **Input Devices** 섹션에서 켤 수 있습니다. @@ -22,18 +42,20 @@ type:overview ![RawInput location in Project Settings menu](RawInput.png) -### 디바이스 환경설정 +## 디바이스 환경설정 -여기서는 새 디바이스를 추가할 수 있습니다. 각 디바이스는 벤더 ID 와 제품 ID 로 식별되며, 이는 디바이스의 드라이버 속성에서 찾을 수 있는 16진 값입니다. 컨트롤러의 환경설정에 (기본으로 8 개의) 축 배열과 (기본으로 12 개의) 버튼이 추가됩니다. 컨트롤러의 (배열 인덱스로 지시된) 축과 버튼을 어떤 **언리얼 엔진** 축이나 키에도 매핑시킬 수 있는 기능이 제공됩니다. 플러그인에는 ("Generic USB Controller Axis 1" 부터 "Generic USB Controller Axis 8" 까지) 8 개의 축과 ("Generic USB Controller Button 1" 부터 "Generic USB Controller Button 12" 까지) 12 개의 버는이 제공됩니다. 각 축과 버튼은 켜고 끌 수 있으며, 축 역시도 반전이나 오프셋 적용이 가능합니다. +여기서는 새 디바이스를 추가할 수 있습니다. 각 디바이스는 벤더 ID 와 제품 ID 로 식별되며, 이는 디바이스의 드라이버 속성에서 찾을 수 있는 16진 값입니다. 컨트롤러의 환경설정에 (기본으로 8 개의) 축 배열과 (기본으로 12 개의) 버튼이 추가됩니다. 컨트롤러의 (배열 인덱스로 지시된) 축과 버튼을 어떤 **언리얼 엔진** 축이나 키에도 매핑시킬 수 있는 기능이 제공됩니다. 플러그인에는 ("Generic USB Controller Axis 1" 부터 "Generic USB Controller Axis 8" 까지) 8 개의 축과 ("Generic USB Controller Button 1" 부터 "Generic USB Controller Button 20" 까지) 20 개의 버튼이 제공됩니다. 각 축과 버튼은 켜고 끌 수 있으며, 축 역시도 반전이나 오프셋 적용이 가능합니다. ![Windows Device Settings](WindowsSettings.png) -_위는 윈도우 제어판 (디바이스 매니저 아래) Logitech G920 에 대한 하드웨어 ID 정보입니다. Vendor ID 는 "VID\_" 뒤의 네 글자이고 (046D), Product ID 는 "PID\_" 뒤의 네 글자입니다 (C262). 이 정보는 RawInput 에서 디바이스 환경설정을 할 때 필요합니다. +[REGION:caption] +위는 윈도우 제어판 (디바이스 매니저 아래) Logitech G920 에 대한 하드웨어 ID 정보입니다. Vendor ID 는 "VID\_" 뒤의 네 글자이고 (046D), Product ID 는 "PID\_" 뒤의 네 글자입니다 (C262). 이 정보는 RawInput 에서 디바이스 환경설정을 할 때 필요합니다. +[/REGION] -### 예제 (비히클 템플릿) +## 예제 (비히클 템플릿) **언리얼 엔진** 에 포함 출시되는 비히클 템플릿을 운전대와 액셀/브레이크 페달이 있는 운전용 게임 컨트롤러인 **Logitech G920** 과 작동하도록 환경설정한 예제입니다. -#### RawInput 에서 디바이스 환경설정 +### RawInput 에서 디바이스 환경설정 운전대는 드라이버가 Axis 1, 브레이크는 Axis 3, 액셀 페달은 Axis 4 로 보고합니다. RawInput 플러그인 세팅에서 각 입력은 반드시 디바이스 드라이버에서 해당하는 축 위치의 배열에 입력해야 합니다. 즉 운전대의 데이터는 반드시 배열 엘리먼트 1, 브레이크 데이터는 배열 엘리먼트 3, 액셀 페달 데이터는 배열 엘리먼트 4 에 있어야 합니다. 다른 모든 항목은 제거하거나 비활성화 마킹해야 합니다. [REGION:note]참고로 입력의 배열 인덱스는 "Generic USB Controller Axis" 나 "Generic USB Controller Input" 값에 해당할 필요가 없습니다. 예를 들어 브레이크는 배열 위치 3 에 있더라도 "Generic USB Controller Axis 2" 에 바인딩됩니다. 다른 컨트롤러가 다른 입력 축을 사용하라도 같은 방식으로 작동하게끔 환경설정할 수 있도록 하기 위해서입니다.[/REGION] @@ -42,7 +64,7 @@ _위는 윈도우 제어판 (디바이스 매니저 아래) Logitech G920 에 디바이스의 출력 범위가 표준 콘트롤러에 기대하는 범위와 일치하지 않기 때문에, 입력 범위를 리매핑합니다. 운전대의 반환 값은 (왼쪽) 0.0 에서 (오른쪽) 1.0 이지만, 입력 범위는 가운데에서 0.0 이 되도록 해야 하므로, 오프셋을 0.5 줍니다. 브레이크와 액셀 페달 역시 0.0 에서 1.0 값을 반환하지만, 디바이스에서는 페달을 밟았을 때 0.0, 떼었을 때 1.0 을 사용하므로, 프로젝트에서는 반대 값을 기대합니다. 이러한 조정을 위해서는 축 값을 반전시킨 뒤 1.0 오프셋을 더합니다. -#### RawInput 축을 입력 바인딩에 매핑 +### RawInput 축을 입력 바인딩에 매핑 ![Input settings](InputData.png) diff --git a/Engine/Documentation/Source/Gameplay/Networking/Blueprints/Blueprints.KOR.udn b/Engine/Documentation/Source/Gameplay/Networking/Blueprints/Blueprints.KOR.udn index 8d1d9e5dbe49..115a767e7239 100644 --- a/Engine/Documentation/Source/Gameplay/Networking/Blueprints/Blueprints.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/Networking/Blueprints/Blueprints.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3366524 Availability:Public Title: 블루프린트에서의 멀티플레이어 Crumbs:%ROOT%, Gameplay, Gameplay/Networking @@ -24,11 +24,12 @@ version: 4.9 자세한 정보는 [](Gameplay/Framework) 문서를 참고하시고, 멀티플레이어 게임을 디자인할 때는 최소한 다음의 팁 정도는 유념해 주시기 바랍니다: -* GameMode 오브젝트는 서버에서만 존재합니다. -* GameState 는 서버와 클라이언트에 존재하며, 서버는 GameState 상의 리플리케이티드 변수를 사용하여 모든 클라이언트에서 게임에 대한 데이터를 최신 상태로 유지할 수 있습니다. -* PlayerController 는 게임에 접속된 모든 플레이어에 대해 서버상에 존재합니다. 클라이언트에서는 그 클라이언트에 소유된 플레이어에 대한 PlayerController 만 존재합니다. 즉 PlayerController 는 모든 클라이언트가 알아야 하는 리플리케이티드 프로퍼티를 저장하기에 최적의 장소가 아니라는 뜻입니다. 그보다는 PlayerState 가 좋습니다. -* PlayerState 는 게임에 접속된 모든 플레이어에 대해 서버와 클라이언트 양쪽에 존재합니다. 이 클래스는 소유중인 클라이언트만이 아닌 모든 클라이언트가 알아야 하는, 이를테면 각 플레이어의 현재 점수와 같은 리플리케이티드 프로퍼티에 사용할 수 있습니다. -* Pawn (및 Character 포함) 역시 서버와 모든 클라이언트에 존재하며, 리플리케이티드 변수 및 이벤트를 갖고 있습니다. 특정 변수나 이벤트에 대해 PlayerState 를 쓸 것이냐 Pawn 을 쓸 것이냐 하는 것은 상황에 따라 다르지만, 주로 고려할 것은 PlayerState 는 플레이어가 접속된 시간동안 내도록 유지되는 반면, Pawn 은 그렇지 않을 수 있습니다. 예를 들어 플레이어 캐릭터가 게임플레이 도중 죽은 경우, 조종중이던 Pawn 은 소멸되고 플레이어 리스폰시 새로운 Pawn 이 생성될 것입니다. +* GameInstance 는 엔진 세션 도중에만 존재합니다. 즉 엔진 시작 시 생성되며, 종료될 때까지 소멸 또는 대체되지 않습니다. 서버와 각 클라이언트마다 별도의 GameInstance 가 존재하며, 이 인스턴스는 서로 통신하지 않습니다. GameInstance 는 게임 세션 외부에 존재하므로, 특정 유형의 지속성 데이터를 저장하기에 좋은 곳입니다. 이를테면 플레이어 전반적인 통계 (지금까지 이긴 게임 횟수), 계정 정보 (특수 아이템 잠김/해제 상태), 언리얼 토너먼트같은 경쟁형 게임에서 돌아가며 플레이할 맵 목록 등을 말합니다. +* GameMode 오브젝트는 서버에서만 존재합니다. 일반적으로 클라이언트가 명시적으로 알 필요가 없는 게임 관련 정보를 저장합니다. 예를 들어 "로켓 런처만" 나오는 특수 규칙 게임에서, 클라이언트는 이 정보를 알 필요가 없지만, 맵에 무기를 무작위로 스폰할 때 서버는 "로켓 런처" 카테고리에서만 선택해야한다 알아야 할 것입니다. +* GameState 는 서버와 클라이언트에 존재하며, 서버는 GameState 상의 리플리케이티드 변수를 사용하여 모든 클라이언트에서 게임에 대한 데이터를 최신 상태로 유지할 수 있습니다. 예로, 야구 게임에서 GameState 를 통해 각 팀의 점수와 현재 이닝을 리플리케이트할 수 있습니다. +* 각 클라이언트에는 그 머신의 플레이어마다 하나의 PlayerController 가 존재합니다. 이는 서버와 연결된 클라이언트 사이에 리플리케이트되지만, 다른 클라이언트에는 리플리케이트되지 않으므로, 서버는 모든 플레이어에 대한 PlayerController 를 갖고 있고, 로컬 클라이언트는 로컬 플레이어에 대한 PlayerController 만 갖습니다. 클라이언트가 접속되어 있는 도중에는 PlayerController 가 존재하여 Pawn 에 할당되지만, Pawn 과는 달리 소멸되거나 리스폰되지는 않습니다. 특정 플레이어에게만 감지된 게임 이벤트에 반응하여 미니맵에 핑을 찍도록 서버가 클라이언트에게 알리는 등의 작업처럼, 다른 클라이언트에 리플리케이트할 필요 없는 클라이언트와 서버 사이 통신에 적합합니다. +* PlayerState 는 게임에 접속된 모든 플레이어에 대해 서버와 클라이언트 양쪽에 존재합니다. 이 클래스는 소유중인 클라이언트만이 아닌 모든 클라이언트가 알아야 하는, 이를테면 프리-포-올 게임에서 각 플레이어의 현재 점수와 같은 리플리케이티드 프로퍼티에 사용할 수 있습니다. PlayerController 처럼 개별 Pawn 에 할당되지만, Pawn 과는 달리 소멸 및 리스폰되지 않습니다. +* Pawn (및 Character 포함) 역시 서버와 모든 클라이언트에 존재하며, 리플리케이티드 변수 및 이벤트를 갖고 있습니다. 특정 변수나 이벤트에 대해 PlayeyController 를 쓸 것이냐, PlayerState 를 쓸 것이냐, Pawn 을 쓸 것이냐 하는 것은 상황에 따라 다르지만, 주로 고려할 것은 PlayerController 와 PlayerState 는 플레이어가 접속된 시간동안 그리고 게임이 새 레벨을 로드하지 않는 한 내도록 유지되는 반면, Pawn 은 그렇지 않을 수 있습니다. 예를 들어 Pawn 이 게임플레이 도중 죽는 경우, 보통 소멸되고 새로운 Pawn 으로 대체되는 반면, PlayerController 와 PlayerState 는 계속해서 존재하며 새로운 Pawn 의 스폰이 끝나면 거기에 할당됩니다. Pawn 의 생명력은 그래서 Pawn 자체에 저장되는데, 실제 그 Pawn 인스턴스에만 해당되며, 새로운 Pawn 으로 대체되면 리셋시켜야 하기 때문됩니다. ## 액터 리플리케이션 diff --git a/Engine/Documentation/Source/Gameplay/Networking/CharacterMovementComponent/CharacterMovementComponent.KOR.udn b/Engine/Documentation/Source/Gameplay/Networking/CharacterMovementComponent/CharacterMovementComponent.KOR.udn index 21c68401cde2..3c61b26cef5d 100644 --- a/Engine/Documentation/Source/Gameplay/Networking/CharacterMovementComponent/CharacterMovementComponent.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/Networking/CharacterMovementComponent/CharacterMovementComponent.KOR.udn @@ -27,7 +27,7 @@ CharacterMovementComponent 를 사용하는 캐릭터는 자동으로 클라이 ##캐릭터 무브먼트 및 시뮬레이티드 프록시 지금까지 설명한 CharacterMovementComponent 의 접근법은 권위적 서버에 접속된 클라이언트 하나에 대해서만 자세히 다루고 있습니다. -AI 조종 캐릭터나 원격 컴퓨터의 플레이어는 "시뮬레이티드 프록시" 로 간주되며, 약간 다른 코드 패쓰를 통합니다. +AI 조종 캐릭터나 원격 컴퓨터의 플레이어는 "시뮬레이티드 프록시" 로 간주되며, 약간 다른 코드 패스를 통합니다. 원격 제어 캐릭터의 이동은 보통 일반적인 `PerformMovement` 코드를 사용하여 (오쏘리티가 있는) 서버에서 업데이트됩니다. 위치, 회전, 속도와 같은 액터 상태는 물론 기타 (점프나 웅크리기같은) 캐릭터 전용 정보도 일반 리플리케이션 메커니즘을 통해 다른 머신으로 리플리케이트됩니다. diff --git a/Engine/Documentation/Source/Gameplay/Networking/Networking.INT.udn b/Engine/Documentation/Source/Gameplay/Networking/Networking.INT.udn index 148fb42065f3..4adb7bfd5ef9 100644 --- a/Engine/Documentation/Source/Gameplay/Networking/Networking.INT.udn +++ b/Engine/Documentation/Source/Gameplay/Networking/Networking.INT.udn @@ -3,7 +3,14 @@ Title: Networking and Multiplayer Crumbs:%ROOT%, Gameplay, Gameplay/Framework Description:Setting up networked games for multiplayer. version: 4.9 +Parent:Engine +type:landing +order:20 +topic-image:NetworkingAndMultiplayer_Topic.png +[DIR(output:"listbutton" parent:"Gameplay/Networking" org:"hierarchy")] + + \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/Networking/Networking.KOR.udn b/Engine/Documentation/Source/Gameplay/Networking/Networking.KOR.udn index 91d3ab810282..a1e458dcd1e9 100644 --- a/Engine/Documentation/Source/Gameplay/Networking/Networking.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/Networking/Networking.KOR.udn @@ -1,10 +1,17 @@ -INTSourceChangelist:3143336 +INTSourceChangelist:3467293 Availability:Public Title: 네트워킹과 멀티플레이 Crumbs:%ROOT%, Gameplay, Gameplay/Framework Description:멀티플레이용 네트워크 게임 구성 방법입니다. version: 4.9 +Parent:Engine +type:landing +order:20 +topic-image:NetworkingAndMultiplayer_Topic.png +[DIR(output:"listbutton" parent:"Gameplay/Networking" org:"hierarchy")] + + \ No newline at end of file diff --git a/Engine/Documentation/Source/Gameplay/Networking/OnlineBeacons/OnlineBeacons.INT.udn b/Engine/Documentation/Source/Gameplay/Networking/OnlineBeacons/OnlineBeacons.INT.udn index 35faf4e6005b..d88987971039 100644 --- a/Engine/Documentation/Source/Gameplay/Networking/OnlineBeacons/OnlineBeacons.INT.udn +++ b/Engine/Documentation/Source/Gameplay/Networking/OnlineBeacons/OnlineBeacons.INT.udn @@ -3,7 +3,7 @@ Title: Online Beacons Crumbs: %ROOT%, Engine Description:Overview of the Online Beacon system Version: 4.13 -parent:Engine +parent:Gameplay/Networking Related: Gameplay/Networking/Actors/RPCs Related: Gameplay/Networking/Actors/Properties diff --git a/Engine/Documentation/Source/Gameplay/Networking/OnlineBeacons/OnlineBeacons.KOR.udn b/Engine/Documentation/Source/Gameplay/Networking/OnlineBeacons/OnlineBeacons.KOR.udn index 7813530bd281..368387d7b8b9 100644 --- a/Engine/Documentation/Source/Gameplay/Networking/OnlineBeacons/OnlineBeacons.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/Networking/OnlineBeacons/OnlineBeacons.KOR.udn @@ -1,10 +1,10 @@ -INTSourceChangelist:3169600 +INTSourceChangelist:3454520 Availability: Public Title: 온라인 비컨 Crumbs: %ROOT%, Engine Description:Online Beacon, 온라인 비컨 시스템 개요입니다. Version: 4.13 -parent:Engine +parent:Gameplay/Networking Related: Gameplay/Networking/Actors/RPCs Related: Gameplay/Networking/Actors/Properties diff --git a/Engine/Documentation/Source/Gameplay/Networking/Overview/Overview.JPN.udn b/Engine/Documentation/Source/Gameplay/Networking/Overview/Overview.JPN.udn index 09dbb2a77068..23cb879912f8 100644 --- a/Engine/Documentation/Source/Gameplay/Networking/Overview/Overview.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/Networking/Overview/Overview.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:2713567 +INTSourceChangelist:3356303 Availability:Public Title:ネットワーク構築の概要 Crumbs:%ROOT%, Gameplay, Gameplay/Framework @@ -6,14 +6,24 @@ Description:マルチプレイヤーに対応するネットワークゲーム Related:Gameplay/Networking/Blueprints Related:Gameplay/Networking/Example Related:Gameplay/Networking/Actors +Related:Gameplay/Networking/Server version:4.9 UE4 のフレームワークはマルチプレイヤーゲームを考慮して作られています。フレームワークの規約に従う限り、シングルプレイ体験をマルチプレイヤーへ拡張する作業はほとんどの場合あまりありません。 -UE4 のネットワークはサーバー/クライアントモデルを元に構築されています。つまり権限を持つサーバー (重要なすべての意思決定) が 1 つあり、このサーバーはクライアントがサーバーのワールドの近似値を最新に保つために、接続中のクライアントが常に更新していることを確認します。 +UE4 のネットワークはサーバー/クライアントモデルを元に構築されています。つまり権限を持つサーバー (重要なすべての意思決定) が 1 つあり、このサーバーはクライアントがサーバーのワールドの近似値を最新に保つために、接続中のクライアントが常に更新していることを確認します。ネットワーク化されていないシングルプレイヤー ゲームにもサーバーがあります。この場合、ローカルマシンがサーバーの役割をします。 ## アクタ シングルプレイヤー体験のアクタは、ゲームワールドの表現に使用します。サーバーが正式な値を保持するのに対し、クライアントはそれぞれのアクタの近似値を保持する点を除いて、マルチプレイヤー体験でも違いはありません。 -アクタは、サーバーがクライアントを最新に保つために使用する主力オブジェクトです。サーバーが特定のクライアントを更新する時は、最後の更新から変更したと判断する関連アクタをすべて収集して、その後これらのアクタを最新ステートに保つためにクライアントへ必要な情報を送信します。 +アクタは、サーバーがクライアントを最新に保つために非常に便利です。サーバーが特定のクライアントを更新する時は、最後の更新から変更したと判断する関連アクタをすべて収集して、その後これらのアクタを最新ステートに保つためにクライアントへ必要な情報を送信します。 + +## ネットワーク モード + +| ネットワーク モード タイプ | 機能 / 理想的なユースケース | +| --- | --- | +| `NM_Standalone` | ローカル マシン上で実行中のサーバーを示し、リモート クライアントからの接続要求は受け付けません。シングルプレイヤー ゲーム、またはローカル マルチプレイヤー ゲームに最適です。 | +| `NM_DedicatedServer` | デディケイテッド サーバーはローカル プレイヤーは使用できないので、サウンド、グラフィックス、ユーザー入力、他のプレイヤー向け機能を切り捨てて効率的に実行できます。パフォーマンス力の高い信頼できるサーバーを必要とする、競争力の高い MOBA タイトル、MMO ゲーム、オンライン シューティングゲームなど、信頼できるサーバー上でホストされるマルチプレイヤー ゲームで使われます。 | +| `NM_ListenServer` | リッスン サーバーはローカル プレイヤーをホストしますが、リモート プレイヤーからの接続も可能です。デディケイテッド サーバーを必要としないランクマッチ型や対戦型ゲームに適しています。ユーザーはサードパーティ サーバーなしで自分のゲームの設定およびプレイができます。ホストにネットワーク レイテンシーがないためホストに優位性を与え、ゲームはホストの警告なしに終了することができます。 | +| `NM_Client` | 唯一、サーバーではないタイプです。このモードにすると、ローカル マシンはデディケイテッド サーバーもしくはリッスン サーバーのクライアントとなるので、サーバー側のロジックを実行しません。 | diff --git a/Engine/Documentation/Source/Gameplay/SaveGame/Blueprints/BP_SaveGame.INT.udn b/Engine/Documentation/Source/Gameplay/SaveGame/Blueprints/BP_SaveGame.INT.udn index f7af562cc72e..600ae2cd54d9 100644 --- a/Engine/Documentation/Source/Gameplay/SaveGame/Blueprints/BP_SaveGame.INT.udn +++ b/Engine/Documentation/Source/Gameplay/SaveGame/Blueprints/BP_SaveGame.INT.udn @@ -32,9 +32,7 @@ You can set default values for the variables after the Blueprint is compiled. _This is a snapshot of the entire saving setup. You can click the image to enlarge it._ [REGION:fullwidth] -First, create an instance, or copy, of your SaveGame object, using the **Create Save Game Object** node. Make sure you set the Save Game Class dropdown to the name of your new SaveGame object Blueprint, -in this case, **MySaveGame**. Because the Create Save Game Object node creates a generic SaveGame object copy, you have to drag off of the **Return Value** pin and **Cast to MySaveGame**. Save -the result of the casting to a variable by using **Promote to Variable** so that you can reuse the SaveGame object easily later on. +First, create an instance, or copy, of your SaveGame object, using the **Create Save Game Object** node. Make sure you set the Save Game Class dropdown to the name of your new Blueprint, in this case, **MySaveGame**. The Create Save Game Object node will automatically change its output pin type to match the type you specify with the Save Game Class input, enabling you to use it directly, without a Cast To node. Save the resulting object to a variable by using **Promote to Variable** so that you can reuse the MySaveGame object you just created later on. ![](SaveGameBP_1.png) @@ -63,8 +61,7 @@ can be read from it. Again, this may not apply in all game implementations. ![](LoadGameBP_1.png) -You can use the **Load Game From Slot** node to create an instance of your SaveGame object Blueprint. Just like when you created a SaveGame object for saving information, you need to cast to your specific -SaveGame object Blueprint so that you can save the result to a variable for easy access later. +You can use the **Load Game From Slot** node to create an instance of your SaveGame object Blueprint. A Cast To node will be needed to treat the resulting object as a MySaveGame, which you will want to do so that you can store it in a variable for easy access later. ![](LoadGameBP_2.png) diff --git a/Engine/Documentation/Source/Gameplay/SaveGame/Blueprints/BP_SaveGame.KOR.udn b/Engine/Documentation/Source/Gameplay/SaveGame/Blueprints/BP_SaveGame.KOR.udn index bd713acf5e86..943bc31adf70 100644 --- a/Engine/Documentation/Source/Gameplay/SaveGame/Blueprints/BP_SaveGame.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/SaveGame/Blueprints/BP_SaveGame.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3397556 Availability:Public Title: 블루프린트로 게임 저장하기 Crumbs:%ROOT%, Gameplay, Gameplay/SaveGame @@ -33,9 +33,7 @@ SaveGame 오브젝트를 새로 생성하기 위해서는, [블루프린트 클 _전체 저장 구성 스냅샷입니다. 이미지를 클릭하면 원래 크기로 볼 수 있습니다._ [REGION:fullwidth] -먼저 **Create Save Game Object** 노드를 사용하여 SaveGame 오브젝트의 인스턴스를 생성 또는 복사합니다. **Save Game Class** 드롭다운 이름을 새로운 SaveGame 오브젝트 블루프린트 이름으로 설정했는지 확인합니다. -이 경우 **MySaveGame** 입니다. **Create Save Game Object** 노드가 범용 SaveGame 오브젝트 사본을 만들기 때문에, **Return Value** 핀을 드래그한 다음 **Cast to MySaveGame** 를 놓아야 합니다. -나중에 SaveGame 오브젝트를 쉽게 재사용하려면 **변수로 승격** 을 통해 변수에 대한 형변환 결과를 저장하세요. +먼저 **Create Save Game Object** 노드를 사용하여 SaveGame 오브젝트의 인스턴스를 생성 또는 복사합니다. **Save Game Class** 드롭다운 이름을 새로운 블루프린트 이름으로 설정했는지 확인합니다. 이 경우 **MySaveGame** 입니다. Create Save Game Object 노드는 출력 핀 유형이 Save Game Class 입력에 지정한 유형에 일치하도록 자동 변경하여 Cast To (형변환) 노드 없이 바로 사용할 수 있도록 해줍니다. 방금 생성한 MySaveGame 오브젝트를 나중에 쉽게 재사용하려면 **변수로 승격** 시켜주면 됩니다. ![](SaveGameBP_1.png) @@ -64,8 +62,7 @@ _전체 저장 셋업에 대한 스냅샷입니다. 이미지를 클릭하면 ![](LoadGameBP_1.png) -**Load Game From Slot** 노드를 사용하여 SaveGame 오브젝트 블루프린트의 인스턴스를 생성할 수 있습니다. 정보 저장을 위해 SaveGame 오브젝트를 생성했을 때와 마찬가지로, 특정 SaveGame 오브젝트 블루프린트로 -형변환시켜 줘야 그 결과를 변수에 저장하여 나중에 쉽게 접근할 수 있습니다. +**Load Game From Slot** 노드를 사용하여 SaveGame 오브젝트 블루프린트의 인스턴스를 생성할 수 있습니다. 결과 오브젝트를 MySaveGame 처럼 취급하기 위해서는 Cast To (형변환) 노드가 필요한데, 그래야 변수에 저장하여 나중에 쉽게 접근할 수 있습니다. ![](LoadGameBP_2.png) diff --git a/Engine/Documentation/Source/Gameplay/Tags/Tags.INT.udn b/Engine/Documentation/Source/Gameplay/Tags/Tags.INT.udn index 2ad0ee753960..75cdf0b30913 100644 --- a/Engine/Documentation/Source/Gameplay/Tags/Tags.INT.udn +++ b/Engine/Documentation/Source/Gameplay/Tags/Tags.INT.udn @@ -1,63 +1,59 @@ -Availability:Docs +Availability:Public Title:Gameplay Tags -Crumbs: %ROOT%, Engine, Engine/Gameplay +Crumbs: %ROOT% Description: Gameplay Tags can be used to identify, categorize, match, and filter objects. version: 4.15 skilllevel:Intermediate Parent:Engine/Gameplay +Order: type:overview +tags:Gameplay -## Gameplay Tags -**Gameplay Tags** are conceptual, hierarchical labels with user-defined names. These tags can have any number of hierarchical levels, separated by the "." character; for example, a Gameplay Tag with three levels would take the form of "Family.Genus.Species", with "Family" being the broadest identifier in the hierarchy, and "Species" being the most specific. Note that the existence of "Family.Genus.Species" implicitly means that "Family.Genus" and "Family" Gameplay Tags also exist. Individual tags are lightweight, and use the type `FGameplayTag`. Since game objects frequently have multiple tags, **Gameplay Tag Containers** (using the type `FGameplayTagContainer`) are provided, and can handle a variety of additional queries. Gameplay Tags (or Gameplay Tag Containers) can be added to any object to associate it with conceptual labels that can then be used to identify, match, categorize, or filter as needed for your project. +[toc(start:2 end:2)] -### Creating Gameplay Tags -Gameplay Tags must be added to the central tag dictionary for the engine to be aware of them. This can be done in three ways via editor functionality. Tags can be added manually in the **Project Settings** menu, with .ini files, through creating data table assets. All three methods are set up under **Project Settings**, by opening the **Gameplay Tags** tab under the **Project** section. +**Gameplay Tags** are conceptual, hierarchical labels with user-defined names. These tags can have any number of hierarchical levels, separated by the "." character; for example, a Gameplay Tag with three levels would take the form of "Family.Genus.Species", with "Family" being the broadest identifier in the hierarchy, and "Species" being the most specific. Note that the existence of "Family.Genus.Species" implicitly means that "Family.Genus" and "Family" Gameplay Tags also exist. Individual tags are lightweight, and use the type `FGameplayTag`. Since game objects frequently have multiple tags, **Gameplay Tag Containers** (using the type `FGameplayTagContainer`) are provided, and can handle a variety of additional queries. Gameplay Tags (or Gameplay Tag Containers) can be added to any project, associating objects with conceptual labels that can then be used to identify, match, categorize, or filter them (as needed) for your project. +## Creating Gameplay Tags +Gameplay Tags must be added to the central tag dictionary for the engine to be aware of them. This can be done in three ways via editor functionality. Tags can be added manually in the **Project Settings** menu, with .ini files, or by creating data table assets. + +All three methods are set up under **Project Settings**, by opening the **Gameplay Tags** tab under the **Project** section. ![Gameplay Tags menu in Project Settings](ProjectSettings.png) -#### Manually Adding Tags +### Manually Adding Tags -The easiest way to add gameplay tags is to use enter them manually in the **Project Settings** menu. By checking the **Import Tags From Config** option, `Config/DefaultGameplayTags.Ini` will be loaded, as well as all Gameplay Tags in any .Ini files found under the `Config/Tags` path. An option labeled **Add New Gameplay Tag** will appear, and this option can be used to add new Gameplay Tags to any existing Gameplay Tag .Ini files, including the default file. Tags added in this way will also have an optional field for entering a brief description, which will appear as a tooltip in the editor. +The easiest way to add Gameplay Tags is to enter them manually in the **Project Settings** menu. By checking the **Import Tags From Config** option, `Config/DefaultGameplayTags.ini` will be loaded, as well as all Gameplay Tags in any .ini files found under the `Config/Tags` path. An option labeled **Add New Gameplay Tag** will appear, and this option can be used to add new Gameplay Tags to any existing Gameplay Tag .ini files, including the default file. Tags added in this way will also have an optional field for entering a brief description, which will appear as a tooltip in the editor. ![Manually Adding Tags in Project Settings](AddNewTag.png) -#### Editing .Ini Files Directly -To add tags using your own .Ini files, the **Import Tags From Config** option must be enabled. Gameplay Tags will then be loaded from each of the .Ini files found your project's `Config/Tags/` path, which are easy to hand-edit. If these edits are made while the editor is running, turning the **Import Tags From Config** option off and back on will reload the files. The format within these files looks like this: - - [UserTags] - GameplayTags=Vehicle.Air.Helicopter - GameplayTags=Movement.Flying - GameplayTags=Movement.Hovering - -If a hand-written file is modified by the editor's **Add New Gameplay Tag** feature, all of the old tags, as well as the new tag, will be copied into a new section. The "[UserTags]" section will remain in the file, but will be ignored during load operations. For example, if "Movement.Landing" were added to our file above, the new file would look like this: - - [UserTags] - GameplayTags=Vehicle.Air.Helicopter - GameplayTags=Movement.Flying - GameplayTags=Movement.Hovering +### Editing .ini Files Directly +To add tags using your own .ini files, the **Import Tags From Config** option must be enabled. Gameplay Tags will then be loaded from each of the .ini files found your project's `Config/Tags/` path, which are easy to hand-edit. If these edits are made while the editor is running, turning the **Import Tags From Config** option off and back on will reload the files. The format within these files looks like this: [/Script/GameplayTags.GameplayTagsList] - GameplayTagList=(Tag="Vehicle.Air.Helicopter",DevComment="") + GameplayTagList=(Tag="Vehicle.Air.Helicopter",DevComment="This is a custom tooltip!") GameplayTagList=(Tag="Movement.Flying",DevComment="") GameplayTagList=(Tag="Movement.Hovering",DevComment="") GameplayTagList=(Tag="Movement.Landing",DevComment="") -[REGION:note]It is not recommended to hand-edit a tag .Ini file after using the **Project Settings** menu to add tags to that file.[/REGION] +This method is convenient for your teammates to add their own tags, since .ini files in `Config/Tags` are easily-edited text files that can be named with any file-naming convention you like. -This method is very convenient as a way to enable members of your team to add their own tags, since .Ini files in `Config/Tags` are easily-edited text files that can be named with any file-naming convention you like. +A "Developer Tag" config file can be used by going to the **Gameplay Tags Developer** menu within **Project Settings**, and filling in the **Developer Config Name** with your desired filename. If enabled, this will save all of the tags that were added to the default .ini file (by you), into an .ini file that you specify. Your .ini file will reside in the `Config/Tags` folder, and can be passed to other developers or submitted to your source control system without further modification. This can be useful on large projects with thousands of tags, or as a way to separate tags created by specific developers or for use with specific game features. This is entirely optional, but it can be helpful for some teams and workflows to have certain tags stored in separate files. -A "Developer Tag" config file can be used by going to the **Gameplay Tags Developer** menu within **Project Settings** and filling in the **Developer Config Name** with your desired filename. If set, this will save all tags you personally add to the default .Ini file to your specified .Ini file instead. Your .Ini file will reside in the `Config/Tags` folder, and can be passed to other developers or submitted to your source control system without further modification. This can be useful on large projects with thousands of tags, or simply as a way to separate tags created by specific developers or for use with specific game features. This is entirely optional, but it can be helpful for some teams and workflows to have certain tags stored in separate files. - -#### Data Table Assets -Finally, tags can be added via [DataTable](Gameplay/DataDriven/#datatables) assets with the row type `GameplayTagTableRow`. This is especially useful for importing Gameplay Tags from an external source, such as an Excel spreadsheet file. Once your asset is created, add it to the **GameplayTagTableList** in the **Project Settings** menu and all tags contained within it will be added to the **Gameplay Tag Manager**. Note that this system supports multiple assets being listed, so you can separate out your project's tags into different spreadsheets if this helps your workflow or organization. +### Data Table Assets +Finally, tags can be added via [DataTable](Gameplay/DataDriven/#datatables) assets with the row type `GameplayTagTableRow`. This is especially useful for importing Gameplay Tags from an external source, such as an Excel spreadsheet file, but you can create your own without a file to import and work with it in-editor. Once your asset is created, add it to the **GameplayTagTableList** in the **Project Settings** menu and all tags contained within it will be added to the **Gameplay Tag Manager**. Note that this system supports multiple assets being listed, so you can separate out your project's tags into different spreadsheets (if this helps your workflow or organization). ![Gameplay Tags in a Data Table Asset](DataAsset.png) -### Managing Gameplay Tags -Once your Gameplay Tags have been added, you can manage them by searching for references to them, deleting them, or renaming them. All of these actions can be accessed with the caret dropdown next to a tag in the **Project Settings** menu. Tags can only be deleted in this menu if they were added via a .Ini file (either hand-edited or added via the **Project Settings** menu), and are not referenced by anything else. Renamed tags will cause additions to be made to the GameplayTagRedirects list, and any renamed tags will be silently fixed on load. +[REGION:caption]Data Table Assets use Unreal Engine assets rather than .ini files, and can be viewed and changed while the editor is running, similar to other game assets.[/REGION] -#### Gameplay Tag Test Operations -There are a number of test operations, all based on the concept of matching tags to other tags, that can be performed on Gameplay Tags and Gameplay Tag Containers. Each of these functions will be called on a Gameplay Tag or Gameplay Tag Container, and will take a single Gameplay Tag or Gameplay Tag Container as a parameter. +## Managing Gameplay Tags +After your Gameplay Tags have been added, you can manage them by searching for references to them, deleting them, or renaming them. All of these actions can be accessed with the caret dropdown next to a tag in the **Project Settings** menu. Tags can only be deleted in this menu if they were added via a .ini file (either hand-edited or added via the **Project Settings** menu), and are not referenced by anything else. Renamed tags will cause additions to be made to the GameplayTagRedirects list, and any renamed tags will be silently fixed on load. + +![Editing Individual Gameplay Tags In Project Settings](ProjectSettingsEditTag.png) + +[REGION:caption]Gameplay Tags can be edited in Project Settings via a caret dropdown.[/REGION] + +### Gameplay Tag Test Operations +There are a number of test operations, all based on the concept of matching tags to other tags, that can be performed on Gameplay Tags and Gameplay Tag Containers. Each of these functions will be called on a Gameplay Tag or Gameplay Tag Container and will take a single Gameplay Tag or Gameplay Tag Container as a parameter. The following table details the operations available for tags and tag containers. In this table, the format "A.1" represents a single Gameplay Tag, while "{A.1}" represents that same tag as part of a Gameplay Tag Container. A container with multiple tags will be of the format "{A.1, B.1}". @@ -76,25 +72,41 @@ The following table details the operations available for tags and tag containers | {A.1, B.1} | HasAll | {A, B} | true | | {A.1, B.1} | HasAllExact | {A, B} | false | -Note that providing empty or default Gameplay Tag Containers as the input parameter will cause all operations to return false, except for `HasAll`, `HasAllExact`, `MatchesAll`, and `MatchesAllExact`. The justification for this is that there are no tags in the parameter container that aren't in the source set, and this is consistent with set theory. +Note that providing empty or default Gameplay Tag Containers as the input parameter will cause all operations to return false, except for `HasAll`, `HasAllExact`, `MatchesAll`, and `MatchesAllExact`. The justification for this, is that there are no tags in the parameter container that are missing from the source set. -### Gameplay Tag Queries +As an example, the following Blueprint will use some of the above-named operations to detect whether a Gameplay Tag Container has `TestTag.One` or `TestTag.Three`, but not both tags, and not `TestTag.Two` (when the test Actor is spawned into a game). For this test, we will use literal container values in our Blueprint for our test, but use a Blueprint (or C++) variable for our Actor's container. + +![Sample Gameplay Tag Operations In A Blueprint](TagOperationsInBP.png) + +## Gameplay Tag Queries Certain types of queries for Gameplay Tag Containers can be stored in a **Gameplay Tag Query** variable in order to make them data-driven, perform them in many places without having to edit more than one variable or piece of code, and speed them up. Gameplay Tag Queries are limited to three basic tests: -**Any Tags Match** succeeds if at least one tag from the query is found in the container. -**All Tags Match** succeeds if there are no tags in the query that are not also found in the container. (This includes the case that no tags are present in the query.) -**No Tags Match** succeeds if there are no tags in the query that are also found in the container. (This includes the case that no tags are present in the query.) + +* **Any Tags Match** succeeds if at least one tag from the query is found in the container. + +* **All Tags Match** succeeds if there are no tags in the query that are not also found in the container. _This includes the case that no tags are present in the query._ + +* **No Tags Match** succeeds if there are no tags in the query that are also found in the container. _This includes the case that no tags are present in the query._ + However, those tests can be combined together via three larger expressions, each of which contains an array of additional expressions or tests: -**Any Expressions Match** succeeds when any of its sub-expressions or tests succeeds. -**All Expressions Match** succeeds when none of its sub-expressions or tests fail. (This includes the case that no sub-expressions or tests are present in the query.) -**No Expressions Match** succeeds when none of its sub-expressions or tests succeed. (This includes the case that no sub-expressions or tests are present in the query.) + +* **Any Expressions Match** succeeds when any of its sub-expressions or tests succeeds. + +* **All Expressions Match** succeeds when none of its sub-expressions or tests fail. _This includes the case that no sub-expressions or tests are present in the query._ + +* **No Expressions Match** succeeds when none of its sub-expressions or tests succeed. _This includes the case that no sub-expressions or tests are present in the query._ + [REGION:note]Note that all three test types refer to "exact" matching as per the table of operations above.[/REGION] -![Sample Gameplay Tag Query](TagQuery.png) +We can recreate our earlier test example where we required either `TestTag.One` or `TestTag.Three` (but not both) to be in the source container, having required that `TestTag.Two` not be, using a single Gameplay Tag Query. For this test, we will use Blueprint (or C++) variables exclusively, although literal values are also supported. Here is our test query variable: -In the above sample query, either TestTag.One or TestTag.Three (but not both) must be in the source container, and TestTag.Two must not be. +![Sample Gameplay Tag Query Variable](TagQuery.png) -### Using Gameplay Tags In Your Game +With this query set up, we can evaluate our Gameplay Tag Container against it in our test Actor's Blueprint as follows: + +![Sample Gameplay Tag Query In A Blueprint](TagQueryInBP.png) + +## Using Gameplay Tags In Your Game To apply the tags you have created to objects in your game, add Gameplay Tags (C++ type `FGameplayTag`) or Gameplay Tag Containers (C++ type `FGameplayTagContainer`) properties to the objects. You can also add **Gameplay Tag Queries** (C++ type `FGameplayTagQuery`) to your objects as desired, or you can use the tag operations directly in Blueprints or C++ code. Once these properties have been added, you can edit them from the code or editor, like any other variable. -### Accessing Gameplay Tags Quickly (Requires C++) -The `IGameplayTagAssetInterface` can be implemented in C++. Doing so, and overriding the `GetOwnedGameplayTags` function, will create a Blueprint-accessible way to populate a Gameplay Tag Container with the tags associated with that object. In most cases, this just means copying the tags from the base class into a new container, but your implementation of the class could gather tags from multiple containers, call a Blueprint function to get access to Blueprint-declared tags, or whatever your object requires. The advantage of this interface is that it enables you to interact with a variety of disparate object types in a standardized way, so that you can get an object's tags without explicitly casting the object and then writing custom code for each possible type to get the correct tag variable (or variables). This is especially useful on larger projects, where it can help to avoid hard-to-reproduce bugs and make code cleaner, faster, and easier to maintain. +## Quickly Accessing Gameplay Tags in C++ +The `IGameplayTagAssetInterface` can be implemented in C++. Doing so, and overriding the `GetOwnedGameplayTags` function, will create a Blueprint-accessible way to populate a Gameplay Tag Container with the tags associated with that object. In most cases, this just means copying the tags from the base class into a new container, but your implementation of the class could gather tags from multiple containers, or call a Blueprint function to get access to Blueprint-declared tags, or whatever your object requires. The advantage of this interface is that it enables you to interact with a variety of disparate object types in a standardized way, so that you can get an object's tags without explicitly casting the object and then writing custom code for each possible type to get the correct tag variable (or variables). This is especially useful on larger projects, where it can help to avoid (hard-to-reproduce) bugs and make code cleaner, faster, and easier to maintain. diff --git a/Engine/Documentation/Source/Gameplay/Tags/Tags.JPN.udn b/Engine/Documentation/Source/Gameplay/Tags/Tags.JPN.udn index 8bbfcb230546..18d1e75a64cb 100644 --- a/Engine/Documentation/Source/Gameplay/Tags/Tags.JPN.udn +++ b/Engine/Documentation/Source/Gameplay/Tags/Tags.JPN.udn @@ -1,68 +1,64 @@ -INTSourceChangelist:0 -Availability:Docs -Title:Gameplay Tags -Crumbs: %ROOT%, Engine, Engine/Gameplay -Description: Gameplay Tags can be used to identify, categorize, match, and filter objects. -version: 4.15 +INTSourceChangelist:3484974 +Availability:Public +Title:Gameplay Tag +Crumbs: %ROOT% +Description:Gameplay Tag を使ってオブジェクトを特定、分類、マッチング、フィルタリングすることができます。 +version:4.15 skilllevel:Intermediate Parent:Engine/Gameplay +Order: type:overview +tags:Gameplay -## Gameplay Tags -**Gameplay Tags** are conceptual, hierarchical labels with user-defined names. These tags can have any number of hierarchical levels, separated by the �.� character; for example, a Gameplay Tag with three levels would take the form of �Family.Genus.Species�, with �Family� being the broadest identifier in the hierarchy, and �Species� being the most specific. Note that the existence of �Family.Genus.Species� implicitly means that �Family.Genus� and �Family� Gameplay Tags also exist. Individual tags are lightweight, and use the type `FGameplayTag`. Since game objects frequently have multiple tags, **Gameplay Tag Containers** (using the type `FGameplayTagContainer`) are provided, and can handle a variety of additional queries. Gameplay Tags (or Gameplay Tag Containers) can be added to any object to associate it with conceptual labels that can then be used to identify, match, categorize, or filter as needed for your project. +[toc(start:2 end:2)] -### Creating Gameplay Tags -Gameplay Tags must be added to the central tag dictionary for the engine to be aware of them. This can be done in three ways via editor functionality. Tags can be added manually in the **Project Settings** menu, with .ini files, through creating data table assets. All three methods are set up under **Project Settings**, by opening the **Gameplay Tags** tab under the **Project** section. +**Gameplay Tag** は概念的なものであり、ユーザー定義の名前を持つ階層ラベルです。こうしたタグは階層レベルをいくつでも持つことが可能であり、"." 文字で区切られます。例えば 3 階層の Gameplay Tag は "Family.Genus.Species" という形式になります。"Family" は階層で最も広い範囲の識別子であり、"Species" が最も限定的なものになります。"Family.Genus.Species" の存在は、 "Family.Genus" と "Family" Gameplay のタグも存在することを暗に示しています。個々のタグは軽量であり、型 `FGameplayTag` を使用します。ゲーム オブジェクトは複数のタグを持つことが多いため、**Gameplay Tag Container** (型 `FGameplayTagContainer` を使用) が用意されており、様々なクエリーを追加で処理することができます。Gameplay Tag (またはGameplay Tag Container) を任意のプロジェクトに追加してオブジェクトを概念的なラベルに関連付けます。次にこれを使ってプロジェクトでこれらを (必要に応じて) 特定、マッチング、分類、フィルタリングします。 +## Gameplay Tag の作成 +エンジンに認識させるために Gameplay Tag をベースとなるタグ辞書に追加しなければなりません。これはエディタの機能を使って次の 3 種類の方法で行うことができます。タグを手動で .ini ファイルを使って、またはデータ テーブル アセットを作成して、**[Project Settings (プロジェクト設定)]** メニューに追加することができます。 + +こうした 3 種類の方法は、**[Project Settings]** で **[Project]** セクションの **[Gameplay Tag]** を開いてセットアップします。 ![Gameplay Tags menu in Project Settings](ProjectSettings.png) -#### Manually Adding Tags +### 手動でタグを追加する -The easiest way to add gameplay tags is to use enter them manually in the **Project Settings** menu. By checking the **Import Tags From Config** option, `Config/DefaultGameplayTags.Ini` will be loaded, as well as all Gameplay Tags in any .Ini files found under the `Config/Tags� path. An option labeled **Add New Gameplay Tag** will appear, and this option can be used to add new Gameplay Tags to any existing Gameplay Tag .Ini files, including the default file. Tags added in this way will also have an optional field for entering a brief description, which will appear as a tooltip in the editor. +Gameplay Tag を追加する最も簡単な方法は **[Project Settings]** メニューで手入力するやり方です。**[Import Tags From Config]** オプションにチェックを入れると、`Config/DefaultGameplayTags.ini` がロードされます。`Config/Tags` パスの.ini ファイルにあるすべてのゲームプレイ タグもロードされます。**[Add New Gameplay Tag]** とラベル付けされたオプションが表示されます。このオプションを使って新規ゲームプレイ タグをデフォルト ファイルを含む既存の Gameplay Tag .ini ファイルに追加します。このように追加されたタグには、短い説明を入力するオプション欄があります。これは、エディタでツールチップとして表示されます。 ![Manually Adding Tags in Project Settings](AddNewTag.png) -#### Editing .Ini Files Directly -To add tags using your own .Ini files, the **Import Tags From Config** option must be enabled. Gameplay Tags will then be loaded from each of the .Ini files found your project�s `Config/Tags/` path, which are easy to hand-edit. If these edits are made while the editor is running, turning the **Import Tags From Config** option off and back on will reload the files. The format within these files looks like this: - - [UserTags] - GameplayTags=Vehicle.Air.Helicopter - GameplayTags=Movement.Flying - GameplayTags=Movement.Hovering - -If a hand-written file is modified by the editor�s **Add New Gameplay Tag** feature, all of the old tags, as well as the new tag, will be copied into a new section. The �[UserTags]� section will remain in the file, but will be ignored during load operations. For example, if �Movement.Landing� were added to our file above, the new file would look like this: - - [UserTags] - GameplayTags=Vehicle.Air.Helicopter - GameplayTags=Movement.Flying - GameplayTags=Movement.Hovering +### .ini ファイルを直接編集する +.ini ファイルを使ってタグを追加するには **[Import Tags From Config]** オプションを有効にしなければなりません。プロジェクトの `Config/Tags/` パスにある各 .ini ファイルから Gameplay Tag がロードされ、手作業で簡単に編集することができます。エディタ実行中にこうした編集が加えられると、**Import Tags From Config** オプションをオフにし、オンに戻すとファイルを再ロードします。ファイル形式は次のようになります。 [/Script/GameplayTags.GameplayTagsList] - GameplayTagList=(Tag="Vehicle.Air.Helicopter",DevComment="") + GameplayTagList=(Tag="Vehicle.Air.Helicopter",DevComment="This is a custom tooltip!") GameplayTagList=(Tag="Movement.Flying",DevComment="") GameplayTagList=(Tag="Movement.Hovering",DevComment="") GameplayTagList=(Tag="Movement.Landing",DevComment="") -[REGION:note]It is not recommended to hand-edit a tag .Ini file after using the **Project Settings** menu to add tags to that file.[/REGION] +これはチームのメンバーが独自のタグを追加できる便利な方法です。`Config/Tags` の .ini ファイルは簡単に編集できるテキスト ファイルであり、任意のファイル命名規則に従い名前を付けることができるからです。 -This method is very convenient as a way to enable members of your team to add their own tags, since .Ini files in `Config/Tags` are easily-edited text files that can be named with any file-naming convention you like. +**[Project Settings]** 内の **[Gameplay Tags Developer]** メニューに進み "Developer Tag" config ファイルを使用し、お好みのファイル名を **Developer Config Name** に入力します。有効にすると、デフォルトの .ini ファイルに自分で追加したすべてのタグを指定した .ini ファイルに保存します。.ini ファイルは `Config/Tags` フォルダにあり、他のデベロッパーに渡したり、さらに修正を加えることなくソース コントロール システムにサブミットすることができます。これは非常に多くのタグを持つ大規模プロジェクトで役立ちます。あるいは、特定のデベロッパーが作成したタグや特定のゲーム機能で使用するタグを区別する手段として役立ちます。これは全くのオプションですが、特定のタグを別個のファイルに保存する一部のチームやワークフローで役立つでしょう。 -A �Developer Tag� config file can be used by going to the **Gameplay Tags Developer** menu within **Project Settings** and filling in the **Developer Config Name** with your desired filename. If set, this will save all tags you personally add to the default .Ini file to your specified .Ini file instead. Your .Ini file will reside in the `Config/Tags` folder, and can be passed to other developers or submitted to your source control system without further modification. This can be useful on large projects with thousands of tags, or simply as a way to separate tags created by specific developers or for use with specific game features. This is entirely optional, but it can be helpful for some teams and workflows to have certain tags stored in separate files. - -#### Data Table Assets -Finally, tags can be added via [DataTable](Gameplay/DataDriven/#datatables) assets with the row type `GameplayTagTableRow`. This is especially useful for importing Gameplay Tags from an external source, such as an Excel spreadsheet file. Once your asset is created, add it to the **GameplayTagTableList** in the **Project Settings** menu and all tags contained within it will be added to the **Gameplay Tag Manager**. Note that this system supports multiple assets being listed, so you can separate out your project�s tags into different spreadsheets if this helps your workflow or organization. +### Data Table アセット +最後に行の型が `GameplayTagTableRow` の [データ テーブル](Gameplay/DataDriven/#データテーブル) アセットを介してタグを追加することができます。これは Excel のスプレッドシート ファイルなどの外部ソースから Gameplay Tag をインポートする際に特に便利です。しかし、インポートするファイルがなくても独自のものを作成してインエディタで作業することができます。アセットを作成したらそれを **[Project Settings]** メニューの **[GameplayTagTableList]** に追加し、その中に入っているすべてのタグが **[Gameplay Tag Manager]** に追加されます。このシステムでは、リストされている複数アセットに対応します。そのため、ワークフローや整理に役立つならば、プロジェクトのタグを複数のスプレッド シートに分けることもできます。 ![Gameplay Tags in a Data Table Asset](DataAsset.png) -### Managing Gameplay Tags -Once your Gameplay Tags have been added, you can manage them by searching for references to them, deleting them, or renaming them. All of these actions can be accessed with the caret dropdown next to a tag in the **Project Settings** menu. Tags can only be deleted in this menu if they were added via a .Ini file (either hand-edited or added via the **Project Settings** menu), and are not referenced by anything else. Renamed tags will cause additions to be made to the GameplayTagRedirects list, and any renamed tags will be silently fixed on load. +[REGION:caption]Data Table アセットは .ini ファイルではなくアンリアル エンジンのアセットを使用します。他のゲーム アセットと同様にエディタ実行中に表示したり、変更することができます。[/REGION] -#### Gameplay Tag Test Operations -There are a number of test operations, all based on the concept of matching tags to other tags, that can be performed on Gameplay Tags and Gameplay Tag Containers. Each of these functions will be called on a Gameplay Tag or Gameplay Tag Container, and will take a single Gameplay Tag or Gameplay Tag Container as a parameter. +## Gameplay Tag を管理する +Gameplay Tag を追加後、それらに対する参照を検索、削除、名前変更して管理することができます。こうした操作をするには、**[Project Settings]** メニューでタグのとなりにある下向き三角のドロップダウンを使用します。タグは ini ファイルで追加した場合に限り (手作業で編集または **Project Settings** メニューから追加)、このメニューから削除可能であり、他のものから参照されません。名前変更したタグは、GameplayTagRedirects リストに入り、名前変更したタグがあればロード中にサイレント修正されます。 -The following table details the operations available for tags and tag containers. In this table, the format �A.1� represents a single Gameplay Tag, while �{A.1}� represents that same tag as part of a Gameplay Tag Container. A container with multiple tags will be of the format �{A.1, B.1}�. +![Editing Individual Gameplay Tags In Project Settings](ProjectSettingsEditTag.png) -| Source | Function/Operation | Input Parameter | Return Value | +[REGION:caption]Gameplay Tag は下向き三角のドロップダウンから [Project Settings (プロジェクト設定)] で編集することができます。[/REGION] + +### Gameplay Tag のテスト演算 +テスト演算は多数ありますが、そのすべてはタグを他のタグにマッチングさせるという概念に基づいています。これは、Gameplay Tag と Gameplay Tag Container で行うことができます。こうした関数はそれぞれ、Gameplay Tag または Gameplay Tag Container と呼ばれ、単独のGameplay Tag または Gameplay Tag Container をパラメータとして取ります。 + +以下の表は、タグとタグ コンテナで利用可能な演算の詳細です。この表ではフォーマット、"A.1" は単独の Gameplay Tag を表します。 "{A.1}" は Gameplay Tag Container の一部である同じタグを表しています。複数のタグを持つコンテナは、"{A.1, B.1}" というフォーマットになります。 + +| ソース| 関数/演算 | 入力パラメータ | 戻り値 | | --- | --- | --- | --- | | A.1 | MatchesTag | A | true | | A.1 | MatchesTagExact (or ==) | A | false | @@ -77,25 +73,41 @@ The following table details the operations available for tags and tag containers | {A.1, B.1} | HasAll | {A, B} | true | | {A.1, B.1} | HasAllExact | {A, B} | false | -Note that providing empty or default Gameplay Tag Containers as the input parameter will cause all operations to return false, except for `HasAll`, `HasAllExact`, `MatchesAll`, and `MatchesAllExact`. The justification for this is that there are no tags in the parameter container that aren�t in the source set, and this is consistent with set theory. +空すなわちデフォルトの Gameplay Tag Container を入力パラメータとして与えると、`HasAll`、 `HasAllExact`、 `MatchesAll`、および `MatchesAllExact` 以外の全ての演算で false を戻すようになります。ソースの集合にないタグが、このパラメータのコンテナにないからです。 -### Gameplay Tag Queries -Certain types of queries for Gameplay Tag Containers can be stored in a **Gameplay Tag Query** variable in order to make them data-driven, perform them in many places without having to edit more than one variable or piece of code, and speed them up. Gameplay Tag Queries are limited to three basic tests: -**Any Tags Match** succeeds if at least one tag from the query is found in the container. -**All Tags Match** succeeds if there are no tags in the query that are not also found in the container. (This includes the case that no tags are present in the query.) -**No Tags Match** succeeds if there are no tags in the query that are also found in the container. (This includes the case that no tags are present in the query.) -However, those tests can be combined together via three larger expressions, each of which contains an array of additional expressions or tests: -**Any Expressions Match** succeeds when any of its sub-expressions or tests succeeds. -**All Expressions Match** succeeds when none of its sub-expressions or tests fail. (This includes the case that no sub-expressions or tests are present in the query.) -**No Expressions Match** succeeds when none of its sub-expressions or tests succeed. (This includes the case that no sub-expressions or tests are present in the query.) -[REGION:note]Note that all three test types refer to �exact� matching as per the table of operations above.[/REGION] +例えば、以下のブループリントでは、テスト アクタがゲームにスポーンされると上記の演算の一部を使って、ある Gameplay Tag Container に、`TestTag.One` または `TestTag.Three` のいずれかがあるかを検出しますが、両方のタグは検出せず、`TestTag.Two` も検出しません。ここではテスト目的のためにブループリントのリテラル コンテナ値を使いますが、アクタのコンテナに対してブループリント (または C++) の変数を使います。 -![Sample Gameplay Tag Query](TagQuery.png) +![Sample Gameplay Tag Operations In A Blueprint](TagOperationsInBP.png) -In the above sample query, either TestTag.One or TestTag.Three (but not both) must be in the source container, and TestTag.Two must not be. +## Gameplay Tag のクエリー +Gameplay Tag コンテナの一部のクエリーのタイプは、**Gameplay Tag Query** 変数に格納してデータ駆動にし、ひとつの変数やコードの一部を編集する必要なく多くの場所で実行し、スピードアップすることができます。Gameplay Tag のクエリーは以下の 3 種類の基本テストに限定されます。 -### Using Gameplay Tags In Your Game -To apply the tags you have created to objects in your game, add Gameplay Tags (C++ type `FGameplayTag`) or Gameplay Tag Containers (C++ type `FGameplayTagContainer`) properties to the objects. You can also add **Gameplay Tag Queries** (C++ type `FGameplayTagQuery`) to your objects as desired, or you can use the tag operations directly in Blueprints or C++ code. Once these properties have been added, you can edit them from the code or editor, like any other variable. +* **Any Tags Match** はクエリーのタグが最低 1 つコンテナで見つかれば成功です。 -### Accessing Gameplay Tags Quickly (Requires C++) -The `IGameplayTagAssetInterface` can be implemented in C++. Doing so, and overriding the `GetOwnedGameplayTags` function, will create a Blueprint-accessible way to populate a Gameplay Tag Container with the tags associated with that object. In most cases, this just means copying the tags from the base class into a new container, but your implementation of the class could gather tags from multiple containers, call a Blueprint function to get access to Blueprint-declared tags, or whatever your object requires. The advantage of this interface is that it enables you to interact with a variety of disparate object types in a standardized way, so that you can get an object�s tags without explicitly casting the object and then writing custom code for each possible type to get the correct tag variable (or variables). This is especially useful on larger projects, where it can help to avoid hard-to-reproduce bugs and make code cleaner, faster, and easier to maintain. +* **All Tags Match** は、クエリーのタグでコンテナでも見つからなかったものがない場合に成功します。 _これには、クエリーにタグが何もない場合も含まれます。_ + +* **No Tags Match** は、クエリーのタグでコンテナで見つかったものがない場合、成功です。 _これには、クエリーにタグが全く存在しない場合が含まれます。_ + +ただし、こうしたテストは 3 つの大きな表現式を組み合わせてテストすることもできます。それぞれ、追加の表現式やテストの配列を含みます。 + +* **Any Expressions Match** は、その部分式やテストが成功すれば成功です。 + +* **All Expressions Match** は、その部分式やテストがひとつも失敗しない場合に成功になります。 _これには部分式やテストがクエリーに全く存在しない場合を含みます。_ + +* **No Expressions Match** は、その部分式やテストがひとつも成功しない場合に成功になります。 _これには部分式やテストがクエリーに全く存在しない場合を含みます。_ + +[REGION:note]上記の 3 種類のテストは、上の演算の表の「完全一致」を表しています。[/REGION] + +上記のテスト サンプル、`TestTag.One` または `TestTag.Three` のいずれかひとつ (両方はだめ) はソース コンテナに入っていて、`TestTag.Two` はコンテナに入っていないことを求めることを、ひとつの Gameplay Tag Query を使って再現することができます。このテストでは、リテラル値もサポートしますが、ブループリント (または C++) の変数だけを使います。以下はテスト クエリーの変数です。 + +![Sample Gameplay Tag Query Variable](TagQuery.png) + +このクエリーをセットアップした状態で、以下のようにテストアクタのブループリントで Gameplay Tag Container を評価することができます。 + +![Sample Gameplay Tag Query In A Blueprint](TagQueryInBP.png) + +## ゲームで Gameplay Tags を使用する +作成したタグをゲーム内のオブジェクトに適用するには、Gameplay Tag (C++ 型 `FGameplayTag`) または Gameplay Tag Container (C++ 型 `FGameplayTagContainer`) のプロパティをオブジェクトに追加します。**Gameplay Tag Queries** (C++ 型 `FGameplayTagQuery`) を必要に応じてオブジェクトに追加するか、ブループリントまたは C++ コードで直接タグ演算を使用することができます。こうしたプロパティを追加したら、他の変数と同様にコードまたはエディタで編集することができます。 + +## C++ で Gameplay Tag に迅速にアクセスする +`IGameplayTagAssetInterface` は C++ で実装可能です。実装し、`GetOwnedGameplayTags` 関数をオーバーライドすると、ブループリントで、そのオブジェクトに関連するタグを Gameplay Tag Container に入れられるようになります。ほとんどの場合、これは単に基底クラスから新規コンテナにタグをコピーすることを意味しますが、クラスを実装すると複数のコンテナからタグを集めて、ブループリントの関数を呼び出してブループリントで宣言したタグにアクセスしたり、オブジェクトが必要とすることを行います。このインタフェースのメリットは標準化された方法で多様な異なるオブジェクトの型とインタラクションできるようにし、明示的にオブジェクトをキャストせずにオブジェクトのタグを取得することができます。次に各型に対してカスタム コードを記述し、正しいタグ変数を取得します。これは大規模プロジェクトで役立ちます。 (再現が難しい) バグの回避や、コードをクリーンにし高速化し、容易に維持管理できるようにします。 diff --git a/Engine/Documentation/Source/Gameplay/Tags/Tags.KOR.udn b/Engine/Documentation/Source/Gameplay/Tags/Tags.KOR.udn index 408ca2e6f9a8..c3e481b7114d 100644 --- a/Engine/Documentation/Source/Gameplay/Tags/Tags.KOR.udn +++ b/Engine/Documentation/Source/Gameplay/Tags/Tags.KOR.udn @@ -1,62 +1,59 @@ -Availability:Docs +INTSourceChangelist:3484974 +Availability:Public Title:게임플레이 태그 -Crumbs: %ROOT%, Engine, Engine/Gameplay +Crumbs: %ROOT% Description: 게임플레이 태그는 오브젝트 식별, 분류, 일치, 필터링에 사용 가능합니다. version: 4.15 skilllevel:Intermediate Parent:Engine/Gameplay +Order: type:overview +tags:Gameplay + +[toc(start:2 end:2)] -## 게임플레이 태그 **Gameplay Tags** (게임플레이 태그)는 사용자 정의 이름을 붙인 개념적 계층형 라벨입니다. 이 태그는 "." 글자로 구분되는 계층구조를 몇 단계든 가질 수 있습니다. 예를 들어 세 단계의 게임플레이 태그는 "Family.Genus.Species" 형태를 띄며, "Family" 가 계층구조에서 가장 넓은 식별자가 되고, "Species" 는 가장 구체적인 것이 됩니다. 참고로 "Family.Genus.Species" 가 존재한ㄴ다는 것은 "Family.Genus" 와 "Family" 게임플레이 태그 역시 존재한다는 것을 암시합니다. 개별 태그는 경량이며, `FGameplayTag` 를 사용합니다. 게임 오브젝트는 자주 다수의 태그를 갖기에 (`FGameplayTagContainer` 유형을 사용하는) **Gameplay Tag Containers** (게임플레이 태그 컨테이너)가 제공되어, 다양한 추가 질의 처리가 가능합니다. 게임플레이 태그 (또는 게임플레이 태그 컨테이너)는 아무 오브젝트에 추가하고 개념적 라벨을 할당한 뒤 프로젝트의 요구에 따라 식별, 일치, 분류, 필터 적용이 가능합니다. ### 게임플레이 태그 생성 -게임플레이 태그는 엔진의 중앙 태그 디렉토리에 추가해야 인식이 가능합니다. 에디터 기능을 통해 세 가지 방식으로 가능합니다. 태그는 **프로젝트 세팅** 메뉴에서, .ini 파일을 통해, 데이터 테이블 애셋을 생성하여, 총 세 가지 방법으로 수동 추가할 수 있습니다. 이 세 가지 방법 모두 **프로젝트 세팅** 아래에서 **프로젝트** 섹션 아래 **Gameplay Tags** 탭에서 구성 가능합니다. +게임플레이 태그는 엔진의 중앙 태그 디렉토리에 추가해야 인식이 가능합니다. 에디터 기능을 통해 세 가지 방식으로 가능합니다. 태그는 **프로젝트 세팅** 메뉴에서, .ini 파일을 통해, 데이터 테이블 애셋을 생성하여, 총 세 가지 방법으로 수동 추가할 수 있습니다. +이 세 가지 방법 모두 **프로젝트 세팅** 아래에서 **프로젝트** 섹션 아래 **Gameplay Tags** 탭에서 구성 가능합니다. ![Gameplay Tags menu in Project Settings](ProjectSettings.png) -#### 태그 수동 추가 +### 태그 수동 추가 게임플레이 태그를 추가하는 가장 쉬운 방법은 **프로젝트 세팅** 메뉴에서 수동 입력하는 것입니다. **Import Tags From Config** 옵션을 체크하면, `Config/DefaultGameplayTags.Ini` 파일이 로드되며, `Config/Tags` 경로의 .ini 파일에서 찾은 모든 게임플레이 태그도 같이 로드됩니다. **Add New Gameplay Tag** 라는 라벨의 옵션이 나타나며, 이 옵션을 사용하여 기본 파일을 포함해서 기존 게임플레이 태그 .ini 파일에 새로운 게임플레이 태그를 추가할 수 있습니다. 이런 식으로 추가된 태그는 짧은 설명을 입력할 수 있는 옵션 칸이 추가로 생기며, 이 부분은 에디터의 툴팁에 나타나게 됩니다. ![Manually Adding Tags in Project Settings](AddNewTag.png) -#### .Ini 파일 직접 편집 +#### .ini 파일 직접 편집 별도의 .ini 파일을 사용해서 태그를 추가하려면, **Import Tags From Config** 옵션을 켜야 합니다. 그러면 프로젝트의 `Config/Tags/` 경로에서 찾은 각 .ini 파일에서 게임플레이 태그가 로드되어 쉽게 수동 편집할 수 있습니다. 에디터 실행 도중 이러한 편집을 한 경우, **Import Tags From Config** 옵션을 껐다 다시 켜면 파일을 다시 로드합니다. 이 파일 내 포맷은 다음과 같습니다: - [UserTags] - GameplayTags=Vehicle.Air.Helicopter - GameplayTags=Movement.Flying - GameplayTags=Movement.Hovering - -에디터의 **Add New Gameplay Tag** 기능으로 수동 작성 파일이 변경되면, 모든 기존 태그와 새로운 태그는 새로운 섹션에 복사됩니다. "[UserTags]" 섹션은 파일에 남아있지만 로드 연산 도중 무시됩니다. 예를 들어 위 파일에 "Movement.Landing" 이 추가되면, 새 파일은 다음과 같을 것입니다: - - [UserTags] - GameplayTags=Vehicle.Air.Helicopter - GameplayTags=Movement.Flying - GameplayTags=Movement.Hovering - [/Script/GameplayTags.GameplayTagsList] - GameplayTagList=(Tag="Vehicle.Air.Helicopter",DevComment="") + GameplayTagList=(Tag="Vehicle.Air.Helicopter",DevComment="This is a custom tooltip!") GameplayTagList=(Tag="Movement.Flying",DevComment="") GameplayTagList=(Tag="Movement.Hovering",DevComment="") GameplayTagList=(Tag="Movement.Landing",DevComment="") -[REGION:note]**프로젝트 세팅** 메뉴를 사용하여 그 파일에 태그를 추가한 이후 태그 .ini 파일을 수동 편집하는 것은 좋지 않습니다.[/REGION] - -이 방법은 팀원이 자신의 태그를 추가하도록 하기에 매우 편리한 방법인데, `Config/Tags` 의 .ini 파일은 원하는 작명 규칙으로 쉽게 이름지을 수 있는 텍스트 파일이기 때문입니다. +이 방법은 팀원이 자신의 태그를 추가하도록 하기에 편리한 방법인데, `Config/Tags` 의 .ini 파일은 원하는 작명 규칙으로 쉽게 이름지을 수 있는 텍스트 파일이기 때문입니다. "Developer Tag" 컨픽 파일은 **프로젝트 세팅** 의 **Gameplay Tags Developer** (게임플레이 태그 개발자) 메뉴에서 **Developer Config Name** (개발자 환경설정 이름)을 원하는 파일명으로 채우면 사용할 수 있습니다. 설정하면 개인적으로 기본 .ini 파일에 추가한 모든 태그가 지정된 .ini 파일에 대신 저장됩니다. 자신의 .ini 파일은 `Config/Tags` 폴더에 들어가며, 추가 변경 없이 다른 개발자에게 전달하거나 소스 콘트롤 시스템에 제출할 수 있습니다. 태그가 수천 개인 거대 프로젝트나, 특정 개발자가 만든 태그를 분류하기 위해서라거나, 아니면 특정 게임 기능으로 사용하기 위한 목적으로 유용하게 쓰일 수 있습니다. 이 기능은 완전 옵션이지만, 별도의 파일에 특정 태그를 저장하려는 팀이나 작업방식에 유용하게 쓰일 수 있습니다. #### 데이터 테이블 애셋 -마지막으로 태그는 `GameplayTagTableRow` 행 유형을 가진 [데이터 테이블](Gameplay/DataDriven/#datatables) 애셋을 통해 추가할 수 있습니다. 이는 엑셀 스프레드시트 파일같은 외부 소스에서 게임플레이 태그를 임포트할 때 특히나 좋습니다. 애셋이 생성되면, **프로젝트 세팅** 메뉴의 **GameplayTagTableList** 에 추가하고, 그 안에 들어있는 모든 태그가 **게임플레이 태그 매니저** 에 추가됩니다. 참고로 이 시스템은 다중 애셋 표시를 지원하므로, 프로젝트의 태그를 여러 개의 스프레드 시트에 나누는 것이 작업방식이나 체계 정리에 도움이 된다면 그렇게도 할 수 있습니다. +마지막으로 태그는 `GameplayTagTableRow` 행 유형을 가진 [데이터 테이블](Gameplay/DataDriven/#datatables) 애셋을 통해 추가할 수 있습니다. 이는 엑셀 스프레드시트 파일같은 외부 소스에서 게임플레이 태그를 임포트할 때 특히나 좋습니다만, 임포트할 파일 없이도 에디터 안에서 작업하여 직접 만들 수 있습니다. 애셋이 생성되면, **프로젝트 세팅** 메뉴의 **GameplayTagTableList** 에 추가하고, 그 안에 들어있는 모든 태그가 **게임플레이 태그 매니저** 에 추가됩니다. 참고로 이 시스템은 다중 애셋 표시를 지원하므로, 프로젝트의 태그를 여러 개의 스프레드 시트에 나누는 것이 작업방식이나 체계 정리에 도움이 된다면 그렇게도 할 수 있습니다. ![Gameplay Tags in a Data Table Asset](DataAsset.png) +[REGION:caption]데이터 테이블 애셋은 .ini 파일이 아닌 언리얼 엔진 애셋을 사용하며, 다른 게임 애셋과 비슷하게 에디터 실행 도중 확인 및 변경 가능합니다.[/REGION] + ### 게임플레이 태그 관리 게임플레이 태그를 추가했으면, 그에 대한 레퍼런스 검색, 삭제, 이름변경 등의 관리가 가능합니다. 이러한 동작 모두 **프로젝트 세팅** 메뉴에서 태그 옆의 드롭다운으로 접근할 수 있습니다. 태그는 (수동 편집 또는 **프로젝트 세팅** 메뉴를 통해 추가된) .ini 파일을 통해 추가된 경우에만, 그리고 다른 것에 레퍼런싱되지 않은 경우에만 삭제할 수 있습니다. 태그 이름변경은 GameplayTagRedirects 목록에 추가 작업이 발생하며, 이름변경된 태그는 로드시 자동으로 수정됩니다. -#### 게임플레이 태그 테스트 연산 +![Editing Individual Gameplay Tags In Project Settings](ProjectSettingsEditTag.png) + +[REGION:caption]게임플레이 태그는 프로젝트 세팅에서 드롭다운을 통해 편집할 수 있습니다.[/REGION] + +### 게임플레이 태그 테스트 연산 테스트 연산이 다수 있는데, 모두 태그를 다른 태그에 일치시키는 개념을 기반으로 한 것으로, 게임플레이 태그 및 게임플레이 태그 컨테이너에서 수행할 수 있습니다. 이 함수 각각은 게임플레이 태그 또는 게임플레이 태그 컨테이너에서 호출할 수 있으며, 하나의 게임플레이 태그 또는 게임플레이 태그 컨테이너를 파라미터로 받습니다. 다음 테이블은 태그 및 태그 컨테이너에 사용할 수 있는 연산 상세 내용입니다. 이 표에서 "A.1" 포맷은 단일 게임플레이 태그를 나타내는 반면, "{A.1}" 은 게임플레이 태그 컨테이너의 일부분 중 같은 태그를 나타냅니다. 태그가 여럿 있는 컨테이너는 "{A.1, B.1}" 포맷이 됩니다. @@ -76,25 +73,41 @@ type:overview | {A.1, B.1} | HasAll | {A, B} | true | | {A.1, B.1} | HasAllExact | {A, B} | false | -참고로 공백 또는 기본 게임플레이 태그 컨테이너를 입력 파라미터로 제공하면 `HasAll`, `HasAllExact`, `MatchesAll`, `MatchesAllExact` 를 제외한 모든 연산이 false 반환하게 됩니다. 이는 소스 세트에 있지 않은 파라미터 태그에는 태그가 없다는 데 대한 정당화가 되며, 집합 이론과도 일관되는 내용입니다. +참고로 공백 또는 기본 게임플레이 태그 컨테이너를 입력 파라미터로 제공하면 `HasAll`, `HasAllExact`, `MatchesAll`, `MatchesAllExact` 를 제외한 모든 연산이 false 반환하게 됩니다. 이는 소스 세트에 없는 파라미터 컨테이너에 태그가 없다는 데 대한 정당화가 됩니다. -### 게임플레이 태그 쿼리 +예로 다음 블루프린트는 위 이름의 연산을 사용하여 테스트 액터가 게임에 스폰될 때 Gameplay Tag Container 에 `TestTag.One` 또는 `TestTag.Three` 가, 둘 다는 아닌 하나만 있는지 검사합니다. 이 테스트에는 시범으로 블루프린트의 리터럴 컨테이너 값을 사용하지만, 액터의 컨테이너에는 블루프린트( 또는 C++) 변수를 사용합니다. + +![블루프린트의 샘플 게임플레이 태그 연산](TagOperationsInBP.png) + +## 게임플레이 태그 쿼리 게임플레이 태그 컨테이너에 대한 특정 유형 쿼리는 **Gameplay Tag Query** 변수에 저장하여 데이터 주도형으로 만들어, 변수나 코드 조각 하나 이상을 편집할 필요 없이 여러 곳에서 수행할 수 있도록 하여 속도를 올릴 수 있습니다. 게임플레이 태그 쿼리는 세 가지 기본 테스트에 제한됩니다: -**Any Tags Match** (아무 태그 일치)는 컨테이너에 쿼리의 태그 중 하나라도 있으면 성공합니다. -**All Tags Match** (모든 태그 일치)는 컨테이너에 없는 태그가 쿼리에도 하나도 없는 경우 성공합니다 (쿼리에 태그가 존재하지 않는 경우도 포함합니다). -**No Tags Match** (태그 일치 없음)은 컨테이너에 있는 태그가 쿼리에는 하나도 없는 경우 성공합니다 (쿼리에 태그가 존재하지 않는 경우도 포함합니다). + +* **Any Tags Match** (아무 태그 일치)는 컨테이너에 쿼리의 태그 중 하나라도 있으면 성공합니다. + +* **All Tags Match** (모든 태그 일치)는 컨테이너에 없는 태그가 쿼리에도 하나도 없는 경우 성공합니다 (쿼리에 태그가 존재하지 않는 경우도 포함합니다). + +* **No Tags Match** (태그 일치 없음)은 컨테이너에 있는 태그가 쿼리에는 하나도 없는 경우 성공합니다 (쿼리에 태그가 존재하지 않는 경우도 포함합니다). + 하지만 이 테스트는 세 가지 커다란 표현식으로 합칠 수 있으며, 이들 각각에는 부가 표현식이나 테스트 배열이 포함됩니다: -**Any Expressions Match** (아무 표현식 일치)는 하위 표현식 또는 테스트가 성공하면 성공합니다. -**All Expressions Match** (모든 표현식 일치)는 하위 표현식 또는 테스트가 실패한 것이 없으면 성공합니다 (여기에는 쿼리에 하위 표현식이나 테스트가 존재하지 않는 경우도 포함됩니다). -**No Expressions Match** (일치 표현식 없음)은 하위 표현식이나 테스트가 성공한 것이 없으면 성공합니다 (여기에는 쿼리에 하위 표현식 또는 테스트가 존재하지 않는 경우도 포함됩니다). + +* **Any Expressions Match** (아무 표현식 일치)는 하위 표현식 또는 테스트가 성공하면 성공합니다. + +* **All Expressions Match** (모든 표현식 일치)는 하위 표현식 또는 테스트가 실패한 것이 없으면 성공합니다 (여기에는 쿼리에 하위 표현식이나 테스트가 존재하지 않는 경우도 포함됩니다). + +* **No Expressions Match** (일치 표현식 없음)은 하위 표현식이나 테스트가 성공한 것이 없으면 성공합니다 (여기에는 쿼리에 하위 표현식 또는 테스트가 존재하지 않는 경우도 포함됩니다). + [REGION:note]참고로 세 가지 테스트 유형 모두 위 테이블 연산에 한해 "정확한" 일치입니다.[/REGION] -![Sample Gameplay Tag Query](TagQuery.png) +이전의 테스트를 재활용하여 소스 컨테이너에 `TestTag.One` 나 `TestTag.Three` 중 (둘 다는 아닌) 하나만 있고 `TestTag.Two` 는 없도록 하는 것을, 하나의 Gameplay Tag Query 로 만들 수 있습니다. 이 테스트에는 블루프린트( 또는 C++) 변수만 독점적으로 사용할텐데, 리터럴 값 역시 지원하기는 합니다. 테스트 쿼리 변수는 이와 같습니다: -위 샘플 쿼리에서 TestTag.One 이나 TestTag.Three 중 하나는 (둘 다는 안됨) 반드시 소스 컨테이너에 있어야 하며, TestTag.Two 는 없어야 합니다. +![샘플 게임플레이 태그 쿼리 변수](TagQuery.png) -### 게임에서 게임플레이 태그 사용 +이 쿼리 구성으로 우리 게임플레이 태그 컨테이너를 테스트 액터의 블루프린트에 있는 것에 대해 평가할 수 있는데, 다음과 같습니다: + +![블루프린트의 샘플 게임플레이 태그 쿼리](TagQueryInBP.png) + +## 게임에서 게임플레이 태그 사용 게임의 오브젝트에 만든 태그를 적용하려면, 오브젝트에 Gameplay Tags (C++ 유형 `FGameplayTag`) 또는 Gameplay Tag Containers (C++ 유형 `FGameplayTagContainer`) 프로퍼티를 추가하면 됩니다. 또한 원하는 대로 오브젝트에 **Gameplay Tag Queries** (C++ 유형 `FGameplayTagQuery`) 추가도 가능하며, 블루프린트나 C++ 코드에서 직접 태그 연산을 사용할 수도 있습니다. 이 프로퍼티 추가가 완료되면, 다른 변수처럼 코드나 에디터에서 편집할 수 있습니다. -### 게임플레이 태그 빠르게 접근하기 (C++ 필요) +### C++ 에서 게임플레이 태그 빠른 접근 `IGameplayTagAssetInterface` 는 C++ 에서 구현할 수 있습니다. 그 후 `GetOwnedGameplayTags` 함수를 오버라이드하면, 블루프린트를 접근하는 방식으로 해당 오브젝트에 태그가 할당된 게임플레이 태그 컨테이너를 채우는 방법을 만들 수 있습니다. 대부분의 경우 베이스 클래스에서 새로운 컨테이너로 태그를 복사한다는 뜻일 뿐이지만, 클래스 구현은 다수의 컨테이너에서 태그를 수집하고, 블루프린트 함수를 호출하여 블루프린트 선언 태그를 접근하거나, 필요한 다른 오브젝트를 접근할 수도 있습니다. 이러한 인터페이스의 장접은 표준화된 방식으로 다양한 오브젝트 유형과 상호작용할 수 있다는 것으로, 오브젝트를 명시적으로 형변환한 뒤 올바른 태그 변수(들)을 구하기 위해 가능한 유형마다 커스텀 코드를 작성하지 않아도 오브젝트 태그를 구할 수 있다는 점입니다. 이는 커대한 프로젝트에서 특히나 유용한데, 재현하기 어려운 버그를 방지하고 코드를 깔끔하고 빠르고 관리하기 쉽도록 만드는 데 도움이 될 수 있기 때문입니다. diff --git a/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/DownloadZip/DownloadZip.INT.udn b/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/DownloadZip/DownloadZip.INT.udn index 98fb20bab57b..7704a798d427 100644 --- a/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/DownloadZip/DownloadZip.INT.udn +++ b/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/DownloadZip/DownloadZip.INT.udn @@ -1,10 +1,12 @@ -Availability:Public +Availability:NoPublish Title:Downloading Unreal as a Zip from GitHub Crumbs:%ROOT%, GettingStarted, GettingStarted/DownloadingUnrealEngine Description:Downloading the Unreal Engine source code as a Zip file. Prereq: GettingStarted/DownloadingUnrealEngine Related: Programming/Development/BuildingUnrealEngine -Version: 4.8 +Parent:GettingStarted +Order: +Version: 4.16 SkillLevel: Advanced If you prefer to download our source code as a Zip file from GitHub, this page is for you. @@ -40,7 +42,7 @@ If you prefer to download our source code as a Zip file from GitHub, this page i 1. Decompress 'UnrealEngine-(branch_name).zip' onto your hard disk. 1. If you already haven't done so, install Visual Studio 2013. Although MFC libraries are included in Visual Studio's default installation settings, make sure that MFC libraries are included for ATL support. [REGION:note] - Developers build UE4 with all desktop editions of Visual Studio, including Microsoft's free version ([Visual Studio Community 2013](https://www.visualstudio.com/products/visual-studio-community-vs)). + Developers build UE4 with all desktop editions of Visual Studio, including the latest version of [Microsoft's Visual Studio](https://www.visualstudio.com/). [/REGION] 1. Open your source folder in Explorer and run **Setup.bat**. [REGION:note] diff --git a/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/DownloadZip/DownloadZip.KOR.udn b/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/DownloadZip/DownloadZip.KOR.udn index affbe3853754..1e3ac3454092 100644 --- a/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/DownloadZip/DownloadZip.KOR.udn +++ b/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/DownloadZip/DownloadZip.KOR.udn @@ -1,11 +1,13 @@ -INTSourceChangelist:3108692 -Availability:Public +INTSourceChangelist:3452211 +Availability:NoPublish Title:Zip 파일로 언리얼 엔진 다운로드 Crumbs:%ROOT%, GettingStarted, GettingStarted/DownloadingUnrealEngine Description:언리얼 엔진 소스 코드를 Zip 파일로 다운로드합니다. Prereq: GettingStarted/DownloadingUnrealEngine Related: Programming/Development/BuildingUnrealEngine -Version: 4.8 +Parent:GettingStarted +Order: +Version: 4.16 SkillLevel: Advanced 소스 코드를 GitHub 에서 ZIP 파일로 다운로드하는 방법이 편하신 분들을 위한 글입니다. @@ -41,7 +43,7 @@ SkillLevel: Advanced 1. 'UnrealEngine-(branch_name).zip' 파일 압축을 하드 디스크에 풉니다. 1. Visual Studio 2013 이 설치되어 있지 않은 경우, 설치합니다. MFC 라이브러리가 Visual Studio 기본 설치 세팅에 포함되어 있기는 하지만, ATL 지원을 위해 MFC 라이브러리가 포함되어 있는지 다시 한 번 확인합니다. [REGION:note] - UE4 빌드는 Visual Studio 모든 데스크톱 에디션으로 가능한데, 무료 버전도 포함됩니다 ([Visual Studio Community 2013](https://www.visualstudio.com/products/visual-studio-community-vs)). + UE4 빌드는 Visual Studio 모든 데스크톱 버전으로 가능합니다: [Microsoft's Visual Studio](https://www.visualstudio.com/). [/REGION] 1. 탐색기에서 소스 폴더를 열고 **run Setup.bat** 를 실행합니다. [REGION:note] diff --git a/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/DownloadingUnrealEngine4.INT.udn b/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/DownloadingUnrealEngine4.INT.udn index 603cad90527f..80989abe4435 100644 --- a/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/DownloadingUnrealEngine4.INT.udn +++ b/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/DownloadingUnrealEngine4.INT.udn @@ -3,10 +3,12 @@ Title:Downloading Unreal Engine Source Code Crumbs: %ROOT%, GettingStarted, GettingStarted/DownloadingUnrealEngine Description:Steps for connecting to the source code repository and downloading the latest build of Unreal Engine. Prereq: GettingStarted/RecommendedSpecifications -Related: GettingStarted/DownloadingUnrealEngine/GitHub -Related: GettingStarted/DownloadingUnrealEngine/DownloadZip -Version: 4.9 +Version: 4.16 +Parent:GettingStarted +Order: +Type:Landing SkillLevel: Advanced +Related:Programming/Development/BuildingUnrealEngine [TOC (start:2 end:3)] @@ -18,10 +20,6 @@ Unreal Engine 4 is available to be downloaded by licensees from Epic's Perforce Source code for Unreal Engine 4 (UE4) can be downloaded by our subscribers from the Unreal Engine GitHub repository. Before you can access the [repository](https://github.com/EpicGames/UnrealEngine), you must be an Unreal Engine subscriber with a GitHub account. For instructions on associating your GitHub account with your Unreal Engine account, visit the [UE4 on GitHub](https://www.unrealengine.com/ue4-on-github) page. - - [INCLUDE:GettingStarted/DownloadingUnrealEngine/SourceBranches] [/PUBLISH:Rocket] @@ -32,17 +30,88 @@ With access to our source code, subscribers can customize the engine and tools t [PUBLISH:Rocket] -## Next Steps +## Downloading the Source Code -Subscribers can download Unreal Engine's source code in one of two ways: +Please follow these instructions to download the Unreal Engine source code. -* [%GettingStarted/DownloadingUnrealEngine/GitHub:title%](GettingStarted/DownloadingUnrealEngine/GitHub) -* [%GettingStarted/DownloadingUnrealEngine/DownloadZip:title%](GettingStarted/DownloadingUnrealEngine/DownloadZip) +%Globals:osselect_linux% + +[OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + active_button_content + [/PARAMLITERAL] + [PARAM:content] + + [INCLUDE:GettingStarted/WindowsInstructions] + + [/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + active_button_content + [/PARAMLITERAL] + [PARAM:content] + + [INCLUDE:GettingStarted/MacInstructions] + + [/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + linux + [/PARAMLITERAL] + [PARAMLITERAL:active] + active_button_content + [/PARAMLITERAL] + [PARAM:content] + + [REGION:warning] + Our developers and support teams currently use the latest version of Ubuntu; as a result, we may not be able to provide support for other Linux distributions (including other versions of Ubuntu). + [/REGION] + + [INCLUDE:GettingStarted/LinuxInstructions] + + [/PARAM] +[/OBJECT] [REGION:note] This page shows subscribers how to download and build Unreal Engine from our source code repository on GitHub. If you'd like to download the binary version of Unreal Engine, read our [](GettingStarted/Installation) documentation to learn how to [Get Unreal](https://www.unrealengine.com/). [/REGION] +## Licensing and Contribution + +Your access to and use of Unreal Engine on GitHub is governed by the [Unreal Engine End User License Agreement](https://www.unrealengine.com/eula). If you don't agree to those terms, as amended from time to time, you are not permitted to access or use Unreal Engine. + +We welcome any contributions to Unreal Engine development through [pull requests](https://github.com/EpicGames/UnrealEngine/pulls/) on GitHub. Most of our active development is in the **master** branch, so we prefer to take pull requests there (particularly for new features). We try to make sure that all new code adheres to the [Epic coding standards](https://docs.unrealengine.com/latest/INT/Programming/Development/CodingStandard/). All contributions are governed by the terms of the EULA. + +## Next Steps + +Now that you've downloaded and set-up Unreal Engine, you're ready to [build the engine from source](Programming/Development/BuildingUnrealEngine). + +#### Footnotes +The first time you start the editor from a fresh source build, you may experience long load times. +The engine is optimizing content for your platform to the _derived data cache_, and it should only happen once. + +Your private forks of the Unreal Engine code are associated with your GitHub account permissions. +If you unsubscribe or switch GitHub user names, you'll need to re-fork and upload your changes from a local copy. + [/PUBLISH:Rocket] [/EXCERPT:Main] diff --git a/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/DownloadingUnrealEngine4.KOR.udn b/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/DownloadingUnrealEngine4.KOR.udn index be80e8d31d34..a885974b3b3e 100644 --- a/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/DownloadingUnrealEngine4.KOR.udn +++ b/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/DownloadingUnrealEngine4.KOR.udn @@ -1,13 +1,15 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3426963 Availability:Public Title:언리얼 엔진 소스 코드 내려받기 Crumbs: %ROOT%, GettingStarted, GettingStarted/DownloadingUnrealEngine Description:소스 코드 저장소에 접속하여 언리얼 엔진 최신 빌드를 다운로드하는 법에 대한 단계별 안내입니다. Prereq: GettingStarted/RecommendedSpecifications -Related: GettingStarted/DownloadingUnrealEngine/GitHub -Related: GettingStarted/DownloadingUnrealEngine/DownloadZip -Version: 4.9 +Version: 4.16 +Parent:GettingStarted +Order: +Type:Landing SkillLevel: Advanced +Related:Programming/Development/BuildingUnrealEngine [TOC (start:2 end:3)] @@ -19,10 +21,6 @@ SkillLevel: Advanced 언리얼 엔진 4 (UE4) 소스 코드는 멤버쉽 회원의 경우 Unreal Engine GitHub repository(저장소)에서 다운로드 가능합니다. [repository](https://github.com/EpicGames/UnrealEngine) (저장소) 접근을 위해서는 GitHub 계정을 가지고 언리얼 엔진 계정에 연동시켜야 합니다. 언리얼 엔진 계정에 GitHub 계정을 연동시키는 법에 대한 안내는, [GitHub 의 언리얼 엔진 4](https://www.unrealengine.com/ue4-on-github) 페이지를 참고하세요. - - [INCLUDE:GettingStarted/DownloadingUnrealEngine/SourceBranches] [/PUBLISH:Rocket] @@ -33,17 +31,88 @@ SkillLevel: Advanced [PUBLISH:Rocket] -## 다음 단계 +## 소스 코드 다운로드 -멤버쉽 회원분들이 언리얼 엔진 소스 코드를 다운로드할 수 있는 방법은 다음과 같습니다: +다음 안내에 따라 언리얼 엔진 소스 코드를 다운로드해 주세요. -* [](GettingStarted/DownloadingUnrealEngine/GitHub) -* [](GettingStarted/DownloadingUnrealEngine/DownloadZip) +%Globals:osselect_linux% + +[OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + active_button_content + [/PARAMLITERAL] + [PARAM:content] + + [INCLUDE:GettingStarted/WindowsInstructions] + + [/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + active_button_content + [/PARAMLITERAL] + [PARAM:content] + + [INCLUDE:GettingStarted/MacInstructions] + + [/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + linux + [/PARAMLITERAL] + [PARAMLITERAL:active] + active_button_content + [/PARAMLITERAL] + [PARAM:content] + + [REGION:warning] + 저희 개발 및 서포트 팀은 현재 Ubuntu 최신 버전을 사용하고 있습니다. 다른 (Ubuntu 버전을 포함해서) 리눅스 배포 버전은 지원하지 못할 수 있습니다. + [/REGION] + + [INCLUDE:GettingStarted/LinuxInstructions] + + [/PARAM] +[/OBJECT] [REGION:note] 이 글은 GitHub 의 소스 코드 저장소에서 언리얼 엔진을 다운로드하여 빌드하는 법을 보여드립니다. 언리얼 엔진 바이너리 버전을 다운로드하려면, [](GettingStarted/Installation) 문서를 통해 [언리얼을 시작](https://www.unrealengine.com/) 하는 법을 배워보세요. [/REGION] +## 라이선싱 및 기여 + +GitHub 의 언리얼 엔진 접근 및 사용 권한은 [언리얼 엔진 최종 사용자 라이선스 계약](https://www.unrealengine.com/eula) 에 따릅니다. 때때로 개정되는 내용을 포함해서 그 조항에 동의하지 않는 경우, 언리얼 엔진 접근 및 사용이 불가능합니다. + +GitHub 의 [pull requests](https://github.com/EpicGames/UnrealEngine/pulls/) 를 통한 언리얼 엔진 개발 기여는 언제든 환영합니다! 현재 대부분의 개발은 **master** 브랜치에서 일어나고 있기에 거기서 (특히나 신기능에 대한) pull request 를 받습니다. 모든 신규 코드는 [에픽 코딩 표준](Programming/Development/CodingStandard) 을 준수하도록 하고 있습니다. 모든 기여 부분은 EULA 조항을 따릅니다. + +## 다음 단계 + +언리얼 엔진 다운로드 및 셋업을 마쳤으면, [소스에서 엔진을 빌드](Programming/Development/BuildingUnrealEngine) 할 차례입니다. + +#### 사족 +새로 받은 소스 빌드에서 에디터를 처음 실행시키면, 로드 시간이 길 수 있습니다. +엔진에서 _파생 데이터 캐시(DDC)_ 에 플랫폼에 맞는 콘텐츠 최적화를 하기 때문인데, 일회성 작업일 것입니다. + +언리얼 엔진 코드 private fork 는 귀하의 GitHub 계정 권한에 연동되어 있습니다. +GitHub 사용자명을 해제하거나 바꾸면, fork 를 다시 한 뒤 로컬 사본에서 변경사항을 업로드해 줘야 할 것입니다. + [/PUBLISH:Rocket] [/EXCERPT:Main] \ No newline at end of file diff --git a/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/GitHub/GitHub.INT.udn b/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/GitHub/GitHub.INT.udn index 5baaa469a80f..2d8a530ead07 100644 --- a/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/GitHub/GitHub.INT.udn +++ b/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/GitHub/GitHub.INT.udn @@ -1,10 +1,12 @@ -Availability:Public +Availability:NoPublish Title:Forking and Cloning Unreal from GitHub Crumbs:%ROOT%, GettingStarted, GettingStarted/DownloadingUnrealEngine Description:Forking and cloning the Unreal Engine source code from GitHub. Prereq: GettingStarted/DownloadingUnrealEngine Related: Programming/Development/BuildingUnrealEngine -Version: 4.8 +Parent:GettingStarted +Order: +Version: 4.16 SkillLevel: Advanced Forking and cloning our source code from GitHub is a great way to get started with Unreal. diff --git a/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/GitHub/GitHub.KOR.udn b/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/GitHub/GitHub.KOR.udn index da4f490e1416..74bca1fcc2e9 100644 --- a/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/GitHub/GitHub.KOR.udn +++ b/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/GitHub/GitHub.KOR.udn @@ -1,11 +1,13 @@ -INTSourceChangelist:3147055 -Availability:Public +INTSourceChangelist:3426963 +Availability:NoPublish Title:GitHub 에서 언리얼 엔진 Fork 및 Clone Crumbs:%ROOT%, GettingStarted, GettingStarted/DownloadingUnrealEngine Description:GitHub 에서 언리얼 엔진 소스 코드를 Fork 및 복제하는 방법입니다. Prereq: GettingStarted/DownloadingUnrealEngine Related: Programming/Development/BuildingUnrealEngine -Version: 4.8 +Parent:GettingStarted +Order: +Version: 4.16 SkillLevel: Advanced GitHub 에서 소스 코드를 Fork 및 Clone 하는 것으로 언리얼 작업을 시작합니다. diff --git a/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/SourceBranches/SourceBranches.INT.udn b/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/SourceBranches/SourceBranches.INT.udn index 0e18749f9a89..226f0ee0966c 100644 --- a/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/SourceBranches/SourceBranches.INT.udn +++ b/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/SourceBranches/SourceBranches.INT.udn @@ -7,7 +7,10 @@ Related: GettingStarted/DownloadingUnrealEngine Related: Programming/Development/BuildingUnrealEngine Related: Programming/Development/CompilingProjects Related: Support/Builds -Version: 4.8 +Version: 4.16 +type:reference +Parent:GettingStarted/DownloadingUnrealEngine +Order: ## Source Code Branches diff --git a/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/SourceBranches/SourceBranches.KOR.udn b/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/SourceBranches/SourceBranches.KOR.udn index a17a43887d6f..d2a2f9b06202 100644 --- a/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/SourceBranches/SourceBranches.KOR.udn +++ b/Engine/Documentation/Source/GettingStarted/DownloadingUnrealEngine/SourceBranches/SourceBranches.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3426963 Availability: NoPublish Title: 소스 브랜치 참고서 Crumbs: %ROOT%, GettingStarted, GettingStarted/DownloadingUnrealEngine @@ -8,7 +8,10 @@ Related: GettingStarted/DownloadingUnrealEngine Related: Programming/Development/BuildingUnrealEngine Related: Programming/Development/CompilingProjects Related: Support/Builds -Version: 4.8 +Version: 4.16 +type:reference +Parent:GettingStarted/DownloadingUnrealEngine +Order: ## 소스 코드 브랜치 diff --git a/Engine/Documentation/Source/GettingStarted/FromUnity/UnrealEngineforUnityDevelopers.CHN.udn b/Engine/Documentation/Source/GettingStarted/FromUnity/UnrealEngineforUnityDevelopers.CHN.udn index a2b575fcda62..47a65aef3bb3 100644 --- a/Engine/Documentation/Source/GettingStarted/FromUnity/UnrealEngineforUnityDevelopers.CHN.udn +++ b/Engine/Documentation/Source/GettingStarted/FromUnity/UnrealEngineforUnityDevelopers.CHN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:2717841 +INTSourceChangelist:3317931 Availability: Public Title: 为 Unity 开发者准备的虚幻引擎 4 Crumbs: %ROOT%, GettingStarted @@ -799,7 +799,7 @@ _点击查看大图。_ ### 物理:刚体 vs. 元组件 -在 Unity 中药给一个 GameObject 物理特性,需要给它一个刚体组件。在虚幻中,任何元组件(C++ 中为 UPrimitiveComponent)都可以是物理对象。一些通用的元组件,比如 ShapeComponent(胶囊形,球形,盒形),StaticMeshComponent,以及 SkeletalMeshComponent。 +在 Unity 中,要给一个 GameObject 物理特性,需要给它一个刚体组件。在虚幻中,任何元组件(C++ 中为 UPrimitiveComponent)都可以是物理对象。一些通用的元组件,比如 ShapeComponent(胶囊形,球形,盒形),StaticMeshComponent,以及 SkeletalMeshComponent。 和 Unity 不同,Unity 将碰撞体和可视物体分列到不同的组件中。而虚幻则将潜在的物理碰撞和潜在的可视效果组合到了 PrimitiveComponent 中。任何在世界中具有形状的物体,要么就是能够被渲染显示,要么就是能作物理交互,它们都继承于 PrimitiveComponent。 @@ -905,28 +905,9 @@ Unity C#: Trigger.SetCollisionEnabled(ECollisionEnabled::QueryOnly); } - void BeginPlay() - { - // Register to find out when an overlap occurs - OnActorBeginOverlap.AddDynamic(this, &AMyActor::OnTriggerEnter); - OnActorEndOverlap.AddDynamic(this, &AMyActor::OnTriggerExit); + virtual void NotifyActorBeginOverlap(AActor* Other) override; - Super::BeginPlay(); - } - - void EndPlay(const EEndPlayReason::Type EndPlayReason) - { - OnActorBeginOverlap.RemoveDynamic(this, &AMyActor::OnTriggerEnter); - OnActorEndOverlap.RemoveDynamic(this, &AMyActor::OnTriggerExit); - - Super:EndPlay(EndPlayReason); - } - - UFUNCTION() - void OnTriggerEnter(AActor* Other); - - UFUNCTION() - void OnTriggerExit(AActor* Other); + virtual void NotifyActorEndOverlap(AActor* Other) override; }; 虚幻 4 蓝图: diff --git a/Engine/Documentation/Source/GettingStarted/FromUnity/UnrealEngineforUnityDevelopers.INT.udn b/Engine/Documentation/Source/GettingStarted/FromUnity/UnrealEngineforUnityDevelopers.INT.udn index f45a59229cfc..f6b077fe636b 100644 --- a/Engine/Documentation/Source/GettingStarted/FromUnity/UnrealEngineforUnityDevelopers.INT.udn +++ b/Engine/Documentation/Source/GettingStarted/FromUnity/UnrealEngineforUnityDevelopers.INT.udn @@ -15,13 +15,66 @@ This guide provides an overview of UE4 from the viewpoint of a Unity user, and a Below are pictures of the Unity Editor and Unreal Editor, color-coded to indicate common functionality. Each block is labeled to show the equivalent UE4 terminology. Unreal Editor's layout is fully customizable by dragging and dropping tabs around. -![](image_1.png) +[OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](EditorCompare_Windows.png) + [/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](EditorCompare_Mac.png) + [/PARAM] +[/OBJECT] + ### Editing Assets In Unity, the Inspector tab is used to edit selected assets in your Project. In UE4, the **Details** panel exposes properties of selected objects, while larger editing tasks lead to a dedicated window or tab. New tabbed windows will open for each edited asset, similar to a web browser. Of course, you can freely drag the tabs around or float them as standalone windows. -![](image_2.png) +[OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](TabbedWindows_Windows.png) + [/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](TabbedWindows_Mac.png) + [/PARAM] +[/OBJECT] ## Quick Glossary @@ -63,7 +116,33 @@ Just like Unity projects, Unreal projects always exist in their own directory an In UE4, each project has a **Content **folder. Similar to a Unity project's Assets folder, this is where your game assets are stored. To import assets into your game, simply drop files into your project's Content directory and they will be automatically imported and appear in the **Content Browser**. The assets in the editor will update automatically as you make changes to the files using an external program. -![image alt text](image_3.png) +[OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](ProjectOnDisk_Windows.png) + [/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](ProjectOnDisk_Mac.png) + [/PARAM] +[/OBJECT] ### What common file formats are supported? diff --git a/Engine/Documentation/Source/GettingStarted/FromUnity/UnrealEngineforUnityDevelopers.KOR.udn b/Engine/Documentation/Source/GettingStarted/FromUnity/UnrealEngineforUnityDevelopers.KOR.udn index 0fb8791226f0..9908ca068292 100644 --- a/Engine/Documentation/Source/GettingStarted/FromUnity/UnrealEngineforUnityDevelopers.KOR.udn +++ b/Engine/Documentation/Source/GettingStarted/FromUnity/UnrealEngineforUnityDevelopers.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3317931 +INTSourceChangelist:3481084 Availability: Public Title:유니티 개발자를 위한 언리얼 엔진 4 Crumbs: %ROOT%, GettingStarted @@ -16,13 +16,66 @@ version: 4.9 아래 그림은 유니티 에디터와 언리얼 에디터를 나란 놓은 것으로, 색을 통해 기능이 같은 부분을 확인할 수 있습니다. 각 블록에는 이름표를 붙여 그에 맞는 UE4 용어를 표시해 뒀습니다. 언리얼 에디터의 레이아웃은 드래그 앤 드롭을 통해 탭을 이리저리 끌어 붙여 입맛대로 조정하는 것이 가능합니다. -![](image_1.png) +[OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](EditorCompare_Windows.png) + [/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](EditorCompare_Mac.png) + [/PARAM] +[/OBJECT] + ### 애셋 편집 유니티에서는 Inspector 탭을 사용하여 프로젝트에 선택된 애셋을 편집합니다. UE4 에서는 **디테일** 패널에 선택된 오브젝트의 프로퍼티가 노출되기는 하지만, 규모가 큰 편집 작업은 **전용 창이나 탭** 에서 이루어집니다. **웹 브라우저와 비슷하게** 편집되는 애셋 각각에 대해 새로운 탭 창이 열립니다. 물론 각 탭은 자유롭게 끌어붙이거나 독립 창으로 띄울 수도 있습니다. -![](image_2.png) +[OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](TabbedWindows_Windows.png) + [/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](TabbedWindows_Mac.png) + [/PARAM] +[/OBJECT] ## 간략 용어집 @@ -64,7 +117,33 @@ version: 4.9 UE4 에는 각 프로젝트마다 **Content** 폴더가 있습니다. 유니티 프로젝트의 Assets 폴더와 비슷하게 이 폴더에 게임 애셋이 저장됩니다. 애셋을 게임에 임포트하려면, 단순히 파일을 프로젝트의 Content 디렉토리에 끌어놓기만 하면 자동으로 임포트되어 **콘텐츠 브라우저** 에 나타납니다. 애셋도 외부 프로그램으로 파일을 변경할 때마다 자동으로 에디터에 업데이트됩니다. -![image alt text](image_3.png) +[OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](ProjectOnDisk_Windows.png) + [/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](ProjectOnDisk_Mac.png) + [/PARAM] +[/OBJECT] ### 주로 지원되는 파일 포맷은? diff --git a/Engine/Documentation/Source/GettingStarted/GettingStarted.INT.udn b/Engine/Documentation/Source/GettingStarted/GettingStarted.INT.udn index f25bc1d6cf25..e81eaa298d24 100644 --- a/Engine/Documentation/Source/GettingStarted/GettingStarted.INT.udn +++ b/Engine/Documentation/Source/GettingStarted/GettingStarted.INT.udn @@ -99,221 +99,125 @@ gettingstarted [/PARAM] [/OBJECT] -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - Editor Basics - [/PARAM] - [PARAM:description] - [INCLUDE:Shared/Glossary/P/#Glossary_project] +## Editor Basics - [INCLUDE:Engine/UI/LevelEditor#levels] - [/PARAM] - [PARAM:links] - * [](Engine/QuickStart "%Engine/QuickStart:description%") - * [Level Editor Walkthrough](Engine/UI/LevelEditor "%Engine/UI/LevelEditor:description%") - * [](Engine/UI/LevelEditor/Toolbar "%Engine/UI/LevelEditor/Toolbar:description%") +[INCLUDE:Shared/Glossary/P/#Glossary_project] - [REGION:gallery] - [REGION:normaltitle] - Related Videos - [/REGION] - [VideoLink(videoid:"w4XlBKeE46E" playlistid:"PLZlv_N0_O1gasd4IcOe9Cx9wHoBB7rxFl" width:"180")] - [/REGION] - [/PARAM] -[/OBJECT] +[INCLUDE:Engine/UI/LevelEditor#levels] -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/viewport_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - Editor Viewports - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/UI/LevelEditor/Viewports#intro] - [/PARAM] - [PARAM:links] - * [](Engine/UI/LevelEditor/Viewports/Basics "%Engine/UI/LevelEditor/Viewports/Basics:description%") - * [](Engine/UI/LevelEditor/Viewports/ViewportControls "%Engine/UI/LevelEditor/Viewports/ViewportControls:description%") - [/PARAM] -[/OBJECT] +%Engine/QuickStart:topic% +%Engine/UI/LevelEditor:topic% +%Engine/UI/LevelEditor/Toolbar:topic% -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/profile_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - Editor Modes - [/PARAM] - [PARAM:description] - [INCLUDE:Shared/Glossary/M#glossary_modes_panel] - [/PARAM] - [PARAM:links] - * [](Engine/UI/LevelEditor/Modes "%Engine/UI/LevelEditor/Modes:description%") - [/PARAM] -[/OBJECT] +[REGION:section] +[REGION:normaltitle] +Related Videos +[/REGION] +[DIR(playlist_id:"PLZlv_N0_O1gasd4IcOe9Cx9wHoBB7rxFl" type:"playlist" output:"playlist")] +[/REGION] -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/levels_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - Actors & Geometry - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/UI/LevelEditor#actors] - [/PARAM] - [PARAM:links] - * [](Engine/Actors/Placement "%Engine/Actors/Placement:description%") - * [Geometry Actors](Engine/Actors/Brushes "%Engine/Actors/Brushes:description%") - * [](Engine/Actors/Transform "%Engine/Actors/Transform:description%") - - [REGION:gallery] - [REGION:normaltitle] - Related Videos - [/REGION] - [VideoLink(videoid:"cl_eoVfNDKU" playlistid:"PLZlv_N0_O1gak1_FoAJVrEGiLIploeF3F" width:"180")] - [/REGION] - [/PARAM] -[/OBJECT] - -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/cb_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - Content Browser - [/PARAM] - [PARAM:description] - [INCLUDE:Shared/Glossary/C/#Glossary_Content_Browser] - [/PARAM] - [PARAM:links] - * [](Engine/Content/QuickStart "%Engine/Content/QuickStart:description%") - * [](Engine/Basics/AssetsAndPackages "%Engine/Basics/AssetsAndPackages:description%") - * [](Engine/Content/Browser "%Engine/Content/Browser:description%") - [/PARAM] -[/OBJECT] - -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/light_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - Lighting - [/PARAM] - [PARAM:description] - Lighting your scenes is accomplished using Light Actors that act as light sources and contain properties to determine the characteristics of the light, such as: - - * How bright the light is - * What color the light is - - There are also different kinds of lights that emit light in different ways. For example, a standard light bulb emits light in all directions. In Unreal Engine, - this is called a _point light_. In other circumstances, the light emitted is physically limited by making the back of the bulb opaque, such as with a flood light. - This would be a _spot light_. Outdoor lighting from the sun - because it is located so far away - appears to come more from a direction instead of from a single - location. To simulate this type of lighting, a _directional light_ is available. - [/PARAM] - [PARAM:links] - * [](Engine/Rendering/LightingAndShadows/QuickStart "%Engine/Rendering/LightingAndShadows/QuickStart:description%") - * [](Engine/Rendering/LightingAndShadows/Basics "%Engine/Rendering/LightingAndShadows/Basics:description%") - [/PARAM] -[/OBJECT] - -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/rendering_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - Materials & Shading - [/PARAM] - [PARAM:description] - - [INCLUDE:Shared/Glossary/M/#Glossary_Material] - [/PARAM] - [PARAM:links] - * [](Engine/Rendering/Materials/IntroductionToMaterials "%Engine/Rendering/Materials/IntroductionToMaterials:description%") - - [REGION:gallery] - [REGION:normaltitle] - Related Videos - [/REGION] - [VideoLink(videoid:"lngF4VVNER4" playlistid:"PLZlv_N0_O1gbQjgY0nDwZNYe_N8IcYWS-" width:"180" image:"https://img.youtube.com/vi/lngF4VVNER4/hqdefault.jpg")] - [/REGION] - [/PARAM] -[/OBJECT] - - -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/blueprint_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - Blueprints Visual Scripting - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/Blueprints#intro] - [/PARAM] - [PARAM:links] - * [Introduction to Blueprints](Engine/Blueprints/GettingStarted "%Engine/Blueprints/GettingStarted:description%") - - [REGION:gallery] - [REGION:normaltitle] - Related Videos - [/REGION] - [VideoLink(videoid:"EFXMW_UEDco" playlistid:"PLZlv_N0_O1gY35ezlSQn1sWOGfh4C7ewO" width:"180")] - [/REGION] - [/PARAM] -[/OBJECT] - -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/prog_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - Programming - [/PARAM] - [PARAM:description] - Implementing gameplay and modifying the engine are essential aspects of any game project. Unreal Engine - gives you the ability to implement gameplay through code or visually using Blueprints or even create a - plugin that modifies or extends the engine and editor to add completely custom functionality for designers - or artists to use. - [/PARAM] - [PARAM:links] - * [](Programming "%Programming:description%") - * [](Programming/Development/VisualStudioSetup "%Programming/Development/VisualStudioSetup:description%") - * [](Programming/QuickStart "%Programming/QuickStart:description%") - * [](Programming/Basics "%Programming/Basics:description%") - * [Learn About the Game Framework](Gameplay/Framework/QuickReference "%Gameplay/Framework/QuickReference:description%") +## Editor Viewports - [REGION:gallery] - [REGION:normaltitle] - Related Videos - [/REGION] - [VideoLink(videoid:"mSRov77hNR4" playlistid:"PLZlv_N0_O1gYup-gvJtMsgJqnEB_dGiM4" width:"180")] - [/REGION] - [/PARAM] -[/OBJECT] +[INCLUDE:Engine/UI/LevelEditor/Viewports#intro] -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/gameplay_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - Playtest Your Game - [/PARAM] - [PARAM:description] - Test and debug your levels and gameplay using Unreal Engine's built-in features. Get real-time feedback - directly in the editor using Play In Editor mode, and even inspect and manipulate the objects in the - game while it is running using Simulate In Editor mode. Make changes to gameplay code, recompile, and - update the game during play using Hot Reload. - [/PARAM] - [PARAM:links] - * [](Engine/UI/LevelEditor/InEditorTesting "%Engine/UI/LevelEditor/InEditorTesting:description%") - * **Platforms** - * [](Platforms/iOS/QuickStart "%Platforms/iOS/QuickStart:description%") - * [](Platforms/Android/GettingStarted "%Platforms/Android/GettingStarted:description%") - * [](Platforms/Oculus/QuickStart "%Platforms/Oculus/QuickStart:description%") - [/PARAM] -[/OBJECT] +%Engine/UI/LevelEditor/Viewports/Basics:topic% +%Engine/UI/LevelEditor/Viewports/ViewportControls:topic% + +## Editor Modes + +[INCLUDE:Shared/Glossary/M#glossary_modes_panel] + +%Engine/UI/LevelEditor/Modes:topic% + +## Actors & Geometry + +[INCLUDE:Engine/UI/LevelEditor#actors] + +%Engine/Actors/Placement:topic% +%Engine/Actors/Brushes:topic% +%Engine/Actors/Transform:topic% + +[REGION:section] +[REGION:normaltitle] +Related Videos +[/REGION] +[DIR(playlist_id:"PLZlv_N0_O1gak1_FoAJVrEGiLIploeF3F" type:"playlist" output:"playlist")] +[/REGION] + +## Content Browser + +[INCLUDE:Shared/Glossary/C/#Glossary_Content_Browser] + +%Engine/Content/QuickStart:topic% +%Engine/Basics/AssetsAndPackages:topic% +%Engine/Content/Browser:topic% + +## Lighting + +Lighting your scenes is accomplished using Light Actors that act as light sources and contain properties to determine the characteristics of the light, such as: + +* How bright the light is +* What color the light is + +There are also different kinds of lights that emit light in different ways. For example, a standard light bulb emits light in all directions. In Unreal Engine, +this is called a _point light_. In other circumstances, the light emitted is physically limited by making the back of the bulb opaque, such as with a flood light. +This would be a _spot light_. Outdoor lighting from the sun - because it is located so far away - appears to come more from a direction instead of from a single +location. To simulate this type of lighting, a _directional light_ is available. + +%Engine/Rendering/LightingAndShadows/QuickStart:description% +%Engine/Rendering/LightingAndShadows/Basics:description% + +## Materials & Shading + +[INCLUDE:Shared/Glossary/M/#Glossary_Material] + +%Engine/Rendering/Materials/IntroductionToMaterials:topic% + +[REGION:section] +[REGION:normaltitle] +Related Videos +[/REGION] +[DIR(playlist_id:"PLZlv_N0_O1gbQjgY0nDwZNYe_N8IcYWS-" type:"playlist" output:"playlist")] +[/REGION] + +## Blueprints Visual Scripting + +[INCLUDE:Engine/Blueprints#intro] + +%Engine/Blueprints/GettingStarted:topic% + +[REGION:gallery] +[REGION:normaltitle] +Related Videos +[/REGION] +[DIR(playlist_id:"PLZlv_N0_O1gY35ezlSQn1sWOGfh4C7ewO" type:"playlist" output:"playlist")] +[/REGION] + +## Programming + +Implementing gameplay and modifying the engine are essential aspects of any game project. Unreal Engine +gives you the ability to implement gameplay through code or visually using Blueprints or even create a +plugin that modifies or extends the engine and editor to add completely custom functionality for designers +or artists to use. + +%Programming:topic% +%Programming/Development/VisualStudioSetup:topic% +%Programming/QuickStart:topic% +%Programming/Basics:topic% +%Gameplay/Framework/QuickReference:topic% + +[REGION:gallery] +[REGION:normaltitle] +Related Videos +[/REGION] +[DIR(playlist_id:"PLZlv_N0_O1gYup-gvJtMsgJqnEB_dGiM4" type:"playlist" output:"playlist")] +[/REGION] + +## Playtest Your Game + +Test and debug your levels and gameplay using Unreal Engine's built-in features. Get real-time feedback +directly in the editor using Play In Editor mode, and even inspect and manipulate the objects in the +game while it is running using Simulate In Editor mode. Make changes to gameplay code, recompile, and +update the game during play using Hot Reload. + +%Engine/UI/LevelEditor/InEditorTesting:topic% diff --git a/Engine/Documentation/Source/GettingStarted/GettingStarted.KOR.udn b/Engine/Documentation/Source/GettingStarted/GettingStarted.KOR.udn index dba2fff8971b..ecd435b5faf7 100644 --- a/Engine/Documentation/Source/GettingStarted/GettingStarted.KOR.udn +++ b/Engine/Documentation/Source/GettingStarted/GettingStarted.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3351664 +INTSourceChangelist:3429256 Availability:Public Title: UE4 시작하기 Crumbs: %ROOT% @@ -100,221 +100,125 @@ gettingstarted [/PARAM] [/OBJECT] -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/editor_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - 에디터 기본 - [/PARAM] - [PARAM:description] - [INCLUDE:Shared/Glossary/P/#Glossary_project] +## 에디터 기본 - [INCLUDE:Engine/UI/LevelEditor#levels] - [/PARAM] - [PARAM:links] - * [](Engine/QuickStart "%Engine/QuickStart:description%") - * [레벨 에디터 길잡이](Engine/UI/LevelEditor "%Engine/UI/LevelEditor:description%") - * [](Engine/UI/LevelEditor/Toolbar "%Engine/UI/LevelEditor/Toolbar:description%") +[INCLUDE:Shared/Glossary/P/#Glossary_project] - [REGION:gallery] - [REGION:normaltitle] - 관련 비디오 - [/REGION] - [VideoLink(videoid:"w4XlBKeE46E" playlistid:"PLZlv_N0_O1gasd4IcOe9Cx9wHoBB7rxFl" width:"180")] - [/REGION] - [/PARAM] -[/OBJECT] +[INCLUDE:Engine/UI/LevelEditor#levels] -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/viewport_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - 에디터 뷰포트 - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/UI/LevelEditor/Viewports#intro] - [/PARAM] - [PARAM:links] - * [](Engine/UI/LevelEditor/Viewports/Basics "%Engine/UI/LevelEditor/Viewports/Basics:description%") - * [](Engine/UI/LevelEditor/Viewports/ViewportControls "%Engine/UI/LevelEditor/Viewports/ViewportControls:description%") - [/PARAM] -[/OBJECT] +%Engine/QuickStart:topic% +%Engine/UI/LevelEditor:topic% +%Engine/UI/LevelEditor/Toolbar:topic% -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/profile_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - 에디터 모드 - [/PARAM] - [PARAM:description] - [INCLUDE:Shared/Glossary/M#glossary_modes_panel] - [/PARAM] - [PARAM:links] - * [](Engine/UI/LevelEditor/Modes "%Engine/UI/LevelEditor/Modes:description%") - [/PARAM] -[/OBJECT] +[REGION:section] +[REGION:normaltitle] +관련 비디오 +[/REGION] +[DIR(playlist_id:"PLZlv_N0_O1gasd4IcOe9Cx9wHoBB7rxFl" type:"playlist" output:"playlist")] +[/REGION] -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/levels_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - 액터 & 지오메트리 - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/UI/LevelEditor#actors] - [/PARAM] - [PARAM:links] - * [](Engine/Actors/Placement "%Engine/Actors/Placement:description%") - * [지오메트리 액터](Engine/Actors/Brushes "%Engine/Actors/Brushes:description%") - * [](Engine/Actors/Transform "%Engine/Actors/Transform:description%") - - [REGION:gallery] - [REGION:normaltitle] - 관련 비디오 - [/REGION] - [VideoLink(videoid:"cl_eoVfNDKU" playlistid:"PLZlv_N0_O1gak1_FoAJVrEGiLIploeF3F" width:"180")] - [/REGION] - [/PARAM] -[/OBJECT] - -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/cb_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - 콘텐츠 브라우저 - [/PARAM] - [PARAM:description] - [INCLUDE:Shared/Glossary/C/#Glossary_Content_Browser] - [/PARAM] - [PARAM:links] - * [](Engine/Content/QuickStart "%Engine/Content/QuickStart:description%") - * [](Engine/Basics/AssetsAndPackages "%Engine/Basics/AssetsAndPackages:description%") - * [](Engine/Content/Browser "%Engine/Content/Browser:description%") - [/PARAM] -[/OBJECT] - -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/light_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - 라이팅 - [/PARAM] - [PARAM:description] - 씬의 라이팅은 광원 역할을 하면서 다음과 같은 빛의 특성을 결정하는 프로퍼티가 들어있는 라이트 액터를 통해 이루어집니다. - - * 라이트가 얼마나 밝은가 - * 라이트의 색은 어떠한가 - - 여러가지 방식으로 빛을 내뿜는 라이트 종류도 여러가지 있습니다. 예를 들어 일반적인 전구는 모든 방향으로 빛을 내뿜습니다. 언리얼 엔진에서, - 이러한 것은 _포인트 라이트_ 라고 합니다. 한편 투광 조명등처럼 전구 뒷부분을 불투명하게 만들어 빛의 방출을 물리적으로 제한시키는 경우도 있습니다. - 그런 것은 _스포트 라이트_ 라고 합니다. 태양에서 오는 야외의 빛은, 태양이 정말 먼 거리에 있기 때문에, 한 지점이 아닌 한 방향에서 오는 것처럼 보입니다. - 이러한 라이팅 유형의 시뮬레이션으로, _디렉셔널 라이트_ 가 있습니다. - [/PARAM] - [PARAM:links] - * [](Engine/Rendering/LightingAndShadows/QuickStart "%Engine/Rendering/LightingAndShadows/QuickStart:description%") - * [](Engine/Rendering/LightingAndShadows/Basics "%Engine/Rendering/LightingAndShadows/Basics:description%") - [/PARAM] -[/OBJECT] - -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/rendering_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - 머티리얼 & 셰이딩 - [/PARAM] - [PARAM:description] - - [INCLUDE:Shared/Glossary/M/#Glossary_Material] - [/PARAM] - [PARAM:links] - * [](Engine/Rendering/Materials/IntroductionToMaterials "%Engine/Rendering/Materials/IntroductionToMaterials:description%") - - [REGION:gallery] - [REGION:normaltitle] - 관련 비디오 - [/REGION] - [VideoLink(videoid:"lngF4VVNER4" playlistid:"PLZlv_N0_O1gbQjgY0nDwZNYe_N8IcYWS-" width:"180" image:"https://img.youtube.com/vi/lngF4VVNER4/hqdefault.jpg")] - [/REGION] - [/PARAM] -[/OBJECT] - - -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/blueprint_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - 블루프린트 비주얼 스크립팅 - [/PARAM] - [PARAM:description] - [INCLUDE:Engine/Blueprints#intro] - [/PARAM] - [PARAM:links] - * [](Engine/Blueprints/GettingStarted "%Engine/Blueprints/GettingStarted:description%") - - [REGION:gallery] - [REGION:normaltitle] - 관련 비디오 - [/REGION] - [VideoLink(videoid:"EFXMW_UEDco" playlistid:"PLZlv_N0_O1gY35ezlSQn1sWOGfh4C7ewO" width:"180")] - [/REGION] - [/PARAM] -[/OBJECT] - -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/prog_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - 프로그래밍 - [/PARAM] - [PARAM:description] - 게임플레이 구현과 엔진 변경은 어느 게임 프로젝트에 있어서도 핵심적인 부분입니다. 언리얼 엔진은 게임플레이 구현시 - 코드를 통한 방식 말고도 블루프린트를 사용한 비주얼 방식으로도 가능하며, 심지어 엔진이나 에디터를 변경 및 - 확장시키는 플러그인을 제작하여 디자이너나 아티스트가 마음대로 커스텀 함수성을 - 추가할 수도 있습니다. - [/PARAM] - [PARAM:links] - * [](Programming "%Programming:description%") - * [](Programming/Development/VisualStudioSetup "%Programming/Development/VisualStudioSetup:description%") - * [](Programming/QuickStart "%Programming/QuickStart:description%") - * [](Programming/Basics "%Programming/Basics:description%") - * [](Gameplay/Framework/QuickReference "%Gameplay/Framework/QuickReference:description%") +## 에디터 뷰포트 - [REGION:gallery] - [REGION:normaltitle] - 관련 비디오 - [/REGION] - [VideoLink(videoid:"mSRov77hNR4" playlistid:"PLZlv_N0_O1gYup-gvJtMsgJqnEB_dGiM4" width:"180")] - [/REGION] - [/PARAM] -[/OBJECT] +[INCLUDE:Engine/UI/LevelEditor/Viewports#intro] -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/gameplay_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - 게임 플레이 테스트 - [/PARAM] - [PARAM:description] - 언리얼 엔진 내장 기능을 사용하여 레벨과 게임플레이를 테스트하고 버그를 잡습니다. - **에디터에서 플레이** (PIE) 모드로 에디터에서 바로 실시간 피드백을 구하고, - **에디터에서 시뮬레이트** (SIE) 모드로는 실행중인 게임에서도 오브젝트를 확인하고 수정할 수 있습니다. - 이를 통해 플레이 도중에도 코드 변경, 리컴파일, 바로 적용이 가능합니다. - [/PARAM] - [PARAM:links] - * [](Engine/UI/LevelEditor/InEditorTesting "%Engine/UI/LevelEditor/InEditorTesting:description%") - * **플랫폼** - * [](Platforms/iOS/QuickStart "%Platforms/iOS/QuickStart:description%") - * [](Platforms/Android/GettingStarted "%Platforms/Android/GettingStarted:description%") - * [](Platforms/Oculus/QuickStart "%Platforms/Oculus/QuickStart:description%") - [/PARAM] -[/OBJECT] +%Engine/UI/LevelEditor/Viewports/Basics:topic% +%Engine/UI/LevelEditor/Viewports/ViewportControls:topic% + +## 에디터 모드 + +[INCLUDE:Shared/Glossary/M#glossary_modes_panel] + +%Engine/UI/LevelEditor/Modes:topic% + +## 액터 & 지오메트리 + +[INCLUDE:Engine/UI/LevelEditor#actors] + +%Engine/Actors/Placement:topic% +%Engine/Actors/Brushes:topic% +%Engine/Actors/Transform:topic% + +[REGION:section] +[REGION:normaltitle] +관련 비디오 +[/REGION] +[DIR(playlist_id:"PLZlv_N0_O1gak1_FoAJVrEGiLIploeF3F" type:"playlist" output:"playlist")] +[/REGION] + +## 콘텐츠 브라우저 + +[INCLUDE:Shared/Glossary/C/#Glossary_Content_Browser] + +%Engine/Content/QuickStart:topic% +%Engine/Basics/AssetsAndPackages:topic% +%Engine/Content/Browser:topic% + +## 라이팅 + +씬의 라이팅은 광원 역할을 하면서 다음과 같은 빛의 특성을 결정하는 프로퍼티가 들어있는 라이트 액터를 통해 이루어집니다. + +* 라이트가 얼마나 밝은가 +* 라이트의 색은 어떠한가 + +여러가지 방식으로 빛을 내뿜는 라이트 종류도 여러가지 있습니다. 예를 들어 일반적인 전구는 모든 방향으로 빛을 내뿜습니다. 언리얼 엔진에서, +이러한 것은 _포인트 라이트_ 라고 합니다. 한편 투광 조명등처럼 전구 뒷부분을 불투명하게 만들어 빛의 방출을 물리적으로 제한시키는 경우도 있습니다. +그런 것은 _스포트 라이트_ 라고 합니다. 태양에서 오는 야외의 빛은, 태양이 정말 먼 거리에 있기 때문에, 한 지점이 아닌 한 방향에서 오는 것처럼 보입니다. +이러한 라이팅 유형의 시뮬레이션으로, _디렉셔널 라이트_ 가 있습니다. + +%Engine/Rendering/LightingAndShadows/QuickStart:description% +%Engine/Rendering/LightingAndShadows/Basics:description% + +## 머티리얼 & 셰이딩 + +[INCLUDE:Shared/Glossary/M/#Glossary_Material] + +%Engine/Rendering/Materials/IntroductionToMaterials:topic% + +[REGION:section] +[REGION:normaltitle] +관련 비디오 +[/REGION] +[DIR(playlist_id:"PLZlv_N0_O1gbQjgY0nDwZNYe_N8IcYWS-" type:"playlist" output:"playlist")] +[/REGION] + +## 블루프린트 비주얼 스크립팅 + +[INCLUDE:Engine/Blueprints#intro] + +%Engine/Blueprints/GettingStarted:topic% + +[REGION:gallery] +[REGION:normaltitle] +관련 비디오 +[/REGION] +[DIR(playlist_id:"PLZlv_N0_O1gY35ezlSQn1sWOGfh4C7ewO" type:"playlist" output:"playlist")] +[/REGION] + +## 프로그래밍 + +게임플레이 구현과 엔진 변경은 어느 게임 프로젝트에 있어서도 핵심적인 부분입니다. 언리얼 엔진은 게임플레이 구현시 +코드를 통한 방식 말고도 블루프린트를 사용한 비주얼 방식으로도 가능하며, 심지어 엔진이나 에디터를 변경 및 +확장시키는 플러그인을 제작하여 디자이너나 아티스트가 마음대로 커스텀 함수성을 +추가할 수도 있습니다. + +%Programming:topic% +%Programming/Development/VisualStudioSetup:topic% +%Programming/QuickStart:topic% +%Programming/Basics:topic% +%Gameplay/Framework/QuickReference:topic% + +[REGION:gallery] +[REGION:normaltitle] +관련 비디오 +[/REGION] +[DIR(playlist_id:"PLZlv_N0_O1gYup-gvJtMsgJqnEB_dGiM4" type:"playlist" output:"playlist")] +[/REGION] + +## 게임 플레이 테스트 + +언리얼 엔진 내장 기능을 사용하여 레벨과 게임플레이를 테스트하고 버그를 잡습니다. +**에디터에서 플레이** (PIE) 모드로 에디터에서 바로 실시간 피드백을 구하고, +**에디터에서 시뮬레이트** (SIE) 모드로는 실행중인 게임에서도 오브젝트를 확인하고 수정할 수 있습니다. +이를 통해 플레이 도중에도 코드 변경, 리컴파일, 바로 적용이 가능합니다. + +%Engine/UI/LevelEditor/InEditorTesting:topic% diff --git a/Engine/Documentation/Source/GettingStarted/HowTo/DetailsPanel/Transform/Transforms.INT.udn b/Engine/Documentation/Source/GettingStarted/HowTo/DetailsPanel/Transform/Transforms.INT.udn index 22ce92d3ad81..16daa41a16c8 100644 --- a/Engine/Documentation/Source/GettingStarted/HowTo/DetailsPanel/Transform/Transforms.INT.udn +++ b/Engine/Documentation/Source/GettingStarted/HowTo/DetailsPanel/Transform/Transforms.INT.udn @@ -42,10 +42,37 @@ For this How To guide, we will be using a new project using the **Blueprint Thir 1. When the Actor is placed, the **Details** panel in the lower-right porition of the editor will become populated. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] [REGION:lightbox] - [![](Details2.png)](Details2.png) - _Click for full view._ + [![](DetailsPanel_Windows.png)](DetailsPanel_Windows.png) [/REGION] + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + [REGION:lightbox] + [![](DetailsPanel_Mac.png)](DetailsPanel_Mac.png) + [/REGION] + [/PARAM] + [/OBJECT] 1. Inside the **Details** panel under **Transform**, click the lock icon for **Scale** and set the **XYZ** values to **3.0**. diff --git a/Engine/Documentation/Source/GettingStarted/HowTo/DetailsPanel/Transform/Transforms.KOR.udn b/Engine/Documentation/Source/GettingStarted/HowTo/DetailsPanel/Transform/Transforms.KOR.udn index f61cae70ecdc..f6ae8e936835 100644 --- a/Engine/Documentation/Source/GettingStarted/HowTo/DetailsPanel/Transform/Transforms.KOR.udn +++ b/Engine/Documentation/Source/GettingStarted/HowTo/DetailsPanel/Transform/Transforms.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3481084 Availability:Public Title:1. 액터 트랜스폼 작업 Crumbs: %ROOT%, Gameplay, GettingStarted\HowTo, GettingStarted\HowTo\DetailsPanel @@ -43,10 +43,37 @@ checkpoint: editorqs 1. 액터가 배치되면, 에디터 우하단의 **디테일** 패널이 채워집니다. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] [REGION:lightbox] - [![](Details2.png)](Details2.png) - _클릭하면 원래 크기로 봅니다._ + [![](DetailsPanel_Windows.png)](DetailsPanel_Windows.png) [/REGION] + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + [REGION:lightbox] + [![](DetailsPanel_Mac.png)](DetailsPanel_Mac.png) + [/REGION] + [/PARAM] + [/OBJECT] 1. **디테일** 패널에서 **트랜스폼** 아래, **스케일** 부분의 자물쇠 아이콘을 클릭하고 **XYZ** 값을 **3.0** 으로 설정합니다. diff --git a/Engine/Documentation/Source/GettingStarted/HowTo/FindingHelp/FindingHelp.INT.udn b/Engine/Documentation/Source/GettingStarted/HowTo/FindingHelp/FindingHelp.INT.udn index 5b19f9ea7908..782a0afb6c27 100644 --- a/Engine/Documentation/Source/GettingStarted/HowTo/FindingHelp/FindingHelp.INT.udn +++ b/Engine/Documentation/Source/GettingStarted/HowTo/FindingHelp/FindingHelp.INT.udn @@ -38,7 +38,33 @@ Some aspects of the Editor may have a **?** icon next to them. This **Help Icon** when clicked will take you to relevant external documentation related to object it is linked to. -![](HelpIcon_2.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](DetailsPanelHelpIcon_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](DetailsPanelHelpIcon_Mac.png) +[/PARAM] +[/OBJECT] Above we have clicked on a **Brush** Actor in our level, then in the **Details** panel, clicked the **?** Help Icon which automatically opened a documentation page on **Geometry Brush Actors**. This is useful when you are not sure what an object does or want to learn more about the object, but not sure where to look on the official documentation pages. @@ -66,7 +92,33 @@ _Click for full image._ Located in the upper-left corner of an Editor Window is the **Menu Bar** and the **Help** option. -![](HelpMenu.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](HelpTutorials_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](HelpTutorials_Mac.png) +[/PARAM] +[/OBJECT] When clicking the **Help** button, several options are available in the dropdown menu. @@ -90,15 +142,93 @@ Inside the **Help Menu** noted above, next to **Documentation...** you may have Pressing **F1** is a keyboard shortcut to bringing up an Official Documentation page. The **F1 Help** button is context sensitive, meaning that depending on where you are in the Editor, a different help page may be presented to you. For example, below we are in the Main Editor View and pressing **F1** for help displays the home documentation page. -![](F1_1.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](F1_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](F1_Mac.png) +[/PARAM] +[/OBJECT] With a **Blueprint** window open, if we were to press **F1** here a different documentation page is displayed for help regarding Blueprints. -![](F1_2.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](BlueprintHelp_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](BlueprintHelp_Mac.png) +[/PARAM] +[/OBJECT] Or if we were in the **Material Editor**, a page on **Materials** is displayed. -![](F1_3.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](MaterialHelp_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](MaterialHelp_Mac.png) +[/PARAM] +[/OBJECT] Whenever you are in a new Editor window and not sure what it is or how to work with it, try pressing **F1** for help. @@ -106,7 +236,33 @@ Whenever you are in a new Editor window and not sure what it is or how to work w You can also search for help by using the **Help Search** bar located in the upper-right corner of the Main Editor Window. -![](HelpSearch.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](HelpSearch_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](HelpSearch_Mac.png) +[/PARAM] +[/OBJECT] Inside the search bar, you can enter any topic and as you start to enter text, a popup window will display results related to your entry. @@ -140,23 +296,153 @@ These options will allow you to **Exit** the tutorial, proceed to the ***Next** You can access the In-Editor Tutorial hub by clicking the **More Tutorials** option noted above, or by clicking **Help** from the Menu Bar and selecting **Tutorials**. -![](Tutorial_4.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](HelpTutorials_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](HelpTutorials_Mac.png) +[/PARAM] +[/OBJECT] When you open the In-Editor Tutorial hub, a list of tutorials will be presented by category. -![](Tutorial_7.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](Tutorials_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](Tutorials_Mac.png) +[/PARAM] +[/OBJECT] Any In-Editor Tutorials that you have completed will be denoted by a green checkmark next to its icon. -![](Tutorial_8.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](TutorialSearch_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](TutorialSearch_Mac.png) +[/PARAM] +[/OBJECT] Any time you enter an area inside the Editor where a new In-Editor Tutorial is available, an icon will blink in the upper right corner. -![](Tutorial_5.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](SubEditorTutorial_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](SubEditorTutorial_Mac.png) +[/PARAM] +[/OBJECT] Click the blinking icon to start an In-Editor Tutorial covering the area you are currently in. -![](Tutorial_6.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](StaticMeshTutorial_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](StaticMeshTutorial_Mac.png) +[/PARAM] +[/OBJECT] Above we opened a Static Mesh asset, then clicked the In-Editor Tutorial icon and a **Static Mesh Editor** tutorial was started. @@ -178,7 +464,33 @@ For more information, see the [Content Examples](Resources/ContentExamples) docu When you want to learn about a particular feature or aspect of the Editor, the [Official Documentation](https://docs.unrealengine.com/latest/INT/index.html) is the place to start. -![](Documentation1.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](ExtraHelpDocumentation_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](ExtraHelpDocumentation_Mac.png) +[/PARAM] +[/OBJECT] You can use the search field to search for the information you want to retrieve, or you can use the **Quick Search Terms** to browse commonly searched topics. Additionally, you can browse the documentation by topic. If you are new to Unreal Engine 4, **Getting Started** is a fine place to start. @@ -188,13 +500,65 @@ For those that want a more hands-on learning experience, you can take a look at If you cannot find what you are looking for in the Official Documentation or have a specific question, you can search [Answer Hub](https://answers.unrealengine.com/index.html) to see if your question has been asked/answered by Epic Staff or the Unreal Engine community. -![](AnswerHUB1.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](AnswerHub_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](AnswerHub_Mac.png) +[/PARAM] +[/OBJECT] You can enter your topic or question in the search field to see if it has been asked or answered before. Below we searched for **Multiplayer Games** to see what topics came up related to our keyword search. -![](AnswerHUB2.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](AnswerHubSearch_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](AnswerHubSearch_Mac.png) +[/PARAM] +[/OBJECT] Any questions/answers related to Multiplayer Games are returned so that we can browse and see if our particular questions regarding Multiplayer have been asked. @@ -209,7 +573,33 @@ If you are new to Answer Hub, there is a Quick Start guide to using it which you Another resource for help is the [Official Unreal Engine 4 Forums](https://forums.unrealengine.com/forum.php). -![](Forums.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](Forums_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](Forums_Mac.png) +[/PARAM] +[/OBJECT] The forums are broken up into several categories from Animation, Blueprints, and C++ Gameplay Programming to Android or iOS development or even Community Content, Tools, and Tutorials. The forums are largely community driven but Epic Staff does contribute to and respond to posts in the forums quite a bit. While Answer Hub is geared toward one-off questions and answers, the forums is a good place to start a discussion on a particular topic or how to approach creating something in Unreal Engine 4. @@ -219,7 +609,33 @@ approach creating something in Unreal Engine 4. The [Official Unreal Engine 4 Wiki](https://wiki.unrealengine.com/Main_Page) is a place you can go for more Tutorials, Sample Projects, or Code samples. -![](Wiki.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](Wiki_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](Wiki_Mac.png) +[/PARAM] +[/OBJECT] The wiki is a community driven learning resource where users can post their own tutorials for others to use and learn from. Often times in Game Development, trial-and-error is the best method in which to learn something and with the wiki, you can learn from others who may have went through similar stumbling blocks as you. diff --git a/Engine/Documentation/Source/GettingStarted/HowTo/FindingHelp/FindingHelp.KOR.udn b/Engine/Documentation/Source/GettingStarted/HowTo/FindingHelp/FindingHelp.KOR.udn index e250bc8233b9..c2bb45a8c2bd 100644 --- a/Engine/Documentation/Source/GettingStarted/HowTo/FindingHelp/FindingHelp.KOR.udn +++ b/Engine/Documentation/Source/GettingStarted/HowTo/FindingHelp/FindingHelp.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3482370 Availability:Public Title:도움말 & 답변 찾기 Crumbs: %ROOT%, Gameplay, GettingStarted\HowTo @@ -39,7 +39,33 @@ version: 4.9 이 **도움말 아이콘** 을 클릭하면 연결된 오브젝트 관련 외부 문서로 이동됩니다. -![](HelpIcon_2.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](DetailsPanelHelpIcon_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](DetailsPanelHelpIcon_Mac.png) +[/PARAM] +[/OBJECT] 위에서, 레벨의 **브러시** 액터를 클릭한 다음 **디테일** 패널에서 **?** 도움말 아이콘을 클릭하면 **지오메트리 브러시 액터** 관련 문서가 자동으로 열립니다. 오브젝트가 무엇인지 잘 몰라 그에 대해 자세히 알고싶은데, 공식 문서에서 무엇을 찾아봐야 할 지 잘 모르겠는 경우에 좋습니다. @@ -67,7 +93,33 @@ _이미지를 클릭하면 원래 크기로 보입니다._ 에디터 창 좌상단 구석에 있는 것이 **메뉴 바** 이며, 마지막에 있는 옵션이 **도움말** 옵션입니다. -![](HelpMenu.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](HelpTutorials_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](HelpTutorials_Mac.png) +[/PARAM] +[/OBJECT] **도움말** 버튼을 클릭하면, 드롭다운 메뉴에 사용가능 옵션이 여러가지 나타납니다. @@ -91,15 +143,93 @@ _이미지를 클릭하면 원래 크기로 보입니다._ **F1** 키는 공식 문서 페이지를 띄우는 키보드 단축키입니다. **F1 도움말** 버튼은 맥락에 따라 달라지는, 즉 에디터 내 어디서 눌렀는다게 따라 다른 도움말 페이지가 제공될 수 있다는 뜻입니다. 예를 들어, 메인 에디터 뷰에서 **F1** 키를 눌러 홈 문서 페이지의 도움말을 표시한 것입니다. -![](F1_1.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](F1_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](F1_Mac.png) +[/PARAM] +[/OBJECT] **블루프린트** 창이 열려있을 때 **F1** 키를 눌렀다면, 블루프린트 관련 도움말이 표시되는 문서가 열립니다. -![](F1_2.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](BlueprintHelp_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](BlueprintHelp_Mac.png) +[/PARAM] +[/OBJECT] 아니면 **머티리얼 에디터** 에 있었던 경우, **머티리얼** 관련 페이지가 표시됩니다. -![](F1_3.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](MaterialHelp_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](MaterialHelp_Mac.png) +[/PARAM] +[/OBJECT] 새 에디터 창에서 작업 방법을 잘 모르겠다면, **F1** 키를 눌러 도움말을 참고해 보세요. @@ -107,7 +237,33 @@ _이미지를 클릭하면 원래 크기로 보입니다._ 메인 에디터 창 우상단 구석에 위치한 **도움말 검색창** 에서도 도움말을 검색할 수 있습니다. -![](HelpSearch.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](HelpSearch_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](HelpSearch_Mac.png) +[/PARAM] +[/OBJECT] 검색창 안에 원하는 주제를 입력할 수 있으며, 글자를 입력하기 시작하면 거기에 관련된 결과가 표시되는 팝업창이 뜹니다. @@ -141,23 +297,153 @@ _이미지를 클릭하면 원래 크기로 보입니다._ 위에 언급한 **추가 튜토리얼** 을 클릭하거나, 메뉴 바의 **도움말** - **튜토리얼** 을 선택하여 에디터내 튜토리얼 허브를 접할 수 있습니다. -![](Tutorial_4.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](HelpTutorials_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](HelpTutorials_Mac.png) +[/PARAM] +[/OBJECT] 에디터내 튜토리얼 허브를 열면, 튜토리얼 목록이 범주별로 나타납니다. -![](Tutorial_7.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](Tutorials_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](Tutorials_Mac.png) +[/PARAM] +[/OBJECT] 완료했던 에디터내 튜토리얼은 그 아이콘 옆에 녹색 체크표시가 붙습니다. -![](Tutorial_8.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](TutorialSearch_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](TutorialSearch_Mac.png) +[/PARAM] +[/OBJECT] 새로운 에디터내 튜토리얼이 가능한 에디터내 특정 부분에 들어서면, 우상단 구석에 아이콘이 깜빡입니다. -![](Tutorial_5.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](SubEditorTutorial_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](SubEditorTutorial_Mac.png) +[/PARAM] +[/OBJECT] 깜빡이는 아이콘을 클릭하면 현재 들어와 있는 영역에 관련된 에디터내 튜토리얼이 시작됩니다. -![](Tutorial_6.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](StaticMeshTutorial_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](StaticMeshTutorial_Mac.png) +[/PARAM] +[/OBJECT] 위에서 **스태틱 메시** 애셋을 연 다음 에디터내 튜토리얼 아이콘을 클릭했더니 **스태틱 메시 에디터** 튜토리얼이 시작되었습니다. @@ -179,7 +465,33 @@ _이미지를 클릭하면 원래 크기로 보입니다._ 에디터의 특정 기능 및 부분에 대해 배우고자 할 때는, [공식 문서](https://docs.unrealengine.com/latest/KOR/index.html) 가 시작하기 딱 좋은 곳입니다. -![](Documentation1.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](ExtraHelpDocumentation_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](ExtraHelpDocumentation_Mac.png) +[/PARAM] +[/OBJECT] 검색창을 통해 얻고자 하는 정보를 검색하거나, **빠른 검색어** 를 통해 자주 검색되는 주제를 둘러볼 수 있습니다. 추가적으로, 주제를 통해 문서를 둘러볼 수 있습니다. 언리얼 엔진 4 에 처음이신 분들은, **시작하기** 부터 시작해 보시면 좋습니다. @@ -189,13 +501,65 @@ _이미지를 클릭하면 원래 크기로 보입니다._ 공식 문서에서 원하는 것을 찾지 못했거나 특정한 질문이 있으신 경우, [Answer Hub](https://answers.unrealengine.com/index.html) 를 검색해 보면 에픽 직원이나 언리얼 엔진 커뮤니티에서 질문/답변이 되었는지 확인해 볼 수 있습니다. -![](AnswerHUB1.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](AnswerHub_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](AnswerHub_Mac.png) +[/PARAM] +[/OBJECT] 검색칸에 주제나 질문을 입력하여 전에 질문/답변이 있었는지 확인할 수 있습니다. 아래에는 **Multiplayer Games** 를 입력하여 검색어에 일치한 주제를 확인한 것입니다. -![](AnswerHUB2.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](AnswerHubSearch_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](AnswerHubSearch_Mac.png) +[/PARAM] +[/OBJECT] 멀티플레이어 게임 관련 질문/답변 결과가 나와 찾는 질문이 이미 있었는지 둘러보며 확인할 수 있습니다. @@ -210,16 +574,69 @@ Answer Hub 가 처음이신 경우, [Quick Start Guide](https://answers.unrealen [공식 언리얼 엔진 4 Forums](https://forums.unrealengine.com/forum.php) 역시도 또하나의 도움말 참고 자료입니다. -![](Forums.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](Forums_Windows.png) +[/PARAM] +[/OBJECT] -포럼은 **애니메이션**, **블루프린트**, **C++ 게임플레이 프로그래밍**, **안드로이드** 나 **iOS** 개발, **커뮤니티 콘텐츠, 툴, 튜토리얼** 등등 여러 범주별로 나뉘어 있습니다. 포럼은 크게 커뮤니티 기반으로 이루어지나, 에픽의 직원들 역시도 포럼 게시물에 답변하는 등 기여를 많이 합니다. **Answer Hub** 가 일회성 질문 답변에 초점을 맞춘 반면, 포럼은 언리얼 엔진 4 의 특정 주제나 무언가를 만드는 접근법에 대한 논의를 시작하기 좋은 곳입니다. +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](Forums_Mac.png) +[/PARAM] +[/OBJECT] + +포럼은 **애니메이션**, **블루프린트**, **C++ 게임플레이 프로그래밍**, **안드로이드** 나 **iOS** 개발, **커뮤니티 콘텐츠, 툴, 튜토리얼** 등등 여러 범주별로 나뉘어 있습니다. 포럼은 크게 커뮤니티 기반으로 이루어지나, 에픽의 직원들 역시도 포럼 게시물에 답변하는 등 기여를 많이 합니다. **Answer Hub** 가 일회성 질문 답변에 초점을 맞춘 반면, 포럼은 언리얼 엔진 4 의 특정 주제나 무언가를 만드는 접근법에 대한 +논의를 시작하기 좋은 곳입니다. ## 외부 도움말: 위키 [공식 언리얼 엔진 4 위키](https://wiki.unrealengine.com/Main_Page) 는 더 많은 튜토리얼, 샘플 프로젝트, 코드 샘플을 찾을 수 있는 곳입니다. -![](Wiki.png) +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](Wiki_Windows.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](Wiki_Mac.png) +[/PARAM] +[/OBJECT] 위키는 커뮤니티 주도형 학습 자료 사이트로, 사용자가 다른 이가 보고 배울 수 있도록 튜토리얼을 올리는 곳입니다. 종종 게임 개발에 있어 시행착오를 통한 개선이 무언가를 배우는 데는 최선의 방법이며, 위키를 통해 여러분과 비슷한 무언가를 겪었을 다른 이들로부터 무언가를 배울 수 있습니다. diff --git a/Engine/Documentation/Source/GettingStarted/HowTo/PIE/PIE.INT.udn b/Engine/Documentation/Source/GettingStarted/HowTo/PIE/PIE.INT.udn index 90045b7af229..80031a3fff81 100644 --- a/Engine/Documentation/Source/GettingStarted/HowTo/PIE/PIE.INT.udn +++ b/Engine/Documentation/Source/GettingStarted/HowTo/PIE/PIE.INT.udn @@ -27,7 +27,37 @@ This section will show you how you can use **Play In Editor** to play your game. When clicking the **Play** button, the game should start and you should see the character in the Level Editor Viewport. - ![](PIE2b.png)(w:800) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + [REGION:lightbox] + ![](PIE_Windows.png) + [/REGION] + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + [REGION:lightbox] + ![](PIE_Mac.png) + [/REGION] + [/PARAM] + [/OBJECT] You will also see text appear in the upper left corner of the Level Editor Viewport. diff --git a/Engine/Documentation/Source/GettingStarted/HowTo/PIE/PIE.KOR.udn b/Engine/Documentation/Source/GettingStarted/HowTo/PIE/PIE.KOR.udn index 7033bfefd403..08f541f37dec 100644 --- a/Engine/Documentation/Source/GettingStarted/HowTo/PIE/PIE.KOR.udn +++ b/Engine/Documentation/Source/GettingStarted/HowTo/PIE/PIE.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3481084 Availability:Public Title:플레이 & 시뮬레이트 Crumbs: %ROOT%, Gameplay, GettingStarted\HowTo @@ -28,7 +28,37 @@ version: 4.9 **플레이** 버튼을 클릭하면 게임이 시작되고, 레벨 에디터 뷰포트에서 캐릭터를 확인할 수 있습니다. - ![](PIE2b.png)(w:800) + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + [REGION:lightbox] + ![](PIE_Windows.png) + [/REGION] + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + [REGION:lightbox] + ![](PIE_Mac.png) + [/REGION] + [/PARAM] + [/OBJECT] 레벨 에디터 뷰포트 좌상단 구석에 텍스트가 나타나는 것도 보일 것입니다. diff --git a/Engine/Documentation/Source/GettingStarted/Installation/InstallingUnrealEngine.KOR.udn b/Engine/Documentation/Source/GettingStarted/Installation/InstallingUnrealEngine.KOR.udn index b55d11ec7159..53aadfd57313 100644 --- a/Engine/Documentation/Source/GettingStarted/Installation/InstallingUnrealEngine.KOR.udn +++ b/Engine/Documentation/Source/GettingStarted/Installation/InstallingUnrealEngine.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3367474 Availability:Public Title:언리얼 엔진 설치하기 Description:언리얼 엔진 설치법 단계별 안내입니다. @@ -14,25 +14,25 @@ SkillLevel: Beginner 이 튜토리얼을 통해 배울 수 있는 내용은 다음과 같습니다: -* [에픽 게임스 계정 생성 (없는 경우)](#Bookmark1) -* [인스톨러 다운로드 및 실행 (에픽 게임스 런처 구성 프로그램)](#Bookmark2) -* [에픽 게임스 런처 로그인](#Bookmark3) +* [에픽 게임즈 계정 생성 (없는 경우)](#Bookmark1) +* [인스톨러 다운로드 및 실행 (에픽 게임즈 런처 구성 프로그램)](#Bookmark2) +* [에픽 게임즈 런처 로그인](#Bookmark3) * [언리얼 엔진 설치](#Bookmark4) * [언리얼 엔진 실행](#Bookmark5) ![](InstallationGoal.png) -에픽 게임스 런처를 통해 UE4 를 보다 편리하게 다운로드하고 업데이트를 설치할 수 있습니다. +에픽 게임즈 런처를 통해 UE4 를 보다 편리하게 다운로드하고 업데이트를 설치할 수 있습니다. [REGION:warning] -이미 에픽 게임스 계정이 있으시다면, [인스톨러 다운로드 및 실행](#Bookmark2) 부분으로 넘어가시기 바랍니다. +이미 에픽 게임즈 계정이 있으시다면, [인스톨러 다운로드 및 실행](#Bookmark2) 부분으로 넘어가시기 바랍니다. [/REGION] (#Bookmark1) -## 에픽 게임스 계정 생성 +## 에픽 게임즈 계정 생성 -에픽 게임스 런처 실행을 위해서는, 유효한 에픽 게임스 계정이 있어야 합니다. +에픽 게임즈 런처 실행을 위해서는, 유효한 에픽 게임즈 계정이 있어야 합니다. [INCLUDE:GettingStarted/AccountSetup#epicAccount] @@ -40,7 +40,7 @@ SkillLevel: Beginner (#Bookmark2) -유효한 에픽 게임스 계정이 있으면 인스톨러 (에픽 게임스 구성 프로그램) 다운로드가 가능합니다. +유효한 에픽 게임즈 계정이 있으면 인스톨러 (에픽 게임즈 구성 프로그램) 다운로드가 가능합니다. %Globals:osselect_linux% @@ -55,20 +55,26 @@ SkillLevel: Beginner active_button_content [/PARAMLITERAL] [PARAM:content] - 1. **다운로드** 버튼을 눌러 인스톨러를 받습니다. - - ![](Download_Screen.png) - - 1. 다운로드가 완료되면, 인스톨러를 실행합니다. - - ![](RunInstaller.png) - - 1. **에픽 게임스 런처 구성** 대화창이 뜨면 **설치** 버튼을 누릅니다. - - ![](RunEpicLauncherSetup.png) + [INCLUDE:#windows_install] [/PARAM] [/OBJECT] + + [OBJECT:ToggleButtonContent] [PARAMLITERAL:category] OS @@ -86,7 +92,7 @@ SkillLevel: Beginner 1. `**Finder**` 에서 `EpicGamesLauncher.dmg` 아이콘을 더블클릭하여 창을 새로 엽니다. - 1. **에픽 게임스 런처** 아이콘을 끌어 **Applications** 폴더에 놓습니다. + 1. **에픽 게임즈 런처** 아이콘을 끌어 **Applications** 폴더에 놓습니다. ![](InstallEpicLaucherMac.png) [/PARAM] @@ -114,7 +120,7 @@ SkillLevel: Beginner (#Bookmark3) -구성 프로그램이 로컬 머신에 에픽 게임스 런처를 설치한 이후에는, 에픽 게임스 계정 정보로 로그인합니다. +구성 프로그램이 로컬 머신에 에픽 게임즈 런처를 설치한 이후에는, 에픽 게임즈 계정 정보로 로그인합니다. ![](EpicSignIn.png) @@ -122,7 +128,7 @@ SkillLevel: Beginner (#Bookmark4) -에픽 게임스 런처에 로그인했으니 UE4 설치 준비가 다 되었습니다. +에픽 게임즈 런처에 로그인했으니 UE4 설치 준비가 다 되었습니다. [REGION:warning] [REGION:largetitle] @@ -131,7 +137,7 @@ SkillLevel: Beginner 언리얼 엔진은 설치되는 버전당 약 8 GB 정도의 하드 디스크 공간이 필요합니다. UE4 설치 전 공간이 충분한지 확인하세요. [/REGION] -1. 에픽 게임스 런처 로딩 화면 안에서 **언리얼 엔진** 탭을 클릭합니다. +1. 에픽 게임즈 런처 로딩 화면 안에서 **언리얼 엔진** 탭을 클릭합니다. ![](LauncherLoadScreen.png) @@ -153,15 +159,15 @@ SkillLevel: Beginner (#Bookmark5) -에픽 게임스 런처가 언리얼 엔진 다운로드 & 설치에 성공한 이후, **실행** 버튼을 누르면 됩니다. +에픽 게임즈 런처가 언리얼 엔진 다운로드 & 설치에 성공한 이후, **실행** 버튼을 누르면 됩니다. ![](LaunchUE4.png) 축하합니다! 지금까지 배우신 내용은 다음과 같습니다: -✓ [에픽 게임스 계정 생성 (없는 경우)](#Bookmark1) -✓ [인스톨러 다운로드 및 실행 (에픽 게임스 런처 구성 프로그램)](#Bookmark2) -✓ [에픽 게임스 런처 로그인](#Bookmark3) +✓ [에픽 게임즈 계정 생성 (없는 경우)](#Bookmark1) +✓ [인스톨러 다운로드 및 실행 (에픽 게임즈 런처 구성 프로그램)](#Bookmark2) +✓ [에픽 게임즈 런처 로그인](#Bookmark3) ✓ [언리얼 엔진 설치](#Bookmark4) ✓ [언리얼 엔진 실행](#Bookmark5) diff --git a/Engine/Documentation/Source/GettingStarted/LinuxInstructions/LinuxInstructions.INT.udn b/Engine/Documentation/Source/GettingStarted/LinuxInstructions/LinuxInstructions.INT.udn new file mode 100644 index 000000000000..e137e75e3ffb --- /dev/null +++ b/Engine/Documentation/Source/GettingStarted/LinuxInstructions/LinuxInstructions.INT.udn @@ -0,0 +1,18 @@ +Availability: NoPublish +Title: Linux Instructions +Crumbs: %ROOT% +Description: Telling Linux users how to download the Unreal Engine source code from GitHub. +version: 4.16 +parent:GettingStarted +Order: + +1. [Set up Git](https://help.github.com/articles/set-up-git/) and [fork our repository](https://help.github.com/articles/fork-a-repo/). + If you'd prefer not to use Git, use the 'Download ZIP' button on the right to get the source as a zip file. + +1. Open your source folder and run **Setup.sh** to download binary content for the engine. + +1. Both cross-compiling and native builds are supported. + + **Cross-compiling** is handy when you are a Windows (Mac support planned too) developer who wants to package your game for Linux with minimal hassle, and it requires a [cross-compiler toolchain](http://cdn.unrealengine.com/qfe/v8_clang-3.9.0-centos7.zip) to be installed (see the [Linux cross-compiling page on the wiki](https://docs.unrealengine.com/latest/INT/Platforms/Linux/GettingStarted/)). + + **Native compilation** is discussed in [a separate README](https://github.com/EpicGames/UnrealEngine/blob/release/Engine/Build/BatchFiles/Linux/README.md) and [community wiki page](https://wiki.unrealengine.com/Building_On_Linux). \ No newline at end of file diff --git a/Engine/Documentation/Source/GettingStarted/LinuxInstructions/LinuxInstructions.JPN.udn b/Engine/Documentation/Source/GettingStarted/LinuxInstructions/LinuxInstructions.JPN.udn new file mode 100644 index 000000000000..4db4fd72489e --- /dev/null +++ b/Engine/Documentation/Source/GettingStarted/LinuxInstructions/LinuxInstructions.JPN.udn @@ -0,0 +1,19 @@ +INTSourceChangelist:3426963 +Availability:NoPublish +Title:Linux ユーザーへの案内 +Crumbs: %ROOT% +Description:Linux ユーザーに GitHub からアンリアル エンジンのソースコードをダウンロードするように伝える +version:4.16 +parent:GettingStarted +Order: + +1. [Set up Git](https://help.github.com/articles/set-up-git/) および [fork our repository](https://help.github.com/articles/fork-a-repo/)。 + Git を使用したくない場合は、'Download ZIP' ボタンを使ってソースを Zip ファイルでダウンロードしてください。 + +1. ソースフォルダを 開き **Setup.sh** を実行して、エンジンのバイナリ コンテンツを ダウンロード します。 + +1. クロスコンパイルとネイティブ ビルドがサポートされます。 + + Windows (Mac もサポート予定) デベロッパーが一番楽な方法でゲームを Linux 向けにパッケージ化する場合、**クロスコンパイル** が便利です。その場合、[クロスコンパイラ ツールチェーン](http://cdn.unrealengine.com/qfe/v8_clang-3.9.0-centos7.zip) のインストールが必要です ([Wiki の Linux 向けクロスコンパイルの説明](https://docs.unrealengine.com/latest/INT/Platforms/Linux/GettingStarted/) をご覧ください)。 + + **ネイティブ コンパイル** は [README](https://github.com/EpicGames/UnrealEngine/blob/release/Engine/Build/BatchFiles/Linux/README.md) および [コミュニティ Wiki ページ](https://wiki.unrealengine.com/Building_On_Linux) で説明されています。 \ No newline at end of file diff --git a/Engine/Documentation/Source/GettingStarted/LinuxInstructions/LinuxInstructions.KOR.udn b/Engine/Documentation/Source/GettingStarted/LinuxInstructions/LinuxInstructions.KOR.udn new file mode 100644 index 000000000000..d67fc97bf4f1 --- /dev/null +++ b/Engine/Documentation/Source/GettingStarted/LinuxInstructions/LinuxInstructions.KOR.udn @@ -0,0 +1,19 @@ +INTSourceChangelist:3426963 +Availability: NoPublish +Title: 리눅스 안내 +Crumbs: %ROOT% +Description: 리눅스에서 GitHub 의 언리얼 엔진 소스 코드를 다운로드하는 방법입니다. +version: 4.16 +parent:GettingStarted +Order: + +1. [Git 셋업](https://help.github.com/articles/set-up-git/) 후 [repository 를 fork](https://help.github.com/articles/fork-a-repo/) 합니다. + Git 를 사용하고 싶지 않은 경우, 오른쪽의 'Download ZIP" 버튼을 누르면 소스를 zip 파일로 받습니다. + +1. 소스 폴더를 열고 **Setup.sh** 를 실행시켜 엔진 바이너리 콘텐츠를 다운로드합니다. + +1. 크로스 컴파일 및 네이티브 빌드 모두 지원합니다. + + **크로스 컴파일** 은 윈도우에서 (맥도 지원할 계획이 있습니다) 최소한의 번거로운 작업으로 리눅스용 게임을 패키징하고자 하는 경우 편리하며, [크로스 컴파일러 툴체인](http://cdn.unrealengine.com/qfe/v8_clang-3.9.0-centos7.zip) 이 설치되어 있어야 합니다 (자세한 내용은 [리눅스 크로스 컴파일 페이지](Platforms/Linux/GettingStarted) 를 참고하세요). + + **네이티브 컴파일** 은 [별도의 README](https://github.com/EpicGames/UnrealEngine/blob/release/Engine/Build/BatchFiles/Linux/README.md) 와 [커뮤니티 wiki 페이지](https://wiki.unrealengine.com/Building_On_Linux) 에서 찾아볼 수 있습니다. \ No newline at end of file diff --git a/Engine/Documentation/Source/GettingStarted/MacInstructions/MacInstructions.INT.udn b/Engine/Documentation/Source/GettingStarted/MacInstructions/MacInstructions.INT.udn new file mode 100644 index 000000000000..0ac04f39c514 --- /dev/null +++ b/Engine/Documentation/Source/GettingStarted/MacInstructions/MacInstructions.INT.udn @@ -0,0 +1,25 @@ +Availability: NoPublish +Title: Mac Instructions +Crumbs: %ROOT% +Description: Telling Mac users how to download the Unreal Engine source code from GitHub. +version: 4.16 +parent:GettingStarted +Order: + +1. Install [GitHub for Mac](https://mac.github.com/) then [fork and clone our repository](https://guides.github.com/activities/forking/). + + To use Git from the Terminal, see the [Setting up Git](https://help.github.com/articles/set-up-git/) and [Fork a Repo](https://help.github.com/articles/fork-a-repo/) articles. + If you'd rather not use Git, use the 'Download ZIP' button on the right to get the source directly. + +1. Install the latest version of [Xcode](https://itunes.apple.com/us/app/xcode/id497799835). + +1. Open your source folder in Finder and double-click on **Setup.command** to download binary content for the engine. You can close the Terminal window afterwards. + + If you downloaded the source as a .zip file, you may see a warning about it being from an unidentified developer (because .zip files on GitHub aren't digitally signed). + To work around it, right-click on Setup.command, select Open, then click the Open button. + +1. In the same folder, double-click **GenerateProjectFiles.command**. It should take less than a minute to complete. + +1. Load the project into Xcode by double-clicking on the **UE4.xcworkspace** file. Select the **ShaderCompileWorker** for **My Mac** target in the title bar, then select the 'Product > Build' menu item. When Xcode finishes building, do the same for the **UE4** for **My Mac** target. Compiling may take anywhere between 15 and 40 minutes, depending on your system specs. + +1. After compiling finishes, select the 'Product > Run' menu item to load the editor. \ No newline at end of file diff --git a/Engine/Documentation/Source/GettingStarted/MacInstructions/MacInstructions.JPN.udn b/Engine/Documentation/Source/GettingStarted/MacInstructions/MacInstructions.JPN.udn new file mode 100644 index 000000000000..dbe9c2135c11 --- /dev/null +++ b/Engine/Documentation/Source/GettingStarted/MacInstructions/MacInstructions.JPN.udn @@ -0,0 +1,26 @@ +INTSourceChangelist:3426963 +Availability:NoPublish +Title:Mac ユーザーへの案内 +Crumbs: %ROOT% +Description:Mac ユーザーに GitHub からアンリアル エンジンのソースコードをダウンロードするように伝える +version:4.16 +parent:GettingStarted +Order: + +1. [GitHub for Mac](https://mac.github.com/) そして [fork and clone our repository](https://guides.github.com/activities/forking/) をインストールします。 + + ターミナルで Git を使用する場合は、[Git を設定する](https://help.github.com/articles/set-up-git/) と [レポジトリをフォークする](https://help.github.com/articles/fork-a-repo/) に関する記事を参照してください。 + Git を使用したくない場合は、'Download ZIP' ボタンを使ってソースを直接ダウンロードしてください。 + +1. [Xcode](https://itunes.apple.com/us/app/xcode/id497799835) の最新版をインストールしてください。 + +1. Finder でソースフォルダを 開き **Setup.sh** をダブルクリックしてエンジンのバイナリ コンテンツをダウンロードします。ダウンロードしたらターミナルのウィンドウを閉じます。 + + Zip ファイルでソースをダウンロードすると、デベロッパーとして認識できない旨の警告が表示されます (GitHub 上の Zip ファイルはデジタル署名されていないので)。 + 回避するには、Setup.コマンドを右くりっくして、[Open] を選択し、[Open] ボタンをクリックします。 + +1. 同じフォルダの中の **GenerateProjectFiles.command** をダブルクリックします。完了までに 1 分弱程度かかります。 + +1. プロジェクトを XCode にロードするには、**「UE4.xcworkspace」** ファイルをダブルクリックします。タイトルバーで **My Mac** ターゲット向け **ShaderCompileWorker** を選択し、次に [Product] > [Build] を選択します。Xcode のビルドが終了したら、**My Mac** ターゲット向け **UE4** を選択し同じことをします。システム仕様によっては、コンパイルに 15 分から 40 分程度かかることがあります。 + +1. コンパイルが終了したら [Product] > [Run] を選択してエディタをロードします。 \ No newline at end of file diff --git a/Engine/Documentation/Source/GettingStarted/MacInstructions/MacInstructions.KOR.udn b/Engine/Documentation/Source/GettingStarted/MacInstructions/MacInstructions.KOR.udn new file mode 100644 index 000000000000..875f9060e564 --- /dev/null +++ b/Engine/Documentation/Source/GettingStarted/MacInstructions/MacInstructions.KOR.udn @@ -0,0 +1,26 @@ +INTSourceChangelist:3426963 +Availability: NoPublish +Title: 맥 안내 +Crumbs: %ROOT% +Description: 맥에서 GitHub 의 언리얼 엔진 소스 코드를 다운로드하는 방법입니다. +version: 4.16 +parent:GettingStarted +Order: + +1. [맥용 GitHub](https://mac.github.com/) 를 설치한 뒤 [repository 를 fork 및 clone](https://guides.github.com/activities/forking/) 합니다. + + Terminal 에서 Git 를 사용하는 방법은, [Setting up Git](https://help.github.com/articles/set-up-git/) 및 [Fork a Repo](https://help.github.com/articles/fork-a-repo/) 페이지를 참고하세요. + Git 를 사용하고 싶지 않으면, 오른쪽의 'Download ZIP' 버튼으로 소스를 바로 다운로드할 수 있습니다. + +1. [Xcode](https://itunes.apple.com/us/app/xcode/id497799835) 최신 버전을 설치합니다. + +1. Finder 에서 소스 폴더를 열고 **Setup.command** 를 더블클릭하여 엔진 바이너리 콘텐츠를 다운로드합니다. 그 후 Terminal 창을 닫아도 됩니다. + + 소스를 .zip 파일로 다운로드했다면, 개발자를 알 수 없다는 경고가 뜰 것입니다 (GitHub 의 .zip 파일은 디지털 사인 되어있지 않기 때문입니다). + 우회법은, Setup.command 에 우클릭하고, Open 을 선택한 뒤 Open 버튼을 클릭하면 됩니다. + +1. 같은 폴더에서 **GenerateProjectFiles.command** 를 더블클릭합니다. 1 분이 채 안되어 완료될 것입니다. + +1. **UE4.xcworkspace** 파일을 더블클릭하여 프로젝트를 Xcode 에 로드합니다. 제목줄에서 **My Mac** 타겟에 대한 **ShaderCompileWorker** 를 선택한 뒤, 'Product > Build' 메뉴 항목을 선택합니다. Xcode 빌드가 끝나면, **My Mac** 타겟의 **UE4** 에 대해서도 같은 작업을 해줍니다. 시스템 사양에 따라 컴파일 시간은 15 - 40 분 정도 걸립니다. + +1. 컴파일이 끝나면, 'Product > Run' 메뉴 항목으로 에디터를 로드합니다. \ No newline at end of file diff --git a/Engine/Documentation/Source/GettingStarted/SubEditors/SubEditors.INT.udn b/Engine/Documentation/Source/GettingStarted/SubEditors/SubEditors.INT.udn index 0504e5bd91c9..3e495fd7ff6c 100644 --- a/Engine/Documentation/Source/GettingStarted/SubEditors/SubEditors.INT.udn +++ b/Engine/Documentation/Source/GettingStarted/SubEditors/SubEditors.INT.udn @@ -3,40 +3,7 @@ Title:Tools and Editors Crumbs: %ROOT%, Gameplay, GettingStarted Description:There are several different types of Editors contained within Unreal Engine 4, this page highlights each of them. version: 4.9 - -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![](editortypes_topic.png) - [/PARAM] - [PARAM:title] - %GettingStarted\SubEditors:title% - [/PARAM] - [PARAM:path] - [RELATIVE:GettingStarted\SubEditors] - [/PARAM] - [PARAM:description] - %GettingStarted\SubEditors:description% - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![](editortypes_topic.png) - [/PARAM] - [PARAM:title] - %GettingStarted\SubEditors:title% - [/PARAM] - [PARAM:path] - [RELATIVE:GettingStarted\SubEditors] - [/PARAM] - [PARAM:description] - %GettingStarted\SubEditors:description% - [/PARAM] -[/OBJECT] -[/VAR] +topic-image:editortypes_topic.png This page is intended to give you an overview of each of the different types of Editors that you will be working with inside Unreal Engine 4. Whether you are inside the **Level Editor** building your game's level, working with the **Blueprint Editor** to script behaviors for the Actors in your level, creating particle effects with the **Cascade Editor** or setting up animations for characters inside the **Persona Editor**; a good understanding of what each Editor can do and how to navigate it can improve your workflow and help prevent any stumbling blocks during development. @@ -45,23 +12,56 @@ Refer to each of the sections below for an overview along with links to more det | ------- | ------------ | -|![](LevelEditorImage.png)(w:400 h:240)|[INCLUDE:GettingStarted\SubEditors#leveleditor]| -|![](MaterialEditorImage.png)(w:400 h:240)|[INCLUDE:GettingStarted\SubEditors#materialeditor]| -|![](BlueprintEditorImage.png)(w:400 h:240)|[INCLUDE:GettingStarted\SubEditors#blueprinteditor]| -|![](BehaviorTreeImage.png)(w:400 h:240)|[INCLUDE:GettingStarted\SubEditors#behavioreditor]| -|![](PersonaEditorImage.png)(w:400 h:240)|[INCLUDE:GettingStarted\SubEditors#personaeditor]| -|![](CascadeEditorImage.png)(w:400 h:240)|[INCLUDE:GettingStarted\SubEditors#cascadeeditor]| -|![](UMGUIEditorImage.png)(w:400 h:240)|[INCLUDE:GettingStarted\SubEditors#umguieditor]| -|![](MatineeEditorImage.png)(w:400 h:240)|[INCLUDE:GettingStarted\SubEditors#matineeeditor]| -|![](SoundCueEditorImage.png)(w:400 h:240)|[INCLUDE:GettingStarted\SubEditors#soundcueeditor]| -|![](SpriteEditorImage.png)(w:400 h:240)|[INCLUDE:GettingStarted\SubEditors#spriteeditor]| -|![](FlipbookEditorImage.png)(w:400 h:240)|[INCLUDE:GettingStarted\SubEditors#flipbookeditor]| -|![](PhatEditorImage.png)(w:400 h:240)|[INCLUDE:GettingStarted\SubEditors#phateditor]| -|![](StaticMeshEditorImage.png)(w:400 h:240)|[INCLUDE:GettingStarted\SubEditors#staticmesheditor]| -|![](MediaFrameworkImage.png)(w:400 h:240)|[INCLUDE:GettingStarted\SubEditors#mediaeditor]| +|[INCLUDE:GettingStarted\SubEditors#leveleditorimage]|[INCLUDE:GettingStarted\SubEditors#leveleditor]| +|[INCLUDE:GettingStarted\SubEditors#materialeditorimage]|[INCLUDE:GettingStarted\SubEditors#materialeditor]| +|[INCLUDE:GettingStarted\SubEditors#blueprinteditorimage]|[INCLUDE:GettingStarted\SubEditors#blueprinteditor]| +|[INCLUDE:GettingStarted\SubEditors#behavioreditorimage]|[INCLUDE:GettingStarted\SubEditors#behavioreditor]| +|[INCLUDE:GettingStarted\SubEditors#personaeditorimage]|[INCLUDE:GettingStarted\SubEditors#personaeditor]| +|[INCLUDE:GettingStarted\SubEditors#cascadeeditorimage]|[INCLUDE:GettingStarted\SubEditors#cascadeeditor]| +|[INCLUDE:GettingStarted\SubEditors#umguieditorimage]|[INCLUDE:GettingStarted\SubEditors#umguieditor]| +|[INCLUDE:GettingStarted\SubEditors#matineeeditorimage]|[INCLUDE:GettingStarted\SubEditors#matineeeditor]| +|[INCLUDE:GettingStarted\SubEditors#soundcueeditorimage]|[INCLUDE:GettingStarted\SubEditors#soundcueeditor]| +|[INCLUDE:GettingStarted\SubEditors#spriteeditorimage]|[INCLUDE:GettingStarted\SubEditors#spriteeditor]| +|[INCLUDE:GettingStarted\SubEditors#flipbookeditorimage]|[INCLUDE:GettingStarted\SubEditors#flipbookeditor]| +|[INCLUDE:GettingStarted\SubEditors#phateditorimage]|[INCLUDE:GettingStarted\SubEditors#phateditor]| +|[INCLUDE:GettingStarted\SubEditors#staticmesheditorimage]|[INCLUDE:GettingStarted\SubEditors#staticmesheditor]| +|[INCLUDE:GettingStarted\SubEditors#mediaeditorimage]|[INCLUDE:GettingStarted\SubEditors#mediaeditor]| +[INCLUDE:Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/1#AndroidLinux_1] [/EXCERPT:LinuxSetup] --> diff --git a/Engine/Documentation/Source/Platforms/Android/GettingStarted/1/AndroidQS_1.JPN.udn b/Engine/Documentation/Source/Platforms/Android/GettingStarted/1/AndroidQS_1.JPN.udn index eac30f8e632d..43a8d36a923c 100644 --- a/Engine/Documentation/Source/Platforms/Android/GettingStarted/1/AndroidQS_1.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Android/GettingStarted/1/AndroidQS_1.JPN.udn @@ -1,9 +1,9 @@ -INTSourceChangelist:3298293 +INTSourceChangelist:3477690 Availability:Public -Title:1.必要な Android の設定 +Title:1.Android 開発に必要な設定 Crumbs:%ROOT%, Platforms, Platforms/Android, Platforms/Android/GettingStarted -Description:CodeWorks for Android 1R4 SDK をインストールします。 -Version:4.12 +Description:CodeWorks for Android 1R6 SDK をインストールします。 +Version:4.16 Skilllevel:Intermediate tags:Android type:multi-step @@ -15,9 +15,9 @@ Checkpoint:AndroidQS [nav] ## ステップ -Android 用の開発でまず最初にすることは、CodeWorks for Android 1R4 のインストールです。 +Android 用の開発でまず最初にすることは、CodeWorks for Android 1R6 のインストールです。 これは、Android デバイスにデプロイするために必要なプログラムとコードが確実にすべてそろいます。 -以下のセクションでは、開発用の PC に CodeWorks for Android 1R4 をインストールする方法を説明します。 +以下のセクションでは、開発用の PC に CodeWorks for Android 1R6 をインストールする方法を説明します。 %Globals:osselect_linux% @@ -70,17 +70,17 @@ Android 用の開発でまず最初にすることは、CodeWorks for Android 1R [EXCERPT:WindowsSetup] [REGION:note] -CodeWorks for Android 1R4 はインストールして、環境変数の設定がまだの場合は、以下の手順はすべて抜かして、エディタから **[Edit Menu (メニューの編集)]** -> **[Project Settings (プロジェクト設定)]** -> **[Android SDK]** プロパティを使って、エディタをインストール場所に指定してください。 +CodeWorks for Android 1R6 はインストール済みで環境変数の設定がまだの場合、以下の手順はすべて抜かして、エディタから **[Edit Menu (メニューの編集)]** -> **[Project Settings (プロジェクト設定)]** -> **[Android SDK]** プロパティを使って、エディタをインストール場所に指定してください。 [/REGION] [region:warning] -CodeWorks for Android 1R4 のインストール中は、インストールに問題が発生しないように、エディタとランチャーを閉じることをお勧めします。 +CodeWorks for Android 1R6 のインストール中は、インストールに問題が発生しないように、エディタとランチャーを閉じることをお勧めします。 [/region] -1. CodeWorks for Android 1R4 をインストールをするには、**[Engine]** > **[Extras]** > **[Android]** フォルダを開きます。 +1. CodeWorks for Android 1R6 をインストールをするには、**[Engine]** > **[Extras]** > **[Android]** フォルダを開きます。 [region:note] - CodeWorks for Android 1R4 インストーラーを正常に完了するためには、Visual Studio をインストールする必要があります。サポートしているバージョンは、2010、2012、2013 (2015 は対象外) です。 + CodeWorks for Android 1R6 インストーラを正常に完了するためには、Visual Studio をインストールする必要があります。サポートしているバージョンは、2010、2012、2013 (2015 は対象外) です。 [/region] | インストールの種類 | 保存場所 | @@ -89,17 +89,17 @@ CodeWorks for Android 1R4 のインストール中は、インストールに問 | GitHub | [EngineSyncLocation\UE4\Engine\Extras\Android | [region:note] - **Github** から UE4 をダウンロードする場合は、まず次のステップを完了しないと CodeWorks for Android 1R4 インストーラーを実行できません。 + **Github** から UE4 をダウンロードする場合は、まず次のステップを完了しないと CodeWorks for Android 1R6 インストーラを実行できません。 以下は、UE4 ソースコードを Github からダウンロードした Windows と Mac の入った PC 向けの手順になりますのでご注意ください。 - ランチャーからダウンロードしたバイナリ ビルドを使用する場合は、このステップを飛ばして CodeWorks for Android 1R4 をすぐにインストールできます。 + ランチャーからダウンロードしたバイナリ ビルドを使用する場合は、このステップを抜かして CodeWorks for Android 1R6 をすぐにインストールできます。 - 1. UE4 を Github からダウンロードして展開したら、**Setup.bat** ファイルを実行して、必要なファイルおよび **CodeWorks for Android 1R4** インストーラーをダウンロードします。 + 1. UE4 を Github からダウンロードして展開したら、**Setup.bat** ファイルを実行して、必要なファイルおよび **CodeWorks for Android 1R6** インストーラをダウンロードします。 - 1. **Setup.bat** の実行が完了したら、以下の手順で CodeWorks for Android 1R4 を実行します。 + 1. **Setup.bat** の実行が完了したら、以下の手順で CodeWorks for Android 1R6 を実行します。 [/region] -1. **AndroidWorks-1R1-windows.exe** ファイルをダブルクリックしてインストール処理を開始します。 +1. **CodeWorksforAndroid-1R6-windows.exe** ファイルをダブルクリックしてインストール処理を開始します。 ![](AndroidWorks_11.png) @@ -111,7 +111,7 @@ CodeWorks for Android 1R4 のインストール中は、インストールに問 ![](AndroidWorks_01.png) -1. CodeWorks for Android 1R4 のダウンロードおよびインストール先を設定したら、**[Next]** ボタンをクリックします。 +1. CodeWorks for Android 1R6 のダウンロードおよびインストール先を設定したら、**[Next]** ボタンをクリックします。 ![](AndroidWorks_02.png) @@ -119,7 +119,7 @@ CodeWorks for Android 1R4 のインストール中は、インストールに問 この設定のままデフォルト位置にしても全く問題ありません。 [/region] -1. **CodeWorks for Android 1R4u2** がインストールされていることを確認したら、**[Next]** ボタンをクリックします。 +1. **CodeWorks for Android 1R6** がインストールされていることを確認したら、**[Next]** ボタンをクリックします。 ![](AndroidWorks_03.png) @@ -127,18 +127,14 @@ CodeWorks for Android 1R4 のインストール中は、インストールに問 ![](AndroidWorks_04.png) -1. 新規ウィンドウが開いて、必要な CodeWorks for Android 1R4 ツールのダウンロードおよびインストールの進捗が表示されます。 +1. 新規ウィンドウが開いて、必要な CodeWorks for Android 1R6 ツールのダウンロードおよびインストールの進捗が表示されます。 [region:note] インターネットへ接続する必要があります。インターネットの接続速度によって数分、もしくは数時間かかる場合があります。 [/region] ![](AndroidWorks_06.png) -1. 必要なすべてのツールのダウンロードおよびインストールが完了すると、以下のウィンドウが表示されます。**[Next]** ボタンを押して、インストール処理を続けます。 - - ![](AndroidWorks_08.png) - -1. **[Next]** ボタンを押して CodeWorks for Android 1R4 のインストールを続行します。 +1. **[Next]** ボタンを押して CodeWorks for Android 1R6 のインストールを続行します。 ![](AndroidWorks_09.png) @@ -151,47 +147,46 @@ CodeWorks for Android 1R4 のインストール中は、インストールに問 ![](AndroidWorks_12.png) [region:note] - UE4 を Github からダウンロードした場合は、CodeWorks for Android 1R4 のインストールが終了した際に、PC あるいは Mac を再起動して環境変数が設定されてから **Setup.bat** ファイルをもう一度実行して、必要な Android 開発ファイルをダウンロードしてください。 + UE4 を Github からダウンロードした場合は、CodeWorks for Android 1R6 のインストールが終了した際に、PC あるいは Mac を再起動して環境変数が設定されてから **Setup.bat** ファイルをもう一度実行して、必要な Android 開発ファイルをダウンロードしてください。 [/region] [/EXCERPT:WindowsSetup] [EXCERPT:MacOSSetup] [REGION:note] -CodeWorks for Android 1R4 はインストール済みで環境変数の設定がまだの場合、以下の手順はすべて抜かして、エディタから **[Edit Menu (メニューの編集)]** -> **[Project Settings (プロジェクト設定)]** -> **[Android SDK]** プロパティを使って、エディタをインストール場所に指定してください。 +CodeWorks for Android 1R6 はインストール済みで環境変数の設定がまだの場合、以下の手順はすべて抜かして、エディタから **[Edit Menu (メニューの編集)]** -> **[Project Settings (プロジェクト設定)]** -> **[Android SDK]** プロパティを使って、エディタをインストール場所に指定してください。 [/REGION] [region:warning] -CodeWorks for Android 1R4 のインストール中は、インストールに問題が発生しないように、エディタとランチャーを閉じることをお勧めします。 +CodeWorks for Android 1R6 のインストール中は、インストールに問題が発生しないように、エディタとランチャーを閉じることをお勧めします。 [/region] -CodeWorks for Android 1R4 を Mac にインストールするには、Java 6 と Java 7 が両方インストールされている必要があります。ご確認ください。 -以下のリンクから、適切なバージョンの Java をダウンロードおよびインストールしてください。 +CodeWorks for Android 1R6 を Mac にインストールするには、Java 8 が両方インストールされている必要があります。ご確認ください。 +以下のリンクから、Java 8 をダウンロードおよびインストールしてください。 -* **Java 6** のダウンロードは [こちら](http://support.apple.com/kb/DL1572) から行えます。 -* **Java 7** のダウンロードは [こちら](http://www.oracle.com/technetwork/java/javase/downloads/jre7-downloads-1880261.html) から行えます。 +* **Java 8** のダウンロードは [こちら]( http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) から行えます。 -1. CodeWorks for Android 1R4 をインストールをするには、**[Engine]** > **[Extras]** > **[Android]** フォルダを開きます。 +1. CodeWorks for Android 1R6 をインストールをするには、**[Engine]** > **[Extras]** > **[Android]** フォルダを開きます。 | インストールの種類 | 保存場所 | | --- | --- | - | Binary | [EngineInstallLocation]\Unreal Engine[EngineVersion]\Engine\Extras\Android | - | GitHub | [EngineSyncLocation\UE4\Engine\Extras\Android | + | Binary | [EngineInstallLocation]\Unreal Engine[EngineVersion]\Engine\Extras\AndroidWorks\Mac | + | GitHub | [EngineSyncLocation\UE4\Engine\Extras\AndroidWorks\Mac | [region:note] - **Github** から UE4 をダウンロードする場合は、まず次のステップを完了しないと CodeWorks for Android 1R4 インストーラーを実行できません。 + **Github** から UE4 をダウンロードする場合は、まず次のステップを完了しないと CodeWorks for Android 1R6 インストーラを実行できません。 以下は、UE4 ソースコードを Githum からダウンロードした Windows と Mac の入った PC 向けの手順になりますのでご注意ください。 - ランチャーからダウンロードしたバイナリ ビルドを使用する場合は、このステップを抜かして CodeWorks for Android 1R4 をすぐにインストールできます。 + ランチャーからダウンロードしたバイナリ ビルドを使用する場合は、このステップを抜かして CodeWorks for Android 1R6 をすぐにインストールできます。 - 1. UE4 を Github からダウンロードして展開したら、**Setup.command** ファイルを実行して、必要なファイルおよび CodeWorks for Android 1R4 インストーラーをダウンロードします。 + 1. UE4 を Github からダウンロードして展開したら、**Setup.command** ファイルを実行して、必要なファイルおよび CodeWorks for Android 1R6 インストーラをダウンロードします。 - 1. **Setup.command** の実行が完了したら、以下の手順で CodeWorks for Android 1R4 を実行します。 + 1. **Setup.command** の実行が完了したら、以下の手順で CodeWorks for Android 1R6 を実行します。 [/region] -1. ** CodeWorks for Android 1R4-osx.dmg** をダブルクリックして、CodeWorks for Android 1R4 インストーラーをロードします。 +1. ** CodeWorks for Android 1R6-osx.dmg** をダブルクリックして、CodeWorks for Android 1R6 インストーラをロードします。 ![](AndroidWorks_Mac_00.png) -1. CodeWorks for Android 1R4 インストーラ アイコンをダブルクリックしてインストール処理を開始します。 +1. CodeWorks for Android 1R6 インストーラ アイコンをダブルクリックしてインストール処理を開始します。 ![](AndroidWorks_Mac_01.png) @@ -203,7 +198,7 @@ CodeWorks for Android 1R4 を Mac にインストールするには、Java 6 と ![](AndroidWorks_Mac_03.png) -1. CodeWorks for Android 1R4 のインストール先を指定して **[Next]** ボタンを押します。 +1. CodeWorks for Android 1R6 のインストール先を指定して **[Next]** ボタンを押します。 [region:note] この設定のままデフォルト位置にしても全く問題ありません。 @@ -211,7 +206,7 @@ CodeWorks for Android 1R4 を Mac にインストールするには、Java 6 と ![](AndroidWorks_Mac_04.png) -1. Android 1R4 Component Manager が表示されたら、**[Next]** ボタンを押してダウンロードとインストール処理を開始します。 +1. Android 1R6 Component Manager が表示されたら、**[Next]** ボタンを押してダウンロードとインストール処理を開始します。 ![](AndroidWorks_Mac_05.png) @@ -219,30 +214,51 @@ CodeWorks for Android 1R4 を Mac にインストールするには、Java 6 と ![](AndroidWorks_Mac_06.png) -1. Android 1R4 Component Manager が必要なツールのダウンロードとインストールを開始します。 +1. Android 1R6 Component Manager が必要なツールのダウンロードとインストールを開始します。 [region:note] インターネットへ接続する必要があります。インターネットの接続速度によって数分、もしくは数時間かかる場合があります。 [/region] - ![](AndroidWorks_Mac_07.png) 1. 必要なすべてのツールのダウンロードおよびインストールが完了すると、以下のウィンドウが表示されます。**[Next]** ボタンを押して続けます。 ![](AndroidWorks_Mac_08.png) -1. **[Finish (終了)]** ボタンを押して、CodeWorks for Android 1R4 のインストールを完了します。 +1. **[Finish (終了)]** ボタンを押して、CodeWorks for Android 1R6 のインストールを完了します。 ![](AndroidWorks_Mac_09.png) [region:note] - UE4 を Github からダウンロードした場合は、CodeWorks for Android 1R4 のインストールが終了した際に、Mac を再起動して環境変数が設定されてから **Setup.command** ファイルをもう一度実行して、必要な Android 開発ファイルをダウンロードしてください。 + UE4 を Github からダウンロードした場合は、CodeWorks for Android 1R6 のインストールが終了した際に、Mac を再起動して環境変数が設定されてから **Setup.command** ファイルをもう一度実行して、必要な Android 開発ファイルをダウンロードしてください。 [/region] +Once CodeWorks for Android 1R6 のインストールが完了したら、以下の操作をして Bash ファイルを編集する必要があります。 + +1. Mac Terminal を開きます。 + + ![](JH_01.png) + +1. Terminal に **「nano ~/.bash_profile」** とタイプします。 + + ![](JH_02.png) + +1. ファイルの最下部までスクロールし、**export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home** を追加します。 + + ![](JH_03.png) + + [region:note] + 上記はデフォルト パスです。別の場所へインストールした場合は、パスが **jdk1.8.0_121.jdk/Contents/Home** に指定されていることを確認してください。 + [/region] + +1. **CTRL + X** を押して Bash ファイルを閉じ、**Y** キーを押して変更を保存してから **Enter** で変更を確定し、最後に Mac を再起動します。 + +1. Mac を再起動したら、Terminal を開いて **「Monitor」** と入力して Enter キーを押します。設定がすべて正常に行われると、Android Device Monitor スプラッシュスクリーンは以下のようになります。 + + ![](JH_04.png) + [/EXCERPT:MacOSSetup] [EXCERPT:LinuxSetup] -本文書は現在作成中です。現在公開されている文書については、 -[新規および更新リソース](https://docs.unrealengine.com/latest/INT/Updates/index.html) を参照してください。 - +[INCLUDE:Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/1#AndroidLinux_1] [/EXCERPT:LinuxSetup] --> diff --git a/Engine/Documentation/Source/Platforms/Android/GettingStarted/1/AndroidQS_1.KOR.udn b/Engine/Documentation/Source/Platforms/Android/GettingStarted/1/AndroidQS_1.KOR.udn index 2852fc95ce2d..35ac6dfa48ea 100644 --- a/Engine/Documentation/Source/Platforms/Android/GettingStarted/1/AndroidQS_1.KOR.udn +++ b/Engine/Documentation/Source/Platforms/Android/GettingStarted/1/AndroidQS_1.KOR.udn @@ -1,9 +1,9 @@ -INTSourceChangelist:3298293 +INTSourceChangelist:3477690 Availability:Public Title:1. 필수 안드로이드 셋업 Crumbs:%ROOT%, Platforms, Platforms/Android, Platforms/Android/GettingStarted -Description: CodeWorks for Android 1R4 SDK 설치 방법 안내입니다. -Version:4.12 +Description: CodeWorks for Android 1R6 SDK 설치 방법 안내입니다. +Version:4.16 Skilllevel:Intermediate Tags:Android type:multi-step @@ -15,9 +15,9 @@ Checkpoint:AndroidQS [nav] ## 단계 -안드로이드 개발을 시작하기에 앞서 먼저 CodeWorks for Android 1R4 를 설치해야 합니다. -CodeWorks for Android 1R4 는 안드로이드 디바이스에 디플로이하기 위해 필요한 프로그램과 코드가 전부 설치되도록 도와줄 것입니다. -여기서는 개발 PC 에 CodeWorks for Android 1R4 를 설치하는 법에 대해 다루겠습니다. +안드로이드 개발을 시작하기에 앞서 먼저 CodeWorks for Android 1R6 를 설치해야 합니다. +CodeWorks for Android 1R6 는 안드로이드 디바이스에 디플로이하기 위해 필요한 프로그램과 코드가 전부 설치되도록 도와줄 것입니다. +여기서는 개발 PC 에 CodeWorks for Android 1R6 를 설치하는 법에 대해 다루겠습니다. %Globals:osselect_linux% @@ -70,17 +70,17 @@ CodeWorks for Android 1R4 는 안드로이드 디바이스에 디플로이하기 [EXCERPT:WindowsSetup] [REGION:note] -이미 CodeWorks for Android 1R4 가 설치되어 있는데 환경 변수는 없어진 경우, 이 단계는 전부 건너뛰고 에디터의 **편집 메뉴** -> **프로젝트 세팅** -> **Android SDK** 프로퍼티에서 설치 위치를 지정해 주기만 해도 됩니다. +이미 CodeWorks for Android 1R6 가 설치되어 있는데 환경 변수는 없어진 경우, 이 단계는 전부 건너뛰고 에디터의 **편집 메뉴** -> **프로젝트 세팅** -> **Android SDK** 프로퍼티에서 설치 위치를 지정해 주기만 해도 됩니다. [/REGION] [region:warning] -CodeWorks for Android 1R4 는 에디터와 런처 둘 다 닫힌 상태로 설치할 것을 강력 추천합니다. 그래야 설치에 문제가 없습니다. +CodeWorks for Android 1R6 는 에디터와 런처 둘 다 닫힌 상태로 설치할 것을 강력 추천합니다. 그래야 설치에 문제가 없습니다. [/region] -1. CodeWorks for Android 1R4 를 설치하려면 **Engine** > **Extras** > **Android** 폴더로 이동합니다. +1. CodeWorks for Android 1R6 를 설치하려면 **Engine** > **Extras** > **Android** 폴더로 이동합니다. [region:note] - CodeWorks for Android 1R4 인스톨러의 정상 완료를 위해서는 Visual Studio 가 설치되어 있어야 합니다. 지원되는 버전은 2010, 2012, 2013 (2015 제외)입니다 . + CodeWorks for Android 1R6 인스톨러의 정상 완료를 위해서는 Visual Studio 가 설치되어 있어야 합니다. 지원되는 버전은 2010, 2012, 2013 (2015 제외)입니다 . [/region] | 설치 유형 | 위치 | @@ -89,17 +89,17 @@ CodeWorks for Android 1R4 는 에디터와 런처 둘 다 닫힌 상태로 설 | GitHub | [EngineSyncLocation\UE4\Engine\Extras\Android | [region:note] - UE4 를 **Github** 에서 다운로드한 경우, CodeWorks for Android 1R4 인스톨러 실행 전 다음과 같은 작업을 해 줘야 합니다. + UE4 를 **Github** 에서 다운로드한 경우, CodeWorks for Android 1R6 인스톨러 실행 전 다음과 같은 작업을 해 줘야 합니다. GitHub 에서 UE4 소스 코드를 다운로드했으면 윈도우 기반 PC 든 맥이든 양쪽에 적용된다는 점 참고 바랍니다. - 런처에서 다운로드한 바이너리 빌드를 사용중이라면 이 부분은 건너뛰고 바로 CodeWorks for Android 1R4 설치로 들어가시면 됩니다. + 런처에서 다운로드한 바이너리 빌드를 사용중이라면 이 부분은 건너뛰고 바로 CodeWorks for Android 1R6 설치로 들어가시면 됩니다. - 1. GitHub 에서 UE4 다운로드를 마치고 압축을 풀었으면, **Setup.bat** 파일을 실행하여 필수 파일과 **CodeWorks for Android 1R4** 인스톨러를 다운로드합니다. + 1. GitHub 에서 UE4 다운로드를 마치고 압축을 풀었으면, **Setup.bat** 파일을 실행하여 필수 파일과 **CodeWorks for Android 1R6** 인스톨러를 다운로드합니다. - 1. **Setup.bat** 실행이 완료되면 CodeWorks for Android 1R4 인스톨러를 실행하고 아래 안내를 따릅니다. + 1. **Setup.bat** 실행이 완료되면 CodeWorks for Android 1R6 인스톨러를 실행하고 아래 안내를 따릅니다. [/region] -1. **CodeWorksforAndroid-1R4-windows.exe** 파일을 더블클릭하여 설치 프로세스를 시작합니다. +1. **CodeWorksforAndroid-1R6-windows.exe** 파일을 더블클릭하여 설치 프로세스를 시작합니다. ![](AndroidWorks_11.png) @@ -111,7 +111,7 @@ CodeWorks for Android 1R4 는 에디터와 런처 둘 다 닫힌 상태로 설 ![](AndroidWorks_01.png) -1. CodeWorks for Android 1R4 를 다운로드하고 설치할 위치를 설정한 뒤 **다음** 버튼을 누릅니다. +1. CodeWorks for Android 1R6 를 다운로드하고 설치할 위치를 설정한 뒤 **다음** 버튼을 누릅니다. ![](AndroidWorks_02.png) @@ -119,7 +119,7 @@ CodeWorks for Android 1R4 는 에디터와 런처 둘 다 닫힌 상태로 설 이 위치는 기본 위치로 놔둬도 전혀 상관 없습니다. [/region] -1. **CodeWorks for Android 1R4u2** 설치중인지 확인한 뒤 **다음** 버튼을 누릅니다. +1. **CodeWorks for Android 1R6** 설치중인지 확인한 뒤 **다음** 버튼을 누릅니다. ![](AndroidWorks_03.png) @@ -127,18 +127,14 @@ CodeWorks for Android 1R4 는 에디터와 런처 둘 다 닫힌 상태로 설 ![](AndroidWorks_04.png) -1. 필수 CodeWorks for Android 1R4 툴의 다운로드 및 설치 진행상황이 표시되는 창이 새로 뜹니다. +1. 필수 CodeWorks for Android 1R6 툴의 다운로드 및 설치 진행상황이 표시되는 창이 새로 뜹니다. [region:note] 이 부분의 완료를 위해서는 인터넷 연결이 필요합니다. 그 인터넷 연결 속도에 따라 몇 분에서 몇 시간까지 걸릴 수 있습니다. [/region] ![](AndroidWorks_06.png) -1. 필수 툴의 다운로드 및 설치가 전부 끝나면 다음 창이 표시됩니다. **다음** 버튼을 눌러 설치 프로세스를 계속합니다. - - ![](AndroidWorks_08.png) - -1. 이제 **다음** 버튼을 눌러 CodeWorks for Android 1R4 설치를 완료합니다. +1. 이제 **다음** 버튼을 눌러 CodeWorks for Android 1R6 설치를 완료합니다. ![](AndroidWorks_09.png) @@ -151,47 +147,46 @@ CodeWorks for Android 1R4 는 에디터와 런처 둘 다 닫힌 상태로 설 ![](AndroidWorks_12.png) [region:note] - GitHub 에서 UE4 를 다운로드한 경우, CodeWorks for Android 1R4 가 설치를 완료하면 환경 변수 설정을 위해 PC 또는 맥을 재시작하고 **Setup.bat** 파일을 한 번 더 실행하여 필수 안드로이드 파일을 다운로드합니다. + GitHub 에서 UE4 를 다운로드한 경우, CodeWorks for Android 1R6 가 설치를 완료하면 환경 변수 설정을 위해 PC 또는 맥을 재시작하고 **Setup.bat** 파일을 한 번 더 실행하여 필수 안드로이드 파일을 다운로드합니다. [/region] [/EXCERPT:WindowsSetup] [EXCERPT:MacOSSetup] [REGION:note] -이미 CodeWorks for Android 1R4 가 설치되어 있는데 환경 변수는 없어진 경우, 이 단계는 전부 건너뛰고 에디터의 **편집 메뉴** -> **프로젝트 세팅** -> **Android SDK** 프로퍼티에서 설치 위치를 지정해 주기만 해도 됩니다. +이미 CodeWorks for Android 1R6 가 설치되어 있는데 환경 변수는 없어진 경우, 이 단계는 전부 건너뛰고 에디터의 **편집 메뉴** -> **프로젝트 세팅** -> **Android SDK** 프로퍼티에서 설치 위치를 지정해 주기만 해도 됩니다. [/REGION] [region:warning] -CodeWorks for Android 1R4 는 에디터와 런처 둘 다 닫힌 상태로 설치할 것을 강력 추천합니다. 그래야 설치에 문제가 없습니다. +CodeWorks for Android 1R6 는 에디터와 런처 둘 다 닫힌 상태로 설치할 것을 강력 추천합니다. 그래야 설치에 문제가 없습니다. [/region] -맥에 CodeWorks for Android 1R4 설치 전 Java 6 와 Java 7 둘 다 설치되어 있는지 확인해야 합니다. -아래 링크를 사용해서 올바른 Java 버전을 다운로드 및 설치하도록 하세요. +맥에 CodeWorks for Android 1R6 설치 전 Java 8 이 설치되어 있는지 확인해야 합니다. +아래 링크를 사용해서 Java 8 을 다운로드 및 설치하도록 하세요. -* **Java 6** 다운로드는 [여기서](http://support.apple.com/kb/DL1572) 가능합니다. -* **Java 7** 다운로드는 [여기서](http://www.oracle.com/technetwork/java/javase/downloads/jre7-downloads-1880261.html) 가능합니다. +* **Java 8** 은 [여기서]( http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) 다운로드할 수 있습니다. -1. CodeWorks for Android 1R4 를 설치하려면 **Engine** > **Extras** > **Android** 폴더로 이동합니다. +1. CodeWorks for Android 1R6 를 설치하려면 **Engine** > **Extras** > **Android** 폴더로 이동합니다. | 설치 유형 | 위치 | | ------------ | ---------| - | 바이너리 | [EngineInstallLocation]\Unreal Engine[EngineVersion]\Engine\Extras\Android | - | GitHub | [EngineSyncLocation\UE4\Engine\Extras\Android | + | Binary | [EngineInstallLocation]\Unreal Engine[EngineVersion]\Engine\Extras\AndroidWorks\Mac | + | GitHub | [EngineSyncLocation\UE4\Engine\Extras\AndroidWorks\Mac | [region:note] - UE4 를 **Github** 에서 다운로드한 경우, CodeWorks for Android 1R4 인스톨러 실행 전 다음과 같은 작업을 해 줘야 합니다. + UE4 를 **Github** 에서 다운로드한 경우, CodeWorks for Android 1R6 인스톨러 실행 전 다음과 같은 작업을 해 줘야 합니다. GitHub 에서 UE4 소스 코드를 다운로드했으면 윈도우 기반 PC 든 맥이든 양쪽에 적용된다는 점 참고 바랍니다. - 런처에서 다운로드한 바이너리 빌드를 사용중이라면 이 부분은 건너뛰고 바로 CodeWorks for Android 1R4 설치로 들어가시면 됩니다. + 런처에서 다운로드한 바이너리 빌드를 사용중이라면 이 부분은 건너뛰고 바로 CodeWorks for Android 1R6 설치로 들어가시면 됩니다. - 1. GitHub 에서 UE4 다운로드를 마치고 압축을 풀었으면, **Setup.command** 파일을 실행하여 필수 파일과 **CodeWorks for Android 1R4** 인스톨러를 다운로드합니다. + 1. GitHub 에서 UE4 다운로드를 마치고 압축을 풀었으면, **Setup.command** 파일을 실행하여 필수 파일과 **CodeWorks for Android 1R6** 인스톨러를 다운로드합니다. - 1. **Setup.command** 실행이 완료되면 CodeWorks for Android 1R4 인스톨러를 실행하고 아래 안내를 따릅니다. + 1. **Setup.command** 실행이 완료되면 CodeWorks for Android 1R6 인스톨러를 실행하고 아래 안내를 따릅니다. [/region] -1. **CodeWorks for Android 1R4-osx.dmg.dmg** 파일을 더블클릭하여 설치 프로세스를 시작합니다. +1. **CodeWorks for Android 1R6-osx.dmg.dmg** 파일을 더블클릭하여 설치 프로세스를 시작합니다. ![](AndroidWorks_Mac_00.png) -1. CodeWorks for Android 1R4 인스톨러 아이콘을 더블클릭하여 설치 프로세스를 시작합니다. +1. CodeWorks for Android 1R6 인스톨러 아이콘을 더블클릭하여 설치 프로세스를 시작합니다. ![](AndroidWorks_Mac_01.png) @@ -203,7 +198,7 @@ CodeWorks for Android 1R4 는 에디터와 런처 둘 다 닫힌 상태로 설 ![](AndroidWorks_Mac_03.png) -1. CodeWorks for Android 1R4 를 다운로드하고 설치할 위치를 설정한 뒤 **다음** 버튼을 누릅니다. +1. CodeWorks for Android 1R6 를 다운로드하고 설치할 위치를 설정한 뒤 **다음** 버튼을 누릅니다. [region:note] 이 위치는 기본 위치로 놔둬도 전혀 상관 없습니다. @@ -211,7 +206,7 @@ CodeWorks for Android 1R4 는 에디터와 런처 둘 다 닫힌 상태로 설 ![](AndroidWorks_Mac_04.png) -1. CodeWorks for Android 1R4 Component Manager 가 표시되면 **다음** 버튼을 눌러 다운로드 및 설치 프로세스를 시작합니다. +1. CodeWorks for Android 1R6 Component Manager 가 표시되면 **다음** 버튼을 눌러 다운로드 및 설치 프로세스를 시작합니다. ![](AndroidWorks_Mac_05.png) @@ -219,30 +214,51 @@ CodeWorks for Android 1R4 는 에디터와 런처 둘 다 닫힌 상태로 설 ![](AndroidWorks_Mac_06.png) -1. CodeWorks for Android 1R4 Component Manager 가 필수 툴 다운로드 및 설치를 시작합니다. +1. CodeWorks for Android 1R6 Component Manager 가 필수 툴 다운로드 및 설치를 시작합니다. [region:note] 이 부분의 완료를 위해서는 인터넷 연결이 필요합니다. 그 인터넷 연결 속도에 따라 몇 분에서 몇 시간까지 걸릴 수 있습니다. [/region] - ![](AndroidWorks_Mac_07.png) 1. 필수 툴의 다운로드 및 설치가 전부 끝나면 다음 창이 표시됩니다. **다음** 버튼을 눌러 설치 프로세스를 계속합니다. ![](AndroidWorks_Mac_08.png) -1. 이제 **완료** 버튼을 눌러 CodeWorks for Android 1R4 설치를 완료합니다. +1. 이제 **완료** 버튼을 눌러 CodeWorks for Android 1R6 설치를 완료합니다. ![](AndroidWorks_Mac_09.png) [region:note] - GitHub 에서 UE4 를 다운로드한 경우, CodeWorks for Android 1R4 가 설치를 완료하면 환경 변수 설정을 위해 PC 또는 맥을 재시작하고 **Setup.command** 파일을 한 번 더 실행하여 필수 안드로이드 파일을 다운로드합니다. + GitHub 에서 UE4 를 다운로드한 경우, CodeWorks for Android 1R6 가 설치를 완료하면 환경 변수 설정을 위해 PC 또는 맥을 재시작하고 **Setup.command** 파일을 한 번 더 실행하여 필수 안드로이드 파일을 다운로드합니다. [/region] +CodeWorks for Android 1R6 설치가 완료되면, 다음과 같이 Bash 파일을 편집해 줘야 합니다: + +1. Mac Terminal 을 엽니다. + + ![](JH_01.png) + +1. Terminal 에 다음과 같이 입력합니다: **nano ~/.bash_profile**. + + ![](JH_02.png) + +1. 파일 끝으로 내려가 **export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home** 를 추가합니다. + + ![](JH_03.png) + + [region:note] + 위 경로는 기본 경로이며, 다른 곳에 설치한 경우 경로가 **jdk1.8.0_121.jdk/Contents/Home** 를 가르키도록 해줘야 합니다. + [/region] + +1. **CTRL + X** 를 눌러 bash 를 빠져나간 뒤 **Y** 를 눌러 변경사항을 저장하고 **Enter** 키를 쳐 변경사항을 확인, 마지막으로 Mac 을 재시작합니다. + +1. Mac 이 재시작되면 Terminal 을 연 뒤 **Monitor** 라 입력하고 엔터를 칩니다. 모두 제대로 구성되었으면 Android Device Monitor 스플래시 화면이 보일 것입니다. + + ![](JH_04.png) + [/EXCERPT:MacOSSetup] [EXCERPT:LinuxSetup] -이 문서는 현재 작업중입니다. 현재 공개된 문서를 확인하려면 [New and Updated Resources](https://docs.unrealengine.com/latest/INT/Updates/index.html) -페이지를 참고하세요. - +[INCLUDE:Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/1#AndroidLinux_1] [/EXCERPT:LinuxSetup] --> diff --git a/Engine/Documentation/Source/Platforms/Android/GettingStarted/2/AndroidQS_2.INT.udn b/Engine/Documentation/Source/Platforms/Android/GettingStarted/2/AndroidQS_2.INT.udn index 373c03ca7b8f..6ad2c930ffdd 100644 --- a/Engine/Documentation/Source/Platforms/Android/GettingStarted/2/AndroidQS_2.INT.udn +++ b/Engine/Documentation/Source/Platforms/Android/GettingStarted/2/AndroidQS_2.INT.udn @@ -2,7 +2,7 @@ Availability:Public Title:2. Set Up Your Android Device Crumbs:%ROOT%, Platforms, Platforms/Android, Platforms/Android/GettingStarted Description:Set up your Android device for development. -Version:4.12 +Version:4.16 Skilllevel:Intermediate tags:Android tags:Mobile @@ -85,7 +85,7 @@ Now that Android Works has been installed it is now time to set up your Android 1. Tap the **Build Number** **7** times to activate developer mode. - ![](Enable_Dev_Mode.png) + ![](Enable_Dev_Mode.png)(w:350) 1. After the first few presses, you will see a message stating You are now **# steps** away from becoming a developer. @@ -95,26 +95,26 @@ Now that Android Works has been installed it is now time to set up your Android 1. Navigate back to the **Settings** menu and select **Developer Options** which should now available. - ![](Dev_Options_Enabled.png) + ![](Dev_Options_Enabled.png)(w:350) 1. In the **Developer Options** menu, enable **USB debugging** by tapping on it with your finger. - ![](Enable_USB_Debugging.png) + ![](Enable_USB_Debugging.png)(w:350) 1. When prompted press the **OK** button to enable USB debugging. - ![](Enable_USB_Debugging_Warning.png) + ![](Enable_USB_Debugging_Warning.png)(w:350) 1. You can tell USB Debugging has been enabled as there will be a green checkmark in the checkmark box next to USB debugging. - ![](USB_Debugging_Enabled.png) + ![](USB_Debugging_Enabled.png)(w:350) -1. Disconnect your Android device from USB and then immediately plug it back in. - After the device is recognized by the PC the following message will appear on your Android device asking you if you want to allow this PC to talk to your device. - Press the checkmark box that says **Always allow this computer** and the press the **OK** button. +1. Disconnect your Android device from USB and then immediately plug it back in. After the device is recognized by the PC the following message will appear on your Android device +asking you if you want to allow this PC to talk to your device. A message box will ask what you'd like to use the USB connection to do. Press the checkmark box that says **Always +allow this computer** and the press the **OK** button. + + ![](PC_RSA_Fingerprint.png)(w:350) - ![](PC_RSA_Fingerprint.png) - 1. To verify that your device is set up properly, open a command prompt by pressing the **Windows + R** keys and typing **cmd** in the **Run** window. ![](Windows_Run_Command.png) @@ -157,37 +157,36 @@ Now that Android Works has been installed it is now time to set up your Android 1. Tap the **Build Number** **7** times to activate developer mode. - ![](Enable_Dev_Mode.png) + ![](Enable_Dev_Mode.png)(w:350) 1. After the first few presses, you will see a message that says, **You are now # steps away from becoming a developer**. 1. Once developer mode has been activated you will get a success message displayed on the screen similar to the one below. - ![](Dev_Mode_Active.png) + ![](Dev_Mode_Active.png)(w:350) 1. Navigate back to the **Settings menu** and select **Developer Options** which is now available. - ![](Dev_Options_Enabled.png) + ![](Dev_Options_Enabled.png)(w:350) 1. In the **Developer Options** menu, enable **USB debugging**. - ![](Enable_USB_Debugging.png) + ![](Enable_USB_Debugging.png)(w:350) 1. When prompted press the **OK** button to enable USB debugging. - ![](Enable_USB_Debugging_Warning.png) + ![](Enable_USB_Debugging_Warning.png)(w:350) 1. You can tell USB Debugging has been enabled as there will be a green checkmark in the checkmark box next to USB debugging. - ![](USB_Debugging_Enabled.png) + ![](USB_Debugging_Enabled.png)(w:350) -1. Disconnect your Android device from USB and then immediately plug it back in. - After the device is recognized by the PC the following message will appear on your Android device asking you if you want to allow this Mac to talk to your device. - Press the checkmark box that says **Always allow this computer** and the press the **OK** button. +1. Disconnect your Android device from USB and then immediately plug it back in. After the device is recognized by the PC the following message will appear on your Android device +asking you if you want to allow this PC to talk to your device. A message box will ask what you'd like to use the USB connection to do. Press the checkmark box that says **Always +allow this computer** and the press the **OK** button. - ![](PC_RSA_Fingerprint.png) - -1. To verify that your device is set up properly, open the **Terminal app** from /Applications/Utilties. + ![](PC_RSA_Fingerprint.png)(w:350) +1. To verify that your device is setup properly, open the **Terminal app** from /Applications/Utilties. ![](MAC_Terminal_Activate.png) @@ -208,14 +207,12 @@ If you do not see your device after you input the adb devices command, here are [/EXCERPT:MacOSSetup] [EXCERPT:LinuxSetup] -We're currently in the process of writing this documentation. Please refer to our [New and Updated Resources](https://docs.unrealengine.com/latest/INT/Updates/index.html) page to see -which documentation is being published at this time. - +[INCLUDE:Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/2#AndroidLinux_2] [/EXCERPT:LinuxSetup] --> ## End Result -When completed you will now have an Android based smartphone that is ready for your UE4 project to be deployed to and run on. +When completed you will now have an Android-based smartphone that is ready for your UE4 project to be deployed to and run on. [nav] diff --git a/Engine/Documentation/Source/Platforms/Android/GettingStarted/2/AndroidQS_2.JPN.udn b/Engine/Documentation/Source/Platforms/Android/GettingStarted/2/AndroidQS_2.JPN.udn index 4591c39c684f..a210533de3df 100644 --- a/Engine/Documentation/Source/Platforms/Android/GettingStarted/2/AndroidQS_2.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Android/GettingStarted/2/AndroidQS_2.JPN.udn @@ -1,9 +1,9 @@ -INTSourceChangelist:3298293 +INTSourceChangelist:3477690 Availability:Public -Title:2.Android デバイスを設定する +Title:2.Android デバイスの設定 Crumbs:%ROOT%, Platforms, Platforms/Android, Platforms/Android/GettingStarted Description:Android デバイスを開発用に設定する -Version:4.12 +Version:4.16 Skilllevel:Intermediate tags:Android tags:Mobile @@ -12,7 +12,7 @@ parent:Platforms/Android/GettingStarted order:2 Checkpoint:AndroidQS -Android Works をインストールしたら、Android デバイスを開発で使用できるように設定します。次のセクションでは、Android デバイスを UE4 プロジェクトで使用するための設定方法を説明します。 +Android Works をインストールしたら、Android デバイスを開発用に設定します。次のセクションでは、Android デバイスを UE4 プロジェクトで使用するための設定方法を説明します。 [nav] @@ -68,7 +68,7 @@ Android Works をインストールしたら、Android デバイスを開発で 1. Android デバイスを USB で開発用 PC に接続します。 -1. デバイス ドライバ ソフトウェアは自動的にインストールされますが、そうでない場合は、[Android の OEM USB ドライバ](http://developer.android.com/tools/extras/oem-usb.html) ページでドライバ インストール リンクと追加情報を確認してください。 +1. デバイス ドライバ ソフトウェアは自動的にインストールされます。インストールされない場合は、[Android の OEM USB ドライバ](http://developer.android.com/tools/extras/oem-usb.html) ページでドライバ インストール リンクと追加情報を確認してください。 1. Android デバイスの **[Settings]** アプリケーションを開きます。 @@ -86,9 +86,9 @@ Android Works をインストールしたら、Android デバイスを開発で 1. **[Build Number]** を **7** 回たたきます。 - ![](Enable_Dev_Mode.png) + ![](Enable_Dev_Mode.png)(w:350) -1. 数回たたいた段階で、「You are now **# steps **away from becoming a developer (デベロッパーになるまであと**# ステップ **)」 というメッセージが表示されます。 +1. 数回たたくと、「You are now **# steps **away from becoming a developer (デベロッパーになるまであと **# ステップ**)」 というメッセージが表示されます。 1. Developer Mode が起動すると、正常な処理を示す以下のメッセージが表示されます。 @@ -96,27 +96,27 @@ Android Works をインストールしたら、Android デバイスを開発で 1. 再度 **[Settings]** メニューへ戻ると **[Developer Options]** が利用可能になっているので、選択します。 - ![](Dev_Options_Enabled.png) + ![](Dev_Options_Enabled.png)(w:350) -1. **[Developer Options]** メニューの **USB デバッグ** を指で 2 回叩いて有効にします。 +1. **[Developer Options]** メニューの **USB デバッグ** を指で 2 回たたいて有効にします。 - ![](Enable_USB_Debugging.png) + ![](Enable_USB_Debugging.png)(w:350) 1. 求められたら **[Ok]** ボタンをクリックして USB デバッグを有効にしてください。 - ![](Enable_USB_Debugging_Warning.png) + ![](Enable_USB_Debugging_Warning.png)(w:350) 1. USB デバッグの横のチェックボックスの緑が有効になっている印です。 - ![](USB_Debugging_Enabled.png) + ![](USB_Debugging_Enabled.png)(w:350) -1. Android デバイスを USB から一旦取り外して、すぐに再度接続してください。 - PC がデバイスを認識したら、この PC にデバイスと通信を許可するかどうかのメッセージが Android デバイス上に表示されます。 - **[Always allow this computer (常に許可)]** を押して、**[OK]** ボタンをクリックします。 +1. Android デバイスを USB から一旦取り外して、すぐに再度接続してください。PC がデバイスを認識したら、 +この Mac にデバイスとの通信許可に関する次のメッセージが Android デバイス上に表示されます。 メッセージ ボックスは USB 接続をどのようにするか尋ねるので、**[Always allow this computer (常に許可)]** を押して、 +**[OK]** ボタンをクリックします。 - ![](PC_RSA_Fingerprint.png) + ![](PC_RSA_Fingerprint.png)(w:350) -1. デバイスの設定が適切か確認するために **Windows + R** キーでコマンド プロンプトを開き、**[Run (実行)]** ウィンドウに **「cmd」** とタイプします。 + 1. デバイスの設定が適切か確認するために **Windows + R** キーでコマンド プロンプトを開き、**[Run (実行)]** ウィンドウに **「cmd」** とタイプします。 ![](Windows_Run_Command.png) @@ -126,7 +126,7 @@ Android Works をインストールしたら、Android デバイスを開発で [region:note] - adb devices と打ち込んでも自分のデバイスが確認できない場合は、次の方法で PC が Android デバイスを認識できるか試してみてください。 + 「adb devices」と打ち込んでも自分のデバイスが確認できない場合は、次の方法で PC が Android デバイスを認識できるか試してみてください。 * デバイスが表示されているのに権限がないと表示される場合は、デバイスに PC に認証させるかどうかを尋ねさせる必要があります。 * デバイスを表示させるためには、デバイスを一旦取り外して再接続しなければならない場合があります。 * [Always allow (常に許可)] チェックボックスにチェックを入れておくことを推奨します。 @@ -144,62 +144,61 @@ Android Works をインストールしたら、Android デバイスを開発で 1. Android デバイスの **[Settings (セッティング)]** アプリケーションを開きます。 1. **[Developer Options (デベロッパー オプション)]** をタップして [Developer Options] メニューを開きます。 - [REGION:note] + [REGION:note] このメニューが表示されない場合は、デバイスの [Developer Options] を有効にしてください。 デベロッパー オプションの詳細は、[Android で使用しているハードウェア](http://developer.android.com/tools/device.html) ページをご覧ください。 [/REGION] -1. 下へスクロールして **[About Phone]** を選びます。Android デバイスによっては、このオプションは **[About Device]**、**[About Tablet]**、または **[About Shield]** となる場合もあります。 +1. 下へスクロールして **[About Phone]** を選びます。Android デバイスによっては、このオプションは **[About Device]**、**[About Tablet]**、または **[About Shield]** となっている場合もあります。 [REGION: note] - 注記:** 新しい Andorid のバージョンでは **[More]** セクションにある場合があります。 + 注記:新しい Andorid のバージョンでは **[More]** セクションにある場合があります。 [/REGION] 1. **[Build Number]** を **7** 回たたきます。 - ![](Enable_Dev_Mode.png) + ![](Enable_Dev_Mode.png)(w:350) -1. 数回たたいた段階で、「**You are now # steps away from becoming a developer (デベロッパーになるまであと # ステップ )**」 というメッセージが表示さrます。 +1. 数回たたいた段階で、「**You are now # steps away from becoming a developer (デベロッパーになるまであと # ステップ)**」というメッセージが表示さrます。 1. Developer Mode が起動すると、以下のようなメッセージが表示されて、通常に処理されたことが分かります。 - ![](Dev_Mode_Active.png) + ![](Dev_Mode_Active.png)(w:350) 1. 再度 **[Settings]** メニューへ戻ると **[Developer Options]** が利用可能な状態になっているので選択します。 - ![](Dev_Options_Enabled.png) + ![](Dev_Options_Enabled.png)(w:350) 1. **[Developer Options]** メニューの **[USB debugging]** を有効にします。 - ![](Enable_USB_Debugging.png) + ![](Enable_USB_Debugging.png)(w:350) -1. 求められたら **[Ok]** ボタンをクリックして USB デバッグを有効にしてください。 +1. 求められたら **[OK]** ボタンをクリックして USB デバッグを有効にしてください。 - ![](Enable_USB_Debugging_Warning.png) + ![](Enable_USB_Debugging_Warning.png)(w:350) 1. USB デバッグの横のチェックボックスの緑が有効になっている印です。 - ![](USB_Debugging_Enabled.png) + ![](USB_Debugging_Enabled.png)(w:350) -1. Android デバイスを USB から一旦取り外して、すぐに再度接続してください。 - PC がデバイスを認識したら、この Mac にデバイスとの通信wp許可するかどうかのメッセージが Android デバイス上に表示されます。 - **[Always allow this computer (常に許可)]** を押して、**[OK]** ボタンをクリックします。 - - ![](PC_RSA_Fingerprint.png) +1. Android デバイスを USB から一旦取り外して、すぐに再度接続してください。PC がデバイスを認識したら、 +この Mac にデバイスとの通信許可に関する次のメッセージが Android デバイス上に表示されます。 メッセージ ボックスは USB 接続をどのようにするか尋ねるので、**[Always allow this computer (常に許可)]** を押して、 +**[OK]** ボタンをクリックします。 + ![](PC_RSA_Fingerprint.png)(w:350) 1. デバイスの設定が適切か確認するために、/Applications/Utilties から **Terminal app** を開きます。 ![](MAC_Terminal_Activate.png) -1. コマンド プロンプトに **ADB devices** とタイプすると、Mac に接続されているすべてのデバイスが表示されます。 +1. コマンド プロンプトに **「ADB devices」** と打ち込むと、Mac に接続されているすべてのデバイスが表示されます。 ![](MAC_Checking_ADB_Devices.png) [region:note] -adb devices と打ち込んでも自分のデバイスが確認できない場合は、次の方法で PC が Android デバイスを認識できるか試してみてください。 -* デバイスが表示されているのに権限がないと表示される場合は、デバイスに PC に認証させるかどうかを尋ねさせる必要があります。 +「adb devices」と打ち込んでも自分のデバイスが確認できない場合は、次の方法で PC が Android デバイスを認識できるか試してみてください。 +* デバイスが表示されても権限がないと表示される場合は、デバイスに PC に認証させるかどうかを尋ねさせる必要があります。 * デバイスを表示させるためには、デバイスを一旦取り外して再接続しなければならない場合があります。 * [Always allow (常に許可)] チェックボックスにチェックを入れておくことを推奨します。 * **Camera (PTP)** ではなく **Media Device (MTP)** として接続されている場合、正しく設定されているデバイスが表示されない場合があります。この段階でご自分のデバイスが ***adb devices*** として全く表示されない場合は、**Camera (PTP)** オプションを選択してください。 @@ -209,9 +208,7 @@ adb devices と打ち込んでも自分のデバイスが確認できない場 [/EXCERPT:MacOSSetup] [EXCERPT:LinuxSetup] -本文書は現在作成中です。現在公開されている文書については、 -[新規および更新リソース](https://docs.unrealengine.com/latest/INT/Updates/index.html) を参照してください。 - +[INCLUDE:Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/2#AndroidLinux_2] [/EXCERPT:LinuxSetup] --> diff --git a/Engine/Documentation/Source/Platforms/Android/GettingStarted/2/AndroidQS_2.KOR.udn b/Engine/Documentation/Source/Platforms/Android/GettingStarted/2/AndroidQS_2.KOR.udn index 59888e296278..a74c445d39ed 100644 --- a/Engine/Documentation/Source/Platforms/Android/GettingStarted/2/AndroidQS_2.KOR.udn +++ b/Engine/Documentation/Source/Platforms/Android/GettingStarted/2/AndroidQS_2.KOR.udn @@ -1,9 +1,9 @@ -INTSourceChangelist:3298293 +INTSourceChangelist:3477690 Availability:Public Title:2. 안드로이드 디바이스 셋업 Crumbs:%ROOT%, Platforms, Platforms/Android, Platforms/Android/GettingStarted Description:안드로이드 디바이스 개발용으로 셋업하기 입니다. -Version:4.12 +Version:4.16 Skilllevel:Intermediate tags:Android tags:Mobile @@ -86,7 +86,7 @@ Android Works 가 설치되었으니 안드로이드 디바이스를 개발에 1. Build Number 를 7 회 탭하여 개발자 모드를 활성화시킵니다. - ![](Enable_Dev_Mode.png) + ![](Enable_Dev_Mode.png)(w:350) 1. 처음 몇 번 탭하고 나면 You are now **# steps** away from becoming a developer. 메시지가 뜰 것입니다. @@ -96,26 +96,26 @@ Android Works 가 설치되었으니 안드로이드 디바이스를 개발에 1. Settings 메뉴로 되돌아가 사용가능해진 Developer Options 를 선택합니다. - ![](Dev_Options_Enabled.png) + ![](Dev_Options_Enabled.png)(w:350) 1. Developer Options 메뉴에서 USB 디버깅을 탭하여 켭니다. - ![](Enable_USB_Debugging.png) + ![](Enable_USB_Debugging.png)(w:350) 1. 묻는 창이 뜨면 OK 를 선택하여 USB 디버깅을 켭니다. - ![](Enable_USB_Debugging_Warning.png) + ![](Enable_USB_Debugging_Warning.png)(w:350) 1. USB 디버깅 활성화 여부는 그 옆의 체크박스에 초록색 체크표시가 있는 것을 보고 알 수 있습니다. - ![](USB_Debugging_Enabled.png) + ![](USB_Debugging_Enabled.png)(w:350) -1. USB 에서 안드로이드 디바이스를 뽑은 다음 바로 다시 꽂습니다. - 디바이스를 PC 에서 인식한 이후 안드로이드 디바이스에 이 PC 와의 통신을 허용하겠냐는 메시지가 뜹니다. - **이 컴퓨터 항상 허용** 이라는 체크박스를 누른 다음 **OK** 버튼을 누릅니다. +1. USB 에서 안드로이드 디바이스를 뽑은 다음 바로 다시 꽂습니다. 디바이스를 PC 에서 인식한 이후 안드로이드 디바이스에 +이 PC 와의 통신을 허용하겠냐는 메시지가 뜹니다. 메시지 박스에서 USB 연결에 무엇을 사용하겠느냐고 물어옵니다. **이 컴퓨터 항상 허용** 이라는 체크박스를 누른 다음 +**OK** 버튼을 누릅니다. + + ![](PC_RSA_Fingerprint.png)(w:350) - ![](PC_RSA_Fingerprint.png) - 1. 디바이스 셋업이 제대로 되었는지 확인하기 위해, 윈도우+R 키를 눌러 실행 창에 cmd 라 입력합니다. ![](Windows_Run_Command.png) @@ -158,36 +158,35 @@ Android Works 가 설치되었으니 안드로이드 디바이스를 개발에 1. Build Number 를 7 회 탭합니다. - ![](Enable_Dev_Mode.png) + ![](Enable_Dev_Mode.png)(w:350) 1. 처음 몇 번 탭하고 나면 **You are now # steps away from becoming a developer.** 메시지가 뜰 것입니다. 1. Developer Mode 가 활성화되면 아래와 같은 성공 메시지가 화면에 뜰 것입니다. - ![](Dev_Mode_Active.png) + ![](Dev_Mode_Active.png)(w:350) 1. Settings 메뉴로 되돌아가 사용가능해진 Developer Options 를 선택합니다. - ![](Dev_Options_Enabled.png) + ![](Dev_Options_Enabled.png)(w:350) 1. Developer Options 메뉴에서 USB 디버깅을 켭니다. - ![](Enable_USB_Debugging.png) + ![](Enable_USB_Debugging.png)(w:350) 1. 묻는 창이 뜨면 OK 를 선택하여 USB 디버깅을 켭니다. - ![](Enable_USB_Debugging_Warning.png) + ![](Enable_USB_Debugging_Warning.png)(w:350) 1. USB 디버깅 활성화 여부는 그 옆의 체크박스에 초록색 체크표시가 있는 것을 보고 알 수 있습니다. - ![](USB_Debugging_Enabled.png) + ![](USB_Debugging_Enabled.png)(w:350) 1. USB 에서 안드로이드 디바이스를 뽑은 다음 바로 다시 꽂습니다. - 디바이스를 PC 에서 인식한 이후 안드로이드 디바이스에 이 PC 와의 통신을 허용하겠냐는 메시지가 뜹니다. - **이 컴퓨터 항상 허용** 이라는 체크박스를 누른 다음 **OK** 버튼을 누릅니다. +이 PC 와의 통신을 허용하겠냐는 메시지가 뜹니다. 메시지 박스에서 USB 연결에 무엇을 사용하겠느냐고 물어옵니다. **이 컴퓨터 항상 허용** 이라는 체크박스를 누른 다음 +**OK** 버튼을 누릅니다. - ![](PC_RSA_Fingerprint.png) - + ![](PC_RSA_Fingerprint.png)(w:350) 1. 디바이스 셋업이 제대로 되었는지 확인하기 위해, /Applications/Utilties 에서 **Terminal app** 을 엽니다. ![](MAC_Terminal_Activate.png) @@ -209,9 +208,7 @@ Android Works 가 설치되었으니 안드로이드 디바이스를 개발에 [/EXCERPT:MacOSSetup] [EXCERPT:LinuxSetup] -이 문서는 현재 작업중입니다. 현재 공개된 문서를 확인하려면 [New and Updated Resources](https://docs.unrealengine.com/latest/INT/Updates/index.html) 페이지를 -참고해 주세요. - +[INCLUDE:Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/2#AndroidLinux_2] [/EXCERPT:LinuxSetup] --> diff --git a/Engine/Documentation/Source/Platforms/Android/GettingStarted/3/AndroidQS_3.INT.udn b/Engine/Documentation/Source/Platforms/Android/GettingStarted/3/AndroidQS_3.INT.udn index b011bd9308be..f6645a393efe 100644 --- a/Engine/Documentation/Source/Platforms/Android/GettingStarted/3/AndroidQS_3.INT.udn +++ b/Engine/Documentation/Source/Platforms/Android/GettingStarted/3/AndroidQS_3.INT.udn @@ -2,7 +2,7 @@ Availability:Public Title:3. Create Your Project Crumbs:%ROOT%, Platforms, Platforms/Android, Platforms/Android/GettingStarted Description:Start a template project -Version:4.12 +Version:4.16 Skilllevel:Intermediate tags:Android tags:Mobile diff --git a/Engine/Documentation/Source/Platforms/Android/GettingStarted/3/AndroidQS_3.JPN.udn b/Engine/Documentation/Source/Platforms/Android/GettingStarted/3/AndroidQS_3.JPN.udn index b26c5d259e6e..bb049983af33 100644 --- a/Engine/Documentation/Source/Platforms/Android/GettingStarted/3/AndroidQS_3.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Android/GettingStarted/3/AndroidQS_3.JPN.udn @@ -1,9 +1,9 @@ -INTSourceChangelist:3150518 +INTSourceChangelist:3477690 Availability:Public -Title:3.プロジェクトを作成する +Title:3.プロジェクトの作成 Crumbs:%ROOT%, Platforms, Platforms/Android, Platforms/Android/GettingStarted Description:テンプレート プロジェクトを開始する -Version:4.12 +Version:4.16 Skilllevel:Intermediate tags:Android tags:Mobile @@ -21,7 +21,7 @@ Blueprint Third Person template を用いてブループリント ベースの -1. **[Unreal Projects Browser]** ウィンドウから、 「EmissiveMaterials」 という名前の FPS プロジェクト を新規作成します。 +1. **[Unreal Projects Browser]** ウィンドウから、「EmissiveMaterials」 という名前の FPS プロジェクトを新規作成します。 * Third Person Template を使う * ハードウェアをモバイル / タブレットに設定する * グラフィック レベルを Scalable 3D または 2D に設定する @@ -33,7 +33,7 @@ Blueprint Third Person template を用いてブループリント ベースの 1. 完了したら緑の **[Create Project (プロジェクトを作成)]** ボタンを押してプロジェクトを作成します。 [REGION:tip] -この例はブループリント ベースのプロジェクトですが、C++ やブループリントなど、すべてのプロジェクト タイプを Android デバイスへパッケージ化およびデプロイできます。 +これはブループリント ベース プロジェクトの例ですが、C++ やブループリントなど、すべてのプロジェクト タイプを Android デバイスへパッケージ化およびデプロイすることができます。 [/REGION] ## 結果 diff --git a/Engine/Documentation/Source/Platforms/Android/GettingStarted/3/AndroidQS_3.KOR.udn b/Engine/Documentation/Source/Platforms/Android/GettingStarted/3/AndroidQS_3.KOR.udn index 1690068d41ae..caf86e5e34b1 100644 --- a/Engine/Documentation/Source/Platforms/Android/GettingStarted/3/AndroidQS_3.KOR.udn +++ b/Engine/Documentation/Source/Platforms/Android/GettingStarted/3/AndroidQS_3.KOR.udn @@ -1,9 +1,9 @@ -INTSourceChangelist:3150518 +INTSourceChangelist:3477690 Availability:Public Title:3. 프로젝트 생성 Crumbs:%ROOT%, Platforms, Platforms/Android, Platforms/Android/GettingStarted Description:템플릿 프로젝트를 시작합니다. -Version:4.12 +Version:4.16 Skilllevel:Intermediate tags:Android tags:Mobile diff --git a/Engine/Documentation/Source/Platforms/Android/GettingStarted/4/AndroidQS_4.INT.udn b/Engine/Documentation/Source/Platforms/Android/GettingStarted/4/AndroidQS_4.INT.udn index f249f2812518..d2876ffeb224 100644 --- a/Engine/Documentation/Source/Platforms/Android/GettingStarted/4/AndroidQS_4.INT.udn +++ b/Engine/Documentation/Source/Platforms/Android/GettingStarted/4/AndroidQS_4.INT.udn @@ -2,6 +2,7 @@ Availability:Public Title:4. Deploy Your Level Crumbs:%ROOT%, Platforms, Platforms/Android, Platforms/Android/GettingStarted Description:Launch your level with one-click deploying. +version:4.16 Skilllevel:Intermediate tags:Android tags:Mobile @@ -54,16 +55,22 @@ The chart below shows you which Texture formats work with which Android based de 1. While your level is being launched on your device the progress will be displayed in the bottom right-hand corner of the screen. When the project has been successfully deployed to your device you will see a message telling you so. - + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + afagQeEvf4Q + [/PARAMLITERAL] [PARAMLITERAL:width] 640 [/PARAMLITERAL] [PARAMLITERAL:height] 360 [/PARAMLITERAL] - [PARAMLITERAL:videoid] - afagQeEvf4Q + [PARAMLITERAL:units] + px + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple [/PARAMLITERAL] [/OBJECT] diff --git a/Engine/Documentation/Source/Platforms/Android/GettingStarted/4/AndroidQS_4.JPN.udn b/Engine/Documentation/Source/Platforms/Android/GettingStarted/4/AndroidQS_4.JPN.udn index edd90aa9cefd..f6983622b70a 100644 --- a/Engine/Documentation/Source/Platforms/Android/GettingStarted/4/AndroidQS_4.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Android/GettingStarted/4/AndroidQS_4.JPN.udn @@ -1,8 +1,9 @@ -INTSourceChangelist:3298293 +INTSourceChangelist:3477690 Availability:Public -Title:4.レベルをデプロイする +Title:4.レベルのデプロイ方法 Crumbs:%ROOT%, Platforms, Platforms/Android, Platforms/Android/GettingStarted Description: ワンクリック デプロイでレベルを起動する +version:4.16 Skilllevel:Intermediate tags:Android tags:Mobile @@ -31,8 +32,8 @@ Android ベースのデバイスとサポートしているテクスチャ フ どのテクスチャ フォーマットがサポートされているのか不確かな場合は、ゲームを実行して以下の操作を行うと確認できます。 1. 画面を指 4 本で一度にタップすると、ダイアログが表示されます。 - 1. これは、コンソールコマンド (stat fps などの) の入力に通常使用するダイアログ ボックスですが、ユーザーのデバイスがサポートしているフォーマットも表示します。 - 1. リストが表示されたら、これを活用してデプロイおよびパッケージングに最も適したタイプを選択します。 + 1. このダイアログ ボックスは通常コンソールコマンド (stat fps などの) の入力に使用しますが、ユーザーのデバイスがサポートしているフォーマットも表示します。 + 1. 表示されたリストの中からデプロイおよびパッケージングに最も適したタイプを選択します。 ![](Available_Texture_Formats.png) @@ -40,12 +41,12 @@ Android ベースのデバイスとサポートしているテクスチャ フ ## ステップ -1. Android ベースのデバイス上のレベルをテストするには、テスト対象のレベルが開いていることをまず確認してください。 - このサンプルでは、最後のステップで作成したブループリント ベースのプロジェクトから **ThirdPersonExampleMap** レベルを使用します。 +1. Android ベースのデバイス上でレベルのテストを行うには、テスト対象のレベルが開いていることをまず確認してください。 + 最後のステップで作成したブループリント ベースのプロジェクトの **ThirdPersonExampleMap** レベルを使って説明します。 ![](Correct_Level_Open.png) -1. **ThirdPersonExampleMap** を開いたら、**メイン ツールバー** の **[Launch]** アイコンの横にある三角をクリックして、さらにオプションを表示します。 +1. **ThirdPersonExampleMap** を開いたら、**メイン ツールバー** の **[Launch]** アイコンの横にある三角をクリックしてオプションを展開します。 ![](Level_Deploy_Options.png) @@ -57,14 +58,20 @@ Android ベースのデバイスとサポートしているテクスチャ フ プロジェクトが正常にデバイスにデプロイされると、その旨のメッセージが表示されます。 [OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + afagQeEvf4Q + [/PARAMLITERAL] [PARAMLITERAL:width] 640 [/PARAMLITERAL] [PARAMLITERAL:height] 360 [/PARAMLITERAL] - [PARAMLITERAL:videoid] - afagQeEvf4Q + [PARAMLITERAL:units] + px + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple [/PARAMLITERAL] [/OBJECT] diff --git a/Engine/Documentation/Source/Platforms/Android/GettingStarted/4/AndroidQS_4.KOR.udn b/Engine/Documentation/Source/Platforms/Android/GettingStarted/4/AndroidQS_4.KOR.udn index c9fc1e4b11fb..e6f168868b14 100644 --- a/Engine/Documentation/Source/Platforms/Android/GettingStarted/4/AndroidQS_4.KOR.udn +++ b/Engine/Documentation/Source/Platforms/Android/GettingStarted/4/AndroidQS_4.KOR.udn @@ -1,8 +1,9 @@ -INTSourceChangelist:3298293 +INTSourceChangelist:3477690 Availability:Public Title:4. 레벨 디플로이 Crumbs:%ROOT%, Platforms, Platforms/Android, Platforms/Android/GettingStarted Description:원클릭 디플로이로 레벨을 실행시킵니다. +version:4.16 Skilllevel:Intermediate tags:Android tags:Mobile @@ -55,16 +56,22 @@ Checkpoint:AndroidQS 1. 디바이스에서 레벨이 실행되는 도중 그 진행상황이 화면 우하단 구석에 표시됩니다. 프로젝트가 디바이스에 성공적으로 디플로이되면 알림창이 뜹니다. - + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + afagQeEvf4Q + [/PARAMLITERAL] [PARAMLITERAL:width] 640 [/PARAMLITERAL] [PARAMLITERAL:height] 360 [/PARAMLITERAL] - [PARAMLITERAL:videoid] - afagQeEvf4Q + [PARAMLITERAL:units] + px + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple [/PARAMLITERAL] [/OBJECT] diff --git a/Engine/Documentation/Source/Platforms/Android/GettingStarted/5/AndroidQS_5.INT.udn b/Engine/Documentation/Source/Platforms/Android/GettingStarted/5/AndroidQS_5.INT.udn index 1fb315fb5c14..81cd50612129 100644 --- a/Engine/Documentation/Source/Platforms/Android/GettingStarted/5/AndroidQS_5.INT.udn +++ b/Engine/Documentation/Source/Platforms/Android/GettingStarted/5/AndroidQS_5.INT.udn @@ -2,7 +2,7 @@ Title:5. Package Your Game Crumbs:%ROOT%, Platforms, Platforms/Android, Platforms/Android/GettingStarted Description:Package your game for installation. -Version:4.12 +Version:4.16 Skilllevel:Intermediate tags:Android tags:Mobile @@ -81,7 +81,7 @@ We are currently packaging in **Development** because we are testing this game, Different devices support different Texture formats depending on the hardware they run on. See, [](Platforms/Android/Reference) for a detailed breakdown of the various formats. [/REGION] -1. You will then be prompted for a location to save your packaged game. For now create a new folder on the desk top and select that as the location to save your project to. +1. You will then be prompted for a location to save your packaged game. For now create a new folder on the desktop and select that as the location to save your project to. ![](package_folder.png) @@ -154,9 +154,7 @@ We are currently packaging in **Development** because we are testing this game, [/EXCERPT:MacOSSetup] [EXCERPT:LinuxSetup] -We're currently in the process of writing this documentation. Please refer to our [New and Updated Resources](https://docs.unrealengine.com/latest/INT/Updates/index.html) page to see -which documentation is being published at this time. - +[INCLUDE:Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/5#AndroidLinux_5] [/EXCERPT:LinuxSetup] --> diff --git a/Engine/Documentation/Source/Platforms/Android/GettingStarted/5/AndroidQS_5.JPN.udn b/Engine/Documentation/Source/Platforms/Android/GettingStarted/5/AndroidQS_5.JPN.udn index 1e5f2321722a..ab05b39833ba 100644 --- a/Engine/Documentation/Source/Platforms/Android/GettingStarted/5/AndroidQS_5.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Android/GettingStarted/5/AndroidQS_5.JPN.udn @@ -1,9 +1,9 @@ -INTSourceChangelist:3298293 +INTSourceChangelist:3477690 Availability:Public Title:5.ゲームのパッケージ化 Crumbs:%ROOT%, Platforms, Platforms/Android, Platforms/Android/GettingStarted Description:ゲームをインストール用にパッケージ化する -Version:4.12 +Version:4.16 Skilllevel:Intermediate tags:Android tags:Mobile @@ -155,9 +155,7 @@ Checkpoint:AndroidQS [/EXCERPT:MacOSSetup] [EXCERPT:LinuxSetup] -本文書は現在作成中です。現在公開されている文書については、 -[新規および更新リソース](https://docs.unrealengine.com/latest/INT/Updates/index.html) を参照してください。 - +[INCLUDE:Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/5#AndroidLinux_5] [/EXCERPT:LinuxSetup] --> diff --git a/Engine/Documentation/Source/Platforms/Android/GettingStarted/5/AndroidQS_5.KOR.udn b/Engine/Documentation/Source/Platforms/Android/GettingStarted/5/AndroidQS_5.KOR.udn index 03164e475225..a105c0eacc60 100644 --- a/Engine/Documentation/Source/Platforms/Android/GettingStarted/5/AndroidQS_5.KOR.udn +++ b/Engine/Documentation/Source/Platforms/Android/GettingStarted/5/AndroidQS_5.KOR.udn @@ -1,9 +1,9 @@ -INTSourceChangelist:3298293 +INTSourceChangelist:3477690 Availability:Public Title:5. 게임 패키징 Crumbs:%ROOT%, Platforms, Platforms/Android, Platforms/Android/GettingStarted Description:설치를 위해 게임을 패키징합니다. -Version:4.12 +Version:4.16 Skilllevel:Intermediate tags:Android tags:Mobile @@ -155,9 +155,7 @@ Checkpoint:AndroidQS [/EXCERPT:MacOSSetup] [EXCERPT:LinuxSetup] -이 문서는 현재 작업중입니다. 현재 공개된 문서를 확인하려면 [New and Updated Resources](https://docs.unrealengine.com/latest/INT/Updates/index.html) -페이지를 참고하세요. - +[INCLUDE:Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/5#AndroidLinux_5] [/EXCERPT:LinuxSetup] --> diff --git a/Engine/Documentation/Source/Platforms/Android/GettingStarted/6/AndroidQS_6.INT.udn b/Engine/Documentation/Source/Platforms/Android/GettingStarted/6/AndroidQS_6.INT.udn index b3a80b0bced4..86db58ece5f3 100644 --- a/Engine/Documentation/Source/Platforms/Android/GettingStarted/6/AndroidQS_6.INT.udn +++ b/Engine/Documentation/Source/Platforms/Android/GettingStarted/6/AndroidQS_6.INT.udn @@ -2,7 +2,7 @@ Availability:Public Title:6. On your Own Crumbs:%ROOT%, Platforms, Platforms/Android, Platforms/Android/GettingStarted Description:Read more about Android development with Unreal Engine. -Version:4.12 +Version:4.16 Skilllevel:Intermediate tags:Android tags:Mobile diff --git a/Engine/Documentation/Source/Platforms/Android/GettingStarted/6/AndroidQS_6.JPN.udn b/Engine/Documentation/Source/Platforms/Android/GettingStarted/6/AndroidQS_6.JPN.udn index ca552e4579ae..597546c2b9a7 100644 --- a/Engine/Documentation/Source/Platforms/Android/GettingStarted/6/AndroidQS_6.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Android/GettingStarted/6/AndroidQS_6.JPN.udn @@ -1,9 +1,9 @@ -INTSourceChangelist:3298293 +INTSourceChangelist:3477690 Availability:Public Title:6.応用編 Crumbs:%ROOT%, Platforms, Platforms/Android, Platforms/Android/GettingStarted Description:アンリアル エンジンによる Android 開発についての追加情報 -Version:4.12 +Version:4.16 Skilllevel:Intermediate tags:Android tags:Mobile diff --git a/Engine/Documentation/Source/Platforms/Android/GettingStarted/6/AndroidQS_6.KOR.udn b/Engine/Documentation/Source/Platforms/Android/GettingStarted/6/AndroidQS_6.KOR.udn index 2acbfad4d9c7..b36ec2e33c51 100644 --- a/Engine/Documentation/Source/Platforms/Android/GettingStarted/6/AndroidQS_6.KOR.udn +++ b/Engine/Documentation/Source/Platforms/Android/GettingStarted/6/AndroidQS_6.KOR.udn @@ -1,9 +1,9 @@ -INTSourceChangelist:3298293 +INTSourceChangelist:3477690 Availability:Public Title:6. 직접 해보기 Crumbs:%ROOT%, Platforms, Platforms/Android, Platforms/Android/GettingStarted Description:언리얼 엔진으로 안드로이드 개발을 하는 데 있어 추가로 참고할 자료입니다. -Version:4.12 +Version:4.16 Skilllevel:Intermediate tags:Android tags:Mobile diff --git a/Engine/Documentation/Source/Platforms/Android/GettingStarted/AndroidQuickStart.INT.udn b/Engine/Documentation/Source/Platforms/Android/GettingStarted/AndroidQuickStart.INT.udn index 180475f7572f..ab75d13f8671 100644 --- a/Engine/Documentation/Source/Platforms/Android/GettingStarted/AndroidQuickStart.INT.udn +++ b/Engine/Documentation/Source/Platforms/Android/GettingStarted/AndroidQuickStart.INT.udn @@ -2,7 +2,7 @@ Availability: Public Title: Android Quick Start Crumbs:%ROOT%, Platforms, Platforms/Android Description:Setting up for development for the Android platform. -Version:4.12 +Version:4.16 Skilllevel:Intermediate tags:Android tags:Mobile @@ -48,9 +48,9 @@ Checkpoint:AndroidQS ![](AndroidTopic.jpg) -Unreal Engine 4 (UE4) uses a special version of the Android Software Development Kit (SDK), called **CodeWorks for Android 1R4**. +Unreal Engine 4 (UE4) uses a special version of the Android Software Development Kit (SDK), called **CodeWorks for Android 1R6**. This version of CodeWorks for Android is the easiest way to set up the SDK and Native Development Kit (NDK) needed to develop -Android projects with UE4. Although we're currently using version 1R4, we intend to use subsequent releases of CodeWorks. +Android projects with UE4. Although we're currently using version 1R6, we intend to use subsequent releases of CodeWorks. If you have other versions of the Android SDK installed (or, older versions of CodeWorks for Android), we recommend that you uninstall them and install CodeWorks for Android, using the CodeWorks for Android installer that's being distributed with UE4. @@ -65,7 +65,7 @@ This guide also teaches you how to put a template game on your Android device wi ## Objectives -* Install and set up the Android SDK. +* Install and setup the Android SDK. * Setting up your Android device for development. * Creating a project that is targeted for Android mobile development. * How to deploy a level to your Android device diff --git a/Engine/Documentation/Source/Platforms/Android/GettingStarted/AndroidQuickStart.JPN.udn b/Engine/Documentation/Source/Platforms/Android/GettingStarted/AndroidQuickStart.JPN.udn index f26e4296e5de..e97ddc978071 100644 --- a/Engine/Documentation/Source/Platforms/Android/GettingStarted/AndroidQuickStart.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Android/GettingStarted/AndroidQuickStart.JPN.udn @@ -1,9 +1,9 @@ -INTSourceChangelist:3298293 +INTSourceChangelist:3451711 Availability:Public Title:Android クイックスタート Crumbs:%ROOT%, Platforms, Platforms/Android Description:Android プラットフォーム開発の設定 -Version:4.12 +Version:4.16 Skilllevel:Intermediate tags:Android tags:Mobile @@ -49,9 +49,9 @@ Checkpoint:AndroidQS ![](AndroidTopic.jpg) -アンリアル エンジン (UE4) は **CodeWorks for Android 1R4** という Android ソフトウェア開発キット (SDK) の特別バージョンを採用しています。 +アンリアル エンジン (UE4) は **CodeWorks for Android 1R6** という Android ソフトウェア開発キット (SDK) の CodeWorks for Android の特別バージョンを使うと、 -UE4 での Android プロジェクト開発に必要な SDK および Native Development Kit (NDK) の設定が最も楽になります。現在使用しているバージョンは 1R4 ですが、CodeWorks の次のバージョンを使用する予定です。 +UE4 での Android プロジェクト開発に必要な SDK および Native Development Kit (NDK) の設定が最も楽になります。現在使用しているバージョンは 1R6 ですが、CodeWorks の次のバージョンを使用する予定です。 違うバージョンの Android SDK (あるいは、CodeWorks for Android の古いバージョン) をインストールしている場合は、 一旦それをアンインストールして、UE4 が配布している CodeWorks for Android インストーラーを使って CodeWorks for Android をインストールすることを推奨します。 @@ -62,7 +62,7 @@ UE4 に付いている CodeWorks for Android インストーラーを使うこ ## 目標 Android クイックスタートでは、UE4 で Android を開発するための PC もしくは Mac の基本的な設定を一通り説明します。 -さらに、アンリアル エディタの起動およびパッケージ化機能を使って、Android デバイスにテンプレート ゲームを入れる方法も説明します。 +さらに、アンリアル エディタの起動およびパッケージ化機能を使って、Android デバイスにテンプレート ゲームを取り込む方法も説明します。 ## 目的 diff --git a/Engine/Documentation/Source/Platforms/Android/GettingStarted/AndroidQuickStart.KOR.udn b/Engine/Documentation/Source/Platforms/Android/GettingStarted/AndroidQuickStart.KOR.udn index 038131486562..48c2a4bb09d2 100644 --- a/Engine/Documentation/Source/Platforms/Android/GettingStarted/AndroidQuickStart.KOR.udn +++ b/Engine/Documentation/Source/Platforms/Android/GettingStarted/AndroidQuickStart.KOR.udn @@ -1,9 +1,9 @@ -INTSourceChangelist:3298293 +INTSourceChangelist:3477690 Availability: Public Title: 안드로이드 퀵 스타트 Crumbs:%ROOT%, Platforms, Platforms/Android Description:안드로이드 플랫폼용 개발 셋업하기 입니다. -Version:4.12 +Version:4.16 Skilllevel:Intermediate tags:Android tags:Mobile @@ -49,9 +49,9 @@ Checkpoint:AndroidQS ![](AndroidTopic.jpg) -언리얼 엔진 4 (UE4) 는 **CodeWorks for Android 1R4** 라는 특수 버전 안드로이드 소프트웨어 개발 키트(SDK)를 사용합니다. +언리얼 엔진 4 (UE4) 는 **CodeWorks for Android 1R6** 라는 특수 버전 안드로이드 소프트웨어 개발 키트(SDK)를 사용합니다. 이 버전의 안드로이드용 CodeWorks 는 UE4 로 안드로이드 프로젝트를 개발하는 데 필요한 SDK 와 NDK 를 구성하기에 -가장 쉬운 방법입니다. 현재 1R4 버전을 사용하고는 있지만, 앞으로 나오는 CodeWorks 새 버전을 사용할 계획입니다. +가장 쉬운 방법입니다. 현재 1R6 버전을 사용하고는 있지만, 앞으로 나오는 CodeWorks 새 버전을 사용할 계획입니다. 다른 안드로이드 SDK 버전( 또는 안드로이드용 CodeWorks 구버전)이 설치된 경우, 먼저 설치를 해제한 뒤 UE4 와 같이 배포되는 안드로이드용 CodeWorks 인스톨러를 사용해서 설치해 주시기 바랍니다. diff --git a/Engine/Documentation/Source/Platforms/Android/InAppPurchases/In-AppPurchases.JPN.udn b/Engine/Documentation/Source/Platforms/Android/InAppPurchases/In-AppPurchases.JPN.udn index a55a73fe8590..5183445ea34b 100644 --- a/Engine/Documentation/Source/Platforms/Android/InAppPurchases/In-AppPurchases.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Android/InAppPurchases/In-AppPurchases.JPN.udn @@ -1,6 +1,5 @@ -INTSourceChangelist:3150518 -Title:Android でアプリ内課金を使用する -Description:アプリ内課金を使って Android ゲームに有料コンテンツを追加する +Title:Android でのアプリ内課金の実装方法 +Description:アプリ内課金を実装して Android ゲームに有料コンテンツを追加する Crumbs: Availability:Public version:4.10 @@ -12,17 +11,17 @@ Related:Platforms/Mobile/InAppPurchases/ ## コンフィギュレーション -1. Google Play でアプリ内課金を設定するためのステップを説明します。 +1. Google Play でアプリ内課金 (In-App Purchase) を設定するためのステップを説明します。 [REGION:note] - Google Play の id はすべて小文字でなければなりません。さらに、iOS と Android の ID を一致させておくとブループリントの設定がとても楽になります。 + Google Play の id にはすべて小文字を使用します。また、iOS と Android の ID を同じにしておくと、ブループリントをとても楽に設定することができます。 [/REGION] ![image alt text](image_0.png) -1. 使用する ID およびアイテムが消費型かそうでないかをメモしておきましょう。 +1. 使用する ID およびアイテムが消費型か非消費型かをメモしておきます。 -1. ブループリント プロジェクトであれば設定の必要はありません。コード プロジェクトのためオンライン システムを使う設定が必要な場合は、プロジェクトの Build.cs ファイルに次のブロックを加えてください。 +1. ブループリント プロジェクトの場合は、そのままで大丈夫です。コード プロジェクト用にオンライン システムを使う設定にするには、プロジェクトの Build.cs ファイルに次のブロックを加えてください。 if (Target.Platform == UnrealTargetPlatform.Android) { @@ -48,7 +47,7 @@ Related:Platforms/Mobile/InAppPurchases/ ## テスティング -Android をテストするには、正しいテスティング プロファイルを設定するだけでなく、パッケージ化した APK を Google Play にアップロードする必要があります。カスタム仕様のキーストアも必要になります。 +Android をテストするためには、テスティング プロファイルを正しく設定し、かつパッケージ化した APK を Google Play にアップロードする必要があります。カスタム キーストアも必要になります。 ## 役に立つリンク diff --git a/Engine/Documentation/Source/Platforms/Android/LaunchScreens/LaunchScreens.INT.udn b/Engine/Documentation/Source/Platforms/Android/LaunchScreens/LaunchScreens.INT.udn index 99ad43124e1a..dd646697493f 100644 --- a/Engine/Documentation/Source/Platforms/Android/LaunchScreens/LaunchScreens.INT.udn +++ b/Engine/Documentation/Source/Platforms/Android/LaunchScreens/LaunchScreens.INT.udn @@ -27,15 +27,93 @@ To configure your project to use the Launch Images: 1. Inside your project from the **File** menu, select **Edit** then select **Project Settings**. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](AndroidSplash1.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](AndroidSplash1_Mac.png) + [/PARAM] + [/OBJECT] 1. In the **Project Settings**, on the left under **Platforms** select **Android** to display the project settings for Android apps. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](AndroidSplash2.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](AndroidSplash2_Mac.png) + [/PARAM] + [/OBJECT] 1. Scroll down to the **Launch Images** section and make sure the **Show launch image** check box is enabled. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](AndroidSplash3.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](AndroidSplash3_Mac.png) + [/PARAM] + [/OBJECT] 1. Click the **...** icon next to each image to open a browser where you can select your image from your computer. @@ -43,8 +121,33 @@ To configure your project to use the Launch Images: 1. Once you have selected the images you want to use they will be added to the project and included during the startup splash screen. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](AndroidSplash5.png) + [/PARAM] + [/OBJECT] + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](AndroidSplash5_Mac.png) + [/PARAM] + [/OBJECT] [REGION:note] Examples for portrait and landscape images may be found in the Engine/Build/Android/Java/res/drawable folder as PNG files. diff --git a/Engine/Documentation/Source/Platforms/Android/OpenGLES31MobileRenderer/OpenGLES31MobileRenderer.INT.udn b/Engine/Documentation/Source/Platforms/Android/OpenGLES31MobileRenderer/OpenGLES31MobileRenderer.INT.udn index 27de7f552d4c..b476109da64d 100644 --- a/Engine/Documentation/Source/Platforms/Android/OpenGLES31MobileRenderer/OpenGLES31MobileRenderer.INT.udn +++ b/Engine/Documentation/Source/Platforms/Android/OpenGLES31MobileRenderer/OpenGLES31MobileRenderer.INT.udn @@ -2,7 +2,7 @@ Title: Android OpenGL ES 3.1 Mobile Renderer Description:Setting up your UE4 Android project to work with the OpenGL ES 3.1 mobile render Crumbs:%ROOT%, Platforms, Platforms/Android, Platforms/Android/OpenGLES31MobileRenderer/ Availability:Public -version:4.12 +version:4.16 Parent:Platforms/Android tags:Mobile tags:Android @@ -23,35 +23,17 @@ While Unreal Engine 4 (UE4) has long supported many OpenGL ES 3.0 and 3.1 featur In order to preview what OpenGL ES 3.1 will look like in the UE4 Editor, you will need to first enable it by doing the following: -1. From the **Main Toolbar**, go to **Edit** and then select the **Editor Preferences** option. - - ![](OGL3_01.png) - -1. Under the **General** section, locate the **Experimental** category and then look for the **Rendering** section. Click on the checkbox next to **Enable Metal/Vulkan/High-end mobile Preview Rendering Level in editor** to enable the option to preview OpenGL ES 3.1. +1. Go to the **Main Tool Bar**, click on the **Settings** option and go to **Preview Rendering Level** option and select the **High-End Mobile / Metal** and finally **High-End Mobile** option. [REGION:lightbox] - [![](Platforms\Android\VulkanMobileRenderer\VMP_03.png)(w:447 h:308)](Platforms\Android\VulkanMobileRenderer\VMP_03.png) + [![](OGL3_10.png)(w:391)](OGL3_10.png) [/REGION] [REGION:caption] Click for full image. [/REGION] - [region:note] - For a more detailed description on how to enable Metal/Vulkan/High-End previewing in the UE4 Editor, check out the [Enabling Vulkan Preview Rendering in Editor](Platforms/Android/VulkanMobileRenderer/#enablingvulkanpreviewrenderingineditor) document. - [/region] - -1. Then on the **Main Tool Bar** click on the **Settings** option and go to **Preview Rendering Level** option and select the **High-End Mobile / Metal** option. - - [REGION:lightbox] - [![](Platforms\Android\VulkanMobileRenderer\VMP_Android_Settings_05.png)(w:391)](Platforms\Android\VulkanMobileRenderer\VMP_Android_Settings_05.png) - [/REGION] - - [REGION:caption] - Click for full image. - [/REGION] - -1. Now if you look at the lower right-hand corner of the UE4 Editor viewport, you should see the text **Feature Level: ES3_1** which means you are now previewing the level using OpenGL ES 3.1's feature set. +1. Once the shaders have recompiled, if you look at the lower right-hand corner of the UE4 Editor viewport, you should see the text **Feature Level: ES3_1** which means you are now previewing the level using OpenGL ES 3.1's feature set. [REGION:lightbox] [![](OGL3_02.png)(w:404)](OGL3_02.png) diff --git a/Engine/Documentation/Source/Platforms/Android/ReducingAPKSize/ReducingAPKSizes.JPN.udn b/Engine/Documentation/Source/Platforms/Android/ReducingAPKSize/ReducingAPKSizes.JPN.udn index b020f87e1de3..711ea8100983 100644 --- a/Engine/Documentation/Source/Platforms/Android/ReducingAPKSize/ReducingAPKSizes.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Android/ReducingAPKSize/ReducingAPKSizes.JPN.udn @@ -1,28 +1,30 @@ -INTSourceChangelist:2945303 +INTSourceChangelist:3108692 Availability:Public -Title:APK パッケージ サイズを減らす方法 +Title:APK パッケージ化サイズを小さくする方法 Crumbs:%ROOT%, Platforms, Platforms/Android -Description:パッケージングした Android ゲームのサイズを減らす方法。 +Description:パッケージ化した Android ゲームのサイズを小さくする方法。 Skilllevel:Intermediate -Version:4.8 +Version:4.12 Parent:Platforms/Android +Related:Engine/Performance/ReducingPackageSize tags:Mobile tags:Android type:overview [TOC(start:2 end:3)] -UE4 プロジェクトが どのタイプの Android デバイスをターゲットにしていても、アプリケーション パッケージまたは **APK** のサイズを Google Play store 向けに 50MB 以下に減らすことは難しいです。 -次のガイドでは、プロジェクトの最終版の APK パッケージのサイズを UE4 エディタに備わっているツール以外は使わずに、できる限り小さくするために役立つステップを説明します。 +Android デバイス向けの UE4 プロジェクトはすべて、アプリケーション パッケージ (**APK**) サイズを Google Play store の容量制限の 50MB 以下にすることが難しいです。 +本ページでは、UE4 エディタに備わっているツール以外は使わずに、製品版プロジェクトの APK サイズをできる限り小さくするために役立つステップを説明します。 ## ETC1 テクスチャに関する留意点 -ETC1 Texture フォーマットを使って Android 向けにプロジェクトをパックすると、Alpha 情報を埋め込んでいるテクスチャを圧縮せずに、それらを完全に圧縮されていないテクスチャとして扱うことに気づく必要があります。 -プロジェクトのランタイム時のパフォーマンスがこの影響を大きく受けることはありませんが、プロジェクト APK のサイズを増やします。 -プロジェクトがアルファを使用しているテクスチャを要求している場合は、Alpha が埋め込まれている 1 つのテクスチャを使用するのではなく、Diffuse と Alpha の 2 つに分けた方が良いです。 -そうすると、プロジェクトがクックされパッケージ化された時に、必ずテクスチャは圧縮されます。 -## プラットフォームに依存しない技術 +ETC1 Texture フォーマットを使って Android 向けにプロジェクトをパッケージ化処理する場合、Alpha 情報を埋め込んでいるテクスチャは圧縮されません。完全に圧縮されていないテクスチャとして処理されることを理解する必要があります。 +プロジェクトのランタイム時パフォーマンスがこの影響を大きく受けることはありませんが、プロジェクト APK のサイズが大きくなります。 +プロジェクトが Alpha 使用のテクスチャを要求している場合は、 +Alpha が埋め込まれている 1 つのテクスチャを Diffuse と Alpha の 2 つのテキストに分けることを推奨します。そのようにすると、プロジェクトがクックおよびパッケージ化される時に、必ずテクスチャが圧縮されます。 -Android 専用の上記の方法の他にも、ターゲット プラットフォームに関係なくパッケージ化されたゲームのサイズを減らす方法はいろいろあります。 +## プラットフォーム タイプに関係なく使える方法 + +Android に特化した上記の方法以外にも、ターゲット プラットフォームに関係なくパッケージ化されたゲーム サイズを小さくする方法は数多くあります。 [INCLUDE:Engine/Performance/ReducingPackageSize#main(offset:1)] diff --git a/Engine/Documentation/Source/Platforms/Android/Reference/AndroidGettingStarted.INT.udn b/Engine/Documentation/Source/Platforms/Android/Reference/AndroidGettingStarted.INT.udn index 52387d548141..e1943a15cecb 100644 --- a/Engine/Documentation/Source/Platforms/Android/Reference/AndroidGettingStarted.INT.udn +++ b/Engine/Documentation/Source/Platforms/Android/Reference/AndroidGettingStarted.INT.udn @@ -2,7 +2,7 @@ Title: Android Development Reference Crumbs:%ROOT%, Platforms, Platforms/Android Description:How to install different Android SDKs, set environment variables, and work with texture formats. -Version: 4.12 +Version: 4.16 SkillLevel: Intermediate Parent:Platforms/Android tags:Mobile @@ -51,7 +51,7 @@ Here is what we currently require for Android game development in UE4: There are several methods for getting the components. If you have already installed one of these, look in the corresponding section for additional requirements: -### CodeWorks for Android 1R4 +### CodeWorks for Android 1R6 [OBJECT:ToggleButtonContent] [PARAMLITERAL:category] OS @@ -84,20 +84,22 @@ There are several methods for getting the components. If you have already instal ## Android テクスチャ フォーマット -Android デバイスはすべて同じ構成をしているわけではありません。特に、レンダリングハードウェアは 4 種類あります。それぞれが異なるフォーマットの圧縮テクスチャをサポートしています。 +Android デバイスはすべて同じ構成をしているわけではありません。特に、レンダリング ハードウェアは 4 種類あります。それぞれが異なるフォーマットの圧縮テクスチャをサポートしています。 [EXCERPT:AndroidFormats] | フォーマット | 説明 | @@ -359,12 +363,12 @@ Android プラットフォーム向けにゲームをデプロイまたはパッ 最初の (**Android**) は、事実上すべてのフォーマットを取り込んで、これらをクックしてパッケージへまとめます。処理時間は多少長めで、作成されるパッケージ サイズも大きくなりますが、 ランタイム時に最適のフォーマットを選択すれば、使用メモリは必要最低限に確実に抑えられます。すべてのデバイスに機能します (**Android (ETC1)**のように)。 -[region:note] +[REGION:note] アンリアル エンジン 4.8 以降のバージョンで、**ES31** および **AEP** レンダリングを Tegra K1 デバイス上で使用できるようになりました。 現在 ES31 と AEP レンダリングをサポートしているデバイス数が限られているため、現段階ではパフォーマンスおよび互換性テストがほとんど完了していないことに留意してください。 これらのデバイスのどれかを使用する場合、プロジェクトの中でデバイスが期待する動きをするように、拡張パフォーマンスと互換テストを行うことを推奨します。 -[/region] +[/REGION] ### フォーマットの選択 -ユーザーのみなさんは、おそらく使用デバイスに最適なフォーマットを選択されるでしょう。デバイスに搭載されている GPU のタイプがわかる場合、上記の表を参照してフォーマットを選択してください。タイプがわからない場合、**[Android]** または **[Android (ETC1)]** を選択します。ゲームの実行時にスクリーンを指 4 本で一度にタップすると、ダイアログが表示されます。これは、コンソールコマンド (stat fps などの) の入力に通常使用するダイアログ ボックスですが、ユーザーのデバイスがサポートしているフォーマットも表示します。リストが表示されたら、これを活用してデプロイおよびパッケージングに最も適したタイプを選択します。対象デバイスでサポートしていないフォーマットが選択された場合、読み込みが失敗します。 +ユーザーのみなさんは、おそらく使用デバイスに最適なフォーマットを選択されるでしょう。デバイスに搭載されている GPU のタイプがわかる場合、上記の表を参照してフォーマットを選択してください。タイプがわからない場合、**[Android]** または **[Android (ETC1)]** を選択します。ゲームの実行時にスクリーンを指 4 本で一度にタップすると、ダイアログが表示されます。このダイアログ ボックスは通常コンソールコマンド (stat fps などの) の入力に使用しますが、ユーザーのデバイスがサポートしているフォーマットも表示します。表示されたリストの中からデプロイおよびパッケージングにより適したタイプを選択します。対象デバイスでサポートしていないフォーマットが選択された場合、読み込みが失敗します。 diff --git a/Engine/Documentation/Source/Platforms/Android/Reference/AndroidGettingStarted.KOR.udn b/Engine/Documentation/Source/Platforms/Android/Reference/AndroidGettingStarted.KOR.udn index eeb797c1e391..8272475802e5 100644 --- a/Engine/Documentation/Source/Platforms/Android/Reference/AndroidGettingStarted.KOR.udn +++ b/Engine/Documentation/Source/Platforms/Android/Reference/AndroidGettingStarted.KOR.udn @@ -1,9 +1,9 @@ -INTSourceChangelist:3298293 +INTSourceChangelist:3477690 Availability:Public Title: 안드로이드 개발 참고서 Crumbs:%ROOT%, Platforms, Platforms/Android Description:다양한 안드로이드 SDK 설치, 환경 변수 설정, 텍스처 포맷 작업 방법 설명입니다. -Version: 4.12 +Version: 4.16 SkillLevel: Intermediate Parent:Platforms/Android tags:Mobile @@ -20,8 +20,8 @@ UE4 안드로이드 프로젝트 개발용 컴퓨터에 설치하고 구성해 ## 안드로이드 SDK 사양 현재 UE4 에서 안드로이드 게임 개발을 하는 데 필요한 사양은 다음과 같습니다: -| 컴포넌트 | 환경 변수 | -| ---------- | --------------------- | + | 컴포넌트 | 환경 변수 | + | ---------- | --------------------- | | [INCLUDE:#codecomponents] | [INCLUDE:#codeenvvar] | [nav] diff --git a/Engine/Documentation/Source/Platforms/GearVR/QuickStart/2/GearVRQuickStart_2.JPN.udn b/Engine/Documentation/Source/Platforms/GearVR/QuickStart/2/GearVRQuickStart_2.JPN.udn index 017d83863b05..ac3563a0a9ab 100644 --- a/Engine/Documentation/Source/Platforms/GearVR/QuickStart/2/GearVRQuickStart_2.JPN.udn +++ b/Engine/Documentation/Source/Platforms/GearVR/QuickStart/2/GearVRQuickStart_2.JPN.udn @@ -1,8 +1,9 @@ -Availability:Public +INTSourceChangelist:3477690 +Availability:Public Title:2.Gear VR プロジェクトの設定 Crumbs:%ROOT%, Platforms, Platforms/GearVR Description:Gear VR ヘッドセットを使用する C++ ベースの UE4 プロジェクトの設定方法 -Version:4.9 +Version:4.16 Skilllevel:Intermediate tags:VR tags:GearVR @@ -15,51 +16,63 @@ Checkpoint:GearVRQS ## ステップ -1. プロジェクトの作成とコンパイルが終了したら、Visual Studio 2015 が (既にインストールされている場合は) エディタと一緒に自動的に開きます。 +1. プロジェクトの作成とコンパイルが終了したら、Visual Studio が (既にインストールされている場合は) エディタと一緒に自動的に開きます。 ![](GVR_Editor_Opened.png) [region:note] - 使用するアンリアル エンジンが 4.8 以降の場合、ブループリント ベースのプロジェクト Visual Studio 2015 は必要ないので開きません。 + 使用するアンリアル エンジンが 4.8 以降の場合、ブループリント ベースのプロジェクト Visual Studio は必要ないので開きません。 [/region] 1. UE4 エディタをロードしたら、**メインのツールバー** から **[Windows]** タブを開いて **[Plugins]** メニューを選択します。 [OBJECT:EmbeddedVideo] - [PARAMLITERAL:width] - 640 - [/PARAMLITERAL] - [PARAMLITERAL:height] - 360 - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - eo79kj2i2bc - [/PARAMLITERAL] + [PARAMLITERAL:videoid] + eo79kj2i2bc + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] -1. プラグイン メニューから **[Head Mounted Displays]** セクションへ移動して、**[Oculus]** オプションを **無効** に、**[Gear VR]** オプションを **有効** にします。エディタを再起動するために**[Restart Now (今すぐ再起動)]** ボタンをクリックして、変更を反映させます。 +1. プラグイン メニューから **[Head Mounted Displays]** セクションへ移動して、**[Oculus]** オプションを **無効** に、**[Gear VR]** オプションを **有効** にします。エディタを再起動するために **[Restart Now (今すぐ再起動)]** ボタンをクリックして、変更を反映させます。 ![](GVR_Plugin_Options_Toggle.png) -1. エディタが再起動したら **メイン ツールバー** から **[Edit (編集)]** を選択して、次に **[Project Settings (プロジェクト設定)]** を選択します。その後 **[APKPacking]** セクションから Android プラットフォームの **[Configure Now (今すぐ設定)]** ボタンをクリックします。 +1. エディタが再起動したら **メイン ツールバー** から **[Edit (編集)]** を選択して、次に **[Project Settings (プロジェクト設定)]** を選択します。その後 **[APKPacking]** セクションから Android プラットフォームの **[Configure Now (今すぐ設定)]** ボタンをクリックします。 [OBJECT:EmbeddedVideo] - [PARAMLITERAL:width] - 640 - [/PARAMLITERAL] - [PARAMLITERAL:height] - 360 - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - If_vSzD5h3w - [/PARAMLITERAL] + [PARAMLITERAL:videoid] + If_vSzD5h3w + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] -1. 次に **[Minimum SDK Version]** を **9** から **19** に変更します。 +1. 次に **[Minimum SDK Version]** と **[Target SDK Version]** を **9** から **19** に変更します。 ![](GVR_Android_SDK_Version.png) -1. **[Configure the Android Manifest for deployment to Gear VR (Gear VR にデプロイする Android Manifest の設定]** チェックボックスが表示されるまでスクロールダウンして、これを有効にします。 +1. **[Configure the Android Manifest for deployment to Gear VR]** チェックボックスが表示されるまでスクロールダウンして、これを有効にします。 [Region:note] これを設定しないと Gear VR ヘッドセットでプロジェクトが実行しないので、とても重要な手順です。 @@ -69,9 +82,9 @@ Checkpoint:GearVRQS 1. 次に **[Android SDK]** セクションを選択して、必要な Android SDK ファイルの場所を開発用 PC に入力します。 必要なフォルダは Tegra ファイルをインストールした場所を参照してください。 - [Region:note] - Android 1R4 用の CodeWorks がインストール済みであれば、ここで行う作業は特にありません。情報が足りなかったり、別の場所に関連づいている場合のみ修正してください。 + [Region:note] + Android 1R6 用の CodeWorks がインストール済みであれば、ここで行う作業は特にありません。情報が足りなかったり、別の場所に関連づいている場合のみ修正してください。 [/region] ![](GVR_Android_SDK_Setup.png) @@ -83,26 +96,23 @@ Checkpoint:GearVRQS [/region] [OBJECT:EmbeddedVideo] - [PARAMLITERAL:width] - 640 - [/PARAMLITERAL] - [PARAMLITERAL:height] - 360 - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - 29oB5aowElQ - [/PARAMLITERAL] + [PARAMLITERAL:videoid] + 29oB5aowElQ + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] - [nav] diff --git a/Engine/Documentation/Source/Platforms/GearVR/QuickStart/2/GearVRQuickStart_2.KOR.udn b/Engine/Documentation/Source/Platforms/GearVR/QuickStart/2/GearVRQuickStart_2.KOR.udn index 1d03a31ed4d7..4e4004ed21ee 100644 --- a/Engine/Documentation/Source/Platforms/GearVR/QuickStart/2/GearVRQuickStart_2.KOR.udn +++ b/Engine/Documentation/Source/Platforms/GearVR/QuickStart/2/GearVRQuickStart_2.KOR.udn @@ -1,9 +1,9 @@ -INTSourceChangelist:3150518 +INTSourceChangelist:3477690 Availability:Public Title:2. 기어 VR 프로젝트 구성 Crumbs:%ROOT%, Platforms, Platforms/GearVR Description:기어 VR 헤드셋과 사용할 C++ 기반 UE4 프로젝트 구성 방법입니다. -Version: 4.9 +Version: 4.16 Skilllevel: Intermediate tags:VR tags:GearVR @@ -16,26 +16,32 @@ Checkpoint:GearVRQS ## 단계 -1. 프로젝트 생성 및 컴파일이 완료되면, Visual Studio 2015 이 (설치된 경우) 에디터와 함께 자동으로 열립니다. +1. 프로젝트 생성 및 컴파일이 완료되면, Visual Studio 가 (설치된 경우) 에디터와 함께 자동으로 열립니다. ![](GVR_Editor_Opened.png) [region:note] - 언리얼 엔진 4.8 이상 버전에 블루프린트 기반 프로젝트를 사용하시는 경우, Visual Studio 2015 은 필요치 않아 열리지 않을 것입니다. + 언리얼 엔진 4.8 이상 버전에 블루프린트 기반 프로젝트를 사용하시는 경우, Visual Studio 는 필요치 않아 열리지 않을 것입니다. [/region] 1. UE4 에디터가 로드되면, **메인 툴바** 에서 **창** 탭을 열고 **플러그인** 메뉴를 선택합니다. - + [OBJECT:EmbeddedVideo] - [PARAMLITERAL:width] - 640 - [/PARAMLITERAL] - [PARAMLITERAL:height] - 360 - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - eo79kj2i2bc - [/PARAMLITERAL] + [PARAMLITERAL:videoid] + eo79kj2i2bc + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] 1. **Plugins** 메뉴에서 **Head Mounted Displays** 섹션으로 가서 **Oculus** 옵션을 **disable**, **Gear VR** 옵션을 **enable** 합니다. 그런 다음 **지금 재시작** 버튼을 눌러 에디터를 재시작, 변경내용이 적용되도록 합니다. @@ -45,18 +51,24 @@ Checkpoint:GearVRQS 1. 에디터가 재시작되면 **메인 툴바** 에서 **편집** - **프로젝트 세팅** 을 선택한 다음, **APKPacking** 섹션의 안드로이드 지원에 대한 **Configure Now** (지금 환경설정) 버튼을 클릭합니다. [OBJECT:EmbeddedVideo] - [PARAMLITERAL:width] - 640 - [/PARAMLITERAL] - [PARAMLITERAL:height] - 360 - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - If_vSzD5h3w - [/PARAMLITERAL] + [PARAMLITERAL:videoid] + If_vSzD5h3w + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] -1. 다음 **Minimum SDK Version** 을 **9** 에서 **19** 로 변경합니다. +1. 다음 **Minimum SDK Version** 및 **Target SDK Version** 을 **9** 에서 **19** 로 변경합니다. ![](GVR_Android_SDK_Version.png) @@ -72,7 +84,7 @@ Checkpoint:GearVRQS Tegra 파일을 설치한 위치에 필요한 폴더를 찾을 수 있습니다. [Region:note] - 이미 CodeWorks for Android 1R4 를 설치했다면 이 정보가 채워져 있을 것입니다. 여기서 뭔가 바꿔야 하는 이유는, 정보가 없거나 잘못된 위치로 되어있을 경우입니다. + 이미 CodeWorks for Android 1R6 를 설치했다면 이 정보가 채워져 있을 것입니다. 여기서 뭔가 바꿔야 하는 이유는, 정보가 없거나 잘못된 위치로 되어있을 경우입니다. [/region] ![](GVR_Android_SDK_Setup.png) @@ -84,26 +96,23 @@ Checkpoint:GearVRQS [/region] [OBJECT:EmbeddedVideo] - [PARAMLITERAL:width] - 640 - [/PARAMLITERAL] - [PARAMLITERAL:height] - 360 - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - 29oB5aowElQ - [/PARAMLITERAL] + [PARAMLITERAL:videoid] + 29oB5aowElQ + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] [/OBJECT] - [nav] diff --git a/Engine/Documentation/Source/Platforms/GearVR/QuickStart/3/GearVRQuickStart_3.INT.udn b/Engine/Documentation/Source/Platforms/GearVR/QuickStart/3/GearVRQuickStart_3.INT.udn index 66d286a2e4f5..789cb2b23f61 100644 --- a/Engine/Documentation/Source/Platforms/GearVR/QuickStart/3/GearVRQuickStart_3.INT.udn +++ b/Engine/Documentation/Source/Platforms/GearVR/QuickStart/3/GearVRQuickStart_3.INT.udn @@ -2,7 +2,7 @@ Availability:Public Title:3. Gear VR Project Packaging & Deployment Crumbs:%ROOT%, Platforms/GearVR Description:Instructions on how to deploy projects form UE4 to use with the Samsung Gear VR Headset. -Version: 4.9 +Version: 4.16 Skilllevel: Intermediate tags:VR tags:GearVR diff --git a/Engine/Documentation/Source/Platforms/GearVR/QuickStart/3/GearVRQuickStart_3.JPN.udn b/Engine/Documentation/Source/Platforms/GearVR/QuickStart/3/GearVRQuickStart_3.JPN.udn index bd9d1785fd1b..7f2ec61f14c3 100644 --- a/Engine/Documentation/Source/Platforms/GearVR/QuickStart/3/GearVRQuickStart_3.JPN.udn +++ b/Engine/Documentation/Source/Platforms/GearVR/QuickStart/3/GearVRQuickStart_3.JPN.udn @@ -1,9 +1,9 @@ -INTSourceChangelist:3150518 +INTSourceChangelist:3451711 Availability:Public -Title:3.Gear VR プロジェクトのパッケージングとデプロイ +Title:3.Gear VR プロジェクトのパッケージング化とデプロイ Crumbs:%ROOT%, Platforms/GearVR Description:UE4 プロジェクトを Samsung Gear VR ヘッドセットに対応するようにデプロイする方法 -Version:4.9 +Version:4.16 Skilllevel:Intermediate tags:VR tags:GearVR @@ -21,7 +21,7 @@ Related:Platforms\GearVR\Debugging 1. 最初に Samsung Galaxy Note 4 スマートフォンと USB コードを接続して、このコードが開発に使用している PC の USB ポートに差し込まれていることを確認してください。 -1. 次に **Main Toolbar** へ移動して、**[File]** > **[Package Project]** > **[Android]** > **[Android ETC 2]** を選択してパッケージング処理を開始します。 +1. 次に **メイン ツールバー** から **[File]** > **[Package Project]** > **[Android]** > **[Android ETC 2]** を選択してパッケージング処理を開始します。 ![](GVR_Deploy_To_Android.png) @@ -29,23 +29,23 @@ Related:Platforms\GearVR\Debugging ![](GVR_Save_Project.png) -1. プロジェクトのサイズ次第では、パッケージング処理は数分、もしくは数時間かかる場合があります。 +1. プロジェクト サイズによって、パッケージング処理は数分から数時間かかります。 処理が完了すると、ビルドを保存するために選択 / 作成したフォルダ内部に以下の画像のようなファイルが 3 つ作成されています。 ![](GVR_Deployed_Files.png) -1. 次にビルドをパッケージ処理したフォルダ内にある **「.BAT」** ファイルを **マウスの左ボタン** で **ダブルクリック** して実行します。 - 「.BAT」ファイルを実行すると、スマートフォンへの現在のデプロイの進捗状況を示すコマンドラインウィンドウが表示されます。 - スマートフォンへのプロジェクトのデプロイが成功すると、コマンドラインウィンドウは自動的に閉じます。 +1. 次にビルドをパッケージ処理したフォルダ内にある **.BAT** ファイルを **マウスの左ボタン** で **ダブルクリック** して実行します。 + .BAT ファイルを実行すると、スマートフォンへのデプロイの進捗状況を示すコマンドライン ウィンドウが表示されます。 + スマートフォンへ正常にプロジェクトがデプロイされると、コマンドライン ウィンドウは自動的に閉じます。 ![](GVR_Run_Bat_File.png) -1. 「.BAT」ファイルを実行すると、デプロイの進捗状況および可能性のあるエラーを示すコマンドライン ウィンドウが表示されます。 +1. .BAT ファイルを実行すると、デプロイの進捗状況および発生する可能性のあるエラーがコマンドライン ウィンドウに表示されます。 ![](GVR_Deployment_Window.png) [region:note] - 「.BAT」ファイルの実行時に表示されるコマンドライン ウィンドウは、終了時に自動的に閉じます。コマンドライン ウィンドウを手動で閉じると、デプロイに問題が生じる要因となるため、ウィンドウを手動で閉じないでください。 + .BAT ファイルの実行時に表示されるコマンドライン ウィンドウは、終了時に自動的に閉じます。コマンドライン ウィンドウを手動で閉じると、デプロイに問題が生じる要因となるため、ウィンドウを手動で閉じないでください。 [/region] 1. コマンドライン ウィンドウが閉じたら、新規に作成したアプリケーションをスマートフォンでチェックします。このアプリケーション名は、作成元の UE4 C++ プロジェクトに使用した名前と一致しなくてはいけません。 @@ -55,5 +55,5 @@ Related:Platforms\GearVR\Debugging [nav] -## 最終結果 +## 結果 完了すると、Samsung Galaxy スマートフォンと Gear VR HMD を使ってプロジェクトの起動と表示が可能になります。 diff --git a/Engine/Documentation/Source/Platforms/GearVR/QuickStart/3/GearVRQuickStart_3.KOR.udn b/Engine/Documentation/Source/Platforms/GearVR/QuickStart/3/GearVRQuickStart_3.KOR.udn index 6b98a4b14862..32cb681a57e2 100644 --- a/Engine/Documentation/Source/Platforms/GearVR/QuickStart/3/GearVRQuickStart_3.KOR.udn +++ b/Engine/Documentation/Source/Platforms/GearVR/QuickStart/3/GearVRQuickStart_3.KOR.udn @@ -1,9 +1,9 @@ -INTSourceChangelist:3150518 +INTSourceChangelist:3451711 Availability:Public Title:3. 기어 VR 프로젝트 패키징 & 디플로이 Crumbs:%ROOT%, Platforms/GearVR Description:삼성 기어 VR 헤드셋을 사용하는 UE4 프로젝트 디플로이 방법 안내입니다. -Version: 4.9 +Version: 4.16 Skilllevel: Intermediate tags:VR tags:GearVR diff --git a/Engine/Documentation/Source/Platforms/GearVR/QuickStart/4/GearVRQuickStart_4.INT.udn b/Engine/Documentation/Source/Platforms/GearVR/QuickStart/4/GearVRQuickStart_4.INT.udn index bcd30c6afcb9..cae3f6afab76 100644 --- a/Engine/Documentation/Source/Platforms/GearVR/QuickStart/4/GearVRQuickStart_4.INT.udn +++ b/Engine/Documentation/Source/Platforms/GearVR/QuickStart/4/GearVRQuickStart_4.INT.udn @@ -3,7 +3,7 @@ Title:4. On Your Own! Crumbs:%ROOT%, Platforms/GearVR Description:Using the methods provided during this guide, polish up your level with additional content and read up on related topics. Navigation:platform -Version: 4.9 +Version: 4.16 Skilllevel: Intermediate tags:VR tags:GearVR diff --git a/Engine/Documentation/Source/Platforms/GearVR/QuickStart/4/GearVRQuickStart_4.JPN.udn b/Engine/Documentation/Source/Platforms/GearVR/QuickStart/4/GearVRQuickStart_4.JPN.udn index c9dc03f39b82..789684079000 100644 --- a/Engine/Documentation/Source/Platforms/GearVR/QuickStart/4/GearVRQuickStart_4.JPN.udn +++ b/Engine/Documentation/Source/Platforms/GearVR/QuickStart/4/GearVRQuickStart_4.JPN.udn @@ -1,10 +1,10 @@ -INTSourceChangeList:3150518 +INTSourceChangelist:3451711 Availability:Public Title:4.応用編 Crumbs:%ROOT%, Platforms/GearVR Description:このガイドで説明した方法を使って、追加のコンテンツでレベルにさらに磨きをかけます。関連トピックスのドキュメントも紹介します。 Navigation:platform -Version:4.9 +Version:4.16 Skilllevel:Intermediate tags:VR tags:GearVR @@ -17,7 +17,7 @@ Checkpoint:GearVRQS Android のスマートフォンに UE4 プロジェクトをデプロイし、Gear VR HMD を使って表示したら、以下の項目を追加してみましょう。 -* [Migrate ツール](Engine/Content/Browser/UserGuide/Migrate/) を使って、コンテンツをモバイル コンテンツ サンプルから使用するプロジェクトに移動することができます。 +* [Migrate ツール](Engine/Content/Browser/UserGuide/Migrate/) を使って、コンテンツをモバイル コンテンツ サンプルから使用するプロジェクトに移動します。 * Android スマートフォンへデプロイした時に、プロジェクトができるだけ速く実行するように [Default Device Profiles](Platforms/Mobile/Performance/TipsAndTricks) の設定を変更します。 diff --git a/Engine/Documentation/Source/Platforms/GearVR/QuickStart/4/GearVRQuickStart_4.KOR.udn b/Engine/Documentation/Source/Platforms/GearVR/QuickStart/4/GearVRQuickStart_4.KOR.udn index 0a0af207e5e7..6083dc8076f4 100644 --- a/Engine/Documentation/Source/Platforms/GearVR/QuickStart/4/GearVRQuickStart_4.KOR.udn +++ b/Engine/Documentation/Source/Platforms/GearVR/QuickStart/4/GearVRQuickStart_4.KOR.udn @@ -1,10 +1,10 @@ -INTSourceChangelist:3150518 +INTSourceChangelist:3451711 Availability:Public Title:4. 직접 해보기! Crumbs:%ROOT%, Platforms/GearVR Description:여기서 안내해 드리는 방법을 통해 추가적인 콘텐츠로 레벨을 다듬어 보고 관련된 다른 자료도 확인할 수 있습니다. Navigation:platform -Version: 4.9 +Version: 4.16 Skilllevel: Intermediate tags:VR tags:GearVR diff --git a/Engine/Documentation/Source/Platforms/GearVR/QuickStart/GearVRQuickStart.INT.udn b/Engine/Documentation/Source/Platforms/GearVR/QuickStart/GearVRQuickStart.INT.udn index 83875eaa28b8..c6043bdf2d85 100644 --- a/Engine/Documentation/Source/Platforms/GearVR/QuickStart/GearVRQuickStart.INT.udn +++ b/Engine/Documentation/Source/Platforms/GearVR/QuickStart/GearVRQuickStart.INT.udn @@ -7,6 +7,7 @@ Platform:Gear VR Skilllevel: Intermediate Version:4.9 type:quick start +type:landing parent:Platforms/GearVR tags:VR tags:GearVR diff --git a/Engine/Documentation/Source/Platforms/GearVR/QuickStart/GearVRQuickStart.JPN.udn b/Engine/Documentation/Source/Platforms/GearVR/QuickStart/GearVRQuickStart.JPN.udn index 2763323f5df9..8e4c5e10b4bb 100644 --- a/Engine/Documentation/Source/Platforms/GearVR/QuickStart/GearVRQuickStart.JPN.udn +++ b/Engine/Documentation/Source/Platforms/GearVR/QuickStart/GearVRQuickStart.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3150518 +INTSourceChangelist:3429260 Availability:Public Title:Samsung Gear VR UE 4 のクイックスタート Crumbs:%ROOT%, Platforms/GearVR @@ -6,8 +6,9 @@ Description:Samsung Gear VR ヘッドセットと使えるようにプロジェ Navigation:platform Platform:Gear VR Skilllevel:Intermediate -version:4.9 +Version:4.9 type:quick start +type:landing parent:Platforms/GearVR tags:VR tags:GearVR diff --git a/Engine/Documentation/Source/Platforms/GearVR/QuickStart/GearVRQuickStart.KOR.udn b/Engine/Documentation/Source/Platforms/GearVR/QuickStart/GearVRQuickStart.KOR.udn index 54920de24f77..45f5a617ac97 100644 --- a/Engine/Documentation/Source/Platforms/GearVR/QuickStart/GearVRQuickStart.KOR.udn +++ b/Engine/Documentation/Source/Platforms/GearVR/QuickStart/GearVRQuickStart.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3150518 +INTSourceChangelist:3429260 Availability:Public Title:삼성 기어 VR UE4 퀵스타트 Crumbs:%ROOT%, Platforms/GearVR @@ -8,6 +8,7 @@ Platform:Gear VR Skilllevel: Intermediate Version:4.9 type:quick start +type:landing parent:Platforms/GearVR tags:VR tags:GearVR diff --git a/Engine/Documentation/Source/Platforms/GoogleVR/Daydream/Daydream.INT.udn b/Engine/Documentation/Source/Platforms/GoogleVR/Daydream/Daydream.INT.udn index 60faad472faa..d0aabea5760a 100644 --- a/Engine/Documentation/Source/Platforms/GoogleVR/Daydream/Daydream.INT.udn +++ b/Engine/Documentation/Source/Platforms/GoogleVR/Daydream/Daydream.INT.udn @@ -4,12 +4,13 @@ Crumbs:%ROOT%, Platforms/GoogleVR Description:Which Google VR features are specific to Daydream devices. Navigation:platform Skilllevel: Intermediate -Version: 4.12 +Version: 4.16 parent:Platforms/GoogleVR type:overview tags:VR tags:Google VR tags:Daydream +topic-image:Platforms\GoogleVR\GoogleVR_Topic_Image.png [TOC(start:2)] @@ -23,40 +24,69 @@ While Google VR can work for almost any Android based device, there are certain ## Downloading Google VR UE4 Branch To get all of the pre-built functionality Google Daydream VR offers you will need to download and compile a special version of UE4 that you will find linked below. This version of UE4 contains the needed code and assets that are required to display the Daydream Motion Controller in the manner Google wants it. -* [Google VR Github Pull](https://github.com/googlevr-unreal/UnrealEngine/tree/4.13-googlevr) +* [Google VR Github Pull](https://github.com/googlevr-unreal/UnrealEngine/releases) Once you have downloaded this version of UE4, follow the directions for the [Downloading Unreal as a Zip from Github](GettingStarted/DownloadingUnrealEngine/DownloadZip) page to complete the rest of the setup process. -## Android NDK 11c -In order to access the full functionality of Daydream, you will need to download and install the Android NDK version 11c. +## Android NDK 12b +In order to access the full functionality of Daydream, you will need to download and install the Android NDK version 12b. -* [NDK 11c Downlaod](https://developer.android.com/ndk/downloads/index.html) +* [NDK 12b Downlaod](https://developer.android.com/ndk/downloads/older_releases.html) -Once downloaded and installed you will need to point UE4 to the new NDK files by going to the **Android SDK** > **SDKConfig** section and changing the NDK path to the new NDK 11c install location and set the SDK API level to **matchndk** and the NDK API Level to **android-24**. +Once downloaded and installed you will need to point UE4 to the new NDK files by going to the **Android SDK** > **SDKConfig** section and changing the NDK path to the new NDK 12b install location and set the SDK API level to **matchndk** and the NDK API Level to **android-24**. -![](GDaydream_New_NDK_00.png) +[REGION:lightbox] +[![](GDaydream_New_NDK_00.png)(w:502)](GDaydream_New_NDK_00.png) +[/REGION] + +[REGION:caption] +Click for full image. +[/REGION] ## Scanline Racing **Scanline Racing** is a feature specific to Daydream devices that when enabled helps to reduce latency in your VR project. To enable Scanline Racing in your Google VR project for Daydream devices you will need to do the following. -1. Open up your **Project Settings** and go to **Platforms** > **Android**. +1. Open up your **Project Settings** and go to **Platforms** > **Android**. Under the **APKPackaging** section, set the following: - ![](GDaydream_Arm64_Support_00.png) + * Minimum SDK Version: **24** + * Target SDK Version: **24** -1. Under the **Build** section enable **Support arm64[aka arm64-v8a]** by clicking on the checkmark box next to its name and disable **Support arm7[aka armebi-v7a]**. + [REGION:lightbox] + [![](GDaydream_Arm64_Support_00.png)(w:502)](GDaydream_Arm64_Support_00.png) + [/REGION] - ![](Platforms\GoogleVR\QuickStart\2\GVRQS_Build_arm64_Support_00.png) + [REGION:caption] + Click for full image. + [/REGION] + +1. Under the **Build** section change the following: + * Support armv7(aka armeabi-v7a): **Disabled** + * Support arm64 (aka arm64-v8a): **Enabled** + + [REGION:lightbox] + [![](GDaydream_Build_Support.png)(w:502)](GDaydream_Build_Support.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] [region:note] Enabling this will add significant time to your first cook as the arm64 libraries need to be compiled. [/region] 1. Then under the **Advanced APKPackaging** section and enable the following options. - * **Configure for deployment to Daydream** - * **Configure GoogleVR Deployment Mode** - * **Configure GoogleVR for low-latency rendering mode (scanline racing)** + * Configure GoogleVR Deployment Mode: **Daydream** + * Configure GoogleVR for sustained-performance mode (scanline racing): **Enabled** + + [REGION:lightbox] + [![](GDaydream_Scanline_Racing_Support_00.png)(w:502)](GDaydream_Scanline_Racing_Support_00.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] - ![](GDaydream_Scanline_Racing_Support_00.png) Then next time you cook your UE4 project and deploy it to your Daydream device low latency rendering will be enabled. @@ -69,7 +99,13 @@ For a more in-depth look at how to use the Google Daydream Controller Motion Con 1. First, open up your project's Plugins menu and under the Input section, enable the **Google VR Motion Controller** plugin. - ![](GDaydream_Plugins.png) + [REGION:lightbox] + [![](GDaydream_Plugins.png)(w:692)](GDaydream_Plugins.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] [region:note] Please note that to use the Plugin you will need to re-start your UE4 Editor. Failing to do so will result in you not being able to use the Google VR Motion Controller. @@ -83,14 +119,14 @@ For a more in-depth look at how to use the Google Daydream Controller Motion Con The Motion Controller component should use the same position and height of the VR Camera. [/region] -1. Now when you run your project your motion controllers should look similar to the following image. +1. When you run your project your motion controllers should look similar to the following image. [REGION:lightbox] [![](unreal-controller-model.png)(w:724)](unreal-controller-model.png) [/REGION] [region:note] - If you are using the 4.14 binary build of UE4 the above content will be missing and you should instead use the standard Motion Controller component. All of this functionality is slated to be in the 4.15 release of UE4. If you need to this functionality now, you will have to download and compile the, [UE4.13 Google VR version](https://github.com/googlevr-unreal/UnrealEngine/tree/4.13-googlevr). + If you are using the 4.14 binary build of UE4 the above content will be missing and you should instead use the standard Motion Controller component. All of this functionality is included with the 4.15 and later releases of UE4. If you need to this functionality now, you will have to download and compile the, [UE4.13 Google VR version](https://github.com/googlevr-unreal/UnrealEngine/tree/4.13-googlevr). [/region] Now that you have a Google VR Motion Controller component on your Pawn, you can edit and adjust how the Motion Controller's function by searching for **Google VR** in the Blueprint Editor and using the nodes that you find. @@ -99,32 +135,99 @@ Now that you have a Google VR Motion Controller component on your Pawn, you can These Training Streams help to provide some additional resources on setting up your Motion Controllers and creating interactions in VR using Motion Controllers. -[REGION:topics third] -[OBJECT:TopicCompactVideo] + +[OBJECT:VideoSeriesLink] [PARAMLITERAL:title] - Setting Up Motion Controllers + Live Training - Setting Up VR Motion Controllers [/PARAMLITERAL] [PARAMLITERAL:videoid] 6ALnsdQnkVQ + [/PARAMLITERAL] + [PARAMLITERAL:playlist] + PLZlv_N0_O1gY7G589Z3I5-Dz7AdFSIWaG + [/PARAMLITERAL] + [PARAMLITERAL:duration] + 1:05:05 + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAMLITERAL:linktype] + block + [/PARAMLITERAL] + [PARAMLITERAL:thumbnail] + https://i.ytimg.com/vi/6ALnsdQnkVQ/maxresdefault.jpg [/PARAMLITERAL] [/OBJECT] -[OBJECT:TopicCompactVideo] + +[OBJECT:VideoSeriesLink] [PARAMLITERAL:title] - Creating Interactions in VR With Motion Controllers Part 1 + 01 - Blueprint Creating Interactions in VR with Motion Controllers [/PARAMLITERAL] [PARAMLITERAL:videoid] eRNtgFo6iU0 + [/PARAMLITERAL] + [PARAMLITERAL:playlist] + PLZlv_N0_O1gY7G589Z3I5-Dz7AdFSIWaG + [/PARAMLITERAL] + [PARAMLITERAL:duration] + 59:50 + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAMLITERAL:linktype] + block + [/PARAMLITERAL] + [PARAMLITERAL:thumbnail] + https://i.ytimg.com/vi/eRNtgFo6iU0/maxresdefault.jpg [/PARAMLITERAL] [/OBJECT] -[OBJECT:TopicCompactVideo] + +[OBJECT:VideoSeriesLink] [PARAMLITERAL:title] - Creating Interactions in VR With Motion Controllers Part 2 + 02 - Blueprint Creating Interactions in VR with Motion Controllers [/PARAMLITERAL] [PARAMLITERAL:videoid] utOahIZgKgc + [/PARAMLITERAL] + [PARAMLITERAL:playlist] + PLZlv_N0_O1gY7G589Z3I5-Dz7AdFSIWaG + [/PARAMLITERAL] + [PARAMLITERAL:duration] + 57:44 + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAMLITERAL:linktype] + block + [/PARAMLITERAL] + [PARAMLITERAL:thumbnail] + https://i.ytimg.com/vi/utOahIZgKgc/maxresdefault.jpg + [/PARAMLITERAL] +[/OBJECT] +[OBJECT:VideoSeriesLink] + [PARAMLITERAL:title] + 01 - Blueprint Creating Interactions in VR with Motion Controllers + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + fcmRGkpWefY + [/PARAMLITERAL] + [PARAMLITERAL:playlist] + PLZlv_N0_O1gY7G589Z3I5-Dz7AdFSIWaG + [/PARAMLITERAL] + [PARAMLITERAL:duration] + 48:20 + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAMLITERAL:linktype] + block + [/PARAMLITERAL] + [PARAMLITERAL:thumbnail] + https://i.ytimg.com/vi/fcmRGkpWefY/maxresdefault.jpg [/PARAMLITERAL] [/OBJECT] -[/REGION] +[region:blank] +[/region] diff --git a/Engine/Documentation/Source/Platforms/GoogleVR/Daydream/Daydream.JPN.udn b/Engine/Documentation/Source/Platforms/GoogleVR/Daydream/Daydream.JPN.udn index 1998de044ddb..b00739beaef5 100644 --- a/Engine/Documentation/Source/Platforms/GoogleVR/Daydream/Daydream.JPN.udn +++ b/Engine/Documentation/Source/Platforms/GoogleVR/Daydream/Daydream.JPN.udn @@ -1,65 +1,95 @@ -INTSourceChangelist:3275566 +INTSourceChangelist:3477690 Availability:Public Title:Google VR と Daydream デバイス Crumbs:%ROOT%, Platforms/GoogleVR -Description:Daydream デバイス特有の Google VR 機能 +Description:Daydream デバイス固有の Google VR 機能 Navigation:platform Skilllevel:Intermediate -Version:4.12 +Version:4.16 parent:Platforms/GoogleVR type:overview tags:VR tags:Google VR tags:Daydream +topic-image:Platforms\GoogleVR\GoogleVR_Topic_Image.png [TOC(start:2)] [region:note] -Google では、Daydream の使用方法を詳しく説明しているマニュアルを提供しています。[Offical Google Daydream Unreal](https://developers.google.com/vr/unreal/) のヘルプサイトをご覧ください。 +Google では、Daydream の詳しい使用方法を解説したマニュアルを提供しています。[Offical Google Daydream Unreal](https://developers.google.com/vr/unreal/) のヘルプサイトをご覧ください。 [/region] -Google VR はほとんどの Android ベースのデバイスで使用できますが、Daydream デバイスのみに有効な機能もいくつかあります。これらの機能とプロジェクトでの使用方法について、次のセクションで説明します。 +Google VR はほとんどの Android ベースのデバイスで使用できますが、Daydream デバイス固有の機能もいくつかあります。これらの機能およびプロジェクトでの使用方法について、次のセクションで説明します。 ## Google VR UE4 Branch をダウンロードする -Google Daydream VR が提供するすべてのビルド済み機能を取得するために、以下のリンクにある UE4 の特別バージョンをダウンロードおよびコンパイルする必要があります。このバージョンには、Google が好む方法で Daydream Motion Controller を表示するために必要なコードとアセットが含まれています。 +Google Daydream VR のビルド済み機能をすべて取得するためには、以下のリンクから UE4 の特別版をダウンロードしコンパイルする必要があります。この特別版には、Google 方式による Daydream Motion Controller の表示に必要なコードとアセットが含まれています。 -* [Google VR Github Pull](https://github.com/googlevr-unreal/UnrealEngine/tree/4.13-googlevr) +* [Google VR Github Pull](https://github.com/googlevr-unreal/UnrealEngine/releases) -このバージョンのダウンロードが完了したら、[Github からアンリアルをZipでダウンロードする方法](GettingStarted/DownloadingUnrealEngine/DownloadZip) の説明に従って、残りのセットアップを完了させます。 +ダウンロードが完了したら、[Github からアンリアルをZipでダウンロードする方法](GettingStarted/DownloadingUnrealEngine/DownloadZip) の説明に従って残りのセットアップを完了させます。 -## Android NDK 11c -Daydream の機能にフルアクセスするためには、Android NDK version 11c のダウンロードおよびインストールが必要となります。 +## Android NDK 12b +Daydream の機能へのフルアクセスには、Android NDK version 12b のダウンロードおよびインストールが必要となります。 -* [NDK 11c Downlaod](https://developer.android.com/ndk/downloads/index.html) +* [NDK 12b Downlaod](https://developer.android.com/ndk/downloads/older_releases.html) -ダウンロードおよびインストールが完了したら、**[Android SDK]** > **[SDKConfig]** セクションで NDK パスを NDK 11c のインストール先に変更し、SDK API level を **matchndk** に、NDK API Level を **android-24** にそれぞれ設定して、UE4 をNDK ファイルに指定する必要があります。 +ダウンロードおよびインストールが完了したら、**[Android SDK]** > **[SDKConfig]** セクションで NDK パスを NDK 12b のインストール先に変更して UE4 をNDK ファイルに指定し、SDK API level を **[matchndk]** に、NDK API Level を **[android-24]** にそれぞれ設定する必要があります。 -![](GDaydream_New_NDK_00.png) +[REGION:lightbox] +[![](GDaydream_New_NDK_00.png)(w:502)](GDaydream_New_NDK_00.png) +[/REGION] + +[REGION:caption] +クリックしてフルサイズで表示 +[/REGION] ## Scanline Racing -**Scanline Racing** は、VR プロジェクトでのレイテンシーを減らすことができる Daydream 固有の機能です。Daydream デバイス向け Google VR プロジェクトで Scanline Racing を有効にするには、以下の操作を行います。 +**Scanline Racing** は、VR プロジェクトでのレイテンシーを低減できる Daydream 固有の機能です。Daydream デバイス向け Google VR プロジェクトで Scanline Racing を有効にするには、以下の操作を行います。 -1. **[Project Settings (プロジェクト設定)]** の **[Platforms]** > **[Android]** を選択します。 +1. **[Project Settings (プロジェクト設定)]** の **[Platforms]** で **[Android]** を選択します。**[APKPackaging]** セクションで、以下の設定を行います。 - ![](GDaydream_Arm64_Support_00.png) + * Minimum SDK Version:**24** + * Target SDK Version:**24** -1. **[Build]** セクションの **[Support arm64[aka arm64-v8a]]** のチェックボックスにチェックを入れて有効にして、**Support arm7[aka armebi-v7a]** を無効にします。 + [REGION:lightbox] + [![](GDaydream_Arm64_Support_00.png)(w:502)](GDaydream_Arm64_Support_00.png) + [/REGION] - ![](Platforms\GoogleVR\QuickStart\2\GVRQS_Build_arm64_Support_00.png) + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. **[Build]** セクションで以下の設定を行います。 + * Support armv7(aka armeabi-v7a):**Disabled** + * Support arm64 (aka arm64-v8a):**Enabled** + + [REGION:lightbox] + [![](GDaydream_Build_Support.png)(w:502)](GDaydream_Build_Support.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] [region:note] - これを有効にすることで、arm64 ライブラリのコンパイルが必要な場合、最初のクックに大幅に時間が追加されます。 + これを有効にしておくと、arm64 ライブラリのコンパイルが必要な時に、初回クック時間が大幅に追加されます。 [/region] 1. 次に、**[Advanced APKPackaging]** セクションの以下のオプションを有効にします。 - * **[Configure for deployment to Daydream]** - * **[Configure GoogleVR Deployment Mode]** - * **[Configure GoogleVR for low-latency rendering mode (scanline racing)]** + * [Configure GoogleVR Deployment Mode]:**Daydream** + * [Configure GoogleVR for sustained-performance mode]:**Enabled** - ![](GDaydream_Scanline_Racing_Support_00.png) + [REGION:lightbox] + [![](GDaydream_Scanline_Racing_Support_00.png)(w:502)](GDaydream_Scanline_Racing_Support_00.png) + [/REGION] -そして UE プロジェクトをクックし、それを低レイテンシー レンダリング設定を有効にした Daydream デバイスにデプロイします。 + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + + +次回 UE プロジェクトをクックし、それを Daydream デバイスにデプロイする時に、低レイテンシー レンダリング設定が有効になります。 ## モーション コントローラー Daydream デバイス用モーション コントローラの操作は、HTC Vive や Oculus Rift のモーション コントローラーの操作とほぼ同じです。この機能を追加するには、以下の手順に従います。 @@ -70,7 +100,13 @@ UE4 で Google Daydream Controller のモーション コントローラーを 1. まず、プロジェクトの [Plugins] メニューを開き、[Input] セクションで **[Google VR Motion Controller]** を有効にします。 - ![](GDaydream_Plugins.png) + [REGION:lightbox] + [![](GDaydream_Plugins.png)(w:692)](GDaydream_Plugins.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] [region:note] プラグインを使用するためには、UE4 エディタを再起動する必要があります。再起動しないと、Google VR モーション コントローラーを使用することができません。 @@ -91,41 +127,114 @@ UE4 で Google Daydream Controller のモーション コントローラーを [/REGION] [region:note] - UE4 の 4.14 バイナリ ビルドを使用している場合、上のコンテンツはなくなるので、代わりに標準の Motion Controller コンポーネントを使用します。この機能のすべては、UE4 のリリース 4.15 に入る予定です。この機能がすぐに必要な場合、[UE4.13 Google VR version](https://github.com/googlevr-unreal/UnrealEngine/tree/4.13-googlevr) のダウンロードおよびコンパイルが必要になります。 + UE4 の 4.14 バイナリ ビルドを使用している場合、上のコンテンツはなくなるので、代わりに標準の Motion Controller コンポーネントを使用します。この機能のすべては、UE4 バージョン 4.15 以降のリリースに含まれます。この機能がすぐに必要な場合、[UE4.13 Google VR version](https://github.com/googlevr-unreal/UnrealEngine/tree/4.13-googlevr) のダウンロードおよびコンパイルが必要になります。 [/region] Google VR Motion Controller コンポーネントをポーンに設定したので、ブループリント エディタで **Google VR** を検索して見つけたノードを使用して、Motion Controller の機能の編集および調整をすることができます。 ## トレーニング ストリーム -これらのトレーニング ストリームでは、Motion Controller の設定、Motion Controller を使った VR でのインタラクション作成に関する追加リソースです。 +これらのトレーニング ストリームは、Motion Controller の設定、Motion Controller を使った VR でのインタラクション作成に関する追加リソースです。 -[REGION:topics third] -[OBJECT:TopicCompactVideo] +[PARAMLITERAL:width] +320 +[/PARAMLITERAL] +[PARAMLITERAL:height] +170 +[/PARAMLITERAL] +[PARAMLITERAL:units] +px +[/PARAMLITERAL] + + +[OBJECT:VideoSeriesLink] [PARAMLITERAL:title] - モーション コントローラーの設定 + ライブ トレーニング - モーション コントローラーの設定 [/PARAMLITERAL] [PARAMLITERAL:videoid] 6ALnsdQnkVQ + [/PARAMLITERAL] + [PARAMLITERAL:playlist] + PLZlv_N0_O1gY7G589Z3I5-Dz7AdFSIWaG + [/PARAMLITERAL] + [PARAMLITERAL:duration] + 1:05:05 + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAMLITERAL:linktype] + block + [/PARAMLITERAL] + [PARAMLITERAL:thumbnail] + https://i.ytimg.com/vi/6ALnsdQnkVQ/maxresdefault.jpg [/PARAMLITERAL] [/OBJECT] -[OBJECT:TopicCompactVideo] +[OBJECT:VideoSeriesLink] [PARAMLITERAL:title] - モーション コントローラーと VR のインタラクションの作成 (パート 1) + 01 - モーション コントローラーで VR でインタラクションを作成するブループリント [/PARAMLITERAL] [PARAMLITERAL:videoid] eRNtgFo6iU0 + [/PARAMLITERAL] + [PARAMLITERAL:playlist] + PLZlv_N0_O1gY7G589Z3I5-Dz7AdFSIWaG + [/PARAMLITERAL] + [PARAMLITERAL:duration] + 59:50 + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAMLITERAL:linktype] + block + [/PARAMLITERAL] + [PARAMLITERAL:thumbnail] + https://i.ytimg.com/vi/eRNtgFo6iU0/maxresdefault.jpg [/PARAMLITERAL] [/OBJECT] -[OBJECT:TopicCompactVideo] +[OBJECT:VideoSeriesLink] [PARAMLITERAL:title] - モーション コントローラーと VR のインタラクションの作成 (パート 2) + 02 - モーション コントローラーで VR でインタラクションを作成するブループリント [/PARAMLITERAL] [PARAMLITERAL:videoid] utOahIZgKgc + [/PARAMLITERAL] + [PARAMLITERAL:playlist] + PLZlv_N0_O1gY7G589Z3I5-Dz7AdFSIWaG + [/PARAMLITERAL] + [PARAMLITERAL:duration] + 57:44 + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAMLITERAL:linktype] + block + [/PARAMLITERAL] + [PARAMLITERAL:thumbnail] + https://i.ytimg.com/vi/utOahIZgKgc/maxresdefault.jpg + [/PARAMLITERAL] +[/OBJECT] +[OBJECT:VideoSeriesLink] + [PARAMLITERAL:title] + 01 - モーション コントローラーで VR でインタラクションを作成するブループリント + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + fcmRGkpWefY + [/PARAMLITERAL] + [PARAMLITERAL:playlist] + PLZlv_N0_O1gY7G589Z3I5-Dz7AdFSIWaG + [/PARAMLITERAL] + [PARAMLITERAL:duration] + 48:20 + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAMLITERAL:linktype] + block + [/PARAMLITERAL] + [PARAMLITERAL:thumbnail] + https://i.ytimg.com/vi/fcmRGkpWefY/maxresdefault.jpg [/PARAMLITERAL] [/OBJECT] -[/REGION] diff --git a/Engine/Documentation/Source/Platforms/GoogleVR/Daydream/Daydream.KOR.udn b/Engine/Documentation/Source/Platforms/GoogleVR/Daydream/Daydream.KOR.udn index 05dabf6ea58a..83cd7b7fd6ac 100644 --- a/Engine/Documentation/Source/Platforms/GoogleVR/Daydream/Daydream.KOR.udn +++ b/Engine/Documentation/Source/Platforms/GoogleVR/Daydream/Daydream.KOR.udn @@ -1,16 +1,17 @@ -INTSourceChangelist:3275566 +INTSourceChangelist:3477690 Availability:Public Title:구글 VR 과 데이드림 디바이스 Crumbs:%ROOT%, Platforms/GoogleVR Description:데이드림 디바이스 전용 구글 VR 기능입니다. Navigation:platform Skilllevel: Intermediate -Version: 4.12 +Version: 4.16 parent:Platforms/GoogleVR type:overview tags:VR tags:Google VR tags:Daydream +topic-image:Platforms\GoogleVR\GoogleVR_Topic_Image.png [TOC(start:2)] @@ -24,40 +25,69 @@ Google VR (구글 VR)이 대부분의 안드로이드 기반 디바이스와 호 ## Google VR UE4 브랜치 다운로드 Google Daydream VR 에서 미리 만들어 제공하는 기능을 전부 구하기 위해서는, 아래 링크에서 찾을 수 있는 UE4 특수 버전을 다운로드하고 컴파일해야 합니다. 이 버전의 UE4 에는 Daydream 모션 콘트롤러를 구글이 원하는 방식으로 표시하는 데 필요한 코드와 애셋이 들어있습니다. -* [Google VR Github Pull](https://github.com/googlevr-unreal/UnrealEngine/tree/4.13-googlevr) +* [Google VR Github Pull](https://github.com/googlevr-unreal/UnrealEngine/releases) 이 버전의 UE4 를 다운로드한 후, [](GettingStarted/DownloadingUnrealEngine/DownloadZip) 문서의 안내를 따라 나머지 구성 절차를 마무리합니다. -## 안드로이드 NDK 11c -Daydream 전체 기능에 접근하기 위해서는, 안드로이드 NDK 버전 11c 를 다운로드하여 설치해야 합니다. +## 안드로이드 NDK 12b +Daydream 전체 기능에 접근하기 위해서는, 안드로이드 NDK 버전 12b 를 다운로드하여 설치해야 합니다. -* [NDK 11c 다운로드](https://developer.android.com/ndk/downloads/index.html) +* [NDK 12b Downlaod](https://developer.android.com/ndk/downloads/older_releases.html) -다운로드와 설치가 끝나면 UE4 가 새로운 NDK 파일을 사용하도록 해 줘야 하는데, **Android SDK** > **SDKConfig** 섹션에서 NDK 경로를 새로 설치한 NDK 11c 경로로 바꿔주고 SDK API 레벨을 **matchndk** 로, NDK API 레벨을 **android-24** 로 설정합니다. +다운로드와 설치가 끝나면 UE4 가 새로운 NDK 파일을 사용하도록 해 줘야 하는데, **Android SDK** > **SDKConfig** 섹션에서 NDK 경로를 새로 설치한 NDK 12b 경로로 바꿔주고 SDK API 레벨을 **matchndk** 로, NDK API 레벨을 **android-24** 로 설정합니다. -![](GDaydream_New_NDK_00.png) +[REGION:lightbox] +[![](GDaydream_New_NDK_00.png)(w:502)](GDaydream_New_NDK_00.png) +[/REGION] + +[REGION:caption] +클릭하면 이미지 원본을 확인합니다. +[/REGION] ### 스캔라인 레이싱 Scanline Racing (스캔라인 레이싱)은 VR 프로젝트의 지연시간을 감소시켜 주는 데이드림 전용 기능입니다. 데이드림 디바이스용 구글 VR 프로젝트에서 스캔라인 레이싱 기능을 켜는 방법은 다음과 같습니다: -1. **프로젝트 세팅** 을 열고 **플랫폼** > **안드로이드** 로 갑니다. +1. **프로젝트 세팅** 을 열고 **플랫폼** > **안드로이드** 로 갑니다. **APKPackaging** 섹션 아래 다음과 같이 설정합니다: - ![](GDaydream_Arm64_Support_00.png) + * Minimum SDK Version: **24** + * Target SDK Version: **24** -1. **Build** (빌드) 섹션 아래 **Support arm64[aka arm64-v8a]** 이름 옆의 체크박스를 클릭하여 활성화시키고 **Support arm7[aka armebi-v7a]** 는 비활성화시킵니다. + [REGION:lightbox] + [![](GDaydream_Arm64_Support_00.png)(w:502)](GDaydream_Arm64_Support_00.png) + [/REGION] - ![](Platforms\GoogleVR\QuickStart\2\GVRQS_Build_arm64_Support_00.png) + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] + +1. **Build** 섹션 아래 다음을 변경합니다: + * Support armv7(aka armeabi-v7a): **Disabled** + * Support arm64 (aka arm64-v8a): **Enabled** + + [REGION:lightbox] + [![](GDaydream_Build_Support.png)(w:502)](GDaydream_Build_Support.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] [region:note] 이 옵션을 활성화시키면 첫 쿠킹시 arm64 라이브러리가 컴파일되므로 시간이 크게 증가합니다. [/region] -1. 그런 다음 **Advanced APKPackaging** 섹션에서 다음 옵션을 켜줍니다. - * **Configure for deployment to Daydream** - * **Configure GoogleVR Deployment Mode** - * **Configure GoogleVR for low-latency rendering mode (scanline racing)** +1. 그리고 **Advanced APKPackaging** 섹션 아래 다음 옵션을 켜줍니다. + * Configure GoogleVR Deployment Mode: **Daydream** + * Configure GoogleVR for sustained-performance mode (scanline racing): **Enabled** + + [REGION:lightbox] + [![](GDaydream_Scanline_Racing_Support_00.png)(w:502)](GDaydream_Scanline_Racing_Support_00.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] - ![](GDaydream_Scanline_Racing_Support_00.png) 다음 번 UE4 프로젝트를 쿠킹하고 데이드림 디바이스에 설치하면 지연시간이 낮은 렌더링이 가능해질 것입니다. @@ -70,7 +100,13 @@ UE4 에서의 Google Daydream 모션 콘트롤러 사용법 관련 심화 내용 1. 먼저, 프로젝트의 플러그인 메뉴를 열고 Input 섹션에서 **Google VR Motion Controller** 플러그인을 켭니다. - ![](GDaydream_Plugins.png) + [REGION:lightbox] + [![](GDaydream_Plugins.png)(w:692)](GDaydream_Plugins.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] [region:note] 참고로 플러그인을 사용하려면 UE4 에디터를 재시작해야 합니다. 그렇게 하지 않으면 Google VR 모션 콘트롤러를 사용할 수 없을 것입니다. @@ -84,14 +120,14 @@ UE4 에서의 Google Daydream 모션 콘트롤러 사용법 관련 심화 내용 Motion Controller 컴포넌트는 VR 카메라와 같은 위치 및 높이를 사용할 것입니다. [/region] -1. 이제 프로젝트를 실행시키면 모션 콘트롤러가 다음 그림과 같아 보일 것입니다. +1. 프로젝트를 실행시키면 모션 콘트롤러가 다음 그림과 같아 보일 것입니다. [REGION:lightbox] [![](unreal-controller-model.png)(w:724)](unreal-controller-model.png) [/REGION] [region:note] - UE4 4.14 바이너리 빌드를 사용중인 경우, 위 콘텐츠가 없어 표준 Motion Controller 컴포넌트를 대신 사용해야 할 것입니다. 이 기능 전부 UE4 4.15 버전에 들어갑니다. 지금 이 기능이 필요한 경우, [UE4.13 Google VR version](https://github.com/googlevr-unreal/UnrealEngine/tree/4.13-googlevr) 을 다운로드하여 컴파일해야 할 것입니다. + UE4 4.14 바이너리 빌드를 사용중인 경우, 위 콘텐츠가 없어 표준 Motion Controller 컴포넌트를 대신 사용해야 할 것입니다. 이 기능 전부 UE4 4.15 이후 버전에 포함되어 있습니다. 지금 이 기능이 필요한 경우, [UE4.13 Google VR version](https://github.com/googlevr-unreal/UnrealEngine/tree/4.13-googlevr) 을 다운로드하여 컴파일해야 할 것입니다. [/region] 폰에 Google VR Motion Controller 컴포넌트가 생겼으니, 이제 모션 콘트롤러의 작동 방식을 편집할 수 있습니다. 블루프린트 에디터에서 **Google VR** 을 검색하여 찾은 노드를 사용하면 됩니다. @@ -100,32 +136,105 @@ UE4 에서의 Google Daydream 모션 콘트롤러 사용법 관련 심화 내용 아래 교육 자료는 모션 콘트롤러 구성 및 활용을 통한 VR 에서의 상호작용 생성에 관련된 것입니다. -[REGION:topics third] -[OBJECT:TopicCompactVideo] +[PARAMLITERAL:width] +320 +[/PARAMLITERAL] +[PARAMLITERAL:height] +170 +[/PARAMLITERAL] +[PARAMLITERAL:units] +px +[/PARAMLITERAL] + + +[OBJECT:VideoSeriesLink] [PARAMLITERAL:title] - 모션 콘트롤러 구성 + 라이브 트레이닝 - VR 모션 컨트롤러 셋업 [/PARAMLITERAL] [PARAMLITERAL:videoid] 6ALnsdQnkVQ + [/PARAMLITERAL] + [PARAMLITERAL:playlist] + PLZlv_N0_O1gY7G589Z3I5-Dz7AdFSIWaG + [/PARAMLITERAL] + [PARAMLITERAL:duration] + 1:05:05 + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAMLITERAL:linktype] + block + [/PARAMLITERAL] + [PARAMLITERAL:thumbnail] + https://i.ytimg.com/vi/6ALnsdQnkVQ/maxresdefault.jpg [/PARAMLITERAL] [/OBJECT] -[OBJECT:TopicCompactVideo] +[OBJECT:VideoSeriesLink] [PARAMLITERAL:title] - 모션 콘트롤러를 활용한 VR 상호작용 제작 - 1 부 + 01 - 모션 컨트롤러로 VR 에서 인터랙션 생성 블루프린트 [/PARAMLITERAL] [PARAMLITERAL:videoid] eRNtgFo6iU0 + [/PARAMLITERAL] + [PARAMLITERAL:playlist] + PLZlv_N0_O1gY7G589Z3I5-Dz7AdFSIWaG + [/PARAMLITERAL] + [PARAMLITERAL:duration] + 59:50 + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAMLITERAL:linktype] + block + [/PARAMLITERAL] + [PARAMLITERAL:thumbnail] + https://i.ytimg.com/vi/eRNtgFo6iU0/maxresdefault.jpg [/PARAMLITERAL] [/OBJECT] -[OBJECT:TopicCompactVideo] +[OBJECT:VideoSeriesLink] [PARAMLITERAL:title] - 모션 콘트롤러를 활용한 VR 상호작용 제작 - 2 부 + 02 - 모션 컨트롤러로 VR 에서 인터랙션 생성 블루프린트 [/PARAMLITERAL] [PARAMLITERAL:videoid] utOahIZgKgc + [/PARAMLITERAL] + [PARAMLITERAL:playlist] + PLZlv_N0_O1gY7G589Z3I5-Dz7AdFSIWaG + [/PARAMLITERAL] + [PARAMLITERAL:duration] + 57:44 + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAMLITERAL:linktype] + block + [/PARAMLITERAL] + [PARAMLITERAL:thumbnail] + https://i.ytimg.com/vi/utOahIZgKgc/maxresdefault.jpg + [/PARAMLITERAL] +[/OBJECT] +[OBJECT:VideoSeriesLink] + [PARAMLITERAL:title] + 01 - Blueprint Creating Interactions in VR with Motion Controllers + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + fcmRGkpWefY + [/PARAMLITERAL] + [PARAMLITERAL:playlist] + PLZlv_N0_O1gY7G589Z3I5-Dz7AdFSIWaG + [/PARAMLITERAL] + [PARAMLITERAL:duration] + 48:20 + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAMLITERAL:linktype] + block + [/PARAMLITERAL] + [PARAMLITERAL:thumbnail] + https://i.ytimg.com/vi/fcmRGkpWefY/maxresdefault.jpg [/PARAMLITERAL] [/OBJECT] -[/REGION] diff --git a/Engine/Documentation/Source/Platforms/GoogleVR/GoogleVR.INT.udn b/Engine/Documentation/Source/Platforms/GoogleVR/GoogleVR.INT.udn index c155ec3d3327..82ba815350a9 100644 --- a/Engine/Documentation/Source/Platforms/GoogleVR/GoogleVR.INT.udn +++ b/Engine/Documentation/Source/Platforms/GoogleVR/GoogleVR.INT.udn @@ -12,6 +12,9 @@ tags:Google VR tags:Platform prereq: Platforms/Android/GettingStarted/ social-image:googlevr_social.png +topic-image:GoogleVR_Topic_Image.png + +![](googlevr_social.png) [region:note] Google has a provided a very detailed document that goes over everything you need to know to get the most out of Daydream. You can find the documents by going to the [Offical Google Daydream Unreal](https://developers.google.com/vr/unreal/) help site. @@ -21,13 +24,13 @@ Google has a provided a very detailed document that goes over everything you nee The GoogleVR Quick Start will walk you through getting your PC and Android-based smartphone to work with UE4 and Google VR. -[DIR(output:"listbutton" type:"quick start" parent:"Platforms/GoogleVR")] +[DIR(output:"topic" type:"quick start" parent:"Platforms/GoogleVR")] ## Google VR Daydream -Daydream is a part of Google VR that adds specific support for rendering optimizations and the use of Motion Controllers. - -[DIR(output:"listbutton" type:"overview" parent:"Platforms/GoogleVR")] +Google Daydream allows you to enable certain rendering optimizations and use Motion Controllers when targeting Daydream devices through the Google VR SDK. +[DIR(output:"topic" type:"overview" parent:"Platforms/GoogleVR")] + \ No newline at end of file diff --git a/Engine/Documentation/Source/Platforms/GoogleVR/GoogleVR.JPN.udn b/Engine/Documentation/Source/Platforms/GoogleVR/GoogleVR.JPN.udn index 7a95aafcca61..4d86a9cb332a 100644 --- a/Engine/Documentation/Source/Platforms/GoogleVR/GoogleVR.JPN.udn +++ b/Engine/Documentation/Source/Platforms/GoogleVR/GoogleVR.JPN.udn @@ -1,5 +1,5 @@ -INTSourceChangelist:3275566 -Title:Google VR 開発 +INTSourceChangelist:3432707 +Title:Google VR の開発 Crumbs:%ROOT%, Platforms Description: Availability:Public @@ -13,6 +13,9 @@ tags:Google VR tags:Platform prereq:Platforms/Android/GettingStarted/ social-image:googlevr_social.png +topic-image:GoogleVR_Topic_Image.png + +![](googlevr_social.png) [region:note] Google では、Daydream の使用方法を詳しく説明しているマニュアルを提供しています。[Offical Google Daydream Unreal](https://developers.google.com/vr/unreal/) のヘルプサイトをご覧ください。 @@ -20,15 +23,15 @@ Google では、Daydream の使用方法を詳しく説明しているマニュ ## はじめよう -PC および Android ベースのスマートフォンを使って UE4 と Google VR を使う方法を説明します。 +GoogleVR クイックスタートでは、PC および Android ベースのスマートフォンでの UE4 および Google VR の使用方法を説明します。 -[DIR(output:"listbutton" type:"quick start" parent:"Platforms/GoogleVR")] +[DIR(output:"topic" type:"quick start" parent:"Platforms/GoogleVR")] ## Google VR Daydream -Daydream は、レンダリングの最適化とモーション コントロールの使用に特別に対応した Google VR の一部です。 - -[DIR(output:"listbutton" type:"overview" parent:"Platforms/GoogleVR")] +Daydream はレンダリングの最適化とモーション コントロールの使用に対応するために Google VR に追加されました。 +[DIR(output:"topic" type:"overview" parent:"Platforms/GoogleVR")] + \ No newline at end of file diff --git a/Engine/Documentation/Source/Platforms/GoogleVR/GoogleVR.KOR.udn b/Engine/Documentation/Source/Platforms/GoogleVR/GoogleVR.KOR.udn index f6012ec3073f..48b7e8688df5 100644 --- a/Engine/Documentation/Source/Platforms/GoogleVR/GoogleVR.KOR.udn +++ b/Engine/Documentation/Source/Platforms/GoogleVR/GoogleVR.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3275566 +INTSourceChangelist:3432707 Title:구글 VR 개발 Crumbs:%ROOT%, Platforms Description: @@ -13,6 +13,9 @@ tags:Google VR tags:Platform prereq: Platforms/Android/GettingStarted/ social-image:googlevr_social.png +topic-image:GoogleVR_Topic_Image.png + +![](googlevr_social.png) [region:note] Google 에서는 Daydream 을 최대한 활용하기 위해 알아야하는 것들이 총망라된 매우 자세한 문서를 제공하고 있습니다. [공식 Google Daydream Unreal](https://developers.google.com/vr/unreal/) 도움말 사이트에서 문서를 찾아보실 수 있습니다. @@ -22,13 +25,13 @@ Google 에서는 Daydream 을 최대한 활용하기 위해 알아야하는 것 GoogleVR 퀵스타트는 PC 와 안드로이드 기반 스마트폰에서 UE4 와 Google VR (구글 VR) 이 작동하도록 하기 위한 준비작업을 안내해 드립니다. -[DIR(output:"listbutton" type:"quick start" parent:"Platforms/GoogleVR")] +[DIR(output:"topic" type:"quick start" parent:"Platforms/GoogleVR")] ## 구글 VR 데이드림 Daydream (데이드림)은 구글 VR 의 일부로, 몇 가지 렌더링 최적화 기능 및 모션 콘트롤러 사용을 지원합니다. -[DIR(output:"listbutton" type:"overview" parent:"Platforms/GoogleVR")] - +[DIR(output:"topic" type:"overview" parent:"Platforms/GoogleVR")] + \ No newline at end of file diff --git a/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/1/GoogleVRQuickStart_1.INT.udn b/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/1/GoogleVRQuickStart_1.INT.udn index f421df8a5ac0..fe9f15330ff1 100644 --- a/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/1/GoogleVRQuickStart_1.INT.udn +++ b/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/1/GoogleVRQuickStart_1.INT.udn @@ -4,7 +4,7 @@ Crumbs:%ROOT%, Platforms/GoogleVR Description:Creating a UE4 project that can be used with Google VR. Navigation:platform Skilllevel: Intermediate -Version: 4.12 +Version: 4.16 Parent:Platforms/GoogleVR/QuickStart order:1 type:multi-step @@ -21,15 +21,33 @@ Google has a provided a very detailed document that goes over everything you nee 1. From the UE4 Launcher make sure that you have UE4 version **4.12** or later downloaded and installed then press the **Launch** button to open the **Unreal Project Browser**. - ![](GVRQS_Launcher_00.png) + [REGION:lightbox] + [![](GVRQS_Launcher_00.png)(w:682)](GVRQS_Launcher_00.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] 1. In the Unreal Project Browser, go to the **New Project** section and select the **Blueprint** base project option. - ![](GVRQS_New_Project_Options_00.png) + [REGION:lightbox] + [![](GVRQS_New_Project_Options_00.png)(w:555)](GVRQS_New_Project_Options_00.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] 1. Due to the demanding rendering requirements of VR in general, it is best to start out any new UE4 VR project with the following settings to ensure that your project will run at the correct frame rate right from the start. - ![](GVRQS_New_Project_Options_01.png) + [REGION:lightbox] + [![](GVRQS_New_Project_Options_01.png)(w:555)](GVRQS_New_Project_Options_01.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] * **Blank Project** * **Mobile / Tablet** * **Scalable 3D / 2D** @@ -37,13 +55,25 @@ Google has a provided a very detailed document that goes over everything you nee 1. Set the location where the project will be created and also give the project a name. - ![](GVRQS_New_Project_Options_02.png) + [REGION:lightbox] + [![](GVRQS_New_Project_Options_02.png)(w:555)](GVRQS_New_Project_Options_02.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] * For this example the project name will be **GVR_QS**. 1. Finally, press the **Create Project** button that is located in the lower right-hand corner to create the project. - ![](GVRQS_New_Project_Options_03.png) + [REGION:lightbox] + [![](GVRQS_New_Project_Options_03.png)(w:555)](GVRQS_New_Project_Options_03.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] In the next section of the Google VR Quick Start, we will go over all the needed project settings to ensure that your UE4 project will work with Google VR. diff --git a/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/1/GoogleVRQuickStart_1.JPN.udn b/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/1/GoogleVRQuickStart_1.JPN.udn index dae2f4c5cea2..2ee30294fec8 100644 --- a/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/1/GoogleVRQuickStart_1.JPN.udn +++ b/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/1/GoogleVRQuickStart_1.JPN.udn @@ -1,11 +1,11 @@ -INTSourceChangelist:3275566 +INTSourceChangelist:3451711 Availability:Public -Title:1.Google VR プロジェクトを作成する +Title:1.Google VR プロジェクトの作成方法 Crumbs:%ROOT%, Platforms/GoogleVR Description:Google VR 向け UE4 プロジェクトの作成 Navigation:platform Skilllevel:Intermediate -Version:4.12 +Version:4.16 Parent:Platforms/GoogleVR/QuickStart order:1 type:multi-step @@ -15,22 +15,40 @@ tags:Google VR [NAV] [region:note] -Google のマニュアルで、Daydream の使用方法が詳しく説明されています。[Offical Google Daydream Unreal](https://developers.google.com/vr/unreal/) のヘルプサイトをご覧ください。 +Google のマニュアルに Daydream の使用方法に関する詳細な説明があります。[Offical Google Daydream Unreal](https://developers.google.com/vr/unreal/) のヘルプサイトをご覧ください。 [/region] - このセクションでは、Google VR 開発に最も適した設定で新規に UE4 プロジェクトを作成する方法を説明します。 + このセクションでは、Google VR 開発に最も適した設定で UE4 プロジェクトを新規作成する方法を説明します。 -1. UE ランチャーから UE4 のバージョン **4.12** 以上がダウンロードおよびインストールされていることを確認して、**[Launch]** ボタンを押して **[Unreal Project Browser]** を開きます。 +1. UE ランチャーから UE4 のバージョン **4.12** 以降がダウンロードおよびインストールされていることを確認して、**[Launch]** ボタンを押して **[Unreal Project Browser]** を開きます。 - ![](GVRQS_Launcher_00.png) + [REGION:lightbox] + [![](GVRQS_Launcher_00.png)(w:682)](GVRQS_Launcher_00.png) + [/REGION] -1. [Unreal Project Browser] の **[New Project]** セクションから **[Blueprint]**ベース プロジェクト オプションを選択します。 + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] - ![](GVRQS_New_Project_Options_00.png) +1. [Unreal Project Browser] の **[New Project]** セクションから **[Blueprint]** ベース プロジェクト オプションを選択します。 + + [REGION:lightbox] + [![](GVRQS_New_Project_Options_00.png)(w:555)](GVRQS_New_Project_Options_00.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] 1. 一般的に VR のレンダリング要件は厳しいので、プロジェクトが最初から正しいフレームレートで動作するように、新規の UE4 プロジェクトには以下の設定をお勧めします。 - ![](GVRQS_New_Project_Options_01.png) + [REGION:lightbox] + [![](GVRQS_New_Project_Options_01.png)(w:555)](GVRQS_New_Project_Options_01.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] * **Blank プロジェクト** * **Mobile / Tablet** * **Scalable 3D / 2D** @@ -38,13 +56,25 @@ Google のマニュアルで、Daydream の使用方法が詳しく説明され 1. プロジェクトの作成先を設定し、プロジェクト名を付けます。 - ![](GVRQS_New_Project_Options_02.png) + [REGION:lightbox] + [![](GVRQS_New_Project_Options_02.png)(w:555)](GVRQS_New_Project_Options_02.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] * この例ではプロジェクトに **「GVR_QS」** という名前を付けます。 1. 最後に、右下隅にある **[Create Project (プロジェクトを作成)]** ボタンを押してプロジェクトを作成します。 - ![](GVRQS_New_Project_Options_03.png) + [REGION:lightbox] + [![](GVRQS_New_Project_Options_03.png)(w:555)](GVRQS_New_Project_Options_03.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] 次のセクションでは、UE4 プロジェクトが Google VR で確実に動くようにプロジェクト設定を行います。 diff --git a/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/1/GoogleVRQuickStart_1.KOR.udn b/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/1/GoogleVRQuickStart_1.KOR.udn index 105325d5abf0..93ef96290eab 100644 --- a/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/1/GoogleVRQuickStart_1.KOR.udn +++ b/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/1/GoogleVRQuickStart_1.KOR.udn @@ -1,11 +1,11 @@ -INTSourceChangelist:3275566 +INTSourceChangelist:3451711 Availability:Public Title:1. 구글 VR 프로젝트 생성 Crumbs:%ROOT%, Platforms/GoogleVR Description:구글 VR 작업이 가능한 UE4 프로젝트를 생성합니다. Navigation:platform Skilllevel: Intermediate -Version: 4.12 +Version: 4.16 Parent:Platforms/GoogleVR/QuickStart order:1 type:multi-step @@ -22,15 +22,33 @@ Google 에서는 Daydream 을 최대한 활용하기 위해 알아야하는 것 1. UE4 런처에서 UE4 버전이 **4.12** 이상인지 확인, 아니면 내려받은 뒤 설치하고, **실행** 버튼을 눌러 **언리얼 프로젝트 브라우저** 를 엽니다. - ![](GVRQS_Launcher_00.png) + [REGION:lightbox] + [![](GVRQS_Launcher_00.png)(w:682)](GVRQS_Launcher_00.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] 1. 언리얼 프로젝트 브라우저에서, **새 프로젝트** 섹션으로 가 **블루프린트** 기반 프로젝트 옵션을 선택합니다. - ![](GVRQS_New_Project_Options_00.png) + [REGION:lightbox] + [![](GVRQS_New_Project_Options_00.png)(w:555)](GVRQS_New_Project_Options_00.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] 1. 일반적으로 VR 의 렌더링 요구사양이 높기에, 처음부터 적당한 프레임 속도를 보장하기 위해서는 다음과 같은 세팅으로 UE4 VR 프로젝트를 생성하는 것이 좋습니다. - ![](GVRQS_New_Project_Options_01.png) + [REGION:lightbox] + [![](GVRQS_New_Project_Options_01.png)(w:555)](GVRQS_New_Project_Options_01.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] * **공백 프로젝트** * **모바일 / 타블렛** * **스케일가능 3D / 2D** @@ -38,13 +56,25 @@ Google 에서는 Daydream 을 최대한 활용하기 위해 알아야하는 것 1. 프로젝트 생성 위치를 설정하고 프로젝트에 이름도 지어줍니다. - ![](GVRQS_New_Project_Options_02.png) + [REGION:lightbox] + [![](GVRQS_New_Project_Options_02.png)(w:555)](GVRQS_New_Project_Options_02.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] * 이 예제에서 프로젝트 이름은 **GVR_QS** 입니다. 1. 마지막으로 우하단 구석의 **프로젝트 생성** 버튼을 눌러 프로젝트를 생성합니다. - ![](GVRQS_New_Project_Options_03.png) + [REGION:lightbox] + [![](GVRQS_New_Project_Options_03.png)(w:555)](GVRQS_New_Project_Options_03.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] 구글 VR 퀵 스타트 다음 회에서는 UE4 프로젝트가 구글 VR 과 정상 작동하도록 하는 데 필요한 프로젝트 세팅을 전부 살펴보도록 하겠습니다. diff --git a/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/2/GoogleVRQuickStart_2.INT.udn b/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/2/GoogleVRQuickStart_2.INT.udn index 3d2210c18c84..59f785926c20 100644 --- a/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/2/GoogleVRQuickStart_2.INT.udn +++ b/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/2/GoogleVRQuickStart_2.INT.udn @@ -4,7 +4,7 @@ Crumbs:%ROOT%, Platforms/GoogleVR Description:Setting up a UE4 project to work with Google VR. Navigation:platform Skilllevel: Intermediate -Version: 4.12 +Version: 4.16 Parent:Platforms/GoogleVR/QuickStart order:2 type:multi-step @@ -25,7 +25,13 @@ Google has a provided a very detailed document that goes over everything you nee 1. Inside of the Plugins menu, go the **Virtual Reality** section and make sure that **Google VR** is enabled. - ![](GVRQS_Pligin_GVR_Enabled_00.png) + [REGION:lightbox] + [![](GVRQS_Pligin_GVR_Enabled_00.png)(w:500)](GVRQS_Pligin_GVR_Enabled_00.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] [region:note] The Google VR plugin should be enabled by default. If it is not enabled, it can be enabled by clicking on the checkmark box next to **Enabled**. When you do this will be prompted to restart the UE4 Editor so that the changes can take place. Failing to re-start the UE4 editor after enabling the Google VR plugin could result in the plugin not working correctly. @@ -62,21 +68,32 @@ Google has a provided a very detailed document that goes over everything you nee 1. Under the **Input** section in the **Mobile** category, remove the **DefaultVirtualJoysticks** from the **Default Touch Interface** by clicking on the small white triangle next to the DefaultVirtualJoysticks and selecting the **Clear** option from the drop-down list. - [OBJECT:EmbeddedVideo] - [PARAMLITERAL:width] - 640 - [/PARAMLITERAL] - [PARAMLITERAL:height] - 360 - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - -Ylbi1TCKZs - [/PARAMLITERAL] - [/OBJECT] + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + -Ylbi1TCKZs + [/PARAMLITERAL] + [PARAMLITERAL:width] + 50 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] -1. In the **Platforms** section under the **Android** section press the **Configure Now** button in the **APKPackaging** and **Google Play Services** sections to ensure that our project can package properly. +1. In the **Platforms** section under the **Android** section press the **Configure Now** button in the **APKPackaging** and **Google Play Services** sections to ensure that our project can package correctly. - ![](GVRQS_Config_Now_00.png) + [REGION:lightbox] + [![](GVRQS_Config_Now_00.png)(w:500)](GVRQS_Config_Now_00.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] 1. In the **APKPackaging** section make sure you have the following options set: @@ -84,29 +101,50 @@ Google has a provided a very detailed document that goes over everything you nee * **Disable verify OBB on first start/update:** Checked * **Enable FullScreen Immersive on KitKat and above devices:** Checked - ![](GVRQS_SDK_Version_00.png) + [REGION:lightbox] + [![](GVRQS_SDK_Version_00.png)(w:500)](GVRQS_SDK_Version_00.png) + [/REGION] -1. Locate the **Build** section and uncheck the **Support armv7 [aka armeabi-v7a]** option and make sure that both **Support arm64[aka arm64-v8a]** and **Support OpenGL ES2** are checked. + [REGION:caption] + Click for full image. + [/REGION] - ![](GVRQS_Build_arm64_Support_00.png) +1. Locate the **Build** section set the following: + + * **Support armv7 (aka armeabi-v7a):** Disabled + * **Support arm64 (aka arm64-v8a):** Enabled + * **Support OpenGL ES2:** Enabled + + [REGION:lightbox] + [![](GVRQS_Build_arm64_Support_00.png)(w:500)](GVRQS_Build_arm64_Support_00.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] 1. Next, in the **Advanced APKPackaging** section and enable the following options: - * **Configure for deployment to Daydream:** Checked * **Configure GoogleVR Deployment Mode:** Daydream & Cardboard - * **Configure GoogleVR for sustained performance mode:** Checked + * **Configure GoogleVR for sustained-performance mode:** Checked - ![](GVRQS_GoogleVR_Options_00.png) + [REGION:lightbox] + [![](GVRQS_GoogleVR_Options_00.png)(w:500)](GVRQS_GoogleVR_Options_00.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] [region:note] - The Configure GoogleVR Deployment Mode has several options that when selected will do that following. + The Configure GoogleVR Deployment Mode has several options that when selected will do the following: * **Cardboard:** Configure GoogleVR to run in Cardboard-only mode. * **Daydream:** Configure GoogleVR to run in Daydream-only mode. In this mode, the app won't be able to run on NonDaydream-ready phones. * **Daydream & Cardboard:** Configure GoogleVR to run in Daydream mode on Daydream-ready phones and fallback to Cardboard mode on NonDaydream-ready phones. [/region] -1. In the **Android SDK** section under the **SDKConfig** section set both the **SDK API Level** and **NDK API Level** to **android-24** instead of their defaults to ensure that your project will be compiled against the most recent Android SDK. +1. In the **Android SDK** section under the **SDKConfig** section set the **SDK API Level** to **matchndk**. Then set the **NDK API Level** to **android-24** to ensure that your project will be compiled against the most recent Android SDK. ![](GVRQS_Android_SDK_Options_00.png) @@ -118,6 +156,6 @@ Google has a provided a very detailed document that goes over everything you nee [/region] -In the next section of the Google VR Quick Start, we will go over what you have to do to package your UE4 project, so it will run on a Google VR device. +In the next section of the Google VR Quick Start, we will go over what you have to do to package your UE4 project so that it will run on a Google VR device. [NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/2/GoogleVRQuickStart_2.JPN.udn b/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/2/GoogleVRQuickStart_2.JPN.udn index f702b6ebdbac..337588e182d7 100644 --- a/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/2/GoogleVRQuickStart_2.JPN.udn +++ b/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/2/GoogleVRQuickStart_2.JPN.udn @@ -1,11 +1,11 @@ -INTSourceChangelist:3275566 +INTSourceChangelist:3477690 Availability:Public -Title:2.Google VR プロジェクトを設定する +Title:2.Google VR プロジェクトの設定 Crumbs:%ROOT%, Platforms/GoogleVR -Description:Google VR で使う UE4 プロジェクトの設定方法 +Description:UE4 プロジェクトを Google VR 向けにセットアップする Navigation:platform Skilllevel:Intermediate -Version:4.12 +Version:4.16 Parent:Platforms/GoogleVR/QuickStart order:2 type:multi-step @@ -15,21 +15,27 @@ tags:Google VR [NAV] [region:note] -Google のマニュアルで、Daydream の使用方法が詳しく説明されています。[Offical Google Daydream Unreal](https://developers.google.com/vr/unreal/) のヘルプサイトをご覧ください。 +Google のマニュアルに Daydream の使用方法に関する詳細な説明があります。[Google Daydream Unreal 公式サイト](https://developers.google.com/vr/unreal/) のヘルプをご覧ください。 [/region] - このセクションでは、UE4 プロジェクトを Google VR で使用するためのセットアップを行います。 + このセクションでは、UE4 プロジェクトを Google VR 向けにセットアップします。 -1. UE4 エディタをロードしたら、**メインツールバー** から **[Edit (編集)]** タブを開いて、**Plugins** メニュー アイテムを選択します。 +1. UE4 エディタをロードしたら、**メイン ツールバー** から **[Edit (編集)]** タブを開き **[Plugins]** メニュー アイテムを選択します。 ![](GVRQS_Pligin_Menu_00.png) 1. [Plugins] メニューから **[Virtual Reality]** セクションを開いて、**[Google VR]** が有効にされていることを確認します。 - ![](GVRQS_Pligin_GVR_Enabled_00.png) + [REGION:lightbox] + [![](GVRQS_Pligin_GVR_Enabled_00.png)(w:500)](GVRQS_Pligin_GVR_Enabled_00.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] [region:note] - Google VR プラグインはデフォルトで有効にされています。有効になっていない場合は、**[Enabled (有効にする)]** の横のチェックボックスをクリックすれば有効になります。この変更を反映するために、UE4 エディタを再起動のプロンプトが表示されます。Google VR プラグインを有効にした場合、UE4 エディタを再起動しないと、プラグインが正常に動作しません。 + Google VR プラグインはデフォルトで有効にされています。有効にするには、**[Enabled (有効にする)]** の横のチェックボックスをクリックします。この変更を反映するために、UE4 エディタを再起動のプロンプトが表示されます。Google VR プラグインを有効にした場合、UE4 エディタを再起動しないとプラグインが正常に動作しません。 [/region] 1. メインツールバーから **[File]** オプションを選択して **[Save (保存する)]** オプションをクリックして **[Save Level As (名前をつけて保存)]** ウィンドウを表示します。 @@ -44,7 +50,7 @@ Google のマニュアルで、Daydream の使用方法が詳しく説明され ![](GVRQS_Project_Settings_00.png) -1. [Project Settings (プロジェクト設定)] メニューから **[Maps & Modes]** セクションの **[Default Maps]** セクションを開いて、**[Editor Startup Map]** と **[Game Default Map]** を EntryLevel map に変更して、プロジェクトが起動すると EntryLevel map が確実にロードされるようにします。 +1. [Project Settings (プロジェクト設定)] メニューから **[Maps & Modes]** セクションの **[Default Maps]** セクションを開いて、**[Editor Startup Map]** と **[Game Default Map]** を EntryLevel map に変更して、プロジェクトが起動すると必ず EntryLevel map がロードされるようにします。 ![](GVRQS_Select_Level_00.png) @@ -53,31 +59,44 @@ Google のマニュアルで、Daydream の使用方法が詳しく説明され ![](GVRQS_Target_Hardware_00.png) [region:note] - **[Pending Changes (変更を保留)]** セクションの下に **[Restart Editor (エディタを再起動)]** ボタンが表示されていたら押して、変更箇所が反映されるようにエディタを再起動します。再起動しないと、プロジェクトで Google VR が動きません。 + 変更を反映するために **[Pending Changes (変更を保留)]** セクションの下に表示される **[Restart Editor (エディタを再起動)]** ボタンを必ず押してエディタを再起動してください。 + 再起動しないと、プロジェクトで Google VR が動きません。 ![](GVRQS_Target_Hardware_01.png) [/region] -1. ステレオスコピック レンダリングを正常に行うためには **[Rendering (レンダリング)]** セクションの **[Mobile HDR]** が無効になっていなければならないので、それを確認します。 +1. ステレオスコピック レンダリングを正常に行うために **[Rendering (レンダリング)]** セクションの **[Mobile HDR]** が無効になっていることを確認します。 ![](GVRQS_Moile_HDR_Off_00.png) -1. **[Input (入力)]** セクションの **[Mobile]** カテゴリで、DefaultVirtualJoysticks の横の小さな白い三角をクリックし、トップダウン リストから **[Clear]** オプションを選択して、**Default Touch Interface** から **Default Touch Interface** を削除します。 +1. **[Input (入力)]** セクションの **[Mobile]** カテゴリで、DefaultVirtualJoysticks の横の小さな白い三角をクリックし、トップダウン リストから **[Clear]** オプションを選択して、**[Default Touch Interface]** から **[Default Touch Interface]** を削除します。 - [OBJECT:EmbeddedVideo] - [PARAMLITERAL:width] - 640 - [/PARAMLITERAL] - [PARAMLITERAL:height] - 360 - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - -Ylbi1TCKZs - [/PARAMLITERAL] - [/OBJECT] + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + -Ylbi1TCKZs + [/PARAMLITERAL] + [PARAMLITERAL:width] + 50 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] + [/OBJECT] -1. **[Platforms]** > **[Android]** セクションの **[APKPackaging]** と **[Google Play Services]** セクションの中にある **[Configure Now (今すぐ設定する)]** ボタンを押して、プロジェクトを正しくパッケージ化されるようにします。 +1. プロジェクトが正しくパッケージ化されるように、**[Platforms]** > **[Android]** セクションの **[APKPackaging]** と **[Google Play Services]** セクションの中にある **[Configure Now (今すぐ設定する)]** ボタンを押します。 - ![](GVRQS_Config_Now_00.png) + [REGION:lightbox] + [![](GVRQS_Config_Now_00.png)(w:500)](GVRQS_Config_Now_00.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] 1. **[APKPackaging]** セクションのオプションを以下の設定にしてください。 @@ -85,29 +104,50 @@ Google のマニュアルで、Daydream の使用方法が詳しく説明され * **[Disable verify OBB on first start/update]:** チェックを入れる * **[Enable FullScreen Immersive on KitKat and above devices]:** チェックを入れる - ![](GVRQS_SDK_Version_00.png) + [REGION:lightbox] + [![](GVRQS_SDK_Version_00.png)(w:500)](GVRQS_SDK_Version_00.png) + [/REGION] -1. **[Build]** セクションの **Support armv7 [aka armeabi-v7a]** オプションのチェックを外し、**[Support arm64[aka arm64-v8a]]** と **[Support OpenGL ES2]** に両方ともチェックを入れます。 + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] - ![](GVRQS_Build_arm64_Support_00.png) +1. **[Build]** セクションを以下のように設定します。 + + * **Support armv7 (aka armeabi-v7a):* ** Disabled + * **Support arm64 (aka arm64-v8a):** Enabled + * **Support OpenGL ES2:** Enabled + + [REGION:lightbox] + [![](GVRQS_Build_arm64_Support_00.png)(w:500)](GVRQS_Build_arm64_Support_00.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] 1. **[Advanced APKPackaging]** セクションの以下のオプションを有効にします。 - * **[Configure for deployment to Daydream]:** チェックを入れる * **[Configure GoogleVR Deployment Mode]:** Daydream & Cardboard - * **[Configure GoogleVR for sustained performance mode]:** チェックを入れる + * **Configure GoogleVR for sustained-performance mode:** チェックを入れる - ![](GVRQS_GoogleVR_Options_00.png) + [REGION:lightbox] + [![](GVRQS_GoogleVR_Options_00.png)(w:500)](GVRQS_GoogleVR_Options_00.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] [region:note] - [Configure GoogleVR Deployment Mode] にには以下のような機能をもつオプションがあります。 + [Configure GoogleVR Deployment Mode] には以下の機能がオプションで使えます。 * **[Cardboard]:** GoogleVR を Cardboard-only モードで実行します。 * **[Daydream]:** GoogleVR を Daydream-only モードで実行します。このモードの場合、アプリケーションは Daydream 非対応のスマートフォンでは動作しません。 * **[Daydream & Cardboard]:** Daydream 対応のスマートフォンで GoogleVR を Daydream モードで実行し、Daydream 非対応のスマートフォンでは Cardboard モードにフォールバックします。 [/region] -1. **[Android SDK]** セクションの **[SDKConfig]** セクションで、**[SDK API Level]** および **[NDK API Level]** をデフォルトではなく **[android-24]** にして、プロジェクトが最新の Android SDK に対して確実にコンパイルされるようにします。 +1. **[Android SDK]** セクションの **[SDKConfig]** セクションで、**[NDK API Level]** を **[matchndk]** に設定します。次に **[NDK API Level]** を **[android-24]** にして、プロジェクトが最新の Android SDK に対して確実にコンパイルされるようにします。 ![](GVRQS_Android_SDK_Options_00.png) @@ -119,7 +159,6 @@ Google のマニュアルで、Daydream の使用方法が詳しく説明され [/region] - 次のセクションでは、UE4 プロジェクトをパッケージ化して、Google VR デバイスで動作するようにします。 [NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/2/GoogleVRQuickStart_2.KOR.udn b/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/2/GoogleVRQuickStart_2.KOR.udn index aa1097cd5840..e819c1685429 100644 --- a/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/2/GoogleVRQuickStart_2.KOR.udn +++ b/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/2/GoogleVRQuickStart_2.KOR.udn @@ -1,11 +1,11 @@ -INTSourceChangelist:3275566 +INTSourceChangelist:3477690 Availability:Public Title:2. 구글 VR 프로젝트 구성 Crumbs:%ROOT%, Platforms/GoogleVR Description:구글 VR 작업용 UE4 프로젝트 구성법입니다. Navigation:platform Skilllevel: Intermediate -Version: 4.12 +Version: 4.16 Parent:Platforms/GoogleVR/QuickStart order:2 type:multi-step @@ -26,7 +26,13 @@ Google 에서는 Daydream 을 최대한 활용하기 위해 알아야하는 것 1. Plugins 메뉴에서 **Virtual Reality** (가상 현실) 섹션으로 가 **Google VR** (구글 VR)이 활성화되어 있는지 확인합니다. - ![](GVRQS_Pligin_GVR_Enabled_00.png) + [REGION:lightbox] + [![](GVRQS_Pligin_GVR_Enabled_00.png)(w:500)](GVRQS_Pligin_GVR_Enabled_00.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] [region:note] 구글 VR 플러그인은 기본적으로 활성화되어 있을 것입니다. 그렇지 않은 경우, 그 옆의 체크박스를 클릭하면 **Enabled** (활성화)됩니다. 그러면 변경사항 적용을 위해 UE4 에디터를 재시작하라는 창이 뜹니다. 구글 VR 플러그인 활성화 후 UE4 에디터를 재시작하지 않으면 플러그인이 정상 작동하지 않을 수 있습니다. @@ -63,21 +69,32 @@ Google 에서는 Daydream 을 최대한 활용하기 위해 알아야하는 것 1. **Input** (입력) 섹션 아래 **Mobile** 카테고리에서, **Default Touch Interface** (기본 터치 인터페이스)의 **DefaultVirtualJoysticks** 옆 작은 하양 삼각형을 클릭하면 뜨는 드롭다운 목록에서 **Clear** (비우기) 옵션을 눌러 제거합니다. - [OBJECT:EmbeddedVideo] - [PARAMLITERAL:width] - 640 - [/PARAMLITERAL] - [PARAMLITERAL:height] - 360 - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - -Ylbi1TCKZs - [/PARAMLITERAL] - [/OBJECT] + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + -Ylbi1TCKZs + [/PARAMLITERAL] + [PARAMLITERAL:width] + 50 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] 1. **Android** (안드로이드) 섹션 아래 **Platforms** (플랫폼) 부분에서 **APKPackaging** (APK 패키징)과 **Google Play Services** (구글 플레이 서비스) 섹션의 **Configure Now** (지금 환경설정) 버튼을 눌러 프로젝트가 패키징을 제대로 할 수 있도록 합니다. - ![](GVRQS_Config_Now_00.png) + [REGION:lightbox] + [![](GVRQS_Config_Now_00.png)(w:500)](GVRQS_Config_Now_00.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] 1. **APKPackaging** 섹션에서 다음 옵션이 설정되었는지 확인합니다: @@ -85,19 +102,40 @@ Google 에서는 Daydream 을 최대한 활용하기 위해 알아야하는 것 * **Disable verify OBB on first start/update:** (첫 시작/업데이트시 OBB 검증 끄기 - 체크 * **Enable FullScreen Immersive on KitKat and above devices:** (KitKat 이상 디바이스에서 전체화면 몰입 모드 켜기) - 체크 - ![](GVRQS_SDK_Version_00.png) + [REGION:lightbox] + [![](GVRQS_SDK_Version_00.png)(w:500)](GVRQS_SDK_Version_00.png) + [/REGION] -1. **Build** 섹션을 찾아 **Support armv7 [aka armeabi-v7a]** 옵션 체크를 해제하고 **Support arm64[aka arm64-v8a]** 와 **Support OpenGL ES2** 둘 다 체크되었는지 확인합니다. + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] - ![](GVRQS_Build_arm64_Support_00.png) +1. **Build** 섹션을 찾아 다음과 같이 설정합니다: + + * **Support armv7 (aka armeabi-v7a):** 꺼짐 + * **Support arm64 (aka arm64-v8a):** 켜짐 + * **Support OpenGL ES2:** 켜짐 + + [REGION:lightbox] + [![](GVRQS_Build_arm64_Support_00.png)(w:500)](GVRQS_Build_arm64_Support_00.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] 1. 다음, **Advanced APKPackaging** 섹션에서 다음 옵션을 켜줍니다: - * **Configure for deployment to Daydream:** (Daydream 으로 설치를 위한 환경설정) 체크 * **Configure GoogleVR Deployment Mode:** (GoogleVR 디플로이 모드 환경설정) Daydream & Cardboard - * **Configure GoogleVR for sustained performance mode:** (GoogleVR 지속 퍼포먼스 모드 환경설정) 체크 + * **Configure GoogleVR for sustained-performance mode:** (GoogleVR 지속 퍼포먼스 모드 환경설정) 체크 - ![](GVRQS_GoogleVR_Options_00.png) + [REGION:lightbox] + [![](GVRQS_GoogleVR_Options_00.png)(w:500)](GVRQS_GoogleVR_Options_00.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] [region:note] Configure GoogleVR Deployment Mode 에는 여러가지 옵션이 있으며, 하는 일은 다음과 같습니다. @@ -107,7 +145,7 @@ Google 에서는 Daydream 을 최대한 활용하기 위해 알아야하는 것 [/region] -1. **Android SDK** (안드로이드 SDK) 섹션의 **SDKConfig** (SDK 환경설정) 섹션 아래 **SDK API Level** 과 **NDK API Level** 둘 다 기본값이 아닌 **android-24** 로 설정하여 프로젝트가 가장 최신의 안드로이드 SDK 로 컴파일되도록 합니다. +1. **Android SDK** (안드로이드 SDK) 섹션의 **SDKConfig** (SDK 환경설정) 섹션 아래 **SDK API Level** 을 **matchndk** 로 설정합니다. 그리고 **NDK API Level** 을 **android-24** 로 설정하여 프로젝트가 가장 최신의 안드로이드 SDK 로 컴파일되도록 합니다. ![](GVRQS_Android_SDK_Options_00.png) diff --git a/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/3/GoogleVRQuickStart_3.INT.udn b/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/3/GoogleVRQuickStart_3.INT.udn index d11730c35e01..22e9880f360f 100644 --- a/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/3/GoogleVRQuickStart_3.INT.udn +++ b/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/3/GoogleVRQuickStart_3.INT.udn @@ -4,7 +4,7 @@ Crumbs:%ROOT%, Platforms/GoogleVR Description:Packing and deploying a UE4 project that can be used with Google VR Navigation:platform Skilllevel: Intermediate -Version: 4.12 +Version: 4.16 Parent:Platforms/GoogleVR/QuickStart order:3 type:multi-step @@ -13,50 +13,64 @@ tags:Google VR [NAV] -In this section of the Google VR Quick Start, we will go over what you have to do to package your UE4 project so it will run on a Google VR device. +In this section of the Google VR Quick Start, we will go over what you have to do to package your UE4 project so that it will run on a Google VR device. [region:note] -Before going any further make sure that the Smartphone used for testing has been plugged into your development PC via a USB cable. +Before going any further make sure that the Smartphone used for testing has been plugged into your development PC via a USB cable and make also make sure that ADB can see your phone as an authorized device. If you are unsure how to do or are having problems getting ADB to see your device, check out the following page for more information [Android How - To Set Up Your Android Device](https://docs.unrealengine.com/latest/INT/Platforms/Android/GettingStarted/2/). [/region] 1. To start the packing process, go to the **Main Toolbar** and from the **File** menu go to **Package Project** > **Android** > **Android (ATC)**. - ![](GVRQS_Package_Project_00.png) + ![](GVRQS_Package_Project_00.png) 1. Once Android(ATC) has been selected, you will be presented with a Windows dialogue box. From this dialogue press, the **Make New Folder** option and call the folder **Androids_Builds**. Once the folder has been created, press the **Okay** button to begin the packing process. - ![](GVRQS_Package_Project_Location_00.png) + ![](GVRQS_Package_Project_Location_00.png) 1. While the project is being packed, a status window will be displayed in the lower right-hand corner of the UE4 Editor. - - [region:tip] - For a more detailed look on what is going on during packing, click on the **Output Log** window. - [/region] + + [region:tip] + For a more detailed look on what is going on during packing, click on the **Output Log** window. + [/region] - ![](GVRQS_Package_Progress_00.png) + [REGION:lightbox] + [![](GVRQS_Package_Progress_00.png)(w:645)](GVRQS_Package_Progress_00.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] 1. Once the project has been packaged, open the Androids_Builds folder and double-click on the **Install_GVR_QS_Development-armv7-es2.bat** file to install the project to your Android Smartphone. - [region:warning] - In order for this to work, you will need to make sure that your Android Smartphone is plugged into your development PC via a USB cable. Failing to do this will result in the project not being installed on the device. - [/region] - ![](GVRQS_Android_Build_Files_00.png) + [region:warning] + For this to work, you will need to make sure that your Android Smartphone is plugged into your development PC via a USB cable. Failing to do this will result in the project not being installed on the device. + [/region] + ![](GVRQS_Android_Build_Files_00.png) -1. Once the .BAT file has been run a command line window will be displayed showing you the progress of the install. When the install is complete the command line window will automatically close. +1. Once the .BAT file has been run a command line window will be displayed showing you the progress of the install. When the install is complete, the command line window will automatically close. - ![](GVRQS_Installing_To_Phone_00.png) + ![](GVRQS_Installing_To_Phone_00.png) 1. Unplug your Smartphone from your PC and then look for an app called **GVR_QS** tap on the GVR_QS icon to launch the project. - ![](GVRQS_App_Location_00.png) + ![](GVRQS_App_Location_00.png) 1. When the GVR_QS project is viewed through a VR Headset, you should see something that looks similar to the following image. - ![](GVRQS_HMD_View_00.png) + [REGION:lightbox] + [![](GVRQS_HMD_View_00.png)(w:720)](GVRQS_HMD_View_00.png) + [/REGION] - [region:note] - Make sure that your phone and UE4 are properly configured for the VR device you are using click on the **Gear** icon that is displayed while the app is running. - ![](GVRQS_HMD_Options_00.png) - From this menu, you can scan the QR code that is on the side of your VR device and that will make sure that UE4 outputs an image that is compatible with your VR device. - [/region] + [REGION:caption] + Click for full image. + [/REGION] + + [region:note] + To make sure that your phone and UE4 are properly configured for the VR device you are using click on the **Gear** icon that is displayed while the app is running. + + ![](GVRQS_HMD_Options_00.png) + + From the displayed menu, you can scan the QR code that is on the side of your VR device, and that will make sure UE4 outputs an image that is compatible with your VR device. + [/region] [NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/3/GoogleVRQuickStart_3.JPN.udn b/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/3/GoogleVRQuickStart_3.JPN.udn index 641cba683e00..2bf81666f01a 100644 --- a/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/3/GoogleVRQuickStart_3.JPN.udn +++ b/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/3/GoogleVRQuickStart_3.JPN.udn @@ -1,11 +1,11 @@ -INTSourceChangeList:3155346 +INTSourceChangelist:3477690 Availability:Public -Title:3.Google VR プロジェクトをパックおよびデプロイする +Title:3.Google VR プロジェクトのパッケージ化およびデプロイ方法 Crumbs:%ROOT%, Platforms/GoogleVR Description:Google VR で使用できる UE4 プロジェクトのパックとデプロイ方法 Navigation:platform Skilllevel:Intermediate -Version:4.12 +Version:4.16 Parent:Platforms/GoogleVR/QuickStart order:3 type:multi-step @@ -20,29 +20,35 @@ tags:Google VR 次のステップに進む前に、使用する Android スマートフォンが USB で開発用 PC に接続されていることを確認してください。 [/region] -1. パッキングを開始するには、**Main Toolbar** で **[File]** > **[Package Project]** > **[Android]** > **[Android (ATC)]** を選択します。 +1. パッケージ化を開始するには、**メイン ツールバー** で **[File]** > **[Package Project]** > **[Android]** > **[Android (ATC)]** を選択します。 ![](GVRQS_Package_Project_00.png) -1. Android(ATC) を選択したら、Windows ダイアログ ボックスが表示されます。このダイアログの **[Make New Folder (新規フォルダを作成)]** オプションを押して、 **「Androids_Builds」** という名前にします。フォルダが作成されたら、**[OK]** ボタンを押してパッキング処理を開始します。 +1. Android(ATC) を選択したら、Windows ダイアログ ボックスが表示されます。このダイアログの **[Make New Folder (新規フォルダを作成)]** オプションを押して、 **「Androids_Builds」** という名前にします。フォルダが作成されたら、**[OK]** ボタンを押してパッケージ化処理を開始します。 ![](GVRQS_Package_Project_Location_00.png) -1. プロジェクトのパッキング処理中は、進捗バーが UE4 エディタの右下隅に表示されます。 +1. プロジェクトのパッケージ化処理中は、進捗バーが UE4 エディタの右下隅に表示されます。 [region:tip] - パッキング処理中の詳細は、**[Output Log (出力ログ)]** ウィンドウに表示されます。 + パッケージ化処理中の詳細は、**[Output Log (出力ログ)]** ウィンドウに表示されます。 [/region] - ![](GVRQS_Package_Progress_00.png) + [REGION:lightbox] + [![](GVRQS_Package_Progress_00.png)(w:645)](GVRQS_Package_Progress_00.png) + [/REGION] -1. プロジェクトがパックされたら、「Androids_Builds」フォルダを開いて **「Install_GVR_QS_Development-armv7-es2.bat」** ファイルをダブルクリックして、Android スマートフォンにプロジェクトをインストールしてください。 + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + +1. プロジェクトがパッケージ化されたら、「Androids_Builds」フォルダを開いて **「Install_GVR_QS_Development-armv7-es2.bat」** ファイルをダブルクリックして、Android スマートフォンにプロジェクトをインストールしてください。 [region:warning] このセクションでの作業では、Android スマートフォンが開発用マシンに USB で接続されている必要があります。接続されていないと、プロジェクトがデバイスにインストールされません。 [/region] ![](GVRQS_Android_Build_Files_00.png) -1. 「.BAT」ファイルを実行すると、インストールの進捗状況を示すコマンドラインウィンドウが実行されます。インストールが完了すると、コマンドライン ウィンドウが自動的に閉じます。 +1. .BAT ファイルを実行すると、インストールの進捗状況を示すコマンドライン ウィンドウが実行されます。インストールが完了すると、コマンドライン ウィンドウが自動的に閉じます。 ![](GVRQS_Installing_To_Phone_00.png) @@ -52,12 +58,20 @@ tags:Google VR 1. GVR_QS プロジェクトを VR ヘッドセットで見ると、以下のような画像になっているはずです。 - ![](GVRQS_HMD_View_00.png) + [REGION:lightbox] + [![](GVRQS_HMD_View_00.png)(w:720)](GVRQS_HMD_View_00.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] [region:note] アプリケーションの実行中に **Gear** アイコンをクリックして、スマートフォンと UE4 が使用する VR デバイス用に適切に設定されていることを確認してください。 + ![](GVRQS_HMD_Options_00.png) - このメニューから、VR デバイスの横にある QR コードをスキャンして、UE4 が VR デバイスと互換性のある画像を出力していることを確認することができます。 + + 表示されたメニューから、VR デバイスの横にある QR コードをスキャンして、UE4 が VR デバイスと互換性のある画像を出力していることを確認することができます。 [/region] [NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/3/GoogleVRQuickStart_3.KOR.udn b/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/3/GoogleVRQuickStart_3.KOR.udn index ab12a038d943..be2dbab0807d 100644 --- a/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/3/GoogleVRQuickStart_3.KOR.udn +++ b/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/3/GoogleVRQuickStart_3.KOR.udn @@ -1,11 +1,11 @@ -INTSourceChangelist:3155346 +INTSourceChangelist:3477690 Availability:Public Title:3. 구글 VR 프로젝트 패키징 & 개발 Crumbs:%ROOT%, Platforms/GoogleVR Description:구글 VR 사용이 가능한 UE4 프로젝트 패키지 및 디플로이 방법 안내입니다. Navigation:platform Skilllevel: Intermediate -Version: 4.12 +Version: 4.16 Parent:Platforms/GoogleVR/QuickStart order:3 type:multi-step @@ -34,7 +34,13 @@ tags:Google VR 패키징 도중 일어나는 작업에 대한 상세 내용은, **출력 로그** 창을 클릭하세요. [/region] - ![](GVRQS_Package_Progress_00.png) + [REGION:lightbox] + [![](GVRQS_Package_Progress_00.png)(w:645)](GVRQS_Package_Progress_00.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] 1. 프로젝트 패키징이 완료되면, Androids_Builds 폴더에 들어가 **Install_GVR_QS_Development-armv7-es2.bat** 파일을 실행시켜 안드로이드 스마트폰에 프로젝트를 설치합니다. [region:warning] @@ -52,12 +58,20 @@ tags:Google VR 1. GVR_QS 프로젝트를 VR 헤드셋으로 보면, 다음 그림과 비슷한 것이 보일 것입니다. - ![](GVRQS_HMD_View_00.png) + [REGION:lightbox] + [![](GVRQS_HMD_View_00.png)(w:720)](GVRQS_HMD_View_00.png) + [/REGION] + + [REGION:caption] + 클릭하면 이미지 원본을 확인합니다. + [/REGION] [region:note] 앱 실행중 표시되는 **기어** 아이콘을 클릭하여 폰과 UE4 가 제대로 환경설정 되었는지 확인하시기 바랍니다. + ![](GVRQS_HMD_Options_00.png) - 이 메뉴에서 VR 디바이스 측면의 QR 코드를 스캔하면 UE4 가 VR 디바이스와 호환되는 이미지를 출력하도록 해 줄 것입니다. + + 표시되는 메뉴에서 VR 디바이스 측면의 QR 코드를 스캔하면 UE4 가 VR 디바이스와 호환되는 이미지를 출력하도록 해 줄 것입니다. [/region] [NAV] \ No newline at end of file diff --git a/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/GoogleVRQuickStart.INT.udn b/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/GoogleVRQuickStart.INT.udn index 2c136d39a53d..a71208acce8a 100644 --- a/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/GoogleVRQuickStart.INT.udn +++ b/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/GoogleVRQuickStart.INT.udn @@ -6,8 +6,10 @@ Version: 4.12 SkillLevel: Intermediate parent:Platforms/GoogleVR type:quick start +type:landing tags:VR tags:Google VR +topic-image:Platforms\GoogleVR\GoogleVR_Cardboard_Topic_Image.png The GoogleVR Quick Start will walk you through setting up your UE4 project to work with Google VR. @@ -46,15 +48,6 @@ Google has a provided a very detailed document that goes over everything you nee - - - - - - - - - diff --git a/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/GoogleVRQuickStart.JPN.udn b/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/GoogleVRQuickStart.JPN.udn index 1b64c28927a5..edfc5009d75f 100644 --- a/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/GoogleVRQuickStart.JPN.udn +++ b/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/GoogleVRQuickStart.JPN.udn @@ -1,5 +1,5 @@ -TINTSourceChangelist:3275566 -itle:Google VR クイックスタート +INTSourceChangelist:3432707 +Title:Google VR クイックスタート Crumbs:%ROOT%, Platforms, Platforms/GoogleVR Description:Google VR の設定および使用方法 Availability:Public @@ -7,8 +7,10 @@ Version:4.12 SkillLevel:Intermediate parent:Platforms/GoogleVR type:quick start +type:landing tags:VR tags:Google VR +topic-image:Platforms\GoogleVR\GoogleVR_Cardboard_Topic_Image.png このクイックスタートでは UE4 プロジェクトを Google VR で使用するための設定方法を説明します。 @@ -47,15 +49,6 @@ Google では、Daydream の使用方法を詳しく説明しているマニュ - - - - - - - - - diff --git a/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/GoogleVRQuickStart.KOR.udn b/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/GoogleVRQuickStart.KOR.udn index e8b0fa984b85..92dfa19f63cf 100644 --- a/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/GoogleVRQuickStart.KOR.udn +++ b/Engine/Documentation/Source/Platforms/GoogleVR/QuickStart/GoogleVRQuickStart.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3275566 +INTSourceChangelist:3432707 Title:구글 VR 퀵 스타트 Crumbs:%ROOT%, Platforms, Platforms/GoogleVR Description:구글 VR 구성 및 사용 방법 안내입니다. @@ -7,8 +7,10 @@ Version: 4.12 SkillLevel: Intermediate parent:Platforms/GoogleVR type:quick start +type:landing tags:VR tags:Google VR +topic-image:Platforms\GoogleVR\GoogleVR_Cardboard_Topic_Image.png Google VR (구글 VR) 퀵 스타트는 구글 VR 을 사용하는 UE4 프로젝트 구성 방법을 안내해 드립니다. diff --git a/Engine/Documentation/Source/Platforms/HTML5/HTML5.INT.udn b/Engine/Documentation/Source/Platforms/HTML5/HTML5.INT.udn index 785f904cf054..a53d628e4d0b 100644 --- a/Engine/Documentation/Source/Platforms/HTML5/HTML5.INT.udn +++ b/Engine/Documentation/Source/Platforms/HTML5/HTML5.INT.udn @@ -8,6 +8,8 @@ Version: 4.9 type:landing parent:Platforms tags:HTML5 +tags:Desktop +Topic-image:HTML5Development_topic.png HTML5 uses the emscripten tool chain from [Mozilla](https://www.mozilla.org/en-US/) to cross-compile C++ into Javascript. diff --git a/Engine/Documentation/Source/Platforms/HTML5/HTML5.JPN.udn b/Engine/Documentation/Source/Platforms/HTML5/HTML5.JPN.udn index 6fb396765472..07cd1cf0ae38 100644 --- a/Engine/Documentation/Source/Platforms/HTML5/HTML5.JPN.udn +++ b/Engine/Documentation/Source/Platforms/HTML5/HTML5.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3150518 +INTSourceChangelist:3467293 Availability:Public Title:HTML5 ゲームの開発 Crumbs:%ROOT%, Platforms @@ -9,6 +9,8 @@ Version:4.9 type:landing parent:Platforms tags:HTML5 +tags:Desktop +Topic-image:HTML5Development_topic.png HTML5 は、[Mozilla](https://www.mozilla.org/en-US/) から Emscripten ツールチェーンを使用して、C++ を Javascript にクロスコンパイルします。 diff --git a/Engine/Documentation/Source/Platforms/HTML5/HTML5.KOR.udn b/Engine/Documentation/Source/Platforms/HTML5/HTML5.KOR.udn index 498e34ebcbd3..2f14fbbfa0cd 100644 --- a/Engine/Documentation/Source/Platforms/HTML5/HTML5.KOR.udn +++ b/Engine/Documentation/Source/Platforms/HTML5/HTML5.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3150518 +INTSourceChangelist:3467293 Availability: Public Title: HTML5 게임 개발 Crumbs:%ROOT%, Platforms @@ -9,6 +9,8 @@ Version: 4.9 type:landing parent:Platforms tags:HTML5 +tags:Desktop +Topic-image:HTML5Development_topic.png HTML5 는 [Mozilla](https://www.mozilla.org/en-US/) 의 emscripten 툴 체인을 사용하여 C++ 를 Javascript 로 크로스 컴파일합니다. diff --git a/Engine/Documentation/Source/Platforms/Linux/AdvancedLinuxDeveloper/LinuxCrossCompileLegacy/LinuxCrossCompileLegacy.INT.udn b/Engine/Documentation/Source/Platforms/Linux/AdvancedLinuxDeveloper/LinuxCrossCompileLegacy/LinuxCrossCompileLegacy.INT.udn index ca2f3aa7bfce..3059da8c9ef8 100644 --- a/Engine/Documentation/Source/Platforms/Linux/AdvancedLinuxDeveloper/LinuxCrossCompileLegacy/LinuxCrossCompileLegacy.INT.udn +++ b/Engine/Documentation/Source/Platforms/Linux/AdvancedLinuxDeveloper/LinuxCrossCompileLegacy/LinuxCrossCompileLegacy.INT.udn @@ -1,6 +1,6 @@ Availability:Public Title: Cross-Compiling for Linux (Legacy) -Crumbs: +Crumbs:%ROOT% Description:For engine versions older than 4.14, this page shows users how to set up cross-compilation for the Linux Platform. Version: 4.14 SkillLevel: Advanced @@ -17,7 +17,7 @@ topic-image:LegacyRef_Topic.png [TOC(start:2 end:3)] -This reference is an archive for users who need to set up their cross-compilation toolchains in Unreal Engine 4 versions that were released prior to 4.14. +This reference is an archive for users who need to set up their cross-compilation toolchains in Unreal Engine 4 (UE4) versions that were released prior to 4.14. [REGION:note] If you're developing your project with Unreal Engine, version 4.14 (or newer), you'll want to refer to our [](Platforms/Linux/GettingStarted) documentation. @@ -28,20 +28,23 @@ If you're developing your project with Unreal Engine, version 4.14 (or newer), y **Cross-compilation** makes it possible for game developers, working in a Windows-centric workflow, to target Linux. At this time, cross-compilation is only supported for Windows. Mac users currently have to resort to [native compilation](https://wiki.unrealengine.com/Building_On_Linux). We support, test, and provide the libraries and toolchains for the Linux-x86_64 platform. -[/EXCERPT:Why_XC] + ## Getting the Toolchain Please use the following table to download the appropriate toolchain: -| Unreal Engine 4 (UE4) Version | Toolchain | -| ------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | -| **<= 4.8** | -v4 [clang-3.5.0-based](http://cdn.unrealengine.com/qfe/v4_clang-3.5.0_ld-2.24_glibc-2.12.2.zip) | -| **4.9 and 4.10** | -v6 [clang-3.6.0-based](https://s3.amazonaws.com/unrealengine/qfe/v6_clang-3.6.0_ld-2.24_glibc-2.12.2.zip) | -| **4.11 thru 4.13** | -v7 [clang-3.7.0-based](https://s3.amazonaws.com/unrealengine/CrossToolchain_Linux/v7_clang-3.7.0_ld-2.24_glibc-2.12.2.zip) | -| **4.14** | -v8 [clang-3.9.0-based](http://cdn.unrealengine.com/qfe/v8_clang-3.9.0-centos7.zip) | +| Toolchain | UE4 Version | +| ----------------------------------------------------------------------------------------------------------------------------------- | -------------- | +| **-v4** [clang-3.5.0-based](http://cdn.unrealengine.com/qfe/v4_clang-3.5.0_ld-2.24_glibc-2.12.2.zip) | <= 4.8 | +| **-v6** [clang-3.6.0-based](https://s3.amazonaws.com/unrealengine/qfe/v6_clang-3.6.0_ld-2.24_glibc-2.12.2.zip) | 4.9 and 4.10 | +| **-v7** [clang-3.7.0-based](https://s3.amazonaws.com/unrealengine/CrossToolchain_Linux/v7_clang-3.7.0_ld-2.24_glibc-2.12.2.zip) | 4.11 thru 4.13 | +| **-v8** [clang-3.9.0-based](http://cdn.unrealengine.com/qfe/v8_clang-3.9.0-centos7.zip) | 4.14 and 4.15 | +| **-v9** [clang-4.0.0-based](http://cdn.unrealengine.com/CrossToolchain_Linux/v9_clang-4.0.0-centos7.zip) | 4.16 | -We also provide the libraries and toolchains that allow you to compile for Linux ARM as well (original Raspberry Pi and up). Although, this will require you to make a (minor) code -change in [Unreal Build Tool](Programming/UnrealBuildSystem) (UBT). + +We also provide the libraries and toolchains that allow you to compile for [Linux ARM](https://s3.amazonaws.com/unrealengine/qfe/arm-unknown-linux-gnueabihf_v5_clang-3.5.0-ld-2.23.1-glibc-2.13.zip) as well (original Raspberry Pi and up). +Although, this will require you to make a (minor) code change in [Unreal Build Tool](Programming/UnrealBuildSystem) (UBT). +[/EXCERPT:Why_XC] From this point on, we assume that you are targeting x86_64 Linux, though most of the following information will apply to compiling for ARM as well (except for the different toolchain). Note that you can [build your own toolchain](https://wiki.unrealengine.com/Building_Linux_cross-toolchain) if you want different versions of the tools, or if you want to target a different architecture. diff --git a/Engine/Documentation/Source/Platforms/Linux/AdvancedLinuxDeveloper/LinuxCrossCompileLegacy/LinuxCrossCompileLegacy.JPN.udn b/Engine/Documentation/Source/Platforms/Linux/AdvancedLinuxDeveloper/LinuxCrossCompileLegacy/LinuxCrossCompileLegacy.JPN.udn index db0149844fb6..d562fe58fc53 100644 --- a/Engine/Documentation/Source/Platforms/Linux/AdvancedLinuxDeveloper/LinuxCrossCompileLegacy/LinuxCrossCompileLegacy.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Linux/AdvancedLinuxDeveloper/LinuxCrossCompileLegacy/LinuxCrossCompileLegacy.JPN.udn @@ -1,7 +1,7 @@ -INTSourceChangelist:3321713 +INTSourceChangelist:3469804 Availability:Public Title:Linux (レガシー) のクロス コンパイル -Crumbs: +Crumbs:%ROOT% Description:4.14 より前のバージョンのエンジン ユーザー向けに、Linux プラットフォーム用クロスコンパイルの設定方法を説明します。 Version:4.14 SkillLevel:Advanced @@ -18,7 +18,7 @@ topic-image:LegacyRef_Topic.png [TOC(start:2 end:3)] -このリファレンスは、4.14 よりも古いアンリアル エンジン 4 のクロスコンパイル ツールの設定が必要なユーザー向けのアーカイブです。 +このリファレンスは、4.14 よりも古いアンリアル エンジン 4 (UE4) のクロスコンパイル ツールの設定が必要なユーザー向けのアーカイブです。 [REGION:note] ご使用のアンリアル エンジンが 4.14 以降の場合は、[](Platforms/Linux/GettingStarted) を参照してください。 @@ -29,27 +29,30 @@ topic-image:LegacyRef_Topic.png **クロスコンパイル** をすると、ゲーム デベロッパーは Linux をターゲットにしつつ、Windows を中心にしたワークフローで作業できるようになります。今回、クロスコンパイルは Windows のみのサポートとなりますので、 Mac ユーザーは現在 [native compilation](https://wiki.unrealengine.com/Building_On_Linux) を使用する必要があります。Linux-x86_64 プラットフォーム向けに、ライブラリおよびツールチェーンのサポート、テスト、提供をしています。 -[/EXCERPT:Why_XC] + ## ツールチェーンの取得 以下の表を使って適切なツールチェーンをダウンロードしてください。 -| アンリアル エンジン 4 (UE4) バージョン | ツールチェーン | -| ------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | -| **<= 4.8** | -v4 [clang-3.5.0-based](http://cdn.unrealengine.com/qfe/v4_clang-3.5.0_ld-2.24_glibc-2.12.2.zip) | -| **4.9 and 4.10** | -v6 [clang-3.6.0-based](https://s3.amazonaws.com/unrealengine/qfe/v6_clang-3.6.0_ld-2.24_glibc-2.12.2.zip) | -| **4.11 thru 4.13** | -v7 [clang-3.7.0-based](https://s3.amazonaws.com/unrealengine/CrossToolchain_Linux/v7_clang-3.7.0_ld-2.24_glibc-2.12.2.zip) | -| **4.14** | -v8 [clang-3.9.0-based](http://cdn.unrealengine.com/qfe/v8_clang-3.9.0-centos7.zip) | +| ツールチェーン | UE4 バージョン | +| ----------------------------------------------------------------------------------------------------------------------------------- | -------------- | +| **-v4** [clang-3.5.0-based](http://cdn.unrealengine.com/qfe/v4_clang-3.5.0_ld-2.24_glibc-2.12.2.zip) | <= 4.8 | +| **-v6** [clang-3.6.0-based](https://s3.amazonaws.com/unrealengine/qfe/v6_clang-3.6.0_ld-2.24_glibc-2.12.2.zip) | 4.9 and 4.10 | +| **-v7** [clang-3.7.0-based](https://s3.amazonaws.com/unrealengine/CrossToolchain_Linux/v7_clang-3.7.0_ld-2.24_glibc-2.12.2.zip) | 4.11 thru 4.13 | +| **-v8** [clang-3.9.0-based](http://cdn.unrealengine.com/qfe/v8_clang-3.9.0-centos7.zip) | 4.14 and 4.15 | +| **-v9** [clang-4.0.0-based](http://cdn.unrealengine.com/CrossToolchain_Linux/v9_clang-4.0.0-centos7.zip) | 4.16 | -ライブラリとツールチェーン (clang-3.5.0-arm) を提供していますので、Linux ARM (オリジナルの Rasberry Pi 以上) のコンパイルが可能です。ただし、[Unreal Build Tool](Programming/UnrealBuildSystem) (UBT) で -少しだけコード変更が必要になります。 -以下の情報のほとんどは ARM のコンパイル (別のツールチェーンを除く) にも通用しますが、ここから先は x86_64 Linux をターゲットに開発を行うユーザーを想定しています。 -異なるバージョンのツールや別のアーキテクチャをターゲットとする場合は、[独自のツールチェーンをビルド](https://wiki.unrealengine.com/Building_Linux_cross-toolchain) することができます。 +Linux ARM (https://s3.amazonaws.com/unrealengine/qfe/arm-unknown-linux-gnueabihf_v5_clang-3.5.0-ld-2.23.1-glibc-2.13.zip) 並びに (original Raspberry Pi and up) のコンパイルが可能なライブラリとツールチェーンも提供しています。 +ただし、[Unreal Build Tool](Programming/UnrealBuildSystem) (UBT) で (マイナーな) コード変更が必要になります。 +[/EXCERPT:Why_XC] + +これより先は x86_64 Linux をターゲットに開発を行うユーザーを想定していますが、ほとんどの情報は ARM のコンパイル (別のツールチェーンを除く) にも適用できます。 +異なるバージョンのツールや別のアーキテクチャをターゲットとする場合は、[独自のツールチェーンのビルド](https://wiki.unrealengine.com/Building_Linux_cross-toolchain) が可能です。 ## ツールチェーンの設定 -[Control Panel (コントロールパネル)]->[System (システム)]->[Advanced system settings (詳細システム設定)]->[Advanced (詳細)]->[Environment variables (環境変数)] の順に選んで、`LINUX_ROOT` という名前の環境変数を追加します。この値はツールチェーンの後に続くバックスラッシュなしの絶対パスです。 +[Control Panel (コントロールパネル)]->[System (システム)]->[Advanced system settings (詳細システム設定)]->[Advanced (詳細)]->[Environment variables (環境変数)] の順に選んで、`LINUX_ROOT` という名前の環境変数を追加します。この値はツールチェーンの絶対パスです (バックスラッシュはありません)。 [REGION:raw] ![](EnvironmentVar.png) @@ -110,8 +113,8 @@ Windows 向け: ## Linux 向けのパッケージング -エディタでパッケージ プロジェクトを開いて、[File]->[Package To]->[Linux] の順に選択する方法が最も簡単なパッケージの作成手段です (前の手順でクロスツールチェーンをインストール済みで、 Linux ターゲットモジュールが対象エディタ用にビルドされていることが前提です。リストに 「Linux」 が表示されない場合は、 -いずれかの手順が終了してない可能性があります。上記を参照してください)。サンプリングしばらくすると (対象プロジェクトに依存、サンプル プロジェクトはいくらか短時間)、 +最も簡単なパッケージ作成方法は、エディタでパッケージ プロジェクトを開いて、[File]->[Package To]->[Linux] の順に選択します +(その前にクロスツールチェーンをインストールしておくこと、Linux ターゲットモジュールが対象エディタ用にビルドされていることが前提です。リストに 「Linux」 が表示されない場合は、いずれかの手順が終了してない可能性があります。上記を参照してください)。サンプリングしばらくすると (対象プロジェクトに依存、サンプル プロジェクトはいくらか短時間)、 パッケージを作成するディレクトリにゲームアセットとバイナリが表示されます。 パッケージ作成のプロセスに関する詳細は、**Show Output Log** リンクから参照してください。プロセスが「unable to find UnrealPak or ShaderCompileWorker (UnrealPak または ShaderCompileWorker が見つかりません)」のエラーメッセージで失敗した場合は、ホスト (Windows) プラットフォーム向けのパッケージのビルド方法を上記で参照してください。 diff --git a/Engine/Documentation/Source/Platforms/Linux/AdvancedLinuxDeveloper/LinuxCrossCompileLegacy/LinuxCrossCompileLegacy.KOR.udn b/Engine/Documentation/Source/Platforms/Linux/AdvancedLinuxDeveloper/LinuxCrossCompileLegacy/LinuxCrossCompileLegacy.KOR.udn index 867044d56156..008189f4a1cc 100644 --- a/Engine/Documentation/Source/Platforms/Linux/AdvancedLinuxDeveloper/LinuxCrossCompileLegacy/LinuxCrossCompileLegacy.KOR.udn +++ b/Engine/Documentation/Source/Platforms/Linux/AdvancedLinuxDeveloper/LinuxCrossCompileLegacy/LinuxCrossCompileLegacy.KOR.udn @@ -1,7 +1,7 @@ -INTSourceChangelist:3321713 +INTSourceChangelist:3469804 Availability:Public Title: 리눅스용 크로스 컴파일 (레거시) -Crumbs: +Crumbs:%ROOT% Description:엔진 4.14 미만 버전에서 리눅스 플랫폼용 크로스 플랫폼 구성 방법을 알려드립니다. Version: 4.14 SkillLevel: Advanced @@ -18,7 +18,7 @@ topic-image:LegacyRef_Topic.png [TOC(start:2 end:3)] -4.14 이전 릴리즈된 언리얼 엔진 4 버전의 크로스 컴파일 툴체인 구성을 하는 사용자를 위한 참고서입니다. +4.14 이전 릴리즈된 언리얼 엔진 4 (UE4) 버전의 크로스 컴파일 툴체인 구성을 하는 사용자를 위한 참고서입니다. [REGION:note] 언리얼 엔진 4.14 (이상) 버전으로 프로젝트를 개발하시는 경우, [](Platforms/Linux/GettingStarted) 문서를 참고해 보시기 바랍니다. @@ -29,20 +29,23 @@ topic-image:LegacyRef_Topic.png **크로스 컴파일** 덕에 윈도우 중심으로 작업하는 게임 개발자들이 리눅스를 타겟으로 개발할 수 있습니다. 현재 크로스 컴파일은 윈도우에만 지원됩니다. 맥 사용자들은 [네이티브 컴파일](https://wiki.unrealengine.com/Building_On_Linux) 에 의존해야 합니다. Linux-x86_64 플랫폼용 라이브러이와 툴체인을 지원, 테스트, 제공해 드리고 있습니다. -[/EXCERPT:Why_XC] + ## 툴체인 구하기 다음 표를 통해 적합한 툴체인을 다운로드할 수 있습니다: -| 언리얼 엔진 4 (UE4) 버전 | 툴체인 | -| ------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | -| **<= 4.8** | -v4 [clang-3.5.0-based](http://cdn.unrealengine.com/qfe/v4_clang-3.5.0_ld-2.24_glibc-2.12.2.zip) | -| **4.9 and 4.10** | -v6 [clang-3.6.0-based](https://s3.amazonaws.com/unrealengine/qfe/v6_clang-3.6.0_ld-2.24_glibc-2.12.2.zip) | -| **4.11 thru 4.13** | -v7 [clang-3.7.0-based](https://s3.amazonaws.com/unrealengine/CrossToolchain_Linux/v7_clang-3.7.0_ld-2.24_glibc-2.12.2.zip) | -| **4.14** | -v8 [clang-3.9.0-based](http://cdn.unrealengine.com/qfe/v8_clang-3.9.0-centos7.zip) | +| 툴체인 | UE4 버전 | +| ----------------------------------------------------------------------------------------------------------------------------------- | -------------- | +| **-v4** [clang-3.5.0-based](http://cdn.unrealengine.com/qfe/v4_clang-3.5.0_ld-2.24_glibc-2.12.2.zip) | <= 4.8 | +| **-v6** [clang-3.6.0-based](https://s3.amazonaws.com/unrealengine/qfe/v6_clang-3.6.0_ld-2.24_glibc-2.12.2.zip) | 4.9 and 4.10 | +| **-v7** [clang-3.7.0-based](https://s3.amazonaws.com/unrealengine/CrossToolchain_Linux/v7_clang-3.7.0_ld-2.24_glibc-2.12.2.zip) | 4.11 thru 4.13 | +| **-v8** [clang-3.9.0-based](http://cdn.unrealengine.com/qfe/v8_clang-3.9.0-centos7.zip) | 4.14 and 4.15 | +| **-v9** [clang-4.0.0-based](http://cdn.unrealengine.com/CrossToolchain_Linux/v9_clang-4.0.0-centos7.zip) | 4.16 | -Linux ARM (원본 Raspberry Pi 이상) 용 컴파일을 위한 라이브러이와 툴체인도 제공해 드리고 있습니다만, 이를 위해서는 -[언리얼 빌드 툴](Programming/UnrealBuildSystem) (UBT) 에서 약간의 코드 수정을 가해야 할 것입니다. + +[Linux ARM](https://s3.amazonaws.com/unrealengine/qfe/arm-unknown-linux-gnueabihf_v5_clang-3.5.0-ld-2.23.1-glibc-2.13.zip) (원본 Raspberry Pi 이상) 용 컴파일을 위한 라이브러이와 툴체인도 제공해 드리고 있습니다만, +이를 위해서는 [언리얼 빌드 툴](Programming/UnrealBuildSystem) (UBT) 에서 약간의 코드 수정을 가해야 할 것입니다. +[/EXCERPT:Why_XC] 아래 대부분은 (툴체인이 다르다는 것만 제외하면) ARM 컴파일에도 적용되지만, 여기서는 x86_64 리눅스를 타겟으로 삼는다 가정하겠습니다. 참고로 다른 버전의 툴이나 다른 아키텍처를 타겟으로 삼고자 하는 경우, [툴체인을 직접 빌드](https://wiki.unrealengine.com/Building_Linux_cross-toolchain) 할 수도 있습니다. diff --git a/Engine/Documentation/Source/Platforms/Linux/GettingStarted/LinuxCrossGettingStarted.INT.udn b/Engine/Documentation/Source/Platforms/Linux/GettingStarted/LinuxCrossGettingStarted.INT.udn index 239c275274d5..42a4f8dc64ac 100644 --- a/Engine/Documentation/Source/Platforms/Linux/GettingStarted/LinuxCrossGettingStarted.INT.udn +++ b/Engine/Documentation/Source/Platforms/Linux/GettingStarted/LinuxCrossGettingStarted.INT.udn @@ -1,6 +1,6 @@ Availability:Public Title: Cross-Compiling for Linux -Crumbs: +Crumbs:%ROOT% Description:Learn how to set up a cross-compilation toolchain in Windows, targeting the Linux platform. Version: 4.15 SkillLevel: Advanced @@ -17,7 +17,7 @@ prereq:Platforms/Linux/BeginnerLinuxDeveloper/SettingUpAnUnrealWorkflow -[TOC(start:2 end:4)] +[TOC(start:2 end:3)] ![](LinuxXC_Banner.png)(w:1200) @@ -46,7 +46,7 @@ Internet connection, downloading the toolchain can take anywhere from a few minu ### Downloading the Toolchain -1. Click the [link](http://cdn.unrealengine.com/qfe/v8_clang-3.9.0-centos7.zip) to download our Clang 3.9.0 based toolchain. +1. Please download the cross-toolchain appropriate for your engine version. 1. Now, create a new folder, naming it `Linux_CrossCompileToolChain`. @@ -82,14 +82,14 @@ Internet connection, downloading the toolchain can take anywhere from a few minu #### Supported Platforms - Refer to the following table to see which platforms can be targeted with your version of UE4: + Refer to the following table to download the appropriate toolchain for your version of UE4: - | **Architecture** | **Sub-Architecture** | **Vendor** | **System** | **Application Binary Interface (abi)** | UE 4.14 Support | UE 4.15 Support | - | ------------------------------------------------------------------- | -------------------- | ---------- | ---------- | -------------------------------------- | --------------- | ---------------- | - | **[AArch64](https://fedoraproject.org/wiki/Architectures/AArch64)** | N/A | Unknown | Linux | gnueabi | ✗ | ✓ | - | **[ARM](https://developer.arm.com/)** | N/A | Unknown | Linux | gnueabihf | ✗ | ✓ | - | **[i686](https://software.intel.com/en-us/)** | N/A | Unknown | Linux | gnu | ✗ | ✗ | - | **[x86_64](http://developer.amd.com/)** | N/A | Unknown | Linux | gnu | ✓ | ✓ | + | **Architecture** | **Sub-Architecture** | **Vendor** | **System** | **Application Binary Interface (abi)** | + | ------------------------------------------------------------------- | -------------------- | ---------- | ---------- | -------------------------------------- | + | **[AArch64](https://fedoraproject.org/wiki/Architectures/AArch64)** | N/A | Unknown | Linux | gnueabi | + | **[ARM](https://developer.arm.com/)** | N/A | Unknown | Linux | gnueabihf | + | **[i686](https://software.intel.com/en-us/)** | N/A | Unknown | Linux | gnu | + | **[x86_64](http://developer.amd.com/)** | N/A | Unknown | Linux | gnu | [REGION:note] Please note that we haven't yet added Engine libraries for the i686 platform. diff --git a/Engine/Documentation/Source/Platforms/Linux/GettingStarted/LinuxCrossGettingStarted.JPN.udn b/Engine/Documentation/Source/Platforms/Linux/GettingStarted/LinuxCrossGettingStarted.JPN.udn index f8bff5e52567..48238f1b0798 100644 --- a/Engine/Documentation/Source/Platforms/Linux/GettingStarted/LinuxCrossGettingStarted.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Linux/GettingStarted/LinuxCrossGettingStarted.JPN.udn @@ -1,7 +1,7 @@ -INTSourceChangelist:3343972 +INTSourceChangelist:3470080 Availability:Public Title:Linux のクロスコンパイル -Crumbs: +Crumbs:%ROOT% Description:Linux プラットフォームをターゲットにして、Windows でクロスコンパイル ツールチェーンを設定してみよう。 Version:4.15 SkillLevel:Advanced @@ -14,17 +14,18 @@ related:Engine/Basics/Projects/Packaging related:Platforms/Linux/AdvancedLinuxDeveloper/LinuxCrossCompileLegacy related:Programming/Basics/ConfigurationFiles topic-image:GettingStarted_Topic.png +prereq:Platforms/Linux/BeginnerLinuxDeveloper/SettingUpAnUnrealWorkflow -[TOC(start:2 end:4)] +[TOC(start:2 end:3)] ![](LinuxXC_Banner.png)(w:1200) クロスコンパイル ツールチェーンの改善に伴い、 アンリアル エンジン 4 (UE4) デベロッパーは Windows 開発環境で多様なプラットフォームをターゲットにすることができるようになりました。このガイドは、クロスコンパイル ツールチェーンの使用可能なプラットフォームを紹介し、 -ツールチェーンのダウンロード ページ、そして最後にUE4 プロジェクトを Linux 用にクロスコンパイルする設定方法を説明します。アンリアル エンジン 4.15 でプロジェクトを開発するための -ターゲット プラットフォーム間切り替え方法も学習できます。 +ツールチェーンのダウンロード ページ、そして最後にUE4 プロジェクトを Linux 用にクロスコンパイルする設定方法を説明します。アンリアル エンジン 4.15 でプロジェクトを開発する +ターゲット プラットフォーム間の切り替え方法も学習できます。 [REGION:note] バージョンが 4.13 より前のエンジンをご使用の場合は、[](Platforms/Linux/AdvancedLinuxDeveloper/LinuxCrossCompileLegacy) を参照してください。 @@ -46,9 +47,9 @@ Linux 用の Visual Studio と使ってエンジンをビルドする必要も ### ツールチェーンのダウンロード -1. [ここ](http://cdn.unrealengine.com/qfe/v8_clang-3.9.0-centos7.zip) をクリックして Clang 3.9.0 ベースのツールチェーンをダウンロードします。 +1. エンジン バージョンに適したクロス ツールチェーンをダウンロードしてください。 -1. そして新規フォルダを作成し、そのフォルダに「Linux_CrossCompileToolChain」と名前を付けます。 +1. そして新規フォルダを作成し、そのフォルダに `Linux_CrossCompileToolChain` と名前を付けます。 [REGION:lightbox] [![](LinuxXC_Step2.png)(w:600)](LinuxXC_Step2.png) @@ -82,14 +83,14 @@ Linux 用の Visual Studio と使ってエンジンをビルドする必要も #### サポート対象プラットフォーム - 以下の表を参照して、使用している UE4 がターゲットにできるプラットフォームを確認してください。 + 以下の表を参照して、適切なツールチェーンをダウンロードしてください。 - | **アーキテクチャ** | **サブアーキテクチャ** | **メーカー** | **システム** | **Application Binary Interface (abi)** | UE 4.15 Support | UE. - | ------------------------------------------------------------------- | -------------------- | ---------- | ---------- | -------------------------------------- | --------------- | ---------------- | - | **[AArch64](https://fedoraproject.org/wiki/Architectures/AArch64)** | N/A | 不明 | Linux | gnueabi | ✗ | ✓ | - | **[ARM](https://developer.arm.com/)** | N/A | 不明 | Linux | gnueabihf | ✗ | ✓ | - | **[i686](https://software.intel.com/en-us/)** | N/A | 不明 | Linux | gnu | ✗ | ✗ | - | **[x86_64](http://developer.amd.com/)** | N/A | 不明 | Linux | gnu | ✓ | ✓ | + | **アーキテクチャ** | **サブアーキテクチャ | **メーカー** | **システム** | **Application Binary Interface (abi)** | + | ------------------------------------------------------------------- | -------------------- | ---------- | ---------- | -------------------------------------- | + | **[AArch64](https://fedoraproject.org/wiki/Architectures/AArch64)** | N/A | 不明 | Linux | gnueabi | + | **[ARM](https://developer.arm.com/)** | N/A | 不明 | Linux | gnueabihf | + | **[i686](https://software.intel.com/en-us/)** | N/A | 不明 | Linux | gnu | + | **[x86_64](http://developer.amd.com/)** | N/A | 不明 | Linux | gnu | [REGION:note] i686 プラットフォーム用のエンジン ライブラリはまだ追加していません。 @@ -153,7 +154,7 @@ Linux 用の Visual Studio と使ってエンジンをビルドする必要も [/REGION] -1. **[New System Variable (新規システム変数)]** ダイアログ メニューが開いたら`LINUX_MULTIARCH_ROOT` 環境変数設定を **[New System Variable]** ダイアログのテキストボックスへコピーします。 +1. **[New System Variable (新規システム変数)]** ダイアログ メニューが開いたら `LINUX_MULTIARCH_ROOT` 環境変数設定を **[New System Variable]** ダイアログのテキストボックスへコピーします。 [REGION:lightbox] [![](LinuxXC_Step11.png)(w:600)](LinuxXC_Step11.png) @@ -168,7 +169,7 @@ Linux 用の Visual Studio と使ってエンジンをビルドする必要も ![](LinuxXC_Step14.png) [REGION:note] - `LINUX_ROOT` 環境変数を設定してしまっていても、パッケージ化の間エンジンは `LINUX_ROOT` よりも `LINUX_MULTIARCH_ROOT` を優先するので、それを削除する必要はありません。 + エンジンはパッケージ化の間は `LINUX_ROOT` よりも `LINUX_MULTIARCH_ROOT` を優先するので、`LINUX_ROOT` 環境変数を既に設定してしまっても削除する必要はありません。 [/REGION] 1. **[OK]** ボタンを押して **[System Properties]** メニューを終了します。 @@ -181,13 +182,13 @@ Linux 用の Visual Studio と使ってエンジンをビルドする必要も ### Linux ビルド コンフィギュレーションの設定 -Linux のパッケージ化が初めての場合は、以下の手順に従ってください。 +初めて Linux のパッケージ化を行う場合は以下の手順に従ってください。 -1. **Command Prompt** を開いて、`Setup.bat` を実行して、**Visual Studio** から UE4 をビルドするための前提条件の依存性の確認、更新、およびインストールを行います。 +1. **Command Prompt** を開いて `[UE4 ROOT]/Setup.bat` を実行し、**Visual Studio** から UE4 をビルドするための前提条件の依存性の確認、更新、およびインストールを行います。 ![](LinuxXC_Step17.png) -1. `GenerateProjectFiles.bat` を実行してプロジェクト ファイルを UE4 向けに設定します。 +1. `[UE4 ROOT]/GenerateProjectFiles.bat` を実行し、プロジェクト ファイルを UE4 向けに設定します。 ![](LinuxXC_Step18.png) @@ -237,13 +238,13 @@ Linux のパッケージ化が初めての場合は、以下の手順に従っ [/REGION] [/REGION] -## 特定のプラットフォームをターゲットにする +## 特定プラットフォームのターゲット化 [REGION:note] -バージョン 4.14 のターゲットは e x86_64 プラットフォームのみです、次のセクションはバージョン 4.15 で作業するデベロッパー向けとなります。 +バージョン 4.14 のターゲットは e x86_64 プラットフォームのみなので、次のセクションはバージョン 4.15 で作業するデベロッパー向けとなります。 [/REGION] -ターゲットとするプラットフォームを指定するには、プロジェクトの [Default Engine Configuration File](Programming/Basics/ConfigurationFiles) を編集する必要があります。そのファイルの保存場所 (`[Project Directory]\Config`) で +ターゲット プラットフォームを指定するには、プロジェクトの [Default Engine Configuration File](Programming/Basics/ConfigurationFiles) を編集する必要があります。そのファイルの保存場所 (`[Project Directory]\Config`) で `DefaultEngine.ini` を開いて次の行を追加します。 [/Script/LinuxTargetPlatform.LinuxTargetSettings] @@ -257,7 +258,7 @@ Linux のパッケージ化が初めての場合は、以下の手順に従っ ## 結果 -これで終わりです!次Linux 用にプロジェクトをパッケージ化しながら、クロスコンパイル ツールチェーンが使用されていることが確認できるようになりました。 +これで終わりです!Linux 用プロジェクトのパッケージ化にクロスコンパイル ツールチェーンが使用されるようになりました。 [REGION:lightbox] [![](LinuxXC_EndResult.png)(w:600)](LinuxXC_EndResult.png) @@ -267,5 +268,5 @@ Linux のパッケージ化が初めての場合は、以下の手順に従っ クリックしてフルサイズで表示 [/REGION] - これで、Windows (ホスト) コンピューターから各種 Linux プラットフォーム用にプロジェクトを [コンパイル](Programming/Development/CompilingProjects)、[ビルド](Programming/Development/BuildConfigurations)、[パッケージ化](Engine/Basics/Projects/Packaging) することが可能になりました。 + これで、Windows (ホスト) コンピューターからプロジェクトを各種 Linux プラットフォーム用に [コンパイル](Programming/Development/CompilingProjects)、[ビルド](Programming/Development/BuildConfigurations)、[パッケージ化](Engine/Basics/Projects/Packaging) することが可能になりました。 \ No newline at end of file diff --git a/Engine/Documentation/Source/Platforms/Linux/GettingStarted/LinuxCrossGettingStarted.KOR.udn b/Engine/Documentation/Source/Platforms/Linux/GettingStarted/LinuxCrossGettingStarted.KOR.udn index 2a287106f94d..bc978299122c 100644 --- a/Engine/Documentation/Source/Platforms/Linux/GettingStarted/LinuxCrossGettingStarted.KOR.udn +++ b/Engine/Documentation/Source/Platforms/Linux/GettingStarted/LinuxCrossGettingStarted.KOR.udn @@ -1,7 +1,7 @@ -INTSourceChangelist:3343972 +INTSourceChangelist:3470080 Availability:Public Title: 리눅스용 크로스 컴파일 -Crumbs: +Crumbs:%ROOT% Description:윈도우에서 리눅스 플랫폼을 타겟으로 하는 크로스 컴파일 툴체인 셋업 방법을 알아봅니다. Version: 4.15 SkillLevel: Advanced @@ -14,10 +14,11 @@ related:Engine/Basics/Projects/Packaging related:Platforms/Linux/AdvancedLinuxDeveloper/LinuxCrossCompileLegacy related:Programming/Basics/ConfigurationFiles topic-image:GettingStarted_Topic.png +prereq:Platforms/Linux/BeginnerLinuxDeveloper/SettingUpAnUnrealWorkflow -[TOC(start:2 end:4)] +[TOC(start:2 end:3)] ![](LinuxXC_Banner.png)(w:1200) @@ -46,7 +47,7 @@ Visual Studio for Linux 에서 엔진을 빌드하기도 해야 합니다. 다 ### 툴체인 다운로드 -1. [이 링크](http://cdn.unrealengine.com/qfe/v8_clang-3.9.0-centos7.zip) 를 클릭하여 Clang 3.9.0 기반 툴체인을 다운로드합니다. +1. 엔진 버전에 적합한 크로스 툴체인을 다운로드해 주세요. 1. 이제 폴더를 생성한 후, 이름을 `Linux_CrossCompileToolChain` 이라 합니다. @@ -82,14 +83,14 @@ Visual Studio for Linux 에서 엔진을 빌드하기도 해야 합니다. 다 #### 지원 플랫폼 - 다음 표에서 UE4 버전별 타겟을 삼을 수 있는 플랫폼을 참고할 수 있습니다: + 다음 표에서 UE4 버전별 적합한 툴체인을 다운로드할 수 있습니다: - | **아키텍처** | **하위 아키텍처** | **벤더** | **시스템** | **어플리케이션 바이너리 인터페이스 (abi)** | UE 4.14 지원 | UE. 4.15 지원 | - | ------------------------------------------------------------------- | -------------------- | ---------- | ---------- | -------------------------------------- | --------------- | ---------------- | - | **[AArch64](https://fedoraproject.org/wiki/Architectures/AArch64)** | 사용불가 | 알 수 없음 | 리눅스 | gnueabi | ✗ | ✓ | - | **[ARM](https://developer.arm.com/)** | 사용불가 | 알 수 없음 | 리눅스 | gnueabihf | ✗ | ✓ | - | **[i686](https://software.intel.com/en-us/)** | 사용불가 | 알 수 없음 | 리눅스 | gnu | ✗ | ✗ | - | **[x86_64](http://developer.amd.com/)** | 사용불가 | 알 수 없음 | 리눅스 | gnu | ✓ | ✓ | + | **아키텍처** | **하위 아키텍처** | **벤더** | **시스템** | **어플리케이션 바이너리 인터페이스 (abi)** | + | ------------------------------------------------------------------- | -------------------- | ---------- | ---------- | -------------------------------------- | + | **[AArch64](https://fedoraproject.org/wiki/Architectures/AArch64)** | 사용불가 | 알 수 없음 | 리눅스 | gnueabi | + | **[ARM](https://developer.arm.com/)** | 사용불가 | 알 수 없음 | 리눅스 | gnueabihf | + | **[i686](https://software.intel.com/en-us/)** | 사용불가 | 알 수 없음 | 리눅스 | gnu | + | **[x86_64](http://developer.amd.com/)** | 사용불가 | 알 수 없음 | 리눅스 | gnu | [REGION:note] 참고로 i686 플랫폼용 Engine 라이브러리는 아직 추가하지 않았습니다. @@ -183,11 +184,11 @@ Visual Studio for Linux 에서 엔진을 빌드하기도 해야 합니다. 다 전에 리눅스용 프로젝트 패키징을 한 적이 없다면 다음 단계를 밟는 것이 좋습니다. -1. **cmd** 창을 열고 `Setup.bat` 를 실행시키면 **Visual Studio** 에서 UE4 를 빌드하는 데 필요한 필수 종속성을 확인, 업데이트, 설치해 줍니다. +1. **cmd** 창을 열고 `[UE4 ROOT]/Setup.bat` 를 실행시키면 **Visual Studio** 에서 UE4 를 빌드하는 데 필요한 필수 종속성을 확인, 업데이트, 설치해 줍니다. ![](LinuxXC_Step17.png) -1. `GenerateProjectFiles.bat` 를 실행하여 UE4 프로젝트 파일을 셋업합니다. +1. `[UE4 ROOT]/GenerateProjectFiles.bat` 를 실행하여 UE4 프로젝트 파일을 셋업합니다. ![](LinuxXC_Step18.png) diff --git a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/1/AndroidOnLinux_1.INT.udn b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/1/AndroidOnLinux_1.INT.udn index 87c06043ba26..a4c2e8fa5432 100644 --- a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/1/AndroidOnLinux_1.INT.udn +++ b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/1/AndroidOnLinux_1.INT.udn @@ -1,6 +1,6 @@ -Availability: Docs +Availability: Public Title: 1 - Required Setup -Crumbs: +Crumbs:%ROOT% Description:Learn how to install and set up the Android SDK for mobile game development with UE4 on Linux. Version: 4.14 type:quick start @@ -15,19 +15,24 @@ Contributor:yaakuro [EXCERPT:AndroidLinux_1] Unreal Engine 4 (UE4) uses a special version of the Android Software Development Kit (SDK), called CodeWorks for -Android 1R5. This version of CodeWorks for Android is the easiest way to set up the SDK and Native Development Kit (NDK) -needed to develop Android projects with UE4. If you have other versions of the Android SDK installed (or, older versions of CodeWorks for +Android. CodeWorks for Android is the easiest way to set up the SDK and Native Development Kit (NDK) +needed to develop Android projects with UE4. If you have older versions (prior to version 1R5) of the Android SDK installed (or, older versions of CodeWorks for Android), we recommend that you uninstall them and install [CodeWorks for Android](https://developer.nvidia.com/codeworks-android), using the CodeWorks for Android installer that's being distributed with UE4. [REGION:note] -Please note that we've bundled the CodeWorks for Android installer with UE4 to make sure that your Android SDK will be compatible with Unreal Engine. +We've bundled the CodeWorks for Android installer with UE4 to make sure that your Android SDK will be compatible with Unreal Engine. +It's important to note that, as of Unreal Engine, version 4.16, UE4 includes CodeWorks for Android 1R6u1. [/REGION] ## Installing CodeWorks for Android +For the purpose of showing you how to get started with Android on Linux, we will use CodeWorks for Android 1R5 while working with Unreal Engine, version 4.14. +UE4 should be closed before installing CodeWorks for Android 1R5. Also, please make sure that you have Java Development Kit 8 (JDK 8) installed, with your `JAVA_HOME` environment variable set to the correct version of the Java Development Kit (JDK). +To verify that `JAVA_HOME` is set properly, enter `echo $JAVA_HOME` into the terminal. If you don't see the correct JDK version, [download JDK 8](http://www.oracle.com/technetwork/java/javase/downloads/index.html), and install it on your Linux computer, making sure to set the `JAVA_HOME` environment variable to the newly installed JDK. + [REGION:warning] -UE4 should be closed before installing CodeWorks for Android 1R5. Also, please make sure that you have Java Development Kit 8 (JDK 8) installed. +Before continuing, please note that Android Vulkan on Linux is not supported at this time. [/REGION] 1. Getting started, open the Terminal and navigate to the `[UE4Root]` folder that contains the compiled engine (using the `cd` command, changing the shell working directory). diff --git a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/1/AndroidOnLinux_1.JPN.udn b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/1/AndroidOnLinux_1.JPN.udn index 0dd4606a2eed..6655113ac677 100644 --- a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/1/AndroidOnLinux_1.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/1/AndroidOnLinux_1.JPN.udn @@ -1,7 +1,7 @@ -INTSourceChangelist:3313485 -Availability:Docs +INTSourceChangelist:3457813 +Availability:Public Title:1 - 必要な設定 -Crumbs: +Crumbs:%ROOT% Description: Linux で UE4 を使ってモバイル ゲーム開発用 Android SDK のインストールおよび設定方法を説明します。 Version:4.14 type:quick start @@ -10,31 +10,37 @@ order:1 tags:Linux SkillLevel:Intermediate Checkpoint:AndroidOnLinuxQS +Contributor:yaakuro [nav] [EXCERPT:AndroidLinux_1] -アンリアル エンジン (UE4) は CodeWorks for Android 1R5 という Android ソフトウェア開発キット (SDK) の -特別バージョンを採用しています。CodeWorks for Android の特別バージョンを使うと、 -UE4 で Android プロジェクトを開発するために必要な SDK および Native Development Kit (NDK) の設定を一番簡単に行うことができます。違うバージョンの Android SDK (あるいは、CodeWorks for Android の古いバージョン) をインストールしている場合は、 -それをアンインストールして、UE4 が配布している CodeWorks for Android インストーラーを使って、 -CodeWorks for Android (https://developer.nvidia.com/codeworks-android) をインストールすることを推奨します。 +アンリアル エンジン (UE4) は CodeWorks for Android という Android ソフトウェア開発キット (SDK) の +特別バージョンです。CodeWorks for Android を使うと、 +UE4 で Android プロジェクトを開発するために必要な SDK および Native Development Kit (NDK) の設定を一番簡単に行うことができます。Android SDK の古いバージョン (1R5 より前) をインストールしている場合 (または CodeWorks for Android の古いバージョン) は、 +それをアンインストールし、UE4 が配布している CodeWorks for Android インストーラーを使って、 +[CodeWorks for Android](https://developer.nvidia.com/codeworks-android) をインストールすることを推奨します。 [REGION:note] -UE4 に込みこまれている CodeWorks for Android インストーラーを使えば、必ずアンリアル エンジンと互換性のある Android SDK がインストールされることに注目してください。 +CodeWorks for Android インストーラは UE4 とセットになっているので、アンリアル エンジンと互換性のある Android SDK が必ずインストールされます。 +アンリアル エンジン 4.16 では、CodeWorks for Android 1R6u1 が組み込まれていますので、十分に注意してください。 [/REGION] ## CodeWorks for Android のインストール手順 +Linux で Android を開始する手順を説明するために、アンリアル エンジン 4.14 で CodeWorks for Android 1R5 を使用します。 +CodeWorks for Android 1R5 をインストールする前に UE4 を終了してください。また、Java Development Kit 8 (JDK 8) が、Java Development Kit (JDK) の正しいバージョンに設定された `JAVA_HOME` 環境変数でインストールされていることも確認してください。 +`JAVA_HOME` の設定が正しいか確認するには、ターミナルに `echo $JAVA_HOME` と入力します。正しい JDK のバージョンが表示されない場合は、`JAVA_HOME` 環境変数を新しくインストールした JDK に設定されていることを確認しながら [download JDK 8](http://www.oracle.com/technetwork/java/javase/downloads/index.html) から Linux コンピューターにインストールします。 + [REGION:warning] -CodeWorks for Android 1R5 をインストールする前に UE4 を終了してください。また、Java Development Kit 8 (JDK 8) がインストールされていることも確認してください。 +先へ進む前に、Android Vulkan は Linux ではまだサポートされていないことにご注意ください。 [/REGION] 1. はじめに、Terminal を開き、コンパイルされたエンジンが入っている `[UE4Root]` フォルダを開きます (`cd` コマンドを使ってシェル作業ディレクトリを変更します)。 ![](LinuxAndroid_Step0.png)(w:900) -1. ターミナルに以下のコマンドを入力して、`[UE4Root]` フォルダの中から CodeWorks for Android 1R5 バイナリ ファイル (**CodeWorksforAndroid-1R5-linux-x64.run**) を開きます: `cd Engine/Extras/AndroidWorks/Linux` +1. ターミナルにコマンド `cd Engine/Extras/AndroidWorks/Linux` を入力して、`[UE4Root]` フォルダの中から CodeWorks for Android 1R5 バイナリ ファイル (**CodeWorksforAndroid-1R5-linux-x64.run**) を開きます。 ![](LinuxAndroid_Step1.png)(w:900) @@ -42,7 +48,7 @@ CodeWorks for Android 1R5 をインストールする前に UE4 を終了して ![](LinuxAndroid_Step2.png)(w:900) - **CodeWorksforAndroid-1R5-linux-x64.run** がまだ実行ができる状態ではないことがファイルの許可設定に表示されます。 + **CodeWorksforAndroid-1R5-linux-x64.run** がまだ実行可能な状態でないことがファイルの許可設定に表示されます。 CodeWorks for android 1R5 binary を実行可能な状態にするには、'execute' が許可されるようにファイルのアクセス権を変更する必要があります。 1. `CodeWorksforAndroid-1R5-linux-x64.run` のファイル許可設定を変更するには、ターミナルに `chmod +x CodeWorksforAndroid-1R5-linux-x64.run` と入力して、通常の実行ファイルのように実行可能にします。 @@ -107,12 +113,12 @@ CodeWorks for Android 1R5 をインストールする前に UE4 を終了して ![](LinuxAndroid_Step15.png)(w:900) -1. 次のステップへ進むまえにコンピュータを必ず再起動してください。 +1. 次のステップへ進む前に、コンピュータを必ず再起動してください。 ![](LinuxAndroid_Note16.png)(w:900) [REGION:tip] - Ubuntu の GUI を使いたくなければ、ターミナルに `sudo reboot` と入力してコンユーターを再起動します。 + Ubuntu の GUI を使わない場合は、ターミナルに `sudo reboot` と入力してからコンピューターを再起動します。 @@ -121,7 +127,7 @@ CodeWorks for Android 1R5 をインストールする前に UE4 を終了して ## 結果 -ここまでで、Linux で UE4 を使ったモバイル ゲーム開発の最初の準備となる Android SDK のインストールが完了しました。 +このステップで、Linux で UE4 を使ったモバイル ゲーム開発の最初の準備となる Android SDK のインストールが完了しました。 次のステップでは、Android デバイスに開発環境を設定する方法を説明します。 [nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/1/AndroidOnLinux_1.KOR.udn b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/1/AndroidOnLinux_1.KOR.udn index 1d7bbde8bfdd..59f3f311e8fd 100644 --- a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/1/AndroidOnLinux_1.KOR.udn +++ b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/1/AndroidOnLinux_1.KOR.udn @@ -1,7 +1,7 @@ -INTSourceChangelist:3351873 -Availability: Docs +INTSourceChangelist:0 +Availability: Public Title: 1 - Required Setup -Crumbs: +Crumbs:%ROOT% Description:Learn how to install and set up the Android SDK for mobile game development with UE4 on Linux. Version: 4.14 type:quick start @@ -16,19 +16,24 @@ Contributor:yaakuro [EXCERPT:AndroidLinux_1] Unreal Engine 4 (UE4) uses a special version of the Android Software Development Kit (SDK), called CodeWorks for -Android 1R5. This version of CodeWorks for Android is the easiest way to set up the SDK and Native Development Kit (NDK) -needed to develop Android projects with UE4. If you have other versions of the Android SDK installed (or, older versions of CodeWorks for +Android. CodeWorks for Android is the easiest way to set up the SDK and Native Development Kit (NDK) +needed to develop Android projects with UE4. If you have older versions (prior to version 1R5) of the Android SDK installed (or, older versions of CodeWorks for Android), we recommend that you uninstall them and install [CodeWorks for Android](https://developer.nvidia.com/codeworks-android), using the CodeWorks for Android installer that's being distributed with UE4. [REGION:note] -Please note that we've bundled the CodeWorks for Android installer with UE4 to make sure that your Android SDK will be compatible with Unreal Engine. +We've bundled the CodeWorks for Android installer with UE4 to make sure that your Android SDK will be compatible with Unreal Engine. +It's important to note that, as of Unreal Engine, version 4.16, UE4 includes CodeWorks for Android 1R6u1. [/REGION] ## Installing CodeWorks for Android +For the purpose of showing you how to get started with Android on Linux, we will use CodeWorks for Android 1R5 while working with Unreal Engine, version 4.14. +UE4 should be closed before installing CodeWorks for Android 1R5. Also, please make sure that you have Java Development Kit 8 (JDK 8) installed, with your `JAVA_HOME` environment variable set to the correct version of the Java Development Kit (JDK). +To verify that `JAVA_HOME` is set properly, enter `echo $JAVA_HOME` into the terminal. If you don't see the correct JDK version, [download JDK 8](http://www.oracle.com/technetwork/java/javase/downloads/index.html), and install it on your Linux computer, making sure to set the `JAVA_HOME` environment variable to the newly installed JDK. + [REGION:warning] -UE4 should be closed before installing CodeWorks for Android 1R5. Also, please make sure that you have Java Development Kit 8 (JDK 8) installed. +Before continuing, please note that Android Vulkan on Linux is not supported at this time. [/REGION] 1. Getting started, open the Terminal and navigate to the `[UE4Root]` folder that contains the compiled engine (using the `cd` command, changing the shell working directory). diff --git a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/2/AndroidOnLinux_2.INT.udn b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/2/AndroidOnLinux_2.INT.udn index ca01379c676d..a99b63211ba5 100644 --- a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/2/AndroidOnLinux_2.INT.udn +++ b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/2/AndroidOnLinux_2.INT.udn @@ -1,6 +1,6 @@ -Availability: Docs +Availability: Public Title: 2 - Setting up your Android Device -Crumbs: +Crumbs:%ROOT% Description:Learn how to enable an Android's development environment. Version: 4.14 type:quick start @@ -46,8 +46,9 @@ Make sure you have access to a USB cable prior to commencing the following steps [/REGION] [REGION:note] - If you don't see this item, you'll need to enable **Developer Options** on your device. For instructions on how to enable Developer Options on Android devices, - visit [Android's User Guide](https://developer.android.com/studio/run/device.html). + If you don't see this item, you'll need to enable **Developer Options** on your device. To enable **Developer Options**, open the **Settings** application, scroll to the bottom and select **About phone**. + After selecting **About phone** scroll to the bottom and tap **Build number** seven (7) times. + For additional instructions on how to enable Developer Options on Android devices, visit [Android's User Guide](https://developer.android.com/studio/debug/dev-options.html). [/REGION] ## Enabling USB Debugging diff --git a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/2/AndroidOnLinux_2.JPN.udn b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/2/AndroidOnLinux_2.JPN.udn index ffde3aa2298c..5edbd71a17f8 100644 --- a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/2/AndroidOnLinux_2.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/2/AndroidOnLinux_2.JPN.udn @@ -1,7 +1,7 @@ -INTSourceChangelist:3313485 -Availability:Docs +INTSourceChangelist:3457813 +Availability:Public Title:2 - Android デバイスを設定する -Crumbs: +Crumbs:%ROOT% Description:Android の開発環境を有効にする方法を説明します。 Version:4.14 type:quick start @@ -10,10 +10,11 @@ order:2 tags:Linux SkillLevel:Intermediate Checkpoint:AndroidOnLinuxQS +Contributor:yaakuro [nav] -Linux コンピューターに Android SDK をインストールが完了しました。 +Linux コンピューターへの Android SDK のインストールが完了しました。 Android デバイス向けモバイル ゲームの開発環境まであと少しです。ただし、Android デバイスでアンリアル エンジンによるゲームを実行するためには、 Android の開発環境を有効にする必要があります。 @@ -21,7 +22,7 @@ Android の開発環境を有効にする必要があります。 次のステップを開始する前に、USB ケーブルへアクセス可能なことを確認してください。 [/REGION] -## Android の Developer Options +## Android の Developer Options を有効にする方法 [EXCERPT:AndroidLinux_2] 1. Android デバイスを USB ケーブルで Linux コンピューターに接続します。 @@ -46,11 +47,12 @@ Android の開発環境を有効にする必要があります。 [/REGION] [REGION:note] - このメニューが表示されない場合は、デバイスの [Developer Options] を有効にしてください。Android デバイスの Developer Option を有効にする方法については、 - [Android ユーザーガイド](https://developer.android.com/studio/run/device.html) をご覧ください。 + このメニューが表示されない場合は、デバイスの [Developer Options] を有効にしてください。**[Developer Options]** を有効にするには、**[Settings]** アプリケーションを開き、下までスクロールして **[About phone]** を選択します。 + **[About phone]** を選択したら、一番下までスクロールし、**[Build number]** を 7 回タップします。 + Android デバイスで Developer Option を有効にする方法については、[Android ユーザーガイド](https://developer.android.com/studio/debug/dev-options.html) をご覧ください。 [/REGION] -## USB デバッグを有効にする +## USB デバッグを有効にする方法 1. **[Developer Options]** メニューの **[USB debugging]** を有効にします。 @@ -62,7 +64,7 @@ Android の開発環境を有効にする必要があります。 クリックしてフルサイズで表示 [/REGION] -1. ウィンドウが表示されたら、USB debugging を有効にする選択がされていることを確認します。表示された内容を確認したら **[OK]** ボタンをタップします。 +1. ウィンドウが表示されたら USB デバッグの有効化を確定します。表示された内容を確認したら **[OK]** ボタンをタップします。 [REGION:lightbox] [![](LinuxAndroid_Step20.png)(w:180)](LinuxAndroid_Step20.png) @@ -72,10 +74,10 @@ Android の開発環境を有効にする必要があります。 クリックしてフルサイズで表示 [/REGION] - これで USB debugging が有効になりました。 + これで USB デバッグが有効になりました。 ![](LinuxAndroid_Step20Note.png) -1. Android デバイスを USB ケーブルから外して、数秒おいて、再度接続します。デバイスが Android 4.2.2 以上で実行されている場合、以下のダイアログが表示され、Linux コンピューターでデバッグを可能にする RSA キーを許可するか聞かれます。**OK** ボタンをタップする前に **[Always allow from this computer (このコンピューターを常に許可する)]** の横のチェックボックスが選択されていることを確認してください。 +1. Android デバイスを USB ケーブルから外して、数秒待ってから再度接続します。デバイスが Android 4.2.2 以上で実行されている場合、以下のダイアログが表示され、Linux コンピューターでデバッグを可能にする RSA キーを許可するか聞かれます。**OK** ボタンをタップする前に **[Always allow from this computer (このコンピューターを常に許可する)]** の横のチェックボックスが選択されていることを確認してください。 [REGION:lightbox] [![](LinuxAndroid_Step21.png)(w:180)](LinuxAndroid_Step21.png) @@ -97,9 +99,9 @@ Linux コンピューターにつながっているデバイスの一覧が表 [REGION:note] ターミナルに `adb devices` と入力してもデバイスが表示されない場合、Linux コンピューターに adb を設定する必要があるかもしれません。[Android Debug Bridge ユーザーガイド](https://developer.android.com/studio/command-line/adb.html) を参照してください。 adb の詳細、コンピューターにプログラムを設定する方法が説明されています。 - コンピューターに確かに adb をインストールおよび設定を行っている場合は、以下のトラブルシューティングを試してください。 + コンピューターに adb を確実にインストールおよび設定している場合は、以下のトラブルシューティングをお試しください。 - * コンピューターから Android デバイスを一旦外して、再度接続する。 + * コンピューターから一旦 Android デバイスを外して、再度接続する。 * **[Always allow from this computer (このコンピューターを常に許可する)]** の横のチェックボックスが選択されていることを確認してください。 * デバイスが許可されていないと表示される場合、Android デバイスに Linux コンピューターに USB debugging の権限を与える必要があるかもしれません。 * Media Transfer Protocol (MTP) を使ったメディア デバイスとして接続されている場合、正しく設定してもデバイスが表示されない場合があります。 diff --git a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/2/AndroidOnLinux_2.KOR.udn b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/2/AndroidOnLinux_2.KOR.udn index cfbeb47a3c9e..06717443c00e 100644 --- a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/2/AndroidOnLinux_2.KOR.udn +++ b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/2/AndroidOnLinux_2.KOR.udn @@ -1,7 +1,7 @@ -INTSourceChangelist:3351873 -Availability: Docs +INTSourceChangelist:0 +Availability: Public Title: 2 - Setting up your Android Device -Crumbs: +Crumbs:%ROOT% Description:Learn how to enable an Android's development environment. Version: 4.14 type:quick start @@ -47,8 +47,9 @@ Make sure you have access to a USB cable prior to commencing the following steps [/REGION] [REGION:note] - If you don't see this item, you'll need to enable **Developer Options** on your device. For instructions on how to enable Developer Options on Android devices, - visit [Android's User Guide](https://developer.android.com/studio/run/device.html). + If you don't see this item, you'll need to enable **Developer Options** on your device. To enable **Developer Options**, open the **Settings** application, scroll to the bottom and select **About phone**. + After selecting **About phone** scroll to the bottom and tap **Build number** seven (7) times. + For additional instructions on how to enable Developer Options on Android devices, visit [Android's User Guide](https://developer.android.com/studio/debug/dev-options.html). [/REGION] ## Enabling USB Debugging diff --git a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/3/AndroidOnLinux_3.INT.udn b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/3/AndroidOnLinux_3.INT.udn index b12f9abb48fb..4090f3579764 100644 --- a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/3/AndroidOnLinux_3.INT.udn +++ b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/3/AndroidOnLinux_3.INT.udn @@ -1,6 +1,6 @@ -Availability: Docs +Availability: Public Title: 3 - Creating your Project -Crumbs: +Crumbs:%ROOT% Description:Learn how to create an Android mobile game project in UE4. Version: 4.14 type:quick start diff --git a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/3/AndroidOnLinux_3.JPN.udn b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/3/AndroidOnLinux_3.JPN.udn index 71e676b93de5..539fba9ef502 100644 --- a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/3/AndroidOnLinux_3.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/3/AndroidOnLinux_3.JPN.udn @@ -1,7 +1,7 @@ -INTSourceChangelist:3293293 -Availability:Docs +INTSourceChangelist:3457813 +Availability:Public Title:3 - プロジェクトを作成する -Crumbs: +Crumbs:%ROOT% Description: UE4 で Android モバイル ゲーム プロジェクトの作成方法を説明します。 Version:4.14 type:quick start @@ -10,10 +10,11 @@ order:3 tags:Linux SkillLevel:Intermediate Checkpoint:AndroidOnLinuxQS +Contributor:yaakuro [nav] -ここまでのステップで、Android SDK のインストールto設定、Android の開発環境のセットアップ、そして Android Debug Bridge が Linux コンピューターに接続中のデバイス一覧を表示できるようになりました。 +ここまでのステップで、Android SDK のインストールおよび設定、Android の開発環境のセットアップが完了し、Android Debug Bridge が Linux コンピューターに接続中のデバイス一覧を表示できるようになりました。 UE4 でモバイル プロジェクトの新規作成ができる状態になりました。 ## モバイル プロジェクトを作成する diff --git a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/3/AndroidOnLinux_3.KOR.udn b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/3/AndroidOnLinux_3.KOR.udn index 95484e644d7f..a0dd88ae4bdc 100644 --- a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/3/AndroidOnLinux_3.KOR.udn +++ b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/3/AndroidOnLinux_3.KOR.udn @@ -1,7 +1,7 @@ -INTSourceChangelist:3351873 -Availability: Docs +INTSourceChangelist:0 +Availability: Public Title: 3 - Creating your Project -Crumbs: +Crumbs:%ROOT% Description:Learn how to create an Android mobile game project in UE4. Version: 4.14 type:quick start diff --git a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/4/AndroidOnLinux_4.INT.udn b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/4/AndroidOnLinux_4.INT.udn index a8d851440af1..502d2d807671 100644 --- a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/4/AndroidOnLinux_4.INT.udn +++ b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/4/AndroidOnLinux_4.INT.udn @@ -1,6 +1,6 @@ -Availability: Docs +Availability: Public Title: 4 - Deploying your Level -Crumbs: +Crumbs:%ROOT% Description:Learn how to deploy a level onto your Android device from UE4. Version: 4.14 type:quick start @@ -24,8 +24,9 @@ Prior to deploying your application, refer to this list, which was written to he * Although it may seem like an obvious consideration, please make sure that the Android device is properly connected to your computer. * If you already haven't done so, verify that Android Debug Bridge (adb) lists your connected device(s). To learn more about adb, enter `adb --help` into the terminal. You can also refer to the [Android Debug Bridge User Guide](https://developer.android.com/studio/command-line/adb.html) to learn more about adb and how to set up the program on your computer. -* In order to properly build, cook, package, and deploy your game to Android, you'll need to have JDK 8 installed, with your `JAVA_HOME` environment variable set to the correct version of the JDK. To verify that `JAVA_HOME` is set properly, enter `echo $JAVA_HOME` into the terminal. If you don't see the correct JDK version, [download JDK 8](http://www.oracle.com/technetwork/java/javase/downloads/index.html), and install it on your Linux computer, making sure to set the `JAVA_HOME` environment variable to the newly installed JDK. -* Make sure that you're building for the appropriate ARM architecture, because if you don't, your project won't deploy properly. After verifying the instruction set that'll work on your device, you can select the appropriate ARM architecture support from inside the Editor by navigating to **Edit > Project Settings... > Android > Build**, and selecting either **Support arm7** or **Support arm64**. Currently, we don't provide **Vulkan** rendering support from UE4 on Linux. +* In order to properly build, cook, package, and deploy your game to Android, you'll need to have JDK 8 installed, with your `JAVA_HOME` environment variable set to the correct version of the JDK. To verify that `JAVA_HOME` is set properly, enter `echo $JAVA_HOME` into the terminal. If you don't see the correct JDK version, [download JDK 8](http://www.oracle.com/technetwork/java/javase/downloads/index.html), and install it on your Linux computer, making sure to set the `JAVA_HOME` environment variable to the newly installed JDK. You can set the `JAVA_HOME` environment variable in the [Android SDK Project Settings](https://developer.android.com/studio/command-line/variables.html). +* Make sure that you're building for the appropriate ARM architecture, because if you don't, your project won't deploy properly. After verifying the instruction set that'll work on your device, you can select the appropriate ARM architecture support from inside the Editor by navigating to **Edit > Project Settings... > Android > Build**, and selecting either **Support arm7** or **Support arm64**. +* Currently, we don't provide **Vulkan** rendering support from UE4 on Linux. * Different Android devices uniquely support a variety of texture formats. If you don't know which texture formats are supported by your Android device, try setting your target texture to the Ericsson Texture Compression 1 (ETC 1) compression scheme, which should be supported by most Android devices. To learn more about supporting multiple textures, check out Android's documentation on [Creating Multiple APKs for Different GL Textures](https://developer.android.com/training/multiple-apks/texture.html). #### Reviewing Available Texture Formats diff --git a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/4/AndroidOnLinux_4.JPN.udn b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/4/AndroidOnLinux_4.JPN.udn index 31647705fcd4..3caca1b57a52 100644 --- a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/4/AndroidOnLinux_4.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/4/AndroidOnLinux_4.JPN.udn @@ -1,7 +1,7 @@ -INTSourceChangelist:3298293 -Availability:Docs +INTSourceChangelist:3457813 +Availability:Public Title:4 - レベルをデプロイする -Crumbs: +Crumbs:%ROOT% Description:UE4 から Android デバイスにレベルをデプロイする方法 Version:4.14 type:quick start @@ -10,6 +10,7 @@ order:4 tags:Linux SkillLevel:Intermediate Checkpoint:AndroidOnLinuxQS +Contributor:yaakuro [nav] @@ -18,25 +19,26 @@ Checkpoint:AndroidOnLinuxQS 細かい点にいろいろ注意する必要があります。**ThirdPersonExampleMap** レベルを Android デバイスにデプロイする前に、 最も一般的な配慮事項のいくつか説明します。 -## Linux でのデプロイ前の配慮事項 +## Linux でのデプロイ前の考慮事項 -ゲームのデバイスへのデプロイ中によく起こる可能性がある問題を避けるために書かれたこのリストを、アプリケーションをデプロイする前に今一度ご確認ください。 +これらはゲームのデバイスへのデプロイ中によく起こる可能性がある問題を避けるための考慮事項です。アプリケーションをデプロイする前に今一度ご確認ください。 -* 当たり前のように思うかもしれませんが、Android デバイスがコンピューターに正しく接続されているか確認してください。 -* そのようになっていない場合、Android Debug Bridge (adb) に接続するデバイスが入っているか確認してください。Adb の詳細は、ターミナルに `adb --help` と入力すれば表示されます。[Android Debug Bridge ユーザー ガイド](https://developer.android.com/studio/command-line/adb.html) でも adb およびコンピューターでのプログラム設定方法について説明しています。 -* ゲームを Android に正しくビルド、クック、パッケージ化、デプロイするためには、`JAVA_HOME` 環境変数を JDK の正しいバージョンに設定して、JDK 8 をインストールする必要があります。`JAVA_HOME` の設定が正しいか確認するには、ターミナルに `echo $JAVA_HOME` と入力します。正しい JDK のバージョンが表示されない場合は、[download JDK 8](http://www.oracle.com/technetwork/java/javase/downloads/index.html) から Linux コンピューターにインストールし、`JAVA_HOME` 環境変数を新しくインストールした JDK に設定します。 -* 適切な ARM アーキテクチャにビルドしていることを確認してください。そうでないとプロジェクトが正しくデプロイできません。デバイスで使用できるインストラクション セットを確認したら、**[Edit] > [Project Settings...] > [Android] > [Build]** から **[Support arm7]** または **[Support arm64]** を選択すれば、適切な ARM アーキテクチャ サポートをエディタ内から選択することができます。現時点では、UE4 は Linux 上での **Vulkan** レンダリングはサポートしていません。 -* Android デバイスは、各種それぞれがテクスチャ形式をユニークにサポートしています。Android デバイスでサポートされているテクスチャ形式が分からない場合は、ほとんどの Android デバイスでサポートされている Ericsson Texture Compression 1 (ETC 1) 圧縮スキームにターゲット テクスチャを設定してみてください。複数のテクスチャに対するサポートについては、[Creating Multiple APKs for Different GL Textures](https://developer.android.com/training/multiple-apks/texture.html) の Android に関する文書を参照してください。 +* 当たり前ですが、Android デバイスがコンピューターに正しく接続されているか確認してください。 +* そうでない場合、Android Debug Bridge (adb) に接続するデバイスが入っているか確認してください。Adb の詳細は、ターミナルに `adb --help` と入力すると表示されます。[Android Debug Bridge ユーザー ガイド](https://developer.android.com/studio/command-line/adb.html) でも adb およびコンピューターでのプログラム設定方法について説明しています。 +* ゲームを Android に正しくビルド、クック、パッケージ化、デプロイするためには、`JAVA_HOME` 環境変数を JDK の正しいバージョンに設定して、JDK 8 をインストールする必要があります。`JAVA_HOME` の設定が正しいか確認するには、ターミナルに `echo $JAVA_HOME` と入力します。正しい JDK のバージョンが表示されない場合は、[download JDK 8](http://www.oracle.com/technetwork/java/javase/downloads/index.html) から Linux コンピューターにインストールし、`JAVA_HOME` 環境変数を新しくインストールした JDK に設定します。[Android SDK プロジェクト設定](https://developer.android.com/studio/command-line/variables.html) で `JAVA_HOME` 環境変数を設定することができます。 +* 適切な ARM アーキテクチャにビルドしていることを確認してください。そうでないとプロジェクトが正しくデプロイできません。デバイスで使用できるインストラクション セットを確認したら、**[Edit] > [Project Settings...] > [Android] > [Build]** から **[Support arm7]** または **[Support arm64]** を選択すれば、適切な ARM アーキテクチャ サポートをエディタ内から選択することができます。 +* 現時点では、UE4 は Linux 上での **Vulkan** レンダリングはサポートしていません。 +* それぞれの Android デバイスが、多様なテクスチャ形式をユニークにサポートしています。Android デバイスでサポートされているテクスチャ形式が分からない場合は、Ericsson Texture Compression 1 (ETC 1) 圧縮スキームにターゲット テクスチャを設定してください。ほとんどの Android デバイスでサポートされているテクスチャです。複数のテクスチャに対するサポートについては、[Creating Multiple APKs for Different GL Textures](https://developer.android.com/training/multiple-apks/texture.html) の Android に関する文書を参照してください。 #### サポート対象のテクスチャ形式 -以下は Android デバイスでサポートされることが多いテクスチャ形式と概要です。 +以下は Android デバイスでサポートされることが多いテクスチャ形式の概要です。 [INCLUDE:Platforms/Android/Reference#androidformats] ## レベルをデプロイする -Android デバイスにゲームをデプロイする際の最重要事項を確認したので、ゲームのデプロイを開始しましょう。 +Android デバイスにゲームをデプロイするための最重要事項を確認したので、ゲームのデプロイを開始しましょう。 1. まず、**ThirdPersonExampleMap** が開いていることを確認してください。 @@ -90,7 +92,7 @@ Android デバイスにゲームをデプロイする際の最重要事項を確 ![](LinuxAndroid_Step29.png) -## サポート対象のテクスチャ形式を決定する +## サポート対象のテクスチャ形式を決定する方法 使用する Android デバイスでサポートされているテクスチャ形式が分からない場合は、次の手順を試してください。 diff --git a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/4/AndroidOnLinux_4.KOR.udn b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/4/AndroidOnLinux_4.KOR.udn index c1d847e5103a..39248955e4ad 100644 --- a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/4/AndroidOnLinux_4.KOR.udn +++ b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/4/AndroidOnLinux_4.KOR.udn @@ -1,7 +1,7 @@ -INTSourceChangelist:3351873 -Availability: Docs +INTSourceChangelist:0 +Availability: Public Title: 4 - Deploying your Level -Crumbs: +Crumbs:%ROOT% Description:Learn how to deploy a level onto your Android device from UE4. Version: 4.14 type:quick start @@ -25,8 +25,9 @@ Prior to deploying your application, refer to this list, which was written to he * Although it may seem like an obvious consideration, please make sure that the Android device is properly connected to your computer. * If you already haven't done so, verify that Android Debug Bridge (adb) lists your connected device(s). To learn more about adb, enter `adb --help` into the terminal. You can also refer to the [Android Debug Bridge User Guide](https://developer.android.com/studio/command-line/adb.html) to learn more about adb and how to set up the program on your computer. -* In order to properly build, cook, package, and deploy your game to Android, you'll need to have JDK 8 installed, with your `JAVA_HOME` environment variable set to the correct version of the JDK. To verify that `JAVA_HOME` is set properly, enter `echo $JAVA_HOME` into the terminal. If you don't see the correct JDK version, [download JDK 8](http://www.oracle.com/technetwork/java/javase/downloads/index.html), and install it on your Linux computer, making sure to set the `JAVA_HOME` environment variable to the newly installed JDK. -* Make sure that you're building for the appropriate ARM architecture, because if you don't, your project won't deploy properly. After verifying the instruction set that'll work on your device, you can select the appropriate ARM architecture support from inside the Editor by navigating to **Edit > Project Settings... > Android > Build**, and selecting either **Support arm7** or **Support arm64**. Currently, we don't provide **Vulkan** rendering support from UE4 on Linux. +* In order to properly build, cook, package, and deploy your game to Android, you'll need to have JDK 8 installed, with your `JAVA_HOME` environment variable set to the correct version of the JDK. To verify that `JAVA_HOME` is set properly, enter `echo $JAVA_HOME` into the terminal. If you don't see the correct JDK version, [download JDK 8](http://www.oracle.com/technetwork/java/javase/downloads/index.html), and install it on your Linux computer, making sure to set the `JAVA_HOME` environment variable to the newly installed JDK. You can set the `JAVA_HOME` environment variable in the [Android SDK Project Settings](https://developer.android.com/studio/command-line/variables.html). +* Make sure that you're building for the appropriate ARM architecture, because if you don't, your project won't deploy properly. After verifying the instruction set that'll work on your device, you can select the appropriate ARM architecture support from inside the Editor by navigating to **Edit > Project Settings... > Android > Build**, and selecting either **Support arm7** or **Support arm64**. +* Currently, we don't provide **Vulkan** rendering support from UE4 on Linux. * Different Android devices uniquely support a variety of texture formats. If you don't know which texture formats are supported by your Android device, try setting your target texture to the Ericsson Texture Compression 1 (ETC 1) compression scheme, which should be supported by most Android devices. To learn more about supporting multiple textures, check out Android's documentation on [Creating Multiple APKs for Different GL Textures](https://developer.android.com/training/multiple-apks/texture.html). #### Reviewing Available Texture Formats diff --git a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/5/AndroidOnLinux_5.INT.udn b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/5/AndroidOnLinux_5.INT.udn index 13c43d690028..b3043261da94 100644 --- a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/5/AndroidOnLinux_5.INT.udn +++ b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/5/AndroidOnLinux_5.INT.udn @@ -1,6 +1,6 @@ -Availability: Docs +Availability: Public Title: 5 - Packaging your Game -Crumbs: +Crumbs:%ROOT% Description:Learn how to package your mobile game for distribution (release). Version: 4.14 type:quick start diff --git a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/5/AndroidOnLinux_5.JPN.udn b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/5/AndroidOnLinux_5.JPN.udn index 333b162c87bf..678a77094304 100644 --- a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/5/AndroidOnLinux_5.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/5/AndroidOnLinux_5.JPN.udn @@ -1,7 +1,7 @@ -INTSourceChangelist:3298293 -Availability:Docs +INTSourceChangelist:3457813 +Availability:Public Title:5 - ゲームをパッケージ化する -Crumbs: +Crumbs:%ROOT% Description:モバイル ゲームを配布 (リリース) 用にパッケージ化する方法を説明します。 Version:4.14 type:quick start @@ -10,12 +10,13 @@ order:5 tags:Linux SkillLevel:Intermediate Checkpoint:AndroidOnLinuxQS +Contributor:yaakuro [nav] -ここまでのチュートリアルでは、モバイル ゲーム プロジェクトを作成し Android デバイスにでデプロイしました。さらにゲームを配布可能にするには、プロジェクトをパッケージ化する必要があります。 -以下の手順では、Android プラットフォームにゲームをパッケージ化して配信可能にする方法を説明します。その前に、プロジェクトのパッケージ化は **Development** モードで行います。これをしっかり理解してください。まず最初に、テスト目的でゲームのパッケージ化を **Development** モードで行うことが -グッドプラクティスです。ゲームの仕上がりに納得したら、エンジンにコンソール 小マント、統計、プロファイリング ツールを削除するように指示する **Shipping** モードプロジェクトをパッケージ化することができます。 +ここまでのチュートリアルでは、モバイル ゲーム プロジェクトを作成し Android デバイスにでデプロイしました。ゲームを配布可能にするには、さらにプロジェクトをパッケージ化する必要があります。 +以下の手順では、Android プラットフォームにゲームをパッケージ化して配信可能にする方法を説明します。プロジェクトのパッケージ化は **Development** モードで行うということを、しっかり理解しておいてください。最初は、テスト目的でゲームのパッケージ化を **Development** モードで行うことが +グッドプラクティスです。ゲームの仕上がりに納得したら、エンジンがコンソール コマンド、統計、プロファイリング ツールを削除する **Shipping** モード プロジェクトをパッケージ化することができます。 [REGION:note] UE4 で使用できる各種ビルド コンフィギュレーションの違いについては、 [](Programming/Development/BuildConfigurations) ページを参照してください。 @@ -23,7 +24,7 @@ UE4 で使用できる各種ビルド コンフィギュレーションの違い ##プロジェクトをパッケージ化する [EXCERPT:AndroidLinux_5] -1. **[File]** メニューをスクロールして **[Package Project]** を選択し、**[Android]** 上にカーソルを合わせて **[Android (ETC1)]** を選択します。 +1. **[File]** メニューを開き、下にスクロールして **[Package Project]** を選択したら **[Android]** 上にカーソルを合わせて **[Android (ETC1)]** を選択します。 [REGION:lightbox] [![](LinuxAndroid_Step31.png)(w:720)](LinuxAndroid_Step31.png) @@ -33,7 +34,7 @@ UE4 で使用できる各種ビルド コンフィギュレーションの違い クリックしてフルサイズで表示 [/REGION] -1. **[Open Directory]** メニューが表示されたら、**[New Folder]** ボタンを使って `Android_Builds` という名前の新規フォルダを作成します。 +1. **[Open Directory]** メニューが表示されたら、**[New Folder]** ボタンを使って「`Android_Builds`」という名前の新規フォルダを作成します。 [REGION:lightbox] [![](LinuxAndroid_Step32.png)(w:720)](LinuxAndroid_Step32.png) @@ -53,7 +54,7 @@ UE4 で使用できる各種ビルド コンフィギュレーションの違い クリックしてフルサイズで表示 [/REGION] -1. UE4 がプロジェクトをパッケージ化している間、進捗バーが右下隅に表示されます。 +1. UE4 によるプロジェクト パッケージ化の間、進捗バーが右下隅に表示されます。 [REGION:lightbox] [![](LinuxAndroid_Step34.png)(w:720)](LinuxAndroid_Step34.png) @@ -63,7 +64,7 @@ UE4 で使用できる各種ビルド コンフィギュレーションの違い クリックしてフルサイズで表示 [/REGION] -1. 処理の最後に、パッケージ化が完了した旨を示すメッセージが表示されます。 +1. パッケージ化の最後に、処理の完了を示すメッセージが表示されます。 [REGION:lightbox] [![](LinuxAndroid_Step35.png)(w:720)](LinuxAndroid_Step35.png) @@ -73,7 +74,7 @@ UE4 で使用できる各種ビルド コンフィギュレーションの違い クリックしてフルサイズで表示 [/REGION] -1. **[Android_Builds]** フォルダを開くと、**「Android_ETC1」** というフォルダがあります。 +1. **[Android_Builds]** フォルダの中に **「Android_ETC1」** というフォルダがあります。 ![](LinuxAndroid_Step36.png) @@ -99,7 +100,7 @@ UE4 で使用できる各種ビルド コンフィギュレーションの違い [/REGION] [REGION:note] - このシェルスクリプトの実行がうまくいかない場合は、ターミナルに `adb devices` と入力して、デバイスがコンピューターに接続されているかを確認してください。 + このシェルスクリプトの実行がうまくいかない場合は、ターミナルに `adb devices` と入力して、デバイスのコンピューターへの接続状態を確認してください。 [/REGION] 1. インストール中、シェル スクリプトは以下の出力をターミナルにフラッシュします。 @@ -118,7 +119,7 @@ UE4 で使用できる各種ビルド コンフィギュレーションの違い [/EXCERPT:AndroidLinux_5] ## 結果 -インストール スクリプトにより Android デバイスへのゲームのインストールが完了し、プロジェクトがデバイスのアプリケーション ドロワーで見えるようになりました。 +インストール スクリプトにより Android デバイスへのゲームのインストールが完了し、プロジェクトがデバイスのアプリケーション ドロワーで表示されました。 [REGION:lightbox] [![](LinuxAndroid_Step5EndResult.png)(w:180)](LinuxAndroid_Step5EndResult.png) @@ -128,14 +129,14 @@ UE4 で使用できる各種ビルド コンフィギュレーションの違い クリックしてフルサイズで表示 [/REGION] -これで終わりです!以下について学習しました。 +これで終わりです!このステップで学習した内容です。 -✓ Linux で UE4 を使ってモバイルゲーム開発用 Android SDK のインストールおよび設定方法。 -✓ Android の開発環境を有効にする方法を説明します。 -✓ UE4 で Android モバイル ゲーム プロジェクトの作成方法を説明します。 -✓ UE4 から Android デバイスにレベルをデプロイする方法 +✓ Linux で UE4 を使ってモバイルゲーム開発用 Android SDK のインストールおよび設定方法 +✓ Android の開発環境を有効にする方法 +✓ UE4 で Android モバイル ゲーム プロジェクトの作成方法 +✓ UE4 から Android デバイスへのレベルのデプロイ方法 ✓ モバイル ゲームをリリース用にパッケージする方法 -次のページでは、今学んだ新しいスキルの応用方法について説明します。 +次のページでは、上記スキルの応用方法について説明します。 [nav] \ No newline at end of file diff --git a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/5/AndroidOnLinux_5.KOR.udn b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/5/AndroidOnLinux_5.KOR.udn index 1ecdeeb71685..ddefe75a6508 100644 --- a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/5/AndroidOnLinux_5.KOR.udn +++ b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/5/AndroidOnLinux_5.KOR.udn @@ -1,7 +1,7 @@ -INTSourceChangelist:3351873 -Availability: Docs +INTSourceChangelist:0 +Availability: Public Title: 5 - Packaging your Game -Crumbs: +Crumbs:%ROOT% Description:Learn how to package your mobile game for distribution (release). Version: 4.14 type:quick start diff --git a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/6/AndroidOnLinux_6.INT.udn b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/6/AndroidOnLinux_6.INT.udn index f96b7277004d..64c4f1d65926 100644 --- a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/6/AndroidOnLinux_6.INT.udn +++ b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/6/AndroidOnLinux_6.INT.udn @@ -1,6 +1,6 @@ -Availability: Docs +Availability: Public Title: 6 - On Your Own! -Crumbs: +Crumbs:%ROOT% Description:Do some exercises on your own. Version: 4.14 type:quick start diff --git a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/6/AndroidOnLinux_6.JPN.udn b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/6/AndroidOnLinux_6.JPN.udn index 6825029ab7be..95da7348d132 100644 --- a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/6/AndroidOnLinux_6.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/6/AndroidOnLinux_6.JPN.udn @@ -1,7 +1,7 @@ -INTSourceChangelist:3313485 -Availability:Docs +INTSourceChangelist:3457813 +Availability:Public Title:6 - 応用編 -Crumbs: +Crumbs:%ROOT% Description:実際に練習してみましょう。 Version:4.14 type:quick start @@ -10,17 +10,18 @@ order:6 tags:Linux SkillLevel:Intermediate Checkpoint:AndroidOnLinuxQS +Contributor:yaakuro [nav] モバイル ゲームの開発には、相当な注意力を要します。デバイス互換性、モバイルのパフォーマンス、スペース制限については特にそうです。 モバイル ゲームの開発中にベスト プラクティスを実施すると、モバイル ゲーム開発スキルを効率的にアップすることができます。 習得したベスト プラクティスを使ってモバイル コンテンツを作成したら、別のデプロイ メソッドでモバイル ゲームをプレビューおよびデプロイする方法を学びましょう。 -このページの最後には、習得したモバイル開発の新しいスキルを実践するための問題を追加しました。 +このページの最後にある実践問題で、習得したモバイル開発の新しいスキルの腕試しができます。 ## ベスト プラクティス -Andoird デバイス用のテンプレート モバイル UE4 プロジェクトの作成、パッケージ化、およびデプロイ方法を学習しました。次は、Linux でUE4 を使用したモバイル ゲームの作成に大きな影響を与えるデバイスの互換性、モバイル パフォーマンス、APK ベスト プラクティスについて考えてみましょう。 +ここまでのステップで、Andoird デバイス用のテンプレート モバイル UE4 プロジェクトの作成、パッケージ化、およびデプロイ方法を学習しました。次は、Linux でUE4 を使用したモバイル ゲームの作成に大きな影響を与えるデバイスの互換性、モバイル パフォーマンス、APK ベスト プラクティスについて考えてみましょう。 ####Android デバイスの互換性 @@ -33,9 +34,9 @@ Andoird デバイス用のテンプレート モバイル UE4 プロジェクト ####APK パッケージ サイズの縮小 -ターゲットとするハードウェアまたはソフトウェア プラットフォームに制限があるために、モバイル ゲーム自体のサイズ制限が必要な場合があります。モバイル ゲーム サイズを縮小するには、モバイル アプリケーションのパッケージ化に Android OS が使用するカスタム仕様ファイル形式 **Android Application Package** (APK) のサイズの縮小が必要な場合があります。パッケージ済みゲームのサイズを縮小する方法については、[APK パッケージ サイズの縮小方法](Platforms/Android/ReducingAPKSize) を参照してください。 +ターゲット ハードウェア / ソフトウェア プラットフォームの制約のため、モバイル ゲーム サイズの制限が必要な場合があります。モバイル ゲーム サイズを縮小するために、モバイル アプリケーションのパッケージ化に Android OS が使用するカスタム仕様ファイル形式である **Android Application Package** (APK) のサイズ縮小が必要な場合があります。パッケージ済みゲームのサイズ縮小方法については、[APK パッケージ サイズの縮小方法](Platforms/Android/ReducingAPKSize) を参照してください。 -## モバイル コンテンツの作成 +## モバイル コンテンツを作成する Linux で UE4 を使ってモバイル ゲームを開発する方法を学びました。実践として、デバイス使えるレンダリング機能を使ってゲーム コンテンツを作成すると良いと思います。以下のリファレンスを参照してください。 @@ -51,11 +52,11 @@ Linux で UE4 を使ってモバイル ゲームを開発する方法を学び ##ワイヤレス ネットワークでデプロイする -モバイル ゲーム コンテンツを作成し、エディタでモバイル ゲームをプレビューするベスト プラクティスを学習しました。それではゲームを Android デバイスまたはワイヤレス ネットワークにデプロイしてみましょう。ワイヤレス ネットワークで Android デバイスに UE4 プロジェクトをデプロイする方法は、[Gear VR Debugging リファレンス ページ](Platforms/GearVR/Debugging) を参照してください。 +モバイル ゲーム コンテンツを作成し、エディタでモバイル ゲームをプレビューするベスト プラクティスを学習しました。それではゲームを Android デバイスまたはワイヤレス ネットワークにデプロイしてみましょう。ワイヤレス ネットワークで Android デバイスに UE4 プロジェクトをデプロイする方法については、[Gear VR Debugging リファレンス ページ](Platforms/GearVR/Debugging) を参照してください。 ##実践問題 -モバイル ゲーム開発スキルをテストし続けるために、次のような練習問題をやってみましょう。 +モバイル ゲーム開発スキルを試したい方は、次の練習問題をやってみましょう。 * Third Person テンプレート以外を使って新規のモバイル プロジェクトを作成します。次に、そのプロジェクトを Android デバイスで実行してみます。 * 異なる Android テクスチャ形式を使ってプロジェクトをパッケージ化し、特定のデバイスで動く形式を文書化します。 diff --git a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/6/AndroidOnLinux_6.KOR.udn b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/6/AndroidOnLinux_6.KOR.udn index 4d8034af0e1d..900185068171 100644 --- a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/6/AndroidOnLinux_6.KOR.udn +++ b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/6/AndroidOnLinux_6.KOR.udn @@ -1,7 +1,7 @@ -INTSourceChangelist:3351873 -Availability: Docs +INTSourceChangelist:0 +Availability: Public Title: 6 - On Your Own! -Crumbs: +Crumbs:%ROOT% Description:Do some exercises on your own. Version: 4.14 type:quick start diff --git a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/AndroidOnLinux.INT.udn b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/AndroidOnLinux.INT.udn index bc220d0005c5..15e9e4db268b 100644 --- a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/AndroidOnLinux.INT.udn +++ b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/AndroidOnLinux.INT.udn @@ -1,6 +1,6 @@ -Availability: Docs +Availability: Public Title: Android On Linux Quick Start -Crumbs: +Crumbs:%ROOT% Description:Learn how to create, deploy, and package games to Android from Linux. Platform:Linux Version: 4.14 diff --git a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/AndroidOnLinux.JPN.udn b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/AndroidOnLinux.JPN.udn index 3fa5add57256..33dff9aeb835 100644 --- a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/AndroidOnLinux.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/AndroidOnLinux.JPN.udn @@ -1,7 +1,7 @@ -INTSourceChangeList:3298293 -Availability:Docs +INTSourceChangelist:3457813 +Availability:Public Title:Linux 上で Android 向けゲームを開発するためのクイックスタート ガイド -Crumbs: +Crumbs:%ROOT% Description:Linux 上で Android 向けゲームを開発する方法を学びます。 Platform:Linux Version:4.14 @@ -14,13 +14,14 @@ prereq:GettingStarted/RecommendedSpecifications prereq:Platforms/Linux/BeginnerLinuxDeveloper/SettingUpAnUnrealWorkflow topic-image:androidLinuxQS_topic.png Checkpoint:AndroidOnLinuxQS +Contributor:yaakuro [REGION:imagetable] ![](DeployedAndroidGame_Linux.png)(w:900) -_このチュートリアルでは、Linux で アンリアル エンジン 4 (UE4) を使用して、Android デバイス用ゲームの作成、デプロイ、パッケージ化を行います。_ +_このチュートリアルでは、Linux で アンリアル エンジン 4 (UE4) を使用して、Android デバイス向けゲームの作成、デプロイ、パッケージ化を行います。_ [/REGION] -Linux から Android デバイス用ゲームの作成および配布を予定しているデベロッパーのためのページです。 +Linux から Android デバイス向けゲームの作成および配布を予定しているデベロッパーのためのページです。 ## 目標 @@ -30,9 +31,9 @@ Linux から Android デバイス用ゲームの作成および配布を予定 このチュートリアルでは、以下の習得を目指します。 -* Linux で UE4 を使ってモバイル ゲーム開発用 Android SDK のインストールおよび設定方法。 -* Android の開発環境を有効にする方法。 -* UE4 で Android モバイル ゲームを作成する方法。 +* Linux で UE4 を使ってモバイルゲーム開発用 Android SDK のインストールおよび設定方法 +* Android の開発環境を有効にする方法 +* UE4 で Android モバイル ゲームを作成する方法 * UE4 から Android デバイスにレベルをデプロイする方法 * モバイル ゲームをリリース用にパッケージする方法 @@ -55,5 +56,5 @@ Linux から Android デバイス用ゲームの作成および配布を予定 [/REGION] [REGION:quote] -優秀なコミュニティからの支援のお陰で、ついに UE4 を使った Linux 開発に Android サポートを追加することができました。 +優秀なコミュニティからの支援のお陰で、ついに UE4 を使った Linux 開発で Android もサポートすることができました。 [/REGION] \ No newline at end of file diff --git a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/AndroidOnLinux.KOR.udn b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/AndroidOnLinux.KOR.udn index df274a8c222b..1a122892c236 100644 --- a/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/AndroidOnLinux.KOR.udn +++ b/Engine/Documentation/Source/Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux/AndroidOnLinux.KOR.udn @@ -1,7 +1,7 @@ -INTSourceChangelist:3351873 -Availability: Docs +INTSourceChangelist:0 +Availability: Public Title: Android On Linux Quick Start -Crumbs: +Crumbs:%ROOT% Description:Learn how to create, deploy, and package games to Android from Linux. Platform:Linux Version: 4.14 diff --git a/Engine/Documentation/Source/Platforms/Linux/Linux.INT.udn b/Engine/Documentation/Source/Platforms/Linux/Linux.INT.udn index bdab25110e19..1d03b303ff70 100644 --- a/Engine/Documentation/Source/Platforms/Linux/Linux.INT.udn +++ b/Engine/Documentation/Source/Platforms/Linux/Linux.INT.udn @@ -8,7 +8,9 @@ Version: 4.14 type:landing parent:Platforms tags:Linux +tags:Desktop related: GettingStarted/RecommendedSpecifications +Topic-image:LinuxDevelopment_topic.png Fueling the future of Linux game development is at your fingertips! Now, more than ever, you can harness the power of Unreal Engine 4 (UE4) to create and share games with Linux users worldwide. If you're new to Linux game development, @@ -18,6 +20,7 @@ you'll want to work your way through the Quick Start Guide before moving onto mo %Platforms/Linux/BeginnerLinuxDeveloper/SettingUpAnUnrealWorkflow:topic% %Platforms/Linux/BeginnerLinuxDeveloper/SettingUpAnIDE:topic% +%Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux:topic% ## Advanced Topics diff --git a/Engine/Documentation/Source/Platforms/Linux/Linux.JPN.udn b/Engine/Documentation/Source/Platforms/Linux/Linux.JPN.udn index f044ca35ed6f..f44305d5ac4e 100644 --- a/Engine/Documentation/Source/Platforms/Linux/Linux.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Linux/Linux.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3364378 +INTSourceChangelist:3467293 Availability:Public Title:Linux ゲームの開発 Crumbs: @@ -9,9 +9,11 @@ Version:4.14 type:landing parent:Platforms tags:Linux +tags:Desktop related:GettingStarted/RecommendedSpecifications +Topic-image:LinuxDevelopment_topic.png -Linux ゲーム開発の未来を開くのは、あなたの指先です!これまでにないほど、アンリアル エンジン 4 (UE4) を利用して、 +あなたの指先が Linux ゲーム開発の未来を開きます!これまでにないほど、アンリアル エンジン 4 (UE4) を利用して、 世界中の Linux ユーザーとゲームを作成し共有することができるようになりました。Linux でゲーム開発をしたことがない場合、高度なトピックスへ進む前に、 クイック スタート ガイドを一読しておくことをお勧めします。 @@ -19,6 +21,7 @@ Linux ゲーム開発の未来を開くのは、あなたの指先です!こ %Platforms/Linux/BeginnerLinuxDeveloper/SettingUpAnUnrealWorkflow:topic% %Platforms/Linux/BeginnerLinuxDeveloper/SettingUpAnIDE:topic% +%Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux:topic% ## 高度なトピック diff --git a/Engine/Documentation/Source/Platforms/Linux/Linux.KOR.udn b/Engine/Documentation/Source/Platforms/Linux/Linux.KOR.udn index 438996161fc3..c4440c57c820 100644 --- a/Engine/Documentation/Source/Platforms/Linux/Linux.KOR.udn +++ b/Engine/Documentation/Source/Platforms/Linux/Linux.KOR.udn @@ -1,7 +1,7 @@ -INTSourceChangelist:3336764 +INTSourceChangelist:3467293 Availability: Public Title: 리눅스 게임 개발 -Crumbs:%ROOT%, Platforms +Crumbs: Description:리눅스 플랫폼용 게임 개발 관련 문서입니다. Platform:Linux Navigation:platform @@ -9,7 +9,9 @@ Version: 4.14 type:landing parent:Platforms tags:Linux +tags:Desktop related: GettingStarted/RecommendedSpecifications +Topic-image:LinuxDevelopment_topic.png 손가락만 움직여도 얻을 수 있는 리눅스 게임 개발의 원동력! 이제 전에 없던 수준으로 언리얼 엔진 4 (UE4) 를 활용하여 전 세계의 리눅스 사용자들과 함께 게임을 만들고 공유할 수 있습니다. 리눅스 게임 개발이 처음이신 경우, @@ -17,11 +19,15 @@ related: GettingStarted/RecommendedSpecifications ## 시작하기 -%Platforms/Linux/GettingStarted:topic% %Platforms/Linux/BeginnerLinuxDeveloper/SettingUpAnUnrealWorkflow:topic% %Platforms/Linux/BeginnerLinuxDeveloper/SettingUpAnIDE:topic% +%Platforms/Linux/IntermediateLinuxDeveloper/AndroidOnLinux:topic% + +## 고급 토픽 + +%Platforms/Linux/GettingStarted:topic% +%Platforms/Linux/AdvancedLinuxDeveloper/LinuxCrossCompileLegacy:topic% ## 참고서 %Platforms/Linux/BeginnerLinuxDeveloper/SupportedGfxDrivers:topic% -%Platforms/Linux/AdvancedLinuxDeveloper/LinuxCrossCompileLegacy:topic% diff --git a/Engine/Documentation/Source/Platforms/Mobile/Achievements/Achievements.JPN.udn b/Engine/Documentation/Source/Platforms/Mobile/Achievements/Achievements.JPN.udn index 0325ab3bac40..e431747a26d6 100644 --- a/Engine/Documentation/Source/Platforms/Mobile/Achievements/Achievements.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Mobile/Achievements/Achievements.JPN.udn @@ -1,5 +1,4 @@ -INTSourceChangelist:3150518 -Title:モバイル サービスのアチーブメントを使用する +Title:モバイル サービスのアチーブメントの使用方法 Description:プレイヤーのエンゲージメントを高めるためにモバイルのアチーブメントを使用する Crumbs: Availability:Public @@ -42,7 +41,7 @@ tags:mobile [/OBJECT] [/VAR] -**アチーブメント** は、苦労してたどり着く目標、名誉のバッジ、あるいは単純に物語の区切りとして使ったり、プレイヤーのゲームへのエンゲージメントを保持できる便利な方法です。 +**アチーブメント** は、努力して達成する目標、バッジ、あるいは単純に物語の区切りとして使ったり、プレイヤーのゲームへのエンゲージメントの保持に便利な手段です。 [OBJECT:ComparisonSlider] [PARAM:before] @@ -75,38 +74,38 @@ tags:mobile **ブループリント内:** -Unreal Match 3 のサンプル ゲームの **Global Game Instance** を例に取りましょう。デバイスのゲーム プラットフォーム (Game Center、Google Play) にログインした後、このポイントで **Cache Achievements** ノードを実行して (一番上の出力実行ピンから何も実行されないようにして) 実際に実行を止め、すべてのアチーブメントを返すサービス時間を与えます: +Unreal Match 3 のサンプル ゲームの **Global Game Instance** を例に取りましょう。デバイスのゲーム プラットフォーム (Game Center、Google Play) にログイン後、このポイントで **Cache Achievements** ノードを実行して (一番上の出力実行ピンから何も実行されないようにして) 実際に実行を停止し、すべてのアチーブメントを返すサービス時間を与えます: ![](cacheAchievements.png) -## アチーブメントから値を読み取る +## アチーブメントの値の読み取り -**Get Cached Achievement Progress** は、提供されている **Player Controller** の所定の **Achievement ID** の進捗を返し、**Cache Achievements** ノードが実行済みで正常に返された場合のみ有効になります。 +**Get Cached Achievement Progress** は、指定された **Player Controller** に対して所定の **Achievement ID** の Progress を返し、**Cache Achievements** ノードが既に実行されて正常に返された場合のみ機能します。 -IOS Game Center の場合、この値は実際は整数として格納されるので、切り捨てのフロート値です。Google Play サービス用にフロート値を受け取ります。 +IOS Game Center の場合、この値は実際は整数として格納されるので、切り捨てのフロート値です。Google Play サービスに対してフロート値を受け取ります。 **ブループリント内:** -Unreal Match 3 のサンプル ゲームの **Global Game Instance** を例に取りましょう。アチーブメントがキャッシュされたら、アチーブメント名および配列からもターゲット スコアをプルしてループを実行し、オフラインで見つかった値と簡単に比較します。そして、サービス値とローカル値で高い方を受け取ります。 +例として、Unreal Match 3 のサンプル ゲームの **Global Game Instance** ブループリントを見てみましょう。アチーブメントがキャッシュされたら、アチーブメント名および配列からもターゲット スコアをプルしてループを実行し、オフラインで見つかった値とすぐに比較します。そして、サービス値とローカル値で高い方を受け取ります。 ![](readAchievement.png) ## アチーブメントへ値を書き出す -**Write Achievement Progress** は、**進捗** を所定のユーザーに提供されているアチーブメント (**Player Controller** と **User Tag**) へパーセント (0.0% - 100.0%) で書き出すためにプラットフォームのアチーブメント システムへメッセージを送ります。インクリメンタルなアチーブメントの場合は低めのパーセントを渡すのに対して、「単発の」アチーブメントの場合は常に **Progress** に `100.0` を渡します。 +**Write Achievement Progress** は、パーセント (0.0% - 100.0%) ベースの **Progress** を所定のユーザーに提供されているアチーブメント (**Player Controller** と **User Tag**) へ書き出すために、プラットフォームのアチーブメント システムへメッセージを送ります。インクリメンタルなアチーブメントの場合は低めのパーセントを渡すのに対して、「単発の」アチーブメントの場合は常に **Progress** に `100.0` を渡します。 iOS Game Center の場合、インクリメンタルなアチーブメントは 1-100 なので、この値は実際に整数で送られます。Google Play サービス用にフロート値を送ります。 -これは **潜在的な** ノードなので、実行出力ピンが多いことに注目してください。一番上は「通過」ですが、他の実行出力ピンと何ら変わりはありません。その下の 2 つのピン (**On Success** と **On Failure**) は、オンライン サービスが値を返す (または返すことに失敗する) と実行されます。実行が **Written Achievement Name** に正常を返すと、**Written Progress**, と **Written User Tag** は null 以外のノードと同等の値を返します。 +このノードは **潜在的な** ノードなので、実行出力ピンたくさん付いています。一番上は「通過」ピンですが、他の実行出力ピンと同じように機能します。その下の 2 つのピン (**On Success** と **On Failure**) は、オンライン サービスが値を返す (または返しに失敗する) と実行されます。実行が **Written Achievement Name** に正常を返すと、**Written Progress** と **Written User Tag** は null 以外のノードと同等の値を返します。 **ブループリント内:** -Unreal Match 3 のサンプル ゲームの **Global Game Instance** を例に取りましょう。現在のアチーブメント値をその値を増やすために必要なメトリクスと比較するループがあります。進展すると **Write Achievement** イベントが呼び出されます。 +例として、Unreal Match 3 のサンプル ゲームの **Global Game Instance** ブループリントを見てみましょう。現在のアチーブメント値をその値を増やすために必要なメトリクスと比較するループがあります。進展すると **Write Achievement** イベントが呼び出されます。 ![](writeAchievement.png) [REGION:note] -潜在的なノードは関数では使用できないので、これで行います。 +潜在的なノードは関数では使用できないので、このように行います。 [/REGION] ## プラットフォーム固有のアチーブメントを表示する diff --git a/Engine/Documentation/Source/Platforms/Mobile/Ads/Ads.JPN.udn b/Engine/Documentation/Source/Platforms/Mobile/Ads/Ads.JPN.udn index ff71f6143c56..ed19bc04d371 100644 --- a/Engine/Documentation/Source/Platforms/Mobile/Ads/Ads.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Mobile/Ads/Ads.JPN.udn @@ -1,5 +1,5 @@ INTSourceChangelist:3150518 -Title:インゲーム広告を使用する +Title:インゲーム広告の使用方法 Description: ゲームを収益化するためにインゲーム広告を使用する Crumbs: Availability:Public diff --git a/Engine/Documentation/Source/Platforms/Mobile/InAppPurchases/In-AppPurchases.JPN.udn b/Engine/Documentation/Source/Platforms/Mobile/InAppPurchases/In-AppPurchases.JPN.udn index 8603b9be8958..04ca04b00022 100644 --- a/Engine/Documentation/Source/Platforms/Mobile/InAppPurchases/In-AppPurchases.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Mobile/InAppPurchases/In-AppPurchases.JPN.udn @@ -1,6 +1,5 @@ -INTSourceChangelist:3150518 -Title:アプリ内課金を使用する -Description:アプリ内課金を使ってゲームに追加の有料コンテンツを提供する +Title:アプリ内課金の使用方法 +Description:アプリ内課金を使ってゲームで追加の有料コンテンツを提供する Crumbs: Availability:Public parent:Platforms/Mobile @@ -42,11 +41,11 @@ tags:mobile [/OBJECT] [/VAR] -アプリ内課金により、プレイヤーに対してコンテンツと機能の追加提供が可能になります。無料ゲームを有料化したり、有料コンテンツをゲームに追加する方法として使用できます。 +アプリ内課金は、プレイヤーにコンテンツと機能を追加で提供することができます。無料ゲームを有料化したり、有料コンテンツをゲームに追加して使用します。 ## コンフィギュレーション -各プラットフォームに対するアプリ内課金の設定の詳細については、プラットフォーム専用ページをご覧ください。 +プラットフォームごとのアプリ内課金設定方法については、プラットフォーム専用ページをご覧ください。 [REGION:buttonlist] * [](Platforms/Android/InAppPurchases) @@ -55,25 +54,25 @@ tags:mobile [EXCERPT:usage] [EXCERPT:usage_android] -## 購入情報を読み取る +## 購入情報の読み取り ![image alt text](image_3.png) -**Read In-App Purchase Information** ブループリント ノード (または関連する C++ 関数コール) を使ってアプリ内購入情報を読み取ります。多くの他のオンライン サブシステム関数と同様、Player Controller を入力および製品の識別子の配列として受け取ります。Read は情報の配列の処理ができますが、以下の Make In-App Purchase は識別子をひとつしか受け取ることができません。関数は In App Purchase 構造体の配列を返し、配列の各エレメントは名前、詳細、価格、その他のデータに分類して UI に表示、もしくはゲームプレイ ロジックで使用することができます。 +**Read In-App Purchase Information** ブループリント ノード (または関連する C++ 関数コール) を使ってアプリ内購入情報を読み取ります。他の多くのオンライン サブシステム関数と同様、Player Controller を入力および製品の識別子の配列として受け取ります。Read は情報の配列の処理ができますが、以下の Make In-App Purchase は識別子をひとつしか受け取ることができません。関数は In App Purchase 構造体の配列を返し、配列の各エレメントは名前、詳細、価格、その他のデータに分類して UI に表示、もしくはゲームプレイ ロジックで使用することができます。 -## 購入を完了する +## 購入の完了 ![image alt text](image_4.png) **Make an In-App Purchase** ブループリント ノード (または関連する C++ 関数コール) を使ってアプリ内購入情報を読み取ります。Player Controller を入力および Product Request 構造体として受け取ります。Product Request は、iTunes Connect あるいは Google Play Developer コンソール (このケースでは match3theme_night) の製品の識別子です。 -**Make an In-App Purchase** ノードは潜在的なので、ゲームプレイのビヘイビアをどのようにしても、購入の成功あるいは失敗はこれらの 2 つの実行ピンを使うかどうかによります。これらはオンライン サービスから応答が戻ってきた後に実行されます。ノードは購入の完了ステータス (Success、Failed、Restored) および 詳細な In App Purchase 情報の構造体も返します。 +**Make an In-App Purchase** ノードは潜在的なので、使いたいゲームプレイのビヘイビアはすべて、購入が成功あるいは失敗したかどうかに依存し、これら 2 つの実行ピンを使います。これらはオンライン サービスから応答が戻ってきた後に実行されます。ノードは購入の完了ステータス (Success、Failed、Restored) および詳細な In App Purchase Information 構造体も返します。 この関数の非潜在的なバージョン (ブループリントはずっと表示します) があります。ここでの終了実行ピンはオンライン サービスからの応答を待たずに、通常は潜在的なバージョンを使用します。 [/EXCERPT:usage_android] -## 購入を復元する +## 購入の復元 ![image alt text](image_5.png) diff --git a/Engine/Documentation/Source/Platforms/Mobile/Leaderboards/Leaderboards.JPN.udn b/Engine/Documentation/Source/Platforms/Mobile/Leaderboards/Leaderboards.JPN.udn index ec3be07a1554..a1acd1534ab7 100644 --- a/Engine/Documentation/Source/Platforms/Mobile/Leaderboards/Leaderboards.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Mobile/Leaderboards/Leaderboards.JPN.udn @@ -1,5 +1,4 @@ -INTSourceChangelist:3150518 -Title:モバイル サービスのリーダーボードを使用する +Title:モバイル サービスのリーダーボードの使用方法 Description:ゲームでリーダーボードを使用する Crumbs: Availability:Public @@ -42,7 +41,7 @@ tags:mobile [/OBJECT] [/VAR] -リーダーボードは、プラットフォーム別にプレイヤーの高得点をトラックし表示する機能です。これによりプレイヤーは権利を自慢することができ、コミュニティの確立がしやすくなります。 +リーダーボードは、プラットフォーム別にプレイヤーの高得点をトラックし表示する機能です。プレイヤーはリーダーボードを使用して権利の主張やコミュニティの確立がしやすくなります。 [OBJECT:ComparisonSlider] [PARAM:before] @@ -66,31 +65,31 @@ tags:mobile [/REGION] [EXCERPT:Usage] -## リーダーボードから読み取る +## リーダーボードの読み取り -**Read Leaderboard Integer** はプラットフォームのゲーム サービス (現在の iOS ゲームセンターあるいは Google Play サービス) から提供されている **Player Controller** の所定の **Stat Name** に保存されている値を要求します。 +**Read Leaderboard Integer** ノードは、プラットフォームのゲーム サービス (現在の iOS ゲームセンターあるいは Google Play サービス) が提供する **Player Controller** の所定の **Stat Name** に保存されている値を要求します。 -これは **潜在的な** ノードなので、実行出力ピンが多いことに注目してください。一番上は「通過」ですが、他の実行出力ピンと何ら変わりはありません。その下の 2 つのピン (**On Success** と **On Failure**) は、オンライン サービスが値を返す (または返すことに失敗する) と実行されます。正常に値を戻す (またはサービスが応答に失敗する) 前の **Leaderboard Value** は 0 です。 +Read Leaderboard Integer ノードは **潜在的な** ノードなので、実行出力ピンたくさん付いています。一番上は「通過」ピンですが、他の実行出力ピンと同じように機能します。その下の 2 つのピン (**On Success** と **On Failure**) は、オンライン サービスが値を返す (または返しに失敗する) と実行されます。正常に値を戻す (またはサービスが応答に失敗する) 前の **Leaderboard Value** は 0 です。 **ブループリント内:** -Unreal Match 3 のサンプル ゲームの **Global Game Instance** を例に取りましょう。下のブループリントにあるノードは Stat Name (リーダーボード) "Match3HighScore" 上の Player Index 0 で Player Controller 用の **Read Leaderboard Integer** ノードといいます。 +例として、Unreal Match 3 のサンプル ゲームの **Global Game Instance** ブループリントを見てみましょう。Stat Name (リーダーボード) "Match3HighScore" 上で Player Index 0 の Player Controller に対して **Read Leaderboard Integer** ノードを呼び出しています。 ![](readLeaderboard.png) ## リーダーボードに書き込む -**Write Leaderboard Integer** ノードは所定の整数 **Stat Value** を提供された **Player Controller** に対して **Stat Name** で指定したリーダーボードに送ります。 +**Write Leaderboard Integer** ノードは与えられた **Player Controller** に対して **Stat Name** で指定したリーダーボードに所定の整数 **Stat Value** を送ります。 **ブループリント内:** -Unreal Match 3 のサンプル ゲームの **VictoryScreen** ブループリントを例に取りましょう。ゲームの勝敗画面の表示時に、Unreal Match 3 は高得点を抽出してロードできるか確認し、可能な場合は高得点をリーダーボードにサブミットします。この動作の前に、アプリケーション起動中に抽出した高得点以外にも高得点があるかを追加で確認することも可能です。ただし、iOS と Android のリーダーボード システムは現在保存されている値より高い値のみ受け取ります。 +例として、Unreal Match 3 のサンプル ゲームの **VictoryScreen** ブループリントを見てみましょう。ゲーム勝敗画面を表示する際、Unreal Match 3 は高得点の抽出およびロードが可能か確認し、可能な場合は高得点をリーダーボードにサブミットします。この動作の前に、アプリケーション起動中に抽出した高得点以外にも高得点があるかを追加で確認することも可能です。ただし、iOS と Android のリーダーボード システムは保存されている値より高い値のみ受け取ります。 ![](writeLeaderboard.PNG) ## プラットフォーム固有のリーダーボードを表示する -**Show Platform Specific Leaderboard Screen** がデバイス上の **Category Name** によって指定されたリーダーボードを表示します。 +**Show Platform Specific Leaderboard Screen** が **Category Name** によって指定されたリーダーボードをデバイスに表示します。 **ブループリント内:** diff --git a/Engine/Documentation/Source/Platforms/Mobile/Lighting/HowTo/CascadedShadow/CascadedShadow.JPN.udn b/Engine/Documentation/Source/Platforms/Mobile/Lighting/HowTo/CascadedShadow/CascadedShadow.JPN.udn index 66bb633e7444..b5b3e3d5d13e 100644 --- a/Engine/Documentation/Source/Platforms/Mobile/Lighting/HowTo/CascadedShadow/CascadedShadow.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Mobile/Lighting/HowTo/CascadedShadow/CascadedShadow.JPN.udn @@ -1,8 +1,7 @@ -INTSourceChangeList:3108692 -Availability:Public +Availability:Public Title:カスケード シャドウの使用方法 Crumbs:%ROOT%, Platforms, Platforms/Mobile -Description:モバイル ゲーム向けのカスケード シャドウ設定 +Description:モバイル ゲーム向けカスケード シャドウの設定方法 Platform:Mobile Related:Platforms/Mobile/Performance Related:Platforms/Mobile/Textures @@ -19,7 +18,7 @@ tags:mobile UE4 モバイル プロジェクトでこの機能を使用するには、以下の手順を行います。 -1. **[Project Settings (プロジェクト設定)]** で **[Engine]** > **[Rendering]** > **[Mobile]** セクションの順に選択し、**[Enable Combined Static and CSM Shadowing (静的シャドウインと CSM シャドウイングの結合を有効にする)]** にチェックが入っていることを確認しまうs。 +1. **[Project Settings (プロジェクト設定)]** で **[Engine]** > **[Rendering]** > **[Mobile]** セクションの順に選択し、**[Enable Combined Static and CSM Shadowing (静的シャドウインと CSM シャドウイングの結合を有効にする)]** にチェックが入っていることを確認します。 [region:lightbox] [![](Platforms\Mobile\Lighting\CSM_Setup_00.png)(w:562 h:310)](Platforms\Mobile\Lighting\CSM_Setup_00.png) @@ -30,7 +29,7 @@ UE4 モバイル プロジェクトでこの機能を使用するには、以下 [/REGION] -1. CSM はシーンに **指向性ライト** がある場合のみ使用できます。指向性ライトがない場合は、1 つ追加し、それを選択しておくようにしてください。次に **[Transform (トランスフォーム)]** セクションの **[Mobility (可動性)]** 設定を **[Stationary (固定)]** にしてください。 +1. CSM はシーンに **指向性ライト** がある場合のみ使用できます。指向性ライトがない場合は、1 つ追加し、それを選択してください。次に **[Transform (トランスフォーム)]** セクションの **[Mobility (可動性)]** 設定を **[Stationary (固定)]** にしてください。 [region:lightbox] [![](Platforms\Mobile\Lighting\CSM_Setup_01.png)(w:300 h:400)](Platforms\Mobile\Lighting\CSM_Setup_01.png) @@ -68,7 +67,7 @@ UE4 モバイル プロジェクトでこの機能を使用するには、以下 [/REGION] [region:note] - 以下の動画で [Receive Combined Static and CSM Shadows from Stationary Lights] の機能をご覧いただけます。この動画では、[Receive Combined Static and CSM Shadows from Stationary Lights] がフロアの構成要素であるスタティックメッシュに対してオンにされていますが、階段の構成要素であるスタティックメッシュにはオンにされていません。プレイヤーがフロア上にいる時はシャドウがありますが、階段上ではシャドウのないことに注目してください。これは、フロアには [Receive Combined Static and CSM Shadows from Stationary Lights] がオンにされ、階段にはオンにされていないためです。 + 以下の動画で [Receive Combined Static and CSM Shadows from Stationary Lights] の機能をご覧いただけます。この動画では、[Receive Combined Static and CSM Shadows from Stationary Lights] がフロアの構成要素であるスタティックメッシュに対してオンにされていますが、階段の構成要素であるスタティックメッシュにはオンにされていません。プレイヤーがフロア上にいる時はシャドウがありますが、階段に上がるとシャドウがないことに注目してください。これは、フロアは [Receive Combined Static and CSM Shadows from Stationary Lights] がオンにされていますが、階段はオンにされていないためです。 [OBJECT:EmbeddedVideo] [PARAMLITERAL:width] @@ -98,7 +97,7 @@ UE4 モバイル プロジェクトでこの機能を使用するには、以下 [Mobile Preview (モバイル プレビュー)] ウィンドウが表示されない場合は、アンリアル エディタ ウィンドウの裏で起動していないか確認してください。 [/region] -1. 正常に起動したら、静的シャドウのある場所にキャラクターを配置し、シャドウに出入りすると、キャラクターの動的シャドウは以下の画像のようにレベル内にベイクされたシャドウと滑らかにブレンドされます。 +1. 正常に起動したら、静的シャドウのある場所にキャラクターを配置します。シャドウに出入りすると、キャラクターの動的シャドウは以下の画像のようにレベル内にベイクされたシャドウと滑らかにブレンドされます。 [REGION:lightbox] [![](Platforms\Mobile\Lighting\CSM_Final_Result.png)(w:262 h:281)](Platforms\Mobile\Lighting\CSM_Final_Result.png) @@ -109,5 +108,5 @@ UE4 モバイル プロジェクトでこの機能を使用するには、以下 [/REGION] [region:note] - 背景に置かれたスタティックメッシュのシャドウをキャラクターにキャストしたい場合は、スタティックメッシュの **[Mobility (可動性)]** 設定を ***[Static (静的)]** から **[Movable (可動)]** に変更します。 + 背景に置いたスタティックメッシュのシャドウをキャラクターにキャストするには、スタティックメッシュの **[Mobility (可動性)]** を ***[Static (静的)]** から **[Movable (可動)]** に変更します。 [/region] \ No newline at end of file diff --git a/Engine/Documentation/Source/Platforms/Mobile/Lighting/MobileLighting.JPN.udn b/Engine/Documentation/Source/Platforms/Mobile/Lighting/MobileLighting.JPN.udn index c2df37eb4edb..2eab4e999067 100644 --- a/Engine/Documentation/Source/Platforms/Mobile/Lighting/MobileLighting.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Mobile/Lighting/MobileLighting.JPN.udn @@ -1,5 +1,4 @@ -INTSourceChangelist:3184883 -Availability:Public +Availability:Public Title:モバイル プラットフォーム向けのライティング Crumbs:%ROOT%, Platforms, Platforms/Mobile Description:モバイル ゲーム向けのライティング設定 @@ -18,7 +17,7 @@ tags:mobile [TOC(start:2 end:3)] -UE4 のモバイル プラットフォームでライトを使う場合、UE4 プロジェクトが正しいフレームで、様々なモバイル デバイス上で使えるようにするために、決められた注意事項と制限事項を守る必要があります。次の文書では、これらの注意事項と制限事項について、およびそれらを避けたり回避する方法について説明します。 +UE4 のモバイル プラットフォームでライトを使う場合、UE4 プロジェクトが正しいフレームで、様々なモバイル デバイス上で動くようにするために、決められた注意事項と制限事項を守る必要があります。これらの注意事項と制限事項、および回避する方法について説明します。 ## サポート対象の機能 @@ -27,7 +26,7 @@ UE4 のモバイル プラットフォームでライトを使う場合、UE4 * HDR のリニア ライティング * 指向性ライトマップ (法線を考慮する) * 太陽上の距離フィールド シャドウ + 解析的なスペキュラ -* 画像ベースのスペキュラ ライティング - 視差修正をせずに最も近い [リフレクション キャプチャ](Engine/Rendering/LightingAndShadows/ReflectionEnvironment/) が各オブジェクトに適用されます。従って、オブジェクト間にシームがあります。 +* 画像ベースのスペキュラ ライティング - 視差修正をせずに最も近い [Reflection Capture](Engine/Rendering/LightingAndShadows/ReflectionEnvironment/) が各オブジェクトに適用されます。従って、オブジェクト間にシームがあります。 * 動的オブジェクトはライティングを正確に受け取りますが、シャドウはキャストしません。 ## サポート対象のライト タイプ @@ -42,13 +41,13 @@ UE4 のモバイル プラットフォームでライトを使う場合、UE4 | Static Spot Light | **Mobility = Static** によるスポットライト。| ## 反射 -反射は、モバイル プロジェクトに生命と信憑性を吹き込むために使用しますが、モバイル デバイスでの使用時に気をつけるべき注意がいくつかあります。対象のモバイル デバイスで確実に反射を使うために必要なことを以下にまとめました。 +反射を使用すると躍動感と写実性を出すことができますが、モバイル デバイスで反射を使用する際には注意すべき点がいくつかあります。対象のモバイル デバイスで反射がきちんと動くようにするために、以下の点を確認してください。 -* ポストプロセス ボリューム内にあるアンビエント キューブマップの **強度** を **0** に設定してすべて無効にする。 +* ポストプロセス ボリューム内のすべてのアンビエント キューブマップの **[Intensity (強度)]** を **[0]** に設定して無効にする。 ![](PP_Settings.png) -* 反射のためのライティングをキャプチャしたい場所に [**SphereReflectionCaptures**](Engine/Rendering/LightingAndShadows/ReflectionEnvironment/#球体の形状) アクタを置きます。 +* 反射用のライティングをキャプチャする場所に [**SphereReflectionCaptures**](Engine/Rendering/LightingAndShadows/ReflectionEnvironment/#球体の形状) アクタを置きます。 [OBJECT:ComparisonSlider] [PARAM:before] @@ -61,7 +60,7 @@ UE4 のモバイル プラットフォームでライトを使う場合、UE4 * 反射をサポートするマテリアルを作成する場合は、以下のことに留意してください。 - * 反射を分割すると、外見を面白くすることができるので、法線マップに高周波および低周波細部が多く含まれるようにしてください。 + * 法線マップに高周波および低周波細部が多くなるようにしてください。反射が分裂しやすくなり、面白い見た目の反射ができます。 [OBJECT:ComparisonSlider] [PARAM:before] @@ -72,7 +71,7 @@ UE4 のモバイル プラットフォームでライトを使う場合、UE4 [/PARAM] [/OBJECT] - * 光沢のある反射、またはぼんやりした反射を様々な角度にすることができるので、ラフネスマップにいろいろな強度の白と黒を入れるようにしてください。 + * ラフネスマップにいろいろな強度の白と黒を入れるようにしてください。反射に光沢を付けたり、多方向にぼんやり反射させることができます。 [OBJECT:ComparisonSlider] [PARAM:before] @@ -94,20 +93,20 @@ UE4 のモバイル プラットフォームでライトを使う場合、UE4 [/PARAM] [/OBJECT] -それぞれの Static Mesh コンポーネントは,最も近い [**リフレクション キャプチャ**](Engine/Rendering/LightingAndShadows/ReflectionEnvironment/) に割り当てられます。つまり、オブジェクト間の反射にシームがあり、大きなメッシュはメッシュの中央に近いところにある好ましくない反射キャプチャを使用することもあります。 +Static Mesh コンポーネントは、それぞれに最も近い [**Reflection Capature**](Engine/Rendering/LightingAndShadows/ReflectionEnvironment/) に割り当てられます。つまり、オブジェクト間の反射にシームができたり、メッシュが大きいとたまたまメッシュの中央の近くにある Reflection Capture を使用することになります。 ## 変調シャドウイング -完全に動的シャドウにすると、モバイル プロジェクトに生命とリアリズムを追加しやすくなります。 -ただし、モバイル デバイスの中には、ハードウェアの制限と、レンダリングするために動的シャドウが必要とするリソース要件が高すぎるために、完全に動的シャドウにすることができないものもあります。この回避策として、負荷の低い **変調シャドウ (Modulated Shadows)** という名前の動的シャドウが新しく UE4 に導入されました。変調シャドウの設定方法については、[**変調シャドウ**](Platforms/Mobile/Lighting/HowTo/ModulatedShadows/) をご覧ください。 +完全に動的シャドウにすると、モバイル プロジェクトに躍動感と写実性を出しやすくなります。 +ただしモバイル デバイスの中には、ハードウェア制限およびレンダリングに必要な動的シャドウのリソース要件が高すぎるため、完全には動的シャドウにできないものもあります。回避策として、負荷の低い動的シャドウの **変調シャドウ (Modulated Shadows)** が新しく UE4 に導入されました。変調シャドウの設定方法については、[**変調シャドウ**](Platforms/Mobile/Lighting/HowTo/ModulatedShadows/) をご覧ください。 ## 動的カスケード シャドウ マップ -Stationary Directional Light (固定の指向性ライト) は、シーンの動的オブジェクトだけに Whole-scene Dynamic Cascade Shadow Maps (CSM) シャドウをキャストするために使用できます。CSM シャドウを使う利点の 1 つは、Stationary Directional Light (固定の指向性ライト) が、シーンの静的オブジェクトによってキャストされた事前計算シャドウと正しくブレンドする点です。CSM シャドウでは、変調シャドウでは確認できるダブル シャドウイングが表示されないので、複数のオブジェクトにシャドウをキャストする場合、処理が速くなります。カスケード シャドウの設定方法については、[**カスケード シャドウ**](Platforms\Mobile\Lighting\HowTo\CascadedShadow\) をご覧ください。 +Stationary Directional Light (固定の指向性ライト) は、シーンの動的オブジェクトだけに Whole-scene Dynamic Cascade Shadow Maps (CSM) シャドウをキャストする場合に使います。CSM シャドウを使う利点の 1 つは、Stationary Directional Light (固定の指向性ライト) がシーンの静的オブジェクトによってキャストされた事前計算シャドウと正しくブレンドされる点です。ダブル シャドウイングは変調シャドウでは確認できても CSM シャドウでは表示されないので、複数のオブジェクトにシャドウをキャストすると処理が速くなります。カスケード シャドウの設定方法については、[**カスケード シャドウ**](Platforms\Mobile\Lighting\HowTo\CascadedShadow\) をご覧ください。 ## 変調シャドウイング VS 動的シャドウイング -変調シャドウイングと動的シャドウイングは、外見も動作も非常に似ています。 -変調シャドウには動的シャドウにはない制約とハードリミットが多く、限られたハードウェア性能でモバイル デバイス上でのパフォーマンスを良くすることができます。 +変調シャドウイングと動的シャドウイングは、外見も動作もよく似ています。 +変調シャドウには動的シャドウにはない制約とハードリミットが多いので、ハードウェアの性能が制限され、モバイル デバイス上でのパフォーマンスを向上させることができるのです。 以下の画像で、動的シャドウと変調シャドウを見比べてみましょう。 [OBJECT:ComparisonSlider] @@ -120,9 +119,9 @@ Stationary Directional Light (固定の指向性ライト) は、シーンの動 [/OBJECT] -上の画像でキャストされている動的シャドウは、すべて共通していて、そっくりに見えます。 +以下は、UE4 プロジェクトで変調シャドウを使用する場合の代表的な機能と制約です。 -* **シャドウ カラーの変更:** 指向性ライトの **[Light]** セクションの **[Modulated Shadow Color]** オプションを調整することで、モジュレート化したシャドウがキャストしたシャドウの色を変えることができます。ゲームプレイの都合上、またはアート面の理由でシャドウの色を調節したい場合に便利です。 +* **シャドウ カラーの変更:** [Directional Light (指向性ライト)] > **[Light]** セクション > **[Modulated Shadow Color]** オプションを調整して、変調シャドウがキャストしたシャドウの色を変更できます。ゲームプレイまはたアートに合わせてシャドウの色を調節する場合に便利です。 [REGION:lightbox] [![](Change_Mod_Shadow_Color.png)(w:771 h:252)](Change_Mod_Shadow_Color.png) @@ -132,7 +131,7 @@ Stationary Directional Light (固定の指向性ライト) は、シーンの動 クリックしてフルサイズで表示 [/REGION] -* **シャドウのブレンド:** プロジェクトで分かると思いますが、変調シャドウは動的シャドウと同じく、他のシャドウとはブレンドしません。つまり、変調シャドウが他のシャドウの上に重なると、単独のシャドウがブレンドされているのではなく、両方のシャドウが見えるのです。 +* **シャドウのブレンド:** 動的シャドウとは違って、変調シャドウはベイク済みシャドウや動的シャドウなど、プロジェクトで表示される他のシャドウとはブレンドしません。つまり、変調シャドウが他のシャドウの上に重なると、ブレンドされている単独のシャドウではなく、両方のシャドウが表示されます。 [OBJECT:ComparisonSlider] [PARAM:before] @@ -143,23 +142,23 @@ Stationary Directional Light (固定の指向性ライト) は、シーンの動 [/PARAM] [/OBJECT] -## 変調シャドウと動的シャドウの操作 +## 変調シャドウと動的シャドウでの作業方法 -変調シャドウと動的シャドウの操作時に、変調シャドウの外見とパフォーマンスを調整するためのコンソールと .INI 設定がいくつかあります。これらの設定および UE4 プロジェクトへの適用方法について、次のセクションで説明します。 +変調シャドウと動的シャドウには、変調シャドウの外見とパフォーマンスを調整するコンソールおよび .INI 設定がいくつかあります。これらの設定および UE4 プロジェクトへの適用方法について、次のセクションで説明します。 [region:note] -変調シャドウが、既存のシャドウ技術とコードを共有するようにします。 -つまり、他のシャドウイング メソッドで使用できるシャドウ cvars と .INI 設定の多くは、変調シャドウおよび動的シャドウでも使用できます。 +変調シャドウはできるだけ既存のシャドウ技術とコードを共有するようにします。 +つまり、他のシャドウイング メソッドで使用できるシャドウ cvars と .INI 設定は、変調シャドウおよび動的シャドウでもほとんどが使用できます。 [/region] -* **シャドウの品質:** 動的シャドウを初めて有効にしてモバイル デバイス上で表示すると、変調シャドウの鮮明度と品質が思っているより若干低い場合があります。これに対応するためには、アンリアル コンソールを開いて、backtick ` キーを使って、数字の後に **r.shadowquality** を打ち込むことでシャドウの品質を調整できます。数字が高いほど、変調シャドウは FPS の負荷に気をつけるようになります。次の画像では、r.shadowquality の値は **0**、**1**、**2**、**3**、**4**、**5** に設定して変調シャドウの品質上でこのエフェクトがどうなるかを表示しました。 +* **シャドウの品質:** 動的シャドウを有効にしてモバイル デバイス上で初めて表示すると、変調シャドウの鮮明さと品質が思っていたより悪くなることがあります。その場合は、アンリアル コンソールを開いて backtick (`) キーを使って数字の後に **r.shadowquality** と入力すると、シャドウの品質を調整できます。数字が高いほど、変調シャドウは FPS の負荷を考慮するようになります。次の画像は、r.shadowquality の値を **0**、**1**、**2**、**3**、**4**、**5** に設定した場合に変調シャドウの品質に与える影響を見ることができます。 [REGION:fullwidth] [INCLUDE:Platforms\Mobile\Lighting\#SQ] [/REGION] -* **セルフシャドウイング:** 変調シャドウは動的オブジェクト上にキャラクターもしくはピックアップなどのセルフ シャドウイングを提供します。ただし、変調シャドウの性能をできるだけ高めるために、この機能はデフォルトでは無効にされています。 -プロジェクトがセルフシャドウイングにかかる余分な負荷に対応できれば、UE4 コンソールに **r.Shadow.EnableModulatedSelfShadow 1** を入力して有効にすることができます。 +* **セルフシャドウイング:** 変調シャドウでは、キャラクターもしくはピックアップなどの動的オブジェクト上にセルフ シャドウイングが可能です。ただし、変調シャドウのパフォーマンスを優先するためにデフォルトでは無効にされています。 +セルフシャドウイングによる余分な負荷に対応できるプロジェクトの場合は、UE4 コンソールに **r.Shadow.EnableModulatedSelfShadow 1** を入力して有効にしてください。 セルフシャドウイングを無効にするには、UE4 コンソールに **r.Shadow.EnableModulatedSelfShadow 0** を入力します。 [OBJECT:ComparisonSlider] @@ -171,8 +170,8 @@ Stationary Directional Light (固定の指向性ライト) は、シーンの動 [/PARAM] [/OBJECT] -* **シャドウ深度:** **r.Shadow.CSMDepthBias** を使って、シャドウのレンダリングの開始位置をオフセットすることができます。 -以下の画像を見ると、r.Shadow.CSMDepthBias がデフォルト値 **0** のままで、その後 **10**、**100**、**500**、**1000** に値を設定すると、変調シャドウがどうなるのかが分かります。 +* **シャドウ深度:** シャドウのレンダリングの開始位置をオフセットするには、**r.Shadow.CSMDepthBias** コマンドを使います。 +以下の画像では、r.Shadow.CSMDepthBias をデフォルト値 **0** から **10**、**100**、**500**、**1000** に値を変更した場合の変調シャドウの変化が分かります。 [REGION:fullwidth] [INCLUDE:Platforms\Mobile\Lighting\#SD] diff --git a/Engine/Documentation/Source/Platforms/Mobile/Mobile.INT.udn b/Engine/Documentation/Source/Platforms/Mobile/Mobile.INT.udn index e062edf68fb0..0a8057ea100d 100644 --- a/Engine/Documentation/Source/Platforms/Mobile/Mobile.INT.udn +++ b/Engine/Documentation/Source/Platforms/Mobile/Mobile.INT.udn @@ -9,6 +9,7 @@ parent:Platforms tags:Mobile order:0 type:landing +topic-image:MobileGameDevelopment_topic.png [REGION:banner] ![](mobile_banner.png) diff --git a/Engine/Documentation/Source/Platforms/Mobile/Mobile.JPN.udn b/Engine/Documentation/Source/Platforms/Mobile/Mobile.JPN.udn index 01666a3eb76e..0f7cf0a924ec 100644 --- a/Engine/Documentation/Source/Platforms/Mobile/Mobile.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Mobile/Mobile.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3150518 +INTSourceChangelist:3467293 Availability:Public Title: モバイル ゲームの開発 Crumbs:%ROOT%, Platforms @@ -10,6 +10,7 @@ parent:Platforms tags:Mobile order:0 type:landing +topic-image:MobileGameDevelopment_topic.png [REGION:banner] ![](mobile_banner.png) diff --git a/Engine/Documentation/Source/Platforms/Mobile/Mobile.KOR.udn b/Engine/Documentation/Source/Platforms/Mobile/Mobile.KOR.udn index da43f3acfad4..6d4bb751caf5 100644 --- a/Engine/Documentation/Source/Platforms/Mobile/Mobile.KOR.udn +++ b/Engine/Documentation/Source/Platforms/Mobile/Mobile.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3150518 +INTSourceChangelist:3467293 Availability:Public Title:모바일 게임 개발 Crumbs:%ROOT%, Platforms @@ -10,6 +10,7 @@ parent:Platforms tags:Mobile order:0 type:landing +topic-image:MobileGameDevelopment_topic.png [REGION:banner] ![](mobile_banner.png) diff --git a/Engine/Documentation/Source/Platforms/Mobile/MobilePackagingWizard/MobilePackagingWizard.INT.udn b/Engine/Documentation/Source/Platforms/Mobile/MobilePackagingWizard/MobilePackagingWizard.INT.udn index ebc59663fafb..8124e1acb784 100644 --- a/Engine/Documentation/Source/Platforms/Mobile/MobilePackagingWizard/MobilePackagingWizard.INT.udn +++ b/Engine/Documentation/Source/Platforms/Mobile/MobilePackagingWizard/MobilePackagingWizard.INT.udn @@ -24,12 +24,63 @@ To access the Mobile Packaging Wizard, you will need to do the following. 1. From the **Main Toolbar**, locate the **Window** option and click on it. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](MPW_Location.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](MPW_Location_Mac.png) + [/PARAM] + [/OBJECT] 1. From the Windows menu that is displayed, click on the **Project Launcher** option to display the Project Launcher. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](MPW_Project_Launcher.png) + [/PARAM] + [/OBJECT] + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](MPW_Project_Launcher_Mac.png) + [/PARAM] + [/OBJECT] [OBJECT:ToggleButtonContent] [PARAMLITERAL:category] @@ -66,29 +117,161 @@ To access the Mobile Packaging Wizard, you will need to do the following. Before the Mobile Packaging Wizard can be used, a new profile that is specific to your project's needs has to be created. In the following section, we will take a look at what needs to be done to create a custom launch profile for your UE4 mobile project. 1. Click on the small white triangle next to **Custom Launch Profiles**, selecting the **Minimal Android APK + DLC** option from the list. - + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](MPW_Select_Android_Option.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](MPW_Select_Option_Mac.png) + [/PARAM] + [/OBJECT] (#bookmark1) + 1. When the **Minimal Android APK + DLC** packaging window is displayed, click on the **Browse** button, and select a location for the packaged content to be placed. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](MPW_Press_Browse.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](MPW_Press_Browse_Mac.png) + [/PARAM] + [/OBJECT] 1. Once you have selected a location for the packaged content to be placed, press the **Next** button to continue the packaging process. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](MPW_Press_Next.png) + [/PARAM] + [/OBJECT] + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](MPW_Press_Next_Mac.png) + [/PARAM] + [/OBJECT] + 1. In the **Distributable APK** menu, set the **Build Configuration** to **Development** and then select the map you want to use, pressing the **Next** button when finished. - + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](MPW_Dis_APK.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](MPW_Dis_APK_Mac.png) + [/PARAM] + [/OBJECT] [region:note] Only the contents referenced by the map(s) you choose will be packaged into the application for upload to the Play Store. Typically, you should choose only a single map that contains a Level Blueprint to kick off the **BuildPatchServices** code with a **UMG** user interface to show the download progress (showing any applicable error conditions). [/region] 1. In the **Downloadable Content** menu, select the Android texture formats your application will support with the maps that will need to be downloaded. When that has been completed, press the **Create Profile** button to create a new Custom Launch Profile. - + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](MPW_Downloadable_Content.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](MPW_Downloadable_Content_Mac.png) + [/PARAM] + [/OBJECT] + ## Building the Application @@ -96,15 +279,67 @@ Now that all of the options for the Mobile Packing Wizard have been set up and s 1. If the Project Launcher is not already open, open it up and then look at the bottom of the Project Launcher in the **Custom Launch Profile** section. In this section, you should have two profiles that start with your project name and are followed by either **Android APK** or **Android DLC**. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](MPW_Custom_Launch_Profiles.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](MPW_Custom_Launch_Profiles_Mac.png) + [/PARAM] + [/OBJECT] [region:note] When you first open up the Project Launcher, the Custom Launch Profiles section could have a few items in it by default. To remove these items, right-click on the item you want to remove, and then select the **Delete** option to remove it. [/region] 1. Locate the **APK** Profile option and then click on the **Launch this Profile** button to begin the packaging process. - + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](MPW_Launch_APK_Profile.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](MPW_Launch_APK_Profile_Mac.png) + [/PARAM] + [/OBJECT] [region:warning] You must package your project's files before you build the DLC. @@ -112,11 +347,63 @@ Now that all of the options for the Mobile Packing Wizard have been set up and s 1. Once the **Launch this Profile** button has been pressed, the Project Launcher will begin the packaging process. You can see the progress of the packaging process in the Project Launcher window. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](MPW_Packaging_Progress.png) + [/PARAM] + [/OBJECT] + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](MPW_Packaging_Progress_Mac.png) + [/PARAM] + [/OBJECT] + 1. When the packaging has completed, click on the **Done** button to load the Project Launcher. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](MPW_Packaging_Completed.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](MPW_Packaging_Completed_Mac.png) + [/PARAM] + [/OBJECT] ## Building the DLC @@ -124,17 +411,97 @@ Once your project has finished the cooking process for the initial download from 1. From the Project Launcher, go to the **Custom Launch Profiles** section and look for your project's **DLC** option. When the DLC option for your project has been located, click on the **Launch this Profile** button to begin the DLC packaging process. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](MPW_Build_DLC.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](MPW_Build_DLC_Mac.png) + [/PARAM] + [/OBJECT] 1. After pressing the **Launch this Profile** button, the Project Launcher will begin to build the DLC for your project. When the DLC has finished being built, click on the **Done** button to continue. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](MPW_DLC_Completed.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](MPW_DLC_Completed_Mac.png) + [/PARAM] + [/OBJECT] + ## Packaging Results Once everything has finished building, open up the folder that was specified in the [second step](#bookmark1) of the "Setting Up a Mobile Packaging Wizard Profile" section. You'll see the following two folders: +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] ![](MPW_App_DLC_Location.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](MPW_App_DLC_Location_Mac.png) +[/PARAM] +[/OBJECT] + Inside of the folders, you will find the various pieces of your project that have been set up to be downloaded after the users have downloaded and installed the application on their mobile device. @@ -148,20 +515,125 @@ Before the Mobile Packaging Wizard can be used, a new profile that is specific t 1. Click on the small white triangle next to **Custom Launch Profiles**, selecting the **Minimal IOS App + DLC** option from the list. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](MPW_Select_iOS_Option.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](MPW_Select_iOS_Option_Mac.png) + [/PARAM] + [/OBJECT] (#bookmark1) + 1. When the **Minimal IOS App + DLC** packaging window is displayed, click on the **Browse** button and select a location for the packaged content to be placed. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](MPW_iOS_Press_Browse_Button.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](MPW_iOS_Press_Browse_Button_Mac.png) + [/PARAM] + [/OBJECT] 1. Once you have selected a location for the packaged content to be placed, press the **Next** button to continue the packaging process. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](MPW_iOS_Press_Next.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](MPW_iOS_Press_Next_Mac.png) + [/PARAM] + [/OBJECT] 1. In the **Distributable Application** menu, set the **Build Configuration** to **Development** and then select the map you want to use, pressing the **Next** button when finished. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](MPW_Dis_iOS.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](MPW_Dis_iOS_Mac.png) + [/PARAM] + [/OBJECT] [region:note] Only the contents referenced by the map(s) you choose will be packaged into the application for upload to the App Store. Typically, you should choose only a single map that contains a Level Blueprint to kick off the **BuildPatchServices** code with a **UMG** user interface to show the download progress (showing any applicable error conditions). @@ -169,7 +641,33 @@ Before the Mobile Packaging Wizard can be used, a new profile that is specific t 1. In the **Downloadable Content** menu, select the maps that should be downloaded and then press the **Create Profile** button to create a new Custom Launch Profile. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](MPW_Downloadable_Content_iOS.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](MPW_Downloadable_Content_iOS_Mac.png) + [/PARAM] + [/OBJECT] ## Building the Application @@ -177,7 +675,33 @@ Now that all of the options for the Mobile Packing Wizard have been set up and s 1. If the Project Launcher is not already open, open it up and then look at the bottom of the Project Launcher in the **Custom Launch Profile** section. In this section, you should have two profiles that start with your project name and are followed by either **IOS App** or **IOS DLC**. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](MPW_Custom_Launch_Profiles_iOS.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](MPW_Custom_Launch_Profiles_iOS_Mac.png) + [/PARAM] + [/OBJECT] [region:note] When you first open up the Project Launcher, the Custom Launch Profiles section could have a few items in it by default. To remove these items, right-click on the item you want to remove, and then select the **Delete** option to remove it. @@ -185,7 +709,33 @@ Now that all of the options for the Mobile Packing Wizard have been set up and s 1. Locate the **IOS App** Profile option and then click on the **Launch this Profile** button to begin the packaging process. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](MPW_Launch_APK_Profile_iOS.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](MPW_Launch_APK_Profile_iOS_Mac.png) + [/PARAM] + [/OBJECT] [region:warning] You must package your project's files before you build the DLC. @@ -193,11 +743,63 @@ Now that all of the options for the Mobile Packing Wizard have been set up and s 1. Once the **Launch this Profile** button has been pressed, the Project Launcher will begin the packaging process. You can see the progress of the packaging process in the Project Launcher window. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](MPW_Packaging_Progress_iOS.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](MPW_Packaging_Progress_iOS_Mac.png) + [/PARAM] + [/OBJECT] 1. When the packaging has completed, click on the **Done** button to load the Project Launcher. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](MPW_Packaging_Completed_iOS.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](MPW_Packaging_Completed_iOS_Mac.png) + [/PARAM] + [/OBJECT] ## Building the DLC @@ -205,17 +807,95 @@ Once your project has finished the cooking process for the initial download from 1. From the Project Launcher, go to the **Custom Launch Profiles** section and look for your project's **DLC** option. When the DLC option for your project has been located, click on the **Launch this Profile** button to begin the DLC packaging process. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](MPW_Build_DLC_iOS.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](MPW_Build_DLC_iOS_Mac.png) + [/PARAM] + [/OBJECT] 1. After pressing the **Launch this Profile** button, the Project Launcher will begin to build the DLC for your project. When the DLC has finished being built, click on the **Done** button to continue. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](MPW_DLC_Completed_iOS.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](MPW_DLC_Completed_iOS_Mac.png) + [/PARAM] + [/OBJECT] ## Packaging Results Once everything has finished building, open up the folder that was specified in the [second step](#bookmark1) of the "Setting Up a Mobile Packaging Wizard Profile" section. You'll see the following two folders: +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] ![](MPW_App_DLC_Location.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](MPW_App_DLC_Location_Mac.png) +[/PARAM] +[/OBJECT] Inside of the folders, you will find the various pieces of your project that have been set up to be downloaded after the users have downloaded and installed the application on their mobile device. diff --git a/Engine/Documentation/Source/Platforms/Mobile/Performance/MobilePerformance.INT.udn b/Engine/Documentation/Source/Platforms/Mobile/Performance/MobilePerformance.INT.udn index 96680c9ddeb2..4fbca1593dd1 100644 --- a/Engine/Documentation/Source/Platforms/Mobile/Performance/MobilePerformance.INT.udn +++ b/Engine/Documentation/Source/Platforms/Mobile/Performance/MobilePerformance.INT.udn @@ -150,9 +150,38 @@ Inside of this file, you can specify what will happen to the resolution of your In the following image, you can see an example of the Mobile Content Scale Factor in action using the command listed above. + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] [REGION:lightbox] [![](T_MCF_INI_File.png)(w:358 h:505)](T_MCF_INI_File.png) [/REGION] +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +[REGION:lightbox] +[![](T_MCF_INI_File_Mac.png)(w:358 h:505)](T_MCF_INI_File_Mac.png) +[/REGION] +[/PARAM] +[/OBJECT] [REGION:caption] Click for full image. [/REGION] @@ -227,9 +256,38 @@ Please note that 1 for high and 2 for medium **IS** correct and not a typo! **From Device Profiles**: You can also adjust the Material Quality by doing the following: 1. From the Main Toolbar go to **Windows** > **Developer Tools** and then click on **Device Profiles**. + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] [REGION:lightbox] [![](MQS_Device_Profiles.png)(w:217 h:371)](MQS_Device_Profiles.png) [/REGION] + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + [REGION:lightbox] + [![](MQS_Device_Profiles_Mac.png)(w:217 h:371)](MQS_Device_Profiles_Mac.png) + [/REGION] + [/PARAM] + [/OBJECT] [REGION:caption] Click for full image. [/REGION] @@ -300,10 +358,37 @@ These two properties can be enabled to help reduce the rendering cost of that Ma ### Mobile Material Rendering Overrides You can override the available rendering option a platform will use by adjusting the **ES2 Quality Settings**. You can find the ES2 Quality Setting for both Android and iOS by going to your **Project Settings** > **Platforms** and then selecting either **Android ES2 Quality** or **iOS ES2 Quality Settings**. To use the overrides, you must first click on the **Enable Quality Override** option and then select the option you want to override by clicking on it. Once all of the options you want have been selected, press the **Update preview shaders** button to re-compile all Materials to work with the options you have specified. - +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] [REGION:lightbox] [![](MQS_Rendering_Overrides.png)(w:613 h:330)](MQS_Rendering_Overrides.png) [/REGION] +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +[REGION:lightbox] +[![](MQS_Rendering_Overrides_Mac.png)(w:613 h:330)](MQS_Rendering_Overrides_Mac.png) +[/REGION] +[/PARAM] +[/OBJECT] [REGION:caption] Click for full image. [/REGION] @@ -314,14 +399,67 @@ Inside of your **Project's Settings** menu under the **Mobile** section you will ### Accessing your Project Settings To access your project settings you will first need to go to the **Main Toolbar** and then select **Edit** > **Project Settings**. +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] ![](MRO_Project_Settings.png) +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +![](MRO_Project_Settings_Mac.png) +[/PARAM] +[/OBJECT] Once the Project Settings menu is open, locate the **Engine** section and then click on the **Rendering** category and look for the **Mobile** heading. +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] [REGION:lightbox] [![](MRO_Rendering_Settings.png)(w:430)](MRO_Rendering_Settings.png) [/REGION] +[/PARAM] +[/OBJECT] +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +[REGION:lightbox] +[![](MRO_Rendering_Settings_Mac.png)(w:430)](MRO_Rendering_Settings_Mac.png) +[/REGION] +[/PARAM] +[/OBJECT] [REGION:caption] Click for full image. [/REGION] diff --git a/Engine/Documentation/Source/Platforms/Mobile/Performance/MobilePerformance.JPN.udn b/Engine/Documentation/Source/Platforms/Mobile/Performance/MobilePerformance.JPN.udn index c7be349c9faf..da213746ba9e 100644 --- a/Engine/Documentation/Source/Platforms/Mobile/Performance/MobilePerformance.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Mobile/Performance/MobilePerformance.JPN.udn @@ -1,5 +1,4 @@ -INTSourceChangelist:3184883 -Availability:Public +Availability:Public Title:モバイル デバイスのパフォーマンス ガイドライン Crumbs:%ROOT%, Platforms, Platforms/Mobile Description:モバイル ゲーム用コンテンツと機能の最適化 @@ -14,29 +13,29 @@ tags:mobile -以下は、モバイル プラットフォーム上のパフォーマンスを最大に発揮させるための注意もしくは提案です。要求の高いものから簡単なものまで紹介します。 +以下は、モバイル プラットフォーム上のパフォーマンスを最大にするための注意事項もしくは推奨事項です。重要なものから順番にリストしました。 -* デバイスで実行する前にライティングがビルドされていることをご確認ください。 -* **ポストプロセス** 機能はほとんどが無効化されていることをご確認ください。実際、iPad4 で使用するポストプロセスはビネットを含めて **Temporal AA** と Film だけです。PC と モバイル間の設定は同じなので、 Bloom や DOF などの負荷の大きい機能群はデフォルトで無効になっています。デフォルト設定の **ポストプロセス** 機能を使うと、60+ms を軽く超えます。ハイエンド デバイスで Bloom、DOF、ライトシャフトが使用できるようにしたいです。`show postprocessing` は **ポストプロセス** の切り替えと負荷量の表示に使用できます。 -* **[Precomputed Visibility (事前計算されたビジビリティ)]**を、必ず正しく設定するようにしてください。そのためには、プレーヤーが歩行可能な場所の周りに **PrecomputedVisibilityVolumes** を配置し、ライティングをビルドする必要があります。ライティングのビルド時およびゲームの実行時には、同じ **パーシスタント** レベルを必ず使用するようにしてください (aka 自体はビルドを行いません)。デバイス上あるいはプレビューに `stat initviews` と入力すると動作を確認ができます。[Statically occluded primitives] が >0 になるようにしてください。`r.ShowPrecomputedVisibilityCells 1` を使用して、エディタでセルを視覚化します。 -* シェードは各ピクセル一回だけの場合がほとんどなので、マスクされた透過 **マテリアル** を慎重に画面のカバーしている小さい部分のみに使用します。ただし、マスクされた透過マテリアルの場合、すべてのレイヤーはシェードされなければなりません。オーバードローにより、フレームの GPU 時間の合計は簡単に 2 倍以上にできます。**モバイル プレビュア** の **シェーダー複雑度ビューモード** でホット スポットを調査します。 -* シーン全体の描画コールはどのビューに対しても <= 700 でなければなりません。ランドスケープを見渡すなど、オクルージョンが弱い領域の場合は非常に難しくなります。デバイスでは `stat openglrhi`、 PC の ES2 previewer では `stat d3d11rhi` で確認できます。 -* シーン全体のトライアングル数はどのビューに対しても <= 500 でなければなりません。iPad4 と iPad Air の両方で、ポリゴン数が 30fps となる必要があると判断されています。デバイスでは `stat openglrhi`、 PC の ES2 previewer では `stat d3d11rhi` で確認できます。 -* **マテリアル** に使用するテクスチャ ルックアップとインストラクションは出来る限り少なくすべきです。5 つのテクスチャ サンプリングを使用できますが、これら全部を使うとかなり負荷の高いマテリアルになります。差し当たり、PC インストラクション数を使って最適化し、ES2 プレビュア シェーダー複雑度を使って負荷合計を視覚化します。 -* マテリアルでは独立したテクスチャ フェッチのみを使用します。ピクセル シェーダー (BaseColor 、 Roughness など) の UV は、スケーリングを始めとするどんな方法でも操作されてはならないという意味です。その代わりに、この新たな **CustomizedUVs** 機能を使ってバーテックス シェーダーでスケーリングを行ってください。環境マッピングなどの特別な機能の中には、 UV での計算を必要とする、特別なケースもあります。 -* メモリ消費の少ない正方テクスチャを選択し、常に 2 のべき乗 (512 、1024、2048) のディメンションを使ってください。ES2 プレビュアの `listtextures` を使って、全てのテクスチャ メモリの行き先を確認します。 +* デバイスの実行前にライティングがビルドされていることを確認してください。 +* **ポストプロセス** 機能がほぼ無効にされているか確認してください。実際、iPad4 で使用するポストプロセスはビネットを含めて **Temporal AA** と Film だけです。PC と モバイルは同じ設定です。Bloom や DOF など負荷の大きい機能はデフォルトで無効になっています。**ポストプロセス** 機能をデフォルト設定にすると、軽く 60+ms を超えます。ハイエンド デバイスでの Bloom、DOF、ライトシャフトの使用を目指しています。`show postprocessing` は **ポストプロセス** の切り替えと負荷量の表示に使用できます。 +* **[Precomputed Visibility (事前計算されたビジビリティ)]** が正しく設定されているか確認してください。そのためには、プレーヤーが歩行可能な場所の周りに **PrecomputedVisibilityVolumes** を配置してライティングをビルドする必要があります。ライティングのビルド時およびゲームの実行時には、必ず同じ **パーシスタント** レベルを使用してください (aka 自体はビルドを行いません)。デバイス上あるいはプレビューに `stat initviews` と入力すると動作を確認ができます。[Statically occluded primitives] が >0 になるようにしてください。`r.ShowPrecomputedVisibilityCells 1` を使用して、エディタでセルを視覚化します。 +* マスクされた透過 **マテリアル** は画面をあまりカバーしていない場合に使用するようにします。ほとんどの場合、シェーディングはピクセルにつき 1 回しか行わないので、iOS デバイスは不透明なサーフェイスのシェーディングに最適です。ただし、マスクされた透過マテリアルの場合、すべてのレイヤーはシェードされなければなりません。オーバードローにより、フレーム GPU 時間の合計はあっという間に 2 倍以上に膨らみます。**モバイル プレビュア** の **[Shader Complexity Viewmode (シェーダー複雑度ビューモード)]** を使ってホット スポットを探します。 +* シーン全体の描画コールはどのビューに対しても <= 700 でなければなりません。ランドスケープを見渡す場合など、オクルージョンが弱い領域ではこれが非常に難しくなります。デバイスでは `stat openglrhi`、PC の ES2 previewer では `stat d3d11rhi` で確認できます。 +* シーン全体のトライアングル数はどのビューに対しても <= 500 でなければなりません。iPad4 および iPad Air では、ポリゴン数は 30fps が必要と判断されています。デバイスでは `stat openglrhi`、PC の ES2 previewer では `stat d3d11rhi` で確認できます。 +* **マテリアル** に使用するテクスチャ ルックアップとインストラクション数はなるべく少なくしてください。テクスチャ サンプリングは 5 つまで使用できますが、全部使用するとマテリアル負荷はかなり高くなります。差し当たり、PC インストラクション数を使って最適化し、ES2 プレビュア シェーダー複雑度を使って負荷合計を視覚化します。 +* マテリアルでは独立したテクスチャ フェッチのみを使用します。ピクセル シェーダー (BaseColor、Roughness など) の UV は、スケーリングを始めとするどんな方法でも操作されてはならないという意味です。その代わりに、この新たな **CustomizedUVs** 機能を使ってバーテックス シェーダーでスケーリングを行ってください。環境マッピングなどの特別な機能の中には、UV での計算が必要な特別なケースもあります。 +* メモリ消費の少ない正方テクスチャを選択し、常に 2 のべき乗 (512、1024、2048) のディメンションを使ってください。ES2 プレビュアの `listtextures` を使って、全てのテクスチャ メモリの行き先を確認します。 ## パフォーマンス ティア -アンリアル エンジン (UE4) はモバイル デバイス上で様々なライティング機能をサポートしています。これらの機能を使うとパフォーマンスに負荷がかかり、遅めのモバイル デバイス上でゲームのパフォーマンスが下がる原因となります。UE4 のほとんどのモバイル ライティング機能のミックスおよびマッチが可能な一方で、これらの機能を以下のティアに分類すると便利です。モバイル ゲームのビルド時には、要求されるゲームのグラフの品質、およびサポート対象のデバイスの種類をもとに、使う機能を決定してください。Epic でテスト済みのデバイスおよび最適と思われるティアに関する詳細は、 [iOS 開発](Platforms/iOS/DeviceCompatibility) のデバイス互換性と [Android 開発](Platforms/Android/DeviceCompatibility) を参照してください。 +アンリアル エンジン (UE4) はモバイル デバイス上で様々なライティング機能をサポートしています。この機能はパフォーマンスに負荷をかけるので、処理が遅いモバイル デバイス上ではゲームのパフォーマンスを下げる原因になります。UE4 のほとんどのモバイル ライティング機能は混ぜたり一致させることができます。以下のように分類すると便利です。モバイル ゲームのビルド時には、要求されるゲームのグラフの品質、およびサポート対象のデバイスの種類をもとに、使う機能を決定してください。エピックでテスト済みのデバイスおよび最適性については、[iOS 開発](Platforms/iOS/DeviceCompatibility) のデバイス互換性と [Android 開発](Platforms/Android/DeviceCompatibility) を参照してください。 ###LDR (Low Dynamic Range) -Low Dynamic Range (LDR) は、UE4 がサポートするパフォーマンスの中で最も高いライティングや **Post Processing** 機能を必要としないゲームにお勧めです。このモードを使用するには、[プロジェクト設定エディタ](Engine/UI/ProjectSettings) のレンダリング セクションで、プロジェクトの「Mobile HDR」を無効にしなければなりません。 +Low Dynamic Range (LDR) は、UE4 がサポートするライティングの中で最もパフォーマンスが高いです。ライティング機能や **Post Processing** 機能を必要としないゲームにお勧めです。このモードを使用するには、[プロジェクト設定エディタ](Engine/UI/ProjectSettings) のレンダリング セクションで、プロジェクトの「Mobile HDR」を無効にしなければなりません。 **長所** -* モバイル デバイスで使用できる最速で最安のオーバーヘッド モードです。処理の遅いモバイル デバイスでゲームを効率よく実行することができます。 +* モバイル デバイスで使用できる最も速く、最も負荷の低いオーバーヘッド モードです。処理の遅いモバイル デバイスで、ゲームを効率よく実行することができます。 * カスタム仕様のシェーダーを定義するマテリアル エディタへのフルアクセスはそのままで、さらにライティングをフェードする簡単なシェーディングも実行します。 @@ -50,78 +49,78 @@ Low Dynamic Range (LDR) は、UE4 がサポートするパフォーマンスの **推奨事項** * すべての **マテリアル** のシェーディング モデルが、最大のパフォーマンスが出せる **[Unlit]** に設定されるようにしてください。 -* ライトをシーンに配置しないでください。さもなければ最大のパフォーマンスはライト次第になってしまいます。 -* **マテリアル** のバーテックス シェーダーのオペレーションを可能な限り多く実行するように配慮してください。そのためには、**カスタム仕様の UV** を有効にし、ノードを接続し、**Texture Coordinate** ノードを使ってピクセル シェーダーで読み取ります。 +* ライトをシーンに配置しないでください。最大パフォーマンスがライトに制限されてしまします。 +* **マテリアル** のバーテックス シェーダーでできるだけ多く演算を実行するように配慮してください。そのためには、**カスタム仕様の UV** を有効にし、ノードを接続し、**Texture Coordinate** ノードを使ってピクセル シェーダーで読み取ります。 ### 基本的なライティング -このティアでは、幅広いモバイル デバイスに対応するためにパフォーマンスを最大にする一方で、静的なライティングと完全にラフな **マテリアル** を使用して興味深いライティングでレベルを作成します。 +このレベルのライティングは、最大のパフォーマンスで幅広いモバイル デバイスに対応しつつ、静的なライティングと Fully Rough 設定の **マテリアル** を使用して凝ったライティングでレベルを作成します。 **長所** * 静的なライティングとグローバル イルミネーションへアクセスできます。 -* トーン マッピングなどの **ポストプロセス** 機能の幾つかへアクセスできるFull HDR パイプラインです。 -* 透過は線形空間でブレンドされ、他の UE4 ゲームで普通に行うようにコンテンツが作成できるようになります。 +* トーン マッピングなどの **ポストプロセス** 機能のいくつかへアクセスできるFull HDR パイプラインです。 +* 透過が線形空間でブレンドされるので、他の UE4 ゲームと同じように普通にコンテンツ作成ができるようになります。 **制限事項** -* 全ての **マテリアル** を **完全にラフ** にしているので、**マテリアル** には興味深いスペキュラ リフレクションは付きません。 -* ライトマップの方向性を無効にした場合も、法線マップにエフェクトはありません。 +* 全ての **マテリアル** を **[Fully Rough]** にしているので、**マテリアル** に特に珍しいスペキュラ リフレクションは付きません。 +* ライトマップの方向性を無効にした場合も、法線マップにエフェクトは付きません。 **推奨事項** -* すべての **マテリアル** は、完全にラフなフラグ設定で作成してください。 -* パフォーマンスをあげるために、**マテリアル** のライトマップの方向性の無効化を考慮してください。 -* マップではスタティック ライトのみを使用してください。 -* ブルームとアンチエイリアシングを無効にしてください。フィルムとカラーコントロールの基本設定も忠実に行ってください。詳細は [モバイル プラットフォーム上でのポストプロセス エフェクト](Platforms/Mobile/PostProcessEffects) を参照してください。 +* すべての **マテリアル** はフラグを [Fully Rough] 設定で作成してください。 +* パフォーマンスをさらにあげるには、**マテリアル** のライトマップの方向性を無効にしてみてください。 +* マップでは static light (静的ライト) のみを使用してください。 +* ブルームとアンチエイリアシングを無効にしてください。さらに、フィルムとカラーコントロールは基本設定を遵守してください。詳細は [モバイル プラットフォーム上でのポストプロセス エフェクト](Platforms/Mobile/PostProcessEffects) を参照してください。 ### Full HDR ライティング -このティアでは、UE4 で使用できるほとんどの HDR ライティング機能に加えてポストプロセス機能も活用します。これらの機能は高品質のライティング機能であるがゆえに、使用するためにはかなりのパフォーマンスが要求されます。 +このレベルのライティングでは、UE4 で使用できるほとんどの HDR ライティング機能に加えてポストプロセス機能も利用できます。クオリティの高いライティング機能のため、パフォーマンス負荷がかなり高くなります。 **長所** * 静的なライティングとグローバル イルミネーションへアクセスできます。 * ポストプロセス機能の幾つかへアクセスできるフルの HDR パイプラインです。 -* 透過は線形空間でブレンドされ、他の UE4 ゲームで普通に行うようにコンテンツが作成できるようになります。 -* 様々なラフネスをサポートしているので、サーフェス上で現実味のあるスペキュラ リフレクションが可能です。 -* ノーマルマップ化されたサーフェスを完全にサポートすることで、メッシュにポリゴンを多数追加しなくてもサーフェスの詳細を興味深くすることができます。 +* 透過が線形空間でブレンドされるので、他の UE4 ゲームと同じように普通にコンテンツ作成ができるようになります。 +* 様々なラフネスをサポートしているので、サーフェス上にリアルなスペキュラ リフレクションを作成できます。 +* ノーマルマップ化されたサーフェスをフルサポートするので、メッシュにポリゴンを追加しなくても興味深いサーフェス ディテールを作成することができます。 **推奨事項** * ブルームを無効化すると、HDR ライティング パイプラインを大いに活用できます。 -* HDR ライティングと組み合わせた現実味のあるスペキュラ リフレクションは、スペキュラのエイリアシングの発生につながります。ノーマルマップをラフネス機能にうまく利用して、ノーマルマップの高周波成分情報が原因のスペキュラのエイリアシングを軽減してください。このアーティファクトの軽減に向けて、ポストプロセス ボリュームのアンチエイリアシングの有効化も検討すべきです。 -* **反射キャプチャ** の配置がベストな結果につながるかも検討してみてください。詳細については [距離フィールド AO のドキュメンテーション](Resources/Showcases/Reflections/#反射キャプチャの配置) をご覧ください! -* シーンでは、パフォーマンスをベストに保つためにも、スタティック ライトとライトマップのみを使用してください。 +* HDR ライティングと組み合わせたリアルなスペキュラ リフレクションは、スペキュラのエイリアシングの原因となります。法線マップにラフネス機能を利用して、法線マップの高周波成分情報が原因のスペキュラのエイリアシングを軽減してください。このアーティファクトを軽減するためには、ポストプロセス ボリュームのアンチエイリアシングの有効化も検討すべきです。 +* **反射キャプチャ** の配置についても検討してみてください。詳細については [反射:反射キャプチャの配置](Resources/Showcases/Reflections/#反射キャプチャの配置) をご覧ください! +* シーンでは、パフォーマンスをベストに保つためにも、Static Light (静的ライト) とライトマップのみを使用してください。 -### 太陽からのピクセル ライティングごとのフル HDR ライティング +### 太陽からのピクセル単位のライティングを使った Full HDR Lighting -この段階では、UE4 のモバイルで使用できる HDR ライティング機能の全てを利用します。「フル HDR ライティング」と長所も推奨事項も同じですが、単一の指向性ライトのレンダリングの質は格段にあがります。 +この段階では、UE4 のモバイルで使用できる HDR ライティング機能の全てを利用します。「Full HDR Lighting レベル」の長所も推奨事項も同じですが、単一の指向性ライトのレンダリングのクオリティは格段にあがります。 **長所** -* 機能と長所は、フル HDR ライティングとすべて同じです。 -* 単一の指向性ライトに対してピクセルごとのディフューズとスペキュラ ライティング -* 単一の指向性ライトに対して事前計算された高品質の距離フィールド シャドウ +* 機能と長所は、Full HDR Lighting とすべて同じです。 +* 単一の指向性ライトに対してピクセル単位のディフューズとスペキュラ ライティング +* 単一の指向性ライトに対して事前計算された高品質のディスタンス フィールド シャドウ **推奨事項** -* 推奨事項は、フル HDR ライティングとすべて同じです。 -* 単一の指向性ライトは固定に設定すべきですが、それ以外はシーンでは Static Light (静的ライト) のみを使用してください。 +* 推奨事項は、Full HDR Lighting とすべて同じです。 +* 単一の指向性ライトは Stationary (固定) に設定すべきですが、それ以外はシーンでは Static Light (静的ライト) のみを使用してください。 ##シェーダー複雑度ビュー モード -PC ES2 プレビュアのシェーダー複雑度ビューモードを使うと、マテリアルの負荷がなんとなく分かります。使用方法は、 -**PC ES2 プレビュア** のコンソール上で `viewmode shadercomplexity` と入力するだけです。SM5 シェーダー複雑度と同様に、 -緑はパフォーマンス良好、明るい赤はかなり高い負荷、白またはピンクは **非常に** 高い負荷を表します。モバイル ショーケースからのサンプルを +PC ES2 プレビュアのシェーダー複雑度ビューモードを使うと、マテリアルのおおよその負荷が分かります。使用方法は、 +**PC ES2 プレビュア** のコンソールに `viewmode shadercomplexity` と入力するだけです。SM5 シェーダー複雑度と同様に、 +緑はパフォーマンス良好、赤は負荷が高め、白またはピンクは **非常に** 高い負荷を表します。モバイル ショーケースからのサンプルを いくつか紹介します。 [REGION:imagetable] @@ -132,10 +131,10 @@ PC ES2 プレビュアのシェーダー複雑度ビューモードを使うと ## モバイル コンテンツ スケール係数 -**Mobile Content Scale Factor** はプロジェクトの解像度をスケーリングして、プロジェクトを表示するるモバイル デバイスの画面解像度を最適にする手段です。 -プロジェクトの config フォルダの中に **DefaultDeviceProfiles.ini** という名前の .INI ファイルを新規作成すれば、複数のデバイス プロファイルの作成と格納が可能になります。 +**Mobile Content Scale Factor** はプロジェクトの解像度をスケーリングして、モバイル デバイスの画面解像度を最適にしてプロジェクトを表示する手段です。 +プロジェクトの config フォルダの中に **「DefaultDeviceProfiles.ini」** という名前の .INI ファイルを新規作成すれば、複数のデバイス プロファイルの作成および格納が可能になります。 このファイルの中に、以下のコマンドを入力してプロジェクトの解像度を指定します。 r.MobileContentScaleFactor = @@ -161,7 +160,7 @@ PC ES2 プレビュアのシェーダー複雑度ビューモードを使うと 上の画像は UE4 Tappy Chicken プロジェクトです。各種モバイル デバイスで再生すると解像度の変化の様子を比較することができます。 ファイルの上部で iOS デバイス用の解像度のスケーリングを行い、下部では Android デバイスの解像度のスケーリングを行います。 **r.MobileContentScaleFactor** の後に付いている番号を確認してください。 -コマンドの後にある数字で、プロジェクトの解像度の拡大縮小を判断します。 +コマンドの後ろにある数字で、プロジェクトの解像度の拡大縮小を判断します。 ### iOS 向けモバイル コンテンツ スケール係数 @@ -189,10 +188,10 @@ Android デバイス向けのモバイル コンテンツ スケール係数を ## Mobile Material Quality 設定 -ローエンドとハイエンドの両方のモバイル デバイスに対応したアンリアル エンジン 4 (UE4) プロジェクト用のコンテンツを作成する場合、一定の機能があるデバイス群では動くのに別のデバイス群では動かないという問題に直面します。さらにアートワークについても、あるデバイスでは正しく表現されるのに、別のデバイスでは全く異なって見えてしまう場合もあります。このような問題への対処方法はいろいろありますが、時間とリソースが著しい上に、エラーを起しやすい場合がほとんどです。その対策として UE4 には Material Quality Level システムが付いています。このシステムは、1 つのマテリアルに対して、デバイスごとに使用できる機能を完全に制御し、様々なデバイスで幅広く使えるように作成することができます。次のセクションでは、これらのシステムの UE4 プロジェクトでの使用方法を説明します。 +ローエンドとハイエンドの両方のモバイル デバイスに対応したアンリアル エンジン 4 (UE4) プロジェクト用のコンテンツを作成する場合、一定の機能があるデバイス群でしか動かなくなるという問題が発生します。さらにアートワークについても、あるデバイスでは正しく表現されるのに、別のデバイスでは全く異なって見えてしまう場合もあります。こうした問題への対処方法は沢山ありますが、莫大な時間とリソースが必要な上に、エラーが発生しやすい場合がほとんどです。その対策として UE4 には Material Quality Level システムが付いています。このシステムは、デバイスごとに使用できる機能を完全に制御することで、1 つのマテリアルを様々なデバイスで使えるようにビルドすることができます。次のセクションでは、これらのシステムの UE4 プロジェクトでの使用方法を説明します。 ### Material Quality Level のプレビュー -UE4 エディタでは、様々な Material Quality Level の結果を表示できます。 +UE4 エディタで、様々な Material Quality Level 設定の結果を表示することができます。 **メインツールバー** の **[Settings (設定)]** > **[Material Quality Level (マテリアル品質レベル)]** の中から、プレビューしたい品質レベルを選択します。 [REGION:lightbox] @@ -211,7 +210,7 @@ Material Quality Level を Low、Medium、High に設定すると、それぞれ ### Material Quality Level の設定 UE4 で Material Quality Level を設定するには以下の手順に従います。 -**コンソールで設定する方法**:Backtick キーを押して UE4 コンソールを開き、次の数字のいずれかの前に `r.MaterialQualityLevel` を打ち込むと、エディタで使用するマテリアルの品質レベルを設定することができます。 +**コンソールで設定する方法**:Backtick キーを押して UE4 コンソールを開き、次のいずれかの数字の前に `r.MaterialQualityLevel` を打ち込むと、エディタで使用するマテリアルの品質レベルを設定することができます。 ![](Platforms\Mobile\Performance\MQS_Console_Command.png) @@ -222,7 +221,7 @@ UE4 で Material Quality Level を設定するには以下の手順に従いま |2|Medium| [region:note] -1 が高めで 2 は中間 **で合っています**。誤植ではありません! +**1 が高く 2 が中間** です。誤植ではありません! [/region] ** Device Profiles のデフォルト設定**:マテリアルの品質はこの方法でも調節できます。 @@ -235,11 +234,11 @@ UE4 で Material Quality Level を設定するには以下の手順に従いま クリックしてフルサイズで表示 [/REGION] -1. Device Profiles の **[Android_Low** profile] の最初の **[レンチマークの]** アイコンをクリックしてプロファイル オプションを開きます。 +1. [Device Profiles] の **[Android_Low]** プロファイルの左側にある **[レンチマークの]** アイコンをクリックしてプロファイル オプションを開きます。 ![](MQS_Edit_Profile.png) -1. **[Console Variables (コンソール変数)]** セクションの **[Rendering (レンダリング)]** オプションの **[+ (プラス記号)]** アイコンをクリックし、入力ウィンドウが表示されたら **「R.MaterialQualityLevel」** と打ち込み、[Enter] キーを押してコマンドをリストに追加します。 +1. **[Console Variables (コンソール変数)]** セクションの **[Rendering (レンダリング)]** オプションの **[+ (プラス記号)]** アイコンをクリックします。入力ウィンドウが表示されたら **「R.MaterialQualityLevel」** と入力して [Enter] キーを押すと、コマンドがリストに追加されます。 [REGION:lightbox] [![](MQS_Set_Con_Var.png)(w:505 h:242)](MQS_Set_Con_Var.png) @@ -248,7 +247,7 @@ UE4 で Material Quality Level を設定するには以下の手順に従いま クリックしてフルサイズで表示 [/REGION] -1. 新規エントリが追加されたら、デフォルト値を **1** から **0** に変更します。ローエンドな Android デバイス上でプロジェクトを表示する場合、最速のマテリアル設定が使われます。 +1. コマンドが追加されたら、デフォルト値を **1** から **0** に変更します。ローエンドな Android デバイス上でプロジェクトを表示する場合、最速のマテリアル設定が使われます。 [REGION:lightbox] [![](MQS_Set_Quality_Level.png)(w:505 h:242)](MQS_Set_Quality_Level.png) @@ -257,8 +256,8 @@ UE4 で Material Quality Level を設定するには以下の手順に従いま クリックしてフルサイズで表示 [/REGION] -### 異なる品質レベルのプレビュー -**[Preview Rendering Level (レンダリング レベルをプレビュー)]** を調節して、異なるハードウェアでのプロジェクトの見え方を UE4 エディタからプレビューします。**メインツールバー** の **[Settings (設定)]** > **[Preview Rendering Level (レンダリング レベルのプレビュー)]** から使用したいプレビュー レベルを選択します。 +### 別の品質レベルのプレビュー +**[Preview Rendering Level (レンダリング レベルをプレビュー)]** を調節して、別のハードウェアで実行した場合のプロジェクトの見え方を UE4 エディタでプレビューします。**メインツールバー** の **[Settings (設定)]** > **[Preview Rendering Level (レンダリング レベルのプレビュー)]** で使用するプレビュー レベルを選択します。 [REGION:lightbox] @@ -268,12 +267,12 @@ UE4 で Material Quality Level を設定するには以下の手順に従いま クリックしてフルサイズで表示 [/REGION] -### Material Quality Level の切り替え -**Quality Switch** マテリアル式は、1 つのマテリアルに対して異なる複雑度を定義することができます。例えば、ハイエンド デバイスでは正常で、ローエンドで複雑な演算やテクスチャ解読が実行不可能な場合、このノードによってハイエンド グラフィクスを表示するだけのパワーのないローエンド モバイル デバイスでの表示用の簡素化版を指定することができます。 +### Material Quality Level の切り替え方法 +**Quality Switch** マテリアル式は、1 つのマテリアルに対して異なる複雑度を定義することができます。例えば、ハイエンドで正常に実行できる複雑な演算やテクスチャ解読がローエンドでは実行できない場合、ローエンド モバイル デバイスにとっては重すぎるハイエンド用の表示をこのノードで簡素化に指定することができます。 ![](image08.png) -マテリアルで Quality Switch を行うには、まず Quality Switch ノードをマテリアル グラフに追加します。次に、品質レベルを変更した時に変わってもらいたい Main Material ノード上に入力があれば、そこに出力を接続します。以下の画像では、Quality Level が変更されるとマテリアルの複雑度が下がるよう、Starter Content に入っている M_Brick_Clay_Old Material を設定しました。 +マテリアルで Quality Switch を行うには、まず Quality Switch ノードをマテリアル グラフに追加します。次に、品質レベルの変更を反映させたい Main Material ノード上にある入力に出力を接続します。以下の画像では、Quality Level が変更されるとマテリアルの複雑度が下がるように、Starter Content に入っている M_Brick_Clay_Old Material を設定しました。 [REGION:lightbox] [![](MQS_Material_Setup.png)(w:789 h:412)](MQS_Material_Setup.png) @@ -285,7 +284,7 @@ UE4 で Material Quality Level を設定するには以下の手順に従いま ### モバイル マテリアルのオプション **Material** を開いて Main Material ノードをクリックし [Details (詳細)] パネルの **[Mobile]** セクションを開くと、以下の 2 つのプロパティがあります。 -* **Fully Rough**:数多くの命令と、テクスチャ サンプリング 1 つを保存してマテリアルを完全に粗くします。 +* **Fully Rough**:多くの命令とテクスチャ サンプリングを 1 つ保存してマテリアルを完全に粗くします。 * **Use Lightmap Directionality**:ライトマップ指向性とピクセルごとの法線を使用します。無効にすると、ライトマップからのライティングはフラットになりますが、負荷が小さくなります。 [REGION:lightbox] @@ -295,11 +294,11 @@ UE4 で Material Quality Level を設定するには以下の手順に従いま クリックしてフルサイズで表示 [/REGION] -パワー低いモバイル デバイスで表示する時に、この 2 つのプロパティは、これらの機能で使うレンダリング パスを完全に削除することにより、マテリアルのレンダリング負荷を軽減します。ただし、これらのオプションはすべてのデバイスでこのマテリアルを有効か無効のいずれかにするので、いちかばちかのオプションです。 +この 2 つのプロパティは、パワーの低いモバイル デバイスでマテリアルを表示する場合に、これらの機能のレンダリング パスを完全に削除してマテリアルのレンダリング負荷を軽減します。ただし、これらのオプションを有効または無効にすると、すべてのデバイスに反映されます。 ### モバイル マテリアルのレンダリングをオーバーライドするオプション -**[ES2 Quality Settings]** の調節により、プラットフォームで使用できるレンダリング オプションのオーバーライドが可能nなります。Android も iOS も、ES2 Quality Setting は **[Project Settings (プロジェクト設定)]** > **[Platforms]** の **[Android ES2 Quality]** または **[iOS ES2 Quality Settings]** の中にあります。オーバーライドを使用するには、**[Enable Quality Override (品質オーバーライドを有効にする)]** オプションを開いて、オーバーライドしたいオプションをクリックして選択します。オプションをすべて選択したら、**[Update preview shaders (プレビュー シャドウを更新)]** ボタンを押してすべてのマテリアルを再コンパイルして、指定したオプションが使えるようにします。 +**[ES2 Quality Settings]** の調節により、プラットフォームで使用できるレンダリング オプションのオーバーライドが可能になります。Android も iOS も、ES2 Quality Setting は **[Project Settings (プロジェクト設定)]** > **[Platforms]** の **[Android ES2 Quality]** または **[iOS ES2 Quality Settings]** にあります。オーバーライドを使用するには、**[Enable Quality Override (品質オーバーライドを有効にする)]** オプションを開いて、オーバーライドしたいオプションをクリックして選択します。オプションをすべて選択したら、**[Update preview shaders (プレビュー シャドウを更新)]** ボタンを押してすべてのマテリアルを再コンパイルして、指定したオプションが使えるようにします。 [REGION:lightbox] @@ -310,7 +309,7 @@ UE4 で Material Quality Level を設定するには以下の手順に従いま [/REGION] ## モバイル レンダリング オプション -**[Project's Settings (プロジェクトの設定)]** メニューの **[Mobile]** セクションに、モバイル プロジェクトでライティングの処理方法を制御するプロパティがたくさん含まれています。これらの設定およびプロジェクトでのエフェクトについて、次のセクションで説明します。 +**[Project's Settings (プロジェクトの設定)]** メニューの **[Mobile]** セクションに、モバイル プロジェクトでライティングの処理方法を調整するプロパティが数多く含まれています。これらの設定およびプロジェクトでのエフェクトについて、次のセクションで説明します。 ### プロジェクト設定へのアクセス方法 **メインツールバー** から **[Edit (編集)]** > **[Project Settings (プロジェクト設定)]** を選びます。 @@ -334,8 +333,8 @@ UE4 で Material Quality Level を設定するには以下の手順に従いま |プロパティ名| 説明| |--------------------|-------| -|Mobile HDR|true の場合、モバイルはフル HDR でレンダリングされます。処理が遅いデバイスではパフォーマンスを上げるために、ライティング機能を必要としないゲームではこの設定は無効にしてください。| -|Max Dynamic Point Lights|モバイル デバイス上でサポートする動的なポイントライトの数です。動的なポイント ライトを必要としないゲームの場合は 0 に設定して、シェーダーの生成数が少なくなります。この設定を変更するには、エディタを再起動する必要があります。| +|Mobile HDR|true の場合、モバイルはフル HDR でレンダリングされます。処理が遅いデバイスではパフォーマンスが下がるため、ライティング機能を必要としないゲームではこの設定を無効にしてください。| +|Max Dynamic Point Lights|モバイル デバイス上でサポートする動的なポイントライトの数です。動的なポイント ライトを必要としないゲームの場合は 0 に設定して、シェーダーの生成数を減らします。この設定を変更するには、エディタを再起動する必要があります。| |Use Shared Dynamic Point LIght Shaders|有効にすると、サーフェイスに当たる動的ポイントライトに好きなだけ (Max Dynamic Point Lights での指定数まで) 同じシェーダーが使われます。処理は遅くなりますが、シェーダーの生成数は少なくなります。この設定を変更するには、エディタを再起動する必要があります。| |Enabled Combined Static and CSM Shadowing|Stationary Light (固定ライト) から静的シャドウと CSM シャドウの両方を受け取るプリミティブです。無効にすると、モバイル テクスチャ サンプリングが解除されます。| diff --git a/Engine/Documentation/Source/Platforms/Mobile/Performance/MobilePerformance.KOR.udn b/Engine/Documentation/Source/Platforms/Mobile/Performance/MobilePerformance.KOR.udn index bfc149cf018f..4fdbdd556e81 100644 --- a/Engine/Documentation/Source/Platforms/Mobile/Performance/MobilePerformance.KOR.udn +++ b/Engine/Documentation/Source/Platforms/Mobile/Performance/MobilePerformance.KOR.udn @@ -295,7 +295,7 @@ UE4 에서 머티리얼 퀄리티 레벨을 설정하는 방법은 다음과 같 클릭하면 이미지 원본을 확인합니다. [/REGION] -이 두 프로퍼티를 켜면 머티리얼을 저사양 디바이스에서 봤을 때 해당 기능의 렌더링 패쓰를 완전히 없애 렌더링 비용을 낮추는 데 도움이 됩니다. 하지만 이는 모든 디바이스에서 이 머티리얼을 켜느냐 마느냐 밖에 없는 양자택일 옵션입니다. +이 두 프로퍼티를 켜면 머티리얼을 저사양 디바이스에서 봤을 때 해당 기능의 렌더링 패스를 완전히 없애 렌더링 비용을 낮추는 데 도움이 됩니다. 하지만 이는 모든 디바이스에서 이 머티리얼을 켜느냐 마느냐 밖에 없는 양자택일 옵션입니다. ### 모바일 머티리얼 렌더링 오버라이드 diff --git a/Engine/Documentation/Source/Platforms/Mobile/Performance/TipsAndTricks/MobilePerfTipsAndTricks.JPN.udn b/Engine/Documentation/Source/Platforms/Mobile/Performance/TipsAndTricks/MobilePerfTipsAndTricks.JPN.udn index 12d2f09d12df..b432651ab835 100644 --- a/Engine/Documentation/Source/Platforms/Mobile/Performance/TipsAndTricks/MobilePerfTipsAndTricks.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Mobile/Performance/TipsAndTricks/MobilePerfTipsAndTricks.JPN.udn @@ -1,9 +1,14 @@ -INTSourceChangelist:2806926 -Title:モバイル パフォーマンス ヒントとコツ -Description:サポートされたモバイル デバイス上でのパフォーマンスが最適になるように、Unreal Match 3 ゲームに採用された最適化と技術 -Crumbs: -Parent:Platforms/Mobile/Performance +INTSourceChangelist:3108692 +Title:モバイル パフォーマンスのヒントとコツ +Description:サポートされたモバイル デバイスで最適なパフォーマンスを提供する Unreal Match 3 ゲームの最適化と技術 +Crumbs:%ROOT%, Platforms, Platforms/Mobile Availability:Public +Version:4.9 +Platform:Mobile +parent:Platforms/Mobile +order:6 +type:overview +tags:mobile [VAR:Topic] [OBJECT:Topic] @@ -81,7 +86,7 @@ Unreal Match 3 の場合、基本のベース プロファイルには何も追 +CVars=sg.EffectsQuality=3 +CVars=fx.MaxCPUParticlesPerEmitter 1000 -iPhone 6 は iPhone 4 よりもパワフルなので、設定は 6 では増えて、4 では減りました。IiOS セクションの下の Android セクションでは、High device profile と Low device profile が同じであることが分かります。 +iPhone 6 は iPhone 4 よりもパワフルなので、設定の多くは 6 では増加し 4 では減少しました。IiOS セクションの下の Android セクションでは、High device profile と Low device profile が同じであることが分かります。 [Android_Low DeviceProfile] +CVars=r.MobileContentScaleFactor=1.0 @@ -101,16 +106,16 @@ Unreal Match 3 に使われている設定とその機能の詳細をまとめ | 設定名 | 説明 | | ------------ | ----------- | -| r.MobileContentScaleFactor | デバイス上でのコンテンツのスケールを制御します。0 に設定すると、デバイスのネイティブ解像度が使用されます。UI スケールに DPI スケール カーブを使う場合は、必ずこの設定を 0 にします。 | -| r.ParticleLODBias | 表示するパーティクル LOD を制御します。0 は基本に使用、1 は最初の LOD、2 は 2 つ目の LOD というように使います。Unreal Match 3 では、最初の LOD だけをローエンド デバイス上でスポーンされたパーティクル量を半分にするために使います。 -| sg.EffectsQuality | ティックあたりのパーティクルのスポーン レートを制御します。0 から 3 の範囲で、デフォルト値は 3 です。この数字を下げると、パーティクルのティックあたりのスポーン量が減ります。この値を 1 にするとパーティクルは非常にまばらになるので、完全にローエンドのデバイスのみに使用することを推奨します。0 に設定するとパーティクルのスポーンが完全に停止します。 | +| r.MobileContentScaleFactor | デバイス上でのコンテンツのスケールを制御します。0 に設定すると、そのデバイスのネイティブ解像度が使用されます。UI スケールに DPI スケール カーブを使う場合は、必ずこの設定を 0 にします。 | +| r.ParticleLODBias | 表示するパーティクル LOD を制御します。0 は基本を使用、1 は最初の LOD、2 は 2 つ目の LOD というように使います。Unreal Match 3 では、最初の LOD だけを使用して、ローエンド デバイス上でスポーンされたパーティクル量を半分に減らします。 | +| sg.EffectsQuality | ティックあたりのパーティクルのスポーン レートを調節します。範囲は 0 から 3 です。デフォルトは 3 に設定されています。値を下げると、ティックあたりのパーティクルのスポーン量が減ります。1 にするとパーティクルはかなりまばらになるので、非常にローエンドのデバイスのみに使用することを推奨します。0 に設定するとパーティクルのスポーンが完全に停止します。 | | fx.MaxCPUParticlesPerEmitter | エミッタ当たりのエミットされる CPU パーティクル数です。 | ## LOD の様々な使用方法 ![](ULOD_00.png) -LOD は、プレイヤーのカメラから遠くのオブジェクトのレンダリング負荷を減らすのに役立つレンダリング ティックです。LOD は、低解像度のオブジェクトを格納することで動き、プレイヤーのカメラからの距離に応じてこれらのオブジェクト間を自動的に切り替えます。LOD が切り替わっているサンプルをこちらの動画でご覧いただけます。 +LOD は、プレイヤーのカメラから遠くにあるオブジェクトのレンダリング負荷を減らす場合に役立つレンダリング トリックです。LOD は、低解像度のオブジェクトを格納することで動き、プレイヤーのカメラからの距離に応じてこれらのオブジェクト間を自動的に切り替えます。以下の動画で動作中の LOD スイッチのサンプルをご覧いただけます。 [OBJECT:EmbeddedVideo] [PARAMLITERAL:videoid] @@ -124,7 +129,7 @@ LOD は、プレイヤーのカメラから遠くのオブジェクトのレン [/PARAMLITERAL] [/OBJECT] -Unreal Match 3 はスタティックメッスの LOD は使いませんが、パーティクル エフェクトの LOD を使うとローエンド デバイスのレンダリング要求を減らしやすくなります。まず最初に、開始点にパーティクルを使って LOD を新規作成します。次に、新規作成された LOD 内で、スポーンされるパーティクル数が半分になります。インスタンスの中には、エフェクト内のモジュールがまるごと無効になるものもあります。この VFX LOD を実際に使ってる様子が以下の画像です。 +Unreal Match 3 はスタティックメッシュに LOD は使用しませんが、パーティクル エフェクトに LOD を使用するとローエンド デバイスでのレンダリング負荷を下げることができます。パーティクルを使って開始点として最初に LOD を新規作成しておくと、新規作成された LOD 内で、スポーンされるパーティクル数が半分になります。インスタンスによっては、エフェクト内のモジュールがすべて無効になる場合もあります。この VFX LOD を実際に使ってる様子が以下の画像です。 [OBJECT:ComparisonSlider] [PARAM:before] @@ -143,7 +148,7 @@ Unreal Match 3 はスタティックメッスの LOD は使いませんが、パ [/REGION] --> -上の画像は **P_Selected_Title** パーティクル エフェクトです。現在選択中の宝石がローエンド デバイス用に最適化してあります。画像の左側はハイエンド デバイス向けの **P_Selected_Title** パーティクル エフェクトの基本です。この画像をじっくり見ると、パーティクル エフェクトの中に小さな白い四角に気が付くと思います。今度は画像の右側を見てください。同じ **P_Selected_Title** エフェクトを使っていても、小さな白い四角は見えません。これは、Unreal Match 3 がローエンド モバイル デバイスでも問題なく動作できるように、それらがエフェクトの LOD から完全に取り除かれたためです。これは必要な操作ほんのまだ半分です。次のステップは、メイン パーティクル エフェクトを使うモバイル デバイスと、メイン パーティクル エフェクトに基づいて様々な LOD を使うモバイル デバイスを定義する必要があります。まず、テキスト エディタで DefaultDeviceProfiles.ini を開き、下の画像にあるように **Android_Low DeviceProfile** エントリを探します。 +上の画像は **P_Selected_Title** パーティクル エフェクトです。現在選択中の宝石がローエンド デバイス用に最適化してあります。画像の左側はハイエンド デバイス向けの **P_Selected_Title** パーティクル エフェクトの基本 (Base) です。この画像をじっくり見ると、パーティクル エフェクトの中に小さな白い四角に気が付くと思います。今度は画像の右側を見てください。同じ **P_Selected_Title** エフェクトを使っていても、小さな白い四角は見えません。これは、Unreal Match 3 がローエンド モバイル デバイスでも問題なく動作できるように、それらがエフェクトの LOD から完全に取り除かれたためです。まだ必要な操作の半分にすぎません。次に、メイン パーティクル エフェクトを使うモバイル デバイスと、メイン パーティクル エフェクトに基づいて様々な LOD を使うモバイル デバイスを定義する必要があります。まず、テキスト エディタで DefaultDeviceProfiles.ini を開き、下の画像にあるように **Android_Low DeviceProfile** エントリを探します。 ![](ULOD_Android_Low_Profile.png) @@ -151,7 +156,7 @@ Unreal Match 3 はスタティックメッスの LOD は使いませんが、パ +CVars=r.ParticleLODBias=1 -[Android Device Profile] セクションの [Low Device] と [Mid Device] のエントリを見ると、この両方の種類はパーティクル エフェクト向けの LOD を使います。一方、[Highest Device] では LOD ではなく基本エフェクトが使われています。下の画像を見ると、パーティクル エフェクトをことなる LOD で表示するため、ローエンド、ミッドエンド、ハイエンドの Android デバイスをすべて一緒に使っていることがわかります。 +[Android Device Profile] セクションの [Low Device] と [Mid Device] のエントリを見ると、両方の種類にはパーティクル エフェクト向けの LOD が使われます。。一方、[Highest Device] では LOD ではなく基本エフェクトが使われています。下の画像を見ると、パーティクル エフェクトをことなる LOD で表示するため、ローエンド、ミッドエンド、ハイエンドの Android デバイスをすべて一緒に使っていることがわかります。 ![](ULOD_Android_Effect_LOD_Settings.png) @@ -171,7 +176,7 @@ Unreal Match 3 はスタティックメッスの LOD は使いませんが、パ ## キャラクターのライティング -Unreal Match 3 でキャラクター用に使われているマテリアルを見てみると、負荷の低い Unlit Shading Model ではなく Default Lit Shading Model をマテリアルに使用していることが分かります。夜のテーマを購入し有効にすると、トーチの灯りによりキャラクターに動的に陰影がつくようにするためです。Unlit になるようにマテリアルが変更されていると、動的シャドウのインタラクションは不可能になります。動的ライトはモバイル デバイスでは特に負荷が高いですが、Unreal Match 3 はリソースをほとんど要求しないので、動的な Point light を一つだけ作ったとしてもパフォーマンスはほとんど変わりません。 +Unreal Match 3 でキャラクター用に使われているマテリアルを見てみると、負荷の低い Unlit Shading Model ではなく Default Lit Shading Model をマテリアルに使用していることが分かります。夜のテーマが購入され有効にされた時に、トーチの灯りによりキャラクターに動的に陰影がつくようにするためです。Unlit になるようにマテリアルが変更されていると、動的シャドウのインタラクションは不可能になります。動的ライトはモバイル デバイスでは特に負荷が高いですが、Unreal Match 3 はリソースをほとんど要求しないので、動的なポイントライトを 1 つだけ付けたとしてもパフォーマンスはほとんど変わりません。 [OBJECT:ComparisonSlider] [PARAM:before] diff --git a/Engine/Documentation/Source/Platforms/Mobile/PostProcessEffects/MobilePostProcessEffects.INT.udn b/Engine/Documentation/Source/Platforms/Mobile/PostProcessEffects/MobilePostProcessEffects.INT.udn index cba774819ca8..767756e4a958 100644 --- a/Engine/Documentation/Source/Platforms/Mobile/PostProcessEffects/MobilePostProcessEffects.INT.udn +++ b/Engine/Documentation/Source/Platforms/Mobile/PostProcessEffects/MobilePostProcessEffects.INT.udn @@ -16,9 +16,37 @@ reference-image:Mobile_PostProcessEffect.gif Mobile Post Processing is implemented as a separate code path from PC/Console Post Processing. This is to reflect the slower dependent texture reads, missing hardware features, extra render target resolve costs, and slower performance in general. To enable Post Processing for your mobile applications, please make sure that **Mobile HDR** is enabled in your **Project Settings** as most of the settings below require Mobile HDR to be enabled for the effect(s) to work. +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] [region: lightbox] [![](MobileHDR_Enabled.png)(w:400)](MobileHDR_Enabled.png) [/region] +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +[region: lightbox] +[![](MobileHDR_Enabled_Mac.png)(w:400)](MobileHDR_Enabled_Mac.png) +[/region] +[/PARAM] +[/OBJECT] [region:caption] Click for full image. @@ -59,17 +87,76 @@ Click for full image. ### Enabling Tonemapper Film via .INI Files To enable or disable the Tonemapper project wide you will need to add **r.tonemapperfilm=1** to the **Rendering Settings** in your project's **DefaultEngine.ini**. + + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] [REGION:lightbox] [![](TM_Default_Engine_INI.png)(w:422 h:199)](TM_Default_Engine_INI.png) [/REGION] +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +[REGION:lightbox] +[![](TM_Default_Engine_INI_Mac.png)(w:422 h:199)](TM_Default_Engine_INI_Mac.png) +[/REGION] +[/PARAM] +[/OBJECT] [REGION:caption] Click for full image. [/REGION] +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] [REGION:lightbox] [![](TM_INI_Location.png)(w:422 h:199)](TM_INI_Location.png) [/REGION] +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +[REGION:lightbox] +[![](TM_INI_Location_Mac.png)(w:422 h:199)](TM_INI_Location_Mac.png) +[/REGION] +[/PARAM] +[/OBJECT] + [REGION:caption] Click for full image. @@ -241,9 +328,37 @@ You can now use the **Custom Depth** Post Process option with the Mobile renderi As this features requires Post-Processing to work correctly, **Mobile HDR** must be enabled. To enable Mobile HDR go to **Project Settings** > **Engine** > **Rendering** > **Mobile** and make sure that **Mobile HDR** is checked. +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +windows +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] [region: lightbox] [![](MobileHDR_Enabled.png)(w:400)](MobileHDR_Enabled.png) [/region] +[/PARAM] +[/OBJECT] + +[OBJECT:ToggleButtonContent] +[PARAMLITERAL:category] +OS +[/PARAMLITERAL] +[PARAMLITERAL:id] +mac +[/PARAMLITERAL] +[PARAMLITERAL:active] +[/PARAMLITERAL] +[PARAM:content] +[region: lightbox] +[![](MobileHDR_Enabled_Mac.png)(w:400)](MobileHDR_Enabled_Mac.png) +[/region] +[/PARAM] +[/OBJECT] [region:caption] Click for full image. diff --git a/Engine/Documentation/Source/Platforms/Mobile/PostProcessEffects/MobilePostProcessEffects.JPN.udn b/Engine/Documentation/Source/Platforms/Mobile/PostProcessEffects/MobilePostProcessEffects.JPN.udn index 21ee622178b8..60c7d94061de 100644 --- a/Engine/Documentation/Source/Platforms/Mobile/PostProcessEffects/MobilePostProcessEffects.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Mobile/PostProcessEffects/MobilePostProcessEffects.JPN.udn @@ -1,6 +1,5 @@ -INTSourceChangelist:3345705 -Availability:Public -Title:モバイル プラットフォームでポストプロセス エフェクトを使う +Availability:Public +Title:モバイル プラットフォームでのポストプロセス エフェクトの使用方法 Crumbs: Description:モバイル ゲームでのポストプロセス エフェクトの使用方法 Platform:Mobile @@ -14,8 +13,8 @@ reference-image:Mobile_PostProcessEffect.gif [TOC(start:2)] -モバイルのポストプロセスは、 PC / コンソールでのポストプロセスとは別のコードパスとして実施されます。その結果、依存するテクスチャの読み取り速度の低下、ハードウェア機能の不足、余分なレンダリング ターゲットの転換負荷、全般的なパフォーマンスの低下につながります。 -**[Project Settings (プロジェクト設定)]** で **[Mobile HDR]** を必ず有効にしてください。以下にあげるほとんどの設定ではエフェクトを使うためにこの設定を有効にする必要があります。 +モバイルのポストプロセスは、 PC / コンソールでのポストプロセスとは別のコードパスとして実行されます。その結果、依存テクスチャの読み取り速度の低下、ハードウェア機能不足、高いレンダリング負荷、そしてパフォーマンス全般の低下につながります。 +**[Project Settings (プロジェクト設定)]** で **[Mobile HDR]** を必ず有効にしてください。これから説明する設定では、この設定を有効にしないとエフェクトが機能しません。 [region: lightbox] [![](MobileHDR_Enabled.png)(w:400)](MobileHDR_Enabled.png) @@ -25,8 +24,8 @@ reference-image:Mobile_PostProcessEffect.gif クリックしてフルサイズで表示 [/region] -## モバイル デバイス用にトーンマッパを有効にする -モバイル デバイスで Tonemapper Post Processing オプションを使うためには、**r.tonemapperfilm** の値をデフォルト値の **0** から **1** へ変更する必要があります。アンリアル エンジン (UE4) でトーンマッパの変更や有効無効の切り替えを行うには、以下の手順に従います。 +## モバイル デバイスのトーンマッパを有効にする +モバイル デバイスで Tonemapper Post Processing オプションを使うためには、**r.tonemapperfilm** をデフォルト値の **0** から **1** へ変更する必要があります。アンリアル エンジン (UE4) でトーンマッパの変更や有効無効の切り替えを行うには、以下の手順に従います。 [OBJECT:ComparisonSlider] [PARAM:before] @@ -42,11 +41,11 @@ reference-image:Mobile_PostProcessEffect.gif トーンマッパを有効にするには、まず **Backtick key(`)** を押してコンソールを開いてから、トーンマッパを有効にする以下のコマンドを入力します。 * **r.tonemapperfilm 1** -トーンマッパを無効にするには、コンソールを開いてトーンマッパを無効にする以下のコマンドを入力します。 +トーンマッパを無効にするには、コンソールを開いて、以下のコマンドを入力します。 * **r.tonemapperfilm 0** [region:note] -このメソッドでは、このセッションのみにトーンマッパを有効にします。常にトーンマッパを有効にしておきたい場合は、使用したいトーンマッパ設定を DefaultEngine.INI に追加する必要があります。 +このメソッドでは、このセッションのみにトーンマッパを有効にします。常にトーンマッパを有効にするには、使用するトーンマッパ設定を DefaultEngine.INI に追加する必要があります。 [/region] [REGION:lightbox] @@ -77,7 +76,7 @@ reference-image:Mobile_PostProcessEffect.gif [/REGION] ### モバイル デバイス上でトーンマッパを有効にする -モバイル デバイス上でトーンマッパを有効にするには、**4 本の指** で同時に画面をタップして **コンソール ウィンドウ** を立ち上げ、次に **r.tonemapperfilm 1** を入力してトーンマッパを有効にする、または **r.tonemapperfilm 0** を入力してトーンマッパを無効にします。 +モバイル デバイス上でトーンマッパを有効にするには、**4 本の指** で同時に画面をタップして **コンソール ウィンドウ** を立ち上げます。有効にするには **r.tonemapperfilm 1**、無効にするには **r.tonemapperfilm 0** を入力します。 [REGION:lightbox] [![](TM_Phone_Console.png)(w:640 h:360)](TM_Phone_Console.png) @@ -88,7 +87,7 @@ reference-image:Mobile_PostProcessEffect.gif [/REGION] ## モバイルでサポートされているポストプロセス エフェクトと設定 -次のセクションでは、モバイル デバイスでサポートされているポストプロセス エフェクトと設定、およびトーンマッパを有効にする必要があるかどうかを説明します。 +次のセクションでは、モバイル デバイスでサポートされているポストプロセス エフェクトと設定方法、およびトーンマッパを有効にする必要性について説明します。 [REGION:lightbox] [![](TM_PostProcess_Settings.png)(w:275 h:355)](TM_PostProcess_Settings.png) @@ -225,8 +224,8 @@ reference-image:Mobile_PostProcessEffect.gif [/REGION] モバイル アプリケーションにエフェクトを追加するには、カスタム ポストプロセス マテリアルの開発が必要です。その際、 -いくつか重要な点を考慮する必要があります。特に、モバイル アプリケーション向けのカスタム ポストプロセス マテリアルは、 -以下の **Blendable Locations** で PostProcessInput0 (Scene Color) からのみフェッチ可能です。これは重要ですので留意してください。 +いくつか重要な点を考慮する必要があります。その中でも特に重要なのは、モバイル アプリケーション向けのカスタム ポストプロセス マテリアルは、 +以下の **Blendable Locations** で PostProcessInput0 (Scene Color) からのみフェッチ可能という点です。 * **Before Tonemapping** * **After Tonemapping** @@ -240,7 +239,7 @@ Blendable Locations の詳細は、[](Engine/Rendering/PostProcessEffects/PostPr ![](Custom_Scene_Depth.png) -この機能が正しく動作するには **Mobile HDR** を有効にしておく必要があります。Mobile HDR を有効にするには、**[Project Settings]** > **[Engine]** > **[Rendering]** > **[Mobile]** で **[Mobile HDR]** にチェックが入っていることを確認してください。 +この機能が正しく動作するためには、**Mobile HDR** を有効にしておく必要があります。Mobile HDR は、**[Project Settings]** > **[Engine]** > **[Rendering]** > **[Mobile]** で **[Mobile HDR]** にチェックが入っていれば有効です。 [region: lightbox] [![](MobileHDR_Enabled.png)(w:400)](MobileHDR_Enabled.png) @@ -251,7 +250,7 @@ Blendable Locations の詳細は、[](Engine/Rendering/PostProcessEffects/PostPr [/region] [region:warning] -ただし、この機能は **Mobile MSAA** が有効にされていると正しく動作しません。デバイス上でエフェクトを表示するには Mobile MSAA を無効にしてください。 +ただし、この機能は **Mobile MSAA** が有効な場合、正しく動作しません。デバイス上でエフェクトを表示するには Mobile MSAA を無効にしてください。 [/region] ## ポストプロセス パフォーマンス全般におけるヒント diff --git a/Engine/Documentation/Source/Platforms/Mobile/PostProcessEffects/MobilePostProcessEffects.KOR.udn b/Engine/Documentation/Source/Platforms/Mobile/PostProcessEffects/MobilePostProcessEffects.KOR.udn index f5f0abb1c0b9..5dd0039a9dc3 100644 --- a/Engine/Documentation/Source/Platforms/Mobile/PostProcessEffects/MobilePostProcessEffects.KOR.udn +++ b/Engine/Documentation/Source/Platforms/Mobile/PostProcessEffects/MobilePostProcessEffects.KOR.udn @@ -14,7 +14,7 @@ reference-image:Mobile_PostProcessEffect.gif [TOC(start:2)] -모바일 포스트 프로세싱은 PC/콘솔 포스트 프로세싱과는 별도의 코드 패쓰로 구현되어 있습니다. 속도가 느린 종속적 텍스처 읽기, 부족한 하드웨어 기능, 더 높은 렌더타겟 리졸브 비용, 전반적으로 느린 퍼포먼스를 반영하기 위해서입니다. +모바일 포스트 프로세싱은 PC/콘솔 포스트 프로세싱과는 별도의 코드 패스로 구현되어 있습니다. 속도가 느린 종속적 텍스처 읽기, 부족한 하드웨어 기능, 더 높은 렌더타겟 리졸브 비용, 전반적으로 느린 퍼포먼스를 반영하기 위해서입니다. 모바일 어플리케이션에 포스트 프로세싱을 켜려면, **프로젝트 세팅** 의 **Mobile HDR** 을 켜야 합니다. 아래 대부분의 세팅은 Mobile HDR 을 켜야 작동하는 기능입니다. [region: lightbox] @@ -265,7 +265,7 @@ AA 메소드는 "None" (가장 빠름) 및 "TemporalAA" 를 지원하며, 여기 r.RenderTargetSwitchWorkaround 일부 모바일 플랫폼에서는 렌더 타겟 전환시의 퍼포먼스 하락을 피하기 위해 우회법이 필요할 것입니다. - 일부 하드웨어에서만 켜는 방법인데, 블룸 퀄리티에도 약간 영향을 끼칩니다. 일반 코드 패쓰보다 느리게 실행되지만, + 일부 하드웨어에서만 켜는 방법인데, 블룸 퀄리티에도 약간 영향을 끼칩니다. 일반 코드 패스보다 느리게 실행되지만, 렌더 타겟 전환을 여러번 피할 수 있어서 더욱 빠릅니다 (기본값: 0_ 모든 32 비트 iOS 디바이스에서 이것을 (1) 켜고자 했습니다 (DeviceProfiles 를 통해 구현). [/REGION] \ No newline at end of file diff --git a/Engine/Documentation/Source/Platforms/Mobile/Textures/MobileTextures.INT.udn b/Engine/Documentation/Source/Platforms/Mobile/Textures/MobileTextures.INT.udn index 742da1a419d9..7e008e13d8d3 100644 --- a/Engine/Documentation/Source/Platforms/Mobile/Textures/MobileTextures.INT.udn +++ b/Engine/Documentation/Source/Platforms/Mobile/Textures/MobileTextures.INT.udn @@ -47,11 +47,63 @@ To set the Texture LOD settings per-device you will need to do the following. 1. From the main Tool Bar open the **Devices Profiles** manager by going to **Windows** > **Developer Tools** and then clicking on **Device Profiles**. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](T_Device_Profiles_Manager.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](T_Device_Profiles_Manager_Mac.png) + [/PARAM] + [/OBJECT] 1. After clicking on the **Device Profiles** option the following menu will be displayed. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](T_DPM.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](T_Device_Profiles_Manager_Mac.png) + [/PARAM] + [/OBJECT] 1. From this menu select the device you want to edit and then click on the three dots that are to the left of the device name to open that devices profile. diff --git a/Engine/Documentation/Source/Platforms/OSVR/OSVR.JPN.udn b/Engine/Documentation/Source/Platforms/OSVR/OSVR.JPN.udn index ae84bbbb5baf..6f4a5d79f8ee 100644 --- a/Engine/Documentation/Source/Platforms/OSVR/OSVR.JPN.udn +++ b/Engine/Documentation/Source/Platforms/OSVR/OSVR.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3150518 +INTSourceChangelist:3429260 Title:OSVR の開発 Crumbs:%ROOT%, Platforms Description: @@ -14,7 +14,7 @@ social-image:googlevr_social.png ## はじめよう -PC および Android ベースのスマートフォンを使って UE4 と OSV を使う方法を説明します。 +OSVR クイックスタートでは、UE4 および OSVR を使用するための PC 設定方法を説明します。 [DIR(output:"listbutton" type:"quick start" parent:"Platforms/OSVR")] diff --git a/Engine/Documentation/Source/Platforms/OSVR/OSVR.KOR.udn b/Engine/Documentation/Source/Platforms/OSVR/OSVR.KOR.udn index e0c6cb1b01d9..dbd0ecdb27bf 100644 --- a/Engine/Documentation/Source/Platforms/OSVR/OSVR.KOR.udn +++ b/Engine/Documentation/Source/Platforms/OSVR/OSVR.KOR.udn @@ -1,5 +1,5 @@ -INTSourceChangelist:3150518 -Title:OSVR Development +INTSourceChangelist:3429260 +Title:OSVR 개발 Crumbs:%ROOT%, Platforms Description: Availability:Docs @@ -13,10 +13,10 @@ tags:OSVR social-image:googlevr_social.png -## Starting Out -The OSVR Quick Start will walk you through getting your PC setup to work with UE4 and OSVR. +## 시작하기 +OSVR 퀵 스타트는 UE4 로 OSVR 작업을 하기 위한 PC 구성을 안내해 드립니다. -[DIR(output:"listbutton" type:"quickstart" parent:"Platforms/OSVR")] +[DIR(output:"listbutton" type:"quick start" parent:"Platforms/OSVR")] diff --git a/Engine/Documentation/Source/Platforms/Oculus/Oculus.INT.udn b/Engine/Documentation/Source/Platforms/Oculus/Oculus.INT.udn index 0a9356ea004c..47d6d334ba99 100644 --- a/Engine/Documentation/Source/Platforms/Oculus/Oculus.INT.udn +++ b/Engine/Documentation/Source/Platforms/Oculus/Oculus.INT.udn @@ -10,6 +10,7 @@ parent:Platforms/VR tags:VR tags:Oculus Rift tags:Platform +Topic-image:OculusRiftDevelopment_topic.png ## Starting Out diff --git a/Engine/Documentation/Source/Platforms/Oculus/Oculus.KOR.udn b/Engine/Documentation/Source/Platforms/Oculus/Oculus.KOR.udn index 6a0f8681c711..31aa9b44b89f 100644 --- a/Engine/Documentation/Source/Platforms/Oculus/Oculus.KOR.udn +++ b/Engine/Documentation/Source/Platforms/Oculus/Oculus.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3235148 +INTSourceChangelist:3467293 Title:오큘러스 리프트 개발 Crumbs:%ROOT%, Platforms Description: @@ -11,6 +11,7 @@ parent:Platforms/VR tags:VR tags:Oculus Rift tags:Platform +Topic-image:OculusRiftDevelopment_topic.png ## 시작하기 diff --git a/Engine/Documentation/Source/Platforms/Oculus/QuickStart/OculusQuickStart.INT.udn b/Engine/Documentation/Source/Platforms/Oculus/QuickStart/OculusQuickStart.INT.udn index 8dd708d7c709..c53aa51f048c 100644 --- a/Engine/Documentation/Source/Platforms/Oculus/QuickStart/OculusQuickStart.INT.udn +++ b/Engine/Documentation/Source/Platforms/Oculus/QuickStart/OculusQuickStart.INT.udn @@ -6,6 +6,7 @@ Version: 4.11 SkillLevel: Intermediate parent:Platforms/Oculus type:quick start +type:landing tags:VR tags:Oculus Rift diff --git a/Engine/Documentation/Source/Platforms/Oculus/QuickStart/OculusQuickStart.KOR.udn b/Engine/Documentation/Source/Platforms/Oculus/QuickStart/OculusQuickStart.KOR.udn index 4fd06c775d22..ba477db1e8b7 100644 --- a/Engine/Documentation/Source/Platforms/Oculus/QuickStart/OculusQuickStart.KOR.udn +++ b/Engine/Documentation/Source/Platforms/Oculus/QuickStart/OculusQuickStart.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3150518 +INTSourceChangelist:3429260 Title:오큘러스 리프트 퀵스타트 Crumbs:%ROOT%, Platforms, Platforms/Oculus Description:오큘러스 리프트용 게임 셋업 및 실행 관련 안내입니다. @@ -7,6 +7,7 @@ Version: 4.11 SkillLevel: Intermediate parent:Platforms/Oculus type:quick start +type:landing tags:VR tags:Oculus Rift diff --git a/Engine/Documentation/Source/Platforms/Platforms.INT.udn b/Engine/Documentation/Source/Platforms/Platforms.INT.udn index 4bc39c8fb33e..28791bd07dda 100644 --- a/Engine/Documentation/Source/Platforms/Platforms.INT.udn +++ b/Engine/Documentation/Source/Platforms/Platforms.INT.udn @@ -7,49 +7,26 @@ version: 4.9 parent:%ROOT% order:8 type:landing +topic-icon:%ROOT%/platform_icon.png -[VAR:Params] -[PARAM:image] - ![%Platforms:title%](%ROOT%/placeholder_topic.png) -[/PARAM] -[PARAM:icon] - ![](%ROOT%/platform_icon.png)(convert:false) -[/PARAM] -[PARAM:title] - %Platforms:title% -[/PARAM] -[PARAM:description] - %Platforms:description% -[/PARAM] -[PARAM:path] - [RELATIVE:Platforms] -[/PARAM] -[/VAR] -[VAR:Topic] -[OBJECT:Topic] -%params% -[/OBJECT] -[/VAR] +## Mobile -[VAR:TopicCompact] -[OBJECT:TopicCompact] -%params% -[/OBJECT] -[/VAR] +[DIR(end:"2" output:"topic" type:"landing" parent:"Platforms" tags:"Mobile" org:"hierarchy")] -[VAR:Role] -[OBJECT:Role] -%params% -[PARAMLITERAL:id] -platforms -[/PARAMLITERAL] -[/OBJECT] -[/VAR] +## Virtual Reality -## Platforms +[DIR(end:"2" output:"topic" type:"landing" parent:"Platforms" tags:"VR" tags:"Platform" org:"hierarchy")] -[DIR(end:"2" output:"listbutton" type:"landing" parent:"Platforms" org:"hierarchy")] +## Desktop + +[DIR(end:"2" output:"topic" type:"landing" parent:"Platforms" tags:"Desktop" org:"hierarchy")] + +[PUBLISH:licensee] +## Console + +[DIR(end:"2" output:"topic" type:"landing" parent:"Platforms" tags:"Console" org:"hierarchy")] +[/PUBLISH:licensee] ## Platform Tools diff --git a/Engine/Documentation/Source/Platforms/Platforms.JPN.udn b/Engine/Documentation/Source/Platforms/Platforms.JPN.udn index 92fddebc3a9d..03b808821c90 100644 --- a/Engine/Documentation/Source/Platforms/Platforms.JPN.udn +++ b/Engine/Documentation/Source/Platforms/Platforms.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3151855 +INTSourceChangelist:3429257 Availability:Public Title:プラットフォーム開発 Crumbs:%ROOT% @@ -8,49 +8,26 @@ version:4.9 parent:%ROOT% order:8 type:landing +topic-icon:%ROOT%/platform_icon.png -[VAR:Params] -[PARAM:image] - ![%Platforms:title%](%ROOT%/placeholder_topic.png) -[/PARAM] -[PARAM:icon] - ![](%ROOT%/platform_icon.png)(convert:false) -[/PARAM] -[PARAM:title] - %Platforms:title% -[/PARAM] -[PARAM:description] - %Platforms:description% -[/PARAM] -[PARAM:path] - [RELATIVE:Platforms] -[/PARAM] -[/VAR] -[VAR:Topic] -[OBJECT:Topic] -%params% -[/OBJECT] -[/VAR] +## モバイル -[VAR:TopicCompact] -[OBJECT:TopicCompact] -%params% -[/OBJECT] -[/VAR] +[DIR(end:"2" output:"topic" type:"landing" parent:"Platforms" tags:"Mobile" org:"hierarchy")] -[VAR:Role] -[OBJECT:Role] -%params% -[PARAMLITERAL:id] -プラットフォーム -[/PARAMLITERAL] -[/OBJECT] -[/VAR] +## VR -## プラットフォーム +[DIR(end:"2" output:"topic" type:"landing" parent:"Platforms" tags:"VR" tags:"Platform" org:"hierarchy")] -[DIR(end:"2" output:"listbutton" type:"landing" parent:"Platforms" org:"hierarchy")] +## デスクトップ + +[DIR(end:"2" output:"topic" type:"landing" parent:"Platforms" tags:"Desktop" org:"hierarchy")] + +[PUBLISH:licensee] +## コンソール + +[DIR(end:"2" output:"topic" type:"landing" parent:"Platforms" tags:"Console" org:"hierarchy")] +[/PUBLISH:licensee] ## Platform ツール diff --git a/Engine/Documentation/Source/Platforms/Platforms.KOR.udn b/Engine/Documentation/Source/Platforms/Platforms.KOR.udn index c54823e3915f..42974a63030a 100644 --- a/Engine/Documentation/Source/Platforms/Platforms.KOR.udn +++ b/Engine/Documentation/Source/Platforms/Platforms.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3151855 +INTSourceChangelist:3429257 Availability:Public Title:플랫폼 개발 Crumbs:%ROOT% @@ -8,49 +8,26 @@ version: 4.9 parent:%ROOT% order:8 type:landing +topic-icon:%ROOT%/platform_icon.png -[VAR:Params] -[PARAM:image] - ![%Platforms:title%](%ROOT%/placeholder_topic.png) -[/PARAM] -[PARAM:icon] - ![](%ROOT%/platform_icon.png)(convert:false) -[/PARAM] -[PARAM:title] - %Platforms:title% -[/PARAM] -[PARAM:description] - %Platforms:description% -[/PARAM] -[PARAM:path] - [RELATIVE:Platforms] -[/PARAM] -[/VAR] -[VAR:Topic] -[OBJECT:Topic] -%params% -[/OBJECT] -[/VAR] +## 모바일 -[VAR:TopicCompact] -[OBJECT:TopicCompact] -%params% -[/OBJECT] -[/VAR] +[DIR(end:"2" output:"topic" type:"landing" parent:"Platforms" tags:"Mobile" org:"hierarchy")] -[VAR:Role] -[OBJECT:Role] -%params% -[PARAMLITERAL:id] -platforms -[/PARAMLITERAL] -[/OBJECT] -[/VAR] +## 가상 현실 -## 플랫폼 +[DIR(end:"2" output:"topic" type:"landing" parent:"Platforms" tags:"VR" tags:"Platform" org:"hierarchy")] -[DIR(end:"2" output:"listbutton" type:"landing" parent:"Platforms" org:"hierarchy")] +## 데스크탑 + +[DIR(end:"2" output:"topic" type:"landing" parent:"Platforms" tags:"Desktop" org:"hierarchy")] + +[PUBLISH:licensee] +## 콘솔 + +[DIR(end:"2" output:"topic" type:"landing" parent:"Platforms" tags:"Console" org:"hierarchy")] +[/PUBLISH:licensee] ## 플랫폼 툴 diff --git a/Engine/Documentation/Source/Platforms/SteamVR/QuickStart/SteamVRQuickStart.INT.udn b/Engine/Documentation/Source/Platforms/SteamVR/QuickStart/SteamVRQuickStart.INT.udn index 9f4108e07938..e11ee51590d3 100644 --- a/Engine/Documentation/Source/Platforms/SteamVR/QuickStart/SteamVRQuickStart.INT.udn +++ b/Engine/Documentation/Source/Platforms/SteamVR/QuickStart/SteamVRQuickStart.INT.udn @@ -5,6 +5,7 @@ Availability:public Navigation:platform Platform:SteamVR type:quick start +type:landing parent:Platforms/SteamVR tags:VR tags:SteamVR diff --git a/Engine/Documentation/Source/Platforms/SteamVR/QuickStart/SteamVRQuickStart.JPN.udn b/Engine/Documentation/Source/Platforms/SteamVR/QuickStart/SteamVRQuickStart.JPN.udn index e1280f8a9bc6..994cf5e408d2 100644 --- a/Engine/Documentation/Source/Platforms/SteamVR/QuickStart/SteamVRQuickStart.JPN.udn +++ b/Engine/Documentation/Source/Platforms/SteamVR/QuickStart/SteamVRQuickStart.JPN.udn @@ -1,11 +1,12 @@ -INTSourceChangelist:3150518 +INTSourceChangelist:3429260 Title:SteamVR クイック スタート Crumbs:%ROOT%, Platforms -Description:SteamVR を UE4 で使うために設定する操作手順 +Description:SteamVR を UE4 で使用するための設定方法 Availability:public Navigation:platform Platform:SteamVR type:quick start +type:landing parent:Platforms/SteamVR tags:VR tags:SteamVR @@ -13,7 +14,7 @@ tags:SteamVR ![](Platforms\SteamVR\T_Vive_HMD.png) このガイドでは、アンリアル エンジン 4 で SteamVR が使えるようにする手順を説明します。 -最後まで完了すると、SteamVR が使用できるプロジェクトを新規に作成することができるようになります。 +最後まで完了すると、SteamVR が使用できるプロジェクトの新規作成が可能になります。 [OBJECT:TopicButtonList] [PARAM:icon] diff --git a/Engine/Documentation/Source/Platforms/SteamVR/QuickStart/SteamVRQuickStart.KOR.udn b/Engine/Documentation/Source/Platforms/SteamVR/QuickStart/SteamVRQuickStart.KOR.udn index 260423f9d839..4a491144466c 100644 --- a/Engine/Documentation/Source/Platforms/SteamVR/QuickStart/SteamVRQuickStart.KOR.udn +++ b/Engine/Documentation/Source/Platforms/SteamVR/QuickStart/SteamVRQuickStart.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3150518 +INTSourceChangelist:3429260 Title: SteamVR 퀵 스타트 Crumbs:%ROOT%, Platforms Description: UE4 에서 SteamVR 을 사용하도록 하는 구성법 안내서입니다. @@ -6,6 +6,7 @@ Availability:public Navigation:platform Platform:SteamVR type:quick start +type:landing parent:Platforms/SteamVR tags:VR tags:SteamVR diff --git a/Engine/Documentation/Source/Platforms/SteamVR/SteamVR.INT.udn b/Engine/Documentation/Source/Platforms/SteamVR/SteamVR.INT.udn index da303d412c1f..27aadb3e2c51 100644 --- a/Engine/Documentation/Source/Platforms/SteamVR/SteamVR.INT.udn +++ b/Engine/Documentation/Source/Platforms/SteamVR/SteamVR.INT.udn @@ -9,6 +9,7 @@ parent:Platforms/VR tags:VR tags:SteamVR tags:Platform +Topic-image:SteamVRDevelopment_topic.png ![](T_Vive_HMD.png) diff --git a/Engine/Documentation/Source/Platforms/SteamVR/SteamVR.JPN.udn b/Engine/Documentation/Source/Platforms/SteamVR/SteamVR.JPN.udn index e119c8359c0b..ffb3fc6cc90e 100644 --- a/Engine/Documentation/Source/Platforms/SteamVR/SteamVR.JPN.udn +++ b/Engine/Documentation/Source/Platforms/SteamVR/SteamVR.JPN.udn @@ -1,7 +1,7 @@ -INTSourceChangelist:3235148 +INTSourceChangelist:3467293 Title:SteamVR の開発 Crumbs:%ROOT%, Platforms -Description:SteamVR 入門 +Description:SteamVR をはじめよう Availability:Public Navigation:platform Platform:SteamVR @@ -10,6 +10,7 @@ parent:Platforms/VR tags:VR tags:SteamVR tags:Platform +Topic-image:SteamVRDevelopment_topic.png ![](T_Vive_HMD.png) diff --git a/Engine/Documentation/Source/Platforms/SteamVR/SteamVR.KOR.udn b/Engine/Documentation/Source/Platforms/SteamVR/SteamVR.KOR.udn index 953d5552aba6..8afc001ec40e 100644 --- a/Engine/Documentation/Source/Platforms/SteamVR/SteamVR.KOR.udn +++ b/Engine/Documentation/Source/Platforms/SteamVR/SteamVR.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3235148 +INTSourceChangelist:3467293 Title: SteamVR 개발 Crumbs:%ROOT%, Platforms Description:SteamVR 개발 시작을 위한 안내서입니다. @@ -10,6 +10,7 @@ parent:Platforms/VR tags:VR tags:SteamVR tags:Platform +Topic-image:SteamVRDevelopment_topic.png ![](T_Vive_HMD.png) diff --git a/Engine/Documentation/Source/Platforms/VR/ContentSetup/VRContent.INT.udn b/Engine/Documentation/Source/Platforms/VR/ContentSetup/VRContent.INT.udn index 919e07e9d0e9..1341a52b4b11 100644 --- a/Engine/Documentation/Source/Platforms/VR/ContentSetup/VRContent.INT.udn +++ b/Engine/Documentation/Source/Platforms/VR/ContentSetup/VRContent.INT.udn @@ -8,44 +8,6 @@ parent:Platforms/VR type:overview tags:VR -[VAR:Params] -[PARAM:image] - ![%Platforms:title%](%ROOT%/placeholder_topic.png) -[/PARAM] -[PARAM:icon] - ![](%ROOT%/platform_icon.png)(convert:false) -[/PARAM] -[PARAM:title] - %Platforms:title% -[/PARAM] -[PARAM:description] - %Platforms:description% -[/PARAM] -[PARAM:path] - [RELATIVE:Platforms] -[/PARAM] -[/VAR] - -[VAR:Topic] -[OBJECT:Topic] -%params% -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] -%params% -[/OBJECT] -[/VAR] - -[VAR:Role] -[OBJECT:Role] -%params% -[PARAMLITERAL:id] -platforms -[/PARAMLITERAL] -[/OBJECT] -[/VAR] [TOC(start:2)] @@ -65,7 +27,6 @@ The following .INI settings were taken from the UE4 powered, VR demo, Showdown. These . INIsettings, if used, should be added to your project's **Config\DefaultEngine.INI** file, under **SystemSettings**. [SystemSettings] - r.VolumeMultiplier=1.0 r.screenpercentage=130 r.SeparateTranslucency=0 r.HZBOcclusion=0 @@ -77,7 +38,6 @@ These . INIsettings, if used, should be added to your project's **Config\Default r.SSR.Quality=1 r.DepthOfFieldQuality=0 r.SceneColorFormat=2 - r.SSSSS=0 r.TranslucencyVolumeBlur=0 r.TranslucencyLightingVolumeDim=4 r.MaxAnisotropy=8 @@ -86,7 +46,6 @@ These . INIsettings, if used, should be added to your project's **Config\Default r.FastBlurThreshold=0 r.SSR.MaxRoughness=0.1 r.rhicmdbypass=0 - r.TiledReflectionEnvironmentMinimumCount=10 sg.EffectsQuality=2 sg.PostProcessQuality=0 @@ -306,7 +265,7 @@ To fix this, fake blob shadows were introduced that could dynamically adjust the This helped give the illusion that a character was casting shadows when they came close to the ground (or other objects). [region:lightbox] - [![](VR_Fake_Shadow_Material.png)](VR_Fake_Shadow_Material.png) + [![](VR_Fake_Shadow_Material.png)(w:1000)](VR_Fake_Shadow_Material.png) [/region] [region:caption] @@ -352,9 +311,8 @@ Set World to Meters Scale| Sets the World to Meters scale, which changes the sca Due to the manner in which HMD's work, some art techniques that are staples of Video Game development, no longer have the impact that they once did. Below, you will find a list of features that might not work as expected in VR, with possible workarounds to address this. -|Know Issues| Workaround | -|---| --- | -| Screen Space Reflections (SSR)|While SSR will still work in VR the reflections that they produce could have issues matching up to what it is reflecting in the world. Instead of using SSR use [Reflection Probes](Resources/Showcases/Reflections#reflectionenvironment) as they are much cheaper and do suffer less from reflection alignment issues.| + +* **Screen Space Reflections(SSR):** While SSR will still work in VR the reflections that they produce could have issues matching up to what it is reflecting in the world. Instead of using SSR use [Reflection Probes](Resources/Showcases/Reflections#reflectionenvironment) as they are much cheaper and do suffer less from reflection alignment issues. **Normal Mapping Issues** @@ -365,7 +323,5 @@ However, that does not mean that you should not, or will not, need to use Normal it just means that you need to more closely evaluate if the data you are trying to convey in the Normal map would be better off being made out of geometry. Below, you will find some different techniques that can be used in place of Normal maps. -|Shader Type | Description| -|---|---| -|[Parallax Mapping](http://en.wikipedia.org/wiki/Parallax_mapping)| Parallax mapping takes Normal mapping to the next level, by accounting for depth cues that Normal mapping does not. A Parallax mapping shader can better display depth information, making objects appear to have more detail than they do. This is due to the fact that no matter what angle you look at, a Parallax map will always correct itself to show you the correct depth information from your view point. The best use of a Parallax map would be for cobblestone pathways and fine detail on surfaces. +* **[Parallax Mapping](http://en.wikipedia.org/wiki/Parallax_mapping):** Parallax mapping takes Normal mapping to the next level, by accounting for depth cues that Normal mapping does not. A Parallax mapping shader can better display depth information, making objects appear to have more detail than they do. This is due to the fact that no matter what angle you look at, a Parallax map will always correct itself to show you the correct depth information from your view point. The best use of a Parallax map would be for cobblestone pathways and fine detail on surfaces. diff --git a/Engine/Documentation/Source/Platforms/VR/ContentSetup/VRContent.JPN.udn b/Engine/Documentation/Source/Platforms/VR/ContentSetup/VRContent.JPN.udn index 6d9505c6309c..15daf389d6f9 100644 --- a/Engine/Documentation/Source/Platforms/VR/ContentSetup/VRContent.JPN.udn +++ b/Engine/Documentation/Source/Platforms/VR/ContentSetup/VRContent.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3322543 +INTSourceChangelist:3429260 Availability:Public Title:仮想現実 (VR) のベスト プラクティス Crumbs: @@ -9,64 +9,25 @@ parent:Platforms/VR type:overview tags:VR -[VAR:Params] -[PARAM:image] - ![%Platforms:title%](%ROOT%/placeholder_topic.png) -[/PARAM] -[PARAM:icon] - ![](%ROOT%/platform_icon.png)(convert:false) -[/PARAM] -[PARAM:title] - %Platforms:title% -[/PARAM] -[PARAM:description] - %Platforms:description% -[/PARAM] -[PARAM:path] - [RELATIVE:Platforms] -[/PARAM] -[/VAR] - -[VAR:Topic] -[OBJECT:Topic] -%params% -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] -%params% -[/OBJECT] -[/VAR] - -[VAR:Role] -[OBJECT:Role] -%params% -[PARAMLITERAL:id] -platforms -[/PARAMLITERAL] -[/OBJECT] -[/VAR] [TOC(start:2)] -ユーザーが最高の VR 体験ができるように、仮想現実 (VR) 向けのコンテンツ開発では -一部のワークフローを調整する必要があります。このガイドの目的は、VR プロジェクト用のコンテンツの開発にあたり、 -留意しておくべき主要事項のいくつかを分かりやすく説明することが目的です。 +ユーザーに最高の VR 体験を提供するには、仮想現実 (VR) 向けコンテンツ開発の +ワークフローを部分的に調整する必要があります。このガイドの目的は、VR プロジェクト用コンテンツの開発にあたり、 +留意しておくべき主要項目を分かりやすく説明することです。 ## VR プロジェクト設定 ベースがブループリントまたは C++ のいずれの場合も、VR 用プロジェクトを新規作成するには、**Scalable 3D または 2D** グラフィクスと **No Starter Content** を使って **[Mobile / Tablet]** オプションを使用したプロジェクトを作成するのがベストです。 -そうすると、VR プロジェクトが起動直後にフレームで確実に実行されます。 +この方法だと、VR プロジェクトが起動直後にフレームで確実に実行されます。 ![](VR_Project_Settings.png) ## VR .INI 設定 -以下の .INI 設定は、UE4 が搭載された VR デモの Showdown のものです。 -これらの .INI 設定を使用する場合は、プロジェクト **「Config\DefaultEngine.INI」** ファイルの **[SystemSettings]** に追加しなければなりません。 +以下は、UE4 が搭載された VR デモの Showdown の.INI 設定です。 +これらの .INI 設定を使用する場合は、プロジェクトの **「Config\DefaultEngine.INI」** ファイルの **[SystemSettings]** に追加しなければなりません。 [SystemSettings] - r.VolumeMultiplier=1.0 r.screenpercentage=130 r.SeparateTranslucency=0 r.HZBOcclusion=0 @@ -78,7 +39,6 @@ platforms r.SSR.Quality=1 r.DepthOfFieldQuality=0 r.SceneColorFormat=2 - r.SSSSS=0 r.TranslucencyVolumeBlur=0 r.TranslucencyLightingVolumeDim=4 r.MaxAnisotropy=8 @@ -87,21 +47,20 @@ platforms r.FastBlurThreshold=0 r.SSR.MaxRoughness=0.1 r.rhicmdbypass=0 - r.TiledReflectionEnvironmentMinimumCount=10 sg.EffectsQuality=2 sg.PostProcessQuality=0 ## VR Instanced Stereo -UE 4.11 のリリースでは、VR のパフォーマンスに対する影響を緩和するために Instanced Stereo レンダリングが実装されました。 +UE 4.11 のリリースでは、パフォーマンスに対する VR の負荷を緩和するために Instanced Stereo レンダリングが実装されました。 この機能は、**[Edit (編集)] -> [Project Settings (プロジェクト設定)] -> [Rendering (レンダリング)] -> VR** の [Instanced Stereo] オプションにチェックを入れて有効にします。 ![](VR_ISR.png) **Instanced Stereo** レンダリングを有効にした後、エンジンを再起動し、シェーダーを再コンパイルする必要があります。 - ベース パスと Early-Z パス (両方ともシリアルおよび並列レンダリング パス) は、機能が有効にされると、スタティック メッシュ、スケルタル メッシュ、スプライト パーティクル、メッシュ パーティクルで機能します。 - 現在、**Instanced Stereo** は PC (DirectX) と PS4 で機能します。それ以外のプラットフォームのサポートは 4.11 初回リリースの後になります。 - 以下のビデオで、VR での Standard Stereo レンダリングと VR での Instanced Stereo レンダリングを紹介しています。 + この機能を有効にすると、ベース パスと Early-Z パス (両方ともシリアルおよび並列レンダリング パス) がスタティック メッシュ、スケルタル メッシュ、スプライト パーティクル、メッシュ パーティクルで使用できます。 + 現在、**Instanced Stereo** は PC (DirectX) と PS4 で使用できます。それ以外のプラットフォームのサポートは 4.11 初回リリースの後になります。 + VR における Standard Stereo レンダリングおよび Instanced Stereo レンダリングを以下の動画で紹介しています。 [OBJECT:EmbeddedVideo] [PARAMLITERAL:width] @@ -117,37 +76,38 @@ UE 4.11 のリリースでは、VR のパフォーマンスに対する影響を ### モバイルで VR マルチビューをサポート -(サポート対象の) モバイル デバイスのいくつかで、VR マルチウィンドウがサポートされました。モバイル マルチビューはデスクトップ PC で使用できる Instanced Stereo レンダリングと似ており、ステレオ レンダリング用に最適化したパスをモバイル デバイスの CPU 上に提供して機能します。この機能を有効にするには、以下の手順を行います。 +(サポート対象の) モバイル デバイスのいくつかで VR マルチウィンドウがサポートされました。モバイル マルチビューはデスクトップ PC で使用できる Instanced Stereo レンダリングと似ており、ステレオ レンダリング用に最適化したパスをモバイル デバイスの CPU 上に提供して機能します。この機能を有効にするには、以下の手順を行います。 [region:warning] -この機能は実験的なので、最新のメール ベースの GPU でのみ動作します。整備が整い、オンラインでより多くのモバイルをサポートするようになると、この警告は出なくなります。 +この機能は実験的なので、最新のメール ベースの GPU でのみ動作します。機能が成熟し、オンラインでより多くのモバイルをサポートするようになると、この警告は出なくなります。 [/region] -1. メイン ツールバー から **[Edit (編集)]** > **[Project Settings (プロジェクト設定)] を選んで、エディタのプロジェクト設定を開きます。 +1. メイン ツールバー から **[Edit (編集)]** > **[Project Settings (プロジェクト設定)]** を選んで、エディタのプロジェクト設定を開きます。 1. 次に、**[Engine]** > **[Rendering]** > **[VR]** を開き、**[Mobile Multi-View (実験的)]** オプションを探します。 -1. [Mobile Multi-View (実験的)] オプションは、名前の横のチェックボックスにチェックを入れると有効になるので、その後で再起動して変更を反映させます。 +1. [Mobile Multi-View (実験的)] オプションは、名前の横のチェックボックスにチェックを入れて有効にしたら、変更を反映させるために再起動します。 ![](VR_MobileMultiView.png) この機能を使うためには、Android のビルド設定を以下のようにする必要があります。 -* **[Android]** > **[Build]** セクションで **[Support OpenGL ES2]** が有効になっていることを 確認してください。 +* **[Android]** > **[Build]** セクションの **[Support OpenGL ES2]** が有効になっていることを確認してください。 * **[Mobile HDR]** と **[Instanced Stereo Rendering]** が無効になっているか確認してください。 * 現時点では、Mobile Multiview は最新のメール ベースの GPU でのみ動作します。 -* 互換性のある GPU を搭載せずに本機能でプロジェクトをパッケージ化した場合、ランタイムに無効になります。 +* 互換性のある GPU を搭載せずに本機能でプロジェクトをパッケージ化した場合、この機能はランタイムで無効になります。 ## VR パフォーマンスのプロファイル -VR には負荷が大きすぎるアセットを追跡するには、プロジェクトのライフタイムを通じて可能な限り、CPU と GPU 上でプロジェクトが何をしているのかをプロファイルする必要があります。 +VR への負荷が大きすぎるアセットを追跡するには、プロジェクトのライフタイム中ずっと CPU と GPU へのプロジェクトの負荷要因をプロファイルする必要があります。 + +* **GPU Profiling** - プロジェクト実行中に **CTRL + SHIFT + , (カンマ キー)** を一緒に押すと、GPU プロファイラが有効になります。キーを押すと新規ウィンドウが開き、以下の画像のようになります。 -* **GPU Profiling** - プロジェクトの実行中に **CTRL + SHIFT + , (カンマ キー)** を一緒に押すと、GPU プロファイラを有効にすることができます。キーを押すと、新規ウィンドウが開いて以下の画像のようになります。 ![](VR_GPU_Profiler.png) -* **CPU Profiler** - CPU 上のプロジェクトの動作分析は、GPU のプロファイルよりも若干複雑になります。この方法についての詳細については、[パフォーマンス プロファイラ](https://docs.unrealengine.com/latest/INT/Engine/Performance/Profiler/index.html) をご覧ください。 +* **CPU Profiler** - CPU 上のプロジェクトの負荷分析は、GPU のプロファイルよりも若干複雑になります。この方法についての詳細については、[パフォーマンス プロファイラ](https://docs.unrealengine.com/latest/INT/Engine/Performance/Profiler/index.html) をご覧ください。 -## VR 前方レンダリング +## VR フォワード レンダリング ![](Engine\Performance\ForwardRenderer\ForwardRenderingBanner.png)(w:840) @@ -159,28 +119,28 @@ VR には負荷が大きすぎるアセットを追跡するには、プロジ ## VR ポストプロセス設定 -VR のレンダリング要件は厳しいので、デフォルトで有効設定にされているほとんどの高度なポスト プロセス機能は無効にしておかないと、 - プロジェクトのパフォーマンスに問題が生じる可能性があります。プロジェクトで無効にするには、以下の手順に従います。 +VR のレンダリング要件は厳しいので、デフォルトで有効設定にされている高度なポスト プロセス機能のほとんどを無効にしておかないと、 + プロジェクトのパフォーマンスに問題が生じる可能性があります。無効にするには、以下の手順に従います。 1. Post Process(PP) ボリュームがレベルにない場合は、レベルに追加します。 1. PP ボリュームを選択し、**[Post Process Volume]** セクションで **[Unbound (境界なし)]** オプションを有効にして、PP ボリュームの設定がレベル全体に適用されるようにします。 ![](VR_PP_Unbound.png) - 1. **[Post Process Volume]** の **[Settings (設定)]** を展開して、各セクションをクリックしてプロパティを有効にして、デフォルト値に値を設定します。デフォルト値 (通常 1.0) を **0** にすれば、この機能は無効になります。 + 1. **[Post Process Volume]** の **[Settings (設定)]** を展開し、各セクションをクリックしてプロパティを有効にしてデフォルト値を設定します。デフォルト値 (通常 1.0) を **0** にすれば、この機能は無効になります。 ![](VR_Disable_PP_Settings.png) [region:note] - この操作をする場合、セクションすべてを開いてプロパティを 0 にする必要はありません。その変わりに、レンズフレア、スクリーン スペース反射、テンポラル アンチエイリアシング、SSAO、ブルームなどの非常に重たい機能や、パフォーマンスに影響を与える機能を最初に無効にします。 + ただし、この場合、すべてのセクションのプロパティを 0 にする必要はありません。まず最初に、レンズフレア、スクリーン スペース反射、テンポラル アンチエイリアシング、SSAO、ブルームなどの非常に負荷の高い機能、またはパフォーマンスに影響を与える機能を無効にします。 [/region] ## VR ワールドのスケーリング VR プラットフォームで可能な限り最高のユーザー体験を提供するためには、 -ワールドのスケーリングは必ず正確に行うことが最も重要です。正確なスケーリングを怠ると、ユーザーに感覚的な様々な問題を感じさせ、 +ワールドのスケーリングを正確に行うことが最も重要です。正確なスケーリングを怠ると、ユーザーに様々な感覚的な違和感を与え、 シミュレーション酔いをさせてしまう可能性もあります。オブジェクトは、プレイヤーのカメラから **0.75 から 3.5 メートル (m)** の範囲が一番見やすくなります。 UE4 内では、**1 アンリアル ユニット (UU) は 1 センチ (cm) と等しくなっています**。つまり、アンリアル内にあるオブジェクトは、 -プレイヤーのカメラ (VR 使用時) から **75 UU から 350 UU** 離れた位置にある時が最も見やすいということです。 +プレイヤーのカメラ (VR 使用時) から **75 UU から 350 UU** が最も見やすい距離ということです。 | 距離 | アンリアル ユニット(UU) での距離 | | --- | --- | @@ -190,8 +150,8 @@ UE4 内では、**1 アンリアル ユニット (UU) は 1 センチ (cm) と UE4 内の **[World Settings (ワールド設定)]** にある **World to Meters** 変数でワールドのスケールを調整することができます。 この数字を増減すると、周りのワールドとの関係でユーザーは自分が大きく、あるいは小さく感じます。 -仮にコンテンツが 1 アンリアル ユニット = 1 CM でビルドされている場合、**[World To Meters]** を **「10」** に設定するとワールドが非常に大きくなります。 -逆に **World To Meters** を **1000** に設定すると、ワールドは非常に小さくなります。 +仮にコンテンツが 1 アンリアル ユニット = 1 CM でビルドされている場合、**[World To Meters]** を **[10]** に設定するとワールドが非常に大きくなります。 +逆に **[World To Meters]** を **[1000]** に設定すると、ワールドは非常に小さくなります。 ![](T_VR_World_To_Meters_00.png) @@ -202,8 +162,8 @@ UE4 内の **[World Settings (ワールド設定)]** にある **World to Meters 以下のベストプラクティスを **遵守** してください。でないと、 ユーザーに非常に不快な VR 体験をさせてしまう可能性があります。 -* HMD のネイティブ フレームレートを常に上回るようにするために、フレームレート、そして欲を言えばバッファを少し維持しなければなりません。 -フレームレートが低くてもシミュレーション酔いの原因になってしまうため、出来る限りゲームを最適化してください。 +* HMD のネイティブ フレームレートを常に上回るようにするために、フレームレート、そして欲を言えばバッファの維持は必要です。 +低いフレームレートもシミュレーション酔いの別の要因になるため、出来る限りゲームを最適化してください。 以下の表は、各種 HMD の UE4 のサポートとこれらのデバイス上での実行に VR プロジェクトが必要とするターゲット フレーム レートです。 | HMD デバイス | ターゲット フレーム レート | | --- | --- | @@ -214,40 +174,40 @@ UE4 内の **[World Settings (ワールド設定)]** にある **World to Meters | Gear VR | 60 FPS| | PSVR | 最高 120 FPS まで変動| -* 開発者は VR デバイスの使用に慣れすぎているため、テスト対象者には最も不適切です。シミュレーション酔いの発生を防ぐためにも、テスト対象者はできるだけ幅広いタイプから選んでゲームをチェックしてください。 +* 開発者は VR デバイスの使用に慣れているため、テスト対象者としては最も不適切です。シミュレーション酔いの発生を防ぐためにも、テスト対象者はできるだけ幅広いタイプから選んでゲームをチェックしてください。 * シネマティクス カメラ、あるいはプレイヤーがカメラ移動を制御できなくするカメラは、ユーザーが最悪の VR 体験をする元凶になりやすいため、使用は避けてください。 * 視野角 (FOV) を手動でオーバーライトしないでください。また、エンド ユーザーに編集目的で視野角を公開しないでください。値はヘッドセットとレンズの物理ジオメトリと一致していなければなりません。これはデバイスの SDK と内部コンフィギュレーションにより自動的に設定されます。不整合があれば、頭を回転させたときにワールドが歪んでいるように見えて、不快感や吐き気につながります。 * カメラ効果に "Walking Bob" を使用しないでください (ファーストパーソンゲームでよくあります)。人の動きを真似するためにカメラを上下すると、プレイヤーにシミュレーション酔いを起させて、VR 体験を台無しにしてしまいます。 -* イベントをプレイヤーに伝えようとするときにカメラを揺らさないでください。手榴弾がプレイヤーの横で爆発した時、VR 以外のゲームではカメラが揺れるのは自然に思いますが、VR ゲームの場合はすぐにシミュレーション酔いを起こします。 -* VR ゲーム用にワールドとレベルを設計している場合、通常よりも暗いライトとカラーを使用するようにしてください。VR ゲームで強く鮮やかなライティングを使用すると、シミュレーション酔いが速く起こってしまう可能性があります。通常よりも落ち着いた描画や暗いライトを使用することで、こうした状況を回避します。 +* イベントをプレイヤーに伝えようとする時に、カメラを揺らさないでください。手榴弾がプレイヤーの横で爆発した時、VR 以外のゲームではカメラが揺れるのは自然に思いますが、VR ゲームの場合はすぐにシミュレーション酔いを起こします。 +* VR ゲーム用にワールドとレベルを設計している場合、通常よりも暗いライトとカラーを使用するようにしてください。VR ゲームで強く鮮やかなライティングを使用すると、シミュレーション酔いが速く起こる可能性があります。通常よりも落ち着いた描画や暗いライトを使用することで、こうした状況を回避します。 * 階段は避けて代わりにエレベーターを使ってください。プレイヤーが素早く移動すると、特に階段の上り下りの場合、方向感覚を失いやすくなります。 * プレイヤーは、徐々にフルスピードにするのではなく、一気にフルスピードにします。さらに、移動速度への加速は常に一定でなくてはなりません。 * 被写界深度あるいはモーション ブラー ポストプロセスは使用しないでください。ユーザーが見ているものへの影響が大きく、さらに重要なのは、ユーザーにシミュレーション酔いをさせてしまうからです。 -これはシミュレーション酔いの根本的原因の徹底調査結果ではありませんが、VR ゲームのプレイ中にプレイヤーの具合が悪くなる原因についての良いヒントになるはずです。 +これらは、シミュレーション酔いの根本的原因の徹底調査結果ではありませんが、VR ゲームのプレイ中にプレイヤーの具合を悪くする原因のヒンとして役立つはずです。 ## VR カメラの設定 -UE4 で VR カメラを設定する場合、VR 体験を立って行うか、座って行うかによって全く異なります。 -座って行う体験の場合、カメラの基点をキャラクターが立っている状態まで人為的に高くする必要があります。 -ただしこの場合、カメラの原点が 0 (グラウンド上) になるようにしてください。 +VR 体験を立って行う場合と座って行う場合では、UE4 での VR カメラ設定がまったく異なります。 +体験を座って行う場合、カメラの基点をキャラクターが立っている状態まで人為的に高くする必要があります。 +この場合、カメラの原点が 0 (グラウンド上) になるようにしてください。 そのためには、キャラクターのベースでカメラ コンポーネントをシーン コンポーネントにアタッチするか、 Eye Height (目の位置) をキャラクター上のコリジョン カプセルの (マイナスの) Cylinder Height (シリンダーの高さ) の半分に設定します。 ## VR キャラクター設定 VR ヘッドセットを使用したキャラクターのセットアップは、標準のキャラクターのセットアップとは若干異なります。例えば、キャラクターの -高さ、幅、速度、カメラ位置、これらはすべて VR キャラクターに合わせて若干の修正が必要となります。 +高さ、幅、速度、カメラ位置を VR キャラクターに合わせて若干修正する必要があります。 [REGION:tip] VR ワールドからオブジェクトをビルドする場合、 - デジタル オブジェクトのスケールを現実世界のオブジェクトと同じにすることが重要です。現実世界にある時のサイズより大きくしたり小さくすると、 - 達成できるはずの没入感を台無しにしてしまうことがあります。 + デジタル オブジェクトのスケールを現実世界のオブジェクトと同じにすることが重要です。スケールが現実世界より大きくても小さくても、 + 目標としている没入感を台無しにしてしまうことがあります。 [/REGION] **キャラクターの高さと幅** -キャラクターの高さと幅は、可能な限り現実世界の寸法と同じにします。サイズは大きすぎても小さすぎても -実現しようとしている没入感を台無しにしてしまう可能性があります。 +キャラクターの高さと幅は、現実世界のサイズと同じにします。スケールが現実世界より大きくても小さくても、 +目標としている没入感を台無しにしてしまうことがあります。 |プロパティ| UE4 デフォルト | 推奨 VR | |---| --- | --- | @@ -256,8 +216,8 @@ VR ヘッドセットを使用したキャラクターのセットアップは **移動速度** -VR の移動速度は設定の推奨が難しいです。 -なぜなら、達成しようとする体験のタイプによって異なるからです。例えば、Elemental VR デモでは、 +VR の移動速度は、目標とする体験のタイプによって異なるため、 +推奨することが難しいです。例えば、Elemental VR デモでは、 移動速度を通常の約 1/4 にしています。 |プロパティ| UE4 デフォルト | 推奨 VR | @@ -266,11 +226,11 @@ Movement Speed:|60 m/s|24 m/s| **カメラ位置** -VR カメラは基本的な目の高さよりも若干低めに配置して、キャラクターの目の高さになるように補正する必要があります。 +VR カメラは、基本的な目の高さよりも若干低めに配置して、キャラクターの目の高さになるように補正する必要があります。 |プロパティ| UE4 デフォルト | 推奨 VR | |---| --- | --- | -Base Eye Height:|180 cm|160 cm| +基本的な目の高さ:|180 cm|160 cm| @@ -279,35 +239,35 @@ Base Eye Height:|180 cm|160 cm| VR コンテンツを制作する場合には、ユーザーは複数の角度からコンテンツを見ていることを忘れないでください。今まで問題なく行ったことであっても、 VR の場合は以下のように回避すべきことがあります。 -* **Scale** - VR ワールドのオブジェクトをスケールする場合は、実寸をできるだけ真似るのが最善の方法です。 -現実世界よりもオブジェクトを大きくしたり、小さくしたりすると、混乱を招き、シミュレーション酔いにつながることがあります。 +* **Scale** - VR ワールドのオブジェクトをスケールする場合は、できるだけ実際のサイズを使うのが最善の方法です。 +オブジェクトのサイズが現実世界と異なると混乱を招き、シミュレーション酔いにつながることがあります。 -* **Missing Polygon Faces** - 標準的なゲームでは、ポリゴン面をプレイヤーには見えないオブジェクトから削除することができます (そうした方がよいです)。 -しかし、VR ゲームではプレイヤーは周囲を見渡す自由度が高くなっており、この方法ではプレイヤーは見えないはずのものが見えてしまう結果になる場合があります。 +* **Missing Polygon Faces** - 標準的なゲームでは、ポリゴン面をプレイヤーには見えないオブジェクトから削除することができます (推奨します)。 +しかし、VR ゲームではプレイヤーは周囲をかなり自由に見渡すことができるため、この方法だとプレイヤーは見えないはずのものが見えてしまう場合があります。 * ** Which Type of Lighting to use** - VR プロジェクトの作成には、レンダリング負荷が最も低い **Static lighting (静的ライト)** と **ライトマップ** を常に使います。 動的ライティングを使う必要がある場合は、動的ライト数を可能な限り少なくして、お互いに触れ合うことのないようにしてください。 -屋外のシーンがある場合は、指向性ライトを Stationary light (固定ライト) ではなく動的に設定して、Cascaded Shadow Maps(CSM); を有効にしておくと、最もシンプルな設定でシャドウを付けることができます。 +屋外のシーンがある場合は、指向性ライトを固定ではなく動的に設定して、[Cascaded Shadow Maps(CSM)] を有効にしておくと、最もシンプルな設定でシャドウを付けることができます。 * ** VR と VFX** - [SubUV テクスチャ](https://docs.unrealengine.com/latest/INT/Engine/Rendering/ParticleSystems/Reference/Modules/SubUV/index.html) による炎や煙のシミュレーションなどのトリックは、VR ではうまく反映されません。 ほとんどのケースにおいて、爆発や煙のトレイルなどの VFX のシミュレーションには 2D パーティクルではなくスタティック メッシュを使います。 近距離フィールド エフェクトあるいはカメラに近いエフェクトは VR できれいに出ますが、これはエフェクトがスタティック メッシュ パーティクルで作成されている場合に限ります。 -* **VR と Transparency** - 透過処理は一般的に、何も変更がないことを確認するために各フレームを再評価する必要があるため、3D グラフィクスでのレンダリング透過処理は非常に負荷が高くなります。 -この再評価のために、VR のレンダリング透過処理は負荷があまりに大きすぎて、本来の長所を潰してしまいます。 +* **VR と Transparency** - 一般的に透過処理は、何も変更がないことを確認するために各フレームを再評価する必要があるため、3D グラフィクスでのレンダリング透過処理は非常に負荷が高くなります。 +この再評価のために、VR のレンダリング透過処理は負荷があまりに大きすぎて、本来の良さが生かせなくなります。 ただし、**DitherTemporalAA** マテリアル関数を使えばこの問題を回避することができます。 このマテリアル関数は、マテリアルが透過処理を使っているかのように見せることができますし、セルフ ソートなど一般的な透過処理の回避も可能です。 ![](VR_Dither_Trans_AA.png) -* **Fake everything you can (できる限り真似をする)** - 動的シャドウ、ライティングなど、負荷の大きいレンダリング オプションを再生成する小技を頭に入れておくと、VR で望みのパフォーマンスを達成しやすくなります。 -Showdown では、キャラクターに動的シャドウをキャストさせると各フレームの負荷が大きすぎることが判明したので割愛しました。 +* **Fake everything you can (できる限り真似をする)** - 動的シャドウ、ライティングなど、負荷の大きいレンダリング オプションを再生成する小技を頭に入れておくと、VR で希望するパフォーマンスが得やすくなります。 +Showdown では、キャラクターに動的シャドウをキャストすると各フレームの負荷が大きすぎることが判明したので割愛しました。 すると今度は、キャラクターが移動中に宙に浮いているように見えてしまいました。 そこで、偽の BLOB シャドウを導入して修正すると、位置と強度を大幅に調整することができました。 これにより、キャラクターがグラウンドや他のオブジェクトに近づくと、シャドウをキャストしているように簡単に見せることができるようになりました。 [region:lightbox] - [![](VR_Fake_Shadow_Material.png)](VR_Fake_Shadow_Material.png) + [![](VR_Fake_Shadow_Material.png)(w:1000)](VR_Fake_Shadow_Material.png) [/region] [region:caption] @@ -331,7 +291,7 @@ Get Positional Tracking Camera Parameters|HMD にポジション トラッキン Get Screen Percentage|VR モードで使用する画面比率を返します。| Get World to Meters Scale|ワールドをマスター スケールに戻すことで、プレイヤーが感じるワールドのスケールに一致させます。| Has Valid Tracking Position| HMD がポジション トラッキングをサポートする場合、現在トラッキングされているかどうかを示します。| -Is Head Mounted Display Enabled|ヘッドマウント ディスプレイを現在使用しているかどうかを返します。| +Is Head Mounted Display Enabled|ヘッドマウント ディスプレイを使用中かどうかを返します。| Is In Low Persistence Mode | HMD が、Low persistence モードの場合、_true_ を戻します。そうでない場合は、_false_ を戻します。| Reset Orientation And Position| 現在のヨーが前方方向で、現在のポジションがゼロポイント (ポジション トラッキング用) であると想定して、ロール (進行軸回転) とピッチ (上下動) を 0 に設定します。| Set Clipping Planes| 遠近のクリッピング平面 (NCP と FCP それぞれ) のステレオ レンダリングを設定します。'stereo ncp = fcp' コンソール コマンドと似ていますが、このコマンドで設定した NCP and FCP は .INI ファイルには保存されません。| @@ -353,20 +313,17 @@ Set World to Meters Scale| ワールドをマスター スケールに設定す HMD 機能が原因で、ビデオ ゲーム開発には必須だったアート技術にあった影響がなくなってしまいました。 以下は、VR では期待どおりに動かない機能、およびそれに対する回避策です。 -|既知の問題| 回避策 | -|---| --- | -| Screen Space Reflections(SSR) (スクリーン スペース反射)|SSR は VR で機能しますが、生成される反射をワールド内の反射と一致させる上で問題が発生する可能性があります。負荷がかなり小さく、反射アライメントの問題も減るため、SSR ではなく [反射プローブ](Resources/Showcases/Reflections#反射背景) を使います。| + +* **スクリーン スペース反射 (SSR):** SSR は VR で機能しますが、生成される反射をワールド内の反射と一致させる上で問題が発生する可能性があります。負荷がかなり小さく、反射アライメントの問題も減るため、SSR ではなく [反射プローブ](Resources/Showcases/Reflections#反射背景) を使います。 **法線マッピングの問題** VR でオブジェクト上の法線マップを見ると、これまでのような効果がなくなっていることがわかります。 法線マップが両眼表示や運動視差を考慮していないためです。 -このため、法線マップは VR デバイスを通してみるとフラットに見えます。 +このため、法線マップは VR デバイスではフラットに見えます。 ただしこれは、法線マップを使用する必要がないという意味ではありません。 法線マップにしようとしているデータをジオメトリで作成すべきかどうかを、しっかり評価する必要があるという意味です。 以下は、法線マップの代わりに使用することができる技術です。 -|形状タイプ|説明| -|---|---| -|[視差マッピング](http://en.wikipedia.org/wiki/Parallax_mapping)| 視差マッピングは、法線マッピングでは考慮しないデプスキューを考慮することで法線マッピングを次のレベルに高めます。視差マッピング シェーダーは、オブジェクトを実際よりも詳細に表示して、深さ情報を詳しく表示できます。これは、どのアングルから見ても、その視点からの正確な深度情報を表示するように視差マップが常に補正しているからです。視差マップは、敷石道や表面の細部などの使用に最適です。 +* **[視差マッピング](http://en.wikipedia.org/wiki/Parallax_mapping):** 視差マッピングは、法線マッピングでは考慮しないデプスキューを考慮することで法線マッピングを次のレベルに高めます。視差マッピング シェーダーは、オブジェクトを実際よりも詳細に表示して、深さ情報を詳しく表示できます。これは、どのアングルから見ても、その視点からの正確な深度情報が表示されるように視差マップが常に補正しているからです。視差マップは、敷石道や表面の細部の表現に最適です。 diff --git a/Engine/Documentation/Source/Platforms/VR/ContentSetup/VRContent.KOR.udn b/Engine/Documentation/Source/Platforms/VR/ContentSetup/VRContent.KOR.udn index 8779eb66aa4f..60798ed58676 100644 --- a/Engine/Documentation/Source/Platforms/VR/ContentSetup/VRContent.KOR.udn +++ b/Engine/Documentation/Source/Platforms/VR/ContentSetup/VRContent.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3322543 +INTSourceChangelist:3429260 Availability:Public Title:가상 현실 실전 사례 Crumbs: @@ -9,44 +9,6 @@ parent:Platforms/VR type:overview tags:VR -[VAR:Params] -[PARAM:image] - ![%Platforms:title%](%ROOT%/placeholder_topic.png) -[/PARAM] -[PARAM:icon] - ![](%ROOT%/platform_icon.png)(convert:false) -[/PARAM] -[PARAM:title] - %Platforms:title% -[/PARAM] -[PARAM:description] - %Platforms:description% -[/PARAM] -[PARAM:path] - [RELATIVE:Platforms] -[/PARAM] -[/VAR] - -[VAR:Topic] -[OBJECT:Topic] -%params% -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] -%params% -[/OBJECT] -[/VAR] - -[VAR:Role] -[OBJECT:Role] -%params% -[PARAMLITERAL:id] -platforms -[/PARAMLITERAL] -[/OBJECT] -[/VAR] [TOC(start:2)] @@ -66,7 +28,6 @@ VR 프로젝트를 새로 만들 때, 프로젝트가 블루프린트 기반이 이러한 .INI 세팅을 사용하려는 경우, **Config\ DefaultEngine.INI** 파일의 **SystemSettings** 아래 추가해 줘야 합니다. [SystemSettings] - r.VolumeMultiplier=1.0 r.screenpercentage=130 r.SeparateTranslucency=0 r.HZBOcclusion=0 @@ -78,7 +39,6 @@ VR 프로젝트를 새로 만들 때, 프로젝트가 블루프린트 기반이 r.SSR.Quality=1 r.DepthOfFieldQuality=0 r.SceneColorFormat=2 - r.SSSSS=0 r.TranslucencyVolumeBlur=0 r.TranslucencyLightingVolumeDim=4 r.MaxAnisotropy=8 @@ -87,7 +47,6 @@ VR 프로젝트를 새로 만들 때, 프로젝트가 블루프린트 기반이 r.FastBlurThreshold=0 r.SSR.MaxRoughness=0.1 r.rhicmdbypass=0 - r.TiledReflectionEnvironmentMinimumCount=10 sg.EffectsQuality=2 sg.PostProcessQuality=0 @@ -99,7 +58,7 @@ UE 4.11 릴리즈에는 UE4 에서의 VR 퍼포먼스 저하를 개선시키는 ![](VR_ISR.png) 인스턴스드 스테레오 렌더링을 켠 이후에는 엔진 재시작과 셰이더 리컴파일이 필요할 것입니다. - 베이스 패스와 얼리-z 패스는 (직렬 및 병렬 렌더링 패쓰 양쪽에서) 이 기능이 켜진 스태틱 메시, 스켈레탈 메시, 스프라이트 파티클, 메시 파티클과 함께 작동합니다. + 베이스 패스와 얼리-z 패스(pass)는 (직렬 및 병렬 렌더링 패스 양쪽에서) 이 기능이 켜진 스태틱 메시, 스켈레탈 메시, 스프라이트 파티클, 메시 파티클과 함께 작동합니다. 인스턴스드 스테레오는 현재 PC (DirectX) 와 PS4 에서 작동하며, 다른 플랫폼은 초기 4.11 릴리즈 이후 지원될 것입니다. VR 렌더링을 스탠다드 스테레오로 할 때와 인스턴스드 스테레오로 할 때를 보여주는 비디오입니다. @@ -307,7 +266,7 @@ Showdown 에서 캐릭터가 다이내믹 섀도를 드리우게 했더니 매 이런 식으로 캐릭터가 바닥이나 다른 오브젝트 가까이 갈 때 그림자를 드리우는 것과 같은 효과를 내는 데 도움이 되었습니다. [region:lightbox] - [![](VR_Fake_Shadow_Material.png)](VR_Fake_Shadow_Material.png) + [![](VR_Fake_Shadow_Material.png)(w:1000)](VR_Fake_Shadow_Material.png) [/region] [region:caption] @@ -353,9 +312,7 @@ Set World to Meters Scale| 월드대 미터 스케일 설정 - 월드대 미터 HMD 작동 방식으로 인하여 기존 비디오 게임 개발에 자주 쓰이던 아트 기법 몇 가지는 더이상 전과 같은 효과를 내지 못하게 되었습니다. 여기서는 VR 에서 예상대로 작동하지 않는 기능과, 그에 대한 우회법을 살펴봅니다. -|알려진 문제점| 우회법 | -|---| --- | -| Screen Space Reflections(SSR)| 스크린 스페이스 리플렉션 - SSR 이 VR 에서 작동은 합니다만, 거기서 만들어지는 반사면이 월드의 실제 내용과 일치하지 않는 문제가 있을 수 있습니다. SSR 대신 [리플렉션 프로브](Resources/Showcases/Reflections) 를 사용하면, 비용도 절감되고 리플렉션 일치 문제도 덜합니다.| +* **Screen Space Reflections(SSR):** 스크린 스페이스 리플렉션 - SSR 이 VR 에서 작동은 합니다만, 거기서 만들어지는 반사면이 월드의 실제 내용과 일치하지 않는 문제가 있을 수 있습니다. SSR 대신 [리플렉션 프로브](Resources/Showcases/Reflections) 를 사용하면, 비용도 절감되고 리플렉션 일치 문제도 덜합니다. **노멀 매핑 문제** @@ -366,7 +323,5 @@ VR 에서 오브젝트의 노멀 맵을 볼 때, 그 임팩트가 예전만 못 데이터를 면밀히 조사하여 노멀 맵으로 내고자 했던 효과를 그냥 지오메트리에 만들어 버리는 것이 낫지 않을지 판단을 해야 한다는 것입니다. 노멀 맵 대신 사용할 수 있는 기법 몇 가지는 다음과 같습니다. -|셰이더 유형 | 설명 | -|---|---| -|[패럴랙스 매핑](http://en.wikipedia.org/wiki/Parallax_mapping)| 패럴랙스 매핑은 노멀 매핑이 고려하지 않는 뎁스 큐를 고려하여 한 단계 발전된 것입니다. 패럴랙스 매핑 셰이더는 오브젝트의 디테일을 원래보다 살려 주어 깊이 정보를 더욱 잘 표시해 줍니다. 그 이유는 어느 각도에서 보든, 패럴랙스 맵은 그 시점에서 올바른 깊이 정보를 표시하는 데 그 자체적으로는 항상 맞기 때문입니다. 패럴랙스 맵을 사용하기 가장 좋은 곳은, 자갈밭 길이나 디테일이 세밀한 표면입니다. +* **[패럴랙스 매핑](http://en.wikipedia.org/wiki/Parallax_mapping):** 패럴랙스 매핑은 노멀 매핑이 고려하지 않는 뎁스 큐를 고려하여 한 단계 발전된 것입니다. 패럴랙스 매핑 셰이더는 오브젝트의 디테일을 원래보다 살려 주어 깊이 정보를 더욱 잘 표시해 줍니다. 그 이유는 어느 각도에서 보든, 패럴랙스 맵은 그 시점에서 올바른 깊이 정보를 표시하는 데 그 자체적으로는 항상 맞기 때문입니다. 패럴랙스 맵을 사용하기 가장 좋은 곳은, 자갈밭 길이나 디테일이 세밀한 표면입니다. diff --git a/Engine/Documentation/Source/Platforms/VR/MotionController/MotionControllerComponent.INT.udn b/Engine/Documentation/Source/Platforms/VR/MotionController/MotionControllerComponent.INT.udn index 1f53ed2b94fb..bb29f773e63c 100644 --- a/Engine/Documentation/Source/Platforms/VR/MotionController/MotionControllerComponent.INT.udn +++ b/Engine/Documentation/Source/Platforms/VR/MotionController/MotionControllerComponent.INT.udn @@ -1,7 +1,7 @@ Availability:Public Title:Motion Controller Component Setup Crumbs:%ROOT%, Platforms -Description:Information over how to setup Motion Controllers for VR interaction. +Description:Information on how to setup Motion Controllers for VR interaction. Navigation:platform Version:4.9 Skilllevel:Intermediate @@ -11,7 +11,7 @@ type:overview [TOC(start:2)] You can add a Motion Controller as a component to your Pawn / Character, set which "Hand" it is supposed to represent. -In the following document we will cover how you can set up your Virtual Reality project to make use of Motion Controllers. +In the following document, we will cover how you can set up your Virtual Reality project to make use of Motion Controllers. [region:tip] Before going any further make sure that your VR Headset and Motion Controllers are plugged into your PC and required the drivers installed. @@ -21,7 +21,7 @@ See the [VR Documents](Platforms/VR) for information on how to get various VR he ## Motion Controller Setup Setting up a VR project to make use of Motion Controllers requires adding a Motion Controller Component to your Pawn and configuring it. -In the this section we will cover how you can quickly get Motion Controllers working with your project. +In this section, we will cover how you can quickly get Motion Controllers working with your project. [region:note] Please note this setup can be applied to any Pawn in any UE4 project. @@ -29,60 +29,84 @@ Please note this setup can be applied to any Pawn in any UE4 project. 1. In the **Content Browser** open the **Player Pawn** Blueprint. - ![](Open_VR_Pawn.png) + [REGION:lightbox] + [![](Open_VR_Pawn.png)(w:427)](Open_VR_Pawn.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] 1. Once the Blueprint is opened, navigate to the **Viewport** tab and in the **Components** section click on the **Add Component** button to expose the components that can be added to this Blueprint. - ![](Find_Components.png) + [REGION:lightbox] + [![](Find_Components.png)(w:418)](Find_Components.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] 1. From the list that is shown search for the Motion Controller using the word **Motion** as the search term. - When the Motion Controller component has been located, click on it to add it to the components list. + When the Motion Controller component has been located, click on it to add it to the components list. - [OBJECT:EmbeddedVideo] - [PARAMLITERAL:width] - 640 - [/PARAMLITERAL] - [PARAMLITERAL:height] - 360 - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - kcyHnfpmWbU - [/PARAMLITERAL] - [/OBJECT] + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 640 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 360 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + kcyHnfpmWbU + [/PARAMLITERAL] + [/OBJECT] 1. Once the Motion Controller has been added, select it by clicking on it and then in the **Details** panel under the **Motion Controller** section make sure the **Hand** is set to **Left**. - ![](Setting_Up_Components.png) + [REGION:lightbox] + [![](Setting_Up_Components.png)(w:418)](Setting_Up_Components.png) + [/REGION] -1. To give the Motion Controller a visual representation in the world, select the **Motion Controller Component** in the **Components panel** and click the **Add Component** button to add a **Static Mesh Component**. - Drag the Static Mesh Component on to the Motion Controller to parent it to the Motion Controller Component then, - in the Details panel, assign a Static Mesh asset to the Static Mesh property of the new component. + [REGION:caption] + Click for full image. + [/REGION] - [OBJECT:EmbeddedVideo] - [PARAMLITERAL:width] - 640 - [/PARAMLITERAL] - [PARAMLITERAL:height] - 360 - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - x4vjDqnHQnk - [/PARAMLITERAL] - [/OBJECT] +1. To give the Motion Controller a visual representation in the world, select the **Motion Controller Component** in the **Components panel** and click the **Add Component** button to add a **Static Mesh Component**. + Drag the Static Mesh Component on to the Motion Controller to parent it to the Motion Controller Component then, + in the Details panel, assign a Static Mesh asset to the Static Mesh property of the new component. - [region:tip] - If your project does not currently have any Static Mesh assets, import one of your own meshes or click the Marketplace button in the toolbar to visit the Marketplace and download some assets to use in your project. - If the Static Mesh you selected is too big or too small you can scale to your likening using the Scale section of the Transform section in the Details panel. - [/region] + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 640 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 360 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + x4vjDqnHQnk + [/PARAMLITERAL] + [/OBJECT] -1. Add another Motion Controller Component parented to the root and set it to be the **Right Hand**. Add a Static Mesh Component parented to the new Motion Controller Component and apply the right hand mesh to it.. + [region:tip] + If your project does not currently have any Static Mesh assets, import one of your meshes or click the Marketplace button in the toolbar to visit the Marketplace and download some assets to use in your project. + If the Static Mesh you selected is too big or too small, you can scale to your likening using the Scale section of the Transform section in the Details panel. + [/region] - ![](Finshed_MC_Setup.png) +1. Add another Motion Controller Component parented to the root and set it to be the **Right Hand**. Add a Static Mesh Component parented to the new Motion Controller Component and applied the right-hand mesh to it. - [region:note] - In the image above, the the two cone shaped meshes have been moved apart to show that there are two of them. - When setting up your project leave both Static Mesh Components at 0,0,0 so that they are located right on top of one another. - [/region] + [REGION:lightbox] + [![](Finshed_MC_Setup.png)(w:418)](Finshed_MC_Setup.png) + [/REGION] + + [REGION:caption] + Click for full image. + [/REGION] + + [region:note] + In the image above, the two cone shaped meshes have been moved apart to show that there are two of them. + When setting up your project leave both Static Mesh Components at 0,0,0 so that they are located right on top of one another. + [/region] ## Working with Motion Controllers @@ -94,7 +118,7 @@ If you search inside of the Blueprint Editor **Palette** using **MotionControlle ![](Working_With_MC.png) -When looking at the available Motion Controller input options there is a capital **L** or **R** next to the name of what that value is supposed to control. +When looking at the available Motion Controller input options, there is a capital **L** or **R** next to the name of what that value is supposed to control. This L or R means that this is for the **Left** or **Right** Motion Controller. ![](MC_Left_Right.png) @@ -102,100 +126,117 @@ This L or R means that this is for the **Left** or **Right** Motion Controller. ## Using Motion Controllers -In the following section we will set the Motion Controllers up so that when you press the trigger button on the **Right-Handed** Motion Controller a Blueprint containing a Static Mesh is spawned into the world, while pressing the trigger button on the **Left-Handed** Motion Controller will remove the mesh from the world. +In the following section, we will set the Motion Controllers up so that when you press the trigger button on the **Right-Handed** Motion Controller, a Blueprint containing a Static Mesh is spawned into the world, while pressing the trigger button on the **Left-Handed** Motion Controller will remove the mesh from the world. -1. In the Content Browser create a new Blueprint named **BP_Sphere** and open it up by double-clicking on it. +1. In the Content Browser, create a new Blueprint named **BP_Sphere** and open it up by double-clicking on it. 1. Navigate to the **Viewport** tab and add a new **Static Mesh Component**. - ![](Add_SM_Component.png) + ![](Add_SM_Component.png) 1. Move the Static Mesh Component on top of the **Default Screen Root** and set the Static Mesh used to the **ArcadeEditorSphere** and compile and save your Blueprint. - [OBJECT:EmbeddedVideo] - [PARAMLITERAL:width] - 640 - [/PARAMLITERAL] - [PARAMLITERAL:height] - 360 - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - PszzV_I0xso - [/PARAMLITERAL] - [/OBJECT] + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 640 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 360 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + PszzV_I0xso + [/PARAMLITERAL] + [/OBJECT] - [region:note] - If you can not find the **ArcadeEditorSphere** make sure that you have the **Engine Content** folder enabled by going to **View Options** and then clicking on the **Engine Content** folder to enable it showing up in the Content Browser. - [/region] + [region:note] + If you can not find the **ArcadeEditorSphere** make sure that you have the **Engine Content** folder enabled by going to **View Options** and then clicking on the **Engine Content** folder to enable it showing up in the Content Browser. + [/region] 1. Close the BP_Sphere Blueprint and open up your **Pawn** Blueprint. 1. In the my Blueprint panel, navigate to the **Event Graph** tab and create a new **Actor** variable with the name **Objects** with its **Variable Type** to array. - - ![](Create_New_Var.png) + + ![](Create_New_Var.png) 1. This Blueprint is going to allow us to add and remove a specified object from the world when the trigger button on the Motion Controllers is pressed. To do this, inside of the Event Graph add and connect the following Blueprint nodes together. When completed you should have something that looks like the following image. - ![](Add_Objects_Setup.png) + [REGION:lightbox] + [![](Add_Objects_Setup.png)(w:459)](Add_Objects_Setup.png) + [/REGION] - [region:note] - The **Spawn Offset** was added to ensure that the objects could be seen while being placed in this example. The offset is not required and can be omitted by connecting the **Return Value** from the **GetActorTransform** node to the **Spawn Transform** input on the **SpawnActor** node. - ![](Add_Objects_Setup_Alt.png) - [/region] + [REGION:caption] + Click for full image. + [/REGION] + + [region:note] + The **Spawn Offset** was added to ensure that the objects could be seen while being placed in this example. The offset is not required and can be omitted by connecting the **Return Value** from the **GetActorTransform** node to the **Spawn Transform** input on the **SpawnActor** node. + [REGION:lightbox] + [![](Add_Objects_Setup_Alt.png)(w:367)](Add_Objects_Setup_Alt.png) + [/REGION] + [REGION:caption] + Click for full image. + [/REGION] + [/region] 1. Select the **Spawn Actor** node and assign the ** BP_Sphere** Blueprint that was created in step one to the Class input. - ![](Setting_SpawnActor_Up.png) + ![](Setting_SpawnActor_Up.png) -1. This section of the BLueprint will allow us to remove the objects that were placed in the world. To add this functionality, add and connect the following Blueprint nodes together. When completed you should have something that looks like the following image. +1. This section of the Blueprint will allow us to remove the objects that were placed in the world. To add this functionality, add and connect the following Blueprint nodes together. When completed you should have something that looks like the following image. - ![](Remove_Objects_Setup.png) + [REGION:lightbox] + [![](Remove_Objects_Setup.png)(w:459)](Remove_Objects_Setup.png) + [/REGION] - [region:note] - The keyboard input keys were placed in the graph for quick testing. You do not have to include those inputs for this to work with Motion Controllers. - [/region] + [REGION:caption] + Click for full image. + [/REGION] + + [region:note] + The keyboard input keys were placed in the graph for quick testing. You do not have to include those inputs for this to work with Motion Controllers. + [/region] 1. **Compile** and **Save** the changes to your Pawn Blueprint and then press the **Play** button. - Once the level has started, try adding objects to the world by pressing the **K** key on the keyboard or by pressing the Right trigger on the Right Handed Motion Controller. - To remove objects from the world, press the **T** key on the keyboard or press the **Left** trigger on the Left Handed Motion Controller which you can see demonstrated in the video below. + Once the level has started, try adding objects to the world by pressing the **K** key on the keyboard or by pressing the Right Trigger on the Right Handed Motion Controller. + To remove objects from the world, press the **T** key on the keyboard or press the **Left** trigger on the Left Handed Motion Controller which you can see demonstrated in the video below. - [OBJECT:EmbeddedVideo] - [PARAMLITERAL:width] - 640 - [/PARAMLITERAL] - [PARAMLITERAL:height] - 360 - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - VXUowSUKT9I - [/PARAMLITERAL] - [/OBJECT] + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 640 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 360 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + VXUowSUKT9I + [/PARAMLITERAL] + [/OBJECT] ## Training Streams [REGION:topics third] [OBJECT:TopicCompactVideo] - [PARAMLITERAL:title] - Setting Up Motion Controllers - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - 6ALnsdQnkVQ - [/PARAMLITERAL] + [PARAMLITERAL:title] + Setting Up Motion Controllers + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + 6ALnsdQnkVQ + [/PARAMLITERAL] [/OBJECT] [OBJECT:TopicCompactVideo] - [PARAMLITERAL:title] - Creating Interactions in VR With Motion Controllers Part 1 - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - eRNtgFo6iU0 - [/PARAMLITERAL] + [PARAMLITERAL:title] + Creating Interactions in VR With Motion Controllers Part 1 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + eRNtgFo6iU0 + [/PARAMLITERAL] [/OBJECT] [OBJECT:TopicCompactVideo] - [PARAMLITERAL:title] - Creating Interactions in VR With Motion Controllers Part 2 - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - utOahIZgKgc - [/PARAMLITERAL] + [PARAMLITERAL:title] + Creating Interactions in VR With Motion Controllers Part 2 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + utOahIZgKgc + [/PARAMLITERAL] [/OBJECT] [/REGION] diff --git a/Engine/Documentation/Source/Platforms/VR/MotionController/MotionControllerComponent.JPN.udn b/Engine/Documentation/Source/Platforms/VR/MotionController/MotionControllerComponent.JPN.udn index 7623e317f45e..596b2cbdd6ca 100644 --- a/Engine/Documentation/Source/Platforms/VR/MotionController/MotionControllerComponent.JPN.udn +++ b/Engine/Documentation/Source/Platforms/VR/MotionController/MotionControllerComponent.JPN.udn @@ -1,200 +1,243 @@ -INTSourceChangelist:2940199 +INTSourceChangelist:3456880 Availability:Public -Title:Motion Controller Component の設定 +Title:モーション コントローラー コンポーネントの設定 Crumbs:%ROOT%, Platforms Description:VR インタラクション用モーション コントローラーの設定方法 Navigation:platform -Version:4.9 -SkillLevel:Intermediate +version:4.9 +Skilllevel:Intermediate parent:Platforms/VR type:overview [TOC(start:2)] -アンリアル エンジン 4.9 のリリースで、アンリアル エンジンのモーション コントローラーとのインターフェースが大幅に変更されました。 -モーション コントローラーをコンポーネントとしてポーン / キャラクターに追加し、どちらの「手」にするかが設定可能になって、モーション コントローラーが使用できるようになりました。 +モーション コントローラーをコンポーネントとしてポーン / キャラクターに追加し、「右手 / 左手」の指定およびモーション コントローラーの使用が可能になりました。 このガイドでは、モーション コントローラーを使うための VR プロジェクトの設定方法について説明します。 [region:tip] VR ヘッドセットとモーション コントローラーがパソコンに接続されていますか。必要なドライバーはインストール済みでしょうか。今一度ご確認ください。 -お済でない場合は [VR に関する情報](Platforms/VR) をご覧ください。UE4 で作業するために各種 VR ヘッドセットの取得方法が記載されています。 +各種 VR ヘッドセットを UE4 向けの設定する方法には、[VR](Platforms/VR) をご覧ください。 [/region] ## モーション コントローラーの設定 -モーション コントローラーを数ステップで簡単に完了できるように VR プロジェクトを設定します。 -次のセクションでは、モーション コントローラーでプロジェクトで簡単に使う方法を説明します。 + VR プロジェクトでモーション コントローラー コンポーネントを使用する設定にするには、モーション コントローラー コンポーネントをポーンに追加し設定する必要があります。 +このセクションでは、モーション コントローラーでプロジェクトで簡単に使う方法を説明します。 -1. コンテンツ ブラウザから Player Pawn ブループリントを開きます。 +[region:note] +この設定は、すべての UE4 プロジェクトに適用できます。 +[/region] - ![](Open_VR_Pawn.png) +1. **コンテンツ ブラウザ** で **Player Pawn** ブループリントを開きます。 - [region:note] - 次のステップは、VR プロジェクトに特化されておらず、すべてのプロジェクトのポーンに適用できます。 - [/region] + [REGION:lightbox] + [![](Open_VR_Pawn.png)(w:427)](Open_VR_Pawn.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] 1. ブループリントを開いたら、**[Viewport]** タブの **[Components]** セクションの **[Add Component (コンポーネントを追加)]** ボタンをクリックして、このブループリントに追加できるコンポーネントを表示します。 - ![](Find_Components.png) + [REGION:lightbox] + [![](Find_Components.png)(w:418)](Find_Components.png) + [/REGION] + + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] 1. **「Motion」** というワードを使って、表示された一覧の中でモーション コントローラーを検索します。 - Motion Controller コンポーネントが見つかったら、クリックしてコンポーネント リストに追加します。 + Motion Controller コンポーネントが見つかったら、クリックしてコンポーネント リストに追加します。 - [OBJECT:EmbeddedVideo] - [PARAMLITERAL:width] - 640 - [/PARAMLITERAL] - [PARAMLITERAL:height] - 360 - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - kcyHnfpmWbU - [/PARAMLITERAL] - [/OBJECT] + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 640 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 360 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + kcyHnfpmWbU + [/PARAMLITERAL] + [/OBJECT] 1. モーション コントローラーが追加されたらクリックして、**[Motion Controller]** セクションの **[Details (詳細)]** パネルの **[Hand]** が **[Left (左)]** に設定されていることを確認してください。 - ![](Setting_Up_Components.png) + [REGION:lightbox] + [![](Setting_Up_Components.png)(w:418)](Setting_Up_Components.png) + [/REGION] -1. ゲームを起動すればモーション コントローラーが動作するようになっていますが、ビジュアルは一切レンダリングされていないのでデフォルトでは何も見えません。 - これを修正するには、**Static Mesh Component** を [Components] セクションに追加して [Static Mesh] セクションのStatic Mesh コンポーネントの [Details (詳細)] セクションでドロップダウン メニューから使用するスタティックメッシュを選択します。 + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] - [OBJECT:EmbeddedVideo] - [PARAMLITERAL:width] - 640 - [/PARAMLITERAL] - [PARAMLITERAL:height] - 360 - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - x4vjDqnHQnk - [/PARAMLITERAL] - [/OBJECT] +1. モーション コントローラーをワールドで視覚表示するには、**[Components] パネル** で **[Motion Controller Component]** を選択し、**[Add Component]** ボタンで **[Static Mesh Component]** を追加します。 + そのスタティックメッシュ コンポーネントをモーション コントローラー上にドラッグして、モーション コントローラー コンポーネントの親とし、 + [Details (詳細)] パネルで、スタティックメッシュ アセットを新規コンポーネントのスタティックメッシュ プロパティに割り当てます。 - [region:tip] - コンテンツ ブラウザにスタティック メッシュが表示されない場合、スタティック メッシュをインポートするか、または **[Engine Content]** を有効にして、そこから選択する必要があります。 - 選択したスタティック メッシュが大きすぎたり小さすぎたりする場合、[Transform (トランスフォーム)] メニューの [Scale] セクションで自由に調整ができます。 - [/region] + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 640 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 360 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + x4vjDqnHQnk + [/PARAMLITERAL] + [/OBJECT] -1. 次は [Right Hand] を追加してこの手順を繰り返します。完了すると、Pawn ブループリントは次の画像のようになっています。 + [region:tip] + 現在プロジェクトにスタティクメッシュ アセットがない場合は、メッシュを 1 つインポートするか、ツールバーの [Marketplace] ボタンをクリックしてマーケットプレイスへ移動し、プロジェクトで使うアセットをいくつかダウンロードしてください。 + 選択したスタティック メッシュが大きすぎたり小さすぎたりする場合、[Details (詳細)] パネルの [Transform (トランスフォーム)] メニューの [Scale] セクションで好きな大きさに調整できます。 + [/region] - ![](Finshed_MC_Setup.png) +1. ルートの親となる別の Motion Controller コンポーネントを追加し、**[Right Hand (右手)]** となるように設定します。新しい Motion Controller コンポーネントの親とし、右手メッシュを適用した Static Mesh コンポーネントを追加します。 - [region:note] - 上の画像では、コーン形状の 2 つのメッシュが 2 つであることを示すために分かれて移動しました。 - プロジェクトを設定する際、お互いの右上に来るように両方のメッシュは 0,0,0 のままにしておきます。 - [/region] + [REGION:lightbox] + [![](Finshed_MC_Setup.png)(w:418)](Finshed_MC_Setup.png) + [/REGION] -## モーション コントローラーの作業 + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] -UE4 内でのモーション コントローラーの作業は、ゲームパッドやキーボードなどの入力デバイスの場合と似ています。 -**MotionController** を検索ワードにしてブループリント エディタの **Palette** を検索すると、Motion Controller で利用可能なすべてのボタンと制御が表示されます。 + [region:note] + 上の画像では、2 つ存在することを表すために、コーン形状を 2 つに分けました。 + プロジェクトを設定する際、お互いの右上に来るように両方のスタティックメッシュ コンポーネントは 0,0,0 のままにしておきます。 + [/region] + +## モーション コントローラーを使った作業 + +UE4 内でのモーション コントローラーを使った作業は、ゲームパッドやキーボードなどの入力デバイスの場合と似ています。 + +[region:tip] +ブループリント エディタの **Palette** で **MotionController** を検索すると、Motion Controller で利用可能なすべてのボタンと制御が表示されます。 +[/region] ![](Working_With_MC.png) -利用可能な Motion Controller 入力オプションを見てみると、大文字の **L** または **R** の隣に、その値が制御する対象の名前があります。 -L と R は、モーション コントローラーの **Left** または **Right** であることを意味しています。 +利用可能な Motion Controller 入力オプション、その横に大文字の **L** / **R**、一番右にはその値が制御する対象が表示されます。 +L / R は、モーション コントローラーの **Left** または **Right** です。 ![](MC_Left_Right.png) ## モーション コントローラーの使用方法 -次のセクションでは、**Right-Handed** モーション コントローラーでトリガー ボタンが押された時にスタティック メッシュを含むブループリントがワールドにスポーンされるように、モーション コントローラーを設定していきます。 -次に **Left-Handed** Motion Controller のトリガー ボタンを押すと、ワールドにスポーンされたスタティック メッシュを含むブループリントがワールドから削除されます。 +次のセクションでは、**Right-Handed** モーション コントローラーでトリガー ボタンが押されるとスタティック メッシュを含むブループリントがワールドにスポーンされるように、モーション コントローラーを設定していきます。 -1. コンテンツ ブラウザ内にブループリントを新規作成し、**BP_Sphere** という名前を付けて、ダブルクリックして開きます。 +1. コンテンツ ブラウザに新規マテリアルを作成し、**「MAT_Floor」** と名前を付けてダブルクリックして開きます。 -1. BP_Sphere Blueprint が開いたら、**[Viewport]** タブを開いて **Static Mesh コンポーネント** を追加します。 +1. **[Viewport]** タブを開いて **スタティックメッシュ コンポーネント** を追加します。 - ![](Add_SM_Component.png) + ![](Add_SM_Component.png) -1. Static Mesh コンポーネントを **Default Screen Root** の上に移動させ、**ArcadeEditorSphere** に使用する設定にして、ブループリントをコンパイルし保存します。 +1. スタティックメッシュ コンポーネントを **Default Screen Root** の上に移動させ、**ArcadeEditorSphere** に使用する設定にして、ブループリントをコンパイルし保存します。 - [OBJECT:EmbeddedVideo] - [PARAMLITERAL:width] - 640 - [/PARAMLITERAL] - [PARAMLITERAL:height] - 360 - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - PszzV_I0xso - [/PARAMLITERAL] - [/OBJECT] + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 640 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 360 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + PszzV_I0xso + [/PARAMLITERAL] + [/OBJECT] - [region:note] - **ArcadeEditorSphere** が表示されない場合は、**[View Options (表示オプション)]** で **「Engine Content」** フォルダを有効にし、**「Engine Content」** フォルダをクリックしてコンテンツ ブラウザで表示されるようにします。 - [/region] + [region:note] + **ArcadeEditorSphere** が表示されない場合は、**[View Options (表示オプション)]** で **「Engine Content」** フォルダを有効にし、**「Engine Content」** フォルダをクリックしてコンテンツ ブラウザで表示されるようにします。 + [/region] -1. BP_Sphere ブループリントを終了して **Pawn** ブループリントを開き、**[Event Graph]** タブをクリックします。 +1. BP_Sphere ブループリントを終了して **Pawn** ブループリントを開きます。 -1. **「Objects」** という名前で **Actor** 変数を新規作成し、**Variable Type** を配列に設定します。 +1. [My Blueprint] パネルの **[Event Graph]** タブを開き、**「Objects」** という名前の **Actor** 変数を新規作成し、**Variable Type** を配列に設定します。 + + ![](Create_New_Var.png) - ![](Create_New_Var.png) +1. モーション コントローラーのトリガー ボタンが押されると、このブループリントでワールドから指定オブジェクトの追加 / 削除が可能になります。そのためには、イベント グラフに次のブループリント ノードを追加して接続します。完了すると以下の画像のようになります。 -1. ワールドにオブジェクトを追加する機能を作成するには、イベント グラフに次のブループリント ノードを追加して接続します。完了すると以下の画像のようになります。 + [REGION:lightbox] + [![](Add_Objects_Setup.png)(w:459)](Add_Objects_Setup.png) + [/REGION] - ![](Add_Objects_Setup.png) + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] - [region:note] - この例に配置されてたオブジェクトは必ず表示されるように、**Spawn Offset** が追加されました。この部分はなくても機能しますので、**GetActorTransform** ノードから **Return Value** を受け取り、**SpawnActor** ブループリント ノードの **Spawn Transform** 入力へつなぐことで省略可能です。 - ![](Add_Objects_Setup_Alt.png) - [/region] + [region:note] + この例に配置されるオブジェクトが必ず表示されるように、**Spawn Offset** が追加されました。この部分はなくても機能します。**GetActorTransform** ノードから **Return Value** を受け取り、**SpawnActor** ブループリント ノードの **Spawn Transform** 入力へつなぐことで省略可能です。 + [REGION:lightbox] + [![](Add_Objects_Setup_Alt.png)(w:367)](Add_Objects_Setup_Alt.png) + [/REGION] + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] + [/region] -1. Add オブジェクトの設定が完了したら、**Spawn Actor** ブループリント ノードを選んで、1 つ前のステップで作成した ** BP_Sphere** ブループリントを **[Class]** セクションから選択します。 +1. **Spawn Actor** ノードを選んで、1 つ前のステップで作成した ** BP_Sphere** ブループリントを Class 入力へ割り当てます。 - ![](Setting_SpawnActor_Up.png) + ![](Setting_SpawnActor_Up.png) -1. ワールドにおかれたオブジェクトを削除する機能を作成するには、次のブループリント ノードを追加して接続します。完了すると以下の画像のようになります。 +1. ブループリントのこのセクションで、ワールドに配置されたオブジェクトの削除が可能になります。この機能を追加するには、以下のブループリント ノードを一緒に追加 / 接続します。完了すると以下の画像のようになります。 - ![](Remove_Objects_Setup.png) + [REGION:lightbox] + [![](Remove_Objects_Setup.png)(w:459)](Remove_Objects_Setup.png) + [/REGION] - [region:note] - 簡単にテストするためにキーボード入力キーをグラフ内に置きました。モーション コントローラーの作業には、この入力を加える必要はありません。 - [/region] + [REGION:caption] + クリックしてフルサイズで表示 + [/REGION] -1. Pawn ブループリントに変更を **コンパイル** して **保存** し、**[Play (再生)]** ボタンを押してレベルをプレビューします。 - レベルが始まったら、キーボードの **K** キーを押すか、Right Handed Motion Controller の Right trigger を押してオブジェクトをワールドに追加してみてください。 - ワールドからオブジェクトを取り除くには、キーボードの **T** キーを押すか、Left Handed Motion Controller の **Left** trigger を押します。以下のビデオで実演しています。 + [region:note] + 簡単にテストするためにキーボード入力キーをグラフ内に置きました。モーション コントローラーでの作業には、この入力は必要はありません。 + [/region] - [OBJECT:EmbeddedVideo] - [PARAMLITERAL:width] - 640 - [/PARAMLITERAL] - [PARAMLITERAL:height] - 360 - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - VXUowSUKT9I - [/PARAMLITERAL] - [/OBJECT] +1. Pawn ブループリントに変更を **コンパイル** して **保存** し、**[Play]** ボタンを押します。 + レベルが始まったら、キーボードの **K** キーを押すか、右手のモーション コントローラーの [Right Trigger] を押してオブジェクトをワールドに追加してみてください。 + ワールドからオブジェクトを取り除くには、キーボードの **T** キーを押すか、左手のモーション コントローラーの **Left** Trigger を押します。以下の動画で実際の操作を確認できます。 + + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 640 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 360 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + VXUowSUKT9I + [/PARAMLITERAL] + [/OBJECT] ## トレーニング ストリーム [REGION:topics third] [OBJECT:TopicCompactVideo] - [PARAMLITERAL:title] - モーション コントローラーの設定 - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - 6ALnsdQnkVQ - [/PARAMLITERAL] + [PARAMLITERAL:title] + モーション コントローラーの設定 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + 6ALnsdQnkVQ + [/PARAMLITERAL] [/OBJECT] [OBJECT:TopicCompactVideo] - [PARAMLITERAL:title] - モーション コントローラーと VR のインタラクションの作成 (パート 1) - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - eRNtgFo6iU0 - [/PARAMLITERAL] + [PARAMLITERAL:title] + モーション コントローラーと VR のインタラクションの作成 (その 1) + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + eRNtgFo6iU0 + [/PARAMLITERAL] [/OBJECT] [OBJECT:TopicCompactVideo] - [PARAMLITERAL:title] - モーション コントローラーと VR のインタラクションの作成 (パート 2) - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - utOahIZgKgc - [/PARAMLITERAL] + [PARAMLITERAL:title] + モーション コントローラーと VR のインタラクションの作成 (その 2) + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + utOahIZgKgc + [/PARAMLITERAL] [/OBJECT] [/REGION] diff --git a/Engine/Documentation/Source/Platforms/VR/MotionController/MotionControllerComponent.KOR.udn b/Engine/Documentation/Source/Platforms/VR/MotionController/MotionControllerComponent.KOR.udn index 425147fb2cad..0b2c7a6b2e4a 100644 --- a/Engine/Documentation/Source/Platforms/VR/MotionController/MotionControllerComponent.KOR.udn +++ b/Engine/Documentation/Source/Platforms/VR/MotionController/MotionControllerComponent.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3456880 Availability:Public Title:모션 콘트롤러 컴포넌트 셋업 Crumbs:%ROOT%, Platforms @@ -30,60 +30,84 @@ VR 프로젝트가 모션 콘트롤러를 사용하도록 하려면, , 폰에 1. 콘텐츠 브라우저에서 Player Pawn 블루프린트를 엽니다. - ![](Open_VR_Pawn.png) + [REGION:lightbox] + [![](Open_VR_Pawn.png)(w:427)](Open_VR_Pawn.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] 1. 블루프린트가 열렸으면, **컴포넌트** 섹션의 **뷰포트** 탭으로 가 **컴포넌트 추가** 버튼을 눌러 이 블루프린트에 추가할 수 있는 컴포넌트를 펼칩니다. - ![](Find_Components.png) + [REGION:lightbox] + [![](Find_Components.png)(w:418)](Find_Components.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] 1. 표시되는 목록에서 **Motion** 을 검색어로 하여 Motion Controller 를 검색합니다. - 모션 콘트롤러 컴포넌트를 찾았으면, 클릭하여 컴포넌트 목록에 추가합니다. + 모션 콘트롤러 컴포넌트를 찾았으면, 클릭하여 컴포넌트 목록에 추가합니다. - [OBJECT:EmbeddedVideo] - [PARAMLITERAL:width] - 640 - [/PARAMLITERAL] - [PARAMLITERAL:height] - 360 - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - kcyHnfpmWbU - [/PARAMLITERAL] - [/OBJECT] + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 640 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 360 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + kcyHnfpmWbU + [/PARAMLITERAL] + [/OBJECT] 1. 모션 콘트롤러가 추가되었으면, 클릭해서 선택한 다음 **디테일** 패널의 **Motion Controller** 섹션 아래 **Hand** 가 **Left** 로 설정되어 있는지 확인합니다. - ![](Setting_Up_Components.png) + [REGION:lightbox] + [![](Setting_Up_Components.png)(w:418)](Setting_Up_Components.png) + [/REGION] + + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] 1. 모션 콘트롤러에 월드 내 시각적 표현을 부여하려면, **컴포넌트 패널** 의 **Motion Controller Component** 를 선택하고 **컴포넌트 추가** 버튼을 클릭한 뒤 **Static Mesh Component** 를 추가합니다. - Static Mesh Component 를 끌어 Motion Controller 위에 놓아 부모로 설정하고, - 새 컴포넌트의 디테일 패널에서 Static Mesh 프로퍼티에 스태틱 메시 애셋을 할당합니다. + Static Mesh Component 를 끌어 Motion Controller 위에 놓아 부모로 설정하고, + 새 컴포넌트의 디테일 패널에서 Static Mesh 프로퍼티에 스태틱 메시 애셋을 할당합니다. - [OBJECT:EmbeddedVideo] - [PARAMLITERAL:width] - 640 - [/PARAMLITERAL] - [PARAMLITERAL:height] - 360 - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - x4vjDqnHQnk - [/PARAMLITERAL] - [/OBJECT] + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 640 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 360 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + x4vjDqnHQnk + [/PARAMLITERAL] + [/OBJECT] - [region:tip] - 프로젝트에 현재 스태틱 메시 애셋이 없다면, 별도의 메시를 하나 임포트하거나, 툴바의 마켓플레이스 버튼을 클릭한 뒤 프로젝트에 사용할 애셋을 다운로드하세요. - 또 선택한 스태틱 메시가 너무 크거나 작으면, 디테일 패널의 트랜스폼 섹션 내 스케일 부분을 사용해서 원하는 대로 조절하면 됩니다. - [/region] + [region:tip] + 프로젝트에 현재 스태틱 메시 애셋이 없다면, 별도의 메시를 하나 임포트하거나, 툴바의 마켓플레이스 버튼을 클릭한 뒤 프로젝트에 사용할 애셋을 다운로드하세요. + 또 선택한 스태틱 메시가 너무 크거나 작으면, 디테일 패널의 트랜스폼 섹션 내 스케일 부분을 사용해서 원하는 대로 조절하면 됩니다. + [/region] 1. 루트를 부모로 하는 모션 콘트롤러 컴포넌트를 또하나 추가하고, **오른손** 으로 설정합니다. 새로운 모션 콘트롤러 컴포넌트를 부모로 하여 스태틱 메시 컴포넌트를 하나 추가한 뒤, 거기에 오른손 메시를 적용합니다. - ![](Finshed_MC_Setup.png) + [REGION:lightbox] + [![](Finshed_MC_Setup.png)(w:418)](Finshed_MC_Setup.png) + [/REGION] - [region:note] - 위 그림에서 두 개의 원뿔 모양 메시가 서로 떨어져 있어 둘이라는 것을 보여줍니다. - 프로젝트에서 이렇게 구성할 때 두 스태틱 메시 컴포넌트 모두 0,0,0 에 놔두어 서로 위에 겹치도록 합니다. - [/region] + [REGION:caption] + 클릭하면 원본 이미지를 확인합니다. + [/REGION] + + [region:note] + 위 그림에서 두 개의 원뿔 모양 메시가 서로 떨어져 있어 둘이라는 것을 보여줍니다. + 프로젝트에서 이렇게 구성할 때 두 스태틱 메시 컴포넌트 모두 0,0,0 에 놔두어 서로 위에 겹치도록 합니다. + [/region] ## 모션 콘트롤러 작업 @@ -109,94 +133,111 @@ VR 프로젝트가 모션 콘트롤러를 사용하도록 하려면, , 폰에 1. **뷰포트** 탭으로 이동하여 **스태틱 메시 컴포넌트** 를 새로 추가합니다. - ![](Add_SM_Component.png) + ![](Add_SM_Component.png) 1. 스태틱 메시 컴포넌트를 **디폴트 스크린 루트** 위로 옮긴 다음 사용된 스태틱 메시를 **ArcadeEditorSphere** 로 설정하고 블루프린트를 컴파일 및 저장합니다. - [OBJECT:EmbeddedVideo] - [PARAMLITERAL:width] - 640 - [/PARAMLITERAL] - [PARAMLITERAL:height] - 360 - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - PszzV_I0xso - [/PARAMLITERAL] - [/OBJECT] + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 640 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 360 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + PszzV_I0xso + [/PARAMLITERAL] + [/OBJECT] - [region:note] - **ArcadeEditorSphere** 를 찾을 수 없다면 **뷰 옵션** 에서 **엔진 콘텐츠** 폴더 표시 옵션을 선택하여 콘텐츠 브라우저에 나타나도록 합니다. - [/region] + [region:note] + **ArcadeEditorSphere** 를 찾을 수 없다면 **뷰 옵션** 에서 **엔진 콘텐츠** 폴더 표시 옵션을 선택하여 콘텐츠 브라우저에 나타나도록 합니다. + [/region] 1. BP_Sphere 블루프린트를 저장하고 **Pawn** 블루프린트를 엽니다. 1. 내 블루프린트 패널에서, **이벤트 그래프** 탭으로 가 새 **Actor** 변수를 만들어 이름을 **Objects** 라 하고 그 **변수 유형** 을 배열로 설정합니다. - - ![](Create_New_Var.png) + + ![](Create_New_Var.png) 1. 이 블루프린트는 모션 콘트롤러의 트리거 버튼을 눌렀을 때 월드에서 특정 오브젝트를 추가하고 제거할 수 있도록 해 줄 것입니다. 그러기 위해, 이벤트 그래프 안에 다음과 같이 블루프린트 노드들을 추가하고 연결해 줍니다. 완료되면 다음 그림과 같은 모습일 것입니다. - ![](Add_Objects_Setup.png) + [REGION:lightbox] + [![](Add_Objects_Setup.png)(w:459)](Add_Objects_Setup.png) + [/REGION] - [region:note] - **Spawn Offset** 을 추가한 것은 이 예제에서 오브젝트를 배치하면서 볼 수 있도록 하기 위해서입니다. 오프셋은 반드시 필요한 부분은 아니며, **GetActorTransform** 노드에서 **Return Value** 를 잡아다가 **SpawnActor** 블루프린트 노드의 **Spawn Transform** 입력에 연결해 주는 것으로 생략할 수 있습니다. - ![](Add_Objects_Setup_Alt.png) - [/region] + [REGION:caption] + Click for full image. + [/REGION] + + [region:note] + **Spawn Offset** 을 추가한 것은 이 예제에서 오브젝트를 배치하면서 볼 수 있도록 하기 위해서입니다. 오프셋은 반드시 필요한 부분은 아니며, **GetActorTransform** 노드에서 **Return Value** 를 잡아다가 **SpawnActor** 블루프린트 노드의 **Spawn Transform** 입력에 연결해 주는 것으로 생략할 수 있습니다. + [REGION:lightbox] + [![](Add_Objects_Setup_Alt.png)(w:367)](Add_Objects_Setup_Alt.png) + [/REGION] + [REGION:caption] + Click for full image. + [/REGION] + [/region] 1. **Spawn Actor** 노드를 선택하고 1 단계에서 만들었던 **BP_Sphere** 블루프린트를 클래스 입력에 할당합니다. - ![](Setting_SpawnActor_Up.png) + ![](Setting_SpawnActor_Up.png) 1. 이 블루프린트 부분은 월드에 배치된 오브젝트를 제거하는 기능을 합니다. 이 함수성을 추가하려면, 다음과 같이 노드들을 추가하고 연결해 줍니다. 완료되면 다음 그림과 같은 모습일 것입니다. - ![](Remove_Objects_Setup.png) + [REGION:lightbox] + [![](Remove_Objects_Setup.png)(w:459)](Remove_Objects_Setup.png) + [/REGION] - [region:note] - 그래프에는 빠른 테스트를 위해 키 입력을 받는 노드를 배치했습니다. 모션 콘트롤러 작동을 위해 필수는 아닙니다. - [/region] + [REGION:caption] + Click for full image. + [/REGION] + + [region:note] + 그래프에는 빠른 테스트를 위해 키 입력을 받는 노드를 배치했습니다. 모션 콘트롤러 작동을 위해 필수는 아닙니다. + [/region] 1. 폰 블루프린트 변경사항을 **컴파일** 및 **저장** 하고 **플레이** 버튼을 누릅니다. - 레벨이 시작되면 **K** 키나 오른손 모션 콘트롤러의 오른쪽 트리거를 누르는 것으로 월드에 오브젝트를 추가해 보세요. - 월드에서 오브젝트를 제거하려면 **T** 키를 누르거나 왼손 모션 콘트롤러의 **왼쪽** 트리거를 누르면 됩니다. 예제는 아래 데모와 같습니다. + 레벨이 시작되면 **K** 키나 오른손 모션 콘트롤러의 오른쪽 트리거를 누르는 것으로 월드에 오브젝트를 추가해 보세요. + 월드에서 오브젝트를 제거하려면 **T** 키를 누르거나 왼손 모션 콘트롤러의 **왼쪽** 트리거를 누르면 됩니다. 예제는 아래 데모와 같습니다. - [OBJECT:EmbeddedVideo] - [PARAMLITERAL:width] - 640 - [/PARAMLITERAL] - [PARAMLITERAL:height] - 360 - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - VXUowSUKT9I - [/PARAMLITERAL] - [/OBJECT] + [OBJECT:EmbeddedVideo] + [PARAMLITERAL:width] + 640 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 360 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + VXUowSUKT9I + [/PARAMLITERAL] + [/OBJECT] ## 교육 자료 [REGION:topics third] [OBJECT:TopicCompactVideo] - [PARAMLITERAL:title] - 모션 콘트롤러 구성 - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - 6ALnsdQnkVQ - [/PARAMLITERAL] + [PARAMLITERAL:title] + 모션 콘트롤러 구성 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + 6ALnsdQnkVQ + [/PARAMLITERAL] [/OBJECT] [OBJECT:TopicCompactVideo] - [PARAMLITERAL:title] - 모션 콘트롤러로 VR 에서의 상호작용 만들기 1 부 - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - eRNtgFo6iU0 - [/PARAMLITERAL] + [PARAMLITERAL:title] + 모션 콘트롤러로 VR 에서의 상호작용 만들기 1 부 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + eRNtgFo6iU0 + [/PARAMLITERAL] [/OBJECT] [OBJECT:TopicCompactVideo] - [PARAMLITERAL:title] - 모션 콘트롤러로 VR 에서의 상호작용 만들기 2 부 - [/PARAMLITERAL] - [PARAMLITERAL:videoid] - utOahIZgKgc - [/PARAMLITERAL] + [PARAMLITERAL:title] + 모션 콘트롤러로 VR 에서의 상호작용 만들기 2 부 + [/PARAMLITERAL] + [PARAMLITERAL:videoid] + utOahIZgKgc + [/PARAMLITERAL] [/OBJECT] [/REGION] diff --git a/Engine/Documentation/Source/Platforms/VR/SplashScreens/VRSplashScreens.JPN.udn b/Engine/Documentation/Source/Platforms/VR/SplashScreens/VRSplashScreens.JPN.udn index 0637b010ea48..3b2db5e2d77f 100644 --- a/Engine/Documentation/Source/Platforms/VR/SplashScreens/VRSplashScreens.JPN.udn +++ b/Engine/Documentation/Source/Platforms/VR/SplashScreens/VRSplashScreens.JPN.udn @@ -1,4 +1,4 @@ -INTChangeList:3244832 +INTSourceChangelist:3355812 Availability:Docs Title:VR スプラッシュ スクリーン Crumbs:%ROOT%, Platforms, Platforms/VR @@ -15,16 +15,16 @@ Unreal Engine 4 (UE4) は、Oculus、Gear VR、SteamVR、PSVR Head Mounted Displ ## VR Splash Screen 対応のプラットフォーム -VR Splash Screen は以下の VR プラットフォームでのみ使用できます。 +VR スプラッシュ スクリーンは以下の VR プラットフォームでのみ使用できます。 * **Oculus VR** * **Gear VR** * **Steam VR** * **PSVR** -## VR Splash Screen プロジェクトの設定 +## VR スプラッシュ スクリーン プロジェクトの設定 -VR splash screen を設定および使用する前に、まず **Game Mode** と **Pawn** ブループリントを新規作成してVR splash screen での作業をしやすくします。次のセクションでは、作成すべきブループリントとその設定方法について説明します。 +VR スプラッシュ スクリーンを設定および使用する前に、まず **Game Mode** と **Pawn** ブループリントを新規作成してVR スプラッシュ スクリーンでの作業をしやすくします。次のセクションでは、作成すべきブループリントとその設定方法について説明します。 1. コンテンツ ブラウザを右クリックして、**[Create Basic Asset (基本アセットの作成)]** リストで **[Blueprint Class]** オプションをクリックします。 diff --git a/Engine/Documentation/Source/Platforms/VR/VR.INT.udn b/Engine/Documentation/Source/Platforms/VR/VR.INT.udn index 62a35ee4578f..569f58da1203 100644 --- a/Engine/Documentation/Source/Platforms/VR/VR.INT.udn +++ b/Engine/Documentation/Source/Platforms/VR/VR.INT.udn @@ -5,63 +5,21 @@ Description:Information over developing for virtual reality platforms. Navigation:platform Version: 4.9 Type:landing +tags:VR +tags:Platform parent:Platforms order:2 - -[VAR:Params] -[PARAM:image] - ![%Platforms/VR:title%](%ROOT%/placeholder_topic.png) -[/PARAM] -[PARAM:icon] - ![](%ROOT%/platform_icon.png)(convert:false) -[/PARAM] -[PARAM:title] - %Platforms/VR:title% -[/PARAM] -[PARAM:description] - %Platforms/VR:description% -[/PARAM] -[PARAM:path] - [RELATIVE:Platforms/VR] -[/PARAM] -[/VAR] - -[VAR:Topic] -[OBJECT:Topic] -%params% -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] -%params% -[/OBJECT] -[/VAR] - -[VAR:Role] -[OBJECT:Role] -%params% -[PARAMLITERAL:id] -vr -[/PARAMLITERAL] -[/OBJECT] -[/VAR] - - -## Starting Out - -[DIR(output:"topic" type:"quick start" tags:"vr")] +topic-icon:%ROOT%/platform_icon.png +topic-image:VirtualRealityDevelopment_topic.png ## Virtual Reality Platforms -[DIR(end:"1" output:"listbutton" type:"landing" tags:"platform" parent:"Platforms/VR")] +[DIR(end:"1" output:"topic" type:"landing" tags:"platform" parent:"Platforms/VR")] ## Virtual Reality Topics -[DIR(end:"1" output:"listbutton" parent:"Platforms/VR" tags:"!platform")] +[DIR(end:"1" output:"topic" parent:"Platforms/VR" tags:"!platform")] ## Training Streams -[REGION:topics third] [DIR(output:"video" type:"video" tags:"Virtual Reality")] -[/REGION] diff --git a/Engine/Documentation/Source/Platforms/VR/VR.JPN.udn b/Engine/Documentation/Source/Platforms/VR/VR.JPN.udn index 95a31797f0d0..3d5421d2aab7 100644 --- a/Engine/Documentation/Source/Platforms/VR/VR.JPN.udn +++ b/Engine/Documentation/Source/Platforms/VR/VR.JPN.udn @@ -1,68 +1,26 @@ -INTSourceChangelist:3340158 +INTSourceChangelist:3467293 Availability:Public -Title:VR を開発する +Title:VR の開発 Crumbs:%ROOT%, Platforms Description:VR 用プラットフォームの開発に関する情報 Navigation:platform Version:4.9 Type:landing +tags:VR +tags:Platform parent:Platforms order:2 - -[VAR:Params] -[PARAM:image] - ![%Platforms/VR:title%](%ROOT%/placeholder_topic.png) -[/PARAM] -[PARAM:icon] - ![](%ROOT%/platform_icon.png)(convert:false) -[/PARAM] -[PARAM:title] - %Platforms/VR:title% -[/PARAM] -[PARAM:description] - %Platforms/VR:description% -[/PARAM] -[PARAM:path] - [RELATIVE:Platforms/VR] -[/PARAM] -[/VAR] - -[VAR:Topic] -[OBJECT:Topic] -%params% -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] -%params% -[/OBJECT] -[/VAR] - -[VAR:Role] -[OBJECT:Role] -%params% -[PARAMLITERAL:id] -VR -[/PARAMLITERAL] -[/OBJECT] -[/VAR] - - -## はじめよう - -[DIR(output:"topic" type:"quick start" tags:"vr")] +topic-icon:%ROOT%/platform_icon.png +topic-image:VirtualRealityDevelopment_topic.png ## VR 用プラットフォーム -[DIR(end:"1" output:"listbutton" type:"landing" tags:"platform" parent:"Platforms/VR")] +[DIR(end:"1" output:"topic" type:"landing" tags:"platform" parent:"Platforms/VR")] ## VR に関するトピックス -[DIR(end:"1" output:"listbutton" parent:"Platforms/VR" tags:"!platform")] +[DIR(end:"1" output:"topic" parent:"Platforms/VR" tags:"!platform")] ## トレーニング ストリーム -[REGION:topics third] [DIR(output:"video" type:"video" tags:"Virtual Reality")] -[/REGION] diff --git a/Engine/Documentation/Source/Platforms/VR/VR.KOR.udn b/Engine/Documentation/Source/Platforms/VR/VR.KOR.udn index 4b71cf319ef1..84a7c1c8556b 100644 --- a/Engine/Documentation/Source/Platforms/VR/VR.KOR.udn +++ b/Engine/Documentation/Source/Platforms/VR/VR.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3340158 +INTSourceChangelist:3467293 Availability:Public Title:가상 현실 개발 Crumbs:%ROOT%, Platforms @@ -6,63 +6,21 @@ Description:가상 현실 플랫폼용 개발에 관련된 정보입니다. Navigation:platform Version: 4.9 Type:landing +tags:VR +tags:Platform parent:Platforms order:2 - -[VAR:Params] -[PARAM:image] - ![%Platforms/VR:title%](%ROOT%/placeholder_topic.png) -[/PARAM] -[PARAM:icon] - ![](%ROOT%/platform_icon.png)(convert:false) -[/PARAM] -[PARAM:title] - %Platforms/VR:title% -[/PARAM] -[PARAM:description] - %Platforms/VR:description% -[/PARAM] -[PARAM:path] - [RELATIVE:Platforms/VR] -[/PARAM] -[/VAR] - -[VAR:Topic] -[OBJECT:Topic] -%params% -[/OBJECT] -[/VAR] - -[VAR:TopicCompact] -[OBJECT:TopicCompact] -%params% -[/OBJECT] -[/VAR] - -[VAR:Role] -[OBJECT:Role] -%params% -[PARAMLITERAL:id] -vr -[/PARAMLITERAL] -[/OBJECT] -[/VAR] - - -## 시작하기 - -[DIR(output:"topic" type:"quick start" tags:"vr")] +topic-icon:%ROOT%/platform_icon.png +topic-image:VirtualRealityDevelopment_topic.png ## 가상 현실 플랫폼 -[DIR(end:"1" output:"listbutton" type:"landing" tags:"platform" parent:"Platforms/VR")] +[DIR(end:"1" output:"topic" type:"landing" tags:"platform" parent:"Platforms/VR")] ## 가상 현실 토픽 -[DIR(end:"1" output:"listbutton" parent:"Platforms/VR" tags:"!platform")] +[DIR(end:"1" output:"topic" parent:"Platforms/VR" tags:"!platform")] ## 교육 자료 -[REGION:topics third] [DIR(output:"video" type:"video" tags:"Virtual Reality")] -[/REGION] \ No newline at end of file diff --git a/Engine/Documentation/Source/Platforms/iOS/InAppPurchases/In-AppPurchases.JPN.udn b/Engine/Documentation/Source/Platforms/iOS/InAppPurchases/In-AppPurchases.JPN.udn index 496436ab80d1..3e8ae05263c5 100644 --- a/Engine/Documentation/Source/Platforms/iOS/InAppPurchases/In-AppPurchases.JPN.udn +++ b/Engine/Documentation/Source/Platforms/iOS/InAppPurchases/In-AppPurchases.JPN.udn @@ -1,11 +1,11 @@ -INTSourceChangelist:3081127 -Title:iOS でアプリ内課金を使用する +INTSourceChangelist:3150518 +Title:iOS でのアプリ内課金の使用方法 Description:iOS ゲームのアプリ内課金を使ってゲームに追加の有料コンテンツを提供する Crumbs: Availability:Public Parent:Platforms/iOS order:1 -type:howto +type:how-to Related: ## コンフィギュレーション @@ -13,14 +13,14 @@ Related: 1. iTunes Connect でアプリ内課金を設定するためのステップを説明します。 [REGION:note] - Google Play の id はすべて小文字でなければなりません。さらに、iOS と Android の ID を一致させておくとブループリントの設定がとても楽になります。 + Google Play の id にはすべて小文字を使用します。また、iOS と Android の ID を同じにしておくと、ブループリントをとても楽に設定することができます。 [/REGION] ![image alt text](image_1.png) -1. 使用する ID およびアイテムが消費型かそうでないかをメモしておきましょう。 +1. 使用する ID およびアイテムが消費型か非消費型かをメモしておきます。 -1. ブループリント プロジェクトであれば設定の必要はありません。コード プロジェクトのためオンライン システムを使う設定が必要な場合は、プロジェクトの Build.cs ファイルに次のブロックを加えてください。 +1. ブループリント プロジェクトの場合は、そのままで大丈夫です。コード プロジェクト用にオンライン システムを使う設定にするには、プロジェクトの Build.cs ファイルに次のブロックを加えてください。 if (Target.Platform == UnrealTargetPlatform.IOS) { diff --git a/Engine/Documentation/Source/Platforms/iOS/QuickStart/7/iOSQuickStart_7.INT.udn b/Engine/Documentation/Source/Platforms/iOS/QuickStart/7/iOSQuickStart_7.INT.udn index 241e1c8fd9b0..5cbe5f838e98 100644 --- a/Engine/Documentation/Source/Platforms/iOS/QuickStart/7/iOSQuickStart_7.INT.udn +++ b/Engine/Documentation/Source/Platforms/iOS/QuickStart/7/iOSQuickStart_7.INT.udn @@ -36,7 +36,34 @@ SkillLevel: Intermediate 1. In the toolbar, click the arrow next to **Launch** to open the **Launch Options** menu and select the iOS device. + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + windows + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] ![](launch_ios.png) + [/PARAM] + [/OBJECT] + + [OBJECT:ToggleButtonContent] + [PARAMLITERAL:category] + OS + [/PARAMLITERAL] + [PARAMLITERAL:id] + mac + [/PARAMLITERAL] + [PARAMLITERAL:active] + [/PARAMLITERAL] + [PARAM:content] + ![](launch_ios_Mac.png) + [/PARAM] + [/OBJECT] + 1. The current map is cooked and packaged and installed on your device. diff --git a/Engine/Documentation/Source/Platforms/iOS/iOS.INT.udn b/Engine/Documentation/Source/Platforms/iOS/iOS.INT.udn index e9981f067c90..2ed9bb663d8e 100644 --- a/Engine/Documentation/Source/Platforms/iOS/iOS.INT.udn +++ b/Engine/Documentation/Source/Platforms/iOS/iOS.INT.udn @@ -9,6 +9,7 @@ type:landing parent:Platforms/Mobile tags:Mobile tags:iOS +topic-image:iOSGameDevelopment_topic.png [OBJECT:TopicButtonList] [PARAM:icon] diff --git a/Engine/Documentation/Source/Platforms/iOS/iOS.JPN.udn b/Engine/Documentation/Source/Platforms/iOS/iOS.JPN.udn index a497bb5eee25..f01d50a4865a 100644 --- a/Engine/Documentation/Source/Platforms/iOS/iOS.JPN.udn +++ b/Engine/Documentation/Source/Platforms/iOS/iOS.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3150518 +INTSourceChangelist:3467293 Availability:Public Title: iOS ゲームの開発 Crumbs:%ROOT%, Platforms @@ -10,6 +10,7 @@ type:landing parent:Platforms/Mobile tags:Mobile tags:iOS +topic-image:iOSGameDevelopment_topic.png [OBJECT:TopicButtonList] [PARAM:icon] diff --git a/Engine/Documentation/Source/Platforms/iOS/iOS.KOR.udn b/Engine/Documentation/Source/Platforms/iOS/iOS.KOR.udn index f887dcf2bce9..3882a6b4a64d 100644 --- a/Engine/Documentation/Source/Platforms/iOS/iOS.KOR.udn +++ b/Engine/Documentation/Source/Platforms/iOS/iOS.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3150518 +INTSourceChangelist:3467293 Availability: Public Title: iOS 게임 개발 Crumbs:%ROOT%, Platforms @@ -10,6 +10,7 @@ type:landing parent:Platforms/Mobile tags:Mobile tags:iOS +topic-image:iOSGameDevelopment_topic.png [OBJECT:TopicButtonList] [PARAM:icon] diff --git a/Engine/Documentation/Source/Programming/Assets/AsyncLoading/AsyncLoading.KOR.udn b/Engine/Documentation/Source/Programming/Assets/AsyncLoading/AsyncLoading.KOR.udn index 1ca4423f98e4..be12b387fa6f 100644 --- a/Engine/Documentation/Source/Programming/Assets/AsyncLoading/AsyncLoading.KOR.udn +++ b/Engine/Documentation/Source/Programming/Assets/AsyncLoading/AsyncLoading.KOR.udn @@ -7,7 +7,7 @@ Version: 4.9 [TOC(start:2)] -UE4 에는 애셋 데이터 비동기 로딩을 훨씬 쉽게 할 수 있는 신규 시스템이 다수 도입, UE3 의 기존 시크프리 콘텐츠 패키지의 함수성 대다수를 대체하고 있습니다. 이 신규 시스템은 개발 도중이나 디바이스상에서 쿠킹된 데이터로 실행할 때나 동일하게 작동하므로, 필요에 따라 데이터를 로딩하기 위한 별도의 코드 패쓰를 유지할 필요가 없습니다. 필요에 따라 데이터를 로드 및 레퍼런싱에 사용되는 방법은 일반적으로 두 가지 있습니다. +UE4 에는 애셋 데이터 비동기 로딩을 훨씬 쉽게 할 수 있는 신규 시스템이 다수 도입, UE3 의 기존 시크프리 콘텐츠 패키지의 함수성 대다수를 대체하고 있습니다. 이 신규 시스템은 개발 도중이나 디바이스상에서 쿠킹된 데이터로 실행할 때나 동일하게 작동하므로, 필요에 따라 데이터를 로딩하기 위한 별도의 코드 패스를 유지할 필요가 없습니다. 필요에 따라 데이터를 로드 및 레퍼런싱에 사용되는 방법은 일반적으로 두 가지 있습니다. ## FStringAssetReference 와 TAssetPtr @@ -80,6 +80,6 @@ TAssetPtr 과 StringAssetReference 는 아티스트나 디자이너가 레퍼런 } } -이 예제에서 ItemList 는 `TArray< TAssetPtr >` 이며, 에디터에서 디자이너에 의해 수정된 것입니다. 코드는 그 리스트에 대해 반복하여 `StringReferences` 로 변환시킨 다음 로드를 위한 대기열에 등록시킵니다. 그 아이템 전부가 로드되(거나 없어서 실패하)면 전달된 델리게이트를 호출합니다. 그러면 그 델리게이트는 같은 아이템 리스트에 대해 반복하여 그 역참조를 구한 다음 플레이어에게 전해줍니다. `StreamableManager` 는 델리게이트가 호출될 때까지 로드하는 애셋에 대한 하드 레퍼런스를 유지시켜, 비동기 로드하려 했던 오브젝트의 델리게이트가 호출되기도 전에 가비지 콜렉팅되는 일이 없도록 합니다. 델리게이트가 호출된 이후에는 그 레퍼런스가 해제되므로, 계속해서 남아있도록 하려면 어딘가에 하드 레퍼런스를 해 줘야 합니다. +이 예제에서 ItemList 는 `TArray< TAssetPtr >` 이며, 에디터에서 디자이너에 의해 수정된 것입니다. 코드는 그 리스트에 대해 반복하여 `StringReferences` 로 변환시킨 다음 로드를 위한 대기열에 등록시킵니다. 그 아이템 전부가 로드되(거나 없어서 실패하)면 전달된 델리게이트를 호출합니다. 그러면 그 델리게이트는 같은 아이템 리스트에 대해 반복하여 그 역참조를 구한 다음 플레이어에게 전해줍니다. `StreamableManager` 는 델리게이트가 호출될 때까지 로드하는 애셋에 대한 하드 레퍼런스를 유지시켜, 비동기 로드하려 했던 오브젝트의 델리게이트가 호출되기도 전에 가비지 컬렉팅되는 일이 없도록 합니다. 델리게이트가 호출된 이후에는 그 레퍼런스가 해제되므로, 계속해서 남아있도록 하려면 어딘가에 하드 레퍼런스를 해 줘야 합니다. 같은 메소드를 사용해서 `FAssetData` 를 비동기 로드할 수도 있는데, 그냥 `ToStringReference` 를 호출한 다음 배열에 추가시키고 델리게이트를 붙여 RequestAsyncLoad 를 호출해 주면 됩니다. 델리게이트는 원하는 무엇이든 될 수 있으므로, 원한다면 페이로드 정보와 함께 전달해 줄 수 있습니다. 위에 언급한 메소드를 조합하면 게임 내 어느 애셋에 대해서도 효율적인 로드가 가능한 시스템을 구축할 수 있을 것입니다. 메모리에 직접 접근하는 게임플레이 코드가 비동기 로드를 처리하도록 변환해 주는 작업에 시간이 조금 걸리겠지만, 그 이후에는 게임에서 발생하는 멈춤 현상이나 차지하는 메모리 양이 훨씬 줄어들 것입니다. diff --git a/Engine/Documentation/Source/Programming/Assets/CustomImporters/CustomImporters.KOR.udn b/Engine/Documentation/Source/Programming/Assets/CustomImporters/CustomImporters.KOR.udn index f2235665361b..2ab33a472ba0 100644 --- a/Engine/Documentation/Source/Programming/Assets/CustomImporters/CustomImporters.KOR.udn +++ b/Engine/Documentation/Source/Programming/Assets/CustomImporters/CustomImporters.KOR.udn @@ -142,7 +142,7 @@ UFactory-파생형은 대부분, 팩토리 클래스의 StaticConstructor() 오 // 지원되는 클래스가 없다고 선언하면 // Import Dialog 에서 'OK'가 선택되어 닫힐 때 - // 임포트 패쓰에서 ResolveSupportedClass() 호출 + // 임포트 패스에서 ResolveSupportedClass() 호출 SupportedClass = NULL; // 이 팩토리가 .ABC 파일에 관심있다고 등록 diff --git a/Engine/Documentation/Source/Programming/Development/BuildGraph/ScriptAnatomy/Tasks/BuildGraphScriptTasks.CHN.udn b/Engine/Documentation/Source/Programming/Development/BuildGraph/ScriptAnatomy/Tasks/BuildGraphScriptTasks.CHN.udn index 205587c472c0..385deb3a6e7d 100644 --- a/Engine/Documentation/Source/Programming/Development/BuildGraph/ScriptAnatomy/Tasks/BuildGraphScriptTasks.CHN.udn +++ b/Engine/Documentation/Source/Programming/Development/BuildGraph/ScriptAnatomy/Tasks/BuildGraphScriptTasks.CHN.udn @@ -1,34 +1,14 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3358550 Availability:Docs Title:BuildGraph 脚本任务 -Crumbs: %ROOT%, Programming, Programming/Development, Programming/Development/BuildGraph, Programming/Development/BuildGraph/ScriptAnatomy +Crumbs: Description:了解如何利用 BuildGraph 创建自定义任务。 version:4.13 parent:Programming/Development/BuildGraph -type:Reference -related:Programming/Development/BuildGraph/ScriptAnatomy +type:overview +tags:Programming tags:BuildGraph -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Programming/Development/BuildGraph/ScriptAnatomy/Tasks%](tasks_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/reference_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Programming/Development/BuildGraph/ScriptAnatomy/Tasks:title% - [/PARAM] - [PARAM:description] - %Programming/Development/BuildGraph/ScriptAnatomy/Tasks:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Programming/Development/BuildGraph/ScriptAnatomy/Tasks] - [/PARAM] -[/OBJECT] -[/VAR] - [TOC(start:1 end:3)] [EXCERPT:BuildGraphScriptTasks] diff --git a/Engine/Documentation/Source/Programming/Development/BuildGraph/ScriptAnatomy/Tasks/BuildGraphScriptTasks.KOR.udn b/Engine/Documentation/Source/Programming/Development/BuildGraph/ScriptAnatomy/Tasks/BuildGraphScriptTasks.KOR.udn index f0c7efaf5362..510994b0ea29 100644 --- a/Engine/Documentation/Source/Programming/Development/BuildGraph/ScriptAnatomy/Tasks/BuildGraphScriptTasks.KOR.udn +++ b/Engine/Documentation/Source/Programming/Development/BuildGraph/ScriptAnatomy/Tasks/BuildGraphScriptTasks.KOR.udn @@ -1,11 +1,11 @@ -INTSourceChangelist:3356804 -Availability: Public +INTSourceChangelist:3358550 +Availability:Docs Title: BuildGraph 스크립트 태스크 Crumbs: Description: BuildGraph 로 커스텀 태스크를 쉽게 만드는 법을 배워봅니다. version: 4.13 parent:Programming/Development/BuildGraph -type:Reference +type:overview tags:Programming tags:BuildGraph diff --git a/Engine/Documentation/Source/Programming/Development/BuildGraph/ScriptAnatomy/Tasks/PredefinedTasks/BuildGraphScriptPredefinedTasks.INT.udn b/Engine/Documentation/Source/Programming/Development/BuildGraph/ScriptAnatomy/Tasks/PredefinedTasks/BuildGraphScriptPredefinedTasks.INT.udn index 3c52dc7f1c6b..82f3fd734878 100644 --- a/Engine/Documentation/Source/Programming/Development/BuildGraph/ScriptAnatomy/Tasks/PredefinedTasks/BuildGraphScriptPredefinedTasks.INT.udn +++ b/Engine/Documentation/Source/Programming/Development/BuildGraph/ScriptAnatomy/Tasks/PredefinedTasks/BuildGraphScriptPredefinedTasks.INT.udn @@ -44,14 +44,16 @@ Spawns the editor to run a commandlet. Compiles a target with UnrealBuildTool. -| | | | | -| ------------- | ------------------------- | -------- | --------------------------------------------------------------------------------- | -| Target | String | Required | The target to compile | -| Configuration | UnrealTargetConfiguration | Required | The configuration to compile | -| Platform | UnrealTargetPlatform | Required | The platform to compile for | -| Arguments | String | Optional | Additional arguments for UnrealBuildTool | -| Tag | Tag List | Optional | Tag to be applied to build products of this task | -| If | Condition | Optional | Whether to execute this task. It is ignored if this condition evaluates to false. | +| | | | | +| --------------------- | ------------------------- | -------- | --------------------------------------------------------------------------------- | +| Target | String | Required | The target to compile | +| Configuration | UnrealTargetConfiguration | Required | The configuration to compile | +| Platform | UnrealTargetPlatform | Required | The platform to compile for | +| Arguments | String | Optional | Additional arguments for UnrealBuildTool | +| AllowXGE | Boolean | Optional | Whether to allow using XGE for compilation | +| AllowParallelExecutor | Boolean | Optional | Whether to allow using the parallel executor for this compile | +| Tag | Tag List | Optional | Tag to be applied to build products of this task | +| If | Condition | Optional | Whether to execute this task. It is ignored if this condition evaluates to false. | ### Cook diff --git a/Engine/Documentation/Source/Programming/Development/BuildGraph/ScriptAnatomy/Tasks/PredefinedTasks/BuildGraphScriptPredefinedTasks.JPN.udn b/Engine/Documentation/Source/Programming/Development/BuildGraph/ScriptAnatomy/Tasks/PredefinedTasks/BuildGraphScriptPredefinedTasks.JPN.udn index ed3ace47b407..88b85526a99d 100644 --- a/Engine/Documentation/Source/Programming/Development/BuildGraph/ScriptAnatomy/Tasks/PredefinedTasks/BuildGraphScriptPredefinedTasks.JPN.udn +++ b/Engine/Documentation/Source/Programming/Development/BuildGraph/ScriptAnatomy/Tasks/PredefinedTasks/BuildGraphScriptPredefinedTasks.JPN.udn @@ -1,12 +1,24 @@ -INTSourceChangelist:3090650 +INTSourceChangelist:3372845 Availability:NoPublish Title:BuildGraph の定義済みタスク -Crumbs: %ROOT%, Programming, Programming/Development, Programming/Development/BuildGraph, Programming/Development/BuildGraph/ScriptAnatomy, Programming/Development/BuildGraph/ScriptAnatomy/Tasks +Crumbs: %ROOT%, Programming, Programming/Development, Programming/Development/BuildGraph, Programming/Development/BuildGraph/BuildGraphScriptTasks Description:これはプロシージャルに生成されるマークダウン ページです。 -version:4.13 -parent:Programming/Development/BuildGraph/ScriptAnatomy/Tasks +version:4.16 +parent:Programming/Development/BuildGraph/BuildGraphScriptTasks -### Command +### AgeStore + +ファイル一式からシンボルを削除するタスクです。このタスクはマイクロソフトのデバッガ ツール SDK に同梱される AGESTORE ユーティリティから名付けられましたが、実際には別個の実装です。主な違いは、どのファイルを削除するかを判断する際に、最終アクセス時間ではなく、最後に修正された時間を使用する点です。 + +| | | | | +| -------- | -------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Platform | UnrealTargetPlatform | Required | シンボルを処理する対象プラットフォーム | +| StoreDir | String | Required | シンボル サーバー ディレクトリ | +| Days | Int32 | Required | シンボルを維持する日数 | +| Filter | String | Optional | シンボルを削除する前にディレクトリ ファイル名でマッチさせるサブストリングこれにより、複数のビルドが同じシンボル サーバーを共有している場合に、"age store" タスクが他のビルドからシンボルを削除するのを防ぎます。具体的なフィルタ値の使用は、プラットフォームのツールチェーンで定義されるシンボル サーバーの構造で決まります。 +| If | Condition | Optional | このタスクを実行するか否かです。この条件式が、 false になると無視されます。 | + +### コマンド 与えられたコマンドを実行するために AutomationTool の子プロセスを呼び出します。 @@ -14,10 +26,10 @@ parent:Programming/Development/BuildGraph/ScriptAnatomy/Tasks | ------------------------ | --------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Name | String | Required | 実行するコマンド名 | | Arguments | String | Optional | コマンドに渡す引数 | -| MergeTelemetryWithPrefix | String | Optional | non-null の場合、コマンドからテレメトリーにこの UAT インスタンスのテレメトリーに与えられたプリフィックスを付けてマージするように指示します。空 (non-null) の文字列になる場合があります。 | +| MergeTelemetryWithPrefix | String | Optional | non-null の場合、コマンドからのテレメトリーにこの UAT インスタンスのテレメトリーに与えられたプリフィックスを付けてマージするように指示します。空 (non-null) の文字列になる場合があります。 | | If | Condition | Optional | このタスクを実行するか否かです。この条件式が、 false になると無視されます。 | -### コマンドレット +### Commandlet コマンドレットを実行するエディタをスポーンします。 @@ -29,7 +41,7 @@ parent:Programming/Development/BuildGraph/ScriptAnatomy/Tasks | EditorExe | File Name | Optional | 使用するエディタの実行ファイル。現在のプラットフォームに対してデフォルトで development UE4Editor の実行ファイルになります。 | If | Condition | Optional | このタスクを実行するか否かです。この条件式が、 false になると無視されます。 | -### コンパイル +### Compile UnrealBuildTool でターゲットをコンパイルします。 @@ -42,7 +54,7 @@ UnrealBuildTool でターゲットをコンパイルします。 | Tag | Tag List | Optional | タスクのビルド生成物に適用するタグ | | If | Condition | Optional | このタスクを実行するか否かです。この条件式が、 false になると無視されます。 | -### クック +### Cook 特定のプラットフォームに対してマップの集まりをクックします。 @@ -53,35 +65,35 @@ UnrealBuildTool でターゲットをコンパイルします。 | Maps | String | Optional | クックするマップのリスト。 '+' 文字で区切られます。 | | Versioned | Boolean | Optional | クッカーに渡す追加の引数 | | Arguments | String | Optional | クッカーに渡す追加の引数 | -| Tag | Tag List | Optional | このタスクのビルド生成物に適用されるタグ | +| Tag | Tag List | Optional | タスクのビルド生成物に適用するタグ | | If | Condition | Optional | このタスクを実行するか否かです。この条件式が、 false になると無視されます。 | -### コピー +### Copy あるディレクトリから別のディレクトリにファイルをコピーします。 -| | | | | -| ------- | -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | -| Files | File Spec | Required | セミコロンで区切られるファイル明細のリスト (例、 *.cpp;Engine/.../*.bat) またはタグセットの名前です。相対パスは、 FromDir に基づきます。 -| FromDir | Directory Name | Required | コピー元のベース ディレクトリ | -| ToDir | Directory Name | Required | コピー先のディレクトリ | -| Tag | Tag List | Optional | タスクのビルド生成物に適用するタグ | -| If | Condition | Optional | このタスクを実行するか否かです。この条件式が、 false になると無視されます。 | +| | | | | +| ----- | --------- | -------- | --------------------------------------------------------------------------------- | +| Files | File Spec | Optional | 入力ファイルのリストに適用されるフィルタです。オプションです。 | +| From | File Spec | Required | コピー元のパターン (例、 Engine/*.txt) | +| To | File Spec | Required | ディレクトリまたはコピー先 | +| Tag | Tag List | Optional | タスクのビルド生成物に適用するタグ | +| If | Condition | Optional | このタスクを実行するか否かです。この条件式が、 false になると無視されます。 | ### CsCompile C# のプロジェクト ファイルやその依存関係をコンパイルします。 -| | | | | -| ------------- | --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | -| Project | String | Required | コンパイルする C# のプロジェクト ファイル。セミコロンで区切ることで複数のプロジェクト ファイルを指定することができます。 | -| Configuration | String | Optional | コンパイルするコンフィギュレーション | -| Platform | String | Optional | コンパイルするプラットフォーム | -| Arguments | String | Optional | コンパイラに渡す追加のオプション | -| EnumerateOnly | Boolean | Optional | ビルドの生成物を列挙するだけで、実際にはプロジェクトをコンパイルしません。 | -| Tag | Tag List | Optional | タスクのビルド生成物に適用するタグ | -| TagReferences | Tag List | Optional | プロジェクトが持つ非 private の参照に適用されるタグ (すなわち、external だが、output dir にはコピーされないもの) | -| If | Condition | Optional | このタスクを実行するか否かです。この条件式が、 false になると無視されます。 | +| | | | | +| ------------- | --------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| Project | String | Required | コンパイルする C# のプロジェクト ファイル。セミコロンで区切ることで複数のプロジェクト ファイルを指定することができます。 | +| Configuration | String | Optional | コンパイルするコンフィギュレーション | +| Platform | String | Optional | コンパイルするプラットフォーム | +| Arguments | String | Optional | コンパイラに渡す追加のオプション | +| EnumerateOnly | Boolean | Optional | ビルドの生成物を列挙するだけで、実際にはプロジェクトをコンパイルしません。 | +| Tag | Tag List | Optional | タスクのビルド生成物に適用するタグ | +| TagReferences | Tag List | Optional | プロジェクトが持つ非 private の参照に適用されるタグ (すなわち、external だが、output dir にはコピーされないもの) | +| If | Condition | Optional | このタスクを実行するか否かです。この条件式が、 false になると無視されます。 | ### Delete @@ -89,7 +101,7 @@ C# のプロジェクト ファイルやその依存関係をコンパイルし | | | | | | ---------------------- | --------- | -------- | ---------------------------------------------------------------------------------------------------------- | -| Files | File Spec | Required | セミコロンで区切られるファイルの明細のリスト (例、 *.cpp;Engine/.../*.bat) またはタグセットの名前です。 | +| Files | File Spec | Required | セミコロンで区切られるファイル明細のリスト (例 *.cpp;Engine/.../*.bat) またはタグセットの名前です。 | | DeleteEmptyDirectories | Boolean | Optional | ファイル削除後に空のディレクトリを削除するか否かです。デフォルトで true になります。 | | If | Condition | Optional | このタスクを実行するか否かです。この条件式が、 false になると無視されます。 | @@ -104,6 +116,18 @@ C# のプロジェクト ファイルやその依存関係をコンパイルし | IncludeContents | Boolean | Optional | 指定すると、指定したファイルのコンテンツを出力します。 | | If | Condition | Optional | このタスクを実行するか否かです。この条件式が、 false になると無視されます。 | +### Move + +あるディレクトリから別のディレクトリにファイルを移動します。 + +| | | | | +| ----- | --------- | -------- | --------------------------------------------------------------------------------- | +| Files | File Spec | Optional | 入力ファイルのリストに適用されるフィルタです。オプションです。 | +| From | File Spec | Required | コピー元のパターン (例、 Engine/*.txt) | +| To | File Spec | Required | ディレクトリまたはコピー先 | +| Tag | Tag List | Optional | タスクのビルド生成物に適用するタグ | +| If | Condition | Optional | このタスクを実行するか否かです。この条件式が、 false になると無視されます。 | + ### PakFile 任意のファイル一式から PAK ファイルを作成します。 @@ -118,8 +142,8 @@ C# のプロジェクト ファイルやその依存関係をコンパイルし | Sign | String | Optional | pak ファイルの暗号キー | | Compress | Boolean | Optional | ファイルを圧縮するか否か | | Arguments | String | Optional | UnrealPak に渡す追加の引数 | -| Tag | Tag List | Optional | タスクのビルド生成物に適用するタグ | -| If | Condition | Optional | このタスクを実行するか否かです。この条件式が、 false になると無視されます。 | +| Tag | Tag List | Optional | タスクのビルド生成物に適用するタグ | +| If | Condition | Optional | このタスクを実行するか否かです。この条件式が、 false になると無視されます。 | ### Rename @@ -144,6 +168,7 @@ C# のプロジェクト ファイルやその依存関係をコンパイルし | Branch | String | Required | ブランチの文字列 | | Build | String | Optional | ビルド バージョンの文字列 | | Licensee | Boolean | Optional | IS_LICENSEE_VERSION フラグを true に設定するか否か。 | +| Promoted | Boolean | Optional | ENGINE_IS_PROMOTED_BUILD フラグを true に設定するか否か。 | | SkipWrite | Boolean | Optional | 設定されると、実際にはファイルに書き込まず、更新されるバージョン ファイルを戻します。ローカルのビルドに役立ちます。 | | Tag | Tag List | Optional | タスクのビルド生成物に適用するタグ | | If | Condition | Optional | このタスクを実行するか否かです。この条件式が、 false になると無視されます。 | @@ -155,7 +180,7 @@ C# のプロジェクト ファイルやその依存関係をコンパイルし | | | | | | ----- | --------- | -------- | ---------------------------------------------------------------------------------------------------------- | | Files | File Spec | Required | セミコロンで区切られるファイル明細のリスト (例 *.cpp;Engine/.../*.bat) またはタグセットの名前です。 | -| Tag | Tag List | Optional | タスクのビルド生成物に適用するタグ | +| Tag | Tag List | Optional | タスクのビルド生成物に適用するタグ | | If | Condition | Optional | このタスクを実行するか否かです。この条件式が、 false になると無視されます。 | ### Spawn @@ -194,7 +219,7 @@ C# のプロジェクト ファイルやその依存関係をコンパイルし | Platform | UnrealTargetPlatform | Required | バイナリをストリップするプラットフォームのツールチェーン | | BaseDir | Directory Name | Optional | ファイルを探すディレクトリ | | Files | File Spec | Required | セミコロンで区切られるファイルの明細のリスト (例、 Engine/.../*.pdb) またはタグセットの名前です。 | -| OutputDir | Directory Name | Required | ストリップされたファイルの出力ディレクトリ。デフォルトは入力パス (入力ファイルを上書き) | +| OutputDir | Directory Name | Optional | ストリップされたファイルの出力ディレクトリ。デフォルトは入力パス (入力ファイルを上書き) | | Tag | Tag List | Optional | タスクのビルド生成物に適用するタグ | | If | Condition | Optional | このタスクを実行するか否かです。この条件式が、 false になると無視されます。 | @@ -202,19 +227,32 @@ C# のプロジェクト ファイルやその依存関係をコンパイルし 新規チェンジリストを作成し、ファイル一式を Perforce ストリームにサブミットします。 -| | | | | -| ----------- | -------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Description | String | Required | サブミットされたチェンジリストの説明 | -| Files | File Spec | Required | サブミットするファイル | -| FileType | String | Optional | サブミットしたファイルに対する Perforce のファイルの種類 (例 binary+FS32) | -| Workspace | String | Optional | ワークスペース名。指定するとファイルをサブミットする任意のストリームおよびルート ディレクトリを使って新しいワークスペースが作成されます。そうでなければ、現在のワークスペースが使用されます。 | -| Stream | String | Optional | ワークスペースのストリームであり、デフォルトで現在のストリームになります。ワークスペースの属性も指定されない限り、無視されます。 | -| RootDir | Directory Name | Optional | ストリームのルート ディレクトリ。指定しないと、デフォルトで現在のルート ディレクトリになります。 | -| If | Condition | Optional | このタスクを実行するか否かです。この条件式が、 false になると無視されます。 | +| | | | | +| --------------- | -------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Description | String | Required | サブミットされたチェンジリストの説明 | +| Files | File Spec | Required | サブミットするファイル | +| FileType | String | Optional | サブミットしたファイルに対する Perforce のファイルの種類 (例 binary+FS32) | +| Workspace | String | Optional | ワークスペース名。指定するとファイルをサブミットする任意のストリームおよびルート ディレクトリを使って新しいワークスペースが作成されます。そうでなければ、現在のワークスペースが使用されます。 | +| Stream | String | Optional | ワークスペースのストリームであり、デフォルトで現在のストリームになります。ワークスペースの属性も指定されない限り、無視されます。 | +| RootDir | Directory Name | Optional | ストリームのルート ディレクトリ。指定しないと、デフォルトで現在のルート ディレクトリになります。 | +| RevertUnchanged | Boolean | Optional | 変更されていないファイルをサブミット前にリバートするか否かです。 | +| If | Condition | Optional | このタスクを実行するか否かです。この条件式が、 false になると無視されます。 | + +### SymStore + +ファイル一式からシンボルを削除するタスクです。 + +| | | | | +| -------- | -------------------- | -------- | --------------------------------------------------------------------------------- | +| Platform | UnrealTargetPlatform | Required | シンボル ファイルを処理するために必要なプラットフォームのチェーン | +| Files | String | Required | 出力ファイルのリスト。このリストから PDB 抽出されます。 | +| StoreDir | String | Required | 圧縮したシンボルの出力ディレクトリ。 | +| Product | String | Required | シンボル ストアを記録するための製品名 | +| If | Condition | Optional | このタスクを実行するか否かです。この条件式が、 false になると無視されます。 | ### Tag -任意のファイル一式にタグを適用します。'Files' パラメーターで与えられるタグとファイルの明細を列挙することによってファイルのリストが見つかります。このリストから、'Filter' パラメーターにマッチしないファイルがあれば取り除かれ、'Except' パラメータでマッチする任意のファイルが続きます。 +任意のファイル一式にタグを適用します。'Files' パラメーターで与えられるタグとファイルの明細を列挙することによってファイルのリストが見つかります。このリストから、'Filter' パラメータにマッチしないファイルがあれば取り除かれ、'Except' パラメータでマッチする任意のファイルが続きます。 | | | | | | ------- | -------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -232,7 +270,7 @@ C# のプロジェクト ファイルやその依存関係をコンパイルし | | | | | | ------------------------------ | -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | Files | File Spec | Required | 読み出すレシート ファイル一式 (*.target)。セミコロンで区切られたワイルドカードおよびタグ名を含みます。 | -| EngineDir | Directory Name | Optional | Engine フォルダへのパス。レシート ファイルで、$(EngineDir) プロパティを拡張するために使用します。デフォルトで現在のワークスペースの Engine ディレクトリになります。 | +| EngineDir | Directory Name | Optional | Engine フォルダへのパス。レシート ファイルで、$(EngineDir) プロパティを拡張するために使用します。デフォルトで現在のワークスペースの Engine ディレクトリになります。 | | ProjectDir | Directory Name | Optional | プロジェクト フォルダへのパス。レシート ファイルで $(ProjectDir) プロパティを展開するために使用されます。デフォルトで現在のワークスペースの Engine ディレクトリになります。 | | BuildProducts | Boolean | Optional | レシートにリスト化されているビルド生成物にタグ付けするか否か。 | | BuildProductType | String | Optional | どのタイプのビルド生成物にタグ付けするか (有効な値については、 TargetReceipt.cs - UnrealBuildTool.BuildProductType をご覧ください) | diff --git a/Engine/Documentation/Source/Programming/Development/BuildGraph/ScriptAnatomy/Tasks/PredefinedTasks/BuildGraphScriptPredefinedTasks.KOR.udn b/Engine/Documentation/Source/Programming/Development/BuildGraph/ScriptAnatomy/Tasks/PredefinedTasks/BuildGraphScriptPredefinedTasks.KOR.udn index 9f98043779ac..fbea11418dfa 100644 --- a/Engine/Documentation/Source/Programming/Development/BuildGraph/ScriptAnatomy/Tasks/PredefinedTasks/BuildGraphScriptPredefinedTasks.KOR.udn +++ b/Engine/Documentation/Source/Programming/Development/BuildGraph/ScriptAnatomy/Tasks/PredefinedTasks/BuildGraphScriptPredefinedTasks.KOR.udn @@ -1,10 +1,22 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3372845 Availability: NoPublish Title: BuildGraph 미리정의된 태스크 -Crumbs: %ROOT%, Programming, Programming/Development, Programming/Development/BuildGraph, Programming/Development/BuildGraph/ScriptAnatomy, Programming/Development/BuildGraph/ScriptAnatomy/Tasks +Crumbs: %ROOT%, Programming, Programming/Development, Programming/Development/BuildGraph, Programming/Development/BuildGraph/BuildGraphScriptTasks Description: 절차적 생성되는 마크다운 페이지입니다. -version: 4.13 -parent:Programming/Development/BuildGraph/ScriptAnatomy/Tasks +version: 4.16 +parent:Programming/Development/BuildGraph/BuildGraphScriptTasks + +### AgeStore + +파일 세트에서 심볼을 벗겨내는 태스크입니다. 이 태스크 이름은 Microsoft 디버거 툴 SDK 인 AGESTORE 유틸리티에서 따온 것이지만, 실제로는 별도 구현입니다. 주요 차이점은 삭제할 파일을 결정하는 데 마지막 접근 시간이 아닌 마지막 변경 시간을 사용한다는 점입니다. + +| | | | | +| -------- | -------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Platform | UnrealTargetPlatform | 필수 | 심볼 에이징 대상 타겟 플랫폼입니다. | +| StoreDir | String | 필수 | 심볼 서버 디렉토리입니다. | +| Days | Int32 | 필수 | 심볼을 며칠이자 유지할지 입니다. | +| Filter | String | 옵션 | 디렉토리 파일명에 이 하위 스트링이 일치하면 심볼을 지웁니다. 다수의 빌드가 같은 심볼 서버를 공유하는 상황에서 "age store" 태스크가 다른 빌드의 심볼을 지우지 못하도록 할 수 있습니다. 필터 값의 구체적인 용도는 플랫폼 툴 체인에 정의된 심볼 서버 구조체로 결정됩니다. | +| If | Condition | 옵션 | 이 태스크 실행 여부입니다. 이 조건 평가 결과 false 이면 무시됩니다. | ### Command @@ -62,18 +74,18 @@ parent:Programming/Development/BuildGraph/ScriptAnatomy/Tasks | | | | | | ------- | -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | -| Files | File Spec | 필수 | 세미콜론으로 구분되는 지정 파일 목록 (예: *.cpp;Engine/.../*.bat), 또는 태그 세트 이름입니다. 상대 경로는 기준은 FromDir 입니다. | -| FromDir | Directory Name | 필수 | 복사할 원본 디렉토리입니다. | -| ToDir | Directory Name | 필수 | 복사할 대상 디렉토리입니다. | -| Tag | Tag List | 옵션 | 이 태스크의 빌드 제품에 적용할 태그입니다. +| Files | File Spec | 옵션 | 입력 파일 목록에 적용시킬 필터입니다. 옵션입니다. | +| From | File Spec | 필수 | 복사해 올 패턴입니다. (예: Engine/*.txt) | +| To | File Spec | 필수 | 복사 대상 디렉토리입니다. | +| Tag | Tag List | 옵션 | 이 태스크의 빌드 제품에 적용할 태그입니다. | | If | Condition | 옵션 | 이 태스크 실행 여부입니다. 이 조건이 false 로 평가되는 경우 무시됩니다. | ### CsCompile C# 프로젝트 파일과 그 종속성을 컴파일합니다. -| | | | | -| ------------- | --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| | | | | +| ------------- | --------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------- | | Project | String | 필수 | 컴파일할 C# 프로젝트 파일입니다. 세미콜론으로 구분해서 프로젝트 파일을 둘 이상 지정할 수 있습니다. | | Configuration | String | 옵션 | 컴파일할 환경설정입니다. | | Platform | String | 옵션 | 컴파일할 플랫폼입니다. | @@ -104,6 +116,18 @@ C# 프로젝트 파일과 그 종속성을 컴파일합니다. | IncludeContents | Boolean | 옵션 | 지정하면 지정한 파일의 내용을 출력합니다. | | If | Condition | 옵션 | 이 태스크 실행 여부입니다. 이 조건이 false 로 평가되는 경우 무시됩니다. | +### Move + +한 디렉토리에서 다른 디렉토리로 파일을 이동합니다. + +| | | | | +| ----- | --------- | -------- | --------------------------------------------------------------------------------- | +| Files | File Spec | 옵션 | 입력 파일 목록에 적용할 필터입니다. 옵션입니다. | +| From | File Spec | 필수 | 복사해 올 패턴입니다. (예: Engine/*.txt) | +| To | File Spec | 필수 | 복사 대상 디렉토리입니다. | +| Tag | Tag List | 옵션 | 이 태스크의 빌드 제품에 적용할 태그입니다. | +| If | Condition | 옵션 | 이 태스크 실행 여부입니다. 이 조건 평가 결과 false 인 경우 무시됩니다. | + ### PakFile 지정한 파일 세트에서 PAK 파일을 생성합니다. @@ -144,6 +168,7 @@ C# 프로젝트 파일과 그 종속성을 컴파일합니다. | Branch | String | 필수 | 브랜치 문자열입니다. | | Build | String | 옵션 | 빌드 버전 문자열입니다. | | Licensee | Boolean | 옵션 | IS_LICENSEE_VERSION 플래그 true 설정 여부입니다. | +| Promoted | Boolean | 옵션 | ENGINE_IS_PROMOTED_BUILD 플래그의 true 설정 여부입니다. | | SkipWrite | Boolean | 옵션 | 설정하면 실제로 파일에 쓰지 않고, 업데이트할 버전 파일만 반환합니다. 로컬 빌드에 좋습니다. | | Tag | Tag List | 옵션 | 이 태스크의 빌드 제품에 적용할 태그입니다. | If | Condition | 옵션 | 이 태스크 실행 여부입니다. 이 조건이 false 로 평가되는 경우 무시됩니다. | @@ -194,7 +219,7 @@ C# 프로젝트 파일과 그 종속성을 컴파일합니다. | Platform | UnrealTargetPlatform | 필수 | 바이너리를 벗겨낼 플랫폼 툴체인입니다. | | BaseDir | Directory Name | 옵션 | 파일을 검색할 디렉토리입니다. | | Files | File Spec | 필수 | 세미콜론으로 구분되는 파일 지정 목록 (예: Engine/.../*.pdb), 또는 태그 세트 이름입니다. | -| OutputDir | Directory Name | 필수 | 벗겨낸 파일의 출력 디렉토리입니다. 기본값은 입력 경로입니다 (입력 파일을 덮어씁니다). | +| OutputDir | Directory Name | 옵션 | 벗겨낸 파일의 출력 디렉토리입니다. 기본값은 입력 경로입니다 (입력 파일을 덮어씁니다). | | Tag | Tag List | 옵션 | 이 태스크의 빌드 제품에 적용할 태그입니다. | If | Condition | 옵션 | 이 태스크 실행 여부입니다. 이 조건이 false 로 평가되는 경우 무시됩니다. | @@ -210,8 +235,21 @@ C# 프로젝트 파일과 그 종속성을 컴파일합니다. | Workspace | String | 옵션 | 워크스페이스 이름입니다. 지정하면 지정된 스트림과 파일을 제출한 루트 디렉토리를 사용하여 새로운 워크스페이스를 만듭니다. 지정하지 않으면, 현재 워크스페이스를 사용합니다. | | Stream | String | 옵션 | 워크스페이스의 스트림입니다. 기본값은 현재 스트림입니다. Workspace 어트리뷰트 역시 지정되지 않는 한 무시됩니다. | | RootDir | Directory Name | 옵션 | 스트림에 대한 루트 디렉토리입니다. 지정하지 않으면, 기본값은 현재 루트 디렉토리입니다. | +| RevertUnchanged | Boolean | 옵션 | submit 시도 전 변경되지 않은 파일을 revert 시킬지 여부입니다. | | If | Condition | 옵션 | 이 태스크 실행 여부입니다. 이 조건이 false 로 평가되는 경우 무시됩니다. | +### SymStore + +파일 세트에서 심볼을 벗겨내는 태스크입니다. + +| | | | | +| -------- | -------------------- | -------- | --------------------------------------------------------------------------------- | +| Platform | UnrealTargetPlatform | 필수 | 심보ㅓㄹ 파일 처리에 필요한 플랫폼 툴체인입니다. | +| Files | String | 필수 | 출력 파일 목록입니다. PDB 는 이 목록에서 추출합니다. | +| StoreDir | String | 필수 | 압축된 심볼에 대한 출력 디렉토리입니다. | +| Product | String | 필수 | 심볼 스토어 레코드에 대한 제품 이름입니다. | +| If | Condition | 옵션 | 이 태스크 실행 여부입니다. 이 조건 평가 결과 false 인 경우 무시됩니다. | + ### Tag 지정된 파일 세트에 태그를 적용합니다. 파일 목록은 태그 열거(enumerate) 및 'Files' 파라미터로 지정한 파일로 찾습니다. 이 목록에서, 'Filter' 파라미터에 일치하지 않는 파일은 제거한 뒤 'Except' 파라미터에 일치하는 것이 이어집니다. diff --git a/Engine/Documentation/Source/Programming/Development/CompilingProjects/CompilingProjects.INT.udn b/Engine/Documentation/Source/Programming/Development/CompilingProjects/CompilingProjects.INT.udn index 35f2d096b2b1..6e822edf7737 100644 --- a/Engine/Documentation/Source/Programming/Development/CompilingProjects/CompilingProjects.INT.udn +++ b/Engine/Documentation/Source/Programming/Development/CompilingProjects/CompilingProjects.INT.udn @@ -2,7 +2,10 @@ Availability:Public Title:Compiling Game Projects Crumbs: %ROOT%, Programming, Programming/Development Description:Compiling individual game projects using Visual Studio on Windows, or Xcode on Mac. -Version: 4.9 +Version: 4.16 +Parent:Programming/Development +Order: +type:overview [TOC (start:2 end:3)] @@ -80,7 +83,7 @@ has instructions for generating project files for additional platforms. ### Building the Project [REGION:note] -Please make sure you are running Visual Studio 2013 Express, Community, or Professional for Windows Desktop installed before proceeding. If you are using Mac, make sure to have Xcode 6.1 or higher installed. +Please make sure you are running Visual Studio 2015 or higher for Windows Desktop installed before proceeding. If you are using Mac, make sure to have Xcode 8 or higher installed. [/REGION] にある GenerateProjectFiles.bat ファイルを実行します。 [REGION:note] - スクリプトはどのフォルダからも実行できます。(必要に応じてデスクトップ上にショートカットを作成してください) + スクリプトはどのフォルダからも実行できます。(必要に応じてデスクトップ上にショートカットを作成してください) [/REGION] * プロジェクト ジェネレータがモジュールとビルド対象のファイルを分析し、プロジェクトファイルを新規に生成します。ファイルの生成は最長で 15 秒間ほどかかります。 -VS 開発者のために、同ディレクトリに「UE4.sln」ファイルが生成されます。UE 4 を使用したゲームやプログラムのビルドおよび実行にこのソリューションファイルを使用します。(初回コンパイルは、Win64 プラットフォームを Development コンフィギュレーションに設定したビルドを推奨しています!) +VS 開発者のために、同ディレクトリに「UE4.sln」ファイルが生成されます。UE 4 を使用したゲームやプログラムのビルドおよび実行にこのソリューションファイルを使用します。(初回コンパイルは、Win64 プラットフォームを Development コンフィギュレーションに設定したビルドを推奨しています) [REGION:note] - デフォルトで、コンソールだけでなくモバイルのプラットフォームもビルドおよびデバッグできるように、SDK が検出されたすべての利用可能なプラットフォームを対象にビルド可能なプロジェクトを生成します。実行している現在のプラットフォーム (Windows など) に対してのみプロジェクトを生成したい場合は、-CurrentPlatform 引数で GenerateProjectFiles.bat を実行します。プロジェクト ファイルは若干負荷が軽くなります。 + デフォルトで、コンソールだけでなくモバイルのプラットフォームもビルドおよびデバッグできるように、SDK が検出されたすべての利用可能なプラットフォームを対象にビルド可能なプロジェクトを生成します。実行している現在のプラットフォーム (Windows など) に対してのみプロジェクトを生成したい場合は、-CurrentPlatform 引数で GenerateProjectFiles.bat を実行します。プロジェクト ファイルの負荷が若干低減されます。 [/REGION] **重要**:ソースコントロール システムから新しいコードの変更を同期した後は必ず GenerateProjectFiles.bat ファイルを再実行してください。ファイルの実行を忘れると、コンパイル時やゲームの実行時に問題が発生する恐れがあります。 @@ -32,7 +44,7 @@ VS 用の [](Programming/Development/VisualStudioSetup/UnrealVS) にあるツー この機能へショートカットキーを割り当てることもできます。VS で [Tools] -> [Options] -> [Environment] -> [Keyboard] を開きUnrealVS.RefreshProjects を検索します。 -この機能はソリューションが読み込まれた後に有効となります (プロジェクトを生成するコードブランチをツールで理解しなくてはいけないため)。`UE4.sln` ファイルがまだ生成されていない場合、最初に `GenerateProjectFiles.bat` スクリプトを直接実行してください。 +この機能はソリューションが読み込まれた後に有効となります(プロジェクトを生成するコードブランチをツールで理解しなくてはいけないため)。`UE4.sln` ファイルがまだ生成されていない場合、最初に `GenerateProjectFiles.bat` スクリプトを直接実行してください。 ## コマンドライン オプション (上級編) @@ -42,11 +54,10 @@ VS 用の [](Programming/Development/VisualStudioSetup/UnrealVS) にあるツー | オプション | 説明 || ----------------- | ------------ | -CurrentPlatform | 検出されたすべての利用可能な対象プラットフォームではなく、現在のデスクトップ プラットフォーム (Windows または Mac) に対してのみビルド可能なプロジェクトを生成します。 | --2012 | VS 2012 のネイティブなフォーマットでプロジェクトを生成します。デフォルトで、VS 2013 ファイルを生成します。 | --2013 | VS 2013 のネイティブなフォーマットでプロジェクトを生成します。これはデフォルトです。| -2015 | VS 2015 のネイティブなフォーマットでプロジェクトを生成します。このオプションが設定されると Visual C++ 2015 コンパイラを使用してコンパイルします。 | +-2017 | VS 2017 のネイティブなフォーマットでプロジェクトを生成します。このオプションが設定されると Visual C++ 2017 コンパイラを使用してコンパイルします。 | -ThirdParty | サードパーティ ライブラリからヘッダとその他のファイルをプロジェクトに追加します。PhysX、Steamworks、Bink などに対応する Visual Assist でシンボルやファイルを見る場合に便利です。ただし、プロジェクトファイルの読み込みに時間が長くかかります! | -Game `GameName` | 指定したプロジェクト名に対するコードとコンテンツのみを含むプロジェクトの生成をプロジェクト ジェネレータに指示します。その他のプロジェクトは除外します。プロジェクト名も必ず指定してください。例えば、`GenerateProjectFiles.bat ShooterGame.uproject -Game` は ShooterGame のソースとターゲットのみを含むプロジェクトを生成します。単一のゲームプロジェクトと一緒にエンジン ソースコードとプログラムを含みたい場合、 `-Engine` パラメータを渡してください。| +Game `GameName` | 指定したプロジェクト名に対するコードとコンテンツのみを含むプロジェクトの生成をプロジェクト ジェネレータに指示します。その他のプロジェクトは除外します。プロジェクト名も必ず指定してください。例えば、「GenerateProjectFiles.bat ShooterGame.uproject -Game 」はShooterGame のソースとターゲットのみを含むプロジェクトを生成します。単一のゲームプロジェクトと一緒にエンジンソースコードとプログラムを含みたい場合、「-Engine」パラメータを渡してください。| Engine | `-Game` と併用した場合、エンジンコード、コンテンツ、そしてプログラムが生成ソリューションに一緒に含まれます。エンジン ソースコードを扱う作業がたくさんあるゲームプロジェクトの開発に便利なオプションです。 | -NoIntelliSense | オートコンプリートとエラー squiggles で使用される IntelliSense データの生成をスキップします。 -AllLanguages | すべての言語のエンジン ドキュメンテーションが含まれます。デフォルトでは、プロジェクトには英語のファイルのみが含まれます。 | @@ -55,55 +66,55 @@ Engine | `-Game` と併用した場合、エンジンコード、 -Platforms=`PlatformName`| ビルド可能なプロジェクトを生成するデフォルトのプラットフォーム セットをオーバーライドし、代わりに指定したプラットフォームに対してプロジェクトを生成します。'+' 記号で区切ることで複数のプラットフォームを指定できます。この操作によって、生成されたソリューション ファイルには指定したプラットフォーム名を含む接尾辞がついた名前も付けられます。 | -## よくある質問 (FAQ) +## よくある質問(FAQ) -### プロジェクトファイルを更新していなくても、新しく追加されたソースファイルがコンパイルされるのはなぜですか? +### プロジェクト ファイルを更新していなくても、新しく追加されたソースファイルがコンパイルされるのはなぜですか? -UE 4 のビルドシステムでは、プロジェクトファイルが実際にコードをコンパイルする必要はありません。アンリアル ビルド ツールは、モジュールと対象のビルドファイルを使用してソースファイルを常に検索します。よって、新しいソースファイルが追加されてコンパイルが開始すると、プロジェクトファイルが再読み込みされていなくてもソースファイルがビルドに含まれます。覚えておいてください。 +UE 4 のビルド システムでは、プロジェクト ファイルが実際にコードをコンパイルする必要はありません。アンリアル ビルド ツールは、モジュールと対象のビルド ファイルを使用してソース ファイルを常に検索します。よって、新しいソースファイルが追加されてコンパイルが開始すると、プロジェクト ファイルが再読み込みされていなくてもソース ファイルがビルドに含まれます。覚えておいてください。 ### 実際のプロジェクトはどこに保存されるのですか? -VS プロジェクトの場合、生成ソリューションは UE4.sln として UE4 のルートディレクトリに保存されます。ただし、プロジェクト ファイルは「/UE4/Engine/Intermediate/ProjectFiles/」ディレクトリに保存されます。これらのファイルの削除やプロジェクトを再生成は好きな時に行えます。ただし、ファイルの削除時にコマンドライン引数などプロジェクト固有の設定が消去されます。 +VS プロジェクトの場合、生成ソリューションは UE4.sln として UE4 のルート ディレクトリに保存されます。ただし、プロジェクト ファイルは「/UE4/Engine/Intermediate/ProjectFiles/」ディレクトリに保存されます。これらのファイルは、削除やプロジェクト再生成を好きな時に行えます。ただし、ファイルの削除時にコマンドライン引数などプロジェクト固有の設定が消去されます。 ### プロジェクトファイルを生成するメリットはなんですか? -メリット、デメリットは確実に両方ありますが、UE4 でプロジェクトファイルを生成する決断に至った主な理由はいくつかあります。 +もちろんデメリットもありますが、プロジェクト ファイル生成に UE4 を選んだ主な理由は以下の通りです。 -* UE 4 はマルチプラットフォームに対応していますが、あるチームは常に特定のプラットフォームのみで開発を行っています。プロジェクトファイルを生成することにより、関連のないプラットフォーム固有のファイルやビルドコンフィギュレーションを省略することができます。 +* UE 4 はマルチプラットフォーム対応なので、あるチームを特定のプラットフォーム専用の開発に割り当てることができます。プロジェクト ファイルを生成すれば、プラットフォーム固のファイルや関係のないビルド コンフィギュレーションを省略することができます。 -*UE4 のプログラミング手法はたくさんのサブモジュールを使用しているので、プログラマーが新たにモジュールを追加する作業を可能な限り容易にすることはとても重要でした。 +* UE4 は幅広いサブモジュールを使用したプログラミング手法です。これは、プログラマーのモジュール新規追加作業をできるだけ簡素化する上でとても重要です。 -* プロジェクト ジェネレータは、正確性の高い定義を排出し、ユーザーが UE4 コードの作業中に Visual Studio IntelliSense が使用するパスを含みます。 +* プロジェクト ジェネレータは、正確性の高い定義を排出し、UE4 コード作業中に Visual Studio IntelliSense が使用するパスを含みます。 -* プロジェクトファイルの自動生成時に新プロジェクトの設定がより簡単になります。 +* プロジェクトファイルの自動生成時に新プロジェクトの設定が非常に簡単です。 -* 当社はマルチプラットフォームと開発環境のサポートを目指しています (例えば VS や Xcode など)。手作業で複数のプロジェクトファイルを維持することはエラーを誘発する上に、単調でつまらない作業です。 +* マルチプラットフォームと開発環境のサポートしています (例えば VS や Xcode など)。手書きコードで複数のプロジェクトファイルを維持しようとすると、エラーを誘発する上に単調でつまらないです。 -* よって、プログラマーが大々的にカスタマイズ可能なプロジェクトファイルを生成したいと考えました。プロジェクトファイルの生成は、将来的により重要となってくると考えています。 +* プログラマーが大々的にカスタマイズ可能なプロジェクトファイルを生成したいと考えました。プロジェクトファイルの生成は、将来的により重要となってくると考えています。 -* ソースファイルのディレクトリ構造は、プロジェクトファイル ソリューションの階層に自動的に反映されます。ソースファイルのブラウズが大変便利になりますが、手作業で作成するプロジェクトの維持はとても困難です。 +* ソースファイルのディレクトリ構造は、プロジェクト ファイル ソリューションの階層に自動反映されます。ソース ファイルのブラウズが大変便利になりますが、手書きコードで作成したプロジェクトの維持はとても困難です。 -* アンリアルエンジンのビルドコンフィギュレーションは非常に複雑で、手作業による維持は困難です。プロジェクトジェネレータは、透明性を持つビルドコンフィギュレーションを開発者に提供します。 +* アンリアル エンジンのビルド コンフィギュレーションは非常に複雑で、手書きコードによる維持は困難です。プロジェクト ジェネレータは、透明性を持つビルド コンフィギュレーションを開発者に提供します。 ### プロジェクトには他にどんなファイルが含まれますか? -C++ モジュールのソースコードと一緒に、生成されるプロジェクトにはその他のファイルが自動的に追加されます。これらのファイルの簡単な検索が目的です。以下は生成プロジェクトへ自動的に追加されるファイルをいくつか挙げた例です。 +C++ モジュールのソースコードと一緒に、生成されるプロジェクトにはその他のファイルが自動的に追加されます。これらのファイルの簡単な検索が目的です。以下は、生成プロジェクトへ自動追加されるファイルの例です。 -* シェーダーソースコード (*.usf ファイル) +* シェーダー ソースコード (*.usf ファイル) * エンジン ドキュメンテーション ファイル (*.udn ファイル) * プログラム コンフィギュレーション ファイル (*.ini ファイル) -* ローカライゼーションファイル (*.int ファイル) +* ローカライゼーション ファイル (*.int ファイル) * プログラム リソース ファイルとマニフェスト (*.rc、*.manifest) -* 特定の外部 (非生成) プロジェクトファイル (例えば UnrealbuildTool や Clean) +* 特定の外部 (非生成) プロジェクト ファイル (例えば UnrealbuildTool や Clean) ### ソース コントロールにプロジェクト ファイルがチェックインされないのはなぜですか? -ソース コントロールのマージは、プロジェクト ファイルとのコンフリクトが生じ、面倒な作業であるうえ大変間違いが起こりやすい作業です。新しいシステムは、プロジェクトファイルを純粋な中間ファイルとして捉えるためこの作業を完全に回避することができます。加えて、異なるゲームプロジェクトに従事している各チームはそれぞれのソリューション ファイルが必要です。エピックで使用するプロジェクトファイルに修正を加えない限り、他のチームには実用性がないファイルとなる可能性が高くなります。 +ソース コントロールのマージは、プロジェクト ファイルとのコンフリクトが生じ、面倒な上、大変間違いが起こりやすい作業です。新しいシステムは、プロジェクトファイルを純粋な中間ファイルとして捉えるためこの作業を完全に回避することができます。加えて、異なるゲームプロジェクトに従事している各チームはそれぞれのソリューション ファイルが必要です。エピックで使用するプロジェクトファイルに修正を加えない限り、他のチームには実用性がないファイルとなる可能性が高くなります。 ### `GenerateProjectFiles.bat` は実際に何を実行するのですか? @@ -119,11 +130,11 @@ C++ モジュールのソースコードと一緒に、生成されるプロジ * 法線ごとにコンパイルおよびデバッグ作業を行います。 -VS で使用しているプロジェクト ファイルの作業中に、ファイルがプロジェクト ジェネレータによって上書きされる恐れがあります。 このため通常の UE4 ソリューションファイルでデバッグ作業をする代わりに、VS へ UnrealBuildTool プロジェクトを直接読み込むと便利な場合もあります。 +VS で使用しているプロジェクト ファイルの作業中に、ファイルがプロジェクト ジェネレータによって上書きされる恐れがあります。このため通常の UE4 ソリューションファイルでデバッグ作業をする代わりに、VS へ UnrealBuildTool プロジェクトを直接読み込むと便利な場合もあります。 -### 複数のコンフィギュレーションの一斉ビルドはをどうやってできますか? +### 複数のコンフィギュレーションの一括ビルドはどのようにしますか? -Visual Studio の Batch Build 機能を使用します。この機能は [Build] メニューにあります。コンパイル作業を行う全てのコンフィギュレーションを選択してビルドをクリックします。将来的により簡単な作業を可能とするインターフェースの作成に取り組んでいます。 +Visual Studio の Batch Build 機能を使用します。この機能は [Build] メニューにあります。コンパイル作業を行うすべてのコンフィギュレーションを選択してビルドをクリックします。今後さらに作業が簡単になるようなインターフェースの作成に取り組んでいます。 diff --git a/Engine/Documentation/Source/Programming/UnrealBuildSystem/ProjectFileGenerator/ProjectFileGenerator.KOR.udn b/Engine/Documentation/Source/Programming/UnrealBuildSystem/ProjectFileGenerator/ProjectFileGenerator.KOR.udn index 509d9e1d9501..fe300b0e948c 100644 --- a/Engine/Documentation/Source/Programming/UnrealBuildSystem/ProjectFileGenerator/ProjectFileGenerator.KOR.udn +++ b/Engine/Documentation/Source/Programming/UnrealBuildSystem/ProjectFileGenerator/ProjectFileGenerator.KOR.udn @@ -1,10 +1,11 @@ -INTSourceChangelist:3355414 +INTSourceChangelist:3426963 Availability:Public Title:자동 프로젝트 파일 생성 -Crumbs: +Crumbs:%ROOT% Parent:Programming/UnrealBuildSystem +Order: Description:현재 워크스페이스에서 게임과 모듈에 쓸 프로젝트 파일을 자동으로 생성하는 프로세스입니다. -Version: 4.9 +Version: 4.16 prereq:Programming/Development/BuildingUnrealEngine topic-image:topic_prjFileGen.png tags:Programming @@ -53,9 +54,8 @@ Visual Studio 용 [](Programming/Development/VisualStudioSetup/UnrealVS) 에는 | 옵션 | 설명 || ---- | ---- | -CurrentPlatform | 감지된 타겟 플랫폼 전부가 아닌, 현재 데스크탑 플랫폼용 프로젝트만 생성합니다 (윈도우 또는 맥). | --2012 | Visual Studio 2012 네이티브 포맷으로 프로젝트를 생성합니다. 기본적으로는 Visual Studio 2013 프로젝트 파일이 생성됩니다. | --2013 | Visual Studio 2013 네이티브 포맷으로 프로젝트를 생성합니다. | --2015 | Visual Studio 2015 네이티브 포맷으로 프로젝트를 생성합니다. 이 옵션 사용시 Visual C++ 2015 컴파일러가 사용됩니다. 기본값입니다. | +-2015 | Visual Studio 2015 네이티브 포맷으로 프로젝트를 생성합니다. 이 옵션 사용시 Visual C++ 2015 컴파일러가 사용됩니다. | +-2017 | VS 2017 원래 포맷으로 프로젝트를 생성합니다. 이 옵션을 설정하면 Visual C++ 2017 컴파일러를 사용합니다. | -ThirdParty | 헤더와 써드 파티 라이브러리의 파일을 프로젝트에 추가합니다. PhysX, Steamworks, Bink 등에 대한 심볼과 파일을 Visual Assist 에서 확인하고자 할 때 좋을 수 있습니다. 그러나 프로젝트 파일 로드 시간이 길어질 수 있습니다! | -Game `GameName` | 프로젝트 제너레이터에 다른 모든 프로젝트는 제외하고 지정된 프로젝트 이름에 대한 코드와 콘텐츠만 포함된 프로젝트를 생성하라 이릅니다. 프로젝트 이름도 반드시 지정하도록 하세요. 예를 들어 `GenerateProjectFiles.bat ShooterGame.uproject -Game` 이라 치면 ShooterGame 용 소스와 타겟만 들어있는 프로젝트가 생성됩니다. 하나의 게임 프로젝트와 함께 Engine 소스 코드와 프로그램을 포함시키려는 경우, `-Engine` 파라미터를 붙여도 됩니다. | -Engine | `-Game` 과 함께 사용하면 Engine 코드, 콘텐츠, 프로그램도 생성되는 솔루션에 포함시키도록 합니다. 게임 프로젝트 작업을 하면서 엔진 소스 작업도 많이 할 것 같다 싶은 경우에 좋습니다. | diff --git a/Engine/Documentation/Source/Programming/UnrealBuildSystem/TargetFiles/TargetFiles.INT.udn b/Engine/Documentation/Source/Programming/UnrealBuildSystem/TargetFiles/TargetFiles.INT.udn index 7902af54c197..b1f1290f84f4 100644 --- a/Engine/Documentation/Source/Programming/UnrealBuildSystem/TargetFiles/TargetFiles.INT.udn +++ b/Engine/Documentation/Source/Programming/UnrealBuildSystem/TargetFiles/TargetFiles.INT.udn @@ -3,6 +3,10 @@ Title: Unreal Build System Target Files Crumbs: %ROOT%, Programming, Programming\UnrealBuildSystem Description:Reference for the target files used by Unreal Build System when building targets. Version: 4.16 +Parent:Programming/UnrealBuildSystem +Order: +Type:reference +Tags:Unreal Build System [TOC (start:2 end:3)] diff --git a/Engine/Documentation/Source/Programming/UnrealBuildSystem/TargetFiles/TargetFiles.JPN.udn b/Engine/Documentation/Source/Programming/UnrealBuildSystem/TargetFiles/TargetFiles.JPN.udn index 2e260575a905..d191ae093e87 100644 --- a/Engine/Documentation/Source/Programming/UnrealBuildSystem/TargetFiles/TargetFiles.JPN.udn +++ b/Engine/Documentation/Source/Programming/UnrealBuildSystem/TargetFiles/TargetFiles.JPN.udn @@ -1,122 +1,43 @@ -INTSourceChangelist:2711147 +INTSourceChangelist:3392479 Availability:Public Title:アンリアルビルド システムのターゲット ファイル Crumbs: %ROOT%, Programming, Programming\UnrealBuildSystem -Description:モジュールをビルドする際にアンリアル ビルド システムが使用するターゲット ファイルのリファレンス -Version:4.9 +Description:ターゲットのビルド時にアンリアル ビルド システムが使用するターゲット ファイルのリファレンス +Version:4.16 +Parent:Programming/UnrealBuildSystem +Order: +Type:reference +Tags:Unreal Build System [TOC (start:2 end:3)] +### 概要 +UnrealBuildTool は、2 タイプのターゲットのビルドをサポートしています。 -アンリアル ビルド システムは、それぞれのアプリケーション UnrealBuildtool ビルドに対し **Target** ファイルを使用します。このビルドは、動的な Rules モジュールへコンパイルされます。これらのファイルは、かつては UnrealBuildTool へ直接コンパイルされた `UEBuild*.cs` ファイルを置き換えるものです。各ターゲットファイルは、UnrealBuildTool がゲームやプログラムのビルド方法の決定に使用するクラスを定義します。 + * **Game** - クック済みデータの実行を要求するスタンドアロン ゲームです。 + * **Client** - Game と同じですが、サーバー コードは含まれません。ネットワーク ゲームに役立ちます。 + * **Client** - Game と同じですが、クライアント コードは含まれません。ネットワーク ゲームのデディケイテッド サーバーに役立ちます。 + * **Editor** - アンリアル エディタを拡張するターゲットです。 + * **Program** - アンリアル エンジンに加えてビルドされているスタンドアロン ユーティリティ プログラムです。 -現在の UnrealBuildTool は、 RulesModule.dll ファイルからビルドされるプロジェクトの適切なターゲットファイルを読み出します。 +ターゲットは、.target.cs 拡張子のついた C# ソース ファイルで宣言され、プロジェクトの *Source* ディレクトリに格納されます。それぞれの .target.cs ファイルは、TargetRules 基本クラスから派生したクラスを宣言し、コンストラクタからのビルド方法を調節するプロパティを設定します。ターゲットをビルドするように指示すると、UnrealBuildTool は target.cs ファイルをコンパイルし、その設定を定義するために中にクラスを構築します。 -2 タイプのターゲットファイルがあります。 +クラス名は、'Target' の前に宣言されたファイル名 と一致しなければなりません (MyProject.target.cs であれば、クラス 'MyProjectTarget' を定義します)。 -* **Game** - 共通の UE4 実行ファイルを利用するターゲットファイルです。 -* **Program** - スタンドアローン実行ファイルのターゲットです。ShaderCompileWorker、SlateViewer、UnrealHeaderTool はこのターゲットタイプです。 +以下が、代表的な target.cs ファイルの構造体です。 + using UnrealBuildTool; + using System.Collections.Generic; -## ターゲットファイルの命名と保存場所 - -ターゲットファイルはプログラムのルート ディレクトリ、またはゲームの「Source」ディレクトリに格納する必要があり、[APPNAME].Target.cs の命名規則を使用しなくてはいけません。 - -例として、\UE4\Engine\Source\Programs\ShaderCompileWorker の「ShaderCompileWorker プログラム」ディレクトリには「ShaderCompileWorker.Target.cs」ファイルが格納されます。 - -同様に、ExampleGame の「Source」ディレクトリは UE4\ExampleGame|Source に位置し、「ExampleGame.Target.cs」ファイルを格納します。 - -## ターゲットファイルのコンテンツ - -各ゲームやプログラムのターゲットファイルで定義されるクラスは、TargetRules (「RulesCompiler.cs」にあります) から派生します。 - -クラス名は、ターゲットの前にツール名やゲーム名、その後にターゲットとなります。例えば、 ShaderCompileWorker ツールのターゲット ファイルで定義されるクラスは、「ShaderCompileWorkerTarget」と命名します。最後に必ず Target を入れてください。既存の *.Build.cs モジュールのルールクラスは全て同一クラスにコンパイルされるため、このクラスとの衝突を避けるために追加します。 - -UnrealBuildTool は、Rules DLL からビルドターゲットの要求時に [APPNAME] を受け取り Target を付け足します。 上記の例に沿って UnrealBuildTool が ShaderCompileWorker Win64 Development を渡すと、 TargetRules クラス名として ShaderCompileWorkerTarget を要求します。 - -### コンストラクタ - -コンストラクタはアプリケーション名と生成するターゲットタイプを設定します。以下は比較のための ExampleGameTarget のコンストラクタです。 - - public ExampleGameTarget(TargetInfo Target) - { - Type = TargetType.Game; - Name = "ExampleGame"; - } - -### バイナリ設定 - -**TargetRules::SetupBinaries()** は UEBuildBinaryConfiguration インスタンスのリストの生成に使用します。このインスタンスは UnrealBuildTool が AppBinaries 配列を埋める際に使用します。 - -### グローバル環境の設定 - -**TargetRules::SetupGlobalEnvironment()** は、UnrealBuildTool のターゲットのさまざまなコンフィギュレーション設定に加え、グローバルな Compile および Link 環境の設定に使用します。 - -[REGION:note] -UEBuildGame クラスがデフォルトでこれらのニーズをカバーするため、現在のゲームには含まれません。ゲームによってこの設定を無効にする必要がある場合、問題なく対応が可能です。 -[/REGION] - -## ターゲットファイルの例 - -以下は「ShaderCompileWorker.Target.cs」ファイルの完全実例です。 - - // Copyright 1998-2017 Epic Games, Inc.All rights reserved. - - using UnrealBuildTool; - using System.Collections.Generic; - - public class ShaderCompileWorkerTarget :TargetRules - { - public ShaderCompileWorkerTarget(TargetInfo Target) - { - Type = TargetType.Program; - Name = "ShaderCompileWorker"; - } - - // - // TargetRules interface. - // - - public override void SetupBinaries( - TargetInfo Target, - ref List OutBuildBinaryConfigurations, - ref List OutExtraModuleNames - ) - { - List LinkModules = new List() { "Core", "ShaderCore", "RenderCore", "RHI", "WindowsTools", "ShaderCompileWorker" }; - OutBuildBinaryConfigurations.Add( - new UEBuildBinaryConfiguration( InType:UEBuildBinaryType.Executable, - InModuleNames:LinkModules ) - ); - } - - public override void SetupGlobalEnvironment( - TargetInfo Target, - ref LinkEnvironmentConfiguration OutLinkEnvironmentConfiguration, - ref CPPEnvironmentConfiguration OutCPPEnvironmentConfiguration - ) - { - // Turn off various third party features we don't need (必要のない各種第三者機能をオフにします) - UEBuildConfiguration.bAllowSteamworks = false; - UEBuildConfiguration.bAllowLive = false; - UEBuildConfiguration.bCompilePerforce = false; - - // Currently we force Lean and Mean mode (現在、Lean モードと Mean モードを強制します) - UEBuildConfiguration.bCompileLeanAndMeanUE = true; - - // Currently this app is not linking against the engine, so we'll compile out references from Core to the rest of the engine (現在、この app はエンジンにリンクしていません。従って、リファレンスを Core からエンジンの残りの部分にコンパイルしていきます) - UEBuildConfiguration.bCompileAgainstEngine = false; - - // ShaderCompileWorker はコンソール アプリケーションです。Windows アプリケーションではありません (エントリーポイントは WinMain() ではなく main() に設定してください ) - OutLinkEnvironmentConfiguration.bIsBuildingConsoleApplication = true; - - // Disable logging, as the workers are spawned often and logging will just slow them down (ワーカーはたびたびスポーンされますが、ロギングが遅れの原因になるので、ロギングは無効にしてください) - OutCPPEnvironmentConfiguration.Definitions.Add("ALLOW_LOG_FILE=0"); - OutCPPEnvironmentConfiguration.Definitions.Add("HACK_HEADER_GENERATOR=1"); - OutCPPEnvironmentConfiguration.Definitions.Add("HACK_SHADER_COMPILER_WORKER=1"); - } - } - + public class MyProjectTarget :TargetRules + { + public MyProjectTarget(TargetInfo Target) : base(Target) + { + Type = TargetType.Game; + // Other properties go here (その他のプロパティはここにくる) + } + } +[INCLUDE:Programming/UnrealBuildSystem/TargetFiles/TargetFilesProperties] diff --git a/Engine/Documentation/Source/Programming/UnrealBuildSystem/TargetFiles/TargetFiles.KOR.udn b/Engine/Documentation/Source/Programming/UnrealBuildSystem/TargetFiles/TargetFiles.KOR.udn index 49ac6f3ae986..161ab070fd6e 100644 --- a/Engine/Documentation/Source/Programming/UnrealBuildSystem/TargetFiles/TargetFiles.KOR.udn +++ b/Engine/Documentation/Source/Programming/UnrealBuildSystem/TargetFiles/TargetFiles.KOR.udn @@ -1,125 +1,43 @@ -INTSourceChangelist:3356804 +INTSourceChangelist:3392479 Availability:Public Title: 언리얼 빌드 시스템 타겟 파일 -Crumbs: -Description:모듈을 빌드할 때 언리얼 빌드 시스템에 사용되는 타겟 파일에 대한 참고서입니다. -Version: 4.9 -parent:Programming/UnrealBuildSystem -topic-image:topic_targets.png -tags:Programming -tags:Unreal Build System -type:reference +Crumbs: %ROOT%, Programming, Programming\UnrealBuildSystem +Description:타겟 빌드 시 언리얼 빌드 시스템에 사용되는 타겟 파일 참고서입니다. +Version: 4.16 +Parent:Programming/UnrealBuildSystem +Order: +Type:reference +Tags:Unreal Build System [TOC (start:2 end:3)] -언리얼 빌드 시스템은, UnrealBuildTool 이 빌드하여 동적인 Rules 모듈에 컴파일되는 각 어플리케이션에 대해 **타겟** (Target) 파일을 사용합니다. 이 파일은 원래 UnrealBuildTool 에 직접 컴파일되었던 `UEBuild*.cs` 파일을 대신합니다. 각 타겟 파일이 정의하는 클래스를 UnrealBuildTool 이 사용하여, 게임이나 프로그램 빌드 방식을 결정합니다. +### 개요 -UnrealBuildTool 은 이제 RulesModule.dll 을 통해 빌드중인 프로젝트에 대한 타겟을 제대로 구해옵니다. +UnrealBuildTool 은 여러가지 타겟 유형 빌드를 지원합니다: -타겟의 종류는 두 가지입니다: + * **Game** - 실행에 쿠킹 데이터를 요하는 독립형 게임입니다. + * **Client** - Game 과 같지만, 서버 코드를 포함하지 않습니다. 네트워크 게임에 유용합니다. + * **Server** - Game 과 같지만, 클라이언트 코드를 포함하지 않습니다. 네트워크 게임의 데디케이티드 서버에 좋습니다. + * **Editor** - 언리얼 에디터를 확장하는 타겟입니다. + * **Program** - 언리얼 엔진 기반 위에 빌드된 독립형 유틸리티 프로그램입니다. -* **Game** - '공유' UE4 실행파일을 활용하는 타겟입니다. -* **Program** - 독립형 실행파일 타겟입니다. ShaderCompileWorker, SlateViewer, UnrealHeaderTool 등이 이런 종류의 타겟입니다. +타겟은 .target.cs 확장자로 된 C# 소스 파일로 선언되며, 프로젝트의 *Source* 디렉토리 안에 저장됩니다. 각 .target.cs 파일은 TargetRules 베이스 클래스에서 파생되는 클래스를 선언하며, 생성자에서 어떻게 빌드할지를 조절하는 프로퍼티를 설정합니다. 타겟 빌드 요청을 받으면, UnrealBuildTool 은 target.cs 파일을 컴파일하고 그 안에 세팅 결정을 위한 클래스를 생성합니다. +클래스 이름은 'Target' 뒤에 나오는 그것이 선언된 파일 이름과 일치해야 합니다 (예를 들어 MyProject.target.cs 는 'MyProjectTarget' 클래스를 정의합니다). -## 타겟 파일 작명규칙과 위치 +타겟 파일의 전형적인 구조체는 다음과 같습니다. -타겟 파일은 반드시 프로그램의 루트 디렉토리나 게임의 `Source` 디렉토리에 있어야 하며, 작명규칙은 이렇습니다: `[APPNAME].Target.cs` - -예를 들어 ShaderCompileWorker 프로그램 디렉토리는 `\UE4\Engine\Source\Programs\ShaderCompileWorker` 이며, `ShaderCompileWorker.Target.cs` 파일이 들어 있습니다. - -비슷하게 ExampleGame `Source` 디렉토리는 `UE4\ExampleGame\Source` 이며, `ExampleGame.Target.cs` 파일이 들어 있습니다. - -## 타겟 파일 내용 - -각 게임이나 프로그램에 대한 타겟 파일에 정의되는 클래스는 (`RulesCompiler.cs` 에서 찾을 수 있는) `TargetRules` 에서 파생됩니다. - -클래스의 이름은 툴이나 게임의 이름에 `target` 을 붙여 만듭니다. 예를 들어 ShaderCompileWorker 툴의 타겟 파일에 정의된 클래스는 `ShaderCompileWorkerTarget` 가 됩니다. 마지막의 `Target` 은 **필수** 입니다. 기존 `*.Build.cs` 모듈 룰 클래스도 모두 같은 DLL 속에 컴파일되므로, 이름이 충돌되지 않도록 하기 위해 추가되는 것입니다. - -UnrealBuildTool 은 Rules DLL 에서 빌드 타겟을 요청할 때, `[APPNAME]` 을 취한 다음 `Target` 을 덧붙입니다. 그래서 위와 같은 예제를 사용할 때, UnrealBuildTool 에 `ShaderCompileWorker Win64 Development` 가 전달되면, `ShaderCompileWorkerTarget` 을 관심있는 `TargetRules` 클래스 이름으로 요청합니다. - -### 생성자 - -생성자(constructor)는 생성할 어플리케이션 이름과 타겟 종류를 설정합니다. 비교용 ExampleGameTarget 생성자입니다: - - public ExampleGameTarget(TargetInfo Target) - { - Type = TargetType.Game; - Name = "ExampleGame"; - } - -### Setup Binaries - -`TargetRules::SetupBinaries()` 는 `UEBuildBinaryConfiguration` 인스턴스 목록을 생성하는 데 사용되는데, UnrealBuildTool 은 이것을 사용하여 (생성하고자 하는 대상인) AppBinaries 배열을 채웁니다. - -### Setup Global Environment - -`TargetRules::SetupGlobalEnvironment()` 는 타겟에 대한 UnrealBuildTool 의 여러가지 빌드 환경설정 세팅을 설정하는 데는 물론, 글로벌 Compile, Link 환경을 셋업하는 데도 사용됩니다. - -[REGION:note] -**주:** 현재 게임에는 기본적으로 UEBuildGame 클래스가 그 작업을 처리해 주고 있기 때문에, 이 함수가 들어있지 않습니다. 그러나 게임에서 이 세팅을 덮어쓰고자 한다면, 얼마든지 그리 할 수 있습니다. -[/REGION] - -## 예제 타겟 파일 - -완성 예제로 ShaderCompileWorker.Target.cs 파일을 들어보겠습니다: - - // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - - using UnrealBuildTool; - using System.Collections.Generic; - - public class ShaderCompileWorkerTarget : TargetRules - { - public ShaderCompileWorkerTarget(TargetInfo Target) - { - Type = TargetType.Program; - Name = "ShaderCompileWorker"; - } - - // - // TargetRules interface. - // - - public override void SetupBinaries( - TargetInfo Target, - ref List OutBuildBinaryConfigurations, - ref List OutExtraModuleNames - ) - { - List LinkModules = new List() { "Core", "ShaderCore", "RenderCore", "RHI", "WindowsTools", "ShaderCompileWorker" }; - OutBuildBinaryConfigurations.Add( - new UEBuildBinaryConfiguration( InType: UEBuildBinaryType.Executable, - InModuleNames: LinkModules ) - ); - } - - public override void SetupGlobalEnvironment( - TargetInfo Target, - ref LinkEnvironmentConfiguration OutLinkEnvironmentConfiguration, - ref CPPEnvironmentConfiguration OutCPPEnvironmentConfiguration - ) - { - // 필요치 않은 써드 파티 기능들을 끕니다. - UEBuildConfiguration.bAllowSteamworks = false; - UEBuildConfiguration.bAllowLive = false; - UEBuildConfiguration.bCompilePerforce = false; - - // 현재 Lean and Mean 모드를 강제합니다. - UEBuildConfiguration.bCompileLeanAndMeanUE = true; - - // 현재 이 앱은 엔진에 대해 링크되고 있지 않으니, Core 에서 엔진 나머지 부분으로의 참조를 컴파일하지 않습니다. - UEBuildConfiguration.bCompileAgainstEngine = false; - - // ShaderCompileWorker 는 콘솔 어플리케이션이며, 윈도우 앱은 아닙니다 (도입점을 WinMain() 대신 main() 으로 설정합니다). - OutLinkEnvironmentConfiguration.bIsBuildingConsoleApplication = true; - - // 워커가 자주 스폰되어 느려지는 요인이 될 로깅을 끕니다. - OutCPPEnvironmentConfiguration.Definitions.Add("ALLOW_LOG_FILE=0"); - OutCPPEnvironmentConfiguration.Definitions.Add("HACK_HEADER_GENERATOR=1"); - OutCPPEnvironmentConfiguration.Definitions.Add("HACK_SHADER_COMPILER_WORKER=1"); - } - } + using UnrealBuildTool; + using System.Collections.Generic; + public class MyProjectTarget : TargetRules + { + public MyProjectTarget(TargetInfo Target) : base(Target) + { + Type = TargetType.Game; + // Other properties go here + } + } +[INCLUDE:Programming/UnrealBuildSystem/TargetFiles/TargetFilesProperties] diff --git a/Engine/Documentation/Source/Programming/UnrealBuildSystem/TargetFiles/TargetFilesProperties/TargetFilesProperties.CHN.udn b/Engine/Documentation/Source/Programming/UnrealBuildSystem/TargetFiles/TargetFilesProperties/TargetFilesProperties.CHN.udn new file mode 100644 index 000000000000..fd4e3ce466e0 --- /dev/null +++ b/Engine/Documentation/Source/Programming/UnrealBuildSystem/TargetFiles/TargetFilesProperties/TargetFilesProperties.CHN.udn @@ -0,0 +1,240 @@ +INTSourceChangelist:0 +Availability: NoPublish +Title: Build Configuration Properties Page +Crumbs: +Description: This is a procedurally generated markdown page. +Version: 4.16 + +### Read-Only Properties + +$ Name (String): The name of this target. + +$ Platform (UnrealTargetPlatform): Platform that this target is being built for. + +$ Configuration (UnrealTargetConfiguration): The configuration being built. + +$ Architecture (String): Architecture that the target is being built for (or an empty string for the default). + +$ ProjectFile (FileReference): Path to the project file for the project containing this target. + + +### Read/Write Properties +$ Type (TargetType): The type of target. + +$ bUsesSteam (Boolean): Whether the target uses Steam. + +$ bUsesCEF3 (Boolean): Whether the target uses CEF3. + +$ bUsesSlate (Boolean): Whether the project uses visual Slate UI (as opposed to the low level windowing/messaging, which is always available). + +$ bUseStaticCRT (Boolean): Forces linking against the static CRT. This is not fully supported across the engine due to the need for allocator implementations to be shared (for example), and TPS libraries to be consistent with each other, but can be used for utility programs. + +$ bDebugBuildsActuallyUseDebugCRT (Boolean): Enables the debug C++ runtime (CRT) for debug builds. By default we always use the release runtime, since the debug version isn't particularly useful when debugging Unreal Engine projects, and linking against the debug CRT libraries forces our third party library dependencies to also be compiled using the debug CRT (and often perform more slowly). Often it can be inconvenient to require a separate copy of the debug versions of third party static libraries simply so that you can debug your program's code. + +$ bOutputPubliclyDistributable (Boolean): Whether the output from this target can be publicly distributed, even if it has dependencies on modules that are in folders with special restrictions (eg. CarefullyRedist, NotForLicensees, NoRedist). + +$ UndecoratedConfiguration (UnrealTargetConfiguration): Specifies the configuration whose binaries do not require a "-Platform-Configuration" suffix. + +$ bBuildAllPlugins (Boolean): Build all the plugins that we can find, even if they're not enabled. This is particularly useful for content-only projects, where you're building the UE4Editor target but running it with a game that enables a plugin. + +$ AdditionalPlugins (List<String>): A list of additional plugins which need to be included in this target. This allows referencing non-optional plugin modules which cannot be disabled, and allows building against specific modules in program targets which do not fit the categories in ModuleHostType. + +$ PakSigningKeysFile (String): Path to the set of pak signing keys to embed in the executable. + +$ SolutionDirectory (String): Allows a Program Target to specify it's own solution folder path. + +$ bOutputToEngineBinaries (Boolean): Output the executable to the engine binaries folder. + +$ bShouldCompileAsDLL (Boolean): Whether this target should be compiled as a DLL. Requires LinkType to be set to TargetLinkType.Monolithic. + +$ ExeBinariesSubFolder (String): Subfolder to place executables in, relative to the default location. + +$ GeneratedCodeVersion (EGeneratedCodeVersion): Allow target module to override UHT code generation version. + +$ bCompilePhysX (Boolean): Whether to include PhysX support. + +$ bCompileAPEX (Boolean): Whether to include PhysX APEX support. + +$ bCompileNvCloth (Boolean): Whether to include NvCloth. + +$ bRuntimePhysicsCooking (Boolean): Whether to allow runtime cooking of physics. + +$ bCompileBox2D (Boolean): Whether to include Box2D support. + +$ bCompileICU (Boolean): Whether to include ICU unicode/i18n support in Core. + +$ bCompileCEF3 (Boolean): Whether to compile CEF3 support. + +$ bBuildEditor (Boolean): Whether to compile the editor or not. Only desktop platforms (Windows or Mac) will use this, other platforms force this to false. + +$ bBuildRequiresCookedData (Boolean): Whether to compile code related to building assets. Consoles generally cannot build assets. Desktop platforms generally can. + +$ bBuildWithEditorOnlyData (Boolean): Whether to compile WITH_EDITORONLY_DATA disabled. Only Windows will use this, other platforms force this to false. + +$ bBuildDeveloperTools (Boolean): Whether to compile the developer tools. + +$ bForceBuildTargetPlatforms (Boolean): Whether to force compiling the target platform modules, even if they wouldn't normally be built. + +$ bForceBuildShaderFormats (Boolean): Whether to force compiling shader format modules, even if they wouldn't normally be built. + +$ bCompileSimplygon (Boolean): Whether we should compile in support for Simplygon or not. + +$ bCompileSimplygonSSF (Boolean): Whether we should compile in support for Simplygon's SSF library or not. + +$ bCompileLeanAndMeanUE (Boolean): Whether to compile lean and mean version of UE. + +$ bCompileAgainstEngine (Boolean): Enabled for all builds that include the engine project. Disabled only when building standalone apps that only link with Core. + +$ bCompileAgainstCoreUObject (Boolean): Enabled for all builds that include the CoreUObject project. Disabled only when building standalone apps that only link with Core. + +$ bIncludeADO (Boolean): If true, include ADO database support in core. + +$ bCompileRecast (Boolean): Whether to compile Recast navmesh generation. + +$ bCompileSpeedTree (Boolean): Whether to compile SpeedTree support. + +$ bForceEnableExceptions (Boolean): Enable exceptions for all modules. + +$ bForceEnableRTTI (Boolean): Enable RTTI for all modules. + +$ bWithServerCode (Boolean): Compile server-only code. + +$ bCompileWithStatsWithoutEngine (Boolean): Whether to include stats support even without the engine. + +$ bCompileWithPluginSupport (Boolean): Whether to include plugin support. + +$ bWithPerfCounters (Boolean): Whether to include PerfCounters support. + +$ bUseLoggingInShipping (Boolean): Whether to turn on logging for test/shipping builds. + +$ bLoggingToMemoryEnabled (Boolean): Whether to turn on logging to memory for test/shipping builds. + +$ bUseLauncherChecks (Boolean): Whether to check that the process was launched through an external launcher. + +$ bUseChecksInShipping (Boolean): Whether to turn on checks (asserts) for test/shipping builds. + +$ bCompileFreeType (Boolean): True if we need FreeType support. + +$ bCompileForSize (Boolean): True if we want to favor optimizing size over speed. + +$ bForceCompileDevelopmentAutomationTests (Boolean): Whether to compile development automation tests. + +$ bForceCompilePerformanceAutomationTests (Boolean): Whether to compile performance automation tests. + +$ bEventDrivenLoader (Boolean): If true, event driven loader will be used in cooked builds. @todoio This needs to be replaced by a runtime solution after async loading refactor. + +$ bEnforceIWYU (Boolean): Enforce "include what you use" rules; warns if monolithic headers (Engine.h, UnrealEd.h, etc...) are used, and checks that source files include their matching header first. + +$ bHasExports (Boolean): Whether the final executable should export symbols. + +$ bPrecompile (Boolean): Make static libraries for all engine modules as intermediates for this target. + +$ bUsePrecompiled (Boolean): Use existing static libraries for all engine modules in this target. + +$ bEnableOSX109Support (Boolean): Whether we should compile with support for OS X 10.9 Mavericks. Used for some tools that we need to be compatible with this version of OS X. + +$ bIsBuildingConsoleApplication (Boolean): True if this is a console application that's being built. + +$ bDisableSymbolCache (Boolean): True if debug symbols that are cached for some platforms should not be created. + +$ bUseUnityBuild (Boolean): Whether to unify C++ code into larger files for faster compilation. + +$ bForceUnityBuild (Boolean): Whether to force C++ source files to be combined into larger files for faster compilation. + +$ bUseAdaptiveUnityBuild (Boolean): Use a heuristic to determine which files are currently being iterated on and exclude them from unity blobs, result in faster incremental compile times. The current implementation uses the read-only flag to distinguish the working set, assuming that files will be made writable by the source control system if they are being modified. This is true for Perforce, but not for Git. + +$ bAdaptiveUnityDisablesOptimizations (Boolean): Disable optimization for files that are in the adaptive non-unity working set. + +$ bAdaptiveUnityDisablesPCH (Boolean): Disables force-included PCHs for files that are in the adaptive non-unity working set. + +$ MinGameModuleSourceFilesForUnityBuild (Int32): The number of source files in a game module before unity build will be activated for that module. This allows small game modules to have faster iterative compile times for single files, at the expense of slower full rebuild times. This setting can be overridden by the bFasterWithoutUnity option in a module's Build.cs file. + +$ bShadowVariableErrors (Boolean): Forces shadow variable warnings to be treated as errors on platforms that support it. + +$ bUndefinedIdentifierErrors (Boolean): Forces the use of undefined identifiers in conditional expressions to be treated as errors. + +$ bUseFastMonoCalls (Boolean): New Monolithic Graphics drivers have optional "fast calls" replacing various D3d functions + +$ bUseFastSemanticsRenderContexts (Boolean): New Xbox driver supports a "fast semantics" context type. This switches it on for the immediate and deferred contexts Try disabling this if you see rendering issues and/or crashes inthe Xbox RHI. + +$ NumIncludedBytesPerUnityCPP (Int32): An approximate number of bytes of C++ code to target for inclusion in a single unified C++ file. + +$ bStressTestUnity (Boolean): Whether to stress test the C++ unity build robustness by including all C++ files files in a project from a single unified file. + +$ bForceDebugInfo (Boolean): Whether to force debug info to be generated. + +$ bDisableDebugInfo (Boolean): Whether to globally disable debug info generation; see DebugInfoHeuristics.cs for per-config and per-platform options. + +$ bDisableDebugInfoForGeneratedCode (Boolean): Whether to disable debug info generation for generated files. This improves link times for modules that have a lot of generated glue code. + +$ bOmitPCDebugInfoInDevelopment (Boolean): Whether to disable debug info on PC in development builds (for faster developer iteration, as link times are extremely fast with debug info disabled). + +$ bUsePDBFiles (Boolean): Whether PDB files should be used for Visual C++ builds. + +$ bUsePCHFiles (Boolean): Whether PCH files should be used. + +$ MinFilesUsingPrecompiledHeader (Int32): The minimum number of files that must use a pre-compiled header before it will be created and used. + +$ bForcePrecompiledHeaderForGameModules (Boolean): When enabled, a precompiled header is always generated for game modules, even if there are only a few source files in the module. This greatly improves compile times for iterative changes on a few files in the project, at the expense of slower full rebuild times for small game projects. This can be overridden by setting MinFilesUsingPrecompiledHeaderOverride in a module's Build.cs file. + +$ bUseIncrementalLinking (Boolean): Whether to use incremental linking or not. Incremental linking can yield faster iteration times when making small changes. Currently disabled by default because it tends to behave a bit buggy on some computers (PDB-related compile errors). + +$ bAllowLTCG (Boolean): Whether to allow the use of link time code generation (LTCG). + +$ bAllowASLRInShipping (Boolean): Whether to allow the use of ASLR (address space layout randomization) if supported. Only applies to shipping builds. + +$ bSupportEditAndContinue (Boolean): Whether to support edit and continue. Only works on Microsoft compilers in 32-bit compiles. + +$ bOmitFramePointers (Boolean): Whether to omit frame pointers or not. Disabling is useful for e.g. memory profiling on the PC. + +$ bStripSymbolsOnIOS (Boolean): Whether to strip iOS symbols or not (implied by bGeneratedSYMFile). + +$ bUseMallocProfiler (Boolean): If true, then enable memory profiling in the build (defines USE_MALLOC_PROFILER=1 and forces bOmitFramePointers=false). + +$ bUseSharedPCHs (Boolean): Enables "Shared PCHs", a feature which significantly speeds up compile times by attempting to share certain PCH files between modules that UBT detects is including those PCH's header files. + +$ bUseShippingPhysXLibraries (Boolean): True if Development and Release builds should use the release configuration of PhysX/APEX. + +$ bUseCheckedPhysXLibraries (Boolean): True if Development and Release builds should use the checked configuration of PhysX/APEX. if bUseShippingPhysXLibraries is true this is ignored. + +$ bCheckLicenseViolations (Boolean): Tells the UBT to check if module currently being built is violating EULA. + +$ bBreakBuildOnLicenseViolation (Boolean): Tells the UBT to break build if module currently being built is violating EULA. + +$ bUseFastPDBLinking (Boolean): Whether to use the :FASTLINK option when building with /DEBUG to create local PDBs on Windows. Fast, but currently seems to have problems finding symbols in the debugger. + +$ bCreateMapFile (Boolean): Outputs a map file as part of the build. + +$ bEnableCodeAnalysis (Boolean): Enables code analysis mode. Currently, this has specific requirements. It only works on Windows platform with the MSVC compiler. Also, it requires a version of the compiler that supports the /analyze option, such as Visual Studio 2013. + +$ BundleVersion (String): Bundle version for Mac apps. + +$ bDeployAfterCompile (Boolean): Whether to deploy the executable after compilation on platforms that require deployment. + +$ bCreateStubIPA (Boolean): If true, then a stub IPA will be generated when compiling is done (minimal files needed for a valid IPA). + +$ bCopyAppBundleBackToDevice (Boolean): If true, then a stub IPA will be generated when compiling is done (minimal files needed for a valid IPA). + +$ bAllowRemotelyCompiledPCHs (Boolean): When enabled, allows XGE to compile pre-compiled header files on remote machines. Otherwise, PCHs are always generated locally. + +$ bCheckSystemHeadersForModification (Boolean): Whether headers in system paths should be checked for modification when determining outdated actions. + +$ bDisableLinking (Boolean): Whether to disable linking for this target. + +$ bFormalBuild (Boolean): Indicates that this is a formal build, intended for distribution. This flag is automatically set to true when Build.version has a changelist set. The only behavior currently bound to this flag is to compile the default resource file separately for each binary so that the OriginalFilename field is set correctly. By default, we only compile the resource once to reduce build times. + +$ bFlushBuildDirOnRemoteMac (Boolean): Whether to clean Builds directory on a remote Mac before building. + +$ bPrintToolChainTimingInfo (Boolean): Whether to write detailed timing info from the compiler and linker. + +$ PCHOutputDirectory (String): The directory to put precompiled header files in. Experimental setting to allow using a path on a faster drive. Defaults to the standard output directory if not set. + +$ GlobalDefinitions (List<String>): Macros to define globally across the whole target. + +$ ExtraModuleNames (List<String>): List of additional modules to be compiled into the target. + +$ BuildEnvironment (TargetBuildEnvironment): Specifies the build environment for this target. See TargetBuildEnvironment for more infomation on the available options. + +$ OverrideExecutableFileExtension (String): Can be set to override the file extension of the executable file (normally .exe or .dll on Windows, for example) + + diff --git a/Engine/Documentation/Source/Programming/UnrealBuildSystem/TargetFiles/TargetFilesProperties/TargetFilesProperties.INT.udn b/Engine/Documentation/Source/Programming/UnrealBuildSystem/TargetFiles/TargetFilesProperties/TargetFilesProperties.INT.udn index e8ce0b77e3d5..a3d5b3faf807 100644 --- a/Engine/Documentation/Source/Programming/UnrealBuildSystem/TargetFiles/TargetFilesProperties/TargetFilesProperties.INT.udn +++ b/Engine/Documentation/Source/Programming/UnrealBuildSystem/TargetFiles/TargetFilesProperties/TargetFilesProperties.INT.udn @@ -42,6 +42,8 @@ $ PakSigningKeysFile (String): Path to the set of pak signing keys to embed in t $ SolutionDirectory (String): Allows a Program Target to specify it's own solution folder path. +$ bBuildInSolutionByDefault (Nullable<Boolean>): Whether the target should be included in the default solution build configuration + $ bOutputToEngineBinaries (Boolean): Output the executable to the engine binaries folder. $ bShouldCompileAsDLL (Boolean): Whether this target should be compiled as a DLL. Requires LinkType to be set to TargetLinkType.Monolithic. @@ -56,8 +58,6 @@ $ bCompileAPEX (Boolean): Whether to include PhysX APEX support. $ bCompileNvCloth (Boolean): Whether to include NvCloth. -$ bRuntimePhysicsCooking (Boolean): Whether to allow runtime cooking of physics. - $ bCompileBox2D (Boolean): Whether to include Box2D support. $ bCompileICU (Boolean): Whether to include ICU unicode/i18n support in Core. @@ -82,6 +82,8 @@ $ bCompileSimplygonSSF (Boolean): Whether we should compile in support for Simpl $ bCompileLeanAndMeanUE (Boolean): Whether to compile lean and mean version of UE. +$ bUseCacheFreedOSAllocs (Boolean): Whether to utilize cache freed OS allocs with MallocBinned + $ bCompileAgainstEngine (Boolean): Enabled for all builds that include the engine project. Disabled only when building standalone apps that only link with Core. $ bCompileAgainstCoreUObject (Boolean): Enabled for all builds that include the CoreUObject project. Disabled only when building standalone apps that only link with Core. @@ -204,8 +206,6 @@ $ bUseFastPDBLinking (Boolean): Whether to use the :FASTLINK option when buildin $ bCreateMapFile (Boolean): Outputs a map file as part of the build. -$ bEnableCodeAnalysis (Boolean): Enables code analysis mode. Currently, this has specific requirements. It only works on Windows platform with the MSVC compiler. Also, it requires a version of the compiler that supports the /analyze option, such as Visual Studio 2013. - $ BundleVersion (String): Bundle version for Mac apps. $ bDeployAfterCompile (Boolean): Whether to deploy the executable after compilation on platforms that require deployment. diff --git a/Engine/Documentation/Source/Programming/UnrealBuildSystem/TargetFiles/TargetFilesProperties/TargetFilesProperties.JPN.udn b/Engine/Documentation/Source/Programming/UnrealBuildSystem/TargetFiles/TargetFilesProperties/TargetFilesProperties.JPN.udn new file mode 100644 index 000000000000..e5dd3edc88b8 --- /dev/null +++ b/Engine/Documentation/Source/Programming/UnrealBuildSystem/TargetFiles/TargetFilesProperties/TargetFilesProperties.JPN.udn @@ -0,0 +1,244 @@ +INTSourceChangelist:3392479 +Availability:NoPublish +Title:ビルド コンフィギュレーション プロパティのページ +Crumbs:%ROOT% +Description:プロシージャルに生成されるマークダウンの説明です。 +Version:4.16 +Parent:Programming/UnrealBuildSystem/TargetFiles +Order: +Type:reference +Tags:Unreal Build System + +### 読み取り専用プロパティ + +$ Name (String):このターゲットの名前です。 + +$ Platform (UnrealTargetPlatform):このターゲットのビルド先プラットフォームです。 + +$ Configuration (UnrealTargetConfiguration):ビルド中のコンフィギュレーションです。 + +$ Architecture (String):ターゲットがビルド先アーキテクチャ (もしくはデフォルト用の空のストリング) です。 + +$ ProjectFile (FileReference):このターゲットを含むプロジェクトのプロジェクト ファイルへのパスです。 + + +### 読み取り / 書き込み用プロパティ +$ Type (TargetType):ターゲットの型です。 + +$ bUsesSteam (Boolean):ターゲットが Steam を使用するかどうかを指定します。 + +$ bUsesCEF3 (Boolean):ターゲットが CEF3 を使用するかどうかを指定します。 + +$ bUsesSlate (Boolean):プロジェクトで視覚的な Slate UI を使用するかどうかを指定します (常に使用できるローレベル ウィンドウイング / メッセージングとは対照的に)。 + +$ bUseStaticCRT (Boolean):強制的に CRT に静的リンクします。アロケータ インプリメンテーションの共有を必要としたり、TPS ライブラリに整合性が必要なので、エンジン全体でサポートしているわけではありませんが、ユーティリティ プログラムで使用することができます。 + +$ bDebugBuildsActuallyUseDebugCRT (Boolean):デバッグ ビルドのデバッグ C++ ランタイム (CRT) を有効にします。アンリアル エンジン プロジェクトをデバッグする場合、デバッグ版がそこまで便利なわけでもないので、デフォルトで常にリリース ランタイムを使用しています。また、Debug CRT ライブラリへリンク付けするとサードパーティ ライブラリ依存も Debug CRT を使って強制的にコンパイルされます (一般的にさらに遅くなります)。プログラム コードのデバッグのためだけにサードパーティ統計ライブラリのデバッグ バージョンを別に要求するのは面倒くさい場合が多いです。 + +$ bOutputPubliclyDistributable (Boolean):モジュール上の依存関係が特別な制約をもつフォルダ (CarefullyRedist、NotForLicensees、NoRedist など) 内にある場合でも、このターゲットからの出力を公開配布できるかどうかを指定します。 + +$ UndecoratedConfiguration (UnrealTargetConfiguration):コンフィギュレーションのバイナリが "-Platform-Configuration" サフィックスを要求しないように指定します。 + +$ bBuildAllPlugins (Boolean):有効にされていなくても見つけることができるすべてのプラグインをビルドします。ビルドしている UE4Editor ターゲットをプラグインを有効にするゲームで実行するような、コンテンツ専用プロジェクトに特に便利です。 + +$ AdditionalPlugins (List<String>):このターゲットにインクルードする必要のある追加プラグイン リストです。無効にすることができないオプショナルではないプラグイン モジュールの参照を可能にし、ModuleHostType の分類に当てはまらないプログラム ターゲットの特定モジュールに対してビルドを可能にします。 + +$ PakSigningKeysFile (String):実行ファイルに埋め込むための PAK ログイン キーへのパスです。 + +$ SolutionDirectory (String):プログラム ターゲットが独自のソリューション フォルダ パスを指定できるようにします。 + +$ bOutputToEngineBinaries (Boolean):実行ファイルをエンジン バイナリ フォルダへ出力します。 + +$ bShouldCompileAsDLL (Boolean):このターゲットを DLL としてコンパイルするかどうかを指定します。Requires LinkType を TargetLinkType.Monolithic に設定する必要があります。 + +$ ExeBinariesSubFolder (String):デフォルト位置に対して、実行ファイルを格納するサブフォルダです。 + +$ GeneratedCodeVersion (EGeneratedCodeVersion):ターゲット モジュールが UHT コード生成版をオーバーライドできるようにします。 + +$ bCompilePhysX (Boolean):PhysX サポートをインクルードするかどうかを指定します。 + +$ bCompileAPEX (Boolean):PhysX APEX サポートをインクルードするかどうかを指定します。 + +$ bCompileNvCloth (Boolean):NvCloth をインクルードするかどうかを指定します。 + +$ bRuntimePhysicsCooking (Boolean):物理のランタイム クッキングを可能にするかどうか指定します。 + +$ bCompileBox2D (Boolean):Box2D サポートをインクルードするかどうか指定します。 + +$ bCompileICU (Boolean):ICU unicode/i18n サポートをコアにインクルードするかどうか指定します。 + +$ bCompileCEF3 (Boolean):CEF3 サポートをコンパイルするかどうか指定します。 + +$ bBuildEditor (Boolean):エディタをコンパイルするかどうか指定します。プラットフォームがデスクトップ (Windows または Mac) の場合のみ使用します。それ以外のプラットフォームで使用すると false となります。 + +$ bBuildRequiresCookedData (Boolean):ビルド アセットに関連したコードをコンパイルするかどうか設定します。コンソールは一般的にアセットのビルドはできません。通常、デスクトップ プラットフォームはできます。 + +$ bBuildWithEditorOnlyData (Boolean):WITH_EDITORONLY_DATA を無効にコンパイルするかどうか指定します。Windows のみで使用します。それ以外のプラットフォームでは強制的に false になります。 + +$ bBuildDeveloperTools (Boolean):コンパイル ツールをコンパイルするかどうか指定します。 + +$ bForceBuildTargetPlatforms (Boolean):通常はビルドされない場合でも、ターゲット プラットフォーム モジュールを強制的にコンパイルするかどうか指定します。 + +$ bForceBuildShaderFormats (Boolean):通常はビルドされない場合でも、シェーダー プラットフォーム モジュールを強制的にコンパイルするかどうか指定します。 + +$ bCompileSimplygon (Boolean):Simplygon をサポートできるようにコンパイルするかどうか指定します。 + +$ bCompileSimplygonSSF (Boolean):Simplygon の SSF ライブラリをサポートできるようにコンパイルするかどうか指定します。 + +$ bCompileLeanAndMeanUE (Boolean):UE のLean と Mean バージョンをコンパイルするかどうか指定します。 + +$ bCompileAgainstEngine (Boolean):エンジン プロジェクトを含むすべてのビルドに対して有効にされます。コアとのみ結合するスタンドアロン app のビルド時のみ無効になります。 + +$ bCompileAgainstCoreUObject (Boolean):CoreUObject プロジェクトを含むすべてのビルドに対して有効にされます。コアとのみ結合するスタンドアロン app のビルド時のみ無効になります。 + +$ bIncludeADO (Boolean):True の場合、ADO データベース サポートをコアに含みます。 + +$ bCompileRecast (Boolean):Recast navmesh 生成をコンパイルするかどうか指定します。 + +$ bCompileSpeedTree (Boolean):SpeedTree サポートをコンパイルするかどうか指定します。 + +$ bForceEnableExceptions (Boolean):すべてのモジュールに対して例外を有効にします。 + +$ bForceEnableRTTI (Boolean):すべてのモジュールに対して RTTI を有効にします。 + +$ bWithServerCode (Boolean):サーバー専用コードをコンパイルします。 + +$ bCompileWithStatsWithoutEngine (Boolean):エンジンなしても統計サポートを含むかどうかを設定します。 + +$ bCompileWithPluginSupport (Boolean):プラグイン サポートをインクルードするかどうかを指定します。 + +$ bWithPerfCounters (Boolean):PerfCounters サポートをインクルードするかどうか指定します。 + +$ bUseLoggingInShipping (Boolean):テスト / シッピング ビルドのロギングをオンにするかどうかを指定します。 + +$ bLoggingToMemoryEnabled (Boolean):テスト / シッピング ビルド用メモリのロギングをオンにするかどうかを指定します。 + +$ bUseLauncherChecks (Boolean):処理が外部ランチャーで起動したことを確認するかどうか指定します。 + +$ bUseChecksInShipping (Boolean):テスト / シッピング ビルドに対するチェック (アサート) をオンにするかどうか指定します。 + +$ bCompileFreeType (Boolean):サポートが必要な場合は true に設定します。 + +$ bCompileForSize (Boolean):速度よりも大きさの最適化を優先したい場合は true に設定します。 + +$ bForceCompileDevelopmentAutomationTests (Boolean):開発自動化テストをコンパイルするかどうか設定します。 + +$ bForceCompilePerformanceAutomationTests (Boolean):パフォーマンス自動化テストをコンパイルするかどうか設定します。 + +$ bEventDrivenLoader (Boolean):True の場合、イベント ドリブン ローダーがクック済みビルドで使用されます。非同期読み込みがリファクタリングされた後、ランタイム ソリューションに置き換える必要があります。 + +$ bEnforceIWYU (Boolean):PCHU"include what you use" ルールが強制され、モノリシック (Engine.h、UnrealEd.h など) の使用に対して警告が出され、ソースファイルがマッチするヘッダをが最初にインクルードされているかをチェックします。 + +$ bHasExports (Boolean):最後の実行ファイルがシンボルをエクスポートするかどうかを指定します。 + +$ bPrecompile (Boolean):すべてのエンジン モジュールに対して統計情報ライブラリをこのターゲットの中間として作成します。 + +$ bUsePrecompiled (Boolean):このターゲットのすべてのエンジン モジュールに対して既存の統計情報ライブラリを使用します。 + +$ bEnableOSX109Support (Boolean): OS X 10.9 Mavericks のサポートをコンパイルするかどうか指定します。OS X のこのバージョンと互換性が必要なツールに対して使用します。 + +$ bIsBuildingConsoleApplication (Boolean):ビルド中のコンソール アプリケーションの場合は true に設定します。 + +$ bDisableSymbolCache (Boolean):いくつかのプラットフォームにキャッシュされたデバッグ シンボルが作成されるべきでない場合は true を設定します。 + +$ bUseUnityBuild (Boolean):コンパイルを速くするために C++ コードを大きいファイルにまとめるかどうかを指定します。 + +$ bForceUnityBuild (Boolean):コンパイルを速くするために C++ コードを強制的に大きいファイルにまとめるかどうかを指定します。 + +$ bUseAdaptiveUnityBuild (Boolean):ヒューリスティックを使って、イタレート中のファイルを判断してユニティ ボディから取り除き、徐々にコンパイル時間を速くします。現在のインプリメンテーションは、修正中の場合ファイルはソース コントロールで書き込み可能になると仮定して、作業中のファイルを区別するために読み取り専用フラグを使って実行しています。この方法は、Perforce には使えますが、Git には適しません。 + +$ bAdaptiveUnityDisablesOptimizations (Boolean):適合するノンユニティ ワーキング セットの中のファイル最適化を無効にします。 + +$ bAdaptiveUnityDisablesPCH (Boolean):適合するノンユニティ ワーキング セットの中のファイルに対して強制インクルード PCH を無効にします。 + +$ MinGameModuleSourceFilesForUnityBuild (Int32):ユニティ ビルドがそのモジュールに対して有効になる前のゲーム モジュール内のソース ファイル数です。小さいゲーム モジュールでは 1 ファイルあたりの反復コンパイル時間が速くなります。この設定は、モジュールの Build.cs ファイルの bFasterWithoutUnity オプションでオーバーライドすることが可能です。 + +$ bShadowVariableErrors (Boolean):シャドウ変数の警告をサポートしているプラットフォーム上では、強制的にエラーとして扱われます。 + +$ bUndefinedIdentifierErrors (Boolean):条件的表現式で未定義の識別子をエラーとして強制的に使用します。 + +$ bUseFastMonoCalls (Boolean):新しいモノリシック グラフィックス ドライバーに、各種 D3d 機能に代わる "fast calls" がオプションで付きました。 + +$ bUseFastSemanticsRenderContexts (Boolean):新しい Xbox ドライバーは「速いセマンティクス」コンテキスト タイプをサポートします。これは、即時およびディファードコンテキストをオンに切り替えます。Xbox RHI でレンダリングに問題があったりクラッシュする場合は、これを無効にしてみてください。 + +$ NumIncludedBytesPerUnityCPP (Int32):1 つの統合された C++ ファイルへのインクルードするための C++ コードのおおよそのバイト数です。 + +$ bStressTestUnity (Boolean):1 つに統合されたファイルからすべての C++ ファイルをプロジェクトにインクルードすることで、C++ ユニティ ビルドの剛健性のテストを重視するかどうかを指定します。 + +$ bForceDebugInfo (Boolean):強制的にデバッグ情報を生成するかどうか設定します。 + +$ bDisableDebugInfo (Boolean):デバッグ情報の生成をグローバルに無効にするかどうかを設定します。コンフィギュレーション別、プラットフォーム別のオプションは DebugInfoHeuristics.cs をご覧ください。 + +$ bDisableDebugInfoForGeneratedCode (Boolean):生成ファイルに対してデバッグ情報の生成を無効にするかどうか指定します。グルーコードが数多く生成されたモジュールへのリンク時間を改善します。 + +$ bOmitPCDebugInfoInDevelopment (Boolean):開発ビルド イタレーションで PC 上のデバッグ情報を無効にするかどうか (デバッグ情報を無効にしてリンク時間を大幅に短縮し、デベロッパーのイタレーションを速めるため) を指定します。 + +$ bUsePDBFiles (Boolean):PDB ファイルを Visual C++ ビルドに使用するかどうかを指定します。 + +$ bUsePCHFiles (Boolean):PCH ファイルを使用するかどうかを指定します。 + +$ MinFilesUsingPrecompiledHeader (Int32):作成および使用前にプリコンパイル済みヘッダーを使わなければならないファイルの必要最小数です。 + +$ bForcePrecompiledHeaderForGameModules (Boolean):有効にすると、モジュールにソース ファイルが少ししかなくても、ゲーム モジュールに対して常にヘッダーが生成されます。これにより、プロジェクトの数ファイル上で繰り返し行う変更に対するコンパイル時間が改善されます。モジュールの Build.cs ファイルに MinFilesUsingPrecompiledHeaderOverride を指定すると、オーバーライドが可能になります。 + +$ bUseIncrementalLinking (Boolean):インクリメンタルリンクの使用について指定します。インクリメンタルリンクは、小さな変更に対するイタレーション時間を短縮できます。コンピューターによってはバグのような症状 (PDB 関連のコンパイル エラー) が出るので、現時点では無効にされています。 + +$ bAllowLTCG (Boolean):リンク時コード生成の使用の許可について指定します。 + +$ bAllowASLRInShipping (Boolean):ASLR (アドレス空間配置のランダム化) がサポートされている場合、使用の許可について指定します。シッピング ビルドのみに適用します。 + +$ bSupportEditAndContinue (Boolean):編集をサポートし継続するかどうかを指定します。32 ビット コンパイルの Microsoft コンパイラでのみ機能します。 + +$ bOmitFramePointers (Boolean):フレーム ポインタの省略について指定します。無効にすると、PC のメモリ プロファイリングなど行う際に便利です。 + +$ bStripSymbolsOnIOS (Boolean):iOS シンボルの削除について (bGeneratedSYMFile で暗示される) 指定します。 + +$ bUseMallocProfiler (Boolean):True にすると、ビルドのメモリ プロファイリングが有効になります (USE_MALLOC_PROFILER=1 を定義し bOmitFramePointers=false を強制します)。 + +$ bUseSharedPCHs (Boolean):UBT が探知するモジュール間で特定のファイルを共有しようとすることでコンパイル時間を大幅に短縮する機能 "Shared PCHs" を有効にすると、これらの PCH のヘッダ ファイルを含みます。 + +$ bUseShippingPhysXLibraries (Boolean):開発ビルドとリリース ビルドが PhysX/APEX のリリース コンフィギュレーションを使う場合は true を指定します。 + +$ bUseCheckedPhysXLibraries (Boolean):開発ビルドとリリース ビルドが PhysX/APEX のチェック済みコンフィギュレーションを使う場合は True にします。bUseShippingPhysXLibraries が true の場合は無視されます。 + +$ bCheckLicenseViolations (Boolean):ビルド中のモジュールが EULA に違反しているかどうか確認するように UBT に伝えます。 + +$ bBreakBuildOnLicenseViolation (Boolean):ビルド中のモジュールが EULA に違反している場合、ビルドの中断を UTB に伝えます。 + +$ bUseFastPDBLinking (Boolean):/DEBUG でビルドしてローカルの PDB をウィンドウ上に作成する場合、:FASTLINK オプションを使用するかどうかを指定します。速くなりますが、デバッガーでのシンボルの検索にまだ問題があるようです。 + +$ bCreateMapFile (Boolean):ビルドの一部としてマップ フィアルを出力します。 + +$ bEnableCodeAnalysis (Boolean):コード分析モードを有効にします。現在、特別要件があります。機能するのは、MSVC コンパイラのある Windows プラットフォームのみです。また、Visual Studio 2013 など、分析オプションをサポートしているバージョンのコンパイラが必要です。 + +$ BundleVersion (String):Mac app 用バンドル版です。 + +$ bDeployAfterCompile (Boolean):デプロイを要求するプラットフォーム上でコンパイルした後に実行ファイルをデプロイするかどうか指定します。 + +$ bCreateStubIPA (Boolean):True の場合、コンパイル処理が終わるとスタブ IPA が生成されます (有効な IPA に必要な最小限のファイル)。 + +$ bCopyAppBundleBackToDevice (Boolean):True の場合、コンパイル処理が終わるとスタブ IPA が生成されます (有効な IPA に必要な最小限のファイル)。 + +$ bAllowRemotelyCompiledPCHs (Boolean):有効の場合、XGE がリモート マシン上でプリコンパイル済みヘッダ ファイルをコンパイルすることができます。有効でない場合、PCH がつねんにローカルに生成されます。 + +$ bCheckSystemHeadersForModification (Boolean):無効のアクションと判断した場合、システム パスのヘッダの修正確認を行うかどうか指定します。 + +$ bDisableLinking (Boolean):このターゲットへのリンクを無効にするかどうか指定します。 + +$ bFormalBuild (Boolean):配布目的の公式ビルドであることを示します。Build.version にチェンジリスト セットがある場合、このフラグは自動的に true に設定されます。このフラグに現在結合されている唯一のビヘイビアは、OriginalFilename が正しく設定されるようにデフォルト リソース ファイルをバイナリごとに別々にコンパイルします。デフォルトでは、ビルド時間を短縮するためにリソースのコンパイルは 1 度しか行いません。 + +$ bFlushBuildDirOnRemoteMac (Boolean):ビルド前にリモート Mac で Builds ディレクトリの中のものをすべて削除するかどうかを指定します。 + +$ bPrintToolChainTimingInfo (Boolean):コンパイラとリンカから詳細なタイミング情報を書き出すかどうかを指定します。 + +$ PCHOutputDirectory (String):プリコンパイル済みヘッダ ファイルを入れるディレクトリです。より速いドライブでのパスを使うことができる実験段階の設定です。設定しない場合は標準の出力ディレクトリがデフォルトになります。 + +$ GlobalDefinitions (List<String>):ターゲット全体をグローバルに定義するためのマクロです。 + +$ ExtraModuleNames (List<String>):ターゲットにコンパイルされる追加モジュールのリストです。 + +$ BuildEnvironment (TargetBuildEnvironment):このターゲットのビルド環境を設定します。使用可能なオプションの詳細は TargetBuildEnvironment をご覧ください。 + +$ OverrideExecutableFileExtension (String):実行ファイルのファイル拡張子 (Windows では通常.exe もしくは .dll) のオーバーライド設定が可能です。 + + diff --git a/Engine/Documentation/Source/Programming/UnrealBuildSystem/TargetFiles/TargetFilesProperties/TargetFilesProperties.KOR.udn b/Engine/Documentation/Source/Programming/UnrealBuildSystem/TargetFiles/TargetFilesProperties/TargetFilesProperties.KOR.udn new file mode 100644 index 000000000000..5adfe06c3730 --- /dev/null +++ b/Engine/Documentation/Source/Programming/UnrealBuildSystem/TargetFiles/TargetFilesProperties/TargetFilesProperties.KOR.udn @@ -0,0 +1,244 @@ +INTSourceChangelist:3392479 +Availability: NoPublish +Title: 빌드 환경설정 페이지 +Crumbs:%ROOT% +Description: 절차적 생성되는 마크다운 페이지입니다. +Version: 4.16 +Parent:Programming/UnrealBuildSystem/TargetFiles +Order: +Type:reference +Tags:Unreal Build System + +### 읽기 전용 프로퍼티 + +$ Name (String): 이 타겟 이름입니다. + +$ Platform (UnrealTargetPlatform): 이 타겟의 빌드 대상 플랫폼입니다. + +$ Configuration (UnrealTargetConfiguration): 빌드 중인 구성입니다. + +$ Architecture (String): 타겟의 빌드 대상 아키텍처입니다 (공백 스트링이면 기본값입니다). + +$ ProjectFile (FileReference): 이 타겟이 들어있는 프로젝트에 대한 프로젝트 파일 경로입니다. + + +### 읽기/쓰기 프로퍼티 +$ Type (TargetType): 타겟 유형입니다. + +$ bUsesSteam (Boolean): 타겟의 Steam 사용 여부입니다. + +$ bUsesCEF3 (Boolean): 타겟의 CEF3 사용 여부입니다. + +$ bUsesSlate (Boolean): 프로젝트의 비주얼 Slate UI 사용 여부입니다 (로우 레벨 윈도잉/메시징과는 달리, 항상 사용 가능합니다). + +$ bUseStaticCRT (Boolean): 정적 CRT 에 대해 강제 링크합니다. 전체 엔진에 걸쳐 완전히 지원되지는 않는데 (예로) 얼로케이터 구현을 공유해야 하기 때문입니다. 그리고 TPS 라이브러리가 서로 일관되어야 하지만, 유틸리티 프로그램용으로는 사용할 수 있습니다. + +$ bDebugBuildsActuallyUseDebugCRT (Boolean): 디버그 빌드에 디버그 C++ 런타임 (CRT) 기능을 켭니다. 기본적으로는 항상 릴리즈 런타임을 사용하는데, 디버그 버전은 언리얼 엔진 프로젝트 디버깅 시 그다지 유용하지 않기 때문이며, 디버그 CRT 라이브러리에 대한 링크는 써드 파티 라이브러리 디펜던시 역시 디버그 CRT 를 사용하여 강제 컴파일되도록 하기 (그래서 종종 퍼포먼스가 느려지기) 때문입니다. 단순히 프로그램 코드 디버깅을 하기 위해 써드 파티 스태틱 라이브러리의 디버그 버전 사본이 별도로 필요하다면 종종 불편할 수 있습니다. + +$ bOutputPubliclyDistributable (Boolean): 이 타겟에서의 출력에 (CarefullyRedist, NotForLicensees, NoRedist 등의) 특별 제한이 걸린 폴더에 있는 모듈의 종속성이 있다 할지라도 공개 배포 가능하도록 할지 여부입니다. + +$ UndecoratedConfiguration (UnrealTargetConfiguration): 바이너리에 "-Platform-Configuration" 접미사가 필요치 않은 구성을 지정합니다. + +$ bBuildAllPlugins (Boolean): 활성화되지 않았더라도 찾을 수 있는 모든 플러그인을 빌드합니다. UE4Editor 타겟을 빌드하면서 플러그인을 활성화시켜 실행시키는 콘텐츠 전용 프로젝트에 특히 유용합니다. + +$ AdditionalPlugins (List<String>): 이 타겟에 포함시켜야 하는 부가 플러그인 목록입니다. 비활성화시킬 수 없는 최적이 아닌 플러그인 모듈 레퍼런싱이 가능하며, ModuleHostType 범주에 맞지 않는 프로그램 타겟의 특정 모듈에 대해 빌드할 수 있습니다. + +$ PakSigningKeysFile (String): 실행파일에 삽입할 pak 사이닝 키 세트 경로입니다. + +$ SolutionDirectory (String): Program Target 이 자체 솔루션 폴더 경로를 지정할 수 있도록 합니다. + +$ bOutputToEngineBinaries (Boolean): 실행파일을 엔진 binaries 폴더에 출력합니다. + +$ bShouldCompileAsDLL (Boolean): 이 타겟을 DLL 로 컴파일할지 여부입니다. LinkType 을 TargetLinkType.Monolithic 으로 설정해야 합니다. + +$ ExeBinariesSubFolder (String): 실행파일을 넣을 하위 폴더로, 기본 위치 기준 상대 경로입니다. + +$ GeneratedCodeVersion (EGeneratedCodeVersion): 타겟 모듈이 UHT 코드 생성 버전을 덮어쓸 수 있도록 합니다. + +$ bCompilePhysX (Boolean): PhysX 지원 포함 여부입니다. + +$ bCompileAPEX (Boolean): PhysX APEX 지원 포함 여부입니다. + +$ bCompileNvCloth (Boolean): NvCloth 포함 여부입니다. + +$ bRuntimePhysicsCooking (Boolean): 피직스 런타임 쿠킹 허용 여부입니다. + +$ bCompileBox2D (Boolean): Box2D 지원 포함 여부입니다. + +$ bCompileICU (Boolean): Core 의 ICU 유니코드/i18n 지원 여부입니다. + +$ bCompileCEF3 (Boolean): CEF3 지원 컴파일 여부입니다. + +$ bBuildEditor (Boolean): 에디터 컴파일 여부입니다. 데스크탑 플랫폼만 (윈도우 또는 맥) 이를 사용하며, 다른 플랫폼에서는 강제 false 설정됩니다. + +$ bBuildRequiresCookedData (Boolean): 애셋 빌드 관련 코드 컴파일 여부입니다. 콘솔은 보통 애셋을 빌드할 수 없습니다. 데스크탑 플랫폼은 보통 할 수 있습니다. + +$ bBuildWithEditorOnlyData (Boolean): WITH_EDITORONLY_DATA 비활성화된 것의 컴파일 여부입니다. 윈도우에서만 이를 사용하며, 다른 플랫폼에서는 강제로 false 설정됩니다. + +$ bBuildDeveloperTools (Boolean): 개발자 툴 컴파일 여부입니다. + +$ bForceBuildTargetPlatforms (Boolean): 정상적으로는 빌드되지 않을 타겟 플랫폼 모듈의 강제 컴파일 여부입니다. + +$ bForceBuildShaderFormats (Boolean): 정상적으로는 빌드되지 않을 셰이더 포맷 모듈의 강제 컴파일 여부입니다. + +$ bCompileSimplygon (Boolean): 심플리곤 지원 컴파일 여부입니다. + +$ bCompileSimplygonSSF (Boolean): 심플리곤의 SSF 라이브러리 지원 컴파일 여부입니다. + +$ bCompileLeanAndMeanUE (Boolean): UE 의 lean and mean 버전 컴파일 여부입니다. + +$ bCompileAgainstEngine (Boolean): 엔진 프로젝트를 포함하는 모든 빌드에 대해 활성화됩니다. Core 하고만 링크되는 독립형 앱 빌드시에만 비활성화됩니다. + +$ bCompileAgainstCoreUObject (Boolean): CoreUObject 프로젝트를 포함하는 모든 빌드에 대해 활성화됩니다. Core 하고만 링크되는 독립형 앱 빌드시에만 비활성화됩니다. + +$ bIncludeADO (Boolean): true 면 코어의 ADO 데이터베이스 지원을 포함합니다. + +$ bCompileRecast (Boolean): Recast 내비메시 생성 컴파일 여부입니다. + +$ bCompileSpeedTree (Boolean): SpeedTree 지원 컴파일 여부입니다. + +$ bForceEnableExceptions (Boolean): 모든 모듈에 대한 예외를 활성화시킵니다. + +$ bForceEnableRTTI (Boolean): 모든 모듈에 대한 RTTI 를 활성화시킵니다. + +$ bWithServerCode (Boolean): 서버 전용 코드를 컴파일합니다. + +$ bCompileWithStatsWithoutEngine (Boolean): 엔진 없이도 통계 지원 포함 여부입니다. + +$ bCompileWithPluginSupport (Boolean): 플러그인 지원 포함 여부입니다. + +$ bWithPerfCounters (Boolean): PerfCounters 지원 포함 여부입니다. + +$ bUseLoggingInShipping (Boolean): test/shipping 빌드에 대한 로그 활성화 여부입니다. + +$ bLoggingToMemoryEnabled (Boolean): test/shipping 빌드에 대한 메모리에 로깅 활성화 여부입니다. + +$ bUseLauncherChecks (Boolean): 프로세스가 외부 런처를 통해 실행되었나 검사할지 여부입니다. + +$ bUseChecksInShipping (Boolean): test/shipping 빌드에 대해 체크 (또는 어서트) 활성화 여부입니다. + +$ bCompileFreeType (Boolean): FreeType 지원이 필요한 true 입니다. + +$ bCompileForSize (Boolean): 속도보다 크기 최적화가 좋은 경우 true 입니다. + +$ bForceCompileDevelopmentAutomationTests (Boolean): 개발 자동화 테스트 컴파일 여부입니다. + +$ bForceCompilePerformanceAutomationTests (Boolean): 퍼포먼스 자동화 테스트 컴파일 여부입니다. + +$ bEventDrivenLoader (Boolean): true 면 쿠킹된 빌드에 이벤트 주도 로더가 사용됩니다. @todoio 비동기 로딩 리팩터 이후 런타임 솔루션으로 대체시켜 줘야 합니다. + +$ bEnforceIWYU (Boolean): "include what you use" 규칙을 적용합니다. 모노리식 헤더(Engine.h, UnrealEd.h ...)가 사용되면 경고를 내며, 소스 파일이 일치하는 헤더를 먼저 포함하는지 검사합니다. + +$ bHasExports (Boolean): 최종 실행파일의 심볼 익스포트 여부입니다. + +$ bPrecompile (Boolean): 모든 엔진 모듈에 대한 스태틱 라이브러리를 이 타겟에 대한 중개 파일로 만듭니다. + +$ bUsePrecompiled (Boolean): 이 타겟의 모든 엔진 모듈에 대해 기존 스태틱 라이브러리를 사용합니다. + +$ bEnableOSX109Support (Boolean): OS X 10.9 Mavericks 에 대한 지원 포함 컴파일 여부입니다. 이 버전의 OS X 와 호환되어야 하는 툴에 사용됩니다. + +$ bIsBuildingConsoleApplication (Boolean): 이것이 빌드 대상 콘솔 어플리케이션인 경우 true 입니다. + +$ bDisableSymbolCache (Boolean): 생성되지 않아야 하는 플랫폼에 대해 디버그 심볼이 캐시된 경우 true 입니다. + +$ bUseUnityBuild (Boolean): 보다 빠른 컴파일을 위해 C++ 코드를 커다란 파일로 통합시킬지 여부입니다. + +$ bForceUnityBuild (Boolean): 보다 빠른 컴파일을 위해 C++ 소스 파일을 보다 큰 파일로 강제 합칠지 여부입니다. + +$ bUseAdaptiveUnityBuild (Boolean): 휴리스틱 기법을 사용하여 현재 반복처리 대상인 파일을 알아낸 뒤 유니티 블롭에서 제외시켜, 점증적 컴파일 시간을 빠르게 합니다. 현재 구현은 변경중인 파일은 소스 콘트롤 시스템이 쓰기가능으로 만든다 가정하고, 읽기전용 플래그로 작업 세트를 구분합니다. Perforce 에는 맞지만, Git 에는 아닙니다. + +$ bAdaptiveUnityDisablesOptimizations (Boolean): 적응형 논-유니티 작업 세트에 있는 파일에 대한 최적화를 비활성화시킵니다. + +$ bAdaptiveUnityDisablesPCH (Boolean): 적응형 논-유니티 작업 세트에 있는 파일에 대한 강제 포함 PCH 를 비활성화시킵니다. + +$ MinGameModuleSourceFilesForUnityBuild (Int32): 게임 모듈에 소스 파일 수가 이 이상 되면 해당 모듈에 대해 유니티 빌드가 가동됩니다. 작은 게임 모듈의 경우 풀 리빌드 시간이 느려지는 대신 단일 파일에 대한 반복처리형 컴파일 시간이 빨라집니다. 이 세팅은 모듈의 Build.cs 파일에서 bFasterWithoutUnity 옵션으로 덮어쓸 수 있습니다. + +$ bShadowVariableErrors (Boolean): 섀도우 변수 경고를 지원하는 플랫폼에서 오류로 강제 취급합니다. + +$ bUndefinedIdentifierErrors (Boolean): 조건절에서 미정의 식별자를 사용하는 것을 강제로 오류로 취급합니다. + +$ bUseFastMonoCalls (Boolean): 새로운 Monolithic Graphics 드라이버에 옵션 "fast calls" 가 다양한 D3d 함수를 대체하도록 합니다. + +$ bUseFastSemanticsRenderContexts (Boolean): 새로운 Xbox 드라이버가 "fast semantics" 컨텍스트 타입을 지원합니다. 이는 즉시 및 디퍼드 컨텍스트에 켜집니다. 렌더링 이슈가 있거나 Xbox RHI 에 크래시가 발생하는 경우 꺼 보세요. + +$ NumIncludedBytesPerUnityCPP (Int32): 단일 통합 C++ 파일에 포함용 타겟으로 삼을 C++ 코드 바이트 수 추정치입니다. + +$ bStressTestUnity (Boolean): 단일 통합 파일에서 프로젝트의 모든 C++ 파일을 포함시켜 C++ 유니티 빌드 안전성 스트레트 테스트를 할지 여부입니다. + +$ bForceDebugInfo (Boolean): 디버그 정보 강제 생성 여부입니다. + +$ bDisableDebugInfo (Boolean): 디버그 정보 생성을 글로벌로 비활성화시킬지 여부입니다. 구성별 및 플랫폼별 옵션은 DebugInfoHeuristics.cs 를 참고하세요. + +$ bDisableDebugInfoForGeneratedCode (Boolean): generated 파일에 대해 디버그 정보 생성 비활성화 여부입니다. generated glue 코드가 많이 있는 모듈의 링크 시간이 개선됩니다. + +$ bOmitPCDebugInfoInDevelopment (Boolean): 개발 빌드의 PC 에서 디버그 정보 비활성화 여부입니다 (개발자의 빠른 반복처리를 위한 옵션으로, 디버그 정보가 비활성화되어 있으면 링크 시간이 매우 빠르기 때문입니다). + +$ bUsePDBFiles (Boolean): Visual C++ 빌드에 PDB 파일을 사용 여부입니다. + +$ bUsePCHFiles (Boolean): PCH 파일 사용 여부입니다. + +$ MinFilesUsingPrecompiledHeader (Int32): 미리 컴파일된 헤더를 사용해야 하는 파일 수가 최소 이 이상 되어야 헤더를 생성 및 사용합니다. + +$ bForcePrecompiledHeaderForGameModules (Boolean): 활성화 시, 게임 모듈에 소스 파일이 조금밖에 없다 하더라도 미리 컴파일된 헤더를 항상 생성하도록 합니다. 프로젝트의 소수 파일에 대한 반복처리 변경 시 컴파일 시간이 크게 향상되는 대신, 작은 게임 프로젝트의 풀 리빌드 시간이 느려집니다. 모듈의 Build.cs 파일에 있는 MinFilesUsingPrecompiledHeaderOverride 세팅으로 덮어쓸 수 있습니다. + +$ bUseIncrementalLinking (Boolean): 점증적 링크 사용 여부입니다. 점증적 링크는 사소한 변경 시 반복처리 시간이 빨라질 수 있습니다. 현재 기본적으로 꺼져있는데, 일부 컴퓨터에서 버그성 동작을 보이는 경향이 있기 때문입니다 (PDB 관련 컴파일 오류). + +$ bAllowLTCG (Boolean): 링크 시간 코드 생성(LTCG) 사용 허용 여부입니다. + +$ bAllowASLRInShipping (Boolean): 주소 스페이스 레이아웃 랜덤화(ASLR) 지원 시 사용 허용 여부입니다. shipping 빌드에만 적용됩니다. + +$ bSupportEditAndContinue (Boolean): 편집 및 계속 지원 여부입니다. 32 비트 컴파일의 Microsoft 컴파일러에만 작동합니다. + +$ bOmitFramePointers (Boolean): 프레임 포인터 생략 여부입니다. 끄는 것이 PC 에서의 메모리 프로파일링 등에 유용합니다. + +$ bStripSymbolsOnIOS (Boolean): iOS 심볼을 벗겨낼지 여부입니다 (bGeneratedSYMFile 에 내포되어 있습니다). + +$ bUseMallocProfiler (Boolean): true 면 빌드에서 메모리 프로파일링이 활성화됩니다 (USE_MALLOC_PROFILER=1 정의 및 강제로 bOmitFramePointers=false 가 됩니다). + +$ bUseSharedPCHs (Boolean): "Shared PCHs" 기능을 활성화시킵니다. UBT 가 감지한 모듈끼리 특정 PCH 파일을 공유시켜 그 PCH 의 헤더 파일을 포함하도록 시도하여 컴파일 시간을 크게 향상시키는 기능입니다. + +$ bUseShippingPhysXLibraries (Boolean): Development 및 Release 빌드가 PhysX/APEX 의 release 구성을 사용해야 하는 경우 true 입니다. + +$ bUseCheckedPhysXLibraries (Boolean): Development 및 Release 빌드가 PhysX/APEX 의 checked 구성을 사용해야 하는 경우 true 입니다. bUseShippingPhysXLibraries 가 true 면 이 옵션은 무시됩니다. + +$ bCheckLicenseViolations (Boolean): UBT 가 현재 빌드중인 모듈이 EULA 를 침해하는지 여부를 검사하도록 합니다. + +$ bBreakBuildOnLicenseViolation (Boolean): UBT 더러 현재 빌드 중인 모듈이 EULA 를 침해하는지 여부를 검사하도록 합니다. + +$ bUseFastPDBLinking (Boolean): 윈도우에서 로컬 PDB 생성을 위해 /DEBUG 로 빌드 시 :FASTLINK 옵션 사용 여부입니다. 빠르지만, 현재 디버거에서 심볼을 찾는 데 문제가 있는 것 같습니다. + +$ bCreateMapFile (Boolean): 맵 파일을 빌드의 일부로 출력합니다. + +$ bEnableCodeAnalysis (Boolean): 코드 분석 모드를 켭니다. 현재, 여기에는 특별한 요건이 있습니다. 윈도우에서 MSVC 컴파일러에만 작동합니다. 또한 Visual Studio 2013 처럼 /analyze 옵션을 지원하는 컴파일러 버전이 필요합니다. + +$ BundleVersion (String): Mac 앱의 번들 버전입니다. + +$ bDeployAfterCompile (Boolean): 디플로이를 요하는 플랫폼에서 컴파일 이후 실행파일 디플로이 여부입니다. + +$ bCreateStubIPA (Boolean): true 면 컴파일 완료시 stub IPA 가 생성됩니다 (유효 IPA 를 위해서는 최소 파일이 필요합니다). + +$ bCopyAppBundleBackToDevice (Boolean): true 면 컴파일 완료시 stub IPA 가 생성됩니다 (유효 IPA 를 위해서는 최소 파일이 필요합니다). + +$ bAllowRemotelyCompiledPCHs (Boolean): 활성화 시, XGE 가 원격 머신에서 미리 컴파일된 헤더(PCH) 파일을 컴파일할 수 있도록 합니다. 아니면, PCH 는 항상 로컬에서 생성됩니다. + +$ bCheckSystemHeadersForModification (Boolean): 시기가 지난 액션을 결정할 때 시스템 경로에 있는 헤더에 대해 변경 검사를 할지 여부입니다. + +$ bDisableLinking (Boolean): 이 타겟에 대한 링크 비활성화 여부입니다. + +$ bFormalBuild (Boolean): 이 빌드는 공식 빌드이며, 배포용임을 나타냅니다. 이 플래그는 Build.version 에 changelist 가 설정된 경우 자동으로 true 설정됩니다. 현재 이 플래그에 묶인 유일한 작동방식은 OriginalFilename 칸이 올바르게 설정될 수 있도록 각 바이너리에 대해 별도로 기본 리소스 파일을 컴파일하는 것입니다. 기본적으로는 빌드 시간을 줄이기 위해 리소스는 한 번만 컴파일합니다. + +$ bFlushBuildDirOnRemoteMac (Boolean): 빌드 전 원격 Mac 의 Builds 디렉토리를 비울지 여부입니다. + +$ bPrintToolChainTimingInfo (Boolean): 컴파일러와 링커의 자세한 타이밍 정보를 쓸지 여부입니다. + +$ PCHOutputDirectory (String): 미리 컴파일된 헤더(PCH) 파일을 넣을 디렉토리입니다. 속도가 더 빠른 드라이브의 경로를 사용할 수 있도록 하기 위한 실험단계 세팅입니다. 설정되지 않으면 기본값은 표준 출력 디렉토리입니다. + +$ GlobalDefinitions (List<String>): 전체 타겟에 대한 글로벌 정의를 위한 매크로입니다. + +$ ExtraModuleNames (List<String>): 타겟에 컴파일시킬 부가 모듈 목록입니다. + +$ BuildEnvironment (TargetBuildEnvironment): 이 타겟에 대한 빌드 환경을 지정합니다. 사용 가능 옵션에 대한 상세 정보는 TargetBuildEnvironment 를 참고하세요. + +$ OverrideExecutableFileExtension (String): 설정하면 실행파일 확장자를 덮어쓸 수 있습니다 (예를 들어 윈도우에서는 보통 .exe 또는 .dll 입니다). + + diff --git a/Engine/Documentation/Source/Programming/UnrealBuildSystem/UnrealBuildSystem.JPN.udn b/Engine/Documentation/Source/Programming/UnrealBuildSystem/UnrealBuildSystem.JPN.udn index 3d025b3d17fb..e0d083e17679 100644 --- a/Engine/Documentation/Source/Programming/UnrealBuildSystem/UnrealBuildSystem.JPN.udn +++ b/Engine/Documentation/Source/Programming/UnrealBuildSystem/UnrealBuildSystem.JPN.udn @@ -1,87 +1,67 @@ -INTSourceChangelist:3336766 +INTSourceChangelist:3372845 Availability:Public Title:アンリアル ビルド システムの設定 Crumbs: Description:エンジンとゲーム プロジェクトをコンパイルするアンリアル・エンジンのカスタムビルドシステム -version:4.9 +version:4.15 parent:Programming -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Programming/UnrealBuildSystem:title%](Engine/build_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/build_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Programming/UnrealBuildSystem:title% - [/PARAM] - [PARAM:description] - %Programming/UnrealBuildSystem:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Programming/UnrealBuildSystem] - [/PARAM] -[/OBJECT] -[/VAR] +tags:Programming +tags:Unreal Build System +type:overview +topic-image:Engine/build_topic.png + +[TOC (start:1 end:3)] [REGION:fullwidth] ![Unreal Build System](build.png) [/REGION] -### UnrealBuildTool -**UnrealBuildTool** (UBT) は、多数の可能なビルド コンフィギュレーションにおいて **アンリアル エンジン 4** (UE4) ソース コードのビルド プロセスを管理するカスタム ツールです。ユーザー設定可能な様々なビルド オプションについては、 -BuildConfiguration.cs で確認してください。 +**アンリアル ビルドシステム** とは、アンリアル エンジン 4 (UE4) のビルド プロセス自動化ツールのコレクションです。ハイレベルでは、UnrealBuildTool と UnrealHeaderTool はアンリアル ビルド システムをサポートします。 +このガイドは、UE4 のモジュラー アーキテクチャに関する簡単な考察も交えながら、UnrealBuildTool と UnrealHeaderTool の概要を説明します。ビルド ツールのこのコレクションを使用したい方のために、 +プロジェクト用にアンリアル ビルド システムを分かりやすくセットアップ / 設定できる操作ガイドが含まれています。終盤には、Include-What-You-Use (IWYU) 依存モデルと BuildGraph スクリプティング システムをさらに学習したい上級ユーザー向けのガイドがあります。 [REGION:note] Mac OS X で UnrealBuildTool や UnrealAutomationTool をデバッグする場合は、以下を必ずインストールしてください。[MonoDevelop 4.2.2](http://monodevelop.com/Download) および [Mono 3.2.7](http://www.go-mono.com/mono-downloads/download.html) [/REGION] -### UnrealHeaderTool -**UnrealHeaderTool** (UHT) は、UObject システムをサポートするカスタム パー寝具およびコード生成のツールです。コードのコンパイルは以下の 2 つのフェーズで行われます。 +## UnrealBuildTool + +UnrealBuildTool (UBT) は、様々なビルド コンフィギュレーションの UE4 ソース コードのビルド プロセスを管理するカスタム ツールです。ユーザー設定可能な様々なビルド オプションについては、 +`BuildConfiguration.cs` で確認してください。 + +## UnrealHeaderTool + +**UnrealHeaderTool** (UHT) は、UObject システムをサポートするカスタムのパースおよびコード生成のツールです。コードのコンパイルは以下の 2 つのフェーズで行われます。 1. UHT が呼び出されると、Unreal 関連のクラスのメタデータの C++ ヘッダーをパースし、様々な UObject 関連の機能を実装するためのカスタム コードを生成します。 1. 結果をコンパイルするために通常の C++ コンパイラが呼び出されます。 コンパイル時に、いずれかのツールがエラーを排出するため、注意深く見るようにしてください。 -### Project Files -ビルド プロセスは、Visual Studio の .sln や .vcproj などの開発環境のプロジェクト ファイルとは関係なく起こります。しかし、こうしたファイルは編集目的には役立ちます。 -そのため、プロジェクトのディレクトリ ツリーの内容に基づき、こうしたファイルを動的に生成するためのツールがあります。このツールは `[Root UE4]` ディレクトリにある [GenerateProjectFiles](Programming\UnrealBuildSystem\ProjectFileGenerator) バッチ ファイルで実行することができます。 - ディスクに追加またはディスクから削除したコード ファイルと、コード エディタとの同期を保つために、時々、このバッチファイルを実行するといろいろと便利です。 +## モジュール アーキテクチャ -### モジュール アーキテクチャ -UE4 は多くのモジュールに分かれています。各モジュールには、.build.cs ファイルがあり、モジュールの従属関係、追加のライブラリ、インクルード パスなどを定義するためのオプションなど、ビルド方法を制御します。 +UE4 は多くのモジュールに分かれています。各モジュールには、`.build.cs` ファイルがあり、モジュールの従属関係、追加のライブラリ、インクルード パスなどを定義するためのオプションなど、ビルド方法を制御します。デフォルトで、こうしたモジュールはダイナミック リンクライブラリ (DLL) にコンパイルされ、単一の実行可能ファイルによってロードされます。`BuildConfiguration.cs` ファイルでモノリシック (単一) 実行ファイルをビルドするように選択できます。 -デフォルトで、こうしたモジュールはダイナミック リンクライブラリ (DLL) にコンパイルされ、単一の実行可能ファイルによってロードされます。BuildConfiguration.cs ファイルでモノリシック (単一) 実行ファイルをビルドするように選択できます。 +## アンリアル ビルド システムの使用方法 -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/start_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - Essentials - [/PARAM] - [PARAM:description] - [/PARAM] - [PARAM:links] - * [](Programming/UnrealBuildSystem/ProjectFileGenerator "%Programming/UnrealBuildSystem/ProjectFileGenerator:description%") - * [](Programming/Development/BuildingUnrealEngine "%Programming/Development/BuildingUnrealEngine:description%") - [/PARAM] -[/OBJECT] +アンリアル ビルド システムを使用する前に、ビルド プロセスは、Visual Studio の `.sln` や `.vcproj` ファイルなどの開発環境のプロジェクト ファイルとは独立して実行されるということを理解することが重要です。しかし、こうしたファイルは編集目的には役立ちます。 +そのため、プロジェクトのディレクトリ ツリーの内容に基づき、こうしたファイルを動的に生成するためのツールがあります。このツールは `[Root UE4]` ディレクトリにある `GenerateProject.bat` ファイルで実行することができます。 -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/profile_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - セットアップとコンフィギュレーション - [/PARAM] - [PARAM:description] - [/PARAM] - [PARAM:links] - * [](Programming/UnrealBuildSystem/Configuration "%Programming/UnrealBuildSystem/Configuration:description%") - * [](Programming/UnrealBuildSystem/TargetFiles "%Programming/UnrealBuildSystem/TargetFiles:description%") - [/PARAM] -[/OBJECT] +[REGION:tip] +`GenerateProject.bat` を時々実行すると、ディスクからファイルが追加 (または削除) され、コード エディタが常に最新の状態になります。 +[/REGION] +### セットアップ + +%Programming/UnrealBuildSystem/ProjectFileGenerator:topic% +%Programming/Development/BuildingUnrealEngine:topic% + +### コンフィギュレーション + +%Programming/UnrealBuildSystem/Configuration:topic% +%Programming/UnrealBuildSystem/TargetFiles:topic% + +## 高度なトピック + +%Programming/UnrealBuildSystem/IWYUReferenceGuide:topic% +%Programming/Development/BuildGraph:topic% diff --git a/Engine/Documentation/Source/Programming/UnrealBuildSystem/UnrealBuildSystem.KOR.udn b/Engine/Documentation/Source/Programming/UnrealBuildSystem/UnrealBuildSystem.KOR.udn index b536de2b0809..ad9ae8541a92 100644 --- a/Engine/Documentation/Source/Programming/UnrealBuildSystem/UnrealBuildSystem.KOR.udn +++ b/Engine/Documentation/Source/Programming/UnrealBuildSystem/UnrealBuildSystem.KOR.udn @@ -1,9 +1,9 @@ -INTSourceChangelist:3356804 +INTSourceChangelist:3372845 Availability:Public Title: 언리얼 빌드 시스템 Crumbs: Description:엔진 및 게임 프로젝트를 컴파일하는 데 사용되는 언리얼 엔진의 커스텀 빌드 시스템입니다. -version:4.9 +version:4.15 parent:Programming tags:Programming tags:Unreal Build System @@ -63,4 +63,5 @@ UE4 는 다수의 모듈로 나뉘어 있습니다. 각 모듈에는 .build.cs ## 고급 토픽 -%Programming/UnrealBuildSystem/IWYUReferenceGuide:topic%%Programming/Development/BuildGraph:topic% +%Programming/UnrealBuildSystem/IWYUReferenceGuide:topic% +%Programming/Development/BuildGraph:topic% diff --git a/Engine/Documentation/Source/Resources/ContentExamples/NavMesh/1_2/1_2.KOR.udn b/Engine/Documentation/Source/Resources/ContentExamples/NavMesh/1_2/1_2.KOR.udn index 89fa77f99a5c..6588b1a4f6b4 100644 --- a/Engine/Documentation/Source/Resources/ContentExamples/NavMesh/1_2/1_2.KOR.udn +++ b/Engine/Documentation/Source/Resources/ContentExamples/NavMesh/1_2/1_2.KOR.udn @@ -70,7 +70,7 @@ Version: 4.9 ![](Resources\ContentExamples\NavMesh\NavMesh_banner.png) [/REGION] -**NavLinkProxy** (내비 링크 프록시) 액터는 폰이 점프하거나 타고 내려갈 수 있는 턱(ledge)을 지정하는데 사용되는 것으로, **내비메시** 안에 단절된 부분을 건너기 위해 잠시 떠날 수 있도록 해 줍니다. 시작점과 끝점을 지정하면 패쓰 노드인 것처럼 간주됩니다. 이 예제에서 폰은 **NavLinkProxy** 의 시작점으로 이동한 뒤 경사로를 타고 끝점까지 이동, **내비메시** 상에 목적지를 향한 내비게이션을 계속합니다. 이 **NavLinkProxy** 는 단방향으로 구성되어 있어, 폰이 되돌아 갈 때는 **NavLinkProxy** 를 사용하기 보다는 경사로를 돌아 갑니다. +**NavLinkProxy** (내비 링크 프록시) 액터는 폰이 점프하거나 타고 내려갈 수 있는 턱(ledge)을 지정하는데 사용되는 것으로, **내비메시** 안에 단절된 부분을 건너기 위해 잠시 떠날 수 있도록 해 줍니다. 시작점과 끝점을 지정하면 패스 노드인 것처럼 간주됩니다. 이 예제에서 폰은 **NavLinkProxy** 의 시작점으로 이동한 뒤 경사로를 타고 끝점까지 이동, **내비메시** 상에 목적지를 향한 내비게이션을 계속합니다. 이 **NavLinkProxy** 는 단방향으로 구성되어 있어, 폰이 되돌아 갈 때는 **NavLinkProxy** 를 사용하기 보다는 경사로를 돌아 갑니다. [REGION:lightbox] [![](NavMesh_1_2_001.png)(w:225)](NavMesh_1_2_001.png) diff --git a/Engine/Documentation/Source/Resources/Showcases/PhotorealisticCharacter/TwinblastBust.CHN.udn b/Engine/Documentation/Source/Resources/Showcases/PhotorealisticCharacter/TwinblastBust.CHN.udn new file mode 100644 index 000000000000..fb97b94eb198 --- /dev/null +++ b/Engine/Documentation/Source/Resources/Showcases/PhotorealisticCharacter/TwinblastBust.CHN.udn @@ -0,0 +1,395 @@ +INTSourceChangelist:3403466 +Availability:Public +Title:照片级角色 +Crumbs:%ROOT%, Resources +Description:照片级角色半身像展示的总览。 +Related:Engine/Rendering/Materials +Related:Engine/Rendering/Materials/PhysicallyBased +Related:Engine/Rendering/Materials/LayeredMaterials +Version:4.15 +topic-image:PhotorealHead.png +social-image:PhotorealHead.png + + +[TOC(start:2 end:3)] + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + K-VyoqRB5_g + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +此展示旨在体现高精度角色着色器技术的使用。这些技术与 Epic 的 MOBA 游戏 Paragon 中角色使用的技术相似。打开项目,按下 Play In Editor 即可查看动画演示。 + +如需了解用于制作此角色技术的更多信息,请观看此视频 [Unreal Engine Livestream - Tech & Techniques Behind Creating the Characters for Paragon](https://www.youtube.com/watch?v=toLJh5nnJA8)。 + +## 皮肤着色 + +角色的皮肤使用 UE4 的 [次表面配置着色模型](Engine/Rendering/Materials/LightingModels/SubSurfaceProfile/)。 + + +![](Skin.png)(w:700 convert:false) + +使用了 [材质函数](Engine/Rendering/Materials/Functions/) 设置皮肤材质的基础。这作为一种可重复使用的制作方法创建 Paragon 的材质。根据此法,美术师可标准化特定类型表面的生成方法。对单个函数进行的基础修改将更新此函数使用之处的所有实例。 + +### 皮肤着色器纹理 + +用于角色皮肤上的纹理分辨率均为 4K,最初由演员面部扫描生成。之后纹理经 Epic 美术师清理并调整。此纹理设置共利用了五种纹理贴图:弥散、粗糙、反射、散射,以及法线。 + +| 纹理 | 名称 | 描述 | +|---------|------|-------------| +|![](SkinDiffuse.png)(w:200 convert:false)|**Diffuse**|弥散贴图为材质提供基色。在 4K 分辨率下,皮肤下的毛细血管均清晰可见。深色的皱纹则能突出法线贴图提供的纹理。(*UE4_Demo_Head_D*)| +|![](SkinRough.png)(w:200 convert:false)|**Roughness**|粗糙贴图保存在弥散纹理的透明通道中。这个常用技术可将使用中的纹理量保持到最低。注意粗糙度在毛孔和皱纹中会有所增加。这会导致这些区域缺乏光亮度,突出弥散和法线贴图带来的深度感。此外还需注意头发纹理的粗糙度为 1.0,防止头皮带来杂散反射高光,并为头发带来更强的深度感。(*UE4_Demo_Head_D*)| +|![](SkinSpec.png)(w:200 convert:false)|**Specular**|反射贴图控制皮肤表面可见的反射高光量。需要注意的是默认反射值为 0.5。此贴图将提升皮肤拉伸更紧之处的反射度,并降低不需要反射之处的反射度(如毛孔中心和皱纹之中)。(*CH2_exp04_merged_spec_f_FC_FINAL*)| +|![](SkinScatter.png)(w:200 convert:false)|**Scatter**|散射贴图控制散射透过皮肤表面的光照量。暗处区域展示出的散射极少(如脸颊),而明亮区域则能感受到更大量的散射(如鼻子和耳朵)。散射颜色则由 [次表面配置文件资源](Engine/Rendering/Materials/LightingModels/SubSurfaceProfile/) 进行管理 (*UE4_Demo_Head_BackScatter*)| +|![](SkinNormal.png)(w:200 convert:false)|**Normal**|法线贴图在常规材质设置中功能正常,扰乱像素法线为表面提供触觉纹理。其设置在此例中并无特殊之处。(*UE4_Demo_Head__normals*)| + + +## 头发着色 + +头发着色由 UE4 的头发着色器模型处理。此着色器是基于物理的着色模型,以 [Eugene d'Eon、Steve Marschner 和 Johannes Hanika] 的研究为基础。[Weta Digital](http://www.wetafx.co.nz/research) 现今正在使用此着色器。着色器通过各向异性反射近似出头发表面的光反射、穿过头发的折射,以及通过多条发缕的散射。 + +将材质的 **Shading Model** 属性设为 **Hair** 即可使用 UE4 头发着色器。 + + +![](HairSM.png) + +### 头发和反射 + +在真实世界中,头发通常有多个镜面反射高光:一个代表光的颜色,另一个则是头发颜色和光颜色的混合。在此文档中,我们将它们称为主要和次要反射高光。头发着色器可近似出高度真实的相同效果。 + +![](TwinblastHair_Specs_Diagram.png)(w:700 convert:false) +[REGION:caption]1.更亮的头发代表主要反射高光。2.更亮的红色头发代表次要反射高光。[/REGION] + +UE4 的头发着色器中使用的近似算法以类似真实世界的方式来创建这些效果。光线照到毛囊表面时不会反射开。头发为半透明,部分光线能够*穿过*它,并可能在其中四处反射,然后退出。头发着色器和头发进行交互时通过光线可能行进的三条通道进行近似,如下方的动态 GIF 图表所示: + +![](HairDiagram.gif)(w:700 convert:false) +[REGION:caption]单个毛囊的相交部分显示头发着色器近似与光线交互的方式,体现光线所采用路径的三个主要类型。请参阅下表中此进程每个部分的描述。[/REGION] + +| 数字 | 描述| +|--------|-------------| +|0.|毛囊的延展方向(从根到梢)。| +|1.|仅限反射的通道,光线会在头发表面形成反弹。这能产生主要反射高光。| +|2.|传播-传播通道,光线通过此通道传入毛囊并从另外一侧退出。这是光线在大量头发中进行散射的方式。| +|3.|传播-反射-传播通道,光线通过此通道进入毛囊,在表面的边界中反射开,然后退出。这能产生次要反射高光。| + +如上方图表所示,一缕发丝并非是完美的圆柱体或管道状。事实上,头发的形状更像是一系列堆叠起来的圆锥体。这意味着从头发表面反射开的光线散射与完美平滑头发所形成的散射有所不同。更进一步而言,每根头发均指向不同的方向,因此反射高光不会被统一,但将基于头发指向的方向进行独立放置。这通常被称作*各向异性*反射,UE4 头发着色器同样支持此特性。 + +### 头发和透明 + +头发着色器使用遮罩混合模式替代半透明。然而,遮罩半透明将生成一个二进制结果——表面为完全不透明或完全透明。噪点递色图案不断在表面上移动,需要突出实心的区域更为密集。递色被用作混合遮罩透明的一种方式,但只在 TemporalAA 启用时生效。 + +[OBJECT:ComparisonSlider] +[PARAM:before] +![Without TemporalAA](Hair_AAOff.png)(w:700 convert:false) +[/PARAM] +[PARAM:after] +![With TemporalAA](Hair_AAOn.png)(w:700 convert:false) +[/PARAM] +[/OBJECT] + +[REGION:note]结合 TemporalAA 使用动态递色需要数帧来进行混合。头发处于动态时可能出现一些穿帮。这是该技术的正常负面效果。[/REGION] + +#### 边缘遮罩 + +![](EdgeMaskGraph.png)(w:700 convert:false) + +虽然并非是着色器本身的一部分,但仍然值得一提的是用于范例角色头发、以及 Epic 游戏*Paragon*中其他角色的材质使用名为“边缘遮罩(Edge Mask)”的技术在头发侧对摄像机时将其淡化。因为头发作为一系列的片进行渲染——参见下方 [头发和几何体](#hairgeometry),因此从一些特定的摄像机角度可能看到每个片的边缘,破坏头发效果。 + +为减轻此问题,材质在表面垂直旋转离开摄像机时计算摄像机相对于顶点法线的矢量,它还将淡出至完全透明。然而此方法的另一个方面时执行此操作头发着色器可能显示更多头皮。这是拥有较厚头发角色的头皮上通常绘有头发纹理的原因。如下图所示。 + +![](HairPaint.png)(w:700 convert:false) + + +[REGION:tip]需要指出的是此效果与 Quality Switch 节点相关联,因此在低性能平台上它可能会容易被关闭,以换取一些着色器性能。如常,推荐在目标平台上进行测试。[/REGION] + + + + + +### 头发创建 + +使用此展示中的技术创建头发需要理解 Epic 构建此角色头发的方式。 + +(#hairgeometry) +#### 头发几何体 + +使用 UE4 头发着色器的头发几何体通常使用一系列非平面的片表面,这是诸多实时头发解决方案中的一个常见方法。它们能在您选择的 DCC 应用中进行制作。 + +[REGION:note]头发几何体细节不存在一成不变的规则,但需要注意的是此角色使用大约 800 个发片,总共约 18000 个三角形。还需要注意头发材质在主材质节点的属性中被设为两面。[/REGION] + +![](HairSheets.png)(w:700 convert:false) + + +#### 头发纹理 + +在 UE4 头发着色器的此使用实例中,最终结果由五个主要纹理构成:*Diffuse*、*Alpha*、*Root*、*Depth* 和每缕独立的 *ID* 纹理。在 Epic,这些纹理通常使用 3ds Max 的头发系统生成,将模拟的头发结果投射到一块几何体上。然而,相似结果拥有多个可用选项。 + + +| 纹理 | 名称 | 描述 | +|---------|------|-------------| +|![](Diffuse.png)(w:200 convert:false)|**Diffuse**|弥散纹理提供头发中主要的弥散或*基础*颜色、有时最好不对此纹理进行着色,通过参数驱动其颜色,角色头发可能染上多种不同颜色时尤为如此。(*UE4_Demo_Hair_D*)| +|![](Alpha.png)(w:200 convert:false)|**Alpha**|Alpha 纹理为头发提供不透明区域,隐藏发缕主体外的几何体。(*UE4_Demo_Hair_A*)| +|![](Root.png)(w:200 convert:false)|**Root**|Root 纹理提供一个遮罩,用于变更从发根至发梢的颜色,可调亮或变暗头发。(*UE4_Demo_Hair_Roots*)| +|![](Depth.png)(w:200 convert:false)|**Depth**|Depth 纹理由 Pixel Depth 偏移所用,使头发获得深入发卷的特征。它也可用作变更不同深度头发颜色或着色值的基础,如在头发朝头皮方向移动时减少整体反射。(*UE4_Demo_Hair_Depth*)| +|![](ID.png)(w:200 convert:false)|**Unique ID**| Unique ID 纹理为给定头发几何体提供一个独一的 0 到 1 之间(黑到白)的值。这用于在头发自身之中提供细微的变化。(*UE4_Demo_Hair_ID*)| + + + +### 头发着色器属性 + +使用头发着色器时用户可看到主材质节点中有一些新属性可用:**Scatter**、**Tangent** 和 **Backlit**。 + +![](HairProperties.png) + +[REGION:warning]在撰写此文档时(版本 4.13),Backlit 属性只作为着色器早期版本的一部分而存在。与其的连接不会由头发着色器内部使用,因此可无视属性。[/REGION] + +#### Scatter + +我们将头发着色器视作*近似*而非*模拟*的其中一个主要原因是事实上并未对每缕单独的发丝进行模拟,也未完美模拟精确的光照行为。在真实世界中,光线从头发毛囊反射开并进行传播时,它会经常遭遇*其他*发缕,可能连续多次重复相同进程。此时没有计算系统能够准确生成此类实时模拟的效果。 + +然而,光线散射通过头发形体的方式仍然决定着头发的在游戏中真实感(是否与真实世界相似)。为进行控制,头发着色器提供了 Scatter 属性,替代主着色器节点上的 Metallic,值限定在 0.0 和 1.0 之间。Scatter 控制通过角色头发整个主体(将其视为单个表面)的光线量。 + +关于 Scatter 重要的一点是,它会比浅色头发更亮,比深色头发更暗。这将遵循自然世界的物理规则,因为深色头发将吸收更多光线。在实际操作中,如果尝试创建一个金发角色,只修改弥散纹理或颜色不够,也需要增加 Scatter 数值。 + + +[OBJECT:ComparisonSlider] +[PARAM:before] +![Scatter value of 0.0](Scatter_0.png)(w:700 convert:false) +[/PARAM] +[PARAM:after] +![Scatter value of 1.0](Scatter_1.png)(w:700 convert:false) +[/PARAM] +[/OBJECT] +[REGION:caption]在此例中发根和发梢颜色被设为偏白的金色,Random Variation 设为 0.0。Scatter 则用于调整被近似通过头发的光线量。这能说明通过修改 Scatter 值能生成多少种色调的头发。[/REGION] + +#### Tangent + +Tangent 属性替代了头发着色器上的 Normal 属性。切线作为与每缕头发平行运行的矢量进行计算,指回到发根。Tangent 属性的作用是帮助形成适当的各向异性反射。在此解释一番,各向异性反射是光线从带微小槽的表面(如拉丝金属)反弹开时出现的效果。 + +![](AnisoVsNonAniso.png)(w:700 convert:false) +[REGION:caption]左侧球体为各向异性着色,右侧球体则不是。您可发现各向异性发射高光沿表面伸展。[/REGION] + +Tangent 属性主要用作为矢量,控制各向异性高光伸展的方向。 + +![](HairTangent.png)(w:700 convert:false) +[REGION:caption]此图中的黄线代表沿发缕的切线,指回发根。[/REGION] + +[REGION:tip]在范例角色的头发着色器中,此矢量被赋予 Z 轴中 0.3 和 -0.3 之间的一个随机偏移(使用 Unique ID 纹理)。这将生成一个矢量(其在圆弧中拥有一个随机方向),有助于提供各向异性反射高光中的变化(如在一束真实头发中拥有的效果)。[/REGION] + +切线可以两种方式进行映射:自动映射或流型图。自动法要求每个头发片的纹理按发根朝向发梢朝下进行朝向。只要头发较短且片不存在弯曲和过度扭曲,这种方法便适用。此法用于范例角色的头发。 + +##### 相切流型图 + +另一种方法需要创建流型图。如角色头发较长且弯曲,需拥有比实际几何体更加卷曲的效果,或头发的单个纹理部分朝向不同方向(并非上文所述的上至下)。流型图代表头发在切线空间中或沿表面移动的方向。Photoreal Character Bust 项目中有一个名为 *T_Hair_Flow* 的未使用流型图。下方是流型图和反射结果的对比。 + +[OBJECT:ComparisonSlider] +[PARAM:before] +![Final Result](SparowFlowMap.png)(w:600 convert:false) +[/PARAM] +[PARAM:after] +![Flow Map Texturing](SparowFlowMap2.png)(w:600 convert:false) +[/PARAM] +[/OBJECT] +[REGION:caption]此处展示了流型图沿 Sparrow 头发表面进行的纹理设置。注意:流型图只用于部分头发片上,并非头发的整个主体上。注意:沿流型图的不同数值将细微地改变沿头发的反射。[/REGION] + + + + +#### 使用头发着色器的像素深度偏差 + +像素深度偏差(PDO)并非头发着色器的特有属性。通俗而言,PDO 使像素拥有凹陷效果(远离摄像机),沿表面形成一种虚拟的景深感。因为头发由简单的几何体片组成(如下文中 [头发和几何体](#hairgeometry) 所述),因此使用 PDO 能为头发整个形体带来一种切实的景深感。它还将打破头发几何体面与头皮相交的交叉点,如下图所示。 + +[OBJECT:ComparisonSlider] +[PARAM:before] +![Without Pixel Depth Offset](PDO_off.png)(w:700 convert:false) +[/PARAM] +[PARAM:after] +![With Pixel Depth Offset](PDO_On.png)(w:700 convert:false) +[/PARAM] +[/OBJECT] + + + + +## 眼睛着色 + +![](EyeShading2.png)(w:700 convert:false) + +眼睛通常被称作“灵魂的窗户”。观者对人的印象主要来自眼睛,其他方面难以匹及。UE4 中的眼睛着色器提供眼睛表面的真实渲染,对眼睛的每个生理部分进行艺术把控。 + +[REGION:warning]UE4 中的眼睛着色器技术含量很高,开发过程使着色器代码、材质、几何体形体和几何体的 UV 布局之间存在 **极强的相依性**。如无着色器开发的丰富经验,**不** 建议使用此着色器从零开始构建眼睛。为达目的,我们强烈建议用户在创建真实人眼时提取此范例中的眼睛几何体,并使用眼睛材质 **as-is** 替换相应纹理。 [/REGION] + +[REGION:tip]Photoreal Character 项目中有一个名为 **PhotorealEyeGeo** 的静态网格体。这能通过 FBX 从项目导出到您选择的 DCC 应用中,以便在您自建的项目中使用。[/REGION] + +### 眼睛生理结构 + +为完全理解眼睛的特性,最好对眼睛生物学进行一定的了解。此处可见的每个部分均在此眼睛设置中被表示,所有部分均可使用应用至范例角色眼睛的材质实例中的公开参数进行修改。 + +以下进行快速讲解: + +![](EyeDiagram.png)(w:700 convert:false) +|数字|名称|描述| +|------|----|-----------| +|1|巩膜|巩膜也称“眼白”。眼睛的这个区域通常十分湿润,拥有少量的触感纹理。| +|2|角膜缘|角膜缘是虹膜和巩膜之间深色环状区域。某些眼睛的该部分会比其他眼睛更为突出,从侧面进行观察看时通常会淡化。 +|3|虹膜|虹膜是眼睛中心周围的色彩环状区域。一个人拥有“绿色”眼睛,指的是虹膜主要是绿色。在真实人眼中,虹膜是可延展和收缩的肌肉状纤维组织,使光线进入瞳孔,或减少进入瞳孔的光线。还需要注意的是在真实世界中,虹膜实际上是碟状或圆锥状,不会凸出眼睛的其他部分。| +|4|瞳孔|瞳孔是眼睛中心的深色点。它是光线传入的洞,使视网膜的视杆细胞和视锥细胞能够接收到光线。 +|5|角膜|角膜是虹膜之上充满液体的透明圆顶物。| + +### 眼睛中的折射——过去与现在 + +眼球充满液体,因此它将对穿过其中的光线产生折射。在真实世界中从多个角度查看眼睛时能发现折射。虹膜和瞳孔将因折射而扭曲,因为是通过角膜进行观察。在游戏和电影中解决此问题的传统方法是创建两个单独的眼睛表面:一个提供巩膜、虹膜和瞳孔;另一个表面在此之上,提供角膜和眼睛的整体湿润度。这能够产生折射,因为下层表面将通过湿润层进行观察。此方法应用在 Epic *男孩和他的风筝*技术 demo 中男孩的眼睛上。下方图表展示了两个表面。 + +![](KiteBoyEyes.png)(w:700 convert:false) + +然而,使用全新的眼睛着色器可通过*单层表面*实现更为真实的效果。通过角膜表面的光线折射现在完全在着色器中进行处理,减少对下方几何体的需求。打开 *MI_EyeRefractive_Bust* 材质实例,调整 **Refraction On/Off** 属性即可对此进行试验。 + +[OBJECT:ComparisonSlider] +[PARAM:before] +![Without Refraction|(Refraction On/Off at 0.0)](NotRefracting.png)(w:700 convert:false) +[/PARAM] +[PARAM:after] +![With Refraction|(Refraction On/Off at 1.0)](Refracting.png)(w:700 convert:false) +[/PARAM] +[/OBJECT] + +### 眼睛着色器参数 + +眼睛着色器较为复杂,推荐使用默认,因此我们在此对材质内置的艺术效果参数进行解析。以下是可在 *MI_EyeRefractive_Bust* 材质实例常量中进行调整的眼睛着色器参数。还将在所有可能的位置纳入建议的参数范围。 + +![](MI_EyeRefractive_Bust.png) + +|名称|描述|建议值范围| +|----|-----------|-------------------| +|[REGION:tablesection]静态切换参数值[/REGION]||| +|**UseEyeBulge**|此属性基于眼球几何体是否使用角膜凸起的物理模型调整着色器的反射属性。|n/a| +|[REGION:tablesection]矢量参数值[/REGION]||| +|**Sclera inner color**| 这是巩膜与虹膜相交时的颜色。|n/a| +|**Sclera outer color**| 这是巩膜在眼睛外边缘的颜色。|n/a| +|**SecondaryEnvBalance**| 此值控制眼睛表面上可见 [次要环境](#eyeshadersecondaryenvironment) 的量。|0.00 - 0.03| +|**SecondaryEnvRotationAxis**| [次要环境](#eyeshadersecondaryenvironment) 是虚拟反射,因此它必须围绕眼睛手动旋转。此属性控制旋转的轴。| <0.0, 0.0, 1.0> (Z 轴)| +|[REGION:tablesection]标量参数值[/REGION]||| +|**Depth Scale**| 此值控制角膜下虹膜反射的深度。|1.0-1.4| +|**Flatten Normal**| 此值控制眼睛法线贴图发生的扁平,注重于巩膜。|0.9 - 1.1| +|**IoR**|角膜下液体的折射索引。控制发生的折射量。|1.336| +|**Iris Concavity Power**| 与 *Iris Concavity Scale* 共用,控制光线通过角膜时在虹膜表面上计算出的光线焦散的形态和量。在通常只在实际照亮的场景中可见,难以在材质实例编辑器中显现。|0.2 - 0.3| +|**Iris Concavity Scale**| 与 *Iris Concavity Power* 共用,控制光线通过角膜时在虹膜表面上计算出的光线焦散的形态和量。在通常只在实际照亮的场景中可见,难以在材质实例编辑器中显现。|0.07 - 0.15| +|**Iris UV Radius**| 控制眼球上虹膜的整体大小。|0.14 - 0.15| +|**Iris Brightness**| 控制虹膜的亮度。| *基于虹膜的颜色* | +|**Iris Roughness**| 此值决定虹膜之上角膜的亮度。| 0.0 - 0.1 | +|**Limbus Dark Scale**| 控制角膜缘深色环状区的大小。| 2.0 - 2.15 | +|**Limbus Pow**| 控制角膜缘区域的整体暗度。过高的数值将使整个角膜缘区域变暗。| 15.0 - 22.0 | +|**Limbus UV Width Color**| 控制角膜缘的范例采样大小,或用于显示角膜缘所分配的眼睛表面的量。这是一个十分精妙的设置,进行调整是应多加考虑。| 0.025 - 0.040 | +|**Limbus UV Width Shading**| 控制光线对角膜缘着色影响的程度。十分精妙的设置,调整时需深思熟虑。| 0.040 - 0.050 | +|**Normal UV Scale**| 控制眼睛表面上法线贴图纹理的大小。| 1.8 - 2.6 | +|**Pupil Scale**| 控制瞳孔的大小。这是用于扩大眼睛的设置。| 0.5 - 1.0 | +|**Refraction On/Off**| 在着色器的折射和非折射版本之间进行混合。| 1.0 | +|**Scale By Center**| 从中心调整整个虹膜/瞳孔区域的大小。| 0.8 - 1.2 | +|**Sclera Brightness**| 控制巩膜(或眼白)的明亮度。| 0.9 - 1.3 | +|**Sclera Roughness**| 控制巩膜的材质粗糙度数值| 0.0 - 0.1 | +|**Secondary Env Rotation**| 此项沿使用 SecondaryEnvRotationAxis 属性所定义的轴旋转 [次要环境立方体贴图](#eyeshadersecondaryenvironment)。| n/a | +|**Shadow Hardness**| 控制巩膜内外颜色之间混合的锐度。使用 Shadow Radius 驱动巩膜表面的着色,近似出眼睑在眼球表面投射下表面散射阴影的效果。| 0.1 - 0.2 | +|**Shadow Radius**| 控制巩膜内外颜色之间混的的大小。结合 Shadow Hardness 使用。| 0.5 - 0.85 | +|**Specularity Iris**| 控制角膜上(虹膜和瞳孔)的反射等级。| 0.25 - 0.8 | +|**Specularity Sclera**| 控制巩膜上的反射等级。| 0.25 - 0.8 | +|**Veins**| 控制由 Sclera Color Map 提供的眼睛静脉的可见度。| *基于 Sclera Color Map 和所需的静脉量。*| +|[REGION:tablesection]纹理参数值[/REGION]||| +|**Iris Color**| 参见下方的 [眼睛纹理](#eyetextures)。| n/a | +|**Normal Map**| 参见下方的 [眼睛纹理](#eyetextures)。| n/a | +|**Sclera Color**| 参见下方的 [眼睛纹理](#eyetextures)。| n/a | +|**Secondary Env**| 这是用作次要反射环境的立方体贴图。参见下方的 [眼睛着色器次要环境](#eyeshadersecondaryenvironment)。| n/a | + + +(#eyeshadersecondaryenvironment) +#### 眼睛着色器次要环境 + +次要环境是眼睛着色器的一部分,为眼睛表面提供虚拟的反射贴图。可使用着色器中的 SecondaryEnv ParamCube 为其提供一个纹理,然后使用其他 SecondaryEnv 属性进行控制。在眼睛的高度特写中十分实用,可观察到特定的反射,如直接环境、另一个角色等。 + +[OBJECT:ComparisonSlider] +[PARAM:before] +![Without Secondary Environment|(SecondaryEnvBalance at 0.0)](SecondaryEnvOFF.png)(w:700 convert:false) +[/PARAM] +[PARAM:after] +![With Secondary Environment|(SecondaryEnvBalance at 0.03)](SecondaryEnvON.png)(w:700 convert:false) +[/PARAM] +[/OBJECT] + +### 眼睛制作 + +之前在此章节中我们已经提到眼睛着色器代码、材质设置和眼睛网格体几何体之间有极强的相依性。以下高级总览将说明眼睛设置为何如此特殊,这些内容有助于将几何体替换为用户自建的角色眼睛模型。 + +自建眼睛时,我们 **强烈** 推荐此范例中的实际眼睛几何体和材质。此处提供的大多数信息均基于已使用范例中资源的假设。 + +[REGION:tip]Photoreal Character 项目中有一个名为 **PhotorealEyeGeo** 的静态网格体。这能通过 FBX 从项目导出到您选择的 DCC 应用中,以便在您自建的项目中使用。[/REGION] + +#### 形态和 UV 布局 + +和真实的人眼一样,眼睛网格体模型并非完美的球体。其前方拥有一个特殊的圆顶,代表角膜。因此眼睛的形状类似于鸡蛋。 + +![](EyeGeometry.png)(w:400 convert:false) +[REGION:caption]此图展示了 Maya 中眼睛几何体的侧面外观。您会发现前方的凸起角膜。[/REGION] + +眼睛的 UV 布局十分重要,因为每个眼睛纹理的比例正是基于它而生成。好消息是,和眼睛着色器完美匹配的 UV 布局相对简单:沿眼睛前方向轴的平面投射。包含背面并非十分重要(因为它们在眼睛后面),在范例角色上也是这样的情况。 + + UV 布局外观如下: + +![](EyeUVs.png)(w:400 convert:false) +[REGION:caption]注意 UV 布局在 0-1 空间上居中,投射直接进入角膜。 [/REGION] + +(#eyetextures) +### 眼睛纹理 + +为眼睛创建的诸多纹理将基于以上创建的 UV 布局,虹膜贴图除外。主要可编辑纹理列表中包含: + +| 纹理 | 名称 | 描述 | +|---------|------|-------------| +|![](ScleraMap.png)(w:200 convert:false) |**Sclera Map**|巩膜贴图控制眼白的颜色,以及眼睛边缘展示的静脉和组织颜色。举例而言,如果需要角色的眼睛布满血丝,这便是需要进行修改的纹理。(*UE4_Demo_Eye_Sclera_Color*)| +|![](DispMap.png)(w:200 convert:false) |**Mid Plane Displacement Map**|中平面置换贴图用于锁定穿透眼睛中心的平面,并用作虹膜深度偏差的基础。(*EyeMidPlaneDisplacement_Example*)| +|![](WetNormal.png)(w:200 convert:false) |**Normal Map**|法线贴图的作用与所有着色器中法线贴图的作用相同——提供触觉纹理变化。在范例角色的眼睛设置中,它沿眼睛的湿润表面生成小块。(*T_Eye_Wet_Normal*)| +|![](Normal.png)(w:200 convert:false) |**Tangent Map**|切线贴图用于控制表面在切线空间中流动的方向。在范例角色的眼睛设置中,它用于突出角膜与巩膜相交方向的变化。(*EYE_NORMALS.EYE_NORMALS*)| +|![](IrisTexture.png)(w:200 convert:false)|**Iris Map**|虹膜纹理较为独特,它不匹配 UV 布局。相反,纹理将填充整个分辨率。UV 和透明遮罩用于控制整体的虹膜大小,以及瞳孔的大小。如自建虹膜贴图,需要使瞳孔大小接近所提供纹理的比例。(*UE4_Demo_Eye_Iris*)| + +[REGION:warning]注意:Tangent Map 输出 **不** 直接插入 Normal Map 输入。它连接到一个 **Tangent Output** 节点(必须单独创建),如主材质 **M_HairSheet_Master2** 所示。 [/REGION] +![](TangentOutput.png) + + + +### 眼睛环境遮挡 + +范例角色眼睛设置的最后一部分是使用一层半透明辅助表面模拟眼睛周围的环境遮挡。在真实世界中,眼睛和其他组织(如眼睑或泪管)接触时将出现十分柔和的阴影。柔和的原因是眼睛自身为半透明,光线将散射通过眼睛。为对此进行真实模拟,我们已放置一个几何体片覆盖眼睛并提供近似的环境遮挡,创建出更加真实的眼睛效果。 + +应用到这个片的材质名为 *MI_Eye_Occlusion_Bust*,可在范例角色模型的 Element 3 中找到。 + +[REGION:note]如要为角色眼睛自建内容,则很可能需要自行构建这块几何体。注意:它需要填充睁开眼睑的区域,其 UV 应清楚地填充 3D 建模程序中 0 到 1 的 UV 空间。 [/REGION] + +![](AOSheetMaya.png)(w:700 convert:false) +[REGION:caption]此图片展示了 Maya 中环境遮挡片几何体,不带面部几何体。此片的边缘将完美填充睁开的眼睑。 [/REGION] + + +[OBJECT:ComparisonSlider] +[PARAM:before] +![Without AO Sheet](WithoutAO.png)(w:700 convert:false) +[/PARAM] +[PARAM:after] +![With AO Sheet](WithAO.png)(w:700 convert:false) +[/PARAM] +[/OBJECT] + + + +## 特别鸣谢 + +特此感谢 [Eugene d'Eon、Steve Marschner 和 Johannes Hanika](http://www.eugenedeon.com/project/importance-sampling-for-physically-based-hair-fiber-models/) 发布他们的作品 [*The importance of sampling for physically-based hair fiber models*](http://dl.acm.org/authorize?6967840)。UE4 头发着色器的部分工作正是基于他们的作品而成。 diff --git a/Engine/Documentation/Source/Resources/Showcases/TwinblastBust/TwinblastBust.INT.udn b/Engine/Documentation/Source/Resources/Showcases/PhotorealisticCharacter/TwinblastBust.INT.udn similarity index 97% rename from Engine/Documentation/Source/Resources/Showcases/TwinblastBust/TwinblastBust.INT.udn rename to Engine/Documentation/Source/Resources/Showcases/PhotorealisticCharacter/TwinblastBust.INT.udn index bd67b08079c5..8183ac5d1441 100644 --- a/Engine/Documentation/Source/Resources/Showcases/TwinblastBust/TwinblastBust.INT.udn +++ b/Engine/Documentation/Source/Resources/Showcases/PhotorealisticCharacter/TwinblastBust.INT.udn @@ -1,16 +1,34 @@ -Availability: Docs -Title:Photoreal Character Bust +Availability: Public +Title:Photorealistic Character Crumbs:%ROOT%, Resources Description:An overview of the Photoreal Character Bust showcase. Related: Engine/Rendering/Materials Related: Engine/Rendering/Materials/PhysicallyBased Related: Engine/Rendering/Materials/LayeredMaterials -Version: 4.13 +Version: 4.15 +topic-image:PhotorealHead.png +social-image:PhotorealHead.png + [TOC(start:2 end:3)] - -![](PhotorealHead.png)(w:700 convert:false) +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + K-VyoqRB5_g + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] The purpose of this showcase is to demonstrate the use of high-quality character shader techniques, similarly to those used on characters from Epic's MOBA game Paragon. To view this showcase, simply open the project and press Play In Editor to see the cinematic pan-around. @@ -239,10 +257,10 @@ Using our new Eye shader, however, an even more realistic effect can be achieved [OBJECT:ComparisonSlider] [PARAM:before] -![Without Refraction (Refraction On/Off at 0.0)](NotRefracting.png)(w:700 convert:false) +![Without Refraction|(Refraction On/Off at 0.0)](NotRefracting.png)(w:700 convert:false) [/PARAM] [PARAM:after] -![With Refraction (Refraction On/Off at 1.0)](Refracting.png)(w:700 convert:false) +![With Refraction|(Refraction On/Off at 1.0)](Refracting.png)(w:700 convert:false) [/PARAM] [/OBJECT] @@ -272,7 +290,7 @@ Due to the complexity of the eye shader and our recommendation that you use it a |**Iris Roughness**| This value drives how shininess of the cornea, the surface directly over the iris. | 0.0 - 0.1 | |**Limbus Dark Scale**| Controls the size of the darkening ring of the limbus. | 2.0 - 2.15 | |**Limbus Pow***| Controls the overall darkening of the limbus area. Overdriven values will darken the entire corneal area. | 15.0 - 22.0 | -|**Limbus UV Width Color| Controls the sample size for the limbus, or how much of the eye surface will be alloted for showing the limbus. This is a fairly delicate setting and should be adjusted with care. | 0.025 - 0.040 | +|**Limbus UV Width Color**| Controls the sample size for the limbus, or how much of the eye surface will be alloted for showing the limbus. This is a fairly delicate setting and should be adjusted with care. | 0.025 - 0.040 | |**Limbus UV Width Shading**| Controls how much light will affect the shading of the limbus. Very delicate setting, adjust with care. | 0.040 - 0.050 | |**Normal UV Scale**| Controls the scale of the normal map texture used across the surface of the eye. | 1.8 - 2.6 | |**Pupil Scale**| Controls the size of the pupil. This is the setting you would use to dilate the eyes. | 0.5 - 1.0 | @@ -300,10 +318,10 @@ The Secondary Environment is a part of the eye shader that provides a faked refl [OBJECT:ComparisonSlider] [PARAM:before] -![Without Secondary Environment (SecondaryEnvBalance at 0.0)](SecondaryEnvOFF.png)(w:700 convert:false) +![Without Secondary Environment|(SecondaryEnvBalance at 0.0)](SecondaryEnvOFF.png)(w:700 convert:false) [/PARAM] [PARAM:after] -![With Secondary Environment (SecondaryEnvBalance at 0.03)](SecondaryEnvON.png)(w:700 convert:false) +![With Secondary Environment|(SecondaryEnvBalance at 0.03)](SecondaryEnvON.png)(w:700 convert:false) [/PARAM] [/OBJECT] diff --git a/Engine/Documentation/Source/Resources/Showcases/TwinblastBust/TwinblastBust.JPN.udn b/Engine/Documentation/Source/Resources/Showcases/PhotorealisticCharacter/TwinblastBust.JPN.udn similarity index 91% rename from Engine/Documentation/Source/Resources/Showcases/TwinblastBust/TwinblastBust.JPN.udn rename to Engine/Documentation/Source/Resources/Showcases/PhotorealisticCharacter/TwinblastBust.JPN.udn index 6f73e96c53ab..527233e8c8e0 100644 --- a/Engine/Documentation/Source/Resources/Showcases/TwinblastBust/TwinblastBust.JPN.udn +++ b/Engine/Documentation/Source/Resources/Showcases/PhotorealisticCharacter/TwinblastBust.JPN.udn @@ -1,34 +1,52 @@ -INTSourceChangelist:3240145 -Availability:Docs -Title:フォトリアルなキャラクターの胸像 +INTSourceChangelist:3403466 +Availability:Public +Title:フォトリアルなキャラクター Crumbs:%ROOT%, Resources Description:フォトリアルなキャラクターの胸像のショーケースの概要 Related:Engine/Rendering/Materials Related:Engine/Rendering/Materials/PhysicallyBased Related:Engine/Rendering/Materials/LayeredMaterials -Version:4.13 +Version:4.15 +topic-image:PhotorealHead.png +social-image:PhotorealHead.png + [TOC(start:2 end:3)] - -![](PhotorealHead.png)(w:700 convert:false) +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + K-VyoqRB5_g + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] このショーケースの目的は、エピックの MOBA ゲーム、Paragon のキャラクターで使用されたのと同様の高品質なキャラクター シェーダー技術についてデモすることです。このショーケースを観るには、このプロジェクトを開いて [Play In Editor] を押して、シネマティックスのパン アラウンドを見ます。 このキャラクターを生成するために使った技術の詳しい情報は、[Unreal Engine Livestream - Tech & Techniques Behind Creating the Characters for Paragon](https://www.youtube.com/watch?v=toLJh5nnJA8) をご覧ください。 -## スキン シェーディング +## スキンシェーディング -キャラクターのスキンは、UE4 の [サブサーフェス プロファイルのシェーディング モデル](Engine/Rendering/Materials/LightingModels/SubSurfaceProfile/) を使って作成されています。 +キャラクターの皮膚は、UE4 の [サブサーフェス プロファイルのシェーディング モデル](Engine/Rendering/Materials/LightingModels/SubSurfaceProfile/) を使って作成されています。 ![](Skin.png)(w:700 convert:false) -スキン マテリアルのベースをセットアップするには、 [マテリアル関数](Engine/Rendering/Materials/Functions/) の使用に注意してください。これは、Paragon のマテリアルを作成する再利用可能なオーサリング アプローチとして行われます。このやり方を用いて、アーティストはひとつの関数に対する基本的な変更が、その関数を使用する全インスタンスを更新することを理解したうえで、一部のタイプのサーフェスを生成するアプローチを標準化することができます。 +皮膚のマテリアルのベースをセットアップするには、 [マテリアル関数](Engine/Rendering/Materials/Functions/) の使用に注意してください。これは、Paragon のマテリアルを作成する再利用可能なオーサリング アプローチとして行われます。このやり方を用いて、アーティストはひとつの関数に対する基本的な変更が、その関数を使用する全インスタンスを更新することを理解したうえで、一部のタイプのサーフェスを生成するアプローチを標準化することができます。 ### スキン シェーダーのテクスチャ -キャラクターのスキンで使われているテクスチャーは、すべて 4K の解像度であり、もともと人の顔をスキャンして作られています。テクスチャはエピックのアーティストがクリーンアップして微調整しています。このスキンのセットアップでは、ディフューズ、ラフネス、スペキュラリティ、散乱、法線の合計 5 種類の テクスチャ マップを利用しています。 +キャラクターの皮膚で使われているテクスチャーは、すべて 4K の解像度であり、もともと人の顔をスキャンして作られています。テクスチャはエピックのアーティストがクリーンアップして微調整しています。この皮膚のセットアップでは、ディフューズ、ラフネス、スペキュラリティ、散乱、法線の合計 5 種類の テクスチャ マップを利用しています。 | テクスチャ | 名前 | 説明 | |---------|------|-------------| @@ -71,7 +89,7 @@ UE4 のヘア シェーダーで使われる近似アルゴリズムは、現実 ### 髪と透過処理 -ヘア シェーダーは、透過性の代わりにマスクしたブレンド モードを使用します。ただし、マスクした透過処理では二値の結果が得られます。サーフェスは完全に不透明か完全に透明になります。ノイズがあるディザ パターンは絶えずサーフェス上を移動し、一段とソリッドである必要があるエリアでは濃くなります。ディザはマスクした透過処理の手段として使用されますが、TemporalAA がアクティブな場合に限り機能します。 +ヘア シェーダーでは半透明の代わりにマスクしたブレンド モードを使用します。ただし、マスクした透過処理では二値の結果が得られます。サーフェスは完全に不透明か完全に透明になります。ノイズのディザ パターンが絶えずサーフェス上を移動し、よりソリッドになる必要がある箇所では密度が高くなります。ディザはマスクした透過処理をブレンドする方法として使われますが、TemporalAA がアクティブな場合に限り機能します。 [OBJECT:ComparisonSlider] [PARAM:before] @@ -82,7 +100,7 @@ UE4 のヘア シェーダーで使われる近似アルゴリズムは、現実 [/PARAM] [/OBJECT] -[REGION:note]アニメートされたディザを TemporalAA と合わせて使用すると、このブレンドをリゾルブするためにいくつかのフレームが必要です。これにより動作中に髪にアーティファクトが生じることがあります。この技術で予期される好ましくない影響です。[/REGION] +[REGION:note]アニメートされたディザを TemporalAA と合わせて使用すると、このブレンドをリゾルブするためにいくつかのフレームが必要です。これにより動作中に髪にアーティファクトが生じることがありますが、これは、この技術で起こる予測範囲内の影響です。[/REGION] #### エッジのマスキング @@ -90,7 +108,7 @@ UE4 のヘア シェーダーで使われる近似アルゴリズムは、現実 シェーダーの一部ではありませんが、サンプル キャラクターの髪で使われているマテリアルおよび 『Paragon』 の他のキャラクターでは、いわゆる「エッジ マスク」を使ってカメラに対して真横になるにつれて髪をフェードさせます。髪は一連の平面としてレンダリングされるため、 (以下の [髪のジオメトリ](#髪のジオメトリ) を参照) 一定のカメラ アングルからは、各シートのエッジが見えて、ヘアのエフェクトが壊れます。 -この問題を緩和するために、マテリアルは頂点法線に対してカメラのベクターを計算し、サーフェスがカメラから垂直に遠ざかるにつれて、完全に透過にフェードしていくようにします。このアプローチの他の面としては、そうすることでヘア シェーダーが頭皮を多く見せる可能性があります。これは髪の量が多いキャラクターでは多くの場合、以下の画像のように頭皮にヘア テクスチャがペイントされている理由でもあります。 +この問題を軽減するために、マテリアルは頂点法線に対してカメラのベクターを計算し、サーフェスがカメラから垂直に遠ざかるにつれて、完全に透過にフェードしていくようにします。このアプローチの他の面としては、そうすることでヘア シェーダーが頭皮を多く見せる可能性があります。これは髪の量が多いキャラクターでは多くの場合、以下の画像のように頭皮にヘア テクスチャがペイントされている理由でもあります。 ![](HairPaint.png)(w:700 convert:false) @@ -101,7 +119,7 @@ UE4 のヘア シェーダーで使われる近似アルゴリズムは、現実 -### 髪のオーサリング +###髪のオーサリング このショーケースで示した技術を使って髪を作成するには、エピックがこのキャラクターの髪をどのように作成したかについて少々理解する必要があります。 @@ -116,7 +134,7 @@ UE4 のヘア シェーダーを使ったヘア ジオメトリは一般的に #### ヘア テクスチャ -UE4 のヘア シェーダーでこれを使用すると、最終結果は以下の 5 つの主要テクスチャによって操作されます。すなわち、*Diffuse*、 *Alpha*、 *Root*、*Depth*、および髪一本毎に固有の *ID* の 5 つです。エピックでは、こうしたテクスチャは通常、3ds Max のヘア システムを使って生成します。シミュレートした髪の結果をジオメトリの一部に投影します。ただし、似たような結果を得るために利用できるオプションが数多くあります。 +UE4 のヘア シェーダーでこれを使用すると、最終結果は以下の 5 つの主要テクスチャによって操作されます。すなわち、*Diffuse*、 *Alpha*、 *Root*、*Depth*、および髪一本毎に固有の *ID* の 5 つです。エピックでは、こうしたテクスチャは通常 3ds Max の Hair システムを使って生成しています。シミュレートしたヘアの結果をジオメトリのピースに投影しています。ただし、同じような結果を得るために利用できるオプションは他にもあります。 | テクスチャ | 名前 | 説明 | @@ -222,7 +240,7 @@ Pixel Depth Offset (PDO、ピクセル深度オフセット) は、ヘア シェ 以下は概要です。 ![](EyeDiagram.png)(w:700 convert:false) -|Number|Name|Description| +|番号|名称|説明| |------|----|-----------| |1|強膜|眼球の白目部分です。目のこの部分は一般的に湿っていて、若干立体的なテクスチャになっています。| |2|縁|虹彩と強膜の間にある暗い色の輪です。目によって目立つ度合いが異なり、真横から見ると見えなくなる傾向があります。| @@ -230,7 +248,7 @@ Pixel Depth Offset (PDO、ピクセル深度オフセット) は、ヘア シェ |4|瞳孔| 瞳孔は、目中央部の暗い部分です。網膜の桿体細胞と錐体視細胞を通った光が通る穴です。| |5|角膜|透明であり、液体で満たされたドーム状のもので、虹彩の表面上にあります。 | -### 目の中の屈折 - 当時と現在 +### 目の中の屈折 - これまでと現在 眼球は液体で満たされているため、その中を通る光は屈折します。複数の角度から目を見ると、現実世界でもこれがわかります。角膜から見ると虹彩と瞳孔は反射によって歪みます。ゲームや映像でこれに対処する従来のアプローチは、2 つの別箇の目のサーフェスを作るというものです。ひとつは、強膜、虹彩、瞳孔になり、その上のもうひとつのサーフェスは角膜と全体的な目の水分になります。これにより、屈折が可能になります。下の方にあるサーフェスが水分がある層のシェルを通して見られるからです。こうしたアプローチは、エピックの「A Boy and His Kite」の技術デモで使用されました。以下の図では、2 つのサーフェスを表しています。 @@ -240,10 +258,10 @@ Pixel Depth Offset (PDO、ピクセル深度オフセット) は、ヘア シェ [OBJECT:ComparisonSlider] [PARAM:before] -![Without Refraction (Refraction On/Off at 0.0)](NotRefracting.png)(w:700 convert:false) +![Without Refraction|(Refraction On/Off at 0.0)](NotRefracting.png)(w:700 convert:false) [/PARAM] [PARAM:after] -![With Refraction (Refraction On/Off at 1.0)](Refracting.png)(w:700 convert:false) +![With Refraction|(Refraction On/Off at 1.0)](Refracting.png)(w:700 convert:false) [/PARAM] [/OBJECT] @@ -301,10 +319,10 @@ Pixel Depth Offset (PDO、ピクセル深度オフセット) は、ヘア シェ [OBJECT:ComparisonSlider] [PARAM:before] -![Without Secondary Environment (SecondaryEnvBalance at 0.0)](SecondaryEnvOFF.png)(w:700 convert:false) +![Without Secondary Environment|(SecondaryEnvBalance at 0.0)](SecondaryEnvOFF.png)(w:700 convert:false) [/PARAM] [PARAM:after] -![With Secondary Environment (SecondaryEnvBalance at 0.03)](SecondaryEnvON.png)(w:700 convert:false) +![With Secondary Environment|(SecondaryEnvBalance at 0.03)](SecondaryEnvON.png)(w:700 convert:false) [/PARAM] [/OBJECT] @@ -328,7 +346,7 @@ Pixel Depth Offset (PDO、ピクセル深度オフセット) は、ヘア シェ UV レイアウトは以下のようになります。 ![](EyeUVs.png)(w:400 convert:false) -[REGION:caption]UV レイアウトは 0-1 空間の中心にあり、プロジェクションは直接角膜の中を見ます。[/REGION] +[REGION:caption]UV レイアウトは 0-1 空間の中心にあり、プロジェクションは直接角膜を見ます。[/REGION] ### 目のテクスチャ @@ -343,7 +361,7 @@ Pixel Depth Offset (PDO、ピクセル深度オフセット) は、ヘア シェ |![](Normal.png)(w:200 convert:false) |**Tangent Map**|タンジェント マップはタンジェント空間に流れこむサーフェスの方向を制御するために使用します。サンプル キャラクターの目のセットアップでは、角膜が強膜と接触する方向の変化を強調するために使用します。(*EYE_NORMALS.EYE_NORMALS*)| |![](IrisTexture.png)(w:200 convert:false)|**Iris Map**|虹彩のテクスチャは UV レイアウトと一致しないという点においてユニークなものです。代わりにこのテクスチャは解像度を全体的に満たします。UV とアルファ マスクは、全体的な虹彩のサイズ、および瞳孔のサイズを制御するために使用します。独自の虹彩マップを作成することが難しければ、与えられたテクスチャの比率に近くなるように瞳孔のサイズを適切に維持するようにしてください。(*UE4_Demo_Eye_Iris*)| -[REGION:warning]Tangent Map の出力が Normal Map の入力に直接 **入力されないことに注意してください。**これは、**Tangent Output** ノードに接続されます。マスター マテリアル、**M_HairSheet_Master2** のように別個に作成しなければなりません。[/REGION] +[REGION:warning]Tangent Map の出力が Normal Map の入力に直接 **入力されないことに注意してください。**これは、**Tangent Output** ノードに接続されます。マスター マテリアルの **M_HairSheet_Master2** のように別個に作成しなければなりません。[/REGION] ![](TangentOutput.png) @@ -373,4 +391,4 @@ Pixel Depth Offset (PDO、ピクセル深度オフセット) は、ヘア シェ ## 謝辞 -[物理ベースの髪の繊維モデルのサンプリングの重要性](http://dl.acm.org/authorize?6967840) を公開してくださった [Eugene d'Eon 氏、 Steve Marschner 氏、 およびJohannes Hanika 氏](http://www.eugenedeon.com/project/importance-sampling-for-physically-based-hair-fiber-models/) の皆様に感謝いたします。 UE4 のヘア シェーダーの一部はこの内容に基づいたものです。 +[Importance of sampling for physically-based hair fiber models (物理ベースの髪の繊維モデルのサンプリングの重要性)](http://dl.acm.org/authorize?6967840) を公開してくださった [Eugene d'Eon 氏、 Steve Marschner 氏、 およびJohannes Hanika 氏](http://www.eugenedeon.com/project/importance-sampling-for-physically-based-hair-fiber-models/) の皆様に感謝いたします。 UE4 のヘア シェーダーの一部はこの内容に基づいたものです。 diff --git a/Engine/Documentation/Source/Resources/Showcases/TwinblastBust/TwinblastBust.KOR.udn b/Engine/Documentation/Source/Resources/Showcases/PhotorealisticCharacter/TwinblastBust.KOR.udn similarity index 90% rename from Engine/Documentation/Source/Resources/Showcases/TwinblastBust/TwinblastBust.KOR.udn rename to Engine/Documentation/Source/Resources/Showcases/PhotorealisticCharacter/TwinblastBust.KOR.udn index aca9dda67679..072a639b7eca 100644 --- a/Engine/Documentation/Source/Resources/Showcases/TwinblastBust/TwinblastBust.KOR.udn +++ b/Engine/Documentation/Source/Resources/Showcases/PhotorealisticCharacter/TwinblastBust.KOR.udn @@ -1,17 +1,35 @@ -INTSourceChangelist:3240145 -Availability: Docs -Title:실사 캐릭터 버스트 +INTSourceChangelist:3403466 +Availability: Public +Title:실사 캐릭터 Crumbs:%ROOT%, Resources -Description:Photoreal Character Bust, 실사 캐릭터 버스터 쇼케이스 개요입니다. +Description:Photoreal Character, 실사 캐릭터 쇼케이스 개요입니다. Related: Engine/Rendering/Materials Related: Engine/Rendering/Materials/PhysicallyBased Related: Engine/Rendering/Materials/LayeredMaterials -Version: 4.13 +Version: 4.15 +topic-image:PhotorealHead.png +social-image:PhotorealHead.png + [TOC(start:2 end:3)] - -![](PhotorealHead.png)(w:700 convert:false) +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + K-VyoqRB5_g + [/PARAMLITERAL] + [PARAMLITERAL:width] + 100 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] 이 쇼케이스의 목적은 에픽의 모바 게임 파라곤의 캐릭터에 사용된 것과 비슷한 하이 퀄리티 캐릭터 셰이더 기법을 선보이는 것입니다. 이 쇼케이스를 확인하려면, 프로젝트를 열고 에디터에서 플레이 버튼을 눌러 캐릭터 주위를 도는 시네마틱을 확인하면 됩니다. @@ -55,30 +73,30 @@ UE4 헤어 셰이더 활용을 위해서는, **Shading Model** 프로퍼티를 * ![](TwinblastHair_Specs_Diagram.png)(w:700 convert:false) [REGION:caption]1. 연한 색 헤어는 일차 스페큘러 하이라이트를 나타냅니다. 2. 밝은 색 헤어는 이차 스페큘러 하이라이트를 나타냅니다.[/REGION] -UE4 헤어 셰이더에 사용된 추정 알고리즘은 현실에서와 비슷한 방식으로 그러한 효과를 냅니다. 빛이 헤어 모낭 표면에 닿으면, 그냥 단순하게 튕겨나가지 않습니다. 헤어는 반투명이라, 일부는 *투과* 시켜, 그 안을 약간 튕겨다니다가 빠져나갑니다. 헤어 셰이더는 빛이 헤어에 닿으면서 벌어질 수 있는 세 가지 경로를 추정하여, 아래 애니메이션 GIF 도표와 같이 표현합니다: +UE4 헤어 셰이더에 사용된 추정 알고리즘은 현실에서와 비슷한 방식으로 그러한 효과를 냅니다. 빛이 헤어 모낭 표면에 닿으면, 그냥 단순하게 튕겨나가지 않습니다. 헤어는 반투명이라, 일부는 *투과* 시켜, 그 안을 약간 튕겨다니다가 빠져나갑니다. 헤어 셰이더는 빛이 헤어에 닿으면서 벌어질 수 있는 세 가지 경로를 추정하여, 아래 애니메이션 GIF 와 같이 표현합니다: ![](HairDiagram.gif)(w:700 convert:false) -[REGION:caption]하나의 헤어 모낭 크로스 섹션이 헤어 셰이더가 빛과의 상호작용을 추정해 내는 모습을 보여주면서, 라이트가 택할 세 가지 주요 유형을 선보입니다. 이 프로세스 각 부분에 대한 설명은 아래 표를 참고하십시오.[/REGION] +[REGION:caption]하나의 헤어 모낭이 겹친 부분을 보면 헤어 셰이더가 빛과의 상호작용을 어떻게 추정해내는지, 세 가지 주요 빛 경로를 보여줍니다. 이 프로세스 각 부분에 대한 설명은 아래 표를 참고하십시오.[/REGION] | 번호 | 설명 | |--------|-------------| |0. |헤어 모낭의 성장 (뿌리에서 끝) 방향입니다. | |1. |리플렉션 전용 경로로, 헤어 표면에서 튕겨져 나오는 빛을 포함합니다. 일차 스페큘러 하이라이트를 만듭니다. | -|2. |투과-투과 경로로, 빛이 헤어 모낭속으로 들어간 뒤 반대편으로 나옵니다. 이런 식으로 헤어 볼륨 안에서 빛이 퍼집니다.| -|3. |투과-리플렉션-투과 경로로, 빛이 헤어 모낭에 들어오면, 표면 내부 바운드를 반사시킨 뒤 빠져나갑니다. 그러면 이차 스페큘러 라이트가 생성됩니다.| +|2. |투과-투과 경로로, 빛이 헤어 모낭속으로 들어간 뒤 반대편으로 나옵니다. 이런 식으로 헤어 볼륨 안에서 빛이 퍼집니다. | +|3. |투과-리플렉션-투과 경로로, 빛이 헤어 모낭에 들어와 표면 내부 경계에서 반사된 뒤 빠져나갑니다. 이를 통해 이차 스페큘러 라이트가 생성됩니다. | -위 그림에서 보듯이, 헤어 한 가닥은 완벽한 원통형 또는 튜브형이 아닙니다. 헤어는 사실상 서로 겹쳐 놓은 원뿔쪽에 가까운 것으로 보입니다. 즉 헤어 표면을 튕겨져 나가는 빛은, 헤어가 완전 부드러울 떄화는 완전히 다른 방식으로 산란된다는 뜻입니다. 게다가, 각 머리칼은 일반적으로 다른 방향을 가리키고 있기 때문에, 스페큘러 하이라이트에는 통일성이 없으나 헤어가 가리키는 방향에 따라 독립적으로 배치할 수 있습니다. 이런 것을 흔히 *anisotropic* (어나이소트로픽, 비등방성) 스페큘러라 합니다. 이 역시도 UE4 헤어 셰이더에 지원되고 있습니다. +위 그림에서 보듯이, 헤어 한 가닥은 완벽한 원통형 또는 튜브형이 아닙니다. 헤어는 사실상 서로 겹쳐 놓은 원뿔처럼 보입니다. 즉 헤어 표면을 튕겨져 나가는 빛은, 헤어가 완전 부드러울 때와는 완전히 다른 방식으로 산란된다는 뜻입니다. 게다가, 각 머리칼은 일반적으로 다른 방향을 가리키고 있기 때문에 스페큘러 하이라이트에는 통일성이 없지만, 헤어가 가리키는 방향에 따라 독립적으로 배치됩니다. 이런 것을 흔히 *anisotropic* (어나이소트로픽, 비등방성) 스페큘러라 합니다. 이 역시도 UE4 헤어 셰이더에 지원되고 있습니다. ### 헤어와 반투명 -헤어 셰이더는 반투명이 아닌 마스크드 블렌드 모드를 사용합니다. 하지만 마스크드 반투명은 이진 결과값을 냅니다 - 완전 불투명하거나 완전 투명한 표면만 가능한 것입니다. 노이즈가 낀 디더링 패턴을 지속적으로 표면에 걸쳐 이동시켜, 속이 꽉 찬 영역은 보다 빽빽하게 만듭니다. 마스크드 반투명을 블렌딩하는 방법으로는 디더링이 사용되나, 템포럴 AA 활성화 상태에서만 작동합니다. +헤어 셰이더는 반투명이 아닌 Masked 블렌드 모드를 사용합니다. 하지만 Masked 반투명은 이진 결과값을 냅니다 - 완전 불투명하거나 완전 투명한 표면만 가능한 것입니다. 노이즈가 낀 디더링 패턴을 지속적으로 표면에 걸쳐 이동시켜, 속이 꽉 찬 영역은 보다 빽빽하게 만듭니다. 마스크드 반투명을 블렌딩하는 방법으로는 디더링이 사용되나, 템포럴 AA 활성화 상태에서만 작동합니다. [OBJECT:ComparisonSlider] [PARAM:before] -![Without TemporalAA](Hair_AAOff.png)(w:700 convert:false) +![템포럴 AA 없음](Hair_AAOff.png)(w:700 convert:false) [/PARAM] [PARAM:after] -![With TemporalAA](Hair_AAOn.png)(w:700 convert:false) +![템포럴 AA 있음](Hair_AAOn.png)(w:700 convert:false) [/PARAM] [/OBJECT] @@ -88,7 +106,7 @@ UE4 헤어 셰이더에 사용된 추정 알고리즘은 현실에서와 비슷 ![](EdgeMaskGraph.png)(w:700 convert:false) -딱히 셰이더 자체의 일부는 아니지만, 에픽의 게임 *파라곤* 의 다른 캐릭터 뿐만 아니라 예제 캐릭터의 헤어에 사용된 머티리얼은 "Edge Mask" (에지 마스크)라는 기법을 사용하여 카메라 가장자리에 걸리는 헤어를 페이드 아웃시키고 있습니다. 헤어는 일련의 면으로 렌더링되기에 (아래 [헤어와 지오메트리](#헤어와지오메트리) 참고) 특정 카메라 각도에서는 각 시트의 에지가 보여 헤어의 느낌이 깨질 수 있습니다. +딱히 셰이더 자체의 일부는 아니지만, 에픽의 게임 *파라곤* 의 다른 캐릭터 뿐만 아니라 예제 캐릭터의 헤어에 사용된 머티리얼은 "Edge Mask" (에지 마스크)라는 기법을 사용하여 카메라 가장자리에 걸리는 헤어를 페이드 아웃시키고 있습니다. 헤어는 일련의 면으로 렌더링되기에 (아래 [헤어 지오메트리](#헤어지오메트리) 참고) 특정 카메라 각도에서는 각 시트의 에지가 보여 헤어의 느낌이 깨질 수 있습니다. 이러한 문제 경감을 위해, 머티리얼은 카메라의 버텍스 노멀에 대한 벡터를 계산하여 표면이 카메라에서 수직 방향으로 멀어지도록 합니다. 완벽한 투명으로 페이드 아웃 시키기도 합니다. 그러나 이 접근법의 다른 측면이 있다면, 그렇게 하는 데 있어 헤어 셰이더에 두피가 더 많이 보일 수 있다는 점입니다. 그래서 두꺼운 헤어의 머리를 지닌 캐릭터 다수가 아래 그림처럼 두피에 헤어 텍스처가 칠해진 것처럼 보이는 이유입니다. @@ -139,7 +157,7 @@ UE4 의 헤어 셰이더를 이용한 헤어 지오메트리는 보통 평면이 #### Scatter -헤어 셰이더를 *시뮬레이션* 이 아닌 *추정* 이라 하는 주요 이유 중 하나는, 모든 헤어 가닥을 실제 시뮬레이션하는 것도 아니요, 완벽히 정확한 라이팅 동작을 시뮬레이션하는 것도 아니기 때문입니다. 현실에서 빛이 헤어 모낭에 반사 및 투과될 때, 종종 *다른* 헤어 가닥을 만나며 같은 프로세스를 연속해서 여러 번 반복해야 할 것입니다. 이 때 그러한 시뮬레이션 효과를 실시간으로 정확히 계산해 낼 수 있는 시스템은 없습니다. +헤어 셰이더를 *시뮬레이션* 이 아닌 *추정* 이라 하는 주요 이유 중 하나는, 모든 헤어 가닥을 실제 시뮬레이션하는 것도 아니고, 완벽히 정확한 라이팅 동작을 시뮬레이션하는 것도 아니기 때문입니다. 현실에서 빛이 헤어 모낭에 반사 및 투과될 때, 종종 *다른* 헤어 가닥을 만나며 같은 프로세스를 연속해서 여러 번 반복해야 할 것입니다. 이 때 그러한 시뮬레이션 효과를 실시간으로 정확히 계산해 낼 수 있는 시스템은 없습니다. 그럼에도 빛이 헤어 본체를 통해 산란되는 방식은 그 헤어의 사실적 느낌에 여전히 매우 중요하며, 현실과 비슷한 느낌을 주는 게임이라면 두말할 것도 없습니다. 이에 대한 제어를 위해, 헤어 셰이더에는 Scatter (스캐터) 프로퍼티가 제공되는데, 주요 셰이더 노드의 메탈릭 값을 대체시켜 0.0 과 1.0 사이의 값으로 제한시키는 것입니다. 스캐터는 캐릭터의 헤어 전체 바디에 얼마만큼의 빛을 통과시킬지 제어합니다. @@ -148,10 +166,10 @@ UE4 의 헤어 셰이더를 이용한 헤어 지오메트리는 보통 평면이 [OBJECT:ComparisonSlider] [PARAM:before] -![Scatter value of 0.0](Scatter_0.png)(w:700 convert:false) +![스캐터 값 0.0](Scatter_0.png)(w:700 convert:false) [/PARAM] [PARAM:after] -![Scatter value of 1.0](Scatter_1.png)(w:700 convert:false) +![스캐터 값 1.0](Scatter_1.png)(w:700 convert:false) [/PARAM] [/OBJECT] [REGION:caption]이 예제에서 Root (뿌리) 부분과 Tip (끝) 부분의 색은 연한 금색으로, Random Variation (무작위 다변화)는 0.0 으로 설정되었습니다. 거기에 스캐터를 사용하여 헤어에 얼마만큼의 빛을 통과시킬지 조절했습니다. 스캐터 값만 바꿔도 다양한 헤어 톤을 낼 수 있다는 것을 보여줍니다.[/REGION] @@ -174,7 +192,7 @@ Tangent (탄젠트) 프로퍼티는 헤어 셰이더를 노멀 프로퍼티를 ##### 탄젠트용 플로우 맵 -다른 방식은 플로우 맵을 만들어야 합니다. 캐릭터 헤어가 길고 굽어지면서 실제 지오메트리보다 꼬불꼬불해 보일 필요가 있을 때, 또는 헤어의 개별 텍스처 부분이 각기 다른 방향을 하고 있을 (위 설명대로 하향식이 아닐) 때 좋습니다. 플로우 맵은 헤어의 이동 방향을 탄젠트 스페이스로, 또는 표면을 따라서 나타냅니다. 실사 캐릭터 버스트 프로젝트 안에 보면 *T_Hair_Flow* 라는 미사용 플로우 맵을 찾을 수 있습니다. 아래는 그 플로우 맵과 스페큘러의 결과를 비교한 것입니다. +다른 방식은 플로우 맵을 만들어야 합니다. 캐릭터 헤어가 길고 굽어지면서 실제 지오메트리보다 꼬불꼬불해 보일 필요가 있을 때, 또는 헤어의 개별 텍스처 부분이 각기 다른 방향을 하고 있을 (위 설명대로 하향식이 아닐) 때 좋습니다. 플로우 맵은 헤어의 이동 방향을 탄젠트 스페이스로, 또는 표면을 따라서 나타냅니다. 실사 캐릭터 프로젝트 안에 보면 *T_Hair_Flow* 라는 미사용 플로우 맵을 찾을 수 있습니다. 아래는 그 플로우 맵과 스페큘러의 결과를 비교한 것입니다. [OBJECT:ComparisonSlider] [PARAM:before] @@ -191,7 +209,7 @@ Tangent (탄젠트) 프로퍼티는 헤어 셰이더를 노멀 프로퍼티를 #### 헤어 셰이더로 픽셀 뎁스 오프셋 사용 -Pixel Depth Offset (PDO, 픽셀 뎁스 오프셋)은 헤어 셰이더 고유 프로퍼티는 아닙니다. 일반적인 용어로, PDO 는 픽셀이 카메라에서 오목하게 떨어져 있는 것처럼 보이게 만들어, 표면에 인공적인 깊이감을 만들어 냅니다. 헤어는 단순한 지오메트리 시트로 이루어져 있기에, 아래 [헤어와 지오메트리](#헤어와지오메트리) 부분에 설명된 대로, PDO 를 사용하면 헤어 모양 전반적으로 확실한 깊이감을 줄 수 있습니다. 또 아래 그림에서처럼 헤어 지오메트리 면이 두피와 만나는 부분에 교차점을 분해시켜 주기도 합니다. +Pixel Depth Offset (PDO, 픽셀 뎁스 오프셋)은 헤어 셰이더 고유 프로퍼티는 아닙니다. 일반적인 용어로, PDO 는 픽셀이 카메라에서 오목하게 떨어져 있는 것처럼 보이게 만들어, 표면에 인공적인 깊이감을 만들어 냅니다. 헤어는 단순한 지오메트리 시트로 이루어져 있기에, 아래 [헤어 지오메트리](#헤어지오메트리) 부분에 설명된 대로, PDO 를 사용하면 헤어 모양 전반적으로 확실한 깊이감을 줄 수 있습니다. 또 아래 그림에서처럼 헤어 지오메트리 면이 두피와 만나는 부분에 교차점을 분해시켜 주기도 합니다. [OBJECT:ComparisonSlider] [PARAM:before] @@ -240,10 +258,10 @@ Pixel Depth Offset (PDO, 픽셀 뎁스 오프셋)은 헤어 셰이더 고유 프 [OBJECT:ComparisonSlider] [PARAM:before] -![Without Refraction (Refraction On/Off at 0.0)](NotRefracting.png)(w:700 convert:false) +![굴절 없음|(굴절 켜기/끄기 0.0)](NotRefracting.png)(w:700 convert:false) [/PARAM] [PARAM:after] -![With Refraction (Refraction On/Off at 1.0)](Refracting.png)(w:700 convert:false) +![굴절 있음|(굴절 켜기/끄기 1.0)](Refracting.png)(w:700 convert:false) [/PARAM] [/OBJECT] @@ -301,10 +319,10 @@ Secondary Environment (이차 배경)은 눈 표면에 가짜 리플렉션 맵 [OBJECT:ComparisonSlider] [PARAM:before] -![Without Secondary Environment (SecondaryEnvBalance at 0.0)](SecondaryEnvOFF.png)(w:700 convert:false) +![이차 배경 없음|(SecondaryEnvBalance 0.0)](SecondaryEnvOFF.png)(w:700 convert:false) [/PARAM] [PARAM:after] -![With Secondary Environment (SecondaryEnvBalance at 0.03)](SecondaryEnvON.png)(w:700 convert:false) +![이차 배경 있음|(SecondaryEnvBalance 0.03)](SecondaryEnvON.png)(w:700 convert:false) [/PARAM] [/OBJECT] @@ -362,10 +380,10 @@ Secondary Environment (이차 배경)은 눈 표면에 가짜 리플렉션 맵 [OBJECT:ComparisonSlider] [PARAM:before] -![Without AO Sheet](WithoutAO.png)(w:700 convert:false) +![AO 시트 없음](WithoutAO.png)(w:700 convert:false) [/PARAM] [PARAM:after] -![With AO Sheet](WithAO.png)(w:700 convert:false) +![AO 시트 있음](WithAO.png)(w:700 convert:false) [/PARAM] [/OBJECT] diff --git a/Engine/Documentation/Source/Resources/Showcases/Showcases.INT.udn b/Engine/Documentation/Source/Resources/Showcases/Showcases.INT.udn index 4508ca4e27fc..f41bf5c47ef7 100644 --- a/Engine/Documentation/Source/Resources/Showcases/Showcases.INT.udn +++ b/Engine/Documentation/Source/Resources/Showcases/Showcases.INT.udn @@ -50,6 +50,7 @@ The corresponding documentation is designed to provide some insight into how eac [/EXCERPT:Showcases] [REGION:topics third] +%Resources/Showcases/PhotorealisticCharacter:topiccompact% %Resources/Showcases/SequencerSubway:topiccompact% %Resources/Showcases/Infiltrator:topiccompact% %Resources/ContentExamples:TopicCompact% diff --git a/Engine/Documentation/Source/Resources/Showcases/Showcases.JPN.udn b/Engine/Documentation/Source/Resources/Showcases/Showcases.JPN.udn index 6f2914b87d7d..cd8341dc0f87 100644 --- a/Engine/Documentation/Source/Resources/Showcases/Showcases.JPN.udn +++ b/Engine/Documentation/Source/Resources/Showcases/Showcases.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3275209 +INTSourceChangelist:3403470 Availability:Public Title:エンジン機能のサンプル Crumbs:%ROOT%, Resources @@ -51,6 +51,7 @@ Version:4.9 [/EXCERPT:Showcases] [REGION:topics third] +%Resources/Showcases/PhotorealisticCharacter:topiccompact% %Resources/Showcases/SequencerSubway:topiccompact% %Resources/Showcases/Infiltrator:topiccompact% %Resources/ContentExamples:TopicCompact% diff --git a/Engine/Documentation/Source/Resources/Showcases/Showcases.KOR.udn b/Engine/Documentation/Source/Resources/Showcases/Showcases.KOR.udn index 758c6d21cfde..131dd70270e2 100644 --- a/Engine/Documentation/Source/Resources/Showcases/Showcases.KOR.udn +++ b/Engine/Documentation/Source/Resources/Showcases/Showcases.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3275209 +INTSourceChangelist:3403470 Availability: Public Title:엔진 기능 예제 Crumbs:%ROOT%, Resources @@ -51,6 +51,7 @@ Version: 4.9 [/EXCERPT:Showcases] [REGION:topics third] +%Resources/Showcases/PhotorealisticCharacter:topiccompact% %Resources/Showcases/SequencerSubway:topiccompact% %Resources/Showcases/Infiltrator:topiccompact% %Resources/ContentExamples:TopicCompact% diff --git a/Engine/Documentation/Source/Resources/Showcases/TwinblastBust/TwinblastBust.CHN.udn b/Engine/Documentation/Source/Resources/Showcases/TwinblastBust/TwinblastBust.CHN.udn deleted file mode 100644 index 07354871fe30..000000000000 --- a/Engine/Documentation/Source/Resources/Showcases/TwinblastBust/TwinblastBust.CHN.udn +++ /dev/null @@ -1,293 +0,0 @@ -INTSourceChangelist:0 -Availability: Docs -Title:Twinblast Bust -Crumbs:%ROOT%, Resources -Description:An overview of the Twinblast Bust showcase. -Related: Engine/Rendering/Materials -Related: Engine/Rendering/Materials/PhysicallyBased -Related: Engine/Rendering/Materials/LayeredMaterials -Version: 4.13 - -[TOC(start:2 end:3)] - -The purpose of this showcase is to demonstrate the use of high-quality character shader techniques, as demonstrated on a character from Epic's MOBA game Paragon. To view this showcase, simply open the project and press Play In Editor to see the cinematic pan-around. - -For more information on the tech used to produce this character, please refer to this [Unreal Engine Livestream - Tech & Techniques Behind Creating the Characters for Paragon](https://www.youtube.com/watch?v=toLJh5nnJA8). - -## Skin Shading - -The character's skin is created primarily through the use of UE4's [Subsurface Profile shading model](Engine/Rendering/Materials/LightingModels/SubSurfaceProfile/). - -![](TwinblastSkinMat.png)(w:700 convert:false) - -Note the use of [Material Functions](Engine/Rendering/Materials/Functions/) to set up the base for the skin Material. This is done as a reusable authoring approach to creating Materials for Paragon. In this way, artists can standardize approaches to generating certain types of surfaces, knowing that a fundamental change to a single Function will update all instances where that Function is being used. - -### Skin Shader Textures - -The textures used on Twinblast's skin are all at 4K resolution and were originally produced from facial scans of the actor. The textures were then cleaned up and tweaked by artists at Epic. This skin setup utilizes five total texture maps: diffuse, roughness, specularity, scatter, and normal. - -| Texture | Name | Description | -|---------|------|-------------| -|![](SkinDiffuse.png)(w:200 convert:false)|**Diffuse**|The diffuse map supplies the Base Color for the Material. At 4K, you can see the tiny capillaries just underneath the surface. Any darkening of wrinkles will accentuate the texture supplied by the normal map. (*TwinBlast_UE4_Demo_Head_D*)| -|![](SkinRough.png)(w:200 convert:false)|**Roughness**|The roughness map is stored within the alpha channel of the diffuse texture. This is a common technique used to minimize the amount of textures in use. Note that the roughness increases wihtin pores and wrinkles. This causes those areas to appear less shiny, accentuating the look of depth provided by the diffuse and normal map. Also note that the hair texture on the head is pushed out to fully rough (1.0) this prevents any stray specular highlights from the scalp, which will give a much more significant sense of depth to the hair. (*TwinBlast_UE4_Demo_Head_D*)| -|![](SkinSpec.png)(w:200 convert:false)|**Specular**|The specular map scales the amount of specular highlight visible across the surface of the skin. It is important to note that the default value for specularity is 0.5. This map boosts specularity at areas where the skin may be stretched a bit tighter, and dampens it in areas where we don't want to see reflection, such as the center of pores and within wrinkles. (*CH2_exp04_merged_spec_f_FC_FINAL*)| -|![](SkinScatter.png)(w:200 convert:false)|**Scatter**|The scatter map controls how much light is going to be scattered through the surface of the skin. Areas that are dark will exhibit very little scatter, such as the cheeks, while lighter areas will have higher amounts of perceived scatter, such as the nose and ears. The color of the scatter is managed by the [Subsurface Profile asset.](Engine/Rendering/Materials/LightingModels/SubSurfaceProfile/) (*TwinBlast_UE4_Demo_Head_BackScatter*)| -|![](SkinNormal.png)(w:200 convert:false)|**Normal**|The normal map works as expected in typical material setups, supplying the tactile texture to the surface by perturbing pixel normals. There is nothing out of the ordinary in its setup for this example. (*TwinBlast_UE4_Demo_Head__normals*)| - - -## Hair Shading - -Hair shading is handled by way of UE4's Hair shader model. This shader is physically based shading model based on research by [Eugene d'Eon, Steve Marschner and Johannes Hanika](http://www.eugenedeon.com/project/importance-sampling-for-physically-based-hair-fiber-models/) and currently used by [Weta Digital](http://www.wetafx.co.nz/research). The shader approximates light's reflection from the surface of the hair with anisotropic specularity, as well as its refraction through it and its scatter throughout multiple strands. - -To utilize the UE4 Hair shader, set the **Shading Model** property of your Material to **Hair**. - - -![](HairSM.png) - -### Hair and Specularity - -In the real world, hair tends to have multiple specular highlights: one representing the color of the light and another that is a mix of hair color and light color. For sake of this document, we will refer to these as primary and secondary specular highlights. The Hair shader approximates the same effects with highly realistic results. - -![](TwinblastHair_Specs_Diagram.png)(w:700 convert:false) -[REGION:caption]1. The lighter hair represents the primary specular highlight. 2. The brighter red hair represents the secondary specular highlight.[/REGION] - -The approximation algorithm used in UE4's hair shader creates these effects in a similar manner to how they are made in the real world. As light strikes the surface of a hair follicle, it does not simply bounce off. Hair is translucent, allowing some light to pass *through* it, to potentially bounce around inside it, then exit. The hair shader approximates this with three possible paths for light to travel as it interacts with hair, as shown in the animated GIF diagram below: - -![](HairDiagram.gif)(w:700 convert:false) -[REGION:caption]Cross section of single hair follicle showing how the hair shader approximates interaction with light, demonstrating the three primary types of paths light will take. See the table below for descriptions of each part of the process.[/REGION] - -| Number | Description | -|--------|-------------| -|0. |The growth (root/tip) direction of the hair follicle. | -|1. |Reflection only path, with light bouncing off the surface of the hair. This produces the primary specular highlight.| -|2. |Transmission-transmission path, in which light passes into the hair follicle and back out the other side. This is how light scatters within a volume of hair.| -|3. |Transmission-reflection-transmission path, in which light enters the hair follicle, reflects off the inside boundary of the surface, and then exits . This produces the secondary specular highlight.| - -As shown in the diagram above, a strand of hair is not a perfect cylinder or tube. In actuality hair appears more as a series of stacked cones. This means light bouncing off the surface of hair will be scattered differently than it would if hair were perfectly smooth. Further, because each strand of hair is generally pointing in a different direction, the specular highlight will not be unified, but will be independently placed based on the direction the hair is pointing. This is often referred to as *anisotropic* specularity, which is also supported by the UE4 hair shader. - -### Hair and Transparency - -The Hair Shader uses the Masked blend mode instead of translucency. However, Masked transparency results in a binary result - surfaces are either fully opaque or fully transparent. A noisy dither pattern is constantly moved across the surface, becoming more dense in areas that need to be more solid. Dither is used as a way to blend Masked transparency, but only works when TemporalAA is active. - -[OBJECT:ComparisonSlider] -[PARAM:before] -![Without TemporalAA](Hair_AAOff.png)(w:700 convert:false) -[/PARAM] -[PARAM:after] -![With TemporalAA](Hair_AAOn.png)(w:700 convert:false) -[/PARAM] -[/OBJECT] - -[REGION:note]Using an animated dither with TemporalAA requires several frames to resolve the blend. This can lead to some artifacting on hair while it is in motion. This is an expected side effect of the technique.[/REGION] - -#### Edge Masking - -![](EdgeMaskGraph.png)(w:700 convert:false) - -Though not specifically part of the shader itself, it is worth noting that the Material used on Twinblast's hair - as well as the other characters of Paragon - uses what is called an "Edge Mask" to fade the hair away as it becomes edge-on to the camera. Since hair is rendered as a series of planes - see [Hair and Geometry](#hairgeometry) below - it is likely that from certain camera angles, one would see the edge of each sheet, breaking the hair effect. - -To help alleviate this problem, the Material calculates the camera's vector against the vertex normal such that as the surface turns perpendicularly away from the camera, it will also fade away to complete transparency. This is also why many characters with thick heads of hair will often have a hair texture painted on the scalp, as seen in the image below. - -![](TwinblastScalp.png)(w:700 convert:false) - -[REGION:tip]It should also be pointed out that this effect is tied to a Quality Switch node, so that on lower-powered platforms it can easily be switched off to trade back some shader performance. As always, it's best to test on target platform.[/REGION] - - - - - -### Hair Authoring - -Creating hair using the techniques shown in this showcase requires a bit of understand of how Epic constructed this character's hair. - -#### Hair Geometry - -Hair geometry using UE4's hair shader is generally going to be constructed using a series of planar surfaces, which is a common approach in many game hair solutions. These can be authored in the DCC app of your choice. - -![](HairGeo.png)(w:700 convert:false) - -#### Hair Textures - -In this use of the UE4 Hair shader, the final result is driven by five primary textures: *Diffuse*, *Alpha*, *Root*, *Depth*, and a unique-per-strand *ID* texture. At Epic, these textures are typically generated using 3ds Max's Hair system, projecting the simulated hair results onto a piece of geometry. However, there are many available options for similar results. - - -| Texture | Name | Description | -|---------|------|-------------| -|![](Diffuse.png)(w:200 convert:false)|**Diffuse**|The Diffuse texture is precisely what one might expect in that supplies the primary diffuse - or *base* - color of the hair itself. It is sometimes desirable to leave this texture uncolored and drive its color via parameters, especially in those cases where a character's hair may take on many different colors. (*TwinBlast_UE4_Demo_Hair_D*)| -|![](Alpha.png)(w:200 convert:false)|**Alpha**|The Alpha texture supplies the areas of opacity for the hair, hiding geometry outside the body of strands. (*TwinBlast_UE4_Demo_Hair_A*)| -|![](Root.png)(w:200 convert:false)|**Root**|The Root texture provides a mask which is used to change the color of the hair from the root to the tip, useful for lightening or darkening hair along its length. (*TwinBlast_UE4_Demo_Hair_Roots*)| -|![](Depth.png)(w:200 convert:false)|**Depth**|The Depth texture is used by Pixel Depth offset to give the illusion of pushing the hair deeper into the hair volume. It can also be used as a basis to change color or shading values for hair at different depths, such as reducing overall specularity as hair falls further toward the scalp. (*TwinBlast_UE4_Demo_Hair_Depth*)| -|![](ID.png)(w:200 convert:false)|**Unique ID**| The Unique ID texture simply provides a unique 0 to 1 (black to white) value for each strand of hair on a given piece of hair geometry. This is used to provide subtle variation within the hair itself. (*TwinBlast_UE4_Demo_Hair_ID*)| - - - -### Hair Shader Properties - -When using the Hair Shader you will notice some new properties available on the main Material node: **Scatter**, **Tangent**, and **Backlit**. - -![](HairProperties.png) - -[REGION:warning]At the time of this writing (4.13), the Backlit property only exists as a part of an early version of the shader. Connections to it are not used internally by the Hair shader and the property can therefore be ignored.[/REGION] - -#### Scatter - -One of the primary reasons we refer to the Hair shader as an *approximation*, rather than a *simulation*, is that it is not actually simulating every individual strand of hair, nor is it simulating perfectly accurate lighting behavior. In the real world, as light bounces off of and transmits through follicles of hair, it will often encounter *other* strands of hair, repeating the same process potentially many times in succession. At this time there is no computing system capable of accurately producing the effects of such a simulation in realtime. - -Nevertheless, the way in which light scatters through a body of hair is still crucial to how realistic that hair appears to be, in a game just as much as in the real world. To control this, the Hair shader provides the Scatter property, which replaces Metallic on your primary shader node and is limited to values between 0.0 and 0.1. Scatter controls how much light can pass into and scatter through the hair *as a whole surface*, rather than per follicle. In simpler terms, this controls how much light passes through the entire body of your character's hair. - -An important point to note about Scatter is that it will tend to be higher for lighter colored hair and darker for darker hair. This follows the physcal rules of the natural world, as darker hair will tend to absorb more light. In practical terms, if you are trying to create a blonde character, you will find that changing the diffuse texture or color is not enough; you will also have to increase the Scatter value as well. - - -[OBJECT:ComparisonSlider] -[PARAM:before] -![Scatter value of 0.0](LowScatter.png)(w:700 convert:false) -[/PARAM] -[PARAM:after] -![Scatter value of 1.0](HighScatter.png)(w:700 convert:false) -[/PARAM] -[/OBJECT] -[REGION:caption]In this example the Diffuse texture has not been modified from its default dark brown color. This illustrates how various tones of hair can be generated just by changing the Scatter value.[/REGION] - -#### Tangent - -The Tangent property replaces the Normal property on the Hair shader. Instead of a typical normal map, the hair shader calculates a tangent. The tangent is calculated as a vector that runs parallel to each strand of hair, pointed back toward the root. In Twinblast's hair shader, this vector is given a random offset in the Z-Axis between 0.3 and -0.3, using the Unique ID texture. This produces a vector which has a random direction within an arc, and aids in providing variation within the anisotropic specular highlights. - -![](HairTangent.png)(w:700 convert:false) -[REGION:caption]In this image the yellow line represents the tangent along a strand of hair, pointing back toward the root.[/REGION] - -Tangents can be mapped in one of two ways: automatically or with the help of a flow map. The automatic method simply requires that that the textures for each sheet of hair be oriented such that the root is toward the top and the tips are toward the bottom. So long as your hair is short, and no sheets are bending around and twisting too much, this approach is adequate. This is the method used on Twinblast's hair. - -##### Flow Maps for Tangency - -The other method requires the creation of a flow map. This is useful if your character's hair is long and is bending and needs to appear to bend and curl more than the actual geometry does, or if the individual texture portions for the hair are oriented in different ways (not top-to-bottom as described above). The flow map will represent the direction the hair is moving in tangent space, or along the surface. Within the Twinblast Bust project, you can find an unused flow map named *T_SparrowHair_Flow*. Below is a comparison of that flowmap and the result of the specularity. - -[OBJECT:ComparisonSlider] -[PARAM:before] -![Final Result](SparowFlowMap.png)(w:600 convert:false) -[/PARAM] -[PARAM:after] -![Flow Map Texturing](SparowFlowMap2.png)(w:600 convert:false) -[/PARAM] -[/OBJECT] -[REGION:caption]Here you can see how the flow map is textured along the surface of Sparrow's hair. Note that the flowmap is only in use on some of the hair sheets, not the entire body of hair. Notice how different values along the flow map subtly shift the specularity along the hair.[/REGION] - - - - -#### Using Pixel Depth Offset with the Hair Shader - -Pixel Depth Offset (PDO) is not a property unique to the Hair shader. In layman's terms, PDO causes pixels to look recessed away from the camera, creating an artificial sense of depth along the surface. Since hair is made up of simple sheets of geometry, as explained in [Hair and Geometry](#hairgeometry) below, the use of PDO can provide a tangible sense of depth to the hair shape as a whole. It also breaks up the intersection point where a plane of hair geometry contacts the scalp, as shown below. - -[OBJECT:ComparisonSlider] -[PARAM:before] -![Without Pixel Depth Offset](PDO_off.png)(w:700 convert:false) -[/PARAM] -[PARAM:after] -![With Pixel Depth Offset](PDO_On.png)(w:700 convert:false) -[/PARAM] -[/OBJECT] - - - - -## Eye Shading - -![](EyeShading.png)(w:700 convert:false) - -Eyes are often referred to as "the windows to the soul." Few aspects of a character have as much influence on the viewer's perception of a character as a real person as that character's eyes. The Eye shader in UE4 is designed to bring realistic rendering of an eye surface, exposing artistic control over each of the biological parts of the eye itself. - -[REGION:warning]The Eye shader in UE4 is highly technical and has been developed such that there are **very strong dependencies** between the shader code, the Material, the shape of the geometry, and the geometry's UV layout. Building an eye from scratch using this shader is not recommended without extensive experience. To that end, we strongly recommend, for those creating realistic humanoid eyes, that you extract the eye geometry from this example and use the eye Material **as-is**, replacing the necessary textures to suit your purpose. [/REGION] - -### Eye Biology - -In order to fully understand the features of the eye it is best to know a little bit of eye biology. Each of the parts you see here are represented in this eye setup, and all can be modified in some way using the exposed parameters in the Material Instance applied to Twinblast's eyes (*MI_TwinBlast_EyeRefractive_Bust*). - -Here is a quick refresher: - -![](EyeDiagram.png)(w:700 convert:false) -|Number|Name|Description| -|------|----|-----------| -|1|Sclera|The sclera is also known as the "white of the eye." This area of the eye is generally very wet and has a slight amount of tactile texture.| -|2|Limbus|The limbus is the dark ring that is present between the iris and the sclera. It is more dominant in some eyes than others, and will tend to fade away when viewed from edge-on.| -|3|Iris|The iris is the ring of color around the center of the eye. When one is said to have "green" eyes, it is because their iris is predominantly green. In a real eye, the iris is a ring of muscle-like fibers that expand and contract, allowing more light into - or closing light out of - the pupil. It is also worth noting that in the real world, the iris is actually more of a disc or cone shape, and does not bulge outward with the rest of the eye.| -|4|Pupil|The pupil is the dark spot at the center of the eye. It is the hole through which light passes so it can be picked up by the rods and cones of the retina.| -|5|Cornea|The cornea is the clear, fluid-filled dome that rests over the surface of the iris. | - -### Refraction within the Eye - -Because the eyeball is filled with fluid, it is given to refracting any light that passes through it. This can be seen in the real world when looking at an eye from multiple angles. The iris and pupil will be distorted by refraction as they are viewed through the cornea. Traditional approaches to solving this for games and film was to create two separate eye surfaces: one that supplied the sclera, iris, and pupil; and another surface on top that supplied the cornea and overall wetness of the eye. This allowed for refraction as the underlying surface was viewed through the wet layer shell. Such an approach was used in Epic's *A Boy and His Kite* tech demo on the boy's eyes. The diagram below shows a representation of the two surfaces. - -![](KiteBoyEyes.png)(w:700 convert:false) - -Using our new Eye shader, however, an even more realistic effect can be achieved with a *single surface*. The refraction of light through the surface of the cornea is now handled entirely within the shader, alleviating the need for underlying geometry. You can experiment with this yourself by opening the *MI_TwinBlast_EyeRefractive_Bust* Material Instance and adjusting the **Depth Scale** property. - -[OBJECT:ComparisonSlider] -[PARAM:before] -![Without Refraction (Depth Scale at 0.0)](EyeNotRefracting.png)(w:700 convert:false) -[/PARAM] -[PARAM:after] -![With Refraction (Depth Scale at 1.2)](EyeRefracting.png)(w:700 convert:false) -[/PARAM] -[/OBJECT] - - -### Eye Authoring - -Earlier in this section we provided a warning that there are strong interdependencies between the code of the Eye shader, the setup of the material, and the geometry of the eye mesh. The following is a high-level overview of what makes the eye setup so particular, which will be useful if you should try replacing the geometry with your own eye mesh for your characters. - -When building your own eyes, we **strongly** recommend that you start using the eye geometry and Material provided in this example. As such, most of the information provided here will be based upon that assumption. - -#### Shape and UV Layout - -Much like the human eye of the real world, the eye mesh is not modeled to be perfectly spherical. Rather, it has a distinct dome at the front to represent the cornea. This gives the eye almost an egg shape. - -![](EyeGeometry.png)(w:400 convert:false) -[REGION:caption]In this image you can see the geometry of the eye viewed from the side in Maya. Note the raised area of the cornea at the front.[/REGION] - -The UV layout for the eye is also critical, as it is from this that the proportions of each eye texture are produced. Fortunately, the UV layout that works best with the Eye shader is relatively basic: a planar projection along the front axis of the eye. Inclusion of backfaces is not extremely important (since they'll be behind the eye anyway), which can be seen on the Twinblast example. - - The UV layout will look like this: - -![](EyeUVs.png)(w:400 convert:false) -[REGION:caption]Notice that the UV layout is centered on the 0-1 space and that the projection looks directly into the cornea. [/REGION] - - -### Eye Textures - -Many of the textures you'll create for your eyes will be based on the UV layout created above, with the exception of the iris map. The list of primary editable textures includes: - -| Texture | Name | Description | -|---------|------|-------------| -|![](ScleraMap.png)(w:200 convert:false) |**Sclera Map**|The sclera map controls the colors of the eye whites, as well as the vein and tissue color that will be present at the edges of the eye. If you wanted your character to be able to have bloodshot eyes, for example, this is the texture you would modify. (*TwinBlast_UE4_Demo_Eye_Sclera_Color*)| -|![](DispMap.png)(w:200 convert:false) |**Mid Plane Displacement Map**|The mid plane displacement map is used to lock down a plane that cuts through the center of the eye, and is used as a basis for offsetting the depth of the iris. (*EyeMidPlaneDisplacement_Example*)| -|![](WetNormal.png)(w:200 convert:false) |**Normal Map**|The normal map does the same job as normal maps in all shaders - it supplies tactile texture variation. In the case of the Twinblast eye setup, it provides tiny lumps and bumps along the wet surface of the eye. (*T_Eye_Wet_Normal*)| -|![](Normal.png)(w:200 convert:false) |**Tangent Map**|The tangent map is used to control the direction the surface is flowing in tangent space. In the case of Twinblast's eye setup, this is used to accentuate the change in direction where the cornea meets the sclera. (*EYE_NORMALS.EYE_NORMALS*)| -|![](IrisTexture.png)(w:200 convert:false)|**Iris Map**|The iris texture is unique in that it does not match the UV layout. Instead, the texure fills the entirety of the resolution. UVs and alpha masks are employed to control the overall iris size, as well as the size of the pupil. If making your own iris maps, try to keep the pupil size reasonably close to the proportions in the supplied texture. (*TwinBlast_UE4_Demo_Eye_Iris*)| - -[REGION:warning]Note that the Tangent Map output is **not** fed directly into the Normal Map input. Rather, it is connected to a **Tangent Output** node, which must be created separately, as seen in the master material **M_HairSheet_Master2**. [/REGION] -![](TangentOutput.png) - - - -### Eye Ambient Occlusion - -The final part of the eye setup for Twinblast is the use of a translucent helper surface to to simulate ambient occlusion around the eye. In the real world - wherever your eye comes in contact with other tissues such as the eyelid or the tear duct - you will see very soft shadowing. The softness is due to the fact that the eye itself is translucent; light will scatter through it. To help simulate this realistically, we have placed a sheet of geometry that covers the eye and provides approximated ambient occlusion, creating a richer degree of realism across the eye. - -The Material applied to this sheet is named *MI_TwinBlast_Eye_Occlusion_Bust* and can be found in Element 3 of the Twinblast model. - -![](AOSheetMaya.png)(w:700 convert:false) -[REGION:caption]This image shows the ambient occlusion sheet geometry in Maya, without the geometry of the face. The border edge of the sheet will perfectly fill the opening of the eyelid. [/REGION] - - -[OBJECT:ComparisonSlider] -[PARAM:before] -![Without AO Sheet](EyeAO_off.png)(w:700 convert:false) -[/PARAM] -[PARAM:after] -![With AO Sheet](EyeAO_on.png)(w:700 convert:false) -[/PARAM] -[/OBJECT] - -## Special Thanks - -Special thanks to [Eugene d'Eon, Steve Marschner and Johannes Hanika](http://www.eugenedeon.com/project/importance-sampling-for-physically-based-hair-fiber-models/) for releasing their work [*The importance of sampling for physically-based hair fiber models*](http://dl.acm.org/authorize?6967840), upon which some of the work of UE4's hair shader is based. diff --git a/Engine/Documentation/Source/Shared/Editor/HLOD/HLOD.CHN.udn b/Engine/Documentation/Source/Shared/Editor/HLOD/HLOD.CHN.udn new file mode 100644 index 000000000000..6e7b08054b57 --- /dev/null +++ b/Engine/Documentation/Source/Shared/Editor/HLOD/HLOD.CHN.udn @@ -0,0 +1,11 @@ +INTSourceChangelist:0 +Availability:NoPublish +Title:HLOD System +Crumbs: + +[EXCERPT:main] +**Hierarchical Level of Detail** meshes (HLODs) have been developed as a way to increase performance and keep the quality bar high for projects using Unreal Engine 4.11 or later. HLODs can replace multiple **Static Mesh Actors** with single, combined **Static Mesh Actor** at long view distances. This helps reduce the number of **Actors** that need to be rendered for the scene, increasing performance by lowering the number of draw calls per frame. +[VAR:ToolTipFullLink] +Engine/HLOD +[/VAR] +[/EXCERPT:main] diff --git a/Engine/Documentation/Source/Shared/Editor/HLOD/HLOD.INT.udn b/Engine/Documentation/Source/Shared/Editor/HLOD/HLOD.INT.udn new file mode 100644 index 000000000000..e546b4ed4b47 --- /dev/null +++ b/Engine/Documentation/Source/Shared/Editor/HLOD/HLOD.INT.udn @@ -0,0 +1,10 @@ +Availability:NoPublish +Title:HLOD System +Crumbs: + +[EXCERPT:main] +**Hierarchical Level of Detail** meshes (HLODs) have been developed as a way to increase performance and keep the quality bar high for projects using Unreal Engine 4.11 or later. HLODs can replace multiple **Static Mesh Actors** with single, combined **Static Mesh Actor** at long view distances. This helps reduce the number of **Actors** that need to be rendered for the scene, increasing performance by lowering the number of draw calls per frame. +[VAR:ToolTipFullLink] +Engine/HLOD +[/VAR] +[/EXCERPT:main] diff --git a/Engine/Documentation/Source/Shared/Editor/HLOD/HLOD.JPN.udn b/Engine/Documentation/Source/Shared/Editor/HLOD/HLOD.JPN.udn new file mode 100644 index 000000000000..37a5b79ddfcb --- /dev/null +++ b/Engine/Documentation/Source/Shared/Editor/HLOD/HLOD.JPN.udn @@ -0,0 +1,11 @@ +INTSourceChangelist:3409833 +Availability:NoPublish +Title:HLOD システム +Crumbs: + +[EXCERPT:main] +**Hierarchical Level of Detail (HLOD)** メッシュは、アンリアル エンジン 4.11 以降を使うプロジェクトのパフォーマンスを高め、クオリティを高く保つために開発されました。HLOD は、表示距離が遠い場合に複数の **Static Mesh アクタ** を、単一に結合された **Static Mesh アクタ** に置き換えることができます。HLOD を使うと、シーンに対してレンダリングする必要がある **アクタ** 数を減らし、1 フレームあたりのドローコール数を少なくしてパフォーマンスを高めることができます。 +[VAR:ToolTipFullLink] +Engine/HLOD +[/VAR] +[/EXCERPT:main] diff --git a/Engine/Documentation/Source/Shared/Editor/HLOD/HLOD.KOR.udn b/Engine/Documentation/Source/Shared/Editor/HLOD/HLOD.KOR.udn new file mode 100644 index 000000000000..433d1062f0ec --- /dev/null +++ b/Engine/Documentation/Source/Shared/Editor/HLOD/HLOD.KOR.udn @@ -0,0 +1,11 @@ +INTSourceChangelist:3409833 +Availability:NoPublish +Title:HLOD System +Crumbs: + +[EXCERPT:main] +**Hierarchical Level of Detail** (계층형 레벨 오브 디테일, HLOD) 메시는 퍼포먼스를 향상시키면서도 퀄리티 기준을 높게 유지할 수 있도록 하기 위한 방편으로 개발된 것으로, 언리얼 엔진 4.11 이상에서 지원됩니다. HLOD 는 다수의 **스태틱 메시 액터** 를 원거리에서 봤을 때 하나의 **스태틱 메시 액터** 로 합치는 기법입니다. 이를 통해 씬에 렌더링해야 하는 **액터** 수를 줄여, 프레임 당 드로 콜 수를 낮춰 퍼포먼스를 향상시키는 데 도움이 됩니다. +[VAR:ToolTipFullLink] +Engine/HLOD +[/VAR] +[/EXCERPT:main] diff --git a/Engine/Documentation/Source/Shared/Editor/MapErrors/MapErrors.KOR.udn b/Engine/Documentation/Source/Shared/Editor/MapErrors/MapErrors.KOR.udn index 160dd62e7d84..d0a799f60937 100644 --- a/Engine/Documentation/Source/Shared/Editor/MapErrors/MapErrors.KOR.udn +++ b/Engine/Documentation/Source/Shared/Editor/MapErrors/MapErrors.KOR.udn @@ -272,7 +272,7 @@ NEEDS DESCRIPTION (#RebuildPaths) [EXCERPT:RebuildPaths] -**패쓰를 리빌드해야 합니다.** +**패스를 리빌드해야 합니다.** [/EXCERPT:RebuildPaths] diff --git a/Engine/Documentation/Source/Shared/Types/FBodyInstance/FBodyInstance.KOR.udn b/Engine/Documentation/Source/Shared/Types/FBodyInstance/FBodyInstance.KOR.udn index 784953d33342..1656e0e43ffe 100644 --- a/Engine/Documentation/Source/Shared/Types/FBodyInstance/FBodyInstance.KOR.udn +++ b/Engine/Documentation/Source/Shared/Types/FBodyInstance/FBodyInstance.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3372845 Availability:NoPublish Title:FBodyInstance RTTs Crumbs: @@ -61,7 +61,10 @@ Engine/Physics/PhysicsBodies#physics ![](PhAT_COM.png) -현재로써는 질량 중심의 실제 위치를 확인할 수 있는 방법이 없지만, 조절하려는 바디의 선형 제동(Linear Damping)을 늘려주면 바디가 낙하할 때 질량 중심으로부터 흔들리는 것을 보고 알 수 있습니다. 레벨에 스켈레탈 메시를 배치하고 피직스를 켜 줘야 실제 느낌이 날 수 있습니다. +Mass Properties (질량 프로퍼티) 표시 플래그는 이동가능 또는 시뮬레이션 바디에 대한 Center of Mass (질량 중심) 및 Inertia Frame (관성 좌표계)를 시각화합니다. 질량 중심은 보통 지오메트리에 삽입되어 있으므로 와이어프레임 렌더링 모드를 켜줘야 합니다. + +![](COM_Geom.png) + [VAR:ToolTipFullLink] Engine/Physics/PhysicsBodies#physics [/VAR] diff --git a/Engine/Documentation/Source/Support/Builds/Builds.INT.udn b/Engine/Documentation/Source/Support/Builds/Builds.INT.udn index 50404d5b184f..5d0ceff76151 100644 --- a/Engine/Documentation/Source/Support/Builds/Builds.INT.udn +++ b/Engine/Documentation/Source/Support/Builds/Builds.INT.udn @@ -9,5 +9,5 @@ topic-icon:%ROOT%/outline_icon.png topic-image:%ROOT%/placeholder_topic.png -[DIR(output:"listbutton" order:"descend" parent:"Support/Builds" org:"hierarchy")] +[DIR(output:"listbutton" order:"descend" parent:"Support/Builds" org:"hierarchy" end:"1")] diff --git a/Engine/Documentation/Source/Support/Builds/Builds.JPN.udn b/Engine/Documentation/Source/Support/Builds/Builds.JPN.udn index 2669e12438cd..b233e5058dc6 100644 --- a/Engine/Documentation/Source/Support/Builds/Builds.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/Builds.JPN.udn @@ -1,138 +1,14 @@ -INTSourceChangelist:3151855 +INTSourceChangelist:3429265 Availability:Public -Title:リリース ノート +Title:リリースノート Crumbs:%ROOT% Description:アンリアル エンジン ビルドのリリースノート parent:%ROOT% order:9 type:landing +topic-icon:%ROOT%/outline_icon.png +topic-image:%ROOT%/placeholder_topic.png -[VAR:Params] -[PARAM:image] - ![%Support/Builds:title%](%ROOT%/placeholder_topic.png) -[/PARAM] -[PARAM:icon] - ![](%ROOT%/outline_icon.png)(convert:false) -[/PARAM] -[PARAM:title] - %Support/Builds:title% -[/PARAM] -[PARAM:description] - %Support/Builds:description% -[/PARAM] -[PARAM:path] - [RELATIVE:Support/Builds] -[/PARAM] -[/VAR] -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Support/Builds:title%](%ROOT%/placeholder_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/outline_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Support/Builds:title% - [/PARAM] - [PARAM:description] - %Support/Builds:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Support/Builds] - [/PARAM] -[/OBJECT] -[/VAR] +[DIR(output:"listbutton" order:"descend" parent:"Support/Builds" org:"hierarchy" end:"1")] -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Support/Builds:title%](%ROOT%/placeholder_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/outline_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Support/Builds:title% - [/PARAM] - [PARAM:description] - %Support/Builds:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Support/Builds] - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:Role] -[OBJECT:Role] -%params% -[PARAMLITERAL:id] -engine -[/PARAMLITERAL] -[/OBJECT] -[/VAR] - -[PUBLISH:Rocket] -[DIR(end:"1" output:"listbutton" order:"descend" parent:"Support/Builds" org:"hierarchy")] -[/PUBLISH:Rocket] - -[PUBLISH:Licensee] -[OBJECT:TopicButtonList] - [PARAM:icon] - [/PARAM] - [PARAM:title] - 2015 - [/PARAM] - [PARAM:description] - [/PARAM] - [PARAM:links] - * [](Support/Builds/ReleaseNotes/2016/4_12) - * [](Support/Builds/ReleaseNotes/2016/4_11) - * [](Support/Builds/ReleaseNotes/2015/4_10) - * [](Support/Builds/ReleaseNotes/2015/4_9) - * [](Support/Builds/ReleaseNotes/2015/4_8) - * [](Support/Builds/ReleaseNotes/2015/4_7) - [/PARAM] -[/OBJECT] - -[OBJECT:TopicButtonList] - [PARAM:icon] - [/PARAM] - [PARAM:title] - 2014 - [/PARAM] - [PARAM:description] - [/PARAM] - [PARAM:links] - * [](Support/Builds/ReleaseNotes/2014/4_6) - * [](Support/Builds/ReleaseNotes/2014/4_5) - * [](Support/Builds/ReleaseNotes/2014/4_4) - * [](Support/Builds/ReleaseNotes/2014/4_3) - * [](Support/Builds/ReleaseNotes/2014/4_2) - * [](Support/Builds/ReleaseNotes/2014/4_1) - * [](Support/Builds/ReleaseNotes/2014/March) - * [](Support/Builds/ReleaseNotes/2014/January) - [/PARAM] -[/OBJECT] - -[OBJECT:TopicButtonList] - [PARAM:icon] - [/PARAM] - [PARAM:title] - 2013 - [/PARAM] - [PARAM:description] - [/PARAM] - [PARAM:links] - * [](Support/Builds/ReleaseNotes/2013/Dec) - * [](Support/Builds/ReleaseNotes/2013/Oct) - * [](Support/Builds/ReleaseNotes/2013/Sept) - * [](Support/Builds/ReleaseNotes/2013/August) - * [](Support/Builds/ReleaseNotes/2013/July) - * [](Support/Builds/ReleaseNotes/2013/June) - * [](Support/Builds/ReleaseNotes/2013/May) - [/PARAM] -[/OBJECT] -[/PUBLISH:Licensee] diff --git a/Engine/Documentation/Source/Support/Builds/Builds.KOR.udn b/Engine/Documentation/Source/Support/Builds/Builds.KOR.udn index 159f1cc8bda9..8a41e71a46b8 100644 --- a/Engine/Documentation/Source/Support/Builds/Builds.KOR.udn +++ b/Engine/Documentation/Source/Support/Builds/Builds.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3151855 +INTSourceChangelist:3429265 Availability:Public Title: 릴리즈 노트 Crumbs:%ROOT% @@ -6,133 +6,9 @@ Description: 언리얼 엔진 빌드 릴리즈 노트입니다. parent:%ROOT% order:9 type:landing +topic-icon:%ROOT%/outline_icon.png +topic-image:%ROOT%/placeholder_topic.png -[VAR:Params] -[PARAM:image] - ![%Support/Builds:title%](%ROOT%/placeholder_topic.png) -[/PARAM] -[PARAM:icon] - ![](%ROOT%/outline_icon.png)(convert:false) -[/PARAM] -[PARAM:title] - %Support/Builds:title% -[/PARAM] -[PARAM:description] - %Support/Builds:description% -[/PARAM] -[PARAM:path] - [RELATIVE:Support/Builds] -[/PARAM] -[/VAR] -[VAR:Topic] -[OBJECT:Topic] - [PARAM:image] - ![%Support/Builds:title%](%ROOT%/placeholder_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/outline_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Support/Builds:title% - [/PARAM] - [PARAM:description] - %Support/Builds:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Support/Builds] - [/PARAM] -[/OBJECT] -[/VAR] +[DIR(output:"listbutton" order:"descend" parent:"Support/Builds" org:"hierarchy" end:"1")] -[VAR:TopicCompact] -[OBJECT:TopicCompact] - [PARAM:image] - ![%Support/Builds:title%](%ROOT%/placeholder_topic.png) - [/PARAM] - [PARAM:icon] - ![](%ROOT%/outline_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - %Support/Builds:title% - [/PARAM] - [PARAM:description] - %Support/Builds:description% - [/PARAM] - [PARAM:path] - [RELATIVE:Support/Builds] - [/PARAM] -[/OBJECT] -[/VAR] - -[VAR:Role] -[OBJECT:Role] -%params% -[PARAMLITERAL:id] -engine -[/PARAMLITERAL] -[/OBJECT] -[/VAR] - -[PUBLISH:Rocket] -[DIR(end:"1" output:"listbutton" order:"descend" parent:"Support/Builds" org:"hierarchy")] -[/PUBLISH:Rocket] - -[PUBLISH:Licensee] -[OBJECT:TopicButtonList] - [PARAM:icon] - [/PARAM] - [PARAM:title] - 2015 - [/PARAM] - [PARAM:description] - [/PARAM] - [PARAM:links] - * [](Support/Builds/ReleaseNotes/2016/4_12) - * [](Support/Builds/ReleaseNotes/2016/4_11) - * [](Support/Builds/ReleaseNotes/2015/4_10) - * [](Support/Builds/ReleaseNotes/2015/4_9) - * [](Support/Builds/ReleaseNotes/2015/4_8) - * [](Support/Builds/ReleaseNotes/2015/4_7) - [/PARAM] -[/OBJECT] - -[OBJECT:TopicButtonList] - [PARAM:icon] - [/PARAM] - [PARAM:title] - 2014 - [/PARAM] - [PARAM:description] - [/PARAM] - [PARAM:links] - * [](Support/Builds/ReleaseNotes/2014/4_6) - * [](Support/Builds/ReleaseNotes/2014/4_5) - * [](Support/Builds/ReleaseNotes/2014/4_4) - * [](Support/Builds/ReleaseNotes/2014/4_3) - * [](Support/Builds/ReleaseNotes/2014/4_2) - * [](Support/Builds/ReleaseNotes/2014/4_1) - * [](Support/Builds/ReleaseNotes/2014/March) - * [](Support/Builds/ReleaseNotes/2014/January) - [/PARAM] -[/OBJECT] - -[OBJECT:TopicButtonList] - [PARAM:icon] - [/PARAM] - [PARAM:title] - 2013 - [/PARAM] - [PARAM:description] - [/PARAM] - [PARAM:links] - * [](Support/Builds/ReleaseNotes/2013/Dec) - * [](Support/Builds/ReleaseNotes/2013/Oct) - * [](Support/Builds/ReleaseNotes/2013/Sept) - * [](Support/Builds/ReleaseNotes/2013/August) - * [](Support/Builds/ReleaseNotes/2013/July) - * [](Support/Builds/ReleaseNotes/2013/June) - * [](Support/Builds/ReleaseNotes/2013/May) - [/PARAM] -[/OBJECT] -[/PUBLISH:Licensee] \ No newline at end of file diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/August/ReleaseNotesAugust2013.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/August/ReleaseNotesAugust2013.JPN.udn index 3c19795ed7d5..176344f0b983 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/August/ReleaseNotesAugust2013.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/August/ReleaseNotesAugust2013.JPN.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:2615072 +INTSourceChangelist:3367470 Title:2013 年 8 月リリースノート Crumbs:%ROOT%, Support/Builds Description: Availability:Licensee -Template:ReleaseNotes.html +Parent:Support/Builds +Order:-6 [TOC(start:2 end:2)] @@ -23,10 +24,10 @@ Template:ReleaseNotes.html * 現時点のエンジン開発ロードマップ: [UE4 Roadmaps](https://udn.unrealengine.com/questions/topics/roadmap.html) * 修正されたバグ: [UE4 Fixed Bugs August 2013](UE4_Fixed_2013_August.xlsx) - * 既知の問題: [UE4 Outstanding Bugs August 2013](UE4_Bugs_2013_August.xlsx) + * 周知のバグ: [UE4 Outstanding Bugs August 2013](UE4_Bugs_2013_August.xlsx) -## 主な新機能 +## 主要な新機能 ####エディタ ツール * **シミュレーション変更を永続的なものにする** @@ -39,12 +40,12 @@ Template:ReleaseNotes.html * プレイモードでも機能します。 * **ツールバーのカスタマイズが、EpicLabs Preference にあります** - * ツールバーのカスタマイズは EpicLabs でオンにできます。 + * **ツールバーのカスタマイズは EpicLabs でオンにできます。 ![](CustomTools_Final.png) * **Edit > Edit Toolbars** の順序で選択し、**Keyboard Shortcuts** ウィンドウからコマンドを互換性のあるツールバーにドラッグできます。 * **テクスチャ インポート中の法線マップ検知** - * エンジンは、テクスチャ マップが法線マップであるかを判断するためにインポート時にテクスチャをヒューリスティックに調べるようになりました。 + * エンジンは、テクスチャ マップが法線マップであるかを判断するためにインポート時にテクスチャを発見的 (ヒューリスティック) に調べるようになりました。 ![](NormMapDet1.png) * LOD、圧縮、その他のデフォルトはインポート時に自動的に設定されます。 ![](NormMapDet2.png) @@ -86,7 +87,7 @@ Template:ReleaseNotes.html * リストの一番上にある _New Project_ アイテムを選択し、**New Project** ウィザードを開きます。 -####レンダリング +#### レンダリング * **マテリアルのパラメータ コレクション** * マテリアルのパラメータ コレクションには大量のマテリアル パラメータを同時に操作する強力な新機能があります。 ![](GlobalParams1.png)(w:420) @@ -107,9 +108,9 @@ Template:ReleaseNotes.html ## 新機能の追加 ####エディタ ツール -* **シミュレーション変更を維持** +* **シミュレーション変更を継続** シミュレーション モードでアクタのプロパティを変更後、こうした変更を選択的に永続的なものにできるようになりました! - * シミュレーション モードでアクタを右クリックしシミュレーション変更を維持、 Keep Simulation Changes (または 'K' キーを押します) を選択します。 + * シミュレーション モードでアクタを右クリックしシミュレーション変更を継続、 Keep Simulation Changes (または 'K' キーを押します) を選択します。 * ヒューリスティック機能を追加して、インポート時に法線マップを特定し、適宜様々な設定を割り当てるようにしました。 * レベル エディタのツールバーに保存ボタンを追加しました。 * **ツールバーのカスタマイズ** -EpicLabs 機能 @@ -142,7 +143,7 @@ Template:ReleaseNotes.html * ブループリント エディタの DestructibleComponent プロパティで被破壊メッシュを設定できるようになりました。 -#### ゲームプレイとフレームワーク +####ゲームプレイとフレームワーク * **カメラ システム** * すべての参加者がプロパティ (パラメータ、ポストプロセスのオーバーライドなど) を設定できるように、どこでも同じ構造体を渡すカメラ情報フローを標準化しました。 * `ACameraActor` が `UCameraComponent` を使用するようにリファクタリングしました。 @@ -179,13 +180,13 @@ Template:ReleaseNotes.html * 様々なウィンドウ サイズを設定するための UE3 コマンドライン パラメータを移植しました(ゲーム ウィンドウの解像度用に ResX/ResY、ゲームウィンドウの位置用に WinX/WinY、コンソール ウィンドウの位置に ConsoleX/ConsoleY) -####レンダリング +#### レンダリング * テクスチャ サンプリングのリミットのトラックは実際にコンパイルした出力を見ることで正確に行われるようになりました。 * WorldPosition マテリアル式はポストプロセス マテリアルで使用できるようになりました。その結果は、ポストプロセスのパスのピクセルを通して見たワールド空間の位置になります。 * WorldPosition マテリアル式では、位置が絶対的なワールド位置であるか、またはカメラに相対的な位置であるかを選択できるようになりました。 * 頂点数が 65536 を超えるスタティック メッシュをインポートおよびレンダリングできるようになりました。 -* ブループリントの固定ライトの修正 - * メッシュまたはライトをブループリントで作成した場合に固定ライトがビルドされないといういくつかの未解決問題があります。 +* ブループリントの Stationary Light (固定ライト) の修正 + * メッシュまたはライトをブループリントで作成した場合に Stationary Light (固定ライト) がビルドされないといういくつかの未解決問題があります。 ####アニメーション / ペルソナ @@ -225,292 +226,292 @@ Template:ReleaseNotes.html ##アップグレード ノート -#### エディタとツール -* uproject ファイルの `GenerateProjectFiles.bat` を削除しました (UE4 ルートの `GenerateProjectFiles.bat`はそのまま残り、生成されません)。 - * これは .uproject ファイルを右クリックして Generate Visual Studio Files を選択して行うようになりました。 - * ビルド フォルダを`.uproject` ファイルに関連付けるには `Engine/Build/BatchFiles/RegisterShellCommands.bat` を使用します。一回にひとつのビルドのみを関連付けます。 -* エディタ起動時に Perforce ダイアログが表示されなくなりました。ソースコントロールのワークフローが合理化されました。 - * ソース コントロールは、エディタの右上隅の色付きのインジケータ ボタンからログインできるようになりました。エディタ全体で様々なメニューにジャストインタイムでアクセスすることもできます。 +####Editor and Tools +* Removed `GenerateProjectFiles.bat` for uproject files (the `GenerateProjectFiles.bat` in the UE4 root remains and is not generated). + * This is now done by right clicking on the .uproject file and selecting Generate Visual Studio Files. + * Use `Engine/Build/BatchFiles/RegisterShellCommands.bat` to associate a build folder with `.uproject` files.Only one build may be associated at a time. +* Perforce dialog no longer pops up on Editor startup.Source control workflow streamlined. + * Source control login is now accessible by clicking the colored indicator button in the top-right hand corner of the Editor.It can also be accessed 'just-in-time' in various menus throughout the Editor. ####ブループリント -*ACharacter はデフォルトの移動入力のバインディングがなくなりました。 - * Character ブループリントが古いデフォルトのネイティブ キーのバインディングを入力に使用するか否かを決める bool、`bAddDefaultMovementBindingsForBlueprint` があります。デフォルトは true です。そのため、カスタム バインディングが必要な場合は、コンテンツはそれを false に設定すべきです。コンテンツを移行する機会があった後には、おそらくこれを取り除きます。 - * 入力軸イベントも移動関数もブループリントにエクスポーズされました。SideScrollerTemplate と ThirdPersonTemplate は例として更新されました。 -* テンプレート デフォルト マップ : テクスチャ データを減らすために Atmospheric fog の高度の数を 32 から 2 に減らしました。 -* Atmospheric fog - ブループリントで作成した Atmospheric fog のコンポーネントを事前計算したデータで維持することが可能になりました。 -* ブループリントは無効な文字を含む名前変更はできません。これはブループリントの実行を阻むからです。 -* `SceneComponent::AttachTo` のアタッチタイプは、ブールから列挙型変数に変更されました。 - * `KeepRelativeOffset` - 現在の相対的な変形を維持します。 - * `KeepWorldPosition` - 現在のワールドの変形を維持します。 - * `SnapToTarget` - 現在の相対的な変形をリセットします。 -* `Actor::MakeMIDForMaterial` は非推奨になりました。CreateMID 関数がマテリアル ライブラリに追加されました。 -* CreateMID を使用する代わりに CreateMIDForElement または CreateMIDForElementFromMaterial を利用します。 -* マテリアル パラメータ コレクションのブループリント関数は、キズメットの関数ライブラリにあります。 +* ACharacter no longer has default movement input bindings. + * There is a bool `bAddDefaultMovementBindingsForBlueprint` that determines whether a Character Blueprint uses the old default native key bindings for input or not.Default is true, so content should set it to false if they want custom bindings.Well probably remove this after people have a chance to migrate content. + * Input axis events are exposed to Blueprints, and movement functions are exposed as well.SideScrollerTemplate and ThirdPersonTemplate have been updated as examples. +* Template Default map : changed atmospheric fog altitude number from 32 to 2, to reduce texture data. +* Atmospheric fog - allow Blueprint-created atmospheric fog components to maintain precomputed data +* Blueprints cannot be renamed to include invalid characters as this was breaking the Blueprint execution. +* `SceneComponent::AttachTo`'s attach type changed to enum from bool + * `KeepRelativeOffset` - Keep current relative transform + * `KeepWorldPosition` - Keep current world transform + * `SnapToTarget` - Reset current relative transform +* `Actor::MakeMIDForMaterial` has been deprecated.CreateMID function is added in the Material Library. +* Instead of using CreateMID, utilize CreateMIDForElement or CreateMIDForElementFromMaterial +* Material parameter collection Blueprint functions are now in a kismet function library [REGION:note] - 注記事項:これは以前のマテリアル パラメータ コレクションのブループリント関数を break します。既存のノードを置き換えなければなりません。 + Note: this breaks the previous material parameter collection Blueprint functions.Existing nodes will have to be replaced. [/REGION] -* シェーダー開発では、ConsoleVariables.ini で `r.ShaderDevelopmentMode` を有効にします。LogShaders はコンパイル エラーでリトライする方法ではなくなりました。 +* For shader development, enable `r.ShaderDevelopmentMode` in ConsoleVariables.ini.LogShaders is no longer the method to get retry on compile error. -#### ゲームプレイとフレームワーク -* あるクラスのすべてのソースをその独自のファイルに入れるためのソース コードの再編成 - * `Actor`、 `Controller`、 `GameReplicationInfo`、 `PlayerReplicationInfo`、 `WorldSettings`、 `Character`、 `Pawn` に影響を及ぼします。 - * `ActorReplication.cpp`、 `ActorEditor.cpp`、 `WorldSettings.cpp` を追加しました。 - * `Script.cpp` を削除しました。 -* PlayerController の入力コンポーネントはコンストラクタで作成されなくなりました。ポーンと同様に仮想関数の SetupInputComponent でもバインディングを行います。 -* `PlayerController.GetInputAnalogStickState` は、未加工のハードウェア値の代わりにゲーム値 (反転とデッドゾーンの適用後) を戻すようになりました。 -* `BIND_` マクロから ConsumeInput を取り除きました。マクロのバインド後にコードから `InputAction`/`InputAxis` を設定するには、以下のような方法で行うことができます。 +####ゲームプレイとフレームワーク +* Reorganization of source code to put all source for a class in its own file(s) + * Affects `Actor`, `Controller`, `GameReplicationInfo`, `PlayerReplicationInfo`, `WorldSettings`, `Character`, `Pawn` + * Added `ActorReplication.cpp`, `ActorEditor.cpp`, `WorldSettings.cpp` + * Remove `Script.cpp` +* PlayerController input component is no longer created in the constructor.Bindings should be done, similar to Pawn, in the virtual function SetupInputComponent. +* `PlayerController.GetInputAnalogStickState` now returns game value (after invert and dead zones have been applied) instead of the raw hardware value. +* ConsumeInput removed from `BIND_` macros.To set `InputAction`/`InputAxis` properties from code after binding the macro can do something similar to: BIND_ACTION(InputComponent, "Fire", IE_Pressed, &AQAPlayerController::OnTriggerPressed); InputComponent->ActionBindings.Last().bConsumeInput = false; -* `MaxDrawDistanceScale` システム設定は新しい `r.ViewDistanceScale` コンソール変数に置き換えられました。 -* `LocalMap` は取り除かれ、DefaultMap を指定するために使用する唯一の設定は `Map` になりました。 -* BeginPlay をリファクタリング - * `PreBeginPlay`/`BeginPlayComponent`/`PostBeginPlay` は、以下のように名前変更されました。`PreInitializeComponents`/`InitializeComponent`/`PostInitializeComponents` - * ブループリントの `ReceiveBeginPlay` イベントは、プレイヤーのスポーン後に発行されるようになりました。 - * `LevelScriptActor.BeginGame` イベントは ReceiveBeginPlay に変換されました。 - * サブレベルでストリーミングし、その配置したアクタは ReceiveBeginPlay 呼び出しを受けます。 -* 多くのカメラ関連の関数のシグネチャは、緩やかな location/rotation/FOV の値の代わりに、フルビュー ステートを含む `FMinimalViewInfo` を取るように変更されました。 -* プロジェクトの最初のバッチ、エンジンとエディタの設定は、新しい Settings UI フレームワークを使用するようにリファクタリングされました。 +* `MaxDrawDistanceScale` system setting has been replaced by new `r.ViewDistanceScale` console variable. +* `LocalMap` has been removed, `Map` is now the only setting used to specify the DefaultMap +* BeginPlay refactor + * `PreBeginPlay`/`BeginPlayComponent`/`PostBeginPlay` renamed to `PreInitializeComponents`/`InitializeComponent`/`PostInitializeComponents` + * `ReceiveBeginPlay` event in Blueprints now fires after the player has been spawned. + * `LevelScriptActor.BeginGame` event converted to ReceiveBeginPlay + * Streamed in sublevels and their placed actors get ReceiveBeginPlay calls +* The signatures of many camera related functions have changed to take a `FMinimalViewInfo`, containing a full view state, instead of loose location/rotation/FOV values. +* The first batch of project, Engine and Editor settings have been refactored to use the new Settings UI framework -####レンダリング -* StaticSwitchParameter マテリアル式はいずれかの入力が接続されない場合にエラーを出力するようになりました。これにより、既存のマテリアルがコンパイルされなくなることがあります。 +#### レンダリング +* StaticSwitchParameter material expressions now emit an error if either inputs are not connected.This may cause some existing materials to not compile. -####アニメーションとペルソナ -* `USkeletalMesh::Sockets` はプライベートになりました。ソケットのリストを取得するために、`GetActiveSocketList()` と `GetMeshOnlySocketList()` が追加されました。これはエディタのみのコードです。 -* `FKSphereElem`/`FKBoxElem`/`FKSphylElem` はリファクタリングされて、フルの FMatrix ではなく最小限の位置、方向の情報を格納するようになりました。こうしたクラスを使用しているコードは変更する必要があります。 +####Animation and Persona +* `USkeletalMesh::Sockets` is now private. `GetActiveSocketList()` and `GetMeshOnlySocketList()` have been added to get the list of sockets.This is editor only code. +* `FKSphereElem`/`FKBoxElem`/`FKSphylElem` have been refactored to store minimal position/orientation info, rather than a full FMatrix.Code using these classes will need to be changed. #### サウンド -* `ReverbVolumeToggleable` は `ReverbVolume` と結合されました。 +* `ReverbVolumeToggleable` combined with `ReverbVolume` ####オンライン -* リファクタリングされたオンライン サブシステム、OnlineProfileInterface は OnlineIdentityInterface と結合されます。 - * 既存のOnlineProfileInterface 機能は削除できるように非推奨になりました。 -* Http モジュールは起動時にインターネット接続をチェックしなくなりました。 - * これは WinInet のブロッキング呼び出しであり、不要なものでした。いずれにせよ接続がなければ非同期要求は失敗するからです。 -* Http モジュールは実際に http 要求をすることを実際に無効にするフラグを持ち、代わりとして単に完了デリゲートを呼び出します。 - * `DefaultEngine.ini`で : +* Refactored Online Subsystem OnlineProfileInterface to be combined with OnlineIdentityInterface + * Deprecated existing OnlineProfileInterface functionality so that it can be deleted +* Http module no longer checks for internet connection at startup + * This was a blocking call for WinInet and not necessary since async request would fail anyway without a connection +* Http module has a flag to disable actually making http requests and just calls completion delegates instead + * In `DefaultEngine.ini`: [Http] bEnableHttp=false -* Http WinInet は、INTERNET_FLAG_RELOAD を介してキャッシュされたデータに依存する代わりに常にサーバーからダウンロードします。 +* Http WinInet implementation always downloads from server instead of relying on cached data via INTERNET_FLAG_RELOAD ####コア -* `TPreallocatedArray` は削除しました。代わりに `TArray>` を使用してください。 -* エディタまたはブループリントで表示されていた非推奨プロパティはエラーになります。非表示にしてください。 -* `AActor` からのナビゲーション関連の関数のリファクタリングのファースト パス。すべてのナビゲーション関連のアクタは `INavRelevantActorInterface` を実装する必要があります。 -* `TAssetPtr` タイプはリビルドされており、アセット データの非同期ロードに使用できます。 - * `FStringAssetReference` はアセットの名前を含む構造体であり、ロードされていないデータを参照するために使用できます。 - * `TAssetPtr` は `TWeakObjectPointer` に類似していますが、現在ロードされていないデータの参照には使用できません。 - * 以前の `TAssetPtr` の使用は機能しません。シリアル化に `FStringAssetReference` を使用するようになったからです。つまり、クッキングとリダイレクトで適切に機能します。`TAssetPtr` によって使用される `FStringAssetReference` に `.GetUniqueID()` でアクセスすることができます。 - * `FStringAssetReferences` と `TAssetPtrs` をプロパティとして使用し、エディタ UI で 常にロードされないデータへの参照を作成します。変換できます。 - * `FStreamableManager` には、 `FStringAssetReferences` を非同期にロードするための関数があり、完了時にはコールバックします。これを使用することにより、メイン スレッドを停止させることなくアセット グループのロードをリクエストできます。 -* プラグインはプラグイン UI で切り替え、有効化、無効化できるようになりました。 - * ゲームでプラグインを使用している場合は、`+EnabledPlugins="YourPluginName"` を `DefaultGame.ini` の `[Plugins]` セクションに追加しなければなりません。 -* ティック グループの名前を AsyncWork の代わりにPre/During/PostPhysics に変更します。 - * `bTickBeforePhysics` フラグを削除します。 -* `IMPLEMENT_PRIMARY_GAME_MODULE` は生成された UELinkerFixup 関数の存在に依存しますが、この関数はすべてのモジュールで `IMPLEMENT_MODULE` が適切にセットアップされていることを必要とします。 -* アンリアルの列挙型変数を、`GetEnumString()` を使用する文字列に変換することは、コア (かつてはエンジン) から行えるようになりました。 +* `TPreallocatedArray` has been removed.You should instead use `TArray>`. +* Editor-visible or Blueprint-visible deprecated properties are now an error.They should be made non-visible. +* First pass of refactoring navigation-related functions out of `AActor`.Now all navigation relevant actors need to implement `INavRelevantActorInterface` +* `TAssetPtr` type has been rebuilt, and can now be used for asynchronous loading of asset data + * A `FStringAssetReference` is a structure that contains the name of an asset, and can be used to refer to data that is not loaded. + * A `TAssetPtr` is similar to a `TWeakObjectPointer`, but it can be used to refer to data that is not currently loaded. + * Any previous uses of `TAssetPtr` will not work, as it now uses `FStringAssetReference` for serialization.This means that it works properly with cooking and redirects.You can access the `FStringAssetReference` used by a `TAssetPtr` with `.GetUniqueID()`. + * You can use `FStringAssetReferences` and `TAssetPtrs` as properties, and the editor UI will let you create references to data that is not always loaded.You can convert a + * `FStreamableManager` now has functions for asynchronously loading `FStringAssetReferences`, with callbacks on completion.You can use this to request loading groups of assets without stalling the main thread +* Plugins may now be toggled enabled/disabled in the plugins UI. + * If your game uses a plugin, you must add `+EnabledPlugins="YourPluginName"` to the `[Plugins]` section of `DefaultGame.ini` +* Rename tick groups to Pre/During/PostPhysics instead of AsyncWork + * Remove `bTickBeforePhysics` flag +* `IMPLEMENT_PRIMARY_GAME_MODULE` now depends on the generated UELinkerFixup function existing, which in turn requires all modules to have `IMPLEMENT_MODULE` setup properly. +* Converting Unreal Enums to strings using `GetEnumString()` can now be used from Core (was in Engine) ####プラットフォーム -* UnrealBuildTool と IPhonePackager が使用する一部の環境変数名を変更/修正しました。Search `*.cs` for: `"ue`. -* Dangerously Fast モードを追加しました。これは実行可能ファイルを再コンパイルし、プロビジョンのようなものはコピーしません。Rebuild/Clean はひとつの slow モードのコンパイルを実行します。 +* Changed/modified some environment variable names used by UnrealBuildTool and IPhonePackager.Search `*.cs` for: `"ue`. +* Added Dangerously Fast mode, which will just recompile the executable, it won't copy provisions, or anything like that.A Rebuild/Clean will perform one slow mode compile. ## 継続事項と改善 ####エディタ ツール -* **マチネ** - * スレート通知が表示され、ユーザーに対してマチネ トラックに静的ライトを追加できないことを伝えます。 - * Matinee Reduce キー メニューが正確に表示されるようになりました。 - * マチネのイベント名テキスト ボックス エントリのウィジェットに最長幅を与え、たくさんのテキストを貼り付けた場合にアサートしなくなりました。 - * Editing Crosshair (クロスヘア (照準) 編集) 操作でチェックボタンを使用し、メニューでオンオフのステートを表示します。 +* **Matinee** + * A Slate notification now appears to tell the user that they can't add a Static Light to a Matinee track + * The Matinee Reduce keys menu now displays correctly + * Gave the Matinee event name text box entry widget a maximum width so it doesn't assert when pasting lots of text + * Use a check button for the Editing Crosshair action to display on/off state in the menu * **Play In Editor/Simulate In Editor** - * PIE GameplayViewport が有効な場合、UDK リモート入力はそのビューポートに対してのみスケーリングされ、ルーティングされます。 - * Play-In-Editor (PIE) 設定は Settings UI で設定できるようになりました。 - * シミュレーション中にeject (制御解除) から possess (制御取得) に切り替えた場合に、アクタは選択解除されなくなりました。 -* **ビューポート** - * 平面ワイヤーフレーム メッシュは正投影ビューで可視状態になります。 - * アンビエント オクルージョンをビジュアル化できるようになりました。これは、表示フラグ経由ではなく [Visualize Buffer ] メニューから行います。 - * レベル ビューポートのコンテンツ メニューにある **Attach To** オプションは検索欄のテキストを自動的にフォーカスします。 - * LevelStreamingVolume アクション、**Level Streaming Volume Previs** をビジュアル化するためのエディタのユーザー設定を追加しました。 -* **ワールド ブラウザ** - * ランドスケープではないレベルに対してレベル境界によるスナップを追加しました (無効にするには、**Ctrl** を押します)。 - * **File > Open World...** コマンドをエディタのメインメニューからワールド ブラウザのメインメニューに移動しました。 - * OS 標準の 'Browse for folder' ダイアログの代わりにカスタムの 'Open world location' ダイアログを追加しました。 -* **シーンアウトライナー** - * シーン アウトライナーを使って、アクタの名前変更を元に戻すことができるようになりました。 - * シーンアウトライナーを変更し、アウトライナーで表示されていない場合、選択したものだけを表示しスクロールできるするようにしました。 - * SIE/PIE 中にレベルがストリームイン / ストリームアウトする場合にシーンアウトライナーが更新するようになりました。 -* **ランドスケープ** - * コピーとギズモの操作に元に戻す機能を追加しました。 - * レイヤーがない場合に [Gizmo Remove Layer] ボタンを無効にします。 - * ランドスケープ プロキシでレベルを直接ワールド ブラウザから作成する機能を追加しました。ランドスケープで事前に最低ひとつのロードされたレベルがあることを必要とします。 -* **フォリッジ** - * マップのリビルド通知に接続し、壊れた/不要になったコンポーネントが PIE をクラッシュさせるのを回避することに反応してフォリッジ インスタンスを BSP コンポーネント全体で移行します。 - * リビルドするジオメトリがオリジナルのターゲット BSP を取り除く場合にターゲットとなっていないフォリッジ インスタンスを削除しないでください。 -* **メッセージ ログ** - * メッセージ ログの API が合理化されました。メッセージ ログ出力がこれまでのエディタからだけではなく、すべてのモジュールから利用可能になりました。 - * 複数の重複メッセージ ログはエディタの起動時に表示されなくなりました。 - * メッセージ ログはレベル変更時、ライティングのビルドのマップ チェック実行時に誤ってポップアップされることはなくなりました。 -* **自動保存** - * 自動保存は、プロジェクトを何もロードしない状態で実行すると無効になるようになりました。これはプロジェクトのロード前に新規プロジェクト画面にいる場合の自動保存を回避するためです。 - * 単にメニューだけでなく、スライダー / スピンボックス / メニューとインタラクションする場合に自動保存通知を開くことをサスペンドします。 -* **UI 全般における改善点** - * 最近使用したレベルをサブメニューに移動しました。 - * 最近使用したプロジェクトは通常のメニュー アイテムを使用するように変更しました。 - * アイコンと可動性のインジケータはハイライトされたときにブラックに変わらなくなりました。 - * ScrollBox RMB のスクロールはリストビューと同じような挙動をします。 - * エスケープ キーを押して新規レベルのダイアログ ボックスを閉じることができるようになりました。 - * エスケープ キーを押してsave all (すべてを保存する) ダイアログ ボックスを閉じることができるようになりました。 - * エディタ起動時にフルフォーカスし、エディタ ウィンドウ内でクリックする必要なく、キーボードのショートカットが正確に機能するようになりました。 - * Settings Editor カテゴリで検索ボックス欄はデフォルトでフォーカスされるようになりました。 - * [Build and Submit] ウィンドウでパッケージをファイルに名前変更しました。 - * STextEntryPopup 引数に MaxWidth 引数を追加しましたが、デフォルトではバインドされていません。 - * ユーザーのデスクトップが右側のプライマリ モニターで設定されている場合、左側のモニターのサブメニューは右端から入ってくることはありません。 - * クックしたコンテンツの警告ダイアログには、実行の失敗理由がより詳細に説明されます。 - * **Build > Lighting Info > LightMap Resolution Adjustment** メニュー内のスタティックメッシュと BSP サーフェスのアイテムが正しいチェックボックス画像を使用し正しく表示されるようにします。 - * ブループリントのプロパティ タブにある [Collision Profile Reset to Default] ボタンの黒のボーダーを取り、他のものと同じように見えるようにしました。 - * インポート アセットのコンテキストメニューのための 16x アイコンを作成しました。 - * 新規アセットに対して複数のリクエストされたクラス アイコンの最初のWIP パス - * プレースホルダー 16x アイコンを置き換えるために新規アイコンが作成されました。 - * 現在、16x アイコンであるすべてのメニュー アイテムについて新規 40px アイコンを作成しました。 - * 5 つのメイン エディタのツール アイコンの新規アイコンと、選択したステートに対して色を変更するアイコン作成しました。アイコンはコードの接続を必要とします。 - * デベロッパ ツール/モジュールのメニューアイテムに @ 16x の新しいビューメニュー アイコン。 - * すべてのウィンドウ メニュー アイテムに @ 16px の新規アイコンを作成しました。これは、メニュー タブでも使用します。 - * 欠落しているNavMeshModifier のプレースホルダー アイコンを 16x & 64x で作成しました。 - * 汎用コマンドと 512px ソース アイコン用に 40px アイコンを作成しました。 - * 複数のボリューム タイプについて 16px & 64px で新規アイコンを作成しました (コンテンツ/プレースメント ブラウザで使用)。 - * 様々な 128px プラグイン アイコンと 20px フォルダー アイコンに対してプラグイン ペインで使用するための新規アイコンを作成しました。 - * 最近使用したレベルと最近使用したプロジェクトの 16 px アイコンを新たに作成しました。 - * 多数のエディタ ウィンドウのタブとメニューにあるエントリにアイコンを追加しました。 - * プレースメント ブラウザにあるボリューム タイプのアイコンを追加しました。 - * プラグイン エディタでさらにアイコンのサポートを追加しました。 -* 中央化されたプロジェクトと Editor settings UIの実装を継続しました。 -* FGuidProperties の詳細ビューのカスタマイズを追加しました。 -* リビルド モデルは、モデルのレベルを利用できない場合 (一定条件下で起こります) にワールドのカレント レベルを使用するようにフォールバックするようになりました。 -* Copy component プロパティはインデックスのミスマッチを考慮するようになりました。 -* テンプレート マップは、正しい名前を表示するようになりました。 -* Swarm はレベルのビルド実行時にデフォルトで最小化で実行するようになりました。 -* 新規エントリが追加すると、ユーザーがスクロールしなければ出力ログは一番下にのみスナップします。 -* DefaultPath は Windows のファイル ダイアログではフルパスとして扱われます。これは、他のブランチとの混乱を回避します。 -* **Alt + drag** のアクタの複製のパフォーマンスを改善しました。これは、エクスポータを登録し、レベルのような大きな UObject のシリアル化のパフォーマンスを向上させることで実現しました。 -* ブラシとボリュームのクラスを適切にタグ付けし、自由に変換できるようにします。 -* Select All Additive Brushes などのブラシ グループを選択する場合、以前のアクタ選択を破棄します。 -* 被破壊メッシュエディタのユーザビリティの向上。 -* アセット レジストリで見つかった長いパッケージ名に変換できない有効なパッケージ文字だけを持つファイルはスキップされるようになりました。 -* ヒット プロキシにテンプレート HitProxyCast を追加しました。 -* アンカーを持つローカル ドキュメントの URL はブラウザで正しく開くようになりました。 + * When a PIE GameplayViewport is active, UDK remote input will be scaled and routed only to that viewport + * Play-In-Editor (PIE) settings can now be configured in the Settings UI + * Actors are no longer unselected when switching from eject to possess while simulating +* **Viewports** + * Planar wireframe meshes are now visible in orthographic views + * Visualize Ambient Occlusion is now available via the Visualize Buffer menu rather than via a showflag. + * **Attach To** option in level viewport content menus now automatically gives text focus to the search field + * Added an Editor user setting for the visualizing LevelStreamingVolume actions:**Level Streaming Volume Previs** +* **World Browser** + * Added snapping by level bounds for non-landscape levels (Hold **Ctrl** to disable it) + * Moved **File > Open World...** command from the Editor main menu to the World Browser main menu + * Added custom 'Open world location' dialog instead of OS standard 'Browse for folder' dialog +* **Scene Outliner** + * You can undo an Actor rename in the Scene Outliner + * Changed the Scene Outliner to only scroll the selection into view when it wasn't visible in the outliner + * SceneOutliner now updates when levels are streamed in/out during SIE/PIE +* **Landscape** + * Added Undo for Copy and Gizmo operations + * Disable Gizmo Remove Layer button when there is no layer + * Added ability to create levels with landscape proxies directly from the world browser.User needs to have at least one loaded level with landscape beforehand +* **Foliage** + * Hook up to notifications for map rebuilds and migrate foliage instances across BSP components in response to avoid broken/obsolete components crashing PIE + * Do not delete untargeted foliage instances if rebuilding geometry removes the original target BSP +* **Message Log** + * Message log API has been streamlined.Message log output is now usable from all modules, not just Editor modules as before + * Multiple duplicate message logs now don't appear on Editor startup + * Message logs now don't pop up incorrectly when changing levels, running map check of building lighting +* **Autosave** + * Now disabled when running without any project loaded.This is to prevent autosave while in the new project screen before loading any projects + * Suspend opening an autosave notification when interacting with sliders/spinbox/menus not just menus +* **General UI Improvements** + * Moved the Recent Levels into a submenu + * Changed the Recent Projects to use regular menu items + * Icons and mobility indicator no longer turn black when highlighted + * ScrollBox RMB scrolling now behaves the same as ListView + * The user can now press the escape key to close the new level dialog box + * The user can now press the escape key to close the save all dialog box + * On launch the Editor now has full focus so keyboard shortcuts now work correctly without having to click inside the Editor window + * The search box field is now in focus by default in the Settings Editor categories + * Renamed Packages to Files in the Build and Submit window + * Added a MaxWidth to STextEntryPopup arguments - still unbounded by default + * When a user's desktop is configured with a right-hand primary monitor, submenus on the left-hand monitor now don't fly in from the far right + * Cooked content warning dialog explains why its failed to run in more detail + * Make the Static Meshes and BSP Surfaces items within the **Build > Lighting Info > LightMap Resolution Adjustment** menu use the right check box images so they display correctly + * Removed the black border on the Collision Profile Reset to Default button in the Blueprint property tab so it looks like the others + * Created 16x icon for import asset context menu + * Initial WIP pass of multiple requested class icons for new assets + * New icon created to replace placeholder 16x icon + * Created new 40px icons for all menu items currently with a 16x icon + * Created new icons for the 5 main editor tool icons, along with color change icons for the selected states.Icons require code hook-up + * New view menu icon for developer tools/modules menu item @ 16x + * Created new icons for all window menu items @ 16px, also to be used for menu tabs + * Created placeholder icons for missing NavMeshModifier at 16x & 64x + * Created 40px icon for generic command & 512px source icon + * Created new icons at 16px & 64px for multiple volume types (used in content/placement browsers) + * Created new icons for the various 128px plugin icons & 20px folder icons for use on the plugins pane + * Created new 16px icons recent levels & recent projects + * Added icons for a number of editor windows' tabs and their entries in the menu + * Added icons for volume types in placement browser + * Added additional icon support in plugins editor +* Continued to implement centralized project and Editor settings UI +* Added details view customization for FGuid properties +* Rebuild model now falls back to using the worlds Current Level when the models Level isn't available (occurs under certain conditions) +* Copy component properties now takes into account index mismatch +* Template maps now show the correct names +* Swarm now runs minimized by default when running level builds +* OutputLog now only snaps to the bottom, when new entries are added, if the user hasn't scrolled away +* DefaultPath is now treated as a full path in the Windows file dialog, which avoids confusion with other branches +* Improve **Alt + drag** Actor duplication performance by registering exporters & improving performance of serializing large UObjects like levels +* Properly tag Brush and Volume classes so that they can be freely converted +* Discard previous actor selection when selecting brush groups, such as Select All Additive Brushes +* Improving usability of destructible mesh editor +* Any files discovered by the asset registry which cannot be converted to a long package name with only valid package characters will now be skipped +* Added a template HitProxyCast for hit proxies. +* Local documentation URLs that have anchors now open in browser correctly ####ブループリント -* ブループリント エディタでは、変数、関数、グラフ、マクロ、およびデリゲートは、**My Blueprint** ウィンドウでインラインで名前変更されるようになりました。 -* フォーカスに影響を与えるべきではないポップアップと通知は影響を与えなくなりました。 -* ブループリント エディタのパレット ウィンドウからの欠落しているアクションが表示されるようになりました。 -* アクタからブループリントを作成する場合、成果物のブループリントではすべてのコンポーネントを不自然に回転させません。 -* コンテンツ ブラウザのブループリント サムネイルに小さな改善を数多く加えました。 -* ブループリント エディタのコンポーネント モード内の詳細タブでネイティブ コンポーネントのプロパティに加えた変更は、ブループリントに基づきアクタのインスタンスに正しく伝搬されるようになりました。 -* ブループリントのプレビュー シーンでアクタ / オブジェクトに対してスクリプトの例外 (例、ブレークポイント) はトリガーされなくなりました。さらにブループリントのプレビュー シーンは PIE/SIE セッションがアクティブな間はティックされなくなりました。そのため、スクリプトのデバッグ中にメッセージ ログが見えにくくなりません。 -* ブループリント グラフの変数ノードは、プロパティが存在しないか非推奨である場合にコンパイル後に警告を表示するようになりました。 -* ブループリント グラフで **Switch on Int** ノードのデフォルトの出力ピンを取り除いてもエディタを再度開いた後にブループリントがコンパイルに失敗することはなくなりました。 -* ブループリントの diff グラフ リストはスクロール可能になり、その他の点でも改善を加えました。 -* ブループリント エディタは、カスタム イベント ノードをコピー/貼り付け/元に戻す/貼り付ける場合にクラッシュしなくなりました。 +* In the Blueprint Editor, variables, functions, graphs, macros, and delegates are now renamed inline in the **My Blueprint** window +* Pop-ups and notifications that should not affect focus should no longer. +* Missing actions from the Palette window in the Blueprint Editor should now appear. +* When creating a Blueprint from actor, the resulting Blueprint will not have all the components rotated strangely. +* Many minor improvements to Blueprint thumbnails in the content browser. +* Changes made to native component properties in the Details tab within Components mode of the Blueprint editor will now correctly propagate out to any Actor instances based on the Blueprint. +* Script exceptions (e.g. breakpoints) are no longer triggered for actors/objects in the Blueprint preview scene.Additionally, the Blueprint preview scene is no longer ticked while a PIE/SIE session is active, so it does not pollute the message log during script debugging. +* Variable nodes in a Blueprint graph will now display a warning after compilation if the property no longer exists or was deprecated. +* Removing the Default output pin on a **Switch on Int** node in a Blueprint graph will no longer cause the Blueprint to fail to compile after re-opening the editor. +* Blueprint Diff graph list now scrollable and other misc improvements. +* Blueprint editor no longer crashes when copy/paste/undo/pasting custom event nodes -#### ゲームプレイとフレームワーク -* 階層のパスファインド -* カスタムの navmesh 接続 (offmesh リンク) :セグメント間。 -* WorldSettings は`.ini` ファイルがマップで保存されているクラスとは別のクラスを示している場合は、新規クラスに移行されます。 -* bPrintToLog とフラグ付けされるブループリントの PrintString メッセージは、コンソールおよびログで表示されるようになりました。 -* 入力キー ノードはプロパティの詳細パネルから切り替えられるバウンド キーを持つことができるようになりました。 -* 様々なスケルタル コントロール関数に DLL エクスポートを追加しました。 -* 効力のなくなった UJsonObject クラスを削除しました。 -* 非推奨の USkeletalControl のパラレル階層を取り除きました。 -* ボックスのクエリ パラメータを Extents から HalfExtents に名前変更しました。ボックスの境界の代わりに半径を示すようにしました。 -* Interp プロパティの任意のネスティング (例、Component.Struct.Prop) およびマチネのトラック名のリダイレクション (INI マップの MatineeTrackRedirectsで) のサポートを追加しました。 -カメラのシェイク強度からの切り捨て (整数 FRotator のレガシー) を取り除きました。 +####ゲームプレイとフレームワーク +* Hierarchical pathfinding +* Custom navmesh connections (offmesh links): segment to segment +* WorldSettings will be migrated to a new class if the `.ini` file dictates a different class than that which was saved in the map. +* Blueprint PrintString messages flagged bPrintToLog now display in console as well as log. +* Input Key nodes can now have the bound key switched from the property details panel. +* Added DLL export to various skeletal control functions. +* Removed dead UJsonObject class. +* Got rid of deprecated USkeletalControl parallel hierarchy. +* Renamed box query parameter from Extents to HalfExtents, indicating that it is the box radius instead of bounds. +* Added support for arbitrary nesting of Interp properties (e.g., Component.Struct.Prop), and redirection of Matinee track names (in the INI map MatineeTrackRedirects). +* Removed a truncation from camera shake strength (legacy of integer FRotator). -####レンダリング -* エディタで実行しない場合、ウィンドウのリサイズ時にすべてのシーンのレンダリング ターゲットは再割り当てされます。これにより、より低い解像度に変更する際にメモリを回復できます。 -* ParticleParameter の分布は GPU エミッタで様々なプロパティを選択できなくなりました。以前は、選択可能でしたが機能しませんでした。 -* Random および Random_Blend 補間の方法は GPU エミッタで選択できなくなりました。.以前は、選択可能でしたが機能しませんでした。 -* パーティクル エミッタのエディタ LOD 値はロード時に 0 に設定されます。 -* **Texture Streaming** - テクスチャをどのようにストリーミングするか (またはしないか) を決める単純なロジックで、動的テクスチャ (ブループリントを含む) に対して修正しました。 -* StaticSwitchParameter マテリアル式はいずれかの入力が接続されない場合にエラーを出力するようになりました。 -* velocity バッファに描画するマテリアルを細分化しました。 -* **SceneTexture** マテリアル式の出力マスク値を修正しました。 -* ユーザーが別個の透過処理と _BLEND_MODULATE_ を合わせて使用しようとするとマテリアル エディタに警告メッセージが表示されるようになりました。 -* メッシュに変更を加えたらスタティックメッシュ エディタが物理ジオメトリをリビルドするようにし、ビューから消えないようにします。 -* トライアングルがないスタティックメッシュのセクションは、マテリアルのスロットを使い切らないようになりました。既存のコンテンツはロード時に修正されます。 -* HQ ライトマップと距離フィールド シャドウの iOS からのストリッピングを追加しました。 -* ES2 ブルームがより幅広くなりました。 -* マテリアル エディタ内でインタラクションしながらマテリアル インスタンスのプロパティ変更のブロードキャストを遅らせます。これは、編集をはるかにスムーズに行うためのものです。 -* マテリアルのシェーダのコンパイルは、ディスクに保存するためのサムネイルの生成前に完了するようになりました。 +#### レンダリング +* When not running with the editor, all scene render targets will be reallocated on resizing the window.This allows memory to be recovered when changing to a lower resolution +* ParticleParameter distributions are now not selectable on GPU emitters for various properties.Previously they would have been selectable but would not have worked. +* Random and Random_Blend interpolation methods are now not selectable for GPU emitters.Previously they would have been selectable but would not have worked. +* Particle emitter's editor LOD value is set to 0 on load. +* **Texture Streaming** - Simpler logic to decide how textures should be streamed (or not), fixes for dynamic textures (including Blueprints) +* StaticSwitchParameter material expressions now emit an error if either inputs are not connected. +* Tessellated materials draw to the velocity buffer. +* Corrected the output mask value for **SceneTexture** material expression. +* A warning message is now displayed in the Material Editor when the user attempts to use _BLEND_MODULATE_ with separate translucency +* Ensure that the static mesh editor rebuilds the physics geometry after any change to the mesh so it doesn't disappear from view +* Static mesh sections with no triangles no longer use up a material slot.Existing content will be fixed on load +* Added stripping of HQ lightmaps and distance field shadows from iOS +* Wider ES2 bloom +* Defer broadcasting material instance property changes while still interacting with them in the material editor, so that editing is much smoother +* Compilation of the shaders for a material are now completed before generating a thumbnail to save to disk -####アニメーションとペルソナ +####Animation and Persona * **PHAT EDITOR** - * PhAT: BodySetup からコリジョン設定を取り除きました。しかし、コリジョン反応の有効/無効は追加しました - * 他のすべての設定は OwnerComponent から派生します。 - * 被破壊物に対してデフォルトのポーンのコリジョンを有効にしました。 - * PhAT のツールチップをユーザーにとってわかりやすいものにしました。 -* スケルタルメッシュの頂点はインポート中に再アレンジされ、よりキャッシュ フレンドリーになりました。 -*スケルトンにソケットを追加、スケルトンからソケットを削除するための元に戻す/リドゥ (取り消しの取り消し) を修正しました。 -* 軸のインジケータをペルソナ ビューポートに追加しました。 + * Removed collision settings from PhAT:BodySetup, but added collision response Enabled/Disabled + * All other settings are derived from OwnerComponent + * Enabled default pawn collision against destructible + * Modified PhAT tooltip to be less confusing to the user. +* Skeletal mesh vertices are rearranged during import to be more cache friendly. +* Undo/Redo fixed for adding/deleting sockets from a skeleton. +* Added the axis indicator to the Persona viewport. #### サウンド -* 子のサウンドクラスからサウンドクラス エディタを開くと、親を含む SoundClass 階層全体が表示されます。 +* Entire SoundClass hierarchy, including parents, will be displayed when opening the Sound Class editor via a child SoundClass. ####オンライン -* オンライン プラットフォームの安定性と堅牢性の改善努力は進行中です。 - * その他 - * キー値のペアに対して bool の FVariantData をサポートします。 - * Identity インターフェースに CreateUniquePlayerId 関数を追加しました。 - * UpdateSession API はデフォルトでバックエンドで更新します。 - * セッション設定をビットフィールドの代わりに bool にしました。 - * クラウド - * クラウドのヘッダーに追加の更新 - * 列挙リストにないローカルのキャッシュ ファイルを削除しました。 - * ユーザー ファイルの書き込み/削除後に列挙リストを更新します。 +* Ongoing efforts to improve the stability and robustness of the online platforms + * Misc + * Support for bool FVariantData for key value pairs + * Added CreateUniquePlayerId function to Identity interface + * UpdateSession API now defaults to updating backend + * Made session settings bool instead of bitfield + * Cloud + * Additional updates to cloud headers + * Delete local cache files not in the enumerated list + * Update enumerated list after write/delete user file ####コア -* 外部 CPU プロファイラ サポート (AQTime, VTune, VSPerf) を再記述しました - * コマンドライン オプションを使用して特定のプロファイラ、`-AQtime`, `-VSPerf` and `-VTune` を選択します。 - * 最初の有効なプロファイルはデフォルトで使用されます (通常は VSPerf)。プロファイラは検索パスでその DLL が見つかる場合のみ利用できます。 -* 多くのスレート コードが中に入っている大きな関数がある場合、BEGIN_/END_SLATE_FUNCTION_BUILD_OPTIMIZATION マクロ ペアにラップし、こうした関数を含むモジュールのデベロッパのビルド時間を改善することができます。 -* 最初のページで back がクリックされると、SWizard がデリゲートを供給するオプションを追加しました。 -* Base ini ファイルを調整し、保存した ini ファイルに追加データを保存するのを回避する支援をするようにしました。 -* config システムが直接 UObject 参照をロードできるため、TemplateMapInfo 構造体を単純化しました。 -* アセット タイプ クラスにいくつかのコメントを移動し、ツールチップ メタデータに表示されるようにしました。これは、**New Asset** メニューがクラスの説明を描画する場所です。 -* ビルド マシンは EditorGameAgnostic ini からロードしたり、EditorGameAgnostic ini に保存したりしなくなりました。また、ビルド マシンはプロジェクト ファイル自動ロードしなくなりました。 -* c++ クラス ウィザードでクラスの妥当性のロジックを更新し、ゲーム モジュールでクラスの拡張を可能にします。 -* パス ピッカーは Classes フォルダを表示しなくなりました。また、選択は常に単独であり、従ってパスの選択解除は認められていません。 -* visual studio を開くオプションをメインフレームのファイル メニューに追加しました。 -* デバッグビルドでハードウェアの調査は行われなくなりました。 -*ビデオ設定をベースとする合成ベンチマーク (ハードウェア調査の一環としてコンソール コマンド `SynthBenchmark`) を開始しました。 -* 詳細モードのシーン コンポーネントを追加し、r.DetailMode でもライトがカリングされるようにしました。 -* デカールのステート変更を最適化しました。 -* JsonReader はホワイトスペースの前後を無視するようになりました。 -* "Error" を含むローカリゼーション文字列がある場合、国際化で収集するログ出力を調整して、自動ビルドが失敗するのを防ぐ機能を追加しました。 -* 国際化マニフェストとアーカイブ ファイルをユニコードのエンコードを使用して強制的に書き込むようにしました。 -* エンジンとエディタのローカリゼーション ファイルを生成するための config ファイルを追加しました。 -* ChunkID info を `FAssetData`, `FPackageFileSummary`, および `FBackgroundAssetData` にインストールするストリーミングを追加しました。 - * 将来のビルドでは、これはストリーミングする `.pak` ファイルの作成と個々のアセットのインストール状態を判断するためのパッケージャによって使用されます。 +* Rewrote external CPU profiler support (AQTime, VTune, VSPerf) + * Use command-line options to select a specific profiler: `-AQtime`, `-VSPerf` and `-VTune` + * The first valid profiler is used by default (usually VSPerf.)Profilers are available only if their DLL is found in a search path. +* If you have any large functions with a lot of Slate code in them, they can now be wrapped in a BEGIN_/END_SLATE_FUNCTION_BUILD_OPTIMIZATION macro pair to improve Developer build times for the modules containing these functions. +* Added option to SWizard to supply a delegate for when back is clicked on the first page. +* Adjusted Base ini files to help avoid saving additional data to saved ini files. +* Simplified TemplateMapInfo struct since the config system can directly load a UObject reference. +* Moved some comments around in asset type classes so that they will appear in tooltip metadata.This is where the **New Asset** menu draws its descriptions for classes. +* Build machines no longer load from or save to the EditorGameAgnostic ini.Also, build machines no longer attempt to auto-load project files. +* Updated class validity logic in the c++ class wizard to allow for the extending of classes in the game module. +* Path pickers no longer show a Classes folder.Also, selection is always single, thus deselecting a path is not allowed. +* An option to open visual studio was added to the File menu in the mainframe. +* Hardware survey no longer done in debug builds +* Started synthetic benchmark (console command `SynthBenchmark`, part of Hardware survey) to base video settings on it +* Added detail mode SceneComponent so lights can be culled by r.DetailMode as well +* Optimized decal state changes +* JsonReader now ignores trailing and preceding whitespace +* Added functionality that will adjust some of the internationalization gather log output to prevent automated builds from failing when localization strings containing "Error" are encountered +* Forcing internationalization manifest and archive files to be written out using unicode encoding +* Added config files for generating Engine and Editor localization files +* Added streaming install ChunkID info to `FAssetData`, `FPackageFileSummary`, and `FBackgroundAssetData`. + * In future builds this will be used by the packager for creating streaming install `.pak` files and for determining the install state of individual assets. ####プラットフォーム -* エンジンとエディタを Mac へ移植中です。 -* GScreenWidth/Height を削除し、デスクトップではないプラットフォームのデフォルトの解像度を 0x0 に設定し、現在の解像度をデバイスに照会するようにします。 +* Porting the engine and the editor to Mac +* Removed GScreenWidth/Height, and set the default resolution for non-desktop platforms to 0x0, to make it query the device for current resolution diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/August/ReleaseNotesAugust2013.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/August/ReleaseNotesAugust2013.KOR.udn index 3d7d6e73b9a7..00da782ecfc1 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/August/ReleaseNotesAugust2013.KOR.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/August/ReleaseNotesAugust2013.KOR.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3367470 Title: August 2013 Release Notes Crumbs:%ROOT%, Support/Builds Description: Availability:Licensee -Template:ReleaseNotes.html +Parent:Support/Builds +Order:-6 [TOC(start:2 end:2)] diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/Dec/ReleaseNotesDecember2013.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/Dec/ReleaseNotesDecember2013.JPN.udn index aab3d6f7f31e..91fbd746da0c 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/Dec/ReleaseNotesDecember2013.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/Dec/ReleaseNotesDecember2013.JPN.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:2615097 +INTSourceChangelist:3367470 Title:2013年12月リリースノート Crumbs:%ROOT%, Support/Builds Description: Availability:Licensee -Template:ReleaseNotes.html +Parent:Support/Builds +Order:-3 [TOC(start:2 end:2)] @@ -32,7 +33,7 @@ QA_APPROVED_UE4_BUILD_MINIMUM * 現時点のエンジン開発ロードマップ: [UE4 Roadmaps](https://udn.unrealengine.com/questions/topics/roadmap.html) * 修正されたバグ: [UE4 Fixed Bugs December 2013](UE4_Fixed_2013_December.xlsx) - * 既知の問題: [UE4 Known Issues December 2013](UE4_Bugs_2013_December.xlsx) + * 周知のバグ: [UE4 Known Issues December 2013](UE4_Bugs_2013_December.xlsx) ## 主要な新機能 @@ -73,13 +74,13 @@ QA_APPROVED_UE4_BUILD_MINIMUM ![](ContentBrowserFolders01.png) * フォルダ表示を有効にするというこは [Show Only Assets In Selected Folders] を有効にすることを意味します。ツリービューでルートを選択すると全てのコンテンツが表示されなくなることにご注意ください。 - * フォルダは以下のように表示されます。フォルダはコンテンツ ブラウザの全ビューモードで表示されます。 + * フォルダは以下のように表示されます。They are displayed in all view modes of the Content Browser: ![](ContentBrowserFolders02.png) * フォルダは、Windows Explorer とほぼ同じ挙動をします。ドラッグ&ドロップ、名前の変更 (F2) 、削除オプションは全て機能します。 * [Asset View] へ新規フォルダを作成することもできます。 - * 新しく [Up] ボタンが追加されました (ナビゲーショントレールの左)。このボタンをクリックするとディレクトリへ移動します。 [Alt+Up] キー操作でも移動可能です。 + * 新しく [Up] ボタンが追加されました ('breadcrumb trail' の左)。このボタンをクリックするとディレクトリへ移動します。 [Alt+Up] キー操作でも移動可能です。 ![](ContentBrowserFolders03.png) @@ -132,18 +133,18 @@ QA_APPROVED_UE4_BUILD_MINIMUM * **インターフェースからの移行** * ブループリントは、以前は関数の呼び出しや別のブループリントの変数へアクセスができなかったことへの対処法として、ブループリント インターフェースを使用していました。もうこの回避策を利用する必要はありません。今後はインターフェースを使用せずに、ブループリントの通信を直接利用した移行を選択されるでしょう。ユーザーのブループリントからインターフェースを削除する新しい機能が追加されました。関数はそのまま使用できます。 - * [Find in Blueprints](ブループリント エディタでは [Ctrl + F] キー)で、移行を簡単にするメッセージ関数の全ての用途を検索することができます。 + * [Find in Blueprints] (ブループリント エディタでは [Ctrl + F] キー)で、移行を簡単にするメッセージ関数の全ての用途を検索することができます。 -####Animation +####アニメーション * **アニメーション リターゲット** * このたび、アニメーション リターゲットのサポートが追加されました! * アニメーション リターゲットとは? - * アニメーション リターゲットとは、特定キャラクター用に作成したアニメーションを使用して、比率の異なるキャラクターでこれを再生する機能です。重要な点は、正しく機能させるために、共通のスケルトンを使用しなくてはいけないことです (同一ボーン名と階層)。パインド ポーズのみが異なります。 + * アニメーション リターゲットとは、特定キャラクター用に作成したアニメーションを使用して、比率の異なるキャラクターでこれを再生する機能です。 重要な点は、正しく機能させるために、共通のスケルトンを使用しなくてはいけないことです (同一ボーン名と階層)。パインド ポーズのみが異なります。 * ペルソナ (Persona) の [Skeleton Tree] ウィンドウに設定が可能なボーン移動のリターゲットは 3 種類あります。 * **スケルトン:**ボーンの移動はターゲット スケルトンのバインド ポーズに由来します。 * **アニメーション**:ボーンの移動は、不変のアニメーション データに由来します。 - * **アニメーションスケーリング**:ボーンの移動はアニメーション データに由来しますが、スケルトンの比率でスケーリングされます。これはターゲット スケルトンのボーンの長さ (アニメーションが再生中のスケルトン) とソース スケルトン (アニメーションが作成されたスケルトン) 間の比率です。 + * **アニメーションスケーリング**:ボーンの移動はアニメーション データに由来しますが、スケルトンの比率でスケーリングされます。これはターゲット スケルトンのボーンの長さ (アニメーションが再生中のスケルトン) とソース スケルトン (アニメーションが作成されたスケルトン) との間の比率です。 ![](AnimationRetargeting01.png) @@ -159,7 +160,7 @@ QA_APPROVED_UE4_BUILD_MINIMUM ## 新規追加 -#### Editor and Tools +#### エディタとツール * DragDropEvent.GetOperationAs() で、ドラッグ&ドロップ操作タイプを簡単にチェックする方法が追加されました。 * ツール ヒントのスコープおよびカスタム設定処理を有効にする OnVisualizeTooltip() イベントが追加されました。 * ブランチ間の頻繁な切り替えが発生した際に、レベルエディタへプロジェクト名を明示的に付与するための「ini」オプションがエディタのユーザー設定に追加されました。 @@ -168,19 +169,19 @@ QA_APPROVED_UE4_BUILD_MINIMUM * スナップ時に不均等なスケーリングを維持するオプションが追加されました。 * クックパスは、ゲームごとのエディタ環境設定に置かれました。 * コンテンツ ブラウザにフォルダが追加されました。 -* [Slate] ウィンドウに細い境界線が追加されました。 +* [Slate] ウィンドウの隣に細いウィンドウ境界を追加しました。 * シーン内のアクタをピックするために、インタラクティブなアクタに「スポイト」ピッカーが追加されました。 * ノード上の既存グラフ アイコンをクリックすると、グラフビューに単独に表示されます。 * 個々のキーを既存トラックへコピー / 切り取り、貼り付けする際に選択キーが考慮されます。 * フォルダの色を設定するための新規のオプションがコンテンツブラウザにあります。 -* ContentBrowserリストとカラムビューは色を表示するようになりました。 +* ContentBrowser リストとカラムビューは色を表示するようになりました。 * クラッシュ後のエディタの再起動時に、自動保存からの復元オプションが表示されます。 * マテリアル エディタのスレート グラフ バージョンの使用が可能になりました。 * コマンドラインに「-oldme」と入力して、旧エディタへアクセスするオプションがデフォルトで有効になっています。 * 表現式とコメントの位置が一時的に入れ替わります。 * Static Bool 表現式はプレビュー ウィンドウを表示しなくなりました。 * Material Input ノードを移動できるようになりました。 - * [ctrl+drag] キーでマテリアルの接続を移動できるようになりました。 + * [ctrl+drag] キーでマテリアルの接続を移動できるようになりました。 * [Enter] キーを押すと検索結果を循環します。 * マテリアル表現式に代替の検索結果が追加されました。「lerp」と入力して線形補間の検索、[One Minus] には「1-x」、 [Square Root] は「sqrt」と入力します。 * ノードのタイトルバーから、パラメータ名のブループリント スタイルの編集を有効にします。 @@ -188,8 +189,8 @@ QA_APPROVED_UE4_BUILD_MINIMUM * SCC Provider プラグインをオーバーライドするために、コマンドラインへ「-SCCProvider=ProviderPluginName」を追加できるようになりました。 * 高度なグリッドスナップ設定が、 [EditorSettings->General->Preferences->Snap] へ追加されました。 * **UnrealDocTool** - * ページのパブリッシュを回避するために、「NoPublish」オプションが追加されました。 - * 特定のUDNドキュメントパスに対し、正確で相対的なターゲットパスへレンダリングさせるために 「`[RELATIVE:path]`」タグが追加されました。 + * Added NoPublish availability option to keep page from publishing. + * Added `[RELATIVE:path]` tag which is rendered into proper relative target path for given UDN document path. #### Blueprints @@ -200,32 +201,32 @@ QA_APPROVED_UE4_BUILD_MINIMUM * Enumeration (列挙型) をName (名前) またはString (文字列) へ変換することができます。 * Get number of entries in ノードが追加されました。 * Behavior Tree ブループリント ノードが音を立てるように、APawn へ BlueprintCallable PawnMakeNoise 関数が追加されました。 -* ブループリントで呼び出しが可能な関数を SceneComponent へ追加しました。Get Num Children Components()、 Get Child Component (インデックス)、 Get Children Components ([Include All Descendants] チェックボックスと一緒に)、そして Get Parent Components が追加されました。 +* ブループリントで呼び出しが可能な関数を SceneComponent へ追加しました。Get Num Children Components()、 Get Child Component (インデックス)、 Get Children Components ([Include All Descendants] チェックボックスと一緒に)、そして Get Parent Components が追加されました。 * ブループリント タブにカテゴリが追加されました。 * BlueprintNativeEvents にサポートが追加されました。コールチェーンにネイティブ実装される点を除いて、BlueprintImplementableEvents と似ています。インターフェースで使用すると、BPNE の機能は限定されることに留意してください。これについては今後のリリースノートで言及していきます。 #### ゲームプレイとフレームワーク -* 結合が可能な Begin/End Cusor Over Events を HUD HitBox で利用できるようになりました。 +* 結合が可能な Begin/End Cusor Over Events を HUD HitBox で利用できるようになりました。 * ブループリントの Input イベントを、イベントノードのプロパティに指定できるようになりました。親クラスのイベントのバインディングをオーバーライドすべきかどうかを指定します。 * ブループリントの変数、関数、マクロは、参照を格納しているクラスが読み込まれていない間に名前変更がされた場合、参照メンバーの検索に使用される内部 GUID に格納出来るようになりました。GUID ベースのシステムを従来のコンテンツに作用させるには、アセットを再保存しなくてはいけません。 * マルチプレイヤー対応 PIE (Play in Editor):1 つのプロセスに複数のワールド * UE4 の 1 つのインスタンス下でマルチプレイヤープレイを行うことができます (接続のために別のインスタンスを起動する代わりに)。 * [Play In Settings] の [Multiplayer] オプションで「Single Process」を選択して有効にします。 * Visual Studio 2013 (VC12)に対する仮サポートを追加しました。 - * WindowsCompiler.VisualStudio2013に WindowsPlatform.Compilerを設定しました(実験的です! - * VS2013のネイティブプロジェクトを取得するために、「"-2013"」を「GenerateProjectFiles.bat」へ渡します(オプション)。 + * WindowsCompiler.VisualStudio2013に WindowsPlatform.Compilerを設定しました(実験的です!) + * VS2013のネイティブプロジェクトを取得するために、「"-2013"」を「GenerateProjectFiles.bat」へ渡します(オプション) * Visual Studio 2013のコンパイル時は、Windows SDK 8.1 を使用します。 * サードパーティによるビルドスクリプトはVS2013ライブラリのパスへ更新されます。 * 今でもWindows XPをターゲットにすることができますが、これは実験的な試みです(WindowsPlatform.SupportWindowsXP=true)。 - * 重要:現時点におけるUE4はVisual Studio 2012のみをサポートしています。コンパイルするにはVisual Studio 2012をインストールしなくてはいけません。2013バージョンは初期試験のためのテスト予備段階です。 - * 重要:サードパーティライブラリはまだVS2013へコンパイルされていないのでリンクできません。 -* UStructs から / へ Json オブジェクトを変換するユーティリティ、JsonUtilities モジュールが追加されました。 -* BodySetup とインスタンスあたりの基準両方で「歩行可能」と判断されるフロア法線をオーバーライド出来る機能が追加されました。有効な設定は以下の通りです。 + * 重要:現時点におけるUE4はVisual Studio 2012のみをサポートしています。コンパイルするにはVisual Studio 2012をインストールしなくてはいけません。2013バージョンは初期試験のためのテスト予備段階です。 + * 重要:サードパーティライブラリはまだVS2013へコンパイルされていないのでリンクできません。 +* UStructs から / へ Json オブジェクトを変換するユーティリティ、JsonUtilities モジュールが追加されました。 +* BodySetup とインスタンスあたりの基準両方で「歩行可能」と判断されるフロア法線をオーバーライド出来る機能が追加されました。Allowable settings are: * Default (デフォルト) (動作に変化はありません) * Increase walkability (歩行範囲の拡大) (通常よりも急斜面な法線を有効にします) * Decrease walkability (歩行範囲の縮小) (通常よりも緩やかな法線を無効にします) - * 注記:現時点の AI navmesh はこれらの設定を無視します。 + * 注記:現時点の AI navmesh はこれらの設定を無視します。 * カスタム AI ナビゲーションリンクは、次のパスに作用します (ドア、はしごなど):USmartNavLinkComponent. * ANavLinkProxy のカスタム AI ナビゲーション リンクにブループリント サポートを追加しました。 * 詳細なパス ファインディング デバッグを ANavigationTestingActor へ追加しました。 @@ -235,7 +236,7 @@ QA_APPROVED_UE4_BUILD_MINIMUM * ユーザーのシステムでリターゲットが使用されると、正確なリターゲットを処理するために、一部のアニメーションは正しい基本ポーズが必要となります (アニメートされたメッシュに基づきます)。 -#### Rendering +#### レンダリング * HZB オクルージョン カリングを追加しました。新規のシステム スケーリングは、以前の HW オクルージョン クエリーに基づいたシステムよりも高いオブジェクト数に適しています。現在はデフォルト設定で無効になっています。「r.HZBOcclusion 1」を有効に設定します。 * 拡張性のために GetRenderingDetailMode() 関数をブループリントに追加しました。 * コンポジットおよびポストプロセス グラフの「r.CompositionGraphDebug」へデバッグ エクスポートを追加しました (yWorks を使用)。グラフはファイルをスクリーンショット フォルダへエクスポートします。 @@ -243,7 +244,7 @@ QA_APPROVED_UE4_BUILD_MINIMUM * 困難なライティング状況でノイズとノイズ漏れを削減します。 * GI ソルバのアーティファクトを示すマップのソルバ品質を強化するために使用可能な、 IndirectLightingQuality ワールド設定を新規に追加しました。 * **カスタム仕様の UV** - * 新しいマテリアル プロパティ、NumCustomizedUVs は、頂点シェーダーで実行されるマテリアル入力を公開します。 + * 新しいマテリアル プロパティ、NumCustomizedUVs は、頂点シェーダーで実行されるマテリアル入力を公開します。 * Customized UV 入力は、演算を頂点シェーダーへ移動することによりマテリアルの最適化に使用します。 * 各拡張グループの CVar は、「ini」ファイルに格納されるようになりました (BaseScalability.ini)。 * DOF (Depth of field: 被写界深度) と別の透過処理を適用前にマテリアルを描画するために、ポストプロセ スマテリアルの切り込み点として BL_BeforeTranslucency を追加しました。 @@ -254,7 +255,7 @@ QA_APPROVED_UE4_BUILD_MINIMUM * [Rendering Detail] モードをパーティクルごとに指定できるようになりました。 * Axis Lock モジュールが GPU パーティクル エミッタでサポートされるようになりました。 * SetEmitterEnable 関数を使用して、 パーティクル サブエミッタをブループリントから有効または無効にできるようになりました。 -* r.UpsampleQuality コンソール変数を追加しました。 +* r.UpsampleQuality コンソール変数を追加しました。 * より小さなスクリーンからアップスケーリングする時の 4 つの品質値の範囲です。 * **Automatic Lightmass Importance ボリューム** * LightmassImportanceVolumes が存在しない場合、ユーザーのシーンと結合する合成ボリュームが使用されます。 @@ -264,15 +265,15 @@ QA_APPROVED_UE4_BUILD_MINIMUM * MinimumImportanceVolumeExtentWithoutWarning の extent 値を 50m から 100m へ増加しました。 -#### Animation +#### アニメーション * [Ctrl-C/Ctrl-V] キー、またはスケルトン ツリーのコンテクスト メニュー アイテムから、ソケット用のコピーおよび貼り付け機能をペルソナに追加しました。複数のソケットを一度にコピーして、ボーンへ貼り付けることができます。 * フロアを上下に移動させる [Floor Height Offset] ボックスがペルソナの [Viewport] メニューに追加されました。メッシュごとに保存します。 -#### Core +#### コア * TAssetPtr -> UObject から負荷時に自動変換が追加されました。 * TMap と TArray には設置サポートに制限があるため、コピーせずにコンテナへ直接エレメントを構築することができます。 - * 単一引数コンストラクタと一緒にクラスを処理する際は、コピーのコンストラクタ呼出しを回避するために、「.Add」の代わりに「Map.Emplace」と「Array.Emplace」を使用します。 + * 単一引数コンストラクタと一緒にクラスを処理する際は、コピーのコンストラクタ呼出しを回避するために、「.Add」の代わりに「Map.Emplace」と「Array.Emplace」を使用します。 * TMap 値は演算子を利用して読み出すことができます[]。 * ValueType& Val = Map[Key]; * 「std::map」とは異なり、これは const コンテナで使用が可能で、キーが存在しない場合は新しいエレメントを挿入しません。その代りアサートします。 @@ -281,7 +282,7 @@ QA_APPROVED_UE4_BUILD_MINIMUM * IndexOfByPredicate: 述語でエレメントの見出しを検索します。 * ContainsByPredicate: 述語と一致するエレメントがあるかテストします。 * デバッガビジュアライザは「GenerateProjectFiles.bat」で自動的にインストールされます。 -* UFUNCTION 指定子がデリゲートの UFunction へ渡されるように UDELEGATE が追加されました。 +* UFUNCTION 指定子がデリゲートの UFunction へ渡されるように UDELEGATE が追加されました。 * UDELEGATE がない古いタイプもまだサポートしています。 * 例: * UDELEGATE() @@ -291,27 +292,27 @@ QA_APPROVED_UE4_BUILD_MINIMUM * FVector::Dot2D の名前が変更されました。 * この関数の名前は、関数の動作を適切に表現していませんでした。 * FVector::CosineAngle2D を代わりに使用します。 -* 空の TArray へインデックスを付けると常にエラーとなります。 +* 空の TArray へインデックスを付けると常にエラーとなります * &Array[0] の回避策が原因で一部のエラーは報告されていません。 * この種の使用法は、Array.GetTypedArray() と置き換えなくてはいけません。 -#### Platforms +#### プラットフォーム * ライブラリのバッチの再コンパイルを単純化するために BuildThirdPartyLibs UAT スクリプトが追加されました (全てのライブラリが有効にされたわけではありません。バッチファイルの設定方はスクリプトを参照してください)。 * 「.uplugin」ファイルへホワイトリストとブラックリストを追加しました (WindowsMoviePlayer.upluginから例を確認してください)。 * **Android** * メインブランチの初期のAndroidサポートは、DXTと PVRTCデバイスをサポートします。 -* アンリアル プロジェクト ファイルに Mac OS X Services インテグレーションを追加しました。 「.uproject」ファイルの選択時に [Service Menu]、もしくは Finder のコンテクスト メニューからゲームまたは生成した Xcode プロジェクト ファイルを起動できるようになりました。 +* アンリアル プロジェクト ファイルに Mac OS X Services インテグレーションを追加しました。 「.uproject」ファイルの選択時に [Service Menu]、もしくは Finder のコンテクスト メニューからゲームまたは生成した Xcode プロジェクト ファイルを起動できるようになりました。 * UE4 の共有コンテナと文字列タイプに LLDB データフォーマッターを実装しました。ユーザーの「~/.lldbinit」へ「command script import UE4/Engine/Extras/LLDBDataFormatters/UE4DataFormatters.py」を追加します。 #### Networking -* **ネットワークアクタリスト** - * 単独のネットワークアクタリストで、向上したパフォーマンスのネットワークに関連したアクタを追跡するようになりました。 +* **ネットワーク アクタ リスト** + * 単独のネットワークアクタリストで、向上したパフォーマンスのネットワークに関連したアクタを追跡するようになりました。. * **レプリケーションの最適化** * パフォーマンスとセキュリティを考慮して、下層のプロパティ レプリケーション ロジックを徹底的に書き直しました。 * **接続全域に渡るワークシェアー** - * 接続全域に渡って共有するレプリケーション ロジックの能力 -* Lifetime プロパティ + * 接続全域に渡って共有するレプリケーション ロジックの能力 +* **Lifetime プロパティ ** * パフォーマンス向上のためにプロパティを登録する新しい方法。 * **ライフタイム プロパティの条件** * ライフタイムにレプリケートされたプロパティに二次的な条件を適用する能力。 @@ -319,113 +320,113 @@ QA_APPROVED_UE4_BUILD_MINIMUM * クライアントとサーバーの非同期状況を診断するためにプロパティ チェックサムをトグルする能力。 -#### Online -* 別のサブシステムが利用不可、または意図的にオフにされている時は、OnlineSubsystemNULL がフォールバックです。 +#### オンライン +* 別のサブシステムが利用不可、または意図的にオフにされている時は、OnlineSubsystemNULL がフォールバックです。 * ゲームコードはオンライン関数を継続的に呼出し、実際のオンラインコミュニケーションをせずにコールバックを取得します。 -* オンライン サブシステムに新規の OnlineMessage インターフェースを追加しました。 - * ユーザーのインボックスに列挙型のメッセージを有効にします。 +* オンライン サブシステムに新規の OnlineMessage インターフェースを追加しました。 + * ユーザーのインボックスに列挙型のメッセージを有効にします * ID でメッセージをダウンロードすることができます。 * あるユーザーから別のユーザーへメッセージを送信することができます。 * 個々のメッセージは削除できます。 - * 順応性のあるペイロードを有効にするために、メッセージペイロードはバリアント データ タイプへ文字列のキー値ペアとして符号化されています。 + * 順応性のあるペイロードを有効にするために、メッセージペイロードはバリアント データ タイプへ文字列のキー値ペアとして符号化されています * 現時点では Mcp OSS のみに実装しています。 -* オンライン サブシステムの OnlineUser インターフェースのリファクタリングです。 +* オンライン サブシステムの OnlineUser インターフェースのリファクタリングです。 * Mcp OSS 実装を追加しました。 * オンライ ンサブシステムの OnlineFriends インターフェースをリファクタリングしました。 * 従来の OSS 実装を更新しました。Steam PC、 PS4、 Facebook iOS/PC、 Gamecenter iOS、 Amazon PC * Steam 実装は各読み込み時にフレンズリストをキャッシュするようになりました。 * 新規の Mcp OSS 実装を追加しました。 * 名前が付けられたフレンズリスト上で操作が可能です。 - * デフォルト設定のフレンズリストに招待を送信するために、ユーザー ID のリストを受け取る exec コマンドを追加しました。 -* Engine モジュールの依存を削除するために OnlineSubsystem をリファクタリングしました。 + * デフォルト設定のフレンズリストに招待を送信するために、ユーザー ID のリストを受け取る exec コマンド "SENDINVITES" を追加しました。 +* Engine モジュールの依存を削除するために OnlineSubsystem をリファクタリングしました。 * エンジン依存は全て OnlineSubsystemUtils モジュールにあります。 * ソースファイルからMcpコンフィグをリファクタリングしました。 -## Upgrade Notes +##アップグレード ノート -#### Editor and Tools -* [World Settings] に独自のタブができました ([Details] タブとは別です)。 -* **スレート** - * スレートのサウンドは、 FName のよりはむしろ FSlateSound を使用するようになりました。スレートにサウンド名を格納するための Fname の使用は非推奨となりました。 - * FSlateSound::FromName_DEPRECATED を利用して一時的にコードを修正することができます。 - * 正規の修正は、スレートで再生するサウンドを保持するために Slate Widget Style を使用します。 - * SHyperlink のテンプレートが廃止されました。ユーザー データを渡すにはデリゲート ペイロードを使用します。 -* const らしさを強調するためにスレートの TAttributes の機能が向上しました。スレート TAttribute の内部に決して副作用をもたらさないでください。 -* SPropertyEditorNumeric、 SSpinBox、 SNumericEntryBox が一般となり、任意の数値型でパラメータ化することができます。 -* [Viewport Transform] ツールバーのアイコンと色を変更しました。 -* Texture2D から Slate Brush Asset を作成するために、コンテンツ ブラウザにコンテンツ メニュー アクションを追加しました。 -* プロパティ エディタに WYSIWYG SlateBrush プレビューが追加されました。 -* マウスの中クリックでコンテンツ ブラウザ フィルタの削除が可能になりました。 +#### エディタとツール +* The World Settings now have their own tab (separate from Details tab). +* **Slate** + * Sounds in Slate now use FSlateSound rather than FName; the use of FName to store sound names in Slate is deprecated. + * You can temporarily fix code using FSlateSound::FromName_DEPRECATED. + * The correct fix is to use a Slate Widget Style to hold any sounds you want Slate to play. + * SHyperlink is no longer templated.Simply use delegate payloads for passing user data. +* Slate TAttributes now do a better job of enforcing const-ness.It is never OK to have a side-effect inside a Slate TAttribute. +* SPropertyEditorNumeric, SSpinBox, SNumericEntryBox are generic now and can be parameterized by any numeric type. +* Changed the icons and colors of the Viewport Transform toolbar. +* Added a Content Browser content menu action to create a Slate Brush Asset from a Texture2D. +* Added WYSIWYG SlateBrush preview to properties editor. +* Content browser filters can now be removed by MMB-clicking on them. * **UnrealDocTool** - * 自動生成されるヘッダIDとブックマークの名前が小文字になって、「'_'」に代わって「'(' and ')'」を使用します。 -* **プラグイン** - * プロジェクト プラグインのリストは、「Game.ini」ファイルから「Engine.ini」ファイルへ移動しました。 + * Automatically generated header IDs and bookmark names are now lower case and with '(' and ')' replaced by '_'. +* **Plugins** + * The list of project plug-ins was moved from Game.ini to Engine.ini #### Blueprints -* ブループリント マクロが、重複した変数名をチェックするようになりました。 -* 初めにコメントを非選択にせずに、広範囲にわたるブループリント ノードをコメント ボックスにアタッチできるようになりました。 -* [My Blueprint] から [Graph] へマクロをドラッグできるようになりました。 -* 新しいエレメントを追加する前に [MyBlueprint] 検索フィルタをリセットするコールが追加されました。新しいエレメントは一度作成されると表示されます。 -* Vector2D ブループリント グラフ アクションは、標準のベクタークラスから分離して Vector2D カテゴリへ移動しました。 -* カラーピッカーのアルファ セクションがブループリント グラフのカラーピン上で有効にされました。 -* セクション付近にコメントを作成する機能が、エディタのノード コンテクスト メニューに追加されました。 -* ソケットコンポーネント用の [Details] ビューは、正しくカテゴリを配置してブループリント エディタで常に表示されるように更新されました。 -* 変数をベースとしたノードに使用する変数を配置する機能が、ブループリント エディタのコンテキスト メニューに追加されました。 -* グラフの一般ノードカリングは、より正確性を増して、ノードの幅 / 高さを考慮するようになりました。 -* より大きく展開するためのクラスピッカー ダイアログが作成されて、デフォルトのクラス選択領域の折りたたみが可能になりました。 -* Blueprint 関数とイベントはより記述的な名前を使用し、フォーマット化されました。 -* タイトルが既に可視出来る場合、Blueprint ノードの名前を変更しても選択しているノードを中心に置きません。 +* Blueprint macros now check for duplicate variable names. +* Encompassed blueprint nodes now attach to a comment box without having to first deselect the comment. +* Macros can now be dragged from My Blueprint into a Graph. +* Added a call to reset the MyBlueprint search filter before adding any new element, so the new element is visible once created. +* The Vector2D blueprint graph actions were moved into the Vector2D category splitting it out from the standard vector class. +* The Alpha section of the color picker has been enabled on blueprint graph color pins. +* The ability to create a comment around selection has been added to the node context menu in the editors. +* The Details view for the socket component was updated so the category is placed correctly and is always visible in the blueprint editor. +* The ability to locate variable uses for any variable based node was added to the context menu in the blueprint editor. +* The graphs general node culling was changed to be more accurate and take account of node widths/heights. +* The class picker dialog has been made to expand to be larger and the default class selection area is now collapsable. +* Blueprint functions and events now use more descriptive/better formatted names. +* Blueprint node renaming now no longer centers the selected node if its title is already visible. #### ゲームプレイとフレームワーク -* USpringArmComponent の一部の挙動は、サブクラスでオーバーライドが簡単に出来るように複数の仮想メモリに分割されました。 -* フラッシュ時にファイル階層と比較しないために、 config の書き込みを有効にする新規のクラスフラグが追加されました。 -* DrawHUD 外部で使用した時の警告の代わりに、 HUD ドローコールから BlueprintProtected を削除しました。 -* FPostProcessSettings の多数のプロパティへ BlueprintType と BlueprintReadWrite が追加されました。 -* UPlayerInput::ExecBindings が DebugExecBindings へ名前変更されて、出荷ビルドからコンパイルされます。 -* UWorldFromContextGetter::GetWorldFromContextObject は、オブジェクトのクラスが渡された先が未対応、またはサポートしているオブジェクトが単に NULL の UWorld ポインタを返しているかを区別するために、 bool 型の参照変数を受け取ります。 -* AActor::CustomTimeDilation は全てのコンポーネントに渡される DeltaTime へ正しく適用されるようになりました。CustomTimeDilation を手動で適用しているコンポーネントは、これを 2 度適用するようになりました。 -* **UEngine 関数の変更** - * GEngine->GetNetMode() の代わりに AActor::GetNetMode() もしくは UWorld::GetNetMode() を使用します - * GEngine->GetNetDriver() の代わりに AActor::GetNetDriver() または UWorld::GetNetDriver() を使用します。 -* **他にも数多くの GEngine 関数が必須の UWorld を使用するようになりました。** +* Split out some behavior of USpringArmComponent into multiple virtuals to make it easier to override in subclasses. +* New class flag added to allow config writes to NOT compare against the file hierarchy when flushed. +* Removed BlueprintProtected from HUD draw calls, in exchange for a warning when they are used outside of DrawHUD. +* Added BlueprintType and BlueprintReadWrite to a number of properties on FPostProcessSettings. +* UPlayerInput::ExecBindings have been renamed DebugExecBindings and will be compiled out of shipping builds. +* UWorldFromContextGetter::GetWorldFromContextObject now takes a bool reference variable to distinguish between situations where the class of the Object passed in is unsupported and where the supported Object simply is returning a NULL UWorld pointer. +* AActor::CustomTimeDilation is now properly applied to the DeltaTime passed to all Components.Any Component which was manually applying the CustomTimeDilation will now have it applied twice. +* **Changes to UEngine functions** + * Use AActor::GetNetMode() or UWorld::GetNetMode() instead of GEngine->GetNetMode() + * Use AActor::GetNetDriver() or UWorld::GetNetDriver() instead of GEngine->GetNetDriver() +* **Many other GEngine functions now take a required UWorld** * GEngine->GetLocalPlayerIterator( GetWorld() ); * GEngine->GetGamePlayers( GetWorld() ); * GEngine->GetGamePlayers( GetWorld() ); * GEngine->GetGamePlayer( GetWorld(), PlayerIndex ); * GEngine->GetFirstGamePlayer( GetWorld() ) const; -* Pathfollowing のデフォルトの動作が改善されました。最も重要なことに、デフォルト設定の「許容半径」は、現在も有効で以前使用されていた「0.0」の代わりに、 Agent の半径を使用するようになりました。 +* Pathfollowing's default behavior improvements.Most importantly default "acceptance radius" is now Agent's radius instead of previously used 0. 0 is still a valid value. -#### Rendering -* ライティングは全マップで再ビルドする必要があります。 -* 減少した LOD の拡張制限がより実用的になりました (一部のデフォルトは更新が必要かもしれません)。 +#### レンダリング +* Lighting needs to be rebuilt for all maps. +* Lowered LOD scalability restrictions to be more useful. (some defaults might need an update). -#### Animation -* 別の位相 ValidateAnimNodePostCompile を anim graph ノードに追加しました。このノードは、ノード (最終クラスに関係するノードのみ) が最終 CDO に対して何かしらの正当性を確認する際に、コンパイルの最後に呼ばれます。 -* transition pose evaluator ノードを配置するオプション表示をメニューから外して、誤ったグラフにうっかり配置された場合、削除が出来るようになりました (必要に応じて自動生成されます)。 -* トグル可能な anim ピンにオブジェクト参照のサポートが追加されました。 +#### アニメーション +* Added another phase ValidateAnimNodePostCompile to anim graph nodes, which is called at the very end of compilation, in case nodes (only ones that contributed to the final class) want to validate something against the final CDO. +* Prevented transition pose evaluator nodes from showing up as a placeable option in the menu and allowed them to be deleted if they were inadvertently placed in the wrong graph (they're autocreated where necessary). +* Added support for object references on togglable anim pins. -#### Core -* ログ出力が UTC タグを使用するように変更されました。 - * ログ出力をパースする全てのツールは、この変更に注意してください。 - * 旧フォーマットは今もサポートされており、コマンドラインで「-logtimesincestart」を渡して使用します。 -* レプリケートしたパラメーターが変更しました。 - * 非 const 参照の TArrays は、結果のレプリケートが戻されていないことを示すために、 const 参照で渡されなくてはいけません。 - * FStrings は、値ではなく const 参照で渡されなくてはいけません。 -* UCLASS 宣言の「配置可能な」指定子は削除されました。 - * クラスはデフォルト設定で配置が可能になりました。 - * 派生クラスの配置を防ぐために、クラスへ「notplaceable」指定子を追加することができます。 - * 「abstract」のマークがついたクラスも配置不可ですが、その派生クラスの配置性には影響しません。 -* アーカイブ カスタム バージョンの明示的な登録が必要になりました。 - * 特定のクラスが Serialize 関数で Ar.CustomVer(Guid) を使用する場合、オブジェクトがカスタムバージョンに依存していることをアーカイブに伝達するために、 Ar.UsingCustomVersion(Guid) を最初に呼ばなくてはいけません。 - * Guid は、 FCustomVersionRegistration グローバル オブジェクトを通じて予め登録しなくてはいけません。 +#### コア +* Log output has changed to using UTC tags. + * Any tools which parses log output needs to be aware of this change. + * The old format is still supported by passing -logtimesincestart at the command line. +* Changes to replicated parameters. + * Non-const reference TArrays should be passed by const reference to indicate that the results are not replicated back. + * FStrings should be passed by const-reference, not value. +* 'placeable' specifier on UCLASS declarations has been removed. + * Classes are now placeable by default. + * A class can have the 'notplaceable' specifier added it to stop it and its descendants being placeable. + * A class marked as 'abstract' is also non-placeable, but this doesn't affect the placeability of its descendants. +* Explicit registration of archive custom versions is now needed. + * If a particular class wishes to use Ar.CustomVer(Guid) in its Serialize function, then it should make a Ar.UsingCustomVersion(Guid) call first to inform the archive that the object depends on that custom version. + * That Guid must have already been registered via an FCustomVersionRegistration global object. + For example: - 例えば: void MyObject::Serialize(FArchive& Ar) { @@ -437,356 +438,356 @@ QA_APPROVED_UE4_BUILD_MINIMUM } } -* CustomVer 利用前に Ar.UsingCustomVersion が呼ばれない場合、アサートが生じます。 -* Num の増加時に、 TArray::SetNum はデフォルト設定のコンストラクタを使用するようになりました。 - * このコールを継続して使用するには、Types はデフォルト設定のコンストラクタを持たなければいけません。 - * 旧出力ゼロ化の動作は、新規の SetNumZeroed 関数で実行することができます。 -* FCrc::MemCrc、 FCrc::StrCrc と FCrc::StrCrcCaps は非推奨となりました。 - * 可能であれば FCrc::MemCrc32 を使用します。CRC32 アルゴリズムで一般的に得られる結果となります。 - * FCrc::MemCrc_DEPRECATED と FCrc::StrCrc_DEPRECATED は、ユーザーが前の結果に依存している場合に使用します。 - * FCrc::StrCrc32 は、今でも文字列に char タイプの独立した CRC を与えるため、必ずしも期待通りの結果ではありませんが、新規の文字列テーブルを使用します。 - * FCrc::StrCrcCaps(*Str) は FCrc::StrCrc_DEPRECATED(*Str.ToUpper()) に置き換えることができます。 -* AVolume は抽象クラスで作成されています。 - * マップ内部の既存ボリューム インスタンスは、ロード時に確実に失敗します。 - * インスタンスのクラスを変更するために、エディタの Convert 機能を利用して、非抽象クラス (例えばBlockingVolume) に変換しなくてはいけません -* IncrediBuildの使用時は、XGEの64-ビットバージョンが利用可能であると予想されます(今も32ビットバージョンを使用しているユーザーはCL # 1892517を取り消してください) -* LTCG は、出荷と Windows ターゲット テストでデフォルトで有効になりました。 - * 無効にするには、ビルド コマンド ラインへ「-noLTCG」を渡すか、「BuildConfiguration.bAllowLTCG=false」を設定します。 -* UObject C++ ヘッダは、「Classes」サブ ディレクトリに必要なくなりました! - * Classes ディレクトリは必要なくなりましたが、上位互換性となります。 - * 「Classes」外部の UObject ヘッダが「*Classes.h」で生成されたグループ ヘッダに含まれることは決してありません。 - * このヘッダは常にユーザー自身で格納してください!(「*Classes.h」ファイルの非推奨化を進めています) - *「Classes」または「Public」フォルダの UObject ヘッダは、プライベートな UObject クラスに依存できません。 - * モジュールの「*.generated.inl」ファイルを格納する前に、手動で UObject ヘッダを格納する必要がなくなりました。 - * 「Generated.inl」ファイルは、このファイルに依存している UObject ヘッダを自動的に含むようになりました。 - * プライベートのモジュール ソース ファイルは、「Private」フォルダ配下に配置する必要がなくなりました。 - * 「Public」フォルダ配下に位置しない限り、全てのソースは Private であると仮定されるようになりました。 - * つまり、ゲームソースを全て単一フォルダに格納することが可能です。 -* 「ObjectVersion.cpp」と「Version.h」ファイルは、他のビルド製品とPerforceへチェックインされなくなりました。「build.properties」ファイルのみが最新のエンジンバージョンで更新されます。 - * つまり、ローカルビルドの「GEngineVersion」は常に0に設定されます。機能することを確認しました。0設定で保存されたエンジンバージョンのパッケージは、エンジンに問題なく読み込まれ(この時ローディングコードから警告が出ます)、その他全てと互換性があると仮定されます(パッケージは最新のパッケージバージョンで保存されることに留意してください。ロード時にこのパッケージと比較してチェックされます)。 -* checkAtCompileTime と STRUCT_OFFSET が更新されました。 - * checkAtCompileTime は全てのプラットフォームに対して static_assert を使用します。 - * Clang により良い診断メッセージを提供し、より安定感のある標準サポートを活用します。 - * STRUCT_OFFSET は全てのプラットフォームに対して offsetof を使用します。 - * 可能な限り標準のサポートを使用します。 - * -Wno-invalid-offsetof は全ての GCC/Clang プラットフォームに与えられます。 - * non-POD タイプのエンジン全域で offsetof の使用と、実質的にこの動作に依存するためです。 +* A missing call to Ar.UsingCustomVersion before using CustomVer will cause an assert. +* TArray::SetNum now uses the default constructor when Num is increasing. + * Types must have default constructors to continue to use this call. + * The old zeroing behavior can be achieved via the new SetNumZeroed function. +* FCrc::MemCrc, FCrc::StrCrc and FCrc::StrCrcCaps have been deprecated. + * FCrc::MemCrc32 should be used if possible, as this give the results that would normally be expected from a CRC32 algorithm. + * FCrc::MemCrc_DEPRECATED and FCrc::StrCrc_DEPRECATED should be used if you are dependent on the old results. + * FCrc::StrCrc32 still gives a char-type-independent CRC for a string, and so doesn't necessarily give expected results, but it uses the new string tables. + * FCrc::StrCrcCaps(*Str) can be replaced with FCrc::StrCrc_DEPRECATED(*Str.ToUpper()). +* AVolume has been made abstract. + * Existing Volume instances within maps will cause ensure-failures at load time. + * They should be converted to a non-abstract type (e.g. BlockingVolume) using the editor's Convert feature to change an instance's class. +* When using IncrediBuild, the 64-bit version of XGE is expected to be available (back out CL # 1892517 if you are still using 32-bit) +* LTCG is now enabled for shipping/test Windows targets by default. + * Pass "-noLTCG" to build command-line to disable it, or set BuildConfiguration.bAllowLTCG=false +* UObject C++ headers no longer need to be in a "Classes" subdirectory! + * Classes directory is no longer needed, but we are backwards compatible. + * UObject headers outside of "Classes" are never included in *Classes.h generated group headers. + * Instead, you should always include these headers yourself!(We are starting to deprecate *Classes.h files) + * UObject headers in "Classes" or "Public" folders cannot depend on private UObject classes. + * You no longer need to include UObject headers manually before including a module's *.generated.inl file. + * Generated.inl files now auto-include their dependent UObject headers. + * Private module source files no longer need to be placed under a "Private" folder. + * Now, all source is assumed Private unless it's under a "Public" folder somewhere! + * This means you can have all of your game source in a single folder if you want. +* ObjectVersion.cpp and Version.h will no longer be checked into P4 with other build products.Only build.properties will be updated with the latest engine version. + * This means that GEngineVersion in local builds will always be set to 0.I made sure this is going to work.Packages saved with 0 engine version can be loaded just fine by the engine (although with a warning from the loading code) and are assumed to be compatible with everything (note that we still save packages with the latest package version which we check against when loading). +* Updates to checkAtCompileTime and STRUCT_OFFSET + * checkAtCompileTime uses static_assert on all platforms. + * Provides better diagnostic messages on clang and leverages standard support, which is more likely to be stable. + * STRUCT_OFFSET uses offsetof on all platforms. + * We should be using standard support when at all possible. + * -Wno-invalid-offsetof thrown on all gcc/clang platforms. + * Because we use offsetof on non-POD types all over the engine, and essentially rely on it working. -#### Platforms +#### プラットフォーム * **iOS** - * IPP協調設計機能(中間pemsの紛失)の修復をして、pemsが紛失した時のためにより詳細なメッセージを追加しました。 - * エンジン/ビルド/IOS/リソースから全てを取り込むためにアイコンディスカバリー機能を変更しました。ゲームは、必要時にいつでもオーバーライドが可能になりました。 - * iPhone5のアスペクト比が有効になりました! - * 予想されるアイコン全てをエンジン/ビルド/IOS/リソースへ追加して、一致させるためにEngine/Build/IOS/UE4Game-Info.plistを更新しました。既存の名前は全て変更されました! - * ゲームに「.plist」ファイルが無い場合、Engine/Build/IOS/UE4Game-Info.plistへフォールバックして、実行可能な名前をBundle識別子へ置きます。 -* Steam SDK はバージョン 1.26 へ更新しました。 -* クッカの PackagesToAlwaysCook デリゲートを FCookModificationDelegate と置き換えました (GameDelegates.h 参照)。 -* 「-onethread」を「-nothreading」へ名前変更しました (-singlethread はそのままです)。 + * Repaired IPP codesigning capabilities (missing intermediate pems) and added a more informative error message in case the pems go missing again. + * Changed icon discovery to grab everything from Engine/Build/IOS/Resources, and the game can override whatever it needs. + * Enabled IPhone5 aspect ratio! + * Added all possible icons to Engine/Build/IOS/Resources and updated Engine/Build/IOS/UE4Game-Info.plist to match - ALL EXISTING WERE RENAMED! + * If a game doesn't have a .plist file, it will fall back to Engine/Build/IOS/UE4Game-Info.plist, putting the executable name into the Bundle identifier. +* Steam SDK updated to v1.26 +* Replaced the cooker's PackagesToAlwaysCook delegate with FCookModificationDelegate (see GameDelegates.h). +* Renamed -onethread to -nothreading (-singlethread remains the same). ## 今後の追加事項と継続事項 -#### Editor and Tools -* サイクルごとの秒統計が「ue4stats」ファイルで正しく記録されるようになりました。別のマシーンでプロファイルを開いても、同じ番号が表示されるようになりました。 -* uprojectsは非エディタビルドで正しく読み込まれるようになりました。 -* Linuxでクラッシュする前にログがフラッシュされるようになりました。 -* アセット ディスカバリー時間が多少早くなりました。 -* 一部のビルド環境で問題の要因となっていた、深層部のパスの例外的に長い名前のプレースホルダ―クラスを削除しました。 -* アセット レジストリに上位クラス名のクエリー サポートを追加しました。いずれかの親クラスがロードされたか否かを示すリストが作成されました。 -* PREFETCH と PREFETCH_CONSOLE マクロを新規の platform 関数と置き換えました。FPlatformMisc::Prefetch. -* Visual Studio のデバッグ ビジュアライザーが、モノシリック ビルドで FNames と機能するようになりました。 -* RecastのBuildThirdPartyLibはLinuxのビルドも可能になりました。 -* リダイレクタがロードされていないマップに修正中に参照された場合、エラーメッセージを表示して、参照しているマップを報告します。コード パッケージも同様です。 -* 非同期リキャスト navmesh ビルドは、ターゲットごとに基づいて有効または無効にすることができます。 -* クックのためにUATを使用時に、複数のクライアント/サーバーターゲットを指定できるようになりました。 -* アクタの Tick 関数は、破壊直後に登録削除されるようになりました。破壊されたアクタは RF_PendingKill を持っているため、いずれにせよティックしません。 -* 非従来型のP4クライアントルートを構成しました。 -* サーバーの自動入力と Perfoce ログインのユーザーネームを復活させました。 -* チュートリアルシステムにウィジェットのオーバーレイ表示を新規に追加しました。 -* 新しいアセットとフォルダがクラス フォルダに作成できないようにしました。 -* 空のプレビューメッシュパスがAutomationTest警告を出さないようにしました。 -* 無効のワークスペースが指定された時に、ソースコントロール ログインは正しく拒否されるようになりました。 -* 主要ウィンドウの z オーダーが通知に影響を受けないようにしました。 -* 他者によってチェックアウトされたアセットは、「Submit to Source Control」で正しく処理されるようになりました。 -* [depot->p4 workspace] から手動マッピングへの依存をなくしました (history & diff で問題を修正) 。 -* 可能な場合、移行ファイルはソース コントロールへ追加されるようになりました。 -* コンテンツ ブラウザの使用時に、ソース コントロールがファイル ステータスをスパムしないようにしました。 -* サブミットするファイルを正確にチェックするバックグラウンド タスクを追加しました。 -* ソース コントロール ログイン ダイアログをより利用しやすい表示にしました。 -* 内蔵パッケージに対して、コンテンツ ブラウザが SCC ステートの要求をしないようにしました。 -* スクロール時にサブミット ダイアログがサイズ変更をしないようにしました。 -* アクタ プロパティの「Use Selected」はサブメニューへ移動しました。 -* いつでも Perforce 操作の停止を有効にします。 -* **ワールド ブラウザ** - * ワールド基点の移動は、物理アクタの移動にPhysX3.3関数を使用するようになりました。 - * ストリーミング レベルに LOD サポートを追加しました。 - * レベルタイルに[Details] パネルを追加しました。[Details] パネルが同様の機能性を提供するため、ストリーミング レベルのビューは削除されました。 - * ワールド フォルダを再スキャンしてワールド ブラウザのキャッシュされたデータを更新する「Refresh」コマンド (F5) を追加しました。 - * タイルのソート順序を定義するレベルタイルプロパティへZOrderを追加しました。 -* クラスのドラッグ時にコンテンツブラウザの「Move」、「Copy」メニューを表示しません。 -* ロード中のスクリーンメッセージにフリッカーが発生しなくなりました。 -* ワールド/ローカル座標ボタンにツールヒントが表示されるようになりました。 -* 再入力をチェックして円形がポーズにリンクしているかチェックします。 -* AddEvent が正確なアクタ ラベルを表示するようになりました。 -* ヘッダから FColorTheme 実装を移動させて、前回のチェックインのマージが原因で発生した不良タブを一掃しました。 -* 追加のデータはスタティックメッシュエディタでアイコン表示されるようになりました。 -* さまざまな細かい改善と微調整がテクスチャエディタのユーザビリティに追加されました。 -* 誤ったエディタモードが原因で発生するエラーは、その理由と表示方法を指定できるようになりました。 -* ベース マテリアルへリセットされた時に、 OnResetToDefaultClicked デリゲートが発行されるようになりました。 -* コマンドラインで「 -interactivetutorials」と一緒に起動されない限り、InteractiveTutorialsはnullです。 -* マップのライティングの再ビルドが必要な場合、マップはダーティとマークされなくなりました。 -* タブ表示する子がない時は、タブ表示を防ぎます。 -* スパムによるスタティックメッシュのスポーン時に、クラッシュを回避します。 -* 新規のコード プロジェクトの作成時にエディタが閉じなくなりました。 -* 平行して挿入するタブが見つからない場合、 InsertDocumentTab がタブをスポーンするようになりました。 -* エディタからソリューションを開くときに、確実に絶対パスを使用します。 -* 焦点を失った時に提案ボックスが非表示になります。 -* エミッターのカラー ピッカーはモーダルではなくなりました。 -* Color Theme がドロップダウン リストに適切なテキストを表示するようになりました。 -* 不具合のあるタブや ID がエディタをクラッシュすることはなくなりました。 -* ソース コントロール「エラー」が原因で「Convert メッシュ」がエラー フラグを表示することはなくなりました。 -* MessageLog はユーザーが表示した最初の入力、もしくは最後のログへデフォルト設定されます。 -* [Enter] キーを押した時点で Asset Picker で何も選択されていない場合、自動選択と単独または最初のアセットののアクティベート機能が追加されました。 -* フォルダパスがプラットフォームに対して有効にフォーマットされていることを確認するため、 [New Project] ウィザードが追加されました。 -* マテリアル選択:素早く入力するとフィルタリングが壊れてしまうため、bShouldNotifyNextAssetSyncフラグを削除しました。 -* [Choose Files to Save] クリック時の Asset Saving 通知がエラーによく似ていたので、Notification(通知) に変更しテキストが明確になるよう修正しました。 -* [Favorites] からレベルの削除は困難でした。お気に入りリストへの入力はレベル リストが開かれた時のみ追加/削除ができました。この必須条件を取り除いて Open/Removing オプションをサブメニューへ移動しました。また、一貫性にかけた内部のエントリ名のバグを修正しました。 -* Normal Map Texturesの自動再インポートは、DXT5n法線マップのDefer Compressionとcompatibilityモードの併用が原因で破損していました。圧縮されていないディファード法線マップに対しXGXR8が追加されました。 -* ウィンドウ管理:新規タブの作成時、またはウィンドウ配下の別のタブを選択して更新します。常に「"map - Unreal Editor"」のネーミングスキームを維持するマスター/ルートウィンドウでない限り、タブラベルのタイトルを変更します。 -* オートセーブ進捗ウィジェットに [Cancel] ボタンをオプションで追加しました。 -* コンテンツ ブラウザ:Shared または Private コレクションを有効にするテストが評価されるのは、コレクション コンテクスト メニュー (右クリック) の作成のみなので、 Shared または Private コレクションを作成することができます。 -* 複数回適用された平行移動、回転、スケーリングはデルタを使用しているため、アタッチされているグループ化されたアクタは正確に平行移動しませんでした。親アクタがグループ アクタで修正されないようにチェックを追加しました。 -* Factory からアクタを追加するために、レベル エディタ コンテキスト メニューを更新しました。アクタは Factory で bShowInEditorQuickMenu フラグを使用します。 -* クロス プロジェクトから移行したレベルのワールド設定が原因のクラッシュを、現行プロジェクトに新たなワールド設定を作成して回避しました。 -* レベル ブラウザのサブレベルの可視性の変更により、サブレベルの「umap」ファイルがダーティになりました。エディタ内部のレベルの可視性の変更のみを行っている場合、ダーティ フラグをリセットします。 -* 参照オブジェクトからコンテンツブラウザへコレクションを作成すると、指定パスにあるNullフォルダが要因となり、"u_pattern_syntax_error"の権限を持つコレクションが作成されていました。このパスの構成を訂正しました。 -* ヘッダのサブカテゴリの一部をより記述的にしました。 -* [Details] パネルに、可視のメニュー項目として「Expand All Categories」と 「Collapse All Categories」があります。 -* [F1] キーはアセット エディタ上でコンテキスト感受性の動作をするようになりました。 -* シーンアウトライナーのソートが可能になりました。 -* **スレート** - * SComboBox と SComboButton は Slate ウィジェットスタイルを使用し、 FEditorStyle 依存ではなくなりました。 - * 必要に応じてタブをフラッシュできるようになりました。 -* PIE または SIE セッションが一時停止、再開、または停止された時にデリゲートの利用が可能になりました (既存の再生と停止に追加)。 -* 新規のアセットのネーミング時に無効なキャラクターに対して警告が表示されます。 -* 最後の自動保存から変更があった時のみに自動保存が実行されます。 -* アセット SCC とダーティステートを表示するためにコンテンツ ブラウザ カラムビューが更新されました。 -* 非モーダル カラー ピッカーが改善されました。 - * 元に戻す / やり直す操作が完全にサポートされました。 - * カラー プロパティの変更はオブジェクト上でインタラクティブにプレビューできます。 -* コアなスレートウィジェット全てから FEditorStyle を削除しました。 - * 進行中の作業ですが、いくつかのウィジェットクラスは作業が完了しています。 -* 以下の領域にエディタの使用状況を追跡する新規のエンジン分析が追加されました: - * PIE(Play-in-editor)の使用量 - * ブループリントの作成(親クラス、タイプ、作成手法) - * タブとウィンドウの使用の結合 - * レベルへポーンを直接追加 - * ブループリントコンテキストメニューの使用量 - * BSP(バイナリ空間分割)ブラシの使用量 -* SoundCue エディタの Result ノードを Output へ名前変更 -* SoundWave をダブルクリックしてプロパティを表示 -* カーブ エディタが前回選択したキーの位置を、新たに選択したキーに適用させないようにしました。 -* Sound Classes と Sound Mixes の潜在的に危険な組み合わせが作成された時に警告が表示されます。 -* 従来の接続の入力へ追加された Sound ノードが自動的に接続するようになりました。 -* ライブ更新が有効な時は、 Material Editor ノードはリアルタイムで更新されます。 -* スレート マテリアル エディタのパフォーマンスが向上しました。 -* Material Editor ノードが以前よりも圧縮されました。 -* マテリアル エディタへのドラッグ&ドロップ操作を取り消せるようになりました。 -* Material Result ノードは正確な入力を表示するようになりました。 -* Material ノードと Comment 位置の変更により、ユーザーは変更の適用を促されるようになりました。 -* 変更時に動的パラメータ名が更新されるようになりました。 -* Material Input ノードのグレーアウト表示されたピンのテキストもグレーアウト表示されるようになりました。 -* サウンドの再インポート時にカスタム設定が保持されます。 -* イタレーションするアクタの検索に TActorIterator は GetObjectsOfClass を使用します。 -* Allow Translucent Selection がデフォルトで使用できるようになりました (ユーザビリティ フィードバックに基づいて)。 -* デフォルトの template マップは (エディタで [File -> New] の選択時に利用可能) 以前よりも簡略化されました。 -* 国際管理化のために終了ロジックを追加しました。システムからメモリリークの誤検出がなくなりました。 -* 国際管理化システムは、常にゲームデータのロードをしなくなりました。 -* 非 Windows プラットフォームは、ローカライズされたフォーマット形式の文字列で、グレイヴ・アクセント (`) と アポストロフィ (' ) を適切にサポートします。 -* アセット機能から収集したローカリゼーションデータにより、コリジョンのレポートが改善しました。 -* Settings UI のナビゲーションメニューが改善しました。 +#### エディタとツール +* The seconds per cycle stat is now properly being recorded in ue4stats files.Opening a profile on different machines now shows the same numbers. +* uprojects are now properly loaded in non-editor builds. +* The log is now flushed before a crash in Linux. +* Asset discovery time should be slightly faster. +* Removed a placeholder class with an exceptionally long name in a deep path which was causing build problems in some build environments. +* Added support to query for ancestor class names in the asset registry.The list is formed whether or not any of the parent classes are loaded. +* Replaced the PREFETCH and PREFETCH_CONSOLE macros with a new platform function:FPlatformMisc::Prefetch. +* The visual studio debugging visualizer now works with FNames in monolithic builds. +* BuildThirdPartyLib for Recast will now also build linux. +* If a redirector is referenced by an unloaded map while it is being fixed up, the error message will now report which map is referencing it.Same for code packages. +* Async recast navmesh building can now be enabled or disabled on a per-target basis. +* You can now specify multiple client/server targets when using UAT to cook. +* An actor's tick functions are now unregistered immediately upon destroy.Destroyed actors do not tick anyway because they have RF_PendingKill. +* Accounted for unconventional P4 client roots (this prevented diffing & history from working) +* Re-instated auto-population of server & username for Perforce login. +* Added new widget overlay to tutorial system. +* Prevented new assets & folders from being created in the Classes folder. +* Prevented empty preview mesh paths from causing an AutomationTest warning. +* Source control login now correctly denied when specifying an invalid workspace. +* Prevented main window z-order from being affected by notifications. +* Assets checked out by others are now correctly handled by "Submit to Source Control". +* Stopped relying on manual mapping from depot->p4 workspace. (fixes issues with history & diff) +* Migrating files now adds them to source control if possible. +* Prevented source control from spamming file status when using content browser. +* Added background task to properly check for files to submit. +* Made the source control login dialog more friendly. +* Prevented content browser from trying to request SCC state for built-in packages. +* Prevented submit dialog from resizing when scrolling. +* 'Use Selected' now moved to sub-menu for Actor properties. +* Allowed cancellation of Perforce operations at any time. +* **World Browser** + * World origin shifting now uses PhysX3.3 builtin function to shift physics actors. + * Added LOD support for a streaming levels. + * Added details panel for level tiles.Streaming levels view was removed, since details panel provides similar functionality. + * Added 'Refresh' command (F5) which rescans world folder and updates World Browser cached data. + * Added ZOrder to a level tile properties which defines tile sorting order. +* Don't display content browser move/copy menu when dragging a class. +* Loading screen message no longer flickers. +* Tooltip for world/local coordinate button now appears. +* Check if circular linked poses by checking against reentry. +* AddEvent now displays the correct actor label. +* Moved FColorTheme implemenation out of header, and cleaned up bad tabs caused by merge from previous checkin. +* Additional Data now has icon in static mesh editor. +* Various minor improvements and tweaks to the texture editor useability. +* Errors that occur due to incorrect editor modes can now specify why and how they are displayed. +* OnResetToDefaultClicked delegate now fires when resetting to base material. +* InteractiveTutorials is null, unless also launching with -interactivetutorials on the commandline. +* Map is no longer marked as dirty if it needs its lighting rebuilt. +* Guard against tabbing when there's no child to tab to. +* Prevent crash when spam spawning static meshesh. +* Editor no longer closes when creating a new code project. +* InsertDocumentTab now spawns a tab if it can't find the one to insert alongside. +* Make sure we're using absolute paths when opening a solution from the editor. +* Suggestion box now disappears on focus loss. +* Emitter color picker is no longer modal. +* Color Theme now displays appropriate text when in dropdown. +* Bad tab/malformed ids no longer crash the editor. +* 'Convert meshes' no longer flags error due source control "error." +* MessageLog now either defaults to the first entry, or the last log the user viewed. +* Added automatic selection and activation of sole or first asset if none is currently selected on pressing Enter to Asset Picker. +* Added check to New Project wizard to make sure that the folder path is validly formatted for the platform. +* Material Selection:Filtering broko when typing quickly so removed the bShouldNotifyNextAssetSync flag which seemed to exist only to cause it to automatically select an asset if it was still loading others. +* The Asset Saving notification when clicking "Choose Files to Save" looked too much like an error, changed to Notification, and modified the text for clarity. +* It was difficult to remove a level from Favorites.Entries in the favorite list could only be added/removed when the level list was open, removed that requirement and moved open/removing to a sub-menu, also fixed inconsistent internal entry naming bug. +* Normal Map Textures automatically reimported were corrupted due to combined use of Defer Compression & compatibility mode DXT5n normal maps, added swizzled XGXR8 mode for uncompressed deferred normal maps. +* Window Management:On creating a new tab, or otherwise updating it by selecting another tab under a window, change the title to that tabs label unless it's the master/root window which always retains the "map - Unreal Editor" naming scheme. +* Add an optional Cancel button to the auto-saving progress widget. +* Content Browser:Could create a Shared or Private collection because the test enabling shared or private collections was only being evaluated after the collections context menu (right-click) was being created. +* Attached grouped actors did not translate properly becuase they were having deltas for translation, rotation & scaling applied multiple times.Added a check to prevent parented actors being modified by the group actor. +* Updated the level editor context menu to add actors from factories which use the bShowInEditorQuickMenu flag on the factory. +* Prevented a crash caused by cross-project migrated levels world settings not existing in the new project, by creating new world settings for it in the current project. +* Changing the visibility of sub-levels from the level browser dirtied the sub-level umap files.Reset the dirty flag if all we're doing is changing the visibility of the level within the Editor. +* Creating a collection from referenced objects in the content browser produced a collection entitled "u_pattern_syntax_error" due to a Null folder in the specified path so corrected the path construction. +* Changed some of the heading sub-categories to be more descriptive. +* Details panel now contains Expand All Categories / Collapse All Categories visibility menu options. +* F1 now behaves context-sensitively on asset editors. +* The scene outliner is now sortable. +* **Slate** + * SComboBox and SComboButton now use a Slate Widget Style and are no longer dependent on FEditorStyle. + * Tabs can now flash when they want attention. +* Delegates are now available for when a PIE or SIE session is paused, resumed, or stepped (in addition to the existing ones for start and stop). +* You are now warned of invalid characters when naming a new asset. +* The auto-save now only runs when things have changed since the last auto-save. +* The Content Browser column view has been updated to display asset SCC and dirty states. +* Improvements to non-modal color pickers. + * Undo/redo fully supported. + * Changes to color properties are previewed interactively on the object. +* Removing FEditorStyle from all core slate widgets. + * This is still in progress but several widget classes have been completed. +* New engine analytics to track editor usage in the following areas: + * Play-in-editor usage. + * Blueprint creation (parent class, type, creation method). + * Docking tab and window usage. + * Pawns added directly to levels. + * Blueprint context menu usage. + * BSP brush usage. +* SoundCue Editor's 'Result' Node renamed to 'Output'. +* Double clicking SoundWave will now display its properties. +* Prevented Curve Editor from applying previously selected key's position to newly selected key. +* Warning shown when creating potentially dangerous combinations of Sound Classes and Sound Mixes. +* Sound Nodes added to the input of an existing connection will now auto connect. +* Material Editor nodes now update in realtime when live update is enabled. +* Performance of Slate Material Editor improved. +* Material Editor nodes are now more compact. +* Dragging and dropping into Material Editor can now be undone. +* Material Result node now shows correct inputs. +* Changes to Material Node and Comment positions now prompt the user to apply changes. +* Dynamic Parameter names now update when changed. +* Greyed out pins now have greyed out text on Material Input node. +* Custom settings are retained when reimporting sounds. +* TActorIterator now uses GetObjectsOfClass to find actors to iterate over. +* "Allow Translucent Selection" now defaults to on (based on usability feedback). +* Default "template" maps (available when using File -> New in editor) have been further simplified. +* Added termination logic for internationalization.No longer see a false (meaningless) positive for memory leaks from the system. +* Internationalization system no longer always loads game data. +* Non-Windows platforms now handle graves and apostrophes (` and ') properly in localized formatting pattern strings. +* Localization data gathering from assets features improved reporting of collisions. +* Improved navigation menu in the Settings UI. * **Play-In-Editor** - * マルチプレイヤー PIE でスクリーン空間をより効率良く使用するために、ウィンドウ レイアウト アルゴリズムが改善されました。 + * Improved window layout algorithm to use screen real estate more efficiently in multiplayer-PIE. #### Blueprints -* [My Blueprint] パネルでアイテムにマウスをかざした時、また Get ノードにマウスをかざすと変数のツールヒントが表示されます。 -* 入力配列ピンをドラッグ時に、Make Array ノードの追加がユーザーに提示されます。 -* 検索ワードにスペースを挿入することで [Find in Blueprint] 機能の検索問題が解消されました。 -* [MyBlueprint] ウィンドウで親グラフをダブルクリックしても、ウィンドウを折りたたんだり展開しません。 -* ブループリント グラフのナビゲーション方法を調整しました。 - * グラフパネルで関数またはマクロ グラフをダブルクリックすると、現在のタブを再利用する代わりに新規のタブが開きます (もしくは既に開いているインスタンスにフォーカスします)。 - * [Find Results] ウィンドウをダブルクリックすると、現在のタブを再利用する代わりに新規のタブが開きます (もしくは既に開いているインスタンスにフォーカスします)。 - * グラフパネルで折りたたみグラフをダブルクリックすると現在のタブが再利用されます。 -* ネイティブ バージョンのいくつかの Make/Break Struct ノードを非表示にします。 -* 親と子のブループリント間のタイムライン名、メンバ変数名、関数グラフ名が重複しないようにする対策を増やしました。 -* スケルタル メッシュからスケルトン、またテクスチャからマテリアルを作成すると、デフォルトで新規のアセットに固有名が与えられます。 -* 選択したアクタからブループリントを作成すると、ダイアログに名前を入力するオプションが与えられます。 -* 全てのコンポーネント クラスにツールヒントが追加されました。 -* ブループリント パレットに MakeとBreak の構造体ノードが追加されました。 -* 必要箇所でコメントが検索できるようにブループリントの検索機能が改善されました。 -* より望ましい結果を提供するために、ブループリント パレット / コンテキストを自動選択するコードを修正しました。 -* ブループリント コンテキスト メニューのキーボード処理を改善しました。 -* 検索ワードにスペースを挿入することで [Find in Blueprint] 機能の検索問題が解消されました。 -* ブループリント コンテキスト メニューに [open in new tab] を追加しました。 +* Variable tooltips will appear when mousing over the item in the My Blueprint panel and when mousing over "Get" nodes. +* When dragging off an input array pin, user will be offered to add a "Make Array" node. +* Find in Blueprint will no longer have issues searching due to spaces in the search term vs the results. +* Double clicking on a parent graph in the MyBlueprint window will not collapse it or expand it. +* Adjusted how the navigating Blueprint graphs. + * Double clicking on a function or macro graph in the graph panel will open a new tab (or focus on an already opened instance) instead of reusing the current tab. + * Double clicking in the Find Results window will open the graph in a new tab (or focus on an already opened instance) instead of reusing the current tab. + * Double clicking on a collapsed graph in the graph panel will reuse the current tab. +* Hid a few Make/Break Struct nodes that had native versions. +* Put in more protection to prevent duplicate timeline, member variable, and function graph names between parent and child Blueprints. +* Creating skeletons from skeletal meshes and materials from textures will give the new asset a default unique name. +* When creating a Blueprint from selected actors, the dialog gives the option of inputing a name. +* Added tooltips to all component classes. +* Added Make/Break for struct nodes to blueprint palette. +* Improved blueprint search so comments are searched where possible. +* Revised code that autoselects in blueprint palette/context menu to provide more desirable results. +* Improved keyboard handling of blueprint context menu. +* Find in Blueprint will no longer have issues searching due to spaces in the search term vs the results. +* Add 'open in new tab' to My Blueprint context menu. #### ゲームプレイとフレームワーク -* ゲームフレームワーク エンジン クラスのコメントをクリーンアップしました。 -* ゲームフレームワーク エンジン クラスから廃止されたプロパティとメソッドが削除されました。 -* 廃止された UWorld プロパティの RealTimeToUnPause が削除されました。 -* 廃止された PlayerController プロパティの MaxResponseTime が削除されました。 -* 廃止された PlayerController メソッドの ConditionalPause() が削除されました。 -* PlayerState から廃止されたネットワーク統計関連の数多くのプロパティを削除しました。 -* HUD と HudSettings クラスから未使用の HUDCanvasScale プロパティを削除しました。 -* UEngineMessage から未使用の FailedSpawnMessage プロパティを削除しました。 -* GameMode から StreamingPauseIcon プロパティを削除しました。クライアントがこのプロパティの使用を試みるとクラッシュします。 -* GameModeとPlayerState から未使用の GameMessageClass プロパティを削除しました。 -* **入力システムの改善** - * 入力デリゲートは、単一フレーム内部でキーが押された / リリースされた順序での実行が保証されるようになりました。 - * 単一フレーム内部で押下、リリース、そして再度押下された場合、入力デリゲートを単一フレーム内で複数回ディスパッチすることができます。 - * ペアの入力アクション (押下とリリースが結合したアクション) は、ダウンステートを管理するようになりました。複数キーがアクションと結合する場合、最初に押されたキーがアクションをキャプチャー、非キャプチャキーによって押下もしくはリリースされたイベントは、キャプチャされているキーがリリースされるまで無視されます。A と B がアクションにマッピングされている例は、押下デリゲートおよびリリース デリゲートの結合の両方の場合に存在します。 - * 例 1: - * A が押下されてアクションをキャプチャして、押下デリゲートがディスパッチされます。 - * B が押下されて、押下デリゲートがディスパッチされないように A がキャプチャされます。 - * B がリリースされて、リリース デリゲートがディスパッチされないように B をキャプチャしません。 - * A がリリースされて、リリース デリゲートがディスパッチされるように A がキャプチャされます。 - * 例 2: - * A が押下されてアクションをキャプチャして、押下デリゲートがディスパッチされます。 - * B が押下されて、押下デリゲートがディスパッチされないように A がキャプチャされます。 - * A がリリースされて、リリースされたデリゲートがディスパッチされるように A がキャプチャされます。 - * A が再度押下されて、 A がキャプチャして押下デリゲートがディスパッチがされるようにキャプチャはありません。 - * 前回のリリース デリゲートがディスパッチされたように、 A がリリースされます。 - * B がリリースされて、リリース デリゲートがディスパッチされないように B をキャプチャしません。 -* [Load Stream Level] と [Unload Stream Level] は、レベルブループリントのみに限らず、任意のブループリントから呼び出すことができます。 -* レベルのストリーミングに配置されたポーンのコントローラーはパーシスタント レベルではなく、ストリーミング レベルでスポーンされるようになりました。 -* BeginPlay 中の操作を可能にするため、HUD は BeginPlay の前に初期化されるようになりました。 -* **Oculus Riftの統合** - * Oculus Rift のサポートに対して、いくつかの改善とバグ修正がされました。ステレオ スコピック ビューで以前レンダリングができなかった特定のポストプロセスとスクリーン空間エフェクトに対する修正が含まれています。 -* 全ての新規のゲーム テンプレート プロジェクトのソース ファイル レイアウトを簡略化しました。 -* コードベースの「SampleGames」ディレクトリテストとして、Platformergameを「Samples」へ移動しました。 - * メインディレクトリから「Samples」配下の「Games」サブディレクトリへ、全てのコードベースのゲーム例の移動に取り組んでいきます。「Games」は現在の「SampleGames」フォルダを名前変更したフォルダです。(例:現時点では //depot/UE4/PlatformerGame/ ? //depot/UE4/Samples/SampleGames/PlatformerGame/ ) (最終的なフォルダ位置は恐らく次のようになります。//depot/UE4/Samples/Games/PlatformerGame/) -* RPC Client/Server 関数から値を返すと、コンパイルエラーとして検知されるようになりました。 -* **コンポーネント移動の最適化** - * 度重なる MoveComponent の呼び出しは、 FScopedMovementUpdate() オブジェクト内に MoveComponent コールをカプセル化するため、移動シーケンスがコミットされるまで大部分の動作を保留にします。 - * スコープ内の移動は、移動がコミットされるまで (スコープが文脈を離れた時に発生) UpdateBounds()、OnUpdateTransform()、 UpdatePhysicsVolume()、 UpdateChildTransforms() などの更新を回避します。 - * 大量のスコープの更新がサポートされています。最終スコープが終了まで移動はコミットされません。 - * 現在の移動スコープは元の状態に戻すことができます。つまり、スコープ開始時に位置は元の位置へ修復されます。 -* **CharacterMovementComponent の最適化** - * UCharacterMovementComponent で実行される移動に対してスコープ内の移動更新を有効にしました。キャラクター移動のパフォーマンスがほとんどのケースで 2 倍から 3 倍に向上しました。 - * 傾斜に沿った移動にもはや StepUp() を使用しませんが、その代りにサーフェスと平行に移動します。所要スイープの数が削減されました。実用的な場面において、傾斜は階段に推奨されるコンテンツ ソリューションです。 -* **CharacterMovementComponent の改善** - * StepUp() の機能性により一貫性が増しました。 - * フロアチェックの観点から、シミュレートした移動が実際の移動とさらに一致するようになりました。 - * シミュレートした移動は、歩行可能な傾斜を垂直なバリアとして処理せずに、スムーズにスライドするようになりました。 - * ベロシティは即座に最高速度にクランプせずに、全移動モード (外力から) で最高ベロシティを上回るようになりました。ベロシティが最高速度を上回った時点で、摩擦とブレーキが適用されます。 - * 非水平面上の地上移動をあたかも水平面上のような移動を維持するベロシティ、またはサーフェスに対して平行移動を維持するベロシティをコントロールするパラメータを追加しました。  -* BP blend ノードを使用時にテキストが正しくトリム (装飾) されるようになりました。 -* デフォルト設定のボーン アタッチメント座標空間をワールドからローカルへ変更しました。 -* アタッチされていないパーティクルのスポーンをサポートするためにパーティクル anim notify UAsset を修正しました。 -* PHat のウィジェットは編集後に消滅することはなくなりました。 -* アタッチポイントの編集時に、通知がドロップダウン リストをサポートするようになりました。 -* ペルソナで保存すると、修正されたアセットのみが保存されるようになりました。 -* Kismet InitとUpdateAnim イベントにツール ヒントが設定されました。 -* 通知によるカスタム通知の削除を有効にするため、メニュー エントリを新たに追加しました。 -* Behavior Trees コアとツールは以前として WIP に位置します。 -* アニメーション システムの改善 - * 物理アニメーション:BlueprintCallable Physics Weight 関数 SetPhysicsWeight/AccumulatePhysicsWeight を追加しました。 - * BlendSpace ノードは、ピン経由で Position と Looping の設定を有効にします。 - * IK ノードは、エフェクタとジョイント位置を表示します。 -* 物理:ラグドール処理を改善するためにデフォルト設定が微調整されました。 -* 最適化:物理 / ティックを無効にすることによりデディケイテッド サーバーの最適化しました。 +* Comment clean up for game framework engine classes. +* Removed obsolete properties and methods from game framework engine classes. +* Removed obsolete UWorld property RealTimeToUnPause. +* Removed obsolete PlayerController property MaxResponseTime. +* Removed obsolete PlayerController method ConditionalPause(). +* Removed a bunch of obsolete networking stats related properties from PlayerState. +* Removed unused HUDCanvasScale property from HUD and HudSettings classes. +* Removed unused FailedSpawnMessage property from UEngineMessage. +* Removed StreamingPauseIcon property from GameMode.Wrong place for it- client will crash if it tries to use it. +* Removed unused GameMessageClass properties from GameMode and PlayerState. +* **Input system improvements** + * Input delegates are now guaranteed to execute in the order the keys were pressed/released when occurring within a single frame. + * An input delegate can now be dispatched multiple times in a single frame if it is pressed and release and re-pressed within a single frame. + * Paired input actions (these are actions for which both a pressed and released are bound) now manage a down state such that if multiple keys are bound to that action the first one pressed captures it and any press or release events by non-capturing keys will be ignored until the capturing key is released.So a few examples where A and B are mapped to an action that has both a pressed and released delegate bound. + * Example 1: + * A is pressed and captures the action, pressed delegate IS dispatched. + * B is pressed, A has capture so the pressed delegate IS NOT dispatched. + * B is released, B did not have capture so the released delegate IS NOT dispatched. + * A is released, A did have capture so the released delegate IS dispatched. + * Example 2: + * A is pressed and captures the action, pressed delegate IS dispatched. + * B is pressed, A has capture so the pressed delegate IS NOT dispatched. + * A is released, A has capture so the released delegate IS dispatched. + * A is pressed again, there is no capture so A captures and the pressed delegate IS dispatched. + * A is released, as previously released delegate IS dispatched + * B is released, B did not have capture so the released delegate IS NOT dispatched. +* Load Stream Level and Unload Stream Level can be called from any blueprint, not just level blueprint. +* The Controller for a Pawn placed in a streamed in level will now be spawned in the streamed level, not the persistent level. +* HUD is now initialized before BeginPlay so as to be available for manipulation during BeginPlay. +* **Oculus Rift Integration** + * There have been several improvements and bug fixes to Oculus Rift support, including fixes to certain post process and screen-space effects that previously did not render when in stereoscopic view. +* All new game template projects now have a simplified source file layout. +* Moving Platformergame into Samples as a code-based SampleGames directory test. + * We'll make an effort to move all code-based example games from the main directory down into a new Games subdirectory under Samples.Games will be the current SampleGames folder renamed. (e.g. CURRENTLY //depot/UE4/PlatformerGame/ ? //depot/UE4/Samples/SampleGames/PlatformerGame/ ) (The final location being something like //depot/UE4/Samples/Games/PlatformerGame/) +* Trying to return a value from a RPC Client/Server function is now detected as a compile error. +* **Component movement optimizations** + * Repeated calls to MoveComponent can defer most of the work until the sequence of moves is committed, by encapsulating the MoveComponent calls within a FScopedMovementUpdate() object. + * Moves within this scope will avoid updates such as UpdateBounds(), OnUpdateTransform(), UpdatePhysicsVolume(), UpdateChildTransforms() etc, until the move is committed (which happens when the Scope goes out of context). + * A stack of scoped updates is supported, and the move is not committed until the final scope is finished. + * The current scope of moves can be reverted, which will restore the position to the initial position at the start of that scope. +* **CharacterMovementComponent optimizations** + * Scoped movement updates are enabled for movement performed by UCharacterMovementComponent, for a 2x to 3x performance increase in character movement in most cases. + * Movement along ramps no longer uses the StepUp() function, but moves parallel to the surface instead, reducing the number of sweeps required.Ramps are the preferred content solution for stairs where practical. +* **CharacterMovementComponent improvements** + * StepUp() functionality is now more consistent + * Simulated movement is more in line with actual movement in terms of floor checks. + * Simulated movement now slides smoothly up walkable ramps instead of treating them as vertical barriers. + * Allow velocity to exceed max velocity in all movement modes (from external forces), rather than clamping immediately to the max velocity.Friction and braking are now applied when velocity exceeds the max. + * Added param to control whether ground movement on non-horizontal surfaces maintains the velocity as if it was horizontal, or whether velocity is maintained parallel to the surface. +* Text is now correctly trimmed when using BP blend nodes. +* Changed default bone attachment coord space to local from world. +* Modified the particle anim notify UAsset to support non-attached particle spawning. +* Widget in PHat no longer disappears after editing. +* Notifies now support a dropdown list when editing the attach point. +* Saving in Persona now only attempts to save modified assets. +* Kismet Init and UpdateAnim events now have tool tips. +* Added a new menu entry to manage notifies to allow deletion of custom notifies. +* Behavior Trees core and tools are still WIP. +* Animation System Improvement + * Physics Animation:Added BlueprintCallable Physics Weight functions SetPhysicsWeight/AccumulatePhysicsWeight + * BlendSpace Node allows to set Position/Looping via Pin. + * IK node displays effector/joint location. +* Physics:Default setting has been tweaked to improve ragdoll. +* Optimization:Dedicated server optimization by disabling physics/tick. -#### Rendering -* HardwareSurvey へ GPUIndex を追加しました (高速設定のため信頼下限で簡単実行)。 -* スペキュラを切り離すために、アルファシーンカラーのアルファ チャンネルを利用して実験的なスクリーン空間のサブサーフェススキャッタリングを採用しました。大部分のレンダリング パスには最少限のコストが発生しますが、32 ビット フォーマットの仕様時は、実験的なスクリーン空間のサブサーフェス スキャッタリングを有効にしません。 -* cvar が拡張オプションとして使用できる場合、ECVF_Scalability がドキュメントに追加されました。 -* r.TonemapperQuality スケーラビリティを追加しました (高スペックのためにノイズをカラー量子化に対抗させるため) -* RT と GT で使用時に、パフォーマンスの向上とスレッドセーフのために型付のコンソール変数を追加しました。 -* テキストをレンダリングするアクタに、簡単選択のためにアンカー スプライトが追加されました。 -* [Exposure] メニュー オプションを整理しました。ポストプロセスの露出コントロールは、「Auto Exposure」配下に名前変更および再グループ化されました。 -* エディタは、中間ではなく精度の高いモードで起動するようになりました。 -* 「r.SceneRenderTargetResizeMethod」を追加しました。 - * シーンのレンダー ターゲットのメモリー使用法をコントロールします。 -* デフォルト テクスチャが選択されたテクスチャを含めた material expression ノードを作成しています。 -* UIBlur レンダリングを最適化しました。 - * リクエストされたセクションのみをレンダリングします (全スクリーンの代わりに)。 -* 迅速なアクセスのために、大部分の CVars を新規の特定タイプのフォーマットへ移動しました。 +#### レンダリング +* Added GPUIndex to HardwareSurvey (quick run with lower confidence for faster startup). +* Experimental screen space subsurface scattering using alpha scene color alpha channel to separate out specular, very minor cost for most passes and if using a 32bit format we don't have it enabled. +* Added ECVF_Scalability to document if a cvar can be used as scalability option. +* Added scalability r.TonemapperQuality (noise to fight color quantization only for higher specs). +* Added typed console variable for better performance and thread safety when using in RT and GT. +* Text render actors now have an anchor sprite for easy selection. +* Exposure menu options have been tidied up.Post process exposure controls have been renamed and regrouped under "Auto Exposure". +* The editor now starts up in high detail mode, not medium. +* Added r.SceneRenderTargetResizeMethod + * Controls memory usage technique for scene render targets. +* Creating material expression nodes which include textures now have the default texture selected. +* Optimized UIBlur rendering. + * Renders only the sections requested (instead of whole screen). +* Moved most CVars to a new type specific format, affording much faster access. -#### Animation -* ユーザーがスケルトンの代わりにアセットをメッシュソケットへドロップしメッシュへアタッチするとペルソナがこれを検知します。 -* 全ての Skeletal Control と Blend Pose Blueprint ノードに記述的なツールヒントが追加されました。 -* PhAT でシミュレーション中、[Ctrl-右マウス] 操作でオブジェクトとのインタラクションが可能なことを示すがオンスクリーンメッセージで表示されます。 -* 未使用なコードは、skeleton compression 関数から削除されました。 +#### アニメーション +* Persona now detects if you drop an asset onto a mesh socket and attaches to the mesh, rather than the skeleton. +* Descriptive tooltips added for all Skeletal Control and Blend Pose Blueprint nodes. +* When simulating in PhAT, an onscreen message now tells the user they can use Ctrl-RightMouse to interact with objects. +* Unused code removed from skeleton compression functions. -#### Core -* エンジン バージョンに基づくように、バイナリ ファイルのバージョン付スキームを修正しました。 -* #プラグマ領域などに接触した際に拒絶しないように、 UnrealHeader ツールは、認識しない全ての# プラグマを無視するようになりました。 -* HeaderGroups は徐々に機能から削除される方向に進んでいます。 headergroups の継続的な使用は中止しなくてはいけません。 -* **ビルドシステム** - * bPrintPerformanceInfo 診断変数を UnrealBuildTool へ新たに追加しました。 -* ULevel へ AssetUserData サポートを追加しました (カスタムペイロードと一緒にレベルを拡張するプラグインを有効にしました)。 -* C++ コードの Hot Reload の信頼性がより高まりました。 +#### コア +* Modified the binary file versioning scheme so that it is based on the engine version. +* UnrealHeaderTool now ignores all unrecognized #pragmas, so it won't baulk when encountering things like #pragma region. +* HeaderGroups are slowly being removed in a move towards removing the feature; the on-going use of headergroups should stop. +* **Build System** + * Added new 'bPrintPerformanceInfo' diagnostic variable to UnrealBuildTool. +* Added AssetUserData support to ULevel (allows plugins to extend Levels with their custom payloads). +* "Hot Reload" of C++ code has been improved to be more reliable. -#### Platforms -* Linuxサポートを改善しました(正しいコールバックを取得するためDWARFがパースするようになりました。プラットフォームの抽象レイヤーはプロセス管理をカバーするように拡張されました。HTTPモジュールの追加機能) -* 全 [Editor] ウィンドウが、Mac OS X の [Dock] メニューにリストされるようにしました。 -* Mac OS X Mavericks の Space でディスプレイごとのマルチモニタ モードでセカンダリ モニタ上にエディタ ウィンドウを配置した時に、エディタ ウィンドウが消滅しないようにしました。 -* スナップとハイパーアクセラレーションを削減するために、一部の [Editor] モードでマウスドラッグ処理を改善しました。 -* Mac OS X 上でダブルクリック操作で Unreal プロジェクトを開くサポートを追加しました。 -* Subversion の Xcode のコピーを利用して、 Mac OS X に対応する Subversion のサポートを有効にしました。 -* マチネにムービーファイルを作成するために Mac OS X サポートを実装しました。 -* 別の実装のようなサウンドとなるように、Mac OS X の CoreAudio reverb を微調整しました。 -* Direct3D バージョンに従って、スレートにスタンドアローンの OpenGL レンダラーを導入しました。 -* シミュレーターに対する早期サポート、次の QA ビルドによりこれらの切り替えが簡単になります。 +#### プラットフォーム +* Improved Linux support (DWARF is now parsed to get proper callstacks, platform abstraction layer extended to cover process management, HTTP module enhancements). +* Made sure all Editor windows are listed in the Dock menu on Mac OS X. +* Stopped Editor windows disappearing when placed on a secondary monitor in Mac OS X Mavericks new Space per-display multi-monitor mode. +* Improvements to mouse drag handling in some Editor modes to reduce snapping & hyper-acceleration. +* Added support for opening Unreal Projects by double-clicking them on Mac OS X. +* Enabled Subversion support for Mac OS X, using Xcode's copy of Subversion. +* Implemented Mac OS X support for creating movie files in Matinee. +* Tweaked CoreAudio reverb on Mac OS X to sound more like the other implementations. +* Brought the standalone OpenGL renderer for Slate into line with the Direct3D version. +* Early support for simulator, next QA build after this will make it easy to switch between both. #### Networking -* セキュリティの改善 -* Lifetime プロパティ -* レプリケーション パフォーマンス +* Security improvements +* Lifetime properties +* Replication performance -#### Online -* オンラインのビーコンコードの安定性が向上しました。 -* もはや必要がなくなってもビーコンアクタは破壊されませんでした。 -* ビーコン コミュニケーションが潜在的に無限のアクタをスポーンする弱点を修正しました。 -* オンラインのセッション API の安全性が向上しました。 -* 「ending/ended」ステートと差別化するために、セッション API に「Destroying」ステートが追加されました。 -* 一般的なオンライン非同期タスクをクリーンアップしました (templatized functions / code reuse)。 -* オンライン インターフェースの全シェアードポインタがスレッドセーフになりました。 -* LAN による Steam への接続が正しく機能するようになりました。 -* 既存の設定キーを所有する冗長したオンライン検索キーを削除しました。 -* FOnlineKeyValuePairs データにネットワーク バイ トオーダー シリアライズ サポートを追加しました。 +#### オンライン +* Stability improvements to the online beacons code. +* Beacon actors weren't destroyed when no longer needed. +* Fixed potential exploit where beacon communication could spawn infinite actors. +* Stability improvements to the online sessions API. +* Sessions API now includes a "Destroying" state to differentiate itself from ending/ended states. +* General online async task cleanup (templatized functions / code reuse). +* All online interface shared pointers are now thread safe. +* Steam with LAN should now work properly. +* Removed redundant online search keys that have existing online setting keys. +* Added network byte order serialization support for FOnlineKeyValuePairs data. * Mcp OSS - * mcp アカウントマッピングテストを追加しました。 - * "QUERYMAPPINGS " 経由の exec - * Mcp コンフィグを組み込みソースファイルへリファクタリングしました。 - * 開発に「defaultengine.ini」ファイルの ini 値をまだ使用することも出来ます。 - * ゲームはコールバックデリゲートを使用してコンフィギュレーションをオーバーライドすることができます。 + * Added mcp account mapping tests. + * Exec via "QUERYMAPPINGS " + * Refactored Mcp configs into embedded source files. + * Can also still use ini values in defaultengine.ini for development. + * Games can override configurations using a callback delegate. * Http -* 要求された completion デリゲートがトリガーされた後に http request ポインタが破壊される問題を修正しました。 - * teh completion デリゲートから同リクエストを繰り返し再利用出来ないことによる、http リクエストのチェーンの破損がありました。 +* Fixed http request pointer being destroyed after request completion delegate was triggered. + * This had broken "chaining" of http requests by not being able to re-use the same request over and over from teh completion delegate. ## 既知の問題 -* パフォーマンスキャプチャテストに表示される警告 -* インポートした「.APB」被破壊性メッシュをフラクチャ (破砕) すると、期待以上の数のフラクチャが発生します。 -* FOLIAGE (フォリッジ):可視化出来るブラシはありません。 -* ウィジェットでスケーリングすると 0 で停止してこの値に留まります。 -* ELEMENTAL(エレメンタル):断崖のマテリアルが黒で表示されます。 +* Warnings on Performance Capture test. +* Fracturing an imported .APB destructible mesh causes more than expected number of fractures. +* FOLIAGE:No visible brush. +* Scaling with the widget stops and sticks at zero. +* ELEMENTAL:Materials on cliff are showing up as black. * Error Failed import:EdGraph /Engine/EditorBlueprintResources/StandardMacros.StandardMacros:Do N -* PLATFORMERGAME:プレイヤーがゲームの途中に差し掛かると、 2 番目のエレベーターがジャンプします。 -* QAGAME:CRASH:「TraceTest.umap」を開きます。 -* SHOOTERGAME:Bot AIが原因で、敵はある期間中に武器を発砲することなく逃げ回ったり静止することができます。 -* SHOOTERGAME:ENSURE:botsと共にマッチを開始します。 -* XboxOne:全てのTextRenderActorsにアーティファクトが生じています。 -* ROCKET:Mac:Xcode:「Game.app」ファイルを起動することができません。 -* ROCKET:Mac:CONTENT EXAMPLES:Blueprint_HUD上のマップの外側にスポーンします。 +* PLATFORMERGAME:2nd elevator jumps when player is halfway through it. +* QAGAME:CRASH:Opening TraceTest.umap +* SHOOTERGAME:Bot AI is causing enemies to run around without firing or stand still for periods of time. +* SHOOTERGAME:ENSURE:Starting a match with bots. +* XboxOne:All TextRenderActors are artifacting. +* ROCKET:Mac:Xcode:Unable to launch Game.app +* ROCKET:Mac:CONTENT EXAMPLES:Spawn outside map on Blueprint_HUD. diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/Dec/ReleaseNotesDecember2013.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/Dec/ReleaseNotesDecember2013.KOR.udn index 48027e475978..5aa9b9885fd7 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/Dec/ReleaseNotesDecember2013.KOR.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/Dec/ReleaseNotesDecember2013.KOR.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3367470 Title: December 2013 Release Notes Crumbs:%ROOT%, Support/Builds Description: Availability:Licensee -Template:ReleaseNotes.html +Parent:Support/Builds +Order:-3 과거 빌드에 대한 번역문은 제공하지 않습니다. diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/July/ReleaseNotesJuly2013.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/July/ReleaseNotesJuly2013.JPN.udn index 1dc680582883..575f4b3f6dc2 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/July/ReleaseNotesJuly2013.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/July/ReleaseNotesJuly2013.JPN.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:2615122 +INTSourceChangelist:3367470 Title:2013 年 7 月リリースノート Crumbs:%ROOT%, Support/Builds Description: Availability:Licensee -Template:ReleaseNotes.html +Parent:Support/Builds +Order:-7 [TOC(start:2 end:2)] @@ -16,7 +17,7 @@ Template:ReleaseNotes.html | **ラベル** | QA_APPROVED_UE4_BUILD_2013_07 | | **チェンジリスト #** | 1735924 | | **VISUAL STUDIO VERSION** | Microsoft Visual Studio 2010 version 10.0.40219.1 SP1 Rel | -| **DIRECTX** | 2010年6月 | +| **DIRECTX** | June 2010 | [/REGION] ## 重要情報 @@ -27,7 +28,7 @@ Template:ReleaseNotes.html * 周知のバグ: [UE4 Outstanding Bugs July 2013](UE4_Bugs_2013_July.xlsx) -## 主な新機能 +## 主要な新機能 ####エディタ ツール * **プラグイン エディタ** @@ -59,7 +60,7 @@ Template:ReleaseNotes.html ####ブループリント * ブループリントが何も値を返さない関数を呼び出した場合、呼び出しが無効のターゲットであれば 'Access None' ログが生成されなくなりました。 -* ブループリントのデバッグ処理が改善されました (実行シーケンスがデバッグ可能になり、非純粋関数のブレークポイントで再発したバグが修正されました)。 +* ブループリントのデバッグ処理が改善されました (実行シーケンスがデバッグ可能になり、 非純粋関数のブレークポイントで再発したバグが修正されました)。 * ブループリントの親の変更をすると、ブループリントから新たに警告が出されるようになりました。 * Level ブループリントまたはアクタのブループリントからの参照状態を表示してユーザーが対処できるように、アクタの削除時のチェックを追加しました。 * グラフの種類を区別してレンダリングを簡素化するために、ブループリント エディタにアイコンが追加されました。 @@ -142,7 +143,7 @@ Template:ReleaseNotes.html * デフォルトの FFastVRAMAllocator クラスを追加しました (デフォルト状態では何もしません)。 -####レンダリング +#### レンダリング * プリミティブのユニフォーム バッファに、ローカル空間領域が含まれるようになりました。 * マテリアル システムがローカル空間領域へアクセスできるように、 **ObjectLocalBounds** エンジン マテリアル関数を追加しました。 * **Alpha** の新しい Texture 圧縮タイプを追加しました。(単一チャンネルです。ガンマ補正ではありません。) @@ -158,7 +159,7 @@ Template:ReleaseNotes.html ####アニメーション / ペルソナ -* Animation ブループリント、 モンタージュ、 ブレンドスペース、AnimOffset アセットを、コンテンツ ブラウザのコンテクストメニューを使って、スケルタルメッシュから直接作成できるようになりました。 +* Animation ブループリント、 モンタージュ、 ブレンドスペース、AnimOffset アセットを、コンテンツ ブラウザのコンテキストメニューを使って、スケルタルメッシュから直接作成できるようになりました。 * AnimGraph で Export to Animation 機能がサポートされるようになりました。 * 現在の anim graph をアニメーションへエクスポートできます (下体 / 上体の分割またはスプリングの場合に便利です)。 * スタティック メッシュ エディタでソケットを複製することができます。 @@ -171,287 +172,287 @@ Template:ReleaseNotes.html ##アップグレード ノート ####ブループリント -* ブループリントの継承 (ブループリントのブループリント) が正式に有効になりました!ブループリントの新規作成時にクラスブラウザで親クラスを選択するか、コンテンツ ブラウザでブループリントをクリックするか、[Create child of this blueprint...] を選択することで、ブループリントのブループリントを作成することができるようになりました。 -* ブループリントが TWeakObjectPtrs を適切にサポートするようになり、それらをパラメータとして使っている UFUNCTIONS を安全に実行できるようになりました。 -* リファレンス変数でブループリントを設定できるようにしました。値を内部的に手書きのコードで操作する必要のあるパラメータをリファレンスでパスする関数に便利です。 -* Creating ブループリントのアセットツリーにスクロールバーを追加しました。 -* VimBlueprint を AnimBlueprint に、 VimInstance を AnimInstance に名前変更しました。変数名 / コメントをアップデートして、"Vim" という単語の削除を反映しました。 +* Blueprint inheritance (blueprints of blueprints) has been officially enabled!You will now be able to create a blueprint of a blueprint, either by selecting the parent class in the class browser when creating a new blueprint, or by right clicking on a blueprint in the Content Browser, and selecting "Create child of this blueprint..." +* Blueprints now properly support TWeakObjectPtrs, and UFUNCTIONS that use them as parameters are now safe for execution +* Blueprints can now set by-reference variables.This is useful for functions that pass parameters by reference that need to manually manipulate the value of those parameters internally +* Scrollbar added to the asset tree for Creating Blueprints +* Renamed VimBlueprint to AnimBlueprint and VimInstance to AnimInstance.Updated variable names/comments to reflect removal of word "Vim" #### サウンド -* 新しい Sound クラス エディタを作成しました - すべての SoundClass の親が必ず 1 つになるように、すべての SoundClass を取り込んで再度保存することをお勧めします。 - * 複数の親を持つ SoundClass が取り込まれると、強制的に親を 1 つにする前に、ログの警告が生成されます。 - * 親はアルファベット順に処理されて希望と違ってしまう場合があるので、この警告を使って SoundClass の親が希望通りになっていることを確認します。 - * 新しいエディタは SoundClass の位置を保存しません。エディタが開かれるたびに、自動的に調整されます。 -* SoundCue アクタに Find in Content Browser オプションを付けました。 +* Created new Sound Class editor - it's advised that all SoundClasses are loaded and re-saved to ensure that all SoundClasses will only have a single parent + * Log Warnings are generated for any loaded SoundClasses that have multiple parents, before they are forced to have a single parent + * Use these warnings to make sure that SoundClasses have the desired parent, as they will just be processed in alphabetical order and may not be what you expect + * The new editor does not save the positioning of SoundClasses, they are arranged automatically every time one is opened in the editor +* SoundCue actor now has Find in Content Browser option ####コア -* FString をリファクタリングしました。 -* FString が TArray から継承されなくなりました。 -* `InStr` を `Find()` に変更し、 `Contains()` を追加しました ( **注記:パラメータとそのデフォルトを変更しました!** ) -* Split 関数のパラメータを変更しました。 -* EndsWith、StartsWith、Replace、ReplaceInline、MatchesWildcard が ESearchCase を bool の代わりに第二引数として受け取るようになりました。 -* 文字列関数のデフォルト ビヘイビアを、大文字小文字の区別を無視するように変更しました。 -* FFilename 関数をすべて FPaths に移動し、静的にしました。文字列で直接機能するようになりました。 -* FFilename タイプを削除しました。 -* パラメータを 5 つまでオーバーロードして FPaths::Combine() を追加しました。 -* パス結合演算子の `*` と `*=` を `/` と `/=` にそれぞれ変更しました。 -* FPaths を CoreMisc.h/.cpp から Paths.h/.cpp へ移動しました。 -* USTRUCT は UFUNCTION を含むことができなくなりました。 -* `TPreallocatedArray` を削除しました。代わりに `TArray >` を使用してください。 -* `FQuat::operator-` は、実装が非直感的なため、削除しました。ライセンシーは既存の全てのリファレンスを、同等の `FQuat::Inverse()` に変更する必要があります。 -* TemplateMapMetadata アセット タイプを非推奨にしました。 - * テンプレート マップは DefaultEngine.ini (例は BaseEngine.ini を参照) の `[/Script/UnrealEd.UnrealEdEngine]` セクションで設定するようになりました。 - * ゲームに TemplateMapMetadata アセットがある場合、 コンテンツ ブラウザでテキスト フィルタを使って検索し削除します。 -* CurveEdPresetCurve アセット タイプを非推奨にしました。 - * ゲームにこのアセットのインスタンスがある場合、コンテンツ ブラウザでテキスト フィルタを使って検索し削除します。 -* プラグインは取り込む前に有効にしておく必要があります。DefaultGame.ini ファイルの `[Plugins]` セクションの EnabledPlugins リストに追加すると、プラグインが有効になります。 -* TContainerTraits を TTypeTraits に変更しました。 - * 理由は、 TTypeTraits はコンテナ エレメントの trait を表現し、コンテナの trait を表現する TContainerTraits という新しい trait があるからです。 - * TContainerTraits を指定するタイプがあれば、 TTypeTraits を指定するように変更しなければなりません。 - * **NeedsConstructor** trait は **NeedsMoveConstructor** と区別するために、 **NeedsCopyConstructor** に変更しました。 +* FString has been refactored +* FString does not inherit from TArray any more +* `InStr` has been replaced by `Find()` and `Contains()` has been added ( **NOTE:Parameters and their defaults have changed!!!** ) +* Parameters of Split function changed +* EndsWith, StartsWith, Replace, ReplaceInline and MatchesWildcard take a ESearchCase as second argument instead of a bool now +* Changed the default behavior of string functions to ignore case +* Moved all FFilename functions to FPaths and made them static.They work directly on strings now +* Removed FFilename type +* Added FPaths::Combine() with overloads for up to 5 parameters +* Replaced path concatenation operator `*` and `*=` with `/` and `/=` +* Moved FPaths from CoreMisc.h/.cpp to Paths.h/.cpp +* USTRUCTs are no longer allowed to contain UFUNCTIONs +* `TPreallocatedArray` has been removed as dangerous. `TArray >` should be used instead +* `FQuat::operator-` has been removed as its implementation was unintuitive.Licensees will need to change all existing references to `FQuat::Inverse()` which is equivalent +* Deprecated the TemplateMapMetadata asset type + * Template maps are now configured in the `[/Script/UnrealEd.UnrealEdEngine]` section of DefaultEngine.ini (see BaseEngine.ini for an example) + * If your game has any TemplateMapMetadata assets, use the text filter in the content browser to find and remove them +* Deprecated CurveEdPresetCurve asset type + * If any instances of this asset are in your game, use the text filter in the content browser to find and remove them +* Plugins now must be enabled before they are loaded.To enable a plugin, add it to the EnabledPlugins list in the `[Plugins]` section of your DefaultGame.ini file +* TContainerTraits has been renamed to TTypeTraits + * This is because there is a new TContainerTraits traits class which represents the traits of containers, whereas TTypeTraits represents the traits of container elements + * If you have any TContainerTraits specializations of your own types, you should change these to specialize TTypeTraits instead + * The **NeedsConstructor** trait is now called **NeedsCopyConstructor** to distinguish it from **NeedsMoveConstructor** ####エディタ ツール * **エディタ** - * CalcCamera のシグネチャ、その他内部カメラ手法の幾つかを変更しました (緩い変数ではなく FMinimalViewInfo struct の使用への切り替え、など)。 - * ビットフィールドの GET_MEMBER_NAME_CHECKED へのサポートを追加しました。 - * 拡張性の改善点 - * カスタム ノード ファクトリに加えて、カスタム ピン ファクトリも登録できるようになりました。 - * UWorld ライフサイクル デリゲートを追加しました。 - * バーチャルの APlayerController::GetAudioListenerPosition を追加しました。 - * 初めて追加された時に、Matinee カーブ トラックが正しく表示されるようになりました。 - * [Check Out Assets (アセットをチェックアウトする)] ウィンドウが表示されると、[Check Out Selected (選択項目をチェックアウト)] ボタンがフォーカスされ、[Enter] を押すとそのオプションが選択されます。 - * Matinee keyframe Set Time のアンドゥ / リドゥが可能になりました。 - * [Level Editor (レベル エディタ)] ウィジェットで、オブジェクトの負のスケーリングができるようになりました。 - * [Level Editor (レベル エディタ)] ウィジェットでオブジェクトをスケールあるいは回転する際に、カーソルが最初の位置にリストアされるようになりました。 - * Streaming Volumes のメニュー オプションを、[Levels] メニューの [Levels] セクションのサブメニューに移動しました。 - * パッケージ保存エラー時に出るエラー メッセージを改善しました。 - * マチネ グループでアクタを選択すると、シーン アウトライナーのアクタが選択されるようになりました。 - * そのタイプのプロパティをもたないアクタにマチネ トラックを追加しようとすると、エラー メッセージが表示されるようになりました。 - * シーン アウトライナー上に Actors Component Mobility 変数の 2 つ目のアイコンが表示されます。 + * The signature of CalcCamera and some other internal camera methods has changed (switching over to use the FMinimalViewInfo struct instead of loose variables, etc...) + * Added support to GET_MEMBER_NAME_CHECKED for bitfields + * Extensibility improvements: + * Made it possible to register a custom pin factory in addition to a custom node factory + * Added UWorld lifecycle delegates + * Added a virtual APlayerController::GetAudioListenerPosition + * Matinee curve track now displays correctly when first added + * When the Check Out Assets windows appears, the Check Out Selected button is now is focus and pressing enter will select that option + * Undo/Redo for Matinee keyframe Set Time + * Level Editor widget now allows negative scaling of an object + * Cursor is restored to its initial position when scaling or rotating an object with the Level Editor widget + * Streaming Volumes menu options moved to a sub-menu within the Levels section of the Levels menu + * Improved error message when a package fails to save + * Selecting the Actor in the Matinee group now selects the actor in the Scene Outliner + * An error message is now displayed when attempting to add a Matinee track for an actor that has no properties of that type + * Scene Outliner now displays a second icon for the Actors Component Mobility variable * **ランドスケープ** - * Retopologize tool + XYOffset が有効になりました。 - * PhysX データを LandscapeMeshCollision コンポーネントに追加しました。 + * Enabled Retopologize tool + XYOffset + * Added cooked PhysX data to LandscapeMeshCollision component ####ゲームプレイとフレームワーク -* **短い名前のパッケージのサポートが ini ファイルから削除されました。セクション名も該当します。** - * つまり、 `[Engine.GameEngine]` などのクラス セクション名は `[/Script/Engine.GameEngine]` に変更する必要があります。 -* AEnvironmentVolume を削除しました。 -* コンポーネントごとではなくバインディングごとに入力を消費するかどうかを、入力バインディングで指定できるようになりました。ConsumeNone/Bound/All を持つコンポーネントの代わりに、それぞれのバインディングがその入力を消費し、後続のコンポーネントが入力を受け取らないようにブロックすることを示す boolean bBlocksInput をコンポーネントが持つかどうかを指定するbConsumesInput boolean を持つようになりました。 -* FGameWidgetWorldContext を FGameWorldContext に名前変更しました。 -* 各種 MovementComponents の名前を命名規則と一致するように変更しました。 +* **Support for short package names has been removed from ini files, this includes section names** + * This means that class sections like `[Engine.GameEngine]` will now have to be renamed to `[/Script/Engine.GameEngine]` +* AEnvironmentVolume has been removed +* Input bindings now specify whether the input should been consumed per binding instead of per component.Instead of the component having ConsumeNone/Bound/All each binding now has a bConsumesInput boolean specifying if it consumes that input and the component has a boolean bBlocksInput indicating that it blocks subsequent components from receiving input (equivalent to ConsumeAll previously) +* FGameWidgetWorldContext renamed to FGameWorldContext +* Renamed various MovementComponents to match naming conventions: * Character * Rotating * Projectile * Vehicle * Shooter -* (UNavigationSystem から派生した) カスタムナビゲーション システムクラスを定義するゲーム専用オプションを実装しました。 +* Introduced an option for game-specific code to define custom navigation system class (derived from UNavigationSystem) * **Collision Profile Refactor** - * ECC_WorldTrace はなくなりましたので、固定ジオメトリを探す場合は ECC_Static を使ってください (Movement チャンネルは ECC_Static なので、Mobility は Movable ではありません)。 - * グローバル デフォルトは、コードと INI ファイルで定義されます。グローバル デフォルトは、すべてがブロックされるわけではなくなりました。 - * デフォルト応答が含まれるように、デフォルト チャンネルの記法の定義を変更しました (グローバル デフォルト)。 - + * ECC_WorldTrace is gone, use ECC_Static if you're looking for stationary geometry (Movement channel is ECC_Static and Mobility is not Movable) + * Global default is defined via code and INI file.Global default isn't all block anymore + * Changed syntax of default channel define to include default response (global default) +CustomTraceChannel=(Channel=GameTraceChannel1, Name=Interact, Response=Ignore) - * プロファイル定義から DefaultResponse を削除しましたた。ただし、グローバル デフォルトから開始します。 - * CollisionResponse データ構造を変更して、グローバル デフォルトから修正されたチャンネルのみ利用できるようにしました (これは CDO 値ではなく、グローバル デフォルトであることに注意してください)。 - * まだまだ変更はあります! -* **UPhysicalMaterialProperty を非推奨にしました**。PhysicalMaterial に DEFAULT.INI で変更できる一般的な列挙型変数値が含まれるようになりました。 - * プロジェクトごとにカスタムできる EPhysicalSurface 列挙型変数をエンジンに追加しました。 - * UPhysicalMaterialProperty とそれぞれの子クラスを非推奨にしました。 - * `DefaultEngine.INI` の例です。 + + * Removed DefaultResponse from Profile definition but it starts from global default. + * CollisionResponse data structure has changed to allow only modified channels from global default (note this isn't CDO value but global default) + * More changes are coming! +* **Deprecated UPhysicalMaterialProperty**.PhysicalMaterial now contains general enum value you can modify in DEFAULT.INI + * Engine now has EPhysicalSurface enum that can be customized by each project + * Deprecated UPhysicalMaterialProperty and every child classes + * Example in the `DefaultEngine.INI`: [PhysicalMaterial.SurfaceTypes] SurfaceType1=Asphalt SurfaceType2=Dirt SurfaceType3=Water -* MeleeRange 変数がAPawn から削除されました。ローカルのポーンで使用には、ゲームの派生クラスに入れておく必要があります。 -* **SkeletalMeshComponent の PhsyicsWeight を削除しました**。`bBlendPhysics` を使うか、または BodyInstance ごとに `PhysicsWeight` を定義します。 +* MeleeRange variable has been removed from APawn.If you're using it in your local pawns, you need to put it in the derived class for your game +* **Removed PhsyicsWeight in SkeletalMeshComponent**.Use `bBlendPhysics` or define `PhysicsWeight` for each BodyInstance -####オンライン -* Stream を参照する OnlineSubsystemLive のスペルミスを修正しました。 -* プラットフォーム レイヤーに HTTP が追加されました。 - * プラットフォームごとにそれぞれの http リクエスト / レスポンスが追加されました。 - * 未実装のプラットフォームは GenericPlatformHttp を使用していることにご注意ください。 +####Online +* Typo fixed in OnlineSubsystemLive which referenced Steam +* Brought HTTP into the platform layer: + * Each platform now has its own http request/response + * Note some platforms are not yet implemented and use GenericPlatformHttp -####レンダリング -* (レンダリング スレッド コマンドの順序で) レンダリング スレッドにプロパゲートしたステートを取得するために、新しいコンソール変数フラグ ECVF_RenderThreadSafe を作成しました。これは他のスレッドに対しては機能しません。 -* 複数のポストプロセス ボリュームを組み合わせる場合、アンビエント キューブは追加ではなく線形補間を行うようになります。 -* 今後のイタレーションに対する加算ライティング条件を削除しました。 +#### レンダリング +* Made new console variable flag ECVF_RenderThreadSafe to get the state propagated to the render thread (in order with other render thread commands), does not work for other threads +* Ambient cubes will now lerp instead of add when combining more than one post process volumes +* Removed additive lighting terms for future iteration ####プラットフォーム -* TargetType ではなく TargetRules オブジェクトを受け取るように PrepTargetForDeployment 関数を変更しました。 -* D3D11Drv を D3D11RHI に変更しました。 -* 全ての D3D11 RHI を 1 つのモジュールにまとめました。 - * WinRTRHI を削除しました。 +* Changed PrepTargetForDeployment function to take the TargetRules object rather than just the TargetType +* Renamed D3D11Drv to D3D11RHI +* Merged all D3D11 RHIs into a single module + * Deleted WinRTRHI -####アニメーションとペルソナ -* Static Mesh Editor Socket プロパティ変更に対して、アンドゥ / リドゥ操作ができるようになりました。 -* Static Mesh Editor Socket 削除に対して、元に戻す / やり直し操作ができるようになりました。 +####Animation and Persona +* Undo/Redo for Static Mesh Editor Socket property changes +* Undo/Redo for Static Mesh Editor Socket deletion ## 継続事項と改善 -#### 分析 -* エンジン分析の改善点 - * エラー レポートを改善しました。 - * 再マップされたキーバインディングをトラックします。 - * OS 言語と GPU ドライバーのバージョンをトラックします。 - * 新規作成されたブループリントをトラックします。 - * 主要なサブ エディタ ツールの動作時間をトラックします。 +####Analytics +* Engine analytics improvements: + * Improved error reporting + * Tracking which keybindings are remapped + * Tracking OS language and GPU driver version + * Tracking new blueprint class creation + * Tracking "up time" of major sub-editor tools ####ブループリント -* ブループリントのルート コンポーネントは、適用された変形を保てなくなりました。 -* ブループリント インターフェースの編集時に、新規関数を純粋関数としてマークできなくなりました。 -* [DELETE] キーを使って選択アイテムをブループリント エディタの [My Blueprint] タブから削除できるようになりました。 -* アンドゥ / リドゥ操作を続けて早く実行しても、ワークスペースをスパムしなくなりました。 -* UObject サブクラス ピンを引き出すと、IsValid ノードが正しく表示されるようになりました。 -* 派生した変数のカテゴリは変更できなくなりました。 -* ルート コンポーネントが選択されると、変形ウィジェットがブループリント コンポーネント エディタで非表示になりました。 -* 浮動小数点値表示で、連続するゼロが少なくなりました。 -* 変数の Find Instances から返された結果を見直して、関連のある結果のみが表示されるようにしました。 -* ウィンドウ メニューからアクセスすると、ブループリントの親変更メニューにタイトルが追加されるようにしました。 -* 引き出したピンを変数に昇格させるオプションを追加しました。 +* The root component in a blueprint can no longer have a transform applied to it +* New functions can no longer be marked pure when editing Blueprint interfaces +* The DELETE key can now be used to remove selected items from the My Blueprint tab in the Blueprint editor +* Performing undo/redo actions in rapid succession no longer spams the workspace with notification pop-ups +* IsValid node will correctly appear when dragging off a UObject subclass pin +* Can no longer modify categories of variables which are inherited +* Transform widget is now hidden in the Blueprint component editor when the root component is selected +* Floating point values now show less trailing zeros +* Revised results returned from Find Instances for variables so only relevant results are shown +* Added title to the blueprint re-parent menu when accessed via the window menu +* Added an option for promote to variable for dragged pins #### サウンド -* Enveloper ノードにモジュレーション設定を追加しました。 -* コンテンツ ブラウザで右クリックしても、サウンドがポーズしなくなりました。 +* Enveloper node now has modulation settings +* Sound is no longer paused when right clicking in the content browser ####コア -* コマンドライン `AllowStdOutLogVerbosity` を追加しました。`* -Cmd.exe` を実行すると、ログレベルが詳細モード以下のログをすべて stdout に出力します。 -* Plugin Descriptor に新規の変更があります。 - * プラグイン記述子に入力フィールドを多数追加しました。(文書はまもなく更新されます!) - * プラグインに Resources サブフォルダ (Icon128.png サムネイル) を追加しました。 -* Simplygon が VS 2012 ビルドにコンパイルされます。 -* モジュールを `FModuleManager::LoadModule` 経由でロードする前に、DLL のバージョンの互換性がテストされるようになりました。 - * FindModules で発見されたモジュールは、リストへの追加前に現在のエンジンのバージョンとの互換性を確認するようにしました。 -* パスにスペースがある場合、VSAccessor がソリューション ファイル パスを開けるようになりました。 -* [New Project] ダイアログで c++ プロジェクトを作成後、エディタではなく visual studio が開くようになりました。実際に c++ プロジェクトを確実にビルドできるように、強めのテスティングを追加しました。 -* プロジェクトが自動ロードに失敗すると、エディタが正常にロードされるまで自動ロードが無効になるようにしました。 -* 新規プロジェクト ダイアログは、最初のページがテンプレート、2 ページ目が名前と位置を選択するウィザードになりました。 -* コンテンツ ブラウザ フィルタは、フィルタがアセットの表示を妨げる場合のみ、アセットとの同期時にリセットされます。 -* プロジェクトのデフォルト位置が、My Documents の直下ではなく、My Documents の中のフォルダになりました。 -* ファイルがテキスト形式でパーフォースに追加されないように、フェイルセーフ コードを追加しました。 -* サービスが利用できない場合、SCC コレクションと作用するためにコレクション エラー処理を追加しました。 -* コンテナの最適化全般 +* Added command line `AllowStdOutLogVerbosity`.This will print every log with a verbosity >= Log to stdout if you run the `* -Cmd.exe` +* New Plugin Descriptor changes + * Many new fields were added to plugin descriptors.(Documentation update coming soon!) + * Plugins can now have a Resources sub-folder (for Icon128.png thumbnail) +* Simplygon now compiles into VS 2012 builds +* DLL Version compatibility is now tested before any module is loaded via `FModuleManager::LoadModule` + * Modules that are discovered in FindModules are now checked for compatibility with the current engine version before they are added to the list +* The VSAccessor can now open solution file paths where there is a space in the path +* After creating a c++ project with the "New Project" dialog, visual studio will open instead of the editor.Also added some stronger testing to make sure you can actually build a c++ project +* When a project fails to auto-load, auto loading is now disabled until the editor is successfully loaded again +* The new project dialog is now a wizard where the first page is selecting a template and the second page is the name and location +* Content Browser filters reset when syncing to an asset only if the filters would prevent that asset from being displayed +* The default location for a project is now in a folder inside of My Documents instead of directly in My Documents +* Added some failsafe code to prevent UAsset files from being added to perforce in text format +* Added collection error handling for working with SCC collections when the server is not available +* General container optimizations ####エディタ ツール * **スレートと UI** - * スレート スタイル システムを改良中です。 + * Working on improving the Slate style system * **エディタ** - * Play in Editor セッションと Simulate セッションの起動パフォーマンスを改善しました。 - * フレームレートが許容範囲内の場合を除き、ほとんどのメニューとツールチップ アニメーションをスキップするようにしました。 - * PIE/SIE モードの時は、シーン アウトライナーのボーダーとパディングを取り除きました。 - * カラーピッカーのスポイトツール マウスポインタは、アクティブになるとピッカー ウィンドウ外に表示されるようになりました。 - * [PromptForCheckoutAndSave] ウィンドウは、ユーザーにチェックされていないパッケージを記憶します。 - * エントリにアイコンが付くように、Consolidate ウィンドウを適切なラジオボタン スタイルに合わせました。 - * ラジオボタンのアイコンとスタイルをアップデートしました。 - * 変更の計算とテクスチャへのペイントにかかる時間を短縮して、メッシュペイントのパフォーマンスを改善しました。 - * **Select Actors Using This Asset** を使う場合、アセットがアクタの親ではなく実際のオーナーに対して確実にトラックされるようにしました。 - * ポップアップ メニューがアクティブの間、自動保存通知と機能はサスペンドとなります。 - * 列挙型変数名をリストの終わりに一致させずにエントリをソートすることで、Property Matrix のフォールト トレランスを強化しました。 - * Property Matrix テーブルのソートを変更して、列挙型変数名をバイト数値ではなくアルファベットで比較できるようにしました。 - * 1-3 の間でバラバラだったカメラ速度を均一にして、小さめのジャンプは 4->3 、大きめは 2->3 としました。 - * 名前変更の際に選択を維持できるようにシーン アウトライナーを変更し、強調表示の問題を解決するために完全にフォーカスに従うように名前編集ボックスを変更しました。 - * アクタの追加後など、ビュー全体をリフレッシュする場合、最後の選択までスクロールするようにシーン アウトライナーを変更しました。 - * Select Actors が選択肢に追加されるのではなく置換されることを記述するためにツールチップを変更しました。 - * FBX インポート オプションで、インポート時にアセットを保存し再度使用できるようになりました。この機能は、スタティックメッシュ、スケルタルメッシュ、アニメーション シーケンスが対象です。 - * コンテンツ ブラウザの [New] メニューの大きさが、画面の高さの半分以上にならないようにしました。 - * アクタを変換しても、アクタのラベルが変更されなくなりました。 - * マップ ファイル エラーの内容を原因に関連した説明にしました。 - * エクスポート ダイアログをユーザーに提示する場合、FBX が最初のオプションとしてリストされるようになりました (適用可能な場合)。 - * 複数のアセット プロパティをマージして表示する場合、RowName が強制的に修正されなくなりました。 - * カテゴリが選択されると、変数 Category ComboBox が自動的に閉じます。 - * シーン アウトライナーが開くと、(レベル内で) 選択されたアクタが (リストで) 選択されるようになりました。 - * 終了ダイアログ抑制フラグが、依存しない config に保存されるようになりました。 - * アセット命名エラー メッセージがより正確になりました。 - * ユーザーの検索条件とアクションがより正確に一致するように、GenerateFilteredItems を修正しました。 - * Create Destructible Mesh が故障の可能性を防ぐようになりました。 - * 保存内容に応じてマップまたはアセットを参照するように、パッケージ保存エラーを修正しました。 - * タイトルバーの下の部分で、移動を選択できるようになりました。 - * Editors Windows リストがアルファベット順になりました。 - * 無効なインデックス チェックをさらに防ぎました。 - * 'exists in package' となっている箇所を 'exists in file' に変更しました。 - * エディタの URL がデータドリブンになりました。 - * 選択したアクタを移動するコードは、選択されたアクタがあることを想定しなくなりました。 - * アクタが NULL かどうかをリスト追加前に GetAttachedActors がチェックするようになりました。 + * Improved performance of starting up Play in Editor and Simulate sessions + * Most menu and tool-tip animations are now skipped except when framerate is acceptable + * Removed Scene Outliners border padding when in PIE/SIE mode + * Color picker's eye-dropper mouse pointer is now shown outside the picker window when active + * PromptForCheckoutAndSave window remembers which packages were unchecked by the user + * Point the Consolidate window at the proper radio button style so entries get icons + * Updated the radio button icons & styles + * Improved mesh painting performance by reducing time spent calculating the changes and painting into the texture + * When using **Select Actors Using This Asset** made sure assets are tracked to their actual owner, not the parent of the Actor + * Suspend the autosave notification & feature while a popup menu is active + * Made Property Matrix more fault tolerant by sorting entries without a matching enum name to the end of the list + * Changed the sort in the Property Matrix table to compare enum names alphabetically rather than by byte values + * Evened out difference between camera speeds 1-3 to provide a smaller jump 4->3 and larger between 2->3 + * Changed the Scene Outliner to maintain selection when renaming & changed the name edit box changed to fully surrender focus to stop highlighting glitches + * Changed the Scene Outliner to scroll to last selection when fully refreshing the view e.g. after adding an actor + * Changed the tooltip to state Select Actors will replace the selection not append to it + * FBX import options are now saved with the asset and reused when importing.This applies to static meshes, skeletal meshes, and animation sequences + * The Content Browser "New" menu can no longer be larger than half the screen height + * Converting actors will no longer re-label the actor + * Map file errors are now a lot more descriptive as to the reason for failure + * FBX is now listed as the first option (if applicable) when presenting the export dialog to the user + * RowName no longer gets forcefully modified if multiple assets properties are shown merged + * Variables Category ComboBox is automatically closed when a category is selected + * Scene Outliner now selects (in the list) those actors who are selected (in the level) when opened + * Quit dialog surpressed flag is now saved to the agnostic config + * Asset naming error messages are now more accurate + * Modified GenerateFilteredItems to be more accurate with regard to matching the users search term with an action + * Create Destructible Mesh now guards against the the possibility of failure + * Modified save package errors so that they refer to either a map or asset depending on what was saved + * Lower area of the title bar is now selectable for movement + * Editors Windows list is now listed alphabetically + * Additional guards against invalid index checks + * Replaced occurrences of 'exists in package' with 'exists in file' + * Editor URLs are now data driven + * Move selected actors code no longer assumes that there are any selected actors + * GetAttachedActors now checks to see if an actor was NULL before adding it to the list -* **ワールド ブラウザ** - * レベル間の親 -> 子の関係を追加しました。 - * ワールドのレベル位置が親レベルと相対的な位置に保存されます。 - * リストとフォルダのビューが、レベル階層ビューに変更されました。 - * 距離に基いたレベル ストリーミングを追加しました。 - * ストリーミング距離をワールド レイヤーごとに指定できるようになりました。 - * 指定されたワールド位置から見えるかもしれないストリーミング レベルのプレビュー (強調表示) を追加しました (**Alt + MousePosition**)。 - * ポストロード時ではなく、レベルがワールドに追加された時にレベル位置が発生するようになりました。 - * レベルがワールドの基点からある程度距離があると、強制ロードはされずに非表示 (shelved) となります。ワールド基点にある程度近い場合、自動的に表示 (unshelved) されます。 - * レベルに AlwaysLoadedLevel タグを追加しました。タグが追加されたレベルは、ユーザーがエディタでワールドを開くと自動的にロードされます。 - * 親->子の関係を使って、デモコンテンツ ワールドを再構成しました。 - * 編集不可能なレベルを持つタイルは、無効ステート (グレーアウト) で表示されます。 - * 階層ビューでのドラッグ&ドロップ操作でストリーミング レベルを追加 / 削除する機能を追加しました。 - * ゲーム内でワールド合成を開く機能を追加しました (`/Game/Maps/MyWorldRoot?worldcomposition`)。 - * ワールド合成を、エディタにロードするデフォルト マップとして指定する機能を追加しました。 - * 矢印キーでレベルを移動する機能を追加しました。 - * ワールド基点の移動が SIE でも機能するようになりました。 - * エディタの環境設定の WorldBrowser を有効 / 無効した後、エディタを再起動しなくても変更が反映されるようになりました。 +* **World Browser** + * Added parent->child relationships between levels + * Level position in the world stored relative to the parent level + * List and folders view was replaced with levels hierarchy view + * Added distance based level streaming + * Streaming distance can be specified for each world layer + * Added preview(highlight) of potentially visible streaming levels from a specified world position (**Alt + MousePosition**) + * Levels positioning now happen at point when level is added to the world instead of post loading stage + * Levels which are far enough from the world origin get hidden(shelved) instead of forcibly unloaded and automatically shown (unshelved) when close enough to the world origin + * Added AlwaysLoadedLevel tag for levels.Tagged levels are automatically loaded when user opens a world in the editor + * Recomposed demolet world using parent->child relationships + * Tiles with non-editable levels will be shown in disabled state (grey out) + * Added ability to add/remove streaming levels by drag and drop operations in hierarchy view + * Added ability to open a world composition in the game (`/Game/Maps/MyWorldRoot?worldcomposition`) + * Added ability to specify a world composition as a default map to load in the editor + * Added ability to move levels by arrow keys + * World origin shifting now works in SIE too + * Enabling/disabling WorldBrowser in editor preferences does not require editor restart to take effect -* **レベル ストリーミング** - * `UWorld::UpdateLevelStreaming` が、永続的なワールドおよび表示される全てのストリームインレベルで、ストリーミング オブジェクトが更新されるようになりました。 - * 同じレベルを参照するストリーミング オブジェクトを複数持つことができるようになりました。 - * すべてのストリーミング オブジェクトのコマンドが / 非表示となっている場合のみ、レベルはアンロード / 非表示にされます。 +* **Level Streaming** + * `UWorld::UpdateLevelStreaming` now updates streaming objects in the persistent world and in all visible streamed-in levels. + * Now it is possible to have several streaming objects referring the same level + * Level gets unloaded/hidden only if all referring streaming objects command to unload/hide it * **ランドスケープ** - * コンパイルを終了するマテリアルのコールバックを追加しました。ランドスケープ エディタ モードとランドスケープ レイヤー サムネイル コードでシェーダー マップ ポインタをテストする代わりにこれを使用します。 - * Landscape NavMesh 生成を最適化しました。 - * 新規ランドスケープ グリッドとグラウンド フロア パネルと Z-fighting しないように、Perspective ビューポートのエディタ グリッドへオフセットを追加しました。 + * Added callback for a material finishing compiling and use it instead of testing the shader map pointer in the landscape editor mode and landscape layer thumbnails code + * Optimized Landscape NavMesh generation + * Added an offset to the editor grid in the perspective viewport to prevent it Z-fighting with the New Landscape grid and ground floor planes * **プロファイラ** ####ゲームプレイとフレームワーク * **物理** - * PhAT コンテクスト メニューを整頓しました - 単一のボディに対して追加されたオプションを解除し削除しました。 - * ワールド オプションを **bShouldSimulatePhysics** に追加しました- このオプションは有効化 / 無効化することができます。 - * シミュレーション許容制限を公開しました。 - * エディタ レベル ビューポートにデフォルトで StaticMeshComponent 、SkeletalMeshComponent 、BrushComponent に対するコリジョンが付きました。 - * デフォルトで "Query Only" コリジョンを有効にします。 + * PhAT context menu for bodies tidied up - unfix and delete options added for single bodies + * Added World option to **bShouldSimulatePhysics** - you can enable/disable using this option + * Exposed simulation tolerance values + * Editor level viewport has collision on by default for StaticMeshComponent, SkeletalMeshComponent, BrushComponent + * By default it enables "Query Only" collision -* **最適化** - * コンポーネント アタッチの最適化:**UseAttachParentBound** +* **Optimization** + * Component Attach optimization:**UseAttachParentBound** -* 配列は、ロードされた順番通りに config へ保存されるようになりました。 -* スプライト コンポーネントを ALight アクタから ULightComponent へ移動しました。 +* Arrays now saved to the config in the same order that they were loaded +* Moved sprite components from ALight actors into ULightComponent -####オンライン -* GameCenter OnlineSubsystem のスタブ モジュールを追加しました。 -* Facebook OnlineSubsystem のスタブ モジュールを追加しました。 +####Online +* Added the stub module for GameCenter OnlineSubsystem +* Added the stub module for Facebook OnlineSubsystem -####レンダリング -* GPU スプライトがエミッタの基点と回転を構成するようになりました。 -* テクスチャ プレビュー ツールは、正しいアスペクト比でアンラップされたキューブ テクスチャを表示します。 -* ライトマップ オーバーラップに対する Lightmass の耐性を強化しました。エラーの報告を行うのは、許容値の 1% を超えなければなりません。 -* フォグは正投影カメラでのビューではレンダリングされません。 -* テクスチャ プレビュー ツールは HDR テクスチャをクランプしなくなりました。露出制御で HDR の詳細が明らかになりました。 -* DX11 の RHIReadSurfaceFloatData のメモリ要件を 8x だけ減らしました。 -* 指向性ライトの幾つかのプロパティ名を変更して、より明確にしました。 -* 動的と静的の間のフェードを調整するために、カスケード シャドウ マップの設定をエクスポーズ / 名称変更しました。 -* MSAA テクスチャの **VisualizeTexture** サポートを追加しました。 -* ゲームにおけるポーズが MotionBlur を適切にポーズします (MotionBlur 品質の操作に便利です)。 -* SystemSettings のうち、以下をコンソール変数としてエクスポーズしました。 +#### レンダリング +* GPU sprites now account for emitter origin and rotation +* Texture preview tool displays unwrapped cube textures with correct aspect ratio +* Made Lightmass more tolerant of lightmap overlaps.A tolerance of 1% must be exceeded before it reports an error +* Fog is not rendered in views with an orthographic camera +* Texture preview tool no longer clamps HDR textures.Exposure control now reveals HDR detail +* Reduced memory requirements of DX11's RHIReadSurfaceFloatData by a factor of 8x +* Renamed some properties in directional light to be more clear +* Exposed/renamed settings for cascade shadow maps to tweak fading between dynamic and static +* Added **VisualizeTexture** support for MSAA textures +* Pause in game is now pausing MotionBlur properly (useful for working on MotionBlur quality) +* Some SystemSettings have now been exposed as console variables: * `r.UseVSync` * `r.MaxAnisotropy` * `r.MaxShadowResolution` @@ -459,35 +460,35 @@ Template:ReleaseNotes.html * `r.SkeletalMeshLODBias` * `r.TranslucencyLightingVolumeDim` * `r.DetailMode` -* `r.UseTextureStreaming`(注記: `r.TextureStreaming` に変更されました) も導入され、ランタイム時におけるテクスチャ ストリーミングの切り替えが可能になりました。 -* ライトマップ ミップマップ生成を改善しました。 -* **bFlipGreenChannel** が、再インポートまたはオーバーライト中に、設定はそのままでテキスト上に保存されるようになりました。 -* Material Expressions Clamp での **ClampMin and ClampMax** の使用を交換しました。 - * **注記:** 'Clamp' ノードが CL 1672610 (03/06/2013) と 1706681 (25/06/2013) の間に変更されたマテリアルはすべて確認が必要です。ClampMin 値と ClampMax 値は初期のチェンジリストでは交換されていますが、前から存在していたアセットは最近までこれに対して注意されていませんでした。 +* `r.UseTextureStreaming`(Note: got renamed to `r.TextureStreaming`) has also been introduced and texture streaming is now toggleable at runtime +* Improved lightmap mipmap generation +* **bFlipGreenChannel** is now preserved on textures during re-import or overwrite while keeping settings +* **Swapped ClampMin and ClampMax** usage in Material Expressions Clamp + * **Note:** Any Materials whose 'Clamp' node was modified between CL 1672610 (03/06/2013) and 1706681 (25/06/2013) will need verifying as the ClampMin and ClampMax values were swapped in the earlier changelist, but pre-existing assets weren't guarded against this until the latter ####プラットフォーム -* クックされたプラットフォームは、バイナリが GameAgnosticExe でない場合、 (個別) プロジェクトベースで実行することができません。 - * 理由は、ゲームがデフォルト クラス (QAGameInfo など) をオーバーライドする可能性があり、アセットを参照しているこれらのクラスがプロジェクト ファイルで使用できなくなってしまうからです。 +* Cooked platforms cannot run project-based (other than themselves) if the binaries is not a GameAgnosticExe + * This is due to the game potential overriding default classes (ie QAGameInfo) and those classes referencing assets not available to the project file * Freetype2 update (2.4.12) -* サポートされていないプラットフォームにターゲットをビルドしようとする場合、UBT はビルド処理中に次のようなメッセージを付けて例外をスローします: does not support the platform -* DynamicRHI の作成を整理しました (コードをプラットフォーム専用ファイルに分けました)。 -* SM_PCD3D_SM5 の単なる確認に変わるように、 RHISupportsTessellation(EShaderPlatform) 関数を追加しました。 -* エンジンとエディタを Mac にポートしました。 +* When you attempt to build a target for an unsupported platform, UBT will throw a build exception w/ a message like this: does not support the platform +* Cleaned up creation of DynamicRHI (split code into platform-specific files) +* Added RHISupportsTessellation(EShaderPlatform) function to replace just checking if SM_PCD3D_SM5 +* Porting the engine and the editor to Mac -####アニメーションとペルソナ -* メッシュの再インポート後も、LoD 設定ウィンドウが正しく機能するようになりました。 -* 現在選択している LoD が削除されると、Persona mesh LoD 設定が "Auto" に変更されるようになりました。 -* ペルソナのフロアがメッシュの原点位置ではなくて、バウンディング ボックスの一番下に置かれるようになったので、メッシュと交わることがなくなります。 -* 現在選択されているボーンを、ペルソナ ビューポートで「選択中のアイテム」の色でレンダリングします。 -* ペルソナ ビューポートの空のスペースをクリックすると、ソケット / ボーンの選択が解除されます。 -* アニメーション タイムライン スライダをスクラブ再生すると、マウスのクリックを放した時ではなく、リアルタイムでアニメーションがアップデートされます。 -* FBX がコンテンツ ブラウザ (これまでどおりペルソナも) の AnimSequences 用のエクスポート オプションになりました。 -* 削除キーでペルソナ スケルトン ツリーで選択されたアセットとアタッチされたアセット削除することができるようになりました。 -* スケルトン ソケットがシーン アウトライナーにアタッチできるようになりました。 -* **Set Mesh Root Translation** オプションがペルソナ ビューポートから取り除かれました。 -* PhAT の **Delete All Bodies** で、アンドゥ / リドゥ操作に必要なアクションが 1 つだけになりました。 -* ペルソナの **Import LoD** が正しく機能するようになりました。 -* 現在のアクションがいつスケルトンとなり保存 (デフォルトのメッシュの変更) が必要になるかを、ペルソナがペルソナがユーザーに知らせるようになりました。 -* ペルソナがエラーの有無をエラーログに表示するようになります。 +####Animation and Persona +* LoD settings window now functions correctly after re-importing the mesh +* Persona mesh LoD setting now changes to "Auto" if the currently selected LoD is deleted +* The floor in Persona is now placed at the bottom of the bounding box of the mesh, rather than at the origin, so it no longer intersects the mesh +* Currently selected bone renders in the "selected item" color in the Persona viewport +* Click in empty space in the Persona viewport will deselect any sockets/bones +* Scrubbing the animation timeline slider will now update animations in real time, rather than when the mouse click is released +* FBX is now an export option for AnimSequences in the Content Browser (as well as in Persona as previously) +* Delete key can now be used to delete selected sockets and attached assets in the Persona skeleton tree +* Skeleton sockets can now be attached to in the Scene Outliner +* **Set Mesh Root Translation** option removed from Persona viewport +* **Delete All Bodies** in PhAT now only requires a single action to undo/redo +* **Import LoD** in Persona now functions correctly +* Persona now informs the user when the current action will result in the Skeleton needing to be saved (changing the default mesh) +* Persona will display the error log if there are errors diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/July/ReleaseNotesJuly2013.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/July/ReleaseNotesJuly2013.KOR.udn index 92128f550b4d..9da9d4bc66d6 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/July/ReleaseNotesJuly2013.KOR.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/July/ReleaseNotesJuly2013.KOR.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3367470 Title: 2013년 7월 릴리즈 노트 Crumbs:%ROOT%, Support/Builds Description: Availability:Licensee -Template:ReleaseNotes.html +Parent:Support/Builds +Order:-7 [TOC(start:2 end:2)] @@ -136,7 +137,7 @@ Template:ReleaseNotes.html ####플랫폼 * 대부분의 플랫폼에 APEX Clothing 이 지원됩니다. * Generic PlatformProperties 에 새 함수가 추가되었습니다: - * **SupportsFastVRAMMemory** - 플랫폼이 FastVRAM 패쓰를 지원하면 True, 아니면 False (디폴트)를 반환합니다. + * **SupportsFastVRAMMemory** - 플랫폼이 FastVRAM 패스를 지원하면 True, 아니면 False (디폴트)를 반환합니다. * TexCreate 와 BUF 힌트 플래그를 새로 추가했습니다: `*_FastVRAM` * 가능하다면 RHI 가 텍스처나 버텍스/콘스턴트 버퍼에 FastVRAM 을 사용하도록 합니다. * 기본 FFastVRAMAllocator 클래스를 추가했습니다 (기본적으로 아무것도 하지 않습니다). @@ -153,7 +154,7 @@ Template:ReleaseNotes.html * z 거리 기반입니다 (전에는 방사형(radial) 이었습니다). * 캐스케이드 이행이 부드럽습니다. * 섀도 바이어스 개선과 아울러 다이내믹 섀도 퀄리티가 약간 향상됩니다. -* 포워드 셰이딩 (ES2) 패쓰가 이제 HDR, 노출, 블룸을 지원합니다. +* 포워드 셰이딩 (ES2) 패스가 이제 HDR, 노출, 블룸을 지원합니다. * MinRoughness 라이트 파라미터를 추가했습니다 (fill light 에 매우 유용합니다). @@ -343,7 +344,7 @@ Template:ReleaseNotes.html * 콘텐츠 브라우저에서 애셋 동기화시 필터로 인해 해당 애셋이 표시되지 않게 될 때만 필터가 리셋됩니다. * 이제 프로젝트의 기본 위치는 "내 문서" 그 자체가 아니라 그 하위 폴더가 됩니다. * UAsset 파일이 퍼포스에 텍스트 포맷으로 추가되는 것을 방지하기 위한 약간의 실패방지 코드를 추가했습니다. -* 서버 다운일 때 SCC 콜렉션 작업 처리를 위한 콜렉션 오류를 추가했습니다. +* 서버 다운일 때 SCC 컬렉션 작업 처리를 위한 컬렉션 오류를 추가했습니다. * 일반적인 컨테이너 최적화가 있었습니다. diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/June/ReleaseNotesJune2013.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/June/ReleaseNotesJune2013.JPN.udn index 3dfcfa4d0bca..c1800809d715 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/June/ReleaseNotesJune2013.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/June/ReleaseNotesJune2013.JPN.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:2615137 -Title:2013年6月リリースノート +INTSourceChangelist:3367470 +Title:2013 年 6 月リリースノート Crumbs:%ROOT%, Support/Builds Description: Availability:Licensee -Template:ReleaseNotes.html +Parent:Support/Builds +Order:-8 [TOC(start:2 end:2)] @@ -13,8 +14,8 @@ Template:ReleaseNotes.html [REGION:simpletable] | アイテム | 情報 | | ---- | ---- | -| **Label** | QA_APPROVED_UE4_BUILD_2013_06 | -| **Changelist #** | 1687979 | +| **ラベル** | QA_APPROVED_UE4_BUILD_2013_06 | +| **チェンジリスト#** | 1687979 | | **VISUAL STUDIO VERSION** | Microsoft Visual Studio 2010 version 10.0.40219.1 SP1 Rel | | **DIRECTX** | 2010年6月 | [/REGION] @@ -25,7 +26,7 @@ Template:ReleaseNotes.html * UE4 パラレル レンダリング ロードマップ: [Parallel Rendering Plans for UE4](https://udn.unrealengine.com/questions/168240/parallel-rendering-plans-for-ue4.html) -##主な新機能 +## 主要な新機能 ####ブループリント * **新たなユーザー定義の列挙型アセット** @@ -55,7 +56,7 @@ Template:ReleaseNotes.html * ピッカーにより、矢印とメニュー下部にあるオプションを使った [コンテンツ ブラウザ] メニューへのアクセスが可能になります。 ![](widget5.png) * 「Browse」がアクセスしやすいようにメイン ウィジェットにレプリケートされます。 - * コンボボタンの矢印をクリックすると、シーン アウトライナーを表示して、アクタ プロパティの特殊化も対応します。メニューの「表示」で、問題となっているアクタ上でビューポイントをフォーカスします。 + * コンボボタンの矢印をクリックすると、シーン アウトライナーを表示して、アクタ プロパティの特殊化も対応します。メニューの「表示」で、問題となっているアクタ上でビューポイントをフォーカスします。 * **FBX 再インポートの改善** * スタティックメッシュ、スケルタルメッシュ、アニメーション シーケンス用に UAssetImportData の派生クラスを作成する FBX コードをリファクタリングしました! @@ -63,7 +64,7 @@ Template:ReleaseNotes.html * FBX からアセットをインポートする場合、作成時の設定インポート オプションがインポート時に保存され、再インポートされるたび再利用されます。 * これらのオプションは、[Asset Import Data] と呼ばれるプロパティのアセットのプロパティで編集可能です。 -#### ゲームプレイとフレームワーク +####ゲームプレイとフレームワーク * **C++ クラス ウィザード** * ポーン、キャラクター、PlayerController、その他のゲーム機能を自分のゲームに新規導入する親クラスを追加する機能です。 ![](NCW.png)(w:640) @@ -93,7 +94,7 @@ Template:ReleaseNotes.html * UENUM のみを含むヘッダーのコンパイルエラーを解消しました。 * 空の文字列の場合、FFileHelper::SaveStringToFile でゼロバイトファイルを書けるようにしました。 * DEFINE_LOG_CATEGORY_STATIC をヘッダーで使用しないことになりました。 - * 逆に、DECLARE_LOG_CATEGORY_EXTERN をヘッダーで指定し、対応する DEFINE_LOG_CATEGORY は関連する.cpp ファイルに置きます。 + * 逆に、DECLARE_LOG_CATEGORY_EXTERN をヘッダで指定し、対応する DEFINE_LOG_CATEGORY は関連する.cpp ファイルに置きます。 * DepotName アクセスを CrashDebugHelper に追加しました。 * ユーザーにデポ名を指定させ、どのブランチからもミニダンプのデバグが出来ようにしました。 * 同期を行わないユーザーがプロジェクト生成中になくしてしまったドキュメントフォルダーに対し適切な処理を行うようにしました。 @@ -122,16 +123,16 @@ Template:ReleaseNotes.html * タブを閉じると、閉じたタブの左側のタブにフォーカスが移ります。 -#### ゲームプレイとフレームワーク +####ゲームプレイとフレームワーク * 既存のプロジェクトへのソースコードファイル追加ウィザードが追加されました。 * [File (ファイル)] から [Add Code to Project... (プロジェクトへコードを追加)] で呼び出します。 * 生成されたコードの著作権行を ini ファイルで設定できるようにしました。 * 新たに反転システムを PlayerInput に追加しました。 * InvertAxis を呼び出して、定義した Axis に対する全ての入力の反転 (古い InvertMouse を InvertAxis Lookup に置き換える) を可能にしました。 * 特定の Axis キーを InvertAxisKey で反転することも可能です (joystick ではなく mouse lookup だけを反転させたい場合は InvertAxisKey MouseY を使用できます)。 -* 新たにポーンを追加しました。SpectatorPawn.PlayerController のスペクテーターステートは SpectatorPawn を使用します。 +* 新たに SpectatorPawn ポーンを追加しました。PlayerController のスペクテーターステートは SpectatorPawn を使用します。 * DebugCameraController、LogVisualizer、他いくつかのゲームのコントローラーを修正し、新たなスペクテータモデルを使用できるようにしました。 -* 剛健なレプリケーションをコンポーネントに追加しました。StaticMeshReplicatedComponent と SkeletalMeshReplicatedComponent +* 以下の剛健なレプリケーションをコンポーネントに追加しました:StaticMeshReplicatedComponent と SkeletalMeshReplicatedComponent * フィルタリングを早めるリキャスト オフメッシュ接続に定義済みフラグをオプションで焼き付ける機能を追加しました。 * RecastNavMesh で距離をパスする際にポリゴンを検索する方法を追加しました。 * RecastNavMesh へのクエリに使用する指定フィルタを実装しました。 @@ -151,7 +152,7 @@ Template:ReleaseNotes.html * (SlateViewer などの) プログラムへのサポートを IOS に対して追加 / 改善しました。 -#### レンダリング +####レンダリング * dx11 の柔軟性のある深度ステンシルの読み取りおよび書き込みアクセス (ローレベルレンダリング機能) をマージしました 。 * Speedtree を統合しました。 * キューブマップ シーンキャプチャ アクタを追加しました。 @@ -178,208 +179,208 @@ Template:ReleaseNotes.html ####アニメーション / ペルソナ * **ペルソナ:** * ユーザーがアニメーションの付加的な基本ポーズを見ることができるようにペルソナのビューポートの [Show (表示)] メニューに [Additive Base (加算ベース)] オプションを追加しました。 - * モーフ ターゲットをコンテクストメニューから削除しました。 + * モーフ ターゲットの削除はコンテクストメニューで処理するようになりました。 -##更新ノート +##アップグレード ノート ####ブループリント -* self からワールド コンテクストを提供できないブループリントクラスに UCLASS メタデータ内で ShowHiddenSelfPins としてフラグを付けられるようにしました。 - * これにより、ブループリントのクラスがフラグの付いているクラスから派生しているブループリントグラフに配置されたノード上で WorldContextObject ピンが表示されます。 - * 現在そのようなフラグが付いている唯一のエンジンクラスは AnimNotify で、AnimNotify ブループリントはコンポーネントを WorldContextObject 入力に接続する必要があります。 -* ブループリントの SkeletonGeneratedClasses を暫定としました。 - * ユーザーは何もアクションをとる必要はありませんが、ブループリントシステムを修正した場合、スケルトンクラスに何もリファレンスを保存しないようにしてください。 - * シリアル化された全てのリファレンスを GeneratedClass へポイントしてください。保存中に消えてしまいます。 +* Blueprint classes that do cannot provide a world context from self can now be flagged in UCLASS metadata as "ShowHiddenSelfPins". + * This will show the WorldContextObject pin on nodes placed in the Blueprint graph where the class of the Blueprint is derived from the flagged class. + * Currently AnimNotify is the only Engine class flagged as such and any AnimNotify Blueprints will need to connect Component to the WorldContextObject input. +* Blueprint SkeletonGeneratedClasses are now transient. + * While this does not require any action on the user's part, if you have modified the blueprint system, make sure you do not save any references to the skeleton class. + * All serialized references should now point to the GeneratedClass, or they will be lost during save. #### サウンド -* 名前が SoundMix に変更された SoundModes に Base SoundMix を 1 つ設定し、複数の SoundMix モディファイアーをプッシュするオプションを付けました。 - * コンテクストブラウザで SoundMixes として表示するためには、SoundModes は完全にロードされる前に全て再保存する必要があります。 +* SoundModes renamed to SoundMix, now have the option to set a single Base SoundMix and push multiple SoundMix modifiers. + * All SoundModes will need re-saving so that they will show up as SoundMixes in the Content Browser before they are fully loaded. ####コア -* 保存した configs がソースファイル階層からのまとまった入力に一致する入力を含まないように UE4 のコンフィギュレーション システムを更新しました。 -* 新たにプロジェクトファイルが作成されると、既存の Visual Studio のコマンドラインは保存されません。 - * UE4 がこのバージョンの場合はプロジェクトを再生成する前にコマンドラインを必ず保存してください。 - * 理由は、生成された .vcxproj ファイルの保存先フォルダが変更されたためです。 -* メタデータ指定子の meta(...) 記法には対応しなくなりました。meta=(...) は限定して使用してください。 -* プロパティの最後についてるコメント (例: "float Property; // My float property") はツールチップ メタデータ用には取得されず、UPROPERTY 宣言の前のコメントに変更されます。 -* 複数のメタデータキーが異なる値を持つことでエラーが発生するようになりました。変更前は、後ろの値が前の値をオーバーライトしていました。 -* マップ保存時のファイル名の確認を強化しました。 +* Updated the config system in UE4 so that saved configs generated do not contain entries for those which match the coalesced entry from the source files hierarchy. +* Existing Visual Studio command-lines will not be preserved when generating new project files. + * Remember to save them off before regenerating projects for this version of UE4. + * This is because the folder that generated .vcxproj files are saved to has changed. +* The meta(...) syntax for metadata specifiers are no longer supported. meta=(...) should be used exclusively. +* Comments on the end of a property (e.g. "float Property; // My float property") are no longer scraped for tooltip metadata and should be changed to be a comment before the UPROPERTY declaration. +* Multiple metadata keys with different values now causes an error.Before this change, successive values would overwrite previous ones. +* Improved the filename checking when saving a map. ####エディタ ツール -* UInterfaces が剛健になり、ネイティブ関数に加えてブループリントが実装可能なイベントも安全に対応するようにしました。 - * 結果、ブループリントに純粋に実装されている UInterface (ブループリント プロパティの「インターフェース」セクション経由など) は BlueprintImplementableEvents のみを含むことが可能になりました。 - * ブループリントにアクセス可能で、ネイティブクラスにも追加されている UInterface (class UMyClass : public UObject, public IMyInterface など) は、 BlueprintImplementable イベントと BlueprintCallable 関数を両方持つことができます。 - * ヘッダージェネレータにより、これらの基準に違反してインターフェースは絶対に作成できないようになっています。 +* UInterfaces are now more robust, and safely allow for both blueprint implementable events, as well as native functions. + * As a result, UInterfaces that are implemented in purely in blueprints (i.e. through the blueprint property's "Interfaces" section), can now only contain BlueprintImplementableEvents. + * UInterfaces that are blueprint accessible, but added in a native class (e.g. class UMyClass : public UObject, public IMyInterface), can have both BlueprintImplementable events and BlueprintCallable functions. + * The header generator will ensure that you can't create an interface that violates these criteria. * **ランドスケープ:** - * クラックがおきにくい PN-AEN および Flat テッセレーションを有効にしました。 - * 怠惰なオブジェクト ポイントを使用して LandscapeComponent と CollisionComponent の相互参照を追加しました。 - * Landscape EdMode でランドスケープ Gizmo が削除されないようにしました。 + * Enabled PN-AEN and Flat crack-free tessellation. + * Added LandscapeComponent vs CollisionComponent cross reference using lazy object pointer. + * Prevented Gizmo deletion in Landscape EdMode. -#### ゲームプレイとフレームワーク -* BugIt 実装を PlayerController から CheatManager へ移しました。 -* InvertMouse と InvertTurn exec 関数と同様、bInvertMouse と bInvertTurn も PlayerController から削除されました (新規 invert システムの詳細は新機能をご覧ください)。 -* bIsControllerConnected が PlayerController から削除されました。 -* bCheck パラメータが SetActorLocation から削除されました。目的地でオーバーラップのチェックをしたい場合は、代わりに Teleport を使ってください。 -* SpawnActor 関数が変更されたため、SpawnActor の呼び出しをリファクタリングする必要があります。 -* GamePlayers へアクセスするなら、代わりに GetWorld 関数経由で LocalPlayer にアクセスする方が望ましいです。 -* **物理:** - * 物理コンストレイント システムを大幅にリファクタリングしました。 - * ConstraintSetup の全ての設定を ConstriantInstance へ移しました。 - * コンストレイント設定クラスを削除しました。 - * RB_ で始まるクラスのほとんどが Physics になりました。 - * 多くのクラスを cpp ファイル (PhysicsHandleComponent、 PhysicsThruster, PhysicsContraintTemplate, PhysicsConstraintComponent, PhysicsConstraintActor, RadialForceComponent) に移動しました。 - * PhysicsHandleComponent をリファクタリングし、組み込みスムージングを付けました。 - * StallZ を削除しました。 -* DestructibleComponents が DestructibleActor 以外のダメージに対応するようになりました。 +####ゲームプレイとフレームワーク +* BugIt implementation has moved from PlayerController to CheatManager. +* bInvertMouse and bInvertTurn as well as InvertMouse and InvertTurn exec functions have been removed from PlayerController (See New Feature for details on new invert system). +* bIsControllerConnected removed from PlayerController. +* Removed bCheck param from SetActorLocation.Use Teleport instead if you care about checking for overlaps at the destination when not sweeping. +* SpawnActor calls will need to be refactored because of change to the SpawnActor function. +* Anything accessing GamePlayers should instead either access a LocalPlayer via a GetWorld function. +* **Physics:** + * Big refactor of physics constraint system; + * Moved all settings out of ConstraintSetup into ConstriantInstance. + * Removed constraint setup classes. + * Many classes that started with RB_.. are now Physics.. + * Moved a lot of classes into their own cpp files (PhysicsHandleComponent, PhysicsThruster, PhysicsContraintTemplate, PhysicsConstraintComponent, PhysicsConstraintActor, RadialForceComponent) + * PhysicsHandleComponent has been refactored, has built-in smoothing. + * Removed StallZ. +* DestructibleComponents now respond to damage outside a DestructibleActor. ####オンライン -* FVector ネット量子化のサポートが拡張されました: [Vector Network Quantization](https://udn.unrealengine.com/questions/166428/vector-network-quantization.html) -* シンプルなストリーミング ファイルサーバー コードを 1 つにマージしました。ストリーミングサーバーがシンプルなネットワークサーバーを拡張するようにクライアント側のコードを更新しました。 +* Extended support for FVector net quantization: [Vector Network Quantization](https://udn.unrealengine.com/questions/166428/vector-network-quantization.html) +* Merged the simple and streaming file server code into one.Updated the clientside code so that a streaming server extends the simple network server. -#### レンダリング -* **ポストプロセスエフェクト:** - * Atmospheric fog : fog のレイヤーが複数の場合の状態に対応します。 -* 他の問題のために元の状態に戻したマルチラインの TextRenderActor は今後修正します。 -* SeparateTransluceny を全てのプロジェクトでデフォルで有効にしました。それにより、より一貫性がとれ、デザイナーにより制御を与え、若干遅いですがシーンカラーの精度を低くすることが可能です。マテリアル設定で機能が無効になっていない限り、透光性はフィールドの深度に影響されなくなりました。 +####レンダリング +* **Post Process Effects:** + * Atmospheric fog : handled situations when more than one fog layer exists. +* Reverted multiline TextRenderActor because of remaining issues - will be fixed later. +* Enabled SeparateTransluceny by default for all projects.More consistent, gives more control to the designer, slightly slower but allows scenecolor to be lower precision, translucency is no longer affected by Depth of Field unless feature is disabled in material setting. * **ライティング&シャドウ:** - * ライトマス EnvironmentColor が領域上部のみになりました。 + * Lightmass EnvironmentColor is now upper hemisphere only. ####プラットフォーム -* UnrealBuildTool は、コードをコンパイルする Mac 名を IPhonePackager に渡すようにしたので、 IPP 環境変数を設定したり IPP コードを変更する必要がなくなりました (不可能になりました)。 -* モバイル プロビジョン ファイル を /Library ではなく ~/Library に移動したので、 Mac 上での不自然な許可が必要なくなりました。 +* UnrealBuildTool now passes the name of the Mac that compiled the code to IPhonePackager, so you don't have to (and can't) set an IPP environment variable or change IPP code. +* Changed mobile provision files to go to ~/Library, not /Library, so no weird permissions are needed on Mac. ## 今後の追加事項と継続的な努力 ####ブループリント -* 一番最後に表示されているプリミティブ コンポーネントをブループリントから削除すると、通常のサムネイルへ戻るようにしました。 -* 新規作成されたブループリントはグラフモードではなくコンポーネントモードで開くようにしました。 -* ブループリント用語、中でも Math Library の検索を強化しました。 -* Blueprint エディタの [Hide Unused Pins (使用していないピンを表示しない)] 切り替えオプションを 3 つにわけ、ツールバーからメニューバー ([View (表示)] オプション) へ移動しました。 -* FortPathFollowingComponent を BlueprintType にしました。 - * ブループリントのエクスポーズされた関数が PathFollowingComponent に追加されました。GetPathActionType() と GetPathDestination() です。 - * 上記の関数で、問題になっているパスは完全か、部分的か、またパスのエンドポイントを決めることができます。 -* ブループリント エディタ:* キャメルケースをきれいなバリアントに自動処理し、ユーザーによるアセット検索のマッチ率をあげました。 -* KISMET SCRIPTING ERROR を LEVEL BLUEPRINT ERROR に名前変更しました。 -* EPET_Kismet を EPET_Blueprint という名前に変更しました。 -* タイムラインが正常に追加され「タイムラインが見つかりません」というエラーを解消しました。 -* クラスビューア経由で作成されたブループリントがパッケージを再びダーティとしてマークするようにしました。 -* ステートマシンノード上でノード別コメントへの対応を追加しました。 +* Removing the last visible primitive component from a blueprint now reverts the blueprint back to a generic thumbnail. +* Newly-created Blueprints now open in Components mode instead of Graph mode. +* Made searching for Blueprint terms more robust... especially for functions in the math library. +* Split the Hide Unused Pins toggle option in the Blueprint editor into three options and moved it out of the toolbar and into the menubar (under the View option). +* Made FortPathFollowingComponent a BlueprintType. + * Added blueprint exposed functions to PathFollowingComponent:GetPathActionType() and GetPathDestination(). + * The new functions allow the user to determine whether the path in question is full, partial, etc. and where the end-point of the path is. +* Blueprint Editor:Increased likelihood of finding a match for users Asset search by automatically handling camel case to sanitized variants. +* Relabeled KISMET SCRIPTING ERROR to LEVEL BLUEPRINT ERROR. +* Renamed EPET_Kismet to EPET_Blueprint. +* Timeline missing error now clears once the timeline has been successfully added. +* Blueprints created via the class viewer now mark their packages as dirty again. +* Added support for per-node comments on state machine nodes. #### サウンド -* ブラシで押し出された領域のリバーブボリュームが正しく動作するようにしました。 -* SoundCue コンテクストメニューの Sound ノードは SoundNode のプレフィックスではなくなりました。 -* ClampMin と ClampMax メタタグを適切な値の書式で使用できるようにしました。 +* Reverb volumes with extruded brush areas will now work correctly. +* Sound nodes in the SoundCue context menu are no longer prefixed with SoundNode. +* ClampMin and ClampMax meta tags are now used in the appropriate numerical format. ####コア -* MinimalAPI および RequiredAPI クラスフラグがコンパイルされた クラスへコピーされ、ランタイム時のクエリが可能になりました。 -* ビルドシステム開発と CIS テストの支援に使用される新しい「AutomationTool」プログラム上で作業を継続します。 -* AActor::bNoDelete はコードベースから完全に削除されました。 -* 適切なツールに加えて UE4 向けに新たな設定の Device profile の作業が進行中です。 -* (再コンパイル、プロジェクトファイルの生成などの操作のために) エディタ内へ呼び出される前に、アンリアル ビルドツールがビルドされるようにしました。 +* MinimalAPI and RequiredAPI class flags are now copied to compiled-in classes so they can be queried at runtime. +* Working continues on new "AutomationTool" program that will be used to assist build system development and CIS testing. +* AActor::bNoDelete has been fully removed from the code base. +* WIP of the new system settings "Device Profile" system for UE4 along with appropriate tools. +* Unreal Build Tool is now built before it is invoked in the editor (For operations like recompile, generating project files, etc). ####エディタ ツール * **ランドスケープ:** - * ランドスケープ スプラインの取り消し / やり直しが選択できるようになり、スプライン エディタ外のランドスケープ スプラインの選択状態を修正しました。 - * PIE/Simulate 内でのランドスケープエディタを無効にしました。 - * エディタでのインタラクティビティをあげるため、ランドスケープツールのレンダリングパフォーマンスを改善しました。 + * Made landscape spline selection undo/redo-able, and fixed selection state of landscape splines outside the spline editor. + * Disabled landscape editor in PIE/Simulate. + * Landscape tool rendering performance improvements to improve interactivity in the editor * **スレート & UI:** - * FSlateApplication::GotoLineInSource が追加されました。フォーマットは FullFilePath|Line:Column です。 - * 新たなプロジェクトダイアログではサムネイルサイズが小さくなり、説明文のラップが調整されました。 - * 40x および 256x のアイコンを調整し、クラスを更新しました。PNG の更新のみ、ビルドを破壊しないチェックイン。 - * BlueprintEditor 関数用に 16px のアイコンを新たに作成しました。エディタ内で更にコード合わせが必要になります。 - * 複数のクラスタイプに対して 256 ピクセルのアイコンを作成しました。コード合わせ、ビルドを破壊しないチェックインが必要です。 - * BSPモード用に 40 ピクセル (20 ピクセルをコードスケールと想定) の初期アイコンを作成しました。 - * 追加コードを対応してこれらを合わせる必要があります。ビルドを破壊しないチェックインチェックイン - チェンジリストは PNG アセットのみ。 - * プレースメントモード用の仮アイコンを作成しました。追加コードを対応してこれらを合わせる必要があります。 - * ビルドを破壊しないチェックイン - チェンジリストは PNG アセットのみ。 - * AtmosphericFog、SphereReflectionCapture、BoxReflectionCapture、DestructibleActor、Note、Pawn、Character、DefaultPawn のアクタクラスの全てに 16px のアイコンを作成しました。 - * PNG アセットのみです。ビルドを破壊しないチェックイン (コード合わせが必要) -* ソース コントロールが無効の場合、SCC ステートがコンテンツ ブラウザに表示されなくなりました。 -* **ワールド ブラウザ:** - * ワールドブラウザのズームレベルが増えました。 - * ワールドブラウザの中でレベル選択が表示 ([Home] ボタン) されるようにしました。 -* エディタのメインメニューの配置が改善されました。 -* 実際のアセットを編集している場合は、アセットメニューのみがメニューバーに追加されます。 -* ワールド設定がツールヒントと一緒に表示されるように、ワールド属性を更新しました。 -* ローカルコレクションの作成失敗のポップアップエラーは、コレクションビューではなくコレクションリストを親に持つようにしました。 -* シーン アウトライナーが PIE アクタの選択と変更に対応するようになりました。 -* エディタ ビューポートのグリッドサイズの増減調整をキーバインドできるようにしました。 -* ログリストがコンソールウインドウに保存されるようになりました。 -* プロジェクトが自動ロードに失敗すると、エディタが正常にロードされるまで自動ロードが無効になりました。 -* uプロジェクトファイルに対して生成されたソリューションファイルのファイル名は、格納されているフォルダではなく .uproject file に因んだ名前が付けられます。 + * Added FSlateApplication::GotoLineInSource.The format is FullFilePath|Line:Column. + * Decreased the thumbnail size in the new project dialog and adjusted description wrapping. + * Updated classes 40x & 256x icons, cropping & tweaks.PNG updates only, non-destructive check-in. + * Created new icons for BlueprintEditor functions @ 16px.Require further code hook-up to be used in editor. + * Created icons for multiple class types at 256px - require code hook-up, non-destructive check-in. + * Initial icon for BSP modes created @ 40px (assume 20px version will be code scale) . + * Requires additional code support to hook these up.Non-destructive checking - Change List is PNG assets only. + * First pass icons for placement mode created.Requires additional code support to hook these up. + * Non-destructive checking - Change List is PNG assets only. + * 16px icons for all the AtmosphericFog, SphereReflectionCapture, BoxReflectionCapture, DestructibleActor, Note, Pawn, Character, DefaultPawn actor classes. + * PNG assets only.Non-destructive check-in (requires code hook-up). +* SCC state is no longer displayed in the content browser if source control is disabled. +* **World Browser:** + * More zoom levels in World browser. + * Fit levels selection to view (Home button) in World browser. +* Editor main menu arrangement has been improved! +* Only add the Asset menu to the menubar, if were editing an actual asset. +* Updated World Props button to say World Settings, along with its tooltip +* Error message popup for local collection creation failure is now parented to the collection view, rather than the collection list. +* Scene Outliner now supports selection and modification of PIE actors. +* Editor viewport grid size increment and decrement controls are now key-bindable. +* 'log list' in the console window is now sorted. +* When a project fails to auto-load, auto loading is now disabled until the editor is successfully loaded again. +* Solution files generated for uproject files are named after the .uproject file instead of the folder containing it. -#### ゲームプレイとフレームワーク -* マップトークンなしに generatedistillfilesets をコマンドライン上で操作すると、全てのマップファイルの使用を想定します。 -* コンパイラがインストールされていない/利用できない状態で c++ テンプレートが選択されると、新規プロジェクト ダイアログがエラーを出すようにしました。 -* 入力イベント/ 軸を PlayerControllers に結合することができます。 -* ShapeComponent プロパティ (SphereRadius、CapsuleRadius など) を保護しました。Set/Get 方法でアクセスします。 - * ShapeComponent GetScaled* と GetUnscaled* アクセサを追加しました。通常、ほとんどの場所はスケーリングされた値を読みます。 - * スケールされていないバージョンの ShapeComponents を使用したことで発生したバグの多くを修正しました。キャラクターの動作がスケール化されたカプセルに対して正しく機能します。 -* FMatrix と FTransform の GetAxis を GetScaledAxis へ変更しました。 -* USkeleton 上の AnimationNotifies をループするコードが若干最適化されました。 -* 明確な代替コンテクストがない GWorld リファレンス数を大幅に減らすために、多くの関数をリファクタリングし、更にいくつかの GWorld リファレンスを削除しました。 - * 現在 GWorld を返すクラスの多くに GetWorld が追加されました (GWorld リファレンスを削除しやすくなります)。 -* SpawnActor と関連するテンプレートが改定されました。 - * これらのほぼ全てのパラメータは SpawnActor 関数 / テンプレートへ渡される構造体にあります。 * GamePlayers をプライベートにしてアクセサを追加しました。 - * ワールド経由でローカルプレーヤーを取得するためにプレーヤー配列を使用してきたインスタンスを大幅に置き換えました。 -* **物理:** - * ソルバー イタレーション カウントを増やして物理シミュレーションを改善しました。 - * リファクタリング:* bCreatePhysicsState フラグを削除しました。 - * コリジョンがオンの場合、物理ステートのみ作成されます。 - * クエリ用にコリジョンのない物理ステートを作成する必要のある場合は、bAlwaysCreatePhysicsState を true にセットします。 -* キャラクターの動作を改善しました。 - * 共通の SlideAlongSurface() あるいは SlideAlongVerticalSurface() 関数を使うため、表面に沿ったスライド用の重複コードを数多くリファクタリングしました。 - * 滑らかなカプセル法線を使うためのスライディング コードを変更しました。 - * ジオメトリのコーナーに沿ったスライドが大幅に改善されました。 - * キャラクターの浮遊ではなく、実際の床をベースにして MaxStepHeight を実行します。 - * StepUp を使ってカプセルの滑らかな部分の高めの表面へあがり、上った時に衝撃点の高さを確認することができます。 - * 前の動作を反映するために恐らくゲームはデフォルト値を増やそうとするでしょう。 - * 設定コードで歩行不可能な表面にキャラクターを配置しないようにしました。低いオブジェクト上を移動する動作について、歩行不可能な法線で今後改善していきます。 - * これらの表面に当たることで間違ったフロア法線がレポートされないように、フロアスウィープテストが隣接する垂直なサーフェスを避けるにようにしました。ComputeFloorHeight() を参照してください。 - * ペネトレーションの開始を処理する MoveComponent に SafeMoveUpdatedComponent() を追加しました。 - * 動作の妨げを探知すると、ペネトレーションはそこから出ようと試み、元の動きを再試行します。 +####ゲームプレイとフレームワーク +* Running generatedistillfilesets with no map tokens on the command line now assumes you want to use all map files. +* The new project dialog now produces an error if you do not have a compiler installed/available and you have a c++ template selected. +* Input events/axis can be bound in PlayerControllers. +* ShapeComponent properties (SphereRadius, CapsuleRadius, etc) are now protected.Use Set/Get methods to access. + * ShapeComponent GetScaled* and GetUnscaled* accessors added.In general most places should read the scaled values. + * Many bugs related to using unscaled versions of ShapeComponents were fixed as a result.Character movement now works correctly for scaled capsules. +* Changed GetAxis to GetScaledAxis on FMatrix and FTransform. +* Small Optimization to code looping over AnimationNotifies on USkeleton. +* Removed several more GWorld references including the refactoring of a number of functions to significantly reduce the number of GWorld references where no obvious alternative context was available. + * Also added a GetWorld to a number of classes that currently returns GWorld (this will make it simpler to remove the GWorld references in due course). +* Revised SpawnActor and the associated templates. + * Most all of the parameters for these are now in a struct that can be passed to the SpawnActor function/template Made GamePlayers private and added accessors. + * Replaced many instances that previously used the players array to get a local player via a world. +* **Physics:** + * Improved physics simulation by increasing solver iteration count. + * Refactoring:Removed bCreatePhysicsState flag; + * It only creates physics state if collision is on. + * If you need to create physics state without collision for query, please set bAlwaysCreatePhysicsState to true. +* Character movement improvements + * Refactored lots of duplicate code for sliding along surfaces to use common SlideAlongSurface() or SlideAlongVerticalSurface() functions. + * Changed sliding code to use smooth capsule normal, not the normal of the surface upon which we impact. + * Most notably improves sliding along corners of geometry. + * We actually enforce MaxStepHeight now, based on the actual floor, not the floating base of the character. + * StepUp also used to allow steps up higher surfaces on the smoothed portion of the capsule, and we now check the height of the impact point when stepping up. + * Games will probably want to increase the default value to reflect the previous behavior. + * StepUp code avoids placing the character on unwalkable (bad floor normal) surfaces.In the future we'll improve behavior when moving over low objects with unwalkable normals. + * Floor sweep tests now avoid adjacent vertical surfaces to prevent false floor normals reported from hits with those surfaces.See ComputeFloorHeight(). + * Added SafeMoveUpdatedComponent() to MoveComponent that handles starting in penetration. + * If penetration is detected that blocks the move, it tries to move out and retry the original move. ####オンライン -* 専用サーバーのサポートを更新しました。 - * Steam のスタンドアロンの専用サーバー API をサポートするため様々なコードを修正しました。 - * サウンドとオーディオデバイスが専用サーバーに対して確実にオフにしました。 -* Windows プラットフォーム ハードウェア サーベイに対して改善しました。 - * 第一回目のサーベイを実施しました。以後、月次で実施します。 - * 持続的なエディタ パフォーマンス (プログラミング / スレート フレームレート) の測定およびエディタへの 1 回ごとの記録を開始しました。 - * CPU、OS、RAM stats を改善しました。 - * エンジンがゲーム特有にカスタマイズされている場合、ハードウェアサーベイ機能を公開しました。 +* Dedicated server support updates + * Fixed various code to support Steam's standalone dedicated server APIs + * Made sure sound and audio devices are off for dedicated servers. +* Improvements to Windows platform hardware survey. + * Survey is performed on first run and once per month thereafter. + * Sustained editor performance (Programming/Slate framerate) is measured and recorded every time to editor is started. + * Improved CPU, operating system and RAM stats. + * Exposed hardware survey features if the engine for game-specific customization. -#### レンダリング -* **マテリアルとテクスチャ:** - * Visualizetexture で深度バッファをマップすることで、より多くの色の読み取りが可能になりました。 - * キューブテクスチャがテクスチャ エディタの中で正しく中央に位置するようにしました。 +####レンダリング +* **Materials and Textures:** + * Visualizetexture now maps depth buffer to a more readable color range. + * Cube textures are now correctly centered in the texture editor. * **ライティング&シャドウ:** - * 複数のシャドー cvar 名を変更しました。 - * シャドー レンダリング調査や色付きシャドーのカスケード用に r.Shadows.FreezeCamera を追加しました。 -* **ポストプロセス エフェクト:** - * ポストプロセス機能が期待どおりに動くかテストする r.exposureoffset を追加しました。 - * TemporalAA テストマテリアルを RenderTestMap に追加しました (高周波ディザリングを TemporalAA と使用すると可能になるレンダリング トリックもある) 。 - * PostProcessVolumes などにおける露出のマニュアル設定を DX10 で出来るようにしました。 -* バンディング関連の問題を解消するためにランダムディザを HDR エクスポートに追加しました。 + * Renamed multiple shadow cvars. + * Added r.Shadows.FreezeCamera for shadow rendering investigations, colored shadow cascades. +* **Post Process Effects:** + * Added r.exposureoffset to test if postprocessing features works as expected. + * Added TemporalAA test materials to RenderTestMap (high frequency dithering using with TemporalAA enables some rendering tricks). + * Manual setting of exposure in PostProcessVolumes etc now works in DX10. +* Added random dither to HDR export to eliminate some banding issues. ####プラットフォーム -* エンジンとエディタを Mac へポートする作業を継続します。 -* 要望があれば、UnrealBuildTool で アプリケーション バンドルを PC にコピーできるようにしました (ビルドマシンが Mac 実行ファイルでチェックするには非常に便利) 。 +* Continued work on porting the engine and the editor to Mac. +* UnrealBuildTool can now copy the app bundle back to the PC if requested (only really useful for build machines checking in Mac executables). diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/June/ReleaseNotesJune2013.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/June/ReleaseNotesJune2013.KOR.udn index cb0647649194..4968101e52eb 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/June/ReleaseNotesJune2013.KOR.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/June/ReleaseNotesJune2013.KOR.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3367470 Title: 2013년 7월 릴리즈 노트 Crumbs:%ROOT%, Support/Builds Description: Availability:Licensee -Template:ReleaseNotes.html +Parent:Support/Builds +Order:-8 [TOC(start:2 end:2)] @@ -157,12 +158,12 @@ Template:ReleaseNotes.html * 큐브 맵 씬 캡처 Cube Map Scene Capture 액터를 추가했습니다. * 큐브 렌더 타겟용 HDR 익스포트 기능이 추가되었습니다. * **머티리얼 & 텍스처:** - * MaterialParameterCollection 머티리얼 파라미터 콜렉션: - * 파라미터 콜렉션과 그 기본값을 정의하는 애셋입니다. + * MaterialParameterCollection 머티리얼 파라미터 컬렉션: + * 파라미터 컬렉션과 그 기본값을 정의하는 애셋입니다. * 머티리얼에서는 CollectionParameter 노드로 이 파리미터들을 레퍼런싱할 수 있습니다. * 그 후 블루프린트에서는 실행시간에 효율적으로 이 파라미터에 대한 값을 설정할 수 있으며, 그러면 모든 머티리얼에 새 값이 들어갑니다. * 전역 머티리얼 파라미터, 또는 레벨별 파라미터, 아니면 그냥 에디터에서 대량의 머티리얼 변화를 편하게 미리보는 용도로 사용할 수 있습니다. - * 콜렉션에서 파라미터를 제거하면 다수의 블루프린트와 머티리얼이 한꺼번에 깨질 수 있으니 주의해야 합니다. + * 컬렉션에서 파라미터를 제거하면 다수의 블루프린트와 머티리얼이 한꺼번에 깨질 수 있으니 주의해야 합니다. * **라이팅 & 섀도잉:** * 라이트매스 솔버 퀄리티가 개선되었습니다. * 스무딩된 노멀이 트라이앵글 노멀과 그리 잘 일치되지 않는 지오메트리의 라이팅이 매우 얼룩지고 빌드시간도 오래 걸리던 것이 해결되었습니다. @@ -314,7 +315,7 @@ Template:ReleaseNotes.html * 에디터 메인 메뉴 배치가 개선되었습니다! * 실제 애셋을 편집중이었다면, 메뉴바에 애셋 메뉴만 추가됩니다. * World Props (월드 프로퍼티) 버튼을 World Settings (월드 세팅) 으로, 툴팁과 함께 업데이트했습니다. -* 로컬 콜렉션 생성 실패에 대한 오류 메시지 창이 콜렉션 리스트에 붙기 보다는 콜렉션 뷰에 붙습니다. +* 로컬 컬렉션 생성 실패에 대한 오류 메시지 창이 컬렉션 리스트에 붙기 보다는 컬렉션 뷰에 붙습니다. * 이제 씬 아웃라이너에 PIE 액터의 선택과 수정이 지원됩니다. * 에디터 뷰포트 그리드 크기 증감 기능에 키를 지정할 수 있게 되었습니다. * 콘솔 창의 'log list' 가 정렬됩니다. diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/May/ReleaseNotesMay2013.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/May/ReleaseNotesMay2013.JPN.udn index da493136a7c4..c5039f3824fa 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/May/ReleaseNotesMay2013.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/May/ReleaseNotesMay2013.JPN.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:1995731 -Title:2013年5月リリースノート +INTSourceChangelist:3367470 +Title:2013 年 5 月リリースノート Availability:Licensee Crumbs:%ROOT%, Support/Builds Description: -Template:ReleaseNotes.html +Parent:Support/Builds +Order:-9 [TOC(start:2 end:2)] @@ -13,8 +14,8 @@ Template:ReleaseNotes.html [REGION:simpletable] | アイテム | 情報 | | ---- | ---- | -| **Label** | QA_APPROVED_UE4_BUILD_2013_05 | -| **Changelist #** | 1652795 | +| **ラベル** | QA_APPROVED_UE4_BUILD_2013_05 | +| **チェンジリスト#** | 1652795 | | **VISUAL STUDIO VERSION** | Microsoft Visual Studio 2010 version 10.0.40219.1 SP1 Rel | | **DIRECTX** | 2010年6月 | [/REGION] @@ -26,7 +27,7 @@ Template:ReleaseNotes.html * UE4 ビルドターゲットの変更: [UE4 Target Changes](https://udn.unrealengine.com/questions/166994/ue4-target-changes.html) -##主な新機能 +## 主要な新機能 #### エディタ システム @@ -39,18 +40,18 @@ Template:ReleaseNotes.html * ユーザーは適用を除外し、何も選択せずに **CreatePhysicsAsset** を非設定にすることができます。 ![](importSkM1.png) ![](importSkM2.png) -* **コリジョン システムインターフェースの改善** - * インターフェースが改善されたコリジョンプロファイルシステムが追加されました。 +* **コリジョン システム インターフェースの改善** + * インターフェースが改善されたコリジョン プロファイル システムが追加されました。 * 現在の設定には、NavigationTestingActor、 BlockingVolume、 Character、 InterpActor、 StaticMeshComonent、そして SkeletalMeshActor が含まれます。利用可能なプロファイル リストは「BaseEngine.ini」ファイルにあります。 - * カスタム編集 UI (以下のスクリーンショット)に新規のチャンネル マッピング機能が追加されました。 + * カスタム編集 UI (以下のスクリーンショット) に新規のチャンネル マッピング機能が追加されました。 * カスタム エンジンおよびゲーム チャンネルは、「BaseEngine.ini」ファイルで名前を変更することができます。 -* **カラーピッカー** +* **カラー ピッカー** * カラーピッカーにスポイトツールが追加されました。オンスクリーンのどこからでもすばやく色をピックアップすることができます。 ![](dropper1.png) ![](picker1.png) * **レベル ブラウザでのソース制御** * ユーザーはレベル ブラウザからソース制御機能へアクセスが可能になりました。 - ![](source.png) + ![](source.png) * ソース制御アプリケーションと UE4 エディタ間を頻繁に切り替えが必要なユーザーにとって、ワークフローの統合及び迅速化の大いなる可能性があります。 @@ -58,15 +59,15 @@ Template:ReleaseNotes.html * **入力バインディングの変更** * 入力コンポーネントはもはや明示的にブループリントへ追加しません。代わりに、入力サブメニューからバインディングをアクタブループリントへ追加することができます。 - * アクションやキーイベントを作成したり、軸の値に対してゲッターを配置することができます。* キーイベントは、 [詳細] パネルでControl、 Alt、 そして Shift キーの組み合わせで指定します。 + * アクションやキーイベントを作成したり、軸の値に対してゲッターを配置することができます。キーイベントは、[詳細] パネルでControl、Alt、Shift キーの組み合わせを指定します。 ![](bindings2.png) ![](bindings3.png) * アクションと軸は、「Base/DefaultInput.ini」ファイルで定義され、各アクションは複数のキーとマッピングすることができます。 * アクタはもはや制御されません。ポーンとして所有されるか、アクタで入力を有効にします。 - * レベルブループリントのバインディングは常にアクティブです。ポーンのバインディングは所有されると常にアクティブになります。アクタのバインディングは、Enable/Disable入力値を呼ぶことによってアクティブまたは非アクティブになります。この時入力スタックは以下の順序になっています。 + アクタ * Bindings in the Level Blueprint are always active, bindings in a Pawn are active whenever it is Possessed, and bindings in an Actor are activated/deactivated by calling Enable/Disable Input, with input stacks being ordered as follows: 1. 有効な入力を持つアクタ - 1. レベルブループリント + 1. Level ブループリント 1. 所有するポーン @@ -82,8 +83,8 @@ Template:ReleaseNotes.html #### レンダリング * ** ポストプロセス マテリアル** - * カスタムのポストプロセス エフェクトがマテリアルエディタで作成できるようになりました! - * 複数のエフェクトをポストプロセス ボリュームに追加することができます。 + * ソケットがスケルトンへデフォルト設定で追加されました。カスタマイズも可能です! + * メッシュのみのソケットもスケルトンに昇格できるようになりました。 * 同一のベースマテリアルが使用されるとポストプロセス ボリュームはマテリアル パラメータをブレンドします。 * ポストプロセス マテリアルはカスタムのレンダリング パスからデプスに、例えば画面上のオブジェクトからマスクを取るためにアクセスできます。 ![](Teaser3.png) ![](Teaser1.png) @@ -95,88 +96,88 @@ Template:ReleaseNotes.html * **サウンドキュー エディタ** * エディタでサウンド キューをプレビューする場合、ブループリントでインパルスが表示されるのと同様にキューを通してパスが表示されます。これはキューが、単純、複雑、またはそれ以外でも役立ちます。 - ![](Car_Impact_Cue.jpg)(w:640) + ![](Car_Impact_Cue.jpg)(w:640) * **減衰の形状** - * それぞれが独自の形状プロパティを持つ、球(デフォルト)、ボックス、カプセル、またはコーン形状から選択が可能になりました。 + * それぞれが独自の形状プロパティを持つ、球 (デフォルト)、ボックス、カプセル、またはコーン形状から選択が可能になりました。 ![](attenuation1.png)(w:425) * 各減衰ボリュームは独自のディメンションとフォールオフの距離を持つようになりました。 -####Unreal フロントエンド +#### Unreal Frontend * **アンリアルコンソールのショートカット** * Unreal Console/FrontEnd は頻繁に使用するコマンドをショートカット ブラウザに保存できるようになりました。これにより、簡単に参照と使用ができるようになります。 - ![](console4.png)(w:800) + ![](console4.png)(w:800) ## 新規追加 #### エディタとツール -* **スレートとUI** +* **スレートと UI** * 全てのメニューは垂直ラッピングをサポートしています。 * 大きなメニューのサイズは、作業領域の高さに収まるように制限されています。 * 必要に応じてメニューに垂直スクロールバーが表示されます。 - * 以下の特定のコンテクストメニュー(x17)に拡張性のあるフックが追加されました:コンテンツブラウザ、レイヤー、レベルエディタ、マテリアルエディタ、マテリアルインスタンスエディタ、レベルブループリント + * 以下の特定のコンテクストメニュー (x17) に拡張性のあるフックが追加されました:コンテンツブラウザ、レイヤー、レベルエディタ、マテリアルエディタ、マテリアルインスタンスエディタ、レベルブループリント * コンテンツ ブラウザは「ノマド タブ」で、最高 4 つまで開くことができます。ノマドタブをドックエリアやタブにドッキングできます。 * Quick Browserと主要タブのコンテンツブラウザは、それぞれがコンテンツ ブラウザ 1 とコンテンツ ブラウザ 2 に置き換えられました。 * コンテンツ ブラウザ 3 とコンテンツ ブラウザ 4 が追加されました。 -* MakeEditWidget メタデータ(ベクターウィジット編集)は、アクタクラスの構造体/配列データメンバー内で定義されたベクターと作業が可能になりました。 -* [New Project] ダイアログは、ロケットビルド以外でも使用が可能になりました。引数なしにUE4Editor.exe(またはこれをダブルクリック)を起動すると、このダイアログが表示されます。 +* MakeEditWidget メタデータ (ベクター ウィジェット編集) は、アクタクラスの構造体/配列データメンバー内で定義されたベクターと作業が可能になりました。 +* [New Project] ダイアログは、ロケットビルド以外でも使用が可能になりました。引数なしにUE4Editor.exe (またはダブルクリック) を起動すると、このダイアログが表示されます。 * エディタの File->New Project オプションからもこのダイアログへアクセスできます。 - * 現時点ではコードテンプレートでプロジェクトを作成することはできません。将来のリリースバージョンで再度試してみてください。 -* [Content Migration] が追加されました。この機能でアセットおよびアセット全ての依存関連物を別のゲームへコピーすることができます。 - * レベルブラウザでレベルを右クリックして、コンテンツブラウザのフォルダまたはコンテンツブラウザの個々のアセットから Migrate を選択します。 -* リダイレクタを右クリックする機能が追加され、手動修正が可能になりました。注意事項一連の警告を伴います。 + * 現時点ではコードテンプレートでプロジェクトを作成することはできません。今後のリリースで再度試してみてください。 +* [Content Migration] が追加されました。この機能でアセットおよびアセット全ての依存関連物を別のゲームへコピーすることができます。 + * レベルブラウザでレベルを右クリックして、コンテンツブラウザのフォルダまたはコンテンツブラウザの個々のアセットから [Migrate] を選択します。 +* リダイレクタを右クリックする機能が追加され、手動修正が可能になりました。一連の警告を伴います。 * ロードされていないマップによって参照されるリダイレクタは修正されませんが、それに対する参照は修正されます。 * コードに参照されるリダイレクタは完全には修正されません。 * ヘッドリビジョンまたは別のユーザーにチェックアウトされていないリダイレクタは完全には修正されません。 * 参照がヘッドリビジョンに存在しないリダイレクタ、参照が別のユーザーにチェックアウトされたリダイレクタ、そして参照のチェックアウトを拒否されたリダイレクタは完全には修正されません。 -* **大きなワールドのサポート** - * ワールドブラウザ機能(開発中)が追加されました。 - * **Edit > Preferences > EpicLabs > WorldBrowser** を選択して有効にします。 - * ワールドは **File > Open World** コマンドから開きます。このコマンドは全てのサブレベルが格納されているフォルダを開きます。 +**大規模ワールドのサポート** + * ワールドブラウザ機能 (開発中) が追加されました。 + * 有効にする手順は **[Edit] > [Preferences] > [EpicLabs] > [WorldBrowser]** です。 + * ワールドは **File > Open World** コマンドで開きます。このコマンドは全てのサブレベルが格納されているフォルダを開きます。 * ワールド ブラウザはサブレベルを視覚的にワールドへ配置し、サブレベル間のストリーミング動作を管理します。 * ゲームでワールドを実行するにはこのコマンド パターンを使用します: `MyGame /Game/MyWorld/MyWorldPersistentMap?addmaps=Map01` - * ゲームプレイ中に読み込まれたワールドは、新しいオリジン(通常はゼロ基点)へ移動します。現時点では自動機能しませんが、将来的には自動で機能する予定です。`SetWorldOrigin`コンソールコマンドでテストが出来ます。 + * ゲームプレイ中に読み込まれたワールドは、新しいオリジン (通常はゼロ基点) へ移動します。現時点では自動機能しませんが、将来的には自動で機能する予定です。`SetWorldOrigin`コンソールコマンドでテストが出来ます。 * **ランドスケープ** * ランドスケープ スプラインメッシュに対して Z のみが有効であった代わりに、「前方」軸が選択できるようになりました。 * スプライン編集モード時にランドスケープ スプラインメッシュをクリックすると、スプライン セグメントが選択されるようになりました。 * ランドスケープは FBX 形式でエクスポートが可能になりました。 - * ランドスケープは LOD の縮小版としてエクスポートが可能になりました。ランドスケープアクタのプロパティに設定されます。 - * ランドスケープのハイトマップとレイヤーに "reimport(再インポート)" 機能が追加されました。レイヤーのために元々インポートされたファイル、またはレイヤが直前にエクスポートされたファイルから再インポートします。 + * ランドスケープは LOD の縮小版としてエクスポートが可能になりました。ランドスケープ アクタのプロパティに設定されます。 + * ランドスケープのハイトマップとレイヤーに "reimport (再インポート)" 機能が追加されました。レイヤーのために元々インポートされたファイル、またはレイヤが直前にエクスポートされたファイルから再インポートします。 * 新しい"Interactive" プロパティの変更タイプは、ランドスケープ スプライン プロパティをインタラクティブに編集時に、コリジョンデータの再ビルドを遅延させるこで遅延を修正するために使用します。 * ランドスケープ スプラインは緻密なコリジョンを生成できるようになりました。例えば弾痕跡をブロックすることが可能になりました。 - * ランドスケープエディタが開いていて編集するランドスケープが無い場合、デフォルト設定で [New Landscape] パネルを拡張することができます。 + * ランドスケープ エディタが開いていて編集するランドスケープが無い場合、デフォルト設定で [New Landscape] パネルを拡張することができます。 * ランドスケープのツールとブラシのボタンおよび設定にツールヒントが追加されました。 -* **レベルエディタのビューポートメニューの改良** - * ビューポートのビューメニューが以下の 2 つのメニューへ分割されました。 - * カメラタイプとビューモードです。 +* **レベル エディタのビューポート メニューの改良** + * ビューポートのビュー メニューが以下の 2 つのメニューへ分割されました。 + * カメラ タイプとビュー モードです。 * さまざまなメニューのラベルとアイテムの配列が整理されました。 * レベル ビューポート メニューのボタンラベルへアイコンが追加されました! - * カメラタイプとビューモードのタイプの両方が表示されます。 + * カメラ タイプとビューモードのタイプの両方が表示されます。 * ツールバーメニューのアイテムウィジットは、オプションのラベルアイコンをサポートするようになりました。 * モジュール UI に [Reload(再読み込み)] ボタンが追加されました。 * レベルエディタに [Recompile Level Editor] オプションが追加されました。 -* エディタのモーダル ウィンドウは、ユーザーが別のウィンドウをクリックするとフラッシュします(現時点では Windows のみです)。 - * アクティブなモーダルウィンドウ(Programming/Slate ウィンドウのみです。OSネイティブなウィンドウではありません)は、別のスレートウィンドウがアクティブになるとフラッシュします。 - * Windows タスクバーからモーダルウィンドウを削除しました。 +* エディタのモーダル ウィンドウは、ユーザーが別のウィンドウをクリックするとフラッシュします (現時点では Windows のみです)。 + * アクティブなモーダル ウィンドウ (Programming / Slate ウィンドウのみです。OS ネイティブなウィンドウではありません) は、別のスレートウィンドウがアクティブになるとフラッシュします。 + * Windows タスクバーからモーダル ウィンドウを削除しました。 * モーダル ウィンドウが表示されている時、バックグラウンド ウィンドウは完全に無効化されます。 -* クラスコメントがエディタのツールヒントとして表示されるようになりました。 +* クラス コメントがエディタのツールヒントとして表示されるようになりました。 * **プロファイラ** - * 新イベントグラフ ウィジットが追加されました(初回イタレーション)。 + * 新イベントグラフ ウィジットが追加されました (初回イタレーション)。 * ユーザーがデータグラフをクリックするたびに、新イベントグラフは新規のタブからドキュメントを開きます。 * 以下のビューモードのサポートが追加されました: * 階層 * フラットで包括的 * フラットで排他的 - * ホットパスに基本的な「"expand hot path"(ホットパスの展開)」とカラーコーディングが実装されました。 - * イベントグラフにコンテクストメニューが追加されました(完全には実装されていません)。 - * 統計の集計が追加されました(初回イタレーション)。 - * データグラフのサマリーは、現統計値と一緒に統計集計情報を表示します。 -* **スタティックメッシュエディタ** + * ホットパスに基本的な「"expand hot path" (ホットパスの展開)」とカラーコーディングが実装されました。 + * イベントグラフにコンテクストメニューが追加されました (完全には実装されていません)。 + * 統計の集計が追加されました (初回イタレーション)。 + * データグラフのサマリーは、現スタッツ値と一緒に統計集計情報を表示します。 +* **スタティックメッシュ エディタ** * ソケットはスタティックメッシュ エディタで名前を変更することができます。 * スタティックメッシュ エディタで [Delete] キーを押すと、選択したソケットを削除するようになりました。 @@ -192,7 +193,7 @@ Template:ReleaseNotes.html * ブループリント エディタに、ソース制御が保持するブループリントの前バージョンに対する diff 機能を有効にする [diff] ボタンが追加されました。 * [My Blueprints] タブから選択したプロパティは [詳細] パネルで直接デフォルト値を編集できるサポート機能が追加されました(実験的)。 * ブループリントエディタ デバッグツールバーに [PIE] ボタンが追加されました。 -* 無限ループを持つブループリントが例外を発生させるようになりました。アクティブな場合、ログを取りブループリント デバッガをブレーク(停止)します。 +* 無限ループを持つブループリントが例外を発生させるようになりました。アクティブな場合、ログを取りブループリント デバッガをブレーク (停止) します。 * 新規に作成したブループリントがグラフモードの代わりにコンポーネントモードで開くようになりました。 * ブループリントのモーダル カラーピッカーがトップレベルウィンドウに表示されないように SColorBlock を親に持つようになりました。 * エディタでは、一時停止したシミュレーションを 1 フレーム毎に進めることができるようになりました。 @@ -200,7 +201,7 @@ Template:ReleaseNotes.html #### 分析 -* イベント率が設定制限を超えると SwrveAnalytics が警告を出すようになりました。 +* イベント率が設定制限を超えると SwrveAnalytics が警告を出すようになりました。 * Swrve は一分間あたり 60 のイベントを定義しますが、これは総計の測定です。一分間あたり 70 のイベントを超える場合、イベントの制限をお勧めします。 * 統計は、UE_BUILD_SHIPPING build setting または-RELEASEANALYTICS cmdline の場合に、Release アカウントを選択するようになりました。 @@ -216,11 +217,11 @@ Template:ReleaseNotes.html * navmesh ビルド時にスタティックジオメトリにナビゲーションリンクの先をスナップする汎用メカニズムが実装されました。 * 最大ナビゲーションクエリー検索ノードを「ini」ファイル経由で設定可能にしました(RecastNavMesh::DefaultMaxSearchNodes)。 * 構造体に Protected と Private が反映されたメンバー変数が含まれるようになりました。 -* 全てのティック関数をログへ書き込むためにダンプする「dumpticks」コンソールコマンドが新規で追加されました。 - * 有効または無効にしたTick関数のみをダンプする、「enabled」と「disabled」パラメータをそれぞれオプションで使用できます。 -* HUD の統計の階層ツリーの表示をトグルする「stats tree threadname (optional statname)'」コンソールコマンドを追加しました。 - * 'stats treeup (optional number of lines)' コンソールコマンドでツリーの上層へ移動します。 - * 'stats treedown (optional number of lines)' コンソールコマンドでツリーの下層へ移動します。 +* 全てのティック関数をログへ書き込むためにダンプする 'dumpticks' コンソール コマンドが新規で追加されました。 + * 有効または無効にしたTick関数のみをダンプする、 'enabled' と 'disabled' パラメータをそれぞれオプションで使用できます。 +* HUD の統計の階層ツリーの表示をトグルする 'stats tree threadname (optional statname)' コンソール コマンドを追加しました。 + * 'stats treeup (任意の行数)' コンソール コマンドでツリーの上層へ移動します。 + * 'stats treedown (任意の行数)' コンソール コマンドでツリーの下層へ移動します。 * IsRunningGame() と IsRunningServer() 関数は、実行ファイルが「MyGame.exe」、 「MyGameServer.exe」、またはゲームで実行しているエディタもしくはサーバーモードであるかをチェックします。 * 一過性の出力を My Documents 内のユーザー保存場所に書き込むためのファーストパス サポート「-SaveToUserDir」で有効にします。 * アクタから複数のGetNetOwnerタイプ関数を削除し、GetNetConnection関数に置き換えました。 @@ -229,30 +230,30 @@ Template:ReleaseNotes.html * NULL on CLIENT -> Non Owner. * NOT NULL ON SERVER -> replication connection to client. * NOT NULL ON CLIENT -> replication owner. - * さまざまなコード領域でレプリケーション オーナーチェックを簡素化することを期待します。 + * さまざまなコード領域でレプリケーション オーナーチェックを簡素化することを期待します。 * プレイヤー コントローラなしのアクタが GetNetConnection をオーバーロードし、 RPC/レプリケーションを使用することができます。 * コンソールオートコンプリート - * コンソール オートコンプリート検索のためにゲームごとにマップパスの設定が可能です。 + * コンソール オートコンプリート検索のためにゲームごとにマップパスの設定が可能です。 * オート コンプリートのマップ名に対して現在のユーザーのデベロッパ フォルダを検索します。 #### コア * **プラグイン** - * 最初のUE4プラグインサポート!(作業中ですが利用可能です)。 + * 最初の UE4 プラグインサポート!(作業中ですが利用可能です) * 「.uplugin」ファイルを作成してモジュールを読み込むことができます。これらのプラグインファイルは「 JSon」形式です。 - * UBTとUE4は自動で`.uplugin` ファイルを検知します。 - * プラグインモジュールとC++コードは自動的に生成されたプロジェクトファイルへ追加されます。 + * UBT と UE4 は自動で`.uplugin` ファイルを検知します。 + * プラグイン モジュールと C++コード は自動的に生成されたプロジェク トファイルへ追加されます。 * エンジンプラグインは検知されて「/Engine/Plugins」ディレクトリから読み込まれます。 * プラグインにはコンテンツ サブフォルダがあります。これらのファイルは自動検知されます。 * プロジェクト指定プラグインがサポートされました!「/Plugins 」ディレクトリを作成できます。 * モノリシックビルドは現時点でプロジェクトの全てのプラグインをコンパイルします。 * プラグインは複数のモジュールをサポートします。それぞれのモジュールは、Editor、Runtime、または Development のいずれかに分類されます。 - * 複数のプラグインのローディング フェーズがサポートされます(PreEngineInit, PreGameInit, Default)。 - * プラグインファイルは基本的なバージョンチェックをサポートします(エンジンおよびファイルのバージョン)。 -* 不良な '-' ケース (通常、電子メールからコマンドラインを張り付ける場合) は、ユーザーに警告し、終了するようにします。 + * 複数のプラグインのローディング フェーズがサポートされます (PreEngineInit, PreGameInit, Default)。 + * プラグインファイルは基本的なバージョンチェックをサポートします (エンジンおよびファイルのバージョン)。 +* 不正な '-' ケース (通常、電子メールからコマンドラインを張り付ける場合) は、ユーザーに警告し、終了するようにします。 * PhysX3Common* を Engine/Binaries/Win<32/64> フォルダから適切な Engine/Binaries/ThirdParty/PhysX フォルダに移動しました。 -* Automation Window, Controller, および Worker のモジュールが再ロード可能な DLL になりました。 +* Automation Window、Controller および Worker のモジュールが再ロード可能な DLL になりました。 * モジュール固有のバージョン番号がアーカイブにシリアル化する場合に使用できるようになりました。 * FCustomVersionRegistration 型のグローバル変数をモジュールに配置し、ロード時にモジュール番号を登録できるようになりました。 * サブオブジェクト リダイレクタを使用してサブオブジェクトを削除できるようになりました。これを行うためには、subobj リダイレクタを .ini ファイルに追加し、NewSubobjName を空の文字列に設定します。 @@ -265,11 +266,11 @@ Template:ReleaseNotes.html * IOSTargetPlatform などのプラットフォーム固有の dll は、Binaries/Win<32/64> フォルダのサブディレクトリにあります。 * モジュール ルールでは、DLL のビルド時に使用する BinariesSubFolder を指定することができます。 * 新しい WindowsServer プラットフォームのクッキングを変更しました。 - * WindowsServer は SM4 および SM5 シェーダーと全てのテクスチャフォーマット処理を無視します。 + * WindowsServer は SM4 および SM5 シェーダーと全てのテクスチャフォーマット処理を無視します。 * render thread コマンドのために **ENQUEUE*** マクロを無効にしました。UE_SERVER=1 実行時は常に NOOP になります。 * デディケイテッド サーバーの最初の作業があります (NULLRHI、レンダリング スレッドを強制しないなど)。 * デディケイテッド サーバーへの自動ログイン(コマンドラインの -login/-pass はオンライン サービスにログインしようとし、RegisterServer() を呼び出します)。 -* 大きな IOS アップデート (Audio, Slate, UnrealConsole サポート) +* 大きな IOS アップデート (Audio、Slate、UnrealConsole サポート) * DLL 検索パスを安全に修正するために PushDllDirectoty/PopDllDirectory が追加されました。 * ロード前に有効なプラットフォーム DLL をチェックするサポートを追加しました (Win64 サポートの DLL を例えば、PS4 にチェックインすると、PS4 SDK をインストールしていなければクラッシュにつながるため PS4 はロードされません)。 @@ -290,422 +291,422 @@ Template:ReleaseNotes.html * シーケンスのプレイヤーとブレンド空間を同期グループのメンバーとし宣言できます。グループ リーダーが他のすべてのメンバーの時間進行と通知生成を制御します。 * 各グループ メンバーには役割があります。最も高いブレンド ウェイト合計 (デフォルト) を持つ場合にリーダー、常にリーダー、決してリーダーにならないメンバーがあります。 * Export FBX 機能をペルソナ ビューポート メニューからアセット ブラウザに移動し、複数のアニメーションを一回でエクスポートする機能を追加しました。 -* モーフ ターゲットの削除はコンテクストメニューで処理するようになりました。 +* モーフ ターゲットの削除はコンテクスト メニューで処理するようになりました。 #### レンダリング -* **パーティクル システム** +* パーティクル システム * グローバル ベクターフィールドのタイトネスは、グローバルベクターフィールドのカスケード モジュールからオーバーライドできます。 * ParticleSizeマテリアルノードが利用可能になりました。このノードはワールド空間にあるパーティクルの XY サイズを返します。 * **マテリアル** - * TextureObject 式は作成時に選択したテクスチャを自動で割り当てます。 - * TextureObject 式に [Use Current Texture] メニューオプションが加わりました。 - * TextureObjects と TextureSamples は新規のメニューオプションで交換できるようになりました。 - * WorldPosition material 式に、ワールド位置にシェーダーオフセットを含むか否かを決定する新設定が追加されました。シェーダー オフセットにはWorld Position Offset といくつかのテッセレーション(細分化処理)が含まれます。 -* **ポストプロセス エフェクト** + * TextureObject式は作成時に選択したテクスチャを自動で割り当てます。 + * TextureObject 式に [Use Current Texture] メニュ ーオプションが加わりました。 + * TextureObjects と TextureSamples は新規のメニュー オプションで交換できるようになりました。 + * WorldPosition material 式に、ワールド位置にシェーダー オフセットを含むか否かを決定する新設定が追加されました。シェーダー オフセットには World Position Offset といくつかのテッセレーション (細分化処理) が含まれます。 +* **ポストプロセス エフェクト:** * 既存のモーション ブラーを以下のような新規のモーション ブラー アルゴリズムで置き換えましたが [](http://graphics.cs.williams.edu/papers/MotionBlurI3D12/McGuire12Blur.pdf) まだ半分の解像度であり、小規模な改善を予定しています。 * ポスト プロセス後のカスタム デプス パスのレンダリング、プリミティブ コンポーネントのチェックボックスの最初のイタレーションは、可視状態にする (シルエットのレンダリングで役立ちます) ために処理を速くする必要性があり、エディタ チェックボックスのメッシュ / プリミティブ コンポーネントまたはゲーム コードで有効にすることができます。 * マテリアルのポスト プロセスの最初のイタレーションが利用できます (PostProcessVolume で全画面パスでレンダリングするマテリアルを指定できます。Postprocess0 または GBuffer のプロパティを入力するにはSceneTexture マテリアル式を使用します)。TemporalAA については改善が必要で複数のパスとその他の変更をサポートします。 * Temporal AA がデフォルトのアンチエイリアス ソリューションになりました。これは FXAA よりも滑らかで高品質な画像を生成します。 -* **ShadowSharpen** プロパティをライトに追加しました。 +* **ShadowSharpen** プロパティをライトに追加しました。 * r.CompositionGraphDebug による合成グラフ デバッグ ダンプを追加しました。 -* 解像度や乗数値を使用する場合に HighResShot コマンドが機能するようになりました。使用例:HighResShot 1920x1080 +* 解像度や乗数値を使用する場合に HighResShot コマンドが機能するようになりました。使用例:HighResShot 1920x1080. #### オーディオ -* SoundNodeBranch が追加されました。名前付けしたブール パラメータを AudioComponent で使用してサウンドキューのビヘイビアを変更することができます。 +* SoundNodeBranch が追加されました。名前付けしたブール パラメータを AudioComponent で使用してサウンド キューのビヘイビアを変更することができます。 * SoundModes は SoundMix へ名前が変更されました。 * Base SoundMix を 1 つ設定し、複数の SoundMix モディファイアーをプッシュするオプションを付けました。 -* 単一の CurrentMode とそのフェード量、およびiBaseSoundMode の考え方は、アクティブな SoundMixes のリストとそれらの現在の状態で置き換えられました。 - * 'STAT SOUNDMIXES' コマンドはどの SoundMixess が現在アクティブであるか (ListSoundModes を効果的に置き換えます) 、そのフェードイン レベル、およびどのモードが EQ を制御しているかを示すようになりました。 +* 単一の CurrentMode とそのフェード量、および iBaseSoundMode の考え方は、アクティブな SoundMixes のリストとそれらの現在の状態で置き換えられました。 + * 'STAT SOUNDMIXES' コマンドはどの SoundMixess が現在アクティブであるか (ListSoundModes を効果的に置き換えます)、そのフェードイン レベル、およびどのモードが EQ を制御しているかを示すようになりました。 * Audio Effect マネージャは EQ の変更を適用する前にサウンド モードのプライオリティをチェックするようになりました。 * EQ の制御は EQ Priority プロパティによってさらに指定可能であり、すべてのサウンド モードが無効になった場合に EQ エフェクトをクリアする新しい関数があります。 -* 新しい Reverb Effect アセットタイプ経由で Reverb 設定を公開します。 +* Reverb 設定を新規 Reverb Effect アセット タイプ経由で公開しました。 -## アップグレードノート +## アップグレード ノート #### エディタとツール * Game, Editor, GameUncooked および Server は、Target.cs ファイル'Type' プロパティで使用する独自のターゲット タイプを持ちます。 - * TargetType.Game: UEBuildGame ターゲットをビルドします。 - * TargetType.Editor: UEBuildEditor ターゲットをビルドします。 - * TargetType.Server: UEBuildServer ターゲット (デディケイテッド サーバー) をビルドします。 - * TargetType.GameUncooked:デフォルトでゲームを実行する (`-game` 引数で) UEBuildEditor ターゲットをビルドします。 - * 詳細とアップグレード情報については [ターゲット変更](https://udn.unrealengine.com/questions/166994/ue4-target-changes.html) をご覧ください。 -* UE4Editor.exe として Example は機能しなくなりました。代わりに UE4Editor.exe QAGame を使用しなければなりません。 -* TFieldIterator コンストラクタのパラメータは、読みやすさを改善するためにブールから列挙型変数に変更されました。既存の TFieldIterator の使用ではアップデートが必要になります。 - すべてのコンポーネントが有効化または無効化できるようになりました。 - * bIsActive が SceneComponent から ActorComponent に移動しました。 - * 非アクティブなコンポーネントがティックを無効にします。 - * ティックを必要とする既存の ActorComponents は適切な時に有効化するか、コンストラクタで bAutoActivate = true を指定する必要があります。 -* Send PhysicsTransform は仮想ではなくなりました。代わりに OnUpdateTransform を使用します。 -* 入力バインディング システムがリストラクチャリングされました。 -* Steam SDK は 1.23a にアップグレードされました。 -* 名前付けしたネット ドライバーを、定義とアクティブなドライバー リストにリファクタリングしました。 - * DefaultEngine.ini の NamedNetDrivers パラメータは、NetDriverDefinitions という名前になりました。 - * GetNetMode は、サーバー/クライアント/スタンドアロンを決めるためのネット ドライバーのステートを見るようになりました。 - * NetMode 変数はまだありますが、非推奨になりました。 -* メッセージング システムが、厳密に型指定されたメッセージ (UStructs)を使用するようにアップグレードされました。 -* GENERATED_UCLASS_BODY() 宣言後のセミコロンがサポートされなくなりました。 -*リファクタリングされたアクタ ファクトリがコンテンツをロードする必要なくコンテンツからアクタを作成できるか否かを決定できるようになりました。 -* これは将来機能がオンラインになったときに、適切にインタラクションするようにどのアクタを作成できないか、どのアクタがこうしたコンテンツの再保存を必要とするかコンテンツをフィルタリングする機能の準備です。 -* すべての 'unofficial' (非公認) (つまり、perforce または ArtistSync からは得られない) 人々が利用するショートカット、バッチ ファイルなどは更新する必要があります。 - * Win32 ビルドを monolithic/requirescookeddata に強制的にするコードを取り除きました。 - * **注記**:Win32 エディタのビルドは、コンパイラのアラインされたパラメータ問題が原因でまだ機能しません (これは VS2010 と VS2012 の両方で起こります)。 - * **注記**:ゲームの'Uncooked' バージョンをビルドすると、すべての古いコマンドラインはまだ機能します。ただし、コマンドレットの実行は例外です。これらは、いずれの exe でも"-run=" が機能することを必要とします。 -* 以前の global canvas 関数 (EG. ) を呼び出しているコードは、コンテキストをパラメータとして渡すのではなくキャンバス コンテキストから同じ関数を呼び出さなくてはならなくなりました。 -* GIsGame は FApp::IsGame() に置き換えられました。 + * TargetType.Game: Builds a UEBuildGame target. + * TargetType.Editor: Builds a UEBuildEditor target. + * TargetType.Server: Builds a UEBuildServer target (dedicated server). + * TargetType.GameUncooked:Builds a UEBuildEditor target that defaults to running the game (via the `-game` argument). + * See [Target Changes](https://udn.unrealengine.com/questions/166994/ue4-target-changes.html) for complete details and upgrade info +* As the UE4Editor.exe Example will no longer work, you must use UE4Editor.exe QAGame instead. +* TFieldIterator constructor params have been changed from boolean to enum types in order to improve readability.Existing uses of TFieldIterator will require updating. + * All components can now be activated or deactivated. + * bIsActive moved from SceneComponent to ActorComponent. + * Inactive components will disable their tick. + * Existing ActorComponents that require a tick will either need to Activate at the appropriate time or specify bAutoActivate = true in the constructor. +* Send PhysicsTransform is no longer virtual.OnUpdateTransform should be used instead. +* Input bindings system restructured. +* Steam SDK upgraded to 1.23a. +* Refactored named net drivers into definitions and active driver list. + * NamedNetDrivers parameter in DefaultEngine.ini is now named NetDriverDefinitions. + * GetNetMode now looks at state of net driver for determining server/client/standalone. + * NetMode variable is still around but is deprecated. +* The Messaging system has been upgraded to use strongly typed messages (UStructs). +* Semi-colons on the end of GENERATED_UCLASS_BODY() declarations are no longer supported. +* Refactored actor factories to be able to determine if they can create an actor from a piece of content without requiring the content be loaded. +* This in preparation for features involving filtering content out which actors can't be created from and will require that such content be resaved when the feature comes online in the future for them to be interact properly. +* All 'unofficial' (ie you don't get it from perforce or the ArtistSync) shortcuts, bat files, etc. that people utilize will need to be updated. + * Removed code that was forcing Win32 builds to be monolithic/requirescookeddata. + * **NOTE:** Win32 editor builds still wont work due to the aligned parameter issue in the compiler (this happens in both VS2010 and VS2012). + * **NOTE:** If you build the 'Uncooked' version of your game, all old commandlines will still work... with the exception of running commandlets.These require "-run=" to work in either exe now. +* Any code that was calling the previously global canvas functions (EG. ) must now call the same functions from the canvas context rather than passing the context as a parameter. +* GIsGame has been replaced with FApp::IsGame(). #### ブループリント -* ブループリントは LifeSpan に配慮するようになりました。LifeSpan がゼロ以外になったらブループリントはティックするように設定され、失効後に自己を破壊します。これはシーン内でティックされるアクタ数が増えるかもしれないことに注意してください。 -* カテゴリの非表示は、ブループリント エディタにおける変数を考慮するようになりました。 - * 意味がない数多くのプロパティからのブループリントへのアクセスを削除しました。 - * 多数のクラスの意味がないカテゴリ (主にコンポーネント) を非表示にしました。例えば、矢印コンポーネントの物理があります。 -* HUD の Canvas プロパティを保護しました。 - * DisplayDebug が HUD ではなくキャンバスを取るようにシグネチャの変更が必要でした。 -* ブループリント関数 Actor.DestroyComponent は非推奨になりました。代わりに ActorComponent.DestroyComponent を使用します。 -* Actor クラスの多くの 'BlueprintCallable' 関数は非推奨になりました。これは既存のレベル ブループリントで警告を発生する場合があります。 - * Actor, Emitter, Light の AmbientSound, DecalActor, DynamicSMActor, RadialForceActor の物理関数に影響を及ぼします。 - * ExposeFunctionCategories メタデータを使用してコンポーネント関数を含むアクタでコンポーネント関数を簡単に呼び出すことができるようになりました。 -* アクタのリファレンスをドラッグすると、エクスポーズしたコンポーネント関数が得られ、'call function on member' ノード ('get' 呼び出しと 'call' 呼び出しを組み合わせます) を配置します。 -アクタをコンポーネント関数に接続しようとすると、アクタに正しい型のコンポーネントが含まれていれば、'Get' ノードを挿入しようとします。 -* アクタから、NativeConstructionScript, IsRootComponentSimulatingPhysics, CheckHitInfo, GetActorMetrics, SetActorAndComponentsTickEnabled を取り除きました。 -* ポーンからAlwaysRelevantDistanceSquared, SetViewRotation, TickSimulated, SetMaxLandingVelocity, HurtByDamageType を取り除きました。 -* PC から PreRender , GetPartyMapName, GetPartyGameTypeName を取り除きました。 -* URB_BodySetup を UBodySetup に名前変更しました。 -* 物理ボリュームから WillHurt, ModifyPlayer, NotifyPawnBecameViewTarget を取り除きました。 -* FEdGraphSchemaAction_K2NewNode::InstantSpawn が SpawnNodeFromTemplate に名前変更されました。 -* グラフ スキーマ メニュー / パレットのビルドのために作成されたカスタムのブループリント ノード テンプレートは、ブループリントにトレースバックできる outer で作成されなければなりません。そこから派生したカスタムのスキーマがあれば例えば UEdGraphSchema_K2 の変更をご覧ください。 -* WorldInfo をWorldSettings に名前変更しました。 - * BaseEngine.ini でリダイレクタを get するようにしてください。 -* AActor::VerifyNoUnreachableReferences を削除しました。 -* AActor::TickSpecial の名前が ::Tick に変更されました。 -* AActor::TickAuthoritative と TickSimulated が削除されました。 +* Blueprints now respect LifeSpan.If LifeSpan is non-zero, blueprints will now be set to tick, and destroy themselves after they expire.Please be aware that this may increase the number of ticked actors in your scenes. +* Category hiding is now respected for variables in Blueprint editor. + * Removed blueprint access from a number of properties where it did not make sense. + * Hide nonsensical categories for lots of classes (mainly components) e.g. physics on an arrow component. +* Made Canvas property of HUD protected. + * Required changing signature of DisplayDebug take a canvas and not a HUD. +* Blueprint function Actor.DestroyComponent has been deprecated.ActorComponent.DestroyComponent should be used instead. +* Many 'BlueprintCallable' functions on Actor classes are now deprecated.This may result in warnings in existing level blueprints. + * Affects AmbientSound, DecalActor, DynamicSMActor, RadialForceActor, physics functions on Actor, Emitter, Light. + * Can now call the Component functions more easily on Actors that contain one, using the ExposeFunctionCategories metadata. +* If you drag off an Actor reference, it will offer exposed Component functions, and will place a 'call function on member' node (which combines 'get' and 'call' nodes). +* If you try and connect an Actor to a component function, it will try and insert a 'Get' node if that Actor contains a Component of the correct type. +* Removed NativeConstructionScript, IsRootComponentSimulatingPhysics, CheckHitInfo, GetActorMetrics, SetActorAndComponentsTickEnabled from Actor. +* Removed AlwaysRelevantDistanceSquared, SetViewRotation, TickSimulated, SetMaxLandingVelocity, HurtByDamageType from Pawn. +* Removed PreRender , GetPartyMapName, GetPartyGameTypeName from PC. +* Renamed URB_BodySetup to UBodySetup. +* Removed WillHurt, ModifyPlayer, NotifyPawnBecameViewTarget from PhysicsVolume. +* FEdGraphSchemaAction_K2NewNode::InstantSpawn has been renamed to SpawnNodeFromTemplate. +* Any custom blueprint node templates created for graph schema menu / palette building must now be created with an outer that can trace back to the blueprint.See the changes made in UEdGraphSchema_K2 for examples if you have a custom schema derived from it. +* Renamed WorldInfo to WorldSettings. + * Make sure to get redirector in BaseEngine.ini. +* AActor::VerifyNoUnreachableReferences has been removed. +* AActor::TickSpecial has been renamed ::Tick. +* AActor::TickAuthoritative and TickSimulated have been removed. #### ゲームプレイとフレームワーク -* PhysicsActor と PhysicalMaterial はサウンド / エフェクトを直接サポートしなくなりました。 - * 各フレームですべての物理コリジョンを与えられるゲーム固有の PhysicsCollisionHandler を作成し、コリジョンで行いたいことを行うことができます。 -* アクタから仮想の NotifyHitActor/NotifyHitByActor を削除しました。 - * ブロックしているコリジョンに対して ReceiveHit をオーバーライドするようになりました。 -* アクタから仮想の NotifyActorTouch, NotifyActorUnTouch, NotifyComponentTouch, NotifyComponentUnTouch を削除しました。 - * PrimtiveComponent で ReceiveActorBeginOverlap とReceiveActorEndOverlap をオーバーライドするか、またはデリゲートをオーバーラップするようになりました。 -* **物理:コリジョン:** - * CollisionProfileSystem の取り消しの取り消し- 新規セットを BaseEngine.ini でチェックします。 - * チャンネルの名前変更:Pawn->PawnMovement, Vehicle->VehicleMovement, RigidBody->PhysicsBody. - * チャンネルの削除:Mover(->Default), RigidBodyInteractable(->PhysicsBody), Cloth, DeadPawn. - * エンジンから取り除かれたチャンネル:TraceWeapon, Projectile, Pickup (QAGame の DefaultEngineをチェック). - * 以前はなかったものにインスタンス化後にコリジョン プロファイルを設定すると、コリジョン プロファイルをオーバーライドできます。 +* PhysicsActor and PhysicalMaterial now no longer have direct support for sounds/effects. + * Now you create a game-specific PhysicsCollisionHandler, which is given all physics collisions each frame, and can do what it wants with them. +* Removed virtuals NotifyHitActor/NotifyHitByActor from Actor. + * Now override ReceiveHit now for a blocking collision. +* Removed virtuals NotifyActorTouch, NotifyActorUnTouch, NotifyComponentTouch, NotifyComponentUnTouch from Actor. + * Now override ReceiveActorBeginOverlap and ReceiveActorEndOverlap, or overlap delegates on PrimtiveComponent. +* **Physics:Collision:** + * CollisionProfileSystem redone - check BaseEngine.ini for new sets. + * Channels Renamed :Pawn->PawnMovement, Vehicle->VehicleMovement, RigidBody->PhysicsBody. + * Channels Removed :Mover(->Default), RigidBodyInteractable(->PhysicsBody), Cloth, DeadPawn. + * Channels moved out of engine:TraceWeapon, Projectile, Pickup (check QAGame's DefaultEngine). + * Setting a collision profile after instantiated for the one that didn't have before can override collision settings. #### レンダリング -* ポストプロセス設定に AA Method を追加しました。 -* ポストプロセス設定から MotionBlurPerObjectDistance を取り除きました。 +* Added AA Method to post process settings. +* Removed MotionBlurPerObjectDistance from post process settings. * **Atmospheric fog:** - * Altitude レイヤー制御プロパティを追加しました。 - * Z 位置にのみ影響を及ぼす Altitude スケール変更を追加しました。 - * r.Atmosphere (0 または 1) のコンソール コマンドを追加しました。これにより、atmospheric fog + reload/remove 関連のリソースを有効 / 無効にします。 - * フォグとは別に大気の表示フラグを追加しました。 - * ビューの均一なバッファ変数をサイズを減らすために半分の解像度になるようにしました。 - * スカイボックスを持たないレベルに対するフォグのレンダリングのアーティファクトを取り除きました。 -* ライトシャフト (光線):LightShaft CVar r.LightShaftDownSampleFactor (ライトシャフト (光線) のダウンサンプリングのスケーリング) を追加しました。 -* ランドスケープ:スムーズ ツールを改善し、スムーズ フィルタ サイズ調整を追加しました。 -* 事前統合された GF を用いた新しい IBL シェーディング モデルの概算。この新しいソリューションはより正確ですが、既存マテリアルの外観を変えることがあります。 + * Added Altitude layer control property. + * Added Altitude scale change which only affects Z location. + * Added r.Atmosphere (0 or 1) console command, which enable/disable atmospheric fog + reload/remove related resources. + * Added show flag for atmosphere, separate from fog. + * Reduced view uniform buffer variables to be half-resolution to reduce size. + * Removed artifacts for fog rendering for levels that doesn't have a skybox. +* LightShaft :Added LightShaft CVar r.LightShaftDownSampleFactor (Scale lightshaft downsampling). +* Landscape :Improved smooth tool, added smooth filter size adjustment. +* New IBL shading model approximation using preintegrated GF.The new solution is more accurate but can change the look of existing materials. #### オーディオ -* SoundNode::Parse API は、グラフがツリーではない場合にサウンドキューで正確にパスを追跡するように変更されました。 - * たどられた各ノードは GetNodeWaveInstanceHash を用いてハッシュを適用します。 - * これは自動的に SoundNode::ParseNodes で処理されます。しかし、ChildNodes でParseNodes を呼び出すノードはこれを直接適用しなければなりません (例、USoundNodeMixer::ParseNodes を参照)。 +* SoundNode::Parse API changed to correctly track the path through SoundCue when the graph isn't a tree. + * Each visited node applies itself to a hash using GetNodeWaveInstanceHash. + * This is handled in SoundNode::ParseNodes automatically, however, any node that calls ParseNodes on its ChildNodes directly must apply this (see USoundNodeMixer::ParseNodes for example). -## 将来的な追加事項と継続事項 +## 今後の追加事項と継続事項 #### ブループリント -* ブループリント エディタのコンポーネント モードでコンポーネントを追加後にコンポーネントを編集するためにブループリントをコンパイルする必要がなくなりました。 -* ブループリント グラフで 入口/出口/折り畳まれたノードをクリック後に、詳細タブから入出力を追加できるようになりました。 -* ブループリント設定をグローバル ユーザー設定に移動しました。これで、代わりに [Preferences Editor] タブからアクセスできるようになりました。ブループリント エディタから設定メニューも取り除きました。 -* ブループリント グローバル設定を詳細パネルに移動しました。このパネルには、ブループリント エディタの新しい [Blueprint Props] ツールバー ボタンからアクセスできます。 - * ブループリント エディタのツールバーから Reparent (親変更) 機能を詳細パネルに移動しました (ツールバー エディタには存在しなくなりました)。 -* ブループリント エディタの詳細パネルでコンポーネントのプロパティに加えた変更は、編集されているブループリントに基づきアクタのインスタンスを正しく更新するようになりました。 -* サブアイテムがひとつしかなければ、Break Links のサブメニューはブループリント グラフに表示されなくなり、サブアイテムそのものだけが表示されます。 -* ブループリント エディタでアクタ以外からアクタベースのブループリントに親変更すると、コンポーネントのトグル ボタンが有効になります。 -* ブループリント エディタのコンポーネント モードでコンポーネントを移動後ブループリントがダーティになります。 -* ブループリントのプレビュー ビューポートには、アンビエント キューブマップを備えたポストプロセス ボリュームが含まれます。 -* コンポーネントの編集モードはブループリント エディタの非アクタ ベースのブループリントに対してアクティベートできなくなりました。 -* マクロ ブループリントの編集時にコンポーネント モードはブループリント エディタでアクティベートできなくなりました。 -* ブループリントの安定性はリファクタリングと非推奨コードを改善しました。 -* GetPlayerCharacter() ブループリント関数を UGameplayStatics に追加しました。GetPlayerPawn() と同様ですが、キャラクターとキャラクターの動きにアクセスする必要がある人に対して、APawn の代わりに ACharacter を戻します。 -* 入力インデックス値が対応するオプション数よりも大きいことが原因で (例、グラフで使用後に、列挙型にコードで追加された値がある場合)、Select Node にコンパイル エラーがある場合、特定の問題を追跡するためにはるかに多くの情報を備えたメッセージを出力するようになりました。エラーが発生したブループリントのフルパスと選択ノードのインデックスタイプ名 (すなわち、bool, int, または特定の列挙型変数名) をリスト表示するようになりました -* 非推奨のブループリント関数は、UFUNCTION メタ セクションにある DeprecationMessage を使用して役立つメッセージを供給することができます。 -* ブループリント エディタの広範な UI とワークフローを改善しました。 -* ブループリント マクロの詳細ビューの入出力の削除ボタンが更新されました。 -* ブループリント変数のレプリケーション ステートの新しいイラストが追加されました。 -* 詳細ビューで Create (作成) と Harvest Blueprint (ブループリントのデータを得る) の ボタンを整理しました。 -* [Find in Blueprints] ダイアログで何も結果がない場合にメッセージが表示されるようになりました。 -* ブルーは、名前でフェッチされる場合に存在しているかについてチェックされるようになりました。 -* ブループリント エディタ終了時に、まずブループリント エディタ ウィンドウが閉じるようになりました。 -* ブループリント エディタの hide pin に新しいアイコンが追加され、既存のプレースホルダー アイコンの hide_unusedpins.png に取って代わり、非破壊のアートのみが更新します。 -* 様々なブループリント コンパイル ステートに対して新しいクリアなアイコンが必要です。既存のプレースホルダー アイコンを新規承認されたバージョンで置き換えました。アート変更のみ - 非破壊です。 -* Create Blueprint from Actor and Harvest Blueprint のアイコンを作成しました。非破壊更新です。 -* 'Find in current Blueprint', 'Blueprint Options' & 'Diff against previous revision' の新しいアイコンを作成しました。サイズは 40px & 512px です。PNG アセットのみです。ビルドを破壊しないチェックイン (コード合わせが必要) -* 外部 (サードパーティ) モジュールは、インクルード パス、PublicInclude パスを追加しました。 -* サードパーティまたはシステム ファイルのインクルード パスはフォワードスラッシュとバックスラッシュをチェックしません。 -* ブループリントへのインターフェース、FortInteractInterface の再追加 (削除後の) はエラーを発生しなくなりました。 -* ブループリント関数はキーワード検索できるようになりました。 -* LoadStreamlevel および UnloadStreamLevel のブループリントのアクションは、指定された名前の部分一致を行い、その文字列で終わるストリーミング レベルを見つけようとします。フルパスは不要です。 -* コンテンツ ブラウザでアクタに対して find を使用する場合にブループリントは他のアセット タイプよりも好ましいものになりました。 -* ブループリントのコンパイル自動生成変数名には、明示的にするためにノード GUID (グローバル一意識別子) が含まれるようになりました。 -* [詳細] パネルのブループリント作成のワークフローを改善しました。 -* ブループリント エディタの UI を改良中。 - * ブループリント エクスプローラと変数のタブは完全に非推奨であり、[MyBlueprint] タブで置き換えられました。 - * ブループリントの検索がリファクタリングされました。 - * ブループリントインターフェイス UI がリファクタリングされました。 - * グラフ アクション メニューでコンテキストに応じた選択肢を切り替える機能を追加しました。 -* ショートカット (F2) をサポートするノードのタイトルを編集するキーボード ショートカットを追加しました。 -* エンジンを修正することなくノード タイトルの名前変更のサポートを追加しました。 -* グラフ スキーマでノード テンプレートが作成される方法について様々な改善を加えました。 -* コメント ボックスに様々な改善を加えました (インプレース編集、ズームアウトまたはオーバーラップ時のヒット テストの向上)。 -* コンパイルしたダーティなアイコンの色の彩度を高め、色を変更した既存のアイコンを再コンパイルする必要があります。アート変更のみ - 非破壊です。 -* 変数追加、関数、マクロ、およびイベント グラフの新しいアイコンを作成しました。利用可能なサイズは 16px, 40px, および 512px です。新規アートアセット - 非破壊のチェックインです。 -* MovementComp_Projectile::StopMovement をブループリントにエクスポーズしました。 -* CallFunction のフィルタリングはフレンドリーネームに基づくようになり、該当する場合は簡潔な名前も使用します。 +* It is no longer necessary to compile a Blueprint in order to edit components after adding them in Components mode in the Blueprint editor. +* Clicking on entry/exit/collapsed nodes in a Blueprint graph now allows you to add inputs and outputs from the Details tab. +* Moved Blueprint settings into global user settings; they are now accessible through the Preferences Editor tab instead.Also removed the Settings menu from the Blueprint editor. +* Moved Blueprint Global Settings into the Details panel accessible via a new Blueprint Props toolbar button in the Blueprint Editor. + * Also relocated the Reparent feature from the Blueprint Editor toolbar into the Details panel (it is no longer present in the editor toolbar). +* Changing component properties in the Details panel of the Blueprint editor now properly updates any Actor instances based on the Blueprint being edited. +* The Break Links submenu no longer appears in a Blueprint graph if there is only one subitem; only the subitem itself is shown. +* The Components toggle button is now enabled when reparenting from a non-Actor to an Actor-based Blueprint in the Blueprint editor. +* The Blueprint is now dirtied after moving its components around in Components mode of the Blueprint editor. +* The Blueprint preview viewport now includes a postprocess volume with an ambient cube map. +* Component editing mode can no longer be activated for non Actor-based Blueprints in the Blueprint editor. +* Components mode can no longer be activated in the Blueprint editor when editing macro Blueprints. +* Blueprint stability work to improve refactoring and deprecating code. +* Added GetPlayerCharacter() blueprint function to UGameplayStatics; it's just like GetPlayerPawn(), but returns an ACharacter instead of an APawn for those who need access to character and character movement. +* When a Select Node has a compilation error due to receiving an input index value higher than the number of options it supports (such as when an enum has values added to it in code after being used in a graph), it now outputs a message with much more information to track down the particular problem.It now lists the full path of the blueprint in which the error occurred and the name of the select node's index type (i.e. bool, int, or the specific name of the enum). +* Deprecated blueprint functions can supply a helpful message using DeprecationMessage in the UFUNCTION meta section. +* Extensive UI and workflow polish for the Blueprint Editor. +* The delete button has been updated for Blueprint Macros details view inputs and outputs. +* New button artwork for the Replication State of Blueprint variables. +* Tidied up the Create and Harvest Blueprint buttons in the Details view. +* Message now shown when there are no results in the Find in Blueprints dialog. +* Blueprint functions are now checked that they exist when fetched by name. +* Blueprint editor windows now close first when exiting the editor. +* New icon for hide pins in blueprint editor, replaced existing placeholder icon hide_unusedpins.png - non-destructive art only update. +* New clearer icons required for the various Blueprint compile states.Replaced existing placeholder icon with new approved versions.Art change only - non-destructive. +* Created icon for Create Blueprint from Actor and Harvest Blueprint (replaced existing placeholder icons) - non-destructive update. +* Created new icons for 'Find in current Blueprint', 'Blueprint Options' & 'Diff against previous revision', sizes available - 40px & 512px.PNG assets only.Non-destructive check-in (requires code hook-up). +* External (ThirdParty) modules now add their include paths the PublicInclude paths. +* ThirdParty or system file include paths are not checked for forward vs back slashes. +* Re-adding interface FortInteractInterface to the blueprint (after removing) no longer results in an error. +* Blueprint functions can now be searched for by keywords +* LoadStreamlevel and UnloadStreamLevel blueprint actions will now do a partial match on the name provided and try to find a streaming level that ends with that string, not requiring full path. +* Blueprints are now preferred over other asset types when using find in content browser on an actor. +* Blueprint Compiling:Autogenerated variable names now include node GUIDs for disambiguation +* Improved workflow of Create Blueprint in the details panel. +* Ongoing UI polish to the blueprint editor. + * Blueprint Explorer and Variables tabs have been fully deprecated and replaced with the MyBlueprint tab. + * Blueprint Searching refactored. + * Blueprint Interface UI refactored + * Added in ability to toggle context sensitivity in the graph action menu. +* Added a keyboard shortcut to edit the node title of any nodes that support it (F2) +* Made it possible to add node title renaming support to any node without engine modifications +* Various improvements to how node templates are created in graph schemas +* Various improvements to comment boxes (in-place editing, better hit testing when zoomed out or overlapping, etc...) +* Needs to be recompiled icon updated existing icons with more colour saturation & a change of color for Compiled - Dirty icon.Art change only - non-destructive. +* Created new icons for Add Variable, Function, Macro, and Event Graph.Sizes available at 16px, 40px, and 512px.New art assets - none destructive check-in. +* Exposed MovementComp_Projectile::StopMovement to Blueprints. +* Filter for CallFunction is now based on friendly name and, if applicable, will also use compact name -#### フレームワーク +#### Framework -* ACharacter::BaseChange() and JumpOff(): の改善点: - * ACharacter::BaseChange() は、ワールド ジオメトリであってもキャラクターがそれに基づいた「実際の」アクタをチェックし、CanBeBaseForCharacter() であるかを確認するようになりました。他の目的でワールド ジオメトリである特定タイプのアクタ (およびWorldInfo をベースとして戻すもの) は、キャラクターに対して正確に JumpOff() するように指示することができるようになりました。 - * MovementComp_Character::JumpOff() は movement ベースを引数としてとり、派生クラスがそれらが立っている実際のアクタに基づきハンドリング (ジャンプ方向を選択など) をオーバーライドできるようにしました。 - * 新規関数、UMovementComp_Character::GetBestDirectionOffActor(...) を記述しました。これは、キャラクターの速度、ベースとなるアクタの寸法などに基づきジャンプの選択をオーバーライドすることができます。 - * コードでのマジック ナンバー(0.5 z 値) を JumpOffJumpZFactor としてエクスポーズしました。このパラメータを使用して、キャラクターのベースにはなりえないものからジャンプする場合にジャンプの高さを微調整できます。 -* **コリジョン** - * デフォルトのポーンがラグドールになるまで物理オブジェクトとインタラクションしないようにしました。 - * チャンネルを ECC_Touch から ECC_Overlap に名前変更しました。 -* Physx メモリ使用量が GetResourceSize によってレポートされます。 -* エンジン バージョンに加えてゲーム バージョンもブランチ名、ビルド設定、およびコマンド引数を戻します。これをクリップボードにもコピーし、TTP で簡単に貼り付けできるようにします。 -* 実行関数のロード / アンロード / リロードでは、モジュールのクリーンアップのプレ / ポストのコールバックを利用しました。 -* GWorlds の全体的削減。 -* 実行関数はリファクタリングし、コマンド機能はコマンド毎の関数に移動しまし。 -* UMovementComponent::SetPlayerDefaults() を削除しました。エンジンでは不要であり、リセットしたいものはゲーム固有のものです。 -* プレイヤー コントローラが停止状態であれば Modifier キーが処理されるようになりました。つまり、ゲーム停止中は GPU プロファイラにアクセス可能であるか、シェーダーが再コンパイル可能であることを意味します。 -* FTransform の Get/SetOrigin は Get/SetLocation に名前変更されました。 -* ライフスパンの実装を改訂しました。 -* グローバルでキャンバス コンテキストに渡されていた一部のキャンバス関数はキャンバス クラスに移動しました。 -* エディタ固有のアクタのラベル付け関数をアクタ クラスから移動しました。 +* Improvements to ACharacter::BaseChange() and JumpOff(): + * ACharacter::BaseChange() now checks the ACTUAL actor the character is based on even if it is World Geometry to see if it CanBeBaseForCharacter().Specific types of actors that are WorldGeometry for other purposes (and so would return the WorldInfo as the base) can now correctly direct characters to JumpOff(). + * MovementComp_Character::JumpOff() now takes the movement base as an argument so that derived classes can override handling (such as choosing the direction to jump) based on the actual actor they're standing on. + * Wrote a new function UMovementComp_Character::GetBestDirectionOffActor(...) which can be overridden to choose to jump based on character velocity, base actor dimensions, etc. + * Exposed a magic number in code (0.5 z value) as JumpOffJumpZFactor.This parameter can be used to tweak the height of a jump when jumping off something that can't be a base for a character. +* **Collision** + * Disabled default pawn to interact with physics object until they turned to ragdoll + * Renamed channels from ECC_Touch to ECC_Overlap +* Physx memory footprint is now reported by GetResourceSize. +* GameVer in addition to Engine Version, will also return Branch Name, Build Configuration and Command Arguments.Will also copy this to the clipboard for easy pasting in TTP. +* load/unload/reload exec functions now utilized pre/post callbacks for module cleanup. +* General reduction of GWorlds. +* Exec functions refactored and command functionality moved into per-command functions. +* Removed UMovementComponent::SetPlayerDefaults().Not needed in engine, plus what you might want to reset to is game specific. +* Modifier keys are now processed when the player controller is in a paused state.This means that the GPU profiler can be accessed or shaders can be recompiled while the game is paused. +* Get/SetOrigin renamed to Get/SetLocation on FTransform +* Revised lifespan implementation +* Some canvas functions that were global and were passed a canvas context have been moved into canvas class. +* Moved editor specific actor labeling functions out of actor class. -#### エンジンとコア +#### Engine and Core -* UnrealBuildTool の起動時間は大幅に改善されました。 -* 「プラグイン」サポートは現在部分的に実装されています。将来のリリースでこれをさらに堅牢にすべく開発に取り組んでいます。 - * テスト目的で 2 つのプラグイン例を追加しました。 -* `bAllowManagedCode` と `WITH_MANAGED_CODE` は完全に削除しました。 -* `LoadANSITextFileToStrings` は空の行を保持します。 -* `FCoreDelegates::LevelAddedToWorld`, `FCoreDelegates::LevelRemovedFromWorld` はゲーム内およびエディタで呼び出されます -* `GetCategory` と `GetCategoryFName` を UProperty から移動しました。これらは、`FObjectEditorUtils` ネームスペースのユーティリティ関数になりました。 -* 分析を最初に実行するときに、エンジンはハードウェアの統計情報を収集するようになりました (現時点では、Windows のみ)。 -* Live Preview、 Stats Profiler、 および Memory Profiler のすべてのアイコンが再作成されました。ビルドを破壊しないチェック - チェンジリストは PNG アセットのみ。 -* 不良コマンドライン'-' ケースは見つけられ、アプリケーション終了前にユーザーに通知します。 -* メッセージング: メッセージの非シリアル化/シリアル化および移植について改善作業中です。 -* UObjectnative ネイティブの基本クラスは、'F' で始まる必要はなくなりました。 -* リモートのデバッグ セットアップ - * Engine.ini は以下の設定になります。 +* UnrealBuildTool startup times have been greatly improved. +* "Plugin" support is now partially implemented.We're still working on making this more robust for a future release. + * Two example plugins were added for testing purposes. +* Fully eliminated `bAllowManagedCode` and `WITH_MANAGED_CODE` +* `LoadANSITextFileToStrings` now preserves empty lines. +* `FCoreDelegates::LevelAddedToWorld`, `FCoreDelegates::LevelRemovedFromWorld` now called in game and editor +* Moved `GetCategory` and `GetCategoryFName` out of UProperty - these are now utility functions in the `FObjectEditorUtils` namespace +* Engine now gathers hardware stats on first run for analysis (currently Windows only). +* All icons recreated for Live Preview, Stats Profiler, & Memory Profiler. replaced existing placeholder icons.Non-destructive checking - Change List is PNG assets only. +* The bad command line '-' case is now caught and informs the user before exiting the app. +* Messaging: ongoing improvements for message de-/serialization and transport +* UObject native base classes no longer have to start with 'F'. +* Remote debugging setup + * Engine.ini has the following settings: [Engine.ErrorHandling] bPromptForRemoteDebugging=false bPromptForRemoteDebugOnEnsure=false - * いずれかが true に設定されると、クラッシュ発生時にリモートで問題をデバッグできるようにプログラマに依頼するように促されます。 - * 2 つめが true であれば、ensure でもプロンプトされます - * これらは、`-PROMPTREMOTEDEBUG` と`-PROMPTREMOVEDEBUGENSURE` を持つコマンドラインでも設定することができます。 + * If either is set to true, then the user will be prompted to get a programmer when a crash occurs so they can remotely debug the issue. + * If the latter is true, the prompt will also occur on ensures. + * They can also be set via the command line with `-PROMPTREMOTEDEBUG` and `-PROMPTREMOVEDEBUGENSURE` respectively. #### プラットフォーム -* エンジンとエディタを Mac へ移植中です。 +* Porting the engine and the editor to Mac * **Unreal Frontend** - * ランチャーは、新しいアンリアル プロジェクト ファイルを使用するようにアップグレード中です。現在は機能していません。 - * デバイス マネージャのツールバー アイコン、電源の on/off/reset の新しいアイコンを作成しました。コード合わせを必要とします。 - * スクリーンショットはリクエスト元であるフロントエンドのアプリケーションに直接送られるようになりました。 - * デバイス マネージャの新規レイアウト - **Power On**, **Power Off**, および **Reboot** をコーディングしました。 -* DependencyCache.bin ファイルはプラットフォーム毎に存在するようになりました。 -* モジュール ルールでは、DLL のビルド時に使用する `BinariesSubFolder` を指定することができます。例: - `BinariesSubFolder=IOS` の場合、その結果の Win64 ビルドの DLL は、 `Engine/Binaries/Win64/IOS` に入れられます。 + * The Launcher is being upgraded to use the new Unreal Project files; currently defunct + * Toolbar icons for Device Manager, created new icons for power on/off/reset.Require code hook-up. + * Screen shots are now sent to directly to the FrontEnd app that requested them + * Coded new layout for the Device Manager - **Power On**, **Power Off**, and **Reboot**. +* DependencyCache.bin files now exist per-platform. +* Module rules can now specify a `BinariesSubFolder` that is used when building DLLs.For example: + If `BinariesSubFolder=IOS`, the resulting DLL for Win64 builds would be placed in `Engine/Binaries/Win64/IOS` -* Game または Server がデスクトップ プラットフォームをターゲットとする場合、特に指定しなければ Sandbox ディレクトリが推定されます。 -* `PhysX3Common` を `Engine/Binaries/ThirdParty` フォルダに移動しました。エンジンの一部として読み込む必要がなくなったからです。 +* If Game or Server target for Desktop platforms, the Sandbox directory will be inferred if not specified. +* Moved `PhysX3Common` to the `Engine/Binaries/ThirdParty` folder as it is no longer required to load as part of Engine -#### オンライン +#### Online -* Steam ロビーがいっぱいであると判断した場合に、Steam ロビーはジョイン機能を自動設定します。 +* Steam lobbies auto set join-ability when it is determined the lobby is full #### オーディオ -* スペースバーを押してエディタ内の現在のサウンド キューを再生、停止できるようになりました。 -* 右のサラウンド スピーカは 6 チャンネル ogg ファイルを使用しても音が弱まらなくなりました。 -* 関連するサウンド ノードが取り除かれるとグラフ ノードが削除されるようになりました。 -* マルチチャンネル サウンドを再インポートすることができます。 -サウンドキュー エディタで接続の切断を元に戻すことができるようになりました。 -* SoundModes は、サウンド再生中に SoundClasses からアクティベートできるようになりました。 -* サウンドウェーブ アセットはサムネイルで波形を表示するようになりました。 -* VOIP データ送信を積極的に使用。 - * 最高 1k までのすべての音声データをまとめて一回で直ちに送信。 - * 複数フレームでデータをバッファリングしなくなりました。 +* Can now play and stop the current Sound Cue in the Editor by hitting the spacebar. +* Surround right speaker is no longer muffled when using 6 channel ogg files. +* Graph Nodes will now be deleted if associated Sound Node is removed. +* Now able to re-import multichannel sounds. +* Can now undo the breaking of connections in Sound Cue Editor. +* SoundModes can now be activated via SoundClasses when sounds are playing. +* SoundWave assets now display a wave form in their thumbnail. +* More greedy VOIP data transmission + * send all voice data up to 1k in one bunch immediately + * no longer buffering data at all over multiple frames #### エディタとツール -* **スレート** - * スレート UI の MultiLineEditableText 機能を開発中。 - * SColorBlock が無効になったスタイリングを使用しないように変更しました。 - * 空の MultiBoxs がそのウィジェットを作るときに余分な場所をとらないようにしました。 -* **ユーザーインターフェース (UI)** - * エディタは開くときに、前のウィンドウの後ろでポップアップしなくなりました。 - * AutonomousTabPanel を NomadTab に名前変更しました。関連する関数名、コメント、および変数を修正しました。 - * タブが既にスポーンされていれば、レイアウトの復元時にノマドタブ スポーナーはタブをスポーンしなくなりました。 - * ノマドタブを主なタブエリアにドッキングできます。ノマドタブはフローと時または主なタブエリアにドックされるときに主要タブのようにスタイリングされます。 - TabSpawnerEntries にはメニュー配置をオプトアウトする機能があります。 - * レガシー タブ タイプのサポートを追加しました。これにより、レガシータブ名をスポーン時の自動変更 ID に登録することができます。 - * エンジン全体で AddHeader のすべての使用と AddMenuSeparator のほとんどの使用を取り除きました。 - * メインのエディタ メニュー (視覚的、配置など) に多くの改善を施しました。 - * 詳細ビューでプロパティ マトリクス ボタンを更新しました。 - * 新しいイラストで Vertex Density モード メニューを更新しました。 - * イマーシブ モードのリストア ボタンを更新しました。 - * フォーリッジ モードの保存 / 読み込みの設定のアイコンのイラストを更新しました。 - * ツールバーとメニューバーのボタンがクリップされた場合、クリックするとクリップしたアイテムを含むコンテキスト メニューを生成する拡張ボタンが表示されます。 - * 元に戻す/リドゥ (取り消しの取り消し) メニュー オプションが再度アイコンを持つようになりました。 - * WorkflowTab は Windows メニューのアセット エディタ カテゴリにリスト表示されます。 - * アルファ値が低い新しい ' x' (削除ボタン) を作成しました。ビルドを破壊しないチェックイン - アート アセットのみ。 - * プロパティ マトリクス ボタンと関連するウィンドウ/メニュー アイテムに対して新しい 16px アイコンを作成しました。コード合わせを必要とします。 - * イマーシブ ボタン アイコンからのリストア - 新しい 16px アイコンを作成しました。コード合わせを必要とします。ビルドを破壊しないチェックイン - アート アセットのみ。 - * エディタのレプリケーション アイコンに新しいアイコンを追加し、ステート変更に対してコード合わせをします。ビルドを破壊しないチェックイン - アート アセットのみ。 - * ビューポートに以下のアイコンを新たに作成しました。Vertex Density. 新たにコード合わせが必要です。アート アセットの置換のみであり、非破壊更新です。 - * フォーリッジ モードにアイコンを新たに作成しました。アート アセットの置換のみであり、非破壊更新です。 - 以下のすべてのアクタ クラスに対して新しい 16px アイコンを作成しました。ArrowComponent, AtmosphericFogComponent, BoxComponent, CapsuleComponent, DestructibleMeshActor/Component, InstancedStaticMeshComponent, MaterialSpriteComponent, RadialBlurComponent, SceneCapture(Component), SceneCapture2D(Component), SceneComponent, SphereComponent, SpriteComponent, TextRenderActor/Component.PNG アセットのみです。ビルドを破壊しないチェックイン (コード合わせが必要) - * すべてのメイン エディタのツールバー アイコンを再作成および更新しました (別の TTP で代替再生オプションの追加アイコンがカバーされています)。ビルドを破壊しないチェックイン - 変更リストは 512px でより高い解像度のアセットのみを追加します。 - * レベル ブラウザ メニューに対して 新規 16px アイコンを作成しました。新しい PNG ファイル、非破壊チェック - コード合わせが必要。 - * 削除した actors. size のアイコンを新たに作成しました。16px. - 非破壊更新です。 -* データとカーブのテーブル アセットに対して、_explore to directory_ と _launch in external editor_ サポートを追加しました。 -* navmesh 生成のパフォーマンスを向上させました。 -* **シーン アウトライナー** - * SIE モード時に黄色のボーダーが表示されます。 - * 新規レベルが追加または削除されるとコンテンツが正確にリフレッシュされます。 - * シーン アウトライナーでは、検索結果にネスティングされたアクタが正確に表示されるようになりました。 -* レイヤーの実装をリファクタリングし、コードパスを簡素化し、統合しました。 -* **プロジェクトのワークフロー** - * 新規プロジェクトのダイアログのビジュアルを改善。 - * プロジェクトの切替時にエディタ起動時に使用したコマンドライン引数が維持されるようになりました。 - * プロジェクトの切替時に終了ダイアログが表示されなくなりました。 - * '^' 文字は、visual studio と混乱を招くため、プロジェクト ファイルのパスでは認められなくなりました。 -* **コンテンツ ブラウザ** - * 最初のアセット検索後に従属関係について再スキャンされたパッケージが適切に更新されるようになりました。 - * コンテンツ ブラウザで explore が選択されている場合、フォルダはオンデマンドで作成されるようになりました。 - * 名前変更プロセスの早い段階でのより良いアセット名のチェック機能を追加し、フレンドリーな新しいネーム コード パスの入力をトリガーできるようにします。 -* GetLabels を FSourceControl に追加し、指定されたパターン文字列に合致するソース コントロールにあるすべてのラベルを戻します。 -* CrashReporter: ウェブサイトはすべてのブラウザについてほとんど行われており、何もかも意図したとおりに機能しています。まだやり残している主なものはドキュメント作成です。 +* **Slate** + * Working on MultiLineEditableText feature for SlateUI + * Changed SColorBlock to not use disabled styling + * Empty MultiBoxs no longer take up additional room when constructing their widget. +* **User Interface** + * The editor no longer pops up behind previous windows when opening. + * Renamed AutonomousTabPanel to NomadTab.Fixed up associated function names, comments, and variables. + * Nomad tab spawners no longer spawn their tab when restoring layout if the tab has already been spawned. + * Nomad tabs can now be docked in major tab wells.Nomad tabs are now styled like Major tabs when floating or docked in major tabwells. + * TabSpawnerEntries now have the ability to opt-out of menu placement. + * Added support for legacy tab types, which allows legacy tab names to be registered to auto-change IDs at spawn time. + * Removed all uses of AddHeader and most uses of AddMenuSeparator throughout the engine. + * Lots of polish to main editor menus (visuals, arrangement, etc.) + * Updated the Property Matrix button in the Details view. + * Updated the Vertex Density mode menu item with new artwork. + * Updated the immersive mode's Restore button. + * Updated icon artwork for Foliage Mode save/load settings. + * An expansion button is displayed when toolbar and menu bar buttons get clipped which, when clicked, generates a context menu containing the clipped items + * Undo/Redo menu options have icons again. + * WorkflowTabs now appear listed under the Asset Editor category of the Windows menu. + * Created new ' x' (delete button) with less alpha.Non-destructive check-in - art asset only + * Created new 16px icon for Property Matrix button & related windows/menu items.Requires code hook-up. + * Restore from Immersive button icon - created new 16px icon, requires code hook-up.Non-destructive check-in, art asset only. + * New icon for Replication icon for editor, to be hooked up in code for state changes.Non-destructive check-in, art asset only. + * Created new icon for Viewport:Vertex Density. requires additional code hook-up.Art asset replacement only, non-destructive update. + * Created new icons for the Foliage Mode.Art asset replacement only, non-destructive update. + * created new 16px icons for all the following actor classes, ArrowComponent, AtmosphericFogComponent, BoxComponent, CapsuleComponent, DestructibleMeshActor/Component, InstancedStaticMeshComponent, MaterialSpriteComponent, RadialBlurComponent, SceneCapture(Component), SceneCapture2D(Component), SceneComponent, SphereComponent, SpriteComponent, TextRenderActor/Component.PNG assets only.Non-destructive check-in (requires code hook-up). + * All main Editor toolbar icons recreated & updated (additional icons for alternative play options are covered in another TTP).Non-destructive check-in - Change List is only adding higher resolution assets at 512px. + * Created new 16px icons for the Level Browser menu.New PNG files, none destructive checking - requires code hook-up. + * Created new icon for deleted actors. size:16px. - non-destructive update. +* Added _explore to directory_ and _launch in external editor_ support for data and curve table assets. +* Improvements to navmesh generation performance +* **Scene Outliner** + * Now has a yellow border when in SIE mode + * Correctly refreshes content when new level added or removed + * Scene Outliner now displays nested actors correctly in the search results. +* Refactored Layers implementation to simplify and consolidate code paths +* **Project Workflow** + * Visual improvements for the new project dialog. + * Switching projects now preserves the command line arguments used to launch the editor. + * Quit dialog no longer appears when switching projects. + * '^' characters are no longer allowed in project file paths since it confuses visual studio. +* **Content Browser** + * Packages that get re-scanned for dependencies after the initial asset search will now properly update. + * Folders are now created on demand if explore is chosen in the Content Browser. + * Added better asset name checking early in the rename process in the Content Browser so we can trigger the friendly enter a new name code path. +* Added GetLabels to FSourceControl, which returns all labels in source control matching the supplied pattern string +* CrashReporter: web site is mostly done for all browsers, everything is working as intended.Major item left is documentation. * **ランドスケープ** - * ランドスケープ アクタを読み込むことなくランドスケープ プロキシを編集する機能を追加しました。 - * ランドスケープ プロキシは独自の元となる場所を持ちますが、必ずしもランドスケープ アクタの位置と同じ場所ではありません。 - * ランドスケープ スプラインは静的コンポーネントとみなされるようになりました。 - * ランドスケープの静的ライトは高さマップを変更するときに無効化されるようになりました。 - * ランドスケープ スプラインのエンド制御点を削除するための ** Are you sure?** ボタンにあるキャンセル ボタンは実際には削除を再度キャンセルします。 - * ランドスケープ エディタはすべてのビューポートをリアルタイムにします。アクティブな perspective (透視図法) ビューポートだけでなく、加えられた変更を簡単に見れるようにします。 - * 新規作成のレイヤー情報オブジェクトがコンテンツ ブラウザに表示され、保存/ 終了時に保存されます。 - * "new layer info" パス テキスト ボックスをフォルダ ピッカーにしました。 -* **マチネ** - * マチネのドロップダウン メニューは、ポッピングを防ぐために正確なサイズでスポーンされるようになりました。 - * マチネのダイアログ テキストの表現を変えて、タブ位置に言及しないようにしました (タブ位置は移動することがあるため)。 - * アクタのレベルがレベル ブラウザで削除された場合に、マチネが閉じるようになりました。 - * カメラ アクタのメッシュを更新し、新しいカメラ アイコンと一貫性がある新しいメッシュを作成し、マテリアルとテクスチャを追加しました。 - * 補間関連のユーティリティ コードをリファクタリングしました。FMatineeUtils ネームスペースに入っています。 - * マチネ トラックの最初のサウンドにサブタイトルが表示されるようになりました。 -* **レベル エディタ** - * レベル エディタ タブは、切り捨てられたレベル名を再度表示するようになりました。 - * 起動時にエディタがどのマップを読み込むかを指定するための新規 config 設定 (DefaultMapName) を追加しました。 - * これは SimpleMapName パイプラインとは異なりますが、コマンドラインでマップ名が指定された場合に似た挙動をします。 - * ロックしたアクタを別のビューポートに移動した場合にビューポートはカメラ位置を更新するようになりました。 - * 番号付けされたアクタを複製すると、新規アクタに次の論理番号をラベル付します。 - * アクタの複製時に 0 の前の部分で自動ネーミングが維持されます。 - * アタッチメント - * 親とその子をドラッグすると、アクタの変形は積み重ねられません。 - * アクタをコピーし貼り付けすると、親子付の階層が維持されるようになりました。 - * 複数のアクタを同じく選択中の別のアクタにアタッチすると、エラーが発生するようになりました。 - * 親がその子孫の子として割り当てられることを防ぎます。 - * キーボードのショートカットは所有/制御解除 (eject ) ボタンのツールチップに表示されるようになりました。 -* BrushEdit が有効な場合に BuildingWall の切替えが可能になりました。 -* LOD (Level of Detail) グループのポップアップの表現を変更してわかりやすくしました。 -* アセット移行ダイアログからパッケージの使用を削除しました。 -* 被破壊メッシュを作成すると、コンテンツ ブラウザで編集しアセットと同期するためにも開きます。 -* エディタが閉じると PlayOn インスタンスは消去されます。 -* スタティックメッシュ エディタで固有の UV を生成することで生じるエラーは通知として表示されるようになりました。 -* ソケット マネージャのウィジェットはレベル エディタ ツールバーからの切替時に正確に更新されるようになりました。 -* ドラッグしたアセットはより正確にヒット プロキシ アクタにスナップされるようになりました。 -* MIC (マテリアル インスタンス定数) パラメータのオーバーライド フラグを切り替えるとマテリアルが更新されるようになりました。 -* スクリーンショットのキャプチャ テストとブラウザの更新を自動化しました。 -* 警告メッセージに関数名コンテキスト情報を追加しました。それがどこからきたかを追跡するためのものです。 Warning: B oneIndex for Bone (b_MF_Hand) is not found in the Skeleton (M_Avg_Base_AnimSkeleton) -* デバッグ作業シアンとマゼンタのデフォルトの FColors を追加しました。DrawDebugCircle を追加しました。 -* マテリアル スロットを持つスタティック メッシュでLOD (Level of Detail) によって参照されていないものは読み込み時に NULL になります。関係のないインデックスも調整されるようになりました。 -* ReferenceViewer はノマド タブになりました。 -* 初期テクスチャを持つマテリアルを作成すると、テクスチャを基本色に適切に接続します。 -* **イベント ビューア:** - * 時間毎にイベントをよりよくソーティングするようにイベント ビューアを更新しました。 - * 階層の各イベントに対してより多くの情報が提供されるようになりました。 -* スタティックメッシュ エディタソケットを表示/非表示にするとスタティックメッシュ エディタのビューポートがリフレッシュされます。 -* アクタを変換するワークフローが改善されました。 -* ツールヒントと一緒にワールド設定が表示されるように、[World Properties] ボタンを更新しました。 -ブループリントユーティリティ (Blutility) はEpic Labs の環境設定 (preference) になりました。 -* ストリーミング レベルのエディタのみのオフセットが実装されました。さらに新しいオプションのコラムをレベル ブラウザに追加し、各ストリーミング レベルに対してエディタのみのオフセットの設定をできるようにしました。 -* 新しいプレースメント ブラウザのモード / ツールセットを作成しました。これは、新規ユーザーとレベル デザイナのワークフローを支援します。 -* ユーザーが書き込みを許可されていないフォルダにあるパッケージを修正するときに警告ダイアログを追加しました。 -* アセットを移行し、パッケージがディスク上にない場合、それについてプロンプトが表示されます。 + * Added ability to edit landscape proxies without loading LandscapeActor + * Landscape proxies now can have own origins not necessarily at the same location as landscape actor position + * Landscape splines are now considered to be static components + * Landscape static lighting is now invalidated when altering the heightmap + * Cancel button on the** Are you sure?** button for deleting end control points of a landscape spline actually cancels the delete again. + * Landscape editor now forces all viewports to real-time, not just the active perspective viewport, making it easier to see changes being made + * Newly created layer info objects now show up in the content browser and want to be saved when saving / quitting. + * Replaced the "new layer info" path text box with a folder picker. +* **Matinee** + * Matinee drop down menu now spawns at the correct size to avoid popping. + * Reworded matinee dialog text to not mention tab position (as it can be moved). + * Matinee now closes when that actors level is remove via the level browser. + * Camera actor mesh updated, created new mesh consistent with new camera icons, added material & texture. + * Refactored interp-related utilities code - it is now in the FMatineeUtils namespace + * Subtitles now shown for first sound in a matinee track. +* **Level Editor** + * Level editor tab again shows truncated level name. + * Added a new config setting (DefaultMapName) for specifying what map the editor should load on startup + * This differs from the SimpleMapName pipeline and, instead, resembles the behavior of when the map name is specified via the command line + * Viewports now update their camera position if their locked actor is moved in another viewport. + * Duplicating numbered actors, labels the new actor with the next logical number. + * Auto-naming now preserved preceding 0s when duplicating actors. + * Attachments + * Actor Transformations no longer stack up if dragging a parent and its child. + * Copy and Pasting actors will now maintain the parenting hierarchy. + * Attaching multiple actors to another actor which is also selected now produces and error. + * Prevent parents becoming assigned as the children of their descendants. + * Keyboard shortcut now appears in the possess/eject button tooltips. +* BuildingWall toggling now possible when BrushEdit is active. +* Reworded LOD group popup to be clearer. +* Removed usage of package from asset migration dialog. +* Creating Destructible Mesh now also opens for edit and syncs to asset in Content Browser. +* PlayOn instances are killed when the editor closes. +* Any error generated by generating unique UVs in the static mesh editor is now displayed as a notification. +* Socket Manager widget now updates correctly when toggled from the level editor toolbar. +* Dragged assets now snap more accurately to the hit proxy actor. +* Toggling the override flag on a MIC param now updates the material. +* Automated Screen Shot capture test and browser update +* Added function name context info to warning message.To help tracking down where it comes from. Warning:BoneIndex for Bone (b_MF_Hand) is not found in the Skeleton (M_Avg_Base_AnimSkeleton) +* Debugging:Added Cyan and Magenta default FColors.Added DrawDebugCircle. +* Static Meshes with Material slots that are not referenced by any LOD are now NULLed on load.Extraneous indices are now trimmed as well. +* The ReferenceViewer is now a Nomad Tab. +* Creating a material with an initial texture now properly hooks up the texture to the base color. +* **Event Viewer:** + * Updated Event Viewer to better sort the events by time. + * More information provided for each event in the hierarchy. +* Static Mesh Editor:Showing/hiding sockets now refreshes the Static Mesh Editors viewport. +* Workflow for converting actors has been improved. +* The World Properties button has been updated to say World Settings, along with its tooltip. +* Blutility is now an Epic Labs preference. +* An Editor-only offset for streaming levels has been implemented, and a new optional column added to the Level Browser that allows setting of an Editor-only offset for each streaming level. +* Creating a new placement browser mode/toolset which will aid new users and level designers in their workflow +* Added a warning dialog for when the user modifies a package that is in a folder that they do not have permission to write to. +* When you are migrating assets and a package does not exist on disk, the user is prompted about it. #### レンダリング -* スプラインメッシュが作成するシェーダーの置換数を 1 頂点ファクトリ (パラメータ化) に減らし、最適化しました。 -* スプラインで変形したスタティックメッシュは LOD をサポートするようになりました。 -* スプラインで変形したスタティックメッシュは静的ライトでライティングできるようになりました。 -* マテリアル エディタのクリーン アップはマテリアルが変更されるとマテリアルのみをダーティにします。 -* カスケード カラーピッカーはカスケード ビューポートの子として登録されます。 -* カスケード レイアウトは正確にロードされるようになりました。 -* 現在、LOD (Level of Detail) ドロップダウンは 0 から開始し、プロパティ配列と合致します。 -* カスケードで Lowest/Highest LOD ボタンの機能を取り替えます。 -* 固定境界の設定時のカスケードの不要な確認ダイアログを削除しました。 -* ConditionalProcessCommandBindings はキー / マウスボタンの保持 / 繰り返し状態を渡し、true の場合にコマンドを無視します。 -* シミュレーション時の再親子付けのオプションが無効になりました。 -* 自動保存通知は、時間の代わりに %d で表示しなくなりました。 -* カスケード エミッター カテゴリは、表示する有効な子が存在する場合に限り表示されるようになりました。 -* スケルタル メッシュ エディタは、現在のスケルタルメッシュを開くときに、前回のスケルタルメッシュの階層を表示しなくなりました。 -* サブサーフェス スキャタリングの色のバンディングの改善。 -* 破砕された被破壊性オブジェクトはデカールを受けなくなりました。 -* IES ライト プロファイルにライトが割り当てられると、IES 輝度を使用するか否かを選択したかについて計算されたテクスチャ乗数を使用します。 -* パーティクルエミッタは、カスケードで機能が有効になっている場合にローカルの z 軸を正確にカメラに向けるようになりました。 -* アクタのスケーリングが GPU パーティクル システムで考慮されるようになりました。 -* モーション ブラーを維持するポーズを追加しましたが、まだ作業が必要です。 -* OpenGL 4.3 による SM5 レンダリング機能を実験的にサポートしています。 -* マテリアルのサムネイル シーンでスタティック メッシュのチェック、、GetViewMatrixParameters をなくしました。ビュー マトリクスを判断することは技術的に不要だからです。 -* さらに Gbuffer 視覚化モードを追加しました。 -* 透過モードを混ぜあわせたもの (法線、分離) を持つ様々なマテリアルを使用する複数のパーツを持つスタティックメッシュのプリミティブが正確にレンダリングされるようになりました。 -* エディタ内のシーンからカリングボリュームが削除されると、この変更を反映するためにすべてのスタティックメッシュのプリミティブでは描画距離が更新されます。 -* atmospheric fog コンポーネントの "Visible In Game" フラグが考慮されるようになりました。 +* Reduced the number of shader permutations created by the spline mesh shader to one (parameterized) vertex factory, and optimized. +* Spline-deformed static meshes now support LODs. +* Spline-deformed static meshes can now be lit by static lighting +* Material Editor clean up now only dirties the material if its changed. +* Cascade color picker now registered as a child of the cascade viewport. +* Cascade layout now loads correctly. +* Current LOD dropdown now starts at 0, to conform with properties array. +* Swap Lowest/Highest LOD button functionality in Cascade. +* removed unnecessary confirmation dialog in Cascade when setting fixed bounds. +* ConditionalProcessCommandBindings now passed held/repeat state of key/mouse button, and ignores any commands if its true. +* Reparent option is now disabled when simulating. +* Autosave notification no longer says %d instead of the time. +* Cascade emitter categories now only appear if there are valid children to display. +* SkeletalMesh Editor no longer displays the hierarchy of the last skeletal mesh when opening the current one. +* Improvements to banding on subsurface scattering colors. +* Destructible objects which have been fractured will now no longer receive decals +* When a light has been assigned an IES light profile, it will use the calculated texture multiplier whether you choose to use the IES brightness or not. +* Particle emitters now correctly orient the local z-axis towards the camera when this feature is enabled from Cascade +* Actor scaling is taken now into account for GPU particle systems. +* Added pause keeping Motion Blur, still needs some work +* There is now experimental support for SM5 rendering features via OpenGL 4.3. +* Removed check for static mesh in the material thumbnail scenes GetViewMatrixParameters as it is not technically required to determine the view matrix. +* Added more Gbuffer visualize modes +* Static mesh primitives with multiple parts using different materials which had mixtures of translucency modes (normal and separate) will now render correctly +* When a culling volume is deleted from the scene in the editor, all static mesh primitives will have their draw distances updated to reflect this change. +* "Visible In Game" flag on the atmospheric fog component is now respected #### アニメーション -* ペルソナ ビューポートの表示メニューの "Preview Mesh" アイテムを "Mesh" に変更しました。 -* アニメーション ノードでピンでエクスポーズ可能なプロパティのレイアウトを改善しました。 -* UAnimMontage::GetSectionTimeLeftFromPos() を追加しました。 -* 方位角 (Azimuth) と高度 (Elevation) の演算コードを修正し、リファクタリングしました。 -* GetClosestCollidingBoneLocation を SkinnedMeshComponent から SkeletalMeshComponent に移動し、実際に衝突している剛体に対してチェックするようにしました。衝突していないものを戻し、トレースに失敗することがあります。 +* Changed "Preview Mesh" item on Persona viewport show menu to "Mesh" +* Improved layout of pin-exposable properties on animation nodes +* Added UAnimMontage::GetSectionTimeLeftFromPos(). +* Fixed and refactored Azimuth and Elevation math code. +* Moved GetClosestCollidingBoneLocation from SkinnedMeshComponent to SkeletalMeshComponent, and made it actually check against colliding rigidbodies!It could return a non colliding one, and traces would fail. diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/May/ReleaseNotesMay2013.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/May/ReleaseNotesMay2013.KOR.udn index 371449f261dc..1333389331f0 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/May/ReleaseNotesMay2013.KOR.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/May/ReleaseNotesMay2013.KOR.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3367470 Availability:Licensee Title: 2013년 5월 릴리즈 노트 Crumbs:%ROOT%, Support/Builds Description: -Template:ReleaseNotes.html +Parent:Support/Builds +Order:-9 [TOC(start:2 end:2)] @@ -172,7 +173,7 @@ Template:ReleaseNotes.html * 계층형 * 포함 시간(합산)에 따른 목록형 * 제외 시간(합산)에 따른 목록형 - * 기본적인 "핫 패쓰 펼침", 핫 패쓰에 대한 컬러 코딩 기능을 구현했습니다. + * 기본적인 "핫 패스 펼침", 핫 패스에 대한 컬러 코딩 기능을 구현했습니다. * 이벤트 그래프에 대한 맥락 메뉴를 추가했습니다 (완벽 구현되지는 않았습니다). * 통계 종합 기능을 추가했습니다 (첫 반복처리 작업). * 데이터 그래프 요약에 종합된 통계 정보와 함께 현재 통계 값이 표시됩니다. @@ -611,7 +612,7 @@ Template:ReleaseNotes.html * **콘텐츠 브라우저** * 첫 애셋 검색 이후 의존성을 재탐색한 패키지도 이제 제대로 업데이트됩니다. * 콘텐츠 브라우저에 explore 가 선택된 경우 요청에 따라 폴더가 생성됩니다. - * 콘텐츠 브라우저 이름변경 프로세스 초기에 더 나은 애셋 이름 검사를 추가, 편하게 새로운 이름 코드 패쓰 입력이 가능합니다. + * 콘텐츠 브라우저 이름변경 프로세스 초기에 더 나은 애셋 이름 검사를 추가, 편하게 새로운 이름 코드 패스 입력이 가능합니다. * FSourceControl 에 GetLabels 를 추가, 소스 콘트롤에서 제공된 패턴 문자열에 일치하는 모든 라벨을 반환합니다. * CrashReporter: 웹사이트가 모든 브라우저에 맞게 거의 완성되었으며, 모두 정상 작동하고 있습니다. 남은 주요 작업은 문서화 작업입니다. * **랜드스케이프** diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/Oct/ReleaseNotesOctober2013.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/Oct/ReleaseNotesOctober2013.JPN.udn index 73a2900e8570..916a1580a0a3 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/Oct/ReleaseNotesOctober2013.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/Oct/ReleaseNotesOctober2013.JPN.udn @@ -1,8 +1,10 @@ -INTSourceChangelist:2688164 +INTSourceChangelist:3367470 Title:2013年10月リリースノート Crumbs:%ROOT%, Support/Builds Description: Availability:Licensee +Parent:Support/Builds +Order:-4 [TOC(start:2 end:2)] @@ -22,22 +24,22 @@ Availability:Licensee * 現時点のエンジン開発ロードマップ: [UE4 Roadmaps](https://udn.unrealengine.com/questions/topics/roadmap.html) * 修正されたバグ: [UE4 Fixed Bugs October 2013](UE4_Fixed_2013_October.xlsx) - * 既知の問題: [UE4 Outstanding Bugs October 2013](UE4_Bugs_2013_October.xlsx) + * 周知のバグ: [UE4 Outstanding Bugs October 2013](UE4_Bugs_2013_October.xlsx) -##主な新機能 +## 主要な新機能 -####エディタとツール +#### エディタとツール * **新しいランドスケープ エディタ** * **ランドスケープ エディタ** の UI は現在、いろいろな改善を反映させて全体を再ビルドしています。 ![](LandScapeEditor01.png) * 用途に合わせてツールを 3 つのモードに分類しました。 - * **Manage** モードには、 **新規ランドスケープ** 、 **コンポーネント** 、 **スプライン** ツールが含まれています。 + * **Manage** モードには、**新規ランドスケープ**、**コンポーネント** 、**スプライン** ツールが含まれています。 * **Sculpt** モードには、リージョンの選択およびコピーペーストに加えて全てのスカルプト (高さマップ) ツールが含まれています。 * **Paint** モードにはペイント (ウェイト マップ) が含まれています。 - * ウィンドウ フィリング ツール セレクタを廃止し、シンプルなドロップダウン セレクタにしたため、UI がぐっとコンパクトになりました。 + * ウィンドウ フィリング ツール セレクタを廃止し、シンプルなドロップダウン セレクタにしたため、UI がとてもコンパクトになりました。 * ランドスケープ エディタを詳細パネルに基づくようにしました。その結果、エディタの残りの部分と整合が取れ、設定名と設定値の間の調整スプリッタなどの新機能が追加されます。 * スカルプト処理は、 _ペイント_ ではなく **スカルプト** と呼ばれるツールで行うようになりました。 @@ -64,7 +66,7 @@ Availability:Licensee ![](ViewportLayouts.png) * レイアウトを選択して、現在のタブ内のビューポートの配置を変更します。現在アクティブになっているレイアウトがオレンジ色で表示されます。 - * レイアウトは、 **レベルビューポート** の **[Keyboard Shortcuts]** (キーボード ショートカット) ウィンドウのコマンドとしても利用できます。 + * レイアウトは、 **レベル ビューポート** の **[Keyboard Shortcuts]** (キーボード ショートカット) ウィンドウのコマンドとしても利用できます。 * キーボードでレイアウトを切り替える場合、キーボード入力フォーカスによりビューポートのタブがコマンドで切り替えられます。ビューポートがフォーカスを持たない場合、特に何も起こりません。 * **新しい環境設定:Show Frame Rate and Memory (フレームレートとメモリの表示)** @@ -110,7 +112,7 @@ Availability:Licensee グラフ内で変数取得または編集設定のいずれかを選択します。 ![](EditingVariableDefaultValues01.png) - または、 **マイブループリント** リストで変数を選択します。 + または、**マイブループリント** リストで変数を選択します。 ![](EditingVariableDefaultValues02.png) @@ -121,7 +123,7 @@ Availability:Licensee ![](WildcardBlueprint01.png) - * この機能は以前まで、 **ForEachLoop** ノードと **ForEachLoopWithBreak** ノードを **StandardMacros** ライブラリに追加するために使用していました。 + * この機能は以前まで、**ForEachLoop** ノードと **ForEachLoopWithBreak** ノードを **StandardMacros** ライブラリに追加するために使用していました。 [REGION:caption] **変換前** @@ -167,25 +169,24 @@ Availability:Licensee * **UE4 の Oculus Rift サポート** * UE4 が Oculus Rift をサポートするようになりました! * Rift にプラグインし、ゲームを起動するだけで、 Oculus Rift を利用できます! - - Rift は自動検出されるので、レンズの歪みを有効にしておくと、ゲームがステレオスコピックでレンダリングされて表示されます。 + Rift は自動検出されるので、レンズの歪みを有効にしておくと、ゲームがステレオスコピックでレンダリングされて表示されます。 ![](OculusSupportUE4_01.png) * 有効の場合、プレイヤー カメラの回転が Rift の方向にロックされます。この設定は **ロックした** ままにすることをお勧めします。 * **ElementalVR** サンプル プロジェクトは、現在メインの、唯一テスト済みの VR 体験です。このプロジェクトを GDC で披露し、 60 FPS に達しました。ユーザーの皆様、是非 VR を体験してみてください! - * 最高の体験についてのメモ: + * 最高の体験のための注釈: * 60 FPS でデモを動かすカードの場合、 **vsync を有効** にすることをお勧めします。HD キットを使用する場合は、スクリーンの向きにより明らかにティアリングが発生するため、特に推奨します! - * **フレーム バッファ処理の無効化** このオプションは nVidia のコントロール パネルにあります。1 に設定してデバイスの遅延を減らします。 + * **フレーム バッファ処理の無効化**このオプションは nVidia のコントロール パネルにあります。1 に設定してデバイスの遅延を減らします。 ![](OculusSupportUE4_02.png) * 紹介しておきたい進行中の案件は以下の通りです。 * **全画面自動探知**:現在、Rift が主要モニタになっていない場合、ウィンドウを手動で Rift に移動してコンソールで全画面に切り替える必要があります (「fullscreen] と入力) 。 * **レンダリング機能は、ステレオスコピック レンダリングと互換性がない場合もあります**。今のところ、 Environmental Reflections はステレオスコピック レンダリングと互換性がありませんし、他にもレンダリングに失敗する機能があるかもしれません!右目が黒い四角で表示されたら、恐らくそれは互換性のない機能なのかもしれません。 - * **遅延の改善** 今のところ、Rift の現在方向に対してカメラ位置を向けるために、まずゲームスレッド上で 1 回、そしてレンダリングの直前に 1 回と、計 2 回更新を行っていますが、まだ最適化の余地があります。Rift プラグインがレンダースレッド上での最終的な更新用に使用するインターフェースも問題なく使えます。明らかな遅延を減らせるのであればゲームに Rift は要らない場合、ゲームは同じインタフェースで 入力の読み取りと調整を別に行える可能性があります。 + * **遅延の改善**今のところ、Rift の現在方向に対してカメラ位置を向けるために、まずゲームスレッド上で 1 回、そしてレンダリングの直前に 1 回と、計 2 回更新を行っていますが、まだ最適化の余地があります。Rift プラグインがレンダースレッド上での最終的な更新用に使用するインターフェースも問題なく使えます。明らかな遅延を減らせるのであればゲームに Rift は要らない場合、ゲームは同じインタフェースで 入力の読み取りと調整を別に行える可能性があります。 -* **PC とコンソール用スクリーン空間のライト シャフト** +* **PC とコンソール用スクリーン スペースのライト シャフト** * ライト シャフトには、 **フォグ オクルージョン手法** と **加算 / ブルーム手法** の 2 種類があります。それぞれにコストがかかるので、希望する方法を 1 つ使用するのが良いでしょう。 * **オクルージョン** * オクルージョン手法は画面上のオブジェクトの深度からマスクの作成、ライトから離れてマスクへブラーの適用、またフォグや大気のマスクがけに使用します。 @@ -199,10 +200,10 @@ Availability:Licensee ![](Bloom.png) -* **Mobile Rendering:Distance Field Shadows (ディスタンス フィールド シャドウ)** +* **モバイル レンダリング:Distance Field Shadows (ディスタンス フィールド シャドウ)** * 太陽の光はディスタンス フィールド シャドウを使い、ピクセル単位で計算されるようになりました。 - ![](DistanceFieldShadows01.png)![](DistanceFieldShadows02.png) + ![](DistanceFieldShadows01.png)![](DistanceFieldShadows02.png) * **Lightmass (ライトマス) の品質改善** * ビルド時間を大幅に増やさずに品質を高める方法として適応サンプリングを使用することにしました。 @@ -214,10 +215,10 @@ Availability:Licensee |改善前|改善後| [/REGION] -####アニメーション +#### アニメーション * **AnimNotifyState Notification** - * 継続するなど、時間の範囲を定義する以外は、 AnimNotifyEvents と似ています。AnimNotifyClass ブループリントで NotifyBegin、NotityTick、NotifyEnd をトリガします。 + * 継続するなど、時間の範囲を定義する以外は、 AnimNotifyEvents と似ています。また AnimNotifyClass ブループリントにおいて、 NotifyBegin 、 NotityTick 、 NotifyEnd をトリガします。 ![](AnimNotifyState01.png) @@ -226,7 +227,7 @@ Availability:Licensee ![](AnimNotifyState02.png)(convert:false) -## 追加項目 +## 新規追加 #### エディタとツール * **[Open Project (プロジェクトを開く)]** で **プロジェクト ブラウザ** を使用するようになりました。 @@ -239,7 +240,7 @@ Availability:Licensee * エディタ UI HUD にフレーム レートとメモリ表示を切り替える環境設定を新しく加えました。 * **[Editor Preference (エディタの環境設定)] > [Developer Tools (デベロッパーツール)] > [Show Frame Rate and Memory (フレームレートとメモリを表示)]** (デフォルトはオン)。 * **ビューポートのレイアウト** - * 4 ペイン 2x2 レイアウトの他に 2 、 3 、 4 つのビューポート ペインが新しく登場しました。 + * 4 ペイン 2x2 レイアウトの他に 2、3、4 つのビューポート ペインが新しく登場しました。 * レベル ビューポートは、それぞれのビューポートのメインメニューにアクセスし、様々なレイアウトに対応させました。 * レイアウトを選択して、現在のタブ内のビューポートの配置を変更します。 * レイアウトは、 **レベルビューポート** の [Keyboard Shortcuts (キーボードショートカット)] ウィンドウのコマンドとしても入力できます。 @@ -247,13 +248,13 @@ Availability:Licensee * NVTriStrip は、コンソール変数 r.TriangleOrderOptimization を 0 に設定すれば使用できます。 * 新規の LOD のインポートや既存の LOD をスタティック メッシュに置き直す機能を追加しました。 * **プロファイラ** - * イベント グラフを改善しました (Average と Maximum イベント グラフの選択オプションが追加されました)。 + * イベント グラフを改善しました (Average と Maximum イベント グラフの選択オプションが追加されました)。 * エクスプローラーからプロファイラへ ue4stats ファイルをドロップ&ドロップする機能を追加しました。 * プロファイラのパフォーマンスが改善されました (キャプチャされた総計ファイルのロード時間の高速化に関するものがほとんどです)。 #### ブループリント -* **[My Blueprint**]** パネルあるいは選択対象の Get/Set ノードで変数が選択された場合に、 **[Details]** パネルの変数デフォルトを編集する機能を追加しました。 +* **[My Blueprint]** パネルあるいは選択対象の Get/Set ノードで変数が選択された場合に、**[Details]** パネルの変数デフォルトを編集する機能を追加しました。 * ライト用の IES プロファイル テクスチャがブループリントに設定できるようにしました。 * **ブループリント エディタ** の中に **Components** モードで作成した変数を割り当てられるようにしました。 * **ブループリント エディタ** の **Graph** モードに **Components** モードで作成した変数の割り当てを可能にしました。 @@ -272,8 +273,8 @@ Availability:Licensee * このビルドにはサポート対象のプラットフォームの Oculus Rift ハードウェアに対する予備サポートが含まれています。エンジン立ち上げ時にデバイスをプラグインすると、ステレオスコピック レンダリング、 HMD 、歪み、読み取りセンサー データが有効になります。この機能は開発中のため、適切なモニターを探知する機能などはまだ動作しています。 * r.MaterialQualityLevel がランタイム時に変更できるようにまりました (マテリアル式 **QualitySwitch** を使用するとアートの見栄えの調整が簡単になります)。 * ガウス ブラー処理のポストプロセス パスの最適化を追加し、大きめのブルームのみにデフォルト使用する r.FastBlurThreshold で調節可能にしました。 -* 内側および外側の半径、フォールオフ指数、最小ダメージに対する引数で、ApplyRadialDamageWithFalloff() 関数を GameplayStatics に追加しました。 -* Subversion へのサポートを追加しました。 +* 内側および外側の半径、フォールオフ指数、最小ダメージに対する引数で、`ApplyRadialDamageWithFalloff()` 関数を `GameplayStatics` に追加しました。 +* サブバージョンへのサポートを追加しました。 * ソース コントロールがプラグインで管理されるようになりました。 * Combo ボックス (およびそのコンテンツ) のキーボード制御を可能にしました。 * カメラ コンポーネントの最大比が 10 から 100 になりました。 @@ -281,10 +282,10 @@ Availability:Licensee * これにより、プリミティブがメインとなるシーンで描画されなくなりますが、他のパス (カスタム 深度パス) では描画されます。 * テクスチャ キューブ アセットへエクスポートする HDR を追加しました。 * 方向ベクターを返す FRotator::Vector() と混乱しないように、 FQuat::Vector() を FQuat::GetRotationAxis() に変更しました。 -* **AnimNotifyState** を追加しました。AnimNotifyState は AnimNotifyEvents とは異なり、継続するなど、時間の範囲を定義します。また AnimNotifyClass ブループリントにおいて、 NotifyBegin 、 NotityTick 、 NotifyEnd をトリガします。 +* **AnimNotifyState** を追加しました。AnimNotifyState は AnimNotifyEvents とは異なり、継続するなど、時間の範囲を定義します。また AnimNotifyClass ブループリントにおいて、NotifyBegin、NotityTick、NotifyEnd をトリガします。 * エディタでの AnimNotify 描画を改善しました。アクティブな通知がハイライトされます。 * AnimMontage が現在のスケルトン上で再生できない場合のログ警告を改善しました。 -* FText の数字 / パーセント / 通貨の形式を改善し、場所と記号を制御ができるにしました。 +* `FText` の数字 / パーセント / 通貨の形式を改善し、場所と記号の制御が可能になりました。 * **PhAT** - 選択中のスタティック メッシュから頂点を選択中のボディにコピーします。 @@ -295,9 +296,9 @@ Availability:Licensee * 新しい調整用 GI ソルバを使用して品質を大幅に改善しました。 * **WorldSettings** の **IndirectLightingQuality** で改善が必要なレベルでソルバ品質を選択的にあげることができます。 * オブジェク同士トが交わる部分の暗いテクセル アーティファクトを減らしました。 -* **移動オブジェクトの数が多い個所を中心にレンダリング スレッドを最適化** - * 1400 の移動オブジェクトのあるテストシーンの RT (リプレイ タイム) の合計は40% 削減されました。 -* **スクリーン空間のライトシャフト** +* **移動オブジェクト数が多い個所を中心にしたレンダリング スレッドの最適化** + * 移動オブジェクトが 1400 あるテストシーンの RT (リプレイ タイム) の合計は40% 削減されました。 +* **スクリーン スペースのライトシャフト** * 安定性を維持するために Temporal AA を使用します。 * 異なる 2 つの機能があります。フォグ オクルージョン手法は現実的で、ブルーム / 加算手法は制御しやすいです。 * **モバイル** @@ -306,7 +307,7 @@ Availability:Licensee #### プラットフォーム -* PC がコンソールと同じキャッシュ化されたテクスチャ ストリーミング(優先されるキャッシュのヒューリスティックによるテクスチャ プール) を使用するようにしました。デフォルトのプールサイズは VRAM の 50% ですが、好きな時に変更できます。 +* PC がコンソールと同じキャッシュ化されたテクスチャ ストリーミング(優先されるキャッシュのヒューリスティックによるテクスチャ プール) を使用するようにしました。デフォルトのプールサイズは VRAM の `50%` ですが、好きな時に変更できます。 * Deployment to Linux へのデプロイ (転送) は **Unreal Automation Tool** (UAT) でサポートされています。 * **IOS** * IPhone5S (64-bit ファットバイナリ) へのサポートと IOS7 の修正を追加しました。 @@ -317,282 +318,282 @@ Availability:Licensee * Facebook IOS SDK をサードパーティ ソースに追加しました。 -## 更新ノート +## アップグレード ノート #### エディタとツール -* **ランドスケープ** - * テクスチャ サンプリングを保存するために、高さマップ法線がウェイトマップにマージしました。 -* ストリーミング レベル用の **Edit properties** コマンドで、 AWorldSettings プロパティではなく ULevelStreaming オブジェクトのプロパティを表示するようにしました。 -* **コンテンツブラウザ** のアセットを**[Delete]** キーで削除できるようにしました。 -* アセット ビューに表示するアイテムがない場合、 **コンテンツブラウザ** が _「Nothing to show; check your filter」_ というメッセージを表示するようにしました。 -* コラム ビューの中では **コンテンツブラウザ** サムネイル スケーリングを無効にしました。 -* テクスチャ インポートの通知が OK または [Revert] ボタンのクリック直後に消えるようにしました。 -* 単一の **Active Bookmark** カテゴリへのブックマーク メニュー入力を移動しました。 -* 無効化されたプロパティに対するコードをプロパティは作成しません ( _マテリアル_ が不透明な場合のオパシティ プロパティなど)。 - * 今までは、コード作成用に無効化されたプロパティに適用する式を持ってシェーダーにこっそり使うことができましたが、今後は適用できませんので修正する必要があります。 -* アクタ アニメーションの詳細パネルのビルドを変更し、プロパティ表示がデリゲートでの制御を可能にしました。これにより、アニメーションをアクタにドラッグするとパネルのステートが不整合のままになるという問題が修正されました。 -* **Create Dynamic Material** _Blueprint_ ノードのツールチップが修正されました。 -* **Play In Editor** 中にリアルタイムな **Enable**/**Disable** ができるようにビューポート作成の動作を変更しました。 -* _Preview Only_ であることを示すペルソナの **スケルトンツリー** にアセット表示用のテキストとツールチップを追加しました。 -* オリジナル機能の出力を削除したので、エラーが表示されなくなりました。 -* Viewport Visualize Buffer メニュー オプションをローカライズしました。 -* Import FBX オプション ウィンドウのヘッダーメニューをローカライズしました。 -* Viewport Show メニュー オプションをローカライズしました。 -* スプラッシュ スクリーンのバージョンと読み込み情報をローカライズしました。 -* サウンドキュー エディタのメニュー オプションをローカライズしました。 -* ブループリント編集のデフォルトをローカライズしました。 -* エディタ設定のキーバインドのオーバーライドに対する通知をローカライズしました。 -* PhAT Editor Animation ツールバー テキストをローカライズしました。 -* ビューポートをローカライズしました。プレビュー:最近使用したのセクション ヘッダー -* Matinee Group コンテキスト メニューの [Rename Group (グループ名を変更)] をローカライズしました。 -* Forsyth のトライアングル順序最適化アルゴリズム (サードパーティ ライブラリとして) をメッシュ インポート パイプラインに統合しました。 +* **Landscape** + * Merged heightmap normal to weightmap, to save texture sampler. +* **Edit properties** command for a streaming level now shows ULevelStreaming object properties instead of AWorldSettings properties. +* Can now delete assets in the **Content Browser** using the **Delete** key. +* **Content Browser** now displays message _"Nothing to show; check your filter"_ message when the asset view has no items to show. +* **Content Browser** thumbnail scaling now disabled when in columns view. +* Texture import notification now fades off immediately after clicking OK or Revert buttons. +* Moved the bookmark menu entries into a single **Active Bookmark** category. +* Materials no longer generate code for properties that have been disabled (i.e. opacity properties when the _Material_ is opaque). + * Previously it would have been possible to have expressions attached to disabled properties which would generate code that could be sneakily used in some way by the shader.This will no longer work and will need fixed up. +* Changed actor animation detail panel building to allow property visibility to be control with delegates.This fixes an issue where dragging an animation onto an actor caused the panel to be left in an inconsistent state. +* Corrected tooltip for **Create Dynamic Material** _Blueprint_ node. +* Changed behavior of viewport creation so that **Enable**/**Disable** of realtime during **Play In Editor** is honored. +* Added extra text and tool tip to asset display to the **Skeleton Tree** in Persona signifying that it is _Preview Only_ +* Deleting the original function output no longer causes an error to be displayed. +* Localized the Viewport Visualize Buffer menu options. +* Localized the Import FBX options window header and menu. +* Localized the Viewport Show menu options. +* Localized the Splash screen version and loading information. +* Localized the SoundCue editor menu options. +* Localized Blueprint Editing Defaults. +* Localized Editor Settings Keybinding override notification. +* Localized PhAT Editor Animation toolbar text. +* Localized Viewport:Preview:Recent section header. +* Localized the Matinee Group context menu Rename Group. +* Integrated Forsyth triangle order optimization algorithm (as third party library) into mesh import pipeline. #### ブループリント -* _CharacterMovementComponent_ の **Acceleration** プロパティが保護され、GetCurrentAcceleration() のみを使用して _ブループリント_ でアクセスできるようにしました。 - * **Acceleration** を修正して移動するブループリントは、代わりに **InputVector** 使用できるように変換されるはずです。 -* ソースファイル数、モジュール数、 Object クラス数、 Blueprint クラス数、 Asset Package 数、マップの数、クラス タイプごとのオブジェクトのインスタンス数に関するプロジェクト リソース 統計を追う分析を追加しました。 -* **ブループリント エディタ** に、 **[Details]** パネルと **[Component]** コンテキスト メニューから _コンポーネント_ に対するイベントを追加する機能を追加しました。 -* _ブループリント_ にある全てのスーパー コール リファレンスは、コードとユーザーが目にする名前の両方とも _Super_ から _Parent_ に変更しました。 -* ただ四角にレ点を入れるのではなくマップ チェック関数としてすぐに見分けをつくように [マップ チェック] アイコンを置き直しました。 -* プロジェクトの使用を記録する分析を追加しました。 -* プループリント_ コンテキスト メニュー表示で抜けた _foo_ 関数を呼び出すアイコンを追加しました。 -* ブループリント配列の **RemoveItem** 関数で全てのインスタンスを除外して、 TArray の動作との一致を可能にしました。 +* **Acceleration** property of _CharacterMovementComponent_ has been made protected, and is accessible in _Blueprints_ only by `GetCurrentAcceleration()`. + * Blueprints that were moving by modifying **Acceleration** should be converted to use the **InputVector** instead. +* Added analytics to track project resource statistics for number of source files, modules, Object Classes, Blueprint Classes, Asset Packages, Maps and the instance counts of objects per class type. +* Added functionality in the **Blueprint Editor** to add events for _Components_ from the **Details** panel and the **Components** context menu. +* Changed all super call reference in the _Blueprints_ to be _Parent_ instead of _Super_ in both code and user facing naming. +* Replaced the map check icon so it is more readily distinguishable as the map check function rather than just a tick box. +* Added analytic that records project usage. +* Added missing icon display in the _Blueprint_ context menu for the call function on _foo_ entries. +* Blueprint array **RemoveItem** function now removes all instances, to match TArray behavior. #### ゲームプレイとフレームワーク -* UGameEngine::UserSettings を GameUserSettings に変更し アンリアル エンジン へ移動しました。 -* UEditorEngine::UserSettings を EditorUserSettings に変更しました。 -* スポーンされ読み込まれたアクタと順序が一致するように PreInitializeComponents を PostActorConstruction に移動しました。 -* AActor::Spawned を AActor::PostActorCreated に変更しました。 -* OnConstruction の前にスポーンされたアクタの PostLoad に類似するように AActor::PostActorCreated を移動しました。 -* UWorld の GameMode ポインタがプライベートになりました。GetAuthGameMode() アクセサを使用します。 -* **名前が変更された Vehicle クラス**: +* `UGameEngine::UserSettings` renamed GameUserSettings and moved to UEngine. +* `UEditorEngine::UserSettings` renamed EditorUserSettings. +* Move `PreInitializeComponents` to be in `PostActorConstruction` so that order is consistent for spawned and loaded actors. +* Rename `AActor::Spawned` to `AActor::PostActorCreated`. +* Move `AActor::PostActorCreated` to occur before `OnConstruction` to be analogous to `PostLoad` for spawned actors. +* The `GameMode` pointer in UWorld is now private.Use GetAuthGameMode() accessors. +* **Vehicle classes renamed**: [REGION:simpletable] - | 変更前 | 変更後 | + | Old | New | | --- | --- | | Vehicle | WheeledVehicle | | VehicleMovementComponent | WheeledVehicleMovementComponent | | VehicleMovementComponent4W | WheeledVehicleMovementComponent4W | [/REGION] -* _NoDrive_ ビークル モデルのサポートは除外されました。 -* Y-up の座標をもつ APEX Clothing アセット上で自動的に **Y-up** から **Z-up** へ変更します。 -* エスケープするためには、メッセージ フォーマット パターン文字列で ' の代わりに \` を使用することになりました。 - * メッセージ フォーマット パターン文字列で { or } を使う場合、個別に \`s - の間を { and } でラップする、あるいは 2 つを一緒にラップします。 - * \` の後に { or } をエスケープせずに印刷するには \` を重ねて (\`\`) 使用します。 -* 高解像度のスクリーンショット パスの実行中、モーション ブラーを無効にしました。 -* LoadPackageAsync は関数ポインタの変わりにデリゲートを受け取れるようになりました。 +* _NoDrive_ vehicle model support removed. +* Change up-axis from **Y-up** to **Z-up** automatically on the APEX Clothing asset which has Y-up axis. +* Message formatting pattern strings now use \` instead of ' to escape. + * If a message formatting pattern string uses { or }, wrap the { and } between \`s - individually or collectively both work. + * Use double \` (\`\`) to print a \` without escaping a { or } after it. +* Disabled motion blur while performing high res screenshot pass. +* `LoadPackageAsync` now accepts a delegate instead of pointer to a function. #### コア -* Arithmatic と名づけられた各種タイプを Numeric に変更しました。 -* ブランチがアーカイブでそれぞれのエントリを定義できるように追加されたカスタム仕様のバージョン スキームを、列挙型変数から UID ベースに変更しました。 - * これまで列挙型変数はカスタム仕様のバージョンの特定のために使われてきました。ObjectVersion.h の EUnrealEngineObjectCustomTag に置かれていました。 - * 今後、カスタム仕様のバージョンは GUID で特定されます。 - * 列挙型変数ベースのカスタム仕様のバージョンが含まれる既存のパッケージは、 GUID の 00000000-00000000-00000000- との広報互換性があるので、これらのパッケージにはこの値の GUID を使用することが望まれます。 - * FCustomVersionRegistration 変数は、カスタム仕様のバージョンの用途を記述している列挙型変数および文字列ではなく GUID で定義されるべきです。 +* Various types named "Arithmatic" were renamed to "Numeric" +* The custom versioning scheme which was added to allow branches to define their own entries in archives has been changed from being enum-based to GUID-based. + * Previously, enums were used to identify a custom version.These were placed in `EUnrealEngineObjectCustomTag` in `ObjectVersion.h`. + * Now a custom version is identified by a GUID. + * Existing packages containing enum-based custom versions are backward compatible with a GUID of `00000000-00000000-00000000-`, so a GUID of this value should be used to load these packages. + * Any `FCustomVersionRegistration` variables should be defined with a GUID instead of an enum and a string which describes what the custom version is for, so this: FCustomVersionRegistration GMyModule((EUnrealEngineObjectCustomTag::Type)0x12345678, MyLatestVersion); - は、以下のようになります: + would become: FCustomVersionRegistration GMyModule(FGuid(0, 0, 0, 0x12345678), MyLatestVersion, TEXT("My module")); -* FMaterialVertexParameters の中で計算された TangentToWorld はスケーリングを除外し、ピクセル シェーダーに渡された TangentToWorld と一致します。 -* UnrealBuildTool (モジュラー ビルド内のエンジン) は、ルート内で 「*.uprojectdirs」ファイルを使い「uproject」ファイルに対して表示するフォルダを 1 レベル深い場所で検索します。 - * この機能は bUseUProjectDirs を false に設定すれば、 UnrealBuildTool で無効にできます。 +* The computed `TangentToWorld` in `FMaterialVertexParameters` now removes scaling and matches `TangentToWorld` passed to the pixel shader. +* UnrealBuildTool (and the Engine in modular builds) will now use `*.uprojectdirs` files in the root to indicate the folders it should search 1 level deep for `uproject` files. + * This feature can be disabled in UnrealBuildTool by simply setting `bUseUProjectDirs` to false. #### プラットフォーム -* クックされていない UE4 とゲームバイナリを取り除きました。 - * UE4Editor.exe を実行、またはコマンドレットを実行すれば、クックされていないゲームをいつでもテストできます。 - * 生成されたプロジェクト ファイルの中に、 Uncooked オプションは存在しなくなりました。その代わりにエディタを使用します。 - * エディタのコマンドラインに -game オプションを渡してゲームを実行します。 - * **Play in Standalone** プロセスを使用してエディタからゲームを実行することもできます。 +* Eliminated Uncooked UE4 and game binaries. + * You now always run `UE4Editor.exe` to test uncooked games, or to execute commandlets. + * The Uncooked option no longer exists in generated project files.Use the Editor instead. + * Pass the `-game` option on the command-line of the editor to run the game instead. + * Or, you can run the game from the editor using **Play in Standalone** Process. [REGION:note] - Uncooked ターゲットは既存プロジェクトが削除するはずです。GameUncooked が有効な TargetType ではなくなりました。差し当たり、 UnrealBuildTool はこれらのファイルを自動でスキップします。 + Existing projects should delete their Uncooked target.GameUncooked is no longer a valid TargetType.For now, UnrealBuildTool will automatically SKIP these files. [/REGION] -* 数ある「*.mm」ファイルを「*.cpp」に更新しました。 +* Updated a number of `*.mm` files to `*.cpp` -#### ネットワーク -* 専用サーバー用のデフォルト マップ / ゲーム情報の ini オプションを追加しました。 -* 少なめのコマンドライン パラメータで専用サーバーを起動させることが可能です。 -* StartupMap コンセプトは DefaultMap と機能的に同じなので削除しました。 +#### Networking +* Added default map / game info ini options for dedicated servers. +* Allows dedicated servers to launch with less commandline parameters. +* Removed StartupMap concept as DefaultMap is functionally the same. -####オンライン -* IsEnabled() 機能はすべてのオンライン サブシステムで一貫しています。 -* 新規ログ オプションとして LogOnlineGame と LogBeacon を追加しました。 -* IsRunningServer から IsRunningDedicatedServer に変更して分かりやすくしました。 -* JoinFriendSession から FindFriendSession に変更して用途を明確にしました。 - * FindFriendSession は友達の場所の検索結果のみを返します。 - * その結果を使って後に JoinSession を呼び出し、フローを完成させなければなりません。 -* IOS 向けに Facebook Identity を追加しました。 -* IOS 向けに Facebook Friends Access を追加しました。OnlineSubsystem Sharing インターフェースを使って権限申請を行います。 -* OSS ユーザーに関するデータをホストする OnlineSubsystem::GetUserInterfac の初回導入を追加しました。 -* OnlineSubsystem Facebook を更新したので IOS と Windows のビルドを並べることができます。 -* サービス キーと権限に関する MCP コンフィギュレーションを config ファイルではなく NoRedist ソース ファイルへ移動しました。 - * 開発便宜上、これらの値の取得には DefaultEngine.ini メソッドを維持しています。 - * ゲームはコールバック デリゲートを使ってコンフィギュレーションをオーバーライドすることができます。 +#### Online +* Consistent `IsEnabled()` functions across all online subsystems. +* Added `LogOnlineGame` and `LogBeacon` as new possible log options. +* Renamed `IsRunningServer` to `IsRunningDedicatedServer` for clarity. +* Renamed `JoinFriendSession` to `FindFriendSession` to be more clear about its purpose. + * `FindFriendSession` only returns a single search result for where the friend is. + * `JoinSession` must still be called afterward with the result to complete the flow. +* Added a Facebook Identity for IOS +* Added Facebook Friends access for IOS.Uses the OnlineSubsystem Sharing interface to request permissions. +* Added the initial implementation of `OnlineSubsystem::GetUserInterface` which hosts data about an OSS user. +* Updated the OnlineSubsystem Facebook so that IOS and windows builds could live side by side. +* Moved MCP configuration of service keys and permissions to NoRedist source files instead of config files + * Still maintained the `DefaultEngine.ini` method of getting these values for development convenience + * Games can override configurations using a callback delegate * Http - * wininet の http モジュールに対してのタイムアウトが公開されました。 + * Exposed http module timeouts for wininet: * HttpConnectionTimeout=60 * HttpReceiveTimeout=30 * HttpSendTimeout=30 - * リクエストはタイムアウトを待たず早めに失敗します。 + * Request will fail faster instead of waiting for the timeout -## 今後の追加および継続事項 +## 今後の追加事項と継続項目 #### エディタとツール -* **ワールド ブラウザ** - * ブランクのパーシスタント レベルをランタイム パッケージからディスク上の実際のパッケージに変更しました。**Open World** コマンドはフォルダではなくマップ ファイルを要求します。 - * **右クリック** するとカーソルを合わせたタイルが正しく選ばれます。 -* アクティブになっているビューポートに表示されるビューモード名がメニューリストの表示と同じになりました。 -* ロック時、レベルを現在のレベルにするためにメニュー オプションを無効にします。 -* データのみの場合と通常の _ブループリント_ には同じアイコンを使用し、両者の区別を付けるため色だけ別にします。 -* シーン テクスチャ ノードにビューポート サイズに対する UV をクランプするオプションが付きました。 -* アセットを新規作成されたコレクションにドラッグしてもエディタがクラッシュしないようになりました。 -* 開始時と同じフレームでゲームを終了した場合のクラッシュを防ぎます。 -* _Matinee_ アクションに対して欠けていたツールチップを追加しました。 -* _Matinee_ の新規作成時に **コンテンツブラウザ** アセットが選択されてもエディタはクラッシュしなくなりました。 -* **Placement Browser** - コレクション ビューでは、無効なパラメータによるエントリ作成の試みは行われなくなります。 -* **コンテンツブラウザ** はテキストではなくアイコンを使用してコレクション タイプを表示するようにしました。 -* **Matinee** のドロップダウンに **Matinee を追加** のオプションを付けました。 -* ソース コントロールが切断されている時、右クリックしたりコレクションの新規作成をしても警告が出ないようにしました。 -* Zoom と _ブループリント_ の見出しをローカライズしました (可能な範囲で)。 -* **ブループリント** / **ペルソナ** モードの見出しをローカライズの表示にしました。 -ドロップダウンの **[浮動トラックを追加]** をローカライズの表示にしました。 -* BSP Pan をローカライズの表示にしました。 -* _Matinee Actor_ の [詳細] セクションを **Transform** の下に表示しました。 -* **Ctrl + W** で複製する場合は、もう 1 回だけ取り消しをする必要があります。 -* _SoundCue_ と _SoundWave_ はダブルクリックしても再生されなくなりましたので、 **サウンドキュー エディタ** を開いてください。 -* **Hidden In Game** としてマークされた _DecalActors_ はエディタに正しく描画します。 -* ガウス曲線の DOF エフェクトを最適化します。**Near Blur Size** がコンソール変数 `r.DepthOfField.NearBlurSizeThreshold` によって定義された閾値より小さければ、近いブラー エフェクトが無効化され、その代わりに負荷の小さいシェーダーが使用されます。 -* バッファのビジュアル化システムを へ平行投影ビューモードで正しく動作しています。 -* Alt + ドラッグでビュー回転をしても、 _ランドスケープ_ がリサイズしようとしなくなりました。 -* ラインの複雑さを緩和し DrawDashedLine() を最適化して、エディタ内での _ランドスケープ_ スプラインのレンダリングを最適化しました。 -* UI 全般における改善点: - * 40x PNG のみで [ViewMode] のアイコンを新規に追加しました。 - * ローカル、共有、プライベート用に追加した新規アイコンは接続する必要があります。 - * [Profiler] アイコンを新規作成し、ビルドに追加、接続しました。 - * [Colorblind Solution] アイコンを更新しました。自動的に動作するはずなので、ビルドを破壊せずにPNG へ置き換える状態にはなっていません。 - * 現在の「コンテンツブラウザ」フォルダのアイコンが光るように調整します。デフォルト アイコンを前のバージョンの外見に戻す色調を弱めるためのコードが必要です。 - * 翻訳ツールバー オプションの既存アイコンを修正し、新規にアイコンを作成しました。PNG アセットが置き換えられたので、新規翻訳アイコンにコード合わせが必要です。 - * メインの [Add Event Caller blueprint] ボタン (40x サイズ) およびコンテクスト メニュー (16x サイズ) の両方のアイコンを新規作成しました。 - * Import FBX Chunks @ 40x のアイコンを新規作成しました。エディタでのコード合わせが必要です。変更は PNG アセットのみ。 - * 16x と 40x の両方の解像度で、「カメラ位置でのスタンドアローン ゲーム」と「再生開始のスタンドアローン ゲーム」用にそれぞれアイコンを新規作成しました。PNG アセットのみで、コード合わせが必要です。 - * [Enum]、[Bluprint Delegate](16 と 24x)、接続中まはた切断中の [Delegate Pins] のアイコンを新規作成しました。PNG アセットのみで、既存の PNG ファイルを置き換えます。 -* 新しいエンジンの分析法であるエディタ トラックのソース管理プロバイダーが変ります。 -* ビューポート ツールバー ボタンが通常のツールバー ボタンのように動作し、クリックすると開いているメニューが閉じます。 -* EpicSurvey プラグイン用のブランチサポートが追加されました。 -* 新しいサーベイの利用可能時にEpicSurvey 通知方法がトースト表示されるように変更し、通知アイコンに対して定義可能な時間遅延と継続時間を追加しました。 -* エディタが **Save All** を使う際に選択を解除したパッケージは、アプリケーションの寿命の限り、その状態を記憶します。 -* ビューポートでのズーム時に使用するマウスホイールのスクロール速度を分けるために新規エディタ設定を追加しました。 -* **コンテンツブラウザ** の検索ボックスには合致する検索結果が全て含まれるようになり、ユーザーは特定のアイテムではなくフォルダ全体を検索できます。 -* PhAT で物理ボディーを開くと対応するボーンを持たない物理ボディを自動削除するオプションを追加しました。 -* エディタのファイル メニューからコンテンツのクックおよびプロジェクトのパッケージが機能するようになりました。ただし、プラグインには若干課題が残っています。 -* プロジェクトの新規作成時、 Open Project ツールが非表示になるようにしました。 -* _コンテクスト ブラウザ_ 中のテキスト「Nothing to show; check your filter」を中央寄せにしました。 -* _Cube Texture_ サムネイルが 2:1 のアスペクト比で描画されるようになりました。 -* プロジェクト ファイル ジェネレータを改善しました。 - * 生成プロジェクトに .uproject ファイル、.uplugin ファイル、プラグイン ファイルが含まれるようにしました。 -* 起動時のマウス制御を Play In Window モードで可能にしました。 -* ユーザーがエディタに明示的にマウス制御を返した場合、インゲーム コンソールを使用してもビューポートの制御が失われないように、マウス制御にのみ従うようにPIE ビューポートは変更します。 -* 右のシフトが下方位置で動かなくなってしまわないように、曖昧だった左右のシフトを正確に排除しました。 -* タスクのプログレス ダイアログ ポップアップによりキーボードフォーカスが奪われないようにすることで、コンテンツ ブラウザのアクションにあるアクションの無限再帰 (呼び出し) を防ぎます。 -* Matinee の [Editing Crosshair (クロスヘア照準を編集)] メニュー オプションに永久チェックボックスが表示されるようにしました。 +* **World Browser** + * Changed blank persistent level from a runtime package to an actual package on a disk.**Open World** command now requires a map file instead of folder. + * **Right-click** now properly selects hovered tiles. +* View mode names displayed in active viewport are now the same as the menu listing. +* Disabled the menu option to make a level the current level when it is locked. +* The same icon is now used for "data only" and regular _Blueprints_, only the color differs to distinguish between them. +* The scene texture node now has an optional clamp of it's UV to the viewport size. +* Editor no longer crashes when dragging asset into newly created collection. +* Prevent crash if user exits game the same frame it begin it. +* Added missing tooltips to _Matinee_ actions. +* Editor no longer crashes if **Content Browser** asset is selected when creating a new _Matinee_. +* **Placement Browser** - Collections view no longer tries to create an entry with invalid parameters. +* **Content Browser** now uses icons instead of text to denote collection type. +* **Matinee** dropdown now has an option for **Add Matinee**. +* No longer a warning when right-clicking or creating a new collection when source control is disconnected. +* Zoom and _Blueprint_ headings are now localized (where possible). +* **Blueprint Editor**/**Persona** mode headings now appear localized. +* Dropdown **Add Float Track** now appears localized. +* BSP Pan now appears localized. +* _Matinee Actor_ details section now appears below **Transform**. +* Duplicate, via **Ctrl + W**, only requires 1 undo step again. +* _SoundCue_ and _SoundWave_ no longer play when double clicked, instead opens **SoundCue Editor**. +* _DecalActors_ marked as **Hidden In Game** will now draw properly in the editor. +* Optimizations for Gaussian DOF effect.If **Near Blur Size** is less than the threshold defined by the console variable `r.DepthOfField.NearBlurSizeThreshold`, the near blur effect will be disabled and cheaper shaders used instead. +* Buffer visualization system now works correctly in orthographic view modes. +* New _Landscape_ doesn't try to resize during alt-drag view rotation any more. +* Optimized _Landscape_ spline rendering in editor by reducing complexity of the lines and optimizing `DrawDashedLine()`. +* General UI Improvements: + * Added new additional ViewMode icons at 40x pixels PNG only. + * Created new Icons added for Local, Shared & Private - will require hookup. + * Created new Profiler Icons and Added to the build - Wired up. + * Updated Icon - Colorblind Solution Should automatically work Red - No Go sign - non-destructive PNG replace. + * Adjust existing Content Browsers folder icons to lighten them. requires code to tint default icons back to look of previous versions. + * Revised existing icons & created new icons for translation toolbar options.PNG assets replaced, new translation icons require code hook-up. + * Created new icons for both the main Add Event Caller blueprint button (40x size) and the context menu (16x size). + * Created a new icon for Import FBX Chunks @ 40x.Requires code to hook-up in edior.Change is PNG asset only. + * Created new icons for 'Standalone Game at Camera Location' & 'Standalone Game at Player Start', at both 16x & 40x resolutions.PNG assets only, require code to hook-up. + * Created new icons for Enum, Bluprint Delegate (16 & 24x), and Delegate Pins connected & disconnected.PNG assets only, replaces existing PNG files. +* New engine analytics - Editor tracks source control provider changes. +* Viewport toolbar buttons now act like regular toolbar buttons and close any open menus when clicked. +* Added branching support for the EpicSurvey plugin. +* Changed EpicSurvey notification mechanics to display a toast when a new survey is available, and added definable time delays and duration for the notification icon. +* Deselecting package when using **Save All** in the Editor now remembers you ignored it for the lifetime of the application. +* Added a new editor setting to separate the middle-mouse scroll speed when using it to zoom in the viewport. +* The **Content Browser**'s search box now includes all the contents of successful search results, allowing a user to search for an entire folder rather than specific items. +* Added option to automatically delete physics bodies with no corresponding bone when opening physics bodies in PhAT. +* Content Cooking & Project Packaging from the Editor's File menu now works; there are still some issues with plug-ins +* 'Open Project' tools are now hidden when creating new project. +* Centered "Nothing to show; check your filter" text in _Content Browser_. +* _Cube Texture_ thumbnails are now draw with 2:1 aspect ratio. +* Project file generator improvements. + * Generated projects now include .uproject files, .uplugin files and plugin resource files. +* Allow the Play In Window mode to take mouse control on start up. +* Change PIE viewports to only surrender mouse control when the user explicitly returns it to the editor, so that using an in-game console won't cause the viewport to lose control. +* Correctly disambiguate right & left shift so that right-shift doesn't get stuck in the down position. +* Prevent infinite recursion in some Content Browser actions by preventing the task pop-up progress dialog from stealing keyboard focus. +* In Matinee give the "Editing Crosshair" menu option a permanently visible tick-box. #### ブループリント -* **MakeArray** ノードは、非純粋関数呼び出しノードだけではなく、全てのノードの前に置けるようにしました。 -* ブループリントのスポーンパラメータに FName が使えるようになりました -* **ブループリント エディタ** の **Components** モードに追加する新規コンポーネントを選択した後、検索フィルタ ボックスをクリアするようにしました。 -* **ブループリント エディタ** の **Graph** モードで変数を選択すると、[詳細] タブから検索バーとプロパティ グリッドを削除しました。 -* 子の _Blueprint_ Component 変数名が親の _ブループリント_ の _コンポーネント_ 変数名と衝突することがなくなりました。 -* **BeginPlay** およびその _ブループリント_ 版である **ReceiveBeginPlay** は、最初に再現されたプロパティがクライアント側で受け取られた _後で_ 動的にスポーンされたアクタに対して呼び出されるようにしました。 -* 選択中のアクタを _ブループリント_ の変換する際は、 _ブループリント_ に対してアタッチされている全てのアクタではなく、選択中のアクタのみを選択します。 -* ドラッグ中の変数をコンテクスト メニューにプロモートして、 _ブループリント_ ペインにある新規変数の名前を自動的に編集するようにしました。 +* **MakeArray** nodes can now be placed in front of any node, not just impure function calls. +* Added support for `FName` _Blueprint_ spawn parameters. +* The search filter box is now cleared after making a selection to add a new component in **Components** mode within the **Blueprint Editor**. +* Removed the search bar and property grid button from the Details tab when variables are selected in **Graph** mode within the **Blueprint Editor**. +* Child _Blueprint_ Component variable names can no longer collide with _Component_ variable names in the parent _Blueprint_. +* **BeginPlay**, and the _Blueprint_ version **ReceiveBeginPlay** should now be called _after_ the initial replicated properties are received on clients, for dynamically spawned actors. +* Converting selected actors to _Blueprint_ will only use the selected actors and not all attached actors for the _Blueprint_. +* Promote to variable in drag context menu new automatically edits the now variables' name in the _Blueprint_ pane. #### ゲームプレイとフレームワーク -* 任意のクラスと派生クラスのオブジェクトの繰り返しのみなので、 TObjectIterator はかなり速くなりました。 - * 派生クラスは除外して指定されたクラスのオブジェクトを明示的に繰り返すことだけも可能になりました。TObjectIterator のコンストラクターをご覧ください。 -* ローカライズされた単語数レポート生成コマンドレットを修正して、 Windows 形式の新規改行文字を正しく処理できるようになりました。 -* さらに効率的にするためのマイナーな最適化をいくつかのハードウェアで実施しました。 -* スケーラビリティを SynthBenchmark に追加し (必要に応じて速くできますが精度は下がります)、品質を判断するために debugoutput を追加しました。 -* Enable / DisableInput を Pawn 、 PlayerController 、 LevelScriptActor から呼び出すようにしました。 -* **コリジョン** - * CollisionProfile の ObjectTypeName によりコード定義されたチャネル ではなく チャネルの DisplayName を許可します ( ECC_GameTraceChannel1 など) 。 - * UI に関する改善点:トレース型とオブジェクト型に分けて、 Collision Profile を Collision Preset に変更しました。 - * Get Hit Result Under Cursor もトレース型とオブジェクト型に対応します。 - * コリジョン プロファイルに対するツールチップ サポートを追加しました。HelpMessage の使用 -* アクタ名を NAME_SIZE の長さに制限することにしました。 -* 完全なオーディオ アセットをあらかじめロードすることで、オンザフライでロードされないようにしました。 -* レベル エディタベースのメインフレームが表示されるまでは、メッセージ ログが表示されないようにしました。 -* debug draw delegates 配列へ同時アクセスしてもクラッシュしなくなりました。 -* 自動検索選択機能を改善しました。 -* GetTextSize が const になったので、 GetTextSize 経由の起動時に実行する必要はありません。 -* キーがかけている FText プロパティアセットのロード時の警告を追加しました。 +* `TObjectIterator` is now much faster as it only iterates over objects of the given class and derived classes. + * You can now also only iterate over objects explicitly of the specified class, excluding derived classes.See `TObjectIterator`'s constructor. +* Modified localization word count report generation commandlet so that it can properly handle windows format new line characters. +* Minor optimization to get more efficient clears on some hardware. +* Added scalability to `SynthBenchmark` (run it faster but less precise when needed), added debugoutput to judge quality better. +* `Enable`/`DisableInput` can now be called on Pawn, PlayerController, and LevelScriptActor. +* **Collision** + * CollisionProfile `ObjectTypeName` allows `DisplayName` of the channel, not code defined channel (i.e. `ECC_GameTraceChannel1`). + * UI improvement:Split trace type vs object type, Renamed Collision Profile to be Collision Preset. + * Get Hit Result Under Cursor also supports trace type and object type. + * Added tool tip support for collision profile.Use HelpMessage. +* Actor names are now limited to `NAME_SIZE` in length. +* Preloaded compilation audio assets to prevent them loading on the fly. +* Prevented message log from showing until a level editor-based mainframe is displayed. +* Prevented crash because of concurrent access to debug draw delegates array. +* Auto find selection improved. +* `GetTextSize` now const - so it no longer needs execution running through it. +* Warning added when loading assets with FText properties that lack a key. * **Unreal Front Launcher** - * この機能は開発中です。ランチャーをこの QA ビルドで再有効化し、 Unreal Automation Tool を利用してゲームをビルド、クック、起動します。全機能が実装されているわけではありませんが、 iOS iPad のビルドとパッケージ化だけではなく、ほぼ全ての Windows 設定でテストしています。 -* **専用サーバーの最適化** - * これらの環境で NeedsLoadForClient/Server == false でアクタをスポーンすることはできません。 - * bAllowTickOnDedicatedServer を FTickFunction に追加します。 - * ParticleSystemComponents は DS にチェックをいれず、 PSC.ActivateSystem をするようにしました。 - * bAllowReceiveTickEventOnDedicatedServer を AActor に追加し、希望に応じて全てのブループリントに DS にチェックを入れることができないようにしま。す。 -* ビークルに関して改善しました + * This is a WIP feature.The launcher has been re-enabled in this QA build and utilizes Unreal Automation Tool to build, cook, and launch games.Not all of the features have been implemented, but it has been tested with most Windows configurations as well as building and packaging iOS ipas. +* **Dedicated server optimizations** + * Disallow spawning Actors with `NeedsLoadForClient/Server == false` in those contexts. + * Add `bAllowTickOnDedicatedServer` to `FTickFunction`. + * ParticleSystemComponents no longer register ticks on DS, and skip `PSC.ActivateSystem`. + * Add `bAllowReceiveTickEventOnDedicatedServer` to `AActor`, to disable all Blueprint ticking on DS if desired. +* Vehicle improvements #### レンダリング -* シャドウ キャスティングは (以前は LoD ごとでしたが) _スケルタル メッシュ_ のマテリアルごとになりました。 -* 法線から合成ラフネステクスチャ機能に改善しました。スペキュラ エイリアシングに役立つ機能です。 +* Shadow casting is now per-material for _Skeletal Meshes_ (was previously per LoD). +* Improved normal to roughness composite texture feature.This helps with specular aliasing. * **モバイル** - * キューブマップ用の HDR エンコードを改善しました。 + * Improved HDR encoding for cubemaps. -#### オーディオ -* SoundWaves から SoundCues を作成すれば、固有で有効な名前を持つ SoundCue が作成されます。 +#### Audio +* Creating SoundCues from SoundWaves will create the SoundCue with a unique and valid name. -#### コア -* Slate モジュールの反映が EditorStyle には依存しなくなりました。 - * SlateStyle を EditorStyle に変更しました。 - *統計値にあまり頼らず、スタイル システムの大幅なリファクタリングを行います。コンテンツを経由してウィジェットのスタイリングを操作するために使用する新規アセット タイプの Slate Widget Style を導入しました。 - * 古いボタンおよびチェックボックス スタイル アセットのファクトリを削除すれば、新規にファクトリを作成なくてすみます (まもなく廃止となります)。 -* 表示テキスト変数の定義時に、新しい SLATE_TEXT_ARGUMENT もしくは SLATE_TEXT_ATTRIBUTE マクロを使用するためにコア スレート ウィジェットを更新します。これにより、ユーザーは FStrings または FText for values のいずれかをパスすることができます。スレート ウィジェットを何回かのステップを踏んで対応する完全なる FText へ変換してみようと思います。最初のステップでは、現在渡されてい る FText 用の .ToString() を削除することができます。次に ANSI* と TCHAR* へのサポートを削除して、 FText を使うために十分な数だけ場所が切り替わったら、マクロロジックを反転して Ftext を TStrings にではなく、 FStings を FText に変換できます。この時点で、 FText を内部で使用するためにコア ウィジェットを変換し、 FString のサポートを段階的に削除し、最終的には完全に削除できます。 - * コア スレート ウィジェット テクスト フィールドの ANSI* および TCHAR* に対するサポートを削除します。 -* UnrealAutomationTool と UnrealBuildTool のビルド用基礎構造に対する改善と修正がいろいろあります。 -* コードベースではないプロジェクトへのコード追加に合わせて uproject ファイルが更新されるようになりました。 -グリッド パネルに行も列もないということが起こらないように注意します。 -* TabManager からアンロード済みオブジェクトに対するリファレンスをなくしました。 -* プロパティ内の上付き文字は強制的に下付き文字になりました。 -* 使用が未承認の FindText をクリーンアップします。 -* テキスト エレメントにはダブル スペースの改行はもう含まれません。 -* ツールバーをクリックすると、ローカライズされたツールバーが展開します。 -* マテリアル エディタ式カテゴリをローカライズしました。 -* 反射 の命名規則の整合を強化しました。 -* バッファの視覚化の命名規則の整合を強化しました。 -* サウンドのスプライトの切り替えをしてもライトのスプライトは切り替わらなくなりました。 -* UDoubleProperty に Double 型の UObject プロパティを追加しました。 -* バイトサイズを人間が読み取れる文字列に合わせるため FText::AsMemory() を追加しました。 -* UHT がエラーを起こさずに空のヘッダファイルを処理できるようにしました。 +#### Core +* Refactoring the Slate module to no longer be dependent on `EditorStyle`. + * Renamed `SlateStyle` to `EditorStyle` + * Large refactor of the style system to be less dependent on statics.Introduced a new asset type, Slate Widget Style, that can be used to drive a widgets styling through content. + * Removing the factories for the old button and checkbox style assets so people stop creating new ones (will be DEPRECATED soon) +* Updated core slate widgets to use a new `SLATE_TEXT_ARGUMENT` or `SLATE_TEXT_ATTRIBUTE` macro when defining their display text variables.This allows users to pass either FStrings or FText for values.This is an attempt to do a multi-step conversion of the slate widgets over to supporting entirely FText.First well be able to remove many .ToString() for FText which are currently being passed.Then we can remove support for ANSI* and TCHAR*, then once a sufficient number of places are switched to using FText we can invert the macro logic to convert FStrings into FText, instead of FText into FStrings, at which point we can convert the core widgets to use FText internally and finally phase out FString support entirely. + * Removed Support for `ANSI*` and `TCHAR*` in core Slate widget text fields. +* Various improvements and fixes to UnrealAutomationTool & UnrealBuildTool build infrastructure. +* Adding code to a non-code project now updates the uproject file accordingly. +* Guard against grid panel with no rows or columns. +* TabManager no longer holds references to objects that have been unloaded. +* Uppercase article words in properties are now forced to lowercase. +* Cleanup unapproved usage of FindText. +* Text elements no longer have double spaced newlines. +* Toolbar Click to Expand Toolbar now appears localized. +* Material Editor expression categories are now localized. +* Improved consistency with Reflections naming convention. +* Improved consistency with Buffer Visualization naming convention. +* Toggling Sounds sprites no longer toggles light sprites. +* Added UDoubleProperty for UObject properties of type double. +* Added `FText::AsMemory()` to format byte sizes to human readable strings. +* UHT can now process empty header files without producing errors. #### プラットフォーム -* Static Library Support を Android ツールチェーンに追加しました。 +* Added static lib support to the Android toolchain. * **Mac** - * エンジンとエディタを Mac へポート中です。 - * Mac OS X の Intel HD 4000 カードへのソフトウェア フォールバックを避けるために、スケルタルメッシュ ボーン マトリクスには大型のユニフォーム バッファではなく頂点バッファおよび頂点テクスチャ フェッチ(Vertex Texture Fetch) を使用します。 - * バッファは常に存在し、結合し、 (FVector4) 以上のサイズで、プラットフォーム間の正しい挙動を確保しています。 - * OpenGL ES2 でレンダリングする場合では、またユニフォーム バッファが使用されます。 - * Mac OS X 上では、高精度のマウス操作の間、カーソル位置を常に手動で更新しエディタ ツールが機能していることを確認します。 - * Mac OS X 用 Forsyth Xcode プロジェクトとライブラリを追加しました。 + * Porting the engine and the editor to Mac. + * Use a vertex buffer and Vertex Texture Fetch rather than a large uniform buffer for skeletal mesh bone matrices to avoid a software fallback on Intel HD 4000 cards under Mac OS X. + * The buffer always exists and is bound and is at least size of(FVector4) to ensure correct cross-platform behaviour. + * The OpenGL ES2 renderer still uses uniform buffers. + * On Mac OS X, always manually update the mouse cursor position during high-precision mouse operations to ensure that editor tools work. + * Added Forsyth Xcode project & libraries for Mac OS X. diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/Oct/ReleaseNotesOctober2013.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/Oct/ReleaseNotesOctober2013.KOR.udn index 62a5333457ab..8e2b6236aff9 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/Oct/ReleaseNotesOctober2013.KOR.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/Oct/ReleaseNotesOctober2013.KOR.udn @@ -1,8 +1,10 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3367470 Title: October 2013 Release Notes Crumbs:%ROOT%, Support/Builds Description: Availability:Licensee +Parent:Support/Builds +Order:-4 [TOC(start:2 end:2)] diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/Sept/ReleaseNotesSeptember2013.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/Sept/ReleaseNotesSeptember2013.JPN.udn index fc4c04e5c321..dff305e5cca7 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/Sept/ReleaseNotesSeptember2013.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/Sept/ReleaseNotesSeptember2013.JPN.udn @@ -1,8 +1,10 @@ -INTSourceChangelist:2618148 +INTSourceChangelist:3367470 Title:2013年9月リリースノート Crumbs:%ROOT%, Support/Builds Description: Availability:Licensee +Parent:Support/Builds +Order:-5 [TOC(start:2 end:2)] @@ -12,8 +14,8 @@ Availability:Licensee [REGION:simpletable] | アイテム | 情報 | | ---- | ---- | -| **Label** | QA_APPROVED_UE4_BUILD_2013_09 | -| **Changelist #** | 1844454 | +| **ラベル** | QA_APPROVED_UE4_BUILD_2013_09 | +| **チェンジリスト #** | 1844454 | | **VISUAL STUDIO VERSION** | Microsoft Visual Studio 2012 バージョン 11.0.60610.01 Update 3 | | **DIRECTX** | 2010年6月 | [/REGION] @@ -50,7 +52,7 @@ Availability:Licensee * ストップ マーカーをダブルクリックすると、ストップするためのカラーピッカー (またはオパシティ用のスライダー) が開きます。 * 左クリックしてストップ マーカーをドラッグすると、タイムラインに沿ってストップ マーカーが移動します。 - 注記:ストップ マーカーを右クリックしても、この機能を使うことができます。 + 注記:ストップ マーカーを右クリックしても、この機能を使うことができます。 * ユーザーはカーブを手動で編集し、グラディエント エディタを非表示することもまだできます。 * **ブループリントのサーバーおよびクライアント RPC のサポート** @@ -86,7 +88,7 @@ Availability:Licensee ![](AutoInsertNodes.png) -* **Add Component ドロップダウンの改善** +* **'Add Component' ドロップダウンの改善** * 検索ボックス、 _ワンクリック_ での追加、アイコン、カテゴリを追加しました。 ![](AddComponentDropdown.png) @@ -110,17 +112,17 @@ Availability:Licensee 中には非常に負荷の高い関数もあるので、使用する際にはパフォーマンスに十分気をつけてください。 [/REGION] -* **アクタ外の Latent 関数** +* **アクタ以外での Latent 関数の使用** * Latent 関数 (Delay など) はどんな _ブループリント_ においても使用することができます! ![](LatentFunctionsOutsideActors.png) * **インターフェース編集モード** - * 必要なものだけ含まれるようにインターフェースを編集する特別なモードがあります。**Interface** モードといいます。 + * 必要なものだけ含まれるようにインターフェースを編集する特別な **Interface** モードというモードがあります。 ![](InterfaceEditorMode.png) -* **作成したコンポーネントはどこにでもアタッチ** +* **作成したコンポーネントをアタッチする** * 作成した _コンポーネント_ をドラッグ&ドロップして、ネイディブ シーンのコンポーネント階層のどこにでもアタッチすることができるようになりました。 * さらに、子 _ブループリント_ に作成した _コンポーネント_ も、親 _ブループリント_ から継承した SceneComponent 階層のどこにでもアタッチすることができます。 @@ -133,12 +135,12 @@ Availability:Licensee ![](DefaultSceneRoot.png) * 追加した _SceneComponent_ は新規 _コンポーネント_ に対してスワップアウトされて、新規ルートになります。 -* **ノード用のショートカット** - * キーを押したまま、ノードクリックすれば、ノードを素早く配置できます! +* **ノードのショートカット** + * キーを押したまま、ノードをクリックすれば、ノードを素早く配置できます! ![](ShortcutsforNodes.png) - * 現在あるショートカットは以下の通りです。`UserSettings.ini` ファイルに更に追加可能です。 _ブループリント_ の **Keybindings** インターフェースが機能するようになりました! + * 現在使用できるショートカットは以下の通りです。`UserSettings.ini` ファイルに更に追加可能です。 _ブループリント_ の **Keybindings** インターフェースが機能するようになりました! | ノード | 目的 | | --- | --- | @@ -170,7 +172,7 @@ Availability:Licensee * サポートされているアセットに対して、アセットメニューから再インポート オプションが利用できるようになりました。 * コンテンツを保存するウィンドウで、Diff オプションがアセットに使用できるようになりました。 * 空のマップには、デフォルトの光源とプレイヤーの開始地点が含まれています。 -* レベルをを削除すると、その状況に応じた警告メッセージが出され、抑制可能になりました。 +* レベルをを削除すると、その状況に応じて異なる警告メッセージが出され、抑制可能になりました。 * アクタの選択が **Play In Editor**/**Simulate In Editor** セッションで実施され、終了するとエディタへ戻るようになりました。 * アセット エディタ プラグイン拡張ポイントが全て状況に応じて変化し、編集中のアセットがどれかを意識するようになりました。 * **被破壊メッシュエディタ**:FBX ファイルを深度 1 被破壊性チャンクとしてインポートします。 @@ -184,7 +186,7 @@ Availability:Licensee #### ブループリント * `ExpandEnumAsExecs` メタデータへのサポートを追加しました。これにより、関数列挙型変数パラメータを複数の実行入力として公開できるようになります。 * **GetAllActorsOfClass**、**GetActorArrayAverageLocation**、**GetActorArrayBounds**、**MoveActorToActor** を `GameplayStatics` に追加しました。 -* コンポーネントの位置 / 回転を徐々に補間するために **MoveComponentTo** lLatent (潜行) 関数を追加しました。 +* コンポーネントの位置 / 回転を徐々に補間するために **MoveComponentTo** latent (潜行) 関数を追加しました。 * _ブループリント_ で `FText` のサポートを追加しました。 * **GetVectorArrayAverage** 、 **GetMinElement** 、 **GetMaxElement** を `MathLibrary` に追加しました。 * **RotateVector** 関数と **UnrotateVector** 関数をローテーターに追加しました。 @@ -204,7 +206,7 @@ Availability:Licensee * 完了した移動リクエスト ID を結果と一緒に送信するために, `AIController` の "move finished" マルチキャスト デリゲートを拡張しました。 * `StaticMesh` が `AssetUserData` オブジェクトをサポートするようになり、エンジンを修正せずにプロジェクト固有のデータを格納できるようになりました。 * `FTransform` プロパティ上の 3D ウィジェットに対するサポートを追加しました。 - * スクリーン空間で青いウィジェットダイヤモンドを固定のサイズにしました。 + * スクリーン スペースで青いウィジェット ダイヤモンドを固定のサイズにしました。 * シンプルにゲームを保存できるシステムを追加しました。ワールドのステート全体のキャプチャ用には作成されていません。 _ブループリント_ で利用可能です。 * スクリーンショットがビデオのように通知を表示するようになりました。 * Map Check がサマリを印刷するようになったので、ユーザーは完了したことが分かります。 @@ -238,13 +240,13 @@ Availability:Licensee * 所有するアクタとその設定 / 破棄を決定するネットコード群をリファクタリングしました。 -#### レンダリング +#### Rendering * Visualizetexture/vis がさらに多くのアイテムをフィルタし、ソート処理が遅くなりました ("vis ?")。 * 複数の拡張性コンソール変数を追加しました。 * DX11 と OpenGL RHI 用の Timer クエリを実装しました。 -* 最も基本的な関数 (r.SSSSS 1) だけですが、スクリーン空間サブサーフェス スキャタリングを追加しました。 +* 最も基本的な関数 (r.SSSSS 1) だけですが、スクリーン スペース サブサーフェス スキャタリングを追加しました。 * GPUBenchmark が SynthBenchmark (既知の問題: 非常に遅い GPU 上だと対有無アウトする) の一部になりました。 -* スクリーン空間のライトシャフト +* スクリーン スペースのライトシャフト * ライトシャフトには、フォグ / 大気のみ影響を与えるオクルージョンと物理ベースではないブルームの 2 種類があります。 * **VisualizeOutOfBoundsPixels** 表示フラグを追加し、ストリップされたパターン内の領域外にあるピクセルに色をつけます。 * リフレクション環境キューブマップが DerivedDataCache にキャッシュされるので、取り込む度に再キャプチャする必要はありません。 @@ -268,7 +270,7 @@ Availability:Licensee #### オーディオ -* ステートマシーン グラフとサウンドキューにコメントボックスを追加しました。 +* ステートマシーン グラフとサウンド キューにコメント ボックスを追加しました。 * Enveloper Sound ノードにより、ビジュアル カーブの編集と Curve Float アセットの使用が可能になりました。 @@ -304,410 +306,410 @@ Availability:Licensee * Game Center の友達のサポートを追加しました。 * Game Center のリーダーボードのサポートを追加しました。 * Game Center の ID / プロフィールのサポートを追加しました。 -* マイクロトランザクション用のプラットフォームを提供するために、 Online Subsystems に Store インターフェースを追加しました。 +* マイクロトランザクション用のプラットフォームを提供するために、Online Subsystems に Store インターフェースを追加しました。 * App 購入サポートに IOS を追加しました。 * 検索結果を与える接続をするために `GetResolvedConnectString` を追加しました。 * `CreatePlayerUniqueId` を変更して、安全のために size パラメータが含まれました。 -## 更新ノート +## アップグレード ノート #### エディタとツール -* **Play In Editor** ビューポートはプレイ中のエディタからすぐにではなく、最初のクリックでフォーカスするようになりました。 - * 新規リファレンス ページが **[Editor Settings] > [Play In] > [Play in Editor]** に追加されました。 - * マウス コントロールをすぐにオンにするには **Game Gets Mouse Control** を有効にします。 -* デバイス上で起動するための基本的な機能を実装しなおしているので、 **[Launch On]** ボタンは現在非表示になっています。 -* ブランチ別にミューテックスに名前をつけて、複数のブランチを同時に実行できるようにしました。 -* **スレート** - * **Slate** コンテキスト ウィンドウの終了順序を変更して、メニュー スタック型ではないウィンドウが破棄される前に入力フォーカスのハンドオーバーを行うようになりました。 - * `InArgs._Style` が有効な場合、`SInlineEditableTextBlock` を変更して `InArgs._Style` から `SEditableTextBox` フォントをオーバーライドして、できるだけ Styles が一貫性を保てるようになりました。 - * ロックされたレベルへアクタを追加する際のユーザー通知を **Slate** UI 通知に変換しました。 -* **スタティック メッシュ エディタ** でのソケット作成にアンドゥ / リドゥを使用できるようになりました。 -* **マチネ** でトラック名とグループ名の変更にアンドゥ / リドゥを使用できるようになりました。 -* `LocalizeUnrealEd` コールを `LOCTEXT`/`NSLOCTEXT` に変更し、`UE_LOG` などのローカリゼーション手法が使われている様々なコールをリファクタリングしました。 -* **[Grid]** メニュー オプションを **[Advanced (詳細)]** からメインの **[Show (表示)]** メニューに移動しました。 -* LOD (Level of Detail) ポップアップの [OK] メッセージを通知に変更しました。 -* Copy/paste of collision in **スタティック メッシュ エディタ** でコピー / ペーストしたコリジョンが、ビューポートに正しく反映されるようになりました。 -* レベルを追加すると、最後に追加したフォルダが記憶されるようになりました。 -* Hide UI トグルをビューポートから [View (表示)] ツールバーへ移動しました。 -* **[Select all with same Archetype (同じ Archetype をすべて選択)]** メニュー オプションを削除しました。 -* **レベル エディタ** ビューポートのアクタをダブルクリックすると、カメラはその選択対象をフォーカスします。 -* アクタ名がブランクだとエラー通知が表示されます。 -* アンドゥ / リドゥ機能が **マテリアル インスタンス エディタ** に追加されました。 -* [**PhAT** Body Physics Type] メニュー オプションがラジオボタンに変更されました。 -* `SWindow` は、ウィンドウ サイズではなく希望するクライアントの領域サイズを構造パラメータとして受け取るようになりました。 +* **Play In Editor** viewports will no longer immediately take focus from the editor on Play, but on first click. + * A new preference section has been added to **Editor Settings > Play In > Play in Editor**. + * To turn on immediate mouse control enable **Game Gets Mouse Control**. +* The **Launch On** button is currently hidden while we re-implement the underlying functionality to launch on devices +* Changed mutex to be named per-branch to allow several branches to run simultaneously +* **Slate** + * Modified the **Slate** context window dismissal order so non menu stack windows do the input focus handover before being destroyed. + * Modified `SInlineEditableTextBlock` to override the `SEditableTextBox` font with the font from the `InArgs._Style` provided the `InArgs._Style` is valid, so the Styles remain consistent where possible. + * Converted the user notification for adding an actor to a locked level to a **Slate** UI notification. +* Undo/redo now works for creation of sockets in the **Static Mesh Editor**. +* Undo/redo now works for Track and group renames in **Matinee**. +* Replaced the `LocalizeUnrealEd` calls with `LOCTEXT`/`NSLOCTEXT` and refactored a lot of other calls that used localization methods such as `UE_LOG`. +* Moved the **Grid** menu option from **Advanced** and into the main **Show** menu. +* Changed the level of detail (LOD) popup ok messages to notifications instead. +* Copy/paste of collision in **Static Mesh Editor** now updates the viewport correctly. +* Adding a level now remembers what folder you added from last. +* Moved the Hide UI toggle from the viewport to the View toolbar. +* Removed the **Select all with same Archetype** menu option. +* Double clicking an actor in the **Level Editor** viewport now focuses the camera on that selection. +* Giving an actor a blank name now displays a error notification. +* Added Undo/redo functionality to the **Material Instance Editor**. +* Changed the **PhAT** Body Physics Type menu options to radio buttons. +* `SWindow` now takes the desired client area size instead of window size as its construction parameter -#### ブループリント -* ヘルス値をポーンから削除し、デス (機能停止) をエンジンから削除しました。 - * ゲームがヘルス値変数を独自の Pawn クラスへコピーする必要があります。 - * ヘルス値とデスを使う全てのサンプル ゲーム (QAGame, ShooterGame ) は、それぞれのヘルス値 / デスを実装するように更新されました。 - * 関連するイベントが削除されました (OnDeath、 OnPlayDying)。ゲームがこれらを単純にコピーする場合もあります。 -* ブループリント用に C++ で作成されたキャラクター移動入力バインディングを削除しました。 - * 今までは、キャラクター上のブール変数 bAddDefaultMovementBindingsForBlueprint によりこれらはデフォルトで有効になっていました。 - * ブループリントは、それぞれ独自のバインディングを追加しなければならなくなりました (ThirdPersonTemplate_BP プロジェクトでサンプルをご覧ください)。 -* OnNodeCommentTextCommitted で大文字小文字を区別するように文字列比較を変更したので、ノード コメントのテキストの編集や修正に大文字と小文字を使用できます。 -* ブループリント エディタの Variable Get/Set グラフ ノードに変数を表示する機能を追加しました。 -* ブループリント エディタのコンテンツを移動せずにコメントを移動できるように、モディファイアのキーステート (L/R Shift) を追加しました。 -* Filemenu Addtofavourites UI のツールチップ テキストを「Add to favourite files」ではなく「add to favourites levels」に修正しました。 -* メッセージ ログ エントリ アイコンと一致するようにメッセージ ログ フィルタのボタンを変更しました。 -* ShapeComponent :シェイプ タイプを元にする場合、不均等のスケーリングをサポートします。 -* DrawDebug 関数がサポートする時間のオプションが増えました (DrawOneFrame 、DrawDuration、DrawPersistent) +#### Blueprints +* Health has been removed from Pawn, and Death has been removed from the engine. + * Games will need to migrate the Health variable to their own Pawn classes if desired. + * All sample games using health and death (eg QAGame, ShooterGame) have been updated to implement health/death on their own. + * Some related events have been removed (OnDeath, OnPlayDying).Games may simply migrate those as well if desired. +* Character movement input bindings that were created in C++ for Blueprint classes have been removed. + * These were previously enabled by default by a bool bAddDefaultMovementBindingsForBlueprint on Characters. + * Blueprints will now need to add their own bindings (see the ThirdPersonTemplate_BP project for a simple example). +* Modified the string comparison to be case aware in OnNodeCommentTextCommitted so you can edit and correct node comment's text case. +* Added the ability to view variables for Variable Get/Set graph nodes in the Blueprint editor. +* Added a modifier key state (L/R Shift) to allow you move comments without moving the contents in the Blueprint editor. +* Modified the Filemenu Addtofavourites UI tooltip text to "add to favourites levels" instead of "Add to favourite files" +* Changed the message log filter button icons to match the message log entry icons. +* ShapeComponent :Support non-uniform scale when it can based on shape type. +* DrawDebug functions supports more options for time(DrawOneFrame, DrawDuration, DrawPersistent) -#### ゲームプレイとフレームワーク -* シンプルな MoveToLocation 関数と MoveToActor 関数が意味のある値を返すように更新しました。 -* DynamicBlockingVolume DynamicPhysicsVolume と DynamicTriggerVolume を削除しました。 -* デザイナが見やすいように、幾つかのランタイム時の警告を 'Message Log' に移動しました。 -* HUD に ReceiveHitBoxRelease を追加し、 ReceiveHitBoxClick から InEventType を削除しました。 -* 機能探知のターゲット プラットフォーム を単純化しました。`ITargetPlatform::SupportsFeature()` を参照してください。 -* 設定 API が若干変更されました。必要な編王については既存の使用方法を参照してください。 -* ネットワーク上でのメッセージを有効にするためには、追って通知があるまで `-Messaging` コマンドライン スイッチが必要になります。 -* `AActor::Owner` が private 変数になりました。access/set には Get/SetOwner を使います。 -* ゲームパッド キーのクリーンアップ - * `EKeys` 列挙型変数で定義されているゲームパッド キーはく XboxTypeS_ ではなく Gamepad_ と呼ばれるようになりました。 - * XBox 特有のキーである `A`、 `B`、 `X`、 `Y`、 `Start`、 `Back` が一般的な名前に変わって、それぞれ `FaceButton_Bottom`、 `FaceButton_Right`、 `FaceButton_Left`、 `FaceButton_Top`、 `Special_Right`、 `Special_Left` となりました。 - * Epic Labs 機能により、ゲームパッドのコンソール固有のラベルがドロップダウンと _ブループリント_ ラベルで表示されます。 - * ゲームパッド サムスティック用のバーチャルな上下左右のイベントが結合されました。 -* `FObjectFinder` はクラス コンストラクタ外では使用できなくなりました。他のコードでの使用を試みると、アサートされる結果になります。 -* **物理** - * コリジョン トレース タイプを [オブジェクト タイプ] と [トレース タイプ] に分けました。オブジェクト タイプは、これまでの `MovementChannel` ( Object Type という名前に変更されました) として使用できるようになりました。 - * カスタム仕様のチャンネルの場合 - * そのタイプをオブジェクトの Object Type として使用できるのであれば、それをオブジェクト タイプとして示さなければなりません。 - * そのタイプがコードでトレースに使用される場合、次の例のように Trace Type として示します。 +#### Gameplay and Framework +* Updated simple MoveToLocation and MoveToActor functions to return meaningful values +* Remove DynamicBlockingVolume DynamicPhysicsVolume and DynamicTriggerVolume +* Several runtime warnings now go to the 'Message Log' to make them more visible to designers +* On HUD, add ReceiveHitBoxRelease and remove InEventType from ReceiveHitBoxClick +* The target platform API for feature detection has been simplified; see `ITargetPlatform::SupportsFeature()` +* The settings API slightly changed; see existing usages for the required changes +* To enable messaging over the network, the `-Messaging` command line switch is required until further notice +* `AActor::Owner` is now a private variable.Use Get/SetOwner to access/set. +* Gamepad key cleanup + * Gamepad keys defined in `EKeys` enum no longer are called XboxTypeS_ and are instead Gamepad_ + * XBox specific keys `A`, `B`, `X`, `Y`, `Start`, and `Back` renamed to generic `FaceButton_Bottom`, `FaceButton_Right`, `FaceButton_Left`, `FaceButton_Top`, `Special_Right`, `Special_Left` + * Epic Labs feature to show console specific labels for gamepads in dropdowns and _Blueprint_ labels. + * Virtual up/down/left/right events for gamepad thumbsticks now hooked up +* `FObjectFinder` can no longer be used outside of class constructors.Any attempt to use it in other code will result in an assert. +* **Physics** + * Collision trace type has been separated to [object type] vs [trace type].Object types can be used as previously `MovementChannel` (now renamed to Object Type) + * For your custom channels + * If that type can be used as Object Type for objects, you should mark that as object types + * If that type is used for trace in code, mark as Trace Type as below example:. - +DefaultChannelResponses=(Channel=ECC_GameTraceChannel1, Name=Weapon, bTraceType=true) + +DefaultChannelResponses=(Channel=ECC_GameTraceChannel1, Name=Weapon, bTraceType=true) - * この変更により、"Trace for objects" API がサポートされるようになりました。これにより、"所定のオブジェクト タイプ" をもつオブジェクトの検索ができるようになります。 - * オブジェクトが移動したり衝突すると、オブジェクト タイプに対する応答が使用されます。 + * With this change, now we support "Trace for objects" APIs.This will let you find any objects with "given object types". + * The response against object type is used when the object moves or collide -#### レンダリング -* Material Property **RefractionBias** が **RefractionDepthBias** という名前になりました。 +####Rendering +* Material Property **RefractionBias** is now called **RefractionDepthBias**. -#### アニメーション -* _SingleAnimSkeletalComponent_ が削除されました。_SkeletalMeshComponent_ を使って AnimationMode と同じ事ができるようになりました。 -* _SkeletalPhysicsActor_ が削除されました。_SkeletalActor_ で同じ事ができるようになりました。 -* SlaveComponent が **マチネ** と **AnimTrack** でサポートされました。 +#### Animation +* _SingleAnimSkeletalComponent_ is removed.Now you can use _SkeletalMeshComponent_ to do the same thing using AnimationMode. +* _SkeletalPhysicsActor_ is removed.Now you can use _SkeletalActor_ to do the same +* SlaveComponent is supported in **Matinee** **AnimTrack** -#### コア -* プロパティへ書き込みたくない場合に保存した config ファイル (`.ini`) に保存できるように`SaveConfig` 機能を更新しました。 -* 初期化されていないオブジェクトを挿入するための `TArray` の int32 コンストラクタは、使い方を間違えやすいので削除しました。 - * 代わりに、以下の明示的な形を使用します。 +#### Core +* Updated the `SaveConfig` functionality so if we do not want to write to a property to a saved config file (`.ini`) +* `TArray`'s int32 constructor to insert uninitialized objects has been removed as it was too easy to use incorrectly. + * The following explicit form should be used instead: TArray Vals; Vals.AddUninitialized(Num); -* Globalization の名前をより正確に *Internationalization へ変更しました。 - * これらのクラスへのすべてのリファレンスとコンフィギュレーション セクションを更新しました。 -* `FText` メッセージのフォーマット機能は、コメント化されたパラメータをサポートしなくなりました。IE: `"{0?PlayerScore}"` - * その代わりに、指定されたパラメータを使用します。IE: `"{PlayerScore}"` -* `EAxis` 列挙型変数が `EAxisList::Type` という名前に変更されました。この変更を反映させるには、クライアント コードを変更する必要があります。 -* `FMatrix`/`FTransform` 軸関数は軸の特定に整数ではなくEAxisList::Type を使用するようになりました。全ての使用を変更する必要があります。 -* Visual Studio 2012 がデフォルトで使用できるようになりました (2010 のサポートも継続します)。 - * すべてのゲームとプログラムで Visual C++ 11 コンパイラが使用されるようになりました。 - * UE4 ソリューションとプロジェクト ファイルは、デフォルトで 2012 ネイティブのフォーマットで生成されるようになりました。 - * 必要であれば、 Visual Studio 2010 も引き続き使用できます (今のところ!)。 - * `UEBuildWindows.cs` に `WindowsPlatform.Compiler = WindowsCompiler.VisualStudio2010` を設定します。 - * `-2012` を `GenerateProjectFiles.bat` に渡します。 - * VS 2012 の変更に対して、サードパーティの *.Build.cs ファイルを更新する必要がある場合があります。 - * `bUseVisualCPlusPlus11` が UnrealBuildTool の `WindowsPlatform.Compiler` に変更されました。 -* Visual Studio プロジェクト レイアウトが新しくなりました。 - * 1 つのゲームに対しプロジェクトが 1 つだけになりました。 - * Build & Run プロジェクトを取り除きました。Fake ターゲット プロジェクトを取り除きました。 - * [Solution Configuration] ドロップダウンを使って _ターゲットのタイプ_ を選択できるようになりました。 - * クックされたゲームあるいはプログラムのビルドと実行には、Debug or Development (サフィックスなし) を使います。 - * プロジェクト ファイル生成と、通常 UBT ビルドの実行が速くなりました! - * デフォルトにすべてのプラットフォームは含まれず、Win64 か Mac のいずれかのみ取得します。 - * 他のプラットフォームをビルドする必要がある場合は、新規の`GenerateProjectFiles_AllPlatforms.bat` ファイルを使います。 - * ソリューションは上位 4 つのフォルダになりました。 - * コードはすべて、ゲームのプロジェクトの下にディスク上と同じように整理されて置かれるようになりました。 - * その他の注記 - * シッピングとテスト コンフィギュレーションがデフォルトで削除されました。これらを取得するためには `-ShippingConfigs` を渡します。 - * Rocket ターゲットは、デフォルトでプロジェクト ファイルに含まれなくなりました。これらを取得するためには、 `-RocketTargets` を渡します。 - * Non-English UDN ファイルがプロジェクト ファイルから削除されました。これらを取得するためには、'-AllLanguages' を渡します。 - * Visual Studio を終了するたびに、 `UE4.sln` の上書きを求められなくなりました。 - * 必要に応じて、 `-NoIntelliSense` での IntelliSense 生成をスキップできるようになりました。 - * WinRT は UBT に対して _デスクトップ プラットフォーム_ とみなされなくなりました。 - * エディタの Shipping config と Test config は UE4 ではサポートされていないので、UI から削除しました。 -* 削除されたアクタ上の SceneComponents にアタッチされている SceneComponents のみをデタッチするように DestroyActor を変更しました。 -* コード ブロック、スパン、クオートの変数とメタデータ参照を無視したままにするように、マークダウン プロセスを変更しました。 -* PUBLISH タグの処理に使用する regex を改善して、タグの後の同じ行に空白文字を入れられるようになりました。 -* ゲームタイプのリファクタリング - * ゲーム関連の幾つかの基本クラスを名前変更しました。 - * GameInfo は GameMode になりました。 - * GameReplicationInfo は GameState になりました。 - * PlayerReplicationInfo は PlayerState になりました。 - * ReplicationInfo 基本クラスは削除されました。 - * リダイレクタが導入され、これらのクラスを使用するとすべてシームレスで更新されるようになります。 -* CRU で発生すべきでない (実際は発生している) エラーに対し、例外チェックを追加しました。 -* 不明瞭なクラッシュを見つけやすいように、ドメイン例外ハンドラを追加しました。 -* **UE4Redist が UE4PrereqSetup に置き換えられました** - * Windows プラットフォームでの UE4 実行の必須条件をインストールすrために、新しい `UE4PrereqSetup.msi` プログラムを使用するようになりました。 `UE4Redist.exe` は使用しなくなり、P4 から削除されました。 - * UE4PrereqSetup は現在 Perforce の `//depot/UE4/Engine/Extras/Redist/en-us/UE4PrereqSetup.msi` にあります。 - * UE4PrereqSetup をインストールする必要は全くありません。他のプログラムと同様、削除したい場合はコントロール パネルを使ってください。 +* Globalization has been more accurately renamed as *Internationalization. + * Update all references to these classes and configuration sections. +* `FText` message formatting no longer supports commented parameters.IE: `"{0?PlayerScore}"` + * Use named parameters instead.IE: `"{PlayerScore}"` +* The `EAxis` enum has been renamed to `EAxisList::Type`.Client code will need to be changed to reflect this. +* `FMatrix`/`FTransform` axis functions now use EAxisList::Type rather than an integer to specify the axis.All usage will need to be changed. +* Visual Studio 2012 is now used by default (2010 is still supported) + * All games and programs now use the Visual C++ 11 compiler. + * UE4 solution and project files are now generated in 2012-native format by default. + * If you need to continue using Visual Studio 2010, you still can (for now!): + * Set `WindowsPlatform.Compiler = WindowsCompiler.VisualStudio2010` in `UEBuildWindows.cs` + * Pass `-2012` to `GenerateProjectFiles.bat` + * You may need to update your third-party *.Build.cs files for VS 2012 changes + * `bUseVisualCPlusPlus11` has been changed to `WindowsPlatform.Compiler` in UnrealBuildTool +* New Visual Studio project layout + * There is now only one project file for each game + * Build & Run projects are eliminated; Fake target projects are eliminated + * You now choose your _target type_ using the Solution Configuration dropdown + * To build and run the Cooked Game or Program, just use Debug or Development (no suffix) + * Project file generation and regular UBT builds run faster! + * We no longer include all platforms by default.Instead, you only get either Win64 or Mac. + * If you need to build other platforms, there is a new `GenerateProjectFiles_AllPlatforms.bat` file for that. + * Solution has flattened down to just four top-levels folders. + * All code is now under your game's project file, organized the same way it is on the disk. + * Other notes + * Shipping and Test configurations are omitted by default.Pass `-ShippingConfigs` to get those. + * Rocket targets aren't included in the project files by default.Pass `-RocketTargets` to get those. + * Non-English UDN files are now omitted from project files.Pass '-AllLanguages' to get those. + * Visual Studio no longer prompts you to overwrite `UE4.sln` every time you exit + * You can now skip IntelliSense generation with `-NoIntelliSense` if you want. + * WinRT is no longer considered a _desktop platform_ to UBT + * We removed Shipping and Test configs for Editor from the UI, because they aren't supported in UE4 +* Changed DestroyActor to only detach SceneComponents attached to SceneComponents on the deleted actor. +* Changed markdown process to leave variable and metadata refs in code blocks, spans and quotes ignored. +* Improved regex used to handle PUBLISH tags to allow whitespace on the same line after tags +* Game type refactor + * Several game-related base classes were renamed + * GameInfo is now GameMode + * GameReplicationInfo is now GameState + * PlayerReplicationInfo is now PlayerState + * ReplicationInfo base class was removed. + * Redirectors are in place and all uses of these classes should update seamlessly. +* Added exception check to error that should not occur (but does) in CRU +* Added domain exception handler to help track down obscure crash +* **UE4Redist has been replaced with UE4PrereqSetup** + * To install prerequisites for running UE4 on Windows platform, we'll now use the new `UE4PrereqSetup.msi` program. `UE4Redist.exe` should no longer be used and has been deleted from P4. + * In Perforce, UE4PrereqSetup is currently located in `//depot/UE4/Engine/Extras/Redist/en-us/UE4PrereqSetup.msi` + * You should never really need to uninstall it, but if you need to just use the Control Panel to remove it like any other program. -#### オンライン -* Online Stats を更新して、統計情報の Leaderboard (成績表) の一部を独自のクラスへ抽出しました。 +#### Online +* Updated the Online Stats so that the stats part of leaderboards write we extracted to its own class * **Base OnlineSubSystem** - * OnlineSubSystem ログのプレフィックスを追加しました。 - * アイデンティティ インターフェイスへのプロファイル インターフェースをリファクタリングしました。 + * Added prefix for OnlineSubSystem logs + * Refactored profile interface into identity interface * **Facebook OnlineSubSystem** - * PC 用に Facebook を初めて実装しました。 - * ブラウザ ウィンドウ経由でアクセス トークン取得のログインができるようになりました。 - * 有効な場合、トークンを使って基本/自分の情報をリクエストできます。 - * Facebook PC OnlineSubSystem 友達追加機能の実装しました。 + * Initial Facebook implementation for PC + * Allows login via browser window for retrieving access token + * Requests basic /me info using token if valid + * Added friends implementation for Facebook PC OnlineSubSystem * **MCP OnlineSubSystem** - * アカウント マッピング要求以外のすべてのものに、同じユーザー認証方法を使用します。 - * サーバー権限をクライアントとサーバーの設定に分類しました。 - * すべてのホスト (リッスン / デディケイテッド サーバー) が、 Mcp リクエストを行う代わりに認証方法の代わりににサービス権限を強制的に使用するようにしました。 - * 同じ認証方法で同時に行ったログインを検出するために使用する起動 API を追加しました。 - * 外部のアカウント情報をユーザーに問い合わせるために必要な OnlineSubSystem MCP 機能を追加しました。 - * Epic のアカウントから名前を表示するために使用することができます。 - * 自動ログインをすると、ID と認証チケットが与えられた、キャッシュされたユーザー アカウントが作成されます。 - * Epic のアカウント情報を取得するための `QUERYACCOUNT` が追加されました。 - * `ACCOUNTCREATION` exe を `CREATEACCOUNT` に変更しました。 - * ダウンロードした mcp ファイルのディスクへのキャッシュ処理を無効にするconfig オプションを追加しました。 - * mcp config セクションをコマンドライン `-MCPCONFIG= ` でオーバーライドしました。 + * Use the same consistent user auth method as everything else for account mapping requests + * Split service permissions into a set for client vs server + * Forced all hosts (listen / dedicated server) to use service permissions instead of user auth method for making Mcp requests + * Added new activation API to be used for detecting simultaneous login with the same credentials + * Added OnlineSubSystem MCP functionality needed to query external account info for a user + * Can be used to get display name from epic account + * Autologin creates a cached user account given an id & auth ticket + * Added `QUERYACCOUNT` for retrieving epic account info + * Renamed `ACCOUNTCREATION` exec to `CREATEACCOUNT` + * Added config option for disabling caching of downloaded mcp files (user,title) to disk + * Override mcp config section via command line override `-MCPCONFIG= ` * **Http** * WinInet - * 既に送信途中にあるリクエストを完了させるための WinInet の `CancelRequest` を実装しました。 - * リクエストをキャンセルしても、全ての completion デリゲートを呼び出します。 - * 利用できる場合は、キープアライブ機能を使って、接続を開いた状態のままにします。 + * Implemented `CancelRequest` for WinInet to finish a request that is already in flight + * Cancelling a request still calls all completion delegates + * Keep connection open using keep-alive functionality if available -## 今後の追加事項と継続事項 +## Future Additions and Ongoing Efforts -#### エディタとツール -* エディタからゲームへの切り替え時にうっかり相互作用してしまわないように、 **Play In Editor** ビューポートのウィンドウ内をクリックしても、1 回目はゲームへ継承しません。 -* BSP サーフェス reslove にダブルバッファリングが使われるようになりました。 -* タブが付けられたアセットエディタを使うために **Curve Editor** を更新しました。 -* 他のアプリの全面にポップアップ表示されないように、通知をリバートしました。 -* ユーザーが使いやすいように、ロードのエラーメッセージのログ出力を改善しました。 -* マップチェックは、ライトがビルドされるたびにログをポップアップ表示するのではなく、通知を追加しました。 -* Pr**Play In Editor**/**Simulate In Editor**モードでアクタを選択する際にクラッシュしないようにしました。 -* プロジェクトがソール管理下にない場合、共有のコレクションは作成することができません。 -* NULL ポストプロセス カメラ コンポーネント上でクラッシュが起こらないようにしました。 -* 使用が許可されていないキャラクターを更新して、プロジェクトのパス名の制限が緩くなるようにしました。 -* アクタのドラッグ / ドロップが、ドラッグではなくドロップでのみ選択されるようになりました。 -* 追加されたパッケージがコンテキスト メニューのパス・ビュー・コンテキスト・メニューにより、ソース コントロールに追加される前に保存されるようになりました。 - * これにより、Perforce でのファイルの破壊を防ぐことができます。 -* ストライプの背景を削除するために **Level Browser** カラーピッカーを親にしました。 -* ドラッグ&ドロップで BSP に適用しているマテリアルがビューポートのフォーカスを正しくリストアするようになりました。 -* ウィジェット モードの切り替え時には、必ず HitProxy がリフレッシュされるようにしました。 -* マテリアル エディタのアンドゥ / リドゥ操作は 2 回実行しません。 -* **Map Check** がライトのリビルドが必要だということを間違って報告をしないようにしました。 -* シャットダウン時にディレクトリ ウォッチャーのクラッシュが起こらないようにしました。 -* 読みやすさ / ユーザビリティを改善しやすいように、メッセージログを少し変更しました。 -* ビデオ キャプチャの動作が止まらなくなったことを確認しました。 -* サポート対象のすべてのツールバー/メニューバーに対して拡張デリゲートを追加しました。 -* 選択を変更すると、、正しい親がプロジェクト ウィザードに表示されるようになりました。 -* シャットダウンが既に実行されていると、タブの終了が承認されます。 -* null ノードが見つけやすいように、ensure 条件を追加しました。 -* 無効化された **Context Sensitive** を含むノードからドラッグすると、すべての可能なアクションが表示されます。 -* 情報が複製でないことを表すために、 **Map Check** ドロップダウンがその代わりにワールドの名前を表示するようになりました。 -* **Save Layout** がユーザー設定をディスクに書き込むようになりました。 -* **Matinee** コンボボックスのスペース使用が減りました。 -* **レベル エディタ** の **ツールバー** がビューポート上で表示されるようになりました。 -* デフォルトのライトは、少しだけ視界が遮られているだけで、オリジナルに近くなりました。 -* コンテキスト メニューにおけるデタッチの扱い方を修正しました。 -* プロパティ スライダーの使用中に通知のスパムが起こらないようになりました。 -* 記録をアンドゥして動画を実行してもクラッシュしないようになりました。 -* **Buffer Visualization** コマンドがなければ、エディタが継続できるようになりました。 -* 相当する _SkeletalMesh_ の再インポート時に、 _PhysicalAssets_ の `DefaultSkeletalMesh` メンバがリストアされます。 -* レベルにアセットをドラッグすると、非表示のアクタが考慮されるようになりました。 -* **Matinee** ビューポートが `Tick` が呼び出されるように `IsVisible()` を使用するようになりました。 -* レベルを削除する時は null グループ ポインタを防ぎます。 -* **[New Level]** ダイアログのスクロール バーがサムネイルにオーバーラップしなくなりました。 -* `Source` フォルダがないと、 **Generate Visual Studio Files** を早めに出してユーザーに警告します。 -* **Crash Reporter** が UE4 のクラッシュに対するチェンジリストとコールスタックを正しく報告するようになりました。 -* デフォルトのマップ設定名を変更し、正しく保存するようになりました。 -* Template マップがエディタに自動的にロードされるようになり、不注意による上書きを防ぐための起動時の保存が必要なくなりました。 -* ドロップダウン メニューが大きすぎてアンカー ウィジェットの上あるいは下に入りきらない場合、正しく表示されるようになりました。 -* ウィンドウ モードで **Alt + Enter** を押すと、フルスクリーン モードからリストアする場合にウィンドウが移動したり、リサイズされなくなりました。 -* **[Message Log (メッセージ ログ)]** タブが **[Output Log (出力ログ)]** タブのようなノマドタブになりました。 -* **[Editor Settings (エディタ設定)]** の **[Source Control (ソース コントロール)]** ダイアログが、すぐにソース コントロール接続に反映されるようになりました。 -* **レベル エディタ** における _アクタ_ の複製を最適化しました。 -* 正投影ビューで BSP ブラシを編集する時に **Alt + マウスボタンのホイール** による回転軸の移動が正しく行えるようになりました。 -* _Spotlight_ を配置すると、正しいデフォルト回転が付くようになりました (既に置かれている _Spotlights_ には影響しません)。 -* **テクスチャ エディタ** でカラーチャンネルを 1 つ選択すると、チャンネルの色による調整ではなく、グレースケールで表示されるようになりました。 -* **被破壊メッシュエディタ**: - * ビューポートでチャンクを選択し、選択されたチャンクのプロパティが編集できるようになりました。 - 簡単な解説 1 - * ビューモード **Buffer Visualization** と **[Refresh (リフレッシュ)]** ボタンのアイコンを更新しました。 -* エディタのほとんどのダイアログの見かけを標準化しました。 -* **Vertex Paint** ツールにおける LOD でメッシュのワークフローを改善しました。 -* エディタで **Simulate** を実行すると、裏側で **Play In Editor** 、次に **Eject** が実行されるようになりました。これにより、シミュレートされたワールド内のすべてのアクタ上への `ReceiveBeginPlay` の呼び出しが可能になりました。 -* **スタティック メッシュ エディタ** での _ソケット_ 名の変更がインラインで行われるようになりました。 -* **その他の UI の更新** - * MapCheck アイコンを16px と 40px で作成しました。コード合わせを必要とします。 - * 接続中および未接続のアニメーション ピン用にティント可能なアイコンとアニメーション結果ノード用に 1p28x アイコン (ティント可能) を作成しました。PNG アセットのみで、コード合わせが必要です。 - * 現在の **[Clear All (すべてクリア)]** 配列ボタン アイコンを変更するためのゴミ箱を作成しました。現在の PNG もこれに変更されます。 - * **[Destructible Mesh Editor]** リフレッシュ ボタン用に 40px アイコンを作成しました。 - * カメラメッシュからバックビュー LCD を取り除いて、ソースアセットを追加しました。 - * 今回実際にカスケードに使用するアンドゥ アイコンとリドゥ アイコンを交換しました。単純な png の交換であり、破壊的なものではありません。 - * [Save All Levels (すべてのレベルを保存)] アイコン用の 16px と 40px アイコン サイズを修正しました - チェンジリストは PNG アセットの更新のみになりました。 - * _AimOffset1D_ と _BlendSpace1D_ 用にアイコンを追加しました (両方ともコード合わせが必要です)。PNG の更新のみです。 - * アイコンを _f_ 関数の記号に切り替えました。既存の PNG アセットのみを上書きします。 +#### Editor and Tools +* **Play In Editor** viewports don't propagate the first click in the window to the game, preventing accidental interaction when switching to the game from the editor. +* BSP surface resolve now uses W-buffering +* Updated **Curve Editor** to use a tabbed asset editor +* Reverted notifications so they don't pop in front of other apps. +* Improved load error message log output to be more useful to users +* Map check now adds a notification, rather than always popping up the log when building lighting +* Prevented crash when selecting actors in **Play In Editor**/**Simulate In Editor** modes +* Shared collections cannot be created if the project is not under source control. +* Prevented crash on NULL post process camera component. +* Updated disallowed characters to allow less-restrictive path names for projects +* Drag/drop Actors are only selected on drop, rather than on drag. +* Newly added packages are now saved before being added to source control via the path view context menu. + * This prevents files being corrupted in Perforce +* Parented **Level Browser** color picker to remove striped background. +* Drag-drop applying materials to BSP now correctly restores viewport focus +* Ensured HitProxy is refreshed when switching widget modes +* Material editor undo/redo does not undo/redo twice +* Prevented **Map Check** from incorrectly reporting that lighting needs rebuilding +* Prevented directory watcher crash on shutdown +* Small changes to the message log to help improve readability/usability. +* Ensures no longer stop video capture from working. +* Extender delegates added to all toolbars/menubars that support it. +* Correct parent now appears in project wizard when alternating selections. +* Approve tabs for closure when shutdown is already in effect. +* Additional ensure conditions added to help track down null node. +* Dragging from a node with **Context Sensitive** disabled now shows all possible actions. +* **Map Check** dropdown now displays the name of the world instead, to indicate that its not duplicate information. +* **Save Layout** now writes the users settings to disc. +* **Matinee** comboboxes now take up less space. +* **Level Editor** **Toolbar** now appears above the viewport. +* Default light is now closer to origin, just slightly out of view. +* Modified how detach is handled in the context menu. +* Prevent notification spam while using property sliders. +* Crash no longer occurs when running movie after undoing recording. +* Allow editor to continue if a **Buffer Visualization** command is missing. +* Restore `DefaultSkeletalMesh` member of _PhysicalAssets_ when re-importing corresponding _SkeletalMesh_. +* Hidden actors are now respected when dragging assets into the level. +* **Matinee** viewport now specifies an `IsVisible()` function so that it will have its `Tick` called. +* Guard against null group pointer when removing levels. +* **New Level** dialog, scrollbar no longer overlaps thumbnails. +* **Generate Visual Studio Files** will now early out and warn the user if the `Source` folder is missing. +* **Crash Reporter** now correctly reports changelists and callstacks for UE4 crashes +* Default map settings were renamed and now save correctly +* Template maps that are auto-loaded on editor startup can no longer be saved to prevent accidental overwriting +* Drop-down menus are now displaying correctly if they're too large to fit either above or below the anchor widget +* Hitting **Alt + Enter** when in windowed mode no longer resizes the window, nor moves it, when restoring the window from fullscreen windowed mode. +* The **Message Log** tab is now a nomad tab, similar to the **Output Log** tab. +* The **Source Control** dialog in the **Editor Settings** are now reflected in the source control connection immediately. +* Optimized _Actor_ duplication in the **Level Editor**. +* Moving the pivot point with **Alt + Middle Mouse Button** when editing BSP brushes in orthographic view now works correctly. +* Placing a _Spotlight_ now has the correct default rotation (does not affect _Spotlights_ already placed). +* Selecting one color channel in the **Texture Editor** is now displayed as grayscale instead of modulated by the color of the channel. +* **Destructible Mesh Editor**: + * Chunks can be selected in viewport and the properties of the selected chunks can be edited. - Succinct description 1 + * Updated icons for the view mode **Buffer Visualization** and the **Refresh** button. +* The majority of the editors dialogs have had their looks standardized. +* Improved workflow for meshes with levels of detail (LODs) in the **Vertex Paint** tool. +* Running **Simulate** in the editor now invisibly executes a **Play In Editor** and then **Eject**.This allows `ReceiveBeginPlay` to have been called on all actors in the simulated world. +* Renaming _Sockets_ in the **Static Mesh Editor** is now done inline. +* **Miscellaneous UI Updates** + * Created new MapCheck icon at 16px and 40px.Requires code hook-up + * Created new tintable icons for the connected and disconnected animation pins and 1p28x icon (again tintable) for the animation result node.PNG assets only, require code hook-ups. + * Created new trash can icon to replace current **Clear All** array button icon - replaces existing PNG. + * Created a new 40px icon for **Destructible Mesh Editor** refresh button. + * Removed back view LCD from camera mesh, and added source assets. + * Replaced undo and redo icons actually used for Cascade this time!Not destructive - simple png replace. + * Revised 16px and 40px icon sizes for Save All Levels icon - Change List is PNG assets update only. + * Additional icons for _AimOffset1D_ and _BlendSpace1D_ (both require code hook-up).PNG updates only. + * Swapped out icon to a _f_ function symbol.Overwrites existing PNG asset only. -#### ブループリント -* **ブループリント エディタ** 内の _コンポーネント_ の名前変更がインラインで行われるようになりました。 -* _Level ブループリント_ のタイトル バーに現在のマップが反映されるように変更しました。 -* **Promote to Variable** によってユーザーは [MyBlueprint] ウィンドウでインラインで名前設定ができるようになりました。 -* ピン選択ウィジェットの Exec ピンが配列として切り替えできなくなりました。 -* _User Defined Enums_ の UI をつくりかえて、詳細なカスタマイズが使えるようにしました。 -* ピンタイプの参照および配列への切り替えが、ポップアップ メニュー外で行えるようになりました。 -* 折りたたまれたグラフは、グラフ ノードで名前変更ができます。 -* **ブループリント エディタ** の **[Component]** タブ ビューポートがパーティクルをティックするようになりました。 -* **タイムライン エディタ** の使いやすさを改善するために、右クリックのコンテキスト メニューを追加しました。 -* ルート コンポーネント ノードが **ブループリント エディタ** の **Components** モードで選択されると、変形ギズモがプレビュー ウィンドウは表示されなくなりました。 -* **ブループリント エディタ** の **Components** モードで、 _ブループリント_ プレビュー アクタへより効率よくアクセスできるようにしました。 -* Multifonts を削除しました。 -* _ブループリント_ を開いた時のデバッグ インスタンスの選択を改善しました。アセット メニューから _ブループリント_ を編集すると、デバッグするインスタンスがある場合はそれを検出します。さらに、後続の _ブループリント_ インスタンスを編集する時に、デバッグ インスタンスが正しく更新されるようになります。 -* **FloatToString** キスメット関数が余分なゼロを取り除くようになりました。 -* 関数の呼び出しにより、アンドゥ / リドゥが正しく行われるようになりました。 -* **Ctrl + K** は、_ブループリント_ 内のアクタ リファレンスの検出にも使用することができます。 -* **ブループリント エディタ** のコンポーネント モードの UI を改善しました。 - * さらに簡単に使えるようにしました。 - * クラス アイコンによるユーザーへのフィードバックを改善し、レイアウトにゆとりをもたせませました。 - * 検索ボックスでコンポーネントがすぐに検出できます。 - * コンポーネントが _カテゴリ_ へ分類されました。 -* 複数のアクタを選択した時の、 _Level ブループリント_ 内のコンテキスト メニュー オプションを改善しました。 -* 数字の検索時における false positives を防ぐために _ブループリント_ の検索結果を改善しました (検索条件から必要のないノード インデックスを削除して)。 -* _リッチ ツールチップ_ 形式のドキュメント (徐々に追加されていく) を自動検索するために、現在あるすべてのタイプのグラフ ノードを接続しました。 -* アクタだけではなく、潜在ビヘイビアを、どの _ブループリント_ でも可能にするために、潜在アクション マネージャを一般化しました (そうでない場合はティックしないアクタ上でも機能します)。潜在アクションは関数ライブラリで宣言することもできます。 -* Touch enter/leave event とデリゲートをアクタとプリミティブ コンポーネントに追加しました -* _State Machine_ entry ノードが conduit (現在ランタイム時にサポートされていません) に接続されないようにしました。 -* ソースの _ブループリント_ にコンパイル エラーある場合、 _AnimBlueprint_ インスタンスが初期化を完了しないようにしました -* _ブループリント_ グラフ配列 から NULL リファレンスを取り除くクリーンアップ コードを追加しました(_State Machines_ の削除後に保存していて、ロード時にクラッシュを引き起こしてしまう、かなり古い Animation アセットを修正しました)。 -* 互換性のないスキーマのグラフ内では変数ノードをドロップできないようにしました。 -* ノードまたはピン上にカーソルを当てていない場合でも、カーソルを当てているグラフを照会するグラフのドラッグ&ドロップ操作機能を追加しました。 +#### Blueprints +* Renaming _Components_ in the **Blueprint Editor** is now done inline. +* Synthetic names in the title bar of _Level Blueprints_ have been changed to reflect the current map. +* **Promote to Variable** will now have the user set the name inline in the MyBlueprint window. +* Exec pins in the pin selector widget are no longer toggleable as arrays. +* Redesigned the UI for _User Defined Enums_ to use details customization. +* Toggling pin types to be references and arrays can now be done outside of the pop-up menu. +* Collapsed graphs can be renamed inside the graph node. +* The **Component** tab viewport in the **Blueprint Editor** now ticks particles. +* Added a right-click context menu to the **Timeline Editor** for improved usage. +* The transform gizmo is no longer visible in the preview viewport when a root component node is selected in **Components** mode within the **Blueprint editor**. +* Made access to the _Blueprint_ preview actor more efficient in **Components** mode of the **Blueprint Editor**. +* Multifonts have been removed. +* Improved debug instance selection when opening _Blueprints_.Editing a _Blueprint_ from the asset menu will find an instance to debug if there is one.Additionally the debug instance should now update correctly when editing subsequent _Blueprint_ instances. +* **FloatToString** kismet function now trims excess zeros. +* Function connections should now undo/redo correctly. +* **Ctrl + K** can once again be used to find an actor's reference in _Blueprints_. +* Improved UI in **Blueprint Editor**'s component mode + * Simpler to use + * Improved user feedback with class icons and a less tightly packed layout + * Search box to quickly find components + * Components are now grouped into _categories_ +* Improved context menu options in _Level Blueprint_ when selecting multiple actors +* Improved Find in _Blueprint_ search results to prevent false positives when searching for numbers (removing the junk node index from search criteria) +* Wired up all current types of graph nodes to automatically look for _rich tooltip_ style documentation (which will be added over time) +* Generalized the latent action manager to allow latent behavior in any type of _Blueprint_, not just actors (it also works on actors that don't otherwise tick).Latent actions can also be declared in function libraries. +* Added touch enter/leave events and delegates to actors and primitive components +* Prevented _State Machine_ entry nodes from being wired up to a conduit (which is not currently supported by the runtime) +* Prevented _AnimBlueprint_ instances from finishing initializing if their source _Blueprint_ had compile errors +* Added cleanup code to remove NULL references from _Blueprint_ graph arrays (fixing very old Animation assets that were saved after deleting _State Machines_, which currently crash on load) +* Made it impossible to drop variable nodes in graphs with an incompatible schema +* Added the ability for graph drag-drop operations to query the hovered graph even when not over a node or pin -#### ゲームプレイとフレームワーク -* ビヘイビアツリー システムは WIP のままです。 -* スクリーンのロードは進行中です。 -* **ワールド ブラウザ** - * ワールド合成を使ってクライアントとしてホストに加わるためのサポートを追加しました。 - * ワールド合成に入っているレベルに対して `ALevelBounds` アクタを追加しました。これによりレベル バウンディング ボックスが定義されますレベルアクタの変更時に自動的に更新、または修正されたバウンドと使用することができます。 - * プログレス バーをレベル タイルに追加しました。 - * **Play In Editor**/**Simulate In Editor** モードにシミュレーション ユーを追加しました。 - * `WORLD_MAX` より大きいバウンドを持つレベルは、レベル バウンドがワールド バウンドと交差する場合に表示されます。 - * 下側にステータス バーを追加しました (マウス位置、マーキーの長方形のサイズ、 ワールドのサイズ)。 -* 現在の _SkeletalMesh_ をデフォルトとして維持するために _スケルトン_ を保存する必要がある旨の通知は、常時ではなく、変更があった場合にのみ表示されるようになりました。 -* ゲーム ビューポートが、別々の _Player Controller_ を制御する複数のゲーム コントローラーから入力を受け取ることができるようになりました。 -* コンポーネント アセット ブローカーを拡張可能にしました。 -* `AActor::bFindCameraComponentWhenViewTarget` を追加して、アクタがビューターゲットの時に使用可能な _Camera コンポーネント_ の使用をやめることができるようにしました。 -* 引き続き **Unreal Automation Tool** の開発中です。 - * **UnrealBuildTool** と **UnrealAutomationTool** ロギング システムを統合しました。 - * プログラムのビルドに対するサポートを追加しました。 - * プラットフォーム抽出レイヤーを追加して、 `AutomationScripts.dll` を複数の (プラットフォーム) DLL に分割しました。 -* **物理** - * プレイヤー / 物理のインタラクションプレイヤーは物理オブジェクトの移動中にプッシュすることができます。 - * プレイヤーは、ブロックしている物理シミュレートされたオブジェクトを押しのけて、オーバーラップしている物理シミュレートされたオブジェクト上にわずかな力を生成することができます。 - * プレイヤーがオブジェクトに適用する力は _CharacterMovementComponent_ で設定することができます (Category=Player Physics を参照)。 +#### Gameplay and Framework +* Behavior Trees system is still a WIP +* Loading Screens in progress. +* **World Browser** + * Added support for joining as a client to a host with world composition + * Added `ALevelBounds` actor for levels participating in world composition, which defines level bounding box.Can be updated automatically on level actors changes or used with just fixed bounds + * Added loading bar to level tiles + * Added simulation view while in **Play In Editor**/**Simulate in Editor** + * Levels which have bounds bigger than `WORLD_MAX` still will be visible in case level bounds intersects world bounds + * Added bottom status bar (mouse location, marquee rectangle size, world size) +* Notification that _Skeleton_ needs to be saved to keep current _SkeletalMesh_ as default now only appears when there is a change, rather than always. +* A game viewport can now receive input from multiple game controllers each controlling a separate _Player Controller_. +* Made the component asset broker extendable +* Added `AActor::bFindCameraComponentWhenViewTarget` to allow actors to opt out of using a _Camera Component_ where available when they are a view target +* Ongoing development of **Unreal Automation Tool** + * Unified **UnrealBuildTool** and **UnrealAutomationTool** logging systems + * Added support for building programs + * Added platform abstraction layer and split `AutomationScripts.dll` into multiple (platform) DLLs. +* **Physics** + * Player/Physics interaction:Player can push around physics objects while moving + * Player can push away blocking physics-simulated objects and will generate a slight force on overlapping physics-simulated objects. + * The force the player applies to the objects can be setup in the _CharacterMovementComponent_. (see Category=Player Physics) -#### レンダリング -* **DOFOverrideTexture** 機能を取り除きました。代わりに、UI エレメントの裏側のコンテンツをぼかすことができる **BlurUI** 機能が付きました。 -* 統合が遅い場合 NVIDIA のパフォーマンス GPU が高くなるように NVIDIA 固有の注釈を追加しました。 -* シャドウ手法は、新手法が既にデフォルトになっている場合が多いので、旧手法は削除しました。 -* バウンディング ボックスの _+1_ を削除しました (かつて物理に必要でしたが、もう必要なくなりました)。バウンディング ボックスを拡張して使うと、シェーディングに問題が生じました。 -* lit(ライティング有り) でないビューの大気エフェクトを無効にしました。 -* エディタ内の **ランドスケープ** スプラインの Z-fighting を減らし、正しいワールドの Z 軸によるスプライン曲線をレンダリングしました。 -* **Lightmass** のバックフェイシング トライアングルによって、写真がブロックされることがなくなりました。 -* **Lightmass** における指向性ライトの重要度の評価を改善しました。 -* OpenGL ES2 レンダラーにガンマ空間の出力を追加しました。 -* OpenGL ES2 に対する EnvBRDF の分析近似値を追加しました。 -* レンダリング スレッドから直接コンポーネント プロパティへアクセスするレース コンディションを作成しずらくするために、`UPrimitiveComponent` ポインタをレンダラー構造体から削除しました。 -* **カスケード** でエミッタを操作する時の LOD に関する警告がより明確になりました。 +#### Rendering +* Removed **DOFOverrideTexture** feature - we will have a **BlurUI** feature instead - that allows to blur content behind UI elements +* Added NVIDIA specific annotation to favor NVIDIA high performance GPU over slower integrated +* Removed old shadow method since the new one was already the default for quite some time. +* Removed _+1_ on the bounding boxes (was once needed for physics, but that's not longer the case).It was causing issues on shading where it was using the enlarged bounding box. +* Disabled atmosphere for non-lit views +* Reduced **Landscape** Spline Z-fighting in the editor and made the spline lines render with the correct world-Z coordinate +* Photons are no longer blocked by back facing triangles in **Lightmass**. +* Improved Directional Light's importance estimation in **Lightmass**. +* Added gamma space output to OpenGL ES2 renderer. +* Added EnvBRDF analytic approximation for OpenGL ES2. +* Removed `UPrimitiveComponent` pointers from renderer structures to make it harder to create race conditions accessing component properties directly from the rendering thread +* Warnings regarding level of detail (LOD) when manipulating emitters in **Cascade** are now more explicit. -#### アニメーション / ペルソナ -* **コンテンツ ブラウザ** で使用するために _[1D Blend Space]_ アイコンをエディタに追加しました。 -* **ペルソナ** でソケットを複製すると、アタッチされたアセットも複製されるようになりました。 -* **ペルソナ** 内にアタッチされたメッシュをキャッシュして、モードが変更しても残るようにしました。 -* _MID_ と _MIC_ のインスタンス名を、ユーザー (_MaterialInstanceDynamic_ と _MaterialInstanceConstant_) に相応しくなるように変更しました。 -* アニメーション シーケンスのスケルタルメッシュへの追加をアンドゥできるようになりました -* bones/sockets/wind に対する **ペルソナ** の回転 / 平行移動ウィジェットが正しく表示および動作するようになりました。 -* **ペルソナ** の **Skeleton Tree** タブでアイテムを選択する時に、ビューの一番上へ強制的にスクロールされてしまうことがなくなりました。 -* **Skeleton Tree** でソケットを **Alt を押しながらドラッグ** すると、そこにドロップしたボーン上にはオリジナルではなくコピーが置かれます。 -* ワールド / ローカル空間のアイコンが **ペルソナ** で黒の四角としてレンダリングしなくなりました。 -* **Copy Bone Names To Clipboard** 機能は、ボーン名にアンダースコアと数を付けなくなりました。 -* **Persona** での _ソケット_ 名の変更がインラインで行われるようになりました。 -* **ペルソナ** のデフォルトのレイアウトを変更して、**[Compiler Results (コンパイラの結果)]** タブと **[Find in Blueprints (ブループリントを検索)]** タブのホームを作りました。 -* **レベル エディタ** のソケット サポートへのスナップを一般化して、 _Skeletal Meshes_ と _Skeletons_ だけではなくて、ソケットを含むすべての _SceneComponent_ 上で機能するようにしました。 +#### Animation/Persona +* Added new _1D Blend Space_ icons to the editor for use in **Content Browser** +* Duplicating sockets in **Persona** now duplicate attached assets too +* Cached attached meshes in **Persona** so that they survive mode changes +* Renamed instances of _MID_ and _MIC_ to something more appropriate for users (_MaterialInstanceDynamic_ and _MaterialInstanceConstant_). +* You can now undo adding an Animation Sequence to a Skeletal Mesh. +* **Persona** rotation/translation widget for bones/sockets/wind now looks and behaves correctly. +* Selecting an item in the **Skeleton Tree** tab in **Persona** no longer forces it to scroll to the top of the view. +* **Alt + Dragging** sockets in the **Skeleton Tree** will place the copy on the bone you drop it onto, rather than the original bone. +* World/Local space icons no longer render as black squares in **Persona**. +* **Copy Bone Names To Clipboard** feature no longer appends an underscore and number to the bone name. +* Renaming _Sockets_ in **Persona** is now done inline. +* Changed default **Persona** layout to have a home for the **Compiler Results** tab and **Find in Blueprints** tab (collapsed, at the bottom of the layout) +* Generalized snap to socket support in the **Level Editor** to work on any _SceneComponent_ that contains sockets, instead of just _Skeletal Meshes_ and _Skeletons_ [REGION:note] - 現在は、本物のソケットのみを使うビヘイビアを維持しており、ボーンのスナップは行われません。 + Currently preserving the behavior of only using true sockets - no bone snapping. [/REGION] -#### オーディオ -* ビューポートで右クリックすると、 _Ambient Sound_ が **Add Actor...** リストに表示されるようになりました。 +#### Audio +* _Ambient Sound_ now shown in the **Add Actor...** list, when right-clicking in a viewport. -#### コア -* テンプレート化されたネイティブの基本クラスが `UCLASS` 定義で使用できるようになりました。以下が例です。 +#### Core +* Templated native base classes can now be used in `UCLASS` definitions, e.g.: UCLASS() class UMyClass : public UObject, public MyNativeClass { }; -* 関数オブジェクトあるいは lambdas と合わせて使用するために、`TArray` に `FindByPredicate()` メンバー関数が含まれるようになりました。 +* `TArray` now has a `FindByPredicate()` member function for use with function objects or lambdas: void Func(const TArray& Ints) { - // Try to find an odd number (偶数を検索) + // Try to find an odd number const int* Result = Ints.FindByPredicate([](int N) { return (N % 2) != 0; }); } -* 列挙型変数のスペーサーがエディタのダイアログで非表示になりました。 -* `TAssetPtr` が `nullptr_t` で機能するようになりました。 -* **Lightmass** が再度モジュラー アプリケーションとしてビルドされました (**Swarm** は **Core** と DLL ベースでのビルド時に作成する **SwarmInterface** DLLに依存します)。 -* Root セットにはない有効なパッケージへのリセット ローダーのみクック中に呼び出します。 -* 異なるワードラップ ビヘイビアを、1 つの整合した再利用可能なアルゴリズムに統一しました。 -* `GIsUnattended` を `FApp::IsUnattended` に置き換えました。無人サーバー上での実行が可能なコードがある場合は、適宜更新する必要があります。 -* すべてのポインタに対して、より適切なハッシング関数を使用するようにしました。64-bit の実行ファイルのポインタの下位 4 ビットはいずれにせよゼロになるので、無視されるように関数を若干調整しました。 -* `GetObjectsOfClass()` と `GetDerivedClasses()` を `ObjectHash.h` に追加しました。 - * これらの関数は、 _ブループリント_ でのロード時間のパフォーマンス問題を解決のために使用されるようになりました。 -* プラグイン名を変更するために、`PluginNameRedirects` を追加しました。 -* フォント エディタに再インポート ボタンを追加しました。 -* **Asset Registry** の API を変更して、`UClass` ポインタではなく `FName` クラス名を受け取るようにしました。 -* `RequiredAPI` をもつクラスのみが `SNewClassDialog` に含めることが可能になりました。 (多少の例外はあり)。 -* Perforce のログ、警告、エラーがログ ファイルの中で区別されました。 -* エンジンとエディタを Mac OS にポートします。 -* Windows XP のコンパイル機能と Visual Studio 2012 へのリンクを追加しました。 - * `WindowsPlatform.SupportWindowsXP` フラグを追加しました (今のところデフォルトはオフ)。 - * Visual Studio 2012 Update の 1 以上をインストールする必要があります。 - * [](http://blogs.msdn.com/b/vcblog/archive/2012/10/08/10357555.aspx ) に従って操作してください。 -* UnSetup と UEDocsURLHandler プログラムを削除しました (使用することがないため)。 -* モジュールとプラグインをロードする際に発生するエラー処理を改善しました。 - * ゲーム プラグインを有効にしたので、ロードに失敗するとエラーが報告されるようになりました。 -* **GeneratePackagingManifest()** を `ITargetPlatform` に追加しました。 - * **アセット レジストリ** の **ChunkIDs** を含んだパッケージ情報を生成しました。主に、チャンク ベースのインストール用の `.pak` ファイル リストの生成が目的です。 -* アセットの可用性と優先順位づけに関する関数を `IAssetRegistry` に追加しました。 - * これらは基本的に、 `FAssetDatas` に保存された ChunkID を使ったプラットフォーム チャンク インストール コードへの呼び出しを単純化したものです。 -**統計情報** - * メモリ使用が改善されました。 - * `STAT NONE` が新しい統計システムで正しく機能するようになりました。 - * ブループリントから統計キャプチャの開始と停止ができます。 +* Enum spacers are now hidden from editor dialogues. +* `TAssetPtr` now works with `nullptr_t`. +* **Lightmass** built as a modular application again (**Swarm** depends on the **Core** and **SwarmInterface** DLLs it creates when building DLL-based) +* Only call reset loaders on valid packages that are not in the root set during cooking. +* Disparate word wrapping behaviors have been reconciled into one consistent, reusable algorithm. +* `GIsUnattended` has been replaced with `FApp::IsUnattended`.If you have any code that can be run on an unattended server, you will need to update it accordingly. +* We are now using a better hashing function for all pointers.The function was slightly adjusted to ignore the lower 4 bits of the pointer in 64-bit executables as they will be zero anyway. +* Added `GetObjectsOfClass()` and `GetDerivedClasses()` to `ObjectHash.h`. + * These functions are now used to address a load time perf issue with _Blueprints_ +* Added `PluginNameRedirects` to handle renamed plugins. +* Added a re-import button to the font editor. +* The **Asset Registry**'s API was changed to accept `FName` class names instead of `UClass` pointers +* Now only classes with `RequiredAPI` are allowed in the `SNewClassDialog` (with a few exceptions). +* Perforce Logs, Warnings, and Errors are now differentiated in the log file. +* Porting the engine and the editor to Mac OS +* Added Windows XP compiling and linking for Visual Studio 2012 + * New `WindowsPlatform.SupportWindowsXP` flag (defaults to off for now) + * Requires Visual Studio 2012 Update 1 or higher to be installed! + * Implemented according to: [](http://blogs.msdn.com/b/vcblog/archive/2012/10/08/10357555.aspx ) +* Deleted UnSetup and UEDocsURLHandler programs (no longer used) +* Improved error handling for module and plugin loading + * Enabled game plugins to now report errors when they fail to load +* Added **GeneratePackagingManifest()** to `ITargetPlatform`. + * Generates packaging info given the **ChunkIDs** in the **Asset Registry**.Primarily intended for generating `.pak` file lists for chunk based installs. +* Added asset availability and prioritization functions to `IAssetRegistry`. + * These are basically simplified calls into the platform chunk install code, using the ChunkID stored on `FAssetDatas`. +* **Stats** + * Better memory utilization. + * `STAT NONE` will now work properly with the new stats system. + * Stat captures may be initiated and stopped from Blueprints. * **UnrealFrontend (UFE)** - * UnrealAutomationTool を使っているランチャーが初めて実装されました。 - * UFE を非モノリシックに切り替えました。 -* UnrealAutomationTool (UAT) がプリコンパイルされたフォールバックから機能できるようになったので、Visual Studio や MSBuild のないマシンからも実行できるようになしました。 -*「XGE」を使用する時に明確に含まれていなくても、 UnrealAutomationTool が UnrealHeaderTool を作成するようにしてください。 -* FMonitoredProcess により、エディタまたはエンジンで監視できる外部プロセスの作成が可能になりました。 -* Unreal Build Tool ホットリロードを必要なモジュールとソースの処理だけになり、時間が短縮されました。 -* 内部例外を継承するために Unreal Build Tool の BuildException のすべての使用を変更しました。 + * Initial implementation of the launcher utilizing UnrealAutomationTool. + * Switched UFE to be non-monolithic. +* Improve UnrealAutomationTool (UAT) to be able to work from a precompiled fallback so UAT can be run from a machine without Visual Studio or MSBuild +* Make sure UnrealAutomationTool builds UnrealHeaderTool even if it is not explicitly included when using XGE +* FMonitoredProcess allows for the creation of external processes that can be monitored by the Editor or Engine +* Reduced time for Unreal Build Tool hot-reload compiles by only processing required modules and sources. +* Changed all uses of BuildException in Unreal Build Tool that are thrown in response to a caught exception to propagate the inner exception. -#### オンライン +#### Online -* Steam/Null の Achievement インターフェース。 +* Achievement interface for Steam/Null. diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/Sept/ReleaseNotesSeptember2013.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/Sept/ReleaseNotesSeptember2013.KOR.udn index 8c3aeee14908..920ce05fb1e4 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/Sept/ReleaseNotesSeptember2013.KOR.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2013/Sept/ReleaseNotesSeptember2013.KOR.udn @@ -1,8 +1,10 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3367470 Title: September 2013 Release Notes Crumbs:%ROOT%, Support/Builds Description: Availability:Licensee +Parent:Support/Builds +Order:-5 [TOC(start:2 end:2)] diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/4_1/ReleaseNotes_4_1.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/4_1/ReleaseNotes_4_1.JPN.udn index 945e3a89281c..77d97b50edcc 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/4_1/ReleaseNotes_4_1.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/4_1/ReleaseNotes_4_1.JPN.udn @@ -1,10 +1,12 @@ -INTSourceChangelist:2735872 -Title:アンリアル エンジン 4.1 リリースノート +INTSourceChangelist:3367477 +Title:アンリアル エンジン 4.1 リリース ノート Crumbs:%ROOT%, Support/Builds Description: Availability:Public -version: 4.1 +version:4.1 +parent:Support/Builds order:1 + [TOC(start:2 end:2)] [PUBLISH:Licensee] @@ -30,7 +32,7 @@ QA_APPROVED_UE4_BUILD_MINIMUM --> [/PUBLISH:Licensee] -## 主な新機能 +## 主要な新機能 #### プラットフォーム @@ -64,7 +66,7 @@ QA_APPROVED_UE4_BUILD_MINIMUM [/PUBLISH:Rocket] -#####新たなコンテンツ サンプル レベル Math Hall +#####新たなコンテンツ サンプルのレベル Math Hall * Math Hall では、基本的なベクター演算と各種数学関数のコンセプトについて説明しています。 @@ -88,14 +90,14 @@ QA_APPROVED_UE4_BUILD_MINIMUM ##### 新たな内蔵型エディタ チュートリアル -* エディタ内にチュートリアルが新たに内蔵されました。チュートリアルは、次のような機能を初めて使用する場合に自動的に表示されます。 +* エディタ内にチュートリアルが新たに内蔵されましたチュートリアルは、次のような機能を初めて使用する場合に自動的に表示されます。 [REGION:raw] ![](editor_tutorials.png) [/REGION] * **カスケード パーティクル エディタ チュートリアル** ではパーティクル システムとエフェクトを作成する際に使用される基本的なインターフェイスとコンセプトを紹介しています。 -* **マテリアル エディタ チュートリアル** では、マテリアル作成の基本が学べます。 +* **マテリアル エディタ チュートリアル ** では、マテリアル作成の基本が学べます。 * **スタティック メッシュ エディタ チュートリアル** では、スタティック メッシュをセットアップするためのインターフェイスとツールについて解説しています。 * **ペルソナ アニメーション エディタ チュートリアル** では、さまざまなアセットのタイプとモードための各種 UI 要素とコンセプトについて説明しています。 @@ -117,7 +119,7 @@ QA_APPROVED_UE4_BUILD_MINIMUM ![](news_feed.png) -#####Asset Deletion Assistant (アセット削除アシスタント) +##### Asset Deletion Assistant (アセット削除アシスタント) * この機能を使用すると、インタラクティブに参照を調べ、修正できるようになるため、簡単にアセットを削除できます。 @@ -127,13 +129,13 @@ QA_APPROVED_UE4_BUILD_MINIMUM * 参照されているアセットをクリックすると、そのアセットに進み、手動で修正できるようになります。 * 参照を置き換えることができます。(正式には、Consolidate <統合> と呼ばれます。) * 強制削除機能が備わっています。また、キャンセルしてユーザー自身で参照を扱うことができます。 -* 複数同時に削除可能です。 +* 複数同時に削除可能です * アセットが他のアセットから参照されていても、それらの他アセットも削除されているならば、問題が生じることはありません。 * 参照のナビゲーション * 参照されているアセットをダブルクリックするとエディタが開きます。 -* 開いているマップでアセットが参照されている場合、そのマップのアセットをダブルクリックすると、開いているマップの中でそのアセットがあるところまでナビゲートしてくれます。 +*開いているマップでアセットが参照されている場合、そのマップのアセットをダブルクリックすると、開いているマップの中でそのアセットがあるところまでナビゲートしてくれます。 -#####ディレクトリをドラッグアンドドロップしてインポート +##### ディレクトリをドラッグアンドドロップしてインポート * テクスチャやメッシュ、アニメーションが入っている複数のフォルダを選択して、直接コンテンツブラウザの中にドラッグすると、フォルダの中のものすべてがインポートされるようになりました。 @@ -147,14 +149,14 @@ QA_APPROVED_UE4_BUILD_MINIMUM * Window メニューから Undo History (元に戻す履歴) ウィンドウを開くことができます。(Window > Undo History)。 -##### New:ビューポート操作のリマップ +##### 新規:ビューポート操作のリマップ * ビューポートのための WASD 操作をユーザーがリマップできるようになりました。 -* これらの設定は、Editor Preferences (エディタの設定) > Keyboards Settings (キーボードの設定) > Viewport Navigation (ビューポート ナビゲーション) に置かれています。 +* これらの設定は、 **[Editor Preferences (エディタの環境設定)] > [Keyboards Settings] > [Viewport Navigation]** に置かれています。 ![](ViewportControls.png) -##### New:デバッグ ヒストグラムによる視覚化 +##### 新規:デバッグ ヒストグラムによる視覚化 * ワールド内で浮動小数点値のヒストグラム (グラフ) を描画できるようになりました。 @@ -165,26 +167,26 @@ QA_APPROVED_UE4_BUILD_MINIMUM ![](debug_histogram_nodes.png) -* 注記:この機能はデバッグのために作られています。デバッグ描画を通常のゲームプレイに利用することは推奨されません。 +* 注記:この機能はデバッグのために作られています。デバッグ描画を通常のゲームプレイに利用することは推奨されません。 -##### Translation Editor (翻訳エディタ) (プレビュー版) +#####翻訳エディタ (プレビュー版) * Translation Editor (翻訳エディタ) を使うことによって、ゲームコードやアセット内の文字列のために翻訳したものを簡単に編集できるようになります。 ![](TranslationEditor03.png) -* 注記:このツールは、まだ作成作業が進行している早期版です。Experimental (実験) セクションの Editor Preferences (エディタの設定) で有効化できます。 +* 注記:このツールは、まだ作成作業が進行している早期版です。Experimental (実験) セクションの Editor Preferences (エディタの設定) で有効化できます。 ### ブループリント -#####グラフ内の接続にジャンプ +##### グラフ内の接続にジャンプ * ピンを右クリックし、接続にジャンプできるようになりました。 ![](JumpToConnections.png) -#####クラスの動的キャスティング +##### クラスの動的キャスティング * ブループリント内で互換性のある型のオブジェクト同士を安全に変換できるようになりました。 @@ -194,7 +196,7 @@ QA_APPROVED_UE4_BUILD_MINIMUM * ブループリント エディタのウィンドウ間でコンポーネントのノードをドラッグアンドドロップできるようになりました。 * 上記操作によって、元のコンポーネントから属性を継承する新たなコンポーネントの変数が新たなブループリントに作成されることになります (ただし、名前の衝突を避けるため、変数名は継承されません)。 -* コンポーネントの付属/分離操作について元に戻す/やり直しが可能になりました。 +* コンポーネントの付属 / 分離操作について元に戻す / やり直しが可能になりました。 * この機能は、Make New Scene Root (新規シーン ルートの作成) の操作にも適用されます。 @@ -203,579 +205,579 @@ QA_APPROVED_UE4_BUILD_MINIMUM #### プロジェクトのアップグレード [PUBLISH:Licensee] -プロジェクトが UE4 ディレクトリの外部にある場合、新規ビルドでプロジェクトを機能させるためには、いくつかのステップが必要になる場合があります。 +プロジェクトが UE4 以外に存在する場合、新しいビルドでプロジェクトを動かすことが必要になる場合があります。 [/PUBLISH:Licensee] [PUBLISH:Rocket] 4.0 によるプロジェクトを 4.1 で動かすためには、操作が必要になる場合があります。 [/PUBLISH:Rocket] -- ブループリントのみのプロジェクトをアップグレードする場合 +- ブループリントのみのプロジェクトをアップグレードする場合 * 通常どおりに新たなエディタに既存のプロジェクトをロードできます。 - * 注記:ブループリントの API の中にはバージョン間で変更されたものもあるため、コンテンツで警告を受ける場合があります。詳しくは **API の変更** のセクションをご覧ください。 + * 注記:ブループリントの API の中にはバージョン間で変更されたものもあるため、コンテンツで警告を受ける場合があります。詳しくは **API Changes** のセクションをご覧ください。 -- C++ コードによるプロジェクトをアップグレードする場合 +- C++ コードによるプロジェクトをアップグレードする場合 * C++ プロジェクトを新たなバージョンのアンリアル・エンジンのために再コンパイルする必要があります。 * ゲームのフォルダから .uproject ファイルを見つけ、右クリックします (Mac の場合は、Command + クリックでも可能です)。 - * **Switch Unreal Engine Version (アンリアル・エンジンのバージョンを切り替える) を選択 -> 4.1** (Mac では、Services メニュー内にあります)。 + * **Switch Unreal Engine Version -> 4.1** を選択します (Mac では、Services メニュー内にあります) * 右クリックして新たな C++ プロジェクト ファイルを作成し、通常通りゲームを再コンパイルします。 - * 注記:注記: C++ の API の中にはバージョン間で変更されたものもあるため、コンパイル エラーが生じる場合があります。詳しくは **API Changes (API の変更 ) ** のセクションをご覧ください。 + * 注記:注記: C++ の API の中にはバージョン間で変更されたものもあるため、コンパイル エラーが生じる場合があります。詳しくは **API Changes** のセクションをご覧ください。 -ご不便をおかけして申し訳ございません。将来のバージョンのために、現在アップグレード プロセスを簡略化する作業を行っております。 +- ご不便をおかけして申し訳ございません。今後のバージョンのために、現在アップグレード プロセスを簡略化する作業を行っております。 #### 既知の問題 - Xbox One SDK がインストールされている場合、名前にアンダースコアがあるプロジェクトを Visual Studio で作成すると失敗する。 - 親ディレクトリのどれかにスペースが含まれているプロジェクトは、 Xbox One と Playstation 4 が完全に対応しきれていない。 -- Steamworks が Mac でサポートされていない。現在作業が進行中です! +- Steamworks is not yet supported on Mac - we're working on it! - ShooterGame が、専用サーバーとしてコンパイルされるために、GitHub からソースを必要とする。 -- First Person (ファーストパーソン) テンプレートから作成されたプロジェクトが、PlayStation 4 でクラッシュする場合がある。 +- First Person (ファーストパーソン) テンプレートから作成されたプロジェクトが、PlayStation 4 でクラッシュする場合がある - Launch On ボタンを使用して Mac にデプロイすると、Elemental デモがクラッシュする。 --Game Center にサインインしている場合、Tappy Chicken が起動時に iOS でクラッシュする。 +- Game Center にサインインしている場合、Tappy Chicken が起動時に iOS でクラッシュする。 #### 謝辞 -今回のリリースのコードに貢献していただいた素晴らしいデベロッパーの方々全員に感謝を申し上げます!  +今回のリリースのコードに貢献していただいた素晴らしいデベロッパーの方々全員に感謝を申し上げます!ありがとうございました! * **Allar (Michael Allar)** - * D3D11RHI をサポートするための共有テクスチャ リソースを追加。 [Added Shared Texture resource support for D3D11RHI](https://github.com/EpicGames/UnrealEngine/pull/6) + * [D3D11RHI をサポートするための共有テクスチャ リソースを追加](https://github.com/EpicGames/UnrealEngine/pull/6) * **AndrewScheidecker (Andrew Scheidecker)** - * Actor->Acor K2 のリダイレクトのタイポを修正。 [Fix Actor->Acor K2 redirect typo](https://github.com/EpicGames/UnrealEngine/pull/28) + * [Actor->Acor K2 のリダイレクトのタイポを修正](https://github.com/EpicGames/UnrealEngine/pull/28) * **cdietschrun** - * Actions taking a object (オブジェクトを取るアクション) のメッセージの修正。 [Fix "Actions taking a object" message](https://github.com/EpicGames/UnrealEngine/pull/12) + * [Actions taking a object (オブジェクトを取るアクション) のメッセージの修正](https://github.com/EpicGames/UnrealEngine/pull/12) * **clide** - - Mac の GL を修正。 [Mac GL Fix](https://github.com/EpicGames/UnrealEngine/pull/5) + - [Mac の GL を修正](https://github.com/EpicGames/UnrealEngine/pull/5) * **dkjer (Donald Kjer)** - * ケースセンシティブなファイルシステムの修正。 [Fixes for case-sensitive filesystems](https://github.com/EpicGames/UnrealEngine/pull/11) + * [ケースセンシティブなファイルシステムの修正](https://github.com/EpicGames/UnrealEngine/pull/11) * **DiCoJamesTan (James Tan)** - * ChildActorComponent に関する添付バグを修正。 [Fix attachment bug with ChildActorComponent ](https://github.com/EpicGames/UnrealEngine/pull/20) + * [ChildActorComponent に関する添付バグを修正](https://github.com/EpicGames/UnrealEngine/pull/20) * **fxtentacle (Hajo Nils Krabbenh.ft)** - * Mac における Azimuth & Elevation の計算を修正。 [Fix Azimuth & Elevation calculation on Mac](https://github.com/EpicGames/UnrealEngine/pull/9) + * [Mac における Azimuth & Elevation の計算を修正](https://github.com/EpicGames/UnrealEngine/pull/9) * **Kamayuq** - * Mac の UnrealBuildTool を修正。 [Mac UnrealBuildTool Fix](https://github.com/EpicGames/UnrealEngine/pull/3) + * [Mac の UnrealBuildTool を修正](https://github.com/EpicGames/UnrealEngine/pull/3) * **Kyle Rocha (kylawl)** - * 平面の交線の関数を KismetMathLibrary に追加。 [Add plane interct function to KismetMathLibrary](https://github.com/EpicGames/UnrealEngine/pull/14) + * [平面の交線の関数を KismetMathLibrary に追加](https://github.com/EpicGames/UnrealEngine/pull/14) * **PostalDude (Frederic Lauzon)** - * モジュール リンカの出力ファイルの無効なパスを修正。 [Fix invalid module linker output file path](https://github.com/EpicGames/UnrealEngine/pull/7) + * [モジュール リンカの出力ファイルの無効なパスを修正](https://github.com/EpicGames/UnrealEngine/pull/7) * **sbc100 (Sam Cleeg)** - * UnrealBuildTool におけるビルドの警告を修正。 [Fix build warnings in UnrealBuildTool](https://github.com/EpicGames/UnrealEngine/pull/16) - * Linux におけるコンパイルの警告を修正。 [Fix linux compile warnings](https://github.com/EpicGames/UnrealEngine/pull/19) + * [UnrealBuildTool におけるビルドの警告を修正](https://github.com/EpicGames/UnrealEngine/pull/16) + * [Linux におけるコンパイルの警告を修正](https://github.com/EpicGames/UnrealEngine/pull/19) * **wshearn (Wesley Hearn)** - * HTML5 による出荷クライアントのビルドを修正。 [Fix HTML5 Shipping Client build](https://github.com/EpicGames/UnrealEngine/pull/15) + * [HTML5 による出荷クライアントのビルドを修正](https://github.com/EpicGames/UnrealEngine/pull/15) -## リリースノート +## リリース ノート 「訳注: 以下は、非常に技術的な部分が含まれるため、翻訳を省略します。」 -#### マーケットプレイスのコンテンツ +#### Marketplace Content -* **ShooterGame**:Xbox One と PlayStation 4 へのデプロイをサポートするようになりました。 +* **ShooterGame**:Now supports Xbox One and PlayStation 4 deployment. ![](shooter_game.png) -* **Memory Game (記憶ゲーム)**: カード合わせの記憶ゲームが、まるごとブループリントで作成されました。モバイル デバイスに最適化されています! +* **Memory Game**:A card-matching memory game created entirely in Blueprints.Optimized for mobile devices! ![](memory_game.png) -* **Effects Cave (エフェクトの洞窟)**:本物の洞窟探検もこれほど面白くはないでしょう!Effects Cave を探検すると、美しいものに出会います。それらは、ワールドを豊かにするために作ることができるものです。GPU によるパーティクル、動的にリットされるスパーク、かすかにたなびく煙などなど、ビジュアル エフェクト エディタのカスケードを使用すると、無数のディテールを積み上げることができるようになるのです。 +* **Effects Cave**:Spelunking has never been this fun!See the pretty things you can make to add richness to your world by exploring the Effects Cave.Using the Cascade visual effects editor you can layer on countless details including GPU-powered particles, dynamically lit sparks, wispy puffs of smoke and more. ![](effects_showcase.png) -* **リアルなレンダリング**:UE4 の物理ベースのマテリアル システムや、改善されたグローバル イルミネーション システムのライトマス、さらにフォトメトリック ライティングを使用することによって、リアルな環境を簡単に構築したり、建築のビジュアライゼーションを模倣することができるようになります。Oculus Rift に対応! +* **Realistic Rendering**:Easily build true-to-life environments or emulate architectural visualizations using UE4's physically-based material system, the improved Lightmass global illumination system and photometric lighting.Supports Oculus Rift! ![](realistic_rendering.png) -* **ブループリント オフィス**:レベルのデザイン ツールや、自動制御セキュリティ システム、高度な AI の振る舞いなど、ブループリントの多様な使用事例を示しています。各使用事例には、簡潔なゲーム内説明が含まれています。 +* **Blueprint Office**:Shows a wide variety of use cases for Blueprints ranging from level design tools to intelligent security systems to sophisticated AI behavior.Each example includes a brief in-game explanation. ![](blueprints_demo.png) -#### 学習リソース +#### Learning Resources -* **動画チュートリアル** - * New: [Multiplayer Networking Video Tutorials](https://www.youtube.com/playlist?list=PLZlv_N0_O1gYwhBTjNLSFPRiBpwe5sTwc) (マルチプレイヤー ネットワーキング動画チュートリアル) (6 巻) Billy Bramer 著 - * New: [Blueprint Video Tutorials](https://www.youtube.com/playlist?list=PLZlv_N0_O1gaG5BW72It4chjhypxIO9ZB) (ブループリント 動画チュートリアル) (新作 7 巻) James Golding および Mike Beach 著 - * New: [Third Person Blueprint Game Setup Tutorial](https://www.youtube.com/watch?v=GWbd0Wowwnk&list=PLZlv_N0_O1gZS5HylO_368myr-Kg2ZLwb&index=2) (サードパーソン ブループリント ゲーム セットアップ チュートリアル) (15 巻) Zak Parrish 著 -* **文書によるチュートリアル** - * New:Particle System Tutorials: (パーティクル システム チュートリアル)VFX [Lesson 1](https://wiki.unrealengine.com/Visual_Effects:_Lesson_01:_Material_Particle_Color), [Lesson 2](https://wiki.unrealengine.com/Visual_Effects:_Lesson_02:_Using_Depth_Fade) Tim Elek 著 - * New: [Matinee Tutorial](https://wiki.unrealengine.com/Matinee_Basics:_Creating_Your_First_Matinee_Sequence) (マチネ チュートリアル) Greg Mitchell 著 -* **ドキュメンテーション** - * **アンリアル エディタのマニュアル** +* **Video Tutorials** + * New: [Multiplayer Networking Video Tutorials](https://www.youtube.com/playlist?list=PLZlv_N0_O1gYwhBTjNLSFPRiBpwe5sTwc) (6 videos) by Billy Bramer. + * New: [Blueprint Video Tutorials](https://www.youtube.com/playlist?list=PLZlv_N0_O1gaG5BW72It4chjhypxIO9ZB) (7 new videos) by James Golding and Mike Beach. + * New: [Third Person Blueprint Game Setup Tutorial](https://www.youtube.com/watch?v=GWbd0Wowwnk&list=PLZlv_N0_O1gZS5HylO_368myr-Kg2ZLwb&index=2) (15 videos) by Zak Parrish. +* **Written Tutorials** + * New:Particle System Tutorials:VFX [Lesson 1](https://wiki.unrealengine.com/Visual_Effects:_Lesson_01:_Material_Particle_Color), [Lesson 2](https://wiki.unrealengine.com/Visual_Effects:_Lesson_02:_Using_Depth_Fade) by Tim Elek. + * New: [Matinee Tutorial](https://wiki.unrealengine.com/Matinee_Basics:_Creating_Your_First_Matinee_Sequence) by Greg Mitchell. +* **Documentation** + * **Unreal Editor Manual** * New:[Blueprint Cheat Sheet](Engine/Blueprints/UserGuide/CheatSheet) * New:[Light Propagation Volumes](Engine/Rendering/LightingAndShadows/LightPropagationVolumes) - * New:[Preview Shadows](Engine/Rendering/LightingAndShadows/Shadows#シャドウのプレビュー) + * New:[Preview Shadows](Engine/Rendering/LightingAndShadows/Shadows#previewshadows) * New:[Pivot Painter](Engine/Content/Tools/PivotPainter) - * New:[Mac Viewport Controls クイック リファレンス](Engine/UI/LevelEditor/Viewports/ViewportControls) - * **プログラミングのガイド** - * New:コードブロックのハイライト - * ランディングページの再編成を更新。 - * データ駆動型ゲームプレイを更新。 - * アクタのスポーン情報を修正。 - * コンポーネントの配列の参照を修正。 + * New:[Mac Viewport Controls Quick Reference](Engine/UI/LevelEditor/Viewports/ViewportControls) + * **Programming Guide** + * New:Code Block Highlighting + * Updated Landing Page Reorganization + * Updated Data Driven Gameplay + * Fixed Actor Spawning Info + * Fixed Components Array References [PUBLISH:Rocket] -#### EULA (エンドユーザーライセンス契約書) +#### End User License Agreement (EULA) -* ライセンシーは、Example Code (Samples フォルダと Templates フォルダにあるコード) を公に配布することが許可されるようになりました。これはソース コードを公に配布することを禁止する規則の例外です。 -* ライセンシーのロイヤルティの義務に関して以下の例外を追加しました。: -* ライセンシーは暦四半期の一期につき各製品の粗利益として得られる 3,000 ドルまでの金額に対してロイヤルティを支払う必要はありません。 -* 暦四半期の一期につき製品の利益が 3,000 ドル未満の場合は、ライセンシーは当該製品の収益を報告する必要はありません。 -* 「製品」に授与された賞に起因する賞金にはロイヤルティは課されません。 -* ライセンシーは最長 30 行までの「ソースコード」の断片を、そのコードの断片の内容について議論する目的のために一般に公開されたフォーラムで投稿することが認められます。 +* Licensees are now permitted to publicly distribute Example Code (code residing in the Samples and Templates folders).This is an exception to the rule prohibiting distribution of Source Code publicly. +* Added the following exceptions to licensees' royalty obligation: +* Licensees are not required to pay royalties on the first $3,000 in gross revenue per Product per quarter. +* If Product revenue is less than $3,000 in a quarter, licensee is not required to report revenue for that Product. +* Financial winnings from awards are exempt from royalties. +* Licensees are now permitted to post Source Code snippets up to 30 lines in length on public forums for discussion purposes. [/PUBLISH:Rocket] [PUBLISH:Rocket] -#### アンリアル エンジンのランチャー +#### Unreal Engine Launcher -* New:複数のバージョンのアンリアル・エンジンを並存させてインストール。 -* ランチャーの新たなバージョン セレクターのドロップダウンリストを使って、インストールして実行したいバージョンを選択してください! -* New:メインの UI 上に新たにできた [Uninstall] ボタンを使って、ランチャーからエンジンのバージョンをアンイストールできるようになりました。 -* New:ランチャーのマーケットプレイスのページにダウンロード サイズが表示されるようになりました。 -* New:マーケットプレイスでさまざまなバージョンのアイテムがサポートされるようになりました。 -* New:EULA (エンドユーザーライセンス契約書) が、ランチャーから表示して承認できるようになりました。 -* New:プロジェクト ファイルを、ランチャーからインストールされたエンジン バージョンと関連付けることができるようになりました。 -* New:アンリアル インストーラーとランチャーが、日本語と韓国語のためにローカライズされました。 -* ランチャーについては、ログイン スクリーンで言語を選択できます。 -* エンジンのダウンロード中に、マーケットプレイスのアイテムをキューに入れられない不具合を修正しました。 -* Windows 7 SP1 がインストールされていない場合にインストーラーが警告を出さない不具合を修正しました。 -* アンリアル・エンジンのショートカットをデスクトップから削除できない場合がある不具合を修正しました。 -* Syncing your account (アカウントを同期中です) でまれに止まってしまう不具合を修正しました。 -* 自動ダウンロードのキャンセルを修正して、再開しないようにしました。 -* 自動アップデートが空のファイルを無視する不具合を修正しました。 -* UI サイズ情報が、小数位をともなって表示されない不具合を修正しました。 -* インストールが失敗した際に、前回成功したファイル以降から再開されるのではなく、最初からやり直されるという不具合を修正しました。 -* データファイルのダウンロードに失敗したことによって、まれにインストールが終了しなくなる不具合を修正しました。 -* Mac 用ランチャーが終了時にクラッシュする不具合を修正しました。 -* ダウンロード サイズのインジケーターを修正して、圧縮されていないサイズではなく圧縮されたダウンロード サイズが表示されるようにしました。 -* 進捗パーセンテージの情報に関する UI の問題を修正しました。 +* New:Install multiple versions of Unreal Engine side-by-side. +* Use the Launcher's new Version Selector drop-down to choose which version you want to install and run! +* New:You can now uninstall the engine versions right through the launcher using a new 'Uninstall' button on the main UI. +* New:Launcher Marketplace pages now show download size. +* New:The Marketplace now supports different versions of items. +* New:The EULA is now shown and accepted through the launcher. +* New:Project files can be associated with engine versions installed through the launcher. +* New:The Unreal Installer and Launcher are now localized for Korean and Japanese. +* For the launcher you can select a language in on the login screen. +* Fixed not being able to queue Marketplace items while the Engine is downloading. +* Fixed installer not warning users if they did not have Windows 7 SP1 installed. +* Fixed an issue preventing Unreal Engine shortcuts from being removed from the desktop on uninstall in some cases. +* Fixed rare issue with being stuck on "Syncing your account". +* Fixed cancelled automatic downloads so they will not resume. +* Fixed self-update ignoring empty files. +* Fixed UI size information not displaying with decimal places. +* Fixed an issue causing a failed installation to start all over again rather than resuming from previously successful files. +* Fixed a rare issue where a failed data file download could cause the install to never finish. +* Fixed Mac Launcher crash on close. +* Fixed download size indicator to support showing the compressed download size rather than uncompressed size. +* Fixed some UI issues with progress percentage information. [/PUBLISH:Rocket] #### エディタとツール -* **一般エディタ** - * New:3D ビューポートのグリッドを改善しました! - * より見やすくするためにグリッド ドットを除去しました。グリッドも、グリッド スナップ設定に従って、スケーリングされるようになりました。 - * 細い線について、パースペクティブ グリッドの正確性を改善しました。 - * orthographic grid (正投影法のグリッド) に、10 の主要グリッド線、レベル間のソフトなフェード遷移、および色付き軸線が備わりました。 - * New:**Preview Meshes** (メッシュのプレビュー) の設定項目を追加することによって、バックスラッシュ キーを押下したままにすると、ビューポートで表示されるメッシュをカスタマイズできるようにしました。 - * New:プロジェクトのアイコンを Window/Project Settings (ウィンドウ/プロジェクトの設定) から割り当てることができるようにしました。 - * New:プロジェクトのスタートアップ ムービーを Window/Project Settings (ウィンドウ/プロジェクトの設定) から割り当てることができるようにしました。 - * New:* C のキーを押すと、マテリアル エディタおよびサウンド キューにコメントを作成できるようにしました。 - * New:マウス中ボタンによるパンの動きを反転させるオプションを追加しました。Editor Preferences (エディタの設定) -> Viewports (ビューポート) の **Invert Middle Mouse Pan** (マウス中ボタンによるパンの動きを反転) オプションから選択できます。 - * New:* プレースメント ブラウザに検索機能を追加しました。 - * New:* **Ctrl** キーを押したままにすると、頂点ペインティングによってアクタが選択解除/再選択されないようになりました。 - * New: **Ctrl + バックスラッシュ** 、および **Ctrl + Delete** を、編集可能テキストボックスに追加しました。 - * New:**Enable Sound** (サウンドを有効にする) オプションを Play-In-Editor (プレイ イン エディタ) に追加しました。 - * New:保存されるものに応じて、Save Map (マップを保存) または Save Asset (アセットを保存) が Save (保存) ウィンドウに表示されるようになりました。 - * New:* 個々のサブカーブをスケーリングできる機能を、カーブ エディタに追加しました。 - * New:デフォルトでコンテンツが自動保存されるようになりました。また、保存されるパッケージの数が表示されるようになりました。 - * New:詳細を見るために **F4** キーを押すと、他の Details (詳細) パネルがすべてロックされている場合に、新たな Details (詳細) パネルが開かれるようになりました。 - * New:* コンテンツ ブラウザのコンテクスト メニューにある Browse (参照) ボタンが、ロードされていないオブジェクトに有効となりました。 - * New:Reset Layout (レイアウトをリセット) 機能が、Editor Preferences (エディタの設定) から Window (ウィンドウ) メニューに移動しました。 - * New:Editor Preferences (エディタの設定) の **Region & Language** (地域と言語) において、コードに入っている場合に (英語で) プロパティ名を表示するための設定が可能になりました。 - * New:Editor Preferences (エディタの設定) で選択の色をカスタマイズできるようになりました。 - * New:レベル エディタのビューポート上で遠くのビュー プレーンをオーバーライドできるようになりました。 - * New:Save Content (コンテンツを保存) ダイアログでコラムがソート可能になりました。 - * New:3D マーキー選択が、元のキーバインディング (Ctrl + Alt + 左クリック ドラッグ) をともなって、再度追加されました。 - * New:* エディタ内の読み込みエラーを診断するためのメッセージ ログのリンクを追加しました。 - * New:アクティブなカメラのセーフ フレームがある場合、High Resolution Screenshot UI (ハイ リゾリューションのスクリーン ショット UI) によって、キャプチャ領域をそのセーフ フレームに設定できるようになりました。 - * New:プラグイン エディタでプラグインを有効化または無効化した後でエディタを再起動してもらうためのプロンプトを追加しました。 - * New:テクスチャ エディタ内のズーム スライダーが、 **Fit to Viewport** (ビューポートに合わせる) の設定に対して適切に作用するように改善しました。 - * エディタ内におけるデカールのスケーリング性能を改善しました。 - * エディタ内における Asset Discovery (アセットの発見) の時間を改善しました。 - * 遠くにある Arrow Component (矢印コンポーネント) の可読性を改善しました。 - * **Code View (コード ビュー)** 機能をアップデートして、プラグインで機能するようにしました。 - * Code View (コード ビュー) プラグインを有効化して、この機能を再開させてください。(Window (ウィンドウ) メニュー -> Plugins (プラグイン) -> Editor (エディタ) -> Code View (コード ビュー)) - * Editor Preferences (エディタの設定) 内の **Region & Language** (地域と言語) の使いやすさを改善しました。設定の変更が、分かりやすく、使いやすくなっているはずです。 - * High Resolution Screenshot (ハイ リゾリューション スクリーンショット) 機能を修正しました。 - * スクリーンショット キャプチャは、ハイ リゾリューション スクリーンショットのアクションが選択されたビューポートに限定されるようになりました。 - * Editor Preferences (エディタの設定) が、あらゆる利用可能な言語と地域を表示しない不具合を修正しました。 - * **Select Actors using this Asset** (このアセットを使用するアクタを選択) が、他のストリーミング サブレベルでアクタを選択しない不具合を修正しました。 - * マウステストが原平面から拡張しないことに起因する、正投影法のビューポートにおける選択の問題を修正しました。 - * 複数のレベルからクリップボードにアクタをコピーした後、アクタが選択されたままになっていない不具合を修正しました。 - * グローバルなショートカット キーが、ある場合に、フローティング ウィンドウで機能しなくなる不具合を修正しました。 - * カメラが選択されていない状態でカメラがマチネでロックされると、セーフフレームとアスペクト比のバーが表示されない不具合を修正しました。 - * ビューポートの設定が、エディタの設定ファイルにではなく、レイアウトの設定ファイルに保存される不具合を修正しました。 - * 通知が、適切なモニター作業領域に置かれない不具合を修正しました。 - * 出力ログからテキストをコピーすると、正しい順番で行がコピーされない不具合を修正しました。 - * 出力ログの自動スクロールを修正しました。 - * レベル ブラウザにおけるレベル ロックの変更を元に戻すまたはやり直しできなくなる不具合を修正しました。 - * スプラッシュ スクリーンでプロジェクト名を表示することによって、非直感的なプロジェクトの切り替えを修正しました。 - * サーベイの通知が、閉じるためにキャンセルした後でもすぐに消えない不具合を修正しました。 - * アクタが入っているレイヤーがビューポートで非表示になっている場合に、アクタが選択されている不具合を修正しました。 - * チュートリアル ウィンドウが音を鳴らさないように修正しました。 - * 仮想ジョイスティックにともなう白い四角のアーティファクトを、 **StartupDelay** 関数を追加することによって修正しました。 - * **FindObject** が呼び出された場合に保存の時に起きるクラッシュを修正しました。 - * ビューポート内におけるカーブ ハンドルの動きを修正して、反転しないようにしました。 - * アセットがブラシのエッジ/頂点にドロップする不具合を修正し、正しい場所に置かれるようにしました。 - * ランチャーからインストールされた場合に、SVN のバイナリがエディタに含まれない不具合を修正しました。 - * ツールチップが、メインメニューの Window (ウィンドウ) のオプションに表示されない不具合を修正しました。 - * フレームレートの設定値が、ゼロより小さく設定できる不具合を修正しました。 - * ScaleMeshes コンソール コマンドによる StaticMesh のスケーリングで、変更を加える前に既存の BuildScale が考慮されていない不具合を修正しました。 - * ブループリント チュートリアルを見た後でホームボタンがチュートリアル ウィンドウに表示されない不具合を修正しました。 - * 使用されていないスプラッシュ スクリーンを削除しました。 +* **General Editor** + * New:Improved the 3D viewport grid! + * Removed the grid dots for a cleaner view.The grid is now also scaled according to the grid snap settings. + * Perspective grid precision improved with thinner lines. + * Orthographic grid now has power of 10 major gridlines, soft fading transitions between levels, and colored axis lines. + * New:Added a **Preview Meshes** preference that allows customization of meshes displayed in viewports when holding the **Backslash** key. + * New:Icons for your project can now be assigned via Window/Project Settings. + * New:Startup Movies for your project can now be assigned via Window/Project Settings. + * New:Pressing the C key now creates comments in the Material and SoundCue editors. + * New:Added an option to invert middle mouse pan movement.**Invert Middle Mouse Pan** option in the Editor Preferences -> Viewports. + * New:Added search support in the Placement Browser. + * New:Holding **Ctrl** now prevents Vertex Painting from de/re-selecting Actors. + * New:Added support for **Ctrl + Backspace** and **Ctrl + Delete** to editable text boxes. + * New:Added **Enable Sound** option to Play-In-Editor settings. + * New:Save window now displays "Save Map" or "Save Asset" depending on what's being saved. + * New:Added ability to scale individual sub-curves to the curve editor. + * New:Content is now autosaved by default, and the notification shows you the number of packages that will be saved. + * New:Pressing **F4** to view details will now potentially spawn a new Details panel if all the currently open ones are locked. + * New:Browse button in the Content Browser context menu now works on unloaded objects. + * New:The Reset Layout feature has been moved to the Window menu from Editor Preferences. + * New:Property names can be set to display as they are in code (English) on the **Region & Language** editor preferences. + * New:You can now customize the selection colors in the Editor Preferences. + * New:You can now override the far view plane on a level editor viewport. + * New:Columns are now sortable in Save Content dialog. + * New:3D marquee select has been re-added with the same original keybinding (**Ctrl + Alt + Left Click Drag**). + * New:Added a message log link to diagnose load errors in-editor. + * New:If there is an active camera safe frame, the High Resolution Screenshot UI allows you to set the capture region to that safe region. + * New:Added prompt to restart the editor after you've enabled or disabled a plugin in the Plugins Editor. + * New:Improved how the zoom slider in the Texture Editor interacts with the **Fit to Viewport** setting. + * Improved decal scaling performance in the editor. + * Improved Asset Discovery time in the editor. + * Improved Arrow Component readability at a distance. + * Updated **Code View** functionality to now exist in a plugin. + * Please enable the **Code View** plugin to reactivate this functionality (**Window Menu -> Plugins -> Editor -> Code View**). + * Fixed **Region & Language** editor preferences to be more user friendly.Changing them should be less confusing or awkward. + * Fixed High Resolution Screenshot facility. + * Screenshot capture is now limited to the viewport from which the High Res Screenshot action was selected. + * Fixed Editor Preferences not listing all available languages and regions. + * Fixed **Select Actors using this Asset** not selecting Actors in other streaming sub-levels. + * Fixed selection problems in orthographic viewports due to mouse tests not extending from beyond the origin plane. + * Fixed Actors not remaining selected after copying Actors from multiple levels into the clipboard. + * Fixed global shortcut keys not functioning in floating windows in some cases + * Fixed safe frames and aspect ratio bars not displaying when locking a camera in Matinee when no camera is selected. + * Fixed viewport settings not being saved into the layout preferences file instead of the editor preferences files. + * Fixed notifications not being anchored to their appropriate monitor work area. + * Fixed copying text from the Output Log not copying lines in the correct order. + * Fixed Output Log auto scrolling. + * Fixed level locking changes in the level browser not being able to be undone or redone. + * Fixed unintuitive project switching by displaying the name of the project in the splash screen. + * Fixed survey notification not fading away instantly after clicking Cancel to close it. + * Fixed Actors being selected when the viewport is hiding the layer they are in. + * Fixed Tutorial window to no longer play sounds. + * Fixed the white square artifact with the Virtual Joystick by adding a **StartupDelay** function. + * Fixed crash on save when **FindObject** is called. + * Fixed curve handle movement in Viewports to no longer be inverted. + * Fixed dropping assets onto Brush edges/verts, it now leaves them at the correct location. + * Fixed SVN binaries not being included with the editor when installed from the launcher. + * Fixed tooltips not appearing in the Window options on the main menu. + * Fixed Frame rate settings being allowed to go below zero. + * Fixed StaticMesh scaling via "ScaleMeshes" console command not taking into account the existing BuildScale into consideration before making any changes. + * Fixed home button not appearing in the tutorial window appears after viewing Blueprint tutorials. + * Removed unused splash screens. * **FBX** - * New:**Import All** (すべてをインポート) ボタンを FBX インポート ダイアログに追加しました。このボタンを使用すると、一度の指示で、同じ FBX の設定値をともなった選択済みファイルがすべてインポートされます。 - * FBX のインポート オプション ウィンドウを整理しました。 - + * New:Added an **Import All** button to the FBX import dialog.This will import all selected files with the same FBX settings without being asked more than once + * Changed FBX Import Options Window for clarity: ![](fbx.png) - * スケルタル メッシュのインポート設定値の下にある **Import Meshes in Bone Hierarchy** のデフォルト設定値を変更し、デフォルトで有効となるようにしました。これによって、ボーン階層内の非スキンメッシュが、ボーンとしてではなく、実際のメッシュとしてインポートされることになります。 - * マテリアルとテクスチャが互いに同じ名前をもつ場合や、メッシュと同一の名前をもつ場合のインポートについて修正しました。この修正によってクラッシュが起きなくなり、名前が衝突した場合はそれぞれにユニークな名前が生成されます。 - * FBX からインポートされたマテリアルでオーバーラップするノードを修正しました。 -* **コンテンツ ブラウザ** - * New:フォルダ上で右クリックして **Rename** (名前変更) を選択することによって、フォルダの名前を変更できるようになりました。 - * New:次のようなコンテンツ ブラウザの表示オプションを新たに追加しました。 - * **Show Only Assets in Selected Folders** (選択されたフォルダのアセットのみを表示) は、検索またはフィルタリング時に、現在選択されているフォルダに入っているアセットのみを表示します。 - * **Real-Time Thumbnails** (リアルタイム サムネイル) が有効になっている場合、アセットがロードされると、マテリアルのアニメーションが表示されます。 - * New:Diff ツールを使用している場合、 **ビヘイビア ツリー** のアセットへの変更が、インタラクティブに表示できるようになりました。 - * **Developer Folder** のオプションが無効化されている場合に、Developer フォルダが、コンテンツ ブラウザのブレッドクラムのトレールに表示される不具合を修正しました。 - * サムネイルのテクスチャのストリーミングを改善して、サムネイルのテクスチャがぼやけたグラフィックでしばしば描画される不具合を修正しました。 - * ウィンドウが開かれた時に、コンテンツ ブラウザの検索窓に直ちに入力できない不具合を修正しました。 - *move/copy (移動/コピー) を修正することによって、フォルダ グループの move/copy 1 回につき 1 度だけアセットの読み込みを求めるようにしました。 -* **マチネ** - * New:マチネが、(BMP および AVI 形式の他に) PNG および JPEG 形式へのレンダリングに対応するようになりました。 - * New:カメラがマチネでロックされ、かつカメラ以外が選択されている場合に、セーフフレームとアスペクト比のバーが表示されない不具合を修正しました。 - * New:マチネが開いている状態で、ビューポートからアクタを削除しようとすると、通知されるようになりました。 - * カーブ エディタのビューポートの無効化を最適化しました。これによって、マチネのパフォーマンスが向上しました。 - * マチネの元に戻す/やり直しの機能が、カスケードなど他エディタと整合しない問題を修正しました。 - * ズーム モード時に、グラフのラベルおよびボタンとインタラクトできない不具合を修正しました。 - * **Slomo** のトラックが、再生速度を 10% 未満まで落とせない不具合を修正しました。 -* **ペルソナ:アニメーション エディタ** - * New:ペルソナで複数のボーンを同時に選択、編集できるようになりました。 - * New:ペルソナに備わっているアセット ブラウザから直接アセットを保存できるようになりました。 - * New:アニメーション通知を選択して Delete キーを押すと、アニメーション通知を削除できるようになりました。 - * New:アセットを参照しているブループリントのノードから直接アセットを開くことができるようになりました。 - * New:* スケルトンから使用されていないボーンをユーザーが削除できるようにする機能をペルソナに追加しました。 - * New:* ペルソナのアセット ブラウザに、最近開いたファイルの履歴を、進む/戻るボタンの方式で表示できる機能を追加しました。 - * New:* ペルソナのアセット ブラウザにフィルタを追加しました。 - * スケルトンにおいて、デフォルトのプレビュー メッシュの設定を変更することによって、NULL メッシュの処理が開始されないようにしました。 - * ボーンへの変更を元に戻す/やり直しできない不具合を修正しました。 - * セッション間で保持されないペルソナの設定項目が存在する不具合を修正しました。 - * ペルソナのモード ウィジェットが、ダーティーな状態を表示しない不具合を修正しました。 - * ペルソナのスケルトン ツリーのコンテクスト メニューがクラッシュする問題を修正しました。 - * ペルソナでスライダーが動かされた時にプレビューのビューポートが描画されない不具合を修正しました。 -* **ソース コントロール** - * New:P4 プラグインは、P4HOST マスカレード、パスワード ログイン、およびデポをストリーミングする接続をサポートするようになりました。 - * New:P4 はプロジェクトにマッピングしないワークスペースに接続できなくなりました (SVN の作業中のコピーに対しても同様)。 - * New:チェックインに成功したときのトースト ポップアップを追加しました。 - Perforce のソース コントロールのプラグインが、Unicode のワークスペース名とユーザー名をサポートしていない不具合を修正しました。 -* **マテリアル エディタ** - * New:**左 + 右のマウスボタン** を押したままドラッグすることで、ズームインとズームアウトができるようになりました。 - * New:マテリアル属性は Feature Level と Quality スイッチに接続できるようになりました。 - * New:マテリアル エディタでピンを引き出す場合に、コンテキストに応じた機能を追加しました。 - * New:Material Details にあるライティング固有のオプションは Unlit モードがアクティブな場合、グレイアウトされるようになりました。 - * New:マテリアルの統計が独自のタブに表示されるように変更しました。 - * New:マテリアル エディタに New Mobile Stats Icon (新しいモバイル統計アイコン) を追加しました。 - * New:マテリアル式ノードに対するタイトルの色付けを追加しました。 - * New:精度を上げるために、Panner マテリアル式に時間の小数部分を使用するオプションを追加しました。 - * 欠落していたデフォルトのマテリアル値を公開し、不要な入力に対するツールチップを追加しました。 - * マテリアルのアセット名がマテリアル エディタのタイトル タブに表示されないという問題を修正しました。 - * マテリアル関数から、任意のマテリアルまたはマテリアルを使用する関数に変更が伝搬されることを修正しました。 -* **ジオメトリの編集** - * New:ジオメトリ ブラシは、中心となるパラメータが変更されてもマテリアル情報を維持しようとします。 - * ポリゴン数が同じままの変更は、完全にサポートされています。 - * ポリゴン数が異なる変更は、メッシュ全体で単一のマテリアルのみサポートされています。 - * ジオメトリ ブラシをドラッグし、シーン アウトライナーにドロップする操作が適切に機能しないという不具合を修正しました。 - * 様々なジオメトリ編集モードのコントロールをスクロールできないという不具合を修正しました。 - * ジオメトリ編集モードがアクティブな状態で、3D シーンでレガシーのビルダ ブラシが見えるという問題を修正しました。 - * ブラシを作成するように Lathe ツールを修正しました。 - * 機能しないため、Volumetric と Sheet のブラシ形状を削除しました。 -* **ランドスケープとフォーリッジ (葉)** - * New:ランドスケープ スプラインは、スプラインのメッシュ用に、**Max Draw Distance** (最大描画距離) 設定を持つようになりました。 - * New:ビューポートに新しいランドスケープ LOD (Level of Detail) プレビュー設定を追加しました。 - * New:コリジョン設定用の新しいコントロールをフォーリッジ ツールに追加しました。 - * New:Change Component Size ツールに **Resample** (再サンプリング) オプションを追加しました。 - * New:ランドスケープ スプラインのスプライトが大きくなりすぎないように、スプラインの幅に自動的にスケーリングします。 - * New:コンポーネントの選択が何もアクティブになっていない場合に、ランドスケープの **move-to-level** (レベルへ移動) ツールが、カーソルの下にあるコンポーネントで機能するようにしました。 - * ランドスケープのビジュアライザ メニューを更新しました。 -* **メッシュのペイントツール** - * New:ペイント ブラシの半径がエディタの preferences (環境設定) で保存されるようになりました。 - * デフォルトのペイント ブラシの半径を 128 に更新しました。 -* **データ テーブル エディタ** - * New:読みやすくするために、偶数行と奇数行は異なる背景色になりました。 - * New:データ テーブル エディタで検索機能が実装されました。 -* **シーンアウトライナー** - * New:シーン アウトライナーの右クリックのコンテキスト メニューでアクタやフォルダを管理するためのオプションが増えました。 - * シーン アウトライナーにあるフォルダでの元に戻す / やり直すの機能を修正しました。 -* **ワールド ブラウザ** - * New:World Browser -map=PersistentMapName?worldcomposition によって作成されたワールドに対するクッキングを処理するためのオプションを追加しました。 - * New:タイルの距離のストリーミングのロード/アンロードの要求間の時間閾値を追加しました。以下のコンフィギュレーション ファイルで変更できます。**TilesStreamingTimeThreshold.** - * New:レベルのタイルに対する位置スナッピングを追加しました。 **Ctrl + 左クリック** してドラッグします。 - * レベルのタイルのワールド ブラウザの非同期読み込みを、ブロッキング ロードと置き換え、"long operation" メッセージを追加しました。 - * **Always Loaded** レベル タイプを削除しました。 -* **デバイス プロファイル エディタ** - * New:デバイス プロファイル エディタは、以下から常に利用できるようになりました。Window Menu -> Device Profile Editor - * デバイス プロファイル エディタの UI を主要な用途を反映するレイアウトになるように更新しました。 - * CVar の追加、削除、ペアレンティングがプロファイルではるかに明確になるように更新されました。 -* **翻訳エディタ** - * New:翻訳エディタは、ローカリゼーション ファイルがどのプロジェクト/言語が翻訳可能であるかを決定するためにエンジン、エディタ、現在読み込まれているプロジェクトのディレクトリを検索するようになりました。 - * New:データをファイルに書き込む、ユーザーが保存を忘れたことによる、またはエディタのクラッシュによるデータ損失を防ぐために、プロパティの変更によってトリガーされるイベントを翻訳データ オブジェクトに追加しました。 - * 再度ソース コントロールから同期する代わりに、可能な場合、古いマニフェストのローカルでキャッシュされているバージョンを読み出すように修正しました。 -#### ブループリント + * Changed the default setting of **Import Meshes in Bone Hierarchy**, under the Skeletal Mesh import settings, to be enabled by default.This will result in any non-skinned meshes in the bone hierarchy being imported as actual meshes and not as bones. + * Fixed importing with Materials and Textures that are the same name as each other or a mesh.This will no longer cause a crash, instead unique names will be generated for each conflict. + * Fixed overlapping nodes on Materials imported from FBX. +* **Content Browser** + * New:You can now rename folders by right clicking on them and selecting **Rename**. + * New:Added new Content Browser view options: + * **Show Only Assets in Selected Folders** will only show assets in the currently selected folder when searching or filtering. + * With **Real-Time Thumbnails** enabled, any loaded asset will show material animation. + * New:Changes to **Behavior Tree** assets can now be displayed interactively while using the Diff Tool. + * Fixed the Developer Folder appearing in the Content Browsers breadcrumb trail if the **Developer Folder** option is disabled. + * Fixed Textures in thumbnails often drawing with blurry graphics by improving streaming for thumbnail Textures. + * Fixed not being able to type immediately into Content Browser search when window is summoned. + * Fixed move/copy to only prompt for asset load once per folder group move/copy. +* **Matinee** + * New:Matinee now supports rendering to PNG and JPEG formats (along with BMP and AVI). + * New:Safe frames and aspect ratio bars can now be displayed when locking a camera and in Matinee when a non-camera is selected. + * New:Notification now occurs when attempting to delete an Actor from the Viewport while Matinee is open. + * Optimized invalidation of curve editor viewport, which improves Matinee's performance. + * Fixed inconsistencies with how Undo/Redo works in Matinee compared to other editors such as Cascade. + * Fixed not being able to interact with graph labels and buttons while in Zoom Mode. + * Fixed **Slomo** tracks not being able to slow the play rate down below 10%. +* **Persona:Animation Editor** + * New:You can now select and edit multiple bones at the same time in Persona. + * New:You can now save assets straight from Persona's built-in Asset Browser. + * New:Animation Notifies can now be deleted by selecting them and pressing the Delete key. + * New:You can now open assets directly from Blueprint nodes that reference them. + * New:Added function to Persona to allow the user to remove unused bones from a skeleton. + * New:Added recently opened file history in the form of Forward and Back browser buttons in the Asset Browser in Persona. + * New:Added filters to Asset Browser in Persona. + * Changed the setting of the default preview mesh on skeletons to make sure they never start will a NULL mesh. + * Fixed not being able to undo and redo changes to bones. + * Fixed some Persona settings not being remembered between sessions. + * Fixed Persona mode widgets not indicating dirty state. + * Fixed a crash in Persona's skeleton tree context menu. + * Fixed the preview viewports not drawing when dragging a slider in Persona. +* **Source Control** + * New:P4 plugin now supports P4HOST masquerading, password login and connection to stream depots. + * New:P4 can no longer connect to workspaces that do not map to your project (and similarly for SVN working copies) + * New:Added toast popup when successfully checking in. + * Fixed Perforce source control plugin not supporting Unicode workspace names and user names. +* **Material Editor** + * New:You can now zoom in and out by holding **Left + Right Mouse Buttons** and dragging. + * New:Material Attributes can now be connected to Feature Level and Quality switches. + * New:Added context sensitivity when dragging off pins in the Material Editor. + * New:Lighting-specific options in the Material Details are now grayed out when Unlit mode is active. + * New:Changed Material statistics to be displayed in their own tab. + * New:Added New Mobile Stats Icon for Material Editor. + * New:Added title coloring for Material Expression nodes. + * New:Added option to Panner Material Expression to use fractional component of the time calculation to improve accuracy. + * Exposed default material values that were missing and added tooltips to non-required inputs. + * Fixed Material asset name not being displayed in the Material Editor Title tab. + * Fixed propagating changes from material functions to any materials or functions using them. +* **Geometry Editing** + * New:Geometry brushes will now attempt to keep the material information even when their core parameters are altered. + * Changes where the number of polygons remain the same are completely supported. + * Changes where the number of polygons differ only support a single material across the whole mesh. + * Fixed dragging and dropping Geometry Brushes into the Scene Outliner not working correctly. + * Fixed not being able to scroll through the various Geometry Editing mode controls. + * Fixed legacy builder brush visible in the 3D scene while Geometry Editing mode is active. + * Fixed the Lathe tool to create a brush. + * Removed Volumetric and Sheet brush shapes as they were non-functional. +* **Landscape and Foliage** + * New:Landscape splines now have a **Max Draw Distance** setting for meshes on the spline. + * New:Added new Landscape LOD preview settings to viewports. + * New:New controls for collision settings were added to Foliage tool. + * New:Added **Resample** option for Change Component Size tool. + * New:The Landscape Spline sprite automatically scales with the width of the spline to prevent them from getting too big. + * New:The Landscape **move-to-level** tool will now operate on the component under the cursor when there is no component selection active. + * Updated the order of the Landscape Visualizers menu. +* **Mesh Paint Tool** + * New:Paint brush radius is now saved with your editor preferences. + * Updated the default paint brush radius to 128. +* **Data Table Editor** + * New:To aid in readability, even and odd rows now have different background colors. + * New:Search has been implemented in the Data Table Editor. +* **Scene Outliner** + * New:More options for managing Actors and folders in the Scene Outliner right click context menu. + * Fixed Undo/redo with folders in the Scene Outliner. +* **World Browser** + * New:Added option to handle cooking for worlds created by World Browser -map=PersistentMapName?worldcomposition. + * New:Added time threshold between tile distance streaming load/unload requests.Can be changed in configuration files:**TilesStreamingTimeThreshold**. + * New:Added position snapping for level tiles, use **Ctrl+Left Click** Drag. + * Replaced World Browser async loading of level tiles with a blocking load and added "long operation" message. + * Removed the **Always Loaded** level type. +* **Device Profile Editor** + * New:Device Profile Editor is now always available through the Window Menu -> Device Profile Editor + * Updated the device profile editor UI with a layout which reflects its primary usage. + * Updated CVar addtion, removal, and parenting to be a lot more evident for a profile. +* **Translation Editor** + * New:Translation Editor now searches the Engine, Editor, and the currently loaded project's directories for localization files to determine which projects/languages can be translated. + * New:Added event triggered by a property change to the translation data object to write the data to file, to prevent data loss due to user forgetting to save, or the editor crashing. + * Fixed Translation Editor to read local cached versions of old manifests when possible instead of syncing them from Source Control again. -* New:ブループリント エディタ内のコンポーネント モードでコンポーネントのアタッチ / デタッチの操作に対する元に戻す / やり直しの機能を追加しました。 -* New:ブループリント グラフでグラフ ノードの再配置に対して元に戻す / やり直しの機能を追加しました。 -* New:ブループリント エディタ内のコンポーネント モードでコンポーネントの複製に対して適切な元に戻す / やり直しの機能を追加しました。 -* New:コンポーネント モードで 2 つの異なるブループリント エディタのウィンドウ間でのコンポーネントのドラッグ機能を追加しました。 -* New:ブループリント エディタ内のコンポーネント モードで複数のコンポーネントを選択した状態でのドラッグ & ドロップ機能を追加しました。 -* New:ユーザーが名前変更可能なノードを名前変更する機能を持つブループリント エディタの詳細ビューにグラフ ノード セクションを追加しました。 -* New:あるインターフェイスから別のインターフェイスにキャストするための機能をブループリントのキャスト ノードに追加しました。 -* New:**Float * (LinearColor)** ブループリント ノードを使用して、浮動小数値によって LinearColors を乗算処理できるようになりました。 -* New:文字列を簡単に分割するために新しい **ParseIntoArray** 関数を追加しました。 -* New:変数 Get/Set ノードは、充実したツールチップを表示できるようになりました。ツールチップを表示するには、ノード上にマウスを合わせ、Ctrl+Alt を押したままにします。 -* New:**Alt + 右クリック** は、ブループリント グラフをズームする代替方法として使用できるようになりました。 -* New:Debug Object ドロップダウンに、メニュー拡張性のあるフックを追加しました。 -* New:ノードが選択されている場合、[詳細] パネルからグラフ ノードの名前変更ができるようになりました。 -* New:ブループリント インターフェイスを検索するためのサポートを追加しました。 -* New:Blueprint Interface の関数を名前変更すると、実装しているBlueprints にある関数も適切に名前変更されるようになりました。 -* New:ブループリント内からモンタージュの **PlayRate** を設定するための機能を追加しました。 -* New:**OnProjectileBounce** に Impact Velocity パラメータを追加し、ブループリントでバウンス べロシティ ベクターのオーバーライドができるようにしました。 -* New:スライダーの UI 範囲 ("slider UI range") に合わせるために、ブループリントの数値の変数に値 (クランプ) 範囲 ("value (clamp) range") の公開を追加しました。 -* ブループリントから特定の呼び出しサイトでの複数の保留中の潜在的なアクションを可能にする更新を行いました。 -* ブループリント エディタのコンボボタン メニューのスケーリングを修正しました。 -* Blueprint Components モードのビューポートにおける **リアルタイム** レンダリングを修正しました。ブループリント エディタ内でコンポーネント モードが非アクティブな場合、リアルタイム レンダリングは無効になります。 -パーティクル システム ヘルパーを含むブループリント アクタ上で作業するための **Toggle Particle System Helpers** オプションを修正しました。 -* 絶対的および相対的な変形設定の間で切り替える際に、ブループリントが修正されたことを示すフラグが適切に付けられるようになりました。 -* グラフ上でノードを移動後に元に戻す / やり直しができないという問題を修正しました。 -* コンポーネント モードでコンポーネントを平行移動している間のグリッド スナップを修正しました。 -* スプライト コンポーネント ビジュアライザが、エディタでシミュレーション (Simulate in Editor) またはエディタでプレイ (Play in Editor) を行っている間にブループリント エディタのプレビューでデフォルトの「アクタ」アイコンに切り替わるという問題を修正しました。 -* Blueprint Interface 関数の名前変更を修正し、実装している Blueprints で適切に名前変更されるようになりました。 +#### Blueprints -#### レンダリング +* New:Added undo/redo support for component attach/detach operations in Components mode within the Blueprint editor. +* New:Added undo/redo support for repositioning graph nodes in a Blueprint graph. +* New:Added proper undo/redo support for duplicating components in Components mode within the Blueprint editor. +* New:Added support for dragging components between 2 different Blueprint editor windows in Components mode. +* New:Added support for drag-and-drop with multiple components selected in Components mode within the Blueprint editor. +* New:Added a graph node section in the details view of the Blueprint editor that provides the ability to rename nodes that the user can rename. +* New:Added ability for Blueprint cast nodes to cast from one interface to another. +* New:You can now multiply LinearColors by floats using a **Float * (LinearColor)** Blueprint node. +* New:Added a new **ParseIntoArray** function for easily splitting up strings. +* New:Variable Get/Set nodes can now display Rich Tooltips.To view them, mouse over a node and hold Ctrl+Alt. +* New:**Alt + Right Click** can now be used as an alternative to zoom Blueprint graphs. +* New:Added menu extensibility hooks for additional items in the Debug Object drop down. +* New:Graph nodes can now be renamed via the details panel when a node is selected +* New:Added support for searching Blueprint Interfaces. +* New:Renaming Blueprint Interface's functions now properly renames the functions in implementing Blueprints. +* New:Added the Ability to set the **PlayRate** of a Montage from within Blueprint. +* New:Added Impact Velocity parameter to **OnProjectileBounce**, to allow blueprints to override bounce velocity vector. +* New:Added "value (clamp) range" exposure to numeric variables in Blueprints to go along with "slider UI range." +* Updates allowing multiple pending latent actions at a particular call site from a Blueprint. +* Fixed Combo button menu scaling in the Blueprint Editor. +* Fixed **Realtime** rendering in the Blueprint Components mode Viewport.It is now disabled when Components mode is deactivated within the Blueprint editor. +* Fixed the **Toggle Particle System Helpers** option to work on Blueprint Actors that contain Particle System Helpers. +* Fixed Blueprints to be properly flagged as being modified when toggling between absolute and relative transform settings. +* Fixed not being able to undo/redo after moving nodes around on the graph. +* Fixed Grid Snap while translating components in Components Mode. +* Fixed Sprite Component visualizers switching to the default "Actor" icon in the Blueprint editor preview during Play in Editor or Simulate in Editor. +* Fixed renaming Blueprint Interface functions, they will now properly rename in implementing Blueprints. -* **一般** - * New:DBuffer デカール エフェクト (マテリアルのデカール反応) の一部を無効にする機能を追加しました。 - * カラー、法線、ラフネスをマスクすることができます。 - * これにより、テクスチャ サンプリング ユニットを解放し、パフォーマンスを向上させ、制御を強化します。 - * New:グラフィックス アダプタ (r.GraphicsAdapter) を選択、またはこれをシステムに自動的に行わせる機能を追加しました。 - * デフォルトでは一体型ではないグラフィックカードが優先されます (現在、アダプタ名で "Intel" をチェックしています)。 - * スカイライトの改善点: - * New:可動オブジェクトが、静的シャドウキャスターからスカイ シャドウイングを受け取ります。 - * TLM_Surface マテリアルがスカイの反射を適切にレンダリングするように修正しました。 - * 光沢のあるスクリーン空間の反射を改善し、ノイズを減らすようにしました。 - * レンダー ターゲットを D3D11 RHI でより低いミップ レベルで設定する場合に、ビューポートのディメンションが不正確に計算されうるという状況を修正しました。 - * D3D テクスチャ オブジェクトの不適切なキャストが行われうるという問題を修正しました。 +#### Rendering + +* **General** + * New:Added ability to disable parts of the DBuffer decals effect (Material Decal Response). + * You can mask color, normal, roughness. + * This can free up texture sampler units, improve performance, and gives more control. + * New:Added feature to choose graphics adapter (r.GraphicsAdapter) or let the system do this automatically + * By default, this favors non-integrated graphics card (at the moment we check for "Intel" in the adapter name). + * Improvements to Sky Lights: + * New:Movable objects receive sky shadowing from static shadow casters. + * Fixed TLM_Surface materials to render sky reflections properly. + * Improved glossy screen space reflections to reduce noise. + * Fixed situation that could cause incorrect viewport dimensions to be calculated when setting render target to lower mip levels with the D3D11 RHI. + * Fixed some possible incorrect casting of D3D texture objects. * **Android** - * New:反射キャプチャ データは、現在マップ パッケージに格納されています。 - * これにより、ES2 に対するクッキングは、常に再保存されているマップに対して有効な反射を持つようになります。 - * モーション ブラー、UIBlur、およびスクリーン空間の環境オクルージョンを最適化しました。 - * ゲームスレッド、レンダリング スレッド、イベント スレッドに対して affinity マスクを設定することで CPU のパフォーマンスを向上させました。 - * バージョン 53.0 以降のドライバを持つ Adreno 330- ベースのデバイス上でDisjointTimerQueries をオンにすることで GPU の処理を向上させました。 - * デバイス上で **STAT UNIT** の GPU フレームタイム測定を有効にするために、CVar の **r.DisjointTimerQueries** を更新しました。 + * New:Reflection capture data is now stored in the map package. + * This allows cooking for ES2 to always have valid reflections for maps that have been resaved. + * Optimized motion blur, UIBlur, and screenspace ambient occlusion. + * Improved CPU performance by setting affinity mask for the gamethread, renderthread and eventthread. + * Improved GPU performance by turning on DisjointTimerQueries on Adreno 330-based devices with a driver later than version 53.0. + * Updated the CVar **r.DisjointTimerQueries** to enable GPU frametime measurement in **STAT UNIT** on device. -#### ゲームプレイとフレームワーク +#### Gameplay and Framework -* New:Project Settings (プロジェクト設定) の [Input] セクションで、マウスがタッチビヘイビアをシミュレーションする旨を示すことができます。 -* つまり、PC でプレイされる簡単なタッチゲームに対してイベントを 1 セットだけマッピングすればよいことになります。 -* New:プロジェクト設定に Audio Settings セクションを追加しました。ここで、Default Sound Class と Default Base Sound Mix を指定できます。 -* New:プロジェクト設定の Maps & Modes セクションに分割スクリーン オプションを追加しました。 -* New:ビジビリティ テストを用いて、いくつかの重要でないパスポイントをスキップし、コンポーネントのパスを簡素化しました。デフォルトでは無効になっています。 -* New:ランドスケープのコリジョン データのクッキングを追加しました。クッキングされたランドスケープは、クッキングされたデータのバイナリ ストリームからコリジョン オブジェクトを作成し、これにより、レベルのストリーミング パフォーマンスを高めます。 -* New:Text Render Actor は、静的頂点とインデックス バッファを生成し、キャッシュするようになりました。 -* モーフ ターゲットがモーフィングした法線を計算する方法を改善しました。 -* 互換性がないためにモジュールの読み込みに失敗した場合のフィードバックの欠如を修正しました。エラーメッセージが表示されるようになりました。 -* クッキング中にエディタのみのスプライトが読み込まれることを修正しました。 -* 移動コンポーネントがアナログ入力を正確に処理するように修正しました。 -* マテリアル インデックスと LOD マッピング インデックスのクラッシュの問題を修正しました。 -* 非同期パッケージの読み込みでは、プリロードする前にポストロードできなくなるように修正しました。 -* デバイス プロファイル例の選択プラグインのUE4 を起動する要件を修正しました。 -* いつも読み込まれている (Always Loaded ) レベルが、デフォルトで「可視状態 (Should be Visible)」としてフラグ付けされるように修正しました。 +* New:In the Input section of the Project Settings you can now indicate that the mouse should simulate touch behavior. +* This means only one set of events needs to be mapped for simple touch games being played on PC. +* New:Added Audio Settings section of Project Settings in which the Default Sound Class and Default Base Sound Mix can be specified. +* New:Splitscreen options added to Maps & Modes section of Project Settings. +* New:Added path simplification to path following component using visibility tests, to skip some irrelevant path points.It is disabled by default. +* New:Added landscape collision data cooking.Cooked landscapes will now create collision objects from a binary stream of cooked data, which improves level streaming performance. +* New:Text Render Actors now generate and cache static vertex and index buffers. +* Improved the way Morph Targets calculated their morphed normal. +* Fixed the lack of feedback if a module fails to load due to a lack of compatibility.An error message will now be displayed. +* Fixed editor-only sprites being loaded while cooking. +* Fixed movement components to correctly handle analog input. +* Fixed a crash in material indices and LOD mapping indices. +* Fixed Async package loading no longer allows objects to be post-loaded before they are pre-loaded. +* Fixed the example device profile selection plugin requirement to launch UE4. +* Fixed Always Loaded levels to be flagged as **Should be Visible** by default. -#### ネットワーキング +#### Networking -* **一般** - * New:Character Movement Componen モードがレプリケートされるようになりました。 - * New:**Launch Character** は、ローカル外で制御されるキャラクターに対してクライアント側でシミュレートできるようになりました。 - * New:**Only Relevant to Owner** の設定が、ブループリントで利用できるようになりました。 - * リモートのネットワークのクライアントとシミュレートされたプロキシに対する移動するプラットフォーム上のキャラクタの動きを改善しました。 +* **General** + * New:Character Movement Component movement mode is now replicated. + * New:**Launch Character** can now be simulated client side for non-locally controlled characters. + * New:The setting **Only Relevant to Owner** is now available to Blueprints. + * Improved character movement on moving platforms for remote network clients and for simulated proxies. * **PlayStation 4** - * ソケットのサブシステムが、UDPP2P ソケットをサポートしています。 + * Socket subsystem support for UDPP2P sockets. -#### アニメーション +#### Animation -* New:参照ポーズ スケーリングのサポートが追加されました。 -分岐点をオーバーラップしないように **AnimMontages** を修正しました。 +* New:Added support for reference pose scale. +* Fixed **AnimMontages** to no longer allow branch points to overlap. -#### 物理 +#### Physics -* New:PhysX は 3.3.1 に、APEX は 1.3.1 にアップグレードされました。 -* 物理データを再クックする必要があるケースがあるかもしれません。 -* このアップグレードでは、いくつかの物理関連のバグを修正します。詳しい情報については、NVIDIA のリリースノートをご覧ください。 -* New:BodyInstance の最高角速度が、コードとブループリントで公開されました。 -* New:ポーンは被破壊メッシュと衝突するようになりました。大きなチャンクと小さなチャンクとでは、ポーンと異なるインタラクションを行うように設定できます。 -* New:ラグドールと物理アセットで破壊可能ジョイントを利用できるようになりました。 -* New:ラグドールと物理アセットでクロス (布地) をサポートします。 -* ボディ質量を暗黙的に使用するように、柔体 (soft) の物理コンストレイントを更新しました。 -* Async 物理シーンがデフォルトで無効になるように更新しました。 -* この機能は幾分高度であり、多くのメモリを使用します。そのため、デフォルトではオフになっており、以下の順序に従い、変更できます。 **Edit Menu -> Project Settings -> Physics -> Simulation ** category -* Async シーンが無効になっていれば、アクタで Enable Async フラグがあってもすべてのアクタは通常のシーンに配置されます。 -* デフォルトで、プレイヤーのポーンが Async シーンでインタラクションしないようになりました。 -* オーバーラップ イベント関連のバグを修正しました。オーバーラップ フラグに関する現在の挙動が、間違った挙動に依存する古いコンテンツでは動かない可能性があります。 -* 2 つのオブジェクト間のコリジョンは、Ignore、Overlap、または Blocking に設定することができます。 -* 2 つのオブジェクトがオーバーラップし、その **両方** で **Generate Overlap Events** フラグが true に設定されているとオーバーラップ イベントが発生します。 -* コードのバグによって、オーバーラップしているオブジェクトのひとつでフラグが false に設定されていても、ある状況でオーバーラップがトリガーされるようになっています。 -* つまり、以前発行していたオーバーラップ イベントは、フラグ付けが不適切なために停止する可能性があります。 -* コリジョンがオーバーラップとしてマーク付けされている場合に限り、Overlap イベントが発行するように修正しました。 -* コリジョンが Blocking としてマークされても、場合によっては Overlap イベントが発行するというバグがありました。 -* Hit Events は、**Simulation Generates Hit Events** を有効にすることによって、両方のオブジェクトをオプトインする必要性があるように修正しました。 +* New:PhysX and APEX have been upgraded to 3.3.1 and 1.3.1. +* In some cases it may be necessary to recook physics data. +* This upgrade fixes some physics related bugs.See NVIDIA release notes for more info. +* New:Maximum angular velocity of a BodyInstance has been exposed in code and blueprints. +* New:Pawns will now collide with destructible mesh.Large and small chunks can be set to get different interaction with pawn. +* New:Breakable joints are now available for ragdolls and physics assets. +* New:Support for cloth on ragdolls and physics assets. +* Updated soft physics constraints to use body mass implicitly. +* Updated the Async physics scene to be disabled by default. +* This feature is somewhat advanced and uses more memory.As such, it has been turned off by default and can be changed in the **Edit Menu -> Project Settings -> Physics -> Simulation** category. +* If Async scene is disabled, all Actors are placed in the regular scene regardless of the **Enable Async** flag on the Actor. +* Updated the player Pawn to no longer interact with the Async scene by default. +* Fixed overlap event related bugs.Correct behavior related to overlap flags may break old content relying on bad behavior. +* A collision between two objects can be set to Ignore, Overlap, or Blocking. +* An overlap event will occur if two objects Overlap and **both** have the **Generate Overlap Events** flag set to true. +* A bug in the code made it so that in certain situations an overlap would trigger even if one of the overlapping objects had the flag set to false. +* This means overlap events that were previously firing could now stop due to improper flagging. +* Fixed Overlap events to only fire when collision is marked as overlap. +* There was a bug where in some cases an overlap event would fire even if a collision was marked as Blocking. +* Fixed Hit Events now require both objects to opt in by enabling **Simulation Generates Hit Events**. -#### オーディオ +#### Audio -* New:PIE 設定に **Enable Sound** オプションを追加しました。 -* New:**Add Input** ボタンを適切な Sound Nodes に追加しました。 -* 作成 / 修正後に DialogueWaves をただちに再生できるように改善しました。 -* [Preselect at Level Load] 設定が使用されている場合、PIE での Random Sound ノードの選択を制限しました。 +* New:Added **Enable Sound** option to PIE settings. +* New:Added **Add Input** button to appropriate Sound Nodes. +* Improved DialogueWaves so they can be played immediately after creation/modification. +* Limited the Random Sound node choices in Play in Editor if **Preselect at Level Load** setting is used. -#### コア +#### Core -* New:UnrealBuildTool は、XML コンフィギュレーション ファイルを使用して設定できるようになりました! -* このツールは、以下の 2 箇所で BuildConfiguration.xml ファイルを探します(Engine/Saved/UnrealBuildTool と My Documnets/Unreal Engine/UnrealBuildTool)。1 つめは、ブランチ / エンジンの構成に対して、2 つめはパーソナル設定に対して使用します。環境変数設定は、こうした値が設定されるとオーバーライドされることがわかるでしょう。 -* この記法は、以下に掲載されています。\Engine\Programs\UnrealBuildTool\BuildConfiguration.xml -* New:クロス コンパイルする Linux クライアントに対するサポートが追加されました。 -* New:すべてのプラットフォームのメモリとアロケータ メモリの統計を、統計システムで利用できるようになりました。 -* New:統計システムにスレッドとスレッド グループのメタデータを追加しました。 -* New:統計ファイルの保存形式を改善しました (まだ完全には利用されていません) 。 -* New:[Windows] シェルの統合では、エンジンの複数バージョンを並べることをサポートしています。 -* エンジンのインストールを追加する、またはシェル拡張やファイルの関連付けのセットアップを初めて行うには、各 Engine\Binaries\Win64 ディレクトリから UnrealVersionSelector を実行します。 -* 各 .uproject ファイルは、別のエンジンのインストールで開くように設定することができます。 -* New:-UTF8Output コマンドライン引数は、エンジンを使用する任意のプログラムに渡して stdout を UTF-8 モードに強制することができます。 -* 記録している Unicode 文字列にクエスチョンマークがある場合に、これを使用します。 -* Visual Studio アクセサ (特に Express に対する) を改善しました。 -* Visual studio 2010 だけが存在しない場合に、Visual Studio のバージョンが何もインストールされていないという問題について InstallVisualizers.bat を修正しました 。 -* Win32 設定でエディタをビルドしようとすると UnrealBuildTool で早期にエラーを発生するように修正しました。 -* 国際管理化ライブラリのサイズを修正しました。 -* 国際管理化は、静的ライブラリからではなく、バイナリファイルからのデータを読み込むようになりました。 +* New:UnrealBuildTool can now be configured using an XML configuration file! +* It looks for the BuildConfiguration.xml file in two possible locations (Engine/Saved/UnrealBuildTool and My Documnets/Unreal Engine/UnrealBuildTool).The first one should be used for branch/engine configurations, while the second one is for personal settings.Notice that environmental variables settings will be overridden by those values if set. +* The syntax is described in \Engine\Programs\UnrealBuildTool\BuildConfiguration.xml. +* New:Added support for cross-compiling Linux client. +* New:All platform memory and allocator memory statistics are now available through the stats system. +* New:Added metadata for threads and thread group for the stats system. +* New:Improved save format of the stats files (not fully utilized yet). +* New:[Windows] Shell integration now supports multiple engine versions side by side. +* To add an engine installation, or to set up shell extensions and file associations for the first time, run UnrealVersionSelector from each Engine\Binaries\Win64 directory. +* Each .uproject file can be configured to open with a different engine installation. +* New:The -UTF8Output command line argument can be passed to any program using the engine to force stdout into UTF-8 mode. +* Use this if you are getting question marks in your Unicode strings being logged. +* Improvements to the Visual Studio accessor (particularly for Express). +* Fixed InstallVisualizers.bat complaining about no version of Visual Studio installed, when only Visual studio 2010 is missing. +* Fixed UnrealBuildTool to raise an error early about attempting to build the Editor in a Win32 configuration. +* Fixed the size of the internationalization libraries. +* Internationalization now loads its data from a binary file rather than from a static library. #### プラットフォーム * Android -* アンドロイドのデバイス検知を改善しました。スレッド化され全般的に効率が高まっています。 -* 接続されたアンドロイド デバイスがサポートしていないテクスチャ フォーマットが Launch に表示される問題を解決しました。接続されたアンドロイド デバイスがサポートしているテクスチャ フォーマットがだけを Launch に表示されるようになりました。 +* Improved Android device detection.It is now threaded and more efficient in general. +* Fixed **Launch** showing texture formats not supported by the connected Android devices.It will now only display texture formats that are supported by the connected Android devices. * Mac -* New:Mac でパッケージ化すると、独立したアプリケーション バンドルが作成されます。 -* New:現在、Mac UE4 は Epic のクラッシュ レポータを使用しています。 -* New:エンジンに同梱されているものの代わりに Mac にインストールされている Mono を使用する機能を追加しました。 -* New:Mac OS X に同梱されている dSYM デバッグ記号を生成するためのUBT のサポートを追加しました。 -* New:Mac プラットフォーム用のテキスト入力方法システムを実装しました。 - * これは、 Mac OS X 上のネイティブの Cocoa InputMethod サービスを使用し、異なる入力方法をサポートします。 -* Xcode プロジェクトを簡素化し、Xcode でのコードのインデックス付けを改善しました。 +* New:Packaging on Mac now creates a self-contained app bundle. +* New:Mac UE4 now uses our crash reporter. +* New:Added ability to use Mono installed on Mac instead of the one bundled with the engine. +* New:Added support to UBT for generating dSYM debugging symbol bundles on Mac OS X. +* New:Implemented text input method system for Mac platform. + * This uses the native Cocoa InputMethod services on Mac OS X to support the different input methods. +* Simplified Xcode project and improved code indexing in Xcode. * iOS -* New:Retina ディスプレイの iPad mini に対してデバイスの列挙型変数を追加しました。 -* New:Game Center 成績表をアプリ内で表示する実験的サポートを追加しました。(EXPERIMENTAL_ShowGameCenterLeaderboard)。 -* New:Windows のワークフローのビルド経由で iOS ビルドをシッピングするために **-compress=best** コマンドラインを追加しました。 -* iAd サポートのために様々な改善とバグ修正を行いました。 -* iOS ゲームセンターでのスレッディング問題を修正しました。 +* New:Added a device enumeration for iPad mini with retina display. +* New:Added experimental support for showing the Game Center leaderboard in-app (EXPERIMENTAL_ShowGameCenterLeaderboard) +* New:Added **-compress=best** command line for Shipping iOS via Windows workflow builds +* Various improvements and bug fixes to iAd support. +* Fixed some threading issues with IOS gamecenter. * PlayStation 4 -* New:**PlayGo** のサポートを追加しました。 -* New:Achievements (プレイヤーの統計) を実装しました。 -* New:シェーダのスクラッチ メモリのサポートが追加されました。 - ConsoleVariables.ini ファイルで **r.ShaderScratchBuffers=1** を有効にします。 -* New:HZB オクルージョンのカリングが、PS4 でサポートされます。 -* レンダー ターゲット / シェーダーの不一致をランタイムに検知する機能を追加しました。 -* レンダー ターゲットの出力形式を、シェーダ ファイルにあるSLOT 定義を使用するのではなく、**ModifyCompilationEnvironment** を通して設定するように更新しました。 -Xbox One -* New:Xbox One に 10:10:10 の最終Color 出力を追加しました。これにより、トーンマッパの量子化ノイズを取り除くことが可能になり、処理速度が一段と速くなります。 -* New:スクリーンの safe area (安全領域) が実装されました。 -* New:Achievements (プレイヤーの統計) を実装しました。 -* すべてのピクセル シェーダーの最適化を有効にしました。 -* より完成度が高い機能になるように、XAudio2 実装を改善しました。 -* 様々な GPU のハングアップを修正しました。 +* New:Added **PlayGo** Support. +* New:Implemented Achievements. +* New:Added support for shader scratch memory. + * Enable with **r.ShaderScratchBuffers=1** in the ConsoleVariables.ini file. +* New:HZB occlusion culling now supported on PS4. +* Added detection of render target/shader mismatches at runtime. +* Updated render target output formats to be set through **ModifyCompilationEnvironment** rather than using the SLOT defines in the shader files. +* Xbox One +* New:Added 10:10:10 final color output on Xbox One.This allows us to remove quantization noise in tonemapper, which is faster. +* New:Screen safe area is now implemented. +* New:Implemented Achievements. +* Enabled optimizations for all pixel shaders. +* Improved XAudio2 implementation to be more feature complete. +* Fixed various GPU hangs. -#### UnrealVS (Visual Studio の拡張) +#### UnrealVS (Visual Studio Extension) -* New:コマンドライン ボックスは、UE4.sln にある 'Game' プロジェクトに対してゲーム プロジェクト ファイルを自動的に追加するようになりました。 -* New:Visual Studio のカスタマイズ機能は、UnrealVS のツールバー コマンドをサポートするようになりました。 -* New:[UnrealVS Quick Build] メニューでは、IDE で config を変更せずに、どのコンフィギュレーションのビルドでも簡単にアクセスすることができるようになりました。 -* New:デバッグを支援するためにロギングを追加しました。 -* ゲーム専用のエディタ ビルド (例、MyGame "Debug Editor|Win64") に対するコード プロジェクトでは、UnrealVS でコマンドラインに追加するプロジェクトが不要になるように変更しました。 -* 上記の例で、エディタをデバッグするための UnrealVS コマンドライン引数はこれまで、"MyGame.uproject" でした。 -* 上記の例の UnrealVS コマンドライン引数は現在単に " " であり、プロジェクトが実行されると、UnrealVS は自動的にプロジェクト名を追加します。 -* プロジェクト名はまだエディタ実行ファイルに渡されますが、現在 UnrealVS はプロジェクト名を自動的に追加し、それを表示しません。 -* 既存のコマンドラインは、これまでどおり機能しますが、表示は異なります。 -* プロジェクト名を入力しないと、UnrealVS は表示されているコマンドラインからそれを除き、警告ダイアログをポップアップします。 -* Windows 以外のプラットフォームで実行可能プロジェクトを正確に認識するように Startup Project セレクタと Batch Build を修正しました。 +* New:Command Line box now automatically adds the game project file for 'Game' projects in UE4.sln. +* New:Visual Studio's Customize feature now supports UnrealVS' tool bar commands. +* New:UnrealVS Quick Build menu now allows easy access to building in any configuration without changing the config in the IDE. +* New:Added logging to help debugging. +* Changed code projects for game-specific editor builds (e.g. MyGame "Debug Editor|Win64") no longer need the project added to the command line in UnrealVS. +* Previously the UnrealVS command line args to debug the editor for the example above would have been "MyGame.uproject " +* The command line in UnrealVS for the example above is now just "", UnrealVS adds the project name automatically when the project is run. +* The project name is still passed to the editor executable but UnrealVS now adds it automatically and does not display it. +* Existing command lines will work as before but will display differently. +* If no project name is supplied, UnrealVS should strip it from the displayed command line and popup a warning dialog. +* Fixed Startup Project selector and Batch Build to correctly recognize executable projects on non-Windows platforms. -## API の変更 +## API Changes -#### ゲームプレイとフレームワーク +#### Gameplay and Framework -* bForceRescan パラメータを IAssetRegistry::ScanPathsSynchronous に追加しました。True ならば、パスのスキャンではスキャン済みのパスを無視しません。 -* IAssetRegistry に GetDerivedClasses を追加しました。これは、単に既存の GetSubClasses に対するラッパー関数です。 -* GameViewportClient で DrawTransition の青色の画面上のメッセージを無効にするフラグを追加しました。 -* ブループリントで GetOverlapInfos を使用するための機能を追加しました。 -* IOnlineExternalUI::ShowLoginUI に対するパラメータとして OnClosed デリゲートを追加しました。 -* GameViewportClient で DrawTransition の青色の画面上のメッセージを無効にするフラグを追加しました。 -* 複数のパスから ObjectLibrary を読み込むためのサポート、およびメモリに ObjectLibrary を簡単に作成するためのコンストラクタを追加しました。 -* UObject::CreateLibrary を呼び出す場合、ObjectLibrary でのブループリントのサポートを改善しました。bHasBlueprintClasses が true の場合、設定されていると、タイプをチェックしてくれます。 -* ワールドではなくプレイヤーにバインドするため、FGameWorldContext から FLocalPlayerContex に名前変更しました。 -* World Context 参照を戻す GetWorldContextFrom 関数を、GetWorldContextFrom*Checked に名前変更しました。 -* GetWorldContextFrom は、ポインタを戻し、供給された入力に対してWorldContext が存在しなければ NULL を戻します。 -AHUD から FSimpleReticle を取り除きました。必要に応じてこれをサブクラスに追加することができます。 -* AGameMode から、使用されていないライフサイクル イベント、OnEngineHasLoaded を削除しました。 -* 不要になったため、SGameWidget クラスを削除しました。 -* GameEngine から PendingLevelPlayerControllerClassName を削除し、LocalPlayer にある PendingLevelPlayerControllerClass と置き換えました。 -* これにより、他の PlayerController の参照と同様に機能するようになり、マップを結合するたびに混乱を招く警告が出ないようにします。 -* 使用するカメラ コンポーネントを見つけようとする場合、コンポーネントを有効にするか否かを考慮するように、AActor::CalcCamera を変更しました (アクティベーションを管理することにより、複数のカメラ コンポーネント間での選択を可能にしました) 。 -* SKismetLinear 表現式は関数として表示されるという点でより許容度が高くなりました (現在、1 つの出力を持つ任意の pure K2Node を何とかしようと試みています)。 -* ADebugCameraController と ADebugCameraHUD は拡張可能になり、エンジン モジュール外部からアクセスすることができます。 +* Added bForceRescan parameter to IAssetRegistry::ScanPathsSynchronous.If true, path scanning not ignore paths that have already been scanned. +* Added GetDerivedClasses to IAssetRegistry.This is just a wrapper function for the pre-existing GetSubClasses. +* Added a flag to disable blue onscreen messages in DrawTransition in GameViewportClient. +* Added ability for Blueprints to use GetOverlapInfos. +* Added OnClosed delegate as a parameter to IOnlineExternalUI::ShowLoginUI. +* Added a flag to disable blue onscreen messages in DrawTransition in GameViewportClient. +* Added support for loading an ObjectLibrary from multiple paths, and a constructor for easily creating an ObjectLibrary in memory. +* Improved the support for Blueprints in an ObjectLibrary when calling UObject::CreateLibrary.If the bHasBlueprintClasses is true, it will check the type for you. +* Renamed FGameWorldContext to FLocalPlayerContext, as it binds to a player and not a world. +* Renamed GetWorldContextFrom functions returning a World Context reference to GetWorldContextFrom*Checked. +* GetWorldContextFrom now returns a pointer and returns NULL if no WorldContext exists for the supplied input. +Removed FSimpleReticle from AHUD. You can add this to your subclass if desired. +* Removed unused lifecycle event OnEngineHasLoaded from AGameMode. +* Removed SGameWidget class as it is no longer necessary +* Removed PendingLevelPlayerControllerClassName from GameEngine and replaced it with PendingLevelPlayerControllerClass in LocalPlayer. +* This makes it work like the other PlayerController references, and avoids a confusing warning on every map join +* Changed AActor::CalcCamera to consider whether a component is activated when trying to find the camera component to use (allowing selection between multiple camera components by managing activation). +* Made SKismetLinearExpression more permissive in what it will show as a function (now tries to do something with any pure K2Node with one output). +* ADebugCameraController and ADebugCameraHUD can now be extended and accessed outside of the Engine module. #### エディタとツール -* スレートのドラッグ & ドロップ操作では、継承と互換性がある RTTI を使用するようになりました。これにより、DragDrop::IsTypeMatch が適切に機能するようになり、継承の階層のあらゆるレベルに静的キャストができるようになります。 -* GetTypeId in FDragDropOperation 派生の以前のインスタンスを、DRAG_DROP_OPERATOR_TYPE に置換してください。 -* FSlateApplication::GetDragDropReflector() は、現在使用されなくなり、削除されました。 -* 使用されていない Linked Obj Editor フレームワークを削除しました。 +* Slate drag drop operations now use RTTI that is compatible with inheritance.This allows DragDrop::IsTypeMatch to work properly allowing for static casting to any level of the inheritance hierarchy. +* Please replace previous instances of GetTypeId in FDragDropOperation derivatives with DRAG_DROP_OPERATOR_TYPE. +* FSlateApplication::GetDragDropReflector() is now obsolete and has been removed. +* Removed unused Linked Obj Editor framework #### プラットフォーム * Mac -* Mac OS X のサポートされる最低限のバージョンは現在、10.9.2 です。 - * 10.9.2 より前の OS X はサポートしなくなりました。以前のバージョンでは修正されない GL ドライバのバグと機能不足によるものです。 -* Mac のビルドは、現在 OS X 10.9 SDK を使用しており、コードとコンパイルの設定は、Xcode 5.1 と互換性があるように更新されています。 -* config ファイルは、~/Library/Preferences に移動し、ログは~/Library/Logs に、Saved フォルダからの他のすべてのファイルは、現在、~/Library/Application Support/Epic にあります。 +* The minimum supported Mac OS X version is now 10.9.2. + * We no longer support OS X versions prior to 10.9.2 due to OpenGL driver bugs & feature deficiencies that won't be fixed in earlier versions. +* Mac build is now using OS X 10.9 SDK, code and compile settings were updated to be compatible with Xcode 5.1. +* Config files on were moved to ~/Library/Preferences, logs to ~/Library/Logs, all other files from Saved folders are now in ~/Library/Application Support/Epic. * PlayStation 4 -* TitleID、パッケージの PassCode やその他のデータの仕様は、 Build/PS4/PackagingDataPS4.txt 配下のプロジェクト ディレクトリのテキスト ファイルにあります。これは、UBT にある古いメタデータ システムを置き換えるものです。 例は、ShooterGame とベースの Engine/BuildPS4 ディレクトリにあります。 -Xbox One -* March 2014 XDK に対してビルドするためにコードを更新しました。 -* 非推奨の関数 (D3DAllocateGraphicsMemory など) を削除 / 置換しました。 +* Specification of TitleID, package PassCode, and other data should now be in a text file in your project directory under Build/PS4/PackagingDataPS4.txt.This replaces the old metadata system in UBT. Examples can be found in ShooterGame, and the base Engine/BuildPS4 directories. +* Xbox One +* Code updated to build against March 2014 XDK. +* Deprecated functions (D3DAllocateGraphicsMemory, etc) have been removed/replaced. -#### コア +#### Core -* FPlatformString::Stricmp は、std::stricmp に合わせるために小文字に変換されました。 -* 文字列がアンダーラインだけ、またはASCII の小文字と大文字の範囲の間でのみ異なる場合、若干異なるソート順になる場合があります。 -* 不正な文字列変換中に警告が発行されるようになりました (例、ASCII で表すことができない Unicode 文字)。 -* コード内でこれが頻繁に起こると出力ログに余分なデバッグ テキストが存在するかもしれません。 -* TArray::Append and TArray::Insert は、オーバーロードされ、一度に複数エレメントを挿入できるようにします。 -* 現在、TSet は operator () の代わりに operator [] を通してアクセスされます。 -* C++11 の ranged-for 構文を使用したい場合に TobjectIterator を使用するのと同じように TObjectRange を使用できるようになりました。 -* 例: for (UClass* Cls :TObjectRange()) -* 使用されていないプロパティ フラグ、CPF_AlwaysInit を削除しました。 -* 使用されていない構造体フラグ、STRUCT_Transient を削除しました。 -* GConfig->SetVector4 および GConfig->GetVector4 を使用して、FVector4 を config ファイルに保存および読み込むためのサポートを追加しました。 -* 以下の言語以外のカルチャー (ロケール) を使用しているライセンシーは、ロケール データを含むために ICU データをリビルドする必要があります。 -* German – de, English – en, Spanish – es, French – fr, Hindi – hi, Italian – it, Japanese – ja, Korean – ko, Polish – pl, Portuguese – pt, Russian – ru, Swedish – sv, Chinese – zh -* DrawDebugHelpers、浮動小数点値のヒストグラム表示するためのサポートを追加しました。サンプルを記録するために FDebugFloatHistory を使用し、ゲームで描画するために DrawDebugFloatHistory を使用します。ブループリントでも利用できます。 +* FPlatformString::Stricmp now converts to lower case to match std::stricmp. +* This may result in slightly different sorting orders if your strings only differ by underscores or any other character between the ASCII lower and upper case ranges. +* Warnings are now issued during bad string conversions (e.g. Unicode characters which can't be represented as ASCII). +* You may notice extra debug text in the output log if this happens often in your code +* TArray::Append and TArray::Insert are now overloaded to allow the insertion of multiple elements at once. +* TSet is now accessed through operator [] instead of operator (). +* You can use now TObjectRange in the same way you use TobjectIterator for when you want to use C++11's ranged-for syntax. +* Example: for (UClass* Cls :TObjectRange()) +* Removed unused property flag CPF_AlwaysInit. +* Removed unused struct flag STRUCT_Transient. +* Added support for saving and loading FVector4 to config files using GConfig->SetVector4 and GConfig->GetVector4. +* Licensees using cultures (locales) other than the following languages will need to rebuild ICU's data to include that locale data: +* German - de, English - en, Spanish - es, French - fr, Hindi - hi, Italian - it, Japanese - ja, Korean - ko, Polish - pl, Portuguese - pt, Russian - ru, Swedish - sv, Chinese - zh +* DrawDebugHelpers: added support for displaying a Histogram of float values.Use FDebugFloatHistory to record samples, and DrawDebugFloatHistory to draw in game.Also available in blueprints. -#### ネットワーキング +#### Networking -* FFastArraySerializerItem 上の PreReplicatedRemove、PostReplicatedAdd、PostReplicatedChange の関数を修正し、所有している配列シリアライザも表すパラメータも持つようにしました。 -* bOnlyRelevantToOwner 設定をブループリントに公開しました。 +* Modified PreReplicatedRemove, PostReplicatedAdd, and PostReplicatedChange functions on FFastArraySerializerItem to also have a parameter representing the owning array serializer. +* Exposed bOnlyRelevantToOwner setting to blueprints. -#### アニメーション +#### Animation -* New:AnimInstance は、ブレンドスペースに対する **CalculateDirection** 関数を持つようになりました。 +* New:AnimInstance now has a **CalculateDirection** function for BlendSpaces. diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/4_1/ReleaseNotes_4_1.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/4_1/ReleaseNotes_4_1.KOR.udn index 1502793df7b5..4ea36e3bd809 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/4_1/ReleaseNotes_4_1.KOR.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/4_1/ReleaseNotes_4_1.KOR.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3367477 Title: 언리얼 엔진 4.1 릴리즈 노트 Crumbs:%ROOT%, Support/Builds Description: Availability:Public version: 4.1 +parent:Support/Builds order:1 [TOC(start:2 end:2)] @@ -313,7 +314,7 @@ We'd like to thank all of the amazing developers who contributed code in this re * **Unreal Editor Manual** * New: [Blueprint Cheat Sheet](Engine/Blueprints/UserGuide/CheatSheet) * New: [Light Propagation Volumes](Engine/Rendering/LightingAndShadows/LightPropagationVolumes) - * New: [Preview Shadows](Engine/Rendering/LightingAndShadows/Shadows#previewshadows) + * New: [Preview Shadows](Engine/Rendering/LightingAndShadows/Shadows) * New: [Pivot Painter](Engine/Content/Tools/PivotPainter) * New: [Mac Viewport Controls Quick Reference](Engine/UI/LevelEditor/Viewports/ViewportControls) * **Programming Guide** diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/4_2/ReleaseNotes_4_2.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/4_2/ReleaseNotes_4_2.KOR.udn index faa88d865f21..4597548dcd7a 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/4_2/ReleaseNotes_4_2.KOR.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/4_2/ReleaseNotes_4_2.KOR.udn @@ -321,7 +321,7 @@ GitHub 에서 작업중인 개발자들의 경우, 프로젝트를 윈도우 XP * 신규: 액터를 붙일 때, 액터 선택기를 사용하여 어느 액터를 어디에 붙일 지 선택할 수 있습니다. * 신규: 에디터에서 지오메트리 그리기시 "게임 뷰" 검사 기능을 추가했습니다. * 신규: 이제 **Alt + [ 또는 ]** 키로 트랜스폼 기즈모 크기를 조절할 수 있습니다 -* 신규: 이제 콜렉션이 로컬 유저 세팅에 따른 맞춤형 색상을 저장 및 표시합니다. +* 신규: 이제 컬렉션이 로컬 유저 세팅에 따른 맞춤형 색상을 저장 및 표시합니다. * 신규: 캐릭터 컴포넌트에 **Flat Bottomed** (하단 평면) 콜리전 옵션이 추가되었습니다. * 신규: 마켓플레이스에서 다운로드한 콘텐츠를 제거할 수 있는 옵션이 생겼습니다. * 신규: 콘텐츠 브라우저에서 드래그 앤 드롭으로 다수의 액터를 생성하는 작업이 한 번의 트랜잭션으로 되돌리기 가능합니다. @@ -521,7 +521,7 @@ GitHub 에서 작업중인 개발자들의 경우, 프로젝트를 윈도우 XP * 새로운 셰이더로 시작시 발생하던 크래시를 고쳤습니다. 리소스 초기화에 RHIClear 가 사용되고 있었습니다. * 분할화면 리플렉션 인바이언먼트 렌더링을 고쳤습니다. * 리플렉션 인바이언먼트가 껴졌을 때의 렌더링을 고쳤습니다. -* SM4 패쓰에 SSR 이 적용되던 것을 고쳤습니다. +* SM4 패스에 SSR 이 적용되던 것을 고쳤습니다. * 레이어드 리플렉션 캡처 관련 블렌딩 버그를 고쳤습니다. * LPV 가 꺼진 경우, LPV 가 비활성화되는 최적화가 전처럼 작동하도록 하는 최적화를 고쳤습니다 (섀도 맵 렌더링이 빨라집니다). * 캐릭터의 미리계산된 GI 적용시 사용되는 모든 라이트 프로브가 절반 밝기로 되던 버그를 고쳤습니다. diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/4_3/ReleaseNotes_4_3.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/4_3/ReleaseNotes_4_3.KOR.udn index 51f785a102ff..13228c16842b 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/4_3/ReleaseNotes_4_3.KOR.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/4_3/ReleaseNotes_4_3.KOR.udn @@ -195,7 +195,7 @@ Single Rotation Axis, 단일 회전축이라는 모드도 지원하는데, 수 ### 신규: Oculus Rift 업그레이드 * 최신 내용을 포함해서 Oculus SDK (0.3.3-pre.1 SDK) 로 업그레이드했습니다! * 풀 모션 트래킹 포함 Oculus Rift DK2 가 바로 지원됩니다. -* 새로운 직접 렌더링 패쓰와 타임 워프로, 디바이스의 반응 지연시간을 획기적으로 줄여줍니다. +* 새로운 직접 렌더링 패스와 타임 워프로, 디바이스의 반응 지연시간을 획기적으로 줄여줍니다. * Oculus Rift DK2 의 성능 시연을 위해 제작된 "Couch Knights" 샘플을 확인해 보세요. ![](OculusRiftUpgrade.png) @@ -407,7 +407,7 @@ Get Data Table Row 는 개별 컴포넌트 변수들로 나눌 수 있는 Row * 느린 태스크 진행상황 대화창으로 인해 발생하는 크래시를 고쳤습니다. * 블루프린트 메시 컴포넌트의 스태틱 라이팅을 고쳤습니다. * 빌드 스케일을 높일 때 **ConvexElems ** 위치가 업데이트되도록 **RescaleSimpleCollision ** 을 고쳤습니다 (기존에는 버텍스만 스케일 조절했습니다). -* 에디터의 '패쓰 빌드' 옵션을 수정했습니다. +* 에디터의 '패스 빌드' 옵션을 수정했습니다. * 컴파일러 에러 수정 및 자잘한 최적화가 있었습니다. * 콘텐츠 브라우저 소스 콘트롤 상태 델리게이트가 공유 포인터 시맨틱을 사용하도록 수정했습니다. * 비헤이비어 트리 버전비교가 거꾸로 나오던 것을 고쳤습니다. @@ -494,7 +494,7 @@ Get Data Table Row 는 개별 컴포넌트 변수들로 나눌 수 있는 Row * ShowLayer 명령 추가 - 레이어의 메시 표시여부를 토글시킵니다. * 스태틱 / 스테이셔너리 스카이라이트에 1회 반사되는 디퓨즈 GI 를 라이트매스로 계산합니다. * 반투명 머티리얼이 스테이셔너리 라이트의 그림자를 받습니다. -* 모바일 렌더링 패쓰에 MSAA 가 지원됩니다. +* 모바일 렌더링 패스에 MSAA 가 지원됩니다. * 클리어 코트 셰이딩 모델을 추가했습니다. * 반투명 관련 굴절 순서를 변경했습니다 (독립 반투명이 아닌 것이 이제 굴절되어 모양이 바뀔 수 있습니다). * LensFlareIntensity 프로퍼티의 기본 세팅을 0 (꺼짐)으로 변경하여 퍼포먼스를 향상시키고 기본 모양새를 깔끔하게 만들었습니다. 1 로 설정하면 예전 방식을 살립니다. @@ -688,7 +688,7 @@ Get Data Table Row 는 개별 컴포넌트 변수들로 나눌 수 있는 Row * 완전 미지원 및 문서화되지 않은 프로토타입이라 사용에 극심한 주의가 요구되며, 제작 단계에서는 사용하지 마십시오. * (언리얼 콜리전 채널/필터링을 포함한) 콜리전 감지 및 반응, 시뮬레이션, 레이 캐스트가 구현되었습니다. * 논-제로 익스텐트 쿼리, 스윕 테스트, 오버랩 테스트는 아직 구현되지 않았습니다. -* 다양한 콜리전 루틴을 정리하여 가급적 공용 패쓰를 통합시키고, 가능한 경우 PhysX 종속성을 감소/통합시켰습니다. +* 다양한 콜리전 루틴을 정리하여 가급적 공용 패스를 통합시키고, 가능한 경우 PhysX 종속성을 감소/통합시켰습니다. * UStaticMeshComponent 뿐만이 아닌 어떠한 종류의 컴포넌트에 대해서도 연관된 애셋을 제공하도록 FBodyInstance 에 대한 디버그 텍스트를 일반화시켰습니다. * 다양한 내부 스윕/오버랩/쿼리 헬퍼 메소드 (Geom*) 가 이제 PhysX 전용이 아닌 언리얼 유형을 받습니다. diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/4_6/ReleaseNotes_4_6.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/4_6/ReleaseNotes_4_6.KOR.udn index 98096230b921..27a1ad2e61a1 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/4_6/ReleaseNotes_4_6.KOR.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/4_6/ReleaseNotes_4_6.KOR.udn @@ -120,7 +120,7 @@ Alex Silkin (alexSilkin), alwei, Allegorithmic, Artem V. Navrotskiy (bozaro), Ce * 터레인, 하이 퀄리티 캐릭터 머티리얼, 고급 포워드 셰이딩 머티리얼과 같은 레이어 머티리얼의 품질 향상에 정말 중요한 부분입니다. -* DirectX 11 및 콘솔은 한 번에 128 개의 텍스처를 지원하지만, (윈도우나 맥의) OpenGL 렌더링 패쓰는 머티리얼당 텍스처가 여전히 13 개 까지로 제한됩니다. 이 제한을 넘는 경우 셰이더가 GL 컴파일에 실패합니다. +* DirectX 11 및 콘솔은 한 번에 128 개의 텍스처를 지원하지만, (윈도우나 맥의) OpenGL 렌더링 패스는 머티리얼당 텍스처가 여전히 13 개 까지로 제한됩니다. 이 제한을 넘는 경우 셰이더가 GL 컴파일에 실패합니다. ###### 스칼라 및 벡터 파라미터 기본값 실시간 미리보기 @@ -319,7 +319,7 @@ Alex Silkin (alexSilkin), alwei, Allegorithmic, Artem V. Navrotskiy (bozaro), Ce **슬레이트에서의 폰트** * C++ 기반 슬레이트 스타일 세트의 기존 폰트 코드도 정상 작동하나, 스타일 세트가 컴포짓 폰트의 이점을 활용하도록 업데이트해 보는 것도 좋습니다. * C++ 슬레이트 코드에서 컴포짓 폰트를 처리할 때는 폰트 애셋보다는 FStandaloneCompositeFont 를 사용할 것을 추천합니다. -* 슬레이트 스타일 세트에 포함된 폰트 오브젝트가 가비지 콜렉터에 보이지 않기 때문입니다. 폰트 애셋을 직접 사용하면 FGCObject 같은 것을 사용해서 외부 레퍼런스를 직접 관리해야 합니다. +* 슬레이트 스타일 세트에 포함된 폰트 오브젝트가 가비지 컬렉터에 보이지 않기 때문입니다. 폰트 애셋을 직접 사용하면 FGCObject 같은 것을 사용해서 외부 레퍼런스를 직접 관리해야 합니다. **캔버스에서의 폰트** * 캔버스는 양쪽 폰트 애셋 캐시 유형을 모두 지원하나, 저희 툴 일부에 대한 현지화 지원을 개선시키기 위해서입니다. diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/January/ReleaseNotesJanuary2014.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/January/ReleaseNotesJanuary2014.JPN.udn index 2c77e77b0b8e..1eedc3825ae3 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/January/ReleaseNotesJanuary2014.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/January/ReleaseNotesJanuary2014.JPN.udn @@ -1,8 +1,10 @@ -Title:2014 年 1 月リリースノート +INTSourceChangelist:3367470 +Title:2014 年 1 月リリースノート Crumbs:%ROOT%, Support/Builds Description: Availability:Licensee -Template:ReleaseNotes.html +Parent:Support/Builds +Order:-2 [TOC(start:2 end:2)] @@ -12,7 +14,7 @@ Template:ReleaseNotes.html [REGION:simpletable] | アイテム | 情報 | | ---- | ---- | -| **Labels** | [INCLUDE:#labels] | +| **ラベル** | [INCLUDE:#labels] | | **Built from Changelist #** | (//depot/UE4-QA/Promotable-CL-1986836) | | **Branched from Changelist #** | (//depot/UE4/Promoted-CL-1973917) | | **Visual Studio Version** | Microsoft Visual Studio 2012 Version 11.0.60610.01 Update 3 | @@ -30,20 +32,20 @@ QA_APPROVED_UE4_BUILD_MINIMUM ## 重要情報 * 現時点のエンジン開発ロードマップ: [UE4 Roadmaps](https://udn.unrealengine.com/questions/topics/roadmap.html) - * 修正されたバグ: [UE4 Fixed Bugs January 2013](UE4_Fixed_2014_January.xlsx) - * 周知の問題: [UE4 Known Issues January 2013](UE4_Bugs_2014_January.xlsx) + * 修正されたバグ: [UE4 Fixed Bugs January 2014](UE4_Fixed_2014_January.xlsx) + * 周知のバグ: [UE4 Known Issues January 2014](UE4_Bugs_2014_January.xlsx) -##主な新機能 +## 主要な新機能 ####ブループリント -* **Format Text Node** +* **Format Text ノード** * 新しい Format Text ノードがブループリントに追加されました。 ![](Support\Builds\ReleaseNotes\2014\January\FormatTextNode01.png) - * 「Format」テキストはリテラルあるいはピン接続が可能です。リテラルを使用すると、フォーマット用の引数が自動生成されます。 + * 「Format」テキストはリテラルあるいはピン接続が可能です。リテラルとして使用すると、フォーマットのために引数が自動生成されます。 ![](Support\Builds\ReleaseNotes\2014\January\FormatTextNode02.png) @@ -51,7 +53,7 @@ QA_APPROVED_UE4_BUILD_MINIMUM ![](Support\Builds\ReleaseNotes\2014\January\FormatTextNode003.png) - * 「Format」ピンは接続された場合、変数のため解読は不可能です。この場合、ピンを自分で追加し、可能性のある引数に因んだ名前を付けます。このように、Format Text ノーの使用設定は、複数の可能性に対して行うことができます。引数が Format の引数に一致すると、与えられた情報を利用します。 + * 「Format」ピンは接続された場合、変数のため解読は不可能です。この場合、ピンを自分で追加し、可能性のある引数に因んだ名前を付けます。このように、Format Text ノードの使用設定は、複数の可能性に対して行うことができます。引数が Format の引数に一致すると、与えられた情報を利用します。 ![](Support\Builds\ReleaseNotes\2014\January\FormatTextNode04.png) @@ -97,19 +99,19 @@ QA_APPROVED_UE4_BUILD_MINIMUM * **シーン アウトライナーにおけるアクタの可視性** * 各アクタの脇に表示される目のアイコンを使って、シーン アウトライナーからアクタの可視性の切り替えが簡単にできるようになりました。 + ![](Support\Builds\ReleaseNotes\2014\January\ActorVisibility.png) - * **レベル ビューポート** - * レベル ビューポートで、例えばカメラを選択すると、カメラから見えるものを現在のビューポートの [Picture-in-Picture] ボックスでプレビューすることができます。カメラの選択を解除すると、プレビューがなくなります。 + * レベル ビューポートで、例えばカメラを選択すると、カメラから見えるものを現在のビューポートの [Picture-in-Picture] ボックスでプレビューすることができます。カメラの選択を解除すると、プレビューされなくなります。 - * レベル ビューポートの Actor Previews にこれらに対するボタンを追加したので、別のオブジェクトを選択しても表示されたままになります。 + * レベル ビューポートの [Actor Previews] にこれらのボタンを追加したので、別のオブジェクトを選択しても表示されたままになります。 ![](Support\Builds\ReleaseNotes\2014\January\LevelViewport01.png) * 見ての通り、これは加算なので、ピンしたプレビューに加えて、選択した他のプレビュー アクタも見ることができます。 - * この機能の便利な使い方としては、カメラ視点のプレビュー中に、 Matinee や複数のビューポートを使用せずにカメラショットによるアクタの移動があるでしょう。 + * 例えば、カメラ視点のプレビュー中に、マチネや複数のビューポートを使用せずにカメラショットによるアクタの移動にこの機能を使うと便利です。 ![](Support\Builds\ReleaseNotes\2014\January\LevelViewport02.png) @@ -132,8 +134,8 @@ QA_APPROVED_UE4_BUILD_MINIMUM 使用するキューブマップを手書きのコードによって指定することもできます。 ![](Support\Builds\ReleaseNotes\2014\January\CubeMap.png) - * これまでは、Lightmass の環境色を通過するスカイ ディフーズに異なる定数を与えながら、スカイを反射させる Ambient Cubemap を選択しなければなりませんでした。 + * これまでは、Lightmass の環境色を通過するスカイ ディフーズに異なる定数カラーを与えながら、スカイを反射させる Ambient Cubemap を選択しなければなりませんでした。 * Sky Light は完全に環境色に変わり、やがては Ambient Cubemap に変わります。 @@ -141,7 +143,7 @@ QA_APPROVED_UE4_BUILD_MINIMUM **ベークされたシャドウイング** - * 現在サポートされている Sky Light は Stationary Mobility のあるバージョンのみです。つまり、 Lightmass からベークされたシャドウイングがあります。 + * 現在サポートされている Sky Light は、Stationary Mobility のあるバージョン、つまり Lightmass からベークされたシャドウイングのみです。 * レベル内に Sky Light を置いたら、ベークされたシャドウイングを取得するために再度ライティングをリビルドする必要があります。 @@ -165,14 +167,14 @@ QA_APPROVED_UE4_BUILD_MINIMUM * プロジェクトでその機能を使用したい場合は、同じ変更をプロジェクト設定で行うことができます。 -## 新機能の追加 +## 新規追加 #### エディタとツール -* 1 つのフィルタを分離し有効にするために、新しいアセットブラウザ フィルタ コンテクストメニューを入力します。 +* 1 つのフィルタを分離し有効にするために、新しいアセットブラウザ フィルタ コンキテクスト メニューを入力します。 * アクティブなフィルタのリストの中の 1 つのフィルタ上にコンテクスト メニューを表示させて、[enable this only: ``] を選択することでアクティベートします。 -* LODs タイトルを折りたたんでも、LOD Distance が表示されるようになりました。 +* LOD のタイトルを折りたたんでも、LOD Distance が表示されるようになりました。 * プロパティ マトリックス ビューでサポートするアセットに対し [Asset picker] ボタンが表示されるようになりました。 -* 選択されたグループ化されたアクタ上を Ctrl +クリックすれば、グループ全体の選択が解除されるようになりました。 +* 選択されたグループ化されたアクタ上を Ctrl +クリックすると、グループ全体の選択が解除されるようになりました。 * フィルタ メニューの一番下にフィルタリセット用のボタンが追加されました。 * サブメニュー入力上でボックスとアクションが切り替えられるようになり、サブメニューを使用するための CB フィルタ メニューが修正されました。 * Dirty maps/assets が名前の横のドックタブにアスタリスクを表示するようになりました。 @@ -182,7 +184,7 @@ QA_APPROVED_UE4_BUILD_MINIMUM * サウンド ノードのパレットがサウンドキュー エディタに追加されました。 * マテリアル エディタ 表現式と関数リストが 1 つのパレットにまとめられました。 * サウンドキュー エディタの Sound ノードをダブルクリックするとそのノードが再生されます。 -* マテリアル関数がマテリアル エディタの右クリック コンテクスト メニューに追加されました。 +* マテリアル関数がマテリアル エディタの右クリック コンテキスト メニューに追加されました。 * Material ノードの Particle Direction、Particle Speed、Particle Position、Particle Relative Time がメッシュ パーティクルで機能するようになりました。 * UTF-8 のサポートが Perforce プラグインに追加されたので、ユニコード サーバーが使用可能になりました。 * インスタンス化されたスタティック メッシュ コンポーネントが [Blueprint Components] ビューで編集可能になりました。 @@ -225,7 +227,7 @@ QA_APPROVED_UE4_BUILD_MINIMUM * スカイライト コンポーネントは距離ジオメトリを自動的にキャプチャし、それをライティングとしてシーンに適用します。 * Lightmass はベント法線アンビエント オクルージョンをベークし、それにより指向性シャドウイングが生じます。 * この機能は新しく、まだ完全には機能していません。例えば、透過アイテムにはキャラクター シャドウが全く適用されません。 -* Particle light モジュールを透過アイテムに影響するように選択することができます。 +* Particle light モジュールを透過アイテムに影響するようにオプトインすることができます。 * 全ての間接ライティングにマテリアル アンビエント オクルージョン出力が適用され、ボリュメトリック パーティクルに有益です。 * **事前計算されたビジビリティの改善点** * より完全に可能性のある再生エリアをカバーする新しいセル配置ヒューリスティックが追加されました。ただしビルド時間は増えました。 @@ -281,7 +283,7 @@ QA_APPROVED_UE4_BUILD_MINIMUM * マニフェストが JSON フォーマットになり、人間にとって読解が、またコンピュータにとってはパースがしやすくなりました。 * 診断を変更しやすいように、ホット リロードのコンフリクトは生成されたヘッダ ファイルの横に書き込まれます(.generated.h.conflict ファイルとして)。 * UnrealHeaderTool が UTF-8 BOMs のファイルをサポートするようになりました。 -* Play-In-Editor(PIE) 用に複製されると、プロパティがシリアル化のみされるように、NonPIETransient プロパティ指定子が追加されました。 +* Play-In-Editor(PIE) 用に複製されると、プロパティがシリアル化のみされるように、NonPIETransient プロパティ指定子が追加されました。 * 追加のパッケージ ファイル位置を指定できるように -pakdir=dir コマンドライン パラメータが追加されました。 * ゼロ エンジン バージョンのサポート - エンジンは 0 エンジン バージョン (ローカル ビルド) パッケージのロードが可能になりました。 * NULL (None) アクティブ クラス リダイレクトのサポート @@ -315,237 +317,237 @@ QA_APPROVED_UE4_BUILD_MINIMUM ## アップグレード ノート #### エディタとツール -* Landscape ES2 :ランドスケープ UV が 2 から 3 に増え、LocalVertexFactory と同じになりました。 -* Collision プロパティが正確に複製されるようになりました。 -* サブレベルはレベルに追加される時、ダーティとマークされなくなりました。 -* WorldSettings ラベルが非表示になりました。 -* [Collections] ボタンをクリックするとソース コントロール ステートが更新されるようになりました。 -* ブループリントをデバッグする際、新規の PIE ウィンドウがグレーアウトしなくなりました。 -* [FBX Import] オプションが記憶されるようになりました。 -* 幾つかのマテリアルで不足しているツールチップを追加しました。 -* コリジョン チャネルがビルドされると コリジョン プロファイルがアップデートされます。 -* アンロードされたマップに属するアセットはメニュー アセット ピッカーにより排除されるようになりました。 -* Collections は再度保存するようになりました。 -* 「Press Escape」メッセージは自動保存の場合にのみ表示されます。 -* LocalizeError の使用を廃止しました。 -* カラーテーマのアルファ値が使用中のカラーピッカーのタイプに応じて正確に表示されるようになりました。 -* DestructibleMesh プロパティが折りたたまれなくなりました。 -* non-code などソリューションが欠けている場合、Debug はパッケージ オプションから削除します。 -* 復元された名前とツールチップをアセット エディタに保存します。 -* Cascade Module の警告がダイアログから通知に変更されました。 -* UFortUIFeedbackBank プロパティへの修正が期待通りに機能しています。 -* プロパティ マトリックス欄の幅がオブジェクト選択の間で維持されるようになりました。 -* アセットと同期すると、ContentBrowser アセット ビューがキーボード フォーカスを受け取るようになりました。 -* ContentBrowser ビューモードのレイアウトが永続的になりました。 -* 同期したアセットにロックされたコンテンツ ブラウザが開かないようにしました。 -* ローカルおよびワールド座標システムで不足している小さなアイコンが追加されました。 -* 作成中に名前の変更によりフォーカスを失っても、コレクションが削除されなくなりました。 -* コンテンツ ブラウザ カウンタの「アセット」を「アイテム」へ名前変更しました。 -* ユーザーがコンパイラを持っていない場合、[add code to project] オプションは無効化されます。 -* [invalid collision] ダイアログを通知に置き換えました。 -* スプライト カテゴリのローカリゼーションの処理方法をリファクタリングします。 -* コレクションをデフォルトで展開表示できるようになり、リサイズが可能になりました。 -* 保存メッセージを Matinee に言い換えました。 -* 不足していた小さな [Phat] アイコンを追加しました。 -* タブ上にアセットをドラッグすると、その後すぐにアクティブになるようになりました。 -* キーボードのショートカットで作成された Copy/Pasting ノードがクラッシュしなくなりました。 -* 環境設定のエクスポート時にレイアウトも保存されるようになりました。 -* PIE の自動再コンパイル ブループリントのオプションが [Editor Preferences] から制御可能になりました。 - * カスタム仕様の *.ini files referencing Kismet.AutoRecompileOnPIE は全て関連する EditorUserSettings ini の /Script/UnrealEd.LevelEditorPlayInSettings.AutoRecompileBlueprints を使用するように変更してください。 -* ALevelGridVolume アクタが削除されました。 -* GetOverlappingActors は呼び出されてもアクタを返さなくなりました。 -* ブループリント関数の位置に対し Position と Translation が変更されました。これにより影響を受ける C++ 関数があります。 - * UPrimitiveComponent::AddImpulseAtPosition() はUPrimitiveComponent::AddImpulseAtLocation() となります。 - * UPrimitiveComponent::AddForceAtPosition() は UPrimitiveComponent::AddForceAtLocation() となります。 - * UMovementComponent::ConstrainPositionToPlane() はUMovementComponent::ConstrainLocationToPlane() となります。 +* Landscape ES2 :Landscape UV increase from 2 to 3 to be same as LocalVertexFactory. +* Collision properties are now duplicated correctly. +* Sub-levels no longer get marked as dirty when added to the level. +* WorldSettings label is now hidden. +* Collections button now updates it's source control state when clicked. +* New PIE windows no longer get greyed out when debugging blueprints. +* FBX Import options are now remembered. +* Added missing tooltip for some material properties. +* Update the Collision Profile when the Collision Channels are built. +* Menu asset picker now excludes assets which belong to unloaded maps. +* Collections now save again. +* "Press Escape" message now only appears when autosaving. +* Removed LocalizeError usage. +* Alpha value of color themes now appears correctly depending on the color picker type being used. +* DestructibleMesh property is no longer collapsed. +* Remove 'Debug' as an packaging option if solution is missing i.e. non-code. +* "Save" name and tooltip restored in asset editors. +* Changed Cascade Module warning from a dialog to a notification. +* Modifications to UFortUIFeedbackBank properties now work as expected. +* Property matrix column widths are now preserved between object selections. +* ContentBrowser asset view now recieves keyboard focus when syncing to assets. +* ContentBrowser view modes now have a persistent layout. +* Prevent opening locked content browsers to sync assets. +* Added missing small icon for local and world coordinate system. +* Collections are no longer removed, when creating, if the rename loses focus. +* Renamed 'asset' to 'item' in the content browser counter. +* Disable the 'add code to project' option when the user has no compiler. +* Replaced 'invalid collision' dialog with notification. +* Refactor how the sprite category localization is handled. +* Collections now appear expanded by default, and can be resized. +* Save message reworded to say Matinee. +* Adding missing small Phat icons. +* When dragging an asset over a tab, it'll now become active after a short period. +* Copy/Pasting nodes created with keyboard shortcuts no longer crashes. +* Layout is now also saved when exporting preferences. +* The option to auto recompile blueprints on PIE is now controllable from Editor Preferences. + * Any custom *.ini files referencing Kismet.AutoRecompileOnPIE should be changed to use /Script/UnrealEd.LevelEditorPlayInSettings.AutoRecompileBlueprints in the relevant EditorUserSettings ini instead. +* ALevelGridVolume actor was removed. +* GetOverlappingActors no longer returns the actor the call is made on. +* Changed Position & Translation to Location in Blueprint functions; impacts several C++ functions: + * UPrimitiveComponent::AddImpulseAtPosition() becomes UPrimitiveComponent::AddImpulseAtLocation() + * UPrimitiveComponent::AddForceAtPosition() becomes UPrimitiveComponent::AddForceAtLocation() + * UMovementComponent::ConstrainPositionToPlane() becomes UMovementComponent::ConstrainLocationToPlane() #### レンダリング -* テキストレンダリングでアクタを垂直のアライメントに平行移動させる際の計算エラーが修正されました。この操作により、正しくない位置に置かれてしまうテキストが発生する恐れがあります。その場合は手作業での修正が必要になります。 -* **エンジンの拡張機能** - * GetRenderingDetailMode が Kismet へ追加されました。 - * GPUIndex が HardwareSurvey へ追加されました。 - * エンジン拡張機能に磨きがかかりました。 - * cvar が拡張オプションとして使用できる場合、ECVF_Scalability がドキュメントに追加されました。 - * ブループリントの GetRenderingMaterialQualityLevel を追加し、ヘルプを追加し、別のヘルプをクランプしました。 - * r.CompileShadersForDevelopment を追加して、設定が 0 の時は早めの出荷用ビルドが出来るようになりいました (未完成の機能のため、手動でアクティベートする必要があります)。 - * MaterialQualityLevel を拡張性設定に追加しました。JonL の提案は 0/1/1/1 ですが、コンテンツによっては 0/0/1/1 の場合もあります。 - * Fortnite に対し非常に低いスペックのレンダリング負荷に調整し、UI Blur バックグラウンドが無効化されました。 - * r.earlyzpass はモードが 2 の時 (画面上でマスクされているか小さい場合) 、移動しない全てのオブジェクトをレンダリングするようになりました。 - * PF_R8G8 UNORM テクスチャ フォーマットが追加されました。 -* **ポストプロセス** - * 自動露光の最低速度をクランプして、人間がこのパラメータで自動露光を無効化してしまわないようにしました。 - * FastBloomThreshold は目立っていたので再度有効化しました。 - * Toe Factor を削除しました。トーンマッパではどのみち使用しませんし、古いトーンマッパはもう存在しません。 - * グラフをより見やすくするために、グラフへのデバッグ エクスポートが追加されました (yWorks を使用) r.CompositionGraphDebug は好くリーションショット フォルダにファイルをエクスポートします。 - * ビデオ オプションのネイティブなフルスクリーンを再度有効化しました。 - * スペキュラを切り離すために、アルファシーンカラーのアルファ チャンネルを利用して実験的な機能としてスクリーン空間のサブサーフェス スキャッタリングを採用しました。大部分のレンダリング パスには最少限のコストが発生しますが、32 ビット フォーマットの仕様時は、実験的なスクリーン空間のサブサーフェス スキャッタリングを有効にしません。当社はスクリーン空間のサブサーフェス スキャッタリングを有効化して使用する予定であり、それが高品質には必要です。スペキュラのあるサブサーフェス マテリアルについては r.SSSSS 150 をご覧ください。 - * (メインとレンダリング スレッド) cvar の読み込み時、パフォーマンスをあげるためにコンソール変数の vars をタイプしました。 - * インターフェースが DrawDenormalizedQuad() に改善され、名前が DrawRectangle() となり、デフォルトで従来型のクワッドを使用して、トライアングルとなることが可能になりました。 - * vis SceneDepth@0 を使用して EarlyZPass コンテンツの可視化が可能になりました。 +* An error in the calculation of text render actor vertical alignment transforms has been fixed.This may potentially result in some text being incorrectly position, which will need manually correcting. +* **Engine Scalability** + * Added GetRenderingDetailMode to Kismet. + * Added GPUIndex to HardwareSurvey. + * More polish on engine scalability feature. + * Added ECVF_Scalability to document if a cvar can be used as scalability option. + * Added Blueprint GetRenderingMaterialQualityLevel, added help and clamped another one. + * Added r.CompileShadersForDevelopment to allow for faster shipping build when set to 0 (needs to be manually activated, unfinished feature). + * Added MaterialQualityLevel to scaleability settings - JonL suggested 0/1/1/1, could have been 0/0/1/1 - depending on content. + * Optimized very low spec rendering cost for Fortnite, disables UI Blur background. + * r.earlyzpass now renders all non moving objects if in mode 2 (masked or small on screen). + * Added PF_R8G8 UNORM texture format. +* **Post Processing** + * Clamped minimal speed for eye adaptation to not have people disabling eyeadaptation through this parameter. + * Reenabled FastBloomThreshold as this was more noticable there. + * Removed toe factor - isn't used in new tonemapper anyway - old tonemapper doesn't exist any more. + * Added debug export to the graph for much nicer readble graphs (using yWorks) r.CompositionGraphDebug exports the files to the screenshots folder. + * Reenabled native fullscreen for video options. + * Experimental feature work: made screenspace subsurface scattering using alpha scene color alpha channel to separate out specular, very minor cost for most passes and if using a 32bit format we don't have the enabled.We intend to use enable ScreenSpace subsurface scattering and that is needed for high quality, see r.SSSSS 150 on subsurface material with a specular. + * Typed console variables vars for better performance when reading cvars (main and render thread). + * Improved interface to DrawDenormalizedQuad(), now renamed to DrawRectangle(), by default using classic quad, can be a triangle. + * Allow visualization of EarlyZPass content using "vis SceneDepth@0" #### ブループリント -* ネストされたブループリント コンポーネントは、親の可動性の方が大きい場合、可動性を変更させる場合があります。 - * 親よりも可動性が低いサブ コンポーネントにフラグが付かないようになりました。 -* ブループリントのゲーム コンポーネントは、エディタのみのコンポーネント下にすでにネストされている場合は、ネストされません (あるいはルートの場合はスワップされます)。 - * ゲーム コンポーネントがエディタのみのコンポーネント化にネストしないようになりました。 +* Nested blueprint components may have their mobility altered if their parent is more mobile than they are. + * We no longer allow sub-components to be flagged with less mobility than their parent. +* Blueprint game-components will be unnested (or swapped, if the root) if they were previously nested under an editor-only component. + * We no longer allow game-components to be nested under editor-only ones. #### ゲームプレイとフレームワーク -* ナビゲーション システムの API を const FNavigationQueryFilter* から TSharedPtr`` を使用するように切り替えました。 -* ネイティブ コードで作成された InputComponent 結合が動的結合ではなく UObject 結合を使用するようになりました。 - * BIND_AXIS と BIND_ACTION は変換の便宜上残されています。いずれ削除されますので使用しないでください。 - * その代わりに InputComponent 上の BindAxis と BindAction 関数を使用すべきです。BindKey と BindTouch も追加されました。 -* MinCompressedDurationGame/Editor が削除されました。置き換えに関する詳細は、新機能の SoundGroups をご覧ください。 +* Switched navigation system's API from using const FNavigationQueryFilter* to TSharedPtr`` +* InputComponent bindings made in native code now use UObject binding instead of dynamic binding. + * BIND_AXIS and BIND_ACTION should no longer be used and, while they remain currently for ease of conversion, they will be removed in the future. + * Instead BindAxis and BindAction functions on InputComponent should be used.BindKey and BindTouch have also been added. +* MinCompressedDurationGame/Editor has been removed.See new feature SoundGroups for details on replacement. #### コア -* ブループリントに格納されているクラスは notplaceable ベースを継承する場合、notplaceable へ変換されるようになりました。 - * 以前であればアサートしました。 -* TIndirectArray は TArray を継承しなくなりました。 - * TIndirectArray から TArray へキャストするコードは失敗します。 - * エクスポーズされていない TArray 関数を使うコードは変更が必要です。例えば GetData() は GetTypedArray() となります。 -* MAX_PATH のオーバーフローを削減するために同じパス名は短縮するようにしました。 - * これにより、ファイルが特定の場所にあることを期待するナビゲーションやバッチ ファイルが影響を受けます。 - * 特に、Intermediate/BuildData/Include は Intermediate/Build/Inc となりました。 -* TWeakObjectPtr は、UObject から派生するタイプでインスタンス化される静的アサートになりました。 - * コンパイラはタイプがもう UObject ではないと想定するので、TWeakObjectPtrs がどこで作成されようとフルクラス定義が求められます。 -* begin() と end() がコンテナ メソッドではなくなりました。 - * これらの関数は純粋に ranged-for サポートに追加されました。ユーザー コード向けではありません。Ranged-for は代替システムとして使用しても機能します。 - * UE コンテナ上で .begin() や .end() を使用するコードは ranged-for スタイルや古い CreateIterator スタイルのイタレーションを使用するように変換してください。 -* UnrealHeaderTool は、パースできないデフォルト引数を認識するとエラーを出すようになりました。 - * 例えば、以下のようなコードは NULL を使うように修正が必要です。 +* Classes saved in blueprints are now converted to notplaceable if they inherit a notplaceable base. + * Previously it would assert. +* TIndirectArray no longer inherits TArray. + * Any code which does TIndirectArray->TArray casts will now fail. + * Code which uses non-exposed TArray functions will need changing, e.g. GetData() should now be GetTypedArray(). +* Some pathnames have been shortened to try and reduce MAX_PATH overflows. + * This may affect navigation or batch files which expect files to be in particular places. + * Notably, Intermediate/BuildData/Include is now Intermediate/Build/Inc. +* TWeakObjectPtr now static asserts that it is being instantiated with a UObject-derived type. + * This will require that a full class definition wherever TWeakObjectPtrs are constructed, as the compiler won't just assume that your type is a UObject any more. +* begin() and end() are no longer container methods. + * These functions were added purely for ranged-for support; they were not intended to be used in user code.Ranged-for will still work as it uses an alternative system. + * Any code using .begin() or .end() on UE containers should be converted to use ranged-for or the older CreateIterator-style of iteration. +* UnrealHeaderTool will now throw an error when it encounters a default argument that it can't parse. + * Code like this, for example, will need to be modified to use NULL: * `UFUNCTION(BlueprintCallable, Category="SomeCategory")` * `void Func(UObject* Obj = nullptr)` * `{` * `}` -* ゲーム ターゲットとして時々使用されてきた bCompileMonolithicBinary グローバル変数が削除されました。 - * その代わり、プログラムの TargetRules ファイル (MyGame.Target.cs) の ShouldCompileMonolithic() をオーバーライドします。 - * 必要であれば、コマンドライン引数を使ってオーバーライドすることもできます (-modular、 -monolithic、MONOLITHIC_BUILD=1)。 -* Unreal Build ツールから Fast Iteration Mode が削除されました (不完全な機能)。 -* デフォルトの最小 Windows API (WINVER) が 0x600 にバンプされました (Windows Vista 以降)。 - * Windows XP をターゲットにしたい場合は、 UEBuildWindows.SupportWindowsXP=_true_ に設定します。 - * Windows XP をターゲットにする場合、弊社では WINVER 0x502 (XP SP3) を使用します。 - * Windows XP サポートはまだ進行中ですが、今後のビルドにおいてサポートを付けることを確約します。 +* Eliminated bCompileMonolithicBinary global variable which was sometimes used by game targets + * Instead, override ShouldCompileMonolithic() in your program's TargetRules file (MyGame.Target.cs). + * You can still use command-line arguments to override this if needed (-modular, -monolithic, or MONOLITHIC_BUILD=1). +* Removed "Fast Iteration Mode" from Unreal Build Tool (incomplete feature). +* Default minimum Windows API (WINVER) was bumped to 0x600 (Windows Vista or higher). + * If you want to target Windows XP, set UEBuildWindows.SupportWindowsXP=_true_. + * When targeting Windows XP, we use WINVER 0x502 (XP SP3). + * Windows XP support is a work-in-progress, but we are committed to supporting it in a future build. #### プラットフォーム -* 全てのデバイス プロファイルをエディタに戻しています。 -* Removed the DeviceProfiles.ini を削除し、その他のエンジン コンフィグ ファイルと同じコンフィグ階層を使うように変換しました。Base->Default->Saved -* コンフィグ オプションを使用すると指定してしまうところに Texture Content Streaming が CVar を使えるように更新されました。 -* このプロパティを戻しています。 -* Device Profile の重複しているプロパティを削除しました。 -* デバイス プロファイル設定を CVars が早く初期されるに更新し、Device Profile Blueprints を削除しました。この結果、選択ロジックを実行するデバイス プロファイル プラグインが作成されました。 -* デフォルトへの保存が更新されたので、正しい記述を使用して配列が書き込まれるようになります。 -* インポート後に保存するように設定エディタを更新しました。 +* Putting all device profiles back in the editor. +* Removed the DeviceProfiles.ini and converted this to use the same config hierarchy as other engine config files.Base->Default->Saved +* Updated the Texture Content Streaming to use allow usage of CVar where we would otherwise have specified that we use a config option. +* Putting back this property. +* Removed Device Profile redundant properties. +* Updated the device profile setup to allow CVars to be initialized eary and removed Device Profile Blueprints, This has resulted in the creation of device profile plugins which run selection logic. +* Updated save to defaults, so that array writes are using correct syntax. +* Updated the settings editor to save after importing. * **iOS** - * バーチャル ジョイスティックがタッチスクリーン デバイスに変更されました。アサートが使われるようになりました。ジョイスティックを無効にしたい場合は、 Engine.ini の「[MobileSlateUI]」セクションの InitialTouchInterface ini 設定をオーバーライドします。 - * デバイス検出と UFE/UAT からの展開 / 起動を可能にするために、Unreal Launch Daemon が Messaging で機能するように修正されました。 + * Virtual joysticks have changed for touchscreen devices.They now use an asset.If you want to disable the joysticks, override the InitialTouchInterface ini setting in the [MobileSlateUI] section of Engine.ini + * Unreal Launch Daemon has been fixed to work with Messaging to allow for device discovery and deploying/launching from UFE/UAT. * **Unreal Frontend** - * Unreal Frontend (UFE) でプラグインを使用できるようになりました。 - * static ips が可能なようにメッセージングを更新します。 - * PC 以外のサブネット上でデバイスまたはセッションを確認するには、以下の操作を行います (これらのステップは PS4 を確認するためにも必要となります)。 - * Engine/Programs/UnrealFrontend/Saved/Config/Windows/Engine.ini を生成するために UFE を再度実行します。 - * Engine.ini を編集し [/Script/UdpMessaging.UdpMessagingSettings] に追加します。 + * Unreal Frontend (UFE) can now utilize plugins. + * Update to messaging to allow for static ips. + * To see a device or session on a subnet different than the PC, do the following (these steps are also needed to see the PS4): + * Run UFE once to generate the Engine/Programs/UnrealFrontend/Saved/Config/Windows/Engine.ini + * Edit Engine.ini and add to the [/Script/UdpMessaging.UdpMessagingSettings] * StaticEndpoints=:6666 - * デバイスを 1 つ以上を追加するには、複数回ラインを追加します。 - * iOS の場合は、Unreal Launch Daemon をデバイスにプッシュして実行し、静的 IP アドレスを上記の通り追加するとデバイスが見えるようになります。 - * PS4 の場合は、上記の IP アドレスを追加するとキット上でセッションを確認できます。 - * XB1 でテストされていませんが、機能するはずです。 - * ランチャー ログのコピー / 保存機能が追加されました。 - * UFE に Quick Launch が追加されました。 - * Quick Launch は選択したデバイス上のプロジェクトを即時展開、起動します。 - * -development は UFE コマンドライン上で指定されると、Quick Launch が起動前にプロジェクトもビルドします。 + * To add more than one device, add the line multiple times. + * In the case of iOS, push Unreal Launch Daemon to the device and run it, add the static ip address as above, and it will now see the device. + * In the case of PS4, just add the ip address as above and it will see sessions on the kit. + * This hasn't been tested with XB1, but it should work. + * Added ability to copy and save the launcher log. + * Addition of Quick Launch to UFE. + * Quick Launch will start a cook on the fly server, deploy, and launch the project on the selected device. + * If -development is specified on the UFE command-line, Quick Launch will also build the project before launch. #### ネットワーキング -* Lifetime プロパティがサポートされたパスのみになり、これにより恐らくコード変更が必要になります。 -* GetReplicationList は GetLifetimeReplicatedProps に変更されました。 - * GetLifetimeReplicatedProps の呼び出しは 1 度のみとなりました。 -* DOREPLIFETIME が non conditional プロパティを登録することになります。 -* DOREPLIFETIME が conditional プロパティを登録することになります。 -* 可能な条件: - * COND_None - 条件なく、変更があればいつでも送信できるプロパティです。 - * COND_InitialOnly - 最初の bunch でのみ送信を試みるプロパティです。 - * COND_OwnerOnly - アクタのオーナーのみに送信するプロパティです。 - * COND_SkipOwner - オーナー以外の全ての接続に送信するプロパティです。 - * COND_SimulatedOnly - アクタをシミュレートするために送信されるプロパティです。 - * COND_AutonomousOnly - 自立したアクタに送信されるプロパティです。 - * COND_SimulatedOrPhysics - シミュレートされた OR bRepPhysics アクタに送信されるプロパティです。 - * COND_InitialOrOwner - 最初のパケット上、またはアクタ オーナーに送信されるプロパティです。 - * COND_Custom - 特定の条件は持ちませんが、 DOREPLIFETIME_ACTIVE_OVERRIDE によりオンオフを切り替える機能が必要とされるプロパティです。 +* Lifetime properties are the only supported path now, this will most likely require code changes. +* GetReplicationList has been replaced by GetLifetimeReplicatedProps. + * GetLifetimeReplicatedProps is only called once now. +* DOREPLIFETIME to register non conditional properties. +* DOREPLIFETIME_CONDITION to register properties with conditions. +* Possible conditions: + * COND_None - This property has no condition, and will send anytime it changes. + * COND_InitialOnly - This property will only attempt to send on the initial bunch. + * COND_OwnerOnly - This property will only send to the actor's owner. + * COND_SkipOwner - This property send to every connection EXCEPT the owner. + * COND_SimulatedOnly - This property will only send to simulated actors. + * COND_AutonomousOnly - This property will only send to autonomous actors. + * COND_SimulatedOrPhysics - This property will send to simulated OR bRepPhysics actors. + * COND_InitialOrOwner - This property will send on the initial packet, or to the actors owner. + * COND_Custom - This property has no particular condition, but wants the ability to toggle on/off via DOREPLIFETIME_ACTIVE_OVERRIDE. -## 今後の追加事項と継続事項 +## 今後の追加事項と継続項目 #### エディタとツール -* Matinee のカーブ制御点を移動するために CTRL を押下する必要がなくなりました。 -* 進行中のビルドをキャンセルできるように「Compiling C++ Code」通知上に [cancel] ボタンができました。 -* [code-view details] ペインから存在しないコード ファイルを開こうとするとエラー通知が発行されるようになりました。 -* アセット エディタのタブ上に該当するアイコンが付きました。 -* [Add Code To Project] ウィザードの基本クラスのリスト上にアクタが含まれるようになりました。 -* アルファの付いた UI Textures がチェックボードで、アルファ ブレンドを有効にしてサムネイルをレンダリングするようになりました。 -* [Defaults] ボタンの Import/Export/Reset が Editor Preferences / Key Bindings で正しく動作するようになりました。 -* エンジン分析がさらに追加されました。 - * ブループリント エディタにおけるユーザーの無効な接続の試みがトラックされるようになりました。 -* UnrealBuildTool:読み取り専用ファイルによる失敗に対し、サイレント障害ではなく明確にエラーメッセージが出されるようになりました。 -* Play-In-Editor(PIE) の終了時に Matinee が閉じるようになりました。 - * Play-In-Editor(PIE) の起動時には既にこれを行っています。 - * Play-In-Editor(PIE) の終了/ 開始時、間違ったワールドでアクタをうっかり編集してしまわないようにしました。 -* レベル ブラウザ機能がワールド ブラウザにマージされました。レベル ブラウザはやがて削除されます。 -* ゲームのスタートアップ時にロードされ表示可能なフラグを設定するための ULevelStreamingKismet の機能が追加されました (InitiallyLoaded、InitiallyVisible)。 -* **ワールド ブラウザ** - * レイヤーごとのフィルタリングが追加されました。 - * レイヤー ストリーミング距離設定がオプションになりました。 - * ストリーミング レベルはブループリント グラフ間でドラッグ&ドロップが可能です ( GetStreamingLevel ノードを作成します)。 - * ワールド基点を変更する bIgnoreOriginShifting を無視するオプションがアクタごとに追加されました。 -* [Material Editor Properties] パネルの名前を「Details」に変更しました。 -* 実行時に渡されたアクタを確認するのではなく Actor イテレータの TSubclassof を使用します。 -* Static bool Material Expressions が右クリック メニューのプレビュー オプションに追加されないようにしました。 -* ブループリント スタイル エディタにおいて shift-click 接続で取り消しができるようになりました。 -* マテリアル エディタでカーソルを乗せたりピンを付けると接続がハイライトされるようになりました。 -* Material Comments に色を追加し、最終入力の位置が保存できるようになりました。 -* BeginPlay 中に作成されたアクタは BeginPlay を呼び出すようになりました。 -* ユーザーが入力量に影響を及ぼすことができる他の表現式と一緒に、Texture 表現式の MIP Value Pin が表示されるようになりました。 -* マテリアル エディタ統計情報バー の下の部分をクリックできるようになりました。 -* Play-In-Editor(PIE) 通知がマテリアル、サウンドキュー、サウンドクラス エディタで表示されないようにしました。 -* マテリアルのピンを正確に [ctrl+drag] できるようになりました。 -* マテリアル ノードとピンに対するツールチップが追加されました。 -* [Material Editor Context] メニューにスクロールバーが付きました。 -* 右クリックの接続でやり直し / 元に戻す作業が正確にできるようになりました。 -* パレットから配置されたマテリアル関数が正常に機能するようになりました。 -* 同じ名前のマテリアル パラメータが設定を共有するようになりました。 -* ピンの位置をキャッシュしてノード接続時のジッターを抑えました。 -* Material ノード プレビューが折りたたまれた後も確実に同期するようにしました。 -* マテリアル エディタの検索結果に新規追加されたノードが含まれます。 -* マテリアル関数の呼び出しをペーストしても入力が正確に表示されるようになりました。 -* Lighting Model がマテリアル ドメインに対して正しくないというエラーが起こらないようにしました。 -* MarkPackageDirty パフォーマンスが改善されました。 -* Transition Map オプションがドロップダウン ピッカーを使用するようになりました。 -* タスクのキャンセル時に Perforce モジュールがクラッシュしないようにしました。 -* C++ クラスがクラス ビューアから作成できるようになりました。 -* ソース コントロールへのサブミット時の余計なプロンプトを削除しました。 -* パッケージ化されたサンプル ゲームには正しいアイコンが付けられています。 -* IDE インストールの警告文の文法ミスを修正しました。 -* 表示フォルダのオプションが [View Options] メニューに入りました。 -* スレッドセーフでないメッセージへのログ アクセスを削除しました。 -* バックエンド フィルタが適用されると、フォルダはコンテンツ ブラウザには表示されません。つまり、フィルタを使用するとビューが「平坦化」されます。 -* インポート前後の接続デリゲートが追加されました。 -* PhAT のオプション ツールチップが更新されました。 -* ソース コントロールが無効でも、削除する場合はファイルが書き込み可能になりました。 -* ブループリント インターフェースからのイベントの外見が新しくなりました。 -* レベル エディタ&マップの再ロード時にクラッシュしないようにしました。 -* ライティングの再ビルド時に、ストリーミング レベルのアクタ / レイヤ / BSP が確実に正しく隠れるようにしました。 -* Property Matrix でキーと入力が正しく機能するようになりました。 -* 親イベント / 関数コール上でダブルクリックすると、親ブループリントが開くようになりました。 -* Component ノードを追加すると、コピー / ペースト時にコンポーネントのデフォルトがコピーされるようになりました。 -* Matinee の追加時に表示されるコンボボックス ウィンドウがキーボードで操作可能になりました。 -* ブループリントの Math Library にさらに検索キーワードが追加されました。 -* FTransform にプロキシ構造体のカスタマイズが新規に追加されました。全ての FTransform プロパティが回転に対するローテーター プロキシを使用して編集可能になり、詳細ビューのアクタ変形のようになりました。 -* 詳細ビューでのアクタ変形のように、レベルの変換が編集可能になりました。 -* IsValidIndex が TBitArray に追加されました。 -* 国際化データ構造を修正したので、任意のメタデータを使用して入力の格納と検索が可能になりました。 -* WIX 製の第三者ライブラリが最新の v3.8 リリースに更新されました。 -* スプライン メッシュにマイナスのスケールを適用しても裏返しにならなくなりました。「前方」軸上でマイナスのスケールを適用するとスプライン メッシュの表から裏へ反転するようになりました。 -* ランドスケープのアルファ / パターンブラシによるテクスチャ マスク セレクタが改善されました。 -* ウィジェット自体が無効になっていても、ウィジェットのツールチップが表示されるようになりました。 -* **スレート** -* SComboBox と SComboButton が FEditorStyle に依存せずに Slate Widget Style を使用するようになりました。 +* It is no longer necessary to hold CTRL to move curve control points in matinee. +* There is now a "cancel" button on the "Compiling C++ Code" notification to allow cancellation of the current build. +* Attempting to open non-existent code files from the code-view details pane now emits an error notification +* Asset editors now have relevant icons on their tabs. +* The Add Code To Project wizard now includes Actor on the list of basic classes. +* UI Textures with alpha now render thumbnails with a checkerboard, and with alpha blending enabled. +* Import/Export/Reset to Defaults buttons now work correctly in Editor Preferences / Key Bindings. +* Added more engine analytics. + * Tracking when user attempts invalid connections in Blueprint Editor. +* UnrealBuildTool:Failure due to read-only project files when generating project files is now a clear error message not a silent failure. +* Matinee now closes when Play-In-Editor(PIE) ends. + * It already does this when Play-In-Editor(PIE) starts. + * Closing stops accidental editing of actors in the wrong world when Play-In-Editor(PIE) starts/ends. +* Levels Browser functionality was merged into World Browser.Levels Browser will be removed eventually. +* Added ability for ULevelStreamingKismet to set loaded and visible flags at game startup (InitiallyLoaded, InitiallyVisible). +* **World Browser** + * Added better filtering by layers. + * Layer streaming distance setting is optional now. + * Streaming levels can be drag'droped from onto blueprint graph (creates GetStreamingLevel node). + * Added per actor option to ignore world origin shifting bIgnoreOriginShifting. +* Changed Material Editor Properties panel name to "Details." +* Use TSubclassof for Actor iterators instead of checking Actor is passed in at runtime. +* Prevented Static bool Material Expressions from adding preview option to right click menu. +* Allowed shift-click connections in blueprint style editors to be undone. +* Connections are now highlighted when hovering or marking a pin in the Material Editor. +* Added colour to Material Comments and allowed position of final input to be saved. +* Actors created during BeginPlay now get BeginPlay called on them. +* MIP Value Pin of Texture expressions now shown, along with any other expressions where users can affect the amount of inputs. +* Can now click on areas underneath the Material Editor stats bar. +* Prevent Play-In-Editor(PIE) notification from displaying in Material, SoundCue and SoundClass editors. +* Can now Ctrl+drag material pins correctly. +* Added tool tips for material nodes and pins. +* Material Editor Context menu now has a scroll bar. +* Right-click connections now undo/redo correctly. +* Material Functions placed from the palette will now work correctly. +* Material Parameters with the same name now share settings. +* Reduced node connection jitter by caching position of pins. +* Made sure Material node previews are synced up after being collapsed. +* Material Editor search results include newly added nodes. +* Pasted material function calls now display correct inputs. +* Prevented error when Lighting Model is not correct for Material Domain. +* Improved MarkPackageDirty performance. +* Transition Map option now uses dropdown picker. +* Prevented crash in Perforce module when cancelling tasks. +* C++ classes can now be created from the Class Viewer. +* Removed extra prompt when submitting to source control. +* Example games now have correct icon when packaged. +* Corrected grammar in warning about IDE installation. +* Option to display folders is now in the View Options menu. +* Removed non-thread safe message log access. +* When backend filters are applied folders are not displayed in the Content Browser.This means the view is 'flattened' when using any filtering. +* Added pre & post-import hook delegates. +* Updated options tooltips in PhAT. +* Files can now be made writable when deleting while source control is disabled. +* Events from Blueprint interfaces now have different appearance. +* Prevented crash when reloading level editor & maps. +* Made sure that actors/layers/BSPs in streaming levels are properly unhidden when rebuilding lighting. +* Arrow keys & enter now function correctly in Property Matrix. +* Double clicking on a parent event/function call now opens the parent Blueprint. +* Add Component nodes now copy their component defaults when copy & pasted. +* Popup combo window when adding keys to Matinee is now controllable via keyboard. +* Added more search keywords to Blueprint math library. +* Added new proxy struct customization for FTransform.All FTransform properties are now editable using rotator proxy for their rotation & appear like the actor transform in the details view. +* Level transform is now editable like Actor transform in the details view. +* Added IsValidIndex to TBitArray. +* Modified internationalization data structures so they can store and lookup entries using arbitrary metadata. +* Updating WIX third party library to final v3.8 release. +* Spline meshes no longer turn inside out when scaled negatively, and negative scale on the "forward" axis now flips the spline mesh front-to-back. +* Improved landscape alpha/pattern brush texture mask selector. +* Tooltips are now displayed for widgets even if the widget itself is disabled. +* **Slate** +* The following widgets now use a Slate Widget Style and are no longer dependent on FEditorStyle: * SProgressBar * SScrollBar * SExpandableArea @@ -556,7 +558,7 @@ QA_APPROVED_UE4_BUILD_MINIMUM * SSplitter * STableRow * SDockTab -* 以下のウィジェットで FEditorStyle は内部では使われなくなりました。 +* The following widgets are no longer using FEditorStyle internally: * SExpandableButton * SNotificationList * SHeader @@ -564,184 +566,184 @@ QA_APPROVED_UE4_BUILD_MINIMUM * SBreadcrumbTrail * SNumericEntryBox * SColorPicker -* **マテリアル エディタ** - マテリアル エディタの [preview toolbar] ボタンはメインのツールバーではなくビューポートのツールバー上に表示されるようになりました。 -* **プラットフォーム ゲーム** - * Slate Widget Style アセットを使用するように変換され、 FEditorStyle に全く依存しなくなりました。 -* AnimInstance イベントの「Kismet」が「Blueprint」に置き換えられました。 - * PhAT の Simulate コマンドが Bound キーを正確に使うようになりました。 - * PhAT の Copy properties コマンドがビューポート以外でも機能するようになりました。 - * Animation ブループリントから派生したブループリントを作成する機能を削除しました。 -* ランドスケープのペイント中にグラウンドが変化すると、フォーリッジの方向が Max Angle 設定に限定されます。 -* UE4Editor*-cmd で開始するプロセスを Windows の Ctrl とクリックで対応し、デストラクタがクラッシュしないように Ctrl とダブルクリックによる強制終了を有効にしました。 -* ユーザーが使いやすいアセット名をもっと含んで、使用されないアセットを削除し、オーディオの使用に整合性を持たせるなど、ストラテジー ゲームの幾つかの特性を整理しました。 -* StrategyGame カメラが改定され、 StrategyCameraComponent クラスの中へ置かれました。 -* レース開始前の自爆の中止、ビューポートでの再生時の一時停止など、ビークル サンプルの幾つかの特性を整理しました。 -* ブラックジャック サンプル ゲームのインターフェースを整理しました。これにより、ブループリント間通信が使用されるようになり、ブループリントがアーカイブに使用していた古いインターフェースは削除されました。 -* オブジェクト上の blackjack フォントを整理しました。クリップ値などです。 -* シューティングゲームの FORCEDINLINE を幾つか整理しました。 +* **Material Editor** + * The preview toolbar buttons in the material editor are now shown on a viewport toolbar, rather than being on the main toolbar. +* **PlatformerGame** + * Converted over to use Slate Widget Style assets, and now has no dependency on FEditorStyle. +* Replaced 'Kismet' with 'Blueprint' on AnimInstance events + * Simulate command in PhAT now uses bound key correctly + * Copy properties command in PhAT now works outside of the viewport + * Removed ability to create derived blueprints from animation blueprints +* Foliage orientation is now limited to Max Angle setting when the ground changes during landscape painting +* Enable windows control-c handling for processes started with UE4Editor*-cmd, force termination on double ctrl-c to prevent destructors crashing +* Cleaned up several aspects of Strategy game including more user friendly asset names, removing unused assets, made audio usage consistent etc. +* StrategyGame camera has been revised and put into its own StrategyCameraComponent class. +* Cleaned up several aspects of vehicle sample including stopping self destruct before race begins, allowed pause when playing in viewport etc. +* Cleaned up blackjack sample game interface - it now uses inter blueprint communication and the old interface bleuprint used to achieve this has been removed. +* Cleaned up blackjack fonts on objects.Chip value etc. +* Cleaned up some FORCEDINLINE in shootergame. #### レンダリング -* デフォルトのポストプロセス マテリアルで透過的に古いパスが見えるようにしました。これにより、ポストプロセス マテリアルのコンパイル中、単一のテクスチャで画面全体が透明になることがなくなりました。 -* 新規のパラメータをマテリアル パラメータ コレクションに追加すると、一意の適切な名前が生成されるようになりました。 -* スタティック メッシュ LOD 距離設定からのクランプ処理を削除しました。 -* 反射面に対する反射キャプチャの精度があがりました。非常に大雑把な面スペキュラです。 -* ES2 の指向性ライトマップ マテリアル フラグの使用を追加しました。 -* 非常に大雑把ではありますが、ES2 のマテリアルにフラグが追加されました。 -* スペキュラ マテリアル出力が ES2 で機能するようになりました。 -* **その他のパーティクル レンダリング** - * 自動生成による境界がかなり狭くなったので、カスケードの [set fixed bounds] を修正します。 - * 透過処理されたボリュメトリック シャドウを投射すると、パーティクルがライトの方へ向くようになりました。 +* Default post process material now has a transparent hole in it, letting you see through to the previous pass.This stops the whole screen being obscured by a single texture when post process material are being compiled. +* When adding a new parameter to a material parameter collection, it now generates a proper unique name. +* Removed clamping from static mesh LOD distance setting. +* Improved accuracy of reflection capture for reflective surfaces.Fully rough dims specular. +* Added use directional lightmap material flag for ES2. +* Added fully rough flag to materials for ES2. +* Specular material output now works on ES2. +* **Misc Particle Rendering** + * Automatically generated bounds are much tighter, fixes 'set fixed bounds' in Cascade. + * Particles now face toward the light when casting translucent volumetric shadows. #### ブループリント -* ブループリントのノード探知能力が改善されました。 - * 様々なノード タイプに対して検索キーワードが幾つか追加されました。 -* ブループリント ノードに関するドキュメント類が改善されました。 - * 目的と機能を分かりやすくまとめるため、幾つかのブループリント ノードに詳細な (「大きい」) ツールチップが追加されました。 -* ブループリントの level actor reference ノードのデザインが新しくなりました。 -* ブループリントの compact array function ノードのデザインが新しくなりました。 -* 全てのブループリントを展開して全てのコメントがインクルードされます。 -* 利用するキーボードをコンポーネント エディタで適切に「複製」したり「削除」できるようになりました。 -* [My Blueprint] ウィンドウでの削除にキーバインドを使用するようになりました。 -* ブループリントのデバッグにおいて F5 でもステップ実行ができるようになりました。 -* ステートマシンの名前変更がグラフ内で可能になりました。 +* Improved blueprint node discoverability. + * Added several search keywords to a variety of node types. +* Improved Blueprint node documentation. + * Added verbose ("big") tooltips to several blueprint nodes to better document their purpose and functionality. +* Redesigned level actor reference nodes in Blueprints. +* Redesigned compact array function nodes in Blueprints. +* Expanding searching all Blueprints to include all comments. +* Components editor will now properly "duplicate" and "delete" utilize keybindings. +* Deleting in the My Blueprint window now utilizes keybindings. +* F5 will now "Step" in Blueprint debug. +* State machines can be renamed in the graph. #### ゲームプレイとフレームワーク -* 物理コンストレイントを終了するためのデリゲートが追加されました。 -* Joint drive 関数がブループリントにエクスポーズされました。 -* コンテンツ ブラウザでの管理できるようにマップをアセットとして取り扱う準備作業。 - * UWorld オブジェクトは、その他の全てのアセットと同様に、それらを含むパッケージに因んだ名前が付くようになりました。 - * 「TheWorld」という名前のオブジェクトをパッケージ内で検索するコードに置き換えるための静的関数 UWorld::GetWorldFromPackage が追加されました。 -* コンテンツ ブラウザ内のフィルタは、それが特別なフィルタのあるタイプでない限り、選択したアセットタイプのサブクラスを表示するようになりました。 - * 例えば、ブループリントは AnimBlueprints は表示されませんが、 DataAsset 派生した DataAssets は全て表示されます。 -* メインのティック ループの一定のオーバーヘッドを削減するため、デディケイテッド サーバーのパフォーマンスに関してマイナーな改善が数多く行われました。 -* パフォーマンスに影響する可能性のある UE_BUILD_TEST 内のものを多数無効にしました。 -* メモリのレポート機能がエンジン全体で改善されました。 -* Windows binned allocator の効率が約 5% 向上したので、提供されるメモリ デバッグ情報も質が改善されました。 -* メモリを保存するために、ウィンドウ上のワーカースレッドのスタック サイズが削減されました。 -* 最大カリング距離がエディタ ビューポートでデフォルトで無視されるようになりました。G でゲーム レンダリング モードに入ると最大カリング距離が順守されます。 -* フォーカスへの優先度が AIController に追加されました。移動、ゲームプレイなどに対し異なるフォーカスを付けることができます。 -* navmesh 上でのランダム位置の検索が Detour の半径で正確に制約されるようになりました。 -* フォーカスへの優先度が AIController に追加されました。移動、ゲームプレイなどに対し異なるフォーカスを付けることができます。 -* navmesh 上でのランダム位置の検索が Detour の半径で正確に制約されるようになりました。 -* navmesh 生成時において、 衝突障害物としてボックス、カプセル、球体プリミティブのサポートが追加されました。 -* サウンドが再生される順序 (逆再生とは反対) でパースされるようになりました。そのため、複数のサウンドが同時再生されると、グループ管理などのノードは正確に評価します。 -* 追加のコマンドライン パラメータをスタンドアロン再生セッションに対して [Editor] -> [Play In settings] から指定できるようになりました。 -* アセットの一括エクスポートがコンテンツ ブラウザからできるようになりました。 -* 「public include」フォルダに間違えて置かれていた幾つかの C++ ファイルが移動されました。 -* 間違えて宣言した SpriteInfo の対処がしやすくなりました。 -* アニメーションを適用せずにボーンを変形できるようにペルソナが変更されました。 -* 管理に必要なコードの量を減らすために、ペルソナのプレビュー シーンをアニメーション ビューポートからペルソナ自体に移動しました。 -* 手動ではなく FTransform 計算をするように、ルート モーション コードをリファクタリングしました。 - * ルート モーション中は PhysicsRotation が無効になります。DesiredRotation はルート モーション回転で問題が発生する可能性があります。 -* FRotator::Equals はノーマライズされたローテータに対してテストを行います。 -* **コリジョン** - * Collision モードの可視化が追加されました。 +* Added delegates for breaking physics constraints. +* Exposed joint drive functions to Blueprints. +* Preparation work for treating maps as assets so they can be managed in the content browser. + * UWorld objects are now named after the package that contains them, just like all other assets. + * Added static function UWorld::GetWorldFromPackage to replace code that was searching for an object named "TheWorld" in a package. +* Filters in the content browser now show you subclasses of the asset type you select unless there is a more specific filter for that type. + * For example, Blueprint will not show you AnimBlueprints, but DataAsset will show you all derived DataAssets. +* Many minor dedicated server perf improvements to reduce constant overhead of the main tick loop. +* Disabled many things in UE_BUILD_TEST that may affect performance. +* Memory reporting has been improved across the engine. +* The windows binned allocator is now around 5% more efficient and gives better memory debugging information. +* Reduced the stack size of worker threads on windows to save memory. +* Max Cull distance is now ignored in the editor viewports by default.Entering game render mode with G will respect max cull distance. +* Added priorities to focus in AIController.We can have different focus for movement, gameplay, etc. +* Find random location on navmesh is exactly constrained by radius in Detour now +* Added priorities to focus in AIController.We can have different focus for movement, gameplay, etc. +* Find random location on navmesh is exactly constrained by radius in Detour now. +* Added support for box, sphyl and sphere primitives as colliding obstacles in navmesh generation. +* Sounds are now parsed in the order they were played (as oppose to reverse order) so that when multiple sounds are played at the same time nodes such as the group control evaluate correctly. +* Additional command line parameters can now be specified for a standalone play session via the Editor -> Play In settings. +* Bulk Exporting of assets can now be done from the content browser. +* Some C++ files which were incorrectly placed in public include folders have been moved. +* Better handling of misdeclared SpriteInfo. +* Changed Persona so that it is possible to transform bones without an animation applied. +* Moved Persona's preview scene out of the animation viewport into Persona itself to reduce the amount of code needed to manage it. +* Refactored root motion code to use FTransform math instead of doing it manually. + * Disable PhysicsRotation while doing root motion.DesiredRotation would fight root motion rotation. +* FRotator::Equals tests against normalized rotators. +* **COLLISION** + * Added collision mode visualization. #### コア -* スタートアップ コードで使用できるように、乱数生成器はエンジン初期化において早めにシードが与えられるようになりました。 -* FUTF8ToTCHAR::Length と FTCHARToUTF8::Length は、「十分足りる」長さではなくて、正確な長さを返すようになりました。 -* クラッシュというようよりは不足ファイルの処理を要求されると、UnrealHeaderTool がエラーを報告します。 -* TArray::RangeCheck が最適化されました。 -* TArray::Append はムーブの必要性を認識しムーブするようになりました (move-aware)。 -* Visual Studio 2010 のサポートを完全に廃止しました (2010 サポートが必要な場合は Nov 2012 QA build をご利用ください)。 -* 大きな改善点は、UnrealBuildTool の依存図式を可視化したことです (-graph オプション)。 - * 出力ファイルが /UE4/Engine/Intermediate/.gephi に保存されるようになりました。 - * 5 種類のグラフが含まれるようになりました (UBT の GraphVisualizationType を参照)。 - * C++ のヘッダーの関係を可視化します。 - * ソールファイル ノードのサイズが改善されました。 - * 項目全般において改善とバグ修正を行いました。 -* Visual Studio 2013 が UnrealVS 拡張機能のサポート対象になりました(注:UE4 はまだ 2013 との互換性はありません)。 -* UE4 ソースコードにより Visual Studio における IntelliSense の動作が改善されました。 -* 各種 UE4 のコンパイル時間が改善されました (継続中)。 -* エディタ:エディタから起動した場合、 ES2 で Faketouches モードを強制するようにしました。 -* Windows プラットフォーム上の Clang コンパイラに対する実験的なサポートの追加が始まりました。 -* モジュール ソース コードの検索中に中間フォルダが見つかると、UnrealBuildTool が警告を出します。 -* Async のロード処理が改善されました (パフォーマンスと修正)。 -* MCPP の VS2013 build が追加されました。 -* nvtesslib の VS2013 build が追加されました。 -* nvtexturetools の VS2013 build が追加されました。 -* Vorbis と Ogg の VS2013 build が追加されました。 -* nvtristrip の VS2013 build が追加されました。 -* ForsythTriOptimizer の VS2013 build が追加されました。 -* HACD の VS2013 build が追加されました。 -* ICU の VS2013 build が追加されました。 -* Box2D の VS2013 build が追加されました。 -* hlslcc の VS2013 build が追加されました。 -* libPNG と zlib の VS2013 build が追加されました。 -* IntelTBB の VS2013 build が追加されました。 -* FreeType2 の VS2013 build が追加されました。 -* Recast の VS2013 build が追加されました。 +* The random number generator is now seeded earlier in engine initialization to allow its use in startup code. +* FUTF8ToTCHAR::Length and FTCHARToUTF8::Length now return precise lengths, rather than 'big enough' lengths. +* UnrealHeaderTool reports an error when it is asked to process a missing file, rather than crashing. +* TArray::RangeCheck optimization. +* TArray::Append is now move-aware. +* Fully removed Visual Studio 2010 support (use the Nov 2012 QA build if you need 2010 support). +* Major improvements to UnrealBuildTool's dependency graph visualization ("-graph" option). + * Output files are now saved in /UE4/Engine/Intermediate/.gephi + * Now includes five different graph types (see GraphVisualizationType in UBT). + * Supports C++ header relationship visualization. + * Better sizing of source file nodes. + * General improvements and bug fixes. +* UnrealVS extension now supports Visual Studio 2013 (NOTE:UE4 does not compile with 2013 yet though). +* IntelliSense now works better with UE4 source code in Visual Studio. +* Various UE4 compile time improvements. (ongoing) +* Editor:We now force "faketouches" mode in ES2 preview when launched from editor. +* Began adding experimental support for Clang compiler on Windows platform. +* UnrealBuildTool will now emit warnings if Intermediate folders are encountered while looking for module source code. +* Async loading improvements (performance + fixes). +* Added a VS2013 build of MCPP. +* Added a VS2013 build of nvtesslib. +* Added a VS2013 build of nvtexturetools. +* Added a VS2013 build of Vorbis and Ogg. +* Added a VS2013 build of nvtristrip. +* Added a VS2013 build of ForsythTriOptimizer. +* Added a VS2013 build of HACD. +* Added a VS2013 build of ICU. +* Added a VS2013 build of Box2D. +* Added a VS2013 build of hlslcc. +* Added a VS2013 build of libPNG and zlib. +* Added a VS2013 build of IntelTBB. +* Added a VS2013 build of FreeType2. +* Added a VS2013 build of Recast. #### ネットワーキング -* 初回パスが FText へのほとんどのネットワーク エラー メッセージをカバーします。 -* NetDriver::InitListen への参照により FURL パラメータを作成したので、実際のポート割り当てを戻すことができます。 +* First pass converting most network error messages to FText. +* Made FURL parameter by reference into NetDriver::InitListen so that actual port assignment can be passed back out. #### プラットフォーム -* アーキテクチャのコンセプトが UBT に追加されました。IOS ("-simulator") と HTML5 ("-win32") での使用を開始しました。このように、異なる CPU アーキテクチャのためのプラットフォームは複数必要ありません。 -* DirectShow の VS2013 build が追加されました。 -* VS2013 のビルドに必要な wincrypt include が追加されました。 -* スタティック メッシュ エディタに「Generate Unique UVs 機能は Windows 以外のプラットフォームにはまだ実装されていない」旨のダイアログ警告が表示されるようになりました。 +* Added the concept of Architecture to UBT.Beginning to be used in IOS ("-simulator") and HTML5 ("-win32").This way, we don't need multiple platforms for a different CPU architecture. +* Added a VS2013 build of DirectShow. +* Added a wincrypt include which is necessary for VS2013 builds. +* Made the StaticMesh editor show a dialog warning users that the "Generate Unique UVs" feature isn't implemented on non-Windows platforms. * **Mac** - * Mavericks の新しいデフォルト マルチモニター モードでの動作中、メイン エディタ ウィンドウによりオーバーラップされたウィンドウがマウスクリックを横取りしないようにしました。 - * Mac OS X Mavericks の新しいマルチモニター モードで複数の画面間を移動する時、ウィンドウが終了や移動したり非表示には絶対にならないようにしました。 - * デバッグ & テクスチャ ローディング機能向けに Mac OS X に提供された新しい OpenGL バージョンにより追加された拡張機能を使用します。 - * Mission Control キーボード ショートカットがエディタを混乱させたりキーボード入力を壊さないようにしました。 - * Mavericks の新しいマルチモニター モードのデフォルト状態でウィンドウが非表示にならないように、Mac OS X にリコンフィギュレーション表示を手動で行います。 - * Mac OS X にデフォルト マージツールの p4merge.app を作成しました。 - * デフォルトのアプリケーションを使ってエディタ サービスの Launch Game を開くようにしました (Finder のダブルクリックと同じプロジェクトです)。 - * 2 つ以上の UE4 インスタンスが動作中、Mac OS X のAMD カード上で青が点滅しないようにしました。 - * Mac OS X に幾つかサンプルをロードする際のクラッシュを避けるため、Nvidia ドライバーのバグに対処しました。  + * Stopped windows overlapped by the main editor window from stealing mouse clicks when running under Mavericks' new default multi-monitor mode. + * Made sure that windows close, move & don't disappear when moved across screens under Mac OS X Mavericks' new default multi-monitor mode. + * Use the extensions added by newer OpenGL versions provided on Mac OS X for debug & texture loading features when available. + * Prevented Mission Control keyboard shortcuts from confusing the editor & breaking keyboard input. + * Manually handle display reconfiguration on Mac OS X so that windows don't disappear under Mavericks' new default multi-monitor mode. + * Made the default merge tool p4merge.app on Mac OS X. + * Make the editor services 'Launch Game' use the default application to open (the project the same as double-clicking in Finder). + * Prevent blue flickering on AMD cards under Mac OS X when more than one UE4 instance is running. + * Worked around an NVIDIA driver bug to avoid crashes loading some samples on Mac OS X. * **Moblie** - * iOS にテクスチャ ストリーミングのサポートが追加されました。 - * OpenGL TexStorage2D の処理がクリーンアップされ、iOS へのテクスチャ格納のサポートが追加されました。 - * OS のメモリ不足警告に対応するため、コールバック関数が追加され iOS 上に実装されました。 - * per-process stat を返す task_info() api を使うために iOS にアロケートされたメモリ情報を変更しました。 - * iOS のバーチャル ジョイスティックが改善されました。 + * Added support for texture streaming on iOS. + * Cleaned up OpenGL TexStorage2D handling and added support for texture storage on iOS. + * Added callback function to handle OS low memory warning, implemented on iOS. + * Changed iOS allocated memory stat to use the task_info() api which returns the per-process stat. + * Improvements to virtual joystick on iOS. -#### オンライン -* OSSNull の GenerateRandomUserId が常に Guids を使うように変更されました。 - * **ストリーム** - * アクセスしやすいようにログ内の App Id printout をストリームとして取り扱います。 - * 実際の Steam API calls の呼び出し前に Steam Dlls がロードされることを確認し、存在しない場合は fail モジュールとなります。 +#### Online +* Changed GenerateRandomUserId for OSSNull to always use Guids. + * **Steam** + * Steam App Id printout in logs for easier access. + * Check for Steam Dlls to be loaded before calling actual Steam API calls, fail module if not present. * **Misc** - * オンライン ティック関数および async タスク マネージャに統計情報を幾つか追加しました。 + * Added some stats to online tick functions and async task manager. -## 周知の問題 +## 既知の問題 * **INFILTRATOR** - * 光源が以前より暗くなりました。 - * 起動時、エディタが反応しません。 + * Lighting is darker than previously. + * Editor unresponsive when launched * **CONTENT EXAMPLES** - * Scalability インターフェースエクストラ メッシュ - * NavMesh:ゲームで壊れたポーン - * Input_Examples:制御のうち動かないものがあります。 + * Mouse_Interface:Extra mesh. + * NavMesh:Pawns broken in game. + * Input_Examples:Some controls are not working * **EDITOR** - * キーボード ショートカット:モディファイア キーの変更により結合のコミットが早まります。 - * ウィークリーテストにおいてサブ エディタのパフォーマンスが落ちました。 + * Keyboard Shortcuts:Changing modifier keys commits binding prematurely. + * Sub-editor performance has dropped during weekly tests. * **ELEMENTAL** - * CRASH:テクスチャ座標の数字が無効です。 + * CRASH:Invalid number of texture coordinates. * **PLATFORMERGAME** - * SaveGameBP に解決できないコンパイラ エラーが存在しています。 + * SaveGameBP unresolved compiler error. * **SHOWCASES** - * PostProcessMatinee:ライティング エラーを再ビルドします + * PostProcessMatinee:Rebuilt lighting error. * **WORLDBROWSER** - * Play-In-Editor では、プレイヤーは移動できません。 + * Player can not move when Play-In-Editor. * **SHOOTERGAME** - * CRASH:Highrise 上にライティングをビルドした後です。 + * CRASH:After building lighting on Highrise. * **Unreal Frontend** - * 高度なタブでは PS4 設定を使用せず、むしろ XboxOne のビルドおよび段階わけを試みます。 - * サンプル プロジェクトを Unreal Frontend から起動するとエラーになります。 + * Advance tab won't use the PS4 settings rather it will attempt to build and stage the XboxOne. + * Samples projects will fail to launch from the Unreal Frontend. * **MAC** - * RENDERING:ビューポートのグラフが破損しました。 + * RENDERING:Graphics corruption in viewport. * **PS4** - * 起動時にクラッシュ (PS4File.cpp:アサーションに失敗しました:OpenParams != nullptr) + * Crashes on launch (PS4File.cpp:Assertion failed:OpenParams != nullptr) * **RENDERING** - * OPENGL:ES2:CRASH:既存のゲーム + * OPENGL:ES2:CRASH:Exiting game * **VEHICLE** - * Low FPS のローエンド ビデオカードのユーザーはコースを完了できなくなります。 + * Users on low-end video cards with Low FPS are unable to complete the course. diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/January/ReleaseNotesJanuary2014.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/January/ReleaseNotesJanuary2014.KOR.udn index b209d96f5f33..4187a034d589 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/January/ReleaseNotesJanuary2014.KOR.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/January/ReleaseNotesJanuary2014.KOR.udn @@ -1,9 +1,10 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3367470 Title: January 2014 Release Notes Crumbs:%ROOT%, Support/Builds Description: Availability:Licensee -Template:ReleaseNotes.html +Parent:Support/Builds +Order:-2 [TOC(start:2 end:2)] diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/March/ReleaseNotesMarch2014.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/March/ReleaseNotesMarch2014.JPN.udn index d9c21c241c84..99f013ce32a1 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/March/ReleaseNotesMarch2014.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/March/ReleaseNotesMarch2014.JPN.udn @@ -1,8 +1,10 @@ -INTSourceChangelist:2591123 +INTSourceChangelist:3367470 Title:2014 年 3 月リリースノート Crumbs:%ROOT%, Support/Builds Description: Availability:Licensee +Parent:Support/Builds +Order:-1 [TOC(start:2 end:2)] @@ -12,10 +14,10 @@ Availability:Licensee [REGION:simpletable] | アイテム | 情報 | | ---- | ---- | -| **Labels** | [INCLUDE:#labels] | +| **ラベル** | [INCLUDE:#labels] | | **Built from Changelist #** | (//depot/UE4-QA/Promotable-CL-) | | **Branched from Changelist #** | (//depot/UE4/Promoted-CL-) | -| **Visual Studio バージョン** | | +| **Visual Studio Version** | | | **DirectX** | June 2010 | [/REGION] @@ -34,11 +36,11 @@ QA_APPROVED_UE4_BUILD_MINIMUM これにより、March QA ビルドが遅れる結果となり、**UE4-Releases/4.0/** のコンテンツは現時点で有効なコンソールに含まれていません。現在 **//depot/UE4-QA-Unstable/** ( *which was branched from Releases* ) に保存されているコンソールを、認証から安全に作業ができるブランチへ戻す作業をしています。 **//depot/UE4-QA/** へすぐにブランチしますが、コンソール ゲームを行う場合は、April QA ビルドで最低 1 つコンソールの認証ビルド、May QA では両方のビルドが含まれるようにします。 * 現時点のエンジン開発ロードマップ: [UE4 Roadmaps](https://udn.unrealengine.com/questions/topics/roadmap.html) -* 修正されたバグ: [UE4 Fixed Bugs March 2014] -* 周知の問題: [UE4 Known Issues March 2014] +* 修正されたバグ: [UE4 Fixed Bugs March 2014] +* 周知のバグ: [UE4 Known Issues March 2014] -## 主な新機能 +## 主要な新機能 #### ブループリント @@ -52,7 +54,7 @@ QA_APPROVED_UE4_BUILD_MINIMUM ![](MacroDebugging01.png) - _実行は Gate マクログラフ内部の Enter 出力に適用されたシーケンス ノード上でブレークします。マクロ内部の Branch ノード上にブレークポイントを設定し、[Resume(再開)] をクリックすると_ + _実行は Gate マクログラフ内部の Enter 出力に適用されたシーケンス ノード上でブレークします。マクロ内部の Branch ノード上にブレークポイントを設定し、[Resume (再開)] をクリックすると_ ![](MacroDebugging02.png) @@ -152,11 +154,11 @@ QA_APPROVED_UE4_BUILD_MINIMUM 1 アンリアル単位 = 1 センチ (cm) - * 新しいスナップサイズです: + * 新しいスナップサイズです。 ![](DecimalIntervals01.png) - * 環境設定の Viewports->Grid Snapping で、ゲームに対するスナップ設定をべき乗に戻すことができます: + * 環境設定の Viewports->Grid Snapping で、ゲームに対するスナップ設定をべき乗に戻すことができます。 ![](DecimalIntervals02.png) @@ -198,7 +200,7 @@ QA_APPROVED_UE4_BUILD_MINIMUM * プレースメント ブラウザが全く新しいデザインで生まれ変わりました! - 新しいプレースメント ブラウザでは、ライト、トリガー、ボリューム、全てのクラスへの迅速なアクセスだけでなく、最近配置したアセットの非常に長いリストにもアクセスできます。 + 新しいプレースメント ブラウザでは、ライト、トリガー、ボリューム、全てのクラスへの迅速なアクセスだけでなく、最近配置したアセットの非常に長いリストにもアクセスできます。 * Editor モードがすべて [Tools] タブの中に統合されました。 @@ -210,14 +212,14 @@ QA_APPROVED_UE4_BUILD_MINIMUM * **[Details] パネルのヘッダがスリムになり、 C++ ファイルを開けるようになりました** - * 2 本だったヘッダー行がシンプルな 1 行に圧縮されました。アイコン ツールチップがクラス名を表示するようになりました (Scene Outliner など)。 + * 2 行だった詳細ヘッダーがシンプルに 1 行に圧縮されました。アイコン ツールチップがクラス名を表示するようになりました (Scene Outliner など)。 * C++ コードのあるアクタの場合は、ヘッダファイルのハイパーリンクをクリックればコードを開くことができます (VS または Xcode をインストールしている場合のみ表示されます)。 ![](DetailsPanel01.png) + * これまではアクタ クラス名にブループリント エディタへ飛ぶハイパーリンクが付いていました。それが今度は別のボタンとなりました。 - これまではアクタ クラス名にブループリント エディタへ飛ぶハイパーリンクが付いていました。それが今度は別のボタンとなりました。 ![](DetailsPanel02.png) * ビューポートの右クリック メニューに C++ ファイルへのアクセスも追加しました (コンパイラをインストールしている場合に限ります)。 @@ -238,11 +240,11 @@ QA_APPROVED_UE4_BUILD_MINIMUM #### レンダリング -* **光沢のあるスクリーン空間の反射** +* **光沢のある Screen Space Reflections** - * マテリアルのラフネスをサポートするスクリーン空間の反射が追加され、デフォルトで有効になりました! + * マテリアルのラフネスをサポートする Screen Space Reflections (スクリーン スペース反射) が追加され、デフォルトで有効になりました! + Screen Space Reflections を使用したくない場合は、ポストプロセス設定でこの機能を弱める / 無効にすることができます。 - スクリーン空間の反射を使用したくない場合は、ポストプロセス設定でこの機能を弱める / 無効にすることができます。 マイナーな調整が必要なマテリアルもありますが、それらは他の反射に対しても正しい表示はされません。 Image Based Lighting と 法線 (解析的) 光源を一致させました。 @@ -268,9 +270,9 @@ QA_APPROVED_UE4_BUILD_MINIMUM #### アニメーション -* **一様でないスケール アニメーション** +* **不均等なスケール アニメーション** - * 一様でないスケール アニメーションがサポートされるようになりました。オプションは必要ありません。アニメーションをインポートすると、スケールが存在する場合、それもインポートされます。 + * 不均等なスケール アニメーションがサポートされるようになりました。オプションは必要ありません。アニメーションをインポートすると、スケールが存在する場合、それもインポートされます。 全てのアニメーションに対してスケールを保存するわけではありませんので、メモリの心配もありません。1 ではないスケールをもつアニメーションのみを保存します。 @@ -283,11 +285,11 @@ QA_APPROVED_UE4_BUILD_MINIMUM [![](Keridan_Facial_Compound.png)](Keridan_Facial_Compound.wmv) -## 新機能の追加 +## 新規追加 #### エディタとツール * 新しいサウンド ノードがサウンドキュー エディタで選択済みのノードへ自動接続されるようになりました。 -* Placement Browser が全く新しいデザインになって戻ってきました!コンテンツ ブラウザの [Clasees] ビューが取り除かれました。 +* Placement Browser が全く新しいデザインになって戻ってきました!コンテンツ ブラウザの [Classes] ビューが取り除かれました。 * JPEG インポートがエディタでサポートされるようになりました。基本の 8bit RGB と Gray JPEG 形式に対応します。 * コンテンツ ブラウザのスレート ブラシにカスタム仕様のサムネイル レンダラーを追加しました。 * [C] キーでマテリアルとサウンドキュー エディタ用にコメントを作成するようになりました。 @@ -298,9 +300,9 @@ QA_APPROVED_UE4_BUILD_MINIMUM * **ランドスケープ** * ランドスケープ平坦化ツールに、高さに合わせて平坦化するオプションが追加されました。 * ランドスケープ エディタに傾斜ツールが追加されました。 -* カメラ アニメーションの作成と編集が Matinee で可能になりました。 +* カメラ アニメーションの作成と編集がマチネで可能になりました。 * ソース コントロール設定がグローバルとプロジェクト別で切り替え可能になりました。 -* アクタを複数の Matinee で同時に制御できるようになりました。 +* アクタを複数のマチネで同時に制御できるようになりました。 * 使用時にユニコードがサポートされるようになりました。また、正しく機能しなかった同期が修正されました。 * ブループリントの関数コールをダブルクリックすると、それぞれのブループリントが開くようになりました。 * エディタを再起動すると、[Asset] タブがリストアされるようになりました。 @@ -318,7 +320,7 @@ QA_APPROVED_UE4_BUILD_MINIMUM * FEditorStyle はスレート コアには存在しなくなりました。 * FEditorStyle は Slate モジュールではなく EditorStyle に存在するようになりました。 * FEditorStyle を使用する場合、「EditorStyle」を .Build.cs ファイルにリンクしているモジュール リストに追加する必要があります。 - * ゲームスタイルに FEditorStyle の使用はお勧めしません。 推奨されるゲームスタイルの設定方法については、ShooterGame または StrategyGame サンプルの例をご覧ください。 + * ゲームスタイルに FEditorStyle の使用はお勧めしません。推奨されるゲームスタイルの設定方法については、ShooterGame または StrategyGame サンプルの例をご覧ください。 * SRichTextBlock がスレートに追加されました。SRichTextBlock には、複数のタイプのフォント、サイズ、カラー、ウィジェットを混ぜることができ、テキスト ドキュメント内で全てが画像化されます。 * ペルソナの通知ステートに、リミットハンドルをドラッグで編集される継続時間が付きました。 * マテリアル エレメントのスケルタル メッシュへの追加および削除が可能になり、 LOD マテリアルが定義できるようになりました。 @@ -328,10 +330,10 @@ QA_APPROVED_UE4_BUILD_MINIMUM * マウスボタンが押されていれば、 WASD が常に可能になりました。 * Perspective (透視図法) ビューポート マーキー選択は、マーキー ボックス内部に可視ピクセルを持つオブジェクトのみを考慮するようになりました。 * [Detail] パネルのプロパティに copy/paste が追加されました。 -* プロジェクトとワールド設定の GameMode の作成 / 選択 / 編集用に新しい UI が追加されました。 +* Project Settings と World Settings の GameMode の作成 / 選択 / 編集用に新しい UI が追加されました。 * **物理アセット ツール** * PhAT は複数選択が可能です。 - * PhAT に、ボディのあるボーンを表示のみする新しい階層フィルタができました。 + * PhAT に、ボディのあるボーンのみを表示する新しい階層フィルタができました。 * PhAT に Selected Simulation と呼ばれる新しいシミュレーション モードができました。 #### ブループリント @@ -358,14 +360,14 @@ QA_APPROVED_UE4_BUILD_MINIMUM * GetActorUp/Right/ForwardVector が追加されました。 #### レンダリング -* ボリューム ライティング サンプルと事前計算済みのビジビリティ セルの表示フラグが可視化されました。 +* ボリューム ライティング サンプルと事前計算されたビジビリティ セルの表示フラグが可視化されました。 * プレビュー シャドウ インジケータ テキストはプレビューに使用されたシーン シャドウをまるどとレンダリングします。 * Visualize カテゴリの表示フラグで無効にすることができます。 * ビルドされていない指向性ライトの Preview CSM はゲームと整合させるため、 PIE には適用されなくなりました。 * ES2 のシェーダーで、 詳細情報およびエラーがマテリアルおよび MIC エディタ内で表示できるようになりました。 -* スクリーン空間の反射に対してラフネスがサポートされるようになりました。 +* スクリーン スペースの反射に対してラフネスがサポートされるようになりました。 * WIP LightPropagationVolumes (Microsoft/Lionhead から統合) が追加されました。 -* Matinee をセットアップせずにレンダリング パスに対して異なるビューポートの状況をテストするために r.ViewportTest が追加されました (ゲームのみで機能)。 +* マチネをセットアップせずにレンダリング パスに対して異なるビューポートの状況をテストするために r.ViewportTest が追加されました (ゲームのみで機能)。 * HLSL 「View.GeneralPurposeTweak」にアクセス可能なcvar 「r.GeneralPurposeTweak」がシェーダー開発用に追加されました。 * ステートが簡単に管理できるように (デバイス プロファイルのオーバーライドなど) Scalability settings cvars が作成されました。 * 全ての 2D テクスチャの LOD バイアスをオーバーライドするための r.MipMapLODBias コンソール変数が追加されました。 @@ -378,7 +380,7 @@ QA_APPROVED_UE4_BUILD_MINIMUM * navmesh 生成用の領域が新しく分割されました。ChunkyMonotone * タイルを長方形のチャンクに分割し (デフォルト:2X2)単調分割を実行します。 * デフォルト モードに比べて明らかに速いです (watershed による)。 - * チャンクを分割することで長くて細いポリゴンが作成されるのを防ぎますが、生成されるポリゴン数が他のメソッドに比べて若干多くなります。 + * チャンクを分割すると細長いポリゴンの作成を防ぐことができますが、生成されるポリゴン数が他のメソッドに比べて若干多くなります。 * [Partitioning method selection] が RecastNavMesh の Generation カテゴリの [Advanced display] へ移動しました。 * 動的な障害物 (デフォルトで歩行可能なものに類似) 用にデフォルトのナビゲーション エリアが追加されました。これはゲーム専用の設定でオーバーライドすることができます。 * EQS デバッグ描画ツールが GameplayDebuggingComponent の表示に追加されました。 @@ -391,7 +393,7 @@ QA_APPROVED_UE4_BUILD_MINIMUM * アニメーション ノード選択時に構造体をカスタマイズするサポートが、ペルソナの詳細パネルに追加されました。 * スケルトンのプレビュー メッシュとペルソナの現在のプレビュー メッシュを別々に設定する機能が追加されました。 * プロパティのデフォルトとは別にプレビュー インスタンス上のプロパティをユーザーが編集できる新しいパネルがペルソナに追加されました。 -* コンテクスト オプション メニューが Animation Blueprint ノードに追加され、ユーザーは関連するアセットを開けるようになりました。 +* コンテキスト オプション メニューが Animation Blueprint ノードに追加され、ユーザーは関連するアセットを開けるようになりました。 * dirty marker がペルソナの Mode Widget に追加されました。 * Save context menu オプションがペルソナのアセット ブラウザに追加されました。 * インゲームのボーン描画を showdebug コマンドで切り替えられるようになりました。 @@ -409,7 +411,7 @@ QA_APPROVED_UE4_BUILD_MINIMUM * Shootergame にテキストチャットが追加されました。 * クラス ビューアのネイティブ クラスをダブルクリックすると IDE 内でヘッダ ファイルが開きます。 * エディタ ヘルプ メニューに API ドキュメントに対するショートカットが付きました。 -* 直近のプロジェクトを自動で読み込むためのオプションがプロジェクト ブラウザに追加されました。 +* 直近プロジェクトの自動読み込みオプションがプロジェクト ブラウザに追加されました。 * コリジョン:コリジョン チャンネル設定が Project Setting/Collision で可能になりました。 * PhysicalSurface :Physical Surface の設定が Project Setting/Physics で可能になりました。 * 自動化テストのコンフィギュレーション:各種自動化テスト アセットを Editor Setting/Automation に追加することができるようになりました。 @@ -421,7 +423,7 @@ QA_APPROVED_UE4_BUILD_MINIMUM * マテリアルごとのグループ化できるアクタ マージ ユーティリティが追加されました (Experimental->Actor Merging の中にあります)。 * デディケイテッド サーバーは、サーバー自体の ini ファイル (DedicatedServer*.ini) を同じディレクトリ内に Default*.ini として格納できるようになりました。 * UBT:TargetInfo クラスに Type プロパティと IsCooked プロパティが追加されました。これにより、クックされたターゲットのバイナリをビルドする場合、モジュールに条件付のビルド規則を設定することができます。 -* アセット レジストリ データとゲームコールバックに基いた、複数のパッケージファイルのビルド作成用の機能が追加されました (ゲーム ダウンロードのチャンキングに便利)。 +* アセット レジストリ データとゲームコールバックに基いた、複数の pak ファイルのビルド作成用の機能が追加されました (ゲーム ダウンロードのチャンキングに便利)。 * nullptr と 0 が BlueprintCallableFunctions ポインタのデフォルト引数として受け取られるようになりました。 * Interface UFunctions はフィールド イタレーションで検索できます。 * 新規の TFieldRange クラスは TFieldIterator と同じように使用されますが、使用対象は for (`UFunction* Func :TFieldRange(Class)`). @@ -449,7 +451,7 @@ QA_APPROVED_UE4_BUILD_MINIMUM * 最適化:SkeletalMeshes 向けの CachedLocalBounds 最適化が全てに対して有効にされました。 * **アニメーションは再保存が必要です** * GUID が Skeleton アセットに追加されたので、 アニメーションがバージョンをトラックできるようになりました。全てのアニメーションを再保存することを推奨します。再保存しない場合、アニメーションはゲームのロード時に圧縮されます。 -* 一様でないスケール アニメーションのサポーはスケーリングの適用時のみ使用できます (1,1,1 ではない場合など) +* 不均等なスケール アニメーションのサポーはスケーリングの適用時のみ使用できます (1,1,1 ではない場合など) * スケールのインポートがうまくいかない場合は、[Preserve Local Transform] を有効にします。 * 湾曲 / 共有はサポート外となります。情報は削除され、ソースデータとは異なる結果が作成されることにご注意ください。 @@ -457,387 +459,387 @@ QA_APPROVED_UE4_BUILD_MINIMUM ## アップグレード ノート #### エディタとツール -* コンテクスト メニューに Actors Delta Transform が選択されました。 -* シーンアウトライナーにキャッシュされていない静的ライトのビルド情報が表示されます。 -* 表示されるアクタをダンプするためのコンソール コマンド (DumpVisibleActors) が追加されました。 -* Atmospheric fog:Precompute 変数に対してブループリントのアクセスが追加されました (エディタのみ有効です)。 -* 10 進法のスナップグリッドがデフォルトで有効になり、スナップサイズが 10 cm になりました。以前のビヘイビアにリバートするためには、ビューポート設定でべき乗のスナップグリッドを有効にする必要があります。 -* エンジン コンテンツがコンテンツ ブラウザでデフォルトで無効にされました。コンテンツ ブラウザでのビュー設定でこれを再度有効にすることができます。 -* VirtualJoystick:UTouchInterface から値を継承します。 - * ジョイスティックのリセンタリングを防ぐ bPreventRecenter が追加されました。 - * 画面の外への移動を防ぎ、ThumbPosition が画面内になるようにクランプします。 - * 起動遅延が追加されました。 - * ジョイスティックごとに速度制御する InputScale が追加されました。 -* もう少し使いやすくするために ProjectileMovementComponent Velocity のデフォルトが (1,0,0) に設定されました。 -* GameModeForPIE を削除しました。 -* 含まれているウィジェットの親階層が有効化どうかを判断する SEnableBox が作成されました。 -* チェックアウト / 追加などを内部処理する外部画像参照ウィジェットができました。 -* アセット タイプ アクションがツールチップの別セクションにアセットのユーザーの説明を表示する機能を追加しました。 -* ストリーミング レベルのあるマップの新規プロセスでの起動と再生を修正するためにレベル ストリーミングをリファクタリングします。 -* ズーム レベルの鮮明度を維持し、カードカラーで原線を表示するように、グラフ パネル グリッドのレンダリング メソッドが変更されました。 +* Selected Actors Delta Transform for context menu. +* Show Uncached static Lighting build info in SceneOutliner. +* Added Console Command to dump visible actors ("DumpVisibleActors"). +* Atmospheric fog:Added Blueprint access for Precompute variables (only valid for editor). +* Decimal snap grid is now enabled by default and the snap size is now 10 cm.You will need to enable the power of two snap grid in the viewport settings to revert to the old behavior. +* Engine content has been disabled by default in the content browser.You can enable this again in the content browsers view settings. +* VirtualJoystick:Inherits values from UTouchInterface. + * Added bPreventRecenter, which prevents Joystick re-centering. + * Prevent moving outside of screen, clamp ThumbPosition to be inside screen. + * Added Activation Delay. + * Added InputScale to control each Joystick's speed. +* Default ProjectileMovementComponent Velocity to (1,0,0) to make it a bit simpler to use. +* Remove GameModeForPIE. +* Created SEnableBox, which lies to the contained widget about whether the parent hierarchy is enabled or not. +* Created an external image reference widget, which internally handles checkout/add/etc... +* Added the ability for asset type actions to provide a user description of the asset, showing up in a separate section of the tooltip. +* Level streaming refactoring to fix Launch and Play in new process for maps with streaming levels. +* Changed graph panel grid rendering method to keep sharpness at all zoom levels and show origin lines in a third color. #### レンダリング -* SSAO がさらに繊細になるようにデフォルトが変更されました。 -* Light プロパティをクリーンアップしました。大きな変更点:点 / スポットライトがデフォルトで逆2乗フォールオフを使うようになりました。Brightness が ライトのタイプごとに新しいデフォルトの Intensity に変更されました。Radius は AttenuationRadius に名前変更されました。 -* 今後のシェーダー最適化に備えて、パラメータを設定する前にシェーダーをグローバルステートにバインドすることが必要になりました。現在バインドされていないパラメータをシェーダーに設定しようとすると作成され確保されます。 -* SystemSettings からほぼ全ての設定が外され、同等のコンソール変数に置き換えられました。これには、GSystemResolution.ResX と GSystemResolution.ResY 経由でコードからのアクセスが可能になったシステム解像度 (GSystemSettings.ResX/ResY) が含まれます。新規コンソール変数 (r.setres) も以前の "setres" コマンドに置き換えるために追加されました。 -* クリッピング平面付近のデフォルトが 10cm に設定されました。そのため、ゲームでかなり長い表示距離を使用すると Z ファイティングが発生する場合があります。詳細は r.SetNearClipPlane を参照してください。 -* PostprocessAmbient が純粋に加算になり、環境感謝やその他のもの (SSAO 以外) にオクルードされなくなりました。遥か遠くのスカイボックス テクスチャではなく、もっと面白いアンビエント (コンテンツは再調整する必要があるかも知れません) を作成するためのものになりました。 -* TextRender デフォルト マテリアルが不透明に変更されました (TemporalAA クオリティの改善により、このオプションが可能になりました)。 -* ScreenPercentage を使うと、コンソールのメモリ使用量が少なります。複数のフレーム上で劇的に変更したい場合には、このメソッドは向いていません。必要であれば、cvars 設定を使って、プラットフォーム / ゲーム プロパティにすることができます。 -* 表示フラグのユーザビリティの変更: ゲームおよびおエディタの表示フラグ ステートを適切に切り替えられるようになりました (2 つのステートを保存および切り替えます)。 -* エディタで TemporalAA がデフォルトになりました (エディタ プリミティブによる点滅が若干予想されます)。 -* ScalabilitySetting パーシステンスをゲームとエディタに分けました (別々の ini ファイル)。そのため、設定の早めのロード (ゲームがまだない状態でも) が可能で、サブシステムの再初期化を防ぎます。 +* Changed SSAO defaults to be more subtle. +* Light properties cleanup.Major changes: point / spot lights use inverse squared falloff by default, Brightness changed to Intensity with new defaults per light type, Radius renamed to AttenuationRadius. +* To prepare for future shader optimisations, it is now a requirement to bind shaders to the global state BEFORE setting any parameters.Trying to set parameters on a shader which isn't currently bound will produce and ensure. +* Almost all settings have been removed from SystemSettings, and replaced with equivalent console variables.This includes system resolution (GSystemSettings.ResX/ResY) which are now accessible from code via GSystemResolution.ResX and GSystemResolution.ResY.A new console variable (r.setres) has also been added to replace the old "setres" command. +* The default near clipping plane has been set to 10cm.This may cause z-fighting if your game uses very long view distances.See r.SetNearClipPlane. +* Made PostprocessAmbient purely additive, not occluded by environment reflections or other things (other than SSAO), now it's meant to make an more interesting ambient (content might need to retweaked) not a infinitly far away skybox texture. +* Changed TextRender default material to be opaque (TemporalAA quality improvements now make this the better option). +* Consoles now use less memory when using ScreenPercentage.In case the game wants to dynamically change it over multiple frames this is not the right method.If needed we can use the cvars settings and make it a platform/game property. +* Usability change of showflags: game and editor showflag state now allows proper toggle (2 states are stored and toggled). +* Allow TemporalAA in editor by default (minor flickering with editor primitives is expected). +* Split ScalabilitySetting persistence into game and editor (different ini files).This allows early loading of the settings (even game isn't there yet) and avoid reinit of subsystems. #### ゲームプレイとフレームワーク -* Oculus integration が更新され、レイテンシーが改善され、ポジション トラッキング デバイスがサポートされました。注記:この機能を利用するには、ポジション トラッキングの LibOVR SDK を Oculus から購入しなければなりません。 -* コンポーネント配列が取り除かれました。 - * コンポーネント配列が取り除かれ、配列に新規コンポーネントを追加する必要はなくなりました。作成したコンポーネントを登録した場合は、 bAutoRegister を false に設定します。コンポーネント配列へは AActor::GetComponents 関数でアクセスします。コンポーネントがアクタとは無関係に作成された場合を除き、そのコンポーネントはアクタの直接外側にならなければなりません。通常、アクタ以外のサブオブジェクトであるコンポーネントを持つことはできません。 -* 入力バインディングの変更 - * キー バインディングが列挙型変数ではなく名前で行えるようになりました。新しい struct FKey により名前がカプセル化され、ヘルパー関数が数多く提供されます。ヘルパー関数の使用は IsGamePadKey などへを推奨しますが、EKeys::IsGamepadKey 関数も移行しやすいと定義されます。 - * EKeys 列挙型変数が削除されました。EKeys::Type または EKey を使用した部分は、通常 FKey に変更する必要があります。 - * EKeys を使った列挙型変数の入力 (例えば EKeys::MouseX) は全てEKeys struct の static const メンバへ変換されているのでキー名を使用してもまだ機能しますが、struct なので Key の値をつけることはできなくなりました。 - * 入力設定の多くは Engine.PlayerInput から Engine.InputSettings へ移されました。最も重要な注釈:AxisConfig、ActionMappings、AxisMappings です。 -* WorldFromContextGetter が削除されました。その代わり、UObjects はすべて GetWorld() というバーチャル関数を実行できるようになりました。 -* APlayerCamera が APlayerCameraManager に名前変更されました。 -* AxisMappings MoveForward、MoveRight、MoveUp、Lookup、Turn、 ActionMapping PushToTalk が BaseInput.ini から削除されました。特定のゲームで必要な場合は DefaultInput.ini に追加しなければなりません。 -* SoundNodeGroupControl が距離を考慮しなくなりました。その代わり、バケットごとの最大サウンド数が次のバケットに行く前に再生されることを確実します。 -* SoundNode NotifyFinished の接続が再構築されました。複数のノードがウェーブ インスタンスの完了通知を要求できるようになりました。 -* UMETA がその他のマークアップ マクロと整合性が取れました。特にデリミターとしてパイプではなくコンマを使うようになりました。 -* Visual Studio 2013 がデフォルトで使用できるようになりました。 - * デベロッパー (and users of packaged builds) は Visual C++ 2013 Redistribution をインストールする必要があります。 - * 必要に応じて Visual Studio 2012 も使用できます (詳細は以下および CL # 1989640 をご覧ください)。 - * 特定のプラットフォームにはデバッグ用アドインが付いており、新しい IDE とは機能しません。 - * これらのプラットフォームが検出され、プロジェクト ファイル フォーマットが自動的に 2012 にされます。 - * GenerateProjectFiles コマンド ライン上に '-2012' あるいは '-2013' を渡せば、いつでもビヘイビアをオーバーライドできます。 - * その他の特別なユースケース: - * すべてに VS 2012 を使いたい場合は (VS 2013 をまだお持ちでないため)、UEBuildWindows.cs. で WindowsPlatform.Compiler をローカルで変更してください。 - * VS 2012 IDE はそのまま使い続けて VS 2013 にコンパイルする場合は、必ず VS 2013 がインストールされていることを確認して '-2012' を GenerateProjectFiles に渡してください。 - * VS 2013 IDE を使ってVS 2012 でコンパイルする場合、 WindowsPlatform.Compiler を 2012 に設定しますが、'-2013' を GenerateProjectFiles に送ります。 -* Windows Desktop Visual Studio 2013 Express for Windows Desktop が完全にサポートされるようになりました! -* DirectX SDK の前提条件がソースも含まれています! - エンジンをビルドするために DirectX SDK を PC にインストールする必要はなくなりました。 -* Visual Studio と Xcode プロジェクト ファイルの変更 - * プロジェクト ファイルが全てのプラットフォームに対してデフォルトで生成されるようになり、 「AllPlatforms" .bat」ファイルは削除されました。 - * -CurrentPlatform を渡せば、以前のビヘイビアにもどすことができます。 - * プロジェクト ファイル:シッピング コンフィギュレーションがデフォルトで含まれるようになりました。 - * シッピング コンフィギュレーションを省くためには "-NoShippingConfigs" を渡します (プロジェクト ファイルをさらに小さく / 速くなります)。 -* デバッグ ビルドがデフォルトでは CRT デバッグ (またはサードパーティ デバッグ ライブラリ) を使わなくなりました。 - * 新しい UnrealBuildTool オプションである bDebugBuildsActuallyUseDebugCRT (BuildConfiguration.cs) が追加されました。 - * bDebugBuildsActuallyUseDebugCRT:CRT デバッグとサードパーティ デバッグ ライブラリへ依存してデバッグ ビルドをコンパイルする場合に当てはあります。そうでない場合は、実際にリリース CRT に対してコンパイルしますが、最適化はオフのままなので、デバッグは簡単です。 - * この設定を有効にすると、デバッグでのコンパイル時にサードパーティの stats ライブラリの実際の Debug バージョンが必要になります。 -* Shipping PhysX バイナリとライブラリが削除されました。 - * デフォルトですべてのコンフィギュレーションの PROFILE バージョンとリンクするようになりました。 -* デフォルトのストリーム ファイルをバイナリから削除しました (steam_appid.txt) 。 - * プロジェクト用の一意の Steamworks ID でゲーム プロジェクト用に steam_appid.txt を作成してください。 -* Shipping ビルドの場合でも、デフォルトで Link-Time-Code-Generation (LTCG) が無効になりました。 -* (重要) DebugGame ビルド コンフィギュレーションが開発コンフィギュレーションとエンジン バイナリを共有するようになりました。 - * DebugGame により、ゲーム モジュールが UE_BUILD_DEVELOPMENT でコンパイルされますが、最適化は無効化されます。 - * -debug をコマンドライン上にパスして、エディタに DebugGame ゲーム モジュールをロードするように命令します。 - * Intermediate\ProjectFiles からユーザー コンフィギュレーション ファイルを削除して、UBT が正しいコマンドラインをプロジェクト設定に自動記入するようにしました。 -* インストールされたビルドの Config 設定は、マイドキュメントではなくユーザーの AppData フォルダに格納されるようになりました。 -* テンプレート プロジェクトに再び .uproject 拡張子が付きました。 -* エンジンのバージョンにチェンジリスト番号に加えて Major.Minor.Hotfix コンポーネントが追加されました (FEngineVersion)。このバージョンは帯域外ホットフィックスを可能にするためにパッケージ内に保存されます。 - * エンジンがモジュールをロードするには、PCLaunch.rc から正しいバージョンの文字列でモジュールを再コンパイルする必要があります。 -* config ファイルでプラグイン リストを有効化すると、モノリシック (単一) ビルドでプラグインをコンパイルするための決定がフィルタされるようになります。 -* LevelEditor: 機能がまだ完全に実装されていないので、"Mobile Preview" メニューは非表示にされています。 -* LevelEditor: "-PlatformTools" コマンドライン スイッチが削除されました。それに依存していた残りの機能は Editor Preferences の [Experimental] セクションから利用できます。 -* 設定: エディタ ユーザー設定のほとんどが新規クラスへ移動され、Settings UI の別のセクションとしてエクスポーズされました。 ローカル設定を再度適用する必要があるかもしれません。 -* メッセージング:UDP メッセージ送信がデフォルトでロードされるプラグイン (UdpMessaging) になりましたが、Shipping ビルドとスタンドアローン型ゲームでアクティベートするための "-messaging" コマンドライン スイッチはまだ必要です。このプロトタイプ実装がプロダクション品質に対して書き換えられています。 +* Oculus integration has been updated with improvements to latency, and support for positional tracking devices.Note:LibOVR SDK for positional tracking must be procured from Oculus in order to use the functionality +* Components Array removal + * The components array has been removed, it is no longer necessary to add newly created components to any array.If you do not wish a created component to be registered set bAutoRegister to false.Access to the components array is via the AActor::GetComponents function.Unless a component is created independently of an Actor, the component must have a direct outer of the Actor.In general, you cannot have components that are subobjects of a non-actor. +* Input binding changes + * Key bindings are now done by name instead of enum.A new struct FKey encapsulates the name and provides a number of helper functions.It is encouraged to use these helper functions for things such as IsGamePadKey, however, the EKeys::IsGamepadKey functions are still defined to make migration easier. + * EKeys enum has been eliminated.Places that used EKeys::Type or EKey will generally need to be changed to FKey + * All EKeys enum entries (e.g. EKeys::MouseX) have been translated in to static const members of an EKeys struct so most usages of key names will still work, however, because it is a struct you can no longer switch on a Key's value. + * Many Input settings have been moved out of Engine.PlayerInput and in to Engine.InputSettings.Of most significant note:AxisConfig, ActionMappings, and AxisMappings. +* WorldFromContextGetter has been removed.All UObjects can now implement a virtual GetWorld() function instead. +* APlayerCamera has been renamed APlayerCameraManager. +* AxisMappings MoveForward, MoveRight, MoveUp, Lookup, and Turn and ActionMapping PushToTalk have been removed from BaseInput.ini.They must be supplied in the DefaultInput.ini for your specific game if required. +* SoundNodeGroupControl no longer considers distance.Instead it simply ensures that the maximum number of sounds for each 'bucket' is playing before falling to the next 'bucket'. +* SoundNode NotifyFinished hooks have been restructured.It is now possible for multiple nodes to request notification of the wave instance completing. +* UMETA is now consistent with other markup macros, in particular it uses comma instead of pipe as delimeter. +* Visual Studio 2013 is now used by default + * Remember that your developers (and users of packaged builds) will need the Visual C++ 2013 redist installed. + * You can still use Visual Studio 2012 if you need to (see below for more info, and CL # 1989640). + * Certain platforms have debugging add-ins that do not work with the new IDE yet. + * We detect these platforms and force the project file format to 2012 automatically. + * You can always override behavior by passing '-2012' or '-2013' on the GenerateProjectFiles command line. + * Other special use cases: + * If you want to use VS 2012 for everything (because you don't have VS 2013 yet), locally modify WindowsPlatform.Compiler in UEBuildWindows.cs. + * If you want to keep using VS 2012 IDE but compile with VS 2013, make sure you have VS 2013 installed and pass '-2012' to GenerateProjectFiles. + * If you want to use the VS 2013 IDE but compile with VS 2012, you can set WindowsPlatform.Compiler to 2012, but pass '-2013' to GenerateProjectFiles. +* Visual Studio 2013 Express for Windows Desktop is now fully supported! +* DirectX SDK prerequisites are now included along with the source! + You no longer need to have the DirectX SDK installed on your PC to build the engine. +* Visual Studio and Xcode project file changes + * Project files now generate for all platforms by default; Removed "AllPlatforms" .bat file. + * You can pass "-CurrentPlatform" to get the old behavior if you want. + * Project files:'Shipping' configuration is now included by default. + * You can pass "-NoShippingConfigs" to omit Shipping config (smaller/faster project files). +* Debug builds no longer use the Debug CRT (or Debug third party libraries) by default + * Added new UnrealBuildTool option: bDebugBuildsActuallyUseDebugCRT (BuildConfiguration.cs) + * bDebugBuildsActuallyUseDebugCRT:This is true if we should compile Debug builds using Debug CRT libs and Debug third party dependencies.Otherwise, we'll actually compile against the Release CRT but leave optimizations turned off, so that it is still easy to debug. + * If you enable this setting, actual Debug versions of third party static libraries will be needed when compiling in Debug. +* Removed 'Shipping' PhysX binaries and libraries + * We now link with PROFILE versions in all configurations by default. +* Removed default Steam file from binaries (steam_appid.txt) + * You should create your own steam_appid.txt for your game project with a unique Steamworks ID for your project. +* Disable Link-Time-Code-Generation (LTCG) by default, even in Shipping builds +* (IMPORTANT) The DebugGame build configuration now shares engine binaries with the Development configuration. + * DebugGame causes game modules to be compiled with UE_BUILD_DEVELOPMENT, but optimization disabled. + * Pass -debug on the command line to tell the editor to load DebugGame game modules. + * Delete user configuration files from Intermediate\ProjectFiles to have UBT automatically fill in the correct command line in your project settings. +* Config settings for installed builds are now stored in the user's AppData folder, rather than My Documents. +* Template projects now have a .uproject extension again. +* The engine version now has a Major.Minor.Hotfix component as well as changelist number (FEngineVersion).This version is saved into packages to allow for out of band hotfixes. + * Modules will need to be recompiled with the correct version strings from PCLaunch.rc for the engine to load them. +* Decision to compile plugins in monolithic builds is filtered by the enabled plugin list in config files. +* LevelEditor: the "Mobile Preview" menu has been hidden, because the functionality isn't fully implemented yet +* LevelEditor: the "-PlatformTools" command line switch has been removed; the remaining features that depended on it are now accessible in the 'Experimental' section of the Editor Preferences +* Settings: many Editor User Settings have been moved into new classes and exposed as separate sections in the Settings UI; your local settings changes may have to be reapplied +* Messaging:UDP message transport is now a plug-in (UdpMessaging) that is loaded by default, but still requires "-messaging" command line switch to activate in Shipping builds and standalone games; we are planning to get rid of the switch after this prototype implementation has been rewritten for production quality; no ETA yet #### アニメーション -* anim sequence プロパティと blendspace プロパティがグラフのピンとしてエクスポーズされました。 -* 既存の Anim ブループリント (デフォルトとイベント グラフはオーバーライドが可能ですが、アニメーション グラフは不可能です) から継承するためのサポートが追加されました。 -* 利用可能なスペースが改善され、レベル エディタと同様に振舞うように、ペルソナのビューポートのツールバーとウィジェットがリファクタリングされました。 -* Anim ブループリントのデバッグ中の各種バグが修正されました。 -* ボーン名に対するスケルトン ツリー ピッカーを表示する FBoneReference 構造体のカスタマイズが追加されました。 -* Animation Player ノード上のアセット ピッカーにフィルタリング ロジックが追加されたので、(スケルトンに基いて) 互換性のあるアセットのみが表示されます。 +* Allowed anim sequence and blendspace properties to be exposed as a pin in the graph. +* Added support for inheriting from an existing Anim Blueprint (allowing overriding the defaults and event graph, but not the anim graph). +* Refactored the Persona viewport toolbar and widgets, improving real estate usage and behaving similar to the level editor. +* Various bug fixes for Anim Blueprint debugging. +* Added a customization for FBoneReference structures, showing a skeleton tree picker for the bone name. +* Added filtering logic to asset pickers on anim player nodes so that only compatible assets (based on skeleton) are shown. #### コア -* プラットフォームごとに中間ファイルが生成されるようになりました。 - * 生成されたファイルに対して何らかの処理を行うツールがあれば、それらは新しい場所へ変更する必要があります。 -* C++ の const_cast とは別物で紛らわしい ConstCast が削除されました。 - * `ConstCast` は `Cast` で置き換えてください。 -* ガーベッジの収集にシリアル化を使用しないため誤解されやすいので、UObjectSerializer は UGCObjectReferencer に、 FSerializableObject は FGCObject に名前が変更されました。 -* ライセンシーからのアクションを必要とするコードのリファクタリングを行いました: - * GIsUCC は IsRunningCommandlet() (ほぼ) に名前が変更されました。 - * USpriteComponent は UBillboardComponent に名前が変更されました。 - * UMaterialSpriteComponent は UMaterialBillboardComponent に名前が変更されました。 +* Intermediate generated files are now per-platform. + * If you have tools which do any kind of processing on generated files, then these will need to be updated to the new locations. +* ConstCast has been removed, because it's confusingly unlike C++'s const_cast. + * `ConstCast` should be replaced with `Cast`. +* Renamed UObjectSerializer to UGCObjectReferencer and FSerializableObject to FGCObject as they do not use serialization to collect garbage anymore and may be misleading. +* Code refactoring that requires action from licensees: + * Renamed GIsUCC to IsRunningCommandlet() (mostly) + * Renamed USpriteComponent to UBillboardComponent + * Renamed UMaterialSpriteComponent to UMaterialBillboardComponent #### プラットフォーム -* **モバイル** - * タッチ入力インターフェース プロパティがエクスポーズされ Setting UI で編集可能になりました。 - * Android 向けのプラットフォーム固有のコンフィギュレーション ファイルのコピーが [Setting] パネル経由で追加されました。 - * [Project Settings] でのアイコン、起動画面、デバイスの方向の編集機能が追加されました。 - * クックされたゲーム用の様々なパッケージ サイズの最適化を行いました。 +* **Moblie** + * Exposed touch input interface properties to be editable in the Settings UI. + * Added copying of platform-specific configuration files for Android and iOS via the Settings panel. + * Added editing for icons, launch screens, and device orientation in Project Settings. + * Various packaging size optimizations for cooked games. * **Android** - * Package と Launch でエディタから直接 Android のサポートが有効にされました (別名 One Click Deploy) 。 - * Android をパッケージすると、 .apk の隣に .obb ファイルが作成され、 .bat がインストールされます。 - * Packaging in Distribution には SigningConfig.xml が適切に設定されなければなりません (サンプルは Engine/Build/Android/Java をご覧ください)。 - * java ファイルの .so が変更された場合のみ、.apk が生成されるようになりました。 + * Enabled Android support directly from the editor with Package and Launch (aka One Click Deploy). + * Packaging Android will create a .obb file next to the .apk, with a .bat to install it. + * Packaging in Distribution needs SigningConfig.xml to be setup properly (see sample in Engine/Build/Android/Java). + * .apk generation now only happens if .so of java files have changed. * **Mac** - * Mac エディタは機能しますが、 ビルド済みのバイナリは本リリースには含まれません。 - * 今のところ、Mac でエディタを動かすためには、バイナリのコンパイルが必要になります。 - * 本件については次回の QA ビルドで解決します。 - * Unreal Frontend は Mac 上で機能します。 + * Mac editor works but pre-built binaries are not included with this release. + * For now, you must compile the binaries in order to run the editor on Mac. + * This will be resolved for the next QA build. + * Unreal Frontend works on Mac. **iOS** - * iOS ビルドおよびパッケージングは Mac 上で行えます。 - * GameCenter OSS に対して様々な修正や改善が行われました。 - * 実験的な iAD サポートが iOS に追加されました。 - * iOS6で出てしまうアイコンの gloass effect が修正されました。 - * Shipping iOS ビルド向けに常にシンボル ストリップするようにしました。 - * PC iOS デプロイメント ワークフローに対し様々な改善が行われました (エディタからコードを署名し、環境変数 uebp_CodeSignWhenStaging=1 を設定しますが、 PC にインストールしたプロビジョニング ファイルに対し有効な認証が必要となります)。 - * UE3 からの iPhonePackager の各種変更点 (ファット バイナリ、スタブに事前割り当てされたサイズを超えるコード署名の修正など) がマージされました。 + * iOS build and packaging works on Mac. + * Various fixes and improvements to GameCenter OSS. + * Added experimental iAD support for iOS. + * Fixed icon glossy effect showing up on iOS6 incorrectly. + * Forced symbol stripping to always be on for Shipping iOS builds. + * Various improvements to the PC iOS deployment workflow (to code sign from the editor, set environment variable uebp_CodeSignWhenStaging=1, but you will have to have a valid certificate for your provision installed on the PC). + * Merged various iPhonePackager changes from UE3 (fat binary support, fix for code signing extending beyond the preallocated size in the stub, etc...). + #### Networking -#### ネットワーキング -* 新しい bool 型変数の bReplicates が追加されました。アクタをリプリケートするために、ブループリントと C++ コンストラクタ に設定してください。手書きで RemoteRole=ROLE_SimulatedProxy を設定する必要がなくなりました。 +* A new bool has been added, bReplicates.This should be set in blueprints and C++ constructors to make an actor replicate.Setting RemoteRole=ROLE_SimulatedProxy manually is no longer necessary. -## 今後の追加事項と継続事項 +## 今後の追加事項と継続項目 #### エディタとツール -* エフェクトのない Material プロパティが正しくグレーアウトされました。 -* 新規マテリアル エディタ内で一番互換性のない接続がされないようにしました。 -* イタレーション中にスポーンされたアクタがそのイタレーションに正しく含まれることを確実にしました。 -* SoundNode 入力の削除が元にもどせることを確実にしました。 -* 入力マッピングの表示が改善されました。 -* Static Switch パラメータが Material Attribute 入力を出力するようになりました。 -* 入力プロジェクト設定に充実したツールチップが追加されました。 -* アセットのドラッグ&ドロップ時にはカーソル インジケータが、アクタ上へのテキストのドロップ時には警告が追加されました。 -* アクタの移動をロックすれば、プロパティ マトリクスにおいて変形の編集ができないようになりました。 -* カラーピッカーの再生成時にテーマがリセットされます。 -* 新規プロジェクトの作成時に表示されるメッセージに IDE 名が追加されました。 -* コンテンツ ブラウザ スプリッタのサイズがセッション間で維持されるようになりました。 -* アセットの正しい名称を Matinee が表示するようになりました。 -* SETRES コンソール コマンドがスタンドアローン ゲームの PIE で (およびコマンドライン上で ResX/ResY が指定された場合) 動くようになりました。 -* アセット名を変更する場合、 `*\<>?` 文字が入力できないようになりました。 -* 「コンテンツ ブラウザで検索」が直前にクリックしたコンテンツ ブラウザを使用するようになりました。 -* [Play From Here] オプションがシーンアウトライナーから利用できるようになりました。 -* RF_Transactional でシリアル化されている場合、アセットに RF_MarkPendingKill を追加できないようになりました。 - * オブジェクトを間違ってアンドゥ バッファへ挿入できないようにしました。 -* Key struct カスタマイズのサイズ設定がより合理的になりました。 -* 新しく作成されたエディタはデフォルトが Subversion のソースコントロールではなくなりました。 -* 現在の BP エディタ モードのブループリント チュートリアル フロー&オートランの適切なチュートリアルが再調整されました。 -* CTRL+Backspace と CTRL+Delete (delete-to-word-boundary) ホットキーがテキストボックスで機能するようになりました。 -* CTRL を押下したままマウスをキーの上に置かなくても、ユーザーは選択したキーをカーブエディタで移動できるようになりました。 -* BSP ブラシがエディタの可視性設定を順守するようになりました。 -* リプリケートされる設定のブループリント変数ノードにアイコンが追加されました。 -* シーンアウトライナーのフッターに選択されたアクタ数が表示されるようになりました。 -* [Escape Now] を押すとすべてのポップアップ ウィンドウが閉じ、 ドラッグ - スピン操作とアクタ ビューポート ドラッグ操作が取り消されます。 -* ファイルパスを再インポートすると、関連したパッケージに相対して格納されるようになりました。 -* 正投影ビューポート上のスケールにビジュアル キューが追加されました。 -* [Reset] ボタンで [Details] パネル上でのアクタ変形を終了できるようになりました。 -* Mesh Paint モードでバケツを選択対象の周りに表示させることができなくなりました。 -* サーベイをキャンセルするとすぐに消えてなくなるようになりました。 -* [Matinee track] メニューのオプションがトラック名と一致するようになりました。 -* InterpTrack クラスに不足していた meta タグが追加されました。 -* プロジェクト ブラウザの説明にプロジェクト作成が含まれなくなりました。 -* 共有の interp データを使用しても Matinee がクラッシュしなくなりました。 -* 新しいエディタ版からプロジェクトを開くと、見事に失敗します。 -* オブジェクト名に「`」を含むことができなくなりました。 -* サウンド キューの「Stop」がストップのシンボルのようになりました。 -* [Show Folder] オプションはコンテンツ ブラウザ以外では無効にされました。 -* スタティック メッシュ エディタの LOD メッセージが LOD Index を正しく表示するようになりました。 -* シーン アウトライナーのソートの矢印がはっきり表示されるようになりました。 -* デフォルトのキーバインディングがユーザー設定に正しく表示されるようになりました。 -* アセットがロードされるとフィルタがアセットとして優先されるように、コンテンツ ブラウザのアセットが更新されました。 -* 正投影ビューポートがビューモードを正しく表示するようになりました。 -* 言語 / 地域を変更するとユーザーに再起動を促すようになりました。 -* スケルタル メッシュ アクタのクラス ピッカーがスケルトンによる選択プールを正しく制限するようになりました。 -* Anim graph ノードの [Details] パネルが子も一緒に正確にプロパティを表示するようになりました。 -* FBX window のツールチップが改善されました。 -* ペルソナでモーフターゲットの取り消しができるようになりました。 -* スケルタル メッシュの情報がペルソナ ビューポートにデフォルトで表示される設定になりました。 -* ペルソナでの通知がエディタの削除コマンドに反応するようになりました。 -* Blendspace シーケンス アセットはペルソナのサンプルから直接開けるようになりました。 -* FBX エクスポート ファイルの位置選択が改善されました。 -* Blendspace ノードの削除と取り消しが正常に機能するようになりました。 -* アニメーション グラフのステートマシンはコピーされた時に名前を維持するようになりました。 -* 充実したツールチップが多くの Animation graph ノードに追加されました。 -* 再生タイムラインは重複したフレーム番号を表示しなくなりました。 -* ブループリント エディタとペルソナのカラーピッカーが改善されはっきり見えるようになりました。 -* 頂点アニメーションはフィルタ機能がなくなりました。 -* PhAT でのフライト制御は 変形モード選択とのコンフリクトを発生しなくなりました。 -* 基本ポーズがリターゲット ソースと呼ばれるようになりました。 -* UnrealVS は VS2012 Pro と VS2013 Pro 向けにビルドされるようになりました。Engine/Extras でそれぞれ専用のフォルダで別々にビルドされます。 -* アンリアル エディタ プラグインのベータ版フラグはアンプラグ ファイルでプラグイン デベロッパーが設定することができます。 - * ベータ版のプラグインはプラグイン マネージャで有効にされると警告が表示されます。 - * ベータ版の情報はプラグイン マネージャでバージョン番号と一緒に表示されます。 +* Material Properties are now correctly greyed out when they have no effect. +* Prevented most incompatible connections in the new Material Editor. +* Made sure actors spawned during iteration are correctly included in the iteration. +* Made sure deletion of SoundNode inputs can be undone correctly. +* Improved display of Input mappings. +* Static Switch Parameters now output any Material Attribute inputs. +* Added rich tooltips for the Input Project Settings. +* Added cursor indicator when drag-dropping assets & a warning when dropping textures on actors. +* Locking actor movement now prevents editing of transform in Property Matrix. +* Reset themes menu when color picker is re-created. +* Added IDE name to message displayed when new project is created. +* Content Browser splitter sizes are now preserved between sessions. +* Matinee now displays correct name for asset. +* SETRES console command now works in PIE in standalone game (and when specifying ResX/ResY on the command line). +* Asset rename now prevents `*\<>?` characters from being entered. +* "Find In Content Browser" now uses the last content browser that was clicked. +* "Play From Here" option is now not available from Scene Outliner. +* Prevented assets from getting RF_MarkPendingKill added when they have been serialized with RF_Transactional. + * Prevents some objects being wrongly inserted into the undo buffer. +* Key struct customization is now sized more reasonably. +* A newly-created editor no longer defaults to Subversion source control. +* Rearranged Blueprint tutorial flow & auto-run appropriate tutorial for current BP editor mode. +* CTRL+Backspace and CTRL+Delete (delete-to-word-boundary) hotkeys now work in text boxes +* Users can now move selected keys in the curve editor without having the mouse over a key by holding CTRL. +* BSP brushes now respect editor visibility settings +* Added an icon to blueprint variable nodes that are set to be replicated. +* Scene outliner now displays the number of selected actors in its footer. +* Pressing escape now closes any popup windows, cancels drag-spinning and actor viewport dragging operations. +* Reimport file paths are now stored relative to their associated packages, where this makes sense. +* Added visual cue for scale on orthographic viewports. +* Reset buttons now exist for actor transforms on the details panel. +* Mesh Paint mode no longer forces backets to be displayed around the selection. +* Cancelling survey now fades away instantly. +* Matinee track menu options now match their track names. +* Added missing meta tags for InterpTrack classes. +* Project browser description no longer mentions creating a project. +* Matinee no longer crashes when using shared interp data. +* Opening projects from newer editor versions now fails gracefully. +* Object names can no longer contain the letter `. +* Sound Cue 'Stop' now looks like a stop symbol. +* Show Folder options is now disabled except for the Content Browser. +* Static Mesh Editor LOD Message now correctly displays the LOD Index. +* Scene outliner sorting arrow is now more visible. +* Default keybinding now appears correctly in Preferences. +* Content Browser assets update to respect filters as assets are loaded. +* Ortho viewport now display the correct viewmode. +* Changing language/region now prompts user to restart. +* Class picker in skeletal mesh actors now correctly restricts selection pool by skeleton. +* Anim graph node details panel now correctly shows properties with children. +* Improvements to FBX window tooltips. +* Morph target deletion in Persona can now be undone. +* Skeletal mesh stats set to default appear in Persona viewport. +* Notifies in Persona now respond to editor delete command. +* Blendspace sequence assets can be opened directly from the samples in Persona. +* Improvements to FBX export file location selection. +* Deleting and undoing blendspace nodes now works correctly. +* State machines in animation graphs preserve their name when copied. +* Rich tooltips added to many animation graph nodes. +* Playback timeline no longer shows duplicate frame numbers. +* Colour pickers in the blueprint editor and Persona improved to be more visible. +* Vertex anims no longer filterable. +* Flight controls in PhAT no longer conflict with transform mode selection. +* Base pose now called Retarget Source. +* UnrealVS is now built for VS2012 Pro and VS2013 Pro, with separate builds in their own folders in Engine/Extras. +* Beta version flag in Unreal Editor plugins can be set by plugin developers in the uplugin file. + * Beta plugins display a warning when enabled in the plugin manager. + * Beta version info is displayed with the version number in the plugin manager. * **ランドスケープ** - * カメラを動かしている間、ランドスケープ ブラシは非表示になりました。 - * デフォルトのランドスケープのスケールが 100、100、100 に変更されました。 -* シューティング ゲームのスポーン ポイントを調整してボットがもっと広まるようにしました。 -* シューティング ゲームのボットのビヘイビアが修正され、発砲できるようになりました。 -* シューティング ゲームのスコアボードに修正をいろいろ加えました。 -* ビークル ゲームでブースト ピックアップが再スポーンされるように変更されました。 -* ビークル ゲームの hovership におけるゲーム インターフェースの使い方がリファクタリングされました。 -* スレート:スレート コア内部のウィジェットが FEditorStyle に依存しなくなりました。 -* ShooterGame、StrategyGame、VehicleGame:Slate Widget Style アセットを使用するように変換され、 FEditorStyle に全く依存しなくなりました。 -* インポート:FBX ログメッセージが Log ウィンドウに送られるようになりました。 -* TextureEditor: テクスチャ エディタのツールバーからテクスチャを再インポートできるようになりました。 -* エディタの翻訳 (作業進行中): - * 取り消し / やり直しがサポートされます。 - * 実際にデータが変更された時のみファイルへ保存されます。 - * 列の挿入/削除/複製ができないようになりました (array UProperty 上に EditFixedSize タグが必要でした)。 - * 履歴がロードできない、またはソース コントロールが無効だとエラーが表示されます (トースト機能 + メッセージログですが、メッセージログは表示されません)。 - * 現在のマニフェストやアーカイブがロードできないとエラーが表示されます (トースト機能 + メッセージログで、メッセージログが表示されます)。 - * ファイルのチェックアウト / 保存に失敗するとエラーメッセージ、成功すると通知が表示されます。 - * 保存のたびにパーフォース上のアーカイブをチェックアウトするのではなく、私達がチェックアウトしていることを覚えておいてください。 - * [Find in Content Browser] とメニューアイテムが削除されました。 - * タブの名前を「TranslationDataObject_1」から「Language Name - Project Name - Translation Editor」に修正しました。 + * Landscape brush is now hidden while moving the camera. + * Default landscape scale has been changed to 100,100,100. +* Adjusted shootergame spawn points to spread bots out more. +* Revised shootergame bot behaviour to allow them to fire up/down. +* Made various revisions to scoreboard in shootergame. +* Revised boost pickups in vehicle game to make them respawn. +* Refactored game interface usage in vehicle game, hovership. +* Slate:Widgets inside the Slate core no longer depend on FEditorStyle. +* ShooterGame, StrategyGame, and VehicleGame:Converted over to use Slate Widget Style assets, and now has no dependency on FEditorStyle. +* IMPORT:FBX Log messages now goes to Log window. +* TextureEditor: textures can now be reimported from the Texture Editor's toolbar. +* Translation Editor (Work in progress): + * Undo/Redo support + * Only save to file when data has actually changed + * Prevent insertion/deletion/duplication of rows (needed EditFixedSize tag on array UProperty). + * Show error if history can't be loaded, or source control disabled (toast + message log, but don't display message log). + * Show error if can't load current manifest or archive (toast + message log, show message log). + * Show error if check-out/save file failed, or notification if it succeeded. + * Don't try to check out the archive on the perforce server every time we save, but instead remember that we checked it out. + * Remove "Find in Content Browser" button and menu item. + * Correct tab title from "TranslationDataObject_1" to "Language Name - Project Name - Translation Editor." #### レンダリング -* 反射環境とスカイ スペキュラ上の最小ミップが削除され、ラフなマテリアルが完全にディフューズされないようになりました。 -* 反射環境が機能レベル SM4 に対応しました。 -* LightAsIfStatic が可動スタティック メッシュ上で再び使用できるようになりました。 -* スカイライトがコンストラクション スクリプトにおいて正しく再キャプチャするようになりました。 -* 選択された BSP サーフェスが、エディタの中の他のオブジェクトのビジュアル化と一致してビジュアル化されるようになりました。 -* 実験的な機能だった TemporalUpsample が削除されました (既存フレームから中割りフレームの再構築)。 -* 実験的な機能だった r.MSAA.DeferredMode が削除されました (メモリ インテンシブ AA ソリューション)。 -* BlurGBuffer 機能が削除されました (TemporalAA add NormalRoughnessToAlpha はほとんど必要なかったため、使用することもほとんどありませんでした)。この機能はStereoRendering では動きませんでした。 -* EngineShowflags 定義コードがリファクタリングされました。 - * フラグが特定のビルド コンフィギュレーションに固定されている場合、コンパイラの最適化が可能になります。 -* **最適化** - * プリミティブがオブジェクト シャドウごとにキャストする必要がある場合のみ、可動指向性ライトに対するプリミティブ / ライトのインタラクションが作成されます。 - * シングルスレッド処理のレンダリング パフォーマンスに対して、マイナーな改善がいろいろなされました。 - * グローバルな動的頂点とインデックス バッファからの割り当ては、小さめのバッファのプールを使って強化されました。 - * モバイル向けシェーダーが多数最適化されました。 - * 描画リストが描画ポリシー内で手前から奥に向かってソートできるようになりました。これにより、 非表示のサーフェスを削除しなくてもモバイルデバイス上でのパフォーマンスが大幅に改善されます。 +* Removed min mip on reflection environment and sky specular - was preventing rough materials from going all the way diffuse. +* Reflection environment support for Feature Level SM4. +* LightAsIfStatic is now usable on movable static meshes again. +* Sky lights now recapture properly in construction scripts. +* Visualization of selected BSP surfaces now matches that of other objects in the editor. +* Removed experimental TemporalUpsample feature (reconstructing inbetween frames from existing frames). +* Removed experimental feature r.MSAA.DeferredMode (memory intensive AA solution). +* Removed BlurGBuffer feature (rarely used, since TemporalAA add NormalRoughnessToAlpha barely needed), feature didn't work with StereoRendering. +* Refactored EngineShowflags definition code. + * Allows compiler optimizations when flags are fixed for certain build configurations. +* **Optimization** + * Primitive/light interactions for movable directional lights are only created if the primitive needs to cast a per-object shadow. + * Numerous small improvements to single threaded rendering performance. + * Allocations from the global dynamic vertex and index buffers are now backed using a pool of smaller buffers. + * Numerous mobile shader optimizations. + * Draw lists can now be sorted front-to-back within a drawing policy, greatly increases performance on mobile devices without hidden surface removal. * **Android** - * Android デバイス上でモザイク フォールバックを使用すると、 画面解像度が 1024 にクランプされます。精度に限界のある GlFragCoord では、これが必要となります。 - * Kindle Fire HDX と Galaxy S4 が FP16 レンダー ターゲットを使用するようになりました。 + * Clamp screen resolution to 1024 when using the mosaic fallback on Android devices.This is necessary due to limited precision in glFragCoord. + * Kindle Fire HDX and Galaxy S4 now use FP16 render targets. #### ブループリント -* ブループリント パレット / コンテクスト メニュー内のブループリント ノードの分類が改善されました。 - * ノード分類を整理するための初回パスを作成しました (ノードはより見つけやすくしつつカテゴリ数を減らす目的)。完全ではありませんが、イタレートし続けているので徐々に良くなっています。 -* ブループリント コンポーネント 変数が Default カテゴリに割り当てられるようになりました。 -* 配列のエレメントをオブジェクト インスタンスへシリアル化する前に内部タイプ情報が完全にロードされていることを配列プロパティが確認するようになりました。 -* ブループリント アセットの取り込み中、無駄なアサートが取り除かれました。 -* ブループリントの [Variable Details] パネルに Transient および Save Game フラグが追加されました。 -* BlueprintType が継承されないように、NotBlueprintType のサポートが UClass headers に追加されました。 +* Better categorizing of blueprint nodes in the blueprint palette/context menu. + * We've made an initial pass to clean up the node categorization (aiming to slim down the number of categories, while making nodes more discoverable)� while it's not perfect, we continue to iterate on it, bettering it as we go. +* Blueprint component variables are now assigned to the "Default" category. +* Array properties will now ensure that internal type information has been fully loaded prior to serializing elements of the array into an object instance. +* Removed an unnecessary assertion during Blueprint asset loading. +* Added "Transient" and "Save Game" flag to variable details panel in Blueprints. +* "NotBlueprintType" support added to UClass headers to stop inheritence of "BlueprintType." #### ゲームプレイとフレームワーク -* DeferStartupPrecache と PrecacheStartupSounds が FAudioDevice に追加されました。これにより、設定の読み込みが可能になるまで、ゲームは起動サウンドのキャッシュを遅らせます。実行時に AudioDevice の MaxChannels を修正するために SetMaxChannels が追加されました。 -* Engine.ini においてサブストリング列挙型変数のリダイレクトを実行する機能が追加されました。例: +* Add DeferStartupPrecache and PrecacheStartupSounds to FAudioDevice, which lets a game delay the caching of startup sounds until after settings can be read.Add SetMaxChannels to modify MaxChannels of AudioDevice at runtime +* Add ability to do substring enum redirects in Engine.ini.Example: +EnumRedirects=(EnumName="ENewEnum",OldEnumSubstring="EOldEnum::",NewEnumSubstring="ENewEnum::") -* 使用しないコマンドレットを多数削除しました。 -* UWorlds が RF_Public と RF_Standalone になりました。UWorlds をアセットのように処理し、コンテンツ ブラウザ内で管理するための準備です。 -* ライトマップが [World settings details] パネル経由で表示可能になりました。 -* レプリケーション システムの安定性が若干改善されました。 -* Navmesh の安定性が若干改善されました。 -* ブループリントの CDO はロード時に再生成された後、 PostLoad を呼び出させるようになりました。 -* オーディオ ハードウェアが見つからない、または初期化に失敗すると、オーディオ デバイスが削除されるようになりました。さらに、オーディオ デバイスはコマンドレット内では初期化されなくなりました。 -* ブループリントの再コンパイルのパフォーマンスが若干改善されました。 -*クロスの安定性が若干改善されました。 -* ペルソナの Anim ノードのツールチップが追加されました。 -* ペルソナ ビューポートの [Show] メニューを整理しました。 -* GetSocketLocalTransfrom と GetSocketWorldTransform をマージしました。 -* オブジェクトの置き換え時にエディタが手動でオブジェクト参照をリフレッシュできるイベントが追加されました。 -* [Create Anim Blueprint] ウィンドウに磨きをかけました (デザインの変更)。 -* [Assign skeleton] ウィンドウに磨きをかけました (スケルトン選択を変更して、プレーンなリストボックスではなくアセット ピッカーを使用するようにしました)。 -* "Retarget Anim Blueprints" に磨きをかけました (何が起こっているのかをユーザーにさらに伝えやすくするための通知が追加されました)。 -* ブループリント ツリーが変更され、オブジェクト名ではなく表示名が使用されるようになりました。 -* 小さいゲーム モジュール用のシングル ソース ファイル上での反復コンパイル時間が短縮されました。 - * ゲーム モジュールが常にプリコンパイルされたヘッダを使用するようになりました (イタレーションの高速化)。 - * これまでは、モジュール数が 8 ユニット ソース ファイルを超えるゲームのみで使用されてきました。 - * このための新規設定:BuildConfiguration.bForcePrecompiledHeaderForGameModules. - * 小さなゲーム モジュールではユニティ ビルドは使用しなくなりました (イタレーションの高速化)。 - * ソース ファイルが 32 未満のゲーム モジュールは強制的にユニティ モード以外になります。 - * このための新規設定:BuildConfiguration.MinGameModuleSourceFilesForUnityBuild. -* プログラム モジュールのデフォルトでは、共有の PCHs は使用されなくなりました (PCHUsageMode を使ったオーバーライドが可能)。 -* CodeView が実験的なエディタ設定に変更されました。デフォルトでは無効です。 - * クラス名上でダブルクリックすると CodeView が C++ コードへジャンプするようになりました。 -* UnrealBuildTool:ユーザーの CPU コア以上のプロセスをスポーンしないでください (ローカル プログラムのみ)。 - * これによりシステム リソースが自由に使えるようになりますが、ビルド時間が短縮できる場合もあります。その他の場合、ビルド時間は実際改善されます。 -* ほとんどのエディタ ウィンドウ アニメーションはデフォルトで無効になっています ([Editor Look and Feel] セクションで切り替えできます)。 -* エディタの [New Project] と [Open Project] ダイアログが大幅に改善されました。 -* スカイボックスを修正し、合成された Lightmass importance volumes が含まれるようになりました。 - * Automatic importance volume 用の境界を計算する場合、軸に対して 10000 を超えるメッシュは無視されるようになりました。 -* コンテンツブラウザ:テクスチャがサムネイル プレビュー シーンにストリームしないように修正されました。 -* Visual Studio がない場合のエラーヘルプが改善されました。 -* DeviceManager: 各種アップグレードにより新機能が追加されユーザービリティが向上しました。デバイス検出が見直されました。 -* DeviceManager: Windows デバイス向けにデバイス シャットダウンが実装されました。 ローカル PC の再起動 / シャットダウン時にユーザーに警告を出します。 -* SessionFrontend: ユーザビリティがいろいろ改善されました。 -* SessionFrontend: [Game Launcher] タブは Session Frontend から削除され、Window メニューからアクセス可能な主要タブとなりました。 -* Messaging: メッセージ エンドポイントをゲーム以外のスレッドから安全に破棄するために FMessageEndpoint::SafeRelease() が追加されました。使用サンプルのコードベースを検索します。 -* MessagingDebugger: 各種アップグレードにより新機能が追加されユーザービリティが向上しました。 -* MessagingDebugger: 現在、Messaging Debugger UI はスタンドアローン UFE からアクセスできなくなっています。次回のリリースで修正されます。 -* PlayInEditor: PIE 設定の前定義されたスクリーン解像度が INI で設定可能になりました。 -* PlayInEditor: レベル エディタの "Launch on Device" 機能が整理され安定しました。 -* PlayInEditor: モバイル エミュレータを使ってスタンドアローン プロセスでゲームを起動する [Mobile Preview] オプションが追加されました。 -* ColorPicker: 各種ユーザビリティが改善され、直近のステートが記憶されるようになりました。 -* Slate: SSlider ウィジェットの性能 (垂直方向のスライダ、ノブの字下げなど) が改善されました。 -* General: 選択した C++11 機能を使用するためのコード変換を継続しました (NULL -> nullptr、auto in for-loops など)。 -* 出力ログで選択された行が読めるようになりました。 +* Deleted many unused commandlets. +* UWorlds are now RF_Public and RF_Standalone.This is in preparation of treating them like assets and managing them in the content browser. +* Lightmaps are now viewable via the world settings details panel. +* Minor stability improvements to the replication system +* Minor navmesh stability improvements. +* CDOs for blueprints now get PostLoad called on them after they are regenerated at load time. +* If audio hardware is not found or fails to initialize, the audio device is now deleted.Also, audio devices are no longer initialized in commandlets. +* Minor performance improvements for recompiling Blueprints. +* Minor cloth stability improvements. +* Added tooltips for anim nodes in Persona. +* Rearranged Show menu in Personas viewport. +* Merged GetSocketLocalTransfrom with GetSocketWorldTransform. +* Added an event to allow editors to manually refresh object references when objects are replaced. +* Polished "Create Anim Blueprint" window (redesign). +* Polished "Assign skeleton" window (changed skeleton selection to use asset pickers instead of plain list box). +* Polished "Retarget Anim Blueprints" (Added notifications to better inform user of what is happening). +* Changed blueprint tree display to use display names instead of object names. +* Better iterative compile times on single source files for small game modules. + * Game modules now always get a precompiled header (faster iteration). + * Previously, only game modules with more than 8 unity source files would get one. + * New setting for this:BuildConfiguration.bForcePrecompiledHeaderForGameModules. + * Small game modules no longer use unity build (faster iteration). + * Now, game modules with less than 32 source files force non-unity mode. + * New setting for this:BuildConfiguration.MinGameModuleSourceFilesForUnityBuild. +* Program modules no longer use shared PCHs by default (can be overridden using PCHUsageMode). +* Changed CodeView to be an experimental editor setting; disabled by default. + * Added double-clicking on Class names to CodeView to jump to C++ code. +* UnrealBuildTool:Don't spawn more processes than the user has CPU cores (local executor only). + * This frees up system resources but can reduce build times in some cases; In other cases it can actually improve build times. +* Disabled most editor window animations by default (can be toggled under "Editor Look and Feel" section). +* Editor's 'New Project' and 'Open Project' dialogs have been significantly improved. +* Fixed skyboxes included in synthesized Lightmass importance volumes. + * Meshes larger than 10,000m along any axis are now ignored when calculating bounds for automatic importance volume. +* Content Browser:Fixed textures not streaming for thumbnail preview scenes. +* Improved error help when Visual Studio appears to be missing. +* DeviceManager: various burst upgrades to add new features and improve usability; device discovery has been overhauled. +* DeviceManager: implemented device shutdown for Windows devices; warning users if rebooting/shutting down local PC. +* SessionFrontend: various usability improvements. +* SessionFrontend: the Game Launcher tab has been removed from the Session Frontend and is now its own major tab accessible from the Window menu. +* Messaging: added FMessageEndpoint::SafeRelease() for safely destroying message endpoints from non-Game threads; search code base for usage examples. +* MessagingDebugger: various burst upgrades to add new features and improve usability +* MessagingDebugger: the Messaging Debugger UI is currently inaccessible from standalone UFE; this will be fixed next release. +* PlayInEditor: the pre-defined screen resolutions for PIE settings are now configurable in the INI. +* PlayInEditor: the "Launch on Device" feature in the Level Editor has been cleaned up and stabilized. +* PlayInEditor: added "Mobile Preview" option that will launch the game in a standalone process with mobile emulation. +* ColorPicker: various usability improvements and now remembers its last state. +* Slate: improved capabilities of SSlider widget (vertical sliders, indented knobs etc.) +* General: continued conversion of code to use selected C++11 features (NULL -> nullptr, auto in for-loops etc.) +* Selected lines in Output Log are now readable. #### コア -* Added LOD レベルの生成が World Browser に追加され、Simplygon が必要になりました。 -* TCircularQueue の実装が完了しました。 -* Opus ボイス コーデックがアップグレードして v1.1 になりました。 -* エンジン外部の深いインストールパスとプロジェクトパスの処理に対し一層努力しています。 -* Const-correctness が修正されました。 -* TArray と TIndirectArray のビヘイビアをさらに統一するための新機能と修正が追加されました。 -* UnrealHeaderTool からのエラー ハンドリングとエラー メッセージが改善されました。 -* UnrealHeaderTool パースのいくつか修正されました。 -* ビルドが高速化しました。 -* StringCast がヌル ポインタを処理するようになりました。 -* TMap/TSet/TMultiMap イタレーションが修正されました。 -* リダイレクト初期化コードが、.ini ファイルから無くなっている CoreUObject.Metadata セクションを処理するようになりました。 -* UnrealHeaderTool で生成したインクルードがノーマライズされました。 -* ツールチップのパースが改善されて、====== や ------ のみの行などの余分な '境界' が除外されました。 -* ツールチップは、これまでなかったプロパティ タイプに対してパースされます。 +* Added LOD levels generation to World Browser, requires Simplygon. +* Finished implementation of TCircularQueue +* Upgraded Opus voice codec to v1.1 +* More efforts to handle deep install paths and project paths outside of the engine. +* Const-correctness fixes. +* New functions and fixes to further unify the behavior of TArray and TIndirectArray. +* Improvements to error handling and error messages from UnrealHeaderTool. +* Some UnrealHeaderTool parsing fixes. +* Build speed improvements. +* StringCast now handles null pointers. +* TMap/TSet/TMultiMap iteration fixes. +* Redirect initialization code now handles the CoreUObject.Metadata section being missing from the .ini file. +* UnrealHeaderTool generated includes are now normalized. +* Improved tooltip parsing to eliminate superfluous 'borders', e.g. lines containing all ======, ------ etc. +* Tooltips are now parsed for more property types which were previously being missed. -#### ネットワーキング -* 古い / 破損した ping コードは取り除かれました。 -* サーバー認証の ping コードが新しく追加されました。 - * クライアントの ping を計算するのに低レベルのネット ドライバーの ACK を使用し、値で不正行為をする能力を減らすバリデーションが追加されました。 - * 新しい ping コードで作業しやすくするために、高レベルのプレイヤー ステート コードで ping のスムージングを調整しました。 +#### Networking +* Removed old/broken ping code +* Added new server-authoritative ping code + * Uses low level net driver acks, to calculate client ping, and adds validation to reduce ability to tamper with values + * Adjusted ping smoothing in high-level player state code, to work better with new ping code #### プラットフォーム * **Mac** - * OS X でのプロジェクト作業にコードが追加されました。 - * ファイルを検知する場合、Finder で親フォルダを開きそのファイルを選択するか、フォルダに対してそれらを開きます。 - * リンカのサイレント障害が原因でMac 上でクラッシュする C++ タイプ のいくつかを明確にしました。 - * Mac OS X 出力ログを新規のエントリまでスクロールするようにしました。 - * Mac OS X でズームされたウィンドウの状態をキャッシュします。 エディタを起動すると isZoomed 用の objc_msgsend がプロファイラの一番上にきます! - * Mac 上でウィンドウ タブがデタッチしやすくなりました。 - * Mac OS X 上でのエディタ起動時にウィンドウが表示されるようになりました。 - * Mac OS X 上で最小化されたウィンドウがマウス イベントを横取りしないようにしました。 - * OS X 上でウィンドウを再形成しようしてもクラッシュしなくなりました。 - * OS X 上でプロンプト ウィンドウを閉じた後でもクラッシュしなくなりました。 - * MacApplication がない場合でも、出力ログ ウィンドウが OS X 上でコンテンツを開き表示することが確認されました。 - * サブ エディタを使用しても、レベル ビューポート グラフィックが OS X から消えてしまわなくなりました。 - * 一時的なスクリーン空間の反射のレンダリング時に破損が起きないようにしました。 - * GLSL で異なる NAN/INF の条件に対応するために、Mac OS X 上で NAN の抑制を有効化しなければなりません。 - * パーティクルのレンダリング時に、テクスチャ バッファのクラッシュを避けるために、低いシェーダー モデルに対してもバインドされます。 - * glMapBuffer と CPU & GL の同期を避けて新しい拡張子が使えない場合、PBO unpack の後に PBO pack を使用してテクスチャ ミップをコピーします。 - * エディタにマウスをかざすと遅くなる原因の 1 つが解決されました。 - * OpenGL に対して非常に遅い glReadPixels パスを取る RHIReadSurfaceData を呼び出すかわりに、バイト バッファへヒット プロキシ データをキャッシュするようにしました。 - * それらをサポートしているすべての GL 上でシームレスなキューブマップが有効になりました。 - * Mac OS X 上で SSR を使用する時のビューポート エッジの歪みを解消しました。 - * CPU のリードバックテクスチャのロックの高速化、Mac OS X 上で一般的なテクスチャのリードバックおよび HZB パフォーマンスに対応対処しました。 + * Make adding code to projects work on OS X. + * When exploring to a file, open the parent folder in Finder and select that file, or for folders just open them. + * Disambiguate some C++ types that were causing crashes on Mac due to silent linker failure. + * Make Mac OS X output log scroll to new entries. + * Cache the window's zoomed state on Mac OS X - the objc_msgsend for isZoomed is sitting top of the profiler when running the editor! + * Make it easier to detach window tabs on the Mac. + * Make windows appear on editor restart on Mac OS X. + * Stop minimized windows stealing mouse events on Mac OS X. + * Stop crashing when trying to reshape windows on OS X. + * Stop crashing after closing prompt windows on OS X. + * Make sure that the output log window opens & displays content on OS X even when there's no MacApplication. + * Stop the level viewport graphics from fading on OS X when using sub-editors. + * Avoid corruption when rendering temporal screen space reflections + * Must enable NAN suppression on Mac OS X to handle differing NAN/INF conditions in GLSL. + * When rendering particles ensure a texture buffer is bound even for lower shader models to avoid a crash. + * Use a PBO pack, followed by a PBO unpack to copy texture mips when newer extensions aren't available to avoid synchronising the CPU & GL with glMapBuffer. + * Eliminate one cause of slowdown when mousing over the editor. + * Cache the hit proxy data into a byte buffer rather than calling RHIReadSurfaceData which takes a very slow glReadPixels path for OpenGL.. + * Enable seamless cube maps on all GL's that support them. + * Eliminate distortions at viewport edge when using SSR on Mac OS X. + * Speed-up locking CPU readback textures and general texture readback on Mac OS X + address HZB performance. * **Android** - * Android の場合、バックバッファの形式は、R5G6B5 よりも R8G8B8 の方が好ましくなりました。 - * Android がマルチスレッドになりました (起動時に適切な CPU コア数をチェックします)。 - * ハイエンドな Qualcomm Adreno GPU に OpenGL ES 3.0 シェーダーが使用されています。 - * GPU のフレーム時間が `STAT UNIT` で測定可能になりました。ドライバーに問題のあるデバイスもあるためデフォルトでは無効になっていますが、 CVar `r.DisjointTimerQueries` を 1 に設定すれば有効になります。 - * Android のコントローラーとキーボードが初めてサポートされました。 - * Android の一時停止 / 再開のビヘイビアが整理されました。  - * Android のビルドはユーザーが生成したスタンドアローン型のツールチェーンに依存しなくなりました。UBT は NDK ツールチェーンを直接呼び出します。 - * NSight 1.5 以降がインストールされていると、Android デバッグ スタブ プロジェクトは作成されなくなりました。 + * Android now prefers R8G8B8 backbuffer format instead of R5G6B5. + * Android is now multithreaded (using proper CPU core count check at startup). + * Now using OpenGL ES 3.0 shaders for high-end Qualcomm Adreno GPUs. + * GPU frametime can now be measured in `STAT UNIT`.It's disabled by default due to driver issues on some devices, but can be enabled by setting the CVar `r.DisjointTimerQueries` to 1. + * Initial Android controller and keyboard support is in. + * Android pause/resume behavior has been cleaned up. + * Android builds no longer rely on a user generated standalone toolchain.UBT calls directly into the NDK toolchains. + * Android debug stub projects are no longer generated if NSight 1.5 or later is installed. #### アニメーション -* **アニメーション** - * スケルトン:様々な印を汚れの問題として修正したので、正当な原因以外ではスケルトンは汚れないはずです。 - * 新規のアニメーション通知がアニメーションに追加された場合、スケルトンを保存する必要がなくなりました。 - * ModifyBone SkeletalControl 名を明確にするために TransformBone に変更しました。 +* **Animation issues** + * Skeleton:Fixed various marking as dirty issues, so you shouldn't see skeleton getting dirty anymore without a proper cause. + * You also don't have to save skeleton anymore when new anim notify is added to the animation. + * ModifyBone SkeletalControl name changed to TransformBone for clarify. -## 周知の問題 +## 既知の問題 -* Mac エディタは機能しますが、 ビルド済みのバイナリは本リリースには含まれません。今のところ、Mac でエディタを動かすためには、バイナリのコンパイルが必要になります。 +* Mac editor works but pre-built binaries are not included with this release.For now, you must compile the binaries in order to run the editor on Mac. diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/March/ReleaseNotesMarch2014.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/March/ReleaseNotesMarch2014.KOR.udn index 3523fa49b798..720cf3ea2fec 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/March/ReleaseNotesMarch2014.KOR.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2014/March/ReleaseNotesMarch2014.KOR.udn @@ -1,8 +1,10 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3367470 Title: March 2014 Release Notes Crumbs:%ROOT%, Support/Builds Description: ### DO NOT TRANSLATE ### Availability:Licensee +Parent:Support/Builds +Order:-1 [TOC(start:2 end:2)] diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2015/4_8/ReleaseNotes_4_8.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2015/4_8/ReleaseNotes_4_8.KOR.udn index bb3583f43dfb..fa9bf30724bd 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2015/4_8/ReleaseNotes_4_8.KOR.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2015/4_8/ReleaseNotes_4_8.KOR.udn @@ -289,7 +289,7 @@ Shooter Game 에서 이 기능을 확인해 보세요. * 와이어에 커서를 올려 강조하거나 관련된 핀의 툴팁을 확인합니다. -* 더블클릭으로 재경유 노드를 삽입합니다 (블루프린트 그래프 전용) +* 더블클릭으로 경유지 노드를 삽입합니다 (블루프린트 그래프 전용) ### 프로시저럴 메시 컴포넌트 (실험단계) @@ -549,11 +549,11 @@ World Position Offset 으로 애니메이팅되는 나무에서의 픽셀별 속 * UObject 생성은 이제 스레드 안전성이 확보되어 워커 스레드에서 수행 가능합니다. 여기에는 모든 UObject 파생 클래스 생성자 역시 스레드 안전성이 확보되어야 합니다. -* StaticFindObject, FindObject, FindObjectFast 함수 역시도 이제 스레드 안전성이 확보되었습니다. 워커 스레드에 사용되고 반환값이 스택에서만 레퍼런싱된 경우, 해당 오브젝트가 어떤 것에도 레퍼런싱되지 않은 것으로 가비지 콜렉터가 간주할 수 있다는 점을 염두에 두시기 바랍니다. +* StaticFindObject, FindObject, FindObjectFast 함수 역시도 이제 스레드 안전성이 확보되었습니다. 워커 스레드에 사용되고 반환값이 스택에서만 레퍼런싱된 경우, 해당 오브젝트가 어떤 것에도 레퍼런싱되지 않은 것으로 가비지 컬렉터가 간주할 수 있다는 점을 염두에 두시기 바랍니다. * 현재 영역이 워커 스레드에서 실행중인 동안에는 GC 실행을 막는다는 점만 빼면 FScopeLock 와 비슷한 기반으로 작동하는 FGCScopeGuard 헬퍼 구조체를 도입했습니다. -* 워커 스레드가 FGCScopeGuard 영역 안에서 코드를 실행하는 경우 가비지 콜렉션을 생략시키는 TryCollectGarbage 함수를 도입했습니다. TryCollectGarbage 는 이제 레벨 틱 코드에 기본으로 사용됩니다. +* 워커 스레드가 FGCScopeGuard 영역 안에서 코드를 실행하는 경우 가비지 컬렉션을 생략시키는 TryCollectGarbage 함수를 도입했습니다. TryCollectGarbage 는 이제 레벨 틱 코드에 기본으로 사용됩니다. * 비동기 로드율은 `stat levels` 를 통해 접근 가능하며, 이제 PostLoad 를 계산에 넣습니다. @@ -1055,7 +1055,7 @@ World Position Offset 으로 애니메이팅되는 나무에서의 픽셀별 속 * 새로운 increment (증가), decrement (감소), negate (부정) 매크로를 새로 추가했습니다. -* 역방향 이동하는 재경유 노드용 방향 전환이 지원됩니다. '상투' 효과를 피할 수 있습니다. +* 역방향 이동하는 경유지 노드용 방향 전환이 지원됩니다. '상투' 효과를 피할 수 있습니다. ![image alt text](image_44.png) @@ -1067,7 +1067,7 @@ World Position Offset 으로 애니메이팅되는 나무에서의 픽셀별 속 * 변수 드래그 앤 드롭으로 카테고리를 변경했던 것도 되돌리기 가능합니다. -* 재경유 노드 코멘트 핀 기능 구현을 변경, 사용자에게 커서를 올렸을 때 현재 디스플레이에 대한 대안을 제공합니다. +* 경유지 노드 코멘트 핀 기능 구현을 변경, 사용자에게 커서를 올렸을 때 현재 디스플레이에 대한 대안을 제공합니다. * 두 날짜 시간 빼기를 블루프린트에 노출시켰습니다. @@ -1215,7 +1215,7 @@ World Position Offset 으로 애니메이팅되는 나무에서의 픽셀별 속 * Current Max Draw Distance 는 블루프린트에서 읽을 수만 있지, 쓸 수는 없습니다. -* 블루프린트에서 스폰된 데칼과 이미터가 더이상 의도치 않게 가비지 콜렉팅되지 않습니다. +* 블루프린트에서 스폰된 데칼과 이미터가 더이상 의도치 않게 가비지 컬렉팅되지 않습니다. * 블루프린트에 기본 배치된 이벤트에 코멘트 풍선이 정상 표시됩니다. @@ -1395,7 +1395,7 @@ World Position Offset 으로 애니메이팅되는 나무에서의 픽셀별 속 * 블루프린트에 새 변수나 이벤트 디스패처 추가시의 작명 규칙 문제를 고쳤습니다. 이제 블루프린트의 다른 항목같은 포맷이 될 것입니다: New[Type]_[Number]. -* 블루프린트 생성 컴포넌트에 대한 되돌리기/다시하기 버퍼에 의해서만 레퍼런싱된 오브젝트가 가비지 콜렉팅되는 것을 고쳤습니다. +* 블루프린트 생성 컴포넌트에 대한 되돌리기/다시하기 버퍼에 의해서만 레퍼런싱된 오브젝트가 가비지 컬렉팅되는 것을 고쳤습니다. * 블루프린트 컴파일을 막을 수 있던 컴포넌트 변수와 컴포넌트 노드 사이의 이름 충돌 가능성을 고쳤습니다. @@ -1493,7 +1493,7 @@ World Position Offset 으로 애니메이팅되는 나무에서의 픽셀별 속 * 접힌 그래프 내 함수 로컬 변수 대체가 작동합니다. -* 재경유 노드는 이제 애니메이션 컴파일 이후 애니메이션 그래프에서 정상 작동합니다. +* 경유지 노드는 이제 애니메이션 컴파일 이후 애니메이션 그래프에서 정상 작동합니다. * 키바인딩을 통한 그래프 내 모든 노드 선택시 더이상 그래프 목록 내 공백 노드로 인한 어서트가 발생하지 않습니다. @@ -1517,11 +1517,11 @@ World Position Offset 으로 애니메이팅되는 나무에서의 픽셀별 속 * 메뉴의 내용을 잘라버리기 보다는, 줌 레벨에 맞춰 팝업 메뉴의 스케일을 조절합니다. -* 재경유 노드와 다른 노드에서 코멘트 풍선 작동방식이 다르던 것을 고쳤습니다. +* 경유지 노드와 다른 노드에서 코멘트 풍선 작동방식이 다르던 것을 고쳤습니다. - * 이제 재경유 노드 코멘트도 다른 코멘트와 마찬가지로 핀 및 표시/숨길 수 있습니다. + * 이제 경유지 노드 코멘트도 다른 코멘트와 마찬가지로 핀 및 표시/숨길 수 있습니다. -* 숨겨진 재경유 노드 위에 커서를 올리면 코멘트가 표시됩니다. +* 숨겨진 경유지 노드 위에 커서를 올리면 코멘트가 표시됩니다. * 에디터에서 새줄 모디파이어 키 코멘트 풍선이 있는 노드가 비슷한 예제에 일치하지 않는 문제가 해결됩니다. @@ -1581,7 +1581,7 @@ World Position Offset 으로 애니메이팅되는 나무에서의 픽셀별 속 * 커브가 타임라인에 소유된 것처럼 외부 커브를 포함한 타임라인이 커브를 깊이 복사(deep copy)하려 하는 문제를 고쳤습니다. 외부 커브는 이제 레퍼런스를 원래대로 놔둔 채 건너뜁니다. 추가적으로 소유된 커브의 깊은 복사는 이제 블루프린트 리인스턴싱 도중 과다하게 깊이 복사되지 않습니다. -* 블루프린트 그래프 액션 관련 특정 상황에서 레벨 전환시 가비지 콜렉션이 실패하게 만드는 문제를 고쳤습니다. +* 블루프린트 그래프 액션 관련 특정 상황에서 레벨 전환시 가비지 컬렉션이 실패하게 만드는 문제를 고쳤습니다. * 머티리얼 표현식에서 코멘트 풍선 관련 다음과 같은 문제를 고쳤습니다. @@ -1629,7 +1629,7 @@ World Position Offset 으로 애니메이팅되는 나무에서의 픽셀별 속 * 엔진이 환경 변수 읽기에 실패했을 때의 경고 로그 메시지를 추가했습니다. -* 월드 사이의 전환이 일어날 때 레퍼런스가 남아 기존 맵의 가비지 콜렉션을 막는 현상을 피하기 위해 월드에 들어있는 모든 오브젝트는 가비지 콜렉션 마킹됩니다. +* 월드 사이의 전환이 일어날 때 레퍼런스가 남아 기존 맵의 가비지 컬렉션을 막는 현상을 피하기 위해 월드에 들어있는 모든 오브젝트는 가비지 컬렉션 마킹됩니다. * 이를 통해 Seamless Travel 전환과 Load Map 전환이 일치됩니다. @@ -1723,7 +1723,7 @@ World Position Offset 으로 애니메이팅되는 나무에서의 픽셀별 속 * 소유 액터 없이 자손 액터 컴포넌트를 사용했을 때의 크래시를 고쳤습니다. -* PIE 에서 심리스 레벨 트랜지션을 할 때 가비지 콜렉션이 기존 월드를 비우는 데 실패해서 발생하던 크래시를 고쳤습니다. +* PIE 에서 심리스 레벨 트랜지션을 할 때 가비지 컬렉션이 기존 월드를 비우는 데 실패해서 발생하던 크래시를 고쳤습니다. * 액터가 클라이언트에서 Begin Play 를 두 번 호출하게 만들 수 있었던 문제를 고쳤습니다. @@ -1771,7 +1771,7 @@ World Position Offset 으로 애니메이팅되는 나무에서의 픽셀별 속 * 머신에 네트워크 어댑터가 둘 이상 있을 때 언리얼 스웜이 IP 주소를 자체적으로 해석하도록 수정했습니다. -* 가비지 콜렉션 퍼포먼스를 향상시켰습니다. +* 가비지 컬렉션 퍼포먼스를 향상시켰습니다. * 컨스트럭션 스크립트 도중의 동적인 데이터 변경이 (실행시간에 다른 방식으로는 변경 불가능한) 무버블 이외의 컴포넌트를 타겟으로 할 수 있도록 메소드를 개선시켰습니다. @@ -1911,7 +1911,7 @@ World Position Offset 으로 애니메이팅되는 나무에서의 픽셀별 속 * 다수의 iOS 프로젝트 세팅에 활성화됩니다 (Enable Game Center 등). -* 가비지 콜렉터 호출 전 스트리밍 플러싱을 활성화시킬 수 있는 ini 옵션을 추가했습니다. +* 가비지 컬렉터 호출 전 스트리밍 플러싱을 활성화시킬 수 있는 ini 옵션을 추가했습니다. * 엔진 ini 의 [Core.System] 섹션 아래 FlushStreamingOnGC 값을 통해 활성화시킬 수 있습니다. @@ -2161,7 +2161,7 @@ World Position Offset 으로 애니메이팅되는 나무에서의 픽셀별 속 * 지오메트리 모드에서 에지를 돌리려 할 때 연관된 폴리곤이 일치하는 경우의 크래시를 고쳤습니다. -* 가비지 콜렉터가 찾은 오브젝트가 스트리밍 코드에 의해서만 레퍼런싱되어 유발된 스트리밍 도중 가비지 콜렉터가 발동될 때의 크래시를 고쳤습니다. +* 가비지 컬렉터가 찾은 오브젝트가 스트리밍 코드에 의해서만 레퍼런싱되어 유발된 스트리밍 도중 가비지 컬렉터가 발동될 때의 크래시를 고쳤습니다. * 깨진 애셋 로드시의 크래시를 고쳤습니다. 대신 경고창이 뜹니다. @@ -2339,7 +2339,7 @@ World Position Offset 으로 애니메이팅되는 나무에서의 픽셀별 속 * 공간화 활성 상태의 스테레오 사운드 플레이시의 경고를 고쳤습니다. -* 가비지 콜렉터에서 퍼지 종료 도중 영구 오브젝트 풀에 상주하는 오브젝트에서 퍼지가 소멸자를 호출하지 않던 버그를 잡았습니다. +* 가비지 컬렉터에서 퍼지 종료 도중 영구 오브젝트 풀에 상주하는 오브젝트에서 퍼지가 소멸자를 호출하지 않던 버그를 잡았습니다. * 에디터 비행 제어가 조합키(Ctrl, Alt, Shift, Cmd)가 눌리지 않은 상태에서만 효과를 발휘하도록 변경했습니다. [조합키]+PgUp 를 다른 동작에 바인딩하는 작업이 가능하도록 하기 위해서입니다. @@ -2449,7 +2449,7 @@ World Position Offset 으로 애니메이팅되는 나무에서의 픽셀별 속 * 이제 새 클래스를 추가한 이후 콘텐츠 브라우저 뷰를 동기화시키고, 새 블루프린트 클래스 추가시 블루프린트 에디터를 열기도 합니다. -* 콘텐츠 브라우저의 "콜렉션 표시"가 이제 기존 에디터 세션의 상태를 기억합니다. +* 콘텐츠 브라우저의 "컬렉션 표시"가 이제 기존 에디터 세션의 상태를 기억합니다. * 콘텐츠 브라우저의 "폴더에서 표시" 및 "탐색기에서 표시" 맥락 메뉴 옵션이 자주 사용되는 관계로 서브메뉴에서 이동시켰습니다. @@ -3571,9 +3571,9 @@ World Position Offset 으로 애니메이팅되는 나무에서의 픽셀별 속 * 실행시간에 컨스트레인트 프로젝션을 켜고 끄는 기능을 추가했습니다. -* 많은 양의 피직스 바디 생성 속도를 높이기 위해 피직스 바디 초기화에 디퍼드 패쓰를 추가했습니다. +* 많은 양의 피직스 바디 생성 속도를 높이기 위해 피직스 바디 초기화에 디퍼드 패스를 추가했습니다. -* 인스턴스드 스태틱 메시 컴포넌트에 맞게 더 빠른 스태틱 이니셜라이제이션 패쓰를 추가했습니다. +* 인스턴스드 스태틱 메시 컴포넌트에 맞게 더 빠른 스태틱 이니셜라이제이션 패스를 추가했습니다. * 폴리지 통계 함수 라이브러리에 메소드를 추가했습니다. @@ -4226,7 +4226,7 @@ World Position Offset 으로 애니메이팅되는 나무에서의 픽셀별 속 * 신형 Morpheus HMD Server 가 지원됩니다. Morpheus PC 프리뷰가 다시 작동합니다. -* 렌더 스레드가 단일 CPU 코어에 잠기게 만드는 버그를 잡았습니다. 가비지 콜렉션을 버벅이게 만드는 여러가지 문제가 해결됩니다. +* 렌더 스레드가 단일 CPU 코어에 잠기게 만드는 버그를 잡았습니다. 가비지 컬렉션을 버벅이게 만드는 여러가지 문제가 해결됩니다. * 텍스처 스트리밍 예산 산정의 버그를 잡았습니다. 이제 텍스처 풀 크기가 제대로 산정됩니다. @@ -4660,7 +4660,7 @@ World Position Offset 으로 애니메이팅되는 나무에서의 픽셀별 속 * LPV 포함 SubsurfaceProfile 셰이더 모델을 사용하는 것을 수정했습니다. -* ViewProjectionMatrix 가 특정 렌더링 패쓰에 대해 설정되지 않아 UMG 렌더링 관련 문제를 유발하던 것을 고쳤습니다. +* ViewProjectionMatrix 가 특정 렌더링 패스에 대해 설정되지 않아 UMG 렌더링 관련 문제를 유발하던 것을 고쳤습니다. * 스크린 샷 퍼포먼스를 향상시켰습니다. @@ -4672,7 +4672,7 @@ World Position Offset 으로 애니메이팅되는 나무에서의 픽셀별 속 * 스카이라이트는 전에 캡처된 적이 없는 경우 활성화시에만 캡처됩니다. -* 스카이라이트 색이나 강도 변경시 렌더링 스테이트를 재생성하지 않는 빠른 (완전 정적인 드로 리스트 재생성) 패쓰를 추가했습니다. +* 스카이라이트 색이나 강도 변경시 렌더링 스테이트를 재생성하지 않는 빠른 (완전 정적인 드로 리스트 재생성) 패스를 추가했습니다. * 게임 콘솔에서도 에디터에서처럼 자동완성 항목이 소팅됩니다. @@ -4800,7 +4800,7 @@ World Position Offset 으로 애니메이팅되는 나무에서의 픽셀별 속 * 라이트매스에서 시작 에이전트에 사용된 코어 수에 묶여있던 다중 CPU 코어 수 제한을 수정했습니다. -* 다이내믹 라이팅 패쓰에 대한 머티리얼 AO 를 수정했습니다. +* 다이내믹 라이팅 패스에 대한 머티리얼 AO 를 수정했습니다. * bLightAsIfStatic 이 켜진 프리미티브가 아직 빌드하지 않은 라이트 영향 반경에 들어간 경우 라이팅이 빌드되지 않던 것을 고쳤습니다. @@ -4846,7 +4846,7 @@ World Position Offset 으로 애니메이팅되는 나무에서의 픽셀별 속 * 머티리얼 에디터에서 빌보드에 사용되는 ViewToWorld 트랜스폼에 영향을 끼칩니다. -* 머티리얼 인스턴스 가비지 콜렉션 도중에 잠재된 크래시를 고쳤습니다. +* 머티리얼 인스턴스 가비지 컬렉션 도중에 잠재된 크래시를 고쳤습니다. * 머티리얼 인스턴스 에디터에서 부모 머티리얼 리셋으로 인해 발행하는 크래시 버그를 잡았습니다. @@ -4926,7 +4926,7 @@ World Position Offset 으로 애니메이팅되는 나무에서의 픽셀별 속 * 검색창에 커스터마이징 향상을 위한 변경을 가했습니다. -* 슬레이트 리소스의 불필요한 가비지 콜렉션을 수정했습니다. +* 슬레이트 리소스의 불필요한 가비지 컬렉션을 수정했습니다. * 위젯 소멸시 발생할 수 있었던 크래시를 고쳤습니다. @@ -5208,7 +5208,7 @@ World Position Offset 으로 애니메이팅되는 나무에서의 픽셀별 속 * 위젯 선택이 바뀌려 할 때 선택된 오브젝트를 클리어합니다. 이로써 위젯 이주 세트의 변화 전, 색 선택기의 스포이드 기능에서 오는 최종 변화가 확실히 마무리될 수 있도록 합니다. -* 애니메이션이 없는, 그리고 보이는 타임라인/애니메이션이 없는 UMG 위젯 컴파일시 발생하는 크래시를 고쳤습니다. 오브젝트가 가비지 콜렉팅되도록 합니다. 이제 GC 방지를 위해 오브젝트 레퍼런스를 보고합니다. +* 애니메이션이 없는, 그리고 보이는 타임라인/애니메이션이 없는 UMG 위젯 컴파일시 발생하는 크래시를 고쳤습니다. 오브젝트가 가비지 컬렉팅되도록 합니다. 이제 GC 방지를 위해 오브젝트 레퍼런스를 보고합니다. * 트로버는 이제 25 조각으로 제한됩니다. @@ -5216,7 +5216,7 @@ World Position Offset 으로 애니메이팅되는 나무에서의 픽셀별 속 * 피벗 포인트가 컴포넌트 상의 위젯 히트 테스트를 제대로 하지 못하던 것을 고쳤습니다. -* 뷰포트나 플레이어 화면에 추가된 UserWidgets 는 이제 전체 레벨 전환이 일어나면 자동 제거 또는 킬 대기 상태로 마킹합니다. 이로써 오래된 월드가 레퍼런싱되어 많은 가비지 콜렉션 크래시 및 골칫꺼리를 안기던 문제가 다수 해결됩니다. +* 뷰포트나 플레이어 화면에 추가된 UserWidgets 는 이제 전체 레벨 전환이 일어나면 자동 제거 또는 킬 대기 상태로 마킹합니다. 이로써 오래된 월드가 레퍼런싱되어 많은 가비지 컬렉션 크래시 및 골칫꺼리를 안기던 문제가 다수 해결됩니다. * 디자이너에 "Wrap With" 를 사용하면 이제 다중 선택된 위젯이 동기간인 경우 제대로 묶어주며, 그 외의 경우 선택된 동기를 가능한 그룹별로 모두 묶어줍니다. diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2016/4_11/ReleaseNotes_4_11.INT.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2016/4_11/ReleaseNotes_4_11.INT.udn index 004c3956b279..695d81efc84c 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2016/4_11/ReleaseNotes_4_11.INT.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2016/4_11/ReleaseNotes_4_11.INT.udn @@ -5646,85 +5646,83 @@ Stats are automatically broken into the threads they execute on and can appear i * Here is an example of how one would build a custom native AnimInstance class using the new proxy, granting Blueprint access to its innards and avoiding copies of shared data between the proxy and the instance: -USTRUCT() + USTRUCT() -struct FExampleAnimInstanceProxy : public FAnimInstanceProxy + struct FExampleAnimInstanceProxy : public FAnimInstanceProxy -{ + { - GENERATED_BODY() + GENERATED_BODY() - FExampleAnimInstanceProxy() + FExampleAnimInstanceProxy() - : FAnimInstanceProxy() + : FAnimInstanceProxy() - {} + {} - FExampleAnimInstanceProxy(UAnimInstance* Instance); + FExampleAnimInstanceProxy(UAnimInstance* Instance); - virtual void Update(float DeltaSeconds) override + virtual void Update(float DeltaSeconds) override - { + { - // Update internal variables + // Update internal variables - MovementAngle += 1.0f * DeltaSeconds; + MovementAngle += 1.0f * DeltaSeconds; - HorizontalSpeed = FMath::Max(0.0f, HorizontalSpeed - DeltaSeconds); + HorizontalSpeed = FMath::Max(0.0f, HorizontalSpeed - DeltaSeconds); - } + } -public: + public: - UPROPERTY(Transient, BlueprintReadWrite, EditAnywhere, Category = "Example") + UPROPERTY(Transient, BlueprintReadWrite, EditAnywhere, Category = "Example") - float MovementAngle; + float MovementAngle; - UPROPERTY(Transient, BlueprintReadWrite, EditAnywhere, Category = "Example") + UPROPERTY(Transient, BlueprintReadWrite, EditAnywhere, Category = "Example") - float HorizontalSpeed; + float HorizontalSpeed; -}; + }; -UCLASS(Transient, Blueprintable) + UCLASS(Transient, Blueprintable) -class UExampleAnimInstance : public UAnimInstance + class UExampleAnimInstance : public UAnimInstance -{ + { - GENERATED_UCLASS_BODY() + GENERATED_UCLASS_BODY() - + private: -private: + // The AllowPrivateAccess meta flag will allow this to be exposed to Blueprint, - // The AllowPrivateAccess meta flag will allow this to be exposed to Blueprint, + // but only to graphs internal to this class. - // but only to graphs internal to this class. + UPROPERTY(Transient, BlueprintReadOnly, Category = "Example", meta = (AllowPrivateAccess = "true")) - UPROPERTY(Transient, BlueprintReadOnly, Category = "Example", meta = (AllowPrivateAccess = "true")) + FExampleAnimInstanceProxy Proxy; - FExampleAnimInstanceProxy Proxy; + virtual FAnimInstanceProxy* CreateAnimInstanceProxy() override - virtual FAnimInstanceProxy* CreateAnimInstanceProxy() override + { - { + // override this to just return the proxy on this instance - // override this to just return the proxy on this instance + return &Proxy; - return &Proxy; + } - } + virtual void DestroyAnimInstanceProxy(FAnimInstanceProxy* InProxy) override - virtual void DestroyAnimInstanceProxy(FAnimInstanceProxy* InProxy) override + { - { + } - } + friend struct FExampleAnimInstanceProxy; - friend struct FExampleAnimInstanceProxy; - -}; + }; * The following functions and variables of the **UAnimInstance** class are **now deprecated**: diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2016/4_11/ReleaseNotes_4_11.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2016/4_11/ReleaseNotes_4_11.JPN.udn index 6075c337a524..5a27a7fa1c3c 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2016/4_11/ReleaseNotes_4_11.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2016/4_11/ReleaseNotes_4_11.JPN.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:2952959 +INTSourceChangelist:3403469 Availability:Public Title:アンリアル エンジン 4.11 リリースノート Crumbs:%ROOT%, Engine @@ -25,17 +25,17 @@ Paragon はチームにとって、ユニークな挑戦の連続でした。Par 細かい最適化をエンジン全体で数多く実施したので Paragon のパフォーマンスを大幅に改善しました。UE4 で作成されたすべてのゲームの改善にもつながるでしょう。これらの最適化の多くが 4.11 で実現され、今後のリリースで更に最適化されます。最適化作業の成果を幾つかを紹介します。 -**Parallelization (並列化):** PC やコンソール上での高いフレームレートの実現には今やマルチコア スケーリングが極めて重要となるので、**スレッド アーキテクチャ**をいくつかの方法で改善しました。タスク作成の負荷を減らして、優先度の高いタスクへのサポートを追加し、同期ポイントを多数取り除きました。 +**Parallelization (並列化):** PC やコンソール上での高いフレームレートの実現には今やマルチコア スケーリングが極めて重要となるので、**スレッド アーキテクチャ** をいくつかの方法で改善しました。タスク作成の負荷を減らして、優先度の高いタスクへのサポートを追加し、同期ポイントを多数取り除きました。 **レンダリング パフォーマンス:** GPU でオーバーヘッドを増やさずに最大の並列処理を実現するために、レンダラが GPU に生成された作業者タスクとコマンド バッファのサイズのバランスを保持できるようになりました。レンダラの同期ポイントも取り除いたので、利用可能なコアが使いやすくなりました。 -**クロス シミュレーション:** 劇的に速くなり、マルチスレッディングが使いやすくなりました。アセットごとに APEX ソルバをワーカースレッドから直接呼び出せるようになりました。そのため、スケジューリングが簡単になり、同期ポイントとオーバーヘッドが多数取り除かれました。クロスは、アニメーション後 (ブレンドが必要ない場合) あるいはスケルタル メッシュ コンポーネントのアップデート後にアップデートされるようになりました。 +**クロス シミュレーション** が格段に速くなり、マルチスレッディングが使いやすくなりました。アセットごとに APEX ソルバをワーカースレッドから直接呼び出せるようになりました。そのため、スケジューリングが簡単になり、同期ポイントとオーバーヘッドが多数取り除かれました。クロスは、アニメーション後 (ブレンドが必要ない場合) あるいはスケルタル メッシュ コンポーネントのアップデート後にアップデートされるようになりました。 **ガーベジ コレクションの高速化:** ガーベジ コレクション "クラスタ" がサポートされて、エンジンがオブジェクト群をひとつのユニットとして処理できるようになったので、考慮すべきオブジェクト数が大幅に減りました。今のところ、マテリアルとパーティクル システムのサブオブジェクトのみクラスタ化されます。さらに、マーク フェーズおよび破壊フェーズがさらにキャッシュ コヒーレントになり、処理時間は 9 分の 1 に短縮、到達可能性分析中のメモリ チェーンも少なくなりました。 **マルチスレッド アニメーション:** アニメーション グラフのアップデートがワーカースレッド上で実行できるようになったので、アニメートされたキャラクター数をコアの数でスケールすることが可能になりました。アップグレード ノートを確認してください。多くのアニメーション関連の API を非推奨とし、ワーカースレッド上で実行できるアニメーション グラフを制限しました。 -**アニメーション変数へのインスタント アクセス:** アニメーション グラフ アップデートに変数アクセスのためのファスト パスが追加されました。ブループリント コードを実行せずに、内部でパラメータを簡単にコピーできるようになりました。メンバ変数、無効の Boolean メンバ変数、ネスティングされた構造体のメンバをコンパイラで、最適化できるようになりました。 +**アニメーション変数へのインスタント アクセス:** アニメーション グラフ アップデートに変数アクセスのためのファスト パスが追加されました。This allows us to simply copy parameters internally rather than executing Blueprint code.メンバ変数、無効の Boolean メンバ変数、ネスティングされた構造体のメンバをコンパイラで、最適化できるようになりました。 **加算アニメーションのベイク処理:** **ベイクした加算アニメーション**をオンにするオプションが付きました。**加算アニメーションの速さ** が **3 倍** になります。加算アニメーションのデルタ ポーズの計算に関わる作業はランタイムではなくクックタイムで処理されます。加算デルタ作成の計算作業のみならず、ランタイム時に必要がなくなったベース アニメーション解凍のメモリ アクセスと割り当ても保存されます。この機能によりクック時間が増加するので、cvar "a.UseBakedAdditiveAnimations" を 1 に設定して有効にする必要があります。今後のバージョンでは、この負荷が発生しないようにして、最適化された状態が永久に保たれるようにエンジンのアニメーション クック処理を改善します。 @@ -45,7 +45,7 @@ Paragon はチームにとって、ユニークな挑戦の連続でした。Par ![image alt text](image_2.png)![image alt text](image_3.png) -2 つのスペキュラ ローブ、トランスミッションとスキャタリングをモデル化します。この機能を使うには、マテリアル エディタのシェーディング モデル リストから**[Hair]**を選択します。 +2 つのスペキュラ ローブ、トランスミッションとスキャタリングをモデル化します。この機能を使うには、マテリアル エディタのシェーディング モデル リストから **[Hair]** を選択します。 ## 新規:リアルなアイシェーディング @@ -65,7 +65,7 @@ Paragon はチームにとって、ユニークな挑戦の連続でした。Par ## 新規:リアルなクロスシェーディング -**クロスを作るためのシェーディング モデル****が追加されました。不明瞭なレイヤーをシミュレートし、これまでよりもリアルなクロスの生成が可能になりました。この機能は、マテリアル エディタで [Cloth shading model] を選択します。 +**クロスを作るためのシェーディング モデル**** が追加されました。不明瞭なレイヤーをシミュレートし、これまでよりもリアルなクロスの生成が可能になりました。この機能は、マテリアル エディタで [Cloth shading model] を選択します。 ![image alt text](image_6.png) @@ -87,11 +87,11 @@ Paragon はチームにとって、ユニークな挑戦の連続でした。Par このカプセル シャドウの実装は非常に効率的です。深度を意識したアップサンプルを使って半分の解像度でシャドウイングを計算し、スクリーン タイル カリングを使ってシャドウイング作業を必要な場所のみに制限します。 -GPU 負荷は、カプセル数およびキャストされたシャドウが影響するピクセル数に比例します。 +GPU 負荷は、カプセル数およびキャストされたシャドウの影響を受けるピクセル数に比例します。 カプセル シャドウを有効にする方法 -1. カプセルのみを使って、物理アセットを新規作成します。球体でもできますが、柔軟性が欠けます。カプセルはジョイントでわずかにオーバーラップします。足のカプセルは、キャラクターが地上にいるように見せる調整のために、もっとも重要です。腕は、地面を覆ったり這ったりする以外は、あまり必要ありません。 +1. カプセルのみを使って、物理アセットを新規作成します。球体でもできますが、柔軟性が欠けます。カプセルはジョイントでわずかにオーバーラップします。足のカプセルは、キャラクターが接地して見えるように調整する上でもっとも重要です。腕は、地面を覆ったり這ったりする以外は、あまり必要ありません。 2. 物理アセットをスケルタル メッシュ アセットの Shadow Physics アセットに割り当てます。 @@ -123,7 +123,7 @@ Dithered Opacity Mask を使って、不透明なマテリアルを使った ** ![image alt text](image_13.gif)(convert:false) -注記:この機能は有効化してもパフォーマンス負荷は低いので、マテリアル上で有効にしておかなければなりません。 +注記:** この機能は有効化してもパフォーマンス負荷は低いので、マテリアル上で有効にしておかなければなりません。 ![image alt text](image_14.png) @@ -195,7 +195,7 @@ Anim Dynamics の主要機能の概要です。 * Anim Dynamics は、APEX クロス オブジェクトに影響を与えるのと同じ風を起こすアクタと使用できます。ノードごとの切り替えが可能で、スケーリングすることで風の完璧に反応させることができます。 -* **補正サブステップ機能** +* **Adaptive sub-stepping** * シミュレーションは、物理プロジェクト設定にもとづいた法線ティック設定による実行、あるいは適応設定による実行が可能です。 @@ -213,7 +213,7 @@ Anim Dynamics の主要機能の概要です。 * Planar limits - Planar exclusion methods (平面制限のある球体コリジョン) + * Planar exclusion methods (平面制限のある球体コリジョン) ## 新規:ゲームプレイからのアニメーションのライブ録画 @@ -237,7 +237,7 @@ Anim Dynamics の主要機能の概要です。 ![image alt text](image_20.png) -## 新規:プラットフォームと SDK のアップデート +## 新規:Platform SDK のアップデート 通常のアップデートと合わせて、各種 VR プラットフォームの起動ウィンドウでのタイトル シッピングに備えて最新の SDK を使うためにすべての主要な VR プラットフォームもアップデートしました。今回のアップデートは安定性と仕上げに重点を置きました。UE4 4.11 で作成したタイトルは VR 出荷ができる状態のはずです! @@ -263,7 +263,7 @@ Anim Dynamics の主要機能の概要です。 * Linux Clang 3.7.0 -* Apple tvOS 9.0 support (GitHub only) +* Apple tvOS 9.0 サポート (GitHub のみ) ## 新規:Improved DirectX 12 @@ -287,7 +287,7 @@ Microsoft が実験的に **Xbox One** の **DirectX 12** にサポートを追 体験版なので、この機能を有効にするtレンダリングあるいは安定性に問題が発生する可能性があります。 -## 新規:Metal Rendering on Mac OS X +## 新規:Mac OS X 上でのメタル レンダリング メタルは Mac OS X El Capitan 上でデフォルトのグラフィック API になりました! @@ -295,7 +295,7 @@ Microsoft が実験的に **Xbox One** の **DirectX 12** にサポートを追 ![image alt text](image_23.png) [/REGION] -エピックは Apple、AMD、Nvidia、Intel と密接に連携して Mac のメタルを統合し、4.11 では OpenGL を OS X El Capitan 用主要グラフィックス API に置き換えました。4.11 では、Metal と OpenGL 全体に同じレンダリング機能がデフォルトで提供されています。Metal は、ストリームライン、プリコンパイルされたシェーダー付きで小さいオーバーヘッドの API、効率のよいマルチスレッド サポートで GPU の処理パワーを最大にします。今後も引き続き、Mac Metal のサポートを拡張させます。エンジンの将来のバージョンでこの新しい API 機能を活用する方法を模索します。 +エピックは Apple、AMD、NVIDIA、Intel と密接に連携して Mac のメタルを統合し、4.11 では OpenGL を OS X El Capitan 用主要グラフィックス API に置き換えました。4.11 では、Metal と OpenGL 全体に同じレンダリング機能がデフォルトで提供されています。Metal は、ストリームライン、プリコンパイルされたシェーダー付きで小さいオーバーヘッドの API、効率のよいマルチスレッド サポートで GPU の処理パワーを最大にします。今後も引き続き、Mac Metal のサポートを拡張させます。エンジンの将来のバージョンでこの新しい API 機能を活用する方法を模索します。 Shader Model 5 機能で実験的にメタルもサポートしました。"-metalsm5" コマンドライン スイッチを使って試してみてください。 @@ -311,13 +311,13 @@ Shader Model 5 機能で実験的にメタルもサポートしました。"-met ![image alt text](image_24.png)(w:640 convert:false) -ポータルは Lightmass に入射光を探す場所を伝えるたけで、ポータル自体が実際に光を放出しているわけではありません。最終的なライティングに重要な小さな隙間を覆う場合にポータルはもってこいです。Lightmass は入射光に向かう光線の焦点を合わせることができるので、質の高いライトとシャドウを生成することができます。(下図**左**: ポータルなし。**右**: ポータルあり。) +ポータルは Lightmass に入射光を探す場所を伝えるたけで、ポータル自体が実際に光を放出しているわけではありません。最終的なライティングに重要な小さな隙間を覆う場合にポータルはもってこいです。Lightmass は入射光に向かう光線の焦点を合わせることができるので、質の高いライトとシャドウを生成することができます。(下図 **左**: ポータルなし。**右**: ポータルあり。) ![image alt text](image_25.png)(w:640 convert:false) Lightmass のクオリティはその他の点でも改善されました。 -* ポイン ライト/スポットライト/ 指向性ライトで光が漏れるアーティファクトとを修正しました。 +* ポイン ライト / スポットライト / 指向性ライトで光が漏れるアーティファクトとを修正しました。 * スカイライトの直接ライティングが改善されました。 @@ -381,7 +381,7 @@ LOD のボーンを無効にするには、**スケルトンツリー** の右 ![image alt text](image_35.png) -### Performance results +### パフォーマンス結果 ![image alt text](image_36.png) @@ -401,9 +401,9 @@ LOD のボーンを無効にするには、**スケルトンツリー** の右 * [Volumetric PerVertex NonDirectional] 設定は非常に速く、Unlit マテリアルとほぼ同じ速度です。 -* Per-vertex lighting モードをできる限り使用することを推奨します。ライティングは各トライアングルを補間するので、非常に大きなパーティクルやトライアングルは例外です。 +* Per-vertex lighting モードをできる限り使用することを推奨します。ライティングはトライアングルごとに補間されるので、パーティクルまたはトライアングルが非常に大きい場合は例外です -## 新規:ライティング チャネル +## 新規:ライティング チャンネル ライティング チャネルは、**オブジェクトのライティング チャネルがオーバーラップした時に**、動的ライトがオブジェクトのみに影響を与えることを可能にします。**ライティング チャネルが 3 つまで** サポートされます。 @@ -499,7 +499,7 @@ Sound Concurrency オブジェクトは、Sound Attenuation Setting オブジェ 後方互換性の場合も、古いビヘイビアを好む場合も、Concurrency stetting オブジェクトをアセット上のローカルデータでオーバーライドする選択ができます。この場合、サウンド アセットは独自の並列処理グループとなり、アセット インスタンスで制限された並列処理の古いビヘイビアが実行されます。4.11 に変換された古いプロジェクトは、サウンド アセットをオーバーライドする設定に自動的になります。 -## 新規:Marker-Based Animation Syncing +## 新規:マーカーベースのアニメーション同期 ![image alt text](image_47.png) @@ -543,7 +543,7 @@ Sound Concurrency オブジェクトは、Sound Attenuation Setting オブジェ プロキシ メッシュ生成が簡素化されて、最近統合された Simplygon SDK の目玉であるメッシュ生成プロセスが [HLOD Outliner] パネルからも行えるようになります。 -その他の改善点 +その他の改善点: * スプライン メッシュが HLOD システムでサポートされます。 @@ -571,11 +571,11 @@ Sound Concurrency オブジェクトは、Sound Attenuation Setting オブジェ ## 新規:ブループリントの詳細検索 -ブループリントの検索ツールがアップデートされ、(精度のよい検索結果につながる) 詳細な検索機能が追加されました。 +The Blueprint search tool has been updated to support more advanced search functionality (to get more targeted results). ![image alt text](image_51.png) -ノード、ピン、グラフ、関数、マクロ、変数、プロパティ、コンポーネントなど特別なエレメントを検索対象にすることができます。詳細はこちら [https://docs.unrealengine.com/latest/INT/Engine/Blueprints/Search/index.html](https://docs.unrealengine.com/latest/INT/Engine/Blueprints/Search/index.html) をご覧ください。 +* ノード、ピン、グラフ、関数、マクロ、変数、プロパティ、コンポーネントなど特別なエレメントを検索対象にすることができます。詳細はこちら [https://docs.unrealengine.com/latest/INT/Engine/Blueprints/Search/index.html](https://docs.unrealengine.com/latest/INT/Engine/Blueprints/Search/index.html) をご覧ください。 * (syntax:Tag=Value を使用した) Tag/Value matching に加えて、And (&&) と Or (||) ロジック演算がサポートされます。 @@ -595,7 +595,7 @@ Sound Concurrency オブジェクトは、Sound Attenuation Setting オブジェ ## 新規:シーケンサーの進捗状況 (実験的) -シーケンサーは、新しいノンリニア シネマティクス アニメーション システムです。シーケンサーはまだまだ開発段階ですので、制作作業で使うことはお勧めできませんが、試しに使ってフィードバックして頂けると大変うれしいです!今後の UE4 リリースで、シーケンサーに関する情報をもっと提供できると思います。 +シーケンサーは、新しいノンリニア シネマティクス アニメーション システムです。シーケンサーは、新しいノンリニア シネマティクス アニメーション システムです。シーケンサーはまだまだ開発段階ですので、制作作業で使うことはお勧めできませんが、試しに使ってフィードバックして頂けると大変うれしいです!今後の UE4 リリースで、シーケンサーに関する情報をもっと提供できると思います。 4.11 でのシーケンサーの注目すべき新機能: @@ -613,7 +613,7 @@ Sound Concurrency オブジェクトは、Sound Attenuation Setting オブジェ シーケンサーを起動するには、[Plugins] パネルを開いて、[Level Sequence Editor] プラグインを有効にしてからエディタを再起動します。 -# Release Notes 「訳注: 以下は、非常に技術的な部分が含まれるため、翻訳を省略します。」 +# リリース ノート 「訳注: 以下は、非常に技術的な部分が含まれるため、翻訳を省略します。」 ### AI @@ -3359,7 +3359,7 @@ Stats are automatically broken into the threads they execute on and can appear i * New:Added an experimental option to enable OpenCL acceleration for the convex decomposition tool on Mac which defaults to off. - * This avoids an OpenCL crash on Nvidia's OpenCL drivers but still allows users of AMD & Intel GPUs to enable it if they wish. + * This avoids an OpenCL crash on the NVIDIA OpenCL drivers but still allows users of AMD & Intel GPUs to enable it if they wish. * Bugfix:Change the ShaderCache to report when resource references are invalid and prevent it from caching states that use invalid references to avoid errors on subsequent runs. @@ -5389,7 +5389,7 @@ Stats are automatically broken into the threads they execute on and can appear i * Added implementation of FPlatformProcess::UserTempDir() -* Bind the index buffer as vertex attribute 0 when performing an attribute-less draw call to work around incorrect gl_VertexID values on Nvidia drivers rather than using different index buffers. +* Bind the index buffer as vertex attribute 0 when performing an attribute-less draw call to work around incorrect gl_VertexID values on NVIDIA drivers rather than using different index buffers. * Detect when UE4 Mac is running under apitrace and fallback to using NSView rather than CoreAnimation to display so that tracing OpenGL works. @@ -5647,85 +5647,83 @@ Stats are automatically broken into the threads they execute on and can appear i * Here is an example of how one would build a custom native AnimInstance class using the new proxy, granting Blueprint access to its innards and avoiding copies of shared data between the proxy and the instance: -USTRUCT() + USTRUCT() -struct FExampleAnimInstanceProxy : public FAnimInstanceProxy + struct FExampleAnimInstanceProxy : public FAnimInstanceProxy -{ + { - GENERATED_BODY() + GENERATED_BODY() - FExampleAnimInstanceProxy() + FExampleAnimInstanceProxy() - :FAnimInstanceProxy() + :FAnimInstanceProxy() - {} + {} - FExampleAnimInstanceProxy(UAnimInstance* Instance); + FExampleAnimInstanceProxy(UAnimInstance* Instance); - virtual void Update(float DeltaSeconds) override + virtual void Update(float DeltaSeconds) override - { + { - // Update internal variables + // Update internal variables - MovementAngle += 1.0f * DeltaSeconds; + MovementAngle += 1.0f * DeltaSeconds; - HorizontalSpeed = FMath::Max(0.0f, HorizontalSpeed - DeltaSeconds); + HorizontalSpeed = FMath::Max(0.0f, HorizontalSpeed - DeltaSeconds); - } + } -public: + public: - UPROPERTY(Transient, BlueprintReadWrite, EditAnywhere, Category = "Example") + UPROPERTY(Transient, BlueprintReadWrite, EditAnywhere, Category = "Example") - float MovementAngle; + float MovementAngle; - UPROPERTY(Transient, BlueprintReadWrite, EditAnywhere, Category = "Example") + UPROPERTY(Transient, BlueprintReadWrite, EditAnywhere, Category = "Example") - float HorizontalSpeed; + float HorizontalSpeed; -}; + }; -UCLASS(Transient, Blueprintable) + UCLASS(Transient, Blueprintable) -class UExampleAnimInstance : public UAnimInstance + class UExampleAnimInstance : public UAnimInstance -{ + { - GENERATED_UCLASS_BODY() + GENERATED_UCLASS_BODY() - private: + private: + // The AllowPrivateAccess meta flag will allow this to be exposed to Blueprint, + // but only to graphs internal to this class. - // The AllowPrivateAccess meta flag will allow this to be exposed to Blueprint, + UPROPERTY(Transient, BlueprintReadOnly, Category = "Example", meta = (AllowPrivateAccess = "true")) - // but only to graphs internal to this class. + FExampleAnimInstanceProxy Proxy; - UPROPERTY(Transient, BlueprintReadOnly, Category = "Example", meta = (AllowPrivateAccess = "true")) + virtual FAnimInstanceProxy* CreateAnimInstanceProxy() override - FExampleAnimInstanceProxy Proxy; + { - virtual FAnimInstanceProxy* CreateAnimInstanceProxy() override + // override this to just return the proxy on this instance - { + return &Proxy; - // override this to just return the proxy on this instance + } - return &Proxy; + virtual void DestroyAnimInstanceProxy(FAnimInstanceProxy* InProxy) override - } + { - virtual void DestroyAnimInstanceProxy(FAnimInstanceProxy* InProxy) override + } - { + friend struct FExampleAnimInstanceProxy; - } - - friend struct FExampleAnimInstanceProxy; - -}; + }; * The following functions and variables of the **UAnimInstance** class are **now deprecated**: diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2016/4_11/ReleaseNotes_4_11.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2016/4_11/ReleaseNotes_4_11.KOR.udn index 9b186d688ce6..7d1169e71eb1 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2016/4_11/ReleaseNotes_4_11.KOR.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2016/4_11/ReleaseNotes_4_11.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3403469 Availability:Public Title:언리얼 엔진 4.11 릴리즈 노트 Crumbs:%ROOT%, Engine @@ -29,9 +29,9 @@ Anton Olkhovik (Sektor), Alessandro Osima (AlessandroOsima), Alexandru Pană (al **렌더링 퍼포먼스**. 이제 렌더러의 GPU 용 명령 버퍼 생성 및 워커 태스크 크기 밸런싱 능력을 개선시켜 GPU 부하 추가 없이 최대한의 병렬 처리 성능을 낼 수 있습니다. 렌더러의 동기화 지점을 제거하여 가능한 모든 코어를 더욱 잘 활용할 수 있도록도 했습니다. -**클로쓰 시뮬레이션** 이 대폭 빨라져 멀티 스레딩을 더욱 잘 활용합니다. 이제 워커 스레드에서 각 애셋에 대한 APEX 솔버를 직접 호출합니다. 이로써 스케쥴 성능이 훨씬 개선되고 다수의 동기화 지점과 부하가 제거됩니다. 클로딩은 이제 (블렌딩이 필요치 않은 경우) 애니메이션 이후 업데이트되고, 그렇지 않은 경우 스켈레탈 메시 컴포넌트 업데이트 이후에 일어납니다. +**클로스 시뮬레이션** 이 대폭 빨라져 멀티 스레딩을 더욱 잘 활용합니다. 이제 워커 스레드에서 각 애셋에 대한 APEX 솔버를 직접 호출합니다. 이로써 스케쥴 성능이 훨씬 개선되고 다수의 동기화 지점과 부하가 제거됩니다. 클로딩은 이제 (블렌딩이 필요치 않은 경우) 애니메이션 이후 업데이트되고, 그렇지 않은 경우 스켈레탈 메시 컴포넌트 업데이트 이후에 일어납니다. -**가비지 콜렉션** 속도가 빨라졌습니다. 이제 가비지 콜렉션 "클러스터"를 지원, 엔진이 오브젝트 그룹을 하나의 단위로 취급하도록 하여, 고려할 오브젝트 갯수를 현저히 줄이는 것이 가능해졌습니다. 현재 머티리얼과 파티클 시스템에 대해서만 클러스터가 지원됩니다. 추가적으로 마킹 & 소멸 단계가 캐시와의 일관성이 높아져, 시간적인 면에서는 1/9 로 감소되고, 도달가능성 분석 단계 도중에서도 메모리 교란(churn) 정도가 줄었습니다. +**가비지 컬렉션** 속도가 빨라졌습니다. 이제 가비지 컬렉션 "클러스터"를 지원, 엔진이 오브젝트 그룹을 하나의 단위로 취급하도록 하여, 고려할 오브젝트 갯수를 현저히 줄이는 것이 가능해졌습니다. 현재 머티리얼과 파티클 시스템에 대해서만 클러스터가 지원됩니다. 추가적으로 마킹 & 소멸 단계가 캐시와의 일관성이 높아져, 시간적인 면에서는 1/9 로 감소되고, 도달가능성 분석 단계 도중에서도 메모리 교란(churn) 정도가 줄었습니다. **멀티 스레드 애니메이션**. 애니메이션 그래프 업데이트가 이제 워커 스레드에서 실행되어 다수의 애니메이션 캐릭터를 복수 코어에 배분시킬 수 있게 되었습니다. 애니메이션 관련 API 다수가 폐기되고, 애니메이션 그래프의 워커 스레드 실행상 제약이 있으니 업그레이드 노트를 참고하시기 바랍니다. @@ -63,9 +63,9 @@ Anton Olkhovik (Sektor), Alessandro Osima (AlessandroOsima), Alexandru Pană (al 업데이트된 셰이딩 모델은 반해상도로 실행되며 차지하는 GPU 메모리도 적습니다. 산란은 해상도와 무관하게 이루어지며, 오브젝트 가장자리의 색 변이도 더이상 없습니다. 텍스처와 라이팅 디테일 보존 관련해서도, 디퓨즈와 스페큘러 라이팅 양쪽을 하나의 픽셀에 꾸려넣기 보다 체크무늬 패턴에 독립적으로 저장시키는 방식으로 개선되었습니다. -## 신규: 실사 클로쓰 셰이딩 +## 신규: 실사 클로스 셰이딩 -**클로쓰용 물리 기반 셰이딩 모델** 을 추가했습니다. 흐릿한 층 시뮬레이션으로 전에 없던 수준의 사실적인 클로쓰 결과물을 내게 되었습니다. 머티리얼 에디터에서 클로쓰 셰이딩 모델을 선택하면 사용할 수 있습니다. +**클로스용 물리 기반 셰이딩 모델** 을 추가했습니다. 흐릿한 층 시뮬레이션으로 전에 없던 수준의 사실적인 클로스 결과물을 내게 되었습니다. 머티리얼 에디터에서 클로스 셰이딩 모델을 선택하면 사용할 수 있습니다. ![image alt text](image_6.png) @@ -193,7 +193,7 @@ Instanced Stereo Rendering (인스턴스드 스테레오 렌더링)은 엔진의 * **바람** - * 애님 다이내믹스는 APEX 클로쓰 오브젝트에 영향을 끼치는 것과 동일한 바람 소스 액터와 함께 사용할 수 있습니다. 이는 노드별로 껐다 켰다 토글 가능하며, 스케일 조절을 통해 완벽한 바람의 느낌을 낼 수 있습니다. + * 애님 다이내믹스는 APEX 클로스 오브젝트에 영향을 끼치는 것과 동일한 바람 소스 액터와 함께 사용할 수 있습니다. 이는 노드별로 껐다 켰다 토글 가능하며, 스케일 조절을 통해 완벽한 바람의 느낌을 낼 수 있습니다. * **적응형 서브스테핑** @@ -1865,7 +1865,7 @@ Sequencer (시퀀서), 비선형 시네마틱 애니메이션 시스템이 새 * Bugfix: Duplicating, in a Property Tree, an array of instanced objects will correctly deep copy the objects instead of a shallow (referenced) copy. -* Bugfix: FBX exporter has two fixes: +* Bugfix: FBX exporter has two 픽스: * Fixed the export order to make sure the hierarchy is exported correctly. @@ -2715,7 +2715,7 @@ Sequencer (시퀀서), 비선형 시네마틱 애니메이션 시스템이 새 * Bugfix: Networking: Processing UDP receive buffer only if bytes received. -* Bugfix: Ping calculation fixes: +* Bugfix: Ping calculation 픽스: * Fix bug where extra acks were contributing to ping. @@ -5695,8 +5695,6 @@ class UExampleAnimInstance : public UAnimInstance GENERATED_UCLASS_BODY() - - private: // The AllowPrivateAccess meta flag will allow this to be exposed to Blueprint, diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2016/4_12/ReleaseNotes_4_12.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2016/4_12/ReleaseNotes_4_12.KOR.udn index ee2ab9d3f978..65fbd59652ea 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2016/4_12/ReleaseNotes_4_12.KOR.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2016/4_12/ReleaseNotes_4_12.KOR.udn @@ -298,7 +298,7 @@ UMG 웹 브라우저 위젯이 이제 iOS 에 지원됩니다! 풀 씬 임포트로 이제 Max / Maya / Blender 에서 이미 만든 환경을 가져와 전체 씬을 에디터의 레벨에 임포트할 수 있습니다. -![image alt text](image_24.jpg)(w:201 h:477 convert:false) ![image alt text](image_25.jpg)(w:572 h:470 convert:false) +![image alt text](image_24.jpg)(w:201 h:477 convert:false) ![image alt text](image_25.png)(w:572 h:470 convert:false) 환경에 새로운 씬 FBX 애셋이 생성되어, 다시 임포트하여 환경 반복처리 작업도 할 수 있습니다. 4.11 에서 사용할 수 있었던 초기 버전은 스태틱 메시가 들어있는 씬만 지원합니다. 4.12 버전에서는 스켈레탈 메시가 포함된 씬도 임포트할 수 있어 완성도가 높아졌습니다. @@ -614,7 +614,7 @@ Async compute (비동기 계산) 기능이 Xbox One 에 지원됩니다. 이를 * 애님 블루프린트 노출 값 처리기가 더이상 TRASHCLASS 로의 함수 레퍼런스를 담지 않습니다. -* 애님 인스턴스 프록시가 리졸브되었을 때의 가비지 콜렉션과 되돌리기/다시하기 관련 버그를 잡았습니다. +* 애님 인스턴스 프록시가 리졸브되었을 때의 가비지 컬렉션과 되돌리기/다시하기 관련 버그를 잡았습니다. * fast path 일 때 구조체에서 본별 레이어드 블렌드를 접근했을 때 값이 제대로 복사되지 않던 것을 고쳤습니다. @@ -652,7 +652,7 @@ Async compute (비동기 계산) 기능이 Xbox One 에 지원됩니다. 이를 * 마커 싱크 애니메이션 틱 도중 Prev Marker not found in GetMarkerIndicesForPosition 어서트가 더이상 발동되지 않던 것을 고쳤습니다. -* 애니메이션 오브젝트가 더이상 게임에서 부적절하게 가비지 콜렉팅되지 않습니다. 또한 커브 녹화의 최적화를 통해 녹화 마무리 시를 제외하고 키를 추가하지 않도록 했습니다. +* 애니메이션 오브젝트가 더이상 게임에서 부적절하게 가비지 컬렉팅되지 않습니다. 또한 커브 녹화의 최적화를 통해 녹화 마무리 시를 제외하고 키를 추가하지 않도록 했습니다. * 캐시 본이 스테이트 머신에서 필요할 때 제대로 호출됩니다. @@ -1160,7 +1160,7 @@ Async compute (비동기 계산) 기능이 Xbox One 에 지원됩니다. 이를 * 슬레이트 스로틀 조절이 더이상 뷰포트 크기조절 정상 작동을 방해하지 않습니다. -* 레퍼런스 뷰어의 Make collection from referenced assets (레퍼런싱된 애셋에서 콜렉션 만들기) 기능을 수정했습니다. +* 레퍼런스 뷰어의 Make collection from referenced assets (레퍼런싱된 애셋에서 컬렉션 만들기) 기능을 수정했습니다. * 클래스 선택기 필터의 작동방식이 다른 모든 에디터내 필터와 일치합니다. @@ -1292,7 +1292,7 @@ Async compute (비동기 계산) 기능이 Xbox One 에 지원됩니다. 이를 * 포즈 이밸류에이터 커스터마이제이션이 이제 올바른 시간에 처리됩니다. 프로퍼티를 디테일 패널에서 제거해도 다시 추가되어 항목이 중복되던 문제가 해결됩니다. -* 페르소나에서 자세한 메시 통계 표시 설정을 했을 때 보고된 트라이앵글 수가 더이상 클로쓰 섹션 수를 복제하지 않습니다. +* 페르소나에서 자세한 메시 통계 표시 설정을 했을 때 보고된 트라이앵글 수가 더이상 클로스 섹션 수를 복제하지 않습니다. * 페르소나에서 이밸류에이터 변환 이후 선택된 그래프 노드를 접근할 때의 크래시를 고쳤습니다. @@ -1334,7 +1334,7 @@ Async compute (비동기 계산) 기능이 Xbox One 에 지원됩니다. 이를 * 쿠킹된 패키지에 저장되던 클래스 플래그인 StaticMesh NavCollision 와 UParticleRequiredModule 임포트로 유발되는 결정론적 쿠킹 문제를 수정했습니다 (로드 순서에 따라 달라졌었습니다). -* 더이상 가비지 콜렉션이 콘텐츠를 변경된 것으로 마킹하지 않습니다. +* 더이상 가비지 컬렉션이 콘텐츠를 변경된 것으로 마킹하지 않습니다. * Fixup Redirects, Cook-on-the-fly Server 커맨드렛에 미세조정 작업이 있었습니다. @@ -1432,7 +1432,7 @@ Async compute (비동기 계산) 기능이 Xbox One 에 지원됩니다. 이를 * 자손 액터 컴포넌트 사본이 에디터 레벨에서 고아가 될 수 있었던 문제를 고쳤습니다. -* 자손 액터 컴포넌트가 킬 대기 상태로 마킹되어 있다가 가비지 콜렉션이 실행될 때까지도 깨끗하게 소멸되지 않았을 때의 크래시를 고쳤습니다. +* 자손 액터 컴포넌트가 킬 대기 상태로 마킹되어 있다가 가비지 컬렉션이 실행될 때까지도 깨끗하게 소멸되지 않았을 때의 크래시를 고쳤습니다. * Sound Quality 노드가 들어있는 사운드 큐를 네이티브 생생자에서 레퍼런싱해도 더이상 크래시가 나지 않습니다. @@ -1476,7 +1476,7 @@ Async compute (비동기 계산) 기능이 Xbox One 에 지원됩니다. 이를 * 콘솔이 닫히면 이제 뷰포트의 입력 상태를 (포커스와 캡처 둘 다) 제대로 복원합니다. -* 가비지 콜렉션 도중 서브 컴포넌트에서 Destroy Component 를 호출할 때의 크래시를 고쳤습니다. +* 가비지 컬렉션 도중 서브 컴포넌트에서 Destroy Component 를 호출할 때의 크래시를 고쳤습니다. * Engine.ini 에 지정된 Game Singleton 클래스가 유효하지 않아도 더이상 크래시가 나지 않습니다. @@ -1760,7 +1760,7 @@ Async compute (비동기 계산) 기능이 Xbox One 에 지원됩니다. 이를 * 애님 다이내믹스에 시뮬레이션 스페이스 및 외부 포스가 지원됩니다. -* 기존 및 앞으로의 클로쓰 청크에 청크당 인플루언스가 4 개 이상 되지 않는지 확인하는 검증을 추가했습니다. 기존 청크는 오류는 아니지만 로그 경고는 납니다. +* 기존 및 앞으로의 클로스 청크에 청크당 인플루언스가 4 개 이상 되지 않는지 확인하는 검증을 추가했습니다. 기존 청크는 오류는 아니지만 로그 경고는 납니다. * 접촉 오프셋 값을 프로젝트 피직스 세팅에 노출시킵니다. 이 값이 기존의 환경 변수 값을 덮어씁니다. @@ -1772,7 +1772,7 @@ Async compute (비동기 계산) 기능이 Xbox One 에 지원됩니다. 이를 * 컴포넌트의 모빌리티가 스태틱으로 변경되면, 그 부모에 더이상 시뮬레이션 오브젝트 마킹이 남아있지 않습니다. -* LOD 변경시 클로쓰가 부드럽게 작동합니다. +* LOD 변경시 클로스가 부드럽게 작동합니다. * 블루프린트의 커스텀 콜리전 변경시 이제 재시작할 필요 없이 배치된 인스턴스가 업데이트됩니다. @@ -1792,9 +1792,9 @@ Async compute (비동기 계산) 기능이 Xbox One 에 지원됩니다. 이를 * BP 호출가능 함수 중 스켈레탈 메시 컴포넌트 트랜스폼에 영향을 끼치는 것이 이제 물리 시뮬레이션 중에도 작동합니다. -* 클로쓰 솔버 빈도가 더이상 1 아래로 떨어지지 않습니다. +* 클로스 솔버 빈도가 더이상 1 아래로 떨어지지 않습니다. -* 클로쓰 업데이트가 스켈레탈 메시 컴포넌트 업데이트 모드를 사용하여 렌더 상태가 아닌 업데이트를 결정합니다.tatus. +* 클로스 업데이트가 스켈레탈 메시 컴포넌트 업데이트 모드를 사용하여 렌더 상태가 아닌 업데이트를 결정합니다.tatus. * (에디터와 게임에서의) 콜리전 그리기가 숨겨진 스태틱 메시 인스턴스에도 정상 작동합니다. @@ -1802,15 +1802,15 @@ Async compute (비동기 계산) 기능이 Xbox One 에 지원됩니다. 이를 * LOD 모델 정리가 되지 않아 발생하던 디스트럭터블 메시 리임포트 크래시를 고쳤습니다. -* 페르소나에서 메시에 클로딩 애셋이 둘 이상일 때 클로쓰 할당을 해제해도 더이상 크래시가 나지 않습니다. +* 페르소나에서 메시에 클로딩 애셋이 둘 이상일 때 클로스 할당을 해제해도 더이상 크래시가 나지 않습니다. * 모든 청크가 비활성 상태일 때 디스트럭터블 컴포넌트의 공백 바운드로 유발되던 ensure 를 수정했습니다. * Consider All Bodies 가 켜진 메시에 대해 바운드가 틀리던 문제를 고쳤습니다. -* 클로쓰의 메모리 누수(렌더 생성시 클로쓰 청크 당 1.43 KB)와 다른 모든 버텍스 팩토리의 불안전 메모리 관리를 제거했습니다. +* 클로스의 메모리 누수(렌더 생성시 클로스 청크 당 1.43 KB)와 다른 모든 버텍스 팩토리의 불안전 메모리 관리를 제거했습니다. -* LOD 본 관련해서, 특정 LOD 에 웨이팅되지 않은 본을 사용하는 클로쓰 청크 할당시의 필수 사항을 고쳤습니다. +* LOD 본 관련해서, 특정 LOD 에 웨이팅되지 않은 본을 사용하는 클로스 청크 할당시의 필수 사항을 고쳤습니다. * 자체 교차 집계가 이제 자체 콜리전 비트맵을 소거시켜, broadphase 크래시가 예방됩니다. diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2016/4_14/ReleaseNotes_4_14.CHN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2016/4_14/ReleaseNotes_4_14.CHN.udn index 7a3d10384ef4..39333df47c57 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2016/4_14/ReleaseNotes_4_14.CHN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2016/4_14/ReleaseNotes_4_14.CHN.udn @@ -3,6 +3,8 @@ Availability:Public Title:虚幻引擎 4.14 版本信息 Description:虚幻引擎 4.14 版本信息说明 Crumbs:%ROOT%, Engine +Parent:Support/Builds +Order:14 reference-image:image_6.gif reference-image:image_7.gif reference-image:image_9.gif diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2016/4_14/ReleaseNotes_4_14.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2016/4_14/ReleaseNotes_4_14.JPN.udn index f050861a4bf6..9e911b7c50e9 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2016/4_14/ReleaseNotes_4_14.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2016/4_14/ReleaseNotes_4_14.JPN.udn @@ -1,8 +1,10 @@ -INTSourceChangelist:3223841 +INTSourceChangelist:3304581 Availability:Public Title:アンリアル エンジン 4.14 リリース ノート Description:Unreal Engine 4.14 リリース ノート Crumbs:%ROOT%, Engine +Parent:Support/Builds +Order:14 reference-image:image_6.gif reference-image:image_7.gif reference-image:image_9.gif diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2016/4_14/ReleaseNotes_4_14.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2016/4_14/ReleaseNotes_4_14.KOR.udn index 1156f2670f81..5a7bb153b10e 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2016/4_14/ReleaseNotes_4_14.KOR.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/2016/4_14/ReleaseNotes_4_14.KOR.udn @@ -528,7 +528,7 @@ Child Actor (자손 액터) 컴포넌트를 추가한 이후에는, 소유중인 ## 신기능: 모바일에서 커스텀 뎁스 지원 -모바일 렌더링 패쓰에서 커스텀 뎁스가 지원됩니다. 커스텀 포스트 프로세스 머티리얼은 이제 씬 뎁스, 커스텀 뎁스는 물론 씬 컬러에서도 샘플링 가능합니다. +모바일 렌더링 패스에서 커스텀 뎁스가 지원됩니다. 커스텀 포스트 프로세스 머티리얼은 이제 씬 뎁스, 커스텀 뎁스는 물론 씬 컬러에서도 샘플링 가능합니다. [REGION:raw] ![image alt text](image_52.png)(w:804 h:394 convert:false) @@ -552,7 +552,7 @@ Child Actor (자손 액터) 컴포넌트를 추가한 이후에는, 소유중인 * 씬 캡처는 이제 안드로이드 6 이전 갤럭시 S6 등 부동소수점 타겟을 지원하지 않는 디바이스에서도 정상 작동합니다. -## 클로쓰 스키닝 개선 +## 클로스 스키닝 개선 엔진 내에서 클로딩에 쓰이는 별도의 메시 대 메시 스키닝 데이터를 계산하는 기능을 추가, 이제 .apx 나 .apb 파일로 익스포트된 렌더 데이터를 사용하는 대신 UE4 가 이미 갖고 있는 렌더 데이터를 사용합니다. APEX 익스포트된 애셋에서 시뮬레이션 메시를 구한 다음, 그 메시에 렌더 데이터 스킨을 다시 입힙니다. 즉 최종 데이터가 원래 임포트한 데이터만큼 괜찮아 보인다는 뜻입니다. @@ -778,7 +778,7 @@ CPU 에 종속된 어떤 경우는, GPU 시간이 CPU 병목 (버블) 현상에 ## 신기능: 모바일용 VR 멀티뷰 지원 -이제 모바일 디바이스에서 (지원되는 경우) 모바일 멀티뷰 패쓰를 사용할 수 있습니다! 모바일 멀티뷰는 데스크탑의 인스턴스드 스테레오와 비슷하며, CPU 의 스테레오 렌더링에 대한 최적화된 패쓰를 제공해 줍니다. +이제 모바일 디바이스에서 (지원되는 경우) 모바일 멀티뷰 패스를 사용할 수 있습니다! 모바일 멀티뷰는 데스크탑의 인스턴스드 스테레오와 비슷하며, CPU 의 스테레오 렌더링에 대한 최적화된 패스를 제공해 줍니다. 이 기능을 사용하려면, 프로젝트 세팅의 VR 섹션 아래에서 활성화시켜 줍니다. 이 기능의 정상 작동을 위해서는 안드로이드 빌드 세팅을 OpenGL ES2 로 설정하고, 모바일 HDR 과 인스턴스드 스테레오는 꺼야 합니다. 현재 이 기능은 최신 Mali 기반 디바이스와 호환됩니다. 이 기능을 켠 채로 패키징을 해도 호환 CPU 가 없는 경우, 실행시간에 꺼집니다. diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_0/Updates/UnrealEngine4_0UpdateNotes.CHN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_0/Updates/UnrealEngine4_0UpdateNotes.CHN.udn new file mode 100644 index 000000000000..140be66cd3c0 --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_0/Updates/UnrealEngine4_0UpdateNotes.CHN.udn @@ -0,0 +1,72 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 虚幻引擎 4.0 更新日志 +Description: +Crumbs: +Parent:Support/Builds +Order:0 + +## 4.0.0 Release + +Released: 03/19/2014 + +Announcement: + +[https://www.unrealengine.com/blog/welcome-to-unreal-engine-4](https://www.unrealengine.com/blog/welcome-to-unreal-engine-4) + +## 4.0.1 Hotfix + +Released: 03/19/2014 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.0.1-release](https://github.com/EpicGames/UnrealEngine/tree/4.0.1-release) + +Fixes: + +* Fixed critical launch issues + +## 4.0.2 Hotfix + +Released: 04/01/2014 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.0.2-release](https://github.com/EpicGames/UnrealEngine/tree/4.0.2-release) + +Fixes: + +* [Windows] Fixed DirectX 11 crash when launching on older GPUs + +* [Windows] Fixed being unable to compile Android projects when launching from the editor + +* [Windows] Fixed crash on startup for some AMD CPUs + +* [Windows] Fixed broken shell extensions when running RegisterShellCommands.bat in GitHub builds using "Run as Administrator" + +* [Windows] Added support files required for Subversion support (preview release) + +* [Windows] Fixed issue where engine could fail to compile with multiple versions of Visual Studio installed + +* [Mac] Fixed crash on startup caused by certain USB peripherals plugged in + +* [Mac] Fixed logs being cut off after crash + +* [Mac] Fixed crash on startup caused by non-standard maximum number of open files + +* [Mac] Noticeably improved performance on non-Intel GPUs + +* [Mac] Fixed crash on startup running ShooterGame as a standalone game + +## QFE for the 4.0.2 Hotfix + +If you are using the latest hotfix for this engine version and experience the issue described below, download and run this ‘quick fix’ to resolve the issue. + +* Fixes Launcher failing to launch after install on Mac; and unable to read info about mouse. ([report](https://answers.unrealengine.com/questions/30577/unreal-engine-install-launcher-fails-osx.html)) + +Download 1: [http://cdn.unrealengine.com/qfe/QFE-FromCL-2034640-Shelve-2048959.zip](http://cdn.unrealengine.com/qfe/QFE-FromCL-2034640-Shelve-2048959.zip) + +Download 2: [http://cdn.unrealengine.com/qfe/UnrealEngine_QFE_2039063.dmg](http://cdn.unrealengine.com/qfe/UnrealEngine_QFE_2039063.dmg) + +Notes: When you get them, install Unreal Engine app from UnrealEngine_QFE_2039063.dmg to your /Applications folder, then open Terminal app and type: + +* open /Applications/Unreal\ Engine.app --args -noselfupdate + +-noselfupdate argument is important because without it the app would update to official version that doesn't work for you. After you download the engine using Unreal Engine app, unzip QFE-FromCL-2034640-Shelve-2048959.zip and run the patch installer it contains. After that you should be able to use the editor etc. You can start the editor by launching it directly: /Users/Shared/UnrealEngine/4.0/Engine/Binaries/MacUE4Editor.app. + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_0/Updates/UnrealEngine4_0UpdateNotes.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_0/Updates/UnrealEngine4_0UpdateNotes.JPN.udn index dccd9d74ccb0..c05d03c156ea 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_0/Updates/UnrealEngine4_0UpdateNotes.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_0/Updates/UnrealEngine4_0UpdateNotes.JPN.udn @@ -1,6 +1,6 @@ INTSourceChangelist:0 Availability:Public -Title: Unreal Engine 4.0 Update Notes +Title: アンリアル エンジン 4.0 アップデート ノート Description: Crumbs: Parent:Support/Builds diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_0/Updates/UnrealEngine4_0UpdateNotes.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_0/Updates/UnrealEngine4_0UpdateNotes.KOR.udn new file mode 100644 index 000000000000..7cfd7f53192d --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_0/Updates/UnrealEngine4_0UpdateNotes.KOR.udn @@ -0,0 +1,72 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 언리얼 엔진 4.0 업데이트 노트 +Description: +Crumbs: +Parent:Support/Builds +Order:0 + +## 4.0.0 릴리즈 + +릴리즈 날짜: 2014/03/19 + +Announcement: + +[https://www.unrealengine.com/blog/welcome-to-unreal-engine-4](https://www.unrealengine.com/blog/welcome-to-unreal-engine-4) + +## 4.0.1 핫픽스 + +릴리즈 날짜: 2014/03/19 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.0.1-release](https://github.com/EpicGames/UnrealEngine/tree/4.0.1-release) + +픽스: + +* 치명적인 실행 관련 이슈를 수정했습니다. + +## 4.0.2 핫픽스 + +릴리즈 날짜: 2014/04/01 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.0.2-release](https://github.com/EpicGames/UnrealEngine/tree/4.0.2-release) + +픽스: + +* [윈도우] 구형 GPU 에서 실행할 때의 DirectX 11 크래시를 고쳤습니다. + +* [윈도우] 에디터에서 실행할 때 안드로이드 프로젝트를 컴파일할 수 없던 것을 고쳤습니다. + +* [윈도우] 일부 AMD CPU 에서 시작시 발생하는 크래시를 고쳤습니다. + +* [윈도우] GitHub 빌드에서 "관리자 권한으로 실행"을 사용하여 RegisterShellCommands.bat 를 실행할 때 깨지던 셸 익스텐션을 수정했습니다. + +* [윈도우] Subversion 지원에 필요한 서포트 파일을 추가했습니다 (프리뷰 릴리즈). + +* [윈도우] Visual Studio 가 여러 버전 설치된 상태에서 엔진 컴파일에 실패할 수 있던 이슈를 고쳤습니다. + +* [맥] 특정 USB 주변장치가 연결된 상태에서 시작시 유발되는 크래시를 고쳤습니다. + +* [맥] 크래시 이후 로그가 잘리던 것을 고쳤습니다. + +* [맥] 열린 파일 최대 갯수가 비표준일 경우 시작 시 발생하는 크래시를 고쳤습니다. + +* [맥] Intel GPU 가 아닌 경우의 퍼포먼스가 크게 향상되었습니다. + +* [맥] ShooterGame 을 독립형 게임으로 실행할 때의 크래시를 고쳤습니다. + +## 4.0.2 핫픽스 QFE + +이번 엔진 버전의 최신 핫픽스를 사용하다가 아래 이슈를 겪으시는 경우, 이 '퀵 픽스'를 다운로드하여 실행하면 이슈 해결이 가능합니다. + +* 맥에 런처를 설치한 후 실행되지 않고, 마우스 관련 정보를 읽어들이지 못하는 데 대한 픽스입니다. ([리포트](https://answers.unrealengine.com/questions/30577/unreal-engine-install-launcher-fails-osx.html)) + +다운로드 1: [http://cdn.unrealengine.com/qfe/QFE-FromCL-2034640-Shelve-2048959.zip](http://cdn.unrealengine.com/qfe/QFE-FromCL-2034640-Shelve-2048959.zip) + +다운로드 2: [http://cdn.unrealengine.com/qfe/UnrealEngine_QFE_2039063.dmg](http://cdn.unrealengine.com/qfe/UnrealEngine_QFE_2039063.dmg) + +주: 받은 후 Unreal Engine 앱을 UnrealEngine_QFE_2039063.dmg 에서 /Applications 폴더로 설치한 뒤, Terminal 앱을 열고 다음과 같이 입력합니다: + +* open /Applications/Unreal\ Engine.app --args -noselfupdate + +-noselfupdate 인수가 중요한데, 없으면 앱에서는 정상 작동되지 않는 공식 버전으로 업데이트되기 때문입니다. Unreal Engine 앱을 사용하여 엔진을 다운로드한 후, QFE-FromCL-2034640-Shelve-2048959.zip 압축을 풀고 거기 들어있는 패치 인스톨러를 실행합니다. 그 후에는 에디터 등을 사용할 수 있을 것입니다. 에디터는 다음 위치에서 바로 실행시킬 수도 있습니다: /Users/Shared/UnrealEngine/4.0/Engine/Binaries/MacUE4Editor.app. + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_1/Updates/UnrealEngine4_1UpdateNotes.CHN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_1/Updates/UnrealEngine4_1UpdateNotes.CHN.udn new file mode 100644 index 000000000000..a3196f1c6bbb --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_1/Updates/UnrealEngine4_1UpdateNotes.CHN.udn @@ -0,0 +1,56 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 虚幻引擎 4.1 更新日志 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/2014/4_1 +Order:0 + +## 4.1.0 Release + +Released: 04/22/2014 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.1.0-release](https://github.com/EpicGames/UnrealEngine/tree/4.1.0-release) + +Release Notes: + +[https://docs.unrealengine.com/latest/INT/Support/Builds/ReleaseNotes/2014/4_1/index.html](https://docs.unrealengine.com/latest/INT/Support/Builds/ReleaseNotes/2014/4_1/index.html) + +## 4.1.1 Hotfix + +Released: 05/12/2014 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.1.1-release](https://github.com/EpicGames/UnrealEngine/tree/4.1.1-release) + +Fixes: + +* Fixed shader material instances not being saved to DDC, causing many shaders to be rebuilt when loading the editor. + +* Fixed crash on iOS/Android reading blueprint assets with certain unaligned opcodes. + +* Fixed handling of volume buttons on Android. + +* Fixed sporadic crash caused by race condition in the XboxOne texture compressor. + +* Fixed engine compiling more shaders than necessary in the material editor. + +* Fixed severe performance regression for some GPU combos on Windows, where the engine would fall back to the software renderer. + +* Fixed crash when pressing the news feed refresh button multiple times. + +* Updated .gitignore to include SDL2 + +* Addressed an analytics error + +## 4.1.2 Hotfix + +Released: 06/25/2014 + +Github: *N/A* + +Fixes: + +* Fix crash when loading certain blueprints + +* Fix corrupted map in StrategyGame causing a crash on 4.1.2 launch + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_1/Updates/UnrealEngine4_1UpdateNotes.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_1/Updates/UnrealEngine4_1UpdateNotes.JPN.udn index 10c6491567a1..95b8698210df 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_1/Updates/UnrealEngine4_1UpdateNotes.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_1/Updates/UnrealEngine4_1UpdateNotes.JPN.udn @@ -1,6 +1,6 @@ INTSourceChangelist:0 Availability:Public -Title: Unreal Engine 4.1 Update Notes +Title: アンリアル エンジン 4.1 アップデート ノート Description: Crumbs: Parent:Support/Builds/ReleaseNotes/2014/4_1 diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_1/Updates/UnrealEngine4_1UpdateNotes.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_1/Updates/UnrealEngine4_1UpdateNotes.KOR.udn new file mode 100644 index 000000000000..05175307913d --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_1/Updates/UnrealEngine4_1UpdateNotes.KOR.udn @@ -0,0 +1,56 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 언리얼 엔진 4.1 업데이트 노트 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/2014/4_1 +Order:0 + +## 4.1.0 릴리즈 + +릴리즈 날짜: 2014/04/22 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.1.0-release](https://github.com/EpicGames/UnrealEngine/tree/4.1.0-release) + +Release Notes: + +[https://docs.unrealengine.com/latest/INT/Support/Builds/ReleaseNotes/2014/4_1/index.html](https://docs.unrealengine.com/latest/INT/Support/Builds/ReleaseNotes/2014/4_1/index.html) + +## 4.1.1 핫픽스 + +릴리즈 날짜: 2014/05/12 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.1.1-release](https://github.com/EpicGames/UnrealEngine/tree/4.1.1-release) + +픽스: + +* DDC 에 셰이더 머티리얼 인스턴스가 저장되지 않아, 에디터를 로드할 때 다수의 셰이더를 다시 빌드하게 만들던 것을 고쳤습니다. + +* 일정한 미정렬 opcode 포함 블루프린트를 읽을 때의 iOS/Android 크래시를 고쳤습니다. + +* 안드로이드의 볼륨 버튼 처리를 수정했습니다. + +* XboxOne 텍스처 압축기에서 경쟁 조건으로 간헐적 발생하는 크래시를 고쳤습니다. + +* 머티리얼 에디터에서 엔진이 필요한 것보다 많은 셰이더를 컴파일하던 것을 고쳤습니다. + +* 윈도우에서 일부 GPU 콤보 관련 심각한 퍼포먼스 퇴보로 인해 엔진이 소프트웨어 렌더러로 예비 전환하게 만들던 것을 고쳤습니다. + +* 뉴스 피드 새로고침 버튼을 여러 번 누를 때 발생하던 크래시를 고쳤습니다. + +* .gitignore 가 SDL2 를 포함하도록 업데이트했습니다. + +* 애널리틱스 오류를 처리했습니다. + +## 4.1.2 핫픽스 + +릴리즈 날짜: 2014/06/25 + +Github: *N/A* + +픽스: + +* 특정 블루프린트를 로드할 때 발생하는 크래시를 고쳤습니다. + +* StrategyGame 의 깨진 맵이 4.1.2 실행 시 크래시를 유발하던 것을 고쳤습니다. + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_10/Updates/UnrealEngine4_10UpdateNotes.CHN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_10/Updates/UnrealEngine4_10UpdateNotes.CHN.udn new file mode 100644 index 000000000000..c7dcc15cbf32 --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_10/Updates/UnrealEngine4_10UpdateNotes.CHN.udn @@ -0,0 +1,178 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 虚幻引擎 4.10 更新日志 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/2015/4_10 +Order:0 + +## 4.10.0 Release + +Released: 11/11/2015 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.10.0-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.10.0-release) + +Release Notes: [](Support/Builds/ReleaseNotes/2015/4_10) + +## 4.10.1 Hotfix + +Released: 12/08/2015 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.10.1-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.10.1-release) + +Fixes: + +* UE-23364 Make sure that Perforce integration works with SSL connections when compiled with VS2015 + +* UE-21181 [CrashReport] Object from PIE level still referenced. (via FWorldContext in UEngine::AddReferencedObjects?) + +* UE-23371 [CrashReport] UE4Editor_GraphEditor!FNodeFactory::CreateNodeWidget() nodefactory.cpp:91 + +* UE-23372 [CrashReport] Indexing Blueprints for FiB data causes: KERNELBASE! + +* UE-23230 iOS min supported version > 6.1 = Crashing Leaderboard Writes + +* UE-23366 [CrashReport] UE4Editor_Engine!USceneComponent::OnComponentDestroyed() [scenecomponent.cpp:676] + +* UE-23250 PS4Tracker Crash + +* UE-23394 Intermittent crash in CacheOptimizeIndexBuffer on Editor startup on Linux + +* UE-23302 GitHub 1751 : Fix for USceneComponent::AttachTo() crash + +* UE-20336 Hovering over tooltip for Post Process Settings causes CPU Color Scheme Change & Win10 hard-freeze + +* UE-23877 Lots of people running into an Ensure in PathFollowingComponent + +* UE-23232 Metal + iOS projects = Black Screen on iPhone 6s + +* UE-23288 Bug: No text being displayed on iPhone 4s + +* UE-23289 Bug: Crash and to home screen on iPhone 4s + +* UE-23382 Compile for Size Causes Animations to Play Incompletely on iOS + +* UE-23290 Bug: No Force Feedback + +* UE-23664 Unable to push to SteamVR in 4.10 while Oculus 0.8 service is running + +* UE-23150 Refraction does not render correctly on Mosaic devices + +* UE-23611 Android streaming audio repeats at start if start time is 0.0 + +* UE-23694 Rework streaming audio fix for hotfix + +* UE-22968 UnrealFrontend Quick Launch to Android Fails While Deploying + +* UE-23655 GitHub 1776 : Fix compile error for Android x86 and x64 + +* UE-21858 Visible dithered quantization to remove banding in New Temporal AA Quality + +* UE-23149 Async linetraces can re-call the results delegate repeatedly + +* UE-23362 Gnm: submitDone () is not called for X seconds + +* UE-23415 USB Keyboard not working in shipping builds + +* UE-23426 Changes to World.h and WorldCollision.h need to be removed + +* UE-23662 HRTF Spatialization Broken + +* UE-23812 Packaged games should not send hardware survey telemetry event + +* UE-23688 Modulated shadow blending incorrect with encoded HDR. + +* UE-23762 Setting Runtime Generation to Static Resets Upon Closing and Re-opening Editor + +* UE-23048 UAIPerceptionStimuliSourceComponent never registers with required senses + +* UE-22866 [4.10 P2] UI is offcenter for dropdown menus and tooltips in editor + +* UE-23064 Target build folder does not clear when repackaging + +* UE-23132 Wildcard Array in Macro Causes Error Message to Appear + +* UE-23233 Upgrading Project to a New Engine Version Causes Errors When Attempting to Open Tutorial Blueprints + +* UE-21717 Self Shadow Only causes rendering artifacts + +* UE-22949 Unable to open UE4Editor on Linux - Bad hlslcc header found + +* UE-23746 4.10 is gathering editor-only BP text for game loc gathers + +* UE-22157 Android In App Purchase can return false even though the transaction is successfully completed. + +* UE-23190 Android/Google Play In-App Purchase Blueprint node only works if you fire the node twice + +* UE-23365 GitHub 1763 : Update README.md / VS2013 -> VS2015 + +* UE-23151 UE4 4.10 needs a Localization Update + +## 4.10.2 Hotfix + +Released: 01/11/2016 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.10.2-release](https://github.com/EpicGames/UnrealEngine/tree/4.10.2-release) + +Fixes: + +* UE-23845 Crash when using "Set Key Time" on an animation key in UMG + +* UE-24685 Matinee movie recording is broken in 4.10 + +* UE-22573 A REINST error occurs in widgets that reference one another + +* UE-24115 Cannot launch the editor in DebugGame Editor configuration from Xcode + +* UE-24563 Editor should launch launcher silently + +## 4.10.3 Hotfix + +Released: 02/17/2016 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.10.3-release](https://github.com/EpicGames/UnrealEngine/tree/4.10.3-release) + +Fixes: + +* OPP-4947 Installation Error code R-1638 / Unable to upgrade to 4.10.1 through launcher if 4.11 has been installed + +* UE-13030 Crash related to loading sub-level - UEngine::LoadMap() + +* UE-22075 Crash on compile when nodes use same name - FPersistentFrameCollectorArchive::operator<<() + +* UE-22696 Crash on importing specific Skeletal FBX exported with FBX2016 + +* UE-22921 Parenting multiple actors under border crashes editor + +* UE-23373 Crash occurs opening some animations - TSharedMapView::Find() + +* UE-23785 Crash in UE4Editor_Core!FSlowTask::GetCurrentMessage() + +* UE-24169 Crash in PlayerInput.cpp - UPlayerInput::ProcessInputStack() + +* UE-24443 Potential Crash When Migrating Assets - FGenericPlatformString::LogBogusChars() + +* UE-26315 Crash in UE4Editor_Engine!UActorComponent::BeginPlay() + +* UE-26872 Loc gathering can crash in 4.10 + +* UE-23231 Can't Upload iOS build signed on PC + +* UE-24972 VR headtracking locked on game start for some templates + +* UE-26158 bIsActorBeingDestroyed incorrectly Commented out + +* UE-26657 Regression on sprite import improvements from 4.9 + +* UE-26903 Loc dashboard doesn't export native translations when exporting a single culture + +## 4.10.4 Hotfix + +Released: 02/22/2016 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.10.4-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.10.4-release) + +Fixes: + +* UE-27124 Switching levels via blueprints crashes editor + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_10/Updates/UnrealEngine4_10UpdateNotes.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_10/Updates/UnrealEngine4_10UpdateNotes.JPN.udn index 92e8f4d8c9f2..6e5810c788e3 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_10/Updates/UnrealEngine4_10UpdateNotes.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_10/Updates/UnrealEngine4_10UpdateNotes.JPN.udn @@ -1,6 +1,6 @@ INTSourceChangelist:0 Availability:Public -Title: Unreal Engine 4.10 Update Notes +Title: アンリアル エンジン 4.10 アップデート ノート Description: Crumbs: Parent:Support/Builds/ReleaseNotes/2015/4_10 diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_10/Updates/UnrealEngine4_10UpdateNotes.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_10/Updates/UnrealEngine4_10UpdateNotes.KOR.udn new file mode 100644 index 000000000000..1e63933a8be5 --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_10/Updates/UnrealEngine4_10UpdateNotes.KOR.udn @@ -0,0 +1,177 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 언리얼 엔진 4.10 업데이트 노트 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/2015/4_10 +Order:0 + +## 4.10.0 릴리즈 + +릴리즈 날짜: 2015/11/11 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.10.0-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.10.0-release) + +릴리즈 노트: [](Support/Builds/ReleaseNotes/2015/4_10) + +## 4.10.1 핫픽스 + +릴리즈 날짜: 2015/12/08 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.10.1-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.10.1-release) + +픽스: + +* UE-23364 VS2015 로 컴파일 시 SSL 접속 포함 Perforce 통합이 작동되는지 확인 + +* UE-21181 [CrashReport] PIE 레벨에서의 오브젝트가 여전히 레퍼런싱됨 (아마 UEngine::AddReferencedObjects 의 FWorldContext 를 통해서?) + +* UE-23371 [CrashReport] UE4Editor_GraphEditor!FNodeFactory::CreateNodeWidget() nodefactory.cpp:91 + +* UE-23372 [CrashReport] FiB 데이터에 대한 블루프린트 인덱스가 다음 유발: KERNELBASE! + +* UE-23230 iOS 최소 지원 버전 > 6.1 = 리더보드 쓰기 시 크래시 + +* UE-23366 [CrashReport] UE4Editor_Engine!USceneComponent::OnComponentDestroyed() [scenecomponent.cpp:676] + +* UE-23250 PS4Tracker 크래시 + +* UE-23394 리눅스에서 에디터 시작 시 CacheOptimizeIndexBuffer 의 간헐적 크래시 + +* UE-23302 GitHub 1751 : USceneComponent::AttachTo() 크래시 픽스 + +* UE-20336 Post Process Settings 툴팁에 커서를 올리면 CPU Color Scheme Change & Win10 하드 프리즈 + +* UE-23877 많은 사람이 PathFollowingComponent 에서 Ensure 발생 + +* UE-23232 Metal + iOS 프로젝트 = iPhone 6s 에서 검은 화면 + +* UE-23288 버그: iPhone 4s 에 텍스트 표시 안됨 + +* UE-23289 버그: iPhone 4s 에서 크래시 후 홈 화면으로 + +* UE-23382 Compile for Size 로 인해 애니메이션이 iOS 에서 불완전 재생 + +* UE-23290 버그: 포스 피드백 없음 + +* UE-23664 Oculus 0.8 서비스 실행 도중 4.10 에서 SteamVR 에 푸시 불가 + +* UE-23150 Mosaic 디바이스에서 굴절이 제대로 렌더링되지 않음 + +* UE-23611 안드로이드 스트리밍 오디오가 시작 시간이 0.0 인 것처럼 시작 부분에서 반복 + +* UE-23694 핫픽스용 스트리밍 오디오 픽스 재작업 + +* UE-22968 UnrealFrontend 에서 디플로이 도중 Quick Launch to Android 실패 + +* UE-23655 GitHub 1776 : Android x86 및 x64 용 컴파일 오류 픽스 + +* UE-21858 새로운 템포럴 AA 퀄리티의 띠 현상 제거를 위해 보이는 디더링 양자화 + +* UE-23149 비동기 라인 트레이스가 반복해서 결과 델리게이트 다시 호출 가능 + +* UE-23362 Gnm: submitDone () 이 X 초간 호출되지 않음 + +* UE-23415 USB 키보드가 shipping 빌드에서 작동되지 않음 + +* UE-23426 World.h 변경 및 WorldCollision.h 제거 필요 + +* UE-23662 HRTF 공간화 깨짐 + +* UE-23812 패키지 게임에서 하드웨어 설문 원격 측정 이벤트 전송하지 않도록. + +* UE-23688 모듈레이트 섀도우가 인코딩된 HDR 에 잘못 블렌딩 + +* UE-23762 에디터를 닫고 다시 열면 런타임 생성을 스태틱 리셋으로 설정 + +* UE-23048 UAIPerceptionStimuliSourceComponent 가 필요한 센스를 포함해서 등록되지 않음 + +* UE-22866 [4.10 P2] 에디터의 드롭다운 메뉴와 툴팁에 UI 가 중앙에서 벗어나 있음 + +* UE-23064 타겟 빌드 폴더가 리패키징 시 클리어 되지 않음 + +* UE-23132 매크로의 와일드카드 배열로 오류 메시지 표시 유발 + +* UE-23233 프로젝트를 새로운 엔진 버전으로 업그레이드하면 튜토리얼 블루프린트를 열려고 할 때 오류 유발 + +* UE-21717 Self Shadow Only 가 렌더링 부작용 유발 + +* UE-22949 리눅스에서 UE4Editor 열 수 없음 - 잘못된 hlslcc 헤더 찾음 + +* UE-23746 4.10 에서 에디터 전용 블루프린트 텍스트를 게임 현지화 텍스트로 수집 + +* UE-22157 거래가 성공적으로 끝났는데도 Android In App Purchase 에서 false 반환 가능 + +* UE-23190 Android/Google Play In-App Purchase Blueprint 노드를 두 번 발동시켜야지만 작동 + +* UE-23365 GitHub 1763 : Update README.md / VS2013 -> VS2015 + +* UE-23151 UE4 4.10 현지화 업데이트 필요 + +## 4.10.2 핫픽스 + +릴리즈 날짜: 2016/01/11 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.10.2-release](https://github.com/EpicGames/UnrealEngine/tree/4.10.2-release) + +픽스: + +* UE-23845 UMG 에서 애니메이션 키에 "Set Key Time" 사용 시의 크래시 + +* UE-24685 마티네 무비 레코딩이 4.10 에서 깨짐 + +* UE-22573 서로를 레퍼런싱하는 노드에서 REINST 오류 발생 + +* UE-24115 Xcode 에서 DebugGame Editor 구성으로 에디터 실행 불가 + +* UE-24563 에디터가 런처를 조용히 실행해야 + +## 4.10.3 핫픽스 + +릴리즈 날짜: 2016/02/17 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.10.3-release](https://github.com/EpicGames/UnrealEngine/tree/4.10.3-release) + +픽스: + +* OPP-4947 설치 오류 코드 R-1638 / 4.11 이 설치된 경우 런처를 통해 4.10.1 로 업그레이드 불가능 + +* UE-13030 서브 레벨 로드 관련 크래시 - UEngine::LoadMap() + +* UE-22075 노드가 같은 이름을 사용할 때 컴파일 시 크래시 - FPersistentFrameCollectorArchive::operator<<() + +* UE-22696 FBX2016 으로 익스포트한 특정 스켈레탈 FBX 임포트 시 크래시 + +* UE-22921 보더 아리 다수의 액터를 부모로 삼을 때 에디터 크래시 + +* UE-23373 일부 애니메이션을 열 때 크래시 - TSharedMapView::Find() + +* UE-23785 UE4Editor_Core!FSlowTask::GetCurrentMessage() 크래시 + +* UE-24169 PlayerInput.cpp - UPlayerInput::ProcessInputStack() 크래시 + +* UE-24443 애셋 이주 시 잠재적 크래시 - FGenericPlatformString::LogBogusChars() + +* UE-26315 UE4Editor_Engine!UActorComponent::BeginPlay() 크래시 + +* UE-26872 4.10 에서 현지화 수집 시 크래시 가능 + +* UE-23231 PC 에서 사이닝한 iOS 빌드 업로드 불가 + +* UE-24972 일부 템플릿의 경우 게임 시작 시 헤드 트래킹 고정 + +* UE-26158 bIsActorBeingDestroyed 를 코멘트로 잘못 빼냄 + +* UE-26657 스프라이트 임포트 시 퇴보가 4.9 에서 개선되었습니다. + +* UE-26903 단일 컬처 익스포트 시 현지화 대시보드가 내장된 이동을 익스포트하지 않음 + +## 4.10.4 핫픽스 + +릴리즈 날짜: 2016/02/22 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.10.4-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.10.4-release) + +픽스: + +* UE-27124 블루프린트를 통해 레벨 전환 시 에디터 크래시 diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_11/Updates/UnrealEngine4_11UpdateNotes.CHN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_11/Updates/UnrealEngine4_11UpdateNotes.CHN.udn new file mode 100644 index 000000000000..22866e047e7b --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_11/Updates/UnrealEngine4_11UpdateNotes.CHN.udn @@ -0,0 +1,154 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 虚幻引擎 4.11 更新日志 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/2016/4_11 +Order:0 + +## 4.11.0 Release + +Released: 03/31/2016 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.11.0-release](https://github.com/EpicGames/UnrealEngine/tree/4.11.0-release) + +Release Notes: [](Support/Builds/ReleaseNotes/2016/4_11) + +## 4.11.1 Hotfix + +Released: 04/07/2016 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.11.1-release](https://github.com/EpicGames/UnrealEngine/tree/4.11.1-release) + +Fixes: + +* UEBP-140 Oculus Integration 1.3 SDK, automation features, adapter support + +* UE-28961 UnrealLightMass fails to compile with VS2015 Update 2 + +* UE-29031 Unable to connect to SSL Perforce Server + +* UE-28933 GarbageCollection crash using IWCE + +* UE-28992 [CrashReport] Crash When Enabling Capsule Direct Shadows on a Skeletal Mesh + +* UE-29005 [CrashReport] UE4Editor_CoreUObject!FGCCollector::HandleObjectReferences() [garbagecollection.cpp:586] + +* UE-29012 Crash attempting to open blueprints with make nodes of missing structures made prior to 4.11 + +* UE-28954 PSVR Using Old Tracking Data + +* UE-29080 GearVR - project unexpectedly closes on launch + +* UE-29108 GearVR vrplatlib.jar staging logic is backward + +## 4.11.2 Hotfix + +Released: 04/18/2016 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.11.2-release](https://github.com/EpicGames/UnrealEngine/tree/4.11.2-release) + +Fixes: + +* UE-28811 Get mouse X/ Get mouse Y returns zero after the user clicks the screen and mouse is shown + +* UE-29148 Using "Show Mouse Cursor" breaks mouse axis movement + +* UE-28378 Mouse is not captured when switching between clients when running PIE + +* UE-29007 Construction script in parent blueprint cannot call function in child blueprint + +* UE-29207 UMG Widgets aren't cleaned up when a player is removed + +* UE-29208 Third Person C++ Template Doesn't use C++ Character + +* UE-29300 CDO Constructor Error when opening C++ Third Person project + +* UE-29136 Ensure starting PIE after editing character blueprint of a code based side scrollers + +* UE-29046 Crash on exit PIE after editing character blueprint of a code based side scrollers + +* UE-29209 Ensure 'Attaching instanced component to template component' in PIE in TP code project after reparenting character BP + +* UE-29100 Disable spawanbles in 4.11 because they can cause scene corruption and won't be compatible with 4.12 + +* UE-28791 Crash smoothing landscape with foliage + +* UE-28926 Editor crashes while sculpting landscape heavily covered in foliage + +* UE-28999 UE 4.11 Project Containing vegetation_pack causes Engine to Crash + +* UE-24725 Vehicle templates have jerky movement when turning due to SpringArmComponent + +* UE-28753 SpringArm causes physics to fail for a character standing on the physics object + +* UE-28991 Cannot manipulate morph targets unique to Slave Component through Master Component + +* UE-29003 Manipulating Morph Target on Master Component distorts Slave Components + +* UE-28789 Root motion has significant error when used in character movement + +* UE-25343 Crash in SetRootBodyIndex ( ParentIndex is 0 but SpaceBases.Num() == 0) + +* UE-29116 Animation CopyRecords need to calculate size at runtime + +* UE-29422 Crash in FollowKnots when compiling Anim Blueprint + +* UE-29326 [CrashReport] UE4Editor_Engine!FBlendedCurve::InitFrom() [animcurvetypes.cpp:590] + +* UE-28011 Media Player assets do not play in packaged games or in standalone + +* UE-29091 Sound Cues with Attenuation 'Override' Nodes break when Upgrading project to 4.11 + +* UE-29403 .wav files with max concurrency count data outside proper range will crash editor when played + +* UE-29548 Crash in VoiceModuleWindows.cpp + +* UE-29397 Sounds not Playing for 2nd Player Client when running in Local Multiplayer Splitscreen Mode + +* UE-27646 Editor Crashes When Using Set Replicates in the Construction Script + +* UE-25234 Bloom offset in right eye when rendering in stereoscopic + +* UE-29513 Custom lighting channels ignored when object culled in stereoscopic + +* UE-28609 R.ScreenPercentage and HMD SP commands do not work on Morpheus + +* UE-29505 Wrong colors on Nexus 6 Devices + +* UE-28805 HDR and Bloom not working on Mali Galaxy S7 (SM-G930F) + +* UE-29420 [Metal][iOS] Memory spike caused by FMetalSurface in 4.11 + +* UE-29421 [Metal][iOS] Crash in FMetalDynamicRHI::RHIReadSurfaceFloatData since 4.11 + +* UE-29006 [CrashReport] UE4Editor-MetalRHI.dylib!FMetalCommandEncoder::RestoreRenderCommandEncoding() + +* UE-29194 PS4 leaks memory in Shipping builds submission timestamp array + +* UE-29390 Html 5 Launch Fails on Windows + +* UE-29392 HTML5 broken load/save + +* UE-28874 New Third Party Plugin does not compile on Mac and Linux and prevents project from opening + +* UE-29158 4.11 regression: Stationary skylights no longer get bounce lighting after a lighting build + +* UE-29255 IndirectLightingIntensity on skylights is broken - can cause level lighting to unexpectedly change after getting the new build + +* UE-29297 Building Grass Map toast stays up forever + +* UE-29332 [CrashReport] Crash When Switching from Lit to Light Complexity Mode + +* UE-29322 [CrashReport] UE4Editor_CoreUObject!StaticFindObjectFastInternalThreadSafe() [uobjecthash.cpp:423] + +* UE-29407 Editor process quits during start up in debug with debugger attached + +## QFE for the 4.11.2 Hotfix + +If you are using the latest hotfix for this engine version and experience the issue described below, download and run this ‘quick fix’ to resolve the issue. + +* Fixes compile issue when attempting to use Visual Studio 2015 Update 3 + +[Windows Download](https://s3.amazonaws.com/unrealengine/qfe/QFE-FromCL-3044413.exe](https://s3.amazonaws.com/unrealengine/qfe/QFE-FromCL-3044413.exe) + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_11/Updates/UnrealEngine4_11UpdateNotes.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_11/Updates/UnrealEngine4_11UpdateNotes.JPN.udn index b40468dc33cb..0b43debf0ce8 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_11/Updates/UnrealEngine4_11UpdateNotes.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_11/Updates/UnrealEngine4_11UpdateNotes.JPN.udn @@ -1,6 +1,6 @@ INTSourceChangelist:0 Availability:Public -Title: Unreal Engine 4.11 Update Notes +Title: アンリアル エンジン 4.11 アップデート ノート Description: Crumbs: Parent:Support/Builds/ReleaseNotes/2016/4_11 diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_11/Updates/UnrealEngine4_11UpdateNotes.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_11/Updates/UnrealEngine4_11UpdateNotes.KOR.udn new file mode 100644 index 000000000000..70c9c9354b8b --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_11/Updates/UnrealEngine4_11UpdateNotes.KOR.udn @@ -0,0 +1,153 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 언리얼 엔진 4.11 업데이트 노트 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/2016/4_11 +Order:0 + +## 4.11.0 릴리즈 + +릴리즈 날짜: 2016/03/31 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.11.0-release](https://github.com/EpicGames/UnrealEngine/tree/4.11.0-release) + +릴리즈 노트: [](Support/Builds/ReleaseNotes/2016/4_11) + +## 4.11.1 핫픽스 + +릴리즈 날짜: 2016/04/07 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.11.1-release](https://github.com/EpicGames/UnrealEngine/tree/4.11.1-release) + +픽스: + +* UEBP-140 오큘러스 통합: 1.3 SDK, 자동화 기능, 어댑터 지원 + +* UE-28961 UnrealLightMass 가 VS2015 Update 2 에서 컴파일 실패 + +* UE-29031 SSL Perforce Server 접속 불가 + +* UE-28933 IWCE 사용 GarbageCollection 크래시 + +* UE-28992 [CrashReport] 스켈레탈 메시에 캡슐 다이렉트 섀도 켜면 크래시 + +* UE-29005 [CrashReport] UE4Editor_CoreUObject!FGCCollector::HandleObjectReferences() [garbagecollection.cpp:586] + +* UE-29012 4.11 이전에 만든 구조체가 없는 make 노드 포함 블루프린트를 열려고 할 때의 크래시 + +* UE-28954 PSVR 에서 오래된 트래킹 데이터 사용 + +* UE-29080 GearVR - 프로젝트 실행 시 예상치 못하게 닫힘 + +* UE-29108 GearVR vrplatlib.jar 스테이징 로직이 반대 + +## 4.11.2 핫픽스 + +릴리즈 날짜: 2016/04/18 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.11.2-release](https://github.com/EpicGames/UnrealEngine/tree/4.11.2-release) + +픽스: + +* UE-28811 사용자가 화면을 클릭하고 마우스가 표시된 이후 Get mouse X/ Get mouse Y 가 0 반환 + +* UE-29148 "Show Mouse Cursor" 사용 시 마우스 축 이동 깨짐 + +* UE-28378 PIE 실행 중 클라이언트 전환 시 마우스 캡처 안됨 + +* UE-29007 부모 블루프린트의 컨스트럭션 스크립트가 자손 블루프린트의 함수 호출 불가 + +* UE-29207 플레이어 제거 시 위젯 클린 업이 되지 않음 + +* UE-29208 삼인칭 C++ 템플릿이 C++ 캐릭터를 사용하지 않음 + +* UE-29300 C++ 삼인칭 프로젝트 열 때 CDO 생성자 오류 + +* UE-29136 코드 기반 횡스크롤의 캐릭터 블루프린트 편집 후 PIE 시작 시 ensure 발생 + +* UE-29046 코드 기반 횡스크롤의 캐릭터 블루프린트 편집 후 PIE 종료 시 크래시 + +* UE-29209 삼인칭 코드 프로젝트에서 캐릭터 블푸 부모 변경 후 PIE 에서 'Attaching instanced component to template component' ensure 발생 + +* UE-29100 4.11 에서 스포너블 비활성화. 씬이 깨지게 만들 수가 있으며, 4.12 와 호환되지 않음. + +* UE-28791 폴리지 포함 랜드스케이프 스무딩 시 크래시 + +* UE-28926 폴리지를 많이 칠한 랜드스케이프 조각 도중 에디터 크래시 + +* UE-28999 UE 4.11 프로젝트에 vegetation_pack 포함된 것이 엔진 크래시 유발 + +* UE-24725 비히클 템플릿에서 회전 시 SpringArmComponent 때문에 덜컥거림 + +* UE-28753 SpringArm 때문에 피직스 오브젝트에 서있는 캐릭터의 피직스 실패 유발 + +* UE-28991 마스터 컴포넌트를 통해 슬레이브 컴포넌트에 고유한 모프 타겟 조작 불가 + +* UE-29003 마스터 컴포넌트의 모프 타겟 조작 시 슬레이브 컴포넌트 왜곡 + +* UE-28789 캐릭터 무브먼트에서 사용 시 루트 모션에 심각한 오류 + +* UE-25343 SetRootBodyIndex 의 크래시 ( ParentIndex 는 0 이나 SpaceBases.Num() == 0) + +* UE-29116 CopyRecords 애니메이션이 실행시간에 크기 계산 필요 + +* UE-29422 애님 블루프린트 컴파일 시 FollowKnots 크래시 + +* UE-29326 [CrashReport] UE4Editor_Engine!FBlendedCurve::InitFrom() [animcurvetypes.cpp:590] + +* UE-28011 미디어 플레이어 애셋이 패키지 게임 또는 독립형에서 플레이되지 않음 + +* UE-29091 Attenuation 'Override' 노드가 있는 사운드 큐가 4.11 로 프로젝트 업그레이드시 깨짐 + +* UE-29403 최대 동시재생 수 데이터가 적정 범위를 벗어난 .wav 파일 재생 시 에디터 크래시 + +* UE-29548 VoiceModuleWindows.cpp 크래시 + +* UE-29397 로컬 멀티플레이어 분할화면 모드에서 실행할 때 두 번째 플레이어 클라이언트에 사운드가 재생되지 않음 + +* UE-27646 컨스트럭션 스크립트에서 Set Replicates 사용 시 에디터 크래시 + +* UE-25234 스테레오 렌더링 시 오른쪽 눈의 블룸 오프셋 + +* UE-29513 스테레오에서 오브젝트 컬링 시 커스텀 라이팅 채널 무시 + +* UE-28609 R.ScreenPercentage 및 HMD SP 명령이 Morpheus 에서 작동 않음 + +* UE-29505 Nexus 6 디바이스에서 컬러 틀림 + +* UE-28805 HDR 및 Bloom 이 Mali Galaxy S7 (SM-G930F) 에서 작동 않음 + +* UE-29420 [Metal][iOS] 4.11 에서 FMetalSurface 로 인해 메모리 스파이크 + +* UE-29421 [Metal][iOS] 4.11 이후 FMetalDynamicRHI::RHIReadSurfaceFloatData 에 크래시 + +* UE-29006 [CrashReport] UE4Editor-MetalRHI.dylib!FMetalCommandEncoder::RestoreRenderCommandEncoding() + +* UE-29194 Shipping 빌드 서미션 타임스탬프 배열에 PS4 메모리 누수 + +* UE-29390 윈도우에서 Html 5 실행 실패 + +* UE-29392 HTML5 에서 로드/저장 깨짐 + +* UE-28874 새로운 써드 파티 플러그인이 맥과 리눅스에서 컴파일되지 않아 프로젝트가 열리지 않음 + +* UE-29158 4.11 퇴보: 스테이셔너리 스카이라이트가 더이상 라이팅 빌드 이후 반사광을 받지 않음 + +* UE-29255 스카이라이트의 IndirectLightingIntensity 깨짐 - 새 빌드 구한 후 레벨 라이팅이 예상치 못하게 변할 수 있음 + +* UE-29297 그래스 맵 토스트 빌드 시 영원히 남아있음 + +* UE-29332 [CrashReport] 라이팅포함 에서 라이트 복잡도 모드로 전환 시 크래시 + +* UE-29322 [CrashReport] UE4Editor_CoreUObject!StaticFindObjectFastInternalThreadSafe() [uobjecthash.cpp:423] + +* UE-29407 디버거 포함 디버그 모드 시작 도중 에디터 프로세스 종료 + +## 4.11.2 용 QFE 핫픽스 + +이 엔진 버전의 최신 핫픽스를 사용하다가 아래 문제를 겪으시는 경우, 이 'quick fix' 를 다운로드하여 실행시키면 해결 가능합니다. + +* Visual Studio 2015 Update 3 사용 시도 시 컴파일 문제를 해결합니다. + +[윈도우 다운로드](https://s3.amazonaws.com/unrealengine/qfe/QFE-FromCL-3044413.exe](https://s3.amazonaws.com/unrealengine/qfe/QFE-FromCL-3044413.exe) diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_12/Updates/UnrealEngine4_12UpdateNotes.CHN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_12/Updates/UnrealEngine4_12UpdateNotes.CHN.udn new file mode 100644 index 000000000000..6ec32bfc9b70 --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_12/Updates/UnrealEngine4_12UpdateNotes.CHN.udn @@ -0,0 +1,216 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 虚幻引擎 4.12 更新日志 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/2016/4_12 +Order:0 + +## 4.12.0 Release + +Released: 06/01/2016 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.12.0-release](https://github.com/EpicGames/UnrealEngine/tree/4.12.0-release) + +Release Notes: [](Support/Builds/ReleaseNotes/2016/4_12) + +## 4.12.1 Hotfix + +Released: 06/07/2016 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.12.1-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.12.1-release) + +Fixes: + +* UE-31570 Crash in StaticDuplicateObject while compiling or editing variables in blueprint widgets + +* UE-31550 Using Integer Bitmask crashes editor + +* UE-23371 [CrashReport]UE4Editor_GraphEditor!FNodeFactory::CreateNodeWidget() nodefactory.cpp:91 + +* UE-26761 Crash When Compiling Child Blueprint Containing a Custom Event with the Same Name as its Parent's Event + +* UE-31443 Crash occurs clicking "Select All" in Foliage Tool in QA-Sequencer map + +* UE-31183 [CrashReport] UE4Editor_Engine!FAnimNode_StateMachine::Evaluate() [animnode_statemachine.cpp:745] + +* UE-31574 RemoveNaNTracks causes anim DDC data to be regenerated every load on old animations + +* UE-31445 [CrashReport] UE4Editor_DetailCustomizations!FBodyInstanceCustomization::GetDefaultCollisionProvider() [bodyinstancecustomization.cpp:35] + +* UE-31255 Shipping Builds packaged for WinXP 32 bit crash when opening on Win7 + +* UE-31492 Can no longer generate a dsym on Mac + +* UE-25561 Read IAP information node causes hang if connection is disconnected + +* UE-31539 GPU crash on PS4 due to GS mode not getting disabled when using parallel contexts + +* UE-31247 Emissive for Static Lighting discarded upon Re-opening Level or Restarting Project + +* UE-28817 [CrashReport] UE4Editor_Engine!FStaticLODModel::Serialize() [skeletalmesh.cpp:1261] + +* UE-15903 [CrashReport] Lighting build triggers array out of bounds crash + +* UE-31620 Roughness Calculation is incorrect in 4.12 + +* UE-26288 Crash on unchecking Generate Lightmap UVs and Applying with Mesh already assigned and painted as Foliage + +* UE-31182 [CrashReport] UE4Editor_Engine!FMaterial::GetShader() [materialshared.cpp:1564] + +* UE-18906 [CrashReport] Crash in !UE4Editor_D3D11RHI!FD3D11DynamicRHI::Shutdown() + +* UE-30985 Reflective surfaces rendering incorrectly in -featureleveles2 -opengl + +* UE-31431 Crash in Sequencer play rate track when setting negative play rate + +* UE-31647 Crash changing the color of a fade track section + +* UE-31648 Sequencer audio doesn't play after rendering a movie in editor. + +## 4.12.2 Hotfix + +Released: 06/09/2016 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.12.2-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.12.2-release) + +Fixes: + +* UE-31740 Crash While Compiling Blueprint in FBlueprintEditorUtils::RefreshExternalBlueprintDependencyNodes() + +* UE-31655 BP EQS generators crash on adding vectors. + +* UE-31723 Attempting to build MinidumpDiagnostics with Visual Studio 2015 Update 2 results in failure + +* UE-31612 Physics enabled Child Actor components that spawn with with a delay, always spawns at world origin + +* UE-31680 [CrashReport] DestroyChildActor->Rename->StaticFindObject() + +* UE-31682 [CrashReport] UE4Editor_CoreUObject!UObjectBaseUtility::GetOutermost() [uobjectbaseutility.cpp:118] + +* UE-31736 SteamController BackRight is not setup correctly + +* UE-29543 Adjusting Light Source Radius/Length creates undesirable effect + +* UE-31589 Capture reflections on translucent materials are broken + +* UE-31715 Static Meshes Disappear with Media Player Asset Applied as Material in Standalone or Packaged Game + +* UE-31687 Vive: Positional Latency with a Possessed Pawn's Camera Component + +## 4.12.3 Hotfix + +Released: 06/16/2016 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.12.3-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.12.3-release) + +Fixes: + +* UE-31735 Get Class Defaults node disconnects output pins when project upgraded from 4.11 to 4.12 + +* UE-31743 Components derived from scene component reset vector location upon closing and re-opening editor + +* UE-31812 CrashReporter Client has no options to close without sending + +* UE-31789 GitHub 2484 : Git Plugin: fix the Submit To Source Control menu broken by new "migrate" support in 4.12 (and master) + +* UE-31702 Assertion opening blueprint with HISMC created in 4.11 + +* UE-30934 GitHub 2406 : Git plugin: Fix for Git diff not working in UE 4.12 (and master) + +* UE-31265 GitHub 2432 : BUGFIX: ProceduralMeshComponent crashes game + +* UE-31578 [CrashReport] UE4Editor_Renderer!InjectTranslucentLightArray() [translucentlighting.cpp:1578] + +* UE-31851 Reflections have an extra vector offset than in 4.11 + +* UE-31787 Vive: Positional Latency w/ Rotation + +## 4.12.4 Hotfix + +Released: 06/28/2016 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.12.4-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.12.4-release) + +Fixes: + +* UE-32179 Properties of blueprint based behavior tree decorators are reset on game start + +* UE-32178 Vehicles set to "obstacle only" in RVO are moving on their own + +* UE-32356 Editor crashes when opening several marketplace assets - Assertion failed: !HasAnyFlags + +* UE-32414 Using TickInterval for a tick used as a prerequisite will crash + +* UE-31897 PhysicsVolume weak pointer returns null only in packaged project + +* UE-31938 Crash report window does not open on GitHub source builds + +* UE-29086 Crash When Typing a Node Comment and Hovering Over the Alignment Option + +* UE-30963 UCS continuously runs while a blueprint's thumbnail in content browser is focused + +* UE-32381 Crash updating thumbnail after compiling blueprint + +* UE-32283 Animations imported with Skeletal Mesh are not marked as dirty and don't get saved + +* UE-30878 [CrashReport] UE4Editor_Foliage!FFoliageInstanceBaseCache::AddInstanceBaseId() [foliageinstancebase.cpp:101] + +* UE-31956 Instance changes no longer propagating to ChildActor after updating from 4.11.2 + +* UE-32219 [CrashReporter] Crash in UEngine::UpdateTimeAndHandleMaxTickRate() + +* UE-32276 AActor::OnRep_AttachmentReplication regression on detach + +* UE-32124 Crash when Deleting Concatenator Node while Playing Sound Cue + +* UE-28604 [CrashReport] UE4Editor_Engine!FSharedPoolPolicyData::GetPoolBucketIndex() [gpuskinvertexfactory.cpp:75] + +* UE-31445 [CrashReport] UE4Editor_DetailCustomizations!FBodyInstanceCustomization::GetDefaultCollisionProvider() [bodyinstancecustomization.cpp:35] + +* UE-32244 Grabbing a Destructible Mesh Child blueprint with a Phsyics Handle crashes the editor + +* UE-31766 [CrashReport] UE4Editor_Engine!AActor::InvalidateLightingCacheDetailed() [actor.cpp:4111] + +* UE-32060 Editing Landscape Collision Mip Level Crashes Editor + +* UE-32132 Safe zone visualization and debugging is broken on Windows + +* UE-31441 A3D doesn't work on PS4 + +* UE-31450 [CrashReport] UE4Editor_UnrealEd!FLightmassExporter::WriteSceneSettings() [lightmass.cpp:1818] + +* UE-31765 [CrashReport] UE4Editor_Renderer!FMeshMaterialShader::SetMesh() [shaderbaseclasses.cpp:457] + +* UE-31454 Using VR Preview and Shader Complexity viewmode will cause a crash + +* UE-29332 [CrashReport] Crash When Switching from Lit to Light Complexity Mode + +* UE-32036 GitHub 2504 : [Editor Hang new in 4.12 fix in FinalPostProcessSettings] Essential project-killing hang fix ? Rama + +* UE-32415 Editing Landscape Collision Mip Level Crashes Editor + +* UE-29146 CameraVectorWS Input Data as Post Process Blendable not Rendering Correctly + +* UE-31549 r.ScreenPercentage.Editor does not function + +* UE-32507 Third party plugin authors cannot stage PRX files on PS4 + +* UE-31914 Remove embedded vertex buffers from GoogleVRHMDViewerPreviews.cpp that are killing compile times and binary sizes + +## 4.12.5 Hotfix + +Released: 07/07/2016 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.12.5-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.12.5-release) + +Fixes: + +* UE-32588 VS2015 Update 3 prevents the editor from compiling code + +* UE-32621 [CrashReport] UE4Editor_Renderer!FGlobalShader::SetParameters() [globalshader.h:134] + +* UE-32715 Crash when selecting "show" > "uncompressed animation" in Persona + +* UE-32772 Hitting ensure in AACtor::BeginPlay in an actor with ChildActorComponents + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_12/Updates/UnrealEngine4_12UpdateNotes.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_12/Updates/UnrealEngine4_12UpdateNotes.JPN.udn index 3f109ac59ed9..95b76155fab0 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_12/Updates/UnrealEngine4_12UpdateNotes.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_12/Updates/UnrealEngine4_12UpdateNotes.JPN.udn @@ -1,6 +1,6 @@ INTSourceChangelist:0 Availability:Public -Title: Unreal Engine 4.12 Update Notes +Title: アンリアル エンジン 4.12 アップデート ノート Description: Crumbs: Parent:Support/Builds/ReleaseNotes/2016/4_12 diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_12/Updates/UnrealEngine4_12UpdateNotes.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_12/Updates/UnrealEngine4_12UpdateNotes.KOR.udn new file mode 100644 index 000000000000..1631504c0084 --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_12/Updates/UnrealEngine4_12UpdateNotes.KOR.udn @@ -0,0 +1,215 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 언리얼 엔진 4.12 업데이트 노트 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/2016/4_12 +Order:0 + +## 4.12.0 릴리즈 + +릴리즈 날짜: 2016/06/01 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.12.0-release](https://github.com/EpicGames/UnrealEngine/tree/4.12.0-release) + +릴리즈 노트: [](Support/Builds/ReleaseNotes/2016/4_12) + +## 4.12.1 핫픽스 + +릴리즈 날짜: 2016/06/07 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.12.1-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.12.1-release) + +픽스: + +* UE-31570 블루프린트 위젯 컴파일 또는 변수 편집 도중의 StaticDuplicateObject 크래시를 고쳤습니다. + +* UE-31550 인티저 비트마스크 사용 시 에디터 크래시를 고쳤습니다. + +* UE-23371 [CrashReport]UE4Editor_GraphEditor!FNodeFactory::CreateNodeWidget() nodefactory.cpp:91 + +* UE-26761 부모 이벤트와 같은 이름의 커스텀 이벤트가 있는 자손 블루프린트 컴파일 시 크래시를 고쳤습니다. + +* UE-31443 QA-Sequencer 맵에서 폴리지 툴로 "모두 선택" 클릭 시 크래시를 고쳤습니다. + +* UE-31183 [CrashReport] UE4Editor_Engine!FAnimNode_StateMachine::Evaluate() [animnode_statemachine.cpp:745] + +* UE-31574 RemoveNaNTracks 가 오래된 애니메이션을 로드할 때마다 애님 DDC 데이터를 재생성하게 만들던 것을 고쳤습니다. + +* UE-31445 [CrashReport] UE4Editor_DetailCustomizations!FBodyInstanceCustomization::GetDefaultCollisionProvider() [bodyinstancecustomization.cpp:35] + +* UE-31255 Win7 에서 WinXP 32 용으로 패키징된 Shipping 빌드를 열 때의 크래시를 고쳤습니다. + +* UE-31492 Mac 에서 더이상 dsym 생성이 불가능하던 것을 고쳤습니다. + +* UE-25561 접속이 끊겼을 때 Read IAP information 노드가 멈추던 것을 고쳤습니다. + +* UE-31539 패럴렐 컨텍스트 사용 시 GS 모드가 꺼지지 않아서 발생하는 PS4 크래시를 고쳤습니다. + +* UE-31247 레벨을 다시 열 때나 프로젝트 재시작 시 스태틱 라이팅의 이미시브가 버려지던 것을 고쳤습니다. + +* UE-28817 [CrashReport] UE4Editor_Engine!FStaticLODModel::Serialize() [skeletalmesh.cpp:1261] + +* UE-15903 [CrashReport] Lighting build triggers array out of bounds crash + +* UE-31620 4.12 에서 러프니스 계산이 잘못되던 것을 고쳤습니다. + +* UE-26288 Generate Lightmap UVs 체크를 해제하고 Applying with Mesh 를 이미 할당한 상태에서 폴리지로 페인트할 때의 크래시를 고쳤습니다. + +* UE-31182 [CrashReport] UE4Editor_Engine!FMaterial::GetShader() [materialshared.cpp:1564] + +* UE-18906 [CrashReport] Crash in !UE4Editor_D3D11RHI!FD3D11DynamicRHI::Shutdown() + +* UE-30985 -featureleveles2 -opengl 상태에서 반사 표면이 잘못 렌더링되던 것을 고쳤습니다. + +* UE-31431 시퀀서 플레이 레이트 트랙에서 음수 설정 시 크래시를 고쳤습니다. + +* UE-31647 페이드 트랙 섹션 컬러 변경 시의 크래시를 고쳤습니다. + +* UE-31648 시퀀서 오디오가 에디터에서 무비 렌더링 이후 재생되지 않는 것을 고쳤습니다. + +## 4.12.2 핫픽스 + +릴리즈 날짜: 2016/06/09 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.12.2-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.12.2-release) + +픽스: + +* UE-31740 FBlueprintEditorUtils::RefreshExternalBlueprintDependencyNodes() 에서 블루프린트 컴파일 도중의 크래시를 고쳤습니다. + +* UE-31655 BP EQS 생성기에서 벡터 추가 시의 크래시를 고쳤습니다. + +* UE-31723 Visual Studio 2015 Update 2 로 MinidumpDiagnostics 빌드 시도 시 실패하던 것을 고쳤습니다. + +* UE-31612 딜레이를 가지고 피직스가 켜진 자손 액터 컴포넌트를 스폰하면 항상 월드 원점에 스폰되던 것을 고쳤습니다. + +* UE-31680 [CrashReport] DestroyChildActor->Rename->StaticFindObject() + +* UE-31682 [CrashReport] UE4Editor_CoreUObject!UObjectBaseUtility::GetOutermost() [uobjectbaseutility.cpp:118] + +* UE-31736 SteamController BackRight 가 제대로 셋업되지 않는 것을 고쳤습니다. + +* UE-29543 Light Source Radius/Length 변경 시 바람직하지 않은 이펙트가 나오던 것을 고쳤습니다. + +* UE-31589 반투명 머티리얼에 리플렉션 캡처가 깨지던 것을 고쳤습니다. + +* UE-31715 스탠드얼론 또는 패키지 게임에서 머티리얼로 적용된 미디어 플레이어 애셋이 있는 스태틱 메시가 사라지던 것을 고쳤습니다. + +* UE-31687 Vive: 빙의된 폰의 Camera Component 관련 위치 + +## 4.12.3 핫픽스 + +릴리즈 날짜: 2016/06/16 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.12.3-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.12.3-release) + +픽스: + +* UE-31735 프로젝트를 4.11 에서 4.12 로 업그레이드할 때 Get Class Defaults 노드가 출력핀 연결이 끊어지던 것을 고쳤습니다. + +* UE-31743 씬 컴포넌트에서 파생된 컴포넌트가 에디터를 닫았다 다시 열면 벡터 위치가 리셋되던 것을 고쳤습니다. + +* UE-31812 CrashReporter 클라이언트에 전송 없이 닫는 옵션이 없던 것을 고쳤습니다. + +* UE-31789 GitHub 2484 : Git Plugin: 4.12 (및 마스터)에 새로 지원된 "migrate" (이주) 기능때문에 깨진 Submit To Source Control 메뉴를 고쳤습니다. + +* UE-31702 4.11 에서 만든 HISMC 포함 블루프린트를 열 때의 어서트를 고쳤습니다. + +* UE-30934 GitHub 2406 : Git plugin: UE 4.12 (및 마스터)에서 Git diff 가 작동하지 않던 것을 고쳤습니다. + +* UE-31265 GitHub 2432 : BUGFIX: ProceduralMeshComponent 로 게임 크래시가 나던 것을 고쳤습니다. + +* UE-31578 [CrashReport] UE4Editor_Renderer!InjectTranslucentLightArray() [translucentlighting.cpp:1578] + +* UE-31851 리플렉션이 4.11 보다 많읂 벡터 오프셋이 많이 붙던 것을 고쳤습니다. + +* UE-31787 Vive: 회전 포함 위치 레이턴시 + +## 4.12.4 핫픽스 + +릴리즈 날짜: 2016/06/28 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.12.4-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.12.4-release) + +픽스: + +* UE-32179 블루프린트 기반 비헤이비어 트리 데코레이터의 프로퍼티가 게임 시작 시 리셋되던 것을 고쳤습니다. + +* UE-32178 RVO 에서 "obstacle only" 로 설정된 비히클히 스스로 움직이던 것을 고쳤습니다. + +* UE-32356 다수의 마켓플레이스 애셋을 열 때의 크래시를 고쳤습니다: 어서트 실패: !HasAnyFlags + +* UE-32414 틱의 TickInterval 을 사전 요구사항으로 사용할 때의 크래시를 고쳤습니다. + +* UE-31897 PhysicsVolume 약 포인터가 패키지 게임에서 항상 null 만 반환하던 것을 고쳤습니다. + +* UE-31938 GitHub 소스 빌드에서 크래시 리포트 창이 열리지 않던 것을 고쳤습니다. + +* UE-29086 노드 코멘트를 입력하고 Alignment 옵션에 커서를 올릴 때 발생하는 크래시를 고쳤습니다. + +* UE-30963 콘텐츠 브라우저에서 블루프린트의 썸네일에 포커스가 잡힌 상태에서 UCS 가 계속 실행되던 것을 고쳤습니다. + +* UE-32381 블루프린트 컴파일 후 썸네일 업데이트 시의 크래시를 고쳤습니다. + +* UE-32283 스켈레탈 메시와 함께 임포트한 애니메이션이 더티 마킹되지 않아 저장되지 않던 것을 고쳤습니다. + +* UE-30878 [CrashReport] UE4Editor_Foliage!FFoliageInstanceBaseCache::AddInstanceBaseId() [foliageinstancebase.cpp:101] + +* UE-31956 인스턴스 변화가 4.11.2 업데이트 이후 자손 액터에 전파되지 않던 것을 고쳤습니다. + +* UE-32219 [CrashReporter] Crash in UEngine::UpdateTimeAndHandleMaxTickRate() + +* UE-32276 디태치 시의 AActor::OnRep_AttachmentReplication 퇴보를 고쳤습니다. + +* UE-32124 사운드 큐 재생 도중 Concatenator 노드를 삭제할 때의 크래시를 고쳤습니다. + +* UE-28604 [CrashReport] UE4Editor_Engine!FSharedPoolPolicyData::GetPoolBucketIndex() [gpuskinvertexfactory.cpp:75] + +* UE-31445 [CrashReport] UE4Editor_DetailCustomizations!FBodyInstanceCustomization::GetDefaultCollisionProvider() [bodyinstancecustomization.cpp:35] + +* UE-32244 Phsyics Handle 이 있는 디스트럭터블 메시 자손 블루프린트를 잡을 때의 에디터 크래시를 고쳤습니다. + +* UE-31766 [CrashReport] UE4Editor_Engine!AActor::InvalidateLightingCacheDetailed() [actor.cpp:4111] + +* UE-32060 랜드스케이프 콜리전 밉 레벨 편집 시의 에디터 크래시를 고쳤습니다. + +* UE-32132 세이프 존 시각화 및 디버깅이 윈도우에서 깨지던 것을 고쳤습니다. + +* UE-31441 A3D 가 PS4 에서 작동하지 않던 것을 고쳤습니다. + +* UE-31450 [CrashReport] UE4Editor_UnrealEd!FLightmassExporter::WriteSceneSettings() [lightmass.cpp:1818] + +* UE-31765 [CrashReport] UE4Editor_Renderer!FMeshMaterialShader::SetMesh() [shaderbaseclasses.cpp:457] + +* UE-31454 VR 프리뷰 및 셰이더 복잡도 뷰모드를 사용하면 크래시가 나던 것을 고쳤습니다. + +* UE-29332 [CrashReport] 라이팅포함에서 라이트 복잡도 모드로 전환 시의 크래시를 고쳤습니다. + +* UE-32036 GitHub 2504 : [Editor Hang new in 4.12 fix in FinalPostProcessSettings] Essential 프로젝트가 죽는 행잉 픽스 ? Rama + +* UE-32415 랜드스케이프 콜리전 밉 레벨 편집 시 에디터 크래시를 고쳤습니다. + +* UE-29146 CameraVectorWS Input Data 가 Post Process Blendable 로 된 경우 제대로 렌더링되지 않던 것을 고쳤습니다. + +* UE-31549 r.ScreenPercentage.Editor 가 작동하지 않던 것을 고쳤습니다. + +* UE-32507 써드 파티 플러그인 제작자가 PS4 에 PRX 파일을 스테이지에 올릴 수 없던 것을 고쳤습니다. + +* UE-31914 GoogleVRHMDViewerPreviews.cpp 에서 임베드된 버텍스 버퍼가 컴파일 시간과 바이너리 크기를 죽이던 것을 제거했습니다. + +## 4.12.5 핫픽스 + +릴리즈 날짜: 2016/07/07 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.12.5-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.12.5-release) + +픽스: + +* UE-32588 VS2015 업데이트 3 로 에디터 코드 컴파일이 안되던 것을 고쳤습니다. + +* UE-32621 [CrashReport] UE4Editor_Renderer!FGlobalShader::SetParameters() [globalshader.h:134] + +* UE-32715 페르소나에서 표시 > 미압축 애니메이션 선택 시의 크래시를 고쳤습니다. + +* UE-32772 ChildActorComponents 가 있는 액터에서 AACtor::BeginPlay 에서 ensure 가 발생하던 것을 고쳤습니다. diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_13/Updates/UnrealEngine4_13UpdateNotes.CHN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_13/Updates/UnrealEngine4_13UpdateNotes.CHN.udn new file mode 100644 index 000000000000..a552bd588dfe --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_13/Updates/UnrealEngine4_13UpdateNotes.CHN.udn @@ -0,0 +1,184 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 虚幻引擎 4.13 更新日志 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/2016/4_13 +Order:0 + +## 4.13.0 Release + +Released: 09/01/2016 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.13.0-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.13.0-release) + +Release Notes: [](Support/Builds/ReleaseNotes/2016/4_13) + +## 4.13.1 Hotfix + +Released: 09/29/2016 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.13.1-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.13.1-release) + +Fixes: + +* UE-35735 Crash Occurs While Running EQS Using Add Generated Vector Node + +* UE-35852 AI Move To Location zeros velocity each call, causing the AI Pawn to freeze if told to move again before reaching destination + +* UE-35585 Migration from 4.12.5 to 4.13 can result in Blueprint functions losing input/ouput variables + +* UE-35609 Delay nodes used in a macro cause subsequent macro calls during the delay to never complete + +* UE-35728 Some files in the Git repo have inconsistent line endings on Linux + +* UE-36107 Cannot create installed build on Linux + +* UE-35236 Launcher installed build is missing the Documentation/Extras folder + +* UE-36214 Crash in TMap struct deserializer + +* UE-35884 Crash when pressing enter after a shape has closed when using the Geometry editor + +* UE-35822 CRASH: Occurring in UTEditor when attempting to re-order BSP brushes + +* UE-35048 [CrashReport] UE4Editor_PropertyEditor!FDetailCategoryImpl::GetParentLayoutImpl() [detailcategorybuilderimpl.h:168] + +* UE-35482 Selecting a brush surface that is flush with other brush surfaces selects all of them after Building Geometry + +* UE-35627 Lightmap Coordinate Index is not automatically set to 1 on import any longer with lightmap UV + +* UE-35608 FBX & OBJ Files no longer Import with their UVs Depending on Software Used + +* UE-36383 Crash moving a spline point after making it the root component of a blueprint + +* UE-35658 Editor crash when a spline component is added to a blueprint and compiled + +* UE-36096 Inifinite loop in tick task manager with tick when paused and interval + +* UE-35254 Editor crashes when importing alembic asset + +* UE-36121 Crash when importing new mesh and regenerating skeleton for additive animation + +* UE-35546 Pose flickering when changing lods and using Layered Blend per Bone + +* UE-35353 Crash when spawning destructible objects in 2 player PIE + +* UE-35639 HLOD generated proxy doesn't create or assign target lightmap coordinate index any longer + +* UE-35494 Invisible landscape components when using tessellation + +* UE-35873 LODBias causes landscape component to stop rendering if set >0 and Forced LOD set to -1 + +* UE-35301 Crash saving hidden landscape streaming level with offset + +* UE-35850 Crash in landscape editor with early Z pass + +* UE-35709 [CrashReport] UE4Editor_Landscape!FLandscapeEditDataInterface::SetAlphaData() [landscapeeditinterface.cpp:2617] + +* UE-36321 Editor Crashes After Deleting Actor with Media Texture + +* UE-36289 WmfMedia: Memory leak while playing videos + +* UE-35477 File Media Source assets created via drag & drop have absolute instead of relative path + +* UE-35504 PS4 Media player has potentially dangerous memory management + +* UE-35696 PS4Media: CPU/GPU may crash due to race condition in destructor + +* UE-35598 Devices reporting OpenGL ES 3.2 such as Galaxy Note 7 detect as ES2-only + +* UE-35179 Need to fall back to GLES if Vulkan API version is too old + +* UE-34782 GPU particles no longer work on iOS or TVOS Metal devices + +* UE-33379 Cannot select Android RHI and feature level from device profile + +* UE-35258 ES2 Fallback Fails on Nougat Devices that do not support Vulkan + +* UE-35261 Android sessions do not appear in Session Frontend + +* UE-32340 HTML5 packaging fails with Github couldn't verify LLVM version + +* UE-32086 Bloom blur produces multi-colored artifacts at the bottom of the screen on Xbox. + +* UE-35492 PS4 deployment does not deploy all the required files. + +* UE-35743 Packaging for Android while using Online Framework and Online Subsystem Steam Plugins cause failure + +* UE-35185 Opening a widget blueprint on Linux causes editor to crash + +* UE-35738 IPv6 implementation is not working on IOS + +* UE-30959 Remove all HITCHHUNTER warnings in next release (4.13) + +* UE-36342 Texture issues with movie player active on Android + +* UE-35363 Huge game window when launching onto Safari 9.1.2 + +* UE-35558 Writing to a file on Android doesn't update the tracked file length + +* UE-35907 Slate Remote Enable Remove Server option in Project Settings -> Plugins causes editor to freeze and a memory leak + +* UE-36099 Dots on screen on PS4 + +* UE-35794 PS4 can hang on GPU when using lit translucent surface materials + +* UE-26375 Crash when editing draw size for a widget component + +* UE-17227 [CrashReport] UE4Editor_Engine!DoReadTaskResults() [shadercompiler.cpp:147] + +* UE-35240 Protostar crashes on launch on Mac + +* UE-28708 GitHub 2188 : Fixed a crash exiting VR Preview on Windows GL4. + +* UE-35320 Stop>Set Sequence>Play causes spawnables to be duplicated + +* UE-35508 Master sequence dialog button is hidden + +* UE-35588 Incorrect translation from matinee move sub tracks to sequencer + +* UE-35285 Sequencer stop node does not return camera to player + +* UE-35571 Sequence recording in standalone crashes + +* UE-35107 Matinee to Level Sequence converter doesn't bind properties + +* UE-22581 Black artifacts/semi-circles on sides of morpheus when moving left to right + +* UE-36076 PS4Tracker's motion sensor data needs to use a valid sizeOfThis + +* UE-35520 sceKernelWaitEqueue timeout in MorpheusHMD.cpp fix for 4.13.1 + +* UE-34986 Need to merge Oculus Online Subsystem Plugin update to expose Android support + +* UE-34786 Editor primitives render incorrectly in stereoscopic with instanced stereo + +* UE-35881 PSVR hmdSetupDialog cancel asserts on app startup + +* UE-36307 PSVR Motion Sensors Need 120hz Update + +* UE-33763 GearVR applications show black screen on Adreno devices + +* UE-36078 Integrate fixes for GoogleVR SDK 1.0 + +* UE-35528 PSVR UE4 stuttering issue + +* UE-35344 Crash when playing a HapticFeedbackEffect_Soundwave + +* UE-35964 Crash playing a HapticFeedbackEffect_Soundwave with no sound assigned + +## 4.13.2 Hotfix + +Released: 10/26/2016 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.13.2-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.13.2-release) + +Fixes: + +* UE-37704 Crash opening packaged project on iOS + +* UE-37249 MallocPoisonProxy can result in a memory stomp for aligned allocations in Debug and Development + +* UE-36573 Need to update to libpng for Android; current one triggers security alert on Google Play + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_13/Updates/UnrealEngine4_13UpdateNotes.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_13/Updates/UnrealEngine4_13UpdateNotes.JPN.udn index 7a0ef9a4ac00..7074d9fdf752 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_13/Updates/UnrealEngine4_13UpdateNotes.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_13/Updates/UnrealEngine4_13UpdateNotes.JPN.udn @@ -1,6 +1,6 @@ INTSourceChangelist:0 Availability:Public -Title: Unreal Engine 4.13 Update Notes +Title: アンリアル エンジン 4.13 アップデート ノート Description: Crumbs: Parent:Support/Builds/ReleaseNotes/2016/4_13 diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_13/Updates/UnrealEngine4_13UpdateNotes.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_13/Updates/UnrealEngine4_13UpdateNotes.KOR.udn new file mode 100644 index 000000000000..9337b250dc40 --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_13/Updates/UnrealEngine4_13UpdateNotes.KOR.udn @@ -0,0 +1,183 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 언리얼 엔진 4.13 업데이트 노트 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/2016/4_13 +Order:0 + +## 4.13.0 릴리즈 + +릴리즈일: 2016/09/01 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.13.0-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.13.0-release) + +릴리즈 노트: [](Support/Builds/ReleaseNotes/2016/4_13) + +## 4.13.1 핫픽스 + +릴리즈일: 2016/09/29 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.13.1-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.13.1-release) + +픽스: + +* UE-35735 Add Generated Vector 노드를 사용하여 EQS 실행 도중의 크래시를 고쳤습니다. + +* UE-35852 AI Move To Location 호출 시마다 속도가 0 으로 설정되어, 목적지에 도달하기 전 다시 움직이라 하는 경우 AI Pawn 이 얼어붙던 것을 고쳤습니다. + +* UE-35585 4.12.5 에서 4.13 으로 이주 시 블루프린트 함수가 입력/출력 변수를 잃을 수 있던 것을 고쳤습니다. + +* UE-35609 매크로에 사용된 Delay 노드가 딜레이 도중 다시 매크로를 호출하면 완료되지 않던 것을 고쳤습니다. + +* UE-35728 Git 리포지터리의 몇몇 파일이 리눅스에서 줄바꿈이 일관되지 않던 것을 고쳤습니다. + +* UE-36107 리눅스에서 설치 빌드를 생성할 수 없던 것을 고쳤습니다. + +* UE-35236 런처 설치 빌드에 Documentation/Extras 폴더가 없던 것을 고쳤습니다. + +* UE-36214 TMap 구조체 deserializer 의 크래시를 고쳤습니다. + +* UE-35884 지오메트리 에디터 사용 시 셰이프가 닫힌 후 Enter 를 누를 때의 크래시를 고쳤습니다. + +* UE-35822 BSP 브러시 순서 변경 시도 시 UTEditor 에 발생하던 크래시를 고쳤습니다. + +* UE-35048 [CrashReport] UE4Editor_PropertyEditor!FDetailCategoryImpl::GetParentLayoutImpl() [detailcategorybuilderimpl.h:168] + +* UE-35482 지오메트리 빌드 이후 다른 브러시 표면과 플러시 상태인 브러시 표면을 선택하면 전부 선택되던 것을 고쳤습니다. + +* UE-35627 라이트맵 UV 로 임포트 시 Lightmap Coordinate Index 가 자동으로 1 로 설정되지 않던 것을 고쳤습니다. + +* UE-35608 사용된 소프트웨어에 따라 FBX & OBJ 파일이 더이상 UV 포함 임포트되지 않던 것을 고쳤습니다. + +* UE-36383 스플라인 포인트를 블루프린트의 루트 컴포넌트로 만든 후 움직일 때의 크래시를 고쳤습니다. + +* UE-35658 블루프린트에 스플라인 컴포넌트를 추가하고 컴파일할 때의 에디터 크래시를 고쳤습니다. + +* UE-36096 일시정지 및 인터벌이 있는 상태에서 틱을 할 때 틱 태스크 매니저의 무한 루프를 고쳤습니다. + +* UE-35254 얼렘빅 애셋 임포트 시의 크래시를 고쳤습니다. + +* UE-36121 애디티브 애니메이션에 메시를 새로 임포트하고 스켈레톤을 재생성할 때의 크래시를 고쳤습니다. + +* UE-35546 LOD 변경 및 Layered Blend per Bone 사용 시의 포즈 깜빡임을 고쳤습니다. + +* UE-35353 2 플레이어 PIE 에서 디스트럭터블 오브젝트 스폰 시의 크래시를 고쳤습니다. + +* UE-35639 HLOD 생성 프록시가 더이상 타겟 라이트맵 좌표 인텍스를 생성 또는 할당하지 않던 것을 고쳤습니다. + +* UE-35494 테셀레이션 사용시 랜드스케이프 컴포넌트가 안보이던 것을 고쳤습니다. + +* UE-35873 LODBias 가 0 초과 설정되고 Forced LOD 는 -1 로 설정된 경우 랜드스케이프 컴포넌트 렌더링이 멈추던 것을 고쳤습니다. + +* UE-35301 오프셋이 있는 숨겨진 랜드스케이프 스트리밍 레벨 저장 시의 크래시를 고쳤습니다. + +* UE-35850 Early Z 패스 관련 랜드스케이프 에디터의 크래시를 고쳤습니다. + +* UE-35709 [CrashReport] UE4Editor_Landscape!FLandscapeEditDataInterface::SetAlphaData() [landscapeeditinterface.cpp:2617] + +* UE-36321 미디어 텍스처가 있는 액터 삭제 이후의 에디터 크래시를 고쳤습니다. + +* UE-36289 WmfMedia: 비디오 플레이 도중 메모리 누수를 고쳤습니다. + +* UE-35477 드래그 & 드롭을 통해 생성된 File Media Source 애셋이 상대 경로가 아닌 절대 경로를 갖던 것을 고쳤습니다. + +* UE-35504 PS4 미디어 플레이어의 메모리 관리가 위험해질 수 있었던 문제를 고쳤습니다. + +* UE-35696 PS4Media: 소멸자의 경쟁 조건으로 인해 CPU/GPU 크래시가 날 수 있던 것을 고쳤습니다. + +* UE-35598 Galaxy Note 7 처럼 OpenGL ES 3.2 지원 디바이스가 ES2 전용으로 감지되던 것을 고쳤습니다. + +* UE-35179 Vulkan API 버전이 너무 오래된 경우 GLES 로 예비 전환되도록 변경되었습니다. + +* UE-34782 GPU 파티클이 iOS 또는 TVOS Metal 디바이스에서 더이상 작동하지 않던 것을 고쳤습니다. + +* UE-33379 디바이스 프로파일에서 Android RHI 및 피처 레벨을 선택할 수 없던 것을 고쳤습니다. + +* UE-35258 Vulkan 을 지원하지 않는 Nougat 디바이스에서 ES2 예비 전환이 실패하던 것을 고쳤습니다. + +* UE-35261 세션 프론트엔드에 안드로이드 세션이 나타나지 않던 것을 고쳤습니다. + +* UE-32340 GitHub 에서 LLVM 버전을 검증할 수 없어서 HTML5 패키징이 실패하던 것을 고쳤습니다. + +* UE-32086 블룸 블러가 Xbox 화면 하단에 여러 색 부작용을 내던 것을 고쳤습니다. + +* UE-35492 PS4 디플로이가 모든 필수 파일을 디플로이하지 않던 것을 고쳤습니다. + +* UE-35743 Online Framework 및 Online Subsystem Steam 플러그인 사용 도중 안드로이드용 패키징을 할 때 실패하던 것을 고쳤습니다. + +* UE-35185 리눅스에서 위젯 블루프린트를 열면 에디터 크래시가 나던 것을 고쳤습니다. + +* UE-35738 IPv6 구현이 iOS 에서 작동하지 않던 것을 고쳤습니다. + +* UE-30959 다음 (4.13) 릴리즈에서 모든 HITCHHUNTER 경고가 제거됩니다. + +* UE-36342 안드로이드에서 무비 플레이어 활성화 관련 텍스처 문제를 고쳤습니다. + +* UE-35363 Safari 9.1.2 에서 실행 시 게임 창이 거대해지던 것을 고쳤습니다. + +* UE-35558 안드로이드에 파일을 쓰는 것이 트래킹된 파일 길이를 업데이트하지 않는 것을 고쳤습니다. + +* UE-35907 프로젝트 세팅 -> 플러그인에서 Slate Remote Enable Remove Server 옵션을 켜면 에디터가 멈추고 메모리 누수가 발생하던 것을 고쳤습니다. + +* UE-36099 PS4 화면에 점이 찍히던 것을 고쳤습니다. + +* UE-35794 PS4 에서 라이팅된 반투명 표면 머티리얼 사용 시 GPU 에서 멈출 수 있었던 것을 고쳤습니다. + +* UE-26375 위젯 컴포넌트의 드로 사이즈 편집시의 크래시를 고쳤습니다. + +* UE-17227 [CrashReport] UE4Editor_Engine!DoReadTaskResults() [shadercompiler.cpp:147] + +* UE-35240 Mac 에서 Protostar 를 실행시킬 때의 크래시를 고쳤습니다. + +* UE-28708 GitHub 2188 : 윈도우 GL4 에서 VR 프리뷰 종료시의 크래시를 고쳤습니다. + +* UE-35320 Stop>Set Sequence>Play 하면 스포너블이 복제되던 것을 고쳤습니다. + +* UE-35508 마스터 시퀀스 다이얼로그 버튼이 숨겨진 것을 고쳤습니다. + +* UE-35588 마티네 무브 서브 트랙에서 시퀀서로 잘못된 트랜슬레이션을 고쳤습니다. + +* UE-35285 시퀀서 스톱 노드가 카메라를 플레이어에게 돌려주지 않던 것을 고쳤습니다. + +* UE-35571 독립형 게임에서 시퀀스 녹화 크래시가 나던 것을 고쳤습니다. + +* UE-35107 Matinee to Level Sequence 컨버터가 프로퍼티를 바인딩하지 않던 것을 고쳤습니다. + +* UE-22581 왼쪽에서 오른쪽으로 움직일 때 모피우스 측면에 검정 부작용/반원같은 것이 보이던 것을 고쳤습니다. + +* UE-36076 PS4Tracker 의 모션 센서 데이터가 유효한 sizeOfThis 를 사용해야 하던 것을 고쳤습니다. + +* UE-35520 MorpheusHMD.cpp 의 sceKernelWaitEqueue 타임아웃을 4.13.1 에서 고쳤습니다. + +* UE-34986 Oculus Online Subsystem Plugin 업데이트를 안드로이드 지원을 노출시키도록 병합시켰습니다. + +* UE-34786 에디터 프리미티브가 인스턴스드 스테레오에서 스테레오로 잘못 렌더링되던 것을 고쳤습니다. + +* UE-35881 앱 시동 시 PSVR hmdSetupDialog 가 어서트를 취소하던 것을 고쳤습니다. + +* UE-36307 PSVR 모션 센서가 120hz 업데이트되었습니다. + +* UE-33763 GearVR 어플리케이션이 Adreno 디바이스에서 검정 화면으로 보이던 것을 고쳤습니다. + +* UE-36078 GoogleVR SDK 1.0 에 대한 픽스를 통합시켰습니다. + +* UE-35528 PSVR UE4 버벅임 문제를 고쳤습니다. + +* UE-35344 HapticFeedbackEffect_Soundwave 재생시의 크래시를 고쳤습니다. + +* UE-35964 사운드가 할당되지 않은 HapticFeedbackEffect_Soundwave 재생시의 크래시를 고쳤습니다. + +## 4.13.2 핫픽스 + +릴리즈일: 2016/10/26 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.13.2-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.13.2-release) + +픽스: + +* UE-37704 iOS 에서 패키지 프로젝트를 열 때의 크래시를 고쳤습니다. + +* UE-37249 MallocPoisonProxy 가 Debug 및 Development 에서 정렬 할당 시 메모리 스톰프가 발생할 수 있던 것을 고쳤습니다. + +* UE-36573 안드로이드용 libpng 가 현재 구글 플레이에서 보안 경고가 뜨던 것을 고쳤습니다. diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_14/Updates/UnrealEngine4_14UpdateNotes.CHN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_14/Updates/UnrealEngine4_14UpdateNotes.CHN.udn new file mode 100644 index 000000000000..bb67a750de4e --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_14/Updates/UnrealEngine4_14UpdateNotes.CHN.udn @@ -0,0 +1,174 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 虚幻引擎 4.14 更新日志 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/2016/4_14 +Order:0 + +## 4.14.0 Release + +Released: 11/15/2016 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.14.0-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.14.0-release) + +Release Notes: [](Support/Builds/ReleaseNotes/2016/4_14) + +## 4.14.1 Hotfix + +Released: 12/08/2016 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.14.1-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.14.1-release) + +Fixes: + +* UE-35609 Delay nodes used in a macro cause subsequent macro calls during the delay to never complete + +* UE-38690 Regression - Nested scene component subobjects are no longer being registered when the owning scene component is added to an existing Actor instance as an instanced component. + +* UE-38835 Rename "Visual Studio '15'" to "Visual Studio 2017" + +* UE-39298 UE4 and UnrealLightmass fail to build Module.SwarmInterface.cpp due to an error trying to open include file 'metahost.h' in SwarmInterface.cpp + +* UE-39284 Running GenerateProjectFiles.bat -2017 completes with warnings + +* UE-38898 UE4 is not compatible with Visual Studio 2017 RC + +* UE-38604 PS4 Platform Staging copies debug files (not allowed) + +* UE-38992 [CrashReport] UE4Editor_Core!FString::Mid() [unrealstring.h:1154] + +* UE-37249 MallocPoisonProxy can result in a memory stomp for aligned allocations in Debug and Development + +* UE-38991 [CrashReport] UE4Editor_Engine!FUObjectAnnotationSparse::AddAnnotation() [uobjectannotation.h:76] + +* UE-38752 Cannot Delete Folder Containing Sub Folders from Content Browser + +* UE-38721 Mouse cursor position is locked to center of screen when bShowMouseCursor is false + +* UE-38599 User Defined Struct Editor Hides Long Variable Lists + +* UE-38706 Dropdowns display incorrectly in non 1:1 zoom in BP on Mac and PC + +* UE-38806 Potential fatal assert when using a custom MID with a TextRenderComponent + +* UE-39059 No scrollbar in Structure UI + +* UE-39198 Limited range of motion when controlling the camera view with the mouse + +* UE-11796 Deleting folders in the Content Browser will not delete them permanently from Project Folder + +* UE-38925 Reimport for a single FBX with multiple meshes will add all mesh pieces instead of the single mesh. + +* UE-38935 Crash with FBX Import as Skeletal Mesh + +* UE-38749 Pressing enter does not appear to activate OnClicked events in UMG When a button is focused + +* UE-37698 Widgets can no longer take focus after clicking somewhere other than the widget itself + +* UE-36766 Crash attempting to open an asset from Aim Offset graph in Persona + +* UE-38811 Camera attached to a Spring Arm jitters when put at a +90 or -90 degree angle on the Y axis. + +* UE-38906 Crash when streaming in a level with a child actor + +* UE-38518 Animation Blueprint: Default values cannot be changed after compiling if node is currently selected + +* UE-39197 Delay node of 0.0 causes crash + +* UE-39137 Crash when Dragging Skeletal Mesh with Apex Clothing into Level + +* UE-38998 [CrashReport] UE4Editor_Engine!UMaterialInterface::GetBaseMaterial() [materialinterface.cpp:268] + +* UE-38716 Physics are popping in Vehicle Advanced Template + +* UE-38989 [CrashReport] PhysX3PROFILE_x64!physx::PxcDiscreteNarrowPhase() [pxcnpbatch.cpp:293] + +* UE-38694 Landscape Grasstype warning causes log spam when landscape is streamed in or out + +* UE-39278 Assertion failed: !LandscapeActor || LandscapeActor == Landscape + +* UE-38900 Paper2d Plugin Content Missing from Content Browser + +* UE-39120 ETC2 Android devices are no longer supported in the Google Play Store as of 4.14 + +* UE-37101 Xbox One: Issues updating texture subregions + +* UE-35738 IPv6 implementation is not working on IOS + +* UE-39420 QAGame crashes when launched onto Android + +* UE-38709 Using Deferred Decal Material With Dbuffer Decal Enabled Crashes Editor + +* UE-38223 Crash In Material Editor When Previewing A Node + +* UE-39051 Engine crash when Scene Capture Component 2D is added to viewport with forward rendering + +* UE-39123 Mac Editor crashes when opening Realistic Rendering sample - FMetalRHICommandContext::RHISetShaderUniformBuffer + +* UE-38609 DFAO runs out of memory on xb1 (DX11 RHI) due to an RHI bug + +* UE-38699 Material Expression comparison keys incorrect, produces duplicate code + +* UE-38325 Tangent Update Feature Not Working + +* UE-38768 Contact Shadow artifacts with ray lengths despite length + +* UE-34264 Procedural Mesh Component Crashes on XB1 + +* UE-39132 Crash when adding actors to the level + +* UE-38353 Crash while deleteing a UMG Animation Track referencing a deleted UMG asset with duplicated BSPs in-scene + +* UE-39067 Oculus Touch controllers jitter when the gamethread runs quickly + +* UE-39113 Post process material needs a full RT clear with hmd mask. + +* UE-39122 Crash when Simulating in Editor after Painting Foliage + +* UEVR-381 Interleaved Compositor: Execute init views before late update + +* UEVR-379 Interleaved Compositor: Implementing Post-Present handoff + +* UE-38670 New IsA() code can be thread-unsafe during saving + +## 4.14.2 Hotfix + +Released: 01/04/2017 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.14.2-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.14.2-release) + +Fixes: + +* UE-39970 Stat FPS and other text rendering as blocks on android. + +* UE-39560 [CrashReport] UE4Editor_Engine!ACullDistanceVolume::CanBeAffectedByVolumes() [culldistancevolume.cpp:62] + +* UE-39557 [CrashReport] UE4Editor_Persona!FDelaunayTriangleGenerator::FlipTriangles() [sanimationblendspace.cpp:375] + +* UE-39341 Compiling a blueprint with SetCollisionResponseToChannel Causes Crash + +* UE-38818 [CrashReport] UE4Editor_D3D11RHI!TerminateOnDeviceRemoved() [d3d11util.cpp:176] + +* UE-38772 [CrashReport] UE4Editor-Core.dylib!FThreadStats::FThreadStats() + +* UE-38750 Imported Materials Are Not Assigned To Correct Element Index Based Off Mat ID (3dsMax) + +* UE-38710 Vehicle physics are resolving erratically and causing random jitter/flips in the Advanced Vehicle Template + +## 4.14.3 Hotfix + +Released: 01/17/2017 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.14.3-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.14.3-release) + +Fixes: + +* UE-40229 Editor Crashes when importing some FBXs with multiple Material IDs in 4.14.2 + +* UE-40294 Put fix for UE-39713 into 4.14.3 (Memory leak in GPURealloc) + +* UE-40243 Calling FAudioDevice::StopAllSounds from UEngine::CommitMapChange asserts + +* UE-40156 PhysX issue causing lag, high ping, and failures + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_14/Updates/UnrealEngine4_14UpdateNotes.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_14/Updates/UnrealEngine4_14UpdateNotes.JPN.udn index 6ffae98f8c6c..e3f726c1d410 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_14/Updates/UnrealEngine4_14UpdateNotes.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_14/Updates/UnrealEngine4_14UpdateNotes.JPN.udn @@ -1,6 +1,6 @@ INTSourceChangelist:0 Availability:Public -Title: Unreal Engine 4.14 Update Notes +Title: アンリアル エンジン 4.14 アップデート ノート Description: Crumbs: Parent:Support/Builds/ReleaseNotes/2016/4_14 diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_14/Updates/UnrealEngine4_14UpdateNotes.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_14/Updates/UnrealEngine4_14UpdateNotes.KOR.udn new file mode 100644 index 000000000000..0089f28d7209 --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_14/Updates/UnrealEngine4_14UpdateNotes.KOR.udn @@ -0,0 +1,173 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 언리얼 엔진 4.14 업데이트 노트 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/2016/4_14 +Order:0 + +## 4.14.0 릴리즈 + +릴리즈일: 2016/11/15 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.14.0-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.14.0-release) + +릴리즈 노트: [](Support/Builds/ReleaseNotes/2016/4_14) + +## 4.14.1 Hotfix + +릴리즈일: 2016/12/08 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.14.1-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.14.1-release) + +픽스: + +* UE-35609 매크로에 딜레이 노드를 사용하면 딜레이 도중 잇따른 매크로 호출이 끝나지 않던 문제를 고쳤습니다. + +* UE-38690 퇴보 - 소유 씬 컴포넌트를 기존 액터 인스턴스에 인스턴스드 컴포넌트로 추가할 때 중첩된 씬 컴포넌트 서브오브젝트가 더이상 등록되지 않던 것을 고쳤습니다. + +* UE-38835 "Visual Studio '15'" 이름을 "Visual Studio 2017" 로 변경했습니다. + +* UE-39298 UE4 와 UnrealLightmass 가 SwarmInterface.cpp 의 'metahost.h' 인클루드 파일을 열려고 할 때 발생하는 오류로 Module.SwarmInterface.cpp 빌드 실패 문제를 고쳤습니다. + +* UE-39284 GenerateProjectFiles.bat -2017 실행 완료 시 경고가 나던 것을 고쳤습니다. + +* UE-38898 UE4 가 Visual Studio 2017 RC 와 호환되지 않습니다. + +* UE-38604 PS4 Platform Staging 이 (허용되지 않는) 디버그 파일을 복사하던 문제를 고쳤습니다. + +* UE-38992 [CrashReport] UE4Editor_Core!FString::Mid() [unrealstring.h:1154] + +* UE-37249 MallocPoisonProxy 가 Debug 와 Development 에서 정렬 할당 시 생길 수 있었던 메모리 스톰프 문제를 고쳤습니다. + +* UE-38991 [CrashReport] UE4Editor_Engine!FUObjectAnnotationSparse::AddAnnotation() [uobjectannotation.h:76] + +* UE-38752 콘텐츠 브라우저에서 하위 폴더가 있는 폴더를 삭제할 수 없던 문제를 고쳤습니다. + +* UE-38721 bShowMouseCursor 가 false 인 경우 마우스 커서 위치가 화면 중앙에 고정되던 것을 고쳤습니다. + +* UE-38599 사용자 정의 구조체 에디터가 긴 변수 리스트를 숨기던 것을 고쳤습니다. + +* UE-38706 Mac 과 PC 에서 블루프린트 1:1 줌 인 상태가 아닐 때 드롭다운이 잘못 표시되던 것을 고쳤습니다. + +* UE-38806 TextRenderComponent 가 있는 커스텀 MID 사용 시 치명적인 어서트가 날 수 있던 것을 고쳤습니다. + +* UE-39059 구조체 UI 에 스크롤바가 없던 것을 고쳤습니다. + +* UE-39198 마우스로 카메라 뷰를 제어할 때 모션 범위가 제한되던 것을 고쳤습니다. + +* UE-11796 콘텐츠 브라우저에서 폴더를 지우면 프로젝트 폴더에서 영구히 삭제되지 않던 것을 고쳤습니다. + +* UE-38925 메시가 여럿인 단일 FBX 를 리임포트하면 단일 메시가 아닌 모든 메시 조각이 추가되던 것을 고쳤습니다. + +* UE-38935 FBX 를 스켈레탈 메시로 임포트할 때의 크래시를 고쳤습니다. + +* UE-38749 버튼에 포커스가 있을 때 Enter 를 치면 UMG 에서 OnClicked 이벤트가 가동되지 않는 것처럼 보이는 것을 고쳤습니다. + +* UE-37698 위젯 자체가 아닌 다른 곳에 클릭한 이후 위젯이 더이상 포커스를 받지 못하던 것을 고쳤습니다. + +* UE-36766 페르소나의 에임 오프셋 그래프에서 애셋을 열려 할 때의 크래시를 고쳤습니다. + +* UE-38811 스프링 암에 붙은 카메라가 Y 축에 +90 또는 -90 도를 넣을 때 떨리던 것을 고쳤습니다. + +* UE-38906 자손 액터가 있는 레벨을 스트림 인 할 때의 크래시를 고쳤습니다. + +* UE-38518 애니메이션 블루프린트: 노드가 현재 선택된 경우 컴파일 이후 기본값을 변경할 수 없던 것을 고쳤습니다. + +* UE-39197 Delay 노드 값이 0.0 이면 크래시가 나던 것을 고쳤습니다. + +* UE-39137 Apex Clothing 이 있는 스켈레탈 메시를 레벨에 끌어놓을 때의 크래시를 고쳤습니다. + +* UE-38998 [CrashReport] UE4Editor_Engine!UMaterialInterface::GetBaseMaterial() [materialinterface.cpp:268] + +* UE-38716 Vehicle Advanced Template 에 피직스 팝핑 현상을 고쳤습니다. + +* UE-38989 [CrashReport] PhysX3PROFILE_x64!physx::PxcDiscreteNarrowPhase() [pxcnpbatch.cpp:293] + +* UE-38694 랜드스케이프 스트림 인 또는 아웃 시 랜드스케이프 그래스타입 경고가 로그 스팸나던 것을 고쳤습니다. + +* UE-39278 어서트 실패: !LandscapeActor || LandscapeActor == Landscape + +* UE-38900 Paper2d 플러그인 콘텐츠가 콘텐츠 브라우저에 없던 것을 고쳤습니다. + +* UE-39120 ETC2 안드로이드 디바이스가 4.14 이후 더이상 Google Play Store 에 지원되지 않던 것을 고쳤습니다. + +* UE-37101 Xbox One: 텍스처 서브리전 업데이트 관련 문제를 고쳤습니다. + +* UE-35738 IPv6 구현이 iOS 에서 작동하지 않던 것을 고쳤습니다. + +* UE-39420 QAGame 을 안드로이드에서 실행할 때 발생하던 크래시를 고쳤습니다. + +* UE-38709 Dbuffer Decal 활성화된 디퍼드 데칼 머티리얼이 에디터 크래시를 내던 것을 고쳤습니다. + +* UE-38223 노드 미리보기 시 머티리얼 에디터의 크래시를 고쳤습니다. + +* UE-39051 포워드 렌더링에서 씬 캡처 컴포넌트 2D 를 뷰포트에 추가했을 때 발생하던 엔진 크래시를 고쳤습니다. + +* UE-39123 Realistic Rendering 샘플을 열 때 Mac 에디터 크래시를 고쳤습니다 - FMetalRHICommandContext::RHISetShaderUniformBuffer + +* UE-38609 RHI 버그로 인한 xb1 (DX11 RHI) 에서의 DFAO 메모리 부족 현상을 고쳤습니다. + +* UE-38699 머티리얼 표현식 비교 키가 잘못되어, 중복 코드를 만들어내던 것을 고쳤습니다. + +* UE-38325 탄젠트 업데이트 기능이 작동하지 않던 것을 고쳤습니다. + +* UE-38768 광선 길이 관련 컨택트 섀도 부작용을 고쳤습니다. + +* UE-34264 XB1 에서의 프로시저럴 메시 컴포넌트 크래시를 고쳤습니다. + +* UE-39132 레벨에 액터를 추가할 때의 크래시를 고쳤습니다. + +* UE-38353 씬 내 복제된 BSP 포함 UMG 애셋을 삭제한 것을 레퍼런싱하는 UMG 애니메이션 트랙 삭제 도중의 크래시를 고쳤습니다. + +* UE-39067 오큘러스 터치 컨트롤러가 게임스레드를 빠르게 실행될 때 떨리던 것을 고쳤습니다. + +* UE-39113 포스트 프로세스 머티리얼이 HMD 마스크로 풀 RT 클리어가 필요하던 것을 고쳤습니다. + +* UE-39122 폴리지 페인트 이후 에디터에서 시뮬레이트할 때의 크래시를 고쳤습니다. + +* UEVR-381 Interleaved Compositor: 마지막 업데이트 전 init views 실행 문제를 고쳤습니다. + +* UEVR-379 Interleaved Compositor: Post-Present 핸드오프 구현 문제를 고쳤습니다. + +* UE-38670 새로운 IsA() 코드가 저장 도중 스레드 안전하지 못할 수 있던 문제를 고쳤습니다. + +## 4.14.2 핫픽스 + +릴리즈일: 2017/01/04 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.14.2-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.14.2-release) + +픽스: + +* UE-39970 Stat FPS 및 기타 텍스트가 안드로이드에서 블록으로 렌더링되던 문제를 고쳤습니다. + +* UE-39560 [CrashReport] UE4Editor_Engine!ACullDistanceVolume::CanBeAffectedByVolumes() [culldistancevolume.cpp:62] + +* UE-39557 [CrashReport] UE4Editor_Persona!FDelaunayTriangleGenerator::FlipTriangles() [sanimationblendspace.cpp:375] + +* UE-39341 SetCollisionResponseToChannel 설정된 블루프린트를 컴파일하면 크래시가 나던 문제를 고쳤습니다. + +* UE-38818 [CrashReport] UE4Editor_D3D11RHI!TerminateOnDeviceRemoved() [d3d11util.cpp:176] + +* UE-38772 [CrashReport] UE4Editor-Core.dylib!FThreadStats::FThreadStats() + +* UE-38750 임포트된 머티리얼이 (3dsMax) Mat ID 기반 올바른 엘리먼트 인덱스에 할당되지 않던 문제를 고쳤습니다. + +* UE-38710 Advanced Vehicle Template 에서 비히클 피직스 리졸브 방식이 잘못되어 무작위 떨림/뒤집힘 현상이 발생하던 것을 고쳤습니다. + +## 4.14.3 핫픽스 + +릴리즈일: 2017/01/17 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.14.3-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.14.3-release) + +픽스: + +* UE-40229 4.14.2 에서 Material ID 가 여럿인 FBX 임포트 시의 에디터 크래시를 고쳤습니다. + +* UE-40294 UE-39713 (GPURealloc 메모리 누수) 픽스를 4.14.3 에 올렸습니다. + +* UE-40243 UEngine::CommitMapChange 에서 FAudioDevice::StopAllSounds 호출 시 어서트가 발생하던 것을 고쳤습니다. + +* UE-40156 PhysX 이슈로 랙, 높은 핑, 실패가 발생하던 것을 고쳤습니다. diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_15/ReleaseNotes_4_15.CHN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_15/ReleaseNotes_4_15.CHN.udn index 313d713a7696..0f009231f9bb 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_15/ReleaseNotes_4_15.CHN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_15/ReleaseNotes_4_15.CHN.udn @@ -1,7 +1,7 @@ INTSourceChangelist:3303749 Availability:Public -Title:虚幻引擎 4.15 发行说明 -Description:虚幻引擎 4.15 的发行说明 +Title:虚幻引擎 4.15 版本信息 +Description:虚幻引擎 4.15 的版本信息 Crumbs:%ROOT%, Engine Parent:Support/Builds Order:15 diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_15/ReleaseNotes_4_15.INT.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_15/ReleaseNotes_4_15.INT.udn index f7c5fad9c389..33016da5a36b 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_15/ReleaseNotes_4_15.INT.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_15/ReleaseNotes_4_15.INT.udn @@ -375,7 +375,7 @@ A **Previous Frame Switch** node has been added to support complex vertex animat YbjqiNZr4K4 [/PARAMLITERAL] [PARAMLITERAL:width] - 720 + 720 [/PARAMLITERAL] [PARAMLITERAL:height] 408 @@ -384,7 +384,7 @@ A **Previous Frame Switch** node has been added to support complex vertex animat simple [/PARAMLITERAL] [/OBJECT] - +th Material vertex animations that are only a function of time already work without modification but cannot account for other variables, such as material parameters, that affect the animation. The previous frame switch enables artists to solve this problem manually when they can track how these parameters change, for instance in a blueprint. Note that using this feature requires Accurate velocities from Vertex Deformation to be enabled. diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_15/ReleaseNotes_4_15.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_15/ReleaseNotes_4_15.KOR.udn index ec02341156b4..58e3618d6f27 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_15/ReleaseNotes_4_15.KOR.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_15/ReleaseNotes_4_15.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3303749 +INTSourceChangelist:3403469 Availability:Public Title: 언리얼 엔진 4.15 릴리즈 노트 Description: Release Notes for Unreal Engine 4.15 @@ -2785,3 +2785,4 @@ Platform-specific release notes for PS4, XBoxOne, and Switch are available in th **Google Daydream** * Daydream apps require android-24. This is not installed by default, but can be manually installed with NVPACK\Chooser.exe. + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_15/Updates/UnrealEngine4_15UpdateNotes.CHN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_15/Updates/UnrealEngine4_15UpdateNotes.CHN.udn new file mode 100644 index 000000000000..487f5a88915b --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_15/Updates/UnrealEngine4_15UpdateNotes.CHN.udn @@ -0,0 +1,118 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 虚幻引擎 4.15 更新日志 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/4_15 +Order:0 + +## 4.15.0 Release + +Released: 02/15/2017 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.15.0-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.15.0-release) + +Release Notes: [](Support/Builds/ReleaseNotes/4_15) + +## 4.15.1 Hotfix + +Released: 03/20/2017 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.15.1-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.15.1-release) + +Fixes: + +* UE-42385 Crash adding an AnimComposite to itself + +* UE-41929 Crash on reimport animation when there is an additive animation track and fbx frame number is different + +* UE-41921 Crash Re-Importing animation with Additive Layer Tracks after adding a bone to the hierarchy + +* UE-41817 Crash when manipulating Bone Space IK before setting EffectorSpaceBoneName + +* UE-40025 Inconsistant Line Trace behavior + +* UE-42756 UnrealVS not installing correctly for VS2017 + +* UE-42321 Unable to launch project from Visual Studio using installed engine build + +* UE-42411 Resource files are not recompiled when Version.h changes + +* UE-42205 Hot reload reported as failed in Visual Studio for projects opened in the Editor after having hot reloads performed successfully previously + +* UE-42507 check(PIEInstanceID != -1) fails when executing SeamlessTravel + +* UE-42480 SetVectorParameterValueOnMaterials In Construction Script Not Working in Packaged Game + +* UE-42459 BP nativization doesn't work with localized text + +* UE-42166 Crash when pressing Ctrl-Z after creating a blueprint function + +* UE-41893 Child blueprints cannot override functions if their parent was nativized + +* UE-41168 Crash opening blueprint when a node class has been removed (e.g., anim blueprint with Ragdoll node with Immediate Mode plugin disabled) + +* UE-42209 Incorrect error message when child actor mobility doesn't match + +* UE-42253 Enum Element Names Reset on Project Upgrade + +* UE-42375 No input received from Raw Input device when packaged for 32bit + +* UE-39884 Foliage LODs do not appear to use the base LODs lightmap any longer + +* UE-42390 Ad banner is displayed incorrectly on Android 7.0 devices + +* UE-42361 Slate UI asset colors washed out on iOS + +* UE-42191 Scene Captures not working on Android + +* UE-42036 Exposure Is More Extreme In High-End Mobile Preview Modes + +* UE-42368 Find Sessions Consistently Returning Results Length of 0 + +* UE-42452 No textures listed when selecting material + +* UE-42789 Rebuilding lighting not saving rebuilt light data + +* UE-42196 Static meshes with auto-generated LODs can no longer share lightmaps between LODs + +* UE-42179 Crash in FStreamingTextureLevelContext::GetBuildDataIndexRef + +* UE-42165 [CrashReport] UE4Editor_Renderer!FReflectionEnvironmentSceneData::ResizeCubemapArrayGPU() [reflectionenvironment.cpp:215] + +* UE-42102 Cooked build size increase due to MIC problem + +* UE-41950 GitHub 3252 : Added MobileMaterialInterface to UsedMaterials + +* UE-29491 Eye Adaption is incorrect at any size other than Fullscreen in PIE + +* UE-42554 Regression: Visibility property is not seen in the animation track in UMG + +* UE-42210 Crash when using Ctrl+Z to undo a single digit change in the size of a widget + +* UE-41829 Crash scrubbing through sequencer when playing montage from old assets + +* UE-42665 Update default super search engine to Bing + +* UE-42428 Enabling "Show Only Modified Properties" causes details panel menu to disappear + +* UE-42312 Crash when saving a Data Table that is referencing itself in a Data Table Row Handle + +* UE-35606 Crash when Importing .OBJ using the File > Import into Level Option + +* UE-42669 "Package localization ID mismatch during cook!" log spam + +* UE-41797 Update to Korean localization + +* UE-42106 Edge case where cursor can become hidden in gameplay + +* UE-42631 Stereo off while prox sensor uncovered causes low framerate + +* UE-42576 Oculus crash on "stereo on" when the proximity sensor is not triggered. + +* UE-42101 [daydream] Black screen with FirstPersonTemplate and 4.15P4 + +* UE-41604 Integrate fix for improper failure case for allocation of RenderTargets in Oculus + +* UE-41568 Need to enable GearVR on Win64 platforms + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_15/Updates/UnrealEngine4_15UpdateNotes.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_15/Updates/UnrealEngine4_15UpdateNotes.JPN.udn index 22a7d3d4043a..305b5f9d66b4 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_15/Updates/UnrealEngine4_15UpdateNotes.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_15/Updates/UnrealEngine4_15UpdateNotes.JPN.udn @@ -1,6 +1,6 @@ INTSourceChangelist:0 Availability:Public -Title: Unreal Engine 4.15 Update Notes +Title: アンリアル エンジン 4.15 アップデート ノート Description: Crumbs: Parent:Support/Builds/ReleaseNotes/4_15 diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_15/Updates/UnrealEngine4_15UpdateNotes.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_15/Updates/UnrealEngine4_15UpdateNotes.KOR.udn new file mode 100644 index 000000000000..63532c04cddf --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_15/Updates/UnrealEngine4_15UpdateNotes.KOR.udn @@ -0,0 +1,118 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 언리얼 엔진 4.15 업데이트 노트 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/4_15 +Order:0 + +## 4.15.0 릴리즈 + +릴리즈 날짜: 2017/02/15 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.15.0-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.15.0-release) + +릴리즈 노트: [](Support/Builds/ReleaseNotes/4_15) + +## 4.15.1 핫픽스 + +릴리즈 날짜: 2017/03/20 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.15.1-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.15.1-release) + +픽스: + +* UE-42385 AnimComposite 을 자신에게 추가할 때 나던 크래시를 고쳤습니다. + +* UE-41929 애니메이션 리임포트 시 애디티브 애니메이션 트랙이 있는데 fbx 프레임 번호가 다를 때 나던 크래시를 고쳤습니다. + +* UE-41921 계층구조에 본을 추가한 뒤 애디티브 레이어 트랙이 있는 애니메이션을 리임포트할 때의 크래시를 고쳤습니다. + +* UE-41817 EffectorSpaceBoneName 설정 전 Bone Space IK 를 조작할 때의 크래시를 고쳤습니다. + +* UE-40025 Line Trace 작동방식이 일관되지 않던 것을 고쳤습니다. + +* UE-42756 UnrealVS 가 VS2017 에 제대로 설치되지 않던 것을 고쳤습니다. + +* UE-42321 설치된 엔진 빌드를 사용하여 Visual Studio 에서 프로젝를 실행할 수 없던 것을 고쳤습니다. + +* UE-42411 Version.h 변경 시 리소스 파일이 리컴파일되지 않던 것을 고쳤습니다. + +* UE-42205 기존에 핫 리로드가 성공적으로 수행된 이후 에디터에 열린 프로젝트에 대해 Visual Studio 에서 핫 리로드가 실패한 것으로 보고되던 것을 고쳤습니다. + +* UE-42507 SeamlessTravel 실행 시 check(PIEInstanceID != -1) 가 실패하던 문제를 고쳤습니다. + +* UE-42480 패키지 게임에서 컨스트럭션 스크립트의 SetVectorParameterValueOnMaterials 가 작동하지 않던 것을 고쳤습니다. + +* UE-42459 BP 네이티브화가 현지화 텍스트에 작동하지 않던 것을 고쳤습니다. + +* UE-42166 블루프린트 함수 생성 이후 Ctrl+Z 를 누를 때의 크래시를 고쳤습니다. + +* UE-41893 부모 블루프린트가 네이티브화된 경우 자손 블루프린트가 함수를 덮어쓸 수 없던 문제를 고쳤습니다. + +* UE-41168 노드 클래스가 제거되었을 때 블루프린트(예: Immediate Mode 플러그인이 비활성화된 Ragdoll 노드가 있는 애님 블루프린트)를 열면 발생하던 크래시를 고쳤습니다. + +* UE-42209 자손 액터 모빌리티가 일치하지 않을 때의 잘못된 오류 메시지를 고쳤습니다. + +* UE-42253 프로젝트 업그레이드 시 Enum 엘리먼트 이름이 리셋되던 것을 고쳤습니다. + +* UE-42375 32 비트 패키지 시 Raw Input 디바이스에서 입력을 받지 못하던 것을 고쳤습니다. + +* UE-39884 폴리지 LOD 가 베이스 LOD 라이트맵을 더이상 사용하지 않는 것처럼 보이던 것을 고쳤습니다. + +* UE-42390 안드로이드 7.0 디바이스에서 광고 배너가 잘못 표시되던 것을 고쳤습니다. + +* UE-42361 iOS 에서 Slate UI 애셋 컬러가 탈색되어 보이던 것을 고쳤습니다. + +* UE-42191 씬 캡처가 안드로이드에서 작동하지 않던 것을 고쳤습니다. + +* UE-42036 고사양 모바일 프리뷰 모드에서 노출이 더욱 극단적으로 나오던 것을 고쳤습니다. + +* UE-42368 Find Sessions 가 계속해서 길이를 0 으로 반환하던 것을 고쳤습니다. + +* UE-42452 머티리얼 선택 시 텍스처가 나열되지 않던 것을 고쳤습니다. + +* UE-42789 라이트 리빌드 시 리빌드된 라이트 데이터를 저장하지 않던 것을 고쳤습니다. + +* UE-42196 자동 생성 LOD 가 있는 스태틱 메시가 더이상 LOD 끼리 라이트맵을 공유하지 않던 것을 고쳤습니다. + +* UE-42179 FStreamingTextureLevelContext::GetBuildDataIndexRef 의 크래시를 고쳤습니다. + +* UE-42165 [CrashReport] UE4Editor_Renderer!FReflectionEnvironmentSceneData::ResizeCubemapArrayGPU() [reflectionenvironment.cpp:215] + +* UE-42102 MIC 문제로 인해 쿠킹 빌드 크기가 늘어나던 것을 고쳤습니다. + +* UE-41950 GitHub 3252 : UsedMaterials 에 MobileMaterialInterface 추가 + +* UE-29491 PIE 중 전체화면 이외의 크기에서 눈 순응이 제대로 나오지 않던 것을 고쳤습니다. + +* UE-42554 퇴보: Visibility 프로퍼티가 UMG 의 애니메이션 트랙에 보이지 않던 것을 고쳤습니다. + +* UE-42210 위젯의 크기를 한 자리수 변경한 것을 Ctrl+Z 로 되돌릴 때의 크래시를 고쳤습니다. + +* UE-41829 오래된 애셋에서 몽타주 재생 시 시퀀서를 통해 스크러빙할 때의 크래시를 고쳤습니다. + +* UE-42665 기본 수퍼 서치 엔진을 Bing 으로 업데이트했습니다. + +* UE-42428 "Show Only Modified Properties" 옵션을 켜면 디테일 메뉴가 사라지던 것을 고쳤습니다. + +* UE-42312 Data Table Row Handle 에서 자신을 레퍼런싱하는 Data Table 저장 시의 크래시를 고쳤습니다. + +* UE-35606 파일 > 레벨로 임포트 옵션으로 .OBJ 임포트 시의 크래시를 고쳤습니다. + +* UE-42669 "Package localization ID mismatch during cook!" 로그 스팸을 고쳤습니다. + +* UE-41797 한국어 현지화를 업데이트했습니다. + +* UE-42106 게임플레이 시 커서가 사라질 수 있었던 희귀한 경우를 고쳤습니다. + +* UE-42631 접근 센서가 커버되지 않은 상황에서 스테레오를 끄면 프레임이 낮아지던 것을 고쳤습니다. + +* UE-42576 접근 센서가 발동되지 않았을 때 스테레오를 켜면 Oculus 크래시가 나던 것을 고쳤습니다. + +* UE-42101 [daydream] FirstPersonTemplate 와 4.15P4 에서의 검정 화면을 고쳤습니다. + +* UE-41604 Oculus 에서 렌더 타겟 할당에 대한 잘못된 실패 케이스 픽스를 통합시켰습니다. + +* UE-41568 Win64 플랫폼에서 GearVR 활성화를 시켜줘야 하던 것을 고쳤습니다. + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_16/4_16ReleaseNotes.CHN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_16/4_16ReleaseNotes.CHN.udn new file mode 100644 index 000000000000..ba3a73122eea --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_16/4_16ReleaseNotes.CHN.udn @@ -0,0 +1,3908 @@ +INTSourceChangelist:3457153 +Availability:Public +Title: 虚幻引擎 4.16 发布! +Description: 虚幻引擎 4.16 发行说明 +Crumbs:%ROOT%, Engine +Parent:Support/Builds +Order:16 +reference-image: image_18.gif +reference-image: image_28.gif +reference-image: image_31.gif +reference-image: image_35.gif + +![](DOCS_BANNER_416.jpg) + +## 新增内容 + +虚幻引擎 4.16 包含一些令人激动的 **新增渲染和动画功能**,针对 **移动和游戏机平台进行了大量的性能改进,还包含无数产品周期质量增强功能**,便于用户更轻松地制作令人印象深刻的环境和交互体验,并能够在更多平台上流畅地运行。 + +利用出色的新增 **体积雾 (Volumetric Fog)** 功能可以增强环境氛围,此功能能够自动渲染真实的烟雾效果,并且在场景中的任何位置都能保持一致的照明,即使是在大规模场景中表现也毫不逊色。 + +利用新增的动态 **轻量级刚体** 和 **底层布料仿真** 工具,让角色活灵活现!使用动画修改器、样条曲线解算器、更新后的姿势驱动程序以及对动画系统的许多其他改进,更好地控制动作流。 + +垃圾回收现在的速度也提高为 **原来的两倍**!UI 渲染性能和 UMG 小部件创建速度也明显提高,用户现在可以创建更加引人注目的界面。**VR 模式**、动画、Sequencer 和其他工具的界面和工作流也已经更新,使得开发流程获得前所未有的简化和流畅体验。 + +4.16 完全支持 **任天堂 Switch**,已经可以用于进行相关制作!Epic Games 与任天堂联手发布完整的任天堂 Switch UE4 源代码,面向获得批准的开发人员免费开放。要了解更多入门信息,请[点击此处阅读更多内容](http://www.unrealengine.com/en_US/blog/launch-your-game-on-the-nintendo-switch-with-unreal-engine-4-16)。 + +**DirectX 12 现在是 Xbox One 的默认渲染器**,在本引擎中提供了对平台支持的性能和功能增强。此外,您现在还可以使用 WebAssembly 和 WebGL 2 开发 HTML5 游戏,这种全新的途径在 UE4 中会继续完善。 + +对于移动开发,现在支持安卓虚拟键盘,并且为蓝图和代码提供了运行时权限。此外,我们还在减少移动应用的可执行文件大小方面取得了重大进步! + +除了 Epic 交付的数百项更新之外,本版本还包括由 GitHub 上非常了不起的虚幻引擎开发人员社区提交的 **160 项改进**!感谢以下每一位贡献者对虚幻引擎 4.16 的贡献: + +0lento、Akihiro Kayama (kayama-shift)、Alice Robinson (Valkrysa)、Altrue、Andreas Rønning (Sunjammer)、Andrew Gaubatz (e-agaubatz)、Angus Jones (crumblycake)、Artem V. Navrotskiy (bozaro)、Black Phoenix (PhoenixBlack)、Cedric Neukirchen (eXifreXi)、Cengiz Terzibas (yaakuro)、Chris Varnz (chrisvarns)、Christopher P. Yarger (cpyarger)、Damian Nowakowski (zompi2)、DarkSlot、DeanoC、Derek van Vliet (derekvanvliet)、devbm、dodgyville、drelidan7、Gabriel Lima (Gabriel-Lima-O)、Gyeonghwan (conquests)、Hao Wang (haowang1013)、Ilya (ill)、Jackblue (JohnsonJackblue)、James Horsley (mmdanggg2)、Jeff Rous (JeffRous)、Jon Watte (jwatte)、Jørgen P. Tjernø (jorgenpt)、jostster、Kalle Hämäläinen (kallehamalainen)、katze7514、Kevin Kuegler (FrostByteGER)、KrisRedbeard、looterz、Manmohan Bishnoi (manmohanbishnoi)、Marat Radchenko (slonopotamus)、Markyroson、Martin Treacy-Schwartz (the1schwartz)、Matt Edmonds (cleaver404)、Matthew Casey (mdcasey)、Matthias (haimat)、Matthias Hölzl (hoelzl)、Matthias Huerbe (MatzeOGH)、Michael Schoell (MichaelSchoell)、Michał‚ Siejak (Nadrin)、Milan Šťastný (aknarts)、Moritz Wundke (moritz-wundke)、Mustafa TOP (MSTF)、Narendra Umate (ardneran)、Nathan Stocks (CleanCut)、NaturalMotionTechnology、Nick Verenik (nverenik)、Paul Murray (awesomeness872)、pfontain、Phil Christensen (Rastaban)、PrimalJohnScott、projectgheist、Rafael Ortis (rafortis)、Rajko Stojadinovic (rajkosto)、Rama (EverNewJoy)、rhughesgeomerics、Ricardo Rodrigues (RicardoEPRodrigues)、Robert Hagglund (hagglund)、Robert Segal (robertfsegal)、Ryan Pavlik (rpav)、sangpan、Sanjay Nambiar (sanjay-nambiar)、Satheesh (ryanjon2040)、Sean Campbell (scampVR)、Sebastian Axinte (ENiGMA9)、Sébastien Rombauts (SRombauts)、SiebenCorgie、Stefan Zimecki (stefanzimecki)、StefanoProsperi、Stephen Johnson (megasjay)、TaeYoung Cho (valval88)、Timothee Besset (TTimo)、Timothy Hagberg (thagberg)、Tom Kneiphof (tomix1024)、Tom Ward (tomwardio)、TRS-justing、unwitherer、Vladimir (VladimirPobedinskiy)、Vladimir Alyamkin (ufna)、wyhily2010、Yaroslav Shmelev (SoulSharer)、yeonseok-yi + +## 主要特性 + +### 新增特性:体积雾 + +使用新增的体积雾功能在环境中创建不可思议的氛围!由于支持多种不同的密度,因此可以模拟尘土或烟雾流动于光束之间的效果,任何数量的光束都会影响体积雾。 + +![image alt text](image_0.png)(w:929 h:529 convert:false) + +![image alt text](image_1.png)(w:928 h:510 convert:false) + +![image alt text](image_2.png)(w:928 h:510 convert:false) + +体积雾支持以下类型的光照: + +* 单向光,通过级联阴影贴图实现阴影,或者通过光函数实现静态阴影。 + +* 任意数量的点和点光源,并伴有动态或静态阴影(如果启用了“投射体积阴影”) + +* 单一天空光,利用启用的“距离场环境光遮蔽”实现阴影 + +* 粒子光照(如果“体积散射强度”大于0) + +您可以使用对粒子系统应用的材质,通过新增的“体积范围”设置来控制体积雾。具有体积材质的单一粒子会导致向体积雾添加一个球体的密度。这完全是 3D 效果,毫不吹嘘。多个球形雾状粒子结合材质干扰可以将雾的效果限制在特定范围。 + +有关设置体积雾的信息,请参阅[本文档](Engine/Rendering/LightingAndShadows/VolumetricFog)。 + +### 新增特性:基于图像的 (FFT) 高光卷积 + +使用新增的基于图像的 (FFT) 卷积功能创建真实的高光后处理效果!虚幻引擎 4.16 交付了 FFT Bloom,让美工能够利用自定义的高光内核形状,完全自主掌控强度以达到自己想象的结果。 + +![image alt text](image_3.png)(w:928 h:485 convert:false) + +通过结合使用原始图像的数学卷积和内核图像,这种高光技术可以产生连续反应,例如星爆效果、扩散发光区域。这种基于图像的卷积之所以能产生额外的真实感,是因为它能够使用视觉上很有趣的非对称内核图像。它通常看起来像是有射线条纹的星爆效果,但可以包含睫毛轮廓、散景或者其他失真效果。 + +**注:** 基于图像的卷积 Bloom 是为了在电影艺术或高端硬件中使用而设计的,而预置(标准)Bloom 应该用于大多数游戏应用。 + +### 新增特性:距离场照明优化 + +在最新一代游戏机和中等规格的 PC 上,**距离场环境光遮蔽** 和 **光线跟踪距离场阴影** 现在速度已经 **提高了 30-50%**!这两个功能使您能够在场景中的动态网格上实现更加真实的环境照明和区域阴影。 + +![image alt text](image_4.png)(w:929 h:513 convert:false) + +此外,静态网格 **距离场生成速度也提高为原来的 2.5 倍**,这得得益于 Intel 的 Embree 光线跟踪库的加速。启用了八位网格距离场和压缩网格距离场项目设置时,内存用量也明显降低。 + +### 新增特性:轻量级刚体仿真 + +利用新增的 **轻量级刚体角色仿真** 创建大量逼真角色!您现在可以使用新增的高性能 **即时模式** PhysX API 在动画蓝图中模拟物理资产。使用这种仿真的角色也可以与世界中的静态几何体产生碰撞。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + VaxxVsv0Fak + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +### 新增特性:底层布料仿真 + +使用新增的底层 NVIDIA NvCloth 布料解析器能够更好地控制布料仿真! + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 5BqodzWZIUA + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +我们已经将 APEX 布料解析器替换为 NVIDIA 提供的更底层的解决方案 NvCloth。这个新的解析器与之前的 APEX 解决方案的核心解析器类似,只是稍微做了一点行为更改,借助它能够更方便地访问用于惯性设置的仿真数据和额外公开的参数。 + +### 新增特性:在任天堂 Switch 上发布游戏! + +注册的开发人员现在可以构建和发布适用于任天堂 Switch 的游戏了!虚幻引擎 4 提供了可随时投入制作的任天堂 Switch 支持,已通过认证,支持多玩家联网游戏,并允许访问多个渲染管道,例如延迟、移动向前和集群向前,使用户几乎能够交付适合任天堂 Switch 的任何类型的游戏。 + +[REGION:raw] +![image alt text](image_7.png)(w:925 h:641 convert:false) +[/REGION] + +### 新增特性:VR 模式 UI 和交互更新 + +虚幻编辑器中的 VR 模式已彻底改造,现在提供更直观的工作流和编辑体验! + +![image alt text](image_8.jpg)(w:722 h:646 convert:false) + +一方面,新型的非对称控制器设置增添了一个改进的新型辐射式菜单,另一方面增添了精度提高的交互激光器,让用户能够快速轻松地处理关卡中的对象。 + +所有 VR 模式操作,包括所有主要的编辑器功能和 UI 面板,现在都可以从更新后的辐射式菜单进行访问。传送系统也进行了更新,现在可以瞬间移动到某个位置,将大小恢复为默认规模,以玩家的视角进行查看。有关更多信息,请参阅 [https://docs.unrealengine.com/latest/INT/Engine/Editor/VR/GDC2017/](https://docs.unrealengine.com/latest/INT/Engine/Editor/VR/GDC2017/) + +### 新增特性:在 VR 中编辑序列 + +Sequencer 过场动画编辑器现在可以在 VR 中使用了!用户现在可以创建新的序列,在关卡中四处移动对象,并且在这个过程中自动为转换创建序列键。通过拉动时间轴和设置这些键,可以创建过场动画序列和回放,这一切都是可以在 VR 中操作。还可以从 Sequencer UI 或辐射式菜单打开现有的关卡序列并进行回放。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + X4Zw9U20Gw4 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +* 新增特性!可调整的键使您能够真实地调整世界中的轨迹! + +* 辐射式菜单中的“拉动时间轴”选项可以前后播放序列的速度获取控制棒或触控板输入。再次按扳机可以退出拉动时间轴模式。 + +### 新增特性:VR 模式下的物理仿真 + +现在可以使用运动控制器与物体交互,**在 VR 模式下模拟物理 Actor**!放置 Actor 装置来模拟物理效果,让物理仿真自己运行以获得真实的散落效果,或者使用运动控制器让 Actor 四处闲逛。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + bG2Qf897CBI + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +### 新增特性:VR 模式下的智能咬合 + +智能咬合使用物体的边界来与场景中的其他 Actor 对齐,使用户能够准确地将它们连接在一起,而无需一直想着网格来构建模块化资产。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + lvqxM1kjubE + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +此功能当前仅在 VR 模式下可用,但我们会在将来的版本中添加对桌面编辑的支持。 + +### 新增特性:Xbox One 渲染器 DirectX 12 + +**DirectX 12 现在是 Xbox One 的默认渲染器!** 我们在 DirectX 12 中进行了一系列稳定性和性能改进。这样就可以将其作为默认的 RHI,为针对 Xbox One 开发的游戏带来 **CPU 和 GPU 性能改进**。 + +![image alt text](image_12.png)(w:556 h:356 convert:false) + +#### 切换回到 D3D11 + +需要切换回到 D3D11 的游戏将需要做如下设置: + +1. 修改游戏 defaultengine.ini 中的 bBuildForD3D12 + +2. 针对 Xbox One 重新构建游戏 + +3. 重新烘焙内容 + +**注:** 在将来的版本中将弃用 D3D11 RHI。 + +### 新增特性:对 WebAssembly 和 WebGL 2 的 HTML5 支持 + +虚幻引擎 4 现在支持 HTML5 全新的 WebAssembly 标准(也称为 WASM),这是最快最有效的编译和运行网络 C++ 的方法!我们目前使用的是 Mozilla 最新的 Emscripten 工具链 (v1.37.9)。这是一种新技术,并非在所有浏览器中都受到支持,因此将其视为抢先体验功能,需要 GitHub 访问权。 + +[REGION:raw] +![image alt text](image_13.png)(w:929 h:630 convert:false) +[/REGION] + +WASM 是一种适用网络应用的新型 JavaScript 代码转二进制格式,能够减小应用下载大小,缩短启动时间,降低内存消耗,提供明显的性能提升。有关 WASM 和浏览器支持的更多详细信息,请前往 [http://webassembly.org/](http://webassembly.org/) + +UE 4.16 还添加了对 WebGL 2.0 的支持,该支持基于 OpenGL ES 3.0,提供了更杰出的渲染性能,提高了视觉保真度,并支持更多渲染功能,包括: + +* UE4 高端移动特性级别的大多数功能 + +* 粒子和植物叶子的实例化几何绘图 + +* 支持多个渲染目标 (MRT) + +* 纹理特性,例如,3D 或体积纹理、2D 数组纹理,不再存在非二次幂纹理限制 + +WASM 和 WebGL 2.0 受 Firefox 52 和 Chrome 57 或更高版本支持(推荐使用 64 位)。请注意,Windows 系统 Chrome 58 中似乎存在一个 bug,有时会导致内存不足错误。我们正在与 Google 通力协作来解决这一问题。请参阅 [UE-44727](https://issues.unrealengine.com/issue/UE-44727) 以了解有关该问题的最新状态。 + +您可以在 HTML5 项目设置的 Emscripten 部分中启用 WASM 和 WebGL 2.0。如果需要最广的浏览器支持,请继续使用 ASM.js 和 WebGL 1。*在即将发布的引擎中将放弃对 ASM.js 和 WebGL 1 的支持,之后会将其删除(确切时间取决于其他浏览器支持)。* + +请观看在线演示:[试着用 HTML5 制作禅意花园](https://hacks.mozilla.org/2017/03/firefox-52-introducing-web-assembly-css-grid-and-the-grid-inspector/),用自己的 Firefox 或 Chrome 浏览器(上述所列的受支持版本)抢先体验这些好处。 + +### 新增特性:垃圾回收速度翻倍 + +垃圾回收性能已经明显改善,现在 **速度是原来的两倍!** 具体的改进包括: + +* 可访问性分析多线程已重新设计,现在能够降低任务管理的开销。 + +* 垃圾回收集群现在支持蓝图生成的类和所选 Actor 类型。 + +* Uobject 非散列代码已经优化,缩短了销毁 Actor 所用的时间。 + +### 新增特性:运动身体与仿真本体 + +现在用户能够使用运动身体与仿真本体。现在可以使用完全由动画数据驱动的子骨骼,例如角色的手,而这些骨骼的本体也可以由物理仿真数据驱动。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + qiiOU_fhex0 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +这样就可以实现很酷的效果,例如,当有滚落的石头朝着玩家身体冲过来的时候,玩家做出攀岩响应。 + +### 新增特性:平台 SDK 升级 + +在每一个版本中,我们都会更新引擎以支持平台伙伴的最新 SDK 版本。 + +[REGION:raw] +![image alt text](image_15.jpg)(w:929 h:522 convert:false) +[/REGION] + +* **Visual Studio:** 要点:在本版本中,Windows 上不再支持 Visual Studio 2013。请升级到 Visual Studio 2015 或 Visual Studio 2017。 + +* **任天堂 Switch:** 支持任天堂 SDK 1.3.1 + +* **Xbox One:** 根据 2016 年 10 月 QFE3 XDK 构建 + +* **PlayStation 4:** 已升级到 PSR SDK 4.508.001 SDK + +* **安卓:** 已更新 CodeWorks for Android 1R6u1 + +* **GoogleVR:** 已将插件更新到 V1.3 + +* **GoogleVR:** SDK 已更新到 1.40.0 + +* **GoogleVR:** 默认模式更改为 Daydream 和 Cardboard + +* **Vulkan:** 将可分发文件和语言处理更新到 SDK 1.0.39.1 + +### 新增特性:Sequencer 镜头轨道增强 + +Sequencer 中的镜头轨道在过场动画和影片创建方面进行了一些改进! + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + GqfJxD1DY8I + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +* **基于镜头的等级偏差:** 在默认情况下,关卡序列层次结构中较低级别的轨道具有优先权。这让电影制作人能够构建一个自己惯用的管道,镜头调整将覆盖镜头所在序列中的轨道。 + +* **针对所有轨道公开“完成时”属性:** 这让用户能够指定在序列完成时,轨道是应该将值恢复为制作动画之前的状态,还是保持不变。在电影制作环境中,通常需要镜头中的动画值恢复为制作动画之前的状态,这样就不会渗入到下一个镜头。在过场动画中,可能需要值一致保持下去,这样就可以从 Sequencer 动画状态直接进入到游戏中。 + +* **预卷/后卷:** 预卷和后卷现在是所有轨道的笼统概念。某些轨道具有特定的行为,例如,镜头切换轨道会在预卷评估期间通知流系统下一个将要出现的镜头切换位置。 + +### 新增特性:Sequencer 中的材质参数集合动画 + +用户现在可以在 Sequencer 中对材质参数集合制作动画,这样就可以全面的把控动画标量和矢量参数,从而在任意数量的材质中引用这些参数。无需再针对每个材质实例对各个参数值制作动画来共享动画。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + u_Cpqz7mFuM + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +### 新增特性:改进了 UI 渲染性能 + +使用失效面板的游戏现在可以选择仅缓存小部件元素,而不是渲染数据,这样就能够体会到大幅改进的纹理批处理的好处,并且能够显著减少绘图调用。结果是在移动设备上显著提高性能! + +[REGION:asyncgif] +![image alt text](image_18.gif)(w:456) +[/REGION] + + +在《战争机器》英雄选择 UI(上图)上,每个应用的逻辑元素都可以缓存,但也可以进行批处理。游戏机变量 Slate.CacheRenderData=0 可以启用这种模式,现在在移动设备上这是默认模式。 + +### 新增特性:改进了动画姿势驱动程序 + +我们对姿势驱动程序功能进行了许多改进,使用户能够以程序方式,比较一组骨骼和另一组参考“目标”的姿势,驱动混合形状或骨骼。这在某些部位尤其有用,比如在肩膀位置,可能需要根据上臂和肩膀的姿势来激活校正变形目标。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + sjtbvyDdW9w + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +* 现在可以选择多个骨骼作为“输入”来读取姿势 + +* 现在可以选取应由节点修改的骨骼 + +* 可以指定“自定义曲线”来表示应如何激活每个目标 + +* 可以选择直接驱动曲线(变形、材质),而不需要姿势资产 + +* UI 已改进为允许创建/编辑目标姿势,用于显示目标激活的条形等等 + +* 现在可以单击视口中的目标位置以将其选中 + +### 新增特性:材质扁平化的不透明和不透明蒙版 + +我们添加了对使用 Actor 合并工具或分层 LOD 系统时 **烘焙掉不透明(蒙版)值** 的支持。产生的(实例化)材质使用配置好的混合模式,确保它采用正确的渲染路径。以下是烘焙掉蒙版材质的示例: + +![image alt text](image_20.png)(w:904 h:740 convert:false) + +### 新增特性:改进了网格绘图工具 + +网格绘图系统进行了大幅改造,改进了易用性,现在更加清晰明朗,允许在编辑器的其他部分复用此功能。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + UezYKhase9g + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +此外,绘图工具现在也可以在骨骼网格上使用!请注意,绘图*并不*以实例为基础(与静态网格形成对比),而是直接应用于骨骼网格资产。 + +### 新增特性:样条曲线解算器 + +动画蓝图中新增了一个样条曲线节点,用于控制角色样条或骨骼链! + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + chqOk4QdPR0 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + + +### 新增特性:在网格表面上检测材质 + +我们为组件添加了一个新功能“从面部索引获取材质”,使用户能够在执行(复杂的)线路跟踪之后检索应用到组件的材质。该功能支持用于静态网格、程序网格组件和 BSP。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + SvsSnkwB1TQ + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +### 新增特性:“观看”动画节点改进 + +“观看”节点的 **观看位置** 属性可以相对于骨骼或骨臼使用。之前在指定骨骼或骨臼时,这个值是被忽略的。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 3C7Q6JJxmtY + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +“观看”控制的可视化也进行了改进。例如,您可以看到夹角、目标位置、插值等等。 + +### 新增特性:动画导出改进 + +我们添加了对创建和导出动画的支持,这些动画可以包含根据指定给骨骼网格的后处理图形生成的额外动画数据,例如,用于物理仿真的动画动态效果。 + +要包含此类额外数据,请从 **创建动画** 或 **导出动画** 菜单中选择 **预览网格**。 + +![image alt text](image_25.png)(w:697 h:256 convert:false) + +### 新增特性:虚幻音频引擎(抢先体验预览) + +GDC 宣布的全新虚幻音频引擎已在 PC、Mac、iOS、安卓和 Switch 上推出了抢先体验版本。它包含跨平台混音器,完全向后兼容现有的音频引擎功能套件,包括新的多平台 EQ 和混响大师级效果。此外,新的虚幻音频引擎还引入了一些新功能,例如,次混音图、次混音效果、源效应、实时合成以及更优秀的音频插件支持。 + +在 4.16 中默认不会启用新增的虚幻音频引擎,因为我们还在继续开发针对游戏机平台、Linux 和 HTML5 的实现后端,以及稳定性和性能改进,尤其是在移动平台上。 + +要启用混音器,请使用命令行参数“-audiomixer”。 + +注:如果在启动编辑器时没有启用混音器,那么大部分新的虚幻音频引擎功能都是隐藏的。 + +#### 新增特性:合成插件(抢先体验) + +新的合成插件包含两个以新的虚幻音频引擎“SynthComponent”类编写的新实时合成器,用于实现功能全面的精简合成器以及实时成粒器。这些新的合成器不仅对过程音乐和声音设计十分有用,而且也充分展示了第三方插件制造商和声效设计师如何实现自己的合成效果。 + +合成插件还包含大量的新 DSP 源效应和次混音效果,可以与新的虚幻音频引擎配合使用: + +* **源效应:** 立体声延迟、Bit Crusher、动态处理器、包络跟随器、EQ 过滤器、虚拟模拟过滤器(Ladder/State 变量)、波形速形器、合唱、相位器 + +* **次混音效果:** 混响、EQ、动态处理器 + +### 新增特性:Steam 音频(抢先体验) + +Epic 和 Valve 联手发布了第一个完全集成的 Steam 音频 SDK 实现,利用了新虚幻音频引擎的新功能。 + +![image alt text](image_26.png)(w:600 h:160 convert:false) + +Steam 音频基本上是集成了新虚幻音频引擎的空间化、遮蔽和混响系统,为 UE4 VR 带来了全新的基于物理的音频体验。这是 Steam 音频的抢先体验版本,其中包含计划在 4.17 发布的重要更新、更多示例项目和工作流改进。Epic 和 Valve 期待各种反馈、疑问、想法或改进意见。 + +请访问 [https://valvesoftware.github.io/steam-audio/](https://valvesoftware.github.io/steam-audio/) 以了解有关 Steam 音频的更多信息、文档和支持帮助。 + +### 新增特性:改进了颜色分级工具 + +颜色分级用户界面已经改进,现在使用起来更加简单! + +![image alt text](image_27.jpg)(w:529 h:257 convert:false) + +* 添加了新的 HSV 模式。 + +* 现在可以使用 Ctrl+拖动滑块,根据滑块的类型动态更改其最小值/最大值。 + +* 添加了新的重置按钮,用于重置整个颜色分级类别。(即,全局、阴影、中间色调、高亮色) + +### 新增特性:改进了动画混合空间编辑器 + +混合空间编辑器现在允许用户使用网格内部的 **显示动画名称** 按钮来显示每个样本的动画名称。用户现在可以将动画拖放到现有样本的上面以将其替换。 + +[REGION:asyncgif] +![image alt text](image_28.gif)(w:905) +[/REGION] + +### 新增特性:本地化字符串表 + +UE4 现在支持本地化字符串表! + +![image alt text](image_29.png)(w:601 h:218 convert:false) + +字符串表提供了一种将本地化文本集中到一个(或多个)已知位置的方法,然后以一种稳定的方法,在其他资产或代码中引用字符串表中的条目,从而轻松地复用本地化文本。字符串表可以使用 C++ 定义,通过 CSV 文件加载,也可以创建为资产。 + +### 新增特性:动画修改器(抢先体验预览) + +动画修改器使用户能够对给定动画序列或骨骼应用一系列动作,例如精确定位右脚踩到地面时的帧,将动画同步标记添加到 ball_r 骨骼位于其最低点(接触到地面)时的帧。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + YC_UJuO9AI8 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +动画蓝图功能库中提供了一组用于访问特定动画数据的一组新功能。访问和应用动画修改器可以通过骨骼编辑器和动画编辑器中的一个新选项卡来执行。动画修改器可以添加到骨骼或动画序列。对于动画序列,动画修改器仅应用到序列本身。当应用于骨骼时,它应用于基于该骨骼的所有动画序列。 + +### 新增特性:安卓虚拟键盘(抢先体验预览) + +安装现在支持使用操作系统的虚拟键盘来取代弹出的对话框输入框! + +[REGION:asyncgif] +![image alt text](image_31.gif)(w:256) +[/REGION] + + +要启用虚拟键盘,可选中 **项目设置 > 平台 > 安卓 > APK 打包** 下的复选框。该选项启用对虚拟键盘的基本支持,但输入元素是否可见,而不会被虚拟键盘遮挡,则使用提供的 OnVirtualKeyboardShown 和 OnVirtualKeyboardHidden 事件处理程序由应用程序自行保证。 + +**注:** 如果用户使用的语言要求使用 IME,那么可能需要使用 Android.NewKeyboard 控制台变量禁用虚拟键盘。 + +### 支持安卓运行时权限 + +虚幻引擎 4 现在支持安卓 23 及更高版本要求的运行时权限,以访问需要 Google 归类为危险的权限的功能。这包括访问联系人、照片、电话状态、外部存储、照相机和定位服务。请参阅以下网页以了解详细信息:[https://developer.android.com/guide/topics/permissions/requesting.html](https://developer.android.com/guide/topics/permissions/requesting.html). + +如果目标系统是安卓 23,那么安卓运行时权限插件现在能够在运行时通过原生代码进行检查,或者如果已经授予了权限,可以使用 **检查安卓权限** 蓝图节点进行检查。如果尚未授予权限,应用可能会使用 **请求安卓权限** 蓝图节点向用户申请该权限,然后使用绑定到 **授予权限时的动态委托** 的事件获取结果。这样就可以在游戏要求使用需要权限的功能之前授予权限,从而改善用户体验。如果目标系统是安卓 23 之前的版本,可以照常在 Android Manifest 中指定权限来授予权限。 + +![image alt text](image_32.png)(w:718 h:346 convert:false) + +**注:** 4.16 要求安装安卓 SDK 23 或更高版本。如果还没有安装该级别的 SDK,可以在 Engine/Extras/AndroidWorks 目录中找到 CodeWorksforAndroid-1R6u1 安装程序。此外,在“项目设置”下的 Android SDK,请将安卓 SDK API 级别从 matchndk 更改为 latest。这样可以确保 UE4 使用在安卓 SDK 平台目录中找到的最新安装的 SDK。无需更改 NDK API 级别,android-19 是允许在 Lollipop(安卓 5.0)之前的安卓版本上安装 APK 的正确级别,如果设置为更高的级别会导致应用要求使用安卓 5.0+。 + +### 用于减小包大小的着色器代码库 + +现在可以使用 **共享材质着色器代码** 项目设置为所有着色器代码启用共享存储位置,这样就会为产生相同着色器代码的材质或材质实例存储单一副本。 + +某些平台(例如 iOS、TVOS 和 MacOS 上的 Metal)支持更高效的特定于平台的着色器库。启用 **共享材质原生库** 项目设置,可以利用这种原生库格式,从而进一步减小包大小。 + +### 新增特性:从 FBX 导入关节囊碰撞 + +现在可以从 FBX 文件导入关节囊简单碰撞,方法就像导入箱子、球体和凸面简单碰撞一样。现在可以在关节囊多边形网格上使用“UCP”前缀,导入时会将其删除,替换为对应的关节囊碰撞形状。 + +### 新增特性:共享与本地资产查看器配置文件的选项独立开来 + +虚幻编辑器现在支持在共享或本地级别存储资产查看器配置文件,使团队能够轻松地使用一组共享配置文件作为统一场景来评估美工资产。在本地级别存储配置文件能够确保用户仍可以使用一组自己想要在本地使用、但团队不需要的自定义配置文件。共享配置文件存储在 *DefaultEditor.ini* 中,要求用户检出或者将其设置为可写入才能使用。 + +### 新增特性:改进了动画预览场景 + +我们对动画工具的预览场景进行了若干改进: + +* 预览场景设置已经移到了现有设置选项卡,而不是位于视口的隐藏菜单中。该设置选项卡现在默认为显示状态。 + +* 主工具栏中添加了快速切换预览网格的快捷方式。适用于所有动画编辑器。 + +* 在添加预览场景时,无需再为了预览额外网格而创建“预览场景集合”资产。现在如果对网格设置感到满意,可以选择将其保存到资产。 + +### 新增特性:向动画查看器添加了默认摄像机选项 + +现在可以保存骨骼网格的“默认摄像机”位置。这适用于打开网格的情况,也可以通过按 Shift+F 来直接进行保存。 + +### 新增特性:播放蒙太奇蓝图节点 + +**播放蒙太奇** 是一个新增的异步节点,可以在任何蓝图逻辑中用于播放动画蒙太奇。它方便用户访问某些回调事件,让用户能够在蒙太奇混出、中断等情况下触发其他节点 + +![image alt text](image_33.png)(w:376 h:272 convert:false) + +* 当蒙太奇完成播放并完全混出时,调用 OnCompleted。 + +* 当由于自动或手动停止导致蒙太奇开始混出时,调用 OnBlendOut。 + +* 当由于被另一个蒙太奇播放而中断导致蒙太奇开始混出时,调用 OnInterrupted。 + +* 当使用蒙太奇资产中的“播放蒙太奇通知”或“播放蒙太奇通知窗口”动画通知时,调用 OnNotifyBegin 和 OnNotifyEnd。这些动画通知可以携带额外的“通知名称”以区分来自同一蒙太奇的不同回调。 + +### 新增特性:为重定位姿势添加了选项 + +现在可以从姿势资产导入要在设置重定位基本姿势时使用的姿势。原来用于修改和保存当前姿势(使用当前姿势)和将骨骼转换重置为参考姿势(重置)的选项仍然可用。 + +**注:** 您可以在动画编辑器中创建姿势资产,并以指定的名称在姿势资产中插入任何姿势。 + +### 新增特性:静态网格编辑器中的静态视图选项 + +静态网格编辑器工具中现在提供了一些独立的选项,用于查看静态网格的简单和复杂碰撞。 + +### 新增特性:LOD 中的烘焙姿势 + +虚幻引擎 4 现在支持使用一个新的缩减设置“烘焙姿势”在 LOD 级别中烘焙姿势。这可以设置为单帧动画序列,以应用到所产生的 LOD 网格。事实证明,在删除骨骼并仍想保留姿势时特别有用。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 0fcNitNu9FE + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + 简单 + [/PARAMLITERAL] +[/OBJECT] + +**注:** 该功能要求使用 Simplygon + +### 新增特性:Sequencer 用户界面改进 + +音频轨道缩略图现在可以通过内部(平滑)RMS 曲线呈现峰值样本。音频轨道现在也可以纵向调节大小! + +[REGION:asyncgif] +![image alt text](image_35.gif)(w:929) +[/REGION] + + +其他 Sequencer UI 改进: + +* Sequencer 控制的 Actor 现在输出到关卡中时能够正确地做好标记。 + +* 现在可以为事件轨道指定额外的事件接收方(即 Actor 蓝图)。 + +* 绑定改进。现在可以在蓝图中为关卡序列拖拽/放置/设置绑定。例如,可以在蓝图中衍生对象,并将其指定到现有轨道。 + +### 新增特性:移动 VR 渲染改进 + +现在对三星 Gear VR 支持直接多视图,当使用移动多视图时,删除了额外的渲染目标和全屏复制,改进了总体性能,降低了内存用量。 + +在 Gear VR 上启用了多视图后,可以使用平面远场,确保以最佳效果呈现场景的立体渲染部分。 + +Google Daydream 支持标准移动多视图,将来版本中将提供直接支持。 + +### 新增特性:PlayStation VR 的社交屏幕(抢先体验预览) + +PSVR 社交屏幕预览提供了对社交屏幕独立模式的支持,即显示器和 HMD 显示屏是不相同的。 + +该预览支持 30fps 的社交屏幕输出,还支持切换几种不同的输出模式。实现了以下样本模式: + +* SystemMirror(这是始终存在的默认镜像模式)。 + +* SeparateTest(仅在社交屏幕上进行黑白切换)。 + +* SeparateTexture(显示蓝图指定的纹理,例如,场景捕获组件写入的渲染目标)。 + +* SeparateMirror(显示完整的 VR 渲染缓冲) + +将来的工作包括优化、针对这些功能的多平台接口、可能支持 60fps 模式(这要求系统对话框解决与某些系统功能的冲突)。 + +新的 PSVR 项目设置 bEnableSocialScreenSeparateMode 必须设置为 true 才能使用此功能。当此设置为 true 时,会为社交屏幕分配额外的屏幕缓冲。搜索“SocialScreen”可以找到用于控制此功能的蓝图功能。 + +### 新增特性:安卓可执行文件大小降低 + +我们对编译器和链接器设置进行了一系列优化,减小了安卓二进制可执行文件的大小。选中 **以隐藏符号可见性进行构建** 选项后,在生成安卓可执行文件时,链接器会更加积极地从虚幻引擎中删除不使用的代码。这样也会从符号表中分离出功能符号,从而进一步减小可执行文件的大小。预计最终 APK 会减小大约 7MB。 + +**注:** 该选项会从设备上的二进制文件中删除一些符号,因此 logcat 输出中会显示一些没有任何符号的本机冲突调用堆栈。为了帮助排除故障,构建系统也会将含有除错符号的未分割二进制文件复制到输出目录,同时生成一个批处理文件以将这些符号添加到调用堆栈。 + +### 新增特性:顶点插值器材质表达式节点 + +在材质图形中添加了顶点插值器节点,现在用户可以更好地控制顶点和像素画之间的插值。添加这些节点是为了改进工作流,因此插值器限制并没有变化,着色器也未进行更改。 + +用于将工作转移到顶点着色器的现有工作流利用自定义 UV 输出。这样可能有点麻烦,而且还要手动打包数据。以下材质示例将预先经过皮肤处理的网格数据打包,然后再解包以在某种效果中使用: + +![image alt text](image_36.png)(w:766 h:665 convert:false) + +新的插值器节点会自动处理打包,因此能够简化并插入图形: + +![image alt text](image_37.png)(w:776 h:357 convert:false) + +之前通过自定义 UV 打包的工作现在会链接到 VS(顶点着色器)引脚,然后从 PS(像素着色器)引脚检索。 + +材质统计输出已更新为显示最新的插值器用量,包括目前已打包和可用的最大值。请注意以上示例中指令的计数方式,而且插值器用量保持不变。统计显示 TexCoord[0] 节点保留了 2 个标量,其余 6 个由预先经过皮肤处理的数据保留,因此在 2 个矢量中总共打包了 8 个标量。 + +该功能与自定义 UV 兼容,并且会将结果打包在一起。 + +### 新增特性:资产管理框架(抢先体验预览) + +资产管理器是一个新增的全局对象,用于在编辑器中或在运行时发现、加载和审计地图以及特定于游戏的资产类型。它提供了一个框架,便于用户创建类似任务、武器或英雄之类的内容,并按需装入。现在仍在开发中,这些功能还没有准备就绪,不适用于只使用蓝图开发的游戏或者经验不足的开发人员,预计将于 4.17 正式推出。项目设置中的资产管理器选项卡可以用于建立游戏的规则: + +在运行时,可以查询资产管理器扫描的主资产类型,然后再进行加载,之后就可以根据需要异步加载。此外,在打包和发布游戏时,资产管理器设置也可以用于建立烘焙和分块规则。AnswerHub 上提供了有关此功能的仍在编写的文档:[https://answers.unrealengine.com/questions/595580/what-is-the-asset-manager.html](https://answers.unrealengine.com/questions/595580/what-is-the-asset-manager.html) + +### 新增特性:资产审计窗口(抢先体验预览) + +资产审计窗口是基于资产管理框架构建的,可以一次性审计大量资产的磁盘大小、内存用量和一般资产属性。这是内容浏览器的专用版本,可以从 **窗口 > 开发人员工具** 菜单进行访问,也可以通过内容浏览器或参考查看器中的右键单击菜单访问。打开窗口后,可以使用各个按钮添加资产,在烘焙资产注册表之外装入的平台数据可以使用平台下拉菜单进行加载。以下是从 PS4 上的射击游戏样本中截取的审计纹理示例: + +![image alt text](image_38.png)(w:929 h:289 convert:false) + +### VR:VR 的统一游戏机命令 + +我们整合并统一了各个 VR 平台的游戏机命令,创建了一个共享层供开发人员使用,而不必单独维护每一种平台。 + +这样有以下好处: + +* 启动新平台更加简单。 + +* 各个 HMD 的参数含义更加一致。 + +* 当前 HMD 实现的冗余减少。 + +* 所有 VR 相关的游戏机命令使用通用的前缀“vr.”。在命令名中清晰地标记了特定于供应商的扩展名。 + +* 更新后的游戏机命令支持补全和内联用法帮助文本。 + +在过渡期间,仍能够识别旧版游戏机命令,但使用时会发出不推荐使用的警告。 + +### 自定义硬件指针 + +现在 Windows、Mac 和 Linux 上支持平台原生自定义硬件指针!您可以设置硬件指针以在项目的用户界面设置中使用。 + +系统允许用户为指针提供多种格式。例如,您可以在设置中指定使用“Slate/FancyPointer”作为默认指针。在游戏内容文件夹的 Slate 目录中,会有 FancyPointer.png + .cur + tiff,用于包含某些平台的多分辨率解析功能。Mac 上将装入 tiff,Windows 上使用 cur/ani 文件,如果没有找到我们支持的特定于某一平台的格式,将查找 png。 + +### 快速创建小部件 + +UMG 小部件创建速度现在提高为三倍!在烘焙时,小部件编译器现在会生成小部件模板/原型,与所生成的蓝图类存储在同一个包中,并在小部件创建期间使用。 + +**技术细节** + +在编译期间,我们生成了一个几乎完全初始化的小部件树,包含所有子用户小部件及其树,连接了所有成员变量,初始化了指定槽,设置任何动画等等。这个几乎完全构造的小部件可以进行实例化以用作原型,但不一定要使用对应的慢速 StaticDuplicateObject 路径。 + +这种方法存在一些限制,如果用户忘记在子对象属性上设置“已实例化”,小部件的部分编译步骤现在会检验实例化是否成功,实例化之后是否存在 GLEO 引用。幸运的是,这种情况应该少之又少,因为所有的 UVisuals(小部件和槽)现在都是 DefaultToInstanced,这样就解决了一些不可避免的要求有已实例化标志的情况。尤其是在原生代码中使用 BindWidget 的很多情况。 + +译者: 版本更新 changelist 详单并不翻译。欢迎跳转 [论坛中文版面](https://forums.unrealengine.com/forumdisplay.php?16-China) 讨论。 + +## Release Notes + +### AI + +* New: Added a profiler for Environment Query System (EQS) that can be accessed through the tabs of the EQS Editor. + + * It collects data automatically during game sessions as long as UES_EQS_DEBUGGER define is set. This includes options for average and max execution time of each step (including breakdown of composite generators), number of items processed by each step, and average frequency of running, which can be useful to identify how often fail safes are actually running. + + * It collects tick load data when USE_EQS_TICKLOADDATA define is set. Each query can store up to 16384 records in cyclic buffer (~4.5 minutes at 60 FPS) showing percentage of EQS tick spent on processing it. This is displayed on the graph in EQS editor tab. + + * A console command has been added, "DumpEnvQueryStats", that saves current EQS profiler data to a file (project's Logs folder, .ue4eqs extension), which can be later loaded and inspected in the EQS Editor. + +* Bugfix: Fixed an issue with Blackboard Key Selector's "Init Selector" that resulted in it picking the first value from the Blackboard rather than the appropriately typed one. + +* Bugfix: Gameplay Task Resource's Auto Resource ID initialization is no longer cleared during Hot Reload. + +* The "Get AI Controller" is now a pure Blueprint Function. + +* Exposed Brain Component's "Is Running" and “Is Paused” functions to Blueprint. + +* Clamped AI Sight's peripheral vision angle as well as changed the UI to not allow values outside of the 0-180 range. + +* Disabled collision on Nav Modifier Volumes. Previously they had an 'Overlap All' response and generated overlap events. They are only supposed to be used for preventing navmesh generation, but overlap events could affect gameplay and are also bad for performance. + +* Made "Skip Agent Height Check When Picking Nav Data" option ignore height when picking nav data for agents. It now picks solely based on the radius when this is enabled. + +#### Behavior Tree + +* Bugfix: Added safeguards to prevent crashes resulted from Blackboard keys being names being longer than 1024 characters. + +* Bugfix: Fixed an issue in dynamic Behavior Tree injection that was causing unexpected behavior when the main BT had more BT injection points. + +* Bugfix: Fixed an issue in Blackboard key instantiation that resulted in the instanced key never being used and BB operations always referring to the original BB entry. + +### Debugging Tools + +* The Gameplay Debugger's input detection has been adjusted so that Tap and Hold work correctly in fixed timestep mode. + +### Navigation + +* Added a flag to Recast Navmesh, "Allow Nav Link As Path End", that is used to control whether path corridors can end on a navigation link or not. This may happen with partial paths and not usually desired behavior. Navigation links at the end are not allowed by default. + +* The Blueprint functions "Project Point To Navigation", “Get Random Reachable Point In Radius”, and “Get Random Point In Navigable Radius” all return booleans determining if the projection/generation was successful, as well as the vector value that describes the requested point. + +* Bugfix: Fixed a memory leak in navmesh generators. + +* Bugfix: Fixed an issue that resulted in losing user settings in Static Mesh's navigation export (Nav Collision object) after changing any property of the Static Mesh. + +* Bugfix: Hand-placed AI pawns now get their Path Following Component's "My Nav Data” variable set properly. + +* Bugfix: Fixed an issue with missing update of navigation area after duplicate or undo operations on Nav Link Proxy and Nav Link Component. + +* Bugfix: Corrected the handling of path following requests by Floating Pawn Movement. + +* Bugfix: Fixed an issue with parameters of geometry trace handling drop-down navigation links. All components blocking on ECC_WorldStatic channel will now report a valid hit. + +* BugFix: HLOD's navigation collision exporting no longer causes unnecessary log output about NavCollision instances in cooked builds. + +#### Animation + +* New: You can now rename Virtual Bones. + +* New: You can now change Virtual Bones so that you can have a Virtual Bone that is a child of another Virtual Bone. + +* New: Added "Get Body Target Transform" to the Physical Animation component, which will return the goal transform that a particular body is trying to get to. + +* New: Control rig Sequences can now be exported to Anim Sequences. + +* New: Preview Scene settings have been exposed in the existing settings tab rather than in a hidden menu of the viewport. + +* New: Support for "Curve Source" nodes to find source components on other Actors. It now searches for the property name rather than the component name. + +* New: Added "Set Preview Mesh" to the toolbar for all animation related Editors. + +* New: Updated Alembic Third-party libraries to the latest versions. + +* New: Added functionality to try and match in-engine Material asset names to FaceSet names found inside of an Alembic cache to automatically assign the correct Materials. + +* New: The Alembic Importer now supports Vertex Color data. + +* New: Added functionality to inform about changes to source data when reimporting your animation data from FBX. It now checks for the following: + + * Whether or not the sequence length has changed. + + * Whether or not previously-imported curves exist in the source data. + +* Bugfix: Fixed a crash when trying to implement a function in a child Anim Blueprint. + +* Bugfix: Fixed a crash when debugging a null Animation Sequence. + +* Bugfix: Trying to access a skinned vertex position on a mesh when using Master Pose component no longer crashes. + +* Bugfix: Attempting to bind to Skeletal Mesh with Anim Blueprint already set no longer crashes. + +* Bugfix: Fixed a crash and effector selection issue for two-bone IK. + +* Bugfix: Right-clicking the empty space in the asset shortcut drop-down no longer crashes. + +* Bugfix: Removed an ensure (warning) by reverting to default unit vectors if zero-sized lookat/lookup vectors are specified for a "Look At" node. + +* Bugfix: Removed a crash when clearing an animation of a 1D blendspace sample. + +* Bugfix: Crash fix to import code for Alembic Caches with the HDF5 backend. + +* Bugfix: Fixed an issue when adjusting curves in the Anim Curves tab using a slider when they are not currently selected. + +* Bugfix: Fixed an issue with Update Rate Optimization update rate being too high. Now we use int, so if you have a high update rate it still can go until it wraps around. + +* Bugfix: Child Anim Blueprints can now be retargeted. + +* Bugfix: Fixed flipping transforms when mirrored. + +* Bugfix: Post Process instances are now appropriately updated, even when the main Anim Instance is not using parallel update. + +* Bugfix: Fixed an issue where running the Editor in a different culture could break pins on nodes that have optional arrays of pins (ie. Animation Graph nodes like Blend By Layer). + +* Bugfix: Fixed an issue with Anim Class being set by name, causing duplicate-named Anim Blueprints to be incorrectly resolved. + +* Bugfix: Fixed an issue where "r.SkeletalMeshLODBias" was affecting meshes in the Animation Editor viewports. + +* Bugfix: Fixed an issue with Animation Preview Scene keyboard binding (I and O hotkeys now hide and show scene elements regardless of tab opened state). + +* Bugfix: Skinned Mesh LOD now updates in the editor under various physics-related circumstances. + +* Bugfix: Fixed an issue with foot placement IK doing line traces on worker threads. + +* Bugfix: Fixed an issue with Anim Blueprints that contain State Machines having blank palettes. + +* Bugfix: Renaming curves in animations now saves properly. + +* Bugfix: Fixed an issue with two-bone IK flickering around full extension when stretch is enabled. + +* Bugfix: Animation now works as expected for dynamically-bound wheeled-vehicle anim instances. + +* Bugfix: Fixed an issue where you could not undo changes from Alembic Import settings. + +* Bugfix: Fixed timing issues occurring while playing back Alembic caches. + +* Bugfix: Fixed an issue with incorrect behavior occurring when placing more than three samples in a straight line for a 2D blendspace. + +* Bugfix: Dropping a new Animation asset on an existing Sequence Player node can now be undone. + +* Bugfix: Breaking transition node connections within Animation State Machines can now be undone. + +* Bugfix: Fixed an issue to ensure that changes to animation sync markers are propagated to currently open blendspace assets. + +* Bugfix: Skeletal Mesh components tick properly when paused if "Tick Event When Paused" is enabled. + +* Bugfix: Fixed Skeletal Mesh Merge duplicating Skeletal sockets. + +* Enabled snapping for translation in the Animation viewports. + +* Removed force inline from Virtual Compression functions. + +* Removed the AnimGraph module from the Graph Editor as a dependency. + +* Bone Reference now has improved performance by caching compact post bone index. + +* Graph files have been moved to Animation Blueprint Editor. + +* We have stopped saving raw curve data into animations on cook in order to save memory and disk space. + +* Ticks now appear properly on Anim Sequence scrub bar. + +* Persona now depends publicly on Skeletal Editor. + +* Montages are now correctly initialized when created. They can be used straight away without first opening them in the Montage Editor. + +* We now propagate thread safety flags to child Animation Blueprints. + +* The Anim Notify Blueprints now start with a "received notify" event node. + +* Made single-node animation instances request clothing simulation resets when their animation is changed. This is because the new animation could be very different from the outgoing animation, and this might cause pops. + +* Refactored "Evaluate Bone Transforms" to prevent usage of Skeletal Mesh component. + + * Deprecated "Evaluate Bone Transforms" in favor of new “'EvaluateSkeletalControl_AnyThread”. + + * Deprecated Skeletal Mesh component argument to "Convert CS Transform To Bone Space" and “​Convert Bone Space Transform To CS”. Now they just take a transform. + +* When selecting bones that are non-required, we now do not render gizmos or text labels. + +* Skeletal selection does not lag behind choice made in the viewport (i.e. when showing bone weights). + +* Added accessor and modifier functions for "Start Time Offset" value in Geometry Cache components. + +##### Animation Assets + +* New: You can now choose a preview slot in the Montage Editor. + +* Bugfix: Fixed a crash when reimporting animations with additive transform tracks. + +* Bugfix: Fixed an issue with additive Pose Asset preview being applied twice. + +* Bugfix: Compressed animation data is now included in Memory Stats for Animation Sequences. + +* Bugfix: Fixed an issue where blendspace interpolation settings would not have a direct effect and required reopening the blendspace asset. + +##### Animation Blueprint + +* New: Added "Spline IK" node. + +* New: Added a property to Blendspace Player nodes that enables users to choose whether the play time is reset when the blendspace changes. + +* New: Animation Blueprints can now specify a Preview Mesh. + +* New: Added the "Look At" node so you can use “Look at Location” on a socket or joint, and improved the Visualizer. + +* Bugfix: Fixed a crash when "Pose Asset" contains a bone that is not in the mesh. + +* Bugfix: Fixed an assertion that could occur when selecting certain items in the Animation Blueprint editor. + +* Bugfix: Fixed a crash when diffing State Machine Transition graphs. + +* Bugfix: Fixed an issue with "Pose Handler" using mesh bone index and not compact bone index for setting up “Bone Blend Weights” array. + +* Bugfix: Fixed an issue with incorrect errors on compiling Aim Offset nodes with exposed blendspace pins. + +* Bugfix. Fixed an issue with additive nodes breaking the current pose when they have no additive animation attached. + +* Bugfix: Fixed issues pertaining to extra references to Animation Blueprints on Skeletal Mesh components. + +* Layered Bone Blend node has been optimized so that it will cache mask weights in compile time. + +##### Import/Export + +* Bugfix: Fixed a crash when reimporting a Skeletal Mesh that has Virtual Bones. + +##### Skeletal Mesh + +* Bugfix: Fixed a crash when using re-import button in the Skeletal Mesh Editor. + +* Bugfix: Fixed a crash related to Skeletal Mesh resources not being initialised before component is registered. + +* Bugfix: Fixed a serialization mismatch in Skeletal Mesh source buffers. + +* When importing a Skeletal Mesh, "Activate Bone Indices" now always includes parents even if it's not skinned. + +#### Tools + +* Bugfix: Fixed a crash in Persona when rotating a bone due to single bone controllers not being initialized correctly. + +* Bugfix: Fixed an ensure when deselecting bones in Anim Blueprint editor. + +* Bugfix: Fixed an issue where mesh-customized sockets were not showing up by default in 'Active' socket filter mode. + +* Bugfix: Fixed issues related to bone removal in Skeletal Mesh LODs. + + * Issue where the "Apply" button would not show after adding bone names. + + * Issue where previously removed bones would not be restored. + + * Ensure that the Skeletal Tree is updated when bones are removed or restored. + +* Double-clicking animation assets in Content Browser will now try to re-use existing Animation Editor windows, rather than opening a new one every time. + +* Animation picker on Skeletal Mesh component is now disabled rather than hidden when no Skeletal Mesh is assigned. + +* The Soundwave-internal curve tables have been moved to the 'Advanced' rollout. + +#### Audio + +* New: Vorbis-encoded audio files can now be streamed. + +* New: Audio streaming is now supported on Android, iOS, and XBox One. + +* Bugfix: Fixed a shutdown crash when there is a pending async audio occlusion trace. + +* Bugfix: Fixed a crash when opening a Media Sound Wave. + +* Bugfix: 'Sound Player' nodes will more efficiently load the referenced sound asset unless a 'Sound Quality' node is being used to select which 'Sound Player' nodes to consider, in which case, the current asset reference evaluation will continue to be used. + +* Bugfix: We only queue subtitles once per-wave instances playback. + +#### Automation + +* New: Added support for -DeveloperReportOutputPath and -DeveloperReportUrl commands to permit local runs of the Automation Tool to generate reports on the report server and launch the browser to view them. + +* 'ResavePackages' commandlet now supports lighting in separate packages when using it to rebuild lighting. + +* Option to disable taking screenshots has been disabled. Screenshot comparison is an integral part of the testing so disabling them is no longer allowed. + +* The system now waits for the asset registry to finish loading assets before running tests. + +#### Blueprints + +* New: Added the 'Remove Gameplay Tag' function to the gameplay tag function library. + +* New: Blueprints containing a String and Text variables can now be marked as multi-line, which enables values to contain newlines when pressing Shift + Enter while editing them. + +* New: Blueprint Variables can now be marked as 'Read-Only' in Blueprint Editor, which prevents them from being set in Blueprints. This behaves the same as using 'BlueprintReadOnly' instead of 'BlueprintReadWrite' on a C++ UPROPERTY() declaration. + +* New: 'Get Default Locale' has been exposed to Blueprints. + +* Macro instances that contain latent actions will now show an overlay clock icon like other latent nodes, which makes them easier to spot and understand that they impact execution flow + + ![image alt text](image_39.png)(w:720 h:180 convert:false) + +* New: Improved comments in Blueprints. + + * Comment node text now wraps while the comment is being edited. + + * Reduced cases where the title of a comment node would clip at the end. + + * Editing the comment for a regular node using the right click menu will now show changes immediately, rather than waiting until the node was moused over again. + +* New: Added the Save and Find in Content Browser buttons to the Level Script Blueprint editor (they will save/show the map package that contains the Level Script). + +* New: Added the ability to search for delegate nodes using the function name that they are bound to. + +* New: 'Array Get' node. + + * Can toggle between returning a reference or copy. + + * Using a reference solves a longstanding issue with arrays of structs not being able to easily make changes to the items in the array. + +* New: 'Get Class Defaults' node has been extended to include output pin exceptions for Set & Map variable defaults. Like array types, the returned value is now a copy of the default value rather than a reference to it. This is done in order to avoid an accidental mutation of the Blueprint class default object. + +* New: Function inputs are now exposed as variable "Get" nodes via the right-click context menu in a Blueprint function graph context. + + * To use: In a Blueprint Function graph, right-click to access the context menu. Any input parameters will be listed as additional "Get" actions. + + * In this way, input parameters can be accessed like local variables from anywhere in the function graph; in other words, it's no longer necessary to drag wires all the way back to the Function Entry node in order to access these values. + +* New: We now support "value-based" Bitfield enum type associations in the editor for a UPROPERTY marked as 'Bitmask' with a 'BitmaskEnum' association. + + * Prior to this release, Bitfield properties did not work with associated enum types in which the enum values were explicitly set to a bitmask value (e.g. 0x80). That is, the value was assumed to always be set to the index of the bit that the flag should set in the editor ("index-based" mode). + + * To switch the associate to the new "value-based" mode, include an additional metadata key in the UENUM() declaration. Example: UENUM(Meta = (Bitmask, *UseEnumValuesAsMaskValuesInEditor="true"*)). + +* New: Added a whitelist mechanism for handling native noexport types that can support direct field access in nativized Blueprint code. + +* Bugfix: Fixed a crash in Blueprint Editor when adding an input parameter to a Custom Event node after deleting a Function Graph containing a Create Event node. + +* Bugfix: Fixed a crash when creating a new Blueprint class from one or more selected Actors in which the root component is not Blueprint-spawnable. + +* Bugfix: Fixed a crash on load in nativized EDL-enabled builds with non-nativized child Blueprint class assets. + +* Bugfix: Fixed a runtime Blueprint VM crash upon removing an element from set after consecutive add/remove iterations. + +* Bugfix: Fixed a crash that could occur when splitting a struct pin on a collapsed graph node. + +* Bugfix: Fixed a crash when trying to use non-supported types as Blueprint map keys. + +* Bugfix: Fixed a crash that could occur when changing a Map's value type string to vector. Map variables are properly cleared when value type is changed to an incompatible type. + +* Bugfix: Fixed a crash when compiling a Blueprint that contains a split pin in a collapsed graph. + +* Bugfix: Fixed a crash loading Blueprints that contain a Blueprint node that no longer exists in code. + +* Bugfix: Fixed a crash when using the Straighten Connection shortcut key (and some other related issues with actions done after the Context Menu is closed). + +* Bugfix: Fixed a crash when opening a Blueprint with a parent class that no longer exists. + +* Bugfix: Fixed a crash with the merge tool when the source control provide is SVN and there are gaps in the revision history. (This may still not work correctly, but it won't crash. The full fix will be covered with UE-43603) + +* Bugfix: Fixed a crash when attempting to name component with a very long name. + +* Bugfix: Fixed a crash that could happen when running Cook On The Fly server with nested struct assets. + +* Bugfix: Fixed a crash that would happen when a level in Blueprint was auto-saved. + +* Bugfix: Fixed an assertion that could occur when compiling a Blueprint with certain nodes (Select, Math Expressions, etc.) + +* Bugfix: Fixed a crash that could occur when reparenting a component Blueprint. + +* Bugfix: Fixed a crash that could happen when setting maps and sets of strings and certain structs. + +* Bugfix: Fixed a crash that would occur when passing a self node through a CustomEvent ref parameter. + +* Bugfix: Fixed a crash that could occur when adding a new Blueprint function and immediately undoing. + +* Bugfix: Fixed a crash that could occur after renaming the category of an implemented interface function inherited from a native C++ parent class in the 'My Blueprint' panel. + +* Bugfix: Fixed a crash that could occur when editing a local curve variable's default value in a Blueprint graph. + +* Bugfix: Fixed an ensure misfire in PIE exit when using Play as Listen Server Mode. + +* Bugfix: Fixed an infinite loop case in the Math Expression node. + +* Bugfix: Fixed an issue where misaligned memory access of noexport struct properties leading to incorrectly initialized values in a nativized cooked build. + +* Bugfix: Fixed an issue with broken collision shapes at runtime when cooking with the optimized Blueprint component instancing data feature turned on. + +* Bugfix: Fixed an issue with a Bitmask Enum type validation failure when serializing a Make Bitmask Literal node + +* Bugfix: Fixed an issue with log spam when compiling a Blueprint function with a local TSet or TMap variable. + +* Bugfix: Fixed an issue with broken pin wires after expanding a duplicated collapsed graph node. + +* Bugfix: Fixed an issue with invalid custom Enum type selection on member fields in the User-Defined Structure editor after a reload. + +* Bugfix: Improved context menu "whole world" algorithm to proper take into consideration localisation when searching for terms. + +* Bugfix: Fixed an issue where renaming interface input/output parameters will no longer cause broken pin links at interface function call sites in Blueprints that are currently loaded. + +* Bugfix: Fixed an issue with broken graph node pin links caused by renaming interface function input/output parameters prior to compiling the interface, but after renaming the function itself. + +* Bugfix: Fixed an inability to save after choosing a Level Script Blueprint class as the default value for a class input pin in a non-Level Script Blueprint class function graph. + +* Bugfix: Fixed an issue where Blueprints containing a 'Key Get Display Name' node will no longer be marked dirty when opening the Blueprint. + +* Bugfix: Fixed an issue where the user defined variable tooltip was not showing up when hovering over Get/Set nodes for local variables. + +* Bugfix: Fixed an issue with old versions of Blueprints being diffed accidentally showing up in Find-in-Blueprints search results. + +* Bugfix: Fixed some issue in Blueprint Diffing where properties of nodes edited in a Details panel would not show up as differences (this impacted Animation Graph nodes most heavily). + +* Bugfix: Fixed an issue in Blueprint nativization that could cause bad interface function calls to be generated. + +* Bugfix: Fixed an issue that could cause stale Blueprint instances in a hidden sub-level to spam a runtime error. + +* Bugfix: Fixed an issue that could cause a Blueprint 'mismatch' error when using 'Set' and 'Map' node. + +* Bugfix: Fixed an issue that could cause struct asset defaults to be wiped on editor reload. + +* Bugfix: Fixed an issue that could cause a packaging error when running with Blueprint nativization and no Blueprints were nativized. + +* Bugfix: Fixed an issue that removed the ability to set Blueprint object variables as 'config' variables, as you cannot set a object reference from a config. + +* Bugfix: Fixed an issue with reroute nodes so that a new output connection will propagate that type through to the node's inputs. + +* Bugfix: Fixed an issue so that 'Get Data Table Row' nodes are now compatible with DataTable variables. + +* Bugfix: Fixed an issue that could cause material parameter setting in a Blueprint construction script to fail. + +* Bugfix: Fixed an issue that could cause overlap events to fire multiple times in PIE. + +* Bugfix: Fixed an issue that would generate the nativized Blueprint plugin even if no Blueprint files were nativized. + +* Bugfix: Fixed an issue that would cause certain components to be orphaned and hidden from the component hierarchy. + +* Bugfix: Fixed an issue that could cause a level Blueprint's bound delegate nodes to not trigger. + +* Bugfix: Fixed an issue in Blueprint nativization that would cause cyclical logic (loops, etc.) to not iterate past the first iteration. + +* Bugfix: Fixed an issue in Blueprint nativization that could cause Blueprint subclasses to ignore their overridden model and default to their parent's. + +* Bugfix: Fixed an issue where non-nativized Blueprints were getting dropped from the cooked asset registry file when running with Blueprint nativization. + +* Bugfix: Fixed an issue where there would be a nativized Blueprint asset build error when there are no native code dependencies. + +* Bugfix: Fixed an issue with incorrect Blueprint graph pin value display names for user-defined enum types. + +* Bugfix: Fixed the variable 'config' setting tooltip to report the correct config file for the user to use. + +* Bugfix: Fixed an issue that could cause Blueprint variables set from a config to have their values improperly overwritten. + +* Bugfix: Fixed several issues with Switch Blueprint nodes not keeping their node and property UI in sync. + +* Bugfix: Fixed several issues where changing pawn/hud/state class from the Level editor toolbar would not work properly until the project was reloaded. + +* Bugfix: Fixed a stale class reference in interface properties that reference a Blueprint defined interface that has been recompiled. + +* Bugfix: Fixed an issue where 'Get Values' and 'Get Keys' nodes were not providing correct results for Map variables that have had values removed. + +* Bugfix: Fixed an issue where Blueprint functions that have all their return nodes pruned (ie. are not connected to anything) now have the correct output pins at call sites. + +* Bugfix: Fixed an issue where 'Movie Scene Sequence' and related code was not working when Blueprints were nativized. + +* Bugfix: Fixed an issue in nativized packaged builds that would cause default values to be lost. + +* Bugfix: Fixed 'Enum As Byte' related warnings in nativized packaged builds. 'Enum As Byte' is no longer used when nativizing Blueprints. + +* Bugfix: Fixed issues with Blueprint nativization where it didn't correctly include headers necessary for owners of subobjects, and instances where all modules needed by the generated code weren't being founds. This fixes one cause of "Cannot open include file" errors when packaging with Blueprint Nativization enabled. + +* Nodes in the blueprint editor again use their custom cursor (grab hand when hovering over a node and crosshairs when hovering over pins). + +* 'Logarithm' node added to the Blueprint Math library. + +* 'Set' pins on 'Intersection', 'Union' and 'Difference' nodes now infer their values uniformly. + +* Out of date Class Default Objects are no longer duplicated when compiling a Blueprint, reducing blueprints compilation time + +* Successive calls to Set Intersect, Union or Difference now provide correct results, previously the Set was not cleared before calculating the new result + +* 'Trace By Profile' collision functions have been exposed to Blueprints. + +* Nativize code is now more precise about dependencies, reducing the resulting executable size and compiler load. + +* Blueprints that override an inheritable component are no longer 'data only'. Blueprints with overridden components but no extra functions now load without losing data. + +* Blueprints that extend types that implement 'Needs Load For Server' or 'Needs Load For Client' now honor those functions, meaning they will not be cooked for targets that their type wants to be excluded from. + +* Delegates in nativized packaged builds correctly prevent double registration. + +* Blueprints used as a child actor class will no longer be marked dirty when compiling the class that references them. + +* When duplicating a Blueprint component, that component will now be a sibling of the duplicated node, not a child of it unless it is the root node being duplicated. + +* Duplicated root nodes will have their scale set to (1,1,1) to avoid applying the scale multiplier twice. + +* Blueprintable Components are no longer considered experimental, they have been enabled by default for several versions. + +* The ticking behavior of latent actions in components has been changed to match how they behave in actors. When the component ticks, the latent actions will now be processed at the same time, rather than happening later in the frame when latent actions for non-ticking actors and components are processed. This does change behavior, so there is a console variable (t.TickComponentLatentActionsWithTheComponent) that can be used to revert to the older behavior until affected component Blueprints that depended on the old ordering behavior can be fixed up. The cvar should be treated as deprecated; it will be removed in a future release. + +* Updated Blueprint nativization so that it generates source files compatible with 'include what you use' (IWYU). + +* Moved nativized Blueprint plugin generation to the project's 'Intermediate\Plugins' folder. + +* Removed make/break nodes from the Blueprint menu for structs that aren't marked as a 'BlueprintType'. + +* Updated marquee selection in graph editors. Ctrl dragging now inverts nodes' selection state, instead of only deselecting them (holding alt is now for pure deselection). + +* The Actor Details view will now refresh property mappings for the current Actor instances selection after a bytecode-only recompile of its Blueprint class as a dependency during reinstancing. + +* Child Blueprint class assets are now marked as dirty if its parent Blueprint class incurs a structural change. This alerts the user that updates to the Child Blueprint would need to be saved on exit. + +* We now emit C++ ctor initialization code for nested default subobjects when nativizing a Blueprint class at cook time. + +* Instanced Static Mesh transform edits are now reflected in the Blueprint editor's preview scene. + +* The editor will now raise an error at cook time after an attempt to nativize a Blueprint class that also implements a native C++ interface with a pure virtual function declaration that is not also marked up with UFUNCTION. This is because we cannot nativize a Blueprint class that does not also have an implementation of a pure virtual function inherited from the interface. + +* C++ interfaces with one or more pure virtual function declarations not also tagged with UFUNCTION are now excluded from the list of available "Implementable" interfaces in the Blueprint class editor. + +* Non-nativized child Blueprint classes will now properly override a nativized parent Blueprint class's component defaults at runtime in a nativized cooked build. + +* We will now implicitly nativize any child Blueprint class that overrides one or more BlueprintCallable functions inherited from a parent Blueprint class that is also nativized. + +* The Blueprint diff tool now reports when a component changes its type between revisions + +* Blueprints are now only dirtied if edited properties are from objects in the Blueprint's package. + +#### Core + +* New: Support added for "double" and 'fname' stat types in UFE stat export to CSV. + +* New: Pak files can now have their index encrypted with AES, preventing them from being opened by unrealpak. + + * An AES key must be provided in the project Encryption.ini, and then index encryption can be enabled in the project packaging settings in the editor. + + [REGION:note] + When either pak index encryption or signing are enabled in the Project Settings, pak ini encryption must also be enabled in order to avoid a potential security issue. All of these settings can be found in the Packaging section of the Project Settings dialog in the editor. + [/REGION] + +* New: Added "Get Component For Axis" and “Set Component For Axis” to FVector and FRotator. + +* New: Added support for -iterate for content plugins that require path remapping during cook/packaging. + +* New: Added a "CookedOnly" plugin type, for plugins meant only to be loaded in cooked games (in support of Blueprint nativization). + +* New: Added a Json Object Converter to add support for saving and loading TMap and TSet UProperties. + +* New: Absolute paths are now allowed in -UserDir= argument. + +* New: Added ability for games to use command line parameters for map overriding in shipping builds if their target.cs file defines UE_ALLOW_MAP_OVERRIDE_IN_SHIPPING macro to 1. + +* New: Added support for instanced elements in TMap and TSet properties being copied during "Copy Properties For Unrelated Objects." + + * This fixes an issue where instanced fields could lose data during recompilation of a Blueprint. + +* New: Added a new method Platform Misc "Get OS Version" that returns a string representing the raw OS version info. + +* New: All HTTP implementations now use a consistent User-Agent string (specified via the overridable function Generic Platform Http "Get Default User Agent" method). + + * Added a Platform and OSVersion string to the default value (platform=FPlatformMisc::IniPlatformName() and osver=FPlatformMisc::GetOSVersion()). + +* Bugfix: Fixed a crash with startup in the runtime asset manager when the on-disc cache already contains more data than the system is configured to use. + +* Bugfix: Fixed a crash in 'Chunk Cache Worker' function constructor. + +* Bugfix: Fixed a crash when launching "Play In Editor" session caused by missing audio data if its DDC data was not present and the audio was streamed in. + +* Bugfix: Fixed a crash when UObject can be added to GC cluster only if all of its Outers can also be added to it. + +* Bugfix: Fixed an assert with LocalExportIndex.IsNull. Now the Event Driven Loader code will properly disambiguate imports with the same name and the same outer name. + +* Bugfix: Fixed a crash when Hot Reloading caused by reinstancing UEngine objects. + +* Bugfix: Fixed an occasional crash during Hot Reload CDO reinstancing that was caused by a redundant insertion into TMap invalidating an existing reference into that TMap. + +* Bugfix: Fixed a crash when importing a Blueprint which contains a non-empty TMap with an enum class key. + +* Bugfix: Fixed a crash when Hot Reloading a project which contains a user-defined struct. + +* when hot reloading a project which contains a user-defined struct. + +* Bugfix: Fixed a crash when deserializing a TMap property item with instanced elements, where the CDO contains default element values for that property. + +* Bugfix: Fixed the use of many printf non-literal formatting strings, as these are potential security issues. + +* Bugfix: Fixed an issue with incorrect error code being returned from UnrealHeaderTool when -WarningsAsErrors and -Verbose are specified code. + +* Bugfix: Fixed an issue with the error code returned by UnrealHeaderTool when an error occurs during preparsing of headers. + +* Bugfix: Fixed a persistent stat metadata warning generated during PIE.. + +* Bugfix: Fixed an issue with FMonitoredProcess to prevent infinite loop in -nothreading mode. + +* Bugfix: Fixed an issue for runtime asset cache not invalidating files with an outdated version number. + +* Bugfix: Fixed stats warnings because each new slate loading screen thread has the same stat name, but is potentially assigned to a different thread. + +* Bugfix: Fixed an issue with CSV parser missing empty cells at the end of the string. + +* Bugfix: Fixed an issue with external plugin cooking and deployment by remapping plugin directories upon cook & deployment Tested directory structures: + + * D:\SomePluginDir + + * D:\UE4\AnotherPluginDir + + * D:\UE4\Engine\Plugins + + * D:\UE4\MyProject\Plugins + +* Bugfix: Fixed a memory leak in MallocBinned which affects the mobile platforms (Android, iOS). + +* Bugfix: Fixed a typo in comments for LODColoration in BaseEngine.ini. + +* Bugfix: Fixed the Log message in "Exclusive Load Package Time Tracker." + +* Bugfix: Fixed an issue where "log.timestamp" command would not work because it was incorrectly handled by "log" console command. + +* Bugfix: Fixed an issue where the logging system could hang when running out of disk space while flushing log and fixed unexpected concurrency assert when flushing the log buffer to disk. + +* Bugfix: Fixed a deadlock when flushing log file while it's already being flushed by a flush timer on the async log writer thread. + +* Bugfix: Fixed a memory leak when running with -nullrhi on the commandline in cooked games caused by shader resources not being destroyed. + +* Bugfix: Fixed an issue to make sure the engine is properly cleaned up on UnrealHeaderTool early exit to prevent UnrealHeaderTool hangs. + +* Bugfix: Fixed an issue to make sure that streamed-in SoundWaves get added to Garbage Collection clusters. + +* Removed dependency preloading system from sync and async loading paths. It has been superseded by the new event driven loading system. + +* Removed remaining references to AES_KEY, instead using the encryption key delegates to access the key where needed. + +* Refactored encryption and signing key access in unrealpak to make it easier to use. + +* Make content projects generate a stub executable when encryption or signing keys are specified so that keys can be embedded correctly. + +* Separate pak cache granularity from pak signing chunk size in the EDL loader. + +* Increase "Serial Size" and “Serial Offset” in FObjectExport to 64bits, to handle larger file sizes. + +* Added some validation of the class index in exportmap entries. + +* Added missing support for compiling plugins external to Engine/Plugins & Game/Plugins. + +* Disabled the 'HeartBeat' function on platforms that don't actually want to use the HeartbeatThread. + +* 'None' is now going to be properly considered by the engine as an invalid filename. + +* The editor will now collect garbage after a map is loaded to make sure any stale components or other objects that are no longer needed are destroyed. This is to make sure that these components are not resurrected by another editor operations like duplication. + +* Made sure the async log writer flushes the log archive even if there's no serialization requests to prevent situations where some of the recent requests haven't been flushed to disk + +* Reduced the code size for the generated Static Register Natives functions. + +* Disabled the garbage collector when recompiling child Blueprints, as is already done for the parent Blueprint. + +* Simplified Unreal Header Tool's code generation logic. + +* Implemented Lex "To Sanitized String" for double. + +* The function Local Player Context "Is Valid" now also checks that the player controller has a player set. + +#### Editor and Tools + +* New: UnrealGameSync now includes a workspace-specific file filter, separately to the global file filter. + +* New: UnrealGameSync now supports pop-up notification for build failures on content changes. + + * To mark a badge as applicable to users submitting content changes, add +ContentBadges=Name to the [Notifications] section of the project specific configuration file at /Build/UnrealGameSync.ini. + +* New: UnrealGameSync now allows a project to specify filters for the streams that should be displayed for fast-switching to. + + * The "Quick Select Stream List" setting in the “Options” section of the Project Settings references a depot path containing a list of strings used to filter the stream list. An option is shown to switch back to showing all available streams, if desired. + +* New: Added support for in memory packages. Helps distinguish between packages which can and can't be cooked. + +* New: Added a Blueprint function to convert a Render Texture to Texture2d. This is only available for use in the Editor. + +* New: Custom Depth can now be enabled for Foliage. + +* New: You can now color-code all of the windows in the editor in order to visually distinguish them when working across multiple branches or projects + + * You can adjust the 'Editor Window Background Color' for a subtle effect, as the default background is already a pretty dark grey: + + ![image alt text](image_40.jpg)(w:929 h:416 convert:false) + + * Or you can edit the tint in the two brushes (which sets the texture to a white default one) to get a very brazen effect: + + ![image alt text](image_41.jpg)(w:929 h:416 convert:false) + +* New: Added Data Table export/import support for TMap and TSet. + +* New: Updated the Windows platform to use the newer Vista+ style browser dialogs, rather than the older XP style dialogs. + +* New: You can now empty the text value within an FText property or pin. + +* New: Added support for .ini-driven classes to use a specific platform's config hierarchy, so that the editor on a desktop platform can read .ini settings from other platforms .ini files. + + * This will allow for NDA'd platforms to keep their ini settings in protected files, but still be editable by the editor. + + * Moved project settings for console platforms over + + * See UObject::GetConfigOverridePlatform() + +* New: Scene importing now allows for plugins to expose new scene import factory types. + +* New: Overhauled "Call In Editor" support and promoted it so it can be used on functions in any class, not just Blueprints derived from AActor: + + * "Call In Editor" can now be used on native UFUNCTION() declarations (e.g., UFUNCTION(Category=CoolCommands, CallInEditor)). + + * Blueprint declared functions can also be marked as CallInEditor (in addition to custom events), which allows you to set the category and tooltip for the buttons. + + * Now shows each function as a separate button, placed in the category associated with the function. + + * Removed the duplicate copies of properties placed in the Blutility section. + + * Prevented operating on functions that have parameters or return values, which could crash before. + + * Added a scoped transaction around "Call In Editor" execution so changes made can be undone. + + * The button strip entry is now searchable by function name or tooltip. + +* New: Added a new Details view option: "Show Hidden Properties while Playing" + + * Enabling this allows you to see every property on selected objects that belong to a simulating world, even non-visible and non-editable properties. + + * This feature is very useful for inspection and debugging, because you can see all of the internals of your Actors and Objects. + + * Be careful when changing values for properties that are not really intended to be changed at runtime. You could introduce instability or even corrupt data. + + * Note that this setting is saved for your entire project. + +* New: Sequencer additions and updates: + + * Tracks can now be prioritized based on their subscene hierarchical bias value. Higher bias values take precedence. + + * Fixed particle system restore state so that it gets the proper initial active state of the particle. + + * Added a generic past menu for Master (root) tracks. + + * Changed the time snapping interval in the toolbar UI so that it no longer additionally updates the Sequencer setting. The setting is only used to initialize the time snapping interval of the Level Sequence. + + * Added translate keys with Ctrl and Left-Right arrows. + + * Added Level Sequence Actor button in the Details panel to open Sequencer. + + * Duplicate shot now puts the duplicate on the next available row, keeping the start/end times the same. + +* New: You can now isolate/select all sections using a specific Material slot. + +* New: The FBX importer updates: + + * Now imports collision models under the FBX LOD Group. + + * Now applies the transform from FBX options only one time for the whole import. + + * When importing an FBX file from Blender, the importer now removes the root node name "armature." + + * No longer removes the socket created in UE4 Editor when using reimport. If affects only imported socket. + +* New: Added some LOD Setting options to the FBX Import Options window. Users can now specify the following Static Mesh LOD Settings Options: + + * Auto Compute LOD Distance + + * Minimum LOD Number + + * LOD number + +* New: The FBX Importer now fills two more Material Inputs (Texture only) from the FBX Material: + + * Specular Factor imported as "Roughness" + + * Shininess imported as "Metallic" + +* New: The FBX exporter can now export with the Front X-Axis. The new option is under the Editor Preferences settings. + +* New: TMaps now support editing structs as keys from within the Details panel. + +* New: The Data Table Row Editor now contains a Reset to Default control. + +* New: Properties added to the header of a Details panel group (ie. via IDetailGroup::HeaderProperty()) now have copy/paste actions exposed in the Context Menu. + +* New: Added the possibility in Slate to reset property group to their default value. + +* New: Added the possibility to perform the following actions in Save/Load Level dialog: + + * Rename + + * Delete + + * Create a New Folder + + * Show in Explorer + + * Show the Size Map tool + +* Bugfix: Fixed a crash when selecting components from an Actor's component tree and then undoing + +* Bugfix: Fixed a crash when attempting to open multiple cooked assets at once in the editor. + +* Bugfix: Fixed a crash when pressing PIE button several times before PIE session begins. + +* Bugfix: Fixed a crash that could occur during seamless travel while playing in a Play-in-Editor session with the "Use single process" option unchecked. + +* Bugfix: Fixed a crash while using the "Delete" button inside of the HLOD outliner while having a Proxy mesh opened in the Static Mesh Editor. + +* Bugfix: Fixed a crash when using import into level with .obj file. + +* Bugfix: Fixed a crash when dragging a re-import scene and there is new asset created. + +* Bugfix: Fixed a crash when creating too many LODs when importing a Static Mesh. + +* Bugfix: Fixed a crash with High Resolution Screenshot Tool that could happen when the Screen Percentage is set to a value other than 100%. + +* Bugfix: Fixed an issue with Device Output Log showing partial lines sometimes. + +* Bugfix: Fixed an issue where array properties would revert to the default values when duplicating an Actor. + +* Bugfix: Fixed an issue with Details panels becoming unusable if "Show Only Modified Properties" is enabled and there are no modified properties. + +* Bugfix: Fixed an issue so that thumbnails for Material assets now respect the "used particle system sprites flag" and show a quad instead of a sphere by default. + +* Bugfix: Fixed an issue for outdated error message instructions for how to fix being unable to launch on an iOS device. + +* Bugfix: Fixed an issue with "Save Current As" option not saving the current level and only saving the Persistent Level and then reloading everything thus causing work to be lost if editing a sub-level. + +* Bugfix: Fixed an issue with Material Instances being marked dirty when opening. + +* Bugfix: Fixed an issue with TAssetSubClassOf properties being reset on undo. + +* Bugfix: Fixed an issue that could cause the wrong Blueprint instance to be duplicated, or copy/pasted. + +* Bugfix: Fixed an issue with the Focus action in the Static Mesh Editor viewport. + +* Bugfix: Fixed an issue with Color Customization so that curve color names are "R", "G", "B", "A" instead of None. + +* Bugfix: Fixed an issue with user's setting for Texture Mip LOD size being incorrectly clamped. + +* Bugfix: Fixed an issue where lighting rig rotations were not set / saved correctly for Preview Scene Profiles. + +* Bugfix: Fixed an issue where auto-exposure values from the Preview Scene Profiles were not correctly applied + +* Bugfix: Fixed an issue where HLOD's "Override Screen Size" would not propagate on a LOD Actor directly. + +* Bugfix: Fixed an issue where the Material Slot assignment wasn't correctly restored on reimport. + +* Bugfix: Fixed an issue to prevent importing more LODs than the maximum allows for. + +* Bugfix: Fixed an issue with the FBX importer's "Front X-Axis conversion". We remove the scale of the camera and adjust the orientation of both the camera and light. + +* Bugfix: Fixed an issue with Auto Reimport "Directory to Monitor" feature. + +* Bugfix: Fixed some issues with the Import commandlet: + + * Fixed possible crash when importing FBX files. + + * Now makes sure that the imported assets are saved when there is no source control. + +* Bugfix: Fixed an issue with Static Mesh conversion from UE4 4.14 to earlier versions. + +* Bugfix: Fixed an issue with the Merge Actors Tool that was sometimes assigning wrong Material IDs to mesh sections. + +* Bugfix: Fixed an issue where the Number of Players and Dedicated Server settings for PIE would not persist correctly after Editor shutdown. + +* Bugfix: Fixed issues related to Auto Reimport: + + * Fixed a crash when attempting to import to mount points that do not exist. + + * Now allow for new assets to be created from monitored directories. + + * Settings now use a path picker when specifying the "Map Directory To" field. + +* Bugfix: Fixed an issue so that Property Editor Inline Class Filter now shows unloaded Blueprint Classes properly in the Editor. + +* Bugfix: Fixed an issue with Undo/Redo transactions of Color Grading. + +* Iterative cooking .ini setting checking improvements have been made. More to come in a future release. + +* Dependency checking performance improvements for iterative cook. More to come in a future release. + +* Panning in orbit mode now takes in account camera speed setting. + +* Pivot Painter 2 is a general purpose vertex animation toolset that comes with specialized subset of material functions to automate foliage animation. The script and material function set are more flexible, easier to use and provide an improved workflow over the first release. Additionally, a content example map ships with the editor to demonstrate how Pivot Painter's output can be referenced in the editor. + +* Added a disclaimer popup for the first time a user enters VR Mode + +* All asset properties in Details panels now have thumbnails on by default. + +* Disabled editor sounds that play when you PIE, simulate or possess the player by default. There is now a setting in the editor preferences to control this. + +* The output log should now have the same text color as other panels in the editor. + +* Removed hard coded list of thumbnails, preventing objects with valid thumbnails from showing up. Thumbnails are now shown by default. Use meta=(DisplayThumbnail=false) on a property to hide thumbnails. + +* Import data and thumbnail data are now transactional. You can now undo and redo their edits. + +* Reread in the target RHIs array every time the list of shader types is needed, instead of caching, because the user could change the settings in the editor, then click cook. + +* The Paint Fill tool has changed the way it works in Texture Weight Painting mode, it now fills the mesh with the currently selected texture weight index. + +* Limited the ability of setting up the Hierarchical Level of Detail (HLOD) system in levels which are contained as streaming levels in other assets. + +* The FBX importer now builds the Static Mesh only once when there is many LODs. + +* The section Material slot assignment is now correctly restored on reimport. + +* When swapping the Static Mesh referenced by a Static Mesh component, we now just clean up the Material Override that exceed the Static Mesh Material array size, instead of clearing all overrides. + +* When using the Full Scene Importer the "Scene Import" data asset can now specify a different source file for reimport. + +* Data pin style preferences are now saved on Editor shutdown. + +* The "Fixup Redirects" commandlet now ensures that files that are marked for delete are correctly submitted to source control. + +* The "Resave Packages" commandlet will now submit files that are marked for delete. + +* Blocking volumes will actually be added to the level when placed via the "Place Actor" command instead of generating warnings. + +* Values that are directly entered for float properties with a specified Delta value will no longer snap to the nearest delta when losing focus. + +* Actor components can now be scaled to negative values using the transform gizmo. + +* Map properties now fully support customized property types used as keys. + +* When deleting an Actor, we now display the name of the referencers. + +* Using the Convert Actor feature now won't change the Actor level. + +* Primitive Statistics window will now properly update itself when adding new Levels. + +* Optimized the lightmap UVs generation to speed up the Static Meshes import flow when packing the UVs into higher resolutions. + +##### Content Browser + +* New: Added "Resave All" functionality to Content Browser folders. + +* New: Added a way to view/copy a list of references (including those that aren't loaded) to the Reference Viewer. + +* New: Importing CSV files will now show the name of the CSV file in the import dialog. + +* New: Added the ability to auto resize column in "Column View" by double clicking column splitters + +* Bugfix: Fixed an issue where folders wouldn't be removed from the Content Browser when deleting them. + +* Bugfix: Fixed an issue with the Reference Viewer where it only ever used the default thumbnail. + +* Bugfix: Fixed some issues for gathering cached asset dependency data. + + * We no longer load dependency data that doesn't have the correct package name. + + * We no longer populate the dependency results when "Gather Depends on Data" is set to false. + +* Bugfix: Fixed an issue that prevented textures from updating correctly if a source texture with the same name as a texture asset is imported from a location that differs from the asset's original source image. + +* Bugfix: Fixed an issue where the Force Feedback "Play" and “Stop” icons weren't rendered correctly and would only be displayed when hovering over the asset or when the asset is currently playing. + +* Bugfix: The Content Browser file path will now update correctly if it is pointing to a path that is deleted through the Sources Panel. + +* Bugfix: Duplicating an asset will correctly name it if there is another one of the same name. + +* Moving a newly-created asset before saving it will no longer save an empty package in the asset's original location. + +* When reimporting multiple assets, the "Yes to All" and "No to All" dialog options will prevent future reimport dialogs from appearing for the same asset type in the same operation. + +* Improve visual of "Column View" in Content Browser. + +##### Cooker + +* Bugfix: Fixed an issue with the rebuild lighting commandlet not checking out files correctly. + +* Bugfix: Fixed an issue where running the same DLC profile created by the Mobile Patching Wizard would increase HTTP chunk size. + +* Bugfix: Fixed an issue with the cooker always cooking "All Maps" even when a single map was specified on commandline. + +##### Foliage + +* New: Added the Show Flag "Foliage Occlusion Bounds" in the Advanced menu to see the bounds generated by the occlusion tree. + +* New: When moving a foliage asset to a new Level, you will now be prompted to save the Foliage Type as an asset if it's a local asset. + +* New: Improved the Foliage painting algorithm to properly support Random Pitch/Yaw when the setting "Collision with World" is enabled. + +* Bugfix: Fixed a crash that occurred when moving the mouse over certain content while in Foliage mode. + +* Bugfix: Fixed an issue that cause foliage thumbnails to incorrectly be duplicated if many of them are onscreen at once. + +* Bugfix: Fixed an issue where removing a Foliage Type wouldn't properly refresh the Details panel. + +* Bugfix: Fixed an issue where the foliage location would shift when using undo/redo transactions. + +* Optimized the occurrence of rebuilding the occlusion tree when performing actions in the editor. + +##### Landscape + +* New: We now automatically fill Landscape with the first created Landscape's Layer Info object. + +* New: Added sorting to Landscape Target Layer tabs. You can now sort by Material definition (which is the default one), alphabetical, or custom a using drag-and-drop operation. + +* New: Added a visibility toggle to only show the used Target Layers by the loaded components. + +* Bugfix: Fixed a crash when changing multipole Landscape Blend Layer nodes from Weight blend to Height blend. + +* Bugfix: Fixed an issue with user Landscape shortcuts not working in the Level Viewport. + +* Bugfix: Fixed an issue when performing an Undo action would delete the newly created Landscape and return back to the new Landscape window. + +* Bugfix: Fixed an issue where Landscape holes (visibility mask) was causing NavMesh problems at the borders of the Landscape component. + +* We have improved when a Level will be marked as dirty when manipulating a Landscape Spline. + +* The Landscape tools Material synchronisation has been updated between game thread and render thread. + +* When adding a new Component, if a Landscape info object exists it will determine which one is used based on its neighbors. + +##### Material Editor + +* Bugfix: Material Custom nodes that contain "tab" characters will now correctly display tab characters after copy/paste. + +##### Matinee + +* Bugfix: Fixed an issue with how tooltips display when using a Material Function in your Material. + +##### PhAT + +* Bugfix: Fixed "Multiple Values" being displayed in Body Setup properties when single bone has multiple bodies + +##### Sequencer + +* New: Added the ability to specify additional Event Receivers for Level Sequence Actors. + +* New: Event tracks can now be defined to trigger events at the start of evaluation, after objects are spawned, or at the end of evaluation. + +* New: Added the ability to retrieve bound objects from Blueprint. + +* New: There have been improvements to the Binding overrides. + + * Added the ability to override spawnable bindings. + + * Added the ability to override bindings in sub Sequences. + + * Deprecated "Get Sequence Bindings" node in favor of "Get Sequence Binding", which is more robust, and provides a better UI/UX for selecting single bindings + + * Added Drag/Drop support for Binding overrides. + +* New: Added the ability to specify Event Receivers on Event Tracks. + + * These are defined by right-clicking on the Event Track in the Sequencer tree, and adding Event Receivers. + + * Such objects must be defined within the Sequence hierarchy (as well as parents, children, grandchildren etc). + +* New: Added a reworked, more generic property path handling system in the Sequencer object change listener. + +* New: Unlocked the Cine Camera Post Process Depth of Field to use options other than CircleDoF. + +* New: "Pre Roll" and “Post Roll” are now exposed at the section level for all sections. + +* New: Enabled "Use Custom Start Frame" and “Use Custom End Frame” when rendering a single shot from the menu. + +* New: You can now set the fade color in the Track display. + +* New: Audio row heights are now also resizable by dragging on the bottom end of the track lane in the track area view. + +* New: Sequencer now re-evaluates when starting PIE or Simulate. This can be disabled with "Bind Sequencer to PIE" and “Bind Sequencer to Simulate” in the Play-in-Editor Advanced settings. + +* New: Split "Snap to the Dragged Key" option into two options, "Snap to the Pressed Key", and "Snap to the Dragged Key". + +* New: Added a loop selection range. If there is no selection range, loop mode is restricted to loop or no loop. + +* New: Added hotkeys to set the selection range to the next and previous shot (page up, page down). Also, added hotkey to set the playback range to all the shots (end). + +* New: You can now set sequencer audio components bIsUISound to false so that they don't continue playing when the game is paused. + +* New: Added an option to instance sub sequences when creating a Master Sequence. + +* New: Notify streaming system prior to Camera cuts by default. To enable, users will need to enable the Pre Roll section of the Camera cuts for the streaming system to activate prior to cutting to cameras. + +* Bugfix: Fixed a crash when selecting keyframes in the viewport. + +* Bugfix: Fixed a crash with Sequencer Recorder when clearing properties to record. + +* Bugfix: Fixed an issue where tick prerequisites were not being set up for Actors streamed in from a streaming Level. + +* Bugfix: Fixed an issue where Sequencer was animating objects from the wrong world. + +* Bugfix: Fixed an issue with event parameter structs being able to be garbage collected, resulting in NULL structs potentially being written out. + +* Bugfix: Fixed an issue with animation looping in Sequencer. + +* Bugfix: Fixed an issue with Sequencer Recorder to fix duplicate components getting recorded. + +* Bugfix: Fixed an issue with FBX import with camera and light animation key imports. + +* Bugfix: Fixed an issue with autokey not setting a keyframe for Slate color with the specified color. + +* Bugfix: Fixed an issue for filtering to include Child nodes. + +* Bugfix: Fixed an issue where the Sub Track node deletion so that all sub tracks aren't deleted, only the row being requested. + +* Bugfix: Fixed an issue to invalidate expired objects when Blueprints are compiled. This fixes Actor references to now handle sections that need to have their GUIDs updated (ie. attach tracks). + +* Bugfix: Fixed an issue so that when finishing a scrub, playback status is now correctly set to stopped rather than set to a stepping state. + +* Bugfix: Fixed a missing command binding alt-r to record selected objects into sequencer. + +* Bugfix: Fixed an issue to Filter hidden functions, which fixes a bug where the field of view property for a cinematic camera appears to be animatable,. It should be hidden just like it is in the property editor. + +* Added a warning when Sequencer tries to write to properties that have changed type. + +* Sequencer templates are now always regenerated on load + +* Level Sequence frame snapshots now take account of fixed-frame interval offsets, and overlapping shot sections on the same row. + +* We now convert Linear Color to Color for fade to get the correct fade color in viewport. + +* Audio waveforms now show peak samples with smoothed RMS in the center. + +* Set max tick rate when in game if force fixed interval playback is enabled. + +* Cache player fade state so that restore state will return the values to the pre animated state. + +##### Source Control + +* Bugfix: Fixed an issue with Git plugin to update the status on directories hotfix. + +* With the Git plugin, use use asynchronous "MarkForAdd" and "CheckIn" operations for the initial commit. + +* Allow binary files in Git stored via git-fat, git-lfs, etc to be diffed. + +##### Static Mesh Editor + +* Bugfix: The camera position now stays in place after reimporting from inside the Static Mesh Editor. + +##### Traps + +* Subversion binaries have been updated to 1.9.5. They should no longer crash when used. + +##### VR-Editor + +* New: Improved functionality for the VR Mode: + + * Improved the look and feel of the rotation gizmo handles while in VR Mode. + + * Improved interaction for painting terrain, foliage, and mesh painting. + + * Improved gizmo handle animations. + +* New: VR Mode is now bound with the Editor Sound settings. + +* New: VR Mode motion controllers now have collision when in simulate. + +* Bugfix: Fixed VR Mode selection now to respect a component's "Is Selectable" state. + +* Bugfix: Fixed an issue with not being able to open a project in the Project Browser with VR Mode auto-entry enabled and the HMD active. + +##### Windows + +* New: Custom Depth can now be enabled for Landscapes + +* Bugfix: Fixed an issue with Landscape spline segment splitting when using streaming levels. + +* Bugfix: Fixed an issue with Landscape painting in orthographic viewports when the painted area's Z value was below 0. + +##### World Browser + +* Bugfix: Fixed an issue when moving a sublevel in World Composition browser does not appear in Undo History. + +##### World Outliner + +* New: Actors in the World Outliner will now bring their children with them when moved into a newly created folder. + +#### Gameplay Framework + +* New: Added an option for components to opt out of physics impulses on damage using "Apply Impulse On Damage". + +* New: Exposed component's "Ignore Radial Impulse" and “Ignore Radial Force” flags to Blueprints. “Ignore Radial Impulse” is now properly respected when applying impulse to relevant movement components. + +* New: The Player Controller's "Should Perform Full Ticket When Paused" can now be set from Blueprints and the Details panel. + +* New: Spawn Sound and Force Feedback Blueprint nodes now have a "Auto Destroy" pin that can be set to false to allow the component to be reused after the sound/pattern complete. + +* New: The number of buttons that can be used by Raw Input is now 20. + +* New: Fields of Attribute MetaData are now editable. + +* New: In the Ability System, the "Cancel Ability" has been exposed to Blueprints. + +* New: For Cameras, support has been added for specifying a default aspect ratio and whether or not to constrain to it in a Camera Manager subclass. + + * Normally the information would come from a Camera component, but this is useful when using custom view logic that doesn't source from a Camera component as the view target. + +* New: Added "​On Component Collision Settings Changed Event" delegate to Primitive Component. Fixed Skeletal Mesh Component not calling Super implementation for “On Component Collision Settings Changed”. + +* New: Refactored Character Movement Component determination of net send rate when combining moves into a virtual function Get Client Net Send Delta Time. Added configurable values to Game Network Manager under ​[/Script/Engine.GameNetworkManager] in BaseGame.ini: "ClientNetSendMoveDeltaTime", “ClientNetSendMoveDeltaTime”, “ClientNetSendMoveThrottleAtNetSpeed”, “ClientNetSendMoveThrottleOverPlayerCount”. + + * This replaces the values that were hardcoded in the network code for characters and enables easier configuration of client send rates for movement. + +* New: We've increased Pawn location replication precision to 2 decimal places from 0. Prevents replicated pawns from being inside geometry by a large amount. Removed CVars controlling CharacterMovement proxy shrink amount and made those instanced properties on the component. + +* New: Added a flag to Character Movement Component to determine whether or not character should Sweep while using "NavWalking", instead of relying on Generate Overlaps flag. + +* New: Added "Apply Gravity While Jumping" flag to Character Movement Component. This helps to reduce Framerate Dependent Jump Height issues when disabled, but raises jump height. This is disabled by default. + +* Bugfix: Fixed a crash due to null World Settings when rendering a thumbnail. + +* Bugfix: Fixed a crash when opening Blueprint after adding a component to native class referenced by a Child Actor Component. + +* Bugfix: Fixed several issues with renaming or deleting Gameplay Tags from the Gameplay Tag Project Settings page. + +* Bugfix: Fixed an issue when calling "Set Visibility" or “Set Hidden In Game” all children of the component will now properly be reconsidered as to whether they should render. + +* Bugfix: After duplicating an Actor, components added to the source instance will now have the correct position in the duplicate. + +* Bugfix: Ability actions can now be properly bound to input components. + +* Bugfix: Construction scripts will no longer be incorrectly rerun on Actors in a level that was hidden and then later made visible again. + +* Bugfix: Fixed an issue warning about invalid world content when loading maps with child Actor components in it. + +* Bugfix: Fixed cases where built lighting on child actors could be lost when loading a level. + +* Bugfix: Fixed case where child actor template was not cleared when setting child actor class to null. + +* Bugfix: Fixed issues with seamless travel in PIE and sub-levels shared between different Persistent Levels. + +* Bugfix: Fixed issues where Child Actor Component's "Parent Component" would be null on the client. + +* Bugfix: Fixed accumulated forces in Character Movement applied incorrectly when movement mode or active state changes. + + * Added ​"Clear Accumulated Forces” + + * "Add Force" and related functions now avoid adding the force if in Movement Mode is set to "None". When ticking in "None", forces are cleared so they don't pile up until the next valid movement mode. Forces are also cleared if the updated component changes or when the capsule simulates physics. + + * "Deactivate" implemented to stop movement and call “Clear Accumulated Forces”. + + * "Clear Accumulated Forces" now also clears pending launch velocity. Exposed “Clear Accumulated Forces” to Blueprints. + + * "Apply Accumulated Forces" does not call ”Clear Accumulated Forces”, since that would prevent pending launch. + + * "Add Force" and “Add Impulse” now also check that character movement is active (not deactivated, able to tick). + + * "Simulate Movement" handles pending launch and clears forces regardless of whether it's simulated proxy. + + * Inlined Actor Component "Is Active" for performance. + +* Bugfix: Fixed characters sliding when landing on slanted surfaces or stairs, when aggressive "Perch" settings could cause a line trace (from the center of a capsule) instead of capsule trace and thereby screw up the floor distance checks. + +* Bugfix: Fixed the case of people moving a Character mesh in Begin Play rather than in the Editor or Construction Script and not having the mesh offset reflected correctly in network games. + + * Added function "Cache Initial Mesh Offset" to cache initial mesh offset, used as the target for network smoothing. This takes location and rotation params so you can be explicit on the values, in case you try to change these during network smoothing, where reading the relative offsets would be skewed. + + * Added a call to this function from Begin Play in addition to the existing call from "Post Initialize Components", and exposed this to Blueprints as well for custom changes to mesh offset at runtime. + +* Bugfix: Fixed an issue with Projectile Movement Component continuing to simulate (and generate hit events) after it is deactivated during simulation. "Has Stopped Simulation" function now checks if “Is Active” is false. + +* Bugfix: Fixed an issue with "Get Welded Bodies" so that it properly returns Skeletal Bodies, instead of the default body for Skeletal Mesh Components. + +* Bugfix: Fixed an issue with infinite jump on client when Jump Max Hold Time is not 0. + +* Stop dynamic force feedback when initiating Actor is destroyed. + +* Clarified the tooltip on the "Inverse Lerp" function. + +* In the Movement Component "Deactivate" calls “Stop Movement” to clear cached velocity. + + * It was undesirable that reactivation many seconds or frames later would restore a stale velocity. + +* The "Collision.ListComponentWithResponseToProfile" command now includes pending kill objects. Use this to inspect collision responses between objects in a game world. + +* Optimized the Math Library "Get Forward Vector" (converts Rotator to forward direction). This way we avoid building a matrix, and avoids 1 more SinCos call. + +#### Learning Resources + +##### Sample Content + +* New: ShooterGame now supports dedicated servers on PC, Mac, and Linux! + +#### Localization + +* New: Improvements to culture switching and LocRes files. + + * LocRes files now de-duplicate translations when they're generated, which can result in smaller LocRes files. + + * The localization compilation step now produces a LocMeta file, which contains meta-data specifying the native culture during compile, and where the native LocRes file can be found. + + * Changing cultures now loads the native localization data prior to loading the non-native translations to ensure that translations are always applied to a consistent base. + + * The "leet" culture (available when localization testing is enabled) is now always applied against the native translation, and correctly restores non-translated text when switching away from the "leet" culture. + + * "-culture=leet" now works correctly on the command line ("-leet" also works). + + * LoadLocalizationResourcesForCulture is no longer called multiple times during initialization of the text localization manager. + +* New: Updated Fast Decimal Format to support the correct 0-9 numerals for the current locale + + * These are typically still Latin, but Middle Eastern languages have some variants. + + * This addresses an inconsistency between FText formatting of numbers and dates (since numbers always used Latin, but dates used the culture correct numerals). + +* New: Split the monolithic culture concept in UE4 + + * UE4 has historically only supported the concept of a single monolithic "culture" that applied to both text localization and internationalization, as well as all asset localization. Typically the "culture" was set to the "locale" of the OS, however that could be undesirable or incorrect on platforms (such as newer versions of Windows) that have a distinct concept of "language" (for localization) and "locale" (for internationalization). + + * This change splits the concept of "culture" into "language" and "locale", and also adds the concept of "asset groups". The language is now used to work out which localization we should use, and the locale is used to control how numbers/dates/times/etc are formatted within our internationalization library. + + * Asset groups expand on the language used by asset localization and allow you to create a group of asset classes that can be assigned a different culture than the main game language. A typical use-case of this would be creating an "audio" group that could, for example, be set to Japanese while the rest of the game runs in English. + + * If your game doesn't care about the distinction between language and locale, and doesn't need to use asset groups, then you're able to continue to use "culture" as you always have. If, however, you do care about those things, then you'll likely want to avoid using the "culture" directly (as it's now a very aggressive setting that overrides all others), and instead favor using language/locale (games will typically treat these as the same) and asset groups as separate concepts (both in settings, and in your in-game UI). + + * The language or locale for a game can be controlled by settings within the "Internationalization" section of your configs (this would typically be set in your Game User Settings config, in the same way that "culture" works), eg) + + [Internationalization] + language=fr + locale=fr + + * The asset groups for a game can be controlled by settings within the "Internationalization.AssetGroupClasses" and "Internationalization.AssetGroupCultures" sections of your configs (the asset group class definition would typically be set in your DefaultGame config, and the cultures the groups use would typically be set in your Game User Settings config), eg) + + [Internationalization.AssetGroupClasses] + +Audio=SoundWave + +Audio=DialogueWave + [Internationalization.AssetGroupCultures] + +Audio=ja + +* Bugfix: Fixed an assert that could trigger when an IME composition is aborted during widget destruction. + +* Bugfix: Fixed a crash that could happen if a config was loaded while the Gather Text commandlet was running. + +* Bugfix: Fixed text namespaces being treated as case-insensitive when exported to JSON manifests and archives. + +* Bugfix: Fixed text format history being clobbered by reference collection. + +* Bugfix: Fixed the pluralization of the decorator text during drag-and-drop operations. + +* Vastly reduced the number of allocations that happen when rebuilding text at runtime. + +#### Networking + +* New: Network dormancy efficiency has been improved greatly (if you have large number of dormant actors, they now will have less overhead). + +* New: Network consider/relevancy code is now also much more efficient. Overall, expect a 20+% improvement in performance if you have lots of Actors in the network Actor list. + +* New: Adaptive network update frequency logic is now on by default. This should improve network performance for games that weren't opt'ing in to this feature. + + * Net.UseAdaptiveNetUpdateFrequency is now 1 by default. + +* New: Replays now support network relevancy. + + * All connections are considered when determining if an Actor is relevant. + + * Enable by setting demo.UseNetRelevancy to 1. + + * Override cull distance with demo.CullDistanceOverride. + +* New: Added more info about the connection to logs when you see "FRepLayout::UpdateChangelistHistory: History overflow, forcing history dump" message. + +* New: Updated OnlineSubSystemNull to properly account for game state and "Allow Join In Progress". + +* Bugfix: Fixed a crash that could occur when updating unmapped objects. + +* Bugfix: Fixed an issue with IPAddressBSD validation when setting IP from string. + +* Bugfix: Fixed a memory leak in network drivers. + +* Bugfix: Fixed an issue with syncing of non-contiguious UENUMs over networks. + +* AActor "Pending Net Update" has been deprecated. Please use “Pending Net Update” that is now on FNetworkObjectInfo (obtained by calling “Get Network Object Info). + +* UNetDriver "Get Network Actor" is now deprecated. Use UNetDriver “Get Network Object Info” instead. + +* Disabled net.PartialBunchReliableThreshold for replays (we don't need to worry about bunch fragment sizes since there is no packet loss for replay connections). + +#### Online + +* New: Steamworks integration has been updated to support version 1.39, including updated steam controller support! + +* New: Web Browser module no longer directly depends on Online Subsystem plugins. + + * It uses the Online Engine Interface shim to explicitly depend on the engine and will use Online Subsystem features when that module is optionally added. + +* New: Added a new overload for Online Session "Find Friend Session" in the session interface that can retrieve sessions for multiple friends. + +* New: Sending and accepting invites on dedicated servers on Steam is now supported. + +* New: Updated OpenSSL libraries to use BCrypt on Windows in order to reduce memory allocations. + +#### Other + +* New: Added a "Buffering" media player event. + +* New: The Plugin Browser now supports customizations to allow for context-specific plugin creation. + +* Bugfix: Fixed a crash with Media Assets in "Tick Video" after media player is garbage collected. + +* Bugfix: Fixed an issue to prevent the default cooked sandbox from trying to read non-cooked assets. + +* Bugfix: Fixed a message router thread not being woken up right away on shutdown.Crashreporter uploads/downloads crash data from AWS + +* Search button is disabled after clicking it once to prevent accidental double-clicks. + +* Reading the config hierarchy for TVOS now matches IOS to get the correct bundle id when packaging a project + +#### Paper2D + +* Bugfix: Custom tile maps using collision can now be created at runtime on any platform without crashing. However on iOS/Android/HTML5 only the boxes and spheres used in the per-tile collision shapes have effect; arbitrary convex collision (e.g., slopes or other triangle-based collision) will not cause collisions or overlaps until support for PhysX runtime cooking is added to these platforms. + +* Bugfix: The Paper2D flipbook editor now shows the current frame correctly when the animation timeline is longer than the editor window and the scroll bar is moved to the right. + +* Bugfix: Paper2D flipbook editor now shows the correct number of frames; previously, it was one frame short. + +#### Physics + +* New: Added sprite to Physics Thruster Component (previously this was only available on Physics Thruster Actor). + +* New: Exposed "Set All Physics Angular Velocity" to Blueprints. + +* New: Added finer-grain PhysX stat information that is available by using "stat physxtasks". + +* New: Added the ability to specify whether a ragdoll is in the sync or async scene with "Use Async Scene". + +* New: Changed default contact-gen method to PCM. This is the default in PhysX 3.4. + +* New: Added "Is In Air" method to Vehicle Wheel. + +* New: For the Wheeled Vehicle Movement Component, the Mass dependent wheel properties now update when mass is updated. + +* New: Created "Add Force At Location Local" function to allow component space forces. + +* New: Added a new Physics settings "Enable Stabilization". Stabilization can help stacks of simulated bodies to come to rest. + +* Bugfix: Fixed a crash in anim dynamics when a world was not valid during pre-update. + +* Bugfix: Fixed a crash when saving sub-levels that don't currently have a correctly initialized scene. + +* Bugfix: Fixed an issue with incorrect slider for "initial Average Frame Rate" physics setting. + +* Bugfix: Fixed an issue with physics constraint warning messages in Message Log. These now list Component/Actor name correctly. + +* Bugfix: Fixed an issue with editing Box and Capsule collision primitive rotations by storing rotation as a Rotator rather than Quaternion. + +* Bugfix: Editing collision profiles in Editor Preferences no longer discards edits. + +* Bugfix: "Find Closest Bone" function no longer ignores the “Required Physics Asset” option. + +* Bugfix: Fixed an issue teleport not working for physical animation component. + +* Bugfix: Fixed an issue incorrect inertia tensor computation for cubes, which was being doubled. + +* Bugfix: Fixed an issue with kinematic body interpolation in substepping causing invalid raycasting, sweeping, or overlapping. + +* Bugfix: Physics Constraint component now works as expected when its target is a Child Actor component. + +* Bugfix: Fixed an issue with collisions between components with CCD enabled having unreliable behavior. + +* Bugfix: Fixed an edge case where generating collision data could cause the engine to hang in an infinite loop. + +* Bugfix: Fixed a regression with Raycasts against Capsules returning invalid hits. + +* Bugfix: Instanced Static Mesh now properly creates physics state when set to Stationary. + +* Bugfix: Fixed a memory leak caused by keeping PhysX shapes in memory after they are no longer being used. + +* Expanded self-collision culling for clothing by providing a scale to tweak the culling queries. This makes a tradeoff between performance and accuracy. + +* Added a guard against infinitely thin geometry, which fixes some NANs. + +* Performance improvements to Anim node "Rigid Body". + +* Physics performance is improved by skipping the update of kinematic bodies when they haven't moved. + +#### Platforms + +* New: Add logging for the NUI GPU reserve so we can see when it's enabled and disabled. + +* New: Exposed JAVA_HOME setting in Android SDK Project Settings on Mac. + +* New: Added "Platform Handle Splash Screen" to deal with hiding splash screen properly on Startup Movies. + +* New: Implemented support for new controllers (Xbox Wireless, SteelSeries Stratus XL, PS4). + + * Note: there are two implementations for Xbox Wireless due to differences in firmware. Firmware before 3.1.1221.0 does not use standard mapping which you can enable by setting the Android.OldXBoxWirelessFirmware CVar to 1 (defaults to new firmware). + +* New: Added support for "r.ScreenPercentage" on mobile allowing the game scene to be rendered at lower resolution than the UI. Requires MobileHDR to be enabled. + +* New: On-screen warnings now appear when a mobile shader permutation required to correctly render the current scene's lighting setup has been disabled in Project Settings. + +* New: Made some big DeviceProfile changes, particularly for the protected platforms. + + * Changed the "type" of some DPs from WindowsNoEditor, etc to Windows. It should be a platform, not a random string. + + * With that change, the platform can be used to save out protected platform DP .ini files to subdirectories, maintaining secrecy + + * Added Config/[PlatformName]/ConfidentialPlatform.ini files so that the DP loading code knows to look in their directories for DPs. See FGenericPlatformMisc::GetConfidentialPlatforms() for more information. + +* New: When uploading a HTML5 project to AWS S3, it now supports "signature version 4" authentication and better error message feedback on upload failures. + +* New: Added "use fixed timestep" setting option for HTML5 builds (This has been separated from Engine > General Settings - Framerate). + + * This is slightly different to "Smooth Framerate" and “Fixed Framerate”. + + * NOTE: Fixing the timestep does not guarantee the actual framerate. Calculations based on delta time may be adversely affected by this. + +* New: Added iOS/Android support for new Audio Mixer. + +* New: "Does Save Game Exist" will now show a message if the save data is corrupt. + +* New: Initial support for voice chat in the Android platform. To use enable the Voice module in DefaultEngine.ini, in the level bp create a session, and in project settings > Platforms > Android > Advanced APKPackaging, check the setting 'Add permissions to support Voice chat (RECORD_AUDIO)'. After this create a multiplayer game between two android devices. For more information check pull request #2894. + +* Bugfix: Fixed a crash with mobile feature level preview when the Low Quality Lightmap shader permutation is disabled. + +* Bugfix: Fixed a crash in clothing on platforms that don't support clothing. + +* Bugfix: Fixed a crash when backgrounding or sleeping on iOS Metal devices. + +* Bugfix: Fixed a crash with UIImagePickerController. + +* Bugfix: Fixed an issue with executable path for stripping Android debug symbols (handle non-Windows properly). + +* Bugfix: Fixed memory reporting for Uniform Buffers in "stat rhi". + +* Bugfix: Fixed a slow memory leak in FD3D12UniqueDescriptorTable. + +* Bugfix: Fixed rendering of batched Slate primitives in D3D11.x. + +* Bugfix: Fixed an issue with S3 public link generator for "Shipping" builds filename. + +* Bugfix: Fixed an issue with iOS IDFV string allocation. + +* Bugfix: Fixed UPL processing on iOS plist files. + +* Bugfix: Fixed network byte ordering for iOS multiplayer sessions. + +* Disabled the game analytics anonymous usage data sent to Epic on the console platforms. + +* Save 66MB of memory by disabling the unused default SHAPE heap in XAudio2. + +* Stop the audio thread from using the 7th CPU core as it can be pre-empted and not get enough execution time. + +* Add -distribution when iOS distribution Packaging. with IPhonePackager.exe. + +* Changed mouse cursor to be always visible when running in Mobile Preview. + +* Refactored memory allocation functions (BinnedAllocFromOS) on all platforms. Made Binned2 malloc work on Linux. + +##### All Mobile + +* Bugfix: Fixed a crash in mobile patching utilities mount method. + +* Bugfix: Fixed an issue with the shader compile for Landscape on platforms below SM4 feature level. + +##### Android + +* New: Bad package names are now detected and APK generation is stopped with a proper error message instead of failing during Java compiling. + + * Package names with fewer than 2 segments are not allowed (e.g., "myproject" is not allowed, but “com.myproject” is legal). + + * Only alphanumeric characters and underscore are allowed in the package name (Note: hyphens in the project name will be converted to underscores, but any other hyphens need to be corrected in Android project settings). + + * All segments must start with a letter; if your project name starts with a letter you will need to replace the [PROJECT] part of the package name in Android project settings. + + * Reserved Java keywords may not be used as the full segment; appending an underscore or other legal characters will fix this. + + * Segments may not be empty (e.g. "com..myproject" is not legal). + +* New: Larger OBB files embedded in APK are now allowed by bypassing Asset Manager. + +* New: We've implemented a first pass of Google Cloud Messaging plugin. This is considered an experimental feature for this release. + +* New: Added missing key codes for keyboard input (@ and #). + +* New: Added a drop-down with some common console commands on Android to the console dialog. + +* New: Patches ant.bat to handle long command line issue on Windows. + + * Copies original ant.bat to ant.orig.bat and writes a new ant.bat which uses subst with an unused drive letter to shorten paths). + + * Note: you can edit the generated ant.bat if you need to change the drive letter used; the editor will not replace it if ant.orig.bat is found. + +* New: Editor now checks to make sure that at least SDK Android-23 is selected and installed. There will be an error message if an earlier version is installed. + +* New: Updated AAR handling to deal with versioning, subproject dependencies for resources, and scope (ignore test). + +* New: Added "Game Activity On New Intent Additions" section to Android Unreal Plugin Language (UPL). + +* New: Added support for using native virtual keyboard with Slate widgets instead of the dialog currently used for text input. + + * Events are triggered when the virtual keyboard is shown and hidden. + + * The show event includes the area of the screen that is covered by the virtual keyboard. + + * This feature is exposed in the Android Project Settings as an experimental feature checkbox. + +* Bugfix: Fixed a crash that could happen when closing the Android web browser. + +* Bugfix: Fixed an issue to handle spaces in ANT_HOME path in generated ant.bat patch. + +* Bugfix: Fixed an issue with application hanging on returning from the lockscreen if orientation is Landscape. + +* Bugfix: Fixed an issue to correct the log warning about Target SDK and permissions. + +* Bugfix: Fixed an issue with Launch On when multiple architectures are enabled in the project. + +* Bugfix: Fixed an issue with ad banner location on Android 7.0 devices. + +* Bugfix: Fixed some documentation errors in UnrealPluginLanguage.cs. + +* Bugfix: Fixed the executable path for stripping Android debug symbols for non-Windows platforms. + +* Bugfix: Fixed an issue with password hiding in input dialog. + +* Bugfix: Fixed an issue with EGL linking issues for ARM64 libraries. + +* Bugfix: Fixed an issue to save and restore texture filtering for movie playback in all cases. + +* Bugfix: Fixed an issue with Mac and Linux install and uninstall scripts if ANDROID_HOME is not set. + +* Bugfix: Fixed an issue with ShowLoginUI interface change in Game Circle plugin. + +* Bugfix: Fixed an issue with HTTPChunkInstaller texture format checks and missing #define warning. + +* Bugfix: Corrected AndroidManifest.xml required features for "Daydream and Cardboard" option when GoogleVR plugin enabled. + +* Bugfix: Fixed an issue to prevent inserting extra permissions into AndroidManifest.xml multiple times from Project Settings. + +* Bugfix: The correct APK file name is now used when launching from editor for Android. + +* Bugfix: Fixed issues with experimental keyboard. + + * Ensure the local scope ScreenRect passed into "On Virtual Keyboard Shown" in AndroidJNI is captured by value instead of by reference. + + * Moved ShowVirtualKeyboardInput's "Keyboard Showing" early-out checks into the UI thread task. This enables the keyboard to continue showing when changing focus between multiple Editable Text Box widgets. + +* Bugfix: Fixed an issue with locations on non-ARMv7 GoogleVR libraries so that it is properly filtered by active architecture. + +* Bugfix: Fixed an issue to properly restore state for Android devices not using separate context for movie playback. + +* Bugfix: Removed an obsolete warning with Java 1.5. The java.source and java.target are now set to 1.7. + +* Only disable Java console command receiver for Shipping builds. + +* Build configuration is passed to UPL for access during packaging as $S(Configuration). + +* Reenabled GooglePlay for ARM64 now that it doesn't crash. + +* Changed Gear VR installLocation to auto as now required by Oculus. + +* Rebuilt ICU libraries for Android with timezones enabled and updated build scripts. + +* Android media player now pauses and resumes with application state. + +* "Is Packaging For Daydream" only returns true if GoogleVR plugin is enabled. + +##### HTML5 + +* New: Emscripten toolchain has been upgraded to 1.37.9. + + * Web assembly + + * WebGL 2 + +* New: There has been an update to GameX template. + + * Multiple (parallel) downloads with progress percentage updates. + + * Test for wasm and WebGL 2 capabilities. + +* New: Updates to python build scripts. + +* New: Configurable .ini settings have been exposed to the editor. These can be found in Project Settings > Engine > HTML5. + +* New: Added support for emscripten "-pre-js" and “-post-js” option when building for HTML5. + +* New: Added support for WebGL 2 shader to turn on Instance Static Mesh Vertex Factory. + +* Bugfix: Fixed an issue with AWS S3 shareable link for shipping builds. + +* Bugfix: Fixed some issues with WebGL 2 shaders. + +* Bugfix: Fixed an issue with HTML5 plugin when Blueprint projects are promoted to code projects automatically. + +* The recommendation from emscripten developers is to use "-separate-asm" option for asm.js builds. + +* Added many new UE4 patches to package HTML on Linux. + +* Since connections are not closed manually (server side), send a dummy payload with content-length data. + +##### Import/Export + +* New: Set Java source and target to 1.7 (fixes Java 1.5 obsolete warnings). + +* New: Added support for changing the variable "r.MobileContentScaleFactor" at runtime on Android. This is useful for device-specific resolution tweaking. + +* Bugfix: Fixed an issue where HTML5 video in a Web Browser widget would only output sound but no video on Android. + +* Bugfix: Fixed an issue where the red and blue channels were reversed in screenshots taken on Android in Vulkan mode. + +* Disabled eglSwapInterval since it can cause issues with some drivers. + +* Changed text for Android Mobile Deferred Renderer setting to indicate that it's only supported on Nvidia K1 and X1 devices. + +##### iOS + +* New: As we move towards the next version of iOS, we will be moving towards 64-bit support only. We have added messaging in this release to start the process of this migration. + +* New: IOS now utilizes the Library/Caches directory to save any data on device. This includes logs and save games. IPhonePackager has been updated to pull the data from this location as well as the Documents directory. + +* New: Xcode 8.3 is properly supported in this release. + +* Bugfix: Fixed a crash if Text Box widget is closed before text is finished being entered. + +* Bugfix: Fixed a crash in the OnlineSubsystem when it is disabled on iOS. + +* Bugfix: Fixed an issue with static audio noise on iOS devices. + +* Bugfix: Fixed an issue with remote compiling by unconverting the path back to host when reading from the module file name. + +* Bugfix: Fixed a memory leak on texture creation with Bulk Data in OpenGLTexture.cpp. + +* Bugfix: Fixed an issue with the device profile names for iPad Pro 9.7 and 12.9. + +##### Linux + +* New: Added pooling of OS allocations on Linux, greatly reducing the need to call mmap/munmap() and avoiding running into vm.max_map_count limit when loading large projects. + +* New: Install of MIME types during setup is now supported. + +* New: UnrealPak is no longer included in the default make target, the prebuilt binary will be used instead. + +* Bugfix: Fixed a crash in ShaderCompileWorker due to misaligned strings. + +* Bugfix: Fixed starting Linux programs using FPlatformProcess::CreateProc() from a path with space. + +* Bugfix: Fixed various issues with Vulkan RHI on Linux. + +* Bugfix: SlateDlg now appropriately compares filter extensions in a case-insensitive way, so both *.fbx and *.FBX work. + +* Bugfix: Fixed bogus "unable to make config file writable" message (the operation was actually succeeding). + +* Bugfix: Fixed clang 4.0 warnings. + +* Bugfix: Fixed inability to rebuild lighting in ResavePackages commandlet on Mac and Linux. + +* Bugfix: Fixed some problems when working from directories that have space character in their names. + +* Bugfix: Fixed older versions of Linux cross-toolchain (ones using LINUX_ROOT instead of LINUX_MULTIARCH_ROOT) not being detected. + +* Bugfix: Fixed a memory leak in callstack symbolication on Linux. This makes memory profiling work again. + +* Bugfix: Fixed an issue with Linux editor splash screen image being wrong when no project has been opened. + +* Bugfix: Fixed MoveFile to work across file systems. + +* Bugfix: Removed redundant RootDir() and EngineDir() on Linux. + +##### Mac + +* New: Enable Metal Shader Model 5 support on Intel as of 10.12.4 and later. + +* New: On Macs that do not support Metal, but erroneously report that they do, show a message box that tells users that the application cannot run instead of crashing on a failed assert. + +* New: Removed Mac OpenGL RHI files and disabled building of OpenGL RHI on Mac. + +* New: Limited support added for exposing debug events to Apple's Instruments "Points of Interest" tool. + +* New: Added RHISetResourceAliasability_RenderThread to FDynamicRHI for RHIs to implement simple render-target aliasing. + +* New: Added FApplePlatformObject, a custom block allocator for Objective-C types (with NSZombie support) which is now used in Metal RHI to decrease allocation costs of Objective-C types. + +* New: Limited support for Xcode automatic code-signing for iOS/tvOS. + +* New: Reimplement RQT_AbsoluteTime for Metal using a similar emulation to OpenGL on Mac so that the scalability system can correctly set the default graphics options. Not all drivers support this and in those cases the scalability settings are determined by an alternative, fixed, code-path. + +* Bugfix: Fixed mouse position issues in fullscreen mode on Mac. + +* Bugfix: Fixed an issue in Avf Media Player causing looped movies to only play once. + +* Worked around Metal's lack of implicit type-casting that was causing incorrect rendering in the Distance Field Ambient Occlusion and Shadows shaders. + +* Re-ordered the options in MetalRHI's internal debug options (Console Variable: "rhi.Metal.RuntimeDebugLevel") to make it more efficient. + +* Minimisation of render-target changes in some passes, notably Scene Occlusion and DBuffer Decals. + +##### Tools + +* Bugfix: Fixed a rare crash with the Web Browser widget on iOS. + +* Bugfix: Fixed iPhonePackager errors in output log when opening Project Settings on Windows. + +* Bugfix: Fixed Get Max Samplers returning an incorrect value for iOS OpenGL, which could have suppressed some warnings for shaders that used more than 8 samplers. + +* Removed duplicate gc.MaxObjectsInGame setting in IOSEngine.ini. + +##### Windows + +* Bugfix: Fixed a problem on Windows where the cursor would get locked to a part of the screen after switching from fullscreen to windowed while the cursor was unlocked. + +#### Programming + +* New: Added an experimental Android option to enable Shipping builds with hidden symbol visibility by default. (bBuildWithHiddenSymbolVisibility). + + * Add JNI_METHOD for java accessible native functions, without this java will trigger an unsatisfiedlinkerror exception. + + * This can significantly reduce the size of the final .so file. + +* New: Added support for map file generation with Android. + +* New: Crash reporter is no longer staged by default when packaging from the editor. The default endpoint for crashes was an Epic server, so including it in packaged games by default was not useful. + +* New: Script plugins can now specify dependencies which should trigger UnrealHeaderTool to be re-run, by overriding the IScriptGeneratorPluginInterface.GetExternalDependencies() method. + +* Bugfix: Fixed a crash where Canvas wouldn't update font engine services if it was never created. + +* Bugfix: Fixed an issue with Automation Tool exception when running Perforce commands if multiple brokers are present in the server configuration. + +* Android links with -gc-sections to remove unused code/data. + +* Program targets can now be excluded from the full solution build roster by setting bBuildInSolutionByDefault to false from their .target.cs file. + +#### Rendering + +* New: Added support for Window PIX. + +* New: Enabled support for NVIDIA Aftermath. On Aftermath enabled executables you can now get a GPU callstack when a GPU crash is detected. + +* New: Enabled support for global Distance Field shaders on GL 4.3 and Vulkan SM5. + +* New: Added support for Quad overdraw viewmode in the Forward Renderer. + +* New: Add support for per-component Skeletal Mesh skin weight overrides. + +* New: Added /VIRTUALIZEDIRECTX option to XgConsole for XGE shader compiling to work on remote machines without DX installed. + +* New: Added support for Structured-Buffer resource views to Metal RHI. + +* New: Added AMD path to experimental D3D11 HDR support. + +* New: Exposed the r.DisableDistortion cvar for toggling distortion rendering. + +* New: The high level rendering code is now PipelineStateObject aware which will allow us to reduce complexity in the rendering backends of Vulkan, Metal and Dx12 in the future. + +* New:Added FShaderCodeLibrary which handles de-duplication of shaders during content cooking and the shader code has moved into a separate library for cooked content runtime loading. This reduces package sizes and load-time overhead. + +* New: Added RHIShaderLibrary for platform specific native shader library implementations. This allows each platform to provide its own optimal shader library implementations. + +* New: Added Metal (MacOS and iOS) native shader library where shaders are loaded from a single Metal library improving the memory footprint, load time, and runtime compile times. + +* New: As part of the cook process for Metal, the archiving process also generate text shaders that can be used when running with optimized Metal shaders. Run with optimized shaders and while debugging with text source. + +* New: Added command line option "-noheartbeatthread" to disable heart beat thread. + +* New: Full refactor of the GPU Skin Cache to fix multiple issues related to Editor, Persona, per-frame numbering. Memory limit is now set per World in the Project Settings > Rendering section. + +* New: ShaderCache now supports running with multithreaded rendering. Command line flag "-norhithread" is no longer required to enable this feature and can now be removed if it was being used solely for this purpose. + +* Bugfix: Fixed a crash with D3D12 in "Update Texture 2D". + +* Bugfix: Fixed an assertion failure in basepass when trying to draw a mesh with Post Process Material. + +* Bugfix: Fixed a crash when the Tile Renderer renders before any other renderer. This could happen in rare cases on Editor bootup. + +* Bugfix: Fixed a crash accessing mesh Material arrays with invalid index. + +* Bugfix: Fixed a potential crash when rendering to accessible buffer. + +* Bugfix: Fixed a possible crash when failing to import cubemaps. + +* Bugfix: Fixed a crash for MacOS/Metal when compiling Materials using the Vector Noise node. + +* Bugfix: Fixed overflow issues that could occur on mali based devices when rendering DoF with bright objects. + +* Bugfix: Various Vulkan fixes: + + * Compiles in Linux. + + * Many cubemap issues squashed. + + * Changed the scratch reflection cubemap clear to SetRenderTargestsAndClear, instead of SetRenderTarget() / Clear(). + + * Added compute fences. + +* Bugfix: Fixed several sRGB related issues with Retainer Box widget. + +* Bugfix: Fixed an issue with prepass/basepass z-fighting, caused by bad vertex welding in depth-only indexbuffer. + +* Bugfix: Fixed an issue with velocity rendering when an off axis projection matrix changes from frame to frame. + + * Affects very few people. Cave rendering and stereo glasses but not HMDs. + +* Bugfix: Fixed an issue with scene motion blur data is only updated for the main renderer frames. Fixes scene captures and planar reflections breaking object motion blur. + +* Bugfix: Fixed an issue with Exponential Height Fog where it renders incorrectly after world origin rebasing. + +* Bugfix: Fixed an issue introduced into 4.15 where Static Meshes with auto-generated LODs were no longer sharing lightmaps between LODs. + +* Bugfix: Fixed bug converting a Procedural Mesh component to a Static Mesh if it only contains a single triangle. + +* Bugfix: Fixed an issue where Scene Capture 2D's show flags would not be applied properly in some circumstances. + +* Bugfix: Fixed an issue where the "disable Stationary Skylight" feature would cause improper warnings. Also made it so that a movable Skylight is always used in Persona preview window so all projects can get preview lighting. + +* Bugfix: Fixed an issue where High Quality Particle Lights would not move properly if their parent was attached to a socket of an animated skeleton. + +* Bugfix: Fixed detection of OpenGL Radeon driver on Mesa. + +* Bugfix: Fixed an issue with shot command in Vulkan. + +* Bugfix: Fixed an issue with refract() intrinsic handling in hlslcc for GL/Metal/Vulkan. + +* Bugfix: Fixed an issue with missing Mobile Material Interface for Landscape "Used Materials" check. + +* Bugfix: Fixed rare case where Decals could incorrectly draw a second time in separate translucency pass. + +* Bugfix: Fixed a bug with the basic eye adaptation mode that could result in incorrect brightness when using a small viewport. This has no effect on the default histogram version of eye adaptation. + +* Bugfix: Fixed an issue with Separate Translucency being affected by Gaussian DoF. + +* Bugfix: Fixed an issue with "Streaming Bounds" show flag not working correctly. It now shows the texture streaming bounds for the textures currently selected in the Content Browser. + +* Bugfix: Fixed possible stall when canceling texture updates. + +* Bugfix: Fixed an issue for tone mapping of bright objects with zero green. Previously, these could have had a one-pixel black outline. + +* Bugfix: Fixed an issue with the IES Light Profile importer with LM-63-1986 format. + +* Texture flags are now properly routed to RHICreateTexture3D from the render target pool. + +* Collection Parameter Nodes no longer rename parameters when duplicated. + +* Renamed console variable "r.Streaming.ScaleTexturesByGlobalMyBias" to "r.Streaming.ScaleTexturesByGlobalMipBias". + +* Now when using the "freezerendering" command, the foliage culling/occlusion will also be frozen. + +* Optimize the computation behind the Screen Position material expression in the pixel shader. + + * Exposes the viewport offset of the view within the render target in the View Property material expression. + +##### FX + +* Bugfix: Fixed an issue with rendering corruption issue with 4 and 8 vertex instanced particles using the wrong Vertex Factory objects. + + * D3D didn't need separate Vertex Factories due to the VertexDecl updating the stride at draw call time, but some platforms were affected. + +##### Lighting + +* New: Improved quality and significantly faster cubemap prefiltering for reflections and skylight. + +* New: Post Process Indirect Lighting Intensity no longer scales Skylight reflections. + +* New: Screen Space Reflections (SSR) now has a higher quality setting for sharp SSR when using Quality Level 4. + +* New: Distance field self shadowing controls for hiding world position offset self-shadow artifacts. + + * Removed Static Mesh Build Settings "Distance Field Bias", which shrunk the distance field, breaking AO and shadows. + +* New: Distance field mesh visualization now uses a cone containing the entire tile to cull objects with, making the results stable. + +* New: Distance field temporal filter stores a confidence value, which is used to track leaking of occlusion during the upsample, and flush those leaked values through the history faster. Reduces DFAO ghosting when the camera is moving. + +* New: Added some new features to the Skylight component. + + * "Occlusion Exponent" which is useful for brightening up indoors without losing contact shadows as “Min Occlusion” does. + + * "Occlusion Combine Mode" which is useful for artists to choose how to combine SSAO with Distance Field Ambient Occlusion. + +* New: Added "r.AOListMeshDistanceFields" which dumps out mesh distance fields sorted by memory size, useful for directing content optimizations. + +* New: Planar reflections handle views smaller than the render target in a general way. + + * Fixes planar reflections with adaptive pixel density (ViewFamily size larger than actual views combined). + + * Planar reflections are now supported in splitscreen. + +* New: Support for fading of Light Propagation Volume cells towards the volume edges. + +* Fresnel of clear coat layer now darkens diffuse for the clear coat shading model. + +* SSR is now reprojected correctly on moving objects. + +* Raised High ShadowQuality to 2048 as 1024 for CSM is too low. + +* Disabled all distance field features on Intel cards because the HD 4000 hangs in the RHICreateTexture3D call to allocate the large atlas. + +##### Materials + +* New: Added a "Sign" material graph node which replaces the library function for more optimal translation. + +* New: Added MinimalAPI to several material expressions. + +* New: Updated default behavior of "Power" node to no longer “abs” or “max” against an arbitrary value as the results were incorrect. + + * Previous version available by calling ClampedPow(x, y) in a "Custom" node. + +* New: Improved material translation preservation of constants. + + * This improves detection of used attributes which prevents some cases of features being enabled incorrectly. + +* New: Material flag normal curvature to roughness now works in the Deferred Renderer. It is no longer forward only. + +* New: Improved Material graph error messages. + +* New: Enabled "r.Streaming.UsePerTextureBias" by default as a way to improve quality in low texture budget settings. + +* Bugfix: Fixed errors across various library Material Functions. + +* Bugfix: Fixed an issue with broken size query for render targets in Material graphs. + + * Implemented missing "Get Size" functionality. + +* Bugfix: Fixed various data type inconsistencies on legacy Make and Break Material Attributes graph nodes. + + * Using these together with the "Get" and “Set” Materia lAttributes nodes should now be more forgiving. + +* Bugfix: Fixed a regression in HLOD shadow casting performance. + +* Bugfix: Fixed inconsistent results with the "Investigate Texture" commands. + +* Bugfix: Fixed possible incorrect results when listing textures used by Material Instances. + +* Bugfix: Fixed an issue where Material Reroute nodes did not bind properly to Texture Object Parameters. + +##### Mobile Rendering + +* New: Mobile Skylights no longer render the scene on the device to determine the sky's color. Mobile skylight uses values determined via captures performed in the editor. This saves memory and performance on device and enables Skylight contribution on devices that do not support fp16 render targets. + +* New: Added "r.Mobile.TonemapperFilm" console variable which can be used to enable/disable new filmic tonemapper on Mobile devices, independently from Desktop platforms (disabled by default). + +* New: Material AO is now supported for the Mobile Rendering path. + +* New: Added better defaults for rendering resolution on iOS devices, to make them more inline with defaults on Android devices. + +* Bugfix: Fixed a crash that could occur on some devices when loading materials which use fonts as texture parameters. + +* Bugfix: Fixed a crash with Particle Cutouts on mobile devices that don't support hardware instancing (ie. Mali-400 GPU). + +* Bugfix: Fixed a crash when enabling shader cache on NVIDIA Shield devices. + +* Bugfix: Fixed a crash when previewing feature level ES3.1 with a Material using World Position Offset. + +* Bugfix: Fixed a crash with Media Player on iOS devices. + +* Bugfix: Fixed an issue with Static Mesh self-shadowing with modulated shadows. + +* Bugfix: Fixed several issues that could cause CSM shadowing on mobile devices to flicker. + +* Bugfix: Fixed an issue with scene captures on mobile when Mobile HDR is disabled and the scene capture source is Scene Color. + +* Bugfix: Fixed an issue with bright dynamic point lights cause bloom rendering artifacts on Android Mali devices. + +* Bugfix: Fixed an issue where Landscapes do not render on some Android PowerVR devices. + +* Bugfix: Fixed an issue where translucent object appear black on Zenfone5. + +* Bugfix: Fixed an redundant blend state change in OpenGL ES2. + +* Bugfix: Fixed rendering artifacts with bloom on iPhone7 using Metal. + +* Bugfix: Fixed an issue where exposure was more extreme on mobile devices with a new filmic tonemapper enabled. + +* Bugfix: Fixed an issue with padded NPOT textures not rendering correctly on iOS. + +* Bugfix: Fixed an issue with gamma issues with canvas elements on iOS Metal devices. + +* Significantly reduced OpenGL state setup for Slate draw calls on Mobile devices. + +* Slate pixel shaders will use half precision, for better UI performance on Mobile devices. + +* Mobile targeted projects will have better UI performance settings by default. + +##### Optimizations + +* New: Added 'r.CompressMeshDistanceFields' console command to rendering project settings, defaults to off to prevent hitches when streaming in levels. + + * When enabled, mesh distance fields are stored zlib compressed in memory until needed for uploading to GPU. + + * 81Mb of backing memory -> 32Mb in GPU Perf Test. + + * Atlas upload time 29ms -> 893ms. + +* New: Added a new global distance field (4x 128^3 clipmaps) which caches mostly static primitives (Mobility set to Static or Stationary). + + * The full global distance field inherits from the mostly static cache, so when a Movable primitive is modified, only other movable primitives in the vicinity need to be re-composited into the global distance field. + + * Global distance field update cost with one large rotating object went from 2.5ms -> 0.2ms on 970GTX. Worst case full volume update is mostly the same. + +* New: Added LOD Distance Factor to Scene Capture Component, which can be used to make scene captures and planar reflections much cheaper to render if the scene has good LODs setup. + +* New: Added the r.LightMaxDrawDistanceScale console command for local light scalability. + +* New: Added a rendering project setting to use 8 bit mesh distance fields. + + * This halves their memory requirement but introduces artifacts with large meshes. + +* New: Added new async tasks to reduce the cost of the texture streaming update on the game thread. + +* New: Added some automatic callbacks whenever dynamic component renderstates are updated in order to also update their texture streaming states. + +* Bugfix: Fixed async SSAO not actually running asynchronously when depth drawing mode was DDM_AllOpaque. + +* Bugfix: Fixed render queries stalling in Test/Shipping builds due to lack of pooling. + +* Ray Traced Distance Field Shadow optimized. + + * From 1.8ms -> 0.8ms in a test scene. + +* Use 16 bit indices for distance field objects culled to tiles, when 16 bit will be enough. This saves 10mb of tile culling buffers. + +* GNM RHI Clear UAV uses a compute shader for buffers larger than 1Kb. + +* GNM Structured buffers are now placed in GPU memory (was previously in CPU memory). + +* DFAO optimizations: + + * Changed the culling algorithm to produce a list of intersecting screen tiles for each object, instead of the other way around. Each tile / object intersection gets its own cone tracing thread group so wavefronts are much smaller and scheduled better. + + * From 3.63ms -> 3.48ms (0.15ms saved). + + * Replaced slow instructions in inner loop with fast approximations (exp2 -> sqr + 1, rcpFast, lengthFast). + + * From 3.25ms -> 3.09ms (0.16ms saved). + + * Moved transform from world to local space out of the inner loop (sample position constructed from local space position + direction). + + * From 3.09ms -> 3.04ms (0.05ms saved). + +* Structured buffers for DF object data. + + * Full global distance field clipmap composite 3.0ms -> 2.0ms due to scalarized loads. + +* Exposed MaxObjectsPerTile with the 'r.AOMaxObjectsPerCullTile' console command and lowered the default from 512 to 256. This saves 17Mb of object tile culling data structures. + + * This can cause flickering in Ray Traced Distance Field shadows if too many objects fall into one shadowmap culling tile. + +* Scene color resolves are restricted to the views. This fixes inefficiency with adaptive pixel density where the views don't match the view family size. + +* When using a full prepass, the base pass no longer writes depth. + + * Saves 0.3ms of Scene Depth Resolve on 970 GTX with MSAA. Also allows masked materials to get EarlyZ in the base pass. + + * Fixed primitives with Use As Occluder set to false being excluded from a full depth pass in static draw lists. + + * Added the "r.BasePassWriteDepthEvenWithFullPrepass" console command for verifying that the base pass depths match the prepass depths. + +* Changing movable skylight properties no longer affects static draw lists. + +* Mesh distance field generation uses Embree, which provides a 2.5x speed increase. + +* Cleared light attenuation for local lights with a quad covering their screen extents. + + * Clearing the entire light attenuation buffer costs 0.1ms. This optimization lowers the minimum cost of a shadow casting light from 0.15ms to 0.03ms. + +* Flushed deferred deletes when reallocating distance field atlas to reduce peak memory, at the cost of a hitch on first frame. + +* Disabled point / spot lights with Max Draw Distance on Low PC. + +* Made use of Metal's "Deferred Store Actions" where available to avoid incorrect “Store” actions introduced when restarting passes to switch encoder types or when using the Metal RHI debugging tools. + +* Stopped the Shader Cache recording all the RHI resources unless it is running on OpenGL. This significantly reduces the CPU overhead of enabling the Shader Cache. + +* HLOD texture force loaded through the "r.Streaming.HLODStrategy" console command will now load visible mips first. + +* The command "BuildMaterialTextureStreamingData" can now be used with "all" as argument to force a rebuild. + +* Reduced the texture streaming overhead for components by keeping track of the state within the streamer. + +##### Postprocessing + +* New: Using Custom Depth to write to the stencil buffer now has the ability to use single-channel bitmasks that ignore depth. This makes it possible to detect overlaps between stencil objects. + +* Bugfix: Fixed log value conversion in tonemapping causing true blacks to be lost. + +* Motion blur no longer gets dark at the edges of the screen. + +#### UI + +* New: Added API to programmatically change the Virtual Cursors UMG Widget on the Viewport Client. + +* Bugfix: Fixed sRGB conversion issues in Retainer Box when used with a material. + +* Multiline editable text boxes can now be marked as read-only. + +* Selecting multiple text widgets will now correctly set text when the text field is edited. + +* Widget Components will now correctly determine between hover and clicked states when using or simulating touch. + +##### Slate + +* New: Added Enum Has All Flags and Enum Has Any Flags, templated functions to make it easier to check for the existence of a flag on enum classes. + +* New: There is now a console variable option, Slate.VerifyHitTestVisibility (off by default), which enables additional visibility checks for widgets. Normally this is not necessary, but if you are changing the visibility of widgets during a frame, and several hit tests need to be performed that frame, there is a chance that a button could be clicked twice in one frame. Enabling this mode will make all hit testing more expensive, so for now it is off by default, but available for licensees that need the extra testing. + +* New: Added the ability to invert alpha when drawing slate textures. This will be used in the future for rendering render targets for the scene which have inverted alpha. + +* Bugfix: Fixed a crash during editable text widget destruction while a context menu was still open. + +* Bugfix: Fixed a crash when deleting a streamed font. + +* Bugfix: Fixed lots of outline data being added to the font cache due to wrongly hashing outline material and color data. + +* Bugfix: Tooltips will no longer show if the cursor is not directly over a Slate window. Fixed a case where the tooltip would not disappear when the cursor is moved over another application's window that was placed on top of a Slate window. + +* Bugfix: Fixed an issue where the cursor would sometimes not appear when its visibility was changed. This was rooted in how the OS requested cursor changes, WM_SETCURSOR on Windows only asks for new cursors when the mouse moves, but often cursors change just because mouse capture changes. So now the path has been centralized in Slate Tick to only handle the cursor changes in one place, and several places that need to refresh the cursor state, now set a flag to handle it on next tick. + +* Bugfix: Fixed a bug with ZOrder being discarded on the SOverlay slot. + +* Bugfix: Fixed Web Browser Viewport to properly scale. + +* Bugfix: SButton now correctly releases mouse capture even if it becomes disabled while pressed, but before 'click' has been fired. + +* Improved text rendering when the last resort font is missing. + + * The last resort font is no longer included in shipping builds, so this change makes some improvements to text rendering when it is missing. + + * The legacy font cache no longer tries to use the last resort font if it is not available (preventing warnings). + + * The Slate font renderer no longer tries to use the last resort font if it is not available. + + * Text shaping will use the last resort character if none of the available fonts can render a given character (likely because the last resort font is missing). + + * HarfBuzz shaped text now uses the fallback character correctly. + +* Kerning-only text shaping no longer draws characters to get their metrics. + +* Text selection height is now the maximum of the line height and text height to account for negative line-height scaling. + +* Added a setting to control whether we should use the font metrics or the bounding box when laying out a font. + + * Not all fonts have accurate metrics data, so using the bounding box can produce much better results for certain fonts. + +* Made slate loading widget / movie playback more thread safe by eliminating Slate application or the main window from being ticked directly on another thread. Is In Game Thread will also no longer return true when called from the slate loading widget thread. + +* Force resolution in standalone if the resolution is larger than primary working area. + +* Moved ESlateDrawEffect & ESlateBatchDrawFlag over to be enum class. Found cases where the enum order was being improperly assumed, and so now it will not be possible to just treat an int32 or a bool as the draw effect value. + +* Slate Application now maintains separate tracking for each pointer being utilized for drag drop, so now multiple fingers on multiple widgets can now simultaneously be attempting a drag, however once one of them becomes successful, we clear all state of all other tracking since only one Drag Drop operation is possible at a time. + +* Fold Tick is now removed from the codebase. We have not supported the other (non-folded) code path for awhile, so there was no point in maintaining the switch. + +* The Checkbox widget no longer just passes visibility down to the internal widgets it creates, that prevents future changes to affect it if it starts collapsed. + +##### UMG + +* New: Added Timing Policy option to Widget Component, so widgets can optionally tick in pausable/dilatable game time rather than real time. + +* New: Added a material function that exposes all of the current UV sets with nice names instead of indexed coordinates. + +* New: Added a method to create Slate Brushes from Paper Sprites the same way we can for materials and textures in blueprints. + +* New: Introduced PreConstruct and Native PreConstruct to the base User Widget. Users can now visualize non-binding based changes in the designer by evaluating a very limited amount of the blueprint code. In the event your user widget crashes on load, due to calling something unsafe, you can disable evaluation in the editor preferences under Widget Designer. + +* New: Introduced a way to inform widgets of more information about the designer. There is now a Designer Changed event sent to all design time widgets letting them know things like the current screen size and DPI scale. + +* Bugfix: Fixed a crash if UI blurs are rotated. + +* Bugfix: Outline color on text elements is now inherited properly. + +* Bugfix: Fixed a bug that prevented Get Owning Player in Widget from returning. + +* Bugfix: Additional fixes to the way we migrate changes from the preview to the serialized version of the widget tree in the widget editor. This fixes several issues with edit-inline Objects on Widgets. + +* Exposed a normalized (0-1) uv coordinate set and scaled pixel size for Box and Border brushes. + +* Widget Interaction Components now ignore Visible(false) Widget Components when tracing. + +* Widget animations now finish evaluating before firing an event alerting that the animation finished. + +* The Widget Interaction Component now checks if the Widget is enabled before it claims that it is over an interactable or keyboard focusable widget. + +* Adding some setters and getters for Redraw Time to the Widget Component. + +* Widgets projected into screenspace from the Widget Component should now appear in the correct locations if the player's camera has an aspect ratio lock. + +* The Safe Zone widget will now show the correct safe zone amount if you use the safezone command line options, which are now documented in the comment for the Safe Zone class. + +* Widget switchers that contain widgets with named slots will now correctly display a widget whose named slot is currently selected. + +* Widgets that are copied and pasted will now retain the same name in the widget hierarchy. + +#### VR + +* New: Added support for getting device depth from Scene Capture Component 2Ds. + +* New: Added ability to disable the autoloading splash screen, which would prevent the manual "hide splash screen" node from working properly. + +* New: Added Gear VR controller support. + +* New: Added support for OES_EGL_image_external to the mobile GL renderer. + +* Bugfix: Negative Stereo Layer priorities are now handled correctly on Steam VR. + +* Bugfix: Fixed threading issue with motion controller tracking that caused controller motion pops. This problem manifested intermittently. + +* Bugfix: Fixed crash on Oculus Rift when attempting to enter stereo mode while the HMD's 'on head' proximity sensor is not triggered. + +* Bugfix: Fixed low framerate when Oculus Rift 'on head' proximity sensor is not triggered and you exit stereo rendering. + +* The GearVR HMD plugin is now only enabled on Windows if the Oculus service is already running. + +* VR console commands have been rewritten to support autocompletion and inline help strings. + + * The VR console commands have also be renamed and now begin with vr.*. + + * The renamed VR commands have backwards compatible aliases, but will print a warning notifying the user about the deprecated functionality. + +* GoogleVR HMD now reacts to changes in the r.ScreenPercentage console command. + +* When the -hmd command line option is used to override the selected HMD, HMD plugins that are loaded early will now be unloaded during PreInit if not selected. + +* Integrated OpenGL support for SteamVR. + +* The left eye is used when selecting LODs to avoid selecting two separate LOD levels when rendering in stereo. + +* PSVR controller tracking limit management system. + + * PSVR can track the HMD and two controllers, but many more devices can be connected. With this system you can manage which controllers are tracked to stay under the limit. + +* Additional WorldScale refactoring for all platforms. + +* GoogleVR plugin updated to version 1.3 + +* Fixed Android manifest for Daydream and Cardboard. + +* Updated GoogleVR plugin to version 1.3. + +* GoogleVR SDK updated to 1.40.0. + +* GoogleVR Mode default changed to Daydream and Cardboard. + +## Programming Release Notes + +#### AI + +* New: Added a new mode to composite EQS generator (UEnvQueryGenerator_Composite), which allows the use of different types of items by each child generator. This can be enabled by advanced properties: bAllowDifferentItemTypes and ForcedItemType. ForcedItemType is the final type returned by the generator, and is used for allocating memory and executing tests. This mode is potentially unsafe and you will have to ensure proper memory layout (matching with ForcedItemType) of all item types used by child generators - usually subsets of ForcedItemType. Keep in mind that allocated memory block is zeroed before use. + +##### Debugging Tools + +* Bugfix: Fixed VisualLog macros for recording segments with user defined thickness. + +* Bugfix: Fixed compilation errors in VisualLog macros for recording custom meshes. + +##### Navigation + +* Bugfix: Fixed memory corruption in generic A* solver: FGraphAStar. + +* Bugfix: Fixed unique Id duplicates in custom navigation links. + +* Bugfix: Fixed FRecastTileGenerator::Modifiers being erroneously counted twice when stating memory. + +* NavModifierVolume has been marked as ENGINE_API and can now be freely used in game code. + +* Made FNavAgentProperties::GetExtent return INVALID_NAVEXTENT if a prop's AgentRadius is not set. This results in properly using FNavAgentProperties::DefaultProperties in navigation queries when no query extent override is provided. + +#### Animation + +* New: Added more exports to AnimationAsset, AnimSequenceBase, and Skeleton classes. + +##### Animation Blueprint + +* Bugfix: Fixed nodes only getting CopyNodeDataToPreviewNode called when pin defaults were changed (not any property change). + +##### Skeletal Mesh + +* New: Added exports to FFbxImporter, FDynamicSkelMeshObjectDataCPUSkin, and FSkeletalMeshObjectCPUSkin, for extensibility. + +#### Audio + +* New: Added new cvars to help with optimization (only applies to the new Audio Mixer). + + * au.DisableReverbSubmix, au.DisableEQSubmix, ​au.DisableParallelSourceProcessing, au.SetAudioChannelCount + +* Bugfix: Fixed MIDI Device plugin public headers not being able to be included from an external module. + +* Optimized internals of new Audio Mixer. Gains approach 15% savings from before: + + * Turned a float divide into a multiply, which occurred at least 32k times per audio update. + + * Avoided thousands of Array.Add() calls during processing, which on shipping still does checks to see if the allocator has to grow, and updates ArrayCount. + + * Removed pointer indirection and successive TArray Add()s in GetChannelMap(). + + * Removed function call overhead to updating channel map. + + * Simplified FSourceParam::Update() to reduce branching and have one return site. + + * Added alternative to GetChannelMap() called UpdateChannelMap() that avoids copying out values to an array. The values can then be fetched from the channel data directly. + + * Refactored internal data to use array of structs rather than struct of arrays for better cache coherency when processing channels one at a time. + +#### Blueprints + +* New: Added an error when declaring a Blueprint Implementable Event with an enum param that is not plain or a byte type (Blueprints only support byte-sized enums). + +#### Core + +* New: There are now several serialization options available to specify what the cooked Asset Registry includes. Look for the serialize flags inside the [AssetRegistry] section of BaseEngine.ini. + +* New: An experimental bUseAssetRegistryForIteration option has been added to CookerSettings. This improves the performance of iterative cooking by loading the cooked Asset Registry directly, but it may still have issues with some changes to source files being missed. + +* New: Added a cvar to control the pak precacher throttle. + +* New: Added new GenericPlatformFile function, GetTimeStampLocal, which returns file time stamp in local time instead of UTC. + +* New: Added a check against assembling the reference token stream while streaming without locking the garbage collector. + +* New: Added a static_assert to prevent the use of TMap keys which do not implement GetTypeHash, as this causes runtime crashes when they are manipulated by a UMapProperty. + +* New: Added a bForceDebugUnrealHeaderTool option to BuildConfiguration.xml which forces the Debug version of UnrealHeaderTool to be run instead of Development. + +* New: Added a static_assert to ensure that TInlineSetAllocator is instantiated with a power-of-two hash size, as this is a requirement for TSet and TMap. + +* New: Added ICppStructOps::IsAbstract() for testing if a native type is abstract via the property system. + +* Bugfix: Fixed TInlineValue not calling virtual destructors. + +* Bugfix: Fixed several issues with editor-only objects not being correctly stripped when cooking. + +* Bugfix: Fixed several issues with Config files loaded from Plugins. They now correctly handle diffing game-specific changes. Engine plugins config files should be named BasePluginname.ini, and game plugins should be DefaultPluginname.ini. + +* Bugfix: Fixed many bugs with the event driven loader and allowed it to work at boot time. + +* Bugfix: Fixed a bug with nativized Blueprints that was introduced with the boot time EDL changes. + +* Bugfix: Fixed race in audio streaming. + +* Bugfix: Fixed bug which would cause a fatal error when cooking subobjects that were pending kill. + +* Bugfix: Fixed a bug with EDL at boot time which caused a fatal error with unfired imports. + +* Bugfix: Fixed a bug with RF_PendingKill subobjects and the new loader. + +* Bugfix: Fixed an obscure problem with stats in commandlets that use async tasks. + +* Bugfix: Fixed rare ensure cooking for the EDL. + +* Bugfix: Fixed boot time EDL causing some issues even when it wasn't being used. + +* Bugfix: Fixed .pak precacher shutdown. + +* Bugfix: Fixed memory leak in .pak precacher. + +* Bugfix: Fixed bad merge of priority change in the EDL. + +* Bugfix: Fixed race that resulted in a memory leak when reading compressed paks. + +* Bugfix: Fixed a weird recursive situation where StaticLoadObject could return an object that has not finished loading. Also produces a fatal error if this happens. EDL only. + +* Bugfix: Fixed batched render fences when BeginDestroy calls FlushRenderingCommands. + +* Bugfix: Fixed loading a package that is already loaded. + +* Bugfix: Fixed crash in signature checks when mounting pak files. + +* Bugfix: Fixed a change to NotifyPrimitiveDetached so that it works in the editor. + +* Bugfix: Fixed hash table lock optimization. + +* Bugfix: Fixed a crash relating to FGenericAsyncReadFileHandle when not using the EDL. + +* Bugfix: Fixed comments in GenericPlatform.h. + +* Bugfix: Fixed errors raised during code generation when a multiply-inherited base class happens to have the same name as a UObject after its prefix is stripped. + +* Bugfix: Fixed a compile error when calling TArray::HeapSort on an array of pointers. + +* Bugfix: Fixed a crash when calling UCookOnTheFlyServer::FFilePlatformRequest::ToString(). + +* Bugfix: Fixed compile errors raised when #pragma is used inside USTRUCTs. + +* Bugfix: Fixed compile errors caused by whitespace existing before a UCLASS() macro. + +* Bugfix: Fixed TStructOpsTypeTraits::WithCopy giving different results when the trait is specialized without a WithCopy value from when it isn't specialized at all. + +* Bugfix: Fixed a compile error when serializing bools to an archive in editor builds, where the archive type overrides other serialization operators. + +* Bugfix: Fixed FWorldTileInfo::Read() to copy the correct licensee version number from the file summary into the archive. + +* Bugfix: Fixed a regression in FObjectAndNameAsStringProxyArchive to re-allow serialization of TWeakObjectPtrs. + +* Bugfix: Fixed some include-what-you-use issues in the engine and plugins. + +* Bugfix: Fixed UPROPERTYs being skipped when there are redundant semi-colons between the properties. + +* Asset Registry memory and performance have been significantly improved in both Editor and cooked games for large projects. + +* Allowed UnrealPak to do a better job with EDL pak files when the order provided is old or from the cooker. + +* Several minor tweaks to low level async IO stuff. + +* Stored a copy of the callback in async read request so that we do not need to worry about lifetime so we can capture variables as needed. + +* Cancelling async loading with the EDL loader now prints a warning and does a flush instead. + +* Suppressed a few EDL cook warnings. + +* Tweaked the EDL for to all platforms. + +* Platform load time performance tweaks. + +* Abstracted the IO tracker and handle manager for other platforms and applied it to all platforms. + +* Protected against UDeviceProfileManager::Get() recursion and demoted a related fatal error to a log statement. + +* Removed old code relating to FAsyncArchive, FAsyncIOSubsystemBase and package level compression. The editor now uses the lowest levels on the new async IO scheme. + +* Increased estimate of summary size. + +* Avoided adding a linker annotation if it actually has not changed. This improves ConditionalBeginDestroy performance. + +* Avoided a redundant removal of PrimitiveComponent from the streaming managers during ConditionalBeginDestroy. + +* Optimized UObject hash tables for speed and space. + +* Put the special boot order things into baseengine.ini so that licensees and games can add to it. + +* Renamed HasBeenAlreadyMadeSharable to DoesSharedInstanceExist. + +* PostLoadSubobjects is now called on all objects regardless of whether they have a CDO as outer or not. + +* When Rename is used to change the Outer without specifying a new name, the existing name is maintained whenever possible. + +* ForwardVector, RightVector, and single float FVector constructors are now recognized by Unreal Header Tool as default values for an FVector parameter. + +* ScriptMacros.h no longers needs to be included in header files that generate a header. + +* Improved the readability of some of the ReferenceChainSearch code. + +* Automatically included ObjectMacros.h in generated headers to prevent compile errors. + +* Made FPaths::Combine() variadic so that it can take arbitrary numbers of arguments. + +* Improved the readability of the verbosity of log categories in the debugger. + +* Updated TArray::Sort comments to clarify what happens when sorting an array of pointers. + +* Clarified the assertion message you get when inserting or removing a TArray element by reference which comes from the array. + +* Clarified the comments for TArray::FindLastByPredicate and FString::FindLastCharByPredicate. + +* Removed UnrealCodeAnalyzer. + +* Raised an error in UnrealHeaderTool when a header containing UCLASSes, USTRUCTs etc. does not include its .generated.h file. + +* Removed TBoolConstant template. + +* Changed TAssetPtr to allow it to be constructed from nullptr without a full definition of T. + +* Removed the WITH_HOT_RELOAD_CTORS macro. + +* Removed the UseVTableConstructors .ini option. + +* Removed generated FName variables for UFUNCTIONs. + +* Removed the generation of obsolete .java and .proto files used for replication. + +* Replaced the set of bools used to FBlueprintCompileReinstancer with a new EBlueprintCompileReinstancerFlags enum. + +* Improved hot reload logging messages to make it clear that a compile attempt on a module does not guarantee a reload of that module. + +* Made UnrealHeaderTool report an error if a UFUNCTION in a derived class has the same name but a different signature from one in a base class. + +#### Editor and Tools + +* New: Added spinner options to VectorInputBox. + +* New: Added a None option to the FKey customization, unless the FKey property had NoClear on it. + +* Bugfix: Implemented a fix to ensure FVirtualTrackArea::HitTestSection checks the row of the section. + +* Bugfix: Fixed an issue where ISequenceAudioRecorder was inaccessible to FAudioRecorder. + +* Project and plugin templates now use "include what you use" style by default. + +* When using BuildGraph, the cached list of completed nodes is now cleared by default, making the -ClearHistory argument redundant. Use the -Resume argument to continue an interrupted build using the current artifacts. + +* BuildGraph now outputs an error if any build products from previous steps are tampered with during the execution of a subsequent step. + +* The editor now offers to download and install Visual Studio 2017 if an existing version of Visual Studio is not found. + +* The AutomationTool -CookDir argument no longer accepts multiple parameters separated by '+' characters, since '+' is valid in directory names. Multiple -CookDir arguments are supported instead. + +* Game mods can now be denoted by setting the bIsMod field to true inside the .uplugin descriptor. Mods will be shown in a separate category in the plugin browser, and will be shown separately in generated project files. Installed editor builds can build and clean mods without modifying build products for the base game. + +##### Content Browser + +* Bugfix: Fixed link error when FAssetData::PrintAssetData() is used in a project. + +##### Sequencer + +* Unified global and object-bound pre animated state, and added InitializeObjectForAnimation method to state producers. + +* Opened the API for MovieSceneAudio-related classes along with some minor functionality additions. + +* Exported MovieSceneTrackEditor to allow custom tracks to be created that derive from existing tracks. + +#### Gameplay Framework + +* New: Added support for FScopedMovementUpdate to be able to queue up overlaps that do not require reflexive bGenerateOverlapEvents. This requires custom code to be able to process these overlaps. + + * This allows custom inspection or processing of overlaps within a scoped move, without enabling the more expensive overlap flag. For instance you could have a fast projectile with an overlap response to a character mesh and get those overlaps from the trace without requiring expensive overlap processing when the mesh moves. + + * Overlap events from the move will still only trigger from UpdateOverlaps() if bGenerateOverlapEvents is enabled on both components, as before. + + * Made some data in FScopedMovementUpdate protected rather than private so it can easily be subclassed, and exposed a new helper ​SetWorldLocationAndRotation() for committing the move. + +* Bugfix: Fixed a crash when manipulating audio component properties from an Actor's constructor during async loading. + +* Bugfix: Fixed CharacterMovementComponent updates with very high delta time on server when initially joining. Made sure the ServerTimeStamp is initialized to current world time rather than zero to prevent large delta. + +* CheatManager functions to Damage/Destroy targets are now easier to override in game-specific subclasses. + +* InputComponent now has BindAction function that allows binding functions with additional parameters. + +* RawInput configuration structures can now be manipulated by other modules. + +* AActor::GetComponents() with generic type is now optimized to not force an allocation when the component count is large. + + * Previously it incorrectly assumed the output array needed space for the entire contents of OwnedComponents. If OwnedComponents.Num() > the array reserve size, this forced an allocation, even if few or no components of the requested type were found. + + * It is still recommended to use TInlineComponent array or an array using TInlineAllocator<> when using this function. + +* Removed allocations during creation in ​AAIController::PostInitializeComponents() (in non-shipping builds). + +* Optimized HasActiveCameraComponent() and ​HasActivePawnControlCameraComponent() to avoid filling an array while searching for a certain component, which could have caused an allocation. + +* Optimized MoveComponent() collision queries to avoid processing PhysX touches when bGenerateOverlapEvents is off. + + * Added support for bIgnoreTouches to FCollisionQueryParams. This allows GeomSweepMulti to filter out touches/overlaps much earlier. + +* MovementComponent does not ignore initial blocking overlaps when moving away from the impact normal from SafeMoveUpdatedComponent(). This fixes various cases where characters could be pushed through moving objects because they were moving away from the overlapping object, but not fast enough. + + * It now always uses the hit result to depenetrate from the impact as much as possible, and then retries the move. + + * Hit events are not triggered for the first test for depenetration. + +* CharacterMovement AdjustFloorHeight() is now allowed to adjust using the line trace if the sweep was in penetration. It also forces another next floor check so it will check after it adjusts the height or depenetrates, relevant when bAlwaysCheckFloor is off. + +* Optimized CharacterMovement tick to not extract transform values twice when they would not change in a small block of code. + +* Call TickCharacterPose() and clear root motion before abandoning tick in ​UCharacterMovementComponent::PerformMovement() when movement mode is None. This prevents root motion building up until the next valid movement mode. + +* Applied a performance tweak to ​ApplyRadialDamageWithFalloff(). + + * Do not rebuild FRadialDamageEvent each loop over hit actors. + + * Added stats for ​BreakHitResult()/MakeHitResult() under "stat game". + +* Optimized attachment to check welding option before expensive casts and body instance fetching. + +#### Localization + +* Bugfix: Fixed a bug where passing an empty FText to ChangeKey() would keep the previous FText value that had been passed in. + +#### Online + +* New: Added the bShowSkipButton parameter to IOnlineExternalUI::ShowLoginUI, which will display the "skip" button on relevant platforms. + +#### Other + +* New: Added missing initialization for SWindow::bIsMirrorWindow. + +* Bugfix: Added missing module dependencies. + +* Bugfix: Fixed a type casting issue. + +#### Physics + +* New: Added virtual keyword to DestructibleComponent ApplyDamage and ApplyDamageRadius. + +* New: Added Physx simulation shader override (see GSimulationFilterShader). + +* Bugfix: Fixed a debug rendering issue by recreating physics when changing mobility of components. + +* Bugfix: Fixed compile error when PHYSX_MEMORY_STATS=1. + +* Bugfix: Fixed performance regression caused by using collision aggregates for Instanced Static Mesh Component. + +* Bugfix: Fixed a crash in AABB Manager when origin shift is used. + +* Made UDestructibleComponent::SpawnFractureEffectsFromDamageEvent virtual. + +* Exported URadialForceComponent class for inheritance. + +* Allowed the editor to compile when bRuntimePhysicsCooking is disabled (cooking is still allowed in WITH_EDITOR builds even with it disabled). + +* EndPhysics tick will no longer be scheduled if QueryOnly is used on a ragdoll. + +* Removed the unsupported option of HideBone with DisableCollision when calling HideBone. This was not actually supported and did nothing so shouldn't break any behavior, just don't call the function. + +* Exposed PhysX enhanced determinism mode using the compiler flag PHYSX_ENABLE_ENHANCED_DETERMINISM. This allows local subsets of the PhysX simulation to behave deterministically independent of what is going on elsewhere in the Physics world. + +#### Platforms + +* Bugfix: Fixed a crash bug in cases where we received a duplicate user login/logout notification from the system software. + +* Bugfix: Fixed Codelite project having duplicated settings. + +* Moved some C++ defines out of the build.cs file into a C++ header. + +* Moved controller connect/disconnect handling to the main thread to fix issues with thread safety for callbacks. + +##### Android + +* New: Added functionality to use the visual studio mobile projects for debugging. To generate them run "generateprojectfiles.bat -vsdebugandroid" from a command prompt. After you have packaged your game for Development and put it on the device, you can set this new project as the start up project and run/debug the project in Visual Studio. + +* New: Support for Android runtime permissions added. Certain permissions have been removed or put under condition to check for support when the target sdk is greater than or equal to 23. + +##### HTML5 + +* New: Added new webassembly (wasm) toolchain - SIMD and multi-threading are not yet supported (these are slated to be in for wasm2). + + * These will be automatically turned off when building with wasm (as opposed to asm.js). + +* Removed HTML5 code from the Engine's SaveGameSystem.h and placed it in HTML5Platform.cpp. + +* Cleaned up HTML5PlatformFile.cpp and made it match as close as possible to linux's version. + +* Created HTML5's own PlatformFeature & SaveGameSystem files, and updated HTML5PlatformMisc to make use of the the new HTML5 SaveGame code. + +##### Linux + +* New: Added FreeBSD memory information functions to facilitate out-of-tree UE4 FreeBSD port. + +* New: Added a new cross-toolchain (version 9, includes clang 4.0) when targeting Linux on Windows. + +* New: Added some support for building on Debian Sid or Stretch. + +* New: Added clang to Fedora dependencies. + +* New: Added ability to compile Linux servers for 32-bit x86 architecture. + +* New: Added files generated for KDevelop to .gitignore. + +* Bugfix: Fixed more third party libraries to use libc++ instead of libstdc++. + +* Bugfix: Fixed memory leaks when symbolicating an address in Linux callstacks (during crash reporting and memory profiling). Makes runs with the memory profiler much faster. + +* Bugfix: Fixed rebuilding of VHACD (a third party library) on a case sensitive filesystem. + +* Bugfix: Fixed CodeLite projects to now use proper Debug binaries for debug configurations. + +* Switched Linux file abstraction to use new managed filehandles. Shared by all platforms with low limit of open files. + +* Whitelisted SteamVR plugin for Linux so SteamVR Blueprint functions are always available, even if stubbed. + +* Made source code accessor aware of clang 3.9 and 4.0. + +* Setup will now install the latest clang on Arch instead of clang35. + +##### Mac + +* Fixed address sanitizer support in MacToolChain (Apple changed the name of the env variable Xcode uses to enable it) and added support for thread sanitizer. + +* Fixed a problem where the glslang library was not enabled on Mac, preventing building an Android project with Vulkan from Mac. + +* Made Binned2 malloc work on Mac. + +#### Programming + +* New: When compiling a module written in include-what-you-use style, source files which are in the adaptive non-unity working set are now built with precompiled headers disabled, to expose errors with missing headers. Set bAdaptiveUnityDisablesPCH to false in BuildConfiguration.xml to disable this behavior. + +* New: Added initial support for async creation of pipeline state objects, enable using r.AsyncPipelineCompile. + +* Module .build.cs files, which depend on the contents of external files, can now add those paths to the ExternalDependencies list. Modifications to those files will trigger the the UBT makefile to be invalidated. + +* Plugin config files are now included in generated project files. + +* UnrealBuildTool will no longer attempt to use SN-DBS for build distribution if the service is disabled. + +* UnrealBuildTool now correctly supports compiling modular targets which do not use the shared engine build environment. + +* C# programs will now be included in generated project files automatically if a blank file called UE4CSharp.prog is found in the same directory. + +* The engine will now warn when trying to load a plugin with a mismatched "EngineVersion" setting. + +* Deprecated shared pointer typedef from ImageWrapper and removed usages. + +* Removed boilerplate header from ImageWrapper. + +* Removed monolithic boilerplate header from NetworkFileSystem. + +* Removed boilerplate header from LauncherCheck. + +* LauncherServices: Removed boilerplate header from LauncherServices. + +* Completed a modernization pass of Automation. + +#### Rendering + +* New: Added thickness option to debug DrawWireDiamond function. + +* New: Added a check to see if there are duplicated shader type names. + +* Bugfix: Fixed obscure check with flushing RHI resources. + +* Bugfix: Fixed hazard with SetMaterialUsage from a thread. + +* Bugfix: Fixed Windows handling of -sm4 and -sm5 so it can be used with -vulkan and -opengl. + +* Bugfix: Fixed selection of swapchain format for Vulkan on some Linux drivers. + +* Bugfix: Fixed an issue on Vulkan when copying into a cubemap face. + +* Bugfix: Fixed a bug calculating vertex declaration hashes on OpenGL. + +* Moved FPositionVertexBuffer & FStaticMeshVertexDataInterface declarations into their own headers, moved FStaticMeshVertexBuffer implementation into its own source file. + +* Updated Vulkan distributables and glslang to SDK 1.0.39.1. + +* Vulkan shaders now build using glslang 1.0.42.2 and includes those headers for redistribution. + +* Prefer D32_S8 on Vulkan instead of D24_S8 for the depth buffer. + +* Removed the temporary functions RHIClearColorTexture, RHIClearDepthStencilTexture and RHIClearColorTextures from each RHI. + +* Separated depth/stencil load/store actions. + +* Use the latest SDK for Vulkan, whether the one we distribute in ThirdParty or an installed version. + +* Implemented SetStencilRef() and SetBlendFactor() on RHIs which were missing it. + +#### UI + +##### Slate + +* Updated Slate to allocate widgets using MakeShared. + + * This saves one allocation per-widget. + +* Moved SVirtualWindow into Slate module from UMG. + +#### VR + +* New: Added an initial base implementation of IHeadMountedDisplay, FHeadMountedDisplayBase, that can be extended by HMD implementations instead of extending IHeadMountedDisplay directly. This base class provides default and or common implementations for parts of the IHeadMountedDisplay interface. Future releases may add more common functionality to this class, reducing the amount of work required to add support for new HMD platforms even further. + +* StereoLayers now have a default emulated implementation, making them supported on most VR platforms that did not already support them. HMD implementations that extend FHeadMountedDisplayBase will automatically inherit the functionality unless explicitly overridden. + +* Common code found in various HMD plugins handling management of StereoLayers has been extracted into a template base class, TStereoLayerManager, that provides a thread-safe way to manage a list of registered stereo layers. + +* The old Morpheus StereoLayers implementation has been removed in favor of the common stereo layers implementation provided by the HMD base class. + +## Upgrade Notes + +#### C++ API Changes + +* As part of the Asset Manager changes, Streamable Manager has been improved to support the concept of Streamable Handles. When requesting an async load, it now returns a shared pointer handle that will keep the requested object loaded as long as it exists. These handles can also be polled or waited on. + + * Synchronous Load and Simple Async Load on Streamable Manager have been deprecated in favor of the new Streamable Handle system. Both of those functions would keep assets loaded until explicitly unloaded, which in practice was not what most people wanted. + +* The Class/Property/Function redirect system has been rewritten to be faster and more flexible. Ini redirects such as "+ActiveClassRedirects" defined in [/Script/Engine.Engine] will still work, but the new system is used by putting redirects like “+ClassRedirects” in the [CoreRedirects] section of Engine.ini. + + * All engine redirects prior to 4.10 have been moved to CoreRedirects.cpp, newer redirects are now in the new format in BaseEngine.ini. + + * A single Property/Function redirect definition will now be applied for both blueprints and serialization, and redirects can now be defined with wildcard matching syntax to simplify large refactors. + + * Object and Package redirects can now be used to allow limited redirection of content references without creating an Object Redirector on disk. + + * Enum redirects have been improved and will now fully work with or without the Enum Name being specified. + +* Several Enum functions dealing with string conversion have been deprecated, and the names and comments have been cleaned up to make it more clear which are meant to be used at Runtime and which are meant to be used in the Editor/for debugging. + +* The console command "r.MSAACount 1" now produces no MSAA or TAA. “r.MSAACount 0” can be used to toggle TAA on for comparisons. + +* Cascaded Shadow Map resolution is now controlled by the console command "r.Shadow.MaxCSMResolution" instead of “r.Shadow.MaxResolution”. + +* New mobile targeted projects will have better UI performance settings by default. + + * Please enable "Explicit Canvas Child Z Order" option in project Slate Settings, to improve UI batching. Enabling this option may require manual Z Order tweaks in UMG Canvas panels if there Z ordering issues. + +* VR console commands have been rewritten to support autocompletion and inline help strings. + + * The VR console commands have also be renamed and now begin with vr.* + + * The renamed VR commands have backwards compatible aliases, but will print a warning notifying the user about the deprecated functionality. + +* The Exec method in Head Mounted Display has been removed, as all VR console commands now use Auto Console Command or similar to register console commands. + + * HMD implementations relying on having an Exec method now need to provide their own ways of registering console command handlers. + +* Set Visibility and Set Hidden In Game in Scene Component are no longer virtual. Instead override On Visibility Changed or On Hidden In Game Changed to respond to changes to these values. + +* The FBox and FBox2D constructors taking an int32 value have been deprecated as the value of that integer was not being used. The Force Init constructor should be used instead. + + * Replace FBox/FBox2D construction of the form FBox(0) with FBox(ForceInit). + +* The Unreal Header Tool now outputs an error when an Editor-only struct member is exposed to blueprints. This is necessary because packaged builds will crash if a Make/Break node for that struct is executed in a blueprint. + + * Any Blueprint exposed Editor-only struct members must either be made not Editor-only or no longer exposed to blueprints. + +* Post Load Map now provides the loaded World as a parameter to the delegate function. The World will be null if the load failed. + + * All existing functions bound to Post Load Map need to have a World pointer added to their signature. + +* Stop saving raw curve data into animations on cook to save memory/disk space. + + * If you are directly accessing Raw Curve Data on an Anim Sequence, this will no longer work in cooked builds. Animation Asset now provides a virtual function, Get Curve Data, to grab a reference to the correct Curve structure. + +* Removed boilerplate header from Automation Window. + + * The AutomationWindow.h boilerplate header file has been removed. Please replace all includes of AutomationWindow.h with IAutomationWindowModule.h + +* Removed boilerplate header from Automation Controller. + + * The AutomationController.h boilerplate header file has been removed. Instead of AutomationController.h, include the individual interface headers that you actually use. Remove the "Interfaces/" subdirectory from existing interface inclusions. + +* Automation Modernization pass + + * The IAutomationWorkerModule.h has been moved to the module's public root directory. Please remove the relative path from your existing include statements. + +* Removed boilerplate header from LauncherCheck. + + * The LauncherCheck.h boilerplate header file has been removed. Include ILauncherCheckModule.h instead of LauncherCheck.h. Remove "Interfaces/" subdirectory from existing ILauncherCheckModule.h inclusions. + +* Removed boilerplate header from LauncherServices. + + * The LauncherServices.h boilerplate header file has been removed. Instead of including LauncherServices.h, include the ILauncherXXX.h files that you actually use. Remove the "Interfaces/" subdirectory from existing ILauncherXXX.h includes. + +* Deprecated shared pointer typedef and removed usages from ImageWrapper. + + * The IImageWrapperPtr typedef has been deprecated. Please use TSharedPtr instead of IImageWrapperPtr. + +* Removed boilerplate header from ImageWrapper. + + * The ImageWrapper.h boilerplate header file has been removed. Instead of including ImageWrapper.h, include the actual IImageWrapperXXX.h files that you use. Remove the "Interfaces/" subdirectory from existing IImageWrapperXXX.h includes. + +* Removed monolithic boilerplate header from NetworkFileSystem. + + * The NetworkFileServer.h boilerplate header file has been removed. Instead of including NetworkFileServer.h, include the INetworkFileXXX.h headers that you actually use. Remove the "Interfaces/" subdirectory from existing INetworkFileXXX.h includes. + +* Changed default contact-gen method to PCM. This is the default in PhysX 3.4. + + * This may have slight implications on jitter and stability, but should be improved overall. The old behavior is still available (set EnablePCM = false in the project settings). + +* Removed the temporary functions RHIClearColorTexture, RHIClearDepthStencilTexture, and RHIClearColorTextures from each RHI. + +* Removed obsolete SmartCastProperty function. + +* Added a static_assert to prevent the use of TMap keys which do not implement GetTypeHash, as this causes runtime crashes when they are manipulated by a UMapProperty. + + * TMap key types must now implement GetTypeHash. Having GetTypeHash be implemented in a base class or being implicitly convertible to a type which is hashable is not sufficient. + +* Fixed TStructOpsTypeTraits::WithCopy giving different results when the trait is specialized without a WithCopy value from when it isn't specialized at all. + + * TStructOpsTypeTraitsBase has been deprecated. + +* Improved support for TTuple. + + * Tuples have a GetTypeHash function and can be used as a TMap key. + + * Can now be serialized to archives. + + * Can now be compared for equality with operators == and !=. + + * Can now be compared lexicographically with operators <, >, <= and >=. + + * TPair is now an alias for a 2-tuple, which is specialized to have Key and Value fields, but otherwise has the same functionality as all other tuples. + + * Tuple.h is now found in the Core/Public/Templates folder, rather than the Core/Public/Delegates folder. + + * TPairInitializer now converts to TPair, rather than TPair being constructible from TPairInitializer. + +* Removed UnrealCodeAnalyzer. + +* Added a static_assert to ensure that TInlineSetAllocator is instantiated with a power-of-two hash size, as this is a requirement for TSet and TMap. + + * TInlineSetAllocator will no longer compile if the hash size is not a power-of-two. + +* Removed TBoolConstant template. + +* Removed the WITH_HOT_RELOAD_CTORS macro. + +* Removed the UseVTableConstructors .ini option. + +* Removed generated FName variables for UFUNCTIONs. + +* Refactored EvaluateBoneTransforms to prevent usage of skeletal mesh component. + + * Deprecated EvaluateBoneTransforms in favor of new ​EvaluateSkeletalControl_AnyThread. + + * Deprecated skeletal mesh component argument to ConvertCSTransformToBoneSpace and ​ConvertBoneSpaceTransformToCS. Now they just take a transform. + +* Added a new overload for IOnlineSession::FindFriendSession in the session interface that can retrieve sessions for multiple friends. + + * Sending and accepting invites on dedicated servers on Steam is now supported. + + * The FOnFindFriendSessionCompleteDelegate now returns an array of FOnlineSessionSearchResult objects instead of just one. + +* The high level rendering code is now PipelineStateObject aware which will allow us to reduce complexity in the rendering backends of Vulkan, Metal and Dx12 in the future. + + * The loose state setting APIs of the Commandlist have been deprecated, instead the entire pipelinestate has to be set at once. + +* Moved controller connect/disconnect handling to the main thread to fix issues with thread safety for callbacks. + +#### Animation + +* When converting skeletal controls to the newer API, convert EvaluateBoneTransforms to ​EvaluateSkeletalControl_AnyThread. Backwards compatibility will be maintained, however warnings will persist. Any mesh component access should be cached in PreUpdate() as accessing the component is not thread safe. + +* If differences in timing between Maya and UE4 are experienced after importing Alembic files, this has been corrected. The fix requires that any problematic assets be reimported. + +#### Blueprints + +* The ticking behavior of latent actions in components has been changed to match how they behave in actors. When the component ticks, the latent actions will now be processed at the same time, rather than happening later in the frame when latent actions for non-ticking actors and components are processed. This does change behavior, so there is a console variable (t.TickComponentLatentActionsWithTheComponent) that can be used to revert to the older behavior until affected component Blueprints that depended on the old ordering behavior can be fixed up. The cvar should be treated as deprecated, and it will be removed in a future release. + +#### Core + +* To save on memory and disk space the cooked Asset Registry no longer includes Dependency information by default. If you need this information at runtime, enable bSerializeDependencies in the [AssetRegistry] section of BaseEngine.ini. + +* Starting asynchronous loads from within asynchronous loads has always been unsafe, but will now explicitly assert. This can be fixed by not starting asynchronous loads from within PostLoad functions, or deferring your game-specific code for a frame when called from an async callback. + +* Callback functions passed into Request Async Load will now execute on the next frame instead of immediately upon completion of an async load. This behavior is to avoid issues with calling async loads recursively, but if your game depends on this behavior you can restore it to call them immediately by setting the cvar s.StreamableDelegateDelayFrames to 0. + +* There is a new format for defining class/function/property redirects in ini files, check the [CoreRedirects] section of BaseEngine.ini for examples. The older formats will still work but the new format provides additional features and a simpler syntax so you may want to upgrade. + +* Any calls to Smart Cast Property should be replaced with code which explicitly handles the inner property of Array Property. + +* Get Type Hash implementations must now be added to types which are used as TMap keys. If your type defines Get Type Hash in a base class or is hashed via an implicit conversion, these should be fixed by implementing their own function and forwarding the call to the appropriate implementation. + +* Any use of TStructOpsTypeTraitsBase should be replaced with TStructOpsTypeTraitsBase2, where T is the type that the trait is being specialized for. + +* `#include "Delegates/Tuple.h"` should be replaced with `#include "Templates/Tuple.h"`. + +* As TPairInitializer is now convertible to TPair, rather than TPair being constructible from TPairInitializer, types which do not correctly implement copy or move semantics by not inhibiting the compiler defaults may cause a bad state when they are inserted into a TMap or TSet. All types used in UE4 containers should correctly define copy or move semantics. + +* Any dependence on Unreal Code Analyzer should be removed from projects. + +* The explicit usage of TInlineSetAllocator in any TSet and TMap should be updated to ensure that the template arguments provided result in hash sizes which are a power-of-two. + +* TBoolConstant should be replaced with TIntegralConstant. + +* Any use of WITH_HOT_RELOAD_CTORS should be replaced with the assumption that the value is 1. + +* Any use of the Use VTable Constructors .ini option should be replaced with the assumption that the value is true. + +* Use of generated FName variables for UFUNCTIONs (e.g. ENGINE_ReceiveTick) should be replaced with a string literal or a custom static FName variable in your own code: + + * For example: static const FName ENGINE_ReceiveTick = TEXT("ReceiveTick"); + +* If Unreal Header Tool reports an error about a function having a different signature from a base class, it should be fixed to have the same signature, or renamed. + +#### Editor and Tools + +* Exposed Make Property Combo Box in Property Customization Helpers to allow embedding an enum combo box into Struct Customizations. + +* Added Custom Column support to the Asset Picker Config. + +* If you use a protected platform, your project settings will start to be saved under MyGame\Config\Platform\PlatformEngine.ini, instead MyGame\Config\DefaultEngine.ini. + +#### Platforms + +* Made some big Device Profile changes, particularly for the protected platforms. You may need to modify your Device Profiles in similar ways if you are a heavy user of them. + + * Changed the "type" of some DPs from WindowsNoEditor, etc to Windows. It should be a platform, not a random string. + + * With that change, the platform can be used to save out protected platform DP .ini files to subdirectories, maintaining secrecy. + + * When saving DeviceProfiles, you may need to look in a platform subdirectory for the DeviceProfiles.ini file. + + * Added Config/[PlatformName]/ConfidentialPlatform.ini files so that the DP loading code knows to look in their directories for DPs. See the GetConfidentialPlatforms() function in GenericPlatformMisc for more information. + +#### Programming + +* The TargetRules.ShouldUseSharedBuildEnvironment() function has been deprecated. Targets can now specify the build environment they wish to use by setting BuildEnvironment to TargetBuildEnvironment.Default/Shared/Unique in their constructor instead. + +* The constructor for ModuleRules-derived classes in .build.cs files should be updated to take a ReadOnlyTargetRules instance, which should be forwarded to the base class. This class contains the same properties as the previous TargetInfo argument, plus all the target-specific settings previously stored in the global BuildConfiguration and UEBuildConfiguration classes. Compatibility shims for accessing these objects will be removed in a future release. The WITH_FORWARDED_MODULE_RULES_CTOR preprocessor definition is now defined, which allows writing code which is compatible with multiple engine versions. + +* The TargetRules.SetupBinaries() callback has been deprecated. Instead of overriding this, targets may override the launch module through the "LaunchModuleName" property in their constructor, and add extra modules to the "ExtraModuleNames" field on the TargetRules object itself. + +#### Rendering + +* UE4Editor is whitelisted for Aftermath with latest Nvidia drivers. To whitelist other game executables contact Nvidia. + +* RHICmdList.Clear() methods are now removed; please use RHICmdList.SetRenderTargetsAndClear() or the DrawClearQuad() utility function from ClearQuad.h. + +* The Cross Compiler Tool is now removed from the Engine, it had too many limitations. Use hlslcc.sln or ShaderCompileWorker -directcompile instead. + +* PipelineStateCache.h contains the new replacement interface for BoundShaderStateCache.h. Otherwise, during the Geometry rendering passes the previously introduced Draw Render State is used to collect and set the Blend, Raster, and Depth Stencil State. Commit Graphics Pipeline State will set the PSO for geometry rendering passes. Postprocessing passes or passes which use Globalshaders have to fill out a Graphics Pipeline State Initializer and set this instead. + +* If configuring via .ini files, use the new variable name "ScaleTexturesByGlobalMipBias" where "ScaleTexturesByGlobalMyBias" was used. + +* Mobile: Skylights on mobile projects may need to be recaptured in the editor before packaging. + +* Mobile: Please replace r.TonemapperFilm=1 cvar with r.Mobile.TonemapperFilm=1 in case you want to use new filmic tonemapper on Mobile platforms. + +#### VR + +* PSVR MotionController tracking management system. + + * Blueprint functions added to manage the set of actively motion tracked controllers in MotionTrackedDevice Function Library. + + * You are recommended to disable tracking of all controllers first, and then enable tracking for the controllers you want to have tracked based on user setting, connected controllers, etc. The system keeps a memory of which controllers are set to be tracked even if the controller is disconnected, or not yet connected. + +* Experimental preview of PSVR Social Screen support. + + * The new Morpheus plugin project setting Enable Social Screen Separate Mode must be set to true to use this feature. When that is true additional render and output buffers will be allocated for the Social Screen. + + * Blueprint functions for controlling the feature can be found by searching for 'SocialScreen'. + + * Future work will replace this API with a more flexible cross platform one, and pursue optimizations of SocialScreen output. + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_16/4_16ReleaseNotes.INT.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_16/4_16ReleaseNotes.INT.udn new file mode 100644 index 000000000000..042f7bc9a8e3 --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_16/4_16ReleaseNotes.INT.udn @@ -0,0 +1,3905 @@ +Availability:Public +Title: Unreal Engine 4.16 Release Notes +Description: Release Notes for Unreal Engine 4.16 +Crumbs:%ROOT%, Engine +Parent:Support/Builds +Order:16 +reference-image: image_18.gif +reference-image: image_28.gif +reference-image: image_31.gif +reference-image: image_35.gif + +![](DOCS_BANNER_416.jpg) + +## What's New + +Unreal Engine 4.16 includes exciting **new rendering and animation features**, significant **performance improvements for mobile and console platforms, and tons of quality of life enhancements** that will make it even easier to make stunning environments and engaging experiences that run smoothly on a wider variety of platforms. + +Enhance the mood of your environments using the amazing new **Volumetric Fog** feature, which can be enabled to automatically render realistic fog and smoke effects with consistent lighting anywhere in a scene, even at a large scale. + +Breathe life into your characters using new dynamic **lightweight rigid body** and **low level cloth simulation** tools! Take greater control of the flow of movement using Animation Modifiers, spline IK solver, updated Pose Driver, and many other improvements to the Animation system. + +Garbage Collection is now **twice as fast**! UI rendering performance and UMG widget creation speed are vastly improved to enable you to create even more compelling interfaces. Interfaces and workflows for **VR Mode**, Animation, Sequencer, and other tools have been updated to make your development process more streamlined than ever before. + +Support for **Nintendo Switch** is fully-featured and ready for production in 4.16! Epic Games has teamed up with Nintendo to release the full UE4 source code for Nintendo Switch to approved developers for free. To learn more about how to get started, [read more here](http://www.unrealengine.com/en_US/blog/launch-your-game-on-the-nintendo-switch-with-unreal-engine-4-16) + +**DirectX 12 is now the default renderer for Xbox One**, bringing both performance and feature enhancements to platform support in the engine. In addition, you can now develop HTML5 games using WebAssembly and WebGL 2, and this new path will continue to improve in UE4. + +For mobile, the Android virtual keyboard is now supported, and runtime permissions have been exposed to both Blueprint and code. Plus, we have made even more strides to reduce executable sizes for mobile apps! + +In addition to hundreds of updates shipping from Epic, this release includes **160 improvements** submitted by the incredible community of Unreal Engine developers on GitHub! Thanks to each of these contributors to Unreal Engine 4.16: + +0lento, Akihiro Kayama (kayama-shift), Alice Robinson (Valkrysa), Altrue, Andreas Rønning (Sunjammer), Andrew Gaubatz (e-agaubatz), Angus Jones (crumblycake), Artem V. Navrotskiy (bozaro), Black Phoenix (PhoenixBlack), Cedric Neukirchen (eXifreXi), Cengiz Terzibas (yaakuro), Chris Varnz (chrisvarns), Christopher P. Yarger (cpyarger), Damian Nowakowski (zompi2), DarkSlot, DeanoC, Derek van Vliet (derekvanvliet), devbm, dodgyville, drelidan7, Gabriel Lima (Gabriel-Lima-O), Gyeonghwan (conquests), Hao Wang (haowang1013), Ilya (ill), Jackblue (JohnsonJackblue), James Horsley (mmdanggg2), Jeff Rous (JeffRous), Jon Watte (jwatte), Jørgen P. Tjernø (jorgenpt), jostster, Kalle Hämäläinen (kallehamalainen), katze7514, Kevin Kuegler (FrostByteGER), KrisRedbeard, looterz, Manmohan Bishnoi (manmohanbishnoi), Marat Radchenko (slonopotamus), Markyroson, Martin Treacy-Schwartz (the1schwartz), Matt Edmonds (cleaver404), Matthew Casey (mdcasey), Matthias (haimat), Matthias Hölzl (hoelzl), Matthias Huerbe (MatzeOGH), Michael Schoell (MichaelSchoell), Michał Siejak (Nadrin), Milan Šťastný (aknarts), Moritz Wundke (moritz-wundke), Mustafa TOP (MSTF), Narendra Umate (ardneran), Nathan Stocks (CleanCut), NaturalMotionTechnology, Nick Verenik (nverenik), Paul Murray (awesomeness872), pfontain, Phil Christensen (Rastaban), PrimalJohnScott, projectgheist, Rafael Ortis (rafortis), Rajko Stojadinovic (rajkosto), Rama (EverNewJoy), rhughesgeomerics, Ricardo Rodrigues (RicardoEPRodrigues), Robert Hagglund (hagglund), Robert Segal (robertfsegal), Ryan Pavlik (rpav), sangpan, Sanjay Nambiar (sanjay-nambiar), Satheesh (ryanjon2040), Sean Campbell (scampVR), Sebastian Axinte (ENiGMA9), Sébastien Rombauts (SRombauts), SiebenCorgie, Stefan Zimecki (stefanzimecki), StefanoProsperi, Stephen Johnson (megasjay), TaeYoung Cho (valval88), Timothee Besset (TTimo), Timothy Hagberg (thagberg), Tom Kneiphof (tomix1024), Tom Ward (tomwardio), TRS-justing, unwitherer, Vladimir (VladimirPobedinskiy), Vladimir Alyamkin (ufna), wyhily2010, Yaroslav Shmelev (SoulSharer), yeonseok-yi + +## Major Features + +### New: Volumetric Fog + +Create incredible ambience and mood in your environments using the new Volumetric Fog! Varying densities are supported so you can simulate clouds of dust or smoke flowing through light shafts, and any number of lights can affect the Volumetric Fog. + +![image alt text](image_0.png)(w:929 h:529 convert:false) + +![image alt text](image_1.png)(w:928 h:510 convert:false) + +![image alt text](image_2.png)(w:928 h:510 convert:false) + +Volumetric Fog supports lighting from: + +* A single Directional Light, with shadowing from Cascaded Shadow Maps or static shadowing, with a Light Function + +* Any number of point and spot lights, with dynamic or static shadowing if 'Cast Volumetric Shadow' is enabled + +* A single Skylight, with shadowing from Distance Field Ambient Occlusion if enabled + +* Particle Lights, if 'Volumetric Scattering Intensity' is greater than 0 + +You can use Materials applied to Particle Systems to control Volumetric Fog with the new Volume Domain setting. A single particle with a Volume Material causes a sphere of density to be added to the Volumetric Fog. The effect is fully 3D with no billboards involved. Multiple spherical fog particles with noise from textures can be used to limit fog to a certain area. + +For information on setting up Volumetric Fog, see the [documentation](Engine/Rendering/LightingAndShadows/VolumetricFog). + +### New: Image-Based (FFT) Convolution for Bloom + +Create physically-realistic bloom post-process effects using the new image-based (FFT) convolution feature! Unreal Engine 4.16 ships with a FFT Bloom that empowers artists to use custom bloom kernel shapes, with total control over the intensity in order to match the results they imagine. + +![image alt text](image_3.png)(w:928 h:485 convert:false) + +By using a mathematical convolution of the source image with a kernel image, this bloom technique can produce a continuum of responses ranging from star-like bursts to diffuse glowing regions. The additional realism generated by the image-based convolution is the result of its ability to use visually interesting, non-symmetric kernel images. It generally looks like a star-burst with radial streaks, but could include eyelash silhouettes, bokeh or other artifacts. + +**Note:** Image-based convolution Bloom is designed for use in cinematics or on high-end hardware, while the pre-existing (standard) Bloom should be used for most game applications. + +### New: Distance Field Lighting Optimizations + +**Distance Field Ambient Occlusion** and **Ray Traced Distance Field Shadows** are now **30-50% faster** on current generation consoles and mid-spec PC! These features allow for more realistic ambient lighting and area shadows on dynamic meshes in your scene. + +![image alt text](image_4.png)(w:929 h:513 convert:false) + +In addition, static mesh **Distance Field Generation is 2.5 times faster**, thanks to acceleration from Intel's Embree ray tracing library. Memory usage is also significantly reduced when enabling the Eight Bit Mesh Distance Fields and Compress Mesh Distance Fields project settings. + +### New: Lightweight Rigid Body Simulation + +Create hordes of physically-simulated characters with the new **lightweight rigid body character simulation!** You can now simulate a Physics Asset inside your Animation Blueprint using a new high-performance **immediate mode** PhysX API. Characters using this simulation can also generate collision with static geometry in the world. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + VaxxVsv0Fak + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +### New: Low-level Clothing Simulation + +Gain more control over clothing simulations using the new low-level NVIDIA NvCloth clothing solver! + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 5BqodzWZIUA + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +We have replaced the APEX clothing solver with a lower level solution called NvCloth from NVIDIA. The new solver is similar to the core solver of the previous APEX solution with few slight behavior changes, and it provides better access to the simulation data and extra exposed parameters for inertia settings. + +### New: Release Games on Nintendo Switch! + +Registered developers can now build and release games for the Nintendo Switch! Unreal Engine 4's production-ready Nintendo Switch support is certification compliant, enables networked multiplayer, and provides access to multiple rendering pipelines - deferred, mobile forward, and clustered forward - to enable you to ship virtually any type of game for Nintendo Switch. + +[REGION:raw] +![image alt text](image_7.png)(w:925 h:641 convert:false) +[/REGION] + +### New: VR Mode UI and Interaction Updates + +VR Mode in Unreal Editor has been overhauled to provide a more intuitive workflow and editing experience! + +![image alt text](image_8.jpg)(w:722 h:646 convert:false) + +A new asymmetrical controller setup puts a new and improved Radial Menu on one hand and an interaction laser with improved precision on the other to make working with objects in your level quick and easy. + +All VR Mode actions, including all major editor features and UI panels, are now accessed from the updated Radial Menu. Teleport has been updated so that you can instantly move to a location and resize to the default scale to see the player's perspective as well. For more information, see [https://docs.unrealengine.com/latest/INT/Engine/Editor/VR/GDC2017/](https://docs.unrealengine.com/latest/INT/Engine/Editor/VR/GDC2017/) + +### New: Edit Sequences in VR + +The Sequencer cinematics editor is now available in VR! You can create a new sequence and move objects around your level - and in the process automatically create sequence keys for their transforms. By scrubbing through time and setting these keys, you can create cinematic sequences and play them back, all inside VR. You can also open existing Level Sequences and play them back, either from the Sequencer UI or from the Radial Menu. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + X4Zw9U20Gw4 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +* New! Adjustable keys allow you to physically adjust your trajectories in the world! + +* The Scrub Time option in the Radial Menu takes thumbstick or touchpad input as the speed with which to play your Sequence backwards and forwards. Press the trigger again to exit Scrub Time mode. + +### New: Physics Simulation in VR Mode + +You can now **simulate physics Actors in VR Mode** using the motion controllers to interact with objects! Place Actors set to simulate physics and let the physical simulation run to get a realistic scattering or to knock Actors around with the motion controllers. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + bG2Qf897CBI + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +### New: Smart Snapping in VR Mode + +Smart snapping uses the bounds of your object to align to other Actors in the scene, enabling you to exactly fit them together without needing to build modular assets with a grid in mind. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + lvqxM1kjubE + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +This feature is currently only available in VR Mode, but we'll add support for desktop editing in a future release. + +### New: Xbox One Renders with DirectX 12 + +**DirectX 12 is now the default renderer for Xbox One!** We've made a number of stability and performance improvements in DirectX 12. This allowed us to enable it as the default RHI bringing **CPU and GPU performance improvements** for titles developed for Xbox One. + +![image alt text](image_12.png)(w:556 h:356 convert:false) + +#### Switching back to D3D11 + +Titles that need to switch back to D3D11 will need to do the following: + +1. Modify bBuildForD3D12 in your title's defaultengine.ini + +2. Rebuild your game for Xbox One + +3. Recook content + +**Note:** The D3D11 RHI will be deprecated in a future release. + +### New: HTML5 Support for WebAssembly and WebGL 2 + +Unreal Engine 4 now supports the new WebAssembly standard (also known as WASM) for HTML5, the fastest and most efficient way to compile and run C++ for the web! We are using Mozilla's latest Emscripten toolchain (v1.37.9). This is a new technology and not supported on all browsers, so it is considered an Early Access feature, and requires GitHub access. + +[REGION:raw] +![image alt text](image_13.png)(w:929 h:630 convert:false) +[/REGION] + +WASM is a new JavaScript code-to-binary format for Web apps that reduces app download size, startup times, memory consumption, and provides a big performance boost. For more details on WASM and browser support, head over to [http://webassembly.org/](http://webassembly.org/) + +UE 4.16 also adds support for WebGL 2.0 which is based on OpenGL ES 3.0 and provides more optimal rendering performance, increased visual fidelity, and support for more rendering features, including: + +* Most features of UE4's high-end mobile feature level + +* Instanced Geometry Drawing for particles and foliage + +* Support for Multiple Render Targets (MRTs) + +* Texture features such as 3D or volume textures, 2D array textures, and no more non-power-of-two texture restrictions + +WASM and WebGL 2.0 are supported by Firefox 52 and Chrome 57 or later (64-bit recommended). Note there appears to be a bug in Chrome 58 on Windows that is causing out-of-memory errors in some cases. We are working with Google to get this issue resolved. Please see [UE-44727](https://issues.unrealengine.com/issue/UE-44727) for the latest status on this issue. + +You can enable WASM and WebGL 2.0 in the Emscripten section of the HTML5 Project Settings. If you require the broadest browser support possible, continue to use ASM.js and WebGL 1. *Support for ASM.js and WebGL 1 will be deprecated in an upcoming engine release, and then removed afterwards (exact timing is dependent on additional browser support).* + +For a LIVE DEMO: [try out Zen Garden on HTML5](https://hacks.mozilla.org/2017/03/firefox-52-introducing-web-assembly-css-grid-and-the-grid-inspector/) to see these benefits first-hand in your own Firefox or Chrome browser (supported versions listed above). + +### New: 2x Faster Garbage Collection + +Garbage collection performance has been significantly improved and is now **more than twice as fast!** Specific improvements include: + +* Reachability analysis multithreading has been redesigned to reduce the overhead of task management. + +* Garbage Collection clustering now supports Blueprint-generated classes and selected Actor types. + +* UObject unhashing code has been optimized to reduce the time spent destroying Actors. + +### New: Kinematic Bodies with Simulated Parents + +We've added the ability to have kinematic physics bodies with simulated parents. You can now have child bones, such as the character's hands, purely driven by animation data, while the parents of those bones can also be driven by physics simulation data. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + qiiOU_fhex0 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +This enables cool effects such as the player scaling a ledge reacting to falling rocks colliding with its body! + +### New: Platform SDK Upgrades + +In every release, we update the engine to support the latest SDK releases from platform partners. + +[REGION:raw] +![image alt text](image_15.jpg)(w:929 h:522 convert:false) +[/REGION] + +* **Visual Studio: ** Important: Visual Studio 2013 is no longer supported on Windows with this release. Please upgrade to either Visual Studio 2015 or Visual Studio 2017. + +* **Nintendo Switch:** supports Nintendo SDK 1.3.1 + +* **Xbox One:** Built against the October 2016 QFE3 XDK + +* **PlayStation 4:** Upgraded to PSR SDK 4.508.001 SDK + +* **Android:** Updated CodeWorks for Android 1R6u1 + +* **GoogleVR:** Updated plugin to version 1.3 + +* **GoogleVR:** SDK updated to 1.40.0 + +* **GoogleVR:** Mode default changed to Daydream & Cardboard + +* **Vulkan:** Updated distributables and glslang to SDK 1.0.39.1 + +### New: Sequencer Shot Track Enhancements + +Shot Tracks in Sequencer gain several improvements for both cinematics and film creation! + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + GqfJxD1DY8I + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +* **Hierarchical bias per shot:** By default, tracks at a lower level in the level sequence hierarchy take precedence. This allows filmmakers to build a pipeline they're accustomed to, where adjustments at the shot override tracks in the sequence they're contained in. + +* **Exposed "When Finished" property for all tracks:** This gives the user the ability to specify whether tracks should return values to their pre-animated state or keep them when the sequence finished. In a film production environment, you would typically want animated values in a shot to return to their pre-animated state so that they don't bleed into the next shot. In a cinematic, you might want the value to persist so that you could continue into the game from the sequencer animated state. + +* **Pre/post roll:** Pre and post roll is now a general concept for all tracks. Some tracks have specific behaviors, for example the camera cuts track will notify the streaming system with the upcoming camera cut position in the pre-roll evaluation period. + +### New: Animate Material Parameter Collections in Sequencer + +You can now animate Material Parameter Collections in Sequencer giving you total control over animating scalar and vector parameters which can be referenced in any number of Materials. You no longer have to animate individual parameter values on each material instance in order to share animation. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + u_Cpqz7mFuM + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +### New: Improved UI Rendering Performance + +Games that use Invalidation Panels now have an option to cache only widget elements rather than render data, enabling them to benefit from much improved texture batching and significantly reduces draw calls. The result is a big performance boost on mobile devices! + +[REGION:asyncgif] +![image alt text](image_18.gif)(w:456) +[/REGION] + + +On the Battle Breakers hero selection UI (shown above), each hero's logical elements are cached but can also be batched together. The console variable Slate.CacheRenderData=0 enables this mode, which is now the default on mobile devices. + +### New: Improved Animation Pose Driver + +We have made many improvements to the Pose Driver feature, which enables you to procedurally drive blend shapes or bones, by comparing the pose of a set of bones to a set of reference 'targets'. This is particularly useful for areas like shoulders, where you may want to activate corrective morph targets depending on the pose of the upper arm and shoulder. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + sjtbvyDdW9w + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +* You can now select multiple bones as 'inputs' to read a pose from + +* You can now pick which bones should be modified by the node + +* You can specify a 'custom curve' for how each target should be activated + +* Can choose to drive curves (morphs, material) directly, instead of needing a Pose Asset + +* UI is improved to allow creation/editing of target poses, bars to show target activation, etc. + +* Target locations in viewport can now be clicked to select them + +### New: Opacity and Opacity Mask for Material Flattening + +We have added support for **baking out opacity (mask) values** when using the Actor Merge Tool or Hierarchical LOD system. The resulting (instanced) material uses your configured blend mode to ensure it follows the correct render path. Here's an example of a baked out masked material: + +![image alt text](image_20.png)(w:904 h:740 convert:false) + +### New: Improved Mesh Paint Tool + +The mesh painting system has been overhauled to improve usability and clarity, and to allow for reusing the functionality in other parts of the Editor. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + UezYKhase9g + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +Also, the painting tools can now be used on skeletal meshes! Note that painting is *not* per-instance (as with static meshes) but is applied directly to the skeletal mesh asset(s). + +### New: Spline IK Solver + +A spline IK node that is useful for controlling character spines or bone chains has been added to Animation Blueprints! + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + chqOk4QdPR0 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + + +### New: Detect Material on Mesh Surfaces + +We've added a new 'Get Material From Face Index' function for Components which enables you to retrieve the Material applied to a Component after performing a (complex) Line Trace. This is supported for Static Meshes, Procedural Mesh Components, and BSP. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + SvsSnkwB1TQ + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +### New: 'Look At' Animation Node Improvements + +The **Look At Location** property of a Look At node can now be used relative to a bone or socket. Previously this value was ignored when you specified a bone or socket. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 3C7Q6JJxmtY + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +The visualization for Look At controls is also improved. For example, you can see the clamp angles, target location, interpolation and so on. + +### New: Animation Export Improvements + +We added support for creating and exporting animations that include additional animation data generated from a post-process graph assigned to the Skeletal Mesh, such as Anim Dynamics for physics simulation. + +To include this additional data, choose **Preview Mesh** from the **Create Animation** or **Export Animation** menus. + +![image alt text](image_25.png)(w:697 h:256 convert:false) + +### New: Unreal Audio Engine (Early Access Preview) + +The new Unreal Audio Engine announced at GDC is available in early access on PC, Mac, iOS, Android, and Switch. It includes a cross-platform audio mixer with full backwards-compatible support for the existing audio engine feature set, including a new multiplatform EQ and Reverb master effects. In addition, the new Unreal Audio Engine introduces new features such as a submix graph, submix effects, source effects, real-time synthesis, and better audio plugin support. + +The new Unreal Audio Engine is not enabled by default in 4.16 as there is continued work on implementing backends for console platforms, Linux, and HTML5, as well as stability and performance improvements, especially on mobile platforms. + +To enable the audio mixer, use the command line argument "-audiomixer". + +Note: Most new Unreal Audio Engine features are hidden if you launch the editor without the audio mixer enabled. + +#### New: Synthesis Plugin (Early Access) + +The new synthesis plugin contains two new real-time synthesizers written using the new Unreal Audio Engine's "SynthComponent" class to implement a fully-featured subtractive synthesizer as well as a real-time granulator. These new synthesizers are not only useful tools for procedural music and sound design, but they serve as an example of how third-party plugin manufactures and even sound designers might implement their own synthesis. + +The synthesis plugin also contains a host of new DSP source and submix effects for use with the new Unreal Audio Engine: + +* **Source Effects:** Stereo Delay, Bit Crusher, Dynamics Processor, Envelope Follower, EQ Filter, Virtual Analog Filter (Ladder/State Variable), Wave Shaper, Chorus, Phaser + +* **Submix Effects:** Reverb, EQ, Dynamics Processor + +### New: Steam Audio (Early Access) + +Epic and Valve have teamed up to release the first fully-integrated implementation of the Steam Audio SDK using the new capabilities of the new Unreal Audio Engine. + +![image alt text](image_26.png)(w:600 h:160 convert:false) + +Steam Audio fundamentally integrates with the new Unreal Audio Engine's spatialization, occlusion, and reverb systems to bring next-gen physics-based audio experiences to UE4 for VR. This is an early access version of Steam Audio with significant updates, more example projects, and workflow improvements planned for 4.17. Epic and Valve welcome any feedback, questions, or ideas for improvements. + +See [https://valvesoftware.github.io/steam-audio/](https://valvesoftware.github.io/steam-audio/) for more information, documentation, and support help about Steam Audio. + +### New: Improved Color Grading Tool + +The Color Grading user interface is improved to make it easier to use! + +![image alt text](image_27.jpg)(w:529 h:257 convert:false) + +* A new HSV mode was added. + +* You can now dynamically change the min/max value of the sliders depending on their type using Ctrl+Slider Drag. + +* A new reset button was added to reset a whole color grading category. (i.e Global, Shadows, Midtones, Highlights) + +### New: Improved Animation Blend Space Editor + +The Blend Space Editor now enables you to display Animation names for each sample using the **Show Animation Names** button inside of the grid. You can now also drag and drop animations on top of existing samples to replace them. + +[REGION:asyncgif] +![image alt text](image_28.gif)(w:905) +[/REGION] + +### New: String Tables for Localization + +UE4 now has support for localized String Tables! + +![image alt text](image_29.png)(w:601 h:218 convert:false) + +String Tables provide a way to centralize your localized text into one (or several) known locations, and then reference the entries within a string table from other assets or code in a robust way that allows for easy re-use of localized text. String Tables can be defined in C++, loaded via CSV file, or created as an asset. + +### New: Animation Modifiers (Early Access Preview) + +Animation Modifiers enable you to apply a sequence of actions to a given Animation Sequence or Skeleton, such as pin-pointing on which frame(s) the right foot is placed on the ground and adding Animation Sync Markers to the frames where the ball_r bone is at its lowest point (touching the floor). + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + YC_UJuO9AI8 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +A new set of functions to access specific animation data are available in the Animation Blueprint function library. Accessing and applying Animation Modifiers is done through a new tab which can be found in the Skeleton Editor and Animation Editor. Animation Modifiers can be added to a Skeleton or Animation Sequence. For Animation Sequences, the Animation Modifier is only applied to the sequence itself. When applied to a Skeleton, it is applied to all Animation Sequences which are based of the Skeleton. + +### New: Virtual Keyboards on Android (Early Access Preview) + +Android now supports using the operating system's virtual keyboard in place of the popup dialog input box! + +[REGION:asyncgif] +![image alt text](image_31.gif)(w:256) +[/REGION] + + +Use of the virtual keyboard is enabled by checking the checkbox under **Project Settings > Platforms > Android > APK Packaging**. This option enables basic support for the virtual keyboard, but your application is responsible for ensuring input elements are visible and not obscured behind the virtual keyboard using the supplied OnVirtualKeyboardShown and OnVirtualKeyboardHidden event handlers. + +**Note:** You may wish to disable the virtual keyboard with the Android.NewKeyboard console variable when the user is using a language requiring IME. + +### Support for Runtime Permissions on Android + +Unreal Engine 4 now supports Runtime Permissions as required by Android 23 and later to access features requiring permissions categorized as dangerous by Google. These include access to contacts, photos, phone state, external storage, camera, and location services. See this webpage for details: [https://developer.android.com/guide/topics/permissions/requesting.html](https://developer.android.com/guide/topics/permissions/requesting.html). + +If targeting Android 23, the Android Runtimes Permission plugin now provides the ability to check at runtime in native code or by using the **Check Android Permission** Blueprint node if a permission is already granted. If the permission has not yet been granted, the app may request it from the user using the **Request Android Permissions** Blueprint node and then get the result using an event bound to **On Permissions Granted Dynamic Delegate**. This allows permissions to be granted just before the game requires functionality needing a permission, improving the user experience. When targeting versions prior Android 23, permissions are granted by specifying them in the Android Manifest as usual. + +![image alt text](image_32.png)(w:718 h:346 convert:false) + +**Note:** 4.16 requires Android SDK 23 or higher to be installed. If you don't have this SDK level installed, you can find the CodeWorksforAndroid-1R6u1 installer in your Engine/Extras/AndroidWorks directory. Also, under "Project Settings", “Android SDK”, please change your Android SDK API Level from “matchndk” to “latest”. This will ensure UE4 will use the newest installed SDK found in your Android SDK platforms directory. There is no need to change the NDK API Level; “android-19” is correct to allow installing your APK on Android versions prior to Lollipop (Android 5.0); setting this higher will cause your app to require Android 5.0+. + +### Shader Code Library to Reduce Package Size + +You can now enable a shared storage location for all shader code using the **Share Material Shader Code** project setting, resulting in a single copy being stored for Materials or Material Instances that generate the same shader code. + +Some platforms such as Metal on iOS, TVOS and MacOS support a more efficient platform-specific shader library. Enabling the **Shared Material Native Libraries** project setting will further reduce the package size by utilizing this native library format. + +### New: Import Capsule Collision from FBX + +You can now import capsule simple collision from an FBX file, in the same way you could already import box, sphere, and convex simple collision. You now use the 'UCP' prefix on a capsule poly mesh, and it will be removed on import, and replaced by a corresponding capsule collision shape. + +### New: Separate Options for Shared vs Local Asset Viewer Profiles + +Unreal Editor now enables you to store asset viewer profiles on a shared or local level, making it possible for teams to have a shared set of profiles which can be used as a unified scene to assess art assets. Storing profiles at a local level ensures that a user can still have a custom set of profiles he prefers to use local but are not required by the team. Shared profiles are stored in *DefaultEditor.ini* and will require you to check out or make it writable. + +### New: Improved Animation Preview Scenes + +We made several improvements to preview scenes for the Animation Tools: + +* Preview scene settings have been moved to the existing settings tab, rather than in a hidden menu in the viewport. This settings tab is now shown by default. + +* Added a shortcut to quickly switch preview mesh to the main toolbar. This applies to all animation editors. + +* When editing preview scenes, you no longer have to create a "preview scene collection" asset just to preview extra meshes. If you are happy with your mesh setup you can now optionally save it to an asset. + +### New: Add Default Camera options to Anim Viewer + +You can now save a 'Default Camera' position for a Skeletal Mesh. This is used when opening the mesh, and can also be jumped do by pressing Shift+F. + +### New: Play Montage Blueprint Node + +**Play Montage** is a new asynchronous node which can be used in any Blueprint logic to play Anim Montages. It provides easy access to some callback events, letting you trigger other nodes when a montage blends out, is interrupted, etc... + +![image alt text](image_33.png)(w:376 h:272 convert:false) + +* OnCompleted is called when the Montage finishes playing and it fully blended out. + +* OnBlendOut is called when the Montage is starting to Blend Out, either because it's stopping automatically or manually. + +* OnInterrupted is called if the Montage is starting to Blend Out, but because it's been interrupted by another Montage playing. + +* OnNotifyBegin and OnNotifyEnd are callbacks when using either 'Play Montage Notify' or 'Play Montage Notify Window' Anim Notifies in the Montage asset. These AnimNotifies can forward an additional 'Notify Name' to differentiate between multiple callbacks from the same Montage. + +### New: Added Options For Retargeting Poses + +You can now import a pose from a Pose Asset to use when setting the Retarget Base Pose. Previous options of modifying and saving the current pose (Use Current Pose) and of resetting bone transform to reference pose (Reset) are still available as well. + +**Note:** You can create Pose Asset in the animation editor and insert any pose to the pose asset with a name assigned. + +### New: Collision View Option In Static Mesh Editor + +There are now separate options for viewing Simple and Complex Collision for a StaticMesh in the StaticMesh Editor tool. + +### New: Baked Poses in LODs + +Unreal Engine 4 now supports baking a pose into a LOD level using a new reduction setting called Bake Pose. This can be set to a single frame anim sequence which will be applied to the resulting LOD mesh. This can prove useful when removing bones and still wanting to retain a pose. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 0fcNitNu9FE + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +**Note:** This feature requires Simplygon + +### New: Sequencer User Interface Improvements + +Thumbnails for Audio Tracks now render the peak samples with an inner (smoothed) RMS curve. Audio Tracks can also be resized vertically! + +[REGION:asyncgif] +![image alt text](image_35.gif)(w:929) +[/REGION] + + +Other Sequencer UI Improvements: + +* Sequencer controlled actors will now tick properly when streamed into a level. + +* You can now specify additional event receivers (ie. actor blueprints) for the event track. + +* Bindings improvements. You can now drag/drop/set bindings for the level sequence in blueprints. For example, you can spawn an object in blueprints and assign that to an existing track. + +### New: Mobile VR Rendering Improvements + +Direct multiview is now supported for Samsung Gear VR, removing an extra render target and full screen copy when using mobile multiview which improves overall performance and reduces memory usage. + +Monoscopic far field can now be used with multiview enabled on Gear VR ensuring the stereo rendering portion of your scene is rendered optimally. + +Google Daydream supports standard mobile multiview with direct support coming in a future release. + +### New: Social Screens for PlayStation VR (Early Access Preview) + +PSVR Social Screen preview provides support for Social Screen separate mode, where the the Monitor and HMD display different things. + +This preview supports 30fps Social Screen output, and switching between several output modes. The following sample modes are implemented: + +* SystemMirror (this is the default mirror mode that has always existed). + +* SeparateTest (simply alternates between black and white on the social screen). + +* SeparateTexture (displays a blueprint specified texture, for example a render target beting written to by a scene capture component). + +* SeparateMirror (displays the full vr render buffer) + +Future work will include optimization, a multi-platform interface to these features, possibly support for 60fps mode (which requires system dialogs to resolve conflicts with certain system features). + +The new PSVR project setting bEnableSocialScreenSeparateMode must be set to true to use this feature. When that is true additional screen buffers will be allocated for the social screen. Blueprint functions for controlling the feature can be found by searching for 'SocialScreen'. + +### New: Android Executable Size Reduction + +We have made a number of optimizations to the compiler and linker settings to reduce the size of the Android binary executable. Checking the **Build with hidden symbol visibility** option allows the linker to more aggressively remove unused code from Unreal Engine when generating the Android executable. This also strips the function symbols from the symbol table further reducing the executable size. We are seeing reductions of around 7MB from the final APK. + +**Note:** This option removes symbols from the binary on the device, so a native crash call stack will appear in the logcat output without any symbols. To facilitate debugging, the build system will also copy an unstripped binary with debug symbols to the output directory, and also generate a batch file that adds symbols to a call stack. + +### New: Vertex Interpolator Material Expression Node + +Vertex Interpolator nodes have been added to the Material graph offering better control for value interpolation between vertex and pixel work. These are intended as a workflow improvement, there are no changes to interpolator limits nor will shaders change. + +The existing workflow for offloading work to a vertex shader is by making use of the Customized UV outputs. This can be a little cumbersome and involves manually packing your data. The example material below packs the pre-skinned mesh data then unpacks it for use in an effect: + +![image alt text](image_36.png)(w:766 h:665 convert:false) + +The new interpolator node handles packing automatically, allowing the graph to be simplified and in-lined: + +![image alt text](image_37.png)(w:776 h:357 convert:false) + +Work that would previously be packed through Customized UVs is hooked up to the VS (vertex shader) pin and retrieved from the PS (pixel shader) pin. + +The material stats output has been updated to show the current interpolator usage, both currently packed and available maximum. Note how in the above examples the instruction counts and interpolator usage remain constant. The stats show 2 scalars are reserved by the TexCoord[0] node and the remaining 6 by our pre-skin data, giving a total of 8 scalars packed across 2 vectors. + +The feature is compatible with Customized UVs and will pack results together. + +### New: Asset Management Framework (Early Access Preview) + +The Asset Manager is a new global object that can be used to discover, load, and audit maps and game-specific asset types in the editor or at runtime. It provides a framework to make it easier to create things like quests, weapons, or heroes and load them on demand. It is is still under active development, and these features will not be ready to be used by Blueprint-only games or inexperienced developers until 4.17. The Asset Manager tab in Project Settings can be used to set up the rules for your game: + +Primary Asset Types that are scanned by the Asset Manager can be queried at runtime before they are loaded, and can then be asynchronously loaded on demand. Also, the Asset Manager settings can be used to set up cook and chunk rules when packaging and releasing a game. In progress documentation for this feature is available on AnswerHub: [https://answers.unrealengine.com/questions/595580/what-is-the-asset-manager.html](https://answers.unrealengine.com/questions/595580/what-is-the-asset-manager.html) + +### New: Asset Audit Window (Early Access Preview) + +Built on top of the Asset Management Framework, the Asset Audit window can be used to audit disk size, memory usage, and general asset properties for many assets at once. It is a specialized version of the Content Browser, and can be accessed from the **Window > Developer Tools** menu, or from the right-click menu in the Content Browser or Reference Viewer. Once you have opened the window, assets can be added using the buttons, and platform data loaded out of cooked asset registries can be loaded using the platform drop down. Here's an example of auditing textures from the Shooter Game sample on PS4: + +![image alt text](image_38.png)(w:929 h:289 convert:false) + +### VR: Unified Console Commands for VR + +We've consolidated and unified console commands across VR platforms to create a shared layer that developers can work from rather than maintaining each platform independently. + +This provides several benefits: + +* Bootstrapping new platforms is easier. + +* Argument meanings across HMDs are more consistent. + +* Current HMD implementations have less redundancies. + +* All VR-related console commands share a common prefix, "vr.". Vendor-specific extensions are clearly marked as such in the command name itself. + +* The updated console commands support tab completion and inline usage help texts. + +During a transition period, the old console commands will still be recognized, but will issue a deprecation warning when used. + +### Custom Hardware Cursors + +Platform native custom hardware cursors are now supported on Windows, Mac and Linux! You can set up the hardware cursors to use in the UserInterface settings for the project. + +The system allows you to provide multiple formats for the cursors. For instance, in the settings you could specify you want the "Slate/FancyPointer" to be your default pointer. In the Slate directory of your game's content folder, you could have a FancyPointer.png + .cur + tiff, to cover the multiresolution capabilities of certain platforms. The tiff would be loaded on Mac, the cur/ani file would be used on Windows, and in case a platform specific format is not found that we support, we look for a png. + +### Fast CreateWidget + +UMG widget creation is now up to 3 times faster! When cooking, the widget compiler now generates a widget template/archetype that is stored in the same package as the generated Blueprint Class and used during widget creation. + +**Technical Details** + +During compiling, we generate a nearly fully initialized widget tree including all sub User Widgets and their trees, hookup all member variables, initialize named slots, setup any animations, etc. This nearly fully constructed widget can be instanced using it as an archetype, and does not have to use the correspondingly slow StaticDuplicateObject path. + +There are restrictions on this method, part of the compiling step for widgets now inspects if the instancing would be successful, or if there would be GLEO references after instancing because a user forgot to setup Instanced on a subobject property. Luckily that should be few and far between since all UVisuals (Widgets & Slots) are now DefaultToInstanced, which takes care of the overwhelming cases that demand the instanced flag. Especially given the bulk of cases using BindWidget in native code. + +## Release Notes + +### AI + +* New: Added a profiler for Environment Query System (EQS) that can be accessed through the tabs of the EQS Editor. + + * It collects data automatically during game sessions as long as UES_EQS_DEBUGGER define is set. This includes options for average and max execution time of each step (including breakdown of composite generators), number of items processed by each step, and average frequency of running, which can be useful to identify how often fail safes are actually running. + + * It collects tick load data when USE_EQS_TICKLOADDATA define is set. Each query can store up to 16384 records in cyclic buffer (~4.5 minutes at 60 FPS) showing percentage of EQS tick spent on processing it. This is displayed on the graph in EQS editor tab. + + * A console command has been added, "DumpEnvQueryStats", that saves current EQS profiler data to a file (project's Logs folder, .ue4eqs extension), which can be later loaded and inspected in the EQS Editor. + +* Bugfix: Fixed an issue with Blackboard Key Selector's "Init Selector" that resulted in it picking the first value from the Blackboard rather than the appropriately typed one. + +* Bugfix: Gameplay Task Resource's Auto Resource ID initialization is no longer cleared during Hot Reload. + +* The "Get AI Controller" is now a pure Blueprint Function. + +* Exposed Brain Component's "Is Running" and “Is Paused” functions to Blueprint. + +* Clamped AI Sight's peripheral vision angle as well as changed the UI to not allow values outside of the 0-180 range. + +* Disabled collision on Nav Modifier Volumes. Previously they had an 'Overlap All' response and generated overlap events. They are only supposed to be used for preventing navmesh generation, but overlap events could affect gameplay and are also bad for performance. + +* Made "Skip Agent Height Check When Picking Nav Data" option ignore height when picking nav data for agents. It now picks solely based on the radius when this is enabled. + +#### Behavior Tree + +* Bugfix: Added safeguards to prevent crashes resulted from Blackboard keys being names being longer than 1024 characters. + +* Bugfix: Fixed an issue in dynamic Behavior Tree injection that was causing unexpected behavior when the main BT had more BT injection points. + +* Bugfix: Fixed an issue in Blackboard key instantiation that resulted in the instanced key never being used and BB operations always referring to the original BB entry. + +### Debugging Tools + +* The Gameplay Debugger's input detection has been adjusted so that Tap and Hold work correctly in fixed timestep mode. + +### Navigation + +* Added a flag to Recast Navmesh, "Allow Nav Link As Path End", that is used to control whether path corridors can end on a navigation link or not. This may happen with partial paths and not usually desired behavior. Navigation links at the end are not allowed by default. + +* The Blueprint functions "Project Point To Navigation", “Get Random Reachable Point In Radius”, and “Get Random Point In Navigable Radius” all return booleans determining if the projection/generation was successful, as well as the vector value that describes the requested point. + +* Bugfix: Fixed a memory leak in navmesh generators. + +* Bugfix: Fixed an issue that resulted in losing user settings in Static Mesh's navigation export (Nav Collision object) after changing any property of the Static Mesh. + +* Bugfix: Hand-placed AI pawns now get their Path Following Component's "My Nav Data” variable set properly. + +* Bugfix: Fixed an issue with missing update of navigation area after duplicate or undo operations on Nav Link Proxy and Nav Link Component. + +* Bugfix: Corrected the handling of path following requests by Floating Pawn Movement. + +* Bugfix: Fixed an issue with parameters of geometry trace handling drop-down navigation links. All components blocking on ECC_WorldStatic channel will now report a valid hit. + +* BugFix: HLOD's navigation collision exporting no longer causes unnecessary log output about NavCollision instances in cooked builds. + +#### Animation + +* New: You can now rename Virtual Bones. + +* New: You can now change Virtual Bones so that you can have a Virtual Bone that is a child of another Virtual Bone. + +* New: Added "Get Body Target Transform" to the Physical Animation component, which will return the goal transform that a particular body is trying to get to. + +* New: Control rig Sequences can now be exported to Anim Sequences. + +* New: Preview Scene settings have been exposed in the existing settings tab rather than in a hidden menu of the viewport. + +* New: Support for "Curve Source" nodes to find source components on other Actors. It now searches for the property name rather than the component name. + +* New: Added "Set Preview Mesh" to the toolbar for all animation related Editors. + +* New: Updated Alembic Third-party libraries to the latest versions. + +* New: Added functionality to try and match in-engine Material asset names to FaceSet names found inside of an Alembic cache to automatically assign the correct Materials. + +* New: The Alembic Importer now supports Vertex Color data. + +* New: Added functionality to inform about changes to source data when reimporting your animation data from FBX. It now checks for the following: + + * Whether or not the sequence length has changed. + + * Whether or not previously-imported curves exist in the source data. + +* Bugfix: Fixed a crash when trying to implement a function in a child Anim Blueprint. + +* Bugfix: Fixed a crash when debugging a null Animation Sequence. + +* Bugfix: Trying to access a skinned vertex position on a mesh when using Master Pose component no longer crashes. + +* Bugfix: Attempting to bind to Skeletal Mesh with Anim Blueprint already set no longer crashes. + +* Bugfix: Fixed a crash and effector selection issue for two-bone IK. + +* Bugfix: Right-clicking the empty space in the asset shortcut drop-down no longer crashes. + +* Bugfix: Removed an ensure (warning) by reverting to default unit vectors if zero-sized lookat/lookup vectors are specified for a "Look At" node. + +* Bugfix: Removed a crash when clearing an animation of a 1D blendspace sample. + +* Bugfix: Crash fix to import code for Alembic Caches with the HDF5 backend. + +* Bugfix: Fixed an issue when adjusting curves in the Anim Curves tab using a slider when they are not currently selected. + +* Bugfix: Fixed an issue with Update Rate Optimization update rate being too high. Now we use int, so if you have a high update rate it still can go until it wraps around. + +* Bugfix: Child Anim Blueprints can now be retargeted. + +* Bugfix: Fixed flipping transforms when mirrored. + +* Bugfix: Post Process instances are now appropriately updated, even when the main Anim Instance is not using parallel update. + +* Bugfix: Fixed an issue where running the Editor in a different culture could break pins on nodes that have optional arrays of pins (ie. Animation Graph nodes like Blend By Layer). + +* Bugfix: Fixed an issue with Anim Class being set by name, causing duplicate-named Anim Blueprints to be incorrectly resolved. + +* Bugfix: Fixed an issue where "r.SkeletalMeshLODBias" was affecting meshes in the Animation Editor viewports. + +* Bugfix: Fixed an issue with Animation Preview Scene keyboard binding (I and O hotkeys now hide and show scene elements regardless of tab opened state). + +* Bugfix: Skinned Mesh LOD now updates in the editor under various physics-related circumstances. + +* Bugfix: Fixed an issue with foot placement IK doing line traces on worker threads. + +* Bugfix: Fixed an issue with Anim Blueprints that contain State Machines having blank palettes. + +* Bugfix: Renaming curves in animations now saves properly. + +* Bugfix: Fixed an issue with two-bone IK flickering around full extension when stretch is enabled. + +* Bugfix: Animation now works as expected for dynamically-bound wheeled-vehicle anim instances. + +* Bugfix: Fixed an issue where you could not undo changes from Alembic Import settings. + +* Bugfix: Fixed timing issues occurring while playing back Alembic caches. + +* Bugfix: Fixed an issue with incorrect behavior occurring when placing more than three samples in a straight line for a 2D blendspace. + +* Bugfix: Dropping a new Animation asset on an existing Sequence Player node can now be undone. + +* Bugfix: Breaking transition node connections within Animation State Machines can now be undone. + +* Bugfix: Fixed an issue to ensure that changes to animation sync markers are propagated to currently open blendspace assets. + +* Bugfix: Skeletal Mesh components tick properly when paused if "Tick Event When Paused" is enabled. + +* Bugfix: Fixed Skeletal Mesh Merge duplicating Skeletal sockets. + +* Enabled snapping for translation in the Animation viewports. + +* Removed force inline from Virtual Compression functions. + +* Removed the AnimGraph module from the Graph Editor as a dependency. + +* Bone Reference now has improved performance by caching compact post bone index. + +* Graph files have been moved to Animation Blueprint Editor. + +* We have stopped saving raw curve data into animations on cook in order to save memory and disk space. + +* Ticks now appear properly on Anim Sequence scrub bar. + +* Persona now depends publicly on Skeletal Editor. + +* Montages are now correctly initialized when created. They can be used straight away without first opening them in the Montage Editor. + +* We now propagate thread safety flags to child Animation Blueprints. + +* The Anim Notify Blueprints now start with a "received notify" event node. + +* Made single-node animation instances request clothing simulation resets when their animation is changed. This is because the new animation could be very different from the outgoing animation, and this might cause pops. + +* Refactored "Evaluate Bone Transforms" to prevent usage of Skeletal Mesh component. + + * Deprecated "Evaluate Bone Transforms" in favor of new “'EvaluateSkeletalControl_AnyThread”. + + * Deprecated Skeletal Mesh component argument to "Convert CS Transform To Bone Space" and “​Convert Bone Space Transform To CS”. Now they just take a transform. + +* When selecting bones that are non-required, we now do not render gizmos or text labels. + +* Skeletal selection does not lag behind choice made in the viewport (i.e. when showing bone weights). + +* Added accessor and modifier functions for "Start Time Offset" value in Geometry Cache components. + +##### Animation Assets + +* New: You can now choose a preview slot in the Montage Editor. + +* Bugfix: Fixed a crash when reimporting animations with additive transform tracks. + +* Bugfix: Fixed an issue with additive Pose Asset preview being applied twice. + +* Bugfix: Compressed animation data is now included in Memory Stats for Animation Sequences. + +* Bugfix: Fixed an issue where blendspace interpolation settings would not have a direct effect and required reopening the blendspace asset. + +##### Animation Blueprint + +* New: Added "Spline IK" node. + +* New: Added a property to Blendspace Player nodes that enables users to choose whether the play time is reset when the blendspace changes. + +* New: Animation Blueprints can now specify a Preview Mesh. + +* New: Added the "Look At" node so you can use “Look at Location” on a socket or joint, and improved the Visualizer. + +* Bugfix: Fixed a crash when "Pose Asset" contains a bone that is not in the mesh. + +* Bugfix: Fixed an assertion that could occur when selecting certain items in the Animation Blueprint editor. + +* Bugfix: Fixed a crash when diffing State Machine Transition graphs. + +* Bugfix: Fixed an issue with "Pose Handler" using mesh bone index and not compact bone index for setting up “Bone Blend Weights” array. + +* Bugfix: Fixed an issue with incorrect errors on compiling Aim Offset nodes with exposed blendspace pins. + +* Bugfix. Fixed an issue with additive nodes breaking the current pose when they have no additive animation attached. + +* Bugfix: Fixed issues pertaining to extra references to Animation Blueprints on Skeletal Mesh components. + +* Layered Bone Blend node has been optimized so that it will cache mask weights in compile time. + +##### Import/Export + +* Bugfix: Fixed a crash when reimporting a Skeletal Mesh that has Virtual Bones. + +##### Skeletal Mesh + +* Bugfix: Fixed a crash when using re-import button in the Skeletal Mesh Editor. + +* Bugfix: Fixed a crash related to Skeletal Mesh resources not being initialised before component is registered. + +* Bugfix: Fixed a serialization mismatch in Skeletal Mesh source buffers. + +* When importing a Skeletal Mesh, "Activate Bone Indices" now always includes parents even if it's not skinned. + +#### Tools + +* Bugfix: Fixed a crash in Persona when rotating a bone due to single bone controllers not being initialized correctly. + +* Bugfix: Fixed an ensure when deselecting bones in Anim Blueprint editor. + +* Bugfix: Fixed an issue where mesh-customized sockets were not showing up by default in 'Active' socket filter mode. + +* Bugfix: Fixed issues related to bone removal in Skeletal Mesh LODs. + + * Issue where the "Apply" button would not show after adding bone names. + + * Issue where previously removed bones would not be restored. + + * Ensure that the Skeletal Tree is updated when bones are removed or restored. + +* Double-clicking animation assets in Content Browser will now try to re-use existing Animation Editor windows, rather than opening a new one every time. + +* Animation picker on Skeletal Mesh component is now disabled rather than hidden when no Skeletal Mesh is assigned. + +* The Soundwave-internal curve tables have been moved to the 'Advanced' rollout. + +#### Audio + +* New: Vorbis-encoded audio files can now be streamed. + +* New: Audio streaming is now supported on Android, iOS, and XBox One. + +* Bugfix: Fixed a shutdown crash when there is a pending async audio occlusion trace. + +* Bugfix: Fixed a crash when opening a Media Sound Wave. + +* Bugfix: 'Sound Player' nodes will more efficiently load the referenced sound asset unless a 'Sound Quality' node is being used to select which 'Sound Player' nodes to consider, in which case, the current asset reference evaluation will continue to be used. + +* Bugfix: We only queue subtitles once per-wave instances playback. + +#### Automation + +* New: Added support for -DeveloperReportOutputPath and -DeveloperReportUrl commands to permit local runs of the Automation Tool to generate reports on the report server and launch the browser to view them. + +* 'ResavePackages' commandlet now supports lighting in separate packages when using it to rebuild lighting. + +* Option to disable taking screenshots has been disabled. Screenshot comparison is an integral part of the testing so disabling them is no longer allowed. + +* The system now waits for the asset registry to finish loading assets before running tests. + +#### Blueprints + +* New: Added the 'Remove Gameplay Tag' function to the gameplay tag function library. + +* New: Blueprints containing a String and Text variables can now be marked as multi-line, which enables values to contain newlines when pressing Shift + Enter while editing them. + +* New: Blueprint Variables can now be marked as 'Read-Only' in Blueprint Editor, which prevents them from being set in Blueprints. This behaves the same as using 'BlueprintReadOnly' instead of 'BlueprintReadWrite' on a C++ UPROPERTY() declaration. + +* New: 'Get Default Locale' has been exposed to Blueprints. + +* Macro instances that contain latent actions will now show an overlay clock icon like other latent nodes, which makes them easier to spot and understand that they impact execution flow + + ![image alt text](image_39.png)(w:720 h:180 convert:false) + +* New: Improved comments in Blueprints. + + * Comment node text now wraps while the comment is being edited. + + * Reduced cases where the title of a comment node would clip at the end. + + * Editing the comment for a regular node using the right click menu will now show changes immediately, rather than waiting until the node was moused over again. + +* New: Added the Save and Find in Content Browser buttons to the Level Script Blueprint editor (they will save/show the map package that contains the Level Script). + +* New: Added the ability to search for delegate nodes using the function name that they are bound to. + +* New: 'Array Get' node. + + * Can toggle between returning a reference or copy. + + * Using a reference solves a longstanding issue with arrays of structs not being able to easily make changes to the items in the array. + +* New: 'Get Class Defaults' node has been extended to include output pin exceptions for Set & Map variable defaults. Like array types, the returned value is now a copy of the default value rather than a reference to it. This is done in order to avoid an accidental mutation of the Blueprint class default object. + +* New: Function inputs are now exposed as variable "Get" nodes via the right-click context menu in a Blueprint function graph context. + + * To use: In a Blueprint Function graph, right-click to access the context menu. Any input parameters will be listed as additional "Get" actions. + + * In this way, input parameters can be accessed like local variables from anywhere in the function graph; in other words, it's no longer necessary to drag wires all the way back to the Function Entry node in order to access these values. + +* New: We now support "value-based" Bitfield enum type associations in the editor for a UPROPERTY marked as 'Bitmask' with a 'BitmaskEnum' association. + + * Prior to this release, Bitfield properties did not work with associated enum types in which the enum values were explicitly set to a bitmask value (e.g. 0x80). That is, the value was assumed to always be set to the index of the bit that the flag should set in the editor ("index-based" mode). + + * To switch the associate to the new "value-based" mode, include an additional metadata key in the UENUM() declaration. Example: UENUM(Meta = (Bitmask, *UseEnumValuesAsMaskValuesInEditor="true"*)). + +* New: Added a whitelist mechanism for handling native noexport types that can support direct field access in nativized Blueprint code. + +* Bugfix: Fixed a crash in Blueprint Editor when adding an input parameter to a Custom Event node after deleting a Function Graph containing a Create Event node. + +* Bugfix: Fixed a crash when creating a new Blueprint class from one or more selected Actors in which the root component is not Blueprint-spawnable. + +* Bugfix: Fixed a crash on load in nativized EDL-enabled builds with non-nativized child Blueprint class assets. + +* Bugfix: Fixed a runtime Blueprint VM crash upon removing an element from set after consecutive add/remove iterations. + +* Bugfix: Fixed a crash that could occur when splitting a struct pin on a collapsed graph node. + +* Bugfix: Fixed a crash when trying to use non-supported types as Blueprint map keys. + +* Bugfix: Fixed a crash that could occur when changing a Map's value type string to vector. Map variables are properly cleared when value type is changed to an incompatible type. + +* Bugfix: Fixed a crash when compiling a Blueprint that contains a split pin in a collapsed graph. + +* Bugfix: Fixed a crash loading Blueprints that contain a Blueprint node that no longer exists in code. + +* Bugfix: Fixed a crash when using the Straighten Connection shortcut key (and some other related issues with actions done after the Context Menu is closed). + +* Bugfix: Fixed a crash when opening a Blueprint with a parent class that no longer exists. + +* Bugfix: Fixed a crash with the merge tool when the source control provide is SVN and there are gaps in the revision history. (This may still not work correctly, but it won't crash. The full fix will be covered with UE-43603) + +* Bugfix: Fixed a crash when attempting to name component with a very long name. + +* Bugfix: Fixed a crash that could happen when running Cook On The Fly server with nested struct assets. + +* Bugfix: Fixed a crash that would happen when a level in Blueprint was auto-saved. + +* Bugfix: Fixed an assertion that could occur when compiling a Blueprint with certain nodes (Select, Math Expressions, etc.) + +* Bugfix: Fixed a crash that could occur when reparenting a component Blueprint. + +* Bugfix: Fixed a crash that could happen when setting maps and sets of strings and certain structs. + +* Bugfix: Fixed a crash that would occur when passing a self node through a CustomEvent ref parameter. + +* Bugfix: Fixed a crash that could occur when adding a new Blueprint function and immediately undoing. + +* Bugfix: Fixed a crash that could occur after renaming the category of an implemented interface function inherited from a native C++ parent class in the 'My Blueprint' panel. + +* Bugfix: Fixed a crash that could occur when editing a local curve variable's default value in a Blueprint graph. + +* Bugfix: Fixed an ensure misfire in PIE exit when using Play as Listen Server Mode. + +* Bugfix: Fixed an infinite loop case in the Math Expression node. + +* Bugfix: Fixed an issue where misaligned memory access of noexport struct properties leading to incorrectly initialized values in a nativized cooked build. + +* Bugfix: Fixed an issue with broken collision shapes at runtime when cooking with the optimized Blueprint component instancing data feature turned on. + +* Bugfix: Fixed an issue with a Bitmask Enum type validation failure when serializing a Make Bitmask Literal node + +* Bugfix: Fixed an issue with log spam when compiling a Blueprint function with a local TSet or TMap variable. + +* Bugfix: Fixed an issue with broken pin wires after expanding a duplicated collapsed graph node. + +* Bugfix: Fixed an issue with invalid custom Enum type selection on member fields in the User-Defined Structure editor after a reload. + +* Bugfix: Improved context menu "whole world" algorithm to proper take into consideration localisation when searching for terms. + +* Bugfix: Fixed an issue where renaming interface input/output parameters will no longer cause broken pin links at interface function call sites in Blueprints that are currently loaded. + +* Bugfix: Fixed an issue with broken graph node pin links caused by renaming interface function input/output parameters prior to compiling the interface, but after renaming the function itself. + +* Bugfix: Fixed an inability to save after choosing a Level Script Blueprint class as the default value for a class input pin in a non-Level Script Blueprint class function graph. + +* Bugfix: Fixed an issue where Blueprints containing a 'Key Get Display Name' node will no longer be marked dirty when opening the Blueprint. + +* Bugfix: Fixed an issue where the user defined variable tooltip was not showing up when hovering over Get/Set nodes for local variables. + +* Bugfix: Fixed an issue with old versions of Blueprints being diffed accidentally showing up in Find-in-Blueprints search results. + +* Bugfix: Fixed some issue in Blueprint Diffing where properties of nodes edited in a Details panel would not show up as differences (this impacted Animation Graph nodes most heavily). + +* Bugfix: Fixed an issue in Blueprint nativization that could cause bad interface function calls to be generated. + +* Bugfix: Fixed an issue that could cause stale Blueprint instances in a hidden sub-level to spam a runtime error. + +* Bugfix: Fixed an issue that could cause a Blueprint 'mismatch' error when using 'Set' and 'Map' node. + +* Bugfix: Fixed an issue that could cause struct asset defaults to be wiped on editor reload. + +* Bugfix: Fixed an issue that could cause a packaging error when running with Blueprint nativization and no Blueprints were nativized. + +* Bugfix: Fixed an issue that removed the ability to set Blueprint object variables as 'config' variables, as you cannot set a object reference from a config. + +* Bugfix: Fixed an issue with reroute nodes so that a new output connection will propagate that type through to the node's inputs. + +* Bugfix: Fixed an issue so that 'Get Data Table Row' nodes are now compatible with DataTable variables. + +* Bugfix: Fixed an issue that could cause material parameter setting in a Blueprint construction script to fail. + +* Bugfix: Fixed an issue that could cause overlap events to fire multiple times in PIE. + +* Bugfix: Fixed an issue that would generate the nativized Blueprint plugin even if no Blueprint files were nativized. + +* Bugfix: Fixed an issue that would cause certain components to be orphaned and hidden from the component hierarchy. + +* Bugfix: Fixed an issue that could cause a level Blueprint's bound delegate nodes to not trigger. + +* Bugfix: Fixed an issue in Blueprint nativization that would cause cyclical logic (loops, etc.) to not iterate past the first iteration. + +* Bugfix: Fixed an issue in Blueprint nativization that could cause Blueprint subclasses to ignore their overridden model and default to their parent's. + +* Bugfix: Fixed an issue where non-nativized Blueprints were getting dropped from the cooked asset registry file when running with Blueprint nativization. + +* Bugfix: Fixed an issue where there would be a nativized Blueprint asset build error when there are no native code dependencies. + +* Bugfix: Fixed an issue with incorrect Blueprint graph pin value display names for user-defined enum types. + +* Bugfix: Fixed the variable 'config' setting tooltip to report the correct config file for the user to use. + +* Bugfix: Fixed an issue that could cause Blueprint variables set from a config to have their values improperly overwritten. + +* Bugfix: Fixed several issues with Switch Blueprint nodes not keeping their node and property UI in sync. + +* Bugfix: Fixed several issues where changing pawn/hud/state class from the Level editor toolbar would not work properly until the project was reloaded. + +* Bugfix: Fixed a stale class reference in interface properties that reference a Blueprint defined interface that has been recompiled. + +* Bugfix: Fixed an issue where 'Get Values' and 'Get Keys' nodes were not providing correct results for Map variables that have had values removed. + +* Bugfix: Fixed an issue where Blueprint functions that have all their return nodes pruned (ie. are not connected to anything) now have the correct output pins at call sites. + +* Bugfix: Fixed an issue where 'Movie Scene Sequence' and related code was not working when Blueprints were nativized. + +* Bugfix: Fixed an issue in nativized packaged builds that would cause default values to be lost. + +* Bugfix: Fixed 'Enum As Byte' related warnings in nativized packaged builds. 'Enum As Byte' is no longer used when nativizing Blueprints. + +* Bugfix: Fixed issues with Blueprint nativization where it didn't correctly include headers necessary for owners of subobjects, and instances where all modules needed by the generated code weren't being founds. This fixes one cause of "Cannot open include file" errors when packaging with Blueprint Nativization enabled. + +* Nodes in the blueprint editor again use their custom cursor (grab hand when hovering over a node and crosshairs when hovering over pins). + +* 'Logarithm' node added to the Blueprint Math library. + +* 'Set' pins on 'Intersection', 'Union' and 'Difference' nodes now infer their values uniformly. + +* Out of date Class Default Objects are no longer duplicated when compiling a Blueprint, reducing blueprints compilation time + +* Successive calls to Set Intersect, Union or Difference now provide correct results, previously the Set was not cleared before calculating the new result + +* 'Trace By Profile' collision functions have been exposed to Blueprints. + +* Nativize code is now more precise about dependencies, reducing the resulting executable size and compiler load. + +* Blueprints that override an inheritable component are no longer 'data only'. Blueprints with overridden components but no extra functions now load without losing data. + +* Blueprints that extend types that implement 'Needs Load For Server' or 'Needs Load For Client' now honor those functions, meaning they will not be cooked for targets that their type wants to be excluded from. + +* Delegates in nativized packaged builds correctly prevent double registration. + +* Blueprints used as a child actor class will no longer be marked dirty when compiling the class that references them. + +* When duplicating a Blueprint component, that component will now be a sibling of the duplicated node, not a child of it unless it is the root node being duplicated. + +* Duplicated root nodes will have their scale set to (1,1,1) to avoid applying the scale multiplier twice. + +* Blueprintable Components are no longer considered experimental, they have been enabled by default for several versions. + +* The ticking behavior of latent actions in components has been changed to match how they behave in actors. When the component ticks, the latent actions will now be processed at the same time, rather than happening later in the frame when latent actions for non-ticking actors and components are processed. This does change behavior, so there is a console variable (t.TickComponentLatentActionsWithTheComponent) that can be used to revert to the older behavior until affected component Blueprints that depended on the old ordering behavior can be fixed up. The cvar should be treated as deprecated; it will be removed in a future release. + +* Updated Blueprint nativization so that it generates source files compatible with 'include what you use' (IWYU). + +* Moved nativized Blueprint plugin generation to the project's 'Intermediate\Plugins' folder. + +* Removed make/break nodes from the Blueprint menu for structs that aren't marked as a 'BlueprintType'. + +* Updated marquee selection in graph editors. Ctrl dragging now inverts nodes' selection state, instead of only deselecting them (holding alt is now for pure deselection). + +* The Actor Details view will now refresh property mappings for the current Actor instances selection after a bytecode-only recompile of its Blueprint class as a dependency during reinstancing. + +* Child Blueprint class assets are now marked as dirty if its parent Blueprint class incurs a structural change. This alerts the user that updates to the Child Blueprint would need to be saved on exit. + +* We now emit C++ ctor initialization code for nested default subobjects when nativizing a Blueprint class at cook time. + +* Instanced Static Mesh transform edits are now reflected in the Blueprint editor's preview scene. + +* The editor will now raise an error at cook time after an attempt to nativize a Blueprint class that also implements a native C++ interface with a pure virtual function declaration that is not also marked up with UFUNCTION. This is because we cannot nativize a Blueprint class that does not also have an implementation of a pure virtual function inherited from the interface. + +* C++ interfaces with one or more pure virtual function declarations not also tagged with UFUNCTION are now excluded from the list of available "Implementable" interfaces in the Blueprint class editor. + +* Non-nativized child Blueprint classes will now properly override a nativized parent Blueprint class's component defaults at runtime in a nativized cooked build. + +* We will now implicitly nativize any child Blueprint class that overrides one or more BlueprintCallable functions inherited from a parent Blueprint class that is also nativized. + +* The Blueprint diff tool now reports when a component changes its type between revisions + +* Blueprints are now only dirtied if edited properties are from objects in the Blueprint's package. + +#### Core + +* New: Support added for "double" and 'fname' stat types in UFE stat export to CSV. + +* New: Pak files can now have their index encrypted with AES, preventing them from being opened by unrealpak. + + * An AES key must be provided in the project Encryption.ini, and then index encryption can be enabled in the project packaging settings in the editor. + + [REGION:note] + When either pak index encryption or signing are enabled in the Project Settings, pak ini encryption must also be enabled in order to avoid a potential security issue. All of these settings can be found in the Packaging section of the Project Settings dialog in the editor. + [/REGION] + +* New: Added "Get Component For Axis" and “Set Component For Axis” to FVector and FRotator. + +* New: Added support for -iterate for content plugins that require path remapping during cook/packaging. + +* New: Added a "CookedOnly" plugin type, for plugins meant only to be loaded in cooked games (in support of Blueprint nativization). + +* New: Added a Json Object Converter to add support for saving and loading TMap and TSet UProperties. + +* New: Absolute paths are now allowed in -UserDir= argument. + +* New: Added ability for games to use command line parameters for map overriding in shipping builds if their target.cs file defines UE_ALLOW_MAP_OVERRIDE_IN_SHIPPING macro to 1. + +* New: Added support for instanced elements in TMap and TSet properties being copied during "Copy Properties For Unrelated Objects." + + * This fixes an issue where instanced fields could lose data during recompilation of a Blueprint. + +* New: Added a new method Platform Misc "Get OS Version" that returns a string representing the raw OS version info. + +* New: All HTTP implementations now use a consistent User-Agent string (specified via the overridable function Generic Platform Http "Get Default User Agent" method). + + * Added a Platform and OSVersion string to the default value (platform=FPlatformMisc::IniPlatformName() and osver=FPlatformMisc::GetOSVersion()). + +* Bugfix: Fixed a crash with startup in the runtime asset manager when the on-disc cache already contains more data than the system is configured to use. + +* Bugfix: Fixed a crash in 'Chunk Cache Worker' function constructor. + +* Bugfix: Fixed a crash when launching "Play In Editor" session caused by missing audio data if its DDC data was not present and the audio was streamed in. + +* Bugfix: Fixed a crash when UObject can be added to GC cluster only if all of its Outers can also be added to it. + +* Bugfix: Fixed an assert with LocalExportIndex.IsNull. Now the Event Driven Loader code will properly disambiguate imports with the same name and the same outer name. + +* Bugfix: Fixed a crash when Hot Reloading caused by reinstancing UEngine objects. + +* Bugfix: Fixed an occasional crash during Hot Reload CDO reinstancing that was caused by a redundant insertion into TMap invalidating an existing reference into that TMap. + +* Bugfix: Fixed a crash when importing a Blueprint which contains a non-empty TMap with an enum class key. + +* Bugfix: Fixed a crash when Hot Reloading a project which contains a user-defined struct. + +* when hot reloading a project which contains a user-defined struct. + +* Bugfix: Fixed a crash when deserializing a TMap property item with instanced elements, where the CDO contains default element values for that property. + +* Bugfix: Fixed the use of many printf non-literal formatting strings, as these are potential security issues. + +* Bugfix: Fixed an issue with incorrect error code being returned from UnrealHeaderTool when -WarningsAsErrors and -Verbose are specified code. + +* Bugfix: Fixed an issue with the error code returned by UnrealHeaderTool when an error occurs during preparsing of headers. + +* Bugfix: Fixed a persistent stat metadata warning generated during PIE.. + +* Bugfix: Fixed an issue with FMonitoredProcess to prevent infinite loop in -nothreading mode. + +* Bugfix: Fixed an issue for runtime asset cache not invalidating files with an outdated version number. + +* Bugfix: Fixed stats warnings because each new slate loading screen thread has the same stat name, but is potentially assigned to a different thread. + +* Bugfix: Fixed an issue with CSV parser missing empty cells at the end of the string. + +* Bugfix: Fixed an issue with external plugin cooking and deployment by remapping plugin directories upon cook & deployment Tested directory structures: + + * D:\SomePluginDir + + * D:\UE4\AnotherPluginDir + + * D:\UE4\Engine\Plugins + + * D:\UE4\MyProject\Plugins + +* Bugfix: Fixed a memory leak in MallocBinned which affects the mobile platforms (Android, iOS). + +* Bugfix: Fixed a typo in comments for LODColoration in BaseEngine.ini. + +* Bugfix: Fixed the Log message in "Exclusive Load Package Time Tracker." + +* Bugfix: Fixed an issue where "log.timestamp" command would not work because it was incorrectly handled by "log" console command. + +* Bugfix: Fixed an issue where the logging system could hang when running out of disk space while flushing log and fixed unexpected concurrency assert when flushing the log buffer to disk. + +* Bugfix: Fixed a deadlock when flushing log file while it's already being flushed by a flush timer on the async log writer thread. + +* Bugfix: Fixed a memory leak when running with -nullrhi on the commandline in cooked games caused by shader resources not being destroyed. + +* Bugfix: Fixed an issue to make sure the engine is properly cleaned up on UnrealHeaderTool early exit to prevent UnrealHeaderTool hangs. + +* Bugfix: Fixed an issue to make sure that streamed-in SoundWaves get added to Garbage Collection clusters. + +* Removed dependency preloading system from sync and async loading paths. It has been superseded by the new event driven loading system. + +* Removed remaining references to AES_KEY, instead using the encryption key delegates to access the key where needed. + +* Refactored encryption and signing key access in unrealpak to make it easier to use. + +* Make content projects generate a stub executable when encryption or signing keys are specified so that keys can be embedded correctly. + +* Separate pak cache granularity from pak signing chunk size in the EDL loader. + +* Increase "Serial Size" and “Serial Offset” in FObjectExport to 64bits, to handle larger file sizes. + +* Added some validation of the class index in exportmap entries. + +* Added missing support for compiling plugins external to Engine/Plugins & Game/Plugins. + +* Disabled the 'HeartBeat' function on platforms that don't actually want to use the HeartbeatThread. + +* 'None' is now going to be properly considered by the engine as an invalid filename. + +* The editor will now collect garbage after a map is loaded to make sure any stale components or other objects that are no longer needed are destroyed. This is to make sure that these components are not resurrected by another editor operations like duplication. + +* Made sure the async log writer flushes the log archive even if there's no serialization requests to prevent situations where some of the recent requests haven't been flushed to disk + +* Reduced the code size for the generated Static Register Natives functions. + +* Disabled the garbage collector when recompiling child Blueprints, as is already done for the parent Blueprint. + +* Simplified Unreal Header Tool's code generation logic. + +* Implemented Lex "To Sanitized String" for double. + +* The function Local Player Context "Is Valid" now also checks that the player controller has a player set. + +#### Editor and Tools + +* New: UnrealGameSync now includes a workspace-specific file filter, separately to the global file filter. + +* New: UnrealGameSync now supports pop-up notification for build failures on content changes. + + * To mark a badge as applicable to users submitting content changes, add +ContentBadges=Name to the [Notifications] section of the project specific configuration file at /Build/UnrealGameSync.ini. + +* New: UnrealGameSync now allows a project to specify filters for the streams that should be displayed for fast-switching to. + + * The "Quick Select Stream List" setting in the “Options” section of the Project Settings references a depot path containing a list of strings used to filter the stream list. An option is shown to switch back to showing all available streams, if desired. + +* New: Added support for in memory packages. Helps distinguish between packages which can and can't be cooked. + +* New: Added a Blueprint function to convert a Render Texture to Texture2d. This is only available for use in the Editor. + +* New: Custom Depth can now be enabled for Foliage. + +* New: You can now color-code all of the windows in the editor in order to visually distinguish them when working across multiple branches or projects + + * You can adjust the 'Editor Window Background Color' for a subtle effect, as the default background is already a pretty dark grey: + + ![image alt text](image_40.jpg)(w:929 h:416 convert:false) + + * Or you can edit the tint in the two brushes (which sets the texture to a white default one) to get a very brazen effect: + + ![image alt text](image_41.jpg)(w:929 h:416 convert:false) + +* New: Added Data Table export/import support for TMap and TSet. + +* New: Updated the Windows platform to use the newer Vista+ style browser dialogs, rather than the older XP style dialogs. + +* New: You can now empty the text value within an FText property or pin. + +* New: Added support for .ini-driven classes to use a specific platform's config hierarchy, so that the editor on a desktop platform can read .ini settings from other platforms .ini files. + + * This will allow for NDA'd platforms to keep their ini settings in protected files, but still be editable by the editor. + + * Moved project settings for console platforms over + + * See UObject::GetConfigOverridePlatform() + +* New: Scene importing now allows for plugins to expose new scene import factory types. + +* New: Overhauled "Call In Editor" support and promoted it so it can be used on functions in any class, not just Blueprints derived from AActor: + + * "Call In Editor" can now be used on native UFUNCTION() declarations (e.g., UFUNCTION(Category=CoolCommands, CallInEditor)). + + * Blueprint declared functions can also be marked as CallInEditor (in addition to custom events), which allows you to set the category and tooltip for the buttons. + + * Now shows each function as a separate button, placed in the category associated with the function. + + * Removed the duplicate copies of properties placed in the Blutility section. + + * Prevented operating on functions that have parameters or return values, which could crash before. + + * Added a scoped transaction around "Call In Editor" execution so changes made can be undone. + + * The button strip entry is now searchable by function name or tooltip. + +* New: Added a new Details view option: "Show Hidden Properties while Playing" + + * Enabling this allows you to see every property on selected objects that belong to a simulating world, even non-visible and non-editable properties. + + * This feature is very useful for inspection and debugging, because you can see all of the internals of your Actors and Objects. + + * Be careful when changing values for properties that are not really intended to be changed at runtime. You could introduce instability or even corrupt data. + + * Note that this setting is saved for your entire project. + +* New: Sequencer additions and updates: + + * Tracks can now be prioritized based on their subscene hierarchical bias value. Higher bias values take precedence. + + * Fixed particle system restore state so that it gets the proper initial active state of the particle. + + * Added a generic past menu for Master (root) tracks. + + * Changed the time snapping interval in the toolbar UI so that it no longer additionally updates the Sequencer setting. The setting is only used to initialize the time snapping interval of the Level Sequence. + + * Added translate keys with Ctrl and Left-Right arrows. + + * Added Level Sequence Actor button in the Details panel to open Sequencer. + + * Duplicate shot now puts the duplicate on the next available row, keeping the start/end times the same. + +* New: You can now isolate/select all sections using a specific Material slot. + +* New: The FBX importer updates: + + * Now imports collision models under the FBX LOD Group. + + * Now applies the transform from FBX options only one time for the whole import. + + * When importing an FBX file from Blender, the importer now removes the root node name "armature." + + * No longer removes the socket created in UE4 Editor when using reimport. If affects only imported socket. + +* New: Added some LOD Setting options to the FBX Import Options window. Users can now specify the following Static Mesh LOD Settings Options: + + * Auto Compute LOD Distance + + * Minimum LOD Number + + * LOD number + +* New: The FBX Importer now fills two more Material Inputs (Texture only) from the FBX Material: + + * Specular Factor imported as "Roughness" + + * Shininess imported as "Metallic" + +* New: The FBX exporter can now export with the Front X-Axis. The new option is under the Editor Preferences settings. + +* New: TMaps now support editing structs as keys from within the Details panel. + +* New: The Data Table Row Editor now contains a Reset to Default control. + +* New: Properties added to the header of a Details panel group (ie. via IDetailGroup::HeaderProperty()) now have copy/paste actions exposed in the Context Menu. + +* New: Added the possibility in Slate to reset property group to their default value. + +* New: Added the possibility to perform the following actions in Save/Load Level dialog: + + * Rename + + * Delete + + * Create a New Folder + + * Show in Explorer + + * Show the Size Map tool + +* Bugfix: Fixed a crash when selecting components from an Actor's component tree and then undoing + +* Bugfix: Fixed a crash when attempting to open multiple cooked assets at once in the editor. + +* Bugfix: Fixed a crash when pressing PIE button several times before PIE session begins. + +* Bugfix: Fixed a crash that could occur during seamless travel while playing in a Play-in-Editor session with the "Use single process" option unchecked. + +* Bugfix: Fixed a crash while using the "Delete" button inside of the HLOD outliner while having a Proxy mesh opened in the Static Mesh Editor. + +* Bugfix: Fixed a crash when using import into level with .obj file. + +* Bugfix: Fixed a crash when dragging a re-import scene and there is new asset created. + +* Bugfix: Fixed a crash when creating too many LODs when importing a Static Mesh. + +* Bugfix: Fixed a crash with High Resolution Screenshot Tool that could happen when the Screen Percentage is set to a value other than 100%. + +* Bugfix: Fixed an issue with Device Output Log showing partial lines sometimes. + +* Bugfix: Fixed an issue where array properties would revert to the default values when duplicating an Actor. + +* Bugfix: Fixed an issue with Details panels becoming unusable if "Show Only Modified Properties" is enabled and there are no modified properties. + +* Bugfix: Fixed an issue so that thumbnails for Material assets now respect the "used particle system sprites flag" and show a quad instead of a sphere by default. + +* Bugfix: Fixed an issue for outdated error message instructions for how to fix being unable to launch on an iOS device. + +* Bugfix: Fixed an issue with "Save Current As" option not saving the current level and only saving the Persistent Level and then reloading everything thus causing work to be lost if editing a sub-level. + +* Bugfix: Fixed an issue with Material Instances being marked dirty when opening. + +* Bugfix: Fixed an issue with TAssetSubClassOf properties being reset on undo. + +* Bugfix: Fixed an issue that could cause the wrong Blueprint instance to be duplicated, or copy/pasted. + +* Bugfix: Fixed an issue with the Focus action in the Static Mesh Editor viewport. + +* Bugfix: Fixed an issue with Color Customization so that curve color names are "R", "G", "B", "A" instead of None. + +* Bugfix: Fixed an issue with user's setting for Texture Mip LOD size being incorrectly clamped. + +* Bugfix: Fixed an issue where lighting rig rotations were not set / saved correctly for Preview Scene Profiles. + +* Bugfix: Fixed an issue where auto-exposure values from the Preview Scene Profiles were not correctly applied + +* Bugfix: Fixed an issue where HLOD's "Override Screen Size" would not propagate on a LOD Actor directly. + +* Bugfix: Fixed an issue where the Material Slot assignment wasn't correctly restored on reimport. + +* Bugfix: Fixed an issue to prevent importing more LODs than the maximum allows for. + +* Bugfix: Fixed an issue with the FBX importer's "Front X-Axis conversion". We remove the scale of the camera and adjust the orientation of both the camera and light. + +* Bugfix: Fixed an issue with Auto Reimport "Directory to Monitor" feature. + +* Bugfix: Fixed some issues with the Import commandlet: + + * Fixed possible crash when importing FBX files. + + * Now makes sure that the imported assets are saved when there is no source control. + +* Bugfix: Fixed an issue with Static Mesh conversion from UE4 4.14 to earlier versions. + +* Bugfix: Fixed an issue with the Merge Actors Tool that was sometimes assigning wrong Material IDs to mesh sections. + +* Bugfix: Fixed an issue where the Number of Players and Dedicated Server settings for PIE would not persist correctly after Editor shutdown. + +* Bugfix: Fixed issues related to Auto Reimport: + + * Fixed a crash when attempting to import to mount points that do not exist. + + * Now allow for new assets to be created from monitored directories. + + * Settings now use a path picker when specifying the "Map Directory To" field. + +* Bugfix: Fixed an issue so that Property Editor Inline Class Filter now shows unloaded Blueprint Classes properly in the Editor. + +* Bugfix: Fixed an issue with Undo/Redo transactions of Color Grading. + +* Iterative cooking .ini setting checking improvements have been made. More to come in a future release. + +* Dependency checking performance improvements for iterative cook. More to come in a future release. + +* Panning in orbit mode now takes in account camera speed setting. + +* Pivot Painter 2 is a general purpose vertex animation toolset that comes with specialized subset of material functions to automate foliage animation. The script and material function set are more flexible, easier to use and provide an improved workflow over the first release. Additionally, a content example map ships with the editor to demonstrate how Pivot Painter's output can be referenced in the editor. + +* Added a disclaimer popup for the first time a user enters VR Mode + +* All asset properties in Details panels now have thumbnails on by default. + +* Disabled editor sounds that play when you PIE, simulate or possess the player by default. There is now a setting in the editor preferences to control this. + +* The output log should now have the same text color as other panels in the editor. + +* Removed hard coded list of thumbnails, preventing objects with valid thumbnails from showing up. Thumbnails are now shown by default. Use meta=(DisplayThumbnail=false) on a property to hide thumbnails. + +* Import data and thumbnail data are now transactional. You can now undo and redo their edits. + +* Reread in the target RHIs array every time the list of shader types is needed, instead of caching, because the user could change the settings in the editor, then click cook. + +* The Paint Fill tool has changed the way it works in Texture Weight Painting mode, it now fills the mesh with the currently selected texture weight index. + +* Limited the ability of setting up the Hierarchical Level of Detail (HLOD) system in levels which are contained as streaming levels in other assets. + +* The FBX importer now builds the Static Mesh only once when there is many LODs. + +* The section Material slot assignment is now correctly restored on reimport. + +* When swapping the Static Mesh referenced by a Static Mesh component, we now just clean up the Material Override that exceed the Static Mesh Material array size, instead of clearing all overrides. + +* When using the Full Scene Importer the "Scene Import" data asset can now specify a different source file for reimport. + +* Data pin style preferences are now saved on Editor shutdown. + +* The "Fixup Redirects" commandlet now ensures that files that are marked for delete are correctly submitted to source control. + +* The "Resave Packages" commandlet will now submit files that are marked for delete. + +* Blocking volumes will actually be added to the level when placed via the "Place Actor" command instead of generating warnings. + +* Values that are directly entered for float properties with a specified Delta value will no longer snap to the nearest delta when losing focus. + +* Actor components can now be scaled to negative values using the transform gizmo. + +* Map properties now fully support customized property types used as keys. + +* When deleting an Actor, we now display the name of the referencers. + +* Using the Convert Actor feature now won't change the Actor level. + +* Primitive Statistics window will now properly update itself when adding new Levels. + +* Optimized the lightmap UVs generation to speed up the Static Meshes import flow when packing the UVs into higher resolutions. + +##### Content Browser + +* New: Added "Resave All" functionality to Content Browser folders. + +* New: Added a way to view/copy a list of references (including those that aren't loaded) to the Reference Viewer. + +* New: Importing CSV files will now show the name of the CSV file in the import dialog. + +* New: Added the ability to auto resize column in "Column View" by double clicking column splitters + +* Bugfix: Fixed an issue where folders wouldn't be removed from the Content Browser when deleting them. + +* Bugfix: Fixed an issue with the Reference Viewer where it only ever used the default thumbnail. + +* Bugfix: Fixed some issues for gathering cached asset dependency data. + + * We no longer load dependency data that doesn't have the correct package name. + + * We no longer populate the dependency results when "Gather Depends on Data" is set to false. + +* Bugfix: Fixed an issue that prevented textures from updating correctly if a source texture with the same name as a texture asset is imported from a location that differs from the asset's original source image. + +* Bugfix: Fixed an issue where the Force Feedback "Play" and “Stop” icons weren't rendered correctly and would only be displayed when hovering over the asset or when the asset is currently playing. + +* Bugfix: The Content Browser file path will now update correctly if it is pointing to a path that is deleted through the Sources Panel. + +* Bugfix: Duplicating an asset will correctly name it if there is another one of the same name. + +* Moving a newly-created asset before saving it will no longer save an empty package in the asset's original location. + +* When reimporting multiple assets, the "Yes to All" and "No to All" dialog options will prevent future reimport dialogs from appearing for the same asset type in the same operation. + +* Improve visual of "Column View" in Content Browser. + +##### Cooker + +* Bugfix: Fixed an issue with the rebuild lighting commandlet not checking out files correctly. + +* Bugfix: Fixed an issue where running the same DLC profile created by the Mobile Patching Wizard would increase HTTP chunk size. + +* Bugfix: Fixed an issue with the cooker always cooking "All Maps" even when a single map was specified on commandline. + +##### Foliage + +* New: Added the Show Flag "Foliage Occlusion Bounds" in the Advanced menu to see the bounds generated by the occlusion tree. + +* New: When moving a foliage asset to a new Level, you will now be prompted to save the Foliage Type as an asset if it's a local asset. + +* New: Improved the Foliage painting algorithm to properly support Random Pitch/Yaw when the setting "Collision with World" is enabled. + +* Bugfix: Fixed a crash that occurred when moving the mouse over certain content while in Foliage mode. + +* Bugfix: Fixed an issue that cause foliage thumbnails to incorrectly be duplicated if many of them are onscreen at once. + +* Bugfix: Fixed an issue where removing a Foliage Type wouldn't properly refresh the Details panel. + +* Bugfix: Fixed an issue where the foliage location would shift when using undo/redo transactions. + +* Optimized the occurrence of rebuilding the occlusion tree when performing actions in the editor. + +##### Landscape + +* New: We now automatically fill Landscape with the first created Landscape's Layer Info object. + +* New: Added sorting to Landscape Target Layer tabs. You can now sort by Material definition (which is the default one), alphabetical, or custom a using drag-and-drop operation. + +* New: Added a visibility toggle to only show the used Target Layers by the loaded components. + +* Bugfix: Fixed a crash when changing multipole Landscape Blend Layer nodes from Weight blend to Height blend. + +* Bugfix: Fixed an issue with user Landscape shortcuts not working in the Level Viewport. + +* Bugfix: Fixed an issue when performing an Undo action would delete the newly created Landscape and return back to the new Landscape window. + +* Bugfix: Fixed an issue where Landscape holes (visibility mask) was causing NavMesh problems at the borders of the Landscape component. + +* We have improved when a Level will be marked as dirty when manipulating a Landscape Spline. + +* The Landscape tools Material synchronisation has been updated between game thread and render thread. + +* When adding a new Component, if a Landscape info object exists it will determine which one is used based on its neighbors. + +##### Material Editor + +* Bugfix: Material Custom nodes that contain "tab" characters will now correctly display tab characters after copy/paste. + +##### Matinee + +* Bugfix: Fixed an issue with how tooltips display when using a Material Function in your Material. + +##### PhAT + +* Bugfix: Fixed "Multiple Values" being displayed in Body Setup properties when single bone has multiple bodies + +##### Sequencer + +* New: Added the ability to specify additional Event Receivers for Level Sequence Actors. + +* New: Event tracks can now be defined to trigger events at the start of evaluation, after objects are spawned, or at the end of evaluation. + +* New: Added the ability to retrieve bound objects from Blueprint. + +* New: There have been improvements to the Binding overrides. + + * Added the ability to override spawnable bindings. + + * Added the ability to override bindings in sub Sequences. + + * Deprecated "Get Sequence Bindings" node in favor of "Get Sequence Binding", which is more robust, and provides a better UI/UX for selecting single bindings + + * Added Drag/Drop support for Binding overrides. + +* New: Added the ability to specify Event Receivers on Event Tracks. + + * These are defined by right-clicking on the Event Track in the Sequencer tree, and adding Event Receivers. + + * Such objects must be defined within the Sequence hierarchy (as well as parents, children, grandchildren etc). + +* New: Added a reworked, more generic property path handling system in the Sequencer object change listener. + +* New: Unlocked the Cine Camera Post Process Depth of Field to use options other than CircleDoF. + +* New: "Pre Roll" and “Post Roll” are now exposed at the section level for all sections. + +* New: Enabled "Use Custom Start Frame" and “Use Custom End Frame” when rendering a single shot from the menu. + +* New: You can now set the fade color in the Track display. + +* New: Audio row heights are now also resizable by dragging on the bottom end of the track lane in the track area view. + +* New: Sequencer now re-evaluates when starting PIE or Simulate. This can be disabled with "Bind Sequencer to PIE" and “Bind Sequencer to Simulate” in the Play-in-Editor Advanced settings. + +* New: Split "Snap to the Dragged Key" option into two options, "Snap to the Pressed Key", and "Snap to the Dragged Key". + +* New: Added a loop selection range. If there is no selection range, loop mode is restricted to loop or no loop. + +* New: Added hotkeys to set the selection range to the next and previous shot (page up, page down). Also, added hotkey to set the playback range to all the shots (end). + +* New: You can now set sequencer audio components bIsUISound to false so that they don't continue playing when the game is paused. + +* New: Added an option to instance sub sequences when creating a Master Sequence. + +* New: Notify streaming system prior to Camera cuts by default. To enable, users will need to enable the Pre Roll section of the Camera cuts for the streaming system to activate prior to cutting to cameras. + +* Bugfix: Fixed a crash when selecting keyframes in the viewport. + +* Bugfix: Fixed a crash with Sequencer Recorder when clearing properties to record. + +* Bugfix: Fixed an issue where tick prerequisites were not being set up for Actors streamed in from a streaming Level. + +* Bugfix: Fixed an issue where Sequencer was animating objects from the wrong world. + +* Bugfix: Fixed an issue with event parameter structs being able to be garbage collected, resulting in NULL structs potentially being written out. + +* Bugfix: Fixed an issue with animation looping in Sequencer. + +* Bugfix: Fixed an issue with Sequencer Recorder to fix duplicate components getting recorded. + +* Bugfix: Fixed an issue with FBX import with camera and light animation key imports. + +* Bugfix: Fixed an issue with autokey not setting a keyframe for Slate color with the specified color. + +* Bugfix: Fixed an issue for filtering to include Child nodes. + +* Bugfix: Fixed an issue where the Sub Track node deletion so that all sub tracks aren't deleted, only the row being requested. + +* Bugfix: Fixed an issue to invalidate expired objects when Blueprints are compiled. This fixes Actor references to now handle sections that need to have their GUIDs updated (ie. attach tracks). + +* Bugfix: Fixed an issue so that when finishing a scrub, playback status is now correctly set to stopped rather than set to a stepping state. + +* Bugfix: Fixed a missing command binding alt-r to record selected objects into sequencer. + +* Bugfix: Fixed an issue to Filter hidden functions, which fixes a bug where the field of view property for a cinematic camera appears to be animatable,. It should be hidden just like it is in the property editor. + +* Added a warning when Sequencer tries to write to properties that have changed type. + +* Sequencer templates are now always regenerated on load + +* Level Sequence frame snapshots now take account of fixed-frame interval offsets, and overlapping shot sections on the same row. + +* We now convert Linear Color to Color for fade to get the correct fade color in viewport. + +* Audio waveforms now show peak samples with smoothed RMS in the center. + +* Set max tick rate when in game if force fixed interval playback is enabled. + +* Cache player fade state so that restore state will return the values to the pre animated state. + +##### Source Control + +* Bugfix: Fixed an issue with Git plugin to update the status on directories hotfix. + +* With the Git plugin, use use asynchronous "MarkForAdd" and "CheckIn" operations for the initial commit. + +* Allow binary files in Git stored via git-fat, git-lfs, etc to be diffed. + +##### Static Mesh Editor + +* Bugfix: The camera position now stays in place after reimporting from inside the Static Mesh Editor. + +##### Traps + +* Subversion binaries have been updated to 1.9.5. They should no longer crash when used. + +##### VR-Editor + +* New: Improved functionality for the VR Mode: + + * Improved the look and feel of the rotation gizmo handles while in VR Mode. + + * Improved interaction for painting terrain, foliage, and mesh painting. + + * Improved gizmo handle animations. + +* New: VR Mode is now bound with the Editor Sound settings. + +* New: VR Mode motion controllers now have collision when in simulate. + +* Bugfix: Fixed VR Mode selection now to respect a component's "Is Selectable" state. + +* Bugfix: Fixed an issue with not being able to open a project in the Project Browser with VR Mode auto-entry enabled and the HMD active. + +##### Windows + +* New: Custom Depth can now be enabled for Landscapes + +* Bugfix: Fixed an issue with Landscape spline segment splitting when using streaming levels. + +* Bugfix: Fixed an issue with Landscape painting in orthographic viewports when the painted area's Z value was below 0. + +##### World Browser + +* Bugfix: Fixed an issue when moving a sublevel in World Composition browser does not appear in Undo History. + +##### World Outliner + +* New: Actors in the World Outliner will now bring their children with them when moved into a newly created folder. + +#### Gameplay Framework + +* New: Added an option for components to opt out of physics impulses on damage using "Apply Impulse On Damage". + +* New: Exposed component's "Ignore Radial Impulse" and “Ignore Radial Force” flags to Blueprints. “Ignore Radial Impulse” is now properly respected when applying impulse to relevant movement components. + +* New: The Player Controller's "Should Perform Full Ticket When Paused" can now be set from Blueprints and the Details panel. + +* New: Spawn Sound and Force Feedback Blueprint nodes now have a "Auto Destroy" pin that can be set to false to allow the component to be reused after the sound/pattern complete. + +* New: The number of buttons that can be used by Raw Input is now 20. + +* New: Fields of Attribute MetaData are now editable. + +* New: In the Ability System, the "Cancel Ability" has been exposed to Blueprints. + +* New: For Cameras, support has been added for specifying a default aspect ratio and whether or not to constrain to it in a Camera Manager subclass. + + * Normally the information would come from a Camera component, but this is useful when using custom view logic that doesn't source from a Camera component as the view target. + +* New: Added "​On Component Collision Settings Changed Event" delegate to Primitive Component. Fixed Skeletal Mesh Component not calling Super implementation for “On Component Collision Settings Changed”. + +* New: Refactored Character Movement Component determination of net send rate when combining moves into a virtual function Get Client Net Send Delta Time. Added configurable values to Game Network Manager under ​[/Script/Engine.GameNetworkManager] in BaseGame.ini: "ClientNetSendMoveDeltaTime", “ClientNetSendMoveDeltaTime”, “ClientNetSendMoveThrottleAtNetSpeed”, “ClientNetSendMoveThrottleOverPlayerCount”. + + * This replaces the values that were hardcoded in the network code for characters and enables easier configuration of client send rates for movement. + +* New: We've increased Pawn location replication precision to 2 decimal places from 0. Prevents replicated pawns from being inside geometry by a large amount. Removed CVars controlling CharacterMovement proxy shrink amount and made those instanced properties on the component. + +* New: Added a flag to Character Movement Component to determine whether or not character should Sweep while using "NavWalking", instead of relying on Generate Overlaps flag. + +* New: Added "Apply Gravity While Jumping" flag to Character Movement Component. This helps to reduce Framerate Dependent Jump Height issues when disabled, but raises jump height. This is disabled by default. + +* Bugfix: Fixed a crash due to null World Settings when rendering a thumbnail. + +* Bugfix: Fixed a crash when opening Blueprint after adding a component to native class referenced by a Child Actor Component. + +* Bugfix: Fixed several issues with renaming or deleting Gameplay Tags from the Gameplay Tag Project Settings page. + +* Bugfix: Fixed an issue when calling "Set Visibility" or “Set Hidden In Game” all children of the component will now properly be reconsidered as to whether they should render. + +* Bugfix: After duplicating an Actor, components added to the source instance will now have the correct position in the duplicate. + +* Bugfix: Ability actions can now be properly bound to input components. + +* Bugfix: Construction scripts will no longer be incorrectly rerun on Actors in a level that was hidden and then later made visible again. + +* Bugfix: Fixed an issue warning about invalid world content when loading maps with child Actor components in it. + +* Bugfix: Fixed cases where built lighting on child actors could be lost when loading a level. + +* Bugfix: Fixed case where child actor template was not cleared when setting child actor class to null. + +* Bugfix: Fixed issues with seamless travel in PIE and sub-levels shared between different Persistent Levels. + +* Bugfix: Fixed issues where Child Actor Component's "Parent Component" would be null on the client. + +* Bugfix: Fixed accumulated forces in Character Movement applied incorrectly when movement mode or active state changes. + + * Added ​"Clear Accumulated Forces” + + * "Add Force" and related functions now avoid adding the force if in Movement Mode is set to "None". When ticking in "None", forces are cleared so they don't pile up until the next valid movement mode. Forces are also cleared if the updated component changes or when the capsule simulates physics. + + * "Deactivate" implemented to stop movement and call “Clear Accumulated Forces”. + + * "Clear Accumulated Forces" now also clears pending launch velocity. Exposed “Clear Accumulated Forces” to Blueprints. + + * "Apply Accumulated Forces" does not call ”Clear Accumulated Forces”, since that would prevent pending launch. + + * "Add Force" and “Add Impulse” now also check that character movement is active (not deactivated, able to tick). + + * "Simulate Movement" handles pending launch and clears forces regardless of whether it's simulated proxy. + + * Inlined Actor Component "Is Active" for performance. + +* Bugfix: Fixed characters sliding when landing on slanted surfaces or stairs, when aggressive "Perch" settings could cause a line trace (from the center of a capsule) instead of capsule trace and thereby screw up the floor distance checks. + +* Bugfix: Fixed the case of people moving a Character mesh in Begin Play rather than in the Editor or Construction Script and not having the mesh offset reflected correctly in network games. + + * Added function "Cache Initial Mesh Offset" to cache initial mesh offset, used as the target for network smoothing. This takes location and rotation params so you can be explicit on the values, in case you try to change these during network smoothing, where reading the relative offsets would be skewed. + + * Added a call to this function from Begin Play in addition to the existing call from "Post Initialize Components", and exposed this to Blueprints as well for custom changes to mesh offset at runtime. + +* Bugfix: Fixed an issue with Projectile Movement Component continuing to simulate (and generate hit events) after it is deactivated during simulation. "Has Stopped Simulation" function now checks if “Is Active” is false. + +* Bugfix: Fixed an issue with "Get Welded Bodies" so that it properly returns Skeletal Bodies, instead of the default body for Skeletal Mesh Components. + +* Bugfix: Fixed an issue with infinite jump on client when Jump Max Hold Time is not 0. + +* Stop dynamic force feedback when initiating Actor is destroyed. + +* Clarified the tooltip on the "Inverse Lerp" function. + +* In the Movement Component "Deactivate" calls “Stop Movement” to clear cached velocity. + + * It was undesirable that reactivation many seconds or frames later would restore a stale velocity. + +* The "Collision.ListComponentWithResponseToProfile" command now includes pending kill objects. Use this to inspect collision responses between objects in a game world. + +* Optimized the Math Library "Get Forward Vector" (converts Rotator to forward direction). This way we avoid building a matrix, and avoids 1 more SinCos call. + +#### Learning Resources + +##### Sample Content + +* New: ShooterGame now supports dedicated servers on PC, Mac, and Linux! + +#### Localization + +* New: Improvements to culture switching and LocRes files. + + * LocRes files now de-duplicate translations when they're generated, which can result in smaller LocRes files. + + * The localization compilation step now produces a LocMeta file, which contains meta-data specifying the native culture during compile, and where the native LocRes file can be found. + + * Changing cultures now loads the native localization data prior to loading the non-native translations to ensure that translations are always applied to a consistent base. + + * The "leet" culture (available when localization testing is enabled) is now always applied against the native translation, and correctly restores non-translated text when switching away from the "leet" culture. + + * "-culture=leet" now works correctly on the command line ("-leet" also works). + + * LoadLocalizationResourcesForCulture is no longer called multiple times during initialization of the text localization manager. + +* New: Updated Fast Decimal Format to support the correct 0-9 numerals for the current locale + + * These are typically still Latin, but Middle Eastern languages have some variants. + + * This addresses an inconsistency between FText formatting of numbers and dates (since numbers always used Latin, but dates used the culture correct numerals). + +* New: Split the monolithic culture concept in UE4 + + * UE4 has historically only supported the concept of a single monolithic "culture" that applied to both text localization and internationalization, as well as all asset localization. Typically the "culture" was set to the "locale" of the OS, however that could be undesirable or incorrect on platforms (such as newer versions of Windows) that have a distinct concept of "language" (for localization) and "locale" (for internationalization). + + * This change splits the concept of "culture" into "language" and "locale", and also adds the concept of "asset groups". The language is now used to work out which localization we should use, and the locale is used to control how numbers/dates/times/etc are formatted within our internationalization library. + + * Asset groups expand on the language used by asset localization and allow you to create a group of asset classes that can be assigned a different culture than the main game language. A typical use-case of this would be creating an "audio" group that could, for example, be set to Japanese while the rest of the game runs in English. + + * If your game doesn't care about the distinction between language and locale, and doesn't need to use asset groups, then you're able to continue to use "culture" as you always have. If, however, you do care about those things, then you'll likely want to avoid using the "culture" directly (as it's now a very aggressive setting that overrides all others), and instead favor using language/locale (games will typically treat these as the same) and asset groups as separate concepts (both in settings, and in your in-game UI). + + * The language or locale for a game can be controlled by settings within the "Internationalization" section of your configs (this would typically be set in your Game User Settings config, in the same way that "culture" works), eg) + + [Internationalization] + language=fr + locale=fr + + * The asset groups for a game can be controlled by settings within the "Internationalization.AssetGroupClasses" and "Internationalization.AssetGroupCultures" sections of your configs (the asset group class definition would typically be set in your DefaultGame config, and the cultures the groups use would typically be set in your Game User Settings config), eg) + + [Internationalization.AssetGroupClasses] + +Audio=SoundWave + +Audio=DialogueWave + [Internationalization.AssetGroupCultures] + +Audio=ja + +* Bugfix: Fixed an assert that could trigger when an IME composition is aborted during widget destruction. + +* Bugfix: Fixed a crash that could happen if a config was loaded while the Gather Text commandlet was running. + +* Bugfix: Fixed text namespaces being treated as case-insensitive when exported to JSON manifests and archives. + +* Bugfix: Fixed text format history being clobbered by reference collection. + +* Bugfix: Fixed the pluralization of the decorator text during drag-and-drop operations. + +* Vastly reduced the number of allocations that happen when rebuilding text at runtime. + +#### Networking + +* New: Network dormancy efficiency has been improved greatly (if you have large number of dormant actors, they now will have less overhead). + +* New: Network consider/relevancy code is now also much more efficient. Overall, expect a 20+% improvement in performance if you have lots of Actors in the network Actor list. + +* New: Adaptive network update frequency logic is now on by default. This should improve network performance for games that weren't opt'ing in to this feature. + + * Net.UseAdaptiveNetUpdateFrequency is now 1 by default. + +* New: Replays now support network relevancy. + + * All connections are considered when determining if an Actor is relevant. + + * Enable by setting demo.UseNetRelevancy to 1. + + * Override cull distance with demo.CullDistanceOverride. + +* New: Added more info about the connection to logs when you see "FRepLayout::UpdateChangelistHistory: History overflow, forcing history dump" message. + +* New: Updated OnlineSubSystemNull to properly account for game state and "Allow Join In Progress". + +* Bugfix: Fixed a crash that could occur when updating unmapped objects. + +* Bugfix: Fixed an issue with IPAddressBSD validation when setting IP from string. + +* Bugfix: Fixed a memory leak in network drivers. + +* Bugfix: Fixed an issue with syncing of non-contiguious UENUMs over networks. + +* AActor "Pending Net Update" has been deprecated. Please use “Pending Net Update” that is now on FNetworkObjectInfo (obtained by calling “Get Network Object Info). + +* UNetDriver "Get Network Actor" is now deprecated. Use UNetDriver “Get Network Object Info” instead. + +* Disabled net.PartialBunchReliableThreshold for replays (we don't need to worry about bunch fragment sizes since there is no packet loss for replay connections). + +#### Online + +* New: Steamworks integration has been updated to support version 1.39, including updated steam controller support! + +* New: Web Browser module no longer directly depends on Online Subsystem plugins. + + * It uses the Online Engine Interface shim to explicitly depend on the engine and will use Online Subsystem features when that module is optionally added. + +* New: Added a new overload for Online Session "Find Friend Session" in the session interface that can retrieve sessions for multiple friends. + +* New: Sending and accepting invites on dedicated servers on Steam is now supported. + +* New: Updated OpenSSL libraries to use BCrypt on Windows in order to reduce memory allocations. + +#### Other + +* New: Added a "Buffering" media player event. + +* New: The Plugin Browser now supports customizations to allow for context-specific plugin creation. + +* Bugfix: Fixed a crash with Media Assets in "Tick Video" after media player is garbage collected. + +* Bugfix: Fixed an issue to prevent the default cooked sandbox from trying to read non-cooked assets. + +* Bugfix: Fixed a message router thread not being woken up right away on shutdown.Crashreporter uploads/downloads crash data from AWS + +* Search button is disabled after clicking it once to prevent accidental double-clicks. + +* Reading the config hierarchy for TVOS now matches IOS to get the correct bundle id when packaging a project + +#### Paper2D + +* Bugfix: Custom tile maps using collision can now be created at runtime on any platform without crashing. However on iOS/Android/HTML5 only the boxes and spheres used in the per-tile collision shapes have effect; arbitrary convex collision (e.g., slopes or other triangle-based collision) will not cause collisions or overlaps until support for PhysX runtime cooking is added to these platforms. + +* Bugfix: The Paper2D flipbook editor now shows the current frame correctly when the animation timeline is longer than the editor window and the scroll bar is moved to the right. + +* Bugfix: Paper2D flipbook editor now shows the correct number of frames; previously, it was one frame short. + +#### Physics + +* New: Added sprite to Physics Thruster Component (previously this was only available on Physics Thruster Actor). + +* New: Exposed "Set All Physics Angular Velocity" to Blueprints. + +* New: Added finer-grain PhysX stat information that is available by using "stat physxtasks". + +* New: Added the ability to specify whether a ragdoll is in the sync or async scene with "Use Async Scene". + +* New: Changed default contact-gen method to PCM. This is the default in PhysX 3.4. + +* New: Added "Is In Air" method to Vehicle Wheel. + +* New: For the Wheeled Vehicle Movement Component, the Mass dependent wheel properties now update when mass is updated. + +* New: Created "Add Force At Location Local" function to allow component space forces. + +* New: Added a new Physics settings "Enable Stabilization". Stabilization can help stacks of simulated bodies to come to rest. + +* Bugfix: Fixed a crash in anim dynamics when a world was not valid during pre-update. + +* Bugfix: Fixed a crash when saving sub-levels that don't currently have a correctly initialized scene. + +* Bugfix: Fixed an issue with incorrect slider for "initial Average Frame Rate" physics setting. + +* Bugfix: Fixed an issue with physics constraint warning messages in Message Log. These now list Component/Actor name correctly. + +* Bugfix: Fixed an issue with editing Box and Capsule collision primitive rotations by storing rotation as a Rotator rather than Quaternion. + +* Bugfix: Editing collision profiles in Editor Preferences no longer discards edits. + +* Bugfix: "Find Closest Bone" function no longer ignores the “Required Physics Asset” option. + +* Bugfix: Fixed an issue teleport not working for physical animation component. + +* Bugfix: Fixed an issue incorrect inertia tensor computation for cubes, which was being doubled. + +* Bugfix: Fixed an issue with kinematic body interpolation in substepping causing invalid raycasting, sweeping, or overlapping. + +* Bugfix: Physics Constraint component now works as expected when its target is a Child Actor component. + +* Bugfix: Fixed an issue with collisions between components with CCD enabled having unreliable behavior. + +* Bugfix: Fixed an edge case where generating collision data could cause the engine to hang in an infinite loop. + +* Bugfix: Fixed a regression with Raycasts against Capsules returning invalid hits. + +* Bugfix: Instanced Static Mesh now properly creates physics state when set to Stationary. + +* Bugfix: Fixed a memory leak caused by keeping PhysX shapes in memory after they are no longer being used. + +* Expanded self-collision culling for clothing by providing a scale to tweak the culling queries. This makes a tradeoff between performance and accuracy. + +* Added a guard against infinitely thin geometry, which fixes some NANs. + +* Performance improvements to Anim node "Rigid Body". + +* Physics performance is improved by skipping the update of kinematic bodies when they haven't moved. + +#### Platforms + +* New: Add logging for the NUI GPU reserve so we can see when it's enabled and disabled. + +* New: Exposed JAVA_HOME setting in Android SDK Project Settings on Mac. + +* New: Added "Platform Handle Splash Screen" to deal with hiding splash screen properly on Startup Movies. + +* New: Implemented support for new controllers (Xbox Wireless, SteelSeries Stratus XL, PS4). + + * Note: there are two implementations for Xbox Wireless due to differences in firmware. Firmware before 3.1.1221.0 does not use standard mapping which you can enable by setting the Android.OldXBoxWirelessFirmware CVar to 1 (defaults to new firmware). + +* New: Added support for "r.ScreenPercentage" on mobile allowing the game scene to be rendered at lower resolution than the UI. Requires MobileHDR to be enabled. + +* New: On-screen warnings now appear when a mobile shader permutation required to correctly render the current scene's lighting setup has been disabled in Project Settings. + +* New: Made some big DeviceProfile changes, particularly for the protected platforms. + + * Changed the "type" of some DPs from WindowsNoEditor, etc to Windows. It should be a platform, not a random string. + + * With that change, the platform can be used to save out protected platform DP .ini files to subdirectories, maintaining secrecy + + * Added Config/[PlatformName]/ConfidentialPlatform.ini files so that the DP loading code knows to look in their directories for DPs. See FGenericPlatformMisc::GetConfidentialPlatforms() for more information. + +* New: When uploading a HTML5 project to AWS S3, it now supports "signature version 4" authentication and better error message feedback on upload failures. + +* New: Added "use fixed timestep" setting option for HTML5 builds (This has been separated from Engine > General Settings - Framerate). + + * This is slightly different to "Smooth Framerate" and “Fixed Framerate”. + + * NOTE: Fixing the timestep does not guarantee the actual framerate. Calculations based on delta time may be adversely affected by this. + +* New: Added iOS/Android support for new Audio Mixer. + +* New: "Does Save Game Exist" will now show a message if the save data is corrupt. + +* New: Initial support for voice chat in the Android platform. To use enable the Voice module in DefaultEngine.ini, in the level bp create a session, and in project settings > Platforms > Android > Advanced APKPackaging, check the setting 'Add permissions to support Voice chat (RECORD_AUDIO)'. After this create a multiplayer game between two android devices. For more information check pull request #2894. + +* Bugfix: Fixed a crash with mobile feature level preview when the Low Quality Lightmap shader permutation is disabled. + +* Bugfix: Fixed a crash in clothing on platforms that don't support clothing. + +* Bugfix: Fixed a crash when backgrounding or sleeping on iOS Metal devices. + +* Bugfix: Fixed a crash with UIImagePickerController. + +* Bugfix: Fixed an issue with executable path for stripping Android debug symbols (handle non-Windows properly). + +* Bugfix: Fixed memory reporting for Uniform Buffers in "stat rhi". + +* Bugfix: Fixed a slow memory leak in FD3D12UniqueDescriptorTable. + +* Bugfix: Fixed rendering of batched Slate primitives in D3D11.x. + +* Bugfix: Fixed an issue with S3 public link generator for "Shipping" builds filename. + +* Bugfix: Fixed an issue with iOS IDFV string allocation. + +* Bugfix: Fixed UPL processing on iOS plist files. + +* Bugfix: Fixed network byte ordering for iOS multiplayer sessions. + +* Disabled the game analytics anonymous usage data sent to Epic on the console platforms. + +* Save 66MB of memory by disabling the unused default SHAPE heap in XAudio2. + +* Stop the audio thread from using the 7th CPU core as it can be pre-empted and not get enough execution time. + +* Add -distribution when iOS distribution Packaging. with IPhonePackager.exe. + +* Changed mouse cursor to be always visible when running in Mobile Preview. + +* Refactored memory allocation functions (BinnedAllocFromOS) on all platforms. Made Binned2 malloc work on Linux. + +##### All Mobile + +* Bugfix: Fixed a crash in mobile patching utilities mount method. + +* Bugfix: Fixed an issue with the shader compile for Landscape on platforms below SM4 feature level. + +##### Android + +* New: Bad package names are now detected and APK generation is stopped with a proper error message instead of failing during Java compiling. + + * Package names with fewer than 2 segments are not allowed (e.g., "myproject" is not allowed, but “com.myproject” is legal). + + * Only alphanumeric characters and underscore are allowed in the package name (Note: hyphens in the project name will be converted to underscores, but any other hyphens need to be corrected in Android project settings). + + * All segments must start with a letter; if your project name starts with a letter you will need to replace the [PROJECT] part of the package name in Android project settings. + + * Reserved Java keywords may not be used as the full segment; appending an underscore or other legal characters will fix this. + + * Segments may not be empty (e.g. "com..myproject" is not legal). + +* New: Larger OBB files embedded in APK are now allowed by bypassing Asset Manager. + +* New: We've implemented a first pass of Google Cloud Messaging plugin. This is considered an experimental feature for this release. + +* New: Added missing key codes for keyboard input (@ and #). + +* New: Added a drop-down with some common console commands on Android to the console dialog. + +* New: Patches ant.bat to handle long command line issue on Windows. + + * Copies original ant.bat to ant.orig.bat and writes a new ant.bat which uses subst with an unused drive letter to shorten paths). + + * Note: you can edit the generated ant.bat if you need to change the drive letter used; the editor will not replace it if ant.orig.bat is found. + +* New: Editor now checks to make sure that at least SDK Android-23 is selected and installed. There will be an error message if an earlier version is installed. + +* New: Updated AAR handling to deal with versioning, subproject dependencies for resources, and scope (ignore test). + +* New: Added "Game Activity On New Intent Additions" section to Android Unreal Plugin Language (UPL). + +* New: Added support for using native virtual keyboard with Slate widgets instead of the dialog currently used for text input. + + * Events are triggered when the virtual keyboard is shown and hidden. + + * The show event includes the area of the screen that is covered by the virtual keyboard. + + * This feature is exposed in the Android Project Settings as an experimental feature checkbox. + +* Bugfix: Fixed a crash that could happen when closing the Android web browser. + +* Bugfix: Fixed an issue to handle spaces in ANT_HOME path in generated ant.bat patch. + +* Bugfix: Fixed an issue with application hanging on returning from the lockscreen if orientation is Landscape. + +* Bugfix: Fixed an issue to correct the log warning about Target SDK and permissions. + +* Bugfix: Fixed an issue with Launch On when multiple architectures are enabled in the project. + +* Bugfix: Fixed an issue with ad banner location on Android 7.0 devices. + +* Bugfix: Fixed some documentation errors in UnrealPluginLanguage.cs. + +* Bugfix: Fixed the executable path for stripping Android debug symbols for non-Windows platforms. + +* Bugfix: Fixed an issue with password hiding in input dialog. + +* Bugfix: Fixed an issue with EGL linking issues for ARM64 libraries. + +* Bugfix: Fixed an issue to save and restore texture filtering for movie playback in all cases. + +* Bugfix: Fixed an issue with Mac and Linux install and uninstall scripts if ANDROID_HOME is not set. + +* Bugfix: Fixed an issue with ShowLoginUI interface change in Game Circle plugin. + +* Bugfix: Fixed an issue with HTTPChunkInstaller texture format checks and missing #define warning. + +* Bugfix: Corrected AndroidManifest.xml required features for "Daydream and Cardboard" option when GoogleVR plugin enabled. + +* Bugfix: Fixed an issue to prevent inserting extra permissions into AndroidManifest.xml multiple times from Project Settings. + +* Bugfix: The correct APK file name is now used when launching from editor for Android. + +* Bugfix: Fixed issues with experimental keyboard. + + * Ensure the local scope ScreenRect passed into "On Virtual Keyboard Shown" in AndroidJNI is captured by value instead of by reference. + + * Moved ShowVirtualKeyboardInput's "Keyboard Showing" early-out checks into the UI thread task. This enables the keyboard to continue showing when changing focus between multiple Editable Text Box widgets. + +* Bugfix: Fixed an issue with locations on non-ARMv7 GoogleVR libraries so that it is properly filtered by active architecture. + +* Bugfix: Fixed an issue to properly restore state for Android devices not using separate context for movie playback. + +* Bugfix: Removed an obsolete warning with Java 1.5. The java.source and java.target are now set to 1.7. + +* Only disable Java console command receiver for Shipping builds. + +* Build configuration is passed to UPL for access during packaging as $S(Configuration). + +* Reenabled GooglePlay for ARM64 now that it doesn't crash. + +* Changed Gear VR installLocation to auto as now required by Oculus. + +* Rebuilt ICU libraries for Android with timezones enabled and updated build scripts. + +* Android media player now pauses and resumes with application state. + +* "Is Packaging For Daydream" only returns true if GoogleVR plugin is enabled. + +##### HTML5 + +* New: Emscripten toolchain has been upgraded to 1.37.9. + + * Web assembly + + * WebGL 2 + +* New: There has been an update to GameX template. + + * Multiple (parallel) downloads with progress percentage updates. + + * Test for wasm and WebGL 2 capabilities. + +* New: Updates to python build scripts. + +* New: Configurable .ini settings have been exposed to the editor. These can be found in Project Settings > Engine > HTML5. + +* New: Added support for emscripten "-pre-js" and “-post-js” option when building for HTML5. + +* New: Added support for WebGL 2 shader to turn on Instance Static Mesh Vertex Factory. + +* Bugfix: Fixed an issue with AWS S3 shareable link for shipping builds. + +* Bugfix: Fixed some issues with WebGL 2 shaders. + +* Bugfix: Fixed an issue with HTML5 plugin when Blueprint projects are promoted to code projects automatically. + +* The recommendation from emscripten developers is to use "-separate-asm" option for asm.js builds. + +* Added many new UE4 patches to package HTML on Linux. + +* Since connections are not closed manually (server side), send a dummy payload with content-length data. + +##### Import/Export + +* New: Set Java source and target to 1.7 (fixes Java 1.5 obsolete warnings). + +* New: Added support for changing the variable "r.MobileContentScaleFactor" at runtime on Android. This is useful for device-specific resolution tweaking. + +* Bugfix: Fixed an issue where HTML5 video in a Web Browser widget would only output sound but no video on Android. + +* Bugfix: Fixed an issue where the red and blue channels were reversed in screenshots taken on Android in Vulkan mode. + +* Disabled eglSwapInterval since it can cause issues with some drivers. + +* Changed text for Android Mobile Deferred Renderer setting to indicate that it's only supported on Nvidia K1 and X1 devices. + +##### iOS + +* New: As we move towards the next version of iOS, we will be moving towards 64-bit support only. We have added messaging in this release to start the process of this migration. + +* New: IOS now utilizes the Library/Caches directory to save any data on device. This includes logs and save games. IPhonePackager has been updated to pull the data from this location as well as the Documents directory. + +* New: Xcode 8.3 is properly supported in this release. + +* Bugfix: Fixed a crash if Text Box widget is closed before text is finished being entered. + +* Bugfix: Fixed a crash in the OnlineSubsystem when it is disabled on iOS. + +* Bugfix: Fixed an issue with static audio noise on iOS devices. + +* Bugfix: Fixed an issue with remote compiling by unconverting the path back to host when reading from the module file name. + +* Bugfix: Fixed a memory leak on texture creation with Bulk Data in OpenGLTexture.cpp. + +* Bugfix: Fixed an issue with the device profile names for iPad Pro 9.7 and 12.9. + +##### Linux + +* New: Added pooling of OS allocations on Linux, greatly reducing the need to call mmap/munmap() and avoiding running into vm.max_map_count limit when loading large projects. + +* New: Install of MIME types during setup is now supported. + +* New: UnrealPak is no longer included in the default make target, the prebuilt binary will be used instead. + +* Bugfix: Fixed a crash in ShaderCompileWorker due to misaligned strings. + +* Bugfix: Fixed starting Linux programs using FPlatformProcess::CreateProc() from a path with space. + +* Bugfix: Fixed various issues with Vulkan RHI on Linux. + +* Bugfix: SlateDlg now appropriately compares filter extensions in a case-insensitive way, so both *.fbx and *.FBX work. + +* Bugfix: Fixed bogus "unable to make config file writable" message (the operation was actually succeeding). + +* Bugfix: Fixed clang 4.0 warnings. + +* Bugfix: Fixed inability to rebuild lighting in ResavePackages commandlet on Mac and Linux. + +* Bugfix: Fixed some problems when working from directories that have space character in their names. + +* Bugfix: Fixed older versions of Linux cross-toolchain (ones using LINUX_ROOT instead of LINUX_MULTIARCH_ROOT) not being detected. + +* Bugfix: Fixed a memory leak in callstack symbolication on Linux. This makes memory profiling work again. + +* Bugfix: Fixed an issue with Linux editor splash screen image being wrong when no project has been opened. + +* Bugfix: Fixed MoveFile to work across file systems. + +* Bugfix: Removed redundant RootDir() and EngineDir() on Linux. + +##### Mac + +* New: Enable Metal Shader Model 5 support on Intel as of 10.12.4 and later. + +* New: On Macs that do not support Metal, but erroneously report that they do, show a message box that tells users that the application cannot run instead of crashing on a failed assert. + +* New: Removed Mac OpenGL RHI files and disabled building of OpenGL RHI on Mac. + +* New: Limited support added for exposing debug events to Apple's Instruments "Points of Interest" tool. + +* New: Added RHISetResourceAliasability_RenderThread to FDynamicRHI for RHIs to implement simple render-target aliasing. + +* New: Added FApplePlatformObject, a custom block allocator for Objective-C types (with NSZombie support) which is now used in Metal RHI to decrease allocation costs of Objective-C types. + +* New: Limited support for Xcode automatic code-signing for iOS/tvOS. + +* New: Reimplement RQT_AbsoluteTime for Metal using a similar emulation to OpenGL on Mac so that the scalability system can correctly set the default graphics options. Not all drivers support this and in those cases the scalability settings are determined by an alternative, fixed, code-path. + +* Bugfix: Fixed mouse position issues in fullscreen mode on Mac. + +* Bugfix: Fixed an issue in Avf Media Player causing looped movies to only play once. + +* Worked around Metal's lack of implicit type-casting that was causing incorrect rendering in the Distance Field Ambient Occlusion and Shadows shaders. + +* Re-ordered the options in MetalRHI's internal debug options (Console Variable: "rhi.Metal.RuntimeDebugLevel") to make it more efficient. + +* Minimisation of render-target changes in some passes, notably Scene Occlusion and DBuffer Decals. + +##### Tools + +* Bugfix: Fixed a rare crash with the Web Browser widget on iOS. + +* Bugfix: Fixed iPhonePackager errors in output log when opening Project Settings on Windows. + +* Bugfix: Fixed Get Max Samplers returning an incorrect value for iOS OpenGL, which could have suppressed some warnings for shaders that used more than 8 samplers. + +* Removed duplicate gc.MaxObjectsInGame setting in IOSEngine.ini. + +##### Windows + +* Bugfix: Fixed a problem on Windows where the cursor would get locked to a part of the screen after switching from fullscreen to windowed while the cursor was unlocked. + +#### Programming + +* New: Added an experimental Android option to enable Shipping builds with hidden symbol visibility by default. (bBuildWithHiddenSymbolVisibility). + + * Add JNI_METHOD for java accessible native functions, without this java will trigger an unsatisfiedlinkerror exception. + + * This can significantly reduce the size of the final .so file. + +* New: Added support for map file generation with Android. + +* New: Crash reporter is no longer staged by default when packaging from the editor. The default endpoint for crashes was an Epic server, so including it in packaged games by default was not useful. + +* New: Script plugins can now specify dependencies which should trigger UnrealHeaderTool to be re-run, by overriding the IScriptGeneratorPluginInterface.GetExternalDependencies() method. + +* Bugfix: Fixed a crash where Canvas wouldn't update font engine services if it was never created. + +* Bugfix: Fixed an issue with Automation Tool exception when running Perforce commands if multiple brokers are present in the server configuration. + +* Android links with -gc-sections to remove unused code/data. + +* Program targets can now be excluded from the full solution build roster by setting bBuildInSolutionByDefault to false from their .target.cs file. + +#### Rendering + +* New: Added support for Window PIX. + +* New: Enabled support for NVIDIA Aftermath. On Aftermath enabled executables you can now get a GPU callstack when a GPU crash is detected. + +* New: Enabled support for global Distance Field shaders on GL 4.3 and Vulkan SM5. + +* New: Added support for Quad overdraw viewmode in the Forward Renderer. + +* New: Add support for per-component Skeletal Mesh skin weight overrides. + +* New: Added /VIRTUALIZEDIRECTX option to XgConsole for XGE shader compiling to work on remote machines without DX installed. + +* New: Added support for Structured-Buffer resource views to Metal RHI. + +* New: Added AMD path to experimental D3D11 HDR support. + +* New: Exposed the r.DisableDistortion cvar for toggling distortion rendering. + +* New: The high level rendering code is now PipelineStateObject aware which will allow us to reduce complexity in the rendering backends of Vulkan, Metal and Dx12 in the future. + +* New:Added FShaderCodeLibrary which handles de-duplication of shaders during content cooking and the shader code has moved into a separate library for cooked content runtime loading. This reduces package sizes and load-time overhead. + +* New: Added RHIShaderLibrary for platform specific native shader library implementations. This allows each platform to provide its own optimal shader library implementations. + +* New: Added Metal (MacOS and iOS) native shader library where shaders are loaded from a single Metal library improving the memory footprint, load time, and runtime compile times. + +* New: As part of the cook process for Metal, the archiving process also generate text shaders that can be used when running with optimized Metal shaders. Run with optimized shaders and while debugging with text source. + +* New: Added command line option "-noheartbeatthread" to disable heart beat thread. + +* New: Full refactor of the GPU Skin Cache to fix multiple issues related to Editor, Persona, per-frame numbering. Memory limit is now set per World in the Project Settings > Rendering section. + +* New: ShaderCache now supports running with multithreaded rendering. Command line flag "-norhithread" is no longer required to enable this feature and can now be removed if it was being used solely for this purpose. + +* Bugfix: Fixed a crash with D3D12 in "Update Texture 2D". + +* Bugfix: Fixed an assertion failure in basepass when trying to draw a mesh with Post Process Material. + +* Bugfix: Fixed a crash when the Tile Renderer renders before any other renderer. This could happen in rare cases on Editor bootup. + +* Bugfix: Fixed a crash accessing mesh Material arrays with invalid index. + +* Bugfix: Fixed a potential crash when rendering to accessible buffer. + +* Bugfix: Fixed a possible crash when failing to import cubemaps. + +* Bugfix: Fixed a crash for MacOS/Metal when compiling Materials using the Vector Noise node. + +* Bugfix: Fixed overflow issues that could occur on mali based devices when rendering DoF with bright objects. + +* Bugfix: Various Vulkan fixes: + + * Compiles in Linux. + + * Many cubemap issues squashed. + + * Changed the scratch reflection cubemap clear to SetRenderTargestsAndClear, instead of SetRenderTarget() / Clear(). + + * Added compute fences. + +* Bugfix: Fixed several sRGB related issues with Retainer Box widget. + +* Bugfix: Fixed an issue with prepass/basepass z-fighting, caused by bad vertex welding in depth-only indexbuffer. + +* Bugfix: Fixed an issue with velocity rendering when an off axis projection matrix changes from frame to frame. + + * Affects very few people. Cave rendering and stereo glasses but not HMDs. + +* Bugfix: Fixed an issue with scene motion blur data is only updated for the main renderer frames. Fixes scene captures and planar reflections breaking object motion blur. + +* Bugfix: Fixed an issue with Exponential Height Fog where it renders incorrectly after world origin rebasing. + +* Bugfix: Fixed an issue introduced into 4.15 where Static Meshes with auto-generated LODs were no longer sharing lightmaps between LODs. + +* Bugfix: Fixed bug converting a Procedural Mesh component to a Static Mesh if it only contains a single triangle. + +* Bugfix: Fixed an issue where Scene Capture 2D's show flags would not be applied properly in some circumstances. + +* Bugfix: Fixed an issue where the "disable Stationary Skylight" feature would cause improper warnings. Also made it so that a movable Skylight is always used in Persona preview window so all projects can get preview lighting. + +* Bugfix: Fixed an issue where High Quality Particle Lights would not move properly if their parent was attached to a socket of an animated skeleton. + +* Bugfix: Fixed detection of OpenGL Radeon driver on Mesa. + +* Bugfix: Fixed an issue with shot command in Vulkan. + +* Bugfix: Fixed an issue with refract() intrinsic handling in hlslcc for GL/Metal/Vulkan. + +* Bugfix: Fixed an issue with missing Mobile Material Interface for Landscape "Used Materials" check. + +* Bugfix: Fixed rare case where Decals could incorrectly draw a second time in separate translucency pass. + +* Bugfix: Fixed a bug with the basic eye adaptation mode that could result in incorrect brightness when using a small viewport. This has no effect on the default histogram version of eye adaptation. + +* Bugfix: Fixed an issue with Separate Translucency being affected by Gaussian DoF. + +* Bugfix: Fixed an issue with "Streaming Bounds" show flag not working correctly. It now shows the texture streaming bounds for the textures currently selected in the Content Browser. + +* Bugfix: Fixed possible stall when canceling texture updates. + +* Bugfix: Fixed an issue for tone mapping of bright objects with zero green. Previously, these could have had a one-pixel black outline. + +* Bugfix: Fixed an issue with the IES Light Profile importer with LM-63-1986 format. + +* Texture flags are now properly routed to RHICreateTexture3D from the render target pool. + +* Collection Parameter Nodes no longer rename parameters when duplicated. + +* Renamed console variable "r.Streaming.ScaleTexturesByGlobalMyBias" to "r.Streaming.ScaleTexturesByGlobalMipBias". + +* Now when using the "freezerendering" command, the foliage culling/occlusion will also be frozen. + +* Optimize the computation behind the Screen Position material expression in the pixel shader. + + * Exposes the viewport offset of the view within the render target in the View Property material expression. + +##### FX + +* Bugfix: Fixed an issue with rendering corruption issue with 4 and 8 vertex instanced particles using the wrong Vertex Factory objects. + + * D3D didn't need separate Vertex Factories due to the VertexDecl updating the stride at draw call time, but some platforms were affected. + +##### Lighting + +* New: Improved quality and significantly faster cubemap prefiltering for reflections and skylight. + +* New: Post Process Indirect Lighting Intensity no longer scales Skylight reflections. + +* New: Screen Space Reflections (SSR) now has a higher quality setting for sharp SSR when using Quality Level 4. + +* New: Distance field self shadowing controls for hiding world position offset self-shadow artifacts. + + * Removed Static Mesh Build Settings "Distance Field Bias", which shrunk the distance field, breaking AO and shadows. + +* New: Distance field mesh visualization now uses a cone containing the entire tile to cull objects with, making the results stable. + +* New: Distance field temporal filter stores a confidence value, which is used to track leaking of occlusion during the upsample, and flush those leaked values through the history faster. Reduces DFAO ghosting when the camera is moving. + +* New: Added some new features to the Skylight component. + + * "Occlusion Exponent" which is useful for brightening up indoors without losing contact shadows as “Min Occlusion” does. + + * "Occlusion Combine Mode" which is useful for artists to choose how to combine SSAO with Distance Field Ambient Occlusion. + +* New: Added "r.AOListMeshDistanceFields" which dumps out mesh distance fields sorted by memory size, useful for directing content optimizations. + +* New: Planar reflections handle views smaller than the render target in a general way. + + * Fixes planar reflections with adaptive pixel density (ViewFamily size larger than actual views combined). + + * Planar reflections are now supported in splitscreen. + +* New: Support for fading of Light Propagation Volume cells towards the volume edges. + +* Fresnel of clear coat layer now darkens diffuse for the clear coat shading model. + +* SSR is now reprojected correctly on moving objects. + +* Raised High ShadowQuality to 2048 as 1024 for CSM is too low. + +* Disabled all distance field features on Intel cards because the HD 4000 hangs in the RHICreateTexture3D call to allocate the large atlas. + +##### Materials + +* New: Added a "Sign" material graph node which replaces the library function for more optimal translation. + +* New: Added MinimalAPI to several material expressions. + +* New: Updated default behavior of "Power" node to no longer “abs” or “max” against an arbitrary value as the results were incorrect. + + * Previous version available by calling ClampedPow(x, y) in a "Custom" node. + +* New: Improved material translation preservation of constants. + + * This improves detection of used attributes which prevents some cases of features being enabled incorrectly. + +* New: Material flag normal curvature to roughness now works in the Deferred Renderer. It is no longer forward only. + +* New: Improved Material graph error messages. + +* New: Enabled "r.Streaming.UsePerTextureBias" by default as a way to improve quality in low texture budget settings. + +* Bugfix: Fixed errors across various library Material Functions. + +* Bugfix: Fixed an issue with broken size query for render targets in Material graphs. + + * Implemented missing "Get Size" functionality. + +* Bugfix: Fixed various data type inconsistencies on legacy Make and Break Material Attributes graph nodes. + + * Using these together with the "Get" and “Set” Materia lAttributes nodes should now be more forgiving. + +* Bugfix: Fixed a regression in HLOD shadow casting performance. + +* Bugfix: Fixed inconsistent results with the "Investigate Texture" commands. + +* Bugfix: Fixed possible incorrect results when listing textures used by Material Instances. + +* Bugfix: Fixed an issue where Material Reroute nodes did not bind properly to Texture Object Parameters. + +##### Mobile Rendering + +* New: Mobile Skylights no longer render the scene on the device to determine the sky's color. Mobile skylight uses values determined via captures performed in the editor. This saves memory and performance on device and enables Skylight contribution on devices that do not support fp16 render targets. + +* New: Added "r.Mobile.TonemapperFilm" console variable which can be used to enable/disable new filmic tonemapper on Mobile devices, independently from Desktop platforms (disabled by default). + +* New: Material AO is now supported for the Mobile Rendering path. + +* New: Added better defaults for rendering resolution on iOS devices, to make them more inline with defaults on Android devices. + +* Bugfix: Fixed a crash that could occur on some devices when loading materials which use fonts as texture parameters. + +* Bugfix: Fixed a crash with Particle Cutouts on mobile devices that don't support hardware instancing (ie. Mali-400 GPU). + +* Bugfix: Fixed a crash when enabling shader cache on NVIDIA Shield devices. + +* Bugfix: Fixed a crash when previewing feature level ES3.1 with a Material using World Position Offset. + +* Bugfix: Fixed a crash with Media Player on iOS devices. + +* Bugfix: Fixed an issue with Static Mesh self-shadowing with modulated shadows. + +* Bugfix: Fixed several issues that could cause CSM shadowing on mobile devices to flicker. + +* Bugfix: Fixed an issue with scene captures on mobile when Mobile HDR is disabled and the scene capture source is Scene Color. + +* Bugfix: Fixed an issue with bright dynamic point lights cause bloom rendering artifacts on Android Mali devices. + +* Bugfix: Fixed an issue where Landscapes do not render on some Android PowerVR devices. + +* Bugfix: Fixed an issue where translucent object appear black on Zenfone5. + +* Bugfix: Fixed an redundant blend state change in OpenGL ES2. + +* Bugfix: Fixed rendering artifacts with bloom on iPhone7 using Metal. + +* Bugfix: Fixed an issue where exposure was more extreme on mobile devices with a new filmic tonemapper enabled. + +* Bugfix: Fixed an issue with padded NPOT textures not rendering correctly on iOS. + +* Bugfix: Fixed an issue with gamma issues with canvas elements on iOS Metal devices. + +* Significantly reduced OpenGL state setup for Slate draw calls on Mobile devices. + +* Slate pixel shaders will use half precision, for better UI performance on Mobile devices. + +* Mobile targeted projects will have better UI performance settings by default. + +##### Optimizations + +* New: Added 'r.CompressMeshDistanceFields' console command to rendering project settings, defaults to off to prevent hitches when streaming in levels. + + * When enabled, mesh distance fields are stored zlib compressed in memory until needed for uploading to GPU. + + * 81Mb of backing memory -> 32Mb in GPU Perf Test. + + * Atlas upload time 29ms -> 893ms. + +* New: Added a new global distance field (4x 128^3 clipmaps) which caches mostly static primitives (Mobility set to Static or Stationary). + + * The full global distance field inherits from the mostly static cache, so when a Movable primitive is modified, only other movable primitives in the vicinity need to be re-composited into the global distance field. + + * Global distance field update cost with one large rotating object went from 2.5ms -> 0.2ms on 970GTX. Worst case full volume update is mostly the same. + +* New: Added LOD Distance Factor to Scene Capture Component, which can be used to make scene captures and planar reflections much cheaper to render if the scene has good LODs setup. + +* New: Added the r.LightMaxDrawDistanceScale console command for local light scalability. + +* New: Added a rendering project setting to use 8 bit mesh distance fields. + + * This halves their memory requirement but introduces artifacts with large meshes. + +* New: Added new async tasks to reduce the cost of the texture streaming update on the game thread. + +* New: Added some automatic callbacks whenever dynamic component renderstates are updated in order to also update their texture streaming states. + +* Bugfix: Fixed async SSAO not actually running asynchronously when depth drawing mode was DDM_AllOpaque. + +* Bugfix: Fixed render queries stalling in Test/Shipping builds due to lack of pooling. + +* Ray Traced Distance Field Shadow optimized. + + * From 1.8ms -> 0.8ms in a test scene. + +* Use 16 bit indices for distance field objects culled to tiles, when 16 bit will be enough. This saves 10mb of tile culling buffers. + +* GNM RHI Clear UAV uses a compute shader for buffers larger than 1Kb. + +* GNM Structured buffers are now placed in GPU memory (was previously in CPU memory). + +* DFAO optimizations: + + * Changed the culling algorithm to produce a list of intersecting screen tiles for each object, instead of the other way around. Each tile / object intersection gets its own cone tracing thread group so wavefronts are much smaller and scheduled better. + + * From 3.63ms -> 3.48ms (0.15ms saved). + + * Replaced slow instructions in inner loop with fast approximations (exp2 -> sqr + 1, rcpFast, lengthFast). + + * From 3.25ms -> 3.09ms (0.16ms saved). + + * Moved transform from world to local space out of the inner loop (sample position constructed from local space position + direction). + + * From 3.09ms -> 3.04ms (0.05ms saved). + +* Structured buffers for DF object data. + + * Full global distance field clipmap composite 3.0ms -> 2.0ms due to scalarized loads. + +* Exposed MaxObjectsPerTile with the 'r.AOMaxObjectsPerCullTile' console command and lowered the default from 512 to 256. This saves 17Mb of object tile culling data structures. + + * This can cause flickering in Ray Traced Distance Field shadows if too many objects fall into one shadowmap culling tile. + +* Scene color resolves are restricted to the views. This fixes inefficiency with adaptive pixel density where the views don't match the view family size. + +* When using a full prepass, the base pass no longer writes depth. + + * Saves 0.3ms of Scene Depth Resolve on 970 GTX with MSAA. Also allows masked materials to get EarlyZ in the base pass. + + * Fixed primitives with Use As Occluder set to false being excluded from a full depth pass in static draw lists. + + * Added the "r.BasePassWriteDepthEvenWithFullPrepass" console command for verifying that the base pass depths match the prepass depths. + +* Changing movable skylight properties no longer affects static draw lists. + +* Mesh distance field generation uses Embree, which provides a 2.5x speed increase. + +* Cleared light attenuation for local lights with a quad covering their screen extents. + + * Clearing the entire light attenuation buffer costs 0.1ms. This optimization lowers the minimum cost of a shadow casting light from 0.15ms to 0.03ms. + +* Flushed deferred deletes when reallocating distance field atlas to reduce peak memory, at the cost of a hitch on first frame. + +* Disabled point / spot lights with Max Draw Distance on Low PC. + +* Made use of Metal's "Deferred Store Actions" where available to avoid incorrect “Store” actions introduced when restarting passes to switch encoder types or when using the Metal RHI debugging tools. + +* Stopped the Shader Cache recording all the RHI resources unless it is running on OpenGL. This significantly reduces the CPU overhead of enabling the Shader Cache. + +* HLOD texture force loaded through the "r.Streaming.HLODStrategy" console command will now load visible mips first. + +* The command "BuildMaterialTextureStreamingData" can now be used with "all" as argument to force a rebuild. + +* Reduced the texture streaming overhead for components by keeping track of the state within the streamer. + +##### Postprocessing + +* New: Using Custom Depth to write to the stencil buffer now has the ability to use single-channel bitmasks that ignore depth. This makes it possible to detect overlaps between stencil objects. + +* Bugfix: Fixed log value conversion in tonemapping causing true blacks to be lost. + +* Motion blur no longer gets dark at the edges of the screen. + +#### UI + +* New: Added API to programmatically change the Virtual Cursors UMG Widget on the Viewport Client. + +* Bugfix: Fixed sRGB conversion issues in Retainer Box when used with a material. + +* Multiline editable text boxes can now be marked as read-only. + +* Selecting multiple text widgets will now correctly set text when the text field is edited. + +* Widget Components will now correctly determine between hover and clicked states when using or simulating touch. + +##### Slate + +* New: Added Enum Has All Flags and Enum Has Any Flags, templated functions to make it easier to check for the existence of a flag on enum classes. + +* New: There is now a console variable option, Slate.VerifyHitTestVisibility (off by default), which enables additional visibility checks for widgets. Normally this is not necessary, but if you are changing the visibility of widgets during a frame, and several hit tests need to be performed that frame, there is a chance that a button could be clicked twice in one frame. Enabling this mode will make all hit testing more expensive, so for now it is off by default, but available for licensees that need the extra testing. + +* New: Added the ability to invert alpha when drawing slate textures. This will be used in the future for rendering render targets for the scene which have inverted alpha. + +* Bugfix: Fixed a crash during editable text widget destruction while a context menu was still open. + +* Bugfix: Fixed a crash when deleting a streamed font. + +* Bugfix: Fixed lots of outline data being added to the font cache due to wrongly hashing outline material and color data. + +* Bugfix: Tooltips will no longer show if the cursor is not directly over a Slate window. Fixed a case where the tooltip would not disappear when the cursor is moved over another application's window that was placed on top of a Slate window. + +* Bugfix: Fixed an issue where the cursor would sometimes not appear when its visibility was changed. This was rooted in how the OS requested cursor changes, WM_SETCURSOR on Windows only asks for new cursors when the mouse moves, but often cursors change just because mouse capture changes. So now the path has been centralized in Slate Tick to only handle the cursor changes in one place, and several places that need to refresh the cursor state, now set a flag to handle it on next tick. + +* Bugfix: Fixed a bug with ZOrder being discarded on the SOverlay slot. + +* Bugfix: Fixed Web Browser Viewport to properly scale. + +* Bugfix: SButton now correctly releases mouse capture even if it becomes disabled while pressed, but before 'click' has been fired. + +* Improved text rendering when the last resort font is missing. + + * The last resort font is no longer included in shipping builds, so this change makes some improvements to text rendering when it is missing. + + * The legacy font cache no longer tries to use the last resort font if it is not available (preventing warnings). + + * The Slate font renderer no longer tries to use the last resort font if it is not available. + + * Text shaping will use the last resort character if none of the available fonts can render a given character (likely because the last resort font is missing). + + * HarfBuzz shaped text now uses the fallback character correctly. + +* Kerning-only text shaping no longer draws characters to get their metrics. + +* Text selection height is now the maximum of the line height and text height to account for negative line-height scaling. + +* Added a setting to control whether we should use the font metrics or the bounding box when laying out a font. + + * Not all fonts have accurate metrics data, so using the bounding box can produce much better results for certain fonts. + +* Made slate loading widget / movie playback more thread safe by eliminating Slate application or the main window from being ticked directly on another thread. Is In Game Thread will also no longer return true when called from the slate loading widget thread. + +* Force resolution in standalone if the resolution is larger than primary working area. + +* Moved ESlateDrawEffect & ESlateBatchDrawFlag over to be enum class. Found cases where the enum order was being improperly assumed, and so now it will not be possible to just treat an int32 or a bool as the draw effect value. + +* Slate Application now maintains separate tracking for each pointer being utilized for drag drop, so now multiple fingers on multiple widgets can now simultaneously be attempting a drag, however once one of them becomes successful, we clear all state of all other tracking since only one Drag Drop operation is possible at a time. + +* Fold Tick is now removed from the codebase. We have not supported the other (non-folded) code path for awhile, so there was no point in maintaining the switch. + +* The Checkbox widget no longer just passes visibility down to the internal widgets it creates, that prevents future changes to affect it if it starts collapsed. + +##### UMG + +* New: Added Timing Policy option to Widget Component, so widgets can optionally tick in pausable/dilatable game time rather than real time. + +* New: Added a material function that exposes all of the current UV sets with nice names instead of indexed coordinates. + +* New: Added a method to create Slate Brushes from Paper Sprites the same way we can for materials and textures in blueprints. + +* New: Introduced PreConstruct and Native PreConstruct to the base User Widget. Users can now visualize non-binding based changes in the designer by evaluating a very limited amount of the blueprint code. In the event your user widget crashes on load, due to calling something unsafe, you can disable evaluation in the editor preferences under Widget Designer. + +* New: Introduced a way to inform widgets of more information about the designer. There is now a Designer Changed event sent to all design time widgets letting them know things like the current screen size and DPI scale. + +* Bugfix: Fixed a crash if UI blurs are rotated. + +* Bugfix: Outline color on text elements is now inherited properly. + +* Bugfix: Fixed a bug that prevented Get Owning Player in Widget from returning. + +* Bugfix: Additional fixes to the way we migrate changes from the preview to the serialized version of the widget tree in the widget editor. This fixes several issues with edit-inline Objects on Widgets. + +* Exposed a normalized (0-1) uv coordinate set and scaled pixel size for Box and Border brushes. + +* Widget Interaction Components now ignore Visible(false) Widget Components when tracing. + +* Widget animations now finish evaluating before firing an event alerting that the animation finished. + +* The Widget Interaction Component now checks if the Widget is enabled before it claims that it is over an interactable or keyboard focusable widget. + +* Adding some setters and getters for Redraw Time to the Widget Component. + +* Widgets projected into screenspace from the Widget Component should now appear in the correct locations if the player's camera has an aspect ratio lock. + +* The Safe Zone widget will now show the correct safe zone amount if you use the safezone command line options, which are now documented in the comment for the Safe Zone class. + +* Widget switchers that contain widgets with named slots will now correctly display a widget whose named slot is currently selected. + +* Widgets that are copied and pasted will now retain the same name in the widget hierarchy. + +#### VR + +* New: Added support for getting device depth from Scene Capture Component 2Ds. + +* New: Added ability to disable the autoloading splash screen, which would prevent the manual "hide splash screen" node from working properly. + +* New: Added Gear VR controller support. + +* New: Added support for OES_EGL_image_external to the mobile GL renderer. + +* Bugfix: Negative Stereo Layer priorities are now handled correctly on Steam VR. + +* Bugfix: Fixed threading issue with motion controller tracking that caused controller motion pops. This problem manifested intermittently. + +* Bugfix: Fixed crash on Oculus Rift when attempting to enter stereo mode while the HMD's 'on head' proximity sensor is not triggered. + +* Bugfix: Fixed low framerate when Oculus Rift 'on head' proximity sensor is not triggered and you exit stereo rendering. + +* The GearVR HMD plugin is now only enabled on Windows if the Oculus service is already running. + +* VR console commands have been rewritten to support autocompletion and inline help strings. + + * The VR console commands have also be renamed and now begin with vr.*. + + * The renamed VR commands have backwards compatible aliases, but will print a warning notifying the user about the deprecated functionality. + +* GoogleVR HMD now reacts to changes in the r.ScreenPercentage console command. + +* When the -hmd command line option is used to override the selected HMD, HMD plugins that are loaded early will now be unloaded during PreInit if not selected. + +* Integrated OpenGL support for SteamVR. + +* The left eye is used when selecting LODs to avoid selecting two separate LOD levels when rendering in stereo. + +* PSVR controller tracking limit management system. + + * PSVR can track the HMD and two controllers, but many more devices can be connected. With this system you can manage which controllers are tracked to stay under the limit. + +* Additional WorldScale refactoring for all platforms. + +* GoogleVR plugin updated to version 1.3 + +* Fixed Android manifest for Daydream and Cardboard. + +* Updated GoogleVR plugin to version 1.3. + +* GoogleVR SDK updated to 1.40.0. + +* GoogleVR Mode default changed to Daydream and Cardboard. + +## Programming Release Notes + +#### AI + +* New: Added a new mode to composite EQS generator (UEnvQueryGenerator_Composite), which allows the use of different types of items by each child generator. This can be enabled by advanced properties: bAllowDifferentItemTypes and ForcedItemType. ForcedItemType is the final type returned by the generator, and is used for allocating memory and executing tests. This mode is potentially unsafe and you will have to ensure proper memory layout (matching with ForcedItemType) of all item types used by child generators - usually subsets of ForcedItemType. Keep in mind that allocated memory block is zeroed before use. + +##### Debugging Tools + +* Bugfix: Fixed VisualLog macros for recording segments with user defined thickness. + +* Bugfix: Fixed compilation errors in VisualLog macros for recording custom meshes. + +##### Navigation + +* Bugfix: Fixed memory corruption in generic A* solver: FGraphAStar. + +* Bugfix: Fixed unique Id duplicates in custom navigation links. + +* Bugfix: Fixed FRecastTileGenerator::Modifiers being erroneously counted twice when stating memory. + +* NavModifierVolume has been marked as ENGINE_API and can now be freely used in game code. + +* Made FNavAgentProperties::GetExtent return INVALID_NAVEXTENT if a prop's AgentRadius is not set. This results in properly using FNavAgentProperties::DefaultProperties in navigation queries when no query extent override is provided. + +#### Animation + +* New: Added more exports to AnimationAsset, AnimSequenceBase, and Skeleton classes. + +##### Animation Blueprint + +* Bugfix: Fixed nodes only getting CopyNodeDataToPreviewNode called when pin defaults were changed (not any property change). + +##### Skeletal Mesh + +* New: Added exports to FFbxImporter, FDynamicSkelMeshObjectDataCPUSkin, and FSkeletalMeshObjectCPUSkin, for extensibility. + +#### Audio + +* New: Added new cvars to help with optimization (only applies to the new Audio Mixer). + + * au.DisableReverbSubmix, au.DisableEQSubmix, ​au.DisableParallelSourceProcessing, au.SetAudioChannelCount + +* Bugfix: Fixed MIDI Device plugin public headers not being able to be included from an external module. + +* Optimized internals of new Audio Mixer. Gains approach 15% savings from before: + + * Turned a float divide into a multiply, which occurred at least 32k times per audio update. + + * Avoided thousands of Array.Add() calls during processing, which on shipping still does checks to see if the allocator has to grow, and updates ArrayCount. + + * Removed pointer indirection and successive TArray Add()s in GetChannelMap(). + + * Removed function call overhead to updating channel map. + + * Simplified FSourceParam::Update() to reduce branching and have one return site. + + * Added alternative to GetChannelMap() called UpdateChannelMap() that avoids copying out values to an array. The values can then be fetched from the channel data directly. + + * Refactored internal data to use array of structs rather than struct of arrays for better cache coherency when processing channels one at a time. + +#### Blueprints + +* New: Added an error when declaring a Blueprint Implementable Event with an enum param that is not plain or a byte type (Blueprints only support byte-sized enums). + +#### Core + +* New: There are now several serialization options available to specify what the cooked Asset Registry includes. Look for the serialize flags inside the [AssetRegistry] section of BaseEngine.ini. + +* New: An experimental bUseAssetRegistryForIteration option has been added to CookerSettings. This improves the performance of iterative cooking by loading the cooked Asset Registry directly, but it may still have issues with some changes to source files being missed. + +* New: Added a cvar to control the pak precacher throttle. + +* New: Added new GenericPlatformFile function, GetTimeStampLocal, which returns file time stamp in local time instead of UTC. + +* New: Added a check against assembling the reference token stream while streaming without locking the garbage collector. + +* New: Added a static_assert to prevent the use of TMap keys which do not implement GetTypeHash, as this causes runtime crashes when they are manipulated by a UMapProperty. + +* New: Added a bForceDebugUnrealHeaderTool option to BuildConfiguration.xml which forces the Debug version of UnrealHeaderTool to be run instead of Development. + +* New: Added a static_assert to ensure that TInlineSetAllocator is instantiated with a power-of-two hash size, as this is a requirement for TSet and TMap. + +* New: Added ICppStructOps::IsAbstract() for testing if a native type is abstract via the property system. + +* Bugfix: Fixed TInlineValue not calling virtual destructors. + +* Bugfix: Fixed several issues with editor-only objects not being correctly stripped when cooking. + +* Bugfix: Fixed several issues with Config files loaded from Plugins. They now correctly handle diffing game-specific changes. Engine plugins config files should be named BasePluginname.ini, and game plugins should be DefaultPluginname.ini. + +* Bugfix: Fixed many bugs with the event driven loader and allowed it to work at boot time. + +* Bugfix: Fixed a bug with nativized Blueprints that was introduced with the boot time EDL changes. + +* Bugfix: Fixed race in audio streaming. + +* Bugfix: Fixed bug which would cause a fatal error when cooking subobjects that were pending kill. + +* Bugfix: Fixed a bug with EDL at boot time which caused a fatal error with unfired imports. + +* Bugfix: Fixed a bug with RF_PendingKill subobjects and the new loader. + +* Bugfix: Fixed an obscure problem with stats in commandlets that use async tasks. + +* Bugfix: Fixed rare ensure cooking for the EDL. + +* Bugfix: Fixed boot time EDL causing some issues even when it wasn't being used. + +* Bugfix: Fixed .pak precacher shutdown. + +* Bugfix: Fixed memory leak in .pak precacher. + +* Bugfix: Fixed bad merge of priority change in the EDL. + +* Bugfix: Fixed race that resulted in a memory leak when reading compressed paks. + +* Bugfix: Fixed a weird recursive situation where StaticLoadObject could return an object that has not finished loading. Also produces a fatal error if this happens. EDL only. + +* Bugfix: Fixed batched render fences when BeginDestroy calls FlushRenderingCommands. + +* Bugfix: Fixed loading a package that is already loaded. + +* Bugfix: Fixed crash in signature checks when mounting pak files. + +* Bugfix: Fixed a change to NotifyPrimitiveDetached so that it works in the editor. + +* Bugfix: Fixed hash table lock optimization. + +* Bugfix: Fixed a crash relating to FGenericAsyncReadFileHandle when not using the EDL. + +* Bugfix: Fixed comments in GenericPlatform.h. + +* Bugfix: Fixed errors raised during code generation when a multiply-inherited base class happens to have the same name as a UObject after its prefix is stripped. + +* Bugfix: Fixed a compile error when calling TArray::HeapSort on an array of pointers. + +* Bugfix: Fixed a crash when calling UCookOnTheFlyServer::FFilePlatformRequest::ToString(). + +* Bugfix: Fixed compile errors raised when #pragma is used inside USTRUCTs. + +* Bugfix: Fixed compile errors caused by whitespace existing before a UCLASS() macro. + +* Bugfix: Fixed TStructOpsTypeTraits::WithCopy giving different results when the trait is specialized without a WithCopy value from when it isn't specialized at all. + +* Bugfix: Fixed a compile error when serializing bools to an archive in editor builds, where the archive type overrides other serialization operators. + +* Bugfix: Fixed FWorldTileInfo::Read() to copy the correct licensee version number from the file summary into the archive. + +* Bugfix: Fixed a regression in FObjectAndNameAsStringProxyArchive to re-allow serialization of TWeakObjectPtrs. + +* Bugfix: Fixed some include-what-you-use issues in the engine and plugins. + +* Bugfix: Fixed UPROPERTYs being skipped when there are redundant semi-colons between the properties. + +* Asset Registry memory and performance have been significantly improved in both Editor and cooked games for large projects. + +* Allowed UnrealPak to do a better job with EDL pak files when the order provided is old or from the cooker. + +* Several minor tweaks to low level async IO stuff. + +* Stored a copy of the callback in async read request so that we do not need to worry about lifetime so we can capture variables as needed. + +* Cancelling async loading with the EDL loader now prints a warning and does a flush instead. + +* Suppressed a few EDL cook warnings. + +* Tweaked the EDL for to all platforms. + +* Platform load time performance tweaks. + +* Abstracted the IO tracker and handle manager for other platforms and applied it to all platforms. + +* Protected against UDeviceProfileManager::Get() recursion and demoted a related fatal error to a log statement. + +* Removed old code relating to FAsyncArchive, FAsyncIOSubsystemBase and package level compression. The editor now uses the lowest levels on the new async IO scheme. + +* Increased estimate of summary size. + +* Avoided adding a linker annotation if it actually has not changed. This improves ConditionalBeginDestroy performance. + +* Avoided a redundant removal of PrimitiveComponent from the streaming managers during ConditionalBeginDestroy. + +* Optimized UObject hash tables for speed and space. + +* Put the special boot order things into baseengine.ini so that licensees and games can add to it. + +* Renamed HasBeenAlreadyMadeSharable to DoesSharedInstanceExist. + +* PostLoadSubobjects is now called on all objects regardless of whether they have a CDO as outer or not. + +* When Rename is used to change the Outer without specifying a new name, the existing name is maintained whenever possible. + +* ForwardVector, RightVector, and single float FVector constructors are now recognized by Unreal Header Tool as default values for an FVector parameter. + +* ScriptMacros.h no longers needs to be included in header files that generate a header. + +* Improved the readability of some of the ReferenceChainSearch code. + +* Automatically included ObjectMacros.h in generated headers to prevent compile errors. + +* Made FPaths::Combine() variadic so that it can take arbitrary numbers of arguments. + +* Improved the readability of the verbosity of log categories in the debugger. + +* Updated TArray::Sort comments to clarify what happens when sorting an array of pointers. + +* Clarified the assertion message you get when inserting or removing a TArray element by reference which comes from the array. + +* Clarified the comments for TArray::FindLastByPredicate and FString::FindLastCharByPredicate. + +* Removed UnrealCodeAnalyzer. + +* Raised an error in UnrealHeaderTool when a header containing UCLASSes, USTRUCTs etc. does not include its .generated.h file. + +* Removed TBoolConstant template. + +* Changed TAssetPtr to allow it to be constructed from nullptr without a full definition of T. + +* Removed the WITH_HOT_RELOAD_CTORS macro. + +* Removed the UseVTableConstructors .ini option. + +* Removed generated FName variables for UFUNCTIONs. + +* Removed the generation of obsolete .java and .proto files used for replication. + +* Replaced the set of bools used to FBlueprintCompileReinstancer with a new EBlueprintCompileReinstancerFlags enum. + +* Improved hot reload logging messages to make it clear that a compile attempt on a module does not guarantee a reload of that module. + +* Made UnrealHeaderTool report an error if a UFUNCTION in a derived class has the same name but a different signature from one in a base class. + +#### Editor and Tools + +* New: Added spinner options to VectorInputBox. + +* New: Added a None option to the FKey customization, unless the FKey property had NoClear on it. + +* Bugfix: Implemented a fix to ensure FVirtualTrackArea::HitTestSection checks the row of the section. + +* Bugfix: Fixed an issue where ISequenceAudioRecorder was inaccessible to FAudioRecorder. + +* Project and plugin templates now use "include what you use" style by default. + +* When using BuildGraph, the cached list of completed nodes is now cleared by default, making the -ClearHistory argument redundant. Use the -Resume argument to continue an interrupted build using the current artifacts. + +* BuildGraph now outputs an error if any build products from previous steps are tampered with during the execution of a subsequent step. + +* The editor now offers to download and install Visual Studio 2017 if an existing version of Visual Studio is not found. + +* The AutomationTool -CookDir argument no longer accepts multiple parameters separated by '+' characters, since '+' is valid in directory names. Multiple -CookDir arguments are supported instead. + +* Game mods can now be denoted by setting the bIsMod field to true inside the .uplugin descriptor. Mods will be shown in a separate category in the plugin browser, and will be shown separately in generated project files. Installed editor builds can build and clean mods without modifying build products for the base game. + +##### Content Browser + +* Bugfix: Fixed link error when FAssetData::PrintAssetData() is used in a project. + +##### Sequencer + +* Unified global and object-bound pre animated state, and added InitializeObjectForAnimation method to state producers. + +* Opened the API for MovieSceneAudio-related classes along with some minor functionality additions. + +* Exported MovieSceneTrackEditor to allow custom tracks to be created that derive from existing tracks. + +#### Gameplay Framework + +* New: Added support for FScopedMovementUpdate to be able to queue up overlaps that do not require reflexive bGenerateOverlapEvents. This requires custom code to be able to process these overlaps. + + * This allows custom inspection or processing of overlaps within a scoped move, without enabling the more expensive overlap flag. For instance you could have a fast projectile with an overlap response to a character mesh and get those overlaps from the trace without requiring expensive overlap processing when the mesh moves. + + * Overlap events from the move will still only trigger from UpdateOverlaps() if bGenerateOverlapEvents is enabled on both components, as before. + + * Made some data in FScopedMovementUpdate protected rather than private so it can easily be subclassed, and exposed a new helper ​SetWorldLocationAndRotation() for committing the move. + +* Bugfix: Fixed a crash when manipulating audio component properties from an Actor's constructor during async loading. + +* Bugfix: Fixed CharacterMovementComponent updates with very high delta time on server when initially joining. Made sure the ServerTimeStamp is initialized to current world time rather than zero to prevent large delta. + +* CheatManager functions to Damage/Destroy targets are now easier to override in game-specific subclasses. + +* InputComponent now has BindAction function that allows binding functions with additional parameters. + +* RawInput configuration structures can now be manipulated by other modules. + +* AActor::GetComponents() with generic type is now optimized to not force an allocation when the component count is large. + + * Previously it incorrectly assumed the output array needed space for the entire contents of OwnedComponents. If OwnedComponents.Num() > the array reserve size, this forced an allocation, even if few or no components of the requested type were found. + + * It is still recommended to use TInlineComponent array or an array using TInlineAllocator<> when using this function. + +* Removed allocations during creation in ​AAIController::PostInitializeComponents() (in non-shipping builds). + +* Optimized HasActiveCameraComponent() and ​HasActivePawnControlCameraComponent() to avoid filling an array while searching for a certain component, which could have caused an allocation. + +* Optimized MoveComponent() collision queries to avoid processing PhysX touches when bGenerateOverlapEvents is off. + + * Added support for bIgnoreTouches to FCollisionQueryParams. This allows GeomSweepMulti to filter out touches/overlaps much earlier. + +* MovementComponent does not ignore initial blocking overlaps when moving away from the impact normal from SafeMoveUpdatedComponent(). This fixes various cases where characters could be pushed through moving objects because they were moving away from the overlapping object, but not fast enough. + + * It now always uses the hit result to depenetrate from the impact as much as possible, and then retries the move. + + * Hit events are not triggered for the first test for depenetration. + +* CharacterMovement AdjustFloorHeight() is now allowed to adjust using the line trace if the sweep was in penetration. It also forces another next floor check so it will check after it adjusts the height or depenetrates, relevant when bAlwaysCheckFloor is off. + +* Optimized CharacterMovement tick to not extract transform values twice when they would not change in a small block of code. + +* Call TickCharacterPose() and clear root motion before abandoning tick in ​UCharacterMovementComponent::PerformMovement() when movement mode is None. This prevents root motion building up until the next valid movement mode. + +* Applied a performance tweak to ​ApplyRadialDamageWithFalloff(). + + * Do not rebuild FRadialDamageEvent each loop over hit actors. + + * Added stats for ​BreakHitResult()/MakeHitResult() under "stat game". + +* Optimized attachment to check welding option before expensive casts and body instance fetching. + +#### Localization + +* Bugfix: Fixed a bug where passing an empty FText to ChangeKey() would keep the previous FText value that had been passed in. + +#### Online + +* New: Added the bShowSkipButton parameter to IOnlineExternalUI::ShowLoginUI, which will display the "skip" button on relevant platforms. + +#### Other + +* New: Added missing initialization for SWindow::bIsMirrorWindow. + +* Bugfix: Added missing module dependencies. + +* Bugfix: Fixed a type casting issue. + +#### Physics + +* New: Added virtual keyword to DestructibleComponent ApplyDamage and ApplyDamageRadius. + +* New: Added Physx simulation shader override (see GSimulationFilterShader). + +* Bugfix: Fixed a debug rendering issue by recreating physics when changing mobility of components. + +* Bugfix: Fixed compile error when PHYSX_MEMORY_STATS=1. + +* Bugfix: Fixed performance regression caused by using collision aggregates for Instanced Static Mesh Component. + +* Bugfix: Fixed a crash in AABB Manager when origin shift is used. + +* Made UDestructibleComponent::SpawnFractureEffectsFromDamageEvent virtual. + +* Exported URadialForceComponent class for inheritance. + +* Allowed the editor to compile when bRuntimePhysicsCooking is disabled (cooking is still allowed in WITH_EDITOR builds even with it disabled). + +* EndPhysics tick will no longer be scheduled if QueryOnly is used on a ragdoll. + +* Removed the unsupported option of HideBone with DisableCollision when calling HideBone. This was not actually supported and did nothing so shouldn't break any behavior, just don't call the function. + +* Exposed PhysX enhanced determinism mode using the compiler flag PHYSX_ENABLE_ENHANCED_DETERMINISM. This allows local subsets of the PhysX simulation to behave deterministically independent of what is going on elsewhere in the Physics world. + +#### Platforms + +* Bugfix: Fixed a crash bug in cases where we received a duplicate user login/logout notification from the system software. + +* Bugfix: Fixed Codelite project having duplicated settings. + +* Moved some C++ defines out of the build.cs file into a C++ header. + +* Moved controller connect/disconnect handling to the main thread to fix issues with thread safety for callbacks. + +##### Android + +* New: Added functionality to use the visual studio mobile projects for debugging. To generate them run "generateprojectfiles.bat -vsdebugandroid" from a command prompt. After you have packaged your game for Development and put it on the device, you can set this new project as the start up project and run/debug the project in Visual Studio. + +* New: Support for Android runtime permissions added. Certain permissions have been removed or put under condition to check for support when the target sdk is greater than or equal to 23. + +##### HTML5 + +* New: Added new webassembly (wasm) toolchain - SIMD and multi-threading are not yet supported (these are slated to be in for wasm2). + + * These will be automatically turned off when building with wasm (as opposed to asm.js). + +* Removed HTML5 code from the Engine's SaveGameSystem.h and placed it in HTML5Platform.cpp. + +* Cleaned up HTML5PlatformFile.cpp and made it match as close as possible to linux's version. + +* Created HTML5's own PlatformFeature & SaveGameSystem files, and updated HTML5PlatformMisc to make use of the the new HTML5 SaveGame code. + +##### Linux + +* New: Added FreeBSD memory information functions to facilitate out-of-tree UE4 FreeBSD port. + +* New: Added a new cross-toolchain (version 9, includes clang 4.0) when targeting Linux on Windows. + +* New: Added some support for building on Debian Sid or Stretch. + +* New: Added clang to Fedora dependencies. + +* New: Added ability to compile Linux servers for 32-bit x86 architecture. + +* New: Added files generated for KDevelop to .gitignore. + +* Bugfix: Fixed more third party libraries to use libc++ instead of libstdc++. + +* Bugfix: Fixed memory leaks when symbolicating an address in Linux callstacks (during crash reporting and memory profiling). Makes runs with the memory profiler much faster. + +* Bugfix: Fixed rebuilding of VHACD (a third party library) on a case sensitive filesystem. + +* Bugfix: Fixed CodeLite projects to now use proper Debug binaries for debug configurations. + +* Switched Linux file abstraction to use new managed filehandles. Shared by all platforms with low limit of open files. + +* Whitelisted SteamVR plugin for Linux so SteamVR Blueprint functions are always available, even if stubbed. + +* Made source code accessor aware of clang 3.9 and 4.0. + +* Setup will now install the latest clang on Arch instead of clang35. + +##### Mac + +* Fixed address sanitizer support in MacToolChain (Apple changed the name of the env variable Xcode uses to enable it) and added support for thread sanitizer. + +* Fixed a problem where the glslang library was not enabled on Mac, preventing building an Android project with Vulkan from Mac. + +* Made Binned2 malloc work on Mac. + +#### Programming + +* New: When compiling a module written in include-what-you-use style, source files which are in the adaptive non-unity working set are now built with precompiled headers disabled, to expose errors with missing headers. Set bAdaptiveUnityDisablesPCH to false in BuildConfiguration.xml to disable this behavior. + +* New: Added initial support for async creation of pipeline state objects, enable using r.AsyncPipelineCompile. + +* Module .build.cs files, which depend on the contents of external files, can now add those paths to the ExternalDependencies list. Modifications to those files will trigger the the UBT makefile to be invalidated. + +* Plugin config files are now included in generated project files. + +* UnrealBuildTool will no longer attempt to use SN-DBS for build distribution if the service is disabled. + +* UnrealBuildTool now correctly supports compiling modular targets which do not use the shared engine build environment. + +* C# programs will now be included in generated project files automatically if a blank file called UE4CSharp.prog is found in the same directory. + +* The engine will now warn when trying to load a plugin with a mismatched "EngineVersion" setting. + +* Deprecated shared pointer typedef from ImageWrapper and removed usages. + +* Removed boilerplate header from ImageWrapper. + +* Removed monolithic boilerplate header from NetworkFileSystem. + +* Removed boilerplate header from LauncherCheck. + +* LauncherServices: Removed boilerplate header from LauncherServices. + +* Completed a modernization pass of Automation. + +#### Rendering + +* New: Added thickness option to debug DrawWireDiamond function. + +* New: Added a check to see if there are duplicated shader type names. + +* Bugfix: Fixed obscure check with flushing RHI resources. + +* Bugfix: Fixed hazard with SetMaterialUsage from a thread. + +* Bugfix: Fixed Windows handling of -sm4 and -sm5 so it can be used with -vulkan and -opengl. + +* Bugfix: Fixed selection of swapchain format for Vulkan on some Linux drivers. + +* Bugfix: Fixed an issue on Vulkan when copying into a cubemap face. + +* Bugfix: Fixed a bug calculating vertex declaration hashes on OpenGL. + +* Moved FPositionVertexBuffer & FStaticMeshVertexDataInterface declarations into their own headers, moved FStaticMeshVertexBuffer implementation into its own source file. + +* Updated Vulkan distributables and glslang to SDK 1.0.39.1. + +* Vulkan shaders now build using glslang 1.0.42.2 and includes those headers for redistribution. + +* Prefer D32_S8 on Vulkan instead of D24_S8 for the depth buffer. + +* Removed the temporary functions RHIClearColorTexture, RHIClearDepthStencilTexture and RHIClearColorTextures from each RHI. + +* Separated depth/stencil load/store actions. + +* Use the latest SDK for Vulkan, whether the one we distribute in ThirdParty or an installed version. + +* Implemented SetStencilRef() and SetBlendFactor() on RHIs which were missing it. + +#### UI + +##### Slate + +* Updated Slate to allocate widgets using MakeShared. + + * This saves one allocation per-widget. + +* Moved SVirtualWindow into Slate module from UMG. + +#### VR + +* New: Added an initial base implementation of IHeadMountedDisplay, FHeadMountedDisplayBase, that can be extended by HMD implementations instead of extending IHeadMountedDisplay directly. This base class provides default and or common implementations for parts of the IHeadMountedDisplay interface. Future releases may add more common functionality to this class, reducing the amount of work required to add support for new HMD platforms even further. + +* StereoLayers now have a default emulated implementation, making them supported on most VR platforms that did not already support them. HMD implementations that extend FHeadMountedDisplayBase will automatically inherit the functionality unless explicitly overridden. + +* Common code found in various HMD plugins handling management of StereoLayers has been extracted into a template base class, TStereoLayerManager, that provides a thread-safe way to manage a list of registered stereo layers. + +* The old Morpheus StereoLayers implementation has been removed in favor of the common stereo layers implementation provided by the HMD base class. + +## Upgrade Notes + +#### C++ API Changes + +* As part of the Asset Manager changes, Streamable Manager has been improved to support the concept of Streamable Handles. When requesting an async load, it now returns a shared pointer handle that will keep the requested object loaded as long as it exists. These handles can also be polled or waited on. + + * Synchronous Load and Simple Async Load on Streamable Manager have been deprecated in favor of the new Streamable Handle system. Both of those functions would keep assets loaded until explicitly unloaded, which in practice was not what most people wanted. + +* The Class/Property/Function redirect system has been rewritten to be faster and more flexible. Ini redirects such as "+ActiveClassRedirects" defined in [/Script/Engine.Engine] will still work, but the new system is used by putting redirects like “+ClassRedirects” in the [CoreRedirects] section of Engine.ini. + + * All engine redirects prior to 4.10 have been moved to CoreRedirects.cpp, newer redirects are now in the new format in BaseEngine.ini. + + * A single Property/Function redirect definition will now be applied for both blueprints and serialization, and redirects can now be defined with wildcard matching syntax to simplify large refactors. + + * Object and Package redirects can now be used to allow limited redirection of content references without creating an Object Redirector on disk. + + * Enum redirects have been improved and will now fully work with or without the Enum Name being specified. + +* Several Enum functions dealing with string conversion have been deprecated, and the names and comments have been cleaned up to make it more clear which are meant to be used at Runtime and which are meant to be used in the Editor/for debugging. + +* The console command "r.MSAACount 1" now produces no MSAA or TAA. “r.MSAACount 0” can be used to toggle TAA on for comparisons. + +* Cascaded Shadow Map resolution is now controlled by the console command "r.Shadow.MaxCSMResolution" instead of “r.Shadow.MaxResolution”. + +* New mobile targeted projects will have better UI performance settings by default. + + * Please enable "Explicit Canvas Child Z Order" option in project Slate Settings, to improve UI batching. Enabling this option may require manual Z Order tweaks in UMG Canvas panels if there Z ordering issues. + +* VR console commands have been rewritten to support autocompletion and inline help strings. + + * The VR console commands have also be renamed and now begin with vr.* + + * The renamed VR commands have backwards compatible aliases, but will print a warning notifying the user about the deprecated functionality. + +* The Exec method in Head Mounted Display has been removed, as all VR console commands now use Auto Console Command or similar to register console commands. + + * HMD implementations relying on having an Exec method now need to provide their own ways of registering console command handlers. + +* Set Visibility and Set Hidden In Game in Scene Component are no longer virtual. Instead override On Visibility Changed or On Hidden In Game Changed to respond to changes to these values. + +* The FBox and FBox2D constructors taking an int32 value have been deprecated as the value of that integer was not being used. The Force Init constructor should be used instead. + + * Replace FBox/FBox2D construction of the form FBox(0) with FBox(ForceInit). + +* The Unreal Header Tool now outputs an error when an Editor-only struct member is exposed to blueprints. This is necessary because packaged builds will crash if a Make/Break node for that struct is executed in a blueprint. + + * Any Blueprint exposed Editor-only struct members must either be made not Editor-only or no longer exposed to blueprints. + +* Post Load Map now provides the loaded World as a parameter to the delegate function. The World will be null if the load failed. + + * All existing functions bound to Post Load Map need to have a World pointer added to their signature. + +* Stop saving raw curve data into animations on cook to save memory/disk space. + + * If you are directly accessing Raw Curve Data on an Anim Sequence, this will no longer work in cooked builds. Animation Asset now provides a virtual function, Get Curve Data, to grab a reference to the correct Curve structure. + +* Removed boilerplate header from Automation Window. + + * The AutomationWindow.h boilerplate header file has been removed. Please replace all includes of AutomationWindow.h with IAutomationWindowModule.h + +* Removed boilerplate header from Automation Controller. + + * The AutomationController.h boilerplate header file has been removed. Instead of AutomationController.h, include the individual interface headers that you actually use. Remove the "Interfaces/" subdirectory from existing interface inclusions. + +* Automation Modernization pass + + * The IAutomationWorkerModule.h has been moved to the module's public root directory. Please remove the relative path from your existing include statements. + +* Removed boilerplate header from LauncherCheck. + + * The LauncherCheck.h boilerplate header file has been removed. Include ILauncherCheckModule.h instead of LauncherCheck.h. Remove "Interfaces/" subdirectory from existing ILauncherCheckModule.h inclusions. + +* Removed boilerplate header from LauncherServices. + + * The LauncherServices.h boilerplate header file has been removed. Instead of including LauncherServices.h, include the ILauncherXXX.h files that you actually use. Remove the "Interfaces/" subdirectory from existing ILauncherXXX.h includes. + +* Deprecated shared pointer typedef and removed usages from ImageWrapper. + + * The IImageWrapperPtr typedef has been deprecated. Please use TSharedPtr instead of IImageWrapperPtr. + +* Removed boilerplate header from ImageWrapper. + + * The ImageWrapper.h boilerplate header file has been removed. Instead of including ImageWrapper.h, include the actual IImageWrapperXXX.h files that you use. Remove the "Interfaces/" subdirectory from existing IImageWrapperXXX.h includes. + +* Removed monolithic boilerplate header from NetworkFileSystem. + + * The NetworkFileServer.h boilerplate header file has been removed. Instead of including NetworkFileServer.h, include the INetworkFileXXX.h headers that you actually use. Remove the "Interfaces/" subdirectory from existing INetworkFileXXX.h includes. + +* Changed default contact-gen method to PCM. This is the default in PhysX 3.4. + + * This may have slight implications on jitter and stability, but should be improved overall. The old behavior is still available (set EnablePCM = false in the project settings). + +* Removed the temporary functions RHIClearColorTexture, RHIClearDepthStencilTexture, and RHIClearColorTextures from each RHI. + +* Removed obsolete SmartCastProperty function. + +* Added a static_assert to prevent the use of TMap keys which do not implement GetTypeHash, as this causes runtime crashes when they are manipulated by a UMapProperty. + + * TMap key types must now implement GetTypeHash. Having GetTypeHash be implemented in a base class or being implicitly convertible to a type which is hashable is not sufficient. + +* Fixed TStructOpsTypeTraits::WithCopy giving different results when the trait is specialized without a WithCopy value from when it isn't specialized at all. + + * TStructOpsTypeTraitsBase has been deprecated. + +* Improved support for TTuple. + + * Tuples have a GetTypeHash function and can be used as a TMap key. + + * Can now be serialized to archives. + + * Can now be compared for equality with operators == and !=. + + * Can now be compared lexicographically with operators <, >, <= and >=. + + * TPair is now an alias for a 2-tuple, which is specialized to have Key and Value fields, but otherwise has the same functionality as all other tuples. + + * Tuple.h is now found in the Core/Public/Templates folder, rather than the Core/Public/Delegates folder. + + * TPairInitializer now converts to TPair, rather than TPair being constructible from TPairInitializer. + +* Removed UnrealCodeAnalyzer. + +* Added a static_assert to ensure that TInlineSetAllocator is instantiated with a power-of-two hash size, as this is a requirement for TSet and TMap. + + * TInlineSetAllocator will no longer compile if the hash size is not a power-of-two. + +* Removed TBoolConstant template. + +* Removed the WITH_HOT_RELOAD_CTORS macro. + +* Removed the UseVTableConstructors .ini option. + +* Removed generated FName variables for UFUNCTIONs. + +* Refactored EvaluateBoneTransforms to prevent usage of skeletal mesh component. + + * Deprecated EvaluateBoneTransforms in favor of new ​EvaluateSkeletalControl_AnyThread. + + * Deprecated skeletal mesh component argument to ConvertCSTransformToBoneSpace and ​ConvertBoneSpaceTransformToCS. Now they just take a transform. + +* Added a new overload for IOnlineSession::FindFriendSession in the session interface that can retrieve sessions for multiple friends. + + * Sending and accepting invites on dedicated servers on Steam is now supported. + + * The FOnFindFriendSessionCompleteDelegate now returns an array of FOnlineSessionSearchResult objects instead of just one. + +* The high level rendering code is now PipelineStateObject aware which will allow us to reduce complexity in the rendering backends of Vulkan, Metal and Dx12 in the future. + + * The loose state setting APIs of the Commandlist have been deprecated, instead the entire pipelinestate has to be set at once. + +* Moved controller connect/disconnect handling to the main thread to fix issues with thread safety for callbacks. + +#### Animation + +* When converting skeletal controls to the newer API, convert EvaluateBoneTransforms to ​EvaluateSkeletalControl_AnyThread. Backwards compatibility will be maintained, however warnings will persist. Any mesh component access should be cached in PreUpdate() as accessing the component is not thread safe. + +* If differences in timing between Maya and UE4 are experienced after importing Alembic files, this has been corrected. The fix requires that any problematic assets be reimported. + +#### Blueprints + +* The ticking behavior of latent actions in components has been changed to match how they behave in actors. When the component ticks, the latent actions will now be processed at the same time, rather than happening later in the frame when latent actions for non-ticking actors and components are processed. This does change behavior, so there is a console variable (t.TickComponentLatentActionsWithTheComponent) that can be used to revert to the older behavior until affected component Blueprints that depended on the old ordering behavior can be fixed up. The cvar should be treated as deprecated, and it will be removed in a future release. + +#### Core + +* To save on memory and disk space the cooked Asset Registry no longer includes Dependency information by default. If you need this information at runtime, enable bSerializeDependencies in the [AssetRegistry] section of BaseEngine.ini. + +* Starting asynchronous loads from within asynchronous loads has always been unsafe, but will now explicitly assert. This can be fixed by not starting asynchronous loads from within PostLoad functions, or deferring your game-specific code for a frame when called from an async callback. + +* Callback functions passed into Request Async Load will now execute on the next frame instead of immediately upon completion of an async load. This behavior is to avoid issues with calling async loads recursively, but if your game depends on this behavior you can restore it to call them immediately by setting the cvar s.StreamableDelegateDelayFrames to 0. + +* There is a new format for defining class/function/property redirects in ini files, check the [CoreRedirects] section of BaseEngine.ini for examples. The older formats will still work but the new format provides additional features and a simpler syntax so you may want to upgrade. + +* Any calls to Smart Cast Property should be replaced with code which explicitly handles the inner property of Array Property. + +* Get Type Hash implementations must now be added to types which are used as TMap keys. If your type defines Get Type Hash in a base class or is hashed via an implicit conversion, these should be fixed by implementing their own function and forwarding the call to the appropriate implementation. + +* Any use of TStructOpsTypeTraitsBase should be replaced with TStructOpsTypeTraitsBase2, where T is the type that the trait is being specialized for. + +* `#include "Delegates/Tuple.h"` should be replaced with `#include "Templates/Tuple.h"`. + +* As TPairInitializer is now convertible to TPair, rather than TPair being constructible from TPairInitializer, types which do not correctly implement copy or move semantics by not inhibiting the compiler defaults may cause a bad state when they are inserted into a TMap or TSet. All types used in UE4 containers should correctly define copy or move semantics. + +* Any dependence on Unreal Code Analyzer should be removed from projects. + +* The explicit usage of TInlineSetAllocator in any TSet and TMap should be updated to ensure that the template arguments provided result in hash sizes which are a power-of-two. + +* TBoolConstant should be replaced with TIntegralConstant. + +* Any use of WITH_HOT_RELOAD_CTORS should be replaced with the assumption that the value is 1. + +* Any use of the Use VTable Constructors .ini option should be replaced with the assumption that the value is true. + +* Use of generated FName variables for UFUNCTIONs (e.g. ENGINE_ReceiveTick) should be replaced with a string literal or a custom static FName variable in your own code: + + * For example: static const FName ENGINE_ReceiveTick = TEXT("ReceiveTick"); + +* If Unreal Header Tool reports an error about a function having a different signature from a base class, it should be fixed to have the same signature, or renamed. + +#### Editor and Tools + +* Exposed Make Property Combo Box in Property Customization Helpers to allow embedding an enum combo box into Struct Customizations. + +* Added Custom Column support to the Asset Picker Config. + +* If you use a protected platform, your project settings will start to be saved under MyGame\Config\Platform\PlatformEngine.ini, instead MyGame\Config\DefaultEngine.ini. + +#### Platforms + +* Made some big Device Profile changes, particularly for the protected platforms. You may need to modify your Device Profiles in similar ways if you are a heavy user of them. + + * Changed the "type" of some DPs from WindowsNoEditor, etc to Windows. It should be a platform, not a random string. + + * With that change, the platform can be used to save out protected platform DP .ini files to subdirectories, maintaining secrecy. + + * When saving DeviceProfiles, you may need to look in a platform subdirectory for the DeviceProfiles.ini file. + + * Added Config/[PlatformName]/ConfidentialPlatform.ini files so that the DP loading code knows to look in their directories for DPs. See the GetConfidentialPlatforms() function in GenericPlatformMisc for more information. + +#### Programming + +* The TargetRules.ShouldUseSharedBuildEnvironment() function has been deprecated. Targets can now specify the build environment they wish to use by setting BuildEnvironment to TargetBuildEnvironment.Default/Shared/Unique in their constructor instead. + +* The constructor for ModuleRules-derived classes in .build.cs files should be updated to take a ReadOnlyTargetRules instance, which should be forwarded to the base class. This class contains the same properties as the previous TargetInfo argument, plus all the target-specific settings previously stored in the global BuildConfiguration and UEBuildConfiguration classes. Compatibility shims for accessing these objects will be removed in a future release. The WITH_FORWARDED_MODULE_RULES_CTOR preprocessor definition is now defined, which allows writing code which is compatible with multiple engine versions. + +* The TargetRules.SetupBinaries() callback has been deprecated. Instead of overriding this, targets may override the launch module through the "LaunchModuleName" property in their constructor, and add extra modules to the "ExtraModuleNames" field on the TargetRules object itself. + +#### Rendering + +* UE4Editor is whitelisted for Aftermath with latest Nvidia drivers. To whitelist other game executables contact Nvidia. + +* RHICmdList.Clear() methods are now removed; please use RHICmdList.SetRenderTargetsAndClear() or the DrawClearQuad() utility function from ClearQuad.h. + +* The Cross Compiler Tool is now removed from the Engine, it had too many limitations. Use hlslcc.sln or ShaderCompileWorker -directcompile instead. + +* PipelineStateCache.h contains the new replacement interface for BoundShaderStateCache.h. Otherwise, during the Geometry rendering passes the previously introduced Draw Render State is used to collect and set the Blend, Raster, and Depth Stencil State. Commit Graphics Pipeline State will set the PSO for geometry rendering passes. Postprocessing passes or passes which use Globalshaders have to fill out a Graphics Pipeline State Initializer and set this instead. + +* If configuring via .ini files, use the new variable name "ScaleTexturesByGlobalMipBias" where "ScaleTexturesByGlobalMyBias" was used. + +* Mobile: Skylights on mobile projects may need to be recaptured in the editor before packaging. + +* Mobile: Please replace r.TonemapperFilm=1 cvar with r.Mobile.TonemapperFilm=1 in case you want to use new filmic tonemapper on Mobile platforms. + +#### VR + +* PSVR MotionController tracking management system. + + * Blueprint functions added to manage the set of actively motion tracked controllers in MotionTrackedDevice Function Library. + + * You are recommended to disable tracking of all controllers first, and then enable tracking for the controllers you want to have tracked based on user setting, connected controllers, etc. The system keeps a memory of which controllers are set to be tracked even if the controller is disconnected, or not yet connected. + +* Experimental preview of PSVR Social Screen support. + + * The new Morpheus plugin project setting Enable Social Screen Separate Mode must be set to true to use this feature. When that is true additional render and output buffers will be allocated for the Social Screen. + + * Blueprint functions for controlling the feature can be found by searching for 'SocialScreen'. + + * Future work will replace this API with a more flexible cross platform one, and pursue optimizations of SocialScreen output. + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_16/4_16ReleaseNotes.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_16/4_16ReleaseNotes.JPN.udn new file mode 100644 index 000000000000..8e1cb1eacff9 --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_16/4_16ReleaseNotes.JPN.udn @@ -0,0 +1,3906 @@ +INTSourceChangelist:3457153 +Availability:Public +Title:アンリアル エンジン 4.16 リリース ノート +Description:Unreal Engine 4.16 リリース ノート +Crumbs:%ROOT%, Engine +Parent:Support/Builds +order:16 +reference-image: image_18.gif +reference-image: image_28.gif +reference-image: image_31.gif +reference-image: image_35.gif + +![](DOCS_BANNER_416.jpg) + +## 新機能 + +アンリアル エンジン 4.16 には、**素晴らしいレンダリングとアニメーションの新機能**、**モバイルおよびコンソール プラットフォームの大幅なパフォーマンス改善、幅広いプラットフォーム上でスムーズに実行する美麗な背景や没入感のある体験を一段と容易に作り出すことができる豊富な拡張機能** も加わりました。 + +魅力的な **Volumetric Fog** 新機能を使って背景の雰囲気を変えてみませんか? この機能を使うと、大規模なシーンであっても、どこでもそれに合わせたライティングと共に、自動的にリアルなフォグやスモーク エフェクトをレンダリングすることができます。 + +動的な **軽量剛体ボディ** と **ローレベルのクロス シミュレーション** ツールを使ってキャラクターに命を吹き込みましょう!Animation Modifier、スプライン IK ソルバー、更新された Pose Driver などアニメーション システムの多くの改善点を活用すると、動きのフローの制御を高めることができます。 + +ガーベジ コレクションが **2 倍程度速くなりました**!UI レンダリングのパフォーマンスと UMG ウィジェットの作成速度が大幅に向上し、一段と見栄えの良いインターフェースを作成できるようになりました。**VR Mode**、 アニメーション、シーケンサー、他のツールも更新されており、開発プロセスをさらに合理化します。 + +アンリアル エンジン 4.16 では、**Nintendo Switch** のすべての機能を含むサポートが開始し、開発にご利用いただくことができます。エピック ゲームズと任天堂の協力により、開発者登録をした方には、対応するアンリアル エンジン 4 のソース コードを無償でご提供します!開始方法については [このページ](http://www.unrealengine.com/en_US/blog/launch-your-game-on-the-nintendo-switch-with-unreal-engine-4-16) をご覧ください。 + +**DirectX 12 が Xbox One のデフォルト レンダラ** になりました。エンジンのプラットフォーム サポートで、パフォーマンス向上と機能拡張を実現します。さらに、WebAssembly と WebGL 2 を使って、HTML5 ゲームを開発できるようになりました。今後も、UE4 ではこの新たな方向性に対して改善を続けていきます。 + +モバイル向けには、Android 用バーチャル キーボードがサポートされるようになりました。ランタイム パーミッションがブループリントとコードの両方で公開されています。さらに、モバイル アプリケーション向けに実行ファイルのサイズを減らす大幅な改善を加えました。 + +今回のリリースには、アンリアル エンジン 4 の何百ものアップデートが含まれており、そのうち **160 の改善点** は GitHub のアンリアル エンジンのデベロッパーのコミュニティから寄せられたものです。アンリアル エンジン 4.16 に貢献をいただいた以下の皆様に謝意を表します (以下、敬称略)。 + +0lento, Akihiro Kayama (kayama-shift), Alice Robinson (Valkrysa), Altrue, Andreas Rønning (Sunjammer), Andrew Gaubatz (e-agaubatz), Angus Jones (crumblycake), Artem V. Navrotskiy (bozaro), Black Phoenix (PhoenixBlack), Cedric Neukirchen (eXifreXi), Cengiz Terzibas (yaakuro), Chris Varnz (chrisvarns), Christopher P. Yarger (cpyarger), Damian Nowakowski (zompi2), DarkSlot, DeanoC, Derek van Vliet (derekvanvliet), devbm, dodgyville, drelidan7, Gabriel Lima (Gabriel-Lima-O), Gyeonghwan (conquests), Hao Wang (haowang1013), Ilya (ill), Jackblue (JohnsonJackblue), James Horsley (mmdanggg2), Jeff Rous (JeffRous), Jon Watte (jwatte), Jørgen P. Tjernø (jorgenpt), jostster, Kalle Hämäläinen (kallehamalainen), katze7514, Kevin Kuegler (FrostByteGER), KrisRedbeard, looterz, Manmohan Bishnoi (manmohanbishnoi), Marat Radchenko (slonopotamus), Markyroson, Martin Treacy-Schwartz (the1schwartz), Matt Edmonds (cleaver404), Matthew Casey (mdcasey), Matthias (haimat), Matthias Hölzl (hoelzl), Matthias Huerbe (MatzeOGH), Michael Schoell (MichaelSchoell), Michał Siejak (Nadrin), Milan Šťastný (aknarts), Moritz Wundke (moritz-wundke), Mustafa TOP (MSTF), Narendra Umate (ardneran), Nathan Stocks (CleanCut), NaturalMotionTechnology, Nick Verenik (nverenik), Paul Murray (awesomeness872), pfontain, Phil Christensen (Rastaban), PrimalJohnScott, projectgheist, Rafael Ortis (rafortis), Rajko Stojadinovic (rajkosto), Rama (EverNewJoy), rhughesgeomerics, Ricardo Rodrigues (RicardoEPRodrigues), Robert Hagglund (hagglund), Robert Segal (robertfsegal), Ryan Pavlik (rpav), sangpan, Sanjay Nambiar (sanjay-nambiar), Satheesh (ryanjon2040), Sean Campbell (scampVR), Sebastian Axinte (ENiGMA9), Sébastien Rombauts (SRombauts), SiebenCorgie, Stefan Zimecki (stefanzimecki), StefanoProsperi, Stephen Johnson (megasjay), TaeYoung Cho (valval88), Timothee Besset (TTimo), Timothy Hagberg (thagberg), Tom Kneiphof (tomix1024), Tom Ward (tomwardio), TRS-justing, unwitherer, Vladimir (VladimirPobedinskiy), Vladimir Alyamkin (ufna), wyhily2010, Yaroslav Shmelev (SoulSharer), yeonseok-yi + +## 主要機能 + +### 新規:Volumetric Fog + +Volumetric Fog を使って背景の雰囲気づくりをしましょう。密度の変化をサポートすることでライトシャフトを漂う埃やスモークをシミュレートできます。ライトをいくつでも使用して Volumetric Fog に影響を与えることができます。 + +![image alt text](image_0.png)(w:929 h:529 convert:false) + +![image alt text](image_1.png)(w:928 h:510 convert:false) + +![image alt text](image_2.png)(w:928 h:510 convert:false) + +Volumetric Fog は以下のライティングをサポートします。 + +* カスケード シャドウ マップからのシャドウイングまたは静的シャドウイング、もしくは Light 関数のある単一の指向性ライト。 + +* Cast Volumetric Shadowing が有効の場合、動的または静的シャドウイングが付いた任意の数のポイントライトおよびスポットライト。 + +* ディスタンス フィールド アンビエント オクルージョンが有効の場合、シャドウイングが付いた単一のスカイライト。 + +* Volumetric Scattering Intensity が 0 より大きい場合はパーティクル ライト。 + +パーティクル システムに適用されているマテリアルを使って新しい Volume Domain 設定を使って Volumetric Fog を制御することができます。ボリューム マテリアルを持つ単一のパーティクルでは、密度を持つ球体が Volumetric Fog に追加されます。エフェクトは完全な 3D で、ビルボードは一切含まれません。テクスチャからのノイズのある複数の球体フォグ パーティクルを使用して、フォグを所定の場所に制限することができます。 + +Volumetric Fog の設定については、この [ドキュメント](Engine/Rendering/LightingAndShadows/VolumetricFog) をご覧ください。 + +### 新規:イメージ ベース (FFT) のブルームの畳み込みエフェクト + +この機能を使って物理的にリアルなブルームのポスト プロセス エフェクトを作りましょう! アンリアル エンジン 4.16 には、FFT ブルーム機能があります。カスタムのブルーム カーネルの形状を使用し、思い描いた結果に合わせて強さを制御することでアーティストの表現の幅が広がります。 + +![image alt text](image_3.png)(w:928 h:485 convert:false) + +カーネル画像と共にソース画像の数学的畳み込みを使うことで、このブルーム技術では星状のバーストから周囲を照らすディフューズまで一連の反応を生み出すことができます。イメージ ベースの折り畳みが生み出す新たなリアリズムは、視覚的に面白い、非対称のカーネル イメージによるものです。通常、放射状の線から成る星状のバーストのように見えますが、まつ毛のようなシルエット、ボケ、その他のアーティファクトを含むことがあります。 + +**Note:** イメージ ベースの畳み込みブルーム機能は、シネマティックスやハイエンド ハードウェアでの使用を想定して作られています。既存の (標準) ブルームは、ほとんどのゲーム アプリケーションでご利用いただけます。 + +### 新規:ディスタンス フィールド ライティングの最適化 + +**ディスタンス フィールド アンビエント オクルージョン** と **レイトレース ディスタンス フィールドシャドウ** は、現行の生成コンソールと標準的仕様の PC で **30-50% 程度速くなっています!** こうした機能によって、一段とリアルな環境光とシーンの動的メッシュに対するエリア シャドウが実現します。 + +![image alt text](image_4.png)(w:929 h:513 convert:false) + +さらにスタティックメッシュの **Distance Field Generation は、Intel の Embree のレイトレーシング ライブラリによって 2.5 倍速くなっています。**Eight Bit Mesh Distance Fields と Compress Mesh Distance Fields のプロジェクト設定を有効にすると、メモリ使用量も大幅に削減します。 + +### 新規:軽量剛体シミュレーション + +**軽量剛体キャラクター シミュレーション 機能を使って物理シミュレーションしたキャラクターを沢山作りましょう!**新しい高性能の **Immediate Mode** PhysX API を使って Animation ブループリント内で物理アセットをシミュレーションできるようになりました。このシミュレーションを使うキャラクターはワールドで静的ジオメトリとのコリジョンを生成することもできます。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + VaxxVsv0Fak + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +### 新規:ローレベル クロス シミュレーション + +ローレベル NVIDIA NvCloth クロス ソルバーを使ってクロス シミュレーションの制御を高めましょう。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 5BqodzWZIUA + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +これまでの APEX Clothing ソルバーを、 NVIDIA の NvCloth と呼ばれるローレベル ソリューションに置き換えました。この新しいソルバーは、以前の APEX ソリューションのコア ソルバーに似ていますが、いくつかの変更があります。シミュレーション データが使いやすくなっていて、慣性の設定用のパラメータが増えています。 + +### 新規:Nintendo Switch 向けゲームを制作しましょう! + +登録開発者は、Nintendo Switch 向けのゲームを制作し、リリースすることができます。制作に使用できる UE4 の Nintendo Switch サポートは認証に合致したものであり、ネットワーク接続のマルチプレイヤーに対応し、ディファード、モバイル フォワード、クラスター フォワードといった複数のレンダリング パイプラインを利用することができます。Nintendo Switch 向けに様々なタイプのゲームを出荷することができます。 + +[REGION:raw] +![image alt text](image_7.png)(w:925 h:641 convert:false) +[/REGION] + +### 新規:VR モード UI とインタラクションの更新 + +アンリアル エディタの VR モードは、一段と直観的なワークフローと編集ができるように改善されました。 + +![image alt text](image_8.jpg)(w:722 h:646 convert:false) + +新しい非対称コントローラーのセットアップでは、改善されたラジアル メニューとレベル内のオブジェクトを迅速かつ容易に扱えるように精度を高めたインタラクション レーザーがあります。 + +主なエディタ機能や UI パネルを含むすべての VR モード アクションは、更新されたラジアル メニューからご利用いただけます。テレポート機能も改善されて、必要な場所にただちに移動し、プレイヤー視点で見えるようにデフォルト スケールにリサイズすることもできます。詳細は、[https://docs.unrealengine.com/latest/INT/Engine/Editor/VR/GDC2017/](https://docs.unrealengine.com/latest/INT/Engine/Editor/VR/GDC2017/) を参照してください。 + +### 新規:VR でシーケンスを編集 + +シーケンサー シネマティックス エディタが VR で利用できるようになりました!新規シーケンスを作り、レベル内でオブジェクトを移動することができます。しかも、このプロセス中にトランスフォームに対するシーケンス キーを自動的に作成することができます。時間をスクラブしてこうしたキーを設定することでシネマティック シーケンスの作成と再生をすべて VR 内で行うことができます。シーケンサーの UI またはラジアル メニューから既存のレベル シーケンスを開いて再生することもできます。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + X4Zw9U20Gw4 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +* New!調整可能なキーを使うと、ワールド内の軌道を物理的に調整することができます! + +* ラジアル メニューの Scrub Time オプションを使うとサムスティックまたはタッチパッドの入力を、シーケンスを前後に再生する速度として使います。再度トリガーを押して Scrub Time モードを終了します。 + +### 新規:VR モードでの物理シミュレーション + +モーション コントローラーを使ってオブジェクトとインタラクションして **VR モードで物理アクタをシミュレーション** できるようになりました。物理をシミュレーションするように設定したアクタを配置し、物理シミュレーションを実行し、リアルなスキャッタリングやモーション コントローラーを使ってアクタを動かすことができます。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + bG2Qf897CBI + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +### 新規:VR モードでのスマート スナッピング + +スマート スナッピングでは、オブジェクトの境界を使ってシーン内の他のアクタと並べて配置します。これにより、グリッドを考えてモジュラー アセットをビルドする必要なく正確に位置合わせすることができます。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + lvqxM1kjubE + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +この機能は、現在 VR モードでのみ利用することができます。今後のリリースでデスクトップの編集のサポートも追加予定です。 + +### 新規:Xbox One で DirectX 12 がレンダラに + +**DirectX 12 は Xbox One のデフォルト レンダラになりました!** DirectX 12 で安定性を高め、パフォーマンスを向上させるために多数の更新を加えました。これをデフォルトの RHI とし、Xbox One 向けに制作されたタイトルで **CPU と GPU の性能を向上** させます。 + +![image alt text](image_12.png)(w:556 h:356 convert:false) + +#### D3D11 へのスイッチバック + +D3D11 にスイッチバックする必要があるタイトルの場合、以下の手順に従います。 + +1. ご自身のタイトルの defaultengine.ini の bBuildForD3D12 を修正します。 + +1. Xbox One 向けのゲームを再ビルドします。 + +1. コンテンツを再クックします。 + +**Note:** D3D11 RHI は、今後のリリースで非推奨になります。 + +### 新規:HTML5 の WebAssembly と WebGL 2 をサポート + +UE4 は HTML5 の新しい WebAssembly 標準 (WASM) をサポートするようになりました。これは、ウェブ向けに C++ をコンパイルし、実行する非常に迅速で効率性の高い方法です。Mozilla の最新の Emscripten ツールチェーン (v1.37.9) を使っています。これは新しい技術であり、すべてのブラウザでサポートされているわけではありません。そのため、早期アクセス機能とみなされ、GitHub のアクセスを必要とします。 + +[REGION:raw] +![image alt text](image_13.png)(w:929 h:630 convert:false) +[/REGION] + +WASM は、アプリケーションのダウンロード サイズ、起動時間、メモリ消費を改善し、パフォーマンスを大幅に高める Web アプリケーション向けのバイナリ形式の JavaScript です。WASM とブラウザのサポートに関する詳細は、[http://webassembly.org/](http://webassembly.org/) をご覧ください。 + +UE 4.16 は WebGL 2.0 もサポートしています。これは、OpenGL ES 3.0 をベースにしたもので、レンダリングのパフォーマンスを最適にし、ビジュアル忠実度を高め、以下を含むレンダリング機能をサポートします。 + +* UE4 のハイエンドのモバイル機能レベルのほとんどの機能 + +* パーティクルとフォリッジのためのインスタンス化されたジオメトリの描画 + +* Multiple Render Targets (MRTs) のサポート + +* 3D またはボリューム テクスチャ、2D テクスチャ配列などのテクスチャ機能と、2 のべき乗以外のテクスチャの制約がなくなります。 + +WASM と WebGL 2.0 は、Firefox 52 と Chrome 57 以降 (64-bit 推奨) でサポートされています。Windows 上で Chrome 58 のバグがあるようです。一部のケースでメモリ不足になるエラーを生じています。この問題の解決に向けて Google と作業を進めています。最新ステータスについては [UE-44727](https://issues.unrealengine.com/issue/UE-44727) を参照してください。 + +HTML5 Project Settings の Emscripten セクションで WASM と WebGL 2.0 を有効にすることができます。出来る限り多くのブラウザをサポートする必要があれば、ASM.js と WebGL 1 を引き続きご利用ください。ASM.js と WebGL 1 のサポートは今後のエンジンのリリースで非推奨になり、その後取り除きます (正確な時期は今後加わるブラウザのサポートに応じて変わります)。 + +Firefox や Chrome のブラウザ (対応バージョンは上記のとおり) での効果については、LIVE DEMO:[try out Zen Garden on HTML5](https://hacks.mozilla.org/2017/03/firefox-52-introducing-web-assembly-css-grid-and-the-grid-inspector/) をご覧ください。 + +### 新規:ガーベジ コレクションが 2 倍程度高速化 + +ガーベジ コレクションのパフォーマンスが大幅に改善し、**2 倍程度速くなりました!** 以下は具体的な改善点です。 + +* タスク管理のオーバーヘッドを減らすために到達可能性解析のマルチスレッディングが再設計されました。 + +* ガーベジ コレクションのクラスタリングは、ブループリントが生成したクラスと選択したアクタのタイプをサポートするようになりました。 + +* アクタを破壊するために使う時間を短縮するために、UObject のアンハッシュコードが最適化されました。 + +### 新規:シミュレートされた親を持つキネマティックボディ機能 + +シミュレートされた親を持つキネマティック物理ボディの機能を加えました。キャラクターの手など、純粋にアニメーション データで操作される子のボーンを持つことができます。こうしたボーンの親も物理シミュレーション データによって操作することができます。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + qiiOU_fhex0 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +これにより、ボディと衝突する落石に反応してレッジ (棚状の障害物) をプレイヤーがよじ登るなど格好いいエフェクトを表現できます。 + +### 新規:Platform SDK のアップグレード + +リリースの都度、プラットフォーム パートナーからの最新の SDK リリースに対応するようにエンジンをアップデートしています。 + +[REGION:raw] +![image alt text](image_15.jpg)(w:929 h:522 convert:false) +[/REGION] + +* **Visual Studio:**重要:このリリースでは、Windows の Visual Studio 2013 はサポートしなくなりました。Visual Studio 2015 または Visual Studio 2017 にアップグレードしてください。 + +* **Nintendo Switch:** Nintendo SDK 1.3.1 をサポート + +* **Xbox One:** October 2016 QFE3 XDK に対してビルド + +* **PlayStation 4:** PSR SDK 4.508.001 SDK にアップグレード + +* **Android:** CodeWorks for Android 1R6u1 にアップデート + +* **GoogleVR:** プラグインをバージョン 1.3 にアップデート + +* **GoogleVR:** SDK を 1.40.0 にアップデート + +* **GoogleVR:** モードのデフォルトが Daydream & Cardboard に変更 + +* **Vulkan:** distributable と glslang を SDK 1.0.39.1 にアップデート + +### 新規:シーケンサーのショット トラックの改善 + +シネマティックスと映像制作についてシーケンサーのショットトラックにいくつかの改善が加えられました。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + GqfJxD1DY8I + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +* **ショット毎の階層バイアス:** デフォルトでレベル シーケンスの階層で低レベルのトラックが優先されます。これにより、映像制作者は、ショットでの調整がそれが含まれるシーケンスのトラックをオーバーライドする使い慣れたパイプラインを構築することができます。 + +* **全てのトラックに対して "When Finished" プロパティをエクスポーズ:** これで事前にアニメートされた状態に値を戻すか、シーケンス終了時にそのままにするかを指定することができます。映像制作環境では、通常、ショットのアニメートした値をアニメート前の状態に戻し、次のショットに影響を与えないようにします。シネマティックスでは、シーケンサーのアニメートした状態からゲームに続くように値を持続させる場合があります。 + +* **Pre/post roll:** プリロールとポストロールはあらゆるトラックで一般的な概念になりました。一部のトラックでは、例えばカメラ カット トラックなどではストリーミング システムにカメラカットの予定位置をプリロールの評価期間中に通知します。 + +### 新規:シーケンサーでマテリアル パラメータ コレクションをアニメートする + +シーケンサーでマテリアル パラメータ コレクションをアニメートできるようになりました。任意の数のマテリアルで参照可能なスカラー パラメータやベクターパラメータを制御することができます。アニメーションを共有するために各マテリアル インスタンスで個々のパラメータ値をアニメートする必要がなくなりました。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + u_Cpqz7mFuM + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +### 新規:UI レンダリング パフォーマンスの向上 + +Invalidation Panel を使うゲームでは、レンダリング データではなくウィジェット エレメントのみをキャッシュするオプションができました。これにより、テクスチャのバッチングを改善し、ドローコールを大幅に削減します。結果としてモバイル デバイスでパフォーマンスが飛躍的に向上します。 + +[REGION:asyncgif] +![image alt text](image_18.gif)(w:456) +[/REGION] + + +Battle Breakers のヒーロー選択 UI (上図) では各ヒーローの論理要素がキャッシングされますが、まとめてバッチングすることもできます。コンソール変数 Slate.CacheRenderData=0 はこのモードを有効にします。これは、現在モバイル デバイスでデフォルトになっています。 + +### 新規:アニメーションの Pose Driver の改善 + +Pose Driver 機能に多くの改善を施しました。これにより、ボーン一式と参照ターゲット一式を比較することでプロシージャルにブレンド シェイプやボーンを操作します。これは、上腕と肩のポーズに応じてモーフターゲットを補正する肩などのエリアで特に役立ちます。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + sjtbvyDdW9w + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +* 複数のボーンをポーズを読み取る入力として選択できるようになりました。 + +* ノードによってどのボーンを選択するかを選ぶことができます。 + +* 各ターゲットをどのようにアクティベートするかについてのカスタム カーブを指定することができます。 + +* Pose Asset を必要とせずに、カーブ (モーフ、マテリアル) の操作を直接選択することができます。 + +* ターゲット ポーズの作成/編集ができるように、ターゲットのアクティベーションを示すバーなど UI を改善しました。 + +* ビューポートのターゲットの位置をクリックして選択できるようになりました。 + +### 新規:マテリアルを平坦化するためのオパシティとオパシティ マスク + +Actor Merge ツール、Hierarchical LOD システムを使う場合の **オパシティ (マスク) 値のベイクアウト** のサポートを追加しました。結果として得られる (インスタンス化) マテリアルでは設定したブレンド モードを使って正しいレンダリング パスに従うようにします。以下は、ベイクアウトしたマスクしたマテリアルの例です。 + +![image alt text](image_20.png)(w:904 h:740 convert:false) + +### 新規:Mesh Paint Tool の改善 + +メッシュのペイント システムを見直してユーザビリティとわかりやすさを改善しました。エディタの他の部分での機能を再利用することができます。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + UezYKhase9g + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +さらに、このペイント ツールはスケルタルメッシュでも利用可能になりました!ペイントはインスタンス毎ではなく (スタティックメッシュと同様に)、スケルタルメッシュ アセットに直接適用されることに注意してください。 + +### 新規:スプライン IK ソルバー + +キャラクターの背骨やボーン チェーンを制御するために便利なスプライン IK ノードが Animation ブループリントに追加されました。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + chqOk4QdPR0 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + + +### 新規:メッシュ サーフェス上のマテリアルの検出 + +コンポーネントに 'Get Material From Face Index' 関数を追加し、 (complex) Line Trace 実行後にコンポーネントに適用されるマテリアル情報を検出することができます。この機能は、スタティックメッシュ、プロシージャルなメッシュ コンポーネント、 BSP でサポートされます。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + SvsSnkwB1TQ + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +### 新規:'Look At' Animation ノードの改善 + +Look At ノードの **Look At Location** プロパティをボーンやソケットに相対的に使用することができます。これまで、ボーンやソケットを指定した場合にこの値は無視されていました。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 3C7Q6JJxmtY + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +Look At 制御のビジュアル化も改善されました。例えば、クランプ アングル、ターゲット位置、補間などが視覚的にわかります。 + +### 新規:アニメーションのエクスポートの改善 + +物理シミュレーションの Anim Dynamics など、スケルタルメッシュに割り当てられたポストプロセスのグラフから生成された追加のアニメーション データを含むアニメーションの作成とエクスポートのサポートを追加しました。 + +この追加データを含めるには、**[Create Animation]** メニューまたは **[Export Animation]** メニューから **Preview Mesh** を選択します。 + +![image alt text](image_25.png)(w:697 h:256 convert:false) + +### 新規:Unreal Audio Engine (早期アクセス プレビュー) + +GDC で発表された新しい Unreal Audio Engine が PC、 Mac、 iOS、 Android、 および Switch で早期アクセス版として利用可能になりました。これにはクロス プラットフォームのオーディオ ミキサーが含まれます。既存のオーディオ エンジン機能に対して完全な後方互換性があります。新しいマルチ プラットフォームの EQ エフェクトと Reverb マスター エフェクトが含まれます。さらに、サブミックス グラフ、サブミックス エフェクト、ソース エフェクト、リアルタイム合成など新機能が盛り沢山で、オーディオ プラグインのサポートも改善されています。 + +この新しい Unreal Audio Engine は 4.16 ではデフォルトで有効になっていません。コンソール プラットフォーム、Linux、および HTML5 のバックエンドの実装、および特にモバイル プラットフォーム向けに安定性とパフォーマンスの改善、など引き続き作業を進めているからです。 + +オーディオ ミキサーを有効にするには、コマンドライン引数、"-audiomixer" を使用します。 + +注意:ほとんどの Unreal Audio Engine の新規機能は、オーディオ ミキサーを有効にせずにエディタをローンチすると非表示になっています。 + +#### 新規:Synthesis プラグイン (早期アクセス版) + +新しい Synthesis プラグインには、Unreal Audio Engine の "SynthComponent" クラスを使って記述した新しい 2 つのリアルタイム シンセサイザーがあり、十分な機能を備えた減算シンセサイザーとリアルタイム グラニュレータを実装します。こうした新しいシンセサイザーはプロシージャルな音楽やサウンド デザインに役立つだけでなく、サードパーティのプラグイン メーカーや、場合によってはサウンド デザイナーが独自の合成をどのように実装するかの例になります。 + +この合成プラグインには、Unreal Audio Engine で使用する新しい DSP ソースのホストとサブミックス エフェクトがあります。 + +* **ソース エフェクト:** ステレオ ディレイ、ビット クラッシャー、ダイナミック プロセッサー、エンベロープ フォロワー、EQ フィルタ、バーチャル アナログ フィルタ (Ladder/State Variable)、Wave Shaper、コーラス、フェイザー + +* **サブミックス エフェクト:** リバーブ、EQ、ダイナミック プロセッサ + +### 新規:Steam Audio (早期アクセス版) + +エピック ゲームズと Valve が協力して、Unreal Audio Engineの新機能を使用し、Steam Audio SDK を完全に統合した実装をリリースしました。 + +![image alt text](image_26.png)(w:600 h:160 convert:false) + + Steam Audio は、基本的に新しい Unreal Audio Engine の空間化、オクルージョン、リバーブのシステムと統合し、UE4 で VR 向けの次世代の物理ベースのオーディオ体験を実現します。これは Steam Audio の早期アクセス版であり、4.17 では大幅な更新、さらに多くのサンプル プロジェクト、ワークフローの改善が予定されています。エピック ゲームズと Valve では、フィードバック、ご質問、改善案をお待ちしております。 + +Steam Audio に関する情報、ドキュメント、サポートのヘルプについては、[https://valvesoftware.github.io/steam-audio/](https://valvesoftware.github.io/steam-audio/) をご覧ください。 + +### 新規:カラー グレーディング ツールの改善 + +カラー グレーディングのユーザーインターフェース (UI) が、簡単に使用できるように改善されました。 + +![image alt text](image_27.jpg)(w:529 h:257 convert:false) + +* HSV モードが追加されました。 + +* Ctrl キーを押しながらスライダーをドラッグしてタイプに応じてスライダーの最小値、最大値を動的に変更することができます。 + +* カラー グレーディングのカテゴリ全体 (すなわち、グローバル、シャドウ、中間調、ハイライト) をリセットする新しいリセット ボタンが加わりました。 + +### 新規:アニメーションのブレンドスペース エディタの改善 + +グリッド内で **[Show Animation Names (アニメーション名表示)]** ボタンを使って各サンプルのアニメーション名を表示させることができます。既存サンプルの上にアニメーションをドラッグ&ドロップして置き換えることができます。 + +[REGION:asyncgif] +![image alt text](image_28.gif)(w:905) +[/REGION] + +### 新規:ローカライズのための文字列テーブル + +UE4 は文字列テーブルをサポートするようになりました! + +![image alt text](image_29.png)(w:601 h:218 convert:false) + +文字列テーブルはローカライズしたテキストをひとつ (または複数) の決まった場所にまとめます。次に他のアセットまたはコードから文字列テーブル内のエントリを参照し、ローカライズしたテキストを簡単に再利用できるようにします。文字列テーブルは C++ で定義し、CSV ファイルで読み込むか、アセットとして作成します。 + +### 新規:Animation Modifier (早期アクセス プレビュー) + +Animation Modifier は、アクションのシーケンスを任意のアニメーション シーケンスまたはスケルトンに適用します。例えば、地面に右足が着くのはどのフレームであるかをピンポイントで示し、Animation Sync Marker を ball_r ボーンが最低ポイント (フロアに接触する) になるフレームに追加します。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + YC_UJuO9AI8 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +特定のアニメーション データにアクセスするための新しい関数一式は、Animation ブループリントの関数ライブラリに入っています。Animation Modifier にアクセスして適用するには、スケルトン エディタとアニメーション エディタにある新しいタブを使います。Animation Modifier はスケルトンまたはアニメーションのシーケンスに追加することができます。アニメーション シーケンスに対して、Animation Modifier はシーケンス自体にのみ適用されます。スケルトンに適用する場合、そのスケルトンに基づいたすべてのアニメーション シーケンスに適用されます。 + +### 新規:Android 用バーチャル キーボード + +ポップアップ ダイアログ入力ボックスの代わりに、Android ではその OS でバーチャル キーボードをサポートするようになりました。 + +[REGION:asyncgif] +![image alt text](image_31.gif)(w:256) +[/REGION] + + +バーチャル キーボードを使用するには、**Project Settings > Platforms > Android > APK Packaging** の順に進み、チェックボックスにチェックを入れます。このオプションは、バーチャル キーボードの基本サポートを有効にするものです。入力エレメントを可視にし、バーチャル キーボードの背後で見えづらくならないように調整するのは各自のアプリケーション側で、OnVirtualKeyboardShown と OnVirtualKeyboardHidden のイベント ハンドラを使って行ってください。 + +**Note:** ユーザーが IME を必要とする言語を使っている場合、バーチャル キーボードを Android.NewKeyboard コンソール変数を使って無効にすることができます。 + +### Android のランタイム パーミッションのサポート + +UE4 は Android 23 以降で必要なランタイム パーミッションをサポートするようになりました。これは、Google によって危険と分類されるパーミッションを必要とする機能を利用するためのものです。こうしたものには、連絡先、写真、電話の状態、外部記憶装置、カメラ、位置情報サービスなどがあります。詳細は、以下のウェブページをご覧ください。[https://developer.android.com/guide/topics/permissions/requesting.html](https://developer.android.com/guide/topics/permissions/requesting.html) + +Android 23 をターゲットにする場合、Android Runtimes Permission プラグインには、ネイティブ コードまたは **Check Android Permission** ブループリント ノードを使って既にパーミッションが与えられているかをランタイムにチェックする機能があります。パーミッションがまだ認められていない場合は、そのアプリケーションが **Request Android Permissions** ブループリント ノードを使ってユーザーからパーミッションをリクエストします。次に **On Permissions Granted Dynamic Delegate** に結合されているイベントを使ってその結果を取得します。これにより、ゲームでパーミッションを必要とする機能を求める前に、パーミッションを与えることが可能になり、ユーザー体験を高めることができます。ターゲットとするバージョンが Android 23 よりも前の場合、通常どおり Android Manifest で指定してパーミッションを与えます。 + +![image alt text](image_32.png)(w:718 h:346 convert:false) + +**Note:** 4.16 では、Android SDK 23 以降をインストールする必要があります。この SDK レベルをインストールしていない場合、Engine/Extras/AndroidWorks ディレクトリに CodeWorksforAndroid-1R6u1 インストーラがあります。さらに、"Project Settings (プロジェクト設定)" の Android SDK で Android SDK API レベルを matchndk から œlatest に変更してください。これにより、UE4 は Android SDK platforms ディレクトリにあるインストールされている最新 SDK を確実に使用するようになります。NDK API Level を変更する必要はありません。 android-19 は、APK を Lollipop (Android 5.0) よりも前のバージョンにインストールする適切なものです。これよりも高く設定すると、アプリケーションで Android 5.0 以降が必要になります。 + +### パッケージ サイズを減らすためのシェーダー コード ライブラリ + +**[Share Material Shader Code]** プロジェクト設定を使用して、すべてのシェーダー コード用の共有保存場所を有効にすることができます。その結果、同じシェーダー コードを生成する複数のマテリアルやマテリアル インスタンスに対してひとつのコピーだけが保存されるようになります。 + +iOS、 TVOS 、MacOS の Metal などの一部のプラットフォームでは、プラットフォーム固有のより高効率のシェーダー ライブラリをサポートしています。**[Shared Material Native Libraries]** プロジェクト設定を有効にすることで、ネイティブ ライブラリ形式を利用してパッケージ サイズをさらに減らします。 + +### 新規:FBX からカプセル コリジョンをインポート + +FBX ファイルからカプセルのシンプル コリジョンを、これまでのボックス、球体、凸型のシンプル コリジョンと同じ方法でインポートできるようになりました。カプセルのポリゴン メッシュで 'UCP' プレフィックスを使用すると、インポート時に取り除かれて、対応するカプセルのコリジョン形状に置き換わります。 + +### 新規:共有とローカルのアセット ビューア プロファイルのオプション + +アンリアル エディタでは、共有またはローカルのレベルでアセット ビューア プロファイルを保存できるようになりました。アート アセットを評価するためにシーンをまとめて使用可能なプロファイル一式をチームで共有できるようになります。ローカル レベルでプロファイルを保存することで、ローカルで使用したいが、チームでは不要なカスタム プロファイル一式を持つことができます。共有プロファイルは、*DefaultEditor.ini* に保存され、ユーザーがチェックアウトするか、書き込み可能にする必要があります。 + +### 新規:アニメーション プレビュー シーンの改善 + +アニメーション ツールのプレビュー シーンに対して以下の改善を加えました。 + +* プレビュー シーン設定は、ビュー ポートの非表示メニューから既存の設定タブに移動しました。この設定タブはデフォルトで表示されるようになりました。 + +* プレビュー メッシュからメイン ツールバーに迅速に切り替えるショートカットを追加しました。これはすべてのアニメーション エディタに適用されます。 + +* プレビュー シーンを編集する場合、余分なメッシュをプレビューするためだけに "preview scene collection" アセットを作成する必要がなくなりました。メッシュのセットアップが満足のゆくものだったら、オプションでそれをアセットに保存できるようになりました。 + +### 新規:Anim Viewer にデフォルト カメラ オプションを追加 + +'Default Camera' 位置をスケルタルメッシュに保存できるようになりました。メッシュを開く時に使用します。また、Shift+F を押してジャンプすることもできます。 + +### 新規:Play Montage ブループリント ノード + +**Play Montage** は、Anim Montages をプレイするためのブループリント ロジックで使用できる新しい非同期ノードです。モンタージュがブレンドおよび中断された場合に別のノードをトリガーさせて、いくつかのコールバック イベントへのアクセスを容易にします。 + +![image alt text](image_33.png)(w:376 h:272 convert:false) + +* Montage がプレイを終了し完全にブレンドされると OnCompleted が呼び出されます。 + +* Montage が Blend Out を開始すると自動的あるいは手動で停止するので、OnBlendOut が呼び出されます。 + +* Montage が Blend Out を開始すると、別の Montage のプレイによって中断されるので、OnInterrupted が呼び出されます。 + +* Montage アセットの 'Play Montage Notify' あるいは 'Play Montage Notify Window' Anim Notifies のいずれかを使用すると、OnNotifyBegin と OnNotifyEnd がコールバックされます。同じ Montage からの複数のコールバックを区別するために、これらの AnimNotifies には 'Notify Name' を追加することができます。 + +### 新規:リターゲット ポーズ オプションの追加 + +Retarget Base Pose を設定すると、Pose アセットから使用するポーズをインポートできるようになりました。使用中のポーズを修正および保存するオプション (Use Current Pose) およびボーンのトランスフォームを参照ポーズにリセットするオプション (Reset) は、今まで通り利用できます。 + +**Note:** アニメーション エディタで Pose アセットを作成し、割り当て名を使ってすべてのポーズをその Pose アセットに挿入することができます。 + +### 新規:スタティックメッシュ エディタのコリジョン ビュー オプション + +スタティックメッシュ エディタ ツールのスタティックメッシュに対して、シンプルおよび複雑なコリジョンを表示する別々のオプションができました。 + +### 新規:LOD にベイクされたポーズをサポート + +アンリアル エンジン 4 は Bake Pose という新しい縮小設定を使って、LOD レベルにベイクしたポーズをサポートするようになりました。この設定は、結果の LOD メッシュに適用される単一フレーム アニメーション シーケンスに対して設定することができます。ボーンを削除してもポーズを維持したい場合、この設定の便利さが分かります。 + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 0fcNitNu9FE + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +**Note:** この機能の使用には Simplygon が必要です。 + +### 新規:シーケンサー ユーザーインターフェース (UI) の改善点 + +オーディオ トラックのサムネイルが内側の (滑らかな) RMS カーブを使ってピーク サンプルをレンダリングするようになりました。オーディオ トラックも垂直方向へサイズ変更できるようになりました! + +[REGION:asyncgif] +![image alt text](image_35.gif)(w:929) +[/REGION] + + +その他のシーケンサー UI の改善点 + +* シーケンサーが制御するアクタがレベルへストリームされる時、正しくティックするようになりました。 + +* イベント トラックに対して追加でイベント レシーバー (アクタ ブループリントなど) の指定ができるようになりました。 + +* バインディングが改善されました。ブループリントのレベル シーケンスに対してバインディングのドラッグ / ドロップ / 設定ができるようになりました。例えば、ブループリントでオブジェクトをスポーンし、それを既存トラックに割り当てることができます。 + +### 新規:Mobile VR Rendering の改善 + +直接マルチビューが Samsung Gear VR に対してサポートされるようになりました。モバイル マルチビューを使用する時は余計なレンダー ターゲットとフルスクリーン コピーを削除することにより、パフォーマンス全般を改善し、メモリ使用量を削減しました。 + +マルチビューを有効にした Gear VR で Monoscopic Far Field Rendering が使用可能になりました。これにより、シーンのステレオ レンダリング部分のレンダリングが最適に行われるようになります。 + +今後のリリースで、Google Daydream が標準のモバイル マルチビューをサポートするようになります。 + +### 新規:PlayStation VR 用ソーシャル スクリーン (早期アクセス プレビュー) + +PSVR ソーシャル スクリーン プレビューは、モニタと HMD が別のものを表示する ソーシャル スクリーン セパレート モードをサポートしています。 + +30fps ソーシャル スクリーン出力をサポートし、複数の出力モードを切り替えます。次のサンプル モードが実装されています。 + +* SystemMirror (デフォルトのミラー モードで常にあります)。 + +* SeparateTest (ソーシャル スクリーンの黒白を単純に切り替えます)。 + +* SeparateTexture (シーン キャプチャ コンポーネントで書き出されたレンダー ターゲットなどのブループリント専用テクスチャです)。 + +* SeparateMirror (フルあるいはバッファを表示) + +これらの機能に対するマルチ プラットフォーム インターフェース、できれば 60 fps モード (所定のシステム機能とのコンフリクトを解決するためのシステム ダイアログが必要) へのサポートといった最適化を今後行います。 + +この機能を使用するためには、新しい PSVR プロジェクト設定 bEnableSocialScreenSeparateMode を true にしなければなりません。true にすると、追加のスクリーン バッファがソーシャル スクリーンに割り当てられます。この機能を制御するブループリント関数は 'SocialScreen' で検索可能です。 + +### 新規:Android 実行ファイルサイズの縮小 + +コンパイラおよびリンカ設定に多数の最適化を行うことで、Android バイナリ実行ファイル サイズを縮小しました。**[Build with hidden symbol visibility (シンボルを非表示でビルド)]** オプションにより、Android 実行ファイル生成時にリンカが、さらに多くの未使用コードをアンリアル エンジンから取り除くことができます。また、シンボル テーブルから関数シンボルもストリップするので、実行ファイル サイズはさらに小さくなります。最終 APK サイズから約 7MB の節減です。 + +**Note:** このオプションはデバイス上のバイナリからシンボルを削除するので、ネイティブ クラッシュ コール スタックはシンボルなしで logcat 出力に表示されます。デバッグ処理の簡素化のため、ビルド システムはストリップされないデバッグ シンボル付のバイナリも出力ディレクトリにコピーします。また、コール スタックにシンボルを追加するバッチ ファイルも生成します。 + +### 新規:Vertex Interpolator Material Expression ノード + +Vertex Interpolator ノードがマテリアル グラフに追加され、頂点とピクセル間での値補間の調整がしやすくなりました。ワークフローの改善が目的なので、interpolator に対する制約やシェーダーへの変更は一切ありません。 + +頂点シェーダーへ作業をオフロード処理するための現在のワークフローは Customized UV 出力で使用されます。このフローは、データのパッケージ処理が手作業なので少々面倒です。以下の例は、予めスキンメッシュ化したデータをパックし、エフェクトで使用するためにアンパックするマテリアルです。 + +![image alt text](image_36.png)(w:766 h:665 convert:false) + +この新しい補間ノードはパック処理を自動で行うので、グラフの簡素化およびインライン化が可能になります。 + +![image alt text](image_37.png)(w:776 h:357 convert:false) + +Customized UV で既にパックされた作業は VS (頂点シェーダー) ピンに接続され PS (ピクセル シェーダー) ピンから抽出されます。 + +マテリアル統計情報出力を更新して、現在パックされているものと最大値の両方の interpolator の使用状況を表示します。上の例で、命令数と interpolator の使用状況が一定であることに注目してください。2 つのベクトルで合計 8 個のスカラーをパックする場合、スカラーの 2 つは TexCoord[0] ノード、残りの 6 つはプリスキン データで確保します。 + +本機能は Customized UV と互換性があり、結果も一緒にパックします。 + +### 新規:アセット管理フレームワーク (早期アクセス プレビュー) + +Asset Manager は新規のグローバル オブジェクトです。エディタ内またはランタイム時に、マップおよびゲーム固有のアセットタイプの発見、ロード、監査を行うことができます。クエスト、武器、ヒーローなどの作成、およびオンデマンドでのそれらのロードを簡単にするフレームワークを提供します。Asset Manager はまだ開発中なので、ブループリント専用ゲームまたは経験の浅いデベロッパーによるこれらの機能の使用は 4.17 までお待ちください。[Project Settings (プロジェクト設定)] の [Asset Manager] タブでゲームのルールを設定することができます。 + +Asset Manager がスキャンした Primary Asset Types は、ロード前のランタイム時にクエリして、オンデマンドで同期しながらロードすることができます。さらに Asset Manager 設定を使って、ゲームのパッケージングやリリース時のクックおよびチャンクのルールの設定もできます。本機能の開発状況に関しては、AnswerHub: [https://answers.unrealengine.com/questions/595580/what-is-the-asset-manager.html](https://answers.unrealengine.com/questions/595580/what-is-the-asset-manager.html) でご確認ください。 + +### 新規:Asset Audit ウィンドウ (早期アクセス プレビュー) + +アセット管理フレームワーク内にビルドされているので、Asset Audit ウィンドウは一度の多数アセットに対して、ディスク サイズ、メモリ使用状況、アセット プロパティ全般の監査を行うことができます。コンテンツ ブラウザの特別版になります。**[Window] > [Developer Tools]** メニュー、もしくはコンテンツ ブラウザまたはリファレンス ビューアの右クリック メニューからアクセスできます。ウィンドウを開いたら、アセットはボタンを使って追加することができます。クック済みアセット レジストリからロードされたプラットフォーム データは、プラットフォーム ドロップダウンを使ってロードすることができます。こちらは、PS4 のシューティングゲームで使われているテクスチャの監査の例です。 + +![image alt text](image_38.png)(w:929 h:289 convert:false) + +### VR: VR 向けコンソールコマンドの統合 + +デベロッパーがプラットフォームごとに独立して作業しなくて済むような共有レイヤーを作成するために、VR プラットフォーム全体のコンソール コマンドの整合および統合を行いました。 + +この統合は、以下のような長所があります。 + +* 新規プラットフォームのブートが簡単になります。 + +* HMD 全体の引数の意味の整合性が保たれます。 + +* 現在の HMD の無駄な実装が減ります。 + +* VR に関係するすべてのコンソール コマンドは共通のプレフィックス "vr." が付きます。メーカー固有の拡張子はコマンド名の中にそのように明記されます。 + +* 更新されたコンソール コマンドは、タブの完成とインライン使用ヘルプ テキストをサポートします。 + +統合過渡期間は古いコンソール コマンドも引き続き認識されますが、使用時に非推奨の警告が出ます。 + +### ハードウェアのカーソルのカスタム化 + +プラットフォーム ネイティブ カスタム ハードウェア カーソルが Windows、Mac、Linux でサポートされるようになりました。プロジェクトの UserInterface 設定でこのハードウェア カーソルの使用を設定することができます。 + +カーソルには複数の形式が用意されています。例えば "Slate/FancyPointer" をデフォルト ポインタとして設定できます。ゲームのコンテンツ フォルダの Slate ディレクトリに FancyPointer.png + .cur + tiff があれば特定のプラットフォームのマルチ解像度に対応することができます。tiff は Mac にロードされ、cur/ani ファイルは Windows で使用されます。プラットフォーム専用形式が見つからない場合は png を検索します。 + +### ウィジェット作成の高速化 + +UMG ウィジェット作成速度が最高 3 倍になりました! クック時にウィジェット コンパイラが、生成された Blueprint クラスとして同じパッケージに格納されウィジェット作成中に使用されるウィジェット テンプレート / アーキタイプを生成するようになりました。 + +**技術的な詳細** + +技術的な詳細 コンパイル中に、すべてのサブ ユーザー ウィジェットとそのツリーを含む、ほぼ完全に初期化されたウィジェット ツリーが生成され、すべてのメンバ変数を結合し、名前の付いたスロットを初期化し、すべてのアニメーションの設定が行われるようにしました。このように、ほぼ完全に構造化されたウィジェットはアーキタイプとして使用したインスタンス化が可能なので、対応している処理の遅い StaticDuplicateObject パスを使う必要がなくなります。 + +このメソッドには制約があります。ウィジェットのコンパイル ステップのどこかで、インスタンス化処理が正常かどうか、あるいはサブオブジェクト プロパティでのユーザーのインスタンス化設定忘れのためにインスタンス化後に GLEO リファレンスが残っていないかどうかを確認します。ただし、すべての UVisuals (ウィジェットおよびスロット) が DefaultToInstanced になり、インスタンス化フラッグを要求するほとんどのケースに対応してくれるので、そのような事はあまりありません。ネイティブ コードで BindWidget を使う場合は特にそうです。 + +## リリース ノート 「訳注: 以下は、非常に技術的な部分が含まれるため、翻訳を省略します。」 + +### AI + +* New:Added a profiler for Environment Query System (EQS) that can be accessed through the tabs of the EQS Editor. + + * It collects data automatically during game sessions as long as UES_EQS_DEBUGGER define is set.This includes options for average and max execution time of each step (including breakdown of composite generators), number of items processed by each step, and average frequency of running, which can be useful to identify how often fail safes are actually running. + + * It collects tick load data when USE_EQS_TICKLOADDATA define is set.Each query can store up to 16384 records in cyclic buffer (~4.5 minutes at 60 FPS) showing percentage of EQS tick spent on processing it.This is displayed on the graph in EQS editor tab. + + * A console command has been added, "DumpEnvQueryStats", that saves current EQS profiler data to a file (project's Logs folder, .ue4eqs extension), which can be later loaded and inspected in the EQS Editor. + +* Bugfix:Fixed an issue with Blackboard Key Selector's "Init Selector" that resulted in it picking the first value from the Blackboard rather than the appropriately typed one. + +* Bugfix:Gameplay Task Resource's Auto Resource ID initialization is no longer cleared during Hot Reload. + +* The "Get AI Controller" is now a pure Blueprint Function. + +* Exposed Brain Component's "Is Running" and “Is Paused” functions to Blueprint. + +* Clamped AI Sight's peripheral vision angle as well as changed the UI to not allow values outside of the 0-180 range. + +* Disabled collision on Nav Modifier Volumes.Previously they had an 'Overlap All' response and generated overlap events.They are only supposed to be used for preventing navmesh generation, but overlap events could affect gameplay and are also bad for performance. + +* Made "Skip Agent Height Check When Picking Nav Data" option ignore height when picking nav data for agents.It now picks solely based on the radius when this is enabled. + +#### Behavior Tree + +* Bugfix:Added safeguards to prevent crashes resulted from Blackboard keys being names being longer than 1024 characters. + +* Bugfix:Fixed an issue in dynamic Behavior Tree injection that was causing unexpected behavior when the main BT had more BT injection points. + +* Bugfix:Fixed an issue in Blackboard key instantiation that resulted in the instanced key never being used and BB operations always referring to the original BB entry. + +### Debugging Tools + +* The Gameplay Debugger's input detection has been adjusted so that Tap and Hold work correctly in fixed timestep mode. + +### Navigation + +* Added a flag to Recast Navmesh, "Allow Nav Link As Path End", that is used to control whether path corridors can end on a navigation link or not.This may happen with partial paths and not usually desired behavior.Navigation links at the end are not allowed by default. + +* The Blueprint functions "Project Point To Navigation", “Get Random Reachable Point In Radius”, and “Get Random Point In Navigable Radius” all return booleans determining if the projection/generation was successful, as well as the vector value that describes the requested point. + +* Bugfix:Fixed a memory leak in navmesh generators. + +* Bugfix:Fixed an issue that resulted in losing user settings in Static Mesh's navigation export (Nav Collision object) after changing any property of the Static Mesh. + +* Bugfix:Hand-placed AI pawns now get their Path Following Component's "My Nav Data” variable set properly. + +* Bugfix:Fixed an issue with missing update of navigation area after duplicate or undo operations on Nav Link Proxy and Nav Link Component. + +* Bugfix:Corrected the handling of path following requests by Floating Pawn Movement. + +* Bugfix:Fixed an issue with parameters of geometry trace handling drop-down navigation links.All components blocking on ECC_WorldStatic channel will now report a valid hit. + +* BugFix:HLOD's navigation collision exporting no longer causes unnecessary log output about NavCollision instances in cooked builds. + +#### Animation + +* New:You can now rename Virtual Bones. + +* New:You can now change Virtual Bones so that you can have a Virtual Bone that is a child of another Virtual Bone. + +* New:Added "Get Body Target Transform" to the Physical Animation component, which will return the goal transform that a particular body is trying to get to. + +* New:Control rig Sequences can now be exported to Anim Sequences. + +* New:Preview Scene settings have been exposed in the existing settings tab rather than in a hidden menu of the viewport. + +* New:Support for "Curve Source" nodes to find source components on other Actors.It now searches for the property name rather than the component name. + +* New:Added "Set Preview Mesh" to the toolbar for all animation related Editors. + +* New:Updated Alembic Third-party libraries to the latest versions. + +* New:Added functionality to try and match in-engine Material asset names to FaceSet names found inside of an Alembic cache to automatically assign the correct Materials. + +* New:The Alembic Importer now supports Vertex Color data. + +* New:Added functionality to inform about changes to source data when reimporting your animation data from FBX.It now checks for the following: + + * Whether or not the sequence length has changed. + + * Whether or not previously-imported curves exist in the source data. + +* Bugfix:Fixed a crash when trying to implement a function in a child Anim Blueprint. + +* Bugfix:Fixed a crash when debugging a null Animation Sequence. + +* Bugfix:Trying to access a skinned vertex position on a mesh when using Master Pose component no longer crashes. + +* Bugfix:Attempting to bind to Skeletal Mesh with Anim Blueprint already set no longer crashes. + +* Bugfix:Fixed a crash and effector selection issue for two-bone IK. + +* Bugfix:Right-clicking the empty space in the asset shortcut drop-down no longer crashes. + +* Bugfix:Removed an ensure (warning) by reverting to default unit vectors if zero-sized lookat/lookup vectors are specified for a "Look At" node. + +* Bugfix:Removed a crash when clearing an animation of a 1D blendspace sample. + +* Bugfix:Crash fix to import code for Alembic Caches with the HDF5 backend. + +* Bugfix:Fixed an issue when adjusting curves in the Anim Curves tab using a slider when they are not currently selected. + +* Bugfix:Fixed an issue with Update Rate Optimization update rate being too high.Now we use int, so if you have a high update rate it still can go until it wraps around. + +* Bugfix:Child Anim Blueprints can now be retargeted. + +* Bugfix:Fixed flipping transforms when mirrored. + +* Bugfix:Post Process instances are now appropriately updated, even when the main Anim Instance is not using parallel update. + +* Bugfix:Fixed an issue where running the Editor in a different culture could break pins on nodes that have optional arrays of pins (ie. Animation Graph nodes like Blend By Layer). + +* Bugfix:Fixed an issue with Anim Class being set by name, causing duplicate-named Anim Blueprints to be incorrectly resolved. + +* Bugfix:Fixed an issue where "r.SkeletalMeshLODBias" was affecting meshes in the Animation Editor viewports. + +* Bugfix:Fixed an issue with Animation Preview Scene keyboard binding (I and O hotkeys now hide and show scene elements regardless of tab opened state). + +* Bugfix:Skinned Mesh LOD now updates in the editor under various physics-related circumstances. + +* Bugfix:Fixed an issue with foot placement IK doing line traces on worker threads. + +* Bugfix:Fixed an issue with Anim Blueprints that contain State Machines having blank palettes. + +* Bugfix:Renaming curves in animations now saves properly. + +* Bugfix:Fixed an issue with two-bone IK flickering around full extension when stretch is enabled. + +* Bugfix:Animation now works as expected for dynamically-bound wheeled-vehicle anim instances. + +* Bugfix:Fixed an issue where you could not undo changes from Alembic Import settings. + +* Bugfix:Fixed timing issues occurring while playing back Alembic caches. + +* Bugfix:Fixed an issue with incorrect behavior occurring when placing more than three samples in a straight line for a 2D blendspace. + +* Bugfix:Dropping a new Animation asset on an existing Sequence Player node can now be undone. + +* Bugfix:Breaking transition node connections within Animation State Machines can now be undone. + +* Bugfix:Fixed an issue to ensure that changes to animation sync markers are propagated to currently open blendspace assets. + +* Bugfix:Skeletal Mesh components tick properly when paused if "Tick Event When Paused" is enabled. + +* Bugfix:Fixed Skeletal Mesh Merge duplicating Skeletal sockets. + +* Enabled snapping for translation in the Animation viewports. + +* Removed force inline from Virtual Compression functions. + +* Removed the AnimGraph module from the Graph Editor as a dependency. + +* Bone Reference now has improved performance by caching compact post bone index. + +* Graph files have been moved to Animation Blueprint Editor. + +* We have stopped saving raw curve data into animations on cook in order to save memory and disk space. + +* Ticks now appear properly on Anim Sequence scrub bar. + +* Persona now depends publicly on Skeletal Editor. + +* Montages are now correctly initialized when created.They can be used straight away without first opening them in the Montage Editor. + +* We now propagate thread safety flags to child Animation Blueprints. + +* The Anim Notify Blueprints now start with a "received notify" event node. + +* Made single-node animation instances request clothing simulation resets when their animation is changed.This is because the new animation could be very different from the outgoing animation, and this might cause pops. + +* Refactored "Evaluate Bone Transforms" to prevent usage of Skeletal Mesh component. + + * Deprecated "Evaluate Bone Transforms" in favor of new “'EvaluateSkeletalControl_AnyThread”. + + * Deprecated Skeletal Mesh component argument to "Convert CS Transform To Bone Space" and “​Convert Bone Space Transform To CS”.Now they just take a transform. + +* When selecting bones that are non-required, we now do not render gizmos or text labels. + +* Skeletal selection does not lag behind choice made in the viewport (i.e. when showing bone weights). + +* Added accessor and modifier functions for "Start Time Offset" value in Geometry Cache components. + +##### Animation Assets + +* New:You can now choose a preview slot in the Montage Editor. + +* Bugfix:Fixed a crash when reimporting animations with additive transform tracks. + +* Bugfix:Fixed an issue with additive Pose Asset preview being applied twice. + +* Bugfix:Compressed animation data is now included in Memory Stats for Animation Sequences. + +* Bugfix:Fixed an issue where blendspace interpolation settings would not have a direct effect and required reopening the blendspace asset. + +##### Animation Blueprint + +* New:Added "Spline IK" node. + +* New:Added a property to Blendspace Player nodes that enables users to choose whether the play time is reset when the blendspace changes. + +* New:Animation Blueprints can now specify a Preview Mesh. + +* New:Added the "Look At" node so you can use “Look at Location” on a socket or joint, and improved the Visualizer. + +* Bugfix:Fixed a crash when "Pose Asset" contains a bone that is not in the mesh. + +* Bugfix:Fixed an assertion that could occur when selecting certain items in the Animation Blueprint editor. + +* Bugfix:Fixed a crash when diffing State Machine Transition graphs. + +* Bugfix:Fixed an issue with "Pose Handler" using mesh bone index and not compact bone index for setting up “Bone Blend Weights” array. + +* Bugfix:Fixed an issue with incorrect errors on compiling Aim Offset nodes with exposed blendspace pins. + +* Bugfix.Fixed an issue with additive nodes breaking the current pose when they have no additive animation attached. + +* Bugfix:Fixed issues pertaining to extra references to Animation Blueprints on Skeletal Mesh components. + +* Layered Bone Blend node has been optimized so that it will cache mask weights in compile time. + +##### Import/Export + +* Bugfix:Fixed a crash when reimporting a Skeletal Mesh that has Virtual Bones. + +##### Skeletal Mesh + +* Bugfix:Fixed a crash when using re-import button in the Skeletal Mesh Editor. + +* Bugfix:Fixed a crash related to Skeletal Mesh resources not being initialised before component is registered. + +* Bugfix:Fixed a serialization mismatch in Skeletal Mesh source buffers. + +* When importing a Skeletal Mesh, "Activate Bone Indices" now always includes parents even if it's not skinned. + +#### Tools + +* Bugfix:Fixed a crash in Persona when rotating a bone due to single bone controllers not being initialized correctly. + +* Bugfix:Fixed an ensure when deselecting bones in Anim Blueprint editor. + +* Bugfix:Fixed an issue where mesh-customized sockets were not showing up by default in 'Active' socket filter mode. + +* Bugfix:Fixed issues related to bone removal in Skeletal Mesh LODs. + + * Issue where the "Apply" button would not show after adding bone names. + + * Issue where previously removed bones would not be restored. + + * Ensure that the Skeletal Tree is updated when bones are removed or restored. + +* Double-clicking animation assets in Content Browser will now try to re-use existing Animation Editor windows, rather than opening a new one every time. + +* Animation picker on Skeletal Mesh component is now disabled rather than hidden when no Skeletal Mesh is assigned. + +* The Soundwave-internal curve tables have been moved to the 'Advanced' rollout. + +#### Audio + +* New:Vorbis-encoded audio files can now be streamed. + +* New:Audio streaming is now supported on Android, iOS, and XBox One. + +* Bugfix:Fixed a shutdown crash when there is a pending async audio occlusion trace. + +* Bugfix:Fixed a crash when opening a Media Sound Wave. + +* Bugfix:'Sound Player' nodes will more efficiently load the referenced sound asset unless a 'Sound Quality' node is being used to select which 'Sound Player' nodes to consider, in which case, the current asset reference evaluation will continue to be used. + +* Bugfix:We only queue subtitles once per-wave instances playback. + +#### Automation + +* New:Added support for -DeveloperReportOutputPath and -DeveloperReportUrl commands to permit local runs of the Automation Tool to generate reports on the report server and launch the browser to view them. + +* 'ResavePackages' commandlet now supports lighting in separate packages when using it to rebuild lighting. + +* Option to disable taking screenshots has been disabled.Screenshot comparison is an integral part of the testing so disabling them is no longer allowed. + +* The system now waits for the asset registry to finish loading assets before running tests. + +#### Blueprints + +* New:Added the 'Remove Gameplay Tag' function to the gameplay tag function library. + +* New:Blueprints containing a String and Text variables can now be marked as multi-line, which enables values to contain newlines when pressing Shift + Enter while editing them. + +* New:Blueprint Variables can now be marked as 'Read-Only' in Blueprint Editor, which prevents them from being set in Blueprints.This behaves the same as using 'BlueprintReadOnly' instead of 'BlueprintReadWrite' on a C++ UPROPERTY() declaration. + +* New:'Get Default Locale' has been exposed to Blueprints. + +* Macro instances that contain latent actions will now show an overlay clock icon like other latent nodes, which makes them easier to spot and understand that they impact execution flow + + ![image alt text](image_39.png)(w:720 h:180 convert:false) + +* New:Improved comments in Blueprints. + + * Comment node text now wraps while the comment is being edited. + + * Reduced cases where the title of a comment node would clip at the end. + + * Editing the comment for a regular node using the right click menu will now show changes immediately, rather than waiting until the node was moused over again. + +* New:Added the Save and Find in Content Browser buttons to the Level Script Blueprint editor (they will save/show the map package that contains the Level Script). + +* New:Added the ability to search for delegate nodes using the function name that they are bound to. + +* New:'Array Get' node. + + * Can toggle between returning a reference or copy. + + * Using a reference solves a longstanding issue with arrays of structs not being able to easily make changes to the items in the array. + +* New:'Get Class Defaults' node has been extended to include output pin exceptions for Set & Map variable defaults.Like array types, the returned value is now a copy of the default value rather than a reference to it.This is done in order to avoid an accidental mutation of the Blueprint class default object. + +* New:Function inputs are now exposed as variable "Get" nodes via the right-click context menu in a Blueprint function graph context. + + * To use:In a Blueprint Function graph, right-click to access the context menu.Any input parameters will be listed as additional "Get" actions. + + * In this way, input parameters can be accessed like local variables from anywhere in the function graph; in other words, it's no longer necessary to drag wires all the way back to the Function Entry node in order to access these values. + +* New:We now support "value-based" Bitfield enum type associations in the editor for a UPROPERTY marked as 'Bitmask' with a 'BitmaskEnum' association. + + * Prior to this release, Bitfield properties did not work with associated enum types in which the enum values were explicitly set to a bitmask value (e.g. 0x80).That is, the value was assumed to always be set to the index of the bit that the flag should set in the editor ("index-based" mode). + + * To switch the associate to the new "value-based" mode, include an additional metadata key in the UENUM() declaration.Example:UENUM(Meta = (Bitmask, *UseEnumValuesAsMaskValuesInEditor="true"*)). + +* New:Added a whitelist mechanism for handling native noexport types that can support direct field access in nativized Blueprint code. + +* Bugfix:Fixed a crash in Blueprint Editor when adding an input parameter to a Custom Event node after deleting a Function Graph containing a Create Event node. + +* Bugfix:Fixed a crash when creating a new Blueprint class from one or more selected Actors in which the root component is not Blueprint-spawnable. + +* Bugfix:Fixed a crash on load in nativized EDL-enabled builds with non-nativized child Blueprint class assets. + +* Bugfix:Fixed a runtime Blueprint VM crash upon removing an element from set after consecutive add/remove iterations. + +* Bugfix:Fixed a crash that could occur when splitting a struct pin on a collapsed graph node. + +* Bugfix:Fixed a crash when trying to use non-supported types as Blueprint map keys. + +* Bugfix:Fixed a crash that could occur when changing a Map's value type string to vector.Map variables are properly cleared when value type is changed to an incompatible type. + +* Bugfix:Fixed a crash when compiling a Blueprint that contains a split pin in a collapsed graph. + +* Bugfix:Fixed a crash loading Blueprints that contain a Blueprint node that no longer exists in code. + +* Bugfix:Fixed a crash when using the Straighten Connection shortcut key (and some other related issues with actions done after the Context Menu is closed). + +* Bugfix:Fixed a crash when opening a Blueprint with a parent class that no longer exists. + +* Bugfix:Fixed a crash with the merge tool when the source control provide is SVN and there are gaps in the revision history.(This may still not work correctly, but it won't crash.The full fix will be covered with UE-43603) + +* Bugfix:Fixed a crash when attempting to name component with a very long name. + +* Bugfix:Fixed a crash that could happen when running Cook On The Fly server with nested struct assets. + +* Bugfix:Fixed a crash that would happen when a level in Blueprint was auto-saved. + +* Bugfix:Fixed an assertion that could occur when compiling a Blueprint with certain nodes (Select, Math Expressions, etc.) + +* Bugfix:Fixed a crash that could occur when reparenting a component Blueprint. + +* Bugfix:Fixed a crash that could happen when setting maps and sets of strings and certain structs. + +* Bugfix:Fixed a crash that would occur when passing a self node through a CustomEvent ref parameter. + +* Bugfix:Fixed a crash that could occur when adding a new Blueprint function and immediately undoing. + +* Bugfix:Fixed a crash that could occur after renaming the category of an implemented interface function inherited from a native C++ parent class in the 'My Blueprint' panel. + +* Bugfix:Fixed a crash that could occur when editing a local curve variable's default value in a Blueprint graph. + +* Bugfix:Fixed an ensure misfire in PIE exit when using Play as Listen Server Mode. + +* Bugfix:Fixed an infinite loop case in the Math Expression node. + +* Bugfix:Fixed an issue where misaligned memory access of noexport struct properties leading to incorrectly initialized values in a nativized cooked build. + +* Bugfix:Fixed an issue with broken collision shapes at runtime when cooking with the optimized Blueprint component instancing data feature turned on. + +* Bugfix:Fixed an issue with a Bitmask Enum type validation failure when serializing a Make Bitmask Literal node + +* Bugfix:Fixed an issue with log spam when compiling a Blueprint function with a local TSet or TMap variable. + +* Bugfix:Fixed an issue with broken pin wires after expanding a duplicated collapsed graph node. + +* Bugfix:Fixed an issue with invalid custom Enum type selection on member fields in the User-Defined Structure editor after a reload. + +* Bugfix:Improved context menu "whole world" algorithm to proper take into consideration localisation when searching for terms. + +* Bugfix:Fixed an issue where renaming interface input/output parameters will no longer cause broken pin links at interface function call sites in Blueprints that are currently loaded. + +* Bugfix:Fixed an issue with broken graph node pin links caused by renaming interface function input/output parameters prior to compiling the interface, but after renaming the function itself. + +* Bugfix:Fixed an inability to save after choosing a Level Script Blueprint class as the default value for a class input pin in a non-Level Script Blueprint class function graph. + +* Bugfix:Fixed an issue where Blueprints containing a 'Key Get Display Name' node will no longer be marked dirty when opening the Blueprint. + +* Bugfix:Fixed an issue where the user defined variable tooltip was not showing up when hovering over Get/Set nodes for local variables. + +* Bugfix:Fixed an issue with old versions of Blueprints being diffed accidentally showing up in Find-in-Blueprints search results. + +* Bugfix:Fixed some issue in Blueprint Diffing where properties of nodes edited in a Details panel would not show up as differences (this impacted Animation Graph nodes most heavily). + +* Bugfix:Fixed an issue in Blueprint nativization that could cause bad interface function calls to be generated. + +* Bugfix:Fixed an issue that could cause stale Blueprint instances in a hidden sub-level to spam a runtime error. + +* Bugfix:Fixed an issue that could cause a Blueprint 'mismatch' error when using 'Set' and 'Map' node. + +* Bugfix:Fixed an issue that could cause struct asset defaults to be wiped on editor reload. + +* Bugfix:Fixed an issue that could cause a packaging error when running with Blueprint nativization and no Blueprints were nativized. + +* Bugfix:Fixed an issue that removed the ability to set Blueprint object variables as 'config' variables, as you cannot set a object reference from a config. + +* Bugfix:Fixed an issue with reroute nodes so that a new output connection will propagate that type through to the node's inputs. + +* Bugfix:Fixed an issue so that 'Get Data Table Row' nodes are now compatible with DataTable variables. + +* Bugfix:Fixed an issue that could cause material parameter setting in a Blueprint construction script to fail. + +* Bugfix:Fixed an issue that could cause overlap events to fire multiple times in PIE. + +* Bugfix:Fixed an issue that would generate the nativized Blueprint plugin even if no Blueprint files were nativized. + +* Bugfix:Fixed an issue that would cause certain components to be orphaned and hidden from the component hierarchy. + +* Bugfix:Fixed an issue that could cause a level Blueprint's bound delegate nodes to not trigger. + +* Bugfix:Fixed an issue in Blueprint nativization that would cause cyclical logic (loops, etc.) to not iterate past the first iteration. + +* Bugfix:Fixed an issue in Blueprint nativization that could cause Blueprint subclasses to ignore their overridden model and default to their parent's. + +* Bugfix:Fixed an issue where non-nativized Blueprints were getting dropped from the cooked asset registry file when running with Blueprint nativization. + +* Bugfix:Fixed an issue where there would be a nativized Blueprint asset build error when there are no native code dependencies. + +* Bugfix:Fixed an issue with incorrect Blueprint graph pin value display names for user-defined enum types. + +* Bugfix:Fixed the variable 'config' setting tooltip to report the correct config file for the user to use. + +* Bugfix:Fixed an issue that could cause Blueprint variables set from a config to have their values improperly overwritten. + +* Bugfix:Fixed several issues with Switch Blueprint nodes not keeping their node and property UI in sync. + +* Bugfix:Fixed several issues where changing pawn/hud/state class from the Level editor toolbar would not work properly until the project was reloaded. + +* Bugfix:Fixed a stale class reference in interface properties that reference a Blueprint defined interface that has been recompiled. + +* Bugfix:Fixed an issue where 'Get Values' and 'Get Keys' nodes were not providing correct results for Map variables that have had values removed. + +* Bugfix:Fixed an issue where Blueprint functions that have all their return nodes pruned (ie. are not connected to anything) now have the correct output pins at call sites. + +* Bugfix:Fixed an issue where 'Movie Scene Sequence' and related code was not working when Blueprints were nativized. + +* Bugfix:Fixed an issue in nativized packaged builds that would cause default values to be lost. + +* Bugfix:Fixed 'Enum As Byte' related warnings in nativized packaged builds.'Enum As Byte' is no longer used when nativizing Blueprints. + +* Bugfix:Fixed issues with Blueprint nativization where it didn't correctly include headers necessary for owners of subobjects, and instances where all modules needed by the generated code weren't being founds.This fixes one cause of "Cannot open include file" errors when packaging with Blueprint Nativization enabled. + +* Nodes in the blueprint editor again use their custom cursor (grab hand when hovering over a node and crosshairs when hovering over pins). + +* 'Logarithm' node added to the Blueprint Math library. + +* 'Set' pins on 'Intersection', 'Union' and 'Difference' nodes now infer their values uniformly. + +* Out of date Class Default Objects are no longer duplicated when compiling a Blueprint, reducing blueprints compilation time + +* Successive calls to Set Intersect, Union or Difference now provide correct results, previously the Set was not cleared before calculating the new result + +* 'Trace By Profile' collision functions have been exposed to Blueprints. + +* Nativize code is now more precise about dependencies, reducing the resulting executable size and compiler load. + +* Blueprints that override an inheritable component are no longer 'data only'.Blueprints with overridden components but no extra functions now load without losing data. + +* Blueprints that extend types that implement 'Needs Load For Server' or 'Needs Load For Client' now honor those functions, meaning they will not be cooked for targets that their type wants to be excluded from. + +* Delegates in nativized packaged builds correctly prevent double registration. + +* Blueprints used as a child actor class will no longer be marked dirty when compiling the class that references them. + +* When duplicating a Blueprint component, that component will now be a sibling of the duplicated node, not a child of it unless it is the root node being duplicated. + +* Duplicated root nodes will have their scale set to (1,1,1) to avoid applying the scale multiplier twice. + +* Blueprintable Components are no longer considered experimental, they have been enabled by default for several versions. + +* The ticking behavior of latent actions in components has been changed to match how they behave in actors.When the component ticks, the latent actions will now be processed at the same time, rather than happening later in the frame when latent actions for non-ticking actors and components are processed.This does change behavior, so there is a console variable (t.TickComponentLatentActionsWithTheComponent) that can be used to revert to the older behavior until affected component Blueprints that depended on the old ordering behavior can be fixed up.The cvar should be treated as deprecated; it will be removed in a future release. + +* Updated Blueprint nativization so that it generates source files compatible with 'include what you use' (IWYU). + +* Moved nativized Blueprint plugin generation to the project's 'Intermediate\Plugins' folder. + +* Removed make/break nodes from the Blueprint menu for structs that aren't marked as a 'BlueprintType'. + +* Updated marquee selection in graph editors.Ctrl dragging now inverts nodes' selection state, instead of only deselecting them (holding alt is now for pure deselection). + +* The Actor Details view will now refresh property mappings for the current Actor instances selection after a bytecode-only recompile of its Blueprint class as a dependency during reinstancing. + +* Child Blueprint class assets are now marked as dirty if its parent Blueprint class incurs a structural change.This alerts the user that updates to the Child Blueprint would need to be saved on exit. + +* We now emit C++ ctor initialization code for nested default subobjects when nativizing a Blueprint class at cook time. + +* Instanced Static Mesh transform edits are now reflected in the Blueprint editor's preview scene. + +* The editor will now raise an error at cook time after an attempt to nativize a Blueprint class that also implements a native C++ interface with a pure virtual function declaration that is not also marked up with UFUNCTION.This is because we cannot nativize a Blueprint class that does not also have an implementation of a pure virtual function inherited from the interface. + +* C++ interfaces with one or more pure virtual function declarations not also tagged with UFUNCTION are now excluded from the list of available "Implementable" interfaces in the Blueprint class editor. + +* Non-nativized child Blueprint classes will now properly override a nativized parent Blueprint class's component defaults at runtime in a nativized cooked build. + +* We will now implicitly nativize any child Blueprint class that overrides one or more BlueprintCallable functions inherited from a parent Blueprint class that is also nativized. + +* The Blueprint diff tool now reports when a component changes its type between revisions + +* Blueprints are now only dirtied if edited properties are from objects in the Blueprint's package. + +#### Core + +* New:Support added for "double" and 'fname' stat types in UFE stat export to CSV. + +* New:Pak files can now have their index encrypted with AES, preventing them from being opened by unrealpak. + + * An AES key must be provided in the project Encryption.ini, and then index encryption can be enabled in the project packaging settings in the editor. + + [REGION:note] + When either pak index encryption or signing are enabled in the Project Settings, pak ini encryption must also be enabled in order to avoid a potential security issue.All of these settings can be found in the Packaging section of the Project Settings dialog in the editor. + [/REGION] + +* New:Added "Get Component For Axis" and “Set Component For Axis” to FVector and FRotator. + +* New:Added support for -iterate for content plugins that require path remapping during cook/packaging. + +* New:Added a "CookedOnly" plugin type, for plugins meant only to be loaded in cooked games (in support of Blueprint nativization). + +* New:Added a Json Object Converter to add support for saving and loading TMap and TSet UProperties. + +* New:Absolute paths are now allowed in -UserDir= argument. + +* New:Added ability for games to use command line parameters for map overriding in shipping builds if their target.cs file defines UE_ALLOW_MAP_OVERRIDE_IN_SHIPPING macro to 1. + +* New:Added support for instanced elements in TMap and TSet properties being copied during "Copy Properties For Unrelated Objects." + + * This fixes an issue where instanced fields could lose data during recompilation of a Blueprint. + +* New:Added a new method Platform Misc "Get OS Version" that returns a string representing the raw OS version info. + +* New:All HTTP implementations now use a consistent User-Agent string (specified via the overridable function Generic Platform Http "Get Default User Agent" method). + + * Added a Platform and OSVersion string to the default value (platform=FPlatformMisc::IniPlatformName() and osver=FPlatformMisc::GetOSVersion()). + +* Bugfix:Fixed a crash with startup in the runtime asset manager when the on-disc cache already contains more data than the system is configured to use. + +* Bugfix:Fixed a crash in 'Chunk Cache Worker' function constructor. + +* Bugfix:Fixed a crash when launching "Play In Editor" session caused by missing audio data if its DDC data was not present and the audio was streamed in. + +* Bugfix:Fixed a crash when UObject can be added to GC cluster only if all of its Outers can also be added to it. + +* Bugfix:Fixed an assert with LocalExportIndex.IsNull.Now the Event Driven Loader code will properly disambiguate imports with the same name and the same outer name. + +* Bugfix:Fixed a crash when Hot Reloading caused by reinstancing UEngine objects. + +* Bugfix:Fixed an occasional crash during Hot Reload CDO reinstancing that was caused by a redundant insertion into TMap invalidating an existing reference into that TMap. + +* Bugfix:Fixed a crash when importing a Blueprint which contains a non-empty TMap with an enum class key. + +* Bugfix:Fixed a crash when Hot Reloading a project which contains a user-defined struct. + +* when hot reloading a project which contains a user-defined struct. + +* Bugfix:Fixed a crash when deserializing a TMap property item with instanced elements, where the CDO contains default element values for that property. + +* Bugfix:Fixed the use of many printf non-literal formatting strings, as these are potential security issues. + +* Bugfix:Fixed an issue with incorrect error code being returned from UnrealHeaderTool when -WarningsAsErrors and -Verbose are specified code. + +* Bugfix:Fixed an issue with the error code returned by UnrealHeaderTool when an error occurs during preparsing of headers. + +* Bugfix:Fixed a persistent stat metadata warning generated during PIE.. + +* Bugfix:Fixed an issue with FMonitoredProcess to prevent infinite loop in -nothreading mode. + +* Bugfix:Fixed an issue for runtime asset cache not invalidating files with an outdated version number. + +* Bugfix:Fixed stats warnings because each new slate loading screen thread has the same stat name, but is potentially assigned to a different thread. + +* Bugfix:Fixed an issue with CSV parser missing empty cells at the end of the string. + +* Bugfix:Fixed an issue with external plugin cooking and deployment by remapping plugin directories upon cook & deployment Tested directory structures: + + * D:\SomePluginDir + + * D:\UE4\AnotherPluginDir + + * D:\UE4\Engine\Plugins + + * D:\UE4\MyProject\Plugins + +* Bugfix:Fixed a memory leak in MallocBinned which affects the mobile platforms (Android, iOS). + +* Bugfix:Fixed a typo in comments for LODColoration in BaseEngine.ini. + +* Bugfix:Fixed the Log message in "Exclusive Load Package Time Tracker." + +* Bugfix:Fixed an issue where "log.timestamp" command would not work because it was incorrectly handled by "log" console command. + +* Bugfix:Fixed an issue where the logging system could hang when running out of disk space while flushing log and fixed unexpected concurrency assert when flushing the log buffer to disk. + +* Bugfix:Fixed a deadlock when flushing log file while it's already being flushed by a flush timer on the async log writer thread. + +* Bugfix:Fixed a memory leak when running with -nullrhi on the commandline in cooked games caused by shader resources not being destroyed. + +* Bugfix:Fixed an issue to make sure the engine is properly cleaned up on UnrealHeaderTool early exit to prevent UnrealHeaderTool hangs. + +* Bugfix:Fixed an issue to make sure that streamed-in SoundWaves get added to Garbage Collection clusters. + +* Removed dependency preloading system from sync and async loading paths.It has been superseded by the new event driven loading system. + +* Removed remaining references to AES_KEY, instead using the encryption key delegates to access the key where needed. + +* Refactored encryption and signing key access in unrealpak to make it easier to use. + +* Make content projects generate a stub executable when encryption or signing keys are specified so that keys can be embedded correctly. + +* Separate pak cache granularity from pak signing chunk size in the EDL loader. + +* Increase "Serial Size" and “Serial Offset” in FObjectExport to 64bits, to handle larger file sizes. + +* Added some validation of the class index in exportmap entries. + +* Added missing support for compiling plugins external to Engine/Plugins & Game/Plugins. + +* Disabled the 'HeartBeat' function on platforms that don't actually want to use the HeartbeatThread. + +* 'None' is now going to be properly considered by the engine as an invalid filename. + +* The editor will now collect garbage after a map is loaded to make sure any stale components or other objects that are no longer needed are destroyed.This is to make sure that these components are not resurrected by another editor operations like duplication. + +* Made sure the async log writer flushes the log archive even if there's no serialization requests to prevent situations where some of the recent requests haven't been flushed to disk + +* Reduced the code size for the generated Static Register Natives functions. + +* Disabled the garbage collector when recompiling child Blueprints, as is already done for the parent Blueprint. + +* Simplified Unreal Header Tool's code generation logic. + +* Implemented Lex "To Sanitized String" for double. + +* The function Local Player Context "Is Valid" now also checks that the player controller has a player set. + +#### Editor and Tools + +* New:UnrealGameSync now includes a workspace-specific file filter, separately to the global file filter. + +* New:UnrealGameSync now supports pop-up notification for build failures on content changes. + + * To mark a badge as applicable to users submitting content changes, add +ContentBadges=Name to the [Notifications] section of the project specific configuration file at /Build/UnrealGameSync.ini. + +* New:UnrealGameSync now allows a project to specify filters for the streams that should be displayed for fast-switching to. + + * The "Quick Select Stream List" setting in the “Options” section of the Project Settings references a depot path containing a list of strings used to filter the stream list.An option is shown to switch back to showing all available streams, if desired. + +* New:Added support for in memory packages.Helps distinguish between packages which can and can't be cooked. + +* New:Added a Blueprint function to convert a Render Texture to Texture2d.This is only available for use in the Editor. + +* New:Custom Depth can now be enabled for Foliage. + +* New:You can now color-code all of the windows in the editor in order to visually distinguish them when working across multiple branches or projects + + * You can adjust the 'Editor Window Background Color' for a subtle effect, as the default background is already a pretty dark grey: + + ![image alt text](image_40.jpg)(w:929 h:416 convert:false) + + * Or you can edit the tint in the two brushes (which sets the texture to a white default one) to get a very brazen effect: + + ![image alt text](image_41.jpg)(w:929 h:416 convert:false) + +* New:Added Data Table export/import support for TMap and TSet. + +* New:Updated the Windows platform to use the newer Vista+ style browser dialogs, rather than the older XP style dialogs. + +* New:You can now empty the text value within an FText property or pin. + +* New:Added support for .ini-driven classes to use a specific platform's config hierarchy, so that the editor on a desktop platform can read .ini settings from other platforms .ini files. + + * This will allow for NDA'd platforms to keep their ini settings in protected files, but still be editable by the editor. + + * Moved project settings for console platforms over + + * See UObject::GetConfigOverridePlatform() + +* New:Scene importing now allows for plugins to expose new scene import factory types. + +* New:Overhauled "Call In Editor" support and promoted it so it can be used on functions in any class, not just Blueprints derived from AActor: + + * "Call In Editor" can now be used on native UFUNCTION() declarations (e.g., UFUNCTION(Category=CoolCommands, CallInEditor)). + + * Blueprint declared functions can also be marked as CallInEditor (in addition to custom events), which allows you to set the category and tooltip for the buttons. + + * Now shows each function as a separate button, placed in the category associated with the function. + + * Removed the duplicate copies of properties placed in the Blutility section. + + * Prevented operating on functions that have parameters or return values, which could crash before. + + * Added a scoped transaction around "Call In Editor" execution so changes made can be undone. + + * The button strip entry is now searchable by function name or tooltip. + +* New:Added a new Details view option:"Show Hidden Properties while Playing" + + * Enabling this allows you to see every property on selected objects that belong to a simulating world, even non-visible and non-editable properties. + + * This feature is very useful for inspection and debugging, because you can see all of the internals of your Actors and Objects. + + * Be careful when changing values for properties that are not really intended to be changed at runtime.You could introduce instability or even corrupt data. + + * Note that this setting is saved for your entire project. + +* New:Sequencer additions and updates: + + * Tracks can now be prioritized based on their subscene hierarchical bias value.Higher bias values take precedence. + + * Fixed particle system restore state so that it gets the proper initial active state of the particle. + + * Added a generic past menu for Master (root) tracks. + + * Changed the time snapping interval in the toolbar UI so that it no longer additionally updates the Sequencer setting.The setting is only used to initialize the time snapping interval of the Level Sequence. + + * Added translate keys with Ctrl and Left-Right arrows. + + * Added Level Sequence Actor button in the Details panel to open Sequencer. + + * Duplicate shot now puts the duplicate on the next available row, keeping the start/end times the same. + +* New:You can now isolate/select all sections using a specific Material slot. + +* New:The FBX importer updates: + + * Now imports collision models under the FBX LOD Group. + + * Now applies the transform from FBX options only one time for the whole import. + + * When importing an FBX file from Blender, the importer now removes the root node name "armature." + + * No longer removes the socket created in UE4 Editor when using reimport.If affects only imported socket. + +* New:Added some LOD Setting options to the FBX Import Options window.Users can now specify the following Static Mesh LOD Settings Options: + + * Auto Compute LOD Distance + + * Minimum LOD Number + + * LOD number + +* New:The FBX Importer now fills two more Material Inputs (Texture only) from the FBX Material: + + * Specular Factor imported as "Roughness" + + * Shininess imported as "Metallic" + +* New:The FBX exporter can now export with the Front X-Axis.The new option is under the Editor Preferences settings. + +* New:TMaps now support editing structs as keys from within the Details panel. + +* New:The Data Table Row Editor now contains a Reset to Default control. + +* New:Properties added to the header of a Details panel group (ie. via IDetailGroup::HeaderProperty()) now have copy/paste actions exposed in the Context Menu. + +* New:Added the possibility in Slate to reset property group to their default value. + +* New:Added the possibility to perform the following actions in Save/Load Level dialog: + + * Rename + + * Delete + + * Create a New Folder + + * Show in Explorer + + * Show the Size Map tool + +* Bugfix:Fixed a crash when selecting components from an Actor's component tree and then undoing + +* Bugfix:Fixed a crash when attempting to open multiple cooked assets at once in the editor. + +* Bugfix:Fixed a crash when pressing PIE button several times before PIE session begins. + +* Bugfix:Fixed a crash that could occur during seamless travel while playing in a Play-in-Editor session with the "Use single process" option unchecked. + +* Bugfix:Fixed a crash while using the "Delete" button inside of the HLOD outliner while having a Proxy mesh opened in the Static Mesh Editor. + +* Bugfix:Fixed a crash when using import into level with .obj file. + +* Bugfix:Fixed a crash when dragging a re-import scene and there is new asset created. + +* Bugfix:Fixed a crash when creating too many LODs when importing a Static Mesh. + +* Bugfix:Fixed a crash with High Resolution Screenshot Tool that could happen when the Screen Percentage is set to a value other than 100%. + +* Bugfix:Fixed an issue with Device Output Log showing partial lines sometimes. + +* Bugfix:Fixed an issue where array properties would revert to the default values when duplicating an Actor. + +* Bugfix:Fixed an issue with Details panels becoming unusable if "Show Only Modified Properties" is enabled and there are no modified properties. + +* Bugfix:Fixed an issue so that thumbnails for Material assets now respect the "used particle system sprites flag" and show a quad instead of a sphere by default. + +* Bugfix:Fixed an issue for outdated error message instructions for how to fix being unable to launch on an iOS device. + +* Bugfix:Fixed an issue with "Save Current As" option not saving the current level and only saving the Persistent Level and then reloading everything thus causing work to be lost if editing a sub-level. + +* Bugfix:Fixed an issue with Material Instances being marked dirty when opening. + +* Bugfix:Fixed an issue with TAssetSubClassOf properties being reset on undo. + +* Bugfix:Fixed an issue that could cause the wrong Blueprint instance to be duplicated, or copy/pasted. + +* Bugfix:Fixed an issue with the Focus action in the Static Mesh Editor viewport. + +* Bugfix:Fixed an issue with Color Customization so that curve color names are "R", "G", "B", "A" instead of None. + +* Bugfix:Fixed an issue with user's setting for Texture Mip LOD size being incorrectly clamped. + +* Bugfix:Fixed an issue where lighting rig rotations were not set / saved correctly for Preview Scene Profiles. + +* Bugfix:Fixed an issue where auto-exposure values from the Preview Scene Profiles were not correctly applied + +* Bugfix:Fixed an issue where HLOD's "Override Screen Size" would not propagate on a LOD Actor directly. + +* Bugfix:Fixed an issue where the Material Slot assignment wasn't correctly restored on reimport. + +* Bugfix:Fixed an issue to prevent importing more LODs than the maximum allows for. + +* Bugfix:Fixed an issue with the FBX importer's "Front X-Axis conversion".We remove the scale of the camera and adjust the orientation of both the camera and light. + +* Bugfix:Fixed an issue with Auto Reimport "Directory to Monitor" feature. + +* Bugfix:Fixed some issues with the Import commandlet: + + * Fixed possible crash when importing FBX files. + + * Now makes sure that the imported assets are saved when there is no source control. + +* Bugfix:Fixed an issue with Static Mesh conversion from UE4 4.14 to earlier versions. + +* Bugfix:Fixed an issue with the Merge Actors Tool that was sometimes assigning wrong Material IDs to mesh sections. + +* Bugfix:Fixed an issue where the Number of Players and Dedicated Server settings for PIE would not persist correctly after Editor shutdown. + +* Bugfix:Fixed issues related to Auto Reimport: + + * Fixed a crash when attempting to import to mount points that do not exist. + + * Now allow for new assets to be created from monitored directories. + + * Settings now use a path picker when specifying the "Map Directory To" field. + +* Bugfix:Fixed an issue so that Property Editor Inline Class Filter now shows unloaded Blueprint Classes properly in the Editor. + +* Bugfix:Fixed an issue with Undo/Redo transactions of Color Grading. + +* Iterative cooking .ini setting checking improvements have been made.More to come in a future release. + +* Dependency checking performance improvements for iterative cook.More to come in a future release. + +* Panning in orbit mode now takes in account camera speed setting. + +* Pivot Painter 2 is a general purpose vertex animation toolset that comes with specialized subset of material functions to automate foliage animation.The script and material function set are more flexible, easier to use and provide an improved workflow over the first release.Additionally, a content example map ships with the editor to demonstrate how Pivot Painter's output can be referenced in the editor. + +* Added a disclaimer popup for the first time a user enters VR Mode + +* All asset properties in Details panels now have thumbnails on by default. + +* Disabled editor sounds that play when you PIE, simulate or possess the player by default.There is now a setting in the editor preferences to control this. + +* The output log should now have the same text color as other panels in the editor. + +* Removed hard coded list of thumbnails, preventing objects with valid thumbnails from showing up.Thumbnails are now shown by default.Use meta=(DisplayThumbnail=false) on a property to hide thumbnails. + +* Import data and thumbnail data are now transactional.You can now undo and redo their edits. + +* Reread in the target RHIs array every time the list of shader types is needed, instead of caching, because the user could change the settings in the editor, then click cook. + +* The Paint Fill tool has changed the way it works in Texture Weight Painting mode, it now fills the mesh with the currently selected texture weight index. + +* Limited the ability of setting up the Hierarchical Level of Detail (HLOD) system in levels which are contained as streaming levels in other assets. + +* The FBX importer now builds the Static Mesh only once when there is many LODs. + +* The section Material slot assignment is now correctly restored on reimport. + +* When swapping the Static Mesh referenced by a Static Mesh component, we now just clean up the Material Override that exceed the Static Mesh Material array size, instead of clearing all overrides. + +* When using the Full Scene Importer the "Scene Import" data asset can now specify a different source file for reimport. + +* Data pin style preferences are now saved on Editor shutdown. + +* The "Fixup Redirects" commandlet now ensures that files that are marked for delete are correctly submitted to source control. + +* The "Resave Packages" commandlet will now submit files that are marked for delete. + +* Blocking volumes will actually be added to the level when placed via the "Place Actor" command instead of generating warnings. + +* Values that are directly entered for float properties with a specified Delta value will no longer snap to the nearest delta when losing focus. + +* Actor components can now be scaled to negative values using the transform gizmo. + +* Map properties now fully support customized property types used as keys. + +* When deleting an Actor, we now display the name of the referencers. + +* Using the Convert Actor feature now won't change the Actor level. + +* Primitive Statistics window will now properly update itself when adding new Levels. + +* Optimized the lightmap UVs generation to speed up the Static Meshes import flow when packing the UVs into higher resolutions. + +##### Content Browser + +* New:Added "Resave All" functionality to Content Browser folders. + +* New:Added a way to view/copy a list of references (including those that aren't loaded) to the Reference Viewer. + +* New:Importing CSV files will now show the name of the CSV file in the import dialog. + +* New:Added the ability to auto resize column in "Column View" by double clicking column splitters + +* Bugfix:Fixed an issue where folders wouldn't be removed from the Content Browser when deleting them. + +* Bugfix:Fixed an issue with the Reference Viewer where it only ever used the default thumbnail. + +* Bugfix:Fixed some issues for gathering cached asset dependency data. + + * We no longer load dependency data that doesn't have the correct package name. + + * We no longer populate the dependency results when "Gather Depends on Data" is set to false. + +* Bugfix:Fixed an issue that prevented textures from updating correctly if a source texture with the same name as a texture asset is imported from a location that differs from the asset's original source image. + +* Bugfix:Fixed an issue where the Force Feedback "Play" and “Stop” icons weren't rendered correctly and would only be displayed when hovering over the asset or when the asset is currently playing. + +* Bugfix:The Content Browser file path will now update correctly if it is pointing to a path that is deleted through the Sources Panel. + +* Bugfix:Duplicating an asset will correctly name it if there is another one of the same name. + +* Moving a newly-created asset before saving it will no longer save an empty package in the asset's original location. + +* When reimporting multiple assets, the "Yes to All" and "No to All" dialog options will prevent future reimport dialogs from appearing for the same asset type in the same operation. + +* Improve visual of "Column View" in Content Browser. + +##### Cooker + +* Bugfix:Fixed an issue with the rebuild lighting commandlet not checking out files correctly. + +* Bugfix:Fixed an issue where running the same DLC profile created by the Mobile Patching Wizard would increase HTTP chunk size. + +* Bugfix:Fixed an issue with the cooker always cooking "All Maps" even when a single map was specified on commandline. + +##### Foliage + +* New:Added the Show Flag "Foliage Occlusion Bounds" in the Advanced menu to see the bounds generated by the occlusion tree. + +* New:When moving a foliage asset to a new Level, you will now be prompted to save the Foliage Type as an asset if it's a local asset. + +* New:Improved the Foliage painting algorithm to properly support Random Pitch/Yaw when the setting "Collision with World" is enabled. + +* Bugfix:Fixed a crash that occurred when moving the mouse over certain content while in Foliage mode. + +* Bugfix:Fixed an issue that cause foliage thumbnails to incorrectly be duplicated if many of them are onscreen at once. + +* Bugfix:Fixed an issue where removing a Foliage Type wouldn't properly refresh the Details panel. + +* Bugfix:Fixed an issue where the foliage location would shift when using undo/redo transactions. + +* Optimized the occurrence of rebuilding the occlusion tree when performing actions in the editor. + +##### Landscape + +* New:We now automatically fill Landscape with the first created Landscape's Layer Info object. + +* New:Added sorting to Landscape Target Layer tabs.You can now sort by Material definition (which is the default one), alphabetical, or custom a using drag-and-drop operation. + +* New:Added a visibility toggle to only show the used Target Layers by the loaded components. + +* Bugfix:Fixed a crash when changing multipole Landscape Blend Layer nodes from Weight blend to Height blend. + +* Bugfix:Fixed an issue with user Landscape shortcuts not working in the Level Viewport. + +* Bugfix:Fixed an issue when performing an Undo action would delete the newly created Landscape and return back to the new Landscape window. + +* Bugfix:Fixed an issue where Landscape holes (visibility mask) was causing NavMesh problems at the borders of the Landscape component. + +* We have improved when a Level will be marked as dirty when manipulating a Landscape Spline. + +* The Landscape tools Material synchronisation has been updated between game thread and render thread. + +* When adding a new Component, if a Landscape info object exists it will determine which one is used based on its neighbors. + +##### Material Editor + +* Bugfix:Material Custom nodes that contain "tab" characters will now correctly display tab characters after copy/paste. + +##### Matinee + +* Bugfix:Fixed an issue with how tooltips display when using a Material Function in your Material. + +##### PhAT + +* Bugfix:Fixed "Multiple Values" being displayed in Body Setup properties when single bone has multiple bodies + +##### Sequencer + +* New:Added the ability to specify additional Event Receivers for Level Sequence Actors. + +* New:Event tracks can now be defined to trigger events at the start of evaluation, after objects are spawned, or at the end of evaluation. + +* New:Added the ability to retrieve bound objects from Blueprint. + +* New:There have been improvements to the Binding overrides. + + * Added the ability to override spawnable bindings. + + * Added the ability to override bindings in sub Sequences. + + * Deprecated "Get Sequence Bindings" node in favor of "Get Sequence Binding", which is more robust, and provides a better UI/UX for selecting single bindings + + * Added Drag/Drop support for Binding overrides. + +* New:Added the ability to specify Event Receivers on Event Tracks. + + * These are defined by right-clicking on the Event Track in the Sequencer tree, and adding Event Receivers. + + * Such objects must be defined within the Sequence hierarchy (as well as parents, children, grandchildren etc). + +* New:Added a reworked, more generic property path handling system in the Sequencer object change listener. + +* New:Unlocked the Cine Camera Post Process Depth of Field to use options other than CircleDoF. + +* New:"Pre Roll" and “Post Roll” are now exposed at the section level for all sections. + +* New:Enabled "Use Custom Start Frame" and “Use Custom End Frame” when rendering a single shot from the menu. + +* New:You can now set the fade color in the Track display. + +* New:Audio row heights are now also resizable by dragging on the bottom end of the track lane in the track area view. + +* New:Sequencer now re-evaluates when starting PIE or Simulate.This can be disabled with "Bind Sequencer to PIE" and “Bind Sequencer to Simulate” in the Play-in-Editor Advanced settings. + +* New:Split "Snap to the Dragged Key" option into two options, "Snap to the Pressed Key", and "Snap to the Dragged Key". + +* New:Added a loop selection range.If there is no selection range, loop mode is restricted to loop or no loop. + +* New:Added hotkeys to set the selection range to the next and previous shot (page up, page down).Also, added hotkey to set the playback range to all the shots (end). + +* New:You can now set sequencer audio components bIsUISound to false so that they don't continue playing when the game is paused. + +* New:Added an option to instance sub sequences when creating a Master Sequence. + +* New:Notify streaming system prior to Camera cuts by default.To enable, users will need to enable the Pre Roll section of the Camera cuts for the streaming system to activate prior to cutting to cameras. + +* Bugfix:Fixed a crash when selecting keyframes in the viewport. + +* Bugfix:Fixed a crash with Sequencer Recorder when clearing properties to record. + +* Bugfix:Fixed an issue where tick prerequisites were not being set up for Actors streamed in from a streaming Level. + +* Bugfix:Fixed an issue where Sequencer was animating objects from the wrong world. + +* Bugfix:Fixed an issue with event parameter structs being able to be garbage collected, resulting in NULL structs potentially being written out. + +* Bugfix:Fixed an issue with animation looping in Sequencer. + +* Bugfix:Fixed an issue with Sequencer Recorder to fix duplicate components getting recorded. + +* Bugfix:Fixed an issue with FBX import with camera and light animation key imports. + +* Bugfix:Fixed an issue with autokey not setting a keyframe for Slate color with the specified color. + +* Bugfix:Fixed an issue for filtering to include Child nodes. + +* Bugfix:Fixed an issue where the Sub Track node deletion so that all sub tracks aren't deleted, only the row being requested. + +* Bugfix:Fixed an issue to invalidate expired objects when Blueprints are compiled.This fixes Actor references to now handle sections that need to have their GUIDs updated (ie. attach tracks). + +* Bugfix:Fixed an issue so that when finishing a scrub, playback status is now correctly set to stopped rather than set to a stepping state. + +* Bugfix:Fixed a missing command binding alt-r to record selected objects into sequencer. + +* Bugfix:Fixed an issue to Filter hidden functions, which fixes a bug where the field of view property for a cinematic camera appears to be animatable,.It should be hidden just like it is in the property editor. + +* Added a warning when Sequencer tries to write to properties that have changed type. + +* Sequencer templates are now always regenerated on load + +* Level Sequence frame snapshots now take account of fixed-frame interval offsets, and overlapping shot sections on the same row. + +* We now convert Linear Color to Color for fade to get the correct fade color in viewport. + +* Audio waveforms now show peak samples with smoothed RMS in the center. + +* Set max tick rate when in game if force fixed interval playback is enabled. + +* Cache player fade state so that restore state will return the values to the pre animated state. + +##### Source Control + +* Bugfix:Fixed an issue with Git plugin to update the status on directories hotfix. + +* With the Git plugin, use use asynchronous "MarkForAdd" and "CheckIn" operations for the initial commit. + +* Allow binary files in Git stored via git-fat, git-lfs, etc to be diffed. + +##### Static Mesh Editor + +* Bugfix:The camera position now stays in place after reimporting from inside the Static Mesh Editor. + +##### Traps + +* Subversion binaries have been updated to 1.9.5.They should no longer crash when used. + +##### VR-Editor + +* New:Improved functionality for the VR Mode: + + * Improved the look and feel of the rotation gizmo handles while in VR Mode. + + * Improved interaction for painting terrain, foliage, and mesh painting. + + * Improved gizmo handle animations. + +* New:VR Mode is now bound with the Editor Sound settings. + +* New:VR Mode motion controllers now have collision when in simulate. + +* Bugfix:Fixed VR Mode selection now to respect a component's "Is Selectable" state. + +* Bugfix:Fixed an issue with not being able to open a project in the Project Browser with VR Mode auto-entry enabled and the HMD active. + +##### Windows + +* New:Custom Depth can now be enabled for Landscapes + +* Bugfix:Fixed an issue with Landscape spline segment splitting when using streaming levels. + +* Bugfix:Fixed an issue with Landscape painting in orthographic viewports when the painted area's Z value was below 0. + +##### World Browser + +* Bugfix:Fixed an issue when moving a sublevel in World Composition browser does not appear in Undo History. + +##### World Outliner + +* New:Actors in the World Outliner will now bring their children with them when moved into a newly created folder. + +#### Gameplay Framework + +* New:Added an option for components to opt out of physics impulses on damage using "Apply Impulse On Damage". + +* New:Exposed component's "Ignore Radial Impulse" and “Ignore Radial Force” flags to Blueprints. “Ignore Radial Impulse” is now properly respected when applying impulse to relevant movement components. + +* New:The Player Controller's "Should Perform Full Ticket When Paused" can now be set from Blueprints and the Details panel. + +* New:Spawn Sound and Force Feedback Blueprint nodes now have a "Auto Destroy" pin that can be set to false to allow the component to be reused after the sound/pattern complete. + +* New:The number of buttons that can be used by Raw Input is now 20. + +* New:Fields of Attribute MetaData are now editable. + +* New:In the Ability System, the "Cancel Ability" has been exposed to Blueprints. + +* New:For Cameras, support has been added for specifying a default aspect ratio and whether or not to constrain to it in a Camera Manager subclass. + + * Normally the information would come from a Camera component, but this is useful when using custom view logic that doesn't source from a Camera component as the view target. + +* New:Added "​On Component Collision Settings Changed Event" delegate to Primitive Component.Fixed Skeletal Mesh Component not calling Super implementation for “On Component Collision Settings Changed”. + +* New:Refactored Character Movement Component determination of net send rate when combining moves into a virtual function Get Client Net Send Delta Time.Added configurable values to Game Network Manager under ​[/Script/Engine.GameNetworkManager] in BaseGame.ini:"ClientNetSendMoveDeltaTime", “ClientNetSendMoveDeltaTime”, “ClientNetSendMoveThrottleAtNetSpeed”, “ClientNetSendMoveThrottleOverPlayerCount”. + + * This replaces the values that were hardcoded in the network code for characters and enables easier configuration of client send rates for movement. + +* New:We've increased Pawn location replication precision to 2 decimal places from 0.Prevents replicated pawns from being inside geometry by a large amount.Removed CVars controlling CharacterMovement proxy shrink amount and made those instanced properties on the component. + +* New:Added a flag to Character Movement Component to determine whether or not character should Sweep while using "NavWalking", instead of relying on Generate Overlaps flag. + +* New:Added "Apply Gravity While Jumping" flag to Character Movement Component.This helps to reduce Framerate Dependent Jump Height issues when disabled, but raises jump height.This is disabled by default. + +* Bugfix:Fixed a crash due to null World Settings when rendering a thumbnail. + +* Bugfix:Fixed a crash when opening Blueprint after adding a component to native class referenced by a Child Actor Component. + +* Bugfix:Fixed several issues with renaming or deleting Gameplay Tags from the Gameplay Tag Project Settings page. + +* Bugfix:Fixed an issue when calling "Set Visibility" or “Set Hidden In Game” all children of the component will now properly be reconsidered as to whether they should render. + +* Bugfix:After duplicating an Actor, components added to the source instance will now have the correct position in the duplicate. + +* Bugfix:Ability actions can now be properly bound to input components. + +* Bugfix:Construction scripts will no longer be incorrectly rerun on Actors in a level that was hidden and then later made visible again. + +* Bugfix:Fixed an issue warning about invalid world content when loading maps with child Actor components in it. + +* Bugfix:Fixed cases where built lighting on child actors could be lost when loading a level. + +* Bugfix:Fixed case where child actor template was not cleared when setting child actor class to null. + +* Bugfix:Fixed issues with seamless travel in PIE and sub-levels shared between different Persistent Levels. + +* Bugfix:Fixed issues where Child Actor Component's "Parent Component" would be null on the client. + +* Bugfix:Fixed accumulated forces in Character Movement applied incorrectly when movement mode or active state changes. + + * Added ​"Clear Accumulated Forces” + + * "Add Force" and related functions now avoid adding the force if in Movement Mode is set to "None".When ticking in "None", forces are cleared so they don't pile up until the next valid movement mode.Forces are also cleared if the updated component changes or when the capsule simulates physics. + + * "Deactivate" implemented to stop movement and call “Clear Accumulated Forces”. + + * "Clear Accumulated Forces" now also clears pending launch velocity.Exposed “Clear Accumulated Forces” to Blueprints. + + * "Apply Accumulated Forces" does not call ”Clear Accumulated Forces”, since that would prevent pending launch. + + * "Add Force" and “Add Impulse” now also check that character movement is active (not deactivated, able to tick). + + * "Simulate Movement" handles pending launch and clears forces regardless of whether it's simulated proxy. + + * Inlined Actor Component "Is Active" for performance. + +* Bugfix:Fixed characters sliding when landing on slanted surfaces or stairs, when aggressive "Perch" settings could cause a line trace (from the center of a capsule) instead of capsule trace and thereby screw up the floor distance checks. + +* Bugfix:Fixed the case of people moving a Character mesh in Begin Play rather than in the Editor or Construction Script and not having the mesh offset reflected correctly in network games. + + * Added function "Cache Initial Mesh Offset" to cache initial mesh offset, used as the target for network smoothing.This takes location and rotation params so you can be explicit on the values, in case you try to change these during network smoothing, where reading the relative offsets would be skewed. + + * Added a call to this function from Begin Play in addition to the existing call from "Post Initialize Components", and exposed this to Blueprints as well for custom changes to mesh offset at runtime. + +* Bugfix:Fixed an issue with Projectile Movement Component continuing to simulate (and generate hit events) after it is deactivated during simulation."Has Stopped Simulation" function now checks if “Is Active” is false. + +* Bugfix:Fixed an issue with "Get Welded Bodies" so that it properly returns Skeletal Bodies, instead of the default body for Skeletal Mesh Components. + +* Bugfix:Fixed an issue with infinite jump on client when Jump Max Hold Time is not 0. + +* Stop dynamic force feedback when initiating Actor is destroyed. + +* Clarified the tooltip on the "Inverse Lerp" function. + +* In the Movement Component "Deactivate" calls “Stop Movement” to clear cached velocity. + + * It was undesirable that reactivation many seconds or frames later would restore a stale velocity. + +* The "Collision.ListComponentWithResponseToProfile" command now includes pending kill objects.Use this to inspect collision responses between objects in a game world. + +* Optimized the Math Library "Get Forward Vector" (converts Rotator to forward direction).This way we avoid building a matrix, and avoids 1 more SinCos call. + +#### Learning Resources + +##### Sample Content + +* New:ShooterGame now supports dedicated servers on PC, Mac, and Linux! + +#### Localization + +* New:Improvements to culture switching and LocRes files. + + * LocRes files now de-duplicate translations when they're generated, which can result in smaller LocRes files. + + * The localization compilation step now produces a LocMeta file, which contains meta-data specifying the native culture during compile, and where the native LocRes file can be found. + + * Changing cultures now loads the native localization data prior to loading the non-native translations to ensure that translations are always applied to a consistent base. + + * The "leet" culture (available when localization testing is enabled) is now always applied against the native translation, and correctly restores non-translated text when switching away from the "leet" culture. + + * "-culture=leet" now works correctly on the command line ("-leet" also works). + + * LoadLocalizationResourcesForCulture is no longer called multiple times during initialization of the text localization manager. + +* New:Updated Fast Decimal Format to support the correct 0-9 numerals for the current locale + + * These are typically still Latin, but Middle Eastern languages have some variants. + + * This addresses an inconsistency between FText formatting of numbers and dates (since numbers always used Latin, but dates used the culture correct numerals). + +* New:Split the monolithic culture concept in UE4 + + * UE4 has historically only supported the concept of a single monolithic "culture" that applied to both text localization and internationalization, as well as all asset localization.Typically the "culture" was set to the "locale" of the OS, however that could be undesirable or incorrect on platforms (such as newer versions of Windows) that have a distinct concept of "language" (for localization) and "locale" (for internationalization). + + * This change splits the concept of "culture" into "language" and "locale", and also adds the concept of "asset groups".The language is now used to work out which localization we should use, and the locale is used to control how numbers/dates/times/etc are formatted within our internationalization library. + + * Asset groups expand on the language used by asset localization and allow you to create a group of asset classes that can be assigned a different culture than the main game language.A typical use-case of this would be creating an "audio" group that could, for example, be set to Japanese while the rest of the game runs in English. + + * If your game doesn't care about the distinction between language and locale, and doesn't need to use asset groups, then you're able to continue to use "culture" as you always have.If, however, you do care about those things, then you'll likely want to avoid using the "culture" directly (as it's now a very aggressive setting that overrides all others), and instead favor using language/locale (games will typically treat these as the same) and asset groups as separate concepts (both in settings, and in your in-game UI). + + * The language or locale for a game can be controlled by settings within the "Internationalization" section of your configs (this would typically be set in your Game User Settings config, in the same way that "culture" works), eg) + + [Internationalization] + language=fr + locale=fr + + * The asset groups for a game can be controlled by settings within the "Internationalization.AssetGroupClasses" and "Internationalization.AssetGroupCultures" sections of your configs (the asset group class definition would typically be set in your DefaultGame config, and the cultures the groups use would typically be set in your Game User Settings config), eg) + + [Internationalization.AssetGroupClasses] + +Audio=SoundWave + +Audio=DialogueWave + [Internationalization.AssetGroupCultures] + +Audio=ja + +* Bugfix:Fixed an assert that could trigger when an IME composition is aborted during widget destruction. + +* Bugfix:Fixed a crash that could happen if a config was loaded while the Gather Text commandlet was running. + +* Bugfix:Fixed text namespaces being treated as case-insensitive when exported to JSON manifests and archives. + +* Bugfix:Fixed text format history being clobbered by reference collection. + +* Bugfix:Fixed the pluralization of the decorator text during drag-and-drop operations. + +* Vastly reduced the number of allocations that happen when rebuilding text at runtime. + +#### Networking + +* New:Network dormancy efficiency has been improved greatly (if you have large number of dormant actors, they now will have less overhead). + +* New:Network consider/relevancy code is now also much more efficient.Overall, expect a 20+% improvement in performance if you have lots of Actors in the network Actor list. + +* New:Adaptive network update frequency logic is now on by default.This should improve network performance for games that weren't opt'ing in to this feature. + + * Net.UseAdaptiveNetUpdateFrequency is now 1 by default. + +* New:Replays now support network relevancy. + + * All connections are considered when determining if an Actor is relevant. + + * Enable by setting demo.UseNetRelevancy to 1. + + * Override cull distance with demo.CullDistanceOverride. + +* New:Added more info about the connection to logs when you see "FRepLayout::UpdateChangelistHistory:History overflow, forcing history dump" message. + +* New:Updated OnlineSubSystemNull to properly account for game state and "Allow Join In Progress". + +* Bugfix:Fixed a crash that could occur when updating unmapped objects. + +* Bugfix:Fixed an issue with IPAddressBSD validation when setting IP from string. + +* Bugfix:Fixed a memory leak in network drivers. + +* Bugfix:Fixed an issue with syncing of non-contiguious UENUMs over networks. + +* AActor "Pending Net Update" has been deprecated.Please use “Pending Net Update” that is now on FNetworkObjectInfo (obtained by calling “Get Network Object Info). + +* UNetDriver "Get Network Actor" is now deprecated.Use UNetDriver “Get Network Object Info” instead. + +* Disabled net.PartialBunchReliableThreshold for replays (we don't need to worry about bunch fragment sizes since there is no packet loss for replay connections). + +#### Online + +* New:Steamworks integration has been updated to support version 1.39, including updated steam controller support! + +* New:Web Browser module no longer directly depends on Online Subsystem plugins. + + * It uses the Online Engine Interface shim to explicitly depend on the engine and will use Online Subsystem features when that module is optionally added. + +* New:Added a new overload for Online Session "Find Friend Session" in the session interface that can retrieve sessions for multiple friends. + +* New:Sending and accepting invites on dedicated servers on Steam is now supported. + +* New:Updated OpenSSL libraries to use BCrypt on Windows in order to reduce memory allocations. + +#### Other + +* New:Added a "Buffering" media player event. + +* New:The Plugin Browser now supports customizations to allow for context-specific plugin creation. + +* Bugfix:Fixed a crash with Media Assets in "Tick Video" after media player is garbage collected. + +* Bugfix:Fixed an issue to prevent the default cooked sandbox from trying to read non-cooked assets. + +* Bugfix:Fixed a message router thread not being woken up right away on shutdown.Crashreporter uploads/downloads crash data from AWS + +* Search button is disabled after clicking it once to prevent accidental double-clicks. + +* Reading the config hierarchy for TVOS now matches IOS to get the correct bundle id when packaging a project + +#### Paper2D + +* Bugfix:Custom tile maps using collision can now be created at runtime on any platform without crashing.However on iOS/Android/HTML5 only the boxes and spheres used in the per-tile collision shapes have effect; arbitrary convex collision (e.g., slopes or other triangle-based collision) will not cause collisions or overlaps until support for PhysX runtime cooking is added to these platforms. + +* Bugfix:The Paper2D flipbook editor now shows the current frame correctly when the animation timeline is longer than the editor window and the scroll bar is moved to the right. + +* Bugfix:Paper2D flipbook editor now shows the correct number of frames; previously, it was one frame short. + +#### Physics + +* New:Added sprite to Physics Thruster Component (previously this was only available on Physics Thruster Actor). + +* New:Exposed "Set All Physics Angular Velocity" to Blueprints. + +* New:Added finer-grain PhysX stat information that is available by using "stat physxtasks". + +* New:Added the ability to specify whether a ragdoll is in the sync or async scene with "Use Async Scene". + +* New:Changed default contact-gen method to PCM.This is the default in PhysX 3.4. + +* New:Added "Is In Air" method to Vehicle Wheel. + +* New:For the Wheeled Vehicle Movement Component, the Mass dependent wheel properties now update when mass is updated. + +* New:Created "Add Force At Location Local" function to allow component space forces. + +* New:Added a new Physics settings "Enable Stabilization".Stabilization can help stacks of simulated bodies to come to rest. + +* Bugfix:Fixed a crash in anim dynamics when a world was not valid during pre-update. + +* Bugfix:Fixed a crash when saving sub-levels that don't currently have a correctly initialized scene. + +* Bugfix:Fixed an issue with incorrect slider for "initial Average Frame Rate" physics setting. + +* Bugfix:Fixed an issue with physics constraint warning messages in Message Log.These now list Component/Actor name correctly. + +* Bugfix:Fixed an issue with editing Box and Capsule collision primitive rotations by storing rotation as a Rotator rather than Quaternion. + +* Bugfix:Editing collision profiles in Editor Preferences no longer discards edits. + +* Bugfix:"Find Closest Bone" function no longer ignores the “Required Physics Asset” option. + +* Bugfix:Fixed an issue teleport not working for physical animation component. + +* Bugfix:Fixed an issue incorrect inertia tensor computation for cubes, which was being doubled. + +* Bugfix:Fixed an issue with kinematic body interpolation in substepping causing invalid raycasting, sweeping, or overlapping. + +* Bugfix:Physics Constraint component now works as expected when its target is a Child Actor component. + +* Bugfix:Fixed an issue with collisions between components with CCD enabled having unreliable behavior. + +* Bugfix:Fixed an edge case where generating collision data could cause the engine to hang in an infinite loop. + +* Bugfix:Fixed a regression with Raycasts against Capsules returning invalid hits. + +* Bugfix:Instanced Static Mesh now properly creates physics state when set to Stationary. + +* Bugfix:Fixed a memory leak caused by keeping PhysX shapes in memory after they are no longer being used. + +* Expanded self-collision culling for clothing by providing a scale to tweak the culling queries.This makes a tradeoff between performance and accuracy. + +* Added a guard against infinitely thin geometry, which fixes some NANs. + +* Performance improvements to Anim node "Rigid Body". + +* Physics performance is improved by skipping the update of kinematic bodies when they haven't moved. + +#### Platforms + +* New:Add logging for the NUI GPU reserve so we can see when it's enabled and disabled. + +* New:Exposed JAVA_HOME setting in Android SDK Project Settings on Mac. + +* New:Added "Platform Handle Splash Screen" to deal with hiding splash screen properly on Startup Movies. + +* New:Implemented support for new controllers (Xbox Wireless, SteelSeries Stratus XL, PS4). + + * Note: there are two implementations for Xbox Wireless due to differences in firmware.Firmware before 3.1.1221.0 does not use standard mapping which you can enable by setting the Android.OldXBoxWirelessFirmware CVar to 1 (defaults to new firmware). + +* New:Added support for "r.ScreenPercentage" on mobile allowing the game scene to be rendered at lower resolution than the UI.Requires MobileHDR to be enabled. + +* New:On-screen warnings now appear when a mobile shader permutation required to correctly render the current scene's lighting setup has been disabled in Project Settings. + +* New:Made some big DeviceProfile changes, particularly for the protected platforms. + + * Changed the "type" of some DPs from WindowsNoEditor, etc to Windows.It should be a platform, not a random string. + + * With that change, the platform can be used to save out protected platform DP .ini files to subdirectories, maintaining secrecy + + * Added Config/[PlatformName]/ConfidentialPlatform.ini files so that the DP loading code knows to look in their directories for DPs.See FGenericPlatformMisc::GetConfidentialPlatforms() for more information. + +* New:When uploading a HTML5 project to AWS S3, it now supports "signature version 4" authentication and better error message feedback on upload failures. + +* New:Added "use fixed timestep" setting option for HTML5 builds (This has been separated from Engine > General Settings - Framerate). + + * This is slightly different to "Smooth Framerate" and “Fixed Framerate”. + + * NOTE:Fixing the timestep does not guarantee the actual framerate.Calculations based on delta time may be adversely affected by this. + +* New:Added iOS/Android support for new Audio Mixer. + +* New:"Does Save Game Exist" will now show a message if the save data is corrupt. + +* New:Initial support for voice chat in the Android platform.To use enable the Voice module in DefaultEngine.ini, in the level bp create a session, and in project settings > Platforms > Android > Advanced APKPackaging, check the setting 'Add permissions to support Voice chat (RECORD_AUDIO)'.After this create a multiplayer game between two android devices.For more information check pull request #2894. + +* Bugfix:Fixed a crash with mobile feature level preview when the Low Quality Lightmap shader permutation is disabled. + +* Bugfix:Fixed a crash in clothing on platforms that don't support clothing. + +* Bugfix:Fixed a crash when backgrounding or sleeping on iOS Metal devices. + +* Bugfix:Fixed a crash with UIImagePickerController. + +* Bugfix:Fixed an issue with executable path for stripping Android debug symbols (handle non-Windows properly). + +* Bugfix:Fixed memory reporting for Uniform Buffers in "stat rhi". + +* Bugfix:Fixed a slow memory leak in FD3D12UniqueDescriptorTable. + +* Bugfix:Fixed rendering of batched Slate primitives in D3D11.x. + +* Bugfix:Fixed an issue with S3 public link generator for "Shipping" builds filename. + +* Bugfix:Fixed an issue with iOS IDFV string allocation. + +* Bugfix:Fixed UPL processing on iOS plist files. + +* Bugfix:Fixed network byte ordering for iOS multiplayer sessions. + +* Disabled the game analytics anonymous usage data sent to Epic on the console platforms. + +* Save 66MB of memory by disabling the unused default SHAPE heap in XAudio2. + +* Stop the audio thread from using the 7th CPU core as it can be pre-empted and not get enough execution time. + +* Add -distribution when iOS distribution Packaging. with IPhonePackager.exe. + +* Changed mouse cursor to be always visible when running in Mobile Preview. + +* Refactored memory allocation functions (BinnedAllocFromOS) on all platforms.Made Binned2 malloc work on Linux. + +##### All Mobile + +* Bugfix:Fixed a crash in mobile patching utilities mount method. + +* Bugfix:Fixed an issue with the shader compile for Landscape on platforms below SM4 feature level. + +##### Android + +* New:Bad package names are now detected and APK generation is stopped with a proper error message instead of failing during Java compiling. + + * Package names with fewer than 2 segments are not allowed (e.g., "myproject" is not allowed, but “com.myproject” is legal). + + * Only alphanumeric characters and underscore are allowed in the package name (Note: hyphens in the project name will be converted to underscores, but any other hyphens need to be corrected in Android project settings). + + * All segments must start with a letter; if your project name starts with a letter you will need to replace the [PROJECT] part of the package name in Android project settings. + + * Reserved Java keywords may not be used as the full segment; appending an underscore or other legal characters will fix this. + + * Segments may not be empty (e.g. "com..myproject" is not legal). + +* New:Larger OBB files embedded in APK are now allowed by bypassing Asset Manager. + +* New:We've implemented a first pass of Google Cloud Messaging plugin.This is considered an experimental feature for this release. + +* New:Added missing key codes for keyboard input (@ and #). + +* New:Added a drop-down with some common console commands on Android to the console dialog. + +* New:Patches ant.bat to handle long command line issue on Windows. + + * Copies original ant.bat to ant.orig.bat and writes a new ant.bat which uses subst with an unused drive letter to shorten paths). + + * Note: you can edit the generated ant.bat if you need to change the drive letter used; the editor will not replace it if ant.orig.bat is found. + +* New:Editor now checks to make sure that at least SDK Android-23 is selected and installed.There will be an error message if an earlier version is installed. + +* New:Updated AAR handling to deal with versioning, subproject dependencies for resources, and scope (ignore test). + +* New:Added "Game Activity On New Intent Additions" section to Android Unreal Plugin Language (UPL). + +* New:Added support for using native virtual keyboard with Slate widgets instead of the dialog currently used for text input. + + * Events are triggered when the virtual keyboard is shown and hidden. + + * The show event includes the area of the screen that is covered by the virtual keyboard. + + * This feature is exposed in the Android Project Settings as an experimental feature checkbox. + +* Bugfix:Fixed a crash that could happen when closing the Android web browser. + +* Bugfix:Fixed an issue to handle spaces in ANT_HOME path in generated ant.bat patch. + +* Bugfix:Fixed an issue with application hanging on returning from the lockscreen if orientation is Landscape. + +* Bugfix:Fixed an issue to correct the log warning about Target SDK and permissions. + +* Bugfix:Fixed an issue with Launch On when multiple architectures are enabled in the project. + +* Bugfix:Fixed an issue with ad banner location on Android 7.0 devices. + +* Bugfix:Fixed some documentation errors in UnrealPluginLanguage.cs. + +* Bugfix:Fixed the executable path for stripping Android debug symbols for non-Windows platforms. + +* Bugfix:Fixed an issue with password hiding in input dialog. + +* Bugfix:Fixed an issue with EGL linking issues for ARM64 libraries. + +* Bugfix:Fixed an issue to save and restore texture filtering for movie playback in all cases. + +* Bugfix:Fixed an issue with Mac and Linux install and uninstall scripts if ANDROID_HOME is not set. + +* Bugfix:Fixed an issue with ShowLoginUI interface change in Game Circle plugin. + +* Bugfix:Fixed an issue with HTTPChunkInstaller texture format checks and missing #define warning. + +* Bugfix:Corrected AndroidManifest.xml required features for "Daydream and Cardboard" option when GoogleVR plugin enabled. + +* Bugfix:Fixed an issue to prevent inserting extra permissions into AndroidManifest.xml multiple times from Project Settings. + +* Bugfix:The correct APK file name is now used when launching from editor for Android. + +* Bugfix:Fixed issues with experimental keyboard. + + * Ensure the local scope ScreenRect passed into "On Virtual Keyboard Shown" in AndroidJNI is captured by value instead of by reference. + + * Moved ShowVirtualKeyboardInput's "Keyboard Showing" early-out checks into the UI thread task.This enables the keyboard to continue showing when changing focus between multiple Editable Text Box widgets. + +* Bugfix:Fixed an issue with locations on non-ARMv7 GoogleVR libraries so that it is properly filtered by active architecture. + +* Bugfix:Fixed an issue to properly restore state for Android devices not using separate context for movie playback. + +* Bugfix:Removed an obsolete warning with Java 1.5.The java.source and java.target are now set to 1.7. + +* Only disable Java console command receiver for Shipping builds. + +* Build configuration is passed to UPL for access during packaging as $S(Configuration). + +* Reenabled GooglePlay for ARM64 now that it doesn't crash. + +* Changed Gear VR installLocation to auto as now required by Oculus. + +* Rebuilt ICU libraries for Android with timezones enabled and updated build scripts. + +* Android media player now pauses and resumes with application state. + +* "Is Packaging For Daydream" only returns true if GoogleVR plugin is enabled. + +##### HTML5 + +* New:Emscripten toolchain has been upgraded to 1.37.9. + + * Web assembly + + * WebGL 2 + +* New:There has been an update to GameX template. + + * Multiple (parallel) downloads with progress percentage updates. + + * Test for wasm and WebGL 2 capabilities. + +* New:Updates to python build scripts. + +* New:Configurable .ini settings have been exposed to the editor.These can be found in Project Settings > Engine > HTML5. + +* New:Added support for emscripten "-pre-js" and “-post-js” option when building for HTML5. + +* New:Added support for WebGL 2 shader to turn on Instance Static Mesh Vertex Factory. + +* Bugfix:Fixed an issue with AWS S3 shareable link for shipping builds. + +* Bugfix:Fixed some issues with WebGL 2 shaders. + +* Bugfix:Fixed an issue with HTML5 plugin when Blueprint projects are promoted to code projects automatically. + +* The recommendation from emscripten developers is to use "-separate-asm" option for asm.js builds. + +* Added many new UE4 patches to package HTML on Linux. + +* Since connections are not closed manually (server side), send a dummy payload with content-length data. + +##### Import/Export + +* New:Set Java source and target to 1.7 (fixes Java 1.5 obsolete warnings). + +* New:Added support for changing the variable "r.MobileContentScaleFactor" at runtime on Android.This is useful for device-specific resolution tweaking. + +* Bugfix:Fixed an issue where HTML5 video in a Web Browser widget would only output sound but no video on Android. + +* Bugfix:Fixed an issue where the red and blue channels were reversed in screenshots taken on Android in Vulkan mode. + +* Disabled eglSwapInterval since it can cause issues with some drivers. + +* Changed text for Android Mobile Deferred Renderer setting to indicate that it's only supported on Nvidia K1 and X1 devices. + +##### iOS + +* New:As we move towards the next version of iOS, we will be moving towards 64-bit support only.We have added messaging in this release to start the process of this migration. + +* New:IOS now utilizes the Library/Caches directory to save any data on device.This includes logs and save games.IPhonePackager has been updated to pull the data from this location as well as the Documents directory. + +* New:Xcode 8.3 is properly supported in this release. + +* Bugfix:Fixed a crash if Text Box widget is closed before text is finished being entered. + +* Bugfix:Fixed a crash in the OnlineSubsystem when it is disabled on iOS. + +* Bugfix:Fixed an issue with static audio noise on iOS devices. + +* Bugfix:Fixed an issue with remote compiling by unconverting the path back to host when reading from the module file name. + +* Bugfix:Fixed a memory leak on texture creation with Bulk Data in OpenGLTexture.cpp. + +* Bugfix:Fixed an issue with the device profile names for iPad Pro 9.7 and 12.9. + +##### Linux + +* New:Added pooling of OS allocations on Linux, greatly reducing the need to call mmap/munmap() and avoiding running into vm.max_map_count limit when loading large projects. + +* New:Install of MIME types during setup is now supported. + +* New:UnrealPak is no longer included in the default make target, the prebuilt binary will be used instead. + +* Bugfix:Fixed a crash in ShaderCompileWorker due to misaligned strings. + +* Bugfix:Fixed starting Linux programs using FPlatformProcess::CreateProc() from a path with space. + +* Bugfix:Fixed various issues with Vulkan RHI on Linux. + +* Bugfix:SlateDlg now appropriately compares filter extensions in a case-insensitive way, so both *.fbx and *.FBX work. + +* Bugfix:Fixed bogus "unable to make config file writable" message (the operation was actually succeeding). + +* Bugfix:Fixed clang 4.0 warnings. + +* Bugfix:Fixed inability to rebuild lighting in ResavePackages commandlet on Mac and Linux. + +* Bugfix:Fixed some problems when working from directories that have space character in their names. + +* Bugfix:Fixed older versions of Linux cross-toolchain (ones using LINUX_ROOT instead of LINUX_MULTIARCH_ROOT) not being detected. + +* Bugfix:Fixed a memory leak in callstack symbolication on Linux.This makes memory profiling work again. + +* Bugfix:Fixed an issue with Linux editor splash screen image being wrong when no project has been opened. + +* Bugfix:Fixed MoveFile to work across file systems. + +* Bugfix:Removed redundant RootDir() and EngineDir() on Linux. + +##### Mac + +* New:Enable Metal Shader Model 5 support on Intel as of 10.12.4 and later. + +* New:On Macs that do not support Metal, but erroneously report that they do, show a message box that tells users that the application cannot run instead of crashing on a failed assert. + +* New:Removed Mac OpenGL RHI files and disabled building of OpenGL RHI on Mac. + +* New:Limited support added for exposing debug events to Apple's Instruments "Points of Interest" tool. + +* New:Added RHISetResourceAliasability_RenderThread to FDynamicRHI for RHIs to implement simple render-target aliasing. + +* New:Added FApplePlatformObject, a custom block allocator for Objective-C types (with NSZombie support) which is now used in Metal RHI to decrease allocation costs of Objective-C types. + +* New:Limited support for Xcode automatic code-signing for iOS/tvOS. + +* New:Reimplement RQT_AbsoluteTime for Metal using a similar emulation to OpenGL on Mac so that the scalability system can correctly set the default graphics options.Not all drivers support this and in those cases the scalability settings are determined by an alternative, fixed, code-path. + +* Bugfix:Fixed mouse position issues in fullscreen mode on Mac. + +* Bugfix:Fixed an issue in Avf Media Player causing looped movies to only play once. + +* Worked around Metal's lack of implicit type-casting that was causing incorrect rendering in the Distance Field Ambient Occlusion and Shadows shaders. + +* Re-ordered the options in MetalRHI's internal debug options (Console Variable: "rhi.Metal.RuntimeDebugLevel") to make it more efficient. + +* Minimisation of render-target changes in some passes, notably Scene Occlusion and DBuffer Decals. + +##### Tools + +* Bugfix:Fixed a rare crash with the Web Browser widget on iOS. + +* Bugfix:Fixed iPhonePackager errors in output log when opening Project Settings on Windows. + +* Bugfix:Fixed Get Max Samplers returning an incorrect value for iOS OpenGL, which could have suppressed some warnings for shaders that used more than 8 samplers. + +* Removed duplicate gc.MaxObjectsInGame setting in IOSEngine.ini. + +##### Windows + +* Bugfix:Fixed a problem on Windows where the cursor would get locked to a part of the screen after switching from fullscreen to windowed while the cursor was unlocked. + +#### Programming + +* New:Added an experimental Android option to enable Shipping builds with hidden symbol visibility by default. (bBuildWithHiddenSymbolVisibility). + + * Add JNI_METHOD for java accessible native functions, without this java will trigger an unsatisfiedlinkerror exception. + + * This can significantly reduce the size of the final .so file. + +* New:Added support for map file generation with Android. + +* New:Crash reporter is no longer staged by default when packaging from the editor.The default endpoint for crashes was an Epic server, so including it in packaged games by default was not useful. + +* New:Script plugins can now specify dependencies which should trigger UnrealHeaderTool to be re-run, by overriding the IScriptGeneratorPluginInterface.GetExternalDependencies() method. + +* Bugfix:Fixed a crash where Canvas wouldn't update font engine services if it was never created. + +* Bugfix:Fixed an issue with Automation Tool exception when running Perforce commands if multiple brokers are present in the server configuration. + +* Android links with -gc-sections to remove unused code/data. + +* Program targets can now be excluded from the full solution build roster by setting bBuildInSolutionByDefault to false from their .target.cs file. + +#### Rendering + +* New:Added support for Window PIX. + +* New:Enabled support for NVIDIA Aftermath.On Aftermath enabled executables you can now get a GPU callstack when a GPU crash is detected. + +* New:Enabled support for global Distance Field shaders on GL 4.3 and Vulkan SM5. + +* New:Added support for Quad overdraw viewmode in the Forward Renderer. + +* New:Add support for per-component Skeletal Mesh skin weight overrides. + +* New:Added /VIRTUALIZEDIRECTX option to XgConsole for XGE shader compiling to work on remote machines without DX installed. + +* New:Added support for Structured-Buffer resource views to Metal RHI. + +* New:Added AMD path to experimental D3D11 HDR support. + +* New:Exposed the r.DisableDistortion cvar for toggling distortion rendering. + +* New:The high level rendering code is now PipelineStateObject aware which will allow us to reduce complexity in the rendering backends of Vulkan, Metal and Dx12 in the future. + +* New:Added FShaderCodeLibrary which handles de-duplication of shaders during content cooking and the shader code has moved into a separate library for cooked content runtime loading.This reduces package sizes and load-time overhead. + +* New:Added RHIShaderLibrary for platform specific native shader library implementations.This allows each platform to provide its own optimal shader library implementations. + +* New:Added Metal (MacOS and iOS) native shader library where shaders are loaded from a single Metal library improving the memory footprint, load time, and runtime compile times. + +* New:As part of the cook process for Metal, the archiving process also generate text shaders that can be used when running with optimized Metal shaders.Run with optimized shaders and while debugging with text source. + +* New:Added command line option "-noheartbeatthread" to disable heart beat thread. + +* New:Full refactor of the GPU Skin Cache to fix multiple issues related to Editor, Persona, per-frame numbering.Memory limit is now set per World in the Project Settings > Rendering section. + +* New:ShaderCache now supports running with multithreaded rendering.Command line flag "-norhithread" is no longer required to enable this feature and can now be removed if it was being used solely for this purpose. + +* Bugfix:Fixed a crash with D3D12 in "Update Texture 2D". + +* Bugfix:Fixed an assertion failure in basepass when trying to draw a mesh with Post Process Material. + +* Bugfix:Fixed a crash when the Tile Renderer renders before any other renderer.This could happen in rare cases on Editor bootup. + +* Bugfix:Fixed a crash accessing mesh Material arrays with invalid index. + +* Bugfix:Fixed a potential crash when rendering to accessible buffer. + +* Bugfix:Fixed a possible crash when failing to import cubemaps. + +* Bugfix:Fixed a crash for MacOS/Metal when compiling Materials using the Vector Noise node. + +* Bugfix:Fixed overflow issues that could occur on mali based devices when rendering DoF with bright objects. + +* Bugfix:Various Vulkan fixes: + + * Compiles in Linux. + + * Many cubemap issues squashed. + + * Changed the scratch reflection cubemap clear to SetRenderTargestsAndClear, instead of SetRenderTarget() / Clear(). + + * Added compute fences. + +* Bugfix:Fixed several sRGB related issues with Retainer Box widget. + +* Bugfix:Fixed an issue with prepass/basepass z-fighting, caused by bad vertex welding in depth-only indexbuffer. + +* Bugfix:Fixed an issue with velocity rendering when an off axis projection matrix changes from frame to frame. + + * Affects very few people.Cave rendering and stereo glasses but not HMDs. + +* Bugfix:Fixed an issue with scene motion blur data is only updated for the main renderer frames.Fixes scene captures and planar reflections breaking object motion blur. + +* Bugfix:Fixed an issue with Exponential Height Fog where it renders incorrectly after world origin rebasing. + +* Bugfix:Fixed an issue introduced into 4.15 where Static Meshes with auto-generated LODs were no longer sharing lightmaps between LODs. + +* Bugfix:Fixed bug converting a Procedural Mesh component to a Static Mesh if it only contains a single triangle. + +* Bugfix:Fixed an issue where Scene Capture 2D's show flags would not be applied properly in some circumstances. + +* Bugfix:Fixed an issue where the "disable Stationary Skylight" feature would cause improper warnings.Also made it so that a movable Skylight is always used in Persona preview window so all projects can get preview lighting. + +* Bugfix:Fixed an issue where High Quality Particle Lights would not move properly if their parent was attached to a socket of an animated skeleton. + +* Bugfix:Fixed detection of OpenGL Radeon driver on Mesa. + +* Bugfix:Fixed an issue with shot command in Vulkan. + +* Bugfix:Fixed an issue with refract() intrinsic handling in hlslcc for GL/Metal/Vulkan. + +* Bugfix:Fixed an issue with missing Mobile Material Interface for Landscape "Used Materials" check. + +* Bugfix:Fixed rare case where Decals could incorrectly draw a second time in separate translucency pass. + +* Bugfix:Fixed a bug with the basic eye adaptation mode that could result in incorrect brightness when using a small viewport.This has no effect on the default histogram version of eye adaptation. + +* Bugfix:Fixed an issue with Separate Translucency being affected by Gaussian DoF. + +* Bugfix:Fixed an issue with "Streaming Bounds" show flag not working correctly.It now shows the texture streaming bounds for the textures currently selected in the Content Browser. + +* Bugfix:Fixed possible stall when canceling texture updates. + +* Bugfix:Fixed an issue for tone mapping of bright objects with zero green.Previously, these could have had a one-pixel black outline. + +* Bugfix:Fixed an issue with the IES Light Profile importer with LM-63-1986 format. + +* Texture flags are now properly routed to RHICreateTexture3D from the render target pool. + +* Collection Parameter Nodes no longer rename parameters when duplicated. + +* Renamed console variable "r.Streaming.ScaleTexturesByGlobalMyBias" to "r.Streaming.ScaleTexturesByGlobalMipBias". + +* Now when using the "freezerendering" command, the foliage culling/occlusion will also be frozen. + +* Optimize the computation behind the Screen Position material expression in the pixel shader. + + * Exposes the viewport offset of the view within the render target in the View Property material expression. + +##### FX + +* Bugfix:Fixed an issue with rendering corruption issue with 4 and 8 vertex instanced particles using the wrong Vertex Factory objects. + + * D3D didn't need separate Vertex Factories due to the VertexDecl updating the stride at draw call time, but some platforms were affected. + +##### Lighting + +* New:Improved quality and significantly faster cubemap prefiltering for reflections and skylight. + +* New:Post Process Indirect Lighting Intensity no longer scales Skylight reflections. + +* New:Screen Space Reflections (SSR) now has a higher quality setting for sharp SSR when using Quality Level 4. + +* New:Distance field self shadowing controls for hiding world position offset self-shadow artifacts. + + * Removed Static Mesh Build Settings "Distance Field Bias", which shrunk the distance field, breaking AO and shadows. + +* New:Distance field mesh visualization now uses a cone containing the entire tile to cull objects with, making the results stable. + +* New:Distance field temporal filter stores a confidence value, which is used to track leaking of occlusion during the upsample, and flush those leaked values through the history faster.Reduces DFAO ghosting when the camera is moving. + +* New:Added some new features to the Skylight component. + + * "Occlusion Exponent" which is useful for brightening up indoors without losing contact shadows as “Min Occlusion” does. + + * "Occlusion Combine Mode" which is useful for artists to choose how to combine SSAO with Distance Field Ambient Occlusion. + +* New:Added "r.AOListMeshDistanceFields" which dumps out mesh distance fields sorted by memory size, useful for directing content optimizations. + +* New:Planar reflections handle views smaller than the render target in a general way. + + * Fixes planar reflections with adaptive pixel density (ViewFamily size larger than actual views combined). + + * Planar reflections are now supported in splitscreen. + +* New:Support for fading of Light Propagation Volume cells towards the volume edges. + +* Fresnel of clear coat layer now darkens diffuse for the clear coat shading model. + +* SSR is now reprojected correctly on moving objects. + +* Raised High ShadowQuality to 2048 as 1024 for CSM is too low. + +* Disabled all distance field features on Intel cards because the HD 4000 hangs in the RHICreateTexture3D call to allocate the large atlas. + +##### Materials + +* New:Added a "Sign" material graph node which replaces the library function for more optimal translation. + +* New:Added MinimalAPI to several material expressions. + +* New:Updated default behavior of "Power" node to no longer “abs” or “max” against an arbitrary value as the results were incorrect. + + * Previous version available by calling ClampedPow(x, y) in a "Custom" node. + +* New:Improved material translation preservation of constants. + + * This improves detection of used attributes which prevents some cases of features being enabled incorrectly. + +* New:Material flag normal curvature to roughness now works in the Deferred Renderer.It is no longer forward only. + +* New:Improved Material graph error messages. + +* New:Enabled "r.Streaming.UsePerTextureBias" by default as a way to improve quality in low texture budget settings. + +* Bugfix:Fixed errors across various library Material Functions. + +* Bugfix:Fixed an issue with broken size query for render targets in Material graphs. + + * Implemented missing "Get Size" functionality. + +* Bugfix:Fixed various data type inconsistencies on legacy Make and Break Material Attributes graph nodes. + + * Using these together with the "Get" and “Set” Materia lAttributes nodes should now be more forgiving. + +* Bugfix:Fixed a regression in HLOD shadow casting performance. + +* Bugfix:Fixed inconsistent results with the "Investigate Texture" commands. + +* Bugfix:Fixed possible incorrect results when listing textures used by Material Instances. + +* Bugfix:Fixed an issue where Material Reroute nodes did not bind properly to Texture Object Parameters. + +##### Mobile Rendering + +* New:Mobile Skylights no longer render the scene on the device to determine the sky's color.Mobile skylight uses values determined via captures performed in the editor.This saves memory and performance on device and enables Skylight contribution on devices that do not support fp16 render targets. + +* New:Added "r.Mobile.TonemapperFilm" console variable which can be used to enable/disable new filmic tonemapper on Mobile devices, independently from Desktop platforms (disabled by default). + +* New:Material AO is now supported for the Mobile Rendering path. + +* New:Added better defaults for rendering resolution on iOS devices, to make them more inline with defaults on Android devices. + +* Bugfix:Fixed a crash that could occur on some devices when loading materials which use fonts as texture parameters. + +* Bugfix:Fixed a crash with Particle Cutouts on mobile devices that don't support hardware instancing (ie. Mali-400 GPU). + +* Bugfix:Fixed a crash when enabling shader cache on NVIDIA Shield devices. + +* Bugfix:Fixed a crash when previewing feature level ES3.1 with a Material using World Position Offset. + +* Bugfix:Fixed a crash with Media Player on iOS devices. + +* Bugfix:Fixed an issue with Static Mesh self-shadowing with modulated shadows. + +* Bugfix:Fixed several issues that could cause CSM shadowing on mobile devices to flicker. + +* Bugfix:Fixed an issue with scene captures on mobile when Mobile HDR is disabled and the scene capture source is Scene Color. + +* Bugfix:Fixed an issue with bright dynamic point lights cause bloom rendering artifacts on Android Mali devices. + +* Bugfix:Fixed an issue where Landscapes do not render on some Android PowerVR devices. + +* Bugfix:Fixed an issue where translucent object appear black on Zenfone5. + +* Bugfix:Fixed an redundant blend state change in OpenGL ES2. + +* Bugfix:Fixed rendering artifacts with bloom on iPhone7 using Metal. + +* Bugfix:Fixed an issue where exposure was more extreme on mobile devices with a new filmic tonemapper enabled. + +* Bugfix:Fixed an issue with padded NPOT textures not rendering correctly on iOS. + +* Bugfix:Fixed an issue with gamma issues with canvas elements on iOS Metal devices. + +* Significantly reduced OpenGL state setup for Slate draw calls on Mobile devices. + +* Slate pixel shaders will use half precision, for better UI performance on Mobile devices. + +* Mobile targeted projects will have better UI performance settings by default. + +##### Optimizations + +* New:Added 'r.CompressMeshDistanceFields' console command to rendering project settings, defaults to off to prevent hitches when streaming in levels. + + * When enabled, mesh distance fields are stored zlib compressed in memory until needed for uploading to GPU. + + * 81Mb of backing memory -> 32Mb in GPU Perf Test. + + * Atlas upload time 29ms -> 893ms. + +* New:Added a new global distance field (4x 128^3 clipmaps) which caches mostly static primitives (Mobility set to Static or Stationary). + + * The full global distance field inherits from the mostly static cache, so when a Movable primitive is modified, only other movable primitives in the vicinity need to be re-composited into the global distance field. + + * Global distance field update cost with one large rotating object went from 2.5ms -> 0.2ms on 970GTX.Worst case full volume update is mostly the same. + +* New:Added LOD Distance Factor to Scene Capture Component, which can be used to make scene captures and planar reflections much cheaper to render if the scene has good LODs setup. + +* New:Added the r.LightMaxDrawDistanceScale console command for local light scalability. + +* New:Added a rendering project setting to use 8 bit mesh distance fields. + + * This halves their memory requirement but introduces artifacts with large meshes. + +* New:Added new async tasks to reduce the cost of the texture streaming update on the game thread. + +* New:Added some automatic callbacks whenever dynamic component renderstates are updated in order to also update their texture streaming states. + +* Bugfix:Fixed async SSAO not actually running asynchronously when depth drawing mode was DDM_AllOpaque. + +* Bugfix:Fixed render queries stalling in Test/Shipping builds due to lack of pooling. + +* Ray Traced Distance Field Shadow optimized. + + * From 1.8ms -> 0.8ms in a test scene. + +* Use 16 bit indices for distance field objects culled to tiles, when 16 bit will be enough.This saves 10mb of tile culling buffers. + +* GNM RHI Clear UAV uses a compute shader for buffers larger than 1Kb. + +* GNM Structured buffers are now placed in GPU memory (was previously in CPU memory). + +* DFAO optimizations: + + * Changed the culling algorithm to produce a list of intersecting screen tiles for each object, instead of the other way around.Each tile / object intersection gets its own cone tracing thread group so wavefronts are much smaller and scheduled better. + + * From 3.63ms -> 3.48ms (0.15ms saved). + + * Replaced slow instructions in inner loop with fast approximations (exp2 -> sqr + 1, rcpFast, lengthFast). + + * From 3.25ms -> 3.09ms (0.16ms saved). + + * Moved transform from world to local space out of the inner loop (sample position constructed from local space position + direction). + + * From 3.09ms -> 3.04ms (0.05ms saved). + +* Structured buffers for DF object data. + + * Full global distance field clipmap composite 3.0ms -> 2.0ms due to scalarized loads. + +* Exposed MaxObjectsPerTile with the 'r.AOMaxObjectsPerCullTile' console command and lowered the default from 512 to 256.This saves 17Mb of object tile culling data structures. + + * This can cause flickering in Ray Traced Distance Field shadows if too many objects fall into one shadowmap culling tile. + +* Scene color resolves are restricted to the views.This fixes inefficiency with adaptive pixel density where the views don't match the view family size. + +* When using a full prepass, the base pass no longer writes depth. + + * Saves 0.3ms of Scene Depth Resolve on 970 GTX with MSAA.Also allows masked materials to get EarlyZ in the base pass. + + * Fixed primitives with Use As Occluder set to false being excluded from a full depth pass in static draw lists. + + * Added the "r.BasePassWriteDepthEvenWithFullPrepass" console command for verifying that the base pass depths match the prepass depths. + +* Changing movable skylight properties no longer affects static draw lists. + +* Mesh distance field generation uses Embree, which provides a 2.5x speed increase. + +* Cleared light attenuation for local lights with a quad covering their screen extents. + + * Clearing the entire light attenuation buffer costs 0.1ms.This optimization lowers the minimum cost of a shadow casting light from 0.15ms to 0.03ms. + +* Flushed deferred deletes when reallocating distance field atlas to reduce peak memory, at the cost of a hitch on first frame. + +* Disabled point / spot lights with Max Draw Distance on Low PC. + +* Made use of Metal's "Deferred Store Actions" where available to avoid incorrect “Store” actions introduced when restarting passes to switch encoder types or when using the Metal RHI debugging tools. + +* Stopped the Shader Cache recording all the RHI resources unless it is running on OpenGL.This significantly reduces the CPU overhead of enabling the Shader Cache. + +* HLOD texture force loaded through the "r.Streaming.HLODStrategy" console command will now load visible mips first. + +* The command "BuildMaterialTextureStreamingData" can now be used with "all" as argument to force a rebuild. + +* Reduced the texture streaming overhead for components by keeping track of the state within the streamer. + +##### Postprocessing + +* New:Using Custom Depth to write to the stencil buffer now has the ability to use single-channel bitmasks that ignore depth.This makes it possible to detect overlaps between stencil objects. + +* Bugfix:Fixed log value conversion in tonemapping causing true blacks to be lost. + +* Motion blur no longer gets dark at the edges of the screen. + +#### UI + +* New:Added API to programmatically change the Virtual Cursors UMG Widget on the Viewport Client. + +* Bugfix:Fixed sRGB conversion issues in Retainer Box when used with a material. + +* Multiline editable text boxes can now be marked as read-only. + +* Selecting multiple text widgets will now correctly set text when the text field is edited. + +* Widget Components will now correctly determine between hover and clicked states when using or simulating touch. + +##### Slate + +* New:Added Enum Has All Flags and Enum Has Any Flags, templated functions to make it easier to check for the existence of a flag on enum classes. + +* New:There is now a console variable option, Slate.VerifyHitTestVisibility (off by default), which enables additional visibility checks for widgets.Normally this is not necessary, but if you are changing the visibility of widgets during a frame, and several hit tests need to be performed that frame, there is a chance that a button could be clicked twice in one frame.Enabling this mode will make all hit testing more expensive, so for now it is off by default, but available for licensees that need the extra testing. + +* New:Added the ability to invert alpha when drawing slate textures.This will be used in the future for rendering render targets for the scene which have inverted alpha. + +* Bugfix:Fixed a crash during editable text widget destruction while a context menu was still open. + +* Bugfix:Fixed a crash when deleting a streamed font. + +* Bugfix:Fixed lots of outline data being added to the font cache due to wrongly hashing outline material and color data. + +* Bugfix:Tooltips will no longer show if the cursor is not directly over a Slate window.Fixed a case where the tooltip would not disappear when the cursor is moved over another application's window that was placed on top of a Slate window. + +* Bugfix:Fixed an issue where the cursor would sometimes not appear when its visibility was changed.This was rooted in how the OS requested cursor changes, WM_SETCURSOR on Windows only asks for new cursors when the mouse moves, but often cursors change just because mouse capture changes.So now the path has been centralized in Slate Tick to only handle the cursor changes in one place, and several places that need to refresh the cursor state, now set a flag to handle it on next tick. + +* Bugfix:Fixed a bug with ZOrder being discarded on the SOverlay slot. + +* Bugfix:Fixed Web Browser Viewport to properly scale. + +* Bugfix:SButton now correctly releases mouse capture even if it becomes disabled while pressed, but before 'click' has been fired. + +* Improved text rendering when the last resort font is missing. + + * The last resort font is no longer included in shipping builds, so this change makes some improvements to text rendering when it is missing. + + * The legacy font cache no longer tries to use the last resort font if it is not available (preventing warnings). + + * The Slate font renderer no longer tries to use the last resort font if it is not available. + + * Text shaping will use the last resort character if none of the available fonts can render a given character (likely because the last resort font is missing). + + * HarfBuzz shaped text now uses the fallback character correctly. + +* Kerning-only text shaping no longer draws characters to get their metrics. + +* Text selection height is now the maximum of the line height and text height to account for negative line-height scaling. + +* Added a setting to control whether we should use the font metrics or the bounding box when laying out a font. + + * Not all fonts have accurate metrics data, so using the bounding box can produce much better results for certain fonts. + +* Made slate loading widget / movie playback more thread safe by eliminating Slate application or the main window from being ticked directly on another thread.Is In Game Thread will also no longer return true when called from the slate loading widget thread. + +* Force resolution in standalone if the resolution is larger than primary working area. + +* Moved ESlateDrawEffect & ESlateBatchDrawFlag over to be enum class.Found cases where the enum order was being improperly assumed, and so now it will not be possible to just treat an int32 or a bool as the draw effect value. + +* Slate Application now maintains separate tracking for each pointer being utilized for drag drop, so now multiple fingers on multiple widgets can now simultaneously be attempting a drag, however once one of them becomes successful, we clear all state of all other tracking since only one Drag Drop operation is possible at a time. + +* Fold Tick is now removed from the codebase.We have not supported the other (non-folded) code path for awhile, so there was no point in maintaining the switch. + +* The Checkbox widget no longer just passes visibility down to the internal widgets it creates, that prevents future changes to affect it if it starts collapsed. + +##### UMG + +* New:Added Timing Policy option to Widget Component, so widgets can optionally tick in pausable/dilatable game time rather than real time. + +* New:Added a material function that exposes all of the current UV sets with nice names instead of indexed coordinates. + +* New:Added a method to create Slate Brushes from Paper Sprites the same way we can for materials and textures in blueprints. + +* New:Introduced PreConstruct and Native PreConstruct to the base User Widget.Users can now visualize non-binding based changes in the designer by evaluating a very limited amount of the blueprint code.In the event your user widget crashes on load, due to calling something unsafe, you can disable evaluation in the editor preferences under Widget Designer. + +* New:Introduced a way to inform widgets of more information about the designer.There is now a Designer Changed event sent to all design time widgets letting them know things like the current screen size and DPI scale. + +* Bugfix:Fixed a crash if UI blurs are rotated. + +* Bugfix:Outline color on text elements is now inherited properly. + +* Bugfix:Fixed a bug that prevented Get Owning Player in Widget from returning. + +* Bugfix:Additional fixes to the way we migrate changes from the preview to the serialized version of the widget tree in the widget editor.This fixes several issues with edit-inline Objects on Widgets. + +* Exposed a normalized (0-1) uv coordinate set and scaled pixel size for Box and Border brushes. + +* Widget Interaction Components now ignore Visible(false) Widget Components when tracing. + +* Widget animations now finish evaluating before firing an event alerting that the animation finished. + +* The Widget Interaction Component now checks if the Widget is enabled before it claims that it is over an interactable or keyboard focusable widget. + +* Adding some setters and getters for Redraw Time to the Widget Component. + +* Widgets projected into screenspace from the Widget Component should now appear in the correct locations if the player's camera has an aspect ratio lock. + +* The Safe Zone widget will now show the correct safe zone amount if you use the safezone command line options, which are now documented in the comment for the Safe Zone class. + +* Widget switchers that contain widgets with named slots will now correctly display a widget whose named slot is currently selected. + +* Widgets that are copied and pasted will now retain the same name in the widget hierarchy. + +#### VR + +* New:Added support for getting device depth from Scene Capture Component 2Ds. + +* New:Added ability to disable the autoloading splash screen, which would prevent the manual "hide splash screen" node from working properly. + +* New:Added Gear VR controller support. + +* New:Added support for OES_EGL_image_external to the mobile GL renderer. + +* Bugfix:Negative Stereo Layer priorities are now handled correctly on Steam VR. + +* Bugfix:Fixed threading issue with motion controller tracking that caused controller motion pops.This problem manifested intermittently. + +* Bugfix:Fixed crash on Oculus Rift when attempting to enter stereo mode while the HMD's 'on head' proximity sensor is not triggered. + +* Bugfix:Fixed low framerate when Oculus Rift 'on head' proximity sensor is not triggered and you exit stereo rendering. + +* The GearVR HMD plugin is now only enabled on Windows if the Oculus service is already running. + +* VR console commands have been rewritten to support autocompletion and inline help strings. + + * The VR console commands have also be renamed and now begin with vr.*. + + * The renamed VR commands have backwards compatible aliases, but will print a warning notifying the user about the deprecated functionality. + +* GoogleVR HMD now reacts to changes in the r.ScreenPercentage console command. + +* When the -hmd command line option is used to override the selected HMD, HMD plugins that are loaded early will now be unloaded during PreInit if not selected. + +* Integrated OpenGL support for SteamVR. + +* The left eye is used when selecting LODs to avoid selecting two separate LOD levels when rendering in stereo. + +* PSVR controller tracking limit management system. + + * PSVR can track the HMD and two controllers, but many more devices can be connected.With this system you can manage which controllers are tracked to stay under the limit. + +* Additional WorldScale refactoring for all platforms. + +* GoogleVR plugin updated to version 1.3 + +* Fixed Android manifest for Daydream and Cardboard. + +* Updated GoogleVR plugin to version 1.3. + +* GoogleVR SDK updated to 1.40.0. + +* GoogleVR Mode default changed to Daydream and Cardboard. + +## Programming Release Notes + +#### AI + +* New:Added a new mode to composite EQS generator (UEnvQueryGenerator_Composite), which allows the use of different types of items by each child generator.This can be enabled by advanced properties: bAllowDifferentItemTypes and ForcedItemType.ForcedItemType is the final type returned by the generator, and is used for allocating memory and executing tests.This mode is potentially unsafe and you will have to ensure proper memory layout (matching with ForcedItemType) of all item types used by child generators - usually subsets of ForcedItemType.Keep in mind that allocated memory block is zeroed before use. + +##### Debugging Tools + +* Bugfix:Fixed VisualLog macros for recording segments with user defined thickness. + +* Bugfix:Fixed compilation errors in VisualLog macros for recording custom meshes. + +##### Navigation + +* Bugfix:Fixed memory corruption in generic A* solver:FGraphAStar. + +* Bugfix:Fixed unique Id duplicates in custom navigation links. + +* Bugfix:Fixed FRecastTileGenerator::Modifiers being erroneously counted twice when stating memory. + +* NavModifierVolume has been marked as ENGINE_API and can now be freely used in game code. + +* Made FNavAgentProperties::GetExtent return INVALID_NAVEXTENT if a prop's AgentRadius is not set.This results in properly using FNavAgentProperties::DefaultProperties in navigation queries when no query extent override is provided. + +#### Animation + +* New:Added more exports to AnimationAsset, AnimSequenceBase, and Skeleton classes. + +##### Animation Blueprint + +* Bugfix:Fixed nodes only getting CopyNodeDataToPreviewNode called when pin defaults were changed (not any property change). + +##### Skeletal Mesh + +* New:Added exports to FFbxImporter, FDynamicSkelMeshObjectDataCPUSkin, and FSkeletalMeshObjectCPUSkin, for extensibility. + +#### Audio + +* New:Added new cvars to help with optimization (only applies to the new Audio Mixer). + + * au.DisableReverbSubmix, au.DisableEQSubmix, ​au.DisableParallelSourceProcessing, au.SetAudioChannelCount + +* Bugfix:Fixed MIDI Device plugin public headers not being able to be included from an external module. + +* Optimized internals of new Audio Mixer.Gains approach 15% savings from before: + + * Turned a float divide into a multiply, which occurred at least 32k times per audio update. + + * Avoided thousands of Array.Add() calls during processing, which on shipping still does checks to see if the allocator has to grow, and updates ArrayCount. + + * Removed pointer indirection and successive TArray Add()s in GetChannelMap(). + + * Removed function call overhead to updating channel map. + + * Simplified FSourceParam::Update() to reduce branching and have one return site. + + * Added alternative to GetChannelMap() called UpdateChannelMap() that avoids copying out values to an array.The values can then be fetched from the channel data directly. + + * Refactored internal data to use array of structs rather than struct of arrays for better cache coherency when processing channels one at a time. + +#### Blueprints + +* New:Added an error when declaring a Blueprint Implementable Event with an enum param that is not plain or a byte type (Blueprints only support byte-sized enums). + +#### Core + +* New:There are now several serialization options available to specify what the cooked Asset Registry includes.Look for the serialize flags inside the [AssetRegistry] section of BaseEngine.ini. + +* New:An experimental bUseAssetRegistryForIteration option has been added to CookerSettings.This improves the performance of iterative cooking by loading the cooked Asset Registry directly, but it may still have issues with some changes to source files being missed. + +* New:Added a cvar to control the pak precacher throttle. + +* New:Added new GenericPlatformFile function, GetTimeStampLocal, which returns file time stamp in local time instead of UTC. + +* New:Added a check against assembling the reference token stream while streaming without locking the garbage collector. + +* New:Added a static_assert to prevent the use of TMap keys which do not implement GetTypeHash, as this causes runtime crashes when they are manipulated by a UMapProperty. + +* New:Added a bForceDebugUnrealHeaderTool option to BuildConfiguration.xml which forces the Debug version of UnrealHeaderTool to be run instead of Development. + +* New:Added a static_assert to ensure that TInlineSetAllocator is instantiated with a power-of-two hash size, as this is a requirement for TSet and TMap. + +* New:Added ICppStructOps::IsAbstract() for testing if a native type is abstract via the property system. + +* Bugfix:Fixed TInlineValue not calling virtual destructors. + +* Bugfix:Fixed several issues with editor-only objects not being correctly stripped when cooking. + +* Bugfix:Fixed several issues with Config files loaded from Plugins.They now correctly handle diffing game-specific changes.Engine plugins config files should be named BasePluginname.ini, and game plugins should be DefaultPluginname.ini. + +* Bugfix:Fixed many bugs with the event driven loader and allowed it to work at boot time. + +* Bugfix:Fixed a bug with nativized Blueprints that was introduced with the boot time EDL changes. + +* Bugfix:Fixed race in audio streaming. + +* Bugfix:Fixed bug which would cause a fatal error when cooking subobjects that were pending kill. + +* Bugfix:Fixed a bug with EDL at boot time which caused a fatal error with unfired imports. + +* Bugfix:Fixed a bug with RF_PendingKill subobjects and the new loader. + +* Bugfix:Fixed an obscure problem with stats in commandlets that use async tasks. + +* Bugfix:Fixed rare ensure cooking for the EDL. + +* Bugfix:Fixed boot time EDL causing some issues even when it wasn't being used. + +* Bugfix:Fixed .pak precacher shutdown. + +* Bugfix:Fixed memory leak in .pak precacher. + +* Bugfix:Fixed bad merge of priority change in the EDL. + +* Bugfix:Fixed race that resulted in a memory leak when reading compressed paks. + +* Bugfix:Fixed a weird recursive situation where StaticLoadObject could return an object that has not finished loading.Also produces a fatal error if this happens.EDL only. + +* Bugfix:Fixed batched render fences when BeginDestroy calls FlushRenderingCommands. + +* Bugfix:Fixed loading a package that is already loaded. + +* Bugfix:Fixed crash in signature checks when mounting pak files. + +* Bugfix:Fixed a change to NotifyPrimitiveDetached so that it works in the editor. + +* Bugfix:Fixed hash table lock optimization. + +* Bugfix:Fixed a crash relating to FGenericAsyncReadFileHandle when not using the EDL. + +* Bugfix:Fixed comments in GenericPlatform.h. + +* Bugfix:Fixed errors raised during code generation when a multiply-inherited base class happens to have the same name as a UObject after its prefix is stripped. + +* Bugfix:Fixed a compile error when calling TArray::HeapSort on an array of pointers. + +* Bugfix:Fixed a crash when calling UCookOnTheFlyServer::FFilePlatformRequest::ToString(). + +* Bugfix:Fixed compile errors raised when #pragma is used inside USTRUCTs. + +* Bugfix:Fixed compile errors caused by whitespace existing before a UCLASS() macro. + +* Bugfix:Fixed TStructOpsTypeTraits::WithCopy giving different results when the trait is specialized without a WithCopy value from when it isn't specialized at all. + +* Bugfix:Fixed a compile error when serializing bools to an archive in editor builds, where the archive type overrides other serialization operators. + +* Bugfix:Fixed FWorldTileInfo::Read() to copy the correct licensee version number from the file summary into the archive. + +* Bugfix:Fixed a regression in FObjectAndNameAsStringProxyArchive to re-allow serialization of TWeakObjectPtrs. + +* Bugfix:Fixed some include-what-you-use issues in the engine and plugins. + +* Bugfix:Fixed UPROPERTYs being skipped when there are redundant semi-colons between the properties. + +* Asset Registry memory and performance have been significantly improved in both Editor and cooked games for large projects. + +* Allowed UnrealPak to do a better job with EDL pak files when the order provided is old or from the cooker. + +* Several minor tweaks to low level async IO stuff. + +* Stored a copy of the callback in async read request so that we do not need to worry about lifetime so we can capture variables as needed. + +* Cancelling async loading with the EDL loader now prints a warning and does a flush instead. + +* Suppressed a few EDL cook warnings. + +* Tweaked the EDL for to all platforms. + +* Platform load time performance tweaks. + +* Abstracted the IO tracker and handle manager for other platforms and applied it to all platforms. + +* Protected against UDeviceProfileManager::Get() recursion and demoted a related fatal error to a log statement. + +* Removed old code relating to FAsyncArchive, FAsyncIOSubsystemBase and package level compression.The editor now uses the lowest levels on the new async IO scheme. + +* Increased estimate of summary size. + +* Avoided adding a linker annotation if it actually has not changed.This improves ConditionalBeginDestroy performance. + +* Avoided a redundant removal of PrimitiveComponent from the streaming managers during ConditionalBeginDestroy. + +* Optimized UObject hash tables for speed and space. + +* Put the special boot order things into baseengine.ini so that licensees and games can add to it. + +* Renamed HasBeenAlreadyMadeSharable to DoesSharedInstanceExist. + +* PostLoadSubobjects is now called on all objects regardless of whether they have a CDO as outer or not. + +* When Rename is used to change the Outer without specifying a new name, the existing name is maintained whenever possible. + +* ForwardVector, RightVector, and single float FVector constructors are now recognized by Unreal Header Tool as default values for an FVector parameter. + +* ScriptMacros.h no longers needs to be included in header files that generate a header. + +* Improved the readability of some of the ReferenceChainSearch code. + +* Automatically included ObjectMacros.h in generated headers to prevent compile errors. + +* Made FPaths::Combine() variadic so that it can take arbitrary numbers of arguments. + +* Improved the readability of the verbosity of log categories in the debugger. + +* Updated TArray::Sort comments to clarify what happens when sorting an array of pointers. + +* Clarified the assertion message you get when inserting or removing a TArray element by reference which comes from the array. + +* Clarified the comments for TArray::FindLastByPredicate and FString::FindLastCharByPredicate. + +* Removed UnrealCodeAnalyzer. + +* Raised an error in UnrealHeaderTool when a header containing UCLASSes, USTRUCTs etc. does not include its .generated.h file. + +* Removed TBoolConstant template. + +* Changed TAssetPtr to allow it to be constructed from nullptr without a full definition of T. + +* Removed the WITH_HOT_RELOAD_CTORS macro. + +* Removed the UseVTableConstructors .ini option. + +* Removed generated FName variables for UFUNCTIONs. + +* Removed the generation of obsolete .java and .proto files used for replication. + +* Replaced the set of bools used to FBlueprintCompileReinstancer with a new EBlueprintCompileReinstancerFlags enum. + +* Improved hot reload logging messages to make it clear that a compile attempt on a module does not guarantee a reload of that module. + +* Made UnrealHeaderTool report an error if a UFUNCTION in a derived class has the same name but a different signature from one in a base class. + +#### Editor and Tools + +* New:Added spinner options to VectorInputBox. + +* New:Added a None option to the FKey customization, unless the FKey property had NoClear on it. + +* Bugfix:Implemented a fix to ensure FVirtualTrackArea::HitTestSection checks the row of the section. + +* Bugfix:Fixed an issue where ISequenceAudioRecorder was inaccessible to FAudioRecorder. + +* Project and plugin templates now use "include what you use" style by default. + +* When using BuildGraph, the cached list of completed nodes is now cleared by default, making the -ClearHistory argument redundant.Use the -Resume argument to continue an interrupted build using the current artifacts. + +* BuildGraph now outputs an error if any build products from previous steps are tampered with during the execution of a subsequent step. + +* The editor now offers to download and install Visual Studio 2017 if an existing version of Visual Studio is not found. + +* The AutomationTool -CookDir argument no longer accepts multiple parameters separated by '+' characters, since '+' is valid in directory names.Multiple -CookDir arguments are supported instead. + +* Game mods can now be denoted by setting the bIsMod field to true inside the .uplugin descriptor.Mods will be shown in a separate category in the plugin browser, and will be shown separately in generated project files.Installed editor builds can build and clean mods without modifying build products for the base game. + +##### Content Browser + +* Bugfix:Fixed link error when FAssetData::PrintAssetData() is used in a project. + +##### Sequencer + +* Unified global and object-bound pre animated state, and added InitializeObjectForAnimation method to state producers. + +* Opened the API for MovieSceneAudio-related classes along with some minor functionality additions. + +* Exported MovieSceneTrackEditor to allow custom tracks to be created that derive from existing tracks. + +#### Gameplay Framework + +* New:Added support for FScopedMovementUpdate to be able to queue up overlaps that do not require reflexive bGenerateOverlapEvents.This requires custom code to be able to process these overlaps. + + * This allows custom inspection or processing of overlaps within a scoped move, without enabling the more expensive overlap flag.For instance you could have a fast projectile with an overlap response to a character mesh and get those overlaps from the trace without requiring expensive overlap processing when the mesh moves. + + * Overlap events from the move will still only trigger from UpdateOverlaps() if bGenerateOverlapEvents is enabled on both components, as before. + + * Made some data in FScopedMovementUpdate protected rather than private so it can easily be subclassed, and exposed a new helper ​SetWorldLocationAndRotation() for committing the move. + +* Bugfix:Fixed a crash when manipulating audio component properties from an Actor's constructor during async loading. + +* Bugfix:Fixed CharacterMovementComponent updates with very high delta time on server when initially joining.Made sure the ServerTimeStamp is initialized to current world time rather than zero to prevent large delta. + +* CheatManager functions to Damage/Destroy targets are now easier to override in game-specific subclasses. + +* InputComponent now has BindAction function that allows binding functions with additional parameters. + +* RawInput configuration structures can now be manipulated by other modules. + +* AActor::GetComponents() with generic type is now optimized to not force an allocation when the component count is large. + + * Previously it incorrectly assumed the output array needed space for the entire contents of OwnedComponents.If OwnedComponents.Num() > the array reserve size, this forced an allocation, even if few or no components of the requested type were found. + + * It is still recommended to use TInlineComponent array or an array using TInlineAllocator<> when using this function. + +* Removed allocations during creation in ​AAIController::PostInitializeComponents() (in non-shipping builds). + +* Optimized HasActiveCameraComponent() and ​HasActivePawnControlCameraComponent() to avoid filling an array while searching for a certain component, which could have caused an allocation. + +* Optimized MoveComponent() collision queries to avoid processing PhysX touches when bGenerateOverlapEvents is off. + + * Added support for bIgnoreTouches to FCollisionQueryParams.This allows GeomSweepMulti to filter out touches/overlaps much earlier. + +* MovementComponent does not ignore initial blocking overlaps when moving away from the impact normal from SafeMoveUpdatedComponent().This fixes various cases where characters could be pushed through moving objects because they were moving away from the overlapping object, but not fast enough. + + * It now always uses the hit result to depenetrate from the impact as much as possible, and then retries the move. + + * Hit events are not triggered for the first test for depenetration. + +* CharacterMovement AdjustFloorHeight() is now allowed to adjust using the line trace if the sweep was in penetration.It also forces another next floor check so it will check after it adjusts the height or depenetrates, relevant when bAlwaysCheckFloor is off. + +* Optimized CharacterMovement tick to not extract transform values twice when they would not change in a small block of code. + +* Call TickCharacterPose() and clear root motion before abandoning tick in ​UCharacterMovementComponent::PerformMovement() when movement mode is None.This prevents root motion building up until the next valid movement mode. + +* Applied a performance tweak to ​ApplyRadialDamageWithFalloff(). + + * Do not rebuild FRadialDamageEvent each loop over hit actors. + + * Added stats for ​BreakHitResult()/MakeHitResult() under "stat game". + +* Optimized attachment to check welding option before expensive casts and body instance fetching. + +#### Localization + +* Bugfix:Fixed a bug where passing an empty FText to ChangeKey() would keep the previous FText value that had been passed in. + +#### Online + +* New:Added the bShowSkipButton parameter to IOnlineExternalUI::ShowLoginUI, which will display the "skip" button on relevant platforms. + +#### Other + +* New:Added missing initialization for SWindow::bIsMirrorWindow. + +* Bugfix:Added missing module dependencies. + +* Bugfix:Fixed a type casting issue. + +#### Physics + +* New:Added virtual keyword to DestructibleComponent ApplyDamage and ApplyDamageRadius. + +* New:Added Physx simulation shader override (see GSimulationFilterShader). + +* Bugfix:Fixed a debug rendering issue by recreating physics when changing mobility of components. + +* Bugfix:Fixed compile error when PHYSX_MEMORY_STATS=1. + +* Bugfix:Fixed performance regression caused by using collision aggregates for Instanced Static Mesh Component. + +* Bugfix:Fixed a crash in AABB Manager when origin shift is used. + +* Made UDestructibleComponent::SpawnFractureEffectsFromDamageEvent virtual. + +* Exported URadialForceComponent class for inheritance. + +* Allowed the editor to compile when bRuntimePhysicsCooking is disabled (cooking is still allowed in WITH_EDITOR builds even with it disabled). + +* EndPhysics tick will no longer be scheduled if QueryOnly is used on a ragdoll. + +* Removed the unsupported option of HideBone with DisableCollision when calling HideBone.This was not actually supported and did nothing so shouldn't break any behavior, just don't call the function. + +* Exposed PhysX enhanced determinism mode using the compiler flag PHYSX_ENABLE_ENHANCED_DETERMINISM.This allows local subsets of the PhysX simulation to behave deterministically independent of what is going on elsewhere in the Physics world. + +#### Platforms + +* Bugfix:Fixed a crash bug in cases where we received a duplicate user login/logout notification from the system software. + +* Bugfix:Fixed Codelite project having duplicated settings. + +* Moved some C++ defines out of the build.cs file into a C++ header. + +* Moved controller connect/disconnect handling to the main thread to fix issues with thread safety for callbacks. + +##### Android + +* New:Added functionality to use the visual studio mobile projects for debugging.To generate them run "generateprojectfiles.bat -vsdebugandroid" from a command prompt.After you have packaged your game for Development and put it on the device, you can set this new project as the start up project and run/debug the project in Visual Studio. + +* New:Support for Android runtime permissions added.Certain permissions have been removed or put under condition to check for support when the target sdk is greater than or equal to 23. + +##### HTML5 + +* New:Added new webassembly (wasm) toolchain - SIMD and multi-threading are not yet supported (these are slated to be in for wasm2). + + * These will be automatically turned off when building with wasm (as opposed to asm.js). + +* Removed HTML5 code from the Engine's SaveGameSystem.h and placed it in HTML5Platform.cpp. + +* Cleaned up HTML5PlatformFile.cpp and made it match as close as possible to linux's version. + +* Created HTML5's own PlatformFeature & SaveGameSystem files, and updated HTML5PlatformMisc to make use of the the new HTML5 SaveGame code. + +##### Linux + +* New:Added FreeBSD memory information functions to facilitate out-of-tree UE4 FreeBSD port. + +* New:Added a new cross-toolchain (version 9, includes clang 4.0) when targeting Linux on Windows. + +* New:Added some support for building on Debian Sid or Stretch. + +* New:Added clang to Fedora dependencies. + +* New:Added ability to compile Linux servers for 32-bit x86 architecture. + +* New:Added files generated for KDevelop to .gitignore. + +* Bugfix:Fixed more third party libraries to use libc++ instead of libstdc++. + +* Bugfix:Fixed memory leaks when symbolicating an address in Linux callstacks (during crash reporting and memory profiling).Makes runs with the memory profiler much faster. + +* Bugfix:Fixed rebuilding of VHACD (a third party library) on a case sensitive filesystem. + +* Bugfix:Fixed CodeLite projects to now use proper Debug binaries for debug configurations. + +* Switched Linux file abstraction to use new managed filehandles.Shared by all platforms with low limit of open files. + +* Whitelisted SteamVR plugin for Linux so SteamVR Blueprint functions are always available, even if stubbed. + +* Made source code accessor aware of clang 3.9 and 4.0. + +* Setup will now install the latest clang on Arch instead of clang35. + +##### Mac + +* Fixed address sanitizer support in MacToolChain (Apple changed the name of the env variable Xcode uses to enable it) and added support for thread sanitizer. + +* Fixed a problem where the glslang library was not enabled on Mac, preventing building an Android project with Vulkan from Mac. + +* Made Binned2 malloc work on Mac. + +#### Programming + +* New:When compiling a module written in include-what-you-use style, source files which are in the adaptive non-unity working set are now built with precompiled headers disabled, to expose errors with missing headers.Set bAdaptiveUnityDisablesPCH to false in BuildConfiguration.xml to disable this behavior. + +* New:Added initial support for async creation of pipeline state objects, enable using r.AsyncPipelineCompile. + +* Module .build.cs files, which depend on the contents of external files, can now add those paths to the ExternalDependencies list.Modifications to those files will trigger the the UBT makefile to be invalidated. + +* Plugin config files are now included in generated project files. + +* UnrealBuildTool will no longer attempt to use SN-DBS for build distribution if the service is disabled. + +* UnrealBuildTool now correctly supports compiling modular targets which do not use the shared engine build environment. + +* C# programs will now be included in generated project files automatically if a blank file called UE4CSharp.prog is found in the same directory. + +* The engine will now warn when trying to load a plugin with a mismatched "EngineVersion" setting. + +* Deprecated shared pointer typedef from ImageWrapper and removed usages. + +* Removed boilerplate header from ImageWrapper. + +* Removed monolithic boilerplate header from NetworkFileSystem. + +* Removed boilerplate header from LauncherCheck. + +* LauncherServices:Removed boilerplate header from LauncherServices. + +* Completed a modernization pass of Automation. + +#### Rendering + +* New:Added thickness option to debug DrawWireDiamond function. + +* New:Added a check to see if there are duplicated shader type names. + +* Bugfix:Fixed obscure check with flushing RHI resources. + +* Bugfix:Fixed hazard with SetMaterialUsage from a thread. + +* Bugfix:Fixed Windows handling of -sm4 and -sm5 so it can be used with -vulkan and -opengl. + +* Bugfix:Fixed selection of swapchain format for Vulkan on some Linux drivers. + +* Bugfix:Fixed an issue on Vulkan when copying into a cubemap face. + +* Bugfix:Fixed a bug calculating vertex declaration hashes on OpenGL. + +* Moved FPositionVertexBuffer & FStaticMeshVertexDataInterface declarations into their own headers, moved FStaticMeshVertexBuffer implementation into its own source file. + +* Updated Vulkan distributables and glslang to SDK 1.0.39.1. + +* Vulkan shaders now build using glslang 1.0.42.2 and includes those headers for redistribution. + +* Prefer D32_S8 on Vulkan instead of D24_S8 for the depth buffer. + +* Removed the temporary functions RHIClearColorTexture, RHIClearDepthStencilTexture and RHIClearColorTextures from each RHI. + +* Separated depth/stencil load/store actions. + +* Use the latest SDK for Vulkan, whether the one we distribute in ThirdParty or an installed version. + +* Implemented SetStencilRef() and SetBlendFactor() on RHIs which were missing it. + +#### UI + +##### Slate + +* Updated Slate to allocate widgets using MakeShared. + + * This saves one allocation per-widget. + +* Moved SVirtualWindow into Slate module from UMG. + +#### VR + +* New:Added an initial base implementation of IHeadMountedDisplay, FHeadMountedDisplayBase, that can be extended by HMD implementations instead of extending IHeadMountedDisplay directly.This base class provides default and or common implementations for parts of the IHeadMountedDisplay interface.Future releases may add more common functionality to this class, reducing the amount of work required to add support for new HMD platforms even further. + +* StereoLayers now have a default emulated implementation, making them supported on most VR platforms that did not already support them.HMD implementations that extend FHeadMountedDisplayBase will automatically inherit the functionality unless explicitly overridden. + +* Common code found in various HMD plugins handling management of StereoLayers has been extracted into a template base class, TStereoLayerManager, that provides a thread-safe way to manage a list of registered stereo layers. + +* The old Morpheus StereoLayers implementation has been removed in favor of the common stereo layers implementation provided by the HMD base class. + +## Upgrade Notes + +#### C++ API Changes + +* As part of the Asset Manager changes, Streamable Manager has been improved to support the concept of Streamable Handles.When requesting an async load, it now returns a shared pointer handle that will keep the requested object loaded as long as it exists.These handles can also be polled or waited on. + + * Synchronous Load and Simple Async Load on Streamable Manager have been deprecated in favor of the new Streamable Handle system.Both of those functions would keep assets loaded until explicitly unloaded, which in practice was not what most people wanted. + +* The Class/Property/Function redirect system has been rewritten to be faster and more flexible.Ini redirects such as "+ActiveClassRedirects" defined in [/Script/Engine.Engine] will still work, but the new system is used by putting redirects like “+ClassRedirects” in the [CoreRedirects] section of Engine.ini. + + * All engine redirects prior to 4.10 have been moved to CoreRedirects.cpp, newer redirects are now in the new format in BaseEngine.ini. + + * A single Property/Function redirect definition will now be applied for both blueprints and serialization, and redirects can now be defined with wildcard matching syntax to simplify large refactors. + + * Object and Package redirects can now be used to allow limited redirection of content references without creating an Object Redirector on disk. + + * Enum redirects have been improved and will now fully work with or without the Enum Name being specified. + +* Several Enum functions dealing with string conversion have been deprecated, and the names and comments have been cleaned up to make it more clear which are meant to be used at Runtime and which are meant to be used in the Editor/for debugging. + +* The console command "r.MSAACount 1" now produces no MSAA or TAA. “r.MSAACount 0” can be used to toggle TAA on for comparisons. + +* Cascaded Shadow Map resolution is now controlled by the console command "r.Shadow.MaxCSMResolution" instead of “r.Shadow.MaxResolution”. + +* New mobile targeted projects will have better UI performance settings by default. + + * Please enable "Explicit Canvas Child Z Order" option in project Slate Settings, to improve UI batching.Enabling this option may require manual Z Order tweaks in UMG Canvas panels if there Z ordering issues. + +* VR console commands have been rewritten to support autocompletion and inline help strings. + + * The VR console commands have also be renamed and now begin with vr.* + + * The renamed VR commands have backwards compatible aliases, but will print a warning notifying the user about the deprecated functionality. + +* The Exec method in Head Mounted Display has been removed, as all VR console commands now use Auto Console Command or similar to register console commands. + + * HMD implementations relying on having an Exec method now need to provide their own ways of registering console command handlers. + +* Set Visibility and Set Hidden In Game in Scene Component are no longer virtual.Instead override On Visibility Changed or On Hidden In Game Changed to respond to changes to these values. + +* The FBox and FBox2D constructors taking an int32 value have been deprecated as the value of that integer was not being used.The Force Init constructor should be used instead. + + * Replace FBox/FBox2D construction of the form FBox(0) with FBox(ForceInit). + +* The Unreal Header Tool now outputs an error when an Editor-only struct member is exposed to blueprints.This is necessary because packaged builds will crash if a Make/Break node for that struct is executed in a blueprint. + + * Any Blueprint exposed Editor-only struct members must either be made not Editor-only or no longer exposed to blueprints. + +* Post Load Map now provides the loaded World as a parameter to the delegate function.The World will be null if the load failed. + + * All existing functions bound to Post Load Map need to have a World pointer added to their signature. + +* Stop saving raw curve data into animations on cook to save memory/disk space. + + * If you are directly accessing Raw Curve Data on an Anim Sequence, this will no longer work in cooked builds.Animation Asset now provides a virtual function, Get Curve Data, to grab a reference to the correct Curve structure. + +* Removed boilerplate header from Automation Window. + + * The AutomationWindow.h boilerplate header file has been removed.Please replace all includes of AutomationWindow.h with IAutomationWindowModule.h + +* Removed boilerplate header from Automation Controller. + + * The AutomationController.h boilerplate header file has been removed.Instead of AutomationController.h, include the individual interface headers that you actually use.Remove the "Interfaces/" subdirectory from existing interface inclusions. + +* Automation Modernization pass + + * The IAutomationWorkerModule.h has been moved to the module's public root directory.Please remove the relative path from your existing include statements. + +* Removed boilerplate header from LauncherCheck. + + * The LauncherCheck.h boilerplate header file has been removed.Include ILauncherCheckModule.h instead of LauncherCheck.h.Remove "Interfaces/" subdirectory from existing ILauncherCheckModule.h inclusions. + +* Removed boilerplate header from LauncherServices. + + * The LauncherServices.h boilerplate header file has been removed.Instead of including LauncherServices.h, include the ILauncherXXX.h files that you actually use.Remove the "Interfaces/" subdirectory from existing ILauncherXXX.h includes. + +* Deprecated shared pointer typedef and removed usages from ImageWrapper. + + * The IImageWrapperPtr typedef has been deprecated.Please use TSharedPtr instead of IImageWrapperPtr. + +* Removed boilerplate header from ImageWrapper. + + * The ImageWrapper.h boilerplate header file has been removed.Instead of including ImageWrapper.h, include the actual IImageWrapperXXX.h files that you use.Remove the "Interfaces/" subdirectory from existing IImageWrapperXXX.h includes. + +* Removed monolithic boilerplate header from NetworkFileSystem. + + * The NetworkFileServer.h boilerplate header file has been removed.Instead of including NetworkFileServer.h, include the INetworkFileXXX.h headers that you actually use.Remove the "Interfaces/" subdirectory from existing INetworkFileXXX.h includes. + +* Changed default contact-gen method to PCM.This is the default in PhysX 3.4. + + * This may have slight implications on jitter and stability, but should be improved overall.The old behavior is still available (set EnablePCM = false in the project settings). + +* Removed the temporary functions RHIClearColorTexture, RHIClearDepthStencilTexture, and RHIClearColorTextures from each RHI. + +* Removed obsolete SmartCastProperty function. + +* Added a static_assert to prevent the use of TMap keys which do not implement GetTypeHash, as this causes runtime crashes when they are manipulated by a UMapProperty. + + * TMap key types must now implement GetTypeHash.Having GetTypeHash be implemented in a base class or being implicitly convertible to a type which is hashable is not sufficient. + +* Fixed TStructOpsTypeTraits::WithCopy giving different results when the trait is specialized without a WithCopy value from when it isn't specialized at all. + + * TStructOpsTypeTraitsBase has been deprecated. + +* Improved support for TTuple. + + * Tuples have a GetTypeHash function and can be used as a TMap key. + + * Can now be serialized to archives. + + * Can now be compared for equality with operators == and !=. + + * Can now be compared lexicographically with operators <, >, <= and >=. + + * TPair is now an alias for a 2-tuple, which is specialized to have Key and Value fields, but otherwise has the same functionality as all other tuples. + + * Tuple.h is now found in the Core/Public/Templates folder, rather than the Core/Public/Delegates folder. + + * TPairInitializer now converts to TPair, rather than TPair being constructible from TPairInitializer. + +* Removed UnrealCodeAnalyzer. + +* Added a static_assert to ensure that TInlineSetAllocator is instantiated with a power-of-two hash size, as this is a requirement for TSet and TMap. + + * TInlineSetAllocator will no longer compile if the hash size is not a power-of-two. + +* Removed TBoolConstant template. + +* Removed the WITH_HOT_RELOAD_CTORS macro. + +* Removed the UseVTableConstructors .ini option. + +* Removed generated FName variables for UFUNCTIONs. + +* Refactored EvaluateBoneTransforms to prevent usage of skeletal mesh component. + + * Deprecated EvaluateBoneTransforms in favor of new ​EvaluateSkeletalControl_AnyThread. + + * Deprecated skeletal mesh component argument to ConvertCSTransformToBoneSpace and ​ConvertBoneSpaceTransformToCS.Now they just take a transform. + +* Added a new overload for IOnlineSession::FindFriendSession in the session interface that can retrieve sessions for multiple friends. + + * Sending and accepting invites on dedicated servers on Steam is now supported. + + * The FOnFindFriendSessionCompleteDelegate now returns an array of FOnlineSessionSearchResult objects instead of just one. + +* The high level rendering code is now PipelineStateObject aware which will allow us to reduce complexity in the rendering backends of Vulkan, Metal and Dx12 in the future. + + * The loose state setting APIs of the Commandlist have been deprecated, instead the entire pipelinestate has to be set at once. + +* Moved controller connect/disconnect handling to the main thread to fix issues with thread safety for callbacks. + +#### Animation + +* When converting skeletal controls to the newer API, convert EvaluateBoneTransforms to ​EvaluateSkeletalControl_AnyThread.Backwards compatibility will be maintained, however warnings will persist.Any mesh component access should be cached in PreUpdate() as accessing the component is not thread safe. + +* If differences in timing between Maya and UE4 are experienced after importing Alembic files, this has been corrected.The fix requires that any problematic assets be reimported. + +#### Blueprints + +* The ticking behavior of latent actions in components has been changed to match how they behave in actors.When the component ticks, the latent actions will now be processed at the same time, rather than happening later in the frame when latent actions for non-ticking actors and components are processed.This does change behavior, so there is a console variable (t.TickComponentLatentActionsWithTheComponent) that can be used to revert to the older behavior until affected component Blueprints that depended on the old ordering behavior can be fixed up.The cvar should be treated as deprecated, and it will be removed in a future release. + +#### Core + +* To save on memory and disk space the cooked Asset Registry no longer includes Dependency information by default.If you need this information at runtime, enable bSerializeDependencies in the [AssetRegistry] section of BaseEngine.ini. + +* Starting asynchronous loads from within asynchronous loads has always been unsafe, but will now explicitly assert.This can be fixed by not starting asynchronous loads from within PostLoad functions, or deferring your game-specific code for a frame when called from an async callback. + +* Callback functions passed into Request Async Load will now execute on the next frame instead of immediately upon completion of an async load.This behavior is to avoid issues with calling async loads recursively, but if your game depends on this behavior you can restore it to call them immediately by setting the cvar s.StreamableDelegateDelayFrames to 0. + +* There is a new format for defining class/function/property redirects in ini files, check the [CoreRedirects] section of BaseEngine.ini for examples.The older formats will still work but the new format provides additional features and a simpler syntax so you may want to upgrade. + +* Any calls to Smart Cast Property should be replaced with code which explicitly handles the inner property of Array Property. + +* Get Type Hash implementations must now be added to types which are used as TMap keys.If your type defines Get Type Hash in a base class or is hashed via an implicit conversion, these should be fixed by implementing their own function and forwarding the call to the appropriate implementation. + +* Any use of TStructOpsTypeTraitsBase should be replaced with TStructOpsTypeTraitsBase2, where T is the type that the trait is being specialized for. + +* `#include "Delegates/Tuple.h"` should be replaced with `#include "Templates/Tuple.h"`. + +* As TPairInitializer is now convertible to TPair, rather than TPair being constructible from TPairInitializer, types which do not correctly implement copy or move semantics by not inhibiting the compiler defaults may cause a bad state when they are inserted into a TMap or TSet.All types used in UE4 containers should correctly define copy or move semantics. + +* Any dependence on Unreal Code Analyzer should be removed from projects. + +* The explicit usage of TInlineSetAllocator in any TSet and TMap should be updated to ensure that the template arguments provided result in hash sizes which are a power-of-two. + +* TBoolConstant should be replaced with TIntegralConstant. + +* Any use of WITH_HOT_RELOAD_CTORS should be replaced with the assumption that the value is 1. + +* Any use of the Use VTable Constructors .ini option should be replaced with the assumption that the value is true. + +* Use of generated FName variables for UFUNCTIONs (e.g. ENGINE_ReceiveTick) should be replaced with a string literal or a custom static FName variable in your own code: + + * For example: static const FName ENGINE_ReceiveTick = TEXT("ReceiveTick"); + +* If Unreal Header Tool reports an error about a function having a different signature from a base class, it should be fixed to have the same signature, or renamed. + +#### Editor and Tools + +* Exposed Make Property Combo Box in Property Customization Helpers to allow embedding an enum combo box into Struct Customizations. + +* Added Custom Column support to the Asset Picker Config. + +* If you use a protected platform, your project settings will start to be saved under MyGame\Config\Platform\PlatformEngine.ini, instead MyGame\Config\DefaultEngine.ini. + +#### Platforms + +* Made some big Device Profile changes, particularly for the protected platforms.You may need to modify your Device Profiles in similar ways if you are a heavy user of them. + + * Changed the "type" of some DPs from WindowsNoEditor, etc to Windows.It should be a platform, not a random string. + + * With that change, the platform can be used to save out protected platform DP .ini files to subdirectories, maintaining secrecy. + + * When saving DeviceProfiles, you may need to look in a platform subdirectory for the DeviceProfiles.ini file. + + * Added Config/[PlatformName]/ConfidentialPlatform.ini files so that the DP loading code knows to look in their directories for DPs.See the GetConfidentialPlatforms() function in GenericPlatformMisc for more information. + +#### Programming + +* The TargetRules.ShouldUseSharedBuildEnvironment() function has been deprecated.Targets can now specify the build environment they wish to use by setting BuildEnvironment to TargetBuildEnvironment.Default/Shared/Unique in their constructor instead. + +* The constructor for ModuleRules-derived classes in .build.cs files should be updated to take a ReadOnlyTargetRules instance, which should be forwarded to the base class.This class contains the same properties as the previous TargetInfo argument, plus all the target-specific settings previously stored in the global BuildConfiguration and UEBuildConfiguration classes.Compatibility shims for accessing these objects will be removed in a future release.The WITH_FORWARDED_MODULE_RULES_CTOR preprocessor definition is now defined, which allows writing code which is compatible with multiple engine versions. + +* The TargetRules.SetupBinaries() callback has been deprecated.Instead of overriding this, targets may override the launch module through the "LaunchModuleName" property in their constructor, and add extra modules to the "ExtraModuleNames" field on the TargetRules object itself. + +#### Rendering + +* UE4Editor is whitelisted for Aftermath with latest Nvidia drivers.To whitelist other game executables contact Nvidia. + +* RHICmdList.Clear() methods are now removed; please use RHICmdList.SetRenderTargetsAndClear() or the DrawClearQuad() utility function from ClearQuad.h. + +* The Cross Compiler Tool is now removed from the Engine, it had too many limitations.Use hlslcc.sln or ShaderCompileWorker -directcompile instead. + +* PipelineStateCache.h contains the new replacement interface for BoundShaderStateCache.h.Otherwise, during the Geometry rendering passes the previously introduced Draw Render State is used to collect and set the Blend, Raster, and Depth Stencil State.Commit Graphics Pipeline State will set the PSO for geometry rendering passes.Postprocessing passes or passes which use Globalshaders have to fill out a Graphics Pipeline State Initializer and set this instead. + +* If configuring via .ini files, use the new variable name "ScaleTexturesByGlobalMipBias" where "ScaleTexturesByGlobalMyBias" was used. + +* Mobile:Skylights on mobile projects may need to be recaptured in the editor before packaging. + +* Mobile:Please replace r.TonemapperFilm=1 cvar with r.Mobile.TonemapperFilm=1 in case you want to use new filmic tonemapper on Mobile platforms. + +#### VR + +* PSVR MotionController tracking management system. + + * Blueprint functions added to manage the set of actively motion tracked controllers in MotionTrackedDevice Function Library. + + * You are recommended to disable tracking of all controllers first, and then enable tracking for the controllers you want to have tracked based on user setting, connected controllers, etc.The system keeps a memory of which controllers are set to be tracked even if the controller is disconnected, or not yet connected. + +* Experimental preview of PSVR Social Screen support. + + * The new Morpheus plugin project setting Enable Social Screen Separate Mode must be set to true to use this feature.When that is true additional render and output buffers will be allocated for the Social Screen. + + * Blueprint functions for controlling the feature can be found by searching for 'SocialScreen'. + + * Future work will replace this API with a more flexible cross platform one, and pursue optimizations of SocialScreen output. + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_16/4_16ReleaseNotes.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_16/4_16ReleaseNotes.KOR.udn new file mode 100644 index 000000000000..212a44b41e87 --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_16/4_16ReleaseNotes.KOR.udn @@ -0,0 +1,3906 @@ +INTSourceChangelist:3457153 +Availability:Public +Title: 언리얼 엔진 4.16 릴리즈 노트 +Description: 언리얼 엔진 4.16 릴리즈 노트 +Crumbs:%ROOT%, Engine +Parent:Support/Builds +Order:16 +reference-image: image_18.gif +reference-image: image_28.gif +reference-image: image_31.gif +reference-image: image_35.gif + +![](DOCS_BANNER_416.jpg) + +## 새 소식 + +언리얼 엔진 4.16 에는 흥미로운 **렌더링 및 애니메이션 신기능**, **모바일 및 콘솔 플랫폼 퍼포먼스의 비약적인 향상** 은 물론, **개발자 여러분 삶의 질 향상을 위한 수많은 개선사항** 이 포함되어 있어, 보다 많은 플랫폼에서 부드럽게 실행되는 눈부신 배경이나 매력적인 체험을 더욱 쉽게 만들 수 있습니다. + +배경의 분위기를 한층 강화시킬 수 있는 놀라운 **볼류메트릭 포그** 신기능을 사용하면, 스케일을 키워도 씬 어디서든 일관된 라이팅을 보이는 사실적인 포그 및 스모크 이펙트를 자동으로 렌더링해 줍니다. + +새로운 다이내믹 **라이트웨이트 리짓 바디** 및 **로우 레벨 클로스 시뮬레이션** 툴로 캐릭터에 생명력을 불어넣어 보세요! 애니메이션 모디파이어, 스플라인 IK 솔버, 업데이트된 포즈 드라이버를 비롯한 애니메이션 시스템의 여러 개선사항을 활용하여 동작의 흐름을 보다 세밀하게 제어할 수 있습니다. + +가비지 컬렉션 속도가 **두 배 빨라졌습니다**! UI 렌더링 퍼포먼스와 UMG 위젯 생성 속도가 크게 향상되어 보다 현란한 인터페이스 제작이 가능합니다. **VR 모드**, 애니메이션, 시퀀서, 기타 툴의 인터페이스와 작업방식도 업데이트되어 개발 프로세스 효율성이 크게 높아졌습니다. + +4.16 부터 **Nintendo Switch** 가 완벽 지원되어 실제 제작단계에서 사용할 수 있게 되었습니다! 에픽게임즈는 Nintendo 와의 협업을 통해 공인된 개발자들에게 Nintendo Switch 용 풀 소스 코드를 무료 배포했습니다. 개발 시작을 위한 자세한 내용은 [여기서](http://www.unrealengine.com/blog/launch-your-game-on-the-nintendo-switch-with-unreal-engine-4-16) 확인해 보세요. + +**이제 Xbox One 의 기본 렌더러를 DirectX 12 로 설정**, 해당 플랫폼을 지원하는 엔진 퍼포먼스와 피처 두 마리 토끼를 동시에 잡았습니다. 게다가 HTML5 게임 개발에 WebAssembly 와 WebGL 2 가 지원되기 시작하였으며, 이 부분은 UE4 에서 지속적으로 발전시켜 나갈 것입니다. + +모바일에서는, 이제 안드로이드 가상 키보드가 지원되며, 실행시간 권한 요청 기능을 블루프린트와 코드 양쪽에서 쓸 수 있습니다. 게다가 모바일 앱 실행파일 크기를 한층 더 줄일 수 있게 되었습니다! + +에픽에서 직접 공개한 업데이트 수백종 이외에도, 이번 릴리즈에는 놀라운 언리얼 엔진 개발자 커뮤니티가 GitHub 를 통해 제출한 **개선사항이 160 종** 포함되어 있습니다! 언리얼 엔진 4.16 에 기여해 주신 분들께 감사드립니다: + +0lento, Akihiro Kayama (kayama-shift), Alice Robinson (Valkrysa), Altrue, Andreas Rønning (Sunjammer), Andrew Gaubatz (e-agaubatz), Angus Jones (crumblycake), Artem V. Navrotskiy (bozaro), Black Phoenix (PhoenixBlack), Cedric Neukirchen (eXifreXi), Cengiz Terzibas (yaakuro), Chris Varnz (chrisvarns), Christopher P. Yarger (cpyarger), Damian Nowakowski (zompi2), DarkSlot, DeanoC, Derek van Vliet (derekvanvliet), devbm, dodgyville, drelidan7, Gabriel Lima (Gabriel-Lima-O), Gyeonghwan (conquests), Hao Wang (haowang1013), Ilya (ill), Jackblue (JohnsonJackblue), James Horsley (mmdanggg2), Jeff Rous (JeffRous), Jon Watte (jwatte), Jørgen P. Tjernø (jorgenpt), jostster, Kalle Hamalainen (kallehamalainen), katze7514, Kevin Kuegler (FrostByteGER), KrisRedbeard, looterz, Manmohan Bishnoi (manmohanbishnoi), Marat Radchenko (slonopotamus), Markyroson, Martin Treacy-Schwartz (the1schwartz), Matt Edmonds (cleaver404), Matthew Casey (mdcasey), Matthias (haimat), Matthias Holzl (hoelzl), Matthias Huerbe (MatzeOGH), Michael Schoell (MichaelSchoell), Michał Siejak (Nadrin), Milan ??astny (aknarts), Moritz Wundke (moritz-wundke), Mustafa TOP (MSTF), Narendra Umate (ardneran), Nathan Stocks (CleanCut), NaturalMotionTechnology, Nick Verenik (nverenik), Paul Murray (awesomeness872), pfontain, Phil Christensen (Rastaban), PrimalJohnScott, projectgheist, Rafael Ortis (rafortis), Rajko Stojadinovic (rajkosto), Rama (EverNewJoy), rhughesgeomerics, Ricardo Rodrigues (RicardoEPRodrigues), Robert Hagglund (hagglund), Robert Segal (robertfsegal), Ryan Pavlik (rpav), sangpan, Sanjay Nambiar (sanjay-nambiar), Satheesh (ryanjon2040), Sean Campbell (scampVR), Sebastian Axinte (ENiGMA9), Sebastien Rombauts (SRombauts), SiebenCorgie, Stefan Zimecki (stefanzimecki), StefanoProsperi, Stephen Johnson (megasjay), TaeYoung Cho (valval88), Timothee Besset (TTimo), Timothy Hagberg (thagberg), Tom Kneiphof (tomix1024), Tom Ward (tomwardio), TRS-justing, unwitherer, Vladimir (VladimirPobedinskiy), Vladimir Alyamkin (ufna), wyhily2010, Yaroslav Shmelev (SoulSharer), yeonseok-yi + +## 주요 기능 + +### 신규: 볼류메트릭 포그 + +새로운 Volumetric Fog (볼류메트릭 포그) 기능으로 환경에 놀라운 배경 효과와 분위기를 연출해 보세요! 다양한 농도 설정이 지원되어 빛줄기 사이로 흐르는 먼지나 연기 구름 시뮬레이션이 가능하며, 이 볼류메트릭 포그에는 다수의 라이트가 동시에 영향을 줄 수 있습니다. + +![image alt text](image_0.png)(w:929 h:529 convert:false) + +![image alt text](image_1.png)(w:928 h:510 convert:false) + +![image alt text](image_2.png)(w:928 h:510 convert:false) + +볼류메트릭 포그가 받을 수 있는 라이팅은 다음과 같습니다: + +* 단일 디렉셔널 라이트, 캐스케이드 섀도우 맵의 섀도잉 또는 스태틱 섀도잉, 라이트 함수. + +* 다수 포인트 및 스포트 라이트, Cast Volumetric Shadow 옵션이 켜진 경우 다이내믹 또는 스태틱 섀도잉. + +* 단일 스카이라이트, 섀도잉은 Distance Field Ambient Occlusion 이 켜진 경우. + +* 파티클 라이트, 'Volumetric Scattering Intensity' 값이 0 보다 큰 경우. + +파티클 시스템에 적용된 머티리얼을 사용하여 새로운 Volume Domain 세팅으로 볼류메트릭 포그를 제어할 수 있습니다. 볼륨 머티리얼이 있는 파티클 하나로 볼류메트릭 포그에 일정 농도의 구체를 추가시킬 수 있습니다. 이 효과는 빌보드와 상관 없는 풀 3D 입니다. 다수의 구체 포그 파티클에 텍스처의 노이즈를 적용하여 사용하면 포그를 특정 영역에 제한시킬 수 있습니다. + +볼류메트릭 포그 구성 관련 정보는 [문서](Engine/Rendering/LightingAndShadows/VolumetricFog) 를 참고하세요. + +### 신규: 블룸에 이미지 기반 (FFT) 컨볼루션 + +새로운 이미지 기반 (FFT) 컨볼루션(합성곱) 기능으로 물리 법칙에 맞는 사실적인 블룸 포스트 프로세스 이펙트를 만들 수 있습니다! 언리얼 엔진 4.16 에 포함된 FFT 블룸 기능으로, 아티스트는 커스텀 블룸 커널 모양을 사용할 수 있을 뿐 아니라, 원하는 결과를 낼 수 있도록 그 세기도 완벽히 제어할 수 있습니다. + +![image alt text](image_3.png)(w:928 h:485 convert:false) + +소스 이미지의 수학 컨볼루션 연산에 커널 이미지를 사용하는 이 블룸 기법을 통해, 별모양 광채에서부터 일정 구역의 디퓨즈 글로우에 이르기까지 다양한 반응 연속체 효과를 낼 수 있습니다. 이미지 기반 컨볼루션으로 사실감을 더할 수 있는 것은, 시각적으로 흥미로운 비대칭 커널 이미지를 사용할 수 있기 때문입니다. 보통은 방사형으로 퍼지는 별모양 광채같아 보이지만, 속눈썹 실루엣, 보케, 기타 부작용같은 모양을 포함시킬 수도 있습니다. + +주: 이미지 기반 컨볼루션 블룸은 시네마틱이나 고사양 하드웨어용으로, 대부분의 게임에서는 기존 (표준) 블룸이 적합할 것입니다. + +### 신규: 디스턴스 필드 라이팅 최적화 + +**디스턴스 필드 앰비언트 오클루전** 및 **레이 트레이스드 디스턴스 필드 섀도우** 가 현 세대 콘솔과 중간 사양 PC 에서 **30-50% 빨라졌습니다**! 씬에 보다 사실적인 앰비언트 라이팅과 다이내믹 메시에 에리어 섀도우를 드리울 수 있도록 해주는 기능입니다. + +![image alt text](image_4.png)(w:929 h:513 convert:false) + +게다가, Intel 의 Embree 레이 트레이싱 라이브러리를 사용하여 **메시 디스턴스 필드 생성 시간도 2.5 배 빨라졌습니다**. 프로젝트 세팅 중 Eight Bit Mesh Distance Fields (8비트 메시 디스턴스 필드) 및 Compress Mesh Distance Fields (메시 디스턴스 필드 압축) 옵션을 사용하면 메모리 사용량 역시 크게 감소합니다. + +### 신규: 라이트웨이트 리짓 바디 시뮬레이션 + +새로운 **라이트웨이트 리짓 바디 캐릭터 시뮬레이션** 으로 물리 시뮬레이션 캐릭터 군단을 만들 수 있습니다! 이제 새로운 고성능 **즉시 모드** PhysX API 로 애니메이션 블루프린트 안에서 피직스 애셋 시뮬레이션이 가능합니다. 이 시뮬레이션을 사용하는 캐릭터는 월드의 스태틱 지오메트리와의 콜리전 생성도 가능합니다. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + VaxxVsv0Fak + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +### 신규: 로우 레벨 클로딩 시뮬레이션 + +Nvidia 의 새로운 로우 레벨 NvCloth 클로딩 솔버를 사용하여 보다 세밀한 클로딩 시뮬레이션 제어가 가능합니다! + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 5BqodzWZIUA + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +기존 APEX 클로딩 솔버를 보다 낮은 수준에서 동작하는 솔루션인 Nvidia 의 NvCloth 로 대체했습니다. 이 새로운 솔버는 작동방식에 약간의 차이를 제외하고 기존 APEX 솔루션의 코어 솔버와 비슷하지만, 시뮬레이션 데이터에 더욱 쉽게 접근할 수 있고 관성 세팅에 몇 가지 추가 파라미터가 노출되어 있습니다. + +### 신규: Nintendo Switch 게임 출시 지원! + +등록한 개발자들은 이제 Nitendo Switch 용 게임 제작 및 출시가 가능합니다! 언리얼 엔진 4 는 Nintendo Switch 검증 사항을 준수하며, 네트워크 멀티플레이어 게임은 물론, 디퍼드 / 모바일 포워드 / 클러스터드 포워드와 같은 멀티 렌더링 파이프라인 접근도 지원하여, 사실상 어떤 유형의 게임도 쉽게 제작할 수 있습니다. + +[REGION:raw] +![image alt text](image_7.png)(w:925 h:641 convert:false) +[/REGION] + +### 신규: VR 모드 UI 및 인터랙션 업데이트 + +언리얼 에디터의 VR 모드가 대폭 개선되어 보다 직관적인 작업방식과 편집 환경을 제공해 줍니다. + +![image alt text](image_8.jpg)(w:722 h:646 convert:false) + +새로운 비대칭 컨트롤러 셋업으로 한 손에는 새롭게 개선된 원형 메뉴를, 다른 한 손에는 보다 정밀해진 인터랙션 레이저로 레벨의 오브젝트 작업을 빠르고 쉽게 할 수 있습니다. + +모든 주요 에디터 기능과 UI 패널을 포함한 모든 VR 동작을 이제 새로워진 원형 메뉴에서 열어볼 수 있습니다. 텔레포트도 업데이트되어 어느 한 위치로 순간 이동한 뒤 기본 스케일로 크기를 조정하여 플레이어 관점에서 확인할 수 있도록 하기도 했습니다. 자세한 정보는 [관련 문서](Engine/Editor/VR/GDC2017) 를 참고하세요. + +### 신규: VR 에서 시퀀스 편집 + +시퀀서 시네마틱 에디터를 이제 VR 에서 사용할 수 있습니다! 새 시퀀스 생성, 레벨에서 오브젝트 이동 작업을 하면, 그 트랜스폼에 대한 시퀀스 키를 자동 생성해 줍니다. 타임라인 스크러빙 후 이 키를 설정하는 것으로, 시네마틱 시퀀스를 만들고 재생하는 작업을 VR 안에서 모두 해낼 수 있습니다. 시퀀서 UI 나 원형 메뉴를 통해서도 기존 레벨 시퀀스를 열거나 재생할 수 있습니다. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + X4Zw9U20Gw4 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +* 신규! 키 조정을 통해 월드의 궤도를 물리적으로 조절할 수 있습니다. + +* 원형 메뉴의 Scrub Time (시간 스크럽) 옵션을 통해 썸스틱이나 터치패드 입력으로 시퀀스 재생 방향과 속도를 정할 수 있습니다. 트리거를 다시 한 번 누르면 시간 스크럽 모드를 빠져나갑니다. + +### 신규: VR 모드 피직스 시뮬레이션 + +이제 **VR 모드에서** 모션 컨트롤러로 레벨의 오브젝트와 상호작용하면서 **피직스 시뮬레이션 적용** 이 가능합니다! 피직스 시뮬레이션 설정된 액터를 배치한 뒤 물리 시뮬레이션을 통해 액터가 사실적으로 퍼지도록 하거나, 모션 컨트롤러로 건드리거나 하면 됩니다. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + bG2Qf897CBI + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +### 신규: VR 모드 스마트 스내핑 + +스마트 스내핑은 오브젝트의 바운드를 사용하여 씬의 다른 액터와 줄을 맞춰주는 기능으로, 미리 그리드를 신경쓸 필요 없이 모듈식 애셋 제작을 할 수 있습니다. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + lvqxM1kjubE + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +이 기능은 현재 VR 모드에서만 가능하나, 앞으로 데스크탑 편집도 지원할 계획입니다. + +### 신규: Xbox One 기본 렌더러 DirectX 12 + +**DirectX 12 가 Xbox One 의 기본 렌더러가 되었습니다**! DirectX 12 에 가한 여러가지 안전성 및 퍼포먼스 개선사항 덕에 Xbox One 의 기본 RHI 로 활용하여, **CPU 및 GPU 퍼포먼스 향상** 효과를 누릴 수 있게 되었습니다. + +![image alt text](image_12.png)(w:556 h:356 convert:false) + +#### D3D11 로 돌아가기 + +D3D11 로 돌아갈 필요가 있는 타이틀의 경우 그 방법은 다음과 같습니다: + +1. 타이틀 defaultengine.ini 에서 bBuildForD3D12 옵션을 변경합니다. + +2. 게임을 Xbox One 용으로 다시 빌드합니다. + +3. 콘텐츠를 다시 쿠킹합니다. + +**주:** D3D11 RHI 는 앞으로 폐기될 예정입니다. + +### 신규: WebAssembly 및 WebGL 2 용 HTML5 지원 + +언리얼 엔진 4 가 이제 HTML5 의 새로운 WebAssembly 표준(다른 명칭으로는 WASM)을 지원하여, 웹에서도 C++ 코드를 가장 빠르고 효율적으로 컴파일하고 실행할 수 있게 되었습니다! Mozilla 의 최신 (v1.37.9) Emscripten 툴체인을 사용하고 있습니다. 이 기능은 아직 모든 브라우저에 지원되지 않는 신기술이라 얼리 액세스 기능으로 간주되고 있으며, GitHub 접근 권한이 필요합니다. + +[REGION:raw] +![image alt text](image_13.png)(w:929 h:630 convert:false) +[/REGION] + +WASM 은 웹 앱에 사용되는 새로운 JavaScript 코드-투-바이너리 포맷으로, 앱 다운로드 크기와 시작 시간 및 메모리 소모량을 감소시켜 퍼포먼스를 크게 향상시켜 줍니다. WASM 및 브라우저 지원 관련 자세한 내용은 http://webassembly.org/ 페이지를 참고하세요. + +UE 4.16 에는 OpenGL ES 3.0 기반 WebGL 2.0 지원도 추가되어 한 층 높은 렌더링 퍼포먼스 최적화와 시각 충실도 향상과 아울러 다음과 같은 렌더링 기능도 추가로 지원합니다: + +* UE4 고사양 모바일 피처 레벨 대부분의 기능 + +* 파티클과 폴리지에 인스턴스드 지오메트리 드로잉 + +* 멀티 렌더 타겟(MRT) 지원 + +* 3D 또는 볼륨 텍스처, 2D 배열 텍스처와 같은 텍스처 기능, 2 제곱 텍스처 금지 제약 없음 + +WASM 및 WebGL 2.0 은 (64 비트 추천) Firefox 52 와 Chrome 57 버전 이상에서 지원됩니다. 윈도우 상의 Chrome 58 버전에서 일부분 메모리 부족 오류를 유발하는 버그가 보이고 있습니다. 구글과의 협업으로 이슈 해결중입니다. [UE-44727](https://issues.unrealengine.com/issue/UE-44727) 에서 그 현황을 확인하실 수 있습니다. + +HTML5 프로젝트 세팅의 Emscripten 부분에서 이 옵션을 변경할 수 있습니다. 가급적 폭넓은 브라우저 지원을 위해서라면 아직은 ASM.js 와 WebGL 1 을 사용하세요. *하지만 ASM.js 및 WebGL 1 지원은 앞으로 나올 엔진 버전에서 폐기 상태에 접어든 이후 제거될 것입니다 (정확한 시기는 브라우저 추가 지원에 따라 달라집니다).* + +Firefox 또는 Chrome (위 지원 버전) 브라우저에서 [HTML5 에서 실행되는 Zen Garden 데모](https://hacks.mozilla.org/2017/03/firefox-52-introducing-web-assembly-css-grid-and-the-grid-inspector/) 를 통해 직접 확인하실 수 있습니다. + +### 신규: 가비지 컬렉션 속도 2 배 향상 + +가비지 컬렉션 퍼포먼스가 크게 향상되어 이제 **두 배 이상 빨라졌습니다**! 구체적인 개선사항은 다음과 같습니다: + +* 도달가능성 분석 멀티스레딩 작업을 새롭게 디자인하여 태스크 관리 비용을 감소시켰습니다. + +* 가비지 컬렉션 클러스터 작업이 블루프린트 생성 클래스 및 선택된 액터 유형을 지원합니다. + +* UObject 언해시 코드 최적화를 통해 액터 소멸에 걸리는 시간을 단축시켰습니다. + +### 신규: 시뮬레이팅 부모 포함 키네마틱 바디 + +시뮬레이션 부모를 포함한 키네마틱 피직스 바디를 만들 수 있는 기능을 추가했습니다. 이제 캐릭터의 손과 같은 자손 본은 순수히 애니메이션 데이터로 구동시키면서, 그 본의 부모 역시도 피직스 시뮬레이션 데이터로 구동되도록 만들 수 있습니다. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + qiiOU_fhex0 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +플레이어가 턱을 오르면서 낙석이 바디에 충돌하는 경우 그에 반응하도록 하는 등의 멋진 이펙트를 만들 수 있습니다. + +### 신규: 플랫폼 SDK 업그레이드 + +매 번 릴리즈마다 플랫폼 파트너사의 최신 SDK 버전을 지원할 수 있도록 엔진을 업그레이드하고 있습니다. + +[REGION:raw] +![image alt text](image_15.jpg)(w:929 h:522 convert:false) +[/REGION] + +* **Visual Studio:** 중요: Visual Studio 2013 은 윈도우에서 이번 릴리즈에 더이상 지원되지 않습니다. Visual Studio 2015 또는 Visual Studio 2017 로 업그레이드해 주세요. + +* **Nintendo Switch:** Nintendo SDK 1.3.1 을 지원합니다. + +* **Xbox One:** October 2016 QFE3 XDK 버전 대상으로 빌드했습니다. + +* **PlayStation 4:** PSR SDK 4.508.001 SDK 로 업그레이드했습니다. + +* **Android:** Updated CodeWorks for Android 1R6u1 + +* **GoogleVR:** 플러그인 1.3 버전으로 업그레이드했습니다. + +* **GoogleVR:** SDK 1.40.0 버전으로 업데이트했습니다. + +* **GoogleVR:** Mode 기본값이 Daydream & Cardboard 로 변경되었습니다. + +* **Vulkan:** 배포 파일과 glslang 을 SDK 1.0.39.1 로 업그레이드했습니다. + +### 신규: 시퀀서 샷 트랙 개선 + +시퀀서의 샷 트랙이 시네마틱 및 영화 제작에도 유용하도록 여러모로 개선되었습니다! + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + GqfJxD1DY8I + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +* **샷 별 계층형 바이어스** - 기본적으로 레벨 시퀀스 계층구조 내 하위 레벨의 트랙이 우선권을 갖습니다. 이를 통해 영화 제작자는 자신에게 익숙한 파이프라인을 만들어, 샷에서 수정을 가하면 그것이 들어있는 시퀀스의 트랙을 덮어쓰도록 할 수 있습니다. + +* **모든 트랙에 When Finished 프로퍼티 노출** - 애니메이션 이전 상태의 값으로 되돌릴지 아니면 시퀀스 종료 상태의 값을 유지할지를 트랙에 지정할 수 있습니다. 영화 제작 환경에서는 보통 샷에서 애니메이션이 적용된 값을 애니메이션 전 상태로 되돌려 다음 샷으로 새어나가지 않도록 합니다. 시네마틱에서는 값을 유지시켜 시퀀서 애니메이션 상태에서부터 게임을 계속할 수 있도록 하는 것이 좋을 것입니다. + +* **프리/포스트 롤** - 이제 모든 트랙에 프리 / 포스트 롤이 일반적인 개념이 되었습니다. 어떤 트랙에는 그에 맞는 작동방식이 있을텐데, 예를 들어 카메라 컷 트랙은 프리 롤 평가 기간의 카메라 컷 예상 위치를 스트리밍 시스템에 알려주는 것입니다. + +### 신규: 시퀀서에서 머티리얼 파라미터 컬렉션 애니메이션 + +이제 시퀀서에서 머티리얼 파라미터 컬렉션에 대한 애니메이션을 통해, 다수의 머티리얼에서도 레퍼런싱할 수 있는 스칼라 및 벡터 파라미터 애니메이션 완벽 제어가 가능합니다. 더이상 애니메이션 공유를 위해 각 머티리얼 인스턴스마다 별개의 파라미터 값 애니메이션을 줄 필요가 없습니다. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + u_Cpqz7mFuM + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +### 신규: UI 렌더링 퍼포먼스 개선 + +이제 게임에서 Invalidation Panel 을 사용하면 렌더 데이터가 아닌 위젯 엘리먼트만 캐시에 저장하는 옵션으로 텍스처 배치 작업을 향상시켜 드로 콜 수를 크게 줄일 수 있습니다. 모바일 디바이스에서 퍼포먼스가 크게 향상될 것입니다! + +[REGION:asyncgif] +![image alt text](image_18.gif)(w:456) +[/REGION] + + +위의 배틀 브레이커스 영웅 선택 UI 에서, 각 영웅의 논리 엘리먼트를 캐시에 저장시켜 함께 배치 처리되도록 할 수 있습니다. 이 모드를 켜는 콘솔 변수는 Slate.CacheRenderData=0 으로, 모바일 디바이스에서는 기본값입니다. + +### 신규: 애니메이션 포즈 드라이버 개선 + +포즈 드라이버 기능 개선을 통해, 본 세트의 포즈를 레퍼런스 '타겟' 세트와 비교하는 식으로 블렌드 셰이프나 본을 절차적으로 구동시킬 수 있게 되었습니다. 어깨처럼 상박과 어깨 포즈에 따라 모프 타겟을 자동 교정하면 좋은 곳에 특히 좋습니다. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + sjtbvyDdW9w + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +* 이제 포즈를 읽어 들일 '입력'으로 다수의 본을 선택할 수 있습니다. + +* 이제 노드가 변경할 본을 선택할 수 있습니다. + +* 각 타겟 가동 방법에 대한 '커스텀 커브' 지정이 가능합니다. + +* 포즈 애셋 필요 없이 (모프, 머티리얼) 커브를 바로 구동시키도록 선택할 수 있습니다. + +* UI 에 타겟 포즈 생성/편집, 타겟 가동 표시 바 등이 개선되었습니다. + +* 뷰포트에서 타겟 위치를 클릭하여 선택할 수 있습니다. + +### 신규: 머티리얼 플래트닝용 오파시티 및 오파티시 마스크 + +블렌드 모드 옵션을 사용하여 머지 액터와 HLOD 로 오파시티 (마스크) 값을 구워내는 기능이 지원됩니다. 결과 (인스턴싱된) 머티리얼은 set blend mode 를 사용하여 올바른 렌더 패스를 따르도록 합니다. 마스크드 머티리얼을 구워낸 예제입니다: + +![image alt text](image_20.png)(w:904 h:740 convert:false) + +### 신규: 메시 페인트 툴 개선 + +메시 페인트 시스템이 대폭 개선되어 사용하기 쉽고 명확해졌으며, 에디터 다른 부분의 기능을 재사용할 수 있게 되었습니다. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + UezYKhase9g + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +또, 스켈레탈 메시에 페인트 툴을 사용할 수 있게 되었습니다. 참고로 페인트는 (스태틱 메시와 마찬가지로) 인스턴스 단위가 아니며 스켈레탈 메시 애셋에 직접 적용됩니다. + +### 신규: 스플라인 IK 솔버 + +캐릭터 스플라인 또는 본 체인 제어에 좋은 Spline IK 노드가 애니메이션 블루프린트에 추가되었습니다! + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + chqOk4QdPR0 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + + +### 신규: 메시 표면의 머티리얼 감지 + +컴포넌트에 추가된 'Get Material From Face Index' (면 인덱스에서 머티리얼 구하기) 함수로 (복합) 라인 트레이스 이후 컴포넌트에 적용된 머티리얼을 구할 수 있습니다. 스태틱 메시, 프로시저럴 메시 컴포넌트, BSP 에 적용됩니다. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + SvsSnkwB1TQ + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +### 신규: 'Look At' 애니메이션 노드 개선 + +이제 Look At 노드의 **Look At Location** 프로퍼티를 본 또는 소켓 기준으로 사용할 수 있습니다. 기존에는 본이나 소켓을 지정해도 이 값을 무시했었습니다. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 3C7Q6JJxmtY + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +Look At 컨트롤에 대한 시각화 역시 개선되었습니다. 예를 들어, 경사 각도, 타겟 위치, 보간 등을 확인할 수 있습니다. + +### 신규: 애니메이션 익스포트 개선 + +스켈레탈 메시에 할당된 포스트 프로세스 그래프에서 생성된 부가 애니메이션 데이터, 이를테면 피직스 시뮬레이션용 애님 다이내믹스같은 것을 포함하는 애니메이션을 만들고 익스포트하는 기능이 지원됩니다. + +이 부가 데이터를 포함시키려면, 애니메이션 생성 또는 애니메이션 익스포트 에서 **프리뷰 메시** 를 선택하면 됩니다. + +![image alt text](image_25.png)(w:697 h:256 convert:false) + +### 신규: 언리얼 오디오 엔진 (얼리 액세스 프리뷰) + +GDC 에서 발표된 새로운 언리얼 오디오 엔진이 PC, Mac, iOS, Android, Switch 에서 얼리 액세스로 접할 수 있습니다. 새로운 멀티플랫폼 EQ 및 Reverb 마스터 이펙트와 함께, 기존 오디오 엔진 피처 세트 하위 호환이 완벽 지원되는 멀티 플랫폼 오디오 믹서가 포함되어 있습니다. 추가로, 새로운 언리얼 오디오 엔진에는 서브믹스 그래프, 서브믹스 이펙트, 소스 이펙트, 실시간 합성, 오디오 플러그인 지원 강화 등의 새로운 기능이 도입되어 있습니다. + +새로운 언리얼 오디오 엔진은 4.16 에 기본으로 켜져있지 않은데, 콘솔 플랫폼, 리눅스, HTML5 용 백엔드 구현과 아울러 특히나 모바일 플랫폼에서의 안전성과 퍼포먼스 향상을 위한 작업이 계속 이루어지고 있기 때문입니다. + +오디오 믹서를 켜려면, "-audiomixer" 명령줄 인수를 붙여주면 됩니다. + +주: 대부분의 언리얼 오디오 엔진 신기능은 오디오 믹서를 켜지 않고 에디터를 실행시키면 숨겨져 있습니다. + +### 신규: Synthesis 플러그인 (얼리 액세스) + +새로운 synthesis 플러그인에는 두 가지 새로운 리얼타임 신디사이저가 들어있습니다. 하나는 새로운 언리얼 오디오 엔진의 "SynthComponent" 클래스를 사용하여 구현한 완전판 서브트랙티브 신디사이저(감산 합성)이고, 다른 하나는 리얼타임 그래뉼레이터입니다. 새 신디사이저는 절차적인 음악이나 사운드 디자인에 유용한 툴일 뿐 아니라, 써드 파티 플러그인 제조사나 심지어 사운드 디자이너도 자신만의 신디사이저를 구현하기 위해 참고할 수 있는 예제 역할을 하기도 합니다. + +synthesis 플러그인에는 새로운 언리얼 오디오 엔진에서 사용할 수 있는 DSP 소스 및 서브믹스 이펙트 호스트도 들어있습니다: + +* **소스 이펙트:** 스테레오 딜레이, 비트 크러셔, 다이내믹스 프로세서, 엔벨롭 팔로워, EQ 필터, 버추얼 아날로그 필터 (래더/스테이트 베리어블), 웨이브 셰이퍼, 코러스, 페이저 + +* **서브믹스 이펙트:** 리버브, EQ, 다이내믹스 프로세서 + +### 신규: Steam Audio (얼리 액세스) + +에픽과 Valve 가 팀을 이뤄 새로운 언리얼 오디오 엔진의 신기능을 활용하여 처음으로 완벽 통합 구현한 Steam Audio SDK 를 발매했습니다. + +![image alt text](image_26.png)(w:600 h:160 convert:false) + +Steam Audio 는 새로운 언리얼 오디오 엔진의 공간화, 오클루전, 리버브 시스템과 근본적인 수준에서 통합되어 UE4 의 VR 을 위한 차세대 물리 기반 오디오 체험을 선사할 수 있습니다. 이번 버전은 Steam Audio 얼리 액세스 버전이며, 4.17 에 중요 업데이트, 추가 예제 프로젝트, 작업방식 개선사항이 계획되어 있습니다. 개선을 위한 피드백, 질문, 아이디어는 언제든 환영입니다. + +Steam Audio 관련 자세한 정보, 문서, 기술지원 도움말은 [https://valvesoftware.github.io/steam-audio/](https://valvesoftware.github.io/steam-audio/) 페이지를 참고하세요. + +### 신규: 컬러 그레이딩 툴 개선 + +컬러 그레이딩 유저 인터페이스가 사용하기 쉽도록 개선되었습니다! + +![image alt text](image_27.jpg)(w:529 h:257 convert:false) + +* 새로운 HSV 모드가 추가되었습니다. + +* Ctrl+슬라이더 드래그로 유형에 따라 최소/최대값을 동적으로 변경할 수 있습니다. + +* 새로 추가된 리셋 버튼으로 전체 컬러 그레이딩 카테고리를 리셋시킬 수 있습니다 (예: 글로벌, 섀도우, 미드톤, 하이라이트). + +### 신규: 애니메이션 블렌드 스페이스 에디터 개선 + +이제 블렌드 스페이스 에디터에서 그리드 안의 **Show Animation Names** (애니메이션 이름 표시) 버튼으로 각 샘플의 애니메이션 이름을 표시할 수 있습니다. 이제 기존 애니메이션 위에 새 애니메이션을 끌어 놓아 대체할 수도 있습니다. + +[REGION:asyncgif] +![image alt text](image_28.gif)(w:905) +[/REGION] + +### 신규: 현지화용 스트링 테이블 + +UE4 에 이제 현지화 스트링 테이블이 지원됩니다! + +![image alt text](image_29.png)(w:601 h:218 convert:false) + +스트링 테이블은 현지화 텍스트를 하나( 또는 여러 개)의 알려진 위치에 몰아두고 스티링 테이블 안의 항목을 다른 애셋이나 코드에서 안정적인 방식으로 레퍼런싱하여 현지화 텍스트를 쉽게 재사용할 수 있습니다. 스트링 테이블은 C++ 에서 정의하거나, CSV 파일을 통해 로드하거나, 애셋으로 생성할 수 있습니다. + +### 신규: 애니메이션 모디파이어 (얼리 액세스 프리뷰) + +애니메이션 모디파이어는 주어진 애니메이션 시퀀스 또는 스켈레톤에 액션 시퀀스를 적용할 수 있습니다. 이를테면 오른발이 바닥에 오는 것이 몇 프레임인지 정확히 지정한 뒤, ball_r 본이 최저점에 오는 (바닥에 닿는) 프레임에 애니메이션 싱크 마커를 추가하는 것입니다. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + YC_UJuO9AI8 + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +새로운 함수 세트로 애니메이션 블루프린트 함수 라이브러리에 사용할 수 있는 특정 애니메이션 데이터를 접근할 수 있습니다. 애니메이션 모디파이어 접근 및 적용은 스켈레톤 에디터와 애니메이션 에디터에서 찾을 수 있는 새 탭에서 이루어집니다. 애니메이션 모디파이어는 스켈레톤 또는 애니메이션 시퀀스에 추가할 수 있습니다. 애니메이션 시퀀스의 경우, 애니메이션 모디파이어는 시퀀스 자체에만 적용됩니다. 스켈레톤에 적용하면, 그 스켈레톤을 기반으로 한 모든 애니메이션 시퀀스에 적용됩니다. + +### 신규: 안드로이드 가상 키보드 (얼리 액세스 프리뷰) + +이제 팝업 입력 대화창 대신 안드로이드 운영 체제의 가상 키보드를 지원합니다! + +[REGION:asyncgif] +![image alt text](image_31.gif)(w:256) +[/REGION] + + +가상 키보드 활성화는 **프로젝트 세팅 > 플랫폼 > Android > APK Packaging** 아래 옵션을 체크하면 됩니다. 이 옵션은 가상 키보드 기본 지원을 활성화시키지만, 입력 요소가 보이면서 가상 키보드 뒤에 가리지 않도록 하기 위해서는 제공된 OnVirtualKeyboardShown 와 OnVirtualKeyboardHidden 이벤트 핸들러를 앱에서 사용해 줘야 합니다. + +**주:** 사용자 언어가 IME 를 필요로 하는 경우 Android.NewKeyboard 콘솔 명령으로 가상 키보드를 끄는 것이 나을 수 있습니다. + +### 안드로이드 실행시간 권한 요청 지원 + +이제 언리얼 엔진 4 에 안드로이드 23 이상에서 필요로 하는 런타임 퍼미션을 지원합니다. 여기에는 연락처, 사진, 폰 상태, 외부 저장장치, 카메라, 위치 서비스에 대한 접근이 포함됩니다. 자세한 내용은 다음 웹페이지를 참고하세요: [https://developer.android.com/guide/topics/permissions/requesting.html](https://developer.android.com/guide/topics/permissions/requesting.html). + +안드로이드 23 을 타겟으로 삼는 경우, Android Runtimes Permission 플러그인에 네이티브 코드나 Check Android Permission 블루프린트 노드를 사용하여 권한이 이미 부여되었는지 검사하는 기능이 제공됩니다. 권한이 아직 부여되지 않은 경우, 앱에서는 Request Android Permissions 블루프린트 노드를 사용하여 사용자에게 요청한 뒤, On Permissions Granted Dynamic 델리게이트에 바인딩된 이벤트를 사용하여 결과를 구할 수 있습니다. 그러면 게임이 권한이 필요한 기능을 사용하기 직전에 권한을 요청하도록 하여, 사용자 경험 향상에 도움이 됩니다. 안드로이드 23 이전 버전을 타겟으로 삼는 경우, 예전처럼 Android Manifest 에 지정하여 권한을 부여해야 합니다. + +![image alt text](image_32.png)(w:718 h:346 convert:false) + +**주:** 4.16 은 Android SDK 23 이상이 설치되어 있어야 합니다. 기존 버전을 사용하시는 경우 SDK 매니저를 사용하여 안드로이드의 Upgrade Note 부분 안내에 따라 설치해 주시기 바랍니다. 또한 Android SDK 프로젝트 세팅에서, Android SDK API Level 을 "matchndk" 에서 "latest" 으로 변경해 주세요. 그러면 Android SDK 플랫폼 디렉토리에 설치된 최신 SDK 를 사용합니다. NDK API Level 은 변경할 필요 없습니다. Lollipop (Android 5.0) 이전 버전 안드로이드에 APK 를 설치할 수 있도록 하려면 "android-19" 가 맞습니다. 이 값을 높여 설정하면 Android 5.0 이상이 필요합니다. + +### 패키지 크기 감소를 위한 셰이더 코드 라이브러리 + +이제 Share Material Shader Code 프로젝트 세팅으로 모든 셰이더 코드의 공유 저장 위치를 지정할 수 있습니다. 그러면 같은 셰이더 코드를 생성하는 머티리얼 또는 머티리얼 인스턴스에 대해 하나의 사본만 저장하게 됩니다. + +iOS, TVOS, MacOS 의 Metal 에서는 보다 효율적인 플랫폼 전용 셰이더 라이브러리를 지원합니다. Shared Material Native Libraries 프로젝트 세팅을 켜면 이 네이티브 라이브러리 포맷을 활용하여 패키지 크기가 한 층 더 줄어듭니다. + +### 신규: FBX 에서 캡슐 콜리전 임포트 + +이제 FBX 파일에서, 이미 박스, 구체, 컨벡스 심플 콜리전을 임포트하듯, 캡슐 심플 콜리전을 임포트할 수 있습니다. 캡슐 폴리 메시의 'UCP' 접두사를 사용하면, 임포트할 때 제거되면서 그에 해당하는 캡슐 콜리전 셰이프로 대체됩니다. + +### 신규: 공유 vs 로컬 애셋 뷰어 프로파일용 별도 옵션 + +이제 언리얼 에디터에서 공유 또는 로컬 레벨에 애셋 뷰어 프로파일을 저장, 팀원들과 프로파일 세트를 공유하고, 아트 애셋 감정을 위한 통합 씬으로 사용할 수 있습니다. 로컬 레벨에 프로파일을 저장하면 팀에는 필요치 않지만 개인적으로 선호하는 프로파일 커스텀 세트를 유지할 수 있습니다. 공유 프로파일은 DefaultEditor.ini 에 저장되며, 체크 아웃 또는 쓰기 가능으로 만들어야 합니다. + +### 신규: 애니메이션 프리뷰 씬 개선 + +애니메이션 툴용 프리뷰 씬이 여러모로 개선되었습니다: + +* 프리뷰 씬 세팅이 뷰포트 숨김 메뉴가 아닌 기존 세팅 탭으로 이동되었습니다. 이 세팅 탭은 이제 기본으로 표시됩니다. + +* 메인 툴바에 프리뷰 메시를 빠르게 전환할 수 있는 바로가기가 추가되었습니다. 모든 애니메이션 에디터에 적용됩니다. + +* 프리뷰 씬을 편집할 때, 더이상 여분 메시 미리보기만을 위한 "프리뷰 씬 컬렉션"을 만들 필요가 없습니다. 메시 셋업이 마음에 들면 애셋에 저장할 수도 있습니다. + +### 신규: 애님 뷰어에 기본 카메라 옵션 추가 + +이제 스켈레탈 메시의 '기본 카메라' 위치를 저장할 수 있습니다. 메시를 열 때 사용되며, Shift+F 키를 눌러 점프할 수도 있습니다. + +### 신규: Play Montage 블루프린트 노드 + +Play Montage 는 어느 블루프린트 로직에서도 애님 몽타주 재생에 쓸 수 있는 새로운 비동기 노드입니다. 이를 통해 몇몇 콜백 이벤트에 쉽게 접근할 수 있어, 몽타주가 블렌드 아웃 되거나 중단되는 등의 경우에 다른 노드를 발동시킬 수 있습니다. + +![image alt text](image_33.png)(w:376 h:272 convert:false) + +* OnCompleted 는 몽타주 재생이 완료되고 완전히 블렌드 아웃 되면 호출됩니다. + +* OnBlendOut 는 몽타주가 자동이든 수동이든 중지되어 Blend Out 시작할 때 호출됩니다. + +* OnInterrupted 는 몽타주가 다른 몽타주 재생에 의해 중단되어 Blend Out 시작할 때 호출됩니다. + +* OnNotifyBegin 및 OnNotifyEnd 는 몽타주 애셋에서 Play Montage Notify 나 Play Montage Notify Window 를 사용할 때의 콜백입니다. 이 애님 노티파이들은 Notify Name 을 추가로 붙여 같은 몽타주에서 온 다수의 콜백을 구분할 수도 있습니다. + +### 신규: 포즈 리타겟용 옵션 추가 + +이제 리타겟 베이스 포즈를 설정할 때 사용할 포즈 애셋에서 포즈를 임포트할 수 있습니다. 현재 포즈를 변경 및 저장하고 (Use Current Pose) 본 트랜스폼을 레퍼런스 포즈로 리셋시키는 (Reset) 기존 옵션도 여전히 사용 가능합니다. + +**주:** 애니메이션 에디터에서 포즈 애셋을 생성하고 이름을 할당한 포즈 애셋에 아무 포즈나 삽입할 수 있습니다. + +### 신규: 스태틱 메시 에디터의 콜리전 뷰 옵션 + +스태틱 메시 에디터 툴에 스태틱 메시의 단순 및 복합 콜리전 표시를 위한 별도의 옵션이 생겼습니다. + +### 신규: LOD 에 포즈 굽기 + +이제 언리얼 엔진 4 에 Bake Pose 라는 새로운 감소 세팅을 사용하여 LOD 레벨에 포즈를 구워 넣는 기능이 지원됩니다. 이 세팅을 단일 프레임 애님 시퀀스로 설정하면 결과 LOD 메시에 적용됩니다. 본은 제거하면서 포즈는 계속 유지하고자 할 때 유용하게 쓰일 수 있습니다. + +[OBJECT:EmbeddedVideo] + [PARAMLITERAL:videoid] + 0fcNitNu9FE + [/PARAMLITERAL] + [PARAMLITERAL:width] + 78 + [/PARAMLITERAL] + [PARAMLITERAL:height] + 56.25 + [/PARAMLITERAL] + [PARAMLITERAL:units] + % + [/PARAMLITERAL] + [PARAMLITERAL:type] + simple + [/PARAMLITERAL] +[/OBJECT] + +**주:** 이 기능은 Simplygon 이 필요합니다. + +### 신규: 시퀀서 유저 인터페이스 개선사항 + +이제 오디오 트랙 썸네일에 내부 (스무딩 적용된) RMS 커브로 피크 샘플이 렌더링됩니다. 오디오 트랙 세로 크기조정도 가능합니다! + +[REGION:asyncgif] +![image alt text](image_35.gif)(w:929) +[/REGION] + + +기타 시퀀서 UI 개선사항: + +* 시퀀서 제어 액터는 이제 레벨에 스트림 인 될 때 제대로 틱 됩니다. + +* 이제 이벤트 트랙에 대한 부가 이벤트 리시버 (예: 액터 블루프린트) 지정이 가능합니다. + +* 바인딩이 개선되었습니다. 이제 블루프린트에서 레벨 시퀀스에 대한 바인딩을 드래그/드롭/설정 가능합니다. 예를 들어 블루프린트에서 오브젝트를 스폰하고 그것을 기존 트랙에 할당할 수 있습니다. + +### 신규: 모바일 VR 렌더링 개선 + +GearVR 에 다이렉트 멀티뷰가 지원됩니다. 모바일 멀티뷰를 사용할 때 렌더 타겟을 추가로 사용하지 않고 전체 화면 사본이 필요치 않아 전반적인 퍼포먼스가 향상되고 메모리 사용량이 줄어듭니다. + +이제 GearVR 에서 멀티뷰가 켜진 상태에서는 모노스코픽 파 필드를 사용하여 씬의 스테레오 렌더링 부분의 최적 렌더링이 가능합니다. + +Google Daydream 은 앞으로 나올 버전에서 다이렉트가 지원되는 표준 모바일 멀티뷰를 지원합니다. + +### 신규: Playstation VR 용 소셜 스크린 (얼리 액세스 프리뷰) + +PSVR 소셜 스크린 프리뷰에 소셜 스크린 분리 모드가 지원됩니다. 모니터와 HMD 디스플레이에 다른 것을 표시하는 모드입니다. + +이 프리뷰는 30fps 소셜 스크린 출력을 지원하며, 다수의 출력 모드 전환이 가능합니다. 구현된 샘플 모드는 다음과 같습니다: + +* SystemMirror (항상 있었던 기본 미러링 모드입니다). + +* SeparateTest (소셜 화면의 단순한 흑백 전환입니다). + +* SeparateTexture (블루프린트 지정 텍스처, 예를 들어 씬 캡처 컴포넌트가 쓰고 있는 렌더 타겟 같은 것을 표시합니다). + +* SeparateMirror (전체 VR 렌더 버퍼를 표시합니다). + +앞으로 이 기능에 대한 최적화, 멀티 플랫폼 인터페이스, 가급적 60fps 모드도 (시스템 대화창에서 특정 시스템 기능과의 충돌을 해결해야 하지만) 지원할 수 있도록 작업중입니다. + +이 기능을 사용하려면 새로 생긴 Morpheus 프로젝트 세팅 bEnableSocialScreenSeparateMode 를 true 로 설정해야 합니다. 그러면 소셜 스크린용 스크린 버퍼가 추가로 할당됩니다. 이 기능 제어를 위한 블루프린트 함수는 SocialScreen 으로 검색하면 됩니다. + +### 신규: 안드로이드 실행파일 크기 감소 + +컴파일러와 링커 세팅을 다수 최적화시켜 안드로이드 바이너리 실행파일 크기를 줄였습니다. Build with hidden symbol visibility 옵션을 켜면 안드로이드 실행파일을 만들 때 언리얼 엔진에서 사용하지 않는 코드를 보다 적극적으로 제거해줍니다. 심볼 테이블에서 함수 심볼도 벗겨내어 실행파일 크기를 한층 더 줄여줍니다. 최종 APK 크기가 약 7MB 줄어드는 것을 확인했습니다. + +**주:** 이 옵션은 디바이스의 바이너리에서 심볼을 제거하므로, logcat 출력에는 네이티브 크래시 콜 스택이 심볼 없이 나타날 것입니다. 디버깅이 가능하도록 하기 위해, 빌드 시스템에서는 디버그 심볼을 벗겨내지 않은 바이너리도 출력 디렉토리에 복사한 뒤, 콜 스택에 심볼을 붙이는 배치 파일을 추가로 생성합니다. + +### 신규: Vertex Interpolator 머티리얼 표현식 노드 + +머티리얼 그래프에 Vertex Interpolator 노드가 추가되어 버텍스 및 픽셀 작업의 값 보간 제어가 더욱 확실해졌습니다. 이는 작업방식상의 개선으로, 인터폴레이터의 한계나 셰이더 변경은 없습니다. + +기존에 버텍스 셰이더 작업을 덜어내는 방식은 Customized UV 출력을 활용하는 것이었습니다. 데이터 수동 패킹 작업이 수반되는 약간 번거로울 수 있는 작업이었지요. 아래 예제 머티리얼은 미리 스키닝된 메시 데이터를 패킹한 후 언패킹하여 이펙트에서 사용하는 것입니다: + +![image alt text](image_36.png)(w:766 h:665 convert:false) + +새로운 인터폴레이터 노드는 패킹을 자동 처리해 주어, 그래프가 단순하고 깔끔해집니다: + +![image alt text](image_37.png)(w:776 h:357 convert:false) + +기존에 Customized UVs 를 통해 패킹하던 작업은 VS (버텍스 셰이더) 핀에 걸어주고 PS (픽셀 셰이더) 핀에서 구합니다. + +머티리얼 통계 출력도, 인터폴레이터의 현재 패킹된 것과 가능한 최대 사용량을 표시하도록 업데이트했습니다. 참고로 위 예제에서 인스트럭션 수와 인터폴레이터 사용량은 그대로입니다. 통계를 보면 2 개의 스칼라가 TexCoord[0] 노드, 나머지 6 개는 미리 스키닝된 데이터에 예약되어 있어, 총 2 개의 벡터에 8 개의 스칼라가 패킹되어 있음을 알 수 있습니다. + +이 기능은 Customized UVs 와 호환되며, 결과를 같이 패킹합니다. + +## 신규: 애셋 관리 프레임워크 (얼리 액세스 프리뷰) + +Asset Manager (애셋 매니저)는 에디터에서나 실행시간에 게임 전용 애셋 유형과 맵을 발견, 로드, 검사하는 데 사용할 수 있는 새로운 글로벌 오브젝트입니다. 퀘스트, 무기, 영웅과 같은 것들을 만들고 요청이 있을 때 로드하는 작업을 수월하게 해주는 프레임워크를 제공합니다. 아직 활발히 개발중인 기능이라, 숙련되지 않은 개발자나 블루프린트 전용 게임에서 사용하기에는 아직 이르며, 4.17 이나 되어야 할 것입니다. 프로젝트 세팅의 애셋 매니저 탭에서 게임의 규칙을 구성할 수 있습니다: + +애셋 매니저가 검색한 주요 애셋 유형은 로드 직전 실행시간에 쿼리한 뒤, 요청이 있을 때 비동기 로드 가능합니다. 또한 애셋 매니저 세팅을 통해 게임을 패키지 제작 및 릴리즈할 때 쿠킹 및 청크 규칙을 구성할 수 있습니다. AnswerHub 에서 이 기능에 대해 작성중인 문서를 참고해 보실 수 있습니다: [https://answers.unrealengine.com/questions/595580/what-is-the-asset-manager.html](https://answers.unrealengine.com/questions/595580/what-is-the-asset-manager.html) + +### 신규: 애셋 검사 창 [얼리 액세스 프리뷰] + +애셋 관리 프레임워크 기반으로 제작된 Asset Audit (애셋 검사) 창을 사용하여 디스크 크기, 메모리 사용량, 다수 애셋에 대한 일반적인 애셋 프로퍼티를 한꺼번에 검사할 수 있습니다. 콘텐츠 브라우저의 특수 버전으로, 창 > 개발자 툴 메뉴에서, 또는 콘텐츠 브라우저나 레퍼런스 뷰어의 우클릭 메뉴에서 접할 수 있습니다. 창을 연 이후에는, 버튼으로 애셋을 추가하고, 플랫폼 드롭다운으로 쿠킹된 애셋 레지스트리에서 로드한 플랫폼 데이터를 로드할 수 있습니다. PS4 에서 ShooterGame 샘플의 텍스처를 검사하는 예제입니다: + +![image alt text](image_38.png)(w:929 h:289 convert:false) + +### VR: VR 용 콘솔 명령 통합 + +각 플랫폼마다 다른 다양한 VR 플랫폼용 콘솔 명령을 한 데 모아 통합시켜, 개발자가 쉽게 작업할 수 있는 공유 레이어를 만들었습니다. + +여기에는 여러가지 장점이 있습니다: + +* 새로운 플랫폼의 독자 처리가 쉬워집니다. + +* HMD 마다 다른 인수의 뜻 일관성이 높아집니다. + +* 현재 HMD 구현 상의 중복이 줄어듭니다. + +* 모든 VR 관련 콘솔 명령에 "vr." 이라는 공통 접두사가 붙습니다. 특정 업체 전용 익스텐션은 명령 이름만 보고도 쉽게 알 수 있습니다. + +* 업데이트된 콘솔 명령은 탭 완료 기능과 내장 사용법 도움말을 지원합니다. + +현재는 과도기라 예전 콘솔 명령 인식은 됩니다만, 사용할 때 폐기 경고가 뜰 것입니다. + +### 커스텀 하드웨어 커서 + +이제 플랫폼에 내장된 커스텀 하드웨어 커서가 윈도우, 맥, 리눅스에 지원됩니다! 프로젝트의 UserInterface 세팅에서 사용할 하드웨어 커서 구성이 가능합니다. + +이 시스템에서는 커서에 여러가지 포맷을 제공할 수 있습니다. 예를 들어, 세팅에서 "Slate/FancyPointer" 를 기본 포인터로 쓰고싶다고 지정할 수 있습니다. 게임 content 폴더의 Slate 디렉토리에 FancyPointer.png + .cur + tiff 를 넣어두면 특정 플랫폼의 다중 해상도 지원이 가능합니다. Tiff 는 맥에서, cur/ani 파일은 윈도우에서 사용되며, 해당 플랫폼에 맞는 포맷을 찾지 못한 경우 png 를 찾습니다. + +### 빠른 위젯 생성 + +UMG 위젯 생성이 최대 3 배 빨라졌습니다! 쿠킹할 때, 이제 위젯 컴파일러는 생성된 블루프린트 클래스와 같은 패키지 안에 저장되어 위젯 생성 도중 사용되는 위젯 템플릿/아키타입을 생성합니다. + +**테크니컬 디테일** + +컴파일 도중, 모든 하위 유저 위젯 및 그 트리를 포함해서 거의 완벽히 초기화된 위젯 트리를 생성하고, 모든 멤버 변수를 걸어주고(hookup), 네임드 슬롯을 초기화하고, 애니메이션 셋업 등의 작업을 합니다. 이렇게 생성 작업이 거의 완료된 위젯을 아키타입으로 사용하여 인스턴싱을 하면, 그에 해당하는 느린 버전의 StaticDuplicateObject 패쓰를 통하지 않아도 됩니다. + +이 메소드에는 제약이 있는데, 이제 위젯의 컴파일 단계 일부에서 인스턴싱이 성공했는지, 또는 사용자가 서브오브젝트 프로퍼티에서 Instanced 구성을 깜빡해서 GLEO 레퍼런스가 생길 것인지 조사합니다. 다행히 그런 경우는 극히 드물텐데, UVisual (위젯 & 슬롯)은 모두 DefaultToInstanced (기본으로 인스턴싱)이므로, Instanced 플래그를 요하는 대부분의 경우는 알아서 처리해주기 때문입니다. 네이티브 코드에서 BindWidget 을 사용하는 대량 작업의 경우라면 더더욱 그렇습니다. + +## Release Notes + +### AI + +* New: Added a profiler for Environment Query System (EQS) that can be accessed through the tabs of the EQS Editor. + + * It collects data automatically during game sessions as long as UES_EQS_DEBUGGER define is set. This includes options for average and max execution time of each step (including breakdown of composite generators), number of items processed by each step, and average frequency of running, which can be useful to identify how often fail safes are actually running. + + * It collects tick load data when USE_EQS_TICKLOADDATA define is set. Each query can store up to 16384 records in cyclic buffer (~4.5 minutes at 60 FPS) showing percentage of EQS tick spent on processing it. This is displayed on the graph in EQS editor tab. + + * A console command has been added, "DumpEnvQueryStats", that saves current EQS profiler data to a file (project's Logs folder, .ue4eqs extension), which can be later loaded and inspected in the EQS Editor. + +* Bugfix: Fixed an issue with Blackboard Key Selector's "Init Selector" that resulted in it picking the first value from the Blackboard rather than the appropriately typed one. + +* Bugfix: Gameplay Task Resource's Auto Resource ID initialization is no longer cleared during Hot Reload. + +* The "Get AI Controller" is now a pure Blueprint Function. + +* Exposed Brain Component's "Is Running" and “Is Paused” functions to Blueprint. + +* Clamped AI Sight's peripheral vision angle as well as changed the UI to not allow values outside of the 0-180 range. + +* Disabled collision on Nav Modifier Volumes. Previously they had an 'Overlap All' response and generated overlap events. They are only supposed to be used for preventing navmesh generation, but overlap events could affect gameplay and are also bad for performance. + +* Made "Skip Agent Height Check When Picking Nav Data" option ignore height when picking nav data for agents. It now picks solely based on the radius when this is enabled. + +#### Behavior Tree + +* Bugfix: Added safeguards to prevent crashes resulted from Blackboard keys being names being longer than 1024 characters. + +* Bugfix: Fixed an issue in dynamic Behavior Tree injection that was causing unexpected behavior when the main BT had more BT injection points. + +* Bugfix: Fixed an issue in Blackboard key instantiation that resulted in the instanced key never being used and BB operations always referring to the original BB entry. + +### Debugging Tools + +* The Gameplay Debugger's input detection has been adjusted so that Tap and Hold work correctly in fixed timestep mode. + +### Navigation + +* Added a flag to Recast Navmesh, "Allow Nav Link As Path End", that is used to control whether path corridors can end on a navigation link or not. This may happen with partial paths and not usually desired behavior. Navigation links at the end are not allowed by default. + +* The Blueprint functions "Project Point To Navigation", “Get Random Reachable Point In Radius”, and “Get Random Point In Navigable Radius” all return booleans determining if the projection/generation was successful, as well as the vector value that describes the requested point. + +* Bugfix: Fixed a memory leak in navmesh generators. + +* Bugfix: Fixed an issue that resulted in losing user settings in Static Mesh's navigation export (Nav Collision object) after changing any property of the Static Mesh. + +* Bugfix: Hand-placed AI pawns now get their Path Following Component's "My Nav Data” variable set properly. + +* Bugfix: Fixed an issue with missing update of navigation area after duplicate or undo operations on Nav Link Proxy and Nav Link Component. + +* Bugfix: Corrected the handling of path following requests by Floating Pawn Movement. + +* Bugfix: Fixed an issue with parameters of geometry trace handling drop-down navigation links. All components blocking on ECC_WorldStatic channel will now report a valid hit. + +* BugFix: HLOD's navigation collision exporting no longer causes unnecessary log output about NavCollision instances in cooked builds. + +#### Animation + +* New: You can now rename Virtual Bones. + +* New: You can now change Virtual Bones so that you can have a Virtual Bone that is a child of another Virtual Bone. + +* New: Added "Get Body Target Transform" to the Physical Animation component, which will return the goal transform that a particular body is trying to get to. + +* New: Control rig Sequences can now be exported to Anim Sequences. + +* New: Preview Scene settings have been exposed in the existing settings tab rather than in a hidden menu of the viewport. + +* New: Support for "Curve Source" nodes to find source components on other Actors. It now searches for the property name rather than the component name. + +* New: Added "Set Preview Mesh" to the toolbar for all animation related Editors. + +* New: Updated Alembic Third-party libraries to the latest versions. + +* New: Added functionality to try and match in-engine Material asset names to FaceSet names found inside of an Alembic cache to automatically assign the correct Materials. + +* New: The Alembic Importer now supports Vertex Color data. + +* New: Added functionality to inform about changes to source data when reimporting your animation data from FBX. It now checks for the following: + + * Whether or not the sequence length has changed. + + * Whether or not previously-imported curves exist in the source data. + +* Bugfix: Fixed a crash when trying to implement a function in a child Anim Blueprint. + +* Bugfix: Fixed a crash when debugging a null Animation Sequence. + +* Bugfix: Trying to access a skinned vertex position on a mesh when using Master Pose component no longer crashes. + +* Bugfix: Attempting to bind to Skeletal Mesh with Anim Blueprint already set no longer crashes. + +* Bugfix: Fixed a crash and effector selection issue for two-bone IK. + +* Bugfix: Right-clicking the empty space in the asset shortcut drop-down no longer crashes. + +* Bugfix: Removed an ensure (warning) by reverting to default unit vectors if zero-sized lookat/lookup vectors are specified for a "Look At" node. + +* Bugfix: Removed a crash when clearing an animation of a 1D blendspace sample. + +* Bugfix: Crash fix to import code for Alembic Caches with the HDF5 backend. + +* Bugfix: Fixed an issue when adjusting curves in the Anim Curves tab using a slider when they are not currently selected. + +* Bugfix: Fixed an issue with Update Rate Optimization update rate being too high. Now we use int, so if you have a high update rate it still can go until it wraps around. + +* Bugfix: Child Anim Blueprints can now be retargeted. + +* Bugfix: Fixed flipping transforms when mirrored. + +* Bugfix: Post Process instances are now appropriately updated, even when the main Anim Instance is not using parallel update. + +* Bugfix: Fixed an issue where running the Editor in a different culture could break pins on nodes that have optional arrays of pins (ie. Animation Graph nodes like Blend By Layer). + +* Bugfix: Fixed an issue with Anim Class being set by name, causing duplicate-named Anim Blueprints to be incorrectly resolved. + +* Bugfix: Fixed an issue where "r.SkeletalMeshLODBias" was affecting meshes in the Animation Editor viewports. + +* Bugfix: Fixed an issue with Animation Preview Scene keyboard binding (I and O hotkeys now hide and show scene elements regardless of tab opened state). + +* Bugfix: Skinned Mesh LOD now updates in the editor under various physics-related circumstances. + +* Bugfix: Fixed an issue with foot placement IK doing line traces on worker threads. + +* Bugfix: Fixed an issue with Anim Blueprints that contain State Machines having blank palettes. + +* Bugfix: Renaming curves in animations now saves properly. + +* Bugfix: Fixed an issue with two-bone IK flickering around full extension when stretch is enabled. + +* Bugfix: Animation now works as expected for dynamically-bound wheeled-vehicle anim instances. + +* Bugfix: Fixed an issue where you could not undo changes from Alembic Import settings. + +* Bugfix: Fixed timing issues occurring while playing back Alembic caches. + +* Bugfix: Fixed an issue with incorrect behavior occurring when placing more than three samples in a straight line for a 2D blendspace. + +* Bugfix: Dropping a new Animation asset on an existing Sequence Player node can now be undone. + +* Bugfix: Breaking transition node connections within Animation State Machines can now be undone. + +* Bugfix: Fixed an issue to ensure that changes to animation sync markers are propagated to currently open blendspace assets. + +* Bugfix: Skeletal Mesh components tick properly when paused if "Tick Event When Paused" is enabled. + +* Bugfix: Fixed Skeletal Mesh Merge duplicating Skeletal sockets. + +* Enabled snapping for translation in the Animation viewports. + +* Removed force inline from Virtual Compression functions. + +* Removed the AnimGraph module from the Graph Editor as a dependency. + +* Bone Reference now has improved performance by caching compact post bone index. + +* Graph files have been moved to Animation Blueprint Editor. + +* We have stopped saving raw curve data into animations on cook in order to save memory and disk space. + +* Ticks now appear properly on Anim Sequence scrub bar. + +* Persona now depends publicly on Skeletal Editor. + +* Montages are now correctly initialized when created. They can be used straight away without first opening them in the Montage Editor. + +* We now propagate thread safety flags to child Animation Blueprints. + +* The Anim Notify Blueprints now start with a "received notify" event node. + +* Made single-node animation instances request clothing simulation resets when their animation is changed. This is because the new animation could be very different from the outgoing animation, and this might cause pops. + +* Refactored "Evaluate Bone Transforms" to prevent usage of Skeletal Mesh component. + + * Deprecated "Evaluate Bone Transforms" in favor of new “'EvaluateSkeletalControl_AnyThread”. + + * Deprecated Skeletal Mesh component argument to "Convert CS Transform To Bone Space" and “​Convert Bone Space Transform To CS”. Now they just take a transform. + +* When selecting bones that are non-required, we now do not render gizmos or text labels. + +* Skeletal selection does not lag behind choice made in the viewport (i.e. when showing bone weights). + +* Added accessor and modifier functions for "Start Time Offset" value in Geometry Cache components. + +##### Animation Assets + +* New: You can now choose a preview slot in the Montage Editor. + +* Bugfix: Fixed a crash when reimporting animations with additive transform tracks. + +* Bugfix: Fixed an issue with additive Pose Asset preview being applied twice. + +* Bugfix: Compressed animation data is now included in Memory Stats for Animation Sequences. + +* Bugfix: Fixed an issue where blendspace interpolation settings would not have a direct effect and required reopening the blendspace asset. + +##### Animation Blueprint + +* New: Added "Spline IK" node. + +* New: Added a property to Blendspace Player nodes that enables users to choose whether the play time is reset when the blendspace changes. + +* New: Animation Blueprints can now specify a Preview Mesh. + +* New: Added the "Look At" node so you can use “Look at Location” on a socket or joint, and improved the Visualizer. + +* Bugfix: Fixed a crash when "Pose Asset" contains a bone that is not in the mesh. + +* Bugfix: Fixed an assertion that could occur when selecting certain items in the Animation Blueprint editor. + +* Bugfix: Fixed a crash when diffing State Machine Transition graphs. + +* Bugfix: Fixed an issue with "Pose Handler" using mesh bone index and not compact bone index for setting up “Bone Blend Weights” array. + +* Bugfix: Fixed an issue with incorrect errors on compiling Aim Offset nodes with exposed blendspace pins. + +* Bugfix. Fixed an issue with additive nodes breaking the current pose when they have no additive animation attached. + +* Bugfix: Fixed issues pertaining to extra references to Animation Blueprints on Skeletal Mesh components. + +* Layered Bone Blend node has been optimized so that it will cache mask weights in compile time. + +##### Import/Export + +* Bugfix: Fixed a crash when reimporting a Skeletal Mesh that has Virtual Bones. + +##### Skeletal Mesh + +* Bugfix: Fixed a crash when using re-import button in the Skeletal Mesh Editor. + +* Bugfix: Fixed a crash related to Skeletal Mesh resources not being initialised before component is registered. + +* Bugfix: Fixed a serialization mismatch in Skeletal Mesh source buffers. + +* When importing a Skeletal Mesh, "Activate Bone Indices" now always includes parents even if it's not skinned. + +#### Tools + +* Bugfix: Fixed a crash in Persona when rotating a bone due to single bone controllers not being initialized correctly. + +* Bugfix: Fixed an ensure when deselecting bones in Anim Blueprint editor. + +* Bugfix: Fixed an issue where mesh-customized sockets were not showing up by default in 'Active' socket filter mode. + +* Bugfix: Fixed issues related to bone removal in Skeletal Mesh LODs. + + * Issue where the "Apply" button would not show after adding bone names. + + * Issue where previously removed bones would not be restored. + + * Ensure that the Skeletal Tree is updated when bones are removed or restored. + +* Double-clicking animation assets in Content Browser will now try to re-use existing Animation Editor windows, rather than opening a new one every time. + +* Animation picker on Skeletal Mesh component is now disabled rather than hidden when no Skeletal Mesh is assigned. + +* The Soundwave-internal curve tables have been moved to the 'Advanced' rollout. + +#### Audio + +* New: Vorbis-encoded audio files can now be streamed. + +* New: Audio streaming is now supported on Android, iOS, and XBox One. + +* Bugfix: Fixed a shutdown crash when there is a pending async audio occlusion trace. + +* Bugfix: Fixed a crash when opening a Media Sound Wave. + +* Bugfix: 'Sound Player' nodes will more efficiently load the referenced sound asset unless a 'Sound Quality' node is being used to select which 'Sound Player' nodes to consider, in which case, the current asset reference evaluation will continue to be used. + +* Bugfix: We only queue subtitles once per-wave instances playback. + +#### Automation + +* New: Added support for -DeveloperReportOutputPath and -DeveloperReportUrl commands to permit local runs of the Automation Tool to generate reports on the report server and launch the browser to view them. + +* 'ResavePackages' commandlet now supports lighting in separate packages when using it to rebuild lighting. + +* Option to disable taking screenshots has been disabled. Screenshot comparison is an integral part of the testing so disabling them is no longer allowed. + +* The system now waits for the asset registry to finish loading assets before running tests. + +#### Blueprints + +* New: Added the 'Remove Gameplay Tag' function to the gameplay tag function library. + +* New: Blueprints containing a String and Text variables can now be marked as multi-line, which enables values to contain newlines when pressing Shift + Enter while editing them. + +* New: Blueprint Variables can now be marked as 'Read-Only' in Blueprint Editor, which prevents them from being set in Blueprints. This behaves the same as using 'BlueprintReadOnly' instead of 'BlueprintReadWrite' on a C++ UPROPERTY() declaration. + +* New: 'Get Default Locale' has been exposed to Blueprints. + +* Macro instances that contain latent actions will now show an overlay clock icon like other latent nodes, which makes them easier to spot and understand that they impact execution flow + + ![image alt text](image_39.png)(w:720 h:180 convert:false) + +* New: Improved comments in Blueprints. + + * Comment node text now wraps while the comment is being edited. + + * Reduced cases where the title of a comment node would clip at the end. + + * Editing the comment for a regular node using the right click menu will now show changes immediately, rather than waiting until the node was moused over again. + +* New: Added the Save and Find in Content Browser buttons to the Level Script Blueprint editor (they will save/show the map package that contains the Level Script). + +* New: Added the ability to search for delegate nodes using the function name that they are bound to. + +* New: 'Array Get' node. + + * Can toggle between returning a reference or copy. + + * Using a reference solves a longstanding issue with arrays of structs not being able to easily make changes to the items in the array. + +* New: 'Get Class Defaults' node has been extended to include output pin exceptions for Set & Map variable defaults. Like array types, the returned value is now a copy of the default value rather than a reference to it. This is done in order to avoid an accidental mutation of the Blueprint class default object. + +* New: Function inputs are now exposed as variable "Get" nodes via the right-click context menu in a Blueprint function graph context. + + * To use: In a Blueprint Function graph, right-click to access the context menu. Any input parameters will be listed as additional "Get" actions. + + * In this way, input parameters can be accessed like local variables from anywhere in the function graph; in other words, it's no longer necessary to drag wires all the way back to the Function Entry node in order to access these values. + +* New: We now support "value-based" Bitfield enum type associations in the editor for a UPROPERTY marked as 'Bitmask' with a 'BitmaskEnum' association. + + * Prior to this release, Bitfield properties did not work with associated enum types in which the enum values were explicitly set to a bitmask value (e.g. 0x80). That is, the value was assumed to always be set to the index of the bit that the flag should set in the editor ("index-based" mode). + + * To switch the associate to the new "value-based" mode, include an additional metadata key in the UENUM() declaration. Example: UENUM(Meta = (Bitmask, *UseEnumValuesAsMaskValuesInEditor="true"*)). + +* New: Added a whitelist mechanism for handling native noexport types that can support direct field access in nativized Blueprint code. + +* Bugfix: Fixed a crash in Blueprint Editor when adding an input parameter to a Custom Event node after deleting a Function Graph containing a Create Event node. + +* Bugfix: Fixed a crash when creating a new Blueprint class from one or more selected Actors in which the root component is not Blueprint-spawnable. + +* Bugfix: Fixed a crash on load in nativized EDL-enabled builds with non-nativized child Blueprint class assets. + +* Bugfix: Fixed a runtime Blueprint VM crash upon removing an element from set after consecutive add/remove iterations. + +* Bugfix: Fixed a crash that could occur when splitting a struct pin on a collapsed graph node. + +* Bugfix: Fixed a crash when trying to use non-supported types as Blueprint map keys. + +* Bugfix: Fixed a crash that could occur when changing a Map's value type string to vector. Map variables are properly cleared when value type is changed to an incompatible type. + +* Bugfix: Fixed a crash when compiling a Blueprint that contains a split pin in a collapsed graph. + +* Bugfix: Fixed a crash loading Blueprints that contain a Blueprint node that no longer exists in code. + +* Bugfix: Fixed a crash when using the Straighten Connection shortcut key (and some other related issues with actions done after the Context Menu is closed). + +* Bugfix: Fixed a crash when opening a Blueprint with a parent class that no longer exists. + +* Bugfix: Fixed a crash with the merge tool when the source control provide is SVN and there are gaps in the revision history. (This may still not work correctly, but it won't crash. The full fix will be covered with UE-43603) + +* Bugfix: Fixed a crash when attempting to name component with a very long name. + +* Bugfix: Fixed a crash that could happen when running Cook On The Fly server with nested struct assets. + +* Bugfix: Fixed a crash that would happen when a level in Blueprint was auto-saved. + +* Bugfix: Fixed an assertion that could occur when compiling a Blueprint with certain nodes (Select, Math Expressions, etc.) + +* Bugfix: Fixed a crash that could occur when reparenting a component Blueprint. + +* Bugfix: Fixed a crash that could happen when setting maps and sets of strings and certain structs. + +* Bugfix: Fixed a crash that would occur when passing a self node through a CustomEvent ref parameter. + +* Bugfix: Fixed a crash that could occur when adding a new Blueprint function and immediately undoing. + +* Bugfix: Fixed a crash that could occur after renaming the category of an implemented interface function inherited from a native C++ parent class in the 'My Blueprint' panel. + +* Bugfix: Fixed a crash that could occur when editing a local curve variable's default value in a Blueprint graph. + +* Bugfix: Fixed an ensure misfire in PIE exit when using Play as Listen Server Mode. + +* Bugfix: Fixed an infinite loop case in the Math Expression node. + +* Bugfix: Fixed an issue where misaligned memory access of noexport struct properties leading to incorrectly initialized values in a nativized cooked build. + +* Bugfix: Fixed an issue with broken collision shapes at runtime when cooking with the optimized Blueprint component instancing data feature turned on. + +* Bugfix: Fixed an issue with a Bitmask Enum type validation failure when serializing a Make Bitmask Literal node + +* Bugfix: Fixed an issue with log spam when compiling a Blueprint function with a local TSet or TMap variable. + +* Bugfix: Fixed an issue with broken pin wires after expanding a duplicated collapsed graph node. + +* Bugfix: Fixed an issue with invalid custom Enum type selection on member fields in the User-Defined Structure editor after a reload. + +* Bugfix: Improved context menu "whole world" algorithm to proper take into consideration localisation when searching for terms. + +* Bugfix: Fixed an issue where renaming interface input/output parameters will no longer cause broken pin links at interface function call sites in Blueprints that are currently loaded. + +* Bugfix: Fixed an issue with broken graph node pin links caused by renaming interface function input/output parameters prior to compiling the interface, but after renaming the function itself. + +* Bugfix: Fixed an inability to save after choosing a Level Script Blueprint class as the default value for a class input pin in a non-Level Script Blueprint class function graph. + +* Bugfix: Fixed an issue where Blueprints containing a 'Key Get Display Name' node will no longer be marked dirty when opening the Blueprint. + +* Bugfix: Fixed an issue where the user defined variable tooltip was not showing up when hovering over Get/Set nodes for local variables. + +* Bugfix: Fixed an issue with old versions of Blueprints being diffed accidentally showing up in Find-in-Blueprints search results. + +* Bugfix: Fixed some issue in Blueprint Diffing where properties of nodes edited in a Details panel would not show up as differences (this impacted Animation Graph nodes most heavily). + +* Bugfix: Fixed an issue in Blueprint nativization that could cause bad interface function calls to be generated. + +* Bugfix: Fixed an issue that could cause stale Blueprint instances in a hidden sub-level to spam a runtime error. + +* Bugfix: Fixed an issue that could cause a Blueprint 'mismatch' error when using 'Set' and 'Map' node. + +* Bugfix: Fixed an issue that could cause struct asset defaults to be wiped on editor reload. + +* Bugfix: Fixed an issue that could cause a packaging error when running with Blueprint nativization and no Blueprints were nativized. + +* Bugfix: Fixed an issue that removed the ability to set Blueprint object variables as 'config' variables, as you cannot set a object reference from a config. + +* Bugfix: Fixed an issue with reroute nodes so that a new output connection will propagate that type through to the node's inputs. + +* Bugfix: Fixed an issue so that 'Get Data Table Row' nodes are now compatible with DataTable variables. + +* Bugfix: Fixed an issue that could cause material parameter setting in a Blueprint construction script to fail. + +* Bugfix: Fixed an issue that could cause overlap events to fire multiple times in PIE. + +* Bugfix: Fixed an issue that would generate the nativized Blueprint plugin even if no Blueprint files were nativized. + +* Bugfix: Fixed an issue that would cause certain components to be orphaned and hidden from the component hierarchy. + +* Bugfix: Fixed an issue that could cause a level Blueprint's bound delegate nodes to not trigger. + +* Bugfix: Fixed an issue in Blueprint nativization that would cause cyclical logic (loops, etc.) to not iterate past the first iteration. + +* Bugfix: Fixed an issue in Blueprint nativization that could cause Blueprint subclasses to ignore their overridden model and default to their parent's. + +* Bugfix: Fixed an issue where non-nativized Blueprints were getting dropped from the cooked asset registry file when running with Blueprint nativization. + +* Bugfix: Fixed an issue where there would be a nativized Blueprint asset build error when there are no native code dependencies. + +* Bugfix: Fixed an issue with incorrect Blueprint graph pin value display names for user-defined enum types. + +* Bugfix: Fixed the variable 'config' setting tooltip to report the correct config file for the user to use. + +* Bugfix: Fixed an issue that could cause Blueprint variables set from a config to have their values improperly overwritten. + +* Bugfix: Fixed several issues with Switch Blueprint nodes not keeping their node and property UI in sync. + +* Bugfix: Fixed several issues where changing pawn/hud/state class from the Level editor toolbar would not work properly until the project was reloaded. + +* Bugfix: Fixed a stale class reference in interface properties that reference a Blueprint defined interface that has been recompiled. + +* Bugfix: Fixed an issue where 'Get Values' and 'Get Keys' nodes were not providing correct results for Map variables that have had values removed. + +* Bugfix: Fixed an issue where Blueprint functions that have all their return nodes pruned (ie. are not connected to anything) now have the correct output pins at call sites. + +* Bugfix: Fixed an issue where 'Movie Scene Sequence' and related code was not working when Blueprints were nativized. + +* Bugfix: Fixed an issue in nativized packaged builds that would cause default values to be lost. + +* Bugfix: Fixed 'Enum As Byte' related warnings in nativized packaged builds. 'Enum As Byte' is no longer used when nativizing Blueprints. + +* Bugfix: Fixed issues with Blueprint nativization where it didn't correctly include headers necessary for owners of subobjects, and instances where all modules needed by the generated code weren't being founds. This fixes one cause of "Cannot open include file" errors when packaging with Blueprint Nativization enabled. + +* Nodes in the blueprint editor again use their custom cursor (grab hand when hovering over a node and crosshairs when hovering over pins). + +* 'Logarithm' node added to the Blueprint Math library. + +* 'Set' pins on 'Intersection', 'Union' and 'Difference' nodes now infer their values uniformly. + +* Out of date Class Default Objects are no longer duplicated when compiling a Blueprint, reducing blueprints compilation time + +* Successive calls to Set Intersect, Union or Difference now provide correct results, previously the Set was not cleared before calculating the new result + +* 'Trace By Profile' collision functions have been exposed to Blueprints. + +* Nativize code is now more precise about dependencies, reducing the resulting executable size and compiler load. + +* Blueprints that override an inheritable component are no longer 'data only'. Blueprints with overridden components but no extra functions now load without losing data. + +* Blueprints that extend types that implement 'Needs Load For Server' or 'Needs Load For Client' now honor those functions, meaning they will not be cooked for targets that their type wants to be excluded from. + +* Delegates in nativized packaged builds correctly prevent double registration. + +* Blueprints used as a child actor class will no longer be marked dirty when compiling the class that references them. + +* When duplicating a Blueprint component, that component will now be a sibling of the duplicated node, not a child of it unless it is the root node being duplicated. + +* Duplicated root nodes will have their scale set to (1,1,1) to avoid applying the scale multiplier twice. + +* Blueprintable Components are no longer considered experimental, they have been enabled by default for several versions. + +* The ticking behavior of latent actions in components has been changed to match how they behave in actors. When the component ticks, the latent actions will now be processed at the same time, rather than happening later in the frame when latent actions for non-ticking actors and components are processed. This does change behavior, so there is a console variable (t.TickComponentLatentActionsWithTheComponent) that can be used to revert to the older behavior until affected component Blueprints that depended on the old ordering behavior can be fixed up. The cvar should be treated as deprecated; it will be removed in a future release. + +* Updated Blueprint nativization so that it generates source files compatible with 'include what you use' (IWYU). + +* Moved nativized Blueprint plugin generation to the project's 'Intermediate\Plugins' folder. + +* Removed make/break nodes from the Blueprint menu for structs that aren't marked as a 'BlueprintType'. + +* Updated marquee selection in graph editors. Ctrl dragging now inverts nodes' selection state, instead of only deselecting them (holding alt is now for pure deselection). + +* The Actor Details view will now refresh property mappings for the current Actor instances selection after a bytecode-only recompile of its Blueprint class as a dependency during reinstancing. + +* Child Blueprint class assets are now marked as dirty if its parent Blueprint class incurs a structural change. This alerts the user that updates to the Child Blueprint would need to be saved on exit. + +* We now emit C++ ctor initialization code for nested default subobjects when nativizing a Blueprint class at cook time. + +* Instanced Static Mesh transform edits are now reflected in the Blueprint editor's preview scene. + +* The editor will now raise an error at cook time after an attempt to nativize a Blueprint class that also implements a native C++ interface with a pure virtual function declaration that is not also marked up with UFUNCTION. This is because we cannot nativize a Blueprint class that does not also have an implementation of a pure virtual function inherited from the interface. + +* C++ interfaces with one or more pure virtual function declarations not also tagged with UFUNCTION are now excluded from the list of available "Implementable" interfaces in the Blueprint class editor. + +* Non-nativized child Blueprint classes will now properly override a nativized parent Blueprint class's component defaults at runtime in a nativized cooked build. + +* We will now implicitly nativize any child Blueprint class that overrides one or more BlueprintCallable functions inherited from a parent Blueprint class that is also nativized. + +* The Blueprint diff tool now reports when a component changes its type between revisions + +* Blueprints are now only dirtied if edited properties are from objects in the Blueprint's package. + +#### Core + +* New: Support added for "double" and 'fname' stat types in UFE stat export to CSV. + +* New: Pak files can now have their index encrypted with AES, preventing them from being opened by unrealpak. + + * An AES key must be provided in the project Encryption.ini, and then index encryption can be enabled in the project packaging settings in the editor. + + [REGION:note] + When either pak index encryption or signing are enabled in the Project Settings, pak ini encryption must also be enabled in order to avoid a potential security issue. All of these settings can be found in the Packaging section of the Project Settings dialog in the editor. + [/REGION] + +* New: Added "Get Component For Axis" and “Set Component For Axis” to FVector and FRotator. + +* New: Added support for -iterate for content plugins that require path remapping during cook/packaging. + +* New: Added a "CookedOnly" plugin type, for plugins meant only to be loaded in cooked games (in support of Blueprint nativization). + +* New: Added a Json Object Converter to add support for saving and loading TMap and TSet UProperties. + +* New: Absolute paths are now allowed in -UserDir= argument. + +* New: Added ability for games to use command line parameters for map overriding in shipping builds if their target.cs file defines UE_ALLOW_MAP_OVERRIDE_IN_SHIPPING macro to 1. + +* New: Added support for instanced elements in TMap and TSet properties being copied during "Copy Properties For Unrelated Objects." + + * This fixes an issue where instanced fields could lose data during recompilation of a Blueprint. + +* New: Added a new method Platform Misc "Get OS Version" that returns a string representing the raw OS version info. + +* New: All HTTP implementations now use a consistent User-Agent string (specified via the overridable function Generic Platform Http "Get Default User Agent" method). + + * Added a Platform and OSVersion string to the default value (platform=FPlatformMisc::IniPlatformName() and osver=FPlatformMisc::GetOSVersion()). + +* Bugfix: Fixed a crash with startup in the runtime asset manager when the on-disc cache already contains more data than the system is configured to use. + +* Bugfix: Fixed a crash in 'Chunk Cache Worker' function constructor. + +* Bugfix: Fixed a crash when launching "Play In Editor" session caused by missing audio data if its DDC data was not present and the audio was streamed in. + +* Bugfix: Fixed a crash when UObject can be added to GC cluster only if all of its Outers can also be added to it. + +* Bugfix: Fixed an assert with LocalExportIndex.IsNull. Now the Event Driven Loader code will properly disambiguate imports with the same name and the same outer name. + +* Bugfix: Fixed a crash when Hot Reloading caused by reinstancing UEngine objects. + +* Bugfix: Fixed an occasional crash during Hot Reload CDO reinstancing that was caused by a redundant insertion into TMap invalidating an existing reference into that TMap. + +* Bugfix: Fixed a crash when importing a Blueprint which contains a non-empty TMap with an enum class key. + +* Bugfix: Fixed a crash when Hot Reloading a project which contains a user-defined struct. + +* when hot reloading a project which contains a user-defined struct. + +* Bugfix: Fixed a crash when deserializing a TMap property item with instanced elements, where the CDO contains default element values for that property. + +* Bugfix: Fixed the use of many printf non-literal formatting strings, as these are potential security issues. + +* Bugfix: Fixed an issue with incorrect error code being returned from UnrealHeaderTool when -WarningsAsErrors and -Verbose are specified code. + +* Bugfix: Fixed an issue with the error code returned by UnrealHeaderTool when an error occurs during preparsing of headers. + +* Bugfix: Fixed a persistent stat metadata warning generated during PIE.. + +* Bugfix: Fixed an issue with FMonitoredProcess to prevent infinite loop in -nothreading mode. + +* Bugfix: Fixed an issue for runtime asset cache not invalidating files with an outdated version number. + +* Bugfix: Fixed stats warnings because each new slate loading screen thread has the same stat name, but is potentially assigned to a different thread. + +* Bugfix: Fixed an issue with CSV parser missing empty cells at the end of the string. + +* Bugfix: Fixed an issue with external plugin cooking and deployment by remapping plugin directories upon cook & deployment Tested directory structures: + + * D:\SomePluginDir + + * D:\UE4\AnotherPluginDir + + * D:\UE4\Engine\Plugins + + * D:\UE4\MyProject\Plugins + +* Bugfix: Fixed a memory leak in MallocBinned which affects the mobile platforms (Android, iOS). + +* Bugfix: Fixed a typo in comments for LODColoration in BaseEngine.ini. + +* Bugfix: Fixed the Log message in "Exclusive Load Package Time Tracker." + +* Bugfix: Fixed an issue where "log.timestamp" command would not work because it was incorrectly handled by "log" console command. + +* Bugfix: Fixed an issue where the logging system could hang when running out of disk space while flushing log and fixed unexpected concurrency assert when flushing the log buffer to disk. + +* Bugfix: Fixed a deadlock when flushing log file while it's already being flushed by a flush timer on the async log writer thread. + +* Bugfix: Fixed a memory leak when running with -nullrhi on the commandline in cooked games caused by shader resources not being destroyed. + +* Bugfix: Fixed an issue to make sure the engine is properly cleaned up on UnrealHeaderTool early exit to prevent UnrealHeaderTool hangs. + +* Bugfix: Fixed an issue to make sure that streamed-in SoundWaves get added to Garbage Collection clusters. + +* Removed dependency preloading system from sync and async loading paths. It has been superseded by the new event driven loading system. + +* Removed remaining references to AES_KEY, instead using the encryption key delegates to access the key where needed. + +* Refactored encryption and signing key access in unrealpak to make it easier to use. + +* Make content projects generate a stub executable when encryption or signing keys are specified so that keys can be embedded correctly. + +* Separate pak cache granularity from pak signing chunk size in the EDL loader. + +* Increase "Serial Size" and “Serial Offset” in FObjectExport to 64bits, to handle larger file sizes. + +* Added some validation of the class index in exportmap entries. + +* Added missing support for compiling plugins external to Engine/Plugins & Game/Plugins. + +* Disabled the 'HeartBeat' function on platforms that don't actually want to use the HeartbeatThread. + +* 'None' is now going to be properly considered by the engine as an invalid filename. + +* The editor will now collect garbage after a map is loaded to make sure any stale components or other objects that are no longer needed are destroyed. This is to make sure that these components are not resurrected by another editor operations like duplication. + +* Made sure the async log writer flushes the log archive even if there's no serialization requests to prevent situations where some of the recent requests haven't been flushed to disk + +* Reduced the code size for the generated Static Register Natives functions. + +* Disabled the garbage collector when recompiling child Blueprints, as is already done for the parent Blueprint. + +* Simplified Unreal Header Tool's code generation logic. + +* Implemented Lex "To Sanitized String" for double. + +* The function Local Player Context "Is Valid" now also checks that the player controller has a player set. + +#### Editor and Tools + +* New: UnrealGameSync now includes a workspace-specific file filter, separately to the global file filter. + +* New: UnrealGameSync now supports pop-up notification for build failures on content changes. + + * To mark a badge as applicable to users submitting content changes, add +ContentBadges=Name to the [Notifications] section of the project specific configuration file at /Build/UnrealGameSync.ini. + +* New: UnrealGameSync now allows a project to specify filters for the streams that should be displayed for fast-switching to. + + * The "Quick Select Stream List" setting in the “Options” section of the Project Settings references a depot path containing a list of strings used to filter the stream list. An option is shown to switch back to showing all available streams, if desired. + +* New: Added support for in memory packages. Helps distinguish between packages which can and can't be cooked. + +* New: Added a Blueprint function to convert a Render Texture to Texture2d. This is only available for use in the Editor. + +* New: Custom Depth can now be enabled for Foliage. + +* New: You can now color-code all of the windows in the editor in order to visually distinguish them when working across multiple branches or projects + + * You can adjust the 'Editor Window Background Color' for a subtle effect, as the default background is already a pretty dark grey: + + ![image alt text](image_40.jpg)(w:929 h:416 convert:false) + + * Or you can edit the tint in the two brushes (which sets the texture to a white default one) to get a very brazen effect: + + ![image alt text](image_41.jpg)(w:929 h:416 convert:false) + +* New: Added Data Table export/import support for TMap and TSet. + +* New: Updated the Windows platform to use the newer Vista+ style browser dialogs, rather than the older XP style dialogs. + +* New: You can now empty the text value within an FText property or pin. + +* New: Added support for .ini-driven classes to use a specific platform's config hierarchy, so that the editor on a desktop platform can read .ini settings from other platforms .ini files. + + * This will allow for NDA'd platforms to keep their ini settings in protected files, but still be editable by the editor. + + * Moved project settings for console platforms over + + * See UObject::GetConfigOverridePlatform() + +* New: Scene importing now allows for plugins to expose new scene import factory types. + +* New: Overhauled "Call In Editor" support and promoted it so it can be used on functions in any class, not just Blueprints derived from AActor: + + * "Call In Editor" can now be used on native UFUNCTION() declarations (e.g., UFUNCTION(Category=CoolCommands, CallInEditor)). + + * Blueprint declared functions can also be marked as CallInEditor (in addition to custom events), which allows you to set the category and tooltip for the buttons. + + * Now shows each function as a separate button, placed in the category associated with the function. + + * Removed the duplicate copies of properties placed in the Blutility section. + + * Prevented operating on functions that have parameters or return values, which could crash before. + + * Added a scoped transaction around "Call In Editor" execution so changes made can be undone. + + * The button strip entry is now searchable by function name or tooltip. + +* New: Added a new Details view option: "Show Hidden Properties while Playing" + + * Enabling this allows you to see every property on selected objects that belong to a simulating world, even non-visible and non-editable properties. + + * This feature is very useful for inspection and debugging, because you can see all of the internals of your Actors and Objects. + + * Be careful when changing values for properties that are not really intended to be changed at runtime. You could introduce instability or even corrupt data. + + * Note that this setting is saved for your entire project. + +* New: Sequencer additions and updates: + + * Tracks can now be prioritized based on their subscene hierarchical bias value. Higher bias values take precedence. + + * Fixed particle system restore state so that it gets the proper initial active state of the particle. + + * Added a generic past menu for Master (root) tracks. + + * Changed the time snapping interval in the toolbar UI so that it no longer additionally updates the Sequencer setting. The setting is only used to initialize the time snapping interval of the Level Sequence. + + * Added translate keys with Ctrl and Left-Right arrows. + + * Added Level Sequence Actor button in the Details panel to open Sequencer. + + * Duplicate shot now puts the duplicate on the next available row, keeping the start/end times the same. + +* New: You can now isolate/select all sections using a specific Material slot. + +* New: The FBX importer updates: + + * Now imports collision models under the FBX LOD Group. + + * Now applies the transform from FBX options only one time for the whole import. + + * When importing an FBX file from Blender, the importer now removes the root node name "armature." + + * No longer removes the socket created in UE4 Editor when using reimport. If affects only imported socket. + +* New: Added some LOD Setting options to the FBX Import Options window. Users can now specify the following Static Mesh LOD Settings Options: + + * Auto Compute LOD Distance + + * Minimum LOD Number + + * LOD number + +* New: The FBX Importer now fills two more Material Inputs (Texture only) from the FBX Material: + + * Specular Factor imported as "Roughness" + + * Shininess imported as "Metallic" + +* New: The FBX exporter can now export with the Front X-Axis. The new option is under the Editor Preferences settings. + +* New: TMaps now support editing structs as keys from within the Details panel. + +* New: The Data Table Row Editor now contains a Reset to Default control. + +* New: Properties added to the header of a Details panel group (ie. via IDetailGroup::HeaderProperty()) now have copy/paste actions exposed in the Context Menu. + +* New: Added the possibility in Slate to reset property group to their default value. + +* New: Added the possibility to perform the following actions in Save/Load Level dialog: + + * Rename + + * Delete + + * Create a New Folder + + * Show in Explorer + + * Show the Size Map tool + +* Bugfix: Fixed a crash when selecting components from an Actor's component tree and then undoing + +* Bugfix: Fixed a crash when attempting to open multiple cooked assets at once in the editor. + +* Bugfix: Fixed a crash when pressing PIE button several times before PIE session begins. + +* Bugfix: Fixed a crash that could occur during seamless travel while playing in a Play-in-Editor session with the "Use single process" option unchecked. + +* Bugfix: Fixed a crash while using the "Delete" button inside of the HLOD outliner while having a Proxy mesh opened in the Static Mesh Editor. + +* Bugfix: Fixed a crash when using import into level with .obj file. + +* Bugfix: Fixed a crash when dragging a re-import scene and there is new asset created. + +* Bugfix: Fixed a crash when creating too many LODs when importing a Static Mesh. + +* Bugfix: Fixed a crash with High Resolution Screenshot Tool that could happen when the Screen Percentage is set to a value other than 100%. + +* Bugfix: Fixed an issue with Device Output Log showing partial lines sometimes. + +* Bugfix: Fixed an issue where array properties would revert to the default values when duplicating an Actor. + +* Bugfix: Fixed an issue with Details panels becoming unusable if "Show Only Modified Properties" is enabled and there are no modified properties. + +* Bugfix: Fixed an issue so that thumbnails for Material assets now respect the "used particle system sprites flag" and show a quad instead of a sphere by default. + +* Bugfix: Fixed an issue for outdated error message instructions for how to fix being unable to launch on an iOS device. + +* Bugfix: Fixed an issue with "Save Current As" option not saving the current level and only saving the Persistent Level and then reloading everything thus causing work to be lost if editing a sub-level. + +* Bugfix: Fixed an issue with Material Instances being marked dirty when opening. + +* Bugfix: Fixed an issue with TAssetSubClassOf properties being reset on undo. + +* Bugfix: Fixed an issue that could cause the wrong Blueprint instance to be duplicated, or copy/pasted. + +* Bugfix: Fixed an issue with the Focus action in the Static Mesh Editor viewport. + +* Bugfix: Fixed an issue with Color Customization so that curve color names are "R", "G", "B", "A" instead of None. + +* Bugfix: Fixed an issue with user's setting for Texture Mip LOD size being incorrectly clamped. + +* Bugfix: Fixed an issue where lighting rig rotations were not set / saved correctly for Preview Scene Profiles. + +* Bugfix: Fixed an issue where auto-exposure values from the Preview Scene Profiles were not correctly applied + +* Bugfix: Fixed an issue where HLOD's "Override Screen Size" would not propagate on a LOD Actor directly. + +* Bugfix: Fixed an issue where the Material Slot assignment wasn't correctly restored on reimport. + +* Bugfix: Fixed an issue to prevent importing more LODs than the maximum allows for. + +* Bugfix: Fixed an issue with the FBX importer's "Front X-Axis conversion". We remove the scale of the camera and adjust the orientation of both the camera and light. + +* Bugfix: Fixed an issue with Auto Reimport "Directory to Monitor" feature. + +* Bugfix: Fixed some issues with the Import commandlet: + + * Fixed possible crash when importing FBX files. + + * Now makes sure that the imported assets are saved when there is no source control. + +* Bugfix: Fixed an issue with Static Mesh conversion from UE4 4.14 to earlier versions. + +* Bugfix: Fixed an issue with the Merge Actors Tool that was sometimes assigning wrong Material IDs to mesh sections. + +* Bugfix: Fixed an issue where the Number of Players and Dedicated Server settings for PIE would not persist correctly after Editor shutdown. + +* Bugfix: Fixed issues related to Auto Reimport: + + * Fixed a crash when attempting to import to mount points that do not exist. + + * Now allow for new assets to be created from monitored directories. + + * Settings now use a path picker when specifying the "Map Directory To" field. + +* Bugfix: Fixed an issue so that Property Editor Inline Class Filter now shows unloaded Blueprint Classes properly in the Editor. + +* Bugfix: Fixed an issue with Undo/Redo transactions of Color Grading. + +* Iterative cooking .ini setting checking improvements have been made. More to come in a future release. + +* Dependency checking performance improvements for iterative cook. More to come in a future release. + +* Panning in orbit mode now takes in account camera speed setting. + +* Pivot Painter 2 is a general purpose vertex animation toolset that comes with specialized subset of material functions to automate foliage animation. The script and material function set are more flexible, easier to use and provide an improved workflow over the first release. Additionally, a content example map ships with the editor to demonstrate how Pivot Painter's output can be referenced in the editor. + +* Added a disclaimer popup for the first time a user enters VR Mode + +* All asset properties in Details panels now have thumbnails on by default. + +* Disabled editor sounds that play when you PIE, simulate or possess the player by default. There is now a setting in the editor preferences to control this. + +* The output log should now have the same text color as other panels in the editor. + +* Removed hard coded list of thumbnails, preventing objects with valid thumbnails from showing up. Thumbnails are now shown by default. Use meta=(DisplayThumbnail=false) on a property to hide thumbnails. + +* Import data and thumbnail data are now transactional. You can now undo and redo their edits. + +* Reread in the target RHIs array every time the list of shader types is needed, instead of caching, because the user could change the settings in the editor, then click cook. + +* The Paint Fill tool has changed the way it works in Texture Weight Painting mode, it now fills the mesh with the currently selected texture weight index. + +* Limited the ability of setting up the Hierarchical Level of Detail (HLOD) system in levels which are contained as streaming levels in other assets. + +* The FBX importer now builds the Static Mesh only once when there is many LODs. + +* The section Material slot assignment is now correctly restored on reimport. + +* When swapping the Static Mesh referenced by a Static Mesh component, we now just clean up the Material Override that exceed the Static Mesh Material array size, instead of clearing all overrides. + +* When using the Full Scene Importer the "Scene Import" data asset can now specify a different source file for reimport. + +* Data pin style preferences are now saved on Editor shutdown. + +* The "Fixup Redirects" commandlet now ensures that files that are marked for delete are correctly submitted to source control. + +* The "Resave Packages" commandlet will now submit files that are marked for delete. + +* Blocking volumes will actually be added to the level when placed via the "Place Actor" command instead of generating warnings. + +* Values that are directly entered for float properties with a specified Delta value will no longer snap to the nearest delta when losing focus. + +* Actor components can now be scaled to negative values using the transform gizmo. + +* Map properties now fully support customized property types used as keys. + +* When deleting an Actor, we now display the name of the referencers. + +* Using the Convert Actor feature now won't change the Actor level. + +* Primitive Statistics window will now properly update itself when adding new Levels. + +* Optimized the lightmap UVs generation to speed up the Static Meshes import flow when packing the UVs into higher resolutions. + +##### Content Browser + +* New: Added "Resave All" functionality to Content Browser folders. + +* New: Added a way to view/copy a list of references (including those that aren't loaded) to the Reference Viewer. + +* New: Importing CSV files will now show the name of the CSV file in the import dialog. + +* New: Added the ability to auto resize column in "Column View" by double clicking column splitters + +* Bugfix: Fixed an issue where folders wouldn't be removed from the Content Browser when deleting them. + +* Bugfix: Fixed an issue with the Reference Viewer where it only ever used the default thumbnail. + +* Bugfix: Fixed some issues for gathering cached asset dependency data. + + * We no longer load dependency data that doesn't have the correct package name. + + * We no longer populate the dependency results when "Gather Depends on Data" is set to false. + +* Bugfix: Fixed an issue that prevented textures from updating correctly if a source texture with the same name as a texture asset is imported from a location that differs from the asset's original source image. + +* Bugfix: Fixed an issue where the Force Feedback "Play" and “Stop” icons weren't rendered correctly and would only be displayed when hovering over the asset or when the asset is currently playing. + +* Bugfix: The Content Browser file path will now update correctly if it is pointing to a path that is deleted through the Sources Panel. + +* Bugfix: Duplicating an asset will correctly name it if there is another one of the same name. + +* Moving a newly-created asset before saving it will no longer save an empty package in the asset's original location. + +* When reimporting multiple assets, the "Yes to All" and "No to All" dialog options will prevent future reimport dialogs from appearing for the same asset type in the same operation. + +* Improve visual of "Column View" in Content Browser. + +##### Cooker + +* Bugfix: Fixed an issue with the rebuild lighting commandlet not checking out files correctly. + +* Bugfix: Fixed an issue where running the same DLC profile created by the Mobile Patching Wizard would increase HTTP chunk size. + +* Bugfix: Fixed an issue with the cooker always cooking "All Maps" even when a single map was specified on commandline. + +##### Foliage + +* New: Added the Show Flag "Foliage Occlusion Bounds" in the Advanced menu to see the bounds generated by the occlusion tree. + +* New: When moving a foliage asset to a new Level, you will now be prompted to save the Foliage Type as an asset if it's a local asset. + +* New: Improved the Foliage painting algorithm to properly support Random Pitch/Yaw when the setting "Collision with World" is enabled. + +* Bugfix: Fixed a crash that occurred when moving the mouse over certain content while in Foliage mode. + +* Bugfix: Fixed an issue that cause foliage thumbnails to incorrectly be duplicated if many of them are onscreen at once. + +* Bugfix: Fixed an issue where removing a Foliage Type wouldn't properly refresh the Details panel. + +* Bugfix: Fixed an issue where the foliage location would shift when using undo/redo transactions. + +* Optimized the occurrence of rebuilding the occlusion tree when performing actions in the editor. + +##### Landscape + +* New: We now automatically fill Landscape with the first created Landscape's Layer Info object. + +* New: Added sorting to Landscape Target Layer tabs. You can now sort by Material definition (which is the default one), alphabetical, or custom a using drag-and-drop operation. + +* New: Added a visibility toggle to only show the used Target Layers by the loaded components. + +* Bugfix: Fixed a crash when changing multipole Landscape Blend Layer nodes from Weight blend to Height blend. + +* Bugfix: Fixed an issue with user Landscape shortcuts not working in the Level Viewport. + +* Bugfix: Fixed an issue when performing an Undo action would delete the newly created Landscape and return back to the new Landscape window. + +* Bugfix: Fixed an issue where Landscape holes (visibility mask) was causing NavMesh problems at the borders of the Landscape component. + +* We have improved when a Level will be marked as dirty when manipulating a Landscape Spline. + +* The Landscape tools Material synchronisation has been updated between game thread and render thread. + +* When adding a new Component, if a Landscape info object exists it will determine which one is used based on its neighbors. + +##### Material Editor + +* Bugfix: Material Custom nodes that contain "tab" characters will now correctly display tab characters after copy/paste. + +##### Matinee + +* Bugfix: Fixed an issue with how tooltips display when using a Material Function in your Material. + +##### PhAT + +* Bugfix: Fixed "Multiple Values" being displayed in Body Setup properties when single bone has multiple bodies + +##### Sequencer + +* New: Added the ability to specify additional Event Receivers for Level Sequence Actors. + +* New: Event tracks can now be defined to trigger events at the start of evaluation, after objects are spawned, or at the end of evaluation. + +* New: Added the ability to retrieve bound objects from Blueprint. + +* New: There have been improvements to the Binding overrides. + + * Added the ability to override spawnable bindings. + + * Added the ability to override bindings in sub Sequences. + + * Deprecated "Get Sequence Bindings" node in favor of "Get Sequence Binding", which is more robust, and provides a better UI/UX for selecting single bindings + + * Added Drag/Drop support for Binding overrides. + +* New: Added the ability to specify Event Receivers on Event Tracks. + + * These are defined by right-clicking on the Event Track in the Sequencer tree, and adding Event Receivers. + + * Such objects must be defined within the Sequence hierarchy (as well as parents, children, grandchildren etc). + +* New: Added a reworked, more generic property path handling system in the Sequencer object change listener. + +* New: Unlocked the Cine Camera Post Process Depth of Field to use options other than CircleDoF. + +* New: "Pre Roll" and “Post Roll” are now exposed at the section level for all sections. + +* New: Enabled "Use Custom Start Frame" and “Use Custom End Frame” when rendering a single shot from the menu. + +* New: You can now set the fade color in the Track display. + +* New: Audio row heights are now also resizable by dragging on the bottom end of the track lane in the track area view. + +* New: Sequencer now re-evaluates when starting PIE or Simulate. This can be disabled with "Bind Sequencer to PIE" and “Bind Sequencer to Simulate” in the Play-in-Editor Advanced settings. + +* New: Split "Snap to the Dragged Key" option into two options, "Snap to the Pressed Key", and "Snap to the Dragged Key". + +* New: Added a loop selection range. If there is no selection range, loop mode is restricted to loop or no loop. + +* New: Added hotkeys to set the selection range to the next and previous shot (page up, page down). Also, added hotkey to set the playback range to all the shots (end). + +* New: You can now set sequencer audio components bIsUISound to false so that they don't continue playing when the game is paused. + +* New: Added an option to instance sub sequences when creating a Master Sequence. + +* New: Notify streaming system prior to Camera cuts by default. To enable, users will need to enable the Pre Roll section of the Camera cuts for the streaming system to activate prior to cutting to cameras. + +* Bugfix: Fixed a crash when selecting keyframes in the viewport. + +* Bugfix: Fixed a crash with Sequencer Recorder when clearing properties to record. + +* Bugfix: Fixed an issue where tick prerequisites were not being set up for Actors streamed in from a streaming Level. + +* Bugfix: Fixed an issue where Sequencer was animating objects from the wrong world. + +* Bugfix: Fixed an issue with event parameter structs being able to be garbage collected, resulting in NULL structs potentially being written out. + +* Bugfix: Fixed an issue with animation looping in Sequencer. + +* Bugfix: Fixed an issue with Sequencer Recorder to fix duplicate components getting recorded. + +* Bugfix: Fixed an issue with FBX import with camera and light animation key imports. + +* Bugfix: Fixed an issue with autokey not setting a keyframe for Slate color with the specified color. + +* Bugfix: Fixed an issue for filtering to include Child nodes. + +* Bugfix: Fixed an issue where the Sub Track node deletion so that all sub tracks aren't deleted, only the row being requested. + +* Bugfix: Fixed an issue to invalidate expired objects when Blueprints are compiled. This fixes Actor references to now handle sections that need to have their GUIDs updated (ie. attach tracks). + +* Bugfix: Fixed an issue so that when finishing a scrub, playback status is now correctly set to stopped rather than set to a stepping state. + +* Bugfix: Fixed a missing command binding alt-r to record selected objects into sequencer. + +* Bugfix: Fixed an issue to Filter hidden functions, which fixes a bug where the field of view property for a cinematic camera appears to be animatable,. It should be hidden just like it is in the property editor. + +* Added a warning when Sequencer tries to write to properties that have changed type. + +* Sequencer templates are now always regenerated on load + +* Level Sequence frame snapshots now take account of fixed-frame interval offsets, and overlapping shot sections on the same row. + +* We now convert Linear Color to Color for fade to get the correct fade color in viewport. + +* Audio waveforms now show peak samples with smoothed RMS in the center. + +* Set max tick rate when in game if force fixed interval playback is enabled. + +* Cache player fade state so that restore state will return the values to the pre animated state. + +##### Source Control + +* Bugfix: Fixed an issue with Git plugin to update the status on directories hotfix. + +* With the Git plugin, use use asynchronous "MarkForAdd" and "CheckIn" operations for the initial commit. + +* Allow binary files in Git stored via git-fat, git-lfs, etc to be diffed. + +##### Static Mesh Editor + +* Bugfix: The camera position now stays in place after reimporting from inside the Static Mesh Editor. + +##### Traps + +* Subversion binaries have been updated to 1.9.5. They should no longer crash when used. + +##### VR-Editor + +* New: Improved functionality for the VR Mode: + + * Improved the look and feel of the rotation gizmo handles while in VR Mode. + + * Improved interaction for painting terrain, foliage, and mesh painting. + + * Improved gizmo handle animations. + +* New: VR Mode is now bound with the Editor Sound settings. + +* New: VR Mode motion controllers now have collision when in simulate. + +* Bugfix: Fixed VR Mode selection now to respect a component's "Is Selectable" state. + +* Bugfix: Fixed an issue with not being able to open a project in the Project Browser with VR Mode auto-entry enabled and the HMD active. + +##### Windows + +* New: Custom Depth can now be enabled for Landscapes + +* Bugfix: Fixed an issue with Landscape spline segment splitting when using streaming levels. + +* Bugfix: Fixed an issue with Landscape painting in orthographic viewports when the painted area's Z value was below 0. + +##### World Browser + +* Bugfix: Fixed an issue when moving a sublevel in World Composition browser does not appear in Undo History. + +##### World Outliner + +* New: Actors in the World Outliner will now bring their children with them when moved into a newly created folder. + +#### Gameplay Framework + +* New: Added an option for components to opt out of physics impulses on damage using "Apply Impulse On Damage". + +* New: Exposed component's "Ignore Radial Impulse" and “Ignore Radial Force” flags to Blueprints. “Ignore Radial Impulse” is now properly respected when applying impulse to relevant movement components. + +* New: The Player Controller's "Should Perform Full Ticket When Paused" can now be set from Blueprints and the Details panel. + +* New: Spawn Sound and Force Feedback Blueprint nodes now have a "Auto Destroy" pin that can be set to false to allow the component to be reused after the sound/pattern complete. + +* New: The number of buttons that can be used by Raw Input is now 20. + +* New: Fields of Attribute MetaData are now editable. + +* New: In the Ability System, the "Cancel Ability" has been exposed to Blueprints. + +* New: For Cameras, support has been added for specifying a default aspect ratio and whether or not to constrain to it in a Camera Manager subclass. + + * Normally the information would come from a Camera component, but this is useful when using custom view logic that doesn't source from a Camera component as the view target. + +* New: Added "​On Component Collision Settings Changed Event" delegate to Primitive Component. Fixed Skeletal Mesh Component not calling Super implementation for “On Component Collision Settings Changed”. + +* New: Refactored Character Movement Component determination of net send rate when combining moves into a virtual function Get Client Net Send Delta Time. Added configurable values to Game Network Manager under ​[/Script/Engine.GameNetworkManager] in BaseGame.ini: "ClientNetSendMoveDeltaTime", “ClientNetSendMoveDeltaTime”, “ClientNetSendMoveThrottleAtNetSpeed”, “ClientNetSendMoveThrottleOverPlayerCount”. + + * This replaces the values that were hardcoded in the network code for characters and enables easier configuration of client send rates for movement. + +* New: We've increased Pawn location replication precision to 2 decimal places from 0. Prevents replicated pawns from being inside geometry by a large amount. Removed CVars controlling CharacterMovement proxy shrink amount and made those instanced properties on the component. + +* New: Added a flag to Character Movement Component to determine whether or not character should Sweep while using "NavWalking", instead of relying on Generate Overlaps flag. + +* New: Added "Apply Gravity While Jumping" flag to Character Movement Component. This helps to reduce Framerate Dependent Jump Height issues when disabled, but raises jump height. This is disabled by default. + +* Bugfix: Fixed a crash due to null World Settings when rendering a thumbnail. + +* Bugfix: Fixed a crash when opening Blueprint after adding a component to native class referenced by a Child Actor Component. + +* Bugfix: Fixed several issues with renaming or deleting Gameplay Tags from the Gameplay Tag Project Settings page. + +* Bugfix: Fixed an issue when calling "Set Visibility" or “Set Hidden In Game” all children of the component will now properly be reconsidered as to whether they should render. + +* Bugfix: After duplicating an Actor, components added to the source instance will now have the correct position in the duplicate. + +* Bugfix: Ability actions can now be properly bound to input components. + +* Bugfix: Construction scripts will no longer be incorrectly rerun on Actors in a level that was hidden and then later made visible again. + +* Bugfix: Fixed an issue warning about invalid world content when loading maps with child Actor components in it. + +* Bugfix: Fixed cases where built lighting on child actors could be lost when loading a level. + +* Bugfix: Fixed case where child actor template was not cleared when setting child actor class to null. + +* Bugfix: Fixed issues with seamless travel in PIE and sub-levels shared between different Persistent Levels. + +* Bugfix: Fixed issues where Child Actor Component's "Parent Component" would be null on the client. + +* Bugfix: Fixed accumulated forces in Character Movement applied incorrectly when movement mode or active state changes. + + * Added ​"Clear Accumulated Forces” + + * "Add Force" and related functions now avoid adding the force if in Movement Mode is set to "None". When ticking in "None", forces are cleared so they don't pile up until the next valid movement mode. Forces are also cleared if the updated component changes or when the capsule simulates physics. + + * "Deactivate" implemented to stop movement and call “Clear Accumulated Forces”. + + * "Clear Accumulated Forces" now also clears pending launch velocity. Exposed “Clear Accumulated Forces” to Blueprints. + + * "Apply Accumulated Forces" does not call ”Clear Accumulated Forces”, since that would prevent pending launch. + + * "Add Force" and “Add Impulse” now also check that character movement is active (not deactivated, able to tick). + + * "Simulate Movement" handles pending launch and clears forces regardless of whether it's simulated proxy. + + * Inlined Actor Component "Is Active" for performance. + +* Bugfix: Fixed characters sliding when landing on slanted surfaces or stairs, when aggressive "Perch" settings could cause a line trace (from the center of a capsule) instead of capsule trace and thereby screw up the floor distance checks. + +* Bugfix: Fixed the case of people moving a Character mesh in Begin Play rather than in the Editor or Construction Script and not having the mesh offset reflected correctly in network games. + + * Added function "Cache Initial Mesh Offset" to cache initial mesh offset, used as the target for network smoothing. This takes location and rotation params so you can be explicit on the values, in case you try to change these during network smoothing, where reading the relative offsets would be skewed. + + * Added a call to this function from Begin Play in addition to the existing call from "Post Initialize Components", and exposed this to Blueprints as well for custom changes to mesh offset at runtime. + +* Bugfix: Fixed an issue with Projectile Movement Component continuing to simulate (and generate hit events) after it is deactivated during simulation. "Has Stopped Simulation" function now checks if “Is Active” is false. + +* Bugfix: Fixed an issue with "Get Welded Bodies" so that it properly returns Skeletal Bodies, instead of the default body for Skeletal Mesh Components. + +* Bugfix: Fixed an issue with infinite jump on client when Jump Max Hold Time is not 0. + +* Stop dynamic force feedback when initiating Actor is destroyed. + +* Clarified the tooltip on the "Inverse Lerp" function. + +* In the Movement Component "Deactivate" calls “Stop Movement” to clear cached velocity. + + * It was undesirable that reactivation many seconds or frames later would restore a stale velocity. + +* The "Collision.ListComponentWithResponseToProfile" command now includes pending kill objects. Use this to inspect collision responses between objects in a game world. + +* Optimized the Math Library "Get Forward Vector" (converts Rotator to forward direction). This way we avoid building a matrix, and avoids 1 more SinCos call. + +#### Learning Resources + +##### Sample Content + +* New: ShooterGame now supports dedicated servers on PC, Mac, and Linux! + +#### Localization + +* New: Improvements to culture switching and LocRes files. + + * LocRes files now de-duplicate translations when they're generated, which can result in smaller LocRes files. + + * The localization compilation step now produces a LocMeta file, which contains meta-data specifying the native culture during compile, and where the native LocRes file can be found. + + * Changing cultures now loads the native localization data prior to loading the non-native translations to ensure that translations are always applied to a consistent base. + + * The "leet" culture (available when localization testing is enabled) is now always applied against the native translation, and correctly restores non-translated text when switching away from the "leet" culture. + + * "-culture=leet" now works correctly on the command line ("-leet" also works). + + * LoadLocalizationResourcesForCulture is no longer called multiple times during initialization of the text localization manager. + +* New: Updated Fast Decimal Format to support the correct 0-9 numerals for the current locale + + * These are typically still Latin, but Middle Eastern languages have some variants. + + * This addresses an inconsistency between FText formatting of numbers and dates (since numbers always used Latin, but dates used the culture correct numerals). + +* New: Split the monolithic culture concept in UE4 + + * UE4 has historically only supported the concept of a single monolithic "culture" that applied to both text localization and internationalization, as well as all asset localization. Typically the "culture" was set to the "locale" of the OS, however that could be undesirable or incorrect on platforms (such as newer versions of Windows) that have a distinct concept of "language" (for localization) and "locale" (for internationalization). + + * This change splits the concept of "culture" into "language" and "locale", and also adds the concept of "asset groups". The language is now used to work out which localization we should use, and the locale is used to control how numbers/dates/times/etc are formatted within our internationalization library. + + * Asset groups expand on the language used by asset localization and allow you to create a group of asset classes that can be assigned a different culture than the main game language. A typical use-case of this would be creating an "audio" group that could, for example, be set to Japanese while the rest of the game runs in English. + + * If your game doesn't care about the distinction between language and locale, and doesn't need to use asset groups, then you're able to continue to use "culture" as you always have. If, however, you do care about those things, then you'll likely want to avoid using the "culture" directly (as it's now a very aggressive setting that overrides all others), and instead favor using language/locale (games will typically treat these as the same) and asset groups as separate concepts (both in settings, and in your in-game UI). + + * The language or locale for a game can be controlled by settings within the "Internationalization" section of your configs (this would typically be set in your Game User Settings config, in the same way that "culture" works), eg) + + [Internationalization] + language=fr + locale=fr + + * The asset groups for a game can be controlled by settings within the "Internationalization.AssetGroupClasses" and "Internationalization.AssetGroupCultures" sections of your configs (the asset group class definition would typically be set in your DefaultGame config, and the cultures the groups use would typically be set in your Game User Settings config), eg) + + [Internationalization.AssetGroupClasses] + +Audio=SoundWave + +Audio=DialogueWave + [Internationalization.AssetGroupCultures] + +Audio=ja + +* Bugfix: Fixed an assert that could trigger when an IME composition is aborted during widget destruction. + +* Bugfix: Fixed a crash that could happen if a config was loaded while the Gather Text commandlet was running. + +* Bugfix: Fixed text namespaces being treated as case-insensitive when exported to JSON manifests and archives. + +* Bugfix: Fixed text format history being clobbered by reference collection. + +* Bugfix: Fixed the pluralization of the decorator text during drag-and-drop operations. + +* Vastly reduced the number of allocations that happen when rebuilding text at runtime. + +#### Networking + +* New: Network dormancy efficiency has been improved greatly (if you have large number of dormant actors, they now will have less overhead). + +* New: Network consider/relevancy code is now also much more efficient. Overall, expect a 20+% improvement in performance if you have lots of Actors in the network Actor list. + +* New: Adaptive network update frequency logic is now on by default. This should improve network performance for games that weren't opt'ing in to this feature. + + * Net.UseAdaptiveNetUpdateFrequency is now 1 by default. + +* New: Replays now support network relevancy. + + * All connections are considered when determining if an Actor is relevant. + + * Enable by setting demo.UseNetRelevancy to 1. + + * Override cull distance with demo.CullDistanceOverride. + +* New: Added more info about the connection to logs when you see "FRepLayout::UpdateChangelistHistory: History overflow, forcing history dump" message. + +* New: Updated OnlineSubSystemNull to properly account for game state and "Allow Join In Progress". + +* Bugfix: Fixed a crash that could occur when updating unmapped objects. + +* Bugfix: Fixed an issue with IPAddressBSD validation when setting IP from string. + +* Bugfix: Fixed a memory leak in network drivers. + +* Bugfix: Fixed an issue with syncing of non-contiguious UENUMs over networks. + +* AActor "Pending Net Update" has been deprecated. Please use “Pending Net Update” that is now on FNetworkObjectInfo (obtained by calling “Get Network Object Info). + +* UNetDriver "Get Network Actor" is now deprecated. Use UNetDriver “Get Network Object Info” instead. + +* Disabled net.PartialBunchReliableThreshold for replays (we don't need to worry about bunch fragment sizes since there is no packet loss for replay connections). + +#### Online + +* New: Steamworks integration has been updated to support version 1.39, including updated steam controller support! + +* New: Web Browser module no longer directly depends on Online Subsystem plugins. + + * It uses the Online Engine Interface shim to explicitly depend on the engine and will use Online Subsystem features when that module is optionally added. + +* New: Added a new overload for Online Session "Find Friend Session" in the session interface that can retrieve sessions for multiple friends. + +* New: Sending and accepting invites on dedicated servers on Steam is now supported. + +* New: Updated OpenSSL libraries to use BCrypt on Windows in order to reduce memory allocations. + +#### Other + +* New: Added a "Buffering" media player event. + +* New: The Plugin Browser now supports customizations to allow for context-specific plugin creation. + +* Bugfix: Fixed a crash with Media Assets in "Tick Video" after media player is garbage collected. + +* Bugfix: Fixed an issue to prevent the default cooked sandbox from trying to read non-cooked assets. + +* Bugfix: Fixed a message router thread not being woken up right away on shutdown.Crashreporter uploads/downloads crash data from AWS + +* Search button is disabled after clicking it once to prevent accidental double-clicks. + +* Reading the config hierarchy for TVOS now matches IOS to get the correct bundle id when packaging a project + +#### Paper2D + +* Bugfix: Custom tile maps using collision can now be created at runtime on any platform without crashing. However on iOS/Android/HTML5 only the boxes and spheres used in the per-tile collision shapes have effect; arbitrary convex collision (e.g., slopes or other triangle-based collision) will not cause collisions or overlaps until support for PhysX runtime cooking is added to these platforms. + +* Bugfix: The Paper2D flipbook editor now shows the current frame correctly when the animation timeline is longer than the editor window and the scroll bar is moved to the right. + +* Bugfix: Paper2D flipbook editor now shows the correct number of frames; previously, it was one frame short. + +#### Physics + +* New: Added sprite to Physics Thruster Component (previously this was only available on Physics Thruster Actor). + +* New: Exposed "Set All Physics Angular Velocity" to Blueprints. + +* New: Added finer-grain PhysX stat information that is available by using "stat physxtasks". + +* New: Added the ability to specify whether a ragdoll is in the sync or async scene with "Use Async Scene". + +* New: Changed default contact-gen method to PCM. This is the default in PhysX 3.4. + +* New: Added "Is In Air" method to Vehicle Wheel. + +* New: For the Wheeled Vehicle Movement Component, the Mass dependent wheel properties now update when mass is updated. + +* New: Created "Add Force At Location Local" function to allow component space forces. + +* New: Added a new Physics settings "Enable Stabilization". Stabilization can help stacks of simulated bodies to come to rest. + +* Bugfix: Fixed a crash in anim dynamics when a world was not valid during pre-update. + +* Bugfix: Fixed a crash when saving sub-levels that don't currently have a correctly initialized scene. + +* Bugfix: Fixed an issue with incorrect slider for "initial Average Frame Rate" physics setting. + +* Bugfix: Fixed an issue with physics constraint warning messages in Message Log. These now list Component/Actor name correctly. + +* Bugfix: Fixed an issue with editing Box and Capsule collision primitive rotations by storing rotation as a Rotator rather than Quaternion. + +* Bugfix: Editing collision profiles in Editor Preferences no longer discards edits. + +* Bugfix: "Find Closest Bone" function no longer ignores the “Required Physics Asset” option. + +* Bugfix: Fixed an issue teleport not working for physical animation component. + +* Bugfix: Fixed an issue incorrect inertia tensor computation for cubes, which was being doubled. + +* Bugfix: Fixed an issue with kinematic body interpolation in substepping causing invalid raycasting, sweeping, or overlapping. + +* Bugfix: Physics Constraint component now works as expected when its target is a Child Actor component. + +* Bugfix: Fixed an issue with collisions between components with CCD enabled having unreliable behavior. + +* Bugfix: Fixed an edge case where generating collision data could cause the engine to hang in an infinite loop. + +* Bugfix: Fixed a regression with Raycasts against Capsules returning invalid hits. + +* Bugfix: Instanced Static Mesh now properly creates physics state when set to Stationary. + +* Bugfix: Fixed a memory leak caused by keeping PhysX shapes in memory after they are no longer being used. + +* Expanded self-collision culling for clothing by providing a scale to tweak the culling queries. This makes a tradeoff between performance and accuracy. + +* Added a guard against infinitely thin geometry, which fixes some NANs. + +* Performance improvements to Anim node "Rigid Body". + +* Physics performance is improved by skipping the update of kinematic bodies when they haven't moved. + +#### Platforms + +* New: Add logging for the NUI GPU reserve so we can see when it's enabled and disabled. + +* New: Exposed JAVA_HOME setting in Android SDK Project Settings on Mac. + +* New: Added "Platform Handle Splash Screen" to deal with hiding splash screen properly on Startup Movies. + +* New: Implemented support for new controllers (Xbox Wireless, SteelSeries Stratus XL, PS4). + + * Note: there are two implementations for Xbox Wireless due to differences in firmware. Firmware before 3.1.1221.0 does not use standard mapping which you can enable by setting the Android.OldXBoxWirelessFirmware CVar to 1 (defaults to new firmware). + +* New: Added support for "r.ScreenPercentage" on mobile allowing the game scene to be rendered at lower resolution than the UI. Requires MobileHDR to be enabled. + +* New: On-screen warnings now appear when a mobile shader permutation required to correctly render the current scene's lighting setup has been disabled in Project Settings. + +* New: Made some big DeviceProfile changes, particularly for the protected platforms. + + * Changed the "type" of some DPs from WindowsNoEditor, etc to Windows. It should be a platform, not a random string. + + * With that change, the platform can be used to save out protected platform DP .ini files to subdirectories, maintaining secrecy + + * Added Config/[PlatformName]/ConfidentialPlatform.ini files so that the DP loading code knows to look in their directories for DPs. See FGenericPlatformMisc::GetConfidentialPlatforms() for more information. + +* New: When uploading a HTML5 project to AWS S3, it now supports "signature version 4" authentication and better error message feedback on upload failures. + +* New: Added "use fixed timestep" setting option for HTML5 builds (This has been separated from Engine > General Settings - Framerate). + + * This is slightly different to "Smooth Framerate" and “Fixed Framerate”. + + * NOTE: Fixing the timestep does not guarantee the actual framerate. Calculations based on delta time may be adversely affected by this. + +* New: Added iOS/Android support for new Audio Mixer. + +* New: "Does Save Game Exist" will now show a message if the save data is corrupt. + +* New: Initial support for voice chat in the Android platform. To use enable the Voice module in DefaultEngine.ini, in the level bp create a session, and in project settings > Platforms > Android > Advanced APKPackaging, check the setting 'Add permissions to support Voice chat (RECORD_AUDIO)'. After this create a multiplayer game between two android devices. For more information check pull request #2894. + +* Bugfix: Fixed a crash with mobile feature level preview when the Low Quality Lightmap shader permutation is disabled. + +* Bugfix: Fixed a crash in clothing on platforms that don't support clothing. + +* Bugfix: Fixed a crash when backgrounding or sleeping on iOS Metal devices. + +* Bugfix: Fixed a crash with UIImagePickerController. + +* Bugfix: Fixed an issue with executable path for stripping Android debug symbols (handle non-Windows properly). + +* Bugfix: Fixed memory reporting for Uniform Buffers in "stat rhi". + +* Bugfix: Fixed a slow memory leak in FD3D12UniqueDescriptorTable. + +* Bugfix: Fixed rendering of batched Slate primitives in D3D11.x. + +* Bugfix: Fixed an issue with S3 public link generator for "Shipping" builds filename. + +* Bugfix: Fixed an issue with iOS IDFV string allocation. + +* Bugfix: Fixed UPL processing on iOS plist files. + +* Bugfix: Fixed network byte ordering for iOS multiplayer sessions. + +* Disabled the game analytics anonymous usage data sent to Epic on the console platforms. + +* Save 66MB of memory by disabling the unused default SHAPE heap in XAudio2. + +* Stop the audio thread from using the 7th CPU core as it can be pre-empted and not get enough execution time. + +* Add -distribution when iOS distribution Packaging. with IPhonePackager.exe. + +* Changed mouse cursor to be always visible when running in Mobile Preview. + +* Refactored memory allocation functions (BinnedAllocFromOS) on all platforms. Made Binned2 malloc work on Linux. + +##### All Mobile + +* Bugfix: Fixed a crash in mobile patching utilities mount method. + +* Bugfix: Fixed an issue with the shader compile for Landscape on platforms below SM4 feature level. + +##### Android + +* New: Bad package names are now detected and APK generation is stopped with a proper error message instead of failing during Java compiling. + + * Package names with fewer than 2 segments are not allowed (e.g., "myproject" is not allowed, but “com.myproject” is legal). + + * Only alphanumeric characters and underscore are allowed in the package name (Note: hyphens in the project name will be converted to underscores, but any other hyphens need to be corrected in Android project settings). + + * All segments must start with a letter; if your project name starts with a letter you will need to replace the [PROJECT] part of the package name in Android project settings. + + * Reserved Java keywords may not be used as the full segment; appending an underscore or other legal characters will fix this. + + * Segments may not be empty (e.g. "com..myproject" is not legal). + +* New: Larger OBB files embedded in APK are now allowed by bypassing Asset Manager. + +* New: We've implemented a first pass of Google Cloud Messaging plugin. This is considered an experimental feature for this release. + +* New: Added missing key codes for keyboard input (@ and #). + +* New: Added a drop-down with some common console commands on Android to the console dialog. + +* New: Patches ant.bat to handle long command line issue on Windows. + + * Copies original ant.bat to ant.orig.bat and writes a new ant.bat which uses subst with an unused drive letter to shorten paths). + + * Note: you can edit the generated ant.bat if you need to change the drive letter used; the editor will not replace it if ant.orig.bat is found. + +* New: Editor now checks to make sure that at least SDK Android-23 is selected and installed. There will be an error message if an earlier version is installed. + +* New: Updated AAR handling to deal with versioning, subproject dependencies for resources, and scope (ignore test). + +* New: Added "Game Activity On New Intent Additions" section to Android Unreal Plugin Language (UPL). + +* New: Added support for using native virtual keyboard with Slate widgets instead of the dialog currently used for text input. + + * Events are triggered when the virtual keyboard is shown and hidden. + + * The show event includes the area of the screen that is covered by the virtual keyboard. + + * This feature is exposed in the Android Project Settings as an experimental feature checkbox. + +* Bugfix: Fixed a crash that could happen when closing the Android web browser. + +* Bugfix: Fixed an issue to handle spaces in ANT_HOME path in generated ant.bat patch. + +* Bugfix: Fixed an issue with application hanging on returning from the lockscreen if orientation is Landscape. + +* Bugfix: Fixed an issue to correct the log warning about Target SDK and permissions. + +* Bugfix: Fixed an issue with Launch On when multiple architectures are enabled in the project. + +* Bugfix: Fixed an issue with ad banner location on Android 7.0 devices. + +* Bugfix: Fixed some documentation errors in UnrealPluginLanguage.cs. + +* Bugfix: Fixed the executable path for stripping Android debug symbols for non-Windows platforms. + +* Bugfix: Fixed an issue with password hiding in input dialog. + +* Bugfix: Fixed an issue with EGL linking issues for ARM64 libraries. + +* Bugfix: Fixed an issue to save and restore texture filtering for movie playback in all cases. + +* Bugfix: Fixed an issue with Mac and Linux install and uninstall scripts if ANDROID_HOME is not set. + +* Bugfix: Fixed an issue with ShowLoginUI interface change in Game Circle plugin. + +* Bugfix: Fixed an issue with HTTPChunkInstaller texture format checks and missing #define warning. + +* Bugfix: Corrected AndroidManifest.xml required features for "Daydream and Cardboard" option when GoogleVR plugin enabled. + +* Bugfix: Fixed an issue to prevent inserting extra permissions into AndroidManifest.xml multiple times from Project Settings. + +* Bugfix: The correct APK file name is now used when launching from editor for Android. + +* Bugfix: Fixed issues with experimental keyboard. + + * Ensure the local scope ScreenRect passed into "On Virtual Keyboard Shown" in AndroidJNI is captured by value instead of by reference. + + * Moved ShowVirtualKeyboardInput's "Keyboard Showing" early-out checks into the UI thread task. This enables the keyboard to continue showing when changing focus between multiple Editable Text Box widgets. + +* Bugfix: Fixed an issue with locations on non-ARMv7 GoogleVR libraries so that it is properly filtered by active architecture. + +* Bugfix: Fixed an issue to properly restore state for Android devices not using separate context for movie playback. + +* Bugfix: Removed an obsolete warning with Java 1.5. The java.source and java.target are now set to 1.7. + +* Only disable Java console command receiver for Shipping builds. + +* Build configuration is passed to UPL for access during packaging as $S(Configuration). + +* Reenabled GooglePlay for ARM64 now that it doesn't crash. + +* Changed Gear VR installLocation to auto as now required by Oculus. + +* Rebuilt ICU libraries for Android with timezones enabled and updated build scripts. + +* Android media player now pauses and resumes with application state. + +* "Is Packaging For Daydream" only returns true if GoogleVR plugin is enabled. + +##### HTML5 + +* New: Emscripten toolchain has been upgraded to 1.37.9. + + * Web assembly + + * WebGL 2 + +* New: There has been an update to GameX template. + + * Multiple (parallel) downloads with progress percentage updates. + + * Test for wasm and WebGL 2 capabilities. + +* New: Updates to python build scripts. + +* New: Configurable .ini settings have been exposed to the editor. These can be found in Project Settings > Engine > HTML5. + +* New: Added support for emscripten "-pre-js" and “-post-js” option when building for HTML5. + +* New: Added support for WebGL 2 shader to turn on Instance Static Mesh Vertex Factory. + +* Bugfix: Fixed an issue with AWS S3 shareable link for shipping builds. + +* Bugfix: Fixed some issues with WebGL 2 shaders. + +* Bugfix: Fixed an issue with HTML5 plugin when Blueprint projects are promoted to code projects automatically. + +* The recommendation from emscripten developers is to use "-separate-asm" option for asm.js builds. + +* Added many new UE4 patches to package HTML on Linux. + +* Since connections are not closed manually (server side), send a dummy payload with content-length data. + +##### Import/Export + +* New: Set Java source and target to 1.7 (fixes Java 1.5 obsolete warnings). + +* New: Added support for changing the variable "r.MobileContentScaleFactor" at runtime on Android. This is useful for device-specific resolution tweaking. + +* Bugfix: Fixed an issue where HTML5 video in a Web Browser widget would only output sound but no video on Android. + +* Bugfix: Fixed an issue where the red and blue channels were reversed in screenshots taken on Android in Vulkan mode. + +* Disabled eglSwapInterval since it can cause issues with some drivers. + +* Changed text for Android Mobile Deferred Renderer setting to indicate that it's only supported on Nvidia K1 and X1 devices. + +##### iOS + +* New: As we move towards the next version of iOS, we will be moving towards 64-bit support only. We have added messaging in this release to start the process of this migration. + +* New: IOS now utilizes the Library/Caches directory to save any data on device. This includes logs and save games. IPhonePackager has been updated to pull the data from this location as well as the Documents directory. + +* New: Xcode 8.3 is properly supported in this release. + +* Bugfix: Fixed a crash if Text Box widget is closed before text is finished being entered. + +* Bugfix: Fixed a crash in the OnlineSubsystem when it is disabled on iOS. + +* Bugfix: Fixed an issue with static audio noise on iOS devices. + +* Bugfix: Fixed an issue with remote compiling by unconverting the path back to host when reading from the module file name. + +* Bugfix: Fixed a memory leak on texture creation with Bulk Data in OpenGLTexture.cpp. + +* Bugfix: Fixed an issue with the device profile names for iPad Pro 9.7 and 12.9. + +##### Linux + +* New: Added pooling of OS allocations on Linux, greatly reducing the need to call mmap/munmap() and avoiding running into vm.max_map_count limit when loading large projects. + +* New: Install of MIME types during setup is now supported. + +* New: UnrealPak is no longer included in the default make target, the prebuilt binary will be used instead. + +* Bugfix: Fixed a crash in ShaderCompileWorker due to misaligned strings. + +* Bugfix: Fixed starting Linux programs using FPlatformProcess::CreateProc() from a path with space. + +* Bugfix: Fixed various issues with Vulkan RHI on Linux. + +* Bugfix: SlateDlg now appropriately compares filter extensions in a case-insensitive way, so both *.fbx and *.FBX work. + +* Bugfix: Fixed bogus "unable to make config file writable" message (the operation was actually succeeding). + +* Bugfix: Fixed clang 4.0 warnings. + +* Bugfix: Fixed inability to rebuild lighting in ResavePackages commandlet on Mac and Linux. + +* Bugfix: Fixed some problems when working from directories that have space character in their names. + +* Bugfix: Fixed older versions of Linux cross-toolchain (ones using LINUX_ROOT instead of LINUX_MULTIARCH_ROOT) not being detected. + +* Bugfix: Fixed a memory leak in callstack symbolication on Linux. This makes memory profiling work again. + +* Bugfix: Fixed an issue with Linux editor splash screen image being wrong when no project has been opened. + +* Bugfix: Fixed MoveFile to work across file systems. + +* Bugfix: Removed redundant RootDir() and EngineDir() on Linux. + +##### Mac + +* New: Enable Metal Shader Model 5 support on Intel as of 10.12.4 and later. + +* New: On Macs that do not support Metal, but erroneously report that they do, show a message box that tells users that the application cannot run instead of crashing on a failed assert. + +* New: Removed Mac OpenGL RHI files and disabled building of OpenGL RHI on Mac. + +* New: Limited support added for exposing debug events to Apple's Instruments "Points of Interest" tool. + +* New: Added RHISetResourceAliasability_RenderThread to FDynamicRHI for RHIs to implement simple render-target aliasing. + +* New: Added FApplePlatformObject, a custom block allocator for Objective-C types (with NSZombie support) which is now used in Metal RHI to decrease allocation costs of Objective-C types. + +* New: Limited support for Xcode automatic code-signing for iOS/tvOS. + +* New: Reimplement RQT_AbsoluteTime for Metal using a similar emulation to OpenGL on Mac so that the scalability system can correctly set the default graphics options. Not all drivers support this and in those cases the scalability settings are determined by an alternative, fixed, code-path. + +* Bugfix: Fixed mouse position issues in fullscreen mode on Mac. + +* Bugfix: Fixed an issue in Avf Media Player causing looped movies to only play once. + +* Worked around Metal's lack of implicit type-casting that was causing incorrect rendering in the Distance Field Ambient Occlusion and Shadows shaders. + +* Re-ordered the options in MetalRHI's internal debug options (Console Variable: "rhi.Metal.RuntimeDebugLevel") to make it more efficient. + +* Minimisation of render-target changes in some passes, notably Scene Occlusion and DBuffer Decals. + +##### Tools + +* Bugfix: Fixed a rare crash with the Web Browser widget on iOS. + +* Bugfix: Fixed iPhonePackager errors in output log when opening Project Settings on Windows. + +* Bugfix: Fixed Get Max Samplers returning an incorrect value for iOS OpenGL, which could have suppressed some warnings for shaders that used more than 8 samplers. + +* Removed duplicate gc.MaxObjectsInGame setting in IOSEngine.ini. + +##### Windows + +* Bugfix: Fixed a problem on Windows where the cursor would get locked to a part of the screen after switching from fullscreen to windowed while the cursor was unlocked. + +#### Programming + +* New: Added an experimental Android option to enable Shipping builds with hidden symbol visibility by default. (bBuildWithHiddenSymbolVisibility). + + * Add JNI_METHOD for java accessible native functions, without this java will trigger an unsatisfiedlinkerror exception. + + * This can significantly reduce the size of the final .so file. + +* New: Added support for map file generation with Android. + +* New: Crash reporter is no longer staged by default when packaging from the editor. The default endpoint for crashes was an Epic server, so including it in packaged games by default was not useful. + +* New: Script plugins can now specify dependencies which should trigger UnrealHeaderTool to be re-run, by overriding the IScriptGeneratorPluginInterface.GetExternalDependencies() method. + +* Bugfix: Fixed a crash where Canvas wouldn't update font engine services if it was never created. + +* Bugfix: Fixed an issue with Automation Tool exception when running Perforce commands if multiple brokers are present in the server configuration. + +* Android links with -gc-sections to remove unused code/data. + +* Program targets can now be excluded from the full solution build roster by setting bBuildInSolutionByDefault to false from their .target.cs file. + +#### Rendering + +* New: Added support for Window PIX. + +* New: Enabled support for NVIDIA Aftermath. On Aftermath enabled executables you can now get a GPU callstack when a GPU crash is detected. + +* New: Enabled support for global Distance Field shaders on GL 4.3 and Vulkan SM5. + +* New: Added support for Quad overdraw viewmode in the Forward Renderer. + +* New: Add support for per-component Skeletal Mesh skin weight overrides. + +* New: Added /VIRTUALIZEDIRECTX option to XgConsole for XGE shader compiling to work on remote machines without DX installed. + +* New: Added support for Structured-Buffer resource views to Metal RHI. + +* New: Added AMD path to experimental D3D11 HDR support. + +* New: Exposed the r.DisableDistortion cvar for toggling distortion rendering. + +* New: The high level rendering code is now PipelineStateObject aware which will allow us to reduce complexity in the rendering backends of Vulkan, Metal and Dx12 in the future. + +* New:Added FShaderCodeLibrary which handles de-duplication of shaders during content cooking and the shader code has moved into a separate library for cooked content runtime loading. This reduces package sizes and load-time overhead. + +* New: Added RHIShaderLibrary for platform specific native shader library implementations. This allows each platform to provide its own optimal shader library implementations. + +* New: Added Metal (MacOS and iOS) native shader library where shaders are loaded from a single Metal library improving the memory footprint, load time, and runtime compile times. + +* New: As part of the cook process for Metal, the archiving process also generate text shaders that can be used when running with optimized Metal shaders. Run with optimized shaders and while debugging with text source. + +* New: Added command line option "-noheartbeatthread" to disable heart beat thread. + +* New: Full refactor of the GPU Skin Cache to fix multiple issues related to Editor, Persona, per-frame numbering. Memory limit is now set per World in the Project Settings > Rendering section. + +* New: ShaderCache now supports running with multithreaded rendering. Command line flag "-norhithread" is no longer required to enable this feature and can now be removed if it was being used solely for this purpose. + +* Bugfix: Fixed a crash with D3D12 in "Update Texture 2D". + +* Bugfix: Fixed an assertion failure in basepass when trying to draw a mesh with Post Process Material. + +* Bugfix: Fixed a crash when the Tile Renderer renders before any other renderer. This could happen in rare cases on Editor bootup. + +* Bugfix: Fixed a crash accessing mesh Material arrays with invalid index. + +* Bugfix: Fixed a potential crash when rendering to accessible buffer. + +* Bugfix: Fixed a possible crash when failing to import cubemaps. + +* Bugfix: Fixed a crash for MacOS/Metal when compiling Materials using the Vector Noise node. + +* Bugfix: Fixed overflow issues that could occur on mali based devices when rendering DoF with bright objects. + +* Bugfix: Various Vulkan fixes: + + * Compiles in Linux. + + * Many cubemap issues squashed. + + * Changed the scratch reflection cubemap clear to SetRenderTargestsAndClear, instead of SetRenderTarget() / Clear(). + + * Added compute fences. + +* Bugfix: Fixed several sRGB related issues with Retainer Box widget. + +* Bugfix: Fixed an issue with prepass/basepass z-fighting, caused by bad vertex welding in depth-only indexbuffer. + +* Bugfix: Fixed an issue with velocity rendering when an off axis projection matrix changes from frame to frame. + + * Affects very few people. Cave rendering and stereo glasses but not HMDs. + +* Bugfix: Fixed an issue with scene motion blur data is only updated for the main renderer frames. Fixes scene captures and planar reflections breaking object motion blur. + +* Bugfix: Fixed an issue with Exponential Height Fog where it renders incorrectly after world origin rebasing. + +* Bugfix: Fixed an issue introduced into 4.15 where Static Meshes with auto-generated LODs were no longer sharing lightmaps between LODs. + +* Bugfix: Fixed bug converting a Procedural Mesh component to a Static Mesh if it only contains a single triangle. + +* Bugfix: Fixed an issue where Scene Capture 2D's show flags would not be applied properly in some circumstances. + +* Bugfix: Fixed an issue where the "disable Stationary Skylight" feature would cause improper warnings. Also made it so that a movable Skylight is always used in Persona preview window so all projects can get preview lighting. + +* Bugfix: Fixed an issue where High Quality Particle Lights would not move properly if their parent was attached to a socket of an animated skeleton. + +* Bugfix: Fixed detection of OpenGL Radeon driver on Mesa. + +* Bugfix: Fixed an issue with shot command in Vulkan. + +* Bugfix: Fixed an issue with refract() intrinsic handling in hlslcc for GL/Metal/Vulkan. + +* Bugfix: Fixed an issue with missing Mobile Material Interface for Landscape "Used Materials" check. + +* Bugfix: Fixed rare case where Decals could incorrectly draw a second time in separate translucency pass. + +* Bugfix: Fixed a bug with the basic eye adaptation mode that could result in incorrect brightness when using a small viewport. This has no effect on the default histogram version of eye adaptation. + +* Bugfix: Fixed an issue with Separate Translucency being affected by Gaussian DoF. + +* Bugfix: Fixed an issue with "Streaming Bounds" show flag not working correctly. It now shows the texture streaming bounds for the textures currently selected in the Content Browser. + +* Bugfix: Fixed possible stall when canceling texture updates. + +* Bugfix: Fixed an issue for tone mapping of bright objects with zero green. Previously, these could have had a one-pixel black outline. + +* Bugfix: Fixed an issue with the IES Light Profile importer with LM-63-1986 format. + +* Texture flags are now properly routed to RHICreateTexture3D from the render target pool. + +* Collection Parameter Nodes no longer rename parameters when duplicated. + +* Renamed console variable "r.Streaming.ScaleTexturesByGlobalMyBias" to "r.Streaming.ScaleTexturesByGlobalMipBias". + +* Now when using the "freezerendering" command, the foliage culling/occlusion will also be frozen. + +* Optimize the computation behind the Screen Position material expression in the pixel shader. + + * Exposes the viewport offset of the view within the render target in the View Property material expression. + +##### FX + +* Bugfix: Fixed an issue with rendering corruption issue with 4 and 8 vertex instanced particles using the wrong Vertex Factory objects. + + * D3D didn't need separate Vertex Factories due to the VertexDecl updating the stride at draw call time, but some platforms were affected. + +##### Lighting + +* New: Improved quality and significantly faster cubemap prefiltering for reflections and skylight. + +* New: Post Process Indirect Lighting Intensity no longer scales Skylight reflections. + +* New: Screen Space Reflections (SSR) now has a higher quality setting for sharp SSR when using Quality Level 4. + +* New: Distance field self shadowing controls for hiding world position offset self-shadow artifacts. + + * Removed Static Mesh Build Settings "Distance Field Bias", which shrunk the distance field, breaking AO and shadows. + +* New: Distance field mesh visualization now uses a cone containing the entire tile to cull objects with, making the results stable. + +* New: Distance field temporal filter stores a confidence value, which is used to track leaking of occlusion during the upsample, and flush those leaked values through the history faster. Reduces DFAO ghosting when the camera is moving. + +* New: Added some new features to the Skylight component. + + * "Occlusion Exponent" which is useful for brightening up indoors without losing contact shadows as “Min Occlusion” does. + + * "Occlusion Combine Mode" which is useful for artists to choose how to combine SSAO with Distance Field Ambient Occlusion. + +* New: Added "r.AOListMeshDistanceFields" which dumps out mesh distance fields sorted by memory size, useful for directing content optimizations. + +* New: Planar reflections handle views smaller than the render target in a general way. + + * Fixes planar reflections with adaptive pixel density (ViewFamily size larger than actual views combined). + + * Planar reflections are now supported in splitscreen. + +* New: Support for fading of Light Propagation Volume cells towards the volume edges. + +* Fresnel of clear coat layer now darkens diffuse for the clear coat shading model. + +* SSR is now reprojected correctly on moving objects. + +* Raised High ShadowQuality to 2048 as 1024 for CSM is too low. + +* Disabled all distance field features on Intel cards because the HD 4000 hangs in the RHICreateTexture3D call to allocate the large atlas. + +##### Materials + +* New: Added a "Sign" material graph node which replaces the library function for more optimal translation. + +* New: Added MinimalAPI to several material expressions. + +* New: Updated default behavior of "Power" node to no longer “abs” or “max” against an arbitrary value as the results were incorrect. + + * Previous version available by calling ClampedPow(x, y) in a "Custom" node. + +* New: Improved material translation preservation of constants. + + * This improves detection of used attributes which prevents some cases of features being enabled incorrectly. + +* New: Material flag normal curvature to roughness now works in the Deferred Renderer. It is no longer forward only. + +* New: Improved Material graph error messages. + +* New: Enabled "r.Streaming.UsePerTextureBias" by default as a way to improve quality in low texture budget settings. + +* Bugfix: Fixed errors across various library Material Functions. + +* Bugfix: Fixed an issue with broken size query for render targets in Material graphs. + + * Implemented missing "Get Size" functionality. + +* Bugfix: Fixed various data type inconsistencies on legacy Make and Break Material Attributes graph nodes. + + * Using these together with the "Get" and “Set” Materia lAttributes nodes should now be more forgiving. + +* Bugfix: Fixed a regression in HLOD shadow casting performance. + +* Bugfix: Fixed inconsistent results with the "Investigate Texture" commands. + +* Bugfix: Fixed possible incorrect results when listing textures used by Material Instances. + +* Bugfix: Fixed an issue where Material Reroute nodes did not bind properly to Texture Object Parameters. + +##### Mobile Rendering + +* New: Mobile Skylights no longer render the scene on the device to determine the sky's color. Mobile skylight uses values determined via captures performed in the editor. This saves memory and performance on device and enables Skylight contribution on devices that do not support fp16 render targets. + +* New: Added "r.Mobile.TonemapperFilm" console variable which can be used to enable/disable new filmic tonemapper on Mobile devices, independently from Desktop platforms (disabled by default). + +* New: Material AO is now supported for the Mobile Rendering path. + +* New: Added better defaults for rendering resolution on iOS devices, to make them more inline with defaults on Android devices. + +* Bugfix: Fixed a crash that could occur on some devices when loading materials which use fonts as texture parameters. + +* Bugfix: Fixed a crash with Particle Cutouts on mobile devices that don't support hardware instancing (ie. Mali-400 GPU). + +* Bugfix: Fixed a crash when enabling shader cache on NVIDIA Shield devices. + +* Bugfix: Fixed a crash when previewing feature level ES3.1 with a Material using World Position Offset. + +* Bugfix: Fixed a crash with Media Player on iOS devices. + +* Bugfix: Fixed an issue with Static Mesh self-shadowing with modulated shadows. + +* Bugfix: Fixed several issues that could cause CSM shadowing on mobile devices to flicker. + +* Bugfix: Fixed an issue with scene captures on mobile when Mobile HDR is disabled and the scene capture source is Scene Color. + +* Bugfix: Fixed an issue with bright dynamic point lights cause bloom rendering artifacts on Android Mali devices. + +* Bugfix: Fixed an issue where Landscapes do not render on some Android PowerVR devices. + +* Bugfix: Fixed an issue where translucent object appear black on Zenfone5. + +* Bugfix: Fixed an redundant blend state change in OpenGL ES2. + +* Bugfix: Fixed rendering artifacts with bloom on iPhone7 using Metal. + +* Bugfix: Fixed an issue where exposure was more extreme on mobile devices with a new filmic tonemapper enabled. + +* Bugfix: Fixed an issue with padded NPOT textures not rendering correctly on iOS. + +* Bugfix: Fixed an issue with gamma issues with canvas elements on iOS Metal devices. + +* Significantly reduced OpenGL state setup for Slate draw calls on Mobile devices. + +* Slate pixel shaders will use half precision, for better UI performance on Mobile devices. + +* Mobile targeted projects will have better UI performance settings by default. + +##### Optimizations + +* New: Added 'r.CompressMeshDistanceFields' console command to rendering project settings, defaults to off to prevent hitches when streaming in levels. + + * When enabled, mesh distance fields are stored zlib compressed in memory until needed for uploading to GPU. + + * 81Mb of backing memory -> 32Mb in GPU Perf Test. + + * Atlas upload time 29ms -> 893ms. + +* New: Added a new global distance field (4x 128^3 clipmaps) which caches mostly static primitives (Mobility set to Static or Stationary). + + * The full global distance field inherits from the mostly static cache, so when a Movable primitive is modified, only other movable primitives in the vicinity need to be re-composited into the global distance field. + + * Global distance field update cost with one large rotating object went from 2.5ms -> 0.2ms on 970GTX. Worst case full volume update is mostly the same. + +* New: Added LOD Distance Factor to Scene Capture Component, which can be used to make scene captures and planar reflections much cheaper to render if the scene has good LODs setup. + +* New: Added the r.LightMaxDrawDistanceScale console command for local light scalability. + +* New: Added a rendering project setting to use 8 bit mesh distance fields. + + * This halves their memory requirement but introduces artifacts with large meshes. + +* New: Added new async tasks to reduce the cost of the texture streaming update on the game thread. + +* New: Added some automatic callbacks whenever dynamic component renderstates are updated in order to also update their texture streaming states. + +* Bugfix: Fixed async SSAO not actually running asynchronously when depth drawing mode was DDM_AllOpaque. + +* Bugfix: Fixed render queries stalling in Test/Shipping builds due to lack of pooling. + +* Ray Traced Distance Field Shadow optimized. + + * From 1.8ms -> 0.8ms in a test scene. + +* Use 16 bit indices for distance field objects culled to tiles, when 16 bit will be enough. This saves 10mb of tile culling buffers. + +* GNM RHI Clear UAV uses a compute shader for buffers larger than 1Kb. + +* GNM Structured buffers are now placed in GPU memory (was previously in CPU memory). + +* DFAO optimizations: + + * Changed the culling algorithm to produce a list of intersecting screen tiles for each object, instead of the other way around. Each tile / object intersection gets its own cone tracing thread group so wavefronts are much smaller and scheduled better. + + * From 3.63ms -> 3.48ms (0.15ms saved). + + * Replaced slow instructions in inner loop with fast approximations (exp2 -> sqr + 1, rcpFast, lengthFast). + + * From 3.25ms -> 3.09ms (0.16ms saved). + + * Moved transform from world to local space out of the inner loop (sample position constructed from local space position + direction). + + * From 3.09ms -> 3.04ms (0.05ms saved). + +* Structured buffers for DF object data. + + * Full global distance field clipmap composite 3.0ms -> 2.0ms due to scalarized loads. + +* Exposed MaxObjectsPerTile with the 'r.AOMaxObjectsPerCullTile' console command and lowered the default from 512 to 256. This saves 17Mb of object tile culling data structures. + + * This can cause flickering in Ray Traced Distance Field shadows if too many objects fall into one shadowmap culling tile. + +* Scene color resolves are restricted to the views. This fixes inefficiency with adaptive pixel density where the views don't match the view family size. + +* When using a full prepass, the base pass no longer writes depth. + + * Saves 0.3ms of Scene Depth Resolve on 970 GTX with MSAA. Also allows masked materials to get EarlyZ in the base pass. + + * Fixed primitives with Use As Occluder set to false being excluded from a full depth pass in static draw lists. + + * Added the "r.BasePassWriteDepthEvenWithFullPrepass" console command for verifying that the base pass depths match the prepass depths. + +* Changing movable skylight properties no longer affects static draw lists. + +* Mesh distance field generation uses Embree, which provides a 2.5x speed increase. + +* Cleared light attenuation for local lights with a quad covering their screen extents. + + * Clearing the entire light attenuation buffer costs 0.1ms. This optimization lowers the minimum cost of a shadow casting light from 0.15ms to 0.03ms. + +* Flushed deferred deletes when reallocating distance field atlas to reduce peak memory, at the cost of a hitch on first frame. + +* Disabled point / spot lights with Max Draw Distance on Low PC. + +* Made use of Metal's "Deferred Store Actions" where available to avoid incorrect “Store” actions introduced when restarting passes to switch encoder types or when using the Metal RHI debugging tools. + +* Stopped the Shader Cache recording all the RHI resources unless it is running on OpenGL. This significantly reduces the CPU overhead of enabling the Shader Cache. + +* HLOD texture force loaded through the "r.Streaming.HLODStrategy" console command will now load visible mips first. + +* The command "BuildMaterialTextureStreamingData" can now be used with "all" as argument to force a rebuild. + +* Reduced the texture streaming overhead for components by keeping track of the state within the streamer. + +##### Postprocessing + +* New: Using Custom Depth to write to the stencil buffer now has the ability to use single-channel bitmasks that ignore depth. This makes it possible to detect overlaps between stencil objects. + +* Bugfix: Fixed log value conversion in tonemapping causing true blacks to be lost. + +* Motion blur no longer gets dark at the edges of the screen. + +#### UI + +* New: Added API to programmatically change the Virtual Cursors UMG Widget on the Viewport Client. + +* Bugfix: Fixed sRGB conversion issues in Retainer Box when used with a material. + +* Multiline editable text boxes can now be marked as read-only. + +* Selecting multiple text widgets will now correctly set text when the text field is edited. + +* Widget Components will now correctly determine between hover and clicked states when using or simulating touch. + +##### Slate + +* New: Added Enum Has All Flags and Enum Has Any Flags, templated functions to make it easier to check for the existence of a flag on enum classes. + +* New: There is now a console variable option, Slate.VerifyHitTestVisibility (off by default), which enables additional visibility checks for widgets. Normally this is not necessary, but if you are changing the visibility of widgets during a frame, and several hit tests need to be performed that frame, there is a chance that a button could be clicked twice in one frame. Enabling this mode will make all hit testing more expensive, so for now it is off by default, but available for licensees that need the extra testing. + +* New: Added the ability to invert alpha when drawing slate textures. This will be used in the future for rendering render targets for the scene which have inverted alpha. + +* Bugfix: Fixed a crash during editable text widget destruction while a context menu was still open. + +* Bugfix: Fixed a crash when deleting a streamed font. + +* Bugfix: Fixed lots of outline data being added to the font cache due to wrongly hashing outline material and color data. + +* Bugfix: Tooltips will no longer show if the cursor is not directly over a Slate window. Fixed a case where the tooltip would not disappear when the cursor is moved over another application's window that was placed on top of a Slate window. + +* Bugfix: Fixed an issue where the cursor would sometimes not appear when its visibility was changed. This was rooted in how the OS requested cursor changes, WM_SETCURSOR on Windows only asks for new cursors when the mouse moves, but often cursors change just because mouse capture changes. So now the path has been centralized in Slate Tick to only handle the cursor changes in one place, and several places that need to refresh the cursor state, now set a flag to handle it on next tick. + +* Bugfix: Fixed a bug with ZOrder being discarded on the SOverlay slot. + +* Bugfix: Fixed Web Browser Viewport to properly scale. + +* Bugfix: SButton now correctly releases mouse capture even if it becomes disabled while pressed, but before 'click' has been fired. + +* Improved text rendering when the last resort font is missing. + + * The last resort font is no longer included in shipping builds, so this change makes some improvements to text rendering when it is missing. + + * The legacy font cache no longer tries to use the last resort font if it is not available (preventing warnings). + + * The Slate font renderer no longer tries to use the last resort font if it is not available. + + * Text shaping will use the last resort character if none of the available fonts can render a given character (likely because the last resort font is missing). + + * HarfBuzz shaped text now uses the fallback character correctly. + +* Kerning-only text shaping no longer draws characters to get their metrics. + +* Text selection height is now the maximum of the line height and text height to account for negative line-height scaling. + +* Added a setting to control whether we should use the font metrics or the bounding box when laying out a font. + + * Not all fonts have accurate metrics data, so using the bounding box can produce much better results for certain fonts. + +* Made slate loading widget / movie playback more thread safe by eliminating Slate application or the main window from being ticked directly on another thread. Is In Game Thread will also no longer return true when called from the slate loading widget thread. + +* Force resolution in standalone if the resolution is larger than primary working area. + +* Moved ESlateDrawEffect & ESlateBatchDrawFlag over to be enum class. Found cases where the enum order was being improperly assumed, and so now it will not be possible to just treat an int32 or a bool as the draw effect value. + +* Slate Application now maintains separate tracking for each pointer being utilized for drag drop, so now multiple fingers on multiple widgets can now simultaneously be attempting a drag, however once one of them becomes successful, we clear all state of all other tracking since only one Drag Drop operation is possible at a time. + +* Fold Tick is now removed from the codebase. We have not supported the other (non-folded) code path for awhile, so there was no point in maintaining the switch. + +* The Checkbox widget no longer just passes visibility down to the internal widgets it creates, that prevents future changes to affect it if it starts collapsed. + +##### UMG + +* New: Added Timing Policy option to Widget Component, so widgets can optionally tick in pausable/dilatable game time rather than real time. + +* New: Added a material function that exposes all of the current UV sets with nice names instead of indexed coordinates. + +* New: Added a method to create Slate Brushes from Paper Sprites the same way we can for materials and textures in blueprints. + +* New: Introduced PreConstruct and Native PreConstruct to the base User Widget. Users can now visualize non-binding based changes in the designer by evaluating a very limited amount of the blueprint code. In the event your user widget crashes on load, due to calling something unsafe, you can disable evaluation in the editor preferences under Widget Designer. + +* New: Introduced a way to inform widgets of more information about the designer. There is now a Designer Changed event sent to all design time widgets letting them know things like the current screen size and DPI scale. + +* Bugfix: Fixed a crash if UI blurs are rotated. + +* Bugfix: Outline color on text elements is now inherited properly. + +* Bugfix: Fixed a bug that prevented Get Owning Player in Widget from returning. + +* Bugfix: Additional fixes to the way we migrate changes from the preview to the serialized version of the widget tree in the widget editor. This fixes several issues with edit-inline Objects on Widgets. + +* Exposed a normalized (0-1) uv coordinate set and scaled pixel size for Box and Border brushes. + +* Widget Interaction Components now ignore Visible(false) Widget Components when tracing. + +* Widget animations now finish evaluating before firing an event alerting that the animation finished. + +* The Widget Interaction Component now checks if the Widget is enabled before it claims that it is over an interactable or keyboard focusable widget. + +* Adding some setters and getters for Redraw Time to the Widget Component. + +* Widgets projected into screenspace from the Widget Component should now appear in the correct locations if the player's camera has an aspect ratio lock. + +* The Safe Zone widget will now show the correct safe zone amount if you use the safezone command line options, which are now documented in the comment for the Safe Zone class. + +* Widget switchers that contain widgets with named slots will now correctly display a widget whose named slot is currently selected. + +* Widgets that are copied and pasted will now retain the same name in the widget hierarchy. + +#### VR + +* New: Added support for getting device depth from Scene Capture Component 2Ds. + +* New: Added ability to disable the autoloading splash screen, which would prevent the manual "hide splash screen" node from working properly. + +* New: Added Gear VR controller support. + +* New: Added support for OES_EGL_image_external to the mobile GL renderer. + +* Bugfix: Negative Stereo Layer priorities are now handled correctly on Steam VR. + +* Bugfix: Fixed threading issue with motion controller tracking that caused controller motion pops. This problem manifested intermittently. + +* Bugfix: Fixed crash on Oculus Rift when attempting to enter stereo mode while the HMD's 'on head' proximity sensor is not triggered. + +* Bugfix: Fixed low framerate when Oculus Rift 'on head' proximity sensor is not triggered and you exit stereo rendering. + +* The GearVR HMD plugin is now only enabled on Windows if the Oculus service is already running. + +* VR console commands have been rewritten to support autocompletion and inline help strings. + + * The VR console commands have also be renamed and now begin with vr.*. + + * The renamed VR commands have backwards compatible aliases, but will print a warning notifying the user about the deprecated functionality. + +* GoogleVR HMD now reacts to changes in the r.ScreenPercentage console command. + +* When the -hmd command line option is used to override the selected HMD, HMD plugins that are loaded early will now be unloaded during PreInit if not selected. + +* Integrated OpenGL support for SteamVR. + +* The left eye is used when selecting LODs to avoid selecting two separate LOD levels when rendering in stereo. + +* PSVR controller tracking limit management system. + + * PSVR can track the HMD and two controllers, but many more devices can be connected. With this system you can manage which controllers are tracked to stay under the limit. + +* Additional WorldScale refactoring for all platforms. + +* GoogleVR plugin updated to version 1.3 + +* Fixed Android manifest for Daydream and Cardboard. + +* Updated GoogleVR plugin to version 1.3. + +* GoogleVR SDK updated to 1.40.0. + +* GoogleVR Mode default changed to Daydream and Cardboard. + +## Programming Release Notes + +#### AI + +* New: Added a new mode to composite EQS generator (UEnvQueryGenerator_Composite), which allows the use of different types of items by each child generator. This can be enabled by advanced properties: bAllowDifferentItemTypes and ForcedItemType. ForcedItemType is the final type returned by the generator, and is used for allocating memory and executing tests. This mode is potentially unsafe and you will have to ensure proper memory layout (matching with ForcedItemType) of all item types used by child generators - usually subsets of ForcedItemType. Keep in mind that allocated memory block is zeroed before use. + +##### Debugging Tools + +* Bugfix: Fixed VisualLog macros for recording segments with user defined thickness. + +* Bugfix: Fixed compilation errors in VisualLog macros for recording custom meshes. + +##### Navigation + +* Bugfix: Fixed memory corruption in generic A* solver: FGraphAStar. + +* Bugfix: Fixed unique Id duplicates in custom navigation links. + +* Bugfix: Fixed FRecastTileGenerator::Modifiers being erroneously counted twice when stating memory. + +* NavModifierVolume has been marked as ENGINE_API and can now be freely used in game code. + +* Made FNavAgentProperties::GetExtent return INVALID_NAVEXTENT if a prop's AgentRadius is not set. This results in properly using FNavAgentProperties::DefaultProperties in navigation queries when no query extent override is provided. + +#### Animation + +* New: Added more exports to AnimationAsset, AnimSequenceBase, and Skeleton classes. + +##### Animation Blueprint + +* Bugfix: Fixed nodes only getting CopyNodeDataToPreviewNode called when pin defaults were changed (not any property change). + +##### Skeletal Mesh + +* New: Added exports to FFbxImporter, FDynamicSkelMeshObjectDataCPUSkin, and FSkeletalMeshObjectCPUSkin, for extensibility. + +#### Audio + +* New: Added new cvars to help with optimization (only applies to the new Audio Mixer). + + * au.DisableReverbSubmix, au.DisableEQSubmix, ​au.DisableParallelSourceProcessing, au.SetAudioChannelCount + +* Bugfix: Fixed MIDI Device plugin public headers not being able to be included from an external module. + +* Optimized internals of new Audio Mixer. Gains approach 15% savings from before: + + * Turned a float divide into a multiply, which occurred at least 32k times per audio update. + + * Avoided thousands of Array.Add() calls during processing, which on shipping still does checks to see if the allocator has to grow, and updates ArrayCount. + + * Removed pointer indirection and successive TArray Add()s in GetChannelMap(). + + * Removed function call overhead to updating channel map. + + * Simplified FSourceParam::Update() to reduce branching and have one return site. + + * Added alternative to GetChannelMap() called UpdateChannelMap() that avoids copying out values to an array. The values can then be fetched from the channel data directly. + + * Refactored internal data to use array of structs rather than struct of arrays for better cache coherency when processing channels one at a time. + +#### Blueprints + +* New: Added an error when declaring a Blueprint Implementable Event with an enum param that is not plain or a byte type (Blueprints only support byte-sized enums). + +#### Core + +* New: There are now several serialization options available to specify what the cooked Asset Registry includes. Look for the serialize flags inside the [AssetRegistry] section of BaseEngine.ini. + +* New: An experimental bUseAssetRegistryForIteration option has been added to CookerSettings. This improves the performance of iterative cooking by loading the cooked Asset Registry directly, but it may still have issues with some changes to source files being missed. + +* New: Added a cvar to control the pak precacher throttle. + +* New: Added new GenericPlatformFile function, GetTimeStampLocal, which returns file time stamp in local time instead of UTC. + +* New: Added a check against assembling the reference token stream while streaming without locking the garbage collector. + +* New: Added a static_assert to prevent the use of TMap keys which do not implement GetTypeHash, as this causes runtime crashes when they are manipulated by a UMapProperty. + +* New: Added a bForceDebugUnrealHeaderTool option to BuildConfiguration.xml which forces the Debug version of UnrealHeaderTool to be run instead of Development. + +* New: Added a static_assert to ensure that TInlineSetAllocator is instantiated with a power-of-two hash size, as this is a requirement for TSet and TMap. + +* New: Added ICppStructOps::IsAbstract() for testing if a native type is abstract via the property system. + +* Bugfix: Fixed TInlineValue not calling virtual destructors. + +* Bugfix: Fixed several issues with editor-only objects not being correctly stripped when cooking. + +* Bugfix: Fixed several issues with Config files loaded from Plugins. They now correctly handle diffing game-specific changes. Engine plugins config files should be named BasePluginname.ini, and game plugins should be DefaultPluginname.ini. + +* Bugfix: Fixed many bugs with the event driven loader and allowed it to work at boot time. + +* Bugfix: Fixed a bug with nativized Blueprints that was introduced with the boot time EDL changes. + +* Bugfix: Fixed race in audio streaming. + +* Bugfix: Fixed bug which would cause a fatal error when cooking subobjects that were pending kill. + +* Bugfix: Fixed a bug with EDL at boot time which caused a fatal error with unfired imports. + +* Bugfix: Fixed a bug with RF_PendingKill subobjects and the new loader. + +* Bugfix: Fixed an obscure problem with stats in commandlets that use async tasks. + +* Bugfix: Fixed rare ensure cooking for the EDL. + +* Bugfix: Fixed boot time EDL causing some issues even when it wasn't being used. + +* Bugfix: Fixed .pak precacher shutdown. + +* Bugfix: Fixed memory leak in .pak precacher. + +* Bugfix: Fixed bad merge of priority change in the EDL. + +* Bugfix: Fixed race that resulted in a memory leak when reading compressed paks. + +* Bugfix: Fixed a weird recursive situation where StaticLoadObject could return an object that has not finished loading. Also produces a fatal error if this happens. EDL only. + +* Bugfix: Fixed batched render fences when BeginDestroy calls FlushRenderingCommands. + +* Bugfix: Fixed loading a package that is already loaded. + +* Bugfix: Fixed crash in signature checks when mounting pak files. + +* Bugfix: Fixed a change to NotifyPrimitiveDetached so that it works in the editor. + +* Bugfix: Fixed hash table lock optimization. + +* Bugfix: Fixed a crash relating to FGenericAsyncReadFileHandle when not using the EDL. + +* Bugfix: Fixed comments in GenericPlatform.h. + +* Bugfix: Fixed errors raised during code generation when a multiply-inherited base class happens to have the same name as a UObject after its prefix is stripped. + +* Bugfix: Fixed a compile error when calling TArray::HeapSort on an array of pointers. + +* Bugfix: Fixed a crash when calling UCookOnTheFlyServer::FFilePlatformRequest::ToString(). + +* Bugfix: Fixed compile errors raised when #pragma is used inside USTRUCTs. + +* Bugfix: Fixed compile errors caused by whitespace existing before a UCLASS() macro. + +* Bugfix: Fixed TStructOpsTypeTraits::WithCopy giving different results when the trait is specialized without a WithCopy value from when it isn't specialized at all. + +* Bugfix: Fixed a compile error when serializing bools to an archive in editor builds, where the archive type overrides other serialization operators. + +* Bugfix: Fixed FWorldTileInfo::Read() to copy the correct licensee version number from the file summary into the archive. + +* Bugfix: Fixed a regression in FObjectAndNameAsStringProxyArchive to re-allow serialization of TWeakObjectPtrs. + +* Bugfix: Fixed some include-what-you-use issues in the engine and plugins. + +* Bugfix: Fixed UPROPERTYs being skipped when there are redundant semi-colons between the properties. + +* Asset Registry memory and performance have been significantly improved in both Editor and cooked games for large projects. + +* Allowed UnrealPak to do a better job with EDL pak files when the order provided is old or from the cooker. + +* Several minor tweaks to low level async IO stuff. + +* Stored a copy of the callback in async read request so that we do not need to worry about lifetime so we can capture variables as needed. + +* Cancelling async loading with the EDL loader now prints a warning and does a flush instead. + +* Suppressed a few EDL cook warnings. + +* Tweaked the EDL for to all platforms. + +* Platform load time performance tweaks. + +* Abstracted the IO tracker and handle manager for other platforms and applied it to all platforms. + +* Protected against UDeviceProfileManager::Get() recursion and demoted a related fatal error to a log statement. + +* Removed old code relating to FAsyncArchive, FAsyncIOSubsystemBase and package level compression. The editor now uses the lowest levels on the new async IO scheme. + +* Increased estimate of summary size. + +* Avoided adding a linker annotation if it actually has not changed. This improves ConditionalBeginDestroy performance. + +* Avoided a redundant removal of PrimitiveComponent from the streaming managers during ConditionalBeginDestroy. + +* Optimized UObject hash tables for speed and space. + +* Put the special boot order things into baseengine.ini so that licensees and games can add to it. + +* Renamed HasBeenAlreadyMadeSharable to DoesSharedInstanceExist. + +* PostLoadSubobjects is now called on all objects regardless of whether they have a CDO as outer or not. + +* When Rename is used to change the Outer without specifying a new name, the existing name is maintained whenever possible. + +* ForwardVector, RightVector, and single float FVector constructors are now recognized by Unreal Header Tool as default values for an FVector parameter. + +* ScriptMacros.h no longers needs to be included in header files that generate a header. + +* Improved the readability of some of the ReferenceChainSearch code. + +* Automatically included ObjectMacros.h in generated headers to prevent compile errors. + +* Made FPaths::Combine() variadic so that it can take arbitrary numbers of arguments. + +* Improved the readability of the verbosity of log categories in the debugger. + +* Updated TArray::Sort comments to clarify what happens when sorting an array of pointers. + +* Clarified the assertion message you get when inserting or removing a TArray element by reference which comes from the array. + +* Clarified the comments for TArray::FindLastByPredicate and FString::FindLastCharByPredicate. + +* Removed UnrealCodeAnalyzer. + +* Raised an error in UnrealHeaderTool when a header containing UCLASSes, USTRUCTs etc. does not include its .generated.h file. + +* Removed TBoolConstant template. + +* Changed TAssetPtr to allow it to be constructed from nullptr without a full definition of T. + +* Removed the WITH_HOT_RELOAD_CTORS macro. + +* Removed the UseVTableConstructors .ini option. + +* Removed generated FName variables for UFUNCTIONs. + +* Removed the generation of obsolete .java and .proto files used for replication. + +* Replaced the set of bools used to FBlueprintCompileReinstancer with a new EBlueprintCompileReinstancerFlags enum. + +* Improved hot reload logging messages to make it clear that a compile attempt on a module does not guarantee a reload of that module. + +* Made UnrealHeaderTool report an error if a UFUNCTION in a derived class has the same name but a different signature from one in a base class. + +#### Editor and Tools + +* New: Added spinner options to VectorInputBox. + +* New: Added a None option to the FKey customization, unless the FKey property had NoClear on it. + +* Bugfix: Implemented a fix to ensure FVirtualTrackArea::HitTestSection checks the row of the section. + +* Bugfix: Fixed an issue where ISequenceAudioRecorder was inaccessible to FAudioRecorder. + +* Project and plugin templates now use "include what you use" style by default. + +* When using BuildGraph, the cached list of completed nodes is now cleared by default, making the -ClearHistory argument redundant. Use the -Resume argument to continue an interrupted build using the current artifacts. + +* BuildGraph now outputs an error if any build products from previous steps are tampered with during the execution of a subsequent step. + +* The editor now offers to download and install Visual Studio 2017 if an existing version of Visual Studio is not found. + +* The AutomationTool -CookDir argument no longer accepts multiple parameters separated by '+' characters, since '+' is valid in directory names. Multiple -CookDir arguments are supported instead. + +* Game mods can now be denoted by setting the bIsMod field to true inside the .uplugin descriptor. Mods will be shown in a separate category in the plugin browser, and will be shown separately in generated project files. Installed editor builds can build and clean mods without modifying build products for the base game. + +##### Content Browser + +* Bugfix: Fixed link error when FAssetData::PrintAssetData() is used in a project. + +##### Sequencer + +* Unified global and object-bound pre animated state, and added InitializeObjectForAnimation method to state producers. + +* Opened the API for MovieSceneAudio-related classes along with some minor functionality additions. + +* Exported MovieSceneTrackEditor to allow custom tracks to be created that derive from existing tracks. + +#### Gameplay Framework + +* New: Added support for FScopedMovementUpdate to be able to queue up overlaps that do not require reflexive bGenerateOverlapEvents. This requires custom code to be able to process these overlaps. + + * This allows custom inspection or processing of overlaps within a scoped move, without enabling the more expensive overlap flag. For instance you could have a fast projectile with an overlap response to a character mesh and get those overlaps from the trace without requiring expensive overlap processing when the mesh moves. + + * Overlap events from the move will still only trigger from UpdateOverlaps() if bGenerateOverlapEvents is enabled on both components, as before. + + * Made some data in FScopedMovementUpdate protected rather than private so it can easily be subclassed, and exposed a new helper ​SetWorldLocationAndRotation() for committing the move. + +* Bugfix: Fixed a crash when manipulating audio component properties from an Actor's constructor during async loading. + +* Bugfix: Fixed CharacterMovementComponent updates with very high delta time on server when initially joining. Made sure the ServerTimeStamp is initialized to current world time rather than zero to prevent large delta. + +* CheatManager functions to Damage/Destroy targets are now easier to override in game-specific subclasses. + +* InputComponent now has BindAction function that allows binding functions with additional parameters. + +* RawInput configuration structures can now be manipulated by other modules. + +* AActor::GetComponents() with generic type is now optimized to not force an allocation when the component count is large. + + * Previously it incorrectly assumed the output array needed space for the entire contents of OwnedComponents. If OwnedComponents.Num() > the array reserve size, this forced an allocation, even if few or no components of the requested type were found. + + * It is still recommended to use TInlineComponent array or an array using TInlineAllocator<> when using this function. + +* Removed allocations during creation in ​AAIController::PostInitializeComponents() (in non-shipping builds). + +* Optimized HasActiveCameraComponent() and ​HasActivePawnControlCameraComponent() to avoid filling an array while searching for a certain component, which could have caused an allocation. + +* Optimized MoveComponent() collision queries to avoid processing PhysX touches when bGenerateOverlapEvents is off. + + * Added support for bIgnoreTouches to FCollisionQueryParams. This allows GeomSweepMulti to filter out touches/overlaps much earlier. + +* MovementComponent does not ignore initial blocking overlaps when moving away from the impact normal from SafeMoveUpdatedComponent(). This fixes various cases where characters could be pushed through moving objects because they were moving away from the overlapping object, but not fast enough. + + * It now always uses the hit result to depenetrate from the impact as much as possible, and then retries the move. + + * Hit events are not triggered for the first test for depenetration. + +* CharacterMovement AdjustFloorHeight() is now allowed to adjust using the line trace if the sweep was in penetration. It also forces another next floor check so it will check after it adjusts the height or depenetrates, relevant when bAlwaysCheckFloor is off. + +* Optimized CharacterMovement tick to not extract transform values twice when they would not change in a small block of code. + +* Call TickCharacterPose() and clear root motion before abandoning tick in ​UCharacterMovementComponent::PerformMovement() when movement mode is None. This prevents root motion building up until the next valid movement mode. + +* Applied a performance tweak to ​ApplyRadialDamageWithFalloff(). + + * Do not rebuild FRadialDamageEvent each loop over hit actors. + + * Added stats for ​BreakHitResult()/MakeHitResult() under "stat game". + +* Optimized attachment to check welding option before expensive casts and body instance fetching. + +#### Localization + +* Bugfix: Fixed a bug where passing an empty FText to ChangeKey() would keep the previous FText value that had been passed in. + +#### Online + +* New: Added the bShowSkipButton parameter to IOnlineExternalUI::ShowLoginUI, which will display the "skip" button on relevant platforms. + +#### Other + +* New: Added missing initialization for SWindow::bIsMirrorWindow. + +* Bugfix: Added missing module dependencies. + +* Bugfix: Fixed a type casting issue. + +#### Physics + +* New: Added virtual keyword to DestructibleComponent ApplyDamage and ApplyDamageRadius. + +* New: Added Physx simulation shader override (see GSimulationFilterShader). + +* Bugfix: Fixed a debug rendering issue by recreating physics when changing mobility of components. + +* Bugfix: Fixed compile error when PHYSX_MEMORY_STATS=1. + +* Bugfix: Fixed performance regression caused by using collision aggregates for Instanced Static Mesh Component. + +* Bugfix: Fixed a crash in AABB Manager when origin shift is used. + +* Made UDestructibleComponent::SpawnFractureEffectsFromDamageEvent virtual. + +* Exported URadialForceComponent class for inheritance. + +* Allowed the editor to compile when bRuntimePhysicsCooking is disabled (cooking is still allowed in WITH_EDITOR builds even with it disabled). + +* EndPhysics tick will no longer be scheduled if QueryOnly is used on a ragdoll. + +* Removed the unsupported option of HideBone with DisableCollision when calling HideBone. This was not actually supported and did nothing so shouldn't break any behavior, just don't call the function. + +* Exposed PhysX enhanced determinism mode using the compiler flag PHYSX_ENABLE_ENHANCED_DETERMINISM. This allows local subsets of the PhysX simulation to behave deterministically independent of what is going on elsewhere in the Physics world. + +#### Platforms + +* Bugfix: Fixed a crash bug in cases where we received a duplicate user login/logout notification from the system software. + +* Bugfix: Fixed Codelite project having duplicated settings. + +* Moved some C++ defines out of the build.cs file into a C++ header. + +* Moved controller connect/disconnect handling to the main thread to fix issues with thread safety for callbacks. + +##### Android + +* New: Added functionality to use the visual studio mobile projects for debugging. To generate them run "generateprojectfiles.bat -vsdebugandroid" from a command prompt. After you have packaged your game for Development and put it on the device, you can set this new project as the start up project and run/debug the project in Visual Studio. + +* New: Support for Android runtime permissions added. Certain permissions have been removed or put under condition to check for support when the target sdk is greater than or equal to 23. + +##### HTML5 + +* New: Added new webassembly (wasm) toolchain - SIMD and multi-threading are not yet supported (these are slated to be in for wasm2). + + * These will be automatically turned off when building with wasm (as opposed to asm.js). + +* Removed HTML5 code from the Engine's SaveGameSystem.h and placed it in HTML5Platform.cpp. + +* Cleaned up HTML5PlatformFile.cpp and made it match as close as possible to linux's version. + +* Created HTML5's own PlatformFeature & SaveGameSystem files, and updated HTML5PlatformMisc to make use of the the new HTML5 SaveGame code. + +##### Linux + +* New: Added FreeBSD memory information functions to facilitate out-of-tree UE4 FreeBSD port. + +* New: Added a new cross-toolchain (version 9, includes clang 4.0) when targeting Linux on Windows. + +* New: Added some support for building on Debian Sid or Stretch. + +* New: Added clang to Fedora dependencies. + +* New: Added ability to compile Linux servers for 32-bit x86 architecture. + +* New: Added files generated for KDevelop to .gitignore. + +* Bugfix: Fixed more third party libraries to use libc++ instead of libstdc++. + +* Bugfix: Fixed memory leaks when symbolicating an address in Linux callstacks (during crash reporting and memory profiling). Makes runs with the memory profiler much faster. + +* Bugfix: Fixed rebuilding of VHACD (a third party library) on a case sensitive filesystem. + +* Bugfix: Fixed CodeLite projects to now use proper Debug binaries for debug configurations. + +* Switched Linux file abstraction to use new managed filehandles. Shared by all platforms with low limit of open files. + +* Whitelisted SteamVR plugin for Linux so SteamVR Blueprint functions are always available, even if stubbed. + +* Made source code accessor aware of clang 3.9 and 4.0. + +* Setup will now install the latest clang on Arch instead of clang35. + +##### Mac + +* Fixed address sanitizer support in MacToolChain (Apple changed the name of the env variable Xcode uses to enable it) and added support for thread sanitizer. + +* Fixed a problem where the glslang library was not enabled on Mac, preventing building an Android project with Vulkan from Mac. + +* Made Binned2 malloc work on Mac. + +#### Programming + +* New: When compiling a module written in include-what-you-use style, source files which are in the adaptive non-unity working set are now built with precompiled headers disabled, to expose errors with missing headers. Set bAdaptiveUnityDisablesPCH to false in BuildConfiguration.xml to disable this behavior. + +* New: Added initial support for async creation of pipeline state objects, enable using r.AsyncPipelineCompile. + +* Module .build.cs files, which depend on the contents of external files, can now add those paths to the ExternalDependencies list. Modifications to those files will trigger the the UBT makefile to be invalidated. + +* Plugin config files are now included in generated project files. + +* UnrealBuildTool will no longer attempt to use SN-DBS for build distribution if the service is disabled. + +* UnrealBuildTool now correctly supports compiling modular targets which do not use the shared engine build environment. + +* C# programs will now be included in generated project files automatically if a blank file called UE4CSharp.prog is found in the same directory. + +* The engine will now warn when trying to load a plugin with a mismatched "EngineVersion" setting. + +* Deprecated shared pointer typedef from ImageWrapper and removed usages. + +* Removed boilerplate header from ImageWrapper. + +* Removed monolithic boilerplate header from NetworkFileSystem. + +* Removed boilerplate header from LauncherCheck. + +* LauncherServices: Removed boilerplate header from LauncherServices. + +* Completed a modernization pass of Automation. + +#### Rendering + +* New: Added thickness option to debug DrawWireDiamond function. + +* New: Added a check to see if there are duplicated shader type names. + +* Bugfix: Fixed obscure check with flushing RHI resources. + +* Bugfix: Fixed hazard with SetMaterialUsage from a thread. + +* Bugfix: Fixed Windows handling of -sm4 and -sm5 so it can be used with -vulkan and -opengl. + +* Bugfix: Fixed selection of swapchain format for Vulkan on some Linux drivers. + +* Bugfix: Fixed an issue on Vulkan when copying into a cubemap face. + +* Bugfix: Fixed a bug calculating vertex declaration hashes on OpenGL. + +* Moved FPositionVertexBuffer & FStaticMeshVertexDataInterface declarations into their own headers, moved FStaticMeshVertexBuffer implementation into its own source file. + +* Updated Vulkan distributables and glslang to SDK 1.0.39.1. + +* Vulkan shaders now build using glslang 1.0.42.2 and includes those headers for redistribution. + +* Prefer D32_S8 on Vulkan instead of D24_S8 for the depth buffer. + +* Removed the temporary functions RHIClearColorTexture, RHIClearDepthStencilTexture and RHIClearColorTextures from each RHI. + +* Separated depth/stencil load/store actions. + +* Use the latest SDK for Vulkan, whether the one we distribute in ThirdParty or an installed version. + +* Implemented SetStencilRef() and SetBlendFactor() on RHIs which were missing it. + +#### UI + +##### Slate + +* Updated Slate to allocate widgets using MakeShared. + + * This saves one allocation per-widget. + +* Moved SVirtualWindow into Slate module from UMG. + +#### VR + +* New: Added an initial base implementation of IHeadMountedDisplay, FHeadMountedDisplayBase, that can be extended by HMD implementations instead of extending IHeadMountedDisplay directly. This base class provides default and or common implementations for parts of the IHeadMountedDisplay interface. Future releases may add more common functionality to this class, reducing the amount of work required to add support for new HMD platforms even further. + +* StereoLayers now have a default emulated implementation, making them supported on most VR platforms that did not already support them. HMD implementations that extend FHeadMountedDisplayBase will automatically inherit the functionality unless explicitly overridden. + +* Common code found in various HMD plugins handling management of StereoLayers has been extracted into a template base class, TStereoLayerManager, that provides a thread-safe way to manage a list of registered stereo layers. + +* The old Morpheus StereoLayers implementation has been removed in favor of the common stereo layers implementation provided by the HMD base class. + +## Upgrade Notes + +#### C++ API Changes + +* As part of the Asset Manager changes, Streamable Manager has been improved to support the concept of Streamable Handles. When requesting an async load, it now returns a shared pointer handle that will keep the requested object loaded as long as it exists. These handles can also be polled or waited on. + + * Synchronous Load and Simple Async Load on Streamable Manager have been deprecated in favor of the new Streamable Handle system. Both of those functions would keep assets loaded until explicitly unloaded, which in practice was not what most people wanted. + +* The Class/Property/Function redirect system has been rewritten to be faster and more flexible. Ini redirects such as "+ActiveClassRedirects" defined in [/Script/Engine.Engine] will still work, but the new system is used by putting redirects like “+ClassRedirects” in the [CoreRedirects] section of Engine.ini. + + * All engine redirects prior to 4.10 have been moved to CoreRedirects.cpp, newer redirects are now in the new format in BaseEngine.ini. + + * A single Property/Function redirect definition will now be applied for both blueprints and serialization, and redirects can now be defined with wildcard matching syntax to simplify large refactors. + + * Object and Package redirects can now be used to allow limited redirection of content references without creating an Object Redirector on disk. + + * Enum redirects have been improved and will now fully work with or without the Enum Name being specified. + +* Several Enum functions dealing with string conversion have been deprecated, and the names and comments have been cleaned up to make it more clear which are meant to be used at Runtime and which are meant to be used in the Editor/for debugging. + +* The console command "r.MSAACount 1" now produces no MSAA or TAA. “r.MSAACount 0” can be used to toggle TAA on for comparisons. + +* Cascaded Shadow Map resolution is now controlled by the console command "r.Shadow.MaxCSMResolution" instead of “r.Shadow.MaxResolution”. + +* New mobile targeted projects will have better UI performance settings by default. + + * Please enable "Explicit Canvas Child Z Order" option in project Slate Settings, to improve UI batching. Enabling this option may require manual Z Order tweaks in UMG Canvas panels if there Z ordering issues. + +* VR console commands have been rewritten to support autocompletion and inline help strings. + + * The VR console commands have also be renamed and now begin with vr.* + + * The renamed VR commands have backwards compatible aliases, but will print a warning notifying the user about the deprecated functionality. + +* The Exec method in Head Mounted Display has been removed, as all VR console commands now use Auto Console Command or similar to register console commands. + + * HMD implementations relying on having an Exec method now need to provide their own ways of registering console command handlers. + +* Set Visibility and Set Hidden In Game in Scene Component are no longer virtual. Instead override On Visibility Changed or On Hidden In Game Changed to respond to changes to these values. + +* The FBox and FBox2D constructors taking an int32 value have been deprecated as the value of that integer was not being used. The Force Init constructor should be used instead. + + * Replace FBox/FBox2D construction of the form FBox(0) with FBox(ForceInit). + +* The Unreal Header Tool now outputs an error when an Editor-only struct member is exposed to blueprints. This is necessary because packaged builds will crash if a Make/Break node for that struct is executed in a blueprint. + + * Any Blueprint exposed Editor-only struct members must either be made not Editor-only or no longer exposed to blueprints. + +* Post Load Map now provides the loaded World as a parameter to the delegate function. The World will be null if the load failed. + + * All existing functions bound to Post Load Map need to have a World pointer added to their signature. + +* Stop saving raw curve data into animations on cook to save memory/disk space. + + * If you are directly accessing Raw Curve Data on an Anim Sequence, this will no longer work in cooked builds. Animation Asset now provides a virtual function, Get Curve Data, to grab a reference to the correct Curve structure. + +* Removed boilerplate header from Automation Window. + + * The AutomationWindow.h boilerplate header file has been removed. Please replace all includes of AutomationWindow.h with IAutomationWindowModule.h + +* Removed boilerplate header from Automation Controller. + + * The AutomationController.h boilerplate header file has been removed. Instead of AutomationController.h, include the individual interface headers that you actually use. Remove the "Interfaces/" subdirectory from existing interface inclusions. + +* Automation Modernization pass + + * The IAutomationWorkerModule.h has been moved to the module's public root directory. Please remove the relative path from your existing include statements. + +* Removed boilerplate header from LauncherCheck. + + * The LauncherCheck.h boilerplate header file has been removed. Include ILauncherCheckModule.h instead of LauncherCheck.h. Remove "Interfaces/" subdirectory from existing ILauncherCheckModule.h inclusions. + +* Removed boilerplate header from LauncherServices. + + * The LauncherServices.h boilerplate header file has been removed. Instead of including LauncherServices.h, include the ILauncherXXX.h files that you actually use. Remove the "Interfaces/" subdirectory from existing ILauncherXXX.h includes. + +* Deprecated shared pointer typedef and removed usages from ImageWrapper. + + * The IImageWrapperPtr typedef has been deprecated. Please use TSharedPtr instead of IImageWrapperPtr. + +* Removed boilerplate header from ImageWrapper. + + * The ImageWrapper.h boilerplate header file has been removed. Instead of including ImageWrapper.h, include the actual IImageWrapperXXX.h files that you use. Remove the "Interfaces/" subdirectory from existing IImageWrapperXXX.h includes. + +* Removed monolithic boilerplate header from NetworkFileSystem. + + * The NetworkFileServer.h boilerplate header file has been removed. Instead of including NetworkFileServer.h, include the INetworkFileXXX.h headers that you actually use. Remove the "Interfaces/" subdirectory from existing INetworkFileXXX.h includes. + +* Changed default contact-gen method to PCM. This is the default in PhysX 3.4. + + * This may have slight implications on jitter and stability, but should be improved overall. The old behavior is still available (set EnablePCM = false in the project settings). + +* Removed the temporary functions RHIClearColorTexture, RHIClearDepthStencilTexture, and RHIClearColorTextures from each RHI. + +* Removed obsolete SmartCastProperty function. + +* Added a static_assert to prevent the use of TMap keys which do not implement GetTypeHash, as this causes runtime crashes when they are manipulated by a UMapProperty. + + * TMap key types must now implement GetTypeHash. Having GetTypeHash be implemented in a base class or being implicitly convertible to a type which is hashable is not sufficient. + +* Fixed TStructOpsTypeTraits::WithCopy giving different results when the trait is specialized without a WithCopy value from when it isn't specialized at all. + + * TStructOpsTypeTraitsBase has been deprecated. + +* Improved support for TTuple. + + * Tuples have a GetTypeHash function and can be used as a TMap key. + + * Can now be serialized to archives. + + * Can now be compared for equality with operators == and !=. + + * Can now be compared lexicographically with operators <, >, <= and >=. + + * TPair is now an alias for a 2-tuple, which is specialized to have Key and Value fields, but otherwise has the same functionality as all other tuples. + + * Tuple.h is now found in the Core/Public/Templates folder, rather than the Core/Public/Delegates folder. + + * TPairInitializer now converts to TPair, rather than TPair being constructible from TPairInitializer. + +* Removed UnrealCodeAnalyzer. + +* Added a static_assert to ensure that TInlineSetAllocator is instantiated with a power-of-two hash size, as this is a requirement for TSet and TMap. + + * TInlineSetAllocator will no longer compile if the hash size is not a power-of-two. + +* Removed TBoolConstant template. + +* Removed the WITH_HOT_RELOAD_CTORS macro. + +* Removed the UseVTableConstructors .ini option. + +* Removed generated FName variables for UFUNCTIONs. + +* Refactored EvaluateBoneTransforms to prevent usage of skeletal mesh component. + + * Deprecated EvaluateBoneTransforms in favor of new ​EvaluateSkeletalControl_AnyThread. + + * Deprecated skeletal mesh component argument to ConvertCSTransformToBoneSpace and ​ConvertBoneSpaceTransformToCS. Now they just take a transform. + +* Added a new overload for IOnlineSession::FindFriendSession in the session interface that can retrieve sessions for multiple friends. + + * Sending and accepting invites on dedicated servers on Steam is now supported. + + * The FOnFindFriendSessionCompleteDelegate now returns an array of FOnlineSessionSearchResult objects instead of just one. + +* The high level rendering code is now PipelineStateObject aware which will allow us to reduce complexity in the rendering backends of Vulkan, Metal and Dx12 in the future. + + * The loose state setting APIs of the Commandlist have been deprecated, instead the entire pipelinestate has to be set at once. + +* Moved controller connect/disconnect handling to the main thread to fix issues with thread safety for callbacks. + +#### Animation + +* When converting skeletal controls to the newer API, convert EvaluateBoneTransforms to ​EvaluateSkeletalControl_AnyThread. Backwards compatibility will be maintained, however warnings will persist. Any mesh component access should be cached in PreUpdate() as accessing the component is not thread safe. + +* If differences in timing between Maya and UE4 are experienced after importing Alembic files, this has been corrected. The fix requires that any problematic assets be reimported. + +#### Blueprints + +* The ticking behavior of latent actions in components has been changed to match how they behave in actors. When the component ticks, the latent actions will now be processed at the same time, rather than happening later in the frame when latent actions for non-ticking actors and components are processed. This does change behavior, so there is a console variable (t.TickComponentLatentActionsWithTheComponent) that can be used to revert to the older behavior until affected component Blueprints that depended on the old ordering behavior can be fixed up. The cvar should be treated as deprecated, and it will be removed in a future release. + +#### Core + +* To save on memory and disk space the cooked Asset Registry no longer includes Dependency information by default. If you need this information at runtime, enable bSerializeDependencies in the [AssetRegistry] section of BaseEngine.ini. + +* Starting asynchronous loads from within asynchronous loads has always been unsafe, but will now explicitly assert. This can be fixed by not starting asynchronous loads from within PostLoad functions, or deferring your game-specific code for a frame when called from an async callback. + +* Callback functions passed into Request Async Load will now execute on the next frame instead of immediately upon completion of an async load. This behavior is to avoid issues with calling async loads recursively, but if your game depends on this behavior you can restore it to call them immediately by setting the cvar s.StreamableDelegateDelayFrames to 0. + +* There is a new format for defining class/function/property redirects in ini files, check the [CoreRedirects] section of BaseEngine.ini for examples. The older formats will still work but the new format provides additional features and a simpler syntax so you may want to upgrade. + +* Any calls to Smart Cast Property should be replaced with code which explicitly handles the inner property of Array Property. + +* Get Type Hash implementations must now be added to types which are used as TMap keys. If your type defines Get Type Hash in a base class or is hashed via an implicit conversion, these should be fixed by implementing their own function and forwarding the call to the appropriate implementation. + +* Any use of TStructOpsTypeTraitsBase should be replaced with TStructOpsTypeTraitsBase2, where T is the type that the trait is being specialized for. + +* `#include "Delegates/Tuple.h"` should be replaced with `#include "Templates/Tuple.h"`. + +* As TPairInitializer is now convertible to TPair, rather than TPair being constructible from TPairInitializer, types which do not correctly implement copy or move semantics by not inhibiting the compiler defaults may cause a bad state when they are inserted into a TMap or TSet. All types used in UE4 containers should correctly define copy or move semantics. + +* Any dependence on Unreal Code Analyzer should be removed from projects. + +* The explicit usage of TInlineSetAllocator in any TSet and TMap should be updated to ensure that the template arguments provided result in hash sizes which are a power-of-two. + +* TBoolConstant should be replaced with TIntegralConstant. + +* Any use of WITH_HOT_RELOAD_CTORS should be replaced with the assumption that the value is 1. + +* Any use of the Use VTable Constructors .ini option should be replaced with the assumption that the value is true. + +* Use of generated FName variables for UFUNCTIONs (e.g. ENGINE_ReceiveTick) should be replaced with a string literal or a custom static FName variable in your own code: + + * For example: static const FName ENGINE_ReceiveTick = TEXT("ReceiveTick"); + +* If Unreal Header Tool reports an error about a function having a different signature from a base class, it should be fixed to have the same signature, or renamed. + +#### Editor and Tools + +* Exposed Make Property Combo Box in Property Customization Helpers to allow embedding an enum combo box into Struct Customizations. + +* Added Custom Column support to the Asset Picker Config. + +* If you use a protected platform, your project settings will start to be saved under MyGame\Config\Platform\PlatformEngine.ini, instead MyGame\Config\DefaultEngine.ini. + +#### Platforms + +* Made some big Device Profile changes, particularly for the protected platforms. You may need to modify your Device Profiles in similar ways if you are a heavy user of them. + + * Changed the "type" of some DPs from WindowsNoEditor, etc to Windows. It should be a platform, not a random string. + + * With that change, the platform can be used to save out protected platform DP .ini files to subdirectories, maintaining secrecy. + + * When saving DeviceProfiles, you may need to look in a platform subdirectory for the DeviceProfiles.ini file. + + * Added Config/[PlatformName]/ConfidentialPlatform.ini files so that the DP loading code knows to look in their directories for DPs. See the GetConfidentialPlatforms() function in GenericPlatformMisc for more information. + +#### Programming + +* The TargetRules.ShouldUseSharedBuildEnvironment() function has been deprecated. Targets can now specify the build environment they wish to use by setting BuildEnvironment to TargetBuildEnvironment.Default/Shared/Unique in their constructor instead. + +* The constructor for ModuleRules-derived classes in .build.cs files should be updated to take a ReadOnlyTargetRules instance, which should be forwarded to the base class. This class contains the same properties as the previous TargetInfo argument, plus all the target-specific settings previously stored in the global BuildConfiguration and UEBuildConfiguration classes. Compatibility shims for accessing these objects will be removed in a future release. The WITH_FORWARDED_MODULE_RULES_CTOR preprocessor definition is now defined, which allows writing code which is compatible with multiple engine versions. + +* The TargetRules.SetupBinaries() callback has been deprecated. Instead of overriding this, targets may override the launch module through the "LaunchModuleName" property in their constructor, and add extra modules to the "ExtraModuleNames" field on the TargetRules object itself. + +#### Rendering + +* UE4Editor is whitelisted for Aftermath with latest Nvidia drivers. To whitelist other game executables contact Nvidia. + +* RHICmdList.Clear() methods are now removed; please use RHICmdList.SetRenderTargetsAndClear() or the DrawClearQuad() utility function from ClearQuad.h. + +* The Cross Compiler Tool is now removed from the Engine, it had too many limitations. Use hlslcc.sln or ShaderCompileWorker -directcompile instead. + +* PipelineStateCache.h contains the new replacement interface for BoundShaderStateCache.h. Otherwise, during the Geometry rendering passes the previously introduced Draw Render State is used to collect and set the Blend, Raster, and Depth Stencil State. Commit Graphics Pipeline State will set the PSO for geometry rendering passes. Postprocessing passes or passes which use Globalshaders have to fill out a Graphics Pipeline State Initializer and set this instead. + +* If configuring via .ini files, use the new variable name "ScaleTexturesByGlobalMipBias" where "ScaleTexturesByGlobalMyBias" was used. + +* Mobile: Skylights on mobile projects may need to be recaptured in the editor before packaging. + +* Mobile: Please replace r.TonemapperFilm=1 cvar with r.Mobile.TonemapperFilm=1 in case you want to use new filmic tonemapper on Mobile platforms. + +#### VR + +* PSVR MotionController tracking management system. + + * Blueprint functions added to manage the set of actively motion tracked controllers in MotionTrackedDevice Function Library. + + * You are recommended to disable tracking of all controllers first, and then enable tracking for the controllers you want to have tracked based on user setting, connected controllers, etc. The system keeps a memory of which controllers are set to be tracked even if the controller is disconnected, or not yet connected. + +* Experimental preview of PSVR Social Screen support. + + * The new Morpheus plugin project setting Enable Social Screen Separate Mode must be set to true to use this feature. When that is true additional render and output buffers will be allocated for the Social Screen. + + * Blueprint functions for controlling the feature can be found by searching for 'SocialScreen'. + + * Future work will replace this API with a more flexible cross platform one, and pursue optimizations of SocialScreen output. + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_2/Updates/UnrealEngine4_2UpdateNotes.CHN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_2/Updates/UnrealEngine4_2UpdateNotes.CHN.udn new file mode 100644 index 000000000000..2498098f653a --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_2/Updates/UnrealEngine4_2UpdateNotes.CHN.udn @@ -0,0 +1,50 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 虚幻引擎 4.2 更新日志 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/2014/4_2 +Order:0 + +## 4.2.0 Release + +Released: 06/04/2014 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.2.0-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.2.0-release) + +Release Notes: [](Support/Builds/ReleaseNotes/2014/4_2) + +## 4.2.1 Hotfix + +Released: 06/17/2014 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.2.1-release](https://github.com/EpicGames/UnrealEngine/tree/4.2.1-release) + +Fixes: + +* Fixed texture streaming for static meshes with multiple LODs when exceeding the default 1gb texture pool. + +* Fixed Paper2D flipbook components and tile map actors not rendering, sprite color not taking effect. + +* [XB1] Fixed particles rendering as black when bounds were zero. + +* Fixed OnSuccess and OnFail outputs not triggering for AI Move To blueprint node. + +* Prevent triggers blocking projectiles in first-person template. + +* [iOS] Some projects would fail to launch on device. + +* [PS4] Packaging in shipping would not create executable. + +* [Mac] Added Subversion binaries to default install. + +## QFE for the 4.2.1 Hotfix + +If you are using the latest hotfix for this engine version and experience the issue described below, download and run this ‘quick fix’ to resolve the issue. + +* Fixes a crash that occurs with Blueprints that have soft and hard dependencies. ([report](https://answers.unrealengine.com/questions/70620/42-urgent-help-needed-unrecoverable.html)) + +[Windows Download](http://cdn.unrealengine.com/qfe/QFE-FromCL-2121920-Shelve-2235825.exe](http://cdn.unrealengine.com/qfe/QFE-FromCL-2121920-Shelve-2235825.exe) + +[Mac Download](http://cdn.unrealengine.com/qfe/QFE-FromCL-2121920-Shelve-2235825_Mac.zip](http://cdn.unrealengine.com/qfe/QFE-FromCL-2121920-Shelve-2235825_Mac.zip) + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_2/Updates/UnrealEngine4_2UpdateNotes.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_2/Updates/UnrealEngine4_2UpdateNotes.JPN.udn index 9b5574b8ed22..eb4d30269d8a 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_2/Updates/UnrealEngine4_2UpdateNotes.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_2/Updates/UnrealEngine4_2UpdateNotes.JPN.udn @@ -1,6 +1,6 @@ INTSourceChangelist:0 Availability:Public -Title: Unreal Engine 4.2 Update Notes +Title: アンリアル エンジン 4.2 アップデート ノート Description: Crumbs: Parent:Support/Builds/ReleaseNotes/2014/4_2 diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_2/Updates/UnrealEngine4_2UpdateNotes.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_2/Updates/UnrealEngine4_2UpdateNotes.KOR.udn new file mode 100644 index 000000000000..e80b285b493b --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_2/Updates/UnrealEngine4_2UpdateNotes.KOR.udn @@ -0,0 +1,50 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 언리얼 엔진 4.2 업데이트 노트 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/2014/4_2 +Order:0 + +## 4.2.0 릴리즈 + +릴리즈 날짜: 2014/06/04 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.2.0-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.2.0-release) + +릴리즈 노트: [](Support/Builds/ReleaseNotes/2014/4_2) + +## 4.2.1 핫픽스 + +릴리즈 날짜: 2014/06/17 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.2.1-release](https://github.com/EpicGames/UnrealEngine/tree/4.2.1-release) + +픽스: + +* 기본 1gb 텍스처 풀을 초과하는 다수의 LOD 가 있는 스태틱 메시의 텍스처 스트리밍을 수정했습니다. + +* Paper2D 플립북 컴포넌트 및 타일 맵 액터가 렌더링되지 않고, 스프라이트 컬러가 이펙트를 받지 않던 것을 고쳤습니다. + +* [XB1] 바운드가 제로인 경우 파티클이 검정으로 렌더링되던 것을 고쳤습니다. + +* OnSuccess 및 OnFail 출력이 AI Move To 블루프린트 노드를 발동시키지 않던 것을 고쳤습니다. + +* 일인칭 템플릿에서 트리거가 프로젝타일을 막지 못하도록 했습니다. + +* [iOS] 일부 프로젝트가 디바이스에서 실행에 실패하던 것을 고쳤습니다. + +* [PS4] Shipping 모드 패키징이 실행파일을 생성하지 못하던 것을 고쳤습니다. + +* [Mac] 기본 인스톨에 Subversion 바이너리를 추가했습니다. + +## 4.2.1 핫픽스 QFE + +이번 엔진 버전의 최신 핫픽스를 사용하다가 아래 이슈를 겪으시는 경우, 이 '퀵 픽스'를 다운로드하여 실행하면 이슈 해결이 가능합니다. + +* 소프트 및 하드 디펜던시를 갖는 블루프린트 관련 발생하는 크래시 픽스. ([리포트](https://answers.unrealengine.com/questions/70620/42-urgent-help-needed-unrecoverable.html)) + +[윈도우 다운로드](http://cdn.unrealengine.com/qfe/QFE-FromCL-2121920-Shelve-2235825.exe](http://cdn.unrealengine.com/qfe/QFE-FromCL-2121920-Shelve-2235825.exe) + +[맥 다운로드](http://cdn.unrealengine.com/qfe/QFE-FromCL-2121920-Shelve-2235825_Mac.zip](http://cdn.unrealengine.com/qfe/QFE-FromCL-2121920-Shelve-2235825_Mac.zip) + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_3/Updates/UnrealEngine4_3UpdateNotes.CHN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_3/Updates/UnrealEngine4_3UpdateNotes.CHN.udn new file mode 100644 index 000000000000..1b7e8b09a19a --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_3/Updates/UnrealEngine4_3UpdateNotes.CHN.udn @@ -0,0 +1,48 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 虚幻引擎 4.3 更新日志 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/2014/4_3 +Order:0 + +## 4.3.0 Release + +Released: 07/16/2014 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.3.0-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.3.0-release) + +Release Notes: [](Support/Builds/ReleaseNotes/2014/4_3) + +## 4.3.1 Hotfix + +Released: 07/29/2014 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.3.1-release](https://github.com/EpicGames/UnrealEngine/tree/4.3.1-release) + +Fixes: + +* Fixed: Japanese Localization + +* Fixed: PIE with Box BSP affected by Radial Force Actor WorldStatic + +* Fixed: PC to iOS workflow doesn't properly sign IPAs for distribution + +* Fixed: menu windows do not open when 'Enable Window Animations' is enabled + +* Fixed: Landscape Spline: Content created with 4.2 Crashes with 4.3 + +* Fixed: only first UV channel is usable other channels are broken and textures will not be mapped + +* Fixed: Morpheus crashes on init + +## QFE for the 4.3.1 Hotfix + +If you are using the latest hotfix for this engine version and experience the issue described below, download and run this ‘quick fix’ to resolve the issue. + +* Fixes a crash that occurs with Blueprints that have soft and hard dependencies. ([report](https://answers.unrealengine.com/questions/70620/42-urgent-help-needed-unrecoverable.html)) + +[Windows Download](http://cdn.unrealengine.com/qfe/QFE-FromCL-2226259-Shelve-2236052.exe](http://cdn.unrealengine.com/qfe/QFE-FromCL-2226259-Shelve-2236052.exe) + +[Mac Download](http://cdn.unrealengine.com/qfe/QFE-FromCL-2226259-Shelve-2236052_Mac.zip](http://cdn.unrealengine.com/qfe/QFE-FromCL-2226259-Shelve-2236052_Mac.zip) + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_3/Updates/UnrealEngine4_3UpdateNotes.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_3/Updates/UnrealEngine4_3UpdateNotes.JPN.udn index a99e0f67092b..a5359399c17e 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_3/Updates/UnrealEngine4_3UpdateNotes.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_3/Updates/UnrealEngine4_3UpdateNotes.JPN.udn @@ -1,6 +1,6 @@ INTSourceChangelist:0 Availability:Public -Title: Unreal Engine 4.3 Update Notes +Title: アンリアル エンジン 4.3 アップデート ノート Description: Crumbs: Parent:Support/Builds/ReleaseNotes/2014/4_3 diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_3/Updates/UnrealEngine4_3UpdateNotes.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_3/Updates/UnrealEngine4_3UpdateNotes.KOR.udn new file mode 100644 index 000000000000..09f0126ab2c3 --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_3/Updates/UnrealEngine4_3UpdateNotes.KOR.udn @@ -0,0 +1,48 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 언리얼 엔진 4.3 업데이트 노트 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/2014/4_3 +Order:0 + +## 4.3.0 릴리즈 + +릴리즈 날짜: 2014/07/16 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.3.0-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.3.0-release) + +릴리즈 노트: [](Support/Builds/ReleaseNotes/2014/4_3) + +## 4.3.1 핫픽스 + +릴리즈 날짜: 2014/07/29 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.3.1-release](https://github.com/EpicGames/UnrealEngine/tree/4.3.1-release) + +픽스: + +* 일본어 현지화 + +* Radial Force Actor WorldStatic 에 영향받은 Box BSP 관련 PIE + +* PC 에서 iOS 작업방식에서 IPA 배포 사이닝이 제대로 되지 않음 + +* 'Enable Window Animations' 옵션이 켜졌을 때 메뉴 창이 열리지 않음 + +* 랜드스케이프 스플라인: 4.2 로 만든 콘텐츠가 4.3 에서 크래시 + +* 첫 UV 채널만 사용되고 다른 채널은 깨지며 텍스처가 매핑되지 않음 + +* Morpheus 초기화 크래시 + +## 4.3.1 핫픽스 QFE + +이 엔진 버전의 최신 핫픽스를 사용하다가 아래 이슈를 겪으시는 경우, 이 '퀵 픽스'를 다운로드하여 실행하면 이슈 해결이 가능합니다. + +* 소프트 및 하드 디펜던시가 있는 블루프린트 관련 발생하는 크래시 픽스 ([리포트](https://answers.unrealengine.com/questions/70620/42-urgent-help-needed-unrecoverable.html)) + +[윈도우 다운로드](http://cdn.unrealengine.com/qfe/QFE-FromCL-2226259-Shelve-2236052.exe](http://cdn.unrealengine.com/qfe/QFE-FromCL-2226259-Shelve-2236052.exe) + +[맥 다운로드](http://cdn.unrealengine.com/qfe/QFE-FromCL-2226259-Shelve-2236052_Mac.zip](http://cdn.unrealengine.com/qfe/QFE-FromCL-2226259-Shelve-2236052_Mac.zip) + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_4/Updates/UnrealEngine4_4UpdateNotes.CHN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_4/Updates/UnrealEngine4_4UpdateNotes.CHN.udn new file mode 100644 index 000000000000..5b3f1ca8137c --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_4/Updates/UnrealEngine4_4UpdateNotes.CHN.udn @@ -0,0 +1,70 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 虚幻引擎 4.4 更新日志 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/2014/4_4 +Order:0 + +## 4.4.0 Release + +Released: 08/14/2014 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.4.0-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.4.0-release) + +Release Notes: [](Support/Builds/ReleaseNotes/2014/4_4) + +## 4.4.1 Hotfix + +Released: 08/26/2014 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.4.1-release](https://github.com/EpicGames/UnrealEngine/tree/4.4.1-release) + +Fixes: + +* Unreal Front End: Fixed a crash that occurred when using cooking-on-the-fly with MacNoEditor + +* Oculus Rift support has been updated to use the Oculus 0.4.1 Beta SDK + +* Fixed a crash when opening animations from the Military Weapons Asset Content Pack on the Marketplace + +* Fixed a bug where mouse handling was broken on Mac + +* Blueprints: Added a redirect to the base engine ini which allows existing content to point to the correct location for an enum, fixing a compatibility break + +* Fixed info.plist search order in UAT + +* Fixed a bug with audio in Couch Knights + +## 4.4.2 Hotfix + +Released: 09/09/2014 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.4.2-release](https://github.com/EpicGames/UnrealEngine/tree/4.4.2-release) + +Fixes: + +* Fixed an error that could occur with Notify tracks in animation Montages. + +* Fixed an error that could cause the Mac Editor to become unresponsive when Slate Text Views were used + +* Fixed game plugin source being compiled with optimizations when Debug or DebugGame configuration is set. + +* Updated Vehicle Template with Oculus Rift support! + +## 4.4.3 Hotfix + +Released: 09/16/2014 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.4.3-release](https://github.com/EpicGames/UnrealEngine/tree/4.4.3-release) + +Fixes: + +* Fixed a crash after loading a Blueprint with particular linked nodes set as a dependency of another Blueprint. + +* Fixed a .NET Framework SDK test dependency added in 4.4.1. + +* Added Xcode 6 support; please review the known issues. + +* Improved Oculus compatibility with the Vehicle template – fixed the camera setup and replaced the vehicle mesh + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_4/Updates/UnrealEngine4_4UpdateNotes.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_4/Updates/UnrealEngine4_4UpdateNotes.JPN.udn index a5ae16089b37..761b9fe054ed 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_4/Updates/UnrealEngine4_4UpdateNotes.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_4/Updates/UnrealEngine4_4UpdateNotes.JPN.udn @@ -1,6 +1,6 @@ INTSourceChangelist:0 Availability:Public -Title: Unreal Engine 4.4 Update Notes +Title: アンリアル エンジン 4.4 アップデート ノート Description: Crumbs: Parent:Support/Builds/ReleaseNotes/2014/4_4 diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_4/Updates/UnrealEngine4_4UpdateNotes.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_4/Updates/UnrealEngine4_4UpdateNotes.KOR.udn new file mode 100644 index 000000000000..26f9ce0a12ea --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_4/Updates/UnrealEngine4_4UpdateNotes.KOR.udn @@ -0,0 +1,70 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 언리얼 엔진 4.4 업데이트 노트 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/2014/4_4 +Order:0 + +## 4.4.0 릴리즈 + +릴리즈 날짜: 2014/08/14 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.4.0-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.4.0-release) + +릴리즈 노트: [](Support/Builds/ReleaseNotes/2014/4_4) + +## 4.4.1 핫픽스 + +릴리즈 날짜: 2014/08/26 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.4.1-release](https://github.com/EpicGames/UnrealEngine/tree/4.4.1-release) + +픽스: + +* Unreal Front End: MacNoEditor 로 cooking-on-the-fly 를 사용할 때 발생하던 크래시를 고쳤습니다. + +* Oculus Rift 지원이 Oculus 0.4.1 Beta SDK 를 사용하도록 업데이트되었습니다. + +* 마켓플레이스에서 Military Weapons Asset Content Pack 의 애니메이션을 열 때 발생하던 크래시를 고쳤습니다. + +* Mac 에서 마우스 처리가 깨지던 버그를 잡았습니다. + +* 블루프린트: base engine ini 로의 리디렉션을 추가하여 기존 콘텐츠가 enum 의 올바른 위치를 지정할 수 있도록 하여 호환성이 깨지던 문제를 해결했습니다. + +* UAT 에서 info.plist 검색 순서를 변경했습니다. + +* Couch Knights 의 오디오 버그를 잡았습니다. + +## 4.4.2 핫픽스 + +릴리즈 날짜: 2014/09/09 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.4.2-release](https://github.com/EpicGames/UnrealEngine/tree/4.4.2-release) + +픽스: + +* 애니메이션 몽타주의 Notify 트랙 관련 발생할 수 있었던 오류를 고쳤습니다. + +* Mac 에디터에서 Slate Text Views 를 사용했을 때 반응 없음 현상을 유발할 수 있었던 오류를 고쳤습니다. + +* Debug 또는 DebugGame 구성이 설정되었을 때 게임 플러그인 소스가 최적화되어 컴파일되도록 수정했습니다. + +* Vehicle Template 에 Oculus Rift 가 지원되도록 업데이트했습니다! + +## 4.4.3 핫픽스 + +릴리즈 날짜: 2014/09/16 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.4.3-release](https://github.com/EpicGames/UnrealEngine/tree/4.4.3-release) + +픽스: + +* 다른 블루프린트의 종속성으로 설정된 특정 링크 노드를 포함한 블루프린트를 로드한 뒤 발생하는 크래시를 고쳤습니다. + +* .NET Framework SDK 종속성 테스트를 4.4.1 에 추가했습니다. + +* Xcode 6 지원을 추가했습니다. 알려진 문제점을 검토해 보세요. + +* Vehicle 템플릿 관련 Oculus 호환성을 개선시켰습니다. 카메라 셋업 수정 및 비히클 메시를 대체했습니다. + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_5/Updates/UnrealEngine4_5UpdateNotes.CHN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_5/Updates/UnrealEngine4_5UpdateNotes.CHN.udn new file mode 100644 index 000000000000..25fc9792b727 --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_5/Updates/UnrealEngine4_5UpdateNotes.CHN.udn @@ -0,0 +1,52 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 虚幻引擎 4.5 更新日志 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/2014/4_5 +Order:0 + +## 4.5.0 Release + +Released: 10/14/2014 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.5.0-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.5.0-release) + +Release Notes: [](Support/Builds/ReleaseNotes/2014/4_5) + +## 4.5.1 Hotfix + +Released: 10/23/2014 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.5.1-release](https://github.com/EpicGames/UnrealEngine/tree/4.5.1-release) + +Fixes: + +* The default landscape material now correctly renders on VehicleGame. + +* Fixed an error when using Hot-Reload with XCode. + +* Fixed an error when packaging projects on Linux OS. + +* Corrected bugs that occurred on Nvidia devices in 10.10 Yosemite. + +* Fixed an error while attempting to join a match of Shootergame while on Linux OS. + +* Fixed the UI in Shootergame to be properly masked on Linux OS. + +* Material Parameter Collections now work properly when called through Blueprints. + +* Mouse input has been adjusted to a more consistent and less sensitive state. + +* Resolved some issues discovered with retargeting animations with Epic compatible skeletons. + +* Fixed an issue with iOS certificate validation while packaging projects. + +## QFE for the 4.5.1 Hotfix + +If you are using the latest hotfix for this engine version and experience the issue described below, download and run this ‘quick fix’ to resolve the issue. + +* Fixes issue where editor incorrectly detects that iTunes isn’t installed and will not allow any iOS Launch On or Package. + +[Windows Download](https://s3.amazonaws.com/unrealengine/qfe/QFE-FromCL-2370532.exe](https://s3.amazonaws.com/unrealengine/qfe/QFE-FromCL-2370532.exe) + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_5/Updates/UnrealEngine4_5UpdateNotes.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_5/Updates/UnrealEngine4_5UpdateNotes.JPN.udn index 5f22ccad2f2f..765f83c9658c 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_5/Updates/UnrealEngine4_5UpdateNotes.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_5/Updates/UnrealEngine4_5UpdateNotes.JPN.udn @@ -1,6 +1,6 @@ INTSourceChangelist:0 Availability:Public -Title: Unreal Engine 4.5 Update Notes +Title: アンリアル エンジン 4.5 アップデート ノート Description: Crumbs: Parent:Support/Builds/ReleaseNotes/2014/4_5 diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_5/Updates/UnrealEngine4_5UpdateNotes.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_5/Updates/UnrealEngine4_5UpdateNotes.KOR.udn new file mode 100644 index 000000000000..c2dc889ff8f1 --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_5/Updates/UnrealEngine4_5UpdateNotes.KOR.udn @@ -0,0 +1,52 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 언리얼 엔진 4.5 업데이트 노트 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/2014/4_5 +Order:0 + +## 4.5.0 릴리즈 + +릴리즈 날짜: 2014/10/14 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.5.0-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.5.0-release) + +릴리즈 노트: [](Support/Builds/ReleaseNotes/2014/4_5) + +## 4.5.1 핫픽스 + +릴리즈 날짜: 2014/10/23 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.5.1-release](https://github.com/EpicGames/UnrealEngine/tree/4.5.1-release) + +픽스: + +* 이제 VehicleGame 에 기본 랜드스케이프 머티리얼이 제대로 렌더링됩니다. + +* XCode 에서 핫 리로드를 사용할 때의 오류를 고쳤습니다. + +* 리눅스 OS 에서 프로젝트 패키지를 만들 때의 오류를 고쳤습니다. + +* 10.10 Yosemite 에서 Nvidia 디바이스에 발생하던 버그를 잡았습니다. + +* 리눅스 OS 에서 Shootergame 경기 참가를 시도할 때 발생하던 오류를 고쳤습니다. + +* Shootergame 의 UI 가 리눅스 OS 에서 제대로 마스킹되도록 수정했습니다. + +* Material Parameter Collection 이 이제 블루프린트를 통해 호출해도 정상 작동합니다. + +* 마우스 입력의 일관성을 향상시키고 덜 민감한 상태로 조정했습니다. + +* 에픽 호환 스켈레톤 포함 애니메이션 리타게팅 관련 발견된 이슈를 몇 가지 해결했습니다. + +* 프로젝트 패키지 작업 도중 iOS Certificate 인증 관련 이슈를 수정했습니다. + +## 4.5.1 핫픽스 QFE + +이 엔진 버전 최신 핫픽스를 사용하면서 아래 이슈를 겪으시는 경우, 이 '퀵 픽스' 를 다운로드하여 실행하면 이슈 해결이 가능합니다. + +* iTunes 가 설치되지 않아 iOS 에서 실행 또는 패키지 옵션을 사용할 수 없도록 에디터에서 잘못 감지되는 이슈에 대한 픽스입니다. + +[윈도우 다운로드](https://s3.amazonaws.com/unrealengine/qfe/QFE-FromCL-2370532.exe](https://s3.amazonaws.com/unrealengine/qfe/QFE-FromCL-2370532.exe) + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_6/Updates/UnrealEngine4_6UpdateNotes.CHN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_6/Updates/UnrealEngine4_6UpdateNotes.CHN.udn new file mode 100644 index 000000000000..1163ab83653d --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_6/Updates/UnrealEngine4_6UpdateNotes.CHN.udn @@ -0,0 +1,62 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 虚幻引擎 4.6 更新日志 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/2014/4_6 +Order:0 + +## 4.6.0 Release + +Released: 12/03/2014 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.6.0-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.6.0-release) + +Release Notes: [](Support/Builds/ReleaseNotes/2014/4_6) + +## 4.6.1 Hotfix + +Released: 12/16/2014 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.6.1-release](https://github.com/EpicGames/UnrealEngine/tree/4.6.1-release) + +Fixes: + +* ContentExamples Media map movie no longer renders black. + +* ContentExamples Media map no longer shows the UDK splash screen. + +* ContentExamples Media map is no longer missing source video. + +* XBox One now boots from Visual Studio correctly. + +* Fixed an error that caused material If nodes to break. + +* Fixed a bug that was causing new and converted non-ascii text projects to crash. + +* Corrected a bug that prevented composite decorators from being opened in Behavior Trees. + +* Event Nodes can now be called for Event Dispatchers. + +* Fixed an error that prevented the creation of new events in the AnimBP Eventgraph for new Anim Notifies. + +* Corrected Static Lighting on InstancedStaticMeshes. + +* Corrected the adb path and device serial number for Android packaged install batch files + +* Fixed an error that caused crashes on Android when Touch events were called too early. + +* Fixed a bug in pathfinding when default querying extent was not large enough on the Z axis. + +* InstancedStaticMesh now renders correctly on mobile devices. + +* Corrected a bug with animation retargeting adversely affecting looping animations. + +## QFE for the 4.6.1 Hotfix + +If you are using the latest hotfix for this engine version and experience the issue described below, download and run this ‘quick fix’ to resolve the issue. + +* Fixes issue where editor incorrectly detects that iTunes isn’t installed and will not allow any iOS Launch On or Package. + +[Windows Download](https://s3.amazonaws.com/unrealengine/qfe/QFE-FromCL-2405993.exe](https://s3.amazonaws.com/unrealengine/qfe/QFE-FromCL-2405993.exe) + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_6/Updates/UnrealEngine4_6UpdateNotes.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_6/Updates/UnrealEngine4_6UpdateNotes.JPN.udn index 483d6a372343..d43c8221178c 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_6/Updates/UnrealEngine4_6UpdateNotes.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_6/Updates/UnrealEngine4_6UpdateNotes.JPN.udn @@ -1,6 +1,6 @@ INTSourceChangelist:0 Availability:Public -Title: Unreal Engine 4.6 Update Notes +Title: アンリアル エンジン 4.6 アップデート ノート Description: Crumbs: Parent:Support/Builds/ReleaseNotes/2014/4_6 diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_6/Updates/UnrealEngine4_6UpdateNotes.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_6/Updates/UnrealEngine4_6UpdateNotes.KOR.udn new file mode 100644 index 000000000000..44b3ab626052 --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_6/Updates/UnrealEngine4_6UpdateNotes.KOR.udn @@ -0,0 +1,62 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 언리얼 엔진 4.6 업데이트 노트 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/2014/4_6 +Order:0 + +## 4.6.0 릴리즈 + +릴리즈 날짜: 2014/12/03 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.6.0-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.6.0-release) + +릴리즈 노트: [](Support/Builds/ReleaseNotes/2014/4_6) + +## 4.6.1 핫픽스 + +릴리즈 날짜: 2014/12/16 + +Github: [https://github.com/EpicGames/UnrealEngine/tree/4.6.1-release](https://github.com/EpicGames/UnrealEngine/tree/4.6.1-release) + +픽스: + +* ContentExamples Media 맵 무비가 더이상 검정으로 렌더링되지 않습니다. + +* ContentExamples Media 맵이 더이상 UDK 스플래시 화면을 표시하지 않습니다. + +* ContentExamples Media 맵이 더이상 소스 비디오가 빠져있지 않습니다. + +* XBox One 이 이제 Visual Studio 에서 정상 부팅됩니다. + +* 머티리얼 If 노드를 깨지게 만들던 오류를 고쳤습니다. + +* ascii 이외 텍스트 프로젝트를 새로 만들거나 변환한 경우 크래시가 나던 버그를 잡았습니다. + +* 비헤이비어 트리에서 컴포짓 데코레이터를 열 수 없게 만들던 버그를 잡았습니다. + +* 이제 Event Nodes 를 Event Dispatchers 에 대해 호출할 수 있습니다. + +* 새로운 애님 노티파이에 대해 애님 블루프린트 이벤트 그래프에서 새 이벤트 생성을 하지 못하게 막던 오류를 고쳤습니다. + +* InstancedStaticMeshes 의 스태틱 라이팅을 고쳤습니다. + +* 안드로이드 패키징된 인스톨 배치 파일에 대한 adb 경로와 디바이스 시리얼 번호를 수정했습니다. + +* 안드로이드에서 Touch 이벤트를 너무 일찍 호출했을 때 크래시를 유발하던 오류를 고쳤습니다. + +* Z 축 기본 쿼리 크기가 충분히 크지 않을 때의 길찾기 버그를 잡았습니다. + +* 이제 모바일 디바이스에서 InstancedStaticMesh 가 제대로 렌더링됩니다. + +* 애니메이션 리타게팅이 루핑 애니메이션에 반대로 영향을 끼치던 버그를 잡았습니다. + +## 4.6.1 핫픽스용 QFE + +이 엔진 버전의 최신 핫픽스를 사용하면서 아래 이슈를 겪으시는 경우, 이 '퀵 픽스'를 다운로드하여 실행하면 이슈 해결이 가능합니다. + +* iTunes 가 설치되지 않아 iOS 에서 실행 또는 패키징 작업을 할 수 없다고 잘못 감지되던 에디터 이슈에 대한 픽스입니다. + +[윈도우 다운로드](https://s3.amazonaws.com/unrealengine/qfe/QFE-FromCL-2405993.exe](https://s3.amazonaws.com/unrealengine/qfe/QFE-FromCL-2405993.exe) + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_7/Updates/UnrealEngine4_7UpdateNotes.CHN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_7/Updates/UnrealEngine4_7UpdateNotes.CHN.udn new file mode 100644 index 000000000000..3c24e06f5d3d --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_7/Updates/UnrealEngine4_7UpdateNotes.CHN.udn @@ -0,0 +1,362 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 虚幻引擎 4.7 更新日志 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/2015/4_7 +Order:0 + +## 4.7.0 Release + +Released: 02/24/2015 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.7.0-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.7.0-release) + +Release Notes: [](Support/Builds/ReleaseNotes/2015/4_7) + +## 4.7.1 Hotfix + +Released: 02/27/2015 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.7.1-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.7.1-release) + +Fixes: + +* UE-6706 Text does not scale when using the "Draw Text" node in a HUD blueprint + +* UE-7139 Crash caused by "/Game/Maps/UEDPIE_2_Menu.Menu not cleaned up by garbage collection!" + +* UE-7497 No Graphs are displayed in Visual Logger after enabling them + +* UE-9745 Color picker does not work. + +* UE-10016 Using the Merge Blueprints feature crashes the editor + +* UE-10114 LevelScript should not get a Overlap event added by default + +* UE-10137 Redirected graph nodes cause a crash in IsDataOnlyBlueprint + +* UE-10141 Vehicle code project has default texture in packaged game + +* UE-10143 High reflectivity on all materials in SunTemple on Android + +* UE-10167 Undoing a pasted custom event node with an input pin results in a crash + +* UE-10169 When installing VS through the editor, invoke installer with a command-line parameter that enables Microsoft's Telemetry + +* UE-10257 Mac to Android first time device is plugged in, after installing tadp user still has to place sdk paths + +* UE-10260 Pre-existing Foliage stays at highest LOD + +* UE-10277 Android fails to show as valid platform for Mac in UFE until editor is opened + +* UE-10283 TargetArray nodes are reported as invalid if played in Standalone mode but not in PIE + +* UE-10298 Creating an exposed variable does not always update correctly to the bp's Details panel + +* UE-10305 Set Timer node does not stop the timer if it is set to zero by the Custom Event + +* UE-10313 Crash playing animation montage in reverse + +* UE-10319 Crash attempting to edit a Struct Transform's rotation value as a slider + +* UE-10406 All shadow casting on Paper2D sprites is broken (no sprites cast shadows) + +* UE-10410 Reparenting an Actor blueprint crashes the editor + +* UE-10510 Crash occurs applying instance changes to blueprint when instances have different changes + +* UE-10524 Icon reports failure to add if creating a project with source control enabled + +* UE-10529 TappyChicken: HTML5: Firefox: The Fullscreen button now displays the screen offcentre (large black border on the right) + +* UE-10537 Editor crash when child component has physics enabled and is moved + +* UE-10562 Empty if blocks are generated in shaders and can cause driver compiler crashes on Android + +* UE-10646 Crash occurs copying a non-scene component in component window + +* UE-10650 Possible crash in USceneComponent::UpdatePhysicsVolume + +* UE-10658 Excessive memory consumption in some circumstances due to off-by-1 count error + +* UE-10732 Actor's attached to an Actor with a blueprint created root component don't stay in correct relative position when moved + +* UE-10793 GitHub 851 : Update .gitignore - ignore FeaturePacks + +* UE-10812 Comparing BB entries doesn't work + +* UE-10822 Crash clearing the undo buffer during blueprint merge + +* UE-10826 Crash compiling Level BP after deleting event + +## 4.7.2 Hotfix + +Released: 03/04/2015 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.7.2-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.7.2-release) + +Fixes: + +* UE-11207 ios launch fail after upgrading to 4.7.1, provision not found, signing key not found + +* UE-11202 Horizontal navigation in Notify timelines is super-frustrating + +* UE-11130 Cannot build code projects for ios + +* UE-11102 Mac editor sometimes crashes in FMacWindow::IsMaximized when creating a new window + +* UE-11046 Crash in FLandscapeComponentSceneProxy::GetStaticBatchElementVisibility with tiny component size + +* UE-11023 Opening the engine crashes: Assert failed: GConfig->GetInt + +* UE-11018 Synced BlackBoard keys don't work + +* UE-8589 MatineeFightScene has no sound on mac + +* UE-8550 Audio cuts out during scene transitions in the Particle Effects cinematic + +## 4.7.3 Hotfix + +Released: 03/17/2015 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.7.3-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.7.3-release) + +Fixes: + +* UE-11029 Crash after converting to 4.7.0 from 4.6.1 + +* UE-11404 Second player is not affecting by any gamepad input. + +* UE-11402 Editor will not build if you have PS4 code, and ONLY SDK 2.0 + +* UE-11485 Compiling the engine with Xcode 6.3 beta generates errors + +* UE-10128 Preview Static mesh does not translate with socket + +* UE-11315 Bugg 38187: SIGSEGV: invalid attempt to access memory at address 0x1010102 + +* UE-10569 Crash when opening maps and blueprints in user's project + +* UE-10708 Build failing for users project with all platforms + +* UE-11312 Mac Bugg 38298: SIGSEGV: invalid attempt to access memory at address 0x3 + +* UE-11369 Crash when clicking on a "Two Bone IK" node + +* UE-11185 A function in a Blueprint Function Library that references another function in that library cannot be saved after closing and reopening the project + +* UE-11322 Crash when refreshing/moving/deleting BP nodes + +* UE-11743 4.7 does not support Morpheus under SDK 2.0 + +* UE-11302 Cannot deploy to iPad + +* UE-11692 Crash when rendering hit proxies + +* UE-11304 Can't compile CrossCompilerTools due to missing file + +* UE-11484 Fix Xcode 6.3 beta clang issues. + +* UE-11393 Tiled landscape import' creates overlapped landscape components + +* UE-11017 GitHub 857 : Fixed native enum support in blackboard component. + +* UE-10697 Crash when opening Post Process Material with Live Data Preview running in Profiler + +* UE-11225 Closing Chunk Parameters tabs with chunk selected and reopening Destructible will cause crash + +* UE-10149 Project crashes on load after modifying Parent Blueprints + +* UE-11244 Crash when renaming assets from the Persona asset browser + +* UE-11272 Blueprint compile error when upgrading project + +* UE-11319 Crash on project open (Assertion Failed) + +* UE-11401 Need more logging in the Deployment Server + +* UE-11292 Editor Crashes when clicking on Transform(Modify) Bone node in Content Examples + +* UE-10900 Crash in FBatchingSPDI::DrawMesh in stand alone game + +* UE-11505 Crash launching Blueprint Office standalone + +* UE-10856 Crash on dragging static meshes into the scene + +* UE-11298 Crash with Distance Fields while using World Composition + +* UE-11422 GitHub 894 : wrong parsing of the return of adb cmd: device + +* UE-11447 Player Character does not collide with landscape + +* UE-11638 GetActorsPerception useless in 4.7 + +* UE-11589 GitHub 909 : Update .gitignore + +* UE-11605 Overridden components are broken in static Actors in cooked build + +* UE-11666 UberGraphFunction should be preloaded in Class::Link + +* UE-11711 Severe log spam when particles collide with static objects + +* UE-11640 AI Move To issues in 4.7 + +* UE-11360 Placing a ' - ' in theproject name will cause the Android build to fail + +* UE-11647 Denver Tegra K1 (Nexus 9) disables rendering thread causing bad performance + +* UE-11383 Screen orientation is ignored on Android devices. + +* UE-11460 A level will not save if a Blueprint that uses a Blueprint Component with an Event Dispatcher is placed in it + +* UE-11600 Performing a hot reload on a project that contains an FStringAssetReference will crash the Editor. + +* UE-11707 Implement workaround for Localization being broken for a number of editor strings + +* UE-11592 Cook on the fly Android projects crash after launching on the device. + +* UE-11739 In some circumstances CrowdManager doesn't get created. + +* UE-11321 Crash when creating landscape + +* UE-11777 BP-implemented BT decorators end up thinking they're not on active branch + +* UE-11826 MediaPlayer14 class lookup crash with distribution builds + +* UE-11840 Launch on Nexus 9 fails due to unknown arm64-v8a architecture + +* UE-11893 Editor crashes when dragging a docked window + +## 4.7.4 Hotfix + +Released: 04/02/2015 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.7.4-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.7.4-release) + +Fixes: + +* UE-11891 MoveToActor doesn't update AI's path on goal actor's move + +* UE-11997 Navigation crashing on PIE in absence of NavOctree + +* UE-12108 [CrashReport] Ensure in UPrimitiveComponent::SetCanEverAffectNavigation() + +* UE-12106 [CrashReport] Saving after blueprint change causes crash. + +* UE-12443 [CrashReport] Crash in blueprints during autosave + +* UE-9417 It is easy to make a comment box unselectable when it overlaps with another comment block + +* UE-10891 Force deleting a blueprint that is parented to another blueprint causes crash + +* UE-10865 4.6.1 to 4.7 conversion crash "Assertion failed: Pin != nullptr ...K2Node_DynamicCast.cpp]" + +* UE-11523 DateTime variables will cause a crash on compile + +* UE-11011 Crash (assert) when accessing a property in a blueprint + +* UE-12073 [CrashReport] Disconnecting/changing blueprint nodes causes crash. + +* UE-12206 GitHub 944 : UE-12128: Properly save structs when struct field default value is different + +* UE-12962 Editor crashes after clicking on "Apply Instance Change to Blueprint" button + +* UE-10574 Component properties of template not propagated when SpawnActor called + +* UE-12109 [CrashReport] Crash while attempting to load a project + +* UE-11368 uv scale of materials on hollow BSP does not persist after building geometry + +* UE-4743 Crash when moving a sprite imported as part of a spritesheet to another folder if the sprite names had invalid character + +* UE-11372 Access Violation in UE4Editor_SlateCore!TWeakPtr when changing view options + +* UE-9824 Widget class is replaced with a placeholder class when reloaded + +* UE-10040 Copy/Paste a button inside of another button then attempting to move the pasted button crashes editor + +* UE-11204 Crash when returning to viewport from immersive mode with an editor window tabbed beneath + +* UE-12915 Crash when using static lighting in foliage + +* UE-7213 Crash occurred trying to cycle gizmo in Persona Anim BP Viewport + +* UE-9982 Sprites with non-center pivots can be invisible in thumbnail renders + +* UE-12196 Automatic collision generation is incorrectly rotated for sprites that were imported as rotated from a sprite sheet + +* UE-12041 Sprite sheets with modified textures don't reimport correctly + +* UE-7918 Sprites don't initialize PixelsPerUnrealUnit in cooked builds, causing invalid values for GetSocketLocation, etc... for assets that have Pixels/uu of 2.56 + +* UE-11903 Crash closing ElementalDemo game in opengl + +* UE-12150 Crash launching PIE when sublevel contains landscape in hidden level + +* UE-12111 [CrashReport] Crash after undoing/deleting landscape. + +* UE-12433 Editor crashes when toggling off visibility for a sublevel that contains a landscape + +* UE-11815 [CrashReport] Crash while attempting to connect iOS device. + +* UE-12165 Morpheus crashes occasionally while running + +* UE-12209 Canvas items are not drawn correctly in Morpheus + +* UE-12211 Morpheus tears visibly even when VSync is on. + +* UE-12212 Morpheus runs HMD distortion shader an extra time. + +* UE-12324 Morpheus rendering broken when console rendering is on the screen. + +* UE-11302 Cannot deploy to iPad + +* UE-12063 Cannot package project on Linux + +* UE-12210 Morpheus IPD is applied incorrectly. + +* UE-13048 Xbox projects (code and BP) launch to black screen, logs show success + +* UE-12213 Landscape material reverts to default when launched onto an Android device + +* UE-12542 MAC: Very slow texture compression times in Editor + +* UE-12235 Large performance regression in shadow rendering. + +* UE-6190 UVs skewed in Mobile Preview mode for some skeletal meshes + +* UE-11865 Open a level that contains instanced meshes (with built lighting) will crash the editor + +* UE-10664 Crash in OpenGL3 and OpenGL4 occurs when opening any map after having a map loaded with foliage. + +* UE-11810 [CrashReport] Crash in ULevel::BuildStreamingData casting Texture + +* UE-11434 New user crashes on Editor load + +* UE-12228 Invalid error messages in crashes + +## 4.7.5 Hotfix + +Released: 04/08/2015 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.7.5-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.7.5-release) + +Fixes: + +* UE-13250 Multiplayer Shootout project sample crashes on start + +* UE-13274 Projects crashing on launch after converting from 4.7.3 to 4.7.4 + +* UE-11828 HydroErosion on landscape crashes on Linux + +## 4.7.6 Hotfix + +Released: 04/20/2015 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.7.6-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.7.6-release) + +Fixes: + +* UE-13664 MAC: Crash on startup + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_7/Updates/UnrealEngine4_7UpdateNotes.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_7/Updates/UnrealEngine4_7UpdateNotes.JPN.udn index 972f4ee957cf..9683b4c8a40d 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_7/Updates/UnrealEngine4_7UpdateNotes.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_7/Updates/UnrealEngine4_7UpdateNotes.JPN.udn @@ -1,6 +1,6 @@ INTSourceChangelist:0 Availability:Public -Title: Unreal Engine 4.7 Update Notes +Title: アンリアル エンジン 4.7 アップデート ノート Description: Crumbs: Parent:Support/Builds/ReleaseNotes/2015/4_7 diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_7/Updates/UnrealEngine4_7UpdateNotes.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_7/Updates/UnrealEngine4_7UpdateNotes.KOR.udn new file mode 100644 index 000000000000..e4f0ae20d762 --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_7/Updates/UnrealEngine4_7UpdateNotes.KOR.udn @@ -0,0 +1,362 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 언리얼 엔진 4.7 업데이트 노트 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/2015/4_7 +Order:0 + +## 4.7.0 릴리즈 + +릴리즈 날짜: 2015/02/24 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.7.0-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.7.0-release) + +릴리즈 노트: [](Support/Builds/ReleaseNotes/2015/4_7) + +## 4.7.1 핫픽스 + +릴리즈 날짜: 2015/02/27 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.7.1-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.7.1-release) + +픽스: + +* UE-6706 HUD 블루프린트에서 Draw Text 노드를 사용할 때 텍스트 스케일이 적용되지 않음 + +* UE-7139 "가비지 콜렉션이 /Game/Maps/UEDPIE_2_Menu.Menu 클린업 하지 못함!" 으로 크래시 유발 + +* UE-7497 그래프를 활성화시켜도 비주얼 로거에 표시되지 않음 + +* UE-9745 색 선택기가 작동하지 않음 + +* UE-10016 Merge Blueprints 기능을 사용하면 에디터 크래시 + +* UE-10114 LevelScript 에 Overlap 이벤트가 기본으로 추가되지 않아야 + +* UE-10137 리디렉션된 그래프 노드가 IsDataOnlyBlueprint 에서 크래시 유발 + +* UE-10141 비히클 코드 프로젝트의 패키징된 게임에 기본 텍스처 + +* UE-10143 안드로이드에서 SunTemple 의 모든 머티리얼이 반사성 높음 + +* UE-10167 입력핀 없는 커스텀 이벤트 노드 붙여넣기를 되돌리면 크래시 + +* UE-10169 에디터를 통해 VS 를 설치할 때, Microsoft 의 Telemetry 를 활성화시키는 명령줄 파라미터를 포함시켜 인스톨러 실행 + +* UE-10257 Mac 에 안드로이드 디바이스를 처음 연결할 때, tadp 를 설치한 후에도 여전히 sdk 경로를 직접 입력해야 함 + +* UE-10260 미리 존재하던 폴리지가 최고 LOD 에 유지 + +* UE-10277 Mac 에서 에디터를 열 때까지 UFE 에서 안드로이드고 유효 플랫폼으로 표시되지 않음 + +* UE-10283 PIE 가 아닌 독립형 모드로 플레이할 때 TargetArray 노드가 유효하지 않은 것으로 보고 + +* UE-10298 노출 변수를 만드는 것이 블루프린트 디테일 패널을 항상 정확히 업데이트하지 않음 + +* UE-10305 커스텀 이벤트에서 Set Timer 노드를 0 으로 설정해도 타이머가 멈추지 않음 + +* UE-10313 애니메이션 몽타주를 거꾸로 재생할 때 크래시 + +* UE-10319 Struct Transform 의 회전 값을 슬라이더로 편집 시도할 때 크래시 + +* UE-10406 Paper2D 의 모든 섀도우 캐스팅이 깨짐 (스프라이트가 그림자를 드리우지 않음) + +* UE-10410 액터 블루프린트 부모를 변경하면 에디터 크래시 + +* UE-10510 인스턴스에 여러가지 변경이 있을 때 블루프린트에 인스턴스 변경사항을 적용하면 크래시 + +* UE-10524 소스 콘트롤을 켠 상태에서 프로젝트를 생성하면 아이콘 추가에 실패했다고 보고 + +* UE-10529 TappyChicken: HTML5: Firefox: 전체화면 버튼이 화면 중심에서 벗어나 표시 (오른쪽에 커다란 검정 테두리) + +* UE-10537 자손 컴포넌트에 피직스가 켜져 있는데 움직이면 에디터 크래시 + +* UE-10562 셰이더에서 블록이 생성된 경우 공백이고, 안드로이드에서 드라이버 컴파일러 크래시 유발 + +* UE-10646 컴포넌트 창에 씬 컴포넌트 이외의 것을 복사하면 크래시 + +* UE-10650 USceneComponent::UpdatePhysicsVolume 에 크래시 발생 가능 + +* UE-10658 카운트 1 오차 오류로 인해 특정 상황에서 과도한 메모리 소모 + +* UE-10732 블루프린트 생성된 루트 컴포넌트가 있는 액터에 붙은 액터가 움직이면 상대 위치가 틀려짐 + +* UE-10793 GitHub 851 : .gitignore 업데이트 - FeaturePacks 무시 + +* UE-10812 BB 항목 비교가 작동하지 않음 + +* UE-10822 블루프린트 병합 도중 되돌리기 버퍼를 지우면 크래시 + +* UE-10826 이벤트를 지운 후 레벨 BP 를 컴파일면 크래시.Crash compiling Level BP after deleting event + +## 4.7.2 핫픽스 + +릴리즈 날짜: 2015/03/04 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.7.2-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.7.2-release) + +픽스: + +* UE-11207 4.7.1 업그레이드 이후 iOS 실행 실패. provision 도 signing key 도 찾지 못함 + +* UE-11202 Notify 타임라인에서 가로 이동이 매우 좌절스러움 + +* UE-11130 ios 용 코드 프로젝트 빌드 불가 + +* UE-11102 Mac 에디터가 가끔 새 창을 만들 때 FMacWindow::IsMaximized 에서 크래시 + +* UE-11046 컴포넌트 크기가 아주 작을 때 FLandscapeComponentSceneProxy::GetStaticBatchElementVisibility 에서 크래시 + +* UE-11023 엔진을 열 때 크래시: Assert 실패: GConfig->GetInt + +* UE-11018 싱크된 BlackBoard 키가 작동하지 않음 + +* UE-8589 MatineeFightScene 가 mac 에서 사운드가 나지 않음 + +* UE-8550 파티클 이펙트 시네마틱에서 씬 전환 도중 오디오 컷이 잘림 + +## 4.7.3 핫픽스 + +릴리즈 날짜: 2015/03/17 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.7.3-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.7.3-release) + +픽스: + +* UE-11029 4.6.1 에서 4.7.0 으로 변환한 이후 크래시 + +* UE-11404 두 번째 플레이어가 게임패드 입력을 받지 못함 + +* UE-11402 PS4 코드와 SDK 2.0 만 있을 때 에디터가 빌드되지 않음 + +* UE-11485 Xcode 6.3 beta 로 엔진을 컴파일하면 오류 생성 + +* UE-10128 프리뷰 스태틱 메시가 소켓과 함께 이동되지 않음 + +* UE-11315 Bugg 38187: SIGSEGV: 유효하지 않은 0x1010102 주소 메모리 접근 시도 + +* UE-10569 유저 프로젝트의 맵 및 블루프린트를 열 때 크래시 + +* UE-10708 모든 플랫폼으로 유저 프로젝트 빌드 실패 + +* UE-11312 Mac Bugg 38298: SIGSEGV: 유효하지 않은 0x3 주소 메모리 접근 시도 + +* UE-11369 "Two Bone IK" 노드에 클릭하면 크래시 + +* UE-11185 Blueprint Function Library 의 함수 중 그 라이브러리의 다른 함수를 레퍼런싱한 함수는 프로젝트를 닫고 다시 연 이후 저장할 수 없음 + +* UE-11322 BP 노드 새로고침/이동/삭제 후 크래시 + +* UE-11743 4.7 에서 SDK 2.0 이하 Morpheus 지원하지 않음 + +* UE-11302 iPad 에 디플로이 불가 + +* UE-11692 히트 프록시를 렌더링할 때 크래시 + +* UE-11304 빠진 파일이 있어 CrossCompilerTools 컴파일 불가 + +* UE-11484 Xcode 6.3 beta clang 이슈 픽스 + +* UE-11393 타일드 랜드스케이프 임포트가 오버랩된 랜드스케이프 컴포넌트 생성 + +* UE-11017 GitHub 857 : 블랙보드 컴포넌트의 네이티브 enum 지원 수정 + +* UE-10697 프로파일러에서 라이브 데이터 프리뷰를 실행한 채 포스트 프로세스 머티리얼을 열면 크래시 + +* UE-11225 청크를 선택한 채 청크 파라미터 탭을 닫고 디스트럭터블을 다시 열면 크래시 + +* UE-10149 부모 블루프린트 변경 이후 프로젝트를 로드하면 크래시 + +* UE-11244 페르소나 애셋 브라우저에서 애셋 이름을 변경하면 크래시 + +* UE-11272 프로젝트를 업그레이드할 때 블루프린트 컴파일 오류 + +* UE-11319 프로젝트를 열 때 크래시 (어서트 실패) + +* UE-11401 디플로이먼트 서버에 로그 추가 필요 + +* UE-11292 Content Examples 의 Transform(Modify) Bone 노드를 클릭하면 에디터 크래시 + +* UE-10900 독립형 게임에서 FBatchingSPDI::DrawMesh 크래시 + +* UE-11505 Blueprint Office 독립형 실행하면 크래시 + +* UE-10856 스태틱 메시를 씬에 끌어 놓으면 크래시 + +* UE-11298 World Composition 사용 도중 Distance Fields 관련 크래시 + +* UE-11422 GitHub 894 : adb cmd: device 의 반환 값 잘못된 해석 + +* UE-11447 Player Character 가 랜드스케이프와 충돌하지 않음 + +* UE-11638 GetActorsPerception 이 4.7 에서 무용지물 + +* UE-11589 GitHub 909 : .gitignore 업데이트 + +* UE-11605 오버라이드한 컴포넌트가 쿠킹된 빌드의 스태틱 액터에서 깨짐 + +* UE-11666 UberGraphFunction 은 Class::Link 에서 미리 로드되어야 함 + +* UE-11711 파티클이 스태틱 오브젝트와 충돌할 때 심각한 로그 스팸 + +* UE-11640 AI Move To 이슈가 4.7 에서 발생 + +* UE-11360 프로젝트 이름에 ' - ' 를 넣으면 안드로이드 빌드 실패 유발 + +* UE-11647 Denver Tegra K1 (Nexus 9) 에서 악성 퍼포먼스를 유발하는 렌더링 스레드 비활성화 + +* UE-11383 안드로이드 디바이스에서 화면 오리엔테이션이 무시됨 + +* UE-11460 안에 이벤트 디스패처가 배치된 블루프린트 컴포넌트를 사용하는 블루프린트가 있는 경우 레벨이 저장되지 않음 + +* UE-11600 FStringAssetReference 가 들어있는 프로젝트에서 핫 리로드를 실행하면 에디터 크래시 + +* UE-11707 다수의 에디터 스트링 현지화가 깨지던 부분에 대한 우회법 구현 + +* UE-11592 안드로이드 프로젝트의 cook-on-the-fly 가 디바이스에서 실행 이후 크래시 + +* UE-11739 특정 환경에서 CrowdManager 가 생성되지 않음 + +* UE-11321 랜드스케이프를 생성할 때 크래시 + +* UE-11777 BP 구현된 BT 데코레이터가 활성 브랜치에 있지 않다고 생각하게 됨 + +* UE-11826 MediaPlayer14 클래스 룩업이 배포 빌드에서 크래시 + +* UE-11840 Nexus 9 에서 실행하면 알려지지 않은 arm64-v8a 아키텍처로 인해 실패 + +* UE-11893 도킹된 창을 드래그할 때 에디터 크래시 + +## 4.7.4 핫픽스 + +릴리즈 날짜: 2015/04/02 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.7.4-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.7.4-release) + +픽스: + +* UE-11891 MoveToActor 가 골 액터 이동 시 AI 경로를 업데이트하지 않음 + +* UE-11997 NavOctree 부재 시 PIE 의 내비게이션 크래시 + +* UE-12108 [CrashReport] UPrimitiveComponent::SetCanEverAffectNavigation() 에서 Ensure 발생 + +* UE-12106 [CrashReport] 블루프린트 변경 이후 저장하면 크래시 유발 + +* UE-12443 [CrashReport] 자동저장 도중 블루프린트 크래시 + +* UE-9417 코멘트 박스가 다른 코멘트 블록에 겹칠 때 선택할 수 없는 경우가 많음 + +* UE-10891 다른 블루프린트의 부모 블루프린트를 강제 삭제하면 크래시 유발 + +* UE-10865 4.6.1 에서 4.7 변환 시 "어서트 실패: Pin != nullptr ...K2Node_DynamicCast.cpp]" + +* UE-11523 DateTime 변수가 컴파일 시 크래시 유발 + +* UE-11011 블루프린트의 프로퍼티 접근 시 크래시 (어서트) + +* UE-12073 [CrashReport] 블루프린트 노드 연결끊기/변경 시 크래시 유발 + +* UE-12206 GitHub 944 : UE-12128: struct 칸 기본 값이 다를 때 struct 제대로 저장 + +* UE-12962 "Apply Instance Change to Blueprint" (인스턴스 변경사항을 블루프린트에 저장) 버튼을 클릭한 이후 에디터 크래시 + +* UE-10574 템플릿의 컴포넌트 프로퍼티가 SpawnActor 를 호출했을 때 전파되지 않음 + +* UE-12109 [CrashReport] 프로젝트 로드 시도 도중 크래시 + +* UE-11368 속이 빈 BSP 의 머티리얼 UV 스케일이 지오메트리 빌드 이후 유지되지 않음 + +* UE-4743 스프라이트 시트의 일부로 임포트된 스프라이트를 다른 폴더로 옮길 때 그 스프라이트 이름에 잘못된 캐릭터가 있는 경우 크래시 + +* UE-11372 뷰 옵션을 변경할 때 UE4Editor_SlateCore!TWeakPtr 에서 Access Violation + +* UE-9824 위젯 클래스가 리로드 시 플레이스홀더 클래스로 대체 + +* UE-10040 다른 버튼 안에 한 버튼을 복사/붙여넣기 한 뒤 붙여넣은 버튼을 이동하려 하면 에디터 크래시 + +* UE-11204 뷰포트 아래 에디터 창을 탭으로 달고 몰입 모드에서 뷰포트로 돌아오면 크래시 + +* UE-12915 폴리지에서 스태틱 라이팅을 사용하면 크래시 + +* UE-7213 페르소나 애님 BP 뷰포트에서 기즈모 순환하면 크래시 + +* UE-9982 피벗이 중심에 있지 않은 스프라이트가 썸네일 렌더링에 안보일 수 있음 + +* UE-12196 자동 콜리전 생성 기능이 스프라이트 시트에서 회전된 것으로 임포트된 스프라이트에 잘못된 회전 적용 + +* UE-12041 텍스처가 변경된 스프라이트 시트가 제대로 리임포트되지 않음 + +* UE-7918 스프라이트가 쿠킹된 빌드에서 PixelsPerUnrealUnit 초기화를 하지 않아, 픽셀/uu 가 2.56 인 애셋에 대한 GetSocketLocation 등의 결과가 잘못 나옴 + +* UE-11903 opengl 에서 ElementalDemo 게임을 닫을 때 크래시 + +* UE-12150 서브레벨의 숨겨진 레벨에 랜드스케이프가 있을 때 PIE 를 실행하면 크래시 + +* UE-12111 [CrashReport] 랜드스케이프 되돌리기/삭제 후 크래시 + +* UE-12433 랜드스케이프가 들어있는 서브레벨의 비저빌리티 토글을 끄면 에디터 크래시 + +* UE-11815 [CrashReport] iOS 디바이스에 연결을 시도하는 도중 크래시 + +* UE-12165 Morpheus 실행 도중 가끔 크래시 + +* UE-12209 Canvas 아이템이 Morpheus 에서 제대로 그려지지 않음 + +* UE-12211 Morpheus 에서 VSync 를 켜도 시각적으로 찢어져 보임 + +* UE-12212 Morpheus 가 증가된 시간에 HMD 디스토션 셰이더 실행 + +* UE-12324 콘솔 렌더링이 화면에 있을 때 Morpheus 렌더링이 깨짐 + +* UE-11302 iPad 에 디플로이 불가 + +* UE-12063 리눅스에서 프로젝트 패키징 불가 + +* UE-12210 Morpheus IPD 가 잘못 적용 + +* UE-13048 Xbox (코드 및 BP) 프로젝트가 검정 화면에 실행되지만 로그에는 성공이라 나옴 + +* UE-12213 랜드스케이프 머티리얼을 안드로이드 디바이스에서 실행하면 기본값 복원 + +* UE-12542 MAC: 에디터에서 텍스처 압축 시간 매우 느림 + +* UE-12235 섀도우 렌더링에 큰 퍼포먼스 퇴보 + +* UE-6190 모바일 프리뷰 모드에서 일부 스켈레탈 메시의 경우 UV 가 왜곡 + +* UE-11865 (라이팅은 빌드되고) 인스턴스드 메시가 들어있는 레벨을 열면 에디터 크래시 + +* UE-10664 폴리지 포함 맵을 로드한 이후 다른 맵을 열 때 OpenGL3 및 OpenGL4 크래시 + +* UE-11810 [CrashReport] Texture 형변환하는 ULevel::BuildStreamingData 에서 크래시 + +* UE-11434 에디터 로드 시 새로운 유저 크래시 + +* UE-12228 크래시에 유효하지 않은 오류 메시지 + +## 4.7.5 핫픽스 + +릴리즈 날짜: 2015/04/08 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.7.5-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.7.5-release) + +픽스: + +* UE-13250 Multiplayer Shootout 프로젝트 샘플 시작 시 크래시 + +* UE-13274 4.7.3 에서 4.7.4 로 프로젝트 변환 후 실행하면 크래시 + +* UE-11828 리눅스에서 랜드스케이프 HydroErosion 크래시 + +## 4.7.6 핫픽스 + +릴리즈 날짜: 2015/04/20 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.7.6-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.7.6-release) + +픽스: + +* UE-13664 MAC: 시작 시 크래시 + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_8/Updates/UnrealEngine4_8UpdateNotes.CHN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_8/Updates/UnrealEngine4_8UpdateNotes.CHN.udn new file mode 100644 index 000000000000..8bf6ea901cf2 --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_8/Updates/UnrealEngine4_8UpdateNotes.CHN.udn @@ -0,0 +1,182 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 虚幻引擎 4.8 更新日志 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/2015/4_8 +Order:0 + +## 4.8.0 Release + +Released: 06/08/2015 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.8.0-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.8.0-release) + +Release Notes: [](Support/Builds/ReleaseNotes/2015/4_8) + +## 4.8.1 Hotfix + +Released: 06/24/2015 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.8.1-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.8.1-release) + +Fixes: + +* UE-11816 [CrashReport] Garbage collection crashes not caused directly by the editor + +* UE-12079 Crash: UGameInstance::StartGameInstance "Failed to enter xx" + +* UE-14313 Tappy chicken size has increased dramatically from 4.6 to 4.7 + +* UE-15505 Elemental Demo when played does not start matinee + +* UE-15651 GitHub 1148 : Fix divide by zero when importing 0-length animations + +* UE-16471 UMapProperty crashes + +* UE-16513 [CrashReport] Adding a Return node to a function that contains a Local array variable then compiling will crash the engine + +* UE-16521 [CrashReport] UE4Editor_Core!FRunnableThread::SetTls() [threadingbase.cpp:267] + +* UE-16711 Xbox fails to open BP projects for shipping config + +* UE-16724 StaticFindObject can return objects that have not been fully streamed in + +* UE-16752 [CrashReport] UE4Editor_D3D11RHI!VerifyD3D11CreateTextureResult() [d3d11util.cpp:223] + +* UE-16754 GatherTextFromSource commandlet always fails when using the deprecated SourceFileSearchFilters setting. + +* UE-16789 'Target' pin name in certain BP nodes jitters in localized mode + +* UE-16806 [CrashReport] UE4Editor_HotReload!GetCachedCDODuplicate() [hotreload.cpp:636] + +* UE-16844 [CrashReport] Building lighting with a CustomMeshComponent in level causes crash + +* UE-16894 Interrupting the KiteDemo cinematic leaves you with no drone controls + +* UE-16900 Crash when Applying Hole Material to Imported Tiled Landscape with World Composition + +* UE-16907 Project using ScriptPluginComponents can crash when upgrading to 4.8 + +* UE-16918 Sprite sheets cannot be reimported in 4.8 in a project that was converted from an older version + +* UE-16971 Packaging fails with plugin and full rebuild checked + +* UE-16972 Self reference disconnecting on editor restart + +* UE-16995 Crash undoing TMap UProperties + +* UE-17008 Editor crashes every time you save if there is no editor startup map set + +* UE-17067 Engine builds need to include engine localization data + +* UE-17075 The localization dashboard generates inaccurate paths when referencing files on a different drive than the binary. + +* UE-17082 Project debug symbols are no longer included in crash reporter callstacks. + +* UE-17087 Assertion failed: !Result || Result->LinkerLoad == Linker crash + +* UE-17111 Indirect Lighting Cache is broken on PS4 + +* UE-17129 Crash when terminating a Matinee camera anim + +* UE-17153 USkinnedMeshComponent::QuerySupportedSockets behaves differently in !WITH_EDITOR + +* UE-17194 LoadPackageInternal may crash due to corrupted linkers + +* UE-17221 Hot reloading does not work on Linux + +* UE-17222 CPU usage is not decreased when the editor isn't in foreground on Linux + +* UE-17228 Cook commandlet dies on Linux with error if run on a headless machine. + +* UE-17233 Media streaming from the internet is not working on Windows + +## 4.8.2 Hotfix + +Released: 07/14/2015 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.8.2-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.8.2-release) + +Fixes: + +* UE-16177 When launching the editor and having oculus_runtime_sdk_0.6.0.0_win_partner installed, the editor crashes. + +* UE-16608 Convert Actor option is grayed out and not selectable. (ConversionRoot metadata not found) + +* UE-16822 [CrashReport] Saving in animation blueprint can cause a crash + +* UE-16896 Level streaming crash in KiteDemo after retriggering cinematic + +* UE-16905 User Play Space Rot does not change anything in Client Play Camera Shake + +* UE-16966 Default settings cannot be used to import character animations + +* UE-16970 StrategyGame crash on android devices bad name index + +* UE-17103 Curve editor breaks randomly in Cascade + +* UE-17118 Custom Output node added to a Material Editor crashes Editor + +* UE-17163 [CrashReport] dxgi! and RHI related crash on project open + +* UE-17167 [CrashReport] Character interaction with asset causes crash + +* UE-17177 Localization manifest writing fails if source control is hooked up and the manifest file does not exist already. + +* UE-17211 [CrashReport] Clicking connection wires between blueprints nodes causes crash + +* UE-17212 Stack overflow due to heavy recursion in indirect lighting cache + +* UE-17213 LightSourceAngle is incorrectly greyed out + +* UE-17216 [CrashReport] Crash in FD3D11ComputeShader::~FD3D11ComputeShader() + +* UE-17226 OnPaint function causes artifacts to show up in a New Editor window + +* UE-17384 Import options broken when importing bones-only fbx animation + +* UE-17385 Android game packaged with obb outside apk does not create SaveGame directory on device + +* UE-17400 Regression for UPROPERTY specifier causing crash ("Template Mismatch during attachment") during PIE + +* UE-17419 Crash compiling BPAIController and RunnerAI via session frontend test + +* UE-17443 DynamicModifiersOnly navmesh generation mode doesn't work + +* UE-17523 Paper2D Set Sprite function in Construction requires mobility to be set to Movable + +* UE-17562 [CrashReport] Crash in TBaseMulticastDelegate >::AddDelegateInstance() + +* UE-17569 GitHub 1309 : [Core][Windows] Don't crash when GetRawInputData() fails. + +* UE-17673 Clicking the GameMode Override dropdown in the World Settings tab crashes the editor + +* UE-17792 Analog Input does not work for network clients (AddMovementInput scale values other than 0 and 1 do not replicate for clients) + +* UE-17829 Second client fails to load when using multiplayer PIE in separate processes + +* UE-18020 Crash Report Client - updates to data collection + +* UE-18041 [CrashReport] Fatal error in PostInitProperties + +* UE-18080 [CrashReport] Crash in UProjectileMovementComponent::TickComponent() + +* UE-18173 Crash report client submits user names for github builds + +## 4.8.3 Hotfix + +Released: 07/29/2015 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.8.3-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.8.3-release) + +Fixes: + +* UE-18668 Crash when closing projects + +* UE-17342 Crash when exiting PIE after server travel + +* UE-18530 Assert in ConformComponentsUtils::FindeNativeArchetype + +* UE-19151 Parallel Rendering is disabled in Shipping builds + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_8/Updates/UnrealEngine4_8UpdateNotes.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_8/Updates/UnrealEngine4_8UpdateNotes.JPN.udn index 555ad44b6927..078491d594bf 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_8/Updates/UnrealEngine4_8UpdateNotes.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_8/Updates/UnrealEngine4_8UpdateNotes.JPN.udn @@ -1,6 +1,6 @@ INTSourceChangelist:0 Availability:Public -Title: Unreal Engine 4.8 Update Notes +Title: アンリアル エンジン 4.8 アップデート ノート Description: Crumbs: Parent:Support/Builds/ReleaseNotes/2015/4_8 diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_8/Updates/UnrealEngine4_8UpdateNotes.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_8/Updates/UnrealEngine4_8UpdateNotes.KOR.udn new file mode 100644 index 000000000000..73306fa3b1ae --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_8/Updates/UnrealEngine4_8UpdateNotes.KOR.udn @@ -0,0 +1,182 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 언리얼 엔진 4.8 업데이트 노트 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/2015/4_8 +Order:0 + +## 4.8.0 릴리즈 + +릴리즈 날짜: 2015/06/08 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.8.0-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.8.0-release) + +릴리즈 노트: [](Support/Builds/ReleaseNotes/2015/4_8) + +## 4.8.1 핫픽스 + +릴리즈 날짜: 2015/06/24 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.8.1-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.8.1-release) + +픽스: + +* UE-11816 [CrashReport] 에디터에 직접적 원인이 없는 가비지 콜렉션 크래시 + +* UE-12079 Crash: UGameInstance::StartGameInstance "Failed to enter xx" + +* UE-14313 Tappy chicken 크기가 4.6 에서 4.7 로 가면서 많이 커짐 + +* UE-15505 Elemental Demo 플레이하면 마티네가 시작되지 않음 + +* UE-15651 GitHub 1148 : 길이가 0 인 애니메이션 임포트할 때 divide by zero 수정 + +* UE-16471 UMapProperty 크래시 + +* UE-16513 [CrashReport] 로컬 배열 변수가 들어있는 함수에 Return 노드를 추가한 뒤 컴파일하면 엔진 크래시 + +* UE-16521 [CrashReport] UE4Editor_Core!FRunnableThread::SetTls() [threadingbase.cpp:267] + +* UE-16711 Xbox 에서 shipping 구성으로 BP 프로젝트 안열림 + +* UE-16724 StaticFindObject 가 완전히 스트림 인 되지 않은 오브젝트 반환 가능 + +* UE-16752 [CrashReport] UE4Editor_D3D11RHI!VerifyD3D11CreateTextureResult() [d3d11util.cpp:223] + +* UE-16754 GatherTextFromSource 커맨드렛이 폐기된 SourceFileSearchFilters 세팅을 사용하면 항상 실패 + +* UE-16789 현지화 모드에서 특정 BP 노드의 'Target' 핀 이름이 떨림 + +* UE-16806 [CrashReport] UE4Editor_HotReload!GetCachedCDODuplicate() [hotreload.cpp:636] + +* UE-16844 [CrashReport] 레벨에 CustomMeshComponent 포함 라이팅 빌드 시 크래시 + +* UE-16894 KiteDemo 시네마틱을 중단하면 드론 컨트롤 못함 + +* UE-16900 월드 컴포지션 포함 임포트된 타일 랜드스케이프에 홀 머티리얼을 적용하면 크래시 + +* UE-16907 ScriptPluginComponents 를 사용하는 프로젝트를 4.8 로 업그레이드하면 크래시 가능 + +* UE-16918 구버전에서 변환된 프로젝트에서 4.8 로 스프라이트 시트 리임포트 불가 + +* UE-16971 플러그인 및 풀 리빌드 체크 상태에서 패키지 실패 + +* UE-16972 에디터를 재시작하면 셀프 레퍼런스 연결 끊어짐 + +* UE-16995 TMap UProperties 되돌리기 크래시 + +* UE-17008 에디터 스타트업 맵이 설정되지 않은 경우 저장할 때마다 에디터 크래시 + +* UE-17067 엔진 빌드에 엔진 현지화 데이터 포함 필요 + +* UE-17075 현지화 대시보드에서 바이너리와 다른 드라이브의 파일을 레퍼런싱할 때 정확하지 않은 경로 생성 + +* UE-17082 프로젝트 디버그 심볼이 더이상 크래시 리포터 콜스택에 포함되지 않음 + +* UE-17087 어서트 실패: !Result || Result->LinkerLoad == Linker 크래시 + +* UE-17111 PS4 에서 간접 라이팅 캐시가 깨짐 + +* UE-17129 마티네 카메라 애님 종료 시 크래시 + +* UE-17153 USkinnedMeshComponent::QuerySupportedSockets 작동이 !WITH_EDITOR 와 다름 + +* UE-17194 LoadPackageInternal 가 깨진 링커로 인해 크래시 가능 + +* UE-17221 핫 리로드가 리눅스에서 작동하지 않음 + +* UE-17222 리눅스에서 에디터가 포그라운드 실행중이지 않을 때 CPU 사용량 감소 + +* UE-17228 헤드리스 머신에서 실행된 경우 Cook 커맨드렛이 리눅스에서 오류를 내며 죽는 현상 + +* UE-17233 인터넷에서 미디어 스트리밍이 윈도우에서 작동하지 않음 + +## 4.8.2 핫픽스 + +릴리즈 날짜: 2015/07/14 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.8.2-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.8.2-release) + +픽스: + +* UE-16177 에디터를 실행하고 oculus_runtime_sdk_0.6.0.0_win_partner 가 설치된 상태에서 에디터 크래시 + +* UE-16608 Convert Actor 옵션이 비활성화되어 선택 불가 (ConversionRoot 메타데이터 없음) + +* UE-16822 [CrashReport] 애니메이션 블루프린트에서 저장이 크래시 유발 가능 + +* UE-16896 KiteDemo 에서 시네마틱 재발동 후 레벨 스트리밍 크래시 + +* UE-16905 User Play Space Rot 이 Client Play Camera Shake 에서 아무것도 변경하지 않음 + +* UE-16966 기본 세팅으로 캐릭터 애니메이션 임포트 불가 + +* UE-16970 StrategyGame 이 안드로이드 디바이스에서 네임 인덱스가 잘못된 경우 크래시 + +* UE-17103 캐스케이드에서 랜덤하게 커브 에디터가 깨짐 + +* UE-17118 머티리얼 에디터에 Custom Output 노드를 추가하면 에디터 크래시 + +* UE-17163 [CrashReport] 프로젝트 열 때 dxgi! 및 RHI 관련 크래시 + +* UE-17167 [CrashReport] 애셋 포함 캐릭터 통합 시 크래시 유발 + +* UE-17177 소스 콘트롤 연결 상태에서 manifest 가 이미 존재하지 않는 경우 현지화 manifest 쓰기 실패 + +* UE-17211 [CrashReport] 블루프린트 노드 사이 연결 선을 클릭하면 크래시 유발 + +* UE-17212 간접 라이팅 캐시의 과도한 반복으로 스택 오버플로우 + +* UE-17213 LightSourceAngle 가 비정상적으로 비활성화 + +* UE-17216 [CrashReport] FD3D11ComputeShader::~FD3D11ComputeShader() 크래시 + +* UE-17226 OnPaint 함수가 새 에디터 창에 부작용 유발 + +* UE-17384 본만 있는 fbx 애니메이션 임포트 시 임포트 옵션 깨짐 + +* UE-17385 apk 외부 obb 로 패키징된 안드로이드 게임이 디바이스에 SaveGame 디렉토리를 생성하지 않음 + +* UE-17400 PIE 도중 ("어태치먼트 도중 템플릿 불일치") 크래시를 유발하는 UPROPERTY 지정자 퇴보 + +* UE-17419 세션 프론트엔드 테스트를 통해 BPAIController 및 RunnerAI 컴파일 도중 크래시 + +* UE-17443 DynamicModifiersOnly 내비메시 생성 모드가 작동하지 않음 + +* UE-17523 컨스트럭션에서 Paper2D Set Sprite 함수가 모빌리티를 Movable 로 설정해야 함 + +* UE-17562 [CrashReport] TBaseMulticastDelegate >::AddDelegateInstance() 크래시 + +* UE-17569 GitHub 1309 : [Core][Windows] GetRawInputData() 실패 시 크래시가 나지 않음 + +* UE-17673 월드 세팅 탭의 GameMode Override 드롭다운을 클릭하면 에디터 크래시 + +* UE-17792 Analog Input 이 네트워크 클라이언트에 작동하지 않음 (AddMovementInput 0 이나 1 이외의 스케일 값이 클라이언트에 리플리케이트되지 않음) + +* UE-17829 별도의 프로세스로 멀티플레이어 PIE 를 사용하면 두 번째 클라이언트 로드 실패 + +* UE-18020 Crash Report Client - 데이터 콜렉션 업데이트 + +* UE-18041 [CrashReport] PostInitProperties 의 치명적 오류 + +* UE-18080 [CrashReport] UProjectileMovementComponent::TickComponent() 크래시 + +* UE-18173 크래시 리포트 클라이언트가 github 빌드의 경우 사용자 이름 제출 + +## 4.8.3 핫픽스 + +릴리즈 날짜: 2015/07/29 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.8.3-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.8.3-release) + +픽스: + +* UE-18668 프로젝트를 닫으면 크래시 + +* UE-17342 서버 트래블 이후 PIE 를 종료하면 크래시 + +* UE-18530 ConformComponentsUtils::FindeNativeArchetype 어서트 + +* UE-19151 Shipping 빌드에서 패럴렐 렌더링 비활성화 + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_9/Updates/UnrealEngine4_9UpdateNotes.CHN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_9/Updates/UnrealEngine4_9UpdateNotes.CHN.udn new file mode 100644 index 000000000000..d989c52f597a --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_9/Updates/UnrealEngine4_9UpdateNotes.CHN.udn @@ -0,0 +1,140 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 虚幻引擎 4.9 更新日志 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/2015/4_9 +Order:0 + +## 4.9.0 Release + +Released: 08/31/2015 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.9.0-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.9.0-release) + +Release Notes: [](Support/Builds/ReleaseNotes/2015/4_9) + +## 4.9.1 Hotfix + +Released: 09/15/2015 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.9.1-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.9.1-release) + +Fixes: + +* UE-20265 ForEach 'Enum' node returns incorrect enum values + +* UE-20643 Enum to Byte conversion returns 2 for the first enum then 4 then 6 and so on rather than 0, 1, 2, etc + +* UE-20878 Child Blueprint getting certain property values cleared in cooked games + +* UE-20009 [CrashReport] UE4Editor_UnrealEd!operator<<() [editortransaction.cpp:157] + +* UE-20867 Issues converting enum to byte in BP + +* UE-20733 Disabling collision of an actor after an overlap event will cause the event to fire twice + +* UE-20466 [CrashReport] UE4Editor_Engine!UAnimSequence::GetBonePose() [animsequence.cpp:994] + +* UE-20413 Montage with negative value of curves doesn't work + +* UE-20496 Overlap checks during swept movement can generate repeated begin/end overlaps, or wrong end overlap event + +* UE-20146 Can't increase lightmap resolution on landscape, it crashes + +* UE-20202 Dynamic point lights generate shader compile errors on HTML5 + +* UE-20492 Renamed/Copied code project folders fail to launch on to iOS + +* UE-20728 Editable Text crashes on Android + +* UE-20380 HTML5: Mac: RunMacHTML5LaunchHelper.command has incorrect file type in P4, causes error + +* UE-20419 Mono error encountered with packaged HTML5 sample + +* UE-20872 Enabling MSAA crashes when using metal + +* UE-20968 Offline Shader Compile has been disabled on Mac + +* Note: When performing a launch on from the Mac to iOS the first time there will be an increase in the cook time as the shaders will be rebuilt. + +* UE-20928 Launch on for Android may crash or use wrong version of aapt + +* UE-20864 Launch on to Wi-Fi Android devices will fail + +* UE-20008 SunTemple exits to home screen on the iPad 4 + +* UE-20590 Can't build UE4Game for IOS from PC + +* UE-12215 Sound effects continue to play when game is suspended on Android + +* UE-20692 Epic Games Launcher unhides while the editor is loading on Mac + +* UE-20991 Launch On for iOS does not automatically start + +* Note: The Launch On feature for iOS on Mac has been temporarily disabled due to an incompatibility with Xcode 7.0. We are working on the issue for 4.10. + +* UE-20640 SSAO 4.9 perf regression fix + +* UE-20335 Blendable Weight set higher than 1.0 crashes + +* UE-20639 Crash on Mobile Previewing or Playing in a New Editor Viewport a Mobile/Tablet - Mobile/HTML Project + +* UE-20297 REGRESSION: HierarchicalInstancedStaticMeshComponent LOD transitions are broken in 4.9 and Main + +* UE-20172 [CrashReport] UE4Editor_Engine!FBatchedElements::FSimpleElementBSSContainer::GetBSS() [batchedelements.h:308] + +* UE-20699 "Build Solution" does not work for GitHub users + +* UE-20291 Rev Oculus SDK to 0.7 / 0.6.18 + +## 4.9.2 Hotfix + +Released: 09/30/2015 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.9.2-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.9.2-release) + +Fixes: + +* UE-20792 DrawMaterial() Function not Rendering Translucent Material to HUD + +* UE-21233 Calling RequestStimuliListenerUpdate on actor with one element in AIPerception Sensing Config causes crash + +* UE-21234 Crash on play when AIPerception Senses Config element is set to "sense config" options + +* UE-20913 Undo after deletion in BP editor causes crash + +* UE-17698 [CrashReport] UE4Editor_CoreUObject!UStruct::IsChildOf() [class.h:400] + +* UE-20644 [CrashReport] Crash while undoing in Blueprints - FObjectRecord::FReader::operator + +* UE-20258 Child blueprint classes can no longer change default values for inherited variables + +* UE-21081 Cannot open assets created in 4.9.1 in 4.9.0 version of editor + +* UE-20210 [CrashReport] Crash on Windows Chinese version when changing editor language + +* UE-21337 Movies are not skipped when Wait for Movies to Complete is false + +* UE-21292 Parallax Occlusion Mapping broken on Macs + +* UE-21127 Crash in FSlateImageRun destructor + +* UE-20550 Sliders and check boxs not working on touch screen device + +* UE-21076 Possible divide by zero in animation transitions with zero crossfade durations + +* UE-20961 [CrashReport] UE4Editor_Engine!FKShapeElem::GetShapeCheck() [shapeelem.h:55] + +* UE-20952 Launching a Project which uses Depth of Field crashes to Home Screen on iOS8 device + +* UE-21123 PowerVR Galaxy S4 (GT-I9500) shows black scene when MobileHDR enabled + +* UE-21367 Submitting to App store for IOS 9 leads to validation errors + +* UE-20940 Effects.umap causes Standalone and Mobile Preview PIE to Crash + +* UE-21126 Foliage culling broken on XboxOne + +* UE-21185 Update buttons on CrashReporter window to encourage submission + diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_9/Updates/UnrealEngine4_9UpdateNotes.JPN.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_9/Updates/UnrealEngine4_9UpdateNotes.JPN.udn index b629c540e525..ea0279b196ac 100644 --- a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_9/Updates/UnrealEngine4_9UpdateNotes.JPN.udn +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_9/Updates/UnrealEngine4_9UpdateNotes.JPN.udn @@ -1,6 +1,6 @@ INTSourceChangelist:0 Availability:Public -Title: Unreal Engine 4.9 Update Notes +Title: アンリアル エンジン 4.9 アップデート ノート Description: Crumbs: Parent:Support/Builds/ReleaseNotes/2015/4_9 diff --git a/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_9/Updates/UnrealEngine4_9UpdateNotes.KOR.udn b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_9/Updates/UnrealEngine4_9UpdateNotes.KOR.udn new file mode 100644 index 000000000000..ad65861c7e98 --- /dev/null +++ b/Engine/Documentation/Source/Support/Builds/ReleaseNotes/4_9/Updates/UnrealEngine4_9UpdateNotes.KOR.udn @@ -0,0 +1,140 @@ +INTSourceChangelist:3367470 +Availability:Public +Title: 언리얼 엔진 4.9 업데이트 노트 +Description: +Crumbs: +Parent:Support/Builds/ReleaseNotes/2015/4_9 +Order:0 + +## 4.9.0 릴리즈 + +릴리즈 날짜: 2015/08/31 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.9.0-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.9.0-release) + +릴리즈 노트: [](Support/Builds/ReleaseNotes/2015/4_9) + +## 4.9.1 핫픽스 + +릴리즈 날짜: 2015/09/15 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.9.1-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.9.1-release) + +픽스: + +* UE-20265 ForEach 'Enum' 노드가 잘못된 enum 값을 반환 + +* UE-20643 Enum to Byte 변환이 0, 1, 2 식이 아닌 2, 4, 6 식으로 반환 + +* UE-20878 자손 블루프린트가 쿠킹된 게임에서 특정 프로퍼티 값을 지움 + +* UE-20009 [CrashReport] UE4Editor_UnrealEd!operator<<() [editortransaction.cpp:157] + +* UE-20867 블루프린트에서 enum to byte 변환 관련 이슈 + +* UE-20733 오버랩 이벤트 후 액터 콜리전을 끄면 이벤트가 두 번 발동 + +* UE-20466 [CrashReport] UE4Editor_Engine!UAnimSequence::GetBonePose() [animsequence.cpp:994] + +* UE-20413 음수 커브 값이 있는 몽타주 작동 않음 + +* UE-20496 스윕 이동 도중 오버랩 체크가 반복된 오버랩 시작/끝 또는 잘못된 오버랩 끝 이벤트 생성 가능 + +* UE-20146 랜드스케이프에서 라이트맵 해상도를 올리면 크래시 + +* UE-20202 다이내믹 포인트 라이트가 HTML5 에서 셰이더 컴파일 오류 + +* UE-20492 코드 프로젝트 폴더 이름변경/복사한 경우 iOS 에서 실행에 실패 + +* UE-20728 Editable Text 가 Android 에서 크래시 + +* UE-20380 HTML5: Mac: RunMacHTML5LaunchHelper.command 가 P4 에 파일 유형이 잘못되어 오류 유발 + +* UE-20419 패키징된 HTML5 샘플 관련 Mono 오류 + +* UE-20872 Metal 사용 시 MSAA 켜면 크래시 + +* UE-20968 Mac 에서 Offline Shader Compile 꺼짐 + +* 주: Mac 에서 IOS 로 처음 실행시킬 때, 셰이더 리빌드로 인해 쿠킹 시간이 증가됩니다. + +* UE-20928 Android 에서 실행 옵션이 크래시가 나거나 aapt 잘못된 버전 사용 + +* UE-20864 Wi-Fi Android 디바이스에서 실행 옵션이 실패 + +* UE-20008 SunTemple 이 iPad 4 에서 홈 화면으로 빠져나감 + +* UE-20590 PC 에서 iOS 용 UE4Game 빌드 불가 + +* UE-12215 Android 에서 게임을 일시정지했을 때 사운드 이펙트가 계속 재생 + +* UE-20692 Mac 에서 에디터 로드 도중 에픽 게임즈 런처 숨김이 해제 + +* UE-20991 iOS 에서 실행 옵션이 자동으로 시작되지 않음 + +* 주: Mac 의 iOS 에서 실행 옵션은 Xcode 7.0 과 호환되지 않아 임시로 비활성화되었습니다. 4.10 에서 이 이슈 해결 작업을 하고 있습니다. + +* UE-20640 SSAO 4.9 퍼포먼스 퇴보 픽스 + +* UE-20335 Blendable Weight 가 1.0 초과 설정된 경우 크래시 + +* UE-20639 모바일/태블릿 - 모바일/HTML 프로젝트를 모바일 프리뷰 또는 새 에디터 뷰포트에서 플레이 시 크래시 + +* UE-20297 퇴보: HierarchicalInstancedStaticMeshComponent LOD 전환이 4.9 와 Main 에서 깨짐 + +* UE-20172 [CrashReport] UE4Editor_Engine!FBatchedElements::FSimpleElementBSSContainer::GetBSS() [batchedelements.h:308] + +* UE-20699 GitHub 사용자에게 Build Solution 이 작동하지 않음 + +* UE-20291 Oculus SDK 를 0.7 / 0.6.18 로 변경 + +## 4.9.2 핫픽스 + +릴리즈 날짜: 2015/09/30 + +Github: [https://github.com/EpicGames/UnrealEngine/releases/tag/4.9.2-release](https://github.com/EpicGames/UnrealEngine/releases/tag/4.9.2-release) + +픽스: + +* UE-20792 DrawMaterial() 함수가 반투명 머티리얼을 HUD 에 렌더링하지 않음 + +* UE-21233 AIPerception Sensing Config 에 엘리멑느가 하나 있는 액터에서 RequestStimuliListenerUpdate 호출 시 크래시 + +* UE-21234 AIPerception Senses Config 엘리먼트가 sense config 옵션으로 설정되었을 때 플레이 시 크래시 + +* UE-20913 BP 에디터에서 삭제 이후 되돌리기 하면 크래시 + +* UE-17698 [CrashReport] UE4Editor_CoreUObject!UStruct::IsChildOf() [class.h:400] + +* UE-20644 [CrashReport] 블루프린트에서 되돌리기할 때 크래시 - FObjectRecord::FReader::operator + +* UE-20258 자손 블루프린트 클래스가 더이상 상속된 변수의 기본값 변경 불가 + +* UE-21081 4.9.0 버전 에디터에서 4.9.1 버전으로 생성된 애셋을 열 수 없음 + +* UE-20210 [CrashReport] 윈도우 중국 버전에서 에디터 언어를 변경할 때 크래시 + +* UE-21337 Wait for Movies to Complete 옵션이 false 인 경우 무비 건너뛰기 불가 + +* UE-21292 Parallax Occlusion Mapping 이 Mac 에서 깨짐 + +* UE-21127 FSlateImageRun 소멸자에서 크래시 + +* UE-20550 터치 스크린 디바이스에서 슬라이더와 체크박스가 작동되지 않음 + +* UE-21076 크로스페이드 기간이 0 인 애니메이션 전환 시 divide by zero 발생 가능 + +* UE-20961 [CrashReport] UE4Editor_Engine!FKShapeElem::GetShapeCheck() [shapeelem.h:55] + +* UE-20952 Depth of Field 를 사용하는 프로젝트 실행 시 iOS 디바이스에서 홈 화면으로 크래시 + +* UE-21123 PowerVR Galaxy S4 (GT-I9500) 에서 MobileHDR 활성화 시 검정 화면 + +* UE-21367 iOS 에서 앱 스토어 제출 시 인증 오류 + +* UE-20940 Effects.umap 으로 인해 Standalone 및 Mobile Preview PIE 크래시 + +* UE-21126 폴리지 컬링이 XboxOne 에서 깨짐 + +* UE-21185 CrashReporter 창의 업데이트 버튼이 제출을 장려하도록 변경 + diff --git a/Engine/Documentation/Source/Support/BusinessAndLegal/BusinessAndLegal.CHN.udn b/Engine/Documentation/Source/Support/BusinessAndLegal/BusinessAndLegal.CHN.udn index 15261993ec9a..89680e6b8fe3 100644 --- a/Engine/Documentation/Source/Support/BusinessAndLegal/BusinessAndLegal.CHN.udn +++ b/Engine/Documentation/Source/Support/BusinessAndLegal/BusinessAndLegal.CHN.udn @@ -20,7 +20,6 @@ Navigation:role [/PARAM] [PARAM:links] * [](Support/BusinessAndLegal/TermsAndConditions "%Support/BusinessAndLegal/TermsAndConditions:description%") - * [](Support/BusinessAndLegal/TrademarksAndLogos "%Support/BusinessAndLegal/TrademarksAndLogos:description%") [/PARAM] [/OBJECT] diff --git a/Engine/Documentation/Source/Support/BusinessAndLegal/BusinessAndLegal.INT.udn b/Engine/Documentation/Source/Support/BusinessAndLegal/BusinessAndLegal.INT.udn index c4a5d6a7c6e7..22bc98f8ae36 100644 --- a/Engine/Documentation/Source/Support/BusinessAndLegal/BusinessAndLegal.INT.udn +++ b/Engine/Documentation/Source/Support/BusinessAndLegal/BusinessAndLegal.INT.udn @@ -9,32 +9,4 @@ Version: 4.9 ![Business and Legal](business.png) [/REGION] -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/start_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - Legal - [/PARAM] - [PARAM:description] - [/PARAM] - [PARAM:links] - * [](Support/BusinessAndLegal/TermsAndConditions "%Support/BusinessAndLegal/TermsAndConditions:description%") - * [](Support/BusinessAndLegal/TrademarksAndLogos "%Support/BusinessAndLegal/TrademarksAndLogos:description%") - [/PARAM] -[/OBJECT] - -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/business_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - Business - [/PARAM] - [PARAM:description] - [/PARAM] - [PARAM:links] - * [](Support/BusinessAndLegal/IntegratedPartnersProgram "%Support/BusinessAndLegal/IntegratedPartnersProgram:description%") - * [](Support/BusinessAndLegal/ShippingChecklist "%Support/BusinessAndLegal/ShippingChecklist:description%") - [/PARAM] -[/OBJECT] +[DIR(output:"listbutton" parent:"Support/BusinessAndLegal")] \ No newline at end of file diff --git a/Engine/Documentation/Source/Support/BusinessAndLegal/BusinessAndLegal.JPN.udn b/Engine/Documentation/Source/Support/BusinessAndLegal/BusinessAndLegal.JPN.udn index b8120453266a..3e23522759d7 100644 --- a/Engine/Documentation/Source/Support/BusinessAndLegal/BusinessAndLegal.JPN.udn +++ b/Engine/Documentation/Source/Support/BusinessAndLegal/BusinessAndLegal.JPN.udn @@ -1,40 +1,13 @@ -INTSourceChangelist:2363518 +INTSourceChangelist:3473445 Availability:Licensee Title:ビジネスとリーガル Crumbs:%ROOT% Description:アンリアル・エンジン 4 を使用したゲーム開発に関するビジネスとリーガル情報 Navigation:role +Version:4.9 [REGION:banner] ![Business and Legal](business.png) [/REGION] -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/start_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - リーガル - [/PARAM] - [PARAM:description] - [/PARAM] - [PARAM:links] - * [](Support/BusinessAndLegal/TermsAndConditions "%Support/BusinessAndLegal/TermsAndConditions:description%") - * [](Support/BusinessAndLegal/TrademarksAndLogos "%Support/BusinessAndLegal/TrademarksAndLogos:description%") - [/PARAM] -[/OBJECT] - -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/business_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - ビジネス - [/PARAM] - [PARAM:description] - [/PARAM] - [PARAM:links] - * [](Support/BusinessAndLegal/IntegratedPartnersProgram "%Support/BusinessAndLegal/IntegratedPartnersProgram:description%") - * [](Support/BusinessAndLegal/ShippingChecklist "%Support/BusinessAndLegal/ShippingChecklist:description%") - [/PARAM] -[/OBJECT] +[DIR(output:"listbutton" parent:"Support/BusinessAndLegal")] \ No newline at end of file diff --git a/Engine/Documentation/Source/Support/BusinessAndLegal/BusinessAndLegal.KOR.udn b/Engine/Documentation/Source/Support/BusinessAndLegal/BusinessAndLegal.KOR.udn index 3b5f266bed71..4ba6d2196536 100644 --- a/Engine/Documentation/Source/Support/BusinessAndLegal/BusinessAndLegal.KOR.udn +++ b/Engine/Documentation/Source/Support/BusinessAndLegal/BusinessAndLegal.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3473445 Availability:Licensee Title:비즈니스와 법무 Crumbs:%ROOT% @@ -10,32 +10,4 @@ Version: 4.9 ![Business and Legal](business.png) [/REGION] -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/start_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - 법무 - [/PARAM] - [PARAM:description] - [/PARAM] - [PARAM:links] - * [](Support/BusinessAndLegal/TermsAndConditions "%Support/BusinessAndLegal/TermsAndConditions:description%") - * [](Support/BusinessAndLegal/TrademarksAndLogos "%Support/BusinessAndLegal/TrademarksAndLogos:description%") - [/PARAM] -[/OBJECT] - -[OBJECT:TopicButtonList] - [PARAM:icon] - ![](%ROOT%/business_icon.png)(convert:false) - [/PARAM] - [PARAM:title] - 비즈니스 - [/PARAM] - [PARAM:description] - [/PARAM] - [PARAM:links] - * [](Support/BusinessAndLegal/IntegratedPartnersProgram "%Support/BusinessAndLegal/IntegratedPartnersProgram:description%") - * [](Support/BusinessAndLegal/ShippingChecklist "%Support/BusinessAndLegal/ShippingChecklist:description%") - [/PARAM] -[/OBJECT] \ No newline at end of file +[DIR(output:"listbutton" parent:"Support/BusinessAndLegal")] \ No newline at end of file diff --git a/Engine/Documentation/Source/Support/BusinessAndLegal/IntegratedPartnersProgram/IntegratedPartnersProgram.CHN.udn b/Engine/Documentation/Source/Support/BusinessAndLegal/IntegratedPartnersProgram/IntegratedPartnersProgram.CHN.udn deleted file mode 100644 index 09e4eaf126f6..000000000000 --- a/Engine/Documentation/Source/Support/BusinessAndLegal/IntegratedPartnersProgram/IntegratedPartnersProgram.CHN.udn +++ /dev/null @@ -1,47 +0,0 @@ -INTSourceChangelist:1547574 -Availability:Licensee -Title: 集成合作伙伴项目 -Crumbs:%ROOT%, Support/BusinessAndLegal -Description:这是一个为集成产品到虚幻引擎4的公司设立的项目,并包括了所有当前项目成员。 - -![Integrated Partners Program](IPP.png) - -Epic Games创建了集成合作伙伴项目(IPP)来和拥有跨平台技术的公司建立正式的商务关系,这些被选中的公司整合并补充虚幻4(UE4)的内容。 在IPP项目下,Epic持续提供给IPP成员UE4源代码访问权限以及完整的技术支持。 加入 IPP 的公司同意通过 Epic 设立的支持渠道为 UE4 授权用户提供高层次技术支持,使他们能应用最新的 UE4版本,并同Epic 一起努力挖掘潜在的推销和联合推广机会。 IPP 项目可以使虚幻引擎 4 用户更加轻松地将 IPP 供应商提供的第三方中间件解决方案整合到他们自己的游戏中。 - -这些产品不包括在[第三方软件]页面列出的工具和软件(Support/BusinessAndLegal/ThirdPartySoftware)。 - -如果您想要集成某个产品,最好联系该产品供应商。 - -## 标识及商标 - -集成合作伙伴项目标识可放置于合作伙伴的网站,产品包装或其他媒体上。请只使用官方标识,并且所有的使用应符合Epic Games规定的使用方针。 - -* [集成合作伙伴项目标识](Support/BusinessAndLegal/TrademarksAndLogos/UE4_Partner_Logos.zip) (4MB .zip) - - -关于标识和商标完整的使用指南可以在[标识与商标](Support/BusinessAndLegal/TrademarksAndLogos)页面找到。 - -## 集成合作伙伴(IPP)项目成员 - -| 合作伙伴 | 产品 | -| ------- | ------- | -| [REGION:tablesection]**完全集成且完全可用**[REGION:lightbox inline][[REGION:infolink][/REGION]](#usedfullinfo)[/REGION][/REGION] || -| **NVIDIA** | [PhysX](http://www.nvidia.com/object/nvidia_physx.html), [APEX](http://developer.nvidia.com/object/apex.html) | -| [REGION:tablesection]**完全集成且部分可用**[REGION:lightbox inline][[REGION:infolink][/REGION]](#usedpartialinfo)[/REGION][/REGION] || -| **Donya Labs** | [Simplygon](http://www.donyalabs.com/) - - -[REGION:hidden] - - [REGION:infobox] - These products are fully integrated into Unreal Engine 4 and no additional purchase is required. - Integration is maintained by Epic & the vendor; both source code & libraries are in Perforce. - [/REGION] - - - [REGION:infobox] - These products are partially integrated into Unreal Engine 4. Both source code and libraries must - be obtained from the vendor and require an additional purchase. - [/REGION] - -[/REGION] diff --git a/Engine/Documentation/Source/Support/BusinessAndLegal/IntegratedPartnersProgram/IntegratedPartnersProgram.INT.udn b/Engine/Documentation/Source/Support/BusinessAndLegal/IntegratedPartnersProgram/IntegratedPartnersProgram.INT.udn deleted file mode 100644 index aea2c63ef08b..000000000000 --- a/Engine/Documentation/Source/Support/BusinessAndLegal/IntegratedPartnersProgram/IntegratedPartnersProgram.INT.udn +++ /dev/null @@ -1,64 +0,0 @@ -Availability:Licensee -Title: Integrated Partners Program -Crumbs:%ROOT%, Support/BusinessAndLegal -Description:Program for companies that have integrated products into Unreal Engine 4. Includes a list of all current program members. -Version: 4.9 - -[Region:raw] -![Integrated Partners Program](IPP.png) -[/Region] - -Epic Games has established the Integrated Partners Program (IPP) for the purposes of having a formal business relationship with selected companies making cross-platform technologies which integrate with, and are complementary to, Unreal Engine 4 (UE4). Under the IPP program, Epic provides continuous UE4 source code access and full technical support to IPP members. Companies who join the IPP agree to provide a high level of technical support for UE4 licensees through Epic's established support channels, keep their implementations up-to-date with the latest UE4 versions, and work with Epic on potential promotional and co-marketing efforts. The IPP program will make it easier for Unreal Engine 4 licensees to incorporate 3rd party middleware solutions from IPP vendors into their games. - -These products are in addition to the tools and software listed on the [Third Party Software](Support/BusinessAndLegal/ThirdPartySoftware) page. - -If you are interested in integrating a product, it is best to contact the vendor. - -## Logos and Trademarks - -Integrated Partner Program logos are available for placement on partners' websites, product packaging, or other media. Only the official logos should be used and all usage must be in accordance with the usage guidelines stipulated by Epic Games. - -* [Integrate Partner Program Logos](Support/BusinessAndLegal/TrademarksAndLogos/UE4_Partner_Logos.zip) (4MB .zip) - - -Complete usage guidelines for both trademarks and logos are available on the [Trademarks and Logos](Support/BusinessAndLegal/TrademarksAndLogos) page. - -## Integrated Partners Program Members - -| Partner | Product | -| ------- | ------- | -| [REGION:tablesection][INCLUDE:#usedfull][/REGION] || -| **NVIDIA** | [PhysX](http://www.nvidia.com/object/nvidia_physx.html), [APEX](http://developer.nvidia.com/object/apex.html) | -| [REGION:tablesection][INCLUDE:#usedpartial][/REGION] || -| **Donya Labs** | [Simplygon](http://www.donyalabs.com/) - - diff --git a/Engine/Documentation/Source/Support/BusinessAndLegal/IntegratedPartnersProgram/IntegratedPartnersProgram.JPN.udn b/Engine/Documentation/Source/Support/BusinessAndLegal/IntegratedPartnersProgram/IntegratedPartnersProgram.JPN.udn deleted file mode 100644 index e3739af55499..000000000000 --- a/Engine/Documentation/Source/Support/BusinessAndLegal/IntegratedPartnersProgram/IntegratedPartnersProgram.JPN.udn +++ /dev/null @@ -1,62 +0,0 @@ -INTSourceChangelist:2373965 -Availability:Licensee -Title:統合パートナープログラム (IPP) -Crumbs:%ROOT%, Support/BusinessAndLegal -Description:アンリアル エンジン 4 に統合している製品をもつ企業向けプログラム現在のプログラム メンバーの一覧が含まれます。 - -![Integrated Partners Program](IPP.png) - -Epic Gamesの統合パートナープログラム (IPP) は、クロス プラットフォーム テクノロジーをアンリアル エンジン 4 に統合、または補完的技術をもたらす厳選された企業と正式なビジネス関係を構築する目的で設立されました。Epic は、IPP プログラム参加メンバーに対して、UE4 のソースコードへのアクセスおよび全面的なテクニカル サポートを提供します。IPP 参加メンバーは、Epic が構築したサポート チャンネルを通して、ハイレベルな技術サポートをアンリアル エンジン 4 (UE4) ライセンシーに提供し、最新の UE4 バージョンで最新の実装を保ち、Epic との連携による潜在的なプロモーション及び共同マーケティングを行うことに同意しております。IPP プログラムに参加することにより、アンリアル エンジン 4 のライセンシーは、IPP 業者が提供する第三者ミドルウェアソリューションの導入が容易になります。 - -これらの製品は、[Third Party Software](Support/BusinessAndLegal/ThirdPartySoftware) に掲載されているツールやソフトウェアに追加されるものです。 - -製品の統合に興味をお持ちでしたら、まずはベンダーまで問い合わせてください。 - -## ロゴと商標 - -ビジネスパートナーのウェブサイト、商品、パッケージやその他の媒体で使用する、統合パートナープログラムのロゴがご利用いただけます。公式ロゴのみを使用し、Epic Games の規定に基づく使用に関するガイドラインに準拠しなければなりません。 - -* [Integrate Partner Program Logos](Support/BusinessAndLegal/TrademarksAndLogos/UE4_Partner_Logos.zip) (4MB .zip) - - -トレードマークとロゴに関する使用ガイドの完全版を [Trademarks and Logos](Support/BusinessAndLegal/TrademarksAndLogos) のページ商標とロゴから参照いただけます。 - -## 統合パートナープログラムのメンバー - -| Partner | Product | -| ------- | ------- | -| [REGION:tablesection][INCLUDE:#usedfull][/REGION] || -| **NVIDIA** | [PhysX](http://www.nvidia.com/object/nvidia_physx.html), [APEX](http://developer.nvidia.com/object/apex.html) | -| [REGION:tablesection][INCLUDE:#usedpartial][/REGION] || -| **Donya Labs** | [Simplygon](http://www.donyalabs.com/) - - \ No newline at end of file diff --git a/Engine/Documentation/Source/Support/BusinessAndLegal/IntegratedPartnersProgram/IntegratedPartnersProgram.KOR.udn b/Engine/Documentation/Source/Support/BusinessAndLegal/IntegratedPartnersProgram/IntegratedPartnersProgram.KOR.udn deleted file mode 100644 index fbec64a57ce5..000000000000 --- a/Engine/Documentation/Source/Support/BusinessAndLegal/IntegratedPartnersProgram/IntegratedPartnersProgram.KOR.udn +++ /dev/null @@ -1,65 +0,0 @@ -INTSourceChangelist:3108692 -Availability:Licensee -Title: 통합 파트너 프로그램 -Crumbs:%ROOT%, Support/BusinessAndLegal -Description:언리얼 엔진 4 에 제품을 통합시킨 회사를 위한 프로그램입니다. 현재 이 프로그램에 가입된 멤버도 포함됩니다. -Version: 4.9 - -[Region:raw] -![Integrated Partners Program](IPP.png) -[/Region] - -에픽 게임스는 언리얼 엔진 4 에 통합되어 상보적인 관계의 크로스 플랫폼 테크놀로지를 개발한 엄선된 회사들과 공식적인 업무 제휴관계를 맺을 목적으로 통합 파트너 프로그램(IPP, Integrated Partners Program)을 수립했습니다. IPP 하에서 에픽은 IPP 회원사에게 지속적인 언리얼 엔진 4 소스 코드 접근 권한과 최대의 기술 지원을 제공합니다. 아울러 IPP 에 합류하는 회사는 에픽이 수립한 지원 창구를 통해 UE4 라이선시께 높은 수준의 기술 지원을 제공하며 UE4 최신 버전에 맞춰 자사의 구현 내용을 최신으로 유지함은 물론, 에픽과 가능한 모든 홍보나 공동 마케팅 노력을 함께할 것임에 동의합니다. IPP 는 언리얼 엔진 4 라이선시께서 해당 회사의 게임에 IPP 벤더의 써드 파티 미들웨어 솔루션을 통합시키는 작업을 수월하게 만들어 줄 것입니다. - -이 곳의 제품들은 [써드 파티 소프트웨어](Support/BusinessAndLegal/ThirdPartySoftware) 페이지에 나열된 툴과 소프트웨어에 더해지는 것입니다. - -제품 통합에 관심이 있으신 경우, 벤더와 상의해 보시기 바랍니다. - -## 로고와 상호 - -통합 파트너 프로그램 로고는 파트너의 웹사이트, 제품 패키지, 기타 매체에 사용할 수 있습니다. 공식 로고만 사용할 수 있으며, 그 모든 사용법은 에픽 게임스가 명시한 사용 지침을 따라야 합니다. - -* [통합 파트너 프로그램 로고](Support/BusinessAndLegal/TrademarksAndLogos/UE4_Partner_Logos.zip) (4MB .zip) - - -상호와 로고의 자세한 사용 지침에 대한 것은 [상호와 로고](Support/BusinessAndLegal/TrademarksAndLogos) 페이지를 참고해 주시기 바랍니다. - -## 통합 파트너 프로그램 회원사 - -| 파트너 | 제품 | -| ------- | ------- | -| [REGION:tablesection][INCLUDE:#usedfull][/REGION] || -| **NVIDIA** | [PhysX](http://www.nvidia.com/object/nvidia_physx.html), [APEX](http://developer.nvidia.com/object/apex.html) | -| [REGION:tablesection][INCLUDE:#usedpartial][/REGION] || -| **Donya Labs** | [Simplygon](http://www.donyalabs.com/) - - \ No newline at end of file diff --git a/Engine/Documentation/Source/Support/BusinessAndLegal/ShippingChecklist/ShippingChecklist.INT.udn b/Engine/Documentation/Source/Support/BusinessAndLegal/ShippingChecklist/ShippingChecklist.INT.udn index 6bc3876268d9..aee8d7effa51 100644 --- a/Engine/Documentation/Source/Support/BusinessAndLegal/ShippingChecklist/ShippingChecklist.INT.udn +++ b/Engine/Documentation/Source/Support/BusinessAndLegal/ShippingChecklist/ShippingChecklist.INT.udn @@ -37,7 +37,7 @@ as on the back of the box for the Game). Licensee agrees to display the "Powered by Unreal Technology" logo on the physical packaging of the Game. Licensee also agrees to display the "Powered by Unreal Technology" logo within the opening sequence or splash screen of the Game. Licensee agrees that any display of the "Powered by Unreal Technology" logo will comply -with the **_Unreal Engine Style Guide_** which can be found on the [Trademarks And Logos](Support/BusinessAndLegal/TrademarksAndLogos) page. +with the **_Unreal Engine Style Guide_** which can be found on the [Logo & Branding](https://www.unrealengine.com/branding) page. As an alternative to static logos, an animated version is also available. @@ -47,8 +47,7 @@ The Unreal Technology logo is not required on any labels for physical media (flo ## Third Party Software Licensee must also provide appropriate legal notices required by any other third party software used in the -Game. A list of libraries included in the Unreal® Engine, and the legal text that goes with -them, can be found at [Third Party Software](Support/BusinessAndLegal/ThirdPartySoftware). +Game. ## Sanctioned Content diff --git a/Engine/Documentation/Source/Support/BusinessAndLegal/ShippingChecklist/ShippingChecklist.JPN.udn b/Engine/Documentation/Source/Support/BusinessAndLegal/ShippingChecklist/ShippingChecklist.JPN.udn index 9f4a96448bb9..eca4b544eeb1 100644 --- a/Engine/Documentation/Source/Support/BusinessAndLegal/ShippingChecklist/ShippingChecklist.JPN.udn +++ b/Engine/Documentation/Source/Support/BusinessAndLegal/ShippingChecklist/ShippingChecklist.JPN.udn @@ -1,20 +1,22 @@ -Availability:Licensee -Title:出荷検品表 +INTSourceChangelist:3473445 +Availability:Licensee +Title:シッピングのチェックリスト Crumbs:%ROOT%, Support/BusinessAndLegal -Description:アンリアル エンジン 4 を使用したゲームの販売時に参照するガイドラインと対処アイテムのリスト +Description:UE4 を使用したゲームのシッピング時に参照するガイドラインとアイテムのリスト +Version:4.9 -アンリアル エンジン 4 を起用したプロジェクトの完成が近づいたら、 -プロジェクトを販売する前にある措置の実行および確認事項がいくつかあります。このドキュメントには、 -アンリアル エンジン 4 を使用した公式ゲームプロジェクトの販売に関する注記事項やドキュメントのコレクションが含まれています。  +アンリアル エンジン 4 (UE4) を起用したプロジェクトの完成が近づいたら、 +プロジェクトをシッピングする前に行うことと、確認事項がいくつかあります。このドキュメントには、 +UE4 を使用した公式ゲーム プロジェクトのシッピングに関する注記事項やドキュメントのコレクションが含まれています。 -プロジェクトにアンリアル エンジン 4 を使用したユーザーは **ライセンシー** となります。ユーザーのプロジェクトは **公式ゲーム** (または **ゲーム**) です。 +プロジェクトに UE4 を使用したユーザーは **ライセンシー** となります。プロジェクトは **公式ゲーム** (または **ゲーム**) になります。 ## 必須の商標表示 ライセンシーは、アンリアル テクノロジー ロゴの使用時は必ず商標を表示しなくてはいけません (公式ゲームのパッケージの裏側など)。 - "Unreal, Unreal Technology および the Powered by Unreal Technology ロゴは、米国およびその他の国と地域における Epic Games, Inc. の商標または登録商標です。" + "Unreal、Unreal Technology、および Powered by Unreal Technology ロゴは、米国およびその他の国と地域における Epic Games, Inc. の商標または登録商標です。" ## 必須の著作権表示 @@ -34,9 +36,9 @@ Description:アンリアル エンジン 4 を使用したゲームの販売時 (公式ゲームのパッケージの裏側など)。 ライセンシーは、ゲームの外箱に "Powered by Unreal Technology" ロゴを表示することに合意するものとします。 -ライセンシーはまた、ゲームのオープニングシークエンスまたはスプラッシュスクリーンに "Powered by Unreal Technology" ロゴを -表示することに合意するものとします。ライセンシーは、"Powered by Unreal Technology" ロゴのいかなる表示において **_アンリアル・エンジン スタイルガイド_** に準拠することに合意するものとします。 -スタイルガイドは [Trademarks And Logos](Support/BusinessAndLegal/TrademarksAndLogos) のページを参照してください。 +ライセンシーはまた、ゲームのオープニング シークエンスまたはスプラッシュ スクリーンに "Powered by Unreal Technology" ロゴを +表示することに合意するものとします。ライセンシーは、"Powered by Unreal Technology" ロゴのいかなる表示においても **_アンリアル・エンジン スタイルガイド_** に準拠することに合意するものとします。 +スタイルガイドは [Logo & Branding](https://www.unrealengine.com/branding) のページを参照してください。 静止ロゴの代替として、アニメーションロゴも利用可能です。 @@ -45,14 +47,13 @@ Unreal Technology ロゴを物理媒体のラベルに表示する必要はあ ## 第三者ソフトウェア -ライセンシーは、ゲームで使用したその他の第三者ソフトウェアが必須とする適切な法的通知を必ず表示しなくてはいけません。 -Unreal® Engine に格納されているライブラリのリストおよびこれらに付随する権利表記は、 -[Third Party Software](Support/BusinessAndLegal/ThirdPartySoftware) を参照してください。 +ライセンシーは、ゲームで使用したその他の第三者ソフトウェアが必須とする適切な法的通知を +必ず表示しなくてはいけません。 ## 公式コンテンツ -アンリアル エディタ版で作成したその他のゲームまたは製品の販売は、ライセンシーがユーザーコンテンツに -セーフガードを実装しない限り、公式ゲームと潜在的に互換性を持つコンテンツを作成することができます。 -他者から供給されるユーザーコンテンツと公式ゲームを非互換性とするには、 -ライセンシーは、公式ゲームが承認ツールからのみコンテンツの受け取りを可能にする措置を取らなければいけません。 +その他のゲームまたは製品はアンリアル エディタのバージョンと合わせてシッピングされることがあり、その場合ライセンシーがそうしたユーザー コンテンツに +セーフガードを実装しない限り、ユーザーは公式ゲームと互換性を持ちうるコンテンツを作成することができます。 +他のソースからのユーザー コンテンツと公式ゲームを非互換にするには、 +ライセンシーは、公式ゲームが認可されたツールからのみコンテンツを受け取るようにする措置 (例、公式ゲーム用のエディタ) を取らなければいけません。上述のコンテンツに影響を受けない公式ゲームの作成は 上述のコンテンツに影響を受けない公式ゲームの作成はすべてライセンシーの責任となります。 diff --git a/Engine/Documentation/Source/Support/BusinessAndLegal/ShippingChecklist/ShippingChecklist.KOR.udn b/Engine/Documentation/Source/Support/BusinessAndLegal/ShippingChecklist/ShippingChecklist.KOR.udn index 162c6b859a08..d318d5c6b605 100644 --- a/Engine/Documentation/Source/Support/BusinessAndLegal/ShippingChecklist/ShippingChecklist.KOR.udn +++ b/Engine/Documentation/Source/Support/BusinessAndLegal/ShippingChecklist/ShippingChecklist.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3108692 +INTSourceChangelist:3473445 Availability:Licensee Title: 출하 점검목록 Crumbs:%ROOT%, Support/BusinessAndLegal @@ -37,7 +37,7 @@ Version: 4.9 라이선시는 게임의 물리적 포장에 "Powered by Unreal Technology" 로고를, 또한 게임의 스플래시 화면이나 시작 화면에 "Powered by Unreal Technology" 로고를 넣는다는 것에 동의합니다. "Powered by Unreal Technology" 로고의 표시는 -[상호와 로고](Support/BusinessAndLegal/TrademarksAndLogos) 페이지에서 찾을 수 있는 +[로고 & 브랜드](https://www.unrealengine.com/branding) 페이지에서 찾을 수 있는 **_언리얼 엔진 스타일 가이드_** 를 따른다는 데 동의합니다. 정적인 로고에 대한 대안으로 애니메이션 버전도 가능합니다. @@ -47,9 +47,8 @@ Version: 4.9 ## 써드 파티 소프트웨어 -라이선시는 게임에 사용된 다른 써드 파티 소프트웨어가 요구하는 법적 문구를 알맞게 실어야 합니다. 언리얼 엔진에 포함된 -라이브러리 목록과 그에 따르는 법적 문구는 [써드 파티 소프트웨어](Support/BusinessAndLegal/ThirdPartySoftware) -페이지에서 찾아보실 수 있습니다. +라이선시는 게임에 사용된 다른 써드 파티 소프트웨어가 요구하는 법적 문구를 알맞게 실어야 +합니다. ## 승인된 콘텐츠 diff --git a/Engine/Documentation/Source/Support/BusinessAndLegal/TrademarksAndLogos/TrademarksAndLogos.CHN.udn b/Engine/Documentation/Source/Support/BusinessAndLegal/TrademarksAndLogos/TrademarksAndLogos.CHN.udn deleted file mode 100644 index 9c011869b18b..000000000000 --- a/Engine/Documentation/Source/Support/BusinessAndLegal/TrademarksAndLogos/TrademarksAndLogos.CHN.udn +++ /dev/null @@ -1,24 +0,0 @@ -INTSourceChangelist:2363518 -Availability:Licensee -Title: 商标和标识 -Crumbs:%ROOT%, Support/BusinessAndLegal -Description:以印刷形式、游戏内使用形式和在网络上使用属于Epic Games, Inc的商标和标识的指南。 - - -虚幻引擎标识和商标只供授权合作伙伴以及符合条件的Epic Games的虚幻引擎授权用户使用。 - -请参考虚幻引擎4风格指南了解虚幻引擎标识的所有要求、限制和使用说明。 - -如果对风格指南中的标识使用指南不清楚,请通过向Epic的市场部– [branding@unrealengine.com](mailto:branding@unrealengine.com)发送邮件提交JPEG或PDF格式资料以供审核。 请为Epic预留足够的时间进行审核及回应。 Epic没有回应并不表示同意。 在继续后续的操作之前,您必须得到Epic游戏的首肯。 - -## 虚幻引擎4风格指南 - -* [风格指南](UE4_Styleguide.pdf) (PDF 3.3MB) - - -## 虚幻引擎4认证的商标 - -* [打印 & 网络商标](Print_and_Web.zip) (.ZIP 13.5MB) -* [启动屏幕商标](SplashScreen.zip) (.ZIP 0.3MB) -* [集成伙伴商标](IntegratedPartner.zip) (.ZIP 3.7MB) -* [水平商标](Horizontal.zip) (.ZIP 1.4MB) diff --git a/Engine/Documentation/Source/Support/BusinessAndLegal/TrademarksAndLogos/TrademarksAndLogos.INT.udn b/Engine/Documentation/Source/Support/BusinessAndLegal/TrademarksAndLogos/TrademarksAndLogos.INT.udn deleted file mode 100644 index 9ea97a574dcc..000000000000 --- a/Engine/Documentation/Source/Support/BusinessAndLegal/TrademarksAndLogos/TrademarksAndLogos.INT.udn +++ /dev/null @@ -1,30 +0,0 @@ -Availability:Licensee -Title: Trademarks and Logos -Crumbs:%ROOT%, Support/BusinessAndLegal -Description:Guide to using the trademarks and logos belonging to Epic Games, Inc. in print, in games, and on the web. -Version: 4.9 - - -The use of the Unreal Engine Logo and Trademarks is available only to licensed partners and qualified Unreal Engine -licensees of Epic Games. - -Please reference the UE4 Style Guide for all requirements, restrictions and usage instructions for the Unreal Engine -logo. - -If a circumstance arises where the style guide is unclear on logo usage direction, please submit materials to be approved -in JPEG or PDF format by email to Epic's marketing department contact - [branding@unrealengine.com](mailto:branding@unrealengine.com). Please allow -sufficient time for Epic to review and respond. A failure by Epic to respond does NOT indicate approval. You must receive -actual approval from Epic games before proceeding. - -## UE4 Style Guide - -* [Style Guide](UE4_Styleguide.pdf) (PDF 3.3MB) - - -## UE4 Approved Logos - -* [Print & Web Logos](Print_and_Web.zip) (.ZIP 13.5MB) -* [Start-up screen Logos](SplashScreen.zip) (.ZIP 0.3MB) -* [Integrated Partner Logos](IntegratedPartner.zip) (.ZIP 3.7MB) -* [Horizontal Logos](Horizontal.zip) (.ZIP 1.4MB) - diff --git a/Engine/Documentation/Source/Support/BusinessAndLegal/TrademarksAndLogos/TrademarksAndLogos.JPN.udn b/Engine/Documentation/Source/Support/BusinessAndLegal/TrademarksAndLogos/TrademarksAndLogos.JPN.udn deleted file mode 100644 index 1b2db09ebc67..000000000000 --- a/Engine/Documentation/Source/Support/BusinessAndLegal/TrademarksAndLogos/TrademarksAndLogos.JPN.udn +++ /dev/null @@ -1,30 +0,0 @@ -INTSourceChangelist:2363518 -Availability:Licensee -Title:商標とロゴ -Crumbs:%ROOT%, Support/BusinessAndLegal -Description:印刷物、ゲーム内、ウェブ上での Epic Games, Inc. に帰属する商標とロゴの使用に関するガイド - - -「Unreal Engine」ロゴと商標の使用は、 -認可を受けたビジネスパートナーと Epic Games の「Unreal Engine」正規ライセンシーのみが利用できます。 - -「Unreal Engine」ロゴに関する条件、制限事項、 -使用に関する説明は、 UE4 スタイルガイドを参照してください。 - -スタイルガイド上でロゴの使用説明に不明瞭な点が生じた場合、 PDF フォーマットの資料を Epic 社のマーケティングディレクター、 - Rex Stover (mailto:rex.stover@epicgames.com) 宛に E メールで送信の上承認を得てください。書類の精査と返答までに -特定のお時間を要しますこと予めご了承願います。当社からの返答がない状況が、承認を得たという解釈にはなりませんのでご注意ください。ロゴの使用前に -必ず当社からの承認を得てください。 - -## UE4 スタイルガイド - -* [スタイルガイド](UE4_Styleguide.pdf) (PDF 3.3MB) - - -## UE4 で許可されているロゴ - -* [Print & Web Logos](Print_and_Web.zip) (.ZIP 13.5MB) -* [Start-up screen Logos](SplashScreen.zip) (.ZIP 0.3MB) -* [Integrated Partner Logos](IntegratedPartner.zip) (.ZIP 3.7MB) -* [Horizontal Logos](Horizontal.zip) (.ZIP 1.4MB) - diff --git a/Engine/Documentation/Source/Support/BusinessAndLegal/TrademarksAndLogos/TrademarksAndLogos.KOR.udn b/Engine/Documentation/Source/Support/BusinessAndLegal/TrademarksAndLogos/TrademarksAndLogos.KOR.udn deleted file mode 100644 index ad93154fb74c..000000000000 --- a/Engine/Documentation/Source/Support/BusinessAndLegal/TrademarksAndLogos/TrademarksAndLogos.KOR.udn +++ /dev/null @@ -1,30 +0,0 @@ -INTSourceChangelist:3108692 -Availability:Licensee -Title: 상호와 로고 -Crumbs:%ROOT%, Support/BusinessAndLegal -Description:에픽 게임스의 상호와 로고를 인쇄물, 게임, 웹에서 사용하는 데 대한 안내서입니다. -Version: 4.9 - - -언리얼 엔진 로고와 상호의 사용은 라이선싱 파트너와 에픽 게임스의 언리얼 엔진 라이선시에게만 -사용이 허가되어 있습니다. - -언리얼 엔진 로고 사용 관련 조건, 제약, 사용 지침에 대해서는 'UE4 스타일 가이드'를 참고해 주시기 -바랍니다. - -스타일 가이드의 로고 사용 지침에 딱 들어맞지 않는 사례가 발생한 경우, 해당 자료를 JPEG 나 PDF 포맷으로 하여 -에픽의 마케팅 담당자 [branding@unrealengine.com](mailto:branding@unrealengine.com) 에게 보내어 승인을 받아 -주시기 바랍니다. 에픽이 검토하여 답변드릴 수 있도록 충분한 시간을 주십시오. 에픽의 답변이 없다고 해서 승인한 것은 -아닙니다. 실사용을 위해서는 먼저 에픽 게임스에게 실제 승인을 받아야 합니다. - -## UE4 스타일 가이드 - -* [스타일 가이드](UE4_Styleguide.pdf) (PDF 3.3MB) - - -## UE4 승인 로고 - -* [인쇄물 & 웹 로고](Print_and_Web.zip) (.ZIP 13.5MB) -* [시작 화면 로고](SplashScreen.zip) (.ZIP 0.3MB) -* [통합 파트너 로고](IntegratedPartner.zip) (.ZIP 3.7MB) -* [가로 로고](Horizontal.zip) (.ZIP 1.4MB) diff --git a/Engine/Documentation/Source/UE4Home.INT.udn b/Engine/Documentation/Source/UE4Home.INT.udn index 7d24b7dd8090..667bc60019b8 100644 --- a/Engine/Documentation/Source/UE4Home.INT.udn +++ b/Engine/Documentation/Source/UE4Home.INT.udn @@ -58,6 +58,12 @@ type:landing [PARAMLITERAL:terms] UMG UI [/PARAMLITERAL] + [PARAMLITERAL:terms] + Sequencer + [/PARAMLITERAL] + [PARAMLITERAL:terms] + VR + [/PARAMLITERAL] [/OBJECT] [/REGION] diff --git a/Engine/Documentation/Source/UE4Home.KOR.udn b/Engine/Documentation/Source/UE4Home.KOR.udn index 4615cd463a1d..6c0e7294f83d 100644 --- a/Engine/Documentation/Source/UE4Home.KOR.udn +++ b/Engine/Documentation/Source/UE4Home.KOR.udn @@ -1,4 +1,4 @@ -INTSourceChangelist:3151855 +INTSourceChangelist:3429222 Availability:Public Title: 언리얼 엔진 4 문서 Crumbs: @@ -59,6 +59,12 @@ type:landing [PARAMLITERAL:terms] UMG UI [/PARAMLITERAL] + [PARAMLITERAL:terms] + 시퀀서 + [/PARAMLITERAL] + [PARAMLITERAL:terms] + VR + [/PARAMLITERAL] [/OBJECT] [/REGION] diff --git a/Engine/Extras/ThirdPartyNotUE/emsdk/Emscripten_License_v1.36.11.txt b/Engine/Extras/ThirdPartyNotUE/emsdk/Emscripten_License_v1.36.11.txt deleted file mode 100644 index 271131375e59..000000000000 --- a/Engine/Extras/ThirdPartyNotUE/emsdk/Emscripten_License_v1.36.11.txt +++ /dev/null @@ -1,101 +0,0 @@ -Emscripten is available under 2 licenses, the MIT license and the -University of Illinois/NCSA Open Source License. - -Both are permissive open source licenses, with little if any -practical difference between them. - -The reason for offering both is that (1) the MIT license is -well-known, while (2) the University of Illinois/NCSA Open Source -License allows Emscripten's code to be integrated upstream into -LLVM, which uses that license, should the opportunity arise. - -The full text of both licenses follows. - -============================================================================== - -Copyright (c) 2010-2014 Emscripten authors, see AUTHORS file. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -============================================================================== - -Copyright (c) 2010-2014 Emscripten authors, see AUTHORS file. -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal with the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimers. - - Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimers - in the documentation and/or other materials provided with the - distribution. - - Neither the names of Mozilla, - nor the names of its contributors may be used to endorse - or promote products derived from this Software without specific prior - written permission. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR -ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. - -============================================================================== - -This program uses portions of Node.js source code located in src/library_path.js, -in accordance with the terms of the MIT license. Node's license follows: - - """ - Copyright Joyent, Inc. and other Node contributors. All rights reserved. - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to - deal in the Software without restriction, including without limitation the - rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - sell copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - """ - -The musl libc project is bundled in this repo, and it has the MIT license, see -system/lib/libc/musl/COPYRIGHT - -The third_party/ subdirectory contains code with other licenses. None of it is -used by default, but certain options use it (e.g., the optional closure compiler -flag will run closure compiler from third_party/). \ No newline at end of file diff --git a/Engine/Extras/ThirdPartyNotUE/emsdk/emscripten/1.37.9/emcc.py b/Engine/Extras/ThirdPartyNotUE/emsdk/emscripten/1.37.9/emcc.py index d3cfa07fe11f..1dc477e3929c 100755 --- a/Engine/Extras/ThirdPartyNotUE/emsdk/emscripten/1.37.9/emcc.py +++ b/Engine/Extras/ThirdPartyNotUE/emsdk/emscripten/1.37.9/emcc.py @@ -1358,6 +1358,11 @@ There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR P newargs.append('-mllvm') newargs.append('-disable-llvm-optzns') + ## *** UE4 EDIT start *** + if shared.Settings.USE_WEBGL2: + newargs.append('-DUE4_HTML5_TARGET_WEBGL2=1') + ## *** UE4 EDIT end *** + shared.Settings.EMSCRIPTEN_VERSION = shared.EMSCRIPTEN_VERSION shared.Settings.OPT_LEVEL = opt_level shared.Settings.DEBUG_LEVEL = debug_level diff --git a/Engine/Extras/ThirdPartyNotUE/emsdk/emscripten/1.37.9/tools/shared.py b/Engine/Extras/ThirdPartyNotUE/emsdk/emscripten/1.37.9/tools/shared.py index fd458fce819a..0b8ce68b80b9 100755 --- a/Engine/Extras/ThirdPartyNotUE/emsdk/emscripten/1.37.9/tools/shared.py +++ b/Engine/Extras/ThirdPartyNotUE/emsdk/emscripten/1.37.9/tools/shared.py @@ -1877,6 +1877,7 @@ class Building: undefs = [] commons = [] for line in output.split('\n'): + line = line.rstrip('\r') # EPIC EDIT -- nick.shin 2017.05.15 -- if symbol files has DOS line endings, this is needed for Linux/OSX builds [UE-44779] if len(line) == 0: continue if ':' in line: continue # e.g. filename.o: , saying which file it's from parts = filter(lambda seg: len(seg) > 0, line.split(' ')) diff --git a/Engine/Extras/VisualStudioDebugging/InstallVisualizers.bat b/Engine/Extras/VisualStudioDebugging/InstallVisualizers.bat index e4f1f9301e43..37e54d16e8ba 100644 --- a/Engine/Extras/VisualStudioDebugging/InstallVisualizers.bat +++ b/Engine/Extras/VisualStudioDebugging/InstallVisualizers.bat @@ -8,6 +8,7 @@ if "%VS140COMNTOOLS%" neq "" ( set FoundVSInstance=1 mkdir "%USERPROFILE%\Documents\Visual Studio 2015\Visualizers" copy UE4.natvis "%USERPROFILE%\Documents\Visual Studio 2015\Visualizers" + copy UE4_Android_Nsight.dat "%VS140COMNTOOLS%\..\IDE\Extensions\NVIDIA\Nsight Tegra\3.4\Debuggers\Visualizers" echo Installed visualizers for Visual Studio 2015 ) @@ -25,10 +26,8 @@ if "%VS110COMNTOOLS%" neq "" ( echo Installed visualizers for Visual Studio 2012 ) -if "%SCE_ORBIS_SDK_DIR%" neq "" ( - mkdir "%USERPROFILE%\Documents\SCE\orbis-debugger" - copy PS4UE4.natvis "%USERPROFILE%\Documents\SCE\orbis-debugger" - echo Installed Visualizers for Orbis +if exist PS4\InstallPS4Visualizer.bat ( + call PS4\InstallPS4Visualizer.bat ) if "%FoundVSInstance%" equ "0" ( diff --git a/Engine/Plugins/2D/Paper2D/Source/Paper2D/Classes/PaperSprite.h b/Engine/Plugins/2D/Paper2D/Source/Paper2D/Classes/PaperSprite.h index 7cec959348dd..1377a975a6fc 100644 --- a/Engine/Plugins/2D/Paper2D/Source/Paper2D/Classes/PaperSprite.h +++ b/Engine/Plugins/2D/Paper2D/Source/Paper2D/Classes/PaperSprite.h @@ -15,7 +15,7 @@ class UMaterialInterface; class UPaperSpriteAtlas; //@TODO: Should have some nice UI and enforce unique names, etc... -USTRUCT() +USTRUCT(BlueprintType) struct FPaperSpriteSocket { GENERATED_USTRUCT_BODY() diff --git a/Engine/Plugins/2D/Paper2D/Source/Paper2D/Classes/PaperTileSet.h b/Engine/Plugins/2D/Paper2D/Source/Paper2D/Classes/PaperTileSet.h index 79429024c0a1..3d222f074aaf 100644 --- a/Engine/Plugins/2D/Paper2D/Source/Paper2D/Classes/PaperTileSet.h +++ b/Engine/Plugins/2D/Paper2D/Source/Paper2D/Classes/PaperTileSet.h @@ -13,7 +13,7 @@ struct FPaperTileInfo; // Information about a single tile in a tile set -USTRUCT(meta=(ShowOnlyInnerProperties)) +USTRUCT(BlueprintType, meta=(ShowOnlyInnerProperties)) struct PAPER2D_API FPaperTileMetadata { public: diff --git a/Engine/Plugins/2D/Paper2D/Source/Paper2D/Private/PaperFlipbookComponent.cpp b/Engine/Plugins/2D/Paper2D/Source/Paper2D/Private/PaperFlipbookComponent.cpp index d48f8f5554f1..fd514e0cf81f 100644 --- a/Engine/Plugins/2D/Paper2D/Source/Paper2D/Private/PaperFlipbookComponent.cpp +++ b/Engine/Plugins/2D/Paper2D/Source/Paper2D/Private/PaperFlipbookComponent.cpp @@ -313,6 +313,8 @@ void UPaperFlipbookComponent::TickFlipbook(float DeltaTime) } } +/// @cond DOXYGEN_WARNINGS + void UPaperFlipbookComponent::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); @@ -320,6 +322,8 @@ void UPaperFlipbookComponent::GetLifetimeReplicatedProps(TArray< FLifetimeProper DOREPLIFETIME(UPaperFlipbookComponent, SourceFlipbook); } +/// @endcond + void UPaperFlipbookComponent::OnRep_SourceFlipbook(class UPaperFlipbook* OldFlipbook) { if (OldFlipbook != SourceFlipbook) diff --git a/Engine/Plugins/2D/Paper2D/Source/Paper2D/Private/PaperSprite.cpp b/Engine/Plugins/2D/Paper2D/Source/Paper2D/Private/PaperSprite.cpp index 03e212259189..915c2c8fb473 100644 --- a/Engine/Plugins/2D/Paper2D/Source/Paper2D/Private/PaperSprite.cpp +++ b/Engine/Plugins/2D/Paper2D/Source/Paper2D/Private/PaperSprite.cpp @@ -785,18 +785,10 @@ void UPaperSprite::RebuildCollisionData() switch (SpriteCollisionDomain) { case ESpriteCollisionMode::Use3DPhysics: - BodySetup = nullptr; - if (BodySetup == nullptr) - { - BodySetup = NewObject(this); - } + BodySetup = NewObject(this); break; case ESpriteCollisionMode::Use2DPhysics: - BodySetup = nullptr; - if (BodySetup == nullptr) - { - BodySetup = NewObject(this); - } + BodySetup = NewObject(this); break; case ESpriteCollisionMode::None: BodySetup = nullptr; @@ -2085,10 +2077,8 @@ void FSpriteGeometryCollisionBuilderBase::ProcessGeometry(const FSpriteGeometryC void FSpriteGeometryCollisionBuilderBase::Finalize() { // Rebuild the body setup -#if WITH_PHYSX && (WITH_RUNTIME_PHYSICS_COOKING || WITH_EDITOR) MyBodySetup->InvalidatePhysicsData(); MyBodySetup->CreatePhysicsMeshes(); -#endif } void FSpriteGeometryCollisionBuilderBase::AddBoxCollisionShapesToBodySetup(const FSpriteGeometryCollection& InGeometry) diff --git a/Engine/Plugins/2D/Paper2D/Source/Paper2D/Private/PaperTileMap.cpp b/Engine/Plugins/2D/Paper2D/Source/Paper2D/Private/PaperTileMap.cpp index a002d3d0cd5c..2181d94b6e1f 100644 --- a/Engine/Plugins/2D/Paper2D/Source/Paper2D/Private/PaperTileMap.cpp +++ b/Engine/Plugins/2D/Paper2D/Source/Paper2D/Private/PaperTileMap.cpp @@ -277,10 +277,8 @@ void UPaperTileMap::UpdateBodySetup() } // Finalize the BodySetup -#if WITH_PHYSX && (WITH_RUNTIME_PHYSICS_COOKING || WITH_EDITOR) BodySetup->InvalidatePhysicsData(); BodySetup->CreatePhysicsMeshes(); -#endif } void UPaperTileMap::GetTileToLocalParameters(FVector& OutCornerPosition, FVector& OutStepX, FVector& OutStepY, FVector& OutOffsetYFactor) const diff --git a/Engine/Plugins/2D/Paper2D/Source/Paper2D/Private/Terrain/PaperTerrainComponent.cpp b/Engine/Plugins/2D/Paper2D/Source/Paper2D/Private/Terrain/PaperTerrainComponent.cpp index 2ed8a746a989..1703847b01d3 100644 --- a/Engine/Plugins/2D/Paper2D/Source/Paper2D/Private/Terrain/PaperTerrainComponent.cpp +++ b/Engine/Plugins/2D/Paper2D/Source/Paper2D/Private/Terrain/PaperTerrainComponent.cpp @@ -261,18 +261,18 @@ FTransform UPaperTerrainComponent::GetTransformAtDistance(float InDistance) cons LocalTransform = FTransform(FRotator(0.0f, 180.0f, 0.0f), FVector::ZeroVector) * LocalTransform; #if PAPER_TERRAIN_DRAW_DEBUG - FTransform WorldTransform = LocalTransform * ComponentToWorld; + FTransform WorldTransform = LocalTransform * GetComponentToWorld(); const float Time = 2.5f; DrawDebugCoordinateSystem(GetWorld(), WorldTransform.GetLocation(), FRotator(WorldTransform.GetRotation()), 15.0f, true, Time, SDPG_Foreground); -// FVector WorldPos = ComponentToWorld.TransformPosition(Position3D); +// FVector WorldPos = GetComponentTransform().TransformPosition(Position3D); // WorldPos.Y -= 0.01; // -// //DrawDebugLine(GetWorld(), WorldPos, WorldPos + ComponentToWorld.TransformVector(Tangent) * 10.0f, FColor::Red, true, Time); -// // DrawDebugLine(GetWorld(), WorldPos, WorldPos + ComponentToWorld.TransformVector(NormalEst) * 10.0f, FColor::Green, true, Time); -// // DrawDebugLine(GetWorld(), WorldPos, WorldPos + ComponentToWorld.TransformVector(Bitangent) * 10.0f, FColor::Blue, true, Time); -// //DrawDebugLine(GetWorld(), WorldPos, WorldPos + ComponentToWorld.TransformVector(Floop) * 10.0f, FColor::Yellow, true, Time); +// //DrawDebugLine(GetWorld(), WorldPos, WorldPos + GetComponentTransform().TransformVector(Tangent) * 10.0f, FColor::Red, true, Time); +// // DrawDebugLine(GetWorld(), WorldPos, WorldPos + GetComponentTransform().TransformVector(NormalEst) * 10.0f, FColor::Green, true, Time); +// // DrawDebugLine(GetWorld(), WorldPos, WorldPos + GetComponentTransform().TransformVector(Bitangent) * 10.0f, FColor::Blue, true, Time); +// //DrawDebugLine(GetWorld(), WorldPos, WorldPos + GetComponentTransform().TransformVector(Floop) * 10.0f, FColor::Yellow, true, Time); // // DrawDebugPoint(GetWorld(), WorldPos, 4.0f, FColor::White, true, 1.0f); #endif @@ -706,11 +706,11 @@ void UPaperTerrainComponent::OnSplineEdited() { const float Time = 5.0f; { - FTransform WorldTransform = GetTransformAtDistance(0.0f) * ComponentToWorld; + FTransform WorldTransform = GetTransformAtDistance(0.0f) * GetComponentTransform(); DrawDebugCoordinateSystem(GetWorld(), WorldTransform.GetLocation(), FRotator(WorldTransform.GetRotation()), 30.0f, true, Time, SDPG_Foreground); } { - FTransform WorldTransform = GetTransformAtDistance(SplineLength) * ComponentToWorld; + FTransform WorldTransform = GetTransformAtDistance(SplineLength) * GetComponentTransform(); DrawDebugCoordinateSystem(GetWorld(), WorldTransform.GetLocation(), FRotator(WorldTransform.GetRotation()), 30.0f, true, Time, SDPG_Foreground); } } @@ -720,10 +720,8 @@ void UPaperTerrainComponent::OnSplineEdited() if (CachedBodySetup != nullptr) { // Finalize the BodySetup -#if WITH_PHYSX && (WITH_RUNTIME_PHYSICS_COOKING || WITH_EDITOR) CachedBodySetup->InvalidatePhysicsData(); CachedBodySetup->CreatePhysicsMeshes(); -#endif } RecreateRenderState_Concurrent(); diff --git a/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/FlipbookEditor/SFlipbookTimeline.cpp b/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/FlipbookEditor/SFlipbookTimeline.cpp index 1c30a14b6edd..f0ee6253c77a 100644 --- a/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/FlipbookEditor/SFlipbookTimeline.cpp +++ b/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/FlipbookEditor/SFlipbookTimeline.cpp @@ -175,7 +175,7 @@ void SFlipbookTimeline::OnAssetsDropped(const class FAssetDragDropOp& DragDropOp { //@TODO: Support inserting in addition to dropping at the end TArray NewFrames; - for (const FAssetData& AssetData : DragDropOp.AssetData) + for (const FAssetData& AssetData : DragDropOp.GetAssets()) { if (UObject* Object = AssetData.GetAsset()) { diff --git a/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/GroupedSprites/PaperGroupedSpriteUtilities.cpp b/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/GroupedSprites/PaperGroupedSpriteUtilities.cpp index bbc7963b35ce..5d860c37e93a 100644 --- a/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/GroupedSprites/PaperGroupedSpriteUtilities.cpp +++ b/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/GroupedSprites/PaperGroupedSpriteUtilities.cpp @@ -132,10 +132,7 @@ void FPaperGroupedSpriteUtilities::SplitSprites(const TArray& InObject ActorsCreated.Add(SpawnedActor); // Give it a good name - if (InstanceData.SourceSprite != nullptr) - { - FActorLabelUtilities::SetActorLabelUnique(SpawnedActor, InstanceData.SourceSprite->GetName()); - } + FActorLabelUtilities::SetActorLabelUnique(SpawnedActor, InstanceData.SourceSprite->GetName()); } } } diff --git a/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/MeshPainting/MeshPaintSpriteAdapter.cpp b/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/MeshPainting/MeshPaintSpriteAdapter.cpp index ca13c0d38795..1eb1e3ace205 100644 --- a/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/MeshPainting/MeshPaintSpriteAdapter.cpp +++ b/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/MeshPainting/MeshPaintSpriteAdapter.cpp @@ -235,6 +235,32 @@ TArray FMeshPaintSpriteAdapter::SphereIntersectVertices(const float Com return InRangeVertices; } +void FMeshPaintSpriteAdapter::GetInfluencedVertexData(const float ComponentSpaceSquaredBrushRadius, const FVector& ComponentSpaceBrushPosition, const FVector& ComponentSpaceCameraPosition, const bool bOnlyFrontFacing, TArray>& OutData) const +{ + // Get a list of (optionally front-facing) triangles that are within a reasonable distance to the brush + TArray InfluencedTriangles = SphereIntersectTriangles( + ComponentSpaceSquaredBrushRadius, + ComponentSpaceBrushPosition, + ComponentSpaceCameraPosition, + bOnlyFrontFacing); + + // Make sure we're dealing with triangle lists + const int32 NumIndexBufferIndices = MeshIndices.Num(); + check(NumIndexBufferIndices % 3 == 0); + + OutData.Reserve(InfluencedTriangles.Num() * 3); + for(int32 InfluencedTriangle : InfluencedTriangles) + { + for(int32 Index = 0; Index < 3; ++Index) + { + OutData.AddDefaulted(); + TPair& OutPair = OutData.Last(); + OutPair.Key = MeshIndices[InfluencedTriangle * 3 + Index]; + OutPair.Value = MeshVertices[OutPair.Key]; + } + } +} + ////////////////////////////////////////////////////////////////////////// // FMeshPaintSpriteAdapterFactory diff --git a/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/MeshPainting/MeshPaintSpriteAdapter.h b/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/MeshPainting/MeshPaintSpriteAdapter.h index e90d77bb1ff9..c1933f0db09b 100644 --- a/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/MeshPainting/MeshPaintSpriteAdapter.h +++ b/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/MeshPainting/MeshPaintSpriteAdapter.h @@ -46,9 +46,12 @@ public: virtual FMatrix GetComponentToWorldMatrix() const override; virtual void GetInfluencedVertexIndices(const float ComponentSpaceSquaredBrushRadius, const FVector& ComponentSpaceBrushPosition, const FVector& ComponentSpaceCameraPosition, const bool bOnlyFrontFacing, TSet &InfluencedVertices) const override; + virtual void GetInfluencedVertexData(const float ComponentSpaceSquaredBrushRadius, const FVector& ComponentSpaceBrushPosition, const FVector& ComponentSpaceCameraPosition, const bool bOnlyFrontFacing, TArray>& OutData) const override; virtual TArray SphereIntersectVertices(const float ComponentSpaceSquaredBrushRadius, const FVector& ComponentSpaceBrushPosition, const FVector& ComponentSpaceCameraPosition, const bool bOnlyFrontFacing) const override; + + protected: UPaperSpriteComponent* SpriteComponent; UPaperSprite* Sprite; diff --git a/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/PaperEditorShared/SpriteGeometryEditing.h b/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/PaperEditorShared/SpriteGeometryEditing.h index ab9ac5042fcf..7a3c099c3aaa 100644 --- a/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/PaperEditorShared/SpriteGeometryEditing.h +++ b/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/PaperEditorShared/SpriteGeometryEditing.h @@ -69,7 +69,7 @@ public: virtual bool CanDeleteSelection() const; - ~FSpriteSelectionHelper() + virtual ~FSpriteSelectionHelper() { } diff --git a/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/TileMapEditing/EdModeTileMap.cpp b/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/TileMapEditing/EdModeTileMap.cpp index 3aea76db8f30..5148f1aa9458 100644 --- a/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/TileMapEditing/EdModeTileMap.cpp +++ b/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/TileMapEditing/EdModeTileMap.cpp @@ -637,7 +637,7 @@ UPaperTileLayer* FEdModeTileMap::GetSelectedLayerUnderCursor(const FViewportCurs { UPaperTileLayer* Layer = TileMap->TileLayers[LayerIndex]; - ComponentToWorld = (TileMapComponent != nullptr) ? TileMapComponent->ComponentToWorld : FTransform::Identity; + ComponentToWorld = TileMapComponent->ComponentToWorld; const FVector LocalStart = ComponentToWorld.InverseTransformPosition(TraceStart); const FVector LocalDirection = ComponentToWorld.InverseTransformVector(TraceDir); const FVector LocalEnd = LocalStart + (LocalDirection * HALF_WORLD_MAX); diff --git a/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/TileMapEditing/PaperTileMapDetailsCustomization.cpp b/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/TileMapEditing/PaperTileMapDetailsCustomization.cpp index 99b0b61fbb21..233306049fb9 100644 --- a/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/TileMapEditing/PaperTileMapDetailsCustomization.cpp +++ b/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/TileMapEditing/PaperTileMapDetailsCustomization.cpp @@ -358,7 +358,7 @@ FReply FPaperTileMapDetailsCustomization::OnPromoteToAssetButtonClicked() PromotionFactory->AssetToRename = TileMapComponent->TileMap; FAssetToolsModule& AssetToolsModule = FAssetToolsModule::GetModule(); - UObject* NewAsset = AssetToolsModule.Get().CreateAsset(PromotionFactory->GetSupportedClass(), PromotionFactory); + UObject* NewAsset = AssetToolsModule.Get().CreateAssetWithDialog(PromotionFactory->GetSupportedClass(), PromotionFactory); // Show it in the content browser TArray ObjectsToSync; diff --git a/Engine/Plugins/2D/Paper2D/Source/PaperSpriteSheetImporter/Private/PaperJsonSpriteSheetImporter.cpp b/Engine/Plugins/2D/Paper2D/Source/PaperSpriteSheetImporter/Private/PaperJsonSpriteSheetImporter.cpp index b1e1ce4d1429..b090610ec4cf 100644 --- a/Engine/Plugins/2D/Paper2D/Source/PaperSpriteSheetImporter/Private/PaperJsonSpriteSheetImporter.cpp +++ b/Engine/Plugins/2D/Paper2D/Source/PaperSpriteSheetImporter/Private/PaperJsonSpriteSheetImporter.cpp @@ -595,11 +595,7 @@ bool FPaperJsonSpriteSheetImporter::PerformImport(const FString& LongPackagePath AssetToolsModule.Get().CreateUniqueAssetName(TentativePackagePath, DefaultSuffix, /*out*/ PackageName, /*out*/ AssetName); // Create a unique package name and asset name for the frame - if (OuterForFrame == nullptr) - { - // Create a package for the frame - OuterForFrame = CreatePackage(nullptr, *PackageName); - } + OuterForFrame = CreatePackage(nullptr, *PackageName); // Create the asset TargetSprite = NewObject(OuterForFrame, *AssetName, Flags); diff --git a/Engine/Plugins/Blendables/LightPropagationVolume/Source/LightPropagationVolumeRuntime/LightPropagationVolumeRuntime.Build.cs b/Engine/Plugins/Blendables/LightPropagationVolume/Source/LightPropagationVolumeRuntime/LightPropagationVolumeRuntime.Build.cs index a7e7fe61003c..90ba318de432 100644 --- a/Engine/Plugins/Blendables/LightPropagationVolume/Source/LightPropagationVolumeRuntime/LightPropagationVolumeRuntime.Build.cs +++ b/Engine/Plugins/Blendables/LightPropagationVolume/Source/LightPropagationVolumeRuntime/LightPropagationVolumeRuntime.Build.cs @@ -6,11 +6,14 @@ public class LightPropagationVolumeRuntime : ModuleRules { public LightPropagationVolumeRuntime(ReadOnlyTargetRules Target) : base(Target) { + ShortName = "LPVRuntime"; + PrivateDependencyModuleNames.AddRange( new string[] { "Core", "CoreUObject", "Engine", // FBlendableManager + "Renderer" // "RHI", // "RenderCore", // "ShaderCore", diff --git a/Engine/Plugins/Blendables/LightPropagationVolume/Source/LightPropagationVolumeRuntime/Public/LightPropagationVolumeBlendable.h b/Engine/Plugins/Blendables/LightPropagationVolume/Source/LightPropagationVolumeRuntime/Public/LightPropagationVolumeBlendable.h index 8f08cd8b1c8e..986f0ea68f22 100644 --- a/Engine/Plugins/Blendables/LightPropagationVolume/Source/LightPropagationVolumeRuntime/Public/LightPropagationVolumeBlendable.h +++ b/Engine/Plugins/Blendables/LightPropagationVolume/Source/LightPropagationVolumeRuntime/Public/LightPropagationVolumeBlendable.h @@ -6,154 +6,9 @@ #include "UObject/ObjectMacros.h" #include "UObject/Object.h" #include "Engine/BlendableInterface.h" +#include "LightPropagationVolumeSettings.h" #include "LightPropagationVolumeBlendable.generated.h" -USTRUCT(BlueprintType) -struct FLightPropagationVolumeSettings -{ - GENERATED_USTRUCT_BODY() - - UPROPERTY(BlueprintReadWrite, EditAnywhere, Category=Overrides, meta=(PinHiddenByDefault, InlineEditConditionToggle)) - uint32 bOverride_LPVIntensity:1; - - UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle)) - uint32 bOverride_LPVDirectionalOcclusionIntensity:1; - - UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle)) - uint32 bOverride_LPVDirectionalOcclusionRadius:1; - - UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle)) - uint32 bOverride_LPVDiffuseOcclusionExponent:1; - - UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle)) - uint32 bOverride_LPVSpecularOcclusionExponent:1; - - UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle)) - uint32 bOverride_LPVDiffuseOcclusionIntensity:1; - - UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle)) - uint32 bOverride_LPVSpecularOcclusionIntensity:1; - - UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle)) - uint32 bOverride_LPVSize:1; - - UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle)) - uint32 bOverride_LPVSecondaryOcclusionIntensity:1; - - UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle)) - uint32 bOverride_LPVSecondaryBounceIntensity:1; - - UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle)) - uint32 bOverride_LPVGeometryVolumeBias:1; - - UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle)) - uint32 bOverride_LPVVplInjectionBias:1; - - UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle)) - uint32 bOverride_LPVEmissiveInjectionIntensity:1; - - /** How strong the dynamic GI from the LPV should be. 0.0 is off, 1.0 is the "normal" value, but higher values can be used to boost the effect*/ - UPROPERTY(interp, BlueprintReadWrite, Category=LightPropagationVolume, meta=(editcondition = "bOverride_LPVIntensity", UIMin = "0", UIMax = "20", DisplayName = "Intensity") ) - float LPVIntensity; - - /** Bias applied to light injected into the LPV in cell units. Increase to reduce bleeding through thin walls*/ - UPROPERTY(interp, BlueprintReadWrite, Category=LightPropagationVolume, AdvancedDisplay, meta=(editcondition = "bOverride_LPVVplInjectionBias", UIMin = "0", UIMax = "2", DisplayName = "Light Injection Bias") ) - float LPVVplInjectionBias; - - /** The size of the LPV volume, in Unreal units*/ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=LightPropagationVolume, meta=(editcondition = "bOverride_LPVSize", UIMin = "100", UIMax = "20000", DisplayName = "Size") ) - float LPVSize; - - /** Secondary occlusion strength (bounce light shadows). Set to 0 to disable*/ - UPROPERTY(interp, BlueprintReadWrite, Category=LightPropagationVolume, meta=(editcondition = "bOverride_LPVSecondaryOcclusionIntensity", UIMin = "0", UIMax = "1", DisplayName = "Secondary Occlusion Intensity") ) - float LPVSecondaryOcclusionIntensity; - - /** Secondary bounce light strength (bounce light shadows). Set to 0 to disable*/ - UPROPERTY(interp, BlueprintReadWrite, Category=LightPropagationVolume, AdvancedDisplay, meta=(editcondition = "bOverride_LPVSecondaryBounceIntensity", UIMin = "0", UIMax = "1", DisplayName = "Secondary Bounce Intensity") ) - float LPVSecondaryBounceIntensity; - - /** Bias applied to the geometry volume in cell units. Increase to reduce darkening due to secondary occlusion */ - UPROPERTY(interp, BlueprintReadWrite, Category=LightPropagationVolume, AdvancedDisplay, meta=(editcondition = "bOverride_LPVGeometryVolumeBias", UIMin = "0", UIMax = "2", DisplayName = "Geometry Volume Bias")) - float LPVGeometryVolumeBias; - - UPROPERTY(interp, BlueprintReadWrite, Category=LightPropagationVolume, AdvancedDisplay, meta=(editcondition = "bOverride_LPVEmissiveInjectionIntensity", UIMin = "0", UIMax = "20", DisplayName = "Emissive Injection Intensity") ) - float LPVEmissiveInjectionIntensity; - - /** Controls the amount of directional occlusion. Requires LPV. Values very close to 1.0 are recommended */ - UPROPERTY(interp, BlueprintReadWrite, Category=LightPropagationVolume, meta=(editcondition = "bOverride_LPVDirectionalOcclusionIntensity", UIMin = "0", UIMax = "1", DisplayName = "Occlusion Intensity") ) - float LPVDirectionalOcclusionIntensity; - - /** Occlusion Radius - 16 is recommended for most scenes */ - UPROPERTY(interp, BlueprintReadWrite, Category=LightPropagationVolume, AdvancedDisplay, meta=(editcondition = "bOverride_LPVDirectionalOcclusionRadius", UIMin = "1", UIMax = "16", DisplayName = "Occlusion Radius") ) - float LPVDirectionalOcclusionRadius; - - /** Diffuse occlusion exponent - increase for more contrast. 1 to 2 is recommended */ - UPROPERTY(interp, BlueprintReadWrite, Category=LightPropagationVolume, meta=(editcondition = "bOverride_LPVDiffuseOcclusionExponent", UIMin = "0.5", UIMax = "5", DisplayName = "Diffuse occlusion exponent") ) - float LPVDiffuseOcclusionExponent; - - /** Specular occlusion exponent - increase for more contrast. 6 to 9 is recommended */ - UPROPERTY(interp, BlueprintReadWrite, Category=LightPropagationVolume, meta=(editcondition = "bOverride_LPVSpecularOcclusionExponent", UIMin = "1", UIMax = "16", DisplayName = "Specular occlusion exponent") ) - float LPVSpecularOcclusionExponent; - - /** Diffuse occlusion intensity - higher values provide increased diffuse occlusion.*/ - UPROPERTY(interp, BlueprintReadWrite, Category=LightPropagationVolume, AdvancedDisplay, meta=(editcondition = "bOverride_LPVDiffuseOcclusionIntensity", UIMin = "0", UIMax = "4", DisplayName = "Diffuse occlusion intensity") ) - float LPVDiffuseOcclusionIntensity; - - /** Specular occlusion intensity - higher values provide increased specular occlusion.*/ - UPROPERTY(interp, BlueprintReadWrite, Category=LightPropagationVolume, AdvancedDisplay, meta=(editcondition = "bOverride_LPVSpecularOcclusionIntensity", UIMin = "0", UIMax = "4", DisplayName = "Specular occlusion intensity") ) - float LPVSpecularOcclusionIntensity; - - /** LPV Fade range - increase to fade more gradually towards the LPV edges.*/ - UPROPERTY(interp, BlueprintReadWrite, Category=LightPropagationVolume, AdvancedDisplay, meta=(editcondition = "bOverride_LPVFadeRange", UIMin = "0", UIMax = "9", DisplayName = "Fade range")) - float LPVFadeRange; - - /** LPV Directional Occlusion Fade range - increase to fade more gradually towards the LPV edges.*/ - UPROPERTY(interp, BlueprintReadWrite, Category=LightPropagationVolume, AdvancedDisplay, meta=(editcondition = "bOverride_LPVDirectionalOcclusionFadeRange", UIMin = "0", UIMax = "9", DisplayName = "DO Fade range")) - float LPVDirectionalOcclusionFadeRange; - - // good start values for a new volume - FLightPropagationVolumeSettings() - { - // to set all bOverride_.. by default to false - FMemory::Memzero(this, sizeof(*this)); - - // default values: - - LPVIntensity = 1.0f; - LPVSize = 5312.0f; - LPVSecondaryOcclusionIntensity = 0.0f; - LPVSecondaryBounceIntensity = 0.0f; - LPVVplInjectionBias = 0.64f; - LPVGeometryVolumeBias = 0.384f; - LPVEmissiveInjectionIntensity = 1.0f; - LPVDirectionalOcclusionIntensity = 0.0f; - LPVDirectionalOcclusionRadius = 8.0f; - LPVDiffuseOcclusionExponent = 1.0f; - LPVSpecularOcclusionExponent = 7.0f; - LPVDiffuseOcclusionIntensity = 1.0f; - LPVSpecularOcclusionIntensity = 1.0f; - LPVFadeRange = 0.0f; - LPVDirectionalOcclusionFadeRange = 0.0f; - } - - /** - * Used to define the values before any override happens. - * Should be as neutral as possible. - */ - void SetBaseValues() - { - *this = FLightPropagationVolumeSettings(); - } - - // for type safety in FBlendableManager - static const FName& GetFName() - { - static const FName Name = FName(TEXT("FLightPropagationVolumeSettings")); - - return Name; - } -}; - // BlueprintType to make the object spawnable in blueprint UCLASS(MinimalAPI, Blueprintable, BlueprintType) class ULightPropagationVolumeBlendable : public UObject, public IBlendableInterface diff --git a/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlOperations.cpp b/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlOperations.cpp index bfccdde9afac..a5e32c7e85ad 100644 --- a/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlOperations.cpp +++ b/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlOperations.cpp @@ -78,7 +78,7 @@ bool FGitCheckInWorker::Execute(FGitSourceControlCommand& InCommand) if(InCommand.bCommandSuccessful) { // Remove any deleted files from status cache - FGitSourceControlModule& GitSourceControl = FModuleManager::LoadModuleChecked("GitSourceControl"); + FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked("GitSourceControl"); FGitSourceControlProvider& Provider = GitSourceControl.GetProvider(); TArray> LocalStates; diff --git a/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlProvider.cpp b/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlProvider.cpp index 10c7df465baf..f23bf35dd43f 100644 --- a/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlProvider.cpp +++ b/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlProvider.cpp @@ -20,7 +20,11 @@ static FName ProviderName("Git"); void FGitSourceControlProvider::Init(bool bForceConnection) { - CheckGitAvailability(); + // Init() is called multiple times at startup: do not check git each time + if(!bGitAvailable) + { + CheckGitAvailability(); + } // bForceConnection: not used anymore } @@ -28,28 +32,23 @@ void FGitSourceControlProvider::Init(bool bForceConnection) void FGitSourceControlProvider::CheckGitAvailability() { FGitSourceControlModule& GitSourceControl = FModuleManager::LoadModuleChecked("GitSourceControl"); - const FString& PathToGitBinary = GitSourceControl.AccessSettings().GetBinaryPath(); + FString PathToGitBinary = GitSourceControl.AccessSettings().GetBinaryPath(); + if(PathToGitBinary.IsEmpty()) + { + // Try to find Git binary, and update settings accordingly + PathToGitBinary = GitSourceControlUtils::FindGitBinaryPath(); + if(!PathToGitBinary.IsEmpty()) + { + GitSourceControl.AccessSettings().SetBinaryPath(PathToGitBinary); + } + } + if(!PathToGitBinary.IsEmpty()) { bGitAvailable = GitSourceControlUtils::CheckGitAvailability(PathToGitBinary, &GitVersion); if(bGitAvailable) { - // Find the path to the root Git directory (if any) - const FString PathToGameDir = FPaths::ConvertRelativePathToFull(FPaths::GameDir()); - const bool bRepositoryFound = GitSourceControlUtils::FindRootDirectory(PathToGameDir, PathToRepositoryRoot); - // Get user name & email (of the repository, else from the global Git config) - GitSourceControlUtils::GetUserConfig(PathToGitBinary, PathToRepositoryRoot, UserName, UserEmail); - if (bRepositoryFound) - { - // Get branch name - GitSourceControlUtils::GetBranchName(PathToGitBinary, PathToRepositoryRoot, BranchName); - bGitRepositoryFound = true; - } - else - { - UE_LOG(LogSourceControl, Error, TEXT("'%s' is not part of a Git repository"), *FPaths::GameDir()); - bGitRepositoryFound = false; - } + CheckRepositoryStatus(PathToGitBinary); } } else @@ -58,10 +57,38 @@ void FGitSourceControlProvider::CheckGitAvailability() } } +void FGitSourceControlProvider::CheckRepositoryStatus(const FString& InPathToGitBinary) +{ + // Find the path to the root Git directory (if any) + const FString PathToGameDir = FPaths::ConvertRelativePathToFull(FPaths::GameDir()); + bGitRepositoryFound = GitSourceControlUtils::FindRootDirectory(PathToGameDir, PathToRepositoryRoot); + if(bGitRepositoryFound) + { + // Get branch name + bGitRepositoryFound = GitSourceControlUtils::GetBranchName(InPathToGitBinary, PathToRepositoryRoot, BranchName); + if (!bGitRepositoryFound) + { + UE_LOG(LogSourceControl, Error, TEXT("'%s' is not a valid Git repository"), *PathToRepositoryRoot); + } + } + else + { + UE_LOG(LogSourceControl, Warning, TEXT("'%s' is not part of a Git repository"), *FPaths::GameDir()); + } + + // Get user name & email (of the repository, else from the global Git config) + GitSourceControlUtils::GetUserConfig(InPathToGitBinary, PathToRepositoryRoot, UserName, UserEmail); +} + void FGitSourceControlProvider::Close() { // clear the cache StateCache.Empty(); + + bGitAvailable = false; + bGitRepositoryFound = false; + UserName.Empty(); + UserEmail.Empty(); } TSharedRef FGitSourceControlProvider::GetStateInternal(const FString& Filename) @@ -217,6 +244,11 @@ bool FGitSourceControlProvider::UsesChangelists() const return false; } +bool FGitSourceControlProvider::UsesCheckout() const +{ + return false; +} + TSharedPtr FGitSourceControlProvider::CreateWorker(const FName& InOperationName) const { const FGetGitSourceControlWorker* Operation = WorkersMap.Find(InOperationName); diff --git a/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlProvider.h b/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlProvider.h index c98102fc0311..791200f4045b 100644 --- a/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlProvider.h +++ b/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlProvider.h @@ -19,11 +19,15 @@ struct FGitVersion int Minor; uint32 bHasCatFileWithFilters : 1; + uint32 bHasGitLfs : 1; + uint32 bHasGitLfsLocking : 1; FGitVersion() : Major(0) , Minor(0) , bHasCatFileWithFilters(false) + , bHasGitLfs(false) + , bHasGitLfsLocking(false) { } @@ -59,6 +63,7 @@ public: virtual void CancelOperation( const TSharedRef& InOperation ) override; virtual bool UsesLocalReadOnlyState() const override; virtual bool UsesChangelists() const override; + virtual bool UsesCheckout() const override; virtual void Tick() override; virtual TArray< TSharedRef > GetLabels( const FString& InMatchingSpec ) const override; #if SOURCE_CONTROL_WITH_SLATE @@ -66,10 +71,15 @@ public: #endif /** - * Run a Git "version" command to check the availability of the binary. + * Check configuration, else standard paths, and run a Git "version" command to check the availability of the binary. */ void CheckGitAvailability(); + /** + * Find the .git/ repository and check it's status. + */ + void CheckRepositoryStatus(const FString& InPathToGitBinary); + /** Is git binary found and working. */ inline bool IsGitAvailable() const { diff --git a/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlSettings.cpp b/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlSettings.cpp index 0c46ba3b5a40..bab4742ddc05 100644 --- a/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlSettings.cpp +++ b/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlSettings.cpp @@ -15,16 +15,21 @@ static const FString SettingsSection = TEXT("GitSourceControl.GitSourceControlSe } -const FString& FGitSourceControlSettings::GetBinaryPath() const +const FString FGitSourceControlSettings::GetBinaryPath() const { FScopeLock ScopeLock(&CriticalSection); return BinaryPath; } -void FGitSourceControlSettings::SetBinaryPath(const FString& InString) +bool FGitSourceControlSettings::SetBinaryPath(const FString& InString) { FScopeLock ScopeLock(&CriticalSection); - BinaryPath = InString; + const bool bChanged = (BinaryPath != InString); + if(bChanged) + { + BinaryPath = InString; + } + return bChanged; } // This is called at startup nearly before anything else in our module: BinaryPath will then be used by the provider @@ -32,23 +37,12 @@ void FGitSourceControlSettings::LoadSettings() { FScopeLock ScopeLock(&CriticalSection); const FString& IniFile = SourceControlHelpers::GetSettingsIni(); - bool bLoaded = GConfig->GetString(*GitSettingsConstants::SettingsSection, TEXT("BinaryPath"), BinaryPath, IniFile); - if(!bLoaded || BinaryPath.IsEmpty()) - { - BinaryPath = GitSourceControlUtils::FindGitBinaryPath(); - } + GConfig->GetString(*GitSettingsConstants::SettingsSection, TEXT("BinaryPath"), BinaryPath, IniFile); } void FGitSourceControlSettings::SaveSettings() const { FScopeLock ScopeLock(&CriticalSection); - - // Re-Check provided git binary path for each change - FGitSourceControlModule& GitSourceControl = FModuleManager::LoadModuleChecked("GitSourceControl"); - GitSourceControl.GetProvider().CheckGitAvailability(); - if (GitSourceControl.GetProvider().IsAvailable()) - { - const FString& IniFile = SourceControlHelpers::GetSettingsIni(); - GConfig->SetString(*GitSettingsConstants::SettingsSection, TEXT("BinaryPath"), *BinaryPath, IniFile); - } + const FString& IniFile = SourceControlHelpers::GetSettingsIni(); + GConfig->SetString(*GitSettingsConstants::SettingsSection, TEXT("BinaryPath"), *BinaryPath, IniFile); } diff --git a/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlSettings.h b/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlSettings.h index b970ebbecbc4..26fc995c5837 100644 --- a/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlSettings.h +++ b/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlSettings.h @@ -8,10 +8,10 @@ class FGitSourceControlSettings { public: /** Get the Git Binary Path */ - const FString& GetBinaryPath() const; + const FString GetBinaryPath() const; /** Set the Git Binary Path */ - void SetBinaryPath(const FString& InString); + bool SetBinaryPath(const FString& InString); /** Load settings from ini file */ void LoadSettings(); diff --git a/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlUtils.cpp b/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlUtils.cpp index 4df69f501407..eeee1cd6f820 100644 --- a/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlUtils.cpp +++ b/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlUtils.cpp @@ -231,11 +231,9 @@ FString FindGitBinaryPath() bool CheckGitAvailability(const FString& InPathToGitBinary, FGitVersion *OutVersion) { - bool bGitAvailable = false; - FString InfoMessages; FString ErrorMessages; - bGitAvailable = RunCommandInternalRaw(TEXT("version"), InPathToGitBinary, FString(), TArray(), TArray(), InfoMessages, ErrorMessages); + bool bGitAvailable = RunCommandInternalRaw(TEXT("version"), InPathToGitBinary, FString(), TArray(), TArray(), InfoMessages, ErrorMessages); if(bGitAvailable) { if(!InfoMessages.Contains("git")) @@ -246,6 +244,7 @@ bool CheckGitAvailability(const FString& InPathToGitBinary, FGitVersion *OutVers { ParseGitVersion(InfoMessages, OutVersion); FindGitCapabilities(InPathToGitBinary, OutVersion); + FindGitLfsCapabilities(InPathToGitBinary, OutVersion); } } @@ -287,6 +286,22 @@ void FindGitCapabilities(const FString& InPathToGitBinary, FGitVersion *OutVersi } } +void FindGitLfsCapabilities(const FString& InPathToGitBinary, FGitVersion *OutVersion) +{ + FString InfoMessages; + FString ErrorMessages; + bool bGitLfsAvailable = RunCommandInternalRaw(TEXT("lfs version"), InPathToGitBinary, FString(), TArray(), TArray(), InfoMessages, ErrorMessages); + if(bGitLfsAvailable) + { + OutVersion->bHasGitLfs = true; + + if(0 <= InfoMessages.Compare(TEXT("git-lfs/2.0.0"))) + { + OutVersion->bHasGitLfsLocking = true; // Git LFS File Locking workflow introduced in "git-lfs/2.0.0" + } + } +} + // Find the root of the Git repository, looking from the provided path and upward in its parent directories. bool FindRootDirectory(const FString& InPath, FString& OutRepositoryRoot) { @@ -355,7 +370,7 @@ void GetUserConfig(const FString& InPathToGitBinary, const FString& InRepository } } -void GetBranchName(const FString& InPathToGitBinary, const FString& InRepositoryRoot, FString& OutBranchName) +bool GetBranchName(const FString& InPathToGitBinary, const FString& InRepositoryRoot, FString& OutBranchName) { bool bResults; TArray InfoMessages; @@ -380,7 +395,13 @@ void GetBranchName(const FString& InPathToGitBinary, const FString& InRepository OutBranchName = "HEAD detached at "; OutBranchName += InfoMessages[0]; } + else + { + bResults = false; + } } + + return bResults; } bool RunCommand(const FString& InCommand, const FString& InPathToGitBinary, const FString& InRepositoryRoot, const TArray& InParameters, const TArray& InFiles, TArray& OutResults, TArray& OutErrorMessages) diff --git a/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlUtils.h b/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlUtils.h index 09ef10d0d7ea..d68cb60e03c7 100644 --- a/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlUtils.h +++ b/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlUtils.h @@ -61,6 +61,13 @@ bool CheckGitAvailability(const FString& InPathToGitBinary, FGitVersion* OutVers */ void FindGitCapabilities(const FString& InPathToGitBinary, FGitVersion *OutVersion); +/** + * Run a Git "lfs" command to check the availability of the "Large File System" extension. + * @param InPathToGitBinary The path to the Git binary + * @param OutGitVersion If provided, populate with the git version parsed from "version" command + */ + void FindGitLfsCapabilities(const FString& InPathToGitBinary, FGitVersion *OutVersion); + /** * Find the root of the Git repository, looking from the provided path and upward in its parent directories * @param InPath The path to the Game Directory (or any path or file in any git repository) @@ -83,8 +90,9 @@ void GetUserConfig(const FString& InPathToGitBinary, const FString& InRepository * @param InPathToGitBinary The path to the Git binary * @param InRepositoryRoot The Git repository from where to run the command - usually the Game directory (can be empty) * @param OutBranchName Name of the current checked-out branch (if any, ie. not in detached HEAD) + * @returns true if the command succeeded and returned no errors */ -void GetBranchName(const FString& InPathToGitBinary, const FString& InRepositoryRoot, FString& OutBranchName); +bool GetBranchName(const FString& InPathToGitBinary, const FString& InRepositoryRoot, FString& OutBranchName); /** * Run a Git command - output is a string TArray. diff --git a/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/SGitSourceControlSettings.cpp b/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/SGitSourceControlSettings.cpp index 3ee4abe3a8eb..bfadce88e461 100644 --- a/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/SGitSourceControlSettings.cpp +++ b/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/SGitSourceControlSettings.cpp @@ -28,6 +28,7 @@ void SGitSourceControlSettings::Construct(const FArguments& InArgs) FSlateFontInfo Font = FEditorStyle::GetFontStyle(TEXT("SourceControl.LoginWindow.Font")); bAutoCreateGitIgnore = true; + bAutoCreateGitAttributes = false; bAutoInitialCommit = true; InitialCommitMessage = LOCTEXT("InitialCommitMessage", "Initial commit"); @@ -188,6 +189,33 @@ void SGitSourceControlSettings::Construct(const FArguments& InArgs) .Font(Font) ] ] + // Option to add a proper .gitattributes file for Git LFS (false by default) + +SVerticalBox::Slot() + .AutoHeight() + .Padding(2.0f) + .VAlign(VAlign_Center) + [ + SNew(SHorizontalBox) + .Visibility(this, &SGitSourceControlSettings::CanInitializeGitRepository) + +SHorizontalBox::Slot() + .FillWidth(0.1f) + [ + SNew(SCheckBox) + .ToolTipText(LOCTEXT("CreateGitAttributes_Tooltip", "Create and add a '.gitattributes' file to enable Git LFS for the whole 'Content/' directory (needs Git LFS extensions to be installed).")) + .IsChecked(ECheckBoxState::Unchecked) + .OnCheckStateChanged(this, &SGitSourceControlSettings::OnCheckedCreateGitAttributes) + .IsEnabled(this, &SGitSourceControlSettings::CanInitializeGitLfs) + ] + +SHorizontalBox::Slot() + .FillWidth(2.9f) + .VAlign(VAlign_Center) + [ + SNew(STextBlock) + .Text(LOCTEXT("CreateGitAttributes", "Add a .gitattributes file to enable Git LFS")) + .ToolTipText(LOCTEXT("CreateGitAttributes_Tooltip", "Create and add a '.gitattributes' file to enable Git LFS")) + .Font(Font) + ] + ] // Option to Make the initial Git commit with custom message +SVerticalBox::Slot() .AutoHeight() @@ -224,10 +252,10 @@ void SGitSourceControlSettings::Construct(const FArguments& InArgs) .Font(Font) ] ] - // Button to initialize the project with Git, create the .gitignore, and make the first commit) + // Button to initialize the project with Git, create .gitignore/.gitattributes files, and make the first commit) +SVerticalBox::Slot() .FillHeight(2.0f) - .Padding(2.0f) + .Padding(2.5f) .VAlign(VAlign_Center) [ SNew(SHorizontalBox) @@ -240,6 +268,7 @@ void SGitSourceControlSettings::Construct(const FArguments& InArgs) .ToolTipText(LOCTEXT("GitInitRepository_Tooltip", "Initialize current project as a new Git repository")) .OnClicked(this, &SGitSourceControlSettings::OnClickedInitializeGitRepository) .HAlign(HAlign_Center) + .ContentPadding(6) ] ] ] @@ -260,8 +289,16 @@ FText SGitSourceControlSettings::GetBinaryPathText() const void SGitSourceControlSettings::OnBinaryPathTextCommited(const FText& InText, ETextCommit::Type InCommitType) const { FGitSourceControlModule& GitSourceControl = FModuleManager::LoadModuleChecked("GitSourceControl"); - GitSourceControl.AccessSettings().SetBinaryPath(InText.ToString()); - GitSourceControl.SaveSettings(); + const bool bChanged = GitSourceControl.AccessSettings().SetBinaryPath(InText.ToString()); + if(bChanged) + { + // Re-Check provided git binary path for each change + GitSourceControl.GetProvider().CheckGitAvailability(); + if(GitSourceControl.GetProvider().IsGitAvailable()) + { + GitSourceControl.SaveSettings(); + } + } } FText SGitSourceControlSettings::GetPathToRepositoryRoot() const @@ -290,6 +327,15 @@ EVisibility SGitSourceControlSettings::CanInitializeGitRepository() const return (bGitAvailable && !bGitRepositoryFound) ? EVisibility::Visible : EVisibility::Collapsed; } +bool SGitSourceControlSettings::CanInitializeGitLfs() const +{ + FGitSourceControlModule& GitSourceControl = FModuleManager::LoadModuleChecked("GitSourceControl"); + const FString& PathToGitBinary = GitSourceControl.AccessSettings().GetBinaryPath(); + const bool bGitLfsAvailable = GitSourceControl.GetProvider().GetGitVersion().bHasGitLfs; + const bool bGitRepositoryFound = GitSourceControl.GetProvider().IsEnabled(); + return (bGitLfsAvailable && !bGitRepositoryFound); +} + FReply SGitSourceControlSettings::OnClickedInitializeGitRepository() { FGitSourceControlModule& GitSourceControl = FModuleManager::LoadModuleChecked("GitSourceControl"); @@ -301,11 +347,11 @@ FReply SGitSourceControlSettings::OnClickedInitializeGitRepository() // 1. Synchronous (very quick) "git init" operation: initialize a Git local repository with a .git/ subdirectory GitSourceControlUtils::RunCommand(TEXT("init"), PathToGitBinary, PathToGameDir, TArray(), TArray(), InfoMessages, ErrorMessages); - // Check the new repository status to enable connection - GitSourceControl.GetProvider().CheckGitAvailability(); - if(GitSourceControl.GetProvider().IsEnabled()) + // Check the new repository status to enable connection (branch, user e-mail) + GitSourceControl.GetProvider().CheckRepositoryStatus(PathToGitBinary); + if(GitSourceControl.GetProvider().IsAvailable()) { - // List of files to add to Source Control (.uproject, Config/, Content/, Source/ files and .gitignore if any) + // List of files to add to Source Control (.uproject, Config/, Content/, Source/ files and .gitignore/.gitattributes if any) TArray ProjectFiles; ProjectFiles.Add(FPaths::GetProjectFilePath()); ProjectFiles.Add(FPaths::GameConfigDir()); @@ -316,14 +362,27 @@ FReply SGitSourceControlSettings::OnClickedInitializeGitRepository() } if(bAutoCreateGitIgnore) { - // 2. Create a standard ".gitignore" file with common patterns for a typical Blueprint & C++ project + // 2.a. Create a standard ".gitignore" file with common patterns for a typical Blueprint & C++ project const FString GitIgnoreFilename = FPaths::Combine(FPaths::GameDir(), TEXT(".gitignore")); - const FString GitIgnoreContent = TEXT("Binaries\nDerivedDataCache\nIntermediate\nSaved\n*.VC.db\n*.opensdf\n*.opendb\n*.sdf\n*.sln\n*.suo\n*.xcodeproj\n*.xcworkspace"); + const FString GitIgnoreContent = TEXT("Binaries\nDerivedDataCache\nIntermediate\nSaved\n.vs\n*.VC.db\n*.opensdf\n*.opendb\n*.sdf\n*.sln\n*.suo\n*.xcodeproj\n*.xcworkspace"); if(FFileHelper::SaveStringToFile(GitIgnoreContent, *GitIgnoreFilename, FFileHelper::EEncodingOptions::ForceUTF8WithoutBOM)) { ProjectFiles.Add(GitIgnoreFilename); } } + if (bAutoCreateGitAttributes) + { + // 2.b. Synchronous (very quick) "lfs install" operation: needs only to be run once by user + GitSourceControlUtils::RunCommand(TEXT("lfs install"), PathToGitBinary, PathToGameDir, TArray(), TArray(), InfoMessages, ErrorMessages); + + // 2.c. Create a ".gitattributes" file to enable Git LFS (Large File System) for the whole "Content/" subdir + const FString GitAttributesFilename = FPaths::Combine(FPaths::GameDir(), TEXT(".gitattributes")); + const FString GitAttributesContent = TEXT("Content/** filter=lfs diff=lfs merge=lfs -text lockable\n"); + if (FFileHelper::SaveStringToFile(GitAttributesContent, *GitAttributesFilename, FFileHelper::EEncodingOptions::ForceUTF8WithoutBOM)) + { + ProjectFiles.Add(GitAttributesFilename); + } + } // 3. Add files to Source Control: launch an asynchronous MarkForAdd operation LaunchMarkForAddOperation(ProjectFiles); @@ -437,6 +496,11 @@ void SGitSourceControlSettings::OnCheckedCreateGitIgnore(ECheckBoxState NewCheck bAutoCreateGitIgnore = (NewCheckedState == ECheckBoxState::Checked); } +void SGitSourceControlSettings::OnCheckedCreateGitAttributes(ECheckBoxState NewCheckedState) +{ + bAutoCreateGitAttributes = (NewCheckedState == ECheckBoxState::Checked); +} + void SGitSourceControlSettings::OnCheckedInitialCommit(ECheckBoxState NewCheckedState) { bAutoInitialCommit = (NewCheckedState == ECheckBoxState::Checked); diff --git a/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/SGitSourceControlSettings.h b/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/SGitSourceControlSettings.h index 3219fd481575..36c8072666d6 100644 --- a/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/SGitSourceControlSettings.h +++ b/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/SGitSourceControlSettings.h @@ -40,13 +40,18 @@ private: FText GetUserName() const; FText GetUserEmail() const; - /** Delegate to initialize a new Git repository */ EVisibility CanInitializeGitRepository() const; + bool CanInitializeGitLfs() const; + + /** Delegate to initialize a new Git repository */ FReply OnClickedInitializeGitRepository(); void OnCheckedCreateGitIgnore(ECheckBoxState NewCheckedState); bool bAutoCreateGitIgnore; + void OnCheckedCreateGitAttributes(ECheckBoxState NewCheckedState); + bool bAutoCreateGitAttributes; + void OnCheckedInitialCommit(ECheckBoxState NewCheckedState); bool bAutoInitialCommit; void OnInitialCommitMessageCommited(const FText& InText, ETextCommit::Type InCommitType); diff --git a/Engine/Plugins/Developer/OneSkyLocalizationService/Source/OneSkyLocalizationService/Private/OneSkyLocalizationServiceOperations.cpp b/Engine/Plugins/Developer/OneSkyLocalizationService/Source/OneSkyLocalizationService/Private/OneSkyLocalizationServiceOperations.cpp index ea1ac22bc697..a13323b6449b 100644 --- a/Engine/Plugins/Developer/OneSkyLocalizationService/Source/OneSkyLocalizationService/Private/OneSkyLocalizationServiceOperations.cpp +++ b/Engine/Plugins/Developer/OneSkyLocalizationService/Source/OneSkyLocalizationService/Private/OneSkyLocalizationServiceOperations.cpp @@ -1016,7 +1016,7 @@ void FOneSkyUploadFileWorker::Query_HttpRequestComplete(FHttpRequestPtr HttpRequ if (bResult) { - TSharedPtr UploadFileOp = StaticCastSharedRef(Command->Operation); + TSharedPtr UploadFileOp = StaticCastSharedRef(Command->Operation); //-V595 FGuid InTargetGuid; int32 InProjectId = -1; diff --git a/Engine/Plugins/Developer/OneSkyLocalizationService/Source/OneSkyLocalizationService/Private/OneSkyLocalizationServiceProvider.cpp b/Engine/Plugins/Developer/OneSkyLocalizationService/Source/OneSkyLocalizationService/Private/OneSkyLocalizationServiceProvider.cpp index aaa5cc8b0db8..2cfea2e080ab 100644 --- a/Engine/Plugins/Developer/OneSkyLocalizationService/Source/OneSkyLocalizationService/Private/OneSkyLocalizationServiceProvider.cpp +++ b/Engine/Plugins/Developer/OneSkyLocalizationService/Source/OneSkyLocalizationService/Private/OneSkyLocalizationServiceProvider.cpp @@ -856,9 +856,6 @@ void FOneSkyLocalizationServiceProvider::ExportCultureForTargetToOneSky_Callback FilesDownloadingForImportFromOneSky.Remove(InRelativeInputFilePathAndName); ErrorText = UploadLocalizationTargetOp->GetOutErrorText(); - InTargetGuid = UploadLocalizationTargetOp->GetInTargetGuid(); - - Target = ILocalizationModule::Get().GetLocalizationTargetByName(TargetName, bIsEngineTarget); FilesUploadingForExportToOneSky.Remove(InRelativeInputFilePathAndName); diff --git a/Engine/Plugins/Developer/PerforceSourceControl/Source/PerforceSourceControl/Private/PerforceSourceControlProvider.cpp b/Engine/Plugins/Developer/PerforceSourceControl/Source/PerforceSourceControl/Private/PerforceSourceControlProvider.cpp index 6782c0ad4422..3b74494d2f7d 100644 --- a/Engine/Plugins/Developer/PerforceSourceControl/Source/PerforceSourceControl/Private/PerforceSourceControlProvider.cpp +++ b/Engine/Plugins/Developer/PerforceSourceControl/Source/PerforceSourceControl/Private/PerforceSourceControlProvider.cpp @@ -322,6 +322,11 @@ bool FPerforceSourceControlProvider::UsesChangelists() const return true; } +bool FPerforceSourceControlProvider::UsesCheckout() const +{ + return true; +} + void FPerforceSourceControlProvider::OutputCommandMessages(const FPerforceSourceControlCommand& InCommand) const { FMessageLog SourceControlLog("SourceControl"); diff --git a/Engine/Plugins/Developer/PerforceSourceControl/Source/PerforceSourceControl/Private/PerforceSourceControlProvider.h b/Engine/Plugins/Developer/PerforceSourceControl/Source/PerforceSourceControl/Private/PerforceSourceControlProvider.h index 845408e9b1d2..376082e132de 100644 --- a/Engine/Plugins/Developer/PerforceSourceControl/Source/PerforceSourceControl/Private/PerforceSourceControlProvider.h +++ b/Engine/Plugins/Developer/PerforceSourceControl/Source/PerforceSourceControl/Private/PerforceSourceControlProvider.h @@ -39,6 +39,7 @@ public: virtual void CancelOperation( const TSharedRef& InOperation ) override; virtual bool UsesLocalReadOnlyState() const override; virtual bool UsesChangelists() const override; + virtual bool UsesCheckout() const override; virtual void Tick() override; virtual TArray< TSharedRef > GetLabels( const FString& InMatchingSpec ) const override; #if SOURCE_CONTROL_WITH_SLATE diff --git a/Engine/Plugins/Developer/RenderDocPlugin/Source/RenderDocPlugin/Private/RenderDocPluginModule.cpp b/Engine/Plugins/Developer/RenderDocPlugin/Source/RenderDocPlugin/Private/RenderDocPluginModule.cpp index 3ab573285877..0654d6aace69 100644 --- a/Engine/Plugins/Developer/RenderDocPlugin/Source/RenderDocPlugin/Private/RenderDocPluginModule.cpp +++ b/Engine/Plugins/Developer/RenderDocPlugin/Source/RenderDocPlugin/Private/RenderDocPluginModule.cpp @@ -281,7 +281,7 @@ void FRenderDocPluginModule::CaptureCurrentViewport() // infer the intended viewport to intercept/capture: FViewport* Viewport (nullptr); check(GEngine); - if (!Viewport && GEngine->GameViewport) + if (GEngine->GameViewport) { check(GEngine->GameViewport->Viewport); if (GEngine->GameViewport->Viewport->HasFocus()) diff --git a/Engine/Plugins/Developer/SubversionSourceControl/Source/SubversionSourceControl/Private/SubversionSourceControlProvider.cpp b/Engine/Plugins/Developer/SubversionSourceControl/Source/SubversionSourceControl/Private/SubversionSourceControlProvider.cpp index f5364ff1903a..c6f593d45cfd 100644 --- a/Engine/Plugins/Developer/SubversionSourceControl/Source/SubversionSourceControl/Private/SubversionSourceControlProvider.cpp +++ b/Engine/Plugins/Developer/SubversionSourceControl/Source/SubversionSourceControl/Private/SubversionSourceControlProvider.cpp @@ -204,6 +204,11 @@ bool FSubversionSourceControlProvider::UsesChangelists() const return false; } +bool FSubversionSourceControlProvider::UsesCheckout() const +{ + return true; +} + TSharedPtr FSubversionSourceControlProvider::CreateWorker(const FName& InOperationName) const { const FGetSubversionSourceControlWorker* Operation = WorkersMap.Find(InOperationName); diff --git a/Engine/Plugins/Developer/SubversionSourceControl/Source/SubversionSourceControl/Private/SubversionSourceControlProvider.h b/Engine/Plugins/Developer/SubversionSourceControl/Source/SubversionSourceControl/Private/SubversionSourceControlProvider.h index 37286fe3d6b9..ce1e46affbef 100644 --- a/Engine/Plugins/Developer/SubversionSourceControl/Source/SubversionSourceControl/Private/SubversionSourceControlProvider.h +++ b/Engine/Plugins/Developer/SubversionSourceControl/Source/SubversionSourceControl/Private/SubversionSourceControlProvider.h @@ -38,6 +38,7 @@ public: virtual void CancelOperation( const TSharedRef& InOperation ) override; virtual bool UsesLocalReadOnlyState() const override; virtual bool UsesChangelists() const override; + virtual bool UsesCheckout() const override; virtual void Tick() override; virtual TArray< TSharedRef > GetLabels( const FString& InMatchingSpec ) const override; #if SOURCE_CONTROL_WITH_SLATE diff --git a/Engine/Plugins/Developer/VisualStudioSourceCodeAccess/Source/VisualStudioSourceCodeAccess/Private/VisualStudioSourceCodeAccessor.cpp b/Engine/Plugins/Developer/VisualStudioSourceCodeAccess/Source/VisualStudioSourceCodeAccess/Private/VisualStudioSourceCodeAccessor.cpp index f4e2c58f313e..ec8c78c8b914 100644 --- a/Engine/Plugins/Developer/VisualStudioSourceCodeAccess/Source/VisualStudioSourceCodeAccess/Private/VisualStudioSourceCodeAccessor.cpp +++ b/Engine/Plugins/Developer/VisualStudioSourceCodeAccess/Source/VisualStudioSourceCodeAccess/Private/VisualStudioSourceCodeAccessor.cpp @@ -23,6 +23,7 @@ #if VSACCESSOR_HAS_DTE #pragma warning(push) #pragma warning(disable: 4278) + #pragma warning(disable: 4471) #pragma warning(disable: 4146) #pragma warning(disable: 4191) #pragma warning(disable: 6244) @@ -211,7 +212,7 @@ EAccessVisualStudioResult AccessVisualStudioViaDTE(TComPtr& OutDTE // Get the solution path for this instance // If it equals the solution we would have opened above in RunVisualStudio(), we'll take that TComPtr Solution; - LPOLESTR OutPath; + BSTR OutPath = nullptr; if (SUCCEEDED(TempDTE->get_Solution(&Solution)) && SUCCEEDED(Solution->get_FullName(&OutPath))) { @@ -223,6 +224,8 @@ EAccessVisualStudioResult AccessVisualStudioViaDTE(TComPtr& OutDTE OutDTE = TempDTE; AccessResult = EAccessVisualStudioResult::VSInstanceIsOpen; } + + SysFreeString(OutPath); } else { @@ -563,15 +566,21 @@ bool GetProcessCommandLine(const ::DWORD InProcessID, FString& OutCommandLine) ::IWbemLocator *pLoc = nullptr; if (SUCCEEDED(::CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&pLoc))) { + FComBSTR ResourceName(TEXT("ROOT\\CIMV2")); + ::IWbemServices *pSvc = nullptr; - if (SUCCEEDED(pLoc->ConnectServer(BSTR(TEXT("ROOT\\CIMV2")), nullptr, nullptr, nullptr, 0, 0, 0, &pSvc))) + if (SUCCEEDED(pLoc->ConnectServer(ResourceName, nullptr, nullptr, nullptr, 0, 0, 0, &pSvc))) { // Set the proxy so that impersonation of the client occurs if (SUCCEEDED(::CoSetProxyBlanket(pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE))) { ::IEnumWbemClassObject* pEnumerator = nullptr; const FString WQLQuery = FString::Printf(TEXT("SELECT ProcessId, CommandLine FROM Win32_Process WHERE ProcessId=%lu"), InProcessID); - if (SUCCEEDED(pSvc->ExecQuery(BSTR(TEXT("WQL")), BSTR(*WQLQuery), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, nullptr, &pEnumerator))) + + FComBSTR WQLBstr(TEXT("WQL")); + FComBSTR WQLQueryBstr(*WQLQuery); + + if (SUCCEEDED(pSvc->ExecQuery(WQLBstr, WQLQueryBstr, WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, nullptr, &pEnumerator))) { while (pEnumerator && !bSuccess) { @@ -704,9 +713,9 @@ EAccessVisualStudioResult AccessVisualStudioViaProcess(::DWORD& OutProcessID, FS { UE_LOG(LogVSAccessor, Warning, TEXT("Couldn't access module information")); AccessResult = EAccessVisualStudioResult::VSInstanceUnknown; + } } } - } else { UE_LOG(LogVSAccessor, Warning, TEXT("Couldn't access module table")); diff --git a/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/AssetManagerEditor.Build.cs b/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/AssetManagerEditor.Build.cs index c67a06ac938f..540c0c866e8e 100644 --- a/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/AssetManagerEditor.Build.cs +++ b/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/AssetManagerEditor.Build.cs @@ -11,8 +11,8 @@ public class AssetManagerEditor : ModuleRules "Core", "CoreUObject", "Engine", - "TargetPlatform" - } + "TargetPlatform" + } ); PrivateDependencyModuleNames.AddRange( @@ -29,9 +29,11 @@ public class AssetManagerEditor : ModuleRules "EditorStyle", "AssetTools", "PropertyEditor", - "GraphEditor", - "ReferenceViewer", - "SandboxFile" + "GraphEditor", + "BlueprintGraph", + "KismetCompiler", + "ReferenceViewer", + "SandboxFile" } ); } diff --git a/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/Private/AssetManagerEditorModule.cpp b/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/Private/AssetManagerEditorModule.cpp index 8c1b9c1fb1a2..3ee940e32d73 100644 --- a/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/Private/AssetManagerEditorModule.cpp +++ b/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/Private/AssetManagerEditorModule.cpp @@ -42,6 +42,9 @@ #include "IPlatformFileSandboxWrapper.h" #include "HAL/PlatformFilemanager.h" #include "Serialization/ArrayReader.h" +#include "EdGraphUtilities.h" +#include "EdGraphSchema_K2.h" +#include "SGraphPin.h" #define LOCTEXT_NAMESPACE "AssetManagerEditor" @@ -49,6 +52,24 @@ DEFINE_LOG_CATEGORY(LogAssetManagerEditor); // Static functions/variables defeined in the interface +class FAssetManagerGraphPanelPinFactory : public FGraphPanelPinFactory +{ + virtual TSharedPtr CreatePin(class UEdGraphPin* InPin) const override + { + const UEdGraphSchema_K2* K2Schema = GetDefault(); + if (InPin->PinType.PinCategory == K2Schema->PC_Struct && InPin->PinType.PinSubCategoryObject == TBaseStructure::Get()) + { + return SNew(SPrimaryAssetIdGraphPin, InPin); + } + if (InPin->PinType.PinCategory == K2Schema->PC_Struct && InPin->PinType.PinSubCategoryObject == TBaseStructure::Get()) + { + return SNew(SPrimaryAssetTypeGraphPin, InPin); + } + + return nullptr; + } +}; + const FName IAssetManagerEditorModule::ResourceSizeName = FName("ResourceSize"); const FName IAssetManagerEditorModule::DiskSizeName = FName("DiskSize"); const FName IAssetManagerEditorModule::ManagedResourceSizeName = FName("ManagedResourceSize"); @@ -74,37 +95,41 @@ TSharedRef IAssetManagerEditorModule::MakePrimaryAssetTypeSelector(FOnG TSharedRef IAssetManagerEditorModule::MakePrimaryAssetIdSelector(FOnGetPrimaryAssetDisplayText OnGetDisplayText, FOnSetPrimaryAssetId OnSetId, bool bAllowClear, TArray AllowedTypes) { - FOnShouldFilterAsset AssetFilter = FOnShouldFilterAsset::CreateStatic(&IAssetManagerEditorModule::OnShouldFilterPrimaryAsset, AllowedTypes); - TAttribute OnGetObjectText = TAttribute::Create(OnGetDisplayText); - FOnSetObject OnSetObject = FOnSetObject::CreateLambda([OnSetId](const FAssetData& AssetData) + FOnGetContent OnCreateMenuContent = FOnGetContent::CreateLambda([OnGetDisplayText, OnSetId, bAllowClear, AllowedTypes]() { - UAssetManager& Manager = UAssetManager::Get(); - - FPrimaryAssetId AssetId; - if (AssetData.IsValid()) + FOnShouldFilterAsset AssetFilter = FOnShouldFilterAsset::CreateStatic(&IAssetManagerEditorModule::OnShouldFilterPrimaryAsset, AllowedTypes); + FOnSetObject OnSetObject = FOnSetObject::CreateLambda([OnSetId](const FAssetData& AssetData) { - AssetId = Manager.GetPrimaryAssetIdFromData(AssetData); - ensure(AssetId.IsValid()); - } + FSlateApplication::Get().DismissAllMenus(); + UAssetManager& Manager = UAssetManager::Get(); - OnSetId.Execute(AssetId); - }); + FPrimaryAssetId AssetId; + if (AssetData.IsValid()) + { + AssetId = Manager.GetPrimaryAssetIdForData(AssetData); + ensure(AssetId.IsValid()); + } - TArray AllowedClasses; - TArray NewAssetFactories; + OnSetId.Execute(AssetId); + }); - return SNew(SComboButton) - .MenuContent() - [ - PropertyCustomizationHelpers::MakeAssetPickerWithMenu( + TArray AllowedClasses; + TArray NewAssetFactories; + + return PropertyCustomizationHelpers::MakeAssetPickerWithMenu( FAssetData(), bAllowClear, AllowedClasses, NewAssetFactories, AssetFilter, OnSetObject, - FSimpleDelegate()) - ] + FSimpleDelegate()); + }); + + TAttribute OnGetObjectText = TAttribute::Create(OnGetDisplayText); + + return SNew(SComboButton) + .OnGetMenuContent(OnCreateMenuContent) .ButtonContent() [ SNew(STextBlock) @@ -151,7 +176,7 @@ bool IAssetManagerEditorModule::OnShouldFilterPrimaryAsset(const FAssetData& InA if (InAssetData.IsValid()) { - FPrimaryAssetId AssetId = Manager.GetPrimaryAssetIdFromData(InAssetData); + FPrimaryAssetId AssetId = Manager.GetPrimaryAssetIdForData(InAssetData); if (AssetId.IsValid()) { if (AllowedTypes.Num() > 0) @@ -287,6 +312,10 @@ void FAssetManagerEditorModule::StartupModule() PropertyModule.RegisterCustomPropertyTypeLayout("PrimaryAssetId", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FPrimaryAssetIdCustomization::MakeInstance)); PropertyModule.NotifyCustomizationModuleChanged(); + // Register Pins + TSharedPtr AssetManagerGraphPanelPinFactory = MakeShareable(new FAssetManagerGraphPanelPinFactory()); + FEdGraphUtilities::RegisterVisualPinFactory(AssetManagerGraphPanelPinFactory); + // Register content browser hook FContentBrowserModule& ContentBrowserModule = FModuleManager::LoadModuleChecked(TEXT("ContentBrowser")); TArray& CBMenuExtenderDelegates = ContentBrowserModule.GetAllAssetViewContextMenuExtenders(); @@ -471,7 +500,7 @@ FString FAssetManagerEditorModule::GetValueForCustomColumn(FAssetData& AssetData { FName SizeTag = (ColumnName == ManagedResourceSizeName) ? ResourceSizeName : DiskSizeName; - FPrimaryAssetId PrimaryAssetId = AssetManager.GetPrimaryAssetIdFromData(AssetData); + FPrimaryAssetId PrimaryAssetId = AssetManager.GetPrimaryAssetIdForData(AssetData); if (!PrimaryAssetId.IsValid()) { @@ -519,9 +548,9 @@ FString FAssetManagerEditorModule::GetValueForCustomColumn(FAssetData& AssetData { int64 TotalWeight = 0; - TArray ReferencingPrimaryAssets; + TSet ReferencingPrimaryAssets; - AssetManager.GetPackageManagerList(AssetData.PackageName, false, ReferencingPrimaryAssets); + AssetManager.GetPackageManagers(AssetData.PackageName, false, ReferencingPrimaryAssets); for (const FPrimaryAssetId& PrimaryAssetId : ReferencingPrimaryAssets) { diff --git a/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/Private/PrimaryAssetIdCustomization.cpp b/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/Private/PrimaryAssetIdCustomization.cpp index a4cdbaeaa1d8..f97172c98934 100644 --- a/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/Private/PrimaryAssetIdCustomization.cpp +++ b/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/Private/PrimaryAssetIdCustomization.cpp @@ -99,7 +99,7 @@ void FPrimaryAssetIdCustomization::OnSetObject(const FAssetData& AssetData) FPrimaryAssetId AssetId; if (AssetData.IsValid()) { - AssetId = Manager.GetPrimaryAssetIdFromData(AssetData); + AssetId = Manager.GetPrimaryAssetIdForData(AssetData); ensure(AssetId.IsValid()); } @@ -107,4 +107,38 @@ void FPrimaryAssetIdCustomization::OnSetObject(const FAssetData& AssetData) } } +void SPrimaryAssetIdGraphPin::Construct(const FArguments& InArgs, UEdGraphPin* InGraphPinObj) +{ + SGraphPin::Construct(SGraphPin::FArguments(), InGraphPinObj); +} + +TSharedRef SPrimaryAssetIdGraphPin::GetDefaultValueWidget() +{ + FString DefaultString = GraphPinObj->GetDefaultAsString(); + CurrentId = FPrimaryAssetId(DefaultString); + + return SNew(SVerticalBox) + .Visibility(this, &SGraphPin::GetDefaultValueVisibility) + + SVerticalBox::Slot() + .AutoHeight() + [ + IAssetManagerEditorModule::MakePrimaryAssetIdSelector( + FOnGetPrimaryAssetDisplayText::CreateSP(this, &SPrimaryAssetIdGraphPin::GetDisplayText), + FOnSetPrimaryAssetId::CreateSP(this, &SPrimaryAssetIdGraphPin::OnIdSelected), + true) + ]; +} + +void SPrimaryAssetIdGraphPin::OnIdSelected(FPrimaryAssetId AssetId) +{ + CurrentId = AssetId; + GraphPinObj->GetSchema()->TrySetDefaultValue(*GraphPinObj, CurrentId.ToString()); +} + +FText SPrimaryAssetIdGraphPin::GetDisplayText() const +{ + return FText::AsCultureInvariant(CurrentId.ToString()); +} + + #undef LOCTEXT_NAMESPACE diff --git a/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/Private/PrimaryAssetIdCustomization.h b/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/Private/PrimaryAssetIdCustomization.h index b6a66d076faa..0e3d103e9184 100644 --- a/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/Private/PrimaryAssetIdCustomization.h +++ b/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/Private/PrimaryAssetIdCustomization.h @@ -5,6 +5,7 @@ #include "CoreMinimal.h" #include "Widgets/SWidget.h" #include "Editor/PropertyEditor/Public/IPropertyTypeCustomization.h" +#include "SGraphPin.h" class IPropertyHandle; @@ -33,3 +34,23 @@ private: TArray AllowedTypes; }; +/** Graph pin version of UI */ +class SPrimaryAssetIdGraphPin : public SGraphPin +{ +public: + SLATE_BEGIN_ARGS(SPrimaryAssetIdGraphPin) {} + SLATE_END_ARGS() + + void Construct(const FArguments& InArgs, UEdGraphPin* InGraphPinObj); + + //~ Begin SGraphPin Interface + virtual TSharedRef GetDefaultValueWidget() override; + //~ End SGraphPin Interface + +private: + + void OnIdSelected(FPrimaryAssetId AssetId); + FText GetDisplayText() const; + + FPrimaryAssetId CurrentId; +}; \ No newline at end of file diff --git a/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/Private/PrimaryAssetTypeCustomization.cpp b/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/Private/PrimaryAssetTypeCustomization.cpp index 1803f6eacf89..141702b3c8dd 100644 --- a/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/Private/PrimaryAssetTypeCustomization.cpp +++ b/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/Private/PrimaryAssetTypeCustomization.cpp @@ -47,5 +47,37 @@ void FPrimaryAssetTypeCustomization::CustomizeHeader(TSharedRef SPrimaryAssetTypeGraphPin::GetDefaultValueWidget() +{ + FString DefaultString = GraphPinObj->GetDefaultAsString(); + CurrentType = FPrimaryAssetType(*DefaultString); + + return SNew(SVerticalBox) + .Visibility(this, &SGraphPin::GetDefaultValueVisibility) + + SVerticalBox::Slot() + .AutoHeight() + [ + IAssetManagerEditorModule::MakePrimaryAssetTypeSelector( + FOnGetPrimaryAssetDisplayText::CreateSP(this, &SPrimaryAssetTypeGraphPin::GetDisplayText), + FOnSetPrimaryAssetType::CreateSP(this, &SPrimaryAssetTypeGraphPin::OnTypeSelected), + true) + ]; +} + +void SPrimaryAssetTypeGraphPin::OnTypeSelected(FPrimaryAssetType AssetType) +{ + CurrentType = AssetType; + GraphPinObj->GetSchema()->TrySetDefaultValue(*GraphPinObj, CurrentType.ToString()); +} + +FText SPrimaryAssetTypeGraphPin::GetDisplayText() const +{ + return FText::AsCultureInvariant(CurrentType.ToString()); +} #undef LOCTEXT_NAMESPACE diff --git a/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/Private/PrimaryAssetTypeCustomization.h b/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/Private/PrimaryAssetTypeCustomization.h index da3ab726fb2f..2023fda237e3 100644 --- a/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/Private/PrimaryAssetTypeCustomization.h +++ b/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/Private/PrimaryAssetTypeCustomization.h @@ -5,6 +5,7 @@ #include "CoreMinimal.h" #include "Widgets/SWidget.h" #include "Editor/PropertyEditor/Public/IPropertyTypeCustomization.h" +#include "SGraphPin.h" class IPropertyHandle; @@ -31,3 +32,23 @@ private: }; +/** Graph pin version of UI */ +class SPrimaryAssetTypeGraphPin : public SGraphPin +{ +public: + SLATE_BEGIN_ARGS(SPrimaryAssetTypeGraphPin) {} + SLATE_END_ARGS() + + void Construct(const FArguments& InArgs, UEdGraphPin* InGraphPinObj); + + //~ Begin SGraphPin Interface + virtual TSharedRef GetDefaultValueWidget() override; + //~ End SGraphPin Interface + +private: + + void OnTypeSelected(FPrimaryAssetType AssetType); + FText GetDisplayText() const; + + FPrimaryAssetType CurrentType; +}; \ No newline at end of file diff --git a/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/Private/SAssetAuditBrowser.cpp b/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/Private/SAssetAuditBrowser.cpp index 4dc8468f76d2..086b5cf20046 100644 --- a/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/Private/SAssetAuditBrowser.cpp +++ b/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/Private/SAssetAuditBrowser.cpp @@ -255,7 +255,8 @@ void SAssetAuditBrowser::Construct(const FArguments& InArgs) Config.HiddenColumnNames.Add(TEXT("Path")); // Add custom columns - Config.CustomColumns.Emplace(FPrimaryAssetId::PrimaryAssetTypeTag, LOCTEXT("AssetType", "Asset Type"), LOCTEXT("AssetTypeTooltip", "Primary Asset Type of this asset"), UObject::FAssetRegistryTag::TT_Numerical, FOnGetCustomAssetColumnData::CreateSP(this, &SAssetAuditBrowser::GetValueForCustomColumn)); + Config.CustomColumns.Emplace(FPrimaryAssetId::PrimaryAssetTypeTag, LOCTEXT("AssetType", "Primary Type"), LOCTEXT("AssetTypeTooltip", "Primary Asset Type of this asset, if set"), UObject::FAssetRegistryTag::TT_Alphabetical, FOnGetCustomAssetColumnData::CreateSP(this, &SAssetAuditBrowser::GetValueForCustomColumn)); + Config.CustomColumns.Emplace(FPrimaryAssetId::PrimaryAssetNameTag, LOCTEXT("AssetName", "Primary Name"), LOCTEXT("AssetNameTooltip", "Primary Asset Name of this asset, if set"), UObject::FAssetRegistryTag::TT_Alphabetical, FOnGetCustomAssetColumnData::CreateSP(this, &SAssetAuditBrowser::GetValueForCustomColumn)); Config.CustomColumns.Emplace(IAssetManagerEditorModule::ManagedResourceSizeName, LOCTEXT("ManagedResourceSize", "Memory Kb"), LOCTEXT("ManagedResourceSizeTooltip", "Memory used by both this asset and any other assets it manages, in kilobytes"), UObject::FAssetRegistryTag::TT_Numerical, FOnGetCustomAssetColumnData::CreateSP(this, &SAssetAuditBrowser::GetValueForCustomColumn)); Config.CustomColumns.Emplace(IAssetManagerEditorModule::ResourceSizeName, LOCTEXT("ResourceSize", "Exclusive Memory Kb"), LOCTEXT("ResourceSizeTooltip", "Memory used exclusively by this asset, in kilobytes"), UObject::FAssetRegistryTag::TT_Numerical, FOnGetCustomAssetColumnData::CreateSP(this, &SAssetAuditBrowser::GetValueForCustomColumn)); Config.CustomColumns.Emplace(IAssetManagerEditorModule::ManagedDiskSizeName, LOCTEXT("ManagedDiskSize", "Disk Kb"), LOCTEXT("ManagedDiskSizeTooltip", "Total disk space used by both this and all managed assets, in kilobytes"), UObject::FAssetRegistryTag::TT_Numerical, FOnGetCustomAssetColumnData::CreateSP(this, &SAssetAuditBrowser::GetValueForCustomColumn)); @@ -264,8 +265,11 @@ void SAssetAuditBrowser::Construct(const FArguments& InArgs) Config.CustomColumns.Emplace(IAssetManagerEditorModule::CookRuleName, LOCTEXT("CookRule", "Cook Rule"), LOCTEXT("CookRuleTooltip", "Rather this asset will be cooked or not"), UObject::FAssetRegistryTag::TT_Alphabetical, FOnGetCustomAssetColumnData::CreateSP(this, &SAssetAuditBrowser::GetValueForCustomColumn)); Config.CustomColumns.Emplace(IAssetManagerEditorModule::ChunksName, LOCTEXT("Chunks", "Chunks"), LOCTEXT("ChunksTooltip", "List of chunks this will be added to when cooked"), UObject::FAssetRegistryTag::TT_Alphabetical, FOnGetCustomAssetColumnData::CreateSP(this, &SAssetAuditBrowser::GetValueForCustomColumn)); - // Ignore blueprint tags + // Ignore these tags as we added them as custom columns + AssetRegistryTagsToIgnore.Add(FPrimaryAssetId::PrimaryAssetTypeTag); AssetRegistryTagsToIgnore.Add(FPrimaryAssetId::PrimaryAssetNameTag); + + // Ignore blueprint tags AssetRegistryTagsToIgnore.Add("ParentClass"); AssetRegistryTagsToIgnore.Add("BlueprintType"); AssetRegistryTagsToIgnore.Add("NumReplicatedProperties"); diff --git a/Engine/Plugins/Editor/AudioCapture/AudioCapture.uplugin b/Engine/Plugins/Editor/AudioCapture/AudioCapture.uplugin index 513414884242..271679bc2dee 100644 --- a/Engine/Plugins/Editor/AudioCapture/AudioCapture.uplugin +++ b/Engine/Plugins/Editor/AudioCapture/AudioCapture.uplugin @@ -12,7 +12,7 @@ "SupportURL" : "", "EnabledByDefault" : true, "CanContainContent" : false, - "IsBetaVersion" : true, + "IsBetaVersion" : false, "Installed" : false, "Modules" : [ diff --git a/Engine/Plugins/Editor/AudioCapture/Source/AudioCapture/Private/RtAudio.cpp b/Engine/Plugins/Editor/AudioCapture/Source/AudioCapture/Private/RtAudio.cpp index be394233c6e0..304b126dc03b 100644 --- a/Engine/Plugins/Editor/AudioCapture/Source/AudioCapture/Private/RtAudio.cpp +++ b/Engine/Plugins/Editor/AudioCapture/Source/AudioCapture/Private/RtAudio.cpp @@ -3170,7 +3170,7 @@ bool RtApiAsio::probeDeviceOpen(unsigned int device, StreamMode mode, unsigned i if (result != ASE_OK) { // Standard method failed. This can happen with strict/misbehaving drivers that return valid buffer size ranges // but only accept the preferred buffer size as parameter for ASIOCreateBuffers. eg. Creatives ASIO driver - // in that case, let's be nave and try that instead + // in that case, let's be naive and try that instead *bufferSize = preferSize; stream_.bufferSize = *bufferSize; result = ASIOCreateBuffers(handle->bufferInfos, nChannels, stream_.bufferSize, &asioCallbacks); diff --git a/Engine/Plugins/Editor/EpicSurvey/EpicSurvey.uplugin b/Engine/Plugins/Editor/EpicSurvey/EpicSurvey.uplugin index 60c5aab0680c..1edce8d097c0 100644 --- a/Engine/Plugins/Editor/EpicSurvey/EpicSurvey.uplugin +++ b/Engine/Plugins/Editor/EpicSurvey/EpicSurvey.uplugin @@ -21,5 +21,12 @@ "Type" : "Editor", "LoadingPhase" : "Default" } + ], + "Plugins": [ + { + "Name": "OnlineSubsystem", + "Enabled": true + } ] + } \ No newline at end of file diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagContainerCustomization.cpp b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagContainerCustomization.cpp index 6fa66dce7865..b78302ad55ca 100644 --- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagContainerCustomization.cpp +++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagContainerCustomization.cpp @@ -10,6 +10,7 @@ #include "PropertyHandle.h" #include "DetailWidgetRow.h" #include "ScopedTransaction.h" +#include "SHyperlink.h" #define LOCTEXT_NAMESPACE "GameplayTagContainerCustomization" @@ -116,10 +117,27 @@ void FGameplayTagContainerCustomization::RefreshTagList() TSharedRef FGameplayTagContainerCustomization::MakeListViewWidget(TSharedPtr Item, const TSharedRef& OwnerTable) { + if (UGameplayTagsManager::Get().ShowGameplayTagAsHyperLinkEditor(*Item.Get())) + { + return SNew( STableRow< TSharedPtr >, OwnerTable ) + [ + SNew(SHyperlink) + .Text( FText::FromString(*Item.Get()) ) + .OnNavigate( this, &FGameplayTagContainerCustomization::OnTagDoubleClicked, *Item.Get() ) + ]; + + } + + return SNew( STableRow< TSharedPtr >, OwnerTable ) - [ - SNew(STextBlock) .Text( FText::FromString(*Item.Get()) ) - ]; + [ + SNew(STextBlock) .Text( FText::FromString(*Item.Get()) ) + ]; +} + +void FGameplayTagContainerCustomization::OnTagDoubleClicked(FString TagName) +{ + UGameplayTagsManager::Get().NotifyGameplayTagDoubleClickedEditor(TagName); } TSharedRef FGameplayTagContainerCustomization::GetListContent() @@ -129,22 +147,7 @@ TSharedRef FGameplayTagContainerCustomization::GetListContent() return SNullWidget::NullWidget; } - FString Categories; - { - TSharedPtr PropertyHandle = StructPropertyHandle; - while(PropertyHandle.IsValid()) - { - if (PropertyHandle->GetProperty() != nullptr) - { - if (PropertyHandle->GetProperty()->HasMetaData( TEXT("Categories") )) - { - Categories = PropertyHandle->GetProperty()->GetMetaData( TEXT("Categories") ); - break; - } - } - PropertyHandle = PropertyHandle->GetParentHandle(); - } - } + FString Categories = UGameplayTagsManager::Get().GetCategoriesMetaFromPropertyHandle(StructPropertyHandle); TArray OuterObjects; StructPropertyHandle->GetOuterObjects(OuterObjects); diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagContainerCustomization.h b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagContainerCustomization.h index 95b309876bf1..56d6d21eb444 100644 --- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagContainerCustomization.h +++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagContainerCustomization.h @@ -72,5 +72,7 @@ private: /** The TagList, kept as a member so we can update it later */ TSharedPtr>> TagListView; + + void OnTagDoubleClicked(FString TagName); }; diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagCustomization.cpp b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagCustomization.cpp index c75ec1d7f89e..fc291db4ea58 100644 --- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagCustomization.cpp +++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagCustomization.cpp @@ -6,9 +6,16 @@ #include "Editor.h" #include "PropertyHandle.h" #include "DetailWidgetRow.h" +#include "GameplayTagsEditorModule.h" +#include "SHyperlink.h" #define LOCTEXT_NAMESPACE "GameplayTagCustomization" +TSharedRef FGameplayTagCustomizationPublic::MakeInstance() +{ + return MakeShareable(new FGameplayTagCustomization); +} + void FGameplayTagCustomization::CustomizeHeader(TSharedRef InStructPropertyHandle, class FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils) { TagContainer = MakeShareable(new FGameplayTagContainer); @@ -41,41 +48,51 @@ void FGameplayTagCustomization::CustomizeHeader(TSharedRefRegisterForUndo(this); } +void FGameplayTagCustomization::OnTagDoubleClicked() +{ + UGameplayTagsManager::Get().NotifyGameplayTagDoubleClickedEditor(TagName); +} + +EVisibility FGameplayTagCustomization::GetVisibilityForTagTextBlockWidget(bool ForTextWidget) const +{ + return (UGameplayTagsManager::Get().ShowGameplayTagAsHyperLinkEditor(TagName) ^ ForTextWidget) ? EVisibility::Visible : EVisibility::Collapsed; +} + TSharedRef FGameplayTagCustomization::GetListContent() { BuildEditableContainerList(); - FString Categories; - { - TSharedPtr PropertyHandle = StructPropertyHandle; - while(PropertyHandle.IsValid()) - { - if (PropertyHandle->GetProperty()) - { - if (PropertyHandle->GetProperty()->HasMetaData( TEXT("Categories") )) - { - Categories = PropertyHandle->GetProperty()->GetMetaData( TEXT("Categories") ); - break; - } - } - PropertyHandle = PropertyHandle->GetParentHandle(); - } - } + FString Categories = UGameplayTagsManager::Get().GetCategoriesMetaFromPropertyHandle(StructPropertyHandle); bool bReadOnly = StructPropertyHandle->GetProperty()->HasAnyPropertyFlags(CPF_EditConst); diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagCustomization.h b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagCustomization.h index 5f6dd11e8d1b..69b0ceabc7b8 100644 --- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagCustomization.h +++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagCustomization.h @@ -14,10 +14,6 @@ class IPropertyHandle; class FGameplayTagCustomization : public IPropertyTypeCustomization, public FEditorUndoClient { public: - static TSharedRef MakeInstance() - { - return MakeShareable(new FGameplayTagCustomization); - } ~FGameplayTagCustomization(); @@ -60,5 +56,8 @@ private: /** Tag name selected*/ FString TagName; + + void OnTagDoubleClicked(); + EVisibility GetVisibilityForTagTextBlockWidget(bool ForTextWidget) const; }; diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagQueryCustomization.cpp b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagQueryCustomization.cpp index ed7e527e3d02..433cc9749475 100644 --- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagQueryCustomization.cpp +++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagQueryCustomization.cpp @@ -13,6 +13,9 @@ #include "Editor.h" #include "PropertyHandle.h" #include "DetailWidgetRow.h" +#include "IPropertyTypeCustomization.h" +#include "IPropertyUtilities.h" +#include "NotifyHook.h" #define LOCTEXT_NAMESPACE "GameplayTagQueryCustomization" @@ -20,7 +23,9 @@ void FGameplayTagQueryCustomization::CustomizeHeader(TSharedRefGetProperty() ? StructPropertyHandle->GetProperty()->HasAnyPropertyFlags(CPF_EditConst) : false; @@ -182,8 +187,8 @@ FReply FGameplayTagQueryCustomization::OnEditButtonClicked() .ClientSize(FVector2D(600, 400)) [ SNew(SGameplayTagQueryWidget, EditableQueries) - .OnSaveAndClose(this, &FGameplayTagQueryCustomization::CloseWidgetWindow) - .OnCancel(this, &FGameplayTagQueryCustomization::CloseWidgetWindow) + .OnSaveAndClose(this, &FGameplayTagQueryCustomization::CloseWidgetWindow, false) + .OnCancel(this, &FGameplayTagQueryCustomization::CloseWidgetWindow, true) .ReadOnly(bReadOnly) ]; @@ -220,16 +225,33 @@ void FGameplayTagQueryCustomization::BuildEditableQueryList() TArray OuterObjects; StructPropertyHandle->GetOuterObjects(OuterObjects); + for (int32 Idx = 0; Idx < RawStructData.Num(); ++Idx) { - EditableQueries.Add(SGameplayTagQueryWidget::FEditableGameplayTagQueryDatum(OuterObjects.IsValidIndex(Idx) ? OuterObjects[Idx] : nullptr, (FGameplayTagQuery*)RawStructData[Idx])); + // Null outer objects may mean that we are inside a UDataTable. This is ok though. We can still dirty the data table via FNotify Hook. (see ::CloseWidgetWindow). However undo will not work. + UObject* Obj = OuterObjects.IsValidIndex(Idx) ? OuterObjects[Idx] : nullptr; + EditableQueries.Add(SGameplayTagQueryWidget::FEditableGameplayTagQueryDatum(Obj, (FGameplayTagQuery*)RawStructData[Idx])); } } } -void FGameplayTagQueryCustomization::CloseWidgetWindow() +void FGameplayTagQueryCustomization::CloseWidgetWindow(bool WasCancelled) { + // Notify change. This is required for these to work inside of UDataTables + if (!WasCancelled && PropertyUtilities.IsValid()) + { + UProperty* TheProperty = StructPropertyHandle->GetProperty(); + + FEditPropertyChain PropertyChain; + PropertyChain.AddHead(TheProperty); + PropertyChain.SetActivePropertyNode(TheProperty); + + FPropertyChangedEvent ChangeEvent(StructPropertyHandle->GetProperty(), EPropertyChangeType::ValueSet, nullptr); + FNotifyHook* NotifyHook = PropertyUtilities->GetNotifyHook(); + NotifyHook->NotifyPostChange(ChangeEvent, &PropertyChain); + } + if( GameplayTagQueryWidgetWindow.IsValid() ) { GameplayTagQueryWidgetWindow->RequestDestroyWindow(); diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagQueryCustomization.h b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagQueryCustomization.h index 499e21822ccd..99ede310591f 100644 --- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagQueryCustomization.h +++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagQueryCustomization.h @@ -48,7 +48,7 @@ private: FText GetQueryDescText() const; - void CloseWidgetWindow(); + void CloseWidgetWindow(bool WasCancelled); /** Build List of Editable Queries */ void BuildEditableQueryList(); @@ -63,5 +63,7 @@ private: TSharedPtr GameplayTagQueryWidgetWindow; FString QueryDescription; + + TSharedPtr PropertyUtilities; }; diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagReferenceHelperDetails.cpp b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagReferenceHelperDetails.cpp index d856141e98fb..bea7f1590842 100644 --- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagReferenceHelperDetails.cpp +++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagReferenceHelperDetails.cpp @@ -8,6 +8,9 @@ #include "GameplayTagContainer.h" #include "UObjectHash.h" #include "UnrealType.h" +#include "GameplayTagsManager.h" +#include "SGameplayTagWidget.h" +#include "IDetailChildrenBuilder.h" #define LOCTEXT_NAMESPACE "GameplayTagReferenceHelperDetails" @@ -193,4 +196,40 @@ TSharedRef FGameplayTagReferenceHelperDetails::OnGenerateWidgetForGam } } +// -------------------------------------------------------------------------------------- + +TSharedRef FGameplayTagCreationWidgetHelperDetails::MakeInstance() +{ + return MakeShareable(new FGameplayTagCreationWidgetHelperDetails()); +} + +void FGameplayTagCreationWidgetHelperDetails::CustomizeHeader( TSharedRef StructPropertyHandle, class FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils ) +{ + +} + +void FGameplayTagCreationWidgetHelperDetails::CustomizeChildren( TSharedRef StructPropertyHandle, class IDetailChildrenBuilder& StructBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils ) +{ + FString FilterString = UGameplayTagsManager::Get().GetCategoriesMetaFromPropertyHandle(StructPropertyHandle); + const float MaxPropertyWidth = 480.0f; + const float MaxPropertyHeight = 240.0f; + + StructBuilder.AddChildContent( LOCTEXT("NewTag", "NewTag") ) + .ValueContent() + .MaxDesiredWidth(MaxPropertyWidth) + [ + SAssignNew(TagWidget, SGameplayTagWidget, TArray()) + .Filter(FilterString) + .NewTagName(FilterString) + .MultiSelect(false) + .GameplayTagUIMode(EGameplayTagUIMode::ManagementMode) + .MaxHeight(MaxPropertyHeight) + .NewTagControlsInitiallyExpanded(true) + //.OnTagChanged(this, &FGameplayTagsSettingsCustomization::OnTagChanged) + ]; + +} + + + #undef LOCTEXT_NAMESPACE \ No newline at end of file diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagReferenceHelperDetails.h b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagReferenceHelperDetails.h index d2f4defce53b..74c1bcb75157 100644 --- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagReferenceHelperDetails.h +++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagReferenceHelperDetails.h @@ -45,4 +45,15 @@ private: TSharedPtr PropertyHandle; struct FGameplayTagReferenceHelper* GetValue(); +}; + +class FGameplayTagCreationWidgetHelperDetails : public IPropertyTypeCustomization +{ +public: + static TSharedRef MakeInstance(); + + /** IPropertyTypeCustomization interface */ + virtual void CustomizeHeader( TSharedRef StructPropertyHandle, class FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils ) override; + virtual void CustomizeChildren( TSharedRef StructPropertyHandle, class IDetailChildrenBuilder& StructBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils ) override; + TSharedPtr TagWidget; }; \ No newline at end of file diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsEditorModule.cpp b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsEditorModule.cpp index ca6a21319efa..b2be9a91f1b5 100644 --- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsEditorModule.cpp +++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsEditorModule.cpp @@ -46,12 +46,13 @@ public: { FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked("PropertyEditor"); PropertyModule.RegisterCustomPropertyTypeLayout("GameplayTagContainer", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FGameplayTagContainerCustomization::MakeInstance)); - PropertyModule.RegisterCustomPropertyTypeLayout("GameplayTag", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FGameplayTagCustomization::MakeInstance)); + PropertyModule.RegisterCustomPropertyTypeLayout("GameplayTag", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FGameplayTagCustomizationPublic::MakeInstance)); PropertyModule.RegisterCustomPropertyTypeLayout("GameplayTagQuery", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FGameplayTagQueryCustomization::MakeInstance)); PropertyModule.RegisterCustomClassLayout(UGameplayTagsList::StaticClass()->GetFName(), FOnGetDetailCustomizationInstance::CreateStatic(&FGameplayTagsSettingsCustomization::MakeInstance)); PropertyModule.RegisterCustomPropertyTypeLayout("GameplayTagReferenceHelper", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FGameplayTagReferenceHelperDetails::MakeInstance)); + PropertyModule.RegisterCustomPropertyTypeLayout("GameplayTagCreationWidgetHelper", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FGameplayTagCreationWidgetHelperDetails::MakeInstance)); PropertyModule.NotifyCustomizationModuleChanged(); } diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsK2Node_LiteralGameplayTag.cpp b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsK2Node_LiteralGameplayTag.cpp index 5853c22f62b9..5afc7b10d2cf 100644 --- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsK2Node_LiteralGameplayTag.cpp +++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsK2Node_LiteralGameplayTag.cpp @@ -23,8 +23,8 @@ void UGameplayTagsK2Node_LiteralGameplayTag::AllocateDefaultPins() { const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Input, K2Schema->PC_String, TEXT("LiteralGameplayTagContainer"), NULL, false, false, TEXT("TagIn")); - CreatePin(EGPD_Output, K2Schema->PC_Struct, TEXT(""), FGameplayTagContainer::StaticStruct(), false, false, K2Schema->PN_ReturnValue); + CreatePin(EGPD_Input, K2Schema->PC_String, TEXT("LiteralGameplayTagContainer"), nullptr, TEXT("TagIn")); + CreatePin(EGPD_Output, K2Schema->PC_Struct, FString(), FGameplayTagContainer::StaticStruct(), K2Schema->PN_ReturnValue); } FLinearColor UGameplayTagsK2Node_LiteralGameplayTag::GetNodeTitleColor() const diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsK2Node_MultiCompareGameplayTagAssetInterface.cpp b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsK2Node_MultiCompareGameplayTagAssetInterface.cpp index 405bd428b598..31c634782fdc 100644 --- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsK2Node_MultiCompareGameplayTagAssetInterface.cpp +++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsK2Node_MultiCompareGameplayTagAssetInterface.cpp @@ -25,7 +25,7 @@ void UGameplayTagsK2Node_MultiCompareGameplayTagAssetInterface::AllocateDefaultP } const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Input, K2Schema->PC_Interface, TEXT(""), UGameplayTagAssetInterface::StaticClass(), false, false, TEXT("Gameplay Tag Asset Interface")); + CreatePin(EGPD_Input, K2Schema->PC_Interface, FString(), UGameplayTagAssetInterface::StaticClass(), TEXT("Gameplay Tag Asset Interface")); } void UGameplayTagsK2Node_MultiCompareGameplayTagAssetInterface::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) @@ -103,6 +103,6 @@ void UGameplayTagsK2Node_MultiCompareGameplayTagAssetInterface::AddPinToSwitchNo PinNames.Add(FName(*PinName)); const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Input, K2Schema->PC_Struct, TEXT(""), FGameplayTagContainer::StaticStruct(), false, true, InPin); - CreatePin(EGPD_Output, K2Schema->PC_Boolean, TEXT(""), NULL, false, false, OutPin); + CreatePin(EGPD_Input, K2Schema->PC_Struct, FString(), FGameplayTagContainer::StaticStruct(), InPin, EPinContainerType::None, true); + CreatePin(EGPD_Output, K2Schema->PC_Boolean, FString(), nullptr, OutPin); } diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsK2Node_MultiCompareGameplayTagAssetInterfaceSingleTags.cpp b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsK2Node_MultiCompareGameplayTagAssetInterfaceSingleTags.cpp index b13d4e9d7633..e2f978ab0b66 100644 --- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsK2Node_MultiCompareGameplayTagAssetInterfaceSingleTags.cpp +++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsK2Node_MultiCompareGameplayTagAssetInterfaceSingleTags.cpp @@ -24,7 +24,7 @@ void UGameplayTagsK2Node_MultiCompareGameplayTagAssetInterfaceSingleTags::Alloca } const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Input, K2Schema->PC_Interface, TEXT(""), UGameplayTagAssetInterface::StaticClass(), false, false, TEXT("Gameplay Tag Asset Interface")); + CreatePin(EGPD_Input, K2Schema->PC_Interface, FString(), UGameplayTagAssetInterface::StaticClass(), TEXT("Gameplay Tag Asset Interface")); } void UGameplayTagsK2Node_MultiCompareGameplayTagAssetInterfaceSingleTags::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) @@ -104,6 +104,6 @@ void UGameplayTagsK2Node_MultiCompareGameplayTagAssetInterfaceSingleTags::AddPin PinNames.Add(FName(*PinName)); const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Input, K2Schema->PC_Struct, TEXT(""), FGameplayTag::StaticStruct(), false, true, InPin); - CreatePin(EGPD_Output, K2Schema->PC_Boolean, TEXT(""), NULL, false, false, OutPin); + CreatePin(EGPD_Input, K2Schema->PC_Struct, FString(), FGameplayTag::StaticStruct(), InPin, EPinContainerType::None, true); + CreatePin(EGPD_Output, K2Schema->PC_Boolean, FString(), nullptr, OutPin); } diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsK2Node_MultiCompareGameplayTagContainer.cpp b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsK2Node_MultiCompareGameplayTagContainer.cpp index c78c6ad6d096..a7b90f36eb4e 100644 --- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsK2Node_MultiCompareGameplayTagContainer.cpp +++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsK2Node_MultiCompareGameplayTagContainer.cpp @@ -23,7 +23,7 @@ void UGameplayTagsK2Node_MultiCompareGameplayTagContainer::AllocateDefaultPins() } const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Input, K2Schema->PC_Struct, TEXT(""), FGameplayTagContainer::StaticStruct(), false, true, TEXT("Gameplay Tag Container")); + CreatePin(EGPD_Input, K2Schema->PC_Struct, FString(), FGameplayTagContainer::StaticStruct(), TEXT("Gameplay Tag Container"), EPinContainerType::None, true); } void UGameplayTagsK2Node_MultiCompareGameplayTagContainer::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) @@ -101,6 +101,6 @@ void UGameplayTagsK2Node_MultiCompareGameplayTagContainer::AddPinToSwitchNode() PinNames.Add(FName(*PinName)); const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Input, K2Schema->PC_Struct, TEXT(""), FGameplayTagContainer::StaticStruct(), false, true, InPin); - CreatePin(EGPD_Output, K2Schema->PC_Boolean, TEXT(""), NULL, false, false, OutPin); + CreatePin(EGPD_Input, K2Schema->PC_Struct, FString(), FGameplayTagContainer::StaticStruct(), InPin, EPinContainerType::None, true); + CreatePin(EGPD_Output, K2Schema->PC_Boolean, FString(), nullptr, OutPin); } diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsK2Node_MultiCompareGameplayTagContainerSingleTags.cpp b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsK2Node_MultiCompareGameplayTagContainerSingleTags.cpp index e24ba36bde1b..479f7b6ee96f 100644 --- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsK2Node_MultiCompareGameplayTagContainerSingleTags.cpp +++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsK2Node_MultiCompareGameplayTagContainerSingleTags.cpp @@ -23,7 +23,7 @@ void UGameplayTagsK2Node_MultiCompareGameplayTagContainerSingleTags::AllocateDef } const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Input, K2Schema->PC_Struct, TEXT(""), FGameplayTagContainer::StaticStruct(), false, true, TEXT("Gameplay Tag Container")); + CreatePin(EGPD_Input, K2Schema->PC_Struct, FString(), FGameplayTagContainer::StaticStruct(), TEXT("Gameplay Tag Container"), EPinContainerType::None, true); } void UGameplayTagsK2Node_MultiCompareGameplayTagContainerSingleTags::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) @@ -101,6 +101,6 @@ void UGameplayTagsK2Node_MultiCompareGameplayTagContainerSingleTags::AddPinToSwi PinNames.Add(FName(*PinName)); const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Input, K2Schema->PC_Struct, TEXT(""), FGameplayTag::StaticStruct(), false, true, InPin); - CreatePin(EGPD_Output, K2Schema->PC_Boolean, TEXT(""), NULL, false, false, OutPin); + CreatePin(EGPD_Input, K2Schema->PC_Struct, FString(), FGameplayTag::StaticStruct(), InPin, EPinContainerType::None, true); + CreatePin(EGPD_Output, K2Schema->PC_Boolean, FString(), nullptr, OutPin); } diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsK2Node_SwitchGameplayTag.cpp b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsK2Node_SwitchGameplayTag.cpp index e07a29a717f7..f5b33986e80f 100644 --- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsK2Node_SwitchGameplayTag.cpp +++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsK2Node_SwitchGameplayTag.cpp @@ -18,7 +18,7 @@ void UGameplayTagsK2Node_SwitchGameplayTag::CreateFunctionPin() { // Set properties on the function pin const UEdGraphSchema_K2* K2Schema = GetDefault(); - UEdGraphPin* FunctionPin = CreatePin(EGPD_Input, K2Schema->PC_Object, TEXT(""), FunctionClass, false, false, FunctionName.ToString()); + UEdGraphPin* FunctionPin = CreatePin(EGPD_Input, K2Schema->PC_Object, FString(), FunctionClass, FunctionName.ToString()); FunctionPin->bDefaultValueIsReadOnly = true; FunctionPin->bNotConnectable = true; FunctionPin->bHidden = true; @@ -98,8 +98,8 @@ void UGameplayTagsK2Node_SwitchGameplayTag::GetMenuActions(FBlueprintActionDatab void UGameplayTagsK2Node_SwitchGameplayTag::CreateSelectionPin() { const UEdGraphSchema_K2* K2Schema = GetDefault(); - UEdGraphPin* Pin = CreatePin(EGPD_Input, K2Schema->PC_Struct, TEXT(""), FGameplayTag::StaticStruct(), false, false, TEXT("Selection")); - K2Schema->SetPinDefaultValueBasedOnType(Pin); + UEdGraphPin* Pin = CreatePin(EGPD_Input, K2Schema->PC_Struct, FString(), FGameplayTag::StaticStruct(), TEXT("Selection")); + K2Schema->SetPinAutogeneratedDefaultValueBasedOnType(Pin); } FEdGraphPinType UGameplayTagsK2Node_SwitchGameplayTag::GetPinType() const @@ -151,7 +151,7 @@ void UGameplayTagsK2Node_SwitchGameplayTag::CreateCasePins() PinNames[Index] = FName(*GetUniquePinName()); } - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, PinNames[Index].ToString()); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, PinNames[Index].ToString()); } } @@ -176,7 +176,7 @@ void UGameplayTagsK2Node_SwitchGameplayTag::AddPinToSwitchNode() PinNames.Add(FName(*PinName)); const UEdGraphSchema_K2* K2Schema = GetDefault(); - UEdGraphPin* NewPin = CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, PinName); + UEdGraphPin* NewPin = CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, PinName); if (PinTags.Num() < PinNames.Num()) { PinTags.Add(FGameplayTag()); diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsK2Node_SwitchGameplayTagContainer.cpp b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsK2Node_SwitchGameplayTagContainer.cpp index 30e3ad146b2c..4f335f84aad4 100644 --- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsK2Node_SwitchGameplayTagContainer.cpp +++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsK2Node_SwitchGameplayTagContainer.cpp @@ -18,7 +18,7 @@ void UGameplayTagsK2Node_SwitchGameplayTagContainer::CreateFunctionPin() { // Set properties on the function pin const UEdGraphSchema_K2* K2Schema = GetDefault(); - UEdGraphPin* FunctionPin = CreatePin(EGPD_Input, K2Schema->PC_Object, TEXT(""), FunctionClass, false, false, FunctionName.ToString()); + UEdGraphPin* FunctionPin = CreatePin(EGPD_Input, K2Schema->PC_Object, FString(), FunctionClass, FunctionName.ToString()); FunctionPin->bDefaultValueIsReadOnly = true; FunctionPin->bNotConnectable = true; FunctionPin->bHidden = true; @@ -98,8 +98,8 @@ void UGameplayTagsK2Node_SwitchGameplayTagContainer::GetMenuActions(FBlueprintAc void UGameplayTagsK2Node_SwitchGameplayTagContainer::CreateSelectionPin() { const UEdGraphSchema_K2* K2Schema = GetDefault(); - UEdGraphPin* Pin = CreatePin(EGPD_Input, K2Schema->PC_Struct, TEXT(""), FGameplayTagContainer::StaticStruct(), false, false, TEXT("Selection")); - K2Schema->SetPinDefaultValueBasedOnType(Pin); + UEdGraphPin* Pin = CreatePin(EGPD_Input, K2Schema->PC_Struct, FString(), FGameplayTagContainer::StaticStruct(), TEXT("Selection")); + K2Schema->SetPinAutogeneratedDefaultValueBasedOnType(Pin); } FEdGraphPinType UGameplayTagsK2Node_SwitchGameplayTagContainer::GetPinType() const @@ -143,7 +143,7 @@ void UGameplayTagsK2Node_SwitchGameplayTagContainer::CreateCasePins() PinNames[Index] = FName(*GetUniquePinName()); } - UEdGraphPin * NewPin = CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), nullptr, false, false, PinNames[Index].ToString()); + UEdGraphPin * NewPin = CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, PinNames[Index].ToString()); if (PinContainers[Index].IsValid()) { @@ -177,7 +177,7 @@ void UGameplayTagsK2Node_SwitchGameplayTagContainer::AddPinToSwitchNode() PinNames.Add(FName(*PinName)); const UEdGraphSchema_K2* K2Schema = GetDefault(); - UEdGraphPin* NewPin = CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), nullptr, false, false, PinName); + UEdGraphPin* NewPin = CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, PinName); NewPin->PinFriendlyName = FText::FromString(PinName); if (PinContainers.Num() < PinNames.Num()) diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SAddNewGameplayTagWidget.cpp b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SAddNewGameplayTagWidget.cpp index f947c1418b33..831080de7503 100644 --- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SAddNewGameplayTagWidget.cpp +++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SAddNewGameplayTagWidget.cpp @@ -11,6 +11,15 @@ void SAddNewGameplayTagWidget::Construct(const FArguments& InArgs) { + + FText HintText = LOCTEXT("NewTagNameHint", "X.Y.Z"); + DefaultNewName = InArgs._NewTagName; + if (DefaultNewName.IsEmpty() == false) + { + HintText = FText::FromString(DefaultNewName); + } + + bAddingNewTag = false; bShouldGetKeyboardFocus = false; @@ -42,7 +51,7 @@ void SAddNewGameplayTagWidget::Construct(const FArguments& InArgs) [ SAssignNew(TagNameTextBox, SEditableTextBox) .MinDesiredWidth(240.0f) - .HintText(LOCTEXT("NewTagNameHint", "X.Y.Z")) + .HintText(HintText) .OnTextCommitted(this, &SAddNewGameplayTagWidget::OnCommitNewTagName) ] ] @@ -166,7 +175,7 @@ void SAddNewGameplayTagWidget::Reset() void SAddNewGameplayTagWidget::SetTagName(const FText& InName) { - TagNameTextBox->SetText(InName); + TagNameTextBox->SetText(InName.IsEmpty() ? FText::FromString(DefaultNewName) : InName); } void SAddNewGameplayTagWidget::SelectTagSource(const FName& InSource) diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SAddNewGameplayTagWidget.h b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SAddNewGameplayTagWidget.h index d9341ab6d345..623210cbf5d5 100644 --- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SAddNewGameplayTagWidget.h +++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SAddNewGameplayTagWidget.h @@ -19,8 +19,10 @@ public: DECLARE_DELEGATE_ThreeParams( FOnGameplayTagAdded, const FString& /*TagName*/, const FString& /*TagComment*/, const FName& /*TagSource*/); SLATE_BEGIN_ARGS(SAddNewGameplayTagWidget) + : _NewTagName(TEXT("")) {} SLATE_EVENT( FOnGameplayTagAdded, OnGameplayTagAdded ) // Callback for when a new tag is added + SLATE_ARGUMENT( FString, NewTagName ) // String that will initially populate the New Tag Name field SLATE_END_ARGS(); virtual void Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime ) override; @@ -86,4 +88,6 @@ private: /** Tracks if this widget should get keyboard focus */ bool bShouldGetKeyboardFocus; + + FString DefaultNewName; }; diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SGameplayTagGraphPin.cpp b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SGameplayTagGraphPin.cpp index d49c8eb66830..0844107bcfc6 100644 --- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SGameplayTagGraphPin.cpp +++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SGameplayTagGraphPin.cpp @@ -53,10 +53,7 @@ void SGameplayTagGraphPin::ParseDefaultValueData() UFunction* ThisFunction = CallFuncNode->GetTargetFunction(); if (ThisFunction) { - if (ThisFunction->HasMetaData(TEXT("GameplayTagFilter"))) - { - FilterString = ThisFunction->GetMetaData(TEXT("GameplayTagFilter")); - } + FilterString = UGameplayTagsManager::Get().GetCategoriesMetaFromFunction(ThisFunction); } } diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SGameplayTagWidget.cpp b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SGameplayTagWidget.cpp index c1bbcd55aea2..e8a08340bcce 100644 --- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SGameplayTagWidget.cpp +++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SGameplayTagWidget.cpp @@ -49,7 +49,7 @@ void SGameplayTagWidget::Construct(const FArguments& InArgs, const TArray InIte return false; } + auto FilterChildrenCheck_r = ([=]() + { + TArray< TSharedPtr > Children = InItem->GetChildTagNodes(); + for( int32 iChild = 0; iChild < Children.Num(); ++iChild ) + { + if( FilterChildrenCheck( Children[iChild] ) ) + { + return true; + } + } + return false; + }); + + + bool DelegateShouldHide = false; + UGameplayTagsManager::Get().OnFilterGameplayTagChildren.Broadcast(RootFilterString, InItem, DelegateShouldHide); + if (DelegateShouldHide) + { + // The delegate wants to hide, see if any children need to show + return FilterChildrenCheck_r(); + } + if( InItem->GetCompleteTagString().Contains( FilterString ) || FilterString.IsEmpty() ) { return true; } - TArray< TSharedPtr > Children = InItem->GetChildTagNodes(); - - for( int32 iChild = 0; iChild < Children.Num(); ++iChild ) - { - if( FilterChildrenCheck( Children[iChild] ) ) - { - return true; - } - } - - return false; + return FilterChildrenCheck_r(); } TSharedRef SGameplayTagWidget::OnGenerateRow(TSharedPtr InItem, const TSharedRef& OwnerTable) diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SGameplayTagWidget.h b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SGameplayTagWidget.h index 572d296a9c92..2aaee079b371 100644 --- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SGameplayTagWidget.h +++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SGameplayTagWidget.h @@ -35,17 +35,21 @@ public: SLATE_BEGIN_ARGS( SGameplayTagWidget ) : _Filter() + , _NewTagName(TEXT("")) , _ReadOnly( false ) , _TagContainerName( TEXT("") ) , _MultiSelect( true ) + , _NewTagControlsInitiallyExpanded( false ) , _PropertyHandle( NULL ) , _GameplayTagUIMode( EGameplayTagUIMode::SelectionMode ) , _MaxHeight(260.0f) {} SLATE_ARGUMENT( FString, Filter ) // Comma delimited string of tag root names to filter by + SLATE_ARGUMENT( FString, NewTagName ) // String that will initially populate the New Tag Name field SLATE_ARGUMENT( bool, ReadOnly ) // Flag to set if the list is read only SLATE_ARGUMENT( FString, TagContainerName ) // The name that will be used for the settings file SLATE_ARGUMENT( bool, MultiSelect ) // If we can select multiple entries + SLATE_ARGUMENT( bool, NewTagControlsInitiallyExpanded ) // If the create new tag controls are initially expanded SLATE_ARGUMENT( TSharedPtr, PropertyHandle ) SLATE_EVENT( FOnTagChanged, OnTagChanged ) // Called when a tag status changes SLATE_ARGUMENT( EGameplayTagUIMode, GameplayTagUIMode ) // Determines behavior of the menu based on where it's used diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Public/GameplayTagsEditorModule.h b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Public/GameplayTagsEditorModule.h index 9aee17927937..9d9ed739e5dd 100644 --- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Public/GameplayTagsEditorModule.h +++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Public/GameplayTagsEditorModule.h @@ -5,6 +5,7 @@ #include "CoreMinimal.h" #include "Modules/ModuleInterface.h" #include "Modules/ModuleManager.h" +#include "IPropertyTypeCustomization.h" /** @@ -47,3 +48,8 @@ public: }; +/** This is public so that child structs of FGameplayTag can use the details customization */ +struct GAMEPLAYTAGSEDITOR_API FGameplayTagCustomizationPublic +{ + static TSharedRef MakeInstance(); +}; \ No newline at end of file diff --git a/Engine/Plugins/Editor/MeshEditor/Source/MeshEditor/MeshEditorMode.cpp b/Engine/Plugins/Editor/MeshEditor/Source/MeshEditor/MeshEditorMode.cpp index 5998223d288a..5e87f8ced250 100644 --- a/Engine/Plugins/Editor/MeshEditor/Source/MeshEditor/MeshEditorMode.cpp +++ b/Engine/Plugins/Editor/MeshEditor/Source/MeshEditor/MeshEditorMode.cpp @@ -725,13 +725,8 @@ void FMeshEditorMode::Enter() UEditorWorldExtensionCollection* ExtensionCollection = GEditor->GetEditorWorldExtensionsManager()->GetEditorWorldExtensions( GetWorld() ); check( ExtensionCollection != nullptr ); - this->ViewportWorldInteraction = Cast( ExtensionCollection->FindExtension( UViewportWorldInteraction::StaticClass() ) ); - if( ViewportWorldInteraction == nullptr ) - { - ViewportWorldInteraction = NewObject(); - } + this->ViewportWorldInteraction = Cast( ExtensionCollection->AddExtension( UViewportWorldInteraction::StaticClass() ) ); check( ViewportWorldInteraction != nullptr ); - ExtensionCollection->AddExtension( ViewportWorldInteraction ); // Register to find out about viewport interaction events ViewportWorldInteraction->OnViewportInteractionHoverUpdate().AddRaw( this, &FMeshEditorMode::OnViewportInteractionHoverUpdate ); diff --git a/Engine/Plugins/Editor/MobileLauncherProfileWizard/Source/MobileLauncherProfileWizard/Private/AndroidProfileWizard.cpp b/Engine/Plugins/Editor/MobileLauncherProfileWizard/Source/MobileLauncherProfileWizard/Private/AndroidProfileWizard.cpp index e5e4c0065448..18ef66228a22 100644 --- a/Engine/Plugins/Editor/MobileLauncherProfileWizard/Source/MobileLauncherProfileWizard/Private/AndroidProfileWizard.cpp +++ b/Engine/Plugins/Editor/MobileLauncherProfileWizard/Source/MobileLauncherProfileWizard/Private/AndroidProfileWizard.cpp @@ -106,7 +106,7 @@ static void SetupAndroidDLCProfile(ILauncherProfileRef& DLCProfile, const FProfi DLCProfile->SetBasedOnReleaseVersionName(AndroidProfileConstants::AppReleaseName); DLCProfile->SetCreateDLC(true); DLCProfile->SetDLCName(AndroidProfileConstants::DLCName); - DLCProfile->SetDLCIncludeEngineContent(false); + DLCProfile->SetDLCIncludeEngineContent(true); DLCProfile->SetIncrementalCooking(false); DLCProfile->SetCompressed(false); diff --git a/Engine/Plugins/Editor/MobileLauncherProfileWizard/Source/MobileLauncherProfileWizard/Private/IOSProfileWizard.cpp b/Engine/Plugins/Editor/MobileLauncherProfileWizard/Source/MobileLauncherProfileWizard/Private/IOSProfileWizard.cpp index 7d8184210dab..279d18e171b9 100644 --- a/Engine/Plugins/Editor/MobileLauncherProfileWizard/Source/MobileLauncherProfileWizard/Private/IOSProfileWizard.cpp +++ b/Engine/Plugins/Editor/MobileLauncherProfileWizard/Source/MobileLauncherProfileWizard/Private/IOSProfileWizard.cpp @@ -103,7 +103,7 @@ static void SetupIOSDLCProfile(ILauncherProfileRef& DLCProfile, const FProfilePa DLCProfile->SetBasedOnReleaseVersionName(IOSProfileConstants::AppReleaseName); DLCProfile->SetCreateDLC(true); DLCProfile->SetDLCName(IOSProfileConstants::DLCName); - DLCProfile->SetDLCIncludeEngineContent(false); + DLCProfile->SetDLCIncludeEngineContent(true); DLCProfile->SetIncrementalCooking(false); DLCProfile->SetCompressed(false); diff --git a/Engine/Plugins/Editor/PluginBrowser/Source/PluginBrowser/Private/SNewPluginWizard.cpp b/Engine/Plugins/Editor/PluginBrowser/Source/PluginBrowser/Private/SNewPluginWizard.cpp index 2585f64e8194..57b03bc8e8b1 100644 --- a/Engine/Plugins/Editor/PluginBrowser/Source/PluginBrowser/Private/SNewPluginWizard.cpp +++ b/Engine/Plugins/Editor/PluginBrowser/Source/PluginBrowser/Private/SNewPluginWizard.cpp @@ -745,7 +745,7 @@ FReply SNewPluginWizard::OnCreatePluginClicked() if (bSucceeded && bHasModules) { FString ProjectFileName = FPaths::GetProjectFilePath(); - FString Arguments = FString::Printf(TEXT("%sEditor %s %s -EditorRecompile -Module %s -Project=\"%s\" -Progress -NoHotReloadFromIDE"), *FPaths::GetBaseFilename(ProjectFileName), FModuleManager::Get().GetUBTConfiguration(), FPlatformMisc::GetUBTPlatform(), *PluginModuleName, *ProjectFileName); + FString Arguments = FString::Printf(TEXT("%sEditor %s %s -EditorRecompile -Module %s -Project=\"%s\" -Plugin \"%s\" -Progress -NoHotReloadFromIDE"), *FPaths::GetBaseFilename(ProjectFileName), FModuleManager::Get().GetUBTConfiguration(), FPlatformMisc::GetUBTPlatform(), *PluginModuleName, *ProjectFileName, *UPluginFilePath); if (!FDesktopPlatformModule::Get()->RunUnrealBuildTool(LOCTEXT("Compiling", "Compiling..."), FPaths::RootDir(), Arguments, GWarn)) { PopErrorNotification(LOCTEXT("FailedToCompile", "Failed to compile source code.")); diff --git a/Engine/Plugins/Editor/PluginBrowser/Source/PluginBrowser/Private/SPluginBrowser.cpp b/Engine/Plugins/Editor/PluginBrowser/Source/PluginBrowser/Private/SPluginBrowser.cpp index 1d3c86abe07b..4c45bb877ea1 100644 --- a/Engine/Plugins/Editor/PluginBrowser/Source/PluginBrowser/Private/SPluginBrowser.cpp +++ b/Engine/Plugins/Editor/PluginBrowser/Source/PluginBrowser/Private/SPluginBrowser.cpp @@ -82,23 +82,18 @@ void SPluginBrowser::Construct( const FArguments& Args ) const float PaddingAmount = 2.0f; - PluginCategories = SNew( SPluginCategoryTree, SharedThis( this ) ); TSharedRef MainContent = SNew( SVerticalBox ) +SVerticalBox::Slot() [ - SNew( SHorizontalBox ) - - +SHorizontalBox::Slot() - .Padding( PaddingAmount ) - .AutoWidth() // @todo plugedit: Probably want a splitter here (w/ saved layout) + SNew( SSplitter ) + +SSplitter::Slot() + .Value(.3f) [ PluginCategories.ToSharedRef() ] - - +SHorizontalBox::Slot() - .Padding( PaddingAmount ) + +SSplitter::Slot() [ SNew( SVerticalBox ) diff --git a/Engine/Plugins/Editor/PluginBrowser/Source/PluginBrowser/Private/SPluginCategoryTree.cpp b/Engine/Plugins/Editor/PluginBrowser/Source/PluginBrowser/Private/SPluginCategoryTree.cpp index 92e8bfd2615a..c876dcdfb1e5 100644 --- a/Engine/Plugins/Editor/PluginBrowser/Source/PluginBrowser/Private/SPluginCategoryTree.cpp +++ b/Engine/Plugins/Editor/PluginBrowser/Source/PluginBrowser/Private/SPluginCategoryTree.cpp @@ -82,6 +82,11 @@ void SPluginCategoryTree::RebuildAndFilterCategoryTree() TSharedPtr SelectCategory; for(TSharedRef Plugin: IPluginManager::Get().GetDiscoveredPlugins()) { + if (Plugin->IsHidden()) + { + continue; + } + // Figure out which base category this plugin belongs in TSharedPtr RootCategory; if (Plugin->GetDescriptor().bIsMod) diff --git a/Engine/Plugins/Editor/PluginBrowser/Source/PluginBrowser/Private/SPluginTile.cpp b/Engine/Plugins/Editor/PluginBrowser/Source/PluginBrowser/Private/SPluginTile.cpp index 6e7c7dd8458b..f12e3412724b 100644 --- a/Engine/Plugins/Editor/PluginBrowser/Source/PluginBrowser/Private/SPluginTile.cpp +++ b/Engine/Plugins/Editor/PluginBrowser/Source/PluginBrowser/Private/SPluginTile.cpp @@ -415,7 +415,7 @@ ECheckBoxState SPluginTile::IsPluginEnabled() const FPluginBrowserModule& PluginBrowserModule = FPluginBrowserModule::Get(); if(PluginBrowserModule.HasPluginPendingEnable(Plugin->GetName())) { - return PluginBrowserModule.GetPluginPendingEnableState(Plugin->GetName()) ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;; + return PluginBrowserModule.GetPluginPendingEnableState(Plugin->GetName()) ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; } else { @@ -423,26 +423,92 @@ ECheckBoxState SPluginTile::IsPluginEnabled() const } } +void FindPluginDependencies(const FString& Name, TSet& Dependencies, TMap& NameToPlugin) +{ + IPlugin* Plugin = NameToPlugin.FindRef(Name); + if (Plugin != nullptr) + { + for (const FPluginReferenceDescriptor& Reference : Plugin->GetDescriptor().Plugins) + { + if (Reference.bEnabled && !Dependencies.Contains(Reference.Name)) + { + Dependencies.Add(Reference.Name); + FindPluginDependencies(Reference.Name, Dependencies, NameToPlugin); + } + } + } +} + void SPluginTile::OnEnablePluginCheckboxChanged(ECheckBoxState NewCheckedState) { - const bool bNewEnabledState = (NewCheckedState == ECheckBoxState::Checked); + const bool bNewEnabledState = NewCheckedState == ECheckBoxState::Checked; const FPluginDescriptor& PluginDescriptor = Plugin->GetDescriptor(); - if (bNewEnabledState && PluginDescriptor.bIsBetaVersion) - { - FText WarningMessage = FText::Format( - LOCTEXT("Warning_EnablingBetaPlugin", "Plugin '{0}' is a beta version and might be unstable or removed without notice. Please use with caution. Are you sure you want to enable the plugin?"), - FText::FromString(PluginDescriptor.FriendlyName)); - if (EAppReturnType::No == FMessageDialog::Open(EAppMsgType::YesNo, WarningMessage)) + if (bNewEnabledState) + { + // If this is plugin is marked as beta, make sure the user is aware before enabling it. + if (PluginDescriptor.bIsBetaVersion) { - // user chose to keep beta plug-in disabled - return; + FText WarningMessage = FText::Format(LOCTEXT("Warning_EnablingBetaPlugin", "Plugin '{0}' is a beta version and might be unstable or removed without notice. Please use with caution. Are you sure you want to enable the plugin?"), FText::FromString(PluginDescriptor.FriendlyName)); + if (EAppReturnType::No == FMessageDialog::Open(EAppMsgType::YesNo, WarningMessage)) + { + return; + } + } + } + else + { + // Get all the plugins we know about + TArray> EnabledPlugins = IPluginManager::Get().GetEnabledPlugins(); + + // Build a map of plugin by name + TMap NameToPlugin; + for (TSharedRef& EnabledPlugin : EnabledPlugins) + { + NameToPlugin.FindOrAdd(EnabledPlugin->GetName()) = &(EnabledPlugin.Get()); + } + + // Find all the plugins which are dependent on this plugin + TArray DependentPluginNames; + for (TSharedRef& EnabledPlugin : EnabledPlugins) + { + FString EnabledPluginName = EnabledPlugin->GetName(); + + TSet Dependencies; + FindPluginDependencies(EnabledPluginName, Dependencies, NameToPlugin); + + if (Dependencies.Num() > 0 && Dependencies.Contains(Plugin->GetName())) + { + FText Caption = LOCTEXT("DisableDependenciesCaption", "Disable Dependencies"); + FText Message = FText::Format(LOCTEXT("DisableDependenciesMessage", "This plugin is required by {0}. Would you like to disable it as well?"), FText::FromString(EnabledPluginName)); + if (FMessageDialog::Open(EAppMsgType::YesNo, Message, &Caption) == EAppReturnType::No) + { + return; + } + DependentPluginNames.Add(EnabledPluginName); + } + } + + // Disable all the dependent plugins too + for (const FString& DependentPluginName : DependentPluginNames) + { + FText FailureMessage; + if (!IProjectManager::Get().SetPluginEnabled(DependentPluginName, false, FailureMessage, NameToPlugin[DependentPluginName]->GetDescriptor().MarketplaceURL)) + { + FMessageDialog::Open(EAppMsgType::Ok, FailureMessage); + } + + TSharedPtr DependentPlugin = IPluginManager::Get().FindPlugin(DependentPluginName); + if (DependentPlugin.IsValid()) + { + FPluginBrowserModule::Get().SetPluginPendingEnableState(DependentPluginName, DependentPlugin->IsEnabled(), false); + } } } + // Finally, enable the plugin we selected FText FailMessage; - if (!IProjectManager::Get().SetPluginEnabled(Plugin->GetName(), bNewEnabledState, FailMessage, PluginDescriptor.MarketplaceURL)) { FMessageDialog::Open(EAppMsgType::Ok, FailMessage); @@ -460,8 +526,6 @@ void SPluginTile::OnEnablePluginCheckboxChanged(ECheckBoxState NewCheckedState) FPluginBrowserModule::Get().SetPluginPendingEnableState(Plugin->GetName(), Plugin->IsEnabled(), bNewEnabledState); } } - - } EVisibility SPluginTile::GetAuthoringButtonsVisibility() const diff --git a/Engine/Plugins/Editor/PluginBrowser/Templates/Advanced/Source/PLUGIN_NAME/Private/PLUGIN_NAME.cpp b/Engine/Plugins/Editor/PluginBrowser/Templates/Advanced/Source/PLUGIN_NAME/Private/PLUGIN_NAME.cpp index 33821a950ef9..ca6355fefb77 100644 --- a/Engine/Plugins/Editor/PluginBrowser/Templates/Advanced/Source/PLUGIN_NAME/Private/PLUGIN_NAME.cpp +++ b/Engine/Plugins/Editor/PluginBrowser/Templates/Advanced/Source/PLUGIN_NAME/Private/PLUGIN_NAME.cpp @@ -1,14 +1,13 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "PLUGIN_NAME.h" - -#include "SlateBasics.h" -#include "SlateExtras.h" - #include "PLUGIN_NAMEStyle.h" #include "PLUGIN_NAMECommands.h" - #include "LevelEditor.h" +#include "Widgets/Docking/SDockTab.h" +#include "Widgets/Layout/SBox.h" +#include "Widgets/Text/STextBlock.h" +#include "Framework/MultiBox/MultiBoxBuilder.h" static const FName PLUGIN_NAMETabName("PLUGIN_NAME"); diff --git a/Engine/Plugins/Editor/PluginBrowser/Templates/Advanced/Source/PLUGIN_NAME/Public/PLUGIN_NAMECommands.cpp b/Engine/Plugins/Editor/PluginBrowser/Templates/Advanced/Source/PLUGIN_NAME/Private/PLUGIN_NAMECommands.cpp similarity index 93% rename from Engine/Plugins/Editor/PluginBrowser/Templates/Advanced/Source/PLUGIN_NAME/Public/PLUGIN_NAMECommands.cpp rename to Engine/Plugins/Editor/PluginBrowser/Templates/Advanced/Source/PLUGIN_NAME/Private/PLUGIN_NAMECommands.cpp index 8619d3a91ebe..488956764b02 100644 --- a/Engine/Plugins/Editor/PluginBrowser/Templates/Advanced/Source/PLUGIN_NAME/Public/PLUGIN_NAMECommands.cpp +++ b/Engine/Plugins/Editor/PluginBrowser/Templates/Advanced/Source/PLUGIN_NAME/Private/PLUGIN_NAMECommands.cpp @@ -1,7 +1,6 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "PLUGIN_NAMECommands.h" -#include "PLUGIN_NAME.h" #define LOCTEXT_NAMESPACE "FPLUGIN_NAMEModule" diff --git a/Engine/Plugins/Editor/PluginBrowser/Templates/Advanced/Source/PLUGIN_NAME/Private/PLUGIN_NAMEStyle.cpp b/Engine/Plugins/Editor/PluginBrowser/Templates/Advanced/Source/PLUGIN_NAME/Private/PLUGIN_NAMEStyle.cpp index 17c26ca9ae00..76e80e8f5c9d 100644 --- a/Engine/Plugins/Editor/PluginBrowser/Templates/Advanced/Source/PLUGIN_NAME/Private/PLUGIN_NAMEStyle.cpp +++ b/Engine/Plugins/Editor/PluginBrowser/Templates/Advanced/Source/PLUGIN_NAME/Private/PLUGIN_NAMEStyle.cpp @@ -1,7 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "PLUGIN_NAMEStyle.h" -#include "PLUGIN_NAME.h" +#include "Styling/SlateStyleRegistry.h" +#include "Framework/Application/SlateApplication.h" #include "SlateGameResources.h" #include "IPluginManager.h" diff --git a/Engine/Plugins/Editor/PluginBrowser/Templates/Advanced/Source/PLUGIN_NAME/Public/PLUGIN_NAME.h b/Engine/Plugins/Editor/PluginBrowser/Templates/Advanced/Source/PLUGIN_NAME/Public/PLUGIN_NAME.h index 6d801f2a1b47..e130e06832c2 100644 --- a/Engine/Plugins/Editor/PluginBrowser/Templates/Advanced/Source/PLUGIN_NAME/Public/PLUGIN_NAME.h +++ b/Engine/Plugins/Editor/PluginBrowser/Templates/Advanced/Source/PLUGIN_NAME/Public/PLUGIN_NAME.h @@ -2,6 +2,7 @@ #pragma once +#include "CoreMinimal.h" #include "ModuleManager.h" class FToolBarBuilder; diff --git a/Engine/Plugins/Editor/PluginBrowser/Templates/Advanced/Source/PLUGIN_NAME/Public/PLUGIN_NAMECommands.h b/Engine/Plugins/Editor/PluginBrowser/Templates/Advanced/Source/PLUGIN_NAME/Public/PLUGIN_NAMECommands.h index e5cca8757f22..0c10a38378a9 100644 --- a/Engine/Plugins/Editor/PluginBrowser/Templates/Advanced/Source/PLUGIN_NAME/Public/PLUGIN_NAMECommands.h +++ b/Engine/Plugins/Editor/PluginBrowser/Templates/Advanced/Source/PLUGIN_NAME/Public/PLUGIN_NAMECommands.h @@ -2,7 +2,8 @@ #pragma once -#include "SlateBasics.h" +#include "CoreMinimal.h" +#include "Framework/Commands/Commands.h" #include "PLUGIN_NAMEStyle.h" class FPLUGIN_NAMECommands : public TCommands diff --git a/Engine/Plugins/Editor/PluginBrowser/Templates/Advanced/Source/PLUGIN_NAME/Public/PLUGIN_NAMEStyle.h b/Engine/Plugins/Editor/PluginBrowser/Templates/Advanced/Source/PLUGIN_NAME/Public/PLUGIN_NAMEStyle.h index 64f7d19700cd..04671caa5580 100644 --- a/Engine/Plugins/Editor/PluginBrowser/Templates/Advanced/Source/PLUGIN_NAME/Public/PLUGIN_NAMEStyle.h +++ b/Engine/Plugins/Editor/PluginBrowser/Templates/Advanced/Source/PLUGIN_NAME/Public/PLUGIN_NAMEStyle.h @@ -2,7 +2,8 @@ #pragma once -#include "SlateBasics.h" +#include "CoreMinimal.h" +#include "Styling/SlateStyle.h" /** */ class FPLUGIN_NAMEStyle diff --git a/Engine/Plugins/Editor/PluginBrowser/Templates/Basic/Source/PLUGIN_NAME/Private/PLUGIN_NAME.cpp b/Engine/Plugins/Editor/PluginBrowser/Templates/Basic/Source/PLUGIN_NAME/Private/PLUGIN_NAME.cpp index 2c7479084491..90442a94d18d 100644 --- a/Engine/Plugins/Editor/PluginBrowser/Templates/Basic/Source/PLUGIN_NAME/Private/PLUGIN_NAME.cpp +++ b/Engine/Plugins/Editor/PluginBrowser/Templates/Basic/Source/PLUGIN_NAME/Private/PLUGIN_NAME.cpp @@ -1,12 +1,10 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "PLUGIN_NAME.h" - -#include "SlateBasics.h" -#include "SlateExtras.h" - #include "PLUGIN_NAMEStyle.h" #include "PLUGIN_NAMECommands.h" +#include "Misc/MessageDialog.h" +#include "Framework/MultiBox/MultiBoxBuilder.h" #include "LevelEditor.h" diff --git a/Engine/Plugins/Editor/PluginBrowser/Templates/Basic/Source/PLUGIN_NAME/Public/PLUGIN_NAMECommands.cpp b/Engine/Plugins/Editor/PluginBrowser/Templates/Basic/Source/PLUGIN_NAME/Private/PLUGIN_NAMECommands.cpp similarity index 93% rename from Engine/Plugins/Editor/PluginBrowser/Templates/Basic/Source/PLUGIN_NAME/Public/PLUGIN_NAMECommands.cpp rename to Engine/Plugins/Editor/PluginBrowser/Templates/Basic/Source/PLUGIN_NAME/Private/PLUGIN_NAMECommands.cpp index 9162efbdd014..74cadd11d615 100644 --- a/Engine/Plugins/Editor/PluginBrowser/Templates/Basic/Source/PLUGIN_NAME/Public/PLUGIN_NAMECommands.cpp +++ b/Engine/Plugins/Editor/PluginBrowser/Templates/Basic/Source/PLUGIN_NAME/Private/PLUGIN_NAMECommands.cpp @@ -1,7 +1,6 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "PLUGIN_NAMECommands.h" -#include "PLUGIN_NAME.h" #define LOCTEXT_NAMESPACE "FPLUGIN_NAMEModule" diff --git a/Engine/Plugins/Editor/PluginBrowser/Templates/Basic/Source/PLUGIN_NAME/Private/PLUGIN_NAMEStyle.cpp b/Engine/Plugins/Editor/PluginBrowser/Templates/Basic/Source/PLUGIN_NAME/Private/PLUGIN_NAMEStyle.cpp index ee31db110264..8e137fde98c8 100644 --- a/Engine/Plugins/Editor/PluginBrowser/Templates/Basic/Source/PLUGIN_NAME/Private/PLUGIN_NAMEStyle.cpp +++ b/Engine/Plugins/Editor/PluginBrowser/Templates/Basic/Source/PLUGIN_NAME/Private/PLUGIN_NAMEStyle.cpp @@ -2,7 +2,8 @@ #include "PLUGIN_NAMEStyle.h" #include "PLUGIN_NAME.h" - +#include "Framework/Application/SlateApplication.h" +#include "Styling/SlateStyleRegistry.h" #include "SlateGameResources.h" #include "IPluginManager.h" diff --git a/Engine/Plugins/Editor/PluginBrowser/Templates/Basic/Source/PLUGIN_NAME/Public/PLUGIN_NAME.h b/Engine/Plugins/Editor/PluginBrowser/Templates/Basic/Source/PLUGIN_NAME/Public/PLUGIN_NAME.h index 81d8d5b1bc26..b16a90e679da 100644 --- a/Engine/Plugins/Editor/PluginBrowser/Templates/Basic/Source/PLUGIN_NAME/Public/PLUGIN_NAME.h +++ b/Engine/Plugins/Editor/PluginBrowser/Templates/Basic/Source/PLUGIN_NAME/Public/PLUGIN_NAME.h @@ -2,6 +2,7 @@ #pragma once +#include "CoreMinimal.h" #include "ModuleManager.h" class FToolBarBuilder; diff --git a/Engine/Plugins/Editor/PluginBrowser/Templates/Basic/Source/PLUGIN_NAME/Public/PLUGIN_NAMECommands.h b/Engine/Plugins/Editor/PluginBrowser/Templates/Basic/Source/PLUGIN_NAME/Public/PLUGIN_NAMECommands.h index b13fd6dc1433..0dea9771a750 100644 --- a/Engine/Plugins/Editor/PluginBrowser/Templates/Basic/Source/PLUGIN_NAME/Public/PLUGIN_NAMECommands.h +++ b/Engine/Plugins/Editor/PluginBrowser/Templates/Basic/Source/PLUGIN_NAME/Public/PLUGIN_NAMECommands.h @@ -2,7 +2,8 @@ #pragma once -#include "SlateBasics.h" +#include "CoreMinimal.h" +#include "Framework/Commands/Commands.h" #include "PLUGIN_NAMEStyle.h" class FPLUGIN_NAMECommands : public TCommands diff --git a/Engine/Plugins/Editor/PluginBrowser/Templates/Basic/Source/PLUGIN_NAME/Public/PLUGIN_NAMEStyle.h b/Engine/Plugins/Editor/PluginBrowser/Templates/Basic/Source/PLUGIN_NAME/Public/PLUGIN_NAMEStyle.h index 1cdec777d8b0..12024d3d300a 100644 --- a/Engine/Plugins/Editor/PluginBrowser/Templates/Basic/Source/PLUGIN_NAME/Public/PLUGIN_NAMEStyle.h +++ b/Engine/Plugins/Editor/PluginBrowser/Templates/Basic/Source/PLUGIN_NAME/Public/PLUGIN_NAMEStyle.h @@ -1,9 +1,10 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once -#include "SlateBasics.h" +#include "CoreMinimal.h" +#include "Styling/SlateStyle.h" -/** */ class FPLUGIN_NAMEStyle { public: diff --git a/Engine/Plugins/Editor/PluginBrowser/Templates/Blank/Source/PLUGIN_NAME/Public/PLUGIN_NAME.h b/Engine/Plugins/Editor/PluginBrowser/Templates/Blank/Source/PLUGIN_NAME/Public/PLUGIN_NAME.h index 1460ab5e21d2..2d6670c80aec 100644 --- a/Engine/Plugins/Editor/PluginBrowser/Templates/Blank/Source/PLUGIN_NAME/Public/PLUGIN_NAME.h +++ b/Engine/Plugins/Editor/PluginBrowser/Templates/Blank/Source/PLUGIN_NAME/Public/PLUGIN_NAME.h @@ -2,6 +2,7 @@ #pragma once +#include "CoreMinimal.h" #include "ModuleManager.h" class FPLUGIN_NAMEModule : public IModuleInterface diff --git a/Engine/Plugins/Editor/PluginBrowser/Templates/EditorMode/Source/PLUGIN_NAME/Private/PLUGIN_NAMEEdMode.cpp b/Engine/Plugins/Editor/PluginBrowser/Templates/EditorMode/Source/PLUGIN_NAME/Private/PLUGIN_NAMEEdMode.cpp index 7f7b59f93996..988ff26ac5f1 100644 --- a/Engine/Plugins/Editor/PluginBrowser/Templates/EditorMode/Source/PLUGIN_NAME/Private/PLUGIN_NAMEEdMode.cpp +++ b/Engine/Plugins/Editor/PluginBrowser/Templates/EditorMode/Source/PLUGIN_NAME/Private/PLUGIN_NAMEEdMode.cpp @@ -1,9 +1,9 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "PLUGIN_NAMEEdMode.h" -#include "PLUGIN_NAME.h" #include "PLUGIN_NAMEEdModeToolkit.h" #include "Toolkits/ToolkitManager.h" +#include "EditorModeManager.h" const FEditorModeID FPLUGIN_NAMEEdMode::EM_PLUGIN_NAMEEdModeId = TEXT("EM_PLUGIN_NAMEEdMode"); diff --git a/Engine/Plugins/Editor/PluginBrowser/Templates/EditorMode/Source/PLUGIN_NAME/Private/PLUGIN_NAMEEdModeToolkit.cpp b/Engine/Plugins/Editor/PluginBrowser/Templates/EditorMode/Source/PLUGIN_NAME/Private/PLUGIN_NAMEEdModeToolkit.cpp index 478053d17d24..d757aa69c021 100644 --- a/Engine/Plugins/Editor/PluginBrowser/Templates/EditorMode/Source/PLUGIN_NAME/Private/PLUGIN_NAMEEdModeToolkit.cpp +++ b/Engine/Plugins/Editor/PluginBrowser/Templates/EditorMode/Source/PLUGIN_NAME/Private/PLUGIN_NAMEEdModeToolkit.cpp @@ -1,8 +1,11 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "PLUGIN_NAMEEdModeToolkit.h" -#include "PLUGIN_NAME.h" #include "PLUGIN_NAMEEdMode.h" +#include "Engine/Selection.h" +#include "Widgets/Input/SButton.h" +#include "Widgets/Text/STextBlock.h" +#include "EditorModeManager.h" #define LOCTEXT_NAMESPACE "FPLUGIN_NAMEEdModeToolkit" diff --git a/Engine/Plugins/Editor/PluginBrowser/Templates/EditorMode/Source/PLUGIN_NAME/Public/PLUGIN_NAME.h b/Engine/Plugins/Editor/PluginBrowser/Templates/EditorMode/Source/PLUGIN_NAME/Public/PLUGIN_NAME.h index 1460ab5e21d2..2d6670c80aec 100644 --- a/Engine/Plugins/Editor/PluginBrowser/Templates/EditorMode/Source/PLUGIN_NAME/Public/PLUGIN_NAME.h +++ b/Engine/Plugins/Editor/PluginBrowser/Templates/EditorMode/Source/PLUGIN_NAME/Public/PLUGIN_NAME.h @@ -2,6 +2,7 @@ #pragma once +#include "CoreMinimal.h" #include "ModuleManager.h" class FPLUGIN_NAMEModule : public IModuleInterface diff --git a/Engine/Plugins/Editor/PluginBrowser/Templates/EditorMode/Source/PLUGIN_NAME/Public/PLUGIN_NAMEEdMode.h b/Engine/Plugins/Editor/PluginBrowser/Templates/EditorMode/Source/PLUGIN_NAME/Public/PLUGIN_NAMEEdMode.h index 4ed003dd0016..8f3689e4ffd6 100644 --- a/Engine/Plugins/Editor/PluginBrowser/Templates/EditorMode/Source/PLUGIN_NAME/Public/PLUGIN_NAMEEdMode.h +++ b/Engine/Plugins/Editor/PluginBrowser/Templates/EditorMode/Source/PLUGIN_NAME/Public/PLUGIN_NAMEEdMode.h @@ -2,8 +2,8 @@ #pragma once -#include "UnrealEd.h" -#include "Editor.h" +#include "CoreMinimal.h" +#include "EdMode.h" class FPLUGIN_NAMEEdMode : public FEdMode { diff --git a/Engine/Plugins/Editor/PluginBrowser/Templates/EditorMode/Source/PLUGIN_NAME/Public/PLUGIN_NAMEEdModeToolkit.h b/Engine/Plugins/Editor/PluginBrowser/Templates/EditorMode/Source/PLUGIN_NAME/Public/PLUGIN_NAMEEdModeToolkit.h index 2b00d9c678d3..214856f8c9df 100644 --- a/Engine/Plugins/Editor/PluginBrowser/Templates/EditorMode/Source/PLUGIN_NAME/Public/PLUGIN_NAMEEdModeToolkit.h +++ b/Engine/Plugins/Editor/PluginBrowser/Templates/EditorMode/Source/PLUGIN_NAME/Public/PLUGIN_NAMEEdModeToolkit.h @@ -2,8 +2,8 @@ #pragma once -#include "Editor/UnrealEd/Public/Toolkits/BaseToolkit.h" - +#include "CoreMinimal.h" +#include "Toolkits/BaseToolkit.h" class FPLUGIN_NAMEEdModeToolkit : public FModeToolkit { diff --git a/Engine/Plugins/Editor/SpeedTreeImporter/Source/SpeedTreeImporter/Private/ReimportSpeedTreeFactory.cpp b/Engine/Plugins/Editor/SpeedTreeImporter/Source/SpeedTreeImporter/Private/ReimportSpeedTreeFactory.cpp index 3aff093d67fa..481589c25f7a 100644 --- a/Engine/Plugins/Editor/SpeedTreeImporter/Source/SpeedTreeImporter/Private/ReimportSpeedTreeFactory.cpp +++ b/Engine/Plugins/Editor/SpeedTreeImporter/Source/SpeedTreeImporter/Private/ReimportSpeedTreeFactory.cpp @@ -4,11 +4,11 @@ #include "Misc/Paths.h" #include "EditorFramework/AssetImportData.h" #include "Engine/StaticMesh.h" +#include "Factories.h" #define LOCTEXT_NAMESPACE "EditorFactories" -DEFINE_LOG_CATEGORY_STATIC(LogEditorFactories, Log, All); diff --git a/Engine/Plugins/Editor/USDImporter/Source/ThirdParty/USD/Boost.tps b/Engine/Plugins/Editor/USDImporter/Source/ThirdParty/USD/Boost.tps new file mode 100644 index 000000000000..1d1b8920aed8 --- /dev/null +++ b/Engine/Plugins/Editor/USDImporter/Source/ThirdParty/USD/Boost.tps @@ -0,0 +1,15 @@ + + + Boost + /Engine/Plugins/Editor/USDImporter/Source/ThirdParty/USD/include/boost/ + 2017-02-15T16:27:27.8009449-05:00 + Generalized C++ tool kit + Dependency of USD + http://www.boost.org/users/license.html + + Licensees + Git + P4 + + /Engine/Source/ThirdParty/Licenses/BoostSoftwarev1_License.txt + \ No newline at end of file diff --git a/Engine/Plugins/Editor/USDImporter/Source/ThirdParty/USD/IntelTBB.tps b/Engine/Plugins/Editor/USDImporter/Source/ThirdParty/USD/IntelTBB.tps new file mode 100644 index 000000000000..01f615b0e3a2 --- /dev/null +++ b/Engine/Plugins/Editor/USDImporter/Source/ThirdParty/USD/IntelTBB.tps @@ -0,0 +1,9 @@ + + + + /Engine/Plugins/Editor/USDImporter/Source/ThirdParty/USD/include/tbb/ + +Redirect: ../../../../../../../../Source/ThirdParty/IntelTBB/IntelTBB.tps + + + \ No newline at end of file diff --git a/Engine/Plugins/Editor/USDImporter/Source/ThirdParty/USD/OpenEXR.tps b/Engine/Plugins/Editor/USDImporter/Source/ThirdParty/USD/OpenEXR.tps new file mode 100644 index 000000000000..d58f2c167500 --- /dev/null +++ b/Engine/Plugins/Editor/USDImporter/Source/ThirdParty/USD/OpenEXR.tps @@ -0,0 +1,9 @@ + + + + /Engine/Plugins/Editor/USDImporter/Source/ThirdParty/USD/OpenEXR/ + +Redirect: ../../../../../../../Source/ThirdParty/openexr/OpenEXR-1.7.1/OpenEXR.tps + + + \ No newline at end of file diff --git a/Engine/Plugins/Editor/USDImporter/Source/ThirdParty/USD/Python.tps b/Engine/Plugins/Editor/USDImporter/Source/ThirdParty/USD/Python.tps new file mode 100644 index 000000000000..588936c5ffbb --- /dev/null +++ b/Engine/Plugins/Editor/USDImporter/Source/ThirdParty/USD/Python.tps @@ -0,0 +1,15 @@ + + + Python v2.7.5 + /Engine/Plugins/Editor/USDImporter/Source/ThirdParty/USD/Python/ + 2017-02-15T16:27:27.8009449-05:00 + Python interpreter and standard library for developing with Python. + Dependency of USD + https://docs.python.org/2.7/license.html + + Licensees + Git + P4 + + None + \ No newline at end of file diff --git a/Engine/Plugins/Editor/USDImporter/Source/USDImporter/Private/USDImporter.cpp b/Engine/Plugins/Editor/USDImporter/Source/USDImporter/Private/USDImporter.cpp index 9a85dc6b6afd..f799f0d85386 100644 --- a/Engine/Plugins/Editor/USDImporter/Source/USDImporter/Private/USDImporter.cpp +++ b/Engine/Plugins/Editor/USDImporter/Source/USDImporter/Private/USDImporter.cpp @@ -223,8 +223,7 @@ UObject* UUSDImporter::ImportMeshes(FUsdImportContext& ImportContext, const TArr } - UObject* NewMesh = nullptr; - NewMesh = ImportSingleMesh(ImportContext, MeshImportType, PrimToImport); + UObject* NewMesh = ImportSingleMesh(ImportContext, MeshImportType, PrimToImport); FAssetRegistryModule::AssetCreated(NewMesh); diff --git a/Engine/Plugins/Editor/USDImporter/Source/USDImporter/Private/USDImporter.h b/Engine/Plugins/Editor/USDImporter/Source/USDImporter/Private/USDImporter.h index 1f91b3176b12..fea7fb7d5ea6 100644 --- a/Engine/Plugins/Editor/USDImporter/Source/USDImporter/Private/USDImporter.h +++ b/Engine/Plugins/Editor/USDImporter/Source/USDImporter/Private/USDImporter.h @@ -72,6 +72,8 @@ struct FUsdImportContext /** If true stop at any USD prim that has an unreal asset reference. Geometry that is a child such prims will be ignored */ bool bFindUnrealAssetReferences; + virtual ~FUsdImportContext() { } + virtual void Init(UObject* InParent, const FString& InName, EObjectFlags InFlags, IUsdStage* InStage); void AddErrorMessage(EMessageSeverity::Type MessageSeverity, FText ErrorMessage); diff --git a/Engine/Plugins/Editor/USDImporter/Source/USDImporter/Private/USDSceneImportFactory.cpp b/Engine/Plugins/Editor/USDImporter/Source/USDImporter/Private/USDSceneImportFactory.cpp index a4723908b4bb..6e4e2b04e29a 100644 --- a/Engine/Plugins/Editor/USDImporter/Source/USDImporter/Private/USDSceneImportFactory.cpp +++ b/Engine/Plugins/Editor/USDImporter/Source/USDImporter/Private/USDSceneImportFactory.cpp @@ -156,13 +156,18 @@ UObject* UUSDSceneImportFactory::FactoryCreateFile(UClass* InClass, UObject* InP Asset = USDImporter->ImportSingleMesh(ImportContext, ImportOptions->MeshImportType, PrimToAssetName.PrimData); - FAssetRegistryModule::AssetCreated(Asset); - Package->MarkPackageDirty(); + if(Asset) + { + FAssetRegistryModule::AssetCreated(Asset); + Package->MarkPackageDirty(); + } + } + + if(Asset) + { + ImportContext.PrimToAssetMap.Add(PrimToAssetName.PrimData.Prim, Asset); } - check(Asset); - - ImportContext.PrimToAssetMap.Add(PrimToAssetName.PrimData.Prim, Asset); ++MeshCount; } } diff --git a/Engine/Plugins/Editor/USDImporter/Source/USDImporter/USDImporter.Build.cs b/Engine/Plugins/Editor/USDImporter/Source/USDImporter/USDImporter.Build.cs index 1ce823b7dfd3..7dc5fa5816e9 100644 --- a/Engine/Plugins/Editor/USDImporter/Source/USDImporter/USDImporter.Build.cs +++ b/Engine/Plugins/Editor/USDImporter/Source/USDImporter/USDImporter.Build.cs @@ -1,6 +1,7 @@ // Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. using System; +using System.IO; namespace UnrealBuildTool.Rules { @@ -48,7 +49,12 @@ namespace UnrealBuildTool.Rules { string LibraryPath = BaseLibDir + "x64/Release/"; PublicAdditionalLibraries.Add(LibraryPath+"/UnrealUSDWrapper.lib"); - } + + foreach (string FilePath in Directory.EnumerateFiles(Path.Combine(ModuleDirectory, "../../Binaries/Win64/"), "*.dll", SearchOption.AllDirectories)) + { + RuntimeDependencies.Add(new RuntimeDependency(FilePath)); + } + } } } } \ No newline at end of file diff --git a/Engine/Plugins/Experimental/AlembicImporter/Source/AlembicLibrary/Private/AbcImporter.cpp b/Engine/Plugins/Experimental/AlembicImporter/Source/AlembicLibrary/Private/AbcImporter.cpp index 79351b8d5889..a98f00b4fc2d 100644 --- a/Engine/Plugins/Experimental/AlembicImporter/Source/AlembicLibrary/Private/AbcImporter.cpp +++ b/Engine/Plugins/Experimental/AlembicImporter/Source/AlembicLibrary/Private/AbcImporter.cpp @@ -637,7 +637,6 @@ void FAbcImporter::TraverseAbcHierarchy(const Alembic::Abc::IObject& InObject, T { // Push back this object for the Hierarchy TArray> NewObjectHierarchy = InObjectHierarchy; - NewObjectHierarchy = InObjectHierarchy; // Only add handled objects to ensure we have valid objects in the hierarchies if (bHandled && AbcImporterUtilities::IsType(ObjectMetaData)) @@ -881,8 +880,7 @@ const TArray FAbcImporter::ImportAsStaticMesh(UObject* InParent, E // Only merged samples if there are any if (Samples.Num()) { - FAbcMeshSample* MergedSample = nullptr; - MergedSample = AbcImporterUtilities::MergeMeshSamples(Samples); + FAbcMeshSample* MergedSample = AbcImporterUtilities::MergeMeshSamples(Samples); FRawMesh RawMesh; GenerateRawMeshFromSample(MergedSample, RawMesh); diff --git a/Engine/Plugins/Experimental/AlembicImporter/Source/ThirdParty/Alembic/Deploy/include/ImathPlatform.h b/Engine/Plugins/Experimental/AlembicImporter/Source/ThirdParty/Alembic/Deploy/include/ImathPlatform.h index 91e82cc20915..d344a4e1100c 100644 --- a/Engine/Plugins/Experimental/AlembicImporter/Source/ThirdParty/Alembic/Deploy/include/ImathPlatform.h +++ b/Engine/Plugins/Experimental/AlembicImporter/Source/ThirdParty/Alembic/Deploy/include/ImathPlatform.h @@ -80,7 +80,7 @@ // supports restrict // - #define IMATH_RESTRICT restrict + #define IMATH_RESTRICT #elif defined __sgi diff --git a/Engine/Plugins/Experimental/BlueprintStats/Source/BlueprintStats/Private/BlueprintStatsModule.cpp b/Engine/Plugins/Experimental/BlueprintStats/Source/BlueprintStats/Private/BlueprintStatsModule.cpp index cabbba9e19b4..1280ba9c7aa0 100644 --- a/Engine/Plugins/Experimental/BlueprintStats/Source/BlueprintStats/Private/BlueprintStatsModule.cpp +++ b/Engine/Plugins/Experimental/BlueprintStats/Source/BlueprintStats/Private/BlueprintStatsModule.cpp @@ -12,9 +12,7 @@ #include "IBlueprintStatsModule.h" #include "BlueprintStats.h" -DECLARE_LOG_CATEGORY_EXTERN(LogBlueprintStats, Verbose, All); - -DEFINE_LOG_CATEGORY(LogBlueprintStats); +DEFINE_LOG_CATEGORY_STATIC(LogBlueprintStats, Verbose, All); class FBlueprintStatsModule : public IBlueprintStatsModule { diff --git a/Engine/Plugins/Experimental/CodeView/Source/CodeView/Private/SCodeView.h b/Engine/Plugins/Experimental/CodeView/Source/CodeView/Private/SCodeView.h index 24a133e9955c..cd831f9bde6e 100644 --- a/Engine/Plugins/Experimental/CodeView/Source/CodeView/Private/SCodeView.h +++ b/Engine/Plugins/Experimental/CodeView/Source/CodeView/Private/SCodeView.h @@ -41,7 +41,7 @@ namespace CodeView { } - ~FTreeItem() + virtual ~FTreeItem() { } diff --git a/Engine/Plugins/Experimental/ControlRig/Source/ControlRig/Private/Rigs/ControlManipulator.cpp b/Engine/Plugins/Experimental/ControlRig/Source/ControlRig/Private/Rigs/ControlManipulator.cpp index 5c75d575d4ed..e79019f15169 100644 --- a/Engine/Plugins/Experimental/ControlRig/Source/ControlRig/Private/Rigs/ControlManipulator.cpp +++ b/Engine/Plugins/Experimental/ControlRig/Source/ControlRig/Private/Rigs/ControlManipulator.cpp @@ -549,7 +549,7 @@ void USphereManipulator::Draw(const FTransform& InTransform, const FSceneView* V if(ColorMaterial.IsValid()) { ColorMaterial->SetVectorParameterValue("Color", FVector(bIsSelected ? SelectedColor : Color)); - DrawSphere(PDI, InTransform.GetLocation(), FVector(Radius) * CurrentProximity, 64, 64, ColorMaterial->GetRenderProxy(false), SDPG_World); + DrawSphere(PDI, InTransform.GetLocation(), FRotator::ZeroRotator, FVector(Radius) * CurrentProximity, 64, 64, ColorMaterial->GetRenderProxy(false), SDPG_World); } } diff --git a/Engine/Plugins/Experimental/ControlRig/Source/ControlRig/Private/Sequencer/ControlRigBindingTemplate.cpp b/Engine/Plugins/Experimental/ControlRig/Source/ControlRig/Private/Sequencer/ControlRigBindingTemplate.cpp index aafae522be0a..b9533707d7c9 100644 --- a/Engine/Plugins/Experimental/ControlRig/Source/ControlRig/Private/Sequencer/ControlRigBindingTemplate.cpp +++ b/Engine/Plugins/Experimental/ControlRig/Source/ControlRig/Private/Sequencer/ControlRigBindingTemplate.cpp @@ -94,7 +94,7 @@ struct FBindControlRigObjectToken : IMovieSceneExecutionToken check(ControlRig); if (USkeletalMeshComponent* SkeletalMeshComponent = Cast(ControlRig->GetBoundObject())) { - if (UControlRigSequencerAnimInstance* AnimInstance = UAnimSequencerInstance::BindToSkeletalMeshComponent(SkeletalMeshComponent)) + if (UControlRigSequencerAnimInstance* AnimInstance = UAnimCustomInstance::BindToSkeletalMeshComponent(SkeletalMeshComponent)) { AnimInstance->RecalcRequiredBones(); } @@ -106,7 +106,7 @@ struct FBindControlRigObjectToken : IMovieSceneExecutionToken check(ControlRig); if (USkeletalMeshComponent* SkeletalMeshComponent = Cast(ControlRig->GetBoundObject())) { - UAnimSequencerInstance::UnbindFromSkeletalMeshComponent(SkeletalMeshComponent); + UAnimCustomInstance::UnbindFromSkeletalMeshComponent(SkeletalMeshComponent); } } diff --git a/Engine/Plugins/Experimental/ControlRig/Source/ControlRig/Public/Rigs/HumanRig.h b/Engine/Plugins/Experimental/ControlRig/Source/ControlRig/Public/Rigs/HumanRig.h index b707093031cb..f8e5304ca14a 100644 --- a/Engine/Plugins/Experimental/ControlRig/Source/ControlRig/Public/Rigs/HumanRig.h +++ b/Engine/Plugins/Experimental/ControlRig/Source/ControlRig/Public/Rigs/HumanRig.h @@ -11,7 +11,7 @@ #include "HumanRig.generated.h" #define MIN_SPINE_CHAIN 2 -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct FLimbControl { GENERATED_BODY() @@ -102,7 +102,7 @@ struct FLimbControl void Initialize(float InUpperLimbLen, float InLowerLimbLen); }; -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct FSpineControl { GENERATED_USTRUCT_BODY() @@ -315,7 +315,7 @@ struct FPoseKey bool GetBlendedResult(FName InNodeName, float InKeyValue, FTransform& OutTransform) const; }; -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct FFingerDescription { GENERATED_USTRUCT_BODY() diff --git a/Engine/Plugins/Experimental/ControlRig/Source/ControlRigEditor/Private/InputOutput/K2Node_ControlRigComponentInput.cpp b/Engine/Plugins/Experimental/ControlRig/Source/ControlRigEditor/Private/InputOutput/K2Node_ControlRigComponentInput.cpp index bb04331f56be..bb288a03574c 100644 --- a/Engine/Plugins/Experimental/ControlRig/Source/ControlRigEditor/Private/InputOutput/K2Node_ControlRigComponentInput.cpp +++ b/Engine/Plugins/Experimental/ControlRig/Source/ControlRigEditor/Private/InputOutput/K2Node_ControlRigComponentInput.cpp @@ -28,8 +28,8 @@ void UK2Node_ControlRigComponentInput::AllocateDefaultPins() const UEdGraphSchema_K2* Schema = GetDefault(); // Create default exec pins - CreatePin(EGPD_Input, Schema->PC_Exec, TEXT(""), NULL, false, false, Schema->PN_Execute); - CreatePin(EGPD_Output, Schema->PC_Exec, TEXT(""), NULL, false, false, Schema->PN_Then); + CreatePin(EGPD_Input, Schema->PC_Exec, FString(), nullptr, Schema->PN_Execute); + CreatePin(EGPD_Output, Schema->PC_Exec, FString(), nullptr, Schema->PN_Then); Super::AllocateDefaultPins(); @@ -45,7 +45,7 @@ void UK2Node_ControlRigComponentInput::CreateInputPins() for (const TSharedRef& InputInfo : InputInfos) { UEdGraphPin* InputPin = CreatePin(EGPD_Input, InputInfo->GetPinType(), InputInfo->GetPinString()); - Schema->SetPinDefaultValueBasedOnType(InputPin); + Schema->SetPinAutogeneratedDefaultValueBasedOnType(InputPin); } } diff --git a/Engine/Plugins/Experimental/ControlRig/Source/ControlRigEditor/Private/InputOutput/K2Node_ControlRigComponentInputOutput.cpp b/Engine/Plugins/Experimental/ControlRig/Source/ControlRigEditor/Private/InputOutput/K2Node_ControlRigComponentInputOutput.cpp index d251bee7c39a..a5e9ae70a9de 100644 --- a/Engine/Plugins/Experimental/ControlRig/Source/ControlRigEditor/Private/InputOutput/K2Node_ControlRigComponentInputOutput.cpp +++ b/Engine/Plugins/Experimental/ControlRig/Source/ControlRigEditor/Private/InputOutput/K2Node_ControlRigComponentInputOutput.cpp @@ -39,7 +39,7 @@ void UK2Node_ControlRigComponentInputOutput::AllocateDefaultPins() // Optionally create input pin for ControlRig if (IsInActor()) { - CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Object, TEXT(""), UControlRigComponent::StaticClass(), false, true, ControlRigComponentPinName); + CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Object, FString(), UControlRigComponent::StaticClass(), ControlRigComponentPinName, EPinContainerType::None, true); } } @@ -52,6 +52,8 @@ bool UK2Node_ControlRigComponentInputOutput::IsCompatibleWithGraph(UEdGraph cons void UK2Node_ControlRigComponentInputOutput::EarlyValidation(class FCompilerResultsLog& MessageLog) const { + Super::EarlyValidation(MessageLog); + if (IsInActor()) { if (ControlRigType.Get() == nullptr) diff --git a/Engine/Plugins/Experimental/ControlRig/Source/ControlRigEditor/Private/InputOutput/K2Node_ControlRigEvaluator.cpp b/Engine/Plugins/Experimental/ControlRig/Source/ControlRigEditor/Private/InputOutput/K2Node_ControlRigEvaluator.cpp index 4e8d8dadb654..c2648562af5f 100644 --- a/Engine/Plugins/Experimental/ControlRig/Source/ControlRigEditor/Private/InputOutput/K2Node_ControlRigEvaluator.cpp +++ b/Engine/Plugins/Experimental/ControlRig/Source/ControlRigEditor/Private/InputOutput/K2Node_ControlRigEvaluator.cpp @@ -113,12 +113,12 @@ void UK2Node_ControlRigEvaluator::AllocateDefaultPins() for (const TSharedRef& InputInfo : InputInfos) { UEdGraphPin* InputPin = CreatePin(EGPD_Input, InputInfo->GetPinType(), InputInfo->GetPinString()); - Schema->SetPinDefaultValueBasedOnType(InputPin); + Schema->SetPinAutogeneratedDefaultValueBasedOnType(InputPin); } if (UClass* Class = GetControlRigClass()) { - CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Object, TEXT(""), Class, false, true, ControlRigPinName); + CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Object, FString(), Class, ControlRigPinName, EPinContainerType::None, true); } for (const TSharedRef& OutputInfo : OutputInfos) diff --git a/Engine/Plugins/Experimental/ControlRig/Source/ControlRigEditor/Private/InputOutput/K2Node_ControlRigOutput.cpp b/Engine/Plugins/Experimental/ControlRig/Source/ControlRigEditor/Private/InputOutput/K2Node_ControlRigOutput.cpp index b21ab15160be..693f4cc6e9f7 100644 --- a/Engine/Plugins/Experimental/ControlRig/Source/ControlRigEditor/Private/InputOutput/K2Node_ControlRigOutput.cpp +++ b/Engine/Plugins/Experimental/ControlRig/Source/ControlRigEditor/Private/InputOutput/K2Node_ControlRigOutput.cpp @@ -32,7 +32,7 @@ void UK2Node_ControlRigOutput::AllocateDefaultPins() for (const TSharedRef& InputInfo : InputInfos) { UEdGraphPin* InputPin = CreatePin(EGPD_Input, InputInfo->GetPinType(), InputInfo->GetPinString()); - Schema->SetPinDefaultValueBasedOnType(InputPin); + Schema->SetPinAutogeneratedDefaultValueBasedOnType(InputPin); } } diff --git a/Engine/Plugins/Experimental/ControlRig/Source/ControlRigEditor/Private/Sequencer/ControlRigTrackEditor.cpp b/Engine/Plugins/Experimental/ControlRig/Source/ControlRigEditor/Private/Sequencer/ControlRigTrackEditor.cpp index 8e6536dcc0ff..97a393ecf7ab 100644 --- a/Engine/Plugins/Experimental/ControlRig/Source/ControlRigEditor/Private/Sequencer/ControlRigTrackEditor.cpp +++ b/Engine/Plugins/Experimental/ControlRig/Source/ControlRigEditor/Private/Sequencer/ControlRigTrackEditor.cpp @@ -112,9 +112,9 @@ public: } // add box for the working size - const float StartOffset = Section.Parameters.TimeScale * Section.Parameters.StartOffset; - const float WorkingStart = -Section.Parameters.TimeScale * PlaybackRange.GetLowerBoundValue() - StartOffset; - const float WorkingSize = Section.Parameters.TimeScale * (MovieScene != nullptr ? MovieScene->GetEditorData().WorkingRange.Size() : 1.0f); + const float StartOffset = 1.0f/Section.Parameters.TimeScale * Section.Parameters.StartOffset; + const float WorkingStart = -1.0f/Section.Parameters.TimeScale * PlaybackRange.GetLowerBoundValue() - StartOffset; + const float WorkingSize = 1.0f/Section.Parameters.TimeScale * (MovieScene != nullptr ? MovieScene->GetEditorData().WorkingRange.Size() : 1.0f); // add dark tint for left out-of-bounds & working range if (StartOffset < 0.0f) @@ -151,7 +151,7 @@ public: } // add dark tint for right out-of-bounds & working range - const float PlaybackEnd = Section.Parameters.TimeScale * PlaybackRange.Size() - StartOffset; + const float PlaybackEnd = 1.0f/Section.Parameters.TimeScale * PlaybackRange.Size() - StartOffset; if (PlaybackEnd < SectionSize) { diff --git a/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/AnimNode_LiveLinkPose.cpp b/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/AnimNode_LiveLinkPose.cpp index 82c1b5f2a924..46b0dbc84220 100644 --- a/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/AnimNode_LiveLinkPose.cpp +++ b/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/AnimNode_LiveLinkPose.cpp @@ -5,6 +5,8 @@ #include "Features/IModularFeatures.h" +#include "AnimInstanceProxy.h" + #define LOCTEXT_NAMESPACE "LiveLinkAnimNode" void FAnimNode_LiveLinkPose::Initialize(const FAnimationInitializeContext& Context) @@ -19,25 +21,32 @@ void FAnimNode_LiveLinkPose::Initialize(const FAnimationInitializeContext& Conte void FAnimNode_LiveLinkPose::Evaluate(FPoseContext& Output) { - FLiveLinkRefSkeleton RefSkeleton; - TArray BoneTransforms; - Output.ResetToRefPose(); - if(LiveLinkClient && LiveLinkClient->GetSubjectData(SubjectName, BoneTransforms, RefSkeleton)) + if (!LiveLinkClient) { - const TArray& BoneNames = RefSkeleton.GetBoneNames(); + return; + } - if ((BoneNames.Num() == 0) || (BoneTransforms.Num() == 0) || (BoneNames.Num() != BoneTransforms.Num())) + FLiveLinkRefSkeleton RefSkeleton; + TArray BoneTransforms; + FLiveLinkCurveKey CurveKey; + TArray Curves; + + if(const FLiveLinkSubjectFrame* Subject = LiveLinkClient->GetSubjectData(SubjectName)) + { + const TArray& BoneNames = Subject->RefSkeleton.GetBoneNames(); + + if ((BoneNames.Num() == 0) || (Subject->Transforms.Num() == 0) || (BoneNames.Num() != Subject->Transforms.Num())) { - UE_LOG(LogTemp, Warning, TEXT("Failed to get live link data %i %i"), BoneNames.Num(), BoneTransforms.Num()); + UE_LOG(LogTemp, Warning, TEXT("Failed to get live link data %i %i"), BoneNames.Num(), Subject->Transforms.Num()); return; } for (int32 i = 0; i < BoneNames.Num(); ++i) { FName BoneName = BoneNames[i]; - FTransform BoneTransform = BoneTransforms[i]; + FTransform BoneTransform = Subject->Transforms[i]; int32 MeshIndex = Output.Pose.GetBoneContainer().GetPoseBoneIndexForBoneName(BoneName); if (MeshIndex != INDEX_NONE) @@ -49,6 +58,23 @@ void FAnimNode_LiveLinkPose::Evaluate(FPoseContext& Output) } } } + + USkeleton* Skeleton = Output.AnimInstanceProxy->GetSkeleton(); + + for (int32 CurveIdx = 0; CurveIdx < Subject->CurveKeyData.CurveNames.Num(); ++CurveIdx) + { + const FOptionalCurveElement& Curve = Subject->Curves[CurveIdx]; + if(Curve.IsValid()) + { + FName CurveName = Subject->CurveKeyData.CurveNames[CurveIdx]; + + SmartName::UID_Type UID = Skeleton->GetUIDByName(USkeleton::AnimCurveMappingName, CurveName); + if (UID != SmartName::MaxUID) + { + Output.Curve.Set(UID, Curve.Value); + } + } + } } } diff --git a/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/LiveLinkClient.cpp b/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/LiveLinkClient.cpp index 0a6ce012f1aa..06b0fad2fed8 100644 --- a/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/LiveLinkClient.cpp +++ b/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/LiveLinkClient.cpp @@ -6,9 +6,204 @@ #include "LiveLinkSourceFactory.h" #include "Guid.h" -const TArray& FLiveLinkTransformData::GetTransformData() +const double VALIDATE_SOURCES_TIME = 3.0; //How long should we wait between validation checks +const int32 MIN_FRAMES_TO_REMOVE = 5; + +FLiveLinkCurveIntegrationData FLiveLinkCurveKey::UpdateCurveKey(const TArray& CurveElements) { - return Transforms.Last(); + FLiveLinkCurveIntegrationData IntegrationData; + + int32 CurrentSize = CurveNames.Num(); + + IntegrationData.CurveValues.AddDefaulted(CurrentSize); + + for(const FLiveLinkCurveElement& Elem : CurveElements) + { + int32 CurveIndex = CurveNames.IndexOfByKey(Elem.CurveName); + if (CurveIndex == INDEX_NONE) + { + CurveIndex = CurveNames.Add(Elem.CurveName); + IntegrationData.CurveValues.AddDefaulted(); + } + IntegrationData.CurveValues[CurveIndex].SetValue(Elem.CurveValue); + } + IntegrationData.NumNewCurves = CurveNames.Num() - CurrentSize; + + return IntegrationData; +} + +void BlendItem(const FTransform& A, const FTransform& B, FTransform& Output, float BlendWeight) +{ + const ScalarRegister ABlendWeight(1.0f - BlendWeight); + const ScalarRegister BBlendWeight(BlendWeight); + + Output = A * ABlendWeight; + Output.AccumulateWithShortestRotation(B, BBlendWeight); + Output.NormalizeRotation(); +} + +void BlendItem(const FOptionalCurveElement& A, const FOptionalCurveElement& B, FOptionalCurveElement& Output, float BlendWeight) +{ + Output.Value = (A.Value * (1.0f - BlendWeight)) + (B.Value * BlendWeight); + Output.bValid = A.bValid || B.bValid; +} + +template +void Blend(const TArray& A, const TArray& B, TArray& Output, float BlendWeight) +{ + check(A.Num() == B.Num()); + Output.SetNum(A.Num(), false); + + for (int32 BlendIndex = 0; BlendIndex < A.Num(); ++BlendIndex) + { + BlendItem(A[BlendIndex], B[BlendIndex], Output[BlendIndex], BlendWeight); + } +} + +void FLiveLinkSubject::AddFrame(const TArray& Transforms, const TArray& CurveElements, const FLiveLinkTimeCode& TimeCode, FGuid FrameSource) +{ + LastModifier = FrameSource; + + FLiveLinkFrame* NewFrame = nullptr; + + if(CachedConnectionSettings.bUseInterpolation) + { + if (TimeCode.Time < LastReadTime) + { + //Gone back in time + Frames.Reset(); + LastReadTime = 0; + SubjectTimeOffset = TimeCode.Offset; + } + + if (Frames.Num() == 0) + { + Frames.AddDefaulted(); + NewFrame = &Frames[0]; + LastReadFrame = 0; + } + else + { + if (LastReadFrame > MIN_FRAMES_TO_REMOVE) + { + check(Frames.Num() > LastReadFrame); + Frames.RemoveAt(0, LastReadFrame, false); + LastReadFrame = 0; + } + + int32 FrameIndex = Frames.Num() - 1; + + for (; FrameIndex >= 0; --FrameIndex) + { + if (Frames[FrameIndex].TimeCode.Time < TimeCode.Time) + { + break; + } + } + + int32 NewFrameIndex = Frames.Insert(FLiveLinkFrame(), FrameIndex + 1); + NewFrame = &Frames[NewFrameIndex]; + } + } + else + { + //No interpolation + if (Frames.Num() > 1) + { + Frames.Reset(); + } + + if (Frames.Num() == 0) + { + Frames.AddDefaulted(); + } + + NewFrame = &Frames[0]; + + LastReadTime = 0; + LastReadFrame = 0; + + SubjectTimeOffset = TimeCode.Offset; + } + + FLiveLinkCurveIntegrationData IntegrationData = CurveKeyData.UpdateCurveKey(CurveElements); + + check(NewFrame); + NewFrame->Transforms = Transforms; + NewFrame->Curves = MoveTemp(IntegrationData.CurveValues); + NewFrame->TimeCode = TimeCode; + + // update existing curves + if (IntegrationData.NumNewCurves > 0) + { + for (FLiveLinkFrame& Frame : Frames) + { + Frame.ExtendCurveData(IntegrationData.NumNewCurves); + } + } +} + +void FLiveLinkSubject::BuildInterpolatedFrame(const double InSeconds, FLiveLinkSubjectFrame& OutFrame) +{ + OutFrame.RefSkeleton = RefSkeleton; + OutFrame.CurveKeyData = CurveKeyData; + + OutFrame.Transforms.Reset(); + OutFrame.Curves.Reset(); + + if (!CachedConnectionSettings.bUseInterpolation) + { + OutFrame.Transforms = Frames.Last().Transforms; + OutFrame.Curves = Frames.Last().Curves; + LastReadTime = Frames.Last().TimeCode.Time; + LastReadFrame = Frames.Num()-1; + } + else + { + LastReadTime = (InSeconds - SubjectTimeOffset) - CachedConnectionSettings.InterpolationOffset; + + bool bBuiltFrame = false; + + for (int32 FrameIndex = Frames.Num() - 1; FrameIndex >= 0; --FrameIndex) + { + if (Frames[FrameIndex].TimeCode.Time < LastReadTime) + { + //Found Start frame + + if (FrameIndex == Frames.Num() - 1) + { + LastReadFrame = FrameIndex; + OutFrame.Transforms = Frames[FrameIndex].Transforms; + OutFrame.Curves = Frames[FrameIndex].Curves; + bBuiltFrame = true; + break; + } + else + { + LastReadFrame = FrameIndex; + const FLiveLinkFrame& PreFrame = Frames[FrameIndex]; + const FLiveLinkFrame& PostFrame = Frames[FrameIndex + 1]; + + // Calc blend weight (Amount through frame gap / frame gap) + const float BlendWeight = (LastReadTime - PreFrame.TimeCode.Time) / (PostFrame.TimeCode.Time - PreFrame.TimeCode.Time); + + Blend(PreFrame.Transforms, PostFrame.Transforms, OutFrame.Transforms, BlendWeight); + Blend(PreFrame.Curves, PostFrame.Curves, OutFrame.Curves, BlendWeight); + + bBuiltFrame = true; + break; + } + } + } + + if (!bBuiltFrame) + { + LastReadFrame = 0; + // Failed to find an interp point so just take earliest frame + OutFrame.Transforms = Frames[0].Transforms; + OutFrame.Curves = Frames[0].Curves; + } + } } FLiveLinkClient::~FLiveLinkClient() @@ -30,70 +225,199 @@ FLiveLinkClient::~FLiveLinkClient() for (int32 Idx = ToRemove.Num() - 1; Idx >= 0; --Idx) { - delete Sources[Idx]; Sources.RemoveAtSwap(ToRemove[Idx],1,false); } } } -void FLiveLinkClient::AddSource(ILiveLinkSource* InSource) +void FLiveLinkClient::Tick(float DeltaTime) +{ + if (LastValidationCheck < FPlatformTime::Seconds() - VALIDATE_SOURCES_TIME) + { + ValidateSources(); + } + + BuildThisTicksSubjectSnapshot(); +} + +void FLiveLinkClient::ValidateSources() +{ + bool bSourcesChanged = false; + for (int32 SourceIdx = Sources.Num() - 1; SourceIdx >= 0; --SourceIdx) + { + if (!Sources[SourceIdx]->IsSourceStillValid()) + { + RemoveSourceInternal(SourceIdx); + + bSourcesChanged = true; + } + } + + for (int32 SourceIdx = SourcesToRemove.Num()-1; SourceIdx >= 0; --SourceIdx) + { + if (SourcesToRemove[SourceIdx]->RequestSourceShutdown()) + { + SourcesToRemove.RemoveAtSwap(SourceIdx, 1, false); + } + } + + LastValidationCheck = FPlatformTime::Seconds(); + + if (bSourcesChanged) + { + OnLiveLinkSourcesChanged.Broadcast(); + } +} + +void FLiveLinkClient::BuildThisTicksSubjectSnapshot() +{ + TArray OldSubjectSnapshotNames; + ActiveSubjectSnapshots.GenerateKeyArray(OldSubjectSnapshotNames); + + const double CurrentInterpTime = FPlatformTime::Seconds(); // Set this up once, every subject + // uses the same time + + { + FScopeLock Lock(&SubjectDataAccessCriticalSection); + + for (TPair& SubjectPair : LiveSubjectData) + { + const FName SubjectName = SubjectPair.Key; + OldSubjectSnapshotNames.RemoveSingleSwap(SubjectName, false); + + FLiveLinkSubject& SourceSubject = SubjectPair.Value; + + FLiveLinkConnectionSettings* SubjectConnectionSettings = GetConnectionSettingsForEntry(SourceSubject.LastModifier); + if (SubjectConnectionSettings) + { + SourceSubject.CachedConnectionSettings = *SubjectConnectionSettings; + } + + if (SourceSubject.Frames.Num() > 0) + { + FLiveLinkSubjectFrame& SnapshotSubject = ActiveSubjectSnapshots.FindOrAdd(SubjectName); + + SourceSubject.BuildInterpolatedFrame(CurrentInterpTime, SnapshotSubject); + } + } + } + + for (FName SubjectName : OldSubjectSnapshotNames) + { + ActiveSubjectSnapshots.Remove(SubjectName); + } +} + +void FLiveLinkClient::AddSource(TSharedPtr InSource) { Sources.Add(InSource); SourceGuids.Add(FGuid::NewGuid()); + ConnectionSettings.AddDefaulted(); - InSource->ReceiveClient(this); + InSource->ReceiveClient(this, SourceGuids.Last()); } +void FLiveLinkClient::RemoveSourceInternal(int32 SourceIdx) +{ + Sources.RemoveAtSwap(SourceIdx, 1, false); + SourceGuids.RemoveAtSwap(SourceIdx, 1, false); + ConnectionSettings.RemoveAtSwap(SourceIdx, 1, false); +} + +void FLiveLinkClient::RemoveSource(FGuid InEntryGuid) +{ + LastValidationCheck = 0.0; //Force validation check next frame + int32 SourceIdx = GetSourceIndexForGUID(InEntryGuid); + if (SourceIdx != INDEX_NONE) + { + SourcesToRemove.Add(Sources[SourceIdx]); + RemoveSourceInternal(SourceIdx); + OnLiveLinkSourcesChanged.Broadcast(); + } +} + +void FLiveLinkClient::RemoveAllSources() +{ + LastValidationCheck = 0.0; //Force validation check next frame + SourcesToRemove = Sources; + Sources.Reset(); + SourceGuids.Reset(); + ConnectionSettings.Reset(); + OnLiveLinkSourcesChanged.Broadcast(); +} + +FLiveLinkTimeCode FLiveLinkClient::MakeTimeCode(double InTime, int32 InFrameNum) const +{ + FLiveLinkTimeCode TC = MakeTimeCodeFromTimeOnly(InTime); + TC.FrameNum = InFrameNum; + return TC; +} + +FLiveLinkTimeCode FLiveLinkClient::MakeTimeCodeFromTimeOnly(double InTime) const +{ + FLiveLinkTimeCode TC; + TC.Time = InTime; + TC.Offset = FPlatformTime::Seconds() - InTime; + return TC; +} + + void FLiveLinkClient::PushSubjectSkeleton(FName SubjectName, const FLiveLinkRefSkeleton& RefSkeleton) { FScopeLock Lock(&SubjectDataAccessCriticalSection); - if (FSubjectData* SubjectData = Subjects.Find(SubjectName)) + if (FLiveLinkSubject* Subject = LiveSubjectData.Find(SubjectName)) { - //LIVELINK TODO - //Handle subject hierarchy changing + Subject->Frames.Reset(); + Subject->RefSkeleton = RefSkeleton; } else { - Subjects.Emplace(SubjectName, FSubjectData(RefSkeleton)); + LiveSubjectData.Emplace(SubjectName, FLiveLinkSubject(RefSkeleton)); } } -void FLiveLinkClient::PushSubjectData(FName SubjectName, const TArray& Transforms) +void FLiveLinkClient::ClearSubject(FName SubjectName) { FScopeLock Lock(&SubjectDataAccessCriticalSection); - if (FSubjectData* SubjectData = Subjects.Find(SubjectName)) - { - SubjectData->TransformData.PushTransformData(Transforms); - } + LiveSubjectData.Remove(SubjectName); } -bool FLiveLinkClient::GetSubjectData(FName SubjectName, TArray& OutTransforms, FLiveLinkRefSkeleton& OutRefSkeleton) +void FLiveLinkClient::PushSubjectData(FGuid SourceGuid, FName SubjectName, const TArray& Transforms, const TArray& CurveElements, const FLiveLinkTimeCode& TimeCode) { FScopeLock Lock(&SubjectDataAccessCriticalSection); - if (FSubjectData* SubjectData = Subjects.Find(SubjectName)) + if (FLiveLinkSubject* Subject = LiveSubjectData.Find(SubjectName)) { - if (SubjectData->TransformData.HasTransformData()) - { - OutTransforms = SubjectData->TransformData.GetTransformData(); - OutRefSkeleton = SubjectData->RefSkeleton; - return true; - } + Subject->AddFrame(Transforms, CurveElements, TimeCode, SourceGuid); } - return false; } -ILiveLinkSource* FLiveLinkClient::GetSourceForGUID(FGuid InEntryGuid) const +const FLiveLinkSubjectFrame* FLiveLinkClient::GetSubjectData(FName SubjectName) { - int32 Idx = SourceGuids.IndexOfByKey(InEntryGuid); + if (FLiveLinkSubjectFrame* Subject = ActiveSubjectSnapshots.Find(SubjectName)) + { + return Subject; + } + return nullptr; +} + +int32 FLiveLinkClient::GetSourceIndexForGUID(FGuid InEntryGuid) const +{ + return SourceGuids.IndexOfByKey(InEntryGuid); +} + +TSharedPtr FLiveLinkClient::GetSourceForGUID(FGuid InEntryGuid) const +{ + int32 Idx = GetSourceIndexForGUID(InEntryGuid); return Idx != INDEX_NONE ? Sources[Idx] : nullptr; } FText FLiveLinkClient::GetSourceTypeForEntry(FGuid InEntryGuid) const { - if (ILiveLinkSource* Source = GetSourceForGUID(InEntryGuid)) + TSharedPtr Source = GetSourceForGUID(InEntryGuid); + if (Source.IsValid()) { return Source->GetSourceType(); } @@ -102,7 +426,8 @@ FText FLiveLinkClient::GetSourceTypeForEntry(FGuid InEntryGuid) const FText FLiveLinkClient::GetMachineNameForEntry(FGuid InEntryGuid) const { - if (ILiveLinkSource* Source = GetSourceForGUID(InEntryGuid)) + TSharedPtr Source = GetSourceForGUID(InEntryGuid); + if (Source.IsValid()) { return Source->GetSourceMachineName(); } @@ -111,9 +436,26 @@ FText FLiveLinkClient::GetMachineNameForEntry(FGuid InEntryGuid) const FText FLiveLinkClient::GetEntryStatusForEntry(FGuid InEntryGuid) const { - if (ILiveLinkSource* Source = GetSourceForGUID(InEntryGuid)) + TSharedPtr Source = GetSourceForGUID(InEntryGuid); + if (Source.IsValid()) { return Source->GetSourceStatus(); } return FText(NSLOCTEXT("TempLocTextLiveLink","InvalidSourceStatus", "Invalid Source Status")); } + +FLiveLinkConnectionSettings* FLiveLinkClient::GetConnectionSettingsForEntry(FGuid InEntryGuid) +{ + const int32 SourceIndex = GetSourceIndexForGUID(InEntryGuid); + return (SourceIndex != INDEX_NONE) ? &ConnectionSettings[SourceIndex] : nullptr; +} + +FDelegateHandle FLiveLinkClient::RegisterSourcesChangedHandle(const FLiveLinkSourcesChanged::FDelegate& SourcesChanged) +{ + return OnLiveLinkSourcesChanged.Add(SourcesChanged); +} + +void FLiveLinkClient::UnregisterSourcesChangedHandle(FDelegateHandle Handle) +{ + OnLiveLinkSourcesChanged.Remove(Handle); +} diff --git a/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/LiveLinkClientPanel.cpp b/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/LiveLinkClientPanel.cpp index 3993c0842960..5ccb07035b17 100644 --- a/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/LiveLinkClientPanel.cpp +++ b/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/LiveLinkClientPanel.cpp @@ -15,6 +15,9 @@ #include "LiveLinkClient.h" #include "UObjectHash.h" #include "EditorStyleSet.h" +#include "ModuleManager.h" +#include "PropertyEditorModule.h" +#include "IStructureDetailsView.h" #include "LiveLinkSourceFactory.h" @@ -35,6 +38,8 @@ public: FText GetSourceType() { return Client->GetSourceTypeForEntry(EntryGuid); } FText GetMachineName() { return Client->GetMachineNameForEntry(EntryGuid); } FText GetEntryStatus() { return Client->GetEntryStatusForEntry(EntryGuid); } + FLiveLinkConnectionSettings* GetConnectionSettings() { return Client->GetConnectionSettingsForEntry(EntryGuid); } + void RemoveFromClient() { Client->RemoveSource(EntryGuid); } private: FGuid EntryGuid; @@ -113,7 +118,11 @@ private: SLiveLinkClientPanel::~SLiveLinkClientPanel() { - + if (Client) + { + Client->UnregisterSourcesChangedHandle(OnSourcesChangedHandle); + OnSourcesChangedHandle.Reset(); + } } void SLiveLinkClientPanel::Construct(const FArguments& Args, FLiveLinkClient* InClient) @@ -121,6 +130,8 @@ void SLiveLinkClientPanel::Construct(const FArguments& Args, FLiveLinkClient* In check(InClient); Client = InClient; + OnSourcesChangedHandle = Client->RegisterSourcesChangedHandle(FLiveLinkSourcesChanged::FDelegate::CreateSP(this, &SLiveLinkClientPanel::OnSourcesChangedHandler)); + RefreshSourceData(false); CommandList = MakeShareable(new FUICommandList); @@ -147,6 +158,19 @@ void SLiveLinkClientPanel::Construct(const FArguments& Args, FLiveLinkClient* In } ToolBarBuilder.EndSection(); + // Connection Settings + FPropertyEditorModule& PropertyEditorModule = FModuleManager::GetModuleChecked("PropertyEditor"); + + FDetailsViewArgs DetailsViewArgs; + //DetailsViewArgs. + FStructureDetailsViewArgs StructureViewArgs; + StructureViewArgs.bShowAssets = true; + StructureViewArgs.bShowClasses = true; + StructureViewArgs.bShowInterfaces = true; + StructureViewArgs.bShowObjects = true; + + StructureDetailsView = PropertyEditorModule.CreateStructureDetailView(DetailsViewArgs, StructureViewArgs, nullptr); + ChildSlot [ SNew(SSplitter) @@ -162,7 +186,7 @@ void SLiveLinkClientPanel::Construct(const FArguments& Args, FLiveLinkClient* In ToolBarBuilder.MakeWidget() ] + SVerticalBox::Slot() - .FillHeight(1.0f) + .FillHeight(0.5f) .Padding(FMargin(0.0f, 4.0f, 0.0f, 0.0f)) [ SNew(SBorder) @@ -198,6 +222,12 @@ void SLiveLinkClientPanel::Construct(const FArguments& Args, FLiveLinkClient* In ] ] ] + + SVerticalBox::Slot() + .FillHeight(0.5f) + .Padding(FMargin(0.0f, 4.0f, 0.0f, 0.0f)) + [ + StructureDetailsView->GetWidget().ToSharedRef() + ] ] ]; @@ -249,7 +279,15 @@ TSharedRef SLiveLinkClientPanel::MakeSourceListViewWidget(FLiveLinkSo void SLiveLinkClientPanel::OnSourceListSelectionChanged(FLiveLinkSourceUIEntryPtr Entry, ESelectInfo::Type SelectionType) const { - + if(Entry.IsValid()) + { + FStructOnScope* Struct = new FStructOnScope(FLiveLinkConnectionSettings::StaticStruct(), (uint8*)Entry->GetConnectionSettings()); + StructureDetailsView->SetStructureData(MakeShareable(Struct)); + } + else + { + StructureDetailsView->SetStructureData(nullptr); + } } TSharedRef< SWidget > SLiveLinkClientPanel::GenerateSourceMenu() @@ -320,18 +358,18 @@ void SLiveLinkClientPanel::RetrieveFactorySourcePanel(FMenuBuilder& MenuBuilder, FReply SLiveLinkClientPanel::OnCloseSourceSelectionPanel(ULiveLinkSourceFactory* FactoryCDO, bool bMakeSource) { - ILiveLinkSource* Source = FactoryCDO->OnSourceCreationPanelClosed(bMakeSource); + TSharedPtr Source = FactoryCDO->OnSourceCreationPanelClosed(bMakeSource); // If we want a source we should get one ... if we dont we shouldn't. Make sure source factory does the right thing in both cases if (bMakeSource) { - check(Source); + check(Source.IsValid()); Client->AddSource(Source); RefreshSourceData(true); } else { - check(!Source); + check(!Source.IsValid()); } FSlateApplication::Get().DismissAllMenus(); return FReply::Handled(); @@ -339,7 +377,12 @@ FReply SLiveLinkClientPanel::OnCloseSourceSelectionPanel(ULiveLinkSourceFactory* void SLiveLinkClientPanel::HandleRemoveSource() { - + TArray Selected; + ListView->GetSelectedItems(Selected); + if (Selected.Num() > 0) + { + Selected[0]->RemoveFromClient(); + } } bool SLiveLinkClientPanel::CanRemoveSource() @@ -349,7 +392,12 @@ bool SLiveLinkClientPanel::CanRemoveSource() void SLiveLinkClientPanel::HandleRemoveAllSources() { + Client->RemoveAllSources(); +} +void SLiveLinkClientPanel::OnSourcesChangedHandler() +{ + RefreshSourceData(true); } #undef LOCTEXT_NAMESPACE \ No newline at end of file diff --git a/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/LiveLinkClientPanel.h b/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/LiveLinkClientPanel.h index c1a97faffcd0..080154645076 100644 --- a/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/LiveLinkClientPanel.h +++ b/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/LiveLinkClientPanel.h @@ -48,8 +48,10 @@ private: void HandleRemoveAllSources(); -private: + // Registered with the client and called when clients sources changes + void OnSourcesChangedHandler(); +private: const TArray& GetCurrentSources() const; TSharedRef MakeSourceListViewWidget(FLiveLinkSourceUIEntryPtr Entry, const TSharedRef& OwnerTable) const; @@ -65,4 +67,10 @@ private: FLiveLinkClient* Client; TMap> SourcePanels; + + // Reference to connection settings struct details panel + TSharedPtr StructureDetailsView; + + // Handle to delegate registered with client so we can update when a source disappears + FDelegateHandle OnSourcesChangedHandle; }; \ No newline at end of file diff --git a/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/LiveLinkMessageBusSource.cpp b/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/LiveLinkMessageBusSource.cpp index 270f647fb670..811162379c51 100644 --- a/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/LiveLinkMessageBusSource.cpp +++ b/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/LiveLinkMessageBusSource.cpp @@ -6,31 +6,62 @@ #include "MessageEndpointBuilder.h" -void FLiveLinkMessageBusSource::ReceiveClient(ILiveLinkClient* InClient) +void FLiveLinkMessageBusSource::ReceiveClient(ILiveLinkClient* InClient, FGuid InSourceGuid) { Client = InClient; + SourceGuid = InSourceGuid; - MessageEndpoint = FMessageEndpoint::Builder(TEXT("LiveLinkMessageBusSource")) - .Handling(this, &FLiveLinkMessageBusSource::HandleSubjectData) - .Handling(this, &FLiveLinkMessageBusSource::HandleSubjectFrame); + MessageEndpoint = FMessageEndpoint::Builder(TEXT("LiveLinkMessageBusSource")) + .Handling(this, &FLiveLinkMessageBusSource::HandleSubjectData) + .Handling(this, &FLiveLinkMessageBusSource::HandleSubjectFrame) + .Handling(this, &FLiveLinkMessageBusSource::HandleHeartbeat) + .Handling(this, &FLiveLinkMessageBusSource::HandleClearSubject); - MessageEndpoint->Send(new FLiveLinkConnect(), ConnectionAddress); + MessageEndpoint->Send(new FLiveLinkConnectMessage(), ConnectionAddress); } +const double LL_CONNECTION_TIMEOUT = 15.0; +const double LL_HALF_CONNECTION_TIMEOUT = LL_CONNECTION_TIMEOUT / 2.0; + bool FLiveLinkMessageBusSource::IsSourceStillValid() { + const double CurrentTime = FPlatformTime::Seconds(); + + if (HeartbeatLastSent > (CurrentTime - LL_HALF_CONNECTION_TIMEOUT) && + ConnectionLastActive < (CurrentTime - LL_CONNECTION_TIMEOUT) ) + { + //We have recently tried to heartbeat and not received anything back + return false; + } + MessageEndpoint->Send(new FLiveLinkHeartbeatMessage(), ConnectionAddress); + HeartbeatLastSent = CurrentTime; + + //Don't know that connection is dead yet return true; } +void FLiveLinkMessageBusSource::HandleHeartbeat(const FLiveLinkHeartbeatMessage& Message, const IMessageContextRef& Context) +{ + ConnectionLastActive = FPlatformTime::Seconds(); +} + +void FLiveLinkMessageBusSource::HandleClearSubject(const FLiveLinkClearSubject& Message, const IMessageContextRef& Context) +{ + ConnectionLastActive = FPlatformTime::Seconds(); + Client->ClearSubject(Message.SubjectName); +} + bool FLiveLinkMessageBusSource::RequestSourceShutdown() { FMessageEndpoint::SafeRelease(MessageEndpoint); return true; } -void FLiveLinkMessageBusSource::HandleSubjectData(const FLiveLinkSubjectData& Message, const IMessageContextRef& Context) +void FLiveLinkMessageBusSource::HandleSubjectData(const FLiveLinkSubjectDataMessage& Message, const IMessageContextRef& Context) { + ConnectionLastActive = FPlatformTime::Seconds(); + //FPlatformMisc::LowLevelOutputDebugStringf(TEXT("HandleSubjectData %s\n"), *Message.SubjectName); /*for (const FString& Name : Message.BoneNames) { @@ -57,12 +88,13 @@ void FLiveLinkMessageBusSource::HandleSubjectData(const FLiveLinkSubjectData& Me UE_LOG(LogTemp, Warning, TEXT("INVALID BONE NAMES RECIEVED %i != existing %i"), Message.BoneNames.Num(), BoneNames.Num()); }*/ - static FName SubjectName(TEXT("Maya")); - Client->PushSubjectSkeleton(SubjectName, Message.RefSkeleton); + Client->PushSubjectSkeleton(Message.SubjectName, Message.RefSkeleton); } -void FLiveLinkMessageBusSource::HandleSubjectFrame(const FLiveLinkSubjectFrame& Message, const IMessageContextRef& Context) +void FLiveLinkMessageBusSource::HandleSubjectFrame(const FLiveLinkSubjectFrameMessage& Message, const IMessageContextRef& Context) { + ConnectionLastActive = FPlatformTime::Seconds(); + //FPlatformMisc::LowLevelOutputDebugString(TEXT("HandleSubjectFrame\n")); /*if (BoneID != Message.BoneID) { @@ -73,6 +105,6 @@ void FLiveLinkMessageBusSource::HandleSubjectFrame(const FLiveLinkSubjectFrame& FPlatformMisc::LowLevelOutputDebugStringf(TEXT("\tTransform: %s\n"), *T.ToString()); }*/ - static FName SubjectName(TEXT("Maya")); - Client->PushSubjectData(SubjectName, Message.Transforms); + FLiveLinkTimeCode TC = Client->MakeTimeCode(Message.Time, Message.FrameNum); + Client->PushSubjectData(SourceGuid, Message.SubjectName, Message.Transforms, Message.Curves, TC); } \ No newline at end of file diff --git a/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/LiveLinkMessageBusSourceEditor.cpp b/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/LiveLinkMessageBusSourceEditor.cpp index 714c450f91cc..b40e321ea576 100644 --- a/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/LiveLinkMessageBusSourceEditor.cpp +++ b/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/LiveLinkMessageBusSourceEditor.cpp @@ -66,12 +66,12 @@ SLiveLinkMessageBusSourceEditor::~SLiveLinkMessageBusSourceEditor() void SLiveLinkMessageBusSourceEditor::Construct(const FArguments& Args) { MessageEndpoint = FMessageEndpoint::Builder(TEXT("LiveLinkMessageBusSource")) - .Handling(this, &SLiveLinkMessageBusSourceEditor::HandlePongMessage); + .Handling(this, &SLiveLinkMessageBusSourceEditor::HandlePongMessage); CurrentPollRequest = FGuid::NewGuid(); //Simple each for connections till UI comes along - MessageEndpoint->Publish(new FLiveLinkPing(CurrentPollRequest)); + MessageEndpoint->Publish(new FLiveLinkPingMessage(CurrentPollRequest)); ChildSlot [ @@ -108,7 +108,7 @@ void SLiveLinkMessageBusSourceEditor::OnSourceListSelectionChanged(FProviderPoll SelectedResult = PollResult; } -void SLiveLinkMessageBusSourceEditor::HandlePongMessage(const FLiveLinkPong& Message, const IMessageContextRef& Context) +void SLiveLinkMessageBusSourceEditor::HandlePongMessage(const FLiveLinkPongMessage& Message, const IMessageContextRef& Context) { if(Message.PollRequest == CurrentPollRequest) { diff --git a/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/LiveLinkMessageBusSourceEditor.h b/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/LiveLinkMessageBusSourceEditor.h index 7aecfd09c21f..21817ed127c7 100644 --- a/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/LiveLinkMessageBusSourceEditor.h +++ b/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/LiveLinkMessageBusSourceEditor.h @@ -9,7 +9,7 @@ #include "Widgets/DeclarativeSyntaxSupport.h" #include "Guid.h" -struct FLiveLinkPong; +struct FLiveLinkPongMessage; struct FMessageAddress; class ITableRow; class STableViewBase; @@ -47,7 +47,7 @@ class SLiveLinkMessageBusSourceEditor : public SCompoundWidget private: - void HandlePongMessage(const FLiveLinkPong& Message, const IMessageContextRef& Context); + void HandlePongMessage(const FLiveLinkPongMessage& Message, const IMessageContextRef& Context); TSharedRef MakeSourceListViewWidget(FProviderPollResultPtr PollResult, const TSharedRef& OwnerTable) const; diff --git a/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/LiveLinkMessageBusSourceFactory.cpp b/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/LiveLinkMessageBusSourceFactory.cpp index 7d7908f088ae..bb301c9465ac 100644 --- a/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/LiveLinkMessageBusSourceFactory.cpp +++ b/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Private/LiveLinkMessageBusSourceFactory.cpp @@ -24,17 +24,17 @@ TSharedPtr ULiveLinkMessageBusSourceFactory::CreateSourceCreationPanel( return ActiveSourceEditor; } -ILiveLinkSource* ULiveLinkMessageBusSourceFactory::OnSourceCreationPanelClosed(bool bMakeSource) +TSharedPtr ULiveLinkMessageBusSourceFactory::OnSourceCreationPanelClosed(bool bMakeSource) { //Clean up - FLiveLinkMessageBusSource* NewSource = nullptr; + TSharedPtr NewSource = nullptr; if (bMakeSource && ActiveSourceEditor.IsValid()) { FProviderPollResultPtr Result = ActiveSourceEditor->GetSelectedSource(); if(Result.IsValid()) { - NewSource = new FLiveLinkMessageBusSource(FText::FromString(Result->Name), FText::FromString(Result->MachineName), Result->Address); + NewSource = MakeShareable( new FLiveLinkMessageBusSource(FText::FromString(Result->Name), FText::FromString(Result->MachineName), Result->Address)); } } ActiveSourceEditor = nullptr; diff --git a/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Public/AnimNode_LiveLinkPose.h b/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Public/AnimNode_LiveLinkPose.h index c48a6355f51f..ac041e265526 100644 --- a/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Public/AnimNode_LiveLinkPose.h +++ b/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Public/AnimNode_LiveLinkPose.h @@ -10,7 +10,7 @@ class ILiveLinkClient; #include "AnimNode_LiveLinkPose.generated.h" -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct LIVELINK_API FAnimNode_LiveLinkPose : public FAnimNode_Base { GENERATED_USTRUCT_BODY() diff --git a/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Public/LiveLinkClient.h b/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Public/LiveLinkClient.h index 338595e454a5..ff53a422bc47 100644 --- a/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Public/LiveLinkClient.h +++ b/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Public/LiveLinkClient.h @@ -4,78 +4,154 @@ #include "Transform.h" #include "CriticalSection.h" +#include "TickableEditorObject.h" #include "ILiveLinkClient.h" #include "ILiveLinkSource.h" #include "LiveLinkRefSkeleton.h" +#include "LiveLinkTypes.h" +#include "LiveLinkConnectionSettings.h" -struct FLiveLinkTransformData +/** Delegate called when the state the client sources has changed. */ +DECLARE_MULTICAST_DELEGATE(FLiveLinkSourcesChanged); + +struct FLiveLinkFrame { public: + TArray Transforms; + TArray Curves; - const TArray& GetTransformData(); + FLiveLinkTimeCode TimeCode; - bool HasTransformData() const { return Transforms.Num() > 0; } - - void PushTransformData(const TArray& InTransforms) + void ExtendCurveData(int32 ExtraCurves) { - if (Transforms.Num() == 0) - { - Transforms.Add(InTransforms); - } - else - { - Transforms.Last() = InTransforms; - } + Curves.AddDefaulted(ExtraCurves); } -private: - - TArray> Transforms; }; -struct FSubjectData +struct FLiveLinkSubject { -public: + // Ref Skeleton for transforms FLiveLinkRefSkeleton RefSkeleton; - - FLiveLinkTransformData TransformData; - FSubjectData(const FLiveLinkRefSkeleton& InRefSkeleton) + // Key for storing curve data (Names) + FLiveLinkCurveKey CurveKeyData; + + // Subject data frames that we have received (transforms and curve values) + TArray Frames; + + // Time difference between current system time and TimeCode times + double SubjectTimeOffset; + + // Last time we read a frame from this subject. Used to determine whether any new incoming + // frames are useable + double LastReadTime; + + //Cache of the last frame we read from, Used for frame cleanup + int32 LastReadFrame; + + // Guid to track the last live link source that modified us + FGuid LastModifier; + + // Connection settings specified by user + FLiveLinkConnectionSettings CachedConnectionSettings; + + FLiveLinkSubject(const FLiveLinkRefSkeleton& InRefSkeleton) : RefSkeleton(InRefSkeleton) {} + + FLiveLinkSubject() + {} + + // Add a frame of data to the subject + void AddFrame(const TArray& Transforms, const TArray& CurveElements, const FLiveLinkTimeCode& TimeCode, FGuid FrameSource); + + // Populate OutFrame with a frame based off of the supplied time and our own offsets + void BuildInterpolatedFrame(const double InSeconds, FLiveLinkSubjectFrame& OutFrame); }; -class FLiveLinkClient : public ILiveLinkClient +class FLiveLinkClient : public ILiveLinkClient, public FTickableEditorObject { public: - FLiveLinkClient() {} + FLiveLinkClient() : LastValidationCheck(0.0) {} ~FLiveLinkClient(); - void AddSource(ILiveLinkSource* InSource); + // Begin FTickableObjectBase implementation + virtual bool IsTickable() const override { return true; } + virtual void Tick(float DeltaTime) override; + virtual TStatId GetStatId() const override { RETURN_QUICK_DECLARE_CYCLE_STAT(LiveLinkClient, STATGROUP_Tickables); } + // End FTickableObjectBase - virtual void PushSubjectSkeleton(FName SubjectName, const FLiveLinkRefSkeleton& RefSkeleton); + // Add a new live link source to the client + void AddSource(TSharedPtr InSource); - virtual void PushSubjectData(FName SubjectName, const TArray& Transforms); + // Remove the specified source from the live link client + void RemoveSource(FGuid InEntryGuid); - virtual bool GetSubjectData(FName SubjectName, TArray& OutTransforms, FLiveLinkRefSkeleton& OutRefSkeleton); + // Remover all sources from the live link client + void RemoveAllSources(); + + // ILiveLinkClient Interface + virtual FLiveLinkTimeCode MakeTimeCode(double InTime, int32 InFrameNum) const; + virtual FLiveLinkTimeCode MakeTimeCodeFromTimeOnly(double InTime) const; + + virtual void PushSubjectSkeleton(FName SubjectName, const FLiveLinkRefSkeleton& RefSkeleton) override; + virtual void ClearSubject(FName SubjectName) override; + virtual void PushSubjectData(FGuid SourceGuid, FName SubjectName, const TArray& Transforms, const TArray& CurveElements, const FLiveLinkTimeCode& TimeCode) override; + // End ILiveLinkClient Interface + + virtual const FLiveLinkSubjectFrame* GetSubjectData(FName SubjectName) override; - const TArray& GetSources() const { return Sources; } const TArray& GetSourceEntries() const { return SourceGuids; } FText GetSourceTypeForEntry(FGuid InEntryGuid) const; FText GetMachineNameForEntry(FGuid InEntryGuid) const; FText GetEntryStatusForEntry(FGuid InEntryGuid) const; + + FLiveLinkConnectionSettings* GetConnectionSettingsForEntry(FGuid InEntryGuid); + + // Functions for managing sources changed delegate + FDelegateHandle RegisterSourcesChangedHandle(const FLiveLinkSourcesChanged::FDelegate& SourcesChanged); + void UnregisterSourcesChangedHandle(FDelegateHandle Handle); + private: - ILiveLinkSource* GetSourceForGUID(FGuid InEntryGuid) const; + // Remove the specified source (must be a valid index, function does no checking) + void RemoveSourceInternal(int32 SourceIdx); + + // Get index of specified source + int32 GetSourceIndexForGUID(FGuid InEntryGuid) const; + + // Get specified live link source + TSharedPtr GetSourceForGUID(FGuid InEntryGuid) const; + + // Test currently added sources to make sure they are still valid + void ValidateSources(); + + // Build subject data so that during the rest of the tick it can be read without + // thread locking or mem copying + void BuildThisTicksSubjectSnapshot(); // Current streamed data for subjects - TMap Subjects; + TMap LiveSubjectData; + + // Built snapshot of streamed subject data (updated once a tick) + TMap ActiveSubjectSnapshots; // Current Sources - TArray Sources; + TArray> Sources; TArray SourceGuids; + TArray ConnectionSettings; + // Sources that we are currently trying to remove + TArray> SourcesToRemove; + // Cache last time we checked the validity of our sources + double LastValidationCheck; + + // Lock to stop multiple threads accessing the subject data map at the same time FCriticalSection SubjectDataAccessCriticalSection; + + // Delegate to notify interested parties when the client sources have changed + FLiveLinkSourcesChanged OnLiveLinkSourcesChanged; }; \ No newline at end of file diff --git a/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Public/LiveLinkConnectionSettings.h b/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Public/LiveLinkConnectionSettings.h new file mode 100644 index 000000000000..3dbeb21141f9 --- /dev/null +++ b/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Public/LiveLinkConnectionSettings.h @@ -0,0 +1,23 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" + +#include "LiveLinkConnectionSettings.generated.h" + +USTRUCT() +struct FLiveLinkConnectionSettings +{ + GENERATED_USTRUCT_BODY() + + FLiveLinkConnectionSettings() : bUseInterpolation(false), InterpolationOffset(0.5f) {} + + // Should this connection use interpolation + UPROPERTY(EditAnywhere, Category = Settings) + bool bUseInterpolation; + + // When interpolating: how far back from current time should we read the buffer (in seconds) + UPROPERTY(EditAnywhere, Category = Settings) + float InterpolationOffset; +}; \ No newline at end of file diff --git a/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Public/LiveLinkMessageBusSource.h b/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Public/LiveLinkMessageBusSource.h index fd0ef9c96768..7a3b329fe893 100644 --- a/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Public/LiveLinkMessageBusSource.h +++ b/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Public/LiveLinkMessageBusSource.h @@ -7,9 +7,11 @@ #include "IMessageContext.h" class ILiveLinkClient; -struct FLiveLinkPong; -struct FLiveLinkSubjectData; -struct FLiveLinkSubjectFrame; +struct FLiveLinkPongMessage; +struct FLiveLinkSubjectDataMessage; +struct FLiveLinkSubjectFrameMessage; +struct FLiveLinkHeartbeatMessage; +struct FLiveLinkClearSubject; class FLiveLinkMessageBusSource : public ILiveLinkSource { @@ -19,9 +21,11 @@ public: : ConnectionAddress(InConnectionAddress) , SourceType(InSourceType) , SourceMachineName(InSourceMachineName) + , HeartbeatLastSent(0.0) + , ConnectionLastActive(0.0) {} - virtual void ReceiveClient(ILiveLinkClient* InClient); + virtual void ReceiveClient(ILiveLinkClient* InClient, FGuid InSourceGuid); void Connect(FMessageAddress& Address); @@ -35,11 +39,18 @@ public: private: - void HandleSubjectData(const FLiveLinkSubjectData& Message, const IMessageContextRef& Context); - void HandleSubjectFrame(const FLiveLinkSubjectFrame& Message, const IMessageContextRef& Context); + // Message bus message handlers + void HandleSubjectData(const FLiveLinkSubjectDataMessage& Message, const IMessageContextRef& Context); + void HandleSubjectFrame(const FLiveLinkSubjectFrameMessage& Message, const IMessageContextRef& Context); + void HandleHeartbeat(const FLiveLinkHeartbeatMessage& Message, const IMessageContextRef& Context); + void HandleClearSubject(const FLiveLinkClearSubject& Message, const IMessageContextRef& Context); + // End Message bus message handlers ILiveLinkClient* Client; + // Our identifier in LiveLink + FGuid SourceGuid; + FMessageEndpointPtr MessageEndpoint; FMessageAddress ConnectionAddress; @@ -47,4 +58,10 @@ private: FText SourceType; FText SourceMachineName; FText SourceStatus; + + // Time we last sent connection heartbeat + double HeartbeatLastSent; + + // Time we last recieved anything + double ConnectionLastActive; }; \ No newline at end of file diff --git a/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Public/LiveLinkMessageBusSourceFactory.h b/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Public/LiveLinkMessageBusSourceFactory.h index 25fdf0d47631..ae77a132ab66 100644 --- a/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Public/LiveLinkMessageBusSourceFactory.h +++ b/Engine/Plugins/Experimental/LiveLink/Source/LiveLink/Public/LiveLinkMessageBusSourceFactory.h @@ -19,7 +19,7 @@ public: virtual FText GetSourceTooltip() const; virtual TSharedPtr CreateSourceCreationPanel(); - virtual ILiveLinkSource* OnSourceCreationPanelClosed(bool bMakeSource); + virtual TSharedPtr OnSourceCreationPanelClosed(bool bMakeSource); TSharedPtr ActiveSourceEditor; }; \ No newline at end of file diff --git a/Engine/Plugins/Experimental/OSVR/Source/OSVR/Private/OSVRHMD.cpp b/Engine/Plugins/Experimental/OSVR/Source/OSVR/Private/OSVRHMD.cpp index 4e3611f49325..ee8c7d22bf3d 100644 --- a/Engine/Plugins/Experimental/OSVR/Source/OSVR/Private/OSVRHMD.cpp +++ b/Engine/Plugins/Experimental/OSVR/Source/OSVR/Private/OSVRHMD.cpp @@ -677,7 +677,7 @@ bool FOSVRHMD::IsHeadTrackingAllowed() const if (GIsEditor) { UEditorEngine* EdEngine = Cast(GEngine); - bool ret = /*Session->IsActive() && */(!EdEngine || (GEnableVREditorHacks || EdEngine->bUseVRPreviewForPlayWorld) || GetDefault()->ViewportGetsHMDControl) && GEngine->IsStereoscopic3D(); + bool ret = /*Session->IsActive() && */(!EdEngine || (GEnableVREditorHacks || EdEngine->bUseVRPreviewForPlayWorld) || GetDefault()->ViewportGetsHMDControl) && GEngine && GEngine->IsStereoscopic3D(); return ret; } #endif diff --git a/Engine/Plugins/Experimental/RawInput/Source/RawInput/Public/RawInputSettings.h b/Engine/Plugins/Experimental/RawInput/Source/RawInput/Public/RawInputSettings.h index f83c28cff5ea..0ddd4aac7b54 100644 --- a/Engine/Plugins/Experimental/RawInput/Source/RawInput/Public/RawInputSettings.h +++ b/Engine/Plugins/Experimental/RawInput/Source/RawInput/Public/RawInputSettings.h @@ -4,6 +4,7 @@ #include "CoreMinimal.h" #include "Engine/DeveloperSettings.h" +#include "InputCoreTypes.h" #include "RawInputSettings.generated.h" diff --git a/Engine/Plugins/Experimental/SimpleHMD/Source/SimpleHMD/Private/SimpleHMD.h b/Engine/Plugins/Experimental/SimpleHMD/Source/SimpleHMD/Private/SimpleHMD.h index 8618a5f8451e..3e4c9cd97d55 100644 --- a/Engine/Plugins/Experimental/SimpleHMD/Source/SimpleHMD/Private/SimpleHMD.h +++ b/Engine/Plugins/Experimental/SimpleHMD/Source/SimpleHMD/Private/SimpleHMD.h @@ -105,5 +105,3 @@ private: void GetCurrentPose(FQuat& CurrentOrientation); }; - -DEFINE_LOG_CATEGORY_STATIC(LogHMD, Log, All); diff --git a/Engine/Plugins/Experimental/StructBox/Source/StructBox/Classes/StructBoxLibrary.h b/Engine/Plugins/Experimental/StructBox/Source/StructBox/Classes/StructBoxLibrary.h index f78b275c6b68..00c47ff116a2 100644 --- a/Engine/Plugins/Experimental/StructBox/Source/StructBox/Classes/StructBoxLibrary.h +++ b/Engine/Plugins/Experimental/StructBox/Source/StructBox/Classes/StructBoxLibrary.h @@ -11,7 +11,7 @@ #include "StructBox.h" #include "StructBoxLibrary.generated.h" -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct FStubStruct { GENERATED_USTRUCT_BODY() diff --git a/Engine/Plugins/Media/AndroidMedia/Source/AndroidMedia/Private/Player/AndroidMediaPlayer.cpp b/Engine/Plugins/Media/AndroidMedia/Source/AndroidMedia/Private/Player/AndroidMediaPlayer.cpp index 7c58751d345a..f10d6e8423fb 100644 --- a/Engine/Plugins/Media/AndroidMedia/Source/AndroidMedia/Private/Player/AndroidMediaPlayer.cpp +++ b/Engine/Plugins/Media/AndroidMedia/Source/AndroidMedia/Private/Player/AndroidMediaPlayer.cpp @@ -2,7 +2,7 @@ #include "AndroidMediaPlayer.h" #include "AndroidJavaMediaPlayer.h" -#include "AndroidJavaMediaPlayer.h" +#include "Misc/CoreDelegates.h" #include "Misc/Paths.h" #include "Android/AndroidFile.h" #include "../AndroidMediaLog.h" @@ -33,6 +33,26 @@ FAndroidMediaPlayer::~FAndroidMediaPlayer() } +void FAndroidMediaPlayer::AppServicePause() +{ + // check state in case changed before ticked + if ((State == EMediaState::Playing) && JavaMediaPlayer.IsValid()) + { + JavaMediaPlayer->Pause(); + } +} + + +void FAndroidMediaPlayer::AppServiceResume() +{ + // check state in case changed before ticked + if ((State == EMediaState::Playing) && JavaMediaPlayer.IsValid()) + { + JavaMediaPlayer->Start(); + } +} + + /* IMediaControls interface *****************************************************************************/ @@ -168,6 +188,18 @@ bool FAndroidMediaPlayer::SupportsSeeking() const void FAndroidMediaPlayer::Close() { + // remove delegates if registered + if (ResumeHandle.IsValid()) + { + FCoreDelegates::ApplicationHasEnteredForegroundDelegate.Remove(ResumeHandle); + ResumeHandle.Reset(); + } + if (PauseHandle.IsValid()) + { + FCoreDelegates::ApplicationWillEnterBackgroundDelegate.Remove(PauseHandle); + PauseHandle.Reset(); + } + if (State == EMediaState::Closed) { return; @@ -329,9 +361,32 @@ void FAndroidMediaPlayer::TickPlayer(float DeltaTime) { if (State != EMediaState::Playing) { + // remove delegates if registered + if (ResumeHandle.IsValid()) + { + FCoreDelegates::ApplicationHasEnteredForegroundDelegate.Remove(ResumeHandle); + ResumeHandle.Reset(); + } + + if (PauseHandle.IsValid()) + { + FCoreDelegates::ApplicationWillEnterBackgroundDelegate.Remove(PauseHandle); + PauseHandle.Reset(); + } + return; } + // register delegate if not registered + if (!ResumeHandle.IsValid()) + { + ResumeHandle = FCoreDelegates::ApplicationHasEnteredForegroundDelegate.AddRaw(this, &FAndroidMediaPlayer::AppServiceResume); + } + if (!PauseHandle.IsValid()) + { + PauseHandle = FCoreDelegates::ApplicationWillEnterBackgroundDelegate.AddRaw(this, &FAndroidMediaPlayer::AppServicePause); + } + Tracks.Tick(); if (!JavaMediaPlayer->IsPlaying()) diff --git a/Engine/Plugins/Media/AndroidMedia/Source/AndroidMedia/Private/Player/AndroidMediaPlayer.h b/Engine/Plugins/Media/AndroidMedia/Source/AndroidMedia/Private/Player/AndroidMediaPlayer.h index 51b46b70aab8..54bf8f338958 100644 --- a/Engine/Plugins/Media/AndroidMedia/Source/AndroidMedia/Private/Player/AndroidMediaPlayer.h +++ b/Engine/Plugins/Media/AndroidMedia/Source/AndroidMedia/Private/Player/AndroidMediaPlayer.h @@ -68,6 +68,8 @@ public: } private: + void AppServicePause(); + void AppServiceResume(); /** The Java side media interface. */ TSharedPtr JavaMediaPlayer; @@ -86,4 +88,8 @@ private: /** Track collection. */ FAndroidMediaTracks Tracks; + + /** Foreground/background delegates */ + FDelegateHandle PauseHandle; + FDelegateHandle ResumeHandle; }; diff --git a/Engine/Plugins/Media/MfMedia/Source/MfMedia/Private/Player/MfMediaTracks.cpp b/Engine/Plugins/Media/MfMedia/Source/MfMedia/Private/Player/MfMediaTracks.cpp index b094e1c7dc0d..50b4d5a5f6ba 100644 --- a/Engine/Plugins/Media/MfMedia/Source/MfMedia/Private/Player/MfMediaTracks.cpp +++ b/Engine/Plugins/Media/MfMedia/Source/MfMedia/Private/Player/MfMediaTracks.cpp @@ -5,7 +5,6 @@ #if MFMEDIA_SUPPORTED_PLATFORM #include "MfMediaUtils.h" -#include "MfMediaVideoSampler.h" #if PLATFORM_WINDOWS #include "WindowsHWrapper.h" @@ -66,31 +65,15 @@ FMfMediaTracks::FMfMediaTracks() , AudioDone(true) , CaptionDone(true) , Enabled(false) - , VideoSampler(new FMfMediaVideoSampler(CriticalSection)) + , VideoDone(true) { - VideoSampler->OnFrame().BindRaw(this, &FMfMediaTracks::HandleVideoSamplerFrame); - - ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER( - FRegisterMediaVideoSamplerCommand, - FMfMediaVideoSampler*, VideoSampler, VideoSampler, - { - VideoSampler->Register(); - }); } FMfMediaTracks::~FMfMediaTracks() { - Reset(); - - ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER( - FUnregisterMediaVideoSamplerCommand, - FMfMediaVideoSampler*, VideoSampler, VideoSampler, - { - delete VideoSampler; - }); - VideoSampler = nullptr; FlushRenderingCommands(); + Reset(); } @@ -129,16 +112,7 @@ void FMfMediaTracks::Reinitialize() { AudioDone = (AudioTracks.Num() == 0); CaptionDone = (CaptionTracks.Num() == 0); - - VideoSampler->Stop(); - if (VideoTracks.Num() > 0) - { - VideoSampler->Start(SourceReader); - if (VideoTracks.IsValidIndex(SelectedVideoTrack)) - { - VideoSampler->SetStreamIndex(VideoTracks[SelectedVideoTrack].StreamIndex); - } - } + VideoDone = (VideoTracks.Num() == 0); } @@ -146,8 +120,6 @@ void FMfMediaTracks::Reset() { FScopeLock Lock(&CriticalSection); - VideoSampler->Stop(); - SelectedAudioTrack = INDEX_NONE; SelectedCaptionTrack = INDEX_NONE; SelectedVideoTrack = INDEX_NONE; @@ -173,6 +145,7 @@ void FMfMediaTracks::Reset() AudioDone = true; CaptionDone = true; + VideoDone = true; Enabled = false; SourceReader = nullptr; @@ -184,11 +157,6 @@ void FMfMediaTracks::SetEnabled(bool InEnabled) FScopeLock Lock(&CriticalSection); Enabled = InEnabled; - if (VideoSampler != nullptr) - { - VideoSampler->SetEnabled(Enabled); - } - if (AudioSink != nullptr) { if (InEnabled) @@ -212,6 +180,93 @@ void FMfMediaTracks::Tick(float DeltaTime) return; } + // Check if new video sample(s) required + if (VideoTracks.IsValidIndex(SelectedVideoTrack) && !VideoDone) + { + FVideoTrack& VideoTrack = VideoTracks[SelectedVideoTrack]; + + // Decrease the time remaining on the currently displayed sample by the passage of time + VideoTrack.SecondsUntilNextSample -= DeltaTime; + + // Read through samples until we catch up + IMFSample* Sample = NULL; + LONGLONG Timestamp = 0; + while (VideoTrack.SecondsUntilNextSample <= 0) + { + SAFE_RELEASE(Sample); + + DWORD StreamFlags = 0; + HRESULT Result = SourceReader->ReadSample(VideoTrack.StreamIndex, 0, NULL, &StreamFlags, &Timestamp, &Sample); + if (FAILED(Result)) + { + UE_LOG(LogMfMedia, Warning, TEXT("Messed up (%s)"), *MfMedia::ResultToString(Result)); + Sample = NULL; + break; + } + if (StreamFlags & MF_SOURCE_READERF_ENDOFSTREAM) + { + VideoDone = true; + SAFE_RELEASE(Sample); + break; + } + if (StreamFlags & MF_SOURCE_READERF_NATIVEMEDIATYPECHANGED) + { + //@TODO + } + if (Sample != NULL) + { + LONGLONG SampleDuration; + Sample->GetSampleDuration(&SampleDuration); + FTimespan Time(SampleDuration); + VideoTrack.SecondsUntilNextSample += Time.GetTotalSeconds(); + } + } + + // Process sample into content + if (Sample != NULL) + { + if (VideoSink != nullptr) + { + // get buffer data + TComPtr Buffer; + if (SUCCEEDED(Sample->ConvertToContiguousBuffer(&Buffer))) + { + DWORD Length; + Buffer->GetCurrentLength(&Length); + + // The video sink needs to be updated on the render thread. + // The render thread takes ownership of the sample and is responsible for releasing it in this case. + // ReadSample gives us samples from a queue provided by the decoder. It's ok for us to hold onto + // this sample even if we ReadSample again before the render thread releases this sample. + ENQUEUE_UNIQUE_RENDER_COMMAND_FOURPARAMETER( + FUpdateMediaTextureCommand, + TComPtr, Buffer, Buffer, + LONGLONG, Timestamp, Timestamp, + IMediaTextureSink*, VideoSink, VideoSink, + IMFSample*, Sample, Sample, + { + uint8* Data = nullptr; + if (SUCCEEDED(Buffer->Lock(&Data, nullptr, nullptr))) + { + VideoSink->UpdateTextureSinkBuffer(Data); + VideoSink->DisplayTextureSinkBuffer(FTimespan(Timestamp)); + Buffer->Unlock(); + SAFE_RELEASE(Sample); + } + }); + } + else + { + SAFE_RELEASE(Sample); + } + } + else + { + SAFE_RELEASE(Sample); + } + } + } + // Check if new audio sample(s) required if (AudioTracks.IsValidIndex(SelectedAudioTrack) && !AudioDone) { @@ -613,7 +668,6 @@ bool FMfMediaTracks::SelectTrack(EMediaTrackType TrackType, int32 TrackIndex) SourceReader->SetStreamSelection(VideoTracks[TrackIndex].StreamIndex, TRUE); } SelectedVideoTrack = TrackIndex; - VideoSampler->SetStreamIndex(VideoTracks[TrackIndex].StreamIndex); InitializeVideoSink(); } @@ -751,6 +805,7 @@ void FMfMediaTracks::AddStreamToTracks(uint32 StreamIndex, IMFPresentationDescri return; } + bool MediaFound = false; if (NumSupportedTypes > 0) { for (DWORD TypeIndex = 0; TypeIndex < NumSupportedTypes; ++TypeIndex) @@ -758,12 +813,13 @@ void FMfMediaTracks::AddStreamToTracks(uint32 StreamIndex, IMFPresentationDescri if (SUCCEEDED(Handler->GetMediaTypeByIndex(TypeIndex, &MediaType)) && SUCCEEDED(Handler->SetCurrentMediaType(MediaType))) { + MediaFound = true; break; } } } - if (MediaType == NULL) + if (MediaType == NULL || !MediaFound) { UE_LOG(LogMfMedia, Warning, TEXT("No supported media type in stream %i of type %s"), StreamIndex, *MfMedia::MajorTypeToString(MajorType)); OutInfo += TEXT(" unsupported media type\n"); @@ -865,7 +921,7 @@ void FMfMediaTracks::AddStreamToTracks(uint32 StreamIndex, IMFPresentationDescri { #if PLATFORM_XBOXONE // filter unsupported video types (XboxOne only supports H.264) - if ((SubType != MFVideoFormat_H264) && (SubType == MFVideoFormat_H264_ES)) + if ((SubType != MFVideoFormat_H264) && (SubType != MFVideoFormat_H264_ES)) { UE_LOG(LogMfMedia, Warning, TEXT("Unsupported video type '%s' (%s) for stream %i"), *MfMediaTracks::FourccToString(SubType.Data1), *MfMediaTracks::GuidToString(SubType), StreamIndex); OutInfo += TEXT(" unsupported SubType\n"); @@ -1072,20 +1128,6 @@ void FMfMediaTracks::InitializeVideoSink() VideoSink->InitializeTextureSink(VideoTrack.OutputDim, VideoTrack.BufferDim, VideoTrack.SinkFormat, EMediaTextureSinkMode::Unbuffered); } -/* FMfMediaStreamCollection callbacks -*****************************************************************************/ - -void FMfMediaTracks::HandleVideoSamplerFrame(int32 StreamIndex, const uint8* Data, const FTimespan& Time) -{ - FScopeLock Lock(&CriticalSection); - - if (VideoSink) - { - VideoSink->UpdateTextureSinkBuffer(Data); - VideoSink->DisplayTextureSinkBuffer(Time); - } -} - #undef LOCTEXT_NAMESPACE diff --git a/Engine/Plugins/Media/MfMedia/Source/MfMedia/Private/Player/MfMediaTracks.h b/Engine/Plugins/Media/MfMedia/Source/MfMedia/Private/Player/MfMediaTracks.h index f4eeacd5f4c5..7a2181b87112 100644 --- a/Engine/Plugins/Media/MfMedia/Source/MfMedia/Private/Player/MfMediaTracks.h +++ b/Engine/Plugins/Media/MfMedia/Source/MfMedia/Private/Player/MfMediaTracks.h @@ -151,14 +151,6 @@ protected: /** Initialize the current video sink. */ void InitializeVideoSink(); -private: - - /** Callback for handling new frames from the video sampler. */ - void HandleVideoSamplerFrame(int32 StreamIndex, const uint8* Data, const FTimespan& Time); - - /** Callback for when the video sampler reaches the end of the stream. */ - void HandleVideoSamplerDone(int32 StreamIndex); - private: /** The currently used audio sink. */ @@ -212,8 +204,8 @@ private: /** The source reader to use. */ TComPtr SourceReader; - /** Video sampler. */ - class FMfMediaVideoSampler* VideoSampler; + /** Whether the video track has reached the end. */ + bool VideoDone; }; diff --git a/Engine/Plugins/Media/MfMedia/Source/MfMedia/Private/Player/MfMediaVideoSampler.cpp b/Engine/Plugins/Media/MfMedia/Source/MfMedia/Private/Player/MfMediaVideoSampler.cpp deleted file mode 100644 index 7e69ff4df9b8..000000000000 --- a/Engine/Plugins/Media/MfMedia/Source/MfMedia/Private/Player/MfMediaVideoSampler.cpp +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. - -#include "MfMediaVideoSampler.h" -#include "Misc/ScopeLock.h" - -/* FMfMediaVideoSampler structors - *****************************************************************************/ - -FMfMediaVideoSampler::FMfMediaVideoSampler(FCriticalSection& InCriticalSection) - : FTickableObjectRenderThread(false, true) // Do not auto register - , CriticalSection(InCriticalSection) - , StreamIndex(INDEX_NONE) - , SecondsUntilNextSample(0.f) - , bEnabled(false) - , bVideoDone(true) -{ } - - -/* FMfMediaVideoSampler interface - *****************************************************************************/ - -void FMfMediaVideoSampler::Start(IMFSourceReader* InSourceReader) -{ - check(FrameDelegate.IsBound()); - - UE_LOG(LogMfMedia, Verbose, TEXT("Video sampler: Starting")); - - SourceReader = InSourceReader; - StreamIndex = INDEX_NONE; - bEnabled = true; - bVideoDone = false; -} - - -void FMfMediaVideoSampler::Stop() -{ - UE_LOG(LogMfMedia, Verbose, TEXT("Video sampler: Stopping")); - - SourceReader = nullptr; - StreamIndex = INDEX_NONE; - bEnabled = false; - bVideoDone = true; -} - -void FMfMediaVideoSampler::SetStreamIndex(int32 InStreamIndex) -{ - StreamIndex = InStreamIndex; - SecondsUntilNextSample = 0.f; -} - -void FMfMediaVideoSampler::SetEnabled(bool bInEnabled) -{ - bEnabled = bInEnabled; -} - - -/* FTickableObjectRenderThread interface - *****************************************************************************/ - -TStatId FMfMediaVideoSampler::GetStatId() const -{ - RETURN_QUICK_DECLARE_CYCLE_STAT(FMfMediaVideoSampler, STATGROUP_Tickables); -} - - -bool FMfMediaVideoSampler::IsTickable() const -{ - return SourceReader != nullptr && StreamIndex != INDEX_NONE && bEnabled && !bVideoDone; -} - - -void FMfMediaVideoSampler::Tick(float DeltaTime) -{ - FScopeLock Lock(&CriticalSection); - - if (!IsTickable()) - { - return; - } - - // Decrease the time remaining on the currently displayed sample by the passage of time - SecondsUntilNextSample -= DeltaTime; - - // Read through samples until we catch up - IMFSample* Sample = NULL; - LONGLONG Timestamp = 0; - while (SecondsUntilNextSample <= 0) - { - SAFE_RELEASE(Sample); - - DWORD StreamFlags = 0; - if (FAILED(SourceReader->ReadSample(StreamIndex, 0, NULL, &StreamFlags, &Timestamp, &Sample))) - { - Sample = NULL; - break; - } - if (StreamFlags & MF_SOURCE_READERF_ENDOFSTREAM) - { - bVideoDone = true; - SAFE_RELEASE(Sample); - break; - } - if (StreamFlags & MF_SOURCE_READERF_NATIVEMEDIATYPECHANGED) - { - //@TODO - } - if (Sample != NULL) - { - LONGLONG SampleDuration; - Sample->GetSampleDuration(&SampleDuration); - FTimespan Time(SampleDuration); - SecondsUntilNextSample += Time.GetTotalSeconds(); - } - } - - // Process sample into content - if (Sample != NULL) - { - // get buffer data - TComPtr Buffer; - if (SUCCEEDED(Sample->ConvertToContiguousBuffer(&Buffer))) - { - DWORD Length; - Buffer->GetCurrentLength(&Length); - - uint8* Data = nullptr; - if (SUCCEEDED(Buffer->Lock(&Data, nullptr, nullptr))) - { - // forward frame data - FrameDelegate.Execute(StreamIndex, Data, FTimespan(Timestamp)); - Buffer->Unlock(); - } - } - SAFE_RELEASE(Sample); - } -} \ No newline at end of file diff --git a/Engine/Plugins/Media/MfMedia/Source/MfMedia/Private/Player/MfMediaVideoSampler.h b/Engine/Plugins/Media/MfMedia/Source/MfMedia/Private/Player/MfMediaVideoSampler.h deleted file mode 100644 index 0b757aa09e10..000000000000 --- a/Engine/Plugins/Media/MfMedia/Source/MfMedia/Private/Player/MfMediaVideoSampler.h +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "../MfMediaPrivate.h" -#include "TickableObjectRenderThread.h" - -/** Delegate that is executed when a new video frame is ready for display. */ -DECLARE_DELEGATE_ThreeParams(FOnMfMediaVideoSamplerFrame, int32 /*StreamIndex*/, const uint8* /*Data*/, const FTimespan& /*Time*/); - -class FMfMediaVideoSampler - : public FTickableObjectRenderThread -{ -public: - - /** Constructor. */ - FMfMediaVideoSampler(FCriticalSection& InCriticalSection); - - /** Virtual destructor. */ - virtual ~FMfMediaVideoSampler() { } - -public: - - /** - * Get a delegate that is executed when a new video frame is ready for display. - * - * @return The delegate. - */ - FOnMfMediaVideoSamplerFrame& OnFrame() - { - return FrameDelegate; - } - - /** - * Start video sampling. - * - * @see Stop - */ - void Start(IMFSourceReader* InSourceReader); - - /** - * Stop video sampling. - * - * @see Start - */ - void Stop(); - - /** - * Sets the stream index to sample from. Use when changing video tracks - */ - void SetStreamIndex(int32 InStreamIndex); - - /** - * Sets whether we should be sampling from the stream or not. - */ - void SetEnabled(bool bInEnabled); - -public: - - //~ FTickableObjectRenderThread interface - - virtual TStatId GetStatId() const override; - virtual bool IsTickable() const override; - virtual void Tick(float DeltaTime) override; - -private: - - /** The critical section used to handle timing between the render and game thread. This is the same critical section as on FMfMediaTracks */ - FCriticalSection& CriticalSection; - - /** The source reader to use. */ - TComPtr SourceReader; - - /** The stream index to sample from */ - int32 StreamIndex; - - /** Time before the next sampling */ - float SecondsUntilNextSample; - - /** If true, we will sample from the stream */ - uint32 bEnabled:1; - - /** If true, we have reached the end of the stream */ - uint32 bVideoDone:1; - - /** Delegate that is executed when a new video frame is ready for display. */ - FOnMfMediaVideoSamplerFrame FrameDelegate; -}; diff --git a/Engine/Plugins/Media/WmfMedia/Source/WmfMedia/Private/Player/WmfMediaTracks.cpp b/Engine/Plugins/Media/WmfMedia/Source/WmfMedia/Private/Player/WmfMediaTracks.cpp index 8584e6b7b70f..c007c9b08906 100644 --- a/Engine/Plugins/Media/WmfMedia/Source/WmfMedia/Private/Player/WmfMediaTracks.cpp +++ b/Engine/Plugins/Media/WmfMedia/Source/WmfMedia/Private/Player/WmfMediaTracks.cpp @@ -990,7 +990,6 @@ void FWmfMediaTracks::AddStreamToTracks(uint32 StreamIndex, IMFMediaSource& InMe const bool Uncompressed = (SubType == MFVideoFormat_RGB555) || (SubType == MFVideoFormat_RGB565) || - (SubType == MFVideoFormat_RGB565) || (SubType == MFVideoFormat_RGB24) || (SubType == MFVideoFormat_RGB32) || (SubType == MFVideoFormat_ARGB32); diff --git a/Engine/Plugins/Media/WmfMedia/Source/WmfMedia/Private/Wmf/WmfMediaResolveState.h b/Engine/Plugins/Media/WmfMedia/Source/WmfMedia/Private/Wmf/WmfMediaResolveState.h index fa97e5730e90..e37e540930f3 100644 --- a/Engine/Plugins/Media/WmfMedia/Source/WmfMedia/Private/Wmf/WmfMediaResolveState.h +++ b/Engine/Plugins/Media/WmfMedia/Source/WmfMedia/Private/Wmf/WmfMediaResolveState.h @@ -27,7 +27,7 @@ enum class EWmfMediaResolveType /** * Implements media source resolve state information. */ -struct FWmfMediaResolveState +struct FWmfMediaResolveState final : public IUnknown { /** The type of the media source being resolved. */ @@ -46,6 +46,9 @@ public: , RefCount(0) { } + virtual ~FWmfMediaResolveState() + { } + public: /** Invalidate the resolve state (resolve events will no longer be forwarded). */ diff --git a/Engine/Plugins/Media/WmfMedia/Source/WmfMedia/Private/Wmf/WmfMediaResolver.cpp b/Engine/Plugins/Media/WmfMedia/Source/WmfMedia/Private/Wmf/WmfMediaResolver.cpp index 264392170eef..4f3a5f6c4dd8 100644 --- a/Engine/Plugins/Media/WmfMedia/Source/WmfMedia/Private/Wmf/WmfMediaResolver.cpp +++ b/Engine/Plugins/Media/WmfMedia/Source/WmfMedia/Private/Wmf/WmfMediaResolver.cpp @@ -23,6 +23,9 @@ FWmfMediaResolver::FWmfMediaResolver() } } +FWmfMediaResolver::~FWmfMediaResolver() +{ +} /* WmfMediaUrlResolver interface *****************************************************************************/ diff --git a/Engine/Plugins/Media/WmfMedia/Source/WmfMedia/Private/Wmf/WmfMediaResolver.h b/Engine/Plugins/Media/WmfMedia/Source/WmfMedia/Private/Wmf/WmfMediaResolver.h index e5598339382d..7ec58907d565 100644 --- a/Engine/Plugins/Media/WmfMedia/Source/WmfMedia/Private/Wmf/WmfMediaResolver.h +++ b/Engine/Plugins/Media/WmfMedia/Source/WmfMedia/Private/Wmf/WmfMediaResolver.h @@ -15,13 +15,14 @@ struct FWmfMediaResolveState; /** * Implements an asynchronous callback object for resolving media URLs. */ -class FWmfMediaResolver +class FWmfMediaResolver final : public IMFAsyncCallback { public: /** Default constructor. */ FWmfMediaResolver(); + virtual ~FWmfMediaResolver(); public: diff --git a/Engine/Plugins/MovieScene/ActorSequenceEditor/Source/ActorSequenceEditor/Private/ActorSequenceComponentCustomization.cpp b/Engine/Plugins/MovieScene/ActorSequenceEditor/Source/ActorSequenceEditor/Private/ActorSequenceComponentCustomization.cpp index 1a0ee3ddb2cc..a0fdc90c696e 100644 --- a/Engine/Plugins/MovieScene/ActorSequenceEditor/Source/ActorSequenceEditor/Private/ActorSequenceComponentCustomization.cpp +++ b/Engine/Plugins/MovieScene/ActorSequenceEditor/Source/ActorSequenceEditor/Private/ActorSequenceComponentCustomization.cpp @@ -15,13 +15,59 @@ #include "BlueprintEditorTabs.h" #include "ScopedTransaction.h" #include "ISequencerModule.h" +#include "Editor.h" #include "ActorSequenceEditorTabSummoner.h" +#include "IPropertyUtilities.h" #include "Widgets/Input/SButton.h" #define LOCTEXT_NAMESPACE "ActorSequenceComponentCustomization" FName SequenceTabId("EmbeddedSequenceID"); +class SActorSequenceEditorWidgetWrapper : public SActorSequenceEditorWidget +{ +public: + ~SActorSequenceEditorWidgetWrapper() + { + GEditor->OnObjectsReplaced().Remove(OnObjectsReplacedHandle); + } + + void Construct(const FArguments& InArgs, TWeakObjectPtr InSequenceComponent) + { + SActorSequenceEditorWidget::Construct(InArgs, nullptr); + + WeakSequenceComponent = InSequenceComponent; + AssignSequence(GetActorSequence()); + + OnObjectsReplacedHandle = GEditor->OnObjectsReplaced().AddSP(this, &SActorSequenceEditorWidgetWrapper::OnObjectsReplaced); + } + +protected: + + UActorSequence* GetActorSequence() const + { + UActorSequenceComponent* SequenceComponent = WeakSequenceComponent.Get(); + return SequenceComponent ? SequenceComponent->GetSequence() : nullptr; + } + + void OnObjectsReplaced(const TMap& ReplacementMap) + { + UActorSequenceComponent* Component = WeakSequenceComponent.Get(true); + + UActorSequenceComponent* NewSequenceComponent = Component ? Cast(ReplacementMap.FindRef(Component)) : nullptr; + if (NewSequenceComponent) + { + WeakSequenceComponent = NewSequenceComponent; + AssignSequence(GetActorSequence()); + } + } + +private: + + TWeakObjectPtr WeakSequenceComponent; + FDelegateHandle OnObjectsReplacedHandle; +}; + TSharedRef FActorSequenceComponentCustomization::MakeInstance() { return MakeShared(); @@ -29,6 +75,8 @@ TSharedRef FActorSequenceComponentCustomization::MakeInsta void FActorSequenceComponentCustomization::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) { + PropertyUtilities = DetailBuilder.GetPropertyUtilities(); + TArray> Objects; DetailBuilder.GetObjectsBeingCustomized(Objects); if (Objects.Num() != 1) @@ -50,10 +98,21 @@ void FActorSequenceComponentCustomization::CustomizeDetails(IDetailLayoutBuilder IDetailCategoryBuilder& Category = DetailBuilder.EditCategory("Sequence", FText(), ECategoryPriority::Important); + bool bIsExternalTabAlreadyOpened = false; + if (HostTabManager.IsValid() && HostTabManager->CanSpawnTab(SequenceTabId)) { WeakTabManager = HostTabManager; + TSharedPtr ExistingTab = HostTabManager->FindExistingLiveTab(SequenceTabId); + if (ExistingTab.IsValid()) + { + UActorSequence* ThisSequence = GetActorSequence(); + + auto SequencerWidget = StaticCastSharedRef(ExistingTab->GetContent()); + bIsExternalTabAlreadyOpened = ThisSequence && SequencerWidget->GetSequence() == ThisSequence; + } + Category.AddCustomRow(FText()) .NameContent() [ @@ -67,18 +126,15 @@ void FActorSequenceComponentCustomization::CustomizeDetails(IDetailLayoutBuilder .OnClicked(this, &FActorSequenceComponentCustomization::InvokeSequencer) [ SNew(STextBlock) - .Text(LOCTEXT("OpenSequenceTabButtonText", "Open in Tab")) + .Text(bIsExternalTabAlreadyOpened ? LOCTEXT("FocusSequenceTabButtonText", "Focus Tab") : LOCTEXT("OpenSequenceTabButtonText", "Open in Tab")) .Font(DetailBuilder.GetDetailFont()) ] ]; } // Only display an inline editor for non-blueprint sequences - if (!GetActorSequence()->GetParentBlueprint()) + if (!GetActorSequence()->GetParentBlueprint() && !bIsExternalTabAlreadyOpened) { - TSharedRef ActorSequenceEditorWidget = SNew(SActorSequenceEditorWidget, nullptr); - ActorSequenceEditorWidget->AssignSequence(GetActorSequence()); - Category.AddCustomRow(FText()) .WholeRowContent() .MaxDesiredWidth(TOptional()) @@ -86,7 +142,7 @@ void FActorSequenceComponentCustomization::CustomizeDetails(IDetailLayoutBuilder SAssignNew(InlineSequencer, SBox) .HeightOverride(300) [ - ActorSequenceEditorWidget + SNew(SActorSequenceEditorWidgetWrapper, WeakSequenceComponent) ] ]; } @@ -97,16 +153,38 @@ FReply FActorSequenceComponentCustomization::InvokeSequencer() TSharedPtr TabManager = WeakTabManager.Pin(); if (TabManager.IsValid() && TabManager->CanSpawnTab(SequenceTabId)) { + TSharedRef Tab = TabManager->InvokeTab(SequenceTabId); + + { + // Set up a delegate that forces a refresh of this panel when the tab is closed to ensure we see the inline widget + TWeakPtr WeakUtilities = PropertyUtilities; + auto OnClosed = [WeakUtilities](TSharedRef) + { + TSharedPtr PinnedPropertyUtilities = WeakUtilities.Pin(); + if (PinnedPropertyUtilities.IsValid()) + { + PinnedPropertyUtilities->EnqueueDeferredAction(FSimpleDelegate::CreateSP(PinnedPropertyUtilities.ToSharedRef(), &IPropertyUtilities::ForceRefresh)); + } + }; + + Tab->SetOnTabClosed(SDockTab::FOnTabClosedCallback::CreateLambda(OnClosed)); + } + + // Move our inline widget content to the tab (so that we keep the existing sequencer state) if (InlineSequencer.IsValid()) - { + { + Tab->SetContent(InlineSequencer->GetChildren()->GetChildAt(0)); InlineSequencer->SetContent(SNullWidget::NullWidget); InlineSequencer->SetVisibility(EVisibility::Collapsed); } - - TSharedRef Content = TabManager->InvokeTab(SequenceTabId)->GetContent(); - StaticCastSharedRef(Content)->AssignSequence(GetActorSequence()); + else + { + StaticCastSharedRef(Tab->GetContent())->AssignSequence(GetActorSequence()); + } } + PropertyUtilities->ForceRefresh(); + return FReply::Handled(); } diff --git a/Engine/Plugins/MovieScene/ActorSequenceEditor/Source/ActorSequenceEditor/Private/ActorSequenceComponentCustomization.h b/Engine/Plugins/MovieScene/ActorSequenceEditor/Source/ActorSequenceEditor/Private/ActorSequenceComponentCustomization.h index e15d4a793f6a..e1ba346f1dae 100644 --- a/Engine/Plugins/MovieScene/ActorSequenceEditor/Source/ActorSequenceEditor/Private/ActorSequenceComponentCustomization.h +++ b/Engine/Plugins/MovieScene/ActorSequenceEditor/Source/ActorSequenceEditor/Private/ActorSequenceComponentCustomization.h @@ -14,6 +14,7 @@ class UActorSequence; class UActorSequenceComponent; class ISequencer; class FSCSEditorTreeNode; +class IPropertyUtilities; class FActorSequenceComponentCustomization : public IDetailCustomization { @@ -30,4 +31,5 @@ private: TWeakObjectPtr WeakSequenceComponent; TWeakPtr WeakTabManager; TSharedPtr InlineSequencer; + TSharedPtr PropertyUtilities; }; \ No newline at end of file diff --git a/Engine/Plugins/MovieScene/ActorSequenceEditor/Source/ActorSequenceEditor/Private/ActorSequenceEditorTabSummoner.cpp b/Engine/Plugins/MovieScene/ActorSequenceEditor/Source/ActorSequenceEditor/Private/ActorSequenceEditorTabSummoner.cpp index d3b5888757f0..6a7c2e4c1e84 100644 --- a/Engine/Plugins/MovieScene/ActorSequenceEditor/Source/ActorSequenceEditor/Private/ActorSequenceEditorTabSummoner.cpp +++ b/Engine/Plugins/MovieScene/ActorSequenceEditor/Source/ActorSequenceEditor/Private/ActorSequenceEditorTabSummoner.cpp @@ -224,6 +224,39 @@ public: return Sequence ? Sequence->GetDisplayName() : LOCTEXT("DefaultSequencerLabel", "Sequencer"); } + UActorSequence* GetActorSequence() const + { + return WeakSequence.Get(); + } + + UObject* GetPlaybackContext() const + { + UActorSequence* LocalActorSequence = GetActorSequence(); + if (LocalActorSequence) + { + if (AActor* Actor = LocalActorSequence->GetTypedOuter()) + { + return Actor; + } + else if (UBlueprintGeneratedClass* GeneratedClass = LocalActorSequence->GetTypedOuter()) + { + return GeneratedClass->SimpleConstructionScript->GetComponentEditorActorInstance(); + } + } + + return nullptr; + } + + TArray GetEventContexts() const + { + TArray Contexts; + if (auto* Context = GetPlaybackContext()) + { + Contexts.Add(Context); + } + return Contexts; + } + void SetActorSequence(UActorSequence* NewSequence) { if (UActorSequence* OldSequence = WeakSequence.Get()) @@ -269,37 +302,10 @@ public: FSequencerInitParams SequencerInitParams; { TWeakObjectPtr LocalWeakSequence = NewSequence; - auto GetPlaybackContext = - [LocalWeakSequence]() -> UObject* - { - UActorSequence* LocalActorSequence = LocalWeakSequence.Get(); - if (LocalActorSequence) - { - if (AActor* Actor = LocalActorSequence->GetTypedOuter()) - { - return Actor; - } - else if (UBlueprintGeneratedClass* GeneratedClass = LocalActorSequence->GetTypedOuter()) - { - return GeneratedClass->SimpleConstructionScript->GetComponentEditorActorInstance(); - } - } - - return nullptr; - }; SequencerInitParams.RootSequence = NewSequence; - SequencerInitParams.EventContexts = TAttribute>::Create(TAttribute>::FGetter::CreateLambda( - [GetPlaybackContext]{ - TArray Contexts; - if (auto* Context = GetPlaybackContext()) - { - Contexts.Add(Context); - } - return Contexts; - } - )); - SequencerInitParams.PlaybackContext = TAttribute::Create(TAttribute::FGetter::CreateLambda(GetPlaybackContext)); + SequencerInitParams.EventContexts = TAttribute>(this, &SActorSequenceEditorWidgetImpl::GetEventContexts); + SequencerInitParams.PlaybackContext = TAttribute(this, &SActorSequenceEditorWidgetImpl::GetPlaybackContext); TSharedRef AddMenuExtender = MakeShareable(new FExtender); @@ -499,6 +505,11 @@ void SActorSequenceEditorWidget::AssignSequence(UActorSequence* NewActorSequence Impl.Pin()->SetActorSequence(NewActorSequence); } +UActorSequence* SActorSequenceEditorWidget::GetSequence() const +{ + return Impl.Pin()->GetActorSequence(); +} + FActorSequenceEditorSummoner::FActorSequenceEditorSummoner(TSharedPtr BlueprintEditor) : FWorkflowTabFactory("EmbeddedSequenceID", BlueprintEditor) , WeakBlueprintEditor(BlueprintEditor) diff --git a/Engine/Plugins/MovieScene/ActorSequenceEditor/Source/ActorSequenceEditor/Private/ActorSequenceEditorTabSummoner.h b/Engine/Plugins/MovieScene/ActorSequenceEditor/Source/ActorSequenceEditor/Private/ActorSequenceEditorTabSummoner.h index 2e3e0f3946b7..f64a9e47e617 100644 --- a/Engine/Plugins/MovieScene/ActorSequenceEditor/Source/ActorSequenceEditor/Private/ActorSequenceEditorTabSummoner.h +++ b/Engine/Plugins/MovieScene/ActorSequenceEditor/Source/ActorSequenceEditor/Private/ActorSequenceEditorTabSummoner.h @@ -21,6 +21,7 @@ public: void Construct(const FArguments&, TWeakPtr InBlueprintEditor); void AssignSequence(UActorSequence* NewActorSequence); + UActorSequence* GetSequence() const; FText GetDisplayLabel() const; private: diff --git a/Engine/Plugins/MovieScene/LevelSequenceEditor/Source/LevelSequenceEditor/Private/CinematicViewport/SCinematicLevelViewport.cpp b/Engine/Plugins/MovieScene/LevelSequenceEditor/Source/LevelSequenceEditor/Private/CinematicViewport/SCinematicLevelViewport.cpp index 7a24088cceb3..8d7cef031ad2 100644 --- a/Engine/Plugins/MovieScene/LevelSequenceEditor/Source/LevelSequenceEditor/Private/CinematicViewport/SCinematicLevelViewport.cpp +++ b/Engine/Plugins/MovieScene/LevelSequenceEditor/Source/LevelSequenceEditor/Private/CinematicViewport/SCinematicLevelViewport.cpp @@ -526,8 +526,6 @@ void SCinematicLevelViewport::Setup(FLevelSequenceEditorToolkit& NewToolkit) ISequencer* Sequencer = GetSequencer(); if (Sequencer) { - FLevelEditorSequencerIntegration::Get().SetViewportTransportControlsVisibility(false); - TypeInterfaceProxy->Impl = Sequencer->GetZeroPadNumericTypeInterface(); if (TransportRange.IsValid()) diff --git a/Engine/Plugins/MovieScene/LevelSequenceEditor/Source/LevelSequenceEditor/Private/CinematicViewport/SCinematicLevelViewport.h b/Engine/Plugins/MovieScene/LevelSequenceEditor/Source/LevelSequenceEditor/Private/CinematicViewport/SCinematicLevelViewport.h index 0894b9e8267a..575b75138b9a 100644 --- a/Engine/Plugins/MovieScene/LevelSequenceEditor/Source/LevelSequenceEditor/Private/CinematicViewport/SCinematicLevelViewport.h +++ b/Engine/Plugins/MovieScene/LevelSequenceEditor/Source/LevelSequenceEditor/Private/CinematicViewport/SCinematicLevelViewport.h @@ -26,7 +26,11 @@ struct FTypeInterfaceProxy; struct FCinematicViewportClient : FLevelEditorViewportClient { FCinematicViewportClient(); + void SetViewportWidget(const TSharedPtr& InViewportWidget) { EditorViewportWidget = InViewportWidget; } + + /** FLevelEditorViewportClient Interface*/ + virtual bool CanAttachTransportControls() const override { return false; } }; diff --git a/Engine/Plugins/MovieScene/LevelSequenceEditor/Source/LevelSequenceEditor/Private/LevelSequenceEditorModule.cpp b/Engine/Plugins/MovieScene/LevelSequenceEditor/Source/LevelSequenceEditor/Private/LevelSequenceEditorModule.cpp index 899f833b0953..a858e8d57a62 100644 --- a/Engine/Plugins/MovieScene/LevelSequenceEditor/Source/LevelSequenceEditor/Private/LevelSequenceEditorModule.cpp +++ b/Engine/Plugins/MovieScene/LevelSequenceEditor/Source/LevelSequenceEditor/Private/LevelSequenceEditorModule.cpp @@ -208,8 +208,8 @@ protected: { IAssetTools& AssetTools = AssetToolsModule->Get(); - for (auto Action : RegisteredAssetTypeActions) - { + for (auto Action : RegisteredAssetTypeActions) + { AssetTools.UnregisterAssetTypeActions(Action); } } @@ -279,7 +279,7 @@ protected: UFactory* Factory = Cast(CurrentClass->GetDefaultObject()); if (Factory->CanCreateNew() && Factory->ImportPriority >= 0 && Factory->SupportedClass == ULevelSequence::StaticClass()) { - NewAsset = AssetTools.CreateAsset(ULevelSequence::StaticClass(), Factory); + NewAsset = AssetTools.CreateAssetWithDialog(ULevelSequence::StaticClass(), Factory); break; } } diff --git a/Engine/Plugins/MovieScene/LevelSequenceEditor/Source/LevelSequenceEditor/Private/Misc/LevelSequenceEditorActorSpawner.cpp b/Engine/Plugins/MovieScene/LevelSequenceEditor/Source/LevelSequenceEditor/Private/Misc/LevelSequenceEditorActorSpawner.cpp index d9de27cff6d3..ccd1416a6487 100644 --- a/Engine/Plugins/MovieScene/LevelSequenceEditor/Source/LevelSequenceEditor/Private/Misc/LevelSequenceEditorActorSpawner.cpp +++ b/Engine/Plugins/MovieScene/LevelSequenceEditor/Source/LevelSequenceEditor/Private/Misc/LevelSequenceEditorActorSpawner.cpp @@ -80,9 +80,10 @@ TValueOrError FLevelSequenceEditorActorSpawner::CreateNewS } } - AActor* Instance = FactoryToUse->CreateActor(&SourceObject, GWorld->PersistentLevel, FTransform(), RF_NoFlags, TemplateName ); + AActor* Instance = FactoryToUse->CreateActor(&SourceObject, GWorld->PersistentLevel, FTransform(), RF_Transient, TemplateName ); NewSpawnable.ObjectTemplate = StaticDuplicateObject(Instance, &OwnerMovieScene, TemplateName); + NewSpawnable.ObjectTemplate->ClearFlags(RF_Transient); GWorld->DestroyActor(Instance); } diff --git a/Engine/Plugins/MovieScene/LevelSequenceEditor/Source/LevelSequenceEditor/Private/Misc/LevelSequenceEditorSpawnRegister.cpp b/Engine/Plugins/MovieScene/LevelSequenceEditor/Source/LevelSequenceEditor/Private/Misc/LevelSequenceEditorSpawnRegister.cpp index 501b5b9a5628..252d332d3e72 100644 --- a/Engine/Plugins/MovieScene/LevelSequenceEditor/Source/LevelSequenceEditor/Private/Misc/LevelSequenceEditorSpawnRegister.cpp +++ b/Engine/Plugins/MovieScene/LevelSequenceEditor/Source/LevelSequenceEditor/Private/Misc/LevelSequenceEditorSpawnRegister.cpp @@ -316,15 +316,12 @@ TValueOrError FLevelSequenceEditorSpawnRegister::CreateNew void FLevelSequenceEditorSpawnRegister::SetupDefaultsForSpawnable(UObject* SpawnedObject, const FGuid& Guid, const FTransformData& TransformData, TSharedRef Sequencer, USequencerSettings* Settings) { - if (SpawnedObject) + for (TSharedPtr MovieSceneObjectSpawner : MovieSceneObjectSpawners) { - for (TSharedPtr MovieSceneObjectSpawner : MovieSceneObjectSpawners) + if (MovieSceneObjectSpawner->CanSetupDefaultsForSpawnable(SpawnedObject)) { - if (MovieSceneObjectSpawner->CanSetupDefaultsForSpawnable(SpawnedObject)) - { - MovieSceneObjectSpawner->SetupDefaultsForSpawnable(SpawnedObject, Guid, TransformData, Sequencer, Settings); - return; - } + MovieSceneObjectSpawner->SetupDefaultsForSpawnable(SpawnedObject, Guid, TransformData, Sequencer, Settings); + return; } } } diff --git a/Engine/Plugins/NetcodeUnitTest/NUTUnrealEngine4/NUTUnrealEngine4.uplugin b/Engine/Plugins/NetcodeUnitTest/NUTUnrealEngine4/NUTUnrealEngine4.uplugin index de31f53d038c..d16ba135e4f2 100644 --- a/Engine/Plugins/NetcodeUnitTest/NUTUnrealEngine4/NUTUnrealEngine4.uplugin +++ b/Engine/Plugins/NetcodeUnitTest/NUTUnrealEngine4/NUTUnrealEngine4.uplugin @@ -27,5 +27,20 @@ "Linux" ] } + ], + "Plugins": + [ + { + "Name": "OnlineSubsystem", + "Enabled": true + }, + { + "Name": "OnlineSubsystemUtils", + "Enabled": true + }, + { + "Name": "NetcodeUnitTest", + "Enabled": true + } ] } diff --git a/Engine/Plugins/NetcodeUnitTest/NetcodeUnitTest/NetcodeUnitTest.uplugin b/Engine/Plugins/NetcodeUnitTest/NetcodeUnitTest/NetcodeUnitTest.uplugin index 2ceac34ad98d..685084e3a245 100644 --- a/Engine/Plugins/NetcodeUnitTest/NetcodeUnitTest/NetcodeUnitTest.uplugin +++ b/Engine/Plugins/NetcodeUnitTest/NetcodeUnitTest/NetcodeUnitTest.uplugin @@ -27,6 +27,18 @@ "Linux" ] } + ], + + "Plugins": + [ + { + "Name": "OnlineSubsystem", + "Enabled": true + }, + { + "Name": "OnlineSubsystemUtils", + "Enabled": true + } ] } diff --git a/Engine/Plugins/NetcodeUnitTest/NetcodeUnitTest/Source/NetcodeUnitTest/Private/NUTUtilReflection.cpp b/Engine/Plugins/NetcodeUnitTest/NetcodeUnitTest/Source/NetcodeUnitTest/Private/NUTUtilReflection.cpp index 6f4ba2a75128..137a12651d4d 100644 --- a/Engine/Plugins/NetcodeUnitTest/NetcodeUnitTest/Source/NetcodeUnitTest/Private/NUTUtilReflection.cpp +++ b/Engine/Plugins/NetcodeUnitTest/NetcodeUnitTest/Source/NetcodeUnitTest/Private/NUTUtilReflection.cpp @@ -524,10 +524,6 @@ FVMReflection& FVMReflection::operator [](const ANSICHAR* InFieldType) { SetError(TEXT("FieldInstance is NULL.")); } - else if (FieldInstance == NULL) - { - SetError(FString::Printf(TEXT("Field '%s' is NULL."), *FieldInstance->GetName())); - } else if (FieldAddress == NULL) { SetError(TEXT("FieldAddress is NULL (should already be pointing to base property address).")); diff --git a/Engine/Plugins/NetcodeUnitTest/NetcodeUnitTest/Source/NetcodeUnitTest/Private/UnitTestCommandlet.cpp b/Engine/Plugins/NetcodeUnitTest/NetcodeUnitTest/Source/NetcodeUnitTest/Private/UnitTestCommandlet.cpp index 7301c15f5426..2baa8f53f262 100644 --- a/Engine/Plugins/NetcodeUnitTest/NetcodeUnitTest/Source/NetcodeUnitTest/Private/UnitTestCommandlet.cpp +++ b/Engine/Plugins/NetcodeUnitTest/NetcodeUnitTest/Source/NetcodeUnitTest/Private/UnitTestCommandlet.cpp @@ -102,11 +102,10 @@ int32 UUnitTestCommandlet::Main(const FString& Params) { UGameEngine* GameEngine = Cast(GEngine); - // GameInstace = GameEngine->GameInstance; - UGameInstance* GameInstance = GET_PRIVATE(UGameEngine, GameEngine, GameInstance); - if (GameEngine != NULL) { + // GameInstace = GameEngine->GameInstance; + UGameInstance* GameInstance = GET_PRIVATE(UGameEngine, GameEngine, GameInstance); UGameViewportClient* NewViewport = NewObject(GameEngine); FWorldContext* CurContext = GameInstance->GetWorldContext(); diff --git a/Engine/Plugins/NetcodeUnitTest/NetcodeUnitTest/Source/NetcodeUnitTest/Private/UnitTestManager.cpp b/Engine/Plugins/NetcodeUnitTest/NetcodeUnitTest/Source/NetcodeUnitTest/Private/UnitTestManager.cpp index 127bc023f4cf..02d9b755c61e 100644 --- a/Engine/Plugins/NetcodeUnitTest/NetcodeUnitTest/Source/NetcodeUnitTest/Private/UnitTestManager.cpp +++ b/Engine/Plugins/NetcodeUnitTest/NetcodeUnitTest/Source/NetcodeUnitTest/Private/UnitTestManager.cpp @@ -160,7 +160,7 @@ bool UUnitTestManager::QueueUnitTest(UClass* UnitTestClass, bool bRequeued/*=fal UnitTestClass != UClientUnitTest::StaticClass() && UnitTestClass != UProcessUnitTest::StaticClass(); UUnitTest* UnitTestDefault = (bValidUnitTestClass ? Cast(UnitTestClass->GetDefaultObject()) : NULL); - bool bSupportsAllGames = (bValidUnitTestClass ? UnitTestDefault->GetSupportedGames().Contains("NullUnitEnv") : false); + bool bSupportsAllGames = (bValidUnitTestClass ? UnitTestDefault->GetSupportedGames().Contains("NullUnitEnv") : false); //-V595 bValidUnitTestClass = UnitTestDefault != NULL; @@ -1749,7 +1749,7 @@ static bool UnitTestExec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) Ar.Logf(TEXT("Failed to execute unit test command '%s', GUnitTestManager == NULL"), Cmd); } - bReturnVal = true; + bReturnVal = true; //-V519 } /** * For the connection-per-unit-test code, which also creates a whole new world/netdriver etc. per unit test, @@ -1917,7 +1917,7 @@ static bool UnitTestExec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) { uint8* Data = (uint8*)PointerVal; - if (Data != nullptr || DataLen == 0) + if (Data != nullptr && DataLen > 0) { NUTDebug::LogHexDump(Data, DataLen); } diff --git a/Engine/Plugins/Online/Android/OnlineSubsystemGameCircle/Build/Android/Java/src/com/epicgames/ue4/AmazonStoreHelper.java b/Engine/Plugins/Online/Android/OnlineSubsystemGameCircle/Build/Android/Java/src/com/epicgames/ue4/AmazonStoreHelper.java index db4ff57dd550..80b4f8155706 100644 --- a/Engine/Plugins/Online/Android/OnlineSubsystemGameCircle/Build/Android/Java/src/com/epicgames/ue4/AmazonStoreHelper.java +++ b/Engine/Plugins/Online/Android/OnlineSubsystemGameCircle/Build/Android/Java/src/com/epicgames/ue4/AmazonStoreHelper.java @@ -53,10 +53,6 @@ public class AmazonStoreHelper implements StoreHelper, PurchasingListener // Save the product ID that was most recently purchased private String MostRecentPurchaseSku; - // Keep track of purchases that are in progress - private ArrayList InProgressPurchases; - - public enum EAmazonResponseStatus { Successful, @@ -80,8 +76,6 @@ public class AmazonStoreHelper implements StoreHelper, PurchasingListener Log.debug("Registering PurchasingListener"); PurchasingService.registerListener(gameActivity.getApplicationContext(), this); Log.debug("IS_SANDBOX_MODE = " + PurchasingService.IS_SANDBOX_MODE); - - InProgressPurchases = new ArrayList(); } public void OnServiceInitialized() @@ -92,7 +86,7 @@ public class AmazonStoreHelper implements StoreHelper, PurchasingListener //~ Begin StoreHelper interface - public boolean QueryInAppPurchases(String[] ProductIDs, boolean[] bConsumable) + public boolean QueryInAppPurchases(String[] ProductIDs) { if(ProductSkus != null) { @@ -113,13 +107,12 @@ public class AmazonStoreHelper implements StoreHelper, PurchasingListener return true; } - public boolean BeginPurchase(String ProductID, boolean bConsumable) + public boolean BeginPurchase(String ProductID) { - Log.debug("AmazonStoreHelper.BeginPurchase - " + ProductID + ", bConsumable = " + bConsumable); + Log.debug("AmazonStoreHelper.BeginPurchase - " + ProductID); final RequestId requestId = PurchasingService.purchase(ProductID); Log.debug("AmazonStoreHelper.BeginPurchase RequestId = " + requestId); - InProgressPurchases.add(new InAppPurchase(ProductID, bConsumable)); return true; } @@ -212,16 +205,6 @@ public class AmazonStoreHelper implements StoreHelper, PurchasingListener LocalUserData = purchaseResponse.getUserData(); - for(int Idx = 0; Idx < InProgressPurchases.size(); ++Idx) - { - if( receipt.getSku().equals( InProgressPurchases.get(Idx).ProductId ) ) - { - Log.debug("Found InProgressPurchase for Product " + receipt.getSku() + " bConsumable = " + InProgressPurchases.get(Idx).bConsumable); - InProgressPurchases.remove(Idx); - break; - } - } - nativePurchaseComplete(EAmazonResponseStatus.Successful.ordinal(), receipt.getSku(), receipt.toJSON().toString(), receipt.getReceiptId()); PurchasingService.notifyFulfillment(receipt.getReceiptId(), FulfillmentResult.FULFILLED); diff --git a/Engine/Plugins/Online/Android/OnlineSubsystemGameCircle/OnlineSubsystemGameCircle.uplugin b/Engine/Plugins/Online/Android/OnlineSubsystemGameCircle/OnlineSubsystemGameCircle.uplugin index c287eb03e9ec..bd8d8b4a8ec7 100644 --- a/Engine/Plugins/Online/Android/OnlineSubsystemGameCircle/OnlineSubsystemGameCircle.uplugin +++ b/Engine/Plugins/Online/Android/OnlineSubsystemGameCircle/OnlineSubsystemGameCircle.uplugin @@ -38,5 +38,11 @@ "Name": "OnlineSubsystemGameCircle", "LoadingPolicy": "Always" } - ] + ], + "Plugins": [ + { + "Name": "OnlineSubsystem", + "Enabled": true + } + ] } \ No newline at end of file diff --git a/Engine/Plugins/Online/Android/OnlineSubsystemGameCircle/Source/OnlineSubsystemGameCircle/Private/OnlineSubsystemGameCircle.cpp b/Engine/Plugins/Online/Android/OnlineSubsystemGameCircle/Source/OnlineSubsystemGameCircle/Private/OnlineSubsystemGameCircle.cpp index e6d3cf3f05ff..b99bfd0bed5c 100644 --- a/Engine/Plugins/Online/Android/OnlineSubsystemGameCircle/Source/OnlineSubsystemGameCircle/Private/OnlineSubsystemGameCircle.cpp +++ b/Engine/Plugins/Online/Android/OnlineSubsystemGameCircle/Source/OnlineSubsystemGameCircle/Private/OnlineSubsystemGameCircle.cpp @@ -170,6 +170,11 @@ bool FOnlineSubsystemGameCircle::Exec(UWorld* InWorld, const TCHAR* Cmd, FOutput return false; } +FText FOnlineSubsystemGameCircle::GetOnlineServiceName() const +{ + return NSLOCTEXT("OnlineSubsystemGameCircle", "OnlineServiceName", "Amazon GameCircle"); +} + bool FOnlineSubsystemGameCircle::IsEnabled(void) { bool bEnabled = true; diff --git a/Engine/Plugins/Online/Android/OnlineSubsystemGameCircle/Source/OnlineSubsystemGameCircle/Public/OnlineSubsystemGameCircle.h b/Engine/Plugins/Online/Android/OnlineSubsystemGameCircle/Source/OnlineSubsystemGameCircle/Public/OnlineSubsystemGameCircle.h index fb140220c517..d5c229a2e2b3 100644 --- a/Engine/Plugins/Online/Android/OnlineSubsystemGameCircle/Source/OnlineSubsystemGameCircle/Public/OnlineSubsystemGameCircle.h +++ b/Engine/Plugins/Online/Android/OnlineSubsystemGameCircle/Source/OnlineSubsystemGameCircle/Public/OnlineSubsystemGameCircle.h @@ -64,6 +64,7 @@ public: virtual bool Shutdown() override; virtual FString GetAppId() const override; virtual bool Exec(class UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) override; + virtual FText GetOnlineServiceName() const override; //~ End IOnlineSubsystem Interface virtual bool Tick(float DeltaTime) override; diff --git a/Engine/Plugins/Online/Android/OnlineSubsystemGooglePlay/OnlineSubsystemGooglePlay.uplugin b/Engine/Plugins/Online/Android/OnlineSubsystemGooglePlay/OnlineSubsystemGooglePlay.uplugin index 6f7e1dfb42ea..631b27f6bfb1 100644 --- a/Engine/Plugins/Online/Android/OnlineSubsystemGooglePlay/OnlineSubsystemGooglePlay.uplugin +++ b/Engine/Plugins/Online/Android/OnlineSubsystemGooglePlay/OnlineSubsystemGooglePlay.uplugin @@ -26,5 +26,15 @@ "Name": "OnlineSubsystemGooglePlay", "LoadingPolicy": "Always" } + ], + "Plugins": [ + { + "Name": "OnlineSubsystem", + "Enabled": true + }, + { + "Name": "AndroidPermission", + "Enabled": true + } ] } \ No newline at end of file diff --git a/Engine/Plugins/Online/Android/OnlineSubsystemGooglePlay/Source/OnlineSubsystemGooglePlay.Build.cs b/Engine/Plugins/Online/Android/OnlineSubsystemGooglePlay/Source/OnlineSubsystemGooglePlay.Build.cs index bd136ffa8c32..751fbaca2ec8 100644 --- a/Engine/Plugins/Online/Android/OnlineSubsystemGooglePlay/Source/OnlineSubsystemGooglePlay.Build.cs +++ b/Engine/Plugins/Online/Android/OnlineSubsystemGooglePlay/Source/OnlineSubsystemGooglePlay.Build.cs @@ -5,7 +5,7 @@ using UnrealBuildTool; public class OnlineSubsystemGooglePlay : ModuleRules { public OnlineSubsystemGooglePlay(ReadOnlyTargetRules Target) : base(Target) - { + { Definitions.Add("ONLINESUBSYSTEMGOOGLEPLAY_PACKAGE=1"); PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; diff --git a/Engine/Plugins/Online/Android/OnlineSubsystemGooglePlay/Source/Private/OnlineAsyncTaskGooglePlayLogin.cpp b/Engine/Plugins/Online/Android/OnlineSubsystemGooglePlay/Source/Private/OnlineAsyncTaskGooglePlayLogin.cpp index e69d804a2028..c2f5c6fc12e4 100644 --- a/Engine/Plugins/Online/Android/OnlineSubsystemGooglePlay/Source/Private/OnlineAsyncTaskGooglePlayLogin.cpp +++ b/Engine/Plugins/Online/Android/OnlineSubsystemGooglePlay/Source/Private/OnlineAsyncTaskGooglePlayLogin.cpp @@ -64,12 +64,14 @@ void FOnlineAsyncTaskGooglePlayLogin::Start_OnTaskThread() void FOnlineAsyncTaskGooglePlayLogin::Finalize() { + UE_LOG(LogOnline, Log, TEXT("FOnlineAsyncTaskGooglePlayLogin: Finalize.")); // Async task manager owns the task and is responsible for cleaning it up. Subsystem->CurrentLoginTask = nullptr; } void FOnlineAsyncTaskGooglePlayLogin::TriggerDelegates() { + UE_LOG(LogOnline, Log, TEXT("FOnlineAsyncTaskGooglePlayLogin: TriggerDelegates. %d"), bWasSuccessful); Delegate.ExecuteIfBound(); } diff --git a/Engine/Plugins/Online/Android/OnlineSubsystemGooglePlay/Source/Private/OnlineSubsystemGooglePlay.cpp b/Engine/Plugins/Online/Android/OnlineSubsystemGooglePlay/Source/Private/OnlineSubsystemGooglePlay.cpp index bb1256286543..fc47ef5ffb79 100644 --- a/Engine/Plugins/Online/Android/OnlineSubsystemGooglePlay/Source/Private/OnlineSubsystemGooglePlay.cpp +++ b/Engine/Plugins/Online/Android/OnlineSubsystemGooglePlay/Source/Private/OnlineSubsystemGooglePlay.cpp @@ -245,6 +245,11 @@ bool FOnlineSubsystemGooglePlay::Exec(UWorld* InWorld, const TCHAR* Cmd, FOutput return false; } +FText FOnlineSubsystemGooglePlay::GetOnlineServiceName() const +{ + return NSLOCTEXT("OnlineSubsystemGooglePlay", "OnlineServiceName", "Google Play"); +} + bool FOnlineSubsystemGooglePlay::IsEnabled(void) { bool bEnableGooglePlaySupport = true; @@ -365,6 +370,10 @@ void FOnlineSubsystemGooglePlay::OnAuthActionFinished(AuthOperation Op, AuthStat CurrentShowLoginUITask->OnAuthActionFinished(Op, Status); } + else + { + UE_LOG(LogOnline, Log, TEXT("OnAuthActionFinished no handler!")); + } } else if (Op == AuthOperation::SIGN_OUT) { @@ -404,13 +413,15 @@ JNI_METHOD void Java_com_epicgames_ue4_GameActivity_nativeGoogleClientConnectCom jenv->ReleaseStringUTFChars(accessToken, charsToken); } + UE_LOG(LogOnline, Log, TEXT("nativeGoogleClientConnectCompleted Success: %d Token: %s"), bSuccess, *AccessToken); + DECLARE_CYCLE_STAT(TEXT("FSimpleDelegateGraphTask.ProcessGoogleClientConnectResult"), STAT_FSimpleDelegateGraphTask_ProcessGoogleClientConnectResult, STATGROUP_TaskGraphTasks); FSimpleDelegateGraphTask::CreateAndDispatchWhenReady( FSimpleDelegateGraphTask::FDelegate::CreateLambda([=]() { FPlatformMisc::LowLevelOutputDebugStringf(TEXT("Google Client connected %s, Access Token: %s\n"), bSuccess ? TEXT("successfully") : TEXT("unsuccessfully"), *AccessToken); - if (FOnlineSubsystemGooglePlay* const OnlineSub = (FOnlineSubsystemGooglePlay*)IOnlineSubsystem::Get()) + if (FOnlineSubsystemGooglePlay* const OnlineSub = static_cast(IOnlineSubsystem::Get(GOOGLEPLAY_SUBSYSTEM))) { OnlineSub->ProcessGoogleClientConnectResult(bSuccess, AccessToken); } diff --git a/Engine/Plugins/Online/Android/OnlineSubsystemGooglePlay/Source/Public/OnlineSubsystemGooglePlay.h b/Engine/Plugins/Online/Android/OnlineSubsystemGooglePlay/Source/Public/OnlineSubsystemGooglePlay.h index b243e22a128d..6260ceefdbfd 100644 --- a/Engine/Plugins/Online/Android/OnlineSubsystemGooglePlay/Source/Public/OnlineSubsystemGooglePlay.h +++ b/Engine/Plugins/Online/Android/OnlineSubsystemGooglePlay/Source/Public/OnlineSubsystemGooglePlay.h @@ -77,6 +77,8 @@ public: virtual bool Shutdown() override; virtual FString GetAppId() const override; virtual bool Exec(class UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) override; + + virtual FText GetOnlineServiceName() const override; //~ End IOnlineSubsystem Interface virtual bool Tick(float DeltaTime) override; diff --git a/Engine/Plugins/Online/HTTPChunkInstaller/Source/HTTPChunkInstaller.Build.cs b/Engine/Plugins/Online/HTTPChunkInstaller/Source/HTTPChunkInstaller.Build.cs deleted file mode 100644 index 8cc1d3e40640..000000000000 --- a/Engine/Plugins/Online/HTTPChunkInstaller/Source/HTTPChunkInstaller.Build.cs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. - -using UnrealBuildTool; - -public class HTTPChunkInstaller : ModuleRules -{ - public HTTPChunkInstaller(ReadOnlyTargetRules Target) : base(Target) - { - PrivateDependencyModuleNames.AddRange( - new string[] { - "BuildPatchServices", - "Core", - "Engine", - "Http", - "Json", - "PakFile", - } - ); - PrivateIncludePathModuleNames.AddRange( - new string[] { - "OnlineSubsystem", - "OnlineSubsystemUtils" - } - ); - - PrivateIncludePaths.Add("../../../../../Engine/Source/Runtime/Online/BuildPatchServices/Private"); - - //if (Target.Platform != UnrealTargetPlatform.Win64 && Target.Platform != UnrealTargetPlatform.Win32 && Target.Platform != UnrealTargetPlatform.IOS) - { - PrecompileForTargets = PrecompileTargetsType.None; - } - - if (Target.Platform == UnrealTargetPlatform.Android) - { - PrivateDependencyModuleNames.Add("OpenGLDrv"); - AddEngineThirdPartyPrivateStaticDependencies(Target, new string[] { "OpenGL" }); - PrivateIncludePaths.AddRange( - new string[] { - "../../../../../Engine/Source/Runtime/OpenGLDrv/Private", - // ... add other private include paths required here ... - } - ); - } - - if (Target.Platform == UnrealTargetPlatform.IOS) - { - // add the SystemConfiguration framework - PublicFrameworks.AddRange( - new string[] { - "SystemConfiguration", - }); - } - } -} diff --git a/Engine/Plugins/Online/HTTPChunkInstaller/Source/Private/HTTPChunkInstaller.cpp b/Engine/Plugins/Online/HTTPChunkInstaller/Source/Private/HTTPChunkInstaller.cpp deleted file mode 100644 index 6ac3caf22fc4..000000000000 --- a/Engine/Plugins/Online/HTTPChunkInstaller/Source/Private/HTTPChunkInstaller.cpp +++ /dev/null @@ -1,1417 +0,0 @@ -// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. - -#include "HTTPChunkInstaller.h" -#include "HTTPChunkInstallerLog.h" -#include "ChunkInstall.h" -#include "LocalTitleFile.h" -#include "HTTPOnlineTitleFile.h" -#include "Misc/EngineVersion.h" -#include "Templates/UniquePtr.h" -#include "Interfaces/IBuildInstaller.h" -#include "BuildPatchManifest.h" -#include "Misc/ScopeLock.h" -#include "HAL/RunnableThread.h" -#include "Misc/FileHelper.h" -#include "Misc/ConfigCacheIni.h" -#include "Misc/CommandLine.h" - -// Gross hack: -// If games haven't updated their OSS to IWYU, and they're using the engine version -// of this plugin, they'll trigger IWYU monolithic errors, so we're temporarily -// suppressing those warnings since we can't force-update our games. - -// Added 2017-02-26; remove as soon as all of our games have taken an Online plugins update -#pragma push_macro("SUPPRESS_MONOLITHIC_HEADER_WARNINGS") -# define SUPPRESS_MONOLITHIC_HEADER_WARNINGS 1 -# include "OnlineSubsystem.h" -# include "Online.h" -#pragma pop_macro("SUPPRESS_MONOLITHIC_HEADER_WARNINGS") - -#if PLATFORM_ANDROID -#include "OpenGLDrv.h" -#endif - -#if PLATFORM_IOS -#include -#endif - -#define LOCTEXT_NAMESPACE "HTTPChunkInstaller" - -// helper to grab the installer service -static IBuildPatchServicesModule* GetBuildPatchServices() -{ - static IBuildPatchServicesModule* BuildPatchServices = nullptr; - if (BuildPatchServices == nullptr) - { - BuildPatchServices = &FModuleManager::LoadModuleChecked(TEXT("BuildPatchServices")); - } - return BuildPatchServices; -} - -// Helper class to find all pak file manifests. -class FChunkSearchVisitor: public IPlatformFile::FDirectoryVisitor -{ -public: - TArray PakManifests; - - FChunkSearchVisitor() - {} - - virtual bool Visit(const TCHAR* FilenameOrDirectory,bool bIsDirectory) - { - if(bIsDirectory == false) - { - FString Filename(FilenameOrDirectory); - if(FPaths::GetBaseFilename(Filename).MatchesWildcard("*.manifest")) - { - PakManifests.AddUnique(Filename); - } - } - return true; - } -}; - - -FHTTPChunkInstall::FHTTPChunkInstall() - : InstallingChunkID(-1) - , InstallerState(ChunkInstallState::Setup) - , InstallSpeed(EChunkInstallSpeed::Fast) - , bFirstRun(true) - , bSystemInitialised(false) -#if !UE_BUILD_SHIPPING - , bDebugNoInstalledRequired(false) -#endif - , bEnabled(false) - , bNeedsRetry(false) - , bPreloaded(false) -{ -} - - -FHTTPChunkInstall::~FHTTPChunkInstall() -{ - if (InstallService.IsValid()) - { - InstallService->CancelInstall(); - InstallService.Reset(); - } -} - -bool FHTTPChunkInstall::Tick(float DeltaSeconds) -{ - static float CountDown = 60.f; - - if (!bEnabled) - return true; - - switch (InstallerState) - { - case ChunkInstallState::Setup: - { - check(OnlineTitleFile.IsValid()); - if (!EnumFilesCompleteHandle.IsValid()) - { - EnumFilesCompleteHandle = OnlineTitleFile->AddOnEnumerateFilesCompleteDelegate_Handle(FOnEnumerateFilesCompleteDelegate::CreateRaw(this, &FHTTPChunkInstall::OSSEnumerateFilesComplete)); - } - if (!ReadFileCompleteHandle.IsValid()) - { - ReadFileCompleteHandle = OnlineTitleFile->AddOnReadFileCompleteDelegate_Handle(FOnReadFileCompleteDelegate::CreateRaw(this, &FHTTPChunkInstall::OSSReadFileComplete)); - } - InstallerState = ChunkInstallState::SetupWait; - } break; - case ChunkInstallState::SetupWait: - { - InstalledManifests.Reset(); - PrevInstallManifests.Reset(); - MountedPaks.Reset(); - InstallerState = ChunkInstallState::QueryRemoteManifests; - } break; - case ChunkInstallState::QueryRemoteManifests: - { - //Now query the title file service for the chunk manifests. This should return the list of expected chunk manifests - check(OnlineTitleFile.IsValid()); - OnlineTitleFile->ClearFiles(); - InstallerState = ChunkInstallState::RequestingTitleFiles; - UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Enumerating manifest files")); - OnlineTitleFile->EnumerateFiles(); - } break; - case ChunkInstallState::SearchTitleFiles: - { - FString CleanName; - TArray FileList; - TitleFilesToRead.Reset(); - RemoteManifests.Reset(); - ExpectedChunks.Empty(); - PendingReads.Reset(); - ManifestsInMemory.Empty(); - OnlineTitleFile->GetFileList(FileList); - for (int32 FileIndex = 0, FileCount = FileList.Num(); FileIndex < FileCount; ++FileIndex) - { - if (FileList[FileIndex].FileName.MatchesWildcard(TEXT("*.manifest"))) - { - UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Found manifest %s"), *FileList[FileIndex].FileName); - TitleFilesToRead.Add(FileList[FileIndex]); - ExpectedChunks.Add(FileList[FileIndex].ChunkID); - } - } - InstallerState = ChunkInstallState::ReadTitleFiles; - } break; - case ChunkInstallState::ReadTitleFiles: - { -/* if (bFirstRun) - { - ChunkMountTask.SetupWork(BPSModule, ContentDir, MountedPaks, ExpectedChunks); - ChunkMountTaskThread.Reset(FRunnableThread::Create(&ChunkMountTask, TEXT("Chunk mounting thread"))); - }*/ - InstallerState = ChunkInstallState::PostSetup; - } break; - case ChunkInstallState::EnterOfflineMode: - { -/* if (bFirstRun) - { - for (auto It = InstalledManifests.CreateConstIterator(); It; ++It) - { - ExpectedChunks.Add(It.Key()); - } - ChunkMountTask.SetupWork(BPSModule, ContentDir, MountedPaks, ExpectedChunks); - ChunkMountTaskThread.Reset(FRunnableThread::Create(&ChunkMountTask, TEXT("Chunk mounting thread"))); - }*/ - InstallerState = ChunkInstallState::OfflineMode; - } break; - case ChunkInstallState::OfflineMode: - { - if (bFirstRun) - { - bFirstRun = false; - } - /* - if (ChunkMountTask.IsDone()) - { - ChunkMountTaskThread->WaitForCompletion(); - ChunkMountTaskThread.Reset(); - MountedPaks.Append(ChunkMountTask.MountedPaks); - - // unmount the out of data paks - for (auto PairData : RemoteManifests) - { - // unmount the previous chunk if it exists - TArray Files = PairData.Value->GetBuildFileList(); - auto ChunkFolderName = FString::Printf(TEXT("%s%d"), TEXT("base"), PairData.Key); - auto ChunkInstallDir = FPaths::Combine(*InstallDir, *ChunkFolderName); - FString ChunkPak = ChunkInstallDir + TEXT("/") + Files[0]; - if (MountedPaks.Contains(ChunkPak)) - { - if (FCoreDelegates::OnUnmountPak.IsBound()) - { - if (FCoreDelegates::OnUnmountPak.Execute(ChunkPak)) - { - MountedPaks.Remove(ChunkPak); - } - } - } - } - - UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Completed First Run")); - bFirstRun = false; - } - }*/ - else if (bNeedsRetry) - { - CountDown -= DeltaSeconds; - if (CountDown <= 0.f) - { - InstallerState = ChunkInstallState::Retry; - } - } - } break; - case ChunkInstallState::Retry: - { - CountDown = 60.f; - bNeedsRetry = false; - RetryDelegate.Broadcast(); - // check for network connection, if restored, try initializing again - if (PreviousInstallerState < ChunkInstallState::SearchTitleFiles) - { - InstallerState = ChunkInstallState::Setup; - bFirstRun = true; - } - else if (PreviousInstallerState < ChunkInstallState::ReadComplete) - { - InstallerState = ChunkInstallState::SearchTitleFiles; - bFirstRun = true; - } - else - { - InstallerState = ChunkInstallState::Idle; - } - } break; - case ChunkInstallState::PostSetup: - { - if (bFirstRun) - { -/* if (ChunkMountTask.IsDone()) - { - ChunkMountTaskThread->WaitForCompletion(); - ChunkMountTaskThread.Reset(); - MountedPaks.Append(ChunkMountTask.MountedPaks); - - // unmount the out of data paks - for (auto PairData : RemoteManifests) - { - // unmount the previous chunk if it exists - TArray Files = PairData.Value->GetBuildFileList(); - auto ChunkFolderName = FString::Printf(TEXT("%s%d"), TEXT("base"), PairData.Key); - auto ChunkInstallDir = FPaths::Combine(*InstallDir, *ChunkFolderName); - FString ChunkPak = ChunkInstallDir + TEXT("/") + Files[0]; - if (MountedPaks.Contains(ChunkPak)) - { - if (FCoreDelegates::OnUnmountPak.IsBound()) - { - if (FCoreDelegates::OnUnmountPak.Execute(ChunkPak)) - { - MountedPaks.Remove(ChunkPak); - } - } - } - } - - UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Completed First Run")); - bFirstRun = false; - }*/ - bFirstRun = false; - } - else - { - InstallerState = ChunkInstallState::Idle; - } - } break; - case ChunkInstallState::Idle: - { - UpdatePendingInstallQueue(); - } break; - case ChunkInstallState::CopyToContent: - { - if (!ChunkCopyInstall.IsDone() || !InstallService->IsComplete()) - { - break; - } - check(InstallingChunkID != -1); - if (InstallService.IsValid()) - { - InstallService.Reset(); - } - ChunkCopyInstallThread.Reset(); - check(RemoteManifests.Find(InstallingChunkID)); - UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Adding Chunk %d to installed manifests"), InstallingChunkID); - InstalledManifests.Add(InstallingChunkID, InstallingChunkManifest); - UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Removing Chunk %d from remote manifests"), InstallingChunkID); - RemoteManifests.Remove(InstallingChunkID, InstallingChunkManifest); - MountedPaks.Append(ChunkCopyInstall.MountedPaks); - if (!RemoteManifests.Contains(InstallingChunkID)) - { - // No more manifests relating to the chunk ID are left to install. - // Inform any listeners that the install has been completed. - FPlatformChunkInstallCompleteMultiDelegate* FoundDelegate = DelegateMap.Find(InstallingChunkID); - if (FoundDelegate) - { - FoundDelegate->Broadcast(InstallingChunkID); - } - } - EndInstall(); - - } break; - case ChunkInstallState::Installing: - { - // get the current progress and send out to the progress delegate - check(InstallService.IsValid()); - FText Percentage = InstallService->GetPercentageText(); - float Progress = InstallService->GetUpdateProgress(); - int64 TotalSize = InstallService->GetInitialDownloadSize(); - int64 CurrentSize = InstallService->GetTotalDownloaded(); - FPlatformChunkInstallProgressMultiDelegate* FoundDelegate = ProgressDelegateMap.Find(InstallingChunkID); - if (FoundDelegate) - { - FoundDelegate->Broadcast(InstallingChunkID, Progress, TotalSize, CurrentSize, Percentage); - } - } - case ChunkInstallState::RequestingTitleFiles: - case ChunkInstallState::WaitingOnRead: - default: - break; - } - - if (OnlineTitleFileHttp.IsValid()) - { - static_cast(OnlineTitleFileHttp.Get())->Tick(DeltaSeconds); - } - - return true; -} - -bool FHTTPChunkInstall::IsConnectedToWiFiorLAN() const -{ -#if PLATFORM_IOS - SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, "8.8.8.8"); - SCNetworkReachabilityFlags flags; - BOOL success = SCNetworkReachabilityGetFlags(reachability, &flags); - CFRelease(reachability); - if (!success) - { - return false; - } - BOOL isReachable = ((flags & kSCNetworkReachabilityFlagsReachable) != 0); - BOOL needsConnection = ((flags & kSCNetworkReachabilityFlagsConnectionRequired) != 0); - BOOL isNetworkReachable = (isReachable && !needsConnection); - - if (!isNetworkReachable) - { - // not on network - return false; - } - else if ((flags & kSCNetworkReachabilityFlagsIsWWAN) != 0) - { - // on cell servce - return false; - } - else - { - // on WiFi - return true; - } -#else - return true; // true for now on PC -#endif -} - -void FHTTPChunkInstall::UpdatePendingInstallQueue() -{ - if (InstallingChunkID != -1 -#if !UE_BUILD_SHIPPING - || bDebugNoInstalledRequired -#endif - ) - { - return; - } - - check(!InstallService.IsValid()); - bool bPatch = false; - while (PriorityQueue.Num() > 0 && InstallerState != ChunkInstallState::Installing) - { - const FChunkPrio& NextChunk = PriorityQueue[0]; - - FScopeLock Lock(&ReadFileGuard); - if (PendingReads.Num() > 0) - { - for (int Index = 0; Index < PendingReads.Num(); Index++) - { - if (PendingReads[Index].ChunkID == NextChunk.ChunkID) - { - // current manifest is in flight, return early and we'll check on the next update - return; - } - } - } - - TArray FoundChunkManifests; - RemoteManifests.MultiFind(NextChunk.ChunkID, FoundChunkManifests); - if (FoundChunkManifests.Num() > 0) - { - auto ChunkManifest = FoundChunkManifests[0]; - auto ChunkIDField = ChunkManifest->GetCustomField("ChunkID"); - if (ChunkIDField.IsValid()) - { - BeginChunkInstall(NextChunk.ChunkID, ChunkManifest, FindPreviousInstallManifest(ChunkManifest)); - } - else - { - PriorityQueue.RemoveAt(0); - } - } - else - { - PriorityQueue.RemoveAt(0); - } - } - if (InstallingChunkID == -1 && IsConnectedToWiFiorLAN()) - { - // check to see if we need to get some title files - if (TitleFilesToRead.Num() > 0 && PendingReads.Num() == 0) - { - // check for an already installed manifest - FString ChunkFdrName; - FString ManifestName; - if (BuildChunkFolderName(ChunkFdrName, ManifestName, TitleFilesToRead[0].ChunkID)) - { - FString ManifestPath = FPaths::Combine(*ContentDir, *ChunkFdrName, *ManifestName); - FString HoldingPath = FPaths::Combine(*HoldingDir, *ChunkFdrName, *ManifestName); - IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile(); - if (PlatformFile.FileExists(*ManifestPath)) - { - auto Manifest = BPSModule->LoadManifestFromFile(ManifestPath); - if (!Manifest.IsValid()) - { - //Something is wrong, suggests corruption so mark the folder for delete - PlatformFile.DeleteFile(*ManifestPath); - } - else - { - auto ChunkIDField = Manifest->GetCustomField("ChunkID"); - if (!ChunkIDField.IsValid()) - { - //Something is wrong, suggests corruption so mark the folder for delete - PlatformFile.DeleteFile(*ManifestPath); - } - else - { - InstalledManifests.Add(TitleFilesToRead[0].ChunkID, Manifest); - } - } - } - } - - // kick off a read of the manifest - FScopeLock Lock(&ReadFileGuard); - PendingReads.Add(TitleFilesToRead[0]); - if (!IsDataInFileCache(TitleFilesToRead[0].Hash)) - { - UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Reading manifest %s from remote source"), *TitleFilesToRead[0].FileName); - OnlineTitleFile->ReadFile(TitleFilesToRead[0].DLName); - TitleFilesToRead.RemoveAt(0); - return; - } - else - { - OSSReadFileComplete(true, TitleFilesToRead[0].DLName); - TitleFilesToRead.RemoveAt(0); - } - } - else if (PendingReads.Num() > 0) - { - return; - } - - // Install the first available chunk - for (auto It = RemoteManifests.CreateConstIterator(); It; ++It) - { - if (It) - { - IBuildManifestPtr ChunkManifest = It.Value(); - auto ChunkIDField = ChunkManifest->GetCustomField("ChunkID"); - if (ChunkIDField.IsValid()) - { - BeginChunkInstall(ChunkIDField->AsInteger(), ChunkManifest, FindPreviousInstallManifest(ChunkManifest)); - return; - } - } - } - } -} - - -EChunkLocation::Type FHTTPChunkInstall::GetChunkLocation(uint32 ChunkID) -{ -#if !UE_BUILD_SHIPPING - if(bDebugNoInstalledRequired) - { - return EChunkLocation::BestLocation; - } -#endif - - // Safe to assume Chunk0 is ready - if (ChunkID == 0) - { - return EChunkLocation::BestLocation; - } - -#if !PLATFORM_IOS - if ((ChunkID == 3 || ChunkID == 4 || ChunkID == 6 || ChunkID == 7 || ChunkID == 8 || ChunkID == 9 - || ChunkID == 101 || ChunkID == 104 || ChunkID == 106 || ChunkID == 110 || ChunkID == 112 || ChunkID == 118 || ChunkID == 119 - || ChunkID == 120 || ChunkID == 121 || ChunkID == 123 || ChunkID == 128 || ChunkID == 130 || ChunkID == 131 || ChunkID == 900 - || ChunkID == 901 || ChunkID == 902 || ChunkID == 903 || ChunkID == 904 || ChunkID == 905 || ChunkID == 906 || ChunkID == 907 - || ChunkID == 908 || ChunkID == 1002) && bPreloaded) - { - return EChunkLocation::BestLocation; - } -#else - if ((ChunkID == 3 || ChunkID == 4 || ChunkID == 6 || ChunkID == 8 - || ChunkID == 101 || ChunkID == 104 || ChunkID == 106 || ChunkID == 110 || ChunkID == 112 || ChunkID == 118 || ChunkID == 119 - || ChunkID == 120 || ChunkID == 121 || ChunkID == 123 || ChunkID == 128 || ChunkID == 130 || ChunkID == 131 || ChunkID == 900 - || ChunkID == 901 || ChunkID == 902 || ChunkID == 903 || ChunkID == 904 || ChunkID == 905 || ChunkID == 906 || ChunkID == 907 - || ChunkID == 908 || ChunkID == 1002) && bPreloaded) - { - return EChunkLocation::BestLocation; - } -#endif // PLATFORM_IOS - - if (bFirstRun || !bSystemInitialised) - { - /** Still waiting on setup to finish, report that nothing is installed yet... */ - return EChunkLocation::DoesNotExist; - } - TArray FoundManifests; - RemoteManifests.MultiFind(ChunkID, FoundManifests); - if (FoundManifests.Num() > 0) - { - return EChunkLocation::NotAvailable; - } - - InstalledManifests.MultiFind(ChunkID, FoundManifests); - if (FoundManifests.Num() > 0) - { - return EChunkLocation::BestLocation; - } - - // new version: not already installed or needs update, need to check the remote file headers for the chunk and then see if we have an installed version of that chunk - { - FScopeLock Lock(&ReadFileGuard); - for (int32 Index = 0; Index < PendingReads.Num(); ++Index) - { - if (PendingReads[Index].ChunkID == ChunkID) - { - return EChunkLocation::NotAvailable; - } - } - } - - for (int32 Index = 0; Index < TitleFilesToRead.Num(); ++Index) - { - if (TitleFilesToRead[Index].ChunkID == ChunkID) - { - // check for an already installed manifest - FString ChunkFdrName; - FString ManifestName; - if (BuildChunkFolderName(ChunkFdrName, ManifestName, ChunkID)) - { - FString ManifestPath = FPaths::Combine(*ContentDir, *ChunkFdrName, *ManifestName); - FString HoldingPath = FPaths::Combine(*HoldingDir, *ChunkFdrName, *ManifestName); - IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile(); - if (PlatformFile.FileExists(*ManifestPath)) - { - auto Manifest = BPSModule->LoadManifestFromFile(ManifestPath); - if (!Manifest.IsValid()) - { - //Something is wrong, suggests corruption so mark the folder for delete - PlatformFile.DeleteFile(*ManifestPath); - } - else - { - auto ChunkIDField = Manifest->GetCustomField("ChunkID"); - if (!ChunkIDField.IsValid()) - { - //Something is wrong, suggests corruption so mark the folder for delete - PlatformFile.DeleteFile(*ManifestPath); - } - else - { - InstalledManifests.Add(ChunkID, Manifest); - } - } - } - } - - // kick off a read of the manifest - FScopeLock Lock(&ReadFileGuard); - PendingReads.Add(TitleFilesToRead[Index]); - if (!IsDataInFileCache(TitleFilesToRead[Index].Hash)) - { - UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Reading manifest %s from remote source"), *TitleFilesToRead[Index].FileName); - OnlineTitleFile->ReadFile(TitleFilesToRead[Index].DLName); - TitleFilesToRead.RemoveAt(Index); - } - else - { - OSSReadFileComplete(true, TitleFilesToRead[Index].DLName); - TitleFilesToRead.RemoveAt(Index); - - // do another check of the remote vs installed - RemoteManifests.MultiFind(ChunkID, FoundManifests); - if (FoundManifests.Num() > 0) - { - return EChunkLocation::NotAvailable; - } - - InstalledManifests.MultiFind(ChunkID, FoundManifests); - if (FoundManifests.Num() > 0) - { - return EChunkLocation::BestLocation; - } - } - - return EChunkLocation::NotAvailable; - } - } - - return EChunkLocation::DoesNotExist; -} - - -float FHTTPChunkInstall::GetChunkProgress(uint32 ChunkID,EChunkProgressReportingType::Type ReportType) -{ -#if !UE_BUILD_SHIPPING - if (bDebugNoInstalledRequired) - { - return 100.f; - } -#endif - - // Safe to assume Chunk0 is ready - if (ChunkID == 0) - { - return 100.f; - } - - if (bFirstRun || !bSystemInitialised) - { - /** Still waiting on setup to finish, report that nothing is installed yet... */ - return 0.f; - } - TArray FoundManifests; - RemoteManifests.MultiFind(ChunkID, FoundManifests); - if (FoundManifests.Num() > 0) - { - float Progress = 0; - if (InstallingChunkID == ChunkID && InstallService.IsValid()) - { - Progress = InstallService->GetUpdateProgress(); - } - return Progress / FoundManifests.Num(); - } - - InstalledManifests.MultiFind(ChunkID, FoundManifests); - if (FoundManifests.Num() > 0) - { - return 100.f; - } - - return 0.f; -} - -void FHTTPChunkInstall::OSSEnumerateFilesComplete(bool bSuccess) -{ - if (bSuccess) - { - InstallerState = ChunkInstallState::SearchTitleFiles; - } - else - { - if (!bNeedsRetry) - { - bNeedsRetry = true; - PreviousInstallerState = InstallerState; - } - if (InstallerState != ChunkInstallState::OfflineMode) - { - InstallerState = ChunkInstallState::EnterOfflineMode; - } - FOnlineTitleFileHttp* TitleFileHttp = static_cast(OnlineTitleFileHttp.Get()); - EChunkInstallErrorCode ErrorCode = EChunkInstallErrorCode::RemoteFailure; - switch (TitleFileHttp->IsClientCompatible()) - { - case FOnlineTitleFileHttp::Compatible::UnknownCompatibility: - // we didn't get far enough to download. let the other error stand - break; - case FOnlineTitleFileHttp::Compatible::ClientIsCompatible: - // version is good, something else failed - break; - case FOnlineTitleFileHttp::Compatible::ClientUpdateRequired: - // don't retry if we detect incompatible client - bNeedsRetry = false; - ErrorCode = EChunkInstallErrorCode::NeedsClientUpdate; - break; - case FOnlineTitleFileHttp::Compatible::ClientIsNewerThanMcp: - // don't retry if we detect incompatible client - bNeedsRetry = false; - ErrorCode = EChunkInstallErrorCode::ClientIsTooNew; - break; - } - ErrorDelegate.Broadcast(FChunkInstallError(ErrorCode, TitleFileHttp->GetErrorMsg())); - } -} - -void FHTTPChunkInstall::OSSReadFileComplete(bool bSuccess, const FString& Filename) -{ - FScopeLock Lock(&ReadFileGuard); - - // find the cloud file header - int TitleFileIndex = -1; - for (int Index = 0; Index < PendingReads.Num(); ++Index) - { - if (PendingReads[Index].DLName == Filename) - { - TitleFileIndex = Index; - break; - } - } - if (TitleFileIndex == -1) - { - return; - } - - if (!bSuccess) // || (InstallerState != ChunkInstallState::WaitingOnRead && InstallerState != ChunkInstallState::ReadTitleFiles)) - { - if (!bNeedsRetry) - { - bNeedsRetry = true; - PreviousInstallerState = InstallerState; - } - if (InstallerState != ChunkInstallState::OfflineMode) - { - InstallerState = ChunkInstallState::EnterOfflineMode; - } - - // remove the pending read - PendingReads.RemoveAt(TitleFileIndex); - - // fire the error - FText ErrorMsg = static_cast(OnlineTitleFileHttp.Get())->GetErrorMsg(); - ErrorDelegate.Broadcast(FChunkInstallError(EChunkInstallErrorCode::RemoteFailure, ErrorMsg)); - return; - } - - FileContentBuffer.Reset(); - bool bReadOK = false; - bool bAlreadyLoaded = ManifestsInMemory.Contains(PendingReads[TitleFileIndex].Hash); - if (!IsDataInFileCache(PendingReads[TitleFileIndex].Hash)) - { - bReadOK = OnlineTitleFile->GetFileContents(PendingReads[TitleFileIndex].DLName, FileContentBuffer); - if (bReadOK) - { - AddDataToFileCache(PendingReads[TitleFileIndex].Hash, FileContentBuffer); - } - } - else if (!bAlreadyLoaded) - { - bReadOK = GetDataFromFileCache(PendingReads[TitleFileIndex].Hash, FileContentBuffer); - if (!bReadOK) - { - RemoveDataFromFileCache(PendingReads[TitleFileIndex].Hash); - } - } - if (bReadOK || bAlreadyLoaded) - { - if (!bAlreadyLoaded) - { - ParseTitleFileManifest(PendingReads[TitleFileIndex].Hash); - } - // Even if the Parse failed remove the file from the list - PendingReads.RemoveAt(TitleFileIndex); - } -} - -void FHTTPChunkInstall::OSSInstallComplete(bool bSuccess, IBuildManifestRef BuildManifest) -{ - if (bSuccess) - { - // Completed OK. Write the manifest. If the chunk doesn't exist, copy to the content dir. - // Otherwise, writing the manifest will prompt a copy on next start of the game - FString ManifestName; - FString ChunkFdrName; - uint32 ChunkID; - bool bIsPatch; - if (!BuildChunkFolderName(BuildManifest, ChunkFdrName, ManifestName, ChunkID, bIsPatch)) - { - //Something bad has happened, bail - EndInstall(); - return; - } - UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Chunk %d install complete, preparing to copy to content directory"), ChunkID); - FString ManifestPath = FPaths::Combine(*InstallDir, *ChunkFdrName, *ManifestName); - FString HoldingManifestPath = FPaths::Combine(*HoldingDir, *ChunkFdrName, *ManifestName); - FString SrcDir = FPaths::Combine(*InstallDir, *ChunkFdrName); - FString DestDir = FPaths::Combine(*ContentDir, *ChunkFdrName); - bool bCopyDir = InstallDir != ContentDir; - TArray FoundManifests; - InstalledManifests.MultiFind(ChunkID, FoundManifests); - for (const auto& It : FoundManifests) - { - auto FoundPatchField = It->GetCustomField("bIsPatch"); - bool bFoundPatch = FoundPatchField.IsValid() ? FoundPatchField->AsString() == TEXT("true") : false; - if (bFoundPatch == bIsPatch) - { - bCopyDir = false; - } - } - ChunkCopyInstall.SetupWork(ManifestPath, HoldingManifestPath, SrcDir, DestDir, BPSModule, BuildManifest, MountedPaks, bCopyDir); - UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Copying Chunk %d to content directory"), ChunkID); - ChunkCopyInstallThread.Reset(FRunnableThread::Create(&ChunkCopyInstall, TEXT("Chunk Install Copy Thread"))); - InstallerState = ChunkInstallState::CopyToContent; - - check(InstallService.IsValid()); - FText Percentage = FText::FromString(TEXT("100%")); - float Progress = 1.0f; - int64 TotalSize = InstallService->GetInitialDownloadSize(); - int64 CurrentSize = InstallService->GetTotalDownloaded(); - double CurrTime = FPlatformTime::Seconds(); - double DeltaTime = (CurrTime - StartTime); - - FPlatformChunkInstallProgressMultiDelegate* FoundDelegate = ProgressDelegateMap.Find(InstallingChunkID); - if (FoundDelegate) - { - FoundDelegate->Broadcast(InstallingChunkID, Progress, TotalSize, CurrentSize, Percentage); - } - AnalyticsDelegate.Broadcast(true, InstallingChunkID, DeltaTime, TotalSize, InstallService->GetBuildStatistics()); - } - else - { - //Something bad has happed, return to the Idle state. We'll re-attempt the install - if (InstallService->HasError()) - { - switch (InstallService->GetErrorType()) - { - case EBuildPatchInstallError::DownloadError: - ErrorDelegate.Broadcast(FChunkInstallError(EChunkInstallErrorCode::RemoteFailure, LOCTEXT("ReadFiles", "Failure to download files, retrying..."))); - break; - case EBuildPatchInstallError::OutOfDiskSpace: - ErrorDelegate.Broadcast(FChunkInstallError(EChunkInstallErrorCode::LocalFailure, LOCTEXT("Diskspace", "No space on device."))); - break; - case EBuildPatchInstallError::MoveFileToInstall: - ErrorDelegate.Broadcast(FChunkInstallError(EChunkInstallErrorCode::LocalFailure, LOCTEXT("InstallFailure", "Failed to install file, retrying..."))); - break; - default: - ErrorDelegate.Broadcast(FChunkInstallError(EChunkInstallErrorCode::GenericFailure, LOCTEXT("UnknownFailure", "Unknown Failure, retrying..."))); - break; - } - } - int64 TotalSize = InstallService->GetInitialDownloadSize(); - double CurrTime = FPlatformTime::Seconds(); - double DeltaTime = (CurrTime - StartTime); - AnalyticsDelegate.Broadcast(false, InstallingChunkID, DeltaTime, TotalSize, InstallService->GetBuildStatistics()); - EndInstall(); - - // set to the retry state - if (!bNeedsRetry) - { - bNeedsRetry = true; - PreviousInstallerState = InstallerState; - } - if (InstallerState != ChunkInstallState::OfflineMode) - { - InstallerState = ChunkInstallState::EnterOfflineMode; - } - } - FPlatformMisc::ControlScreensaver(FGenericPlatformMisc::Enable); -} - -bool FHTTPChunkInstall::FilesHaveChanged(IBuildManifestPtr LocalManifest, IBuildManifestPtr RemoteManifest, int32 InInstallingChunkID) -{ -#if (!WITH_EDITORONLY_DATA || IS_PROGRAM) - if (LocalManifest->GetDownloadSize() != RemoteManifest->GetDownloadSize()) - { - return true; - } - - // same number of files check to see if the file StartBuis out dated - auto ChunkFolderName = FString::Printf(TEXT("%s%d"), TEXT("base"), InInstallingChunkID); - auto ChunkInstallDir = FPaths::Combine(*InstallDir, *ChunkFolderName); - FBuildPatchAppManifestPtr CurrentManifest = StaticCastSharedPtr< FBuildPatchAppManifest >(LocalManifest); - FBuildPatchAppManifestPtr InstallManifest = StaticCastSharedPtr< FBuildPatchAppManifest >(RemoteManifest); - TSet OutOfDateFiles; - CurrentManifest->GetOutdatedFiles(InstallManifest.ToSharedRef(), ChunkInstallDir, OutOfDateFiles); - return OutOfDateFiles.Num() > 0; -#else - return false; -#endif -} - -void FHTTPChunkInstall::ParseTitleFileManifest(const FString& ManifestFileHash) -{ -#if !UE_BUILD_SHIPPING - if (bDebugNoInstalledRequired) - { - // Forces the installer to think that no remote manifests exist, so nothing needs to be installed. - return; - } -#endif - FString JsonBuffer; - FFileHelper::BufferToString(JsonBuffer, FileContentBuffer.GetData(), FileContentBuffer.Num()); - auto RemoteManifest = BPSModule->MakeManifestFromJSON(JsonBuffer); - if (!RemoteManifest.IsValid()) - { - UE_LOG(LogHTTPChunkInstaller, Warning, TEXT("Manifest was invalid")); - return; - } - auto RemoteChunkIDField = RemoteManifest->GetCustomField("ChunkID"); - if (!RemoteChunkIDField.IsValid()) - { - UE_LOG(LogHTTPChunkInstaller, Warning, TEXT("Manifest ChunkID was invalid or missing")); - return; - } - //Compare to installed manifests and add to the remote if it needs to be installed. - uint32 ChunkID = (uint32)RemoteChunkIDField->AsInteger(); - if (!ExpectedChunks.Contains(ChunkID)) - { - ExpectedChunks.Add(ChunkID); - } - - // new version: check for an already installed manifest - TArray FoundManifests; - InstalledManifests.MultiFind(ChunkID, FoundManifests); - uint32 FoundCount = FoundManifests.Num(); - if (FoundCount > 0) - { - auto RemotePatchManifest = RemoteManifest->GetCustomField("bIsPatch"); - auto RemoteVersion = RemoteManifest->GetVersionString(); - bool bRemoteIsPatch = RemotePatchManifest.IsValid() ? RemotePatchManifest->AsString() == TEXT("true") : false; - for (uint32 FoundIndex = 0; FoundIndex < FoundCount; ++FoundIndex) - { - const auto& InstalledManifest = FoundManifests[FoundIndex]; - auto InstalledVersion = InstalledManifest->GetVersionString(); - auto InstallPatchManifest = InstalledManifest->GetCustomField("bIsPatch"); - bool bInstallIsPatch = InstallPatchManifest.IsValid() ? InstallPatchManifest->AsString() == TEXT("true") : false; - if ((InstalledVersion != RemoteVersion && bInstallIsPatch == bRemoteIsPatch) || FilesHaveChanged(InstalledManifest, RemoteManifest, ChunkID)) - { - UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Adding Chunk %d to remote manifests"), ChunkID); - RemoteManifests.Add(ChunkID, RemoteManifest); - if(!ManifestFileHash.IsEmpty()) - { - ManifestsInMemory.Add(ManifestFileHash); - } - //Remove from the installed map -// if (bFirstRun) - { - // Prevent the paks from being mounted by removing the manifest file - FString ChunkFdrName; - FString ManifestName; - bool bIsPatch; - if (BuildChunkFolderName(InstalledManifest.ToSharedRef(), ChunkFdrName, ManifestName, ChunkID, bIsPatch)) - { - FString ManifestPath = FPaths::Combine(*ContentDir, *ChunkFdrName, *ManifestName); - FString HoldingPath = FPaths::Combine(*HoldingDir, *ChunkFdrName, *ManifestName); - IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile(); - PlatformFile.CreateDirectoryTree(*FPaths::Combine(*HoldingDir, *ChunkFdrName)); - PlatformFile.MoveFile(*HoldingPath, *ManifestPath); - } - UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Adding Chunk %d to previous installed manifests"), ChunkID); - PrevInstallManifests.Add(ChunkID, InstalledManifest); - UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Removing Chunk %d from installed manifests"), ChunkID); - InstalledManifests.Remove(ChunkID, InstalledManifest); - } - } - else - { - // mount the found chunk - FString ChunkFdrName; - FString ManifestName; - bool bIsPatch; - if (BuildChunkFolderName(InstalledManifest.ToSharedRef(), ChunkFdrName, ManifestName, ChunkID, bIsPatch)) - { - FString ManifestPath = FPaths::Combine(*ContentDir, *ChunkFdrName, *ManifestName); - FString DestDir = FPaths::Combine(*ContentDir, *ChunkFdrName); - ChunkMountOnlyTask.SetupWork(ManifestPath, DestDir, InstalledManifest.ToSharedRef(), MountedPaks); - UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Mounting Chunk %d"), TitleFilesToRead[0].ChunkID); - ChunkMountOnlyTaskThread.Reset(FRunnableThread::Create(&ChunkMountOnlyTask, TEXT("Chunk Mount Only Thread"))); - while (!ChunkMountOnlyTask.IsDone()) - { - FPlatformProcess::Sleep(0.0f); - } - MountedPaks.Append(ChunkMountOnlyTask.MountedPaks); - } - } - } - } - else - { - UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Adding Chunk %d to remote manifests"), ChunkID); - RemoteManifests.Add(ChunkID, RemoteManifest); - if (!ManifestFileHash.IsEmpty()) - { - ManifestsInMemory.Add(ManifestFileHash); - } - } -} - -bool FHTTPChunkInstall::BuildChunkFolderName(IBuildManifestRef Manifest, FString& ChunkFdrName, FString& ManifestName, uint32& ChunkID, bool& bIsPatch) -{ - auto ChunkIDField = Manifest->GetCustomField("ChunkID"); - auto ChunkPatchField = Manifest->GetCustomField("bIsPatch"); - - if (!ChunkIDField.IsValid()) - { - return false; - } - ChunkID = ChunkIDField->AsInteger(); - bIsPatch = ChunkPatchField.IsValid() ? ChunkPatchField->AsString() == TEXT("true") : false; - ManifestName = FString::Printf(TEXT("chunk_%u"), ChunkID); - if (bIsPatch) - { - ManifestName += TEXT("_patch"); - } - ManifestName += TEXT(".manifest"); - ChunkFdrName = FString::Printf(TEXT("%s%d"), !bIsPatch ? TEXT("base") : TEXT("patch"), ChunkID); - return true; -} - -bool FHTTPChunkInstall::BuildChunkFolderName(FString& ChunkFdrName, FString& ManifestName, uint32 ChunkID) -{ - ManifestName = FString::Printf(TEXT("chunk_%u"), ChunkID); - ManifestName += TEXT(".manifest"); - ChunkFdrName = FString::Printf(TEXT("%s%d"), TEXT("base"), ChunkID); - return true; -} - -bool FHTTPChunkInstall::PrioritizeChunk(uint32 ChunkID, EChunkPriority::Type Priority) -{ - int32 FoundIndex; - PriorityQueue.Find(FChunkPrio(ChunkID, Priority), FoundIndex); - if (FoundIndex != INDEX_NONE) - { - PriorityQueue.RemoveAt(FoundIndex); - } - // Low priority is assumed if the chunk ID doesn't exist in the queue - if (Priority != EChunkPriority::Low) - { - PriorityQueue.AddUnique(FChunkPrio(ChunkID, Priority)); - PriorityQueue.Sort(); - } - return true; -} - -FDelegateHandle FHTTPChunkInstall::SetChunkInstallDelgate(uint32 ChunkID, FPlatformChunkInstallCompleteDelegate Delegate) -{ - FPlatformChunkInstallCompleteMultiDelegate* FoundDelegate = DelegateMap.Find(ChunkID); - if (FoundDelegate) - { - return FoundDelegate->Add(Delegate); - } - else - { - FPlatformChunkInstallCompleteMultiDelegate MC; - auto RetVal = MC.Add(Delegate); - DelegateMap.Add(ChunkID, MC); - return RetVal; - } - return FDelegateHandle(); -} - -void FHTTPChunkInstall::RemoveChunkInstallDelgate(uint32 ChunkID, FDelegateHandle Delegate) -{ - FPlatformChunkInstallCompleteMultiDelegate* FoundDelegate = DelegateMap.Find(ChunkID); - if (!FoundDelegate) - { - return; - } - FoundDelegate->Remove(Delegate); -} - -FDelegateHandle FHTTPChunkInstall::SetChunkInstallProgressDelgate(uint32 ChunkID, FPlatformChunkInstallProgressDelegate Delegate) -{ - FPlatformChunkInstallProgressMultiDelegate* FoundDelegate = ProgressDelegateMap.Find(ChunkID); - if (FoundDelegate) - { - return FoundDelegate->Add(Delegate); - } - else - { - FPlatformChunkInstallProgressMultiDelegate MC; - auto RetVal = MC.Add(Delegate); - ProgressDelegateMap.Add(ChunkID, MC); - return RetVal; - } - return FDelegateHandle(); -} - -void FHTTPChunkInstall::RemoveChunkInstallProgressDelgate(uint32 ChunkID, FDelegateHandle Delegate) -{ - FPlatformChunkInstallProgressMultiDelegate* FoundDelegate = ProgressDelegateMap.Find(ChunkID); - if (!FoundDelegate) - { - return; - } - FoundDelegate->Remove(Delegate); -} - -FDelegateHandle FHTTPChunkInstall::SetErrorDelegate(FPlatformChunkInstallErrorDelegate Delegate) -{ - return ErrorDelegate.Add(Delegate); -} - -void FHTTPChunkInstall::RemoveErrorDelegate(FDelegateHandle Delegate) -{ - ErrorDelegate.Remove(Delegate); -} - -FDelegateHandle FHTTPChunkInstall::SetChunkAnalyticsDelegate(FPlatformChunkAnalyticsDelegate Delegate) -{ - return AnalyticsDelegate.Add(Delegate); -} - -void FHTTPChunkInstall::RemoveChunkAnalyticsDelegate(FDelegateHandle Delegate) -{ - AnalyticsDelegate.Remove(Delegate); -} - -FDelegateHandle FHTTPChunkInstall::SetRetryDelegate(FPlatformChunkInstallRetryDelegate Delegate) -{ - return RetryDelegate.Add(Delegate); -} - -void FHTTPChunkInstall::RemoveRetryDelegate(FDelegateHandle Delegate) -{ - RetryDelegate.Remove(Delegate); -} - -void FHTTPChunkInstall::BeginChunkInstall(uint32 ChunkID,IBuildManifestPtr ChunkManifest, IBuildManifestPtr PrevInstallChunkManifest) -{ - check(ChunkManifest->GetCustomField("ChunkID").IsValid()); - InstallingChunkID = ChunkID; - check(ChunkID > 0); - InstallingChunkManifest = ChunkManifest; - IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile(); - auto PatchField = ChunkManifest->GetCustomField("bIsPatch"); - bool bIsPatch = PatchField.IsValid() ? PatchField->AsString() == TEXT("true") : false; - auto ChunkFolderName = FString::Printf(TEXT("%s%d"),!bIsPatch ? TEXT("base") : TEXT("patch"), InstallingChunkID); - auto ChunkInstallDir = FPaths::Combine(*InstallDir,*ChunkFolderName); - auto ChunkStageDir = FPaths::Combine(*StageDir,*ChunkFolderName); - if(!PlatformFile.DirectoryExists(*ChunkStageDir)) - { - PlatformFile.CreateDirectoryTree(*ChunkStageDir); - } - if(!PlatformFile.DirectoryExists(*ChunkInstallDir)) - { - PlatformFile.CreateDirectoryTree(*ChunkInstallDir); - } - CloudDir = static_cast(OnlineTitleFileHttp.Get())->GetBaseUrl(); - BPSModule->SetCloudDirectory(CloudDir); - BPSModule->SetStagingDirectory(ChunkStageDir); - - TArray Files = ChunkManifest->GetBuildFileList(); - FString ChunkPak = ChunkInstallDir + TEXT("/") + Files[0]; - ensure(!MountedPaks.Contains(ChunkPak)); - - UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Starting Chunk %d install"), InstallingChunkID); - StartTime = FPlatformTime::Seconds(); - InstallService = BPSModule->StartBuildInstall(PrevInstallChunkManifest,ChunkManifest,ChunkInstallDir,FBuildPatchBoolManifestDelegate::CreateRaw(this,&FHTTPChunkInstall::OSSInstallComplete)); - if(InstallSpeed == EChunkInstallSpeed::Paused && !InstallService->IsPaused()) - { - InstallService->TogglePauseInstall(); - } - InstallerState = ChunkInstallState::Installing; - FPlatformMisc::ControlScreensaver(FGenericPlatformMisc::Disable); -} - -/** - * Note: the following cache functions are synchronous and may need to become asynchronous... - */ -bool FHTTPChunkInstall::AddDataToFileCache(const FString& ManifestHash,const TArray& Data) -{ - if (ManifestHash.IsEmpty()) - { - return false; - } - UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Adding data hash %s to file cache"), *ManifestHash); - return FFileHelper::SaveArrayToFile(Data, *FPaths::Combine(*CacheDir, *ManifestHash)); -} - -bool FHTTPChunkInstall::IsDataInFileCache(const FString& ManifestHash) -{ - if(ManifestHash.IsEmpty()) - { - return false; - } - IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile(); - return PlatformFile.FileExists(*FPaths::Combine(*CacheDir, *ManifestHash)); -} - -bool FHTTPChunkInstall::GetDataFromFileCache(const FString& ManifestHash, TArray& Data) -{ - if(ManifestHash.IsEmpty()) - { - return false; - } - UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Reading data hash %s from file cache"), *ManifestHash); - return FFileHelper::LoadFileToArray(Data, *FPaths::Combine(*CacheDir, *ManifestHash)); -} - -bool FHTTPChunkInstall::RemoveDataFromFileCache(const FString& ManifestHash) -{ - if(ManifestHash.IsEmpty()) - { - return false; - } - UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Removing data hash %s from file cache"), *ManifestHash); - IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile(); - auto ManifestPath = FPaths::Combine(*CacheDir, *ManifestHash); - if (PlatformFile.FileExists(*ManifestPath)) - { - return PlatformFile.DeleteFile(*ManifestPath); - } - return false; -} - -void FHTTPChunkInstall::SetupMasterManifest(const FString& InBaseUrl, const FString& ManifestData) -{ - EnumFilesCompleteHandle.Reset(); - ReadFileCompleteHandle.Reset(); - - FString TitleFileSource; - bool bValidTitleFileSource = GConfig->GetString(TEXT("HTTPChunkInstall"), TEXT("TitleFileSource"), TitleFileSource, GEngineIni); - if (bValidTitleFileSource && TitleFileSource == TEXT("Http")) - { - OnlineTitleFile = OnlineTitleFileHttp = MakeShareable(new FOnlineTitleFileHttp(InBaseUrl, ManifestData)); - } - else if (bValidTitleFileSource && TitleFileSource != TEXT("Local")) - { - OnlineTitleFile = Online::GetTitleFileInterface(*TitleFileSource); - } - else - { - FString LocalTileFileDirectory = FPaths::GameConfigDir(); - auto bGetConfigDir = GConfig->GetString(TEXT("HTTPChunkInstall"), TEXT("LocalTitleFileDirectory"), LocalTileFileDirectory, GEngineIni); - OnlineTitleFile = MakeShareable(new FLocalTitleFile(LocalTileFileDirectory)); -#if !UE_BUILD_SHIPPING - bDebugNoInstalledRequired = !bGetConfigDir; -#endif - } - - // parse config - CloudDirectory = TEXT(""); - CloudDir = FPaths::Combine(*FPaths::GameContentDir(), TEXT("Cloud")); - StageDir = FPaths::Combine(*FPaths::GameSavedDir(), TEXT("Chunks"), TEXT("Staged")); - InstallDir = FPaths::Combine(*FPaths::GameSavedDir(), TEXT("Chunks"), TEXT("Installed")); // By default this should match ContentDir - BackupDir = FPaths::Combine(*FPaths::GameSavedDir(), TEXT("Chunks"), TEXT("Backup")); - CacheDir = FPaths::Combine(*FPaths::GameSavedDir(), TEXT("Chunks"), TEXT("Cache")); - HoldingDir = FPaths::Combine(*FPaths::GameSavedDir(), TEXT("Chunks"), TEXT("Hold")); - ContentDir = FPaths::Combine(*FPaths::GameSavedDir(), TEXT("Chunks"), TEXT("Installed")); // By default this should match InstallDir - - FString TmpString1; - FString TmpString2; - if (GConfig->GetString(TEXT("HTTPChunkInstall"), TEXT("CloudDirectory"), TmpString1, GEngineIni)) - { - CloudDirectory = CloudDir = TmpString1; -#if PLATFORM_ANDROID - if (FOpenGL::SupportsASTC()) - { - CloudDirectory = CloudDir = CloudDir.Replace(TEXT("^FORMAT"), TEXT("ASTC")); - } - else if (FOpenGL::SupportsATITC()) - { - CloudDirectory = CloudDir = CloudDir.Replace(TEXT("^FORMAT"), TEXT("ATC")); - } - else if (FOpenGL::SupportsDXT()) - { - CloudDirectory = CloudDir = CloudDir.Replace(TEXT("^FORMAT"), TEXT("DXT")); - } - else if (FOpenGL::SupportsPVRTC()) - { - CloudDirectory = CloudDir = CloudDir.Replace(TEXT("^FORMAT"), TEXT("PVRTC")); - } - else if (FOpenGL::SupportsETC2()) - { - CloudDirectory = CloudDir = CloudDir.Replace(TEXT("^FORMAT"), TEXT("ETC2")); - } - else - { - CloudDirectory = CloudDir = CloudDir.Replace(TEXT("^FORMAT"), TEXT("ETC1")); - } -#endif - } - if ((GConfig->GetString(TEXT("HTTPChunkInstall"), TEXT("CloudProtocol"), TmpString1, GEngineIni)) && (GConfig->GetString(TEXT("HTTPChunkInstall"), TEXT("CloudDomain"), TmpString2, GEngineIni))) - { - if (TmpString1 == TEXT("mcp")) - { - CloudDir = static_cast(OnlineTitleFileHttp.Get())->GetBaseUrl(); - } - else - { - CloudDir = FString::Printf(TEXT("%s://%s"), *TmpString1, *TmpString2); - } - } - if (GConfig->GetString(TEXT("HTTPChunkInstall"), TEXT("StageDirectory"), TmpString1, GEngineIni)) - { - StageDir = TmpString1; - } - if (GConfig->GetString(TEXT("HTTPChunkInstall"), TEXT("InstallDirectory"), TmpString1, GEngineIni)) - { - InstallDir = TmpString1; - } - if (GConfig->GetString(TEXT("HTTPChunkInstall"), TEXT("BackupDirectory"), TmpString1, GEngineIni)) - { - BackupDir = TmpString1; - } - if (GConfig->GetString(TEXT("HTTPChunkInstall"), TEXT("ContentDirectory"), TmpString1, GEngineIni)) - { - ContentDir = TmpString1; - } - if (GConfig->GetString(TEXT("HTTPChunkInstall"), TEXT("HoldingDirectory"), TmpString1, GEngineIni)) - { - HoldingDir = TmpString1; - } -} - -void FHTTPChunkInstall::Initialize(const FString& InBaseUrl, const FString& ManifestData) -{ - InitialiseSystem(InBaseUrl, ManifestData); - bEnabled = true; -} - -void FHTTPChunkInstall::InitialiseSystem(const FString& InBaseUrl, const FString& ManifestData) -{ - BPSModule = GetBuildPatchServices(); - -#if !UE_BUILD_SHIPPING - const TCHAR* CmdLine = FCommandLine::Get(); - if (!FPlatformProperties::RequiresCookedData() || FParse::Param(CmdLine, TEXT("NoPak")) || FParse::Param(CmdLine, TEXT("NoChunkInstall"))) - { - bDebugNoInstalledRequired = true; - } -#endif - - // set up the master manifest - SetupMasterManifest(InBaseUrl, ManifestData); - - // clean up the stage directory to force re-downloading partial data -// IFileManager::Get().DeleteDirectory(*StageDir, false, true); - - bFirstRun = true; - bSystemInitialised = true; -} - -IBuildManifestPtr FHTTPChunkInstall::FindPreviousInstallManifest(const IBuildManifestPtr& ChunkManifest) -{ - auto ChunkIDField = ChunkManifest->GetCustomField("ChunkID"); - if (!ChunkIDField.IsValid()) - { - return IBuildManifestPtr(); - } - auto ChunkID = ChunkIDField->AsInteger(); - TArray FoundManifests; - PrevInstallManifests.MultiFind(ChunkID, FoundManifests); - return FoundManifests.Num() == 0 ? IBuildManifestPtr() : FoundManifests[0]; -} - -void FHTTPChunkInstall::EndInstall() -{ - if (InstallService.IsValid()) - { - //InstallService->CancelInstall(); - InstallService.Reset(); - } - InstallingChunkID = -1; - InstallingChunkManifest.Reset(); - InstallerState = ChunkInstallState::Idle; -} - -/** - * Module for the HTTP Chunk Installer - */ -class FHTTPChunkInstallerModule : public IPlatformChunkInstallModule -{ -public: - TUniquePtr ChunkInstaller; - - FHTTPChunkInstallerModule() - : ChunkInstaller(new FHTTPChunkInstall()) - { - - } - - virtual IPlatformChunkInstall* GetPlatformChunkInstall() - { - return ChunkInstaller.Get(); - } -}; - -IMPLEMENT_MODULE(FHTTPChunkInstallerModule, HTTPChunkInstaller); - -#undef LOCTEXT_NAMESPACE diff --git a/Engine/Plugins/Online/HTTPChunkInstaller/Source/Private/HTTPOnlineTitleFile.cpp b/Engine/Plugins/Online/HTTPChunkInstaller/Source/Private/HTTPOnlineTitleFile.cpp deleted file mode 100644 index 1fd091f38c2b..000000000000 --- a/Engine/Plugins/Online/HTTPChunkInstaller/Source/Private/HTTPOnlineTitleFile.cpp +++ /dev/null @@ -1,811 +0,0 @@ -// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. - -#include "HTTPOnlineTitleFile.h" -#include "HTTPChunkInstallerLog.h" -#include "CoreMinimal.h" -#include "OnlineSubsystemTypes.h" -#include "HttpModule.h" -#include "Interfaces/IHttpResponse.h" -#include "HAL/FileManager.h" -#include "Async/AsyncWork.h" -#include "Misc/ConfigCacheIni.h" -#include "Misc/EngineVersion.h" -#include "Dom/JsonObject.h" -#include "Serialization/JsonReader.h" -#include "Serialization/JsonSerializer.h" -#include "Misc/FileHelper.h" -#include "Serialization/Archive.h" - -#if PLATFORM_ANDROID -#include "OpenGLDrv.h" -#endif - -#define LOCTEXT_NAMESPACE "HTTPChunkInstaller" - -FOnlineTitleFileHttp::FOnlineTitleFileHttp(const FString& InBaseUrl, const FString& InManifestData) - : BaseUrl(InBaseUrl) - , EnumerateFilesUrl(TEXT("")) - , ErrorMsg() - , Manifest(TEXT("Master.manifest")) - , CompatibleClientVersion(0) -{ - GConfig->GetString(TEXT("HTTPOnlineTitleFile"), TEXT("ManifestName"), Manifest, GEngineIni); - GConfig->GetString(TEXT("HTTPOnlineTitleFile"), TEXT("EnumerateFilesUrl"), EnumerateFilesUrl, GEngineIni); - bCacheFiles = true; - bPlatformSupportsSHA256 = false; - ManifestData = InManifestData; - -#if PLATFORM_ANDROID - if (FOpenGL::SupportsASTC()) - { - EnumerateFilesUrl = EnumerateFilesUrl.Replace(TEXT("^FORMAT"), TEXT("ASTC")); - Manifest = Manifest.Replace(TEXT("^FORMAT"), TEXT("astc")); - } - else if (FOpenGL::SupportsATITC()) - { - EnumerateFilesUrl = EnumerateFilesUrl.Replace(TEXT("^FORMAT"), TEXT("ATC")); - Manifest = Manifest.Replace(TEXT("^FORMAT"), TEXT("atc")); - } - else if (FOpenGL::SupportsDXT()) - { - EnumerateFilesUrl = EnumerateFilesUrl.Replace(TEXT("^FORMAT"), TEXT("DXT")); - Manifest = Manifest.Replace(TEXT("^FORMAT"), TEXT("dxt")); - } - else if (FOpenGL::SupportsPVRTC()) - { - EnumerateFilesUrl = EnumerateFilesUrl.Replace(TEXT("^FORMAT"), TEXT("PVRTC")); - Manifest = Manifest.Replace(TEXT("^FORMAT"), TEXT("pvrtc")); - } - else if (FOpenGL::SupportsETC2()) - { - EnumerateFilesUrl = EnumerateFilesUrl.Replace(TEXT("^FORMAT"), TEXT("ETC2")); - Manifest = Manifest.Replace(TEXT("^FORMAT"), TEXT("etc2")); - } - else - { - EnumerateFilesUrl = EnumerateFilesUrl.Replace(TEXT("^FORMAT"), TEXT("ETC1")); - Manifest = Manifest.Replace(TEXT("^FORMAT"), TEXT("etc1")); - } -#endif -} - -bool FOnlineTitleFileHttp::GetFileContents(const FString& FileName, TArray& FileContents) -{ - const TArray* FilesPtr = &Files; - if (FilesPtr != NULL) - { - for (TArray::TConstIterator It(*FilesPtr); It; ++It) - { - if (It->FileName == FileName) - { - FileContents = It->Data; - return true; - } - } - } - return false; -} - -bool FOnlineTitleFileHttp::ClearFiles() -{ - for (int Idx = 0; Idx < Files.Num(); Idx++) - { - if (Files[Idx].AsyncState == EOnlineAsyncTaskState::InProgress) - { - UE_LOG(LogHTTPChunkInstaller, Warning, TEXT("Cant clear files. Pending file op for %s"), *Files[Idx].FileName); - return false; - } - } - // remove all cached file entries - Files.Empty(); - return true; -} - -bool FOnlineTitleFileHttp::ClearFile(const FString& FileName) -{ - for (int Idx = 0; Idx < Files.Num(); Idx++) - { - if (Files[Idx].FileName == FileName) - { - if (Files[Idx].AsyncState == EOnlineAsyncTaskState::InProgress) - { - UE_LOG(LogHTTPChunkInstaller, Warning, TEXT("Cant clear file. Pending file op for %s"), *Files[Idx].FileName); - return false; - } - else - { - Files.RemoveAt(Idx); - return true; - } - } - } - return false; -} - -void FOnlineTitleFileHttp::DeleteCachedFiles(bool bSkipEnumerated) -{ - TArray CachedFiles; - IFileManager::Get().FindFiles(CachedFiles, *(GetLocalCachePath() / TEXT("*")), true, false); - - for (auto CachedFile : CachedFiles) - { - bool bSkip = bSkipEnumerated && GetCloudFileHeader(CachedFile); - if (!bSkip) - { - IFileManager::Get().Delete(*GetLocalFilePath(CachedFile), false, true); - } - } -} - -bool FOnlineTitleFileHttp::EnumerateFiles(const FPagedQuery& Page) -{ - static const FText ErrorGeneric = LOCTEXT("EnumerateFilesError_Generic", "Enumerate Files request failed."); - - // clear the compatible client version when we start an enumeration - CompatibleClientVersion = 0; - - // Make sure an enumeration request is not currently pending - if (EnumerateFilesRequests.Num() > 0) - { - UE_LOG(LogHTTPChunkInstaller, Warning, TEXT("EnumerateFiles request already in progress")); - ErrorMsg = ErrorGeneric; - TriggerOnEnumerateFilesCompleteDelegates(false); - return false; - } - - if (!ManifestData.IsEmpty()) - { - // parse the manifest - if (!ParseManifest(ManifestData)) - { - UE_LOG(LogHTTPChunkInstaller, Warning, TEXT("EnumerateFiles failed to parse manifest: %s"), *ErrorMsg.ToString()); - TriggerOnEnumerateFilesCompleteDelegates(false); - return false; - } - - // make sure the chunks in this manifest are compatible with our current client - if (IsClientCompatible() != Compatible::ClientIsCompatible) - { - UE_LOG(LogHTTPChunkInstaller, Warning, TEXT("EnumerateFiles failed due to update required. Current CL=%u, but manifest requires %u"), FEngineVersion::Current().GetChangelist(), CompatibleClientVersion); - ErrorMsg = LOCTEXT("EnumerateFilesError_UpdateRequired", "This game requires an update in order to continue playing."); - TriggerOnEnumerateFilesCompleteDelegates(false); - return false; - } - - // Everything went ok, so we can remove any cached files that are not in the current list - ErrorMsg = FText::GetEmpty(); - DeleteCachedFiles(true); - TriggerOnEnumerateFilesCompleteDelegates(true); - } - else - { - // Create the Http request and add to pending request list - TSharedRef HttpRequest = FHttpModule::Get().CreateRequest(); - EnumerateFilesRequests.Add(HttpRequest, Page); - - FString EnumerateUrl = GetBaseUrl() + EnumerateFilesUrl + TEXT("/") + Manifest; - HttpRequest->SetURL(EnumerateUrl); - HttpRequest->SetVerb(TEXT("GET")); - HttpRequest->OnProcessRequestComplete().BindRaw(this, &FOnlineTitleFileHttp::EnumerateFiles_HttpRequestComplete); - if (!HttpRequest->ProcessRequest()) - { - UE_LOG(LogHTTPChunkInstaller, Warning, TEXT("EnumerateFiles unable to queue HTTP request")); - ErrorMsg = ErrorGeneric; - TriggerOnEnumerateFilesCompleteDelegates(false); - return false; - } - } - - return true; -} - -void FOnlineTitleFileHttp::GetFileList(TArray& OutFiles) -{ - TArray* FilesPtr = &FileHeaders; - if (FilesPtr != NULL) - { - OutFiles = *FilesPtr; - } - else - { - OutFiles.Empty(); - } -} - -bool FOnlineTitleFileHttp::ReadFile(const FString& FileName) -{ - bool bStarted = false; - - FCloudFileHeader* CloudFileHeader = GetCloudFileHeader(FileName); - - // Make sure valid filename was specified3 - if (FileName.IsEmpty() || FileName.Contains(TEXT(" "))) - { - UE_LOG(LogHTTPChunkInstaller, Warning, TEXT("Invalid filename filename=%s"), *FileName); - ErrorMsg = FText::Format(LOCTEXT("ReadFile_FileNotFound", "File not found: {0}"), FText::FromString(FileName)); - TriggerOnReadFileCompleteDelegates(false, FileName); - return false; - } - - // Make sure a file request for this file is not currently pending - for (const auto& Pair : FileRequests) - { - if (Pair.Value == FPendingFileRequest(FileName)) - { - UE_LOG(LogHTTPChunkInstaller, Verbose, TEXT("ReadFileRemote is already in progress for (%s)"), *FileName); - return true; - } - } - - FCloudFile* CloudFile = GetCloudFile(FileName, true); - if (CloudFile->AsyncState == EOnlineAsyncTaskState::InProgress) - { - UE_LOG(LogHTTPChunkInstaller, Verbose, TEXT("ReadFile is already in progress for (%s)"), *FileName); - return true; - } - - if (bCacheFiles) - { - // Try to read this from the cache if possible - bStarted = StartReadFileLocal(FileName); - } - if (!bStarted) - { - // Failed locally (means not on disk) so fetch from server - bStarted = ReadFileRemote(FileName); - } - - if (!bStarted || CloudFile->AsyncState == EOnlineAsyncTaskState::Failed) - { - UE_LOG(LogHTTPChunkInstaller, Warning, TEXT("ReadFile request failed for file (%s)"), *FileName); - ErrorMsg = FText::Format(LOCTEXT("ReadFile_RequestFailed", "Read request failed for file ({0})"), FText::FromString(FileName)); - TriggerOnReadFileCompleteDelegates(false, FileName); - } - else if (CloudFile->AsyncState == EOnlineAsyncTaskState::Done) - { - ErrorMsg = FText::GetEmpty(); - TriggerOnReadFileCompleteDelegates(true, FileName); - } - return bStarted; -} - -void FOnlineTitleFileHttp::Tick(float DeltaTime) -{ - TArray ItemsToRemove; - ItemsToRemove.Reserve(AsyncLocalReads.Num()); - - // Check for any completed tasks - for (int32 TaskIdx = 0; TaskIdx < AsyncLocalReads.Num(); TaskIdx++) - { - FTitleAsyncReadData& Task = AsyncLocalReads[TaskIdx]; - if (Task.AsyncTask->IsDone()) - { - FinishReadFileLocal(Task.AsyncTask->GetTask()); - ItemsToRemove.Add(TaskIdx); - UE_LOG(LogHTTPChunkInstaller, VeryVerbose, TEXT("Title Task Complete: %s"), *Task.Filename); - } - else - { - const int64 NewValue = Task.BytesRead.GetValue(); - if (NewValue != Task.LastBytesRead) - { - Task.LastBytesRead = NewValue; - TriggerOnReadFileProgressDelegates(Task.Filename, NewValue); - } - } - } - - // Clean up any tasks that were completed - for (int32 ItemIdx = ItemsToRemove.Num() - 1; ItemIdx >= 0; ItemIdx--) - { - const int32 TaskIdx = ItemsToRemove[ItemIdx]; - FTitleAsyncReadData& TaskToDelete = AsyncLocalReads[TaskIdx]; - UE_LOG(LogHTTPChunkInstaller, VeryVerbose, TEXT("Title Task Removal: %s read: %d"), *TaskToDelete.Filename, TaskToDelete.BytesRead.GetValue()); - delete TaskToDelete.AsyncTask; - AsyncLocalReads.RemoveAtSwap(TaskIdx); - } -} - -bool FOnlineTitleFileHttp::StartReadFileLocal(const FString& FileName) -{ - UE_LOG(LogHTTPChunkInstaller, VeryVerbose, TEXT("StartReadFile %s"), *FileName); - bool bStarted = false; - FCloudFileHeader* CloudFileHeader = GetCloudFileHeader(FileName); - if (CloudFileHeader != nullptr) - { - // Mark file entry as in progress - FCloudFile* CloudFile = GetCloudFile(FileName, true); - CloudFile->AsyncState = EOnlineAsyncTaskState::InProgress; - if (CloudFileHeader->Hash.IsEmpty()) - { - UE_LOG(LogHTTPChunkInstaller, Warning, TEXT("Requested file (%s) is missing a hash, so can't be verified"), *FileName); - } - FTitleAsyncReadData* NewItem = new FTitleAsyncReadData(); - NewItem->Filename = FileName; - - // Create the async task and start it - NewItem->AsyncTask = new FAsyncTask(FileName, - GetLocalFilePath(FileName), CloudFileHeader->Hash, CloudFileHeader->HashType, &NewItem->BytesRead); - - AsyncLocalReads.Add(NewItem); - NewItem->AsyncTask->StartBackgroundTask(); - bStarted = true; - } - return bStarted; -} - -void FOnlineTitleFileHttp::FinishReadFileLocal(FTitleFileHttpAsyncLoadAndVerify& AsyncLoad) -{ - UE_LOG(LogHTTPChunkInstaller, VeryVerbose, TEXT("FinishReadFileLocal %s"), *AsyncLoad.OriginalFileName); - FCloudFileHeader* CloudFileHeader = GetCloudFileHeader(AsyncLoad.OriginalFileName); - FCloudFile* CloudFile = GetCloudFile(AsyncLoad.OriginalFileName, true); - if (CloudFileHeader != nullptr && CloudFile != nullptr) - { - // if hash matches then just use the local file - if (AsyncLoad.bHashesMatched) - { - UE_LOG(LogHTTPChunkInstaller, Verbose, TEXT("Local file hash matches cloud header. No need to download for filename=%s"), *AsyncLoad.OriginalFileName); - CloudFile->Data = AsyncLoad.FileData; - CloudFile->AsyncState = EOnlineAsyncTaskState::Done; - ErrorMsg = FText::GetEmpty(); - TriggerOnReadFileProgressDelegates(AsyncLoad.OriginalFileName, static_cast(AsyncLoad.BytesRead->GetValue())); - TriggerOnReadFileCompleteDelegates(true, AsyncLoad.OriginalFileName); - } - else - { - // Request it from server - ReadFileRemote(AsyncLoad.OriginalFileName); - } - } - else - { - UE_LOG(LogHTTPChunkInstaller, Warning, TEXT("ReadFile request failed for file (%s)"), *AsyncLoad.OriginalFileName); - ErrorMsg = FText::Format(LOCTEXT("ReadFile_RequestFailed", "Read request failed for file ({0})"), FText::FromString(AsyncLoad.OriginalFileName)); - TriggerOnReadFileCompleteDelegates(false, AsyncLoad.OriginalFileName); - } -} - -bool FOnlineTitleFileHttp::ReadFileRemote(const FString& FileName) -{ - UE_LOG(LogHTTPChunkInstaller, VeryVerbose, TEXT("ReadFileRemote %s"), *FileName); - - bool bStarted = false; - FCloudFileHeader* CloudFileHeader = GetCloudFileHeader(FileName); - if (CloudFileHeader != nullptr) - { - FCloudFile* CloudFile = GetCloudFile(FileName, true); - CloudFile->Data.Empty(); - CloudFile->AsyncState = EOnlineAsyncTaskState::InProgress; - - // Create the Http request and add to pending request list - TSharedRef HttpRequest = FHttpModule::Get().CreateRequest(); - FileRequests.Add(HttpRequest, FPendingFileRequest(FileName)); - FileProgressRequestsMap.Add(HttpRequest, FPendingFileRequest(FileName)); - - HttpRequest->OnProcessRequestComplete().BindRaw(this, &FOnlineTitleFileHttp::ReadFile_HttpRequestComplete); - HttpRequest->OnRequestProgress().BindRaw(this, &FOnlineTitleFileHttp::ReadFile_HttpRequestProgress); - FString RequestUrl; - // Grab the file from the specified URL if that was set, otherwise use the old method that hits the game service - if (CloudFileHeader != nullptr && !CloudFileHeader->URL.IsEmpty()) - { - RequestUrl = CloudFileHeader->URL; - } - else - { - RequestUrl = GetBaseUrl() + FileName; - } - HttpRequest->SetURL(RequestUrl); - HttpRequest->SetVerb(TEXT("GET")); - bStarted = HttpRequest->ProcessRequest(); - - if (!bStarted) - { - UE_LOG(LogHTTPChunkInstaller, Error, TEXT("Unable to start the HTTP request to fetch file (%s)"), *FileName); - } - } - else - { - UE_LOG(LogHTTPChunkInstaller, Error, TEXT("No cloud file header entry for filename=%s."), *FileName); - } - return bStarted; -} - -void FOnlineTitleFileHttp::EnumerateFiles_HttpRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded) -{ - const FPagedQuery& PendingOp = EnumerateFilesRequests.FindRef(HttpRequest); - EnumerateFilesRequests.Remove(HttpRequest); - - bool bResult = false; - FString ResponseStr; - - if (HttpResponse.IsValid() && (EHttpResponseCodes::IsOk(HttpResponse->GetResponseCode()) || HttpResponse->GetResponseCode() == EHttpResponseCodes::NotModified)) - { - ResponseStr = HttpResponse->GetContentAsString(); - UE_LOG(LogHTTPChunkInstaller, Verbose, TEXT("EnumerateFiles request complete. url=%s code=%d response=%s"), - *HttpRequest->GetURL(), HttpResponse->GetResponseCode(), *ResponseStr); - - if (PendingOp.Start == 0) - { - FileHeaders.Empty(); - } - - // parse the html for the file list - if (ResponseStr.StartsWith(TEXT(" Lines; - ResponseStr.ParseIntoArrayLines(Lines); - for (int Index = 0; Index < Lines.Num(); ++Index) - { - if (Lines[Index].StartsWith(TEXT("
  • "))) - { - TArray Elements; - Lines[Index].ParseIntoArray(Elements, TEXT(">")); - if (!Elements[2].StartsWith(TEXT("Chunks"))) - { - FString File = Elements[2].Replace(TEXT("GetResponseCode()) - { - case 403: - case 404: - ErrorMsg = LOCTEXT("MissingFile", "File not found."); - break; - - default: - ErrorMsg = FText::Format(LOCTEXT("HttpResponse", "HTTP {0} response"), - FText::AsNumber(HttpResponse->GetResponseCode())); - break; - } - } - else - { - ErrorMsg = LOCTEXT("ConnectionFailure", "Connection to the server failed."); - } - } - - if (!ErrorMsg.IsEmpty()) - { - UE_LOG(LogHTTPChunkInstaller, Warning, TEXT("EnumerateFiles request failed. %s"), *ErrorMsg.ToString()); - } - else - { - // Everything went ok, so we can remove any cached files that are not in the current list - DeleteCachedFiles(true); - } - - TriggerOnEnumerateFilesCompleteDelegates(bResult); -} - -FString FOnlineTitleFileHttp::GetBaseUrl() const -{ - return BaseUrl + TEXT("/") + BuildUrl + TEXT("/"); -} - -FOnlineTitleFileHttp::Compatible FOnlineTitleFileHttp::IsClientCompatible() const -{ - if (CompatibleClientVersion == 0) - { - // no manifest downloaded yet? - return Compatible::UnknownCompatibility; - } - uint32 BuildCl = FEngineVersion::Current().GetChangelist(); - if (BuildCl == 0) - { - // programmer build? - return Compatible::ClientIsCompatible; - } - - if (CompatibleClientVersion == BuildCl) - { - return Compatible::ClientIsCompatible; - } - return BuildCl < CompatibleClientVersion ? Compatible::ClientUpdateRequired : Compatible::ClientIsNewerThanMcp; -} - -bool FOnlineTitleFileHttp::ParseManifest(FString& ResponseStr) -{ - // Create the Json parser - TSharedPtr JsonObject; - TSharedRef > JsonReader = TJsonReaderFactory<>::Create(ResponseStr); - if (!FJsonSerializer::Deserialize(JsonReader, JsonObject) || !JsonObject.IsValid()) - { - ErrorMsg = LOCTEXT("ParseManifestError_Json", "Unable to parse manifest JSON."); - return false; - } - - // get the data location, just the same as the build version - BuildUrl = JsonObject->GetStringField(TEXT("BuildUrl")); - TSharedPtr ClientVersionValue = JsonObject->GetField(TEXT("ClientVersion")); - if (ClientVersionValue->Type == EJson::Number) - { - // load from JSON directly - CompatibleClientVersion = (uint32)ClientVersionValue->AsNumber(); - } - else - { - // parse the old CL_%u format - FString StringValue = ClientVersionValue->AsString(); - CompatibleClientVersion = FCString::Atoi(*StringValue.RightChop(3)); - } - - // Parse the array of file headers - TArray > JsonFileHeaders = JsonObject->GetArrayField(TEXT("files")); - for (TArray >::TConstIterator It(JsonFileHeaders); It; ++It) - { - TSharedPtr JsonFileHeader = (*It)->AsObject(); - if (JsonFileHeader.IsValid()) - { - FCloudFileHeader FileHeader; - if (JsonFileHeader->HasField(TEXT("hash"))) - { - FileHeader.Hash = JsonFileHeader->GetStringField(TEXT("hash")); - FileHeader.HashType = FileHeader.Hash.IsEmpty() ? NAME_None : NAME_SHA1; - } - // This one takes priority over the old SHA1 hash if present (requires platform support) - if (bPlatformSupportsSHA256 && JsonFileHeader->HasField(TEXT("hash256"))) - { - FString Hash256 = JsonFileHeader->GetStringField(TEXT("hash256")); - if (!Hash256.IsEmpty()) - { - FileHeader.Hash = Hash256; - FileHeader.HashType = FileHeader.Hash.IsEmpty() ? NAME_None : NAME_SHA256; - } - } - if (JsonFileHeader->HasField(TEXT("uniqueFilename"))) - { - FileHeader.DLName = JsonFileHeader->GetStringField(TEXT("uniqueFilename")); - } - if (JsonFileHeader->HasField(TEXT("filename"))) - { - FileHeader.FileName = JsonFileHeader->GetStringField(TEXT("filename")); - } - if (JsonFileHeader->HasField(TEXT("length"))) - { - FileHeader.FileSize = FMath::TruncToInt(JsonFileHeader->GetNumberField(TEXT("length"))); - } - if (JsonFileHeader->HasField(TEXT("URL"))) - { - FileHeader.URL = GetBaseUrl() + JsonFileHeader->GetStringField(TEXT("URL")); - } - - if (FileHeader.FileName.IsEmpty()) - { - FileHeader.FileName = FileHeader.DLName; - } - - // for now parse out the chunk ID - // TODO: move this in to the manifest itself - int startIndex = FileHeader.FileName.Find(TEXT("pakchunk")) + 8; - int endIndex = FileHeader.FileName.Find(TEXT("CL_")); - FString SubStr = FileHeader.FileName.Mid(startIndex, (endIndex - startIndex)); - FileHeader.ChunkID = FCString::Atoi(*SubStr); - - if (FileHeader.Hash.IsEmpty() || - (FileHeader.DLName.IsEmpty() && FileHeader.URL.IsEmpty()) || - FileHeader.HashType == NAME_None) - { - UE_LOG(LogHTTPChunkInstaller, Error, TEXT("Invalid file entry hash=%s hashType=%s dlname=%s filename=%s URL=%s"), - *FileHeader.Hash, - *FileHeader.HashType.ToString(), - *FileHeader.DLName, - *FileHeader.FileName, - *FileHeader.URL); - ErrorMsg = LOCTEXT("ParseManifestError_BadFileEntry", "Bad manifest (invalid file entry)."); - return false; - } - - int32 FoundIdx = INDEX_NONE; - for (int32 Idx = 0; Idx < FileHeaders.Num(); Idx++) - { - const FCloudFileHeader& ExistingFile = FileHeaders[Idx]; - if (ExistingFile.DLName == FileHeader.DLName) - { - FoundIdx = Idx; - break; - } - } - if (FoundIdx != INDEX_NONE) - { - FileHeaders[FoundIdx] = FileHeader; - } - else - { - FileHeaders.Add(FileHeader); - } - } - } - - return true; -} - -void FOnlineTitleFileHttp::ReadFile_HttpRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded) -{ - bool bResult = false; - FString ResponseStr; - - // should have a pending Http request - FPendingFileRequest PendingRequest = FileRequests.FindChecked(HttpRequest); - FileRequests.Remove(HttpRequest); - // remove from progress updates - FileProgressRequestsMap.Remove(HttpRequest); - HttpRequest->OnRequestProgress().Unbind(); - - // Cloud file being operated on - FCloudFile* CloudFile = GetCloudFile(PendingRequest.FileName, true); - CloudFile->AsyncState = EOnlineAsyncTaskState::Failed; - CloudFile->Data.Empty(); - - if (HttpResponse.IsValid() && EHttpResponseCodes::IsOk(HttpResponse->GetResponseCode())) - { - UE_LOG(LogHTTPChunkInstaller, Verbose, TEXT("ReadFile request complete. url=%s code=%d"), - *HttpRequest->GetURL(), HttpResponse->GetResponseCode()); - - // update the memory copy of the file with data that was just downloaded - CloudFile->AsyncState = EOnlineAsyncTaskState::Done; - CloudFile->Data = HttpResponse->GetContent(); - - if (bCacheFiles) - { - // cache to disk on successful download - SaveCloudFileToDisk(CloudFile->FileName, CloudFile->Data); - } - - bResult = true; - ErrorMsg = FText::GetEmpty(); - } - else - { - if (HttpResponse.IsValid()) - { - ErrorMsg = FText::Format(LOCTEXT("HttpResponseFrom", "HTTP {0} response from {1}"), - FText::AsNumber(HttpResponse->GetResponseCode()), - FText::FromString(HttpResponse->GetURL())); - } - else - { - ErrorMsg = FText::Format(LOCTEXT("HttpResponseTo", "Connection to {0} failed"), FText::FromString(HttpRequest->GetURL())); - } - } - - if (!ErrorMsg.IsEmpty()) - { - UE_LOG(LogHTTPChunkInstaller, Warning, TEXT("EnumerateFiles request failed. %s"), *ErrorMsg.ToString()); - } - TriggerOnReadFileCompleteDelegates(bResult, PendingRequest.FileName); -} - -void FOnlineTitleFileHttp::ReadFile_HttpRequestProgress(FHttpRequestPtr HttpRequest, int32 BytesSent, int32 BytesReceived) -{ - FPendingFileRequest PendingRequest = FileProgressRequestsMap.FindChecked(HttpRequest); - // Just forward this to anyone that is listening - TriggerOnReadFileProgressDelegates(PendingRequest.FileName, BytesReceived); -} - -FCloudFile* FOnlineTitleFileHttp::GetCloudFile(const FString& FileName, bool bCreateIfMissing) -{ - FCloudFile* CloudFile = NULL; - for (int Idx = 0; Idx < Files.Num(); Idx++) - { - if (Files[Idx].FileName == FileName) - { - CloudFile = &Files[Idx]; - break; - } - } - if (CloudFile == NULL && bCreateIfMissing) - { - CloudFile = new(Files)FCloudFile(FileName); - } - return CloudFile; -} - -FCloudFileHeader* FOnlineTitleFileHttp::GetCloudFileHeader(const FString& FileName) -{ - FCloudFileHeader* CloudFileHeader = NULL; - - for (int Idx = 0; Idx < FileHeaders.Num(); Idx++) - { - if (FileHeaders[Idx].DLName == FileName) - { - CloudFileHeader = &FileHeaders[Idx]; - break; - } - } - - return CloudFileHeader; -} - -void FOnlineTitleFileHttp::SaveCloudFileToDisk(const FString& Filename, const TArray& Data) -{ - // save local disk copy as well - FString LocalFilePath = GetLocalFilePath(Filename); - bool bSavedLocal = FFileHelper::SaveArrayToFile(Data, *LocalFilePath); - if (bSavedLocal) - { - UE_LOG(LogHTTPChunkInstaller, Verbose, TEXT("WriteUserFile request complete. Local file cache updated =%s"), - *LocalFilePath); - } - else - { - UE_LOG(LogHTTPChunkInstaller, Warning, TEXT("WriteUserFile request complete. Local file cache failed to update =%s"), - *LocalFilePath); - } -} - -void FTitleFileHttpAsyncLoadAndVerify::DoWork() -{ - // load file from disk - bool bLoadedFile = false; - - FArchive* Reader = IFileManager::Get().CreateFileReader(*FileName, FILEREAD_Silent); - if (Reader) - { - int64 SizeToRead = Reader->TotalSize(); - FileData.Reset(SizeToRead); - FileData.AddUninitialized(SizeToRead); - - uint8* FileDataPtr = FileData.GetData(); - - static const int64 ChunkSize = 100 * 1024; - - int64 TotalBytesRead = 0; - while (SizeToRead > 0) - { - int64 Val = FMath::Min(SizeToRead, ChunkSize); - Reader->Serialize(FileDataPtr + TotalBytesRead, Val); - BytesRead->Add(Val); - TotalBytesRead += Val; - SizeToRead -= Val; - } - - ensure(SizeToRead == 0 && Reader->TotalSize() == TotalBytesRead); - bLoadedFile = Reader->Close(); - delete Reader; - } - - // verify hash of file if it exists - if (bLoadedFile) - { - UE_LOG(LogHTTPChunkInstaller, Verbose, TEXT("ReadFile request. Local file read from cache =%s"), *FileName); - if (HashType == NAME_SHA1) - { - bHashesMatched = IsValidSHA1(ExpectedHash, FileData); - } - else if (HashType == NAME_SHA256) - { - bHashesMatched = IsValidSHA256(ExpectedHash, FileData); - } - } - else - { - UE_LOG(LogHTTPChunkInstaller, Verbose, TEXT("Local file (%s) not cached locally"), *FileName); - } - if (!bHashesMatched) - { - // Empty local that was loaded - FileData.Empty(); - } -} - -#undef LOCTEXT_NAMESPACE diff --git a/Engine/Plugins/Online/HTTPChunkInstaller/Source/Public/HTTPOnlineTitleFile.h b/Engine/Plugins/Online/HTTPChunkInstaller/Source/Public/HTTPOnlineTitleFile.h deleted file mode 100644 index bd7a9b9bfc27..000000000000 --- a/Engine/Plugins/Online/HTTPChunkInstaller/Source/Public/HTTPOnlineTitleFile.h +++ /dev/null @@ -1,344 +0,0 @@ -// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "CoreMinimal.h" -#include "Interfaces/OnlineTitleFileInterface.h" -#include "Interfaces/IHttpRequest.h" -#include "Misc/SecureHash.h" -#include "HAL/ThreadSafeCounter64.h" -#include "Misc/Paths.h" -#include "Stats/Stats.h" - -const FName NAME_SHA1(TEXT("SHA1")); -const FName NAME_SHA256(TEXT("SHA256")); - -class FTitleFileHttpAsyncLoadAndVerify : - public FNonAbandonableTask -{ -public: - /** File data loaded for the async read */ - TArray FileData; - /** Amount of data read from the file to be owned/referenced by the game thread */ - FThreadSafeCounter64* BytesRead; - /** The original name of the file being read */ - const FString OriginalFileName; - /** The name of the file being read off of disk */ - const FString FileName; - /** The hash value the backend said it should have */ - const FString ExpectedHash; - /** The hash type SHA1 or SHA256 right now */ - const FName HashType; - /** Whether the hashes matched */ - bool bHashesMatched; - - /** Initializes the variables needed to load and verify the data */ - FTitleFileHttpAsyncLoadAndVerify(const FString& InOriginalFileName, const FString& InFileName, const FString& InExpectedHash, const FName InHashType, FThreadSafeCounter64* InBytesReadCounter) : - BytesRead(InBytesReadCounter), - OriginalFileName(InOriginalFileName), - FileName(InFileName), - ExpectedHash(InExpectedHash), - HashType(InHashType), - bHashesMatched(false) - { - - } - - /** - * Loads and hashes the file data. Empties the data if the hash check fails - */ - void DoWork(); - - FORCEINLINE TStatId GetStatId() const - { - RETURN_QUICK_DECLARE_CYCLE_STAT(FTitleFileHttpAsyncLoadAndVerify, STATGROUP_ThreadPoolAsyncTasks); - } - -private: - /** Validates that a buffer matches the same signature as was specified */ - bool IsValidSHA1(const FString& Hash, const TArray& Source) const - { - uint8 LocalHash[20]; - FSHA1::HashBuffer(Source.GetData(), Source.Num(), LocalHash); - // concatenate 20 bye SHA1 hash to string - FString LocalHashStr; - for (int Idx = 0; Idx < 20; Idx++) - { - LocalHashStr += FString::Printf(TEXT("%02x"), LocalHash[Idx]); - } - return Hash == LocalHashStr; - } - bool IsValidSHA256(const FString& Hash, const TArray& Source) const - { - FSHA256Signature Signature; - if (FPlatformMisc::GetSHA256Signature(Source.GetData(), Source.Num(), Signature)) - { - return Signature.ToString() == Hash; - } - return false; - } -}; - - -// helper class for an HTTP Online Title File -class FOnlineTitleFileHttp : public IOnlineTitleFile -{ -public: - /** - * Constructor - * - * @param InSubsystem mcp subsystem being used - */ - FOnlineTitleFileHttp(const FString& InBaseUrl, const FString& InManifestData); - - /** - * Destructor - */ - virtual ~FOnlineTitleFileHttp() - {} - - /** - * Copies the file data into the specified buffer for the specified file - * - * @param FileName the name of the file to read - * @param FileContents the out buffer to copy the data into - * - * @return true if the data was copied, false otherwise - */ - virtual bool GetFileContents(const FString& FileName, TArray& FileContents) override; - - /** - * Empties the set of downloaded files if possible (no async tasks outstanding) - * - * @return true if they could be deleted, false if they could not - */ - virtual bool ClearFiles() override; - - /** - * Empties the cached data for this file if it is not being downloaded currently - * - * @param FileName the name of the file to remove from the cache - * - * @return true if it could be deleted, false if it could not - */ - virtual bool ClearFile(const FString& FileName) override; - - /** - * Delete cached files on disk - * - * @param bSkipEnumerated if true then only non-enumerated files are deleted - */ - virtual void DeleteCachedFiles(bool bSkipEnumerated) override; - - static FString GetManifestCacheLocation() - { - return FString::Printf(TEXT("%s/master.manifest"), *FPaths::GameSavedDir()); - } - - /** - * Requests a list of available files from the network store - * - * @return true if the request has started, false if not - */ - virtual bool EnumerateFiles(const FPagedQuery& Page = FPagedQuery()) override; - - /** - * Returns the list of files that was returned by the network store - * - * @param Files out array of file metadata - * - */ - virtual void GetFileList(TArray& OutFiles) override; - - /** - * Starts an asynchronous read of the specified file from the network platform's file store - * - * @param FileToRead the name of the file to read - * - * @return true if the calls starts successfully, false otherwise - */ - virtual bool ReadFile(const FString& FileName) override; - - /** Used to check that async tasks have completed and can be completed */ - virtual void Tick(float DeltaTime); - - void Shutdown() - { - - } - - FText GetErrorMsg() const { - return ErrorMsg; - } - -private: - - /** Reads the file from the local cache if it can. This is async */ - bool StartReadFileLocal(const FString& FileName); - - /** Completes the async operation of the local file read */ - void FinishReadFileLocal(FTitleFileHttpAsyncLoadAndVerify& AsyncLoad); - - /** Requests the file from MCP. This is async */ - bool ReadFileRemote(const FString& FileName); - - /** - * Delegate called when a Http request completes for enumerating list of file headers - */ - void EnumerateFiles_HttpRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded); - - /** - * Delegate called when a Http request completes for reading a cloud file - */ - void ReadFile_HttpRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded); - - /** - * Delegate called as a Http request progresses for reading a cloud file - */ - void ReadFile_HttpRequestProgress(FHttpRequestPtr HttpRequest, int32 BytesSent, int32 BytesReceived); - - /** - * Find/create cloud file entry - * - * @param FileName cached file entry to find - * @param bCreateIfMissing create the file entry if not found - * - * @return cached cloud file entry - */ - FCloudFile* GetCloudFile(const FString& FileName, bool bCreateIfMissing); - - /** - * Find cloud file header entry - * - * @param FileName cached file entry to find - * - * @return cached cloud file header entry - */ - FCloudFileHeader* GetCloudFileHeader(const FString& FileName); - - /** - * Converts filename into a local file cache path - * - * @param FileName name of file being loaded - * - * @return unreal file path to be used by file manager - */ - FString GetLocalFilePath(const FString& FileName) - { - return GetLocalCachePath() + FileName; - } - - /** - * @return full path to cache directory - */ - FString GetLocalCachePath() - { - return FPaths::GamePersistentDownloadDir() / TEXT("EMS/"); - } - - /** - * Save a file from a given user to disk - * - * @param FileName name of file being saved - * @param Data data to write to disk - */ - void SaveCloudFileToDisk(const FString& Filename, const TArray& Data); - - bool ParseManifest(FString& ResponseStr); - - /** - * Should use the initialization constructor instead - */ - FOnlineTitleFileHttp(); - - /** Config based url for accessing the HTTP server */ - FString BaseUrl; - - /** Config based url for enumerating list of cloud files*/ - FString EnumerateFilesUrl; - - /** Extended error message */ - FText ErrorMsg; - - /** Manifest file to be read from */ - FString Manifest; - - FString BuildUrl; - - uint32 CompatibleClientVersion; - - FString ManifestData; - -public: - FString GetBaseUrl() const; - - enum class Compatible - { - UnknownCompatibility, - ClientIsCompatible, - ClientUpdateRequired, - ClientIsNewerThanMcp - }; - Compatible IsClientCompatible() const; - -private: - /** List of pending Http requests for enumerating files */ - TMap EnumerateFilesRequests; - - /** Info used to send request for a file */ - struct FPendingFileRequest - { - /** - * Constructor - */ - FPendingFileRequest(const FString& InFileName = FString(TEXT(""))) - : FileName(InFileName) - { - - } - - /** - * Equality op - */ - inline bool operator==(const FPendingFileRequest& Other) const - { - return FileName == Other.FileName; - } - - /** File being operated on by the pending request */ - FString FileName; - }; - /** List of pending Http requests for reading files */ - TMap FileRequests; - TMap FileProgressRequestsMap; - - TArray FileHeaders; - TArray Files; - bool bCacheFiles; - bool bPlatformSupportsSHA256; - - /** Information about local file reads that are in progress */ - struct FTitleAsyncReadData - { - /** Name of the file being loaded */ - FString Filename; - /** Amount of data that has been loaded on the async thread so far */ - FThreadSafeCounter64 BytesRead; - /** Bytes read last time game thread noticed */ - int64 LastBytesRead; - /** Async tasks doing the work */ - FAsyncTask* AsyncTask; - - FTitleAsyncReadData() : - LastBytesRead(0), - AsyncTask(nullptr) - { } - - bool operator==(const FTitleAsyncReadData& Other) const - { - return Filename == Other.Filename && AsyncTask == Other.AsyncTask; - } - }; - /** Holds the outstanding tasks for hitch free loading and hash calculation */ - TIndirectArray AsyncLocalReads; -}; diff --git a/Engine/Plugins/Online/IOS/OnlineSubsystemIOS/OnlineSubsystemIOS.uplugin b/Engine/Plugins/Online/IOS/OnlineSubsystemIOS/OnlineSubsystemIOS.uplugin index 40968e33fe00..7f82c87af128 100644 --- a/Engine/Plugins/Online/IOS/OnlineSubsystemIOS/OnlineSubsystemIOS.uplugin +++ b/Engine/Plugins/Online/IOS/OnlineSubsystemIOS/OnlineSubsystemIOS.uplugin @@ -27,5 +27,11 @@ "Name": "OnlineSubsystemIOS", "LoadingPolicy": "Always" } + ], + "Plugins": [ + { + "Name": "OnlineSubsystem", + "Enabled": true + } ] } \ No newline at end of file diff --git a/Engine/Plugins/Online/IOS/OnlineSubsystemIOS/Source/OnlineSubsystemIOS.Build.cs b/Engine/Plugins/Online/IOS/OnlineSubsystemIOS/Source/OnlineSubsystemIOS.Build.cs index 3a07b72e8b60..bdfe5d389be2 100644 --- a/Engine/Plugins/Online/IOS/OnlineSubsystemIOS/Source/OnlineSubsystemIOS.Build.cs +++ b/Engine/Plugins/Online/IOS/OnlineSubsystemIOS/Source/OnlineSubsystemIOS.Build.cs @@ -5,7 +5,7 @@ using UnrealBuildTool; public class OnlineSubsystemIOS : ModuleRules { public OnlineSubsystemIOS(ReadOnlyTargetRules Target) : base(Target) - { + { PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; PrivateIncludePaths.AddRange( new string[] { diff --git a/Engine/Plugins/Online/IOS/OnlineSubsystemIOS/Source/Private/OnlineSubsystemIOS.cpp b/Engine/Plugins/Online/IOS/OnlineSubsystemIOS/Source/Private/OnlineSubsystemIOS.cpp index a5a88bdd2609..393cf58eb203 100644 --- a/Engine/Plugins/Online/IOS/OnlineSubsystemIOS/Source/Private/OnlineSubsystemIOS.cpp +++ b/Engine/Plugins/Online/IOS/OnlineSubsystemIOS/Source/Private/OnlineSubsystemIOS.cpp @@ -5,12 +5,16 @@ #import "OnlineAppStoreUtils.h" FOnlineSubsystemIOS::FOnlineSubsystemIOS() + : StoreHelper(nil) + , AppStoreHelper(nil) { StoreHelper = nil; } FOnlineSubsystemIOS::FOnlineSubsystemIOS(FName InInstanceName) : FOnlineSubsystemImpl(IOS_SUBSYSTEM, InInstanceName) + , StoreHelper(nil) + , AppStoreHelper(nil) { StoreHelper = nil; } @@ -199,6 +203,7 @@ void FOnlineSubsystemIOS::InitStoreKitHelper() void FOnlineSubsystemIOS::CleanupStoreKitHelper() { [StoreHelper release]; + StoreHelper = nil; } void FOnlineSubsystemIOS::InitAppStoreHelper() @@ -210,6 +215,7 @@ void FOnlineSubsystemIOS::InitAppStoreHelper() void FOnlineSubsystemIOS::CleanupAppStoreHelper() { [AppStoreHelper release]; + AppStoreHelper = nil; } FAppStoreUtils* FOnlineSubsystemIOS::GetAppStoreUtils() @@ -231,6 +237,11 @@ bool FOnlineSubsystemIOS::Tick(float DeltaTime) return true; } +FText FOnlineSubsystemIOS::GetOnlineServiceName() const +{ + return NSLOCTEXT("OnlineSubsystemIOS", "OnlineServiceName", "Game Center"); +} + bool FOnlineSubsystemIOS::Shutdown() { bool bSuccessfullyShutdown = true; diff --git a/Engine/Plugins/Online/IOS/OnlineSubsystemIOS/Source/Public/OnlineSubsystemIOS.h b/Engine/Plugins/Online/IOS/OnlineSubsystemIOS/Source/Public/OnlineSubsystemIOS.h index 84084340fa7c..dd7b9de6ef1b 100644 --- a/Engine/Plugins/Online/IOS/OnlineSubsystemIOS/Source/Public/OnlineSubsystemIOS.h +++ b/Engine/Plugins/Online/IOS/OnlineSubsystemIOS/Source/Public/OnlineSubsystemIOS.h @@ -51,6 +51,7 @@ public: virtual FString GetAppId() const override; virtual bool Exec(class UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) override; virtual bool Tick(float DeltaTime) override; + virtual FText GetOnlineServiceName() const override; //~ End IOnlineSubsystem Interface PACKAGE_SCOPE: diff --git a/Engine/Plugins/Online/OnlineFramework/OnlineFramework.uplugin b/Engine/Plugins/Online/OnlineFramework/OnlineFramework.uplugin index da4fb8aa8b50..7a1f907ff926 100644 --- a/Engine/Plugins/Online/OnlineFramework/OnlineFramework.uplugin +++ b/Engine/Plugins/Online/OnlineFramework/OnlineFramework.uplugin @@ -37,5 +37,15 @@ "Name": "OnlineFramework", "LoadingPolicy": "Always" } - ] + ], + "Plugins": [ + { + "Name": "OnlineSubsystem", + "Enabled": true + }, + { + "Name": "OnlineSubsystemUtils", + "Enabled": true + } + ] } \ No newline at end of file diff --git a/Engine/Plugins/Online/OnlineFramework/Source/Hotfix/Private/UpdateManager.cpp b/Engine/Plugins/Online/OnlineFramework/Source/Hotfix/Private/UpdateManager.cpp index 2749c37b412a..d119f31aa454 100644 --- a/Engine/Plugins/Online/OnlineFramework/Source/Hotfix/Private/UpdateManager.cpp +++ b/Engine/Plugins/Online/OnlineFramework/Source/Hotfix/Private/UpdateManager.cpp @@ -63,6 +63,11 @@ UUpdateManager::UUpdateManager() , UpdateStateEnum(nullptr) , UpdateCompletionEnum(nullptr) { +#if !PLATFORM_PS4 + // PS4 needs to detect its environment via a call to login + bPlatformEnvironmentDetected = true; +#endif + LastUpdateCheck[0] = LastUpdateCheck[1] = FDateTime(0); LastCompletionResult[0] = LastCompletionResult[1] = EUpdateCompletionStatus::UpdateUnknown; if (!HasAnyFlags(RF_ClassDefaultObject)) @@ -100,6 +105,9 @@ UUpdateManager::EUpdateStartResult UUpdateManager::StartCheckInternal(bool bInCh UE_LOG(LogHotfixManager, Display, TEXT("Update checks disabled!")); bInitialUpdateFinished = true; + // Move to the pending state until the delayed response can fire, to more closely match non-editor behavior. + SetUpdateState(EUpdateState::UpdatePending); + auto StartDelegate = [this]() { CheckComplete(EUpdateCompletionStatus::UpdateSuccess_NoChange); diff --git a/Engine/Plugins/Online/OnlineFramework/Source/LoginFlow/Private/LoginFlowManager.cpp b/Engine/Plugins/Online/OnlineFramework/Source/LoginFlow/Private/LoginFlowManager.cpp index c457d694d59d..cc4968ed3f93 100644 --- a/Engine/Plugins/Online/OnlineFramework/Source/LoginFlow/Private/LoginFlowManager.cpp +++ b/Engine/Plugins/Online/OnlineFramework/Source/LoginFlow/Private/LoginFlowManager.cpp @@ -7,6 +7,10 @@ #include "OnlineExternalUIInterface.h" #include "OnlineError.h" +#include "IWebBrowserSingleton.h" +#include "WebBrowserModule.h" +#include "IWebBrowserCookieManager.h" + DEFINE_LOG_CATEGORY(LogLoginFlow); #define LOGIN_TOKEN_FOUND FString() @@ -39,6 +43,11 @@ FLoginFlowManager::FLoginFlowManager() } FLoginFlowManager::~FLoginFlowManager() +{ + Reset(); +} + +void FLoginFlowManager::Reset() { // if we're in an active flow, just fire dismissal then shut down if (PendingLogin.IsValid()) @@ -54,16 +63,21 @@ FLoginFlowManager::~FLoginFlowManager() if (OnlineSub != nullptr) { IOnlineExternalUIPtr OnlineExternalUI = OnlineSub->GetExternalUIInterface(); + IOnlineIdentityPtr OnlineIdentity = OnlineSub->GetIdentityInterface(); if (OnlineExternalUI.IsValid()) { OnlineExternalUI->ClearOnLoginFlowUIRequiredDelegate_Handle(OnlineParams.LoginFlowUIRequiredDelegateHandle); } + if (OnlineIdentity.IsValid()) + { + OnlineIdentity->ClearOnLoginFlowLogoutDelegate_Handle(OnlineParams.LoginFlowLogoutDelegateHandle); + } } } OnlineSubsystemsMap.Empty(); } -bool FLoginFlowManager::AddLoginFlow(FName OnlineIdentifier, const FOnDisplayPopup& InPopupDelegate) +bool FLoginFlowManager::AddLoginFlow(FName OnlineIdentifier, const FOnDisplayPopup& InPopupDelegate, bool bPersistCookies) { bool bSuccess = false; @@ -73,13 +87,42 @@ bool FLoginFlowManager::AddLoginFlow(FName OnlineIdentifier, const FOnDisplayPop IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get(OnlineIdentifier); if (OnlineSub != nullptr) { - // bind to the OSS delegate + // get information from OSS and bind to the OSS delegate + IOnlineIdentityPtr OnlineIdentity = OnlineSub->GetIdentityInterface(); IOnlineExternalUIPtr OnlineExternalUI = OnlineSub->GetExternalUIInterface(); - if (OnlineExternalUI.IsValid()) + if (OnlineIdentity.IsValid() && OnlineExternalUI.IsValid()) { + IWebBrowserSingleton* WebBrowserSingleton = IWebBrowserModule::Get().GetSingleton(); + FString ContextName = FString::Printf(TEXT("LoginFlowContext_%s"), *OnlineIdentifier.ToString()); + FOnlineParams& NewParams = OnlineSubsystemsMap.Add(OnlineIdentifier); NewParams.OnlineIdentifier = OnlineIdentifier; NewParams.OnDisplayPopup = InPopupDelegate; +#ifdef WEBBROWSER_HASAPPLICATIONCACHEDIR + NewParams.BrowserContextSettings = MakeShared(ContextName); + NewParams.BrowserContextSettings->bPersistSessionCookies = bPersistCookies; + if (NewParams.BrowserContextSettings->bPersistSessionCookies) + { + // Taken from FWebBrowserSingleton + FString CachePath(FPaths::Combine(WebBrowserSingleton->ApplicationCacheDir(), TEXT("webcache"))); + CachePath = FPaths::ConvertRelativePathToFull(CachePath); + NewParams.BrowserContextSettings->CookieStorageLocation = CachePath; + } + + if (!WebBrowserSingleton->RegisterContext(*NewParams.BrowserContextSettings)) + { + UE_LOG(LogLoginFlow, Warning, TEXT("Failed to register context in web browser singleton for %s"), *NewParams.BrowserContextSettings->Id); + } + + NewParams.LoginFlowLogoutDelegateHandle = OnlineIdentity->AddOnLoginFlowLogoutDelegate_Handle(FOnLoginFlowLogoutDelegate::CreateSP(this, &FLoginFlowManager::OnLoginFlowLogout, OnlineIdentifier)); +#else + if (!bPersistCookies) + { + // context settings to not persist cookies + NewParams.BrowserContextSettings = MakeShared(TEXT("LoginFlowContext")); + } +#endif + NewParams.LoginFlowUIRequiredDelegateHandle = OnlineExternalUI->AddOnLoginFlowUIRequiredDelegate_Handle(FOnLoginFlowUIRequiredDelegate::CreateSP(this, &FLoginFlowManager::OnLoginFlowStarted, OnlineIdentifier)); bSuccess = true; } @@ -131,12 +174,12 @@ void FLoginFlowManager::OnLoginFlowStarted(const FString& RequestedURL, const FO SAssignNew(PendingLogin->PopupHolder, SBox); // give the widget to the App to display and get back a callback we should use to dismiss it - FString AnalyticsSessionId; PendingLogin->OnPopupDismissed = Params->OnDisplayPopup.Execute(PendingLogin->PopupHolder.ToSharedRef()); // generate a login flow chromium widget ILoginFlowModule::FCreateSettings CreateSettings; CreateSettings.Url = RequestedURL; + CreateSettings.BrowserContextSettings = Params->BrowserContextSettings; // Setup will allow login flow module events to trigger passed in delegates CreateSettings.CloseCallback = FOnLoginFlowRequestClose::CreateSP(this, &FLoginFlowManager::OnLoginFlow_Close, PendingLogin->InstanceId); @@ -247,3 +290,26 @@ void FLoginFlowManager::FinishLogin() // clear this object so we can handle another login PendingLogin.Reset(); } + +void FLoginFlowManager::OnLoginFlowLogout(const TArray& LoginDomains, FName InOnlineIdentifier) +{ + FOnlineParams* Params = OnlineSubsystemsMap.Find(InOnlineIdentifier); + if (Params) + { + IWebBrowserSingleton* WebBrowserSingleton = IWebBrowserModule::Get().GetSingleton(); + TOptional ContextId; + if (Params->BrowserContextSettings.IsValid()) + { + ContextId = Params->BrowserContextSettings->Id; + } + TSharedPtr CookieManager = WebBrowserSingleton->GetCookieManager(ContextId); + for (const FString& LoginDomain : LoginDomains) + { + CookieManager->DeleteCookies(LoginDomain); + } + } + else + { + UE_LOG(LogLoginFlow, Error, TEXT("No login flow registered for online subsystem %s"), *InOnlineIdentifier.ToString()); + } +} diff --git a/Engine/Plugins/Online/OnlineFramework/Source/LoginFlow/Private/LoginFlowViewModel.cpp b/Engine/Plugins/Online/OnlineFramework/Source/LoginFlow/Private/LoginFlowViewModel.cpp index dca5d7ec124c..83c40aca6e0a 100644 --- a/Engine/Plugins/Online/OnlineFramework/Source/LoginFlow/Private/LoginFlowViewModel.cpp +++ b/Engine/Plugins/Online/OnlineFramework/Source/LoginFlow/Private/LoginFlowViewModel.cpp @@ -34,9 +34,12 @@ public: virtual bool HandleBrowserUrlChanged(const FText& Url) override { - if (OnRedirectURL.IsBound()) + if (0) // HandleBeforeBrowse seems to do all that is required atm { - return OnRedirectURL.Execute(Url.ToString()); + if (OnRedirectURL.IsBound()) + { + return OnRedirectURL.Execute(Url.ToString()); + } } return false; } diff --git a/Engine/Plugins/Online/OnlineFramework/Source/LoginFlow/Private/SLoginFlow.cpp b/Engine/Plugins/Online/OnlineFramework/Source/LoginFlow/Private/SLoginFlow.cpp index 6c2ccf2b4a49..9f0de9f25c1a 100644 --- a/Engine/Plugins/Online/OnlineFramework/Source/LoginFlow/Private/SLoginFlow.cpp +++ b/Engine/Plugins/Online/OnlineFramework/Source/LoginFlow/Private/SLoginFlow.cpp @@ -254,10 +254,13 @@ private: void HandleBrowserUrlChanged(const FText& Url) { - FString CurrentURL = MainBrowser->GetUrl(); - UE_LOG(LogLoginFlow, Log, TEXT("HandleBrowserUrlChanged Current: %s New: %s"), *CurrentURL, *Url.ToString()); + if (0) // HandleBrowserBeforeBrowse seems to do all that is required atm + { + FString CurrentURL = MainBrowser->GetUrl(); + UE_LOG(LogLoginFlow, Log, TEXT("HandleBrowserUrlChanged Current: %s New: %s"), *CurrentURL, *Url.ToString()); - ViewModel->HandleBrowserUrlChanged(Url); + ViewModel->HandleBrowserUrlChanged(Url); + } } bool HandleBrowserCloseWindow(const TWeakPtr& BrowserWindowPtr) @@ -446,12 +449,15 @@ private: bool HandleBrowserBeforeBrowse(const FString& Url, const FWebNavigationRequest& Request) { - UE_LOG(LogLoginFlow, Log, TEXT("HandleBrowserBeforeBrowse URL: %s %d Redirect: %d"), *Url, Request.bIsMainFrame, Request.bIsRedirect); - - if (Request.bIsRedirect) + if (Request.bIsMainFrame && Request.bIsRedirect) { + UE_LOG(LogLoginFlow, Log, TEXT("HandleBrowserBeforeBrowse URL: %s"), *Url); return ViewModel->HandleBeforeBrowse(Url); } + else + { + UE_LOG(LogLoginFlow, VeryVerbose, TEXT("HandleBrowserBeforeBrowse skipped URL: %s MainFrame: %d Redirect: %d"), *Url, Request.bIsMainFrame, Request.bIsRedirect); + } return false; } diff --git a/Engine/Plugins/Online/OnlineFramework/Source/LoginFlow/Public/ILoginFlowManager.h b/Engine/Plugins/Online/OnlineFramework/Source/LoginFlow/Public/ILoginFlowManager.h index 5488e4fbdf93..76987d96c229 100644 --- a/Engine/Plugins/Online/OnlineFramework/Source/LoginFlow/Public/ILoginFlowManager.h +++ b/Engine/Plugins/Online/OnlineFramework/Source/LoginFlow/Public/ILoginFlowManager.h @@ -34,11 +34,16 @@ public: /** * Register an online subsystem with the login flow factory (call at startup) * - * @param InOnlineIdentifier online subsystem identifier requiring a login flow UI + * @param OnlineIdentifier online subsystem identifier requiring a login flow UI * @param InPopupDelegate external delegate to receive widgets from the login flow + * @param bPersistCookies let the global web context manage cookies, or keep them in memory only + * @return whether or not the login flow was successfully added */ - virtual bool AddLoginFlow(FName OnlineIdentifier, const FOnDisplayPopup& InPopupDelegate) = 0; + virtual bool AddLoginFlow(FName OnlineIdentifier, const FOnDisplayPopup& InPopupDelegate, bool bPersistCookies = true) = 0; /** Cancel an active login flow */ virtual void CancelLoginFlow() = 0; + + /** Cleanup and remove all registered login flows, detaching from online subsystems */ + virtual void Reset() = 0; }; diff --git a/Engine/Plugins/Online/OnlineFramework/Source/LoginFlow/Public/LoginFlowManager.h b/Engine/Plugins/Online/OnlineFramework/Source/LoginFlow/Public/LoginFlowManager.h index 50d39669c305..f596be3c997f 100644 --- a/Engine/Plugins/Online/OnlineFramework/Source/LoginFlow/Public/LoginFlowManager.h +++ b/Engine/Plugins/Online/OnlineFramework/Source/LoginFlow/Public/LoginFlowManager.h @@ -22,8 +22,9 @@ public: ~FLoginFlowManager(); //~ Begin ILoginFlowManager interface - virtual bool AddLoginFlow(FName OnlineIdentifier, const FOnDisplayPopup& InPopupDelegate) override; + virtual bool AddLoginFlow(FName OnlineIdentifier, const FOnDisplayPopup& InPopupDelegate, bool bPersistCookies) override; virtual void CancelLoginFlow() override; + virtual void Reset() override; //~ End ILoginFlowManager interface private: @@ -39,6 +40,9 @@ private: /** Finish login flow, notifying listeners */ void FinishLogin(); + /** Delegate fired by online identity when a logout/cleanup is requested */ + void OnLoginFlowLogout(const TArray& LoginDomains, FName OnlineIdentifier); + private: struct FOnlineParams @@ -47,7 +51,12 @@ private: FName OnlineIdentifier; /** Single-cast delegate instance (bind to this to handle display) */ FOnDisplayPopup OnDisplayPopup; + /** Handle to bound login flow ui required delegate */ FDelegateHandle LoginFlowUIRequiredDelegateHandle; + /** Handle to bound login flow logout delegate */ + FDelegateHandle LoginFlowLogoutDelegateHandle; + /** Optional browser context settings if bPersistCookies is false */ + TSharedPtr BrowserContextSettings; }; /** Mapping of online subsystem identifiers to the parameters they have setup for login flow */ diff --git a/Engine/Plugins/Online/OnlineFramework/Source/Party/Private/Chatroom.cpp b/Engine/Plugins/Online/OnlineFramework/Source/Party/Private/Chatroom.cpp index 2f64e3fe0307..f08654e48d2d 100644 --- a/Engine/Plugins/Online/OnlineFramework/Source/Party/Private/Chatroom.cpp +++ b/Engine/Plugins/Online/OnlineFramework/Source/Party/Private/Chatroom.cpp @@ -236,8 +236,6 @@ void UChatroom::OnChatRoomLeft(const FUniqueNetId& LocalUserId, const FChatRoomI void UChatroom::ChatRoomLeftInternal(const FChatRoomId& RoomId, const FOnChatRoomLeft& CompletionDelegate) { - ensure(CurrentChatRoomId.IsEmpty()); - GetTimerManager().SetTimerForNextTick(FTimerDelegate::CreateLambda([CompletionDelegate, RoomId]() { // Announce that chat is available diff --git a/Engine/Plugins/Online/OnlineFramework/Source/Party/Private/Party.cpp b/Engine/Plugins/Online/OnlineFramework/Source/Party/Private/Party.cpp index ad58161216e7..fd5447e848b5 100644 --- a/Engine/Plugins/Online/OnlineFramework/Source/Party/Private/Party.cpp +++ b/Engine/Plugins/Online/OnlineFramework/Source/Party/Private/Party.cpp @@ -13,6 +13,17 @@ #define LOCTEXT_NAMESPACE "Parties" +namespace PartyConsoleVariables +{ + // CVars + TAutoConsoleVariable CVarPartyEnableAutoRejoin( + TEXT("Party.CVarEnableAutoRejoin"), + 1, + TEXT("Enable automatic rejoining of parties\n") + TEXT("1 Enables. 0 disables."), + ECVF_Default); +} + UParty::UParty(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer), bLeavingPersistentParty(false) @@ -97,7 +108,7 @@ void UParty::OnLogoutComplete(int32 LocalUserNum, bool bWasSuccessful) } else { - UE_LOG(LogParty, Log, TEXT("[%s] Removed - Invalid party Id")); + UE_LOG(LogParty, Log, TEXT("Removed - Invalid party Id")); } Party->HandleRemovedFromParty(EMemberExitedReason::Left); } @@ -556,7 +567,8 @@ void UParty::PartyStateChanged(const FUniqueNetId& LocalUserId, const FOnlinePar if (State == EPartyState::Disconnected) { // If we have other members in our party, then we will try to rejoin this when we come back online - if (ShouldCacheDisconnectedPersistentPartyForRejoin(PartyState)) + if (PartyConsoleVariables::CVarPartyEnableAutoRejoin.GetValueOnGameThread() && + ShouldCacheDisconnectedPersistentPartyForRejoin(PartyState)) { UE_LOG(LogParty, Log, TEXT("PartyStateChanged: [%s] Caching party for rejoin"), *InPartyId.ToString()); TArray> MemberIds; diff --git a/Engine/Plugins/Online/OnlineFramework/Source/Party/Private/PartyGameState.cpp b/Engine/Plugins/Online/OnlineFramework/Source/Party/Private/PartyGameState.cpp index f6244763ed71..df8e50d3b40c 100644 --- a/Engine/Plugins/Online/OnlineFramework/Source/Party/Private/PartyGameState.cpp +++ b/Engine/Plugins/Online/OnlineFramework/Source/Party/Private/PartyGameState.cpp @@ -1016,6 +1016,28 @@ void UPartyGameState::SetAcceptingMembers(bool bIsAcceptingMembers, EJoinPartyDe } } +bool UPartyGameState::IsAcceptingMembers(EJoinPartyDenialReason* const DenialReason /*= nullptr*/) const +{ + if (CurrentConfig.bIsAcceptingMembers) + { + // Accepting members + if (DenialReason != nullptr) + { + *DenialReason = EJoinPartyDenialReason::NoReason; + } + return true; + } + else + { + // Not accepting members + if (DenialReason != nullptr) + { + *DenialReason = static_cast(CurrentConfig.NotAcceptingMembersReason); + } + return false; + } +} + bool UPartyGameState::IsInJoinableGameState() const { bool bInGame = false; @@ -1095,6 +1117,8 @@ void UPartyGameState::OnUpdatePartyConfigComplete(const FUniqueNetId& LocalUserI { CurrentConfig = *OssParty->Config; bDebugAcceptingMembers = CurrentConfig.bIsAcceptingMembers; + + OnPartyConfigurationChanged().Broadcast(CurrentConfig); } } diff --git a/Engine/Plugins/Online/OnlineFramework/Source/Party/Public/PartyGameState.h b/Engine/Plugins/Online/OnlineFramework/Source/Party/Public/PartyGameState.h index bd93cb2422fc..a3719c6ee2d8 100644 --- a/Engine/Plugins/Online/OnlineFramework/Source/Party/Public/PartyGameState.h +++ b/Engine/Plugins/Online/OnlineFramework/Source/Party/Public/PartyGameState.h @@ -175,6 +175,13 @@ private: */ DECLARE_MULTICAST_DELEGATE_OneParam(FOnInvitesDisabledChanged, bool /* bInvitesDisabled */); + /** + * Delegate fired when a party's configuration is updated + * + * @param NewConfiguration Updated configuration + */ + DECLARE_MULTICAST_DELEGATE_OneParam(FOnPartyConfigurationChanged, const FPartyConfiguration& /* NewConfiguration */); + protected: @@ -275,6 +282,13 @@ public: */ void SetAcceptingMembers(bool bIsAcceptingMembers, EJoinPartyDenialReason DenialReason); + /** + * Check if we are currently accepting members. + * + * @param Optional pointer to a Denial reason that is set when the party is not joinable + */ + bool IsAcceptingMembers(EJoinPartyDenialReason* const DenialReason = nullptr) const; + /** * Check if you have permission to send invites to this party * @@ -348,6 +362,8 @@ public: FOnLeaderInvitesOnlyChanged& OnLeaderInvitesOnlyChanged() { return LeaderInvitesOnlyChanged; } /** @return delegate fired when invite permissions have changed */ FOnInvitesDisabledChanged& OnInvitesDisabledChanged() { return InvitesDisabledChanged; } + /** @return delegate fired when the party configuration has changed */ + FOnPartyConfigurationChanged& OnPartyConfigurationChanged() { return PartyConfigurationChanged; } protected: @@ -456,6 +472,7 @@ protected: FOnLeaderFriendsOnlyChanged LeaderFriendsOnlyChanged; FOnLeaderInvitesOnlyChanged LeaderInvitesOnlyChanged; FOnInvitesDisabledChanged InvitesDisabledChanged; + FOnPartyConfigurationChanged PartyConfigurationChanged; /** * Common initialization for a newly instantiated party diff --git a/Engine/Plugins/Online/OnlineFramework/Source/Rejoin/Public/RejoinCheck.h b/Engine/Plugins/Online/OnlineFramework/Source/Rejoin/Public/RejoinCheck.h index 4c5202be156a..c6a7a3724fa1 100644 --- a/Engine/Plugins/Online/OnlineFramework/Source/Rejoin/Public/RejoinCheck.h +++ b/Engine/Plugins/Online/OnlineFramework/Source/Rejoin/Public/RejoinCheck.h @@ -89,7 +89,7 @@ public: * * @param CompletionDelegate delegate called after the check for possible rejoin is complete */ - void CheckRejoinStatus(const FOnRejoinCheckComplete& CompletionDelegate = FOnRejoinCheckComplete()); + virtual void CheckRejoinStatus(const FOnRejoinCheckComplete& CompletionDelegate = FOnRejoinCheckComplete()); /** * Rejoin the last session if one is found. One final call to CheckRejoinStatus is made to @@ -174,11 +174,12 @@ protected: /** Clear all timers associated with rejoin */ void ClearTimers(); -private: - /** Rejoin status */ UPROPERTY() ERejoinStatus LastKnownStatus; + +private: + /** Flag set during a possible brief period where the user hit rejoin but the check was already in flight */ UPROPERTY() bool bRejoinAfterCheck; diff --git a/Engine/Plugins/Online/OnlineSubsystem/Source/OnlineSubsystem.Build.cs b/Engine/Plugins/Online/OnlineSubsystem/Source/OnlineSubsystem.Build.cs index 3e3b7532fedb..20926c1759fd 100644 --- a/Engine/Plugins/Online/OnlineSubsystem/Source/OnlineSubsystem.Build.cs +++ b/Engine/Plugins/Online/OnlineSubsystem/Source/OnlineSubsystem.Build.cs @@ -5,7 +5,7 @@ using UnrealBuildTool; public class OnlineSubsystem : ModuleRules { public OnlineSubsystem(ReadOnlyTargetRules Target) : base(Target) - { + { PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; PublicDependencyModuleNames.AddRange( diff --git a/Engine/Plugins/Online/OnlineSubsystem/Source/Private/OnlineNotification.cpp b/Engine/Plugins/Online/OnlineSubsystem/Source/Private/OnlineNotification.cpp index 73a9b88b06f3..fb2964ae8940 100644 --- a/Engine/Plugins/Online/OnlineSubsystem/Source/Private/OnlineNotification.cpp +++ b/Engine/Plugins/Online/OnlineSubsystem/Source/Private/OnlineNotification.cpp @@ -3,52 +3,36 @@ #include "OnlineNotification.h" #include "Serialization/JsonTypes.h" #include "JsonObjectConverter.h" +#include "OnlineSubsystem.h" -FOnlineNotification::FOnlineNotification() : -Payload(nullptr), -ToUserId(nullptr), -FromUserId(nullptr) -{ - -} - -// Treated as a system notification unless ToUserId is added -FOnlineNotification::FOnlineNotification(const FString& InTypeStr, const TSharedPtr& InPayload) +FOnlineNotification::FOnlineNotification( + const FString& InTypeStr, + const TSharedPtr& InPayload, + TSharedPtr InToUserId, + TSharedPtr InFromUserId +) : TypeStr(InTypeStr) -, Payload(InPayload) -, ToUserId(nullptr) -, FromUserId(nullptr) -{ - -} - -// Notification to a specific user. FromUserId is optional -FOnlineNotification::FOnlineNotification(const FString& InTypeStr, const TSharedPtr& InPayload, TSharedPtr InToUserId) -: TypeStr(InTypeStr) -, Payload(InPayload) -, ToUserId(InToUserId) -, FromUserId(nullptr) -{ - -} - -FOnlineNotification::FOnlineNotification(const FString& InTypeStr, const TSharedPtr& InPayload, TSharedPtr InToUserId, TSharedPtr InFromUserId) -: TypeStr(InTypeStr) -, Payload(InPayload) +, Payload(InPayload.IsValid() ? InPayload->AsObject() : nullptr) , ToUserId(InToUserId) , FromUserId(InFromUserId) { - } bool FOnlineNotification::ParsePayload(UStruct* StructType, void* StructPtr) const { - if (StructType && StructPtr) + check(StructType && StructPtr); + return Payload.IsValid() && FJsonObjectConverter::JsonObjectToUStruct(Payload.ToSharedRef(), StructType, StructPtr, 0, 0); +} + +void FOnlineNotification::SetTypeFromPayload() +{ + // Lazy init of type, if supplied in payload + if (Payload.IsValid() && TypeStr.IsEmpty()) { - if (Payload.IsValid() && Payload->Type == EJson::Object) + if (!Payload->TryGetStringField(TEXT("Type"), TypeStr)) { - return FJsonObjectConverter::JsonObjectToUStruct(Payload->AsObject().ToSharedRef(), StructType, StructPtr, 0, 0); + UE_LOG(LogOnline, Error, TEXT("No type in notification JSON object")); + TypeStr = TEXT(""); } } - return false; } diff --git a/Engine/Plugins/Online/OnlineSubsystem/Source/Private/OnlinePartyInterface.cpp b/Engine/Plugins/Online/OnlineSubsystem/Source/Private/OnlinePartyInterface.cpp index 1b4179678b3b..c858cfe99ccf 100644 --- a/Engine/Plugins/Online/OnlineSubsystem/Source/Private/OnlinePartyInterface.cpp +++ b/Engine/Plugins/Online/OnlineSubsystem/Source/Private/OnlinePartyInterface.cpp @@ -115,8 +115,6 @@ bool FPartyConfiguration::operator==(const FPartyConfiguration& Other) const { return JoinRequestAction == Other.JoinRequestAction && PresencePermissions == Other.PresencePermissions && - JoinRequestAction == Other.JoinRequestAction && - PresencePermissions == Other.PresencePermissions && InvitePermissions == Other.InvitePermissions && bChatEnabled == Other.bChatEnabled && bIsAcceptingMembers == Other.bIsAcceptingMembers && diff --git a/Engine/Plugins/Online/OnlineSubsystem/Source/Private/OnlineSessionSettings.cpp b/Engine/Plugins/Online/OnlineSubsystem/Source/Private/OnlineSessionSettings.cpp index a46f407b8ff1..6a47ac4a28f0 100644 --- a/Engine/Plugins/Online/OnlineSubsystem/Source/Private/OnlineSessionSettings.cpp +++ b/Engine/Plugins/Online/OnlineSubsystem/Source/Private/OnlineSessionSettings.cpp @@ -203,6 +203,8 @@ void FOnlineSearchSettings::Set(FName Key, const ValueType& Value, EOnlineCompar } } +/// @cond DOXYGEN_WARNINGS + /** Explicit instantiation of supported types to Set template above */ template ONLINESUBSYSTEM_API void FOnlineSearchSettings::Set(FName Key, const int32& Value, EOnlineComparisonOp::Type InType, int32 InID); template ONLINESUBSYSTEM_API void FOnlineSearchSettings::Set(FName Key, const float& Value, EOnlineComparisonOp::Type InType, int32 InID); @@ -212,6 +214,8 @@ template ONLINESUBSYSTEM_API void FOnlineSearchSettings::Set(FName Key, template ONLINESUBSYSTEM_API void FOnlineSearchSettings::Set< TArray >(FName Key, const TArray& Value, EOnlineComparisonOp::Type InType, int32 InID); template ONLINESUBSYSTEM_API void FOnlineSearchSettings::Set(FName Key, const bool& Value, EOnlineComparisonOp::Type InType, int32 InID); +/// @endcond + template void FOnlineSearchSettings::Set(FName Key, const ValueType& Value, EOnlineComparisonOp::Type InType) { @@ -227,6 +231,8 @@ void FOnlineSearchSettings::Set(FName Key, const ValueType& Value, EOnlineCompar } } +/// @cond DOXYGEN_WARNINGS + /** Explicit instantiation of supported types to Set template above */ template ONLINESUBSYSTEM_API void FOnlineSearchSettings::Set(FName Key, const int32& Value, EOnlineComparisonOp::Type InType); template ONLINESUBSYSTEM_API void FOnlineSearchSettings::Set(FName Key, const float& Value, EOnlineComparisonOp::Type InType); @@ -236,6 +242,8 @@ template ONLINESUBSYSTEM_API void FOnlineSearchSettings::Set(FName Key, template ONLINESUBSYSTEM_API void FOnlineSearchSettings::Set< TArray >(FName Key, const TArray& Value, EOnlineComparisonOp::Type InType); template ONLINESUBSYSTEM_API void FOnlineSearchSettings::Set(FName Key, const bool& Value, EOnlineComparisonOp::Type InType); +/// @endcond + template bool FOnlineSearchSettings::Get(FName Key, ValueType& Value) const { @@ -249,6 +257,8 @@ bool FOnlineSearchSettings::Get(FName Key, ValueType& Value) const return false; } +/// @cond DOXYGEN_WARNINGS + /** Explicit instantiation of supported types to Get template above */ template ONLINESUBSYSTEM_API bool FOnlineSearchSettings::Get(FName Key, int32& Value) const; template ONLINESUBSYSTEM_API bool FOnlineSearchSettings::Get(FName Key, float& Value) const; @@ -258,6 +268,8 @@ template ONLINESUBSYSTEM_API bool FOnlineSearchSettings::Get(FName Key, template ONLINESUBSYSTEM_API bool FOnlineSearchSettings::Get< TArray >(FName Key, TArray& Value) const; template ONLINESUBSYSTEM_API bool FOnlineSearchSettings::Get(FName Key, bool& Value) const; +/// @endcond + EOnlineComparisonOp::Type FOnlineSearchSettings::GetComparisonOp(FName Key) const { const FOnlineSessionSearchParam* SearchParam = SearchParams.Find(Key); diff --git a/Engine/Plugins/Online/OnlineSubsystem/Source/Private/OnlineSubsystemImpl.cpp b/Engine/Plugins/Online/OnlineSubsystem/Source/Private/OnlineSubsystemImpl.cpp index b4838b2e824c..414476b76713 100644 --- a/Engine/Plugins/Online/OnlineSubsystem/Source/Private/OnlineSubsystemImpl.cpp +++ b/Engine/Plugins/Online/OnlineSubsystem/Source/Private/OnlineSubsystemImpl.cpp @@ -10,6 +10,12 @@ #include "Interfaces/OnlineFriendsInterface.h" #include "Interfaces/OnlinePurchaseInterface.h" +#if UE_BUILD_SHIPPING +#include "JsonObject.h" +#include "JsonReader.h" +#include "JsonSerializer.h" +#endif + namespace OSSConsoleVariables { // CVars diff --git a/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineChatInterface.h b/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineChatInterface.h index d8c1cf7129aa..a0ba2d03f394 100644 --- a/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineChatInterface.h +++ b/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineChatInterface.h @@ -201,6 +201,7 @@ typedef FOnChatPrivateMessageReceived::FDelegate FOnChatPrivateMessageReceivedDe class IOnlineChat { public: + virtual ~IOnlineChat() { } /** * Kick off request for creating a chat room with a provided configuration diff --git a/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineEntitlementsInterface.h b/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineEntitlementsInterface.h index 472047898b52..080e70e2d040 100644 --- a/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineEntitlementsInterface.h +++ b/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineEntitlementsInterface.h @@ -37,6 +37,9 @@ struct FOnlineEntitlement , ConsumedCount(0) {} + virtual ~FOnlineEntitlement() + {} + /** * @return Any additional data associated with the entitlement */ @@ -72,6 +75,8 @@ typedef FOnQueryEntitlementsComplete::FDelegate FOnQueryEntitlementsCompleteDele class IOnlineEntitlements { public: + virtual ~IOnlineEntitlements() { } + /** * Checks for and retrieves a single cached entitlement for a user * diff --git a/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineExternalUIInterface.h b/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineExternalUIInterface.h index 7a748eaab1a2..924a1f8bdc95 100644 --- a/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineExternalUIInterface.h +++ b/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineExternalUIInterface.h @@ -37,6 +37,15 @@ struct FLoginFlowResult const bool bError = !Error.bSucceeded && Error.NumericErrorCode; return bSuccess || bError; } + + FString ToDebugString() const + { +#if UE_BUILD_SHIPPING + return FString::Printf(TEXT("Token: [REDACTED] Error: %s"), Error.ToLogString()); +#else + return FString::Printf(TEXT("Token: %s Error: %s"), *Token, Error.ToLogString()); +#endif + } }; /** diff --git a/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineIdentityInterface.h b/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineIdentityInterface.h index e7ece2c5d069..7bfa2e73a3c5 100644 --- a/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineIdentityInterface.h +++ b/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineIdentityInterface.h @@ -113,6 +113,14 @@ typedef FOnLoginComplete::FDelegate FOnLoginCompleteDelegate; DECLARE_MULTICAST_DELEGATE_TwoParams(FOnLogoutComplete, int32 /*LocalUserNum*/, bool /*bWasSuccessful*/); typedef FOnLogoutComplete::FDelegate FOnLogoutCompleteDelegate; +/** + * Delegate called when logout requires login flow to cleanup + * + * @param LoginDomains the login domains to clean up + */ +DECLARE_MULTICAST_DELEGATE_OneParam(FOnLoginFlowLogout, const TArray& /*LoginDomains*/); +typedef FOnLoginFlowLogout::FDelegate FOnLoginFlowLogoutDelegate; + /** * Interface for registration/authentication of user identities */ @@ -217,6 +225,12 @@ public: */ DEFINE_ONLINE_PLAYER_DELEGATE_ONE_PARAM(MAX_LOCAL_PLAYERS, OnLogoutComplete, bool); + /** + * Delegate called when the online subsystem requires an the login flow to logout and cleanup + * @param LoginDomains login domains to be cleaned up + */ + DEFINE_ONLINE_DELEGATE_ONE_PARAM(OnLoginFlowLogout, const TArray& /*LoginDomains*/); + /** * Logs the player into the online service using parameters passed on the * command line. Expects -AUTH_LOGIN= -AUTH_PASSWORD=. If either diff --git a/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineMessageInterface.h b/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineMessageInterface.h index afbbd6772a60..d937c9fc8d10 100644 --- a/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineMessageInterface.h +++ b/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineMessageInterface.h @@ -199,6 +199,8 @@ class IOnlineMessage public: + virtual ~IOnlineMessage() { } + /** * Enumerate list of available message headers from user's inbox * diff --git a/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineSessionInterface.h b/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineSessionInterface.h index c97050a08830..047391e10678 100644 --- a/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineSessionInterface.h +++ b/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineSessionInterface.h @@ -110,6 +110,32 @@ namespace EOnJoinSessionCompleteResult UnknownError }; } + +namespace Lex +{ + /** Convert a EOnJoinSessionCompleteResult into a string */ + inline const TCHAR* ToString(const EOnJoinSessionCompleteResult::Type Value) + { + switch (Value) + { + case EOnJoinSessionCompleteResult::Success: + return TEXT("Success"); + case EOnJoinSessionCompleteResult::SessionIsFull: + return TEXT("SessionIsFull"); + case EOnJoinSessionCompleteResult::SessionDoesNotExist: + return TEXT("SessionDoesNotExist"); + case EOnJoinSessionCompleteResult::CouldNotRetrieveAddress: + return TEXT("CouldNotretrieveAddress"); + case EOnJoinSessionCompleteResult::AlreadyInSession: + return TEXT("AlreadyInSession"); + case EOnJoinSessionCompleteResult::UnknownError: + ; // Intentional fall-through + } + + return TEXT("UnknownError"); + } +} + /** * Delegate fired when the joining process for an online session has completed * diff --git a/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineSharingInterface.h b/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineSharingInterface.h index d597c2214f03..b1a66da8890a 100644 --- a/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineSharingInterface.h +++ b/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineSharingInterface.h @@ -126,6 +126,7 @@ DECLARE_DELEGATE_ThreeParams(FOnRequestCurrentPermissionsComplete, int32 /*Local class IOnlineSharing { public: + virtual ~IOnlineSharing() { } /////////////////////////////////////////////////////////// // PERMISSIONS diff --git a/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineStoreInterface.h b/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineStoreInterface.h index 006a4f52163e..5a4e8420287d 100644 --- a/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineStoreInterface.h +++ b/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineStoreInterface.h @@ -230,6 +230,8 @@ class IOnlineStore { public: + virtual ~IOnlineStore() { } + /** * Search for what purchases are available * diff --git a/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineUserCloudInterface.h b/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineUserCloudInterface.h index 302b66f77fa0..4aa2a91f1849 100644 --- a/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineUserCloudInterface.h +++ b/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineUserCloudInterface.h @@ -78,7 +78,7 @@ typedef FOnDeleteUserFileComplete::FDelegate FOnDeleteUserFileCompleteDelegate; * @param BytesUsed Will be set to the total number of bytes used by the user * @param TotalQuota The total number of bytes the user is entitled to write */ -DECLARE_MULTICAST_DELEGATE_FourParams(FOnRequestUsageInfoComplete, bool, const FUniqueNetId&, int64, TOptional); +DECLARE_MULTICAST_DELEGATE_FourParams(FOnRequestUsageInfoComplete, bool, const FUniqueNetId&, int64, const TOptional&); typedef FOnRequestUsageInfoComplete::FDelegate FOnRequestUsageInfoCompleteDelegate; @@ -257,7 +257,7 @@ public: * @param BytesUsed Will be set to the total number of bytes used by the user * @param TotalQuota The total number of bytes the user is entitled to write */ - DEFINE_ONLINE_DELEGATE_FOUR_PARAM(OnRequestUsageInfoComplete, bool, const FUniqueNetId&, int64, TOptional); + DEFINE_ONLINE_DELEGATE_FOUR_PARAM(OnRequestUsageInfoComplete, bool, const FUniqueNetId&, int64, const TOptional&); /** * Print out the state of the cloud for this service diff --git a/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineUserInterface.h b/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineUserInterface.h index 2eb81f1518b8..47487a0915bd 100644 --- a/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineUserInterface.h +++ b/Engine/Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineUserInterface.h @@ -35,6 +35,8 @@ class IOnlineUser public: + virtual ~IOnlineUser() { } + /** * Starts an async task that queries/reads the info for a list of users * diff --git a/Engine/Plugins/Online/OnlineSubsystem/Source/Public/OnlineAsyncTaskManager.h b/Engine/Plugins/Online/OnlineSubsystem/Source/Public/OnlineAsyncTaskManager.h index a85292286299..3e414e9052d2 100644 --- a/Engine/Plugins/Online/OnlineSubsystem/Source/Public/OnlineAsyncTaskManager.h +++ b/Engine/Plugins/Online/OnlineSubsystem/Source/Public/OnlineAsyncTaskManager.h @@ -204,7 +204,7 @@ public: virtual bool WasSuccessful() override { return true; } private: - /** True after it has ticked once and run the Callable on the online thred */ + /** True after it has ticked once and run the Callable on the online thread */ bool bHasTicked; /** Stored copy of the object to invoke on the game thread. */ CallableType CallableObject; @@ -263,7 +263,20 @@ public: }; /** - * + * The foundation of all async operations in every online subsystem + * + * A task manager ticks on its own thread, managing both a serial and parallel queue of FOnlineAsyncTasks + * Each task works through the serial queue in the following manner + * GameThread + * - Initialize() + * OnlineThread + * -- Tick() until IsDone() + * -- Add task to OutQueue + * GameThread + * - Finalize() + * - TriggerDelegates() + * + * Parallel task queue works in a similar flow, except the tasks don't wait for any previous tasks to complete */ class ONLINESUBSYSTEM_API FOnlineAsyncTaskManager : public FRunnable, FSingleThreadRunnable { diff --git a/Engine/Plugins/Online/OnlineSubsystem/Source/Public/OnlineNotification.h b/Engine/Plugins/Online/OnlineSubsystem/Source/Public/OnlineNotification.h index 4a20490d036b..96124a03cda2 100644 --- a/Engine/Plugins/Online/OnlineSubsystem/Source/Public/OnlineNotification.h +++ b/Engine/Plugins/Online/OnlineSubsystem/Source/Public/OnlineNotification.h @@ -4,46 +4,56 @@ #include "CoreMinimal.h" #include "UObject/CoreOnline.h" +#include "JsonObjectWrapper.h" class FJsonValue; /** Notification object, used to send messages between systems */ struct ONLINESUBSYSTEM_API FOnlineNotification { -public: - FOnlineNotification() ; - - // Treated as a system notification unless ToUserId is added - FOnlineNotification(const FString& InTypeStr, const TSharedPtr& InPayload); - - // Notification to a specific user. FromUserId is optional - FOnlineNotification(const FString& InTypeStr, const TSharedPtr& InPayload, TSharedPtr InToUserId); - - FOnlineNotification(const FString& InTypeStr, const TSharedPtr& InPayload, TSharedPtr InToUserId, TSharedPtr InFromUserId); - -public: + /** + * Default constructor + */ + FOnlineNotification() + { + } /** - * Templated helper for payload parsing - * @param PayloadOut The structure to read the payload into + * Constructor from type and FJsonValue + * System message unless ToUserId is specified; FromUserId optional */ - template - FORCEINLINE bool ParsePayload(USTRUCT_T& PayloadOut, const FString& ExpectedType) const + FOnlineNotification( + const FString& InTypeStr, + const TSharedPtr& InPayload, + TSharedPtr InToUserId = nullptr, + TSharedPtr InFromUserId = nullptr + ); + + /** + * Constructor from type and FJsonObject + * System message unless ToUserId is specified; FromUserId optional + */ + FOnlineNotification( + const FString& InTypeStr, + const TSharedPtr& InPayload, + TSharedPtr InToUserId = nullptr, + TSharedPtr InFromUserId = nullptr + ) + : TypeStr(InTypeStr) + , Payload(InPayload) + , ToUserId(InToUserId) + , FromUserId(InFromUserId) { - if (TypeStr != ExpectedType) - { - return false; - } - return ParsePayload(USTRUCT_T::StaticStruct(), &PayloadOut); } + /** * Parse a payload and assume there is a static const TypeStr member to use */ - template - FORCEINLINE bool ParsePayload(USTRUCT_T& PayloadOut) const + template + bool ParsePayload(FStruct& PayloadOut) const { - return ParsePayload(PayloadOut, USTRUCT_T::TypeStr); + return ParsePayload(FStruct::StaticStruct(), &PayloadOut); } /** @@ -51,13 +61,24 @@ public: */ bool ParsePayload(UStruct* StructType, void* StructPtr) const; -public: + /** + * Does this notification have a valid payload? + */ + explicit operator bool() const + { + return Payload.IsValid(); + } + + /** + * Set up the type string for the case where the type is embedded in the payload + */ + void SetTypeFromPayload(); /** A string defining the type of this notification, used to determine how to parse the payload */ FString TypeStr; /** The payload of this notification */ - TSharedPtr Payload; + TSharedPtr Payload; /** User to deliver the notification to. Can be null for system notifications. */ TSharedPtr ToUserId; diff --git a/Engine/Plugins/Online/OnlineSubsystem/Source/Public/OnlineSubsystem.h b/Engine/Plugins/Online/OnlineSubsystem/Source/Public/OnlineSubsystem.h index ed2712f963df..8c1cc63c5fb8 100644 --- a/Engine/Plugins/Online/OnlineSubsystem/Source/Public/OnlineSubsystem.h +++ b/Engine/Plugins/Online/OnlineSubsystem/Source/Public/OnlineSubsystem.h @@ -541,6 +541,11 @@ public: * @param UserIdList - list of other users in the PS4 party to send invites to */ DEFINE_ONLINE_DELEGATE_TWO_PARAM(OnPlayTogetherEventReceived, int32, TArray>); + + /** + * @return The name of the online service this platform uses + */ + virtual FText GetOnlineServiceName() const = 0; }; /** Public references to the online subsystem pointer should use this */ diff --git a/Engine/Plugins/Online/OnlineSubsystem/Source/Public/OnlineSubsystemNames.h b/Engine/Plugins/Online/OnlineSubsystem/Source/Public/OnlineSubsystemNames.h index 9b0083084fdf..a1a82f2264eb 100644 --- a/Engine/Plugins/Online/OnlineSubsystem/Source/Public/OnlineSubsystemNames.h +++ b/Engine/Plugins/Online/OnlineSubsystem/Source/Public/OnlineSubsystemNames.h @@ -40,10 +40,18 @@ #define PS4_SUBSYSTEM FName(TEXT("PS4")) #endif +#ifndef PS4SERVER_SUBSYSTEM +#define PS4SERVER_SUBSYSTEM FName(TEXT("PS4SERVER")) +#endif + #ifndef LIVE_SUBSYSTEM #define LIVE_SUBSYSTEM FName(TEXT("LIVE")) #endif +#ifndef LIVESERVER_SUBSYSTEM +#define LIVESERVER_SUBSYSTEM FName(TEXT("LIVESERVER")) +#endif + #ifndef THUNDERHEAD_SUBSYSTEM #define THUNDERHEAD_SUBSYSTEM FName(TEXT("THUNDERHEAD")) #endif @@ -60,6 +68,10 @@ #define WECHAT_SUBSYSTEM FName(TEXT("WeChat")) #endif +#ifndef TWITCH_SUBSYSTEM +#define TWITCH_SUBSYSTEM FName(TEXT("TWITCH")) +#endif + #ifndef SWITCH_SUBSYSTEM #define SWITCH_SUBSYSTEM FName(TEXT("SWITCH")) #endif diff --git a/Engine/Plugins/Online/OnlineSubsystemAmazon/OnlineSubsystemAmazon.uplugin b/Engine/Plugins/Online/OnlineSubsystemAmazon/OnlineSubsystemAmazon.uplugin index 347b62988c79..682a67be538b 100644 --- a/Engine/Plugins/Online/OnlineSubsystemAmazon/OnlineSubsystemAmazon.uplugin +++ b/Engine/Plugins/Online/OnlineSubsystemAmazon/OnlineSubsystemAmazon.uplugin @@ -22,5 +22,11 @@ "Name": "OnlineSubsystemAmazon", "LoadingPolicy": "Always" } + ], + "Plugins": [ + { + "Name": "OnlineSubsystem", + "Enabled": true + } ] } \ No newline at end of file diff --git a/Engine/Plugins/Online/OnlineSubsystemAmazon/Source/OnlineSubsystemAmazon.Build.cs b/Engine/Plugins/Online/OnlineSubsystemAmazon/Source/OnlineSubsystemAmazon.Build.cs index 3fcbbd8c5d42..2125908aeff0 100644 --- a/Engine/Plugins/Online/OnlineSubsystemAmazon/Source/OnlineSubsystemAmazon.Build.cs +++ b/Engine/Plugins/Online/OnlineSubsystemAmazon/Source/OnlineSubsystemAmazon.Build.cs @@ -6,7 +6,7 @@ using System.IO; public class OnlineSubsystemAmazon : ModuleRules { public OnlineSubsystemAmazon(ReadOnlyTargetRules Target) : base(Target) - { + { Definitions.Add("ONLINESUBSYSTEMAMAZON_PACKAGE=1"); PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; diff --git a/Engine/Plugins/Online/OnlineSubsystemAmazon/Source/Private/OnlineSubsystemAmazon.cpp b/Engine/Plugins/Online/OnlineSubsystemAmazon/Source/Private/OnlineSubsystemAmazon.cpp index 3ea15935aeaa..40e2635c0a8a 100644 --- a/Engine/Plugins/Online/OnlineSubsystemAmazon/Source/Private/OnlineSubsystemAmazon.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemAmazon/Source/Private/OnlineSubsystemAmazon.cpp @@ -113,6 +113,11 @@ bool FOnlineSubsystemAmazon::Exec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevi return false; } +FText FOnlineSubsystemAmazon::GetOnlineServiceName() const +{ + return NSLOCTEXT("OnlineSubsystemAmazon", "OnlineServiceName", "Amazon"); +} + bool FOnlineSubsystemAmazon::IsEnabled(void) { // Check the ini for disabling Amazon diff --git a/Engine/Plugins/Online/OnlineSubsystemAmazon/Source/Public/OnlineSubsystemAmazon.h b/Engine/Plugins/Online/OnlineSubsystemAmazon/Source/Public/OnlineSubsystemAmazon.h index dd291c291027..e24d65a1156d 100644 --- a/Engine/Plugins/Online/OnlineSubsystemAmazon/Source/Public/OnlineSubsystemAmazon.h +++ b/Engine/Plugins/Online/OnlineSubsystemAmazon/Source/Public/OnlineSubsystemAmazon.h @@ -63,6 +63,7 @@ public: virtual bool Shutdown() override; virtual FString GetAppId() const override; virtual bool Exec(class UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) override; + virtual FText GetOnlineServiceName() const override; // FTickerBaseObject diff --git a/Engine/Plugins/Online/OnlineSubsystemFacebook/OnlineSubsystemFacebook.uplugin b/Engine/Plugins/Online/OnlineSubsystemFacebook/OnlineSubsystemFacebook.uplugin index 3976cd6f799f..33b09de6136f 100644 --- a/Engine/Plugins/Online/OnlineSubsystemFacebook/OnlineSubsystemFacebook.uplugin +++ b/Engine/Plugins/Online/OnlineSubsystemFacebook/OnlineSubsystemFacebook.uplugin @@ -28,5 +28,12 @@ "Name": "OnlineSubsystemFacebook", "LoadingPolicy": "Always" } + ], + "Plugins": [ + { + "Name": "OnlineSubsystem", + "Enabled": true + } ] + } \ No newline at end of file diff --git a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/OnlineSubsystemFacebook.Build.cs b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/OnlineSubsystemFacebook.Build.cs index 3f1526e31125..c2b1fa7b52e0 100644 --- a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/OnlineSubsystemFacebook.Build.cs +++ b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/OnlineSubsystemFacebook.Build.cs @@ -5,52 +5,79 @@ using UnrealBuildTool; public class OnlineSubsystemFacebook : ModuleRules { - public OnlineSubsystemFacebook(ReadOnlyTargetRules Target) : base(Target) + public OnlineSubsystemFacebook(ReadOnlyTargetRules Target) : base(Target) { Definitions.Add("ONLINESUBSYSTEMFACEBOOK_PACKAGE=1"); PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; - PrivateIncludePaths.Add("Private"); + PrivateIncludePaths.Add("Private"); - PrivateDependencyModuleNames.AddRange( - new string[] { - "Core", - "CoreUObject", - "HTTP", + PrivateDependencyModuleNames.AddRange( + new string[] { + "Core", + "CoreUObject", + "HTTP", "ImageCore", "Json", - "OnlineSubsystem", - } - ); - - AddEngineThirdPartyPrivateStaticDependencies(Target, "Facebook"); - - if (Target.Platform == UnrealTargetPlatform.IOS) - { - PrivateIncludePaths.Add("Private/IOS"); - } - else if (Target.Platform == UnrealTargetPlatform.Android) - { - Definitions.Add("UE4_FACEBOOK_VER=4.19.0"); - - PrivateDependencyModuleNames.AddRange( - new string[] { - "Launch", + "OnlineSubsystem", } ); - string PluginPath = Utils.MakePathRelativeTo(ModuleDirectory, BuildConfiguration.RelativeEnginePath); - AdditionalPropertiesForReceipt.Add(new ReceiptProperty("AndroidPlugin", Path.Combine(PluginPath, "OnlineSubsystemFacebook_UPL.xml"))); + AddEngineThirdPartyPrivateStaticDependencies(Target, "Facebook"); - PrivateIncludePaths.Add("Private/Android"); - } - else if (Target.Platform == UnrealTargetPlatform.Win32 || Target.Platform == UnrealTargetPlatform.Win64) - { - PrivateIncludePaths.Add("Private/Windows"); - } + if (Target.Platform == UnrealTargetPlatform.IOS) + { + Definitions.Add("WITH_FACEBOOK=1"); + PrivateIncludePaths.Add("Private/IOS"); + } + else if (Target.Platform == UnrealTargetPlatform.Android) + { + bool bHasFacebookSDK = false; + string FacebookNFLDir = ""; + try + { + FacebookNFLDir = System.IO.Path.Combine(ModuleDirectory, "ThirdParty", "Android", "NotForLicensees", "FacebookSDK"); + bHasFacebookSDK = System.IO.Directory.Exists(FacebookNFLDir); + } + catch (System.Exception) + { + } + + PrivateIncludePaths.Add("Private/Android"); + + if (bHasFacebookSDK) + { + string Err = string.Format("Facebook SDK found in {0}", FacebookNFLDir); + System.Console.WriteLine(Err); + + Definitions.Add("WITH_FACEBOOK=1"); + Definitions.Add("UE4_FACEBOOK_VER=4.19.0"); + + PrivateDependencyModuleNames.AddRange( + new string[] { + "Launch", + } + ); + + string PluginPath = Utils.MakePathRelativeTo(ModuleDirectory, BuildConfiguration.RelativeEnginePath); + AdditionalPropertiesForReceipt.Add(new ReceiptProperty("AndroidPlugin", Path.Combine(PluginPath, "OnlineSubsystemFacebook_UPL.xml"))); + } + else + { + string Err = string.Format("Facebook SDK not found in {0}", FacebookNFLDir); + System.Console.WriteLine(Err); + Definitions.Add("WITH_FACEBOOK=0"); + } + } + else if (Target.Platform == UnrealTargetPlatform.Win32 || Target.Platform == UnrealTargetPlatform.Win64) + { + Definitions.Add("WITH_FACEBOOK=1"); + PrivateIncludePaths.Add("Private/Windows"); + } else { + Definitions.Add("WITH_FACEBOOK=0"); PrecompileForTargets = PrecompileTargetsType.None; } } -} +} \ No newline at end of file diff --git a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/OnlineSubsystemFacebook_UPL.xml b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/OnlineSubsystemFacebook_UPL.xml index 088dbc38ba17..b6ae171e5791 100644 --- a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/OnlineSubsystemFacebook_UPL.xml +++ b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/OnlineSubsystemFacebook_UPL.xml @@ -30,9 +30,9 @@ - + - + @@ -76,6 +76,11 @@ + +-keep class epicgames.ue4.FacebookLogin.** { + public *; +} + diff --git a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Android/OnlineFriendsFacebook.cpp b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Android/OnlineFriendsFacebook.cpp index a7a9014881eb..c7323b670635 100644 --- a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Android/OnlineFriendsFacebook.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Android/OnlineFriendsFacebook.cpp @@ -3,6 +3,8 @@ #include "OnlineFriendsFacebook.h" #include "OnlineSubsystemFacebookPrivate.h" +#if WITH_FACEBOOK + FOnlineFriendsFacebook::FOnlineFriendsFacebook(FOnlineSubsystemFacebook* InSubsystem) : FOnlineFriendsFacebookCommon(InSubsystem) { @@ -17,3 +19,5 @@ FOnlineFriendsFacebook::~FOnlineFriendsFacebook() { } +#endif // WITH_FACEBOOK + diff --git a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Android/OnlineIdentityFacebook.cpp b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Android/OnlineIdentityFacebook.cpp index c3e8af757aaa..5d2b740e7840 100644 --- a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Android/OnlineIdentityFacebook.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Android/OnlineIdentityFacebook.cpp @@ -3,6 +3,8 @@ #include "OnlineIdentityFacebook.h" #include "OnlineSubsystemFacebookPrivate.h" +#if WITH_FACEBOOK + #include "Android/AndroidJNI.h" #include "Android/AndroidApplication.h" #include "Misc/ConfigCacheIni.h" @@ -163,7 +165,7 @@ void FOnlineIdentityFacebook::OnLoginAttemptComplete(int32 LocalUserNum, const F bool FOnlineIdentityFacebook::Logout(int32 LocalUserNum) { - bool bTriggeredLogin = false; + bool bTriggeredLogout = false; bool bPendingOp = LoginCompletionDelegate.IsBound() || LogoutCompletionDelegate.IsBound(); if (!bPendingOp) { @@ -195,8 +197,8 @@ bool FOnlineIdentityFacebook::Logout(int32 LocalUserNum) }); extern bool AndroidThunkCpp_Facebook_Logout(); - bTriggeredLogin = AndroidThunkCpp_Facebook_Logout(); - if (!ensure(bTriggeredLogin)) + bTriggeredLogout = AndroidThunkCpp_Facebook_Logout(); + if (!ensure(bTriggeredLogout)) { // Only if JEnv is wrong OnLogoutComplete(EFacebookLoginResponse::RESPONSE_ERROR); @@ -212,7 +214,7 @@ bool FOnlineIdentityFacebook::Logout(int32 LocalUserNum) UE_LOG_ONLINE(Warning, TEXT("Operation already in progress")); } - if (!bTriggeredLogin) + if (!bTriggeredLogout) { FacebookSubsystem->ExecuteNextTick([this, LocalUserNum]() { @@ -220,7 +222,7 @@ bool FOnlineIdentityFacebook::Logout(int32 LocalUserNum) }); } - return bTriggeredLogin; + return bTriggeredLogout; } void FOnlineIdentityFacebook::OnLoginComplete(EFacebookLoginResponse InResponseCode, const FString& InAccessToken) @@ -341,7 +343,7 @@ bool AndroidThunkCpp_Facebook_Logout() JNI_METHOD void Java_com_epicgames_ue4_FacebookLogin_nativeLogoutComplete(JNIEnv* jenv, jobject thiz, jsize responseCode) { EFacebookLoginResponse LogoutResponse = (EFacebookLoginResponse)responseCode; - UE_LOG_ONLINE(Verbose, TEXT("nativeLogoutComplete %s"), ToString(LogoutResponse)); + UE_LOG_ONLINE(VeryVerbose, TEXT("nativeLogoutComplete %s"), ToString(LogoutResponse)); DECLARE_CYCLE_STAT(TEXT("FSimpleDelegateGraphTask.ProcessFacebookLogout"), STAT_FSimpleDelegateGraphTask_ProcessFacebookLogout, STATGROUP_TaskGraphTasks); FSimpleDelegateGraphTask::CreateAndDispatchWhenReady( @@ -363,7 +365,7 @@ JNI_METHOD void Java_com_epicgames_ue4_FacebookLogin_nativeLogoutComplete(JNIEnv ); } - +#endif // WITH_FACEBOOK diff --git a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Android/OnlineIdentityFacebook.h b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Android/OnlineIdentityFacebook.h index a82f409b83c7..b082422fb0a9 100644 --- a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Android/OnlineIdentityFacebook.h +++ b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Android/OnlineIdentityFacebook.h @@ -14,7 +14,7 @@ enum class EFacebookLoginResponse : uint8 { /** Facebook SDK ok response */ RESPONSE_OK = 0, - /** Facebook SDK user cancelation */ + /** Facebook SDK user cancellation */ RESPONSE_CANCELED = 1, /** Facebook SDK error */ RESPONSE_ERROR = 2, diff --git a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Android/OnlineSharingFacebook.cpp b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Android/OnlineSharingFacebook.cpp index fddc6b777ce4..0ad1339188fe 100644 --- a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Android/OnlineSharingFacebook.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Android/OnlineSharingFacebook.cpp @@ -5,6 +5,8 @@ #include "OnlineSubsystemFacebookPrivate.h" #include "OnlineIdentityFacebook.h" +#if WITH_FACEBOOK + #include "Android/AndroidJNI.h" #include "Android/AndroidApplication.h" #include "Async/TaskGraphInterfaces.h" @@ -284,3 +286,5 @@ JNI_METHOD void Java_com_epicgames_ue4_FacebookLogin_nativeRequestPublishPermiss ENamedThreads::GameThread ); } + +#endif // WITH_FACEBOOK diff --git a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Android/OnlineSubsystemFacebook.cpp b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Android/OnlineSubsystemFacebook.cpp index 55748b633096..be3e3a6885a5 100644 --- a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Android/OnlineSubsystemFacebook.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Android/OnlineSubsystemFacebook.cpp @@ -21,10 +21,14 @@ FOnlineSubsystemFacebook::~FOnlineSubsystemFacebook() bool FOnlineSubsystemFacebook::Init() { +#if WITH_FACEBOOK FacebookIdentity = MakeShareable(new FOnlineIdentityFacebook(this)); FacebookFriends = MakeShareable(new FOnlineFriendsFacebook(this)); FacebookSharing = MakeShareable(new FOnlineSharingFacebook(this)); return true; +#else + return false; +#endif } bool FOnlineSubsystemFacebook::Shutdown() diff --git a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Android/OnlineUserFacebook.cpp b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Android/OnlineUserFacebook.cpp index 681972238675..dc586b76c2b6 100644 --- a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Android/OnlineUserFacebook.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Android/OnlineUserFacebook.cpp @@ -4,6 +4,8 @@ #include "OnlineUserFacebook.h" #include "OnlineSubsystemFacebookPrivate.h" +#if WITH_FACEBOOK + FOnlineUserFacebook::FOnlineUserFacebook(FOnlineSubsystemFacebook* InSubsystem) : FOnlineUserFacebookCommon(InSubsystem) { @@ -12,3 +14,5 @@ FOnlineUserFacebook::FOnlineUserFacebook(FOnlineSubsystemFacebook* InSubsystem) FOnlineUserFacebook::~FOnlineUserFacebook() { } + +#endif // WITH_FACEBOOK diff --git a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/OnlineIdentityFacebookCommon.cpp b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/OnlineIdentityFacebookCommon.cpp index a17254e746f1..d181ef409bb1 100644 --- a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/OnlineIdentityFacebookCommon.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/OnlineIdentityFacebookCommon.cpp @@ -131,8 +131,13 @@ void FOnlineIdentityFacebookCommon::MeUser_HttpRequestComplete(FHttpRequestPtr H ResponseStr = HttpResponse->GetContentAsString(); if (EHttpResponseCodes::IsOk(HttpResponse->GetResponseCode())) { +#if UE_BUILD_SHIPPING + static const FString URL = TEXT("[REDACTED]"); +#else + const FString URL = HttpRequest->GetURL(); +#endif UE_LOG(LogOnline, Verbose, TEXT("RegisterUser request complete. url=%s code=%d response=%s"), - *HttpRequest->GetURL(), HttpResponse->GetResponseCode(), *ResponseStr); + *URL, HttpResponse->GetResponseCode(), *ResponseStr); TSharedRef User = MakeShared(); if (User->Parse(PendingRegisterUser.AccessToken, ResponseStr)) diff --git a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/OnlineSharingFacebookCommon.cpp b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/OnlineSharingFacebookCommon.cpp index ac2a8d83f6d9..5bcfae712b03 100644 --- a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/OnlineSharingFacebookCommon.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/OnlineSharingFacebookCommon.cpp @@ -219,8 +219,13 @@ void FOnlineSharingFacebookCommon::Permissions_HttpComplete(FHttpRequestPtr Http ResponseStr = HttpResponse->GetContentAsString(); if (EHttpResponseCodes::IsOk(HttpResponse->GetResponseCode())) { +#if UE_BUILD_SHIPPING + static const FString URL = TEXT("[REDACTED]"); +#else + const FString URL = HttpRequest->GetURL(); +#endif UE_LOG(LogOnline, Verbose, TEXT("Permissions request complete. url=%s code=%d response=%s"), - *HttpRequest->GetURL(), HttpResponse->GetResponseCode(), *ResponseStr); + *URL, HttpResponse->GetResponseCode(), *ResponseStr); if (CurrentPermissions.RefreshPermissions(ResponseStr)) { diff --git a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/OnlineSubsystemFacebookCommon.cpp b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/OnlineSubsystemFacebookCommon.cpp index 6c16c66969ca..b3792df46c6f 100644 --- a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/OnlineSubsystemFacebookCommon.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/OnlineSubsystemFacebookCommon.cpp @@ -216,3 +216,7 @@ IOnlineTurnBasedPtr FOnlineSubsystemFacebookCommon::GetTurnBasedInterface() cons return nullptr; } +FText FOnlineSubsystemFacebookCommon::GetOnlineServiceName() const +{ + return NSLOCTEXT("OnlineSubsystemFacebook", "OnlineServiceName", "Facebook"); +} diff --git a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/OnlineSubsystemFacebookCommon.h b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/OnlineSubsystemFacebookCommon.h index 97383d5b745c..9b54044917ae 100644 --- a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/OnlineSubsystemFacebookCommon.h +++ b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/OnlineSubsystemFacebookCommon.h @@ -51,6 +51,7 @@ public: virtual bool Shutdown() override; virtual FString GetAppId() const override; virtual bool Exec(class UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) override; + virtual FText GetOnlineServiceName() const override; // FTickerBaseObject diff --git a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Windows/OnlineExternalUIInterfaceFacebook.cpp b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Windows/OnlineExternalUIInterfaceFacebook.cpp index 16f3a0764e40..f2a4ef8ba854 100644 --- a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Windows/OnlineExternalUIInterfaceFacebook.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Windows/OnlineExternalUIInterfaceFacebook.cpp @@ -3,6 +3,7 @@ #include "OnlineExternalUIInterfaceFacebook.h" #include "OnlineSubsystemFacebook.h" #include "OnlineIdentityFacebook.h" +#include "PlatformHttp.h" #include "OnlineError.h" #define FB_STATE_TOKEN TEXT("state") @@ -11,7 +12,7 @@ #define FB_ERRORDESC_TOKEN TEXT("error_description") #define LOGIN_ERROR_UNKNOWN TEXT("com.epicgames.login.unknown") - +#define LOGIN_ERROR_AUTH_FAILURE TEXT("com.epicgames.login.auth_failure") bool FOnlineExternalUIFacebook::ShowLoginUI(const int ControllerIndex, bool bShowOnlineOnly, bool bShowSkipButton, const FOnLoginUIClosedDelegate& Delegate) { @@ -45,6 +46,76 @@ bool FOnlineExternalUIFacebook::ShowLoginUI(const int ControllerIndex, bool bSho return bStarted; } +FLoginFlowResult FOnlineExternalUIFacebook::ParseRedirectResult(const FFacebookLoginURL& URLDetails, const FString& RedirectURL) +{ + FLoginFlowResult Result; + + TMap ParamsMap; + + FString ResponseStr = RedirectURL.Mid(URLDetails.LoginRedirectUrl.Len() + 1); + { + // Remove the "Facebook fragment" + // https://developers.facebook.com/blog/post/552/ + FString ParamsOnly; + if (!ResponseStr.Split(TEXT("#_=_"), &ParamsOnly, nullptr)) + { + ParamsOnly = ResponseStr; + } + + TArray Params; + ParamsOnly.ParseIntoArray(Params, TEXT("&")); + for (FString& Param : Params) + { + FString Key, Value; + if (Param.Split(TEXT("="), &Key, &Value)) + { + ParamsMap.Add(Key, Value); + } + } + } + + const FString* State = ParamsMap.Find(FB_STATE_TOKEN); + if (State) + { + if (URLDetails.State == *State) + { + const FString* AccessToken = ParamsMap.Find(FB_ACCESS_TOKEN); + if (AccessToken) + { + Result.Error.bSucceeded = true; + Result.Token = *AccessToken; + } + else + { + const FString* ErrorCode = ParamsMap.Find(FB_ERRORCODE_TOKEN); + if (ErrorCode) + { + Result.Error.ErrorRaw = ResponseStr; + + const FString* ErrorDesc = ParamsMap.Find(FB_ERRORDESC_TOKEN); + if (ErrorDesc) + { + Result.Error.ErrorMessage = FText::FromString(*ErrorDesc); + } + + Result.Error.ErrorCode = *ErrorCode; + Result.Error.NumericErrorCode = FPlatformString::Atoi(**ErrorCode); + } + else + { + // Set some default in case parsing fails + Result.Error.ErrorRaw = LOGIN_ERROR_UNKNOWN; + Result.Error.ErrorMessage = FText::FromString(LOGIN_ERROR_UNKNOWN); + Result.Error.ErrorCode = TEXT("-1"); + Result.Error.NumericErrorCode = -1; + } + } + } + } + + return Result; +} + FLoginFlowResult FOnlineExternalUIFacebook::OnLoginRedirectURL(const FString& RedirectURL) { FLoginFlowResult Result; @@ -56,68 +127,21 @@ FLoginFlowResult FOnlineExternalUIFacebook::OnLoginRedirectURL(const FString& Re if (URLDetails.IsValid()) { // Wait for the RedirectURI to appear - if (!RedirectURL.Contains(URLDetails.LoginUrl) && RedirectURL.StartsWith(URLDetails.LoginRedirectUrl)) + if (!RedirectURL.Contains(FPlatformHttp::UrlEncode(URLDetails.LoginUrl))) { - TMap ParamsMap; - - FString ResponseStr = RedirectURL.Mid(URLDetails.LoginRedirectUrl.Len() + 1); + if (RedirectURL.StartsWith(URLDetails.LoginRedirectUrl)) { - // Remove the "Facebook fragment" - // https://developers.facebook.com/blog/post/552/ - FString ParamsOnly; - if (!ResponseStr.Split(TEXT("#_=_"), &ParamsOnly, nullptr)) - { - ParamsOnly = ResponseStr; - } - - TArray Params; - ParamsOnly.ParseIntoArray(Params, TEXT("&")); - for (FString& Param : Params) - { - FString Key, Value; - if (Param.Split(TEXT("="), &Key, &Value)) - { - ParamsMap.Add(Key, Value); - } - } + Result = ParseRedirectResult(URLDetails, RedirectURL); } - - const FString* State = ParamsMap.Find(FB_STATE_TOKEN); - if (State) + else { - if (URLDetails.State == *State) + static const FString FacebookHelpURL = TEXT("https://www.facebook.com/login/help.php"); + if (RedirectURL.StartsWith(FacebookHelpURL)) { - const FString* AccessToken = ParamsMap.Find(FB_ACCESS_TOKEN); - if (AccessToken) - { - Result.Error.bSucceeded = true; - Result.Token = *AccessToken; - } - else - { - const FString* ErrorCode = ParamsMap.Find(FB_ERRORCODE_TOKEN); - if (ErrorCode) - { - Result.Error.ErrorRaw = ResponseStr; - - const FString* ErrorDesc = ParamsMap.Find(FB_ERRORDESC_TOKEN); - if (ErrorDesc) - { - Result.Error.ErrorMessage = FText::FromString(*ErrorDesc); - } - - Result.Error.ErrorCode = *ErrorCode; - Result.Error.NumericErrorCode = FPlatformString::Atoi(**ErrorCode); - } - else - { - // Set some default in case parsing fails - Result.Error.ErrorRaw = LOGIN_ERROR_UNKNOWN; - Result.Error.ErrorMessage = FText::FromString(LOGIN_ERROR_UNKNOWN); - Result.Error.ErrorCode = TEXT("-1"); - Result.Error.NumericErrorCode = -1; - } - } + Result.Error.ErrorRaw = LOGIN_ERROR_AUTH_FAILURE; + Result.Error.ErrorMessage = FText::FromString(LOGIN_ERROR_AUTH_FAILURE); + Result.Error.ErrorCode = TEXT("-2"); + Result.Error.NumericErrorCode = -2; } } } @@ -129,7 +153,7 @@ FLoginFlowResult FOnlineExternalUIFacebook::OnLoginRedirectURL(const FString& Re void FOnlineExternalUIFacebook::OnExternalLoginFlowComplete(const FLoginFlowResult& Result, int ControllerIndex, const FOnLoginUIClosedDelegate Delegate) { - UE_LOG(LogOnline, Log, TEXT("OnExternalLoginFlowComplete %s %s"), *Result.Token, Result.Error.ToLogString()); + UE_LOG(LogOnline, Log, TEXT("OnExternalLoginFlowComplete %s"), *Result.ToDebugString()); bool bStarted = false; if (Result.IsValid()) diff --git a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Windows/OnlineExternalUIInterfaceFacebook.h b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Windows/OnlineExternalUIInterfaceFacebook.h index d4143e3b31b7..a0eb6c60ebb2 100644 --- a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Windows/OnlineExternalUIInterfaceFacebook.h +++ b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/Private/Windows/OnlineExternalUIInterfaceFacebook.h @@ -8,6 +8,7 @@ class FOnlineSubsystemFacebook; class IHttpRequest; +struct FFacebookLoginURL; /** * Implementation for the Facebook external UIs @@ -22,8 +23,8 @@ PACKAGE_SCOPE: * Constructor * @param InSubsystem The owner of this external UI interface. */ - FOnlineExternalUIFacebook(FOnlineSubsystemFacebook* InSubsystem) : - FOnlineExternalUIFacebookCommon(InSubsystem) + FOnlineExternalUIFacebook(FOnlineSubsystemFacebook* InSubsystem) + : FOnlineExternalUIFacebookCommon(InSubsystem) { } @@ -41,6 +42,14 @@ public: private: + /** + * Parse a successful URL redirect from Facebook + * + * @param URLDetails URL config settings + * @param RedirectURL an URL knowns to start with the redirect URI + */ + FLoginFlowResult ParseRedirectResult(const FFacebookLoginURL& URLDetails, const FString& RedirectURL); + /** * Delegate fired when redirect URLs from the login flow are passed back for parsing * We are looking for the success or error completion state from Facebook to grab the access token or complete the flow diff --git a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/ThirdParty/Android/FacebookAndroid.tps b/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/ThirdParty/Android/FacebookAndroid.tps deleted file mode 100644 index 65bce227c5eb..000000000000 --- a/Engine/Plugins/Online/OnlineSubsystemFacebook/Source/ThirdParty/Android/FacebookAndroid.tps +++ /dev/null @@ -1,26 +0,0 @@ - - - Facebook SDK for Android - /Engine/Plugins/Online/OnlineSubsystemFacebook/Source/ThirdParty/Android - 2017-02-20T15:27:35.7267644-05:00 - Access to the Facebook SDK for Android - External provider authentication of users and access to social features provided by Facebook - - Android - - - UE4 - - lib - https://github.com/facebook/facebook-android-sdk/blob/master/LICENSE.txt - - Licensees - Git - P4 - - false - true - None - http://developers.facebook.com/policy/ - FacebookAndroid.tps - \ No newline at end of file diff --git a/Engine/Plugins/Online/OnlineSubsystemGoogle/OnlineSubsystemGoogle.uplugin b/Engine/Plugins/Online/OnlineSubsystemGoogle/OnlineSubsystemGoogle.uplugin index 059b69224d55..7a1251dd8d18 100644 --- a/Engine/Plugins/Online/OnlineSubsystemGoogle/OnlineSubsystemGoogle.uplugin +++ b/Engine/Plugins/Online/OnlineSubsystemGoogle/OnlineSubsystemGoogle.uplugin @@ -20,5 +20,12 @@ "Win64","Win32" ] } - ] + ], + "Plugins": [ + { + "Name": "OnlineSubsystem", + "Enabled": true + } + ] + } \ No newline at end of file diff --git a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/OnlineSubsystemGoogle.Build.cs b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/OnlineSubsystemGoogle.Build.cs index 393d28a6d3a6..04eb03470584 100644 --- a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/OnlineSubsystemGoogle.Build.cs +++ b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/OnlineSubsystemGoogle.Build.cs @@ -26,13 +26,10 @@ public class OnlineSubsystemGoogle : ModuleRules if (Target.Platform == UnrealTargetPlatform.IOS) { - //PrivateIncludePaths.Add("Private/IOS"); + PrivateIncludePaths.Add("Private/IOS"); } else if (Target.Platform == UnrealTargetPlatform.Android) { - /** - Definitions.Add("UE4_GOOGLE_VER="); - PrivateDependencyModuleNames.AddRange( new string[] { "Launch", @@ -43,7 +40,7 @@ public class OnlineSubsystemGoogle : ModuleRules AdditionalPropertiesForReceipt.Add(new ReceiptProperty("AndroidPlugin", Path.Combine(PluginPath, "OnlineSubsystemGoogle_UPL.xml"))); PrivateIncludePaths.Add("Private/Android"); - */ + } else if (Target.Platform == UnrealTargetPlatform.Win32 || Target.Platform == UnrealTargetPlatform.Win64) { diff --git a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/OnlineSubsystemGoogle_UPL.xml b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/OnlineSubsystemGoogle_UPL.xml new file mode 100644 index 000000000000..64441f5a6963 --- /dev/null +++ b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/OnlineSubsystemGoogle_UPL.xml @@ -0,0 +1,273 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -keep class epicgames.ue4.GoogleLogin.** { + public *; +} + + + + + + + + + + + + +// Google imports + + + + + + + + + + + // Begin Google gameActivityClassAdditions + private GoogleLogin googleLogin; + public GoogleLogin getGoogleLogin() { return googleLogin; } + + public int AndroidThunkJava_Google_Login(String[] ScopeFields) + { + Log.debug("[JAVA] - AndroidThunkJava_Google_Login begin"); + int resultCode = -1; + if (googleLogin != null) + { + resultCode = googleLogin.login(ScopeFields); + } + Log.debug("[JAVA] - AndroidThunkJava_Google_Login result: " + resultCode); + return resultCode; + } + + public int AndroidThunkJava_Google_Logout() + { + Log.debug("[JAVA] - AndroidThunkJava_Google_Logout begin"); + int resultCode = -1; + if (googleLogin != null) + { + resultCode = googleLogin.logout(); + } + Log.debug("[JAVA] - AndroidThunkJava_Google_Logout result: " + resultCode); + return resultCode; + } + + // End Google gameActivityClassAdditions + + + + + + + + + + + // Google gameActivityReadMetadataAdditions + + + + + + + + + + + // Begin Google onCreate + + + + + + + + + googleLogin = new GoogleLogin(this, Log); + if (!googleLogin.init(getPackageName(), BuildConfiguration, androidClientId, serverClientId, savedInstanceState)) + { + googleLogin = null; + Log.error("[JAVA] - Google SDK failed to initialize!"); + } + else + { + Log.debug("[JAVA] - Google SDK success!"); + } + // End Google onCreate + + + + + + + + + + + // Begin Google onDestroy + if (googleLogin != null) + { + googleLogin.onDestroy(); + } + // End Google onDestroy + + + + + + + + + + + // Begin Google onStart + if (googleLogin != null) + { + googleLogin.onStart(); + } + // End Google onStart + + + + + + + + + + + // Begin Google onStop + if (googleLogin != null) + { + googleLogin.onStop(); + } + // End Google onStop + + + + + + + + + + + // Begin Google onPause + // End Google onPause + + + + + + + + + + + // Begin Google onResume + // End Google onResume + + + + + + + + + + + // Begin Google onActivityResult + if (googleLogin != null) + { + googleLogin.onActivityResult(requestCode, resultCode, data); + Log.debug("[JAVA] - Google after activity result"); + } + // End Google onActivityResult + + + + + + + + + diff --git a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Android/OnlineExternalUIInterfaceGoogle.cpp b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Android/OnlineExternalUIInterfaceGoogle.cpp new file mode 100644 index 000000000000..364e129fb4eb --- /dev/null +++ b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Android/OnlineExternalUIInterfaceGoogle.cpp @@ -0,0 +1,15 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#include "OnlineExternalUIInterfaceGoogle.h" +#include "OnlineSubsystemGoogle.h" +#include "OnlineIdentityGoogle.h" +#include "OnlineError.h" + + +bool FOnlineExternalUIGoogle::ShowLoginUI(const int ControllerIndex, bool bShowOnlineOnly, bool bShowSkipButton, const FOnLoginUIClosedDelegate& Delegate) +{ + bool bStarted = false; + return bStarted; +} + + diff --git a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Android/OnlineExternalUIInterfaceGoogle.h b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Android/OnlineExternalUIInterfaceGoogle.h new file mode 100644 index 000000000000..162ea3a282e7 --- /dev/null +++ b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Android/OnlineExternalUIInterfaceGoogle.h @@ -0,0 +1,44 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "OnlineSubsystemGoogle.h" +#include "OnlineExternalUIGoogleCommon.h" +#include "OnlineSubsystemGooglePackage.h" + +class FOnlineSubsystemGoogle; + +/** + * Implementation for the Google external UIs + */ +class FOnlineExternalUIGoogle : public FOnlineExternalUIGoogleCommon +{ + +PACKAGE_SCOPE: + + /** + * Constructor + * @param InSubsystem The owner of this external UI interface. + */ + FOnlineExternalUIGoogle(FOnlineSubsystemGoogle* InSubsystem) : + FOnlineExternalUIGoogleCommon(InSubsystem) + { + } + +public: + + /** + * Destructor. + */ + virtual ~FOnlineExternalUIGoogle() + { + } + + // IOnlineExternalUI + virtual bool ShowLoginUI(const int ControllerIndex, bool bShowOnlineOnly, bool bShowSkipButton, const FOnLoginUIClosedDelegate& Delegate = FOnLoginUIClosedDelegate()) override; + + +}; + +typedef TSharedPtr FOnlineExternalUIGooglePtr; + diff --git a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Android/OnlineIdentityGoogle.cpp b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Android/OnlineIdentityGoogle.cpp new file mode 100644 index 000000000000..3ac9172e96ea --- /dev/null +++ b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Android/OnlineIdentityGoogle.cpp @@ -0,0 +1,385 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "OnlineIdentityGoogle.h" +#include "OnlineSubsystemGooglePrivate.h" + +#include "Android/AndroidJNI.h" +#include "Android/AndroidApplication.h" +#include "Misc/ConfigCacheIni.h" +#include "Async/TaskGraphInterfaces.h" + +FOnlineIdentityGoogle::FOnlineIdentityGoogle(FOnlineSubsystemGoogle* InSubsystem) + : FOnlineIdentityGoogleCommon(InSubsystem) + , bHasLoginOutstanding(false) +{ + UE_LOG(LogOnline, Display, TEXT("FOnlineIdentityGoogle::FOnlineIdentityGoogle()")); + + // Setup permission scope fields + GConfig->GetArray(TEXT("OnlineSubsystemGoogle.OnlineIdentityGoogle"), TEXT("ScopeFields"), ScopeFields, GEngineIni); + // always required login access fields + ScopeFields.AddUnique(TEXT(GOOGLE_PERM_PUBLIC_PROFILE)); + + FOnGoogleLoginCompleteDelegate LoginDelegate = FOnGoogleLoginCompleteDelegate::CreateRaw(this, &FOnlineIdentityGoogle::OnLoginComplete); + OnGoogleLoginCompleteHandle = AddOnGoogleLoginCompleteDelegate_Handle(LoginDelegate); + + FOnGoogleLogoutCompleteDelegate LogoutDelegate = FOnGoogleLogoutCompleteDelegate::CreateRaw(this, &FOnlineIdentityGoogle::OnLogoutComplete); + OnGoogleLogoutCompleteHandle = AddOnGoogleLogoutCompleteDelegate_Handle(LogoutDelegate); +} + +bool FOnlineIdentityGoogle::Login(int32 LocalUserNum, const FOnlineAccountCredentials& AccountCredentials) +{ + UE_LOG_ONLINE(Verbose, TEXT("FOnlineIdentityGoogle::Login")); + bool bTriggeredLogin = false; + bool bPendingOp = LoginCompletionDelegate.IsBound() || LogoutCompletionDelegate.IsBound(); + if (!bPendingOp) + { + ELoginStatus::Type LoginStatus = GetLoginStatus(LocalUserNum); + if (LoginStatus == ELoginStatus::NotLoggedIn) + { + LoginCompletionDelegate = FOnInternalLoginComplete::CreateLambda( + [this, LocalUserNum](EGoogleLoginResponse InResponseCode, const FString& InAccessToken) + { + UE_LOG_ONLINE(Verbose, TEXT("FOnInternalLoginComplete %s %s"), ToString(InResponseCode), *InAccessToken); + if (InResponseCode == EGoogleLoginResponse::RESPONSE_OK) + { + FString ErrorStr; + + TSharedPtr JsonJavaUserData; + TSharedRef< TJsonReader<> > JsonReader = TJsonReaderFactory<>::Create(InAccessToken); + + if (FJsonSerializer::Deserialize(JsonReader, JsonJavaUserData) && + JsonJavaUserData.IsValid()) + { + const TSharedPtr* AuthData = nullptr; + if (JsonJavaUserData->TryGetObjectField(TEXT("auth_data"), AuthData)) + { + const TSharedPtr* UserProfile = nullptr; + if (JsonJavaUserData->TryGetObjectField(TEXT("user_data"), UserProfile)) + { + FAuthTokenGoogle AuthToken; + if (AuthToken.Parse(*AuthData)) + { + TSharedRef User = MakeShared(); + if (User->Parse(AuthToken, *UserProfile)) + { + // update/add cached entry for user + UserAccounts.Add(User->GetUserId()->ToString(), User); + // keep track of user ids for local users + UserIds.Add(LocalUserNum, User->GetUserId()); + } + else + { + ErrorStr = FString::Printf(TEXT("Error parsing user profile. payload=%s"), *InAccessToken); + } + } + else + { + ErrorStr = FString::Printf(TEXT("Error parsing auth token. payload=%s"), *InAccessToken); + } + } + else + { + ErrorStr = FString::Printf(TEXT("user_data field missing. payload=%s"), *InAccessToken); + } + } + else + { + ErrorStr = FString::Printf(TEXT("auth_data field missing. payload=%s"), *InAccessToken); + } + } + else + { + ErrorStr = FString::Printf(TEXT("Failed to deserialize java data. payload=%s"), *InAccessToken); + } + + OnLoginAttemptComplete(LocalUserNum, ErrorStr); + } + else + { + FString ErrorStr; + if (InResponseCode == EGoogleLoginResponse::RESPONSE_CANCELED) + { + ErrorStr = GOOGLE_AUTH_CANCELED; + } + else + { + ErrorStr = FString::Printf(TEXT("Login failure %s"), ToString(InResponseCode)); + } + OnLoginAttemptComplete(LocalUserNum, ErrorStr); + } + }); + + extern bool AndroidThunkCpp_Google_Login(const TArray&); + bTriggeredLogin = AndroidThunkCpp_Google_Login(ScopeFields); + if (!ensure(bTriggeredLogin)) + { + // Only if JEnv is wrong + UE_LOG_ONLINE(Verbose, TEXT("FOnlineIdentityGoogle::Login AndroidThunkCpp_Google_Login failed to trigger")); + OnLoginComplete(EGoogleLoginResponse::RESPONSE_ERROR, TEXT("")); + } + } + else + { + TriggerOnLoginCompleteDelegates(LocalUserNum, true, *GetUniquePlayerId(LocalUserNum), TEXT("Already logged in")); + } + } + else + { + UE_LOG_ONLINE(Verbose, TEXT("FOnlineIdentityGoogle::Login Operation already in progress!")); + FString ErrorStr = FString::Printf(TEXT("Operation already in progress")); + TriggerOnLoginCompleteDelegates(LocalUserNum, false, GetEmptyUniqueId(), ErrorStr); + } + + return bTriggeredLogin; +} + +void FOnlineIdentityGoogle::OnLoginAttemptComplete(int32 LocalUserNum, const FString& ErrorStr) +{ + const FString ErrorStrCopy(ErrorStr); + + if (GetLoginStatus(LocalUserNum) == ELoginStatus::LoggedIn) + { + UE_LOG(LogOnline, Display, TEXT("Google login was successful.")); + TSharedPtr UserId = GetUniquePlayerId(LocalUserNum); + check(UserId.IsValid()); + + GoogleSubsystem->ExecuteNextTick([this, UserId, LocalUserNum, ErrorStrCopy]() + { + TriggerOnLoginCompleteDelegates(LocalUserNum, true, *UserId, ErrorStrCopy); + TriggerOnLoginStatusChangedDelegates(LocalUserNum, ELoginStatus::NotLoggedIn, ELoginStatus::LoggedIn, *UserId); + }); + } + else + { + LogoutCompletionDelegate = FOnInternalLogoutComplete::CreateLambda( + [this, LocalUserNum, ErrorStrCopy](EGoogleLoginResponse InResponseCode) + { + UE_LOG_ONLINE(Warning, TEXT("Google login failed: %s"), *ErrorStrCopy); + + TSharedPtr UserId = GetUniquePlayerId(LocalUserNum); + if (UserId.IsValid()) + { + // remove cached user account + UserAccounts.Remove(UserId->ToString()); + } + else + { + UserId = GetEmptyUniqueId().AsShared(); + } + // remove cached user id + UserIds.Remove(LocalUserNum); + + TriggerOnLoginCompleteDelegates(LocalUserNum, false, *UserId, ErrorStrCopy); + }); + + // Clean up anything left behind from cached access tokens + extern bool AndroidThunkCpp_Google_Logout(); + bool bTriggeredLogout = AndroidThunkCpp_Google_Logout(); + if (!ensure(bTriggeredLogout)) + { + // Only if JEnv is wrong + UE_LOG_ONLINE(Verbose, TEXT("FOnlineIdentityGoogle::OnLoginAttemptComplete AndroidThunkCpp_Google_Logout failed to trigger")); + OnLogoutComplete(EGoogleLoginResponse::RESPONSE_ERROR); + } + } +} + +bool FOnlineIdentityGoogle::Logout(int32 LocalUserNum) +{ + bool bTriggeredLogout = false; + bool bPendingOp = LoginCompletionDelegate.IsBound() || LogoutCompletionDelegate.IsBound(); + if (!bPendingOp) + { + ELoginStatus::Type LoginStatus = GetLoginStatus(LocalUserNum); + if (LoginStatus == ELoginStatus::LoggedIn) + { + LogoutCompletionDelegate = FOnInternalLogoutComplete::CreateLambda( + [this, LocalUserNum](EGoogleLoginResponse InResponseCode) + { + UE_LOG_ONLINE(Verbose, TEXT("FOnInternalLogoutComplete %s"), ToString(InResponseCode)); + TSharedPtr UserId = GetUniquePlayerId(LocalUserNum); + if (UserId.IsValid()) + { + // remove cached user account + UserAccounts.Remove(UserId->ToString()); + } + else + { + UserId = GetEmptyUniqueId().AsShared(); + } + // remove cached user id + UserIds.Remove(LocalUserNum); + + GoogleSubsystem->ExecuteNextTick([this, UserId, LocalUserNum]() + { + TriggerOnLogoutCompleteDelegates(LocalUserNum, true); + TriggerOnLoginStatusChangedDelegates(LocalUserNum, ELoginStatus::LoggedIn, ELoginStatus::NotLoggedIn, *UserId); + }); + }); + + extern bool AndroidThunkCpp_Google_Logout(); + bTriggeredLogout = AndroidThunkCpp_Google_Logout(); + if (!ensure(bTriggeredLogout)) + { + // Only if JEnv is wrong + UE_LOG_ONLINE(Verbose, TEXT("FOnlineIdentityGoogle::Logout AndroidThunkCpp_Google_Logout failed to trigger")); + OnLogoutComplete(EGoogleLoginResponse::RESPONSE_ERROR); + } + } + else + { + UE_LOG_ONLINE(Warning, TEXT("No logged in user found for LocalUserNum=%d."), LocalUserNum); + } + } + else + { + UE_LOG_ONLINE(Warning, TEXT("FOnlineIdentityGoogle::Logout - Operation already in progress")); + } + + if (!bTriggeredLogout) + { + UE_LOG_ONLINE(Verbose, TEXT("FOnlineIdentityGoogle::Logout didn't trigger logout")); + GoogleSubsystem->ExecuteNextTick([this, LocalUserNum]() + { + TriggerOnLogoutCompleteDelegates(LocalUserNum, false); + }); + } + + return bTriggeredLogout; +} + +void FOnlineIdentityGoogle::OnLoginComplete(EGoogleLoginResponse InResponseCode, const FString& InAccessToken) +{ + UE_LOG_ONLINE(Verbose, TEXT("OnLoginComplete %s %s"), ToString(InResponseCode), *InAccessToken); + ensure(LoginCompletionDelegate.IsBound()); + LoginCompletionDelegate.ExecuteIfBound(InResponseCode, InAccessToken); + LoginCompletionDelegate.Unbind(); +} + +void FOnlineIdentityGoogle::OnLogoutComplete(EGoogleLoginResponse InResponseCode) +{ + UE_LOG_ONLINE(Verbose, TEXT("OnLogoutComplete %s"), ToString(InResponseCode)); + ensure(LogoutCompletionDelegate.IsBound()); + LogoutCompletionDelegate.ExecuteIfBound(InResponseCode); + LogoutCompletionDelegate.Unbind(); +} + + +#define CHECK_JNI_METHOD(Id) checkf(Id != nullptr, TEXT("Failed to find " #Id)); + +bool AndroidThunkCpp_Google_Login(const TArray& InScopeFields) +{ + UE_LOG_ONLINE(Verbose, TEXT("AndroidThunkCpp_Google_Login")); + bool bSuccess = false; + if (JNIEnv* Env = FAndroidApplication::GetJavaEnv()) + { + const bool bIsOptional = false; + static jmethodID GoogleLoginMethod = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_Google_Login", "([Ljava/lang/String;)I", bIsOptional); + CHECK_JNI_METHOD(GoogleLoginMethod); + UE_LOG_ONLINE(Verbose, TEXT("GoogleLoginMethod 0x%08x"), GoogleLoginMethod); + + // Convert scope array into java fields + jobjectArray ScopeIDArray = (jobjectArray)Env->NewObjectArray(InScopeFields.Num(), FJavaWrapper::JavaStringClass, nullptr); + for (uint32 Param = 0; Param < InScopeFields.Num(); Param++) + { + jstring StringValue = Env->NewStringUTF(TCHAR_TO_UTF8(*InScopeFields[Param])); + Env->SetObjectArrayElement(ScopeIDArray, Param, StringValue); + Env->DeleteLocalRef(StringValue); + } + + int32 ReturnVal = FJavaWrapper::CallIntMethod(Env, FJavaWrapper::GameActivityThis, GoogleLoginMethod, ScopeIDArray); + + // clean up references + Env->DeleteLocalRef(ScopeIDArray); + bSuccess = true; + UE_LOG_ONLINE(Verbose, TEXT("AndroidThunkCpp_Google_Login retval=%d"), ReturnVal); + } + else + { + UE_LOG_ONLINE(Verbose, TEXT("AndroidThunkCpp_Google_Login JNI error")); + } + + return bSuccess; +} + +extern "C" void Java_com_epicgames_ue4_GoogleLogin_nativeLoginComplete(JNIEnv* jenv, jobject thiz, jsize responseCode, jstring javaData) +{ + EGoogleLoginResponse LoginResponse = (EGoogleLoginResponse)responseCode; + + const char* charsJavaData = jenv->GetStringUTFChars(javaData, 0); + FString JavaData = FString(UTF8_TO_TCHAR(charsJavaData)); + jenv->ReleaseStringUTFChars(javaData, charsJavaData); + + UE_LOG_ONLINE(Verbose, TEXT("nativeLoginComplete Response: %s Data: %s"), ToString(LoginResponse), *JavaData); + + DECLARE_CYCLE_STAT(TEXT("FSimpleDelegateGraphTask.ProcessGoogleLogin"), STAT_FSimpleDelegateGraphTask_ProcessGoogleLogin, STATGROUP_TaskGraphTasks); + FSimpleDelegateGraphTask::CreateAndDispatchWhenReady( + FSimpleDelegateGraphTask::FDelegate::CreateLambda([=]() + { + FPlatformMisc::LowLevelOutputDebugStringf(TEXT("Google login completed %s"), ToString(LoginResponse)); + if (IOnlineSubsystem* const OnlineSub = IOnlineSubsystem::Get(GOOGLE_SUBSYSTEM)) + { + FOnlineIdentityGooglePtr IdentityGoogleInt = StaticCastSharedPtr(OnlineSub->GetIdentityInterface()); + if (IdentityGoogleInt.IsValid()) + { + IdentityGoogleInt->TriggerOnGoogleLoginCompleteDelegates(LoginResponse, JavaData); + } + } + }), + GET_STATID(STAT_FSimpleDelegateGraphTask_ProcessGoogleLogin), + nullptr, + ENamedThreads::GameThread + ); +} + +bool AndroidThunkCpp_Google_Logout() +{ + UE_LOG_ONLINE(Verbose, TEXT("AndroidThunkCpp_Google_Logout")); + bool bSuccess = false; + if (JNIEnv* Env = FAndroidApplication::GetJavaEnv()) + { + const bool bIsOptional = false; + static jmethodID GoogleLogoutMethod = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_Google_Logout", "()I", bIsOptional); + CHECK_JNI_METHOD(GoogleLogoutMethod); + UE_LOG_ONLINE(Verbose, TEXT("GoogleLogoutMethod 0x%08x"), GoogleLogoutMethod); + int32 ReturnVal = FJavaWrapper::CallIntMethod(Env, FJavaWrapper::GameActivityThis, GoogleLogoutMethod); + + bSuccess = true; + UE_LOG_ONLINE(Verbose, TEXT("AndroidThunkCpp_Google_Logout retval=%d"), ReturnVal); + } + else + { + UE_LOG_ONLINE(Verbose, TEXT("AndroidThunkCpp_Google_Logout JNI error")); + } + return bSuccess; +} + +extern "C" void Java_com_epicgames_ue4_GoogleLogin_nativeLogoutComplete(JNIEnv* jenv, jobject thiz, jsize responseCode) +{ + EGoogleLoginResponse LogoutResponse = (EGoogleLoginResponse)responseCode; + UE_LOG_ONLINE(Verbose, TEXT("nativeLogoutComplete %s"), ToString(LogoutResponse)); + + DECLARE_CYCLE_STAT(TEXT("FSimpleDelegateGraphTask.ProcessGoogleLogout"), STAT_FSimpleDelegateGraphTask_ProcessGoogleLogout, STATGROUP_TaskGraphTasks); + FSimpleDelegateGraphTask::CreateAndDispatchWhenReady( + FSimpleDelegateGraphTask::FDelegate::CreateLambda([=]() + { + FPlatformMisc::LowLevelOutputDebugStringf(TEXT("Google logout completed %s"), ToString(LogoutResponse)); + if (IOnlineSubsystem* const OnlineSub = IOnlineSubsystem::Get(GOOGLE_SUBSYSTEM)) + { + FOnlineIdentityGooglePtr IdentityGoogleInt = StaticCastSharedPtr(OnlineSub->GetIdentityInterface()); + if (IdentityGoogleInt.IsValid()) + { + IdentityGoogleInt->TriggerOnGoogleLogoutCompleteDelegates(LogoutResponse); + } + } + }), + GET_STATID(STAT_FSimpleDelegateGraphTask_ProcessGoogleLogout), + nullptr, + ENamedThreads::GameThread + ); +} + + + + + diff --git a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Android/OnlineIdentityGoogle.h b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Android/OnlineIdentityGoogle.h new file mode 100644 index 000000000000..5afe4d1e4488 --- /dev/null +++ b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Android/OnlineIdentityGoogle.h @@ -0,0 +1,141 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "OnlineIdentityGoogleCommon.h" +#include "OnlineSubsystemGoogleTypes.h" +#include "OnlineAccountGoogleCommon.h" +#include "OnlineSubsystemGooglePackage.h" + +class FOnlineSubsystemGoogle; + +#define GOOGLE_AUTH_CANCELED TEXT("com.epicgames.login.canceled"); + +/** Tied to GoogleLogin.java */ +enum class EGoogleLoginResponse : uint8 +{ + /** Google Sign In SDK ok response */ + RESPONSE_OK = 0, + /** Google Sign In SDK user cancellation */ + RESPONSE_CANCELED = 1, + /** Google Sign In SDK error */ + RESPONSE_ERROR = 2, +}; + +inline const TCHAR* ToString(EGoogleLoginResponse Response) +{ + switch (Response) + { + case EGoogleLoginResponse::RESPONSE_OK: + return TEXT("RESPONSE_OK"); + case EGoogleLoginResponse::RESPONSE_CANCELED: + return TEXT("RESPONSE_CANCELED"); + case EGoogleLoginResponse::RESPONSE_ERROR: + return TEXT("RESPONSE_ERROR"); + } + + return TEXT(""); +} + +/** + * Delegate fired when the Google Android SDK has completed a login request + * + * @param InResponseCode response from the Google SDK + * @param InAccessToken access token if the response was RESPONSE_OK + */ +DECLARE_MULTICAST_DELEGATE_TwoParams(FOnGoogleLoginComplete, EGoogleLoginResponse /*InResponseCode*/, const FString& /*InAccessToken*/); +typedef FOnGoogleLoginComplete::FDelegate FOnGoogleLoginCompleteDelegate; + +/** + * Delegate fired when the Google Android SDK has completed a logout request + * + * @param InResponseCode response from the Google SDK + */ +DECLARE_MULTICAST_DELEGATE_OneParam(FOnGoogleLogoutComplete, EGoogleLoginResponse /*InResponseCode*/); +typedef FOnGoogleLogoutComplete::FDelegate FOnGoogleLogoutCompleteDelegate; + +/** Android implementation of a Google user account */ +class FUserOnlineAccountGoogle : public FUserOnlineAccountGoogleCommon +{ +public: + + explicit FUserOnlineAccountGoogle(const FString& InUserId = FString(), const FAuthTokenGoogle& InAuthToken = FAuthTokenGoogle()) + : FUserOnlineAccountGoogleCommon(InUserId, InAuthToken) + { + } + + virtual ~FUserOnlineAccountGoogle() + { + } +}; + +/** + * Google service implementation of the online identity interface + */ +class FOnlineIdentityGoogle : + public FOnlineIdentityGoogleCommon +{ + /** Whether we have a registration in flight or not */ + bool bHasLoginOutstanding; + +public: + // IOnlineIdentity + + virtual bool Login(int32 LocalUserNum, const FOnlineAccountCredentials& AccountCredentials) override; + virtual bool Logout(int32 LocalUserNum) override; + + // FOnlineIdentityGoogle + + FOnlineIdentityGoogle(FOnlineSubsystemGoogle* InSubsystem); + + /** + * Destructor + */ + virtual ~FOnlineIdentityGoogle() + { + } + +PACKAGE_SCOPE: + + /** + * Delegate fired internally when the Java Google SDK has completed, notifying any OSS listeners + * Not meant for external use + * + * @param InResponseCode response from the Google SDK + * @param InAccessToken access token from the Google SDK if login was successful + */ + DEFINE_ONLINE_DELEGATE_TWO_PARAM(OnGoogleLoginComplete, EGoogleLoginResponse /*InResponseCode*/, const FString& /*InAccessToken*/); + + /** + * Delegate fired internally when the Java Google SDK has completed, notifying any OSS listeners + * Not meant for external use + * + * @param InResponseCode response from the Google SDK + */ + DEFINE_ONLINE_DELEGATE_ONE_PARAM(OnGoogleLogoutComplete, EGoogleLoginResponse /*InResponseCode*/); + + /** Last function called for any single login attempt */ + void OnLoginAttemptComplete(int32 LocalUserNum, const FString& ErrorStr); + + /** Generic handler for the Java SDK login callback */ + void OnLoginComplete(EGoogleLoginResponse InResponseCode, const FString& InAccessToken); + /** Generic handler for the Java SDK logout callback */ + void OnLogoutComplete(EGoogleLoginResponse InResponseCode); + +private: + + /** Config based list of permission scopes to use when logging in */ + TArray ScopeFields; + + FDelegateHandle OnGoogleLoginCompleteHandle; + FDelegateHandle OnGoogleLogoutCompleteHandle; + + /** Delegate holder for all internal related login callbacks */ + DECLARE_DELEGATE_TwoParams(FOnInternalLoginComplete, EGoogleLoginResponse /*InLoginResponse*/, const FString& /*AccessToken*/); + FOnInternalLoginComplete LoginCompletionDelegate; + /** Delegate holder for all internal related logout callbacks */ + DECLARE_DELEGATE_OneParam(FOnInternalLogoutComplete, EGoogleLoginResponse /*InLoginResponse*/); + FOnInternalLogoutComplete LogoutCompletionDelegate; +}; + +typedef TSharedPtr FOnlineIdentityGooglePtr; \ No newline at end of file diff --git a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Android/OnlineSubsystemGoogle.cpp b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Android/OnlineSubsystemGoogle.cpp index 272e4a3fdb20..883fc4fba892 100644 --- a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Android/OnlineSubsystemGoogle.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Android/OnlineSubsystemGoogle.cpp @@ -2,8 +2,10 @@ #include "OnlineSubsystemGoogle.h" #include "OnlineSubsystemGooglePrivate.h" -//#include "OnlineIdentityGoogle.h" -//#include "OnlineExternalUIInterfaceGoogle.h" +#include "OnlineIdentityGoogle.h" +#include "OnlineExternalUIInterfaceGoogle.h" + +#include "Misc/ConfigCacheIni.h" FOnlineSubsystemGoogle::FOnlineSubsystemGoogle() { @@ -20,10 +22,11 @@ FOnlineSubsystemGoogle::~FOnlineSubsystemGoogle() bool FOnlineSubsystemGoogle::Init() { + UE_LOG(LogOnline, Display, TEXT("FOnlineSubsystemGoogle::Init()")); if (FOnlineSubsystemGoogleCommon::Init()) { - //GoogleIdentity = MakeShareable(new FOnlineIdentityGoogle(this)); - //GoogleExternalUI = MakeShareable(new FOnlineExternalUIGoogle(this)); + GoogleIdentity = MakeShareable(new FOnlineIdentityGoogle(this)); + GoogleExternalUI = MakeShareable(new FOnlineExternalUIGoogle(this)); return true; } diff --git a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/IOS/OnlineIdentityGoogle.cpp b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/IOS/OnlineIdentityGoogle.cpp new file mode 100644 index 000000000000..e02323049c4b --- /dev/null +++ b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/IOS/OnlineIdentityGoogle.cpp @@ -0,0 +1,22 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "OnlineIdentityGoogle.h" +#include "OnlineSubsystemGooglePrivate.h" + +FOnlineIdentityGoogle::FOnlineIdentityGoogle(FOnlineSubsystemGoogle* InSubsystem) + : FOnlineIdentityGoogleCommon(InSubsystem) +{ +} + +bool FOnlineIdentityGoogle::Login(int32 LocalUserNum, const FOnlineAccountCredentials& AccountCredentials) +{ + bool bTriggeredLogin = false; + return bTriggeredLogin; +} + +bool FOnlineIdentityGoogle::Logout(int32 LocalUserNum) +{ + bool bTriggeredLogout = false; + return bTriggeredLogout; +} + diff --git a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/IOS/OnlineIdentityGoogle.h b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/IOS/OnlineIdentityGoogle.h new file mode 100644 index 000000000000..e98f784cbeba --- /dev/null +++ b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/IOS/OnlineIdentityGoogle.h @@ -0,0 +1,52 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "OnlineIdentityGoogleCommon.h" +#include "OnlineSubsystemGoogleTypes.h" +#include "OnlineAccountGoogleCommon.h" +#include "OnlineSubsystemGooglePackage.h" + +class FOnlineSubsystemGoogle; + +/** iOS implementation of a Google user account */ +class FUserOnlineAccountGoogle : public FUserOnlineAccountGoogleCommon +{ +public: + + explicit FUserOnlineAccountGoogle(const FString& InUserId = FString(), const FAuthTokenGoogle& InAuthToken = FAuthTokenGoogle()) + : FUserOnlineAccountGoogleCommon(InUserId, InAuthToken) + { + } + + virtual ~FUserOnlineAccountGoogle() + { + } +}; + +/** + * Google service implementation of the online identity interface + */ +class FOnlineIdentityGoogle : + public FOnlineIdentityGoogleCommon +{ + +public: + // IOnlineIdentity + + virtual bool Login(int32 LocalUserNum, const FOnlineAccountCredentials& AccountCredentials) override; + virtual bool Logout(int32 LocalUserNum) override; + + // FOnlineIdentityGoogle + + FOnlineIdentityGoogle(FOnlineSubsystemGoogle* InSubsystem); + + /** + * Destructor + */ + virtual ~FOnlineIdentityGoogle() + { + } +}; + +typedef TSharedPtr FOnlineIdentityGooglePtr; \ No newline at end of file diff --git a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/OnlineAccountGoogleCommon.cpp b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/OnlineAccountGoogleCommon.cpp index cbe97d9d221f..01faeea219fc 100644 --- a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/OnlineAccountGoogleCommon.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/OnlineAccountGoogleCommon.cpp @@ -16,28 +16,7 @@ bool FUserOnlineAccountGoogleCommon::Parse(const FAuthTokenGoogle& InAuthToken, if (FJsonSerializer::Deserialize(JsonReader, JsonUser) && JsonUser.IsValid()) { - if (FromJson(JsonUser)) - { - if (!UserId.IsEmpty()) - { - UserIdPtr = MakeShared(UserId); - - AddUserAttributes(JsonUser); - - // update the access token - AuthToken = InAuthToken; - - bResult = true; - } - else - { - UE_LOG_ONLINE(Warning, TEXT("FUserOnlineAccountGoogleCommon: Missing user id. payload=%s"), *InJsonStr); - } - } - else - { - UE_LOG_ONLINE(Warning, TEXT("FUserOnlineAccountGoogleCommon: Invalid response payload=%s"), *InJsonStr); - } + bResult = Parse(InAuthToken, JsonUser); } else { @@ -57,6 +36,49 @@ bool FUserOnlineAccountGoogleCommon::Parse(const FAuthTokenGoogle& InAuthToken, return bResult; } +bool FUserOnlineAccountGoogleCommon::Parse(const FAuthTokenGoogle& InAuthToken, TSharedPtr InJsonObject) +{ + bool bResult = false; + if (InAuthToken.IsValid()) + { + if (InJsonObject.IsValid()) + { + if (FromJson(InJsonObject)) + { + if (!UserId.IsEmpty()) + { + UserIdPtr = MakeShared(UserId); + + AddUserAttributes(InJsonObject); + + // update the access token + AuthToken = InAuthToken; + + bResult = true; + } + else + { + UE_LOG_ONLINE(Warning, TEXT("FUserOnlineAccountGoogleCommon: Missing user id in json object")); + } + } + else + { + UE_LOG_ONLINE(Warning, TEXT("FUserOnlineAccountGoogleCommon: Invalid json object")); + } + } + else + { + UE_LOG_ONLINE(Warning, TEXT("FUserOnlineAccountGoogleCommon: Invalid json object pointer")); + } + } + else + { + UE_LOG_ONLINE(Warning, TEXT("FUserOnlineAccountGoogleCommon: Invalid auth token")); + } + + return bResult; +} + TSharedRef FUserOnlineAccountGoogleCommon::GetUserId() const { return UserIdPtr; diff --git a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/OnlineAccountGoogleCommon.h b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/OnlineAccountGoogleCommon.h index 25f2fa78428c..1ad8624dc99b 100644 --- a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/OnlineAccountGoogleCommon.h +++ b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/OnlineAccountGoogleCommon.h @@ -50,6 +50,14 @@ public: */ bool Parse(const FAuthTokenGoogle& InAuthToken, const FString& InJsonStr); + /** + * Parse Json profile request data into the user account + * + * @param InAuthToken previously associated auth token with this Json response + * @param InJsonObject a json payload from a /me request + */ + bool Parse(const FAuthTokenGoogle& InAuthToken, TSharedPtr InJsonObject); + protected: /** diff --git a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/OnlineIdentityGoogleCommon.cpp b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/OnlineIdentityGoogleCommon.cpp index 46d237236634..8a965f60138a 100644 --- a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/OnlineIdentityGoogleCommon.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/OnlineIdentityGoogleCommon.cpp @@ -4,6 +4,7 @@ #include "OnlineIdentityGoogle.h" #include "OnlineSubsystemGooglePrivate.h" #include "OnlineSubsystemGoogleTypes.h" +#include "OnlineSubsystemGoogle.h" #include "HttpModule.h" #include "Interfaces/IHttpResponse.h" #include "Misc/ConfigCacheIni.h" @@ -48,11 +49,12 @@ bool FJsonWebTokenGoogle::Parse(const FString& InJWTStr) //Verify that the value of iss in the ID token is Google issued static const FString Issuer1 = TEXT("https://accounts.google.com"); static const FString Issuer2 = TEXT("accounts.google.com"); - if ((Payload.ISS == Issuer1) || (Payload.ISS == Issuer2)) { // Verify that the value of aud in the ID token is equal to your apps client ID. - if (Payload.Aud == IOnlineSubsystem::Get(GOOGLE_SUBSYSTEM)->GetAppId()) + FOnlineSubsystemGoogle* GoogleSubsystem = static_cast(IOnlineSubsystem::Get(GOOGLE_SUBSYSTEM)); + if (Payload.Aud == GoogleSubsystem->GetAppId() || + Payload.Aud == GoogleSubsystem->GetServerClientId()) { //https://www.codescience.com/blog/2016/oauth2-server-to-server-authentication-from-salesforce-to-google-apis // exp Required The expiration time of the assertion, specified as seconds since 00:00:00 UTC, January 1, 1970. This value has a maximum of 1 hour after the issued time. @@ -75,16 +77,22 @@ bool FJsonWebTokenGoogle::Parse(const FString& InJWTStr) else { UE_LOG(LogOnline, Warning, TEXT("Google auth: Expiry Time inconsistency")); + UE_LOG(LogOnline, Warning, TEXT(" Expiry: %s"), *ExpiryTime.ToString()); + UE_LOG(LogOnline, Warning, TEXT(" Issue: %s"), *IssueTime.ToString()); } } else { UE_LOG(LogOnline, Warning, TEXT("Google auth: Audience inconsistency")); + UE_LOG(LogOnline, Warning, TEXT(" Payload: %s"), *Payload.Aud); + UE_LOG(LogOnline, Warning, TEXT(" ClientId: %s"), *GoogleSubsystem->GetAppId()); + UE_LOG(LogOnline, Warning, TEXT(" ServerClientId: %s"), *GoogleSubsystem->GetServerClientId()); } } else { UE_LOG(LogOnline, Warning, TEXT("Google auth: Issuer inconsistency")); + UE_LOG(LogOnline, Warning, TEXT(" ISS: %s"), *Payload.ISS); } } else @@ -163,24 +171,40 @@ bool FAuthTokenGoogle::Parse(const FString& InJsonStr) if (FJsonSerializer::Deserialize(JsonReader, JsonAuth) && JsonAuth.IsValid()) { - if (FromJson(JsonAuth)) + bSuccess = Parse(JsonAuth); + } + } + else + { + UE_LOG_ONLINE(Warning, TEXT("FAuthTokenGoogle: Empty Json string")); + } + + return bSuccess; +} + +bool FAuthTokenGoogle::Parse(TSharedPtr InJsonObject) +{ + bool bSuccess = false; + + if (InJsonObject.IsValid()) + { + if (FromJson(InJsonObject)) + { + if (!AccessToken.IsEmpty()) { - if (!AccessToken.IsEmpty()) + if (IdTokenJWT.Parse(IdToken)) { - if (IdTokenJWT.Parse(IdToken)) - { - AddAuthAttributes(JsonAuth); - AuthType = EGoogleAuthTokenType::AccessToken; - ExpiresInUTC = FDateTime::UtcNow() + FTimespan(ExpiresIn * ETimespan::TicksPerSecond); - bSuccess = true; - } + AddAuthAttributes(InJsonObject); + AuthType = EGoogleAuthTokenType::AccessToken; + ExpiresInUTC = FDateTime::UtcNow() + FTimespan(ExpiresIn * ETimespan::TicksPerSecond); + bSuccess = true; } } } } else { - UE_LOG_ONLINE(Warning, TEXT("FAuthTokenGoogle: Empty Json string")); + UE_LOG_ONLINE(Warning, TEXT("FAuthTokenGoogle: Invalid Json pointer")); } return bSuccess; @@ -362,8 +386,15 @@ void FOnlineIdentityGoogleCommon::MeUser_HttpRequestComplete(FHttpRequestPtr Htt } else { - //FErrorGoogle Error; - //Error.FromJson(ResponseStr); + FErrorGoogle Error; + if (Error.FromJson(ResponseStr) && !Error.Error_Description.IsEmpty()) + { + ErrorStr = Error.Error_Description; + } + else + { + ErrorStr = FString::Printf(TEXT("Failed to parse Google error %s"), *ResponseStr); + } } } else diff --git a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/OnlineIdentityGoogleCommon.h b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/OnlineIdentityGoogleCommon.h index ba5070845b13..61cf3949ce3c 100644 --- a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/OnlineIdentityGoogleCommon.h +++ b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/OnlineIdentityGoogleCommon.h @@ -8,6 +8,14 @@ #include "IHttpRequest.h" #include "OnlineSubsystemGooglePackage.h" +// Google scope fields +// email profile +// https://www.googleapis.com/auth/plus.login +// https://www.googleapis.com/auth/plus.me +// https://www.googleapis.com/auth/userinfo.email +// https://www.googleapis.com/auth/userinfo.profile +#define GOOGLE_PERM_PUBLIC_PROFILE "https://www.googleapis.com/auth/plus.login" + class FOnlineSubsystemGoogle; class FUserOnlineAccountGoogleCommon; diff --git a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/OnlineSubsystemGoogleCommon.cpp b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/OnlineSubsystemGoogleCommon.cpp index 792739e7c93c..9465af1ef322 100644 --- a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/OnlineSubsystemGoogleCommon.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/OnlineSubsystemGoogleCommon.cpp @@ -15,6 +15,11 @@ FOnlineSubsystemGoogleCommon::FOnlineSubsystemGoogleCommon() { UE_LOG(LogOnline, Warning, TEXT("Missing ClientId= in [OnlineSubsystemGoogle] of DefaultEngine.ini")); } + + if (!GConfig->GetString(TEXT("OnlineSubsystemGoogle"), TEXT("ServerClientId"), ServerClientId, GEngineIni)) + { + UE_LOG(LogOnline, Warning, TEXT("Missing ServerClientId= in [OnlineSubsystemGoogle] of DefaultEngine.ini")); + } } FOnlineSubsystemGoogleCommon::FOnlineSubsystemGoogleCommon(FName InInstanceName) @@ -24,6 +29,11 @@ FOnlineSubsystemGoogleCommon::FOnlineSubsystemGoogleCommon(FName InInstanceName) { UE_LOG(LogOnline, Warning, TEXT("Missing ClientId= in [OnlineSubsystemGoogle] of DefaultEngine.ini")); } + + if (!GConfig->GetString(TEXT("OnlineSubsystemGoogle"), TEXT("ServerClientId"), ServerClientId, GEngineIni)) + { + UE_LOG(LogOnline, Warning, TEXT("Missing ServerClientId= in [OnlineSubsystemGoogle] of DefaultEngine.ini")); + } } FOnlineSubsystemGoogleCommon::~FOnlineSubsystemGoogleCommon() @@ -202,3 +212,8 @@ IOnlineTurnBasedPtr FOnlineSubsystemGoogleCommon::GetTurnBasedInterface() const return nullptr; } +FText FOnlineSubsystemGoogleCommon::GetOnlineServiceName() const +{ + return NSLOCTEXT("OnlineSubsystemGoogleCommon", "OnlineServiceName", "Google"); +} + diff --git a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/OnlineSubsystemGoogleCommon.h b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/OnlineSubsystemGoogleCommon.h index 13ba4893887c..d42a19027b63 100644 --- a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/OnlineSubsystemGoogleCommon.h +++ b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/OnlineSubsystemGoogleCommon.h @@ -44,6 +44,7 @@ public: virtual IOnlinePresencePtr GetPresenceInterface() const override; virtual IOnlineChatPtr GetChatInterface() const override; virtual IOnlineTurnBasedPtr GetTurnBasedInterface() const override; + virtual FText GetOnlineServiceName() const override; virtual bool Init() override; virtual bool Shutdown() override; virtual FString GetAppId() const override; @@ -72,11 +73,17 @@ PACKAGE_SCOPE: FOnlineSubsystemGoogleCommon(); FOnlineSubsystemGoogleCommon(FName InInstanceName); + /** @return the backend server client id */ + FString GetServerClientId() const { return ServerClientId; } + protected: /** The client id given to us by Google Dashboard */ FString ClientId; + /** Server client id that this client will be engaging with */ + FString ServerClientId; + /** Google implementation of identity interface */ FOnlineIdentityGoogleCommonPtr GoogleIdentity; diff --git a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/OnlineSubsystemGoogleTypes.h b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/OnlineSubsystemGoogleTypes.h index d796d84cf73d..41d4aeed7fc0 100644 --- a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/OnlineSubsystemGoogleTypes.h +++ b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/OnlineSubsystemGoogleTypes.h @@ -132,8 +132,8 @@ public: explicit FAuthTokenGoogle(const FString& InRefreshToken, EGoogleRefreshToken) : AuthType(EGoogleAuthTokenType::RefreshToken) - , RefreshToken(InRefreshToken) , ExpiresIn(0) + , RefreshToken(InRefreshToken) , ExpiresInUTC(0) { } @@ -177,6 +177,15 @@ public: */ bool Parse(const FString& InJsonStr); + /** + * Parse a Google json auth response into an access/refresh token + * + * @param InJsonObject json object containing the token information + * + * @return true if parsing was successful, false otherwise + */ + bool Parse(TSharedPtr InJsonObject); + /** * Parse a Google json auth refresh response into an access/refresh token * @@ -339,7 +348,16 @@ public: FErrorGoogle() { } + + /** Error type */ + FString Error; + /** Description of error */ + FString Error_Description; + + FString ToDebugString() const { return FString::Printf(TEXT("%s [Desc:%s]"), *Error, *Error_Description); } BEGIN_ONLINE_JSON_SERIALIZER + ONLINE_JSON_SERIALIZE("error", Error); + ONLINE_JSON_SERIALIZE("error_description", Error_Description); END_ONLINE_JSON_SERIALIZER }; diff --git a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Windows/OnlineExternalUIInterfaceGoogle.cpp b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Windows/OnlineExternalUIInterfaceGoogle.cpp index e02cce30f1ec..ab9515da8f7f 100644 --- a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Windows/OnlineExternalUIInterfaceGoogle.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Windows/OnlineExternalUIInterfaceGoogle.cpp @@ -5,10 +5,6 @@ #include "OnlineIdentityGoogle.h" #include "OnlineError.h" -#include "SocketSubsystem.h" -#include "IPAddress.h" -#include "Sockets.h" - #define GOOGLE_STATE_TOKEN TEXT("state") #define GOOGLE_ACCESS_TOKEN TEXT("code") #define GOOGLE_ERRORCODE_TOKEN TEXT("error") @@ -59,7 +55,7 @@ FLoginFlowResult FOnlineExternalUIGoogle::OnLoginRedirectURL(const FString& Redi if (URLDetails.IsValid()) { // Wait for the RedirectURI to appear - if (!RedirectURL.Contains(URLDetails.LoginUrl) && RedirectURL.StartsWith(URLDetails.LoginRedirectUrl)) + if (!RedirectURL.Contains(FPlatformHttp::UrlEncode(URLDetails.LoginUrl)) && RedirectURL.StartsWith(URLDetails.LoginRedirectUrl)) { TMap ParamsMap; @@ -142,7 +138,7 @@ FLoginFlowResult FOnlineExternalUIGoogle::OnLoginRedirectURL(const FString& Redi void FOnlineExternalUIGoogle::OnExternalLoginFlowComplete(const FLoginFlowResult& Result, int ControllerIndex, const FOnLoginUIClosedDelegate Delegate) { - UE_LOG(LogOnline, Log, TEXT("OnExternalLoginFlowComplete %s %s"), *Result.Token, Result.Error.ToLogString()); + UE_LOG(LogOnline, Log, TEXT("OnExternalLoginFlowComplete %s"), *Result.ToDebugString()); bool bStarted = false; if (Result.IsValid()) diff --git a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Windows/OnlineExternalUIInterfaceGoogle.h b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Windows/OnlineExternalUIInterfaceGoogle.h index dcabba54a5ad..52342eacf23a 100644 --- a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Windows/OnlineExternalUIInterfaceGoogle.h +++ b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Windows/OnlineExternalUIInterfaceGoogle.h @@ -7,8 +7,6 @@ #include "OnlineSubsystemGooglePackage.h" class FOnlineSubsystemGoogle; -class IHttpRequest; -class FSocket; /** * Implementation for the Google external UIs diff --git a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Windows/OnlineIdentityGoogle.cpp b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Windows/OnlineIdentityGoogle.cpp index 4a5977197a0b..97fe452ead08 100644 --- a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Windows/OnlineIdentityGoogle.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/Private/Windows/OnlineIdentityGoogle.cpp @@ -4,13 +4,6 @@ #include "OnlineSubsystemGooglePrivate.h" #include "OnlineExternalUIInterfaceGoogle.h" #include "Misc/ConfigCacheIni.h" -// Google scope fields -// email profile -// https://www.googleapis.com/auth/plus.login -// https://www.googleapis.com/auth/plus.me -// https://www.googleapis.com/auth/userinfo.email -// https://www.googleapis.com/auth/userinfo.profile -#define GOOGLE_PERM_PUBLIC_PROFILE "https://www.googleapis.com/auth/plus.login" FOnlineIdentityGoogle::FOnlineIdentityGoogle(FOnlineSubsystemGoogle* InSubsystem) : FOnlineIdentityGoogleCommon(InSubsystem) @@ -285,8 +278,15 @@ void FOnlineIdentityGoogle::ExchangeRequest_HttpRequestComplete(FHttpRequestPtr } else { - //FErrorGoogle Error; - //Error.FromJson(ResponseStr); + FErrorGoogle Error; + if (Error.FromJson(ResponseStr) && !Error.Error_Description.IsEmpty()) + { + ErrorStr = Error.Error_Description; + } + else + { + ErrorStr = FString::Printf(TEXT("Failed to parse Google error %s"), *ResponseStr); + } } } else @@ -380,8 +380,15 @@ void FOnlineIdentityGoogle::RefreshAuthRequest_HttpRequestComplete(FHttpRequestP } else { - //FErrorGoogle Error; - //Error.FromJson(ResponseStr); + FErrorGoogle Error; + if (Error.FromJson(ResponseStr) && !Error.Error_Description.IsEmpty()) + { + ErrorStr = Error.Error_Description; + } + else + { + ErrorStr = FString::Printf(TEXT("Failed to parse Google error %s"), *ResponseStr); + } } } else diff --git a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/ThirdParty/Android/GoogleSignInAndroid.tps b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/ThirdParty/Android/GoogleSignInAndroid.tps new file mode 100644 index 000000000000..81539ea93ab7 --- /dev/null +++ b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/ThirdParty/Android/GoogleSignInAndroid.tps @@ -0,0 +1,26 @@ + + + Google Sign-In for Android + Engine/Source/ThirdParty/Android/extras/google/m2repository/com/google/android/gms/play-services-auth + 2017-03-29T17:26:27.9556369-04:00 + SDK for getting user credentials validated against Google authentication services + More login options for users in our games, rather than requiring Epic username/password + + Android + + + UE4 + + dll + https://www.google.com/policies/terms/ + + Licensees + Git + P4 + + false + false + None + Not sure + None + \ No newline at end of file diff --git a/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/ThirdParty/Android/Java/GoogleLogin.java b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/ThirdParty/Android/Java/GoogleLogin.java new file mode 100644 index 000000000000..13ab49f7ce33 --- /dev/null +++ b/Engine/Plugins/Online/OnlineSubsystemGoogle/Source/ThirdParty/Android/Java/GoogleLogin.java @@ -0,0 +1,533 @@ +package com.epicgames.ue4; + +import android.util.Log; + +import android.accounts.Account; +import android.app.Activity; +import android.content.Intent; +import android.content.IntentSender; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.Signature; +import android.content.res.Resources; +import android.os.Bundle; +import android.util.Base64; + +import com.google.android.gms.auth.api.Auth; +import com.google.android.gms.auth.api.signin.GoogleSignInAccount; +import com.google.android.gms.auth.api.signin.GoogleSignInOptions; +import com.google.android.gms.auth.api.signin.GoogleSignInResult; +import com.google.android.gms.auth.api.signin.GoogleSignInStatusCodes; +import com.google.android.gms.common.ConnectionResult; +import com.google.android.gms.common.GoogleApiAvailability; + +import com.google.android.gms.common.api.GoogleApiClient; +import com.google.android.gms.common.api.OptionalPendingResult; +import com.google.android.gms.common.api.ResultCallback; +import com.google.android.gms.common.api.Status; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class GoogleLogin implements + GoogleApiClient.OnConnectionFailedListener +{ + /** Responses supported by this class */ + public static final int GOOGLE_RESPONSE_OK = 0; + public static final int GOOGLE_RESPONSE_CANCELED = 1; + public static final int GOOGLE_RESPONSE_ERROR = 2; + + /** Debug output tag */ + private static final String TAG = "UE4-GOOGLE"; + + /** Key to save in bundle when restoring state */ + private static final String STATE_RESOLVING_ERROR = "resolving_error"; + // Request code to use when launching the resolution activity + private static final int REQUEST_RESOLVE_ERROR = 1001; + // Bool to track whether the app is already resolving an error + private boolean bResolvingError = false; + + // Output device for log messages. + private Logger GoogleLog; + private Logger ActivityLog; + + /** + * Activity needed here to send the signal back when user successfully logged in. + */ + private GameActivity activity; + + /** Android key from Google API dashboard */ + private String clientId; + /** Backend server key from Google API dashboard */ + private String serverClientId; + /** Unique request id when using sign in activity */ + private static final int REQUEST_SIGN_IN = 9001; + /** Google API client needed for actual sign in */ + private GoogleApiClient mGoogleApiClient; + /** Callbacks for handling Google sign in behavior */ + private GoogleApiClient.ConnectionCallbacks connectionCallbacks; + /** Connection status */ + private boolean bConnected = false; + + public GoogleLogin(GameActivity activity, final Logger InLog) + { + this.activity = activity; + + GoogleLog = new Logger(TAG); + ActivityLog = InLog; + } + + public boolean init(String inPackageName, String BuildConfiguration, String inClientId, String inServerClientId, Bundle savedInstanceState) + { + boolean bInitSuccess = false; + boolean bShippingBuild = BuildConfiguration.equals("Shipping"); + + if (bShippingBuild) + { + GoogleLog.SuppressLogs(); + } + + boolean bClientIdValid = (inClientId != null && !inClientId.isEmpty()); + boolean bServerIdValid = (inServerClientId != null && !inServerClientId.isEmpty()); + if (bClientIdValid && bServerIdValid) + { + GoogleLog.debug("init"); + + boolean bIsAvailable = isGooglePlayServicesAvailable(); + GoogleLog.debug("Is Google Play Services Available:" + bIsAvailable); + if (bIsAvailable) + { + PrintGoogleServiceSettings(); + + bResolvingError = savedInstanceState != null && + savedInstanceState.getBoolean(STATE_RESOLVING_ERROR, false); + + GoogleLog.debug("inPackageName: " + inPackageName); + clientId = inClientId; + GoogleLog.debug("GoogleSignIn clientId:" + clientId); + serverClientId = inServerClientId; + GoogleLog.debug("GoogleSignIn serverClientId:" + serverClientId); + + connectionCallbacks = getConnectionCallbacks(); + + // Configure sign-in to request the user's ID, email address, and basic + // profile. ID and basic profile are included in DEFAULT_SIGN_IN. + GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) + .requestIdToken(serverClientId) + .requestProfile() + //.requestServerAuthCode(serverClientId) + .requestEmail() + .build(); + + // Build a GoogleApiClient with access to the Google Sign-In API and the + // options specified by gso. + mGoogleApiClient = new GoogleApiClient.Builder(activity) + //.enableAutoManage(activity /* FragmentActivity */, this /* OnConnectionFailedListener */) + .addConnectionCallbacks(connectionCallbacks) + .addOnConnectionFailedListener(this) + .addApi(Auth.GOOGLE_SIGN_IN_API, gso) + .build(); + + PrintGoogleAPIState(); + PrintKeyHash(inPackageName); + bInitSuccess = true; + } + } + else + { + GoogleLog.debug("clientId: " + inClientId + " or serverClientId: " + inServerClientId + " is invalid"); + } + + return bInitSuccess; + } + + public void onStart() + { + GoogleLog.debug("onStart"); + mGoogleApiClient.connect(); + PrintGoogleAPIState(); + + OptionalPendingResult opr = Auth.GoogleSignInApi.silentSignIn(mGoogleApiClient); + if (opr.isDone()) { + // If the user's cached credentials are valid, the OptionalPendingResult will be "done" + // and the GoogleSignInResult will be available instantly. + GoogleLog.debug("Got cached sign-in"); + GoogleSignInResult result = opr.get(); + handleSignInResult(result); + } else { + // If the user has not previously signed in on this device or the sign-in has expired, + // this asynchronous branch will attempt to sign in the user silently. Cross-device + // single sign-on will occur in this branch. + opr.setResultCallback(new ResultCallback() { + @Override + public void onResult(GoogleSignInResult googleSignInResult) { + GoogleLog.debug("Sign-in callback"); + handleSignInResult(googleSignInResult); + } + }); + } + + PrintGoogleAPIState(); + } + + public void onStop() + { + GoogleLog.debug("onStop"); + mGoogleApiClient.disconnect(); + } + + public void onSaveInstanceState(Bundle outState) + { + GoogleLog.debug("onSaveInstanceState"); + outState.putBoolean(STATE_RESOLVING_ERROR, bResolvingError); + } + + public void onDestroy() + { + GoogleLog.debug("onDestroy"); + //mGoogleApiClient.unregisterConnectionCallbacks(connectionCallbacks); + } + + private GoogleApiClient.ConnectionCallbacks getConnectionCallbacks() + { + return new GoogleApiClient.ConnectionCallbacks() + { + @Override + public void onConnected(Bundle connectionHint) + { + bConnected = true; + if (connectionHint != null) { + GoogleLog.debug("onConnected " + connectionHint.toString()); + } + else + { + GoogleLog.debug("onConnected null bundle"); + } + } + @Override + public void onConnectionSuspended(int cause) + { + // CAUSE_SERVICE_DISCONNECTED + // CAUSE_NETWORK_LOST; + GoogleLog.debug("onConnectionSuspended " + cause); + bConnected = false; + } + }; + } + + public int login(String[] ScopeFields) + { + GoogleLog.debug("login:" + ScopeFields.toString()); + PrintGoogleAPIState(); + + int resultCode = GOOGLE_RESPONSE_ERROR; + if (!mGoogleApiClient.isConnecting()) + { + GoogleLog.debug("login intent:"); + Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient); + if (signInIntent != null) + { + GoogleLog.debug("login start activity:"); + activity.startActivityForResult(signInIntent, REQUEST_SIGN_IN); + resultCode = GOOGLE_RESPONSE_OK; + } + else + { + GoogleLog.debug("getSignInIntent failure:"); + nativeLoginComplete(GOOGLE_RESPONSE_ERROR, ""); + } + } + else + { + GoogleLog.debug("onSignIn: still connecting"); + nativeLoginComplete(GOOGLE_RESPONSE_ERROR, ""); + } + + return resultCode; + } + + public int logout() + { + GoogleLog.debug("logout"); + PrintGoogleAPIState(); + + int resultCode = GOOGLE_RESPONSE_ERROR; + if (!mGoogleApiClient.isConnecting()) + { + GoogleLog.debug("calling signout"); + Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback( + new ResultCallback() + { + @Override + public void onResult(Status status) + { + GoogleLog.debug("onSignOut Complete" + status + " " + status.getStatusMessage()); + nativeLogoutComplete(GOOGLE_RESPONSE_OK); + } + }); + resultCode = GOOGLE_RESPONSE_OK; + } + else + { + GoogleLog.debug("onSignOut: still connecting"); + nativeLogoutComplete(GOOGLE_RESPONSE_ERROR); + } + + return resultCode; + } + + public void onActivityResult(int requestCode, int resultCode, Intent data) + { + GoogleLog.debug("onActivityResult: " + requestCode + " result: " + resultCode); + // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...); + if (requestCode == REQUEST_SIGN_IN) + { + GoogleLog.debug("onActivityResult REQUEST_SIGN_IN"); + if (resultCode == Activity.RESULT_OK) + { + GoogleLog.debug("signing in"); + } + + GoogleLog.debug("data: " + ((data != null) ? data.toString() : "null")); + + GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data); + if (result != null) + { + handleSignInResult(result); + + GoogleLog.debug("onActivityResult result:" + result.isSuccess()); + GoogleLog.debug("result:" + result.toString()); + if (result.isSuccess()) + { + // Signed in successfully... + GoogleSignInAccount acct = result.getSignInAccount(); + nativeLoginComplete(GOOGLE_RESPONSE_OK, getLoginJsonStr(acct)); + } + else + { + // Signed out + Status myStatus = result.getStatus(); + GoogleLog.debug("Code:" + GoogleSignInStatusCodes.getStatusCodeString(myStatus.getStatusCode())); + GoogleLog.debug("Message:" + myStatus.getStatusMessage()); + nativeLoginComplete(GOOGLE_RESPONSE_ERROR, ""); + } + } + else + { + GoogleLog.debug("onActivityResult result is null"); + nativeLoginComplete(GOOGLE_RESPONSE_ERROR, ""); + } + GoogleLog.debug("onActivityResult end"); + } + + if (requestCode == REQUEST_RESOLVE_ERROR) + { + bResolvingError = false; + if (resultCode == Activity.RESULT_OK) + { + // Make sure the app is not already connected or attempting to connect + if (!mGoogleApiClient.isConnecting() && !mGoogleApiClient.isConnected()) + { + mGoogleApiClient.connect(); + } + } + } + } + + public void onConnectionFailed(ConnectionResult connectionResult) + { + // An unresolvable error has occurred and Google APIs (including Sign-In) will not + // be available. + GoogleLog.debug("onConnectionFailed:" + connectionResult); + //PendingIntent signInIntent = connectionResult.getResolution(); + + if (bResolvingError) + { + // Already attempting to resolve an error. + GoogleLog.debug("already resolving"); + return; + } + else if (connectionResult.hasResolution()) + { + try + { + GoogleLog.debug("start resolving"); + bResolvingError = true; + connectionResult.startResolutionForResult(activity, REQUEST_RESOLVE_ERROR); + } + catch (IntentSender.SendIntentException e) + { + // There was an error with the resolution intent. Try again. + GoogleLog.debug("error resolving"); + mGoogleApiClient.connect(); + } + } + else + { + // Show dialog using GoogleApiAvailability.getErrorDialog() + //showErrorDialog(connectionResult.getErrorCode()); + GoogleLog.debug("no resolution"); + bResolvingError = true; + } + } + + private void handleSignInResult(GoogleSignInResult result) + { + if (result != null) + { + GoogleLog.debug("handleSignInResult:" + result.isSuccess()); + if (result.isSuccess()) + { + // Signed in successfully, show authenticated UI. + GoogleSignInAccount acct = result.getSignInAccount(); + PrintUserAccountInfo(acct); + //nativeLoginComplete(GOOGLE_RESPONSE_OK, getLoginJsonStr(acct)); + } + else + { + // Signed out + Status myStatus = result.getStatus(); + GoogleLog.debug("Code:" + GoogleSignInStatusCodes.getStatusCodeString(myStatus.getStatusCode())); + GoogleLog.debug("Message:" + myStatus.getStatusMessage()); + //nativeLoginComplete(GOOGLE_RESPONSE_ERROR, ""); + } + } + else + { + GoogleLog.debug("handleSignInResult: result is null"); + } + } + + private String getLoginJsonStr(GoogleSignInAccount acct) + { + if (acct != null) + { + return "{\"user_data\":" + getUserJsonStr(acct) + "," + + "\"auth_data\":" + getAuthTokenJsonStr(acct) + "}"; + } + + return ""; + } + + private String getUserJsonStr(GoogleSignInAccount acct) + { + if (acct != null) + { + return "{\"sub\":\""+ acct.getId() + "\"," + + "\"given_name\":\"" + acct.getGivenName() + "\"," + + "\"family_name\":\"" + acct.getFamilyName() + "\"," + + "\"name\":\"" + acct.getDisplayName() + "\"," + + "\"picture\":\"" + acct.getPhotoUrl() + "\"" + "}"; + } + return ""; + } + + private String getAuthTokenJsonStr(GoogleSignInAccount acct) + { + if (acct != null) + { + return "{\"access_token\":\"androidInternal\"," + + "\"refresh_token\":\"androidInternal\"," + + "\"id_token\":\""+ acct.getIdToken() + "\"}"; + } + return ""; + } + + public void PrintGoogleAPIState() + { + boolean bEnabled = false; + if (bEnabled) + { + PrintWriter printWriter = new PrintWriter(System.out, true); + GoogleLog.debug("--------------------------------------"); + mGoogleApiClient.dumpAll(TAG, FileDescriptor.out, printWriter, null); + GoogleLog.debug("Connected: " + mGoogleApiClient.isConnected() + " Connecting: " + mGoogleApiClient.isConnecting()); + GoogleLog.debug("--------------------------------------"); + } + } + + private String GetResourceById(String resourceName, Resources resources, String packageName) + { + try + { + int resourceId = resources.getIdentifier(resourceName, "string", packageName); + return activity.getString(resourceId); + } + catch (Exception e) { + GoogleLog.debug("Resource: " + resourceName + " is not found!"); + return ""; + } + } + + public void PrintGoogleServiceSettings() + { + String packageName = activity.getPackageName(); + Resources resources = activity.getResources(); + + GoogleLog.debug("--------------------------------------"); + GoogleLog.debug("default_web_client_id:" + GetResourceById("default_web_client_id", resources, packageName)); + GoogleLog.debug("gcm_defaultSenderId:" + GetResourceById("gcm_defaultSenderId", resources, packageName)); + GoogleLog.debug("google_api_key:" + GetResourceById("google_api_key", resources, packageName)); + GoogleLog.debug("google_app_id:" + GetResourceById("google_app_id", resources, packageName)); + GoogleLog.debug("google_crash_reporting_api_key:" + GetResourceById("google_crash_reporting_api_key", resources, packageName)); + GoogleLog.debug("--------------------------------------"); + } + + public void PrintUserAccountInfo(GoogleSignInAccount acct) + { + GoogleLog.debug("User Details:"); + GoogleLog.debug(" DisplayName:" + acct.getDisplayName()); + GoogleLog.debug(" Id:" + acct.getId()); + GoogleLog.debug(" Email:" + acct.getEmail()); + // 10.2.0 GoogleLog.debug(" Account:" + acct.getAccount().toString()); + + GoogleLog.debug(" Scopes:" + acct.getGrantedScopes()); + GoogleLog.debug(" IdToken:" + acct.getIdToken()); + GoogleLog.debug(" ServerAuthCode:" + acct.getServerAuthCode()); + } + + private boolean isGooglePlayServicesAvailable() + { + GoogleApiAvailability apiAvail = GoogleApiAvailability.getInstance(); + int status = apiAvail.isGooglePlayServicesAvailable(activity); + GoogleLog.debug("isGooglePlayServicesAvailable statusCode: " + status); + if (status == ConnectionResult.SUCCESS) + { + return true; + } + else + { + return false; + } + } + + public void PrintKeyHash(String packageName) + { + try + { + PackageInfo info = activity.getPackageManager().getPackageInfo( + packageName, + PackageManager.GET_SIGNATURES); + for (Signature signature : info.signatures) + { + MessageDigest md = MessageDigest.getInstance("SHA"); + md.update(signature.toByteArray()); + GoogleLog.debug(Base64.encodeToString(md.digest(), Base64.DEFAULT)); + } + } + catch (PackageManager.NameNotFoundException e) + { + GoogleLog.debug("NameNotFoundException:" + e); + } + catch (NoSuchAlgorithmException e) + { + GoogleLog.debug("NoSuchAlgorithmException:" + e); + } + } + + // Callback that notify the C++ implementation that a task has completed + public native void nativeLoginComplete(int responseCode, String javaData); + public native void nativeLogoutComplete(int responseCode); +} diff --git a/Engine/Plugins/Online/OnlineSubsystemNull/OnlineSubsystemNull.uplugin b/Engine/Plugins/Online/OnlineSubsystemNull/OnlineSubsystemNull.uplugin index 230d3dfdb572..020c2ee2b264 100644 --- a/Engine/Plugins/Online/OnlineSubsystemNull/OnlineSubsystemNull.uplugin +++ b/Engine/Plugins/Online/OnlineSubsystemNull/OnlineSubsystemNull.uplugin @@ -16,5 +16,16 @@ "Type": "Runtime", "LoadingPhase" : "Default" } - ] + ], + "Plugins": [ + { + "Name": "OnlineSubsystem", + "Enabled": true + }, + { + "Name": "OnlineSubsystemUtils", + "Enabled": true + } + ] + } \ No newline at end of file diff --git a/Engine/Plugins/Online/OnlineSubsystemNull/Source/OnlineSubsystemNull.Build.cs b/Engine/Plugins/Online/OnlineSubsystemNull/Source/OnlineSubsystemNull.Build.cs index e0b7d54af1bd..9a6d29e62c3c 100644 --- a/Engine/Plugins/Online/OnlineSubsystemNull/Source/OnlineSubsystemNull.Build.cs +++ b/Engine/Plugins/Online/OnlineSubsystemNull/Source/OnlineSubsystemNull.Build.cs @@ -6,7 +6,7 @@ using System.IO; public class OnlineSubsystemNull : ModuleRules { public OnlineSubsystemNull(ReadOnlyTargetRules Target) : base(Target) - { + { Definitions.Add("ONLINESUBSYSTEMNULL_PACKAGE=1"); PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; diff --git a/Engine/Plugins/Online/OnlineSubsystemNull/Source/Private/OnlineSessionInterfaceNull.cpp b/Engine/Plugins/Online/OnlineSubsystemNull/Source/Private/OnlineSessionInterfaceNull.cpp index d15fec79995a..4443f84cf121 100644 --- a/Engine/Plugins/Online/OnlineSubsystemNull/Source/Private/OnlineSessionInterfaceNull.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemNull/Source/Private/OnlineSessionInterfaceNull.cpp @@ -1040,7 +1040,7 @@ void FOnlineSessionNull::OnValidQueryPacketReceived(uint8* PacketData, int32 Pac for (int32 SessionIndex = 0; SessionIndex < Sessions.Num(); SessionIndex++) { FNamedOnlineSession* Session = &Sessions[SessionIndex]; - + // Don't respond to query if the session is not a joinable LAN match. if (Session && IsSessionJoinable(*Session)) { diff --git a/Engine/Plugins/Online/OnlineSubsystemNull/Source/Private/OnlineSessionInterfaceNull.h b/Engine/Plugins/Online/OnlineSubsystemNull/Source/Private/OnlineSessionInterfaceNull.h index b215581447c0..5ac4d595683a 100644 --- a/Engine/Plugins/Online/OnlineSubsystemNull/Source/Private/OnlineSessionInterfaceNull.h +++ b/Engine/Plugins/Online/OnlineSubsystemNull/Source/Private/OnlineSessionInterfaceNull.h @@ -309,7 +309,7 @@ public: virtual bool SendSessionInviteToFriends(int32 LocalUserNum, FName SessionName, const TArray< TSharedRef >& Friends) override; virtual bool SendSessionInviteToFriends(const FUniqueNetId& LocalUserId, FName SessionName, const TArray< TSharedRef >& Friends) override; virtual bool GetResolvedConnectString(FName SessionName, FString& ConnectInfo, FName PortType) override; - virtual bool GetResolvedConnectString(const class FOnlineSessionSearchResult& SearchResult, FName PortType, FString& ConnectInfo) override; + virtual bool GetResolvedConnectString(const FOnlineSessionSearchResult& SearchResult, FName PortType, FString& ConnectInfo) override; virtual FOnlineSessionSettings* GetSessionSettings(FName SessionName) override; virtual bool RegisterPlayer(FName SessionName, const FUniqueNetId& PlayerId, bool bWasInvited) override; virtual bool RegisterPlayers(FName SessionName, const TArray< TSharedRef >& Players, bool bWasInvited = false) override; diff --git a/Engine/Plugins/Online/OnlineSubsystemNull/Source/Private/OnlineSubsystemNull.cpp b/Engine/Plugins/Online/OnlineSubsystemNull/Source/Private/OnlineSubsystemNull.cpp index 0229eb237d2e..8db1c8dc4cbf 100644 --- a/Engine/Plugins/Online/OnlineSubsystemNull/Source/Private/OnlineSubsystemNull.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemNull/Source/Private/OnlineSubsystemNull.cpp @@ -241,6 +241,11 @@ bool FOnlineSubsystemNull::Exec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice return false; } +FText FOnlineSubsystemNull::GetOnlineServiceName() const +{ + return NSLOCTEXT("OnlineSubsystemNull", "OnlineServiceName", "Null"); +} + bool FOnlineSubsystemNull::IsEnabled() { return true; diff --git a/Engine/Plugins/Online/OnlineSubsystemNull/Source/Public/OnlineSubsystemNull.h b/Engine/Plugins/Online/OnlineSubsystemNull/Source/Public/OnlineSubsystemNull.h index 6536c0d60b05..2ec5358be552 100644 --- a/Engine/Plugins/Online/OnlineSubsystemNull/Source/Public/OnlineSubsystemNull.h +++ b/Engine/Plugins/Online/OnlineSubsystemNull/Source/Public/OnlineSubsystemNull.h @@ -62,12 +62,13 @@ public: virtual IOnlineMessagePtr GetMessageInterface() const override; virtual IOnlinePresencePtr GetPresenceInterface() const override; virtual IOnlineChatPtr GetChatInterface() const override; - virtual IOnlineTurnBasedPtr GetTurnBasedInterface() const override; + virtual IOnlineTurnBasedPtr GetTurnBasedInterface() const override; virtual bool Init() override; virtual bool Shutdown() override; virtual FString GetAppId() const override; virtual bool Exec(class UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) override; + virtual FText GetOnlineServiceName() const override; // FTickerObjectBase diff --git a/Engine/Plugins/Online/OnlineSubsystemOculus/OnlineSubsystemOculus.uplugin b/Engine/Plugins/Online/OnlineSubsystemOculus/OnlineSubsystemOculus.uplugin index bdce3a661bd7..9be1ca9c2dbc 100644 --- a/Engine/Plugins/Online/OnlineSubsystemOculus/OnlineSubsystemOculus.uplugin +++ b/Engine/Plugins/Online/OnlineSubsystemOculus/OnlineSubsystemOculus.uplugin @@ -29,5 +29,16 @@ "Name": "OnlineSubsystemOculus", "LoadingPolicy": "Always" } + ], + "Plugins": [ + { + "Name": "OnlineSubsystem", + "Enabled": true + }, + { + "Name": "OnlineSubsystemUtils", + "Enabled": true + } ] + } \ No newline at end of file diff --git a/Engine/Plugins/Online/OnlineSubsystemOculus/Source/OnlineSubsystemOculus.Build.cs b/Engine/Plugins/Online/OnlineSubsystemOculus/Source/OnlineSubsystemOculus.Build.cs index 53f47bae4787..386dae7bfac1 100644 --- a/Engine/Plugins/Online/OnlineSubsystemOculus/Source/OnlineSubsystemOculus.Build.cs +++ b/Engine/Plugins/Online/OnlineSubsystemOculus/Source/OnlineSubsystemOculus.Build.cs @@ -5,7 +5,7 @@ using UnrealBuildTool; public class OnlineSubsystemOculus : ModuleRules { public OnlineSubsystemOculus(ReadOnlyTargetRules Target) : base(Target) - { + { Definitions.Add("ONLINESUBSYSTEMOCULUS_PACKAGE=1"); PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; diff --git a/Engine/Plugins/Online/OnlineSubsystemOculus/Source/Private/OVR_PlatformLoader.cpp b/Engine/Plugins/Online/OnlineSubsystemOculus/Source/Private/OVR_PlatformLoader.cpp index a6a43494e801..cb9e170f736b 100644 --- a/Engine/Plugins/Online/OnlineSubsystemOculus/Source/Private/OVR_PlatformLoader.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemOculus/Source/Private/OVR_PlatformLoader.cpp @@ -252,7 +252,7 @@ static int ValidateCertificateContents(CertificateEntry* chain, CRYPT_PROVIDER_S pCertData->pCert, CERT_NAME_ATTR_TYPE, 0, - szOID_COMMON_NAME, + (void*)szOID_COMMON_NAME, subjectStr, ARRAYSIZE(subjectStr)); diff --git a/Engine/Plugins/Online/OnlineSubsystemOculus/Source/Private/OnlineSubsystemOculus.cpp b/Engine/Plugins/Online/OnlineSubsystemOculus/Source/Private/OnlineSubsystemOculus.cpp index 8b801c5ddb72..b0b30cad9ff3 100644 --- a/Engine/Plugins/Online/OnlineSubsystemOculus/Source/Private/OnlineSubsystemOculus.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemOculus/Source/Private/OnlineSubsystemOculus.cpp @@ -326,6 +326,11 @@ bool FOnlineSubsystemOculus::Exec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevi return false; } +FText FOnlineSubsystemOculus::GetOnlineServiceName() const +{ + return NSLOCTEXT("OnlineSubsystemOculus", "OnlineServiceName", "Oculus Platform"); +} + bool FOnlineSubsystemOculus::IsEnabled() { bool bEnableOculus = true; diff --git a/Engine/Plugins/Online/OnlineSubsystemOculus/Source/Private/OnlineVoiceOculus.h b/Engine/Plugins/Online/OnlineSubsystemOculus/Source/Private/OnlineVoiceOculus.h index 63d569cfee53..7131980889de 100644 --- a/Engine/Plugins/Online/OnlineSubsystemOculus/Source/Private/OnlineVoiceOculus.h +++ b/Engine/Plugins/Online/OnlineSubsystemOculus/Source/Private/OnlineVoiceOculus.h @@ -70,7 +70,7 @@ public: } virtual bool IsLocalPlayerTalking(uint32 LocalUserNum) override { - return (!bIsLocalPlayerMuted && 0 <= LocalUserNum && LocalUserNum <= MAX_LOCAL_PLAYERS); + return (!bIsLocalPlayerMuted && LocalUserNum <= MAX_LOCAL_PLAYERS); } virtual bool IsRemotePlayerTalking(const FUniqueNetId& UniqueId) override; virtual bool IsMuted(uint32 LocalUserNum, const FUniqueNetId& UniqueId) const override; diff --git a/Engine/Plugins/Online/OnlineSubsystemOculus/Source/Public/OnlineSubsystemOculus.h b/Engine/Plugins/Online/OnlineSubsystemOculus/Source/Public/OnlineSubsystemOculus.h index 6595c25d40f6..ff26fc4e4791 100644 --- a/Engine/Plugins/Online/OnlineSubsystemOculus/Source/Public/OnlineSubsystemOculus.h +++ b/Engine/Plugins/Online/OnlineSubsystemOculus/Source/Public/OnlineSubsystemOculus.h @@ -64,6 +64,7 @@ public: virtual bool Shutdown() override; virtual FString GetAppId() const override; virtual bool Exec(class UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) override; + virtual FText GetOnlineServiceName() const override; // FTickerObjectBase diff --git a/Engine/Plugins/Online/OnlineSubsystemSteam/OnlineSubsystemSteam.uplugin b/Engine/Plugins/Online/OnlineSubsystemSteam/OnlineSubsystemSteam.uplugin index bd107f552de3..7d140acd0617 100644 --- a/Engine/Plugins/Online/OnlineSubsystemSteam/OnlineSubsystemSteam.uplugin +++ b/Engine/Plugins/Online/OnlineSubsystemSteam/OnlineSubsystemSteam.uplugin @@ -29,5 +29,16 @@ "Name": "OnlineSubsystemSteam", "LoadingPolicy": "Always" } + ], + "Plugins": [ + { + "Name": "OnlineSubsystem", + "Enabled": true + }, + { + "Name": "OnlineSubsystemUtils", + "Enabled": true + } ] + } \ No newline at end of file diff --git a/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Private/OnlineSessionAsyncServerSteam.h b/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Private/OnlineSessionAsyncServerSteam.h index 41b334966f30..c40f07b4fa59 100644 --- a/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Private/OnlineSessionAsyncServerSteam.h +++ b/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Private/OnlineSessionAsyncServerSteam.h @@ -162,7 +162,7 @@ public: * currently waiting for the Steam rules to be returned before creating a final search * result to associate with the currently running query */ -class FPendingSearchResultSteam : public ISteamMatchmakingRulesResponse +class FPendingSearchResultSteam final : public ISteamMatchmakingRulesResponse { /** Hidden on purpose */ FPendingSearchResultSteam() : @@ -208,7 +208,7 @@ public: } - ~FPendingSearchResultSteam() + virtual ~FPendingSearchResultSteam() { } diff --git a/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Private/OnlineSessionInterfaceSteam.cpp b/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Private/OnlineSessionInterfaceSteam.cpp index 34a9232ad763..11acf8c7e947 100644 --- a/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Private/OnlineSessionInterfaceSteam.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Private/OnlineSessionInterfaceSteam.cpp @@ -1555,31 +1555,28 @@ void FOnlineSessionSteam::OnValidQueryPacketReceived(uint8* PacketData, int32 Pa FScopeLock ScopeLock(&SessionLock); for (int32 SessionIndex = 0; SessionIndex < Sessions.Num(); SessionIndex++) { - FNamedOnlineSession* Session = &Sessions[SessionIndex]; + FNamedOnlineSession& Session = Sessions[SessionIndex]; + + const FOnlineSessionSettings& Settings = Session.SessionSettings; + + const bool bIsMatchInProgress = Session.SessionState == EOnlineSessionState::InProgress; + + const bool bIsMatchJoinable = Settings.bIsLANMatch && + (!bIsMatchInProgress || Settings.bAllowJoinInProgress) && + Settings.NumPublicConnections > 0; // Don't respond to query if the session is not a joinable LAN match. - if (Session) + if (bIsMatchJoinable) { - const FOnlineSessionSettings& Settings = Session->SessionSettings; - - const bool bIsMatchInProgress = Session->SessionState == EOnlineSessionState::InProgress; - - const bool bIsMatchJoinable = Settings.bIsLANMatch && - (!bIsMatchInProgress || Settings.bAllowJoinInProgress) && - Settings.NumPublicConnections > 0; - - if (bIsMatchJoinable) - { - FNboSerializeToBufferSteam Packet(LAN_BEACON_MAX_PACKET_SIZE); - // Create the basic header before appending additional information - LANSession->CreateHostResponsePacket(Packet, ClientNonce); + FNboSerializeToBufferSteam Packet(LAN_BEACON_MAX_PACKET_SIZE); + // Create the basic header before appending additional information + LANSession->CreateHostResponsePacket(Packet, ClientNonce); - // Add all the session details - AppendSessionToPacket(Packet, Session); + // Add all the session details + AppendSessionToPacket(Packet, &Session); - // Broadcast this response so the client can see us - LANSession->BroadcastPacket(Packet, Packet.GetByteCount()); - } + // Broadcast this response so the client can see us + LANSession->BroadcastPacket(Packet, Packet.GetByteCount()); } } } diff --git a/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Private/OnlineSessionInterfaceSteam.h b/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Private/OnlineSessionInterfaceSteam.h index fc8a018115d2..a8d343caf701 100644 --- a/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Private/OnlineSessionInterfaceSteam.h +++ b/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Private/OnlineSessionInterfaceSteam.h @@ -518,7 +518,7 @@ public: virtual bool SendSessionInviteToFriends(int32 LocalUserNum, FName SessionName, const TArray< TSharedRef >& Friends) override; virtual bool SendSessionInviteToFriends(const FUniqueNetId& LocalUserId, FName SessionName, const TArray< TSharedRef >& Friends) override; virtual bool GetResolvedConnectString(FName SessionName, FString& ConnectInfo, FName PortType) override; - virtual bool GetResolvedConnectString(const class FOnlineSessionSearchResult& SearchResult, FName PortType, FString& ConnectInfo) override; + virtual bool GetResolvedConnectString(const FOnlineSessionSearchResult& SearchResult, FName PortType, FString& ConnectInfo) override; virtual FOnlineSessionSettings* GetSessionSettings(FName SessionName) override; virtual bool RegisterPlayer(FName SessionName, const FUniqueNetId& PlayerId, bool bWasInvited) override; virtual bool RegisterPlayers(FName SessionName, const TArray< TSharedRef >& Players, bool bWasInvited = false) override; diff --git a/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Private/OnlineSubsystemSteam.cpp b/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Private/OnlineSubsystemSteam.cpp index 0a474872f5ac..0193a9397223 100644 --- a/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Private/OnlineSubsystemSteam.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Private/OnlineSubsystemSteam.cpp @@ -768,3 +768,8 @@ FString FOnlineSubsystemSteam::GetAppId() const { return FString::Printf(TEXT("%d"),GetSteamAppId()); } + +FText FOnlineSubsystemSteam::GetOnlineServiceName() const +{ + return NSLOCTEXT("OnlineSubsystemSteam", "OnlineServiceName", "Steam"); +} diff --git a/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Private/OnlineSubsystemSteamPrivate.h b/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Private/OnlineSubsystemSteamPrivate.h index 9c12f1b34d9f..3771a790f07e 100644 --- a/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Private/OnlineSubsystemSteamPrivate.h +++ b/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Private/OnlineSubsystemSteamPrivate.h @@ -20,13 +20,6 @@ #undef ONLINE_LOG_PREFIX #define ONLINE_LOG_PREFIX TEXT("STEAM: ") -// @todo Steam: Steam headers trigger secure-C-runtime warnings in Visual C++. Rather than mess with _CRT_SECURE_NO_WARNINGS, we'll just -// disable the warnings locally. Remove when this is fixed in the SDK -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4996) -#endif - #pragma push_macro("ARRAY_COUNT") #undef ARRAY_COUNT @@ -35,23 +28,12 @@ #error Steam SDK not located. Expected to be found in Engine/Source/ThirdParty/Steamworks/{SteamVersion} #endif -#if USING_CODE_ANALYSIS -MSVC_PRAGMA(warning(push)) -MSVC_PRAGMA(warning(disable : ALL_CODE_ANALYSIS_WARNINGS)) -#endif // USING_CODE_ANALYSIS +THIRD_PARTY_INCLUDES_START #include "steam/steam_api.h" - -#if USING_CODE_ANALYSIS -MSVC_PRAGMA(warning(pop)) -#endif // USING_CODE_ANALYSIS - #include "steam/steam_gameserver.h" +THIRD_PARTY_INCLUDES_END + #pragma pop_macro("ARRAY_COUNT") -// @todo Steam: See above -#ifdef _MSC_VER -#pragma warning(pop) -#endif - diff --git a/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Private/VoiceInterfaceSteam.cpp b/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Private/VoiceInterfaceSteam.cpp index 74203c5370d3..2a1b6084bf32 100644 --- a/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Private/VoiceInterfaceSteam.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Private/VoiceInterfaceSteam.cpp @@ -534,7 +534,7 @@ void FOnlineVoiceSteam::ProcessMuteChangeNotification() if (LP && LP->PlayerController) { // If there is a player controller, we can mute/unmute people - if (LocalTalkers[Index].bIsRegistered && LP->PlayerController != NULL) + if (LocalTalkers[Index].bIsRegistered) { // Use the common method of checking muting UpdateMuteListForLocalTalker(Index, LP->PlayerController); diff --git a/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Public/OnlineSubsystemSteam.h b/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Public/OnlineSubsystemSteam.h index b2c369ed81c8..506031677be0 100644 --- a/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Public/OnlineSubsystemSteam.h +++ b/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Public/OnlineSubsystemSteam.h @@ -242,7 +242,8 @@ public: virtual bool Init() override; virtual bool Shutdown() override; virtual bool Exec(class UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) override; - FString GetAppId() const override; + virtual FString GetAppId() const override; + virtual FText GetOnlineServiceName() const override; // FTickerObjectBase diff --git a/Engine/Plugins/Online/OnlineSubsystemTwitch/OnlineSubsystemTwitch.uplugin b/Engine/Plugins/Online/OnlineSubsystemTwitch/OnlineSubsystemTwitch.uplugin new file mode 100644 index 000000000000..bf6051c36e09 --- /dev/null +++ b/Engine/Plugins/Online/OnlineSubsystemTwitch/OnlineSubsystemTwitch.uplugin @@ -0,0 +1,31 @@ +{ + "FileVersion" : 1, + + "FriendlyName" : "Online Subsystem Twitch", + "Version" : 1, + "VersionName" : "1.0", + "Description" : "Access to Twitch platform", + "Category" : "Online Platform", + "CreatedBy" : "Epic Games, Inc.", + "CreatedByURL" : "http://epicgames.com", + "EnabledByDefault" : false, + + "Modules": [ + { + "Name": "OnlineSubsystemTwitch", + "Type": "Runtime", + "LoadingPhase": "Default" + } + ], + "Plugins": + [ + { + "Name": "OnlineSubsystem", + "Enabled": true + }, + { + "Name": "OnlineSubsystemUtils", + "Enabled": true + } + ] +} \ No newline at end of file diff --git a/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/OnlineSubsystemTwitch.Build.cs b/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/OnlineSubsystemTwitch.Build.cs new file mode 100644 index 000000000000..f81c07176c8e --- /dev/null +++ b/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/OnlineSubsystemTwitch.Build.cs @@ -0,0 +1,41 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +using UnrealBuildTool; +using System.IO; + +public class OnlineSubsystemTwitch : ModuleRules +{ + public OnlineSubsystemTwitch(ReadOnlyTargetRules Target) : base(Target) + { + Definitions.Add("ONLINESUBSYSTEM_TWITCH_PACKAGE=1"); + PCHUsage = ModuleRules.PCHUsageMode.UseSharedPCHs; + + PrivateIncludePaths.Add("Private"); + + PublicDependencyModuleNames.AddRange( + new string[] { + "Core", + "CoreUObject" + } + ); + + PrivateDependencyModuleNames.AddRange( + new string[] { + "Sockets", + "HTTP", + "Json", + "OnlineSubsystem" + } + ); + + if (UEBuildConfiguration.bCompileAgainstEngine) + { + PrivateDependencyModuleNames.AddRange( + new string[] { + "Engine", + "OnlineSubsystemUtils" + } + ); + } + } +} diff --git a/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Private/OnlineAccountTwitch.cpp b/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Private/OnlineAccountTwitch.cpp new file mode 100644 index 000000000000..3f963ce1f948 --- /dev/null +++ b/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Private/OnlineAccountTwitch.cpp @@ -0,0 +1,137 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "OnlineSubsystemTwitchPrivate.h" +#include "OnlineAccountTwitch.h" + +TSharedRef FUserOnlineAccountTwitch::GetUserId() const +{ + return UserId; +} + +FString FUserOnlineAccountTwitch::GetRealName() const +{ + FString Result; + GetAccountData(TEXT("name"), Result); + return Result; +} + +FString FUserOnlineAccountTwitch::GetDisplayName(const FString& Platform) const +{ + FString Result; + GetAccountData(TEXT("displayName"), Result); + return Result; +} + +bool FUserOnlineAccountTwitch::GetUserAttribute(const FString& AttrName, FString& OutAttrValue) const +{ + return GetAccountData(AttrName, OutAttrValue); +} + +bool FUserOnlineAccountTwitch::SetUserAttribute(const FString& AttrName, const FString& AttrValue) +{ + return SetAccountData(AttrName, AttrValue); +} + +FString FUserOnlineAccountTwitch::GetAccessToken() const +{ + return AuthTicket; +} + +bool FUserOnlineAccountTwitch::GetAuthAttribute(const FString& AttrName, FString& OutAttrValue) const +{ + return false; +} + +/** + * Authorization JSON block from Twitch token validation + */ +struct FTwitchTokenValidationResponseAuthorizationJson : public FJsonSerializable +{ + BEGIN_JSON_SERIALIZER + JSON_SERIALIZE_ARRAY("scopes", Scopes); + END_JSON_SERIALIZER + + /** List of scope fields the user has given permissions to in the token */ + TArray Scopes; +}; + +/** + * Token JSON block from Twitch token validation + */ +struct FTwitchTokenValidationResponseJson : public FJsonSerializable +{ + BEGIN_JSON_SERIALIZER + JSON_SERIALIZE("valid", bValid); + JSON_SERIALIZE_OBJECT_SERIALIZABLE("authorization", Authorization); + JSON_SERIALIZE("user_name", UserName); + JSON_SERIALIZE("user_id", UserId); + JSON_SERIALIZE("client_id", ClientId); + END_JSON_SERIALIZER + + /** Whether or not the token is still valid */ + bool bValid; + /** Json block containing scope fields, if the token is valid */ + FTwitchTokenValidationResponseAuthorizationJson Authorization; + /** Twitch user name, if the token is valid*/ + FString UserName; + /** Twitch user Id, if the token is valid */ + FString UserId; + /** Client Id the token was granted for, if the token is valid */ + FString ClientId; +}; + +bool FUserOnlineAccountTwitch::Parse(const FString& InAuthTicket, const FString& JsonStr) +{ + bool bResult = false; + + if (!InAuthTicket.IsEmpty()) + { + if (!JsonStr.IsEmpty()) + { + TSharedPtr JsonUser; + TSharedRef< TJsonReader<> > JsonReader = TJsonReaderFactory<>::Create(JsonStr); + + if (FJsonSerializer::Deserialize(JsonReader, JsonUser) && + JsonUser.IsValid() && + JsonUser->HasTypedField(TEXT("token"))) + { + FTwitchTokenValidationResponseJson TwitchToken; + if (TwitchToken.FromJson(JsonUser->GetObjectField(TEXT("token")))) + { + if (TwitchToken.bValid) + { + UserId = MakeShared(TwitchToken.UserId); + if (!TwitchToken.UserName.IsEmpty()) + { + SetAccountData(TEXT("displayName"), TwitchToken.UserName); + } + AuthTicket = InAuthTicket; + ScopePermissions = MoveTemp(TwitchToken.Authorization.Scopes); + bResult = true; + } + else + { + UE_LOG_ONLINE(Log, TEXT("FUserOnlineAccountTwitch::Parse: Twitch token is not valid")); + } + } + else + { + UE_LOG_ONLINE(Warning, TEXT("FUserOnlineAccountTwitch::Parse: JSON response missing field 'token': payload=%s"), *JsonStr); + } + } + else + { + UE_LOG_ONLINE(Warning, TEXT("FUserOnlineAccountTwitch::Parse: Failed to parse JSON response: payload=%s"), *JsonStr); + } + } + else + { + UE_LOG_ONLINE(Warning, TEXT("FUserOnlineAccountTwitch::Parse: Empty JSON")); + } + } + else + { + UE_LOG_ONLINE(Warning, TEXT("FUserOnlineAccountTwitch::Parse: Empty Auth Ticket")); + } + return bResult; +} diff --git a/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Private/OnlineExternalUITwitch.cpp b/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Private/OnlineExternalUITwitch.cpp new file mode 100644 index 000000000000..359910456ac3 --- /dev/null +++ b/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Private/OnlineExternalUITwitch.cpp @@ -0,0 +1,256 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "OnlineSubsystemTwitchPrivate.h" +#include "OnlineExternalUITwitch.h" +#include "OnlineIdentityTwitch.h" +#include "OnlineError.h" + +#define TWITCH_STATE_TOKEN TEXT("state") +#define TWITCH_ACCESS_TOKEN TEXT("access_token") + +#define LOGIN_ERROR_UNKNOWN TEXT("com.epicgames.login.unknown") + +bool FOnlineExternalUITwitch::ShowLoginUI(const int ControllerIndex, bool bShowOnlineOnly, bool bShowSkipButton, const FOnLoginUIClosedDelegate& Delegate) +{ + bool bStarted = false; + if (ControllerIndex >= 0 && ControllerIndex < MAX_LOCAL_PLAYERS) + { + FOnlineIdentityTwitchPtr IdentityInt = TwitchSubsystem->GetTwitchIdentityService(); + if (IdentityInt.IsValid()) + { + const FTwitchLoginURL& URLDetails = IdentityInt->GetLoginURLDetails(); + if (URLDetails.IsValid()) + { + const FString& CurrentLoginNonce = IdentityInt->GetCurrentLoginNonce(); + const FString RequestedURL = URLDetails.GetURL(CurrentLoginNonce); + if (OnLoginFlowUIRequiredDelegates.IsBound()) + { + bool bShouldContinueLoginFlow = false; + FOnLoginRedirectURL OnRedirectURLDelegate = FOnLoginRedirectURL::CreateThreadSafeSP(this, &FOnlineExternalUITwitch::OnLoginRedirectURL); + FOnLoginFlowComplete OnExternalLoginFlowCompleteDelegate = FOnLoginFlowComplete::CreateThreadSafeSP(this, &FOnlineExternalUITwitch::OnExternalLoginFlowComplete, ControllerIndex, Delegate); + TriggerOnLoginFlowUIRequiredDelegates(RequestedURL, OnRedirectURLDelegate, OnExternalLoginFlowCompleteDelegate, bShouldContinueLoginFlow); + bStarted = bShouldContinueLoginFlow; + } + else + { + IOnlineSubsystem* ConsoleSubsystem = IOnlineSubsystem::GetByPlatform(); + IOnlineExternalUIPtr ConsoleExternalUI = ConsoleSubsystem ? ConsoleSubsystem->GetExternalUIInterface() : nullptr; + if (ConsoleExternalUI.IsValid()) + { + FShowWebUrlParams ShowParams; + ShowParams.bEmbedded = false; // TODO: See if we can pipe along the embedded coordinates + ShowParams.bShowBackground = true; + ShowParams.bShowCloseButton = true; + ShowParams.bResetCookies = true; // potential for previously logged in user + ShowParams.CallbackPath = URLDetails.LoginRedirectUrl; + + FOnShowWebUrlClosedDelegate OnConsoleShowWebUrlCompleteDelegate = FOnShowWebUrlClosedDelegate::CreateThreadSafeSP(this, &FOnlineExternalUITwitch::OnConsoleShowWebUrlComplete, ControllerIndex, Delegate); + bStarted = ConsoleExternalUI->ShowWebURL(RequestedURL, ShowParams, OnConsoleShowWebUrlCompleteDelegate); + if (!bStarted) + { + UE_LOG_ONLINE(Warning, TEXT("FOnlineExternalUITwitch::ShowLoginUI: Console ShowWebURL failed")); + } + } + } + } + else + { + UE_LOG_ONLINE(Error, TEXT("ShowLoginUI: Url Details not properly configured")); + } + } + else + { + UE_LOG_ONLINE(Error, TEXT("ShowLoginUI: Missing identity interface")); + } + } + else + { + UE_LOG_ONLINE(Error, TEXT("ShowLoginUI: Invalid controller index (%d)"), ControllerIndex); + } + + if (!bStarted) + { + TwitchSubsystem->ExecuteNextTick([ControllerIndex, Delegate]() + { + Delegate.ExecuteIfBound(nullptr, ControllerIndex); + }); + } + + return bStarted; +} + +FLoginFlowResult FOnlineExternalUITwitch::ParseRedirectResult(const FTwitchLoginURL& URLDetails, const FString& RedirectURL) +{ + FLoginFlowResult Result; + + TMap ParamsMap; + + FString ResponseStr = RedirectURL.Mid(URLDetails.LoginRedirectUrl.Len() + 1); + { + TArray Params; + ResponseStr.ParseIntoArray(Params, TEXT("&")); + for (FString& Param : Params) + { + FString Key, Value; + if (Param.Split(TEXT("="), &Key, &Value)) + { + ParamsMap.Add(MoveTemp(Key), MoveTemp(Value)); + } + } + } + + const FString* State = ParamsMap.Find(TWITCH_STATE_TOKEN); + if (State) + { + FOnlineIdentityTwitchPtr IdentityInt = TwitchSubsystem->GetTwitchIdentityService(); + check(IdentityInt.IsValid()); + + const FString& CurrentLoginNonce = IdentityInt->GetCurrentLoginNonce(); + if (CurrentLoginNonce == *State) + { + const FString* AccessToken = ParamsMap.Find(TWITCH_ACCESS_TOKEN); + if (AccessToken) + { + Result.Error.bSucceeded = true; + Result.Token = *AccessToken; + } + else + { + // Set some default in case parsing fails + Result.Error.ErrorRaw = LOGIN_ERROR_UNKNOWN; + Result.Error.ErrorMessage = FText::FromString(LOGIN_ERROR_UNKNOWN); + Result.Error.ErrorCode = TEXT("-1"); + Result.Error.NumericErrorCode = -1; + } + } + else + { + UE_LOG_ONLINE(Warning, TEXT("FOnlineExternalUITwitch::ParseRedirectResult: State does not match (received=%s, expected=%s)"), **State, *CurrentLoginNonce); + } + } + + return Result; +} + +FLoginFlowResult FOnlineExternalUITwitch::OnLoginRedirectURL(const FString& RedirectURL) +{ + FLoginFlowResult Result; + + FOnlineIdentityTwitchPtr IdentityInt = TwitchSubsystem->GetTwitchIdentityService(); + if (IdentityInt.IsValid()) + { + const FTwitchLoginURL& URLDetails = IdentityInt->GetLoginURLDetails(); + if (URLDetails.IsValid()) + { + // Wait for the RedirectURI to appear + if (RedirectURL.StartsWith(URLDetails.LoginRedirectUrl)) + { + Result = ParseRedirectResult(URLDetails, RedirectURL); + } + else + { + // TODO: Does Twitch redirect the user to a URL we would want to close on? I haven't found any, it just keeps the user on the login page + } + } + } + + return Result; +} + +void FOnlineExternalUITwitch::OnLoginUIComplete(const FLoginFlowResult& Result, int ControllerIndex, const FOnLoginUIClosedDelegate& Delegate) +{ + bool bStarted = false; + if (Result.IsValid()) + { + FOnlineIdentityTwitchPtr IdentityInt = TwitchSubsystem->GetTwitchIdentityService(); + if (IdentityInt.IsValid()) + { + bStarted = true; + + FOnLoginCompleteDelegate CompletionDelegate; + CompletionDelegate = FOnLoginCompleteDelegate::CreateThreadSafeSP(this, &FOnlineExternalUITwitch::OnAccessTokenLoginComplete, Delegate); + IdentityInt->LoginWithAccessToken(ControllerIndex, Result.Token, CompletionDelegate); + } + } + + if (!bStarted) + { + TwitchSubsystem->ExecuteNextTick([ControllerIndex, Delegate]() + { + Delegate.ExecuteIfBound(nullptr, ControllerIndex); + }); + } +} + +void FOnlineExternalUITwitch::OnExternalLoginFlowComplete(const FLoginFlowResult& Result, int ControllerIndex, const FOnLoginUIClosedDelegate Delegate) +{ + UE_LOG_ONLINE(Log, TEXT("OnExternalLoginFlowComplete %s"), *Result.ToDebugString()); + OnLoginUIComplete(Result, ControllerIndex, Delegate); +} + +void FOnlineExternalUITwitch::OnConsoleShowWebUrlComplete(const FString& FinalUrl, int ControllerIndex, const FOnLoginUIClosedDelegate Delegate) +{ + FLoginFlowResult Result = OnLoginRedirectURL(FinalUrl); + + UE_LOG_ONLINE(Log, TEXT("OnConsoleShowWebUrlComplete %s"), *Result.ToDebugString()); + OnLoginUIComplete(Result, ControllerIndex, Delegate); +} + +void FOnlineExternalUITwitch::OnAccessTokenLoginComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& UserId, const FString& Error, FOnLoginUIClosedDelegate Delegate) +{ + TSharedPtr StrongUserId = UserId.AsShared(); + TwitchSubsystem->ExecuteNextTick([StrongUserId, LocalUserNum, Delegate]() + { + Delegate.ExecuteIfBound(StrongUserId, LocalUserNum); + }); +} + +bool FOnlineExternalUITwitch::ShowFriendsUI(int32 LocalUserNum) +{ + return false; +} + +bool FOnlineExternalUITwitch::ShowInviteUI(int32 LocalUserNum, FName SessionName) +{ + return false; +} + +bool FOnlineExternalUITwitch::ShowAchievementsUI(int32 LocalUserNum) +{ + return false; +} + +bool FOnlineExternalUITwitch::ShowLeaderboardUI(const FString& LeaderboardName) +{ + return false; +} + +bool FOnlineExternalUITwitch::ShowWebURL(const FString& Url, const FShowWebUrlParams& ShowParams, const FOnShowWebUrlClosedDelegate& Delegate) +{ + return false; +} + +bool FOnlineExternalUITwitch::CloseWebURL() +{ + return false; +} + +bool FOnlineExternalUITwitch::ShowAccountUpgradeUI(const FUniqueNetId& UniqueId) +{ + return false; +} + +bool FOnlineExternalUITwitch::ShowStoreUI(int32 LocalUserNum, const FShowStoreParams& ShowParams, const FOnShowStoreUIClosedDelegate& Delegate) +{ + return false; +} + +bool FOnlineExternalUITwitch::ShowSendMessageUI(int32 LocalUserNum, const FShowSendMessageParams& ShowParams, const FOnShowSendMessageUIClosedDelegate& Delegate) +{ + return false; +} + +bool FOnlineExternalUITwitch::ShowProfileUI(const FUniqueNetId& Requestor, const FUniqueNetId& Requestee, const FOnProfileUIClosedDelegate& Delegate) +{ + return false; +} diff --git a/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Private/OnlineExternalUITwitch.h b/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Private/OnlineExternalUITwitch.h new file mode 100644 index 000000000000..f95728e31c34 --- /dev/null +++ b/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Private/OnlineExternalUITwitch.h @@ -0,0 +1,114 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "OnlineSubsystemTwitch.h" +#include "OnlineSubsystemTwitchPackage.h" +#include "OnlineExternalUIInterface.h" + +class FOnlineSubsystemTwitch; +class IHttpRequest; +struct FTwitchLoginURL; + +/** + * Implementation for the Twitch external UIs + */ +class ONLINESUBSYSTEMTWITCH_API FOnlineExternalUITwitch : + public IOnlineExternalUI, + public TSharedFromThis +{ +PACKAGE_SCOPE: + + /** + * Constructor + * @param InSubsystem The owner of this external UI interface. + */ + FOnlineExternalUITwitch(FOnlineSubsystemTwitch* InSubsystem) + : TwitchSubsystem(InSubsystem) + { + } + + /** Reference to the owning subsystem */ + FOnlineSubsystemTwitch* TwitchSubsystem; + +public: + + /** + * Destructor. + */ + virtual ~FOnlineExternalUITwitch() = default; + + // IOnlineExternalUI + virtual bool ShowLoginUI(const int ControllerIndex, bool bShowOnlineOnly, bool bShowSkipButton, const FOnLoginUIClosedDelegate& Delegate = FOnLoginUIClosedDelegate()) override; + virtual bool ShowFriendsUI(int32 LocalUserNum) override; + virtual bool ShowInviteUI(int32 LocalUserNum, FName SessionName = GameSessionName) override; + virtual bool ShowAchievementsUI(int32 LocalUserNum) override; + virtual bool ShowLeaderboardUI(const FString& LeaderboardName) override; + virtual bool ShowWebURL(const FString& Url, const FShowWebUrlParams& ShowParams, const FOnShowWebUrlClosedDelegate& Delegate = FOnShowWebUrlClosedDelegate()) override; + virtual bool CloseWebURL() override; + virtual bool ShowProfileUI(const FUniqueNetId& Requestor, const FUniqueNetId& Requestee, const FOnProfileUIClosedDelegate& Delegate = FOnProfileUIClosedDelegate()) override; + virtual bool ShowAccountUpgradeUI(const FUniqueNetId& UniqueId) override; + virtual bool ShowStoreUI(int32 LocalUserNum, const FShowStoreParams& ShowParams, const FOnShowStoreUIClosedDelegate& Delegate = FOnShowStoreUIClosedDelegate()) override; + virtual bool ShowSendMessageUI(int32 LocalUserNum, const FShowSendMessageParams& ShowParams, const FOnShowSendMessageUIClosedDelegate& Delegate = FOnShowSendMessageUIClosedDelegate()) override; + +private: + + /** + * Parse a successful URL redirect from Twitch + * + * @param URLDetails URL config settings + * @param RedirectURL an URL knowns to start with the redirect URI + * @return login flow result populated with token or error + */ + FLoginFlowResult ParseRedirectResult(const FTwitchLoginURL& URLDetails, const FString& RedirectURL); + + /** + * Delegate fired when redirect URLs from the login flow are passed back for parsing + * We are looking for the success or error completion state from Twitch to grab the access token or complete the flow + * + * @param RedirectURL URL received from the login flow for parsing + * @return login flow result populated with token or error + */ + FLoginFlowResult OnLoginRedirectURL(const FString& RedirectURL); + + /** + * Called when login flow or console ShowWebURL completes + * + * @param Result final result of the login flow action + * @param ControllerIndex index of the local user initiating the request + * @param Delegate UI closed delegate to fire, completing the external UIs part in the login process + */ + void OnLoginUIComplete(const FLoginFlowResult& Result, int ControllerIndex, const FOnLoginUIClosedDelegate& Delegate); + + /** + * Delegate fired when the login flow is complete + * + * @param Result final result of the login flow action + * @param ControllerIndex index of the local user initiating the request + * @param Delegate UI closed delegate to fire, completing the external UIs part in the login process + */ + void OnExternalLoginFlowComplete(const FLoginFlowResult& Result, int ControllerIndex, const FOnLoginUIClosedDelegate Delegate); + + /** + * Delegate fired when the console's ShowWebURL completes + * + * @param FinalUrl the url that was used as the final redirect before closing + * @param ControllerIndex index of the local user initiating the request + * @param Delegate UI closed delegate to fire, completing the external UIs part in the login process + */ + void OnConsoleShowWebUrlComplete(const FString& FinalUrl, int ControllerIndex, const FOnLoginUIClosedDelegate Delegate); + + /** + * Delegate fired when the Twitch identity interface has completed login using the token retrieved from the login flow + * + * @param LocalUserNum index of the local user initiating the request + * @param bWasSuccessful was the login call successful + * @param UserId user id of the logged in user, or null if login failed + * @param Error error string if applicable + * @param Delegate UI closed delegate to fire, completing the external UIs part in the login process + */ + void OnAccessTokenLoginComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& UserId, const FString& Error, FOnLoginUIClosedDelegate Delegate); +}; + +typedef TSharedPtr FOnlineExternalUITwitchPtr; + diff --git a/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Private/OnlineIdentityTwitch.cpp b/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Private/OnlineIdentityTwitch.cpp new file mode 100644 index 000000000000..8be7bbe3c964 --- /dev/null +++ b/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Private/OnlineIdentityTwitch.cpp @@ -0,0 +1,521 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "OnlineSubsystemTwitchPrivate.h" +#include "OnlineIdentityTwitch.h" +#include "OnlineAccountTwitch.h" +#include "OnlineExternalUIInterface.h" +#include "Http.h" +#include "Misc/ConfigCacheIni.h" + +TSharedPtr FOnlineIdentityTwitch::GetUserAccountTwitch(const FUniqueNetId& UserId) const +{ + TSharedPtr Result; + + const TSharedRef* FoundUserAccount = UserAccounts.Find(UserId.ToString()); + if (FoundUserAccount != nullptr) + { + Result = *FoundUserAccount; + } + + return Result; +} + +TSharedPtr FOnlineIdentityTwitch::GetUserAccount(const FUniqueNetId& UserId) const +{ + return GetUserAccountTwitch(UserId); +} + +TArray > FOnlineIdentityTwitch::GetAllUserAccounts() const +{ + TArray > Result; + + for (const TPair >& It : UserAccounts) + { + Result.Add(It.Value); + } + + return Result; +} + +TSharedPtr FOnlineIdentityTwitch::GetUniquePlayerId(int32 LocalUserNum) const +{ + if (LocalUserNum >= 0 && LocalUserNum < MAX_LOCAL_PLAYERS) + { + const TSharedPtr* FoundId = UserIds.Find(LocalUserNum); + if (FoundId != nullptr) + { + return *FoundId; + } + } + return nullptr; +} + +TSharedPtr FOnlineIdentityTwitch::CreateUniquePlayerId(uint8* Bytes, int32 Size) +{ + if (Bytes != nullptr && Size > 0) + { + FString StrId(Size, (TCHAR*)Bytes); + return MakeShared(MoveTemp(StrId)); + } + return nullptr; +} + +TSharedPtr FOnlineIdentityTwitch::CreateUniquePlayerId(const FString& Str) +{ + return MakeShared(Str); +} + +bool FOnlineIdentityTwitch::Login(int32 LocalUserNum, const FOnlineAccountCredentials& AccountCredentials) +{ + FString ErrorStr; + + if (bHasLoginOutstanding) + { + ErrorStr = FString::Printf(TEXT("Login already pending for user")); + } + else if (!LoginURLDetails.IsValid()) + { + ErrorStr = FString::Printf(TEXT("OnlineSubsystemTwitch is improperly configured in DefaultEngine.ini LoginURL=%s LoginRedirectUrl=%s ClientId=%s"), + *LoginURLDetails.LoginUrl, *LoginURLDetails.LoginRedirectUrl, *LoginURLDetails.ClientId); + } + else if (LocalUserNum < 0 || LocalUserNum >= MAX_LOCAL_PLAYERS) + { + ErrorStr = FString::Printf(TEXT("Invalid LocalUserNum=%d"), LocalUserNum); + } + else + { + if (!AccountCredentials.Token.IsEmpty() && AccountCredentials.Type == GetAuthType()) + { + bHasLoginOutstanding = true; + + // Validate the provided auth token and get our current scope permissions + LoginWithAccessToken(LocalUserNum, AccountCredentials.Token, FOnLoginCompleteDelegate::CreateThreadSafeSP(this, &FOnlineIdentityTwitch::OnAccessTokenLoginComplete)); + } + else + { + IOnlineExternalUIPtr OnlineExternalUI = Subsystem->GetExternalUIInterface(); + if (OnlineExternalUI.IsValid()) + { + CurrentLoginNonce = LoginURLDetails.GenerateNonce(); + + bHasLoginOutstanding = true; + + FOnLoginUIClosedDelegate CompletionDelegate = FOnLoginUIClosedDelegate::CreateThreadSafeSP(this, &FOnlineIdentityTwitch::OnExternalUILoginComplete); + OnlineExternalUI->ShowLoginUI(LocalUserNum, true, true, CompletionDelegate); + } + else + { + ErrorStr = FString::Printf(TEXT("External interface missing")); + } + } + } + + if (!ErrorStr.IsEmpty()) + { + UE_LOG_ONLINE(Error, TEXT("Login for user %d failed: %s"), LocalUserNum, *ErrorStr); + + OnLoginAttemptComplete(LocalUserNum, ErrorStr); + return false; + } + return true; +} + +void FOnlineIdentityTwitch::LoginWithAccessToken(int32 LocalUserNum, const FString& AccessToken, const FOnLoginCompleteDelegate& InCompletionDelegate) +{ + // Validate the provided auth token and get our current scope permissions + const FOnlineAccountCredentials AccountCredentials(GetAuthType(), FString(), AccessToken); + ValidateAuthToken(LocalUserNum, AccountCredentials, FOnValidateAuthTokenComplete::CreateThreadSafeSP(this, &FOnlineIdentityTwitch::OnValidateAuthTokenComplete, InCompletionDelegate)); +} + +void FOnlineIdentityTwitch::OnValidateAuthTokenComplete(int32 LocalUserNum, const FOnlineAccountCredentials& AccountCredentials, TSharedPtr User, const FString& InErrorStr, const FOnLoginCompleteDelegate InCompletionDelegate) +{ + FString ErrorStr = InErrorStr; + + if (ErrorStr.IsEmpty()) + { + // Confirm the specified user ID matches the auth token + if (AccountCredentials.Id.IsEmpty() || + AccountCredentials.Id == User->GetUserId()->ToString()) + { + // Confirm we have all of the scope permissions we require + bool bHasAllPermissions = true; + FString MissingScopeFields; + for (const FString& ScopeField : LoginURLDetails.ScopeFields) + { + bool bHasPermission = User->GetScopePermissions().Contains(ScopeField); + if (!bHasPermission) + { + bHasAllPermissions = false; + if (!MissingScopeFields.IsEmpty()) + { + MissingScopeFields += TEXT(" "); + } + MissingScopeFields += ScopeField; + } + } + if (!MissingScopeFields.IsEmpty()) + { + UE_LOG_ONLINE(Log, TEXT("FOnlineIdentityTwitch::OnValidateAuthTokenComplete: User %d missing scope field(s) [%s]"), LocalUserNum, *MissingScopeFields); + ErrorStr = LOGIN_ERROR_MISSING_PERMISSIONS; + ErrorStr += TEXT(" "); + ErrorStr += MissingScopeFields; + } + } + else + { + ErrorStr = LOGIN_ERROR_TOKEN_NOT_FOR_USER; + } + } + + if (ErrorStr.IsEmpty()) + { + // update/add cached entry for user + UserAccounts.Add(User->GetUserId()->ToString(), User.ToSharedRef()); + // keep track of user ids for local users + UserIds.Add(LocalUserNum, User->GetUserId()); + } + else + { + UE_LOG_ONLINE(Log, TEXT("ValidateAuthToken for user %d failed: %s"), LocalUserNum, *ErrorStr); + } + + bool bWasSuccessful = ErrorStr.IsEmpty(); + InCompletionDelegate.ExecuteIfBound(LocalUserNum, bWasSuccessful, bWasSuccessful ? *User->GetUserId() : *ZeroId, ErrorStr); +} + +void FOnlineIdentityTwitch::ValidateAuthToken(int32 LocalUserNum, const FOnlineAccountCredentials& AccountCredentials, const FOnValidateAuthTokenComplete& InCompletionDelegate) +{ + // kick off http request to validate access token + TSharedRef HttpRequest = FHttpModule::Get().CreateRequest(); + + FString Url(LoginURLDetails.TokenValidateUrl); + + HttpRequest->OnProcessRequestComplete().BindThreadSafeSP(this, &FOnlineIdentityTwitch::ValidateAuthToken_HttpRequestComplete, LocalUserNum, AccountCredentials, InCompletionDelegate); + HttpRequest->SetURL(MoveTemp(Url)); + HttpRequest->SetHeader(TEXT("Accept"), Subsystem->GetTwitchApiVersion()); + HttpRequest->SetHeader(TEXT("Authorization"), FString::Printf(TEXT("OAuth %s"), *AccountCredentials.Token)); + HttpRequest->SetVerb(TEXT("GET")); + HttpRequest->ProcessRequest(); +} + +void FOnlineIdentityTwitch::ValidateAuthToken_HttpRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded, int32 LocalUserNum, const FOnlineAccountCredentials AccountCredentials, const FOnValidateAuthTokenComplete InCompletionDelegate) +{ + TSharedPtr User; + FString ResponseStr, ErrorStr; + + if (bSucceeded && + HttpResponse.IsValid()) + { + if (EHttpResponseCodes::IsOk(HttpResponse->GetResponseCode()) && + HttpResponse->GetContentType().StartsWith(TEXT("application/json"))) + { + ResponseStr = HttpResponse->GetContentAsString(); + UE_LOG_ONLINE(Verbose, TEXT("Request Current Permissions request complete for user %d. url=%s code=%d response=%s"), + LocalUserNum, *HttpRequest->GetURL(), HttpResponse->GetResponseCode(), *ResponseStr); + + User = MakeShared(); + if (!User->Parse(AccountCredentials.Token, ResponseStr)) + { + ErrorStr = FString::Printf(TEXT("Error parsing login. payload=%s"), + *ResponseStr); + } + } + else + { + ErrorStr = FString::Printf(TEXT("Invalid response. code=%d contentType=%s error=%s"), + HttpResponse->GetResponseCode(), *HttpResponse->GetContentType(), *ResponseStr); + } + } + else + { + ErrorStr = TEXT("No response"); + } + + InCompletionDelegate.ExecuteIfBound(LocalUserNum, AccountCredentials, User, ErrorStr); +} + +void FOnlineIdentityTwitch::OnAccessTokenLoginComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& UniqueId, const FString& Error) +{ + bHasLoginOutstanding = false; + CurrentLoginNonce.Empty(); + OnLoginAttemptComplete(LocalUserNum, Error); +} + +void FOnlineIdentityTwitch::OnLoginAttemptComplete(int32 LocalUserNum, const FString& ErrorStr) +{ + const FString ErrorStrCopy(ErrorStr); + if (GetLoginStatus(LocalUserNum) == ELoginStatus::LoggedIn) + { + UE_LOG_ONLINE(Log, TEXT("Twitch login for user %d was successful."), LocalUserNum); + TSharedPtr UserId = GetUniquePlayerId(LocalUserNum); + check(UserId.IsValid()); + + Subsystem->ExecuteNextTick([this, UserId, LocalUserNum, ErrorStrCopy]() + { + TriggerOnLoginCompleteDelegates(LocalUserNum, true, *UserId, ErrorStrCopy); + TriggerOnLoginStatusChangedDelegates(LocalUserNum, ELoginStatus::NotLoggedIn, ELoginStatus::LoggedIn, *UserId); + }); + } + else + { + UE_LOG_ONLINE(Warning, TEXT("Twitch login for user %d failed: %s"), LocalUserNum, *ErrorStr); + Subsystem->ExecuteNextTick([this, LocalUserNum, ErrorStrCopy]() + { + TriggerOnLoginCompleteDelegates(LocalUserNum, false, *ZeroId, ErrorStrCopy); + }); + } +} + +void FOnlineIdentityTwitch::OnExternalUILoginComplete(TSharedPtr UniqueId, const int ControllerIndex) +{ + FString ErrorStr; + bool bWasSuccessful = UniqueId.IsValid() && UniqueId->IsValid(); + OnAccessTokenLoginComplete(ControllerIndex, bWasSuccessful, bWasSuccessful ? *UniqueId : *ZeroId, ErrorStr); +} + +bool FOnlineIdentityTwitch::Logout(int32 LocalUserNum) +{ + bool bResult = false; + TSharedPtr UserId = GetUniquePlayerId(LocalUserNum); + if (UserId.IsValid()) + { + FString AuthToken = GetAuthToken(LocalUserNum); + if (bRevokeTokenOnLogout && !AuthToken.IsEmpty()) + { + RevokeAuthToken(LocalUserNum, AuthToken, FOnLogoutCompleteDelegate::CreateThreadSafeSP(this, &FOnlineIdentityTwitch::OnRevokeAuthTokenComplete)); + } + else + { + Subsystem->ExecuteNextTick([this, LocalUserNum]() + { + OnTwitchLogoutComplete(LocalUserNum); + }); + } + bResult = true; + } + else + { + UE_LOG_ONLINE(Warning, TEXT("No logged in user found for LocalUserNum=%d."), + LocalUserNum); + Subsystem->ExecuteNextTick([this, LocalUserNum]() { + TriggerOnLogoutCompleteDelegates(LocalUserNum, false); + }); + } + return bResult; +} + +void FOnlineIdentityTwitch::OnTwitchLogoutComplete(int32 LocalUserNum) +{ + UE_LOG_ONLINE(Log, TEXT("Twitch logout for user %d complete"), LocalUserNum); + TSharedPtr UserId = GetUniquePlayerId(LocalUserNum); + if (ensure(UserId.IsValid())) + { + // remove cached user account + UserAccounts.Remove(UserId->ToString()); + // remove cached user id + UserIds.Remove(LocalUserNum); + + TriggerOnLoginFlowLogoutDelegates(LoginDomains); + + Subsystem->ExecuteNextTick([this, UserId, LocalUserNum]() + { + TriggerOnLogoutCompleteDelegates(LocalUserNum, true); + TriggerOnLoginStatusChangedDelegates(LocalUserNum, ELoginStatus::LoggedIn, ELoginStatus::NotLoggedIn, *UserId); + }); + } +} + +void FOnlineIdentityTwitch::RevokeAuthToken(int32 LocalUserNum, const FString& AuthToken, const FOnLogoutCompleteDelegate& InCompletionDelegate) +{ + // kick off http request to validate access token + TSharedRef HttpRequest = FHttpModule::Get().CreateRequest(); + + FString Url(TokenRevokeUrl); + FString PostData(FString::Printf(TEXT("client_id=%s&token=%s"), *FGenericPlatformHttp::UrlEncode(LoginURLDetails.ClientId), *FGenericPlatformHttp::UrlEncode(AuthToken))); + + HttpRequest->OnProcessRequestComplete().BindThreadSafeSP(this, &FOnlineIdentityTwitch::RevokeAuthToken_HttpRequestComplete, LocalUserNum, InCompletionDelegate); + HttpRequest->SetURL(TokenRevokeUrl); + HttpRequest->SetHeader(TEXT("Accept"), Subsystem->GetTwitchApiVersion()); + HttpRequest->SetHeader(TEXT("Content-Type"), TEXT("application/x-www-form-urlencoded")); + HttpRequest->SetVerb(TEXT("POST")); + HttpRequest->SetContentAsString(PostData); + HttpRequest->ProcessRequest(); +} + +void FOnlineIdentityTwitch::RevokeAuthToken_HttpRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded, int32 LocalUserNum, const FOnLogoutCompleteDelegate InCompletionDelegate) +{ + bool bWasSuccessful = false; + + FString ResponseStr, ErrorStr; + + if (bSucceeded && + HttpResponse.IsValid()) + { + if (EHttpResponseCodes::IsOk(HttpResponse->GetResponseCode()) && + HttpResponse->GetContentType().StartsWith(TEXT("application/json"))) + { + bWasSuccessful = true; + ResponseStr = HttpResponse->GetContentAsString(); + UE_LOG_ONLINE(Verbose, TEXT("Revoke auth token request complete for user %d. url=%s code=%d response=%s"), + LocalUserNum, *HttpRequest->GetURL(), HttpResponse->GetResponseCode(), *ResponseStr); + } + else + { + ErrorStr = FString::Printf(TEXT("Invalid response. code=%d contentType=%s error=%s"), + HttpResponse->GetResponseCode(), *HttpResponse->GetContentType(), *ResponseStr); + } + } + else + { + ErrorStr = TEXT("No response"); + } + + InCompletionDelegate.ExecuteIfBound(LocalUserNum, bWasSuccessful); +} + +void FOnlineIdentityTwitch::OnRevokeAuthTokenComplete(int32 LocalUserNum, bool bWasSuccessful) +{ + if (bWasSuccessful) + { + UE_LOG_ONLINE(Log, TEXT("User %d successfully revoked their auth token"), LocalUserNum); + } + else + { + UE_LOG_ONLINE(Log, TEXT("User %d failed to revoke their auth token"), LocalUserNum); + } + OnTwitchLogoutComplete(LocalUserNum); +} + +bool FOnlineIdentityTwitch::AutoLogin(int32 LocalUserNum) +{ + return false; +} + +ELoginStatus::Type FOnlineIdentityTwitch::GetLoginStatus(int32 LocalUserNum) const +{ + TSharedPtr UserId = GetUniquePlayerId(LocalUserNum); + if (UserId.IsValid()) + { + return GetLoginStatus(*UserId); + } + return ELoginStatus::NotLoggedIn; +} + +ELoginStatus::Type FOnlineIdentityTwitch::GetLoginStatus(const FUniqueNetId& UserId) const +{ + TSharedPtr UserAccount = GetUserAccount(UserId); + if (UserAccount.IsValid() && + UserAccount->GetUserId()->IsValid() && + !UserAccount->GetAccessToken().IsEmpty()) + { + return ELoginStatus::LoggedIn; + } + return ELoginStatus::NotLoggedIn; +} + +FString FOnlineIdentityTwitch::GetPlayerNickname(int32 LocalUserNum) const +{ + TSharedPtr UserId = GetUniquePlayerId(LocalUserNum); + if (UserId.IsValid()) + { + return GetPlayerNickname(*UserId); + } + return TEXT("InvalidTwitchUser"); +} + +FString FOnlineIdentityTwitch::GetPlayerNickname(const FUniqueNetId& UserId) const +{ + // display name will be cached for users that registered or logged in manually + const TSharedRef* FoundUserAccount = UserAccounts.Find(UserId.ToString()); + if (FoundUserAccount != nullptr) + { + FString DisplayName = (*FoundUserAccount)->GetDisplayName(); + if (!DisplayName.IsEmpty()) + { + return DisplayName; + } + } + return TEXT("InvalidTwitchUser"); +} + +FString FOnlineIdentityTwitch::GetAuthToken(int32 LocalUserNum) const +{ + FString AuthToken; + + TSharedPtr UserId = GetUniquePlayerId(LocalUserNum); + if (UserId.IsValid()) + { + TSharedPtr FoundUserAccount = GetUserAccountTwitch(*UserId); + if (FoundUserAccount.IsValid()) + { + AuthToken = FoundUserAccount->GetAccessToken(); + } + } + + return AuthToken; +} + +FOnlineIdentityTwitch::FOnlineIdentityTwitch(class FOnlineSubsystemTwitch* InSubsystem) + : Subsystem(InSubsystem) + , bHasLoginOutstanding(false) + , bRevokeTokenOnLogout(false) + , ZeroId(MakeShared()) +{ + check(InSubsystem); + if (!GConfig->GetString(TEXT("OnlineSubsystemTwitch.OnlineIdentityTwitch"), TEXT("LoginUrl"), LoginURLDetails.LoginUrl, GEngineIni)) + { + UE_LOG_ONLINE(Warning, TEXT("Missing LoginUrl= in [OnlineSubsystemTwitch.OnlineIdentityTwitch] of DefaultEngine.ini")); + } + if (!GConfig->GetBool(TEXT("OnlineSubsystemTwitch.OnlineIdentityTwitch"), TEXT("bForceVerify"), LoginURLDetails.bForceVerify, GEngineIni)) + { + UE_LOG_ONLINE(Warning, TEXT("Missing bForceVerify= in [OnlineSubsystemTwitch.OnlineIdentityTwitch] of DefaultEngine.ini")); + } + if (!GConfig->GetString(TEXT("OnlineSubsystemTwitch.OnlineIdentityTwitch"), TEXT("LoginRedirectUrl"), LoginURLDetails.LoginRedirectUrl, GEngineIni)) + { + UE_LOG_ONLINE(Warning, TEXT("Missing LoginRedirectUrl= in [OnlineSubsystemTwitch.OnlineIdentityTwitch] of DefaultEngine.ini")); + } + if (!GConfig->GetString(TEXT("OnlineSubsystemTwitch.OnlineIdentityTwitch"), TEXT("TokenValidateUrl"), LoginURLDetails.TokenValidateUrl, GEngineIni)) + { + UE_LOG_ONLINE(Warning, TEXT("Missing TokenValidateUrl= in [OnlineSubsystemTwitch.OnlineIdentityTwitch] of DefaultEngine.ini")); + } + + LoginURLDetails.ClientId = Subsystem->GetAppId(); + + GConfig->GetArray(TEXT("OnlineSubsystemTwitch.OnlineIdentityTwitch"), TEXT("LoginDomains"), LoginDomains, GEngineIni); + + // Setup permission scope fields + GConfig->GetArray(TEXT("OnlineSubsystemTwitch.OnlineIdentityTwitch"), TEXT("ScopeFields"), LoginURLDetails.ScopeFields, GEngineIni); + + if (!GConfig->GetString(TEXT("OnlineSubsystemTwitch.OnlineIdentityTwitch"), TEXT("TokenRevokeUrl"), TokenRevokeUrl, GEngineIni)) + { + UE_LOG_ONLINE(Warning, TEXT("Missing TokenRevokeUrl= in [OnlineSubsystemTwitch.OnlineIdentityTwitch] of DefaultEngine.ini")); + } + if (!GConfig->GetBool(TEXT("OnlineSubsystemTwitch.OnlineIdentityTwitch"), TEXT("bRevokeTokenOnLogout"), bRevokeTokenOnLogout, GEngineIni)) + { + UE_LOG_ONLINE(Warning, TEXT("Missing bRevokeTokenOnLogout= in [OnlineSubsystemTwitch.OnlineIdentityTwitch] of DefaultEngine.ini")); + } +} + +FPlatformUserId FOnlineIdentityTwitch::GetPlatformUserIdFromUniqueNetId(const FUniqueNetId& UniqueNetId) +{ + for (int PlayerIdx = 0; PlayerIdx < MAX_LOCAL_PLAYERS; ++PlayerIdx) + { + TSharedPtr CurrentUniqueId = GetUniquePlayerId(PlayerIdx); + if (CurrentUniqueId.IsValid() && (*CurrentUniqueId == UniqueNetId)) + { + return PlayerIdx; + } + } + + return PLATFORMUSERID_NONE; +} + +void FOnlineIdentityTwitch::GetUserPrivilege(const FUniqueNetId& UserId, EUserPrivileges::Type Privilege, const FOnGetUserPrivilegeCompleteDelegate& Delegate) +{ + Delegate.ExecuteIfBound(UserId, Privilege, (uint32)EPrivilegeResults::NoFailures); +} + +FString FOnlineIdentityTwitch::GetAuthType() const +{ + return TEXT("twitch"); +} diff --git a/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Private/OnlineSubsystemModuleTwitch.cpp b/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Private/OnlineSubsystemModuleTwitch.cpp new file mode 100644 index 000000000000..9ef577fc0801 --- /dev/null +++ b/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Private/OnlineSubsystemModuleTwitch.cpp @@ -0,0 +1,65 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "OnlineSubsystemTwitchPrivate.h" + +IMPLEMENT_MODULE(FOnlineSubsystemTwitchModule, OnlineSubsystemTwitch); + +/** + * Class responsible for creating instance(s) of the subsystem + */ +class FOnlineFactoryTwitch : public IOnlineFactory +{ +public: + + FOnlineFactoryTwitch() = default; + virtual ~FOnlineFactoryTwitch() = default; + + virtual IOnlineSubsystemPtr CreateSubsystem(FName InstanceName) + { + if (FOnlineSubsystemTwitch::IsEnabled()) + { + FOnlineSubsystemTwitchPtr OnlineSub = MakeShared(InstanceName); + if (!OnlineSub->Init()) + { + UE_LOG_ONLINE(Warning, TEXT("Twitch API failed to initialize instance %s!"), *InstanceName.ToString()); + OnlineSub->Shutdown(); + OnlineSub = nullptr; + } + + return OnlineSub; + } + else + { + static bool bHasAlerted = false; + if (!bHasAlerted) + { + // Alert once with a warning for visibility (should be at the beginning) + UE_LOG_ONLINE(Log, TEXT("Twitch API disabled.")); + bHasAlerted = true; + } + } + + return nullptr; + } +}; + +void FOnlineSubsystemTwitchModule::StartupModule() +{ + UE_LOG_ONLINE(Log, TEXT("Twitch Startup!")); + + TwitchFactory = MakeUnique(); + + // Create and register our singleton factory with the main online subsystem for easy access + FOnlineSubsystemModule& OSS = FModuleManager::GetModuleChecked("OnlineSubsystem"); + OSS.RegisterPlatformService(TWITCH_SUBSYSTEM, TwitchFactory.Get()); +} + +void FOnlineSubsystemTwitchModule::ShutdownModule() +{ + UE_LOG_ONLINE(Log, TEXT("Twitch Shutdown!")); + + FOnlineSubsystemModule& OSS = FModuleManager::GetModuleChecked("OnlineSubsystem"); + OSS.UnregisterPlatformService(TWITCH_SUBSYSTEM); + + TwitchFactory.Reset(); +} diff --git a/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Private/OnlineSubsystemTwitch.cpp b/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Private/OnlineSubsystemTwitch.cpp new file mode 100644 index 000000000000..58f725f5e3a4 --- /dev/null +++ b/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Private/OnlineSubsystemTwitch.cpp @@ -0,0 +1,267 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "OnlineSubsystemTwitchPrivate.h" +#include "OnlineIdentityTwitch.h" +#include "OnlineExternalUITwitch.h" +#include "Engine/Console.h" +#include "Misc/ConfigCacheIni.h" + +IOnlineSessionPtr FOnlineSubsystemTwitch::GetSessionInterface() const +{ + return nullptr; +} + +IOnlineFriendsPtr FOnlineSubsystemTwitch::GetFriendsInterface() const +{ + return nullptr; +} + +IOnlinePartyPtr FOnlineSubsystemTwitch::GetPartyInterface() const +{ + return nullptr; +} + +IOnlineGroupsPtr FOnlineSubsystemTwitch::GetGroupsInterface() const +{ + return nullptr; +} + +IOnlineSharedCloudPtr FOnlineSubsystemTwitch::GetSharedCloudInterface() const +{ + return nullptr; +} + +IOnlineUserCloudPtr FOnlineSubsystemTwitch::GetUserCloudInterface() const +{ + return nullptr; +} + +IOnlineEntitlementsPtr FOnlineSubsystemTwitch::GetEntitlementsInterface() const +{ + return nullptr; +} + +IOnlineLeaderboardsPtr FOnlineSubsystemTwitch::GetLeaderboardsInterface() const +{ + return nullptr; +} + +IOnlineVoicePtr FOnlineSubsystemTwitch::GetVoiceInterface() const +{ + return nullptr; +} + +IOnlineExternalUIPtr FOnlineSubsystemTwitch::GetExternalUIInterface() const +{ + return TwitchExternalUIInterface; +} + +IOnlineTimePtr FOnlineSubsystemTwitch::GetTimeInterface() const +{ + return nullptr; +} + +IOnlineIdentityPtr FOnlineSubsystemTwitch::GetIdentityInterface() const +{ + return TwitchIdentity; +} + +IOnlineTitleFilePtr FOnlineSubsystemTwitch:: GetTitleFileInterface() const +{ + return nullptr; +} + +IOnlineStorePtr FOnlineSubsystemTwitch::GetStoreInterface() const +{ + return nullptr; +} + +IOnlineStoreV2Ptr FOnlineSubsystemTwitch::GetStoreV2Interface() const +{ + return nullptr; +} + +IOnlinePurchasePtr FOnlineSubsystemTwitch::GetPurchaseInterface() const +{ + return nullptr; +} + +IOnlineEventsPtr FOnlineSubsystemTwitch::GetEventsInterface() const +{ + return nullptr; +} + +IOnlineAchievementsPtr FOnlineSubsystemTwitch::GetAchievementsInterface() const +{ + return nullptr; +} + +IOnlineSharingPtr FOnlineSubsystemTwitch::GetSharingInterface() const +{ + return nullptr; +} + +IOnlineUserPtr FOnlineSubsystemTwitch::GetUserInterface() const +{ + return nullptr; +} + +IOnlineMessagePtr FOnlineSubsystemTwitch::GetMessageInterface() const +{ + return nullptr; +} + +IOnlinePresencePtr FOnlineSubsystemTwitch::GetPresenceInterface() const +{ + return nullptr; +} + +IOnlineChatPtr FOnlineSubsystemTwitch::GetChatInterface() const +{ + return nullptr; +} + +IOnlineTurnBasedPtr FOnlineSubsystemTwitch::GetTurnBasedInterface() const +{ + return nullptr; +} + +bool FOnlineSubsystemTwitch::Init() +{ + UE_LOG_ONLINE(Verbose, TEXT("FOnlineSubsystemTwitch::Init() Name: %s"), *InstanceName.ToString()); + + if (!GConfig->GetString(TEXT("OnlineSubsystemTwitch"), TEXT("ClientId"), ClientId, GEngineIni)) + { + UE_LOG(LogOnline, Warning, TEXT("Missing ClientId= in [OnlineSubsystemTwitch] of DefaultEngine.ini")); + } + + TwitchIdentity = MakeShared(this); + TwitchExternalUIInterface = MakeShared(this); + + return true; +} + +void FOnlineSubsystemTwitch::PreUnload() +{ + UE_LOG_ONLINE(Verbose, TEXT("FOnlineSubsystemTwitch::Preunload() Name: %s"), *InstanceName.ToString()); +} + +bool FOnlineSubsystemTwitch::Shutdown() +{ + UE_LOG_ONLINE(Verbose, TEXT("FOnlineSubsystemTwitch::Shutdown() Name: %s"), *InstanceName.ToString()); + + FOnlineSubsystemImpl::Shutdown(); + +#define DESTRUCT_INTERFACE(Interface) \ + if (Interface.IsValid()) \ + { \ + ensure(Interface.IsUnique()); \ + Interface = nullptr; \ + } + + DESTRUCT_INTERFACE(TwitchIdentity); + DESTRUCT_INTERFACE(TwitchExternalUIInterface); + +#undef DESTRUCT_INTERFACE + return true; +} + +FString FOnlineSubsystemTwitch::GetAppId() const +{ + return ClientId; +} + +bool FOnlineSubsystemTwitch::Exec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) +{ + if (FOnlineSubsystemImpl::Exec(InWorld, Cmd, Ar)) + { + return true; + } + + bool bWasHandled = false; + if (FParse::Command(&Cmd, TEXT("TEST"))) + { +#if WITH_DEV_AUTOMATION_TESTS + if (FParse::Command(&Cmd, TEXT("AUTH"))) + { + bWasHandled = HandleAuthExecCommands(InWorld, Cmd, Ar); + } +#endif // WITH_DEV_AUTOMATION_TESTS + } + + return bWasHandled; +} + +FText FOnlineSubsystemTwitch::GetOnlineServiceName() const +{ + return NSLOCTEXT("OnlineSubsystemTwitch", "OnlineServiceName", "Twitch"); +} + +bool FOnlineSubsystemTwitch::HandleAuthExecCommands(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) +{ + bool bWasHandled = false; + +#if WITH_DEV_AUTOMATION_TESTS + if (FParse::Command(&Cmd, TEXT("INFO"))) + { + FString AuthType = FParse::Token(Cmd, false); + bWasHandled = true; + } + else if (FParse::Command(&Cmd, TEXT("LOGIN"))) + { + FOnlineIdentityTwitchPtr Identity = GetTwitchIdentityService(); + bWasHandled = true; + + int32 LocalUserNum = 0; + FString Id = FParse::Token(Cmd, false); + FString Auth = FParse::Token(Cmd, false); + + static FDelegateHandle LoginCompleteDelegateHandle; + if (LoginCompleteDelegateHandle.IsValid()) + { + UE_LOG_ONLINE(Error, TEXT("Another login attempt is already in progress")); + } + auto Delegate = FOnLoginCompleteDelegate::CreateLambda([Identity, Id, Auth](int32 InLocalUserNum, bool bWasSuccessful, const FUniqueNetId& UserId, const FString& Error) { + ensure(LoginCompleteDelegateHandle.IsValid()); + if (bWasSuccessful) + { + UE_LOG_ONLINE(Display, TEXT("Twitch login completed successfully. UserId=%s"), *UserId.ToString()); + } + else + { + if (Error.StartsWith(LOGIN_ERROR_MISSING_PERMISSIONS)) + { + TArray MissingPermissions; + Error.ParseIntoArray(MissingPermissions, TEXT(" ")); + // First index will be LOGIN_ERROR_MISSING_PERMISSIONS, so skip + for (int32 MissingPermissionIndex = 1; MissingPermissionIndex < MissingPermissions.Num(); ++MissingPermissionIndex) + { + UE_LOG_ONLINE(Display, TEXT("Twitch log in failed: Missing permission %s"), *MissingPermissions[MissingPermissionIndex]); + } + } + } + Identity->ClearOnLoginCompleteDelegate_Handle(InLocalUserNum, LoginCompleteDelegateHandle); + LoginCompleteDelegateHandle.Reset(); + }); + LoginCompleteDelegateHandle = Identity->AddOnLoginCompleteDelegate_Handle(LocalUserNum, Delegate); + Identity->Login(LocalUserNum, FOnlineAccountCredentials(Identity->GetAuthType(), Id, Auth)); + } +#endif // WITH_DEV_AUTOMATION_TESTS + + return bWasHandled; +} + + +bool FOnlineSubsystemTwitch::IsEnabled() +{ + // Check the ini for disabling Twitch + bool bEnableTwitch = true; + GConfig->GetBool(TEXT("OnlineSubsystemTwitch"), TEXT("bEnabled"), bEnableTwitch, GEngineIni); + return bEnableTwitch; +} + +FOnlineSubsystemTwitch::FOnlineSubsystemTwitch(FName InInstanceName) + : FOnlineSubsystemImpl(TWITCH_SUBSYSTEM, InInstanceName) + , TwitchApiVersion(TEXT("application/vnd.twitchtv.v5+json")) +{ +} diff --git a/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Private/OnlineSubsystemTwitchPrivate.h b/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Private/OnlineSubsystemTwitchPrivate.h new file mode 100644 index 000000000000..08c6ebfeaa85 --- /dev/null +++ b/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Private/OnlineSubsystemTwitchPrivate.h @@ -0,0 +1,13 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "ModuleManager.h" + +#include "OnlineSubsystemTwitch.h" +#include "OnlineSubsystemTwitchModule.h" + +/** pre-pended to all Twitch logging */ +#undef ONLINE_LOG_PREFIX +#define ONLINE_LOG_PREFIX TEXT("TWITCH: ") diff --git a/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Public/OnlineAccountTwitch.h b/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Public/OnlineAccountTwitch.h new file mode 100644 index 000000000000..b47dc128fbab --- /dev/null +++ b/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Public/OnlineAccountTwitch.h @@ -0,0 +1,103 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "OnlineSubsystemTypes.h" +#include "JsonSerializerMacros.h" +#include "OnlineSubsystemTwitchPackage.h" + +/** + * Info associated with an user account generated by this online service + */ +class ONLINESUBSYSTEMTWITCH_API FUserOnlineAccountTwitch : + public FUserOnlineAccount +{ +public: + + // FOnlineUser + + virtual TSharedRef GetUserId() const override; + virtual FString GetRealName() const override; + virtual FString GetDisplayName(const FString& Platform = FString()) const override; + virtual bool GetUserAttribute(const FString& AttrName, FString& OutAttrValue) const override; + virtual bool SetUserAttribute(const FString& AttrName, const FString& AttrValue) override; + + // FUserOnlineAccount + + virtual FString GetAccessToken() const override; + virtual bool GetAuthAttribute(const FString& AttrName, FString& OutAttrValue) const override; + + // FUserOnlineAccountTwitch + FUserOnlineAccountTwitch(const FString& InUserId = FString(), const FString& InAuthTicket = FString()) + : UserId(MakeShared(InUserId)) + , AuthTicket(InAuthTicket) + { + } + + virtual ~FUserOnlineAccountTwitch() = default; + + /** + * Parse Json profile request data into the user account + * + * @param InAuthTicket previously associated auth ticket with this Json response + * @param JsonStr a json payload from a /me request + * @return whether the parsing was successful or not + */ + bool Parse(const FString& InAuthTicket, const FString& JsonStr); + + /** @return Array of scope permissions we have to this account */ + const TArray& GetScopePermissions() const { return ScopePermissions; } + +protected: + + /** + * Get account data attribute + * + * @param Key account data entry key + * @param OutVal [out] value that was found + * + * @return true if entry was found + */ + inline bool GetAccountData(const FString& Key, FString& OutVal) const + { + const FString* FoundVal = AccountData.Find(Key); + if (FoundVal != nullptr) + { + OutVal = *FoundVal; + return true; + } + return false; + } + + /** + * Set account data attribute + * + * @param Key account data entry key + * @param Val value that we want to set + * + * @return true if entry changed + */ + inline bool SetAccountData(const FString& Key, const FString& Val) + { + const FString* FoundVal = AccountData.Find(Key); + if (FoundVal == nullptr || *FoundVal != Val) + { + AccountData.Add(Key, Val); + return true; + } + return false; + } + + /** Any addition account data associated with the user */ + FJsonSerializableKeyValueMap AccountData; + + /** User Id represented as a FUniqueNetId */ + TSharedRef UserId; + /** Ticket which is provided to user once authenticated by the online service */ + FString AuthTicket; + /** Scope permissions the user has authorized us for */ + TArray ScopePermissions; +}; + +/** Mapping from user id to account info and associated auth */ +typedef TMap > FUserOnlineAccountTwitchMap; diff --git a/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Public/OnlineIdentityTwitch.h b/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Public/OnlineIdentityTwitch.h new file mode 100644 index 000000000000..8445017b3b82 --- /dev/null +++ b/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Public/OnlineIdentityTwitch.h @@ -0,0 +1,240 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "OnlineIdentityInterface.h" +#include "OnlineSubsystemTwitchPackage.h" +#include "Http.h" +#include "Guid.h" + +typedef TSharedPtr FHttpRequestPtr; +typedef TSharedPtr FHttpResponsePtr; +class FUserOnlineAccountTwitch; +class FOnlineSubsystemTwitch; +typedef TMap > FUserOnlineAccountTwitchMap; + +/** This string will be followed by space separated permissions that are missing, so use FString.StartsWith to check for this error */ +#define LOGIN_ERROR_MISSING_PERMISSIONS TEXT("errors.com.epicgames.oss.twitch.identity.missing_permissions") +/** The specified user doesn't match the specified auth token */ +#define LOGIN_ERROR_TOKEN_NOT_FOR_USER TEXT("errors.com.epicgames.oss.twitch.identity.token_not_for_user") + +/** + * Contains URL details for Twitch interaction + */ +struct FTwitchLoginURL +{ + FTwitchLoginURL() + : bForceVerify(false) + { + } + + /** The endpoint at Twitch we are supposed to hit for auth */ + FString LoginUrl; + /** Whether or not we should always prompt the user for authorization */ + bool bForceVerify; + /** The redirect url for Twitch to redirect to upon completion. */ + FString LoginRedirectUrl; + /** The url to validate a OAuth token with Twitch */ + FString TokenValidateUrl; + /** The client id given to us by Twitch */ + FString ClientId; + /** Config based list of permission scopes to use when logging in */ + TArray ScopeFields; + + /** + * @return whether this is properly configured or not + */ + bool IsValid() const + { + return !LoginUrl.IsEmpty() && !LoginRedirectUrl.IsEmpty() && !ClientId.IsEmpty(); + } + + /** + * @return a random nonce + */ + static FString GenerateNonce() + { + // random guid to represent client generated state for verification on login + return FGuid::NewGuid().ToString(); + } + + /** + * @return the auth url to spawn in the browser + */ + FString GetURL(const FString& Nonce) const + { + FString Scopes = FString::Join(ScopeFields, TEXT(" ")); + + return FString::Printf(TEXT("%s?force_verify=%s&response_type=token&client_id=%s&scope=%s&state=%s&redirect_uri=%s"), + *LoginUrl, + bForceVerify ? TEXT("true") : TEXT("false"), + *FGenericPlatformHttp::UrlEncode(ClientId), + *FGenericPlatformHttp::UrlEncode(Scopes), + *FGenericPlatformHttp::UrlEncode(Nonce), + *FGenericPlatformHttp::UrlEncode(LoginRedirectUrl)); + } +}; + +/** + * Twitch service implementation of the online identity interface + */ +class ONLINESUBSYSTEMTWITCH_API FOnlineIdentityTwitch : + public IOnlineIdentity, + public TSharedFromThis +{ +public: + + // IOnlineIdentity + + virtual bool Login(int32 LocalUserNum, const FOnlineAccountCredentials& AccountCredentials) override; + virtual bool Logout(int32 LocalUserNum) override; + virtual bool AutoLogin(int32 LocalUserNum) override; + virtual TSharedPtr GetUserAccount(const FUniqueNetId& UserId) const override; + virtual TArray > GetAllUserAccounts() const override; + virtual TSharedPtr GetUniquePlayerId(int32 LocalUserNum) const override; + virtual TSharedPtr CreateUniquePlayerId(uint8* Bytes, int32 Size) override; + virtual TSharedPtr CreateUniquePlayerId(const FString& Str) override; + virtual ELoginStatus::Type GetLoginStatus(int32 LocalUserNum) const override; + virtual ELoginStatus::Type GetLoginStatus(const FUniqueNetId& UserId) const override; + virtual FString GetPlayerNickname(int32 LocalUserNum) const override; + virtual FString GetPlayerNickname(const FUniqueNetId& UserId) const override; + virtual FString GetAuthToken(int32 LocalUserNum) const override; + virtual void GetUserPrivilege(const FUniqueNetId& UserId, EUserPrivileges::Type Privilege, const FOnGetUserPrivilegeCompleteDelegate& Delegate) override; + virtual FPlatformUserId GetPlatformUserIdFromUniqueNetId(const FUniqueNetId& UniqueNetId) override; + virtual FString GetAuthType() const override; + +PACKAGE_SCOPE: + + // FOnlineIdentityTwitch + + /** + * Constructor + * + * @param InSubsystem Twitch subsystem being used + */ + FOnlineIdentityTwitch(FOnlineSubsystemTwitch* InSubsystem); + + /** Default constructor unavailable */ + FOnlineIdentityTwitch() = delete; + + /** + * Destructor + */ + virtual ~FOnlineIdentityTwitch() = default; + + /** @return the Twitch user account for the specified user id */ + TSharedPtr GetUserAccountTwitch(const FUniqueNetId& UserId) const; + + /** @return the login configuration details */ + const FTwitchLoginURL& GetLoginURLDetails() const { return LoginURLDetails; } + + /** @return the current login attempt's nonce */ + const FString& GetCurrentLoginNonce() const { return CurrentLoginNonce; } + +PACKAGE_SCOPE: + + /** + * Login with an existing access token + * + * @param LocalUserNum id of the local user initiating the request + * @param AccessToken access token already received from Twitch + * @param InCompletionDelegate delegate to fire when operation completes + */ + void LoginWithAccessToken(int32 LocalUserNum, const FString& AccessToken, const FOnLoginCompleteDelegate& InCompletionDelegate); + +private: + /** + * Delegate fired after a Twitch token has been validated + * + * @param LocalUserNum the controller number of the associated user + * @param AccountCredentials user account credentials needed to sign in to the online service + * @param OnlineAccount online account if successfully parsed + * @param ErrorStr error associated with the request + */ + DECLARE_DELEGATE_FourParams(FOnValidateAuthTokenComplete, int32 /*LocalUserNum*/, const FOnlineAccountCredentials& /*AccountCredentials*/, TSharedPtr /*User*/, const FString& /*ErrorStr*/); + + /** + * Validate a Twitch auth token + * + * @param LocalUserNum the controller number of the associated user + * @param AccountCredentials user account credentials needed to sign in to the online service + * @param InCompletionDelegate delegate to fire when operation completes + */ + void ValidateAuthToken(int32 LocalUserNum, const FOnlineAccountCredentials& AccountCredentials, const FOnValidateAuthTokenComplete& InCompletionDelegate); + + /** + * Delegate fired when the http request from ValidateAuthToken completes + */ + void ValidateAuthToken_HttpRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded, int32 LocalUserNum, const FOnlineAccountCredentials AccountCredentials, const FOnValidateAuthTokenComplete InCompletionDelegate); + + /** + * Delegate fired when the call to ValidateAuthToken completes + */ + void OnValidateAuthTokenComplete(int32 LocalUserNum, const FOnlineAccountCredentials& AccountCredentials, TSharedPtr User, const FString& ErrorStr, const FOnLoginCompleteDelegate InCompletionDelegate); + + /** + * Delegate fired when the internal call to Login with AccessToken is specified + */ + void OnAccessTokenLoginComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& UserId, const FString& Error); + + /** + * Function called when call to Login completes + */ + void OnLoginAttemptComplete(int32 LocalUserNum, const FString& ErrorStr); + + /** + * Delegate fired when the call to ShowLoginUI completes + */ + void OnExternalUILoginComplete(TSharedPtr UniqueId, const int ControllerIndex); + + /** + * Function called after logging out has completed, including the optional revoke token step + * @param LocalUserNum id of the local user initiating the request + * @param bWasSuccessful true if we successfully logged out of Twitch + */ + void OnTwitchLogoutComplete(int32 LocalUserNum); + + /** + * Revokes the auth token associated with an account + * @param LocalUserNum id of the local user initiating the request + * @param AuthToken auth token for the user that needs to be revoked + * @param InCompletionDelegate delegate to fire when operation completes + */ + void RevokeAuthToken(int32 LocalUserNum, const FString& AuthToken, const FOnLogoutCompleteDelegate& InCompletionDelegate); + + /** + * Delegate fired when the http request from RevokeAuthToken completes + */ + void RevokeAuthToken_HttpRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded, int32 LocalUserNum, const FOnLogoutCompleteDelegate InCompletionDelegate); + + /** + * Delegate fired when the call to RevokeAuthToken completes + */ + void OnRevokeAuthTokenComplete(int32 LocalUserNum, bool bWasSuccessful); + + /** Users that have been registered */ + FUserOnlineAccountTwitchMap UserAccounts; + /** Ids mapped to locally registered users */ + TMap > UserIds; + + /** Reference to the main subsystem */ + FOnlineSubsystemTwitch* Subsystem; + + /** Const details about communicating with twitch API */ + FTwitchLoginURL LoginURLDetails; + /** Domains used for login, for cookie management */ + TArray LoginDomains; + /** Nonce for current login attempt */ + FString CurrentLoginNonce; + /** Whether we have a registration in flight or not */ + bool bHasLoginOutstanding; + /** URL used to revoke an access token */ + FString TokenRevokeUrl; + /** Whether we want to revoke the access token on logout or not */ + bool bRevokeTokenOnLogout; + + /** Re-usable empty unique id for errors */ + TSharedRef ZeroId; +}; + +typedef TSharedPtr FOnlineIdentityTwitchPtr; diff --git a/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Public/OnlineSubsystemTwitch.h b/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Public/OnlineSubsystemTwitch.h new file mode 100644 index 000000000000..9fe362937405 --- /dev/null +++ b/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Public/OnlineSubsystemTwitch.h @@ -0,0 +1,112 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "OnlineSubsystem.h" +#include "OnlineSubsystemImpl.h" +#include "OnlineSubsystemTwitchModule.h" +#include "OnlineSubsystemTwitchPackage.h" + +/** Forward declarations of all interface classes */ +typedef TSharedPtr FOnlineIdentityTwitchPtr; +typedef TSharedPtr FOnlineExternalUITwitchPtr; + +class FOnlineAsyncTaskManagerTwitch; +class FRunnableThread; + +/** + * Twitch backend services + */ +class ONLINESUBSYSTEMTWITCH_API FOnlineSubsystemTwitch : + public FOnlineSubsystemImpl +{ +public: + + // IOnlineSubsystem + + virtual IOnlineSessionPtr GetSessionInterface() const override; + virtual IOnlineFriendsPtr GetFriendsInterface() const override; + virtual IOnlinePartyPtr GetPartyInterface() const override; + virtual IOnlineGroupsPtr GetGroupsInterface() const override; + virtual IOnlineSharedCloudPtr GetSharedCloudInterface() const override; + virtual IOnlineUserCloudPtr GetUserCloudInterface() const override; + virtual IOnlineEntitlementsPtr GetEntitlementsInterface() const override; + virtual IOnlineLeaderboardsPtr GetLeaderboardsInterface() const override; + virtual IOnlineVoicePtr GetVoiceInterface() const override; + virtual IOnlineExternalUIPtr GetExternalUIInterface() const override; + virtual IOnlineTimePtr GetTimeInterface() const override; + virtual IOnlineIdentityPtr GetIdentityInterface() const override; + virtual IOnlineTitleFilePtr GetTitleFileInterface() const override; + virtual IOnlineStorePtr GetStoreInterface() const override; + virtual IOnlineStoreV2Ptr GetStoreV2Interface() const override; + virtual IOnlinePurchasePtr GetPurchaseInterface() const override; + virtual IOnlineEventsPtr GetEventsInterface() const override; + virtual IOnlineAchievementsPtr GetAchievementsInterface() const override; + virtual IOnlineSharingPtr GetSharingInterface() const override; + virtual IOnlineUserPtr GetUserInterface() const override; + virtual IOnlineMessagePtr GetMessageInterface() const override; + virtual IOnlinePresencePtr GetPresenceInterface() const override; + virtual IOnlineChatPtr GetChatInterface() const override; + virtual IOnlineTurnBasedPtr GetTurnBasedInterface() const override; + virtual bool Init() override; + virtual void PreUnload() override; + virtual bool Shutdown() override; + virtual FString GetAppId() const override; + virtual bool Exec(class UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) override; + virtual FText GetOnlineServiceName() const override; + + // FOnlineSubsystemTwitch + + /** + * Destructor + */ + virtual ~FOnlineSubsystemTwitch() = default; + + /** + * Is Twitch available for use + * + * @return true if Twitch functionality is available, false otherwise + */ + static bool IsEnabled(); + + /** + * Get the twitch login service configuration + * + * @return login service instance associated with the subsystem + */ + inline FOnlineIdentityTwitchPtr GetTwitchIdentityService() const + { + return TwitchIdentity; + } + + +PACKAGE_SCOPE: + + /** Only the factory makes instances */ + FOnlineSubsystemTwitch(FName InInstanceName); + + /** Default constructor unavailable */ + FOnlineSubsystemTwitch() = delete; + + /** @return Twich API version */ + const FString& GetTwitchApiVersion() const { return TwitchApiVersion; } + +private: + + bool HandleAuthExecCommands(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar); + + /** Interface to the identity registration/auth services */ + FOnlineIdentityTwitchPtr TwitchIdentity; + + /** Interface for external UI services on Twitch */ + FOnlineExternalUITwitchPtr TwitchExternalUIInterface; + + /** The client id given to us by Twitch */ + FString ClientId; + + /** Twitch API version */ + FString TwitchApiVersion; +}; + +typedef TSharedPtr FOnlineSubsystemTwitchPtr; + diff --git a/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Public/OnlineSubsystemTwitchModule.h b/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Public/OnlineSubsystemTwitchModule.h new file mode 100644 index 000000000000..68a1267bdff6 --- /dev/null +++ b/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Public/OnlineSubsystemTwitchModule.h @@ -0,0 +1,61 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "ModuleInterface.h" +#include "ModuleManager.h" + +/** + * Module used for talking with an Twitch service via Http requests + */ +class FOnlineSubsystemTwitchModule : public IModuleInterface +{ +private: + + /** Class responsible for creating instance(s) of the subsystem */ + TUniquePtr TwitchFactory; + +public: + + /** + * Constructor + */ + FOnlineSubsystemTwitchModule() = default; + + /** + * Destructor + */ + virtual ~FOnlineSubsystemTwitchModule() = default; + + // IModuleInterface + + /** + * Called right after the module DLL has been loaded and the module object has been created + */ + virtual void StartupModule() override; + + /** + * Called before the module is unloaded, right before the module object is destroyed. + */ + virtual void ShutdownModule() override; + + /** + * Override this to set whether your module is allowed to be unloaded on the fly + * + * @return Whether the module supports shutdown separate from the rest of the engine. + */ + virtual bool SupportsDynamicReloading() override + { + return false; + } + + /** + * Override this to set whether your module would like cleanup on application shutdown + * + * @return Whether the module supports shutdown on application exit + */ + virtual bool SupportsAutomaticShutdown() override + { + return false; + } +}; diff --git a/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Public/OnlineSubsystemTwitchPackage.h b/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Public/OnlineSubsystemTwitchPackage.h new file mode 100644 index 000000000000..34eea227c9de --- /dev/null +++ b/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Public/OnlineSubsystemTwitchPackage.h @@ -0,0 +1,13 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +// Can't be #pragma once because other modules may define PACKAGE_SCOPE + +// Intended to be the last include in an exported class definition +// Properly defines some members as "public to the module" vs "private to the consumer/user" + +#undef PACKAGE_SCOPE +#ifdef ONLINESUBSYSTEM_TWITCH_PACKAGE +#define PACKAGE_SCOPE public +#else +#define PACKAGE_SCOPE protected +#endif diff --git a/Engine/Plugins/Online/OnlineSubsystemUtils/OnlineSubsystemUtils.uplugin b/Engine/Plugins/Online/OnlineSubsystemUtils/OnlineSubsystemUtils.uplugin index c6d2be9c6ec2..73523eb93f9d 100644 --- a/Engine/Plugins/Online/OnlineSubsystemUtils/OnlineSubsystemUtils.uplugin +++ b/Engine/Plugins/Online/OnlineSubsystemUtils/OnlineSubsystemUtils.uplugin @@ -23,9 +23,15 @@ } ], "LocalizationTargets": [ - { - "Name": "OnlineSubsystemUtils", - "LoadingPolicy": "Always" - } - ] + { + "Name": "OnlineSubsystemUtils", + "LoadingPolicy": "Always" + } + ], + "Plugins": [ + { + "Name": "OnlineSubsystem", + "Enabled": true + } + ] } \ No newline at end of file diff --git a/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineBlueprintSupport/OnlineBlueprintSupport.Build.cs b/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineBlueprintSupport/OnlineBlueprintSupport.Build.cs index d4672a0c677c..60e98731275e 100644 --- a/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineBlueprintSupport/OnlineBlueprintSupport.Build.cs +++ b/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineBlueprintSupport/OnlineBlueprintSupport.Build.cs @@ -5,7 +5,7 @@ using UnrealBuildTool; public class OnlineBlueprintSupport : ModuleRules { public OnlineBlueprintSupport(ReadOnlyTargetRules Target) : base(Target) - { + { PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; PrivateDependencyModuleNames.AddRange( diff --git a/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/OnlineSubsystemUtils.Build.cs b/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/OnlineSubsystemUtils.Build.cs index a83f0533c305..5faff6d60e04 100644 --- a/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/OnlineSubsystemUtils.Build.cs +++ b/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/OnlineSubsystemUtils.Build.cs @@ -5,7 +5,7 @@ using UnrealBuildTool; public class OnlineSubsystemUtils : ModuleRules { public OnlineSubsystemUtils(ReadOnlyTargetRules Target) : base(Target) - { + { Definitions.Add("ONLINESUBSYSTEMUTILS_PACKAGE=1"); PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; diff --git a/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Private/OnlineBeacon.cpp b/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Private/OnlineBeacon.cpp index d5a5554fd432..f7a0d5de7252 100644 --- a/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Private/OnlineBeacon.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Private/OnlineBeacon.cpp @@ -13,6 +13,7 @@ AOnlineBeacon::AOnlineBeacon(const FObjectInitializer& ObjectInitializer) : BeaconState(EBeaconState::DenyRequests) { NetDriverName = FName(TEXT("BeaconDriver")); + bRelevantForNetworkReplays = false; } bool AOnlineBeacon::InitBase() diff --git a/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Private/OnlineBeaconClient.cpp b/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Private/OnlineBeaconClient.cpp index 4e55d7d77f15..147db6a4cbbb 100644 --- a/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Private/OnlineBeaconClient.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Private/OnlineBeaconClient.cpp @@ -141,6 +141,9 @@ void AOnlineBeaconClient::OnFailure() Super::OnFailure(); } + +/// @cond DOXYGEN_WARNINGS + void AOnlineBeaconClient::ClientOnConnected_Implementation() { SetConnectionState(EBeaconConnectionState::Open); @@ -157,6 +160,8 @@ void AOnlineBeaconClient::ClientOnConnected_Implementation() OnConnected(); } +/// @endcond + bool AOnlineBeaconClient::UseShortConnectTimeout() const { return ConnectionState == EBeaconConnectionState::Open; diff --git a/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Private/OnlineEngineInterfaceImpl.cpp b/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Private/OnlineEngineInterfaceImpl.cpp index b4c0920e48d7..3883a5ba9c22 100644 --- a/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Private/OnlineEngineInterfaceImpl.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Private/OnlineEngineInterfaceImpl.cpp @@ -4,10 +4,19 @@ #include "OnlineSubsystem.h" #include "Interfaces/OnlineIdentityInterface.h" #include "OnlineSubsystemUtils.h" +#include "Misc/ConfigCacheIni.h" +#include "Engine/NetConnection.h" UOnlineEngineInterfaceImpl::UOnlineEngineInterfaceImpl(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) + , VoiceSubsystemNameOverride(NAME_None) + , DefaultSubsystemName(NAME_None) { + FString DefaultSubsystemNameString; + if (GConfig->GetString(TEXT("OnlineSubsystem"), TEXT("DefaultPlatformService"), DefaultSubsystemNameString, GEngineIni)) + { + DefaultSubsystemName = FName(*DefaultSubsystemNameString); + } } bool UOnlineEngineInterfaceImpl::IsLoaded(FName OnlineIdentifier) @@ -55,6 +64,37 @@ void UOnlineEngineInterfaceImpl::DestroyOnlineSubsystem(FName OnlineIdentifier) IOnlineSubsystem::Destroy(OnlineIdentifier); } +#if OSS_DEDICATED_SERVER_VOICECHAT +FName UOnlineEngineInterfaceImpl::GetDefaultOnlineSubsystemName() const +{ + return DefaultSubsystemName; +} +#endif + +FName UOnlineEngineInterfaceImpl::GetDedicatedServerSubsystemNameForSubsystem(const FName Subsystem) const +{ + // For console platforms with their own online subsystem, there may be a separate + // online system that can run on dedicated servers, since the console one typically + // won't compile/run on dedicated server platforms. The console and server OSSs should + // maintain compatibility with serialized data, such as voice packets, so that the server + // OSS can properly forward them to other clients using the console OSS. + + // Clients may send their platform subsystem name via the "OnlinePlatform=" login URL option, + // then the server can pass the value of that option to this function to get the name of + // the corresponding server OSS for that client, if one exists. + + if (Subsystem == LIVE_SUBSYSTEM) + { + return LIVESERVER_SUBSYSTEM; + } + else if (Subsystem == PS4_SUBSYSTEM) + { + return PS4SERVER_SUBSYSTEM; + } + + return NAME_None; +} + TSharedPtr UOnlineEngineInterfaceImpl::CreateUniquePlayerId(const FString& Str) { IOnlineIdentityPtr IdentityInt = Online::GetIdentityInterface(); @@ -304,7 +344,7 @@ bool UOnlineEngineInterfaceImpl::GetResolvedConnectString(UWorld* World, FName S TSharedPtr UOnlineEngineInterfaceImpl::GetLocalPacket(UWorld* World, uint8 LocalUserNum) { - IOnlineVoicePtr VoiceInt = Online::GetVoiceInterface(World); + IOnlineVoicePtr VoiceInt = Online::GetVoiceInterface(World, VoiceSubsystemNameOverride); if (VoiceInt.IsValid()) { TSharedPtr LocalPacket = VoiceInt->GetLocalPacket(LocalUserNum); @@ -314,19 +354,37 @@ TSharedPtr UOnlineEngineInterfaceImpl::GetLocalPacket(UWorld* Worl return nullptr; } -TSharedPtr UOnlineEngineInterfaceImpl::SerializeRemotePacket(UWorld* World, FArchive& Ar) +#if OSS_DEDICATED_SERVER_VOICECHAT +TSharedPtr UOnlineEngineInterfaceImpl::SerializeRemotePacket(UWorld* World, const UNetConnection* const RemoteConnection, FArchive& Ar) { - IOnlineVoicePtr VoiceInt = Online::GetVoiceInterface(World); + FName VoiceSubsystemName = VoiceSubsystemNameOverride; + if (RemoteConnection && RemoteConnection->Driver && RemoteConnection->Driver->GetNetMode() == NM_DedicatedServer) + { + VoiceSubsystemName = GetDedicatedServerSubsystemNameForSubsystem(RemoteConnection->GetPlayerOnlinePlatformName()); + } + + IOnlineVoicePtr VoiceInt = Online::GetVoiceInterface(World, VoiceSubsystemName); if (VoiceInt.IsValid()) { return VoiceInt->SerializeRemotePacket(Ar); } return nullptr; } +#else +TSharedPtr UOnlineEngineInterfaceImpl::SerializeRemotePacket(UWorld* World, FArchive& Ar) +{ + IOnlineVoicePtr VoiceInt = Online::GetVoiceInterface(World, VoiceSubsystemNameOverride); + if (VoiceInt.IsValid()) + { + return VoiceInt->SerializeRemotePacket(Ar); + } + return nullptr; +} +#endif void UOnlineEngineInterfaceImpl::StartNetworkedVoice(UWorld* World, uint8 LocalUserNum) { - IOnlineVoicePtr VoiceInt = Online::GetVoiceInterface(World); + IOnlineVoicePtr VoiceInt = Online::GetVoiceInterface(World, VoiceSubsystemNameOverride); if (VoiceInt.IsValid()) { VoiceInt->StartNetworkedVoice(LocalUserNum); @@ -335,7 +393,7 @@ void UOnlineEngineInterfaceImpl::StartNetworkedVoice(UWorld* World, uint8 LocalU void UOnlineEngineInterfaceImpl::StopNetworkedVoice(UWorld* World, uint8 LocalUserNum) { - IOnlineVoicePtr VoiceInt = Online::GetVoiceInterface(World); + IOnlineVoicePtr VoiceInt = Online::GetVoiceInterface(World, VoiceSubsystemNameOverride); if (VoiceInt.IsValid()) { VoiceInt->StopNetworkedVoice(LocalUserNum); @@ -344,7 +402,7 @@ void UOnlineEngineInterfaceImpl::StopNetworkedVoice(UWorld* World, uint8 LocalUs void UOnlineEngineInterfaceImpl::ClearVoicePackets(UWorld* World) { - IOnlineVoicePtr VoiceInt = Online::GetVoiceInterface(World); + IOnlineVoicePtr VoiceInt = Online::GetVoiceInterface(World, VoiceSubsystemNameOverride); if (VoiceInt.IsValid()) { VoiceInt->ClearVoicePackets(); @@ -353,7 +411,7 @@ void UOnlineEngineInterfaceImpl::ClearVoicePackets(UWorld* World) bool UOnlineEngineInterfaceImpl::MuteRemoteTalker(UWorld* World, uint8 LocalUserNum, const FUniqueNetId& PlayerId, bool bIsSystemWide) { - IOnlineVoicePtr VoiceInt = Online::GetVoiceInterface(World); + IOnlineVoicePtr VoiceInt = Online::GetVoiceInterface(World, VoiceSubsystemNameOverride); if (VoiceInt.IsValid()) { return VoiceInt->MuteRemoteTalker(LocalUserNum, PlayerId, bIsSystemWide); @@ -363,7 +421,7 @@ bool UOnlineEngineInterfaceImpl::MuteRemoteTalker(UWorld* World, uint8 LocalUser bool UOnlineEngineInterfaceImpl::UnmuteRemoteTalker(UWorld* World, uint8 LocalUserNum, const FUniqueNetId& PlayerId, bool bIsSystemWide) { - IOnlineVoicePtr VoiceInt = Online::GetVoiceInterface(World); + IOnlineVoicePtr VoiceInt = Online::GetVoiceInterface(World, VoiceSubsystemNameOverride); if (VoiceInt.IsValid()) { return VoiceInt->UnmuteRemoteTalker(LocalUserNum, PlayerId, bIsSystemWide); @@ -373,7 +431,7 @@ bool UOnlineEngineInterfaceImpl::UnmuteRemoteTalker(UWorld* World, uint8 LocalUs int32 UOnlineEngineInterfaceImpl::GetNumLocalTalkers(UWorld* World) { - IOnlineVoicePtr VoiceInt = Online::GetVoiceInterface(World); + IOnlineVoicePtr VoiceInt = Online::GetVoiceInterface(World, VoiceSubsystemNameOverride); if (VoiceInt.IsValid()) { return VoiceInt->GetNumLocalTalkers(); diff --git a/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Private/OnlineEngineInterfaceImpl.h b/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Private/OnlineEngineInterfaceImpl.h index 5513912ec028..99e717e3ff43 100644 --- a/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Private/OnlineEngineInterfaceImpl.h +++ b/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Private/OnlineEngineInterfaceImpl.h @@ -8,6 +8,11 @@ #include "Net/OnlineEngineInterface.h" #include "OnlineEngineInterfaceImpl.generated.h" +/** If OnlineEngineInterface.h doesn't define this, it isn't available. */ +#ifndef OSS_DEDICATED_SERVER_VOICECHAT +#define OSS_DEDICATED_SERVER_VOICECHAT 0 +#endif + class Error; class FVoicePacket; struct FWorldContext; @@ -27,11 +32,24 @@ public: virtual bool DoesInstanceExist(FName OnlineIdentifier) override; virtual void ShutdownOnlineSubsystem(FName OnlineIdentifier) override; virtual void DestroyOnlineSubsystem(FName OnlineIdentifier) override; +#if OSS_DEDICATED_SERVER_VOICECHAT + virtual FName GetDefaultOnlineSubsystemName() const override; +#endif private: + /** Allow the subsystem used for voice functions to be overridden, in case it needs to be different than the default subsystem. May be useful on console platforms. */ + UPROPERTY(config) + FName VoiceSubsystemNameOverride; + + /** Cache the name of the default subsystem, returned by GetDefaultOnlineSubsystemName(). */ + FName DefaultSubsystemName; + FName GetOnlineIdentifier(UWorld* World); + /** Returns the name of a corresponding dedicated server subsystem for the given subsystem, or NAME_None if such a system doesn't exist. */ + FName GetDedicatedServerSubsystemNameForSubsystem(const FName Subsystem) const; + /** * Identity */ @@ -84,7 +102,11 @@ private: public: virtual TSharedPtr GetLocalPacket(UWorld* World, uint8 LocalUserNum) override; +#if OSS_DEDICATED_SERVER_VOICECHAT + virtual TSharedPtr SerializeRemotePacket(UWorld* World, const UNetConnection* const RemoteConnection, FArchive& Ar) override; +#else virtual TSharedPtr SerializeRemotePacket(UWorld* World, FArchive& Ar) override; +#endif virtual void StartNetworkedVoice(UWorld* World, uint8 LocalUserNum) override; virtual void StopNetworkedVoice(UWorld* World, uint8 LocalUserNum) override; diff --git a/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Private/PartyBeaconClient.cpp b/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Private/PartyBeaconClient.cpp index bf8024a1dfa1..62786bb12fd6 100644 --- a/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Private/PartyBeaconClient.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Private/PartyBeaconClient.cpp @@ -317,6 +317,8 @@ void APartyBeaconClient::OnFailure() Super::OnFailure(); } +/// @cond DOXYGEN_WARNINGS + bool APartyBeaconClient::ServerReservationRequest_Validate(const FString& SessionId, const FPartyReservation& Reservation) { return !SessionId.IsEmpty() && Reservation.PartyLeader.IsValid() && Reservation.PartyMembers.Num() > 0; @@ -397,6 +399,8 @@ void APartyBeaconClient::ClientReservationResponse_Implementation(EPartyReservat } } +/// @endcond + void APartyBeaconClient::ProcessReservationResponse(EPartyReservationResult::Type ReservationResponse) { if (!bCancelReservation) @@ -412,6 +416,8 @@ void APartyBeaconClient::ProcessReservationResponse(EPartyReservationResult::Typ } } +/// @cond DOXYGEN_WARNINGS + void APartyBeaconClient::ClientCancelReservationResponse_Implementation(EPartyReservationResult::Type ReservationResponse) { ensure(bCancelReservation); @@ -441,6 +447,8 @@ void APartyBeaconClient::ClientCancelReservationResponse_Implementation(EPartyRe } } +/// @endcond + void APartyBeaconClient::ProcessCancelReservationResponse(EPartyReservationResult::Type ReservationResponse) { ensure(ReservationResponse == EPartyReservationResult::ReservationRequestCanceled || ReservationResponse == EPartyReservationResult::ReservationNotFound); @@ -448,6 +456,8 @@ void APartyBeaconClient::ProcessCancelReservationResponse(EPartyReservationResul OnCancelledComplete(); } +/// @cond DOXYGEN_WARNINGS + void APartyBeaconClient::ClientSendReservationUpdates_Implementation(int32 NumRemainingReservations) { if (!bCancelReservation) @@ -476,12 +486,16 @@ void APartyBeaconClient::ClientSendReservationUpdates_Implementation(int32 NumRe } } +/// @endcond + void APartyBeaconClient::ProcessReservationUpdate(int32 NumRemainingReservations) { UE_LOG(LogBeacon, Verbose, TEXT("Party beacon reservations remaining %d"), NumRemainingReservations); ReservationCountUpdate.ExecuteIfBound(NumRemainingReservations); } +/// @cond DOXYGEN_WARNINGS + void APartyBeaconClient::ClientSendReservationFull_Implementation() { if (!bCancelReservation) @@ -510,6 +524,8 @@ void APartyBeaconClient::ClientSendReservationFull_Implementation() } } +/// @endcond + void APartyBeaconClient::ProcessReservationFull() { UE_LOG(LogBeacon, Verbose, TEXT("Party beacon reservations full")); diff --git a/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Private/TestBeaconClient.cpp b/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Private/TestBeaconClient.cpp index e05b7e6b2bf2..08cd924c9aee 100644 --- a/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Private/TestBeaconClient.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Private/TestBeaconClient.cpp @@ -15,6 +15,8 @@ void ATestBeaconClient::OnFailure() Super::OnFailure(); } +/// @cond DOXYGEN_WARNINGS + void ATestBeaconClient::ClientPing_Implementation() { #if !UE_BUILD_SHIPPING @@ -39,3 +41,5 @@ void ATestBeaconClient::ServerPong_Implementation() ClientPing(); #endif } + +/// @endcond \ No newline at end of file diff --git a/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Private/VoiceInterfaceImpl.cpp b/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Private/VoiceInterfaceImpl.cpp index f90a37bbcb39..e839dcb738cf 100644 --- a/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Private/VoiceInterfaceImpl.cpp +++ b/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Private/VoiceInterfaceImpl.cpp @@ -564,7 +564,7 @@ void FOnlineVoiceImpl::ProcessMuteChangeNotification() if (LP && LP->PlayerController) { // If there is a player controller, we can mute/unmute people - if (LocalTalkers[Index].bIsRegistered && LP->PlayerController != NULL) + if (LocalTalkers[Index].bIsRegistered) { // Use the common method of checking muting UpdateMuteListForLocalTalker(Index, LP->PlayerController); diff --git a/Engine/Plugins/Runtime/Analytics/Adjust/Adjust.uplugin b/Engine/Plugins/Runtime/Analytics/Adjust/Adjust.uplugin new file mode 100644 index 000000000000..8fb20ac4afcc --- /dev/null +++ b/Engine/Plugins/Runtime/Analytics/Adjust/Adjust.uplugin @@ -0,0 +1,43 @@ +{ + "FileVersion" : 3, + "Version" : 1, + "VersionName" : "1.0", + "FriendlyName" : "Adjust Analytics Provider", + "Description" : "Adjust Analytics Provider", + "Category" : "Analytics", + "CreatedBy" : "Epic Games, Inc.", + "CreatedByURL" : "http://epicgames.com", + "DocsURL" : "https://docs.unrealengine.com/latest/INT/Gameplay/Analytics/index.html", + "MarketplaceURL" : "", + "SupportURL" : "", + "EnabledByDefault" : false, + "CanContainContent" : false, + "IsBetaVersion" : false, + "Installed" : false, + "Modules" : + [ + { + "Name" : "AdjustEditor", + "Type" : "Editor", + "LoadingPhase" : "Default" + }, + { + "Name" : "AndroidAdjust", + "Type" : "Runtime", + "LoadingPhase" : "PreDefault", + "WhitelistPlatforms" : + [ + "Android" + ] + }, + { + "Name" : "IOSAdjust", + "Type" : "Runtime", + "LoadingPhase" : "PreDefault", + "WhitelistPlatforms" : + [ + "IOS" + ] + } + ] +} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Analytics/Adjust/Source/AdjustEditor/AdjustEditor.Build.cs b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AdjustEditor/AdjustEditor.Build.cs new file mode 100644 index 000000000000..2948b21b428a --- /dev/null +++ b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AdjustEditor/AdjustEditor.Build.cs @@ -0,0 +1,29 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +using UnrealBuildTool; + +public class AdjustEditor : ModuleRules +{ + public AdjustEditor(ReadOnlyTargetRules Target) : base(Target) + { + PrivateIncludePaths.Add("AdjustEditor/Private"); + + PrivateDependencyModuleNames.AddRange( + new string[] { + "Core", + "CoreUObject", + "Analytics", + "AnalyticsVisualEditing", + "Engine", + "Projects" + } + ); + + PrivateIncludePathModuleNames.AddRange( + new string[] + { + "Settings" + } + ); + } +} diff --git a/Engine/Plugins/Runtime/Analytics/Adjust/Source/AdjustEditor/Classes/AdjustSettings.h b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AdjustEditor/Classes/AdjustSettings.h new file mode 100644 index 000000000000..1c2cf19d27ce --- /dev/null +++ b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AdjustEditor/Classes/AdjustSettings.h @@ -0,0 +1,107 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "AnalyticsSettings.h" +#include "AdjustSettings.generated.h" + +UENUM() +namespace EAndroidAdjustLogging +{ + enum Type + { + /** enable all logging */ + verbose UMETA(DisplayName = "VERBOSE"), + /** enable more logging */ + debug UMETA(DisplayName = "DEBUG"), + /** the default */ + info UMETA(DisplayName = "INFO"), + /** disable info logging */ + warn UMETA(DisplayName = "WARN"), + /** disable warnings as well */ + error UMETA(DisplayName = "ERROR"), + /** disable errors as well */ + assert UMETA(DisplayName = "ASSERT"), + /** disable all log output */ + supress UMETA(DisplayName = "SUPRESS"), + }; +} + +/** + * Holds the event name and corresponding token from Adjust dashboard. + */ +USTRUCT() +struct FAdjustEventMapping +{ + GENERATED_USTRUCT_BODY() + + /** The event name (the one passed in to RecordEvent calls). */ + UPROPERTY(EditAnywhere, Category = AdjustEvents) + FString Name; + + /** The token of the corresponding event, generated by the Adjust dashboard. */ + UPROPERTY(EditAnywhere, Category = AdjustEvents) + FString Token; +}; + +UCLASS() +class UAdjustSettings + : public UAnalyticsSettingsBase +{ + GENERATED_UCLASS_BODY() + + // Check to run in sandbox mode instead of production for non-distribution builds + UPROPERTY(EditAnywhere, Category=Adjust, meta=(ConfigRestartRequired = true, DisplayName = "Sandbox mode for non-distribution?")) + bool bSandboxNondistribution; + + // Check to run in sandbox mode instead of production for distribution builds + UPROPERTY(EditAnywhere, Category=Adjust, meta=(ConfigRestartRequired = true, DisplayName = "Sandbox mode for distribution?")) + bool bSandboxDistribution; + + // Application token from dashboard + UPROPERTY(EditAnywhere, Category=Adjust, meta=(ConfigRestartRequired = true, DisplayName = "Application token")) + FString AppToken; + + // Level of verbosity to use for logging + UPROPERTY(EditAnywhere, Category=Adjust, meta=(DisplayName = "Logging level")) + TEnumAsByte LogLevel; + + // Token from dashboard for tracker URL (may be left empty) + UPROPERTY(EditAnywhere, Category=Adjust, meta=(DisplayName = "Default tracker token")) + FString DefaultTracker; + + // Override the process name; will use the package name if not provided + UPROPERTY(EditAnywhere, Category=Adjust, meta=(DisplayName = "Process name (optional)")) + FString ProcessName; + + // Optional event buffering (send in batches once a minute instead of immediately) + UPROPERTY(EditAnywhere, Category=Adjust, meta=(DisplayName = "Enable event buffering")) + bool bEventBuffering; + + // Send while in application in background + UPROPERTY(EditAnywhere, Category=Adjust, meta=(DisplayName = "Send while in background")) + bool bSendInBackground; + + // Optional start delay (up to 10 seconds) before first events are sent + UPROPERTY(EditAnywhere, Category=Adjust, meta=(DisplayName = "Delay start (seconds)")) + float DelayStart; + + // Mapping of event names to tokens generated by Adjust dashboard. + UPROPERTY(EditAnywhere, Category = AdjustEvents) + TArray EventMap; + +// UAnalyticsSettingsBase interface +protected: + /** + * Provides a mechanism to read the section based information into this UObject's properties + */ + virtual void ReadConfigSettings(); + /** + * Provides a mechanism to save this object's properties to the section based ini values + */ + virtual void WriteConfigSettings(); + +private: + bool GetBoolFromConfig(const FString& IniName, const FString& SectionName, const FString& KeyName, bool bIsRequired, bool bDefault); + void WriteConfigSection(const FString& Section); +}; diff --git a/Engine/Plugins/Runtime/Analytics/Adjust/Source/AdjustEditor/Private/AdjustEditor.cpp b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AdjustEditor/Private/AdjustEditor.cpp new file mode 100644 index 000000000000..4d44088de7b7 --- /dev/null +++ b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AdjustEditor/Private/AdjustEditor.cpp @@ -0,0 +1,145 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#include "AdjustEditor.h" + +#include "AdjustEditorPrivatePCH.h" + +#include "AdjustSettings.h" +#include "Analytics.h" + +IMPLEMENT_MODULE( FAdjustEditorModule, AdjustEditorModule ); + +#define LOCTEXT_NAMESPACE "Adjust" + +void FAdjustEditorModule::StartupModule() +{ +} + +void FAdjustEditorModule::ShutdownModule() +{ +} + +UAdjustSettings::UAdjustSettings(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + SettingsDisplayName = LOCTEXT("SettingsDisplayName", "Adjust"); + SettingsTooltip = LOCTEXT("SettingsTooltip", "Adjust configuration settings"); +} + +bool UAdjustSettings::GetBoolFromConfig(const FString& IniName, const FString& InSectionName, const FString& KeyName, bool bIsRequired, bool bDefault) +{ + FString Result = FAnalytics::Get().GetConfigValueFromIni(IniName, InSectionName, KeyName, bIsRequired); + if (Result.Len() == 0) + { + return bDefault; + } + Result = Result.ToLower(); + return Result.Equals(TEXT("true")) || Result.Equals(TEXT("yes")); +} + +void UAdjustSettings::ReadConfigSettings() +{ + // Just read the release section since we write same values to all sections + bSandboxNondistribution = GetBoolFromConfig(GetIniName(), GetReleaseIniSection(), TEXT("AdjustSandboxNondistribution"), false, true); + bSandboxDistribution = GetBoolFromConfig(GetIniName(), GetReleaseIniSection(), TEXT("AdjustSandboxDistribution"), false, false); + AppToken = FAnalytics::Get().GetConfigValueFromIni(GetIniName(), GetReleaseIniSection(), TEXT("AdjustAppToken"), true); + + FString LogLevelIn = FAnalytics::Get().GetConfigValueFromIni(GetIniName(), GetReleaseIniSection(), TEXT("AdjustLogLevel"), false); + if (LogLevelIn.Equals("VERBOSE")) + LogLevel = EAndroidAdjustLogging::verbose; + else if (LogLevelIn.Equals("DEBUG")) + LogLevel = EAndroidAdjustLogging::debug; + else if (LogLevelIn.Equals("INFO")) + LogLevel = EAndroidAdjustLogging::info; + else if (LogLevelIn.Equals("WARN")) + LogLevel = EAndroidAdjustLogging::warn; + else if (LogLevelIn.Equals("ERROR")) + LogLevel = EAndroidAdjustLogging::error; + else if (LogLevelIn.Equals("ASSERT")) + LogLevel = EAndroidAdjustLogging::assert; + else if (LogLevelIn.Equals("SUPRESS")) + LogLevel = EAndroidAdjustLogging::supress; + else LogLevel = EAndroidAdjustLogging::info; + + DefaultTracker = FAnalytics::Get().GetConfigValueFromIni(GetIniName(), GetReleaseIniSection(), TEXT("AdjustDefaultTracker"), false); + ProcessName = FAnalytics::Get().GetConfigValueFromIni(GetIniName(), GetReleaseIniSection(), TEXT("AdjustProcessName"), false); + bEventBuffering = GetBoolFromConfig(GetIniName(), GetReleaseIniSection(), TEXT("AdjustEventBuffering"), false, false); + bSendInBackground = GetBoolFromConfig(GetIniName(), GetReleaseIniSection(), TEXT("AdjustSendInBackground"), false, false); + + FString Result = FAnalytics::Get().GetConfigValueFromIni(GetIniName(), GetReleaseIniSection(), TEXT("AdjustDelayStart"), false); + if (Result.Len() == 0) + { + Result = "0.0"; + } + DelayStart = FCString::Atof(*Result); + + // For now read event mapping from own section + EventMap.Empty(); + TArray EventNames; + TArray EventTokens; + int NameCount = GConfig->GetArray(TEXT("AdjustAnalyticsEventMapping"), TEXT("EventNames"), EventNames, GetIniName()); + int TokenCount = GConfig->GetArray(TEXT("AdjustAnalyticsEventMapping"), TEXT("EventTokens"), EventTokens, GetIniName()); + int Count = NameCount <= TokenCount ? NameCount : TokenCount; + for (int Index = 0; Index < Count; ++Index) + { + FAdjustEventMapping Mapping; + Mapping.Name = EventNames[Index]; + Mapping.Token = EventTokens[Index]; + EventMap.Add(Mapping); + } +} + +void UAdjustSettings::WriteConfigSettings() +{ + // Just write the same values to all configurations for now (we don't care which one we read) + WriteConfigSection(GetReleaseIniSection()); + WriteConfigSection(GetTestIniSection()); + WriteConfigSection(GetDebugIniSection()); + WriteConfigSection(GetDevelopmentIniSection()); + + // For now write the event mapping to own section manually here + TArray EventNames; + TArray EventTokens; + for (FAdjustEventMapping Entry : EventMap) + { + EventNames.Add(Entry.Name); + EventTokens.Add(Entry.Token); + } + GConfig->FConfigCacheIni::SetArray(TEXT("AdjustAnalyticsEventMapping"), TEXT("EventNames"), EventNames, GetIniName()); + GConfig->FConfigCacheIni::SetArray(TEXT("AdjustAnalyticsEventMapping"), TEXT("EventTokens"), EventTokens, GetIniName()); +} + +void UAdjustSettings::WriteConfigSection(const FString& Section) +{ + FAnalytics::Get().WriteConfigValueToIni(GetIniName(), Section, TEXT("AdjustSandboxNondistribution"), bSandboxNondistribution ? TEXT("true") : TEXT("false")); + FAnalytics::Get().WriteConfigValueToIni(GetIniName(), Section, TEXT("AdjustSandboxDistribution"), bSandboxDistribution ? TEXT("true") : TEXT("false")); + FAnalytics::Get().WriteConfigValueToIni(GetIniName(), Section, TEXT("AdjustAppToken"), AppToken); + + FString LogLevelOut = TEXT("INFO"); + switch (LogLevel) + { + case EAndroidAdjustLogging::verbose: LogLevelOut = TEXT("VERBOSE"); break; + case EAndroidAdjustLogging::debug: LogLevelOut = TEXT("DEBUG"); break; + case EAndroidAdjustLogging::info: LogLevelOut = TEXT("INFO"); break; + case EAndroidAdjustLogging::warn: LogLevelOut = TEXT("WARN"); break; + case EAndroidAdjustLogging::error: LogLevelOut = TEXT("ERROR"); break; + case EAndroidAdjustLogging::assert: LogLevelOut = TEXT("ASSERT"); break; + case EAndroidAdjustLogging::supress: LogLevelOut = TEXT("SUPRESS"); break; + } + FAnalytics::Get().WriteConfigValueToIni(GetIniName(), Section, TEXT("AdjustLogLevel"), LogLevelOut); + + FAnalytics::Get().WriteConfigValueToIni(GetIniName(), Section, TEXT("AdjustDefaultTracker"), DefaultTracker); + FAnalytics::Get().WriteConfigValueToIni(GetIniName(), Section, TEXT("AdjustProcessName"), ProcessName); + FAnalytics::Get().WriteConfigValueToIni(GetIniName(), Section, TEXT("AdjustEventBuffering"), bEventBuffering ? TEXT("true") : TEXT("false")); + FAnalytics::Get().WriteConfigValueToIni(GetIniName(), Section, TEXT("AdjustSendInBackground"), bSendInBackground ? TEXT("true") : TEXT("false")); + if (DelayStart > 0.0f) + { + FAnalytics::Get().WriteConfigValueToIni(GetIniName(), Section, TEXT("AdjustDelayStart"), FString::SanitizeFloat(DelayStart)); + } + else + { + FAnalytics::Get().WriteConfigValueToIni(GetIniName(), Section, TEXT("AdjustDelayStart"), TEXT("0.0")); + } +} + +#undef LOCTEXT_NAMESPACE diff --git a/Engine/Plugins/Runtime/Analytics/Adjust/Source/AdjustEditor/Private/AdjustEditorPrivatePCH.h b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AdjustEditor/Private/AdjustEditorPrivatePCH.h new file mode 100644 index 000000000000..b18e628ddda2 --- /dev/null +++ b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AdjustEditor/Private/AdjustEditorPrivatePCH.h @@ -0,0 +1,6 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +// You should place include statements to your module's private header files here. You only need to +// add includes for headers that are used in most of your module's source files though. + +#pragma once \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Analytics/Adjust/Source/AdjustEditor/Public/AdjustEditor.h b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AdjustEditor/Public/AdjustEditor.h new file mode 100644 index 000000000000..f252f258fc6b --- /dev/null +++ b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AdjustEditor/Public/AdjustEditor.h @@ -0,0 +1,13 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "ModuleInterface.h" + +class FAdjustEditorModule : + public IModuleInterface +{ +private: + virtual void StartupModule() override; + virtual void ShutdownModule() override; +}; + diff --git a/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/Adjust_UPL.xml b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/Adjust_UPL.xml new file mode 100644 index 000000000000..7c1d6d4365b7 --- /dev/null +++ b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/Adjust_UPL.xml @@ -0,0 +1,372 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} +-keep class com.adjust.sdk.plugin.MacAddressUtil { + java.lang.String getMacAddress(android.content.Context); +} +-keep class com.adjust.sdk.plugin.AndroidIdUtil { + java.lang.String getAndroidId(android.content.Context); +} +-keep class com.google.android.gms.common.ConnectionResult { + int SUCCESS; +} +-keep class com.google.android.gms.ads.identifier.AdvertisingIdClient { + com.google.android.gms.ads.identifier.AdvertisingIdClient$Info getAdvertisingIdInfo(android.content.Context); +} +-keep class com.google.android.gms.ads.identifier.AdvertisingIdClient$Info { + java.lang.String getId(); + boolean isLimitAdTrackingEnabled(); +} + + + + + + + + + + + + + + + + + + + + + +import java.util.LinkedHashMap; +import java.util.Map; +import android.net.Uri; +import com.adjust.sdk.Adjust; +import com.adjust.sdk.AdjustAttribution; +import com.adjust.sdk.AdjustConfig; +import com.adjust.sdk.AdjustEvent; +import com.adjust.sdk.AdjustEventFailure; +import com.adjust.sdk.AdjustEventSuccess; +import com.adjust.sdk.LogLevel; +import com.adjust.sdk.OnAttributionChangedListener; +import com.adjust.sdk.OnDeeplinkResponseListener; +import com.adjust.sdk.OnEventTrackingFailedListener; +import com.adjust.sdk.OnEventTrackingSucceededListener; +import com.adjust.sdk.OnSessionTrackingFailedListener; +import com.adjust.sdk.OnSessionTrackingSucceededListener; +import com.adjust.sdk.AdjustSessionFailure; +import com.adjust.sdk.AdjustSessionSuccess; + + + + + + Map<String, String> Adjust_Event_CallbackParameters; + Map<String, String> Adjust_Event_PartnerParameters; + + public void AndroidThunkJava_Adjust_SetEnabled(boolean Enable) + { + // Disable or enable tracking (REMEMBERED BETWEEEN SESSIONS!!) + Adjust.setEnabled(Enable); + } + + public void AndroidThunkJava_Adjust_SetOfflineMode(boolean Offline) + { + // Offline mode: (will save to file and send when disabled) ALWAYS STARTS in online mode! + Adjust.setOfflineMode(Offline); + } + + public void AndroidThunkJava_Adjust_SetPushToken(String Token) + { + Adjust.setPushToken(Token); + } + + public void AndroidThunkJava_Adjust_AddSessionPartnerParameter(String Key, String Value) + { + Adjust.addSessionPartnerParameter(Key, Value); + } + + public void AndroidThunkJava_Adjust_RemoveSessionPartnerParameter(String Key) + { + Adjust.removeSessionPartnerParameter(Key); + } + + public void AndroidThunkJava_Adjust_ResetSessionPartnerParameters() + { + Adjust.resetSessionPartnerParameters(); + } + + public void AndroidThunkJava_Adjust_Event_AddCallbackParameter(String Key, String Value) + { + if (Adjust_Event_CallbackParameters == null) + { + // use LinkedHashMap to preserve the ordering + Adjust_Event_CallbackParameters = new LinkedHashMap<String, String>(); + } + Adjust_Event_CallbackParameters.put(Key, Value); + } + + public void AndroidThunkJava_Adjust_Event_RemoveCallbackParameter(String Key) + { + if (Adjust_Event_CallbackParameters != null) + { + Adjust_Event_CallbackParameters.remove(Key); + } + } + + public void AndroidThunkJava_Adjust_Event_ResetCallbackParameters() + { + Adjust_Event_CallbackParameters = null; + } + + public void AndroidThunkJava_Adjust_Event_AddPartnerParameter(String Key, String Value) + { + if (Adjust_Event_PartnerParameters == null) + { + // use LinkedHashMap to preserve the ordering + Adjust_Event_PartnerParameters = new LinkedHashMap<String, String>(); + } + Adjust_Event_PartnerParameters.put(Key, Value); + } + + public void AndroidThunkJava_Adjust_Event_RemovePartnerParameter(String Key) + { + if (Adjust_Event_PartnerParameters != null) + { + Adjust_Event_PartnerParameters.remove(Key); + } + } + + public void AndroidThunkJava_Adjust_Event_ResetPartnerParameters() + { + Adjust_Event_PartnerParameters = null; + } + + private AdjustEvent Adjust_CreateEvent(String Token) + { + AdjustEvent event = new AdjustEvent(Token); + if (Adjust_Event_CallbackParameters != null) + { + for (LinkedHashMap.Entry<String, String> entry : Adjust_Event_CallbackParameters.entrySet()) + { + event.addCallbackParameter(entry.getKey(), entry.getValue()); + } + } + if (Adjust_Event_PartnerParameters != null) + { + for (LinkedHashMap.Entry<String, String> entry : Adjust_Event_PartnerParameters.entrySet()) + { + event.addPartnerParameter(entry.getKey(), entry.getValue()); + } + } + return event; + } + + public void AndroidThunkJava_Adjust_SendEvent(String Token) + { + Adjust.trackEvent(Adjust_CreateEvent(Token)); + } + + public void AndroidThunkJava_Adjust_SendRevenueEvent(String Token, String OrderId, double Amount, String Currency) + { + AdjustEvent event = Adjust_CreateEvent(Token); + event.setRevenue(Amount, Currency); // 0.01, USD + if (OrderId != "") + { + event.setOrderId(OrderId); // optional to prevent duplication (remembers last 10) + } + Adjust.trackEvent(event); + } + + + + + + + + + + String environment = AdjustConfig.ENVIRONMENT_SANDBOX; + + + + + String environment = AdjustConfig.ENVIRONMENT_PRODUCTION; + + + + + + + + + + + AdjustConfig config = new AdjustConfig(this, appToken, environment); + + + + + + + config.setSendInBackground(true); + + + + + config.setSendInBackground(false); + + + + + + + config.setEventBufferingEnabled(true); + + + + + config.setEventBufferingEnabled(false); + + + + + + + + + + + + + + + + + + + + // set attribution delegate + config.setOnAttributionChangedListener(new OnAttributionChangedListener() { + @Override + public void onAttributionChanged(AdjustAttribution attribution) { + Log.debug("[ADJUST] attribution: " + attribution.toString()); + } + }); + + // set event success tracking delegate + config.setOnEventTrackingSucceededListener(new OnEventTrackingSucceededListener() { + @Override + public void onFinishedEventTrackingSucceeded(AdjustEventSuccess eventSuccessResponseData) { + Log.debug("[ADJUST] success event tracking: " + eventSuccessResponseData.toString()); + } + }); + + // set event failure tracking delegate + config.setOnEventTrackingFailedListener(new OnEventTrackingFailedListener() { + @Override + public void onFinishedEventTrackingFailed(AdjustEventFailure eventFailureResponseData) { + Log.debug("[ADJUST] failed event tracking: " + eventFailureResponseData.toString()); + } + }); + + // set session success tracking delegate + config.setOnSessionTrackingSucceededListener(new OnSessionTrackingSucceededListener() { + @Override + public void onFinishedSessionTrackingSucceeded(AdjustSessionSuccess sessionSuccessResponseData) { + Log.debug("[ADJUST] success session tracking: " + sessionSuccessResponseData.toString()); + } + }); + + // set session failure tracking delegate + config.setOnSessionTrackingFailedListener(new OnSessionTrackingFailedListener() { + @Override + public void onFinishedSessionTrackingFailed(AdjustSessionFailure sessionFailureResponseData) { + Log.debug("[ADJUST] failed session tracking: " + sessionFailureResponseData.toString()); + } + }); + + // evaluate deeplink to be launched + config.setOnDeeplinkResponseListener(new OnDeeplinkResponseListener() { + @Override + public boolean launchReceivedDeeplink(Uri deeplink) { + Log.debug("[ADJUST] deeplink to open: " + deeplink); + return true; + } + }); + + Adjust.onCreate(config); + + + + + + Adjust.onResume(); + + + + + + Adjust.onPause(); + + + diff --git a/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/AndroidAdjust.Build.cs b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/AndroidAdjust.Build.cs new file mode 100644 index 000000000000..a15d6f2cbcac --- /dev/null +++ b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/AndroidAdjust.Build.cs @@ -0,0 +1,51 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +using System.IO; + +namespace UnrealBuildTool.Rules +{ + public class AndroidAdjust : ModuleRules + { + public AndroidAdjust(ReadOnlyTargetRules Target) : base(Target) + { + BinariesSubFolder = "NotForLicensees"; + + PublicDependencyModuleNames.AddRange( + new string[] + { + "Core", + // ... add other public dependencies that you statically link with here ... + } + ); + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "Analytics", + // ... add private dependencies that you statically link with here ... + } + ); + + PublicIncludePathModuleNames.AddRange( + new string[] + { + "Analytics", + "Core", + "Launch", + } + ); + + string PluginPath = Utils.MakePathRelativeTo(ModuleDirectory, BuildConfiguration.RelativeEnginePath); + bool bHasAdjustSDK = true; // Directory.Exists(System.IO.Path.Combine(PluginPath, "ThirdParty", "adjust_library")); + if (bHasAdjustSDK) + { + Definitions.Add("WITH_ADJUST=1"); + AdditionalPropertiesForReceipt.Add(new ReceiptProperty("AndroidPlugin", Path.Combine(PluginPath, "Adjust_UPL.xml"))); + } + else + { + Definitions.Add("WITH_ADJUST=0"); + } + } + } +} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/Private/AndroidAdjust.cpp b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/Private/AndroidAdjust.cpp new file mode 100644 index 000000000000..0acdf65360de --- /dev/null +++ b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/Private/AndroidAdjust.cpp @@ -0,0 +1,499 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#include "AndroidAdjust.h" +#include "ModuleManager.h" +#include "AndroidAdjustPrivatePCH.h" +#include "Android/AndroidJNI.h" +#include "Android/AndroidApplication.h" +#include "Paths.h" +#include "ConfigCacheIni.h" + +DEFINE_LOG_CATEGORY_STATIC(LogAnalytics, Display, All); + +IMPLEMENT_MODULE( FAnalyticsAndroidAdjust, AndroidAdjust ) + +TSharedPtr FAnalyticsProviderAdjust::Provider; + +void FAnalyticsAndroidAdjust::StartupModule() +{ +} + +void FAnalyticsAndroidAdjust::ShutdownModule() +{ + FAnalyticsProviderAdjust::Destroy(); +} + +// Android JNI to call Adjust UPL injected methods +void AndroidThunkCpp_Adjust_SetEnabled(bool bEnable) +{ + if (JNIEnv* Env = FAndroidApplication::GetJavaEnv()) + { + static jmethodID Method = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_Adjust_SetEnabled", "(Z)V", false); + FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, Method, bEnable); + } +} + +void AndroidThunkCpp_Adjust_SetOfflineMode(bool bOffline) +{ + if (JNIEnv* Env = FAndroidApplication::GetJavaEnv()) + { + static jmethodID Method = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_Adjust_SetOfflineMode", "(Z)V", false); + FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, Method, bOffline); + } +} + +void AndroidThunkCpp_Adjust_SetPushToken(const FString& Token) +{ + if (JNIEnv* Env = FAndroidApplication::GetJavaEnv()) + { + static jmethodID Method = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, " AndroidThunkJava_Adjust_SetPushToken", "(Ljava/lang/String;)V", false); + jstring TokenJava = Env->NewStringUTF(TCHAR_TO_UTF8(*Token)); + FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, Method, TokenJava); + Env->DeleteLocalRef(TokenJava); + } +} + +void AndroidThunkCpp_Adjust_AddSessionPartnerParameter(const FString& Key, const FString& Value) +{ + if (JNIEnv* Env = FAndroidApplication::GetJavaEnv()) + { + static jmethodID Method = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_Adjust_AddSessionPartnerParameter", "(Ljava/lang/String;Ljava/lang/String;)V", false); + jstring KeyJava = Env->NewStringUTF(TCHAR_TO_UTF8(*Key)); + jstring ValueJava = Env->NewStringUTF(TCHAR_TO_UTF8(*Value)); + FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, Method, KeyJava, ValueJava); + Env->DeleteLocalRef(KeyJava); + Env->DeleteLocalRef(ValueJava); + } +} + +void AndroidThunkCpp_Adjust_RemoveSessionPartnerParameter(const FString& Key) +{ + if (JNIEnv* Env = FAndroidApplication::GetJavaEnv()) + { + static jmethodID Method = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_Adjust_RemoveSessionPartnerParameter", "(Ljava/lang/String;)V", false); + jstring KeyJava = Env->NewStringUTF(TCHAR_TO_UTF8(*Key)); + FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, Method, KeyJava); + Env->DeleteLocalRef(KeyJava); + } +} + +void AndroidThunkCpp_Adjust_ResetSessionPartnerParameters() +{ + if (JNIEnv* Env = FAndroidApplication::GetJavaEnv()) + { + static jmethodID Method = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_Adjust_ResetSessionPartnerParameters", "()V", false); + FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, Method); + } +} + +void AndroidThunkCpp_Adjust_Event_AddCallbackParameter(const FString& Key, const FString& Value) +{ + if (JNIEnv* Env = FAndroidApplication::GetJavaEnv()) + { + static jmethodID Method = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_Adjust_Event_AddCallbackParameter", "(Ljava/lang/String;Ljava/lang/String;)V", false); + jstring KeyJava = Env->NewStringUTF(TCHAR_TO_UTF8(*Key)); + jstring ValueJava = Env->NewStringUTF(TCHAR_TO_UTF8(*Value)); + FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, Method, KeyJava, ValueJava); + Env->DeleteLocalRef(KeyJava); + Env->DeleteLocalRef(ValueJava); + } +} + +void AndroidThunkCpp_Adjust_Event_RemoveCallbackParameter(const FString& Key) +{ + if (JNIEnv* Env = FAndroidApplication::GetJavaEnv()) + { + static jmethodID Method = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_Adjust_Event_RemoveCallbackParameter", "(Ljava/lang/String;)V", false); + jstring KeyJava = Env->NewStringUTF(TCHAR_TO_UTF8(*Key)); + FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, Method, KeyJava); + Env->DeleteLocalRef(KeyJava); + } +} + +void AndroidThunkCpp_Adjust_Event_ResetCallbackParameters() +{ + if (JNIEnv* Env = FAndroidApplication::GetJavaEnv()) + { + static jmethodID Method = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_Adjust_Event_ResetCallbackParameters", "()V", false); + FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, Method); + } +} + +void AndroidThunkCpp_Adjust_Event_AddPartnerParameter(const FString& Key, const FString& Value) +{ + if (JNIEnv* Env = FAndroidApplication::GetJavaEnv()) + { + static jmethodID Method = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_Adjust_Event_AddPartnerParameter", "(Ljava/lang/String;Ljava/lang/String;)V", false); + jstring KeyJava = Env->NewStringUTF(TCHAR_TO_UTF8(*Key)); + jstring ValueJava = Env->NewStringUTF(TCHAR_TO_UTF8(*Value)); + FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, Method, KeyJava, ValueJava); + Env->DeleteLocalRef(KeyJava); + Env->DeleteLocalRef(ValueJava); + } +} + +void AndroidThunkCpp_Adjust_Event_RemovePartnerParameter(const FString& Key) +{ + if (JNIEnv* Env = FAndroidApplication::GetJavaEnv()) + { + static jmethodID Method = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_Adjust_Event_RemovePartnerParameter", "(Ljava/lang/String;)V", false); + jstring KeyJava = Env->NewStringUTF(TCHAR_TO_UTF8(*Key)); + FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, Method, KeyJava); + Env->DeleteLocalRef(KeyJava); + } +} + +void AndroidThunkCpp_Adjust_Event_ResetPartnerParameters() +{ + if (JNIEnv* Env = FAndroidApplication::GetJavaEnv()) + { + static jmethodID Method = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_Adjust_Event_ResetPartnerParameters", "()V", false); + FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, Method); + } +} + +void AndroidThunkCpp_Adjust_SendEvent(const FString& Token) +{ + if (JNIEnv* Env = FAndroidApplication::GetJavaEnv()) + { + static jmethodID Method = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_Adjust_SendEvent", "(Ljava/lang/String;)V", false); + jstring TokenJava = Env->NewStringUTF(TCHAR_TO_UTF8(*Token)); + FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, Method, TokenJava); + Env->DeleteLocalRef(TokenJava); + } +} + +void AndroidThunkCpp_Adjust_SendRevenueEvent(const FString& Token, const FString& OrderId, double Amount, const FString& Currency) +{ + if (JNIEnv* Env = FAndroidApplication::GetJavaEnv()) + { + static jmethodID Method = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_Adjust_SendRevenueEvent", "(Ljava/lang/String;Ljava/lang/String;DLjava/lang/String;)V", false); + jstring TokenJava = Env->NewStringUTF(TCHAR_TO_UTF8(*Token)); + jstring OrderIdJava = Env->NewStringUTF(TCHAR_TO_UTF8(*OrderId)); + jstring CurrencyJava = Env->NewStringUTF(TCHAR_TO_UTF8(*Currency)); + FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, Method, TokenJava, OrderIdJava, Amount, CurrencyJava); + Env->DeleteLocalRef(TokenJava); + Env->DeleteLocalRef(OrderIdJava); + Env->DeleteLocalRef(CurrencyJava); + } +} + +// End Android JNI to call Adjust UPL injected methods + +TSharedPtr FAnalyticsAndroidAdjust::CreateAnalyticsProvider(const FAnalyticsProviderConfigurationDelegate& GetConfigValue) const +{ + if (GetConfigValue.IsBound()) + { + const FString InAppToken = GetConfigValue.Execute(TEXT("AdjustAppToken"), true); + return FAnalyticsProviderAdjust::Create(InAppToken); + } + else + { + UE_LOG(LogAnalytics, Warning, TEXT("AndroidAdjust::CreateAnalyticsProvider called with an unbound delegate")); + } + return nullptr; +} + +// Provider + +FAnalyticsProviderAdjust::FAnalyticsProviderAdjust(const FString inAppToken) : + AppToken(inAppToken) +{ +#if WITH_ADJUST + // NOTE: currently expect these events to have been added! + // SessionAttributes + // Item Purchase + // Currency Purchase + // Currency Given + // Error + // Progress + + // add event attributes from ini + FString IniName = FString::Printf(TEXT("%sDefaultEngine.ini"), *FPaths::SourceConfigDir()); + EventMap.Empty(); + TArray EventNames; + TArray EventTokens; + int NameCount = GConfig->GetArray(TEXT("AdjustAnalyticsEventMapping"), TEXT("EventNames"), EventNames, IniName); + int TokenCount = GConfig->GetArray(TEXT("AdjustAnalyticsEventMapping"), TEXT("EventTokens"), EventTokens, IniName); + int Count = NameCount <= TokenCount ? NameCount : TokenCount; + for (int Index = 0; Index < Count; ++Index) + { + EventMap.Add(EventNames[Index], EventTokens[Index]); + } + + #else + UE_LOG(LogAnalytics, Warning, TEXT("WITH_ADJUST=0. Are you missing the SDK?")); +#endif +} + +FAnalyticsProviderAdjust::~FAnalyticsProviderAdjust() +{ + if (bHasSessionStarted) + { + EndSession(); + } +} + +bool FAnalyticsProviderAdjust::StartSession(const TArray& Attributes) +{ +#if WITH_ADJUST + const int32 AttrCount = Attributes.Num(); + + // add session attributes (this will be on all events) + + for (auto Attr : Attributes) + { + AndroidThunkCpp_Adjust_AddSessionPartnerParameter(Attr.AttrName, Attr.AttrValue); + } + RecordEvent(TEXT("SessionAttributes"), Attributes); + + if (!bHasSessionStarted) + { + UE_LOG(LogAnalytics, Display, TEXT("AndroidAdjust::StartSession(%d attributes)"), AttrCount); + } + else + { + UE_LOG(LogAnalytics, Display, TEXT("AndroidAdjust::RestartSession(%d attributes)"), AttrCount); + } + bHasSessionStarted = true; + return bHasSessionStarted; +#else + UE_LOG(LogAnalytics, Warning, TEXT("WITH_ADJUST=0. Are you missing the SDK?")); + return false; +#endif +} + +void FAnalyticsProviderAdjust::EndSession() +{ +#if WITH_ADJUST + bHasSessionStarted = false; + + UE_LOG(LogAnalytics, Display, TEXT("AndroidAdjust::EndSession")); +#else + UE_LOG(LogAnalytics, Warning, TEXT("WITH_ADJUST=0. Are you missing the SDK?")); +#endif +} + +void FAnalyticsProviderAdjust::FlushEvents() +{ +#if WITH_ADJUST + UE_LOG(LogAnalytics, Display, TEXT("AndroidAdjust::FlushEvents")); +#else + UE_LOG(LogAnalytics, Warning, TEXT("WITH_ADJUST=0. Are you missing the SDK?")); +#endif +} + +void FAnalyticsProviderAdjust::SetUserID(const FString& InUserID) +{ +#if WITH_ADJUST + UserId = InUserID; + UE_LOG(LogAnalytics, Display, TEXT("AndroidAdjust::SetUserID(%s)"), *UserId); +#else + UE_LOG(LogAnalytics, Warning, TEXT("WITH_ADJUST=0. Are you missing the SDK?")); +#endif +} + +FString FAnalyticsProviderAdjust::GetUserID() const +{ +#if WITH_ADJUST + UE_LOG(LogAnalytics, Display, TEXT("AndroidAdjust::GetUserID - returning cached id '%s'"), *UserId); + + return UserId; +#else + UE_LOG(LogAnalytics, Warning, TEXT("WITH_ADJUST=0. Are you missing the SDK?")); + return FString(); +#endif +} + +FString FAnalyticsProviderAdjust::GetSessionID() const +{ +#if WITH_ADJUST + FString Id = TEXT("unavailable"); + + UE_LOG(LogAnalytics, Display, TEXT("AndroidAdjust::GetSessionID - returning the id as '%s'"), *Id); + + return Id; +#else + UE_LOG(LogAnalytics, Warning, TEXT("WITH_ADJUST=0. Are you missing the SDK?")); + return FString(); +#endif +} + +bool FAnalyticsProviderAdjust::SetSessionID(const FString& InSessionID) +{ +#if WITH_ADJUST + // Ignored + UE_LOG(LogAnalytics, Display, TEXT("AndroidAdjust::SetSessionID - ignoring call")); + return false; +#else + UE_LOG(LogAnalytics, Warning, TEXT("WITH_ADJUST=0. Are you missing the SDK?")); + return false; +#endif +} + +void FAnalyticsProviderAdjust::RecordEvent(const FString& EventName, const TArray& Attributes) +{ +#if WITH_ADJUST + FString* EventTokenRef = EventMap.Find(EventName); + if (EventTokenRef != nullptr) + { + FString EventToken = *EventTokenRef; + + AndroidThunkCpp_Adjust_Event_ResetCallbackParameters(); + AndroidThunkCpp_Adjust_Event_ResetPartnerParameters(); + + const int32 AttrCount = Attributes.Num(); + if (AttrCount > 0) + { + // add event attributes + for (auto Attr : Attributes) + { + AndroidThunkCpp_Adjust_Event_AddCallbackParameter(Attr.AttrName, Attr.AttrValue); + } + } + AndroidThunkCpp_Adjust_SendEvent(EventToken); + UE_LOG(LogAnalytics, Display, TEXT("AndroidAdjust::RecordEvent('%s', %d attributes) Token=%s"), *EventName, AttrCount, *EventToken); + } +#else + UE_LOG(LogAnalytics, Warning, TEXT("WITH_ADJUST=0. Are you missing the SDK?")); +#endif +} + +void FAnalyticsProviderAdjust::RecordItemPurchase(const FString& ItemId, const FString& Currency, int PerItemCost, int ItemQuantity) +{ +#if WITH_ADJUST + FString* EventTokenRef = EventMap.Find(TEXT("Item Purchase")); + if (EventTokenRef != nullptr) + { + FString EventToken = *EventTokenRef; + + AndroidThunkCpp_Adjust_Event_ResetPartnerParameters(); + + AndroidThunkCpp_Adjust_Event_ResetCallbackParameters(); + AndroidThunkCpp_Adjust_Event_AddCallbackParameter(TEXT("ItemId"), ItemId); + AndroidThunkCpp_Adjust_Event_AddCallbackParameter(TEXT("Currency"), Currency); + AndroidThunkCpp_Adjust_Event_AddCallbackParameter(TEXT("PerItemCost"), FString::FromInt(PerItemCost)); + AndroidThunkCpp_Adjust_Event_AddCallbackParameter(TEXT("ItemQuantity"), FString::FromInt(ItemQuantity)); + + // @TODO: This is probably wrong.. might just want to do a normal event and forget about revenue / order id (note: input is in cents so divide by 100) + AndroidThunkCpp_Adjust_SendRevenueEvent(EventToken, ItemId, PerItemCost * ItemQuantity * 0.01, Currency); + + UE_LOG(LogAnalytics, Display, TEXT("AndroidAdjust::RecordItemPurchase('%s', '%s', %d, %d) Token=%s"), *ItemId, *Currency, PerItemCost, ItemQuantity, *EventToken); + } +#else + UE_LOG(LogAnalytics, Warning, TEXT("WITH_ADJUST=0. Are you missing the SDK?")); +#endif +} + +void FAnalyticsProviderAdjust::RecordCurrencyPurchase(const FString& GameCurrencyType, int GameCurrencyAmount, const FString& RealCurrencyType, float RealMoneyCost, const FString& PaymentProvider) +{ +#if WITH_ADJUST + FString* EventTokenRef = EventMap.Find(TEXT("Currency Purchase")); + if (EventTokenRef != nullptr) + { + FString EventToken = *EventTokenRef; + + AndroidThunkCpp_Adjust_Event_ResetPartnerParameters(); + + AndroidThunkCpp_Adjust_Event_ResetCallbackParameters(); + AndroidThunkCpp_Adjust_Event_AddCallbackParameter(TEXT("GameCurrencyType"), GameCurrencyType); + AndroidThunkCpp_Adjust_Event_AddCallbackParameter(TEXT("GameCurrencyAmount"), FString::FromInt(GameCurrencyAmount)); + AndroidThunkCpp_Adjust_Event_AddCallbackParameter(TEXT("RealCurrencyType"), RealCurrencyType); + AndroidThunkCpp_Adjust_Event_AddCallbackParameter(TEXT("RealMoneyCost"), FString::Printf(TEXT("%.02f"), RealMoneyCost)); + AndroidThunkCpp_Adjust_Event_AddCallbackParameter(TEXT("PaymentProvider"), PaymentProvider); + + // @TODO: This is probably wrong.. might just want to do a normal event and forget about revenue / order id + AndroidThunkCpp_Adjust_SendRevenueEvent(EventToken, GameCurrencyType, RealMoneyCost, RealCurrencyType); + + UE_LOG(LogAnalytics, Display, TEXT("AndroidAdjust::RecordCurrencyPurchase('%s', %d, '%s', %.02f, %s) Token=%s"), *GameCurrencyType, GameCurrencyAmount, *RealCurrencyType, RealMoneyCost, *PaymentProvider, *EventToken); + } +#else + UE_LOG(LogAnalytics, Warning, TEXT("WITH_ADJUST=0. Are you missing the SDK?")); +#endif +} + +void FAnalyticsProviderAdjust::RecordCurrencyGiven(const FString& GameCurrencyType, int GameCurrencyAmount) +{ +#if WITH_ADJUST + FString* EventTokenRef = EventMap.Find(TEXT("Currency Given")); + if (EventTokenRef != nullptr) + { + FString EventToken = *EventTokenRef; + + AndroidThunkCpp_Adjust_Event_ResetPartnerParameters(); + + AndroidThunkCpp_Adjust_Event_ResetCallbackParameters(); + AndroidThunkCpp_Adjust_Event_AddCallbackParameter(TEXT("GameCurrencyType"), GameCurrencyType); + AndroidThunkCpp_Adjust_Event_AddCallbackParameter(TEXT("GameCurrencyAmount"), FString::FromInt(GameCurrencyAmount)); + + AndroidThunkCpp_Adjust_SendEvent(EventToken); + + UE_LOG(LogAnalytics, Display, TEXT("AndroidAdjust::RecordCurrencyGiven('%s', %d) Token=%s"), *GameCurrencyType, GameCurrencyAmount, *EventToken); + } +#else + UE_LOG(LogAnalytics, Warning, TEXT("WITH_ADJUST=0. Are you missing the SDK?")); +#endif +} + +void FAnalyticsProviderAdjust::RecordError(const FString& Error, const TArray& EventAttrs) +{ +#if WITH_ADJUST + FString* EventTokenRef = EventMap.Find(TEXT("Error")); + if (EventTokenRef != nullptr) + { + FString EventToken = *EventTokenRef; + + AndroidThunkCpp_Adjust_Event_ResetCallbackParameters(); + AndroidThunkCpp_Adjust_Event_ResetPartnerParameters(); + + const int32 AttrCount = EventAttrs.Num(); + if (AttrCount > 0) + { + // add event attributes + for (auto Attr : EventAttrs) + { + AndroidThunkCpp_Adjust_Event_AddCallbackParameter(Attr.AttrName, Attr.AttrValue); + } + } + + AndroidThunkCpp_Adjust_SendEvent(EventToken); + + UE_LOG(LogAnalytics, Display, TEXT("AndroidAdjust::RecordError('%s', %d) Token=%s"), *Error, AttrCount, *EventToken); + } +#else + UE_LOG(LogAnalytics, Warning, TEXT("WITH_ADJUST=0. Are you missing the SDK?")); +#endif +} + +void FAnalyticsProviderAdjust::RecordProgress(const FString& ProgressType, const FString& ProgressHierarchy, const TArray& EventAttrs) +{ +#if WITH_ADJUST + FString* EventTokenRef = EventMap.Find(TEXT("Progress")); + if (EventTokenRef != nullptr) + { + FString EventToken = *EventTokenRef; + + AndroidThunkCpp_Adjust_Event_ResetCallbackParameters(); + AndroidThunkCpp_Adjust_Event_ResetPartnerParameters(); + + AndroidThunkCpp_Adjust_Event_AddCallbackParameter(TEXT("ProgressType"), ProgressType); + AndroidThunkCpp_Adjust_Event_AddCallbackParameter(TEXT("ProgressHierarchy"), ProgressHierarchy); + + const int32 AttrCount = EventAttrs.Num(); + if (AttrCount > 0) + { + // add event attributes + for (auto Attr : EventAttrs) + { + AndroidThunkCpp_Adjust_Event_AddCallbackParameter(Attr.AttrName, Attr.AttrValue); + } + } + + AndroidThunkCpp_Adjust_SendEvent(EventToken); + + UE_LOG(LogAnalytics, Display, TEXT("AndroidAdjust::RecordProgress('%s', %s, %d) Token=%s"), *ProgressType, *ProgressHierarchy, AttrCount, *EventToken); + } +#else + UE_LOG(LogAnalytics, Warning, TEXT("WITH_ADJUST=0. Are you missing the SDK?")); +#endif +} diff --git a/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/Private/AndroidAdjustPrivatePCH.h b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/Private/AndroidAdjustPrivatePCH.h new file mode 100644 index 000000000000..b166a00068a9 --- /dev/null +++ b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/Private/AndroidAdjustPrivatePCH.h @@ -0,0 +1,12 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#include "CoreMinimal.h" + +#include "AndroidAdjust.h" +#include "AndroidAdjustProvider.h" + +#if WITH_ADJUST +#endif + +// You should place include statements to your module's private header files here. You only need to +// add includes for headers that are used in most of your module's source files though. diff --git a/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/Private/AndroidAdjustProvider.h b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/Private/AndroidAdjustProvider.h new file mode 100644 index 000000000000..2b9c5a9bf598 --- /dev/null +++ b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/Private/AndroidAdjustProvider.h @@ -0,0 +1,56 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "IAnalyticsProvider.h" + +class FAnalyticsProviderAdjust : + public IAnalyticsProvider +{ + /** The AppToken given to you by Adjust dashboard */ + FString AppToken; + /** Tracks whether we need to start the session or restart it */ + bool bHasSessionStarted; + /** Cached user id */ + FString UserId; + /** Event name to token mapping */ + TMap EventMap; + + /** Singleton for analytics */ + static TSharedPtr Provider; + FAnalyticsProviderAdjust(const FString inAppToken); + +public: + static TSharedPtr Create(const FString inAppToken) + { + if (!Provider.IsValid()) + { + Provider = TSharedPtr(new FAnalyticsProviderAdjust(inAppToken)); + } + return Provider; + } + static void Destroy() + { + Provider.Reset(); + } + + virtual ~FAnalyticsProviderAdjust(); + + virtual bool StartSession(const TArray& Attributes) override; + virtual void EndSession() override; + virtual void FlushEvents() override; + + virtual void SetUserID(const FString& InUserID) override; + virtual FString GetUserID() const override; + + virtual FString GetSessionID() const override; + virtual bool SetSessionID(const FString& InSessionID) override; + + virtual void RecordEvent(const FString& EventName, const TArray& Attributes) override; + virtual void RecordItemPurchase(const FString& ItemId, const FString& Currency, int PerItemCost, int ItemQuantity) override; + virtual void RecordCurrencyPurchase(const FString& GameCurrencyType, int GameCurrencyAmount, const FString& RealCurrencyType, float RealMoneyCost, const FString& PaymentProvider) override; + virtual void RecordCurrencyGiven(const FString& GameCurrencyType, int GameCurrencyAmount) override; + + virtual void RecordError(const FString& Error, const TArray& EventAttrs) override; + virtual void RecordProgress(const FString& ProgressType, const FString& ProgressHierarchy, const TArray& EventAttrs) override; +}; diff --git a/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/Public/AndroidAdjust.h b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/Public/AndroidAdjust.h new file mode 100644 index 000000000000..a21c0b3ed950 --- /dev/null +++ b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/Public/AndroidAdjust.h @@ -0,0 +1,46 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "IAnalyticsProviderModule.h" +#include "ModuleManager.h" + +class IAnalyticsProvider; + +/** + * The public interface to this module + */ +class FAnalyticsAndroidAdjust : + public IAnalyticsProviderModule +{ + //-------------------------------------------------------------------------- + // Module functionality + //-------------------------------------------------------------------------- +public: + /** + * Singleton-like access to this module's interface. This is just for convenience! + * Beware of calling this during the shutdown phase, though. Your module might have been unloaded already. + * + * @return Returns singleton instance, loading the module on demand if needed + */ + static inline FAnalyticsAndroidAdjust& Get() + { + return FModuleManager::LoadModuleChecked< FAnalyticsAndroidAdjust >( "AndroidAdjust" ); + } + + //-------------------------------------------------------------------------- + // provider factory functions + //-------------------------------------------------------------------------- +public: + /** + * IAnalyticsProviderModule interface. + * Creates the analytics provider given a configuration delegate. + * The keys required exactly match the field names in the Config object. + */ + virtual TSharedPtr CreateAnalyticsProvider(const FAnalyticsProviderConfigurationDelegate& GetConfigValue) const override; + +private: + virtual void StartupModule() override; + virtual void ShutdownModule() override; +}; + diff --git a/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/ThirdParty/adjust_library/AdjustAndroidSDK.tps b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/ThirdParty/adjust_library/AdjustAndroidSDK.tps new file mode 100644 index 000000000000..fbc6e30e94ac --- /dev/null +++ b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/ThirdParty/adjust_library/AdjustAndroidSDK.tps @@ -0,0 +1,15 @@ + + + Adjust Android SDK + /Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/ThirdParty/adjust_library/ + 2016-11-21T12:05:58.059833-05:00 + For tracking analytics on mobile, similar to Flurry + Needed for WEX + https://github.com/adjust/android_sdk/blob/master/MIT-LICENSE + + Licensees + Git + P4 + + /Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/ThirdParty/adjust_library/AdjustAndroidSDK_License.txt + \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/ThirdParty/adjust_library/AdjustAndroidSDK_License.txt b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/ThirdParty/adjust_library/AdjustAndroidSDK_License.txt new file mode 100644 index 000000000000..39aff2239fb9 --- /dev/null +++ b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/ThirdParty/adjust_library/AdjustAndroidSDK_License.txt @@ -0,0 +1,21 @@ +Copyright (c) 2012-2014 adjust GmbH, +http://www.adjust.com + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/ThirdParty/adjust_library/AndroidManifest.xml b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/ThirdParty/adjust_library/AndroidManifest.xml new file mode 100644 index 000000000000..b720f1f15bd3 --- /dev/null +++ b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/ThirdParty/adjust_library/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + diff --git a/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/ThirdParty/adjust_library/build.xml b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/ThirdParty/adjust_library/build.xml new file mode 100644 index 000000000000..2e01ab462dbb --- /dev/null +++ b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/ThirdParty/adjust_library/build.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/ThirdParty/adjust_library/custom_rules.xml b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/ThirdParty/adjust_library/custom_rules.xml new file mode 100644 index 000000000000..9ff805a37686 --- /dev/null +++ b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/ThirdParty/adjust_library/custom_rules.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Engine/Source/Runtime/Apple/AudioMixerCoreAudio/Private/AudioMixerPlatformApple.cpp b/Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/ThirdParty/adjust_library/src/DO_NOT_DELETE.txt similarity index 100% rename from Engine/Source/Runtime/Apple/AudioMixerCoreAudio/Private/AudioMixerPlatformApple.cpp rename to Engine/Plugins/Runtime/Analytics/Adjust/Source/AndroidAdjust/ThirdParty/adjust_library/src/DO_NOT_DELETE.txt diff --git a/Engine/Plugins/Runtime/Analytics/Adjust/Source/IOSAdjust/IOSAdjust.Build.cs b/Engine/Plugins/Runtime/Analytics/Adjust/Source/IOSAdjust/IOSAdjust.Build.cs new file mode 100644 index 000000000000..befd352042ce --- /dev/null +++ b/Engine/Plugins/Runtime/Analytics/Adjust/Source/IOSAdjust/IOSAdjust.Build.cs @@ -0,0 +1,63 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +using System.IO; + +namespace UnrealBuildTool.Rules +{ + public class IOSAdjust : ModuleRules + { + public IOSAdjust(ReadOnlyTargetRules Target) : base(Target) + { + BinariesSubFolder = "NotForLicensees"; + + PublicDependencyModuleNames.AddRange( + new string[] + { + "Core", + // ... add other public dependencies that you statically link with here ... + } + ); + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "Analytics", + // ... add private dependencies that you statically link with here ... + } + ); + + // Add the Adjust framework + PublicAdditionalFrameworks.Add( + new UEBuildFramework( + "AdjustSdk", // Framework name + "../../ThirdPartyFrameworks/AdjustSdk.embeddedframework.zip" // Zip name + ) + ); + + PublicFrameworks.AddRange( + new string[] { +// "AdSuppport", // optional +// "iAd", // optional + } + ); + + PublicIncludePathModuleNames.AddRange( + new string[] + { + "Analytics", + } + ); + + //string PluginPath = Utils.MakePathRelativeTo(ModuleDirectory, BuildConfiguration.RelativeEnginePath); + bool bHasAdjustSDK = true; // Directory.Exists(System.IO.Path.Combine(PluginPath, "ThirdParty", "adjust_library")); + if (bHasAdjustSDK) + { + Definitions.Add("WITH_ADJUST=1"); + } + else + { + Definitions.Add("WITH_ADJUST=0"); + } + } + } +} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Analytics/Adjust/Source/IOSAdjust/Private/IOSAdjust.cpp b/Engine/Plugins/Runtime/Analytics/Adjust/Source/IOSAdjust/Private/IOSAdjust.cpp new file mode 100644 index 000000000000..77a815a3b44b --- /dev/null +++ b/Engine/Plugins/Runtime/Analytics/Adjust/Source/IOSAdjust/Private/IOSAdjust.cpp @@ -0,0 +1,432 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#include "IOSAdjust.h" +#include "IOSAdjustPrivatePCH.h" +#include "Paths.h" +#include "ConfigCacheIni.h" + +#import + +DEFINE_LOG_CATEGORY_STATIC(LogAnalytics, Display, All); + +IMPLEMENT_MODULE( FAnalyticsIOSAdjust, IOSAdjust ) + +TSharedPtr FAnalyticsProviderAdjust::Provider; + +void FAnalyticsIOSAdjust::StartupModule() +{ +} + +void FAnalyticsIOSAdjust::ShutdownModule() +{ + FAnalyticsProviderAdjust::Destroy(); +} + +static bool ConvertToBool(const FString& InString, bool bDefault) +{ + if (InString.Len() == 0) + { + return bDefault; + } + FString Result = InString.ToLower(); + return Result.Equals(TEXT("true")) || Result.Equals(TEXT("yes")); +} + +TSharedPtr FAnalyticsIOSAdjust::CreateAnalyticsProvider(const FAnalyticsProviderConfigurationDelegate& GetConfigValue) const +{ + if (GetConfigValue.IsBound()) + { + const FString InSandboxNondistribution = GetConfigValue.Execute(TEXT("AdjustSandboxNondistribution"), false); + const FString InSandboxDistribution = GetConfigValue.Execute(TEXT("AdjustSandboxDistribution"), false); + const FString InAppToken = GetConfigValue.Execute(TEXT("AdjustAppToken"), true); + const FString InLogLevel = GetConfigValue.Execute(TEXT("AdjustLogLevel"), false); + const FString InDefaultTracker = GetConfigValue.Execute(TEXT("AdjustDefaultTracker"), false); + const FString InEventBuffering = GetConfigValue.Execute(TEXT("AdjustEventBuffering"), false); + const FString InSendInBackground = GetConfigValue.Execute(TEXT("AdjustSendInBackground"), false); + const FString InDelayStart = GetConfigValue.Execute(TEXT("AdjustDelayStart"), false); + + // @TODO: this is probably a bad assumption +#if UE_BUILD_SHIPPING + bool bInSandbox = ConvertToBool(InSandboxDistribution, false); +#else + bool bInSandbox = ConvertToBool(InSandboxNondistribution, true); +#endif + bool bInEventBuffering = ConvertToBool(InEventBuffering, false); + bool bInSendInBackground = ConvertToBool(InSendInBackground, false); + + float DelayStart = 0.0f; + if (InDelayStart.Len() > 0) + { + DelayStart = FCString::Atof(*InDelayStart); + } + + return FAnalyticsProviderAdjust::Create(InAppToken, bInSandbox, InLogLevel, InDefaultTracker, bInEventBuffering, bInSendInBackground, DelayStart); + } + else + { + UE_LOG(LogAnalytics, Warning, TEXT("IOSAdjust::CreateAnalyticsProvider called with an unbound delegate")); + } + return nullptr; +} + +// Provider + +FAnalyticsProviderAdjust::FAnalyticsProviderAdjust(const FString InAppToken, bool bInSandbox, const FString InLogLevel, const FString InDefaultTracker, bool bInEventBuffering, bool bSendInBackground, float InDelayStart) : + AppToken(InAppToken) +{ +#if WITH_ADJUST + // NOTE: currently expect these events to have been added! + // SessionAttributes + // Item Purchase + // Currency Purchase + // Currency Given + // Error + // Progress + + // add event attributes from ini + FString IniName = FString::Printf(TEXT("%sDefaultEngine.ini"), *FPaths::SourceConfigDir()); + EventMap.Empty(); + TArray EventNames; + TArray EventTokens; + int NameCount = GConfig->GetArray(TEXT("AdjustAnalyticsEventMapping"), TEXT("EventNames"), EventNames, IniName); + int TokenCount = GConfig->GetArray(TEXT("AdjustAnalyticsEventMapping"), TEXT("EventTokens"), EventTokens, IniName); + int Count = NameCount <= TokenCount ? NameCount : TokenCount; + for (int Index = 0; Index < Count; ++Index) + { + EventMap.Add(EventNames[Index], EventTokens[Index]); + } + + // I hope this is the right place to do this (supposed to be in didFinishLaunching in application delegate + NSString* IOSAppToken = [NSString stringWithFString : InAppToken]; + NSString* Environment = bInSandbox ? ADJEnvironmentSandbox : ADJEnvironmentProduction; + ADJConfig* adjustConfig; + + // Yes, I know SUPRESS is inconsistent, this is from their SDK + if (InLogLevel.Equals("SUPRESS")) + adjustConfig = [ADJConfig configWithAppToken:IOSAppToken environment:Environment allowSuppressLogLevel:YES]; + else + adjustConfig = [ADJConfig configWithAppToken:IOSAppToken environment:Environment]; + + if (InLogLevel.Equals("VERBOSE")) + [adjustConfig setLogLevel:ADJLogLevelVerbose]; + else if (InLogLevel.Equals("DEBUG")) + [adjustConfig setLogLevel:ADJLogLevelDebug]; + else if (InLogLevel.Equals("INFO")) + [adjustConfig setLogLevel:ADJLogLevelInfo]; + else if (InLogLevel.Equals("WARN")) + [adjustConfig setLogLevel:ADJLogLevelWarn]; + else if (InLogLevel.Equals("ERROR")) + [adjustConfig setLogLevel:ADJLogLevelError]; + else if (InLogLevel.Equals("ASSERT")) + [adjustConfig setLogLevel:ADJLogLevelAssert]; + else if (InLogLevel.Equals("SUPRESS")) + [adjustConfig setLogLevel:ADJLogLevelSuppress]; + else [adjustConfig setLogLevel:ADJLogLevelInfo]; + + if (!InDefaultTracker.IsEmpty()) + { + [adjustConfig setDefaultTracker:[NSString stringWithFString : InDefaultTracker]]; + } + + if (bInEventBuffering) + { + [adjustConfig setEventBufferingEnabled:YES]; + } + + if (bSendInBackground) + { + [adjustConfig setSendInBackground:YES]; + } + + if (InDelayStart > 0.0f) + { + [adjustConfig setDelayStart:InDelayStart]; + } + + [Adjust appDidLaunch:adjustConfig]; + [Adjust trackSubsessionStart]; + +#else + UE_LOG(LogAnalytics, Warning, TEXT("WITH_ADJUST=0. Are you missing the SDK?")); +#endif +} + +FAnalyticsProviderAdjust::~FAnalyticsProviderAdjust() +{ + if (bHasSessionStarted) + { + EndSession(); + } +} + +bool FAnalyticsProviderAdjust::StartSession(const TArray& Attributes) +{ +#if WITH_ADJUST + const int32 AttrCount = Attributes.Num(); + + // add session attributes (this will be on all events) + + for (auto Attr : Attributes) + { + NSString* IOSKey = [NSString stringWithFString : Attr.AttrName]; + NSString* IOSValue = [NSString stringWithFString : Attr.AttrValue]; + [Adjust addSessionPartnerParameter:IOSKey value:IOSValue]; + } + RecordEvent(TEXT("SessionAttributes"), Attributes); + + if (!bHasSessionStarted) + { + UE_LOG(LogAnalytics, Display, TEXT("IOSAdjust::StartSession(%d attributes)"), AttrCount); + } + else + { + UE_LOG(LogAnalytics, Display, TEXT("IOSAdjust::RestartSession(%d attributes)"), AttrCount); + } + bHasSessionStarted = true; + return bHasSessionStarted; +#else + UE_LOG(LogAnalytics, Warning, TEXT("WITH_ADJUST=0. Are you missing the SDK?")); + return false; +#endif +} + +void FAnalyticsProviderAdjust::EndSession() +{ +#if WITH_ADJUST + bHasSessionStarted = false; + + UE_LOG(LogAnalytics, Display, TEXT("IOSAdjust::EndSession")); +#else + UE_LOG(LogAnalytics, Warning, TEXT("WITH_ADJUST=0. Are you missing the SDK?")); +#endif +} + +void FAnalyticsProviderAdjust::FlushEvents() +{ +#if WITH_ADJUST + [Adjust sendFirstPackages]; + UE_LOG(LogAnalytics, Display, TEXT("IOSAdjust::FlushEvents")); +#else + UE_LOG(LogAnalytics, Warning, TEXT("WITH_ADJUST=0. Are you missing the SDK?")); +#endif +} + +void FAnalyticsProviderAdjust::SetUserID(const FString& InUserID) +{ +#if WITH_ADJUST + UserId = InUserID; + UE_LOG(LogAnalytics, Display, TEXT("IOSAdjust::SetUserID(%s)"), *UserId); +#else + UE_LOG(LogAnalytics, Warning, TEXT("WITH_ADJUST=0. Are you missing the SDK?")); +#endif +} + +FString FAnalyticsProviderAdjust::GetUserID() const +{ +#if WITH_ADJUST + UE_LOG(LogAnalytics, Display, TEXT("IOSAdjust::GetUserID - returning cached id '%s'"), *UserId); + + return UserId; +#else + UE_LOG(LogAnalytics, Warning, TEXT("WITH_ADJUST=0. Are you missing the SDK?")); + return FString(); +#endif +} + +FString FAnalyticsProviderAdjust::GetSessionID() const +{ +#if WITH_ADJUST + FString Id = TEXT("unavailable"); + + UE_LOG(LogAnalytics, Display, TEXT("IOSAdjust::GetSessionID - returning the id as '%s'"), *Id); + + return Id; +#else + UE_LOG(LogAnalytics, Warning, TEXT("WITH_ADJUST=0. Are you missing the SDK?")); + return FString(); +#endif +} + +bool FAnalyticsProviderAdjust::SetSessionID(const FString& InSessionID) +{ +#if WITH_ADJUST + // Ignored + UE_LOG(LogAnalytics, Display, TEXT("IOSAdjust::SetSessionID - ignoring call")); + return false; +#else + UE_LOG(LogAnalytics, Warning, TEXT("WITH_ADJUST=0. Are you missing the SDK?")); + return false; +#endif +} + +void FAnalyticsProviderAdjust::RecordEvent(const FString& EventName, const TArray& Attributes) +{ +#if WITH_ADJUST + FString* EventTokenRef = EventMap.Find(EventName); + if (EventTokenRef != nullptr) + { + FString EventToken = *EventTokenRef; + NSString* IOSEventToken = [NSString stringWithFString : EventToken]; + + ADJEvent *event = [ADJEvent eventWithEventToken:IOSEventToken]; + const int32 AttrCount = Attributes.Num(); + if (AttrCount > 0) + { + // add event attributes + for (auto Attr : Attributes) + { + NSString* IOSKey = [NSString stringWithFString : Attr.AttrName]; + NSString* IOSValue = [NSString stringWithFString : Attr.AttrValue]; + [event addCallbackParameter:IOSKey value:IOSValue]; + } + } + [Adjust trackEvent:event]; + + UE_LOG(LogAnalytics, Display, TEXT("IOSAdjust::RecordEvent('%s', %d attributes) Token=%s"), *EventName, AttrCount, *EventToken); + } +#else + UE_LOG(LogAnalytics, Warning, TEXT("WITH_ADJUST=0. Are you missing the SDK?")); +#endif +} + +void FAnalyticsProviderAdjust::RecordItemPurchase(const FString& ItemId, const FString& Currency, int PerItemCost, int ItemQuantity) +{ +#if WITH_ADJUST + FString* EventTokenRef = EventMap.Find(TEXT("Item Purchase")); + if (EventTokenRef != nullptr) + { + FString EventToken = *EventTokenRef; + NSString* IOSEventToken = [NSString stringWithFString : EventToken]; + + ADJEvent *event = [ADJEvent eventWithEventToken:IOSEventToken]; + [event addCallbackParameter:@"ItemId" value:[NSString stringWithFString : ItemId]]; + [event addCallbackParameter:@"Currency" value:[NSString stringWithFString : Currency]]; + [event addCallbackParameter:@"PerItemCost" value:[NSString stringWithFormat:@"%d", PerItemCost]]; + [event addCallbackParameter:@"ItemQuantity" value:[NSString stringWithFormat:@"%d", ItemQuantity]]; + + // @TODO: This is probably wrong.. might just want to do a normal event and forget about revenue / order id (note: input is in cents so divide by 100) + [event setRevenue:(PerItemCost * ItemQuantity * 0.01) currency:[NSString stringWithFString : Currency]]; +// [event setTransactionId:[NSString stringWithFString : ItemId]]; + [Adjust trackEvent:event]; + + UE_LOG(LogAnalytics, Display, TEXT("IOSAdjust::RecordItemPurchase('%s', '%s', %d, %d) Token=%s"), *ItemId, *Currency, PerItemCost, ItemQuantity, *EventToken); + } +#else + UE_LOG(LogAnalytics, Warning, TEXT("WITH_ADJUST=0. Are you missing the SDK?")); +#endif +} + +void FAnalyticsProviderAdjust::RecordCurrencyPurchase(const FString& GameCurrencyType, int GameCurrencyAmount, const FString& RealCurrencyType, float RealMoneyCost, const FString& PaymentProvider) +{ +#if WITH_ADJUST + FString* EventTokenRef = EventMap.Find(TEXT("Currency Purchase")); + if (EventTokenRef != nullptr) + { + FString EventToken = *EventTokenRef; + NSString* IOSEventToken = [NSString stringWithFString : EventToken]; + + ADJEvent *event = [ADJEvent eventWithEventToken:IOSEventToken]; + [event addCallbackParameter:@"GameCurrencyType" value:[NSString stringWithFString : GameCurrencyType]]; + [event addCallbackParameter:@"GameCurrencyAmount" value:[NSString stringWithFormat:@"%d", GameCurrencyAmount]]; + [event addCallbackParameter:@"RealCurrencyType" value:[NSString stringWithFString : RealCurrencyType]]; + [event addCallbackParameter:@"RealMoneyCost" value:[NSString stringWithFormat:@"%.02f", RealMoneyCost]]; + [event addCallbackParameter:@"PaymentProvider" value:[NSString stringWithFString : PaymentProvider]]; + + [event setRevenue:RealMoneyCost currency:[NSString stringWithFString : RealCurrencyType]]; + [Adjust trackEvent:event]; + + UE_LOG(LogAnalytics, Display, TEXT("IOSAdjust::RecordCurrencyPurchase('%s', %d, '%s', %.02f, %s) Token=%s"), *GameCurrencyType, GameCurrencyAmount, *RealCurrencyType, RealMoneyCost, *PaymentProvider, *EventToken); + } +#else + UE_LOG(LogAnalytics, Warning, TEXT("WITH_ADJUST=0. Are you missing the SDK?")); +#endif +} + +void FAnalyticsProviderAdjust::RecordCurrencyGiven(const FString& GameCurrencyType, int GameCurrencyAmount) +{ +#if WITH_ADJUST + FString* EventTokenRef = EventMap.Find(TEXT("Currency Given")); + if (EventTokenRef != nullptr) + { + FString EventToken = *EventTokenRef; + NSString* IOSEventToken = [NSString stringWithFString : EventToken]; + + ADJEvent *event = [ADJEvent eventWithEventToken:IOSEventToken]; + [event addCallbackParameter:@"GameCurrencyType" value:[NSString stringWithFString : GameCurrencyType]]; + [event addCallbackParameter:@"GameCurrencyAmount" value:[NSString stringWithFormat:@"%d", GameCurrencyAmount]]; + + [Adjust trackEvent:event]; + + UE_LOG(LogAnalytics, Display, TEXT("IOSAdjust::RecordCurrencyGiven('%s', %d) Token=%s"), *GameCurrencyType, GameCurrencyAmount, *EventToken); + } +#else + UE_LOG(LogAnalytics, Warning, TEXT("WITH_ADJUST=0. Are you missing the SDK?")); +#endif +} + +void FAnalyticsProviderAdjust::RecordError(const FString& Error, const TArray& EventAttrs) +{ +#if WITH_ADJUST + FString* EventTokenRef = EventMap.Find(TEXT("Error")); + if (EventTokenRef != nullptr) + { + FString EventToken = *EventTokenRef; + NSString* IOSEventToken = [NSString stringWithFString : EventToken]; + + ADJEvent *event = [ADJEvent eventWithEventToken:IOSEventToken]; + + const int32 AttrCount = EventAttrs.Num(); + if (AttrCount > 0) + { + // add event attributes + for (auto Attr : EventAttrs) + { + NSString* IOSKey = [NSString stringWithFString : Attr.AttrName]; + NSString* IOSValue = [NSString stringWithFString : Attr.AttrValue]; + [event addCallbackParameter:IOSKey value:IOSValue]; + } + } + + [Adjust trackEvent:event]; + + UE_LOG(LogAnalytics, Display, TEXT("AndroidAdjust::RecordError('%s', %d) Token=%s"), *Error, AttrCount, *EventToken); + } +#else + UE_LOG(LogAnalytics, Warning, TEXT("WITH_ADJUST=0. Are you missing the SDK?")); +#endif +} + +void FAnalyticsProviderAdjust::RecordProgress(const FString& ProgressType, const FString& ProgressHierarchy, const TArray& EventAttrs) +{ +#if WITH_ADJUST + FString* EventTokenRef = EventMap.Find(TEXT("Progress")); + if (EventTokenRef != nullptr) + { + FString EventToken = *EventTokenRef; + NSString* IOSEventToken = [NSString stringWithFString : EventToken]; + + ADJEvent *event = [ADJEvent eventWithEventToken:IOSEventToken]; + + [event addCallbackParameter:@"ProgressType" value:[NSString stringWithFString : ProgressType]]; + [event addCallbackParameter:@"ProgressHierarchy" value:[NSString stringWithFString : ProgressHierarchy]]; + + const int32 AttrCount = EventAttrs.Num(); + if (AttrCount > 0) + { + // add event attributes + for (auto Attr : EventAttrs) + { + NSString* IOSKey = [NSString stringWithFString : Attr.AttrName]; + NSString* IOSValue = [NSString stringWithFString : Attr.AttrValue]; + [event addCallbackParameter:IOSKey value:IOSValue]; + } + } + + [Adjust trackEvent:event]; + + UE_LOG(LogAnalytics, Display, TEXT("AndroidAdjust::RecordProgress('%s', '%s', %d) Token=%s"), *ProgressType, *ProgressHierarchy, AttrCount, *EventToken); + } +#else + UE_LOG(LogAnalytics, Warning, TEXT("WITH_ADJUST=0. Are you missing the SDK?")); +#endif +} diff --git a/Engine/Plugins/Runtime/Analytics/Adjust/Source/IOSAdjust/Private/IOSAdjustPrivatePCH.h b/Engine/Plugins/Runtime/Analytics/Adjust/Source/IOSAdjust/Private/IOSAdjustPrivatePCH.h new file mode 100644 index 000000000000..4347c3a1fb9e --- /dev/null +++ b/Engine/Plugins/Runtime/Analytics/Adjust/Source/IOSAdjust/Private/IOSAdjustPrivatePCH.h @@ -0,0 +1,12 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#include "CoreMinimal.h" + +#include "IOSAdjust.h" +#include "IOSAdjustProvider.h" + +#if WITH_ADJUST +#endif + +// You should place include statements to your module's private header files here. You only need to +// add includes for headers that are used in most of your module's source files though. diff --git a/Engine/Plugins/Runtime/Analytics/Adjust/Source/IOSAdjust/Private/IOSAdjustProvider.h b/Engine/Plugins/Runtime/Analytics/Adjust/Source/IOSAdjust/Private/IOSAdjustProvider.h new file mode 100644 index 000000000000..e31f39d239a6 --- /dev/null +++ b/Engine/Plugins/Runtime/Analytics/Adjust/Source/IOSAdjust/Private/IOSAdjustProvider.h @@ -0,0 +1,56 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "IAnalyticsProvider.h" + +class FAnalyticsProviderAdjust : + public IAnalyticsProvider +{ + /** The AppToken given to you by Adjust dashboard */ + FString AppToken; + /** Tracks whether we need to start the session or restart it */ + bool bHasSessionStarted; + /** Cached user id */ + FString UserId; + /** Event name to token mapping */ + TMap EventMap; + + /** Singleton for analytics */ + static TSharedPtr Provider; + FAnalyticsProviderAdjust(const FString InAppToken, bool bInSandbox, const FString InLogLevel, const FString InDefaultTracker, bool bInEventBuffering, bool bSendInBackground, float InDelayStart); + +public: + static TSharedPtr Create(const FString InAppToken, bool bInSandbox, const FString InLogLevel, const FString InDefaultTracker, bool bInEventBuffering, bool bSendInBackground, float InDelayStart) + { + if (!Provider.IsValid()) + { + Provider = TSharedPtr(new FAnalyticsProviderAdjust(InAppToken, bInSandbox,InLogLevel, InDefaultTracker, bInEventBuffering, bSendInBackground, InDelayStart)); + } + return Provider; + } + static void Destroy() + { + Provider.Reset(); + } + + virtual ~FAnalyticsProviderAdjust(); + + virtual bool StartSession(const TArray& Attributes) override; + virtual void EndSession() override; + virtual void FlushEvents() override; + + virtual void SetUserID(const FString& InUserID) override; + virtual FString GetUserID() const override; + + virtual FString GetSessionID() const override; + virtual bool SetSessionID(const FString& InSessionID) override; + + virtual void RecordEvent(const FString& EventName, const TArray& Attributes) override; + virtual void RecordItemPurchase(const FString& ItemId, const FString& Currency, int PerItemCost, int ItemQuantity) override; + virtual void RecordCurrencyPurchase(const FString& GameCurrencyType, int GameCurrencyAmount, const FString& RealCurrencyType, float RealMoneyCost, const FString& PaymentProvider) override; + virtual void RecordCurrencyGiven(const FString& GameCurrencyType, int GameCurrencyAmount) override; + + virtual void RecordError(const FString& Error, const TArray& EventAttrs) override; + virtual void RecordProgress(const FString& ProgressType, const FString& ProgressHierarchy, const TArray& EventAttrs) override; +}; diff --git a/Engine/Plugins/Runtime/Analytics/Adjust/Source/IOSAdjust/Public/IOSAdjust.h b/Engine/Plugins/Runtime/Analytics/Adjust/Source/IOSAdjust/Public/IOSAdjust.h new file mode 100644 index 000000000000..be36d7d3ab9e --- /dev/null +++ b/Engine/Plugins/Runtime/Analytics/Adjust/Source/IOSAdjust/Public/IOSAdjust.h @@ -0,0 +1,46 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "IAnalyticsProviderModule.h" +#include "ModuleManager.h" + +class IAnalyticsProvider; + +/** + * The public interface to this module + */ +class FAnalyticsIOSAdjust : + public IAnalyticsProviderModule +{ + //-------------------------------------------------------------------------- + // Module functionality + //-------------------------------------------------------------------------- +public: + /** + * Singleton-like access to this module's interface. This is just for convenience! + * Beware of calling this during the shutdown phase, though. Your module might have been unloaded already. + * + * @return Returns singleton instance, loading the module on demand if needed + */ + static inline FAnalyticsIOSAdjust& Get() + { + return FModuleManager::LoadModuleChecked< FAnalyticsIOSAdjust >( "IOSAdjust" ); + } + + //-------------------------------------------------------------------------- + // provider factory functions + //-------------------------------------------------------------------------- +public: + /** + * IAnalyticsProviderModule interface. + * Creates the analytics provider given a configuration delegate. + * The keys required exactly match the field names in the Config object. + */ + virtual TSharedPtr CreateAnalyticsProvider(const FAnalyticsProviderConfigurationDelegate& GetConfigValue) const override; + +private: + virtual void StartupModule() override; + virtual void ShutdownModule() override; +}; + diff --git a/Engine/Plugins/Runtime/Analytics/Adjust/ThirdPartyFrameworks/AdjustSdk.tps b/Engine/Plugins/Runtime/Analytics/Adjust/ThirdPartyFrameworks/AdjustSdk.tps new file mode 100644 index 000000000000..dcf50817b9d2 --- /dev/null +++ b/Engine/Plugins/Runtime/Analytics/Adjust/ThirdPartyFrameworks/AdjustSdk.tps @@ -0,0 +1,15 @@ + + + TapJoy SDK + /Engine/Plugins/Runtime/Advertising/IOSTapJoy/ThirdPartyFrameworks + 2016-11-09T19:10:57.4480563-05:00 + Tracks ad conversions from Tapjoy ads + Redistributed to licensees along with UE4 so they don't have to download it themselves. Hooks into our UE4 TapJoy plugin + Custom agreement between Epic/TapJoy + + Licensees + Git + P4 + + None + \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Analytics/Adjust/ThirdPartyFrameworks/AdjustiOSSDK.tps b/Engine/Plugins/Runtime/Analytics/Adjust/ThirdPartyFrameworks/AdjustiOSSDK.tps new file mode 100644 index 000000000000..846938cc9b8d --- /dev/null +++ b/Engine/Plugins/Runtime/Analytics/Adjust/ThirdPartyFrameworks/AdjustiOSSDK.tps @@ -0,0 +1,15 @@ + + + Adjust iOS SDK + /Engine/Plugins/Runtime/Analytics/Adjust/ThirdPartyFrameworks/ + 2016-11-21T12:05:04.0964372-05:00 + For tracking analytics on mobile, similar to Flurry + Needed for WEX + https://github.com/adjust/ios_sdk/blob/master/MIT-LICENSE + + Licensees + Git + P4 + + /Engine/Plugins/Runtime/Analytics/Adjust/ThirdPartyFrameworks/AdjustiOSSDK_License.txt + \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Analytics/Adjust/ThirdPartyFrameworks/AdjustiOSSDK_License.txt b/Engine/Plugins/Runtime/Analytics/Adjust/ThirdPartyFrameworks/AdjustiOSSDK_License.txt new file mode 100644 index 000000000000..fb73d0e082ed --- /dev/null +++ b/Engine/Plugins/Runtime/Analytics/Adjust/ThirdPartyFrameworks/AdjustiOSSDK_License.txt @@ -0,0 +1,21 @@ +Copyright (c) 2012-2014 adjust GmbH, +http://www.adjust.com + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Analytics/AnalyticsMulticast/Source/AnalyticsMulticast/Private/AnalyticsMulticast.cpp b/Engine/Plugins/Runtime/Analytics/AnalyticsMulticast/Source/AnalyticsMulticast/Private/AnalyticsMulticast.cpp index a53400dbe048..9f3c061e1c20 100644 --- a/Engine/Plugins/Runtime/Analytics/AnalyticsMulticast/Source/AnalyticsMulticast/Private/AnalyticsMulticast.cpp +++ b/Engine/Plugins/Runtime/Analytics/AnalyticsMulticast/Source/AnalyticsMulticast/Private/AnalyticsMulticast.cpp @@ -6,8 +6,6 @@ #include "Analytics.h" -DEFINE_LOG_CATEGORY_STATIC(LogAnalytics, Display, All); - IMPLEMENT_MODULE( FAnalyticsMulticast, AnalyticsMulticast ); class FAnalyticsProviderMulticast : public IAnalyticsProvider diff --git a/Engine/Plugins/Runtime/Analytics/Apsalar/Source/IOSApsalar/Private/IOSApsalar.cpp b/Engine/Plugins/Runtime/Analytics/Apsalar/Source/IOSApsalar/Private/IOSApsalar.cpp index f664b56de328..78ec88ea19d7 100644 --- a/Engine/Plugins/Runtime/Analytics/Apsalar/Source/IOSApsalar/Private/IOSApsalar.cpp +++ b/Engine/Plugins/Runtime/Analytics/Apsalar/Source/IOSApsalar/Private/IOSApsalar.cpp @@ -8,7 +8,7 @@ #import "Apsalar.h" #endif -DEFINE_LOG_CATEGORY_STATIC(LogAnalytics, Display, All); +#include "Analytics.h" IMPLEMENT_MODULE( FAnalyticsIOSApsalar, IOSApsalar ) diff --git a/Engine/Plugins/Runtime/Analytics/Flurry/Source/IOSFlurry/Source/IOSFlurry/Private/IOSFlurry.cpp b/Engine/Plugins/Runtime/Analytics/Flurry/Source/IOSFlurry/Source/IOSFlurry/Private/IOSFlurry.cpp index 61c3cd6bafc7..ef9c33be51e8 100644 --- a/Engine/Plugins/Runtime/Analytics/Flurry/Source/IOSFlurry/Source/IOSFlurry/Private/IOSFlurry.cpp +++ b/Engine/Plugins/Runtime/Analytics/Flurry/Source/IOSFlurry/Source/IOSFlurry/Private/IOSFlurry.cpp @@ -7,7 +7,7 @@ #import "Flurry.h" #endif -DEFINE_LOG_CATEGORY_STATIC(LogAnalytics, Display, All); +#include "Analytics.h" IMPLEMENT_MODULE( FAnalyticsIOSFlurry, IOSFlurry ) diff --git a/Engine/Plugins/Runtime/AndroidDeviceProfileSelector/Source/AndroidDeviceProfileSelector/AndroidDeviceProfileSelector.Build.cs b/Engine/Plugins/Runtime/AndroidDeviceProfileSelector/Source/AndroidDeviceProfileSelector/AndroidDeviceProfileSelector.Build.cs index d0390da38e72..eb991e472a63 100644 --- a/Engine/Plugins/Runtime/AndroidDeviceProfileSelector/Source/AndroidDeviceProfileSelector/AndroidDeviceProfileSelector.Build.cs +++ b/Engine/Plugins/Runtime/AndroidDeviceProfileSelector/Source/AndroidDeviceProfileSelector/AndroidDeviceProfileSelector.Build.cs @@ -6,6 +6,8 @@ namespace UnrealBuildTool.Rules { public AndroidDeviceProfileSelector(ReadOnlyTargetRules Target) : base(Target) { + ShortName = "AndroidDPS"; + PublicIncludePaths.AddRange( new string[] { "Runtime/AndroidDeviceProfileSelector/Public", diff --git a/Engine/Plugins/Runtime/AndroidPermission/Source/AndroidPermission/Private/AndroidPermissionFunctionLibrary.cpp b/Engine/Plugins/Runtime/AndroidPermission/Source/AndroidPermission/Private/AndroidPermissionFunctionLibrary.cpp index a19d922a02c0..3a41a170e73e 100644 --- a/Engine/Plugins/Runtime/AndroidPermission/Source/AndroidPermission/Private/AndroidPermissionFunctionLibrary.cpp +++ b/Engine/Plugins/Runtime/AndroidPermission/Source/AndroidPermission/Private/AndroidPermissionFunctionLibrary.cpp @@ -25,6 +25,8 @@ static jmethodID _CheckPermissionMethodId; static jmethodID _AcquirePermissionMethodId; #endif +DEFINE_LOG_CATEGORY(LogAndroidPermission); + void UAndroidPermissionFunctionLibrary::Initialize() { #if PLATFORM_ANDROID diff --git a/Engine/Plugins/Runtime/AndroidPermission/Source/AndroidPermission/Public/AndroidPermission.h b/Engine/Plugins/Runtime/AndroidPermission/Source/AndroidPermission/Public/AndroidPermission.h index ca45c6a567d8..1527bb55ba02 100644 --- a/Engine/Plugins/Runtime/AndroidPermission/Source/AndroidPermission/Public/AndroidPermission.h +++ b/Engine/Plugins/Runtime/AndroidPermission/Source/AndroidPermission/Public/AndroidPermission.h @@ -17,7 +17,7 @@ #include "ModuleManager.h" -DEFINE_LOG_CATEGORY_STATIC(LogAndroidPermission, Log, All); +ANDROIDPERMISSION_API DECLARE_LOG_CATEGORY_EXTERN(LogAndroidPermission, Log, All); class FAndroidPermissionModule : public IModuleInterface { diff --git a/Engine/Plugins/Runtime/CableComponent/Source/CableComponent/Classes/CableComponent.h b/Engine/Plugins/Runtime/CableComponent/Source/CableComponent/Classes/CableComponent.h index 28e1550191b9..6e8dffa6d165 100644 --- a/Engine/Plugins/Runtime/CableComponent/Source/CableComponent/Classes/CableComponent.h +++ b/Engine/Plugins/Runtime/CableComponent/Source/CableComponent/Classes/CableComponent.h @@ -39,6 +39,7 @@ public: virtual void OnRegister() override; virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override; virtual void SendRenderDynamicData_Concurrent() override; + virtual void CreateRenderState_Concurrent() override; //~ Begin UActorComponent Interface. //~ Begin USceneComponent Interface. diff --git a/Engine/Plugins/Runtime/CableComponent/Source/CableComponent/Private/CableComponent.cpp b/Engine/Plugins/Runtime/CableComponent/Source/CableComponent/Private/CableComponent.cpp index 96217c9cfbbd..ca9814fb7974 100644 --- a/Engine/Plugins/Runtime/CableComponent/Source/CableComponent/Private/CableComponent.cpp +++ b/Engine/Plugins/Runtime/CableComponent/Source/CableComponent/Private/CableComponent.cpp @@ -508,8 +508,7 @@ void UCableComponent::PerformCableCollision() if (World && GetCollisionEnabled() != ECollisionEnabled::NoCollision) { // Get collision settings from component - static FName CableCollisionName(TEXT("CableCollision")); - FCollisionQueryParams Params(CableCollisionName); + FCollisionQueryParams Params(SCENE_QUERY_STAT(CableCollision)); ECollisionChannel TraceChannel = GetCollisionObjectType(); FCollisionResponseParams ResponseParams(GetCollisionResponseToChannels()); @@ -676,6 +675,13 @@ void UCableComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, F UpdateComponentToWorld(); }; +void UCableComponent::CreateRenderState_Concurrent() +{ + Super::CreateRenderState_Concurrent(); + + SendRenderDynamicData_Concurrent(); +} + void UCableComponent::SendRenderDynamicData_Concurrent() { if(SceneProxy) diff --git a/Engine/Plugins/Runtime/GameplayAbilities/GameplayAbilities.uplugin b/Engine/Plugins/Runtime/GameplayAbilities/GameplayAbilities.uplugin index 538ec2399a17..b95542d12bd7 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/GameplayAbilities.uplugin +++ b/Engine/Plugins/Runtime/GameplayAbilities/GameplayAbilities.uplugin @@ -26,5 +26,12 @@ "Type" : "Developer", "LoadingPhase" : "PreDefault" } + ], + "Plugins": [ + { + "Name": "GameplayTagsEditor", + "Enabled": true + } ] + } \ No newline at end of file diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/GameplayAbility.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/GameplayAbility.cpp index 678671098ade..29ad51a4d524 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/GameplayAbility.cpp +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/GameplayAbility.cpp @@ -275,7 +275,7 @@ bool UGameplayAbility::CanActivateAbility(const FGameplayAbilitySpecHandle Handl FGameplayTagContainer& OutTags = OptionalRelevantTags ? *OptionalRelevantTags : DummyContainer; // make sure the ActorInfo and its ability system component are valid, if not bail out. - if (ActorInfo == nullptr || !ActorInfo->AbilitySystemComponent.IsValid()) + if (!ActorInfo->AbilitySystemComponent.IsValid()) { return false; } @@ -541,7 +541,7 @@ bool UGameplayAbility::IsEndAbilityValid(const FGameplayAbilitySpecHandle Handle } // check to see if this is an NonInstanced or if the ability is active. - const FGameplayAbilitySpec* Spec = AbilityComp ? AbilityComp->FindAbilitySpecFromHandle(Handle) : nullptr; + const FGameplayAbilitySpec* Spec = AbilityComp->FindAbilitySpecFromHandle(Handle); const bool bIsSpecActive = Spec ? Spec->IsActive() : IsActive(); if (!bIsSpecActive) diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/GameplayAbilityTargetActor.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/GameplayAbilityTargetActor.cpp index 3403c14bea69..87dfc8b40c9c 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/GameplayAbilityTargetActor.cpp +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/GameplayAbilityTargetActor.cpp @@ -143,7 +143,7 @@ bool AGameplayAbilityTargetActor::OnReplicatedTargetDataReceived(FGameplayAbilit bool AGameplayAbilityTargetActor::ShouldProduceTargetData() const { // return true if we are locally owned, or (we are the server and this is a gameplaytarget ability that can produce target data server side) - return (MasterPC && (MasterPC->IsLocalController() || ShouldProduceTargetDataOnServer)); + return (MasterPC && MasterPC->IsLocalController()) || ShouldProduceTargetDataOnServer; } void AGameplayAbilityTargetActor::BindToConfirmCancelInputs() diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/GameplayAbilityTargetActor_GroundTrace.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/GameplayAbilityTargetActor_GroundTrace.cpp index 43ee731f17ad..e93c5ebb0823 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/GameplayAbilityTargetActor_GroundTrace.cpp +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/GameplayAbilityTargetActor_GroundTrace.cpp @@ -140,10 +140,9 @@ bool AGameplayAbilityTargetActor_GroundTrace::AdjustCollisionResultForShape(cons FHitResult AGameplayAbilityTargetActor_GroundTrace::PerformTrace(AActor* InSourceActor) { - static const FName LineTraceSingleName(TEXT("AGameplayAbilityTargetActor_GroundTrace")); bool bTraceComplex = false; - FCollisionQueryParams Params(LineTraceSingleName, bTraceComplex); + FCollisionQueryParams Params(SCENE_QUERY_STAT(AGameplayAbilityTargetActor_GroundTrace), bTraceComplex); Params.bReturnPhysicalMaterial = true; Params.bTraceAsyncScene = true; Params.AddIgnoredActor(InSourceActor); diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/GameplayAbilityTargetActor_Radius.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/GameplayAbilityTargetActor_Radius.cpp index af3e9a6ca21c..f28612d06dea 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/GameplayAbilityTargetActor_Radius.cpp +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/GameplayAbilityTargetActor_Radius.cpp @@ -49,10 +49,9 @@ FGameplayAbilityTargetDataHandle AGameplayAbilityTargetActor_Radius::MakeTargetD TArray > AGameplayAbilityTargetActor_Radius::PerformOverlap(const FVector& Origin) { - static FName RadiusTargetingOverlap = FName(TEXT("RadiusTargetingOverlap")); bool bTraceComplex = false; - FCollisionQueryParams Params(RadiusTargetingOverlap, bTraceComplex); + FCollisionQueryParams Params(SCENE_QUERY_STAT(RadiusTargetingOverlap), bTraceComplex); Params.bReturnPhysicalMaterial = false; Params.bTraceAsyncScene = false; diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/GameplayAbilityTargetActor_SingleLineTrace.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/GameplayAbilityTargetActor_SingleLineTrace.cpp index 0e0d9fd00c04..ae352242e485 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/GameplayAbilityTargetActor_SingleLineTrace.cpp +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/GameplayAbilityTargetActor_SingleLineTrace.cpp @@ -16,13 +16,12 @@ AGameplayAbilityTargetActor_SingleLineTrace::AGameplayAbilityTargetActor_SingleL FHitResult AGameplayAbilityTargetActor_SingleLineTrace::PerformTrace(AActor* InSourceActor) { - static const FName LineTraceSingleName(TEXT("AGameplayAbilityTargetActor_SingleLineTrace")); bool bTraceComplex = false; TArray ActorsToIgnore; ActorsToIgnore.Add(InSourceActor); - FCollisionQueryParams Params(LineTraceSingleName, bTraceComplex); + FCollisionQueryParams Params(SCENE_QUERY_STAT(AGameplayAbilityTargetActor_SingleLineTrace), bTraceComplex); Params.bReturnPhysicalMaterial = true; Params.bTraceAsyncScene = true; Params.AddIgnoredActors(ActorsToIgnore); diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/GameplayAbilityWorldReticle_ActorVisualization.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/GameplayAbilityWorldReticle_ActorVisualization.cpp index 018ac1123f9e..19fd2a86eff7 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/GameplayAbilityWorldReticle_ActorVisualization.cpp +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/GameplayAbilityWorldReticle_ActorVisualization.cpp @@ -69,6 +69,3 @@ void AGameplayAbilityWorldReticle_ActorVisualization::EndPlay(const EEndPlayReas { Super::EndPlay(EndPlayReason); } - -/** Returns CollisionComponent subobject **/ -UCapsuleComponent* AGameplayAbilityWorldReticle_ActorVisualization::GetCollisionComponent() { return CollisionComponent; } diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitAbilityActivate.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitAbilityActivate.cpp index 4bec5936a9b1..8ee855e4735e 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitAbilityActivate.cpp +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitAbilityActivate.cpp @@ -30,6 +30,16 @@ UAbilityTask_WaitAbilityActivate* UAbilityTask_WaitAbilityActivate::WaitForAbili return MyObj; } +UAbilityTask_WaitAbilityActivate* UAbilityTask_WaitAbilityActivate::WaitForAbilityActivate_Query(UGameplayAbility* OwningAbility, FGameplayTagQuery Query, bool InIncludeTriggeredAbilities, bool InTriggerOnce) +{ + auto MyObj = NewAbilityTask(OwningAbility); + MyObj->Query = Query; + MyObj->IncludeTriggeredAbilities = InIncludeTriggeredAbilities; + MyObj->TriggerOnce = InTriggerOnce; + return MyObj; + +} + void UAbilityTask_WaitAbilityActivate::Activate() { if (AbilitySystemComponent) @@ -63,6 +73,15 @@ void UAbilityTask_WaitAbilityActivate::OnAbilityActivate(UGameplayAbility* Activ } } + if (Query.IsEmpty() == false) + { + if (Query.Matches(ActivatedAbility->AbilityTags) == false) + { + // Failed query + return; + } + } + if (ShouldBroadcastAbilityTaskDelegates()) { OnActivate.Broadcast(ActivatedAbility); diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitAbilityCommit.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitAbilityCommit.cpp index 210598f8ea35..f2b8d7691e95 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitAbilityCommit.cpp +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitAbilityCommit.cpp @@ -21,6 +21,14 @@ UAbilityTask_WaitAbilityCommit* UAbilityTask_WaitAbilityCommit::WaitForAbilityCo return MyObj; } +UAbilityTask_WaitAbilityCommit* UAbilityTask_WaitAbilityCommit::WaitForAbilityCommit_Query(UGameplayAbility* OwningAbility, FGameplayTagQuery Query, bool InTriggerOnce) +{ + auto MyObj = NewAbilityTask(OwningAbility); + MyObj->Query = Query; + MyObj->TriggerOnce = InTriggerOnce; + return MyObj; +} + void UAbilityTask_WaitAbilityCommit::Activate() { if (AbilitySystemComponent) @@ -48,6 +56,15 @@ void UAbilityTask_WaitAbilityCommit::OnAbilityCommit(UGameplayAbility *Activated return; } + if (Query.IsEmpty() == false) + { + if (Query.Matches(ActivatedAbility->AbilityTags) == false) + { + // Failed query + return; + } + } + if (ShouldBroadcastAbilityTaskDelegates()) { OnCommit.Broadcast(ActivatedAbility); diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitAttributeChange.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitAttributeChange.cpp index a16ed43ea594..d821bdb3d091 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitAttributeChange.cpp +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitAttributeChange.cpp @@ -41,12 +41,15 @@ void UAbilityTask_WaitAttributeChange::Activate() { if (AbilitySystemComponent) { - OnAttributeChangeDelegateHandle = AbilitySystemComponent->RegisterGameplayAttributeEvent(Attribute).AddUObject(this, &UAbilityTask_WaitAttributeChange::OnAttributeChange); + OnAttributeChangeDelegateHandle = AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(Attribute).AddUObject(this, &UAbilityTask_WaitAttributeChange::OnAttributeChange); } } -void UAbilityTask_WaitAttributeChange::OnAttributeChange(float NewValue, const FGameplayEffectModCallbackData* Data) +void UAbilityTask_WaitAttributeChange::OnAttributeChange(const FOnAttributeChangeData& CallbackData) { + float NewValue = CallbackData.NewValue; + const FGameplayEffectModCallbackData* Data = CallbackData.GEModData; + if (Data == nullptr) { // There may be no execution data associated with this change, for example a GE being removed. @@ -107,7 +110,7 @@ void UAbilityTask_WaitAttributeChange::OnDestroy(bool AbilityEnded) { if (AbilitySystemComponent) { - AbilitySystemComponent->RegisterGameplayAttributeEvent(Attribute).Remove(OnAttributeChangeDelegateHandle); + AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(Attribute).Remove(OnAttributeChangeDelegateHandle); } Super::OnDestroy(AbilityEnded); diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitAttributeChangeRatioThreshold.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitAttributeChangeRatioThreshold.cpp index b97be1af687c..1b0df2b1c883 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitAttributeChangeRatioThreshold.cpp +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitAttributeChangeRatioThreshold.cpp @@ -41,8 +41,8 @@ void UAbilityTask_WaitAttributeChangeRatioThreshold::Activate() OnChange.Broadcast(bMatchedComparisonLastAttributeChange, LastAttributeDenominatorValue != 0.f ? LastAttributeNumeratorValue/LastAttributeDenominatorValue : 0.f); } - OnNumeratorAttributeChangeDelegateHandle = AbilitySystemComponent->RegisterGameplayAttributeEvent(AttributeNumerator).AddUObject(this, &UAbilityTask_WaitAttributeChangeRatioThreshold::OnNumeratorAttributeChange); - OnDenominatorAttributeChangeDelegateHandle = AbilitySystemComponent->RegisterGameplayAttributeEvent(AttributeDenominator).AddUObject(this, &UAbilityTask_WaitAttributeChangeRatioThreshold::OnDenominatorAttributeChange); + OnNumeratorAttributeChangeDelegateHandle = AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(AttributeNumerator).AddUObject(this, &UAbilityTask_WaitAttributeChangeRatioThreshold::OnNumeratorAttributeChange); + OnDenominatorAttributeChangeDelegateHandle = AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(AttributeDenominator).AddUObject(this, &UAbilityTask_WaitAttributeChangeRatioThreshold::OnDenominatorAttributeChange); } } @@ -76,15 +76,15 @@ void UAbilityTask_WaitAttributeChangeRatioThreshold::OnRatioChange() } } -void UAbilityTask_WaitAttributeChangeRatioThreshold::OnNumeratorAttributeChange(float NewValue, const FGameplayEffectModCallbackData* Data) +void UAbilityTask_WaitAttributeChangeRatioThreshold::OnNumeratorAttributeChange(const FOnAttributeChangeData& CallbackData) { - LastAttributeNumeratorValue = NewValue; + LastAttributeNumeratorValue = CallbackData.NewValue; OnAttributeChange(); } -void UAbilityTask_WaitAttributeChangeRatioThreshold::OnDenominatorAttributeChange(float NewValue, const FGameplayEffectModCallbackData* Data) +void UAbilityTask_WaitAttributeChangeRatioThreshold::OnDenominatorAttributeChange(const FOnAttributeChangeData& CallbackData) { - LastAttributeDenominatorValue = NewValue; + LastAttributeDenominatorValue = CallbackData.NewValue; OnAttributeChange(); } @@ -127,8 +127,8 @@ void UAbilityTask_WaitAttributeChangeRatioThreshold::OnDestroy(bool AbilityEnded { if (AbilitySystemComponent) { - AbilitySystemComponent->RegisterGameplayAttributeEvent(AttributeNumerator).Remove(OnNumeratorAttributeChangeDelegateHandle); - AbilitySystemComponent->RegisterGameplayAttributeEvent(AttributeDenominator).Remove(OnDenominatorAttributeChangeDelegateHandle); + AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(AttributeNumerator).Remove(OnNumeratorAttributeChangeDelegateHandle); + AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(AttributeDenominator).Remove(OnDenominatorAttributeChangeDelegateHandle); } Super::OnDestroy(AbilityEnded); diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitAttributeChangeThreshold.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitAttributeChangeThreshold.cpp index b0831e877d31..5437186456dc 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitAttributeChangeThreshold.cpp +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitAttributeChangeThreshold.cpp @@ -36,12 +36,14 @@ void UAbilityTask_WaitAttributeChangeThreshold::Activate() OnChange.Broadcast(bMatchedComparisonLastAttributeChange, CurrentValue); } - OnAttributeChangeDelegateHandle = AbilitySystemComponent->RegisterGameplayAttributeEvent(Attribute).AddUObject(this, &UAbilityTask_WaitAttributeChangeThreshold::OnAttributeChange); + OnAttributeChangeDelegateHandle = AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(Attribute).AddUObject(this, &UAbilityTask_WaitAttributeChangeThreshold::OnAttributeChange); } } -void UAbilityTask_WaitAttributeChangeThreshold::OnAttributeChange(float NewValue, const FGameplayEffectModCallbackData* Data) +void UAbilityTask_WaitAttributeChangeThreshold::OnAttributeChange(const FOnAttributeChangeData& CallbackData) { + float NewValue = CallbackData.NewValue; + bool bPassedComparison = DoesValuePassComparison(NewValue); if (bPassedComparison != bMatchedComparisonLastAttributeChange) { @@ -90,7 +92,7 @@ void UAbilityTask_WaitAttributeChangeThreshold::OnDestroy(bool AbilityEnded) { if (AbilitySystemComponent) { - AbilitySystemComponent->RegisterGameplayAttributeEvent(Attribute).Remove(OnAttributeChangeDelegateHandle); + AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(Attribute).Remove(OnAttributeChangeDelegateHandle); } Super::OnDestroy(AbilityEnded); diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitGameplayEffectApplied.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitGameplayEffectApplied.cpp index 06419c2d231c..5153cca3611e 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitGameplayEffectApplied.cpp +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitGameplayEffectApplied.cpp @@ -37,6 +37,22 @@ void UAbilityTask_WaitGameplayEffectApplied::OnApplyGameplayEffectCallback(UAbil return; } + if (SourceTagQuery.IsEmpty() == false) + { + if (!SourceTagQuery.Matches(*SpecApplied.CapturedSourceTags.GetAggregatedTags())) + { + return; + } + } + + if (TargetTagQuery.IsEmpty() == false) + { + if (!TargetTagQuery.Matches(*SpecApplied.CapturedTargetTags.GetAggregatedTags())) + { + return; + } + } + if (Locked) { ABILITY_LOG(Error, TEXT("WaitGameplayEffectApplied recursion detected. Ability: %s. Applied Spec: %s. This could cause an infinite loop! Ignoring"), *GetNameSafe(Ability), *SpecApplied.ToSimpleString()); diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitGameplayEffectApplied_Self.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitGameplayEffectApplied_Self.cpp index e3a04aa1c276..069f8a1f90de 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitGameplayEffectApplied_Self.cpp +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitGameplayEffectApplied_Self.cpp @@ -22,6 +22,18 @@ UAbilityTask_WaitGameplayEffectApplied_Self* UAbilityTask_WaitGameplayEffectAppl return MyObj; } +UAbilityTask_WaitGameplayEffectApplied_Self* UAbilityTask_WaitGameplayEffectApplied_Self::WaitGameplayEffectAppliedToSelf_Query(UGameplayAbility* OwningAbility, const FGameplayTargetDataFilterHandle InFilter, FGameplayTagQuery InSourceTagQuery, FGameplayTagQuery InTargetTagQuery, bool InTriggerOnce, AActor* OptionalExternalOwner, bool InListenForPeriodicEffect) +{ + auto MyObj = NewAbilityTask(OwningAbility); + MyObj->Filter = InFilter; + MyObj->SourceTagQuery = InSourceTagQuery; + MyObj->TargetTagQuery = InTargetTagQuery; + MyObj->TriggerOnce = InTriggerOnce; + MyObj->SetExternalActor(OptionalExternalOwner); + MyObj->ListenForPeriodicEffects = InListenForPeriodicEffect; + return MyObj; +} + void UAbilityTask_WaitGameplayEffectApplied_Self::BroadcastDelegate(AActor* Avatar, FGameplayEffectSpecHandle SpecHandle, FActiveGameplayEffectHandle ActiveHandle) { if (ShouldBroadcastAbilityTaskDelegates()) diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitGameplayEffectApplied_Target.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitGameplayEffectApplied_Target.cpp index 43c1afa16df7..8b5bb94b1be1 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitGameplayEffectApplied_Target.cpp +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/Abilities/Tasks/AbilityTask_WaitGameplayEffectApplied_Target.cpp @@ -22,6 +22,18 @@ UAbilityTask_WaitGameplayEffectApplied_Target* UAbilityTask_WaitGameplayEffectAp return MyObj; } +UAbilityTask_WaitGameplayEffectApplied_Target* UAbilityTask_WaitGameplayEffectApplied_Target::WaitGameplayEffectAppliedToTarget_Query(UGameplayAbility* OwningAbility, const FGameplayTargetDataFilterHandle InFilter, FGameplayTagQuery SourceTagQuery, FGameplayTagQuery TargetTagQuery, bool InTriggerOnce, AActor* OptionalExternalOwner, bool InListenForPeriodicEffect) +{ + auto MyObj = NewAbilityTask(OwningAbility); + MyObj->Filter = InFilter; + MyObj->SourceTagQuery = SourceTagQuery; + MyObj->TargetTagQuery = TargetTagQuery; + MyObj->TriggerOnce = InTriggerOnce; + MyObj->SetExternalActor(OptionalExternalOwner); + MyObj->ListenForPeriodicEffects = InListenForPeriodicEffect; + return MyObj; +} + void UAbilityTask_WaitGameplayEffectApplied_Target::BroadcastDelegate(AActor* Avatar, FGameplayEffectSpecHandle SpecHandle, FActiveGameplayEffectHandle ActiveHandle) { if (ShouldBroadcastAbilityTaskDelegates()) diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AbilitySystemBlueprintLibrary.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AbilitySystemBlueprintLibrary.cpp index 0ae0d36f9c88..9dea2085b3f6 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AbilitySystemBlueprintLibrary.cpp +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AbilitySystemBlueprintLibrary.cpp @@ -660,7 +660,11 @@ FGameplayEffectSpecHandle UAbilitySystemBlueprintLibrary::AssignSetByCallerMagni FGameplayEffectSpec* Spec = SpecHandle.Data.Get(); if (Spec) { + PRAGMA_DISABLE_DEPRECATION_WARNINGS + Spec->SetSetByCallerMagnitude(DataName, Magnitude); + + PRAGMA_ENABLE_DEPRECATION_WARNINGS } else { @@ -670,6 +674,21 @@ FGameplayEffectSpecHandle UAbilitySystemBlueprintLibrary::AssignSetByCallerMagni return SpecHandle; } +FGameplayEffectSpecHandle UAbilitySystemBlueprintLibrary::AssignTagSetByCallerMagnitude(FGameplayEffectSpecHandle SpecHandle, FGameplayTag DataTag, float Magnitude) +{ + FGameplayEffectSpec* Spec = SpecHandle.Data.Get(); + if (Spec) + { + Spec->SetSetByCallerMagnitude(DataTag, Magnitude); + } + else + { + ABILITY_LOG(Warning, TEXT("UAbilitySystemBlueprintLibrary::AssignSetByCallerTagMagnitude called with invalid SpecHandle")); + } + + return SpecHandle; +} + FGameplayEffectSpecHandle UAbilitySystemBlueprintLibrary::SetDuration(FGameplayEffectSpecHandle SpecHandle, float Duration) { FGameplayEffectSpec* Spec = SpecHandle.Data.Get(); @@ -862,21 +881,28 @@ int32 UAbilitySystemBlueprintLibrary::GetActiveGameplayEffectStackLimitCount(FAc return 0; } +float UAbilitySystemBlueprintLibrary::GetModifiedAttributeMagnitude(const FGameplayEffectSpec& Spec, FGameplayAttribute Attribute) +{ + float Delta = 0.f; + for (const FGameplayEffectModifiedAttribute &Mod : Spec.ModifiedAttributes) + { + if (Mod.Attribute == Attribute) + { + Delta += Mod.TotalMagnitude; + } + } + return Delta; +} + float UAbilitySystemBlueprintLibrary::GetModifiedAttributeMagnitude(FGameplayEffectSpecHandle SpecHandle, FGameplayAttribute Attribute) { FGameplayEffectSpec* Spec = SpecHandle.Data.Get(); float Delta = 0.f; if (Spec) { - for (FGameplayEffectModifiedAttribute &Mod : Spec->ModifiedAttributes) - { - if (Mod.Attribute == Attribute) - { - Delta += Mod.TotalMagnitude; - } - } + return GetModifiedAttributeMagnitude(*Spec, Attribute); } - return Delta; + return 0; } FString UAbilitySystemBlueprintLibrary::GetActiveGameplayEffectDebugString(FActiveGameplayEffectHandle ActiveHandle) diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AbilitySystemComponent.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AbilitySystemComponent.cpp index f25b7a56726e..8e3671c584e6 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AbilitySystemComponent.cpp +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AbilitySystemComponent.cpp @@ -455,7 +455,14 @@ FOnGameplayEffectTagCountChanged& UAbilitySystemComponent::RegisterGenericGamepl FOnGameplayAttributeChange& UAbilitySystemComponent::RegisterGameplayAttributeEvent(FGameplayAttribute Attribute) { +PRAGMA_DISABLE_DEPRECATION_WARNINGS return ActiveGameplayEffects.RegisterGameplayAttributeEvent(Attribute); +PRAGMA_ENABLE_DEPRECATION_WARNINGS +} + +FOnGameplayAttributeValueChange& UAbilitySystemComponent::GetGameplayAttributeValueChangeDelegate(FGameplayAttribute Attribute) +{ + return ActiveGameplayEffects.GetGameplayAttributeValueChangeDelegate(Attribute); } UProperty* UAbilitySystemComponent::GetOutgoingDurationProperty() @@ -532,6 +539,8 @@ FActiveGameplayEffectHandle UAbilitySystemComponent::ApplyGameplayEffectSpecToSe // of the add operation FScopedActiveGameplayEffectLock ScopeLock(ActiveGameplayEffects); + FScopeCurrentGameplayEffectBeingApplied ScopedGEApplication(&Spec, this); + const bool bIsNetAuthority = IsOwnerActorAuthoritative(); // Check Network Authority @@ -664,6 +673,12 @@ FActiveGameplayEffectHandle UAbilitySystemComponent::ApplyGameplayEffectSpecToSe OurCopyOfSpec->SetDuration(UGameplayEffect::INFINITE_DURATION, true); } } + + if (OurCopyOfSpec) + { + // Update (not push) the global spec being applied [we want to switch it to our copy, from the const input copy) + UAbilitySystemGlobals::Get().SetCurrentAppliedGE(OurCopyOfSpec); + } // We still probably want to apply tags and stuff even if instant? diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AbilitySystemComponent_Abilities.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AbilitySystemComponent_Abilities.cpp index ba800538d7d6..d81f86c68196 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AbilitySystemComponent_Abilities.cpp +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AbilitySystemComponent_Abilities.cpp @@ -31,6 +31,8 @@ #include "TickableAttributeSetInterface.h" #include "GameplayTagResponseTable.h" #include "Engine/DemoNetDriver.h" +#include "GameFramework/CharacterMovementComponent.h" +#include "GameFramework/Character.h" #define LOCTEXT_NAMESPACE "AbilitySystemComponent" @@ -1018,6 +1020,29 @@ bool UAbilitySystemComponent::TryActivateAbility(FGameplayAbilitySpecHandle Abil return false; } + //Flush any remaining server moves before activating the ability. + // Flushing the server moves prevents situations where previously pending move's DeltaTimes are figured into montages that are about to play and update. + // When this happened, clients would have a smaller delta time than the server which meant the server would get ahead and receive their notifies before the client, etc. + // The system depends on the server not getting ahead, so it's important to send along any previously pending server moves here. + if (ActorInfo && ActorInfo->AvatarActor.Get() && !ActorInfo->IsNetAuthority()) + { + AActor* MyActor = ActorInfo->AvatarActor.Get(); + + if (MyActor) + { + ACharacter* MyCharacter = Cast(MyActor); + if (MyCharacter) + { + UCharacterMovementComponent* CharMoveComp = Cast(MyCharacter->GetMovementComponent()); + + if (CharMoveComp) + { + CharMoveComp->FlushServerMoves(); + } + } + } + } + if (NetMode != ROLE_Authority && (Ability->GetNetExecutionPolicy() == EGameplayAbilityNetExecutionPolicy::ServerOnly || Ability->GetNetExecutionPolicy() == EGameplayAbilityNetExecutionPolicy::ServerInitiated)) { if (bAllowRemoteActivation) @@ -2408,7 +2433,7 @@ void UAbilitySystemComponent::OnRep_ReplicatedAnimMontage() if( RepAnimMontageInfo.AnimMontage ) { // New Montage to play - bool ReplicatedPlayBit = bool(RepAnimMontageInfo.ForcePlayBit); + const bool ReplicatedPlayBit = bool(RepAnimMontageInfo.ForcePlayBit); if ((LocalAnimMontageInfo.AnimMontage != RepAnimMontageInfo.AnimMontage) || (LocalAnimMontageInfo.PlayBit != ReplicatedPlayBit)) { LocalAnimMontageInfo.PlayBit = ReplicatedPlayBit; @@ -2441,13 +2466,13 @@ void UAbilitySystemComponent::OnRep_ReplicatedAnimMontage() } else { - int32 RepSectionID = LocalAnimMontageInfo.AnimMontage->GetSectionIndexFromPosition(RepAnimMontageInfo.Position); - int32 RepNextSectionID = int32(RepAnimMontageInfo.NextSectionID) - 1; + const int32 RepSectionID = LocalAnimMontageInfo.AnimMontage->GetSectionIndexFromPosition(RepAnimMontageInfo.Position); + const int32 RepNextSectionID = int32(RepAnimMontageInfo.NextSectionID) - 1; // And NextSectionID for the replicated SectionID. if( RepSectionID != INDEX_NONE ) { - int32 NextSectionID = AnimInstance->Montage_GetNextSectionID(LocalAnimMontageInfo.AnimMontage, RepSectionID); + const int32 NextSectionID = AnimInstance->Montage_GetNextSectionID(LocalAnimMontageInfo.AnimMontage, RepSectionID); // If NextSectionID is different than the replicated one, then set it. if( NextSectionID != RepNextSectionID ) @@ -2456,7 +2481,7 @@ void UAbilitySystemComponent::OnRep_ReplicatedAnimMontage() } // Make sure we haven't received that update too late and the client hasn't already jumped to another section. - int32 CurrentSectionID = LocalAnimMontageInfo.AnimMontage->GetSectionIndexFromPosition(AnimInstance->Montage_GetPosition(LocalAnimMontageInfo.AnimMontage)); + const int32 CurrentSectionID = LocalAnimMontageInfo.AnimMontage->GetSectionIndexFromPosition(AnimInstance->Montage_GetPosition(LocalAnimMontageInfo.AnimMontage)); if ((CurrentSectionID != RepSectionID) && (CurrentSectionID != RepNextSectionID)) { // Client is in a wrong section, teleport him into the begining of the right section @@ -2466,16 +2491,25 @@ void UAbilitySystemComponent::OnRep_ReplicatedAnimMontage() } // Update Position. If error is too great, jump to replicated position. - float CurrentPosition = AnimInstance->Montage_GetPosition(LocalAnimMontageInfo.AnimMontage); - int32 CurrentSectionID = LocalAnimMontageInfo.AnimMontage->GetSectionIndexFromPosition(CurrentPosition); + const float CurrentPosition = AnimInstance->Montage_GetPosition(LocalAnimMontageInfo.AnimMontage); + const int32 CurrentSectionID = LocalAnimMontageInfo.AnimMontage->GetSectionIndexFromPosition(CurrentPosition); + const float DeltaPosition = RepAnimMontageInfo.Position - CurrentPosition; + // Only check threshold if we are located in the same section. Different sections require a bit more work as we could be jumping around the timeline. - if ((CurrentSectionID == RepSectionID) && (FMath::Abs(CurrentPosition - RepAnimMontageInfo.Position) > MONTAGE_REP_POS_ERR_THRESH) && RepAnimMontageInfo.IsStopped == 0) + // And therefore DeltaPosition is not as trivial to determine. + if ((CurrentSectionID == RepSectionID) && (FMath::Abs(DeltaPosition) > MONTAGE_REP_POS_ERR_THRESH) && (RepAnimMontageInfo.IsStopped == 0)) { // fast forward to server position and trigger notifies if (FAnimMontageInstance* MontageInstance = AnimInstance->GetActiveInstanceForMontage(RepAnimMontageInfo.AnimMontage)) { - MontageInstance->HandleEvents(CurrentPosition, RepAnimMontageInfo.Position, nullptr); - AnimInstance->TriggerAnimNotifies(0.f); + // Skip triggering notifies if we're going backwards in time, we've already triggered them. + const float DeltaTime = !FMath::IsNearlyZero(RepAnimMontageInfo.PlayRate) ? (DeltaPosition / RepAnimMontageInfo.PlayRate) : 0.f; + if (DeltaTime >= 0.f) + { + MontageInstance->UpdateWeight(DeltaTime); + MontageInstance->HandleEvents(CurrentPosition, RepAnimMontageInfo.Position, nullptr); + AnimInstance->TriggerAnimNotifies(DeltaTime); + } } AnimInstance->Montage_SetPosition(LocalAnimMontageInfo.AnimMontage, RepAnimMontageInfo.Position); } diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AbilitySystemDebugHUD.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AbilitySystemDebugHUD.cpp index 14d62097b7e7..a7db15a231b5 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AbilitySystemDebugHUD.cpp +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AbilitySystemDebugHUD.cpp @@ -45,7 +45,7 @@ void AAbilitySystemDebugHUD::DrawWithBackground(UFont* InFont, const FString& Te OffsetY += 25; } -void AAbilitySystemDebugHUD::DrawDebugHUD(UCanvas* InCanvas, APlayerController* PC) +void AAbilitySystemDebugHUD::DrawDebugHUD(UCanvas* InCanvas, APlayerController*) { Canvas = InCanvas; if (!Canvas) @@ -59,7 +59,7 @@ void AAbilitySystemDebugHUD::DrawDebugHUD(UCanvas* InCanvas, APlayerController* return; } - PC = LocalPlayer->PlayerController; + APlayerController *PC = LocalPlayer->PlayerController; if (!PC) { return; diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AbilitySystemTestPawn.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AbilitySystemTestPawn.cpp index c241f7069373..22fe1d7b51e8 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AbilitySystemTestPawn.cpp +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AbilitySystemTestPawn.cpp @@ -35,5 +35,3 @@ UAbilitySystemComponent* AAbilitySystemTestPawn::GetAbilitySystemComponent() con return FindComponentByClass(); } -/** Returns AbilitySystemComponent subobject **/ -UAbilitySystemComponent* AAbilitySystemTestPawn::GetAbilitySystemComponent() { return AbilitySystemComponent; } diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AttributeSet.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AttributeSet.cpp index ca5e8d4a7b53..1740e9f25fa2 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AttributeSet.cpp +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AttributeSet.cpp @@ -226,6 +226,64 @@ void FGameplayAttribute::PostSerialize(const FArchive& Ar) } } +void FGameplayAttribute::GetAllAttributeProperties(TArray& OutProperties, FString FilterMetaStr) +{ + // Gather all UAttribute classes + for (TObjectIterator ClassIt; ClassIt; ++ClassIt) + { + UClass *Class = *ClassIt; + if (Class->IsChildOf(UAttributeSet::StaticClass()) && !Class->ClassGeneratedBy) + { +#if WITH_EDITOR + // Allow entire classes to be filtered globally + if (Class->HasMetaData(TEXT("HideInDetailsView"))) + { + continue; + } +#endif + + for (TFieldIterator PropertyIt(Class, EFieldIteratorFlags::ExcludeSuper); PropertyIt; ++PropertyIt) + { + UProperty* Property = *PropertyIt; + +#if WITH_EDITOR + if (!FilterMetaStr.IsEmpty() && Property->HasMetaData(*FilterMetaStr)) + { + continue; + } + + // Allow properties to be filtered globally (never show up) + if (Property->HasMetaData(TEXT("HideInDetailsView"))) + { + continue; + } +#endif + + OutProperties.Add(Property); + } + } + +#if WITH_EDITOR + // UAbilitySystemComponent can add 'system' attributes + if (Class->IsChildOf(UAbilitySystemComponent::StaticClass()) && !Class->ClassGeneratedBy) + { + for (TFieldIterator PropertyIt(Class, EFieldIteratorFlags::ExcludeSuper); PropertyIt; ++PropertyIt) + { + UProperty* Property = *PropertyIt; + + + // SystemAttributes have to be explicitly tagged + if (Property->HasMetaData(TEXT("SystemGameplayAttribute")) == false) + { + continue; + } + OutProperties.Add(Property); + } + } +#endif + } +} + UAttributeSet::UAttributeSet(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/GameplayCueManager.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/GameplayCueManager.cpp index 4aa53c266c51..423e7f2620dd 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/GameplayCueManager.cpp +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/GameplayCueManager.cpp @@ -417,15 +417,12 @@ AGameplayCueNotify_Actor* UGameplayCueManager::GetInstancedCueActor(AActor* Targ { FActorSpawnParameters SpawnParams; SpawnParams.Owner = NewOwnerActor; - if (SpawnedCue == nullptr) + if (LogGameplayCueActorSpawning) { - if (LogGameplayCueActorSpawning) - { - ABILITY_LOG(Warning, TEXT("Spawning GameplaycueActor: %s"), *CueClass->GetName()); - } - - SpawnedCue = World->SpawnActor(CueClass, TargetActor->GetActorLocation(), TargetActor->GetActorRotation(), SpawnParams); + ABILITY_LOG(Warning, TEXT("Spawning GameplaycueActor: %s"), *CueClass->GetName()); } + + SpawnedCue = World->SpawnActor(CueClass, TargetActor->GetActorLocation(), TargetActor->GetActorRotation(), SpawnParams); } // Associate this GameplayCueNotifyActor with this target actor/key diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/GameplayCueNotify_Actor.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/GameplayCueNotify_Actor.cpp index e8cf7860e183..bccebcfb810c 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/GameplayCueNotify_Actor.cpp +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/GameplayCueNotify_Actor.cpp @@ -344,7 +344,7 @@ bool AGameplayCueNotify_Actor::Recycle() // Clear owner, hide, detach from parent SetOwner(nullptr); SetActorHiddenInGame(true); - DetachRootComponentFromParent(); + DetachFromActor(FDetachmentTransformRules::KeepWorldTransform); return true; } diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/GameplayDebuggerCategory_Abilities.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/GameplayDebuggerCategory_Abilities.cpp index 0f1279fe862b..2dce8fd87843 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/GameplayDebuggerCategory_Abilities.cpp +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/GameplayDebuggerCategory_Abilities.cpp @@ -1,13 +1,15 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #include "GameplayDebuggerCategory_Abilities.h" + +#if WITH_GAMEPLAY_DEBUGGER + #include "GameplayTagContainer.h" #include "GameplayAbilitySpec.h" #include "GameplayEffect.h" #include "AbilitySystemGlobals.h" #include "AbilitySystemComponent.h" -#if WITH_GAMEPLAY_DEBUGGER - FGameplayDebuggerCategory_Abilities::FGameplayDebuggerCategory_Abilities() { SetDataPackReplication(&DataPack); diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/GameplayDebuggerCategory_Abilities.h b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/GameplayDebuggerCategory_Abilities.h index c22c5b05743b..142b40510cef 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/GameplayDebuggerCategory_Abilities.h +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/GameplayDebuggerCategory_Abilities.h @@ -2,16 +2,14 @@ #pragma once -#include "CoreMinimal.h" #if WITH_GAMEPLAY_DEBUGGER + +#include "CoreMinimal.h" #include "GameplayDebuggerCategory.h" -#endif class AActor; class APlayerController; -#if WITH_GAMEPLAY_DEBUGGER - class FGameplayDebuggerCategory_Abilities : public FGameplayDebuggerCategory { public: diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/GameplayEffect.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/GameplayEffect.cpp index 164ecf1d7063..331aecd2466b 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/GameplayEffect.cpp +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/GameplayEffect.cpp @@ -160,6 +160,8 @@ void UGameplayEffect::PostEditChangeProperty(FPropertyChangedEvent& PropertyChan } HasGrantedApplicationImmunityQuery = !GrantedApplicationImmunityQuery.IsEmpty(); + + UAbilitySystemGlobals::Get().GameplayEffectPostEditChangeProperty(this, PropertyChangedEvent); } #endif // #if WITH_EDITOR @@ -356,8 +358,22 @@ bool FGameplayEffectModifierMagnitude::AttemptCalculateMagnitude(const FGameplay break; case EGameplayEffectMagnitudeCalculation::SetByCaller: - OutCalculatedMagnitude = InRelevantSpec.GetSetByCallerMagnitude(SetByCallerMagnitude.DataName, WarnIfSetByCallerFail, DefaultSetbyCaller); - break; + { + if (SetByCallerMagnitude.DataTag.IsValid()) + { + OutCalculatedMagnitude = InRelevantSpec.GetSetByCallerMagnitude(SetByCallerMagnitude.DataTag, WarnIfSetByCallerFail, DefaultSetbyCaller); + } + else + { + PRAGMA_DISABLE_DEPRECATION_WARNINGS + + OutCalculatedMagnitude = InRelevantSpec.GetSetByCallerMagnitude(SetByCallerMagnitude.DataName, WarnIfSetByCallerFail, DefaultSetbyCaller); + + PRAGMA_ENABLE_DEPRECATION_WARNINGS + } + } + break; + default: ABILITY_LOG(Error, TEXT("Unknown MagnitudeCalculationType %d in AttemptCalculateMagnitude"), (int32)MagnitudeCalculationType); OutCalculatedMagnitude = 0.f; @@ -642,7 +658,8 @@ FGameplayEffectSpec::FGameplayEffectSpec(FGameplayEffectSpec&& Other) , bCompletedTargetAttributeCapture(Other.bCompletedTargetAttributeCapture) , bDurationLocked(Other.bDurationLocked) , GrantedAbilitySpecs(MoveTemp(Other.GrantedAbilitySpecs)) - , SetByCallerMagnitudes(MoveTemp(Other.SetByCallerMagnitudes)) + , SetByCallerNameMagnitudes(MoveTemp(Other.SetByCallerNameMagnitudes)) + , SetByCallerTagMagnitudes(MoveTemp(Other.SetByCallerTagMagnitudes)) , EffectContext(Other.EffectContext) , Level(Other.Level) { @@ -668,7 +685,8 @@ FGameplayEffectSpec& FGameplayEffectSpec::operator=(FGameplayEffectSpec&& Other) bCompletedTargetAttributeCapture = Other.bCompletedTargetAttributeCapture; bDurationLocked = Other.bDurationLocked; GrantedAbilitySpecs = MoveTemp(Other.GrantedAbilitySpecs); - SetByCallerMagnitudes = MoveTemp(Other.SetByCallerMagnitudes); + SetByCallerNameMagnitudes = MoveTemp(Other.SetByCallerNameMagnitudes); + SetByCallerTagMagnitudes = MoveTemp(Other.SetByCallerTagMagnitudes); EffectContext = Other.EffectContext; Level = Other.Level; return *this; @@ -693,7 +711,8 @@ FGameplayEffectSpec& FGameplayEffectSpec::operator=(const FGameplayEffectSpec& O bCompletedTargetAttributeCapture = Other.bCompletedTargetAttributeCapture; bDurationLocked = Other.bDurationLocked; GrantedAbilitySpecs = Other.GrantedAbilitySpecs; - SetByCallerMagnitudes = Other.SetByCallerMagnitudes; + SetByCallerNameMagnitudes = Other.SetByCallerNameMagnitudes; + SetByCallerTagMagnitudes = Other.SetByCallerTagMagnitudes; EffectContext = Other.EffectContext; Level = Other.Level; return *this; @@ -1110,15 +1129,33 @@ void FGameplayEffectSpec::GetAllAssetTags(OUT FGameplayTagContainer& Container) } } + void FGameplayEffectSpec::SetSetByCallerMagnitude(FName DataName, float Magnitude) { - SetByCallerMagnitudes.FindOrAdd(DataName) = Magnitude; + if (DataName != NAME_None) + { + SetByCallerNameMagnitudes.FindOrAdd(DataName) = Magnitude; + } +} + +void FGameplayEffectSpec::SetSetByCallerMagnitude(FGameplayTag DataTag, float Magnitude) +{ + if (DataTag.IsValid()) + { + SetByCallerTagMagnitudes.FindOrAdd(DataTag) = Magnitude; + } } float FGameplayEffectSpec::GetSetByCallerMagnitude(FName DataName, bool WarnIfNotFound, float DefaultIfNotFound) const { float Magnitude = DefaultIfNotFound; - const float* Ptr = SetByCallerMagnitudes.Find(DataName); + const float* Ptr = nullptr; + + if (DataName != NAME_None) + { + Ptr = SetByCallerNameMagnitudes.Find(DataName); + } + if (Ptr) { Magnitude = *Ptr; @@ -1131,6 +1168,28 @@ float FGameplayEffectSpec::GetSetByCallerMagnitude(FName DataName, bool WarnIfNo return Magnitude; } +float FGameplayEffectSpec::GetSetByCallerMagnitude(FGameplayTag DataTag, bool WarnIfNotFound, float DefaultIfNotFound) const +{ + float Magnitude = DefaultIfNotFound; + const float* Ptr = nullptr; + + if (DataTag.IsValid()) + { + Ptr = SetByCallerTagMagnitudes.Find(DataTag); + } + + if (Ptr) + { + Magnitude = *Ptr; + } + else if (WarnIfNotFound) + { + ABILITY_LOG(Error, TEXT("FGameplayEffectSpec::GetMagnitude called for Data %s on Def %s when magnitude had not yet been set by caller."), *DataTag.ToString(), *Def->GetName()); + } + + return Magnitude; +} + // -------------------------------------------------------------------------------------------------------------------------------------------------------- // // FGameplayEffectAttributeCaptureSpec @@ -2205,6 +2264,8 @@ bool FActiveGameplayEffectsContainer::ShouldUseMinimalReplication() void FActiveGameplayEffectsContainer::SetBaseAttributeValueFromReplication(FGameplayAttribute Attribute, float ServerValue) { + float OldValue = Owner->GetNumericAttribute(Attribute); + FAggregatorRef* RefPtr = AttributeAggregatorMap.Find(Attribute); if (RefPtr && RefPtr->Get()) { @@ -2217,9 +2278,22 @@ void FActiveGameplayEffectsContainer::SetBaseAttributeValueFromReplication(FGame else { // No aggregators on the client but still broadcast the dirty delegate - if (FOnGameplayAttributeChange* Delegate = AttributeChangeDelegates.Find(Attribute)) + PRAGMA_DISABLE_DEPRECATION_WARNINGS + if (FOnGameplayAttributeChange* LegacyDelegate = AttributeChangeDelegates.Find(Attribute)) { - Delegate->Broadcast(ServerValue, nullptr); + LegacyDelegate->Broadcast(ServerValue, nullptr); + } + PRAGMA_ENABLE_DEPRECATION_WARNINGS + + if (FOnGameplayAttributeValueChange* Delegate = AttributeValueChangeDelegates.Find(Attribute)) + { + FOnAttributeChangeData CallbackData; + CallbackData.Attribute = Attribute; + CallbackData.NewValue = ServerValue; + CallbackData.OldValue = OldValue; + CallbackData.GEModData = nullptr; + + Delegate->Broadcast(CallbackData); } } } @@ -2334,21 +2408,37 @@ void FActiveGameplayEffectsContainer::CaptureAttributeForGameplayEffect(OUT FGam void FActiveGameplayEffectsContainer::InternalUpdateNumericalAttribute(FGameplayAttribute Attribute, float NewValue, const FGameplayEffectModCallbackData* ModData, bool bFromRecursiveCall) { ABILITY_LOG(Log, TEXT("Property %s new value is: %.2f"), *Attribute.GetName(), NewValue); + + float OldValue = Owner->GetNumericAttribute(Attribute); Owner->SetNumericAttribute_Internal(Attribute, NewValue); if (!bFromRecursiveCall) { - FOnGameplayAttributeChange* Delegate = AttributeChangeDelegates.Find(Attribute); - if (Delegate) + // We should only have one: either cached CurrentModcallbackData, or explicit callback data passed directly in. + if (ModData && CurrentModcallbackData) { - // We should only have one: either cached CurrentModcallbackData, or explicit callback data passed directly in. - if (ModData && CurrentModcallbackData) - { - ABILITY_LOG(Warning, TEXT("Had passed in ModData and cached CurrentModcallbackData in FActiveGameplayEffectsContainer::InternalUpdateNumericalAttribute. For attribute %s on %s."), *Attribute.GetName(), *Owner->GetFullName() ); - } + ABILITY_LOG(Warning, TEXT("Had passed in ModData and cached CurrentModcallbackData in FActiveGameplayEffectsContainer::InternalUpdateNumericalAttribute. For attribute %s on %s."), *Attribute.GetName(), *Owner->GetFullName() ); + } + + const FGameplayEffectModCallbackData* DataToShare = ModData ? ModData : CurrentModcallbackData; - // Broadcast dirty delegate. If we were given explicit mod data then pass it. - Delegate->Broadcast(NewValue, ModData ? ModData : CurrentModcallbackData); + // DEPRECATED Delegate + PRAGMA_DISABLE_DEPRECATION_WARNINGS + if (FOnGameplayAttributeChange* LegacyDelegate = AttributeChangeDelegates.Find(Attribute)) + { + LegacyDelegate->Broadcast(NewValue, DataToShare); + } + PRAGMA_ENABLE_DEPRECATION_WARNINGS + + // NEW Delegate + if (FOnGameplayAttributeValueChange* NewDelegate = AttributeValueChangeDelegates.Find(Attribute)) + { + FOnAttributeChangeData CallbackData; + CallbackData.Attribute = Attribute; + CallbackData.NewValue = NewValue; + CallbackData.OldValue = OldValue; + CallbackData.GEModData = DataToShare; + NewDelegate->Broadcast(CallbackData); } } CurrentModcallbackData = nullptr; @@ -2539,6 +2629,9 @@ FActiveGameplayEffect* FActiveGameplayEffectsContainer::ApplyGameplayEffectSpec( FGameplayEffectSpec& ExistingSpec = ExistingStackableGE->Spec; StartingStackCount = ExistingSpec.StackCount; + + // This is now the global "being applied GE" + UAbilitySystemGlobals::Get().SetCurrentAppliedGE(&ExistingSpec); // How to apply multiple stacks at once? What if we trigger an overflow which can reject the application? // We still want to apply the stacks that didnt push us over, but we also want to call HandleActiveGameplayEffectStackOverflow. @@ -2643,6 +2736,9 @@ FActiveGameplayEffect* FActiveGameplayEffectsContainer::ApplyGameplayEffectSpec( } } + // This is now the global "being applied GE" + UAbilitySystemGlobals::Get().SetCurrentAppliedGE(&AppliedActiveGE->Spec); + FGameplayEffectSpec& AppliedEffectSpec = AppliedActiveGE->Spec; UAbilitySystemGlobals::Get().GlobalPreGameplayEffectSpecApply(AppliedEffectSpec, Owner); @@ -2917,10 +3013,9 @@ void FActiveGameplayEffectsContainer::AddActiveGameplayEffectGrantedTagsAndModif { for (const FGameplayTag& CueTag : Cue.GameplayCueTags) { - // Note: minimal replication does not replicate the effect context with the gameplay cue parameters. - // This is just a choice right now. If needed, it may be better to convert the effect context to GC parameters *here* - // and pass those into this function - Owner->AddGameplayCue_MinimalReplication(CueTag); + // We are now replicating the EffectContext in minimally replicated cues. It may be worth allowing this be determined on a per cue basis one day. + // (not sending the EffectContext can make things wrong. E.g, the EffectCauser becomes the target of the GE rather than the source) + Owner->AddGameplayCue_MinimalReplication(CueTag, Effect.Spec.GetEffectContext()); } } } @@ -3861,7 +3956,14 @@ int32 FActiveGameplayEffectsContainer::GetActiveEffectCount(const FGameplayEffec FOnGameplayAttributeChange& FActiveGameplayEffectsContainer::RegisterGameplayAttributeEvent(FGameplayAttribute Attribute) { +PRAGMA_DISABLE_DEPRECATION_WARNINGS return AttributeChangeDelegates.FindOrAdd(Attribute); +PRAGMA_ENABLE_DEPRECATION_WARNINGS +} + +FOnGameplayAttributeValueChange& FActiveGameplayEffectsContainer::GetGameplayAttributeValueChangeDelegate(FGameplayAttribute Attribute) +{ + return AttributeValueChangeDelegates.FindOrAdd(Attribute); } bool FActiveGameplayEffectsContainer::HasReceivedEffectWithPredictedKey(FPredictionKey PredictionKey) const diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/GameplayEffectTypes.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/GameplayEffectTypes.cpp index ddee9e503cce..e0089ac2c05e 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/GameplayEffectTypes.cpp +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/GameplayEffectTypes.cpp @@ -126,6 +126,7 @@ void FGameplayEffectContext::SetAbility(const UGameplayAbility* InGameplayAbilit { if (InGameplayAbility) { + AbilityInstanceNotReplicated = InGameplayAbility; AbilityCDO = InGameplayAbility->GetClass()->GetDefaultObject(); AbilityLevel = InGameplayAbility->GetAbilityLevel(); } @@ -136,6 +137,12 @@ const UGameplayAbility* FGameplayEffectContext::GetAbility() const return AbilityCDO.Get(); } +const UGameplayAbility* FGameplayEffectContext::GetAbilityInstance_NotReplicated() const +{ + return AbilityInstanceNotReplicated.Get(); +} + + void FGameplayEffectContext::AddActors(const TArray>& InActors, bool bReset) { if (bReset && Actors.Num()) diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/GameplayAbilityTypes.h b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/GameplayAbilityTypes.h index b13dace29c22..824bafeea904 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/GameplayAbilityTypes.h +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/GameplayAbilityTypes.h @@ -393,7 +393,7 @@ struct GAMEPLAYABILITIES_API FAttributeDefaults UPROPERTY(EditAnywhere, Category = "AttributeTest") TSubclassOf Attributes; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AttributeTest") + UPROPERTY(EditAnywhere, Category = "AttributeTest") class UDataTable* DefaultStartingTable; }; diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/GameplayAbilityWorldReticle_ActorVisualization.h b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/GameplayAbilityWorldReticle_ActorVisualization.h index 1ea3ac405f8c..147e47fef866 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/GameplayAbilityWorldReticle_ActorVisualization.h +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/GameplayAbilityWorldReticle_ActorVisualization.h @@ -21,7 +21,6 @@ public: private: /** Hardcoded collision component, so other objects don't think they can collide with the visualization actor */ - DEPRECATED_FORGAME(4.6, "CollisionComponent should not be accessed directly, please use GetCollisionComponent() function instead. CollisionComponent will soon be private and your code will not compile.") UPROPERTY() class UCapsuleComponent* CollisionComponent; public: @@ -33,5 +32,5 @@ public: virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; /** Returns CollisionComponent subobject **/ - GAMEPLAYABILITIES_API class UCapsuleComponent* GetCollisionComponent(); + GAMEPLAYABILITIES_API class UCapsuleComponent* GetCollisionComponent() { return CollisionComponent; } }; diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitAbilityActivate.h b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitAbilityActivate.h index 33592722aff0..1d2f591284a1 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitAbilityActivate.h +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitAbilityActivate.h @@ -15,8 +15,8 @@ class AActor; /** * Waits for the actor to activate another ability */ -UCLASS(MinimalAPI) -class UAbilityTask_WaitAbilityActivate : public UAbilityTask +UCLASS() +class GAMEPLAYABILITIES_API UAbilityTask_WaitAbilityActivate : public UAbilityTask { GENERATED_UCLASS_BODY() @@ -36,12 +36,18 @@ class UAbilityTask_WaitAbilityActivate : public UAbilityTask UFUNCTION(BlueprintCallable, Category = "Ability|Tasks", meta = (HidePin = "OwningAbility", DefaultToSelf = "OwningAbility", BlueprintInternalUseOnly = "TRUE")) static UAbilityTask_WaitAbilityActivate* WaitForAbilityActivateWithTagRequirements(UGameplayAbility* OwningAbility, FGameplayTagRequirements TagRequirements, bool IncludeTriggeredAbilities = false, bool TriggerOnce = true); + /** Wait until a new ability (of the same or different type) is activated. Only input based abilities will be counted unless IncludeTriggeredAbilities is true. */ + UFUNCTION(BlueprintCallable, Category="Ability|Tasks", meta = (HidePin = "OwningAbility", DefaultToSelf = "OwningAbility", BlueprintInternalUseOnly = "TRUE")) + static UAbilityTask_WaitAbilityActivate* WaitForAbilityActivate_Query(UGameplayAbility* OwningAbility, FGameplayTagQuery Query, bool IncludeTriggeredAbilities=false, bool TriggerOnce=true); + FGameplayTag WithTag; FGameplayTag WithoutTag; bool IncludeTriggeredAbilities; bool TriggerOnce; FGameplayTagRequirements TagRequirements; + FGameplayTagQuery Query; + protected: virtual void OnDestroy(bool AbilityEnded) override; diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitAbilityCommit.h b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitAbilityCommit.h index e088f1127172..84e079165f0e 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitAbilityCommit.h +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitAbilityCommit.h @@ -12,8 +12,8 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FWaitAbilityCommitDelegate, UGamepla /** * Waits for the actor to activate another ability */ -UCLASS(MinimalAPI) -class UAbilityTask_WaitAbilityCommit : public UAbilityTask +UCLASS() +class GAMEPLAYABILITIES_API UAbilityTask_WaitAbilityCommit : public UAbilityTask { GENERATED_UCLASS_BODY() @@ -25,14 +25,20 @@ class UAbilityTask_WaitAbilityCommit : public UAbilityTask UFUNCTION() void OnAbilityCommit(UGameplayAbility *ActivatedAbility); - /** Wait until a new ability (of the same or different type) is commited. Used to gracefully interrupt abilities in specific ways. */ + /** Wait until a new ability (of the same or different type) is commited. */ UFUNCTION(BlueprintCallable, Category="Ability|Tasks", meta = (HidePin = "OwningAbility", DefaultToSelf = "OwningAbility", BlueprintInternalUseOnly = "TRUE", DisplayName = "Wait For New Ability Commit")) static UAbilityTask_WaitAbilityCommit* WaitForAbilityCommit(UGameplayAbility* OwningAbility, FGameplayTag WithTag, FGameplayTag WithoutTage, bool TriggerOnce=true); + UFUNCTION(BlueprintCallable, Category="Ability|Tasks", meta = (HidePin = "OwningAbility", DefaultToSelf = "OwningAbility", BlueprintInternalUseOnly = "TRUE", DisplayName = "Wait For New Ability Commit Query")) + static UAbilityTask_WaitAbilityCommit* WaitForAbilityCommit_Query(UGameplayAbility* OwningAbility, FGameplayTagQuery Query, bool TriggerOnce=true); + FGameplayTag WithTag; FGameplayTag WithoutTag; bool TriggerOnce; + + FGameplayTagQuery Query; + protected: virtual void OnDestroy(bool AbilityEnded) override; diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitAttributeChange.h b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitAttributeChange.h index 5404bf5af05d..e1948b8c8a63 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitAttributeChange.h +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitAttributeChange.h @@ -31,8 +31,8 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE(FWaitAttributeChangeDelegate); /** * Waits for the actor to activate another ability */ -UCLASS(MinimalAPI) -class UAbilityTask_WaitAttributeChange : public UAbilityTask +UCLASS() +class GAMEPLAYABILITIES_API UAbilityTask_WaitAttributeChange : public UAbilityTask { GENERATED_UCLASS_BODY() @@ -41,7 +41,7 @@ class UAbilityTask_WaitAttributeChange : public UAbilityTask virtual void Activate() override; - void OnAttributeChange(float NewValue, const FGameplayEffectModCallbackData*); + void OnAttributeChange(const FOnAttributeChangeData& CallbackData); /** Wait until an attribute changes. */ UFUNCTION(BlueprintCallable, Category="Ability|Tasks", meta = (HidePin = "OwningAbility", DefaultToSelf = "OwningAbility", BlueprintInternalUseOnly = "TRUE")) diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitAttributeChangeRatioThreshold.h b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitAttributeChangeRatioThreshold.h index 4613d3786124..564324323be7 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitAttributeChangeRatioThreshold.h +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitAttributeChangeRatioThreshold.h @@ -26,8 +26,8 @@ class UAbilityTask_WaitAttributeChangeRatioThreshold : public UAbilityTask virtual void Activate() override; - void OnNumeratorAttributeChange(float NewValue, const FGameplayEffectModCallbackData* Data); - void OnDenominatorAttributeChange(float NewValue, const FGameplayEffectModCallbackData* Data); + void OnNumeratorAttributeChange(const FOnAttributeChangeData& CallbackData); + void OnDenominatorAttributeChange(const FOnAttributeChangeData& CallbackData); /** Wait on attribute ratio change meeting a comparison threshold. */ UFUNCTION(BlueprintCallable, Category="Ability|Tasks", meta = (HidePin = "OwningAbility", DefaultToSelf = "OwningAbility", BlueprintInternalUseOnly = "TRUE")) diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitAttributeChangeThreshold.h b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitAttributeChangeThreshold.h index 1026a077a2ec..0ff7f6a1d7d9 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitAttributeChangeThreshold.h +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitAttributeChangeThreshold.h @@ -25,7 +25,7 @@ class UAbilityTask_WaitAttributeChangeThreshold : public UAbilityTask virtual void Activate() override; - void OnAttributeChange(float NewValue, const FGameplayEffectModCallbackData* Data); + void OnAttributeChange(const FOnAttributeChangeData& CallbackData); /** Wait on attribute change meeting a comparison threshold. */ UFUNCTION(BlueprintCallable, Category="Ability|Tasks", meta = (HidePin = "OwningAbility", DefaultToSelf = "OwningAbility", BlueprintInternalUseOnly = "TRUE")) diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitGameplayEffectApplied.h b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitGameplayEffectApplied.h index 3465b908e0e7..768e9e705914 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitGameplayEffectApplied.h +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitGameplayEffectApplied.h @@ -23,6 +23,10 @@ class UAbilityTask_WaitGameplayEffectApplied : public UAbilityTask FGameplayTargetDataFilterHandle Filter; FGameplayTagRequirements SourceTagRequirements; FGameplayTagRequirements TargetTagRequirements; + + FGameplayTagQuery SourceTagQuery; + FGameplayTagQuery TargetTagQuery; + bool TriggerOnce; bool ListenForPeriodicEffects; diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitGameplayEffectApplied_Self.h b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitGameplayEffectApplied_Self.h index e33f36574ab3..8dde4614be8b 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitGameplayEffectApplied_Self.h +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitGameplayEffectApplied_Self.h @@ -10,8 +10,8 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FGameplayEffectAppliedSelfDelegate, AActor*, Source, FGameplayEffectSpecHandle, SpecHandle, FActiveGameplayEffectHandle, ActiveHandle ); -UCLASS(MinimalAPI) -class UAbilityTask_WaitGameplayEffectApplied_Self : public UAbilityTask_WaitGameplayEffectApplied +UCLASS() +class GAMEPLAYABILITIES_API UAbilityTask_WaitGameplayEffectApplied_Self : public UAbilityTask_WaitGameplayEffectApplied { GENERATED_UCLASS_BODY() @@ -24,6 +24,15 @@ class UAbilityTask_WaitGameplayEffectApplied_Self : public UAbilityTask_WaitGame */ UFUNCTION(BlueprintCallable, Category="Ability|Tasks", meta = (HidePin = "OwningAbility", DefaultToSelf = "OwningAbility", BlueprintInternalUseOnly = "TRUE")) static UAbilityTask_WaitGameplayEffectApplied_Self* WaitGameplayEffectAppliedToSelf(UGameplayAbility* OwningAbility, const FGameplayTargetDataFilterHandle SourceFilter, FGameplayTagRequirements SourceTagRequirements, FGameplayTagRequirements TargetTagRequirements, bool TriggerOnce=false, AActor* OptionalExternalOwner=nullptr, bool ListenForPeriodicEffect=false ); + + /** + * Wait until the owner *receives* a GameplayEffect from a given source (the source may be the owner too!). If TriggerOnce is true, this task will only return one time. Otherwise it will return everytime a GE is applied that meets the requirements over the life of the ability + * Optional External Owner can be used to run this task on someone else (not the owner of the ability). By default you can leave this empty. + * + * This version uses FGameplayTagQuery (more power) instead of FGameplayTagRequirements (faster) + */ + UFUNCTION(BlueprintCallable, Category="Ability|Tasks", meta = (HidePin = "OwningAbility", DefaultToSelf = "OwningAbility", BlueprintInternalUseOnly = "TRUE")) + static UAbilityTask_WaitGameplayEffectApplied_Self* WaitGameplayEffectAppliedToSelf_Query(UGameplayAbility* OwningAbility, const FGameplayTargetDataFilterHandle SourceFilter, FGameplayTagQuery SourceTagQuery, FGameplayTagQuery TargetTagQuery, bool TriggerOnce=false, AActor* OptionalExternalOwner=nullptr, bool ListenForPeriodicEffect=false ); protected: diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitGameplayEffectApplied_Target.h b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitGameplayEffectApplied_Target.h index fb7dd582a19f..c0e2c11e62f3 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitGameplayEffectApplied_Target.h +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitGameplayEffectApplied_Target.h @@ -10,8 +10,8 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FGameplayEffectAppliedTargetDelegate, AActor*, Target, FGameplayEffectSpecHandle, SpecHandle, FActiveGameplayEffectHandle, ActiveHandle ); -UCLASS(MinimalAPI) -class UAbilityTask_WaitGameplayEffectApplied_Target : public UAbilityTask_WaitGameplayEffectApplied +UCLASS() +class GAMEPLAYABILITIES_API UAbilityTask_WaitGameplayEffectApplied_Target : public UAbilityTask_WaitGameplayEffectApplied { GENERATED_UCLASS_BODY() @@ -24,6 +24,13 @@ class UAbilityTask_WaitGameplayEffectApplied_Target : public UAbilityTask_WaitGa */ UFUNCTION(BlueprintCallable, Category="Ability|Tasks", meta = (HidePin = "OwningAbility", DefaultToSelf = "OwningAbility", BlueprintInternalUseOnly = "TRUE")) static UAbilityTask_WaitGameplayEffectApplied_Target* WaitGameplayEffectAppliedToTarget(UGameplayAbility* OwningAbility, const FGameplayTargetDataFilterHandle TargetFilter, FGameplayTagRequirements SourceTagRequirements, FGameplayTagRequirements TargetTagRequirements, bool TriggerOnce=false, AActor* OptionalExternalOwner=nullptr, bool ListenForPeriodicEffects=false); + + /** + * Wait until the owner (or External Owner) applies a GameplayEffect to a Target (the target may be the owner too!). If TriggerOnce is true, this task will only return one time. Otherwise it will return everytime a GE is applied that meets the requirements over the life of the ability + * Optional External Owner can be used to run this task on someone else (not the owner of the ability). By default you can leave this empty. + */ + UFUNCTION(BlueprintCallable, Category="Ability|Tasks", meta = (HidePin = "OwningAbility", DefaultToSelf = "OwningAbility", BlueprintInternalUseOnly = "TRUE")) + static UAbilityTask_WaitGameplayEffectApplied_Target* WaitGameplayEffectAppliedToTarget_Query(UGameplayAbility* OwningAbility, const FGameplayTargetDataFilterHandle SourceFilter, FGameplayTagQuery SourceTagQuery, FGameplayTagQuery TargetTagQuery, bool TriggerOnce=false, AActor* OptionalExternalOwner=nullptr, bool ListenForPeriodicEffect=false ); protected: diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitGameplayEvent.h b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitGameplayEvent.h index 049fe139780b..85a78ff53cbd 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitGameplayEvent.h +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitGameplayEvent.h @@ -12,8 +12,8 @@ class UAbilitySystemComponent; DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FWaitGameplayEventDelegate, FGameplayEventData, Payload); -UCLASS(MinimalAPI) -class UAbilityTask_WaitGameplayEvent : public UAbilityTask +UCLASS() +class GAMEPLAYABILITIES_API UAbilityTask_WaitGameplayEvent : public UAbilityTask { GENERATED_UCLASS_BODY() diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitGameplayTag.h b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitGameplayTag.h index 866ef4bc8832..10b903f2b430 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitGameplayTag.h +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/Tasks/AbilityTask_WaitGameplayTag.h @@ -9,8 +9,8 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE(FWaitGameplayTagDelegate); -UCLASS(MinimalAPI) -class UAbilityTask_WaitGameplayTagAdded : public UAbilityTask_WaitGameplayTag +UCLASS() +class GAMEPLAYABILITIES_API UAbilityTask_WaitGameplayTagAdded : public UAbilityTask_WaitGameplayTag { GENERATED_UCLASS_BODY() @@ -29,8 +29,8 @@ class UAbilityTask_WaitGameplayTagAdded : public UAbilityTask_WaitGameplayTag virtual void GameplayTagCallback(const FGameplayTag Tag, int32 NewCount) override; }; -UCLASS(MinimalAPI) -class UAbilityTask_WaitGameplayTagRemoved : public UAbilityTask_WaitGameplayTag +UCLASS() +class GAMEPLAYABILITIES_API UAbilityTask_WaitGameplayTagRemoved : public UAbilityTask_WaitGameplayTag { GENERATED_UCLASS_BODY() diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/AbilitySystemBlueprintLibrary.h b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/AbilitySystemBlueprintLibrary.h index 40dbd42ae5de..5920e5ae8e4a 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/AbilitySystemBlueprintLibrary.h +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/AbilitySystemBlueprintLibrary.h @@ -243,6 +243,9 @@ class GAMEPLAYABILITIES_API UAbilitySystemBlueprintLibrary : public UBlueprintFu UFUNCTION(BlueprintCallable, Category = "Ability|GameplayEffect") static FGameplayEffectSpecHandle AssignSetByCallerMagnitude(FGameplayEffectSpecHandle SpecHandle, FName DataName, float Magnitude); + UFUNCTION(BlueprintCallable, Category = "Ability|GameplayEffect") + static FGameplayEffectSpecHandle AssignTagSetByCallerMagnitude(FGameplayEffectSpecHandle SpecHandle, FGameplayTag DataTag, float Magnitude); + UFUNCTION(BlueprintCallable, Category = "Ability|GameplayEffect") static FGameplayEffectSpecHandle SetDuration(FGameplayEffectSpecHandle SpecHandle, float Duration); @@ -294,6 +297,9 @@ class GAMEPLAYABILITIES_API UAbilitySystemBlueprintLibrary : public UBlueprintFu UFUNCTION(BlueprintCallable, Category = "Ability|GameplayEffect") static float GetModifiedAttributeMagnitude(FGameplayEffectSpecHandle SpecHandle, FGameplayAttribute Attribute); + /** Helper function that may be useful to call from native as well */ + static float GetModifiedAttributeMagnitude(const FGameplayEffectSpec& SpecHandle, FGameplayAttribute Attribute); + // ------------------------------------------------------------------------------- // FActiveGameplayEffectHandle // ------------------------------------------------------------------------------- diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/AbilitySystemComponent.h b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/AbilitySystemComponent.h index e770f7a42fd1..996993406e5d 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/AbilitySystemComponent.h +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/AbilitySystemComponent.h @@ -553,8 +553,11 @@ class GAMEPLAYABILITIES_API UAbilitySystemComponent : public UGameplayTasksCompo /** Returns multicast delegate that is invoked whenever a tag is added or removed (but not if just count is increased. Only for 'new' and 'removed' events) */ FOnGameplayEffectTagCountChanged& RegisterGenericGameplayTagEvent(); + FOnGameplayAttributeChange& RegisterGameplayAttributeEvent(FGameplayAttribute Attribute); + FOnGameplayAttributeValueChange& GetGameplayAttributeValueChangeDelegate(FGameplayAttribute Attribute); + // -------------------------------------------- // System Attributes // -------------------------------------------- diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/AbilitySystemGlobals.h b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/AbilitySystemGlobals.h index 2d8e8202f93c..9d502c977b4f 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/AbilitySystemGlobals.h +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/AbilitySystemGlobals.h @@ -66,6 +66,11 @@ class GAMEPLAYABILITIES_API UAbilitySystemGlobals : public UObject /** Global callback that can handle game-specific code that needs to run before applying a gameplay effect spec */ virtual void GlobalPreGameplayEffectSpecApply(FGameplayEffectSpec& Spec, UAbilitySystemComponent* AbilitySystemComponent); + // Stubs for WIP feature that will come to engine + virtual void PushCurrentAppliedGE(const FGameplayEffectSpec* Spec, UAbilitySystemComponent* AbilitySystemComponent) { } + virtual void SetCurrentAppliedGE(const FGameplayEffectSpec* Spec) { } + virtual void PopCurrentAppliedGE() { } + /** Returns true if the ability system should try to predict gameplay effects applied to non local targets */ bool ShouldPredictTargetGameplayEffects() const { @@ -109,6 +114,11 @@ class GAMEPLAYABILITIES_API UAbilitySystemGlobals : public UObject #endif } +#if WITH_EDITOR + // Allows projects to override PostEditChangeProeprty on GEs without having to subclass Gameplayeffect. Intended for validation/auto populating based on changed data. + virtual void GameplayEffectPostEditChangeProperty(class UGameplayEffect* GE, FPropertyChangedEvent& PropertyChangedEvent) { } +#endif + /** The class to instantiate as the globals object. Defaults to this class but can be overridden */ UPROPERTY(config) FStringClassReference AbilitySystemGlobalsClassName; @@ -343,3 +353,16 @@ public: void Notify_FindAssetInEditor(FString AssetName, int AssetType); FOnAbilitySystemAssetFoundDelegate AbilityFindAssetInEditorCallbacks; }; + + +struct FScopeCurrentGameplayEffectBeingApplied +{ + FScopeCurrentGameplayEffectBeingApplied(const FGameplayEffectSpec* Spec, UAbilitySystemComponent* AbilitySystemComponent) + { + UAbilitySystemGlobals::Get().PushCurrentAppliedGE(Spec, AbilitySystemComponent); + } + ~FScopeCurrentGameplayEffectBeingApplied() + { + UAbilitySystemGlobals::Get().PopCurrentAppliedGE(); + } +}; \ No newline at end of file diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/AbilitySystemTestPawn.h b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/AbilitySystemTestPawn.h index ca62377b95d8..4300454bd6b0 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/AbilitySystemTestPawn.h +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/AbilitySystemTestPawn.h @@ -20,9 +20,8 @@ class GAMEPLAYABILITIES_API AAbilitySystemTestPawn : public ADefaultPawn, public virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override; -private_subobject: +private: /** DefaultPawn collision component */ - DEPRECATED_FORGAME(4.6, "AbilitySystemComponent should not be accessed directly, please use GetAbilitySystemComponent() function instead. AbilitySystemComponent will soon be private and your code will not compile.") UPROPERTY(Category = AbilitySystem, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) class UAbilitySystemComponent* AbilitySystemComponent; public: @@ -33,5 +32,5 @@ public: static FName AbilitySystemComponentName; /** Returns AbilitySystemComponent subobject **/ - class UAbilitySystemComponent* GetAbilitySystemComponent(); + class UAbilitySystemComponent* GetAbilitySystemComponent() { return AbilitySystemComponent; } }; diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/AttributeSet.h b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/AttributeSet.h index 0ac9658a7acc..9e345cfbac9e 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/AttributeSet.h +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/AttributeSet.h @@ -125,6 +125,9 @@ struct GAMEPLAYABILITIES_API FGameplayAttribute UPROPERTY(Category = GameplayAttribute, VisibleAnywhere, BlueprintReadOnly) FString AttributeName; + // In editor, this will filter out properties with meta tag "HideInDetailsView" or equal to FilterMetaStr. In non editor, it returns all properties. + static void GetAllAttributeProperties(TArray& OutProperties, FString FilterMetaStr=FString()); + private: friend class FAttributePropertyDetails; diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/GameplayAbilitySpec.h b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/GameplayAbilitySpec.h index 9a6b4fa35714..9f2ba7df8aa8 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/GameplayAbilitySpec.h +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/GameplayAbilitySpec.h @@ -208,7 +208,7 @@ private: /** An activatable ability spec, hosted on the ability system component. This defines both what the ability is (what class, what level, input binding etc) * and also holds runtime state that must be kept outside of the ability being instanced/activated. */ -USTRUCT() +USTRUCT(BlueprintType) struct GAMEPLAYABILITIES_API FGameplayAbilitySpec : public FFastArraySerializerItem { GENERATED_USTRUCT_BODY() @@ -305,7 +305,7 @@ struct GAMEPLAYABILITIES_API FGameplayAbilitySpec : public FFastArraySerializerI /** Fast serializer wrapper for above struct */ -USTRUCT() +USTRUCT(BlueprintType) struct GAMEPLAYABILITIES_API FGameplayAbilitySpecContainer : public FFastArraySerializer { GENERATED_USTRUCT_BODY() diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/GameplayEffect.h b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/GameplayEffect.h index c9727cd43088..b6124c36b0f4 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/GameplayEffect.h +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/GameplayEffect.h @@ -207,9 +207,12 @@ struct FSetByCallerFloat {} /** The Name the caller (code or blueprint) will use to set this magnitude by. */ - UPROPERTY(EditDefaultsOnly, Category=SetByCaller) + UPROPERTY(VisibleDefaultsOnly, Category=SetByCaller) FName DataName; + UPROPERTY(EditDefaultsOnly, Category = SetByCaller, meta = (Categories = "SetByCaller")) + FGameplayTag DataTag; + /** Equality/Inequality operators */ bool operator==(const FSetByCallerFloat& Other) const; bool operator!=(const FSetByCallerFloat& Other) const; @@ -332,7 +335,7 @@ protected: * Struct representing modifier info used exclusively for "scoped" executions that happen instantaneously. These are * folded into a calculation only for the extent of the calculation and never permanently added to an aggregator. */ -USTRUCT() +USTRUCT(BlueprintType) struct FGameplayEffectExecutionScopedModifierInfo { GENERATED_USTRUCT_BODY() @@ -376,7 +379,7 @@ struct FGameplayEffectExecutionScopedModifierInfo /** * Struct for gameplay effects that apply only if another gameplay effect (or execution) was successfully applied. */ -USTRUCT() +USTRUCT(BlueprintType) struct GAMEPLAYABILITIES_API FConditionalGameplayEffect { GENERATED_USTRUCT_BODY() @@ -398,7 +401,7 @@ struct GAMEPLAYABILITIES_API FConditionalGameplayEffect * Struct representing the definition of a custom execution for a gameplay effect. * Custom executions run special logic from an outside class each time the gameplay effect executes. */ -USTRUCT() +USTRUCT(BlueprintType) struct GAMEPLAYABILITIES_API FGameplayEffectExecutionDefinition { GENERATED_USTRUCT_BODY() @@ -439,7 +442,7 @@ struct GAMEPLAYABILITIES_API FGameplayEffectExecutionDefinition * Does not tell us how exactly * */ -USTRUCT() +USTRUCT(BlueprintType) struct GAMEPLAYABILITIES_API FGameplayModifierInfo { GENERATED_USTRUCT_BODY() @@ -487,7 +490,7 @@ struct GAMEPLAYABILITIES_API FGameplayModifierInfo * This is a cosmetic cue that can be tied to a UGameplayEffect. * This is essentially a GameplayTag + a Min/Max level range that is used to map the level of a GameplayEffect to a normalized value used by the GameplayCue system. */ -USTRUCT() +USTRUCT(BlueprintType) struct FGameplayEffectCue { GENERATED_USTRUCT_BODY() @@ -868,7 +871,7 @@ private: * FGameplayEffectSpec is modifiable. We start with initial conditions and modifications be applied to it. In this sense, it is stateful/mutable but it * is still distinct from an FActiveGameplayEffect which in an applied instance of an FGameplayEffectSpec. */ -USTRUCT() +USTRUCT(BlueprintType) struct GAMEPLAYABILITIES_API FGameplayEffectSpec { GENERATED_USTRUCT_BODY() @@ -947,8 +950,14 @@ struct GAMEPLAYABILITIES_API FGameplayEffectSpec /** Sets the magnitude of a SetByCaller modifier */ void SetSetByCallerMagnitude(FName DataName, float Magnitude); + /** Sets the magnitude of a SetByCaller modifier */ + void SetSetByCallerMagnitude(FGameplayTag DataTag, float Magnitude); + /** Returns the magnitude of a SetByCaller modifier. Will return 0.f and Warn if the magnitude has not been set. */ - float GetSetByCallerMagnitude(FName DataName, bool WarnIfNotFound=true, float DefaultIfNotFound=0.f) const; + float GetSetByCallerMagnitude(FName DataName, bool WarnIfNotFound = true, float DefaultIfNotFound = 0.f) const; + + /** Returns the magnitude of a SetByCaller modifier. Will return 0.f and Warn if the magnitude has not been set. */ + float GetSetByCallerMagnitude(FGameplayTag DataTag, bool WarnIfNotFound = true, float DefaultIfNotFound = 0.f) const; void SetLevel(float InLevel); @@ -1072,7 +1081,8 @@ public: private: /** Map of set by caller magnitudes */ - TMap SetByCallerMagnitudes; + TMap SetByCallerNameMagnitudes; + TMap SetByCallerTagMagnitudes; UPROPERTY() FGameplayEffectContextHandle EffectContext; // This tells us how we got here (who / what applied us) @@ -1612,8 +1622,11 @@ struct GAMEPLAYABILITIES_API FActiveGameplayEffectsContainer : public FFastArray // ------------------------------------------------------------------------------------------- + DEPRECATED(4.17, "Use GetGameplayAttributeValueChangeDelegate (the delegate signature has changed)") FOnGameplayAttributeChange& RegisterGameplayAttributeEvent(FGameplayAttribute Attribute); + FOnGameplayAttributeValueChange& GetGameplayAttributeValueChangeDelegate(FGameplayAttribute Attribute); + void OnOwnerTagChange(FGameplayTag TagChange, int32 NewCount); bool HasApplicationImmunityToSpec(const FGameplayEffectSpec& SpecToApply, const FActiveGameplayEffect*& OutGEThatProvidedImmunity) const; @@ -1713,7 +1726,11 @@ private: TMap AttributeAggregatorMap; + // DEPRECATED: use AttributeValueChangeDelegates TMap AttributeChangeDelegates; + + TMap AttributeValueChangeDelegates; + TMap > ActiveEffectTagDependencies; diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/GameplayEffectExecutionCalculation.h b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/GameplayEffectExecutionCalculation.h index d8dc70b08166..a590e3facd58 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/GameplayEffectExecutionCalculation.h +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/GameplayEffectExecutionCalculation.h @@ -15,7 +15,7 @@ class UAbilitySystemComponent; /** Struct representing parameters for a custom gameplay effect execution. Should not be held onto via reference, used just for the scope of the execution */ -USTRUCT() +USTRUCT(BlueprintType) struct GAMEPLAYABILITIES_API FGameplayEffectCustomExecutionParameters { GENERATED_USTRUCT_BODY() @@ -125,7 +125,7 @@ private: }; /** Struct representing the output of a custom gameplay effect execution. */ -USTRUCT() +USTRUCT(BlueprintType) struct GAMEPLAYABILITIES_API FGameplayEffectCustomExecutionOutput { GENERATED_USTRUCT_BODY() diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/GameplayEffectExtension.h b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/GameplayEffectExtension.h index 55445b80ff1f..fb947f3a32d7 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/GameplayEffectExtension.h +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/GameplayEffectExtension.h @@ -21,7 +21,6 @@ struct FGameplayEffectModCallbackData , EvaluatedData(InEvaluatedData) , Target(InTarget) { - } const struct FGameplayEffectSpec& EffectSpec; // The spec that the mod came from diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/GameplayEffectTypes.h b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/GameplayEffectTypes.h index 3d80eea413ef..31ac4a7634f9 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/GameplayEffectTypes.h +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/GameplayEffectTypes.h @@ -232,7 +232,7 @@ private: bool bPassedFiltersAndWasExecuted; }; -USTRUCT() +USTRUCT(BlueprintType) struct FGameplayModifierEvaluatedData { GENERATED_USTRUCT_BODY() @@ -278,7 +278,7 @@ struct FGameplayModifierEvaluatedData }; /** Struct defining gameplay attribute capture options for gameplay effects */ -USTRUCT() +USTRUCT(BlueprintType) struct GAMEPLAYABILITIES_API FGameplayEffectAttributeCaptureDefinition { GENERATED_USTRUCT_BODY() @@ -373,6 +373,8 @@ struct GAMEPLAYABILITIES_API FGameplayEffectContext /** returns the CDO of the ability used to instigate this context */ const UGameplayAbility* GetAbility() const; + const UGameplayAbility* GetAbilityInstance_NotReplicated() const; + int32 GetAbilityLevel() const { return AbilityLevel; @@ -490,10 +492,14 @@ protected: UPROPERTY() TWeakObjectPtr EffectCauser; - /** the ability that is responsible for this effect context */ + /** the ability CDO that is responsible for this effect context (replicated) */ UPROPERTY() TWeakObjectPtr AbilityCDO; + /** the ability instance that is responsible for this effect context (NOT replicated) */ + UPROPERTY(NotReplicated) + TWeakObjectPtr AbilityInstanceNotReplicated; + UPROPERTY() int32 AbilityLevel; @@ -622,6 +628,16 @@ struct FGameplayEffectContextHandle return nullptr; } + /** Returns the Ability Instance (never replicated) */ + const UGameplayAbility* GetAbilityInstance_NotReplicated() const + { + if (IsValid()) + { + return Data->GetAbilityInstance_NotReplicated(); + } + return nullptr; + } + int32 GetAbilityLevel() const { if (IsValid()) @@ -954,8 +970,20 @@ DECLARE_MULTICAST_DELEGATE_ThreeParams(FOnActiveGameplayEffectStackChange, FActi /** FActiveGameplayEffectHandle that is being effect, the start time, duration of the effect */ DECLARE_MULTICAST_DELEGATE_ThreeParams(FOnActiveGameplayEffectTimeChange, FActiveGameplayEffectHandle, float, float); +// This is deprecated, use FOnGameplayAttributeValueChange DECLARE_MULTICAST_DELEGATE_TwoParams(FOnGameplayAttributeChange, float, const FGameplayEffectModCallbackData*); +struct FOnAttributeChangeData +{ + FGameplayAttribute Attribute; + + float NewValue; + float OldValue; + const FGameplayEffectModCallbackData* GEModData; +}; + +DECLARE_MULTICAST_DELEGATE_OneParam(FOnGameplayAttributeValueChange, const FOnAttributeChangeData&); + DECLARE_DELEGATE_RetVal(FGameplayTagContainer, FGetGameplayTags); DECLARE_DELEGATE_RetVal_OneParam(FOnGameplayEffectTagCountChanged&, FRegisterGameplayTagChangeDelegate, FGameplayTag); diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilitiesEditor/Private/AttributeDetails.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilitiesEditor/Private/AttributeDetails.cpp index 05a21fc6162d..26217e45d20e 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilitiesEditor/Private/AttributeDetails.cpp +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilitiesEditor/Private/AttributeDetails.cpp @@ -43,57 +43,7 @@ void FAttributePropertyDetails::CustomizeHeader( TSharedRef Str FString FilterMetaStr = StructPropertyHandle->GetProperty()->GetMetaData(TEXT("FilterMetaTag")); TArray PropertiesToAdd; - - { - // Gather all UAttribute classes - for (TObjectIterator ClassIt; ClassIt; ++ClassIt) - { - UClass *Class = *ClassIt; - if (Class->IsChildOf(UAttributeSet::StaticClass()) && !Class->ClassGeneratedBy) - { - // Allow entire classes to be filtered globally - if (Class->HasMetaData(TEXT("HideInDetailsView"))) - { - continue; - } - - for (TFieldIterator PropertyIt(Class, EFieldIteratorFlags::ExcludeSuper); PropertyIt; ++PropertyIt) - { - UProperty* Property = *PropertyIt; - - if (!FilterMetaStr.IsEmpty() && Property->HasMetaData(*FilterMetaStr)) - { - continue; - } - - // Allow properties to be filtered globally (never show up) - if (Property->HasMetaData(TEXT("HideInDetailsView"))) - { - continue; - } - - PropertiesToAdd.Add(Property); - } - } - - // UAbilitySystemComponent can add 'system' attributes - if (Class->IsChildOf(UAbilitySystemComponent::StaticClass()) && !Class->ClassGeneratedBy) - { - for (TFieldIterator PropertyIt(Class, EFieldIteratorFlags::ExcludeSuper); PropertyIt; ++PropertyIt) - { - UProperty* Property = *PropertyIt; - - // SystemAttributes have to be explicitly tagged - if (Property->HasMetaData(TEXT("SystemGameplayAttribute")) == false) - { - continue; - } - - PropertiesToAdd.Add(Property); - } - } - } - } + FGameplayAttribute::GetAllAttributeProperties(PropertiesToAdd, FilterMetaStr); for ( auto* Property : PropertiesToAdd ) { diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilitiesEditor/Private/GameplayAbilitiesEditorModule.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilitiesEditor/Private/GameplayAbilitiesEditorModule.cpp index 3c4a622c7e30..8133241d66db 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilitiesEditor/Private/GameplayAbilitiesEditorModule.cpp +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilitiesEditor/Private/GameplayAbilitiesEditorModule.cpp @@ -45,6 +45,8 @@ #include "LevelEditor.h" #include "Misc/HotReloadInterface.h" #include "EditorReimportHandler.h" +#include "GameplayEffectCreationMenu.h" +#include "ISettingsModule.h" class FGameplayAbilitiesEditorModule : public IGameplayAbilitiesEditorModule @@ -140,6 +142,17 @@ void FGameplayAbilitiesEditorModule::StartupModule() TSharedRef GABAction = MakeShareable(new FAssetTypeActions_GameplayAbilitiesBlueprint()); RegisterAssetTypeAction(AssetTools, GABAction); + if (ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings")) + { + SettingsModule->RegisterSettings("Project", "Project", "Gameplay Effect Parents", + NSLOCTEXT("GameplayAbilitiesEditorModule", "GameplayEffectParentName", "Gameplay Effect Parents"), + NSLOCTEXT("GameplayAbilitiesEditorModule", "GameplayEffectParentNameDesc", "Data Driven way of specifying common parent Gameplay Effect classes that are accessible through File menu"), + GetMutableDefault() + ); + + GetDefault()->AddMenuExtensions(); + } + // Register factories for pins and nodes GameplayAbilitiesGraphPanelPinFactory = MakeShareable(new FGameplayAbilitiesGraphPanelPinFactory()); FEdGraphUtilities::RegisterVisualPinFactory(GameplayAbilitiesGraphPanelPinFactory); diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilitiesEditor/Private/GameplayEffectCreationMenu.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilitiesEditor/Private/GameplayEffectCreationMenu.cpp new file mode 100644 index 000000000000..59dd667df427 --- /dev/null +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilitiesEditor/Private/GameplayEffectCreationMenu.cpp @@ -0,0 +1,165 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "GameplayEffectCreationMenu.h" +#include "GameplayAbilitiesEditor.h" + + +#include "LevelEditor.h" +#include "AssetEditorManager.h" +#include "Modules/ModuleManager.h" +#include "Framework/MultiBox/MultiBoxBuilder.h" +#include "ContentBrowserModule.h" +#include "ContentBrowserDelegates.h" +#include "Factories/BlueprintFactory.h" +#include "AssetToolsModule.h" +#include "IContentBrowserSingleton.h" + +// Static +TFunction< FString(FString BaseName, FString Path) > UGameplayEffectCreationMenu::GetDefaultAssetNameFunc; + +UGameplayEffectCreationMenu::UGameplayEffectCreationMenu() +{ + +} + +// Helper struct/function. The editable data is flat and we want to build a tree representation of it +struct FGEMenuItem : TSharedFromThis +{ + TMap> SubItems; + + FString DefaultAssetName; + TSubclassOf CDO; + + static void BuildMenus_r(TSharedPtr Item, FMenuBuilder& MenuBuilder, TArray SelectedPaths) + { + for (auto It : Item->SubItems) + { + TSharedPtr SubItem = It.Value; + FString CatName = It.Key; + + // Add a submenu if this guy has sub items + if (SubItem->SubItems.Num() > 0) + { + MenuBuilder.AddSubMenu( + FText::FromString(CatName), + FText::FromString(CatName), + FNewMenuDelegate::CreateLambda([SubItem, SelectedPaths](FMenuBuilder& SubMenuBuilder) + { + BuildMenus_r(SubItem, SubMenuBuilder, SelectedPaths); + }) + ); + } + + // Add the actual menu item to create the new GE + if (SubItem->CDO.Get() != nullptr) + { + MenuBuilder.AddMenuEntry( + FText::FromString(CatName), // note: the last category string is what we use for this. Using the "Default Asset Name" is not desirable here. (e.g., Damage|Ability|Instant but "Damage" is default asset name) + FText(), + FSlateIcon(), + FUIAction( + FExecuteAction::CreateLambda([=]() + { + if (SelectedPaths.Num() > 0) + { + FAssetToolsModule& AssetToolsModule = FModuleManager::GetModuleChecked("AssetTools"); + FContentBrowserModule& ContentBrowserModule = FModuleManager::LoadModuleChecked("ContentBrowser"); + + TArray SelectedAssets; + ContentBrowserModule.Get().GetSelectedAssets(SelectedAssets); + + // Create the GameplayCue Notify + UBlueprintFactory* BlueprintFactory = NewObject(); + BlueprintFactory->ParentClass = SubItem->CDO; + + // Figure out default name. Projects can set UGameplayEffectCreationMenu::GetDefaultAssetNameFunc to customize this. + FString PackageName = SelectedPaths[0]; + FString AssetName; + if (UGameplayEffectCreationMenu::GetDefaultAssetNameFunc) + { + AssetName = UGameplayEffectCreationMenu::GetDefaultAssetNameFunc(SubItem->DefaultAssetName, PackageName); + } + else + { + AssetName = FString::Printf(TEXT("GE_%s"), *SubItem->DefaultAssetName); + } + + FString DefaultFullPath = PackageName / AssetName; + + AssetToolsModule.Get().CreateUniqueAssetName(DefaultFullPath, TEXT(""), /*out*/ PackageName, /*out*/ AssetName); + + ContentBrowserModule.Get().CreateNewAsset(*AssetName, SelectedPaths[0], UBlueprint::StaticClass(), BlueprintFactory); + } + + })) + ); + } + } + } +}; + +void TopMenuBuilderFunc(FMenuBuilder& TopMenuBuilder, const TArray SelectedPaths, TArray Definitions) +{ + if (Definitions.Num() == 0) + { + return; + } + + TopMenuBuilder.AddSubMenu( + NSLOCTEXT("GameplayAbilitiesEditorModule", "CreateGameplayEffect", "New Gameplay Effect"), + NSLOCTEXT("GameplayAbilitiesEditorModule", "CreateGameplayEffect", "Create new Gameplay Effect from list of curated parents"), + FNewMenuDelegate::CreateLambda([SelectedPaths, Definitions](FMenuBuilder& GETopMenuBuilder) + { + // Loop through our Definitions and build FGEItems + TSharedPtr RootItem = MakeShareable(new FGEMenuItem); + for (const FGameplayEffectCreationData& Def : Definitions) + { + if (Def.ParentGameplayEffect.Get() == nullptr) + { + continue; + } + + TArray CategoryStrings; + Def.MenuPath.ParseIntoArray(CategoryStrings, TEXT("|"), true); + + FGEMenuItem* CurrentItem = RootItem.Get(); + for (int32 idx=0; idx < CategoryStrings.Num(); ++idx) + { + FString& Str = CategoryStrings[idx]; + TSharedPtr& DestItem = CurrentItem->SubItems.FindOrAdd(Str); + if (!DestItem.IsValid()) + { + DestItem = MakeShareable(new FGEMenuItem); + } + CurrentItem = DestItem.Get(); + } + + CurrentItem->DefaultAssetName = Def.BaseName; + CurrentItem->CDO = Def.ParentGameplayEffect.Get(); + } + + // Build menu delegates based on our data + FGEMenuItem::BuildMenus_r(RootItem, GETopMenuBuilder, SelectedPaths); + })); +} + +void UGameplayEffectCreationMenu::AddMenuExtensions() const +{ +#if 1 + TSharedPtr CommandBindings = MakeShareable(new FUICommandList()); + + FContentBrowserModule& ContentBrowserModule = FModuleManager::GetModuleChecked( TEXT("ContentBrowser") ); + ContentBrowserModule.GetAllAssetContextMenuExtenders().Add(FContentBrowserMenuExtender_SelectedPaths::CreateLambda([=](const TArray& SelectedPaths) + { + TSharedRef Extender = MakeShared(); + Extender->AddMenuExtension( + "ContentBrowserNewAdvancedAsset", + EExtensionHook::After, + TSharedPtr(), + FMenuExtensionDelegate::CreateStatic(&TopMenuBuilderFunc, SelectedPaths, Definitions) + ); + + return Extender; + })); +#endif +} diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilitiesEditor/Private/SGameplayCueEditor.cpp b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilitiesEditor/Private/SGameplayCueEditor.cpp index a94c91432a1c..aaffe3fd3aae 100644 --- a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilitiesEditor/Private/SGameplayCueEditor.cpp +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilitiesEditor/Private/SGameplayCueEditor.cpp @@ -347,178 +347,8 @@ public: ]; } -BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION - /** Builds widget for rows in the GameplayCue Editor tab */ - TSharedRef OnGenerateWidgetForGameplayCueListView(TSharedPtr< FGCTreeItem > InItem, const TSharedRef& OwnerTable) - { - class SCueItemWidget : public SMultiColumnTableRow< TSharedPtr< FGCTreeItem > > - { - public: - SLATE_BEGIN_ARGS(SCueItemWidget){} - SLATE_END_ARGS() - - void Construct(const FArguments& InArgs, const TSharedRef& InOwnerTable, TSharedPtr InListItem, SGameplayCueEditorImpl* InGameplayCueEditor ) - { - Item = InListItem; - GameplayCueEditor = InGameplayCueEditor; - SMultiColumnTableRow< TSharedPtr< FGCTreeItem > >::Construct( - FSuperRowType::FArguments() - , InOwnerTable); - } - private: - - virtual TSharedRef GenerateWidgetForColumn(const FName& ColumnName) override - { - if (ColumnName == CueTagColumnName) - { - return - SNew(SHorizontalBox) - + SHorizontalBox::Slot() - .AutoWidth() - [ - SNew(SExpanderArrow, SharedThis(this)) - ] - + SHorizontalBox::Slot() - .FillWidth(1) - .VAlign(VAlign_Center) - [ - SNew(STextBlock) - .ColorAndOpacity(Item->GameplayCueTag.IsValid() ? FSlateColor::UseForeground() : FSlateColor::UseSubduedForeground()) - .Text(FText::FromString(Item->Description.IsEmpty() ? Item->GameplayCueTagName.ToString() : FString::Printf(TEXT("%s (%s)"), *Item->Description, *Item->GameplayCueTagName.ToString()))) - ]; - } - else if (ColumnName == CueHandlerColumnName) - { - if (Item->GameplayCueNotifyObj.ToString().IsEmpty() == false) - { - FString ObjName = Item->GameplayCueNotifyObj.ToString(); - - int32 idx; - if (ObjName.FindLastChar(TEXT('.'), idx)) - { - ObjName = ObjName.RightChop(idx + 1); - if (ObjName.FindLastChar(TEXT('_'), idx)) - { - ObjName = ObjName.Left(idx); - } - } - - return - SNew(SBox) - .HAlign(HAlign_Left) - [ - SNew(SHyperlink) - .Style(FEditorStyle::Get(), "Common.GotoBlueprintHyperlink") - .Text(FText::FromString(ObjName)) - .OnNavigate(this, &SCueItemWidget::NavigateToHandler) - ]; - } - else if (Item->FunctionPtr.IsValid()) - { - FString ObjName; - UFunction* Func = Item->FunctionPtr.Get(); - UClass* OuterClass = Cast(Func->GetOuter()); - if (OuterClass) - { - ObjName = OuterClass->GetName(); - ObjName.RemoveFromEnd(TEXT("_c")); - } - - return - SNew(SBox) - .HAlign(HAlign_Left) - [ - SNew(SHyperlink) - .Text(FText::FromString(ObjName)) - .OnNavigate(this, &SCueItemWidget::NavigateToHandler) - ]; - } - else - { - return - SNew(SBox) - .HAlign(HAlign_Left) - [ - SNew(SHyperlink) - .Style(FEditorStyle::Get(), "Common.GotoNativeCodeHyperlink") - .Text(LOCTEXT("AddNew", "Add New")) - .OnNavigate(this, &SCueItemWidget::OnAddNewClicked) - ]; - } - } - else - { - return SNew(STextBlock).Text(LOCTEXT("UnknownColumn", "Unknown Column")); - } - } - - /** Create new GameplayCueNotify: brings up dialog to pick class, then creates it via the content browser. */ - void OnAddNewClicked() - { - { - // Add the tag if its not already. Note that the FGameplayTag may be valid as an implicit tag, and calling this - // will create it as an explicit tag, which is what we want. If the tag already exists - - TGuardValue SupressUpdate(SGameplayCueEditorImpl::bSuppressCueViewUpdate, true); - - IGameplayTagsEditorModule::Get().AddNewGameplayTagToINI(Item->GameplayCueTagName.ToString()); - } - - UClass* ParentClass=nullptr; - - // If this is an override, use the parent GC notify class as the base class - if (Item->ParentGameplayCueNotifyObj.IsValid()) - { - UObject* Obj = Item->ParentGameplayCueNotifyObj.ResolveObject(); - if (!Obj) - { - Obj = Item->ParentGameplayCueNotifyObj.TryLoad(); - } - - ParentClass = Cast(Obj); - if (ParentClass == nullptr) - { - ABILITY_LOG(Warning, TEXT("Unable to resolve object for parent GC notify: %s"), *Item->ParentGameplayCueNotifyObj.ToString()); - } - } - - GameplayCueEditor->OnSelectionChanged(Item, ESelectInfo::Direct); - - SGameplayCueEditor::CreateNewGameplayCueNotifyDialogue(Item->GameplayCueTagName.ToString(), ParentClass); - } - - void NavigateToHandler() - { - if (Item->GameplayCueNotifyObj.IsValid()) - { - SGameplayCueEditor::OpenEditorForNotify(Item->GameplayCueNotifyObj.ToString()); - - } - else if (Item->FunctionPtr.IsValid()) - { - SGameplayCueEditor::OpenEditorForNotify(Item->FunctionPtr->GetOuter()->GetPathName()); - } - } - - TSharedPtr< FGCTreeItem > Item; - SGameplayCueEditorImpl* GameplayCueEditor; - }; - - if ( InItem.IsValid() ) - { - return SNew(SCueItemWidget, GameplayCueTreeView.ToSharedRef(), InItem, this); - } - else - { - return - SNew(STableRow< TSharedPtr >, OwnerTable) - [ - SNew(STextBlock) - .Text(LOCTEXT("UnknownItemType", "Unknown Item Type")) - ]; - } - } + TSharedRef OnGenerateWidgetForGameplayCueListView(TSharedPtr< FGCTreeItem > InItem, const TSharedRef& OwnerTable); void OnFilterStateChanged(ECheckBoxState NewValue, TSharedPtr< FGCFilterTreeItem > Item) { @@ -539,73 +369,7 @@ BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION return FilterIds.Contains(Item->Data.UniqueID) ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; } - TSharedRef OnGenerateWidgetForFilterListView(TSharedPtr< FGCFilterTreeItem > InItem, const TSharedRef& OwnerTable) - { - class SFilterItemWidget : public SMultiColumnTableRow< TSharedPtr< FGCFilterTreeItem > > - { - public: - SLATE_BEGIN_ARGS(SFilterItemWidget){} - SLATE_END_ARGS() - - void Construct(const FArguments& InArgs, const TSharedRef& InOwnerTable, SGameplayCueEditorImpl* InGameplayCueEditor, TSharedPtr InListItem ) - { - Item = InListItem; - GameplayCueEditor = InGameplayCueEditor; - SMultiColumnTableRow< TSharedPtr< FGCFilterTreeItem > >::Construct(FSuperRowType::FArguments(), InOwnerTable); - } - private: - - virtual TSharedRef GenerateWidgetForColumn(const FName& ColumnName) override - { - if (ColumnName == CueTagColumnName) - { - return - SNew(SHorizontalBox) - + SHorizontalBox::Slot() - .AutoWidth() - [ - SNew(SExpanderArrow, SharedThis(this)) - ] - + SHorizontalBox::Slot() - .FillWidth(1) - .VAlign(VAlign_Center) - [ - SNew(SCheckBox) - .OnCheckStateChanged(GameplayCueEditor, &SGameplayCueEditorImpl::OnFilterStateChanged, Item) - .IsChecked(GameplayCueEditor, &SGameplayCueEditorImpl::IsFilterChecked, Item) - .IsEnabled(Item->Data.Enabled) - .ToolTipText(FText::FromString(Item->Data.ToolTip)) - [ - SNew(STextBlock) - .Text(FText::FromString(Item->Data.EditorDescription.ToString())) - .ToolTipText(FText::FromString(Item->Data.ToolTip)) - ] - ]; - } - else - { - return SNew(STextBlock).Text(LOCTEXT("UnknownColumn", "Unknown Column")); - } - } - - TSharedPtr< FGCFilterTreeItem > Item; - SGameplayCueEditorImpl* GameplayCueEditor; - }; - - if ( InItem.IsValid() ) - { - return SNew(SFilterItemWidget, FilterTreeView.ToSharedRef(), this, InItem); - } - else - { - return - SNew(STableRow< TSharedPtr >, OwnerTable) - [ - SNew(STextBlock) - .Text(LOCTEXT("UnknownFilterType", "Unknown Filter Type")) - ]; - } - } + TSharedRef OnGenerateWidgetForFilterListView(TSharedPtr< FGCFilterTreeItem > InItem, const TSharedRef& OwnerTable); void OnPropertyValueChanged() { @@ -1083,6 +847,247 @@ static FReply RecompileGameplayCueEditor_OnClicked() return FReply::Handled(); } +BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION + +/** Builds widget for rows in the GameplayCue Editor tab */ +TSharedRef SGameplayCueEditorImpl::OnGenerateWidgetForGameplayCueListView(TSharedPtr< FGCTreeItem > InItem, const TSharedRef& OwnerTable) +{ + class SCueItemWidget : public SMultiColumnTableRow< TSharedPtr< FGCTreeItem > > + { + public: + SLATE_BEGIN_ARGS(SCueItemWidget) {} + SLATE_END_ARGS() + + void Construct(const FArguments& InArgs, const TSharedRef& InOwnerTable, TSharedPtr InListItem, SGameplayCueEditorImpl* InGameplayCueEditor) + { + Item = InListItem; + GameplayCueEditor = InGameplayCueEditor; + SMultiColumnTableRow< TSharedPtr< FGCTreeItem > >::Construct( + FSuperRowType::FArguments() + , InOwnerTable); + } + private: + + virtual TSharedRef GenerateWidgetForColumn(const FName& ColumnName) override + { + if (ColumnName == CueTagColumnName) + { + return + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(SExpanderArrow, SharedThis(this)) + ] + + SHorizontalBox::Slot() + .FillWidth(1) + .VAlign(VAlign_Center) + [ + SNew(STextBlock) + .ColorAndOpacity(Item->GameplayCueTag.IsValid() ? FSlateColor::UseForeground() : FSlateColor::UseSubduedForeground()) + .Text(FText::FromString(Item->Description.IsEmpty() ? Item->GameplayCueTagName.ToString() : FString::Printf(TEXT("%s (%s)"), *Item->Description, *Item->GameplayCueTagName.ToString()))) + ]; + } + else if (ColumnName == CueHandlerColumnName) + { + if (Item->GameplayCueNotifyObj.ToString().IsEmpty() == false) + { + FString ObjName = Item->GameplayCueNotifyObj.ToString(); + + int32 idx; + if (ObjName.FindLastChar(TEXT('.'), idx)) + { + ObjName = ObjName.RightChop(idx + 1); + if (ObjName.FindLastChar(TEXT('_'), idx)) + { + ObjName = ObjName.Left(idx); + } + } + + return + SNew(SBox) + .HAlign(HAlign_Left) + [ + SNew(SHyperlink) + .Style(FEditorStyle::Get(), "Common.GotoBlueprintHyperlink") + .Text(FText::FromString(ObjName)) + .OnNavigate(this, &SCueItemWidget::NavigateToHandler) + ]; + } + else if (Item->FunctionPtr.IsValid()) + { + FString ObjName; + UFunction* Func = Item->FunctionPtr.Get(); + UClass* OuterClass = Cast(Func->GetOuter()); + if (OuterClass) + { + ObjName = OuterClass->GetName(); + ObjName.RemoveFromEnd(TEXT("_c")); + } + + return + SNew(SBox) + .HAlign(HAlign_Left) + [ + SNew(SHyperlink) + .Text(FText::FromString(ObjName)) + .OnNavigate(this, &SCueItemWidget::NavigateToHandler) + ]; + } + else + { + return + SNew(SBox) + .HAlign(HAlign_Left) + [ + SNew(SHyperlink) + .Style(FEditorStyle::Get(), "Common.GotoNativeCodeHyperlink") + .Text(LOCTEXT("AddNew", "Add New")) + .OnNavigate(this, &SCueItemWidget::OnAddNewClicked) + ]; + } + } + else + { + return SNew(STextBlock).Text(LOCTEXT("UnknownColumn", "Unknown Column")); + } + } + + /** Create new GameplayCueNotify: brings up dialog to pick class, then creates it via the content browser. */ + void OnAddNewClicked() + { + { + // Add the tag if its not already. Note that the FGameplayTag may be valid as an implicit tag, and calling this + // will create it as an explicit tag, which is what we want. If the tag already exists + + TGuardValue SupressUpdate(SGameplayCueEditorImpl::bSuppressCueViewUpdate, true); + + IGameplayTagsEditorModule::Get().AddNewGameplayTagToINI(Item->GameplayCueTagName.ToString()); + } + + UClass* ParentClass = nullptr; + + // If this is an override, use the parent GC notify class as the base class + if (Item->ParentGameplayCueNotifyObj.IsValid()) + { + UObject* Obj = Item->ParentGameplayCueNotifyObj.ResolveObject(); + if (!Obj) + { + Obj = Item->ParentGameplayCueNotifyObj.TryLoad(); + } + + ParentClass = Cast(Obj); + if (ParentClass == nullptr) + { + ABILITY_LOG(Warning, TEXT("Unable to resolve object for parent GC notify: %s"), *Item->ParentGameplayCueNotifyObj.ToString()); + } + } + + GameplayCueEditor->OnSelectionChanged(Item, ESelectInfo::Direct); + + SGameplayCueEditor::CreateNewGameplayCueNotifyDialogue(Item->GameplayCueTagName.ToString(), ParentClass); + } + + void NavigateToHandler() + { + if (Item->GameplayCueNotifyObj.IsValid()) + { + SGameplayCueEditor::OpenEditorForNotify(Item->GameplayCueNotifyObj.ToString()); + + } + else if (Item->FunctionPtr.IsValid()) + { + SGameplayCueEditor::OpenEditorForNotify(Item->FunctionPtr->GetOuter()->GetPathName()); + } + } + + TSharedPtr< FGCTreeItem > Item; + SGameplayCueEditorImpl* GameplayCueEditor; + }; + + if (InItem.IsValid()) + { + return SNew(SCueItemWidget, GameplayCueTreeView.ToSharedRef(), InItem, this); + } + else + { + return + SNew(STableRow< TSharedPtr >, OwnerTable) + [ + SNew(STextBlock) + .Text(LOCTEXT("UnknownItemType", "Unknown Item Type")) + ]; + } +} + +TSharedRef SGameplayCueEditorImpl::OnGenerateWidgetForFilterListView(TSharedPtr< FGCFilterTreeItem > InItem, const TSharedRef& OwnerTable) +{ + class SFilterItemWidget : public SMultiColumnTableRow< TSharedPtr< FGCFilterTreeItem > > + { + public: + SLATE_BEGIN_ARGS(SFilterItemWidget) {} + SLATE_END_ARGS() + + void Construct(const FArguments& InArgs, const TSharedRef& InOwnerTable, SGameplayCueEditorImpl* InGameplayCueEditor, TSharedPtr InListItem) + { + Item = InListItem; + GameplayCueEditor = InGameplayCueEditor; + SMultiColumnTableRow< TSharedPtr< FGCFilterTreeItem > >::Construct(FSuperRowType::FArguments(), InOwnerTable); + } + private: + + virtual TSharedRef GenerateWidgetForColumn(const FName& ColumnName) override + { + if (ColumnName == CueTagColumnName) + { + return + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(SExpanderArrow, SharedThis(this)) + ] + + SHorizontalBox::Slot() + .FillWidth(1) + .VAlign(VAlign_Center) + [ + SNew(SCheckBox) + .OnCheckStateChanged(GameplayCueEditor, &SGameplayCueEditorImpl::OnFilterStateChanged, Item) + .IsChecked(GameplayCueEditor, &SGameplayCueEditorImpl::IsFilterChecked, Item) + .IsEnabled(Item->Data.Enabled) + .ToolTipText(FText::FromString(Item->Data.ToolTip)) + [ + SNew(STextBlock) + .Text(FText::FromString(Item->Data.EditorDescription.ToString())) + .ToolTipText(FText::FromString(Item->Data.ToolTip)) + ] + ]; + } + else + { + return SNew(STextBlock).Text(LOCTEXT("UnknownColumn", "Unknown Column")); + } + } + + TSharedPtr< FGCFilterTreeItem > Item; + SGameplayCueEditorImpl* GameplayCueEditor; + }; + + if (InItem.IsValid()) + { + return SNew(SFilterItemWidget, FilterTreeView.ToSharedRef(), this, InItem); + } + else + { + return + SNew(STableRow< TSharedPtr >, OwnerTable) + [ + SNew(STextBlock) + .Text(LOCTEXT("UnknownFilterType", "Unknown Filter Type")) + ]; + } +} + void SGameplayCueEditorImpl::Construct(const FArguments& InArgs) { UGameplayCueManager* CueManager = UAbilitySystemGlobals::Get().GetGameplayCueManager(); diff --git a/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilitiesEditor/Public/GameplayEffectCreationMenu.h b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilitiesEditor/Public/GameplayEffectCreationMenu.h new file mode 100644 index 000000000000..f659f8d5e9da --- /dev/null +++ b/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilitiesEditor/Public/GameplayEffectCreationMenu.h @@ -0,0 +1,47 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. +#pragma once + +#include "Templates/SubclassOf.h" +#include "GameplayEffect.h" +#include "GameplayEffectCreationMenu.generated.h" + +class UGameplayEffect; + +USTRUCT() +struct FGameplayEffectCreationData +{ + GENERATED_BODY() + + /** Where to show this in the menu. Use "|" for sub categories. E.g, "Status|Hard|Stun|Root". */ + UPROPERTY(EditAnywhere, Category="Gameplay Effect") + FString MenuPath; + + /** The default BaseName of the new asset. E.g "Damage" -> GE_Damage or GE_HeroName_AbilityName_Damage */ + UPROPERTY(EditAnywhere, Category="Gameplay Effect") + FString BaseName; + + UPROPERTY(EditAnywhere, Category="Gameplay Effect") + TSubclassOf ParentGameplayEffect; +}; + +/** Container to hold EventKeywords for PIE testing */ +UCLASS(config=Game,defaultconfig, notplaceable) +class GAMEPLAYABILITIESEDITOR_API UGameplayEffectCreationMenu : public UObject +{ + GENERATED_BODY() + +public: + + UGameplayEffectCreationMenu(); + + // Set this in your project to programatically define default GE names + static TFunction< FString(FString BaseName, FString Path) > GetDefaultAssetNameFunc; + + + + void AddMenuExtensions() const; + + UPROPERTY(config, EditAnywhere, Category="Gameplay Effect") + TArray Definitions; +}; + diff --git a/Engine/Plugins/Runtime/GearVR/Source/GearVR/Private/GearVR.cpp b/Engine/Plugins/Runtime/GearVR/Source/GearVR/Private/GearVR.cpp index 39783ae358f4..620574ec8b4e 100644 --- a/Engine/Plugins/Runtime/GearVR/Source/GearVR/Private/GearVR.cpp +++ b/Engine/Plugins/Runtime/GearVR/Source/GearVR/Private/GearVR.cpp @@ -271,6 +271,8 @@ bool FGearVR::OnStartGameFrame( FWorldContext& WorldContext ) rv = GetEyePoses(*CurrentFrame, CurrentFrame->CurEyeRenderPose, CurrentFrame->CurSensorState); + UpdateHMDWornState(); + #if !UE_BUILD_SHIPPING { // used for debugging, do not remove FQuat CurHmdOrientation; @@ -288,6 +290,30 @@ FGameFrame* FGearVR::GetFrame() const return static_cast(GetCurrentFrame()); } +EHMDWornState::Type FGearVR::GetHMDWornState() +{ + return HMDWornState; +} + +void FGearVR::UpdateHMDWornState() +{ + bool isHMTMounted = (vrapi_GetSystemStatusInt(&JavaGT, VRAPI_SYS_STATUS_MOUNTED) != VRAPI_FALSE); + EHMDWornState::Type NewHMDWornState = isHMTMounted ? EHMDWornState::Worn : EHMDWornState::NotWorn; + + if (NewHMDWornState != HMDWornState) + { + HMDWornState = NewHMDWornState; + if (HMDWornState == EHMDWornState::Worn) + { + FCoreDelegates::VRHeadsetPutOnHead.Broadcast(); + } + else if (HMDWornState == EHMDWornState::NotWorn) + { + FCoreDelegates::VRHeadsetRemovedFromHead.Broadcast(); + } + } +} + EHMDDeviceType::Type FGearVR::GetHMDDeviceType() const { return EHMDDeviceType::DT_GearVR; @@ -439,7 +465,7 @@ void FGearVR::FOVCommandHandler(const TArray& Args, UWorld* World, FOut const bool bEnableDevOverrides = (DevOverridesTCVar && DevOverridesTCVar->GetValueOnAnyThread() != 0); const TCHAR* FieldName = bIsVertical ? TEXT("VFOV") : TEXT("HFOV"); FSettings* CurrentSettings = GetSettings(); - float& Field = bIsVertical ? CurrentSettings->VFOVInRadians : CurrentSettings->VFOVInRadians; + float& Field = bIsVertical ? CurrentSettings->VFOVInRadians : CurrentSettings->HFOVInRadians; if (Args.Num() > 0) { @@ -1078,7 +1104,7 @@ void FGearVR::UpdateStereoRenderingParams() { FSettings* CurrentSettings = GetSettings(); - if ((!CurrentSettings->IsStereoEnabled() && !CurrentSettings->Flags.bHeadTrackingEnforced)) + if (!CurrentSettings->IsStereoEnabled() && !CurrentSettings->Flags.bHeadTrackingEnforced) { return; } diff --git a/Engine/Plugins/Runtime/GearVR/Source/GearVR/Private/GearVR.h b/Engine/Plugins/Runtime/GearVR/Source/GearVR/Private/GearVR.h index 812a8b778970..6919b80470eb 100644 --- a/Engine/Plugins/Runtime/GearVR/Source/GearVR/Private/GearVR.h +++ b/Engine/Plugins/Runtime/GearVR/Source/GearVR/Private/GearVR.h @@ -595,6 +595,7 @@ public: virtual bool OnStartGameFrame( FWorldContext& WorldContext ) override; virtual bool IsHMDConnected() override; + virtual EHMDWornState::Type GetHMDWornState() override; virtual EHMDDeviceType::Type GetHMDDeviceType() const override; virtual bool GetHMDMonitorInfo(MonitorInfo&) override; @@ -793,6 +794,10 @@ private: // data TSharedPtr Splash; + /** Is the HMD being worn by the user (according to the api) */ + EHMDWornState::Type HMDWornState; + void UpdateHMDWornState(); + union OCFlagsUnion { struct diff --git a/Engine/Plugins/Runtime/GearVR/Source/GearVR/Private/GearVRRender.cpp b/Engine/Plugins/Runtime/GearVR/Source/GearVR/Private/GearVRRender.cpp index b970a0172e33..c898e342384f 100644 --- a/Engine/Plugins/Runtime/GearVR/Source/GearVR/Private/GearVRRender.cpp +++ b/Engine/Plugins/Runtime/GearVR/Source/GearVR/Private/GearVRRender.cpp @@ -1328,7 +1328,7 @@ void FCustomPresent::CopyTexture_RenderThread(FRHICommandListImmediate& RHICmdLi SetRenderTarget(RHICmdList, DstTexture, FTextureRHIRef()); //RHICmdList.Clear(true, FLinearColor(1.0f, 0.0f, 0.0f, 1.0f), false, 0.0f, false, 0, FIntRect()); // @DBG - DrawClearQuad(RHICmdList, GMaxRHIFeatureLevel, FLinearColor(0.0f, 0.0f, 0.0f, 0.0f)); + DrawClearQuad(RHICmdList, FLinearColor(0.0f, 0.0f, 0.0f, 0.0f)); RHICmdList.SetViewport(DstRect.Min.X, DstRect.Min.Y, 0, DstRect.Max.X, DstRect.Max.Y, 1.0f); FGraphicsPipelineStateInitializer GraphicsPSOInit; diff --git a/Engine/Plugins/Runtime/GearVR/Source/GearVR/Private/GearVRSplash.cpp b/Engine/Plugins/Runtime/GearVR/Source/GearVR/Private/GearVRSplash.cpp index 0c5c544066a3..7eb58ecf9232 100644 --- a/Engine/Plugins/Runtime/GearVR/Source/GearVR/Private/GearVRSplash.cpp +++ b/Engine/Plugins/Runtime/GearVR/Source/GearVR/Private/GearVRSplash.cpp @@ -133,7 +133,7 @@ void FGearVRSplash::Tick(float DeltaTime) { FRenderSplashInfo& Splash = RenderSplashScreens[i]; // Let update only each 2nd frame if rotation is needed - if ((!Splash.Desc.DeltaRotation.Equals(FQuat::Identity) && DeltaSecondsHighFreq > 2.f * DisplayRefreshRate)) + if (!Splash.Desc.DeltaRotation.Equals(FQuat::Identity) && DeltaSecondsHighFreq > 2.f * DisplayRefreshRate) { if (pCurrentFrame) { diff --git a/Engine/Plugins/Runtime/GearVR/Source/GearVRController/Private/GearVRController.h b/Engine/Plugins/Runtime/GearVR/Source/GearVRController/Private/GearVRController.h index 80a169fd3807..fb6c8fef55bc 100644 --- a/Engine/Plugins/Runtime/GearVR/Source/GearVRController/Private/GearVRController.h +++ b/Engine/Plugins/Runtime/GearVR/Source/GearVRController/Private/GearVRController.h @@ -6,9 +6,9 @@ #include "IMotionController.h" #include "HeadMountedDisplay.h" #include "../../GearVR/Private/GearVR.h" -#include "VrApi_Input.h" #if GEARVR_SUPPORTED_PLATFORMS +#include "VrApi_Input.h" /** * Unreal Engine support for Oculus motion controller devices diff --git a/Engine/Plugins/Runtime/GearVR/Source/GearVRController/Private/GearVRControllerComponent.cpp b/Engine/Plugins/Runtime/GearVR/Source/GearVRController/Private/GearVRControllerComponent.cpp index c828e082130a..7368df6646af 100644 --- a/Engine/Plugins/Runtime/GearVR/Source/GearVRController/Private/GearVRControllerComponent.cpp +++ b/Engine/Plugins/Runtime/GearVR/Source/GearVRController/Private/GearVRControllerComponent.cpp @@ -5,6 +5,7 @@ #include "Components/StaticMeshComponent.h" #include "Engine/StaticMesh.h" #include "MotionControllerComponent.h" +#include "ModuleManager.h" UGearVRControllerComponent::UGearVRControllerComponent() : ControllerMesh(nullptr) @@ -14,8 +15,14 @@ UGearVRControllerComponent::UGearVRControllerComponent() PrimaryComponentTick.bCanEverTick = true; bAutoActivate = true; - - ControllerMesh = Cast(StaticLoadObject(UStaticMesh::StaticClass(), NULL, TEXT("/GearVR/Meshes/GearVRController"))); + // GearVR plugin is enabled by default, so it is built into the executable for content projects. + // If you disable the plugin the mesh content will be missing, and when the default object is + // constructed you get a fatal load error. + // This check avoids that error. + if (FModuleManager::Get().IsModuleLoaded("GearVR")) + { + ControllerMesh = Cast(StaticLoadObject(UStaticMesh::StaticClass(), NULL, TEXT("/GearVR/Meshes/GearVRController"))); + } } UMotionControllerComponent* UGearVRControllerComponent::GetMotionController() const diff --git a/Engine/Plugins/Runtime/GoogleCloudMessaging/GoogleCloudMessaging.uplugin b/Engine/Plugins/Runtime/GoogleCloudMessaging/GoogleCloudMessaging.uplugin index 1a8d6024ecbe..aaee394acee9 100644 --- a/Engine/Plugins/Runtime/GoogleCloudMessaging/GoogleCloudMessaging.uplugin +++ b/Engine/Plugins/Runtime/GoogleCloudMessaging/GoogleCloudMessaging.uplugin @@ -8,7 +8,7 @@ "CreatedBy" : "Epic Games, Inc.", "CreatedByURL" : "http://epicgames.com", "EnabledByDefault" : true, - "Installed" : false, + "Installed" : false, "Modules" : [ { diff --git a/Engine/Plugins/Runtime/GoogleCloudMessaging/Source/GoogleCloudMessaging/GoogleCloudMessaging_UPL.xml b/Engine/Plugins/Runtime/GoogleCloudMessaging/Source/GoogleCloudMessaging/GoogleCloudMessaging_UPL.xml index 6c964798a519..c8b8ebc4fb0c 100644 --- a/Engine/Plugins/Runtime/GoogleCloudMessaging/Source/GoogleCloudMessaging/GoogleCloudMessaging_UPL.xml +++ b/Engine/Plugins/Runtime/GoogleCloudMessaging/Source/GoogleCloudMessaging/GoogleCloudMessaging_UPL.xml @@ -1,176 +1,188 @@ - - - - - - - - - - - - - - - com.google.android.gms,play-services-gcm,9.2.0 - - - - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - - - + + + + + com.google.android.gms,play-services-gcm,9.8.0 + + + + - - - - - + + + + + + + - - + + + + + + + + + + + + + + + - - - + + + + + - - - + + - - - + + + - - + + + - - - - - - + + + - + + + + + + + + + + - - - - - - - - - - + + + + + + + + + - - - - - - - - - // Methods that notify the native code about Google Cloud Messaging interactions - public native void nativeGCMRegisteredForRemoteNotifications(String token); - public native void nativeGCMFailedToRegisterForRemoteNotifications(String errorMessage); - public native void nativeGCMReceivedRemoteNotification(String message); - - - - - - + + + + + + + // Methods that notify the native code about Google Cloud Messaging interactions + public native void nativeGCMRegisteredForRemoteNotifications(String token); + public native void nativeGCMFailedToRegisterForRemoteNotifications(String errorMessage); + public native void nativeGCMReceivedRemoteNotification(String message); + + public void AndroidThunkJava_RegisterForRemoteNotifications() + { + // start IntentService to register this application with Google Cloud Messaging + Intent intent = new Intent(_activity.getApplicationContext(), RemoteNotificationsRegistrationIntentService.class); + startService(intent); + } + public void AndroidThunkJava_UnregisterForRemoteNotifications() + { + } + + + + + public void AndroidThunkJava_RegisterForRemoteNotifications() + { + } + public void AndroidThunkJava_UnregisterForRemoteNotifications() + { + } + + + + + + - - - - - - - - - - // start IntentService to register this application with Google Cloud Messaging - Intent intent = new Intent(_activity.getApplicationContext(), RemoteNotificationsRegistrationIntentService.class); - startService(intent); - - - - - + + - - - - diff --git a/Engine/Plugins/Runtime/GoogleCloudMessaging/Source/GoogleCloudMessaging/Private/GoogleCloudMessaging.cpp b/Engine/Plugins/Runtime/GoogleCloudMessaging/Source/GoogleCloudMessaging/Private/GoogleCloudMessaging.cpp index e9c0003b5fe5..1a3aa2d3ba50 100644 --- a/Engine/Plugins/Runtime/GoogleCloudMessaging/Source/GoogleCloudMessaging/Private/GoogleCloudMessaging.cpp +++ b/Engine/Plugins/Runtime/GoogleCloudMessaging/Source/GoogleCloudMessaging/Private/GoogleCloudMessaging.cpp @@ -20,14 +20,8 @@ DEFINE_LOG_CATEGORY( LogGoogleCloudMessaging ); class FEditorGoogleCloudMessaging : public IGoogleCloudMessagingModuleInterface { - virtual void RegisterForRemoteNotifications() override; }; -void FEditorGoogleCloudMessaging::RegisterForRemoteNotifications() -{ - UE_LOG( LogGoogleCloudMessaging, Warning, TEXT("Not implemented in the editor") ); -} - IMPLEMENT_MODULE( FEditorGoogleCloudMessaging, GoogleCloudMessaging ) #endif diff --git a/Engine/Plugins/Runtime/GoogleCloudMessaging/Source/GoogleCloudMessaging/Private/GoogleCloudMessagingAndroid.cpp b/Engine/Plugins/Runtime/GoogleCloudMessaging/Source/GoogleCloudMessaging/Private/GoogleCloudMessagingAndroid.cpp index 9265d3700872..3a076f907e15 100644 --- a/Engine/Plugins/Runtime/GoogleCloudMessaging/Source/GoogleCloudMessaging/Private/GoogleCloudMessagingAndroid.cpp +++ b/Engine/Plugins/Runtime/GoogleCloudMessaging/Source/GoogleCloudMessaging/Private/GoogleCloudMessagingAndroid.cpp @@ -6,6 +6,7 @@ #include "Async/TaskGraphInterfaces.h" #include "Misc/CoreDelegates.h" +#include "Misc/ConfigCacheIni.h" #include "Android/AndroidJNI.h" #include "Android/AndroidApplication.h" @@ -13,21 +14,14 @@ DEFINE_LOG_CATEGORY( LogGoogleCloudMessaging ); -class FAndroigGoogleCloudMessaging : public IGoogleCloudMessagingModuleInterface +class FAndroidGoogleCloudMessaging : public IGoogleCloudMessagingModuleInterface { - virtual void RegisterForRemoteNotifications() override; }; -IMPLEMENT_MODULE( FAndroigGoogleCloudMessaging, GoogleCloudMessaging ) +IMPLEMENT_MODULE(FAndroidGoogleCloudMessaging, GoogleCloudMessaging) -void FAndroigGoogleCloudMessaging::RegisterForRemoteNotifications() -{ - if( JNIEnv* Env = FAndroidApplication::GetJavaEnv() ) - { - jmethodID jRegisterForRemoteNotifications = FJavaWrapper::FindMethod( Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_RegisterForRemoteNotifications", "()V", false ); - FJavaWrapper::CallVoidMethod( Env, FJavaWrapper::GameActivityThis, jRegisterForRemoteNotifications, false ); - } -} +static TArray GCMTokenBytes; +static FString GCMErrorMessage = TEXT(""); // registered for remote notifications JNI_METHOD void Java_com_epicgames_ue4_GameActivity_nativeGCMRegisteredForRemoteNotifications( JNIEnv* jenv, jobject thiz, jstring jGCMToken ) @@ -35,9 +29,9 @@ JNI_METHOD void Java_com_epicgames_ue4_GameActivity_nativeGCMRegisteredForRemote auto GCMTokenLength = jenv->GetStringUTFLength( jGCMToken ); const char* GCMTokenChars = jenv->GetStringUTFChars( jGCMToken, 0 ); - TArray GCMTokenBytes; - GCMTokenBytes.AddUninitialized( GCMTokenLength ); - FMemory::Memcpy( GCMTokenBytes.GetData(), GCMTokenChars, GCMTokenLength * sizeof( uint8 ) ); + TArray TokenBytes; + TokenBytes.AddUninitialized( GCMTokenLength ); + FMemory::Memcpy( TokenBytes.GetData(), GCMTokenChars, GCMTokenLength * sizeof( uint8 ) ); FString GCMToken; GCMToken = FString( UTF8_TO_TCHAR( GCMTokenChars ) ); @@ -47,6 +41,7 @@ JNI_METHOD void Java_com_epicgames_ue4_GameActivity_nativeGCMRegisteredForRemote FSimpleDelegateGraphTask::CreateAndDispatchWhenReady( FSimpleDelegateGraphTask::FDelegate::CreateLambda( [=]() { UE_LOG(LogGoogleCloudMessaging, Display, TEXT("GCM Registration Token: %s"), *GCMToken); + GCMTokenBytes = TokenBytes; FCoreDelegates::ApplicationRegisteredForRemoteNotificationsDelegate.Broadcast( GCMTokenBytes ); }), TStatId(), nullptr, ENamedThreads::GameThread ); } @@ -54,14 +49,15 @@ JNI_METHOD void Java_com_epicgames_ue4_GameActivity_nativeGCMRegisteredForRemote // failed to register for remote notifications JNI_METHOD void Java_com_epicgames_ue4_GameActivity_nativeGCMFailedToRegisterForRemoteNotifications( JNIEnv* jenv, jobject thiz, jstring jErrorMessage ) { - FString GCMErrorMessage; + FString ErrorMessage; const char* GCMErrorMessageChars = jenv->GetStringUTFChars( jErrorMessage, 0 ); GCMErrorMessage = FString( UTF8_TO_TCHAR( GCMErrorMessageChars ) ); jenv->ReleaseStringUTFChars( jErrorMessage, GCMErrorMessageChars ); FSimpleDelegateGraphTask::CreateAndDispatchWhenReady( FSimpleDelegateGraphTask::FDelegate::CreateLambda( [=]() { - UE_LOG(LogGoogleCloudMessaging, Display, TEXT("GCM Registration Error: %s"), *GCMErrorMessage); + UE_LOG(LogGoogleCloudMessaging, Display, TEXT("GCM Registration Error: %s"), *ErrorMessage); + GCMErrorMessage = ErrorMessage; FCoreDelegates::ApplicationFailedToRegisterForRemoteNotificationsDelegate.Broadcast( GCMErrorMessage ); }), TStatId(), nullptr, ENamedThreads::GameThread ); } @@ -90,7 +86,7 @@ JNI_METHOD void Java_com_epicgames_ue4_GameActivity_nativeGCMReceivedRemoteNotif FSimpleDelegateGraphTask::CreateAndDispatchWhenReady( FSimpleDelegateGraphTask::FDelegate::CreateLambda( [=]() { UE_LOG(LogGoogleCloudMessaging, Display, TEXT("GCM AppState = %d, Message : %s"), AppState, *Message); - FCoreDelegates::ApplicationReceivedRemoteNotificationDelegate.Broadcast( Message /* , AppState */ ); + FCoreDelegates::ApplicationReceivedRemoteNotificationDelegate.Broadcast( Message, AppState ); }), TStatId(), nullptr, ENamedThreads::GameThread ); } diff --git a/Engine/Plugins/Runtime/GoogleCloudMessaging/Source/GoogleCloudMessaging/Public/GoogleCloudMessaging.h b/Engine/Plugins/Runtime/GoogleCloudMessaging/Source/GoogleCloudMessaging/Public/GoogleCloudMessaging.h index 00b2f8b29faa..4ff14fad72e8 100644 --- a/Engine/Plugins/Runtime/GoogleCloudMessaging/Source/GoogleCloudMessaging/Public/GoogleCloudMessaging.h +++ b/Engine/Plugins/Runtime/GoogleCloudMessaging/Source/GoogleCloudMessaging/Public/GoogleCloudMessaging.h @@ -16,8 +16,6 @@ class IGoogleCloudMessagingModuleInterface : public IModuleInterface public: - virtual void RegisterForRemoteNotifications() = 0; - /** * Singleton-like access to this module's interface. This is just for convenience! * Beware of calling this during the shutdown phase, though. Your module might have been unloaded already. diff --git a/Engine/Plugins/Runtime/GoogleCloudMessaging/Source/Java/RemoteNotificationsListener.java b/Engine/Plugins/Runtime/GoogleCloudMessaging/Source/Java/RemoteNotificationsListener.java index e3fd8cedf370..1aebdcef4bc8 100644 --- a/Engine/Plugins/Runtime/GoogleCloudMessaging/Source/Java/RemoteNotificationsListener.java +++ b/Engine/Plugins/Runtime/GoogleCloudMessaging/Source/Java/RemoteNotificationsListener.java @@ -4,12 +4,51 @@ package com.epicgames.ue4; import android.os.Bundle; import com.google.android.gms.gcm.GcmListenerService; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.support.v4.app.NotificationCompat; + public class RemoteNotificationsListener extends GcmListenerService { - @Override - public void onMessageReceived( String from, Bundle data ) - { - String message = data.getString( "message" ); - GameActivity._activity.nativeGCMReceivedRemoteNotification( message ); - } + @Override + public void onMessageReceived( String from, Bundle data ) + { + String message = data.getString( "message" ); + + /* + Intent notificationIntent = new Intent(this, GameActivity.class); + notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); + + int notificationIconID = context.getResources().getIdentifier("ic_notification", "drawable", context.getPackageName()); + if (notificationIconID == 0) + { + notificationIconID = context.getResources().getIdentifier("icon", "drawable", context.getPackageName()); + } + PendingIntent pendingNotificationIntent = PendingIntent.getActivity(this, notificationIconID, notificationIntent, 0); + + NotificationCompat.Builder builder = new NotificationCompat.Builder(this) + .setSmallIcon(notificationIconID) + .setContentIntent(pendingNotificationIntent) + .setWhen(System.currentTimeMillis()) + .setContentTitle("GCM Message") + .setStyle(new NotificationCompat.BigTextStyle().bigText(message)) + .setContentText(message); + if (android.os.Build.VERSION.SDK_INT >= 21) + { + builder.setColor(0xff0e1e43); + } + Notification notification = builder.build(); + notification.flags |= Notification.FLAG_AUTO_CANCEL; + notification.defaults |= Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE; + + NotificationManager notificationManager = (NotificationManager)this.getSystemService(Context.NOTIFICATION_SERVICE); + notificationManager.notify((int)System.currentTimeMillis(), notification); + */ + + GameActivity._activity.nativeGCMReceivedRemoteNotification( message ); + } } diff --git a/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/GoogleVRController.uplugin b/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/GoogleVRController.uplugin index a47f487a8fb0..00bff56500ae 100644 --- a/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/GoogleVRController.uplugin +++ b/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/GoogleVRController.uplugin @@ -1,7 +1,7 @@ { "FileVersion": 3, "Version": 7, - "VersionName": "1.3 (GVR NDK v1.30.0)", + "VersionName": "1.3 (GVR NDK v1.40.0)", "FriendlyName": "Google VR Motion Controller", "Description": "Support for the Google VR motion controller", "Category": "Input Devices", @@ -22,5 +22,12 @@ "LoadingPhase": "PostConfigInit", "WhitelistPlatforms": [ "Android", "Win32", "Win64", "IOS" ] } - ] + ], + "Plugins": [ + { + "Name": "GoogleVRHMD", + "Enabled": true + } + ] + } diff --git a/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Classes/GoogleVRControllerTooltipComponent.h b/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Classes/GoogleVRControllerTooltipComponent.h index e8c77fff0dce..ccd2a57c357d 100644 --- a/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Classes/GoogleVRControllerTooltipComponent.h +++ b/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Classes/GoogleVRControllerTooltipComponent.h @@ -22,8 +22,6 @@ class UMotionControllerComponent; -DEFINE_LOG_CATEGORY_STATIC(LogGoogleVRControllerTooltip, Log, All); - UENUM(BlueprintType) enum class EGoogleVRControllerTooltipLocation : uint8 { diff --git a/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Classes/GoogleVRGazeReticleComponent.h b/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Classes/GoogleVRGazeReticleComponent.h index f7a8fbab22bf..0b9fdc59055e 100644 --- a/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Classes/GoogleVRGazeReticleComponent.h +++ b/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Classes/GoogleVRGazeReticleComponent.h @@ -25,8 +25,6 @@ class UGoogleVRPointerInputComponent; class UCameraComponent; -DEFINE_LOG_CATEGORY_STATIC(LogGoogleVRGazeReticle, Log, All); - /** * GoogleVRGazeReticleComponent is a customizable reticle used to interact with * actors and widgets by looking at them. Intended for use with Google Cardboard appliations. diff --git a/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Classes/GoogleVRMotionControllerComponent.h b/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Classes/GoogleVRMotionControllerComponent.h index 941630b91a76..8ca0c594ad91 100644 --- a/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Classes/GoogleVRMotionControllerComponent.h +++ b/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Classes/GoogleVRMotionControllerComponent.h @@ -25,8 +25,6 @@ class UGoogleVRPointerInputComponent; class UMaterialInterface; class UMaterialParameterCollection; -DEFINE_LOG_CATEGORY_STATIC(LogGoogleVRMotionController, Log, All); - /** * GoogleVRMotionControllerComponent is a customizable Daydream Motion Controller. * diff --git a/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Classes/GoogleVRPointerInputComponent.h b/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Classes/GoogleVRPointerInputComponent.h index 09b7864dcbd1..83371b2cf874 100644 --- a/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Classes/GoogleVRPointerInputComponent.h +++ b/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Classes/GoogleVRPointerInputComponent.h @@ -22,8 +22,6 @@ class UGoogleVRWidgetInteractionComponent; -DEFINE_LOG_CATEGORY_STATIC(LogGoogleVRPointerInput, Log, All); - DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FGoogleVRInputDelegate, FHitResult, HitResult); DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FGoogleVRInputExitActorDelegate, AActor*, PreviousActor, FHitResult, HitResult); DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FGoogleVRInputExitComponentDelegate, UPrimitiveComponent*, PreviousComponent, FHitResult, HitResult); diff --git a/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Private/GoogleVRController.cpp b/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Private/GoogleVRController.cpp index 5b023bd04986..ee8651d4f03f 100644 --- a/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Private/GoogleVRController.cpp +++ b/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Private/GoogleVRController.cpp @@ -34,6 +34,8 @@ extern gvr_context* GVRAPI; extern gvr_user_prefs* GVRUserPrefs; #endif // GOOGLEVRCONTROLLER_SUPPORTED_ANDROID_PLATFORMS +DEFINE_LOG_CATEGORY_STATIC(LogGoogleVRController, Log, All); + #if GOOGLEVRCONTROLLER_SUPPORTED_EMULATOR_PLATFORMS #define CONTROLLER_EVENT_FORWARDED_PORT 7003 //Change this port number if it is already taken. #define ADB_FORWARD_RETRY_TIME 5.0 //5 seconds diff --git a/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Private/GoogleVRController.h b/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Private/GoogleVRController.h index a6c2d942e1ee..bf4ccde64d75 100644 --- a/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Private/GoogleVRController.h +++ b/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Private/GoogleVRController.h @@ -28,8 +28,6 @@ using namespace gvr; #endif -DEFINE_LOG_CATEGORY_STATIC(LogGoogleVRController, Log, All); - /** Total number of controllers in a set */ #define CONTROLLERS_PER_PLAYER 2 diff --git a/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Private/GoogleVRControllerTooltipComponent.cpp b/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Private/GoogleVRControllerTooltipComponent.cpp index 16fa018d819b..fc6c2be1fddf 100644 --- a/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Private/GoogleVRControllerTooltipComponent.cpp +++ b/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Private/GoogleVRControllerTooltipComponent.cpp @@ -21,6 +21,8 @@ #include "Engine/World.h" #include "Materials/MaterialInterface.h" +DEFINE_LOG_CATEGORY_STATIC(LogGoogleVRControllerTooltip, Log, All); + UGoogleVRControllerTooltipComponent::UGoogleVRControllerTooltipComponent(const FObjectInitializer& ObjectInitializer) : TooltipLocation(EGoogleVRControllerTooltipLocation::TouchPadOutside) , TextRenderComponent(nullptr) diff --git a/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Private/GoogleVRGazeReticleComponent.cpp b/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Private/GoogleVRGazeReticleComponent.cpp index c897d0d35ab6..9d15ca4b94b7 100644 --- a/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Private/GoogleVRGazeReticleComponent.cpp +++ b/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Private/GoogleVRGazeReticleComponent.cpp @@ -22,6 +22,8 @@ #include "Engine/StaticMesh.h" #include "Engine/World.h" +DEFINE_LOG_CATEGORY_STATIC(LogGoogleVRGazeReticle, Log, All); + UGoogleVRGazeReticleComponent::UGoogleVRGazeReticleComponent() : Mesh(nullptr) , Material(nullptr) diff --git a/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Private/GoogleVRMotionControllerComponent.cpp b/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Private/GoogleVRMotionControllerComponent.cpp index 054d6a4b0dc1..903df8d1ad3a 100644 --- a/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Private/GoogleVRMotionControllerComponent.cpp +++ b/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Private/GoogleVRMotionControllerComponent.cpp @@ -28,6 +28,8 @@ #include "Engine/World.h" #include "Engine/StaticMesh.h" +DEFINE_LOG_CATEGORY_STATIC(LogGoogleVRMotionController, Log, All); + const FVector UGoogleVRMotionControllerComponent::TOUCHPAD_POINT_DIMENSIONS = FVector(0.01f, 0.01f, 0.0004f); UGoogleVRMotionControllerComponent::UGoogleVRMotionControllerComponent() diff --git a/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Private/GoogleVRPointerInputComponent.cpp b/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Private/GoogleVRPointerInputComponent.cpp index ef30c375af6f..761e47f5936b 100644 --- a/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Private/GoogleVRPointerInputComponent.cpp +++ b/Engine/Plugins/Runtime/GoogleVR/GoogleVRController/Source/GoogleVRController/Private/GoogleVRPointerInputComponent.cpp @@ -22,6 +22,7 @@ #include "Components/PrimitiveComponent.h" #include "Engine/World.h" +DEFINE_LOG_CATEGORY_STATIC(LogGoogleVRPointerInput, Log, All); UGoogleVRPointerInputComponent::UGoogleVRPointerInputComponent(const FObjectInitializer& ObjectInitializer) : PointerInputMode(EGoogleVRPointerInputMode::Camera) @@ -169,7 +170,7 @@ void UGoogleVRPointerInputComponent::TickComponent(float DeltaTime, ELevelTick T { OnPointerExitComponentEvent.Broadcast(PreviousHitComponent, LatestHitResult); - if (PreviousHitComponent != nullptr && PreviousHitComponent->Implements()) + if (PreviousHitComponent->Implements()) { IGoogleVRComponentPointerResponder::Execute_OnPointerExit(PreviousHitComponent, PreviousHitComponent, LatestHitResult, this); } @@ -180,7 +181,7 @@ void UGoogleVRPointerInputComponent::TickComponent(float DeltaTime, ELevelTick T { OnPointerExitActorEvent.Broadcast(PreviousHitActor, LatestHitResult); - if (PreviousHitActor != nullptr && PreviousHitActor->Implements()) + if (PreviousHitActor->Implements()) { IGoogleVRActorPointerResponder::Execute_OnPointerExit(PreviousHitActor, PreviousHitActor, LatestHitResult, this); } @@ -193,7 +194,7 @@ void UGoogleVRPointerInputComponent::TickComponent(float DeltaTime, ELevelTick T { OnPointerEnterActorEvent.Broadcast(LatestHitResult); - if (HitActor != nullptr && HitActor->Implements()) + if (HitActor->Implements()) { IGoogleVRActorPointerResponder::Execute_OnPointerEnter(HitActor, LatestHitResult, this); } @@ -206,7 +207,7 @@ void UGoogleVRPointerInputComponent::TickComponent(float DeltaTime, ELevelTick T { OnPointerEnterComponentEvent.Broadcast(LatestHitResult); - if (HitComponent != nullptr && HitComponent->Implements()) + if (HitComponent->Implements()) { IGoogleVRComponentPointerResponder::Execute_OnPointerEnter(HitComponent, LatestHitResult, this); } @@ -223,7 +224,7 @@ void UGoogleVRPointerInputComponent::TickComponent(float DeltaTime, ELevelTick T { OnPointerHoverActorEvent.Broadcast(LatestHitResult); - if (HitActor != nullptr && HitActor->Implements()) + if (HitActor->Implements()) { IGoogleVRActorPointerResponder::Execute_OnPointerHover(HitActor, LatestHitResult, this); } @@ -236,7 +237,7 @@ void UGoogleVRPointerInputComponent::TickComponent(float DeltaTime, ELevelTick T { OnPointerHoverComponentEvent.Broadcast(LatestHitResult); - if (HitComponent != nullptr && HitComponent->Implements()) + if (HitComponent->Implements()) { IGoogleVRComponentPointerResponder::Execute_OnPointerHover(HitComponent, LatestHitResult, this); } @@ -349,7 +350,7 @@ void UGoogleVRPointerInputComponent::ClickButtonReleased() if (PendingClickActor != nullptr) { - if (PendingClickActor != nullptr && PendingClickActor->Implements()) + if (PendingClickActor->Implements()) { IGoogleVRActorPointerResponder::Execute_OnPointerReleased(PendingClickActor, LatestHitResult, this); } @@ -367,7 +368,7 @@ void UGoogleVRPointerInputComponent::ClickButtonReleased() if (PendingClickComponent != nullptr) { - if (PendingClickComponent != nullptr && PendingClickComponent->Implements()) + if (PendingClickComponent->Implements()) { IGoogleVRComponentPointerResponder::Execute_OnPointerReleased(PendingClickComponent, LatestHitResult, this); } diff --git a/Engine/Plugins/Runtime/GoogleVR/GoogleVRHMD/GoogleVRHMD.uplugin b/Engine/Plugins/Runtime/GoogleVR/GoogleVRHMD/GoogleVRHMD.uplugin index aed1380b1219..44d1cb031c0e 100644 --- a/Engine/Plugins/Runtime/GoogleVR/GoogleVRHMD/GoogleVRHMD.uplugin +++ b/Engine/Plugins/Runtime/GoogleVR/GoogleVRHMD/GoogleVRHMD.uplugin @@ -1,7 +1,7 @@ { "FileVersion": 3, "Version": 7, - "VersionName": "1.3 (GVR NDK v1.30.0)", + "VersionName": "1.3 (GVR NDK v1.40.0)", "FriendlyName": "Google VR", "Description": "Support for Google VR on mobile devices", "Category": "Virtual Reality", diff --git a/Engine/Plugins/Runtime/GoogleVR/GoogleVRHMD/Source/GoogleVRHMD/GoogleVRHMD_APL.xml b/Engine/Plugins/Runtime/GoogleVR/GoogleVRHMD/Source/GoogleVRHMD/GoogleVRHMD_APL.xml index d438a03a77d8..bfb6771f3cfd 100644 --- a/Engine/Plugins/Runtime/GoogleVR/GoogleVRHMD/Source/GoogleVRHMD/GoogleVRHMD_APL.xml +++ b/Engine/Plugins/Runtime/GoogleVR/GoogleVRHMD/Source/GoogleVRHMD/GoogleVRHMD_APL.xml @@ -17,7 +17,7 @@ - + diff --git a/Engine/Plugins/Runtime/GoogleVR/GoogleVRHMD/Source/GoogleVRHMD/Private/GoogleVRHMD.h b/Engine/Plugins/Runtime/GoogleVR/GoogleVRHMD/Source/GoogleVRHMD/Private/GoogleVRHMD.h index 3a59c1bb3aea..4c4f43e30c3b 100644 --- a/Engine/Plugins/Runtime/GoogleVR/GoogleVRHMD/Source/GoogleVRHMD/Private/GoogleVRHMD.h +++ b/Engine/Plugins/Runtime/GoogleVR/GoogleVRHMD/Source/GoogleVRHMD/Private/GoogleVRHMD.h @@ -29,8 +29,6 @@ #include "GoogleVRSplash.h" #include "Containers/Queue.h" -DEFINE_LOG_CATEGORY_STATIC(LogHMD, Log, All); - #define LOG_VIEWER_DATA_FOR_GENERATION 0 #if GOOGLEVRHMD_SUPPORTED_PLATFORMS diff --git a/Engine/Plugins/Runtime/GoogleVR/GoogleVRHMD/Source/GoogleVRHMD/Private/GoogleVRSplash.cpp b/Engine/Plugins/Runtime/GoogleVR/GoogleVRHMD/Source/GoogleVRHMD/Private/GoogleVRSplash.cpp index 867ce147ca49..8236e7cfa1ad 100644 --- a/Engine/Plugins/Runtime/GoogleVR/GoogleVRHMD/Source/GoogleVRHMD/Private/GoogleVRSplash.cpp +++ b/Engine/Plugins/Runtime/GoogleVR/GoogleVRHMD/Source/GoogleVRHMD/Private/GoogleVRSplash.cpp @@ -210,7 +210,7 @@ void FGoogleVRSplash::RenderStereoSplashScreen(FRHICommandListImmediate& RHICmdL const auto FeatureLevel = GMaxRHIFeatureLevel; // Should really be SetRT and Clear SetRenderTarget(RHICmdList, DstTexture, FTextureRHIRef()); - DrawClearQuad(RHICmdList, FeatureLevel, FLinearColor(0.0f, 0.0f, 0.0f, 0.0f)); + DrawClearQuad(RHICmdList, FLinearColor(0.0f, 0.0f, 0.0f, 0.0f)); // If the texture is not avaliable, we just clear the DstTexture with black. if (SplashTexture && SplashTexture->IsValidLowLevel()) @@ -304,7 +304,7 @@ void FGoogleVRSplash::SubmitBlackFrame() GVRCustomPresent->BeginRendering(GVRHMD->CachedHeadPose); SetRenderTarget(RHICmdList, DstTexture, FTextureRHIRef()); - DrawClearQuad(RHICmdList, GMaxRHIFeatureLevel, FLinearColor(0.0f, 0.0f, 0.0f, 0.0f)); + DrawClearQuad(RHICmdList, FLinearColor(0.0f, 0.0f, 0.0f, 0.0f)); GVRCustomPresent->FinishRendering(); } diff --git a/Engine/Plugins/Runtime/GoogleVR/GoogleVRTransition2D/Source/GoogleVRTransition2D/Private/GoogleVRTransition2D.cpp b/Engine/Plugins/Runtime/GoogleVR/GoogleVRTransition2D/Source/GoogleVRTransition2D/Private/GoogleVRTransition2D.cpp index 433486e3647e..43373ebc0bc2 100644 --- a/Engine/Plugins/Runtime/GoogleVR/GoogleVRTransition2D/Source/GoogleVRTransition2D/Private/GoogleVRTransition2D.cpp +++ b/Engine/Plugins/Runtime/GoogleVR/GoogleVRTransition2D/Source/GoogleVRTransition2D/Private/GoogleVRTransition2D.cpp @@ -18,6 +18,8 @@ #define LOCTEXT_NAMESPACE "FGoogleVRTransition2DModule" +DEFINE_LOG_CATEGORY(LogGoogleVRTransition2D); + void FGoogleVRTransition2DModule::StartupModule() { UGoogleVRTransition2DBPLibrary::Initialize(); diff --git a/Engine/Plugins/Runtime/GoogleVR/GoogleVRTransition2D/Source/GoogleVRTransition2D/Public/GoogleVRTransition2D.h b/Engine/Plugins/Runtime/GoogleVR/GoogleVRTransition2D/Source/GoogleVRTransition2D/Public/GoogleVRTransition2D.h index a1aceb6875f5..fbf9bcb75b04 100644 --- a/Engine/Plugins/Runtime/GoogleVR/GoogleVRTransition2D/Source/GoogleVRTransition2D/Public/GoogleVRTransition2D.h +++ b/Engine/Plugins/Runtime/GoogleVR/GoogleVRTransition2D/Source/GoogleVRTransition2D/Public/GoogleVRTransition2D.h @@ -17,7 +17,7 @@ #include "ModuleManager.h" -DEFINE_LOG_CATEGORY_STATIC(LogGoogleVRTransition2D, Log, All); +DECLARE_LOG_CATEGORY_EXTERN(LogGoogleVRTransition2D, Log, All); class FGoogleVRTransition2DModule : public IModuleInterface { diff --git a/Engine/Plugins/Online/HTTPChunkInstaller/Config/Localization/HTTPChunkInstaller.ini b/Engine/Plugins/Runtime/HTTPChunkInstaller/Config/Localization/HTTPChunkInstaller.ini similarity index 100% rename from Engine/Plugins/Online/HTTPChunkInstaller/Config/Localization/HTTPChunkInstaller.ini rename to Engine/Plugins/Runtime/HTTPChunkInstaller/Config/Localization/HTTPChunkInstaller.ini diff --git a/Engine/Plugins/Online/HTTPChunkInstaller/HTTPChunkInstaller.uplugin b/Engine/Plugins/Runtime/HTTPChunkInstaller/HTTPChunkInstaller.uplugin similarity index 94% rename from Engine/Plugins/Online/HTTPChunkInstaller/HTTPChunkInstaller.uplugin rename to Engine/Plugins/Runtime/HTTPChunkInstaller/HTTPChunkInstaller.uplugin index 14161dad9690..162a7ba6c517 100644 --- a/Engine/Plugins/Online/HTTPChunkInstaller/HTTPChunkInstaller.uplugin +++ b/Engine/Plugins/Runtime/HTTPChunkInstaller/HTTPChunkInstaller.uplugin @@ -8,7 +8,7 @@ "Category" : "Online Platform", "CreatedBy" : "Epic Games, Inc.", "CreatedByURL" : "http://epicgames.com", - "EnabledByDefault" : true, + "EnabledByDefault" : false, "Modules": [ { diff --git a/Engine/Plugins/Runtime/HTTPChunkInstaller/Source/HTTPChunkInstaller.Build.cs b/Engine/Plugins/Runtime/HTTPChunkInstaller/Source/HTTPChunkInstaller.Build.cs new file mode 100644 index 000000000000..745ea3fe3886 --- /dev/null +++ b/Engine/Plugins/Runtime/HTTPChunkInstaller/Source/HTTPChunkInstaller.Build.cs @@ -0,0 +1,26 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +using UnrealBuildTool; + +public class HTTPChunkInstaller : ModuleRules +{ + public HTTPChunkInstaller(ReadOnlyTargetRules Target) + : base(Target) + { + PrivateDependencyModuleNames.AddRange( + new string[] { + "BuildPatchServices", + "Core", + "Engine", + "Http", + "Json", + "PakFile", + } + ); + + // if (Target.Platform != UnrealTargetPlatform.Win64 && Target.Platform != UnrealTargetPlatform.Win32 && Target.Platform != UnrealTargetPlatform.IOS) + { + PrecompileForTargets = PrecompileTargetsType.None; + } + } +} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/HTTPChunkInstaller/Source/Private/HTTPChunkInstaller.cpp b/Engine/Plugins/Runtime/HTTPChunkInstaller/Source/Private/HTTPChunkInstaller.cpp new file mode 100644 index 000000000000..2c7a80afd86c --- /dev/null +++ b/Engine/Plugins/Runtime/HTTPChunkInstaller/Source/Private/HTTPChunkInstaller.cpp @@ -0,0 +1,1735 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#include "HTTPChunkInstaller.h" +#include "HTTPChunkInstallerLog.h" +#include "ChunkInstall.h" +#include "UniquePtr.h" +#include "LocalTitleFile.h" +#include "SecureHash.h" +#include "IHttpRequest.h" +#include "IHttpResponse.h" +#include "HttpModule.h" +#include "JsonObject.h" +#include "JsonReader.h" +#include "JsonSerializer.h" +#include "ThreadSafeCounter64.h" +#include "ConfigCacheIni.h" +#include "FileHelper.h" +#include "RunnableThread.h" +#include "CommandLine.h" +#include "ModuleManager.h" + +#define LOCTEXT_NAMESPACE "HTTPChunkInstaller" + +// helper to grab the installer service +static IBuildPatchServicesModule* GetBuildPatchServices() +{ + static IBuildPatchServicesModule* BuildPatchServices = nullptr; + if (BuildPatchServices == nullptr) + { + BuildPatchServices = &FModuleManager::LoadModuleChecked(TEXT("BuildPatchServices")); + } + return BuildPatchServices; +} + +const FName NAME_SHA1(TEXT("SHA1")); +const FName NAME_SHA256(TEXT("SHA256")); + +class FTitleFileHttpAsyncLoadAndVerify : + public FNonAbandonableTask +{ +public: + /** File data loaded for the async read */ + TArray FileData; + /** Amount of data read from the file to be owned/referenced by the game thread */ + FThreadSafeCounter64* BytesRead; + /** The original name of the file being read */ + const FString OriginalFileName; + /** The name of the file being read off of disk */ + const FString FileName; + /** The hash value the backend said it should have */ + const FString ExpectedHash; + /** The hash type SHA1 or SHA256 right now */ + const FName HashType; + /** Whether the hashes matched */ + bool bHashesMatched; + + /** Initializes the variables needed to load and verify the data */ + FTitleFileHttpAsyncLoadAndVerify(const FString& InOriginalFileName, const FString& InFileName, const FString& InExpectedHash, const FName InHashType, FThreadSafeCounter64* InBytesReadCounter) : + BytesRead(InBytesReadCounter), + OriginalFileName(InOriginalFileName), + FileName(InFileName), + ExpectedHash(InExpectedHash), + HashType(InHashType), + bHashesMatched(false) + { + + } + + /** + * Loads and hashes the file data. Empties the data if the hash check fails + */ + void DoWork() + { + // load file from disk + bool bLoadedFile = false; + + FArchive* Reader = IFileManager::Get().CreateFileReader(*FileName, FILEREAD_Silent); + if (Reader) + { + int64 SizeToRead = Reader->TotalSize(); + FileData.Reset(SizeToRead); + FileData.AddUninitialized(SizeToRead); + + uint8* FileDataPtr = FileData.GetData(); + + static const int64 ChunkSize = 100 * 1024; + + int64 TotalBytesRead = 0; + while (SizeToRead > 0) + { + int64 Val = FMath::Min(SizeToRead, ChunkSize); + Reader->Serialize(FileDataPtr + TotalBytesRead, Val); + BytesRead->Add(Val); + TotalBytesRead += Val; + SizeToRead -= Val; + } + + ensure(SizeToRead == 0 && Reader->TotalSize() == TotalBytesRead); + bLoadedFile = Reader->Close(); + delete Reader; + } + + // verify hash of file if it exists + if (bLoadedFile) + { + UE_LOG(LogHTTPChunkInstaller, Verbose, TEXT("ReadFile request. Local file read from cache =%s"), *FileName); + if (HashType == NAME_SHA1) + { + bHashesMatched = IsValidSHA1(ExpectedHash, FileData); + } + else if (HashType == NAME_SHA256) + { + bHashesMatched = IsValidSHA256(ExpectedHash, FileData); + } + } + else + { + UE_LOG(LogHTTPChunkInstaller, Verbose, TEXT("Local file (%s) not cached locally"), *FileName); + } + if (!bHashesMatched) + { + // Empty local that was loaded + FileData.Empty(); + } + } + + FORCEINLINE TStatId GetStatId() const + { + RETURN_QUICK_DECLARE_CYCLE_STAT(FTitleFileHttpAsyncLoadAndVerify, STATGROUP_ThreadPoolAsyncTasks); + } + +private: + /** Validates that a buffer matches the same signature as was specified */ + bool IsValidSHA1(const FString& Hash, const TArray& Source) const + { + uint8 LocalHash[20]; + FSHA1::HashBuffer(Source.GetData(), Source.Num(), LocalHash); + // concatenate 20 bye SHA1 hash to string + FString LocalHashStr; + for (int Idx = 0; Idx < 20; Idx++) + { + LocalHashStr += FString::Printf(TEXT("%02x"), LocalHash[Idx]); + } + return Hash == LocalHashStr; + } + bool IsValidSHA256(const FString& Hash, const TArray& Source) const + { + FSHA256Signature Signature; + if (FPlatformMisc::GetSHA256Signature(Source.GetData(), Source.Num(), Signature)) + { + return Signature.ToString() == Hash; + } + return false; + } +}; + +// helper class for an HTTP Online Title File +class FOnlineTitleFileHttp : public ICloudTitleFile +{ +public: + /** + * Constructor + * + * @param InSubsystem mcp subsystem being used + */ + FOnlineTitleFileHttp(const FString& InBaseUrl) + : EnumerateFilesUrl(TEXT("")) + , BaseUrl(InBaseUrl) + { + GConfig->GetString(TEXT("HTTPOnlineTitleFile"), TEXT("BaseUrl"), BaseUrl, GEngineIni); + GConfig->GetString(TEXT("HTTPOnlineTitleFile"), TEXT("EnumerateFilesUrl"), EnumerateFilesUrl, GEngineIni); + bCacheFiles = true; + bPlatformSupportsSHA256 = false; + } + + /** + * Destructor + */ + virtual ~FOnlineTitleFileHttp() + {} + + /** + * Copies the file data into the specified buffer for the specified file + * + * @param FileName the name of the file to read + * @param FileContents the out buffer to copy the data into + * + * @return true if the data was copied, false otherwise + */ + virtual bool GetFileContents(const FString& FileName, TArray& FileContents) override + { + const TArray* FilesPtr = &Files; + if (FilesPtr != NULL) + { + for (TArray::TConstIterator It(*FilesPtr); It; ++It) + { + if (It->FileName == FileName) + { + FileContents = It->Data; + return true; + } + } + } + return false; + } + + /** + * Empties the set of downloaded files if possible (no async tasks outstanding) + * + * @return true if they could be deleted, false if they could not + */ + virtual bool ClearFiles() override + { + for (int Idx = 0; Idx < Files.Num(); Idx++) + { + if (Files[Idx].AsyncState == ECloudAsyncTaskState::InProgress) + { + UE_LOG(LogHTTPChunkInstaller, Warning, TEXT("Cant clear files. Pending file op for %s"), *Files[Idx].FileName); + return false; + } + } + // remove all cached file entries + Files.Empty(); + return true; + } + + /** + * Empties the cached data for this file if it is not being downloaded currently + * + * @param FileName the name of the file to remove from the cache + * + * @return true if it could be deleted, false if it could not + */ + virtual bool ClearFile(const FString& FileName) override + { + for (int Idx = 0; Idx < Files.Num(); Idx++) + { + if (Files[Idx].FileName == FileName) + { + if (Files[Idx].AsyncState == ECloudAsyncTaskState::InProgress) + { + UE_LOG(LogHTTPChunkInstaller, Warning, TEXT("Cant clear file. Pending file op for %s"), *Files[Idx].FileName); + return false; + } + else + { + Files.RemoveAt(Idx); + return true; + } + } + } + return false; + } + + /** + * Delete cached files on disk + * + * @param bSkipEnumerated if true then only non-enumerated files are deleted + */ + virtual void DeleteCachedFiles(bool bSkipEnumerated) override + { + TArray CachedFiles; + IFileManager::Get().FindFiles(CachedFiles, *(GetLocalCachePath() / TEXT("*")), true, false); + + for (auto CachedFile : CachedFiles) + { + bool bSkip = bSkipEnumerated && GetCloudFileHeader(CachedFile); + if (!bSkip) + { + IFileManager::Get().Delete(*GetLocalFilePath(CachedFile), false, true); + } + } + } + + /** + * Requests a list of available files from the network store + * + * @return true if the request has started, false if not + */ + virtual bool EnumerateFiles(const FCloudPagedQuery& Page = FCloudPagedQuery()) override + { + FString ErrorStr; + bool bStarted = false; + + // Make sure an enumeration request is not currently pending + if (EnumerateFilesRequests.Num() > 0) + { + ErrorStr = TEXT("Request already in progress."); + } + else + { + // Create the Http request and add to pending request list + TSharedRef HttpRequest = FHttpModule::Get().CreateRequest(); + EnumerateFilesRequests.Add(HttpRequest, Page); + + HttpRequest->OnProcessRequestComplete().BindRaw(this, &FOnlineTitleFileHttp::EnumerateFiles_HttpRequestComplete); + HttpRequest->SetURL(GetBaseUrl()+EnumerateFilesUrl+TEXT("/Master.manifest")); + HttpRequest->SetVerb(TEXT("GET")); + bStarted = HttpRequest->ProcessRequest(); + } + if (!bStarted) + { + UE_LOG(LogHTTPChunkInstaller, Warning, TEXT("EnumerateFiles request failed. %s"), *ErrorStr); + TriggerOnEnumerateFilesCompleteDelegates(false); + } + return bStarted; + } + + /** + * Returns the list of files that was returned by the network store + * + * @param Files out array of file metadata + * + */ + virtual void GetFileList(TArray& OutFiles) override + { + TArray* FilesPtr = &FileHeaders; + if (FilesPtr != NULL) + { + OutFiles = *FilesPtr; + } + else + { + OutFiles.Empty(); + } + } + + /** + * Starts an asynchronous read of the specified file from the network platform's file store + * + * @param FileToRead the name of the file to read + * + * @return true if the calls starts successfully, false otherwise + */ + virtual bool ReadFile(const FString& FileName) override + { + bool bStarted = false; + + FCloudHeader* CloudFileHeader = GetCloudFileHeader(FileName); + + // Make sure valid filename was specified3 + if (FileName.IsEmpty() || FileName.Contains(TEXT(" "))) + { + UE_LOG(LogHTTPChunkInstaller, Warning, TEXT("Invalid filename filename=%s"), *FileName); + TriggerOnReadFileCompleteDelegates(false, FileName); + return false; + } + + // Make sure a file request for this file is not currently pending + for (const auto& Pair : FileRequests) + { + if (Pair.Value == FPendingFileRequest(FileName)) + { + UE_LOG(LogHTTPChunkInstaller, Verbose, TEXT("ReadFileRemote is already in progress for (%s)"), *FileName); + return true; + } + } + + FCloudEntry* CloudFile = GetCloudFile(FileName, true); + if (CloudFile->AsyncState == ECloudAsyncTaskState::InProgress) + { + UE_LOG(LogHTTPChunkInstaller, Verbose, TEXT("ReadFile is already in progress for (%s)"), *FileName); + return true; + } + + if (bCacheFiles) + { + // Try to read this from the cache if possible + bStarted = StartReadFileLocal(FileName); + } + if (!bStarted) + { + // Failed locally (means not on disk) so fetch from server + bStarted = ReadFileRemote(FileName); + } + + if (!bStarted || CloudFile->AsyncState == ECloudAsyncTaskState::Failed) + { + UE_LOG(LogHTTPChunkInstaller, Warning, TEXT("ReadFile request failed for file (%s)"), *FileName); + TriggerOnReadFileCompleteDelegates(false, FileName); + } + else if (CloudFile->AsyncState == ECloudAsyncTaskState::Done) + { + TriggerOnReadFileCompleteDelegates(true, FileName); + } + return bStarted; + } + + /** Used to check that async tasks have completed and can be completed */ + virtual void Tick(float DeltaTime) + { + TArray ItemsToRemove; + ItemsToRemove.Reserve(AsyncLocalReads.Num()); + + // Check for any completed tasks + for (int32 TaskIdx = 0; TaskIdx < AsyncLocalReads.Num(); TaskIdx++) + { + FTitleAsyncReadData& Task = AsyncLocalReads[TaskIdx]; + if (Task.AsyncTask->IsDone()) + { + FinishReadFileLocal(Task.AsyncTask->GetTask()); + ItemsToRemove.Add(TaskIdx); + UE_LOG(LogHTTPChunkInstaller, VeryVerbose, TEXT("Title Task Complete: %s"), *Task.Filename); + } + else + { + const int64 NewValue = Task.BytesRead.GetValue(); + if (NewValue != Task.LastBytesRead) + { + Task.LastBytesRead = NewValue; + TriggerOnReadFileProgressDelegates(Task.Filename, NewValue); + } + } + } + + // Clean up any tasks that were completed + for (int32 ItemIdx = ItemsToRemove.Num() - 1; ItemIdx >= 0; ItemIdx--) + { + const int32 TaskIdx = ItemsToRemove[ItemIdx]; + FTitleAsyncReadData& TaskToDelete = AsyncLocalReads[TaskIdx]; + UE_LOG(LogHTTPChunkInstaller, VeryVerbose, TEXT("Title Task Removal: %s read: %d"), *TaskToDelete.Filename, TaskToDelete.BytesRead.GetValue()); + delete TaskToDelete.AsyncTask; + AsyncLocalReads.RemoveAtSwap(TaskIdx); + } + } + + void Shutdown() + { + + } + +private: + + /** Reads the file from the local cache if it can. This is async */ + bool StartReadFileLocal(const FString& FileName) + { + UE_LOG(LogHTTPChunkInstaller, VeryVerbose, TEXT("StartReadFile %s"), *FileName); + bool bStarted = false; + FCloudHeader* CloudFileHeader = GetCloudFileHeader(FileName); + if (CloudFileHeader != nullptr) + { + // Mark file entry as in progress + FCloudEntry* CloudFile = GetCloudFile(FileName, true); + CloudFile->AsyncState = ECloudAsyncTaskState::InProgress; + if (CloudFileHeader->Hash.IsEmpty()) + { + UE_LOG(LogHTTPChunkInstaller, Warning, TEXT("Requested file (%s) is missing a hash, so can't be verified"), *FileName); + } + FTitleAsyncReadData* NewItem = new FTitleAsyncReadData(); + NewItem->Filename = FileName; + + // Create the async task and start it + NewItem->AsyncTask = new FAsyncTask(FileName, + GetLocalFilePath(FileName), CloudFileHeader->Hash, CloudFileHeader->HashType, &NewItem->BytesRead); + + AsyncLocalReads.Add(NewItem); + NewItem->AsyncTask->StartBackgroundTask(); + bStarted = true; + } + return bStarted; + } + /** Completes the async operation of the local file read */ + void FinishReadFileLocal(FTitleFileHttpAsyncLoadAndVerify& AsyncLoad) + { + UE_LOG(LogHTTPChunkInstaller, VeryVerbose, TEXT("FinishReadFileLocal %s"), *AsyncLoad.OriginalFileName); + FCloudHeader* CloudFileHeader = GetCloudFileHeader(AsyncLoad.OriginalFileName); + FCloudEntry* CloudFile = GetCloudFile(AsyncLoad.OriginalFileName, true); + if (CloudFileHeader != nullptr && CloudFile != nullptr) + { + // if hash matches then just use the local file + if (AsyncLoad.bHashesMatched) + { + UE_LOG(LogHTTPChunkInstaller, Verbose, TEXT("Local file hash matches cloud header. No need to download for filename=%s"), *AsyncLoad.OriginalFileName); + CloudFile->Data = AsyncLoad.FileData; + CloudFile->AsyncState = ECloudAsyncTaskState::Done; + TriggerOnReadFileProgressDelegates(AsyncLoad.OriginalFileName, static_cast(AsyncLoad.BytesRead->GetValue())); + TriggerOnReadFileCompleteDelegates(true, AsyncLoad.OriginalFileName); + } + else + { + // Request it from server + ReadFileRemote(AsyncLoad.OriginalFileName); + } + } + else + { + UE_LOG(LogHTTPChunkInstaller, Warning, TEXT("ReadFile request failed for file (%s)"), *AsyncLoad.OriginalFileName); + TriggerOnReadFileCompleteDelegates(false, AsyncLoad.OriginalFileName); + } + } + /** Requests the file from MCP. This is async */ + bool ReadFileRemote(const FString& FileName) + { + UE_LOG(LogHTTPChunkInstaller, VeryVerbose, TEXT("ReadFileRemote %s"), *FileName); + + bool bStarted = false; + FCloudHeader* CloudFileHeader = GetCloudFileHeader(FileName); + if (CloudFileHeader != nullptr) + { + FCloudEntry* CloudFile = GetCloudFile(FileName, true); + CloudFile->Data.Empty(); + CloudFile->AsyncState = ECloudAsyncTaskState::InProgress; + + // Create the Http request and add to pending request list + TSharedRef HttpRequest = FHttpModule::Get().CreateRequest(); + FileRequests.Add(HttpRequest, FPendingFileRequest(FileName)); + FileProgressRequestsMap.Add(HttpRequest, FPendingFileRequest(FileName)); + + HttpRequest->OnProcessRequestComplete().BindRaw(this, &FOnlineTitleFileHttp::ReadFile_HttpRequestComplete); + HttpRequest->OnRequestProgress().BindRaw(this, &FOnlineTitleFileHttp::ReadFile_HttpRequestProgress); + FString RequestUrl; + // Grab the file from the specified URL if that was set, otherwise use the old method that hits the game service + if (CloudFileHeader != nullptr && !CloudFileHeader->URL.IsEmpty()) + { + RequestUrl = CloudFileHeader->URL; + } + else + { + RequestUrl = GetBaseUrl() + FileName; + } + HttpRequest->SetURL(RequestUrl); + HttpRequest->SetVerb(TEXT("GET")); + bStarted = HttpRequest->ProcessRequest(); + + if (!bStarted) + { + UE_LOG(LogHTTPChunkInstaller, Error, TEXT("Unable to start the HTTP request to fetch file (%s)"), *FileName); + } + } + else + { + UE_LOG(LogHTTPChunkInstaller, Error, TEXT("No cloud file header entry for filename=%s."), *FileName); + } + return bStarted; + } + + /** + * Delegate called when a Http request completes for enumerating list of file headers + */ + void EnumerateFiles_HttpRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded) + { + const FCloudPagedQuery& PendingOp = EnumerateFilesRequests.FindRef(HttpRequest); + EnumerateFilesRequests.Remove(HttpRequest); + + bool bResult = false; + FString ResponseStr, ErrorStr; + + if (HttpResponse.IsValid() && EHttpResponseCodes::IsOk(HttpResponse->GetResponseCode())) + { + ResponseStr = HttpResponse->GetContentAsString(); + UE_LOG(LogHTTPChunkInstaller, Verbose, TEXT("EnumerateFiles request complete. url=%s code=%d response=%s"), + *HttpRequest->GetURL(), HttpResponse->GetResponseCode(), *ResponseStr); + + if (PendingOp.Start == 0) + { + FileHeaders.Empty(); + } + + // parse the html for the file list + if (ResponseStr.StartsWith(TEXT(" Lines; + ResponseStr.ParseIntoArrayLines(Lines); + for (int Index = 0; Index < Lines.Num(); ++Index) + { + if (Lines[Index].StartsWith(TEXT("
  • "))) + { + TArray Elements; + Lines[Index].ParseIntoArray(Elements, TEXT(">")); + if (!Elements[2].StartsWith(TEXT("Chunks"))) + { + FString File = Elements[2].Replace(TEXT(" JsonObject; + TSharedRef > JsonReader = TJsonReaderFactory<>::Create(ResponseStr); + + if (FJsonSerializer::Deserialize(JsonReader, JsonObject) && + JsonObject.IsValid()) + { + // Parse the array of file headers + TArray > JsonFileHeaders = JsonObject->GetArrayField(TEXT("files")); + for (TArray >::TConstIterator It(JsonFileHeaders); It; ++It) + { + TSharedPtr JsonFileHeader = (*It)->AsObject(); + if (JsonFileHeader.IsValid()) + { + FCloudHeader FileHeader; + if (JsonFileHeader->HasField(TEXT("hash"))) + { + FileHeader.Hash = JsonFileHeader->GetStringField(TEXT("hash")); + FileHeader.HashType = FileHeader.Hash.IsEmpty() ? NAME_None : NAME_SHA1; + } + // This one takes priority over the old SHA1 hash if present (requires platform support) + if (bPlatformSupportsSHA256 && JsonFileHeader->HasField(TEXT("hash256"))) + { + FString Hash256 = JsonFileHeader->GetStringField(TEXT("hash256")); + if (!Hash256.IsEmpty()) + { + FileHeader.Hash = Hash256; + FileHeader.HashType = FileHeader.Hash.IsEmpty() ? NAME_None : NAME_SHA256; + } + } + if (JsonFileHeader->HasField(TEXT("uniqueFilename"))) + { + FileHeader.DLName = JsonFileHeader->GetStringField(TEXT("uniqueFilename")); + } + if (JsonFileHeader->HasField(TEXT("filename"))) + { + FileHeader.FileName = JsonFileHeader->GetStringField(TEXT("filename")); + } + if (JsonFileHeader->HasField(TEXT("length"))) + { + FileHeader.FileSize = FMath::TruncToInt(JsonFileHeader->GetNumberField(TEXT("length"))); + } + if (JsonFileHeader->HasField(TEXT("URL"))) + { + FileHeader.URL = GetBaseUrl() + EnumerateFilesUrl + TEXT("/") + JsonFileHeader->GetStringField(TEXT("URL")); + } + + if (FileHeader.FileName.IsEmpty()) + { + FileHeader.FileName = FileHeader.DLName; + } + + if (FileHeader.Hash.IsEmpty() || + (FileHeader.DLName.IsEmpty() && FileHeader.URL.IsEmpty()) || + FileHeader.HashType == NAME_None) + { + UE_LOG(LogHTTPChunkInstaller, Warning, TEXT("Invalid file entry hash=%s hashType=%s dlname=%s filename=%s URL=%s"), + *FileHeader.Hash, + *FileHeader.HashType.ToString(), + *FileHeader.DLName, + *FileHeader.FileName, + *FileHeader.URL); + } + else + { + int32 FoundIdx = INDEX_NONE; + for (int32 Idx = 0; Idx < FileHeaders.Num(); Idx++) + { + const FCloudHeader& ExistingFile = FileHeaders[Idx]; + if (ExistingFile.DLName == FileHeader.DLName) + { + FoundIdx = Idx; + break; + } + } + if (FoundIdx != INDEX_NONE) + { + FileHeaders[FoundIdx] = FileHeader; + } + else + { + FileHeaders.Add(FileHeader); + } + } + } + } + } + bResult = true; + } + } + else + { + if (HttpResponse.IsValid()) + { + ErrorStr = FText::Format(LOCTEXT("HttpResponse", "HTTP {0} response from {1}"), + FText::AsNumber(HttpResponse->GetResponseCode()), + FText::FromString(HttpResponse->GetURL())).ToString(); + } + else + { + ErrorStr = FText::Format(LOCTEXT("HttpResponse", "Connection to {0} failed"), FText::FromString(HttpRequest->GetURL())).ToString(); + } + } + + if (!ErrorStr.IsEmpty()) + { + UE_LOG(LogHTTPChunkInstaller, Warning, TEXT("EnumerateFiles request failed. %s"), *ErrorStr); + } + else + { + // Everything went ok, so we can remove any cached files that are not in the current list + DeleteCachedFiles(true); + } + + TriggerOnEnumerateFilesCompleteDelegates(bResult); + } + + /** + * Delegate called when a Http request completes for reading a cloud file + */ + void ReadFile_HttpRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded) + { + bool bResult = false; + FString ResponseStr, ErrorStr; + + // should have a pending Http request + FPendingFileRequest PendingRequest = FileRequests.FindChecked(HttpRequest); + FileRequests.Remove(HttpRequest); + // remove from progress updates + FileProgressRequestsMap.Remove(HttpRequest); + HttpRequest->OnRequestProgress().Unbind(); + + // Cloud file being operated on + FCloudEntry* CloudFile = GetCloudFile(PendingRequest.FileName, true); + CloudFile->AsyncState = ECloudAsyncTaskState::Failed; + CloudFile->Data.Empty(); + + if (HttpResponse.IsValid() && EHttpResponseCodes::IsOk(HttpResponse->GetResponseCode())) + { + UE_LOG(LogHTTPChunkInstaller, Verbose, TEXT("ReadFile request complete. url=%s code=%d"), + *HttpRequest->GetURL(), HttpResponse->GetResponseCode()); + + // update the memory copy of the file with data that was just downloaded + CloudFile->AsyncState = ECloudAsyncTaskState::Done; + CloudFile->Data = HttpResponse->GetContent(); + + if (bCacheFiles) + { + // cache to disk on successful download + SaveCloudFileToDisk(CloudFile->FileName, CloudFile->Data); + } + + bResult = true; + } + else + { + if (HttpResponse.IsValid()) + { + ErrorStr = FText::Format(LOCTEXT("HttpResponse", "HTTP {0} response from {1}"), + FText::AsNumber(HttpResponse->GetResponseCode()), + FText::FromString(HttpResponse->GetURL())).ToString(); + } + else + { + ErrorStr = FText::Format(LOCTEXT("HttpResponse", "Connection to {0} failed"), FText::FromString(HttpRequest->GetURL())).ToString(); + } + } + + if (!ErrorStr.IsEmpty()) + { + UE_LOG(LogHTTPChunkInstaller, Warning, TEXT("EnumerateFiles request failed. %s"), *ErrorStr); + } + TriggerOnReadFileCompleteDelegates(bResult, PendingRequest.FileName); + } + + /** + * Delegate called as a Http request progresses for reading a cloud file + */ + void ReadFile_HttpRequestProgress(FHttpRequestPtr HttpRequest, int32 BytesSent, int32 BytesReceived) + { + FPendingFileRequest PendingRequest = FileProgressRequestsMap.FindChecked(HttpRequest); + // Just forward this to anyone that is listening + TriggerOnReadFileProgressDelegates(PendingRequest.FileName, BytesReceived); + } + + /** + * Find/create cloud file entry + * + * @param FileName cached file entry to find + * @param bCreateIfMissing create the file entry if not found + * + * @return cached cloud file entry + */ + FCloudEntry* GetCloudFile(const FString& FileName, bool bCreateIfMissing) + { + FCloudEntry* CloudFile = NULL; + for (int Idx = 0; Idx < Files.Num(); Idx++) + { + if (Files[Idx].FileName == FileName) + { + CloudFile = &Files[Idx]; + break; + } + } + if (CloudFile == NULL && bCreateIfMissing) + { + CloudFile = new(Files)FCloudEntry(FileName); + } + return CloudFile; + } + + /** + * Find cloud file header entry + * + * @param FileName cached file entry to find + * + * @return cached cloud file header entry + */ + FCloudHeader* GetCloudFileHeader(const FString& FileName) + { + FCloudHeader* CloudFileHeader = NULL; + + for (int Idx = 0; Idx < FileHeaders.Num(); Idx++) + { + if (FileHeaders[Idx].DLName == FileName) + { + CloudFileHeader = &FileHeaders[Idx]; + break; + } + } + + return CloudFileHeader; + } + + /** + * Converts filename into a local file cache path + * + * @param FileName name of file being loaded + * + * @return unreal file path to be used by file manager + */ + FString GetLocalFilePath(const FString& FileName) + { + return GetLocalCachePath() + FileName; + } + + /** + * @return full path to cache directory + */ + FString GetLocalCachePath() + { + return FPaths::GamePersistentDownloadDir() / TEXT("EMS/"); + } + + /** + * Save a file from a given user to disk + * + * @param FileName name of file being saved + * @param Data data to write to disk + */ + void SaveCloudFileToDisk(const FString& Filename, const TArray& Data) + { + // save local disk copy as well + FString LocalFilePath = GetLocalFilePath(Filename); + bool bSavedLocal = FFileHelper::SaveArrayToFile(Data, *LocalFilePath); + if (bSavedLocal) + { + UE_LOG(LogHTTPChunkInstaller, Verbose, TEXT("WriteUserFile request complete. Local file cache updated =%s"), + *LocalFilePath); + } + else + { + UE_LOG(LogHTTPChunkInstaller, Warning, TEXT("WriteUserFile request complete. Local file cache failed to update =%s"), + *LocalFilePath); + } + } + + /** + * Should use the initialization constructor instead + */ + FOnlineTitleFileHttp(); + + /** Config based url for enumerating list of cloud files*/ + FString EnumerateFilesUrl; + /** Config based url for accessing the HTTP server */ + FString BaseUrl; + + FString GetBaseUrl() + { + return TEXT("http://") + BaseUrl + TEXT("/"); + } + + /** List of pending Http requests for enumerating files */ + TMap EnumerateFilesRequests; + + /** Info used to send request for a file */ + struct FPendingFileRequest + { + /** + * Constructor + */ + FPendingFileRequest(const FString& InFileName = FString(TEXT(""))) + : FileName(InFileName) + { + + } + + /** + * Equality op + */ + inline bool operator==(const FPendingFileRequest& Other) const + { + return FileName == Other.FileName; + } + + /** File being operated on by the pending request */ + FString FileName; + }; + /** List of pending Http requests for reading files */ + TMap FileRequests; + TMap FileProgressRequestsMap; + + TArray FileHeaders; + TArray Files; + bool bCacheFiles; + bool bPlatformSupportsSHA256; + + /** Information about local file reads that are in progress */ + struct FTitleAsyncReadData + { + /** Name of the file being loaded */ + FString Filename; + /** Amount of data that has been loaded on the async thread so far */ + FThreadSafeCounter64 BytesRead; + /** Bytes read last time game thread noticed */ + int64 LastBytesRead; + /** Async tasks doing the work */ + FAsyncTask* AsyncTask; + + FTitleAsyncReadData() : + LastBytesRead(0), + AsyncTask(nullptr) + { } + + bool operator==(const FTitleAsyncReadData& Other) const + { + return Filename == Other.Filename && AsyncTask == Other.AsyncTask; + } + }; + /** Holds the outstanding tasks for hitch free loading and hash calculation */ + TIndirectArray AsyncLocalReads; +}; + +// Helper class to find all pak file manifests. +class FChunkSearchVisitor: public IPlatformFile::FDirectoryVisitor +{ +public: + TArray PakManifests; + + FChunkSearchVisitor() + {} + + virtual bool Visit(const TCHAR* FilenameOrDirectory,bool bIsDirectory) + { + if(bIsDirectory == false) + { + FString Filename(FilenameOrDirectory); + if(FPaths::GetBaseFilename(Filename).MatchesWildcard("*.manifest")) + { + PakManifests.AddUnique(Filename); + } + } + return true; + } +}; + + +FHTTPChunkInstall::FHTTPChunkInstall() + : InstallingChunkID(-1) + , InstallerState(ChunkInstallState::Setup) + , InstallSpeed(EChunkInstallSpeed::Fast) + , bFirstRun(true) + , bSystemInitialised(false) +#if !UE_BUILD_SHIPPING + , bDebugNoInstalledRequired(false) +#endif +{ + +} + + +FHTTPChunkInstall::~FHTTPChunkInstall() +{ + if (InstallService.IsValid()) + { + InstallService->CancelInstall(); + InstallService.Reset(); + } +} + +bool FHTTPChunkInstall::Tick(float DeltaSeconds) +{ + if (!bSystemInitialised) + { + InitialiseSystem(); + } + + switch (InstallerState) + { + case ChunkInstallState::Setup: + { + check(OnlineTitleFile.IsValid()); + EnumFilesCompleteHandle = OnlineTitleFile->AddOnEnumerateFilesCompleteDelegate_Handle(FOnEnumerateFilesCompleteDelegate::CreateRaw(this,&FHTTPChunkInstall::OSSEnumerateFilesComplete)); + ReadFileCompleteHandle = OnlineTitleFile->AddOnReadFileCompleteDelegate_Handle(FOnReadFileCompleteDelegate::CreateRaw(this,&FHTTPChunkInstall::OSSReadFileComplete)); + ChunkSetupTask.SetupWork(BPSModule, InstallDir, ContentDir, HoldingDir, MountedPaks); + ChunkSetupTaskThread.Reset(FRunnableThread::Create(&ChunkSetupTask, TEXT("Chunk discovery thread"))); + InstallerState = ChunkInstallState::SetupWait; + } break; + case ChunkInstallState::SetupWait: + { + if (ChunkSetupTask.IsDone()) + { + ChunkSetupTaskThread->WaitForCompletion(); + ChunkSetupTaskThread.Reset(); + for (auto It = ChunkSetupTask.InstalledChunks.CreateConstIterator(); It; ++It) + { + UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Adding Chunk %d to installed manifests"), It.Key()); + InstalledManifests.Add(It.Key(), It.Value()); + } + for (auto It = ChunkSetupTask.HoldingChunks.CreateConstIterator(); It; ++It) + { + UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Adding Chunk %d to holding manifests"), It.Key()); + PrevInstallManifests.Add(It.Key(), It.Value()); + } + MountedPaks.Append(ChunkSetupTask.MountedPaks); + InstallerState = ChunkInstallState::QueryRemoteManifests; + } + } break; + case ChunkInstallState::QueryRemoteManifests: + { + //Now query the title file service for the chunk manifests. This should return the list of expected chunk manifests + check(OnlineTitleFile.IsValid()); + OnlineTitleFile->ClearFiles(); + InstallerState = ChunkInstallState::RequestingTitleFiles; + UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Enumerating manifest files")); + OnlineTitleFile->EnumerateFiles(); + } break; + case ChunkInstallState::SearchTitleFiles: + { + FString CleanName; + TArray FileList; + TitleFilesToRead.Reset(); + RemoteManifests.Reset(); + ExpectedChunks.Empty(); + OnlineTitleFile->GetFileList(FileList); + for (int32 FileIndex = 0, FileCount = FileList.Num(); FileIndex < FileCount; ++FileIndex) + { + if (FileList[FileIndex].FileName.MatchesWildcard(TEXT("*.manifest"))) + { + UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Found manifest %s"), *FileList[FileIndex].FileName); + TitleFilesToRead.Add(FileList[FileIndex]); + } + } + InstallerState = ChunkInstallState::ReadTitleFiles; + } break; + case ChunkInstallState::ReadTitleFiles: + { + if (TitleFilesToRead.Num() > 0 && InstallSpeed != EChunkInstallSpeed::Paused) + { + if (!IsDataInFileCache(TitleFilesToRead[0].Hash)) + { + UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Reading manifest %s from remote source"), *TitleFilesToRead[0].FileName); + InstallerState = ChunkInstallState::WaitingOnRead; + OnlineTitleFile->ReadFile(TitleFilesToRead[0].DLName); + } + else + { + InstallerState = ChunkInstallState::ReadComplete; + } + } + else + { + InstallerState = ChunkInstallState::PostSetup; + } + } break; + case ChunkInstallState::ReadComplete: + { + FileContentBuffer.Reset(); + bool bReadOK = false; + bool bAlreadyLoaded = ManifestsInMemory.Contains(TitleFilesToRead[0].Hash); + if (!IsDataInFileCache(TitleFilesToRead[0].Hash)) + { + bReadOK = OnlineTitleFile->GetFileContents(TitleFilesToRead[0].DLName, FileContentBuffer); + if (bReadOK) + { + AddDataToFileCache(TitleFilesToRead[0].Hash, FileContentBuffer); + } + } + else if (!bAlreadyLoaded) + { + bReadOK = GetDataFromFileCache(TitleFilesToRead[0].Hash, FileContentBuffer); + if (!bReadOK) + { + RemoveDataFromFileCache(TitleFilesToRead[0].Hash); + } + } + if (bReadOK) + { + if (!bAlreadyLoaded) + { + ParseTitleFileManifest(TitleFilesToRead[0].Hash); + } + // Even if the Parse failed remove the file from the list + TitleFilesToRead.RemoveAt(0); + } + if (TitleFilesToRead.Num() == 0) + { + if (bFirstRun) + { + ChunkMountTask.SetupWork(BPSModule, ContentDir, MountedPaks, ExpectedChunks); + ChunkMountTaskThread.Reset(FRunnableThread::Create(&ChunkMountTask, TEXT("Chunk mounting thread"))); + } + InstallerState = ChunkInstallState::PostSetup; + } + else + { + InstallerState = ChunkInstallState::ReadTitleFiles; + } + } break; + case ChunkInstallState::EnterOfflineMode: + { + for (auto It = InstalledManifests.CreateConstIterator(); It; ++It) + { + ExpectedChunks.Add(It.Key()); + } + ChunkMountTask.SetupWork(BPSModule, ContentDir, MountedPaks, ExpectedChunks); + ChunkMountTaskThread.Reset(FRunnableThread::Create(&ChunkMountTask, TEXT("Chunk mounting thread"))); + InstallerState = ChunkInstallState::PostSetup; + } break; + case ChunkInstallState::PostSetup: + { + if (bFirstRun) + { + if (ChunkMountTask.IsDone()) + { + ChunkMountTaskThread->WaitForCompletion(); + ChunkMountTaskThread.Reset(); + MountedPaks.Append(ChunkMountTask.MountedPaks); + UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Completed First Run")); + bFirstRun = false; + if (PriorityQueue.Num() == 0) + { + SetInstallSpeed(EChunkInstallSpeed::Paused); + } + } + } + else + { + InstallerState = ChunkInstallState::Idle; + } + } break; + case ChunkInstallState::Idle: + { + UpdatePendingInstallQueue(); + } break; + case ChunkInstallState::CopyToContent: + { + if (!ChunkCopyInstall.IsDone() || !InstallService->IsComplete()) + { + break; + } + check(InstallingChunkID != -1); + if (InstallService.IsValid()) + { + InstallService.Reset(); + } + ChunkCopyInstallThread.Reset(); + check(RemoteManifests.Find(InstallingChunkID)); + UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Adding Chunk %d to installed manifests"), InstallingChunkID); + InstalledManifests.Add(InstallingChunkID, InstallingChunkManifest); + UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Removing Chunk %d from remote manifests"), InstallingChunkID); + RemoteManifests.Remove(InstallingChunkID, InstallingChunkManifest); + MountedPaks.Append(ChunkCopyInstall.MountedPaks); + if (!RemoteManifests.Contains(InstallingChunkID)) + { + // No more manifests relating to the chunk ID are left to install. + // Inform any listeners that the install has been completed. + FPlatformChunkInstallCompleteMultiDelegate* FoundDelegate = DelegateMap.Find(InstallingChunkID); + if (FoundDelegate) + { + FoundDelegate->Broadcast(InstallingChunkID); + } + } + EndInstall(); + + } break; + case ChunkInstallState::Installing: + case ChunkInstallState::RequestingTitleFiles: + case ChunkInstallState::WaitingOnRead: + default: + break; + } + + if (OnlineTitleFileHttp.IsValid()) + { + static_cast(OnlineTitleFileHttp.Get())->Tick(DeltaSeconds); + } + + return true; +} + +void FHTTPChunkInstall::UpdatePendingInstallQueue() +{ + if (InstallingChunkID != -1 +#if !UE_BUILD_SHIPPING + || bDebugNoInstalledRequired +#endif + ) + { + return; + } + + check(!InstallService.IsValid()); + bool bPatch = false; + while (PriorityQueue.Num() > 0 && InstallerState != ChunkInstallState::Installing) + { + const FChunkPrio& NextChunk = PriorityQueue[0]; + TArray FoundChunkManifests; + RemoteManifests.MultiFind(NextChunk.ChunkID, FoundChunkManifests); + if (FoundChunkManifests.Num() > 0) + { + auto ChunkManifest = FoundChunkManifests[0]; + auto ChunkIDField = ChunkManifest->GetCustomField("ChunkID"); + if (ChunkIDField.IsValid()) + { + BeginChunkInstall(NextChunk.ChunkID, ChunkManifest, FindPreviousInstallManifest(ChunkManifest)); + } + else + { + PriorityQueue.RemoveAt(0); + } + } + else + { + PriorityQueue.RemoveAt(0); + } + } + if (InstallingChunkID == -1) + { + // Install the first available chunk + for (auto It = RemoteManifests.CreateConstIterator(); It; ++It) + { + if (It) + { + IBuildManifestPtr ChunkManifest = It.Value(); + auto ChunkIDField = ChunkManifest->GetCustomField("ChunkID"); + if (ChunkIDField.IsValid()) + { + BeginChunkInstall(ChunkIDField->AsInteger(), ChunkManifest, FindPreviousInstallManifest(ChunkManifest)); + return; + } + } + } + } +} + + +EChunkLocation::Type FHTTPChunkInstall::GetChunkLocation(uint32 ChunkID) +{ +#if !UE_BUILD_SHIPPING + if(bDebugNoInstalledRequired) + { + return EChunkLocation::BestLocation; + } +#endif + + // Safe to assume Chunk0 is ready + if (ChunkID == 0) + { + return EChunkLocation::BestLocation; + } + + if (bFirstRun || !bSystemInitialised) + { + /** Still waiting on setup to finish, report that nothing is installed yet... */ + return EChunkLocation::NotAvailable; + } + TArray FoundManifests; + RemoteManifests.MultiFind(ChunkID, FoundManifests); + if (FoundManifests.Num() > 0) + { + return EChunkLocation::NotAvailable; + } + + InstalledManifests.MultiFind(ChunkID, FoundManifests); + if (FoundManifests.Num() > 0) + { + return EChunkLocation::BestLocation; + } + + return EChunkLocation::DoesNotExist; +} + + +float FHTTPChunkInstall::GetChunkProgress(uint32 ChunkID,EChunkProgressReportingType::Type ReportType) +{ +#if !UE_BUILD_SHIPPING + if (bDebugNoInstalledRequired) + { + return 100.f; + } +#endif + + // Safe to assume Chunk0 is ready + if (ChunkID == 0) + { + return 100.f; + } + + if (bFirstRun || !bSystemInitialised) + { + /** Still waiting on setup to finish, report that nothing is installed yet... */ + return 0.f; + } + TArray FoundManifests; + RemoteManifests.MultiFind(ChunkID, FoundManifests); + if (FoundManifests.Num() > 0) + { + float Progress = 0; + if (InstallingChunkID == ChunkID && InstallService.IsValid()) + { + Progress = InstallService->GetUpdateProgress(); + } + return Progress / FoundManifests.Num(); + } + + InstalledManifests.MultiFind(ChunkID, FoundManifests); + if (FoundManifests.Num() > 0) + { + return 100.f; + } + + return 0.f; +} + +void FHTTPChunkInstall::OSSEnumerateFilesComplete(bool bSuccess) +{ + InstallerState = bSuccess ? ChunkInstallState::SearchTitleFiles : ChunkInstallState::EnterOfflineMode; +} + +void FHTTPChunkInstall::OSSReadFileComplete(bool bSuccess, const FString& Filename) +{ + InstallerState = bSuccess ? ChunkInstallState::ReadComplete : ChunkInstallState::EnterOfflineMode; +} + +void FHTTPChunkInstall::OSSInstallComplete(bool bSuccess, IBuildManifestRef BuildManifest) +{ + if (bSuccess) + { + // Completed OK. Write the manifest. If the chunk doesn't exist, copy to the content dir. + // Otherwise, writing the manifest will prompt a copy on next start of the game + FString ManifestName; + FString ChunkFdrName; + uint32 ChunkID; + bool bIsPatch; + if (!BuildChunkFolderName(BuildManifest, ChunkFdrName, ManifestName, ChunkID, bIsPatch)) + { + //Something bad has happened, bail + EndInstall(); + return; + } + UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Chunk %d install complete, preparing to copy to content directory"), ChunkID); + FString ManifestPath = FPaths::Combine(*InstallDir, *ChunkFdrName, *ManifestName); + FString HoldingManifestPath = FPaths::Combine(*HoldingDir, *ChunkFdrName, *ManifestName); + FString SrcDir = FPaths::Combine(*InstallDir, *ChunkFdrName); + FString DestDir = FPaths::Combine(*ContentDir, *ChunkFdrName); + bool bCopyDir = InstallDir != ContentDir; + TArray FoundManifests; + InstalledManifests.MultiFind(ChunkID, FoundManifests); + for (const auto& It : FoundManifests) + { + auto FoundPatchField = It->GetCustomField("bIsPatch"); + bool bFoundPatch = FoundPatchField.IsValid() ? FoundPatchField->AsString() == TEXT("true") : false; + if (bFoundPatch == bIsPatch) + { + bCopyDir = false; + } + } + ChunkCopyInstall.SetupWork(ManifestPath, HoldingManifestPath, SrcDir, DestDir, BPSModule, BuildManifest, MountedPaks, bCopyDir); + UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Copying Chunk %d to content directory"), ChunkID); + ChunkCopyInstallThread.Reset(FRunnableThread::Create(&ChunkCopyInstall, TEXT("Chunk Install Copy Thread"))); + InstallerState = ChunkInstallState::CopyToContent; + } + else + { + //Something bad has happened, return to the Idle state. We'll re-attempt the install + EndInstall(); + } +} + +void FHTTPChunkInstall::ParseTitleFileManifest(const FString& ManifestFileHash) +{ +#if !UE_BUILD_SHIPPING + if (bDebugNoInstalledRequired) + { + // Forces the installer to think that no remote manifests exist, so nothing needs to be installed. + return; + } +#endif + FString JsonBuffer; + FFileHelper::BufferToString(JsonBuffer, FileContentBuffer.GetData(), FileContentBuffer.Num()); + auto RemoteManifest = BPSModule->MakeManifestFromJSON(JsonBuffer); + if (!RemoteManifest.IsValid()) + { + UE_LOG(LogHTTPChunkInstaller, Warning, TEXT("Manifest was invalid")); + return; + } + auto RemoteChunkIDField = RemoteManifest->GetCustomField("ChunkID"); + if (!RemoteChunkIDField.IsValid()) + { + UE_LOG(LogHTTPChunkInstaller, Warning, TEXT("Manifest ChunkID was invalid or missing")); + return; + } + //Compare to installed manifests and add to the remote if it needs to be installed. + uint32 ChunkID = (uint32)RemoteChunkIDField->AsInteger(); + ExpectedChunks.Add(ChunkID); + TArray FoundManifests; + InstalledManifests.MultiFind(ChunkID, FoundManifests); + uint32 FoundCount = FoundManifests.Num(); + if (FoundCount > 0) + { + auto RemotePatchManifest = RemoteManifest->GetCustomField("bIsPatch"); + auto RemoteVersion = RemoteManifest->GetVersionString(); + bool bRemoteIsPatch = RemotePatchManifest.IsValid() ? RemotePatchManifest->AsString() == TEXT("true") : false; + for (uint32 FoundIndex = 0; FoundIndex < FoundCount; ++FoundIndex) + { + const auto& InstalledManifest = FoundManifests[FoundIndex]; + auto InstalledVersion = InstalledManifest->GetVersionString(); + auto InstallPatchManifest = InstalledManifest->GetCustomField("bIsPatch"); + bool bInstallIsPatch = InstallPatchManifest.IsValid() ? InstallPatchManifest->AsString() == TEXT("true") : false; + if (InstalledVersion != RemoteVersion && bInstallIsPatch == bRemoteIsPatch) + { + UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Adding Chunk %d to remote manifests"), ChunkID); + RemoteManifests.Add(ChunkID, RemoteManifest); + if(!ManifestFileHash.IsEmpty()) + { + ManifestsInMemory.Add(ManifestFileHash); + } + //Remove from the installed map + if (bFirstRun) + { + // Prevent the paks from being mounted by removing the manifest file + FString ChunkFdrName; + FString ManifestName; + bool bIsPatch; + if (BuildChunkFolderName(InstalledManifest.ToSharedRef(), ChunkFdrName, ManifestName, ChunkID, bIsPatch)) + { + FString ManifestPath = FPaths::Combine(*ContentDir, *ChunkFdrName, *ManifestName); + FString HoldingPath = FPaths::Combine(*HoldingDir, *ChunkFdrName, *ManifestName); + IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile(); + PlatformFile.CreateDirectoryTree(*FPaths::Combine(*HoldingDir, *ChunkFdrName)); + PlatformFile.MoveFile(*HoldingPath, *ManifestPath); + } + UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Adding Chunk %d to previous installed manifests"), ChunkID); + PrevInstallManifests.Add(ChunkID, InstalledManifest); + UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Removing Chunk %d from installed manifests"), ChunkID); + InstalledManifests.Remove(ChunkID, InstalledManifest); + } + } + } + } + else + { + UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Adding Chunk %d to remote manifests"), ChunkID); + RemoteManifests.Add(ChunkID, RemoteManifest); + if (!ManifestFileHash.IsEmpty()) + { + ManifestsInMemory.Add(ManifestFileHash); + } + } +} + +bool FHTTPChunkInstall::BuildChunkFolderName(IBuildManifestRef Manifest, FString& ChunkFdrName, FString& ManifestName, uint32& ChunkID, bool& bIsPatch) +{ + auto ChunkIDField = Manifest->GetCustomField("ChunkID"); + auto ChunkPatchField = Manifest->GetCustomField("bIsPatch"); + + if (!ChunkIDField.IsValid()) + { + return false; + } + ChunkID = ChunkIDField->AsInteger(); + bIsPatch = ChunkPatchField.IsValid() ? ChunkPatchField->AsString() == TEXT("true") : false; + ManifestName = FString::Printf(TEXT("chunk_%u"), ChunkID); + if (bIsPatch) + { + ManifestName += TEXT("_patch"); + } + ManifestName += TEXT(".manifest"); + ChunkFdrName = FString::Printf(TEXT("%s%d"), !bIsPatch ? TEXT("base") : TEXT("patch"), ChunkID); + return true; +} + +bool FHTTPChunkInstall::PrioritizeChunk(uint32 ChunkID, EChunkPriority::Type Priority) +{ + int32 FoundIndex; + PriorityQueue.Find(FChunkPrio(ChunkID, Priority), FoundIndex); + if (FoundIndex != INDEX_NONE) + { + PriorityQueue.RemoveAt(FoundIndex); + } + // Low priority is assumed if the chunk ID doesn't exist in the queue + if (Priority != EChunkPriority::Low) + { + PriorityQueue.AddUnique(FChunkPrio(ChunkID, Priority)); + PriorityQueue.Sort(); + } + return true; +} + +FDelegateHandle FHTTPChunkInstall::SetChunkInstallDelgate(uint32 ChunkID, FPlatformChunkInstallCompleteDelegate Delegate) +{ + FPlatformChunkInstallCompleteMultiDelegate* FoundDelegate = DelegateMap.Find(ChunkID); + if (FoundDelegate) + { + return FoundDelegate->Add(Delegate); + } + else + { + FPlatformChunkInstallCompleteMultiDelegate MC; + auto RetVal = MC.Add(Delegate); + DelegateMap.Add(ChunkID, MC); + return RetVal; + } + return FDelegateHandle(); +} + +void FHTTPChunkInstall::RemoveChunkInstallDelgate(uint32 ChunkID, FDelegateHandle Delegate) +{ + FPlatformChunkInstallCompleteMultiDelegate* FoundDelegate = DelegateMap.Find(ChunkID); + if (!FoundDelegate) + { + return; + } + FoundDelegate->Remove(Delegate); +} + +void FHTTPChunkInstall::BeginChunkInstall(uint32 ChunkID,IBuildManifestPtr ChunkManifest, IBuildManifestPtr PrevInstallChunkManifest) +{ + check(ChunkManifest->GetCustomField("ChunkID").IsValid()); + InstallingChunkID = ChunkID; + check(ChunkID > 0); + InstallingChunkManifest = ChunkManifest; + IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile(); + auto PatchField = ChunkManifest->GetCustomField("bIsPatch"); + bool bIsPatch = PatchField.IsValid() ? PatchField->AsString() == TEXT("true") : false; + auto ChunkFolderName = FString::Printf(TEXT("%s%d"),!bIsPatch ? TEXT("base") : TEXT("patch"), InstallingChunkID); + auto ChunkInstallDir = FPaths::Combine(*InstallDir,*ChunkFolderName); + auto ChunkStageDir = FPaths::Combine(*StageDir,*ChunkFolderName); + if(!PlatformFile.DirectoryExists(*ChunkStageDir)) + { + PlatformFile.CreateDirectoryTree(*ChunkStageDir); + } + if(!PlatformFile.DirectoryExists(*ChunkInstallDir)) + { + PlatformFile.CreateDirectoryTree(*ChunkInstallDir); + } + BPSModule->SetCloudDirectory(CloudDir + TEXT("/") + CloudDirectory); + BPSModule->SetStagingDirectory(ChunkStageDir); + UE_LOG(LogHTTPChunkInstaller,Log,TEXT("Starting Chunk %d install"),InstallingChunkID); + InstallService = BPSModule->StartBuildInstall(PrevInstallChunkManifest,ChunkManifest,ChunkInstallDir,FBuildPatchBoolManifestDelegate::CreateRaw(this,&FHTTPChunkInstall::OSSInstallComplete)); + if(InstallSpeed == EChunkInstallSpeed::Paused && !InstallService->IsPaused()) + { + InstallService->TogglePauseInstall(); + } + InstallerState = ChunkInstallState::Installing; +} + +/** + * Note: the following cache functions are synchronous and may need to become asynchronous... + */ +bool FHTTPChunkInstall::AddDataToFileCache(const FString& ManifestHash,const TArray& Data) +{ + if (ManifestHash.IsEmpty()) + { + return false; + } + UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Adding data hash %s to file cache"), *ManifestHash); + return FFileHelper::SaveArrayToFile(Data, *FPaths::Combine(*CacheDir, *ManifestHash)); +} + +bool FHTTPChunkInstall::IsDataInFileCache(const FString& ManifestHash) +{ + if(ManifestHash.IsEmpty()) + { + return false; + } + IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile(); + return PlatformFile.FileExists(*FPaths::Combine(*CacheDir, *ManifestHash)); +} + +bool FHTTPChunkInstall::GetDataFromFileCache(const FString& ManifestHash, TArray& Data) +{ + if(ManifestHash.IsEmpty()) + { + return false; + } + UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Reading data hash %s from file cache"), *ManifestHash); + return FFileHelper::LoadFileToArray(Data, *FPaths::Combine(*CacheDir, *ManifestHash)); +} + +bool FHTTPChunkInstall::RemoveDataFromFileCache(const FString& ManifestHash) +{ + if(ManifestHash.IsEmpty()) + { + return false; + } + UE_LOG(LogHTTPChunkInstaller, Log, TEXT("Removing data hash %s from file cache"), *ManifestHash); + IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile(); + auto ManifestPath = FPaths::Combine(*CacheDir, *ManifestHash); + if (PlatformFile.FileExists(*ManifestPath)) + { + return PlatformFile.DeleteFile(*ManifestPath); + } + return false; +} + +void FHTTPChunkInstall::InitialiseSystem() +{ + BPSModule = GetBuildPatchServices(); + +#if !UE_BUILD_SHIPPING + const TCHAR* CmdLine = FCommandLine::Get(); + if (!FPlatformProperties::RequiresCookedData() || FParse::Param(CmdLine, TEXT("NoPak")) || FParse::Param(CmdLine, TEXT("NoChunkInstall"))) + { + bDebugNoInstalledRequired = true; + } +#endif + + // Grab the title file interface + FString TitleFileSource; + bool bValidTitleFileSource = GConfig->GetString(TEXT("HTTPChunkInstall"), TEXT("TitleFileSource"), TitleFileSource, GEngineIni); + if (bValidTitleFileSource && TitleFileSource == TEXT("Http")) + { + OnlineTitleFile = OnlineTitleFileHttp = MakeShareable(new FOnlineTitleFileHttp(CloudDir)); + } +/* else if (bValidTitleFileSource && TitleFileSource != TEXT("Local")) + { + OnlineTitleFile = Online::GetTitleFileInterface(*TitleFileSource); + }*/ + else + { + FString LocalTileFileDirectory = FPaths::GameConfigDir(); + auto bGetConfigDir = GConfig->GetString(TEXT("HTTPChunkInstall"), TEXT("LocalTitleFileDirectory"), LocalTileFileDirectory, GEngineIni); + OnlineTitleFile = MakeShareable(new FLocalTitleFile(LocalTileFileDirectory)); +#if !UE_BUILD_SHIPPING + bDebugNoInstalledRequired = !bGetConfigDir; +#endif + } + CloudDirectory = TEXT(""); + CloudDir = FPaths::Combine(*FPaths::GameContentDir(), TEXT("Cloud")); + StageDir = FPaths::Combine(*FPaths::GameSavedDir(), TEXT("Chunks"), TEXT("Staged")); + InstallDir = FPaths::Combine(*FPaths::GameSavedDir(), TEXT("Chunks"), TEXT("Installed")); // By default this should match ContentDir + BackupDir = FPaths::Combine(*FPaths::GameSavedDir(), TEXT("Chunks"), TEXT("Backup")); + CacheDir = FPaths::Combine(*FPaths::GameSavedDir(), TEXT("Chunks"), TEXT("Cache")); + HoldingDir = FPaths::Combine(*FPaths::GameSavedDir(), TEXT("Chunks"), TEXT("Hold")); + ContentDir = FPaths::Combine(*FPaths::GameSavedDir(), TEXT("Chunks"), TEXT("Installed")); // By default this should match InstallDir + + FString TmpString1; + FString TmpString2; + if (GConfig->GetString(TEXT("HTTPChunkInstall"), TEXT("CloudDirectory"), TmpString1, GEngineIni)) + { + CloudDirectory = CloudDir = TmpString1; + } + if ((GConfig->GetString(TEXT("HTTPChunkInstall"), TEXT("CloudProtocol"), TmpString1, GEngineIni)) && (GConfig->GetString(TEXT("HTTPChunkInstall"), TEXT("CloudDomain"), TmpString2, GEngineIni))) + { + CloudDir = FString::Printf(TEXT("%s://%s"), *TmpString1, *TmpString2); + } + if (GConfig->GetString(TEXT("HTTPChunkInstall"), TEXT("StageDirectory"), TmpString1, GEngineIni)) + { + StageDir = TmpString1; + } + if (GConfig->GetString(TEXT("HTTPChunkInstall"), TEXT("InstallDirectory"), TmpString1, GEngineIni)) + { + InstallDir = TmpString1; + } + if (GConfig->GetString(TEXT("HTTPChunkInstall"), TEXT("BackupDirectory"), TmpString1, GEngineIni)) + { + BackupDir = TmpString1; + } + if (GConfig->GetString(TEXT("HTTPChunkInstall"), TEXT("ContentDirectory"), TmpString1, GEngineIni)) + { + ContentDir = TmpString1; + } + if (GConfig->GetString(TEXT("HTTPChunkInstall"), TEXT("HoldingDirectory"), TmpString1, GEngineIni)) + { + HoldingDir = TmpString1; + } + + bFirstRun = true; + bSystemInitialised = true; +} + +IBuildManifestPtr FHTTPChunkInstall::FindPreviousInstallManifest(const IBuildManifestPtr& ChunkManifest) +{ + auto ChunkIDField = ChunkManifest->GetCustomField("ChunkID"); + if (!ChunkIDField.IsValid()) + { + return IBuildManifestPtr(); + } + auto ChunkID = ChunkIDField->AsInteger(); + TArray FoundManifests; + PrevInstallManifests.MultiFind(ChunkID, FoundManifests); + return FoundManifests.Num() == 0 ? IBuildManifestPtr() : FoundManifests[0]; +} + +void FHTTPChunkInstall::EndInstall() +{ + if (InstallService.IsValid()) + { + //InstallService->CancelInstall(); + InstallService.Reset(); + } + InstallingChunkID = -1; + InstallingChunkManifest.Reset(); + InstallerState = ChunkInstallState::Idle; +} + +/** + * Module for the HTTP Chunk Installer + */ +class FHTTPChunkInstallerModule : public IPlatformChunkInstallModule +{ +public: + TUniquePtr ChunkInstaller; + + FHTTPChunkInstallerModule() + : ChunkInstaller(new FHTTPChunkInstall()) + { + + } + + virtual IPlatformChunkInstall* GetPlatformChunkInstall() + { + return ChunkInstaller.Get(); + } +}; + +IMPLEMENT_MODULE(FHTTPChunkInstallerModule, HTTPChunkInstaller); \ No newline at end of file diff --git a/Engine/Plugins/Online/HTTPChunkInstaller/Source/Private/HTTPChunkInstallerLog.cpp b/Engine/Plugins/Runtime/HTTPChunkInstaller/Source/Private/HTTPChunkInstallerLog.cpp similarity index 100% rename from Engine/Plugins/Online/HTTPChunkInstaller/Source/Private/HTTPChunkInstallerLog.cpp rename to Engine/Plugins/Runtime/HTTPChunkInstaller/Source/Private/HTTPChunkInstallerLog.cpp diff --git a/Engine/Plugins/Online/HTTPChunkInstaller/Source/Private/LocalTitleFile.cpp b/Engine/Plugins/Runtime/HTTPChunkInstaller/Source/Private/LocalTitleFile.cpp similarity index 91% rename from Engine/Plugins/Online/HTTPChunkInstaller/Source/Private/LocalTitleFile.cpp rename to Engine/Plugins/Runtime/HTTPChunkInstaller/Source/Private/LocalTitleFile.cpp index 8854d07fba47..3e4400a499e4 100644 --- a/Engine/Plugins/Online/HTTPChunkInstaller/Source/Private/LocalTitleFile.cpp +++ b/Engine/Plugins/Runtime/HTTPChunkInstaller/Source/Private/LocalTitleFile.cpp @@ -1,9 +1,9 @@ // Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. #include "LocalTitleFile.h" -#include "Misc/Paths.h" -#include "HAL/FileManager.h" -#include "Misc/FileHelper.h" +#include "FileManagerGeneric.h" +#include "Paths.h" +#include "FileHelper.h" FLocalTitleFile::FLocalTitleFile(const FString& InRootDirectory) : RootDirectory(InRootDirectory) @@ -64,7 +64,7 @@ void FLocalTitleFile::DeleteCachedFiles(bool bSkipEnumerated) // not implemented } -bool FLocalTitleFile::EnumerateFiles(const FPagedQuery& Page) +bool FLocalTitleFile::EnumerateFiles(const FCloudPagedQuery& Page) { const FString WildCard = FPaths::Combine(*RootDirectory, TEXT("*")); @@ -75,7 +75,7 @@ bool FLocalTitleFile::EnumerateFiles(const FPagedQuery& Page) { const FString Filename = Filenames[FileIdx]; - FCloudFileHeader NewHeader; + FCloudHeader NewHeader; NewHeader.FileName = Filename; NewHeader.DLName = Filename + FString::Printf(TEXT("%d"),FileIdx); NewHeader.FileSize = 0; @@ -89,7 +89,7 @@ bool FLocalTitleFile::EnumerateFiles(const FPagedQuery& Page) return true; } -void FLocalTitleFile::GetFileList(TArray& InFileHeaders) +void FLocalTitleFile::GetFileList(TArray& InFileHeaders) { InFileHeaders.Append(FileHeaders); } diff --git a/Engine/Plugins/Online/HTTPChunkInstaller/Source/Public/ChunkInstall.h b/Engine/Plugins/Runtime/HTTPChunkInstaller/Source/Public/ChunkInstall.h similarity index 53% rename from Engine/Plugins/Online/HTTPChunkInstaller/Source/Public/ChunkInstall.h rename to Engine/Plugins/Runtime/HTTPChunkInstaller/Source/Public/ChunkInstall.h index 8103adf34182..6e7fa5cef0cc 100644 --- a/Engine/Plugins/Online/HTTPChunkInstaller/Source/Public/ChunkInstall.h +++ b/Engine/Plugins/Runtime/HTTPChunkInstaller/Source/Public/ChunkInstall.h @@ -2,19 +2,18 @@ #pragma once -#include "HAL/Runnable.h" -#include "HAL/PlatformProcess.h" -#include "HAL/Event.h" -#include "HAL/PlatformFile.h" -#include "HAL/FileManager.h" -#include "HAL/PlatformFilemanager.h" +#include "CoreMinimal.h" +#include "Runnable.h" #include "Interfaces/IBuildManifest.h" -#include "Interfaces/IBuildPatchServicesModule.h" -#include "Misc/Paths.h" -#include "Misc/CoreDelegates.h" -#include "Stats/Stats.h" - -class IBuildPatchServicesModule; +#include "IBuildPatchServicesModule.h" +#include "PlatformProcess.h" +#include "Event.h" +#include "GenericPlatformFile.h" +#include "Paths.h" +#include "PlatformFilemanager.h" +#include "CoreDelegates.h" +#include "FileManager.h" +#include "Stats.h" class FChunkInstallTask : public FRunnable { @@ -28,7 +27,7 @@ public: IBuildManifestPtr BuildManifest; bool bCopy; const TArray* CurrentMountPaks; - FEvent* CompleteEvent; + FEvent* CompleteEvent; /** Output */ TArray MountedPaks; @@ -160,124 +159,3 @@ public: RETURN_QUICK_DECLARE_CYCLE_STAT(FChunkInstallTask, STATGROUP_ThreadPoolAsyncTasks); } }; - - -class FChunkMountOnlyTask : public FRunnable -{ -public: - /** Input parameters */ - FString ManifestPath; - FString DestDir; - bool bCopy; - const TArray* CurrentMountPaks; - IBuildManifestPtr BuildManifest; - FEvent* CompleteEvent; - /** Output */ - TArray MountedPaks; - - FChunkMountOnlyTask() - { - CompleteEvent = FPlatformProcess::GetSynchEventFromPool(true); - } - - ~FChunkMountOnlyTask() - { - FPlatformProcess::ReturnSynchEventToPool(CompleteEvent); - CompleteEvent = nullptr; - } - - void SetupWork(FString InManifestPath, FString InDestDir, IBuildManifestRef InBuildManifest, const TArray& InCurrentMountedPaks) - { - ManifestPath = InManifestPath; - DestDir = InDestDir; - BuildManifest = InBuildManifest; - CurrentMountPaks = &InCurrentMountedPaks; - - MountedPaks.Reset(); - CompleteEvent->Reset(); - } - - void DoWork() - { - // Helper class to find all pak files. - class FPakSearchVisitor : public IPlatformFile::FDirectoryVisitor - { - TArray& FoundPakFiles; - public: - FPakSearchVisitor(TArray& InFoundPakFiles) - : FoundPakFiles(InFoundPakFiles) - {} - virtual bool Visit(const TCHAR* FilenameOrDirectory, bool bIsDirectory) - { - if (bIsDirectory == false) - { - FString Filename(FilenameOrDirectory); - if (FPaths::GetExtension(Filename) == TEXT("pak")) - { - FoundPakFiles.Add(Filename); - } - } - return true; - } - }; - - check(CurrentMountPaks); - - TArray PakFiles; - IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile(); - - // Find all pak files. - FPakSearchVisitor Visitor(PakFiles); - PlatformFile.IterateDirectoryRecursively(*DestDir, Visitor); - auto PakReadOrderField = BuildManifest->GetCustomField("PakReadOrdering"); - uint32 PakReadOrder = PakReadOrderField.IsValid() ? (uint32)PakReadOrderField->AsInteger() : 0; - for (uint32 PakIndex = 0, PakCount = PakFiles.Num(); PakIndex < PakCount; ++PakIndex) - { - if (!CurrentMountPaks->Contains(PakFiles[PakIndex]) && !MountedPaks.Contains(PakFiles[PakIndex])) - { - // TODO: are we a patch? - // if (PakFiles[PakIndex].EndsWith("_P.pak")) - // { - // // bump the read priority - // ++PakReadOrder; - // } - if (FCoreDelegates::OnMountPak.IsBound()) - { - auto bSuccess = FCoreDelegates::OnMountPak.Execute(PakFiles[PakIndex], PakReadOrder, nullptr); -#if !UE_BUILD_SHIPPING - if (!bSuccess) - { - // This can fail because of the sandbox system - which the pak system doesn't understand. - auto SandboxedPath = IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*PakFiles[PakIndex]); - bSuccess = FCoreDelegates::OnMountPak.Execute(SandboxedPath, PakReadOrder, nullptr); - } -#endif - MountedPaks.Add(PakFiles[PakIndex]); - } - } - } - - CompleteEvent->Trigger(); - } - - uint32 Run() - { - DoWork(); - return 0; - } - - bool IsDone() - { - return CompleteEvent->Wait(FTimespan(0)); - } - - static const TCHAR *Name() - { - return TEXT("FChunkDescovery"); - } - - FORCEINLINE TStatId GetStatId() const - { - RETURN_QUICK_DECLARE_CYCLE_STAT(FChunkMountOnlyTask, STATGROUP_ThreadPoolAsyncTasks); - } -}; diff --git a/Engine/Plugins/Online/HTTPChunkInstaller/Source/Public/ChunkSetup.h b/Engine/Plugins/Runtime/HTTPChunkInstaller/Source/Public/ChunkSetup.h similarity index 96% rename from Engine/Plugins/Online/HTTPChunkInstaller/Source/Public/ChunkSetup.h rename to Engine/Plugins/Runtime/HTTPChunkInstaller/Source/Public/ChunkSetup.h index bcdac5a9d6c7..26366965ae33 100644 --- a/Engine/Plugins/Online/HTTPChunkInstaller/Source/Public/ChunkSetup.h +++ b/Engine/Plugins/Runtime/HTTPChunkInstaller/Source/Public/ChunkSetup.h @@ -2,12 +2,7 @@ #pragma once -#include "CoreMinimal.h" -#include "GenericPlatform/GenericPlatformFile.h" -#include "HAL/Runnable.h" -#include "Stats/Stats.h" - -// Helper class to find all pak/manifests files. +// Helper class to find all pak/mainfests files. class FFileSearchVisitor : public IPlatformFile::FDirectoryVisitor { FString FileWildcard; @@ -313,13 +308,8 @@ public: bSuccess = FCoreDelegates::OnMountPak.Execute(SandboxedPath, PakReadOrder, nullptr); } #endif - if (bSuccess) - { - MountedPaks.Add(PakPath); - - //Register the install - BPSModule->RegisterAppInstallation(Manifest.ToSharedRef(), FilenameOrDirectory); - } + //Register the install + BPSModule->RegisterAppInstallation(Manifest.ToSharedRef(), FilenameOrDirectory); } } } diff --git a/Engine/Plugins/Runtime/HTTPChunkInstaller/Source/Public/CloudDelegateMacros.h b/Engine/Plugins/Runtime/HTTPChunkInstaller/Source/Public/CloudDelegateMacros.h new file mode 100644 index 000000000000..1de032a04f9a --- /dev/null +++ b/Engine/Plugins/Runtime/HTTPChunkInstaller/Source/Public/CloudDelegateMacros.h @@ -0,0 +1,76 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" + +#define DEFINE_CLOUD_DELEGATE_BASE(DelegateName) \ +public: \ + F##DelegateName DelegateName##Delegates; \ +public: \ + virtual FDelegateHandle Add##DelegateName##Delegate_Handle(const F##DelegateName##Delegate& Delegate) \ + { \ + DelegateName##Delegates.Add(Delegate); \ + return Delegate.GetHandle(); \ + } \ + virtual void Clear##DelegateName##Delegate_Handle(FDelegateHandle& Handle) \ + { \ + DelegateName##Delegates.Remove(Handle); \ + Handle.Reset(); \ + } + +#define DEFINE_CLOUD_DELEGATE(DelegateName) \ + DEFINE_CLOUD_DELEGATE_BASE(DelegateName) \ + virtual void Trigger##DelegateName##Delegates() \ + { \ + DelegateName##Delegates.Broadcast(); \ + } + +#define DEFINE_CLOUD_DELEGATE_ONE_PARAM(DelegateName, Param1Type) \ + DEFINE_CLOUD_DELEGATE_BASE(DelegateName) \ + virtual void Trigger##DelegateName##Delegates(Param1Type Param1) \ + { \ + DelegateName##Delegates.Broadcast(Param1); \ + } + +#define DEFINE_CLOUD_DELEGATE_TWO_PARAM(DelegateName, Param1Type, Param2Type) \ + DEFINE_CLOUD_DELEGATE_BASE(DelegateName) \ + virtual void Trigger##DelegateName##Delegates(Param1Type Param1, Param2Type Param2) \ + { \ + DelegateName##Delegates.Broadcast(Param1, Param2); \ + } + +#define DEFINE_CLOUD_DELEGATE_THREE_PARAM(DelegateName, Param1Type, Param2Type, Param3Type) \ + DEFINE_CLOUD_DELEGATE_BASE(DelegateName) \ + virtual void Trigger##DelegateName##Delegates(Param1Type Param1, Param2Type Param2, Param3Type Param3) \ + { \ + DelegateName##Delegates.Broadcast(Param1, Param2, Param3); \ + } + +#define DEFINE_CLOUD_DELEGATE_FOUR_PARAM(DelegateName, Param1Type, Param2Type, Param3Type, Param4Type) \ + DEFINE_CLOUD_DELEGATE_BASE(DelegateName) \ + virtual void Trigger##DelegateName##Delegates(Param1Type Param1, Param2Type Param2, Param3Type Param3, Param4Type Param4) \ + { \ + DelegateName##Delegates.Broadcast(Param1, Param2, Param3, Param4); \ + } + +#define DEFINE_CLOUD_DELEGATE_FIVE_PARAM(DelegateName, Param1Type, Param2Type, Param3Type, Param4Type, Param5Type) \ + DEFINE_CLOUD_DELEGATE_BASE(DelegateName) \ + virtual void Trigger##DelegateName##Delegates(Param1Type Param1, Param2Type Param2, Param3Type Param3, Param4Type Param4, Param5Type Param5) \ + { \ + DelegateName##Delegates.Broadcast(Param1, Param2, Param3, Param4, Param5); \ + } + +#define DEFINE_CLOUD_DELEGATE_SIX_PARAM(DelegateName, Param1Type, Param2Type, Param3Type, Param4Type, Param5Type, Param6Type) \ + DEFINE_CLOUD_DELEGATE_BASE(DelegateName) \ + virtual void Trigger##DelegateName##Delegates(Param1Type Param1, Param2Type Param2, Param3Type Param3, Param4Type Param4, Param5Type Param5, Param6Type Param6) \ + { \ + DelegateName##Delegates.Broadcast(Param1, Param2, Param3, Param4, Param5, Param6); \ + } + +#define DEFINE_CLOUD_DELEGATE_SEVEN_PARAM(DelegateName, Param1Type, Param2Type, Param3Type, Param4Type, Param5Type, Param6Type, Param7Type) \ + DEFINE_CLOUD_DELEGATE_BASE(DelegateName) \ + virtual void Trigger##DelegateName##Delegates(Param1Type Param1, Param2Type Param2, Param3Type Param3, Param4Type Param4, Param5Type Param5, Param6Type Param6, Param7Type Param7) \ + { \ + DelegateName##Delegates.Broadcast(Param1, Param2, Param3, Param4, Param5, Param6, Param7); \ + } diff --git a/Engine/Plugins/Runtime/HTTPChunkInstaller/Source/Public/CloudTitleFileInterface.h b/Engine/Plugins/Runtime/HTTPChunkInstaller/Source/Public/CloudTitleFileInterface.h new file mode 100644 index 000000000000..54fd8719f7f4 --- /dev/null +++ b/Engine/Plugins/Runtime/HTTPChunkInstaller/Source/Public/CloudTitleFileInterface.h @@ -0,0 +1,267 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "CloudDelegateMacros.h" + +/** +* Paging info needed for a request that can return paged results +*/ +class FCloudPagedQuery +{ +public: + FCloudPagedQuery(int32 InStart = 0, int32 InCount = -1) + : Start(InStart) + , Count(InCount) + {} + + /** @return true if valid range */ + bool IsValidRange() const + { + return Start >= 0 && Count >= 0; + } + + /** first entry to fetch */ + int32 Start; + /** total entries to fetch. -1 means ALL */ + int32 Count; +}; + +/** Holds metadata about a given downloadable file */ +struct FCloudHeader +{ + /** Hash value, if applicable, of the given file contents */ + FString Hash; + /** The hash algorithm used to sign this file */ + FName HashType; + /** Filename as downloaded */ + FString DLName; + /** Logical filename, maps to the downloaded filename */ + FString FileName; + /** File size */ + int32 FileSize; + /** The full URL to download the file if it is stored in a CDN or separate host site */ + FString URL; + /** The chunk id this file represents */ + uint32 ChunkID; + + /** Constructors */ + FCloudHeader() : + FileSize(0), + ChunkID(0) + {} + + FCloudHeader(const FString& InFileName, const FString& InDLName, int32 InFileSize) : + DLName(InDLName), + FileName(InFileName), + FileSize(InFileSize), + ChunkID(0) + {} + + bool operator==(const FCloudHeader& Other) const + { + return FileSize == Other.FileSize && + Hash == Other.Hash && + HashType == Other.HashType && + DLName == Other.DLName && + FileName == Other.FileName && + URL == Other.URL && + ChunkID == Other.ChunkID; + } + + bool operator<(const FCloudHeader& Other) const + { + return FileName.Compare(Other.FileName, ESearchCase::IgnoreCase) < 0; + } +}; + +/** The state of an async task (read friends, read content, write cloud file, etc) request */ +namespace ECloudAsyncTaskState +{ + enum Type + { + /** The task has not been started */ + NotStarted, + /** The task is currently being processed */ + InProgress, + /** The task has completed successfully */ + Done, + /** The task failed to complete */ + Failed + }; + + /** @return the stringified version of the enum passed in */ + inline const TCHAR* ToString(ECloudAsyncTaskState::Type EnumVal) + { + switch (EnumVal) + { + case NotStarted: + { + return TEXT("NotStarted"); + } + case InProgress: + { + return TEXT("InProgress"); + } + case Done: + { + return TEXT("Done"); + } + case Failed: + { + return TEXT("Failed"); + } + } + return TEXT(""); + } +}; + +/** Holds the data used in downloading a file asynchronously from the online service */ +struct FCloudEntry +{ + /** The name of the file as requested */ + FString FileName; + /** The async state the file download is in */ + ECloudAsyncTaskState::Type AsyncState; + /** The buffer of data for the file */ + TArray Data; + + /** Constructors */ + FCloudEntry() : + AsyncState(ECloudAsyncTaskState::NotStarted) + { + } + + FCloudEntry(const FString& InFileName) : + FileName(InFileName), + AsyncState(ECloudAsyncTaskState::NotStarted) + { + } + + virtual ~FCloudEntry() {} +}; + +/** + * Delegate fired when the list of files has been returned from the network store + * + * @param bWasSuccessful whether the file list was successful or not + * + */ +DECLARE_MULTICAST_DELEGATE_OneParam(FOnEnumerateFilesComplete, bool); +typedef FOnEnumerateFilesComplete::FDelegate FOnEnumerateFilesCompleteDelegate; + +/** + * Delegate fired when as file read from the network platform's storage progresses + * + * @param FileName the name of the file this was for + * @param NumBytes the number of bytes read so far + */ +DECLARE_MULTICAST_DELEGATE_TwoParams(FOnReadFileProgress, const FString&, uint64); +typedef FOnReadFileProgress::FDelegate FOnReadFileProgressDelegate; + +/** + * Delegate fired when a file read from the network platform's storage is complete + * + * @param bWasSuccessful whether the file read was successful or not + * @param FileName the name of the file this was for + * + */ +DECLARE_MULTICAST_DELEGATE_TwoParams(FOnReadFileComplete, bool, const FString&); +typedef FOnReadFileComplete::FDelegate FOnReadFileCompleteDelegate; + +class ICloudTitleFile +{ +protected: + ICloudTitleFile() {}; + +public: + virtual ~ICloudTitleFile() {}; + + /** + * Copies the file data into the specified buffer for the specified file + * + * @param FileName the name of the file to read + * @param FileContents the out buffer to copy the data into + * + * @return true if the data was copied, false otherwise + */ + virtual bool GetFileContents(const FString& FileName, TArray& FileContents) = 0; + + /** + * Empties the set of downloaded files if possible (no async tasks outstanding) + * + * @return true if they could be deleted, false if they could not + */ + virtual bool ClearFiles() = 0; + + /** + * Empties the cached data for this file if it is not being downloaded currently + * + * @param FileName the name of the file to remove from the cache + * + * @return true if it could be deleted, false if it could not + */ + virtual bool ClearFile(const FString& FileName) = 0; + + /** + * Delete cached files on disk + * + * @param bSkipEnumerated if true then only non-enumerated files are deleted + */ + virtual void DeleteCachedFiles(bool bSkipEnumerated) = 0; + + /** + * Requests a list of available files from the network store + * + * @param Page paging info to use for query + * + * @return true if the request has started, false if not + */ + virtual bool EnumerateFiles(const FCloudPagedQuery& Page = FCloudPagedQuery()) = 0; + + /** + * Delegate fired when the list of files has been returned from the network store + * + * @param bWasSuccessful whether the file list was successful or not + * + */ + DEFINE_CLOUD_DELEGATE_ONE_PARAM(OnEnumerateFilesComplete, bool); + + /** + * Returns the list of files that was returned by the network store + * + * @param Files out array of file metadata + * + */ + virtual void GetFileList(TArray& Files) = 0; + + /** + * Starts an asynchronous read of the specified file from the network platform's file store + * + * @param FileToRead the name of the file to read + * + * @return true if the calls starts successfully, false otherwise + */ + virtual bool ReadFile(const FString& FileName) = 0; + + /** + * Delegate fired when a file read from the network platform's storage is complete + * + * @param bWasSuccessful whether the file read was successful or not + * @param FileName the name of the file this was for + * + */ + DEFINE_CLOUD_DELEGATE_TWO_PARAM(OnReadFileComplete, bool, const FString&); + + /** + * Delegate fired when as file read from the network platform's storage progresses + * + * @param FileName the name of the file this was for + * @param NumBytes the number of bytes read so far + */ + DEFINE_CLOUD_DELEGATE_TWO_PARAM(OnReadFileProgress, const FString&, uint64); +}; + +typedef TSharedPtr ICloudTitleFilePtr; +typedef TSharedRef ICloudTitleFileRef; diff --git a/Engine/Plugins/Online/HTTPChunkInstaller/Source/Public/HTTPChunkInstaller.h b/Engine/Plugins/Runtime/HTTPChunkInstaller/Source/Public/HTTPChunkInstaller.h similarity index 52% rename from Engine/Plugins/Online/HTTPChunkInstaller/Source/Public/HTTPChunkInstaller.h rename to Engine/Plugins/Runtime/HTTPChunkInstaller/Source/Public/HTTPChunkInstaller.h index f12ab8459d10..5c8482ba3fc2 100644 --- a/Engine/Plugins/Online/HTTPChunkInstaller/Source/Public/HTTPChunkInstaller.h +++ b/Engine/Plugins/Runtime/HTTPChunkInstaller/Source/Public/HTTPChunkInstaller.h @@ -2,57 +2,12 @@ #pragma once -#include "CoreMinimal.h" -#include "GenericPlatform/GenericPlatformChunkInstall.h" -#include "Templates/UniquePtr.h" +#include "GenericPlatformChunkInstall.h" +#include "UniquePtr.h" +#include "CloudTitleFileInterface.h" #include "ChunkInstall.h" #include "ChunkSetup.h" -#include "Containers/Ticker.h" - -// Gross hack: -// If games haven't updated their OSS to IWYU, and they're using the engine version -// of this plugin, they'll trigger IWYU monolithic errors, so we're temporarily -// suppressing those warnings since we can't force-update our games. - -// Added 2017-02-26; remove as soon as all of our games have taken an Online plugins update -#pragma push_macro("SUPPRESS_MONOLITHIC_HEADER_WARNINGS") -# define SUPPRESS_MONOLITHIC_HEADER_WARNINGS 1 -# include "OnlineSubsystem.h" -#pragma pop_macro("SUPPRESS_MONOLITHIC_HEADER_WARNINGS") - -struct FBuildInstallStats; - -enum class EChunkInstallErrorCode -{ - NoError, - GenericFailure, - RemoteFailure, // download errors, mcp errors, etc - LocalFailure, // disk errors, out of space errors, etc - NeedsClientUpdate, // manifest says we need a new client - ManifestDownloadFailure, // manifest failed to download - ClientIsTooNew, // client is newer than MCP (wrong environment?) -}; - -struct FChunkInstallError -{ - FChunkInstallError() - : ErrorCode(EChunkInstallErrorCode::NoError) - { - } - FChunkInstallError(EChunkInstallErrorCode InErrorCode, const FText& InErrorMessage) - : ErrorCode(InErrorCode) - , ErrorMessage(InErrorMessage) - { - } - - EChunkInstallErrorCode ErrorCode; - FText ErrorMessage; -}; - -DECLARE_DELEGATE_OneParam(FPlatformChunkInstallErrorDelegate, const FChunkInstallError&); -DECLARE_DELEGATE_FiveParams(FPlatformChunkInstallProgressDelegate, uint32, float, int64, int64, const FText&); -DECLARE_DELEGATE_FiveParams(FPlatformChunkAnalyticsDelegate, bool, uint32, float, int64, const FBuildInstallStats&); -DECLARE_DELEGATE(FPlatformChunkInstallRetryDelegate); +#include "Ticker.h" /** * HTTP based implementation of chunk based install @@ -87,7 +42,7 @@ public: if (InstallSpeed != InInstallSpeed) { InstallSpeed = InInstallSpeed; - if (InstallService.IsValid() && + if (InstallService.IsValid() && ((InstallSpeed == EChunkInstallSpeed::Paused && !InstallService->IsPaused()) || (InstallSpeed != EChunkInstallSpeed::Paused && InstallService->IsPaused()))) { InstallService->TogglePauseInstall(); @@ -95,18 +50,10 @@ public: } return true; } - + virtual bool PrioritizeChunk( uint32 ChunkID, EChunkPriority::Type Priority ) override; virtual FDelegateHandle SetChunkInstallDelgate(uint32 ChunkID, FPlatformChunkInstallCompleteDelegate Delegate) override; virtual void RemoveChunkInstallDelgate(uint32 ChunkID, FDelegateHandle Delegate) override; - FDelegateHandle SetErrorDelegate(FPlatformChunkInstallErrorDelegate Delegate); - void RemoveErrorDelegate(FDelegateHandle Delegate); - FDelegateHandle SetChunkInstallProgressDelgate(uint32 ChunkID, FPlatformChunkInstallProgressDelegate Delegate); - void RemoveChunkInstallProgressDelgate(uint32 ChunkID, FDelegateHandle Delegate); - FDelegateHandle SetChunkAnalyticsDelegate(FPlatformChunkAnalyticsDelegate Delegate); - void RemoveChunkAnalyticsDelegate(FDelegateHandle Delegate); - FDelegateHandle SetRetryDelegate(FPlatformChunkInstallRetryDelegate Delegate); - void RemoveRetryDelegate(FDelegateHandle Delegate); virtual bool DebugStartNextChunk() { @@ -119,20 +66,9 @@ public: void EndInstall(); - void Initialize(const FString& InBaseUrl, const FString& InManifestData); - bool IsEnabled() const { return bEnabled; } - bool IsReadyToInstall() const { return InstallerState > ChunkInstallState::PostSetup; } - - void SetupMasterManifest(const FString& InBaseUrl, const FString& ManifestData); - - inline bool IsRetryAvailable() const { return InstallerState == ChunkInstallState::OfflineMode; } - void Retry() { check(IsRetryAvailable()); InstallerState = ChunkInstallState::Retry; } - - void SetPreloaded(bool bPreload) { bPreloaded = bPreload; } - private: - void InitialiseSystem(const FString& InBaseUrl, const FString& InManifestData); + void InitialiseSystem(); bool AddDataToFileCache(const FString& ManifestHash,const TArray& Data); bool IsDataInFileCache(const FString& ManifestHash); bool GetDataFromFileCache(const FString& ManifestHash,TArray& Data); @@ -142,33 +78,24 @@ private: void BeginChunkInstall(uint32 NextChunkID,IBuildManifestPtr ChunkManifest, IBuildManifestPtr PrevInstallChunkManifest); void ParseTitleFileManifest(const FString& ManifestFileHash); bool BuildChunkFolderName(IBuildManifestRef Manifest, FString& ChunkFdrName, FString& ManifestName, uint32& ChunkID, bool& bIsPatch); - bool BuildChunkFolderName(FString& ChunkFdrName, FString& ManifestName, uint32 ChunkID); void OSSEnumerateFilesComplete(bool bSuccess); void OSSReadFileComplete(bool bSuccess, const FString& Filename); void OSSInstallComplete(bool, IBuildManifestRef); - bool FilesHaveChanged(IBuildManifestPtr LocalManifest, IBuildManifestPtr RemoteManifest, int32 ChunkID); - bool IsConnectedToWiFiorLAN() const; DECLARE_MULTICAST_DELEGATE_OneParam(FPlatformChunkInstallCompleteMultiDelegate, uint32); - DECLARE_MULTICAST_DELEGATE_OneParam(FPlatformChunkInstallErrorMultiDelegate, const FChunkInstallError&); - DECLARE_MULTICAST_DELEGATE_FiveParams(FPlatformChunkInstallProgressMultiDelegate, uint32, float, int64, int64, const FText&); - DECLARE_MULTICAST_DELEGATE_FiveParams(FPlatformChunkAnalyticsMultiDelegate, bool, uint32, float, int64, const FBuildInstallStats&); - DECLARE_MULTICAST_DELEGATE(FPlatformChunkInstallRetryMultiDelegate); enum struct ChunkInstallState { Setup, SetupWait, QueryRemoteManifests, + EnterOfflineMode, MoveInstalledChunks, RequestingTitleFiles, SearchTitleFiles, ReadTitleFiles, WaitingOnRead, ReadComplete, - EnterOfflineMode, - OfflineMode, - Retry, PostSetup, Idle, Installing, @@ -204,22 +131,18 @@ private: TUniquePtr ChunkSetupTaskThread; FChunkMountTask ChunkMountTask; TUniquePtr ChunkMountTaskThread; - FChunkMountOnlyTask ChunkMountOnlyTask; - TUniquePtr ChunkMountOnlyTaskThread; TMultiMap InstalledManifests; TMultiMap PrevInstallManifests; TMultiMap RemoteManifests; TMap DelegateMap; - TMap ProgressDelegateMap; TSet ManifestsInMemory; TSet ExpectedChunks; - TArray TitleFilesToRead; - TArray RemoteManifestsToBeRead; + TArray TitleFilesToRead; TArray FileContentBuffer; TArray PriorityQueue; TArray MountedPaks; - IOnlineTitleFilePtr OnlineTitleFile; - IOnlineTitleFilePtr OnlineTitleFileHttp; + ICloudTitleFilePtr OnlineTitleFile; + ICloudTitleFilePtr OnlineTitleFileHttp; IBuildInstallerPtr InstallService; IBuildManifestPtr InstallingChunkManifest; FDelegateHandle EnumFilesCompleteHandle; @@ -235,20 +158,10 @@ private: IBuildPatchServicesModule* BPSModule; uint32 InstallingChunkID; ChunkInstallState InstallerState; - ChunkInstallState PreviousInstallerState; EChunkInstallSpeed::Type InstallSpeed; bool bFirstRun; bool bSystemInitialised; #if !UE_BUILD_SHIPPING bool bDebugNoInstalledRequired; #endif - FCriticalSection ReadFileGuard; - TArray PendingReads; - FPlatformChunkInstallErrorMultiDelegate ErrorDelegate; - bool bEnabled; - bool bNeedsRetry; - FPlatformChunkAnalyticsMultiDelegate AnalyticsDelegate; - double StartTime; - FPlatformChunkInstallRetryMultiDelegate RetryDelegate; - bool bPreloaded; }; \ No newline at end of file diff --git a/Engine/Plugins/Online/HTTPChunkInstaller/Source/Private/HTTPChunkInstallerLog.h b/Engine/Plugins/Runtime/HTTPChunkInstaller/Source/Public/HTTPChunkInstallerLog.h similarity index 100% rename from Engine/Plugins/Online/HTTPChunkInstaller/Source/Private/HTTPChunkInstallerLog.h rename to Engine/Plugins/Runtime/HTTPChunkInstaller/Source/Public/HTTPChunkInstallerLog.h diff --git a/Engine/Plugins/Online/HTTPChunkInstaller/Source/Public/LocalTitleFile.h b/Engine/Plugins/Runtime/HTTPChunkInstaller/Source/Public/LocalTitleFile.h similarity index 64% rename from Engine/Plugins/Online/HTTPChunkInstaller/Source/Public/LocalTitleFile.h rename to Engine/Plugins/Runtime/HTTPChunkInstaller/Source/Public/LocalTitleFile.h index ae9ca490de18..8b975015508a 100644 --- a/Engine/Plugins/Online/HTTPChunkInstaller/Source/Public/LocalTitleFile.h +++ b/Engine/Plugins/Runtime/HTTPChunkInstaller/Source/Public/LocalTitleFile.h @@ -2,23 +2,22 @@ #pragma once -#include "CoreMinimal.h" -#include "OnlineTitleFileInterface.h" +#include "CloudTitleFileInterface.h" -class FLocalTitleFile : public IOnlineTitleFile +class FLocalTitleFile : public ICloudTitleFile { public: FLocalTitleFile(const FString& InRootDirectory); - // IOnlineTitleFile interface + // ICloudTitleFile interface virtual bool GetFileContents(const FString& DLName, TArray& FileContents) override; virtual bool ClearFiles() override; virtual bool ClearFile(const FString& DLName) override; virtual void DeleteCachedFiles(bool bSkipEnumerated) override; - virtual bool EnumerateFiles(const FPagedQuery& Page = FPagedQuery()) override; - virtual void GetFileList(TArray& InFileHeaders) override; + virtual bool EnumerateFiles(const FCloudPagedQuery& Page = FCloudPagedQuery()) override; + virtual void GetFileList(TArray& InFileHeaders) override; virtual bool ReadFile(const FString& DLName) override; protected: @@ -28,6 +27,6 @@ protected: private: FString RootDirectory; - TArray FileHeaders; + TArray FileHeaders; TMap< FString, TArray > DLNameToFileContents; }; \ No newline at end of file diff --git a/Engine/Plugins/Runtime/ImmediatePhysics/ImmediatePhysics.uplugin b/Engine/Plugins/Runtime/ImmediatePhysics/ImmediatePhysics.uplugin index 7217bd25c1bc..a09de735f5a0 100644 --- a/Engine/Plugins/Runtime/ImmediatePhysics/ImmediatePhysics.uplugin +++ b/Engine/Plugins/Runtime/ImmediatePhysics/ImmediatePhysics.uplugin @@ -12,7 +12,7 @@ "SupportURL" : "", "EnabledByDefault" : true, "CanContainContent" : false, - "IsBetaVersion" : true, + "IsBetaVersion" : false, "Installed" : false, "Modules" : [ diff --git a/Engine/Plugins/Runtime/ImmediatePhysics/Source/ImmediatePhysics/Private/BoneControllers/AnimNode_RigidBody.cpp b/Engine/Plugins/Runtime/ImmediatePhysics/Source/ImmediatePhysics/Private/BoneControllers/AnimNode_RigidBody.cpp index c8cdf8608d8a..b44fc04f9fff 100644 --- a/Engine/Plugins/Runtime/ImmediatePhysics/Source/ImmediatePhysics/Private/BoneControllers/AnimNode_RigidBody.cpp +++ b/Engine/Plugins/Runtime/ImmediatePhysics/Source/ImmediatePhysics/Private/BoneControllers/AnimNode_RigidBody.cpp @@ -21,7 +21,8 @@ using namespace ImmediatePhysics; #define LOCTEXT_NAMESPACE "ImmediatePhysics" -FAnimNode_RigidBody::FAnimNode_RigidBody() +FAnimNode_RigidBody::FAnimNode_RigidBody(): + QueryParams(NAME_None, FCollisionQueryParams::GetUnknownStatId()) { bResetSimulated = false; PhysicsSimulation = nullptr; @@ -335,7 +336,7 @@ DECLARE_CYCLE_STAT(TEXT("FAnimNode_Ragdoll::UpdateWorldGeometry"), STAT_Immediat void FAnimNode_RigidBody::UpdateWorldGeometry(const UWorld& World, const USkeletalMeshComponent& SKC) { SCOPE_CYCLE_COUNTER(STAT_ImmediateUpdateWorldGeometry); - QueryParams = FCollisionQueryParams(TEXT("RagdollNodeFindGeometry"), /*bTraceComplex=*/false); + QueryParams = FCollisionQueryParams(SCENE_QUERY_STAT(RagdollNodeFindGeometry), /*bTraceComplex=*/false); #if WITH_EDITOR if(!World.IsGameWorld()) { @@ -414,7 +415,7 @@ void FAnimNode_RigidBody::PreUpdate(const UAnimInstance* InAnimInstance) if(SKC) { - if (PhysicsSimulation && bEnableWorldGeometry && !bComponentSpaceSimulation && World) + if (PhysicsSimulation && bEnableWorldGeometry && !bComponentSpaceSimulation) { UpdateWorldGeometry(*World, *SKC); } diff --git a/Engine/Plugins/Runtime/ImmediatePhysics/Source/ImmediatePhysics/Private/ImmediatePhysicsSimulation.cpp b/Engine/Plugins/Runtime/ImmediatePhysics/Source/ImmediatePhysics/Private/ImmediatePhysicsSimulation.cpp index 0e82bff1dde5..82918ecb357e 100644 --- a/Engine/Plugins/Runtime/ImmediatePhysics/Source/ImmediatePhysics/Private/ImmediatePhysicsSimulation.cpp +++ b/Engine/Plugins/Runtime/ImmediatePhysics/Source/ImmediatePhysics/Private/ImmediatePhysicsSimulation.cpp @@ -474,7 +474,7 @@ void FSimulation::GenerateContacts() } const uint32 OtherActorIdx = ShapeSOA.OwningActors[OtherShapeIdx]; - if(OtherActorIdx >= NumSimulatedBodies && OtherActorIdx < NumSimulatedBodies) + if(OtherActorIdx >= NumActiveSimulatedBodies && OtherActorIdx < NumSimulatedBodies) { continue; } diff --git a/Engine/Plugins/Runtime/LocationServicesAndroidImpl/LocationServicesAndroidImpl.uplugin b/Engine/Plugins/Runtime/LocationServicesAndroidImpl/LocationServicesAndroidImpl.uplugin index fe3718af3a88..97362e4ee328 100644 --- a/Engine/Plugins/Runtime/LocationServicesAndroidImpl/LocationServicesAndroidImpl.uplugin +++ b/Engine/Plugins/Runtime/LocationServicesAndroidImpl/LocationServicesAndroidImpl.uplugin @@ -28,5 +28,15 @@ "Android" ] } + ], + "Plugins": [ + { + "Name": "LocationServicesBPLibrary", + "Enabled": true + }, + { + "Name": "AndroidPermission", + "Enabled": true + } ] } \ No newline at end of file diff --git a/Engine/Plugins/Runtime/LocationServicesIOSImpl/LocationServicesIOSImpl.uplugin b/Engine/Plugins/Runtime/LocationServicesIOSImpl/LocationServicesIOSImpl.uplugin index bc7835cfd804..6535c55e41c5 100644 --- a/Engine/Plugins/Runtime/LocationServicesIOSImpl/LocationServicesIOSImpl.uplugin +++ b/Engine/Plugins/Runtime/LocationServicesIOSImpl/LocationServicesIOSImpl.uplugin @@ -28,5 +28,11 @@ "IOS" ] } + ], + "Plugins": [ + { + "Name": "LocationServicesBPLibrary", + "Enabled": true + } ] } \ No newline at end of file diff --git a/Engine/Plugins/Runtime/TwitchLiveStreaming/TwitchLiveStreaming.uplugin b/Engine/Plugins/Runtime/MeshReconstruction/DummyMeshReconstructor/DummyMeshReconstructor.uplugin similarity index 55% rename from Engine/Plugins/Runtime/TwitchLiveStreaming/TwitchLiveStreaming.uplugin rename to Engine/Plugins/Runtime/MeshReconstruction/DummyMeshReconstructor/DummyMeshReconstructor.uplugin index 5b90eaa29801..b698a958fcce 100644 --- a/Engine/Plugins/Runtime/TwitchLiveStreaming/TwitchLiveStreaming.uplugin +++ b/Engine/Plugins/Runtime/MeshReconstruction/DummyMeshReconstructor/DummyMeshReconstructor.uplugin @@ -2,9 +2,9 @@ "FileVersion" : 3, "Version" : 1, "VersionName" : "1.0", - "FriendlyName" : "Twitch Live Streaming", - "Description" : "Live video broadcasting to Twitch for games and the editor", - "Category" : "Misc", + "FriendlyName" : "Sample Mesh Reconstructor", + "Description" : "Sample of how to drive mesh reconstruction. Generates dummy geometry to demonstrate API usage.", + "Category" : "Virtual Reality", "CreatedBy" : "Epic Games, Inc.", "CreatedByURL" : "http://epicgames.com", "DocsURL" : "", @@ -17,14 +17,15 @@ "Modules" : [ { - "Name" : "TwitchLiveStreaming", + "Name" : "DummyMeshReconstructor", "Type" : "Runtime", - "LoadingPhase" : "Default", + "LoadingPhase" : "PostConfigInit", "WhitelistPlatforms" : [ - "Win32", - "Win64" + "Android", + "Win64", + "Win32" ] } ] -} \ No newline at end of file +} diff --git a/Engine/Plugins/Runtime/MeshReconstruction/DummyMeshReconstructor/Source/DummyMeshReconstructor/DummyMeshReconstructor.Build.cs b/Engine/Plugins/Runtime/MeshReconstruction/DummyMeshReconstructor/Source/DummyMeshReconstructor/DummyMeshReconstructor.Build.cs new file mode 100644 index 000000000000..beecfb255e29 --- /dev/null +++ b/Engine/Plugins/Runtime/MeshReconstruction/DummyMeshReconstructor/Source/DummyMeshReconstructor/DummyMeshReconstructor.Build.cs @@ -0,0 +1,23 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +namespace UnrealBuildTool.Rules +{ + public class DummyMeshReconstructor : ModuleRules + { + public DummyMeshReconstructor(ReadOnlyTargetRules Target) : base(Target) + { + PrivateIncludePaths.Add("DummyMeshReconstructor/Private"); + + PublicDependencyModuleNames.AddRange + ( + new string[] + { + "Core", + "CoreUObject", + "Engine", + "MRMesh", + } + ); + } + } +} diff --git a/Engine/Plugins/Runtime/MeshReconstruction/DummyMeshReconstructor/Source/DummyMeshReconstructor/Private/DummyMeshReconstructorModule.cpp b/Engine/Plugins/Runtime/MeshReconstruction/DummyMeshReconstructor/Source/DummyMeshReconstructor/Private/DummyMeshReconstructorModule.cpp new file mode 100644 index 000000000000..e13a19e36993 --- /dev/null +++ b/Engine/Plugins/Runtime/MeshReconstruction/DummyMeshReconstructor/Source/DummyMeshReconstructor/Private/DummyMeshReconstructorModule.cpp @@ -0,0 +1,258 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "DummyMeshReconstructorModule.h" +#include "BaseMeshReconstructorModule.h" +#include "Modules/ModuleManager.h" +#include "Runnable.h" +#include "PlatformProcess.h" +#include "RunnableThread.h" +#include "ThreadSafeBool.h" +#include "MRMeshComponent.h" +#include "DynamicMeshBuilder.h" +#include "Queue.h" + +static const FVector BRICK_SIZE(256.0f, 256.0f, 256.0f); +static const int32 BRICK_COORD_RANDMAX = 8; + +class FDummyMeshReconstructor : public FRunnable +{ +public: + FDummyMeshReconstructor( IMRMesh& MRMeshComponent ) + : bKeepRunning(true) + , bResendAllData(false) + , TargetMRMesh( MRMeshComponent ) + , ReconstructorThread(nullptr) + { + + // Pre-allocate the reconstructed geometry data. + // Re-allocating this array will cause dangling pointers from MRMeshComponent. + ReconstructedGeometry.Reserve(BRICK_COORD_RANDMAX*BRICK_COORD_RANDMAX*BRICK_COORD_RANDMAX); + + // Start a new thread. + ReconstructorThread = TUniquePtr(FRunnableThread::Create(this, TEXT("Dummy Mesh Reconstructor"))); + } + + ~FDummyMeshReconstructor() + { + // Stop the geometry generator thread. + if (ReconstructorThread.IsValid()) + { + ReconstructorThread->Kill(true); + } + } + + /** + * Get the MRMeshComponent that is currently presenting our data. + * Used for checking against re-connects to the same component. + */ + const IMRMesh& GetTargetMRMesh() const { return TargetMRMesh; } + + /** Re-send all the geometry data to the paired MRMeshComponent */ + void ResendAllData() + { + bResendAllData.AtomicSet(true); + } + +private: + //~ FRunnable + virtual uint32 Run() override + { + // + // Main geometry generator loop + // + + while (bKeepRunning) + { + if (bResendAllData) + { + // The component requested that we re-send all the data. + for (FPayload& Payload : ReconstructedGeometry) + { + TargetMRMesh.SendBrickData(IMRMesh::FSendBrickDataArgs + { + Payload.BrickCoords, + Payload.Vertices, + Payload.Indices + }); + } + bResendAllData.AtomicSet(false); + } + + // Send newly-generated brick. + { + // Allocate a new brick. We own this memory. + const int32 NewPayloadIndex = NewRandomPayload(); + TargetMRMesh.SendBrickData(IMRMesh::FSendBrickDataArgs + { + ReconstructedGeometry[NewPayloadIndex].BrickCoords, + ReconstructedGeometry[NewPayloadIndex].Vertices, + ReconstructedGeometry[NewPayloadIndex].Indices + }); + } + + FPlatformProcess::Sleep(1.0f/5.0f); + } + + return 0; + } + + virtual void Stop() override + { + bKeepRunning.AtomicSet(false); + } + //~ FRunnable + + struct FPayload + { + FIntVector BrickCoords; + TArray Vertices; + TArray Indices; + }; + + int32 NewRandomPayload() + { + static const int32 MIN_BOXES = 2; + static const int32 MAX_BOXES = 20; + static const FBox RANDOM_SIZE_BOX = FBox(FVector::ZeroVector, 0.25f*BRICK_SIZE); + + const int32 NumBoxes = FMath::FloorToInt(FMath::RandRange(MIN_BOXES, MAX_BOXES)); + const int32 NumUniqueVerts = NumBoxes * 8; + const int32 NumTris = NumBoxes * 6 * 2; // 2 tris per box face + const int32 NumVertIndices = 3 * NumTris; + + + const FIntVector BrickCoords( + FMath::FloorToInt(FMath::RandRange(0, BRICK_COORD_RANDMAX)), + FMath::FloorToInt(FMath::RandRange(0, BRICK_COORD_RANDMAX)), + FMath::FloorToInt(FMath::RandRange(0, BRICK_COORD_RANDMAX)) + ); + + const FVector BrickOrigin(BRICK_SIZE.X*BrickCoords.X, BRICK_SIZE.Y*BrickCoords.Y, BRICK_SIZE.Z*BrickCoords.Z); + const FBox RandomLocationsBox = FBox(BrickOrigin, BrickOrigin + FVector(1024, 1024, 1024)); + + // + // !! Allocate a new Brick. We own this data. + // + ReconstructedGeometry.AddDefaulted(1); + FPayload& NewPayload = ReconstructedGeometry.Last(); + NewPayload.BrickCoords = BrickCoords; + NewPayload.Vertices.Reserve(NumUniqueVerts); + NewPayload.Indices.Reserve(NumVertIndices); + + auto AddBox = [](FVector Origin, FVector Extents, FPayload& NewPayloadIn) + { + const int32 IndexOffset = NewPayloadIn.Vertices.Num(); + NewPayloadIn.Vertices.Emplace(FVector(Origin.X + Extents.X, Origin.Y - Extents.Y, Origin.Z + Extents.Z)); // IndexOffset+0 + NewPayloadIn.Vertices.Last().Color = FColor(255, 0, 255); + NewPayloadIn.Vertices.Emplace(FVector(Origin.X + Extents.X, Origin.Y + Extents.Y, Origin.Z + Extents.Z)); // IndexOffset+1 + NewPayloadIn.Vertices.Last().Color = FColor(255, 255, 255); + NewPayloadIn.Vertices.Emplace(FVector(Origin.X + Extents.X, Origin.Y + Extents.Y, Origin.Z - Extents.Z)); // IndexOffset+2 + NewPayloadIn.Vertices.Last().Color = FColor(255, 255, 0); + NewPayloadIn.Vertices.Emplace(FVector(Origin.X + Extents.X, Origin.Y - Extents.Y, Origin.Z - Extents.Z)); // IndexOffset+3 + NewPayloadIn.Vertices.Last().Color = FColor(255, 0, 0); + NewPayloadIn.Vertices.Emplace(FVector(Origin.X - Extents.X, Origin.Y - Extents.Y, Origin.Z + Extents.Z)); // IndexOffset+4 + NewPayloadIn.Vertices.Last().Color = FColor(0, 0, 255); + NewPayloadIn.Vertices.Emplace(FVector(Origin.X - Extents.X, Origin.Y + Extents.Y, Origin.Z + Extents.Z)); // IndexOffset+5 + NewPayloadIn.Vertices.Last().Color = FColor(0, 255, 255); + NewPayloadIn.Vertices.Emplace(FVector(Origin.X - Extents.X, Origin.Y + Extents.Y, Origin.Z - Extents.Z)); // IndexOffset+6 + NewPayloadIn.Vertices.Last().Color = FColor(0, 255, 0); + NewPayloadIn.Vertices.Emplace(FVector(Origin.X - Extents.X, Origin.Y - Extents.Y, Origin.Z - Extents.Z)); // IndexOffset+7 + NewPayloadIn.Vertices.Last().Color = FColor(0, 0, 0); + + NewPayloadIn.Indices.Add(IndexOffset + 0); + NewPayloadIn.Indices.Add(IndexOffset + 1); + NewPayloadIn.Indices.Add(IndexOffset + 2); + + NewPayloadIn.Indices.Add(IndexOffset + 0); + NewPayloadIn.Indices.Add(IndexOffset + 2); + NewPayloadIn.Indices.Add(IndexOffset + 3); + + NewPayloadIn.Indices.Add(IndexOffset + 0); + NewPayloadIn.Indices.Add(IndexOffset + 4); + NewPayloadIn.Indices.Add(IndexOffset + 1); + + NewPayloadIn.Indices.Add(IndexOffset + 1); + NewPayloadIn.Indices.Add(IndexOffset + 4); + NewPayloadIn.Indices.Add(IndexOffset + 5); + + NewPayloadIn.Indices.Add(IndexOffset + 7); + NewPayloadIn.Indices.Add(IndexOffset + 5); + NewPayloadIn.Indices.Add(IndexOffset + 4); + + NewPayloadIn.Indices.Add(IndexOffset + 6); + NewPayloadIn.Indices.Add(IndexOffset + 5); + NewPayloadIn.Indices.Add(IndexOffset + 7); + + NewPayloadIn.Indices.Add(IndexOffset + 7); + NewPayloadIn.Indices.Add(IndexOffset + 3); + NewPayloadIn.Indices.Add(IndexOffset + 2); + + NewPayloadIn.Indices.Add(IndexOffset + 7); + NewPayloadIn.Indices.Add(IndexOffset + 2); + NewPayloadIn.Indices.Add(IndexOffset + 6); + + NewPayloadIn.Indices.Add(IndexOffset + 7); + NewPayloadIn.Indices.Add(IndexOffset + 4); + NewPayloadIn.Indices.Add(IndexOffset + 0); + + NewPayloadIn.Indices.Add(IndexOffset + 7); + NewPayloadIn.Indices.Add(IndexOffset + 0); + NewPayloadIn.Indices.Add(IndexOffset + 3); + + NewPayloadIn.Indices.Add(IndexOffset + 1); + NewPayloadIn.Indices.Add(IndexOffset + 5); + NewPayloadIn.Indices.Add(IndexOffset + 6); + + NewPayloadIn.Indices.Add(IndexOffset + 2); + NewPayloadIn.Indices.Add(IndexOffset + 1); + NewPayloadIn.Indices.Add(IndexOffset + 6); + }; + + + for (int i = 0; i < NumBoxes; ++i) + { + auto wat = FVector(FMath::RandRange(5.0f, 100.0f), FMath::RandRange(5.0f, 100.0f), FMath::RandRange(5.0f, 100.0f)); + + AddBox(FMath::RandPointInBox(RandomLocationsBox), FMath::RandPointInBox(RANDOM_SIZE_BOX), NewPayload); + } + + return ReconstructedGeometry.Num() - 1; + } + + + FThreadSafeBool bKeepRunning; + FThreadSafeBool bResendAllData; + IMRMesh& TargetMRMesh; + TArray ReconstructedGeometry; + TUniquePtr ReconstructorThread; +}; + +// Thin wrapper around the running thread that does all the reconstruction. +class FDummyMeshReconstructorModule : public FBaseMeshReconstructorModule +{ +private: + virtual void PairWithComponent(IMRMesh& MRMeshComponent) override + { + if (const bool bAlreadyPaired = Reconstructor.IsValid() && (&Reconstructor->GetTargetMRMesh() == &MRMeshComponent) ) + { + // We are already paired to this component, but for some reason + // we are re-connecting (probably render proxy re-create). + // Resend all the data so that the component can process it. + Reconstructor->ResendAllData(); + } + else + { + // We are connecting to a new component. Flush all current data. + Reconstructor = MakeUnique(MRMeshComponent); + } + } + + virtual void Stop() override + { + Reconstructor.Reset(); + } + + TUniquePtr Reconstructor; +}; + +IMPLEMENT_MODULE(FDummyMeshReconstructorModule, DummyMeshReconstructor); \ No newline at end of file diff --git a/Engine/Plugins/Runtime/MeshReconstruction/DummyMeshReconstructor/Source/DummyMeshReconstructor/Public/DummyMeshReconstructorModule.h b/Engine/Plugins/Runtime/MeshReconstruction/DummyMeshReconstructor/Source/DummyMeshReconstructor/Public/DummyMeshReconstructorModule.h new file mode 100644 index 000000000000..bbf995367ba0 --- /dev/null +++ b/Engine/Plugins/Runtime/MeshReconstruction/DummyMeshReconstructor/Source/DummyMeshReconstructor/Public/DummyMeshReconstructorModule.h @@ -0,0 +1,8 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" + + +// We aren't defining any new APIs. Just implementing. So keep this file empty if possible. \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Nvidia/Ansel/Source/Ansel/Private/Ansel.cpp b/Engine/Plugins/Runtime/Nvidia/Ansel/Source/Ansel/Private/Ansel.cpp index fbc1abcb07a8..bff1acded9ac 100644 --- a/Engine/Plugins/Runtime/Nvidia/Ansel/Source/Ansel/Private/Ansel.cpp +++ b/Engine/Plugins/Runtime/Nvidia/Ansel/Source/Ansel/Private/Ansel.cpp @@ -564,8 +564,7 @@ private: { TSharedPtr Photography = nullptr; - FNVAnselCameraPhotographyPrivate* PhotographyPrivate = nullptr; - PhotographyPrivate = new FNVAnselCameraPhotographyPrivate(); + FNVAnselCameraPhotographyPrivate* PhotographyPrivate = new FNVAnselCameraPhotographyPrivate(); if (PhotographyPrivate->IsSupported()) { Photography = TSharedPtr(PhotographyPrivate); diff --git a/Engine/Plugins/Runtime/OculusInput/OculusInput.uplugin b/Engine/Plugins/Runtime/OculusInput/OculusInput.uplugin index 587be427330b..95a9701a0144 100644 --- a/Engine/Plugins/Runtime/OculusInput/OculusInput.uplugin +++ b/Engine/Plugins/Runtime/OculusInput/OculusInput.uplugin @@ -17,5 +17,13 @@ "Type" : "Runtime", "WhitelistPlatforms" : [ "Win64", "Win32" ] } + ], + + "Plugins": + [ + { + "Name": "OculusRift", + "Enabled": true + } ] } diff --git a/Engine/Plugins/Runtime/OculusInput/Source/Private/OculusInput.cpp b/Engine/Plugins/Runtime/OculusInput/Source/Private/OculusInput.cpp index 7594fb97524b..67964303155c 100644 --- a/Engine/Plugins/Runtime/OculusInput/Source/Private/OculusInput.cpp +++ b/Engine/Plugins/Runtime/OculusInput/Source/Private/OculusInput.cpp @@ -10,6 +10,8 @@ #if OCULUS_INPUT_SUPPORTED_PLATFORMS +DEFINE_LOG_CATEGORY(LogOcInput); + #define OVR_TESTING 0 #define OVR_DEBUG_LOGGING 0 diff --git a/Engine/Plugins/Runtime/OculusInput/Source/Private/OculusInput.h b/Engine/Plugins/Runtime/OculusInput/Source/Private/OculusInput.h index fedcd49a4e06..a9cee37ea175 100644 --- a/Engine/Plugins/Runtime/OculusInput/Source/Private/OculusInput.h +++ b/Engine/Plugins/Runtime/OculusInput/Source/Private/OculusInput.h @@ -111,6 +111,6 @@ private: ovrTouchHapticsDesc HapticsDesc; }; -DEFINE_LOG_CATEGORY_STATIC(LogOcInput, Log, All); +DECLARE_LOG_CATEGORY_EXTERN(LogOcInput, Log, All); #endif //OCULUS_INPUT_SUPPORTED_PLATFORMS diff --git a/Engine/Plugins/Runtime/OculusLibrary/OculusLibrary.uplugin b/Engine/Plugins/Runtime/OculusLibrary/OculusLibrary.uplugin index c265dee9e9c3..142bcb071562 100644 --- a/Engine/Plugins/Runtime/OculusLibrary/OculusLibrary.uplugin +++ b/Engine/Plugins/Runtime/OculusLibrary/OculusLibrary.uplugin @@ -27,5 +27,13 @@ "Android" ] } + ], + + "Plugins": + [ + { + "Name": "OculusRift", + "Enabled": true + } ] } \ No newline at end of file diff --git a/Engine/Plugins/Runtime/OculusRift/Source/OculusRift/Private/OculusRiftHMD.cpp b/Engine/Plugins/Runtime/OculusRift/Source/OculusRift/Private/OculusRiftHMD.cpp index cc55cf6a492f..9141c4d3a7cb 100644 --- a/Engine/Plugins/Runtime/OculusRift/Source/OculusRift/Private/OculusRiftHMD.cpp +++ b/Engine/Plugins/Runtime/OculusRift/Source/OculusRift/Private/OculusRiftHMD.cpp @@ -1721,7 +1721,7 @@ void FOculusRiftHMD::UpdateStereoRenderingParams() FSettings* CurrentSettings = GetSettings(); - if ((!CurrentSettings->IsStereoEnabled() && !CurrentSettings->Flags.bHeadTrackingEnforced)) + if (!CurrentSettings->IsStereoEnabled() && !CurrentSettings->Flags.bHeadTrackingEnforced) { return; } diff --git a/Engine/Plugins/Runtime/OculusRift/Source/OculusRift/Private/OculusRiftHMD.h b/Engine/Plugins/Runtime/OculusRift/Source/OculusRift/Private/OculusRiftHMD.h index e64654c11eba..74dfda564cc5 100644 --- a/Engine/Plugins/Runtime/OculusRift/Source/OculusRift/Private/OculusRiftHMD.h +++ b/Engine/Plugins/Runtime/OculusRift/Source/OculusRift/Private/OculusRiftHMD.h @@ -445,7 +445,7 @@ private: FAutoConsoleCommand CubemapCommand; #endif // !UE_BUILD_SHIPPING // Exec handler that aliases old deprecated Oculus Rift console commands to the new ones. - virtual bool Exec(class UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) override; + virtual bool Exec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) override; }; diff --git a/Engine/Plugins/Runtime/OculusRift/Source/OculusRift/Private/OculusRiftHMDConfig.cpp b/Engine/Plugins/Runtime/OculusRift/Source/OculusRift/Private/OculusRiftHMDConfig.cpp index 8d7d3510ac27..e9a21782de06 100644 --- a/Engine/Plugins/Runtime/OculusRift/Source/OculusRift/Private/OculusRiftHMDConfig.cpp +++ b/Engine/Plugins/Runtime/OculusRift/Source/OculusRift/Private/OculusRiftHMDConfig.cpp @@ -4,7 +4,7 @@ #include "OculusRiftHMD.h" #if !UE_BUILD_SHIPPING #include "SceneCubemapCapturer.h" -static void CubemapCommandHandler(const TArray&, UWorld*, FOutputDevice&); +static void CubemapCommandHandler(const TArray& Args, UWorld* World, FOutputDevice& Ar); #endif @@ -24,6 +24,7 @@ static void CubemapCommandHandler(const TArray&, UWorld*, FOutputDevice }\ Ar.Logf(ConsoleName TEXT(" = %s"), (FieldExpr) ? TEXT("On") : TEXT("Off")); +/// @cond DOXYGEN_WARNINGS FOculusRiftConsoleCommands::FOculusRiftConsoleCommands(class FOculusRiftHMD* InHMDPtr) : PixelDensityCommand(TEXT("vr.oculus.PixelDensity"), @@ -71,6 +72,8 @@ FOculusRiftConsoleCommands::FOculusRiftConsoleCommands(class FOculusRiftHMD* InH { } +/// @endcond + // Translate between legacy mirror mode values to the new ones static EMirrorWindowMode TranslateMirrorMode(int32 ObsoleteMode) { @@ -91,6 +94,8 @@ static EMirrorWindowMode TranslateMirrorMode(int32 ObsoleteMode) } } +/// @cond DOXYGEN_WARNINGS + /** Clutch to support setting the r.ScreenPercentage and make the equivalent change to PixelDensity @@ -283,6 +288,8 @@ void FOculusRiftHMD::GridCommandHandler(const TArray& Args, UWorld*, FO BOOLEAN_COMMAND_HANDLER_BODY(TEXT("vr.oculus.Debug.bDrawGrid"), Settings->Flags.bDrawGrid) } +/// @endcond + const uint32 CaptureHeight = 2048; static void CubemapCommandHandler(const TArray& Args, UWorld* World, FOutputDevice& Ar) { @@ -314,6 +321,8 @@ static void CubemapCommandHandler(const TArray& Args, UWorld* World, FO CubemapCapturer->StartCapture(World, bCreateGearVRCubemap ? CaptureHeight / 2 : CaptureHeight); } +/// @cond DOXYGEN_WARNINGS + void FOculusRiftHMD::EnforceHeadTrackingCommandHandler(const TArray& Args, UWorld* World, FOutputDevice& Ar) { bool bOldValue = Settings->Flags.bHeadTrackingEnforced; @@ -569,4 +578,6 @@ void FOculusRiftHMD::SaveToIni() #endif // #if !UE_BUILD_SHIPPING } +/// @endcond + #endif diff --git a/Engine/Plugins/Runtime/OculusRift/Source/OculusRift/Private/OculusRiftRender.cpp b/Engine/Plugins/Runtime/OculusRift/Source/OculusRift/Private/OculusRiftRender.cpp index aecaf9fee8cf..a3d9f47ccc5a 100644 --- a/Engine/Plugins/Runtime/OculusRift/Source/OculusRift/Private/OculusRiftRender.cpp +++ b/Engine/Plugins/Runtime/OculusRift/Source/OculusRift/Private/OculusRiftRender.cpp @@ -64,7 +64,7 @@ void FViewExtension::PreRenderViewFamily_RenderThread(FRHICommandListImmediate& RHICmdList.SetViewport(GapMinX, 0, 0, GapMaxX, ViewportSizeY, 1.0f); SetRenderTarget(RHICmdList, ViewFamily.RenderTarget->GetRenderTargetTexture(), FTextureRHIRef()); - DrawClearQuad(RHICmdList, GMaxRHIFeatureLevel, FLinearColor::Black); + DrawClearQuad(RHICmdList, FLinearColor::Black); } check(ViewFamily.RenderTarget->GetRenderTargetTexture()); @@ -249,7 +249,7 @@ void FCustomPresent::CopyTexture_RenderThread(FRHICommandListImmediate& RHICmdLi if (bNoAlphaWrite) { // for quads, write RGB, RGB = src.rgb * 1 + dst.rgb * 0 - DrawClearQuad(RHICmdList, GMaxRHIFeatureLevel, FLinearColor(0.0f, 0.0f, 0.0f, 1.0f)); + DrawClearQuad(RHICmdList, FLinearColor(0.0f, 0.0f, 0.0f, 1.0f)); GraphicsPSOInit.BlendState = TStaticBlendState::GetRHI(); } else @@ -262,7 +262,7 @@ void FCustomPresent::CopyTexture_RenderThread(FRHICommandListImmediate& RHICmdLi { if (bNoAlphaWrite) { - DrawClearQuad(RHICmdList, GMaxRHIFeatureLevel, FLinearColor(1.0f, 1.0f, 1.0f, 1.0f)); + DrawClearQuad(RHICmdList, FLinearColor(1.0f, 1.0f, 1.0f, 1.0f)); GraphicsPSOInit.BlendState = TStaticBlendState::GetRHI(); } else @@ -405,7 +405,7 @@ void FOculusRiftHMD::RenderTexture_RenderThread(class FRHICommandListImmediate& if( DstViewRect != BackBufferRect ) { SetRenderTarget(RHICmdList, BackBuffer, FTextureRHIRef()); - DrawClearQuad(RHICmdList, GMaxRHIFeatureLevel, true, FLinearColor(0.0f, 0.0f, 0.0f, 1.0f), false, 0, false, 0, BackBufferRect.Max, DstViewRect); + DrawClearQuad(RHICmdList, true, FLinearColor(0.0f, 0.0f, 0.0f, 1.0f), false, 0, false, 0, BackBufferRect.Max, DstViewRect); } pCustomPresent->CopyTexture_RenderThread(RHICmdList, BackBuffer, SrcTexture, SrcTexture->GetTexture2D()->GetSizeX(), SrcTexture->GetTexture2D()->GetSizeY(), DstViewRect, SrcViewRect, false, false); diff --git a/Engine/Plugins/Runtime/OculusRift/Source/OculusRift/Private/OculusRiftRenderD3D.cpp b/Engine/Plugins/Runtime/OculusRift/Source/OculusRift/Private/OculusRiftRenderD3D.cpp index fa074ee44e6f..951f4abe3d7a 100644 --- a/Engine/Plugins/Runtime/OculusRift/Source/OculusRift/Private/OculusRiftRenderD3D.cpp +++ b/Engine/Plugins/Runtime/OculusRift/Source/OculusRift/Private/OculusRiftRenderD3D.cpp @@ -248,6 +248,7 @@ FD3D11Texture2DSet* FD3D11Texture2DSet::D3D11CreateTexture2DSet( ovrResult res = ovr_GetTextureSwapChainBufferDX(OvrSession, InTextureSet, i, IID_PPV_ARGS(pD3DTexture.GetInitReference())); if (!OVR_SUCCESS(res)) { + delete NewTextureSet; UE_LOG(LogHMD, Error, TEXT("ovr_GetTextureSwapChainBufferDX failed, error = %d"), int(res)); return nullptr; } diff --git a/Engine/Plugins/Runtime/OculusRift/Source/OculusRift/Private/OculusRiftRenderD3D12.cpp b/Engine/Plugins/Runtime/OculusRift/Source/OculusRift/Private/OculusRiftRenderD3D12.cpp index eaf401ac9906..8fbf39f03b06 100644 --- a/Engine/Plugins/Runtime/OculusRift/Source/OculusRift/Private/OculusRiftRenderD3D12.cpp +++ b/Engine/Plugins/Runtime/OculusRift/Source/OculusRift/Private/OculusRiftRenderD3D12.cpp @@ -115,11 +115,7 @@ FOculusRiftHMD::D3D12Bridge::D3D12Bridge(const FOvrSessionSharedPtr& InOvrSessio check(IsInGameThread()); // Disable RHI thread - if(GRHISupportsRHIThread && GIsThreadedRendering && GUseRHIThread) - { - FSuspendRenderingThread SuspendRenderingThread(true); - GUseRHIThread = false; - } + SetRHIThreadEnabled(false, false); } bool FOculusRiftHMD::D3D12Bridge::IsUsingGraphicsAdapter(const ovrGraphicsLuid& luid) diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononBlueprintFunctionLibrary.cpp b/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononBlueprintFunctionLibrary.cpp deleted file mode 100644 index 7a9017e5db73..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononBlueprintFunctionLibrary.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// -// Copyright (C) Impulsonic, Inc. All rights reserved. -// - -#include "PhononBlueprintFunctionLibrary.h" - -#include "PhononModule.h" - -UPhononBlueprintFunctionLibrary::UPhononBlueprintFunctionLibrary(const FObjectInitializer& ObjectInitializer) - : Super(ObjectInitializer) -{ -} - -void UPhononBlueprintFunctionLibrary::SetPhononDirectSpatializationMethod(EIplSpatializationMethod DirectSpatializationMethod) -{ -} - -void UPhononBlueprintFunctionLibrary::SetPhononDirectHrtfInterpolationMethod(EIplHrtfInterpolationMethod DirectHrtfInterpolationMethod) -{ -} - -void UPhononBlueprintFunctionLibrary::SetPhononDirectOcclusionMethod(EIplDirectOcclusionMethod DirectOcclusionMethod) -{ -} - -void UPhononBlueprintFunctionLibrary::SetPhononDirectOcclusionSourceRadius(float DirectOcclusionSourceRadius) -{ -} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononBlueprintFunctionLibrary.h b/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononBlueprintFunctionLibrary.h deleted file mode 100644 index cdfd38c2b0ff..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononBlueprintFunctionLibrary.h +++ /dev/null @@ -1,29 +0,0 @@ -// -// Copyright (C) Impulsonic, Inc. All rights reserved. -// - -#pragma once - -#include "PhononCommon.h" -#include "Kismet/BlueprintFunctionLibrary.h" -#include "PhononBlueprintFunctionLibrary.generated.h" - -UCLASS() -class UPhononBlueprintFunctionLibrary : public UBlueprintFunctionLibrary -{ - GENERATED_UCLASS_BODY() - -public: - - UFUNCTION(BlueprintCallable, Category = "Audio") - static void SetPhononDirectSpatializationMethod(EIplSpatializationMethod DirectSpatializationMethod); - - UFUNCTION(BlueprintCallable, Category = "Audio") - static void SetPhononDirectHrtfInterpolationMethod(EIplHrtfInterpolationMethod DirectHrtfInterpolationMethod); - - UFUNCTION(BlueprintCallable, Category = "Audio") - static void SetPhononDirectOcclusionMethod(EIplDirectOcclusionMethod DirectOcclusionMethod); - - UFUNCTION(BlueprintCallable, Category = "Audio") - static void SetPhononDirectOcclusionSourceRadius(float DirectOcclusionSourceRadius); -}; diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononGeometryComponent.cpp b/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononGeometryComponent.cpp deleted file mode 100644 index 67273709f578..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononGeometryComponent.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// -// Copyright (C) Impulsonic, Inc. All rights reserved. -// - -#include "PhononGeometryComponent.h" diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononGeometryComponent.h b/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononGeometryComponent.h deleted file mode 100644 index ccfd36f4f596..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononGeometryComponent.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// Copyright (C) Impulsonic, Inc. All rights reserved. -// - -#pragma once - -#include "Components/ActorComponent.h" -#include "PhononGeometryComponent.generated.h" - -/** - * Phonon Geometry components are used to tag an actor as containing geometry relevant to acoustics calculations. - * Usually placed on StaticMesh or Landscape actors. - */ -UCLASS(ClassGroup = (Audio), HideCategories = (Activation, Collision), meta = (BlueprintSpawnableComponent)) -class UPhononGeometryComponent : public UActorComponent -{ - GENERATED_BODY() -}; \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononModule.cpp b/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononModule.cpp deleted file mode 100644 index c7ae0c6bfe36..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononModule.cpp +++ /dev/null @@ -1,294 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#include "PhononModule.h" - -#include "PhononCommon.h" -#include "PhononSpatialization.h" -#include "PhononOcclusion.h" -#include "PhononReverb.h" -#include "PhononScene.h" -#include "PhononSettings.h" -#include "PhononProbeVolume.h" -#include "PhononListenerComponent.h" - -#include "CoreMinimal.h" -#include "Stats/Stats.h" -#include "Modules/ModuleInterface.h" -#include "Modules/ModuleManager.h" -#include "Misc/Paths.h" -#include "HAL/PlatformProcess.h" -#include "Classes/Kismet/GameplayStatics.h" -#include "IPluginManager.h" -#include "EngineUtils.h" -#include "Regex.h" - -IMPLEMENT_MODULE(FPhononModule, FPhonon) - -void* FPhononModule::PhononDllHandle = nullptr; - -static bool bModuleStartedUp = false; - -FPhononModule::FPhononModule() - : SpatializationInstance(nullptr) - , OcclusionInstance(nullptr) - , ReverbInstance(nullptr) - , ListenerObserverInstance(nullptr) - , SampleRate(0.0f) - , OwningAudioDevice(nullptr) - , ComputeDevice(nullptr) - , PhononScene(nullptr) - , PhononEnvironment(nullptr) - , EnvironmentalRenderer(nullptr) - , ProbeManager(nullptr) - , BinauralRenderer(nullptr) -{ - -} - -FPhononModule::~FPhononModule() -{ - check(!ComputeDevice); - check(!PhononScene); - check(!PhononEnvironment); - check(!EnvironmentalRenderer); - check(!ProbeManager); - check(!BinauralRenderer); -} - -void FPhononModule::StartupModule() -{ - check(bModuleStartedUp == false); - - bModuleStartedUp = true; - - UE_LOG(LogPhonon, Log, TEXT("FPhononModule Startup")); - OwningAudioDevice = nullptr; - - SpatializationInstance = nullptr; - OcclusionInstance = nullptr; - ReverbInstance = nullptr; - ComputeDevice = nullptr; - PhononScene = nullptr; - PhononEnvironment = nullptr; - EnvironmentalRenderer = nullptr; - ProbeManager = nullptr; - BinauralRenderer = nullptr; - SampleRate = 0; - - // We're overriding the IAudioSpatializationPlugin StartupModule, so we must be sure to register - // the modular features. Without this line, we will not see SPATIALIZATION HRTF in the editor UI. - IModularFeatures::Get().RegisterModularFeature(GetModularFeatureName(), this); - - if (!FPhononModule::PhononDllHandle) - { - // TODO: do platform code to get the DLL location for the platform - FString PathToDll = FPaths::EngineDir() / TEXT("Binaries/ThirdParty/Phonon/Win64/"); - - - FString DLLToLoad = PathToDll + TEXT("phonon.dll"); - FPhononModule::PhononDllHandle = Phonon::LoadDll(DLLToLoad); - } - - iplCreateBinauralRenderer(Phonon::GlobalContext, RenderingSettings, nullptr, &BinauralRenderer); -} - -void FPhononModule::ShutdownModule() -{ - UE_LOG(LogPhonon, Log, TEXT("FPhononModule Shutdown")); - - check(bModuleStartedUp == true); - - bModuleStartedUp = false; - - if (BinauralRenderer) - { - iplDestroyBinauralRenderer(&BinauralRenderer); - } - - if (FPhononModule::PhononDllHandle) - { - FPlatformProcess::FreeDllHandle(FPhononModule::PhononDllHandle); - FPhononModule::PhononDllHandle = nullptr; - } -} - -void FPhononModule::CreateEnvironment(UWorld* World, FAudioDevice* InAudioDevice) -{ - UE_LOG(LogPhonon, Log, TEXT("Creating Phonon environment...")); - - check(OwningAudioDevice == nullptr); - OwningAudioDevice = InAudioDevice; - - int32 IndirectImpulseResponseOrder = GetDefault()->IndirectImpulseResponseOrder; - int32 IndirectImpulseResponseDuration = GetDefault()->IndirectImpulseResponseDuration; - - SimulationSettings.maxConvolutionSources = 64; - SimulationSettings.numBounces = GetDefault()->RealtimeBounces; - SimulationSettings.numDiffuseSamples = GetDefault()->RealtimeSecondaryRays; - SimulationSettings.numRays = GetDefault()->RealtimeRays; - SimulationSettings.ambisonicsOrder = IndirectImpulseResponseOrder; - SimulationSettings.irDuration = IndirectImpulseResponseDuration; - SimulationSettings.sceneType = IPL_SCENETYPE_PHONON; - - RenderingSettings.convolutionType = IPL_CONVOLUTIONTYPE_PHONON; - RenderingSettings.frameSize = 1024; // FIXME - RenderingSettings.samplingRate = AUDIO_SAMPLE_RATE; // FIXME - - EnvironmentalOutputAudioFormat.channelLayout = IPL_CHANNELLAYOUT_STEREO; - EnvironmentalOutputAudioFormat.channelLayoutType = IPL_CHANNELLAYOUTTYPE_AMBISONICS; - EnvironmentalOutputAudioFormat.channelOrder = IPL_CHANNELORDER_DEINTERLEAVED; - EnvironmentalOutputAudioFormat.numSpeakers = (IndirectImpulseResponseOrder + 1) * (IndirectImpulseResponseOrder + 1); - EnvironmentalOutputAudioFormat.speakerDirections = nullptr; - EnvironmentalOutputAudioFormat.ambisonicsOrder = IndirectImpulseResponseOrder; - EnvironmentalOutputAudioFormat.ambisonicsNormalization = IPL_AMBISONICSNORMALIZATION_N3D; - EnvironmentalOutputAudioFormat.ambisonicsOrdering = IPL_AMBISONICSORDERING_ACN; - - if (World) - { - FString MapName = World->GetMapName(); - - // Strip out the PIE prefix for the map name before looking for the phononscene. - const FRegexPattern PieMapPattern(TEXT("UEDPIE_\\d_")); - FRegexMatcher Matcher(PieMapPattern, MapName); - - // Look for the PIE pattern - if (Matcher.FindNext()) - { - int32 Beginning = Matcher.GetMatchBeginning(); - int32 Ending = Matcher.GetMatchEnding(); - MapName = MapName.Mid(Ending, MapName.Len()); - } - - FString SceneFile = FPaths::GameDir() + "Content/" + MapName + ".phononscene"; - - if (FPaths::FileExists(SceneFile)) - { - IPLerror Error = IPLerror::IPL_STATUS_SUCCESS; - - Error = iplLoadFinalizedScene(Phonon::GlobalContext, SimulationSettings, TCHAR_TO_ANSI(*SceneFile), ComputeDevice, nullptr, &PhononScene); - Phonon::LogPhononStatus(Error); - - Error = iplCreateProbeManager(&ProbeManager); - Phonon::LogPhononStatus(Error); - - TArray PhononProbeVolumes; - UGameplayStatics::GetAllActorsOfClass(World, APhononProbeVolume::StaticClass(), PhononProbeVolumes); - - for (AActor* PhononProbeVolumeActor : PhononProbeVolumes) - { - APhononProbeVolume* PhononProbeVolume = Cast(PhononProbeVolumeActor); - IPLhandle ProbeBatch = nullptr; - Error = iplLoadProbeBatch(PhononProbeVolume->GetProbeBatchData(), PhononProbeVolume->GetProbeBatchDataSize(), &ProbeBatch); - Phonon::LogPhononStatus(Error); - - iplAddProbeBatch(ProbeManager, ProbeBatch); - - ProbeBatches.Add(ProbeBatch); - } - - Error = iplCreateEnvironment(Phonon::GlobalContext, ComputeDevice, SimulationSettings, PhononScene, ProbeManager, &PhononEnvironment); - Phonon::LogPhononStatus(Error); - - Error = iplCreateEnvironmentalRenderer(Phonon::GlobalContext, PhononEnvironment, RenderingSettings, EnvironmentalOutputAudioFormat, &EnvironmentalRenderer); - Phonon::LogPhononStatus(Error); - - Phonon::FPhononOcclusion* PhononOcclusion = static_cast(OcclusionInstance.Get()); - PhononOcclusion->SetEnvironmentalRenderer(EnvironmentalRenderer); - - Phonon::FPhononReverb* PhononReverb = static_cast(ReverbInstance.Get()); - PhononReverb->SetEnvironmentalRenderer(EnvironmentalRenderer); - } - else - { - UE_LOG(LogPhonon, Log, TEXT("Unable to load scene: %s not found."), *SceneFile); - } - } - else - { - UE_LOG(LogPhonon, Log, TEXT("Unable to load scene: null World.")); - } -} - -void FPhononModule::DestroyEnvironment(FAudioDevice* InAudioDevice) -{ - check(OwningAudioDevice == InAudioDevice); - - OwningAudioDevice = nullptr; - - if (ProbeManager) - { - for (IPLhandle ProbeBatch : ProbeBatches) - { - iplRemoveProbeBatch(ProbeManager, ProbeBatch); - iplDestroyProbeBatch(&ProbeBatch); - } - - iplDestroyProbeManager(&ProbeManager); - } - - if (EnvironmentalRenderer) - { - iplDestroyEnvironmentalRenderer(&EnvironmentalRenderer); - } - - if (PhononEnvironment) - { - iplDestroyEnvironment(&PhononEnvironment); - } - - if (PhononScene) - { - iplDestroyScene(&PhononScene); - } - - if (ComputeDevice) - { - iplDestroyComputeDevice(&ComputeDevice); - } -} - -void FPhononModule::SetSampleRate(const int32 InSampleRate) -{ - SampleRate = InSampleRate; -} - -TSharedPtr FPhononModule::CreateSpatializationInterface(class FAudioDevice* AudioDevice) -{ - return SpatializationInstance = TSharedPtr(new Phonon::FPhononSpatialization()); -} - -TSharedPtr FPhononModule::CreateOcclusionInterface(class FAudioDevice* AudioDevice) -{ - return OcclusionInstance = TSharedPtr(new Phonon::FPhononOcclusion()); -} - -TSharedPtr FPhononModule::CreateReverbInterface(class FAudioDevice* AudioDevice) -{ - return ReverbInstance = TSharedPtr(new Phonon::FPhononReverb()); -} - -TSharedPtr FPhononModule::CreateListenerObserverInterface(class FAudioDevice* AudioDevice) -{ - return ListenerObserverInstance = TSharedPtr(new Phonon::FPhononListenerObserver()); -} - -Phonon::FPhononSpatialization* FPhononModule::GetSpatializationInstance() const -{ - return static_cast(SpatializationInstance.Get()); -} - -Phonon::FPhononOcclusion* FPhononModule::GetOcclusionInstance() const -{ - return static_cast(OcclusionInstance.Get()); -} - -Phonon::FPhononReverb* FPhononModule::GetReverbInstance() const -{ - return static_cast(ReverbInstance.Get()); -} - -Phonon::FPhononListenerObserver* FPhononModule::GetListenerObserverInstance() const -{ - return static_cast(ListenerObserverInstance.Get()); -} - diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononModule.h b/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononModule.h deleted file mode 100644 index f78a87ed59d5..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononModule.h +++ /dev/null @@ -1,73 +0,0 @@ -// -// Copyright (C) Impulsonic, Inc. All rights reserved. -// - -#pragma once - -#include "IPhononModule.h" -#include -#include "phonon.h" - -namespace Phonon -{ - class FPhononSpatialization; - class FPhononOcclusion; - class FPhononReverb; - class FPhononListenerObserver; -} - -class FPhononModule : public IPhononModule -{ -public: - FPhononModule(); - ~FPhononModule(); - - virtual void StartupModule() override; - virtual void ShutdownModule() override; - - virtual TSharedPtr CreateSpatializationInterface(class FAudioDevice* AudioDevice) override; - virtual TSharedPtr CreateOcclusionInterface(class FAudioDevice* AudioDevice) override; - virtual TSharedPtr CreateReverbInterface(class FAudioDevice* AudioDevice) override; - virtual TSharedPtr CreateListenerObserverInterface(class FAudioDevice* AudioDevice) override; - - void CreateEnvironment(UWorld* World, FAudioDevice* InAudioDevice); - void DestroyEnvironment(FAudioDevice* InAudioDevice); - - void SetSampleRate(const int32 SampleRate); - - virtual bool SupportsMultipleAudioDevices() const { return false; } - virtual bool ImplementsSpatialization() const { return true; } - virtual bool ImplementsOcclusion() const { return true; } - virtual bool ImplementsReverb() const { return true; } - - Phonon::FPhononSpatialization* GetSpatializationInstance() const; - Phonon::FPhononOcclusion* GetOcclusionInstance() const; - Phonon::FPhononReverb* GetReverbInstance() const; - Phonon::FPhononListenerObserver* GetListenerObserverInstance() const; - -private: - - TSharedPtr SpatializationInstance; - TSharedPtr OcclusionInstance; - TSharedPtr ReverbInstance; - TSharedPtr ListenerObserverInstance; - - int32 SampleRate; - - FAudioDevice* OwningAudioDevice; - - IPLhandle ComputeDevice; - IPLhandle PhononScene; - IPLhandle PhononEnvironment; - IPLhandle EnvironmentalRenderer; - IPLhandle ProbeManager; - IPLhandle BinauralRenderer; - TArray ProbeBatches; - IPLSimulationSettings SimulationSettings; - IPLRenderingSettings RenderingSettings; - - IPLAudioFormat EnvironmentalOutputAudioFormat; - - // TODO: make this an instance var - static void* PhononDllHandle; -}; \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononOcclusion.cpp b/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononOcclusion.cpp deleted file mode 100644 index f66cf86fdaf7..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononOcclusion.cpp +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#include "PhononOcclusion.h" -#include "PhononOcclusionSourceSettings.h" -#include "PhononCommon.h" -#include "ScopeLock.h" -#include "PhononModule.h" - -namespace Phonon -{ - FPhononOcclusion::FPhononOcclusion() - : EnvironmentalRenderer(nullptr) - { - } - - FPhononOcclusion::~FPhononOcclusion() - { - } - - void FPhononOcclusion::Initialize(int32 SampleRate, int32 NumSources) - { - DirectSoundSources.SetNum(NumSources); - - FPhononModule& PhononModule = FModuleManager::GetModuleChecked("Phonon"); - PhononModule.SetSampleRate(SampleRate); - } - - void FPhononOcclusion::SetOcclusionSettings(uint32 SourceId, UOcclusionPluginSourceSettingsBase* InSettings) - { - UPhononOcclusionSourceSettings* OcclusionSettings = CastChecked(InSettings); - DirectAttenuation = OcclusionSettings->DirectAttenuation; - DirectOcclusionMethod = OcclusionSettings->DirectOcclusionMethod; - DirectOcclusionSourceRadius = OcclusionSettings->DirectOcclusionSourceRadius; - } - - void FPhononOcclusion::ProcessAudio(const FAudioPluginSourceInputData& InputData, FAudioPluginSourceOutputData& OutputData) - { - IPLDirectSoundPath DirectSoundPath; - - { - FScopeLock Lock(&DirectSoundSources[InputData.SourceId].CriticalSection); - DirectSoundPath = DirectSoundSources[InputData.SourceId].DirectSoundPath; - DirectSoundSources[InputData.SourceId].Position = Phonon::UnrealToPhononIPLVector3(InputData.SpatializationParams->EmitterWorldPosition); - DirectSoundSources[InputData.SourceId].bNeedsUpdate = true; - } - - float ConfiguredOcclusionFactor = DirectOcclusionMethod == EIplDirectOcclusionMethod::NONE ? 1.0f : DirectSoundPath.occlusionFactor; - float ConfiguredAttenuationFactor = DirectAttenuation ? DirectSoundPath.distanceAttenuation : 1.0f; - - for (int32 i = 0; i < InputData.AudioBuffer->Num(); ++i) - { - OutputData.AudioBuffer[i] = (*InputData.AudioBuffer)[i] * ConfiguredOcclusionFactor * ConfiguredAttenuationFactor; - } - } - - void FPhononOcclusion::UpdateDirectSoundSources(const FVector& ListenerPosition, const FVector& ListenerForward, const FVector& ListenerUp) - { - if (!EnvironmentalRenderer) - { - return; - } - - for (DirectSoundSource& DirectSoundSourceInstance : DirectSoundSources) - { - FScopeLock Lock(&DirectSoundSourceInstance.CriticalSection); - - if (DirectSoundSourceInstance.bNeedsUpdate) - { - IPLDirectSoundPath DirectSoundPath = iplGetDirectSoundPath(EnvironmentalRenderer, Phonon::UnrealToPhononIPLVector3(ListenerPosition), - Phonon::UnrealToPhononIPLVector3(ListenerForward, false), Phonon::UnrealToPhononIPLVector3(ListenerUp, false), - DirectSoundSourceInstance.Position, DirectOcclusionSourceRadius, (IPLDirectOcclusionMethod)DirectOcclusionMethod); - - DirectSoundSourceInstance.DirectSoundPath = DirectSoundPath; - DirectSoundSourceInstance.bNeedsUpdate = false; - } - } - } -} - diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononOcclusion.h b/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononOcclusion.h deleted file mode 100644 index e96e0533a476..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononOcclusion.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "IAudioExtensionPlugin.h" -#include "PhononOcclusionSourceSettings.h" -#include "phonon.h" -#include - -namespace Phonon -{ - struct DirectSoundSource - { - DirectSoundSource() - : bNeedsUpdate(false) - { - DirectSoundPath.occlusionFactor = 1.0f; - DirectSoundPath.distanceAttenuation = 1.0f; - Position.x = Position.y = Position.z = 0.0f; - } - - FCriticalSection CriticalSection; - IPLDirectSoundPath DirectSoundPath; - IPLVector3 Position; - bool bNeedsUpdate; - }; - - class FPhononOcclusion : public IAudioOcclusion - { - public: - FPhononOcclusion(); - ~FPhononOcclusion(); - - virtual void Initialize(int32 SampleRate, int32 NumSources) override; - virtual void SetOcclusionSettings(uint32 VoiceId, UOcclusionPluginSourceSettingsBase* InSettings) override; - virtual void ProcessAudio(const FAudioPluginSourceInputData& InputData, FAudioPluginSourceOutputData& OutputData) override; - - void UpdateDirectSoundSources(const FVector& ListenerPosition, const FVector& ListenerForward, const FVector& ListenerUp); - - void SetEnvironmentalRenderer(IPLhandle InEnvironmentalRenderer) - { - EnvironmentalRenderer = InEnvironmentalRenderer; - } - - private: - - EIplDirectOcclusionMethod DirectOcclusionMethod; - - float DirectOcclusionSourceRadius; - - bool DirectAttenuation; - - IPLhandle EnvironmentalRenderer; - - TArray DirectSoundSources; - }; -} - diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononProbeComponent.cpp b/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononProbeComponent.cpp deleted file mode 100644 index 22a5e4743d4c..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononProbeComponent.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright (C) Impulsonic, Inc. All rights reserved. -// - -#include "PhononProbeComponent.h" -#include "UObject/ConstructorHelpers.h" -#include "Engine/Texture2D.h" - -UPhononProbeComponent::UPhononProbeComponent() -{ -#if WITH_EDITORONLY_DATA - if (!IsRunningCommandlet()) - { - // Structure to hold one-time initialization - struct FConstructorStatics - { - ConstructorHelpers::FObjectFinderOptional PhononProbeComponentTextureObject; - FName ID_PhononProbeComponent; - FText NAME_PhononProbeComponent; - FConstructorStatics() - : PhononProbeComponentTextureObject(TEXT("/Phonon/S_PhononProbe_64")) - , ID_PhononProbeComponent(TEXT("PhononProbeComponent")) - , NAME_PhononProbeComponent(NSLOCTEXT("SpriteCategory", "PhononProbeComponent", "PhononProbeComponent")) - { - } - }; - static FConstructorStatics ConstructorStatics; - - this->Sprite = ConstructorStatics.PhononProbeComponentTextureObject.Get(); - this->RelativeScale3D = FVector(1.0f, 1.0f, 1.0f); - this->SpriteInfo.Category = ConstructorStatics.ID_PhononProbeComponent; - this->SpriteInfo.DisplayName = ConstructorStatics.NAME_PhononProbeComponent; - } -#endif // WITH_EDITORONLY_DATA -} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononProbeComponent.h b/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononProbeComponent.h deleted file mode 100644 index fea3120e6b5d..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononProbeComponent.h +++ /dev/null @@ -1,22 +0,0 @@ -// -// Copyright (C) Impulsonic, Inc. All rights reserved. -// - -#pragma once - -#include "Components/ActorComponent.h" -#include "Components/BillboardComponent.h" -#include "PhononProbeComponent.generated.h" - -UCLASS(ClassGroup = (Audio), HideCategories = (Activation, Collision)) -class PHONON_API UPhononProbeComponent : public UBillboardComponent -{ - GENERATED_BODY() - -public: - UPhononProbeComponent(); - - // Influence radius defines the volume within which this probe's sample data is used for rendering. - UPROPERTY(EditAnywhere, Category = ProbeSettings, meta = (ClampMin = "0.0", ClampMax = "1024.0", UIMin = "0.0", UIMax = "1024.0")) - float InfluenceRadius; -}; diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononProbeVolume.cpp b/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononProbeVolume.cpp deleted file mode 100644 index 2ed19bfd8f1d..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononProbeVolume.cpp +++ /dev/null @@ -1,129 +0,0 @@ -// -// Copyright (C) Impulsonic, Inc. All rights reserved. -// - -#include "PhononProbeVolume.h" - -#include "PhononProbeComponent.h" -#include "PhononScene.h" -#include "PhononCommon.h" - -#if WITH_EDITOR -#include "Editor.h" -#include "LevelEditorViewport.h" -#endif - -#include - -APhononProbeVolume::APhononProbeVolume(const FObjectInitializer& ObjectInitializer) - : Super(ObjectInitializer) - , HorizontalSpacing(1.0) - , HeightAboveFloor(1.5) -{ -} - -void APhononProbeVolume::GenerateProbes() -{ -#if WITH_EDITOR - - // Clear out old data - ProbeBoxData.Empty(); - ProbeBatchData.Empty(); - - // Load the scene - UWorld* World = GEditor->LevelViewportClients[0]->GetWorld(); - IPLhandle PhononScene = nullptr; - TArray PhononStaticMeshes; - Phonon::LoadScene(World, &PhononScene, &PhononStaticMeshes); - - // Compute bounding box in Phonon coords - IPLhandle ProbeBox = nullptr; - FVector BoxCenter, BoxExtents; - this->Brush->Bounds.GetBox().GetCenterAndExtents(BoxCenter, BoxExtents); - BoxExtents *= this->GetTransform().GetScale3D(); - FVector Center = this->GetTransform().GetLocation(); - IPLVector3 MinExtent = Phonon::UnrealToPhononIPLVector3(Center - BoxExtents); - IPLVector3 MaxExtent = Phonon::UnrealToPhononIPLVector3(Center + BoxExtents); - - if (MinExtent.x > MaxExtent.x) - std::swap(MinExtent.x, MaxExtent.x); - - if (MinExtent.y > MaxExtent.y) - std::swap(MinExtent.y, MaxExtent.y); - - if (MinExtent.z > MaxExtent.z) - std::swap(MinExtent.z, MaxExtent.z); - - IPLBox ProbeBoxExtents; - ProbeBoxExtents.minCoordinates = MinExtent; - ProbeBoxExtents.maxCoordinates = MaxExtent; - - // Configure placement parameters - IPLProbePlacementParams ProbePlacementParameters; - ProbePlacementParameters.placement = PlacementStrategy == EPhononProbePlacementStrategy::CENTROID ? IPL_PLACEMENT_CENTROID : IPL_PLACEMENT_UNIFORMFLOOR; - ProbePlacementParameters.heightAboveFloor = HeightAboveFloor; - ProbePlacementParameters.spacing = HorizontalSpacing; - ProbePlacementParameters.maxOctreeDepth = 0; - ProbePlacementParameters.maxOctreeTriangles = 0; - - // Create probe box, generate probes - iplCreateProbeBox(PhononScene, ProbeBoxExtents, ProbePlacementParameters, nullptr, &ProbeBox); - - // Get probe locations/radii - IPLint32 NumProbes = iplGetProbeSpheres(ProbeBox, nullptr); - TArray ProbeSpheres; - ProbeSpheres.SetNumUninitialized(NumProbes); - iplGetProbeSpheres(ProbeBox, ProbeSpheres.GetData()); - - for (UPhononProbeComponent * PhononProbeComponent : PhononProbeComponents) - { - PhononProbeComponent->UnregisterComponent(); - } - PhononProbeComponents.Empty(); - - IPLhandle ProbeBatch = nullptr; - iplCreateProbeBatch(&ProbeBatch); - - // Spawn probe components - FRotator DefaultRotation(0, 0, 0); - for (IPLint32 i = 0; i < NumProbes; ++i) - { - FVector ProbeLocation = Phonon::PhononToUnrealFVector(Phonon::FVectorFromIPLVector3(ProbeSpheres[i].center)); - UE_LOG(LogPhonon, Log, TEXT("Spawning at location %f %f %f"), ProbeLocation.X, ProbeLocation.Y, ProbeLocation.Z); - - FName ProbeName = FName(*FString::Printf(TEXT("PhononProbeComponent%d"), i)); - UPhononProbeComponent* PhononProbeComponent = NewObject(this, ProbeName); - - PhononProbeComponent->RegisterComponent(); - PhononProbeComponent->SetWorldLocation(ProbeLocation); - PhononProbeComponent->SetWorldRotation(DefaultRotation); - PhononProbeComponent->InfluenceRadius = ProbeSpheres[i].radius; - PhononProbeComponent->AttachToComponent(RootComponent, FAttachmentTransformRules(EAttachmentRule::KeepWorld, false)); - PhononProbeComponents.Add(PhononProbeComponent); - - iplAddProbeToBatch(ProbeBatch, ProbeBox, i); - } - - // Save probe box data - IPLint32 ProbeBoxDataSize = iplSaveProbeBox(ProbeBox, nullptr); - ProbeBoxData.SetNumUninitialized(ProbeBoxDataSize); - iplSaveProbeBox(ProbeBox, ProbeBoxData.GetData()); - - // Save probe batch data - iplFinalizeProbeBatch(ProbeBatch); - IPLint32 ProbeBatchDataSize = iplSaveProbeBatch(ProbeBatch, nullptr); - ProbeBatchData.SetNumUninitialized(ProbeBatchDataSize); - iplSaveProbeBatch(ProbeBatch, ProbeBatchData.GetData()); - - // Clean up - iplDestroyProbeBox(&ProbeBox); - iplDestroyProbeBatch(&ProbeBatch); - - for (IPLhandle PhononStaticMesh : PhononStaticMeshes) - { - iplDestroyStaticMesh(&PhononStaticMesh); - } - iplDestroyScene(&PhononScene); - -#endif -} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononProbeVolume.h b/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononProbeVolume.h deleted file mode 100644 index c9ce7ae943fd..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononProbeVolume.h +++ /dev/null @@ -1,103 +0,0 @@ -// -// Copyright (C) Impulsonic, Inc. All rights reserved. -// - -#pragma once - -#include "PhononCommon.h" -#include "GameFramework/Volume.h" -#include "PhononProbeVolume.generated.h" - -UENUM() -enum class EPhononProbePlacementStrategy : uint8 -{ - CENTROID = 0 UMETA(DisplayName = "Centroid"), - //OCTREE = 1 UMETA(DisplayName = "Octree"), - UNIFORM_FLOOR = 1 UMETA(DisplayName = "Uniform Floor"), -}; - -UENUM() -enum class EPhononProbeMobility : uint8 -{ - // Static probes remain fixed at runtime. - STATIC = 0 UMETA(DisplayName = "Static"), - // Dynamic probes inherit this volume's offset at runtime. - DYNAMIC = 1 UMETA(DisplayName = "Dynamic") -}; - -/** - * Phonon Probe volumes ... - */ -UCLASS(HideCategories = (Actor, Advanced, Attachment, Collision)) -class PHONON_API APhononProbeVolume : public AVolume -{ - GENERATED_UCLASS_BODY() - -public: - - void GenerateProbes(); - - uint8* GetProbeBoxData() - { - return ProbeBoxData.GetData(); - } - - const int32 GetProbeBoxDataSize() const - { - return ProbeBoxData.Num(); - } - - uint8* GetProbeBatchData() - { - return ProbeBatchData.GetData(); - } - - const int32 GetProbeBatchDataSize() const - { - return ProbeBatchData.Num(); - } - - void UpdateProbeBoxData(IPLhandle ProbeBox) - { - // Update probe box serialized data - auto NewProbeBoxDataSize = iplSaveProbeBox(ProbeBox, nullptr); - ProbeBoxData.SetNumUninitialized(NewProbeBoxDataSize); - iplSaveProbeBox(ProbeBox, ProbeBoxData.GetData()); - - // Update probe batch serialized data - IPLhandle ProbeBatch = nullptr; - iplCreateProbeBatch(&ProbeBatch); - - auto NumProbes = iplGetProbeSpheres(ProbeBox, nullptr); - for (auto i = 0; i < NumProbes; ++i) - { - iplAddProbeToBatch(ProbeBatch, ProbeBox, i); - } - - iplFinalizeProbeBatch(ProbeBatch); - auto ProbeBatchDataSize = iplSaveProbeBatch(ProbeBatch, nullptr); - ProbeBatchData.SetNumUninitialized(ProbeBatchDataSize); - iplSaveProbeBatch(ProbeBatch, ProbeBatchData.GetData()); - iplDestroyProbeBatch(&ProbeBatch); - } - - UPROPERTY(EditAnywhere, Category = ProbeGeneration) - EPhononProbePlacementStrategy PlacementStrategy; - - UPROPERTY(EditAnywhere, Category = ProbeGeneration, meta = (ClampMin = "0.0", ClampMax = "1024.0", UIMin = "0.0", UIMax = "1024.0")) - float HorizontalSpacing; - - UPROPERTY(EditAnywhere, Category = ProbeGeneration, meta = (ClampMin = "0.0", ClampMax = "1024.0", UIMin = "0.0", UIMax = "1024.0")) - float HeightAboveFloor; - -private: - - UPROPERTY() - TArray PhononProbeComponents; - - UPROPERTY() - TArray ProbeBoxData; - - UPROPERTY() - TArray ProbeBatchData; -}; \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononScene.h b/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononScene.h deleted file mode 100644 index ed1baf295006..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononScene.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// Copyright (C) Impulsonic, Inc. All rights reserved. -// - -#pragma once - -#include "phonon.h" -#include "CoreMinimal.h" - -namespace Phonon -{ - PHONON_API void LoadScene(class UWorld* World, IPLhandle* PhononScene, TArray* PhononStaticMeshes); -} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononSettings.cpp b/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononSettings.cpp deleted file mode 100644 index ade2edf6a700..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononSettings.cpp +++ /dev/null @@ -1,225 +0,0 @@ -// -// Copyright (C) Impulsonic, Inc. All rights reserved. -// - -#include "PhononSettings.h" - -UPhononSettings::UPhononSettings() - : ExportBSPGeometry(true) - , ExportLandscapeGeometry(true) - , StaticMeshMaterialPreset(EPhononMaterial::GENERIC) - , BSPMaterialPreset(EPhononMaterial::GENERIC) - , LandscapeMaterialPreset(EPhononMaterial::GENERIC) - , IndirectContribution(1.0f) - , IndirectImpulseResponseOrder(1) - , IndirectImpulseResponseDuration(1.0f) - , ReverbSimulationType(EIplSimulationType::DISABLED) - //, EnableMixerOptimization(true) - , RealtimeQualityPreset(EQualitySettings::LOW) - , RealtimeBounces(2) - , RealtimeRays(8192) - , RealtimeSecondaryRays(512) - , BakedQualityPreset(EQualitySettings::LOW) - , BakedBounces(128) - , BakedRays(16384) - , BakedSecondaryRays(2048) -{ - auto MaterialPreset = Phonon::MaterialPresets[StaticMeshMaterialPreset]; - StaticMeshLowFreqAbsorption = MaterialPreset.lowFreqAbsorption; - StaticMeshMidFreqAbsorption = MaterialPreset.midFreqAbsorption; - StaticMeshHighFreqAbsorption = MaterialPreset.highFreqAbsorption; - StaticMeshScattering = MaterialPreset.scattering; - - MaterialPreset = Phonon::MaterialPresets[BSPMaterialPreset]; - BSPLowFreqAbsorption = MaterialPreset.lowFreqAbsorption; - BSPMidFreqAbsorption = MaterialPreset.midFreqAbsorption; - BSPHighFreqAbsorption = MaterialPreset.highFreqAbsorption; - BSPScattering = MaterialPreset.scattering; - - MaterialPreset = Phonon::MaterialPresets[LandscapeMaterialPreset]; - LandscapeLowFreqAbsorption = MaterialPreset.lowFreqAbsorption; - LandscapeMidFreqAbsorption = MaterialPreset.midFreqAbsorption; - LandscapeHighFreqAbsorption = MaterialPreset.highFreqAbsorption; - LandscapeScattering = MaterialPreset.scattering; -} - -IPLMaterial UPhononSettings::GetDefaultStaticMeshMaterial() const -{ - IPLMaterial DAM; - DAM.lowFreqAbsorption = StaticMeshLowFreqAbsorption; - DAM.midFreqAbsorption = StaticMeshMidFreqAbsorption; - DAM.highFreqAbsorption = StaticMeshHighFreqAbsorption; - DAM.scattering = StaticMeshScattering; - - return DAM; -} - -IPLMaterial UPhononSettings::GetDefaultBSPMaterial() const -{ - IPLMaterial DAM; - DAM.lowFreqAbsorption = BSPLowFreqAbsorption; - DAM.midFreqAbsorption = BSPMidFreqAbsorption; - DAM.highFreqAbsorption = BSPHighFreqAbsorption; - DAM.scattering = BSPScattering; - - return DAM; -} - -IPLMaterial UPhononSettings::GetDefaultLandscapeMaterial() const -{ - IPLMaterial DAM; - DAM.lowFreqAbsorption = LandscapeLowFreqAbsorption; - DAM.midFreqAbsorption = LandscapeMidFreqAbsorption; - DAM.highFreqAbsorption = LandscapeHighFreqAbsorption; - DAM.scattering = LandscapeScattering; - - return DAM; -} - -#if WITH_EDITOR -void UPhononSettings::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) -{ - FName PropertyName = (PropertyChangedEvent.Property != nullptr) ? PropertyChangedEvent.Property->GetFName() : NAME_None; - - auto MaterialPreset = Phonon::MaterialPresets[StaticMeshMaterialPreset]; - auto RealtimeSimulationQuality = RealtimeSimulationQualityPresets[RealtimeQualityPreset]; - auto BakedSimulationQuality = BakedSimulationQualityPresets[BakedQualityPreset]; - - if ((PropertyName == GET_MEMBER_NAME_CHECKED(UPhononSettings, StaticMeshMaterialPreset))) - { - StaticMeshLowFreqAbsorption = MaterialPreset.lowFreqAbsorption; - StaticMeshMidFreqAbsorption = MaterialPreset.midFreqAbsorption; - StaticMeshHighFreqAbsorption = MaterialPreset.highFreqAbsorption; - StaticMeshScattering = MaterialPreset.scattering; - - for (TFieldIterator PropIt(GetClass()); PropIt; ++PropIt) - { - UProperty* Property = *PropIt; - if (Property->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, StaticMeshLowFreqAbsorption) || - Property->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, StaticMeshMidFreqAbsorption) || - Property->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, StaticMeshHighFreqAbsorption) || - Property->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, StaticMeshScattering)) - { - UpdateSinglePropertyInConfigFile(Property, GetDefaultConfigFilename()); - } - } - } - else if ((PropertyName == GET_MEMBER_NAME_CHECKED(UPhononSettings, BSPMaterialPreset))) - { - MaterialPreset = Phonon::MaterialPresets[BSPMaterialPreset]; - BSPLowFreqAbsorption = MaterialPreset.lowFreqAbsorption; - BSPMidFreqAbsorption = MaterialPreset.midFreqAbsorption; - BSPHighFreqAbsorption = MaterialPreset.highFreqAbsorption; - BSPScattering = MaterialPreset.scattering; - - for (TFieldIterator PropIt(GetClass()); PropIt; ++PropIt) - { - UProperty* Property = *PropIt; - if (Property->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, BSPLowFreqAbsorption) || - Property->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, BSPMidFreqAbsorption) || - Property->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, BSPHighFreqAbsorption) || - Property->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, BSPScattering)) - { - UpdateSinglePropertyInConfigFile(Property, GetDefaultConfigFilename()); - } - } - } - else if ((PropertyName == GET_MEMBER_NAME_CHECKED(UPhononSettings, LandscapeMaterialPreset))) - { - MaterialPreset = Phonon::MaterialPresets[LandscapeMaterialPreset]; - LandscapeLowFreqAbsorption = MaterialPreset.lowFreqAbsorption; - LandscapeMidFreqAbsorption = MaterialPreset.midFreqAbsorption; - LandscapeHighFreqAbsorption = MaterialPreset.highFreqAbsorption; - LandscapeScattering = MaterialPreset.scattering; - - for (TFieldIterator PropIt(GetClass()); PropIt; ++PropIt) - { - UProperty* Property = *PropIt; - if (Property->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, LandscapeLowFreqAbsorption) || - Property->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, LandscapeMidFreqAbsorption) || - Property->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, LandscapeHighFreqAbsorption) || - Property->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, LandscapeScattering)) - { - UpdateSinglePropertyInConfigFile(Property, GetDefaultConfigFilename()); - } - } - } - else if ((PropertyName == GET_MEMBER_NAME_CHECKED(UPhononSettings, RealtimeQualityPreset))) - { - RealtimeBounces = RealtimeSimulationQuality.Bounces; - RealtimeRays = RealtimeSimulationQuality.Rays; - RealtimeSecondaryRays = RealtimeSimulationQuality.SecondaryRays; - - for (TFieldIterator PropIt(GetClass()); PropIt; ++PropIt) - { - UProperty* Property = *PropIt; - if (Property->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, RealtimeBounces) || - Property->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, RealtimeRays) || - Property->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, RealtimeSecondaryRays)) - { - UpdateSinglePropertyInConfigFile(Property, GetDefaultConfigFilename()); - } - } - } - else if ((PropertyName == GET_MEMBER_NAME_CHECKED(UPhononSettings, BakedQualityPreset))) - { - BakedBounces = BakedSimulationQuality.Bounces; - BakedRays = BakedSimulationQuality.Rays; - BakedSecondaryRays = BakedSimulationQuality.SecondaryRays; - - for (TFieldIterator PropIt(GetClass()); PropIt; ++PropIt) - { - UProperty* Property = *PropIt; - if (Property->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, BakedBounces) || - Property->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, BakedRays) || - Property->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, BakedSecondaryRays)) - { - UpdateSinglePropertyInConfigFile(Property, GetDefaultConfigFilename()); - } - } - } -} - -bool UPhononSettings::CanEditChange(const UProperty* InProperty) const -{ - const bool ParentVal = Super::CanEditChange(InProperty); - - if (InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, StaticMeshLowFreqAbsorption) || - InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, StaticMeshMidFreqAbsorption) || - InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, StaticMeshHighFreqAbsorption) || - InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, StaticMeshScattering)) - { - return ParentVal && (StaticMeshMaterialPreset == EPhononMaterial::CUSTOM); - } - else if (InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, BSPLowFreqAbsorption) || - InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, BSPMidFreqAbsorption) || - InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, BSPHighFreqAbsorption) || - InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, BSPScattering)) - { - return ParentVal && (BSPMaterialPreset == EPhononMaterial::CUSTOM); - } - else if (InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, LandscapeLowFreqAbsorption) || - InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, LandscapeMidFreqAbsorption) || - InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, LandscapeHighFreqAbsorption) || - InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, LandscapeScattering)) - { - return ParentVal && (LandscapeMaterialPreset == EPhononMaterial::CUSTOM); - } - else if (InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, RealtimeBounces) || - InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, RealtimeRays) || - InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, RealtimeSecondaryRays)) - { - return ParentVal && (RealtimeQualityPreset == EQualitySettings::CUSTOM); - } - else if (InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, BakedBounces) || - InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, BakedRays) || - InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSettings, BakedSecondaryRays)) - { - return ParentVal && (BakedQualityPreset == EQualitySettings::CUSTOM); - } - else - { - return ParentVal; - } -} -#endif \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononSettings.h b/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononSettings.h deleted file mode 100644 index 731301c29598..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononSettings.h +++ /dev/null @@ -1,159 +0,0 @@ -// -// Copyright (C) Impulsonic, Inc. All rights reserved. -// - -#pragma once - -#include "PhononMaterial.h" -#include "PhononCommon.h" -#include "PhononSettings.generated.h" - -UCLASS(config = Engine, defaultconfig) -class PHONON_API UPhononSettings : public UObject -{ - GENERATED_BODY() - -public: - - UPhononSettings(); - - IPLMaterial GetDefaultStaticMeshMaterial() const; - IPLMaterial GetDefaultBSPMaterial() const; - IPLMaterial GetDefaultLandscapeMaterial() const; - -#if WITH_EDITOR - virtual void PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) override; - virtual bool CanEditChange(const UProperty* InProperty) const override; -#endif - - UPROPERTY(GlobalConfig, EditAnywhere, Category = General) - EIplAudioEngine AudioEngine; - - UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export", meta = (DisplayName = "Export BSP Geometry")) - bool ExportBSPGeometry; - - UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export", meta = (DisplayName = "Export Landscape Geometry")) - bool ExportLandscapeGeometry; - - /////// - - UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default Static Mesh Material", meta = (DisplayName = "Material Preset")) - EPhononMaterial StaticMeshMaterialPreset; - - UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default Static Mesh Material", meta = (ClampMin = "0.0", ClampMax = "1.0", UIMin = "0.0", UIMax = "1.0", - DisplayName = "Low Frequency Absorption")) - float StaticMeshLowFreqAbsorption; - - UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default Static Mesh Material", meta = (ClampMin = "0.0", ClampMax = "1.0", UIMin = "0.0", UIMax = "1.0", - DisplayName = "Mid Frequency Absorption")) - float StaticMeshMidFreqAbsorption; - - UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default Static Mesh Material", meta = (ClampMin = "0.0", ClampMax = "1.0", UIMin = "0.0", UIMax = "1.0", - DisplayName = "High Frequency Absorption")) - float StaticMeshHighFreqAbsorption; - - UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default Static Mesh Material", meta = (ClampMin = "0.0", ClampMax = "1.0", UIMin = "0.0", UIMax = "1.0", - DisplayName = "Scattering")) - float StaticMeshScattering; - - /////// - - UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default BSP Material", meta = (DisplayName = "Material Preset")) - EPhononMaterial BSPMaterialPreset; - - UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default BSP Material", meta = (ClampMin = "0.0", ClampMax = "1.0", UIMin = "0.0", UIMax = "1.0", - DisplayName = "Low Frequency Absorption")) - float BSPLowFreqAbsorption; - - UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default BSP Material", meta = (ClampMin = "0.0", ClampMax = "1.0", UIMin = "0.0", UIMax = "1.0", - DisplayName = "Mid Frequency Absorption")) - float BSPMidFreqAbsorption; - - UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default BSP Material", meta = (ClampMin = "0.0", ClampMax = "1.0", UIMin = "0.0", UIMax = "1.0", - DisplayName = "High Frequency Absorption")) - float BSPHighFreqAbsorption; - - UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default BSP Material", meta = (ClampMin = "0.0", ClampMax = "1.0", UIMin = "0.0", UIMax = "1.0", - DisplayName = "Scattering")) - float BSPScattering; - - /////// - - UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default Landscape Material", meta = (DisplayName = "Material Preset")) - EPhononMaterial LandscapeMaterialPreset; - - UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default Landscape Material", meta = (ClampMin = "0.0", ClampMax = "1.0", UIMin = "0.0", UIMax = "1.0", - DisplayName = "Low Frequency Absorption")) - float LandscapeLowFreqAbsorption; - - UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default Landscape Material", meta = (ClampMin = "0.0", ClampMax = "1.0", UIMin = "0.0", UIMax = "1.0", - DisplayName = "Mid Frequency Absorption")) - float LandscapeMidFreqAbsorption; - - UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default Landscape Material", meta = (ClampMin = "0.0", ClampMax = "1.0", UIMin = "0.0", UIMax = "1.0", - DisplayName = "High Frequency Absorption")) - float LandscapeHighFreqAbsorption; - - UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default Landscape Material", meta = (ClampMin = "0.0", ClampMax = "1.0", UIMin = "0.0", UIMax = "1.0", - DisplayName = "Scattering")) - float LandscapeScattering; - - /////// - - // Scale factor to make the indirect contribution louder or softer. - UPROPERTY(GlobalConfig, EditAnywhere, Category = IndirectSound, meta = (ClampMin = "0.0", ClampMax = "128.0", UIMin = "0.0", UIMax = "128.0")) - float IndirectContribution; - - // The output of indirect propagation is stored in ambisonics of this order. - UPROPERTY(GlobalConfig, EditAnywhere, Category = IndirectSound, meta = (ClampMin = "0", ClampMax = "8", UIMin = "0", UIMax = "8", - DisplayName = "Impulse Response Order")) - int32 IndirectImpulseResponseOrder; - - // The length of impulse response to compute for each sound source. - UPROPERTY(GlobalConfig, EditAnywhere, Category = IndirectSound, meta = (ClampMin = "1.0", ClampMax = "8.0", UIMin = "1.0", UIMax = "8.0", - DisplayName = "Impulse Response Duration")) - float IndirectImpulseResponseDuration; - - UPROPERTY(GlobalConfig, EditAnywhere, Category = "IndirectSound") - EIplSimulationType ReverbSimulationType; - - /* - // Whether propagation should be applied per-source or on the mixed audio. - UPROPERTY(GlobalConfig, EditAnywhere, Category = IndirectSound) - bool EnableMixerOptimization; - */ - - UPROPERTY(GlobalConfig, EditAnywhere, Category = "IndirectSound|Real-Time Quality Settings", meta = (DisplayName = "Quality Preset")) - EQualitySettings RealtimeQualityPreset; - - // The number of times an indirect sound path bounces through the environment. - UPROPERTY(GlobalConfig, EditAnywhere, Category = "IndirectSound|Real-Time Quality Settings", meta = (ClampMin = "0", ClampMax = "128", UIMin = "0", UIMax = "128", - DisplayName = "Bounces")) - int32 RealtimeBounces; - - // The number of primary rays to shoot from each sound source. - UPROPERTY(GlobalConfig, EditAnywhere, Category = "IndirectSound|Real-Time Quality Settings", meta = (ClampMin = "0", ClampMax = "65536", UIMin = "0", UIMax = "65536", - DisplayName = "Rays")) - int32 RealtimeRays; - - UPROPERTY(GlobalConfig, EditAnywhere, Category = "IndirectSound|Real-Time Quality Settings", meta = (ClampMin = "0", ClampMax = "8192", UIMin = "0", UIMax = "8192", - DisplayName = "Secondary Rays")) - int32 RealtimeSecondaryRays; - - UPROPERTY(GlobalConfig, EditAnywhere, Category = "IndirectSound|Baked Quality Settings", meta = (DisplayName = "Quality Preset")) - EQualitySettings BakedQualityPreset; - - // The number of times an indirect sound path bounces through the environment. - UPROPERTY(GlobalConfig, EditAnywhere, Category = "IndirectSound|Baked Quality Settings", meta = (ClampMin = "0", ClampMax = "128", UIMin = "0", UIMax = "128", - DisplayName = "Bounces")) - int32 BakedBounces; - - // The number of primary rays to shoot from each sound source. - UPROPERTY(GlobalConfig, EditAnywhere, Category = "IndirectSound|Baked Quality Settings", meta = (ClampMin = "0", ClampMax = "65536", UIMin = "0", UIMax = "65536", - DisplayName = "Rays")) - int32 BakedRays; - - UPROPERTY(GlobalConfig, EditAnywhere, Category = "IndirectSound|Baked Quality Settings", meta = (ClampMin = "0", ClampMax = "8192", UIMin = "0", UIMax = "8192", - DisplayName = "Secondary Rays")) - int32 BakedSecondaryRays; -}; \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononSourceComponent.cpp b/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononSourceComponent.cpp deleted file mode 100644 index 58d706e31716..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononSourceComponent.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// -// Copyright (C) Impulsonic, Inc. All rights reserved. -// - -#include "PhononSourceComponent.h" \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononSpatialization.cpp b/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononSpatialization.cpp deleted file mode 100644 index 6cddb425e127..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononSpatialization.cpp +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#include "PhononSpatialization.h" -#include "PhononSpatializationSourceSettings.h" -#include "PhononCommon.h" - -namespace Phonon -{ - FPhononSpatialization::FPhononSpatialization() - : BinauralRenderer(nullptr) - { - InputAudioFormat.channelLayout = IPL_CHANNELLAYOUT_MONO; - InputAudioFormat.channelLayoutType = IPL_CHANNELLAYOUTTYPE_SPEAKERS; - InputAudioFormat.channelOrder = IPL_CHANNELORDER_INTERLEAVED; - InputAudioFormat.numSpeakers = 1; - InputAudioFormat.speakerDirections = nullptr; - InputAudioFormat.ambisonicsOrder = -1; - InputAudioFormat.ambisonicsNormalization = IPL_AMBISONICSNORMALIZATION_N3D; - InputAudioFormat.ambisonicsOrdering = IPL_AMBISONICSORDERING_ACN; - - BinauralOutputAudioFormat.channelLayout = IPL_CHANNELLAYOUT_STEREO; - BinauralOutputAudioFormat.channelLayoutType = IPL_CHANNELLAYOUTTYPE_SPEAKERS; - BinauralOutputAudioFormat.channelOrder = IPL_CHANNELORDER_INTERLEAVED; - BinauralOutputAudioFormat.numSpeakers = 2; - BinauralOutputAudioFormat.speakerDirections = nullptr; - BinauralOutputAudioFormat.ambisonicsOrder = -1; - BinauralOutputAudioFormat.ambisonicsNormalization = IPL_AMBISONICSNORMALIZATION_N3D; - BinauralOutputAudioFormat.ambisonicsOrdering = IPL_AMBISONICSORDERING_ACN; - } - - FPhononSpatialization::~FPhononSpatialization() - { - if (BinauralRenderer) - { - iplDestroyBinauralRenderer(&BinauralRenderer); - } - } - - // TODO dunno if outputbufferlength is correct - void FPhononSpatialization::Initialize(const uint32 SampleRate, const uint32 NumSources, const uint32 OutputBufferLength) - { - RenderingSettings.convolutionType = IPL_CONVOLUTIONTYPE_PHONON; - RenderingSettings.frameSize = OutputBufferLength; - RenderingSettings.samplingRate = SampleRate; - - iplCreateBinauralRenderer(Phonon::GlobalContext, RenderingSettings, nullptr, &BinauralRenderer); - - for (uint32 i = 0; i < NumSources; ++i) - { - FPhononBinauralSource BinauralSource; - BinauralSource.InBuffer.format = InputAudioFormat; - BinauralSource.InBuffer.numSamples = OutputBufferLength; - BinauralSource.InBuffer.interleavedBuffer = nullptr; - BinauralSource.InBuffer.deinterleavedBuffer = nullptr; - - BinauralSource.OutArray.SetNumZeroed(OutputBufferLength * 2); - BinauralSource.OutBuffer.format = BinauralOutputAudioFormat; - BinauralSource.OutBuffer.numSamples = OutputBufferLength; - BinauralSource.OutBuffer.interleavedBuffer = nullptr; - BinauralSource.OutBuffer.deinterleavedBuffer = nullptr; - - iplCreateBinauralEffect(BinauralRenderer, InputAudioFormat, BinauralOutputAudioFormat, &BinauralSource.BinauralEffect); - - BinauralSources.Add(BinauralSource); - } - } - - void FPhononSpatialization::SetSpatializationSettings(const uint32 SourceId, USpatializationPluginSourceSettingsBase* InSettings) - { - auto SpatializationSettings = static_cast(InSettings); - } - - void FPhononSpatialization::ProcessAudio(const FAudioPluginSourceInputData& InputData, FAudioPluginSourceOutputData& OutputData) - { - auto& BinauralSource = BinauralSources[InputData.SourceId]; - BinauralSource.InBuffer.interleavedBuffer = InputData.AudioBuffer->GetData(); - BinauralSource.OutBuffer.interleavedBuffer = OutputData.AudioBuffer.GetData(); - - iplApplyBinauralEffect(BinauralSource.BinauralEffect, BinauralSource.InBuffer, - Phonon::UnrealToPhononIPLVector3(InputData.SpatializationParams->EmitterPosition, false), IPL_HRTFINTERPOLATION_NEAREST, - BinauralSource.OutBuffer); - } - - bool FPhononSpatialization::IsSpatializationEffectInitialized() const - { - return true; - } - - bool FPhononSpatialization::CreateSpatializationEffect(uint32 SourceId) - { - return true; - } -} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Public/PhononOcclusionSourceSettings.h b/Engine/Plugins/Runtime/Phonon/Source/Phonon/Public/PhononOcclusionSourceSettings.h deleted file mode 100644 index 6dbcd840bfdf..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Public/PhononOcclusionSourceSettings.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "IAudioExtensionPlugin.h" -#include "PhononCommon.h" -#include "PhononOcclusionSourceSettings.generated.h" - -UCLASS() -class PHONON_API UPhononOcclusionSourceSettings : public UOcclusionPluginSourceSettingsBase -{ - GENERATED_BODY() - -public: - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SourceEffect") - EIplDirectOcclusionMethod DirectOcclusionMethod; - - // TODO: enabled only for volumetric - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SourceEffect") - float DirectOcclusionSourceRadius; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SourceEffect") - bool DirectAttenuation; -}; - diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Public/PhononReverbSourceSettings.h b/Engine/Plugins/Runtime/Phonon/Source/Phonon/Public/PhononReverbSourceSettings.h deleted file mode 100644 index a28059daef68..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Public/PhononReverbSourceSettings.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "IAudioExtensionPlugin.h" -#include "PhononCommon.h" -#include "PhononReverbSourceSettings.generated.h" - -UCLASS() -class PHONON_API UPhononReverbSourceSettings : public UReverbPluginSourceSettingsBase -{ - GENERATED_BODY() - -public: - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SourceEffect") - EIplSimulationType IndirectSimulationType; - - // TODO: enabled only if not using mixer for propagation effects - /* - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SourceEffect") - EIplIndirectSpatializationMethod IndirectSpatializationMethod; - */ -}; - diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Public/PhononSpatializationSourceSettings.h b/Engine/Plugins/Runtime/Phonon/Source/Phonon/Public/PhononSpatializationSourceSettings.h deleted file mode 100644 index 6112674632fe..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Public/PhononSpatializationSourceSettings.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "IAudioExtensionPlugin.h" -#include "PhononCommon.h" -#include "PhononSpatializationSourceSettings.generated.h" - -UCLASS() -class PHONON_API UPhononSpatializationSourceSettings : public USpatializationPluginSourceSettingsBase -{ - GENERATED_BODY() - -public: - - UPROPERTY(GlobalConfig, EditAnywhere, Category = SourceEffect) - EIplSpatializationMethod SpatializationMethod; - - UPROPERTY(GlobalConfig, EditAnywhere, Category = SourceEffect, meta = (DisplayName = "HRTF Interpolation Method")) - EIplHrtfInterpolationMethod HrtfInterpolationMethod; -}; - diff --git a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/PhononEditor.Build.cs b/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/PhononEditor.Build.cs deleted file mode 100644 index 00f44e0196ef..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/PhononEditor.Build.cs +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -namespace UnrealBuildTool.Rules -{ - public class PhononEditor : ModuleRules - { - public PhononEditor(ReadOnlyTargetRules Target) : base(Target) - { - PrivateIncludePaths.AddRange( - new string[] { - "PhononEditor/Private", - "Phonon/Private", - "Phonon/Public" - } - ); - - PublicIncludePaths.AddRange( - new string[] { - "Phonon/Public" - } - ); - - - PublicDependencyModuleNames.AddRange( - new string[] { - "Core", - "CoreUObject", - "Engine", - "InputCore", - "UnrealEd", - "LevelEditor", - "EditorStyle", - "RenderCore", - "ShaderCore", - "RHI", - "AudioEditor", - "AudioMixer", - "Phonon" - } - ); - - PrivateIncludePathModuleNames.AddRange( - new string[] { - "AssetTools", - "Landscape" - }); - - PrivateDependencyModuleNames.AddRange( - new string[] { - "Slate", - "SlateCore", - "UnrealEd", - "AudioEditor", - "LevelEditor", - "Landscape", - "Core", - "CoreUObject", - "Engine", - "InputCore", - "PropertyEditor", - "Projects", - "EditorStyle", - "Phonon", - "ComponentVisualizers" - } - ); - - AddEngineThirdPartyPrivateStaticDependencies(Target, "libPhonon"); - AddEngineThirdPartyPrivateStaticDependencies(Target, "DX11Audio"); - } - } -} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononEditorModule.cpp b/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononEditorModule.cpp deleted file mode 100644 index 8cab1fe4e3e4..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononEditorModule.cpp +++ /dev/null @@ -1,268 +0,0 @@ -// -// Copyright (C) Impulsonic, Inc. All rights reserved. -// - -#include "PhononEditorModule.h" - -#include "ISettingsModule.h" - -#include "Editor.h" - -#include "Engine/World.h" -#include "SlateStyleRegistry.h" -#include "Kismet/GameplayStatics.h" -#include "Async/Async.h" -#include "UnrealEdGlobals.h" -#include "Editor/UnrealEdEngine.h" -#include "LevelEditorViewport.h" -#include "LevelEditor.h" -#include "PropertyEditorModule.h" -#include "SlateStyle.h" -#include "IPluginManager.h" -#include "ClassIconFinder.h" -#include "MultiBox/MultiBoxBuilder.h" - -#include "TickableNotification.h" -#include "PhononScene.h" -#include "PhononSettings.h" -#include "PhononProbeVolume.h" -#include "PhononProbeVolumeDetails.h" -#include "PhononSourceComponent.h" -#include "PhononSourceComponentDetails.h" -#include "PhononSourceComponentVisualizer.h" - -DEFINE_LOG_CATEGORY(LogPhononEditor); - -IMPLEMENT_MODULE(Phonon::FPhononEditorModule, PhononEditor) - -namespace Phonon -{ - void FPhononEditorModule::StartupModule() - { - // Create tickable notifications - ExportSceneTickable = MakeShareable(new FTickableNotification()); - BakeReverbTickable = MakeShareable(new FTickableNotification()); - - // Register detail customizations - FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked("PropertyEditor"); - - PropertyModule.RegisterCustomClassLayout("PhononProbeVolume", FOnGetDetailCustomizationInstance::CreateStatic(&FPhononProbeVolumeDetails::MakeInstance)); - PropertyModule.RegisterCustomClassLayout("PhononSourceComponent", FOnGetDetailCustomizationInstance::CreateStatic(&FPhononSourceComponentDetails::MakeInstance)); - - // Register component visualizers - RegisterComponentVisualizer(UPhononSourceComponent::StaticClass()->GetFName(), MakeShareable(new FPhononSourceComponentVisualizer())); - - // Extend the toolbar build menu with custom actions - if (!IsRunningCommandlet()) - { - FLevelEditorModule* LevelEditorModule = FModuleManager::LoadModulePtr(TEXT("LevelEditor")); - if (LevelEditorModule) - { - auto BuildMenuExtender = FLevelEditorModule::FLevelEditorMenuExtender::CreateRaw(this, &FPhononEditorModule::OnExtendLevelEditorBuildMenu); - - LevelEditorModule->GetAllLevelEditorToolbarBuildMenuExtenders().Add(BuildMenuExtender); - } - } - - // Register plugin settings - ISettingsModule* SettingsModule = FModuleManager::Get().GetModulePtr("Settings"); - if (SettingsModule) - { - SettingsModule->RegisterSettings("Project", "Plugins", "Steam Audio", NSLOCTEXT("Steam Audio", "Steam Audio", "Steam Audio"), - NSLOCTEXT("Phonon", "Configure Steam Audio settings", "Configure Steam Audio settings"), GetMutableDefault()); - } - - // Create and register custom slate style - FString PhononContent = IPluginManager::Get().FindPlugin("Phonon")->GetBaseDir() + "/Content"; - FVector2D Vec16 = FVector2D(16.0f, 16.0f); - - PhononStyleSet = MakeShareable(new FSlateStyleSet("Phonon")); - PhononStyleSet->SetContentRoot(FPaths::EngineContentDir() / TEXT("Editor/Slate")); - PhononStyleSet->SetCoreContentRoot(FPaths::EngineContentDir() / TEXT("Slate")); - PhononStyleSet->Set("ClassIcon.PhononSourceComponent", new FSlateImageBrush(PhononContent + "/S_PhononSource_16.png", Vec16)); - PhononStyleSet->Set("ClassIcon.PhononListenerComponent", new FSlateImageBrush(PhononContent + "/S_PhononListener_16.png", Vec16)); - PhononStyleSet->Set("ClassIcon.PhononGeometryComponent", new FSlateImageBrush(PhononContent + "/S_PhononGeometry_16.png", Vec16)); - PhononStyleSet->Set("ClassIcon.PhononMaterialComponent", new FSlateImageBrush(PhononContent + "/S_PhononMaterial_16.png", Vec16)); - FSlateStyleRegistry::RegisterSlateStyle(*PhononStyleSet.Get()); - } - - void FPhononEditorModule::ShutdownModule() - { - FSlateStyleRegistry::UnRegisterSlateStyle(*PhononStyleSet.Get()); - - if (GUnrealEd) - { - for (FName& ClassName : RegisteredComponentClassNames) - { - GUnrealEd->UnregisterComponentVisualizer(ClassName); - } - } - } - - void FPhononEditorModule::RegisterComponentVisualizer(const FName ComponentClassName, TSharedPtr Visualizer) - { - if (GUnrealEd) - { - GUnrealEd->RegisterComponentVisualizer(ComponentClassName, Visualizer); - } - - RegisteredComponentClassNames.Add(ComponentClassName); - - if (Visualizer.IsValid()) - { - Visualizer->OnRegister(); - } - } - - TSharedRef FPhononEditorModule::OnExtendLevelEditorBuildMenu(const TSharedRef CommandList) - { - TSharedRef Extender(new FExtender()); - - Extender->AddMenuExtension("LevelEditorNavigation", EExtensionHook::After, nullptr, - FMenuExtensionDelegate::CreateRaw(this, &FPhononEditorModule::CreateBuildMenu)); - - return Extender; - } - - void FPhononEditorModule::CreateBuildMenu(FMenuBuilder& Builder) - { - FUIAction ActionExportScene(FExecuteAction::CreateRaw(this, &FPhononEditorModule::ExportScene), - FCanExecuteAction::CreateRaw(this, &FPhononEditorModule::IsReadyToExportScene)); - - FUIAction ActionBakeReverb(FExecuteAction::CreateRaw(this, &FPhononEditorModule::BakeReverb), - FCanExecuteAction::CreateRaw(this, &FPhononEditorModule::IsReadyToBakeReverb)); - - Builder.BeginSection("LevelEditorIR", NSLOCTEXT("Phonon", "Phonon", "Phonon")); - - Builder.AddMenuEntry(NSLOCTEXT("Phonon", "Export Scene", "Export Scene"), - NSLOCTEXT("Phonon", "Exports Phonon geometry.", "Export Phonon geometry."), FSlateIcon(), ActionExportScene, NAME_None, - EUserInterfaceActionType::Button); - - Builder.AddMenuEntry(NSLOCTEXT("Phonon", "Bake Reverb", "Bake Reverb"), - NSLOCTEXT("Phonon", "Bakes reverb at all probe locations.", "Bakes reverb at all probe locations."), FSlateIcon(), ActionBakeReverb, - NAME_None, EUserInterfaceActionType::Button); - - Builder.EndSection(); - } - - void FPhononEditorModule::ExportScene() - { - // Display editor notification - ExportSceneTickable->SetDisplayText(NSLOCTEXT("Phonon", "Exporting scene...", "Exporting scene...")); - ExportSceneTickable->CreateNotification(); - - // Export the scene - UWorld* World = GEditor->LevelViewportClients[0]->GetWorld(); - IPLhandle PhononScene = nullptr; - TArray PhononStaticMeshes; - Phonon::LoadScene(World, &PhononScene, &PhononStaticMeshes); - - // Save to disk - FString BaseSceneFile = FPaths::GameDir() + "Content/" + World->GetMapName(); - FString SceneFile = BaseSceneFile + ".phononscene"; - FString ObjSceneFile = BaseSceneFile + ".obj"; - iplSaveFinalizedScene(PhononScene, TCHAR_TO_ANSI(*SceneFile)); - iplDumpSceneToObjFile(PhononScene, TCHAR_TO_ANSI(*ObjSceneFile)); - - // Clean up Phonon structures - for (IPLhandle PhononStaticMesh : PhononStaticMeshes) - { - iplDestroyStaticMesh(&PhononStaticMesh); - } - iplDestroyScene(&PhononScene); - - // Display editor notification - ExportSceneTickable->SetDisplayText(NSLOCTEXT("Phonon", "Export successful!", "Export successful!")); - ExportSceneTickable->DestroyNotification(); - } - - bool FPhononEditorModule::IsReadyToExportScene() const - { - return true; - } - - void FPhononEditorModule::BakeReverb() - { - // Display editor notification - BakeReverbTickable->SetDisplayText(NSLOCTEXT("Phonon", "Baking reverb...", "Baking reverb...")); - BakeReverbTickable->CreateNotification(); - - UWorld* World = GEditor->LevelViewportClients[0]->GetWorld(); - - // Get all probe volumes (cannot do this in the async task) - TArray PhononProbeVolumes; - UGameplayStatics::GetAllActorsOfClass(World, APhononProbeVolume::StaticClass(), PhononProbeVolumes); - - TFunction BakeTask = [=]() - { - IPLBakingSettings BakingSettings; - BakingSettings.bakeParametric = IPL_FALSE; - BakingSettings.bakeConvolution = IPL_TRUE; - - IPLSimulationSettings SimulationSettings; - SimulationSettings.sceneType = IPL_SCENETYPE_PHONON; - SimulationSettings.irDuration = GetDefault()->IndirectImpulseResponseDuration; - SimulationSettings.ambisonicsOrder = GetDefault()->IndirectImpulseResponseOrder; - SimulationSettings.maxConvolutionSources = 0; - SimulationSettings.numBounces = GetDefault()->BakedBounces; - SimulationSettings.numRays = GetDefault()->BakedRays; - SimulationSettings.numDiffuseSamples = GetDefault()->BakedSecondaryRays; - - IPLhandle ComputeDevice = nullptr; - //iplCreateComputeDevice(IPL_COMPUTEDEVICE_CPU, 1, &ComputeDevice); - - IPLLoadSceneProgressCallback LoadSceneProgressCallback = nullptr; - - IPLhandle PhononScene = nullptr; - IPLhandle PhononEnvironment = nullptr; - - BakeReverbTickable->SetDisplayText(NSLOCTEXT("Phonon", "Loading scene...", "Loading scene...")); - - if (World) - { - FString SceneFile = FPaths::GameDir() + "Content/" + World->GetMapName() + ".phononscene"; - - if (FPaths::FileExists(SceneFile)) - { - iplLoadFinalizedScene(Phonon::GlobalContext, SimulationSettings, TCHAR_TO_ANSI(*SceneFile), ComputeDevice, LoadSceneProgressCallback, &PhononScene); - iplCreateEnvironment(Phonon::GlobalContext, ComputeDevice, SimulationSettings, PhononScene, nullptr, &PhononEnvironment); - } - else - { - // TODO: load - UE_LOG(LogPhononEditor, Log, TEXT("Unable to load scene: %s not found."), *SceneFile); - } - } - else - { - UE_LOG(LogPhononEditor, Log, TEXT("Unable to load scene: null World.")); - } - - BakeReverbTickable->SetDisplayText(NSLOCTEXT("Phonon", "Baking reverb...", "Baking reverb...")); - - for (AActor* PhononProbeVolumeActor : PhononProbeVolumes) - { - APhononProbeVolume* PhononProbeVolume = Cast(PhononProbeVolumeActor); - IPLhandle ProbeBox = nullptr; - iplLoadProbeBox(PhononProbeVolume->GetProbeBoxData(), PhononProbeVolume->GetProbeBoxDataSize(), &ProbeBox); - iplBakeReverb(PhononEnvironment, ProbeBox, BakingSettings, nullptr); - PhononProbeVolume->UpdateProbeBoxData(ProbeBox); - iplDestroyProbeBox(&ProbeBox); - } - - iplDestroyEnvironment(&PhononEnvironment); - iplDestroyScene(&PhononScene); - - // Display editor notification - BakeReverbTickable->SetDisplayText(NSLOCTEXT("Phonon", "Bake complete!", "Bake complete!")); - BakeReverbTickable->DestroyNotification(); - }; - - TFuture BakeResult = Async(EAsyncExecution::Thread, BakeTask); - } - - bool FPhononEditorModule::IsReadyToBakeReverb() const - { - return true; - } -} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononOcclusionSettingsFactory.cpp b/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononOcclusionSettingsFactory.cpp deleted file mode 100644 index 4055bcdcf52a..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononOcclusionSettingsFactory.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#include "PhononOcclusionSettingsFactory.h" -#include "PhononOcclusionSourceSettings.h" -#include "UObject/ObjectMacros.h" -#include "UObject/Object.h" - -UClass* FAssetTypeActions_PhononOcclusionSettings::GetSupportedClass() const -{ - return UPhononOcclusionSourceSettings::StaticClass(); -} - -UPhononOcclusionSettingsFactory::UPhononOcclusionSettingsFactory(const FObjectInitializer& ObjectInitializer) - : Super(ObjectInitializer) -{ - SupportedClass = UPhononOcclusionSourceSettings::StaticClass(); - - bCreateNew = true; - bEditorImport = false; - bEditAfterNew = true; -} - -UObject* UPhononOcclusionSettingsFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) -{ - UPhononOcclusionSourceSettings* NewPresetBank = NewObject(InParent, InName, Flags); - - return NewPresetBank; -} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononOcclusionSettingsFactory.h b/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononOcclusionSettingsFactory.h deleted file mode 100644 index 312bc595c39b..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononOcclusionSettingsFactory.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "IAudioExtensionPlugin.h" -#include "AssetToolsModule.h" -#include "Factories/Factory.h" -#include "AssetTypeActions_Base.h" -#include "PhononOcclusionSettingsFactory.generated.h" - -class FAssetTypeActions_PhononOcclusionSettings : public FAssetTypeActions_Base -{ -public: - virtual FText GetName() const override { return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_PhononOcclusionSettings", "Phonon Source Occlusion Settings"); } - virtual FColor GetTypeColor() const override { return FColor(245, 195, 101); } - virtual UClass* GetSupportedClass() const override; - virtual uint32 GetCategories() override { return EAssetTypeCategories::Sounds; } -}; - -UCLASS(MinimalAPI, hidecategories = Object) -class UPhononOcclusionSettingsFactory : public UFactory -{ - GENERATED_UCLASS_BODY() - - //~ Begin UFactory Interface - virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override; - //~ Begin UFactory Interface -}; - diff --git a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononProbeVolumeDetails.cpp b/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononProbeVolumeDetails.cpp deleted file mode 100644 index 466c2887c400..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononProbeVolumeDetails.cpp +++ /dev/null @@ -1,74 +0,0 @@ -// -// Copyright (C) Impulsonic, Inc. All rights reserved. -// - -#include "PhononProbeVolumeDetails.h" - -#include "DetailLayoutBuilder.h" -#include "DetailCategoryBuilder.h" -#include "DetailWidgetRow.h" -#include "IDetailsView.h" -#include "IDetailCustomization.h" -#include "PhononProbeVolume.h" -#include "Widgets/Input/SButton.h" -#include "Widgets/Layout/SBox.h" -#include "Widgets/Text/STextBlock.h" - -namespace Phonon -{ - TSharedRef FPhononProbeVolumeDetails::MakeInstance() - { - return MakeShareable(new FPhononProbeVolumeDetails); - } - - void FPhononProbeVolumeDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLayout) - { - const TArray>& SelectedObjects = DetailLayout.GetDetailsView().GetSelectedObjects(); - - for (int32 ObjectIndex = 0; ObjectIndex < SelectedObjects.Num(); ++ObjectIndex) - { - const TWeakObjectPtr& CurrentObject = SelectedObjects[ObjectIndex]; - if (CurrentObject.IsValid()) - { - APhononProbeVolume* CurrentCaptureActor = Cast(CurrentObject.Get()); - if (CurrentCaptureActor) - { - PhononProbeVolume = CurrentCaptureActor; - break; - } - } - } - - DetailLayout.HideCategory("BrushSettings"); - - DetailLayout.EditCategory("ProbeGeneration") - .AddCustomRow(NSLOCTEXT("PhononProbeVolumeDetails", "Generate Probes", "Generate Probes")) - .NameContent() - [ - SNullWidget::NullWidget - ] - .ValueContent() - [ - SNew(SBox) - .WidthOverride(125) - [ - SNew(SButton) - .ContentPadding(3) - .VAlign(VAlign_Center) - .HAlign(HAlign_Center) - .OnClicked(this, &FPhononProbeVolumeDetails::OnGenerateProbes) - [ - SNew(STextBlock) - .Text(NSLOCTEXT("PhononProbeVolumeDetails", "Generate Probes", "Generate Probes")) - .Font(IDetailLayoutBuilder::GetDetailFont()) - ] - ] - ]; - } - - FReply FPhononProbeVolumeDetails::OnGenerateProbes() - { - PhononProbeVolume->GenerateProbes(); - return FReply::Handled(); - } -} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononReverbSettingsFactory.cpp b/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononReverbSettingsFactory.cpp deleted file mode 100644 index 599b7804e7ea..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononReverbSettingsFactory.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#include "PhononReverbSettingsFactory.h" -#include "PhononReverbSourceSettings.h" -#include "UObject/ObjectMacros.h" -#include "UObject/Object.h" - -UClass* FAssetTypeActions_PhononReverbSettings::GetSupportedClass() const -{ - return UPhononReverbSourceSettings::StaticClass(); -} - -UPhononReverbSettingsFactory::UPhononReverbSettingsFactory(const FObjectInitializer& ObjectInitializer) - : Super(ObjectInitializer) -{ - SupportedClass = UPhononReverbSourceSettings::StaticClass(); - - bCreateNew = true; - bEditorImport = false; - bEditAfterNew = true; -} - -UObject* UPhononReverbSettingsFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) -{ - UPhononReverbSourceSettings* NewPresetBank = NewObject(InParent, InName, Flags); - - return NewPresetBank; -} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononReverbSettingsFactory.h b/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononReverbSettingsFactory.h deleted file mode 100644 index d05fdb6fbb5c..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononReverbSettingsFactory.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "IAudioExtensionPlugin.h" -#include "AssetToolsModule.h" -#include "Factories/Factory.h" -#include "AssetTypeActions_Base.h" -#include "PhononReverbSettingsFactory.generated.h" - -class FAssetTypeActions_PhononReverbSettings : public FAssetTypeActions_Base -{ -public: - virtual FText GetName() const override { return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_PhononReverbSettings", "Phonon Source Reverb Settings"); } - virtual FColor GetTypeColor() const override { return FColor(245, 195, 101); } - virtual UClass* GetSupportedClass() const override; - virtual uint32 GetCategories() override { return EAssetTypeCategories::Sounds; } -}; - -UCLASS(MinimalAPI, hidecategories = Object) -class UPhononReverbSettingsFactory : public UFactory -{ - GENERATED_UCLASS_BODY() - - //~ Begin UFactory Interface - virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override; - //~ Begin UFactory Interface -}; - diff --git a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononSourceComponentDetails.cpp b/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononSourceComponentDetails.cpp deleted file mode 100644 index 9b1ae60d2154..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononSourceComponentDetails.cpp +++ /dev/null @@ -1,210 +0,0 @@ -// -// Copyright (C) Impulsonic, Inc. All rights reserved. -// - -#include "PhononSourceComponentDetails.h" - -#include "PhononCommon.h" -#include "PhononSourceComponent.h" -#include "PhononProbeVolume.h" -#include "PhononSettings.h" -#include "PhononEditorModule.h" -#include "TickableNotification.h" -#include "phonon.h" -#include "Components/AudioComponent.h" - -#include "DetailLayoutBuilder.h" -#include "DetailCategoryBuilder.h" -#include "DetailWidgetRow.h" -#include "IDetailsView.h" -#include "IDetailCustomization.h" -#include "IDetailChildrenBuilder.h" -#include "LevelEditorViewport.h" -#include "Kismet/GameplayStatics.h" -#include "Async/Async.h" -#include "EngineUtils.h" - -#include "Widgets/Input/SButton.h" -#include "Widgets/Layout/SBox.h" -#include "Widgets/Text/STextBlock.h" - -#include "Editor.h" - -namespace Phonon -{ - FPhononSourceComponentDetails::FPhononSourceComponentDetails() - : BakePropagationTickable(MakeShareable(new FTickableNotification())) - { - } - - TSharedRef FPhononSourceComponentDetails::MakeInstance() - { - return MakeShareable(new FPhononSourceComponentDetails()); - } - - void FPhononSourceComponentDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLayout) - { - const TArray>& SelectedObjects = DetailLayout.GetDetailsView().GetSelectedObjects(); - - for (int32 ObjectIndex = 0; ObjectIndex < SelectedObjects.Num(); ++ObjectIndex) - { - const TWeakObjectPtr& CurrentObject = SelectedObjects[ObjectIndex]; - if (CurrentObject.IsValid()) - { - UPhononSourceComponent* SelectedPhononSourceComponent = Cast(CurrentObject.Get()); - if (SelectedPhononSourceComponent) - { - PhononSourceComponent = SelectedPhononSourceComponent; - break; - } - } - } - - DetailLayout.EditCategory("Baking") - .AddCustomRow(NSLOCTEXT("PhononSourceComponentDetails", "Bake Propagation", "Bake Propagation")) - .NameContent() - [ - SNullWidget::NullWidget - ] - .ValueContent() - [ - SNew(SBox) - .WidthOverride(125) - [ - SNew(SButton) - .ContentPadding(3) - .VAlign(VAlign_Center) - .HAlign(HAlign_Center) - .OnClicked(this, &FPhononSourceComponentDetails::OnBakePropagation) - [ - SNew(STextBlock) - .Text(NSLOCTEXT("PhononSourceComponentDetails", "Bake Propagation", "Bake Propagation")) - .Font(IDetailLayoutBuilder::GetDetailFont()) - ] - ] - ]; - } - - static void LoadSceneProgressCallback(float Progress) - { - - } - - static void BakeProgressCallback(float Progress) - { - - } - - static uint32 GeneratePhononSourceID(UWorld* World) - { - TMap SourceIDMap; - - for (TActorIterator AActorItr(World); AActorItr; ++AActorItr) - { - if (AActorItr->GetComponentByClass(UPhononSourceComponent::StaticClass()) && - AActorItr->GetComponentByClass(UAudioComponent::StaticClass())) - { - UAudioComponent* AudioComponent = static_cast(AActorItr->GetComponentByClass(UAudioComponent::StaticClass())); - SourceIDMap.Add(AudioComponent->GetAudioComponentUserID(), true); - } - } - - int32 NewSourceID = FMath::Rand(); - while (SourceIDMap.Contains(NewSourceID)) - { - NewSourceID = FMath::Rand(); - } - - return NewSourceID; - } - - FReply FPhononSourceComponentDetails::OnBakePropagation() - { - BakePropagationTickable->SetDisplayText(NSLOCTEXT("Phonon", "Baking propagation...", "Baking propagation...")); - BakePropagationTickable->CreateNotification(); - - UWorld* World = GEditor->LevelViewportClients[0]->GetWorld(); - check(World); - - // Get all probe volumes (cannot do this in the async task - not on game thread) - TArray PhononProbeVolumes; - UGameplayStatics::GetAllActorsOfClass(World, APhononProbeVolume::StaticClass(), PhononProbeVolumes); - - // Assign the audio component an ID if it doesn't have one - { - UAudioComponent* AudioComponent = static_cast(PhononSourceComponent->GetOwner()->GetComponentByClass(UAudioComponent::StaticClass())); - if (!AudioComponent->GetAudioComponentUserID()) - { - AudioComponent->AudioComponentUserID = GeneratePhononSourceID(World); - } - } - - TFunction BakeTask = [=]() - { - IPLBakingSettings BakingSettings; - BakingSettings.bakeParametric = IPL_FALSE; - BakingSettings.bakeConvolution = IPL_TRUE; - - IPLSimulationSettings SimulationSettings; - SimulationSettings.sceneType = IPL_SCENETYPE_PHONON; - SimulationSettings.irDuration = GetDefault()->IndirectImpulseResponseDuration; - SimulationSettings.ambisonicsOrder = GetDefault()->IndirectImpulseResponseOrder; - SimulationSettings.maxConvolutionSources = 0; - SimulationSettings.numBounces = GetDefault()->BakedBounces; - SimulationSettings.numRays = GetDefault()->BakedRays; - SimulationSettings.numDiffuseSamples = GetDefault()->BakedSecondaryRays; - - IPLhandle ComputeDevice = nullptr; - IPLhandle PhononScene = nullptr; - IPLhandle PhononEnvironment = nullptr; - - BakePropagationTickable->SetDisplayText(NSLOCTEXT("Phonon", "Loading scene...", "Loading scene...")); - - FString SceneFile = FPaths::GameDir() + "Content/" + World->GetMapName() + ".phononscene"; - - if (FPaths::FileExists(SceneFile)) - { - iplLoadFinalizedScene(Phonon::GlobalContext, SimulationSettings, TCHAR_TO_ANSI(*SceneFile), ComputeDevice, LoadSceneProgressCallback, &PhononScene); - iplCreateEnvironment(Phonon::GlobalContext, ComputeDevice, SimulationSettings, PhononScene, nullptr, &PhononEnvironment); - } - else - { - UE_LOG(LogPhononEditor, Log, TEXT("Unable to load scene: %s not found."), *SceneFile); - } - - BakePropagationTickable->SetDisplayText(NSLOCTEXT("Phonon", "Baking...", "Baking...")); - - for (AActor* PhononProbeVolumeActor : PhononProbeVolumes) - { - APhononProbeVolume* PhononProbeVolume = Cast(PhononProbeVolumeActor); - - IPLhandle ProbeBox = nullptr; - iplLoadProbeBox(PhononProbeVolume->GetProbeBoxData(), PhononProbeVolume->GetProbeBoxDataSize(), &ProbeBox); - - IPLSphere SourceInfluence; - SourceInfluence.radius = PhononSourceComponent->BakeRadius; - SourceInfluence.center = Phonon::UnrealToPhononIPLVector3(PhononSourceComponent->GetComponentLocation()); - - UAudioComponent* AudioComponent = static_cast(PhononSourceComponent->GetOwner()->GetComponentByClass(UAudioComponent::StaticClass())); - FString AudioComponentName = FString::FromInt(AudioComponent->GetAudioComponentUserID()); - - iplDeleteBakedDataByName(ProbeBox, TCHAR_TO_ANSI(*AudioComponentName)); - iplBakePropagation(PhononEnvironment, ProbeBox, SourceInfluence, TCHAR_TO_ANSI(*AudioComponentName), BakingSettings, - BakeProgressCallback); - - PhononProbeVolume->UpdateProbeBoxData(ProbeBox); - iplDestroyProbeBox(&ProbeBox); - } - - iplDestroyEnvironment(&PhononEnvironment); - iplDestroyScene(&PhononScene); - - // Display editor notification - BakePropagationTickable->SetDisplayText(NSLOCTEXT("Phonon", "Bake complete!", "Bake complete!")); - BakePropagationTickable->DestroyNotification(); - }; - - TFuture BakeResult = Async(EAsyncExecution::Thread, BakeTask); - return FReply::Handled(); - } -} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononSpatializationSettingsFactory.cpp b/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononSpatializationSettingsFactory.cpp deleted file mode 100644 index 8851687d2703..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononSpatializationSettingsFactory.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#include "PhononSpatializationSettingsFactory.h" -#include "PhononSpatializationSourceSettings.h" -#include "UObject/ObjectMacros.h" -#include "UObject/Object.h" - -UClass* FAssetTypeActions_PhononSpatializationSettings::GetSupportedClass() const -{ - return UPhononSpatializationSourceSettings::StaticClass(); -} - -UPhononSpatializationSettingsFactory::UPhononSpatializationSettingsFactory(const FObjectInitializer& ObjectInitializer) - : Super(ObjectInitializer) -{ - SupportedClass = UPhononSpatializationSourceSettings::StaticClass(); - - bCreateNew = true; - bEditorImport = false; - bEditAfterNew = true; -} - -UObject* UPhononSpatializationSettingsFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) -{ - UPhononSpatializationSourceSettings* NewPresetBank = NewObject(InParent, InName, Flags); - - return NewPresetBank; -} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononSpatializationSettingsFactory.h b/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononSpatializationSettingsFactory.h deleted file mode 100644 index 768f9876befb..000000000000 --- a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononSpatializationSettingsFactory.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "IAudioExtensionPlugin.h" -#include "AssetToolsModule.h" -#include "Factories/Factory.h" -#include "AssetTypeActions_Base.h" -#include "PhononSpatializationSettingsFactory.generated.h" - -class FAssetTypeActions_PhononSpatializationSettings : public FAssetTypeActions_Base -{ -public: - virtual FText GetName() const override { return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_PhononSpatializationSettings", "Phonon Source Spatialization Settings"); } - virtual FColor GetTypeColor() const override { return FColor(245, 195, 101); } - virtual UClass* GetSupportedClass() const override; - virtual uint32 GetCategories() override { return EAssetTypeCategories::Sounds; } -}; - -UCLASS(MinimalAPI, hidecategories = Object) -class UPhononSpatializationSettingsFactory : public UFactory -{ - GENERATED_UCLASS_BODY() - - //~ Begin UFactory Interface - virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override; - //~ Begin UFactory Interface -}; - diff --git a/Engine/Plugins/Runtime/PhysXVehicles/Source/PhysXVehicles/Private/WheeledVehicle.cpp b/Engine/Plugins/Runtime/PhysXVehicles/Source/PhysXVehicles/Private/WheeledVehicle.cpp index e2487c3359b3..91545358fb97 100644 --- a/Engine/Plugins/Runtime/PhysXVehicles/Source/PhysXVehicles/Private/WheeledVehicle.cpp +++ b/Engine/Plugins/Runtime/PhysXVehicles/Source/PhysXVehicles/Private/WheeledVehicle.cpp @@ -50,7 +50,3 @@ class UWheeledVehicleMovementComponent* AWheeledVehicle::GetVehicleMovementCompo return VehicleMovement; } -/** Returns Mesh subobject **/ -USkeletalMeshComponent* AWheeledVehicle::GetMesh() const { return Mesh; } -/** Returns VehicleMovement subobject **/ -UWheeledVehicleMovementComponent* AWheeledVehicle::GetVehicleMovement() const { return VehicleMovement; } diff --git a/Engine/Plugins/Runtime/PhysXVehicles/Source/PhysXVehicles/Private/WheeledVehicleMovementComponent.cpp b/Engine/Plugins/Runtime/PhysXVehicles/Source/PhysXVehicles/Private/WheeledVehicleMovementComponent.cpp index 5335876d0f54..b692d2ba8764 100644 --- a/Engine/Plugins/Runtime/PhysXVehicles/Source/PhysXVehicles/Private/WheeledVehicleMovementComponent.cpp +++ b/Engine/Plugins/Runtime/PhysXVehicles/Source/PhysXVehicles/Private/WheeledVehicleMovementComponent.cpp @@ -150,6 +150,12 @@ void UWheeledVehicleMovementComponent::SetUpdatedComponent(USceneComponent* NewU //Skip PawnMovementComponent and simply set PawnOwner to null if we don't have a PawnActor as owner UNavMovementComponent::SetUpdatedComponent(NewUpdatedComponent); PawnOwner = NewUpdatedComponent ? Cast(NewUpdatedComponent->GetOwner()) : nullptr; + + if(USkeletalMeshComponent* SKC = Cast(NewUpdatedComponent)) + { + //TODO: this is a hack until we get proper local space kinematic support + SKC->bLocalSpaceKinematics = true; + } } bool UWheeledVehicleMovementComponent::CanCreateVehicle() const @@ -1018,6 +1024,8 @@ void UWheeledVehicleMovementComponent::UpdateState( float DeltaTime ) } } +/// @cond DOXYGEN_WARNINGS + bool UWheeledVehicleMovementComponent::ServerUpdateState_Validate(float InSteeringInput, float InThrottleInput, float InBrakeInput, float InHandbrakeInput, int32 InCurrentGear) { return true; @@ -1043,6 +1051,8 @@ void UWheeledVehicleMovementComponent::ServerUpdateState_Implementation(float In ReplicatedState.CurrentGear = InCurrentGear; } +/// @endcond + float UWheeledVehicleMovementComponent::CalcSteeringInput() { if (bUseRVOAvoidance) @@ -1712,6 +1722,7 @@ void UWheeledVehicleMovementComponent::PostEditChangeProperty( FPropertyChangedE #endif // WITH_EDITOR +/// @cond DOXYGEN_WARNINGS void UWheeledVehicleMovementComponent::GetLifetimeReplicatedProps( TArray< FLifetimeProperty > & OutLifetimeProps ) const { @@ -1720,6 +1731,8 @@ void UWheeledVehicleMovementComponent::GetLifetimeReplicatedProps( TArray< FLife DOREPLIFETIME( UWheeledVehicleMovementComponent, ReplicatedState ); } +/// @endcond + void UWheeledVehicleMovementComponent::ComputeConstants() { DragArea = ChassisWidth * ChassisHeight; diff --git a/Engine/Plugins/Runtime/PhysXVehicles/Source/PhysXVehicles/Public/WheeledVehicle.h b/Engine/Plugins/Runtime/PhysXVehicles/Source/PhysXVehicles/Public/WheeledVehicle.h index 7e6092213814..55d2448dfb71 100644 --- a/Engine/Plugins/Runtime/PhysXVehicles/Source/PhysXVehicles/Public/WheeledVehicle.h +++ b/Engine/Plugins/Runtime/PhysXVehicles/Source/PhysXVehicles/Public/WheeledVehicle.h @@ -24,14 +24,12 @@ class PHYSXVEHICLES_API AWheeledVehicle : public APawn { GENERATED_UCLASS_BODY() -private_subobject: +private: /** The main skeletal mesh associated with this Vehicle */ - DEPRECATED_FORGAME(4.6, "Mesh should not be accessed directly, please use GetMesh() function instead. Mesh will soon be private and your code will not compile.") UPROPERTY(Category = Vehicle, VisibleDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) class USkeletalMeshComponent* Mesh; /** vehicle simulation component */ - DEPRECATED_FORGAME(4.6, "VehicleMovement should not be accessed directly, please use GetVehicleMovement() function instead. VehicleMovement will soon be private and your code will not compile.") UPROPERTY(Category = Vehicle, VisibleDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) class UWheeledVehicleMovementComponent* VehicleMovement; public: @@ -50,7 +48,7 @@ public: //~ End Actor Interface /** Returns Mesh subobject **/ - class USkeletalMeshComponent* GetMesh() const; + class USkeletalMeshComponent* GetMesh() const { return Mesh; } /** Returns VehicleMovement subobject **/ - class UWheeledVehicleMovementComponent* GetVehicleMovement() const; + class UWheeledVehicleMovementComponent* GetVehicleMovement() const { return VehicleMovement; } }; diff --git a/Engine/Plugins/Runtime/ProceduralMeshComponent/Source/ProceduralMeshComponent/Private/ProceduralMeshComponent.cpp b/Engine/Plugins/Runtime/ProceduralMeshComponent/Source/ProceduralMeshComponent/Private/ProceduralMeshComponent.cpp index 4efa74bd2edb..46776c8ce677 100644 --- a/Engine/Plugins/Runtime/ProceduralMeshComponent/Source/ProceduralMeshComponent/Private/ProceduralMeshComponent.cpp +++ b/Engine/Plugins/Runtime/ProceduralMeshComponent/Source/ProceduralMeshComponent/Private/ProceduralMeshComponent.cpp @@ -844,17 +844,24 @@ bool UProceduralMeshComponent::ContainsPhysicsTriMeshData(bool InUseAllTriData) return false; } +UBodySetup* UProceduralMeshComponent::CreateBodySetupHelper() +{ + // The body setup in a template needs to be public since the property is Tnstanced and thus is the archetype of the instance meaning there is a direct reference + UBodySetup* NewBodySetup = NewObject(this, NAME_None, (IsTemplate() ? RF_Public : RF_NoFlags)); + NewBodySetup->BodySetupGuid = FGuid::NewGuid(); + + NewBodySetup->bGenerateMirroredCollision = false; + NewBodySetup->bDoubleSidedGeometry = true; + NewBodySetup->CollisionTraceFlag = bUseComplexAsSimpleCollision ? CTF_UseComplexAsSimple : CTF_UseDefault; + + return NewBodySetup; +} + void UProceduralMeshComponent::CreateProcMeshBodySetup() { - if (ProcMeshBodySetup == NULL) + if (ProcMeshBodySetup == nullptr) { - // The body setup in a template needs to be public since the property is Tnstanced and thus is the archetype of the instance meaning there is a direct reference - ProcMeshBodySetup = NewObject(this, NAME_None, (IsTemplate() ? RF_Public : RF_NoFlags)); - ProcMeshBodySetup->BodySetupGuid = FGuid::NewGuid(); - - ProcMeshBodySetup->bGenerateMirroredCollision = false; - ProcMeshBodySetup->bDoubleSidedGeometry = true; - ProcMeshBodySetup->CollisionTraceFlag = bUseComplexAsSimpleCollision ? CTF_UseComplexAsSimple : CTF_UseDefault; + ProcMeshBodySetup = CreateBodySetupHelper(); } } @@ -862,40 +869,62 @@ void UProceduralMeshComponent::UpdateCollision() { SCOPE_CYCLE_COUNTER(STAT_ProcMesh_UpdateCollision); - bool bCreatePhysState = false; // Should we create physics state at the end of this function? + UWorld* World = GetWorld(); + const bool bUseAsyncCook = World && World->IsGameWorld() && bUseAsyncCooking; - // If its created, shut it down now - if (bPhysicsStateCreated) + if(bUseAsyncCook) { - DestroyPhysicsState(); - bCreatePhysState = true; + AsyncBodySetupQueue.Add(CreateBodySetupHelper()); } - - // Ensure we have a BodySetup - CreateProcMeshBodySetup(); + else + { + AsyncBodySetupQueue.Empty(); //If for some reason we modified the async at runtime, just clear any pending async body setups + CreateProcMeshBodySetup(); + } + + UBodySetup* UseBodySetup = bUseAsyncCook ? AsyncBodySetupQueue.Last() : ProcMeshBodySetup; // Fill in simple collision convex elements - ProcMeshBodySetup->AggGeom.ConvexElems = CollisionConvexElems; + UseBodySetup->AggGeom.ConvexElems = CollisionConvexElems; // Set trace flag - ProcMeshBodySetup->CollisionTraceFlag = bUseComplexAsSimpleCollision ? CTF_UseComplexAsSimple : CTF_UseDefault; + UseBodySetup->CollisionTraceFlag = bUseComplexAsSimpleCollision ? CTF_UseComplexAsSimple : CTF_UseDefault; - // New GUID as collision has changed - ProcMeshBodySetup->BodySetupGuid = FGuid::NewGuid(); - // Also we want cooked data for this - ProcMeshBodySetup->bHasCookedCollisionData = true; - -#if WITH_PHYSX && (WITH_RUNTIME_PHYSICS_COOKING || WITH_EDITOR) - // Clear current mesh data - ProcMeshBodySetup->InvalidatePhysicsData(); - // Create new mesh data - ProcMeshBodySetup->CreatePhysicsMeshes(); -#endif // WITH_RUNTIME_PHYSICS_COOKING || WITH_EDITOR - - // Create new instance state if desired - if (bCreatePhysState) + if(bUseAsyncCook) { - CreatePhysicsState(); + UseBodySetup->CreatePhysicsMeshesAsync(FOnAsyncPhysicsCookFinished::CreateUObject(this, &UProceduralMeshComponent::FinishPhysicsAsyncCook, UseBodySetup)); + } + else + { + // New GUID as collision has changed + UseBodySetup->BodySetupGuid = FGuid::NewGuid(); + // Also we want cooked data for this + UseBodySetup->bHasCookedCollisionData = true; + UseBodySetup->InvalidatePhysicsData(); + UseBodySetup->CreatePhysicsMeshes(); + RecreatePhysicsState(); + } +} + +void UProceduralMeshComponent::FinishPhysicsAsyncCook(UBodySetup* FinishedBodySetup) +{ + TArray NewQueue; + NewQueue.Reserve(AsyncBodySetupQueue.Num()); + + int32 FoundIdx; + if(AsyncBodySetupQueue.Find(FinishedBodySetup, FoundIdx)) + { + //The new body was found in the array meaning it's newer so use it + ProcMeshBodySetup = FinishedBodySetup; + RecreatePhysicsState(); + + //remove any async body setups that were requested before this one + for(int32 AsyncIdx = FoundIdx+1; AsyncIdx < AsyncBodySetupQueue.Num(); ++AsyncIdx) + { + NewQueue.Add(AsyncBodySetupQueue[AsyncIdx]); + } + + AsyncBodySetupQueue = NewQueue; } } diff --git a/Engine/Plugins/Runtime/ProceduralMeshComponent/Source/ProceduralMeshComponent/Public/ProceduralMeshComponent.h b/Engine/Plugins/Runtime/ProceduralMeshComponent/Source/ProceduralMeshComponent/Public/ProceduralMeshComponent.h index 7e2e097e8962..31430fb970e5 100644 --- a/Engine/Plugins/Runtime/ProceduralMeshComponent/Source/ProceduralMeshComponent/Public/ProceduralMeshComponent.h +++ b/Engine/Plugins/Runtime/ProceduralMeshComponent/Source/ProceduralMeshComponent/Public/ProceduralMeshComponent.h @@ -45,7 +45,7 @@ struct FProcMeshTangent }; /** One vertex for the procedural mesh, used for storing data internally */ -USTRUCT() +USTRUCT(BlueprintType) struct FProcMeshVertex { GENERATED_USTRUCT_BODY() @@ -229,6 +229,12 @@ class PROCEDURALMESHCOMPONENT_API UProceduralMeshComponent : public UMeshCompone UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Procedural Mesh") bool bUseComplexAsSimpleCollision; + /** + * Controls whether the physics cooking should be done off the game thread. This should be used when collision geometry doesn't have to be immediately up to date (For example streaming in far away objects) + */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Procedural Mesh") + bool bUseAsyncCooking; + /** Collision data */ UPROPERTY(Instanced) class UBodySetup* ProcMeshBodySetup; @@ -269,6 +275,11 @@ private: void CreateProcMeshBodySetup(); /** Mark collision data as dirty, and re-create on instance if necessary */ void UpdateCollision(); + /** Once async physics cook is done, create needed state */ + void FinishPhysicsAsyncCook(UBodySetup* FinishedBodySetup); + + /** Helper to create new body setup objects */ + UBodySetup* CreateBodySetupHelper(); /** Array of sections of mesh */ UPROPERTY() @@ -281,7 +292,10 @@ private: /** Local space bounds of mesh */ UPROPERTY() FBoxSphereBounds LocalBounds; - + + /** Queue for async body setups that are being cooked */ + UPROPERTY(transient) + TArray AsyncBodySetupQueue; friend class FProceduralMeshSceneProxy; }; diff --git a/Engine/Plugins/Runtime/RuntimePhysXCooking/RuntimePhysXCooking.uplugin b/Engine/Plugins/Runtime/RuntimePhysXCooking/RuntimePhysXCooking.uplugin new file mode 100644 index 000000000000..8735ace67c58 --- /dev/null +++ b/Engine/Plugins/Runtime/RuntimePhysXCooking/RuntimePhysXCooking.uplugin @@ -0,0 +1,25 @@ +{ + "FileVersion" : 3, + "Version" : 1, + "VersionName" : "1.0", + "FriendlyName" : "Runtime PhysX Cooking", + "Description" : "Runtime cooking of physics data (convex hulls, heightfields, etc...)", + "Category" : "Physics", + "CreatedBy" : "Epic Games, Inc.", + "CreatedByURL" : "http://epicgames.com", + "DocsURL" : "", + "MarketplaceURL" : "", + "SupportURL" : "", + "EnabledByDefault" : true, + "CanContainContent" : false, + "IsBetaVersion" : false, + "Installed" : false, + "Modules" : + [ + { + "Name" : "RuntimePhysXCooking", + "Type" : "Runtime", + "LoadingPhase" : "PreDefault" + } + ] +} diff --git a/Engine/Plugins/Runtime/RuntimePhysXCooking/Source/RuntimePhysXCooking/Private/RuntimePhysXCooking.cpp b/Engine/Plugins/Runtime/RuntimePhysXCooking/Source/RuntimePhysXCooking/Private/RuntimePhysXCooking.cpp new file mode 100644 index 000000000000..a80832374e3e --- /dev/null +++ b/Engine/Plugins/Runtime/RuntimePhysXCooking/Source/RuntimePhysXCooking/Private/RuntimePhysXCooking.cpp @@ -0,0 +1,25 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "ModuleManager.h" +#include "PhysXCooking.h" + +/** + * FRuntimePhysXCooking. Cooks physics data at runtime +**/ +class FRuntimePhysXCooking : public FPhysXCooking +{ + //This is just a wrapper for the engine module, but we are able to use it dynamically via plugin +}; + + +/** + * Module for PhysX cooking at runtime + */ + +class FRuntimePhysXPlatformModule : public FPhysXPlatformModule +{ + //This is just a wrapper for the engine module, but we are able to use it dynamically via plugin + +}; + +IMPLEMENT_MODULE(FRuntimePhysXPlatformModule, RuntimePhysXCooking ); diff --git a/Engine/Plugins/Runtime/RuntimePhysXCooking/Source/RuntimePhysXCooking/RuntimePhysXCooking.Build.cs b/Engine/Plugins/Runtime/RuntimePhysXCooking/Source/RuntimePhysXCooking/RuntimePhysXCooking.Build.cs new file mode 100644 index 000000000000..60511b84ad98 --- /dev/null +++ b/Engine/Plugins/Runtime/RuntimePhysXCooking/Source/RuntimePhysXCooking/RuntimePhysXCooking.Build.cs @@ -0,0 +1,21 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +using UnrealBuildTool; +using System.IO; + +public class RuntimePhysXCooking : ModuleRules +{ + public RuntimePhysXCooking(ReadOnlyTargetRules Target) : base(Target) + { + PrivateDependencyModuleNames.AddRange( + new string[] { + "Core", + "CoreUObject", // @todo Mac: for some reason it's needed to link in debug on Mac + "Engine", + "PhysXCooking" + } + ); + + SetupModulePhysXAPEXSupport(Target); + } +} diff --git a/Engine/Plugins/Runtime/SoundUtilities/Source/SoundUtilities/Private/SoundUtilitiesModule.cpp b/Engine/Plugins/Runtime/SoundUtilities/Source/SoundUtilities/Private/SoundUtilitiesModule.cpp index 3d7d0613220f..51389721df14 100644 --- a/Engine/Plugins/Runtime/SoundUtilities/Source/SoundUtilities/Private/SoundUtilitiesModule.cpp +++ b/Engine/Plugins/Runtime/SoundUtilities/Source/SoundUtilities/Private/SoundUtilitiesModule.cpp @@ -8,7 +8,7 @@ DEFINE_LOG_CATEGORY(LogSoundUtilities); -IMPLEMENT_MODULE(FSoundUtilitiesModule, FSynthesis) +IMPLEMENT_MODULE(FSoundUtilitiesModule, SoundUtilities) void FSoundUtilitiesModule::StartupModule() { diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Phonon.tps b/Engine/Plugins/Runtime/Steam/SteamAudio/Phonon.tps new file mode 100644 index 000000000000..ff3405d3732d --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Phonon.tps @@ -0,0 +1,9 @@ + + + + /Engine/Plugins/Runtime/Steam/SteamAudio/ + +Redirect: ../../../../Source/ThirdParty/libPhonon/LibPhonon.tps + + + \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononCommon.cpp b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononCommon.cpp similarity index 66% rename from Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononCommon.cpp rename to Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononCommon.cpp index 2a92b21bb65c..32455ead4d5c 100644 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononCommon.cpp +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononCommon.cpp @@ -1,22 +1,20 @@ // -// Copyright (C) Impulsonic, Inc. All rights reserved. +// Copyright (C) Valve Corporation. All rights reserved. // #include "PhononCommon.h" - +#include "Misc/Paths.h" #include "EngineUtils.h" #include "FileManager.h" #include "IPluginManager.h" -#include "Misc/Paths.h" #include "HAL/PlatformProcess.h" -DEFINE_LOG_CATEGORY(LogPhonon); +DEFINE_LOG_CATEGORY(LogSteamAudio); -static TMap GetRealtimeQualityPresets() +static TMap GetRealtimeQualityPresets() { - TMap Presets; - - SimulationQualitySettings Settings; + TMap Presets; + SteamAudio::FSimulationQualitySettings Settings; Settings.Bounces = 2; Settings.Rays = 4096; @@ -41,25 +39,24 @@ static TMap GetRealtimeQualityPrese return Presets; } -static TMap GetBakedQualityPresets() +static TMap GetBakedQualityPresets() { - TMap Presets; + TMap Presets; + SteamAudio::FSimulationQualitySettings Settings; - SimulationQualitySettings Settings; - - Settings.Bounces = 128; + Settings.Bounces = 64; Settings.Rays = 16384; Settings.SecondaryRays = 2048; Presets.Add(EQualitySettings::LOW, Settings); - Settings.Bounces = 256; + Settings.Bounces = 128; Settings.Rays = 32768; Settings.SecondaryRays = 4096; Presets.Add(EQualitySettings::MEDIUM, Settings); - Settings.Bounces = 512; + Settings.Bounces = 256; Settings.Rays = 65536; - Settings.SecondaryRays = 4096; + Settings.SecondaryRays = 8192; Presets.Add(EQualitySettings::HIGH, Settings); Settings.Bounces = 0; @@ -70,11 +67,11 @@ static TMap GetBakedQualityPresets( return Presets; } -TMap RealtimeSimulationQualityPresets = GetRealtimeQualityPresets(); -TMap BakedSimulationQualityPresets = GetBakedQualityPresets(); - -namespace Phonon +namespace SteamAudio { + TMap RealtimeSimulationQualityPresets = GetRealtimeQualityPresets(); + TMap BakedSimulationQualityPresets = GetBakedQualityPresets(); + static void* UnrealAlloc(const size_t size, const size_t alignment) { return FMemory::Malloc(size, alignment); @@ -88,7 +85,7 @@ namespace Phonon static void UnrealLog(char* msg) { FString Message(msg); - UE_LOG(LogPhonon, Log, TEXT("%s"), *Message); + UE_LOG(LogSteamAudio, Log, TEXT("%s"), *Message); } const IPLContext GlobalContext = @@ -97,9 +94,6 @@ namespace Phonon nullptr, //UnrealAlloc, nullptr //UnrealFree }; - - // 1 Unreal Unit = 1cm, 1 Phonon Unit = 1m - static const float PHONON_SCALEFACTOR = 0.01f; FVector UnrealToPhononFVector(const FVector& UnrealCoords, const bool bScale) { @@ -107,7 +101,7 @@ namespace Phonon PhononCoords.X = UnrealCoords.Y; PhononCoords.Y = UnrealCoords.Z; PhononCoords.Z = -UnrealCoords.X; - return bScale ? PhononCoords * PHONON_SCALEFACTOR : PhononCoords; + return bScale ? PhononCoords * SCALEFACTOR : PhononCoords; } IPLVector3 UnrealToPhononIPLVector3(const FVector& UnrealCoords, const bool bScale) @@ -119,9 +113,9 @@ namespace Phonon if (bScale) { - PhononCoords.x *= PHONON_SCALEFACTOR; - PhononCoords.y *= PHONON_SCALEFACTOR; - PhononCoords.z *= PHONON_SCALEFACTOR; + PhononCoords.x *= SCALEFACTOR; + PhononCoords.y *= SCALEFACTOR; + PhononCoords.z *= SCALEFACTOR; } return PhononCoords; @@ -136,9 +130,9 @@ namespace Phonon if (bScale) { - UnrealCoords.X /= PHONON_SCALEFACTOR; - UnrealCoords.Y /= PHONON_SCALEFACTOR; - UnrealCoords.Z /= PHONON_SCALEFACTOR; + UnrealCoords.X /= SCALEFACTOR; + UnrealCoords.Y /= SCALEFACTOR; + UnrealCoords.Z /= SCALEFACTOR; } return UnrealCoords; @@ -171,17 +165,9 @@ namespace Phonon return Vector; } - void LogPhononStatus(IPLerror Status) - { - if (Status != IPL_STATUS_SUCCESS) - { - UE_LOG(LogPhonon, Error, TEXT("Error: %s"), *ErrorCodeToFString(Status)); - } - } - void* LoadDll(const FString& DllFile) { - UE_LOG(LogPhonon, Log, TEXT("Attempting to load %s"), *DllFile); + UE_LOG(LogSteamAudio, Log, TEXT("Attempting to load %s"), *DllFile); void* DllHandle = nullptr; @@ -191,27 +177,35 @@ namespace Phonon } else { - UE_LOG(LogPhonon, Error, TEXT("File does not exist. %s"), *DllFile); + UE_LOG(LogSteamAudio, Error, TEXT("File does not exist. %s"), *DllFile); } if (!DllHandle) { - UE_LOG(LogPhonon, Error, TEXT("Unable to load %s."), *DllFile); + UE_LOG(LogSteamAudio, Error, TEXT("Unable to load %s."), *DllFile); } else { - UE_LOG(LogPhonon, Log, TEXT("Loaded %s."), *DllFile); + UE_LOG(LogSteamAudio, Log, TEXT("Loaded %s."), *DllFile); } return DllHandle; } - /** - * Returns a string representing the given error code. - */ - FString ErrorCodeToFString(const IPLerror ErrorCode) + void LogSteamAudioStatus(const IPLerror Status) { - switch (ErrorCode) + if (Status != IPL_STATUS_SUCCESS) + { + UE_LOG(LogSteamAudio, Error, TEXT("Error: %s"), *StatusToFString(Status)); + } + } + + /** + * Returns a string representing the given status. + */ + FString StatusToFString(const IPLerror Status) + { + switch (Status) { case IPL_STATUS_SUCCESS: return FString(TEXT("Success.")); diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononCommon.h b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononCommon.h similarity index 52% rename from Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononCommon.h rename to Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononCommon.h index 77bb38aba92a..114e14bfdc1d 100644 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononCommon.h +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononCommon.h @@ -1,5 +1,5 @@ // -// Copyright (C) Impulsonic, Inc. All rights reserved. +// Copyright (C) Valve Corporation. All rights reserved. // #pragma once @@ -8,14 +8,7 @@ #include "CoreMinimal.h" #include "UObject/ObjectMacros.h" -DECLARE_LOG_CATEGORY_EXTERN(LogPhonon, Log, All); - -struct SimulationQualitySettings -{ - int32 Bounces; - int32 Rays; - int32 SecondaryRays; -}; +DECLARE_LOG_CATEGORY_EXTERN(LogSteamAudio, Log, All); UENUM(BlueprintType) enum class EQualitySettings : uint8 @@ -26,9 +19,6 @@ enum class EQualitySettings : uint8 CUSTOM UMETA(DisplayName = "Custom") }; -extern TMap RealtimeSimulationQualityPresets; -extern TMap BakedSimulationQualityPresets; - UENUM(BlueprintType) enum class EIplSpatializationMethod : uint8 { @@ -65,39 +55,47 @@ enum class EIplSimulationType : uint8 REALTIME UMETA(DisplayName = "Real-Time"), // Precompute indirect sound. BAKED UMETA(DisplayName = "Baked"), + // Do not simulate indirect sound. DISABLED UMETA(DisplayName = "Disabled") }; -UENUM(BlueprintType) -enum class EIplIndirectSpatializationMethod : uint8 -{ - PANNING UMETA(DisplayName = "Panning"), - HRTF UMETA(DisplayName = "HRTF") -}; - UENUM(BlueprintType) enum class EIplAudioEngine : uint8 { - UNREAL UMETA(DisplayName = "Unreal"), - FMOD UMETA(DisplayName = "FMOD"), - WWISE UMETA(DisplayName = "Wwise") + // Native Unreal audio engine. + UNREAL UMETA(DisplayName = "Unreal") }; -namespace Phonon +namespace SteamAudio { - extern const IPLContext PHONON_API GlobalContext; + struct FSimulationQualitySettings + { + int32 Bounces; + int32 Rays; + int32 SecondaryRays; + }; - IPLVector3 PHONON_API IPLVector3FromFVector(const FVector& Coords); - FVector PHONON_API FVectorFromIPLVector3(const IPLVector3& Coords); + // 1 Unreal Unit = 1cm, 1 Phonon Unit = 1m + const float SCALEFACTOR = 0.01f; - FVector PHONON_API UnrealToPhononFVector(const FVector& Coords, const bool bScale = true); - IPLVector3 PHONON_API UnrealToPhononIPLVector3(const FVector& Coords, const bool bScale = true); - FVector PHONON_API PhononToUnrealFVector(const FVector& Coords, const bool bScale = true); - IPLVector3 PHONON_API PhononToUnrealIPLVector3(const FVector& Coords, const bool bScale = true); + extern TMap RealtimeSimulationQualityPresets; + extern TMap BakedSimulationQualityPresets; - void LogPhononStatus(IPLerror Status); + extern const IPLContext STEAMAUDIO_API GlobalContext; + IPLVector3 STEAMAUDIO_API IPLVector3FromFVector(const FVector& Coords); + FVector STEAMAUDIO_API FVectorFromIPLVector3(const IPLVector3& Coords); + FVector STEAMAUDIO_API UnrealToPhononFVector(const FVector& Coords, const bool bScale = true); + IPLVector3 STEAMAUDIO_API UnrealToPhononIPLVector3(const FVector& Coords, const bool bScale = true); + FVector STEAMAUDIO_API PhononToUnrealFVector(const FVector& Coords, const bool bScale = true); + IPLVector3 STEAMAUDIO_API PhononToUnrealIPLVector3(const FVector& Coords, const bool bScale = true); + + /** Attempts to loads the specified DLL, performing some basic error checking. Returns handle to DLL or nullptr on error.*/ void* LoadDll(const FString& DllFile); - FString ErrorCodeToFString(const IPLerror ErrorCode); -} + /** Error logs non-successful statuses. */ + void LogSteamAudioStatus(const IPLerror Status); + + /** Converts IPL statuses to a readable FString. */ + FString StatusToFString(const IPLerror Status); +} diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononGeometryComponent.cpp b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononGeometryComponent.cpp new file mode 100644 index 000000000000..747ebe694a18 --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononGeometryComponent.cpp @@ -0,0 +1,48 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#include "PhononGeometryComponent.h" +#include "PhononScene.h" +#include "Engine/StaticMeshActor.h" +#include "StaticMeshResources.h" + +UPhononGeometryComponent::UPhononGeometryComponent() + : ExportAllChildren(false) + , NumVertices(0) + , NumTriangles(0) +{ +} + +void UPhononGeometryComponent::UpdateStatistics() +{ + if (ExportAllChildren) + { + NumTriangles = SteamAudio::GetNumTrianglesAtRoot(GetOwner()); + } + else + { + NumTriangles = SteamAudio::GetNumTrianglesForStaticMesh(Cast(GetOwner())); + } + + NumVertices = NumTriangles * 3; +} + +#if WITH_EDITOR +void UPhononGeometryComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) +{ + FName PropertyName = (PropertyChangedEvent.Property != nullptr) ? PropertyChangedEvent.Property->GetFName() : NAME_None; + + if ((PropertyName == GET_MEMBER_NAME_CHECKED(UPhononGeometryComponent, ExportAllChildren))) + { + UpdateStatistics(); + } +} +#endif + +void UPhononGeometryComponent::OnComponentCreated() +{ + Super::OnComponentCreated(); + + UpdateStatistics(); +} diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononGeometryComponent.h b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononGeometryComponent.h new file mode 100644 index 000000000000..e33fac1e2520 --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononGeometryComponent.h @@ -0,0 +1,42 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#pragma once + +#include "Components/ActorComponent.h" +#include "PhononGeometryComponent.generated.h" + +/** + * Phonon Geometry components are used to tag an actor as containing geometry relevant to acoustics calculations. + * Should be placed on Static Mesh actors. + */ +UCLASS(ClassGroup = (Audio), HideCategories = (Activation, Collision, Cooking), meta = (BlueprintSpawnableComponent)) +class UPhononGeometryComponent : public UActorComponent +{ + GENERATED_BODY() + +public: + UPhononGeometryComponent(); + + void OnComponentCreated(); + +#if WITH_EDITOR + virtual void PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) override; +#endif + + // Whether or not to export all actors attached to this actor. + UPROPERTY(EditAnywhere, Category = Settings) + bool ExportAllChildren; + + // The number of vertices exported to Steam Audio. + UPROPERTY(VisibleAnywhere, Category = GeometryStatistics, meta = (DisplayName = "Vertices")) + uint32 NumVertices; + + // The number of triangles exported to Steam Audio. + UPROPERTY(VisibleAnywhere, Category = GeometryStatistics, meta = (DisplayName = "Triangles")) + uint32 NumTriangles; + +private: + void UpdateStatistics(); +}; \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononListenerComponent.cpp b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononListenerObserver.cpp similarity index 51% rename from Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononListenerComponent.cpp rename to Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononListenerObserver.cpp index d805ff569f29..fd3029c2fd49 100644 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononListenerComponent.cpp +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononListenerObserver.cpp @@ -1,49 +1,56 @@ // -// Copyright (C) Impulsonic, Inc. All rights reserved. +// Copyright (C) Valve Corporation. All rights reserved. // -#include "PhononListenerComponent.h" -#include "PhononModule.h" +#include "PhononListenerObserver.h" +#include "SteamAudioModule.h" #include "PhononOcclusion.h" #include "PhononReverb.h" +#include "AudioDevice.h" -namespace Phonon +namespace SteamAudio { FPhononListenerObserver::FPhononListenerObserver() : bEnvironmentCreated(false) - , PhononModule(nullptr) + , SteamAudioModule(nullptr) { - } FPhononListenerObserver::~FPhononListenerObserver() { - } - void FPhononListenerObserver::OnListenerUpdated(FAudioDevice* AudioDevice, UWorld* ListenerWorld, const int32 ViewportIndex, const FTransform& ListenerTransform, const float InDeltaSeconds) + void FPhononListenerObserver::OnListenerUpdated(FAudioDevice* AudioDevice, UWorld* ListenerWorld, const int32 ViewportIndex, + const FTransform& ListenerTransform, const float InDeltaSeconds) { // TODO: SUPPORT MULTIPLE WORLDS +#if WITH_EDITOR + if (AudioDevice->IsMainAudioDevice()) + { + return; + } +#endif + if (!bEnvironmentCreated) { bEnvironmentCreated = true; - PhononModule = &FModuleManager::GetModuleChecked("Phonon"); - PhononModule->CreateEnvironment(ListenerWorld, AudioDevice); + SteamAudioModule = &FModuleManager::GetModuleChecked("SteamAudio"); + SteamAudioModule->CreateEnvironment(ListenerWorld, AudioDevice); } - check(PhononModule); + check(SteamAudioModule); FVector Position = ListenerTransform.GetLocation(); FVector Forward = ListenerTransform.GetUnitAxis(EAxis::Y); FVector Up = ListenerTransform.GetUnitAxis(EAxis::Z); - Phonon::FPhononOcclusion* OcclusionInstance = PhononModule->GetOcclusionInstance(); + SteamAudio::FPhononOcclusion* OcclusionInstance = SteamAudioModule->GetOcclusionInstance(); if (OcclusionInstance) { OcclusionInstance->UpdateDirectSoundSources(Position, Forward, Up); } - Phonon::FPhononReverb* ReverbInstance = PhononModule->GetReverbInstance(); + SteamAudio::FPhononReverb* ReverbInstance = SteamAudioModule->GetReverbInstance(); if (ReverbInstance) { ReverbInstance->UpdateListener(Position, Forward, Up); @@ -55,8 +62,8 @@ namespace Phonon if (bEnvironmentCreated) { bEnvironmentCreated = false; - PhononModule->DestroyEnvironment(AudioDevice); - PhononModule = nullptr; + SteamAudioModule->DestroyEnvironment(AudioDevice); + SteamAudioModule = nullptr; } } } diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononListenerComponent.h b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononListenerObserver.h similarity index 53% rename from Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononListenerComponent.h rename to Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononListenerObserver.h index 1f0b1a0ee239..5d2cb9173584 100644 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononListenerComponent.h +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononListenerObserver.h @@ -1,13 +1,12 @@ // -// Copyright (C) Impulsonic, Inc. All rights reserved. +// Copyright (C) Valve Corporation. All rights reserved. // #pragma once -#include "Components/SceneComponent.h" -#include "PhononModule.h" +#include "SteamAudioModule.h" -namespace Phonon +namespace SteamAudio { class FPhononListenerObserver : public IAudioListenerObserver { @@ -15,13 +14,12 @@ namespace Phonon FPhononListenerObserver(); ~FPhononListenerObserver(); - virtual void OnListenerUpdated(FAudioDevice* AudioDevice, UWorld* ListenerWorld, const int32 ViewportIndex, const FTransform& ListenerTransform, const float InDeltaSeconds) override; + virtual void OnListenerUpdated(FAudioDevice* AudioDevice, UWorld* ListenerWorld, const int32 ViewportIndex, + const FTransform& ListenerTransform, const float InDeltaSeconds) override; virtual void OnListenerShutdown(FAudioDevice* AudioDevice) override; protected: bool bEnvironmentCreated; - FPhononModule* PhononModule; + FSteamAudioModule* SteamAudioModule; }; } - - diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononMaterial.cpp b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononMaterial.cpp similarity index 92% rename from Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononMaterial.cpp rename to Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononMaterial.cpp index 0fcc12052874..3d5ff5acc116 100644 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononMaterial.cpp +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononMaterial.cpp @@ -1,5 +1,5 @@ // -// Copyright (C) Impulsonic, Inc. All rights reserved. +// Copyright (C) Valve Corporation. All rights reserved. // #include "PhononMaterial.h" @@ -74,5 +74,4 @@ static TMap GetMaterialPresets() return Presets; } -TMap Phonon::MaterialPresets = GetMaterialPresets(); - +TMap SteamAudio::MaterialPresets = GetMaterialPresets(); diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononMaterial.h b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononMaterial.h similarity index 89% rename from Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononMaterial.h rename to Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononMaterial.h index 94f11a7eb975..4909b3f73faa 100644 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononMaterial.h +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononMaterial.h @@ -1,5 +1,5 @@ // -// Copyright (C) Impulsonic, Inc. All rights reserved. +// Copyright (C) Valve Corporation. All rights reserved. // #pragma once @@ -7,7 +7,6 @@ #include "CoreMinimal.h" #include "UObject/ObjectMacros.h" #include "phonon.h" -#include UENUM() enum class EPhononMaterial : uint8 @@ -26,7 +25,7 @@ enum class EPhononMaterial : uint8 CUSTOM = 11 UMETA(DisplayName = "Custom") }; -namespace Phonon +namespace SteamAudio { extern TMap MaterialPresets; } \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononMaterialComponent.cpp b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononMaterialComponent.cpp similarity index 88% rename from Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononMaterialComponent.cpp rename to Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononMaterialComponent.cpp index be2db1665ace..70c27192ab32 100644 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononMaterialComponent.cpp +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononMaterialComponent.cpp @@ -1,13 +1,14 @@ // -// Copyright (C) Impulsonic, Inc. All rights reserved. +// Copyright (C) Valve Corporation. All rights reserved. // #include "PhononMaterialComponent.h" UPhononMaterialComponent::UPhononMaterialComponent() : MaterialPreset(EPhononMaterial::GENERIC) + , MaterialIndex(0) { - IPLMaterial SelectedMaterialPreset = Phonon::MaterialPresets[MaterialPreset]; + IPLMaterial SelectedMaterialPreset = SteamAudio::MaterialPresets[MaterialPreset]; LowFreqAbsorption = SelectedMaterialPreset.lowFreqAbsorption; MidFreqAbsorption = SelectedMaterialPreset.midFreqAbsorption; HighFreqAbsorption = SelectedMaterialPreset.highFreqAbsorption; @@ -30,7 +31,7 @@ void UPhononMaterialComponent::PostEditChangeProperty(struct FPropertyChangedEve { FName PropertyName = (PropertyChangedEvent.Property != NULL) ? PropertyChangedEvent.Property->GetFName() : NAME_None; - IPLMaterial SelectedMaterialPreset = Phonon::MaterialPresets[MaterialPreset]; + IPLMaterial SelectedMaterialPreset = SteamAudio::MaterialPresets[MaterialPreset]; if ((PropertyName == GET_MEMBER_NAME_CHECKED(UPhononMaterialComponent, MaterialPreset))) { @@ -58,4 +59,4 @@ bool UPhononMaterialComponent::CanEditChange(const UProperty* InProperty) const return ParentVal; } } -#endif \ No newline at end of file +#endif diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononMaterialComponent.h b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononMaterialComponent.h similarity index 69% rename from Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononMaterialComponent.h rename to Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononMaterialComponent.h index 18357046c239..4f4f7dba2dc8 100644 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononMaterialComponent.h +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononMaterialComponent.h @@ -1,10 +1,10 @@ // -// Copyright (C) Impulsonic, Inc. All rights reserved. +// Copyright (C) Valve Corporation. All rights reserved. // #pragma once -#include "PhononSettings.h" +#include "PhononMaterial.h" #include "Components/ActorComponent.h" #include "PhononMaterialComponent.generated.h" @@ -12,7 +12,7 @@ * Phonon Material components are used to customize an actor's acoustic properties. Only valid on actors that also * have a Phonon Geometry component. */ -UCLASS(ClassGroup = (Audio), HideCategories = (Activation, Collision), meta = (BlueprintSpawnableComponent)) +UCLASS(ClassGroup = (Audio), HideCategories = (Activation, Collision, Cooking), meta = (BlueprintSpawnableComponent)) class UPhononMaterialComponent : public UActorComponent { GENERATED_BODY() @@ -30,18 +30,24 @@ public: UPROPERTY() int32 MaterialIndex; + // Choose from a variety of preset physical materials, or choose Custom to specify values manually. UPROPERTY(EditAnywhere, Category = Settings) EPhononMaterial MaterialPreset; + // How much this material absorbs low frequency sound. UPROPERTY(EditAnywhere, Category = Settings, meta = (ClampMin = "0.0", ClampMax = "1.0", UIMin = "0.0", UIMax = "1.0")) float LowFreqAbsorption; + // How much this material absorbs mid frequency sound. UPROPERTY(EditAnywhere, Category = Settings, meta = (ClampMin = "0.0", ClampMax = "1.0", UIMin = "0.0", UIMax = "1.0")) float MidFreqAbsorption; + // How much this material absorbs high frequency sound. UPROPERTY(EditAnywhere, Category = Settings, meta = (ClampMin = "0.0", ClampMax = "1.0", UIMin = "0.0", UIMax = "1.0")) float HighFreqAbsorption; + // Specifies how "rough" the surface is. Surfaces with a high scattering value randomly reflect sound in all directions; + // surfaces with a low scattering value reflect sound in a mirror-like manner. UPROPERTY(EditAnywhere, Category = Settings, meta = (ClampMin = "0.0", ClampMax = "1.0", UIMin = "0.0", UIMax = "1.0")) float Scattering; }; \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononOcclusion.cpp b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononOcclusion.cpp new file mode 100644 index 000000000000..6856bbdc8407 --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononOcclusion.cpp @@ -0,0 +1,225 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#include "PhononOcclusion.h" +#include "PhononOcclusionSourceSettings.h" +#include "PhononCommon.h" +#include "SteamAudioModule.h" +#include "ScopeLock.h" + +//================================================================================================================================================== +// FPhononOcclusion +//================================================================================================================================================== + +namespace SteamAudio +{ + FPhononOcclusion::FPhononOcclusion() + : EnvironmentalRenderer(nullptr) + , SteamAudioModule(nullptr) + { + } + + FPhononOcclusion::~FPhononOcclusion() + { + } + + void FPhononOcclusion::Initialize(const int32 SampleRate, const int32 NumSources) + { + DirectSoundSources.SetNum(NumSources); + + SteamAudioModule = &FModuleManager::GetModuleChecked("SteamAudio"); + SteamAudioModule->SetSampleRate(SampleRate); + } + + void FPhononOcclusion::OnInitSource(const uint32 SourceId, const FName& AudioComponentUserId, UOcclusionPluginSourceSettingsBase* InSettings) + { + if (!EnvironmentalRenderer) + { + UE_LOG(LogSteamAudio, Error, TEXT("Unable to find environmental renderer for occlusion. Audio will not be occluded. Make sure to export the scene.")); + return; + } + + UE_LOG(LogSteamAudio, Log, TEXT("Creating occlusion effect.")); + + UPhononOcclusionSourceSettings* OcclusionSettings = CastChecked(InSettings); + DirectSoundSources[SourceId].bDirectAttenuation = OcclusionSettings->DirectAttenuation; + DirectSoundSources[SourceId].DirectOcclusionMethod = OcclusionSettings->DirectOcclusionMethod; + DirectSoundSources[SourceId].Radius = OcclusionSettings->DirectOcclusionSourceRadius; + + const int32 NumInterpolationFrames = 4; + DirectSoundSources[SourceId].DirectLerp.Init(NumInterpolationFrames); + } + + void FPhononOcclusion::OnReleaseSource(const uint32 SourceId) + { + UE_LOG(LogSteamAudio, Log, TEXT("Destroying occlusion effect.")); + } + + void FPhononOcclusion::ProcessAudio(const FAudioPluginSourceInputData& InputData, FAudioPluginSourceOutputData& OutputData) + { + if (!EnvironmentalRenderer) + { + FMemory::Memcpy(OutputData.AudioBuffer.GetData(), InputData.AudioBuffer->GetData(), InputData.AudioBuffer->Num() * sizeof(float)); + return; + } + + auto& DirectSoundSource = DirectSoundSources[InputData.SourceId]; + float ConfiguredOcclusionFactor; + float ConfiguredAttenuationFactor; + + { + FScopeLock Lock(&DirectSoundSources[InputData.SourceId].CriticalSection); + DirectSoundSource.Position = SteamAudio::UnrealToPhononIPLVector3(InputData.SpatializationParams->EmitterWorldPosition); + DirectSoundSource.bNeedsUpdate = true; + ConfiguredOcclusionFactor = DirectSoundSource.DirectOcclusionMethod == EIplDirectOcclusionMethod::NONE ? + 1.0f : DirectSoundSource.DirectSoundPath.occlusionFactor; + ConfiguredAttenuationFactor = DirectSoundSource.bDirectAttenuation ? DirectSoundSource.DirectSoundPath.distanceAttenuation : 1.0f; + } + + DirectSoundSource.DirectLerp.Set(ConfiguredOcclusionFactor * ConfiguredAttenuationFactor); + float PerSampleIncrement; + int32 NumSamplesInFrame = InputData.AudioBuffer->Num() / InputData.NumChannels; + float LerpedAttenuationFactor = DirectSoundSource.DirectLerp.Update(PerSampleIncrement, NumSamplesInFrame); + + for (int32 i = 0, count = 0; i < NumSamplesInFrame; ++i) + { + for (int32 j = 0; j < InputData.NumChannels; ++j, ++count) + { + OutputData.AudioBuffer[count] = (*InputData.AudioBuffer)[count] * LerpedAttenuationFactor; + } + + LerpedAttenuationFactor += PerSampleIncrement; + } + } + + void FPhononOcclusion::UpdateDirectSoundSources(const FVector& ListenerPosition, const FVector& ListenerForward, const FVector& ListenerUp) + { + if (!EnvironmentalRenderer) + { + return; + } + + FScopeLock EnvironmentLock(&SteamAudioModule->GetEnvironmentCriticalSection()); + + for (FDirectSoundSource& DirectSoundSource : DirectSoundSources) + { + FScopeLock DirectSourceLock(&DirectSoundSource.CriticalSection); + + if (DirectSoundSource.bNeedsUpdate) + { + IPLDirectSoundPath DirectSoundPath = iplGetDirectSoundPath(EnvironmentalRenderer, SteamAudio::UnrealToPhononIPLVector3(ListenerPosition), + SteamAudio::UnrealToPhononIPLVector3(ListenerForward, false), SteamAudio::UnrealToPhononIPLVector3(ListenerUp, false), + DirectSoundSource.Position, DirectSoundSource.Radius * SteamAudio::SCALEFACTOR, + static_cast(DirectSoundSource.DirectOcclusionMethod)); + + DirectSoundSource.DirectSoundPath = DirectSoundPath; + DirectSoundSource.bNeedsUpdate = false; + } + } + } + + void FPhononOcclusion::SetEnvironmentalRenderer(IPLhandle InEnvironmentalRenderer) + { + EnvironmentalRenderer = InEnvironmentalRenderer; + } +} + +//================================================================================================================================================== +// FOcclusionSource +//================================================================================================================================================== + +namespace SteamAudio +{ + FDirectSoundSource::FDirectSoundSource() + : bNeedsUpdate(false) + { + DirectSoundPath.occlusionFactor = 1.0f; + DirectSoundPath.distanceAttenuation = 1.0f; + Position.x = Position.y = Position.z = 0.0f; + } +} + +//================================================================================================================================================== +// FAttenuationInterpolator +//================================================================================================================================================== + +namespace SteamAudio +{ + void FAttenuationInterpolator::Init(const int32 InterpolationFrames) + { + NumInterpFrames = InterpolationFrames; + FrameIndex = 0; + + StartValue = 0.0f; + EndValue = 0.0f; + CurrentValue = 0.0f; + NextValue = 0.0f; + bIsInit = true; + bIsDone = false; + } + + void FAttenuationInterpolator::Reset() + { + bIsInit = true; + } + + float FAttenuationInterpolator::Update(float& PerSampleIncrement, const int32 SamplesToInterpolate) + { + if (bIsDone) + { + PerSampleIncrement = 0.0f; + return CurrentValue; + } + else + { + float delta = 1.0f / NumInterpFrames; + float alpha = FrameIndex * delta; + if (alpha >= 1.0f) + { + bIsDone = true; + CurrentValue = EndValue; + NextValue = EndValue; + } + else if ((alpha + delta) >= 1.0f) + { + CurrentValue = FMath::Lerp(StartValue, EndValue, alpha); + NextValue = EndValue; + } + else + { + CurrentValue = FMath::Lerp(StartValue, EndValue, alpha); + NextValue = FMath::Lerp(StartValue, EndValue, alpha + delta); + } + + PerSampleIncrement = (NextValue - CurrentValue) / SamplesToInterpolate; + FrameIndex++; + return CurrentValue; + } + } + + void FAttenuationInterpolator::Set(const float AttenuationValue) + { + if (bIsInit || NumInterpFrames == 0) + { + bIsInit = false; + CurrentValue = AttenuationValue; + StartValue = AttenuationValue; + EndValue = AttenuationValue; + FrameIndex = NumInterpFrames; + bIsDone = NumInterpFrames == 0; + } + else + { + StartValue = NextValue; + EndValue = AttenuationValue; + FrameIndex = 0; + bIsDone = false; + } + } + + float FAttenuationInterpolator::Get() + { + return CurrentValue; + } +} diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononOcclusion.h b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononOcclusion.h new file mode 100644 index 000000000000..75436842f906 --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononOcclusion.h @@ -0,0 +1,69 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#pragma once + +#include "IAudioExtensionPlugin.h" +#include "PhononCommon.h" +#include "phonon.h" +#include "SteamAudioModule.h" + +class UOcclusionPluginSourceSettingsBase; + +namespace SteamAudio +{ + class FAttenuationInterpolator + { + public: + void Init(const int32 InterpolationFrames); + void Reset(); + float Update(float& PerSampleIncrement, const int32 SamplesToInterpolate); + void Set(const float AttenuationValue); + float Get(); + + private: + int32 FrameIndex; + int32 NumInterpFrames; + float CurrentValue; + float NextValue; + float StartValue; + float EndValue; + bool bIsDone; + bool bIsInit; + }; + + struct FDirectSoundSource + { + FDirectSoundSource(); + + FCriticalSection CriticalSection; + IPLDirectSoundPath DirectSoundPath; + EIplDirectOcclusionMethod DirectOcclusionMethod; + FAttenuationInterpolator DirectLerp; + IPLVector3 Position; + float Radius; + bool bDirectAttenuation; + bool bNeedsUpdate; + }; + + class FPhononOcclusion : public IAudioOcclusion + { + public: + FPhononOcclusion(); + ~FPhononOcclusion(); + + virtual void Initialize(const int32 SampleRate, const int32 NumSources) override; + virtual void OnInitSource(const uint32 SourceId, const FName& AudioComponentUserId, UOcclusionPluginSourceSettingsBase* InSettings) override; + virtual void OnReleaseSource(const uint32 SourceId) override; + virtual void ProcessAudio(const FAudioPluginSourceInputData& InputData, FAudioPluginSourceOutputData& OutputData) override; + + void UpdateDirectSoundSources(const FVector& ListenerPosition, const FVector& ListenerForward, const FVector& ListenerUp); + void SetEnvironmentalRenderer(IPLhandle EnvironmentalRenderer); + + private: + IPLhandle EnvironmentalRenderer; + TArray DirectSoundSources; + FSteamAudioModule* SteamAudioModule; + }; +} diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononOcclusionSourceSettings.cpp b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononOcclusionSourceSettings.cpp new file mode 100644 index 000000000000..a39fc54585ae --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononOcclusionSourceSettings.cpp @@ -0,0 +1,25 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#include "PhononOcclusionSourceSettings.h" + +UPhononOcclusionSourceSettings::UPhononOcclusionSourceSettings() + : DirectOcclusionMethod(EIplDirectOcclusionMethod::RAYCAST) + , DirectOcclusionSourceRadius(100.0f) + , DirectAttenuation(true) +{} + +#if WITH_EDITOR +bool UPhononOcclusionSourceSettings::CanEditChange(const UProperty* InProperty) const +{ + const bool ParentVal = Super::CanEditChange(InProperty); + + if ((InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononOcclusionSourceSettings, DirectOcclusionSourceRadius))) + { + return ParentVal && DirectOcclusionMethod == EIplDirectOcclusionMethod::VOLUMETRIC; + } + + return ParentVal; +} +#endif diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononProbeComponent.cpp b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononProbeComponent.cpp new file mode 100644 index 000000000000..80ee63154cad --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononProbeComponent.cpp @@ -0,0 +1,5 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#include "PhononProbeComponent.h" diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononProbeComponent.h b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononProbeComponent.h new file mode 100644 index 000000000000..b47e98f5c5ad --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononProbeComponent.h @@ -0,0 +1,18 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#pragma once + +#include "Components/SceneComponent.h" +#include "PhononProbeComponent.generated.h" + +UCLASS(ClassGroup = (Audio), HideCategories = (Activation, Collision)) +class STEAMAUDIO_API UPhononProbeComponent : public USceneComponent +{ + GENERATED_BODY() + +public: + UPROPERTY() + TArray ProbeLocations; +}; diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononProbeVolume.cpp b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononProbeVolume.cpp new file mode 100644 index 000000000000..a45335b51b17 --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononProbeVolume.cpp @@ -0,0 +1,157 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#include "PhononProbeVolume.h" + +#include "PhononProbeComponent.h" +#include "PhononScene.h" +#include "PhononCommon.h" + +#if WITH_EDITOR +#include "Editor.h" +#include "LevelEditorViewport.h" +#endif + +#include + +APhononProbeVolume::APhononProbeVolume(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) + , HorizontalSpacing(400.0f) + , HeightAboveFloor(150.0f) + , NumProbes(0) +{ + FRotator DefaultRotation(0, 0, 0); + PhononProbeComponent = CreateDefaultSubobject(TEXT("PhononProbeComponent0")); + PhononProbeComponent->SetWorldLocation(this->GetActorLocation()); + PhononProbeComponent->SetWorldRotation(DefaultRotation); + PhononProbeComponent->SetupAttachment(this->GetRootComponent()); +} + +#if WITH_EDITOR +void APhononProbeVolume::PlaceProbes(IPLhandle PhononScene, IPLProbePlacementProgressCallback ProbePlacementCallback, + TArray& ProbeSpheres) +{ + // Clear out old data + ProbeBoxData.Empty(); + ProbeBatchData.Empty(); + + // Compute bounding box in Phonon coords + IPLhandle ProbeBox = nullptr; + FVector BoxCenter, BoxExtents; + this->Brush->Bounds.GetBox().GetCenterAndExtents(BoxCenter, BoxExtents); + BoxExtents *= this->GetTransform().GetScale3D(); + FVector Center = this->GetTransform().GetLocation(); + IPLVector3 MinExtent = SteamAudio::UnrealToPhononIPLVector3(Center - BoxExtents); + IPLVector3 MaxExtent = SteamAudio::UnrealToPhononIPLVector3(Center + BoxExtents); + + if (MinExtent.x > MaxExtent.x) + std::swap(MinExtent.x, MaxExtent.x); + + if (MinExtent.y > MaxExtent.y) + std::swap(MinExtent.y, MaxExtent.y); + + if (MinExtent.z > MaxExtent.z) + std::swap(MinExtent.z, MaxExtent.z); + + IPLBox ProbeBoxExtents; + ProbeBoxExtents.minCoordinates = MinExtent; + ProbeBoxExtents.maxCoordinates = MaxExtent; + + // Configure placement parameters + IPLProbePlacementParams ProbePlacementParameters; + ProbePlacementParameters.placement = PlacementStrategy == EPhononProbePlacementStrategy::CENTROID ? IPL_PLACEMENT_CENTROID : IPL_PLACEMENT_UNIFORMFLOOR; + ProbePlacementParameters.heightAboveFloor = HeightAboveFloor * SteamAudio::SCALEFACTOR; + ProbePlacementParameters.spacing = HorizontalSpacing * SteamAudio::SCALEFACTOR; + ProbePlacementParameters.maxOctreeDepth = 0; + ProbePlacementParameters.maxOctreeTriangles = 0; + + // Create probe box, generate probes + iplCreateProbeBox(PhononScene, ProbeBoxExtents, ProbePlacementParameters, ProbePlacementCallback, &ProbeBox); + + // Get probe locations/radii + NumProbes = iplGetProbeSpheres(ProbeBox, nullptr); + ProbeSpheres.SetNumUninitialized(NumProbes); + iplGetProbeSpheres(ProbeBox, ProbeSpheres.GetData()); + + IPLhandle ProbeBatch = nullptr; + iplCreateProbeBatch(&ProbeBatch); + + for (IPLint32 i = 0; i < NumProbes; ++i) + { + iplAddProbeToBatch(ProbeBatch, ProbeBox, i); + } + + // Save probe box data + ProbeBoxDataSize = iplSaveProbeBox(ProbeBox, nullptr); + ProbeBoxData.SetNumUninitialized(ProbeBoxDataSize); + iplSaveProbeBox(ProbeBox, ProbeBoxData.GetData()); + + // Save probe batch data + iplFinalizeProbeBatch(ProbeBatch); + IPLint32 ProbeBatchDataSize = iplSaveProbeBatch(ProbeBatch, nullptr); + ProbeBatchData.SetNumUninitialized(ProbeBatchDataSize); + iplSaveProbeBatch(ProbeBatch, ProbeBatchData.GetData()); + + // Clean up + iplDestroyProbeBox(&ProbeBox); + iplDestroyProbeBatch(&ProbeBatch); +} + +bool APhononProbeVolume::CanEditChange(const UProperty* InProperty) const +{ + const bool ParentVal = Super::CanEditChange(InProperty); + + if ((InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(APhononProbeVolume, HorizontalSpacing)) || + (InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(APhononProbeVolume, HeightAboveFloor))) + { + return ParentVal && PlacementStrategy == EPhononProbePlacementStrategy::UNIFORM_FLOOR; + } + + return ParentVal; +} +#endif + +void APhononProbeVolume::UpdateProbeBoxData(IPLhandle ProbeBox) +{ + // Update probe box serialized data + ProbeBoxDataSize = iplSaveProbeBox(ProbeBox, nullptr); + ProbeBoxData.SetNumUninitialized(ProbeBoxDataSize); + iplSaveProbeBox(ProbeBox, ProbeBoxData.GetData()); + + // Update probe batch serialized data + IPLhandle ProbeBatch = nullptr; + iplCreateProbeBatch(&ProbeBatch); + + NumProbes = iplGetProbeSpheres(ProbeBox, nullptr); + for (auto i = 0; i < NumProbes; ++i) + { + iplAddProbeToBatch(ProbeBatch, ProbeBox, i); + } + + iplFinalizeProbeBatch(ProbeBatch); + auto ProbeBatchDataSize = iplSaveProbeBatch(ProbeBatch, nullptr); + ProbeBatchData.SetNumUninitialized(ProbeBatchDataSize); + iplSaveProbeBatch(ProbeBatch, ProbeBatchData.GetData()); + iplDestroyProbeBatch(&ProbeBatch); +} + +uint8* APhononProbeVolume::GetProbeBoxData() +{ + return ProbeBoxData.GetData(); +} + +const int32 APhononProbeVolume::GetProbeBoxDataSize() const +{ + return ProbeBoxData.Num(); +} + +uint8* APhononProbeVolume::GetProbeBatchData() +{ + return ProbeBatchData.GetData(); +} + +const int32 APhononProbeVolume::GetProbeBatchDataSize() const +{ + return ProbeBatchData.Num(); +} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononProbeVolume.h b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononProbeVolume.h new file mode 100644 index 000000000000..336dc9fe0ac2 --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononProbeVolume.h @@ -0,0 +1,115 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#pragma once + +#include "PhononCommon.h" +#include "GameFramework/Volume.h" +#include "PhononProbeVolume.generated.h" + +UENUM() +enum class EPhononProbePlacementStrategy : uint8 +{ + // Places a single probe at the centroid of the volume. + CENTROID = 0 UMETA(DisplayName = "Centroid"), + // Places uniformly spaced probes along the floor at a specified height. + UNIFORM_FLOOR = 1 UMETA(DisplayName = "Uniform Floor") +}; + +UENUM() +enum class EPhononProbeMobility : uint8 +{ + // Static probes remain fixed at runtime. + STATIC = 0 UMETA(DisplayName = "Static"), + // Dynamic probes inherit this volume's offset at runtime. + DYNAMIC = 1 UMETA(DisplayName = "Dynamic") +}; + +USTRUCT() +struct FBakedDataInfo +{ + GENERATED_BODY() + + UPROPERTY() + FName Name; + + UPROPERTY() + int32 Size; +}; + +inline bool operator==(const FBakedDataInfo& lhs, const FBakedDataInfo& rhs) +{ + return lhs.Name == rhs.Name && lhs.Size == rhs.Size; +} + +inline bool operator<(const FBakedDataInfo& lhs, const FBakedDataInfo& rhs) +{ + return lhs.Name < rhs.Name; +} + +/** + * Phonon Probe volumes generate a set of probes at which acoustic information will be sampled + * at bake time. + */ +UCLASS(HideCategories = (Actor, Advanced, Attachment, Collision)) +class STEAMAUDIO_API APhononProbeVolume : public AVolume +{ + GENERATED_UCLASS_BODY() + +public: + +#if WITH_EDITOR + virtual bool CanEditChange(const UProperty* InProperty) const override; + + void PlaceProbes(IPLhandle PhononScene, IPLProbePlacementProgressCallback ProbePlacementCallback, TArray& ProbeSpheres); +#endif + + void UpdateProbeBoxData(IPLhandle ProbeBox); + + uint8* GetProbeBoxData(); + + const int32 GetProbeBoxDataSize() const; + + uint8* GetProbeBatchData(); + + const int32 GetProbeBatchDataSize() const; + + // Method by which probes are placed within the volume. + UPROPERTY(EditAnywhere, Category = ProbeGeneration) + EPhononProbePlacementStrategy PlacementStrategy; + + // How far apart to place probes. + UPROPERTY(EditAnywhere, Category = ProbeGeneration, meta = (ClampMin = "0.0", ClampMax = "5000.0", UIMin = "0.0", UIMax = "5000.0")) + float HorizontalSpacing; + + // How high above the floor to place probes. + UPROPERTY(EditAnywhere, Category = ProbeGeneration, meta = (ClampMin = "0.0", ClampMax = "5000.0", UIMin = "0.0", UIMax = "5000.0")) + float HeightAboveFloor; + + // Number of probes contained in this probe volume. + UPROPERTY(VisibleAnywhere, Category = ProbeVolumeStatistics, meta = (DisplayName = "Probe Points")) + int32 NumProbes; + + // Size of probe data in bytes. + UPROPERTY(VisibleAnywhere, Category = ProbeVolumeStatistics, meta = (DisplayName = "Probe Data Size")) + int32 ProbeBoxDataSize; + + UPROPERTY(VisibleAnywhere, Category = ProbeVolumeStatistics, meta = (DisplayName = "Detailed Statistics")) + TArray BakedDataInfo; + +private: + UPROPERTY() + class UPhononProbeComponent* PhononProbeComponent; + +private: + + UPROPERTY() + TArray ProbeBoxData; + + UPROPERTY() + TArray ProbeBatchData; + +public: + UPhononProbeComponent* GetPhononProbeComponent() { return PhononProbeComponent; } +}; \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononReverb.cpp b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononReverb.cpp similarity index 56% rename from Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononReverb.cpp rename to Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononReverb.cpp index c96b7cbbac8f..8c43dfcf5b73 100644 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononReverb.cpp +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononReverb.cpp @@ -1,28 +1,33 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. +// +// Copyright (C) Valve Corporation. All rights reserved. +// #include "PhononReverb.h" -#include "PhononSettings.h" +#include "SteamAudioModule.h" +#include "SteamAudioSettings.h" #include "PhononReverbSourceSettings.h" #include "Sound/SoundEffectSubmix.h" #include "Sound/SoundSubmix.h" #include "DSP/Dsp.h" #include "ScopeLock.h" -namespace Phonon +namespace SteamAudio { //============================================================================================================================================== - // FPhononReverb implementation + // FPhononReverb //============================================================================================================================================== FPhononReverb::FPhononReverb() : EnvironmentalRenderer(nullptr) , BinauralRenderer(nullptr) , IndirectBinauralEffect(nullptr) + , IndirectPanningEffect(nullptr) , ReverbConvolutionEffect(nullptr) , AmbisonicsChannels(0) , IndirectOutDeinterleaved(nullptr) + , SteamAudioModule(nullptr) { - const int32 IndirectImpulseResponseOrder = GetDefault()->IndirectImpulseResponseOrder; + const int32 IndirectImpulseResponseOrder = GetDefault()->IndirectImpulseResponseOrder; InputAudioFormat.channelLayout = IPL_CHANNELLAYOUT_MONO; InputAudioFormat.channelLayoutType = IPL_CHANNELLAYOUTTYPE_SPEAKERS; @@ -63,32 +68,34 @@ namespace Phonon FPhononReverb::~FPhononReverb() { - // We are not responsible for destroying the renderer. - EnvironmentalRenderer = nullptr; - - for (FPhononReverbSource& PhononReverbSource : PhononReverbSources) + for (auto& ReverbSource : ReverbSources) { - if (PhononReverbSource.ConvolutionEffect) + if (ReverbSource.ConvolutionEffect) { - iplDestroyConvolutionEffect(&PhononReverbSource.ConvolutionEffect); + iplDestroyConvolutionEffect(&ReverbSource.ConvolutionEffect); } } - if (BinauralRenderer) - { - iplDestroyBinauralRenderer(&BinauralRenderer); - } - - if (IndirectBinauralEffect) - { - iplDestroyBinauralEffect(&IndirectBinauralEffect); - } - if (ReverbConvolutionEffect) { iplDestroyConvolutionEffect(&ReverbConvolutionEffect); } + if (IndirectBinauralEffect) + { + iplDestroyAmbisonicsBinauralEffect(&IndirectBinauralEffect); + } + + if (IndirectPanningEffect) + { + iplDestroyAmbisonicsPanningEffect(&IndirectPanningEffect); + } + + if (BinauralRenderer) + { + iplDestroyBinauralRenderer(&BinauralRenderer); + } + if (IndirectOutDeinterleaved) { for (int32 i = 0; i < AmbisonicsChannels; ++i) @@ -102,14 +109,17 @@ namespace Phonon void FPhononReverb::Initialize(const int32 SampleRate, const int32 NumSources, const int32 FrameSize) { + SteamAudioModule = &FModuleManager::GetModuleChecked("SteamAudio"); + RenderingSettings.convolutionType = IPL_CONVOLUTIONTYPE_PHONON; RenderingSettings.frameSize = FrameSize; RenderingSettings.samplingRate = SampleRate; - iplCreateBinauralRenderer(Phonon::GlobalContext, RenderingSettings, nullptr, &BinauralRenderer); + iplCreateBinauralRenderer(SteamAudio::GlobalContext, RenderingSettings, nullptr, &BinauralRenderer); iplCreateAmbisonicsBinauralEffect(BinauralRenderer, IndirectOutputAudioFormat, BinauralOutputAudioFormat, &IndirectBinauralEffect); + iplCreateAmbisonicsPanningEffect(BinauralRenderer, IndirectOutputAudioFormat, BinauralOutputAudioFormat, &IndirectPanningEffect); - int32 IndirectImpulseResponseOrder = GetDefault()->IndirectImpulseResponseOrder; + int32 IndirectImpulseResponseOrder = GetDefault()->IndirectImpulseResponseOrder; AmbisonicsChannels = (IndirectImpulseResponseOrder + 1) * (IndirectImpulseResponseOrder + 1); IndirectOutDeinterleaved = new float*[AmbisonicsChannels]; @@ -117,7 +127,6 @@ namespace Phonon { IndirectOutDeinterleaved[i] = new float[FrameSize]; } - //IndirectIntermediateArray.SetNumZeroed(FrameSize * (IndirectImpulseResponseOrder + 1) * (IndirectImpulseResponseOrder + 1)); IndirectIntermediateBuffer.format = IndirectOutputAudioFormat; IndirectIntermediateBuffer.numSamples = FrameSize; IndirectIntermediateBuffer.interleavedBuffer = nullptr; @@ -132,42 +141,42 @@ namespace Phonon IndirectOutBuffer.format = BinauralOutputAudioFormat; IndirectOutBuffer.numSamples = FrameSize; IndirectOutBuffer.interleavedBuffer = IndirectOutArray.GetData(); - IndirectOutBuffer.deinterleavedBuffer = nullptr; + IndirectOutBuffer.deinterleavedBuffer = nullptr; - PhononReverbSources.SetNum(NumSources); - - for (auto& PhononReverbSource : PhononReverbSources) + ReverbSources.SetNum(NumSources); + for (auto& ReverbSource : ReverbSources) { - PhononReverbSource.InBuffer.format = InputAudioFormat; - PhononReverbSource.InBuffer.numSamples = FrameSize; + ReverbSource.InBuffer.format = InputAudioFormat; + ReverbSource.InBuffer.numSamples = FrameSize; } + + ReverbIndirectContribution = 1.0f; } - void FPhononReverb::SetReverbSettings(const uint32 SourceId, const uint32 AudioComponentUserId, UReverbPluginSourceSettingsBase* InSettings) + void FPhononReverb::OnInitSource(const uint32 SourceId, const FName& AudioComponentUserId, UReverbPluginSourceSettingsBase* InSettings) { if (!EnvironmentalRenderer) { - UE_LOG(LogTemp, Error, TEXT("COMPILE THINGIE FIRST. Maybe back reverb. I don't know. Ask Valve.")); + UE_LOG(LogSteamAudio, Error, TEXT("Unable to find environmental renderer for reverb. Reverb will not be applied. Make sure to export the scene.")); return; } - auto Settings = static_cast(InSettings); - auto AudioComponentName = FString::FromInt(AudioComponentUserId); + UE_LOG(LogSteamAudio, Log, TEXT("Creating reverb effect.")); - if (PhononReverbSources[SourceId].ConvolutionEffect) - { - iplDestroyConvolutionEffect(&PhononReverbSources[SourceId].ConvolutionEffect); - } + auto Settings = static_cast(InSettings); + auto& ReverbSource = ReverbSources[SourceId]; + + ReverbSource.IndirectContribution = Settings->IndirectContribution; switch (Settings->IndirectSimulationType) { case EIplSimulationType::BAKED: - iplCreateConvolutionEffect(EnvironmentalRenderer, TCHAR_TO_ANSI(*AudioComponentName), IPL_SIMTYPE_BAKED, InputAudioFormat, - IndirectOutputAudioFormat, &PhononReverbSources[SourceId].ConvolutionEffect); + iplCreateConvolutionEffect(EnvironmentalRenderer, TCHAR_TO_ANSI(*AudioComponentUserId.ToString()), IPL_SIMTYPE_BAKED, InputAudioFormat, + IndirectOutputAudioFormat, &ReverbSource.ConvolutionEffect); break; case EIplSimulationType::REALTIME: - iplCreateConvolutionEffect(EnvironmentalRenderer, TCHAR_TO_ANSI(*AudioComponentName), IPL_SIMTYPE_REALTIME, InputAudioFormat, - IndirectOutputAudioFormat, &PhononReverbSources[SourceId].ConvolutionEffect); + iplCreateConvolutionEffect(EnvironmentalRenderer, TCHAR_TO_ANSI(*AudioComponentUserId.ToString()), IPL_SIMTYPE_REALTIME, + InputAudioFormat, IndirectOutputAudioFormat, &ReverbSource.ConvolutionEffect); break; case EIplSimulationType::DISABLED: default: @@ -175,30 +184,36 @@ namespace Phonon } } - FSoundEffectSubmix* FPhononReverb::GetEffectSubmix(USoundSubmix* Submix) + void FPhononReverb::OnReleaseSource(const uint32 SourceId) { - USubmixEffectReverbPluginPreset* ReverbPluginPreset = NewObject(Submix, TEXT("Master Reverb Plugin Effect Preset")); - auto Effect = static_cast(ReverbPluginPreset->CreateNewEffect()); - Effect->SetPhononReverbPlugin(this); - return static_cast(Effect); + UE_LOG(LogSteamAudio, Log, TEXT("Destroying reverb effect.")); + + ReverbSources[SourceId].IndirectContribution = 1.0f; + iplDestroyConvolutionEffect(&ReverbSources[SourceId].ConvolutionEffect); } void FPhononReverb::ProcessSourceAudio(const FAudioPluginSourceInputData& InputData, FAudioPluginSourceOutputData& OutputData) { - if (!EnvironmentalRenderer) + if (!EnvironmentalRenderer) { return; } - PhononReverbSources[InputData.SourceId].InBuffer.interleavedBuffer = InputData.AudioBuffer->GetData(); + FScopeLock EnvironmentLock(&SteamAudioModule->GetEnvironmentCriticalSection()); - auto Position = Phonon::UnrealToPhononIPLVector3(InputData.SpatializationParams->EmitterWorldPosition); + auto& ReverbSource = ReverbSources[InputData.SourceId]; + auto Position = SteamAudio::UnrealToPhononIPLVector3(InputData.SpatializationParams->EmitterWorldPosition); - // Send dry audio to Phonon - if (PhononReverbSources[InputData.SourceId].ConvolutionEffect) + if (ReverbSource.ConvolutionEffect) { - iplSetDryAudioForConvolutionEffect(PhononReverbSources[InputData.SourceId].ConvolutionEffect, Position, - PhononReverbSources[InputData.SourceId].InBuffer); + ReverbSource.IndirectInArray.SetNumUninitialized(InputData.AudioBuffer->Num()); + for (auto i = 0; i < InputData.AudioBuffer->Num(); ++i) + { + ReverbSource.IndirectInArray[i] = (*InputData.AudioBuffer)[i] * ReverbSource.IndirectContribution; + } + ReverbSource.InBuffer.interleavedBuffer = ReverbSource.IndirectInArray.GetData(); + + iplSetDryAudioForConvolutionEffect(ReverbSource.ConvolutionEffect, Position, ReverbSource.InBuffer); } } @@ -209,37 +224,51 @@ namespace Phonon return; } - FScopeLock Lock(&ListenerCriticalSection); + FScopeLock EnvironmentLock(&SteamAudioModule->GetEnvironmentCriticalSection()); + //FScopeLock ListenerLock(&ListenerCriticalSection); if (ReverbConvolutionEffect) { - DryBuffer.interleavedBuffer = InData.AudioBuffer->GetData(); + ReverbIndirectInArray.SetNumUninitialized(InData.AudioBuffer->Num()); + for (auto i = 0; i < InData.AudioBuffer->Num(); ++i) + { + ReverbIndirectInArray[i] = (*InData.AudioBuffer)[i] * ReverbIndirectContribution; + } + + DryBuffer.interleavedBuffer = ReverbIndirectInArray.GetData(); iplSetDryAudioForConvolutionEffect(ReverbConvolutionEffect, ListenerPosition, DryBuffer); } iplGetMixedEnvironmentalAudio(EnvironmentalRenderer, ListenerPosition, ListenerForward, ListenerUp, IndirectIntermediateBuffer); - iplApplyAmbisonicsBinauralEffect(IndirectBinauralEffect, IndirectIntermediateBuffer, IndirectOutBuffer); - auto IndirectContribution = GetDefault()->IndirectContribution; - - for (auto i = 0; i < IndirectOutArray.Num(); ++i) + switch (GetDefault()->IndirectSpatializationMethod) { - (*OutData.AudioBuffer)[i] = IndirectOutArray[i] * IndirectContribution; + case EIplSpatializationMethod::HRTF: + iplApplyAmbisonicsBinauralEffect(IndirectBinauralEffect, IndirectIntermediateBuffer, IndirectOutBuffer); + break; + case EIplSpatializationMethod::PANNING: + iplApplyAmbisonicsPanningEffect(IndirectPanningEffect, IndirectIntermediateBuffer, IndirectOutBuffer); + break; } + + FMemory::Memcpy(OutData.AudioBuffer->GetData(), IndirectOutArray.GetData(), sizeof(float) * IndirectOutArray.Num()); } - void FPhononReverb::SetEnvironmentalRenderer(IPLhandle InEnvironmentalRenderer) + void FPhononReverb::CreateReverbEffect() { - EnvironmentalRenderer = InEnvironmentalRenderer; - - switch (GetDefault()->ReverbSimulationType) + check(EnvironmentalRenderer); + + FScopeLock Lock(&SteamAudioModule->GetEnvironmentCriticalSection()); + + ReverbIndirectContribution = GetDefault()->IndirectContribution; + switch (GetDefault()->ReverbSimulationType) { case EIplSimulationType::BAKED: - iplCreateConvolutionEffect(EnvironmentalRenderer, "__reverb__", IPL_SIMTYPE_BAKED, ReverbInputAudioFormat, IndirectOutputAudioFormat, + iplCreateConvolutionEffect(EnvironmentalRenderer, (IPLstring)"__reverb__", IPL_SIMTYPE_BAKED, ReverbInputAudioFormat, IndirectOutputAudioFormat, &ReverbConvolutionEffect); break; case EIplSimulationType::REALTIME: - iplCreateConvolutionEffect(EnvironmentalRenderer, "__reverb__", IPL_SIMTYPE_REALTIME, ReverbInputAudioFormat, IndirectOutputAudioFormat, + iplCreateConvolutionEffect(EnvironmentalRenderer, (IPLstring)"__reverb__", IPL_SIMTYPE_REALTIME, ReverbInputAudioFormat, IndirectOutputAudioFormat, &ReverbConvolutionEffect); break; case EIplSimulationType::DISABLED: @@ -250,17 +279,44 @@ namespace Phonon void FPhononReverb::UpdateListener(const FVector& Position, const FVector& Forward, const FVector& Up) { - FScopeLock Lock(&ListenerCriticalSection); - ListenerPosition = Phonon::UnrealToPhononIPLVector3(Position); - ListenerForward = Phonon::UnrealToPhononIPLVector3(Forward, false); - ListenerUp = Phonon::UnrealToPhononIPLVector3(Up, false); + //FScopeLock Lock(&ListenerCriticalSection); + ListenerPosition = SteamAudio::UnrealToPhononIPLVector3(Position); + ListenerForward = SteamAudio::UnrealToPhononIPLVector3(Forward, false); + ListenerUp = SteamAudio::UnrealToPhononIPLVector3(Up, false); + } + + FSoundEffectSubmix* FPhononReverb::GetEffectSubmix(USoundSubmix* Submix) + { + USubmixEffectReverbPluginPreset* ReverbPluginPreset = NewObject(Submix, TEXT("Master Reverb Plugin Effect Preset")); + auto Effect = static_cast(ReverbPluginPreset->CreateNewEffect()); + Effect->SetPhononReverbPlugin(this); + return static_cast(Effect); + } + + void FPhononReverb::SetEnvironmentalRenderer(IPLhandle InEnvironmentalRenderer) + { + EnvironmentalRenderer = InEnvironmentalRenderer; + } + + //============================================================================================================================================== + // FReverbSource + //============================================================================================================================================== + + FReverbSource::FReverbSource() + : ConvolutionEffect(nullptr) + , IndirectContribution(1.0f) + { } } //================================================================================================================================================== -// FSubmixEffectReverbPlugin implementation +// FSubmixEffectReverbPlugin //================================================================================================================================================== +FSubmixEffectReverbPlugin::FSubmixEffectReverbPlugin() + : PhononReverbPlugin(nullptr) +{} + void FSubmixEffectReverbPlugin::Init(const FSoundEffectSubmixInitData& InSampleRate) { } @@ -278,3 +334,8 @@ void FSubmixEffectReverbPlugin::OnProcessAudio(const FSoundEffectSubmixInputData { PhononReverbPlugin->ProcessMixedAudio(InData, OutData); } + +void FSubmixEffectReverbPlugin::SetPhononReverbPlugin(SteamAudio::FPhononReverb* InPhononReverbPlugin) +{ + PhononReverbPlugin = InPhononReverbPlugin; +} diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononReverb.h b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononReverb.h similarity index 74% rename from Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononReverb.h rename to Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononReverb.h index e1c9d67ffa97..3031fc1e32fa 100644 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononReverb.h +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononReverb.h @@ -1,4 +1,6 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. +// +// Copyright (C) Valve Corporation. All rights reserved. +// #pragma once @@ -9,17 +11,16 @@ #include "phonon.h" #include "PhononReverb.generated.h" -namespace Phonon +namespace SteamAudio { - class FPhononReverbSource + struct FReverbSource { - public: - FPhononReverbSource() - : ConvolutionEffect(nullptr) - {} + FReverbSource(); IPLhandle ConvolutionEffect; + float IndirectContribution; IPLAudioBuffer InBuffer; + TArray IndirectInArray; }; class FPhononReverb : public IAudioReverb @@ -29,18 +30,21 @@ namespace Phonon ~FPhononReverb(); virtual void Initialize(const int32 SampleRate, const int32 NumSources, const int32 FrameSize) override; - virtual void SetReverbSettings(const uint32 SourceId, const uint32 AudioComponentUserId, UReverbPluginSourceSettingsBase* InSettings) override; + virtual void OnInitSource(const uint32 SourceId, const FName& AudioComponentUserId, UReverbPluginSourceSettingsBase* InSettings) override; + virtual void OnReleaseSource(const uint32 SourceId) override; virtual class FSoundEffectSubmix* GetEffectSubmix(class USoundSubmix* Submix) override; virtual void ProcessSourceAudio(const FAudioPluginSourceInputData& InputData, FAudioPluginSourceOutputData& OutputData) override; void ProcessMixedAudio(const FSoundEffectSubmixInputData& InData, FSoundEffectSubmixOutputData& OutData); void SetEnvironmentalRenderer(IPLhandle EnvironmentalRenderer); + void CreateReverbEffect(); void UpdateListener(const FVector& Position, const FVector& Forward, const FVector& Up); private: IPLhandle EnvironmentalRenderer; IPLhandle BinauralRenderer; IPLhandle IndirectBinauralEffect; + IPLhandle IndirectPanningEffect; IPLhandle ReverbConvolutionEffect; IPLAudioBuffer DryBuffer; @@ -64,35 +68,35 @@ namespace Phonon IPLRenderingSettings RenderingSettings; - TArray PhononReverbSources; + TArray ReverbSources; + + float ReverbIndirectContribution; + TArray ReverbIndirectInArray; + + class FSteamAudioModule* SteamAudioModule; }; } -USTRUCT() -struct FSubmixEffectReverbPluginSettings -{ - GENERATED_USTRUCT_BODY() -}; - class FSubmixEffectReverbPlugin : public FSoundEffectSubmix { public: - FSubmixEffectReverbPlugin() - : PhononReverbPlugin(nullptr) - {} + FSubmixEffectReverbPlugin(); virtual void Init(const FSoundEffectSubmixInitData& InSampleRate) override; virtual uint32 GetDesiredInputChannelCountOverride() const override; virtual void OnProcessAudio(const FSoundEffectSubmixInputData& InData, FSoundEffectSubmixOutputData& OutData) override; virtual void OnPresetChanged() override; - void SetPhononReverbPlugin(Phonon::FPhononReverb* InPhononReverbPlugin) - { - PhononReverbPlugin = InPhononReverbPlugin; - } + void SetPhononReverbPlugin(SteamAudio::FPhononReverb* PhononReverbPlugin); private: - Phonon::FPhononReverb* PhononReverbPlugin; + SteamAudio::FPhononReverb* PhononReverbPlugin; +}; + +USTRUCT() +struct FSubmixEffectReverbPluginSettings +{ + GENERATED_USTRUCT_BODY() }; UCLASS() @@ -103,6 +107,6 @@ class USubmixEffectReverbPluginPreset : public USoundEffectSubmixPreset public: EFFECT_PRESET_METHODS_NO_ASSET_ACTIONS(SubmixEffectReverbPlugin) - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = SubmixEffectPreset) + UPROPERTY(EditAnywhere, Category = SubmixEffectPreset) FSubmixEffectReverbPluginSettings Settings; -}; \ No newline at end of file +}; diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononReverbSourceSettings.cpp b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononReverbSourceSettings.cpp new file mode 100644 index 000000000000..dd704c0a4207 --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononReverbSourceSettings.cpp @@ -0,0 +1,10 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#include "PhononReverbSourceSettings.h" + +UPhononReverbSourceSettings::UPhononReverbSourceSettings() + : IndirectSimulationType(EIplSimulationType::REALTIME) + , IndirectContribution(1.0f) +{} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononScene.cpp b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononScene.cpp similarity index 73% rename from Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononScene.cpp rename to Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononScene.cpp index 61354f534771..9526654b64f4 100644 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononScene.cpp +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononScene.cpp @@ -1,5 +1,5 @@ // -// Copyright (C) Impulsonic, Inc. All rights reserved. +// Copyright (C) Valve Corporation. All rights reserved. // #include "PhononScene.h" @@ -11,6 +11,7 @@ #include "EngineUtils.h" #include "Engine/StaticMeshActor.h" #include "StaticMeshResources.h" +#include "SteamAudioSettings.h" #if WITH_EDITOR @@ -36,7 +37,7 @@ */ -namespace Phonon +namespace SteamAudio { static void LoadBSPGeometry(UWorld* World, IPLhandle PhononScene, TArray* PhononStaticMeshes); static void LoadStaticMeshActors(UWorld* World, IPLhandle PhononScene, TArray* PhononStaticMeshes); @@ -59,25 +60,25 @@ namespace Phonon check(PhononScene); check(PhononStaticMeshes); - UE_LOG(LogPhonon, Log, TEXT("Loading Phonon scene.")); + UE_LOG(LogSteamAudio, Log, TEXT("Loading Phonon scene.")); IPLSimulationSettings SimulationSettings; SimulationSettings.sceneType = IPL_SCENETYPE_PHONON; - IPLerror IplResult = iplCreateScene(Phonon::GlobalContext, nullptr, SimulationSettings, CalculateNumMaterials(World), PhononScene); + IPLerror IplResult = iplCreateScene(SteamAudio::GlobalContext, nullptr, SimulationSettings, CalculateNumMaterials(World), PhononScene); if (IplResult != IPL_STATUS_SUCCESS) { - UE_LOG(LogPhonon, Warning, TEXT("Error creating Phonon scene.")); + UE_LOG(LogSteamAudio, Warning, TEXT("Error creating Phonon scene.")); return; } LoadStaticMeshActors(World, *PhononScene, PhononStaticMeshes); - if (GetDefault()->ExportLandscapeGeometry) + if (GetDefault()->ExportLandscapeGeometry) { LoadLandscapeActors(World, *PhononScene, PhononStaticMeshes); } - if (GetDefault()->ExportBSPGeometry) + if (GetDefault()->ExportBSPGeometry) { LoadBSPGeometry(World, *PhononScene, PhononStaticMeshes); } @@ -121,6 +122,39 @@ namespace Phonon return NumVerts; } + /** + * Walks up the actor attachment chain, checking for a Phonon Geometry component. + */ + static bool IsActorPhononGeometry(AActor* Actor) + { + auto CurrentActor = Actor; + while (CurrentActor) + { + if (CurrentActor->GetComponentByClass(UPhononGeometryComponent::StaticClass())) + { + return true; + } + CurrentActor = CurrentActor->GetAttachParentActor(); + } + + return false; + } + + static UPhononMaterialComponent* GetPhononMaterialComponent(AActor* Actor) + { + auto CurrentActor = Actor; + while (CurrentActor) + { + if (CurrentActor->GetComponentByClass(UPhononMaterialComponent::StaticClass())) + { + return static_cast(CurrentActor->GetComponentByClass(UPhononMaterialComponent::StaticClass())); + } + CurrentActor = CurrentActor->GetAttachParentActor(); + } + + return nullptr; + } + /** * Loads any static mesh actors, adding any Phonon static meshes to the provided array. */ @@ -130,10 +164,7 @@ namespace Phonon check(PhononScene); check(PhononStaticMeshes); - UE_LOG(LogPhonon, Log, TEXT("Loading static mesh actors.")); - - // There are size(MaterialPresets) + 3 fixed material slots. - auto CustomMaterialIdx = MaterialPresets.Num() + 3; + UE_LOG(LogSteamAudio, Log, TEXT("Loading static mesh actors.")); TArray IplVertices; TArray IplTriangles; @@ -142,8 +173,7 @@ namespace Phonon for (TActorIterator AStaticMeshItr(World); AStaticMeshItr; ++AStaticMeshItr) { // Only consider static mesh actors that have both an acoustic geometry component attached and valid render data - if (AStaticMeshItr->GetComponentByClass(UPhononGeometryComponent::StaticClass()) && - AStaticMeshItr->GetStaticMeshComponent()->GetStaticMesh() && + if (IsActorPhononGeometry(*AStaticMeshItr) && AStaticMeshItr->GetStaticMeshComponent()->GetStaticMesh() && AStaticMeshItr->GetStaticMeshComponent()->GetStaticMesh()->HasValidRenderData()) { auto PhononGeometryComponent = static_cast( @@ -161,34 +191,23 @@ namespace Phonon IplTriangles.Add(IplTriangle); } - auto PhononMaterialComponent = static_cast( - AStaticMeshItr->GetComponentByClass(UPhononMaterialComponent::StaticClass())); - - auto DefaultMaterial = GetDefault()->StaticMeshMaterialPreset; - auto MaterialIdx = 0; + auto PhononMaterialComponent = GetPhononMaterialComponent(*AStaticMeshItr); + auto MaterialIndex = 0; if (PhononMaterialComponent) { - switch (PhononMaterialComponent->MaterialPreset) - { - case EPhononMaterial::CUSTOM: - MaterialIdx = CustomMaterialIdx++; - iplSetSceneMaterial(PhononScene, MaterialIdx, PhononMaterialComponent->GetMaterialPreset()); - break; - default: - MaterialIdx = static_cast(PhononMaterialComponent->MaterialPreset); - break; - } + MaterialIndex = PhononMaterialComponent->MaterialIndex; + iplSetSceneMaterial(PhononScene, PhononMaterialComponent->MaterialIndex, PhononMaterialComponent->GetMaterialPreset()); } else { // The default static mesh material is always registered at size(MaterialPresets) - MaterialIdx = MaterialPresets.Num(); + MaterialIndex = MaterialPresets.Num(); } for (auto i = 0; i < IplTriangles.Num(); ++i) { - IplMaterialIndices.Add(MaterialIdx); + IplMaterialIndices.Add(MaterialIndex); } } } @@ -210,7 +229,7 @@ namespace Phonon check(PhononScene); check(PhononStaticMeshes); - UE_LOG(LogPhonon, Log, TEXT("Loading BSP geometry.")); + UE_LOG(LogSteamAudio, Log, TEXT("Loading BSP geometry.")); TArray IplVertices; TArray IplTriangles; @@ -219,7 +238,7 @@ namespace Phonon // Gather and convert all world vertices to Phonon coords for (auto& WorldVertex : World->GetModel()->Points) { - IplVertices.Add(Phonon::UnrealToPhononIPLVector3(WorldVertex)); + IplVertices.Add(SteamAudio::UnrealToPhononIPLVector3(WorldVertex)); } // Gather vertex indices for all faces ("nodes" are faces) @@ -274,7 +293,7 @@ namespace Phonon check(PhononScene); check(PhononStaticMeshes); - UE_LOG(LogPhonon, Log, TEXT("Loading landscape actors.")); + UE_LOG(LogSteamAudio, Log, TEXT("Loading landscape actors.")); TArray IplVertices; TArray IplTriangles; @@ -295,10 +314,10 @@ namespace Phonon { auto StartIndex = IplVertices.Num(); - IplVertices.Add(Phonon::UnrealToPhononIPLVector3(CDI.GetWorldVertex(x, y))); - IplVertices.Add(Phonon::UnrealToPhononIPLVector3(CDI.GetWorldVertex(x, y + 1))); - IplVertices.Add(Phonon::UnrealToPhononIPLVector3(CDI.GetWorldVertex(x + 1, y + 1))); - IplVertices.Add(Phonon::UnrealToPhononIPLVector3(CDI.GetWorldVertex(x + 1, y))); + IplVertices.Add(SteamAudio::UnrealToPhononIPLVector3(CDI.GetWorldVertex(x, y))); + IplVertices.Add(SteamAudio::UnrealToPhononIPLVector3(CDI.GetWorldVertex(x, y + 1))); + IplVertices.Add(SteamAudio::UnrealToPhononIPLVector3(CDI.GetWorldVertex(x + 1, y + 1))); + IplVertices.Add(SteamAudio::UnrealToPhononIPLVector3(CDI.GetWorldVertex(x + 1, y))); IPLTriangle Triangle; @@ -339,13 +358,13 @@ namespace Phonon { if (IplVertices.Num() > 0) { - UE_LOG(LogPhonon, Log, TEXT("Registering new mesh with %d verts."), IplVertices.Num()); + UE_LOG(LogSteamAudio, Log, TEXT("Registering new mesh with %d verts."), IplVertices.Num()); IPLhandle IplStaticMesh = nullptr; auto IplResult = iplCreateStaticMesh(PhononScene, IplVertices.Num(), IplTriangles.Num(), &IplStaticMesh); if (IplResult != IPL_STATUS_SUCCESS) { - UE_LOG(LogPhonon, Warning, TEXT("Error adding a new object to the acoustic scene.")); + UE_LOG(LogSteamAudio, Warning, TEXT("Error adding a new object to the acoustic scene.")); return; } @@ -356,7 +375,7 @@ namespace Phonon } else { - UE_LOG(LogPhonon, Warning, TEXT("Skipping mesh registration because no vertices were found.")); + UE_LOG(LogSteamAudio, Warning, TEXT("Skipping mesh registration because no vertices were found.")); } } @@ -370,20 +389,19 @@ namespace Phonon // There are size(MaterialPresets) + 3 fixed slots. int32 NumMaterials = MaterialPresets.Num() + 3; - for (TActorIterator AStaticMeshItr(World); AStaticMeshItr; ++AStaticMeshItr) + for (TActorIterator AActorItr(World); AActorItr; ++AActorItr) { - // Only consider static mesh actors that have both an acoustic geometry component attached and valid render data - if (AStaticMeshItr->GetComponentByClass(UPhononGeometryComponent::StaticClass()) && - AStaticMeshItr->GetComponentByClass(UPhononMaterialComponent::StaticClass()) && - AStaticMeshItr->GetStaticMeshComponent()->GetStaticMesh() && - AStaticMeshItr->GetStaticMeshComponent()->GetStaticMesh()->HasValidRenderData()) + auto PhononMaterialComponent = static_cast( + AActorItr->GetComponentByClass(UPhononMaterialComponent::StaticClass())); + if (PhononMaterialComponent) { - auto PhononMaterialComponent = static_cast( - AStaticMeshItr->GetComponentByClass(UPhononMaterialComponent::StaticClass())); - if (PhononMaterialComponent->MaterialPreset == EPhononMaterial::CUSTOM) { - ++NumMaterials; + PhononMaterialComponent->MaterialIndex = NumMaterials++; + } + else + { + PhononMaterialComponent->MaterialIndex = static_cast(PhononMaterialComponent->MaterialPreset); } } } @@ -403,9 +421,49 @@ namespace Phonon iplSetSceneMaterial(PhononScene, static_cast(Preset.Key), Preset.Value); } - iplSetSceneMaterial(PhononScene, MaterialPresets.Num(), GetDefault()->GetDefaultStaticMeshMaterial()); - iplSetSceneMaterial(PhononScene, MaterialPresets.Num() + 1, GetDefault()->GetDefaultBSPMaterial()); - iplSetSceneMaterial(PhononScene, MaterialPresets.Num() + 2, GetDefault()->GetDefaultLandscapeMaterial()); + iplSetSceneMaterial(PhononScene, MaterialPresets.Num(), GetDefault()->GetDefaultStaticMeshMaterial()); + iplSetSceneMaterial(PhononScene, MaterialPresets.Num() + 1, GetDefault()->GetDefaultBSPMaterial()); + iplSetSceneMaterial(PhononScene, MaterialPresets.Num() + 2, GetDefault()->GetDefaultLandscapeMaterial()); + } + + uint32 GetNumTrianglesForStaticMesh(AStaticMeshActor* StaticMeshActor) + { + auto NumTriangles = 0; + + if (StaticMeshActor == nullptr) + { + return NumTriangles; + } + + const auto& LODModel = StaticMeshActor->GetStaticMeshComponent()->GetStaticMesh()->RenderData->LODResources[0]; + for (const auto& Section : LODModel.Sections) + { + NumTriangles += Section.NumTriangles; + } + + return NumTriangles; + } + + uint32 GetNumTrianglesAtRoot(AActor* RootActor) + { + auto NumTriangles = 0; + + if (RootActor == nullptr) + { + return NumTriangles; + } + + NumTriangles = GetNumTrianglesForStaticMesh(Cast(RootActor)); + + TArray AttachedActors; + RootActor->GetAttachedActors(AttachedActors); + + for (auto AttachedActor : AttachedActors) + { + NumTriangles += GetNumTrianglesAtRoot(AttachedActor); + } + + return NumTriangles; } } diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononScene.h b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononScene.h new file mode 100644 index 000000000000..7cc656935f81 --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononScene.h @@ -0,0 +1,18 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#pragma once + +#include "CoreMinimal.h" +#include "GameFramework/Actor.h" +#include "phonon.h" + +class AStaticMeshActor; + +namespace SteamAudio +{ + void STEAMAUDIO_API LoadScene(class UWorld* World, IPLhandle* PhononScene, TArray* PhononStaticMeshes); + uint32 GetNumTrianglesForStaticMesh(AStaticMeshActor* StaticMeshActor); + uint32 GetNumTrianglesAtRoot(AActor* RootActor); +} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononSourceComponent.cpp b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononSourceComponent.cpp new file mode 100644 index 000000000000..05deb1a37a4b --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononSourceComponent.cpp @@ -0,0 +1,5 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#include "PhononSourceComponent.h" \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononSourceComponent.h b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononSourceComponent.h similarity index 60% rename from Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononSourceComponent.h rename to Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononSourceComponent.h index 3aae27779b09..2dba459bbf79 100644 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononSourceComponent.h +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononSourceComponent.h @@ -1,5 +1,5 @@ // -// Copyright (C) Impulsonic, Inc. All rights reserved. +// Copyright (C) Valve Corporation. All rights reserved. // #pragma once @@ -12,13 +12,16 @@ * to be applied at runtime. */ UCLASS(ClassGroup = (Audio), meta = (BlueprintSpawnableComponent), HideCategories = (Activation, Collision, Tags, Rendering, Physics, LOD)) -class PHONON_API UPhononSourceComponent : public USceneComponent +class STEAMAUDIO_API UPhononSourceComponent : public USceneComponent { GENERATED_BODY() public: - - // Any acoustic probes that lie within the bake radius will be used to produce baked impulse response data for this source location. + // Any Phonon probes that lie within the baking radius will be used to produce baked impulse response data for this source location. UPROPERTY(EditAnywhere, Category = Baking) - float BakeRadius = 1.0f; + float BakingRadius = 1600.0f; + + // Users must specify a unique identifier for baked data lookup at runtime. + UPROPERTY(EditAnywhere, Category = Baking) + FName UniqueIdentifier; }; \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononSpatialization.cpp b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononSpatialization.cpp new file mode 100644 index 000000000000..c6d08143b242 --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononSpatialization.cpp @@ -0,0 +1,174 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#include "PhononSpatialization.h" +#include "PhononSpatializationSourceSettings.h" +#include "PhononCommon.h" + +namespace SteamAudio +{ + //============================================================================================================================================== + // FPhononSpatialization + //============================================================================================================================================== + + FPhononSpatialization::FPhononSpatialization() + : BinauralRenderer(nullptr) + { + InputAudioFormat.channelLayout = IPL_CHANNELLAYOUT_MONO; + InputAudioFormat.channelLayoutType = IPL_CHANNELLAYOUTTYPE_SPEAKERS; + InputAudioFormat.channelOrder = IPL_CHANNELORDER_INTERLEAVED; + InputAudioFormat.numSpeakers = 1; + InputAudioFormat.speakerDirections = nullptr; + InputAudioFormat.ambisonicsOrder = -1; + InputAudioFormat.ambisonicsNormalization = IPL_AMBISONICSNORMALIZATION_N3D; + InputAudioFormat.ambisonicsOrdering = IPL_AMBISONICSORDERING_ACN; + + BinauralOutputAudioFormat.channelLayout = IPL_CHANNELLAYOUT_STEREO; + BinauralOutputAudioFormat.channelLayoutType = IPL_CHANNELLAYOUTTYPE_SPEAKERS; + BinauralOutputAudioFormat.channelOrder = IPL_CHANNELORDER_INTERLEAVED; + BinauralOutputAudioFormat.numSpeakers = 2; + BinauralOutputAudioFormat.speakerDirections = nullptr; + BinauralOutputAudioFormat.ambisonicsOrder = -1; + BinauralOutputAudioFormat.ambisonicsNormalization = IPL_AMBISONICSNORMALIZATION_N3D; + BinauralOutputAudioFormat.ambisonicsOrdering = IPL_AMBISONICSORDERING_ACN; + } + + FPhononSpatialization::~FPhononSpatialization() + { + if (BinauralRenderer) + { + iplDestroyBinauralRenderer(&BinauralRenderer); + } + } + + void FPhononSpatialization::Initialize(const uint32 SampleRate, const uint32 NumSources, const uint32 OutputBufferLength) + { + RenderingSettings.convolutionType = IPL_CONVOLUTIONTYPE_PHONON; + RenderingSettings.frameSize = OutputBufferLength; + RenderingSettings.samplingRate = SampleRate; + + iplCreateBinauralRenderer(SteamAudio::GlobalContext, RenderingSettings, nullptr, &BinauralRenderer); + + BinauralSources.AddDefaulted(NumSources); + for (auto& BinauralSource : BinauralSources) + { + BinauralSource.InBuffer.format = InputAudioFormat; + BinauralSource.InBuffer.numSamples = OutputBufferLength; + BinauralSource.InBuffer.interleavedBuffer = nullptr; + BinauralSource.InBuffer.deinterleavedBuffer = nullptr; + + BinauralSource.OutArray.SetNumZeroed(OutputBufferLength * 2); + BinauralSource.OutBuffer.format = BinauralOutputAudioFormat; + BinauralSource.OutBuffer.numSamples = OutputBufferLength; + BinauralSource.OutBuffer.interleavedBuffer = nullptr; + BinauralSource.OutBuffer.deinterleavedBuffer = nullptr; + } + } + + void FPhononSpatialization::OnInitSource(const uint32 SourceId, const FName& AudioComponentUserId, + USpatializationPluginSourceSettingsBase* InSettings) + { + auto SpatializationSettings = static_cast(InSettings); + auto& BinauralSource = BinauralSources[SourceId]; + + UE_LOG(LogSteamAudio, Log, TEXT("Creating spatialization effect.")); + + if (SpatializationSettings) + { + switch (SpatializationSettings->SpatializationMethod) + { + case EIplSpatializationMethod::HRTF: + iplCreateBinauralEffect(BinauralRenderer, InputAudioFormat, BinauralOutputAudioFormat, &BinauralSource.BinauralEffect); + break; + case EIplSpatializationMethod::PANNING: + iplCreatePanningEffect(BinauralRenderer, InputAudioFormat, BinauralOutputAudioFormat, &BinauralSource.PanningEffect); + break; + } + + BinauralSource.SpatializationMethod = SpatializationSettings->SpatializationMethod; + BinauralSource.HrtfInterpolationMethod = SpatializationSettings->HrtfInterpolationMethod; + } + else + { + iplCreateBinauralEffect(BinauralRenderer, InputAudioFormat, BinauralOutputAudioFormat, &BinauralSource.BinauralEffect); + BinauralSource.SpatializationMethod = EIplSpatializationMethod::HRTF; + BinauralSource.HrtfInterpolationMethod = EIplHrtfInterpolationMethod::NEAREST; + } + } + + void FPhononSpatialization::OnReleaseSource(const uint32 SourceId) + { + auto& BinauralSource = BinauralSources[SourceId]; + + UE_LOG(LogSteamAudio, Log, TEXT("Destroying spatialization effect.")); + + switch (BinauralSource.SpatializationMethod) + { + case EIplSpatializationMethod::HRTF: + iplDestroyBinauralEffect(&BinauralSource.BinauralEffect); + break; + case EIplSpatializationMethod::PANNING: + iplDestroyPanningEffect(&BinauralSource.PanningEffect); + break; + } + } + + void FPhononSpatialization::ProcessAudio(const FAudioPluginSourceInputData& InputData, FAudioPluginSourceOutputData& OutputData) + { + auto& BinauralSource = BinauralSources[InputData.SourceId]; + BinauralSource.InBuffer.interleavedBuffer = InputData.AudioBuffer->GetData(); + BinauralSource.OutBuffer.interleavedBuffer = OutputData.AudioBuffer.GetData(); + + // Workaround. The directions passed to spatializer is not consistent with the + // coordinate system of UE4, therefore special tranformation is performed here. + // Review this change if further changes are made to the direction passed to the + // spatializer. + IPLVector3 RelativeDirection; + RelativeDirection.x = InputData.SpatializationParams->EmitterPosition.Y; + RelativeDirection.y = InputData.SpatializationParams->EmitterPosition.X; + RelativeDirection.z = InputData.SpatializationParams->EmitterPosition.Z; + + switch (BinauralSource.SpatializationMethod) + { + case EIplSpatializationMethod::HRTF: + iplApplyBinauralEffect(BinauralSource.BinauralEffect, BinauralSource.InBuffer, RelativeDirection, + static_cast(BinauralSource.HrtfInterpolationMethod), BinauralSource.OutBuffer); + break; + case EIplSpatializationMethod::PANNING: + iplApplyPanningEffect(BinauralSource.PanningEffect, BinauralSource.InBuffer, RelativeDirection, + BinauralSource.OutBuffer); + break; + } + } + + bool FPhononSpatialization::IsSpatializationEffectInitialized() const + { + return true; + } + + //============================================================================================================================================== + // FBinauralSource + //============================================================================================================================================== + + FBinauralSource::FBinauralSource() + : BinauralEffect(nullptr) + , PanningEffect(nullptr) + , SpatializationMethod(EIplSpatializationMethod::HRTF) + , HrtfInterpolationMethod(EIplHrtfInterpolationMethod::NEAREST) + { + } + + FBinauralSource::~FBinauralSource() + { + if (BinauralEffect) + { + iplDestroyBinauralEffect(&BinauralEffect); + } + + if (PanningEffect) + { + iplDestroyPanningEffect(&PanningEffect); + } + } +} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononSpatialization.h b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononSpatialization.h similarity index 58% rename from Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononSpatialization.h rename to Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononSpatialization.h index 29a7beaed0df..8dae7e1bf724 100644 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Private/PhononSpatialization.h +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononSpatialization.h @@ -1,20 +1,24 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. +// +// Copyright (C) Valve Corporation. All rights reserved. +// #pragma once #include "IAudioExtensionPlugin.h" #include "phonon.h" +#include "PhononCommon.h" -namespace Phonon +namespace SteamAudio { - struct FPhononBinauralSource + struct FBinauralSource { - FPhononBinauralSource() - : BinauralEffect(nullptr) - { - } + FBinauralSource(); + ~FBinauralSource(); IPLhandle BinauralEffect; + IPLhandle PanningEffect; + EIplSpatializationMethod SpatializationMethod; + EIplHrtfInterpolationMethod HrtfInterpolationMethod; IPLAudioBuffer InBuffer; IPLAudioBuffer OutBuffer; TArray OutArray; @@ -26,17 +30,18 @@ namespace Phonon FPhononSpatialization(); ~FPhononSpatialization(); - virtual void ProcessAudio(const FAudioPluginSourceInputData& InputData, FAudioPluginSourceOutputData& OutputData) override; - virtual bool IsSpatializationEffectInitialized() const override; virtual void Initialize(const uint32 SampleRate, const uint32 NumSources, const uint32 OutputBufferLength) override; - virtual bool CreateSpatializationEffect(uint32 SourceId) override; - virtual void SetSpatializationSettings(uint32 VoiceId, USpatializationPluginSourceSettingsBase* InSettings) override; + virtual bool IsSpatializationEffectInitialized() const override; + virtual void OnInitSource(const uint32 SourceId, const FName& AudioComponentUserId, + USpatializationPluginSourceSettingsBase* InSettings) override; + virtual void OnReleaseSource(const uint32 SourceId) override; + virtual void ProcessAudio(const FAudioPluginSourceInputData& InputData, FAudioPluginSourceOutputData& OutputData) override; private: IPLAudioFormat InputAudioFormat; IPLAudioFormat BinauralOutputAudioFormat; IPLhandle BinauralRenderer; IPLRenderingSettings RenderingSettings; - TArray BinauralSources; + TArray BinauralSources; }; } diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononSpatializationSourceSettings.cpp b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononSpatializationSourceSettings.cpp new file mode 100644 index 000000000000..8603d25e6486 --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/PhononSpatializationSourceSettings.cpp @@ -0,0 +1,24 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#include "PhononSpatializationSourceSettings.h" + +UPhononSpatializationSourceSettings::UPhononSpatializationSourceSettings() + : SpatializationMethod(EIplSpatializationMethod::HRTF) + , HrtfInterpolationMethod(EIplHrtfInterpolationMethod::NEAREST) +{} + +#if WITH_EDITOR +bool UPhononSpatializationSourceSettings::CanEditChange(const UProperty* InProperty) const +{ + const bool ParentVal = Super::CanEditChange(InProperty); + + if ((InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UPhononSpatializationSourceSettings, HrtfInterpolationMethod))) + { + return ParentVal && SpatializationMethod == EIplSpatializationMethod::HRTF; + } + + return ParentVal; +} +#endif \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/SteamAudioModule.cpp b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/SteamAudioModule.cpp new file mode 100644 index 000000000000..8db5610e6f8d --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/SteamAudioModule.cpp @@ -0,0 +1,322 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#include "SteamAudioModule.h" + +#include "PhononCommon.h" +#include "PhononSpatialization.h" +#include "PhononOcclusion.h" +#include "PhononReverb.h" +#include "PhononScene.h" +#include "SteamAudioSettings.h" +#include "PhononProbeVolume.h" +#include "PhononListenerObserver.h" +#include "AudioDevice.h" + +#include "CoreMinimal.h" +#include "Stats/Stats.h" +#include "Modules/ModuleInterface.h" +#include "Modules/ModuleManager.h" +#include "Classes/Kismet/GameplayStatics.h" +#include "IPluginManager.h" +#include "EngineUtils.h" +#include "Regex.h" +#include "ScopeLock.h" +#include "Misc/Paths.h" +#include "HAL/PlatformProcess.h" + +IMPLEMENT_MODULE(SteamAudio::FSteamAudioModule, SteamAudio) + +namespace SteamAudio +{ + void* FSteamAudioModule::PhononDllHandle = nullptr; + + static bool bModuleStartedUp = false; + + FSteamAudioModule::FSteamAudioModule() + : SpatializationInstance(nullptr) + , OcclusionInstance(nullptr) + , ReverbInstance(nullptr) + , ListenerObserverInstance(nullptr) + , SampleRate(0.0f) + , OwningAudioDevice(nullptr) + , ComputeDevice(nullptr) + , PhononScene(nullptr) + , PhononEnvironment(nullptr) + , EnvironmentalRenderer(nullptr) + , ProbeManager(nullptr) + { + } + + FSteamAudioModule::~FSteamAudioModule() + { + check(!ComputeDevice); + check(!PhononScene); + check(!PhononEnvironment); + check(!EnvironmentalRenderer); + check(!ProbeManager); + } + + void FSteamAudioModule::StartupModule() + { + check(bModuleStartedUp == false); + + bModuleStartedUp = true; + + UE_LOG(LogSteamAudio, Log, TEXT("FSteamAudioModule Startup")); + OwningAudioDevice = nullptr; + + SpatializationInstance = nullptr; + OcclusionInstance = nullptr; + ReverbInstance = nullptr; + ComputeDevice = nullptr; + PhononScene = nullptr; + PhononEnvironment = nullptr; + EnvironmentalRenderer = nullptr; + ProbeManager = nullptr; + SampleRate = 0; + + // We're overriding the IAudioSpatializationPlugin StartupModule, so we must be sure to register + // the modular features. Without this line, we will not see SPATIALIZATION HRTF in the editor UI. + IModularFeatures::Get().RegisterModularFeature(GetModularFeatureName(), this); + + if (!FSteamAudioModule::PhononDllHandle) + { + // TODO: do platform code to get the DLL location for the platform + FString PathToDll = FPaths::EngineDir() / TEXT("Binaries/ThirdParty/Phonon/Win64/"); + + FString DLLToLoad = PathToDll + TEXT("phonon.dll"); + FSteamAudioModule::PhononDllHandle = LoadDll(DLLToLoad); + } + } + + void FSteamAudioModule::ShutdownModule() + { + UE_LOG(LogSteamAudio, Log, TEXT("FSteamAudioModule Shutdown")); + + check(bModuleStartedUp == true); + + bModuleStartedUp = false; + + if (FSteamAudioModule::PhononDllHandle) + { + FPlatformProcess::FreeDllHandle(FSteamAudioModule::PhononDllHandle); + FSteamAudioModule::PhononDllHandle = nullptr; + } + } + + void FSteamAudioModule::CreateEnvironment(UWorld* World, FAudioDevice* InAudioDevice) + { + if (World == nullptr) + { + UE_LOG(LogSteamAudio, Error, TEXT("Unable to create Phonon environment: null World.")); + return; + } + + if (InAudioDevice == nullptr) + { + UE_LOG(LogSteamAudio, Error, TEXT("Unable to create Phonon environment: null Audio Device.")); + return; + } + + check(OwningAudioDevice == nullptr); + OwningAudioDevice = InAudioDevice; + + FString MapName = World->GetMapName(); + + // Strip out the PIE prefix for the map name before looking for the phononscene. + const FRegexPattern PieMapPattern(TEXT("UEDPIE_\\d_")); + FRegexMatcher Matcher(PieMapPattern, MapName); + + // Look for the PIE pattern + if (Matcher.FindNext()) + { + int32 Beginning = Matcher.GetMatchBeginning(); + int32 Ending = Matcher.GetMatchEnding(); + MapName = MapName.Mid(Ending, MapName.Len()); + } + + FString SceneFile = FPaths::GameDir() + "Content/" + MapName + ".phononscene"; + + if (!FPaths::FileExists(SceneFile)) + { + UE_LOG(LogSteamAudio, Error, TEXT("Unable to create Phonon environment: Phonon scene not found. Be sure to export the scene.")); + return; + } + + int32 IndirectImpulseResponseOrder = GetDefault()->IndirectImpulseResponseOrder; + float IndirectImpulseResponseDuration = GetDefault()->IndirectImpulseResponseDuration; + + SimulationSettings.maxConvolutionSources = GetDefault()->MaxSources; + SimulationSettings.numBounces = GetDefault()->RealtimeBounces; + SimulationSettings.numDiffuseSamples = GetDefault()->RealtimeSecondaryRays; + SimulationSettings.numRays = GetDefault()->RealtimeRays; + SimulationSettings.ambisonicsOrder = IndirectImpulseResponseOrder; + SimulationSettings.irDuration = IndirectImpulseResponseDuration; + SimulationSettings.sceneType = IPL_SCENETYPE_PHONON; + + RenderingSettings.convolutionType = IPL_CONVOLUTIONTYPE_PHONON; + RenderingSettings.frameSize = 1024; // FIXME + RenderingSettings.samplingRate = InAudioDevice->SampleRate; + + EnvironmentalOutputAudioFormat.channelLayout = IPL_CHANNELLAYOUT_STEREO; + EnvironmentalOutputAudioFormat.channelLayoutType = IPL_CHANNELLAYOUTTYPE_AMBISONICS; + EnvironmentalOutputAudioFormat.channelOrder = IPL_CHANNELORDER_DEINTERLEAVED; + EnvironmentalOutputAudioFormat.numSpeakers = (IndirectImpulseResponseOrder + 1) * (IndirectImpulseResponseOrder + 1); + EnvironmentalOutputAudioFormat.speakerDirections = nullptr; + EnvironmentalOutputAudioFormat.ambisonicsOrder = IndirectImpulseResponseOrder; + EnvironmentalOutputAudioFormat.ambisonicsNormalization = IPL_AMBISONICSNORMALIZATION_N3D; + EnvironmentalOutputAudioFormat.ambisonicsOrdering = IPL_AMBISONICSORDERING_ACN; + + IPLerror Error = IPLerror::IPL_STATUS_SUCCESS; + + Error = iplLoadFinalizedScene(GlobalContext, SimulationSettings, TCHAR_TO_ANSI(*SceneFile), ComputeDevice, nullptr, &PhononScene); + LogSteamAudioStatus(Error); + + Error = iplCreateProbeManager(&ProbeManager); + LogSteamAudioStatus(Error); + + TArray PhononProbeVolumes; + UGameplayStatics::GetAllActorsOfClass(World, APhononProbeVolume::StaticClass(), PhononProbeVolumes); + + for (AActor* PhononProbeVolumeActor : PhononProbeVolumes) + { + APhononProbeVolume* PhononProbeVolume = Cast(PhononProbeVolumeActor); + IPLhandle ProbeBatch = nullptr; + Error = iplLoadProbeBatch(PhononProbeVolume->GetProbeBatchData(), PhononProbeVolume->GetProbeBatchDataSize(), &ProbeBatch); + LogSteamAudioStatus(Error); + + iplAddProbeBatch(ProbeManager, ProbeBatch); + + ProbeBatches.Add(ProbeBatch); + } + + Error = iplCreateEnvironment(GlobalContext, ComputeDevice, SimulationSettings, PhononScene, ProbeManager, &PhononEnvironment); + LogSteamAudioStatus(Error); + + Error = iplCreateEnvironmentalRenderer(GlobalContext, PhononEnvironment, RenderingSettings, EnvironmentalOutputAudioFormat, &EnvironmentalRenderer); + LogSteamAudioStatus(Error); + + FPhononOcclusion* PhononOcclusion = static_cast(OcclusionInstance.Get()); + PhononOcclusion->SetEnvironmentalRenderer(EnvironmentalRenderer); + + FPhononReverb* PhononReverb = static_cast(ReverbInstance.Get()); + PhononReverb->SetEnvironmentalRenderer(EnvironmentalRenderer); + PhononReverb->CreateReverbEffect(); + } + + void FSteamAudioModule::DestroyEnvironment(FAudioDevice* InAudioDevice) + { + check(OwningAudioDevice == InAudioDevice); + + OwningAudioDevice = nullptr; + + FScopeLock Lock(&EnvironmentCriticalSection); + + FPhononOcclusion* PhononOcclusion = static_cast(OcclusionInstance.Get()); + PhononOcclusion->SetEnvironmentalRenderer(nullptr); + + FPhononReverb* PhononReverb = static_cast(ReverbInstance.Get()); + PhononReverb->SetEnvironmentalRenderer(nullptr); + + if (ProbeManager) + { + for (IPLhandle ProbeBatch : ProbeBatches) + { + iplRemoveProbeBatch(ProbeManager, ProbeBatch); + iplDestroyProbeBatch(&ProbeBatch); + } + + ProbeBatches.Empty(); + + iplDestroyProbeManager(&ProbeManager); + } + + if (EnvironmentalRenderer) + { + iplDestroyEnvironmentalRenderer(&EnvironmentalRenderer); + } + + if (PhononEnvironment) + { + iplDestroyEnvironment(&PhononEnvironment); + } + + if (PhononScene) + { + iplDestroyScene(&PhononScene); + } + + if (ComputeDevice) + { + iplDestroyComputeDevice(&ComputeDevice); + } + } + + bool FSteamAudioModule::ImplementsSpatialization() const + { + return true; + } + + bool FSteamAudioModule::ImplementsOcclusion() const + { + return true; + } + + bool FSteamAudioModule::ImplementsReverb() const + { + return true; + } + + TSharedPtr FSteamAudioModule::CreateSpatializationInterface(class FAudioDevice* AudioDevice) + { + return SpatializationInstance = TSharedPtr(new FPhononSpatialization()); + } + + TSharedPtr FSteamAudioModule::CreateOcclusionInterface(class FAudioDevice* AudioDevice) + { + return OcclusionInstance = TSharedPtr(new FPhononOcclusion()); + } + + TSharedPtr FSteamAudioModule::CreateReverbInterface(class FAudioDevice* AudioDevice) + { + return ReverbInstance = TSharedPtr(new FPhononReverb()); + } + + TSharedPtr FSteamAudioModule::CreateListenerObserverInterface(class FAudioDevice* AudioDevice) + { + return ListenerObserverInstance = TSharedPtr(new FPhononListenerObserver()); + } + + void FSteamAudioModule::SetSampleRate(const int32 InSampleRate) + { + SampleRate = InSampleRate; + } + + FPhononSpatialization* FSteamAudioModule::GetSpatializationInstance() const + { + return static_cast(SpatializationInstance.Get()); + } + + FPhononOcclusion* FSteamAudioModule::GetOcclusionInstance() const + { + return static_cast(OcclusionInstance.Get()); + } + + FPhononReverb* FSteamAudioModule::GetReverbInstance() const + { + return static_cast(ReverbInstance.Get()); + } + + FPhononListenerObserver* FSteamAudioModule::GetListenerObserverInstance() const + { + return static_cast(ListenerObserverInstance.Get()); + } + + FCriticalSection& FSteamAudioModule::GetEnvironmentCriticalSection() + { + return EnvironmentCriticalSection; + } +} + diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/SteamAudioModule.h b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/SteamAudioModule.h new file mode 100644 index 000000000000..bfbda9dde35f --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/SteamAudioModule.h @@ -0,0 +1,62 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#pragma once + +#include "ISteamAudioModule.h" +#include "phonon.h" + +namespace SteamAudio +{ + class FSteamAudioModule : public ISteamAudioModule + { + public: + FSteamAudioModule(); + ~FSteamAudioModule(); + + virtual void StartupModule() override; + virtual void ShutdownModule() override; + + virtual bool ImplementsSpatialization() const override; + virtual bool ImplementsOcclusion() const override; + virtual bool ImplementsReverb() const override; + + virtual TSharedPtr CreateSpatializationInterface(class FAudioDevice* AudioDevice) override; + virtual TSharedPtr CreateOcclusionInterface(class FAudioDevice* AudioDevice) override; + virtual TSharedPtr CreateReverbInterface(class FAudioDevice* AudioDevice) override; + virtual TSharedPtr CreateListenerObserverInterface(class FAudioDevice* AudioDevice) override; + + void CreateEnvironment(UWorld* World, FAudioDevice* InAudioDevice); + void DestroyEnvironment(FAudioDevice* InAudioDevice); + + void SetSampleRate(const int32 SampleRate); + FCriticalSection& GetEnvironmentCriticalSection(); + class FPhononSpatialization* GetSpatializationInstance() const; + class FPhononOcclusion* GetOcclusionInstance() const; + class FPhononReverb* GetReverbInstance() const; + class FPhononListenerObserver* GetListenerObserverInstance() const; + + private: + static void* PhononDllHandle; + + TSharedPtr SpatializationInstance; + TSharedPtr OcclusionInstance; + TSharedPtr ReverbInstance; + TSharedPtr ListenerObserverInstance; + + int32 SampleRate; + FAudioDevice* OwningAudioDevice; + + FCriticalSection EnvironmentCriticalSection; + IPLhandle ComputeDevice; + IPLhandle PhononScene; + IPLhandle PhononEnvironment; + IPLhandle EnvironmentalRenderer; + IPLhandle ProbeManager; + TArray ProbeBatches; + IPLSimulationSettings SimulationSettings; + IPLRenderingSettings RenderingSettings; + IPLAudioFormat EnvironmentalOutputAudioFormat; + }; +} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/SteamAudioSettings.cpp b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/SteamAudioSettings.cpp new file mode 100644 index 000000000000..b658e4f93983 --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/SteamAudioSettings.cpp @@ -0,0 +1,226 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#include "SteamAudioSettings.h" + +USteamAudioSettings::USteamAudioSettings() + : StaticMeshMaterialPreset(EPhononMaterial::GENERIC) + , BSPMaterialPreset(EPhononMaterial::GENERIC) + , LandscapeMaterialPreset(EPhononMaterial::GENERIC) + , ExportBSPGeometry(true) + , ExportLandscapeGeometry(true) + , RealtimeQualityPreset(EQualitySettings::LOW) + , RealtimeBounces(2) + , RealtimeRays(8192) + , RealtimeSecondaryRays(512) + , BakedQualityPreset(EQualitySettings::LOW) + , BakedBounces(128) + , BakedRays(16384) + , BakedSecondaryRays(2048) + , IndirectImpulseResponseOrder(1) + , IndirectImpulseResponseDuration(1.0f) + , IndirectSpatializationMethod(EIplSpatializationMethod::PANNING) + , ReverbSimulationType(EIplSimulationType::DISABLED) + , IndirectContribution(1.0f) + , MaxSources(32) +{ + auto MaterialPreset = SteamAudio::MaterialPresets[StaticMeshMaterialPreset]; + StaticMeshLowFreqAbsorption = MaterialPreset.lowFreqAbsorption; + StaticMeshMidFreqAbsorption = MaterialPreset.midFreqAbsorption; + StaticMeshHighFreqAbsorption = MaterialPreset.highFreqAbsorption; + StaticMeshScattering = MaterialPreset.scattering; + + MaterialPreset = SteamAudio::MaterialPresets[BSPMaterialPreset]; + BSPLowFreqAbsorption = MaterialPreset.lowFreqAbsorption; + BSPMidFreqAbsorption = MaterialPreset.midFreqAbsorption; + BSPHighFreqAbsorption = MaterialPreset.highFreqAbsorption; + BSPScattering = MaterialPreset.scattering; + + MaterialPreset = SteamAudio::MaterialPresets[LandscapeMaterialPreset]; + LandscapeLowFreqAbsorption = MaterialPreset.lowFreqAbsorption; + LandscapeMidFreqAbsorption = MaterialPreset.midFreqAbsorption; + LandscapeHighFreqAbsorption = MaterialPreset.highFreqAbsorption; + LandscapeScattering = MaterialPreset.scattering; +} + +IPLMaterial USteamAudioSettings::GetDefaultStaticMeshMaterial() const +{ + IPLMaterial DAM; + DAM.lowFreqAbsorption = StaticMeshLowFreqAbsorption; + DAM.midFreqAbsorption = StaticMeshMidFreqAbsorption; + DAM.highFreqAbsorption = StaticMeshHighFreqAbsorption; + DAM.scattering = StaticMeshScattering; + + return DAM; +} + +IPLMaterial USteamAudioSettings::GetDefaultBSPMaterial() const +{ + IPLMaterial DAM; + DAM.lowFreqAbsorption = BSPLowFreqAbsorption; + DAM.midFreqAbsorption = BSPMidFreqAbsorption; + DAM.highFreqAbsorption = BSPHighFreqAbsorption; + DAM.scattering = BSPScattering; + + return DAM; +} + +IPLMaterial USteamAudioSettings::GetDefaultLandscapeMaterial() const +{ + IPLMaterial DAM; + DAM.lowFreqAbsorption = LandscapeLowFreqAbsorption; + DAM.midFreqAbsorption = LandscapeMidFreqAbsorption; + DAM.highFreqAbsorption = LandscapeHighFreqAbsorption; + DAM.scattering = LandscapeScattering; + + return DAM; +} + +#if WITH_EDITOR +void USteamAudioSettings::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) +{ + FName PropertyName = (PropertyChangedEvent.Property != nullptr) ? PropertyChangedEvent.Property->GetFName() : NAME_None; + + auto MaterialPreset = SteamAudio::MaterialPresets[StaticMeshMaterialPreset]; + auto RealtimeSimulationQuality = SteamAudio::RealtimeSimulationQualityPresets[RealtimeQualityPreset]; + auto BakedSimulationQuality = SteamAudio::BakedSimulationQualityPresets[BakedQualityPreset]; + + if ((PropertyName == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, StaticMeshMaterialPreset))) + { + StaticMeshLowFreqAbsorption = MaterialPreset.lowFreqAbsorption; + StaticMeshMidFreqAbsorption = MaterialPreset.midFreqAbsorption; + StaticMeshHighFreqAbsorption = MaterialPreset.highFreqAbsorption; + StaticMeshScattering = MaterialPreset.scattering; + + for (TFieldIterator PropIt(GetClass()); PropIt; ++PropIt) + { + UProperty* Property = *PropIt; + if (Property->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, StaticMeshLowFreqAbsorption) || + Property->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, StaticMeshMidFreqAbsorption) || + Property->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, StaticMeshHighFreqAbsorption) || + Property->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, StaticMeshScattering)) + { + UpdateSinglePropertyInConfigFile(Property, GetDefaultConfigFilename()); + } + } + } + else if ((PropertyName == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, BSPMaterialPreset))) + { + MaterialPreset = SteamAudio::MaterialPresets[BSPMaterialPreset]; + BSPLowFreqAbsorption = MaterialPreset.lowFreqAbsorption; + BSPMidFreqAbsorption = MaterialPreset.midFreqAbsorption; + BSPHighFreqAbsorption = MaterialPreset.highFreqAbsorption; + BSPScattering = MaterialPreset.scattering; + + for (TFieldIterator PropIt(GetClass()); PropIt; ++PropIt) + { + UProperty* Property = *PropIt; + if (Property->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, BSPLowFreqAbsorption) || + Property->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, BSPMidFreqAbsorption) || + Property->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, BSPHighFreqAbsorption) || + Property->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, BSPScattering)) + { + UpdateSinglePropertyInConfigFile(Property, GetDefaultConfigFilename()); + } + } + } + else if ((PropertyName == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, LandscapeMaterialPreset))) + { + MaterialPreset = SteamAudio::MaterialPresets[LandscapeMaterialPreset]; + LandscapeLowFreqAbsorption = MaterialPreset.lowFreqAbsorption; + LandscapeMidFreqAbsorption = MaterialPreset.midFreqAbsorption; + LandscapeHighFreqAbsorption = MaterialPreset.highFreqAbsorption; + LandscapeScattering = MaterialPreset.scattering; + + for (TFieldIterator PropIt(GetClass()); PropIt; ++PropIt) + { + UProperty* Property = *PropIt; + if (Property->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, LandscapeLowFreqAbsorption) || + Property->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, LandscapeMidFreqAbsorption) || + Property->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, LandscapeHighFreqAbsorption) || + Property->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, LandscapeScattering)) + { + UpdateSinglePropertyInConfigFile(Property, GetDefaultConfigFilename()); + } + } + } + else if ((PropertyName == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, RealtimeQualityPreset))) + { + RealtimeBounces = RealtimeSimulationQuality.Bounces; + RealtimeRays = RealtimeSimulationQuality.Rays; + RealtimeSecondaryRays = RealtimeSimulationQuality.SecondaryRays; + + for (TFieldIterator PropIt(GetClass()); PropIt; ++PropIt) + { + UProperty* Property = *PropIt; + if (Property->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, RealtimeBounces) || + Property->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, RealtimeRays) || + Property->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, RealtimeSecondaryRays)) + { + UpdateSinglePropertyInConfigFile(Property, GetDefaultConfigFilename()); + } + } + } + else if ((PropertyName == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, BakedQualityPreset))) + { + BakedBounces = BakedSimulationQuality.Bounces; + BakedRays = BakedSimulationQuality.Rays; + BakedSecondaryRays = BakedSimulationQuality.SecondaryRays; + + for (TFieldIterator PropIt(GetClass()); PropIt; ++PropIt) + { + UProperty* Property = *PropIt; + if (Property->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, BakedBounces) || + Property->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, BakedRays) || + Property->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, BakedSecondaryRays)) + { + UpdateSinglePropertyInConfigFile(Property, GetDefaultConfigFilename()); + } + } + } +} + +bool USteamAudioSettings::CanEditChange(const UProperty* InProperty) const +{ + const bool ParentVal = Super::CanEditChange(InProperty); + + if (InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, StaticMeshLowFreqAbsorption) || + InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, StaticMeshMidFreqAbsorption) || + InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, StaticMeshHighFreqAbsorption) || + InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, StaticMeshScattering)) + { + return ParentVal && (StaticMeshMaterialPreset == EPhononMaterial::CUSTOM); + } + else if (InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, BSPLowFreqAbsorption) || + InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, BSPMidFreqAbsorption) || + InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, BSPHighFreqAbsorption) || + InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, BSPScattering)) + { + return ParentVal && (BSPMaterialPreset == EPhononMaterial::CUSTOM); + } + else if (InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, LandscapeLowFreqAbsorption) || + InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, LandscapeMidFreqAbsorption) || + InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, LandscapeHighFreqAbsorption) || + InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, LandscapeScattering)) + { + return ParentVal && (LandscapeMaterialPreset == EPhononMaterial::CUSTOM); + } + else if (InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, RealtimeBounces) || + InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, RealtimeRays) || + InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, RealtimeSecondaryRays)) + { + return ParentVal && (RealtimeQualityPreset == EQualitySettings::CUSTOM); + } + else if (InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, BakedBounces) || + InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, BakedRays) || + InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(USteamAudioSettings, BakedSecondaryRays)) + { + return ParentVal && (BakedQualityPreset == EQualitySettings::CUSTOM); + } + else + { + return ParentVal; + } +} +#endif \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/SteamAudioSettings.h b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/SteamAudioSettings.h new file mode 100644 index 000000000000..f60a02e36f47 --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Private/SteamAudioSettings.h @@ -0,0 +1,193 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#pragma once + +#include "PhononMaterial.h" +#include "PhononCommon.h" +#include "SteamAudioSettings.generated.h" + +UCLASS(config = Engine, defaultconfig) +class STEAMAUDIO_API USteamAudioSettings : public UObject +{ + GENERATED_BODY() + +public: + + USteamAudioSettings(); + + IPLMaterial GetDefaultStaticMeshMaterial() const; + IPLMaterial GetDefaultBSPMaterial() const; + IPLMaterial GetDefaultLandscapeMaterial() const; + +#if WITH_EDITOR + virtual void PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) override; + virtual bool CanEditChange(const UProperty* InProperty) const override; +#endif + + // Which audio engine to use. + UPROPERTY(GlobalConfig, EditAnywhere, Category = General) + EIplAudioEngine AudioEngine; + + //============================================================================================================================================== + + // Whether or not to export BSP geometry. + UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export", meta = (DisplayName = "Export BSP Geometry")) + bool ExportBSPGeometry; + + // Whether or not to export Landscape geometry. + UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export", meta = (DisplayName = "Export Landscape Geometry")) + bool ExportLandscapeGeometry; + + //============================================================================================================================================== + + // Preset material settings for Static Mesh actors. + UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default Static Mesh Material", meta = (DisplayName = "Material Preset")) + EPhononMaterial StaticMeshMaterialPreset; + + // How much this material absorbs low frequency sound. + UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default Static Mesh Material", meta = (ClampMin = "0.0", ClampMax = "1.0", + UIMin = "0.0", UIMax = "1.0", DisplayName = "Low Frequency Absorption")) + float StaticMeshLowFreqAbsorption; + + // How much this material absorbs mid frequency sound. + UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default Static Mesh Material", meta = (ClampMin = "0.0", ClampMax = "1.0", + UIMin = "0.0", UIMax = "1.0", DisplayName = "Mid Frequency Absorption")) + float StaticMeshMidFreqAbsorption; + + // How much this material absorbs high frequency sound. + UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default Static Mesh Material", meta = (ClampMin = "0.0", ClampMax = "1.0", + UIMin = "0.0", UIMax = "1.0", DisplayName = "High Frequency Absorption")) + float StaticMeshHighFreqAbsorption; + + // Specifies how "rough" the surface is. Surfaces with a high scattering value randomly reflect sound in all directions; + // surfaces with a low scattering value reflect sound in a mirror-like manner. + UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default Static Mesh Material", meta = (ClampMin = "0.0", ClampMax = "1.0", + UIMin = "0.0", UIMax = "1.0", DisplayName = "Scattering")) + float StaticMeshScattering; + + //============================================================================================================================================== + + // Preset material settings for BSP geometry. + UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default BSP Material", meta = (DisplayName = "Material Preset")) + EPhononMaterial BSPMaterialPreset; + + // How much this material absorbs low frequency sound. + UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default BSP Material", meta = (ClampMin = "0.0", ClampMax = "1.0", + UIMin = "0.0", UIMax = "1.0", DisplayName = "Low Frequency Absorption")) + float BSPLowFreqAbsorption; + + // How much this material absorbs mid frequency sound. + UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default BSP Material", meta = (ClampMin = "0.0", ClampMax = "1.0", + UIMin = "0.0", UIMax = "1.0", DisplayName = "Mid Frequency Absorption")) + float BSPMidFreqAbsorption; + + // How much this material absorbs high frequency sound. + UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default BSP Material", meta = (ClampMin = "0.0", ClampMax = "1.0", + UIMin = "0.0", UIMax = "1.0", DisplayName = "High Frequency Absorption")) + float BSPHighFreqAbsorption; + + // Specifies how "rough" the surface is. Surfaces with a high scattering value randomly reflect sound in all directions; + // surfaces with a low scattering value reflect sound in a mirror-like manner. + UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default BSP Material", meta = (ClampMin = "0.0", ClampMax = "1.0", + UIMin = "0.0", UIMax = "1.0", DisplayName = "Scattering")) + float BSPScattering; + + //============================================================================================================================================== + + // Preset material settings for landscape actors. + UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default Landscape Material", meta = (DisplayName = "Material Preset")) + EPhononMaterial LandscapeMaterialPreset; + + // How much this material absorbs low frequency sound. + UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default Landscape Material", meta = (ClampMin = "0.0", ClampMax = "1.0", + UIMin = "0.0", UIMax = "1.0", DisplayName = "Low Frequency Absorption")) + float LandscapeLowFreqAbsorption; + + // How much this material absorbs mid frequency sound. + UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default Landscape Material", meta = (ClampMin = "0.0", ClampMax = "1.0", + UIMin = "0.0", UIMax = "1.0", DisplayName = "Mid Frequency Absorption")) + float LandscapeMidFreqAbsorption; + + // How much this material absorbs high frequency sound. + UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default Landscape Material", meta = (ClampMin = "0.0", ClampMax = "1.0", + UIMin = "0.0", UIMax = "1.0", DisplayName = "High Frequency Absorption")) + float LandscapeHighFreqAbsorption; + + // Specifies how "rough" the surface is. Surfaces with a high scattering value randomly reflect sound in all directions; + // surfaces with a low scattering value reflect sound in a mirror-like manner. + UPROPERTY(GlobalConfig, EditAnywhere, Category = "Scene Export|Default Landscape Material", meta = (ClampMin = "0.0", ClampMax = "1.0", + UIMin = "0.0", UIMax = "1.0", DisplayName = "Scattering")) + float LandscapeScattering; + + //============================================================================================================================================== + + // Output of indirect propagation is stored in ambisonics of this order. + UPROPERTY(GlobalConfig, EditAnywhere, Category = IndirectSound, meta = (ClampMin = "0", ClampMax = "4", UIMin = "0", UIMax = "4", + DisplayName = "Ambisonics Order")) + int32 IndirectImpulseResponseOrder; + + // Length of impulse response to compute for each sound source. + UPROPERTY(GlobalConfig, EditAnywhere, Category = IndirectSound, meta = (ClampMin = "0.1", ClampMax = "5.0", UIMin = "0.1", UIMax = "5.0", + DisplayName = "Impulse Response Duration")) + float IndirectImpulseResponseDuration; + + // How to spatialize indirect sound. + UPROPERTY(GlobalConfig, EditAnywhere, Category = IndirectSound) + EIplSpatializationMethod IndirectSpatializationMethod; + + // How to simulate listener-centric reverb. + UPROPERTY(GlobalConfig, EditAnywhere, Category = IndirectSound) + EIplSimulationType ReverbSimulationType; + + // Scaling applied to indirect sound. + UPROPERTY(GlobalConfig, EditAnywhere, Category = IndirectSound, meta = (ClampMin = "0.0", ClampMax = "10.0", UIMin = "0.0", UIMax = "10.0")) + float IndirectContribution; + + // Maximum number of supported sources. + UPROPERTY(GlobalConfig, EditAnywhere, Category = IndirectSound, meta = (ClampMin = "1", ClampMax = "128", UIMin = "1", UIMax = "128")) + uint32 MaxSources; + + //============================================================================================================================================== + + // Preset quality settings for realtime simulation. + UPROPERTY(GlobalConfig, EditAnywhere, Category = "IndirectSound|Real-Time Quality Settings", meta = (DisplayName = "Quality Preset")) + EQualitySettings RealtimeQualityPreset; + + // Number of bounces for realtime simulation. + UPROPERTY(GlobalConfig, EditAnywhere, Category = "IndirectSound|Real-Time Quality Settings", meta = (ClampMin = "1", ClampMax = "32", + UIMin = "1", UIMax = "32", DisplayName = "Bounces")) + int32 RealtimeBounces; + + // Number of rays to trace for realtime simulation. + UPROPERTY(GlobalConfig, EditAnywhere, Category = "IndirectSound|Real-Time Quality Settings", meta = (ClampMin = "512", ClampMax = "16384", + UIMin = "512", UIMax = "16384", DisplayName = "Rays")) + int32 RealtimeRays; + + // Number of secondary rays to trace for realtime simulation. + UPROPERTY(GlobalConfig, EditAnywhere, Category = "IndirectSound|Real-Time Quality Settings", meta = (ClampMin = "128", ClampMax = "4096", + UIMin = "128", UIMax = "4096", DisplayName = "Secondary Rays")) + int32 RealtimeSecondaryRays; + + //============================================================================================================================================== + + // Preset quality settings for baked simulation. + UPROPERTY(GlobalConfig, EditAnywhere, Category = "IndirectSound|Baked Quality Settings", meta = (DisplayName = "Quality Preset")) + EQualitySettings BakedQualityPreset; + + // Number of bounces for baked simulation. + UPROPERTY(GlobalConfig, EditAnywhere, Category = "IndirectSound|Baked Quality Settings", meta = (ClampMin = "16", ClampMax = "256", + UIMin = "16", UIMax = "256", DisplayName = "Bounces")) + int32 BakedBounces; + + // Number of rays to shoot for baked simulation. + UPROPERTY(GlobalConfig, EditAnywhere, Category = "IndirectSound|Baked Quality Settings", meta = (ClampMin = "8192", ClampMax = "65536", + UIMin = "8192", UIMax = "65536", DisplayName = "Rays")) + int32 BakedRays; + + // Number of secondary rays to shoot for baked simulation. + UPROPERTY(GlobalConfig, EditAnywhere, Category = "IndirectSound|Baked Quality Settings", meta = (ClampMin = "1024", ClampMax = "16384", + UIMin = "1024", UIMax = "16384", DisplayName = "Secondary Rays")) + int32 BakedSecondaryRays; +}; \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Public/IPhononModule.h b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Public/ISteamAudioModule.h similarity index 66% rename from Engine/Plugins/Runtime/Phonon/Source/Phonon/Public/IPhononModule.h rename to Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Public/ISteamAudioModule.h index 0f3badb088d3..8b76b1277e65 100644 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Public/IPhononModule.h +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Public/ISteamAudioModule.h @@ -1,10 +1,12 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. +// +// Copyright (C) Valve Corporation. All rights reserved. +// #pragma once #include "IAudioExtensionPlugin.h" -class IPhononModule : public IAudioPlugin +class ISteamAudioModule : public IAudioPlugin { public: @@ -14,9 +16,9 @@ public: * * @return Returns singleton instance, loading the module on demand if needed */ - static inline IPhononModule& Get() + static inline ISteamAudioModule& Get() { - return FModuleManager::LoadModuleChecked("PhononModule"); + return FModuleManager::LoadModuleChecked("SteamAudioModule"); } /** @@ -26,7 +28,7 @@ public: */ static inline bool IsAvailable() { - return FModuleManager::Get().IsModuleLoaded("PhononModule"); + return FModuleManager::Get().IsModuleLoaded("SteamAudioModule"); } }; diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Public/PhononOcclusionSourceSettings.h b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Public/PhononOcclusionSourceSettings.h new file mode 100644 index 000000000000..a37cf72b10f3 --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Public/PhononOcclusionSourceSettings.h @@ -0,0 +1,32 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#pragma once + +#include "IAudioExtensionPlugin.h" +#include "PhononCommon.h" +#include "PhononOcclusionSourceSettings.generated.h" + +UCLASS() +class STEAMAUDIO_API UPhononOcclusionSourceSettings : public UOcclusionPluginSourceSettingsBase +{ + GENERATED_BODY() + +public: + UPhononOcclusionSourceSettings(); + +#if WITH_EDITOR + virtual bool CanEditChange(const UProperty* InProperty) const override; +#endif + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = OcclusionSettings) + EIplDirectOcclusionMethod DirectOcclusionMethod; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = OcclusionSettings) + float DirectOcclusionSourceRadius; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = OcclusionSettings, meta = (DisplayName = "Physics-based Attenuation")) + bool DirectAttenuation; +}; + diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Public/PhononReverbSourceSettings.h b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Public/PhononReverbSourceSettings.h new file mode 100644 index 000000000000..fbb468c02f1e --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Public/PhononReverbSourceSettings.h @@ -0,0 +1,26 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#pragma once + +#include "IAudioExtensionPlugin.h" +#include "PhononCommon.h" +#include "PhononReverbSourceSettings.generated.h" + +UCLASS() +class STEAMAUDIO_API UPhononReverbSourceSettings : public UReverbPluginSourceSettingsBase +{ + GENERATED_BODY() + +public: + UPhononReverbSourceSettings(); + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = ReverbSettings) + EIplSimulationType IndirectSimulationType; + + // Scale factor to make the indirect contribution louder or softer. + UPROPERTY(GlobalConfig, EditAnywhere, Category = ReverbSettings, meta = (ClampMin = "0.0", ClampMax = "10.0", UIMin = "0.0", UIMax = "10.0")) + float IndirectContribution; +}; + diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Public/PhononSpatializationSourceSettings.h b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Public/PhononSpatializationSourceSettings.h new file mode 100644 index 000000000000..fb741b6cef68 --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/Public/PhononSpatializationSourceSettings.h @@ -0,0 +1,29 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#pragma once + +#include "IAudioExtensionPlugin.h" +#include "PhononCommon.h" +#include "PhononSpatializationSourceSettings.generated.h" + +UCLASS() +class STEAMAUDIO_API UPhononSpatializationSourceSettings : public USpatializationPluginSourceSettingsBase +{ + GENERATED_BODY() + +public: + UPhononSpatializationSourceSettings(); + +#if WITH_EDITOR + virtual bool CanEditChange(const UProperty* InProperty) const override; +#endif + + UPROPERTY(GlobalConfig, EditAnywhere, Category = SpatializationSettings) + EIplSpatializationMethod SpatializationMethod; + + UPROPERTY(GlobalConfig, EditAnywhere, Category = SpatializationSettings, meta = (DisplayName = "HRTF Interpolation Method")) + EIplHrtfInterpolationMethod HrtfInterpolationMethod; +}; + diff --git a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Phonon.Build.cs b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/SteamAudio.Build.cs similarity index 86% rename from Engine/Plugins/Runtime/Phonon/Source/Phonon/Phonon.Build.cs rename to Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/SteamAudio.Build.cs index acd88a980105..8f9b24e69a63 100644 --- a/Engine/Plugins/Runtime/Phonon/Source/Phonon/Phonon.Build.cs +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudio/SteamAudio.Build.cs @@ -1,17 +1,17 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. +// Copyright (C) Valve Corporation. All rights reserved. namespace UnrealBuildTool.Rules { - public class Phonon : ModuleRules + public class SteamAudio : ModuleRules { - public Phonon(ReadOnlyTargetRules Target) : base(Target) + public SteamAudio(ReadOnlyTargetRules Target) : base(Target) { OptimizeCode = CodeOptimization.Never; PrivateIncludePaths.AddRange( new string[] { - "Phonon/Private", + "SteamAudio/Private", } ); @@ -56,4 +56,4 @@ namespace UnrealBuildTool.Rules AddEngineThirdPartyPrivateStaticDependencies(Target, "DX11Audio"); } } -} \ No newline at end of file +} diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononOcclusionSettingsFactory.cpp b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononOcclusionSettingsFactory.cpp new file mode 100644 index 000000000000..377db89a320e --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononOcclusionSettingsFactory.cpp @@ -0,0 +1,52 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#include "PhononOcclusionSettingsFactory.h" +#include "PhononOcclusionSourceSettings.h" +#include "UObject/ObjectMacros.h" +#include "UObject/Object.h" + +namespace SteamAudio +{ + FText FAssetTypeActions_PhononOcclusionSettings::GetName() const + { + return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_PhononOcclusionSettings", "Phonon Source Occlusion Settings"); + } + + FColor FAssetTypeActions_PhononOcclusionSettings::GetTypeColor() const + { + return FColor(245, 195, 101); + } + + UClass* FAssetTypeActions_PhononOcclusionSettings::GetSupportedClass() const + { + return UPhononOcclusionSourceSettings::StaticClass(); + } + + uint32 FAssetTypeActions_PhononOcclusionSettings::GetCategories() + { + return EAssetTypeCategories::Sounds; + } +} + +UPhononOcclusionSettingsFactory::UPhononOcclusionSettingsFactory(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + SupportedClass = UPhononOcclusionSourceSettings::StaticClass(); + + bCreateNew = true; + bEditorImport = false; + bEditAfterNew = true; +} + +UObject* UPhononOcclusionSettingsFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, + FFeedbackContext* Warn) +{ + return Cast(NewObject(InParent, InName, Flags)); +} + +uint32 UPhononOcclusionSettingsFactory::GetMenuCategories() const +{ + return EAssetTypeCategories::Sounds; +} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononOcclusionSettingsFactory.h b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononOcclusionSettingsFactory.h new file mode 100644 index 000000000000..b1ea02c0c272 --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononOcclusionSettingsFactory.h @@ -0,0 +1,34 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#pragma once + +#include "IAudioExtensionPlugin.h" +#include "AssetToolsModule.h" +#include "Factories/Factory.h" +#include "AssetTypeActions_Base.h" +#include "PhononOcclusionSettingsFactory.generated.h" + +namespace SteamAudio +{ + class FAssetTypeActions_PhononOcclusionSettings : public FAssetTypeActions_Base + { + public: + virtual FText GetName() const override; + virtual FColor GetTypeColor() const override; + virtual UClass* GetSupportedClass() const override; + virtual uint32 GetCategories() override; + }; +} + +UCLASS(MinimalAPI, hidecategories = Object) +class UPhononOcclusionSettingsFactory : public UFactory +{ + GENERATED_UCLASS_BODY() + + virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, + FFeedbackContext* Warn) override; + + virtual uint32 GetMenuCategories() const override; +}; diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononProbeComponentVisualizer.cpp b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononProbeComponentVisualizer.cpp new file mode 100644 index 000000000000..3720afed00a2 --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononProbeComponentVisualizer.cpp @@ -0,0 +1,24 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#include "PhononProbeComponentVisualizer.h" +#include "PhononProbeComponent.h" +#include "SceneView.h" +#include "SceneManagement.h" + +namespace SteamAudio +{ + void FPhononProbeComponentVisualizer::DrawVisualization(const UActorComponent* Component, const FSceneView* View, FPrimitiveDrawInterface* PDI) + { + const UPhononProbeComponent* ProbeComponent = Cast(Component); + if (ProbeComponent) + { + const FColor Color(0, 153, 255); + for (const auto& ProbeLocation : ProbeComponent->ProbeLocations) + { + PDI->DrawPoint(ProbeLocation, Color, 10, SDPG_World); + } + } + } +} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononProbeComponentVisualizer.h b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononProbeComponentVisualizer.h new file mode 100644 index 000000000000..de556c5ce7ac --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononProbeComponentVisualizer.h @@ -0,0 +1,19 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#pragma once + +#include "ComponentVisualizer.h" + +class FPrimitiveDrawInterface; +class FSceneView; + +namespace SteamAudio +{ + class FPhononProbeComponentVisualizer : public FComponentVisualizer + { + public: + virtual void DrawVisualization(const UActorComponent* Component, const FSceneView* View, FPrimitiveDrawInterface* PDI) override; + }; +} diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononProbeVolumeDetails.cpp b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononProbeVolumeDetails.cpp new file mode 100644 index 000000000000..7b6377a7825b --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononProbeVolumeDetails.cpp @@ -0,0 +1,221 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#include "PhononProbeVolumeDetails.h" + +#include "DetailLayoutBuilder.h" +#include "DetailCategoryBuilder.h" +#include "DetailWidgetRow.h" +#include "IDetailsView.h" +#include "IDetailCustomization.h" +#include "PhononProbeVolume.h" +#include "PhononProbeComponent.h" +#include "TickableNotification.h" +#include "Async/Async.h" +#include "PhononScene.h" +#include "LevelEditorViewport.h" +#include "Settings/LevelEditorPlaySettings.h" +#include "Settings/LevelEditorViewportSettings.h" +#include "PropertyCustomizationHelpers.h" +#include "IDetailChildrenBuilder.h" +#include "IDetailPropertyRow.h" +#include "Widgets/Input/SButton.h" +#include "Widgets/Text/STextBlock.h" +#include "Widgets/Layout/SBox.h" +#include "Editor.h" + +namespace SteamAudio +{ + static TSharedPtr GGenerateProbesTickable = MakeShareable(new FTickableNotification()); + + static void GenerateProbesProgressCallback(float Progress) + { + FFormatNamedArguments Arguments; + Arguments.Add(TEXT("GenerateProbesProgress"), FText::AsPercent(Progress)); + GGenerateProbesTickable->SetDisplayText(FText::Format(NSLOCTEXT("SteamAudio", "ComputingProbeLocationsText", + "Computing probe locations ({GenerateProbesProgress} complete)"), Arguments)); + } + + TSharedRef FPhononProbeVolumeDetails::MakeInstance() + { + return MakeShareable(new FPhononProbeVolumeDetails); + } + + FText GetKBTextFromByte(const int32 NumBytes) + { + float NumKilobytes = (float)NumBytes / 1000.0f; + NumKilobytes = (float)roundf(NumKilobytes * 10) / 10; + FFormatNamedArguments Arguments; + Arguments.Add(TEXT("NumKilobytes"), FText::AsNumber(NumKilobytes)); + return FText::Format(NSLOCTEXT("KBText", "KBText", "{NumKilobytes} KB"), Arguments); + } + + FText FPhononProbeVolumeDetails::GetTotalDataSize() + { + return GetKBTextFromByte(PhononProbeVolume->ProbeBoxDataSize); + } + + void FPhononProbeVolumeDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLayout) + { + const TArray>& SelectedObjects = DetailLayout.GetDetailsView().GetSelectedObjects(); + + for (int32 ObjectIndex = 0; ObjectIndex < SelectedObjects.Num(); ++ObjectIndex) + { + const TWeakObjectPtr& CurrentObject = SelectedObjects[ObjectIndex]; + if (CurrentObject.IsValid()) + { + APhononProbeVolume* CurrentCaptureActor = Cast(CurrentObject.Get()); + if (CurrentCaptureActor) + { + PhononProbeVolume = CurrentCaptureActor; + break; + } + } + } + + DetailLayout.HideCategory("BrushSettings"); + + DetailLayout.EditCategory("ProbeGeneration").AddProperty(GET_MEMBER_NAME_CHECKED(APhononProbeVolume, PlacementStrategy)); + DetailLayout.EditCategory("ProbeGeneration").AddProperty(GET_MEMBER_NAME_CHECKED(APhononProbeVolume, HorizontalSpacing)); + DetailLayout.EditCategory("ProbeGeneration").AddProperty(GET_MEMBER_NAME_CHECKED(APhononProbeVolume, HeightAboveFloor)); + DetailLayout.EditCategory("ProbeGeneration").AddCustomRow(NSLOCTEXT("PhononProbeVolumeDetails", "Generate Probes", "Generate Probes")) + .NameContent() + [ + SNullWidget::NullWidget + ] + .ValueContent() + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(SButton) + .ContentPadding(2) + .VAlign(VAlign_Center) + .HAlign(HAlign_Center) + .OnClicked(this, &FPhononProbeVolumeDetails::OnGenerateProbes) + [ + SNew(STextBlock) + .Text(NSLOCTEXT("PhononProbeVolumeDetails", "Generate Probes", "Generate Probes")) + .Font(IDetailLayoutBuilder::GetDetailFont()) + ] + ] + ]; + + TSharedPtr BakedDataProperty = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(APhononProbeVolume, BakedDataInfo)); + TSharedRef BakedDataBuilder = MakeShareable(new FDetailArrayBuilder(BakedDataProperty.ToSharedRef())); + BakedDataBuilder->OnGenerateArrayElementWidget(FOnGenerateArrayElementWidget::CreateSP(this, &FPhononProbeVolumeDetails::OnGenerateBakedDataInfo)); + DetailLayout.EditCategory("ProbeVolumeStatistics").AddProperty(GET_MEMBER_NAME_CHECKED(APhononProbeVolume, NumProbes)); + + auto ProbeDataSize = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(APhononProbeVolume, ProbeBoxDataSize)); + TAttribute TotalDataSize = TAttribute::Create(TAttribute::FGetter::CreateSP(this, &FPhononProbeVolumeDetails::GetTotalDataSize)); + + DetailLayout.EditCategory("ProbeVolumeStatistics").AddProperty(ProbeDataSize).CustomWidget() + .NameContent() + [ + SNew(STextBlock) + .Text(NSLOCTEXT("PhononProbeVolumeDetails", "Probe Data Size", "Probe Data Size")) + .Font(IDetailLayoutBuilder::GetDetailFont()) + ] + .ValueContent() + [ + SNew(STextBlock) + .Text(TotalDataSize) + .Font(IDetailLayoutBuilder::GetDetailFont()) + ]; + DetailLayout.EditCategory("ProbeVolumeStatistics").AddCustomBuilder(BakedDataBuilder); + } + + void FPhononProbeVolumeDetails::OnGenerateBakedDataInfo(TSharedRef PropertyHandle, int32 ArrayIndex, IDetailChildrenBuilder& ChildrenBuilder) + { + auto& BakedDataRow = ChildrenBuilder.AddChildProperty(PropertyHandle); + auto& BakedDataInfo = PhononProbeVolume->BakedDataInfo[ArrayIndex]; + + BakedDataRow.ShowPropertyButtons(false); + BakedDataRow.CustomWidget(false) + .NameContent() + [ + SNew(STextBlock) + .Text(FText::FromName(BakedDataInfo.Name)) + .Font(IDetailLayoutBuilder::GetDetailFont()) + ] + .ValueContent() + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + [ + SNew(SBox) + .MinDesiredWidth(200) + .VAlign(VAlign_Center) + [ + SNew(STextBlock) + .Text(GetKBTextFromByte(BakedDataInfo.Size)) + .Font(IDetailLayoutBuilder::GetDetailFont()) + ] + ] + + SHorizontalBox::Slot() + .AutoWidth() + [ + PropertyCustomizationHelpers::MakeDeleteButton(FSimpleDelegate::CreateSP(this, &FPhononProbeVolumeDetails::OnClearBakedDataClicked, ArrayIndex)) + ] + ]; + } + + void FPhononProbeVolumeDetails::OnClearBakedDataClicked(const int32 ArrayIndex) + { + IPLhandle ProbeBox = nullptr; + iplLoadProbeBox(PhononProbeVolume->GetProbeBoxData(), PhononProbeVolume->GetProbeBoxDataSize(), &ProbeBox); + iplDeleteBakedDataByName(ProbeBox, TCHAR_TO_ANSI(*PhononProbeVolume->BakedDataInfo[ArrayIndex].Name.ToString())); + PhononProbeVolume->BakedDataInfo.RemoveAt(ArrayIndex); + PhononProbeVolume->UpdateProbeBoxData(ProbeBox); + iplDestroyProbeBox(&ProbeBox); + } + + FReply FPhononProbeVolumeDetails::OnGenerateProbes() + { + GGenerateProbesTickable->SetDisplayText(NSLOCTEXT("SteamAudio", "Generating probes...", "Generating probes...")); + GGenerateProbesTickable->CreateNotification(); + + // Grab a copy of the volume ptr as it will be destroyed if user clicks off of volume in GUI + auto PhononProbeVolumeHandle = PhononProbeVolume.Get(); + + // Load the scene + UWorld* World = GEditor->LevelViewportClients[0]->GetWorld(); + IPLhandle PhononScene = nullptr; + TArray PhononStaticMeshes; + SteamAudio::LoadScene(World, &PhononScene, &PhononStaticMeshes); + + AsyncTask(ENamedThreads::AnyNormalThreadNormalTask, [=]() + { + // Place probes + IPLhandle SceneCopy = PhononScene; + TArray ProbeSpheres; + PhononProbeVolumeHandle->PlaceProbes(PhononScene, GenerateProbesProgressCallback, ProbeSpheres); + PhononProbeVolumeHandle->BakedDataInfo.Empty(); + + // Release Phonon resources + for (IPLhandle PhononStaticMesh : PhononStaticMeshes) + { + iplDestroyStaticMesh(&PhononStaticMesh); + } + iplDestroyScene(&SceneCopy); + + // Update probe component with new probe locations + auto& ProbeLocations = PhononProbeVolumeHandle->GetPhononProbeComponent()->ProbeLocations; + ProbeLocations.Empty(); + ProbeLocations.SetNumUninitialized(ProbeSpheres.Num()); + for (auto i = 0; i < ProbeSpheres.Num(); ++i) + { + ProbeLocations[i] = SteamAudio::PhononToUnrealFVector(SteamAudio::FVectorFromIPLVector3(ProbeSpheres[i].center)); + } + + // Notify UI that we're done + GGenerateProbesTickable->QueueWorkItem(FWorkItem([](FText& DisplayText) { + DisplayText = NSLOCTEXT("SteamAudio", "Probe placement complete.", "Probe placement complete."); + }, SNotificationItem::CS_Success, true)); + }); + + return FReply::Handled(); + } +} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononProbeVolumeDetails.h b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononProbeVolumeDetails.h similarity index 56% rename from Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononProbeVolumeDetails.h rename to Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononProbeVolumeDetails.h index 1e689f68e3e5..97327beff65f 100644 --- a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononProbeVolumeDetails.h +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononProbeVolumeDetails.h @@ -1,5 +1,5 @@ // -// Copyright (C) Impulsonic, Inc. All rights reserved. +// Copyright (C) Valve Corporation. All rights reserved. // #pragma once @@ -8,9 +8,11 @@ #include "Input/Reply.h" class IDetailLayoutBuilder; +class IDetailChildrenBuilder; +class IPropertyHandle; class APhononProbeVolume; -namespace Phonon +namespace SteamAudio { class FPhononProbeVolumeDetails : public IDetailCustomization { @@ -20,8 +22,11 @@ namespace Phonon private: virtual void CustomizeDetails(IDetailLayoutBuilder& DetailLayout) override; - FReply OnGenerateProbes(); + void OnGenerateBakedDataInfo(TSharedRef PropertyHandle, int32 ArrayIndex, IDetailChildrenBuilder& ChildrenBuilder); + void OnClearBakedDataClicked(const int32 ArrayIndex); + FText GetTotalDataSize(); + FReply OnGenerateProbes(); TWeakObjectPtr PhononProbeVolume; }; } \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononReverbSettingsFactory.cpp b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononReverbSettingsFactory.cpp new file mode 100644 index 000000000000..a10c2b00771e --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononReverbSettingsFactory.cpp @@ -0,0 +1,52 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#include "PhononReverbSettingsFactory.h" +#include "PhononReverbSourceSettings.h" +#include "UObject/ObjectMacros.h" +#include "UObject/Object.h" + +namespace SteamAudio +{ + FText FAssetTypeActions_PhononReverbSettings::GetName() const + { + return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_PhononReverbSettings", "Phonon Source Reverb Settings"); + } + + FColor FAssetTypeActions_PhononReverbSettings::GetTypeColor() const + { + return FColor(245, 195, 101); + } + + UClass* FAssetTypeActions_PhononReverbSettings::GetSupportedClass() const + { + return UPhononReverbSourceSettings::StaticClass(); + } + + uint32 FAssetTypeActions_PhononReverbSettings::GetCategories() + { + return EAssetTypeCategories::Sounds; + } +} + +UPhononReverbSettingsFactory::UPhononReverbSettingsFactory(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + SupportedClass = UPhononReverbSourceSettings::StaticClass(); + + bCreateNew = true; + bEditorImport = false; + bEditAfterNew = true; +} + +UObject* UPhononReverbSettingsFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, + FFeedbackContext* Warn) +{ + return Cast(NewObject(InParent, InName, Flags)); +} + +uint32 UPhononReverbSettingsFactory::GetMenuCategories() const +{ + return EAssetTypeCategories::Sounds; +} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononReverbSettingsFactory.h b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononReverbSettingsFactory.h new file mode 100644 index 000000000000..6806c8f2c6bf --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononReverbSettingsFactory.h @@ -0,0 +1,34 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#pragma once + +#include "IAudioExtensionPlugin.h" +#include "AssetToolsModule.h" +#include "Factories/Factory.h" +#include "AssetTypeActions_Base.h" +#include "PhononReverbSettingsFactory.generated.h" + +namespace SteamAudio +{ + class FAssetTypeActions_PhononReverbSettings : public FAssetTypeActions_Base + { + public: + virtual FText GetName() const override; + virtual FColor GetTypeColor() const override; + virtual UClass* GetSupportedClass() const override; + virtual uint32 GetCategories() override; + }; +} + +UCLASS(MinimalAPI, hidecategories = Object) +class UPhononReverbSettingsFactory : public UFactory +{ + GENERATED_UCLASS_BODY() + + virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, + FFeedbackContext* Warn) override; + + virtual uint32 GetMenuCategories() const override; +}; diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononSourceComponentDetails.cpp b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononSourceComponentDetails.cpp new file mode 100644 index 000000000000..36cffeeec52d --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononSourceComponentDetails.cpp @@ -0,0 +1,268 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#include "PhononSourceComponentDetails.h" + +#include "PhononCommon.h" +#include "PhononSourceComponent.h" +#include "PhononProbeVolume.h" +#include "SteamAudioSettings.h" +#include "SteamAudioEditorModule.h" +#include "TickableNotification.h" +#include "phonon.h" +#include "Components/AudioComponent.h" + +#include "DetailLayoutBuilder.h" +#include "DetailCategoryBuilder.h" +#include "DetailWidgetRow.h" +#include "IDetailsView.h" +#include "IDetailCustomization.h" +#include "IDetailChildrenBuilder.h" +#include "LevelEditorViewport.h" +#include "Kismet/GameplayStatics.h" +#include "Async/Async.h" +#include "EngineUtils.h" +#include "Widgets/Input/SButton.h" +#include "Widgets/Text/STextBlock.h" +#include "Editor.h" + +#include + +namespace SteamAudio +{ + //============================================================================================================================================== + // Global data and functions for baking + //============================================================================================================================================== + + static TSharedPtr GBakeSourcePropagationTickable = MakeShareable(new SteamAudio::FTickableNotification()); + static int32 GCurrentSourceProbeVolume = 0; + static int32 GNumSourceProbeVolumes = 0; + static std::atomic GIsBakingSourcePropagation = false; + + static void LoadSceneProgressCallback(float Progress) + { + } + + static void BakePropagationProgressCallback(float Progress) + { + FFormatNamedArguments Arguments; + Arguments.Add(TEXT("BakeProgress"), FText::AsPercent(Progress)); + Arguments.Add(TEXT("CurrentProbeVolume"), FText::AsNumber(GCurrentSourceProbeVolume)); + Arguments.Add(TEXT("NumProbeVolumes"), FText::AsNumber(GNumSourceProbeVolumes)); + GBakeSourcePropagationTickable->SetDisplayText(FText::Format(NSLOCTEXT("SteamAudio", "BakeText", + "Baking {CurrentProbeVolume}/{NumProbeVolumes} probe volumes ({BakeProgress} complete)"), Arguments)); + } + + //============================================================================================================================================== + // FPhononSourceComponentDetails + //============================================================================================================================================== + + TSharedRef FPhononSourceComponentDetails::MakeInstance() + { + return MakeShareable(new FPhononSourceComponentDetails()); + } + + void FPhononSourceComponentDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLayout) + { + const TArray>& SelectedObjects = DetailLayout.GetDetailsView().GetSelectedObjects(); + + for (int32 ObjectIndex = 0; ObjectIndex < SelectedObjects.Num(); ++ObjectIndex) + { + const TWeakObjectPtr& CurrentObject = SelectedObjects[ObjectIndex]; + if (CurrentObject.IsValid()) + { + auto SelectedPhononSourceComponent = Cast(CurrentObject.Get()); + if (SelectedPhononSourceComponent) + { + PhononSourceComponent = SelectedPhononSourceComponent; + break; + } + } + } + + DetailLayout.EditCategory("Baking").AddProperty(GET_MEMBER_NAME_CHECKED(UPhononSourceComponent, UniqueIdentifier)); + DetailLayout.EditCategory("Baking").AddProperty(GET_MEMBER_NAME_CHECKED(UPhononSourceComponent, BakingRadius)); + DetailLayout.EditCategory("Baking").AddCustomRow(NSLOCTEXT("PhononSourceComponentDetails", "Bake Propagation", "Bake Propagation")) + .NameContent() + [ + SNullWidget::NullWidget + ] + .ValueContent() + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(SButton) + .ContentPadding(2) + .VAlign(VAlign_Center) + .HAlign(HAlign_Center) + .IsEnabled(this, &FPhononSourceComponentDetails::IsBakeEnabled) + .OnClicked(this, &FPhononSourceComponentDetails::OnBakePropagation) + [ + SNew(STextBlock) + .Text(NSLOCTEXT("PhononSourceComponentDetails", "Bake Propagation", "Bake Propagation")) + .Font(IDetailLayoutBuilder::GetDetailFont()) + ] + ] + ]; + } + + FReply FPhononSourceComponentDetails::OnBakePropagation() + { + GIsBakingSourcePropagation.store(true); + + GBakeSourcePropagationTickable->SetDisplayText(NSLOCTEXT("SteamAudio", "Baking propagation...", "Baking propagation...")); + GBakeSourcePropagationTickable->CreateNotificationWithCancel(FSimpleDelegate::CreateRaw(this, &FPhononSourceComponentDetails::CancelBakePropagation)); + + auto World = GEditor->LevelViewportClients[0]->GetWorld(); + check(World); + + // Get all probe volumes (cannot do this in the async task - not on game thread) + TArray PhononProbeVolumes; + UGameplayStatics::GetAllActorsOfClass(World, APhononProbeVolume::StaticClass(), PhononProbeVolumes); + + // Ensure we have at least one probe + bool AtLeastOneProbe = false; + + for (auto PhononProbeVolumeActor : PhononProbeVolumes) + { + auto PhononProbeVolume = Cast(PhononProbeVolumeActor); + if (PhononProbeVolume->NumProbes > 0) + { + AtLeastOneProbe = true; + break; + } + } + + if (!AtLeastOneProbe) + { + UE_LOG(LogSteamAudioEditor, Error, TEXT("Ensure at least one Phonon Probe Volume with probes exists.")); + GBakeSourcePropagationTickable->SetDisplayText(NSLOCTEXT("SteamAudio", "Bake failed.", "Bake failed. Create at least one Phonon Probe Volume that has probes.")); + GBakeSourcePropagationTickable->DestroyNotification(SNotificationItem::CS_Fail); + GIsBakingSourcePropagation.store(false); + return FReply::Handled(); + } + + // Set the User ID on the audio component + auto AudioComponent = static_cast(PhononSourceComponent->GetOwner()->GetComponentByClass(UAudioComponent::StaticClass())); + AudioComponent->AudioComponentUserID = PhononSourceComponent->UniqueIdentifier; + + AsyncTask(ENamedThreads::AnyNormalThreadNormalTask, [=]() + { + IPLBakingSettings BakingSettings; + BakingSettings.bakeParametric = IPL_FALSE; + BakingSettings.bakeConvolution = IPL_TRUE; + + IPLSimulationSettings SimulationSettings; + SimulationSettings.sceneType = IPL_SCENETYPE_PHONON; + SimulationSettings.irDuration = GetDefault()->IndirectImpulseResponseDuration; + SimulationSettings.ambisonicsOrder = GetDefault()->IndirectImpulseResponseOrder; + SimulationSettings.maxConvolutionSources = 0; + SimulationSettings.numBounces = GetDefault()->BakedBounces; + SimulationSettings.numRays = GetDefault()->BakedRays; + SimulationSettings.numDiffuseSamples = GetDefault()->BakedSecondaryRays; + + IPLhandle ComputeDevice = nullptr; + IPLhandle PhononScene = nullptr; + IPLhandle PhononEnvironment = nullptr; + + // Grab a copy of the component ptr because it will be destroyed if user clicks off of it in GUI + auto PhononSourceComponentHandle = PhononSourceComponent.Get(); + + GBakeSourcePropagationTickable->SetDisplayText(NSLOCTEXT("SteamAudio", "Loading scene...", "Loading scene...")); + + FString SceneFile = FPaths::GameDir() + "Content/" + World->GetMapName() + ".phononscene"; + + if (FPaths::FileExists(SceneFile)) + { + iplLoadFinalizedScene(SteamAudio::GlobalContext, SimulationSettings, TCHAR_TO_ANSI(*SceneFile), ComputeDevice, LoadSceneProgressCallback, &PhononScene); + iplCreateEnvironment(SteamAudio::GlobalContext, ComputeDevice, SimulationSettings, PhononScene, nullptr, &PhononEnvironment); + } + else + { + UE_LOG(LogSteamAudioEditor, Error, TEXT("Unable to load scene: %s not found."), *SceneFile); + GBakeSourcePropagationTickable->SetDisplayText(NSLOCTEXT("SteamAudio", "Bake failed.", "Bake failed. Export scene first.")); + GBakeSourcePropagationTickable->DestroyNotification(SNotificationItem::CS_Fail); + GIsBakingSourcePropagation.store(false); + return; + } + + GBakeSourcePropagationTickable->SetDisplayText(NSLOCTEXT("SteamAudio", "Baking...", "Baking...")); + GNumSourceProbeVolumes = PhononProbeVolumes.Num(); + GCurrentSourceProbeVolume = 1; + + for (auto PhononProbeVolumeActor : PhononProbeVolumes) + { + auto PhononProbeVolume = Cast(PhononProbeVolumeActor); + + IPLhandle ProbeBox = nullptr; + iplLoadProbeBox(PhononProbeVolume->GetProbeBoxData(), PhononProbeVolume->GetProbeBoxDataSize(), &ProbeBox); + + IPLSphere SourceInfluence; + SourceInfluence.radius = PhononSourceComponentHandle->BakingRadius * SteamAudio::SCALEFACTOR; + SourceInfluence.center = SteamAudio::UnrealToPhononIPLVector3(PhononSourceComponentHandle->GetComponentLocation()); + + auto AudioComponent = static_cast(PhononSourceComponentHandle->GetOwner()->GetComponentByClass(UAudioComponent::StaticClass())); + + iplDeleteBakedDataByName(ProbeBox, TCHAR_TO_ANSI(*AudioComponent->GetAudioComponentUserID().ToString())); + iplBakePropagation(PhononEnvironment, ProbeBox, SourceInfluence, TCHAR_TO_ANSI(*AudioComponent->GetAudioComponentUserID().ToString()), + BakingSettings, BakePropagationProgressCallback); + + FBakedDataInfo BakedDataInfo; + BakedDataInfo.Name = PhononSourceComponentHandle->UniqueIdentifier; + BakedDataInfo.Size = iplGetBakedDataSizeByName(ProbeBox, TCHAR_TO_ANSI(*PhononSourceComponentHandle->UniqueIdentifier.ToString())); + + auto ExistingInfo = PhononProbeVolume->BakedDataInfo.FindByPredicate([=](const FBakedDataInfo& InfoItem) + { + return InfoItem.Name == BakedDataInfo.Name; + }); + + if (ExistingInfo) + { + ExistingInfo->Size = BakedDataInfo.Size; + } + else + { + PhononProbeVolume->BakedDataInfo.Add(BakedDataInfo); + PhononProbeVolume->BakedDataInfo.Sort(); + } + + if (!GIsBakingSourcePropagation.load()) + { + iplDestroyEnvironment(&PhononEnvironment); + iplDestroyScene(&PhononScene); + GBakeSourcePropagationTickable->SetDisplayText(NSLOCTEXT("SteamAudio", "Bake propagation cancelled.", "Bake propagation cancelled.")); + GBakeSourcePropagationTickable->DestroyNotification(SNotificationItem::CS_Fail); + return; + } + + PhononProbeVolume->UpdateProbeBoxData(ProbeBox); + iplDestroyProbeBox(&ProbeBox); + ++GCurrentSourceProbeVolume; + } + + iplDestroyEnvironment(&PhononEnvironment); + iplDestroyScene(&PhononScene); + + // Display editor notification + GBakeSourcePropagationTickable->SetDisplayText(NSLOCTEXT("SteamAudio", "Bake propagation complete.", "Bake propagation complete.")); + GBakeSourcePropagationTickable->DestroyNotification(); + GIsBakingSourcePropagation.store(false); + }); + + return FReply::Handled(); + } + + void FPhononSourceComponentDetails::CancelBakePropagation() + { + iplCancelBake(); + GIsBakingSourcePropagation.store(false); + } + + bool FPhononSourceComponentDetails::IsBakeEnabled() const + { + return !(PhononSourceComponent->UniqueIdentifier.IsNone() || GIsBakingSourcePropagation.load()); + } +} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononSourceComponentDetails.h b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononSourceComponentDetails.h similarity index 72% rename from Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononSourceComponentDetails.h rename to Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononSourceComponentDetails.h index 9892e0d00114..fe8935feaf37 100644 --- a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononSourceComponentDetails.h +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononSourceComponentDetails.h @@ -1,5 +1,5 @@ // -// Copyright (C) Impulsonic, Inc. All rights reserved. +// Copyright (C) Valve Corporation. All rights reserved. // #pragma once @@ -10,22 +10,20 @@ class UPhononSourceComponent; class IDetailLayoutBuilder; -namespace Phonon +namespace SteamAudio { class FPhononSourceComponentDetails : public IDetailCustomization { public: - FPhononSourceComponentDetails(); - static TSharedRef MakeInstance(); private: virtual void CustomizeDetails(IDetailLayoutBuilder& DetailLayout) override; FReply OnBakePropagation(); + bool IsBakeEnabled() const; + void CancelBakePropagation(); TWeakObjectPtr PhononSourceComponent; - - TSharedPtr BakePropagationTickable; }; -} \ No newline at end of file +} diff --git a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononSourceComponentVisualizer.cpp b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononSourceComponentVisualizer.cpp similarity index 76% rename from Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononSourceComponentVisualizer.cpp rename to Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononSourceComponentVisualizer.cpp index 01d9447a5002..fc8d3752d6fc 100644 --- a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononSourceComponentVisualizer.cpp +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononSourceComponentVisualizer.cpp @@ -1,11 +1,13 @@ // -// Copyright (C) Impulsonic, Inc. All rights reserved. +// Copyright (C) Valve Corporation. All rights reserved. // #include "PhononSourceComponentVisualizer.h" #include "PhononSourceComponent.h" +#include "SceneView.h" +#include "SceneManagement.h" -namespace Phonon +namespace SteamAudio { void FPhononSourceComponentVisualizer::DrawVisualization(const UActorComponent* Component, const FSceneView* View, FPrimitiveDrawInterface* PDI) { @@ -15,7 +17,7 @@ namespace Phonon const FColor OuterRadiusColor(0, 153, 255); auto Translation = AttenuatedComponent->GetComponentTransform().GetTranslation(); - DrawWireSphereAutoSides(PDI, Translation, OuterRadiusColor, AttenuatedComponent->BakeRadius * 100, SDPG_World); + DrawWireSphereAutoSides(PDI, Translation, OuterRadiusColor, AttenuatedComponent->BakingRadius, SDPG_World); } } } \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononSourceComponentVisualizer.h b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononSourceComponentVisualizer.h similarity index 64% rename from Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononSourceComponentVisualizer.h rename to Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononSourceComponentVisualizer.h index 7c84eb108d98..474734367b58 100644 --- a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononSourceComponentVisualizer.h +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononSourceComponentVisualizer.h @@ -1,19 +1,19 @@ // -// Copyright (C) Impulsonic, Inc. All rights reserved. +// Copyright (C) Valve Corporation. All rights reserved. // #pragma once #include "ComponentVisualizer.h" -#include "ShowFlags.h" -#include "SceneView.h" -#include "SceneManagement.h" -namespace Phonon +class FPrimitiveDrawInterface; +class FSceneView; + +namespace SteamAudio { class FPhononSourceComponentVisualizer : public FComponentVisualizer { public: virtual void DrawVisualization(const UActorComponent* Component, const FSceneView* View, FPrimitiveDrawInterface* PDI) override; }; -} \ No newline at end of file +} diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononSpatializationSettingsFactory.cpp b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononSpatializationSettingsFactory.cpp new file mode 100644 index 000000000000..39b761ceae0b --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononSpatializationSettingsFactory.cpp @@ -0,0 +1,52 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#include "PhononSpatializationSettingsFactory.h" +#include "PhononSpatializationSourceSettings.h" +#include "UObject/ObjectMacros.h" +#include "UObject/Object.h" + +namespace SteamAudio +{ + FText FAssetTypeActions_PhononSpatializationSettings::GetName() const + { + return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_PhononSpatializationSettings", "Phonon Source Spatialization Settings"); + } + + FColor FAssetTypeActions_PhononSpatializationSettings::GetTypeColor() const + { + return FColor(245, 195, 101); + } + + UClass* FAssetTypeActions_PhononSpatializationSettings::GetSupportedClass() const + { + return UPhononSpatializationSourceSettings::StaticClass(); + } + + uint32 FAssetTypeActions_PhononSpatializationSettings::GetCategories() + { + return EAssetTypeCategories::Sounds; + } +} + +UPhononSpatializationSettingsFactory::UPhononSpatializationSettingsFactory(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + SupportedClass = UPhononSpatializationSourceSettings::StaticClass(); + + bCreateNew = true; + bEditorImport = false; + bEditAfterNew = true; +} + +UObject* UPhononSpatializationSettingsFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName InName, EObjectFlags Flags, + UObject* Context, FFeedbackContext* Warn) +{ + return Cast(NewObject(InParent, InName, Flags)); +} + +uint32 UPhononSpatializationSettingsFactory::GetMenuCategories() const +{ + return EAssetTypeCategories::Sounds; +} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononSpatializationSettingsFactory.h b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononSpatializationSettingsFactory.h new file mode 100644 index 000000000000..d91944c1c901 --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/PhononSpatializationSettingsFactory.h @@ -0,0 +1,34 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#pragma once + +#include "IAudioExtensionPlugin.h" +#include "AssetToolsModule.h" +#include "Factories/Factory.h" +#include "AssetTypeActions_Base.h" +#include "PhononSpatializationSettingsFactory.generated.h" + +namespace SteamAudio +{ + class FAssetTypeActions_PhononSpatializationSettings : public FAssetTypeActions_Base + { + public: + virtual FText GetName() const override; + virtual FColor GetTypeColor() const override; + virtual UClass* GetSupportedClass() const override; + virtual uint32 GetCategories() override; + }; +} + +UCLASS(MinimalAPI, hidecategories = Object) +class UPhononSpatializationSettingsFactory : public UFactory +{ + GENERATED_UCLASS_BODY() + + virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, + FFeedbackContext* Warn) override; + + virtual uint32 GetMenuCategories() const override; +}; diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/SteamAudioEditorModule.cpp b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/SteamAudioEditorModule.cpp new file mode 100644 index 000000000000..1433b82fc76d --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/SteamAudioEditorModule.cpp @@ -0,0 +1,367 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +#include "SteamAudioEditorModule.h" + +#include "ISettingsModule.h" +#include "Engine/World.h" +#include "SlateStyleRegistry.h" +#include "Kismet/GameplayStatics.h" +#include "Async/Async.h" +#include "UnrealEdGlobals.h" +#include "Editor/UnrealEdEngine.h" +#include "LevelEditorViewport.h" +#include "LevelEditor.h" +#include "PropertyEditorModule.h" +#include "SlateStyle.h" +#include "IPluginManager.h" +#include "ClassIconFinder.h" +#include "Editor.h" + +#include "TickableNotification.h" +#include "PhononScene.h" +#include "SteamAudioSettings.h" +#include "PhononProbeVolume.h" +#include "PhononProbeVolumeDetails.h" +#include "PhononProbeComponent.h" +#include "PhononProbeComponentVisualizer.h" +#include "PhononSourceComponent.h" +#include "PhononSourceComponentDetails.h" +#include "PhononSourceComponentVisualizer.h" +#include "Framework/MultiBox/MultiBoxBuilder.h" + +#include + +DEFINE_LOG_CATEGORY(LogSteamAudioEditor); + +IMPLEMENT_MODULE(SteamAudio::FSteamAudioEditorModule, SteamAudioEditor) + +namespace SteamAudio +{ + //============================================================================================================================================== + // Global data and functions for baking + //============================================================================================================================================== + + static TSharedPtr GExportSceneTickable = MakeShareable(new FTickableNotification()); + static TSharedPtr GBakeReverbTickable = MakeShareable(new FTickableNotification()); + static std::atomic GIsBakingReverb = false; + static int32 GCurrentProbeVolume = 0; + static int32 GNumProbeVolumes = 0; + + static void BakeReverbProgressCallback(float Progress) + { + FFormatNamedArguments Arguments; + Arguments.Add(TEXT("BakeProgress"), FText::AsPercent(Progress)); + Arguments.Add(TEXT("CurrentProbeVolume"), FText::AsNumber(GCurrentProbeVolume)); + Arguments.Add(TEXT("NumProbeVolumes"), FText::AsNumber(GNumProbeVolumes)); + GBakeReverbTickable->SetDisplayText(FText::Format(NSLOCTEXT("SteamAudio", "BakeText", + "Baking {CurrentProbeVolume}/{NumProbeVolumes} probe volumes ({BakeProgress} complete)"), Arguments)); + } + + //============================================================================================================================================== + // FSteamAudioEditorModule + //============================================================================================================================================== + + void FSteamAudioEditorModule::StartupModule() + { + // Register detail customizations + FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked("PropertyEditor"); + + PropertyModule.RegisterCustomClassLayout("PhononProbeVolume", FOnGetDetailCustomizationInstance::CreateStatic(&FPhononProbeVolumeDetails::MakeInstance)); + PropertyModule.RegisterCustomClassLayout("PhononSourceComponent", FOnGetDetailCustomizationInstance::CreateStatic(&FPhononSourceComponentDetails::MakeInstance)); + + // Extend the toolbar build menu with custom actions + if (!IsRunningCommandlet()) + { + FLevelEditorModule* LevelEditorModule = FModuleManager::LoadModulePtr(TEXT("LevelEditor")); + if (LevelEditorModule) + { + auto BuildMenuExtender = FLevelEditorModule::FLevelEditorMenuExtender::CreateRaw(this, &FSteamAudioEditorModule::OnExtendLevelEditorBuildMenu); + + LevelEditorModule->GetAllLevelEditorToolbarBuildMenuExtenders().Add(BuildMenuExtender); + } + } + + // Register plugin settings + ISettingsModule* SettingsModule = FModuleManager::Get().GetModulePtr("Settings"); + if (SettingsModule) + { + SettingsModule->RegisterSettings("Project", "Plugins", "Steam Audio", NSLOCTEXT("SteamAudio", "Steam Audio", "Steam Audio"), + NSLOCTEXT("SteamAudio", "Configure Steam Audio settings", "Configure Steam Audio settings"), GetMutableDefault()); + } + + // Create and register custom slate style + FString SteamAudioContent = IPluginManager::Get().FindPlugin("SteamAudio")->GetBaseDir() + "/Content"; + FVector2D Vec16 = FVector2D(16.0f, 16.0f); + FVector2D Vec64 = FVector2D(64.0f, 64.0f); + + SteamAudioStyleSet = MakeShareable(new FSlateStyleSet("SteamAudio")); + SteamAudioStyleSet->SetContentRoot(FPaths::EngineContentDir() / TEXT("Editor/Slate")); + SteamAudioStyleSet->SetCoreContentRoot(FPaths::EngineContentDir() / TEXT("Slate")); + SteamAudioStyleSet->Set("ClassIcon.PhononSourceComponent", new FSlateImageBrush(SteamAudioContent + "/S_PhononSource_16.png", Vec16)); + SteamAudioStyleSet->Set("ClassIcon.PhononGeometryComponent", new FSlateImageBrush(SteamAudioContent + "/S_PhononGeometry_16.png", Vec16)); + SteamAudioStyleSet->Set("ClassIcon.PhononMaterialComponent", new FSlateImageBrush(SteamAudioContent + "/S_PhononMaterial_16.png", Vec16)); + + SteamAudioStyleSet->Set("ClassIcon.PhononSpatializationSourceSettings", new FSlateImageBrush(SteamAudioContent + "/S_PhononSpatializationSourceSettings_16.png", Vec16)); + SteamAudioStyleSet->Set("ClassThumbnail.PhononSpatializationSourceSettings", new FSlateImageBrush(SteamAudioContent + "/S_PhononSpatializationSourceSettings_64.png", Vec64)); + + SteamAudioStyleSet->Set("ClassIcon.PhononOcclusionSourceSettings", new FSlateImageBrush(SteamAudioContent + "/S_PhononOcclusionSourceSettings_16.png", Vec16)); + SteamAudioStyleSet->Set("ClassThumbnail.PhononOcclusionSourceSettings", new FSlateImageBrush(SteamAudioContent + "/S_PhononOcclusionSourceSettings_64.png", Vec64)); + + SteamAudioStyleSet->Set("ClassIcon.PhononReverbSourceSettings", new FSlateImageBrush(SteamAudioContent + "/S_PhononReverbSourceSettings_16.png", Vec16)); + SteamAudioStyleSet->Set("ClassThumbnail.PhononReverbSourceSettings", new FSlateImageBrush(SteamAudioContent + "/S_PhononReverbSourceSettings_64.png", Vec64)); + FSlateStyleRegistry::RegisterSlateStyle(*SteamAudioStyleSet.Get()); + + // Register component visualizers + RegisterComponentVisualizer(UPhononSourceComponent::StaticClass()->GetFName(), MakeShareable(new FPhononSourceComponentVisualizer())); + RegisterComponentVisualizer(UPhononProbeComponent::StaticClass()->GetFName(), MakeShareable(new FPhononProbeComponentVisualizer())); + } + + void FSteamAudioEditorModule::ShutdownModule() + { + // Unregister component visualizers + if (GUnrealEd) + { + for (FName& ClassName : RegisteredComponentClassNames) + { + GUnrealEd->UnregisterComponentVisualizer(ClassName); + } + } + + FSlateStyleRegistry::UnRegisterSlateStyle(*SteamAudioStyleSet.Get()); + } + + void FSteamAudioEditorModule::ExportScene() + { + // Display editor notification + GExportSceneTickable->SetDisplayText(NSLOCTEXT("SteamAudio", "Exporting scene...", "Exporting scene...")); + GExportSceneTickable->CreateNotification(); + + // Export the scene + UWorld* World = GEditor->LevelViewportClients[0]->GetWorld(); + IPLhandle PhononScene = nullptr; + TArray PhononStaticMeshes; + SteamAudio::LoadScene(World, &PhononScene, &PhononStaticMeshes); + + // Save to disk + FString BaseSceneFile = FPaths::GameDir() + "Content/" + World->GetMapName(); + FString SceneFile = BaseSceneFile + ".phononscene"; + FString ObjSceneFile = BaseSceneFile + ".obj"; + iplSaveFinalizedScene(PhononScene, TCHAR_TO_ANSI(*SceneFile)); + iplDumpSceneToObjFile(PhononScene, TCHAR_TO_ANSI(*ObjSceneFile)); + + // Clean up Phonon structures + for (IPLhandle PhononStaticMesh : PhononStaticMeshes) + { + iplDestroyStaticMesh(&PhononStaticMesh); + } + iplDestroyScene(&PhononScene); + + // Display editor notification + GExportSceneTickable->SetDisplayText(NSLOCTEXT("SteamAudio", "Export scene complete.", "Export scene complete.")); + GExportSceneTickable->DestroyNotification(); + } + + void FSteamAudioEditorModule::BakeReverb() + { + GIsBakingReverb.store(true); + + // Display editor notification + GBakeReverbTickable->SetDisplayText(NSLOCTEXT("SteamAudio", "Baking reverb...", "Baking reverb...")); + GBakeReverbTickable->CreateNotificationWithCancel(FSimpleDelegate::CreateRaw(this, &FSteamAudioEditorModule::CancelBakeReverb)); + + UWorld* World = GEditor->LevelViewportClients[0]->GetWorld(); + + // Get all probe volumes (cannot do this in the async task) + TArray PhononProbeVolumes; + UGameplayStatics::GetAllActorsOfClass(World, APhononProbeVolume::StaticClass(), PhononProbeVolumes); + + // Ensure we have at least one probe + bool AtLeastOneProbe = false; + + for (auto PhononProbeVolumeActor : PhononProbeVolumes) + { + auto PhononProbeVolume = Cast(PhononProbeVolumeActor); + if (PhononProbeVolume->NumProbes > 0) + { + AtLeastOneProbe = true; + break; + } + } + + if (!AtLeastOneProbe) + { + UE_LOG(LogSteamAudioEditor, Error, TEXT("Ensure at least one Phonon Probe Volume with probes exists.")); + GBakeReverbTickable->SetDisplayText(NSLOCTEXT("SteamAudio", "Bake failed.", "Bake failed. Create at least one Phonon Probe Volume that has probes.")); + GBakeReverbTickable->DestroyNotification(SNotificationItem::CS_Fail); + GIsBakingReverb.store(false); + return; + } + + AsyncTask(ENamedThreads::AnyNormalThreadNormalTask, [=]() + { + IPLBakingSettings BakingSettings; + BakingSettings.bakeParametric = IPL_FALSE; + BakingSettings.bakeConvolution = IPL_TRUE; + + IPLSimulationSettings SimulationSettings; + SimulationSettings.sceneType = IPL_SCENETYPE_PHONON; + SimulationSettings.irDuration = GetDefault()->IndirectImpulseResponseDuration; + SimulationSettings.ambisonicsOrder = GetDefault()->IndirectImpulseResponseOrder; + SimulationSettings.maxConvolutionSources = 0; + SimulationSettings.numBounces = GetDefault()->BakedBounces; + SimulationSettings.numRays = GetDefault()->BakedRays; + SimulationSettings.numDiffuseSamples = GetDefault()->BakedSecondaryRays; + + IPLhandle ComputeDevice = nullptr; + IPLLoadSceneProgressCallback LoadSceneProgressCallback = nullptr; + + IPLhandle PhononScene = nullptr; + IPLhandle PhononEnvironment = nullptr; + + GBakeReverbTickable->SetDisplayText(NSLOCTEXT("SteamAudio", "Loading scene...", "Loading scene...")); + + if (World) + { + FString SceneFile = FPaths::GameDir() + "Content/" + World->GetMapName() + ".phononscene"; + + if (FPaths::FileExists(SceneFile)) + { + iplLoadFinalizedScene(SteamAudio::GlobalContext, SimulationSettings, TCHAR_TO_ANSI(*SceneFile), ComputeDevice, LoadSceneProgressCallback, &PhononScene); + iplCreateEnvironment(SteamAudio::GlobalContext, ComputeDevice, SimulationSettings, PhononScene, nullptr, &PhononEnvironment); + } + else + { + UE_LOG(LogSteamAudioEditor, Error, TEXT("Unable to load scene: %s not found."), *SceneFile); + GBakeReverbTickable->SetDisplayText(NSLOCTEXT("SteamAudio", "Bake failed.", "Bake failed. Export scene first.")); + GBakeReverbTickable->DestroyNotification(SNotificationItem::CS_Fail); + GIsBakingReverb.store(false); + return; + } + } + else + { + UE_LOG(LogSteamAudioEditor, Error, TEXT("Unable to load scene: null World.")); + GBakeReverbTickable->SetDisplayText(NSLOCTEXT("SteamAudio", "Bake failed.", "Bake failed. Export scene first.")); + GBakeReverbTickable->DestroyNotification(SNotificationItem::CS_Fail); + GIsBakingReverb.store(false); + return; + } + + GBakeReverbTickable->SetDisplayText(NSLOCTEXT("SteamAudio", "Baking reverb...", "Baking reverb...")); + GNumProbeVolumes = PhononProbeVolumes.Num(); + GCurrentProbeVolume = 1; + + for (AActor* PhononProbeVolumeActor : PhononProbeVolumes) + { + APhononProbeVolume* PhononProbeVolume = Cast(PhononProbeVolumeActor); + IPLhandle ProbeBox = nullptr; + iplLoadProbeBox(PhononProbeVolume->GetProbeBoxData(), PhononProbeVolume->GetProbeBoxDataSize(), &ProbeBox); + iplBakeReverb(PhononEnvironment, ProbeBox, BakingSettings, BakeReverbProgressCallback); + + FBakedDataInfo BakedDataInfo; + BakedDataInfo.Name = "__reverb__"; + BakedDataInfo.Size = iplGetBakedDataSizeByName(ProbeBox, (IPLstring)"__reverb__"); + + auto ExistingInfo = PhononProbeVolume->BakedDataInfo.FindByPredicate([=](const FBakedDataInfo& InfoItem) + { + return InfoItem.Name == BakedDataInfo.Name; + }); + + if (ExistingInfo) + { + ExistingInfo->Size = BakedDataInfo.Size; + } + else + { + PhononProbeVolume->BakedDataInfo.Add(BakedDataInfo); + PhononProbeVolume->BakedDataInfo.Sort(); + } + + if (!GIsBakingReverb.load()) + { + iplDestroyEnvironment(&PhononEnvironment); + iplDestroyScene(&PhononScene); + GBakeReverbTickable->SetDisplayText(NSLOCTEXT("SteamAudio", "Bake reverb cancelled.", "Bake reverb cancelled.")); + GBakeReverbTickable->DestroyNotification(SNotificationItem::CS_Fail); + return; + } + + PhononProbeVolume->UpdateProbeBoxData(ProbeBox); + iplDestroyProbeBox(&ProbeBox); + ++GCurrentProbeVolume; + } + + iplDestroyEnvironment(&PhononEnvironment); + iplDestroyScene(&PhononScene); + + // Display editor notification + GBakeReverbTickable->SetDisplayText(NSLOCTEXT("SteamAudio", "Bake reverb complete.", "Bake reverb complete.")); + GBakeReverbTickable->DestroyNotification(); + GIsBakingReverb.store(false); + }); + } + + void FSteamAudioEditorModule::RegisterComponentVisualizer(const FName ComponentClassName, TSharedPtr Visualizer) + { + if (GUnrealEd) + { + GUnrealEd->RegisterComponentVisualizer(ComponentClassName, Visualizer); + } + + RegisteredComponentClassNames.Add(ComponentClassName); + + if (Visualizer.IsValid()) + { + Visualizer->OnRegister(); + } + } + + TSharedRef FSteamAudioEditorModule::OnExtendLevelEditorBuildMenu(const TSharedRef CommandList) + { + TSharedRef Extender(new FExtender()); + + Extender->AddMenuExtension("LevelEditorNavigation", EExtensionHook::After, nullptr, + FMenuExtensionDelegate::CreateRaw(this, &FSteamAudioEditorModule::CreateBuildMenu)); + + return Extender; + } + + void FSteamAudioEditorModule::CreateBuildMenu(FMenuBuilder& Builder) + { + FUIAction ActionExportScene(FExecuteAction::CreateRaw(this, &FSteamAudioEditorModule::ExportScene), + FCanExecuteAction::CreateRaw(this, &FSteamAudioEditorModule::IsReadyToExportScene)); + + FUIAction ActionBakeReverb(FExecuteAction::CreateRaw(this, &FSteamAudioEditorModule::BakeReverb), + FCanExecuteAction::CreateRaw(this, &FSteamAudioEditorModule::IsReadyToBakeReverb)); + + Builder.BeginSection("LevelEditorIR", NSLOCTEXT("SteamAudio", "Phonon", "Phonon")); + + Builder.AddMenuEntry(NSLOCTEXT("SteamAudio", "Export Scene", "Export Scene"), + NSLOCTEXT("SteamAudio", "Exports Phonon geometry.", "Export Phonon geometry."), FSlateIcon(), ActionExportScene, NAME_None, + EUserInterfaceActionType::Button); + + Builder.AddMenuEntry(NSLOCTEXT("SteamAudio", "Bake Reverb", "Bake Reverb"), + NSLOCTEXT("SteamAudio", "Bakes reverb at all probe locations.", "Bakes reverb at all probe locations."), FSlateIcon(), ActionBakeReverb, + NAME_None, EUserInterfaceActionType::Button); + + Builder.EndSection(); + } + + void FSteamAudioEditorModule::CancelBakeReverb() + { + iplCancelBake(); + GIsBakingReverb.store(false); + } + + bool FSteamAudioEditorModule::IsReadyToExportScene() const + { + return true; + } + + bool FSteamAudioEditorModule::IsReadyToBakeReverb() const + { + return !GIsBakingReverb.load(); + } +} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononEditorModule.h b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/SteamAudioEditorModule.h similarity index 55% rename from Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononEditorModule.h rename to Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/SteamAudioEditorModule.h index ee8067230561..f585a3a2edd0 100644 --- a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/PhononEditorModule.h +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/SteamAudioEditorModule.h @@ -1,22 +1,20 @@ // -// Copyright (C) Impulsonic, Inc. All rights reserved. +// Copyright (C) Valve Corporation. All rights reserved. // #pragma once -#include "IPhononEditorModule.h" -#include "SlateStyle.h" +#include "ISteamAudioEditorModule.h" +#include "Framework/MultiBox/MultiBoxExtender.h" -DECLARE_LOG_CATEGORY_EXTERN(LogPhononEditor, Log, All); +DECLARE_LOG_CATEGORY_EXTERN(LogSteamAudioEditor, Log, All); class FComponentVisualizer; -class FExtender; -class FMenuBuilder; -class FUICommandList; +class FSlateStyleSet; -namespace Phonon +namespace SteamAudio { - class FPhononEditorModule : public IPhononEditorModule + class FSteamAudioEditorModule : public ISteamAudioEditorModule { public: virtual void StartupModule() override; @@ -29,15 +27,13 @@ namespace Phonon bool IsReadyToExportScene() const; void BakeReverb(); + void CancelBakeReverb(); bool IsReadyToBakeReverb() const; void RegisterComponentVisualizer(const FName ComponentClassName, TSharedPtr Visualizer); private: - TSharedPtr ExportSceneTickable; - TSharedPtr BakeReverbTickable; - TSharedPtr PhononStyleSet; - + TSharedPtr SteamAudioStyleSet; TArray RegisteredComponentClassNames; }; -} \ No newline at end of file +} diff --git a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/TickableNotification.cpp b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/TickableNotification.cpp similarity index 50% rename from Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/TickableNotification.cpp rename to Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/TickableNotification.cpp index 3e426d60b1d6..259742e2bc6d 100644 --- a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/TickableNotification.cpp +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/TickableNotification.cpp @@ -1,14 +1,27 @@ // -// Copyright (C) Impulsonic, Inc. All rights reserved. +// Copyright (C) Valve Corporation. All rights reserved. // #include "TickableNotification.h" #include "SNotificationList.h" #include "NotificationManager.h" #include "LevelEditor.h" +#include "Misc/ScopeLock.h" -namespace Phonon +namespace SteamAudio { + FWorkItem::FWorkItem() + : Task(nullptr) + , FinalState(SNotificationItem::CS_Success) + , bIsFinalItem(false) + {} + + FWorkItem::FWorkItem(const TFunction& Task, const SNotificationItem::ECompletionState InFinalState, const bool bIsFinalItem) + : Task(Task) + , FinalState(InFinalState) + , bIsFinalItem(bIsFinalItem) + {} + FTickableNotification::FTickableNotification() : bIsTicking(false) { @@ -16,8 +29,6 @@ namespace Phonon void FTickableNotification::CreateNotification() { - //FScopeLock Lock(&CriticalSection); - FNotificationInfo Info(DisplayText); Info.bFireAndForget = false; Info.FadeOutDuration = 4.0f; @@ -28,20 +39,39 @@ namespace Phonon bIsTicking = true; } + + void FTickableNotification::CreateNotificationWithCancel(const FSimpleDelegate& CancelDelegate) + { + FNotificationInfo Info(DisplayText); + Info.bFireAndForget = false; + Info.FadeOutDuration = 4.0f; + Info.ExpireDuration = 0.0f; + Info.ButtonDetails.Add(FNotificationButtonInfo(NSLOCTEXT("SteamAudio", "Cancel", "Cancel"), FText::GetEmpty(), CancelDelegate)); + + NotificationPtr = FSlateNotificationManager::Get().AddNotification(Info); + NotificationPtr.Pin()->SetCompletionState(SNotificationItem::CS_Pending); + + bIsTicking = true; + } void FTickableNotification::DestroyNotification(const SNotificationItem::ECompletionState InFinalState) { - //FScopeLock Lock(&CriticalSection); - bIsTicking = false; - FinalState = InFinalState; + this->FinalState = InFinalState; } void FTickableNotification::SetDisplayText(const FText& InDisplayText) { - //FScopeLock Lock(&CriticalSection); + FScopeLock Lock(&CriticalSection); - DisplayText = InDisplayText; + this->DisplayText = InDisplayText; + } + + void FTickableNotification::QueueWorkItem(const FWorkItem& WorkItem) + { + FScopeLock Lock(&CriticalSection); + + WorkQueue.Enqueue(WorkItem); } void FTickableNotification::NotifyDestruction() @@ -59,10 +89,19 @@ namespace Phonon void FTickableNotification::Tick(float DeltaTime) { - //FScopeLock Lock(&CriticalSection); + FScopeLock Lock(&CriticalSection); if (bIsTicking && NotificationPtr.Pin().IsValid()) { + if (!WorkQueue.IsEmpty()) + { + FWorkItem WorkItem; + WorkQueue.Dequeue(WorkItem); + WorkItem.Task(DisplayText); + FinalState = WorkItem.FinalState; + bIsTicking = !WorkItem.bIsFinalItem; + } + NotificationPtr.Pin()->SetText(DisplayText); } else diff --git a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/TickableNotification.h b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/TickableNotification.h similarity index 50% rename from Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/TickableNotification.h rename to Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/TickableNotification.h index 5697ec46c7d7..2815a90747c7 100644 --- a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Private/TickableNotification.h +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Private/TickableNotification.h @@ -1,22 +1,35 @@ // -// Copyright (C) Impulsonic, Inc. All rights reserved. +// Copyright (C) Valve Corporation. All rights reserved. // #pragma once #include "TickableEditorObject.h" #include "SNotificationList.h" +#include "Queue.h" -namespace Phonon +namespace SteamAudio { + struct FWorkItem + { + FWorkItem(); + FWorkItem(const TFunction& Task, const SNotificationItem::ECompletionState InFinalState, const bool bIsFinalItem); + + TFunction Task; + SNotificationItem::ECompletionState FinalState; + bool bIsFinalItem; + }; + class FTickableNotification : public FTickableEditorObject { public: FTickableNotification(); void CreateNotification(); - void DestroyNotification(const SNotificationItem::ECompletionState FinalState = SNotificationItem::CS_Success); - void SetDisplayText(const FText& DisplayText); + void CreateNotificationWithCancel(const FSimpleDelegate& CancelDelegate); + void DestroyNotification(const SNotificationItem::ECompletionState InFinalState = SNotificationItem::CS_Success); + void SetDisplayText(const FText& InDisplayText); + void QueueWorkItem(const FWorkItem& WorkItem); protected: virtual void Tick(float DeltaTime) override; @@ -27,10 +40,10 @@ namespace Phonon void NotifyDestruction(); TWeakPtr NotificationPtr; - FCriticalSection CriticalSection; FText DisplayText; bool bIsTicking; + TQueue WorkQueue; SNotificationItem::ECompletionState FinalState; }; -} \ No newline at end of file +} diff --git a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Public/IPhononEditorModule.h b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Public/ISteamAudioEditorModule.h similarity index 65% rename from Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Public/IPhononEditorModule.h rename to Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Public/ISteamAudioEditorModule.h index de593a7dc054..209a0b92c64a 100644 --- a/Engine/Plugins/Runtime/Phonon/Source/PhononEditor/Public/IPhononEditorModule.h +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/Public/ISteamAudioEditorModule.h @@ -1,11 +1,13 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. +// +// Copyright (C) Valve Corporation. All rights reserved. +// #pragma once #include "Modules/ModuleInterface.h" #include "Modules/ModuleManager.h" -class IPhononEditorModule : public IModuleInterface +class ISteamAudioEditorModule : public IModuleInterface { public: /** @@ -14,9 +16,9 @@ public: * * @return Returns singleton instance, loading the module on demand if needed */ - static inline IPhononEditorModule& Get() + static inline ISteamAudioEditorModule& Get() { - return FModuleManager::LoadModuleChecked("PhononEditorModule"); + return FModuleManager::LoadModuleChecked("SteamAudioEditorModule"); } /** @@ -26,6 +28,6 @@ public: */ static inline bool IsAvailable() { - return FModuleManager::Get().IsModuleLoaded("PhononEditorModule"); + return FModuleManager::Get().IsModuleLoaded("SteamAudioEditorModule"); } }; diff --git a/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/SteamAudioEditor.Build.cs b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/SteamAudioEditor.Build.cs new file mode 100644 index 000000000000..e7fcd6352225 --- /dev/null +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/Source/SteamAudioEditor/SteamAudioEditor.Build.cs @@ -0,0 +1,73 @@ +// +// Copyright (C) Valve Corporation. All rights reserved. +// + +namespace UnrealBuildTool.Rules +{ + public class SteamAudioEditor : ModuleRules + { + public SteamAudioEditor(ReadOnlyTargetRules Target) : base(Target) + { + PrivateIncludePaths.AddRange( + new string[] { + "SteamAudioEditor/Private", + "SteamAudio/Private", + "SteamAudio/Public" + } + ); + + PublicIncludePaths.AddRange( + new string[] { + "SteamAudio/Public" + } + ); + + + PublicDependencyModuleNames.AddRange( + new string[] { + "Core", + "CoreUObject", + "Engine", + "InputCore", + "UnrealEd", + "LevelEditor", + "EditorStyle", + "RenderCore", + "ShaderCore", + "RHI", + "AudioEditor", + "AudioMixer", + "SteamAudio" + } + ); + + PrivateIncludePathModuleNames.AddRange( + new string[] { + "AssetTools", + "Landscape" + }); + + PrivateDependencyModuleNames.AddRange( + new string[] { + "Slate", + "SlateCore", + "UnrealEd", + "AudioEditor", + "LevelEditor", + "Landscape", + "Core", + "CoreUObject", + "Engine", + "InputCore", + "PropertyEditor", + "Projects", + "EditorStyle", + "SteamAudio" + } + ); + + AddEngineThirdPartyPrivateStaticDependencies(Target, "libPhonon"); + AddEngineThirdPartyPrivateStaticDependencies(Target, "DX11Audio"); + } + } +} \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Phonon/Phonon.uplugin b/Engine/Plugins/Runtime/Steam/SteamAudio/SteamAudio.uplugin similarity index 64% rename from Engine/Plugins/Runtime/Phonon/Phonon.uplugin rename to Engine/Plugins/Runtime/Steam/SteamAudio/SteamAudio.uplugin index 1864ed5525d9..dfa92fbd8904 100644 --- a/Engine/Plugins/Runtime/Phonon/Phonon.uplugin +++ b/Engine/Plugins/Runtime/Steam/SteamAudio/SteamAudio.uplugin @@ -1,15 +1,15 @@ { "FileVersion" : 3, "Version" : 1, - "VersionName" : "2.0", + "VersionName" : "2.0-beta.3", "FriendlyName" : "Steam Audio", "Description" : "Physically-based sound rendering.", "Category" : "Audio", "CreatedBy" : "Valve Corporation", - "CreatedByURL" : "http://www.valvesoftware.com/", + "CreatedByURL" : "https://valvesoftware.github.io/steam-audio", "DocsURL" : "", "MarketplaceURL" : "", - "SupportURL" : "", + "SupportURL" : "https://steamcommunity.com/app/596420", "EnabledByDefault" : false, "CanContainContent" : true, "IsBetaVersion" : true, @@ -17,18 +17,18 @@ "Modules" : [ { - "Name" : "Phonon", + "Name" : "SteamAudio", "Type" : "Runtime", - "LoadingPhase": "PreDefault", + "LoadingPhase" : "PreDefault", "WhitelistPlatforms" : [ "Win64" ] }, { - "Name" : "PhononEditor", + "Name" : "SteamAudioEditor", "Type" : "Editor", - "LoadingPhase" : "Default", + "LoadingPhase" : "PostEngineInit", "WhitelistPlatforms" : [ "Win64" diff --git a/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVR/Private/SteamVRHMD.cpp b/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVR/Private/SteamVRHMD.cpp index cf1820ed7491..89a860e3d9ff 100644 --- a/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVR/Private/SteamVRHMD.cpp +++ b/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVR/Private/SteamVRHMD.cpp @@ -262,6 +262,11 @@ TSharedPtr< class IHeadMountedDisplay, ESPMode::ThreadSafe > FSteamVRPlugin::Cre pVRIsHmdPresent FSteamVRHMD::VRIsHmdPresentFn = nullptr; pVRGetGenericInterface FSteamVRHMD::VRGetGenericInterfaceFn = nullptr; +bool FSteamVRHMD::IsHMDConnected() +{ + return FSteamVRHMD::VRIsHmdPresentFn ? (bool)(*FSteamVRHMD::VRIsHmdPresentFn)() : false; +} + bool FSteamVRHMD::IsHMDEnabled() const { return bHmdEnabled; @@ -719,7 +724,7 @@ ETrackingStatus FSteamVRHMD::GetControllerTrackingStatus(uint32 DeviceId) const bool FSteamVRHMD::GetControllerHandPositionAndOrientation( const int32 ControllerIndex, EControllerHand Hand, FVector& OutPosition, FQuat& OutOrientation ) { - if ((ControllerIndex < 0) || (ControllerIndex >= MAX_STEAMVR_CONTROLLER_PAIRS) || Hand < EControllerHand::Left || Hand > EControllerHand::Right) + if ((ControllerIndex < 0) || (ControllerIndex >= MAX_STEAMVR_CONTROLLER_PAIRS) || Hand < EControllerHand::Left || Hand > EControllerHand::Right) //-V547 { return false; } @@ -730,7 +735,7 @@ bool FSteamVRHMD::GetControllerHandPositionAndOrientation( const int32 Controlle ETrackingStatus FSteamVRHMD::GetControllerTrackingStatus(int32 ControllerIndex, EControllerHand DeviceHand) const { - if ((ControllerIndex < 0) || (ControllerIndex >= MAX_STEAMVR_CONTROLLER_PAIRS) || DeviceHand < EControllerHand::Left || DeviceHand > EControllerHand::Right) + if ((ControllerIndex < 0) || (ControllerIndex >= MAX_STEAMVR_CONTROLLER_PAIRS) || DeviceHand < EControllerHand::Left || DeviceHand > EControllerHand::Right) //-V547 { return ETrackingStatus::NotTracked; } @@ -1083,15 +1088,23 @@ bool FSteamVRHMD::EnableStereo(bool bStereo) uint32 Width, Height; GetWindowBounds( &PosX, &PosY, &Width, &Height ); SceneVP->SetViewportSize( Width, Height ); + bStereoEnabled = bStereoDesired; } else { + // Note: Setting before resize to ensure we don't try to allocate a new vr rt. + bStereoEnabled = bStereoDesired; + + FRHIViewport* const ViewportRHI = SceneVP->GetViewportRHI(); + if (ViewportRHI != nullptr) + { + ViewportRHI->SetCustomPresent(nullptr); + } + FVector2D size = SceneVP->FindWindow()->GetSizeInScreen(); SceneVP->SetViewportSize( size.X, size.Y ); Window->SetViewportSizeDrivenByWindow( true ); } - - bStereoEnabled = bStereoDesired; } } @@ -1115,6 +1128,9 @@ void FSteamVRHMD::CalculateStereoViewOffset(const enum EStereoscopicPass StereoP { if( StereoPassType != eSSP_FULL) { + // Needed to transform world locked stereo layers + PlayerLocation = ViewLocation; + vr::Hmd_Eye HmdEye = (StereoPassType == eSSP_LEFT_EYE) ? vr::Eye_Left : vr::Eye_Right; vr::HmdMatrix34_t HeadFromEye = VRSystem->GetEyeToHeadTransform(HmdEye); @@ -1256,6 +1272,10 @@ void FSteamVRHMD::PreRenderViewFamily_RenderThread(FRHICommandListImmediate& RHI const FTransform NewRelativeTransform(NewOrientation, NewPosition); ApplyLateUpdate(ViewFamily.Scene, OldRelativeTransform, NewRelativeTransform); + + const FQuat ViewOrientation = MainView->ViewRotation.Quaternion(); + PlayerOrientation = ViewOrientation * MainView->BaseHmdOrientation.Inverse(); + } void FSteamVRHMD::PostInitViewFamily_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& InViewFamily) {} diff --git a/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVR/Private/SteamVRHMD.h b/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVR/Private/SteamVRHMD.h index 4b052ff644c4..ac3e2f16bdee 100644 --- a/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVR/Private/SteamVRHMD.h +++ b/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVR/Private/SteamVRHMD.h @@ -2,6 +2,9 @@ #pragma once #include "ISteamVRPlugin.h" + +#if STEAMVR_SUPPORTED_PLATFORMS + #include "HeadMountedDisplay.h" #include "HeadMountedDisplayBase.h" #include "SteamVRFunctionLibrary.h" @@ -17,8 +20,6 @@ #include "OpenGLDrv.h" #endif -#if STEAMVR_SUPPORTED_PLATFORMS - #include "SceneViewExtension.h" #define STEAMVR_USE_VULKAN_RHI 0 @@ -82,7 +83,7 @@ public: virtual bool OnStartGameFrame( FWorldContext& WorldContext ) override; - virtual bool IsHMDConnected() override { return true; } + virtual bool IsHMDConnected() override; virtual bool IsHMDEnabled() const override; virtual EHMDWornState::Type GetHMDWornState() override; virtual void EnableHMD(bool allow = true) override; @@ -472,7 +473,7 @@ private: virtual void UpdateLayer(struct FSteamVRLayer& Layer, uint32 LayerId, bool bIsValid) const override; - void UpdateLayerTextures(); + void UpdateStereoLayers_RenderThread(); TSharedPtr SplashTicker; @@ -520,6 +521,8 @@ private: FString DisplayId; FSteamVRHMDCompat CompatExec; + FQuat PlayerOrientation; + FVector PlayerLocation; #if PLATFORM_WINDOWS TRefCountPtr pBridge; @@ -541,6 +544,4 @@ public: }; -DEFINE_LOG_CATEGORY_STATIC(LogHMD, Log, All); - #endif //STEAMVR_SUPPORTED_PLATFORMS diff --git a/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVR/Private/SteamVRRender.cpp b/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVR/Private/SteamVRRender.cpp index 3d00a13562a4..5f321f1719a9 100644 --- a/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVR/Private/SteamVRRender.cpp +++ b/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVR/Private/SteamVRRender.cpp @@ -2,6 +2,9 @@ // #include "CoreMinimal.h" #include "SteamVRPrivate.h" + +#if STEAMVR_SUPPORTED_PLATFORMS + #include "SteamVRHMD.h" #include "RendererPrivate.h" @@ -17,8 +20,6 @@ #include "VulkanContext.h" #endif -#if STEAMVR_SUPPORTED_PLATFORMS - static TAutoConsoleVariable CUsePostPresentHandoff(TEXT("vr.SteamVR.UsePostPresentHandoff"), 0, TEXT("Whether or not to use PostPresentHandoff. If true, more GPU time will be available, but this relies on no SceneCaptureComponent2D or WidgetComponents being active in the scene. Otherwise, it will break async reprojection.")); void FSteamVRHMD::DrawDistortionMesh_RenderThread(struct FRenderingCompositePassContext& Context, const FIntPoint& TextureSize) @@ -29,16 +30,16 @@ void FSteamVRHMD::DrawDistortionMesh_RenderThread(struct FRenderingCompositePass void FSteamVRHMD::RenderTexture_RenderThread(FRHICommandListImmediate& RHICmdList, FTexture2DRHIParamRef BackBuffer, FTexture2DRHIParamRef SrcTexture) const { check(IsInRenderingThread()); - const_cast(this)->UpdateLayerTextures(); + const_cast(this)->UpdateStereoLayers_RenderThread(); if (bSplashIsShown) { SetRenderTarget(RHICmdList, SrcTexture, FTextureRHIRef()); - DrawClearQuad(RHICmdList, GMaxRHIFeatureLevel, FLinearColor(0, 0, 0, 0)); + DrawClearQuad(RHICmdList, FLinearColor(0, 0, 0, 0)); } static const auto CVarMirrorMode = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("vr.MirrorMode")); - int WindowMirrorMode = FMath::Clamp(CVarMirrorMode->GetValueOnRenderThread(), 0 ,2); + const int WindowMirrorMode = CVarMirrorMode->GetValueOnRenderThread(); if (WindowMirrorMode != 0) { @@ -51,7 +52,7 @@ void FSteamVRHMD::RenderTexture_RenderThread(FRHICommandListImmediate& RHICmdLis if (WindowMirrorMode == 1) { // need to clear when rendering only one eye since the borders won't be touched by the DrawRect below - DrawClearQuad(RHICmdList, GMaxRHIFeatureLevel, FLinearColor::Black); + DrawClearQuad(RHICmdList, FLinearColor::Black); } FGraphicsPipelineStateInitializer GraphicsPSOInit; @@ -101,6 +102,56 @@ void FSteamVRHMD::RenderTexture_RenderThread(FRHICommandListImmediate& RHICmdLis *VertexShader, EDRF_Default); } + else + { + // Defaulting all unknown modes to 'single eye cropped'. + // aka WindowMirrorMode == 5 + + // These numbers define rectangle of the whole eye texture we slice out. + // They are pretty much what looked good to whoever came up with them. + const float SrcUSize = 0.3f; + const float SrcVSize = 0.6f; + + check(ViewportWidth > 0); + check(ViewportHeight > 0); + const float SrcAspect = (float)SrcUSize / (float)SrcVSize; + const float DstAspect = (float)ViewportWidth / (float)ViewportHeight; + + float USize = SrcUSize; + float VSize = SrcVSize; + if (DstAspect > SrcAspect) + { + // src is narrower, crop top and bottom + // U is for just one eye, so the full U src range is 0-0.5, while V ranges 0-1. + VSize = (USize * 2.0f) / DstAspect; + } + else if (SrcAspect > DstAspect) + { + // src is wider, crop left and right + // U is for just one eye, so the full U src range is 0-0.5, while V ranges 0-1. + USize = (VSize* 0.5f) * DstAspect; + } + else + { + check(SrcAspect == DstAspect); + } + + // U is for just one eye, so the full U src range is 0-0.5, while V ranges 0-1. + const float UStart = (0.5f - USize) * 0.5f; + const float VStart = (1.0f - VSize) * 0.5f; + + RendererModule->DrawRectangle( + RHICmdList, + 0, 0, + ViewportWidth, ViewportHeight, + UStart, VStart, + USize, VSize, + FIntPoint(ViewportWidth, ViewportHeight), + FIntPoint(1, 1), + *VertexShader, + EDRF_Default); + } + } } @@ -265,7 +316,6 @@ void FSteamVRHMD::VulkanBridge::FinishRendering() LeftBounds.vMin = 0.0f; LeftBounds.vMax = 1.0f; - vr::VRTextureBounds_t RightBounds; RightBounds.uMin = 0.5f; RightBounds.uMax = 1.0f; @@ -289,6 +339,7 @@ void FSteamVRHMD::VulkanBridge::FinishRendering() Plugin->VRCompositor->Submit(vr::Eye_Left, &texture, &LeftBounds); Plugin->VRCompositor->Submit(vr::Eye_Right, &texture, &RightBounds); + ImmediateContext.GetCommandBufferManager()->SubmitUploadCmdBuffer(false); } } @@ -422,4 +473,4 @@ void FSteamVRHMD::OpenGLBridge::PostPresent() #endif // PLATFORM_WINDOWS -#endif // STEAMVR_SUPPORTED_PLATFORMS \ No newline at end of file +#endif // STEAMVR_SUPPORTED_PLATFORMS diff --git a/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVR/Private/SteamVRStereoLayers.cpp b/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVR/Private/SteamVRStereoLayers.cpp index 60a504d9f3d1..b8dd07083d23 100644 --- a/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVR/Private/SteamVRStereoLayers.cpp +++ b/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVR/Private/SteamVRStereoLayers.cpp @@ -129,6 +129,15 @@ void FSteamVRHMD::UpdateLayer(struct FSteamVRLayer& Layer, uint32 LayerId, bool return; } + if (Layer.LayerDesc.Flags & IStereoLayers::LAYER_FLAG_TEX_NO_ALPHA_CHANNEL) + { + UE_LOG(LogHMD, Warning, TEXT("Unsupported StereoLayer flag. SteamVR StereoLayers do not support disabling alpha renderding. Make the texture opaque instead.")); + } + if (Layer.LayerDesc.ShapeType != IStereoLayers::QuadLayer) + { + UE_LOG(LogHMD, Warning, TEXT("Unsupported StereoLayer shape. SteamVR StereoLayers can only be Quads.")); + } + // UVs vr::VRTextureBounds_t TextureBounds; TextureBounds.uMin = Layer.LayerDesc.UVRect.Min.X; @@ -136,9 +145,29 @@ void FSteamVRHMD::UpdateLayer(struct FSteamVRLayer& Layer, uint32 LayerId, bool TextureBounds.vMin = Layer.LayerDesc.UVRect.Min.Y; TextureBounds.vMax = Layer.LayerDesc.UVRect.Max.Y; OVR_VERIFY(VROverlay->SetOverlayTextureBounds(Layer.OverlayHandle, &TextureBounds)); - const float WorldToMeterScale = FMath::Max(GetWorldToMetersScale(), 0.1f); + const float WorldToMeterScale = GetWorldToMetersScale(); + check(WorldToMeterScale > 0.f); OVR_VERIFY(VROverlay->SetOverlayWidthInMeters(Layer.OverlayHandle, Layer.LayerDesc.QuadSize.X / WorldToMeterScale)); - OVR_VERIFY(VROverlay->SetOverlayTexelAspect(Layer.OverlayHandle, Layer.LayerDesc.QuadSize.X / Layer.LayerDesc.QuadSize.Y)); + + float TexelAspect = 1.0f; + // OpenVR overlays already take texture size into account, so we have to explicitly undo that in case the preserve texture ratio flag is not set. + if (!(Layer.LayerDesc.Flags & IStereoLayers::LAYER_FLAG_QUAD_PRESERVE_TEX_RATIO) && Layer.LayerDesc.Texture.IsValid()) + { + FRHITexture2D* Texture2D = Layer.LayerDesc.Texture->GetTexture2D(); + if (Texture2D && Texture2D->GetSizeX() != 0) + { + // Initially set texel aspect so the image will be rendered in 1:1 ratio regardless of image size. + TexelAspect = (float)Texture2D->GetSizeY() / (float)Texture2D->GetSizeX(); + } + + // Now apply the ratio determined by Quad size: + if (Layer.LayerDesc.QuadSize.Y > 0.0f) + { + TexelAspect *= (Layer.LayerDesc.QuadSize.X / Layer.LayerDesc.QuadSize.Y); + } + } + + OVR_VERIFY(VROverlay->SetOverlayTexelAspect(Layer.OverlayHandle, TexelAspect)); // Shift layer priority values up by -INT32_MIN, as SteamVR uses unsigned integers for the layer order where UE uses signed integers. // This will preserve the correct order between layers with negative and positive priorities @@ -148,21 +177,10 @@ void FSteamVRHMD::UpdateLayer(struct FSteamVRLayer& Layer, uint32 LayerId, bool switch (Layer.LayerDesc.PositionType) { case ELayerType::WorldLocked: -#if 0 { - // needs final implementation - - FQuat PlayerOrientation = BaseOrientation.Inverse() * PlayerOrientation; - FTransform PlayerTorso(PlayerOrientation, PlayerPosition); - - FTransform Transform = PlayerTorso.Inverse() * Layer.LayerDesc.Transform; - - vr::HmdMatrix34_t HmdTransform; - TransformToSteamSpace(Transform, HmdTransform, WorldToMeterScale); - OVR_VERIFY(VROverlay->SetOverlayTransformTrackedDeviceRelative(Layer.OverlayHandle, VRCompositor->GetTrackingSpace(), &HmdTransform)); + // World locked layer positions are updated every frame. break; } -#endif case ELayerType::TrackerLocked: { vr::HmdMatrix34_t HmdTransform; @@ -182,20 +200,39 @@ void FSteamVRHMD::UpdateLayer(struct FSteamVRLayer& Layer, uint32 LayerId, bool //============================================================================= -void FSteamVRHMD::UpdateLayerTextures() +void FSteamVRHMD::UpdateStereoLayers_RenderThread() { - // If there have been no layer changes since last frame we can return - // Additionally, if we don't have a valid tracking position, the calls to ShowOverlay/SetOverlayTexture below will not have any effect. - if (!GetStereoLayersDirty() || !HasValidTrackingPosition()) + // If we don't have a valid tracking position, the calls to ShowOverlay/SetOverlayTexture below will not have any effect. + if (!HasValidTrackingPosition()) { return; } - ForEachLayer([=](uint32 /* unused */, FSteamVRLayer& Layer) + static const auto CVarMixLayerPriorities = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("vr.StereoLayers.bMixLayerPriorities")); + const bool bUpdateLayerPriorities = (CVarMixLayerPriorities->GetValueOnRenderThread() == 0) && GetStereoLayersDirty(); + + typedef TTuple LayerPriorityInfo; + TArray LayerPriorities; + + const float WorldToMeterScale = GetWorldToMetersScale(); + check(WorldToMeterScale > 0.f); + FQuat AdjustedPlayerOrientation = BaseOrientation.Inverse() * PlayerOrientation; + FTransform InvWorldTransform = FTransform(AdjustedPlayerOrientation, PlayerLocation).Inverse(); + + // We have loop through all layers every frame, in case we have world locked layers or continuously updated textures. + ForEachLayer([&](uint32 /* unused */, FSteamVRLayer& Layer) { if (Layer.OverlayHandle != vr::k_ulOverlayHandleInvalid) { + // Update world locked layer positions. + if (Layer.LayerDesc.PositionType == ELayerType::WorldLocked) + { + vr::HmdMatrix34_t HmdTransform; + TransformToSteamSpace(Layer.LayerDesc.Transform * InvWorldTransform, HmdTransform, WorldToMeterScale); + OVR_VERIFY(VROverlay->SetOverlayTransformAbsolute(Layer.OverlayHandle, VRCompositor->GetTrackingSpace(), &HmdTransform)); + } + // Update layer textures if (Layer.bUpdateTexture || (Layer.LayerDesc.Flags & LAYER_FLAG_TEX_CONTINUOUS_UPDATE)) { vr::Texture_t Texture; @@ -215,8 +252,50 @@ void FSteamVRHMD::UpdateLayerTextures() Layer.bUpdateTexture = false; } + + if (bUpdateLayerPriorities) + { + LayerPriorities.Add(LayerPriorityInfo(Layer.OverlayHandle, Layer.LayerDesc.Priority, Layer.LayerDesc.PositionType == FaceLocked)); + } } }); + + if (bUpdateLayerPriorities && LayerPriorities.Num() > 0) + { + auto SortLayersPredicate = [&](const LayerPriorityInfo& A, const LayerPriorityInfo& B) + { + const bool bAisFaceLocked = A.Get<2>(); + const bool bBisFaceLocked = B.Get<2>(); + + if (bAisFaceLocked != bBisFaceLocked) + { + return bBisFaceLocked; + } + else + { + return A.Get<1>() < B.Get<1>(); + } + }; + + LayerPriorities.Sort(SortLayersPredicate); + + uint32 SortOrder = 0; + int32 PrevPriority = LayerPriorities[0].Get<1>(); + bool PrevWasFaceLocked = LayerPriorities[0].Get<2>(); + + for (LayerPriorityInfo Info : LayerPriorities) + { + // If multiple layers have the same priority, assign same sort order to them as well. + if (PrevPriority != Info.Get<1>() || PrevWasFaceLocked != Info.Get<2>()) + { + PrevPriority = Info.Get<1>(); + PrevWasFaceLocked = Info.Get<2>(); + SortOrder++; + } + OVR_VERIFY(VROverlay->SetOverlaySortOrder(Info.Get<0>(), SortOrder)); + } + + } } //============================================================================= diff --git a/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVR/Public/ISteamVRPlugin.h b/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVR/Public/ISteamVRPlugin.h index c6a16dea0a73..2203a84a5e22 100644 --- a/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVR/Public/ISteamVRPlugin.h +++ b/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVR/Public/ISteamVRPlugin.h @@ -2,7 +2,7 @@ #pragma once -#define STEAMVR_SUPPORTED_PLATFORMS (PLATFORM_LINUX || (PLATFORM_WINDOWS && WINVER > 0x0502)) +#define STEAMVR_SUPPORTED_PLATFORMS ((PLATFORM_LINUX && PLATFORM_CPU_X86_FAMILY && PLATFORM_64BITS) || (PLATFORM_WINDOWS && WINVER > 0x0502)) #include "ModuleManager.h" #include "IHeadMountedDisplayModule.h" diff --git a/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVR/SteamVR.Build.cs b/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVR/SteamVR.Build.cs index f7089f752973..c45adc0cbd75 100644 --- a/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVR/SteamVR.Build.cs +++ b/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVR/SteamVR.Build.cs @@ -43,7 +43,7 @@ namespace UnrealBuildTool.Rules AddEngineThirdPartyPrivateStaticDependencies(Target, "OpenVR"); PrivateDependencyModuleNames.AddRange(new string[] { "D3D11RHI" }); //@todo steamvr: multiplatform } - else if (Target.Platform == UnrealTargetPlatform.Linux) + else if (Target.Platform == UnrealTargetPlatform.Linux && Target.Architecture.StartsWith("x86_64")) { AddEngineThirdPartyPrivateStaticDependencies(Target, "OpenVR"); AddEngineThirdPartyPrivateStaticDependencies(Target, "OpenGL"); diff --git a/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVRController/Private/SteamVRController.cpp b/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVRController/Private/SteamVRController.cpp index 413be232caa3..d510d46a262c 100644 --- a/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVRController/Private/SteamVRController.cpp +++ b/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVRController/Private/SteamVRController.cpp @@ -575,10 +575,6 @@ private: if (SteamVRPlugin == nullptr) { SteamVRPlugin = &FModuleManager::LoadModuleChecked(TEXT("SteamVR")); - if (SteamVRPlugin == nullptr) - { - return nullptr; - } } return SteamVRPlugin->GetVRSystem(); diff --git a/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVRController/Public/ISteamVRControllerPlugin.h b/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVRController/Public/ISteamVRControllerPlugin.h index 199d69aeb046..6c84c4141387 100644 --- a/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVRController/Public/ISteamVRControllerPlugin.h +++ b/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVRController/Public/ISteamVRControllerPlugin.h @@ -6,7 +6,7 @@ #include "ModuleManager.h" #include "IInputDeviceModule.h" -#define STEAMVRCONTROLLER_SUPPORTED_PLATFORMS (PLATFORM_LINUX || (PLATFORM_WINDOWS && WINVER > 0x0502)) +#define STEAMVRCONTROLLER_SUPPORTED_PLATFORMS ((PLATFORM_LINUX && PLATFORM_CPU_X86_FAMILY && PLATFORM_64BITS) || (PLATFORM_WINDOWS && WINVER > 0x0502)) /** * The public interface to this module. In most cases, this interface is only public to sibling modules diff --git a/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVRController/SteamVRController.Build.cs b/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVRController/SteamVRController.Build.cs index dd386c774e7d..2b47e5835c87 100644 --- a/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVRController/SteamVRController.Build.cs +++ b/Engine/Plugins/Runtime/Steam/SteamVR/Source/SteamVRController/SteamVRController.Build.cs @@ -29,7 +29,7 @@ public class SteamVRController : ModuleRules AddEngineThirdPartyPrivateStaticDependencies(Target, "OpenVR"); - if (Target.Platform == UnrealTargetPlatform.Linux) + if (Target.Platform == UnrealTargetPlatform.Linux && Target.Architecture.StartsWith("x86_64")) { AddEngineThirdPartyPrivateStaticDependencies(Target, "OpenGL"); PrivateDependencyModuleNames.Add("OpenGLDrv"); diff --git a/Engine/Plugins/Runtime/Steam/SteamVR/SteamVR.uplugin b/Engine/Plugins/Runtime/Steam/SteamVR/SteamVR.uplugin index 253a0f2feaec..4be96d7f3696 100644 --- a/Engine/Plugins/Runtime/Steam/SteamVR/SteamVR.uplugin +++ b/Engine/Plugins/Runtime/Steam/SteamVR/SteamVR.uplugin @@ -23,7 +23,8 @@ "WhitelistPlatforms" : [ "Win64", - "Win32" + "Win32", + "Linux" ] }, { @@ -38,4 +39,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Classes/SynthComponents/SynthComponentGranulator.h b/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Classes/SynthComponents/SynthComponentGranulator.h index cdaf24f2ee87..ab7ef1e3bf84 100644 --- a/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Classes/SynthComponents/SynthComponentGranulator.h +++ b/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Classes/SynthComponents/SynthComponentGranulator.h @@ -60,9 +60,6 @@ class SYNTHESIS_API UGranularSynth : public USynthComponent public: - UPROPERTY(EditAnywhere, Category = "Synth|Preset") - USoundWave* SoundWave; - // This will override the current sound wave if one is set, stop audio, and reload the new sound wave UFUNCTION(BlueprintCallable, Category = "Synth|Components|Audio") void SetSoundWave(USoundWave* InSoundWave); @@ -126,15 +123,13 @@ public: protected: - UPROPERTY(transient) - USoundWave* SoundWaveCopy; - - UPROPERTY(transient) - USoundWave* PendingSoundWaveSet; + TQueue PendingStoppingSoundWaves; Audio::FGranularSynth GranularSynth; + Audio::FSoundWavePCMLoader SoundWaveLoader; - bool bTransferPendingToSound; bool bIsLoaded; bool bRegistered; + + bool bIsLoading; }; \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Classes/SynthComponents/SynthComponentWaveTable.h b/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Classes/SynthComponents/SynthComponentWaveTable.h index 56a6889d5928..6c902dbecd29 100644 --- a/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Classes/SynthComponents/SynthComponentWaveTable.h +++ b/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Classes/SynthComponents/SynthComponentWaveTable.h @@ -86,18 +86,10 @@ public: bool IsLoaded() const; protected: - - UPROPERTY(transient) - USoundWave* SoundWaveCopy; - - UPROPERTY(transient) - USoundWave* PendingSoundWaveSet; - Audio::FSampleBufferReader SampleBufferReader; Audio::FSampleBuffer SampleBuffer; + Audio::FSoundWavePCMLoader SoundWaveLoader; + float SampleDurationSec; float SamplePlaybackProgressSec; - bool bTransferPendingToSound; - bool bIsLoaded; - bool bIsLoadedBroadcast; }; diff --git a/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Private/EpicSynth1.cpp b/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Private/EpicSynth1.cpp index a0ef94625cb8..9be4547e5ec4 100644 --- a/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Private/EpicSynth1.cpp +++ b/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Private/EpicSynth1.cpp @@ -408,8 +408,8 @@ namespace Audio bool FEpicSynth1Voice::CreatePatch(const FPatchId PatchId, const ESynth1PatchSource PatchSource, const TArray& PatchCables, const bool bEnableByDefault) { - FModulationMatrix* ModMatrix = &ParentSynth->ModMatrix; - if (DynamicPatches.Contains(PatchId.Id) || !ModMatrix) + FModulationMatrix& ModMatrix = ParentSynth->ModMatrix; + if (DynamicPatches.Contains(PatchId.Id)) { return false; } @@ -431,7 +431,7 @@ namespace Audio } DynamicPatches.Add(PatchId.Id, NewPatch); - ModMatrix->AddPatch(VoiceId, NewPatch.Get()); + ModMatrix.AddPatch(VoiceId, NewPatch.Get()); return true; } diff --git a/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Private/SourceEffectEQ.cpp b/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Private/SourceEffectEQ.cpp index 77107811526d..6d156f6adee8 100644 --- a/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Private/SourceEffectEQ.cpp +++ b/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Private/SourceEffectEQ.cpp @@ -2,9 +2,10 @@ #include "SourceEffects/SourceEffectEQ.h" #include "Audio.h" +#include "AudioDevice.h" FSourceEffectEQ::FSourceEffectEQ() - : SampleRate(AUDIO_SAMPLE_RATE) + : SampleRate(0) { FMemory::Memzero((void*)InAudioFrame, sizeof(float)*2); FMemory::Memzero((void*)OutAudioFrame, sizeof(float)*2); diff --git a/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Private/SynthComponentGranulator.cpp b/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Private/SynthComponentGranulator.cpp index f65d6f7b39f4..2213f903bd80 100644 --- a/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Private/SynthComponentGranulator.cpp +++ b/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Private/SynthComponentGranulator.cpp @@ -5,13 +5,10 @@ UGranularSynth::UGranularSynth(const FObjectInitializer& ObjInitializer) : Super(ObjInitializer) - , SoundWaveCopy(nullptr) - , PendingSoundWaveSet(nullptr) - , bTransferPendingToSound(false) , bIsLoaded(false) , bRegistered(false) { - + PrimaryComponentTick.bCanEverTick = true; } UGranularSynth::~UGranularSynth() @@ -22,6 +19,7 @@ UGranularSynth::~UGranularSynth() void UGranularSynth::Init(const int32 SampleRate) { NumChannels = 2; + SoundWaveLoader.Init(GetAudioDevice()); } void UGranularSynth::OnGenerateAudio(TArray& OutAudio) @@ -40,14 +38,9 @@ void UGranularSynth::OnRegister() SetComponentTickEnabled(true); RegisterComponent(); - GranularSynth.Init(GetAudioDevice(), 500); - - if (SoundWave) + if (FAudioDevice* AudioDevice = GetAudioDevice()) { - SoundWaveCopy = DuplicateObject(SoundWave, GetTransientPackage()); - SoundWaveCopy->AddToRoot(); - - GranularSynth.LoadSoundWave(SoundWaveCopy); + GranularSynth.Init(AudioDevice->GetSampleRate(), 500); } } } @@ -55,12 +48,6 @@ void UGranularSynth::OnRegister() void UGranularSynth::OnUnregister() { Super::OnUnregister(); - - if (IsValid(SoundWaveCopy)) - { - SoundWaveCopy->RemoveFromRoot(); - SoundWaveCopy = nullptr; - } } void UGranularSynth::SetAttackTime(const float AttackTimeMsec) @@ -111,32 +98,29 @@ void UGranularSynth::NoteOff(const float Note, const bool bKill) }); } - void UGranularSynth::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) { - if (bTransferPendingToSound) + if (SoundWaveLoader.Update()) { - bTransferPendingToSound = false; - check(PendingSoundWaveSet); - if (SoundWaveCopy) + Audio::FSampleBuffer SampleBuffer; + SoundWaveLoader.GetSampleBuffer(SampleBuffer); + + SynthCommand([this, SampleBuffer]() { - SoundWaveCopy->RemoveFromRoot(); - } - SoundWaveCopy = PendingSoundWaveSet; - PendingSoundWaveSet = nullptr; + GranularSynth.LoadSampleBuffer(SampleBuffer); + + // Clear the pending sound waves queue since we've now loaded a new buffer of data + SoundWaveLoader.Reset(); + }); } } void UGranularSynth::SetSoundWave(USoundWave* InSoundWave) { - PendingSoundWaveSet = DuplicateObject(InSoundWave, GetTransientPackage()); - PendingSoundWaveSet->AddToRoot(); - - SynthCommand([this]() - { - GranularSynth.LoadSoundWave(PendingSoundWaveSet); - bTransferPendingToSound = true; - }); + if (InSoundWave) + { + SoundWaveLoader.LoadSoundWave(InSoundWave); + } } void UGranularSynth::SetGrainsPerSecond(const float GrainsPerSecond) @@ -232,5 +216,5 @@ float UGranularSynth::GetCurrentPlayheadTime() const bool UGranularSynth::IsLoaded() const { - return GranularSynth.IsSoundWaveLoaded(); + return SoundWaveLoader.IsSoundWaveLoaded(); } \ No newline at end of file diff --git a/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Private/SynthComponentWaveTable.cpp b/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Private/SynthComponentWaveTable.cpp index 481d3cbc08f4..7e47f383489c 100644 --- a/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Private/SynthComponentWaveTable.cpp +++ b/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Private/SynthComponentWaveTable.cpp @@ -11,9 +11,6 @@ USynthSamplePlayer::USynthSamplePlayer(const FObjectInitializer& ObjInitializer) , SoundWave(nullptr) , SampleDurationSec(0.0f) , SamplePlaybackProgressSec(0.0F) - , bTransferPendingToSound(false) - , bIsLoaded(false) - , bIsLoadedBroadcast(false) { PrimaryComponentTick.bCanEverTick = true; } @@ -27,7 +24,7 @@ void USynthSamplePlayer::Init(const int32 SampleRate) NumChannels = 2; SampleBufferReader.Init(SampleRate); - bIsLoaded = false; + SoundWaveLoader.Init(GetAudioDevice()); } void USynthSamplePlayer::SetPitch(float InPitch, float InTimeSec) @@ -86,7 +83,7 @@ float USynthSamplePlayer::GetSampleDuration() const bool USynthSamplePlayer::IsLoaded() const { - return bIsLoaded; + return SoundWaveLoader.IsSoundWaveLoaded(); } float USynthSamplePlayer::GetCurrentPlaybackProgressTime() const @@ -105,17 +102,11 @@ float USynthSamplePlayer::GetCurrentPlaybackProgressPercent() const void USynthSamplePlayer::SetSoundWave(USoundWave* InSoundWave) { - PendingSoundWaveSet = DuplicateObject(InSoundWave, GetTransientPackage()); - PendingSoundWaveSet->AddToRoot(); + SoundWaveLoader.LoadSoundWave(InSoundWave); SynthCommand([this]() { SampleBufferReader.ClearBuffer(); - - SampleBuffer.Init(GetAudioDevice()); - SampleBuffer.LoadSoundWave(PendingSoundWaveSet); - - bTransferPendingToSound = true; }); } @@ -125,57 +116,37 @@ void USynthSamplePlayer::OnRegister() SetComponentTickEnabled(true); RegisterComponent(); - - if (SoundWave) - { - SoundWaveCopy = DuplicateObject(SoundWave, GetTransientPackage()); - SoundWaveCopy->AddToRoot(); - - // Load the sound wave right here synchronously - SampleBuffer.Init(GetAudioDevice()); - SampleBuffer.LoadSoundWave(SoundWaveCopy); - } } void USynthSamplePlayer::OnUnregister() { Super::OnUnregister(); - - if (IsValid(SoundWaveCopy)) - { - SoundWaveCopy->RemoveFromRoot(); - SoundWaveCopy = nullptr; - } } void USynthSamplePlayer::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) { - if (bIsLoaded && !bIsLoadedBroadcast) + if (SoundWaveLoader.Update()) { - bIsLoadedBroadcast = true; OnSampleLoaded.Broadcast(); + + Audio::FSampleBuffer NewSampleBuffer; + SoundWaveLoader.GetSampleBuffer(NewSampleBuffer); + + SynthCommand([this, NewSampleBuffer]() + { + SampleBuffer = NewSampleBuffer; + + // Clear the pending sound waves queue since we've now loaded a new buffer of data + SoundWaveLoader.Reset(); + }); } OnSamplePlaybackProgress.Broadcast(GetCurrentPlaybackProgressTime(), GetCurrentPlaybackProgressPercent()); - - if (bTransferPendingToSound) - { - bTransferPendingToSound = false; - check(PendingSoundWaveSet); - if (SoundWaveCopy) - { - SoundWaveCopy->RemoveFromRoot(); - } - SoundWaveCopy = PendingSoundWaveSet; - PendingSoundWaveSet = nullptr; - } } void USynthSamplePlayer::OnGenerateAudio(TArray& OutAudio) { - SampleBuffer.UpdateLoading(); - - if (SampleBuffer.IsLoaded() && !SampleBufferReader.HasBuffer()) + if (SampleBuffer.GetData() && !SampleBufferReader.HasBuffer()) { const int16* BufferData = SampleBuffer.GetData(); const int32 BufferNumSamples = SampleBuffer.GetNumSamples(); @@ -183,10 +154,9 @@ void USynthSamplePlayer::OnGenerateAudio(TArray& OutAudio) const int32 BufferSampleRate = SampleBuffer.GetSampleRate(); SampleBufferReader.SetBuffer(&BufferData, BufferNumSamples, BufferNumChannels, BufferSampleRate); SampleDurationSec = BufferNumSamples / BufferSampleRate; - bIsLoaded = true; } - if (bIsLoaded) + if (SampleBufferReader.HasBuffer()) { const int32 NumFrames = OutAudio.Num() / NumChannels; SampleBufferReader.Generate(OutAudio, NumFrames, NumChannels, true); diff --git a/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Private/SynthesisModule.cpp b/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Private/SynthesisModule.cpp index 548068ebfb16..8c208bad5639 100644 --- a/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Private/SynthesisModule.cpp +++ b/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Private/SynthesisModule.cpp @@ -8,7 +8,7 @@ DEFINE_LOG_CATEGORY(LogSynthesis); -IMPLEMENT_MODULE(FSynthesisModule, FSynthesis) +IMPLEMENT_MODULE(FSynthesisModule, Synthesis) void FSynthesisModule::StartupModule() { diff --git a/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Private/UI/Synth2DSlider.cpp b/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Private/UI/Synth2DSlider.cpp index 497501d42654..4342f1888edb 100644 --- a/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Private/UI/Synth2DSlider.cpp +++ b/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Private/UI/Synth2DSlider.cpp @@ -36,8 +36,8 @@ void USynth2DSlider::SynchronizeProperties() { Super::SynchronizeProperties(); - TAttribute ValueXBinding = OPTIONAL_BINDING(float, ValueX); - TAttribute ValueYBinding = OPTIONAL_BINDING(float, ValueY); + TAttribute ValueXBinding = PROPERTY_BINDING(float, ValueX); + TAttribute ValueYBinding = PROPERTY_BINDING(float, ValueY); MySlider->SetSliderHandleColor(SliderHandleColor); MySlider->SetValueX(ValueXBinding); diff --git a/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Private/UI/SynthKnob.cpp b/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Private/UI/SynthKnob.cpp index 17e0f7de6868..b30c3d55f068 100644 --- a/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Private/UI/SynthKnob.cpp +++ b/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Private/UI/SynthKnob.cpp @@ -35,7 +35,7 @@ void USynthKnob::SynchronizeProperties() { Super::SynchronizeProperties(); - TAttribute ValueBinding = OPTIONAL_BINDING(float, Value); + TAttribute ValueBinding = PROPERTY_BINDING(float, Value); MySynthKnob->SetValue(ValueBinding); MySynthKnob->SetLocked(Locked); diff --git a/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Public/UI/Synth2DSlider.h b/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Public/UI/Synth2DSlider.h index ef04eb916d99..b70486bc4f54 100644 --- a/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Public/UI/Synth2DSlider.h +++ b/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Public/UI/Synth2DSlider.h @@ -147,4 +147,8 @@ protected: void HandleOnMouseCaptureEnd(); void HandleOnControllerCaptureBegin(); void HandleOnControllerCaptureEnd(); + +protected: + PROPERTY_BINDING_IMPLEMENTATION(float, ValueX); + PROPERTY_BINDING_IMPLEMENTATION(float, ValueY); }; diff --git a/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Public/UI/SynthKnob.h b/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Public/UI/SynthKnob.h index 98d4a404aee1..faed8dd686be 100644 --- a/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Public/UI/SynthKnob.h +++ b/Engine/Plugins/Runtime/Synthesis/Source/Synthesis/Public/UI/SynthKnob.h @@ -143,4 +143,7 @@ protected: void HandleOnMouseCaptureEnd(); void HandleOnControllerCaptureBegin(); void HandleOnControllerCaptureEnd(); + +protected: + PROPERTY_BINDING_IMPLEMENTATION(float, Value); }; diff --git a/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/ThirdParty/Twitch/InstallingTwitchSDK.txt b/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/ThirdParty/Twitch/InstallingTwitchSDK.txt deleted file mode 100644 index cbb23c8d2d4a..000000000000 --- a/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/ThirdParty/Twitch/InstallingTwitchSDK.txt +++ /dev/null @@ -1,30 +0,0 @@ -SETTING UP THE TWITCH SDK WITH UNREAL ENGINE -============================================ - - -The Twitch SDK is currently not included with Unreal Engine by default. This means that the -TwitchLiveStreaming plugin will not be able to function, and Twitch features will not be available -in the game or editor. - -To use Twitch in your game, you'll need to contact Twitch and obtain a copy of the SDK along with permission -to use it in your product. We're currently using SDK version 6.21, so you'll want to get that version. -After downloading the SDK, you can follow the instructions below to set it up with UE4. Make sure to read -over Twitch's license as well as the Twitch SDK integration guide they will provide. - -To install the SDK: - - - Acquire the Twitch C++ SDK. You'll need to contact Twitch to get access. - - Make sure you pull down the correct version of the SDK. (6.21) - - Also remember to read the Twitch SDK license agreement. - - - Unzip the SDK to the /Engine/Plugins/Runtime/TwitchLiveStreaming/Source/ThirdParty/Twitch/Twitch-6.21/ folder (create the folder if it is missing) - - - Copy the precompiled binary files in the Twitch SDK "lib" folder to a the /Engine/Plugins/Runtime/TwitchLiveStreaming/Binaries/ThirdParty/Twitch/Twitch-6.21/Win64 (or Win32) folder (create the folder if it is missing) - - - Recompile the engine. The TwitchLiveStreaming plugin will see the SDK files, and activate support for Twitch broadcasting in the game and editor. - - - See the Unreal Engine manual for more about using the built-in Twitch integration for broadcasting your game or editor sessions - - -That's it! Have fun! - diff --git a/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/ThirdParty/Twitch/Twitch.Build.cs b/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/ThirdParty/Twitch/Twitch.Build.cs deleted file mode 100644 index 38cf3a703b14..000000000000 --- a/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/ThirdParty/Twitch/Twitch.Build.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -using UnrealBuildTool; -using System; -using System.IO; - -public class Twitch : ModuleRules -{ - public Twitch( ReadOnlyTargetRules Target ) : base(Target) - { - Type = ModuleType.External; - - // Only Windows is supported for now - if( Target.Platform == UnrealTargetPlatform.Win64 || Target.Platform == UnrealTargetPlatform.Win32 ) - { - string TwitchBaseDir = Path.Combine( UEBuildConfiguration.UEThirdPartySourceDirectory, "..", "..", "Plugins", "Runtime", "TwitchLiveStreaming", "Source", "ThirdParty", "NotForLicensees", "Twitch" ); // Check the NotForLicensees folder first - string TwitchDLLDir = "$(PluginDir)/Binaries/ThirdParty/NotForLicensees/Twitch"; - if ( !Directory.Exists( TwitchBaseDir ) ) - { - TwitchBaseDir = Path.Combine(UEBuildConfiguration.UEThirdPartySourceDirectory, "..", "..", "Plugins", "Runtime", "TwitchLiveStreaming", "Source", "ThirdParty", "Twitch"); // Use the normal location - TwitchDLLDir = "$(PluginDir)/Binaries/ThirdParty/Twitch/Twitch"; - } - - if( Target.Platform == UnrealTargetPlatform.Win64 ) - { - RuntimeDependencies.Add( new RuntimeDependency( TwitchDLLDir + "/Win64/twitchsdk_64_release.dll" ) ); - RuntimeDependencies.Add( new RuntimeDependency( TwitchDLLDir + "/Win64/avutil-ttv-51.dll" ) ); - RuntimeDependencies.Add( new RuntimeDependency( TwitchDLLDir + "/Win64/libmfxsw64.dll" ) ); - RuntimeDependencies.Add( new RuntimeDependency( TwitchDLLDir + "/Win64/libmp3lame-ttv.dll" ) ); - RuntimeDependencies.Add( new RuntimeDependency( TwitchDLLDir + "/Win64/swresample-ttv-0.dll" ) ); - } - else if( Target.Platform == UnrealTargetPlatform.Win32 ) - { - RuntimeDependencies.Add( new RuntimeDependency( TwitchDLLDir + "/Win32/twitchsdk_32_release.dll" ) ); - RuntimeDependencies.Add( new RuntimeDependency( TwitchDLLDir + "/Win32/avutil-ttv-51.dll" ) ); - RuntimeDependencies.Add( new RuntimeDependency( TwitchDLLDir + "/Win32/libmfxsw32.dll" ) ); - RuntimeDependencies.Add( new RuntimeDependency( TwitchDLLDir + "/Win32/libmp3lame-ttv.dll" ) ); - RuntimeDependencies.Add( new RuntimeDependency( TwitchDLLDir + "/Win32/swresample-ttv-0.dll" ) ); - } - - // Add the various base include paths for the Twitch SDK - PublicIncludePaths.Add( Path.Combine( TwitchBaseDir, "include" ) ); - PublicIncludePaths.Add( Path.Combine( TwitchBaseDir, "twitchcore", "include" ) ); - PublicIncludePaths.Add( Path.Combine( TwitchBaseDir, "twitchchat", "include" ) ); - } - } -} diff --git a/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/ThirdParty/Twitch/Twitch.tps b/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/ThirdParty/Twitch/Twitch.tps deleted file mode 100644 index 58a6767c436f..000000000000 --- a/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/ThirdParty/Twitch/Twitch.tps +++ /dev/null @@ -1,7 +0,0 @@ - - - -Redirect: ../NotForLicensees/Twitch/Twitch.tps -Notes: We don't distribute the Twitch SDK, but our TPS info for internal usage is given at the above link. - - diff --git a/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/TwitchLiveStreaming/ITwitchLiveStreaming.h b/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/TwitchLiveStreaming/ITwitchLiveStreaming.h deleted file mode 100644 index 6b03d923069b..000000000000 --- a/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/TwitchLiveStreaming/ITwitchLiveStreaming.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "CoreMinimal.h" -#include "ModuleManager.h" -#include "ModuleInterface.h" - -/** - * The interface to the Twitch live streaming module - */ -class ITwitchLiveStreaming : public IModuleInterface -{ - -public: - - /** - * Singleton-like access to this module's interface. This is just for convenience! - * Beware of calling this during the shutdown phase, though. Your module might have been unloaded already. - * - * @return Returns singleton instance, loading the module on demand if needed - */ - static inline ITwitchLiveStreaming& Get() - { - return FModuleManager::LoadModuleChecked( "TwitchLiveStreaming" ); - } - - /** - * Checks to see if this module is loaded and ready. It is only valid to call Get() if IsAvailable() returns true. - * - * @return True if the module is loaded and ready to use - */ - static inline bool IsAvailable() - { - return FModuleManager::Get().IsModuleLoaded( "TwitchLiveStreaming" ); - } -}; - diff --git a/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/TwitchLiveStreaming/TwitchLiveStreaming.Build.cs b/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/TwitchLiveStreaming/TwitchLiveStreaming.Build.cs deleted file mode 100644 index 9d9f4fab48cc..000000000000 --- a/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/TwitchLiveStreaming/TwitchLiveStreaming.Build.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -namespace UnrealBuildTool.Rules -{ - public class TwitchLiveStreaming : ModuleRules - { - public TwitchLiveStreaming(ReadOnlyTargetRules Target) : base(Target) - { - BinariesSubFolder = "NotForLicensees"; - - PrivateDependencyModuleNames.AddRange( - new string[] - { - "Core", - "CoreUObject", - "Engine", - "RenderCore", - "RHI" - }); - - if (Target.Type == TargetType.Editor) - { - DynamicallyLoadedModuleNames.AddRange( - new string[] - { - "Settings" - }); - - PublicIncludePathModuleNames.AddRange( - new string[] - { - "Settings" - }); - } - - string TwitchNotForLicenseesLibDir = System.IO.Path.Combine( UEBuildConfiguration.UEThirdPartySourceDirectory, "..", "..", "Plugins", "Runtime", "TwitchLiveStreaming", "Source", "ThirdParty", "NotForLicensees", "Twitch", "lib" ); // Check the NotForLicensees folder first - string TwitchLibDir = System.IO.Path.Combine( UEBuildConfiguration.UEThirdPartySourceDirectory, "..", "..", "Plugins", "Runtime", "TwitchLiveStreaming", "Source", "ThirdParty", "Twitch", "lib" ); - bool bHaveTwitchSDK = false; - - try - { - bHaveTwitchSDK = System.IO.Directory.Exists( TwitchNotForLicenseesLibDir ) || System.IO.Directory.Exists( TwitchLibDir ); - } - catch( System.Exception ) - { - } - - if( bHaveTwitchSDK ) - { - AddEngineThirdPartyPrivateStaticDependencies( Target, "Twitch" ); - Definitions.Add( "WITH_TWITCH=1" ); - } - else - { - Definitions.Add( "WITH_TWITCH=0" ); - } - } - } -} diff --git a/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/TwitchLiveStreaming/TwitchLiveStreaming.cpp b/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/TwitchLiveStreaming/TwitchLiveStreaming.cpp deleted file mode 100644 index 02cb6b12782a..000000000000 --- a/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/TwitchLiveStreaming/TwitchLiveStreaming.cpp +++ /dev/null @@ -1,2158 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#include "TwitchLiveStreaming.h" -#include "TwitchLiveStreamingModule.h" -#include "TwitchProjectSettings.h" -#include "ModuleManager.h" -#include "Runtime/Core/Public/Features/IModularFeatures.h" -#include "Runtime/Core/Public/Stats/Stats2.h" -#include "HAL/PlatformProcess.h" -#include "Misc/Paths.h" -#include "HAL/FileManager.h" -#include "Misc/CommandLine.h" -#include "Engine/Texture2D.h" -#if WITH_EDITOR -#include "ISettingsModule.h" -#endif - - -DEFINE_LOG_CATEGORY_STATIC( LogTwitch, Log, All ); - - -#if WITH_TWITCH - -IMPLEMENT_MODULE( FTwitchLiveStreaming, TwitchLiveStreaming ) -DECLARE_MEMORY_STAT( TEXT( "Twitch Memory" ), STAT_TwitchMemory, STATGROUP_Memory ); - -#define LOCTEXT_NAMESPACE "TwitchPlugin" - -namespace TwitchLiveStreaming -{ - static const bool bUseTwitchSDKForWebBrowserInteraction = true; // @todo twitch: Make configurable? Or deprecate some options here - - static const uint32 TwitchRequestAuthTokenFlags = - TTV_RequestAuthToken_Broadcast | // Permission to broadcast - TTV_RequestAuthToken_Chat; // Permission to chat -} - - -void FTwitchLiveStreaming::StartupModule() -{ - TwitchDLLHandle = nullptr; - - TwitchSetTraceLevel = nullptr; - TwitchInit = nullptr; - TwitchShutdown = nullptr; - TwitchPollTasks = nullptr; - TwitchRequestAuthToken = nullptr; - TwitchImplicitGrantAuthToken = nullptr; - TwitchLogin = nullptr; - TwitchErrorToString = nullptr; - TwitchGetIngestServers = nullptr; - TwitchFreeIngestList = nullptr; - TwitchStart = nullptr; - TwitchStop = nullptr; - TwitchGetMaxResolution = nullptr; - TwitchGetDefaultParams = nullptr; - TwitchSubmitVideoFrame = nullptr; - TwitchFreeGameLiveStreamList = nullptr; - TwitchGetGameLiveStreams = nullptr; - - TwitchWebCamInit = nullptr; - TwitchWebCamShutdown = nullptr; - TwitchWebCamStart = nullptr; - TwitchWebCamStop = nullptr; - TwitchWebCamFlushEvents = nullptr; - TwitchWebCamIsFrameAvailable = nullptr; - TwitchWebCamGetFrame = nullptr; - - TwitchChatInit = nullptr; - TwitchChatShutdown = nullptr; - TwitchChatConnect = nullptr; - TwitchChatDisconnect = nullptr; - TwitchChatSendMessage = nullptr; - TwitchChatFlushEvents = nullptr; - - TwitchState = ETwitchState::NotLoaded; - BroadcastState = EBroadcastState::Idle; - bWantsToBroadcastNow = false; - - bWantsWebCamNow = false; - WebCamState = EWebCamState::Uninitialized; - WebCamDeviceIndex = INDEX_NONE; - WebCamCapabilityIndex = INDEX_NONE; - WebCamVideoBufferWidth = 0; - WebCamVideoBufferHeight = 0; - bIsWebCamTextureFlippedVertically = false; - WebCamTexture = nullptr; - - bWantsChatEnabled = false; - ChatState = EChatState::Uninitialized; - - FMemory::Memzero( VideoBuffers ); - - // @todo twitch: Sometimes crashes on exit after streaming in the editor on Windows 8.1 - // @todo twitch urgent: Authorization of end-user games is having problems (bad auth token error) - // @todo twitch: Frames are not pushed while in a modal loop. Need to register to get called from Slate modal loop in FSlateApplication::Tick() (even if modal == true). We need to call BroadcastEditorVideoFrame() there, basically. - // @todo twitch: Twitch sometimes doesn't stream video on the feed, even though the engine appears to be sending frame successfully. Restarting usually fixes it. - // @todo twitch: Add analytics information for live streaming - // @todo twitch: Editor: Display list of available Unreal Engine live streams in the editor GUI - // @todo twitch: Make sure that documentation includes: "-TwitchDebug" arg, console commands, BP interface, C++ interface, editor vs game - // @todo twitch: Editor: Add buttons for audio volume, muting, pausing stream, commercials, editing channel info, etc. - // @todo twitch: Add C++/blueprint API for audio, pausing, commercials, channel info, etc. - // @todo twitch: On iOS, use TTV_SubmitCVPixelBuffer() to send frames - // @todo twitch: Use TTV_SetStreamInfo to set our game's name, etc. (These can be set in the Twitch.tv web UI too) - // @todo twitch: Use TTV_GetStreamInfo to get at current viewer count, and TTV_GetUserInfo to get the user's display name! Also, channel info... - // @todo twitch: Use TTV_PauseVideo() to pause display (SDK will generate frames instead), and use TTV_SetVolume() to mute/unmute! (submitting new frames will unpause video automatically) - // @todo twitch: Use TTV_RunCommercial() to go to break! (needs scope permission bit) - // @todo twitch: Check out meta-data APIs (SendActionMetaData, etc) (https://github.com/twitchtv/sdk-dist/wiki/Sending-Metadata, https://github.com/twitchtv/sdk-dist/wiki/Meta-data-API-v1-Event-Schema) - // @todo twitch: Enable this plugin by default - // @todo twitch: Implement MacOS and iOS support - // @todo twitch: Editor: Need hyperlink to my stream from editor! - // @todo twitch: Editor: Show audio microphone input level, so you can be sure you are not muted - // @todo twitch: Editor: Ideally we want a "zoom in" feature to use during editor live streams - - // Register our custom project settings -#if WITH_EDITOR - ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings"); - if( SettingsModule != nullptr ) - { - SettingsModule->RegisterSettings( - "Project", "Plugins", "Twitch", - LOCTEXT( "TwitchSettingsName", "Twitch" ), - LOCTEXT( "TwitchSettingsDescription", "Twitch game broadcasting settings" ), - GetMutableDefault< UTwitchProjectSettings >() ); - } -#endif - - // Register as a modular feature - IModularFeatures::Get().RegisterModularFeature( TEXT( "LiveStreaming" ), this ); -} - - -void FTwitchLiveStreaming::ShutdownModule() -{ - // Unregister our feature - IModularFeatures::Get().UnregisterModularFeature( TEXT( "LiveStreaming" ), this ); - -#if WITH_EDITOR - // Unregister custom project settings - ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings"); - if( SettingsModule != nullptr ) - { - SettingsModule->UnregisterSettings( "Project", "Plugins", "Twitch" ); - } -#endif - - if( TwitchState != ETwitchState::NotLoaded ) - { - // No longer safe to run callback functions, as we could be shutting down - OnStatusChangedEvent.Clear(); - OnChatMessageEvent.Clear(); - - // Turn off Twitch chat system - if( ChatState != EChatState::Uninitialized ) - { - UE_LOG( LogTwitch, Display, TEXT( "Shutting down Twitch chat system" ) ); - const TTV_ErrorCode TwitchErrorCode = TwitchChatShutdown( nullptr, nullptr ); - if( !TTV_SUCCEEDED( TwitchErrorCode ) ) - { - const FString TwitchErrorString( UTF8_TO_TCHAR( TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "An error occured while shutting down Twitch's chat system.\n\nError: %s (%d)" ), *TwitchErrorString, (int32)TwitchErrorCode ); - } - ChatState = EChatState::Uninitialized; - } - - // Turn off Twitch web cam system - if( WebCamState != EWebCamState::Uninitialized ) - { - UE_LOG( LogTwitch, Display, TEXT( "Shutting down Twitch web cam system") ); - const TTV_ErrorCode TwitchErrorCode = TwitchWebCamShutdown( nullptr, nullptr ); - if( !TTV_SUCCEEDED( TwitchErrorCode ) ) - { - const FString TwitchErrorString( UTF8_TO_TCHAR( TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "An error occured while shutting down Twitch's web cam system.\n\nError: %s (%d)"), *TwitchErrorString, (int32)TwitchErrorCode ); - } - WebCamState = EWebCamState::Uninitialized; - } - - // Release the web cam texture - const bool bReleaseResourceToo = false; // No need to release on shutdown, it will free up during normal GC phase - ReleaseWebCamTexture( bReleaseResourceToo ); - - // We are no longer broadcasting - if( BroadcastState != EBroadcastState::Idle ) - { - // Broadcast will be forcibly stopped by Twitch when we shutdown below. We'll release our graphics resources afterwards. - BroadcastState = EBroadcastState::Idle; - } - - if( TwitchState != ETwitchState::NotLoaded && TwitchState != ETwitchState::Uninitialized ) - { - TwitchState = ETwitchState::Uninitialized; - - // Turn off Twitch. NOTE: Any pending callbacks could fire at this point. - UE_LOG( LogTwitch, Display, TEXT( "Shutting down Twitch SDK") ); - const TTV_ErrorCode TwitchErrorCode = TwitchShutdown(); - if( !TTV_SUCCEEDED( TwitchErrorCode ) ) - { - const FString TwitchErrorString( UTF8_TO_TCHAR( TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "An error occured while shutting down Twitch.\n\nError: %s (%d)"), *TwitchErrorString, (int32)TwitchErrorCode ); - } - } - - // Clean up video buffers - for( uint32 VideoBufferIndex = 0; VideoBufferIndex < TwitchVideoBufferCount; ++VideoBufferIndex ) - { - delete[] VideoBuffers[ VideoBufferIndex ]; - VideoBuffers[ VideoBufferIndex ] = nullptr; - } - AvailableVideoBuffers.Reset(); - - if( TwitchState == ETwitchState::Uninitialized ) - { - check( TwitchDLLHandle != nullptr ); - - // Release the DLL - UE_LOG( LogTwitch, Display, TEXT( "Unloading Twitch SDK DLL") ); - FPlatformProcess::FreeDllHandle( TwitchDLLHandle ); - TwitchDLLHandle = nullptr; - } - - TwitchState = ETwitchState::NotLoaded; - } -} - - -void FTwitchLiveStreaming::InitOnDemand() -{ - if( TwitchState == ETwitchState::NotLoaded ) - { - // Load the Twitch SDK dll - // @todo twitch: This all needs to be handled differently for iOS (static linkage) - FString TwitchDLLFolder( FPaths::Combine( - *FPaths::EngineDir(), - TEXT("Plugins/Runtime/TwitchLiveStreaming/Binaries/ThirdParty/NotForLicensees/Twitch/"), // Check the "NotForLicensees" folder first - FPlatformProcess::GetBinariesSubdirectory() ) ); - if( !IFileManager::Get().DirectoryExists( *TwitchDLLFolder ) ) - { - TwitchDLLFolder = FPaths::Combine( - *FPaths::EngineDir(), - TEXT("Plugins/Runtime/TwitchLiveStreaming/Binaries/ThirdParty/Binaries/ThirdParty/Twitch/"), // Check the normal folder - FPlatformProcess::GetBinariesSubdirectory() ); - } - - - // Load the SDK DLL - LoadTwitchSDK( TwitchDLLFolder ); - - if( TwitchState == ETwitchState::Uninitialized ) - { - // Initialize the Twitch SDK - InitTwitch( TwitchDLLFolder ); - } - } -} - - - -void FTwitchLiveStreaming::LoadTwitchSDK( const FString& TwitchDLLFolder ) -{ - check( TwitchState == ETwitchState::NotLoaded ); - - { - // Make sure Twitch SDK DLL can find it's statically dependent DLLs - FPlatformProcess::PushDllDirectory( *TwitchDLLFolder ); - - const FString TwitchDLLFile( FPaths::Combine( - *TwitchDLLFolder, -#if PLATFORM_MAC - // Mac dylib - TEXT("libsdk-mac-dynamic.dylib"), -#else - // Windows DLL - *FString::Printf( TEXT("twitchsdk_%s_%s.dll"), - PLATFORM_64BITS ? TEXT( "64" ) : TEXT( "32" ), - #if UE_BUILD_DEBUG && !defined(NDEBUG) // Use !defined(NDEBUG) to check to see if we actually are linking with Debug third party libraries (bDebugBuildsActuallyUseDebugCRT) - TEXT( "Debug" ) - #else - TEXT( "Release" ) - #endif -#endif - ) ) ); - TwitchDLLHandle = FPlatformProcess::GetDllHandle( *TwitchDLLFile ); - - FPlatformProcess::PopDllDirectory( *TwitchDLLFolder ); - } - - - if( TwitchDLLHandle != nullptr ) - { - void* LambdaDLLHandle = TwitchDLLHandle; - - // Helper function to load DLL exports and report warnings - auto GetTwitchDllExport = [ &LambdaDLLHandle ]( const TCHAR* FuncName ) -> void* - { - void* FuncPtr = FPlatformProcess::GetDllExport( LambdaDLLHandle, FuncName ); - if( FuncPtr == nullptr ) - { - UE_LOG( LogTwitch, Warning, TEXT( "Failed to locate the expected DLL import function '%s' in the Twitch DLL." ), *FuncName ); - FPlatformProcess::FreeDllHandle( LambdaDLLHandle ); - LambdaDLLHandle = nullptr; - } - return FuncPtr; - }; - - // Grab Twitch SDK function pointers - - TwitchSetTraceLevel = (TwitchSetTraceLevelFuncPtr)GetTwitchDllExport( TEXT( "TTV_SetTraceLevel" ) ); - TwitchInit = (TwitchInitFuncPtr)GetTwitchDllExport( TEXT( "TTV_Init" ) ); - TwitchShutdown = (TwitchShutdownFuncPtr)GetTwitchDllExport( TEXT( "TTV_Shutdown" ) ); - TwitchPollTasks = (TwitchPollTasksFuncPtr)GetTwitchDllExport( TEXT( "TTV_PollTasks" ) ); - TwitchRequestAuthToken = (TwitchRequestAuthTokenFuncPtr)GetTwitchDllExport( TEXT( "TTV_RequestAuthToken" ) ); - TwitchImplicitGrantAuthToken = (TwitchImplicitGrantAuthTokenFuncPtr)GetTwitchDllExport( TEXT( "TTV_ImplicitGrantAuthToken" ) ); - TwitchLogin = (TwitchLoginFuncPtr)GetTwitchDllExport( TEXT( "TTV_Login" ) ); - TwitchErrorToString = (TwitchErrorToStringFuncPtr)GetTwitchDllExport( TEXT( "TTV_ErrorToString" ) ); - TwitchGetIngestServers = (TwitchGetIngestServersFuncPtr)GetTwitchDllExport( TEXT( "TTV_GetIngestServers" ) ); - TwitchFreeIngestList = (TwitchFreeIngestListFuncPtr)GetTwitchDllExport( TEXT( "TTV_FreeIngestList" ) ); - TwitchStart = (TwitchStartFuncPtr)GetTwitchDllExport( TEXT( "TTV_Start" ) ); - TwitchStop = (TwitchStopFuncPtr)GetTwitchDllExport( TEXT( "TTV_Stop" ) ); - TwitchGetMaxResolution = (TwitchGetMaxResolutionFuncPtr)GetTwitchDllExport( TEXT( "TTV_GetMaxResolution" ) ); - TwitchGetDefaultParams = (TwitchGetDefaultParamsFuncPtr)GetTwitchDllExport( TEXT( "TTV_GetDefaultParams" ) ); - TwitchSubmitVideoFrame = (TwitchSubmitVideoFrameFuncPtr)GetTwitchDllExport( TEXT( "TTV_SubmitVideoFrame" ) ); - TwitchFreeGameLiveStreamList = (TwitchFreeGameLiveStreamListFuncPtr)GetTwitchDllExport( TEXT( "TTV_FreeGameLiveStreamList" ) ); - TwitchGetGameLiveStreams = (TwitchGetGameLiveStreamsFuncPtr)GetTwitchDllExport( TEXT( "TTV_GetGameLiveStreams" ) ); - - TwitchWebCamInit = (TwitchWebCamInitFuncPtr)GetTwitchDllExport( TEXT( "TTV_WebCam_Init" ) ); - TwitchWebCamShutdown = (TwitchWebCamShutdownFuncPtr)GetTwitchDllExport( TEXT( "TTV_WebCam_Shutdown" ) ); - TwitchWebCamStart = (TwitchWebCamStartFuncPtr)GetTwitchDllExport( TEXT( "TTV_WebCam_Start" ) ); - TwitchWebCamStop = (TwitchWebCamStopFuncPtr)GetTwitchDllExport( TEXT( "TTV_WebCam_Stop" ) ); - TwitchWebCamFlushEvents = (TwitchWebCamFlushEventsFuncPtr)GetTwitchDllExport( TEXT( "TTV_WebCam_FlushEvents" ) ); - TwitchWebCamIsFrameAvailable = (TwitchWebCamIsFrameAvailableFuncPtr)GetTwitchDllExport( TEXT( "TTV_WebCam_IsFrameAvailable" ) ); - TwitchWebCamGetFrame = (TwitchWebCamGetFrameFuncPtr)GetTwitchDllExport( TEXT( "TTV_WebCam_GetFrame" ) ); - - TwitchChatInit = (TwitchChatInitFuncPtr)GetTwitchDllExport( TEXT( "TTV_Chat_Init" ) ); - TwitchChatShutdown = (TwitchChatShutdownFuncPtr)GetTwitchDllExport( TEXT( "TTV_Chat_Shutdown" ) ); - TwitchChatConnect = (TwitchChatConnectFuncPtr)GetTwitchDllExport( TEXT( "TTV_Chat_Connect" ) ); - TwitchChatDisconnect = (TwitchChatDisconnectFuncPtr)GetTwitchDllExport( TEXT( "TTV_Chat_Disconnect" ) ); - TwitchChatSendMessage = (TwitchChatSendMessageFuncPtr)GetTwitchDllExport( TEXT( "TTV_Chat_SendMessage" ) ); - TwitchChatFlushEvents = (TwitchChatFlushEventsFuncPtr)GetTwitchDllExport( TEXT( "TTV_Chat_FlushEvents" ) ); - - TwitchDLLHandle = LambdaDLLHandle; - } - else - { - int32 ErrorNum = FPlatformMisc::GetLastError(); - TCHAR ErrorMsg[1024]; - FPlatformMisc::GetSystemErrorMessage( ErrorMsg, 1024, ErrorNum ); - UE_LOG( LogTwitch, Warning, TEXT("Failed to get Twitch DLL handle.\n\nError: %s (%d)"), ErrorMsg, ErrorNum ); - } - - if( TwitchDLLHandle != nullptr ) - { - // OK, everything loaded! But we're not initialized yet. - TwitchState = ETwitchState::Uninitialized; - } -} - - -FTwitchLiveStreaming::FTwitchProjectSettings FTwitchLiveStreaming::LoadProjectSettings() -{ - FTwitchProjectSettings Settings; - if( GIsEditor && !GIsPlayInEditorWorld ) - { - // In the editor, we use a single Twitch application "client ID" for all sessions. - const FString ConfigCategory( TEXT( "TwitchEditorBroadcasting" ) ); - - // This is the Twitch 'client ID' for the Unreal Engine Twitch application. This allows anyone to login to Twitch and broadcast - // usage of the editor to their Twitch channel. This is only used when running the editor though. To allow your users to - // stream gameplay to Twitch, you'll need to create your own Twitch client ID and set that in your project's settings! - Settings.ClientID = TEXT( "nu2tppawhw58o74a2burkyc9fyuvjlr" ); - Settings.RedirectURI = TEXT( "http://localhost:6180" ); - Settings.LocalPortNumber = 6180; - Settings.AuthSuccessRedirectURI = TEXT( "" ); // @todo twitch: Need nice Unreal Engine redirect landing pages - Settings.AuthFailureRedirectURI = TEXT( "" ); // @todo twitch: Need nice Unreal Engine redirect landing pages - Settings.ClientSecret = TEXT( "" ); - } - else - { - // For the game, Twitch settings are configured inside of the game-specific project settings. Use the editor's - // Project Settings window to configure settings for streaming your game to Twitch! - const auto& TwitchProjectSettings = *GetDefault< UTwitchProjectSettings >(); - Settings.ClientID = TwitchProjectSettings.ApplicationClientID; - Settings.RedirectURI = TwitchProjectSettings.RedirectURI; - Settings.LocalPortNumber = TwitchProjectSettings.LocalPortNumber; - Settings.AuthSuccessRedirectURI = TwitchProjectSettings.AuthSuccessRedirectURI; - Settings.AuthFailureRedirectURI = TwitchProjectSettings.AuthFailureRedirectURI; - Settings.ClientSecret = TwitchProjectSettings.DirectAuthenticationClientSecretID; - } - - return Settings; -} - - -void FTwitchLiveStreaming::InitTwitch( const FString& TwitchWindowsDLLFolder ) -{ - check( TwitchState == ETwitchState::Uninitialized ); - - // @todo twitch: This can be enabled to emit verbose log spew from the Twitch SDK to the IDE output window - if( FParse::Param( FCommandLine::Get(), TEXT("TwitchDebug") ) ) - { - TwitchSetTraceLevel( TTV_ML_DEBUG ); - } - - // Load Twitch configuration from disk - ProjectSettings = LoadProjectSettings(); - - // Setup memory allocation and deallocation overrides - TTV_MemCallbacks TwitchMemCallbacks; - { - struct Local - { - static void* TwitchAlloc( size_t Size, size_t Alignment ) - { - void* Result = FMemory::Malloc( Size, uint32( Alignment ) ); -#if STATS - const SIZE_T ActualSize = FMemory::GetAllocSize( Result ); - INC_DWORD_STAT_BY( STAT_TwitchMemory, ActualSize ); -#endif // STATS - return Result; - } - - static void TwitchFree( void* Ptr ) - { -#if STATS - const SIZE_T Size = FMemory::GetAllocSize( Ptr ); - DEC_DWORD_STAT_BY( STAT_TwitchMemory, Size ); -#endif // STATS - FMemory::Free( Ptr ); - } - - }; - - TwitchMemCallbacks.size = sizeof( TwitchMemCallbacks ); - TwitchMemCallbacks.allocCallback = &Local::TwitchAlloc; - TwitchMemCallbacks.freeCallback = &Local::TwitchFree; - } - - const TTV_ErrorCode TwitchErrorCode = TwitchInit( &TwitchMemCallbacks, TCHAR_TO_ANSI( *ProjectSettings.ClientID ), *TwitchWindowsDLLFolder ); - if( !TTV_SUCCEEDED( TwitchErrorCode ) ) - { - const FString TwitchErrorString( UTF8_TO_TCHAR( TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Couldn't initialize Twitch SDK.\n\nError: %s (%d)"), *TwitchErrorString, (int32)TwitchErrorCode ); - } - else - { - UE_LOG( LogTwitch, Display, TEXT( "Twitch plugin is initialized and ready") ); - TwitchState = ETwitchState::ReadyToAuthenticate; - } -} - - -void FTwitchLiveStreaming::Async_AuthenticateWithTwitchDirectly( const FString& UserName, const FString& Password, const FString& ClientSecret ) -{ - check( TwitchState == ETwitchState::ReadyToAuthenticate ); - - // This will be filled in by TTV_RequestAuthToken() or TTV_ImplicitGrantAuthToken() - FMemory::Memzero( TwitchAuthToken ); - - TTV_AuthParams TwitchAuthParams; - TwitchAuthParams.size = sizeof( TwitchAuthParams ); - - auto UserNameAnsi = StringCast( *UserName ); - TwitchAuthParams.userName = UserNameAnsi.Get(); - - auto PasswordAnsi = StringCast( *Password ); - TwitchAuthParams.password = PasswordAnsi.Get(); - - auto ClientSecretAnsi = StringCast( *ClientSecret ); - TwitchAuthParams.clientSecret = ClientSecretAnsi.Get(); - - // Called when TwitchRequestAuthToken finishes async work - void* CallbackUserDataPtr = this; - TTV_TaskCallback TwitchTaskCallback = []( TTV_ErrorCode TwitchErrorCode, void* CallbackUserDataPtr ) - { - FTwitchLiveStreaming* This = static_cast( CallbackUserDataPtr ); - - // Make sure we're still in the state that we were expecting - if( This->TwitchState != ETwitchState::Uninitialized && ensure( This->TwitchState == ETwitchState::WaitingForDirectAuthentication ) ) - { - if( TTV_SUCCEEDED( TwitchErrorCode ) ) - { - // If this call succeeded, we must now have valid auth token data - if( ensure( This->TwitchAuthToken.data[0] != 0 ) ) - { - // OK, we're authorized now. Next we need to login. - UE_LOG( LogTwitch, Display, TEXT( "Twitch authentication was successful (auth token '%s')"), ANSI_TO_TCHAR( This->TwitchAuthToken.data ) ); - This->PublishStatus( EStatusType::Progress, LOCTEXT( "Status_AuthenticationOK", "Successfully authenticated with Twitch" ) ); - This->TwitchState = ETwitchState::ReadyToLogin; - } - } - else - { - const FString TwitchErrorString( UTF8_TO_TCHAR( This->TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Failed to authenticate with Twitch server.\n\nError: %s (%d)"), *TwitchErrorString, (int32)TwitchErrorCode ); - This->PublishStatus( EStatusType::Failure, FText::Format( LOCTEXT( "Status_AuthenticationFailed", "Failed to authenticate with Twitch ({0})" ), FText::FromString( TwitchErrorString ) ) ); - This->TwitchState = ETwitchState::LoginFailure; - } - } - }; - - UE_LOG( LogTwitch, Display, TEXT( "Authenticating with Twitch directly as user '%s' (passing along password and client secret)"), ANSI_TO_TCHAR( TwitchAuthParams.userName ) ); - PublishStatus( EStatusType::Progress, LOCTEXT( "Status_Authenticating", "Authenticating with Twitch..." ) ); - - TwitchState = ETwitchState::WaitingForDirectAuthentication; - const TTV_ErrorCode TwitchErrorCode = TwitchRequestAuthToken( &TwitchAuthParams, TwitchLiveStreaming::TwitchRequestAuthTokenFlags, TwitchTaskCallback, CallbackUserDataPtr, &TwitchAuthToken ); - if( !TTV_SUCCEEDED( TwitchErrorCode ) ) - { - const FString TwitchErrorString( UTF8_TO_TCHAR( TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Failed to initiate authentication with Twitch server.\n\nError: %s (%d)"), *TwitchErrorString, (int32)TwitchErrorCode ); - PublishStatus( EStatusType::Failure, FText::Format( LOCTEXT( "Status_AuthenticationStartFailed", "Failed to start authenticate with Twitch ({0})" ), FText::FromString( TwitchErrorString ) ) ); - TwitchState = ETwitchState::LoginFailure; - } -} - - -void FTwitchLiveStreaming::Async_AuthenticateWithTwitchUsingBrowser_UsingTwitchSDK() -{ - check( TwitchState == ETwitchState::ReadyToAuthenticate ); - - // Called when TTV_ImplicitGrantAuthToken finishes async work - void* CallbackUserDataPtr = this; - TTV_TaskCallback TwitchTaskCallback = []( TTV_ErrorCode TwitchErrorCode, void* CallbackUserDataPtr ) - { - FTwitchLiveStreaming* This = static_cast( CallbackUserDataPtr ); - - // Make sure we're still in the state that we were expecting - if( This->TwitchState != ETwitchState::Uninitialized && ensure( This->TwitchState == ETwitchState::WaitingForBrowserBasedAuthentication ) ) - { - if( TTV_SUCCEEDED( TwitchErrorCode ) ) - { - // If this call succeeded, we must now have valid auth token data - if( ensure( This->TwitchAuthToken.data[ 0 ] != 0 ) ) - { - // OK, we're authorized now. Next we need to login. - UE_LOG( LogTwitch, Display, TEXT( "Twitch authentication using web browser was successful (auth token '%s')" ), ANSI_TO_TCHAR( This->TwitchAuthToken.data ) ); - This->PublishStatus( EStatusType::Progress, LOCTEXT( "Status_AuthenticationOK", "Successfully authenticated with Twitch" ) ); - This->TwitchState = ETwitchState::ReadyToLogin; - } - } - else - { - const FString TwitchErrorString( UTF8_TO_TCHAR( This->TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Failed to authenticate with Twitch using web browser.\n\nError: %s (%d)" ), *TwitchErrorString, (int32)TwitchErrorCode ); - This->PublishStatus( EStatusType::Failure, FText::Format( LOCTEXT( "Status_AuthenticationFailed", "Failed to authenticate with Twitch ({0})" ), FText::FromString( TwitchErrorString ) ) ); - This->TwitchState = ETwitchState::LoginFailure; - } - } - }; - - UE_LOG( LogTwitch, Display, TEXT( "Asking Twitch to launch a web browser so that the user can authenticate" ) ); - PublishStatus( EStatusType::Progress, LOCTEXT( "Status_AuthenticatingWithBrowserUsingTwitch", "Waiting for Twitch browser authentication..." ) ); - - TwitchState = ETwitchState::WaitingForBrowserBasedAuthentication; - - // @todo twitch: As far as I can tell, there is no timeout mechanism with this feature! This means it will spin on a thread forever waiting - // for the browser to be summoned and respond with an auth token. If there is a problem with the user logging in, or if the user is not - // connected to the internet, this may never call back! - const TTV_ErrorCode TwitchErrorCode = TwitchImplicitGrantAuthToken( - TCHAR_TO_ANSI( *ProjectSettings.ClientID ), - TCHAR_TO_ANSI( *FString::FromInt( ProjectSettings.LocalPortNumber ) ), - TCHAR_TO_ANSI( *ProjectSettings.AuthSuccessRedirectURI ), - TCHAR_TO_ANSI( *ProjectSettings.AuthFailureRedirectURI ), - TwitchLiveStreaming::TwitchRequestAuthTokenFlags, - TwitchTaskCallback, - CallbackUserDataPtr, - &TwitchAuthToken ); - - if( !TTV_SUCCEEDED( TwitchErrorCode ) ) - { - const FString TwitchErrorString( UTF8_TO_TCHAR( TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Failed to initiate implicit grant authentication using a web browser.\n\nError: %s (%d)" ), *TwitchErrorString, (int32)TwitchErrorCode ); - PublishStatus( EStatusType::Failure, FText::Format( LOCTEXT( "Status_ImplicitGranAuthFailed", "Failed to start implicit gran authentication using Twitch ({0})" ), FText::FromString( TwitchErrorString ) ) ); - TwitchState = ETwitchState::LoginFailure; - } -} - - - -void FTwitchLiveStreaming::Async_AuthenticateWithTwitchUsingBrowser_Manually() -{ - check( TwitchState == ETwitchState::ReadyToAuthenticate ); - - UE_LOG( LogTwitch, Display, TEXT( "Manually launching a web browser so that the user can authenticate with Twitch") ); - PublishStatus( EStatusType::Progress, LOCTEXT( "Status_AuthenticatingWithBrowserManually", "Waiting for manual web browser authentication..." ) ); - - // List of possible scopes can be found here: https://github.com/justintv/Twitch-API/blob/master/authentication.md#scopes - // @todo twitch: Allow user to login with chat access only (no broadcasting), for games that just want to participate in chat - const FString TwitchScopes( TEXT( "user_read+channel_read+channel_editor+channel_commercial+sdk_broadcast+chat_login+metadata_events_edit" ) ); // channel_commercial+metadata_events_edit+user_blocks_edit+user_blocks_read+user_follows_edit+channel_commercial+channel_stream+channel_subscriptions+user_subscriptions+channel_check_subscription" ) ); - - // Build up a URL string to give to the web browser - const FString URLString( FString::Printf( - TEXT( "https://api.twitch.tv/kraken/oauth2/authorize?response_type=token&client_id=%s&redirect_uri=%s&scope=%s" ), - *ProjectSettings.ClientID, // Client ID - *ProjectSettings.RedirectURI, // Redirect URI - *TwitchScopes ) ); // Space(+)-separated list of scopes - - // Launch the web browser on this computer - FString LaunchURLError; - FPlatformProcess::LaunchURL( *URLString, TEXT( "" ), &LaunchURLError ); - - if( LaunchURLError.IsEmpty() ) - { - // OK, let's hang tight while the user logs in. We'll check up on it by calling CheckIfBrowserLoginCompleted() every so often - TwitchState = ETwitchState::WaitingForBrowserBasedAuthentication; - - BrowserLoginStartTime = FDateTime::UtcNow(); - LastBrowserLoginCheckTime = FDateTime::MinValue(); - } - else - { - // Something went wrong, couldn't launch the browser - UE_LOG( LogTwitch, Warning, TEXT( "Unable to launch web browser to start Twitch authentication (URL: '%s', Error: '%s')" ), *URLString, *LaunchURLError ); - PublishStatus( EStatusType::Failure, FText::Format( LOCTEXT( "Status_WebAuthenticationStartFailed", "Failed to launch web browser to authenticate with Twitch ({0})" ), FText::FromString( LaunchURLError ) ) ); - TwitchState = ETwitchState::LoginFailure; - } -} - - -void FTwitchLiveStreaming::CheckIfBrowserLoginCompleted() -{ - // @todo twitch: It would be nice if we could close the browser tab after we've got the access token from it - - // How long to wait before we go looking for a window title that matches our request. We don't want to get a stale - // browser tab that has an old authentication token, so we need to make sure to give the browser tab enough time to open - const float SecondsBeforeFirstLoginCheck = 0.25f; - - // How long between each check we perform. This is just to reduce CPU usage. - const float SecondsBetweenBrowserLoginChecks = 0.2f; - - // How long the user has to authenticate with Twitch using the web site. They may need to interactively login at this time, - // so we need to be a little bit generous - const float BrowserLoginTimeoutDuration = 120.0f; - - const FDateTime CurrentTime = FDateTime::UtcNow(); - if( CurrentTime - BrowserLoginStartTime >= FTimespan::FromSeconds( SecondsBeforeFirstLoginCheck ) ) - { - if( ( CurrentTime - LastBrowserLoginCheckTime ) >= FTimespan::FromSeconds( SecondsBetweenBrowserLoginChecks ) ) - { - LastBrowserLoginCheckTime = CurrentTime; - - // Find the browser window we spawned which should now be titled with the redirect URL - FString Title; - if( FPlatformMisc::GetWindowTitleMatchingText( *ProjectSettings.RedirectURI, Title ) ) - { - // Parse access token from the login redirect url - FString AccessToken; - if( FParse::Value(*Title, TEXT("#access_token="), AccessToken) && !AccessToken.IsEmpty() ) - { - // Strip off any URL parameters and just keep the token itself - FString AccessTokenOnly; - if( AccessToken.Split( TEXT("&"), &AccessTokenOnly, NULL ) ) - { - AccessToken = AccessTokenOnly; - } - - FPlatformString::Strcpy( TwitchAuthToken.data, AccessToken.Len() + 1, TCHAR_TO_ANSI( *AccessToken ) ); - - // OK, we have the auth token! - TwitchState = ETwitchState::ReadyToLogin; - } - else - { - // Couldn't parse the window title text - UE_LOG( LogTwitch, Warning, TEXT( "Failed to parse the authentication token text from the scraped browser window with the redirect URI string ('%s')"), *Title ); - PublishStatus( EStatusType::Failure, LOCTEXT( "Status_WebAuthenticationParseFailed", "Authentication failed. Couldn't find authentication token string in web URL" ) ); - TwitchState = ETwitchState::LoginFailure; - } - } - else - { - // Couldn't find a browser window with a title we were expecting. - if( ( CurrentTime - BrowserLoginStartTime ) >= FTimespan::FromSeconds( BrowserLoginTimeoutDuration ) ) - { - // Too much time has passed. We need to abort the login - UE_LOG( LogTwitch, Warning, TEXT( "We timed out after %.2f seconds waiting for user to complete browser-based authentication with Twitch"), BrowserLoginTimeoutDuration ); - PublishStatus( EStatusType::Failure, LOCTEXT( "Status_WebAuthenticationTimedOut", "Twitch web authentication timed out. Please restart your broadcast to try again." ) ); - TwitchState = ETwitchState::LoginFailure; - } - else - { - // We'll try again later. - } - } - } - } -} - - -void FTwitchLiveStreaming::Async_LoginToTwitch() -{ - check( TwitchState == ETwitchState::ReadyToLogin ); - - // Calling TTV_Login() will fill the TwitchChannelInfo structure with information about the Twitch channel - FMemory::Memzero( TwitchChannelInfo ); // @todo twitch: We should expose this to the live stream API - TwitchChannelInfo.size = sizeof( TwitchChannelInfo ); - - // Called when TwitchLogin finishes async work - void* CallbackUserDataPtr = this; - TTV_TaskCallback TwitchTaskCallback = []( TTV_ErrorCode TwitchErrorCode, void* CallbackUserDataPtr ) - { - FTwitchLiveStreaming* This = static_cast( CallbackUserDataPtr ); - - // Make sure we're still in the state that we were expecting - if( This->TwitchState != ETwitchState::Uninitialized && ensure( This->TwitchState == ETwitchState::WaitingForLogin ) ) - { - if( TTV_SUCCEEDED( TwitchErrorCode ) ) - { - // OK, we're now logged in! - UE_LOG( LogTwitch, Display, TEXT( "Logged into Twitch successfully!") ); - UE_LOG( LogTwitch, Display, TEXT( "Connected to Twitch channel '%s' (Name:%s, URL: %s)"), ANSI_TO_TCHAR( This->TwitchChannelInfo.displayName ), ANSI_TO_TCHAR( This->TwitchChannelInfo.name ), ANSI_TO_TCHAR( This->TwitchChannelInfo.channelUrl ) ); - This->PublishStatus( EStatusType::Progress, LOCTEXT( "Status_LoginOK", "Logged into Twitch successfully!" ) ); - - This->TwitchState = ETwitchState::LoggedIn; - } - else - { - const FString TwitchErrorString( UTF8_TO_TCHAR( This->TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Failed to login to Twitch.\n\nError: %s (%d)"), *TwitchErrorString, (int32)TwitchErrorCode ); - This->PublishStatus( EStatusType::Failure, FText::Format( LOCTEXT( "Status_LoginFailed", "Failed to login to Twitch ({0})" ), FText::FromString( TwitchErrorString ) ) ); - This->TwitchState = ETwitchState::LoginFailure; - } - } - }; - - UE_LOG( LogTwitch, Display, TEXT( "Logging into Twitch (auth token '%s')..."), ANSI_TO_TCHAR( TwitchAuthToken.data ) ); - PublishStatus( EStatusType::Progress, LOCTEXT( "Status_LoggingIn", "Logging into Twitch server..." ) ); - - TwitchState = ETwitchState::WaitingForLogin; - const TTV_ErrorCode TwitchErrorCode = TwitchLogin( &TwitchAuthToken, TwitchTaskCallback, CallbackUserDataPtr, &TwitchChannelInfo ); - if( !TTV_SUCCEEDED( TwitchErrorCode ) ) - { - const FString TwitchErrorString( UTF8_TO_TCHAR( TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Failed to initiate login to Twitch.\n\nError: %s (%d)"), *TwitchErrorString, (int32)TwitchErrorCode ); - PublishStatus( EStatusType::Failure, FText::Format( LOCTEXT( "Status_LoginStartFailed", "Failed to start logging into Twitch ({0})" ), FText::FromString( TwitchErrorString ) ) ); - TwitchState = ETwitchState::LoginFailure; - } -} - - - -void FTwitchLiveStreaming::Async_GetIngestServers() -{ - check( TwitchState == ETwitchState::LoggedIn ); - check( BroadcastState == EBroadcastState::Idle ); - - // This will be filled in by calling TTV_GetIngestServers() - FMemory::Memzero( TwitchIngestList ); - - // Called when TwitchGetIngestServers finishes async work - void* CallbackUserDataPtr = this; - TTV_TaskCallback TwitchTaskCallback = []( TTV_ErrorCode TwitchErrorCode, void* CallbackUserDataPtr ) - { - FTwitchLiveStreaming* This = static_cast( CallbackUserDataPtr ); - - // Make sure we're still in the state that we were expecting - if( This->TwitchState != ETwitchState::Uninitialized && ensure( This->BroadcastState == EBroadcastState::WaitingForGetIngestServers ) ) - { - if( TTV_SUCCEEDED( TwitchErrorCode ) ) - { - // OK we have our list of servers. We can now start broadcasting when ready. - UE_LOG( LogTwitch, Display, TEXT( "Found %i Twitch ingest servers:" ), This->TwitchIngestList.ingestCount ); - for( uint32 ServerIndex = 0; ServerIndex < This->TwitchIngestList.ingestCount; ++ServerIndex ) - { - const auto& ServerInfo = This->TwitchIngestList.ingestList[ ServerIndex ]; - UE_LOG( LogTwitch, Display, TEXT( " %i. %s (URL:%s, default:%s)"), ServerIndex, ANSI_TO_TCHAR( ServerInfo.serverName ), ANSI_TO_TCHAR( ServerInfo.serverUrl ), ServerInfo.defaultServer ? TEXT( "yes" ) : TEXT( "no" ) ); - } - This->BroadcastState = EBroadcastState::ReadyToBroadcast; - } - else - { - const FString TwitchErrorString( UTF8_TO_TCHAR( This->TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Failed to query list of available ingest servers.\n\nError: %s (%d)"), *TwitchErrorString, (int32)TwitchErrorCode ); - This->PublishStatus( EStatusType::Failure, FText::Format( LOCTEXT( "Status_QueryServerListFailed", "Failed to query server list ({0})" ), FText::FromString( TwitchErrorString ) ) ); - This->BroadcastState = EBroadcastState::BroadcastingFailure; - } - } - }; - - UE_LOG( LogTwitch, Display, TEXT( "Querying available Twitch ingest servers for broadcasting...") ); - PublishStatus( EStatusType::Progress, LOCTEXT( "Status_QueryingServers", "Querying Twitch server list..." ) ); - BroadcastState = EBroadcastState::WaitingForGetIngestServers; - const TTV_ErrorCode TwitchErrorCode = TwitchGetIngestServers( &TwitchAuthToken, TwitchTaskCallback, CallbackUserDataPtr, &TwitchIngestList ); - if( !TTV_SUCCEEDED( TwitchErrorCode ) ) - { - const FString TwitchErrorString( UTF8_TO_TCHAR( TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Failed to initiate query for list of available ingest servers.\n\nError: %s (%d)"), *TwitchErrorString, (int32)TwitchErrorCode ); - PublishStatus( EStatusType::Failure, FText::Format( LOCTEXT( "Status_QueryServerListStartFailed", "Failed to start querying server list ({0})" ), FText::FromString( TwitchErrorString ) ) ); - BroadcastState = EBroadcastState::BroadcastingFailure; - } -} - - -void FTwitchLiveStreaming::Async_StartBroadcasting() -{ - check( BroadcastState == EBroadcastState::ReadyToBroadcast ); - - // Pick an ingest server - TTV_IngestServer SelectedTwitchIngestServer; - FMemory::Memzero( SelectedTwitchIngestServer ); - { - // Select the default ingest server recommended by the Twitch SDK - // @todo twitch: We might want to run an 'ingest test' first. This will help with bitrate selection too, apparently - bool bFoundDefaultServer = false; - for( uint32 ServerIndex = 0; ServerIndex < TwitchIngestList.ingestCount; ++ServerIndex ) - { - const TTV_IngestServer& CurrentTwitchIngestServer = TwitchIngestList.ingestList[ ServerIndex ]; - if( CurrentTwitchIngestServer.defaultServer == true ) - { - // Use the default server - SelectedTwitchIngestServer = CurrentTwitchIngestServer; - bFoundDefaultServer = true; - break; - } - } - if( bFoundDefaultServer ) - { - UE_LOG( LogTwitch, Display, TEXT( "Selected Twitch ingest server '%s' for broadcasting"), ANSI_TO_TCHAR( SelectedTwitchIngestServer.serverName ) ); - } - else - { - UE_LOG( LogTwitch, Warning, TEXT( "Failed to start broadcasting because we couldn't find a default ingest server to use") ); - PublishStatus( EStatusType::Failure, LOCTEXT( "Status_FailedToFindServer", "Couldn't find a valid Twitch server to stream to" ) ); - BroadcastState = EBroadcastState::BroadcastingFailure; - } - } - - - UE_LOG( LogTwitch, Display, TEXT( "Twitch broadcast configured for %i x %i resolution"), BroadcastConfig.VideoBufferWidth, BroadcastConfig.VideoBufferHeight ); - - - // Check with Twitch to see if the configured resolution is too high, and warn the user if so - { - // @todo twitch: Customize these properly or make data driven. Though, we don't really use this for much of anything yet, other than a warning log message - - const uint32 TwitchMaxKbps = 1024; // Maximum bitrate supported (this should be determined by running the ingest tester for a given ingest server) - const float TwitchBitsPerPixel = 0.2f; // The bits per pixel used in the final encoded video. A fast motion game (e.g. first person shooter) required more bits per pixel of encoded video avoid compression artifacting. Use 0.1 for an average motion game. For games without too many fast changes in the scene, you could use a value below 0.1 but not much. For fast moving games with lots of scene changes a value as high as 0.2 would be appropriate. - const float TwitchAspectRatio = 1.6f; // The aspect ratio of the video which we'll use for calculating width and height - - uint MaximumWidth = 0; - uint MaximumHeight = 0; - if( BroadcastState == EBroadcastState::ReadyToBroadcast ) - { - const TTV_ErrorCode TwitchErrorCode = TwitchGetMaxResolution( - TwitchMaxKbps, - BroadcastConfig.FramesPerSecond, - TwitchBitsPerPixel, - TwitchAspectRatio, - &MaximumWidth, - &MaximumHeight ); - if( !TTV_SUCCEEDED( TwitchErrorCode ) ) - { - const FString TwitchErrorString( UTF8_TO_TCHAR( TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Failed to determine maximum resolution for Twitch video stream.\n\nError: %s (%d)"), *TwitchErrorString, (int32)TwitchErrorCode ); - BroadcastState = EBroadcastState::BroadcastingFailure; - } - - UE_LOG( LogTwitch, Display, TEXT( "Twitch suggested a maximum streaming resolution of %i x %i for our parameters"), MaximumWidth, MaximumHeight ); - } - - if( (int)MaximumWidth < BroadcastConfig.VideoBufferWidth || (int)MaximumHeight < BroadcastConfig.VideoBufferHeight ) - { - UE_LOG( LogTwitch, Warning, TEXT( "Twitch warns that configured resolution (%i x %i) is too high for the configured bit rate and frame rate, suggests using %i x %i instead."), BroadcastConfig.VideoBufferWidth, BroadcastConfig.VideoBufferHeight, MaximumWidth, MaximumHeight ); - } - } - - // Start streaming - if( BroadcastState == EBroadcastState::ReadyToBroadcast ) - { - // @todo twitch: Make sure these settings are all filled in! - TTV_VideoParams TwitchVideoParams; - FMemory::Memzero( TwitchVideoParams ); - TwitchVideoParams.size = sizeof( TwitchVideoParams ); - TwitchVideoParams.outputWidth = BroadcastConfig.VideoBufferWidth; - TwitchVideoParams.outputHeight = BroadcastConfig.VideoBufferHeight; - TwitchVideoParams.targetFps = BroadcastConfig.FramesPerSecond; // @todo twitch: We can save CPU cycles by not emitting frames when Twitch is behind (maybe compare buffer pointer to see if same buffer as last time?) - - // Ask Twitch to fill in the rest of the video options based on the width, height and target FPS - TwitchGetDefaultParams( &TwitchVideoParams ); - - // Set our pixel format - switch( BroadcastConfig.PixelFormat ) - { - case FBroadcastConfig::EBroadcastPixelFormat::B8G8R8A8: - TwitchVideoParams.pixelFormat = TTV_PF_BGRA; - break; - - case FBroadcastConfig::EBroadcastPixelFormat::R8G8B8A8: - default: - TwitchVideoParams.pixelFormat = TTV_PF_RGBA; - break; - - case FBroadcastConfig::EBroadcastPixelFormat::A8R8G8B8: - TwitchVideoParams.pixelFormat = TTV_PF_ARGB; - break; - - case FBroadcastConfig::EBroadcastPixelFormat::A8B8G8R8: - TwitchVideoParams.pixelFormat = TTV_PF_ABGR; - break; - } - - TTV_AudioParams TwitchAudioParams; - FMemory::Memzero( TwitchAudioParams ); - TwitchAudioParams.size = sizeof( TwitchAudioParams ); - TwitchAudioParams.audioEnabled = BroadcastConfig.bCaptureAudioFromComputer || BroadcastConfig.bCaptureAudioFromMicrophone; - TwitchAudioParams.enableMicCapture = BroadcastConfig.bCaptureAudioFromMicrophone; - TwitchAudioParams.enablePlaybackCapture = BroadcastConfig.bCaptureAudioFromComputer; - TwitchAudioParams.enablePassthroughAudio = false; // @todo twitch: Usually only needed on iOS platform - - const uint32 TwitchStartFlags = 0; // @todo twitch: Also supports: TTV_Start_BandwidthTest - - // @todo twitch: This call may fail on Mac if SoundFlower is not installed - - // Called when TwitchStart finishes async work - void* CallbackUserDataPtr = this; - TTV_TaskCallback TwitchTaskCallback = []( TTV_ErrorCode TwitchErrorCode, void* CallbackUserDataPtr ) - { - FTwitchLiveStreaming* This = static_cast( CallbackUserDataPtr ); - - // Make sure we're still in the state that we were expecting - if( This->TwitchState != ETwitchState::Uninitialized && ensure( This->BroadcastState == EBroadcastState::WaitingToStartBroadcasting ) ) - { - if( TTV_SUCCEEDED( TwitchErrorCode ) ) - { - // OK we are now LIVE! - UE_LOG( LogTwitch, Display, TEXT( "Twitch broadcast has started. You are now LIVE!" ) ); - This->BroadcastState = EBroadcastState::Broadcasting; - This->PublishStatus( EStatusType::BroadcastStarted, LOCTEXT( "Status_BroadcastStarted", "Twitch broadcast started. You are now LIVE!" ) ); - - // Get our video buffers ready - This->AvailableVideoBuffers.Reset(); - for( uint32 VideoBufferIndex = 0; VideoBufferIndex < This->TwitchVideoBufferCount; ++VideoBufferIndex ) - { - // Allocate buffer (width * height * bytes per pixel) - This->VideoBuffers[ VideoBufferIndex ] = new uint8[ This->BroadcastConfig.VideoBufferWidth * This->BroadcastConfig.VideoBufferHeight * 4 ]; - This->AvailableVideoBuffers.Add( This->VideoBuffers[ VideoBufferIndex ] ); - } - } - else - { - const FString TwitchErrorString( UTF8_TO_TCHAR( This->TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Failed to start broadcasting to Twitch.\n\nError: %s (%d)"), *TwitchErrorString, (int32)TwitchErrorCode ); - This->PublishStatus( EStatusType::Failure, FText::Format( LOCTEXT( "Status_BroadcastFailed", "Twitch broadcasting failed ({0})" ), FText::FromString( TwitchErrorString ) ) ); - This->BroadcastState = EBroadcastState::BroadcastingFailure; - } - } - }; - - UE_LOG( LogTwitch, Display, TEXT( "Starting Twitch broadcast..." ) ); - PublishStatus( EStatusType::Progress, LOCTEXT( "Status_StartingBroadcast", "Starting broadcast..." ) ); - - BroadcastState = EBroadcastState::WaitingToStartBroadcasting; - const TTV_ErrorCode TwitchErrorCode = TwitchStart( &TwitchVideoParams, &TwitchAudioParams, &SelectedTwitchIngestServer, TwitchStartFlags, TwitchTaskCallback, CallbackUserDataPtr ); - if( !TTV_SUCCEEDED( TwitchErrorCode ) ) - { - const FString TwitchErrorString( UTF8_TO_TCHAR( TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Failed to initiate start of broadcasting to Twitch.\n\nError: %s (%d)"), *TwitchErrorString, (int32)TwitchErrorCode ); - PublishStatus( EStatusType::Failure, FText::Format( LOCTEXT( "Status_BroadcastStartFailed", "Failed to start broadcast ({0})" ), FText::FromString( TwitchErrorString ) ) ); - BroadcastState = EBroadcastState::BroadcastingFailure; - } - } -} - - - -void FTwitchLiveStreaming::Async_StopBroadcasting() -{ - check( BroadcastState == EBroadcastState::Broadcasting ); - - // Called when TwitchStop finishes async work - void* CallbackUserDataPtr = this; - TTV_TaskCallback TwitchTaskCallback = []( TTV_ErrorCode TwitchErrorCode, void* CallbackUserDataPtr ) - { - FTwitchLiveStreaming* This = static_cast( CallbackUserDataPtr ); - - // Make sure we're still in the state that we were expecting - if( This->TwitchState != ETwitchState::Uninitialized && ensure( This->BroadcastState == EBroadcastState::WaitingToStopBroadcasting ) ) - { - if( TTV_SUCCEEDED( TwitchErrorCode ) ) - { - // Broadcasting has stopped. We can start again whenever we want. - UE_LOG( LogTwitch, Display, TEXT( "Twitch broadcast has stopped. We are longer streaming live." ) ); - This->PublishStatus( EStatusType::BroadcastStopped, LOCTEXT( "Status_BroadcastStopped", "Broadcasting has ended." ) ); - This->BroadcastState = EBroadcastState::ReadyToBroadcast; - - // Clean up video buffers - This->AvailableVideoBuffers.Reset(); - for( uint32 VideoBufferIndex = 0; VideoBufferIndex < This->TwitchVideoBufferCount; ++VideoBufferIndex ) - { - delete[] This->VideoBuffers[ VideoBufferIndex ]; - This->VideoBuffers[ VideoBufferIndex ] = nullptr; - } - } - else - { - const FString TwitchErrorString( UTF8_TO_TCHAR( This->TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Failed to stop broadcasting to Twitch.\n\nError: %s (%d)"), *TwitchErrorString, (int32)TwitchErrorCode ); - This->PublishStatus( EStatusType::Failure, FText::Format( LOCTEXT( "Status_BroadcastStopFailed", "Failed while stopping Twitch broadcast ({0})" ), FText::FromString( TwitchErrorString ) ) ); - This->BroadcastState = EBroadcastState::BroadcastingFailure; - } - } - }; - - UE_LOG( LogTwitch, Display, TEXT( "Halting Twitch broadcast..." ) ); - PublishStatus( EStatusType::Progress, LOCTEXT( "Status_StoppingBroadcast", "Stopping Twitch broadcast..." ) ); - - BroadcastState = EBroadcastState::WaitingToStopBroadcasting; - const TTV_ErrorCode TwitchErrorCode = TwitchStop( TwitchTaskCallback, CallbackUserDataPtr ); - if( !TTV_SUCCEEDED( TwitchErrorCode ) ) - { - const FString TwitchErrorString( UTF8_TO_TCHAR( TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Failed to initiative stop of broadcasting to Twitch.\n\nError: %s (%d)"), *TwitchErrorString, (int32)TwitchErrorCode ); - PublishStatus( EStatusType::Failure, FText::Format( LOCTEXT( "Status_BroadcastStopCallFailed", "Error while stopping Twitch broadcast ({0})" ), FText::FromString( TwitchErrorString ) ) ); - BroadcastState = EBroadcastState::BroadcastingFailure; - } -} - - -void FTwitchLiveStreaming::Async_SendVideoFrame( const FColor* VideoFrameBuffer ) -{ - check( BroadcastState == EBroadcastState::Broadcasting ); - - // Called when TwitchStop finishes async work - void* CallbackUserDataPtr = this; - TTV_BufferUnlockCallback TwitchBufferUnlockCallback = []( const uint8_t* Buffer, void* CallbackUserDataPtr ) - { - FTwitchLiveStreaming* This = static_cast( CallbackUserDataPtr ); - - // This buffer has become available to use again! - This->AvailableVideoBuffers.Add( const_cast( Buffer ) ); - }; - - // We should always have an available buffer ready. Twitch guarantees that it never uses more than three at a time. - uint8* TwitchFrameBuffer = AvailableVideoBuffers.Pop(); - - // Fill the buffer - FMemory::Memcpy( TwitchFrameBuffer, VideoFrameBuffer, BroadcastConfig.VideoBufferWidth * BroadcastConfig.VideoBufferHeight * 4 ); - - const TTV_ErrorCode TwitchErrorCode = TwitchSubmitVideoFrame( TwitchFrameBuffer, TwitchBufferUnlockCallback, CallbackUserDataPtr ); - if( !TTV_SUCCEEDED( TwitchErrorCode ) ) - { - // NOTE: Even if sending the buffer fails for some reason, we continue to stream. - // @todo twitch: Any specific error codes for this that we should catch and totally abort the stream? - - // NOTE: This warning is set as 'verbose' because we don't want to kill performance by spamming a transmit error every frame - UE_LOG( LogTwitch, Verbose, TEXT( "Unable to transmit video buffer to Twitch.\n\nError: %s (%d)"), UTF8_TO_TCHAR( TwitchErrorToString( TwitchErrorCode ) ), (int32)TwitchErrorCode ); - } -} - - - -void FTwitchLiveStreaming::PublishStatus( const EStatusType Type, const FText& Text ) -{ - if( OnStatusChangedEvent.IsBound() ) - { - FLiveStreamingStatus NewStatus; - NewStatus.CustomStatusDescription = Text; - NewStatus.StatusType = Type; - - OnStatusChangedEvent.Broadcast( NewStatus ); - } -} - - - -ILiveStreamingService::FOnStatusChanged& FTwitchLiveStreaming::OnStatusChanged() -{ - return OnStatusChangedEvent; -} - - -void FTwitchLiveStreaming::StartBroadcasting( const FBroadcastConfig& Config ) -{ - InitOnDemand(); - - if( !IsBroadcasting() ) - { - bWantsToBroadcastNow = true; - BroadcastConfig = Config; - - // Tick right away to initiate the login - this->Tick( 0.0f ); - } -} - - -void FTwitchLiveStreaming::StopBroadcasting() -{ - InitOnDemand(); - - if( IsBroadcasting() ) - { - bWantsToBroadcastNow = false; - - // Tick right away to halt the broadcast - this->Tick( 0.0f ); - } -} - - -bool FTwitchLiveStreaming::IsBroadcasting() const -{ - return bWantsToBroadcastNow; -} - - -bool FTwitchLiveStreaming::IsReadyForVideoFrames() const -{ - return BroadcastState == EBroadcastState::Broadcasting; -} - - -void FTwitchLiveStreaming::MakeValidVideoBufferResolution( int& VideoBufferWidth, int& VideoBufferHeight ) const -{ - struct Local - { - /** Given a number, rounds the number of to the next specified multiple */ - static int RoundUpToNextMultipleOf( int Value, int Multiple ) - { - int Result = Value; - if( Multiple != 0 ) - { - int Remainder = Value % Multiple; - if( Remainder != 0 ) - { - Result = Value + Multiple - Remainder; - } - } - return Result; - } - }; - - // Twitch requires video buffer width to be a multiple of 32, and video buffer height to be a multiple of 16 - // NOTE: This might affect the aspect ratio of the resolution. The caller will need to compensate. - VideoBufferWidth = Local::RoundUpToNextMultipleOf( VideoBufferWidth, 32 ); - VideoBufferHeight = Local::RoundUpToNextMultipleOf( VideoBufferHeight, 16 ); -} - - -void FTwitchLiveStreaming::QueryBroadcastConfig( FBroadcastConfig& OutBroadcastConfig ) const -{ - if( ensure( IsBroadcasting() ) ) - { - OutBroadcastConfig = BroadcastConfig; - } -} - - -void FTwitchLiveStreaming::PushVideoFrame( const FColor* VideoFrameBuffer ) -{ - if( TwitchState != ETwitchState::Uninitialized && ensure( BroadcastState == EBroadcastState::Broadcasting ) ) - { - Async_SendVideoFrame( VideoFrameBuffer ); - } -} - - -void FTwitchLiveStreaming::StartWebCam( const FWebCamConfig& Config ) -{ - InitOnDemand(); - if( !IsWebCamEnabled() ) - { - bWantsWebCamNow = true; - WebCamConfig = Config; - - // Tick right away to initiate the web cam setup - this->Tick( 0.0f ); - } -} - - -void FTwitchLiveStreaming::StopWebCam() -{ - InitOnDemand(); - if( IsWebCamEnabled() ) - { - bWantsWebCamNow = false; - - // Tick right away to halt the web cam - this->Tick( 0.0f ); - } -} - - -bool FTwitchLiveStreaming::IsWebCamEnabled() const -{ - return bWantsWebCamNow; -} - - -UTexture2D* FTwitchLiveStreaming::GetWebCamTexture( bool& bIsImageFlippedHorizontally, bool& bIsImageFlippedVertically ) -{ - bIsImageFlippedHorizontally = false; // Twitch never flips a web cam image horizontally - bIsImageFlippedVertically = bIsWebCamTextureFlippedVertically; - return WebCamTexture.Get(); -} - - -ILiveStreamingService::FOnChatMessage& FTwitchLiveStreaming::OnChatMessage() -{ - return OnChatMessageEvent; -} - - -void FTwitchLiveStreaming::ConnectToChat() -{ - InitOnDemand(); - if( !IsChatEnabled() ) - { - bWantsChatEnabled = true; - - // Tick right away to initiate the chat connect - this->Tick( 0.0f ); - } -} - - -void FTwitchLiveStreaming::DisconnectFromChat() -{ - InitOnDemand(); - if( IsChatEnabled() ) - { - bWantsChatEnabled = false; - - // Tick right away to halt the chat - this->Tick( 0.0f ); - } -} - - -bool FTwitchLiveStreaming::IsChatEnabled() const -{ - return bWantsChatEnabled; -} - - -void FTwitchLiveStreaming::SendChatMessage( const FString& ChatMessage ) -{ - if( TwitchState != ETwitchState::Uninitialized && ensure( IsChatEnabled() && ChatState == EChatState::Connected ) ) - { - Async_SendChatMessage( ChatMessage ); - } -} - - -void FTwitchLiveStreaming::QueryLiveStreams( const FString& GameName, FQueryLiveStreamsCallback CompletionCallback ) -{ - InitOnDemand(); - - // @todo twitch urgent: Don't we need to be logged in first? Need to do async login as part of this? Or expose a Login API with status events - Async_GetGameLiveStreams( GameName, CompletionCallback ); -} - - - -void FTwitchLiveStreaming::Tick( float DeltaTime ) -{ - if( TwitchState != ETwitchState::NotLoaded && TwitchState != ETwitchState::Uninitialized ) - { - // To be able to broadcast video or chat, we need to get authorization from the Twitch server and complete a successful login - if( bWantsToBroadcastNow || bWantsChatEnabled ) - { - // User wants to be broadcasting. Let's get it going! - if( TwitchState == ETwitchState::ReadyToAuthenticate ) - { - // If we have a user name and password, we can authenticate with Twitch directly. This also requires access to the Twitch - // application's "Client Secret" code. Because of security issues with manual handling of user names and passwords, this - // type of authentication to work, your application's Client ID must first be whitelisted by the Twitch developers. - // @todo twitch: Editor support prompting for username/password if missing? (for direct login support) - if( !ProjectSettings.ClientSecret.IsEmpty() ) - { - Async_AuthenticateWithTwitchDirectly( BroadcastConfig.LoginUserName, BroadcastConfig.LoginPassword, ProjectSettings.ClientSecret ); - } - else - { - if( TwitchLiveStreaming::bUseTwitchSDKForWebBrowserInteraction ) - { - Async_AuthenticateWithTwitchUsingBrowser_UsingTwitchSDK(); - } - else - { - Async_AuthenticateWithTwitchUsingBrowser_Manually(); - } - } - } - else if( !TwitchLiveStreaming::bUseTwitchSDKForWebBrowserInteraction && TwitchState == ETwitchState::WaitingForBrowserBasedAuthentication ) - { - CheckIfBrowserLoginCompleted(); - } - else if( TwitchState == ETwitchState::ReadyToLogin ) - { - Async_LoginToTwitch(); - } - } - - // Are we logged in yet? - if( TwitchState == ETwitchState::LoggedIn ) - { - if( bWantsToBroadcastNow ) - { - if( BroadcastState == EBroadcastState::Idle ) - { - Async_GetIngestServers(); - } - else if( BroadcastState == EBroadcastState::ReadyToBroadcast ) - { - Async_StartBroadcasting(); - } - } - else - { - // User does not want to be broadcasting at this time - if( BroadcastState == EBroadcastState::Broadcasting ) - { - Async_StopBroadcasting(); - } - } - - if( bWantsChatEnabled ) - { - // Startup the chat system if we haven't done that yet - if( ChatState == EChatState::Uninitialized ) - { - Async_InitChatSupport(); - } - else if( ChatState == EChatState::Initialized ) - { - Async_ConnectToChat(); - } - else if( ChatState == EChatState::Connected ) - { - // ... - } - } - else - { - if( ChatState == EChatState::Connected ) - { - Async_DisconnectFromChat(); - } - } - } - - if( bWantsWebCamNow ) - { - // Startup the web cam support if we haven't done that yet - if( WebCamState == EWebCamState::Uninitialized ) - { - Async_InitWebCamSupport(); - } - else if( WebCamState == EWebCamState::Initialized ) - { - // Do we have a device? - if( WebCamDeviceIndex != INDEX_NONE ) - { - Async_StartWebCam(); - } - else - { - // User wants to start a web cam, but we couldn't find one that we support - } - } - else if( WebCamState == EWebCamState::Started ) - { - UpdateWebCamTexture(); - } - } - else - { - if( WebCamState == EWebCamState::Started ) - { - Async_StopWebCam(); - } - } - - - // If we hit a login failure or broadcasting failure, stop waiting to broadcast and wait to be asked again by the caller - if( BroadcastState == EBroadcastState::BroadcastingFailure ) - { - UE_LOG( LogTwitch, Warning, TEXT( "After Twitch broadcasting failure, reverting to non-broadcasting state" ) ); - PublishStatus( EStatusType::BroadcastStopped, LOCTEXT( "Status_BroadcastStoppedUnexpectedly", "Broadcasting has ended unexpectedly." ) ); - BroadcastState = EBroadcastState::Idle; - bWantsToBroadcastNow = false; - } - - if( TwitchState == ETwitchState::LoginFailure ) - { - UE_LOG( LogTwitch, Warning, TEXT( "After Twitch authenticate/login failure, reverting to non-broadcasting, non-authenticated state" ) ); - TwitchState = ETwitchState::ReadyToAuthenticate; - bWantsToBroadcastNow = false; - bWantsChatEnabled = false; - } - - // If the web cam system failed to initialize, we'll just leave it alone - if( WebCamState == EWebCamState::InitFailure ) - { - bWantsWebCamNow = false; - } - else if( WebCamState == EWebCamState::StartOrStopFailure ) - { - UE_LOG( LogTwitch, Warning, TEXT( "After Twitch web cam start or stop failure, reverting to web cam disabled state" ) ); - if( WebCamState == EWebCamState::Started ) - { - PublishStatus( EStatusType::WebCamStopped, LOCTEXT( "Status_WebCamStoppedUnexpectedly", "Web cam stopped unexpectedly" ) ); - } - WebCamState = EWebCamState::Initialized; - bWantsWebCamNow = false; - } - - - // If the chat system failed to initialize, we'll just leave it alone - if( ChatState == EChatState::InitFailure ) - { - bWantsChatEnabled = false; - } - else if( ChatState == EChatState::ConnectOrDisconnectFailure ) - { - UE_LOG( LogTwitch, Warning, TEXT( "After Twitch chat connection or disconnection failure, reverting chat to disabled state" ) ); - if( ChatState == EChatState::Connected ) - { - PublishStatus( EStatusType::ChatDisconnected, LOCTEXT( "Status_ChatStoppedUnexpectedly", "Chat stopped unexpectedly" ) ); - } - ChatState = EChatState::Initialized; - bWantsChatEnabled = false; - } - - - // Allow the Twitch SDK to process any callbacks that are pending - TwitchPollTasks(); - - // Process Twitch web cam events and fire off callbacks - TwitchWebCamFlushEvents(); - - // Process Twitch chat system events - TwitchChatFlushEvents(); - } -} - - -bool FTwitchLiveStreaming::IsTickable() const -{ - // Only tickable when properly initialized - return ( TwitchState != ETwitchState::NotLoaded && TwitchState != ETwitchState::Uninitialized ); -} - - -TStatId FTwitchLiveStreaming::GetStatId() const -{ - RETURN_QUICK_DECLARE_CYCLE_STAT( FTwitchLiveStreaming, STATGROUP_Tickables ); -} - - -bool FTwitchLiveStreaming::IsTickableWhenPaused() const -{ - // Always ticked, even when the game is suspended - return true; -} - - -bool FTwitchLiveStreaming::IsTickableInEditor() const -{ - // Always ticked, even in the editor - return true; -} - - -void FTwitchLiveStreaming::Async_InitWebCamSupport() -{ - check( WebCamState == EWebCamState::Uninitialized ); - - void* CallbackUserDataPtr = this; - - // Called when TwitchWebCamInit finishes async work - TTV_WebCamInitializationCallback TwitchWebCamInitializationCallback = []( TTV_ErrorCode TwitchErrorCode, void* CallbackUserDataPtr ) - { - FTwitchLiveStreaming* This = static_cast( CallbackUserDataPtr ); - - // Make sure we're still in the state that we were expecting - if( This->TwitchState != ETwitchState::Uninitialized && ensure( This->WebCamState == EWebCamState::WaitingForInit ) ) - { - if( TTV_SUCCEEDED( TwitchErrorCode ) ) - { - // Web cam system is ready - UE_LOG( LogTwitch, Display, TEXT( "Twitch web cam support is initialized") ); - - This->WebCamState = EWebCamState::Initialized; - } - else - { - const FString TwitchErrorString( UTF8_TO_TCHAR( This->TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Failed to init Twitch web cam support.\n\nError: %s (%d)"), *TwitchErrorString, (int32)TwitchErrorCode ); - This->WebCamState = EWebCamState::InitFailure; - } - } - }; - - // Called when a web camera is added or removed - TTV_WebCamDeviceChangeCallback TwitchWebCamDeviceChangeCallback = []( TTV_WebCamDeviceChange Change, const TTV_WebCamDevice* Device, TTV_ErrorCode TwitchErrorCode, void* CallbackUserDataPtr ) - { - FTwitchLiveStreaming* This = static_cast( CallbackUserDataPtr ); - - // This callback could come in at pretty much any time - if( This->TwitchState != ETwitchState::Uninitialized && ensure( This->WebCamState != EWebCamState::Uninitialized && This->WebCamState != EWebCamState::WaitingForInit ) ) - { - if( TTV_SUCCEEDED( TwitchErrorCode ) ) - { - // @todo twitch: Warn when no devices are connected at all and users decides they want web cam? (Or have API to determine whether camera is available) - if( Change == TTV_WEBCAM_DEVICE_FOUND ) - { - UE_LOG( LogTwitch, Display, TEXT( "Twitch detected a new web cam: %s"), UTF8_TO_TCHAR( Device->name ) ); - - // If we don't have a web cam yet, we'll use the first one we find - // @todo twitch: For now, we're just choosing the first web cam that we find that supports a format we like - if( This->WebCamDeviceIndex == INDEX_NONE ) - { - This->WebCamCapabilityIndex = INDEX_NONE; - // @todo twitch: Not possible to change web cam resolutions after we've inited (even with different params to StartBroadcast), because we never re-enumerate these after initial Init - const int DesiredPixels = This->WebCamConfig.DesiredWebCamWidth * This->WebCamConfig.DesiredWebCamHeight; - const float DesiredAspect = (float)This->WebCamConfig.DesiredWebCamWidth / (float)This->WebCamConfig.DesiredWebCamHeight; - - int BestCapabilitySoFar = INDEX_NONE; - int BestCapabilityPixelDiff = 10000000; - float BestCapabilityAspectDiff = 100000.0f; - for( uint32 CapabilityIndex = 0; CapabilityIndex < Device->capabilityList.count; ++CapabilityIndex ) - { - const auto& Capability = Device->capabilityList.list[ CapabilityIndex ]; - - // @todo twitch: Currently we required ARGB32 formats. We could support others though. - if( Capability.format == TTV_WEBCAM_FORMAT_ARGB32 ) - { - const int ThisCapabilityPixels = Capability.resolution.width * Capability.resolution.height; - const float ThisCapabilityAspect = (float)Capability.resolution.width / (float)Capability.resolution.height; - - const float MaxPixelsVariance = 200 * 200.0f; - const float MaxAspectVariance = 0.3f; - - const int PixelsDiff = FMath::Abs( ThisCapabilityPixels - DesiredPixels ); - const float AspectDiff = FMath::Abs( ThisCapabilityAspect - DesiredAspect ); - if( BestCapabilitySoFar == INDEX_NONE || - - // Clearly better - ( PixelsDiff < BestCapabilityPixelDiff && - AspectDiff < BestCapabilityAspectDiff ) || - - // Sort of better. Closer to desired resolution, but aspect is worse - ( PixelsDiff < BestCapabilityPixelDiff && - AspectDiff < ( BestCapabilityAspectDiff + MaxAspectVariance / 2.0f ) ) || - - // Sort of better. Closer to desired aspect, but resolution is worse - ( PixelsDiff < ( BestCapabilityPixelDiff + MaxPixelsVariance / 2 ) && - AspectDiff < BestCapabilityAspectDiff ) ) - { - // Best one so far - BestCapabilitySoFar = CapabilityIndex; - BestCapabilityPixelDiff = PixelsDiff; - BestCapabilityAspectDiff = AspectDiff; - } - } - } - - if( BestCapabilitySoFar != INDEX_NONE ) - { - const auto& Capability = Device->capabilityList.list[ BestCapabilitySoFar ]; - - // OK, we found a format that works - This->WebCamDeviceIndex = Device->deviceIndex; - This->WebCamCapabilityIndex = Capability.capabilityIndex; - This->WebCamVideoBufferWidth = Capability.resolution.width; - This->WebCamVideoBufferHeight = Capability.resolution.height; - This->bIsWebCamTextureFlippedVertically = !Capability.isTopToBottom; - } - else - { - UE_LOG( LogTwitch, Warning, TEXT( "Web cam device '%s' did not have any formats that we could support"), UTF8_TO_TCHAR( Device->name ) ); - } - } - } - else if( Change == TTV_WEBCAM_DEVICE_LOST ) - { - // Are we already streaming a camera feed? - if( This->WebCamDeviceIndex != INDEX_NONE ) - { - // If this was the camera we were streaming with, then we need to unhook everything - if( (uint32)Device->deviceIndex == This->WebCamDeviceIndex ) - { - // No longer able to stream this web cam - This->WebCamDeviceIndex = INDEX_NONE; - - if( This->WebCamState == EWebCamState::Started ) - { - UE_LOG( LogTwitch, Display, TEXT( "Stopped web cam '%s' because device was unplugged" ), UTF8_TO_TCHAR( Device->name ) ); - This->PublishStatus( EStatusType::WebCamStopped, LOCTEXT( "Status_WebCamUnplugged", "Web cam was unplugged" ) ); - - This->WebCamState = EWebCamState::Initialized; - - // Release our texture so it won't be used for rendering anymore - const bool bReleaseResourceToo = false; - This->ReleaseWebCamTexture( bReleaseResourceToo ); - } - } - } - - UE_LOG( LogTwitch, Display, TEXT( "Twitch detected a web cam was disconnected: %s"), UTF8_TO_TCHAR( Device->name ) ); - } - } - else - { - const FString TwitchErrorString( UTF8_TO_TCHAR( This->TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Received an error from Twitch with a web cam device add/remove callback.\n\nError: %s (%d)"), *TwitchErrorString, (int32)TwitchErrorCode ); - - // NOTE: We don't bother failing the whole system for an error like this - } - } - }; - - UE_LOG( LogTwitch, Display, TEXT( "Initializing Twitch web cam support...") ); - - TTV_WebCamCallbacks TwitchWebCamCallbacks; - TwitchWebCamCallbacks.deviceChangeCallback = TwitchWebCamDeviceChangeCallback; - TwitchWebCamCallbacks.deviceChangeUserData = CallbackUserDataPtr; - - WebCamState = EWebCamState::WaitingForInit; - const TTV_ErrorCode TwitchErrorCode = TwitchWebCamInit( &TwitchWebCamCallbacks, TwitchWebCamInitializationCallback, CallbackUserDataPtr ); - if( !TTV_SUCCEEDED( TwitchErrorCode ) ) - { - const FString TwitchErrorString( UTF8_TO_TCHAR( TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Failed to start initialization of Twitch web cam support.\n\nError: %s (%d)"), *TwitchErrorString, (int32)TwitchErrorCode ); - WebCamState = EWebCamState::InitFailure; - } -} - - -void FTwitchLiveStreaming::Async_StartWebCam() -{ - check( WebCamState == EWebCamState::Initialized ); - check( WebCamDeviceIndex != INDEX_NONE && WebCamCapabilityIndex != INDEX_NONE ); - - void* CallbackUserDataPtr = this; - - // @todo twitch: Starting the web cam doesn't seem to automatically start capturing from the default microphone, unless you turn on "What U Hear" in Windows. - - // Called when TwitchWebCamStart finishes async work - TTV_WebCamDeviceStatusCallback TwitchWebCamStatusCallback = []( const TTV_WebCamDevice* Device, const TTV_WebCamDeviceCapability* Capability, TTV_ErrorCode TwitchErrorCode, void* CallbackUserDataPtr ) - { - FTwitchLiveStreaming* This = static_cast( CallbackUserDataPtr ); - - // Make sure we're still in the state that we were expecting - if( This->TwitchState != ETwitchState::Uninitialized && ensure( This->WebCamState == EWebCamState::WaitingForStart ) ) - { - if( TTV_SUCCEEDED( TwitchErrorCode ) ) - { - UE_LOG( LogTwitch, Display, TEXT( "Started recording using web cam '%s' at %i x %i"), UTF8_TO_TCHAR( Device->name ), Capability->resolution.width, Capability->resolution.height ); - This->PublishStatus( EStatusType::WebCamStarted, LOCTEXT( "Status_WebCamStarted", "Web cam enabled" ) ); - - This->WebCamState = EWebCamState::Started; - } - else - { - const FString TwitchErrorString( UTF8_TO_TCHAR( This->TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Failed to start recording with web cam.\n\nError: %s (%d)"), *TwitchErrorString, (int32)TwitchErrorCode ); - This->WebCamState = EWebCamState::StartOrStopFailure; - } - } - }; - - - UE_LOG( LogTwitch, Display, TEXT( "Starting web cam...") ); - - WebCamState = EWebCamState::WaitingForStart; - const TTV_ErrorCode TwitchErrorCode = TwitchWebCamStart( WebCamDeviceIndex, WebCamCapabilityIndex, TwitchWebCamStatusCallback, CallbackUserDataPtr ); - if( !TTV_SUCCEEDED( TwitchErrorCode ) ) - { - const FString TwitchErrorString( UTF8_TO_TCHAR( TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Failed to begin starting up web camera.\n\nError: %s (%d)"), *TwitchErrorString, (int32)TwitchErrorCode ); - WebCamState = EWebCamState::StartOrStopFailure; - } -} - - -void FTwitchLiveStreaming::Async_StopWebCam() -{ - check( WebCamState == EWebCamState::Started ); - - void* CallbackUserDataPtr = this; - - // Called when TwitchWebCamStop finishes async work - TTV_WebCamDeviceStatusCallback TwitchWebCamStatusCallback = []( const TTV_WebCamDevice* Device, const TTV_WebCamDeviceCapability* Capability, TTV_ErrorCode TwitchErrorCode, void* CallbackUserDataPtr ) - { - FTwitchLiveStreaming* This = static_cast( CallbackUserDataPtr ); - - // Make sure we're still in the state that we were expecting - if( This->TwitchState != ETwitchState::Uninitialized && ensure( This->WebCamState == EWebCamState::WaitingForStop ) ) - { - if( TTV_SUCCEEDED( TwitchErrorCode ) ) - { - UE_LOG( LogTwitch, Display, TEXT( "Stopped web cam '%s'"), UTF8_TO_TCHAR( Device->name ) ); - This->PublishStatus( EStatusType::WebCamStopped, LOCTEXT( "Status_WebCamStopped", "Web cam is now off" ) ); - - This->WebCamState = EWebCamState::Initialized; - - // Release our texture so it won't be used for rendering anymore - const bool bReleaseResourceToo = false; - This->ReleaseWebCamTexture( bReleaseResourceToo ); - } - else - { - const FString TwitchErrorString( UTF8_TO_TCHAR( This->TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Failed to stop recording with web cam.\n\nError: %s (%d)"), *TwitchErrorString, (int32)TwitchErrorCode ); - This->WebCamState = EWebCamState::StartOrStopFailure; - } - } - }; - - - UE_LOG( LogTwitch, Display, TEXT( "Stopping web cam...") ); - - WebCamState = EWebCamState::WaitingForStop; - const TTV_ErrorCode TwitchErrorCode = TwitchWebCamStop( WebCamDeviceIndex, TwitchWebCamStatusCallback, CallbackUserDataPtr ); - if( !TTV_SUCCEEDED( TwitchErrorCode ) ) - { - const FString TwitchErrorString( UTF8_TO_TCHAR( TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Failed to begin stopping web camera.\n\nError: %s (%d)"), *TwitchErrorString, (int32)TwitchErrorCode ); - WebCamState = EWebCamState::StartOrStopFailure; - } -} - - -void FTwitchLiveStreaming::UpdateWebCamTexture() -{ - check( WebCamState == EWebCamState::Started ); - - // Do we have a new texture available? - bool bIsFrameAvailable = false; - { - const TTV_ErrorCode TwitchErrorCode = TwitchWebCamIsFrameAvailable( WebCamDeviceIndex, &bIsFrameAvailable ); - if( !TTV_SUCCEEDED( TwitchErrorCode ) ) - { - const FString TwitchErrorString( UTF8_TO_TCHAR( TwitchErrorToString( TwitchErrorCode ) ) ); - - UE_LOG( LogTwitch, Verbose, TEXT( "Error while checking to see if new frame from web camera is available.\n\nError: %s (%d)"), *TwitchErrorString, (int32)TwitchErrorCode ); - } - } - - bool bWasWebCamTextureCreated = false; - if( bIsFrameAvailable ) - { - const uint32 WebCamBufferPitch = WebCamVideoBufferWidth * 4; // 4 bytes per pixel - - // This will be passed off to the render thread, which will delete it when it has finished with it - // @todo twitch: This is a bit heavy to keep reallocating/deallocating, but not a big deal. Maybe we can ping pong between buffers instead. - uint8* WebCamBuffer = new uint8[ WebCamBufferPitch * WebCamVideoBufferHeight ]; - - // Get a copy of the web cam frame data from Twitch - const TTV_ErrorCode TwitchErrorCode = TwitchWebCamGetFrame( WebCamDeviceIndex, WebCamBuffer, WebCamBufferPitch ); - if( TTV_SUCCEEDED( TwitchErrorCode ) ) - { - // @todo twitch: If texture format changes, we'd need to re-create it too. Currently we don't support other formats though. - if( !WebCamTexture.IsValid() || WebCamVideoBufferWidth != WebCamTexture->GetSurfaceWidth() || WebCamVideoBufferHeight != WebCamTexture->GetSurfaceHeight() ) - { - // Texture has not been created yet, or desired size has changed - const bool bReleaseResourceToo = true; - ReleaseWebCamTexture( bReleaseResourceToo ); - - // NOTE: We're not really using this texture as a render target, as we map the resource and upload bits to the texture - // from system memory directly. We never actually bind it as a render target. However, this is the best API we have for - // dealing with textures like this. - UTexture2D* NewWebCamTexture = UTexture2D::CreateTransient( WebCamVideoBufferWidth, WebCamVideoBufferHeight, PF_B8G8R8A8 ); - - // Add the texture to the root set so that it doesn't get garbage collected. We'll remove it from the root set ourselves when we're done with it. - NewWebCamTexture->AddToRoot(); - - NewWebCamTexture->AddressX = TA_Clamp; - NewWebCamTexture->AddressY = TA_Clamp; - NewWebCamTexture->bIsStreamable = false; - NewWebCamTexture->CompressionSettings = TC_Default; - NewWebCamTexture->Filter = TF_Bilinear; - NewWebCamTexture->LODGroup = TEXTUREGROUP_UI; - NewWebCamTexture->NeverStream = true; - NewWebCamTexture->SRGB = true; - - NewWebCamTexture->UpdateResource(); - - WebCamTexture = NewWebCamTexture; - bWasWebCamTextureCreated = true; - } - - struct FUploadWebCamTextureContext - { - uint8* WebCamBuffer; // Render thread assumes ownership - uint32 WebCamBufferPitch; - FTexture2DResource* DestTextureResource; - } UploadWebCamTextureContext = - { - WebCamBuffer, - WebCamBufferPitch, - (FTexture2DResource*)WebCamTexture->Resource - }; - - ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER( - UploadWebCamTexture, - FUploadWebCamTextureContext,Context,UploadWebCamTextureContext, - { - const FUpdateTextureRegion2D UpdateRegion( - 0, 0, // Dest X, Y - 0, 0, // Source X, Y - Context.DestTextureResource->GetSizeX(), // Width - Context.DestTextureResource->GetSizeY() ); // Height - - RHIUpdateTexture2D( - Context.DestTextureResource->GetTexture2DRHI(), // Destination GPU texture - 0, // Mip map index - UpdateRegion, // Update region - Context.WebCamBufferPitch, // Source buffer pitch - Context.WebCamBuffer ); // Source buffer pointer - - // Delete the buffer now that we've uploaded the bytes - delete[] Context.WebCamBuffer; - }); - } - else - { - const FString TwitchErrorString( UTF8_TO_TCHAR( TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Verbose, TEXT( "Error while requesting web cam frame buffer.\n\nError: %s (%d)"), *TwitchErrorString, (int32)TwitchErrorCode ); - } - } - - if( bWasWebCamTextureCreated ) - { - PublishStatus( EStatusType::WebCamTextureReady, LOCTEXT( "Status_WebCamTextureReady", "Web cam video enabled" ) ); - } -} - - -void FTwitchLiveStreaming::ReleaseWebCamTexture( const bool bReleaseResourceToo ) -{ - if( WebCamTexture.IsValid() ) - { - // Release the web cam texture - if( bReleaseResourceToo ) - { - WebCamTexture->ReleaseResource(); - } - WebCamTexture->RemoveFromRoot(); - WebCamTexture = nullptr; - - bIsWebCamTextureFlippedVertically = false; - - PublishStatus( EStatusType::WebCamTextureNotReady, LOCTEXT( "Status_WebCamTextureNotReady", "Web cam video disabled" ) ); - } -} - - -void FTwitchLiveStreaming::Async_InitChatSupport() -{ - check( ChatState == EChatState::Uninitialized ); - - void* CallbackUserDataPtr = this; - - // Called when TwitchChatInit finishes async work - TTV_ChatInitializationCallback TwitchChatInitializationCallback = []( TTV_ErrorCode TwitchErrorCode, void* CallbackUserDataPtr ) - { - FTwitchLiveStreaming* This = static_cast( CallbackUserDataPtr ); - - // Make sure we're still in the state that we were expecting - if( This->TwitchState != ETwitchState::Uninitialized && ensure( This->ChatState == EChatState::WaitingForInit ) ) - { - if( TTV_SUCCEEDED( TwitchErrorCode ) ) - { - // Chat system is ready - UE_LOG( LogTwitch, Display, TEXT( "Twitch chat support is initialized") ); - - This->ChatState = EChatState::Initialized; - } - else - { - const FString TwitchErrorString( UTF8_TO_TCHAR( This->TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Failed to init Twitch chat support.\n\nError: %s (%d)"), *TwitchErrorString, (int32)TwitchErrorCode ); - This->ChatState = EChatState::InitFailure; - } - } - }; - - - UE_LOG( LogTwitch, Display, TEXT( "Initializing Twitch chat support...") ); - - // @todo twitch: Could eventually add support for handling emoticons here, and badges - const TTV_ChatTokenizationOption TwitchChatTokenizationOption = TTV_CHAT_TOKENIZATION_OPTION_NONE; - - ChatState = EChatState::WaitingForInit; - const TTV_ErrorCode TwitchErrorCode = TwitchChatInit( TwitchChatTokenizationOption, TwitchChatInitializationCallback, CallbackUserDataPtr ); - if( !TTV_SUCCEEDED( TwitchErrorCode ) ) - { - const FString TwitchErrorString( UTF8_TO_TCHAR( TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Failed to start initialization of Twitch chat support.\n\nError: %s (%d)"), *TwitchErrorString, (int32)TwitchErrorCode ); - ChatState = EChatState::InitFailure; - } -} - - - -void FTwitchLiveStreaming::Async_ConnectToChat() -{ - check( TwitchState == ETwitchState::LoggedIn ); - check( ChatState == EChatState::Initialized ); - - void* CallbackUserDataPtr = this; - - // Called when Twitch chat connection succeeds, or when the user becomes disconnected - TTV_ChatStatusCallback TwitchChatStatusCallback = []( TTV_ErrorCode TwitchErrorCode, void* CallbackUserDataPtr ) - { - FTwitchLiveStreaming* This = static_cast( CallbackUserDataPtr ); - - // Make sure we're still in the state that we were expecting - if( This->ChatState == EChatState::WaitingToConnect ) - { - if( TTV_SUCCEEDED( TwitchErrorCode ) ) - { - // Connected to chat! - UE_LOG( LogTwitch, Display, TEXT( "Connected to chat!" ) ); - This->PublishStatus( EStatusType::ChatConnected, LOCTEXT( "Status_ChatConnected", "Connected to chat server" ) ); - This->ChatState = EChatState::Connected; - } - else - { - const FString TwitchErrorString( UTF8_TO_TCHAR( This->TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Failed to connect to Twitch chat.\n\nError: %s (%d)" ), *TwitchErrorString, (int32)TwitchErrorCode ); - This->ChatState = EChatState::ConnectOrDisconnectFailure; - } - } - else if( This->ChatState == EChatState::WaitingForDisconnect ) - { - if( TTV_SUCCEEDED( TwitchErrorCode ) ) - { - // Disconnected from chat! - UE_LOG( LogTwitch, Display, TEXT( "Disconnected from chat" ) ); - This->PublishStatus( EStatusType::ChatDisconnected, LOCTEXT( "Status_ChatDisconnected", "Disconnected from chat server" ) ); - This->ChatState = EChatState::Initialized; - } - else - { - const FString TwitchErrorString( UTF8_TO_TCHAR( This->TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Failed to disconnect from Twitch chat.\n\nError: %s (%d)" ), *TwitchErrorString, (int32)TwitchErrorCode ); - This->ChatState = EChatState::ConnectOrDisconnectFailure; - } - } - else - { - const FString TwitchErrorString( UTF8_TO_TCHAR( This->TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Received a chat status message at a time that we were not expected.\n\nError code: %s (%d)" ), *TwitchErrorString, (int32)TwitchErrorCode ); - } - - }; - - TTV_ChatChannelMembershipCallback TwitchChatChannelMembershipCallback = []( TTV_ChatEvent Event, const TTV_ChatChannelInfo* ChannelInfo, void* CallbackUserDataPtr ) - { - FTwitchLiveStreaming* This = static_cast( CallbackUserDataPtr ); - - // @todo twitch: Add chat callbacks for pushing information about the channel back to the game - }; - - TTV_ChatChannelUserChangeCallback TwitchChatChannelUserChangeCallback = []( const TTV_ChatUserList* JoinList, const TTV_ChatUserList* LeaveList, const TTV_ChatUserList* InfoChangeList, void* CallbackUserDataPtr ) - { - FTwitchLiveStreaming* This = static_cast( CallbackUserDataPtr ); - - // @todo twitch: Add chat events for users joining/leaving the channel - }; - - TTV_ChatChannelMessageCallback TwitchChatChannelMessageCallback = []( const TTV_ChatRawMessageList* MessageList, void* CallbackUserDataPtr ) - { - FTwitchLiveStreaming* This = static_cast( CallbackUserDataPtr ); - - // We received a chat message. Let's route it to anyone who is listening! - if( This->OnChatMessageEvent.IsBound() ) - { - for( uint32 MessageIndex = 0; MessageIndex < MessageList->messageCount; ++MessageIndex ) - { - const auto& TwitchMessage = MessageList->messageList[ MessageIndex ]; - - // @todo twitch: Make use of the other settings in this TTV_ChatRawMessage struct, such as the user name's color and whether - // the message is an action - const FText UserNameText( FText::FromString( UTF8_TO_TCHAR( TwitchMessage.userName ) ) ); - const FText MessageText( FText::FromString( UTF8_TO_TCHAR( TwitchMessage.message ) ) ); - - This->OnChatMessageEvent.Broadcast( UserNameText, MessageText ); - } - } - }; - - TTV_ChatChannelTokenizedMessageCallback TwitchChatChannelTokenizedMessageCallback = []( const TTV_ChatTokenizedMessageList* MessageList, void* CallbackUserDataPtr ) - { - // NOTE: Not currently expecting to ever receive this event, because we connect with the TTV_CHAT_TOKENIZATION_OPTION_NONE option - check( 0 ); - }; - - UE_LOG( LogTwitch, Display, TEXT( "Connecting to chat..." ) ); - - const utf8char* TwitchChatUsername = "testing"; // @todo twitch urgent (need GetUserInfo() implemented? Or allow user to supply chat name) - - // We'll authorize chat using the same token we received after logging into Twitch - const char* TwitchChatAuthToken = TwitchAuthToken.data; - check( TwitchChatAuthToken != nullptr ); - - TTV_ChatCallbacks TwitchChatCallbacks; - TwitchChatCallbacks.statusCallback = TwitchChatStatusCallback; // The callback to call for connection and disconnection events from the chat service. Cannot be NULL. - TwitchChatCallbacks.membershipCallback = TwitchChatChannelMembershipCallback; // The callback to call when the local user joins or leaves a channel. Cannot be NULL. - TwitchChatCallbacks.userCallback = TwitchChatChannelUserChangeCallback; // The callback to call when other users join or leave a channel. This may be NULL. - TwitchChatCallbacks.messageCallback = TwitchChatChannelMessageCallback; // The callback to call when raw messages are received on a channel. - TwitchChatCallbacks.tokenizedMessageCallback = TwitchChatChannelTokenizedMessageCallback; // The callback to call when tokenized messages are received on a channel. - TwitchChatCallbacks.clearCallback = nullptr; // The callback to call when the chatroom should be cleared. Can be NULL. - TwitchChatCallbacks.unsolicitedUserData = CallbackUserDataPtr; // The userdata to pass in the callbacks. - - - ChatState = EChatState::WaitingToConnect; - const TTV_ErrorCode TwitchErrorCode = TwitchChatConnect( TwitchChatUsername, TwitchChatAuthToken, &TwitchChatCallbacks ); - if( !TTV_SUCCEEDED( TwitchErrorCode ) ) - { - const FString TwitchErrorString( UTF8_TO_TCHAR( TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Failed to begin connecting to chat.\n\nError: %s (%d)" ), *TwitchErrorString, (int32)TwitchErrorCode ); - ChatState = EChatState::ConnectOrDisconnectFailure; - } -} - - -void FTwitchLiveStreaming::Async_DisconnectFromChat() -{ - check( ChatState == EChatState::Connected ); - - UE_LOG( LogTwitch, Display, TEXT( "Disconnecting from chat..." ) ); - - ChatState = EChatState::WaitingForDisconnect; - const TTV_ErrorCode TwitchErrorCode = TwitchChatDisconnect(); - if( !TTV_SUCCEEDED( TwitchErrorCode ) ) - { - const FString TwitchErrorString( UTF8_TO_TCHAR( TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Failed to begin disconnecting from chat.\n\nError: %s (%d)" ), *TwitchErrorString, (int32)TwitchErrorCode ); - ChatState = EChatState::ConnectOrDisconnectFailure; - } -} - - -void FTwitchLiveStreaming::Async_SendChatMessage( const FString& ChatMessage ) -{ - check( ChatState == EChatState::Connected ); - - UE_LOG( LogTwitch, Display, TEXT( "Sending chat message: %s" ), *ChatMessage ); - - // NOTE: There is no callback when the message is received - const TTV_ErrorCode TwitchErrorCode = TwitchChatSendMessage( TCHAR_TO_UTF8( *ChatMessage ) ); - if( !TTV_SUCCEEDED( TwitchErrorCode ) ) - { - const FString TwitchErrorString( UTF8_TO_TCHAR( TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Failed to send chat message to Twitch.\n\nError: %s (%d)" ), *TwitchErrorString, (int32)TwitchErrorCode ); - } -} - - -void FTwitchLiveStreaming::Async_GetGameLiveStreams( const FString& GameName, FQueryLiveStreamsCallback CompletionCallback ) -{ - struct FCallbackPayload - { - FTwitchLiveStreaming* This; - - /** Name of the game we're querying streams for */ - FString GameName; - - /** List of game streams queried from TwitchGetGameLiveStreams */ - TTV_LiveGameStreamList TwitchGameStreamList; - - /** Callback to run when we're done */ - FQueryLiveStreamsCallback CompletionCallback; - }; - - auto* CallbackPayload = new FCallbackPayload(); // This will be deleted by the async callback function below - CallbackPayload->This = this; - CallbackPayload->GameName = GameName; - FMemory::Memzero( CallbackPayload->TwitchGameStreamList ); - CallbackPayload->CompletionCallback = CompletionCallback; - - void* CallbackUserDataPtr = CallbackPayload; - - // Called when TwitchGetGameLiveStreams finishes async work - TTV_TaskCallback TwitchTaskCallback = []( TTV_ErrorCode TwitchErrorCode, void* CallbackUserDataPtr ) - { - FCallbackPayload* CallbackPayload = static_cast( CallbackUserDataPtr ); - FTwitchLiveStreaming* This = CallbackPayload->This; - - bool bQueryWasSuccessful = true; - if( TTV_SUCCEEDED( TwitchErrorCode ) ) - { - UE_LOG( LogTwitch, Display, TEXT( "Successfully queried live game stream list" ) ); - } - else - { - bQueryWasSuccessful = false; - const FString TwitchErrorString( UTF8_TO_TCHAR( This->TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Failed to query game live streams.\n\nError: %s (%d)" ), *TwitchErrorString, (int32)TwitchErrorCode ); - } - - // Build up an Unreal-friendly list of streams - TArray< FLiveStreamInfo > ListOfStreams; - for( uint32 InfoIndex = 0; InfoIndex < CallbackPayload->TwitchGameStreamList.count; ++InfoIndex ) - { - const auto& TwitchLiveGameStreamInfo = CallbackPayload->TwitchGameStreamList.list[ InfoIndex ]; - - FLiveStreamInfo StreamInfo; - StreamInfo.GameName = CallbackPayload->GameName; - StreamInfo.StreamName = TwitchLiveGameStreamInfo.streamTitle; // @todo twitch: Also include TwitchLiveGameStreamInfo.channelDisplayName? - StreamInfo.URL = TwitchLiveGameStreamInfo.channelUrl; - ListOfStreams.Add( StreamInfo ); - } - - // Free the list of game streams that Twitch allocated - if( CallbackPayload->TwitchGameStreamList.list != nullptr ) - { - This->TwitchFreeGameLiveStreamList( &CallbackPayload->TwitchGameStreamList ); - } - - // Run the user's callback! - CallbackPayload->CompletionCallback.ExecuteIfBound( ListOfStreams, bQueryWasSuccessful ); - - // Delete the callback payload now that we're done with it - delete CallbackPayload; - }; - - - UE_LOG( LogTwitch, Display, TEXT( "Querying game live streams for '%s'..." ), *GameName ); - - const TTV_ErrorCode TwitchErrorCode = TwitchGetGameLiveStreams( TCHAR_TO_ANSI( *GameName ), TwitchTaskCallback, CallbackUserDataPtr, &CallbackPayload->TwitchGameStreamList ); - if( !TTV_SUCCEEDED( TwitchErrorCode ) ) - { - const FString TwitchErrorString( UTF8_TO_TCHAR( TwitchErrorToString( TwitchErrorCode ) ) ); - UE_LOG( LogTwitch, Warning, TEXT( "Failed to start querying game live streams.\n\nError: %s (%d)" ), *TwitchErrorString, (int32)TwitchErrorCode ); - - // Run the user's callback, but report a failure message - const TArray< FLiveStreamInfo > EmptyListOfStreams; - const bool bQueryWasSuccessful = false; - CompletionCallback.ExecuteIfBound( EmptyListOfStreams, bQueryWasSuccessful ); - } -} - - -#undef LOCTEXT_NAMESPACE - -#else // WITH_TWITCH - -class FTwitchLiveStreaming_NoTwitchSDK : public IModuleInterface -{ -public: - - /** IModuleInterface implementation */ - virtual void StartupModule() override - { - UE_LOG( LogTwitch, Verbose, TEXT( "TwitchLiveStreaming plugin was built without Twitch SDK. Twitch features will not be available." ) ); - } -}; - -IMPLEMENT_MODULE( FTwitchLiveStreaming_NoTwitchSDK, TwitchLiveStreaming ) - -#endif diff --git a/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/TwitchLiveStreaming/TwitchLiveStreaming.h b/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/TwitchLiveStreaming/TwitchLiveStreaming.h deleted file mode 100644 index e172a3802ff1..000000000000 --- a/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/TwitchLiveStreaming/TwitchLiveStreaming.h +++ /dev/null @@ -1,424 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#pragma once - -#include "CoreMinimal.h" -#include "ITwitchLiveStreaming.h" -#include "Runtime/Engine/Public/Features/ILiveStreamingService.h" -#include "Runtime/Engine/Public/Tickable.h" -#include "UObject/WeakObjectPtr.h" - -#if WITH_TWITCH - -THIRD_PARTY_INCLUDES_START - // Twitch SDK includes - #include "twitchsdk.h" - #include "twitchwebcam.h" - #include "twitchchat.h" -THIRD_PARTY_INCLUDES_END - - -/** - * Twitch live streaming implementation - */ -class FTwitchLiveStreaming : public ITwitchLiveStreaming, public ILiveStreamingService, public FTickableGameObject -{ -public: - - /** IModuleInterface implementation */ - virtual void StartupModule() override; - virtual void ShutdownModule() override; - - /** ILiveStreamingService implementation */ - virtual FOnStatusChanged& OnStatusChanged() override; - virtual void StartBroadcasting( const FBroadcastConfig& Config ) override; - virtual void StopBroadcasting() override; - virtual bool IsBroadcasting() const override; - virtual bool IsReadyForVideoFrames() const override; - virtual void MakeValidVideoBufferResolution( int& VideoBufferWidth, int& VideoBufferHeight ) const override; - virtual void QueryBroadcastConfig( FBroadcastConfig& OutBroadcastConfig ) const override; - virtual void PushVideoFrame( const FColor* VideoFrameBuffer ) override; - virtual void StartWebCam( const FWebCamConfig& Config ) override; - virtual void StopWebCam() override; - virtual bool IsWebCamEnabled() const override; - virtual UTexture2D* GetWebCamTexture( bool& bIsImageFlippedHorizontally, bool& bIsImageFlippedVertically ) override; - virtual FOnChatMessage& OnChatMessage() override; - virtual void ConnectToChat() override; - virtual void DisconnectFromChat() override; - virtual bool IsChatEnabled() const override; - virtual void SendChatMessage( const FString& ChatMessage ) override; - virtual void QueryLiveStreams( const FString& GameName, FQueryLiveStreamsCallback CompletionCallback ) override; - -private: - - /** Initializes Twitch lazily */ - void InitOnDemand(); - - /** Loads the Twitch SDK dynamic library */ - void LoadTwitchSDK( const FString& TwitchDLLFolder ); - - struct FTwitchProjectSettings - { - FString ClientID; - FString RedirectURI; - int32 LocalPortNumber; - FString AuthSuccessRedirectURI; - FString AuthFailureRedirectURI; - FString ClientSecret; - }; - - /** Loads settings for Twitch from project configuration files */ - FTwitchProjectSettings LoadProjectSettings(); - - /** Initializes the Twitch SDK */ - void InitTwitch( const FString& TwitchWindowsDLLFolder ); - - /** Tries to authenticate credentials with Twitch by connecting directly to the service */ - void Async_AuthenticateWithTwitchDirectly( const FString& UserName, const FString& Password, const FString& ClientSecret ); - - /** Tries to authenticate credentials with Twitch using a web browser to login (Twitch SDK's implementation) */ - void Async_AuthenticateWithTwitchUsingBrowser_UsingTwitchSDK(); - - /** Tries to authenticate credentials with Twitch using a web browser to login (manual implementation) */ - void Async_AuthenticateWithTwitchUsingBrowser_Manually(); - - /** Checks to see if the user has successfully authenticated with Twitch using the web browser */ - void CheckIfBrowserLoginCompleted(); - - /** Attempts to login to the Twitch server */ - void Async_LoginToTwitch(); - - /** Queries available servers */ - void Async_GetIngestServers(); - - /** Starts broadcasting video and audio */ - void Async_StartBroadcasting(); - - /** Stops broadcasting */ - void Async_StopBroadcasting(); - - /** Transmits a single frame of video to Twitch */ - void Async_SendVideoFrame( const FColor* VideoFrameBuffer ); - - typedef FLiveStreamingStatus::EStatusType EStatusType; - - /** Executes user callbacks to let the user know about some kind of Twitch status change */ - void PublishStatus( const EStatusType Type, const FText& Text ); - - /** FTickableGameObject implementation */ - virtual void Tick( float DeltaTime ) override; - virtual bool IsTickable() const override; - virtual TStatId GetStatId() const override; - virtual bool IsTickableWhenPaused() const override; - virtual bool IsTickableInEditor() const override; - - -private: - - /** The various states we can be in. Nearly everything happens asynchronously, so we track what's going on with a simple state machine. */ - enum class ETwitchState - { - NotLoaded, - Uninitialized, - ReadyToAuthenticate, - WaitingForBrowserBasedAuthentication, - WaitingForDirectAuthentication, - ReadyToLogin, - WaitingForLogin, - LoggedIn, - LoginFailure, - }; - - /** We'll broadcast this event when any status changes happen to Twitch, such as logging in or activating a web camera */ - FOnStatusChanged OnStatusChangedEvent; - - /** Current state that we're in */ - ETwitchState TwitchState; - - /** Handle to the Twitch DLL */ - void* TwitchDLLHandle; - - /** Settings for Twitch, loaded from project configuration files */ - FTwitchProjectSettings ProjectSettings; - - /** Twitch authorization token, valid after authorization completes and kept around so we can pass it to various Twitch SDK functions */ - TTV_AuthToken TwitchAuthToken; - - /** Time that we started browser-based login. This is used to timeout a request that is unresponsive. */ - FDateTime BrowserLoginStartTime; - - /** Time that we last checked to see if browser-based login had completed. This is used to wait between retries, to reduce CPU usage. */ - FDateTime LastBrowserLoginCheckTime; - - - /** - * Twitch init and authentication functions - */ - - typedef TTV_ErrorCode( *TwitchSetTraceLevelFuncPtr )( TTV_MessageLevel traceLevel ); - TwitchSetTraceLevelFuncPtr TwitchSetTraceLevel; - - typedef TTV_ErrorCode( *TwitchInitFuncPtr )( const TTV_MemCallbacks* memCallbacks, const char* clientID, const wchar_t* dllPath ); - TwitchInitFuncPtr TwitchInit; - - typedef TTV_ErrorCode( *TwitchShutdownFuncPtr )( ); - TwitchShutdownFuncPtr TwitchShutdown; - - typedef TTV_ErrorCode( *TwitchPollTasksFuncPtr )( ); - TwitchPollTasksFuncPtr TwitchPollTasks; - - typedef TTV_ErrorCode( *TwitchRequestAuthTokenFuncPtr )( const TTV_AuthParams* authParams, uint32_t flags, TTV_TaskCallback callback, void* userData, TTV_AuthToken* authToken ); - TwitchRequestAuthTokenFuncPtr TwitchRequestAuthToken; - - typedef TTV_ErrorCode( *TwitchImplicitGrantAuthTokenFuncPtr )( const char* clientId, const char* port, const char* successRedirect, const char* failureRedirect, uint32_t flags, TTV_TaskCallback callback, void* userData, TTV_AuthToken* authToken ); - TwitchImplicitGrantAuthTokenFuncPtr TwitchImplicitGrantAuthToken; - - typedef TTV_ErrorCode( *TwitchLoginFuncPtr )( const TTV_AuthToken* authToken, TTV_TaskCallback callback, void* userData, TTV_ChannelInfo* channelInfo ); - TwitchLoginFuncPtr TwitchLogin; - - typedef const char* ( *TwitchErrorToStringFuncPtr )( TTV_ErrorCode err ); - TwitchErrorToStringFuncPtr TwitchErrorToString; - - - /** - * Live broadcasting support - */ - - /** Broadcasting states */ - enum class EBroadcastState - { - Idle, - WaitingForGetIngestServers, - ReadyToBroadcast, - WaitingToStartBroadcasting, - Broadcasting, - WaitingToStopBroadcasting, - BroadcastingFailure - }; - - /** Current broadcasting state */ - EBroadcastState BroadcastState; - - /** True if the user wants to be broadcasting right now */ - bool bWantsToBroadcastNow; - - /** User's configuration of this broadcast */ - FBroadcastConfig BroadcastConfig; - - /** Info about the current channel (only valid after login completes) */ - TTV_ChannelInfo TwitchChannelInfo; - - /** List of ingest servers available to broadcast using. */ - TTV_IngestList TwitchIngestList; - - /** Number of video buffers that Twitch requires */ - static const uint32 TwitchVideoBufferCount = 3; - - /** List of three capture buffers that Twitch requires in order to stream video. We'll cycle through them every time - a new video frame is pushed to Twitch */ - uint8* VideoBuffers[ TwitchVideoBufferCount ]; - - /** List of buffers that are currently available. This array contains a subset of buffers in the VideoBuffers list that are - currently available for streaming. */ - TArray< uint8* > AvailableVideoBuffers; - - - /** - * Twitch broadcasting functions - */ - - typedef TTV_ErrorCode( *TwitchGetIngestServersFuncPtr )( const TTV_AuthToken* authToken, TTV_TaskCallback callback, void* userData, TTV_IngestList* ingestList ); - TwitchGetIngestServersFuncPtr TwitchGetIngestServers; - - typedef TTV_ErrorCode( *TwitchFreeIngestListFuncPtr )( TTV_IngestList* ingestList ); - TwitchFreeIngestListFuncPtr TwitchFreeIngestList; - - typedef TTV_ErrorCode( *TwitchStartFuncPtr )( const TTV_VideoParams* videoParams, const TTV_AudioParams* audioParams, const TTV_IngestServer* ingestServer, uint32_t flags, TTV_TaskCallback callback, void* userData ); - TwitchStartFuncPtr TwitchStart; - - typedef TTV_ErrorCode( *TwitchStopFuncPtr )( TTV_TaskCallback callback, void* userData ); - TwitchStopFuncPtr TwitchStop; - - typedef TTV_ErrorCode( *TwitchGetMaxResolutionFuncPtr )( uint maxKbps, uint frameRate, float bitsPerPixel, float aspectRatio, uint* width, uint* height ); - TwitchGetMaxResolutionFuncPtr TwitchGetMaxResolution; - - typedef TTV_ErrorCode( *TwitchGetDefaultParamsFuncPtr )( TTV_VideoParams* videoParams ); - TwitchGetDefaultParamsFuncPtr TwitchGetDefaultParams; - - typedef TTV_ErrorCode( *TwitchSubmitVideoFrameFuncPtr )( const uint8_t* frameBuffer, TTV_BufferUnlockCallback callback, void* userData ); - TwitchSubmitVideoFrameFuncPtr TwitchSubmitVideoFrame; - - - - /** - * WebCam support - */ - - /** Updates the web cam texture by copying the latest frame from the camera to a GPU texture asynchronously */ - void UpdateWebCamTexture(); - - /** Starts initializing web cam support */ - void Async_InitWebCamSupport(); - - /** Starts recording from the web camera */ - void Async_StartWebCam(); - - /** Stops recording from the web camera */ - void Async_StopWebCam(); - - /** Releases the web cam texture */ - void ReleaseWebCamTexture( const bool bReleaseResourceToo ); - - - /** The various web cam states we can be in */ - enum class EWebCamState - { - Uninitialized, - WaitingForInit, - Initialized, - InitFailure, - WaitingForStart, - Started, - WaitingForStop, - StartOrStopFailure - }; - - /** True if the user wants to show a web cam right now */ - bool bWantsWebCamNow; - - /** User's web cam configuration */ - FWebCamConfig WebCamConfig; - - /** Current web cam state that we're in */ - EWebCamState WebCamState; - - /** Selected web cam device index */ - int32 WebCamDeviceIndex; - - /** Selected web cam capability index (basically the video resolution) */ - int32 WebCamCapabilityIndex; - - /** Web cam video buffer width */ - int32 WebCamVideoBufferWidth; - - /** Web cam video buffer height */ - int32 WebCamVideoBufferHeight; - - /** True if the web cam texture is flipped vertically, as captured from the camera, and needs to be displayed bottom to top */ - bool bIsWebCamTextureFlippedVertically; - - /** Texture that stores the web cam image, copied asynchronously from the CPU */ - TWeakObjectPtr< class UTexture2D > WebCamTexture; - - - /** - * Twitch WebCam SDK functions - */ - - typedef TTV_ErrorCode ( *TwitchWebCamInitFuncPtr )( const TTV_WebCamCallbacks* interruptCallbacks, TTV_WebCamInitializationCallback initCallback, void* userdata ); - TwitchWebCamInitFuncPtr TwitchWebCamInit; - - typedef TTV_ErrorCode ( *TwitchWebCamShutdownFuncPtr )( TTV_WebCamShutdownCallback callback, void* userdata ); - TwitchWebCamShutdownFuncPtr TwitchWebCamShutdown; - - typedef TTV_ErrorCode ( *TwitchWebCamStartFuncPtr )( int deviceIndex, int capabilityIndex, TTV_WebCamDeviceStatusCallback callback, void* userdata ); - TwitchWebCamStartFuncPtr TwitchWebCamStart; - - typedef TTV_ErrorCode ( *TwitchWebCamStopFuncPtr )( int deviceIndex, TTV_WebCamDeviceStatusCallback callback, void* userdata ); - TwitchWebCamStopFuncPtr TwitchWebCamStop; - - typedef TTV_ErrorCode ( *TwitchWebCamFlushEventsFuncPtr )(); - TwitchWebCamFlushEventsFuncPtr TwitchWebCamFlushEvents; - - typedef TTV_ErrorCode ( *TwitchWebCamIsFrameAvailableFuncPtr )( int deviceIndex, bool* available ); - TwitchWebCamIsFrameAvailableFuncPtr TwitchWebCamIsFrameAvailable; - - typedef TTV_ErrorCode ( *TwitchWebCamGetFrameFuncPtr )( int deviceIndex, void* buffer, unsigned int pitch ); - TwitchWebCamGetFrameFuncPtr TwitchWebCamGetFrame; - - - - /** - * Chat support - */ - - /** Initializes Twitch's chat system asynchronously */ - void Async_InitChatSupport(); - - /** Tries to connect to Twitch's chat server */ - void Async_ConnectToChat(); - - /** Quits the chat connection */ - void Async_DisconnectFromChat(); - - /** Sends a chat message. You need to be connected for this to work! */ - void Async_SendChatMessage( const FString& ChatMessage ); - - /** The various chat states we can be in */ - enum class EChatState - { - Uninitialized, - WaitingForInit, - Initialized, - InitFailure, - WaitingToConnect, - Connected, - WaitingForDisconnect, - ConnectOrDisconnectFailure - }; - - /** True if the user wants to connect to chat right now */ - bool bWantsChatEnabled; - - /** Current chat state that we're in */ - EChatState ChatState; - - /** Broadcast whenever we receive a chat message from the server */ - FOnChatMessage OnChatMessageEvent; - - - /** - * Twitch Chat SDK functions - */ - - typedef TTV_ErrorCode( *TwitchChatInitFuncPtr )( TTV_ChatTokenizationOption tokenizationOptions, TTV_ChatInitializationCallback callback, void* userdata ); - TwitchChatInitFuncPtr TwitchChatInit; - - typedef TTV_ErrorCode( *TwitchChatShutdownFuncPtr )( TTV_ChatShutdownCallback callback, void* userdata ); - TwitchChatShutdownFuncPtr TwitchChatShutdown; - - typedef TTV_ErrorCode( *TwitchChatConnectFuncPtr )( const utf8char* username, const char* authToken, const TTV_ChatCallbacks* chatCallbacks ); - TwitchChatConnectFuncPtr TwitchChatConnect; - - typedef TTV_ErrorCode( *TwitchChatDisconnectFuncPtr )(); - TwitchChatDisconnectFuncPtr TwitchChatDisconnect; - - typedef TTV_ErrorCode( *TwitchChatSendMessageFuncPtr )( const utf8char* message ); - TwitchChatSendMessageFuncPtr TwitchChatSendMessage; - - typedef TTV_ErrorCode( *TwitchChatFlushEventsFuncPtr )(); - TwitchChatFlushEventsFuncPtr TwitchChatFlushEvents; - - - - /** - * Query operations - */ - - /** Kicks off a query for a list of game live streams */ - void Async_GetGameLiveStreams( const FString& GameName, FQueryLiveStreamsCallback CompletionCallback ); - - - /** - * Twitch miscellaneous SDK functions - */ - - typedef TTV_ErrorCode( *TwitchGetGameLiveStreamsFuncPtr )( const char* gameName, TTV_TaskCallback callback, void* userData, TTV_LiveGameStreamList* gameStreamList ); - TwitchGetGameLiveStreamsFuncPtr TwitchGetGameLiveStreams; - - typedef TTV_ErrorCode( *TwitchFreeGameLiveStreamListFuncPtr )( TTV_LiveGameStreamList* gameStreamList ); - TwitchFreeGameLiveStreamListFuncPtr TwitchFreeGameLiveStreamList; - -}; - - -#endif // WITH_TWITCH \ No newline at end of file diff --git a/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/TwitchLiveStreaming/TwitchLiveStreamingModule.h b/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/TwitchLiveStreaming/TwitchLiveStreamingModule.h deleted file mode 100644 index c548b24f1a26..000000000000 --- a/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/TwitchLiveStreaming/TwitchLiveStreamingModule.h +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "CoreMinimal.h" - -#ifndef WITH_TWITCH - #error Expecting WITH_TWITCH to be defined to either 0 or 1 in TwitchLiveStreaming.Build.cs - #define WITH_TWITCH 1 // For IntelliSense to be happy -#endif \ No newline at end of file diff --git a/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/TwitchLiveStreaming/TwitchProjectSettings.cpp b/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/TwitchLiveStreaming/TwitchProjectSettings.cpp deleted file mode 100644 index 50cdb6f29f1b..000000000000 --- a/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/TwitchLiveStreaming/TwitchProjectSettings.cpp +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#include "TwitchProjectSettings.h" - - -UTwitchProjectSettings::UTwitchProjectSettings( const FObjectInitializer& ObjectInitializer ) - : Super( ObjectInitializer ) -{ -} - diff --git a/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/TwitchLiveStreaming/TwitchProjectSettings.h b/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/TwitchLiveStreaming/TwitchProjectSettings.h deleted file mode 100644 index 09552ed10006..000000000000 --- a/Engine/Plugins/Runtime/TwitchLiveStreaming/Source/TwitchLiveStreaming/TwitchProjectSettings.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#pragma once - -#include "CoreMinimal.h" -#include "UObject/Object.h" -#include "TwitchProjectSettings.generated.h" - -UCLASS(Config=Engine, DefaultConfig) -class UTwitchProjectSettings : public UObject -{ - GENERATED_UCLASS_BODY() - -public: - - /** This is the Twitch Client ID for your game's Twitch application. You'll need to supply a valid Client ID for your game in order for - it to be allowed to broadcast to Twitch. You can get a Client ID by visiting the Twitch web site, logging in and creating a - Twitch Application for your game. Copy the Client ID from the Twitch web site into this field. */ - UPROPERTY(Config, EditAnywhere, Category=Settings) - FString ApplicationClientID; - - /** The redirect URI is the web page that the user will be redirected to after authenticating with Twitch. Usually this page - would show that the login was successful and the user can simply close the browser tab. If you don't want to host a page - you can simply point this to a localhost port. Remember, Twitch requires you to set the RedirectURI in your application's - configuration page on the Twitch web site. If the URI doesn't exactly match what is here, authentication will fail. */ - UPROPERTY(Config, EditAnywhere, Category=Settings) - FString RedirectURI; - - /** The port number on the localhost to use when authenticating using implicit grant authentication. This should be the same - port number as the one used in the RedirectURI. */ - UPROPERTY( Config, EditAnywhere, Category = Settings ) - int32 LocalPortNumber; - - /** The web page the user should be sent to after they've logged in successfully. This page should usually tell the user - that they've logged in, and they can task switch back to the application now. */ - UPROPERTY( Config, EditAnywhere, Category = Settings ) - FString AuthSuccessRedirectURI; - - /** The web page the user should be sent to if something went wrong after logging in. */ - UPROPERTY( Config, EditAnywhere, Category = Settings ) - FString AuthFailureRedirectURI; - - /** Twitch "client secret" ID. This is required if you want to use direct authentication instead of authenticating through - a web browser. */ - UPROPERTY( Config, EditAnywhere, Category = Settings ) - FString DirectAuthenticationClientSecretID; -}; - - diff --git a/Engine/Plugins/Runtime/WindowsMoviePlayer/Source/WindowsMoviePlayer/Private/WindowsMovieStreamer.cpp b/Engine/Plugins/Runtime/WindowsMoviePlayer/Source/WindowsMoviePlayer/Private/WindowsMovieStreamer.cpp index 18964dfa8ff7..943f547bb1dc 100644 --- a/Engine/Plugins/Runtime/WindowsMoviePlayer/Source/WindowsMoviePlayer/Private/WindowsMovieStreamer.cpp +++ b/Engine/Plugins/Runtime/WindowsMoviePlayer/Source/WindowsMoviePlayer/Private/WindowsMovieStreamer.cpp @@ -49,7 +49,7 @@ bool FMediaFoundationMovieStreamer::Init(const TArray& MoviePaths, TEnu return false; } - MovieIndex = -1; + MovieIndex = 0; PlaybackType = inPlaybackType; StoredMoviePaths = MoviePaths; @@ -86,13 +86,13 @@ bool FMediaFoundationMovieStreamer::Tick(float DeltaTime) if (!VideoPlayer->MovieIsRunning()) { CloseMovie(); - if (MovieIndex < StoredMoviePaths.Num() - 1) + if (MovieIndex < StoredMoviePaths.Num()) { OpenNextMovie(); } else if (PlaybackType != MT_Normal) { - MovieIndex = PlaybackType == MT_LoadingLoop ? StoredMoviePaths.Num() - 2 : -1; + MovieIndex = PlaybackType == MT_LoadingLoop ? StoredMoviePaths.Num() - 1 : 0; OpenNextMovie(); } else @@ -122,7 +122,6 @@ void FMediaFoundationMovieStreamer::Cleanup() void FMediaFoundationMovieStreamer::OpenNextMovie() { - MovieIndex++; check(StoredMoviePaths.Num() > 0 && MovieIndex < StoredMoviePaths.Num()); FString MoviePath = FPaths::GameContentDir() + TEXT("Movies/") + StoredMoviePaths[MovieIndex]; @@ -165,6 +164,8 @@ void FMediaFoundationMovieStreamer::OpenNextMovie() MovieViewport->SetTexture(Texture); VideoPlayer->StartPlayback(); } + ++MovieIndex; + } void FMediaFoundationMovieStreamer::CloseMovie() diff --git a/Engine/Plugins/ScriptPlugin/Source/ScriptEditorPlugin/Private/ScriptBlueprintCompiler.cpp b/Engine/Plugins/ScriptPlugin/Source/ScriptEditorPlugin/Private/ScriptBlueprintCompiler.cpp index 3448c448d8d3..489ccba37d67 100644 --- a/Engine/Plugins/ScriptPlugin/Source/ScriptEditorPlugin/Private/ScriptBlueprintCompiler.cpp +++ b/Engine/Plugins/ScriptPlugin/Source/ScriptEditorPlugin/Private/ScriptBlueprintCompiler.cpp @@ -74,9 +74,9 @@ void FScriptBlueprintCompiler::CreateClassVariablesFromBlueprint() } if (!PinCategory.IsEmpty()) { - FEdGraphPinType ScriptPinType(PinCategory, TEXT(""), InnerType, false, false, false, false, FEdGraphTerminalType()); + FEdGraphPinType ScriptPinType(PinCategory, FString(), InnerType, EPinContainerType::None, false, FEdGraphTerminalType()); UProperty* ScriptProperty = CreateVariable(Field.Name, ScriptPinType); - if (ScriptProperty != NULL) + if (ScriptProperty) { ScriptProperty->SetMetaData(TEXT("Category"), *ScriptBP->GetName()); ScriptProperty->SetPropertyFlags(CPF_BlueprintVisible | CPF_Edit); @@ -104,7 +104,7 @@ void FScriptBlueprintCompiler::CreateScriptContextProperty() if (ContextClass) { - FEdGraphPinType ScriptContextPinType(Schema->PC_Object, TEXT(""), ContextClass, false, false, false, false, FEdGraphTerminalType()); + FEdGraphPinType ScriptContextPinType(Schema->PC_Object, FString(), ContextClass, EPinContainerType::None, false, FEdGraphTerminalType()); ContextProperty = CastChecked(CreateVariable(TEXT("Generated_ScriptContext"), ScriptContextPinType)); ContextProperty->SetPropertyFlags(CPF_ContainsInstancedReference | CPF_InstancedReference); } diff --git a/Engine/Plugins/Tests/EditorTests/Source/EditorTests/Private/UnrealEd/CollisionAutomationTests.cpp b/Engine/Plugins/Tests/EditorTests/Source/EditorTests/Private/UnrealEd/CollisionAutomationTests.cpp index f670790b83f2..c899d4d67361 100644 --- a/Engine/Plugins/Tests/EditorTests/Source/EditorTests/Private/UnrealEd/CollisionAutomationTests.cpp +++ b/Engine/Plugins/Tests/EditorTests/Source/EditorTests/Private/UnrealEd/CollisionAutomationTests.cpp @@ -153,7 +153,6 @@ bool FComponentSweepMultiTest::RunTest(const FString& Parameters) UWorld* World = FAutomationEditorCommonUtils::CreateNewMap(); TestNotNull( TEXT("Failed to create world for Physics.Collision.Ray Test. Tests aborted."), World ); - static FName TraceIdent = FName(TEXT("TestTrace")); FVector StartPos; FVector EndPos; @@ -189,7 +188,7 @@ bool FComponentSweepMultiTest::RunTest(const FString& Parameters) StartPos = TestRayCollisionActor->GetActorLocation(); EndPos = TestRayMeshActor->GetActorLocation(); // Setup the query - FComponentQueryParams ShapeQueryParameters(TraceIdent, nullptr); + FComponentQueryParams ShapeQueryParameters(SCENE_QUERY_STAT(TestTrace), nullptr); ShapeQueryParameters.bTraceComplex = true; ShapeQueryParameters.bTraceAsyncScene = true; diff --git a/Engine/Plugins/Tests/EditorTests/Source/EditorTests/Private/UnrealEd/EditorBuildPromotionTests.cpp b/Engine/Plugins/Tests/EditorTests/Source/EditorTests/Private/UnrealEd/EditorBuildPromotionTests.cpp index bbb5765f47fe..c119632990cc 100644 --- a/Engine/Plugins/Tests/EditorTests/Source/EditorTests/Private/UnrealEd/EditorBuildPromotionTests.cpp +++ b/Engine/Plugins/Tests/EditorTests/Source/EditorTests/Private/UnrealEd/EditorBuildPromotionTests.cpp @@ -1865,7 +1865,7 @@ namespace BuildPromotionTestHelper const UEdGraphSchema_K2* K2Schema = GetDefault(); // Add string member variable - FEdGraphPinType StringPinType(K2Schema->PC_String, TEXT(""), NULL, false, false, false, false, FEdGraphTerminalType()); + FEdGraphPinType StringPinType(K2Schema->PC_String, FString(), nullptr, EPinContainerType::None, false, FEdGraphTerminalType()); FBlueprintEditorUtils::AddMemberVariable(BlueprintObject, EditorBuildPromotionTestUtils::BlueprintStringVariableName, StringPinType); // Add print string node connected to the BeginPlay node; save it for use later diff --git a/Engine/Plugins/Tests/EditorTests/Source/EditorTests/Private/UnrealEd/FbxAutomationTests.cpp b/Engine/Plugins/Tests/EditorTests/Source/EditorTests/Private/UnrealEd/FbxAutomationTests.cpp index 15de06751d09..42e9e109db89 100644 --- a/Engine/Plugins/Tests/EditorTests/Source/EditorTests/Private/UnrealEd/FbxAutomationTests.cpp +++ b/Engine/Plugins/Tests/EditorTests/Source/EditorTests/Private/UnrealEd/FbxAutomationTests.cpp @@ -161,6 +161,9 @@ bool FFbxImportAssetsAutomationTest::RunTest(const FString& Parameters) //Create a factory and set the options UFbxFactory* FbxFactory = NewObject(UFbxFactory::StaticClass()); FbxFactory->AddToRoot(); + + TestPlan->ImportUI->bResetMaterialSlots = false; + FbxFactory->ImportUI = TestPlan->ImportUI; //Skip the auto detect type on import, the test set a specific value FbxFactory->SetDetectImportTypeOnImport(false); @@ -259,6 +262,9 @@ bool FFbxImportAssetsAutomationTest::RunTest(const FString& Parameters) { UReimportFbxStaticMeshFactory* FbxStaticMeshReimportFactory = NewObject(UReimportFbxStaticMeshFactory::StaticClass()); FbxStaticMeshReimportFactory->AddToRoot(); + + TestPlan->ImportUI->bResetMaterialSlots = false; + FbxStaticMeshReimportFactory->ImportUI = TestPlan->ImportUI; UStaticMesh *ReimportStaticMesh = Cast(GlobalImportedObjects[0]); @@ -297,6 +303,9 @@ bool FFbxImportAssetsAutomationTest::RunTest(const FString& Parameters) { UReimportFbxSkeletalMeshFactory* FbxSkeletalMeshReimportFactory = NewObject(UReimportFbxSkeletalMeshFactory::StaticClass()); FbxSkeletalMeshReimportFactory->AddToRoot(); + + TestPlan->ImportUI->bResetMaterialSlots = false; + FbxSkeletalMeshReimportFactory->ImportUI = TestPlan->ImportUI; USkeletalMesh *ReimportSkeletalMesh = Cast(GlobalImportedObjects[0]); @@ -387,7 +396,6 @@ bool FFbxImportAssetsAutomationTest::RunTest(const FString& Parameters) ImportData->ImportUniformScale = TestPlan->ImportUI->StaticMeshImportData->ImportUniformScale; ImportData->bImportAsScene = TestPlan->ImportUI->StaticMeshImportData->bImportAsScene; - FbxMeshUtils::ImportStaticMeshLOD(ExistingStaticMesh, LodFile, TestPlan->LodIndex); } else if (GlobalImportedObjects[0]->IsA(USkeletalMesh::StaticClass())) diff --git a/Engine/Plugins/Tests/FunctionalTestingEditor/Source/FunctionalTestingEditor.Build.cs b/Engine/Plugins/Tests/FunctionalTestingEditor/Source/FunctionalTestingEditor.Build.cs index 637781b8e8b8..75eb00e28fe3 100644 --- a/Engine/Plugins/Tests/FunctionalTestingEditor/Source/FunctionalTestingEditor.Build.cs +++ b/Engine/Plugins/Tests/FunctionalTestingEditor/Source/FunctionalTestingEditor.Build.cs @@ -29,7 +29,8 @@ public class FunctionalTestingEditor : ModuleRules "FunctionalTesting", "PlacementMode", "WorkspaceMenuStructure", - "ScreenShotComparisonTools" + "ScreenShotComparisonTools", + "AssetTools" } ); } diff --git a/Engine/Plugins/Tests/FunctionalTestingEditor/Source/Private/AssetTypeActions_GroundTruthData.cpp b/Engine/Plugins/Tests/FunctionalTestingEditor/Source/Private/AssetTypeActions_GroundTruthData.cpp new file mode 100644 index 000000000000..f194d0b2a327 --- /dev/null +++ b/Engine/Plugins/Tests/FunctionalTestingEditor/Source/Private/AssetTypeActions_GroundTruthData.cpp @@ -0,0 +1,12 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "AssetTypeActions_GroundTruthData.h" + +#define LOCTEXT_NAMESPACE "AssetTypeActions" + +void FAssetTypeActions_GroundTruthData::OpenAssetEditor(const TArray& InObjects, TSharedPtr EditWithinLevelEditor) +{ + FSimpleAssetEditor::CreateEditor(EToolkitMode::Standalone, EditWithinLevelEditor, InObjects); +} + +#undef LOCTEXT_NAMESPACE diff --git a/Engine/Plugins/Tests/FunctionalTestingEditor/Source/Private/AssetTypeActions_GroundTruthData.h b/Engine/Plugins/Tests/FunctionalTestingEditor/Source/Private/AssetTypeActions_GroundTruthData.h new file mode 100644 index 000000000000..58af4776aad6 --- /dev/null +++ b/Engine/Plugins/Tests/FunctionalTestingEditor/Source/Private/AssetTypeActions_GroundTruthData.h @@ -0,0 +1,23 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "Toolkits/IToolkitHost.h" +#include "AssetTypeActions_Base.h" +#include "GroundTruthData.h" + +class FMenuBuilder; + +class FAssetTypeActions_GroundTruthData : public FAssetTypeActions_Base +{ +public: + // IAssetTypeActions Implementation + virtual FColor GetTypeColor() const override { return FColor(255, 196, 128); } + virtual bool CanLocalize() const override { return false; } + virtual uint32 GetCategories() override { return EAssetTypeCategories::Misc; } + virtual FText GetName() const override { return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_GroundTruthData", "Ground Truth Data"); } + virtual UClass* GetSupportedClass() const override { return UGroundTruthData::StaticClass(); } + virtual void OpenAssetEditor(const TArray& InObjects, TSharedPtr EditWithinLevelEditor = TSharedPtr()) override; + // End IAssetTypeActions +}; diff --git a/Engine/Plugins/Tests/FunctionalTestingEditor/Source/Private/EditorAutomationModule.cpp b/Engine/Plugins/Tests/FunctionalTestingEditor/Source/Private/EditorAutomationModule.cpp index b793b85e787b..aa0987101bbc 100644 --- a/Engine/Plugins/Tests/FunctionalTestingEditor/Source/Private/EditorAutomationModule.cpp +++ b/Engine/Plugins/Tests/FunctionalTestingEditor/Source/Private/EditorAutomationModule.cpp @@ -22,6 +22,8 @@ #include "WorkspaceMenuStructure.h" #include "WorkspaceMenuStructureModule.h" #include "Widgets/Docking/SDockTab.h" +#include "AssetTypeActions_GroundTruthData.h" +#include "IAssetTools.h" #define LOCTEXT_NAMESPACE "EditorAutomation" @@ -121,6 +123,9 @@ class FEditorAutomationModule : public IEditorAutomationModule { OnModulesChanged("PlacementMode", EModuleChangeReason::ModuleLoaded); } + + IAssetTools& AssetTools = FModuleManager::LoadModuleChecked("AssetTools").Get(); + AssetTools.RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_GroundTruthData())); } void ShutdownModule() diff --git a/Engine/Plugins/Tests/FunctionalTestingEditor/Source/Private/GroundTruthDataFactory.cpp b/Engine/Plugins/Tests/FunctionalTestingEditor/Source/Private/GroundTruthDataFactory.cpp new file mode 100644 index 000000000000..ab2cbe38ad15 --- /dev/null +++ b/Engine/Plugins/Tests/FunctionalTestingEditor/Source/Private/GroundTruthDataFactory.cpp @@ -0,0 +1,34 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "GroundTruthDataFactory.h" +#include "GroundTruthData.h" +#include "AssetTypeCategories.h" + +#define LOCTEXT_NAMESPACE "UGroundTruthDataFactory" + +UGroundTruthDataFactory::UGroundTruthDataFactory(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + bCreateNew = true; + bEditAfterNew = false; + bEditorImport = false; + SupportedClass = UGroundTruthData::StaticClass(); +} + +UObject* UGroundTruthDataFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName InName, EObjectFlags InFlags, UObject* Context, FFeedbackContext* Warn) +{ + UGroundTruthData* GroundTruthData = NewObject(InParent, SupportedClass, InName, InFlags | RF_Transactional); + return GroundTruthData; +} + +uint32 UGroundTruthDataFactory::GetMenuCategories() const +{ + return EAssetTypeCategories::Misc; +} + +FText UGroundTruthDataFactory::GetDisplayName() const +{ + return LOCTEXT("MenuEntry", "Ground Truth Data"); +} + +#undef LOCTEXT_NAMESPACE diff --git a/Engine/Plugins/Tests/FunctionalTestingEditor/Source/Private/GroundTruthDataFactory.h b/Engine/Plugins/Tests/FunctionalTestingEditor/Source/Private/GroundTruthDataFactory.h new file mode 100644 index 000000000000..94e2c7e4c3f7 --- /dev/null +++ b/Engine/Plugins/Tests/FunctionalTestingEditor/Source/Private/GroundTruthDataFactory.h @@ -0,0 +1,20 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "Factories/Factory.h" +#include "GroundTruthDataFactory.generated.h" + +UCLASS(hidecategories=Object, collapsecategories) +class UGroundTruthDataFactory : public UFactory +{ + GENERATED_UCLASS_BODY() + + // UFactory Interface + virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override; + virtual uint32 GetMenuCategories() const override; + virtual FText GetDisplayName() const override; + // End of UFactory Interface +}; diff --git a/Engine/Plugins/Tests/RuntimeTests/Source/RuntimeTests/Private/AutomationExpectedError.spec.cpp b/Engine/Plugins/Tests/RuntimeTests/Source/RuntimeTests/Private/AutomationExpectedError.spec.cpp new file mode 100644 index 000000000000..ea7e875e0570 --- /dev/null +++ b/Engine/Plugins/Tests/RuntimeTests/Source/RuntimeTests/Private/AutomationExpectedError.spec.cpp @@ -0,0 +1,172 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "AutomationTest.h" + +BEGIN_DEFINE_SPEC(FAutomationExpectedErrorTest, "System.Automation.ExpectedError", EAutomationTestFlags::EngineFilter | EAutomationTestFlags::ApplicationContextMask) +END_DEFINE_SPEC(FAutomationExpectedErrorTest) +void FAutomationExpectedErrorTest::Define() +{ + Describe("A defined expected error in a test", [this]() + { + + It("will not add an error with a number of occurrences less than zero", [this]() + { + // Suppress error logged when adding entry with invalid occurrence count + AddExpectedError(TEXT("number of expected occurrences must be >= 0"), EAutomationExpectedErrorFlags::Contains, 1); + + AddExpectedError(TEXT("The two values are not equal"), EAutomationExpectedErrorFlags::Contains, -1); + + TArray Errors; + GetExpectedErrors(Errors); + + // Only the first expected error should exist in the list. + TestEqual("Expected Errors Count", Errors.Num(), 1); + }); + + It("will add an error with a number of occurrences equal to zero", [this]() + { + AddExpectedError(TEXT("Expected Error"), EAutomationExpectedErrorFlags::Contains, 0); + + TArray Errors; + GetExpectedErrors(Errors); + TestEqual("Expected Errors Count", Errors.Num(), 1); + + // Add the expected error to ensure all test conditions pass + AddError(TEXT("Expected Error")); + }); + + It("will not duplicate an existing expected error using the same matcher", [this]() + { + // Suppress warning logged when adding duplicate value + AddExpectedError(TEXT("cannot add duplicate entries"), EAutomationExpectedErrorFlags::Contains, 1); + + AddExpectedError(TEXT("Expected Error"), EAutomationExpectedErrorFlags::Contains, 1); + AddExpectedError(TEXT("Expected Error"), EAutomationExpectedErrorFlags::Contains, 1); + + TArray Errors; + GetExpectedErrors(Errors); + TestEqual("Expected Errors Count", Errors.Num(), 2); + + // Add the expected error to ensure all test conditions pass + AddError(TEXT("Expected Error")); + }); + + It("will not duplicate an expected error using a different matcher", [this]() + { + // Suppress warning logged when adding duplicate value + AddExpectedError(TEXT("cannot add duplicate entries"), EAutomationExpectedErrorFlags::Contains, 2); + + AddExpectedError(TEXT("Expected Exact Error"), EAutomationExpectedErrorFlags::Exact, 1); + AddExpectedError(TEXT("Expected Exact Error"), EAutomationExpectedErrorFlags::Contains, 1); + + AddExpectedError(TEXT("Expected Contains Error"), EAutomationExpectedErrorFlags::Contains, 1); + AddExpectedError(TEXT("Expected Contains Error"), EAutomationExpectedErrorFlags::Exact, 1); + + TArray Errors; + GetExpectedErrors(Errors); + TestEqual("Expected Errors Count", Errors.Num(), 3); + + // Add the expected errors to ensure all test conditions pass + AddError(TEXT("Expected Exact Error")); + AddError(TEXT("Expected Contains Error")); + }); + + // Disabled until fix for UE-44340 (crash creating invalid regex) is merged + xIt("will not add an error with an invalid regex pattern", [this]() + { + AddExpectedError(TEXT("invalid regex }])([{"), EAutomationExpectedErrorFlags::Contains, 0); + + TArray Errors; + GetExpectedErrors(Errors); + + TestEqual("Expected Errors Count", Errors.Num(), 0); + }); + + It("will match both Error and Warning messages", [this]() + { + AddExpectedError(TEXT("Expected Message"), EAutomationExpectedErrorFlags::Contains, 0); + AddError(TEXT("Expected Message")); + AddWarning(TEXT("Expected Message")); + }); + + It("will not fail or warn if encountered", [this]() + { + AddExpectedError(TEXT("Expected Error"), EAutomationExpectedErrorFlags::Contains, 1); + AddExpectedError(TEXT("Expected Warning"), EAutomationExpectedErrorFlags::Contains, 1); + AddError(TEXT("Expected Error")); + AddWarning(TEXT("Expected Warning")); + }); + + It("will not match multiple occurrences in the same message when using Contains matcher", [this]() + { + AddExpectedError(TEXT("Expected"), EAutomationExpectedErrorFlags::Contains, 1); + AddError(TEXT("ExpectedExpectedExpected ExpectedExpectedExpected")); + }); + + It("will match different messages that fit the regex pattern", [this]() + { + AddExpectedError(TEXT("Response \\(-?\\d+\\)"), EAutomationExpectedErrorFlags::Contains, 4); + AddError(TEXT("Response (0)")); + AddError(TEXT("Response (1)")); + AddError(FString::Printf(TEXT("Response (%d)"), MIN_int64)); + AddError(FString::Printf(TEXT("Response (%d)"), MAX_uint64)); + }); + + }); + +} + +// Tests for cases where expected errors will fail a test. +// IMPORTANT: The pass condition for these tests is that they FAIL. To prevent +// the expected failures from interfering with regular test runs, these tests +// must be run manually. +BEGIN_DEFINE_SPEC(FAutomationExpectedErrorFailureTest, "System.Automation.ExpectedError", EAutomationTestFlags::EngineFilter | EAutomationTestFlags::ApplicationContextMask | EAutomationTestFlags::RequiresUser) +END_DEFINE_SPEC(FAutomationExpectedErrorFailureTest) + +void FAutomationExpectedErrorFailureTest::Define() +{ + Describe("An expected error failure", [this]() + { + It("will occur if expected a specific number of times and NOT encountered.", [this]() + { + AddExpectedError(TEXT("Expected Error"), EAutomationExpectedErrorFlags::Exact, 1); + }); + + It("will occur if expected a specific number of times and is encountered too few times.", [this]() + { + AddExpectedError(TEXT("Expected Error"), EAutomationExpectedErrorFlags::Exact, 2); + AddError(TEXT("Expected Error")); + }); + + It("will occur if expected a specific number of times and is encountered too many times.", [this]() + { + AddExpectedError(TEXT("Expected Error"), EAutomationExpectedErrorFlags::Exact, 1); + AddError(TEXT("Expected Error")); + AddError(TEXT("Expected Error")); + }); + + It("will occur if expected any number of times and is not encountered.", [this]() + { + AddExpectedError(TEXT("Expected Error"), EAutomationExpectedErrorFlags::Exact, 0); + }); + + It("will occur if multiple expected errors are NOT encountered.", [this]() + { + AddExpectedError(TEXT("Expected Error 1"), EAutomationExpectedErrorFlags::Exact, 1); + AddExpectedError(TEXT("Expected Error 2"), EAutomationExpectedErrorFlags::Contains, 1); + }); + + It("will occur if not all expected errors are encountered.", [this]() + { + AddExpectedError(TEXT("Expected error 1"), EAutomationExpectedErrorFlags::Exact, 1); + AddExpectedError(TEXT("Expected error 2"), EAutomationExpectedErrorFlags::Contains, 1); + AddError(TEXT("Expected error 1")); + }); + + It("will occur if only partial matches are encountered when using Exact matcher", [this]() + { + AddExpectedError(TEXT("Expected"), EAutomationExpectedErrorFlags::Exact, 1); + AddError(TEXT("Expected error")); + }); + }); +} \ No newline at end of file diff --git a/Engine/Programs/UnrealGameSync/UnrealGameSync.ini b/Engine/Programs/UnrealGameSync/UnrealGameSync.ini index 9dbca66cfa23..a1b7a99caaae 100644 --- a/Engine/Programs/UnrealGameSync/UnrealGameSync.ini +++ b/Engine/Programs/UnrealGameSync/UnrealGameSync.ini @@ -1,2 +1,7 @@ [Options] UseFastModularVersioning=1 ++ExcludeChanges=lightmaps ++ExcludeChanges=^Added collection '.*'\s*$ ++ExcludeChanges=^Added '.*' to collection '.*'\s*$ ++ExcludeChanges=^Added \d+ objects to collection '.*': ++ExcludeChanges=^Changed the parent of collection '.*' diff --git a/Engine/Shaders/BasePassPixelShader.usf b/Engine/Shaders/BasePassPixelShader.usf index 38bb2779c67e..4cc64272f475 100644 --- a/Engine/Shaders/BasePassPixelShader.usf +++ b/Engine/Shaders/BasePassPixelShader.usf @@ -46,6 +46,7 @@ float NormalCurvatureToRoughness(float3 WorldNormal) #endif +#include "ShadingModelsMaterial.usf" #if MATERIAL_SHADINGMODEL_HAIR || SIMPLE_FORWARD_DIRECTIONAL_LIGHT #include "ShadingModels.usf" #endif @@ -667,151 +668,47 @@ void FPixelShaderInOut_MainPS( } #endif - float3 LocalBaseColor = BaseColor; - float LocalSpecular = Specular; - half Opacity = GetMaterialOpacity(PixelMaterialInputs); FGBufferData GBuffer = (FGBufferData)0; - GBuffer.WorldNormal = MaterialParameters.WorldNormal; - GBuffer.BaseColor = BaseColor; - GBuffer.Metallic = Metallic; - GBuffer.Specular = Specular; - GBuffer.Roughness = Roughness; GBuffer.GBufferAO = MaterialAO; GBuffer.PerObjectGBufferData = Primitive.PerObjectGBufferData; GBuffer.Depth = MaterialParameters.ScreenPosition.w; - GBuffer.PrecomputedShadowFactors = GetPrecomputedShadowMasks(Interpolants); - #if MATERIAL_SHADINGMODEL_UNLIT - GBuffer.ShadingModelID = SHADINGMODELID_UNLIT; - #elif MATERIAL_SHADINGMODEL_DEFAULT_LIT - GBuffer.ShadingModelID = SHADINGMODELID_DEFAULT_LIT; - #elif MATERIAL_SHADINGMODEL_SUBSURFACE - GBuffer.ShadingModelID = SHADINGMODELID_SUBSURFACE; - GBuffer.CustomData.rgb = EncodeSubsurfaceColor(SubsurfaceColor); - GBuffer.CustomData.a = Opacity; - #elif MATERIAL_SHADINGMODEL_PREINTEGRATED_SKIN - GBuffer.ShadingModelID = SHADINGMODELID_PREINTEGRATED_SKIN; - GBuffer.CustomData.rgb = EncodeSubsurfaceColor(SubsurfaceColor); - GBuffer.CustomData.a = Opacity; - #elif MATERIAL_SHADINGMODEL_SUBSURFACE_PROFILE - // Optimization: if opacity is 0 then revert to default shading model - #if SUBSURFACE_PROFILE_OPACITY_THRESHOLD - if (Opacity > 0.0) - #endif - { - GBuffer.ShadingModelID = SHADINGMODELID_SUBSURFACE_PROFILE; - GBuffer.CustomData.rgb = EncodeSubsurfaceProfile(SubsurfaceProfile); - GBuffer.CustomData.a = Opacity; - } - #if SUBSURFACE_PROFILE_OPACITY_THRESHOLD - else - { - GBuffer.ShadingModelID = SHADINGMODELID_DEFAULT_LIT; - GBuffer.CustomData = 0; - } - #endif - #elif MATERIAL_SHADINGMODEL_CLEAR_COAT + SetGBufferForShadingModel( + GBuffer, + MaterialParameters, + Opacity, + BaseColor, + Metallic, + Specular, + Roughness, + float4(SubsurfaceColor, SubsurfaceProfile)); + +#if USES_GBUFFER + GBuffer.SelectiveOutputMask = GetSelectiveOutputMask(); + + #if WRITES_VELOCITY_TO_GBUFFER { - GBuffer.ShadingModelID = SHADINGMODELID_CLEAR_COAT; - - float ClearCoat = saturate( GetMaterialCustomData0(MaterialParameters) ); - float ClearCoatRoughness = saturate( GetMaterialCustomData1(MaterialParameters) ); - float MetalSpec = 0.9; - - float NoV = saturate( dot( MaterialParameters.WorldNormal, MaterialParameters.CameraVector ) ); - - // Approximation of refraction's effect on EnvBRDF - float RefractionScale = ( (NoV * 0.5 + 0.5) * NoV - 1 ) * saturate( 1.25 - 1.25 * Roughness ) + 1; - - // Approximation of absorption integral, tuned for Roughness=0.4 - float3 AbsorptionColor = BaseColor * (1 / MetalSpec); - float3 Absorption = AbsorptionColor * ( (NoV - 1) * 0.85 * ( 1 - lerp( AbsorptionColor, Square(AbsorptionColor), -0.78 ) ) + 1 ); - - float F0 = 0.04; - float Fc = Pow5( 1 - NoV ); - float F = Fc + (1 - Fc) * F0; - float LayerAttenuation = lerp( 1, (1 - F), ClearCoat ); - BaseColor *= LayerAttenuation; - - GBuffer.BaseColor = lerp( BaseColor, MetalSpec * Absorption * RefractionScale, Metallic * ClearCoat ); - GBuffer.Specular *= lerp( 1, RefractionScale, ClearCoat ); - - GBuffer.CustomData.x = ClearCoat; - GBuffer.CustomData.y = ClearCoatRoughness; - - #if CLEAR_COAT_BOTTOM_NORMAL - { - float2 oct2 = UnitVectorToOctahedron(GBuffer.WorldNormal); - - #if NUM_MATERIAL_OUTPUTS_CLEARCOATBOTTOMNORMAL > 0 - #if MATERIAL_TANGENTSPACENORMAL - float3 tempnormal = normalize(TransformTangentVectorToWorld( MaterialParameters.TangentToWorld, ClearCoatBottomNormal0(MaterialParameters) )); - #else - float3 tempnormal = ClearCoatBottomNormal0(MaterialParameters); - #endif - - float2 oct1 = UnitVectorToOctahedron(tempnormal); - float2 oct3 = ( (oct1 - oct2) * 0.5 ) + (128.0/255.0); - GBuffer.CustomData.a = oct3.x; - GBuffer.CustomData.z = oct3.y; - #else - GBuffer.CustomData.a = 128.0/255.0; - GBuffer.CustomData.z = 128.0/255.0; - #endif - } - #endif - } - #elif MATERIAL_SHADINGMODEL_TWOSIDED_FOLIAGE - GBuffer.ShadingModelID = SHADINGMODELID_TWOSIDED_FOLIAGE; - GBuffer.CustomData.rgb = EncodeSubsurfaceColor(SubsurfaceColor); - GBuffer.CustomData.a = Opacity; - #elif MATERIAL_SHADINGMODEL_HAIR - GBuffer.ShadingModelID = SHADINGMODELID_HAIR; - GBuffer.CustomData.xy = UnitVectorToOctahedron( MaterialParameters.WorldNormal ) * 0.5 + 0.5; - GBuffer.CustomData.z = saturate( GetMaterialCustomData0(MaterialParameters) ); // Backlit - #elif MATERIAL_SHADINGMODEL_CLOTH - GBuffer.ShadingModelID = SHADINGMODELID_CLOTH; - GBuffer.CustomData.rgb = SubsurfaceColor; - GBuffer.CustomData.a = saturate( GetMaterialCustomData0(MaterialParameters) ); // Cloth - GBuffer.IndirectIrradiance *= 1 - GBuffer.CustomData.a; - #elif MATERIAL_SHADINGMODEL_EYE - GBuffer.ShadingModelID = SHADINGMODELID_EYE; - #if NUM_MATERIAL_OUTPUTS_GETTANGENTOUTPUT > 0 - float3 Tangent = GetTangentOutput0(MaterialParameters); - GBuffer.CustomData.xy = UnitVectorToOctahedron( normalize(Tangent) ) * 0.5 + 0.5; - #endif - GBuffer.CustomData.z = saturate( GetMaterialCustomData0(MaterialParameters) ); // Iris Mask - GBuffer.CustomData.w = saturate( GetMaterialCustomData1(MaterialParameters) ); // Iris Distance + // 2d velocity, includes camera an object motion + #if WRITES_VELOCITY_TO_GBUFFER_USE_POS_INTERPOLATOR + float2 Velocity = Calculate2DVelocity(BasePassInterpolants.VelocityScreenPosition, BasePassInterpolants.VelocityPrevScreenPosition); #else - // missing shading model, compiler should report ShadingModelID is not set + float2 Velocity = Calculate2DVelocity(MaterialParameters.ScreenPosition, BasePassInterpolants.VelocityPrevScreenPosition); #endif - #if USES_GBUFFER - GBuffer.SelectiveOutputMask = GetSelectiveOutputMask(); - - #if WRITES_VELOCITY_TO_GBUFFER - { - // 2d velocity, includes camera an object motion - #if WRITES_VELOCITY_TO_GBUFFER_USE_POS_INTERPOLATOR - float2 Velocity = Calculate2DVelocity(BasePassInterpolants.VelocityScreenPosition, BasePassInterpolants.VelocityPrevScreenPosition); - #else - float2 Velocity = Calculate2DVelocity(MaterialParameters.ScreenPosition, BasePassInterpolants.VelocityPrevScreenPosition); - #endif - - // Make sure not to touch 0,0 which is clear color - GBuffer.Velocity = float4(EncodeVelocityToTexture(Velocity), 0, 0) * BasePassInterpolants.VelocityPrevScreenPosition.z; - } - #else - GBuffer.Velocity = 0; - #endif + // Make sure not to touch 0,0 which is clear color + GBuffer.Velocity = float4(EncodeVelocityToTexture(Velocity), 0, 0) * BasePassInterpolants.VelocityPrevScreenPosition.z; + } + #else + GBuffer.Velocity = 0; #endif +#endif // So that the following code can still use DiffuseColor and SpecularColor. - GBuffer.SpecularColor = lerp(0.08 * LocalSpecular.xxx, LocalBaseColor, Metallic.xxx); + GBuffer.SpecularColor = lerp(0.08 * Specular.xxx, BaseColor, Metallic.xxx); #if MATERIAL_NORMAL_CURVATURE_TO_ROUGHNESS float GeometricAARoughness = NormalCurvatureToRoughness(MaterialParameters.WorldNormal); @@ -828,10 +725,10 @@ void FPixelShaderInOut_MainPS( bool bChecker = CheckerFromPixelPos(MaterialParameters.SvPosition.xy); if ( GBuffer.ShadingModelID == SHADINGMODELID_SUBSURFACE_PROFILE ) { - AdjustBaseColorAndSpecularColorForSubsurfaceProfileLighting(LocalBaseColor, GBuffer.SpecularColor, LocalSpecular, bChecker); + AdjustBaseColorAndSpecularColorForSubsurfaceProfileLighting(BaseColor, GBuffer.SpecularColor, Specular, bChecker); } #endif - GBuffer.DiffuseColor = LocalBaseColor - LocalBaseColor * Metallic; + GBuffer.DiffuseColor = BaseColor - BaseColor * Metallic; #if USE_DEVELOPMENT_SHADERS { diff --git a/Engine/Shaders/Common.usf b/Engine/Shaders/Common.usf index eb33a1107482..226c5a3254ea 100644 --- a/Engine/Shaders/Common.usf +++ b/Engine/Shaders/Common.usf @@ -84,6 +84,11 @@ #endif +#if COMPILER_HLSLCC +#define ddx_fine(x) ddx(x) +#define ddy_fine(y) ddy(y) +#endif + #if POST_PROCESS_ALPHA #define SceneColorLayout float4 #define CastFloat4ToSceneColorLayout(x) (x) @@ -1082,7 +1087,8 @@ MaterialFloat3 RGBTDecode8BPC(MaterialFloat4 RGBT, MaterialFloat Range) #define HDR_ENCODE_NONE 0.0 // 64bpp HDR #define HDR_ENCODE_MOSAIC 1.0 // 32bpp HDR using Mosaic encoding -#define HDR_ENCODE_RGBA 2.0 // 32bpp HDR using RGBA encoding +#define HDR_ENCODE_RGBE 2.0 // 32bpp HDR using RGBE encoding +#define HDR_ENCODE_RGBA8 3.0 // 32bpp HDR mode without any actual encoding. half GetHDR32bppEncodeMode() { @@ -1107,12 +1113,13 @@ MaterialFloat4 Encode32BPPHDR(MaterialFloat4 Color, float2 SvPosition) { return MaterialFloat4(HdrMosaic(Color.rgb, SvPosition), Color.a); } - else if (Mode == HDR_ENCODE_RGBA) + else if (Mode == HDR_ENCODE_RGBE) { return RGBTEncode8BPC(Color.rgb, DEFAULT_32BPPHDR_ENCODED_RANGE); } - else - { + else + { + // Mode == HDR_ENCODE_NONE || Mode == HDR_ENCODE_RGBA8 return Color; } } @@ -1124,12 +1131,13 @@ MaterialFloat4 Decode32BPPHDR(MaterialFloat4 Encoded, MaterialFloat3 OtherEncode { return MaterialFloat4(HdrDemosaic(Encoded.rgb, OtherEncoded, SvPosition), 0.0f); } - if (Mode == HDR_ENCODE_RGBA) + if (Mode == HDR_ENCODE_RGBE) { return MaterialFloat4(RGBTDecode8BPC(Encoded, DEFAULT_32BPPHDR_ENCODED_RANGE), 0.0f); } - else + else { + // Mode == HDR_ENCODE_NONE || Mode == HDR_ENCODE_RGBA8 return Encoded; } } diff --git a/Engine/Shaders/DecalCommon.usf b/Engine/Shaders/DecalCommon.usf index 86b7b5b7d265..45f7d278f1f2 100644 --- a/Engine/Shaders/DecalCommon.usf +++ b/Engine/Shaders/DecalCommon.usf @@ -36,7 +36,7 @@ void DecalCommonOutput(inout FPixelShaderIn In, inout FPixelShaderOut Out, float #if (ES2_PROFILE || ES3_1_PROFILE) #if (COMPILER_GLSL_ES2 || COMPILER_GLSL_ES3_1) || (MOBILE_EMULATION) // Do decal blending if encoding requires it. - if (GetHDR32bppEncodeMode() == HDR_ENCODE_RGBA) + if (GetHDR32bppEncodeMode() == HDR_ENCODE_RGBE) { Out.MRT[0].rgb = FrameBufferDecalBlendOp(Out.MRT[0]); } diff --git a/Engine/Shaders/DeferredDecal.usf b/Engine/Shaders/DeferredDecal.usf index 010f29d99d1e..9b7c5092c863 100644 --- a/Engine/Shaders/DeferredDecal.usf +++ b/Engine/Shaders/DeferredDecal.usf @@ -156,9 +156,6 @@ void FPixelShaderInOut_MainPS(inout FPixelShaderIn In, inout FPixelShaderOut Out // make SvPosition appear to be rasterized with the depth from the depth buffer In.SvPosition.z = LookupDeviceZ(ScreenUV); - // default to no shadows, good for volumetric decals - Out.MRT[4] = 1; - const bool bVolumetric = DECAL_BLEND_MODE == DECALBLENDMODEID_VOLUMETRIC; float3 OSPosition; @@ -302,7 +299,7 @@ void FPixelShaderInOut_MainPS(inout FPixelShaderIn In, inout FPixelShaderOut Out GBufferData.Roughness = GetMaterialRoughness(PixelMaterialInputs); GBufferData.CustomData = 0; GBufferData.IndirectIrradiance = 0; - GBufferData.PrecomputedShadowFactors = 0; + GBufferData.PrecomputedShadowFactors = 1; GBufferData.GBufferAO = 1; GBufferData.ShadingModelID = SHADINGMODELID_DEFAULT_LIT; GBufferData.SelectiveOutputMask = 0; diff --git a/Engine/Shaders/DeferredLightPixelShaders.usf b/Engine/Shaders/DeferredLightPixelShaders.usf index be0282eff96b..0dc74af0d8d6 100644 --- a/Engine/Shaders/DeferredLightPixelShaders.usf +++ b/Engine/Shaders/DeferredLightPixelShaders.usf @@ -68,9 +68,10 @@ void DirectionalPixelMain( FDeferredLightData LightData = SetupLightDataForStandardDeferred(); - uint2 Random = Rand3DPCG16( uint3( SVPos.xy, View.StateFrameIndexMod8 ) ).xy; + uint2 Random = Rand3DPCG16( uint3( SVPos.xy, View.Random ) ).xy; + float Dither = InterleavedGradientNoise( SVPos.xy, View.StateFrameIndexMod8 ); - OutColor = GetDynamicLighting(WorldPosition, CameraVector, ScreenSpaceData.GBuffer, ScreenSpaceData.AmbientOcclusion, ScreenSpaceData.GBuffer.ShadingModelID, LightData, GetPerPixelLightAttenuation(InUV), Random); + OutColor = GetDynamicLighting(WorldPosition, CameraVector, ScreenSpaceData.GBuffer, ScreenSpaceData.AmbientOcclusion, ScreenSpaceData.GBuffer.ShadingModelID, LightData, GetPerPixelLightAttenuation(InUV), Dither, Random); } } @@ -105,11 +106,10 @@ void RadialPixelMain( FDeferredLightData LightData = SetupLightDataForStandardDeferred(); - uint2 Random = Rand3DPCG16( uint3( SVPos.xy, 0 ) ).xy; - Random.x ^= View.Random; - Random.y ^= View.Random; + uint2 Random = Rand3DPCG16( uint3( SVPos.xy, View.Random ) ).xy; + float Dither = InterleavedGradientNoise( SVPos.xy, View.StateFrameIndexMod8 ); - OutColor = GetDynamicLighting(WorldPosition, CameraVector, ScreenSpaceData.GBuffer, ScreenSpaceData.AmbientOcclusion, ScreenSpaceData.GBuffer.ShadingModelID, LightData, GetPerPixelLightAttenuation(ScreenUV), Random); + OutColor = GetDynamicLighting(WorldPosition, CameraVector, ScreenSpaceData.GBuffer, ScreenSpaceData.AmbientOcclusion, ScreenSpaceData.GBuffer.ShadingModelID, LightData, GetPerPixelLightAttenuation(ScreenUV), Dither, Random); OutColor *= ComputeLightProfileMultiplier(WorldPosition, DeferredLightUniforms.LightPosition, DeferredLightUniforms.NormalizedLightDirection); } } \ No newline at end of file diff --git a/Engine/Shaders/DeferredLightingCommon.usf b/Engine/Shaders/DeferredLightingCommon.usf index e9543ed7a21a..3fa64bce36b3 100644 --- a/Engine/Shaders/DeferredLightingCommon.usf +++ b/Engine/Shaders/DeferredLightingCommon.usf @@ -274,40 +274,23 @@ void GetShadowTerms(FGBufferData GBuffer, FDeferredLightData LightData, float3 W } float ShadowRayCast( - float3 RayOriginTranslatedWorld, float3 RayDirection, float ContactShadowLength, float PixelDepthLength, + float3 RayOriginTranslatedWorld, float3 RayDirection, float RayLength, int NumSteps, float StepOffset ) { - const float Epsilon = 0.001; float4 RayStartClip = mul( float4( RayOriginTranslatedWorld, 1 ), View.TranslatedWorldToClip ); - float4 RayDirClip = mul( float4( RayDirection * min(PixelDepthLength / length(RayDirection), 1.0 ), 0 ), View.TranslatedWorldToClip ); + float4 RayDirClip = mul( float4( RayDirection * RayLength, 0 ), View.TranslatedWorldToClip ); float4 RayEndClip = RayStartClip + RayDirClip; float3 RayStartScreen = RayStartClip.xyz / RayStartClip.w; float3 RayEndScreen = RayEndClip.xyz / RayEndClip.w; float3 RayStepScreen = RayEndScreen - RayStartScreen; - float2 AspectRatio = float2(1.0, View.ViewSizeAndInvSize.y * View.ViewSizeAndInvSize.z); - RayStepScreen *= min(2.0 * ContactShadowLength / length(RayStepScreen.xy * AspectRatio), 1.0); - - // Clip the ray to the screen borders. - { - float2 S = (1.0 + (RayStepScreen.xy < 0 ? 1.0.xx : -1.0.xx) * RayStartScreen.xy) / (abs(RayStepScreen.xy) + Epsilon); - RayStepScreen *= min(min(S.x, S.y), 1.0); - } - - // Avoid self colisions. - if (RayStepScreen.z < 0.0) - { - float2 RayStepPixels = RayStepScreen.xy * 0.5 * View.ViewSizeAndInvSize.xy; - RayStartScreen.xy += 2.0 * View.ViewSizeAndInvSize.zw * (1.42 * RayStepPixels / length(RayStepPixels)); - } - RayStartScreen.z += (1.0 - abs(RayDirection.z) / length(RayDirection)) * (0.008 / (PixelDepthLength * ContactShadowLength)); float3 RayStartUVz = float3( RayStartScreen.xy * View.ScreenPositionScaleBias.xy + View.ScreenPositionScaleBias.wz, RayStartScreen.z ); float3 RayStepUVz = float3( RayStepScreen.xy * View.ScreenPositionScaleBias.xy, RayStepScreen.z ); - float4 RayDepthClip = RayStartClip + mul( float4( 0, 0, ContactShadowLength * PixelDepthLength, 0 ), View.ViewToClip ); + float4 RayDepthClip = RayStartClip + mul( float4( 0, 0, RayLength, 0 ), View.ViewToClip ); float3 RayDepthScreen = RayDepthClip.xyz / RayDepthClip.w; const float Step = 1.0 / NumSteps; @@ -315,7 +298,7 @@ float ShadowRayCast( // *2 to get less morie pattern in extreme cases, larger values make object appear not grounded in reflections const float CompareTolerance = abs( RayDepthScreen.z - RayStartScreen.z ) * Step * 2; - float SampleTime = StepOffset * Step; + float SampleTime = StepOffset * Step + Step; float FirstHitTime = -1.0; @@ -383,7 +366,7 @@ void GetLocalLightAttenuation( float Length0 = LengthSqr0 * rLength0; float Length1 = LengthSqr1 * rLength1; - DistanceAttenuation = rcp( ( Length0 * Length1 + dot( ToLight0, ToLight1 ) ) * 0.5 + 1 ); + DistanceAttenuation = rcp( ( Length0 * Length1 + dot( ToLight0, ToLight1 ) ) * 0.5 + DistanceBiasSqr ); NoL = saturate( 0.5 * ( dot(N, ToLight0) * rLength0 + dot(N, ToLight1) * rLength1 ) ); } else @@ -450,7 +433,7 @@ void GetLocalLightAttenuation( } /** Calculates lighting for a given position, normal, etc with a fully featured lighting model designed for quality. */ -float4 GetDynamicLighting(float3 WorldPosition, float3 CameraVector, FGBufferData GBuffer, float AmbientOcclusion, uint ShadingModelID, FDeferredLightData LightData, float4 LightAttenuation, uint2 Random) +float4 GetDynamicLighting(float3 WorldPosition, float3 CameraVector, FGBufferData GBuffer, float AmbientOcclusion, uint ShadingModelID, FDeferredLightData LightData, float4 LightAttenuation, float Dither, uint2 Random) { FLightAccumulator LightAccumulator = (FLightAccumulator)0; @@ -489,12 +472,11 @@ float4 GetDynamicLighting(float3 WorldPosition, float3 CameraVector, FGBufferDat BRANCH if( LightData.ShadowedBits > 1 && LightData.ContactShadowLength > 0 ) { - float StepOffset = float( Random.x & 0xffff ) / (1<<16) + 0.1; - - float Shadow = ShadowRayCast( WorldPosition + View.PreViewTranslation, ToLight, LightData.ContactShadowLength, GBuffer.Depth, 8, StepOffset ); + float StepOffset = Dither - 0.5; + float Shadow = ShadowRayCast( WorldPosition + View.PreViewTranslation, L, LightData.ContactShadowLength * GBuffer.Depth, 8, StepOffset ); SurfaceShadow *= Shadow; - //SubsurfaceShadow *= Shadow; + SubsurfaceShadow *= Shadow * 0.5 + 0.5; } #endif } @@ -507,9 +489,8 @@ float4 GetDynamicLighting(float3 WorldPosition, float3 CameraVector, FGBufferDat BRANCH if( LightData.ShadowedBits < 2 && GBuffer.ShadingModelID == SHADINGMODELID_HAIR ) { - float StepOffset = float( Random.x & 0xffff ) / (1<<16) + 0.1; - - SubsurfaceShadow = ShadowRayCast( WorldPosition + View.PreViewTranslation, L, 0.1, GBuffer.Depth, 8, StepOffset ); + float StepOffset = Dither - 0.5; + SubsurfaceShadow = ShadowRayCast( WorldPosition + View.PreViewTranslation, L, 0.1 * GBuffer.Depth, 8, StepOffset ); } #endif diff --git a/Engine/Shaders/DistanceFieldLightingPost.usf b/Engine/Shaders/DistanceFieldLightingPost.usf index 7eefdebfb32e..9304cae69e2c 100644 --- a/Engine/Shaders/DistanceFieldLightingPost.usf +++ b/Engine/Shaders/DistanceFieldLightingPost.usf @@ -324,6 +324,12 @@ void FilterHistoryPS( #define IRRADIANCE_TARGET SV_Target1 #endif +// Pack into [0-1] for PF_FloatR11G11B10 +float3 EncodeBentNormal(float3 BentNormal) +{ + return BentNormal * .5f + .5f; +} + Texture2D SpecularOcclusionTexture; SamplerState SpecularOcclusionSampler; @@ -430,13 +436,13 @@ void AOUpsamplePS( #if OUTPUT_AO #if PASS_THROUGH_DEBUG_VALUE - OutBentNormal = float4(BentNormal, 1); + OutBentNormal = float4(EncodeBentNormal(BentNormal), 1); #else OutBentNormal = float4(length(BentNormal).xxx, 1); #endif #else #if OUTPUT_BENT_NORMAL - OutBentNormal = float4(BentNormal, SpecularOcclusion); + OutBentNormal = float4(EncodeBentNormal(BentNormal), SpecularOcclusion); #if SUPPORT_IRRADIANCE OutIrradiance = float4(Irradiance, 1); #endif diff --git a/Engine/Shaders/ForwardLightingCommon.usf b/Engine/Shaders/ForwardLightingCommon.usf index ee49328977d6..b6af93cf51a7 100644 --- a/Engine/Shaders/ForwardLightingCommon.usf +++ b/Engine/Shaders/ForwardLightingCommon.usf @@ -133,7 +133,7 @@ float3 GetForwardDirectLighting(uint GridIndex, float3 WorldPosition, float3 Cam float WholeSceneShadowing = LightData.DistanceFadeMAD.y < 0.0f ? DynamicShadowing : 1.0f; float4 LightAttenuation = float4(WholeSceneShadowing.xx, PerObjectShadowing.xx); - float3 NewLighting = GetDynamicLighting(WorldPosition, -CameraVector, GBufferData, 1, GBufferData.ShadingModelID, LightData, LightAttenuation, uint2(0,0)).xyz; + float3 NewLighting = GetDynamicLighting(WorldPosition, -CameraVector, GBufferData, 1, GBufferData.ShadingModelID, LightData, LightAttenuation, 0.5, uint2(0,0)).xyz; FLATTEN if ((ForwardGlobalLightData.DirectionalLightShadowMapChannelMask >> 8) & Primitive.LightingChannelMask) @@ -167,7 +167,7 @@ float3 GetForwardDirectLighting(uint GridIndex, float3 WorldPosition, float3 Cam float4 PreviewShadowMapChannelMask = UnpackShadowMapChannelMask(PackedShadowMapChannelMask >> 4); float DynamicShadowing = dot(PreviewShadowMapChannelMask, DynamicShadowFactors); float4 LightAttenuation = float4(1, 1, DynamicShadowing.x, DynamicShadowing.x); - float3 NewLighting = GetDynamicLighting(WorldPosition, -CameraVector, GBufferData, 1, GBufferData.ShadingModelID, LightData, LightAttenuation, uint2(0,0)).xyz; + float3 NewLighting = GetDynamicLighting(WorldPosition, -CameraVector, GBufferData, 1, GBufferData.ShadingModelID, LightData, LightAttenuation, 0.5, uint2(0,0)).xyz; FLATTEN if ((PackedShadowMapChannelMask >> 8) & Primitive.LightingChannelMask) diff --git a/Engine/Shaders/GlobalDistanceField.usf b/Engine/Shaders/GlobalDistanceField.usf index 676d38201fb5..35e3b0d79903 100644 --- a/Engine/Shaders/GlobalDistanceField.usf +++ b/Engine/Shaders/GlobalDistanceField.usf @@ -188,11 +188,19 @@ Buffer CulledObjectGrid; Texture3D ParentGlobalDistanceFieldTexture; RWTexture3D RWGlobalDistanceFieldTexture; -#ifndef COMPOSITE_THREADGROUP_SIZE -#define COMPOSITE_THREADGROUP_SIZE 1 +#ifndef COMPOSITE_THREADGROUP_SIZEX +#define COMPOSITE_THREADGROUP_SIZEX 1 #endif -#define COMPOSITE_THREADGORUP_TOTALSIZE (COMPOSITE_THREADGROUP_SIZE * COMPOSITE_THREADGROUP_SIZE * COMPOSITE_THREADGROUP_SIZE) +#ifndef COMPOSITE_THREADGROUP_SIZEY +#define COMPOSITE_THREADGROUP_SIZEY 1 +#endif + +#ifndef COMPOSITE_THREADGROUP_SIZEZ +#define COMPOSITE_THREADGROUP_SIZEZ 1 +#endif + +#define COMPOSITE_THREADGORUP_TOTALSIZE (COMPOSITE_THREADGROUP_SIZEX * COMPOSITE_THREADGROUP_SIZEY * COMPOSITE_THREADGROUP_SIZEZ) #define MAX_CULLED_DF_OBJECTS 512 groupshared uint SharedCulledObjectList[MAX_CULLED_DF_OBJECTS]; @@ -200,7 +208,7 @@ groupshared uint NumTileCulledObjects; #define USE_CULL_GRID 1 -[numthreads(COMPOSITE_THREADGROUP_SIZE, COMPOSITE_THREADGROUP_SIZE, COMPOSITE_THREADGROUP_SIZE)] +[numthreads(COMPOSITE_THREADGROUP_SIZEX, COMPOSITE_THREADGROUP_SIZEY, COMPOSITE_THREADGROUP_SIZEZ)] void CompositeObjectDistanceFieldsCS( uint3 GroupId : SV_GroupID, uint3 DispatchThreadId : SV_DispatchThreadID, @@ -218,10 +226,11 @@ void CompositeObjectDistanceFieldsCS( GroupMemoryBarrierWithGroupSync(); - uint ThreadIndex = (GroupThreadId.z * COMPOSITE_THREADGROUP_SIZE + GroupThreadId.y) * COMPOSITE_THREADGROUP_SIZE + GroupThreadId.x; + uint ThreadIndex = (GroupThreadId.z * COMPOSITE_THREADGROUP_SIZEY + GroupThreadId.y) * COMPOSITE_THREADGROUP_SIZEX + GroupThreadId.x; - float3 TileBoxExtent = .5f * COMPOSITE_THREADGROUP_SIZE * VolumeTexelSize * GlobalVolumeExtent * 2; - float3 TileBoxCenter = UpdateRegionVolumeMin + ((GroupId.xyz + .5f) * COMPOSITE_THREADGROUP_SIZE + .5f) * VolumeTexelSize * GlobalVolumeExtent * 2; + float3 GroupSize = float3(COMPOSITE_THREADGROUP_SIZEX, COMPOSITE_THREADGROUP_SIZEY, COMPOSITE_THREADGROUP_SIZEZ); + float3 TileBoxExtent = .5f * GroupSize * VolumeTexelSize * GlobalVolumeExtent * 2; + float3 TileBoxCenter = UpdateRegionVolumeMin + ((GroupId.xyz + .5f) * GroupSize + .5f) * VolumeTexelSize * GlobalVolumeExtent * 2; #if USE_CULL_GRID uint GridBaseIndex = ComputeGridBaseIndex(DispatchThreadId / CULL_GRID_TILE_SIZE); diff --git a/Engine/Shaders/GpuSkinVertexFactory.usf b/Engine/Shaders/GpuSkinVertexFactory.usf index 191ed808c6b3..07309d12a0b8 100644 --- a/Engine/Shaders/GpuSkinVertexFactory.usf +++ b/Engine/Shaders/GpuSkinVertexFactory.usf @@ -539,8 +539,16 @@ FVertexFactoryInterpolantsVSToPS VertexFactoryGetInterpolantsVSToPS(FVertexFacto { FVertexFactoryInterpolantsVSToPS Interpolants; -#if NUM_MATERIAL_TEXCOORDS - GetMaterialCustomizedUVs(VertexParameters, Interpolants.TexCoords); +#if NUM_TEX_COORD_INTERPOLATORS + float2 CustomizedUVs[NUM_TEX_COORD_INTERPOLATORS]; + GetMaterialCustomizedUVs(VertexParameters, CustomizedUVs); + GetCustomInterpolators(VertexParameters, CustomizedUVs); + + UNROLL + for (int CoordinateIndex = 0; CoordinateIndex < NUM_TEX_COORD_INTERPOLATORS; CoordinateIndex++) + { + Interpolants.TexCoords[CoordinateIndex] = CustomizedUVs[CoordinateIndex]; + } #endif Interpolants.TangentToWorld0.w = 0; diff --git a/Engine/Shaders/HeightFogCommon.usf b/Engine/Shaders/HeightFogCommon.usf index 1eaac6d5691c..cabe94834464 100644 --- a/Engine/Shaders/HeightFogCommon.usf +++ b/Engine/Shaders/HeightFogCommon.usf @@ -110,9 +110,10 @@ half4 GetExponentialHeightFog(float3 WorldPositionRelativeToCamera, float Exclud // Calculate the line integral of the ray from the camera to the receiver position through the fog density function // The exponential fog density function is d = GlobalDensity * exp(-HeightFalloff * z) - float EffectiveZ = (abs(RayDirectionZ) > FLT_EPSILON2) ? RayDirectionZ : FLT_EPSILON2; - float Falloff = max(-127.0f, ExponentialFogParameters.y * EffectiveZ); // if it's lower than -127.0, then exp2() goes crazy in OpenGL's GLSL. - float ExponentialHeightLineIntegralShared = RayOriginTerms * (1.0f - exp2(-Falloff) ) / Falloff; + float Falloff = max(-127.0f, ExponentialFogParameters.y * RayDirectionZ); // if it's lower than -127.0, then exp2() goes crazy in OpenGL's GLSL. + float LineIntegral = ( 1.0f - exp2(-Falloff) ) / Falloff; + float LineIntegralTaylor = log(2.0) - ( 0.5 * Pow2( log(2.0) ) ) * Falloff; // Taylor expansion around 0 + float ExponentialHeightLineIntegralShared = RayOriginTerms * ( abs(Falloff) > FLT_EPSILON2 ? LineIntegral : LineIntegralTaylor ); float ExponentialHeightLineIntegral = ExponentialHeightLineIntegralShared * RayLength; half3 InscatteringColor = ComputeInscatteringColor(CameraToReceiver, CameraToReceiverLength); diff --git a/Engine/Shaders/LandscapeVertexFactory.usf b/Engine/Shaders/LandscapeVertexFactory.usf index ce0467f9eb5f..86fa99cbd7ca 100644 --- a/Engine/Shaders/LandscapeVertexFactory.usf +++ b/Engine/Shaders/LandscapeVertexFactory.usf @@ -158,9 +158,7 @@ struct FVertexFactoryIntermediates { float4 InputPosition; float3 LocalPosition; -#if USING_TESSELLATION float3 WorldNormal; -#endif }; float3 GetLocalPosition(FVertexFactoryIntermediates Intermediates) @@ -642,13 +640,15 @@ FVertexFactoryIntermediates GetVertexFactoryIntermediates(FVertexFactoryInput In Intermediates.LocalPosition = lerp( float3(InputPositionLODAdjusted, Height), float3(InputPositionNextLOD, HeightNextLOD), MorphAlpha ); -#if USING_TESSELLATION +#if FEATURE_LEVEL >= FEATURE_LEVEL_SM4 float2 Normal = float2(SampleValue.b, SampleValue.a); float2 NormalNextLOD = float2(SampleValueNextLOD.b, SampleValueNextLOD.a); float2 InterpNormal = lerp( Normal, NormalNextLOD, MorphAlpha ) * float2(2.0,2.0) - float2(1.0,1.0); Intermediates.WorldNormal = float3( InterpNormal, sqrt(max(1.0-dot(InterpNormal,InterpNormal),0.0)) ); +#else + Intermediates.WorldNormal = float3( 0.0, 0.0, 1.0 ); #endif - + return Intermediates; } @@ -687,7 +687,7 @@ float2 LandscapeVertexFactorySampleHeight(FVertexFactoryInput Input, FVertexFact */ float3x3 VertexFactoryGetTangentToLocal( FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates ) { - float3x3 Result = float3x3(float3(1,0,0),float3(0,1,0),float3(0,0,1)); + float3x3 Result = CalcTangentBasisFromWorldNormal(Intermediates.WorldNormal); return Result; } diff --git a/Engine/Shaders/LightGridInjection.usf b/Engine/Shaders/LightGridInjection.usf index 61d05acd5152..8abb53221996 100644 --- a/Engine/Shaders/LightGridInjection.usf +++ b/Engine/Shaders/LightGridInjection.usf @@ -18,7 +18,7 @@ float ComputeDepthFromZSlice(uint ZSlice) { float SliceDepth = (exp2(ZSlice / ForwardGlobalLightData.LightGridZParams.z) - ForwardGlobalLightData.LightGridZParams.y) / ForwardGlobalLightData.LightGridZParams.x; - if (ZSlice == ForwardGlobalLightData.CulledGridSize.z) + if (ZSlice == (uint)ForwardGlobalLightData.CulledGridSize.z) { // Extend the last slice depth max out to world max // This allows clamping the depth range to reasonable values, @@ -53,25 +53,47 @@ void ComputeCellViewAABB(uint3 GridCoordinate, out float3 ViewTileMin, out float float4 MaxDepthCorner2 = mul(float4(UnitPlaneTileMin.x, UnitPlaneTileMax.y, MaxTileDeviceZ, 1), View.ClipToView); float4 MaxDepthCorner3 = mul(float4(UnitPlaneTileMax.x, UnitPlaneTileMin.y, MaxTileDeviceZ, 1), View.ClipToView); - //@todo - derive min and max from quadrant - ViewTileMin.xy = min(MinDepthCorner0.xy / MinDepthCorner0.w, MinDepthCorner1.xy / MinDepthCorner1.w); - ViewTileMin.xy = min(ViewTileMin.xy, MinDepthCorner2.xy / MinDepthCorner2.w); - ViewTileMin.xy = min(ViewTileMin.xy, MinDepthCorner3.xy / MinDepthCorner3.w); - ViewTileMin.xy = min(ViewTileMin.xy, MaxDepthCorner0.xy / MaxDepthCorner0.w); - ViewTileMin.xy = min(ViewTileMin.xy, MaxDepthCorner1.xy / MaxDepthCorner1.w); - ViewTileMin.xy = min(ViewTileMin.xy, MaxDepthCorner2.xy / MaxDepthCorner2.w); - ViewTileMin.xy = min(ViewTileMin.xy, MaxDepthCorner3.xy / MaxDepthCorner3.w); + float2 ViewMinDepthCorner0 = MinDepthCorner0.xy / MinDepthCorner0.w; + float2 ViewMinDepthCorner1 = MinDepthCorner1.xy / MinDepthCorner1.w; + float2 ViewMinDepthCorner2 = MinDepthCorner2.xy / MinDepthCorner2.w; + float2 ViewMinDepthCorner3 = MinDepthCorner3.xy / MinDepthCorner3.w; + float2 ViewMaxDepthCorner0 = MaxDepthCorner0.xy / MaxDepthCorner0.w; + float2 ViewMaxDepthCorner1 = MaxDepthCorner1.xy / MaxDepthCorner1.w; + float2 ViewMaxDepthCorner2 = MaxDepthCorner2.xy / MaxDepthCorner2.w; + float2 ViewMaxDepthCorner3 = MaxDepthCorner3.xy / MaxDepthCorner3.w; - ViewTileMax.xy = max(MinDepthCorner0.xy / MinDepthCorner0.w, MinDepthCorner1.xy / MinDepthCorner1.w); - ViewTileMax.xy = max(ViewTileMax.xy, MinDepthCorner2.xy / MinDepthCorner2.w); - ViewTileMax.xy = max(ViewTileMax.xy, MinDepthCorner3.xy / MinDepthCorner3.w); - ViewTileMax.xy = max(ViewTileMax.xy, MaxDepthCorner0.xy / MaxDepthCorner0.w); - ViewTileMax.xy = max(ViewTileMax.xy, MaxDepthCorner1.xy / MaxDepthCorner1.w); - ViewTileMax.xy = max(ViewTileMax.xy, MaxDepthCorner2.xy / MaxDepthCorner2.w); - ViewTileMax.xy = max(ViewTileMax.xy, MaxDepthCorner3.xy / MaxDepthCorner3.w); + //@todo - derive min and max from quadrant + ViewTileMin.xy = min(ViewMinDepthCorner0, ViewMinDepthCorner1); + ViewTileMin.xy = min(ViewTileMin.xy, ViewMinDepthCorner2); + ViewTileMin.xy = min(ViewTileMin.xy, ViewMinDepthCorner3); + ViewTileMin.xy = min(ViewTileMin.xy, ViewMaxDepthCorner0); + ViewTileMin.xy = min(ViewTileMin.xy, ViewMaxDepthCorner1); + ViewTileMin.xy = min(ViewTileMin.xy, ViewMaxDepthCorner2); + ViewTileMin.xy = min(ViewTileMin.xy, ViewMaxDepthCorner3); + + ViewTileMax.xy = max(ViewMinDepthCorner0, ViewMinDepthCorner1); + ViewTileMax.xy = max(ViewTileMax.xy, ViewMinDepthCorner2); + ViewTileMax.xy = max(ViewTileMax.xy, ViewMinDepthCorner3); + ViewTileMax.xy = max(ViewTileMax.xy, ViewMaxDepthCorner0); + ViewTileMax.xy = max(ViewTileMax.xy, ViewMaxDepthCorner1); + ViewTileMax.xy = max(ViewTileMax.xy, ViewMaxDepthCorner2); + ViewTileMax.xy = max(ViewTileMax.xy, ViewMaxDepthCorner3); ViewTileMin.z = MinTileZ; - ViewTileMax.z = MaxTileZ; + ViewTileMax.z = MaxTileZ; +} + +bool IntersectConeWithSphere(float3 ConeVertex, float3 ConeAxis, float ConeRadius, float2 CosSinAngle, float4 SphereToTest) +{ + float3 ConeVertexToSphereCenter = SphereToTest.xyz - ConeVertex; + float ConeVertexToSphereCenterLengthSq = dot(ConeVertexToSphereCenter, ConeVertexToSphereCenter); + float SphereProjectedOntoConeAxis = dot(ConeVertexToSphereCenter, -ConeAxis); + float DistanceToClosestPoint = CosSinAngle.x * sqrt(ConeVertexToSphereCenterLengthSq - SphereProjectedOntoConeAxis * SphereProjectedOntoConeAxis) - SphereProjectedOntoConeAxis * CosSinAngle.y; + + bool bSphereTooFarFromCone = DistanceToClosestPoint > SphereToTest.w; + bool bSpherePastConeEnd = SphereProjectedOntoConeAxis > SphereToTest.w + ConeRadius; + bool bSphereBehindVertex = SphereProjectedOntoConeAxis < -SphereToTest.w; + return !(bSphereTooFarFromCone || bSpherePastConeEnd || bSphereBehindVertex); } [numthreads(THREADGROUP_SIZE, THREADGROUP_SIZE, THREADGROUP_SIZE)] @@ -82,7 +104,7 @@ void LightGridInjectionCS( { uint3 GridCoordinate = DispatchThreadId; - if (all(GridCoordinate < ForwardGlobalLightData.CulledGridSize)) + if (all(GridCoordinate < (uint3)ForwardGlobalLightData.CulledGridSize)) { uint GridIndex = (GridCoordinate.z * ForwardGlobalLightData.CulledGridSize.y + GridCoordinate.y) * ForwardGlobalLightData.CulledGridSize.x + GridCoordinate.x; @@ -95,6 +117,8 @@ void LightGridInjectionCS( float3 ViewTileCenter = .5f * (ViewTileMin + ViewTileMax); float3 ViewTileExtent = ViewTileMax - ViewTileCenter; + float3 WorldTileCenter = mul(float4(ViewTileCenter, 1), View.ViewToTranslatedWorld).xyz - View.PreViewTranslation; + float4 WorldTileBoundingSphere = float4(WorldTileCenter, length(ViewTileExtent)); uint NumAvailableLinks = ForwardGlobalLightData.NumGridCells * ForwardGlobalLightData.MaxCulledLightsPerCell * NUM_CULLED_GRID_PRIMITIVE_TYPES; @@ -104,14 +128,19 @@ void LightGridInjectionCS( uint LocalLightBaseIndex = LocalLightIndex * LOCAL_LIGHT_DATA_STRIDE; float4 LightPositionAndInvRadius = ForwardLocalLightBuffer[LocalLightBaseIndex + 0]; float LightRadius = 1.0f / LightPositionAndInvRadius.w; + bool bPassSpotlightTest = true; #define REFINE_SPOTLIGHT_BOUNDS 1 #if REFINE_SPOTLIGHT_BOUNDS float CosOuterCone = ForwardLocalLightBuffer[LocalLightBaseIndex + 3].x; - + if (CosOuterCone > -2.0f) { + float2 CosSinAngle = float2(CosOuterCone, sqrt(1 - CosOuterCone * CosOuterCone)); float3 LightDirection = ForwardLocalLightBuffer[LocalLightBaseIndex + 2].xyz; + + bPassSpotlightTest = IntersectConeWithSphere(LightPositionAndInvRadius.xyz, LightDirection, LightRadius, CosSinAngle, WorldTileBoundingSphere); + LightPositionAndInvRadius.xyz -= .5f * LightDirection * LightRadius; // Use the law of cosines to find the distance to the furthest edge of the spotlight cone from a position that is halfway down the spotlight direction LightRadius = sqrt(1.25f * LightRadius * LightRadius - LightRadius * LightRadius * CosOuterCone); @@ -122,7 +151,7 @@ void LightGridInjectionCS( float BoxDistanceSq = ComputeSquaredDistanceFromBoxToPoint(ViewTileCenter, ViewTileExtent, ViewSpaceLightPosition); - if (BoxDistanceSq < LightRadius * LightRadius) + if (BoxDistanceSq < LightRadius * LightRadius && bPassSpotlightTest) { #if USE_LINKED_CULL_LIST uint NextLink; diff --git a/Engine/Shaders/LocalVertexFactory.usf b/Engine/Shaders/LocalVertexFactory.usf index 09cca853d52b..1ed9008b1993 100644 --- a/Engine/Shaders/LocalVertexFactory.usf +++ b/Engine/Shaders/LocalVertexFactory.usf @@ -108,7 +108,7 @@ struct FVertexFactoryInput #if NUM_MATERIAL_TEXCOORDS_VERTEX #if GPUSKIN_PASS_THROUGH // These must match GPUSkinVertexFactory.usf - float2 TexCoords[NUM_MATERIAL_TEXCOORDS_VERTEX] : ATTRIBUTE5; + float2 TexCoords[NUM_MATERIAL_TEXCOORDS_VERTEX] : ATTRIBUTE4; #if NUM_MATERIAL_TEXCOORDS_VERTEX > 4 #error Too many texture coordinate sets defined on GPUSkin vertex input. Max: 4. #endif diff --git a/Engine/Shaders/MaterialTemplate.usf b/Engine/Shaders/MaterialTemplate.usf index 655e25f34fa8..3e2335aca617 100644 --- a/Engine/Shaders/MaterialTemplate.usf +++ b/Engine/Shaders/MaterialTemplate.usf @@ -5,6 +5,7 @@ */ #include "Random.usf" +#include "MonteCarlo.usf" #include "UniformBuffers/Material.usf" // for MaterialExpressionDepthOfFieldFunction @@ -767,9 +768,10 @@ MaterialFloat4 ProcessMaterialColorTextureLookup(MaterialFloat4 TextureValue) TextureValue.rgb = pow(TextureValue.rgb, 1.0f / 2.2f); // TODO: replace with a more accurate lin -> sRGB conversion. } #endif - - // sRGB read approximation - TextureValue.rgb *= TextureValue.rgb; + // sRGB read approximation (in highp if possible) + float3 LinRGB = TextureValue.rgb; + LinRGB *= LinRGB; + return MaterialFloat4(LinRGB, TextureValue.a); #endif return TextureValue; } @@ -789,8 +791,10 @@ MaterialFloat ProcessMaterialGreyscaleTextureLookup(MaterialFloat TextureValue) TextureValue = pow(TextureValue, 1.0f/2.2f); // TODO: replace with a more accurate lin -> sRGB conversion. } #endif - // sRGB read approximation - TextureValue *= TextureValue; + // sRGB read approximation (in highp if possible) + float LinValue = TextureValue; + LinValue *= LinValue; + return MaterialFloat(LinValue); #endif return TextureValue; } @@ -1743,8 +1747,15 @@ void GetMaterialCoverageAndClipping(FMaterialPixelParameters Parameters, FPixelM //float Dither5 = ( ( (uint)Parameters.SvPosition.x + (uint)Parameters.SvPosition.y * 2 + (uint)View.TemporalAAParams.x ) % 5 ) / 5.0; float Dither5 = frac( ( Parameters.SvPosition.x + Parameters.SvPosition.y * 2 - 1.5 + View.TemporalAAParams.x ) / 5 ); float Noise = frac( dot( float2( 171.0, 231.0 ) / 71, Parameters.SvPosition.xy ) ); - float Dither = ( Dither5 * 5 + Noise ) * (1.0 / 6.0) - 0.5; - clip( GetMaterialMask(PixelMaterialInputs) + Dither ); + float Dither = ( Dither5 * 5 + Noise ) * (1.0 / 6.0); + + float2 DepthGrad = { + ddx( Parameters.SvPosition.z ), + ddy( Parameters.SvPosition.z ) + }; + Dither = frac( Dither + dot( DepthGrad, float2( 4093, 3571 ) ) ); + + clip( GetMaterialMask(PixelMaterialInputs) + Dither - 0.5 ); #else clip(GetMaterialMask(PixelMaterialInputs)); #endif diff --git a/Engine/Shaders/MeshDecals.usf b/Engine/Shaders/MeshDecals.usf index 918cc96d6644..17a5a4aa8d94 100644 --- a/Engine/Shaders/MeshDecals.usf +++ b/Engine/Shaders/MeshDecals.usf @@ -8,9 +8,23 @@ #include "Material.usf" #include "VertexFactory.usf" +// Additional guard to remove all struct usage if empty to avoid platform conflicts. +// This define can be removed if additional data is added to the interpolants struct +#define NEED_MESH_DECAL_INTERPOLATORS USE_WORLD_POSITION_EXCLUDING_SHADER_OFFSETS + +struct FMeshDecalInterpolants +{ +#if USE_WORLD_POSITION_EXCLUDING_SHADER_OFFSETS + float3 PixelPositionExcludingWPO : TEXCOORD8; // Arbitrary free slot +#endif +}; + struct FMeshDecalVSToPS { FVertexFactoryInterpolantsVSToPS FactoryInterpolants; +#if NEED_MESH_DECAL_INTERPOLATORS + FMeshDecalInterpolants MeshDecalInterpolants; +#endif float4 Position : SV_POSITION; }; @@ -18,6 +32,9 @@ struct FMeshDecalVSToPS struct FMeshDecalVSToDS { FVertexFactoryInterpolantsVSToDS FactoryInterpolants; + #if NEED_MESH_DECAL_INTERPOLATORS + FMeshDecalInterpolants MeshDecalInterpolants; + #endif float4 Position : VS_To_DS_Position; OPTIONAL_VertexID_VS_To_DS }; @@ -38,6 +55,10 @@ struct FMeshDecalVSToPS O.FactoryInterpolants = VertexFactoryInterpolate(a.FactoryInterpolants, aInterp, b.FactoryInterpolants, bInterp); + #if USE_WORLD_POSITION_EXCLUDING_SHADER_OFFSETS + INTERPOLATE_MEMBER(MeshDecalInterpolants.PixelPositionExcludingWPO); + #endif + return O; } @@ -48,6 +69,10 @@ struct FMeshDecalVSToPS FMeshDecalVSToPS O; O.FactoryInterpolants = VertexFactoryAssignInterpolants(Interpolants.FactoryInterpolants); + + #if USE_WORLD_POSITION_EXCLUDING_SHADER_OFFSETS + O.MeshDecalInterpolants.PixelPositionExcludingWPO = Interpolants.MeshDecalInterpolants.PixelPositionExcludingWPO; + #endif // Finally, transform position to clip-space O.Position = mul(WorldPosition, View.TranslatedWorldToClip); @@ -72,9 +97,13 @@ void MainVS( ResolvedView = ResolveView(); FVertexFactoryIntermediates VFIntermediates = GetVertexFactoryIntermediates(Input); - float4 WorldPosition = VertexFactoryGetWorldPosition(Input, VFIntermediates); + float4 WorldPosition = VertexFactoryGetWorldPosition(Input, VFIntermediates); float3x3 TangentToLocal = VertexFactoryGetTangentToLocal(Input, VFIntermediates); +#if USE_WORLD_POSITION_EXCLUDING_SHADER_OFFSETS + Output.MeshDecalInterpolants.PixelPositionExcludingWPO = WorldPosition.xyz; +#endif + FMaterialVertexParameters VertexParameters = GetMaterialVertexParameters(Input, VFIntermediates, WorldPosition.xyz, TangentToLocal); // Isolate instructions used for world position offset on xbox 360, // As these cause the optimizer to generate different position calculating instructions in each pass, resulting in self-z-fighting. @@ -115,23 +144,35 @@ void MainVS( // is called in MainPS() from PixelShaderOutputCommon.usf void FPixelShaderInOut_MainPS( - FVertexFactoryInterpolantsVSToPS Interpolants, + FVertexFactoryInterpolantsVSToPS FactoryInterpolants, +#if NEED_MESH_DECAL_INTERPOLATORS + FMeshDecalInterpolants MeshDecalInterpolants, +#endif inout FPixelShaderIn In, inout FPixelShaderOut Out) { #if INSTANCED_STEREO - ResolvedView = ResolveView(GetEyeIndex(Interpolants.PackedEyeIndex)); + ResolvedView = ResolveView(GetEyeIndex(FactoryInterpolants.PackedEyeIndex)); #else ResolvedView = ResolveView(); #endif - FMaterialPixelParameters MaterialParameters = GetMaterialPixelParameters(Interpolants, In.SvPosition); - - // default to no shadows, good for volumetric decals - Out.MRT[4] = 1; + FMaterialPixelParameters MaterialParameters = GetMaterialPixelParameters(FactoryInterpolants, In.SvPosition); FPixelMaterialInputs PixelMaterialInputs; - CalcPixelMaterialInputs(MaterialParameters, PixelMaterialInputs); +#if USE_WORLD_POSITION_EXCLUDING_SHADER_OFFSETS + { + float4 ScreenPosition = SvPositionToResolvedScreenPosition(In.SvPosition); + float3 TranslatedWorldPosition = SvPositionToResolvedTranslatedWorld(In.SvPosition); + CalcMaterialParametersEx(MaterialParameters, PixelMaterialInputs, In.SvPosition, ScreenPosition, In.bIsFrontFace, TranslatedWorldPosition, MeshDecalInterpolants.PixelPositionExcludingWPO); + } +#else + { + float4 ScreenPosition = SvPositionToResolvedScreenPosition(In.SvPosition); + float3 TranslatedWorldPosition = SvPositionToResolvedTranslatedWorld(In.SvPosition); + CalcMaterialParametersEx(MaterialParameters, PixelMaterialInputs, In.SvPosition, ScreenPosition, In.bIsFrontFace, TranslatedWorldPosition, TranslatedWorldPosition); + } +#endif // Store the results in local variables and reuse instead of calling the functions multiple times. half3 BaseColor = GetMaterialBaseColor(PixelMaterialInputs); @@ -165,7 +206,7 @@ void FPixelShaderInOut_MainPS( GBufferData.Roughness = GetMaterialRoughness(PixelMaterialInputs); GBufferData.CustomData = 0; GBufferData.IndirectIrradiance = 0; - GBufferData.PrecomputedShadowFactors = 0; + GBufferData.PrecomputedShadowFactors = 1; GBufferData.GBufferAO = 1; GBufferData.ShadingModelID = SHADINGMODELID_DEFAULT_LIT; GBufferData.SelectiveOutputMask = 0; @@ -175,6 +216,7 @@ void FPixelShaderInOut_MainPS( } +#define PIXELSHADEROUTPUT_MESHDECALPASS NEED_MESH_DECAL_INTERPOLATORS #define PIXELSHADEROUTPUT_INTERPOLANTS 1 #define PIXELSHADEROUTPUT_MRT0 (DECAL_RENDERTARGET_COUNT > 0) #define PIXELSHADEROUTPUT_MRT1 (DECAL_RENDERTARGET_COUNT > 1 && (BIND_RENDERTARGET1 || COMPILER_METAL)) diff --git a/Engine/Shaders/MetalCommon.usf b/Engine/Shaders/MetalCommon.usf index 4d3ff4f81fef..befd342aec14 100644 --- a/Engine/Shaders/MetalCommon.usf +++ b/Engine/Shaders/MetalCommon.usf @@ -5,7 +5,7 @@ =============================================================================*/ // Update this GUID to improve shader recompilation for Metal only shaders -// GUID = {4C28BE9A-DE1D-4F9A-BE92-8098E5EF45B8} +// GUID = {2D5E385E-6E4F-452C-A3B3-74CEDEB279DB} #pragma once diff --git a/Engine/Shaders/MobileBasePassPixelShader.usf b/Engine/Shaders/MobileBasePassPixelShader.usf index 48d2ee3230ec..989af1b5319c 100644 --- a/Engine/Shaders/MobileBasePassPixelShader.usf +++ b/Engine/Shaders/MobileBasePassPixelShader.usf @@ -451,6 +451,7 @@ void Main( Settings.TransitionScale = MobileDirectionalLight.DirectionalLightShadowTransition; Settings.ShadowBufferSize = MobileDirectionalLight.DirectionalLightShadowSize; Settings.bSubsurface = false; + Settings.bTreatMaxDepthUnshadowed = false; Settings.DensityMulConstant = 0; Settings.ProjectionDepthBiasParameters = 0; @@ -559,7 +560,7 @@ void Main( } #if !FULLY_ROUGH - Color += (Attenuation * PointNoL) * LightColorAndFalloffExponent[i].rgb * (DiffuseColor + SpecularColor * PhongApprox(Roughness, PointRoL)); + Color += min(65000.0, (Attenuation * PointNoL) * LightColorAndFalloffExponent[i].rgb * (DiffuseColor + SpecularColor * PhongApprox(Roughness, PointRoL))); #else Color += (Attenuation * PointNoL) * LightColorAndFalloffExponent[i].rgb * DiffuseColor; #endif @@ -627,9 +628,9 @@ void Main( OutColor *= ClipForEditorPrimitives(MaterialParameters); clip(OutColor.a - GetMaterialOpacityMaskClipValue()); #else - #if ES2_PROFILE && !OUTPUT_GAMMA_SPACE + #if ES2_PROFILE && !OUTPUT_GAMMA_SPACE && !MATERIALDOMAIN_UI half Mode = GetHDR32bppEncodeMode(); - if (Mode == HDR_ENCODE_RGBA) + if (Mode == HDR_ENCODE_RGBE) { OutColor.rgb = FrameBufferBlendOp(OutColor); OutColor = RGBTEncode8BPC(OutColor.rgb, DEFAULT_32BPPHDR_ENCODED_RANGE); diff --git a/Engine/Shaders/MonteCarlo.usf b/Engine/Shaders/MonteCarlo.usf index cfd135271bbd..77e1254c29d0 100644 --- a/Engine/Shaders/MonteCarlo.usf +++ b/Engine/Shaders/MonteCarlo.usf @@ -28,6 +28,101 @@ float2 Hammersley( uint Index, uint NumSamples, uint2 Random ) return float2( E1, E2 ); } +/////// +// Typical usage of the Sobol functions below: +// 1: uint4 base = PixelSobol(uint2(SvPosition.xy), View.FrameNumber); // Sample 0 at pixel current frame +// 2: uint4 rand = base; +// 3: float2 point0 = float2(rand.xy) / 0x1000000; // 2D point from first independent 2D sample set, in [0,1) x [0,1) +// 4: float2 point1 = float2(rand.zw) / 0x1000000; // 2D point from second 2D sample set, in [0,1) x [0,1) +// ... +// 5: rand = DirectSobol(base, 1); // Sample 1 for current pixel/frame +// ... +// 6: rand = DirectSobol(base, 2); // Sample 2 for current pixel/frame (up to sample 1023) +// Equivalent and possibly slightly faster +// 1-4: As above +// 5: rand = NextSobol(rand, 1); +// ... +// 6: rand = NextSobol(rand, 2); +// If index is not constant (or in an unrolled loop), can use Bits argument to DirectSobol +// for(int i=1; i<7; ++i) +// rand = DirectSobol(base, i, 3); // since i <= 3 bits +// +// Frame is just the bottom three bits of a global index. If changing per frame isn't needed, use +// PixelSobol(uint2(SvPosition.xy), Index); // for Index in [0,7] +// DirectSobol(PixelSobol(..., Index & 7), Index >> 3) // for Index in [0, 8191] +// +// In all cases, if more than two 2D streams are needed, xor base with a random 24-bit-per-component uint2 seed + +// Evaluate initial Sobol points for a pixel +// @param PixelPos Screen position +// @param Frame Current frame number or frame mod 8 (only uses bottom 3 bits) +// @return four 16-bit Sobol numbers in the range 0 to 0xffff +uint4 PixelSobol(uint2 PixelPos, uint Frame) +{ + // look up for pixel + int3 SobolCoord = int3(PixelPos, 0) & 0xff; + uint4 Result = View.SobolSamplingTexture.Load(SobolCoord); + + // factor in frame number + Result ^= (Frame & 1) ? uint4(0xfb00u, 0xc700u, 0x8680u, 0x4c80u) : 0; + Result ^= (Frame & 2) ? uint4(0x50c0u, 0x9740u, 0xf240u, 0x9240u) : 0; + Result ^= (Frame & 4) ? uint4(0x06e0u, 0x8fa0u, 0x8220u, 0x0e20u) : 0; + return Result; +} + +// Evaluate Sobol sequence directly from sequence index +// @param Base Base Sobol values for this pixel +// @param Index Which 4D Sobol point to return +// @param Bits Optional max bits in index (to avoid extra calculation) +// @return four 16-bit Sobol numbers in the range 0 to 0xffff +uint4 DirectSobol(uint4 Base, int Index, int Bits = 10) +{ + uint4 SobolNumbers[10] = { + uint4(0x2c10u, 0xfab0u, 0x4110u, 0x1610u), + uint4(0xe868u, 0x0a08u, 0xa608u, 0x7608u), + uint4(0x880eu, 0x821eu, 0x8a02u, 0x280au), + uint4(0x0c5cu, 0x9e54u, 0xe204u, 0x9e04u), + uint4(0xe945u, 0xf8edu, 0xa400u, 0x4682u), + uint4(0x8068u, 0x0f80u, 0xe300u, 0xa74du), + uint4(0x660eu, 0x8580u, 0xb700u, 0x9817u), + uint4(0x905cu, 0x9000u, 0x4501u, 0x1405u), + uint4(0xbc45u, 0xf380u, 0x0c00u, 0x5826u), + uint4(0x00e8u, 0x0780u, 0x2600u, 0x760bu), + }; + + uint4 Result = Base; + UNROLL for (int b = 0; b < 10 && b < Bits; ++b) + { + Result ^= (Index & (1 << b)) ? SobolNumbers[b] : 0; + } + return Result; +} + +// Evaluate Sobol sequence sequentially from previous value and index +// @param Previous Sobol values for index-1 +// @param Index Which 4D Sobol point to return. Must be in the range 1 to 1023 +// @return four 16-bit Sobol numbers in the range 0 to 0xffff +// matches DirectSobol, but more efficient when computing sequential values +uint4 NextSobol(uint4 Previous, int Index) +{ + // SobolGray[i] is SobolNumbers[0] ^ SobolNumbers[1] ^ ... ^ SobolNumbers[i] + uint4 SobolGray[10] = { + uint4(0x2c10u, 0xfab0u, 0x4110u, 0x1610u), + uint4(0xc478u, 0xf0b8u, 0xe718u, 0x6018u), + uint4(0x4c76u, 0x72a6u, 0x6d1au, 0x4812u), + uint4(0x402au, 0xecf2u, 0x8f1eu, 0xd616u), + uint4(0xa96fu, 0x141fu, 0x2b1eu, 0x9094u), + uint4(0x2907u, 0x1b9fu, 0xc81eu, 0x37d9u), + uint4(0x4f09u, 0x9e1fu, 0x7f1eu, 0xafceu), + uint4(0xdf55u, 0x0e1fu, 0x3a1fu, 0xbbcbu), + uint4(0x6310u, 0xfd9fu, 0x361fu, 0xe3edu), + uint4(0x63f8u, 0xfa1fu, 0x101fu, 0x95e6u) + }; + + return Previous ^ SobolGray[firstbitlow(Index)]; +} + +/////// float4 UniformSampleSphere( float2 E ) { float Phi = 2 * PI * E.x; diff --git a/Engine/Shaders/MorphTargets.usf b/Engine/Shaders/MorphTargets.usf index 2de9851b7ae6..fa63518ebad7 100644 --- a/Engine/Shaders/MorphTargets.usf +++ b/Engine/Shaders/MorphTargets.usf @@ -8,130 +8,63 @@ //////////////////////////////////////////////////////////////// -#ifndef USE_BYTE_BUFFER -#define USE_BYTE_BUFFER 0 -#endif -#if USE_BYTE_BUFFER -RWByteAddressBuffer MorphVertexBuffer; -#else RWBuffer MorphVertexBuffer; -#endif -// .x = NumLODVertices, .y = NumVertexInfoMorphs -float4 MorphTargetCounts; +float MorphTargetWeight; +uint MorphWorkItems; +uint2 OffsetAndSize; +float4 PositionScale; -Buffer PerVertexInfoList; -Buffer FlattenedDeltaList; -Buffer AllWeightsPerMorphs; +Buffer VertexIndicies; +Buffer MorphDeltas; #if 0 // This is how MorphVertexBuffer is interpreted as (6 floats) struct FMorphGPUSkinVertex { - FVector DeltaPosition; - FVector DeltaTangentZ; + FFloat16 PosDelta[3]; + FFloat16 TangentDelta[3]; }; - -// This is how PerVertexInfoList is interpreted as (3 uints) -struct FPerVertexInfo -{ - uint32 DestVertexIndex; - uint32 StartDelta; - uint32 NumDeltas; -}; - -// This is how FFlattenedDelta is interpreted as (7 uints) -struct FFlattenedDeltaList -{ - FVector PosDelta; - FVector TangentDelta; - uint32 WeightIndex; -}; - -// AllWeightsPerMorphs is a float per weight #endif -void ApplyMorphDeltas(uint DestVertexIndex, uint StartDelta, uint NumDeltas, out float3 Position, out float3 TangentZ) +[numthreads(6, 32, 1)] +void GPUMorphUpdateCS(uint2 DispatchId : SV_DispatchThreadID, uint2 GroupId : SV_GroupThreadID) { - // See FFlattenedDelta - const uint FlattenedDeltaListStride = 7; + const uint WorkItemIndex = DispatchId.y + OffsetAndSize.x; + const uint ElementIndex = GroupId.x; - Position = 0; - TangentZ = 0; - float AccumulatedWeight = 0; + if (WorkItemIndex < OffsetAndSize.y) + { + const uint MorphVertexBufferStride = 3 + 3; + float MorphDelta = MorphDeltas[MorphVertexBufferStride * WorkItemIndex + ElementIndex]; + float MorphOffset = MorphTargetWeight * MorphDelta; - for (uint Index = 0; Index < NumDeltas; ++Index) - { - uint DeltaIndex = Index + StartDelta; - float3 MorphVertexPositionDelta = float3( - asfloat(FlattenedDeltaList[FlattenedDeltaListStride * DeltaIndex + 0]), - asfloat(FlattenedDeltaList[FlattenedDeltaListStride * DeltaIndex + 1]), - asfloat(FlattenedDeltaList[FlattenedDeltaListStride * DeltaIndex + 2])); - float3 MorphVertexTangentZDelta = float3( - asfloat(FlattenedDeltaList[FlattenedDeltaListStride * DeltaIndex + 3]), - asfloat(FlattenedDeltaList[FlattenedDeltaListStride * DeltaIndex + 4]), - asfloat(FlattenedDeltaList[FlattenedDeltaListStride * DeltaIndex + 5])); - uint WeightIndex = FlattenedDeltaList[FlattenedDeltaListStride * DeltaIndex + 6]; + float Scale = PositionScale[min(ElementIndex, (uint)3)]; + int QuantizedOffset = round(MorphOffset * Scale); - const float Weight = asfloat(AllWeightsPerMorphs[WeightIndex]); - - Position += Weight * MorphVertexPositionDelta; - TangentZ += Weight * MorphVertexTangentZDelta; - AccumulatedWeight += abs(Weight); - } - - // if accumulated weight is >1.f - // previous code was applying the weight again in GPU if less than 1, but it doesn't make sense to do so - // so instead, we just divide by AccumulatedWeight if it's more than 1. - // now DeltaTangentZ isn't FPackedNormal, so you can apply any value to it. - if (AccumulatedWeight > 1.f) - { - TangentZ /= AccumulatedWeight; + const uint DestVertexIndex = MorphVertexBufferStride * VertexIndicies[WorkItemIndex] + ElementIndex; + InterlockedAdd(MorphVertexBuffer[DestVertexIndex], asuint(QuantizedOffset)); } } - -[numthreads(64,1,1)] -void GPUMorphUpdateCS(uint DispatchId : SV_DispatchThreadID) +[numthreads(6, 32, 1)] +void GPUMorphNormalizeCS(uint2 DispatchId : SV_DispatchThreadID, uint2 GroupId : SV_GroupThreadID) { - // See FMorphDelta - const uint MorphDeltaStride = 3 + 3 + 1; + const uint WorkItemIndex = DispatchId.y; + const uint ElementIndex = GroupId.x; - uint NumVertexInfoMorphs = (uint)MorphTargetCounts.y; - if (DispatchId.x < NumVertexInfoMorphs) + if (WorkItemIndex < MorphWorkItems) { - // See FPerVertexInfo - const uint PerVertexInfoStride = 3; - // Equivalent to PerVertexInfoList - const uint DestVertexIndex = PerVertexInfoList[DispatchId.x * PerVertexInfoStride + 0]; - const uint StartDelta = PerVertexInfoList[DispatchId.x * PerVertexInfoStride + 1]; - const uint NumDeltas = PerVertexInfoList[DispatchId.x * PerVertexInfoStride + 2]; + float Scale = PositionScale[min(ElementIndex, (uint)3)]; - float3 Position = 0; - float3 TangentZ = 0; - - ApplyMorphDeltas(DestVertexIndex, StartDelta, NumDeltas, Position, TangentZ); - - // See FMorphGPUSkinVertex const uint MorphVertexBufferStride = 3 + 3; -#if USE_BYTE_BUFFER - // Equivalent to MorphVertexBuffer - MorphVertexBuffer.Store((MorphVertexBufferStride * DestVertexIndex + 0) * 4, asuint(Position.x)); - MorphVertexBuffer.Store((MorphVertexBufferStride * DestVertexIndex + 1) * 4, asuint(Position.y)); - MorphVertexBuffer.Store((MorphVertexBufferStride * DestVertexIndex + 2) * 4, asuint(Position.z)); - MorphVertexBuffer.Store((MorphVertexBufferStride * DestVertexIndex + 3) * 4, asuint(TangentZ.x)); - MorphVertexBuffer.Store((MorphVertexBufferStride * DestVertexIndex + 4) * 4, asuint(TangentZ.y)); - MorphVertexBuffer.Store((MorphVertexBufferStride * DestVertexIndex + 5) * 4, asuint(TangentZ.z)); -#else - // Equivalent to MorphVertexBuffer - MorphVertexBuffer[MorphVertexBufferStride * DestVertexIndex + 0] = asuint(Position.x); - MorphVertexBuffer[MorphVertexBufferStride * DestVertexIndex + 1] = asuint(Position.y); - MorphVertexBuffer[MorphVertexBufferStride * DestVertexIndex + 2] = asuint(Position.z); - MorphVertexBuffer[MorphVertexBufferStride * DestVertexIndex + 3] = asuint(TangentZ.x); - MorphVertexBuffer[MorphVertexBufferStride * DestVertexIndex + 4] = asuint(TangentZ.y); - MorphVertexBuffer[MorphVertexBufferStride * DestVertexIndex + 5] = asuint(TangentZ.z); -#endif + const uint DestVertexIndex = MorphVertexBufferStride * WorkItemIndex + ElementIndex; + + float NomalizedResult = float(asint(MorphVertexBuffer[DestVertexIndex])) * Scale; + //normalize directions by 1 / accumulated absolute weights + NomalizedResult = (ElementIndex > 2) ? NomalizedResult * MorphTargetWeight : NomalizedResult; + MorphVertexBuffer[DestVertexIndex] = asuint(NomalizedResult); } } diff --git a/Engine/Shaders/PageTableUpdate.usf b/Engine/Shaders/PageTableUpdate.usf new file mode 100644 index 000000000000..74ed9b086002 --- /dev/null +++ b/Engine/Shaders/PageTableUpdate.usf @@ -0,0 +1,110 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "Common.usf" + +uint PageTableSize; +uint FirstUpdate; +uint NumUpdates; + +struct FPageUpdatePacked +{ + uint vAddress; + uint pAddress; +}; + +struct FPageUpdate +{ + uint vAddress; + uint pAddress; + uint vLevel; + uint vLogSize; +}; + +StructuredBuffer< FPageUpdatePacked > UpdateBuffer; + +uint ReverseMortonCode2( uint x ) +{ + x &= 0x55555555; + x = (x ^ (x >> 1)) & 0x33333333; + x = (x ^ (x >> 2)) & 0x0f0f0f0f; + x = (x ^ (x >> 4)) & 0x00ff00ff; + x = (x ^ (x >> 8)) & 0x0000ffff; + return x; +} + +void PageTableUpdateVS( + uint VertexID : SV_VertexID, + uint InstanceID : SV_InstanceID, + out nointerpolation float4 OutColor : TEXCOORD0, + out float4 OutPosition : SV_POSITION + ) +{ + OutPosition = float4(0, 0, 0, 1); + OutColor = 0; + + // needs to be the same on C++ side (faster on NVIDIA and AMD) + uint QuadsPerInstance = 8; + uint UpdateIndex = FirstUpdate + InstanceID * QuadsPerInstance + (VertexID >> 2); + + BRANCH + if( UpdateIndex - FirstUpdate >= NumUpdates ) + { + return; + } + + FPageUpdatePacked UpdatePacked = UpdateBuffer[ UpdateIndex ]; + + // Little Endian + FPageUpdate Update; + Update.vAddress = UpdatePacked.vAddress; + Update.pAddress = ( UpdatePacked.pAddress >> 0 ) & 0xffff; + Update.vLevel = ( UpdatePacked.pAddress >> 16 ) & 0xff; + Update.vLogSize = ( UpdatePacked.pAddress >> 24 ) & 0xff; + + uint vSize = 1 << Update.vLogSize; + + uint2 vPage; + vPage.x = ReverseMortonCode2( Update.vAddress ); + vPage.y = ReverseMortonCode2( Update.vAddress >> 1 ); + + uint2 pPage; + pPage.x = ReverseMortonCode2( Update.pAddress ); + pPage.y = ReverseMortonCode2( Update.pAddress >> 1 ); + + uint2 CornerOffset = uint2( + (VertexID >> 0) & 1, + (VertexID >> 1) & 1 + ); + + uint2 vCorner = vPage + vSize * CornerOffset; + OutPosition.xy = ( (float2)vCorner / PageTableSize ) * float2( 2, -2 ) + float2( -1, 1 ); + +#if 0 + // Pack 16bit 6:6:4 + // 64 x 64 physical pages + // 16 mip levels + uint Page; + Page = pPage.x << 0; + Page |= pPage.y << 6; + Page |= Update.vLevel << 12; + + OutColor = (float)Page; +#else + // 8:8:8:8 page table format + // [van Waveren 2012, "Software Virtual Textures"] + uint Scale = ( PageTableSize * 16 ) >> Update.vLevel; + OutColor.r = pPage.x; + OutColor.g = pPage.y; + OutColor.b = Scale & 0xff; + OutColor.a = Scale >> 8; + OutColor *= (1.0 / 255.0); +#endif +} + +void PageTableUpdatePS( + nointerpolation float4 InColor : TEXCOORD0, + out float4 OutColor : SV_Target0 + ) +{ + OutColor = InColor; +} \ No newline at end of file diff --git a/Engine/Shaders/PixelQuadMessagePassing.usf b/Engine/Shaders/PixelQuadMessagePassing.usf new file mode 100644 index 000000000000..55ea50062f73 --- /dev/null +++ b/Engine/Shaders/PixelQuadMessagePassing.usf @@ -0,0 +1,54 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +/*============================================================================= + PixelQuadMessagePassing.usf: Contains functions to do pixel quad message passing within the pixel shaders. +=========================================================================*/ + +#pragma once + + +// ddx/y_fine() are not supported in SM4. +#define HAS_PIXEL_QUAD_MESSAGE_PASSING_SUPPORT ((FEATURE_LEVEL >= FEATURE_LEVEL_SM5) && !MOBILE_EMULATION && PIXELSHADER) + + +// Pixel quad message passing in SM5 requires some thread informations. +struct FPQMPContext +{ + // Position of the pixel within the 2x2 pixel quad. + float2 PixelPos; +}; + + +// Returns a required thread context to perform pixel quad message passing in SM5. +FPQMPContext PQMPInit(float2 SvPosition) +{ + FPQMPContext PQMP; +#if HAS_PIXEL_QUAD_MESSAGE_PASSING_SUPPORT + PQMP.PixelPos = floor(2.0 * frac(SvPosition * 0.5)); +#else + PQMP.PixelPos = float2(0, 0); +#endif + return PQMP; +} + + +// Get the average value of across the pixel quad. +float PQMPAverage(FPQMPContext PQMP, float v) +{ +#if HAS_PIXEL_QUAD_MESSAGE_PASSING_SUPPORT + v = v + (0.5 - PQMP.PixelPos.x) * ddx_fine(v); + return v + (0.5 - PQMP.PixelPos.y) * ddy_fine(v); +#else + return v; +#endif +} + +float2 PQMPAverage(FPQMPContext PQMP, float2 v) +{ +#if HAS_PIXEL_QUAD_MESSAGE_PASSING_SUPPORT + v = v + (0.5 - PQMP.PixelPos.x) * ddx_fine(v); + return v + (0.5 - PQMP.PixelPos.y) * ddy_fine(v); +#else + return v; +#endif +} diff --git a/Engine/Shaders/PixelShaderOutputCommon.usf b/Engine/Shaders/PixelShaderOutputCommon.usf index 9d793b9e433c..8e65b62a29b7 100644 --- a/Engine/Shaders/PixelShaderOutputCommon.usf +++ b/Engine/Shaders/PixelShaderOutputCommon.usf @@ -10,6 +10,9 @@ PixelShaderOutputCommon.usf: To allow PS input/output passed int functions throu #ifndef PIXELSHADEROUTPUT_BASEPASS #define PIXELSHADEROUTPUT_BASEPASS 0 #endif +#ifndef PIXELSHADEROUTPUT_MESHDECALPASS + #define PIXELSHADEROUTPUT_MESHDECALPASS 0 +#endif #ifndef PIXELSHADEROUTPUT_MRT0 #define PIXELSHADEROUTPUT_MRT0 0 #endif @@ -51,6 +54,8 @@ void MainPS #endif #if PIXELSHADEROUTPUT_BASEPASS FBasePassInterpolantsVSToPS BasePassInterpolants, +#elif PIXELSHADEROUTPUT_MESHDECALPASS + FMeshDecalInterpolants MeshDecalInterpolants, #endif in INPUT_POSITION_QUALIFIERS float4 SvPosition : SV_Position // after all interpolators @@ -119,6 +124,8 @@ void MainPS #if PIXELSHADEROUTPUT_BASEPASS FPixelShaderInOut_MainPS(Interpolants, BasePassInterpolants, PixelShaderIn, PixelShaderOut); +#elif PIXELSHADEROUTPUT_MESHDECALPASS + FPixelShaderInOut_MainPS(Interpolants, MeshDecalInterpolants, PixelShaderIn, PixelShaderOut); #elif PIXELSHADEROUTPUT_INTERPOLANTS FPixelShaderInOut_MainPS(Interpolants, PixelShaderIn, PixelShaderOut); #else diff --git a/Engine/Shaders/PostProcessBokehDOF.usf b/Engine/Shaders/PostProcessBokehDOF.usf index c32f5d9f810f..ef05b18ec5df 100644 --- a/Engine/Shaders/PostProcessBokehDOF.usf +++ b/Engine/Shaders/PostProcessBokehDOF.usf @@ -450,7 +450,7 @@ float4 DOFRecombineCommon(float2 UV, float4 SvPosition) #endif #if RECOMBINE_METHOD == 2 || RECOMBINE_METHOD == 3 - float4 SeparateTranslucency = UpsampleSeparateTranslucency(SvPosition.xy, FullResUV); + float4 SeparateTranslucency = UpsampleSeparateTranslucency(SvPosition.xy, FullResUV, PostprocessInput2, PostprocessInput2Size.zw); // add RGB, darken by A (this allows to represent translucent and additive blending) OutColor.rgb = OutColor.rgb * SeparateTranslucency.a + SeparateTranslucency.rgb; diff --git a/Engine/Shaders/PostProcessTemporalAA.usf b/Engine/Shaders/PostProcessTemporalAA.usf index 986b67492eb6..f905a6e33c0b 100644 --- a/Engine/Shaders/PostProcessTemporalAA.usf +++ b/Engine/Shaders/PostProcessTemporalAA.usf @@ -281,6 +281,31 @@ void SSRTemporalAAPS( #endif } +float4 DOFTemporalAACommon(in float2 UV, in float InExposureScale) +{ + float4 OutColor = 0; + +#if ENABLE_TEMPORAL_AA + #define AA_FILTERED 0 + #define AA_ALPHA 1 + #define AA_CROSS 4 + #define AA_DYNAMIC 1 + #define AA_NAN 1 + #define AA_BORDER 1 + #define AA_FORCE_ALPHA_CLAMP 1 + #define AA_YCOCG 1 +#if COMPUTESHADER + #define AA_SINGLE_PASS_RESPONSIVE 1 +#endif + #include "PostProcessTemporalCommon.usf" + +#else + OutColor = PostprocessInput0.SampleLevel(PostprocessInput0Sampler, UV, 0); +#endif + + return OutColor; +} + void DOFTemporalAAPS( in noperspective float2 UV : TEXCOORD0, in noperspective float3 InExposureScaleVignette : TEXCOORD1, @@ -290,20 +315,8 @@ void DOFTemporalAAPS( float4 SvPosition : SV_POSITION, // after all interpolators out float4 OutColor : SV_Target0 ) { -#if ENABLE_TEMPORAL_AA float InExposureScale = InExposureScaleVignette.x; - #define AA_FILTERED 0 - #define AA_ALPHA 1 - #define AA_CROSS 4 - #define AA_DYNAMIC 1 - #define AA_NAN 1 - #define AA_BORDER 1 - #define AA_FORCE_ALPHA_CLAMP 1 - #define AA_YCOCG 1 - #include "PostProcessTemporalCommon.usf" -#else - OutColor = PostprocessInput0.SampleLevel(PostprocessInput0Sampler, UV, 0); -#endif + OutColor = DOFTemporalAACommon(UV, InExposureScale); } #if COMPUTESHADER @@ -318,20 +331,8 @@ void DOFTemporalAACS(uint2 DispatchThreadId : SV_DispatchThreadID) return; } -#if ENABLE_TEMPORAL_AA float InExposureScale = EyeAdaptationLookup(); - #define AA_FILTERED 0 - #define AA_ALPHA 1 - #define AA_CROSS 4 - #define AA_DYNAMIC 1 - #define AA_NAN 1 - #define AA_BORDER 1 - #define AA_FORCE_ALPHA_CLAMP 1 - #define AA_YCOCG 1 - #include "PostProcessTemporalCommon.usf" -#else - OutColor = PostprocessInput0.SampleLevel(PostprocessInput0Sampler, UV, 0); -#endif + OutColor = DOFTemporalAACommon(UV, InExposureScale); uint2 PixelPos = DispatchThreadId + (uint2)View.ViewRectMin.xy; OutComputeTex[PixelPos] = OutColor; @@ -363,23 +364,32 @@ void LightShaftTemporalAAPS( // 0.0f or 1.0f (if the RT format is not PF_FloatRGBA) float DitherScale; -float4 MainTemporalAACommon(in float2 UV, in float InExposureScale) +float4 MainTemporalAACommon(in float2 UV, in float4 SvPosition, in float InExposureScale) { float4 OutColor = 0; - #define AA_FILTERED 1 - #define AA_ALPHA (POST_PROCESS_ALPHA) - #define AA_BORDER 1 - #define AA_CROSS 2 - #define AA_AABB 1 - #define AA_YCOCG 1 - #define AA_BICUBIC 1 - #define AA_ACCURATE_ALPHA (POST_PROCESS_ALPHA) - #define AA_DYNAMIC_ANTIGHOST 1 -#if COMPUTESHADER - #define AA_SINGLE_PASS_RESPONSIVE 1 +#if ENABLE_TEMPORAL_AA + #if MINIMAL_REPROJECTION_DEBUG + OutColor = float4(MinimalReprojectionForDebugging(UV, SvPosition), 0); + #else + #define AA_FILTERED 1 + #define AA_ALPHA (POST_PROCESS_ALPHA) + #define AA_BORDER 1 + #define AA_CROSS 2 + #define AA_AABB 1 + #define AA_YCOCG 1 + #define AA_BICUBIC 1 + #define AA_ACCURATE_ALPHA (POST_PROCESS_ALPHA) + #define AA_DYNAMIC_ANTIGHOST 1 + #if COMPUTESHADER + #define AA_SINGLE_PASS_RESPONSIVE 1 + #endif + #include "PostProcessTemporalCommon.usf" + + #endif +#else + OutColor = PostprocessInput0.SampleLevel(PostprocessInput0Sampler, UV, 0); #endif - #include "PostProcessTemporalCommon.usf" return OutColor; } @@ -394,16 +404,8 @@ void MainTemporalAAPS( in float4 SvPosition : SV_Position, // after all interpolators out float4 OutColor : SV_Target0 ) { -#if ENABLE_TEMPORAL_AA - #if MINIMAL_REPROJECTION_DEBUG - OutColor = float4(MinimalReprojectionForDebugging(UV, SvPosition), 0); - #else - float InExposureScale = InExposureScaleVignette.x; - OutColor = MainTemporalAACommon(UV, InExposureScale); - #endif -#else - OutColor = PostprocessInput0.SampleLevel(PostprocessInput0Sampler, UV, 0); -#endif + float InExposureScale = InExposureScaleVignette.x; + OutColor = MainTemporalAACommon(UV, SvPosition, InExposureScale); } #if COMPUTESHADER @@ -419,16 +421,8 @@ void MainTemporalAACS(uint2 DispatchThreadId : SV_DispatchThreadID) return; } -#if ENABLE_TEMPORAL_AA - #if MINIMAL_REPROJECTION_DEBUG - OutColor = float4(MinimalReprojectionForDebugging(UV, SvPosition), 0); - #else - float InExposureScale = EyeAdaptationLookup(); - OutColor = MainTemporalAACommon(UV, InExposureScale); - #endif -#else - OutColor = PostprocessInput0.SampleLevel(PostprocessInput0Sampler, UV, 0); -#endif + float InExposureScale = EyeAdaptationLookup(); + OutColor = MainTemporalAACommon(UV, SvPosition, InExposureScale); uint2 PixelPos = DispatchThreadId + (uint2)View.ViewRectMin.xy; OutComputeTex[PixelPos] = OutColor; @@ -439,6 +433,7 @@ float4 MainFastTemporalAACommon(in float2 UV, in float InExposureScale) { float4 OutColor = 0; +#if ENABLE_TEMPORAL_AA #define AA_FILTERED 1 #define AA_ALPHA (POST_PROCESS_ALPHA) #define AA_BORDER 1 @@ -451,6 +446,10 @@ float4 MainFastTemporalAACommon(in float2 UV, in float InExposureScale) #endif #include "PostProcessTemporalCommon.usf" +#else + OutColor = PostprocessInput0.SampleLevel(PostprocessInput0Sampler, UV, 0); +#endif + return OutColor; } @@ -463,12 +462,8 @@ void MainFastTemporalAAPS( in float4 SvPosition : SV_Position, // after all interpolators out float4 OutColor : SV_Target0 ) { -#if ENABLE_TEMPORAL_AA float InExposureScale = InExposureScaleVignette.x; OutColor = MainFastTemporalAACommon(UV, InExposureScale); -#else - OutColor = PostprocessInput0.SampleLevel(PostprocessInput0Sampler, UV, 0); -#endif } #if COMPUTESHADER @@ -483,12 +478,8 @@ void MainFastTemporalAACS(uint2 DispatchThreadId : SV_DispatchThreadID) return; } -#if ENABLE_TEMPORAL_AA float InExposureScale = EyeAdaptationLookup(); OutColor = MainFastTemporalAACommon(UV, InExposureScale); -#else - OutColor = PostprocessInput0.SampleLevel(PostprocessInput0Sampler, UV, 0); -#endif uint2 PixelPos = DispatchThreadId + (uint2)View.ViewRectMin.xy; OutComputeTex[PixelPos] = OutColor; diff --git a/Engine/Shaders/PostProcessTonemap.usf b/Engine/Shaders/PostProcessTonemap.usf index d460d82f5e6a..0fceb4ccadd0 100644 --- a/Engine/Shaders/PostProcessTonemap.usf +++ b/Engine/Shaders/PostProcessTonemap.usf @@ -524,7 +524,13 @@ void MainPS( out float4 OutColor : SV_Target0 ) { +#if EYEADAPTATION_EXPOSURE_FIX == 1 + float3 vEyeAdapationVS = InExposureScaleVignette; + vEyeAdapationVS.x = EyeAdaptation.Load(int3(0, 0, 0)).r; + OutColor = TonemapCommonPS(UV, vEyeAdapationVS, GrainUV, FringeUV, FullViewUV, SvPosition); +#else OutColor = TonemapCommonPS(UV, InExposureScaleVignette, GrainUV, FringeUV, FullViewUV, SvPosition); +#endif } #if COMPUTESHADER @@ -759,15 +765,15 @@ void MainPS_ES2( #if (USE_BLOOM || USE_LIGHT_SHAFTS || USE_VIGNETTE) { half4 CombinedBloomSunVignette = Texture2DSample(PostprocessInput1, PostprocessInput1Sampler, FullViewUV.xy); - if (GetHDR32bppEncodeMode() != HDR_ENCODE_MOSAIC) - { - #if USE_32BPP_HDR + #if USE_32BPP_HDR + if (GetHDR32bppEncodeMode() == HDR_ENCODE_RGBE) + { CombinedBloomSunVignette.rgb = Decode32BPPHDR(CombinedBloomSunVignette).rgb; LinearColor.rgb = LinearColor.rgb + CombinedBloomSunVignette.rgb; - #else - LinearColor.rgb = LinearColor.rgb * CombinedBloomSunVignette.a + CombinedBloomSunVignette.rgb; - #endif - } + } + #else + LinearColor.rgb = LinearColor.rgb * CombinedBloomSunVignette.a + CombinedBloomSunVignette.rgb; + #endif } #endif diff --git a/Engine/Shaders/ReflectionEnvironmentShaders.usf b/Engine/Shaders/ReflectionEnvironmentShaders.usf index 6d3dc791143f..3162c1b84adf 100644 --- a/Engine/Shaders/ReflectionEnvironmentShaders.usf +++ b/Engine/Shaders/ReflectionEnvironmentShaders.usf @@ -248,7 +248,16 @@ float4 SampleCubemap(float3 Coordinates) return SampleCubemap(Coordinates, SourceMipIndex); } +void DownsamplePS_Mobile( + FScreenVertexOutput Input, + out float4 OutColor : SV_Target0 +) +{ + float2 ScaledUVs = Input.UV * 2 - 1; + float3 CubeCoordinates = GetCubemapVector(ScaledUVs); + OutColor = SampleCubemap(CubeCoordinates); +} void FilterPS( FScreenVertexOutput Input, diff --git a/Engine/Shaders/ReflectionEnvironmentShared.usf b/Engine/Shaders/ReflectionEnvironmentShared.usf index 85022fd3a3ba..005152b4e9cb 100644 --- a/Engine/Shaders/ReflectionEnvironmentShared.usf +++ b/Engine/Shaders/ReflectionEnvironmentShared.usf @@ -149,7 +149,7 @@ float3 GetLookupVectorForBoxCapture(float3 ReflectionVector, float3 WorldPositio return ProjectedCaptureVector; } -float3 GetLookupVectorForSphereCapture(float3 ReflectionVector, float3 WorldPosition, float4 SphereCapturePositionAndRadius, float NormalizedDistanceToCapture, float3 LocalCaptureOffset, out float DistanceAlpha) +float3 GetLookupVectorForSphereCapture(float3 ReflectionVector, float3 WorldPosition, float4 SphereCapturePositionAndRadius, float NormalizedDistanceToCapture, float3 LocalCaptureOffset, inout float DistanceAlpha) { float3 ProjectedCaptureVector = ReflectionVector; float ProjectionSphereRadius = SphereCapturePositionAndRadius.w; diff --git a/Engine/Shaders/SeparateTranslucency.usf b/Engine/Shaders/SeparateTranslucency.usf index dbfab147cbe6..6f1dcbb07620 100644 --- a/Engine/Shaders/SeparateTranslucency.usf +++ b/Engine/Shaders/SeparateTranslucency.usf @@ -20,12 +20,15 @@ void UpdateNearestSample(float Z, float2 UV, float FullResZ, inout float MinDist } } -//@todo - support for all platforms, just skip the GatherRed optimization where not supported -#define SUPPORTS_NEAREST_DEPTH_NEIGHBOR_UPSAMPLE (SM5_PROFILE && !METAL_SM5_PROFILE || PS4_PROFILE) - -float4 UpsampleSeparateTranslucency(float2 Position, float2 UV) +float4 BilinearUpsampling(float2 UV, Texture2D LowResTex) { -#if NEAREST_DEPTH_NEIGHBOR_UPSAMPLE && SUPPORTS_NEAREST_DEPTH_NEIGHBOR_UPSAMPLE + return Texture2DSample(LowResTex, BilinearClampedSampler, UV); +} + +float4 NearestDepthNeighborUpsampling(float2 Position, float2 UV, Texture2D LowResTex, float2 LowResTexelSize) +{ +//@todo - support for all platforms, just skip the GatherRed optimization where not supported +#if (SM5_PROFILE && !METAL_SM5_PROFILE || PS4_PROFILE) // The relative depth comparison breaks down at larger distances and incorrectly causes point sampling on the skybox pixels float MaxOperationDepth = 2000000.0f; @@ -39,7 +42,6 @@ float4 UpsampleSeparateTranslucency(float2 Position, float2 UV) // Search for the UV of the low res neighbor whose depth is closest to the full res depth float MinDist = 1.e8f; - float2 LowResTexelSize = PostprocessInput2Size.zw; float2 UV00 = UV - 0.5f * LowResTexelSize; float2 NearestUV = UV00; @@ -63,18 +65,28 @@ float4 UpsampleSeparateTranslucency(float2 Position, float2 UV) && abs(LowResDepth.x - FullResDepth) * InvFullResDepth < RelativeDepthThreshold && abs(LowResDepth.y - FullResDepth) * InvFullResDepth < RelativeDepthThreshold) { - Output = Texture2DSampleLevel(PostprocessInput2, PostprocessInput2Sampler, UV, 0); - //Output = float4(1, 0, 0, .1f); + Output = Texture2DSampleLevel(LowResTex, BilinearClampedSampler, UV, 0); } else { - Output = Texture2DSampleLevel(PostprocessInput2, PointClampedSampler, NearestUV, 0); - //Output = float4(0, 1, 0, .1f); + Output = Texture2DSampleLevel(LowResTex, PointClampedSampler, NearestUV, 0); } return Output; #else - return Texture2DSample(PostprocessInput2, PostprocessInput2Sampler, UV); + + return Texture2DSample(LowResTex, BilinearClampedSampler, UV); + #endif } + + +float4 UpsampleSeparateTranslucency(float2 Position, float2 UV, Texture2D LowResTex, float2 LowResTexelSize) +{ +#if NEAREST_DEPTH_NEIGHBOR_UPSAMPLE + return NearestDepthNeighborUpsampling(Position, UV, LowResTex, LowResTexelSize); +#else + return BilinearUpsampling(UV, LowResTex); +#endif +} \ No newline at end of file diff --git a/Engine/Shaders/ShaderVersion.usf b/Engine/Shaders/ShaderVersion.usf index 7ea51d22f928..2b30aa594273 100644 --- a/Engine/Shaders/ShaderVersion.usf +++ b/Engine/Shaders/ShaderVersion.usf @@ -2,4 +2,4 @@ // Each time the console command is executed it generates a new GUID. As this file is included // in common.usf (which should be included in any shader) it allows to invalidate the shader DDC. // -// GUID = A5D32FD08DAE4754B7F8105EA046ED4A \ No newline at end of file +// GUID = 2A71E9A0C147FE8C9B99A2BB4D077B32 diff --git a/Engine/Shaders/ShadingModels.usf b/Engine/Shaders/ShadingModels.usf index 7c3af80b0bf6..f67bb87d56bc 100644 --- a/Engine/Shaders/ShadingModels.usf +++ b/Engine/Shaders/ShadingModels.usf @@ -46,12 +46,15 @@ void StandardShadingPerLight( Shared, float3 L, float3 V, half3 N ) float3 StandardShading( float3 DiffuseColor, float3 SpecularColor, float3 LobeRoughness, float3 LobeEnergy, float3 L, float3 V, half3 N ) { - float3 H = normalize(V + L); - float NoL = saturate( dot(N, L) ); - float NoV = saturate( abs( dot(N, V) ) + 1e-5 ); - float NoH = saturate( dot(N, H) ); - float VoH = saturate( dot(V, H) ); - + float NoL = dot(N, L); + float NoV = dot(N, V); + float LoV = dot(L, V); + float InvLenH = rsqrt( 2 + 2 * LoV ); + float NoH = saturate( ( NoL + NoV ) * InvLenH ); + float VoH = saturate( InvLenH + InvLenH * LoV ); + NoL = saturate(NoL); + NoV = saturate(abs(NoV) + 1e-5); + // Generalized microfacet specular float D = D_GGX( LobeRoughness[1], NoH ) * LobeEnergy[1]; float Vis = Vis_SmithJointApprox( LobeRoughness[1], NoV, NoL ); @@ -116,7 +119,7 @@ float3 ClearCoatShading( FGBufferData GBuffer, float3 LobeRoughness, float3 Lobe float CNoH = saturate( dot(ClearCoatUnderNormal, H) ); float D2 = D_GGX(LobeRoughness[1], CNoH ) * LobeEnergy[1]; - float Vis2 = Vis_Schlick( LobeRoughness[1], NoV, NoL ); + float Vis2 = Vis_SmithJointApprox( LobeRoughness[1], NoV, NoL ); //float3 F2 = F_Schlick( GBuffer.SpecularColor, VoH ); float3 F2 = saturate( 50.0 * GBuffer.SpecularColor.g ) * Fc + (1 - Fc) * GBuffer.SpecularColor; @@ -133,7 +136,7 @@ float3 ClearCoatShading( FGBufferData GBuffer, float3 LobeRoughness, float3 Lobe // Generalized microfacet specular float D2 = D_GGX( LobeRoughness[1], NoH ) * LobeEnergy[1]; - float Vis2 = Vis_Schlick( LobeRoughness[1], NoV, NoL ); + float Vis2 = Vis_SmithJointApprox( LobeRoughness[1], NoV, NoL ); //float3 F2 = F_Schlick( GBuffer.SpecularColor, VoH ); float3 F2 = saturate( 50.0 * GBuffer.SpecularColor.g ) * Fc + (1 - Fc) * GBuffer.SpecularColor; @@ -205,7 +208,7 @@ float3 ClearCoatShading( FGBufferData GBuffer, float3 LobeRoughness, float3 Lobe // Generalized microfacet specular float D2 = D_GGX( Roughness, NoH ) * LobeEnergy[2]; - float Vis2 = Vis_Schlick( Roughness, NoV2, NoL2 ); + float Vis2 = Vis_SmithJointApprox( Roughness, NoV2, NoL2 ); float3 F2 = F_Schlick( GBuffer.SpecularColor, VoH ); float3 Fr2 = Diffuse_Lambert( GBuffer.DiffuseColor ) * LobeEnergy[2] + (D2 * Vis2) * F2; @@ -219,11 +222,14 @@ float3 ClothShading( FGBufferData GBuffer, float3 LobeRoughness, float3 LobeEner const float3 FuzzColor = saturate(GBuffer.CustomData.rgb); const float Cloth = saturate(GBuffer.CustomData.a); - float3 H = normalize(V + L); - float NoL = saturate( dot(N, L) ); - float NoV = saturate( abs( dot(N, V) ) + 1e-5 ); - float NoH = saturate( dot(N, H) ); - float VoH = saturate( dot(V, H) ); + float NoL = dot(N, L); + float NoV = dot(N, V); + float LoV = dot(L, V); + float InvLenH = rsqrt( 2 + 2 * LoV ); + float NoH = saturate( ( NoL + NoV ) * InvLenH ); + float VoH = saturate( InvLenH + InvLenH * LoV ); + NoL = saturate(NoL); + NoV = saturate(abs(NoV) + 1e-5); // Diffuse float3 Diffuse = Diffuse_Lambert( GBuffer.DiffuseColor ); @@ -639,12 +645,15 @@ float3 SubsurfaceShadingTwoSided( float3 SubsurfaceColor, float3 L, float3 V, ha float3 EyeShading( FGBufferData GBuffer, float3 LobeRoughness, float3 LobeEnergy, float3 L, float3 V, half3 N ) { - float3 H = normalize(V + L); - float NoL = saturate( dot(N, L) ); - float NoV = saturate( abs( dot(N, V) ) + 1e-5 ); - float NoH = saturate( dot(N, H) ); - float VoH = saturate( dot(V, H) ); - + float NoL = dot(N, L); + float NoV = dot(N, V); + float LoV = dot(L, V); + float InvLenH = rsqrt( 2 + 2 * LoV ); + float NoH = saturate( ( NoL + NoV ) * InvLenH ); + float VoH = saturate( InvLenH + InvLenH * LoV ); + NoL = saturate(NoL); + NoV = saturate(abs(NoV) + 1e-5); + // Generalized microfacet specular float D = D_GGX( LobeRoughness[1], NoH ) * LobeEnergy[1]; float Vis = Vis_SmithJointApprox( LobeRoughness[1], NoV, NoL ); @@ -655,9 +664,10 @@ float3 EyeShading( FGBufferData GBuffer, float3 LobeRoughness, float3 LobeEnergy float3 EyeSubsurfaceShading( FGBufferData GBuffer, float3 L, float3 V, half3 N ) { - float3 H = normalize(V + L); - float VoH = saturate( dot(V, H) ); - float NoV = saturate( abs( dot(N, V) ) + 1e-5 ); + float NoL = dot(N, L); + float LoV = dot(L, V); + float InvLenH = rsqrt( 2 + 2 * LoV ); + float VoH = saturate( InvLenH + InvLenH * LoV ); // F_Schlick float F0 = GBuffer.Specular * 0.08; @@ -676,14 +686,14 @@ float3 EyeSubsurfaceShading( FGBufferData GBuffer, float3 L, float3 V, half3 N ) // introduce some concavity, this does the job. float3 CausticNormal = normalize(lerp(IrisNormal, -N, IrisMask*IrisDistance)); - float NoL = saturate( dot( IrisNormal, L ) ); - float Power = lerp( 12, 1, NoL ); + float IrisNoL = saturate( dot( IrisNormal, L ) ); + float Power = lerp( 12, 1, IrisNoL ); float Caustic = 0.6 + 0.2 * ( Power + 1 ) * pow( saturate( dot( CausticNormal, L ) ), Power ); - float Iris = NoL * Caustic; + float Iris = IrisNoL * Caustic; // http://blog.stevemcauley.com/2011/12/03/energy-conserving-wrapped-diffuse/ float Wrap = 0.15; - float Sclera = saturate( ( dot(N, L) + Wrap ) / Square( 1 + Wrap ) ); + float Sclera = saturate( ( NoL + Wrap ) / Square( 1 + Wrap ) ); return (1 - F) * lerp( Sclera, Iris, IrisMask ) * GBuffer.DiffuseColor / PI; } diff --git a/Engine/Shaders/ShadingModelsMaterial.usf b/Engine/Shaders/ShadingModelsMaterial.usf new file mode 100644 index 000000000000..c5f47997841a --- /dev/null +++ b/Engine/Shaders/ShadingModelsMaterial.usf @@ -0,0 +1,127 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +/*============================================================================= + ShadingModelsMaterial.usf: Pixel shader function for computing a GBuffer from shading model. +=============================================================================*/ + +void SetGBufferForShadingModel( + in out FGBufferData GBuffer, + in const FMaterialPixelParameters MaterialParameters, + const float Opacity, + const half3 BaseColor, + const half Metallic, + const half Specular, + const float Roughness, + const float4 SubsurfaceData) +{ + const float3 SubsurfaceColor = SubsurfaceData.rgb; + const float SubsurfaceProfile = SubsurfaceData.a; + + GBuffer.WorldNormal = MaterialParameters.WorldNormal; + GBuffer.BaseColor = BaseColor; + GBuffer.Metallic = Metallic; + GBuffer.Specular = Specular; + GBuffer.Roughness = Roughness; + +#if MATERIAL_SHADINGMODEL_UNLIT + GBuffer.ShadingModelID = SHADINGMODELID_UNLIT; +#elif MATERIAL_SHADINGMODEL_DEFAULT_LIT + GBuffer.ShadingModelID = SHADINGMODELID_DEFAULT_LIT; +#elif MATERIAL_SHADINGMODEL_SUBSURFACE + GBuffer.ShadingModelID = SHADINGMODELID_SUBSURFACE; + GBuffer.CustomData.rgb = EncodeSubsurfaceColor(SubsurfaceColor); + GBuffer.CustomData.a = Opacity; +#elif MATERIAL_SHADINGMODEL_PREINTEGRATED_SKIN + GBuffer.ShadingModelID = SHADINGMODELID_PREINTEGRATED_SKIN; + GBuffer.CustomData.rgb = EncodeSubsurfaceColor(SubsurfaceColor); + GBuffer.CustomData.a = Opacity; +#elif MATERIAL_SHADINGMODEL_SUBSURFACE_PROFILE + // Optimization: if opacity is 0 then revert to default shading model + #if SUBSURFACE_PROFILE_OPACITY_THRESHOLD + if (Opacity > 0.0) + #endif + { + GBuffer.ShadingModelID = SHADINGMODELID_SUBSURFACE_PROFILE; + GBuffer.CustomData.rgb = EncodeSubsurfaceProfile(SubsurfaceProfile); + GBuffer.CustomData.a = Opacity; + } + #if SUBSURFACE_PROFILE_OPACITY_THRESHOLD + else + { + GBuffer.ShadingModelID = SHADINGMODELID_DEFAULT_LIT; + GBuffer.CustomData = 0; + } + #endif +#elif MATERIAL_SHADINGMODEL_CLEAR_COAT + GBuffer.ShadingModelID = SHADINGMODELID_CLEAR_COAT; + + float ClearCoat = saturate( GetMaterialCustomData0(MaterialParameters) ); + float ClearCoatRoughness = saturate( GetMaterialCustomData1(MaterialParameters) ); + float MetalSpec = 0.9; + + float NoV = saturate( dot( MaterialParameters.WorldNormal, MaterialParameters.CameraVector ) ); + + // Approximation of refraction's effect on EnvBRDF + float RefractionScale = ( (NoV * 0.5 + 0.5) * NoV - 1 ) * saturate( 1.25 - 1.25 * Roughness ) + 1; + + // Approximation of absorption integral, tuned for Roughness=0.4 + float3 AbsorptionColor = BaseColor * (1 / MetalSpec); + float3 Absorption = AbsorptionColor * ( (NoV - 1) * 0.85 * ( 1 - lerp( AbsorptionColor, Square(AbsorptionColor), -0.78 ) ) + 1 ); + + float F0 = 0.04; + float Fc = Pow5( 1 - NoV ); + float F = Fc + (1 - Fc) * F0; + float LayerAttenuation = lerp( 1, (1 - F), ClearCoat ); + + GBuffer.BaseColor = lerp( BaseColor * LayerAttenuation, MetalSpec * Absorption * RefractionScale, Metallic * ClearCoat ); + GBuffer.Specular *= lerp( 1, RefractionScale, ClearCoat ); + + GBuffer.CustomData.x = ClearCoat; + GBuffer.CustomData.y = ClearCoatRoughness; + + #if CLEAR_COAT_BOTTOM_NORMAL + { + float2 oct2 = UnitVectorToOctahedron(GBuffer.WorldNormal); + + #if NUM_MATERIAL_OUTPUTS_CLEARCOATBOTTOMNORMAL > 0 + #if MATERIAL_TANGENTSPACENORMAL + float3 tempnormal = normalize(TransformTangentVectorToWorld( MaterialParameters.TangentToWorld, ClearCoatBottomNormal0(MaterialParameters) )); + #else + float3 tempnormal = ClearCoatBottomNormal0(MaterialParameters); + #endif + + float2 oct1 = UnitVectorToOctahedron(tempnormal); + float2 oct3 = ( (oct1 - oct2) * 0.5 ) + (128.0/255.0); + GBuffer.CustomData.a = oct3.x; + GBuffer.CustomData.z = oct3.y; + #else + GBuffer.CustomData.a = 128.0/255.0; + GBuffer.CustomData.z = 128.0/255.0; + #endif + } + #endif +#elif MATERIAL_SHADINGMODEL_TWOSIDED_FOLIAGE + GBuffer.ShadingModelID = SHADINGMODELID_TWOSIDED_FOLIAGE; + GBuffer.CustomData.rgb = EncodeSubsurfaceColor(SubsurfaceColor); + GBuffer.CustomData.a = Opacity; +#elif MATERIAL_SHADINGMODEL_HAIR + GBuffer.ShadingModelID = SHADINGMODELID_HAIR; + GBuffer.CustomData.xy = UnitVectorToOctahedron( MaterialParameters.WorldNormal ) * 0.5 + 0.5; + GBuffer.CustomData.z = saturate( GetMaterialCustomData0(MaterialParameters) ); // Backlit +#elif MATERIAL_SHADINGMODEL_CLOTH + GBuffer.ShadingModelID = SHADINGMODELID_CLOTH; + GBuffer.CustomData.rgb = SubsurfaceColor; + GBuffer.CustomData.a = saturate( GetMaterialCustomData0(MaterialParameters) ); // Cloth + GBuffer.IndirectIrradiance *= 1 - GBuffer.CustomData.a; +#elif MATERIAL_SHADINGMODEL_EYE + GBuffer.ShadingModelID = SHADINGMODELID_EYE; + #if NUM_MATERIAL_OUTPUTS_GETTANGENTOUTPUT > 0 + float3 Tangent = GetTangentOutput0(MaterialParameters); + GBuffer.CustomData.xy = UnitVectorToOctahedron( normalize(Tangent) ) * 0.5 + 0.5; + #endif + GBuffer.CustomData.z = saturate( GetMaterialCustomData0(MaterialParameters) ); // Iris Mask + GBuffer.CustomData.w = saturate( GetMaterialCustomData1(MaterialParameters) ); // Iris Distance +#else + // missing shading model, compiler should report ShadingModelID is not set +#endif +} \ No newline at end of file diff --git a/Engine/Shaders/ShadowDepthVertexShader.usf b/Engine/Shaders/ShadowDepthVertexShader.usf index cce53de856b6..83750421190b 100644 --- a/Engine/Shaders/ShadowDepthVertexShader.usf +++ b/Engine/Shaders/ShadowDepthVertexShader.usf @@ -267,10 +267,10 @@ void Main( #if INTERPOLATE_VF_ATTRIBUTES // Masked materials need texture coords to clip OutParameters.FactoryInterpolants = VertexFactoryGetInterpolantsVSToPS(Input, VFIntermediates, VertexParameters); + #endif - #if INTERPOLATE_POSITION - OutParameters.PixelPosition = WorldPos.xyz; - #endif + #if INTERPOLATE_POSITION + OutParameters.PixelPosition = WorldPos.xyz; #endif #if !PERSPECTIVE_CORRECT_DEPTH && !COMPILER_SUPPORTS_EMPTY_STRUCTS diff --git a/Engine/Shaders/ShadowFilteringCommon.usf b/Engine/Shaders/ShadowFilteringCommon.usf index 6980515cbaa8..4eba6810968e 100644 --- a/Engine/Shaders/ShadowFilteringCommon.usf +++ b/Engine/Shaders/ShadowFilteringCommon.usf @@ -4,6 +4,11 @@ ShadowFilteringCommon.usf: Contains functions to filter a shadowmap, shared between forward/deferred shading. =========================================================================*/ +#pragma once + +#include "PixelQuadMessagePassing.usf" + + struct FPCFSamplerSettings { Texture2D ShadowDepthTexture; @@ -21,6 +26,9 @@ struct FPCFSamplerSettings // set by the caller, constant for the code so only one code branch should be compiled bool bSubsurface; + // Whether to treat shadow depths near 1 as unshadowed. This is useful when the shadowmap does not contain all the points being shadowed. + bool bTreatMaxDepthUnshadowed; + // only used if bSubsurface is true float DensityMulConstant; @@ -167,7 +175,15 @@ float4 CalculateOcclusion(float4 ShadowmapDepth, FPCFSamplerSettings Settings) // Using a soft transition based on depth difference // Offsets shadows a bit but reduces self shadowing artifacts considerably float TransitionScale = Settings.TransitionScale; //SoftTransitionScale.z; - return saturate((ShadowmapDepth - Settings.SceneDepth) * TransitionScale + 1); + float4 ShadowFactor = saturate((ShadowmapDepth - Settings.SceneDepth) * TransitionScale + 1); + + FLATTEN + if (Settings.bTreatMaxDepthUnshadowed) + { + ShadowFactor = saturate(ShadowFactor + (ShadowmapDepth > .99f)); + } + + return ShadowFactor; } } @@ -189,7 +205,15 @@ float3 CalculateOcclusion(float3 ShadowmapDepth, FPCFSamplerSettings Settings) // Using a soft transition based on depth difference // Offsets shadows a bit but reduces self shadowing artifacts considerably float TransitionScale = Settings.TransitionScale; //SoftTransitionScale.z; - return saturate((ShadowmapDepth - Settings.SceneDepth) * TransitionScale + 1); + float3 ShadowFactor = saturate((ShadowmapDepth - Settings.SceneDepth) * TransitionScale + 1); + + FLATTEN + if (Settings.bTreatMaxDepthUnshadowed) + { + ShadowFactor = saturate(ShadowFactor + (ShadowmapDepth > .99f)); + } + + return ShadowFactor; } } @@ -262,6 +286,7 @@ float Manual1x1PCF(float2 ShadowPosition, FPCFSamplerSettings Settings) return PCF1x1(Fraction, Values00); } + float ManualPCF(float2 ShadowPosition, FPCFSamplerSettings Settings) { diff --git a/Engine/Shaders/ShadowPercentageCloserFiltering.usf b/Engine/Shaders/ShadowPercentageCloserFiltering.usf new file mode 100644 index 000000000000..861c844c4fd0 --- /dev/null +++ b/Engine/Shaders/ShadowPercentageCloserFiltering.usf @@ -0,0 +1,500 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +/*============================================================================= + ShadowPercentageCloserFiltering.usf: Contains functions to do percentage closer soft shadow sampling. +=========================================================================*/ + +#include "ShadowFilteringCommon.usf" + + +// CONFIGURATION OF PCSS +// ----------------------------------------------------------------------- + +// Whether to compile some debugging utilitaries. +#define PCSS_DEBUG_UTILITITARIES 0 + +// Whether to debug pixel where they early return. +#define PCSS_DEBUG_EARLY_RETURN 0 + +// Wheather some computation should be shared across 2x2 pixel quad. +// 0: disabled. +// 1: share occluder search result. +// 2: share occluder search and PCF results. +#define PCSS_SHARE_PER_PIXEL_QUAD 2 + +// Wheather to set a maximum depth bias. +#define PCSS_MAX_DEPTH_BIAS 1 + +// Idea of the experiment to turn on. +#define PCSS_ANTI_ALIASING_METHOD 2 + +// PCF experiment to solve translucent shadow artifacts. +// 0: Dummy PCF. +// 1: Cone traced occluder sums with occluder distance based weighting. +#define PCSS_PCF_EXPERIMENT 0 + +// Wheather to enable the sharpening filter after PCF for sharper edges than the shadow map resolution. +#define PCSS_ENABLE_POST_PCF_SHARPENING 1 + + +// POISSON KERNEL +// ----------------------------------------------------------------------- + +struct FPCSSSamplerSettings +{ + Texture2D ShadowDepthTexture; + SamplerState ShadowDepthTextureSampler; + + //XY - Pixel size of shadowmap + //ZW - Inverse pixel size of shadowmap + float4 ShadowBufferSize; + + // Offset and size of the shadow tile within the shadow depth texture. + float4 ShadowTileOffsetAndSize; + + // SceneDepth in shadow view space. + float SceneDepth; + + // Transition scale (TODO: Could probably nuke that guy). + float TransitionScale; + + // Tan(0.5 * Light Source Angle) in the shadow view space. + float TanLightSourceAngle; + + // Maximum kernel size in the tile's UV space. + float MaxKernelSize; + + // Pixel's postion for random number generation. + float2 SvPosition; + + // Thread's pixel quad message passing context. + FPQMPContext PQMPContext; + + // Viewport UV for debuging purposes. + float2 DebugViewportUV; +}; + + +// POISSON KERNEL +// ----------------------------------------------------------------------- + +#define PCSS_SEARCH_SAMPLES 16 +#define PCSS_SAMPLES 32 + +static const float2 PCSSSamples[PCSS_SEARCH_SAMPLES] = { + float2(0.03522659013938079, -0.06773381793326105), + float2(-0.2226592407149033, 0.28712634420696953), + float2(0.29521592554288656, 0.3091113612849006), + float2(0.45445972849126726, -0.06885997394231347), + float2(-0.5294175874764113, -0.046014035861565994), + float2(-0.452648396511972, -0.47909964168393443), + float2(-0.24846147512522798, 0.7335295870878695), + float2(0.3577384490251264, 0.7225563640511622), + float2(0.6637172290495703, -0.5130051538790028), + float2(0.8247905306055152, 0.2699748069491893), + float2(0.2677328749047735, -0.8264198346042448), + float2(0.8735142147828027, -0.13873095107832628), + float2(-0.9200356771077463, 0.12928348617112767), + float2(-0.333591990232354, -0.88825657027033), + float2(-0.6744079723354472, 0.7098786719042596), + float2(-0.916141973131132, -0.35310318938523944), +}; + +static const float2 PCFSamples[PCSS_SAMPLES] = { + float2(0.05184623507064756, 0.1300833011807859), + float2(-0.1577127330375604, -0.04411805230289356), + float2(-0.3608032569836849, 0.14224022015847443), + float2(0.32943189033164505, -0.23116230997768047), + float2(-0.3248396383424306, -0.24779640789279145), + float2(-0.08378000616865044, -0.42320666155308073), + float2(0.27231365926326034, 0.4570699627554666), + float2(0.4665144073390388, 0.2723623292705937), + float2(-0.3585638845043682, 0.4184774097652295), + float2(-0.05651562661921321, 0.6247868960227553), + float2(-0.33439047389336457, -0.5347681672345762), + float2(0.23213281841559313, -0.5970219039183482), + float2(-0.6407636828693648, 0.11993935952614704), + float2(0.6532651709764936, 0.050993271277866264), + float2(-0.6024883054476216, -0.27760818629456524), + float2(0.48856009912681686, -0.47214983370201674), + float2(0.22574621537299483, 0.7150421652622163), + float2(0.5333102819109856, 0.5347971792924224), + float2(-0.8677248476742625, -0.039097016569094784), + float2(0.7864067837429691, 0.4116218032124058), + float2(0.0148798999072412, 0.8888627595628051), + float2(-0.51288316652954, -0.733326766790393), + float2(-0.6630269006484741, 0.6126292700542129), + float2(-0.845774354018934, 0.32435673562428946), + float2(0.8332104797006348, -0.3622295582682804), + float2(-0.2446550784225213, -0.8800972615287274), + float2(-0.32118393732444706, 0.8618550333128141), + float2(0.2393990624981109, -0.8931529275822183), + float2(-0.7628371490800573, -0.5306507752416643), + float2(0.47612860488155273, 0.8066697476711497), + float2(0.6204553222569549, -0.7122745692650101), + float2(0.9557311286580455, 0.14112604822367059), +}; + + +// PCSS SPECIFIC UTILITARY FUNCTIONS +// ----------------------------------------------------------------------- + +float2x2 GenerateScale2x2Matrix(float2 MajorAxis, float MajorMinusMinorScale, float MinorScale) +{ + return float2x2( + MinorScale + MajorMinusMinorScale * MajorAxis.x * MajorAxis.x, MajorMinusMinorScale * MajorAxis.y * MajorAxis.x, + MajorMinusMinorScale * MajorAxis.x * MajorAxis.y, MinorScale + MajorMinusMinorScale * MajorAxis.y * MajorAxis.y); +} + +float2x2 GenerateDirectionalScale2x2Matrix(float2 Direction, float ScaleMinusOne) +{ + return float2x2( + 1 + ScaleMinusOne * Direction.x * Direction.x, ScaleMinusOne * Direction.y * Direction.x, + ScaleMinusOne * Direction.x * Direction.y, 1 + ScaleMinusOne * Direction.y * Direction.y); +} + + +#if PCSS_DEBUG_UTILITITARIES + +// Function to debug the direction of ellipse major and minor axes in the shadow map UV space. +float PCSSDebugUVDir(float2 v) +{ + return frac(atan2(v.x, v.y) / (PI)+0.25); +} + +#endif //PCSS_DEBUG_UTILITITARIES + + +// PCSS FILTER +// ----------------------------------------------------------------------- + +float DirectionalPCSS(FPCSSSamplerSettings Settings, float2 ShadowPosition, float3 ShadowPositionDDX, float3 ShadowPositionDDY) +{ + float3 DepthBiasPlaneNormal = cross(ShadowPositionDDX, ShadowPositionDDY); +#if PCSS_MAX_DEPTH_BIAS + float DepthBiasFactor = 1 / max(abs(DepthBiasPlaneNormal.z), length(DepthBiasPlaneNormal) * 0.0872665); +#else + float DepthBiasFactor = 1 / abs(DepthBiasPlaneNormal.z); +#endif + float2 DepthBiasDotFactors = DepthBiasPlaneNormal.xy * DepthBiasFactor; + + float2 ShadowTexelSizeX = Settings.ShadowBufferSize.zw / Settings.ShadowTileOffsetAndSize.zw; //TODO: remove truncation. + const float MinFilterSize = max(ShadowTexelSizeX.x, ShadowTexelSizeX.y); + float PCSSMinFilterSize = MinFilterSize; + float PCFMinFilterSize = MinFilterSize; + + // dot(surface's normal, light direction). + float3 NormalizedDepthBiasPlaneNormal = normalize(DepthBiasPlaneNormal); + float DotNormal = NormalizedDepthBiasPlaneNormal.z; + + float RandomRotation = Rand3DPCG16(uint3(Settings.SvPosition, View.StateFrameIndexMod8)).x * (2.f * PI / 0x10000); + float RandomFilterScale = Rand3DPCG16(uint3(Settings.SvPosition, View.StateFrameIndexMod8 + 8)).x * (0.5f / 0x10000) + 0.5f; + float2x2 PerPixelRotationMatrix = float2x2(cos(RandomRotation), sin(RandomRotation), -sin(RandomRotation), cos(RandomRotation)); + float2x2 OccluderSearchUVMatrix = PerPixelRotationMatrix; + +#if PCSS_ANTI_ALIASING_METHOD == 1 || PCSS_ANTI_ALIASING_METHOD == 2 // Dilate occluder search. + PCSSMinFilterSize *= 3; +#endif + + float SearchRadius = max(PCSSMinFilterSize, RandomFilterScale * min(Settings.SceneDepth * Settings.TanLightSourceAngle, Settings.MaxKernelSize)); + +#if PCSS_ANTI_ALIASING_METHOD == 6 // Experience 6: anysotropy. + float2 ShadowPositionDx = ddx(ShadowPosition); + float2 ShadowPositionDy = ddy(ShadowPosition); + float2 ShadowAnisotropicVector = ShadowPositionDx + ShadowPositionDy; + float2 ShadowPositionDelta = sqrt(float2( + ShadowPositionDx.x * ShadowPositionDx.x + ShadowPositionDy.x * ShadowPositionDy.x, + ShadowPositionDx.y * ShadowPositionDx.y + ShadowPositionDy.y * ShadowPositionDy.y)); + + float MajorAnisotropy = max(ShadowPositionDelta.x, ShadowPositionDelta.y); + float MinorAnisotropy = min(ShadowPositionDelta.x, ShadowPositionDelta.y); + + float MinorAnisotropyFactor = clamp(MinorAnisotropy / SearchRadius, 1, 7); + float MajorAnisotropyFactor = clamp(MajorAnisotropy / SearchRadius, 1, 7); + if (View.GeneralPurposeTweak < 1.5) { + MajorAnisotropyFactor = 1; + MinorAnisotropyFactor = 1; + } + if (View.GeneralPurposeTweak < 2.5) { + MajorAnisotropyFactor = clamp(length(ShadowAnisotropicVector) / SearchRadius, 1, 7); + MinorAnisotropyFactor = 1; + } + //return MajorAnisotropyFactor - MinorAnisotropyFactor; + //return (MinorAnisotropyFactor - 1); + + float2 ShadowAnisotropicDir = normalize(ShadowAnisotropicVector); + float2x2 AnysotropticProjectionMatrix = GenerateScale2x2Matrix( + ShadowAnisotropicDir, MajorAnisotropyFactor - MinorAnisotropyFactor, MinorAnisotropyFactor); + + PerPixelRotationMatrix = mul(AnysotropticProjectionMatrix, PerPixelRotationMatrix); + OccluderSearchUVMatrix = PerPixelRotationMatrix; +#endif + + // Search for an average occluder depth. + float DepthSum = 0; + float DepthSquaredSum = 0; + float SumWeight = 0; + float DiscardedSampleCount = 0; + float2 UVOffsetSum = float2(0, 0); + float2 UVOffsetSquareSum = float2(0, 0); + float UVCrossSum = 0; + for (int i = 0; i < PCSS_SEARCH_SAMPLES; i++) + { + float2 SampleUVOffset = mul(OccluderSearchUVMatrix, PCSSSamples[i]) * SearchRadius; + float2 SampleUV = ShadowPosition + SampleUVOffset * Settings.ShadowTileOffsetAndSize.zw; + + float ShadowDepth = Texture2DSampleLevel(Settings.ShadowDepthTexture, Settings.ShadowDepthTextureSampler, SampleUV, 0).r; + float ShadowDepthCompare = Settings.SceneDepth - ShadowDepth; + + float SampleDepthBias = max(dot(DepthBiasDotFactors, SampleUVOffset), 0); + + // TODO: Cone trace to early return more often on SumWeight == 0? + if (ShadowDepthCompare > SampleDepthBias) + { + DepthSum += ShadowDepth; + DepthSquaredSum += ShadowDepth * ShadowDepth; + SumWeight += 1; + float2 UV = mul(OccluderSearchUVMatrix, PCSSSamples[i]); + UVOffsetSum += UV; + UVOffsetSquareSum += UV * UV; + UVCrossSum += UV.x * UV.y; + } + else if (ShadowDepthCompare > 0) + { + DiscardedSampleCount += 1; + } + } + +#if PCSS_SHARE_PER_PIXEL_QUAD // Pixel quad share setup. + const float MaxTexelShare = 1; + float2 MaxDerivative = max(abs(ddx(ShadowPosition)), abs(ddy(ShadowPosition))); + float DoPerQuad = 0.8 * max(1 - max(MaxDerivative.x, MaxDerivative.y) / (MinFilterSize * MaxTexelShare), 0); +#else + float DoPerQuad = 0; +#endif + +#if PCSS_SHARE_PER_PIXEL_QUAD >= 1 // Share occluder search computation per quad. + DepthSum = lerp(DepthSum, 4 * PQMPAverage(Settings.PQMPContext, DepthSum), DoPerQuad); + DepthSquaredSum = lerp(DepthSquaredSum, 4 * PQMPAverage(Settings.PQMPContext, DepthSquaredSum), DoPerQuad); + SumWeight = lerp(SumWeight, 4 * PQMPAverage(Settings.PQMPContext, SumWeight), DoPerQuad); + UVOffsetSum = lerp(UVOffsetSum, 4 * PQMPAverage(Settings.PQMPContext, UVOffsetSum), DoPerQuad); + UVOffsetSquareSum = lerp(UVOffsetSquareSum, 4 * PQMPAverage(Settings.PQMPContext, UVOffsetSquareSum), DoPerQuad); + UVCrossSum = lerp(UVCrossSum, 4 * PQMPAverage(Settings.PQMPContext, UVCrossSum), DoPerQuad); +#endif + + if (SumWeight == 0) + { + // If no occluder found, early return as if this pixel was unshadowed. + return PCSS_DEBUG_EARLY_RETURN ? 0.8 : 1; + } + else if (SumWeight >= lerp(PCSS_SEARCH_SAMPLES, 4 * PCSS_SEARCH_SAMPLES - 0.5, DoPerQuad)) + { + // If every occluder search sample have found an occluder, then early return as if this pixel was totaly shadowed. + return PCSS_DEBUG_EARLY_RETURN ? 0.2 : 0; + } + + float NormalizeFactor = (1 / SumWeight); + float2 OccluderUVGradient = UVOffsetSum * NormalizeFactor; + float2x2 PCFUVMatrix = PerPixelRotationMatrix; + +#if 0 // Signal analysis: + // This shows the direction of the UV offset average of the occluders. + if (Settings.DebugScreenUV.x > 0.7 && 1) return PCSSDebugUVDir(OccluderUVGradient); + + // This shows the length of the UV offset average of the occluders. + if (Settings.DebugScreenUV.x > 0.5 && 0) return length(OccluderUVGradient); + + // This shows the number of occluders. + if (Settings.DebugScreenUV.x > 0.5 && 0) return SumWeight / 3; +#endif + + float DepthAvg = DepthSum * NormalizeFactor; + float DepthVariance = NormalizeFactor * DepthSquaredSum - DepthAvg * DepthAvg; + float DepthStandardDeviation = sqrt(DepthVariance); + float AverageOccluderDistance = (Settings.SceneDepth - DepthAvg); + float Penumbra = min((Settings.SceneDepth - DepthAvg) * Settings.TanLightSourceAngle, Settings.MaxKernelSize); + + float RawFilterRadius = RandomFilterScale * Penumbra; + float FilterRadius = max(PCFMinFilterSize, RawFilterRadius); + float TanDirectionalLightAngle = FilterRadius / (RandomFilterScale * (Settings.SceneDepth - DepthAvg)); + +#if PCSS_ANTI_ALIASING_METHOD == 1 // Experiement 4: do elliptical PCF kernel according to the occluder UV gradient. + { + float ElepticalFading = PCFMinFilterSize / FilterRadius; + float ElepticalFactor = length(OccluderUVGradient) * SumWeight * ElepticalFading; + float2 GrandAxisDir = normalize(float2(OccluderUVGradient.y, -OccluderUVGradient.x)); + float2x2 ElepticalProjectionMatrix = GenerateDirectionalScale2x2Matrix(GrandAxisDir, ElepticalFactor); + + PCFUVMatrix = mul(ElepticalProjectionMatrix, PCFUVMatrix); + } +#elif PCSS_ANTI_ALIASING_METHOD == 2 + { + // Minimal number of times the longest egeinst vector should be from the shorter one. + const float EigenThreshold = 1.3; + + // Number of occluders requiered to consider the covriance matrix valid. + const float MinimumCovaranceOccluders = 2; + + // Compute covariance matrix: + // a b + // b c + // + // With: + // a == CovarianceMatrixDiagonal.x + // b == CovarianceMatrixNonDiagonal + // c == CovarianceMatrixDiagonal.y + float CovarianceMatrixNonDiagonal = SumWeight * UVCrossSum - OccluderUVGradient.x * OccluderUVGradient.y; + float2 CovarianceMatrixDiagonal = float2( + SumWeight * UVOffsetSquareSum.x - OccluderUVGradient.x * OccluderUVGradient.x, + SumWeight * UVOffsetSquareSum.y - OccluderUVGradient.y * OccluderUVGradient.y); + + // Compute covariance matrix's Eigen values. + float CovarianceMatrixTrace = CovarianceMatrixDiagonal.x + CovarianceMatrixDiagonal.y; + float T = sqrt(CovarianceMatrixTrace * CovarianceMatrixTrace - + 4 * (CovarianceMatrixDiagonal.x * CovarianceMatrixDiagonal.y - CovarianceMatrixNonDiagonal * CovarianceMatrixNonDiagonal)); + float2 EigenValues = 0.5 * (CovarianceMatrixTrace + float2(T, -T)); + + // Choose the longest Egein vector. + float MaxEigenValue = max(EigenValues.x, EigenValues.y); + float MinEigenValue = min(EigenValues.x, EigenValues.y); + //float2 EigenVector = normalize(float2(CovarianceMatrixNonDiagonal, MaxEigenValue - CovarianceMatrixDiagonal.x)); + float2 LongestEigenVector = normalize(float2(MaxEigenValue - CovarianceMatrixDiagonal.y, CovarianceMatrixNonDiagonal)); + float LongestEigenVectorFactor = sqrt(MaxEigenValue / MinEigenValue) - EigenThreshold; + float CovarianceBasedEllipticalFactor = 8 * LongestEigenVectorFactor; + + // Linear interpolator between the average occluder UV offset method (0) to the covariance method (1). + float CovarianceFade = saturate((SumWeight >= MinimumCovaranceOccluders ? 1 : 0) * LongestEigenVectorFactor); + + // Heuristic: Force to use the average occluder UV offset method if the length of average of the offset is high. + CovarianceFade *= saturate(1 - 5 * (length(OccluderUVGradient) - 0.5)); + + // Ellipse's major axis computed from the average occluder UV offset. + float2 AverageBasedMajorAxis = normalize(float2(OccluderUVGradient.y, -OccluderUVGradient.x)); + float AverageBasedEllipticalFactor = length(OccluderUVGradient) * SumWeight; + + // Ellipitical fade based on how many time the filter size. + float EllipticalFade = PCFMinFilterSize / FilterRadius; + + // Final ellipse's major axis and scale. + float2 EllipseMajorAxis = normalize(lerp(AverageBasedMajorAxis, LongestEigenVector, CovarianceFade)); + float MaxEllipticalFactor = 6 - 3 * CovarianceFade; + float EllipticalFactor = min(lerp(AverageBasedEllipticalFactor, CovarianceBasedEllipticalFactor, CovarianceFade), MaxEllipticalFactor) * EllipticalFade; + + // Heuristic: reduce the ellipse shapse in corners of light. + //float ShadowCornerMultiplier = 1 - pow(saturate(30 * (length(OccluderUVGradient) - 0.45)) * abs(dot(AverageBasedMajorAxis, LongestEigenVector)), 3); + //EllipticalFactor *= ShadowCornerMultiplier; + + // Projection matrix that transform the disk shaped kernel to an ellipse. + float2x2 ElepticalProjectionMatrix = GenerateDirectionalScale2x2Matrix(EllipseMajorAxis, EllipticalFactor); + + // Hacks the PCF's per pixel UV rotation matrix. + PCFUVMatrix = mul(ElepticalProjectionMatrix, PCFUVMatrix); + +#if 0 // Final major axis analysis. + if (Settings.DebugScreenUV.x > 0.5) return PCSSDebugUVDir(EllipseMajorAxis); + +#elif 0 // Final elliptical factor + if (Settings.DebugScreenUV.x > 0.5) return EllipticalFactor * 0.1; + +#elif 0 // Covarance fade factor + if (Settings.DebugScreenUV.x > 0.5) return CovarianceFade; + +#elif 0 // Not enough occluder samples. + if (Settings.DebugScreenUV.x > 0.5) return SumWeight < 3 ? 1 : 0; + +#elif 0 + if (Settings.DebugScreenUV.x > 0.5) return ShadowCornerMultiplier; + +#elif 0 // Egein vector + if (Settings.DebugScreenUV.x > 0.5) return sqrt(MaxEigenValue / MinEigenValue) - 1; + +#elif 0 + if (Settings.DebugScreenUV.x > 0.5) return (length(OccluderUVGradient) - 0.7) * 5; + +#elif 0 // Signal analysis. + if (Settings.DebugScreenUV.x > 0.7 && 1) return EllipticalFade; + if (Settings.DebugScreenUV.x > 0.5 && 1) return EllipticalFactor; + if (Settings.DebugScreenUV.x > 0.3 && 1) return CovarianceFade; + +#elif 0 // Major axis transition analysis. + if (Settings.DebugScreenUV.x > 0.7) return PCSSDebugUVDir(AverageBasedMajorAxis); + if (Settings.DebugScreenUV.x > 0.5) return PCSSDebugUVDir(LongestEigenVector); + if (Settings.DebugScreenUV.x > 0.3) return CovarianceFade; +#endif + } +#endif + +#if PCSS_PCF_EXPERIMENT == 1 // -> Shadow occlusion sum. + // UV area covered by one sample one the disk on the average depth. + const float NormalizedSampleArea = 1 / float(PCSS_SAMPLES); + + // PCF loop. + float ShadowOcclusionSum = 0; + for (int j = 0; j < PCSS_SAMPLES; j++) + { + float OriginalUVLength = length(PCFSamples[j]); + float2 SampleUVOffset = mul(PCFUVMatrix, PCFSamples[j]) * FilterRadius;// *pow(OriginalUVLength, 0.9); + float2 SampleUV = ShadowPosition + SampleUVOffset * Settings.ShadowTileOffsetAndSize.zw; + float SampleDepth = Texture2DSampleLevel(Settings.ShadowDepthTexture, Settings.ShadowDepthTextureSampler, SampleUV, 0).r; + float ShadowDepthCompare = Settings.SceneDepth - SampleDepth; + + float SampleDepthBias = length(SampleUVOffset) / TanLightSourceAngle; + //float SampleDepthBias = max(dot(DepthBiasDotFactors, SampleUVOffset), 0); + + if (ShadowDepthCompare > SampleDepthBias) + { + float SampleSizeMultiplier = AverageOccluderDistance / min(ShadowDepthCompare, AverageOccluderDistance); + ShadowOcclusionSum += NormalizedSampleArea * SampleSizeMultiplier * SampleSizeMultiplier; + } + } + ShadowOcclusionSum = lerp(ShadowOcclusionSum, PQMPAverage(Settings.PQMPContext, ShadowOcclusionSum), DoPerQuad * 0.5); + float Visibility = max(1.0 - ShadowOcclusionSum, 0.0); + +#else + // PCF loop. + float VisibleLightAccumulation = 0; + for (int j = 0; j < PCSS_SAMPLES; j++) + { + float2 SampleUVOffset = mul(PCFUVMatrix, PCFSamples[j]) * FilterRadius; + float2 SampleUV = ShadowPosition + SampleUVOffset * Settings.ShadowTileOffsetAndSize.zw; + float SampleDepth = Texture2DSampleLevel(Settings.ShadowDepthTexture, Settings.ShadowDepthTextureSampler, SampleUV, 0).r; + + float SampleDepthBias = max(dot(DepthBiasDotFactors, SampleUVOffset), 0); + + VisibleLightAccumulation += saturate((SampleDepth - Settings.SceneDepth + SampleDepthBias) * Settings.TransitionScale + 1); + } + + float Visibility = VisibleLightAccumulation / float(PCSS_SAMPLES); + +#endif // PCSS_PCF_EXPERIMENT == 0 + +#if PCSS_ENABLE_POST_PCF_SHARPENING // Sharpen the PCF result. + { + // Average distance between samles in UV space. + const float AverageSampleDistance = sqrt(1 / (float(PCSS_SAMPLES) * PI)); + + // Maximum factor of sharpness to introduce. + const float MaxSharpnessFactor = 4; + + // Filter to avoid applying the sharpening filter on high frequency shadows. + float SharpenessFading = saturate(1.5 * (length(OccluderUVGradient) - AverageSampleDistance)); + + // Factor introducing the sharpness. + float FinalSharpenessFactor = lerp(1, clamp(PCFMinFilterSize / RawFilterRadius, 1, MaxSharpnessFactor), SharpenessFading); + + // Apply the sharpness onto the visibility. + Visibility = saturate(FinalSharpenessFactor * (Visibility - 0.5) + 0.5); + +#if 0 + if (Settings.DebugScreenUV.x > 0.8) return SharpeningFade; + if (Settings.DebugScreenUV.x > 0.5) return (SharpeningFactor - 1) * 0.25; +#endif + } +#endif //PCSS_ENABLE_POST_PCF_SHARPENING + +#if PCSS_SHARE_PER_PIXEL_QUAD >= 2 // Share PCF computation. + Visibility = lerp(Visibility, PQMPAverage(Settings.PQMPContext, Visibility), DoPerQuad * 0.5); +#endif + + return Visibility; +} diff --git a/Engine/Shaders/ShadowProjectionPixelShader.usf b/Engine/Shaders/ShadowProjectionPixelShader.usf index 95d24abf9cf7..6834bec2143f 100644 --- a/Engine/Shaders/ShadowProjectionPixelShader.usf +++ b/Engine/Shaders/ShadowProjectionPixelShader.usf @@ -8,8 +8,6 @@ #define FORCE_FLOATS (COMPILER_METAL) #endif -#include "Common.usf" - #ifndef USE_FADE_PLANE #define USE_FADE_PLANE 0 #endif @@ -18,6 +16,17 @@ #define SHADOW_QUALITY 6 #endif +#ifndef APPLY_TRANSLUCENCY_SHADOWS + #define APPLY_TRANSLUCENCY_SHADOWS 0 +#endif + +#ifndef USE_PCSS + #define USE_PCSS 0 +#endif + + +#include "Common.usf" + #if FEATURE_LEVEL >= FEATURE_LEVEL_SM5 // Gather() is supported #define FEATURE_GATHER4 1 @@ -28,6 +37,9 @@ #include "ShadowProjectionCommon.usf" #include "ShadowFilteringCommon.usf" +#if USE_PCSS +#include "ShadowPercentageCloserFiltering.usf" +#endif #include "DeferredShadingCommon.usf" #include "DynamicLightingCommon.usf" @@ -42,6 +54,13 @@ float2 ProjectionDepthBiasParameters; float InvFadePlaneLength; #endif +#if USE_PCSS + // PCSS specific parameters. + // - x: tan(0.5 * Directional Light Angle) in shadow projection space; + // - y: Max filter size in shadow tile UV space. + float4 PCSSParameters; +#endif + float4 ModulatedShadowColor; float4 ShadowTileOffsetAndSize; @@ -65,11 +84,21 @@ void Main( out float4 OutColor : SV_Target0 ) { + const FPQMPContext PQMPContext = PQMPInit(SVPos.xy); + float2 ScreenUV = float2( SVPos.xy * View.BufferSizeAndInvSize.zw ); float SceneW = CalcSceneDepth( ScreenUV ); - float2 ScreenPosition = ( ScreenUV.xy - View.ScreenPositionScaleBias.wz ) / View.ScreenPositionScaleBias.xy; - float4 ShadowPosition = mul(float4(ScreenPosition.xy * SceneW,SceneW,1), ScreenToShadowMatrix); + float4 ScreenPosition = float4(((ScreenUV.xy - View.ScreenPositionScaleBias.wz ) / View.ScreenPositionScaleBias.xy) * SceneW, SceneW, 1); + float4 ShadowPosition = mul(ScreenPosition, ScreenToShadowMatrix); + + #if USE_PCSS + float3 ScreenPositionDDX = ddx_fine(ScreenPosition.xyz); + float3 ScreenPositionDDY = ddy_fine(ScreenPosition.xyz); + float4 ShadowPositionDDX = mul(float4(ScreenPositionDDX, 0), ScreenToShadowMatrix); + float4 ShadowPositionDDY = mul(float4(ScreenPositionDDY, 0), ScreenToShadowMatrix); + #endif + // TODO: Take care of ShadowPositionDDX/Y for non directional shadows. ShadowPosition.xy /= ShadowPosition.w; #if MODULATED_SHADOWS @@ -89,42 +118,60 @@ void Main( float SSSTransmission = 1; float BlendFactor = 1; - -#if APPLY_TRANSLUCENCY_SHADOWS - Shadow = CalculateTranslucencyShadowing(ShadowPosition.xy, ShadowPosition.z); - -#else - // For debugging #define UNFILTERED_SHADOW_PROJECTION 0 + #if UNFILTERED_SHADOW_PROJECTION - + { Shadow = LightSpacePixelDepthForOpaque < Texture2DSampleLevel(ShadowDepthTexture, ShadowDepthTextureSampler, ShadowPosition.xy, 0).r; - - #else - + } + #elif APPLY_TRANSLUCENCY_SHADOWS + { + Shadow = CalculateTranslucencyShadowing(ShadowPosition.xy, ShadowPosition.z); + } + #elif USE_PCSS + { + FPCSSSamplerSettings Settings; + + Settings.ShadowDepthTexture = ShadowDepthTexture; + Settings.ShadowDepthTextureSampler = ShadowDepthTextureSampler; + Settings.ShadowBufferSize = ShadowBufferSize; + Settings.ShadowTileOffsetAndSize = ShadowTileOffsetAndSize; + Settings.SceneDepth = LightSpacePixelDepthForOpaque; + Settings.TransitionScale = SoftTransitionScale.z; + Settings.TanLightSourceAngle = PCSSParameters.x; + Settings.MaxKernelSize = PCSSParameters.y; + Settings.SvPosition = SVPos; + Settings.PQMPContext = PQMPContext; + Settings.DebugViewportUV = ScreenUV; + + Shadow = DirectionalPCSS(Settings, ShadowPosition.xy, ShadowPositionDDX.xyz, ShadowPositionDDY.xyz); + } + #else // !USE_PCSS + { FPCFSamplerSettings Settings; - + Settings.ShadowDepthTexture = ShadowDepthTexture; Settings.ShadowDepthTextureSampler = ShadowDepthTextureSampler; Settings.ShadowBufferSize = ShadowBufferSize; Settings.TransitionScale = SoftTransitionScale.z; Settings.SceneDepth = LightSpacePixelDepthForOpaque; Settings.bSubsurface = false; + Settings.bTreatMaxDepthUnshadowed = false; Settings.DensityMulConstant = 0; Settings.ProjectionDepthBiasParameters = 0; Shadow = ManualPCF(ShadowPosition.xy, Settings); - - #endif + } + #endif // !USE_PCSS #if USE_FADE_PLANE // Create a blend factor which is one before and at the fade plane, and lerps to zero at the far plane. BlendFactor = 1.0f - saturate((SceneW - FadePlaneOffset) * InvFadePlaneLength); #endif - #if FEATURE_LEVEL >= FEATURE_LEVEL_SM4 && !FORWARD_SHADING + #if FEATURE_LEVEL >= FEATURE_LEVEL_SM4 && !FORWARD_SHADING && !APPLY_TRANSLUCENCY_SHADOWS FGBufferData GBufferData = GetGBufferData(ScreenUV); @@ -160,6 +207,7 @@ void Main( Settings.TransitionScale = SoftTransitionScale.z; Settings.SceneDepth = LightSpacePixelDepthForSSS + ProjectionDepthBiasParameters.x; Settings.bSubsurface = true; + Settings.bTreatMaxDepthUnshadowed = false; Settings.DensityMulConstant = Density * ProjectionDepthBiasParameters.y; Settings.ProjectionDepthBiasParameters = ProjectionDepthBiasParameters; @@ -170,9 +218,11 @@ void Main( #endif -#endif - - Shadow = saturate( (Shadow - 0.5) * ShadowSharpen + 0.5 ); + #if !USE_PCSS + // There is no point changing the shadow sharpen on PCSS, can directly reduce the light + // source angle that would actually make the algorithm to run faster. + Shadow = saturate( (Shadow - 0.5) * ShadowSharpen + 0.5 ); + #endif // 0 is shadowed, 1 is unshadowed // RETURN_COLOR not needed unless writing to SceneColor; @@ -203,7 +253,7 @@ void Main( OutColor.a = 0; #if (ES2_PROFILE || ES3_1_PROFILE) && ( (COMPILER_GLSL_ES2) || (MOBILE_EMULATION) ) // Do decal blending if encoding requires it. - if (GetHDR32bppEncodeMode() == HDR_ENCODE_RGBA) + if (GetHDR32bppEncodeMode() == HDR_ENCODE_RGBE) { OutColor.rgb = ModulatedShadowBlendOp(OutColor.rgb); // do 32bpp hdr encoding for mobile if required. diff --git a/Engine/Shaders/SimpleElementPixelShader.usf b/Engine/Shaders/SimpleElementPixelShader.usf index 57a9fdf1ae46..3dd7c519c984 100644 --- a/Engine/Shaders/SimpleElementPixelShader.usf +++ b/Engine/Shaders/SimpleElementPixelShader.usf @@ -92,7 +92,7 @@ float3 SimpleElementFrameBufferBlendOp(float4 Source) float4 SimpleElementEncodeFor32BPPHDR(float4 OutColor) { #if ES2_PROFILE && USE_32BPP_HDR - if (GetHDR32bppEncodeMode() == HDR_ENCODE_RGBA) + if (GetHDR32bppEncodeMode() == HDR_ENCODE_RGBE) { OutColor.rgb = SimpleElementFrameBufferBlendOp(OutColor); } diff --git a/Engine/Shaders/SkyLighting.usf b/Engine/Shaders/SkyLighting.usf index 5fb7066f8298..f26307ae90ac 100644 --- a/Engine/Shaders/SkyLighting.usf +++ b/Engine/Shaders/SkyLighting.usf @@ -13,6 +13,12 @@ Texture2D BentNormalAOTexture; SamplerState BentNormalAOSampler; +// Unpack from [0-1] PF_FloatR11G11B10 +float3 DecodeBentNormal(float3 EncodedBentNormal) +{ + return EncodedBentNormal * 2 - 1; +} + Texture2D IrradianceTexture; SamplerState IrradianceSampler; @@ -43,7 +49,7 @@ void SkyLightDiffusePS( float3 DiffuseIrradiance = 0; #if APPLY_SHADOWING - float3 BentNormal = Texture2DSampleLevel(BentNormalAOTexture, BentNormalAOSampler, UV, 0).xyz; + float3 BentNormal = DecodeBentNormal(Texture2DSampleLevel(BentNormalAOTexture, BentNormalAOSampler, UV, 0).xyz); #define USE_DIRECTIONAL_OCCLUSION_ON_SKY_DIFFUSE 1 diff --git a/Engine/Shaders/SkyLightingShared.usf b/Engine/Shaders/SkyLightingShared.usf index 60fbff290511..7b469f0d0af7 100644 --- a/Engine/Shaders/SkyLightingShared.usf +++ b/Engine/Shaders/SkyLightingShared.usf @@ -19,6 +19,12 @@ float ApproximateConeConeIntersection(float ArcLength0, float ArcLength1, float Texture2D BentNormalAOTexture; SamplerState BentNormalAOSampler; +// Unpack from [0-1] PF_FloatR11G11B10 +float3 DecodeBentNormal(float3 EncodedBentNormal) +{ + return EncodedBentNormal * 2 - 1; +} + float ApplyBentNormalAO; float InvSkySpecularOcclusionStrength; float4 OcclusionTintAndMinOcclusion; @@ -32,8 +38,7 @@ void GetDistanceFieldAOSpecularOcclusion(float2 ScreenUV, float3 ReflectionVecto BRANCH if (ApplyBentNormalAO > 0) { - float4 TextureValue = Texture2DSampleLevel(BentNormalAOTexture, BentNormalAOSampler, ScreenUV, 0); - float3 BentNormalAO = TextureValue.xyz; + float3 BentNormalAO = DecodeBentNormal(Texture2DSampleLevel(BentNormalAOTexture, BentNormalAOSampler, ScreenUV, 0).xyz); float BentNormalLength = length(BentNormalAO); BRANCH @@ -68,7 +73,7 @@ void GetDistanceFieldAOSpecularOcclusion(float2 ScreenUV, float3 ReflectionVecto float GetDynamicSkyIndirectIrradiance(float2 ScreenUV, float3 WorldNormal) { - float3 BentNormal = Texture2DSampleLevel(BentNormalAOTexture, BentNormalAOSampler, ScreenUV, 0).xyz; + float3 BentNormal = DecodeBentNormal(Texture2DSampleLevel(BentNormalAOTexture, BentNormalAOSampler, ScreenUV, 0).xyz); float SkyVisibility = length(BentNormal); float3 DiffuseLookup = GetSkySHDiffuse(WorldNormal) * View.SkyLightColor.rgb; return Luminance(DiffuseLookup) * SkyVisibility; diff --git a/Engine/Shaders/SlateElementPixelShader.usf b/Engine/Shaders/SlateElementPixelShader.usf index 9f9b0c21bf82..6d4dbf337131 100644 --- a/Engine/Shaders/SlateElementPixelShader.usf +++ b/Engine/Shaders/SlateElementPixelShader.usf @@ -29,7 +29,7 @@ half3 GammaCorrect(half3 InColor) { half3 CorrectedColor = InColor; -#if (!(ES2_PROFILE || ES3_1_PROFILE)) || USE_MATERIALS || METAL_PROFILE // Metal supports sRGB textures +#if SOURCE_IN_LINEAR_SPACE FLATTEN if( GammaValues.y != 1.0f ) { CorrectedColor = ApplyGammaCorrection(CorrectedColor, GammaValues.x); @@ -141,7 +141,7 @@ half4 GetColor( VertexToPixelInterpolants InVertex, float2 UV ) // Make no assumptionn of what vertex color does in a custom material shader FinalColor = BaseColor; #else - FinalColor = BaseColor*InVertex.Color; + FinalColor = BaseColor * InVertex.Color; #endif return FinalColor; @@ -295,13 +295,18 @@ half4 Main( VertexToPixelInterpolants VIn ) : SV_Target0 #endif #if DRAW_DISABLED_EFFECT - //desaturate - half3 LumCoeffs = half3( 0.3, 0.59, .11 ); + #if SOURCE_IN_LINEAR_SPACE + half3 LumCoeffs = half3( 0.3, 0.59, .11 ); + half3 Grayish = half3(.1, .1, .1); + #else + // These are just the linear space values above converted to sRGB space. + half3 LumCoeffs = float3( 0.5843, 0.7921, 0.3647 ); + half3 Grayish = float3(0.349, 0.349, 0.349); + #endif + + //desaturate half Lum = dot( LumCoeffs, OutColor.rgb ); - OutColor.rgb = lerp( OutColor.rgb, half3(Lum,Lum,Lum), .8 ); - - half3 Grayish = {.1, .1, .1}; - + OutColor.rgb = lerp( OutColor.rgb, float3(Lum,Lum,Lum), .8 ); OutColor.rgb = lerp( OutColor.rgb, Grayish, clamp( distance( OutColor.rgb, Grayish ), 0, .8) ); #endif @@ -342,3 +347,20 @@ float4 DebugOverdrawMain( VertexToPixelInterpolants VIn ) : SV_Target0 return .1; } + +/** Batch Color */ +float4 BatchColor; + +float4 DebugBatchingMain(VertexToPixelInterpolants VIn) : SV_Target0 +{ + +#if !DEBUG_CLIPPING + // Clip pixels which are outside of the clipping rect + float2 ClipOrigin = VIn.ClipOriginAndPos.xy; + float2 WindowPos = VIn.ClipOriginAndPos.zw; + float4 ClipTest = PointInParallelogram(WindowPos, ClipOrigin, VIn.ClipExtents); + clip(ClipTest); +#endif + + return BatchColor; +} diff --git a/Engine/Shaders/SlateShaderCommon.usf b/Engine/Shaders/SlateShaderCommon.usf index 5b5c9cae66b0..9c57b9e7003f 100644 --- a/Engine/Shaders/SlateShaderCommon.usf +++ b/Engine/Shaders/SlateShaderCommon.usf @@ -17,6 +17,10 @@ #define NUM_SLATE_TEXCOORDS 1 #endif +// On mobile renderers we don't convert textures into linear space when slate is rendering. +// since the final output is a gamma space render target. +// Metal iOS supports sampling from sRGB textures +#define SOURCE_IN_LINEAR_SPACE !(ES2_PROFILE || ES3_1_PROFILE) || USE_MATERIALS || METAL_PROFILE /** Shader types (mirrored from ESlateShader::Type in RenderingCommon.h */ #define ST_Default 0 diff --git a/Engine/Shaders/SlateVertexShader.usf b/Engine/Shaders/SlateVertexShader.usf index 03589bc13379..ae9dd8a9a8dd 100644 --- a/Engine/Shaders/SlateVertexShader.usf +++ b/Engine/Shaders/SlateVertexShader.usf @@ -28,7 +28,7 @@ VertexToPixelInterpolants Main( // save off the original input position value, Line AA will require this VOut.OriginalPosition = WorldPosition; -#if (!(ES2_PROFILE || ES3_1_PROFILE)) || USE_MATERIALS || METAL_PROFILE +#if SOURCE_IN_LINEAR_SPACE InColor.rgb = sRGBToLinear(InColor.rgb); #endif @@ -40,7 +40,7 @@ VertexToPixelInterpolants Main( VOut.Color = FinalVertexColor; VOut.TextureCoordinates[0] = InTextureCoordinates; -#if USE_MATERIALS +#if USE_MATERIALS FMaterialVertexParameters VertexParameters = (FMaterialVertexParameters)0; VertexParameters.WorldPosition = WorldPosition.xyz; @@ -49,7 +49,7 @@ VertexToPixelInterpolants Main( #if NUM_MATERIAL_TEXCOORDS_VERTEX #if !USE_SLATE_INSTANCING - // pass along local screen space size + // pass along local screen space size // To look this up in a material you use uv channel 3 float4 InstanceParam = float4(0,0, PixelSize); #endif diff --git a/Engine/Shaders/TiledDeferredLightShaders.usf b/Engine/Shaders/TiledDeferredLightShaders.usf index aead20158136..85a9a118113c 100644 --- a/Engine/Shaders/TiledDeferredLightShaders.usf +++ b/Engine/Shaders/TiledDeferredLightShaders.usf @@ -271,7 +271,7 @@ void TiledDeferredLightingMain( LightData.ShadowedBits = dot(LightData.ShadowMapChannelMask, float4(1, 1, 1, 1)); // Lights requiring light attenuation are not supported tiled for now - CompositedLighting += GetDynamicLighting(WorldPosition, CameraVector, ScreenSpaceData.GBuffer, ScreenSpaceData.AmbientOcclusion, InGBufferData.ShadingModelID, LightData, float4(1, 1, 1, 1), uint2(0,0)); + CompositedLighting += GetDynamicLighting(WorldPosition, CameraVector, ScreenSpaceData.GBuffer, ScreenSpaceData.AmbientOcclusion, InGBufferData.ShadingModelID, LightData, float4(1, 1, 1, 1), 0.5, uint2(0,0)); } // The simple shading model does not depend on ShadingModelID, so use it anytime the material is lit diff --git a/Engine/Shaders/TranslucencyUpsampling.usf b/Engine/Shaders/TranslucencyUpsampling.usf new file mode 100644 index 000000000000..d17def075b46 --- /dev/null +++ b/Engine/Shaders/TranslucencyUpsampling.usf @@ -0,0 +1,22 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +/*============================================================================= + TranslucencyUpsampling.usf: PostProcessing shader to upscale +=============================================================================*/ + +#include "Common.usf" +#include "SeparateTranslucency.usf" + +// Texture2D SceneDepthTexture +Texture2D LowResColorTexture; +float4 LowResColorTexelSize; + +void SimpleUpsamplingPS(FScreenVertexOutput Input, out float4 OutColor : SV_Target0) +{ + OutColor = BilinearUpsampling(Input.UV, LowResColorTexture); +} + +void NearestDepthNeighborUpsamplingPS(FScreenVertexOutput Input, out float4 OutColor : SV_Target0) +{ + OutColor = NearestDepthNeighborUpsampling(Input.Position.xy, Input.UV, LowResColorTexture, LowResColorTexelSize.zw); +} diff --git a/Engine/Shaders/UpdateTextureShaders.usf b/Engine/Shaders/UpdateTextureShaders.usf index 33a6940c2497..9b860c503c16 100644 --- a/Engine/Shaders/UpdateTextureShaders.usf +++ b/Engine/Shaders/UpdateTextureShaders.usf @@ -47,7 +47,10 @@ Texture2D SrcTexture; [numthreads(8,8,1)] void CopyTexture2DCS( uint3 ThreadId : SV_DispatchThreadID ) { - DestTexture[ThreadId.xy] = SrcTexture.Load(int3(ThreadId.x, ThreadId.y, 0)); + if (all(ThreadId.xy >= DestPosSize.xy) && all(ThreadId.xy < DestPosSize.zw)) + { + DestTexture[ThreadId.xy] = SrcTexture.Load(int3(ThreadId.x, ThreadId.y, 0)); + } } Buffer SrcCopyBuffer; diff --git a/Engine/Shaders/VolumeLightingCommon.usf b/Engine/Shaders/VolumeLightingCommon.usf index 5234e8ef1071..195af9d60cec 100644 --- a/Engine/Shaders/VolumeLightingCommon.usf +++ b/Engine/Shaders/VolumeLightingCommon.usf @@ -72,6 +72,8 @@ float ComputeVolumeShadowing(float3 WorldPositionForLighting, bool bPointLight, Settings.SceneDepth = HomogeneousShadowPosition.z; Settings.TransitionScale = 40; Settings.bSubsurface = false; + // We can sample outside of the static shadowmap, which is centered around the scene. These 'infinite' depth values should not cause occlusion. + Settings.bTreatMaxDepthUnshadowed = true; Settings.DensityMulConstant = 0; Settings.ProjectionDepthBiasParameters = float2(0, 0); diff --git a/Engine/Shaders/VolumetricFog.usf b/Engine/Shaders/VolumetricFog.usf index 6abba5750f57..0bdccdfa4e79 100644 --- a/Engine/Shaders/VolumetricFog.usf +++ b/Engine/Shaders/VolumetricFog.usf @@ -61,6 +61,7 @@ float3 ScatteringFunction() } float3 GlobalAlbedo; +float3 GlobalEmissive; float GlobalExtinctionScale; #ifndef THREADGROUP_SIZE @@ -94,7 +95,7 @@ void MaterialSetupCS( if (all((int3)GridCoordinate < VolumetricFog.GridSizeInt)) { RWVBufferA[GridCoordinate] = float4(Scattering, Absorption); - RWVBufferB[GridCoordinate] = float4(0, 0, 0, 0); + RWVBufferB[GridCoordinate] = float4(GlobalEmissive, 0); } } @@ -175,7 +176,9 @@ void WriteToBoundingSphereVS( Output.LayerIndex = LayerIndex + MinZ; } -float3 FrameJitterOffset; +float HistoryWeight; +float4 FrameJitterOffsets[16]; +uint HistoryMissSuperSampleCount; float PhaseG; float InverseSquaredLightDistanceBiasScale; @@ -193,58 +196,87 @@ void InjectShadowedLocalLightPS( uint3 GridCoordinate = uint3(SvPosition.xy, Input.LayerIndex); - float3 CellOffset = FrameJitterOffset; - //float CellOffset = .5f; - - float SceneDepth; - float3 WorldPosition = ComputeCellWorldPosition(GridCoordinate, CellOffset, SceneDepth); - float3 CameraVector = normalize(WorldPosition - View.WorldCameraOrigin); - - FDeferredLightData LightData; - LightData.LightPositionAndInvRadius = float4(DeferredLightUniforms.LightPosition, DeferredLightUniforms.LightInvRadius); - LightData.LightColorAndFalloffExponent = float4(DeferredLightUniforms.LightColor, DeferredLightUniforms.LightFalloffExponent); - LightData.LightDirection = DeferredLightUniforms.NormalizedLightDirection; - LightData.SpotAnglesAndSourceRadius = float4(DeferredLightUniforms.SpotAngles, DeferredLightUniforms.SourceRadius, DeferredLightUniforms.SourceLength); - LightData.MinRoughness = DeferredLightUniforms.MinRoughness; - LightData.ContactShadowLength = DeferredLightUniforms.ContactShadowLength; - LightData.DistanceFadeMAD = DeferredLightUniforms.DistanceFadeMAD; - LightData.ShadowMapChannelMask = DeferredLightUniforms.ShadowMapChannelMask; - LightData.ShadowedBits = DeferredLightUniforms.ShadowedBits; - - LightData.bInverseSquared = INVERSE_SQUARED_FALLOFF; - LightData.bRadialLight = true; - LightData.bSpotLight = LightData.SpotAnglesAndSourceRadius.x > -2.0f; - - float VolumetricScatteringIntensity = DeferredLightUniforms.VolumetricScatteringIntensity; - - float3 L = 0; - float3 ToLight = 0; - float NoL = 0; - float DistanceAttenuation = 1; - float LightRadiusMask = 1; - float SpotFalloff = 1; - - float CellRadius = length(WorldPosition - ComputeCellWorldPosition(GridCoordinate + uint3(1, 1, 1), CellOffset)); - // Bias the inverse squared light falloff based on voxel size to prevent aliasing near the light source - float DistanceBias = max(CellRadius * InverseSquaredLightDistanceBiasScale, 1); - GetLocalLightAttenuation(WorldPosition, float3(0, 0, 1), LightData, DistanceBias * DistanceBias, ToLight, L, NoL, DistanceAttenuation, LightRadiusMask, SpotFalloff); - float CombinedAttenuation = DistanceAttenuation * LightRadiusMask * SpotFalloff; - - float ShadowFactor = 1.0f; - - if (CombinedAttenuation > 0) + // Somehow pixels are being rasterized outside of the viewport on a 970 GTX, perhaps due to use of a geometry shader bypassing the viewport scissor. + // This triggers the HistoryMissSuperSampleCount path causing significant overhead for shading off-screen pixels. + if (all(GridCoordinate < VolumetricFog.GridSizeInt)) { - ShadowFactor = ComputeVolumeShadowing(WorldPosition, LightData.bRadialLight && !LightData.bSpotLight, LightData.bSpotLight); - } + FDeferredLightData LightData; + LightData.LightPositionAndInvRadius = float4(DeferredLightUniforms.LightPosition, DeferredLightUniforms.LightInvRadius); + LightData.LightColorAndFalloffExponent = float4(DeferredLightUniforms.LightColor, DeferredLightUniforms.LightFalloffExponent); + LightData.LightDirection = DeferredLightUniforms.NormalizedLightDirection; + LightData.SpotAnglesAndSourceRadius = float4(DeferredLightUniforms.SpotAngles, DeferredLightUniforms.SourceRadius, DeferredLightUniforms.SourceLength); + LightData.MinRoughness = DeferredLightUniforms.MinRoughness; + LightData.ContactShadowLength = DeferredLightUniforms.ContactShadowLength; + LightData.DistanceFadeMAD = DeferredLightUniforms.DistanceFadeMAD; + LightData.ShadowMapChannelMask = DeferredLightUniforms.ShadowMapChannelMask; + LightData.ShadowedBits = DeferredLightUniforms.ShadowedBits; - OutScattering.rgb = DeferredLightUniforms.LightColor - * (PhaseFunction(PhaseG, dot(L, -CameraVector)) * CombinedAttenuation * ShadowFactor * VolumetricScatteringIntensity); + LightData.bInverseSquared = INVERSE_SQUARED_FALLOFF; + LightData.bRadialLight = true; + LightData.bSpotLight = LightData.SpotAnglesAndSourceRadius.x > -2.0f; + + float VolumetricScatteringIntensity = DeferredLightUniforms.VolumetricScatteringIntensity; + + float3 L = 0; + float3 ToLight = 0; + float NoL = 0; + float DistanceAttenuation = 1; + float LightRadiusMask = 1; + float SpotFalloff = 1; + + uint NumSuperSamples = 1; + +#if USE_TEMPORAL_REPROJECTION + + float3 HistoryUV = ComputeVolumeUV(ComputeCellWorldPosition(GridCoordinate, .5f), UnjitteredPrevWorldToClip); + float HistoryAlpha = HistoryWeight; + + FLATTEN + if (any(HistoryUV < 0) || any(HistoryUV > 1)) + { + HistoryAlpha = 0; + } + + NumSuperSamples = HistoryAlpha < .001f ? HistoryMissSuperSampleCount : 1; + +#endif + + for (uint SampleIndex = 0; SampleIndex < NumSuperSamples; SampleIndex++) + { + float3 CellOffset = FrameJitterOffsets[SampleIndex].xyz; + //float CellOffset = .5f; + + float SceneDepth; + float3 WorldPosition = ComputeCellWorldPosition(GridCoordinate, CellOffset, SceneDepth); + float3 CameraVector = normalize(WorldPosition - View.WorldCameraOrigin); + + float CellRadius = length(WorldPosition - ComputeCellWorldPosition(GridCoordinate + uint3(1, 1, 1), CellOffset)); + // Bias the inverse squared light falloff based on voxel size to prevent aliasing near the light source + float DistanceBias = max(CellRadius * InverseSquaredLightDistanceBiasScale, 1); + GetLocalLightAttenuation(WorldPosition, float3(0, 0, 1), LightData, DistanceBias * DistanceBias, ToLight, L, NoL, DistanceAttenuation, LightRadiusMask, SpotFalloff); + float CombinedAttenuation = DistanceAttenuation * LightRadiusMask * SpotFalloff; + + float ShadowFactor = 1.0f; + + if (CombinedAttenuation > 0) + { + ShadowFactor = ComputeVolumeShadowing(WorldPosition, LightData.bRadialLight && !LightData.bSpotLight, LightData.bSpotLight); + } + + OutScattering.rgb += DeferredLightUniforms.LightColor + * (PhaseFunction(PhaseG, dot(L, -CameraVector)) * CombinedAttenuation * ShadowFactor * VolumetricScatteringIntensity); + + // To debug culling + //OutScattering.rgb += DeferredLightUniforms.LightColor * .0000001f; + } + + OutScattering.rgb /= (float)NumSuperSamples; + } } Texture3D VBufferA; Texture3D VBufferB; -float HistoryWeight; Texture3D LightScatteringHistory; SamplerState LightScatteringHistorySampler; @@ -396,6 +428,8 @@ float ComputeStaticShadowing(float3 WorldPosition) Settings.SceneDepth = HomogeneousShadowPosition.z; Settings.TransitionScale = 40; Settings.bSubsurface = false; + // We can sample outside of the static shadowmap, which is centered around the lightmass importance volume. These 'infinite' depth values should not cause occlusion. + Settings.bTreatMaxDepthUnshadowed = true; Settings.DensityMulConstant = 0; Settings.ProjectionDepthBiasParameters = float2(0, 0); @@ -403,7 +437,7 @@ float ComputeStaticShadowing(float3 WorldPosition) #else // Sample the shadowmap depth and determine if this voxel is shadowed float ShadowDepth = Texture2DSampleLevel(ForwardGlobalLightData.DirectionalLightStaticShadowmap, ForwardGlobalLightData.StaticShadowmapSampler, ShadowUVs, 0).x; - ShadowFactor = HomogeneousShadowPosition.z < ShadowDepth; + ShadowFactor = HomogeneousShadowPosition.z < ShadowDepth || ShadowDepth > .99f; #endif } } @@ -423,155 +457,11 @@ void LightScatteringCS( uint3 GroupThreadId : SV_GroupThreadID) { uint3 GridCoordinate = DispatchThreadId; - - float3 CellOffset = FrameJitterOffset; - //float CellOffset = .5f; - - float SceneDepth; - float3 WorldPosition = ComputeCellWorldPosition(GridCoordinate, CellOffset, SceneDepth); - float CameraVectorLength = length(WorldPosition - View.WorldCameraOrigin); - float3 CameraVector = (WorldPosition - View.WorldCameraOrigin) / CameraVectorLength; - float4 MaterialScatteringAndAbsorption = VBufferA[GridCoordinate]; - - // Shadowed point and spot lights were computed earlier - float3 LightScattering = LocalShadowedLightScattering[GridCoordinate].xyz; - - BRANCH - if (ForwardGlobalLightData.HasDirectionalLight) - { - float ShadowFactor = ComputeStaticShadowing(WorldPosition); - - if (ForwardGlobalLightData.NumDirectionalLightCascades > 0 && UseDirectionalLightShadowing > 0) - { - uint CascadeIndex = ForwardGlobalLightData.NumDirectionalLightCascades; - - for (uint TestCascadeIndex = 0; TestCascadeIndex < ForwardGlobalLightData.NumDirectionalLightCascades; TestCascadeIndex++) - { - if (SceneDepth < ForwardGlobalLightData.CascadeEndDepths[TestCascadeIndex]) - { - CascadeIndex = TestCascadeIndex; - break; - } - } - - if (CascadeIndex < ForwardGlobalLightData.NumDirectionalLightCascades) - { - // Transform the world position into shadowmap space - float4 HomogeneousShadowPosition = mul(float4(WorldPosition, 1), ForwardGlobalLightData.DirectionalLightWorldToShadowMatrix[CascadeIndex]); - float2 ShadowUVs = HomogeneousShadowPosition.xy / HomogeneousShadowPosition.w; - float4 ShadowmapMinMax = ForwardGlobalLightData.DirectionalLightShadowmapMinMax[CascadeIndex]; - - // Treat as unshadowed if the voxel is outside of the shadow map - if (all(ShadowUVs >= ShadowmapMinMax.xy && ShadowUVs <= ShadowmapMinMax.zw)) - { - // Sample the shadowmap depth and determine if this voxel is shadowed - float ShadowDepth = Texture2DSampleLevel(ForwardGlobalLightData.DirectionalLightShadowmapAtlas, ForwardGlobalLightData.ShadowmapSampler, ShadowUVs, 0).x; - ShadowFactor = HomogeneousShadowPosition.z < ShadowDepth - ForwardGlobalLightData.DirectionalLightDepthBias.x; - } - } - } - - ShadowFactor *= GetLightFunction(WorldPosition); - - float3 DirectionalLightColor = ForwardGlobalLightData.DirectionalLightColor; - - if (UseHeightFogColors > 0) - { - // Attempt to maintain intensity ratio between sky and sun - DirectionalLightColor = VolumetricFog.HeightFogDirectionalLightInscatteringColor * Luminance(ForwardGlobalLightData.DirectionalLightColor); - } - - LightScattering += DirectionalLightColor - * (ShadowFactor - * ForwardGlobalLightData.DirectionalLightVolumetricScatteringIntensity - * PhaseFunction(PhaseG, dot(ForwardGlobalLightData.DirectionalLightDirection, -CameraVector))); - } - - // Skylight - if (SkyLightVolumetricScatteringIntensity > 0) - { - FTwoBandSHVector RotatedHGZonalHarmonic; - RotatedHGZonalHarmonic.V = float4(1.0f, CameraVector.y, CameraVector.z, CameraVector.x) * float4(1.0f, PhaseG, PhaseG, PhaseG); - - float3 SkyLighting; - - if (UseHeightFogColors > 0) - { - float3 HeightFogInscatteringColor = ComputeInscatteringColor(CameraVector, CameraVectorLength); - float ScalarFactor = SHAmbientFunction(); - FTwoBandSHVectorRGB SkyIrradianceSH; - SkyIrradianceSH.R.V = float4(ScalarFactor * HeightFogInscatteringColor.r, 0, 0, 0); - SkyIrradianceSH.G.V = float4(ScalarFactor * HeightFogInscatteringColor.g, 0, 0, 0); - SkyIrradianceSH.B.V = float4(ScalarFactor * HeightFogInscatteringColor.b, 0, 0, 0); - - SkyLighting = max(DotSH(SkyIrradianceSH, RotatedHGZonalHarmonic), 0); - } - else - { - FTwoBandSHVectorRGB SkyIrradianceSH; - SkyIrradianceSH.R.V = SkySH[0]; - SkyIrradianceSH.G.V = SkySH[1]; - SkyIrradianceSH.B.V = SkySH[2]; - - SkyLighting = View.SkyLightColor.rgb * max(DotSH(SkyIrradianceSH, RotatedHGZonalHarmonic), 0) / PI; - } - - float SkyVisibility = ComputeSkyVisibility(WorldPosition); - LightScattering += (SkyVisibility * SkyLightVolumetricScatteringIntensity) * SkyLighting; - } - - uint GridIndex = ComputeLightGridCellIndex(GridCoordinate.xy * VolumetricFog.FogGridToPixelXY, SceneDepth, 0); - const FCulledLightsGridData CulledLightsGrid = GetCulledLightsGrid(GridIndex, 0); - - float CellRadius = length(WorldPosition - ComputeCellWorldPosition(GridCoordinate + uint3(1, 1, 1), CellOffset)); - // Bias the inverse squared light falloff based on voxel size to prevent aliasing near the light source - float DistanceBiasSqr = max(CellRadius * InverseSquaredLightDistanceBiasScale, 1); - DistanceBiasSqr *= DistanceBiasSqr; - - // Forward lighting of unshadowed point and spot lights - LOOP - for (uint LocalLightListIndex = 0; LocalLightListIndex < CulledLightsGrid.NumLocalLights; LocalLightListIndex++) - { - const FLocalLightData LocalLight = GetLocalLightData(CulledLightsGrid.DataStartIndex + LocalLightListIndex, 0); - - float VolumetricScatteringIntensity = f16tof32(asuint(LocalLight.SpotAnglesAndSourceRadiusPacked.w) >> 16); - - if (VolumetricScatteringIntensity > 0) - { - FDeferredLightData LightData = (FDeferredLightData)0; - LightData.LightPositionAndInvRadius = LocalLight.LightPositionAndInvRadius; - LightData.LightColorAndFalloffExponent = LocalLight.LightColorAndFalloffExponent; - LightData.LightDirection = LocalLight.LightDirectionAndShadowMask.xyz; - float SourceLength = f16tof32(asuint(LocalLight.SpotAnglesAndSourceRadiusPacked.w)); - LightData.SpotAnglesAndSourceRadius = float4(LocalLight.SpotAnglesAndSourceRadiusPacked.xyz, SourceLength); - LightData.bInverseSquared = LightData.LightColorAndFalloffExponent.w == 0; - LightData.bRadialLight = true; - LightData.bSpotLight = LightData.SpotAnglesAndSourceRadius.x > -2.0f; - - float3 L = 0; - float3 ToLight = 0; - float NoL = 0; - float DistanceAttenuation = 1; - float LightRadiusMask = 1; - float SpotFalloff = 1; - - GetLocalLightAttenuation(WorldPosition, float3(0, 0, 1), LightData, DistanceBiasSqr, ToLight, L, NoL, DistanceAttenuation, LightRadiusMask, SpotFalloff); - - float CombinedAttenuation = DistanceAttenuation * LightRadiusMask * SpotFalloff; - - LightScattering += LocalLight.LightColorAndFalloffExponent.xyz - * (PhaseFunction(PhaseG, dot(L, -CameraVector)) * CombinedAttenuation * VolumetricScatteringIntensity); - } - } - - float Extinction = MaterialScatteringAndAbsorption.w + Luminance(MaterialScatteringAndAbsorption.xyz); - float3 MaterialEmissive = VBufferB[GridCoordinate].xyz; - float4 ScatteringAndExtinction = EncodeHDR(float4(LightScattering * MaterialScatteringAndAbsorption.xyz + MaterialEmissive, Extinction)); + float3 LightScattering = 0; + uint NumSuperSamples = 1; #if USE_TEMPORAL_REPROJECTION float3 HistoryUV = ComputeVolumeUV(ComputeCellWorldPosition(GridCoordinate, .5f), UnjitteredPrevWorldToClip); - float4 HistoryScatteringAndExtinction = Texture3DSampleLevel(LightScatteringHistory, LightScatteringHistorySampler, HistoryUV, 0); - float HistoryAlpha = HistoryWeight; FLATTEN @@ -580,7 +470,172 @@ void LightScatteringCS( HistoryAlpha = 0; } - ScatteringAndExtinction = lerp(ScatteringAndExtinction, HistoryScatteringAndExtinction, HistoryAlpha); + // Supersample if the history was outside the camera frustum + // The compute shader is dispatched with extra threads, make sure those don't supersample + NumSuperSamples = HistoryAlpha < .001f && all(GridCoordinate < VolumetricFog.GridSizeInt) ? HistoryMissSuperSampleCount : 1; + +#endif + + for (uint SampleIndex = 0; SampleIndex < NumSuperSamples; SampleIndex++) + { + float3 CellOffset = FrameJitterOffsets[SampleIndex].xyz; + //float CellOffset = .5f; + + float SceneDepth; + float3 WorldPosition = ComputeCellWorldPosition(GridCoordinate, CellOffset, SceneDepth); + float CameraVectorLength = length(WorldPosition - View.WorldCameraOrigin); + float3 CameraVector = (WorldPosition - View.WorldCameraOrigin) / CameraVectorLength; + + BRANCH + if (ForwardGlobalLightData.HasDirectionalLight) + { + float ShadowFactor = ComputeStaticShadowing(WorldPosition); + + if (ForwardGlobalLightData.NumDirectionalLightCascades > 0 && UseDirectionalLightShadowing > 0) + { + uint CascadeIndex = ForwardGlobalLightData.NumDirectionalLightCascades; + + for (uint TestCascadeIndex = 0; TestCascadeIndex < ForwardGlobalLightData.NumDirectionalLightCascades; TestCascadeIndex++) + { + if (SceneDepth < ForwardGlobalLightData.CascadeEndDepths[TestCascadeIndex]) + { + CascadeIndex = TestCascadeIndex; + break; + } + } + + if (CascadeIndex < ForwardGlobalLightData.NumDirectionalLightCascades) + { + // Transform the world position into shadowmap space + float4 HomogeneousShadowPosition = mul(float4(WorldPosition, 1), ForwardGlobalLightData.DirectionalLightWorldToShadowMatrix[CascadeIndex]); + float2 ShadowUVs = HomogeneousShadowPosition.xy / HomogeneousShadowPosition.w; + float4 ShadowmapMinMax = ForwardGlobalLightData.DirectionalLightShadowmapMinMax[CascadeIndex]; + + // Treat as unshadowed if the voxel is outside of the shadow map + if (all(ShadowUVs >= ShadowmapMinMax.xy && ShadowUVs <= ShadowmapMinMax.zw)) + { + // Sample the shadowmap depth and determine if this voxel is shadowed + float ShadowDepth = Texture2DSampleLevel(ForwardGlobalLightData.DirectionalLightShadowmapAtlas, ForwardGlobalLightData.ShadowmapSampler, ShadowUVs, 0).x; + ShadowFactor = HomogeneousShadowPosition.z < ShadowDepth - ForwardGlobalLightData.DirectionalLightDepthBias.x; + } + } + } + + ShadowFactor *= GetLightFunction(WorldPosition); + + float3 DirectionalLightColor = ForwardGlobalLightData.DirectionalLightColor; + + if (UseHeightFogColors > 0) + { + // Attempt to maintain intensity ratio between sky and sun + DirectionalLightColor = VolumetricFog.HeightFogDirectionalLightInscatteringColor * Luminance(ForwardGlobalLightData.DirectionalLightColor); + } + + LightScattering += DirectionalLightColor + * (ShadowFactor + * ForwardGlobalLightData.DirectionalLightVolumetricScatteringIntensity + * PhaseFunction(PhaseG, dot(ForwardGlobalLightData.DirectionalLightDirection, -CameraVector))); + } + + // Skylight + if (SkyLightVolumetricScatteringIntensity > 0) + { + FTwoBandSHVector RotatedHGZonalHarmonic; + RotatedHGZonalHarmonic.V = float4(1.0f, CameraVector.y, CameraVector.z, CameraVector.x) * float4(1.0f, PhaseG, PhaseG, PhaseG); + + float3 SkyLighting; + + if (UseHeightFogColors > 0) + { + float3 HeightFogInscatteringColor = ComputeInscatteringColor(CameraVector, CameraVectorLength); + float ScalarFactor = SHAmbientFunction(); + FTwoBandSHVectorRGB SkyIrradianceSH; + SkyIrradianceSH.R.V = float4(ScalarFactor * HeightFogInscatteringColor.r, 0, 0, 0); + SkyIrradianceSH.G.V = float4(ScalarFactor * HeightFogInscatteringColor.g, 0, 0, 0); + SkyIrradianceSH.B.V = float4(ScalarFactor * HeightFogInscatteringColor.b, 0, 0, 0); + + SkyLighting = max(DotSH(SkyIrradianceSH, RotatedHGZonalHarmonic), 0); + } + else + { + FTwoBandSHVectorRGB SkyIrradianceSH; + SkyIrradianceSH.R.V = SkySH[0]; + SkyIrradianceSH.G.V = SkySH[1]; + SkyIrradianceSH.B.V = SkySH[2]; + + SkyLighting = View.SkyLightColor.rgb * max(DotSH(SkyIrradianceSH, RotatedHGZonalHarmonic), 0) / PI; + } + + float SkyVisibility = ComputeSkyVisibility(WorldPosition); + LightScattering += (SkyVisibility * SkyLightVolumetricScatteringIntensity) * SkyLighting; + } + + uint GridIndex = ComputeLightGridCellIndex(GridCoordinate.xy * VolumetricFog.FogGridToPixelXY, SceneDepth, 0); + const FCulledLightsGridData CulledLightsGrid = GetCulledLightsGrid(GridIndex, 0); + + float CellRadius = length(WorldPosition - ComputeCellWorldPosition(GridCoordinate + uint3(1, 1, 1), CellOffset)); + // Bias the inverse squared light falloff based on voxel size to prevent aliasing near the light source + float DistanceBiasSqr = max(CellRadius * InverseSquaredLightDistanceBiasScale, 1); + DistanceBiasSqr *= DistanceBiasSqr; + + // Forward lighting of unshadowed point and spot lights + LOOP + for (uint LocalLightListIndex = 0; LocalLightListIndex < CulledLightsGrid.NumLocalLights; LocalLightListIndex++) + { + const FLocalLightData LocalLight = GetLocalLightData(CulledLightsGrid.DataStartIndex + LocalLightListIndex, 0); + + float VolumetricScatteringIntensity = f16tof32(asuint(LocalLight.SpotAnglesAndSourceRadiusPacked.w) >> 16); + + if (VolumetricScatteringIntensity > 0) + { + FDeferredLightData LightData = (FDeferredLightData)0; + LightData.LightPositionAndInvRadius = LocalLight.LightPositionAndInvRadius; + LightData.LightColorAndFalloffExponent = LocalLight.LightColorAndFalloffExponent; + LightData.LightDirection = LocalLight.LightDirectionAndShadowMask.xyz; + float SourceLength = f16tof32(asuint(LocalLight.SpotAnglesAndSourceRadiusPacked.w)); + LightData.SpotAnglesAndSourceRadius = float4(LocalLight.SpotAnglesAndSourceRadiusPacked.xyz, SourceLength); + LightData.bInverseSquared = LightData.LightColorAndFalloffExponent.w == 0; + LightData.bRadialLight = true; + LightData.bSpotLight = LightData.SpotAnglesAndSourceRadius.x > -2.0f; + + float3 L = 0; + float3 ToLight = 0; + float NoL = 0; + float DistanceAttenuation = 1; + float LightRadiusMask = 1; + float SpotFalloff = 1; + + GetLocalLightAttenuation(WorldPosition, float3(0, 0, 1), LightData, DistanceBiasSqr, ToLight, L, NoL, DistanceAttenuation, LightRadiusMask, SpotFalloff); + + float CombinedAttenuation = DistanceAttenuation * LightRadiusMask * SpotFalloff; + + LightScattering += LocalLight.LightColorAndFalloffExponent.xyz + * (PhaseFunction(PhaseG, dot(L, -CameraVector)) * CombinedAttenuation * VolumetricScatteringIntensity); + + // To debug culling + //LightScattering += LocalLight.LightColorAndFalloffExponent.xyz * .0000001f; + } + } + } + + LightScattering /= (float)NumSuperSamples; + + // Shadowed point and spot lights were computed earlier + LightScattering += LocalShadowedLightScattering[GridCoordinate].xyz; + + float4 MaterialScatteringAndAbsorption = VBufferA[GridCoordinate]; + float Extinction = MaterialScatteringAndAbsorption.w + Luminance(MaterialScatteringAndAbsorption.xyz); + float3 MaterialEmissive = VBufferB[GridCoordinate].xyz; + float4 ScatteringAndExtinction = EncodeHDR(float4(LightScattering * MaterialScatteringAndAbsorption.xyz + MaterialEmissive, Extinction)); + +#if USE_TEMPORAL_REPROJECTION + BRANCH + if (HistoryAlpha > 0) + { + float4 HistoryScatteringAndExtinction = Texture3DSampleLevel(LightScatteringHistory, LightScatteringHistorySampler, HistoryUV, 0); + ScatteringAndExtinction = lerp(ScatteringAndExtinction, HistoryScatteringAndExtinction, HistoryAlpha); + } + #endif if (all(GridCoordinate < VolumetricFog.GridSizeInt)) diff --git a/Engine/Source/Developer/Apple/MetalShaderFormat/Private/MetalBackend.cpp b/Engine/Source/Developer/Apple/MetalShaderFormat/Private/MetalBackend.cpp index 1e41074d3fe1..7d34bd904921 100644 --- a/Engine/Source/Developer/Apple/MetalShaderFormat/Private/MetalBackend.cpp +++ b/Engine/Source/Developer/Apple/MetalShaderFormat/Private/MetalBackend.cpp @@ -4435,7 +4435,6 @@ bool FMetalCodeBackend::GenerateMain(EHlslShaderFrequency Frequency, const char* { check(!Variable->type->is_array()); check(Variable->semantic); - check(Variable->semantic); int attributeIndex = -1; #if PLATFORM_WINDOWS sscanf_s(Variable->semantic, "[[ attribute(ATTRIBUTE%d) ]]", &attributeIndex); @@ -4454,7 +4453,7 @@ bool FMetalCodeBackend::GenerateMain(EHlslShaderFrequency Frequency, const char* { instance_id = Variable; } - else if (!Variable->semantic || strcmp(Variable->semantic, "SV_POSITION") != 0) + else if (strcmp(Variable->semantic, "SV_POSITION") != 0) { // @todo Error about the ignored variables - audit to ensure only SV_Position is duplicated _mesa_glsl_error(ParseState, "Unhandled input variable %s [[%s]] found in tessellation shader.\n", Variable->name, Variable->semantic); diff --git a/Engine/Source/Developer/Apple/MetalShaderFormat/Private/MetalShaderCompiler.cpp b/Engine/Source/Developer/Apple/MetalShaderFormat/Private/MetalShaderCompiler.cpp index 33e20feb21e3..4ba3197b5e4c 100644 --- a/Engine/Source/Developer/Apple/MetalShaderFormat/Private/MetalShaderCompiler.cpp +++ b/Engine/Source/Developer/Apple/MetalShaderFormat/Private/MetalShaderCompiler.cpp @@ -1166,7 +1166,7 @@ static void BuildMetalShaderOutput( ShaderOutput.bSucceeded = bSucceeded || ShaderOutput.bSucceeded; } - + if (ShaderInput.Environment.CompilerFlags.Contains(CFLAG_KeepDebugInfo)) { // store data we can pickup later with ShaderCode.FindOptionalData('n'), could be removed for shipping diff --git a/Engine/Source/Developer/Apple/MetalShaderFormat/Private/MetalUtils.cpp b/Engine/Source/Developer/Apple/MetalShaderFormat/Private/MetalUtils.cpp index 74f3e0488c93..8a2c620e2141 100644 --- a/Engine/Source/Developer/Apple/MetalShaderFormat/Private/MetalUtils.cpp +++ b/Engine/Source/Developer/Apple/MetalShaderFormat/Private/MetalUtils.cpp @@ -2541,7 +2541,7 @@ void FMetalCodeBackend::PackInputsAndOutputs(exec_list* Instructions, _mesa_glsl */ } -struct FConvertHalfToFloatUniformAndSamples : public ir_rvalue_visitor +struct FConvertHalfToFloatUniformAndSamples final : public ir_rvalue_visitor { struct FPair { @@ -2568,6 +2568,10 @@ struct FConvertHalfToFloatUniformAndSamples : public ir_rvalue_visitor { } + virtual ~FConvertHalfToFloatUniformAndSamples() + { + } + void DoConvertOneMap(TReplacedVarMap& Map) { for (auto& TopIter : Map) @@ -2712,7 +2716,7 @@ void FMetalCodeBackend::ConvertHalfToFloatUniformsAndSamples(exec_list* ir, _mes } } -struct FMetalBreakPrecisionChangesVisitor : public ir_rvalue_visitor +struct FMetalBreakPrecisionChangesVisitor final : public ir_rvalue_visitor { _mesa_glsl_parse_state* State; @@ -2720,6 +2724,8 @@ struct FMetalBreakPrecisionChangesVisitor : public ir_rvalue_visitor FMetalBreakPrecisionChangesVisitor(_mesa_glsl_parse_state* InState) : State(InState) {} + virtual ~FMetalBreakPrecisionChangesVisitor() { } + void ConvertBlock(exec_list* instructions) { FMetalBreakPrecisionChangesVisitor Visitor(State); @@ -2822,7 +2828,7 @@ void FMetalCodeBackend::BreakPrecisionChangesVisitor(exec_list* ir, _mesa_glsl_p Visitor.run(ir); } -struct FDeReferencePackedVarsVisitor : public ir_rvalue_visitor +struct FDeReferencePackedVarsVisitor final : public ir_rvalue_visitor { _mesa_glsl_parse_state* State; int ExpressionDepth; @@ -2833,6 +2839,10 @@ struct FDeReferencePackedVarsVisitor : public ir_rvalue_visitor { } + virtual ~FDeReferencePackedVarsVisitor() + { + } + virtual ir_visitor_status visit_enter(ir_expression* ir) override { ++ExpressionDepth; diff --git a/Engine/Source/Developer/AssetTools/Private/AssetFixUpRedirectors.cpp b/Engine/Source/Developer/AssetTools/Private/AssetFixUpRedirectors.cpp index 83bc8663bd97..7bd19440c98a 100644 --- a/Engine/Source/Developer/AssetTools/Private/AssetFixUpRedirectors.cpp +++ b/Engine/Source/Developer/AssetTools/Private/AssetFixUpRedirectors.cpp @@ -462,12 +462,22 @@ void FAssetFixUpRedirectors::FixUpStringAssetReferences(const TArray RedirectorMap; + + for (const FRedirectorRefs& RedirectorRef : RedirectorsToFix) { - FAssetRenameManager::RenameReferencingStringAssetReferences(PackagesToCheck, - RedirectorRef.Redirector->GetPathName(), - RedirectorRef.Redirector->DestinationObject->GetPathName()); + UObjectRedirector* Redirector = RedirectorRef.Redirector; + RedirectorMap.Add(Redirector->GetPathName(), Redirector->DestinationObject->GetPathName()); + + if (UBlueprint* Blueprint = Cast(Redirector->DestinationObject)) + { + // Add redirect for class and default as well + RedirectorMap.Add(FString::Printf(TEXT("%s_C"), *Redirector->GetPathName()), FString::Printf(TEXT("%s_C"), *Redirector->DestinationObject->GetPathName())); + RedirectorMap.Add(FString::Printf(TEXT("Default__%s_C"), *Redirector->GetPathName()), FString::Printf(TEXT("Default__%s_C"), *Redirector->DestinationObject->GetPathName())); + } } + + FAssetRenameManager::RenameReferencingStringAssetReferences(PackagesToCheck, RedirectorMap); } #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Developer/AssetTools/Private/AssetRenameManager.cpp b/Engine/Source/Developer/AssetTools/Private/AssetRenameManager.cpp index 549ba6523fc7..6ed2bc9b3ea8 100644 --- a/Engine/Source/Developer/AssetTools/Private/AssetRenameManager.cpp +++ b/Engine/Source/Developer/AssetTools/Private/AssetRenameManager.cpp @@ -41,6 +41,7 @@ #include "Interfaces/IMainFrameModule.h" #include "Kismet2/KismetEditorUtilities.h" #include "Kismet2/BlueprintEditorUtils.h" +#include "Misc/RedirectCollector.h" #define LOCTEXT_NAMESPACE "AssetRenameManager" @@ -574,63 +575,24 @@ void FAssetRenameManager::DetectReadOnlyPackages(TArray PackagesToCheck, const FString& OldAssetPath, const FString& NewAssetPath) +void FAssetRenameManager::RenameReferencingStringAssetReferences(const TArray PackagesToCheck, const TMap& AssetRedirectorMap) { struct FStringAssetReferenceRenameSerializer : public FArchiveUObject { - FStringAssetReferenceRenameSerializer(const FString& InOldAssetPath, const FString& InNewAssetPath) - : OldAssetPath(InOldAssetPath), NewAssetPath(InNewAssetPath) + FStringAssetReferenceRenameSerializer() { // Mark it as saving to correctly process all references ArIsSaving = true; } - - FArchive& operator<<(FStringAssetReference& Reference) override - { - if (Reference.ToString() == OldAssetPath) - { - Reference.SetPath(NewAssetPath); - } - - // Generated class path support. - if (Reference.ToString() == OldAssetPath + "_C") - { - Reference.SetPath(NewAssetPath + "_C"); - } - - return *this; - } - - FArchive& operator<<(FAssetPtr& AssetPtr) - { - // Fixup AssetPtrs string asset reference, as the pointed to object may have changed - - UObject* Object = static_cast(AssetPtr.Get()); - if (Object) - { - AssetPtr = Object; - } - else - { - *this << AssetPtr.GetUniqueID(); - } - - return *this; - } - - private: - const FString& OldAssetPath; - const FString& NewAssetPath; }; - FStringAssetReferenceRenameSerializer RenameSerializer(OldAssetPath, NewAssetPath); + // Add redirects as needed + for (const TPair& Pair : AssetRedirectorMap) + { + GRedirectCollector.AddAssetPathRedirection(Pair.Key, Pair.Value); + } + + FStringAssetReferenceRenameSerializer RenameSerializer; for (auto* Package : PackagesToCheck) { @@ -746,7 +708,17 @@ void FAssetRenameManager::PerformAssetRename(TArrayGetPathName()); + TMap RedirectorMap; + RedirectorMap.Add(OldAssetPath, Asset->GetPathName()); + + if (UBlueprint* Blueprint = Cast(Asset)) + { + // Add redirect for class and default as well + RedirectorMap.Add(FString::Printf(TEXT("%s_C"), *OldAssetPath), FString::Printf(TEXT("%s_C"), *Asset->GetPathName())); + RedirectorMap.Add(FString::Printf(TEXT("Default__%s_C"), *OldAssetPath), FString::Printf(TEXT("Default__%s_C"), *Asset->GetPathName())); + } + + RenameReferencingStringAssetReferences(PackagesToCheck, RedirectorMap); } GWarn->EndSlowTask(); diff --git a/Engine/Source/Developer/AssetTools/Private/AssetRenameManager.h b/Engine/Source/Developer/AssetTools/Private/AssetRenameManager.h index 703f4f41689c..f04bcefd96ac 100644 --- a/Engine/Source/Developer/AssetTools/Private/AssetRenameManager.h +++ b/Engine/Source/Developer/AssetTools/Private/AssetRenameManager.h @@ -29,10 +29,9 @@ public: * Function that renames all FStringAssetReference object with the old asset path to the new one. * * @param PackagesToCheck Packages to check for referencing FStringAssetReference. - * @param OldAssetPath Old path. - * @param NewAssetPath New path. + * @param AssetRedirectorMap Map from old asset path to new asset path */ - static void RenameReferencingStringAssetReferences(const TArray PackagesToCheck, const FString& OldAssetPath, const FString& NewAssetPath); + static void RenameReferencingStringAssetReferences(const TArray PackagesToCheck, const TMap& AssetRedirectorMap); private: /** Attempts to load and fix redirector references for the supplied assets */ diff --git a/Engine/Source/Developer/AssetTools/Private/AssetTools.cpp b/Engine/Source/Developer/AssetTools/Private/AssetTools.cpp index 6e9574d306bd..5c0c5344f0d9 100644 --- a/Engine/Source/Developer/AssetTools/Private/AssetTools.cpp +++ b/Engine/Source/Developer/AssetTools/Private/AssetTools.cpp @@ -110,10 +110,23 @@ #define LOCTEXT_NAMESPACE "AssetTools" -FAssetTools::FAssetTools() - : AssetRenameManager( MakeShareable(new FAssetRenameManager) ) - , AssetFixUpRedirectors( MakeShareable(new FAssetFixUpRedirectors) ) - , NextUserCategoryBit( EAssetTypeCategories::FirstUser ) + +TScriptInterface UEditorScriptAccessors::GetAssetTools() +{ + return &UAssetToolsImpl::Get(); +} + +/** UInterface constructor */ +UAssetTools::UAssetTools(const class FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ +} + +UAssetToolsImpl::UAssetToolsImpl(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) + , AssetRenameManager(MakeShareable(new FAssetRenameManager)) + , AssetFixUpRedirectors(MakeShareable(new FAssetFixUpRedirectors)) + , NextUserCategoryBit(EAssetTypeCategories::FirstUser) { // Register the built-in advanced categories AllocatedCategoryBits.Add(TEXT("_BuiltIn_0"), FAdvancedAssetCategory(EAssetTypeCategories::Animation, LOCTEXT("AnimationAssetCategory", "Animation"))); @@ -129,94 +142,89 @@ FAssetTools::FAssetTools() EAssetTypeCategories::Type BlendablesCategoryBit = RegisterAdvancedAssetCategory(FName(TEXT("Blendables")), LOCTEXT("BlendablesAssetCategory", "Blendables")); // Register the built-in asset type actions - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_AnimationAsset) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_AnimBlueprint) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_AnimComposite) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_AnimMontage) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_AnimSequence) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_AimOffset) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_AimOffset1D) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_BlendSpace) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_PoseAsset)); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_BlendSpace1D) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_Blueprint) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_CameraAnim) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_CanvasRenderTarget2D) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_Curve) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_CurveFloat) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_CurveTable) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_CurveVector) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_CurveLinearColor) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_DataAsset) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_DataTable) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_DestructibleMesh) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_Enum) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_Class) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_Struct) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_SceneImportData)); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_Font) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_FontFace) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_ForceFeedbackEffect) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_SubsurfaceProfile)); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_InstancedFoliageSettings) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_InterpData) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_LandscapeLayer) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_LandscapeGrassType)); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_Material(BlendablesCategoryBit))); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_MaterialFunction) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_MaterialInstanceConstant(BlendablesCategoryBit)) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_MaterialInterface) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_MaterialParameterCollection) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_ObjectLibrary) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_ParticleSystem) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_PhysicalMaterial) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_PhysicsAsset) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_PreviewMeshCollection) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_ProceduralFoliageSpawner) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_Redirector) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_Rig) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_SkeletalMesh) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_Skeleton) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_SlateBrush) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_SlateWidgetStyle) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_StaticMesh) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_Texture) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_Texture2D) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_TextureCube) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_TextureRenderTarget) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_TextureRenderTarget2D) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_TextureRenderTargetCube) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_TextureLightProfile) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_TouchInterface) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_VectorField) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_VectorFieldAnimated) ); - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_VectorFieldStatic) ); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_AnimationAsset)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_AnimBlueprint)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_AnimComposite)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_AnimMontage)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_AnimSequence)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_AimOffset)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_AimOffset1D)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_BlendSpace)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_PoseAsset)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_BlendSpace1D)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_Blueprint)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_CameraAnim)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_CanvasRenderTarget2D)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_Curve)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_CurveFloat)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_CurveTable)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_CurveVector)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_CurveLinearColor)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_DataAsset)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_DataTable)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_DestructibleMesh)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_Enum)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_Class)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_Struct)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_SceneImportData)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_Font)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_FontFace)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_ForceFeedbackEffect)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_SubsurfaceProfile)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_InstancedFoliageSettings)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_InterpData)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_LandscapeLayer)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_LandscapeGrassType)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_Material(BlendablesCategoryBit))); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_MaterialFunction)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_MaterialInstanceConstant(BlendablesCategoryBit))); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_MaterialInterface)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_MaterialParameterCollection)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_ObjectLibrary)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_ParticleSystem)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_PhysicalMaterial)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_PhysicsAsset)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_PreviewMeshCollection)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_ProceduralFoliageSpawner)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_Redirector)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_Rig)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_SkeletalMesh)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_Skeleton)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_SlateBrush)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_SlateWidgetStyle)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_StaticMesh)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_Texture)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_Texture2D)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_TextureCube)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_TextureRenderTarget)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_TextureRenderTarget2D)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_TextureRenderTargetCube)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_TextureLightProfile)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_TouchInterface)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_VectorField)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_VectorFieldAnimated)); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_VectorFieldStatic)); // Note: Please don't add any more actions here! They belong in an editor-only module that is more tightly // coupled to your new system, and you should not create a dependency on your new system from AssetTools. - if ( UEditorEngine::IsUsingWorldAssets() ) + if (UEditorEngine::IsUsingWorldAssets()) { - RegisterAssetTypeActions( MakeShareable(new FAssetTypeActions_World) ); + RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_World)); } } -FAssetTools::~FAssetTools() -{ - -} - -void FAssetTools::RegisterAssetTypeActions(const TSharedRef& NewActions) +void UAssetToolsImpl::RegisterAssetTypeActions(const TSharedRef& NewActions) { AssetTypeActionsList.Add(NewActions); } -void FAssetTools::UnregisterAssetTypeActions(const TSharedRef& ActionsToRemove) +void UAssetToolsImpl::UnregisterAssetTypeActions(const TSharedRef& ActionsToRemove) { AssetTypeActionsList.Remove(ActionsToRemove); } -void FAssetTools::GetAssetTypeActionsList( TArray>& OutAssetTypeActionsList ) const +void UAssetToolsImpl::GetAssetTypeActionsList( TArray>& OutAssetTypeActionsList ) const { for (auto ActionsIt = AssetTypeActionsList.CreateConstIterator(); ActionsIt; ++ActionsIt) { @@ -224,7 +232,7 @@ void FAssetTools::GetAssetTypeActionsList( TArray>& } } -TWeakPtr FAssetTools::GetAssetTypeActionsForClass( UClass* Class ) const +TWeakPtr UAssetToolsImpl::GetAssetTypeActionsForClass( UClass* Class ) const { TSharedPtr MostDerivedAssetTypeActions; @@ -245,7 +253,7 @@ TWeakPtr FAssetTools::GetAssetTypeActionsForClass( UClass* Cl return MostDerivedAssetTypeActions; } -EAssetTypeCategories::Type FAssetTools::RegisterAdvancedAssetCategory(FName CategoryKey, FText CategoryDisplayName) +EAssetTypeCategories::Type UAssetToolsImpl::RegisterAdvancedAssetCategory(FName CategoryKey, FText CategoryDisplayName) { EAssetTypeCategories::Type Result = FindAdvancedAssetCategory(CategoryKey); if (Result == EAssetTypeCategories::Misc) @@ -275,7 +283,7 @@ EAssetTypeCategories::Type FAssetTools::RegisterAdvancedAssetCategory(FName Cate return Result; } -EAssetTypeCategories::Type FAssetTools::FindAdvancedAssetCategory(FName CategoryKey) const +EAssetTypeCategories::Type UAssetToolsImpl::FindAdvancedAssetCategory(FName CategoryKey) const { if (const FAdvancedAssetCategory* ExistingCategory = AllocatedCategoryBits.Find(CategoryKey)) { @@ -287,22 +295,22 @@ EAssetTypeCategories::Type FAssetTools::FindAdvancedAssetCategory(FName Category } } -void FAssetTools::GetAllAdvancedAssetCategories(TArray& OutCategoryList) const +void UAssetToolsImpl::GetAllAdvancedAssetCategories(TArray& OutCategoryList) const { AllocatedCategoryBits.GenerateValueArray(OutCategoryList); } -void FAssetTools::RegisterClassTypeActions(const TSharedRef& NewActions) +void UAssetToolsImpl::RegisterClassTypeActions(const TSharedRef& NewActions) { ClassTypeActionsList.Add(NewActions); } -void FAssetTools::UnregisterClassTypeActions(const TSharedRef& ActionsToRemove) +void UAssetToolsImpl::UnregisterClassTypeActions(const TSharedRef& ActionsToRemove) { ClassTypeActionsList.Remove(ActionsToRemove); } -void FAssetTools::GetClassTypeActionsList( TArray>& OutClassTypeActionsList ) const +void UAssetToolsImpl::GetClassTypeActionsList( TArray>& OutClassTypeActionsList ) const { for (auto ActionsIt = ClassTypeActionsList.CreateConstIterator(); ActionsIt; ++ActionsIt) { @@ -310,7 +318,7 @@ void FAssetTools::GetClassTypeActionsList( TArray>& } } -TWeakPtr FAssetTools::GetClassTypeActionsForClass( UClass* Class ) const +TWeakPtr UAssetToolsImpl::GetClassTypeActionsForClass( UClass* Class ) const { TSharedPtr MostDerivedClassTypeActions; @@ -331,7 +339,7 @@ TWeakPtr FAssetTools::GetClassTypeActionsForClass( UClass* Cl return MostDerivedClassTypeActions; } -bool FAssetTools::GetAssetActions( const TArray& InObjects, FMenuBuilder& MenuBuilder, bool bIncludeHeading ) +bool UAssetToolsImpl::GetAssetActions( const TArray& InObjects, FMenuBuilder& MenuBuilder, bool bIncludeHeading ) { bool bAddedActions = false; @@ -395,7 +403,7 @@ struct FRootedOnScope } }; -UObject* FAssetTools::CreateAsset(const FString& AssetName, const FString& PackagePath, UClass* AssetClass, UFactory* Factory, FName CallingContext) +UObject* UAssetToolsImpl::CreateAsset(const FString& AssetName, const FString& PackagePath, UClass* AssetClass, UFactory* Factory, FName CallingContext) { FRootedOnScope DontGCFactory(Factory); @@ -412,7 +420,7 @@ UObject* FAssetTools::CreateAsset(const FString& AssetName, const FString& Packa return nullptr; } - const FString PackageName = PackagePath + TEXT("/") + AssetName; + const FString PackageName = PackageTools::SanitizePackageName(PackagePath + TEXT("/") + AssetName); // Make sure we can create the asset without conflicts if ( !CanCreateAsset(AssetName, PackageName, LOCTEXT("CreateANewObject", "Create a new object")) ) @@ -440,7 +448,7 @@ UObject* FAssetTools::CreateAsset(const FString& AssetName, const FString& Packa FAssetRegistryModule::AssetCreated(NewObj); // analytics create record - FAssetTools::OnNewCreateRecord(AssetClass, false); + UAssetToolsImpl::OnNewCreateRecord(AssetClass, false); // Mark the package dirty... Pkg->MarkPackageDirty(); @@ -449,7 +457,12 @@ UObject* FAssetTools::CreateAsset(const FString& AssetName, const FString& Packa return NewObj; } -UObject* FAssetTools::CreateAsset(UClass* AssetClass, UFactory* Factory, FName CallingContext) +UObject* UAssetToolsImpl::CreateAsset(UClass* AssetClass, UFactory* Factory, FName CallingContext /*= NAME_None*/) +{ + return CreateAssetWithDialog(AssetClass, Factory, CallingContext); +} + +UObject* UAssetToolsImpl::CreateAssetWithDialog(UClass* AssetClass, UFactory* Factory, FName CallingContext) { if (Factory != nullptr) { @@ -474,7 +487,7 @@ UObject* FAssetTools::CreateAsset(UClass* AssetClass, UFactory* Factory, FName C } -UObject* FAssetTools::CreateAssetWithDialog(const FString& AssetName, const FString& PackagePath, UClass* AssetClass, UFactory* Factory, FName CallingContext) +UObject* UAssetToolsImpl::CreateAssetWithDialog(const FString& AssetName, const FString& PackagePath, UClass* AssetClass, UFactory* Factory, FName CallingContext) { FSaveAssetDialogConfig SaveAssetDialogConfig; SaveAssetDialogConfig.DialogTitleOverride = LOCTEXT("SaveAssetDialogTitle", "Save Asset As"); @@ -501,7 +514,7 @@ UObject* FAssetTools::CreateAssetWithDialog(const FString& AssetName, const FStr return nullptr; } -UObject* FAssetTools::DuplicateAssetWithDialog(const FString& AssetName, const FString& PackagePath, UObject* OriginalObject) +UObject* UAssetToolsImpl::DuplicateAssetWithDialog(const FString& AssetName, const FString& PackagePath, UObject* OriginalObject) { FSaveAssetDialogConfig SaveAssetDialogConfig; SaveAssetDialogConfig.DialogTitleOverride = LOCTEXT("DuplicateAssetDialogTitle", "Duplicate Asset As"); @@ -524,7 +537,7 @@ UObject* FAssetTools::DuplicateAssetWithDialog(const FString& AssetName, const F return nullptr; } -UObject* FAssetTools::DuplicateAsset(const FString& AssetName, const FString& PackagePath, UObject* OriginalObject) +UObject* UAssetToolsImpl::DuplicateAsset(const FString& AssetName, const FString& PackagePath, UObject* OriginalObject) { // Verify the source object if ( !OriginalObject ) @@ -565,18 +578,23 @@ UObject* FAssetTools::DuplicateAsset(const FString& AssetName, const FString& Pa } // analytics create record - FAssetTools::OnNewCreateRecord(NewObject->GetClass(), true); + UAssetToolsImpl::OnNewCreateRecord(NewObject->GetClass(), true); } return NewObject; } -void FAssetTools::RenameAssets(const TArray& AssetsAndNames) const +void UAssetToolsImpl::RenameAssets(const TArray& AssetsAndNames) const { AssetRenameManager->RenameAssets(AssetsAndNames); } -TArray FAssetTools::ImportAssets(const FString& DestinationPath) +TArray UAssetToolsImpl::ImportAssets(const FString& DestinationPath) +{ + return ImportAssetsWithDialog(DestinationPath); +} + +TArray UAssetToolsImpl::ImportAssetsWithDialog(const FString& DestinationPath) { TArray ReturnObjects; FString FileTypes, AllExtensions; @@ -645,20 +663,22 @@ TArray FAssetTools::ImportAssets(const FString& DestinationPath) return ReturnObjects; } -TArray FAssetTools::ImportAssetsAutomated(const UAutomatedAssetImportData& ImportData) const +TArray UAssetToolsImpl::ImportAssetsAutomated(const UAutomatedAssetImportData* ImportData) const { + check(ImportData); + FAssetImportParams Params; Params.bAutomated = true; - Params.bForceOverrideExisting = ImportData.bReplaceExisting; + Params.bForceOverrideExisting = ImportData->bReplaceExisting; Params.bSyncToBrowser = false; - Params.SpecifiedFactory = ImportData.Factory; - Params.ImportData = &ImportData; + Params.SpecifiedFactory = ImportData->Factory; + Params.ImportData = ImportData; - return ImportAssetsInternal(ImportData.Filenames, ImportData.DestinationPath, nullptr, Params); + return ImportAssetsInternal(ImportData->Filenames, ImportData->DestinationPath, nullptr, Params); } -void FAssetTools::ExpandDirectories(const TArray& Files, const FString& DestinationPath, TArray>& FilesAndDestinations) const +void UAssetToolsImpl::ExpandDirectories(const TArray& Files, const FString& DestinationPath, TArray>& FilesAndDestinations) const { // Iterate through all files in the list, if any folders are found, recurse and expand them. for ( int32 FileIdx = 0; FileIdx < Files.Num(); ++FileIdx ) @@ -693,8 +713,7 @@ void FAssetTools::ExpandDirectories(const TArray& Files, const FString& } } } - -TArray FAssetTools::ImportAssets(const TArray& Files, const FString& RootDestinationPath, UFactory* SpecifiedFactory, bool bSyncToBrowser, TArray> *FilesAndDestinations) const +TArray UAssetToolsImpl::ImportAssets(const TArray& Files, const FString& DestinationPath, UFactory* ChosenFactory, bool bSyncToBrowser /* = true */, TArray>* FilesAndDestinations /* = nullptr */) const { const bool bForceOverrideExisting = false; @@ -703,12 +722,12 @@ TArray FAssetTools::ImportAssets(const TArray& Files, const F Params.bAutomated = false; Params.bForceOverrideExisting = false; Params.bSyncToBrowser = bSyncToBrowser; - Params.SpecifiedFactory = SpecifiedFactory; + Params.SpecifiedFactory = ChosenFactory; - return ImportAssetsInternal(Files, RootDestinationPath, FilesAndDestinations, Params); + return ImportAssetsInternal(Files, DestinationPath, FilesAndDestinations, Params); } -void FAssetTools::CreateUniqueAssetName(const FString& InBasePackageName, const FString& InSuffix, FString& OutPackageName, FString& OutAssetName) const +void UAssetToolsImpl::CreateUniqueAssetName(const FString& InBasePackageName, const FString& InSuffix, FString& OutPackageName, FString& OutAssetName) const { const FString SanitizedBasePackageName = PackageTools::SanitizePackageName(InBasePackageName); @@ -779,7 +798,7 @@ void FAssetTools::CreateUniqueAssetName(const FString& InBasePackageName, const while (bObjectExists != false); } -bool FAssetTools::AssetUsesGenericThumbnail( const FAssetData& AssetData ) const +bool UAssetToolsImpl::AssetUsesGenericThumbnail( const FAssetData& AssetData ) const { if ( !AssetData.IsValid() ) { @@ -844,7 +863,7 @@ bool FAssetTools::AssetUsesGenericThumbnail( const FAssetData& AssetData ) const return false; } -void FAssetTools::DiffAgainstDepot( UObject* InObject, const FString& InPackagePath, const FString& InPackageName ) const +void UAssetToolsImpl::DiffAgainstDepot( UObject* InObject, const FString& InPackagePath, const FString& InPackageName ) const { check( InObject ); @@ -874,11 +893,8 @@ void FAssetTools::DiffAgainstDepot( UObject* InObject, const FString& InPackageP FString TempFileName; if(Revision->Get(TempFileName)) { - // Forcibly disable compile on load in case we are loading old blueprints that might try to update/compile - TGuardValue DisableCompileOnLoad(GForceDisableBlueprintCompileOnLoad, true); - // Try and load that package - UPackage* TempPackage = LoadPackage(nullptr, *TempFileName, LOAD_ForDiff); + UPackage* TempPackage = LoadPackage(nullptr, *TempFileName, LOAD_ForDiff|LOAD_DisableCompileOnLoad); if(TempPackage != nullptr) { // Grab the old asset from that old package @@ -902,7 +918,7 @@ void FAssetTools::DiffAgainstDepot( UObject* InObject, const FString& InPackageP } } -void FAssetTools::DiffAssets(UObject* OldAsset, UObject* NewAsset, const struct FRevisionInfo& OldRevision, const struct FRevisionInfo& NewRevision) const +void UAssetToolsImpl::DiffAssets(UObject* OldAsset, UObject* NewAsset, const struct FRevisionInfo& OldRevision, const struct FRevisionInfo& NewRevision) const { if(OldAsset == nullptr || NewAsset == nullptr) { @@ -930,7 +946,7 @@ void FAssetTools::DiffAssets(UObject* OldAsset, UObject* NewAsset, const struct } } -FString FAssetTools::DumpAssetToTempFile(UObject* Asset) const +FString UAssetToolsImpl::DumpAssetToTempFile(UObject* Asset) const { check(Asset); @@ -970,7 +986,7 @@ FString WrapArgument(const FString& Argument) (Argument.EndsWith("\"")) ? TEXT(""): TEXT("\"")); } -bool FAssetTools::CreateDiffProcess(const FString& DiffCommand, const FString& OldTextFilename, const FString& NewTextFilename, const FString& DiffArgs) const +bool UAssetToolsImpl::CreateDiffProcess(const FString& DiffCommand, const FString& OldTextFilename, const FString& NewTextFilename, const FString& DiffArgs) const { // Construct Arguments FString Arguments = FString::Printf( TEXT("%s %s %s"),*WrapArgument(OldTextFilename), *WrapArgument(NewTextFilename), *DiffArgs ); @@ -1029,7 +1045,7 @@ bool FAssetTools::CreateDiffProcess(const FString& DiffCommand, const FString& return false; } -void FAssetTools::MigratePackages(const TArray& PackageNamesToMigrate) const +void UAssetToolsImpl::MigratePackages(const TArray& PackageNamesToMigrate) const { // Packages must be saved for the migration to work const bool bPromptUserToSave = true; @@ -1042,7 +1058,7 @@ void FAssetTools::MigratePackages(const TArray& PackageNamesToMigrate) co { // Open a dialog asking the user to wait while assets are being discovered SDiscoveringAssetsDialog::OpenDiscoveringAssetsDialog( - SDiscoveringAssetsDialog::FOnAssetsDiscovered::CreateRaw(this, &FAssetTools::PerformMigratePackages, PackageNamesToMigrate) + SDiscoveringAssetsDialog::FOnAssetsDiscovered::CreateUObject(this, &UAssetToolsImpl::PerformMigratePackages, PackageNamesToMigrate) ); } else @@ -1053,7 +1069,7 @@ void FAssetTools::MigratePackages(const TArray& PackageNamesToMigrate) co } } -void FAssetTools::OnNewImportRecord(UClass* AssetType, const FString& FileExtension, bool bSucceeded, bool bWasCancelled, const FDateTime& StartTime) +void UAssetToolsImpl::OnNewImportRecord(UClass* AssetType, const FString& FileExtension, bool bSucceeded, bool bWasCancelled, const FDateTime& StartTime) { // Don't attempt to report usage stats if analytics isn't available if(AssetType != nullptr && FEngineAnalytics::IsAvailable()) @@ -1069,7 +1085,7 @@ void FAssetTools::OnNewImportRecord(UClass* AssetType, const FString& FileExtens } } -void FAssetTools::OnNewCreateRecord(UClass* AssetType, bool bDuplicated) +void UAssetToolsImpl::OnNewCreateRecord(UClass* AssetType, bool bDuplicated) { // Don't attempt to report usage stats if analytics isn't available if(AssetType != nullptr && FEngineAnalytics::IsAvailable()) @@ -1082,7 +1098,7 @@ void FAssetTools::OnNewCreateRecord(UClass* AssetType, bool bDuplicated) } } -TArray FAssetTools::ImportAssetsInternal(const TArray& Files, const FString& RootDestinationPath, TArray> *FilesAndDestinationsPtr, const FAssetImportParams& Params) const +TArray UAssetToolsImpl::ImportAssetsInternal(const TArray& Files, const FString& RootDestinationPath, TArray> *FilesAndDestinationsPtr, const FAssetImportParams& Params) const { UFactory* SpecifiedFactory = Params.SpecifiedFactory; const bool bForceOverrideExisting = Params.bForceOverrideExisting; @@ -1511,31 +1527,31 @@ TArray FAssetTools::ImportAssetsInternal(const TArray& Files, // Sync content browser to the newly created assets if(ReturnObjects.Num() && (bSyncToBrowser != false)) { - FAssetTools::Get().SyncBrowserToAssets(ReturnObjects); + UAssetToolsImpl::Get().SyncBrowserToAssets(ReturnObjects); } return ReturnObjects; } -FAssetTools& FAssetTools::Get() +UAssetToolsImpl& UAssetToolsImpl::Get() { FAssetToolsModule& Module = FModuleManager::GetModuleChecked("AssetTools"); - return static_cast(Module.Get()); + return static_cast(Module.Get()); } -void FAssetTools::SyncBrowserToAssets(const TArray& AssetsToSync) +void UAssetToolsImpl::SyncBrowserToAssets(const TArray& AssetsToSync) { FContentBrowserModule& ContentBrowserModule = FModuleManager::Get().LoadModuleChecked("ContentBrowser"); ContentBrowserModule.Get().SyncBrowserToAssets( AssetsToSync, /*bAllowLockedBrowsers=*/true ); } -void FAssetTools::SyncBrowserToAssets(const TArray& AssetsToSync) +void UAssetToolsImpl::SyncBrowserToAssets(const TArray& AssetsToSync) { FContentBrowserModule& ContentBrowserModule = FModuleManager::Get().LoadModuleChecked("ContentBrowser"); ContentBrowserModule.Get().SyncBrowserToAssets( AssetsToSync, /*bAllowLockedBrowsers=*/true ); } -bool FAssetTools::CheckForDeletedPackage(const UPackage* Package) const +bool UAssetToolsImpl::CheckForDeletedPackage(const UPackage* Package) const { if ( ISourceControlModule::Get().IsEnabled() ) { @@ -1572,7 +1588,7 @@ bool FAssetTools::CheckForDeletedPackage(const UPackage* Package) const return true; } -bool FAssetTools::CanCreateAsset(const FString& AssetName, const FString& PackageName, const FText& OperationText) const +bool UAssetToolsImpl::CanCreateAsset(const FString& AssetName, const FString& PackageName, const FText& OperationText) const { // @todo: These 'reason' messages are not localized strings! FText Reason; @@ -1665,7 +1681,7 @@ bool FAssetTools::CanCreateAsset(const FString& AssetName, const FString& Packag return true; } -void FAssetTools::PerformMigratePackages(TArray PackageNamesToMigrate) const +void UAssetToolsImpl::PerformMigratePackages(TArray PackageNamesToMigrate) const { // Form a full list of packages to move by including the dependencies of the supplied packages TSet AllPackageNamesToMove; @@ -1700,12 +1716,12 @@ void FAssetTools::PerformMigratePackages(TArray PackageNamesToMigrate) co { ReportPackageNames.Add((*PackageIt).ToString()); } - SPackageReportDialog::FOnReportConfirmed OnReportConfirmed = SPackageReportDialog::FOnReportConfirmed::CreateRaw(this, &FAssetTools::MigratePackages_ReportConfirmed, ReportPackageNames); + SPackageReportDialog::FOnReportConfirmed OnReportConfirmed = SPackageReportDialog::FOnReportConfirmed::CreateUObject(this, &UAssetToolsImpl::MigratePackages_ReportConfirmed, ReportPackageNames); SPackageReportDialog::OpenPackageReportDialog(ReportMessage, ReportPackageNames, OnReportConfirmed); } } -void FAssetTools::MigratePackages_ReportConfirmed(TArray ConfirmedPackageNamesToMigrate) const +void UAssetToolsImpl::MigratePackages_ReportConfirmed(TArray ConfirmedPackageNamesToMigrate) const { // Choose a destination folder IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get(); @@ -1920,7 +1936,7 @@ void FAssetTools::MigratePackages_ReportConfirmed(TArray ConfirmedPacka MigrateLog.Notify(LogMessage, Severity, true); } -void FAssetTools::RecursiveGetDependencies(const FName& PackageName, TSet& AllDependencies) const +void UAssetToolsImpl::RecursiveGetDependencies(const FName& PackageName, TSet& AllDependencies) const { FAssetRegistryModule& AssetRegistryModule = FModuleManager::Get().LoadModuleChecked(TEXT("AssetRegistry")); TArray Dependencies; @@ -1942,7 +1958,7 @@ void FAssetTools::RecursiveGetDependencies(const FName& PackageName, TSet } } -void FAssetTools::FixupReferencers(const TArray& Objects) const +void UAssetToolsImpl::FixupReferencers(const TArray& Objects) const { AssetFixUpRedirectors->FixupReferencers(Objects); } diff --git a/Engine/Source/Developer/AssetTools/Private/AssetTools.h b/Engine/Source/Developer/AssetTools/Private/AssetTools.h index c30b327497d5..1879048900af 100644 --- a/Engine/Source/Developer/AssetTools/Private/AssetTools.h +++ b/Engine/Source/Developer/AssetTools/Private/AssetTools.h @@ -7,6 +7,7 @@ #include "IAssetTypeActions.h" #include "AssetData.h" #include "AssetRenameManager.h" +#include "AssetTools.generated.h" class FAssetFixUpRedirectors; class FMenuBuilder; @@ -37,11 +38,18 @@ struct FAssetImportParams bool bAutomated : 1; }; -class FAssetTools : public IAssetTools + +/** For backwards compatibility */ +typedef class UAssetToolsImpl FAssetTools; + +PRAGMA_DISABLE_DEPRECATION_WARNINGS + +UCLASS(transient) +class UAssetToolsImpl : public UObject, public IAssetTools { + GENERATED_BODY() public: - FAssetTools(); - virtual ~FAssetTools(); + UAssetToolsImpl(const FObjectInitializer& ObjectInitializer); // IAssetTools implementation virtual void RegisterAssetTypeActions(const TSharedRef& NewActions) override; @@ -58,13 +66,15 @@ public: virtual bool GetAssetActions( const TArray& InObjects, FMenuBuilder& MenuBuilder, bool bIncludeHeading = true ) override; virtual UObject* CreateAsset(const FString& AssetName, const FString& PackagePath, UClass* AssetClass, UFactory* Factory, FName CallingContext = NAME_None) override; virtual UObject* CreateAsset(UClass* AssetClass, UFactory* Factory, FName CallingContext = NAME_None) override; + virtual UObject* CreateAssetWithDialog(UClass* AssetClass, UFactory* Factory, FName CallingContext = NAME_None) override; virtual UObject* CreateAssetWithDialog(const FString& AssetName, const FString& PackagePath, UClass* AssetClass, UFactory* Factory, FName CallingContext = NAME_None) override; virtual UObject* DuplicateAsset(const FString& AssetName, const FString& PackagePath, UObject* OriginalObject) override; virtual UObject* DuplicateAssetWithDialog(const FString& AssetName, const FString& PackagePath, UObject* OriginalObject) override; virtual void RenameAssets(const TArray& AssetsAndNames) const override; virtual TArray ImportAssets(const FString& DestinationPath) override; - virtual TArray ImportAssets(const TArray& Files, const FString& DestinationPath, UFactory* ChosenFactory, bool bSyncToBrowser = true, TArray> *FilesAndDestinations = nullptr) const override; - virtual TArray ImportAssetsAutomated(const UAutomatedAssetImportData& ImportData) const override; + virtual TArray ImportAssetsWithDialog(const FString& DestinationPath) override; + virtual TArray ImportAssets(const TArray& Files, const FString& DestinationPath, UFactory* ChosenFactory, bool bSyncToBrowser = true, TArray>* FilesAndDestinations = nullptr) const override; + virtual TArray ImportAssetsAutomated(const UAutomatedAssetImportData* ImportData) const override; virtual void CreateUniqueAssetName(const FString& InBasePackageName, const FString& InSuffix, FString& OutPackageName, FString& OutAssetName) const override; virtual bool AssetUsesGenericThumbnail( const FAssetData& AssetData ) const override; virtual void DiffAgainstDepot(UObject* InObject, const FString& InPackagePath, const FString& InPackageName) const override; @@ -75,10 +85,9 @@ public: virtual void FixupReferencers(const TArray& Objects) const override; virtual FAssetPostRenameEvent& OnAssetPostRename() override { return AssetRenameManager->OnAssetPostRenameEvent(); } virtual void ExpandDirectories(const TArray& Files, const FString& DestinationPath, TArray>& FilesAndDestinations) const override; - public: /** Gets the asset tools singleton as a FAssetTools for asset tools module use */ - static FAssetTools& Get(); + static UAssetToolsImpl& Get(); /** Syncs the primary content browser to the specified assets, whether or not it is locked. Most syncs that come from AssetTools -feel- like they came from the content browser, so this is okay. */ void SyncBrowserToAssets(const TArray& AssetsToSync); @@ -110,10 +119,10 @@ private: private: /** The manager to handle renaming assets */ - TSharedRef AssetRenameManager; + TSharedPtr AssetRenameManager; /** The manager to handle fixing up redirectors */ - TSharedRef AssetFixUpRedirectors; + TSharedPtr AssetFixUpRedirectors; /** The list of all registered AssetTypeActions */ TArray> AssetTypeActionsList; @@ -127,3 +136,5 @@ private: /** The next user category bit to allocate (set to 0 when there are no more bits left) */ uint32 NextUserCategoryBit; }; + +PRAGMA_ENABLE_DEPRECATION_WARNINGS diff --git a/Engine/Source/Developer/AssetTools/Private/AssetToolsModule.cpp b/Engine/Source/Developer/AssetTools/Private/AssetToolsModule.cpp index 95668a2ede49..3c9d5eb5d823 100644 --- a/Engine/Source/Developer/AssetTools/Private/AssetToolsModule.cpp +++ b/Engine/Source/Developer/AssetTools/Private/AssetToolsModule.cpp @@ -12,9 +12,10 @@ DEFINE_LOG_CATEGORY(LogAssetTools); void FAssetToolsModule::StartupModule() { - AssetTools = new FAssetTools(); ConsoleCommands = new FAssetToolsConsoleCommands(*this); + AssetToolsPtr = GetMutableDefault(); + // create a message log for the asset tools to use FMessageLogModule& MessageLogModule = FModuleManager::LoadModuleChecked("MessageLog"); FMessageLogInitializationOptions InitOptions; @@ -24,12 +25,6 @@ void FAssetToolsModule::StartupModule() void FAssetToolsModule::ShutdownModule() { - if (AssetTools != NULL) - { - delete AssetTools; - AssetTools = NULL; - } - if (ConsoleCommands != NULL) { delete ConsoleCommands; @@ -46,6 +41,5 @@ void FAssetToolsModule::ShutdownModule() IAssetTools& FAssetToolsModule::Get() const { - check(AssetTools); - return *AssetTools; + return *AssetToolsPtr; } diff --git a/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_AnimationAsset.cpp b/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_AnimationAsset.cpp index 31fd2a930538..9dee93cf354e 100644 --- a/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_AnimationAsset.cpp +++ b/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_AnimationAsset.cpp @@ -238,7 +238,7 @@ void FAssetTypeActions_AnimationAsset::ExecuteFindSkeleton(TArray> InAnimAssets) { - if((!OldSkeleton || OldSkeleton->GetPreviewMesh(false))) + if(!OldSkeleton || OldSkeleton->GetPreviewMesh(false)) { EditorAnimUtils::RetargetAnimations(OldSkeleton, NewSkeleton, InAnimAssets, bRemapReferencedAssets, NameRule, bConvertSpaces); } diff --git a/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_Blueprint.cpp b/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_Blueprint.cpp index 753aefda882c..9e596a905866 100644 --- a/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_Blueprint.cpp +++ b/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_Blueprint.cpp @@ -81,7 +81,7 @@ void FAssetTypeActions_Blueprint::OpenAssetEditor( const TArray& InObj bool bLetOpen = true; if (!Blueprint->SkeletonGeneratedClass || !Blueprint->GeneratedClass) { - bLetOpen = EAppReturnType::Yes == FMessageDialog::Open(EAppMsgType::YesNoCancel, LOCTEXT("FailedToLoadBlueprintWithContinue", "Blueprint could not be loaded because it derives from an invalid class. Check to make sure the parent class for this blueprint hasn't been removed! Do you want to continue (it can crash the editor)?")); + bLetOpen = EAppReturnType::Yes == FMessageDialog::Open(EAppMsgType::YesNo, LOCTEXT("FailedToLoadBlueprintWithContinue", "Blueprint could not be loaded because it derives from an invalid class. Check to make sure the parent class for this blueprint hasn't been removed! Do you want to continue (it can crash the editor)?")); } if (bLetOpen) { diff --git a/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_Curve.cpp b/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_Curve.cpp index 13135f517dcf..3bc17ebb26cd 100644 --- a/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_Curve.cpp +++ b/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_Curve.cpp @@ -12,7 +12,7 @@ void FAssetTypeActions_Curve::OpenAssetEditor( const TArray& InObjects for (auto ObjIt = InObjects.CreateConstIterator(); ObjIt; ++ObjIt) { auto Curve = Cast(*ObjIt); - if (Curve != NULL) + if (Curve != nullptr) { FCurveAssetEditorModule& CurveAssetEditorModule = FModuleManager::LoadModuleChecked( "CurveAssetEditor" ); TSharedRef< ICurveAssetEditor > NewCurveAssetEditor = CurveAssetEditorModule.CreateCurveAssetEditor( Mode, EditWithinLevelEditor, Curve ); @@ -25,6 +25,9 @@ void FAssetTypeActions_Curve::GetResolvedSourceFilePaths(const TArray& for (auto& Asset : TypeAssets) { const auto Curve = CastChecked(Asset); - Curve->AssetImportData->ExtractFilenames(OutSourceFilePaths); + if (Curve->AssetImportData) + { + Curve->AssetImportData->ExtractFilenames(OutSourceFilePaths); + } } } diff --git a/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_ForceFeedbackEffect.cpp b/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_ForceFeedbackEffect.cpp index 359055af65fd..85987c7dc432 100644 --- a/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_ForceFeedbackEffect.cpp +++ b/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_ForceFeedbackEffect.cpp @@ -198,7 +198,8 @@ TSharedPtr FAssetTypeActions_ForceFeedbackEffect::GetThumbnailOverlay(c .ButtonStyle(FEditorStyle::Get(), "HoverHintOnly") .ToolTipText_Lambda(OnToolTipTextLambda) .Cursor(EMouseCursor::Default) // The outer widget can specify a DragHand cursor, so we need to override that here - .ForegroundColor(FSlateColor::UseForeground()) + .ForegroundColor(FSlateColor::UseForeground()) + .IsFocusable(false) .IsEnabled_Lambda(IsEnabledLambda) .OnClicked_Lambda(OnClickedLambda) .Visibility_Lambda(OnGetVisibilityLambda) diff --git a/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_World.cpp b/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_World.cpp index 9a6cd68c398f..357690d975b8 100644 --- a/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_World.cpp +++ b/Engine/Source/Developer/AssetTools/Private/AssetTypeActions/AssetTypeActions_World.cpp @@ -25,7 +25,7 @@ void FAssetTypeActions_World::OpenAssetEditor( const TArray& InObjects const bool bShowProgress = true; FEditorFileUtils::LoadMap(FileToOpen, bLoadAsTemplate, bShowProgress); } - + // We can only edit one world at a time... so just break after the first valid world to load break; } diff --git a/Engine/Source/Developer/AssetTools/Public/AssetToolsModule.h b/Engine/Source/Developer/AssetTools/Public/AssetToolsModule.h index 84becf6e0378..afae4e7733c8 100644 --- a/Engine/Source/Developer/AssetTools/Public/AssetToolsModule.h +++ b/Engine/Source/Developer/AssetTools/Public/AssetToolsModule.h @@ -5,8 +5,8 @@ #include "CoreMinimal.h" #include "Modules/ModuleInterface.h" #include "Modules/ModuleManager.h" +#include "IAssetTools.h" -class IAssetTools; class FAssetToolsModule : public IModuleInterface { @@ -29,6 +29,6 @@ public: } private: - IAssetTools* AssetTools; + TWeakObjectPtr AssetToolsPtr; class FAssetToolsConsoleCommands* ConsoleCommands; }; diff --git a/Engine/Source/Developer/AssetTools/Public/IAssetTools.h b/Engine/Source/Developer/AssetTools/Public/IAssetTools.h index d6d69731bca3..3ee55aa46f4f 100644 --- a/Engine/Source/Developer/AssetTools/Public/IAssetTools.h +++ b/Engine/Source/Developer/AssetTools/Public/IAssetTools.h @@ -5,26 +5,46 @@ #include "CoreMinimal.h" #include "UObject/WeakObjectPtr.h" #include "UObject/Package.h" +#include "UObject/ObjectMacros.h" +#include "UObject/Class.h" +#include "UObject/Interface.h" #include "AssetTypeCategories.h" +#include "IAssetTypeActions.h" +#include "AutomatedAssetImportData.h" +#include "IAssetTools.generated.h" + class FAssetData; class IAssetTypeActions; class IClassTypeActions; class UFactory; +USTRUCT(BlueprintType) struct FAssetRenameData { + GENERATED_BODY() + + UPROPERTY(BlueprintReadWrite, Category=AssetRenameData) TWeakObjectPtr Asset; + + UPROPERTY(BlueprintReadWrite, Category = AssetRenameData) FString PackagePath; + + UPROPERTY(BlueprintReadWrite, Category = AssetRenameData) FString NewName; + + UPROPERTY(BlueprintReadWrite, Category = AssetRenameData) FString OriginalAssetPath; + FAssetRenameData() + {} + FAssetRenameData(const TWeakObjectPtr& InAsset, const FString& InPackagePath, const FString& InNewName) : Asset(InAsset) , PackagePath(InPackagePath) , NewName(InNewName) { - if(InAsset.IsValid()) + if (InAsset.IsValid()) { OriginalAssetPath = InAsset.Get()->GetOutermost()->GetName(); } @@ -48,11 +68,18 @@ struct FAdvancedAssetCategory }; +UINTERFACE(MinimalApi, BlueprintType, meta = (CannotImplementInterfaceInBlueprint)) +class UAssetTools : public UInterface +{ + GENERATED_UINTERFACE_BODY() +}; + class IAssetTools { + GENERATED_IINTERFACE_BODY() + public: - /** Virtual destructor */ - virtual ~IAssetTools() {} + /** Registers an asset type actions object so it can provide information about and actions for asset types. */ virtual void RegisterAssetTypeActions(const TSharedRef& NewActions) = 0; @@ -61,20 +88,20 @@ public: virtual void UnregisterAssetTypeActions(const TSharedRef& ActionsToRemove) = 0; /** Generates a list of currently registered AssetTypeActions */ - virtual void GetAssetTypeActionsList( TArray>& OutAssetTypeActionsList ) const = 0; + virtual void GetAssetTypeActionsList(TArray>& OutAssetTypeActionsList) const = 0; /** Gets the appropriate AssetTypeActions for the supplied class */ - virtual TWeakPtr GetAssetTypeActionsForClass( UClass* Class ) const = 0; + virtual TWeakPtr GetAssetTypeActionsForClass(UClass* Class) const = 0; /** - * Allocates a Category bit for a user-defined Category, or EAssetTypeCategories::Misc if all available bits are allocated. - * Ignores duplicate calls with the same CategoryKey (returns the existing bit but does not change the display name). - */ + * Allocates a Category bit for a user-defined Category, or EAssetTypeCategories::Misc if all available bits are allocated. + * Ignores duplicate calls with the same CategoryKey (returns the existing bit but does not change the display name). + */ virtual EAssetTypeCategories::Type RegisterAdvancedAssetCategory(FName CategoryKey, FText CategoryDisplayName) = 0; /** Returns the allocated Category bit for a user-specified Category, or EAssetTypeCategories::Misc if it doesn't exist */ virtual EAssetTypeCategories::Type FindAdvancedAssetCategory(FName CategoryKey) const = 0; - + /** Returns the list of all advanced asset categories */ virtual void GetAllAdvancedAssetCategories(TArray& OutCategoryList) const = 0; @@ -85,10 +112,10 @@ public: virtual void UnregisterClassTypeActions(const TSharedRef& ActionsToRemove) = 0; /** Generates a list of currently registered ClassTypeActions */ - virtual void GetClassTypeActionsList( TArray>& OutClassTypeActionsList ) const = 0; + virtual void GetClassTypeActionsList(TArray>& OutClassTypeActionsList) const = 0; /** Gets the appropriate ClassTypeActions for the supplied class */ - virtual TWeakPtr GetClassTypeActionsForClass( UClass* Class ) const = 0; + virtual TWeakPtr GetClassTypeActionsForClass(UClass* Class) const = 0; /** * Fills out a menubuilder with a list of commands that can be applied to the specified objects. @@ -98,7 +125,7 @@ public: * @param bIncludeHeader if true, will include a heading in the menu if any options were found * @return true if any options were added to the MenuBuilder */ - virtual bool GetAssetActions( const TArray& InObjects, class FMenuBuilder& MenuBuilder, bool bIncludeHeading = true ) = 0; + virtual bool GetAssetActions(const TArray& InObjects, class FMenuBuilder& MenuBuilder, bool bIncludeHeading = true) = 0; /** * Creates an asset with the specified name, path, and factory @@ -110,66 +137,81 @@ public: * @param CallingContext optional name of the module or method calling CreateAsset() - this is passed to the factory * @return the new asset or NULL if it fails */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Asset Tools") virtual UObject* CreateAsset(const FString& AssetName, const FString& PackagePath, UClass* AssetClass, UFactory* Factory, FName CallingContext = NAME_None) = 0; /** Opens an asset picker dialog and creates an asset with the specified name and path */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Asset Tools") virtual UObject* CreateAssetWithDialog(const FString& AssetName, const FString& PackagePath, UClass* AssetClass, UFactory* Factory, FName CallingContext = NAME_None) = 0; /** Opens an asset picker dialog and creates an asset with the chosen path */ + DEPRECATED(4.17, "This version of CreateAsset has been deprecated. Use CreateAssetWithDialog instead") virtual UObject* CreateAsset(UClass* AssetClass, UFactory* Factory, FName CallingContext = NAME_None) = 0; + /** Opens an asset picker dialog and creates an asset with the path chosen in the dialog */ + virtual UObject* CreateAssetWithDialog(UClass* AssetClass, UFactory* Factory, FName CallingContext = NAME_None) = 0; + /** Opens an asset picker dialog and creates an asset with the specified name and path. Uses OriginalObject as the duplication source. */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Asset Tools") virtual UObject* DuplicateAssetWithDialog(const FString& AssetName, const FString& PackagePath, UObject* OriginalObject) = 0; /** Creates an asset with the specified name and path. Uses OriginalObject as the duplication source. */ + UFUNCTION(BlueprintCallable, Category="Editor Scripting | Asset Tools") virtual UObject* DuplicateAsset(const FString& AssetName, const FString& PackagePath, UObject* OriginalObject) = 0; /** Renames assets using the specified names. */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Asset Tools") virtual void RenameAssets(const TArray& AssetsAndNames) const = 0; /** Event issued at the end of the rename process */ virtual FAssetPostRenameEvent& OnAssetPostRename() = 0; - /** - * Opens a file open dialog to choose files to import to the destination path. - * - * @param DestinationPath Path to import files to - * @return list of sucessfully imported assets - */ + DEPRECATED(4.17, "This version of ImportAssets has been deprecated. Use ImportAssetsWithDialog instead") virtual TArray ImportAssets(const FString& DestinationPath) = 0; - /** - * Imports the specified files to the destination path. + /** + * Opens a file open dialog to choose files to import to the destination path. + * + * @param DestinationPath Path to import files to + * @return list of successfully imported assets + */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Asset Tools") + virtual TArray ImportAssetsWithDialog(const FString& DestinationPath) = 0; + + /** + * Imports the specified files to the destination path. * * @param Files Files to import * @param DestinationPath destination path for imported files * @param ChosenFactory Specific factory to use for object creation * @param bSyncToBrowser If true sync content browser to first imported asset after import - * @return list of sucessfully imported assets + * @return list of successfully imported assets */ - virtual TArray ImportAssets(const TArray& Files, const FString& DestinationPath, UFactory* ChosenFactory = NULL, bool bSyncToBrowser = true, TArray> *FilesAndDestinations = nullptr) const = 0; + virtual TArray ImportAssets(const TArray& Files, const FString& DestinationPath, UFactory* ChosenFactory = NULL, bool bSyncToBrowser = true, TArray>* FilesAndDestinations = nullptr) const = 0; /** * Imports assets using data specified completely up front. Does not ever ask any questions of the user or show any modal error messages * * @param AutomatedImportData Data that specifies how to import each file - * @return list of sucessfully imported assets + * @return list of successfully imported assets */ - virtual TArray ImportAssetsAutomated(const class UAutomatedAssetImportData& ImportData) const = 0; + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Asset Tools") + virtual TArray ImportAssetsAutomated( const UAutomatedAssetImportData* ImportData) const = 0; /** Creates a unique package and asset name taking the form InBasePackageName+InSuffix */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Asset Tools") virtual void CreateUniqueAssetName(const FString& InBasePackageName, const FString& InSuffix, FString& OutPackageName, FString& OutAssetName) const = 0; /** Returns true if the specified asset uses a stock thumbnail resource */ - virtual bool AssetUsesGenericThumbnail( const FAssetData& AssetData ) const = 0; + virtual bool AssetUsesGenericThumbnail(const FAssetData& AssetData) const = 0; /** - * Try to diff the local version of an asset against the latest one from the depot - * + * Try to diff the local version of an asset against the latest one from the depot + * * @param InObject - The object we want to compare against the depot * @param InPackagePath - The fullpath to the package * @param InPackageName - The name of the package - */ + */ virtual void DiffAgainstDepot(UObject* InObject, const FString& InPackagePath, const FString& InPackageName) const = 0; /** Try and diff two assets using class-specific tool. Will do nothing if either asset is NULL, or they are not the same class. */ @@ -178,10 +220,10 @@ public: /** Util for dumping an asset to a temporary text file. Returns absolute filename to temp file */ virtual FString DumpAssetToTempFile(UObject* Asset) const = 0; - /* Attempt to spawn Diff tool as external process + /** Attempt to spawn Diff tool as external process * * @param DiffCommand - Command used to launch the diff tool - * @param OldTextFilename - File path to original file + * @param OldTextFilename - File path to original file * @param NewTextFilename - File path to new file * @param DiffArgs - Any extra command line arguments (defaulted to empty) * @@ -198,3 +240,13 @@ public: /** Expands any folders found in the files list, and returns a flattened list of destination paths and files. Mirrors directory structure. */ virtual void ExpandDirectories(const TArray& Files, const FString& DestinationPath, TArray>& FilesAndDestinations) const = 0; }; + +UCLASS(transient) +class UEditorScriptAccessors : public UObject +{ + GENERATED_BODY() + +public: + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Asset Tools") + static TScriptInterface GetAssetTools(); +}; diff --git a/Engine/Source/Developer/AudioFormatOpus/AudioFormatOpus.Build.cs b/Engine/Source/Developer/AudioFormatOpus/AudioFormatOpus.Build.cs index 6d703a4eb662..bd672fd29340 100644 --- a/Engine/Source/Developer/AudioFormatOpus/AudioFormatOpus.Build.cs +++ b/Engine/Source/Developer/AudioFormatOpus/AudioFormatOpus.Build.cs @@ -18,7 +18,8 @@ public class AudioFormatOpus : ModuleRules if ((Target.Platform == UnrealTargetPlatform.Win64) || (Target.Platform == UnrealTargetPlatform.Win32) || (Target.Platform == UnrealTargetPlatform.Linux) || - (Target.Platform == UnrealTargetPlatform.Mac) + (Target.Platform == UnrealTargetPlatform.Mac) || + (Target.Platform == UnrealTargetPlatform.XboxOne) //(Target.Platform == UnrealTargetPlatform.HTML5 && Target.Architecture == "-win32") ) { diff --git a/Engine/Source/Developer/AutomationController/Private/AutomationControllerManager.h b/Engine/Source/Developer/AutomationController/Private/AutomationControllerManager.h index 66a2cc062468..b1fd2447cb9b 100644 --- a/Engine/Source/Developer/AutomationController/Private/AutomationControllerManager.h +++ b/Engine/Source/Developer/AutomationController/Private/AutomationControllerManager.h @@ -327,12 +327,12 @@ protected: /** * Create a json file that contains all of our test report data at /saved/automation/logs/AutomationReport-{CL}-{DateTime}.json */ - void GenerateJsonTestPassSummary(const FAutomatedTestPassResults& SerializedPassResults, FDateTime Timestamp); + bool GenerateJsonTestPassSummary(const FAutomatedTestPassResults& SerializedPassResults, FDateTime Timestamp); /** * Generates a full html report of the testing, which may include links to images. All of it will be bundled under a folder. */ - void GenerateHtmlTestPassSummary(const FAutomatedTestPassResults& SerializedPassResults, FDateTime Timestamp); + bool GenerateHtmlTestPassSummary(const FAutomatedTestPassResults& SerializedPassResults, FDateTime Timestamp); /** * Gather all info, warning, and error lines generated over the course of a test. @@ -403,6 +403,12 @@ private: /** Handles FAutomationWorkerScreenImage messages. */ void HandleReceivedScreenShot( const FAutomationWorkerScreenImage& Message, const IMessageContextRef& Context ); + /** Handles FAutomationWorkerTestDataRequest messages. */ + void HandleTestDataRequest(const FAutomationWorkerTestDataRequest& Message, const IMessageContextRef& Context); + + /** Handles FAutomationWorkerPerformanceDataRequest messages. */ + void HandlePerformanceDataRequest(const FAutomationWorkerPerformanceDataRequest& Message, const IMessageContextRef& Context); + /** Handles FAutomationWorkerRequestNextNetworkCommand messages. */ void HandleRequestNextNetworkCommandMessage( const FAutomationWorkerRequestNextNetworkCommand& Message, const IMessageContextRef& Context ); diff --git a/Engine/Source/Developer/AutomationController/Private/AutomationControllerManger.cpp b/Engine/Source/Developer/AutomationController/Private/AutomationControllerManger.cpp index a900e8d39589..9de0fab502bd 100644 --- a/Engine/Source/Developer/AutomationController/Private/AutomationControllerManger.cpp +++ b/Engine/Source/Developer/AutomationController/Private/AutomationControllerManger.cpp @@ -27,6 +27,8 @@ #include "Logging/MessageLog.h" #endif +DEFINE_LOG_CATEGORY_STATIC(AutomationControllerLog, Log, All) + FAutomationControllerManager::FAutomationControllerManager() { CheckpointFile = nullptr; @@ -320,21 +322,23 @@ void FAutomationControllerManager::CollectTestResults(TSharedPtrLogf(ELogVerbosity::Error, TEXT("Test Report Json is invalid - report not generated.")); + if ( FFileHelper::SaveStringToFile(Json, *ReportFileName, FFileHelper::EEncodingOptions::ForceUTF8) ) + { + return true; + } } + + UE_LOG(AutomationControllerLog, Error, TEXT("Test Report Json is invalid - report not generated.")); + return false; } -void FAutomationControllerManager::GenerateHtmlTestPassSummary(const FAutomatedTestPassResults& SerializedPassResults, FDateTime Timestamp) +bool FAutomationControllerManager::GenerateHtmlTestPassSummary(const FAutomatedTestPassResults& SerializedPassResults, FDateTime Timestamp) { FString ReportTemplate; const bool bLoadedResult = FFileHelper::LoadFileToString(ReportTemplate, *( FPaths::EngineContentDir() / TEXT("Automation/Report-Template.html") )); @@ -342,15 +346,14 @@ void FAutomationControllerManager::GenerateHtmlTestPassSummary(const FAutomatedT if ( bLoadedResult ) { FString ReportFileName = FString::Printf(TEXT("%s/index.html"), *ReportOutputPath); - if ( !FFileHelper::SaveStringToFile(ReportTemplate, *ReportFileName, FFileHelper::EEncodingOptions::ForceUTF8) ) + if ( FFileHelper::SaveStringToFile(ReportTemplate, *ReportFileName, FFileHelper::EEncodingOptions::ForceUTF8) ) { - GLog->Logf(ELogVerbosity::Error, TEXT("Test Report Html is invalid - report not generated.")); + return true; } } - else - { - GLog->Logf(ELogVerbosity::Error, TEXT("Test Report Html is invalid - report not generated.")); - } + + UE_LOG(AutomationControllerLog, Error, TEXT("Test Report Html is invalid - report not generated.")); + return false; } FString FAutomationControllerManager::SlugString(const FString& DisplayString) const @@ -497,6 +500,7 @@ void FAutomationControllerManager::Startup() .Handling(this, &FAutomationControllerManager::HandleRequestTestsReplyCompleteMessage) .Handling(this, &FAutomationControllerManager::HandleRunTestsReplyMessage) .Handling(this, &FAutomationControllerManager::HandleReceivedScreenShot) + .Handling(this, &FAutomationControllerManager::HandleTestDataRequest) .Handling(this, &FAutomationControllerManager::HandleWorkerOfflineMessage); if ( MessageEndpoint.IsValid() ) @@ -598,8 +602,12 @@ void FAutomationControllerManager::ProcessResults() { FDateTime Timestamp = FDateTime::Now(); + UE_LOG(AutomationControllerLog, Display, TEXT("Generating Automation Report @ %s."), *ReportOutputPath); + if ( IFileManager::Get().DirectoryExists(*ReportOutputPath) ) { + UE_LOG(AutomationControllerLog, Display, TEXT("Existing report directory found, deleting %s."), *ReportOutputPath); + // Clear the old report folder. Why move it first? Because RemoveDirectory // is actually an async call that is not immediately carried out by the Windows OS; Moving a directory on the other hand, is sync. // So we move, to a temporary location, then delete it. @@ -607,7 +615,7 @@ void FAutomationControllerManager::ProcessResults() IFileManager::Get().Move(*TempDirectory, *ReportOutputPath); IFileManager::Get().DeleteDirectory(*TempDirectory, false, true); } - + FScreenshotExportResults ExportResults = ScreenshotManager->ExportComparisonResultsAsync(ReportOutputPath).Get(); FAutomatedTestPassResults SerializedPassResults = OurPassResults; @@ -656,6 +664,8 @@ void FAutomationControllerManager::ProcessResults() } } + UE_LOG(AutomationControllerLog, Display, TEXT("Writing reports... %s."), *ReportOutputPath); + // Generate Json GenerateJsonTestPassSummary(SerializedPassResults, Timestamp); @@ -664,6 +674,8 @@ void FAutomationControllerManager::ProcessResults() if ( !DeveloperReportUrl.IsEmpty() ) { + UE_LOG(AutomationControllerLog, Display, TEXT("Launching Report URL %s."), *DeveloperReportUrl); + FPlatformProcess::LaunchURL(*DeveloperReportUrl, nullptr, nullptr); } } @@ -887,6 +899,62 @@ void FAutomationControllerManager::HandleReceivedScreenShot(const FAutomationWor ComparisonQueue.Enqueue(Comparison); } +void FAutomationControllerManager::HandleTestDataRequest(const FAutomationWorkerTestDataRequest& Message, const IMessageContextRef& Context) +{ + const FString TestDataRoot = FPaths::ConvertRelativePathToFull(FPaths::GameDir() / TEXT("Test")); + const FString DataFile = Message.DataType / Message.DataPlatform / Message.DataTestName / Message.DataName + TEXT(".json"); + const FString DataFullPath = TestDataRoot / DataFile; + + // Generate the folder for the data if it doesn't exist. + const bool bTree = true; + IFileManager::Get().MakeDirectory(*FPaths::GetPath(DataFile), bTree); + + bool bIsNew = true; + FString ResponseJsonData = Message.JsonData; + + if ( FPaths::FileExists(DataFullPath) ) + { + if ( FFileHelper::LoadFileToString(ResponseJsonData, *DataFullPath) ) + { + bIsNew = false; + } + else + { + // TODO Error + } + } + + if ( bIsNew ) + { + FString IncomingTestData = FPaths::GameSavedDir() / TEXT("Automation/IncomingData/") / DataFile; + if ( FFileHelper::SaveStringToFile(Message.JsonData, *IncomingTestData) ) + { + //TODO Anything extra to do here? + } + else + { + //TODO What do we do if this fails? + } + } + + FAutomationWorkerTestDataResponse* ResponseMessage = new FAutomationWorkerTestDataResponse(); + ResponseMessage->bIsNew = bIsNew; + ResponseMessage->JsonData = ResponseJsonData; + + MessageEndpoint->Send(ResponseMessage, Context->GetSender()); +} + +void FAutomationControllerManager::HandlePerformanceDataRequest(const FAutomationWorkerPerformanceDataRequest& Message, const IMessageContextRef& Context) +{ + //TODO Read/Performance data. + + FAutomationWorkerPerformanceDataResponse* ResponseMessage = new FAutomationWorkerPerformanceDataResponse(); + ResponseMessage->bSuccess = true; + ResponseMessage->ErrorMessage = TEXT(""); + + MessageEndpoint->Send(ResponseMessage, Context->GetSender()); +} + void FAutomationControllerManager::HandleRequestNextNetworkCommandMessage(const FAutomationWorkerRequestNextNetworkCommand& Message, const IMessageContextRef& Context) { // Harvest iteration of running the tests this result came from (stops stale results from being committed to subsequent runs) diff --git a/Engine/Source/Developer/AutomationDriver/Private/AutomatedApplication.cpp b/Engine/Source/Developer/AutomationDriver/Private/AutomatedApplication.cpp index 8cfb60175f33..290b86b8bbe7 100644 --- a/Engine/Source/Developer/AutomationDriver/Private/AutomatedApplication.cpp +++ b/Engine/Source/Developer/AutomationDriver/Private/AutomatedApplication.cpp @@ -355,9 +355,9 @@ public: return RealApplication->GetWorkArea(CurrentWindow); } - virtual bool TryCalculatePopupWindowPosition(const FPlatformRect& Anchor, const FVector2D& Size, const EPopUpOrientation::Type Orientation, FVector2D* const OutCalculatedPopUpPosition) const override + virtual bool TryCalculatePopupWindowPosition(const FPlatformRect& Anchor, const FVector2D& Size, const FVector2D& ProposedPlacement, const EPopUpOrientation::Type Orientation, FVector2D* const OutCalculatedPopUpPosition) const override { - return RealApplication->TryCalculatePopupWindowPosition(Anchor, Size, Orientation, OutCalculatedPopUpPosition); + return RealApplication->TryCalculatePopupWindowPosition(Anchor, Size, ProposedPlacement, Orientation, OutCalculatedPopUpPosition); } virtual void GetInitialDisplayMetrics(FDisplayMetrics& OutDisplayMetrics) const override diff --git a/Engine/Source/Developer/AutomationDriver/Private/StepExecutor.cpp b/Engine/Source/Developer/AutomationDriver/Private/StepExecutor.cpp index 4dae57622bab..7a5bc9e14bbd 100644 --- a/Engine/Source/Developer/AutomationDriver/Private/StepExecutor.cpp +++ b/Engine/Source/Developer/AutomationDriver/Private/StepExecutor.cpp @@ -133,7 +133,7 @@ private: } CurrentStepIndex = StepIndex; - float Milliseconds = Result.NextWait.GetTicks() / ETimespan::TicksPerMillisecond; + float Milliseconds = (float)(Result.NextWait.GetTicks()) / ETimespan::TicksPerMillisecond; float Delay = FMath::Max(SMALL_NUMBER, (Milliseconds / 1000) * Configuration->ExecutionSpeedMultiplier); if (LastDelay < KINDA_SMALL_NUMBER) diff --git a/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackend.cpp b/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackend.cpp index ec1e90620f50..378e3f057880 100644 --- a/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackend.cpp +++ b/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackend.cpp @@ -162,7 +162,7 @@ void FBlueprintCompilerCppBackend::EmitAssignmentStatment(FEmitterLocalContext& FString BeginCast; FString EndCast; - FEmitHelper::GenerateAutomaticCast(EmitterContext, Statement.LHS->Type, Statement.RHS[0]->Type, BeginCast, EndCast); + FEmitHelper::GenerateAutomaticCast(EmitterContext, Statement.LHS->Type, Statement.RHS[0]->Type, Statement.LHS->AssociatedVarProperty, Statement.RHS[0]->AssociatedVarProperty, BeginCast, EndCast); const FString RHS = FString::Printf(TEXT("%s%s%s"), *BeginCast, *SourceExpression, *EndCast); EmitterContext.AddLine(SetterExpression.BuildFull(RHS)); } @@ -509,7 +509,7 @@ FString FBlueprintCompilerCppBackend::EmitSwitchValueStatmentInner(FEmitterLocal FEdGraphPinType LType; if (Schema->ConvertPropertyToPinType(DefaultValueTerm->AssociatedVarProperty, LType)) { - FEmitHelper::GenerateAutomaticCast(EmitterContext, LType, Term->Type, BeginCast, EndCast, true); + FEmitHelper::GenerateAutomaticCast(EmitterContext, LType, Term->Type, DefaultValueTerm->AssociatedVarProperty, Term->AssociatedVarProperty, BeginCast, EndCast, true); } const FString TermEvaluation = TermToText(EmitterContext, Term, ENativizedTermUsage::UnspecifiedOrReference); //should bGetter be false ? @@ -642,7 +642,7 @@ FString FBlueprintCompilerCppBackend::EmitMethodInputParameterList(FEmitterLocal { CastWildCard.FillWildcardType(FuncParamProperty, LType); - FEmitHelper::GenerateAutomaticCast(EmitterContext, LType, Term->Type, BeginCast, CloseCast); + FEmitHelper::GenerateAutomaticCast(EmitterContext, LType, Term->Type, FuncParamProperty, Term->AssociatedVarProperty, BeginCast, CloseCast); TermUsage = LType.bIsReference ? ENativizedTermUsage::UnspecifiedOrReference : ENativizedTermUsage::Getter; } VarName += BeginCast; @@ -679,7 +679,7 @@ static FString CustomThunkFunctionPostfix(FBlueprintCompiledStatement& Statement if (UArrayProperty* ArrayProperty = Cast(*PropIt)) { ArrayTerm = Statement.RHS[NumParams]; - ensure(ArrayTerm && ArrayTerm->Type.bIsArray); + ensure(ArrayTerm && ArrayTerm->Type.IsArray()); break; } NumParams++; @@ -713,11 +713,13 @@ static FString CustomThunkFunctionPostfix(FBlueprintCompiledStatement& Statement FString FBlueprintCompilerCppBackend::EmitCallStatmentInner(FEmitterLocalContext& EmitterContext, FBlueprintCompiledStatement& Statement, bool bInline, FString PostFix) { + check(Statement.FunctionToCall != nullptr); + const bool bCallOnDifferentObject = Statement.FunctionContext && (Statement.FunctionContext->Name != TEXT("self")); const bool bStaticCall = Statement.FunctionToCall->HasAnyFunctionFlags(FUNC_Static); const bool bUseSafeContext = bCallOnDifferentObject && !bStaticCall; - const bool bAnyInterfaceCall = bCallOnDifferentObject && Statement.FunctionContext && (UEdGraphSchema_K2::PC_Interface == Statement.FunctionContext->Type.PinCategory); - const bool bInterfaceCallExecute = bAnyInterfaceCall && Statement.FunctionToCall && Statement.FunctionToCall->HasAnyFunctionFlags(FUNC_Event | FUNC_BlueprintEvent); + const bool bAnyInterfaceCall = bCallOnDifferentObject && Statement.FunctionContext && (Statement.bIsInterfaceContext || UEdGraphSchema_K2::PC_Interface == Statement.FunctionContext->Type.PinCategory); + const bool bInterfaceCallExecute = bAnyInterfaceCall && Statement.FunctionToCall->HasAnyFunctionFlags(FUNC_Event | FUNC_BlueprintEvent); const bool bNativeEvent = FEmitHelper::ShouldHandleAsNativeEvent(Statement.FunctionToCall, false); const UClass* CurrentClass = EmitterContext.GetCurrentlyGeneratedClass(); @@ -775,7 +777,7 @@ FString FBlueprintCompilerCppBackend::EmitCallStatmentInner(FEmitterLocalContext check(Schema); if (Schema->ConvertPropertyToPinType(FuncToCallReturnProperty, RType)) { - FEmitHelper::GenerateAutomaticCast(EmitterContext, Statement.LHS->Type, RType, BeginCast, CloseCast); + FEmitHelper::GenerateAutomaticCast(EmitterContext, Statement.LHS->Type, RType, Statement.LHS->AssociatedVarProperty, FuncToCallReturnProperty, BeginCast, CloseCast); } Result += BeginCast; } @@ -783,19 +785,31 @@ FString FBlueprintCompilerCppBackend::EmitCallStatmentInner(FEmitterLocalContext FNativizationSummaryHelper::FunctionUsed(CurrentClass, Statement.FunctionToCall); + UClass* FunctionOwner = Statement.FunctionToCall->GetOwnerClass(); // Emit object to call the method on if (bInterfaceCallExecute) { - auto ContextInterfaceClass = CastChecked(Statement.FunctionContext->Type.PinSubCategoryObject.Get()); - ensure(ContextInterfaceClass->IsChildOf()); - Result += FString::Printf(TEXT("%s::Execute_%s(%s.GetObject() ") + UClass* ContextInterfaceClass = CastChecked(Statement.FunctionContext->Type.PinSubCategoryObject.Get()); + const bool bInputIsInterface = ContextInterfaceClass->IsChildOf(); + + FString ExecuteFormat = TEXT("%s::Execute_%s(%s "); + if (bInputIsInterface) + { + ExecuteFormat.InsertAt(ExecuteFormat.Len()-1, TEXT(".GetObject()")); + } + else + { + ContextInterfaceClass = FunctionOwner; + ensure(ContextInterfaceClass->IsChildOf()); + } + + Result += FString::Printf(*ExecuteFormat , *FEmitHelper::GetCppName(ContextInterfaceClass) , *FunctionToCallOriginalName , *TermToText(EmitterContext, Statement.FunctionContext, ENativizedTermUsage::Getter, false)); } else { - auto FunctionOwner = Statement.FunctionToCall->GetOwnerClass(); auto OwnerBPGC = Cast(FunctionOwner); const bool bUnconvertedClass = OwnerBPGC && !EmitterContext.Dependencies.WillClassBeConverted(OwnerBPGC); const bool bIsCustomThunk = bStaticCall && ( Statement.FunctionToCall->GetBoolMetaData(TEXT("CustomThunk")) @@ -835,7 +849,7 @@ FString FBlueprintCompilerCppBackend::EmitCallStatmentInner(FEmitterLocalContext Result += CustomThunkFunctionPostfix(Statement); } - if (Statement.bIsParentContext && bNativeEvent) + if ((Statement.bIsParentContext || Statement.bIsInterfaceContext) && bNativeEvent) { ensure(!bCallOnDifferentObject); Result += TEXT("_Implementation"); @@ -1047,10 +1061,10 @@ FString FBlueprintCompilerCppBackend::TermToText(FEmitterLocalContext& EmitterCo } const bool bNativeConstTemplateArg = Term->AssociatedVarProperty && Term->AssociatedVarProperty->HasMetaData(FName(TEXT("NativeConstTemplateArg"))); - if (Term->Type.bIsArray && bNativeConstTemplateArg && bIsAccessible && bGetter) + if (Term->Type.IsArray() && bNativeConstTemplateArg && bIsAccessible && bGetter) { FEdGraphPinType InnerType = Term->Type; - InnerType.bIsArray = false; + InnerType.ContainerType = EPinContainerType::None; InnerType.bIsConst = false; const FString CppType = FEmitHelper::PinTypeToNativeType(InnerType); ResultPath = FString::Printf(TEXT("TArrayCaster(%s).Get<%s>()"), *CppType, *ResultPath, *CppType); diff --git a/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendBase.cpp b/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendBase.cpp index 4cf9506612a6..4a01d651376e 100644 --- a/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendBase.cpp +++ b/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendBase.cpp @@ -174,7 +174,7 @@ struct FIncludeHeaderHelper Dst.AddLine(FString::Printf(TEXT("#include \"%s%s\""), Message, bAddDotH ? TEXT(".h") : TEXT(""))); } - static void EmitInner(FCodeText& Dst, const TSet& Src, const TSet& Declarations, TSet& AlreadyIncluded) + static void EmitInner(FCodeText& Dst, const TSet& Src, const TSet& Declarations, const FCompilerNativizationOptions& NativizationOptions, TSet& AlreadyIncluded) { auto EngineSourceDir = FPaths::EngineSourceDir(); auto GameSourceDir = FPaths::GameSourceDir(); @@ -197,8 +197,13 @@ struct FIncludeHeaderHelper AlreadyIncluded.Add(Name, &bAlreadyIncluded); if (!bAlreadyIncluded) { - const FString GeneratedFilename = FEmitHelper::GetBaseFilename(Field); - FIncludeHeaderHelper::EmitIncludeHeader(Dst, *GeneratedFilename, true); + const FString GeneratedFilename = FEmitHelper::GetBaseFilename(Field, NativizationOptions); + + // In some cases the caller may have already primed this array with the generated filename. + if (!AlreadyIncluded.Contains(GeneratedFilename)) + { + FIncludeHeaderHelper::EmitIncludeHeader(Dst, *GeneratedFilename, true); + } } } // headers for native items @@ -256,7 +261,7 @@ struct FIncludedUnconvertedWrappers { FCodeText AdditionalIncludes; TSet DummyStrSet; - FIncludeHeaderHelper::EmitInner(AdditionalIncludes, InContext.UsedUnconvertedWrapper, TSet{}, DummyStrSet); + FIncludeHeaderHelper::EmitInner(AdditionalIncludes, InContext.UsedUnconvertedWrapper, TSet{}, InContext.NativizationOptions, DummyStrSet); (bInInludeInBody ? InContext.Body : InContext.Header).Result.ReplaceInline(Placeholder(), *AdditionalIncludes.Result); } @@ -301,7 +306,7 @@ FString FBlueprintCompilerCppBackendBase::GenerateCodeFromClass(UClass* SourceCl } // use GetBaseFilename() so that we can coordinate #includes and filenames - auto CleanCppClassName = FEmitHelper::GetBaseFilename(SourceClass); + auto CleanCppClassName = FEmitHelper::GetBaseFilename(SourceClass, NativizationOptions); auto CppClassName = FEmitHelper::GetCppName(SourceClass); FGatherConvertedClassDependencies Dependencies(SourceClass, NativizationOptions); @@ -466,7 +471,7 @@ FString FBlueprintCompilerCppBackendBase::GenerateCodeFromClass(UClass* SourceCl { FCodeText AdditionalIncludes; TSet DummyStrSet; - FIncludeHeaderHelper::EmitInner(AdditionalIncludes, EmitterContext.StructsUsedAsInlineValues, TSet{}, DummyStrSet); + FIncludeHeaderHelper::EmitInner(AdditionalIncludes, EmitterContext.StructsUsedAsInlineValues, TSet{}, EmitterContext.NativizationOptions, DummyStrSet); EmitterContext.Body.Result.ReplaceInline(PlaceholderForInlinedStructInlude, *AdditionalIncludes.Result); } @@ -884,14 +889,14 @@ void FBlueprintCompilerCppBackendBase::ConstructFunctionBody(FEmitterLocalContex } } -void FBlueprintCompilerCppBackendBase::GenerateCodeFromEnum(UUserDefinedEnum* SourceEnum, FString& OutHeaderCode, FString& OutCPPCode) +void FBlueprintCompilerCppBackendBase::GenerateCodeFromEnum(UUserDefinedEnum* SourceEnum, const FCompilerNativizationOptions& NativizationOptions, FString& OutHeaderCode, FString& OutCPPCode) { check(SourceEnum); FCodeText Header; Header.AddLine(TEXT("#pragma once")); const FString EnumCppName = *FEmitHelper::GetCppName(SourceEnum); // use GetBaseFilename() so that we can coordinate #includes and filenames - Header.AddLine(FString::Printf(TEXT("#include \"%s.generated.h\""), *FEmitHelper::GetBaseFilename(SourceEnum))); + Header.AddLine(FString::Printf(TEXT("#include \"%s.generated.h\""), *FEmitHelper::GetBaseFilename(SourceEnum, NativizationOptions))); Header.AddLine(FString::Printf(TEXT("UENUM(BlueprintType, %s )"), *FEmitHelper::ReplaceConvertedMetaData(SourceEnum))); Header.AddLine(FString::Printf(TEXT("enum class %s : uint8"), *EnumCppName)); Header.AddLine(TEXT("{")); @@ -930,7 +935,7 @@ void FBlueprintCompilerCppBackendBase::GenerateCodeFromEnum(UUserDefinedEnum* So const FString PCHFilename = FEmitHelper::GetPCHFilename(); if (!PCHFilename.IsEmpty()) { - Body.AddLine(FString::Printf(TEXT("#include \"%s\""), *PCHFilename)); + Body.AddLine(FString::Printf(TEXT("#include \"%s\""), *PCHFilename)); } else { @@ -942,7 +947,7 @@ void FBlueprintCompilerCppBackendBase::GenerateCodeFromEnum(UUserDefinedEnum* So } } - Body.AddLine(FString::Printf(TEXT("#include \"%s.h\""), *FEmitHelper::GetBaseFilename(SourceEnum))); + Body.AddLine(FString::Printf(TEXT("#include \"%s.h\""), *FEmitHelper::GetBaseFilename(SourceEnum, NativizationOptions))); // generate implementation of GetUserFriendlyName: Body.AddLine(FString::Printf(TEXT("FText %s__GetUserFriendlyName(int32 InValue)"), *EnumCppName, *EnumCppName)); @@ -976,14 +981,14 @@ void FBlueprintCompilerCppBackendBase::GenerateCodeFromEnum(UUserDefinedEnum* So OutCPPCode = MoveTemp(Body.Result); } -FString FBlueprintCompilerCppBackendBase::GenerateCodeFromStruct(UUserDefinedStruct* SourceStruct, const FCompilerNativizationOptions& NativizationOptions) +void FBlueprintCompilerCppBackendBase::GenerateCodeFromStruct(UUserDefinedStruct* SourceStruct, const FCompilerNativizationOptions& NativizationOptions, FString& OutHeaderCode, FString& OutCPPCode) { check(SourceStruct); FGatherConvertedClassDependencies Dependencies(SourceStruct, NativizationOptions); FNativizationSummaryHelper::RegisterRequiredModules(NativizationOptions.PlatformName, Dependencies.RequiredModuleNames); FEmitterLocalContext EmitterContext(Dependencies, NativizationOptions); // use GetBaseFilename() so that we can coordinate #includes and filenames - EmitFileBeginning(FEmitHelper::GetBaseFilename(SourceStruct), EmitterContext, true, true); + EmitFileBeginning(FEmitHelper::GetBaseFilename(SourceStruct, NativizationOptions), EmitterContext, true, true); { FIncludedUnconvertedWrappers IncludedUnconvertedWrappers(EmitterContext, false); const FString CppStructName = FEmitHelper::GetCppName(SourceStruct); @@ -1014,7 +1019,8 @@ FString FBlueprintCompilerCppBackendBase::GenerateCodeFromStruct(UUserDefinedStr EmitterContext.Header.AddLine(TEXT("};")); } - return EmitterContext.Header.Result; + OutCPPCode = MoveTemp(EmitterContext.Body.Result); + OutHeaderCode = MoveTemp(EmitterContext.Header.Result); } FString FBlueprintCompilerCppBackendBase::GenerateWrapperForClass(UClass* SourceClass, const FCompilerNativizationOptions& NativizationOptions) @@ -1099,7 +1105,7 @@ FString FBlueprintCompilerCppBackendBase::GenerateWrapperForClass(UClass* Source } // Include standard stuff - EmitFileBeginning(FEmitHelper::GetBaseFilename(SourceClass), EmitterContext, bGenerateAnyMCDelegateProperty, true, true, SuperClassToUse); + EmitFileBeginning(FEmitHelper::GetBaseFilename(SourceClass, NativizationOptions), EmitterContext, bGenerateAnyMCDelegateProperty, true, true, SuperClassToUse); { FIncludedUnconvertedWrappers IncludedUnconvertedWrappers(EmitterContext, false); @@ -1308,6 +1314,7 @@ void FBlueprintCompilerCppBackendBase::EmitFileBeginning(const FString& CleanNam FIncludeHeaderHelper::EmitIncludeHeader(EmitterContext.Body, *MainHeaderFilename, false); } } + FIncludeHeaderHelper::EmitIncludeHeader(EmitterContext.Body, *CleanName, true); FIncludeHeaderHelper::EmitIncludeHeader(bIncludeCodeHelpersInHeader ? EmitterContext.Header : EmitterContext.Body, TEXT("GeneratedCodeHelpers"), true); FIncludeHeaderHelper::EmitIncludeHeader(EmitterContext.Header, TEXT("Blueprint/BlueprintSupport"), true); @@ -1324,16 +1331,16 @@ void FBlueprintCompilerCppBackendBase::EmitFileBeginning(const FString& CleanNam { IncludeInHeader.Add(AdditionalFieldToIncludeInHeader); } - FIncludeHeaderHelper::EmitInner(EmitterContext.Header, IncludeInHeader, bFullyIncludedDeclaration ? TSet() : EmitterContext.Dependencies.DeclareInHeader, AlreadyIncluded); + FIncludeHeaderHelper::EmitInner(EmitterContext.Header, IncludeInHeader, bFullyIncludedDeclaration ? TSet() : EmitterContext.Dependencies.DeclareInHeader, EmitterContext.NativizationOptions, AlreadyIncluded); if (bFullyIncludedDeclaration) { - FIncludeHeaderHelper::EmitInner(EmitterContext.Header, EmitterContext.Dependencies.DeclareInHeader, TSet(), AlreadyIncluded); + FIncludeHeaderHelper::EmitInner(EmitterContext.Header, EmitterContext.Dependencies.DeclareInHeader, TSet(), EmitterContext.NativizationOptions, AlreadyIncluded); } else { IncludeInBody.Append(EmitterContext.Dependencies.DeclareInHeader); } - FIncludeHeaderHelper::EmitInner(EmitterContext.Body, IncludeInBody, TSet(), AlreadyIncluded); + FIncludeHeaderHelper::EmitInner(EmitterContext.Body, IncludeInBody, TSet(), EmitterContext.NativizationOptions, AlreadyIncluded); if (bIncludeGeneratedH) { diff --git a/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendBase.h b/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendBase.h index 0ca1f0688c1f..0af346b88038 100644 --- a/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendBase.h +++ b/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendBase.h @@ -44,8 +44,8 @@ public: // IBlueprintCompilerCppBackend implementation virtual FString GenerateCodeFromClass(UClass* SourceClass, TIndirectArray& Functions, bool bGenerateStubsOnly, const FCompilerNativizationOptions& NativizationOptions, FString& OutCppBody) override; - virtual void GenerateCodeFromEnum(UUserDefinedEnum* SourceEnum, FString& OutHeaderCode, FString& OutCPPCode) override; - virtual FString GenerateCodeFromStruct(UUserDefinedStruct* SourceStruct, const FCompilerNativizationOptions& NativizationOptions) override; + virtual void GenerateCodeFromEnum(UUserDefinedEnum* SourceEnum, const FCompilerNativizationOptions& NativizationOptions, FString& OutHeaderCode, FString& OutCPPCode) override; + virtual void GenerateCodeFromStruct(UUserDefinedStruct* SourceStruct, const FCompilerNativizationOptions& NativizationOptions, FString& OutHeaderCode, FString& OutCPPCode) override; virtual FString GenerateWrapperForClass(UClass* SourceClass, const FCompilerNativizationOptions& NativizationOptions) override; // end of IBlueprintCompilerCppBackend implementation diff --git a/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendGatherDependencies.cpp b/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendGatherDependencies.cpp index eb2942695f8b..a498fa84c3a8 100644 --- a/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendGatherDependencies.cpp +++ b/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendGatherDependencies.cpp @@ -70,6 +70,30 @@ struct FGatherConvertedClassDependenciesHelperBase : public FReferenceCollector Dependencies.IncludeInBody.Add(InField); } } + + void AddConvertedClassDependency(UBlueprintGeneratedClass* InBPGC) + { + if (InBPGC && !Dependencies.ConvertedClasses.Contains(InBPGC)) + { + Dependencies.ConvertedClasses.Add(InBPGC); + } + } + + void AddConvertedStructDependency(UUserDefinedStruct* InUDS) + { + if (InUDS && !Dependencies.ConvertedStructs.Contains(InUDS)) + { + Dependencies.ConvertedStructs.Add(InUDS); + } + } + + void AddConvertedEnumDependency(UUserDefinedEnum* InUDE) + { + if (InUDE && !Dependencies.ConvertedEnum.Contains(InUDE)) + { + Dependencies.ConvertedEnum.Add(InUDE); + } + } }; struct FFindAssetsToInclude : public FGatherConvertedClassDependenciesHelperBase @@ -80,6 +104,110 @@ struct FFindAssetsToInclude : public FGatherConvertedClassDependenciesHelperBase FindReferences(Dependencies.GetActualStruct()); } + void MaybeIncludeObjectAsDependency(UObject* Object, UStruct* CurrentlyConvertedStruct) + { + if (Object->HasAnyFlags(RF_ClassDefaultObject)) + { + // Static functions from libraries are called on CDO. (The functions is stored as a name not an object). + UClass* OwnerClass = Object->GetClass(); + if (OwnerClass && (OwnerClass != CurrentlyConvertedStruct)) + { + // First, see if we need to add the class as a dependency. The CDO itself will then be added below. + MaybeIncludeObjectAsDependency(OwnerClass, CurrentlyConvertedStruct); + } + } + + const bool bUseZConstructorInGeneratedCode = false; + UField* AsField = Cast(Object); + UBlueprintGeneratedClass* ObjAsBPGC = Cast(Object); + const bool bWillBeConvetedAsBPGC = ObjAsBPGC && Dependencies.WillClassBeConverted(ObjAsBPGC); + if (bWillBeConvetedAsBPGC) + { + if (ObjAsBPGC != CurrentlyConvertedStruct) + { + AddConvertedClassDependency(ObjAsBPGC); + if (!bUseZConstructorInGeneratedCode) + { + IncludeTheHeaderInBody(ObjAsBPGC); + } + } + return; + } + else if (UUserDefinedStruct* UDS = Cast(Object)) + { + if (!UDS->HasAnyFlags(RF_ClassDefaultObject)) + { + AddConvertedStructDependency(UDS); + if (!bUseZConstructorInGeneratedCode) + { + IncludeTheHeaderInBody(UDS); + } + } + } + else if (UUserDefinedEnum* UDE = Cast(Object)) + { + if (!UDE->HasAnyFlags(RF_ClassDefaultObject)) + { + AddConvertedEnumDependency(UDE); + } + } + else if ((Object->IsAsset() || AsField) && !Object->IsIn(CurrentlyConvertedStruct)) + { + if (AsField) + { + if (UClass* OwnerClass = AsField->GetOwnerClass()) + { + if (OwnerClass != AsField) + { + // This is a field owned by a class, so attempt to add the class as a dependency. + MaybeIncludeObjectAsDependency(OwnerClass, CurrentlyConvertedStruct); + } + else + { + // Add the class itself as a dependency. + Dependencies.Assets.AddUnique(OwnerClass); + + if (ObjAsBPGC) + { + // For BPGC types, we also include the CDO as a dependency (since it will be serialized). + // Note that if we get here, we already know from above that the BPGC is not being converted. + Dependencies.Assets.AddUnique(ObjAsBPGC->GetDefaultObject()); + } + } + } + else if (UStruct* OwnerStruct = AsField->GetOwnerStruct()) + { + if (OwnerStruct != AsField) + { + // This is a field that's owned by a struct, so attempt to add the struct as a dependency. + MaybeIncludeObjectAsDependency(OwnerStruct, CurrentlyConvertedStruct); + } + else + { + // Add the struct itself as a dependency. + Dependencies.Assets.AddUnique(OwnerStruct); + } + } + else + { + // UFUNCTION, UENUM, etc. + Dependencies.Assets.AddUnique(Object); + } + } + else + { + // Include the asset as a dependency. + Dependencies.Assets.AddUnique(Object); + } + + // No need to traverse these objects any further, so we just return. + return; + } + + // Recursively add references from this object. + FindReferencesForNewObject(Object); + } + virtual void HandleObjectReference(UObject*& InObject, const UObject* InReferencingObject, const UProperty* InReferencingProperty) override { UObject* Object = InObject; @@ -101,82 +229,8 @@ struct FFindAssetsToInclude : public FGatherConvertedClassDependenciesHelperBase return; } - if (Object->HasAnyFlags(RF_ClassDefaultObject)) - { - // Static functions from libraries are called on CDO. (The functions is stored as a name not an object). - UClass* OwnerClass = Object->GetClass(); - if (OwnerClass && (OwnerClass != CurrentlyConvertedStruct)) - { - UBlueprintGeneratedClass* OwnerAsBPGC = Cast(OwnerClass); - if (OwnerAsBPGC && !Dependencies.ConvertedClasses.Contains(OwnerAsBPGC) && Dependencies.WillClassBeConverted(OwnerAsBPGC)) - { - Dependencies.ConvertedClasses.Add(OwnerAsBPGC); - } - } - } - - const bool bUseZConstructorInGeneratedCode = false; - //TODO: What About Delegates? - UField* AsField = Cast(Object); - UBlueprintGeneratedClass* ObjAsBPGC = Cast(Object); - //TODO: update once the BootTimeEDL is ready - const bool bWillBeConvetedAsBPGC = ObjAsBPGC && Dependencies.WillClassBeConverted(ObjAsBPGC); - if (bWillBeConvetedAsBPGC) - { - if (ObjAsBPGC != CurrentlyConvertedStruct) - { - Dependencies.ConvertedClasses.Add(ObjAsBPGC); - if(!bUseZConstructorInGeneratedCode) - { - IncludeTheHeaderInBody(ObjAsBPGC); - } - } - return; - } - else if (UUserDefinedStruct* UDS = Cast(Object)) - { - if (!UDS->HasAnyFlags(RF_ClassDefaultObject)) - { - Dependencies.ConvertedStructs.Add(UDS); - if(!bUseZConstructorInGeneratedCode) - { - IncludeTheHeaderInBody(UDS); - } - } - } - else if (UUserDefinedEnum* UDE = Cast(Object)) - { - if (!UDE->HasAnyFlags(RF_ClassDefaultObject)) - { - Dependencies.ConvertedEnum.Add(UDE); - } - } - else if ((Object->IsAsset() || AsField) && !Object->IsIn(CurrentlyConvertedStruct)) - { - if (AsField) - { - UClass* OwnerClass = AsField->GetOwnerClass(); - if (OwnerClass) - { - Dependencies.Assets.AddUnique(OwnerClass); - } - else if (UStruct* OwnerStruct = AsField->GetOwnerStruct()) - { - Dependencies.Assets.AddUnique(OwnerStruct); - } - else - { - Dependencies.Assets.AddUnique(Object); - } - } - else - { - Dependencies.Assets.AddUnique(Object); - } - return; - } - - FindReferencesForNewObject(Object); + // Attempt to add the referenced object as a dependency. + MaybeIncludeObjectAsDependency(Object, CurrentlyConvertedStruct); } }; @@ -204,7 +258,7 @@ struct FFindHeadersToInclude : public FGatherConvertedClassDependenciesHelperBas { if (UK2Node_EnumLiteral* LiteralEnumNode = Cast(K2Node)) { - UEnum* Enum = LiteralEnumNode ? LiteralEnumNode->Enum : nullptr; + UEnum* Enum = LiteralEnumNode->Enum; IncludeTheHeaderInBody(Enum); } // HACK FOR LITERAL ENUMS: @@ -290,7 +344,7 @@ struct FFindHeadersToInclude : public FGatherConvertedClassDependenciesHelperBas { IncludeTheHeaderInBody(ObjAsField); } - else if (BPGC) + else { IncludeTheHeaderInBody(Dependencies.GetFirstNativeOrConvertedClass(BPGC)); // Wrappers for unconverted BP will be included only when thay are directly used. See usage of FEmitterLocalContext::MarkUnconvertedClassAsNecessary. @@ -374,12 +428,12 @@ FGatherConvertedClassDependencies::FGatherConvertedClassDependencies(UStruct* In TSet FieldsToAdd; for (auto Iter = FieldSet.CreateIterator(); Iter; ++Iter) { - UClass* CurrentClass = (*Iter) ? (*Iter)->GetOwnerClass() : nullptr; - UBlueprint* CurrentBP = CurrentClass ? Cast(CurrentClass->ClassGeneratedBy) : nullptr; - if (CurrentBP && FBlueprintEditorUtils::IsDataOnlyBlueprint(CurrentBP)) + const UClass* CurrentClass = (*Iter) ? (*Iter)->GetOwnerClass() : nullptr; + const UBlueprint* CurrentBP = CurrentClass ? Cast(CurrentClass->ClassGeneratedBy) : nullptr; + if (CurrentBP && FBlueprintEditorUtils::IsDataOnlyBlueprint(CurrentBP) && !WillClassBeConverted(Cast(CurrentClass))) { Iter.RemoveCurrent(); - FieldsToAdd.Add(GetFirstNativeOrConvertedClass(CurrentClass, true)); + FieldsToAdd.Add(GetFirstNativeOrConvertedClass(CurrentClass->GetSuperClass())); } } @@ -424,7 +478,7 @@ FGatherConvertedClassDependencies::FGatherConvertedClassDependencies(UStruct* In GatherRequiredModules(IncludeInBody); } -UClass* FGatherConvertedClassDependencies::GetFirstNativeOrConvertedClass(UClass* InClass, bool bExcludeBPDataOnly) const +UClass* FGatherConvertedClassDependencies::GetFirstNativeOrConvertedClass(UClass* InClass) const { check(InClass); for (UClass* ItClass = InClass; ItClass; ItClass = ItClass->GetSuperClass()) @@ -432,14 +486,6 @@ UClass* FGatherConvertedClassDependencies::GetFirstNativeOrConvertedClass(UClass UBlueprintGeneratedClass* BPGC = Cast(ItClass); if (ItClass->HasAnyClassFlags(CLASS_Native) || WillClassBeConverted(BPGC)) { - if (bExcludeBPDataOnly) - { - UBlueprint* BP = BPGC ? Cast(BPGC->ClassGeneratedBy) : nullptr; - if (BP && FBlueprintEditorUtils::IsDataOnlyBlueprint(BP)) - { - continue; - } - } return ItClass; } } @@ -591,9 +637,14 @@ void FGatherConvertedClassDependencies::DependenciesForHeader() for (TFieldIterator PropertyIt(UDS); PropertyIt; ++PropertyIt) { UObject* DefaultValueObject = ((UObjectPropertyBase*)*PropertyIt)->GetObjectPropertyValue_InContainer(StructOnScope.GetStructMemory()); - UField* ObjAsField = Cast(DefaultValueObject); - UField* FieldForHeader = ObjAsField ? ObjAsField : (DefaultValueObject ? DefaultValueObject->GetClass() : nullptr); - IncludeInHeader.Add(FieldForHeader); + if (ShouldIncludeHeaderFor(DefaultValueObject)) + { + UField* ObjAsField = Cast(DefaultValueObject); + if (UField* FieldForHeader = ObjAsField ? ObjAsField : (DefaultValueObject ? DefaultValueObject->GetClass() : nullptr)) + { + DeclareInHeader.Add(FieldForHeader); + } + } } } diff --git a/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendModule.cpp b/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendModule.cpp index 09c08f743a90..48883e5f0a82 100644 --- a/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendModule.cpp +++ b/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendModule.cpp @@ -14,7 +14,7 @@ public: //~ End IBlueprintCompilerCppBackendModuleInterface interface //~ Begin IBlueprintCompilerCppBackendModule interface - virtual FString ConstructBaseFilename(const UObject* AssetObj) override; + virtual FString ConstructBaseFilename(const UObject* AssetObj, const FCompilerNativizationOptions& NativizationOptions) override; virtual FPCHFilenameQuery& OnPCHFilenameQuery() override; virtual FIsTargetedForConversionQuery& OnIsTargetedForConversionQuery() override; virtual TMap, TWeakObjectPtr >& GetOriginalClassMap() override; @@ -44,10 +44,10 @@ TSharedPtr& FBlueprintCompilerCppBackendModule::Nativizati return NativizationSummaryPtr; } -FString FBlueprintCompilerCppBackendModule::ConstructBaseFilename(const UObject* AssetObj) +FString FBlueprintCompilerCppBackendModule::ConstructBaseFilename(const UObject* AssetObj, const FCompilerNativizationOptions& NativizationOptions) { // use the same function that the backend uses for #includes - return FEmitHelper::GetBaseFilename(AssetObj); + return FEmitHelper::GetBaseFilename(AssetObj, NativizationOptions); } IBlueprintCompilerCppBackendModule::FPCHFilenameQuery& FBlueprintCompilerCppBackendModule::OnPCHFilenameQuery() diff --git a/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendUMG.cpp b/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendUMG.cpp index c090cf3231cc..cf9df6592e63 100644 --- a/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendUMG.cpp +++ b/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendUMG.cpp @@ -94,7 +94,7 @@ void FBackendHelperUMG::EmitWidgetInitializationFunctions(FEmitterLocalContext& const FString AnimationsArrayNativeName = GenerateLocalProperty(Context, FindFieldChecked(UWidgetBlueprintGeneratedClass::StaticClass(), TEXT("Animations")), reinterpret_cast(&WidgetClass->Animations)); const FString BindingsArrayNativeName = GenerateLocalProperty(Context, FindFieldChecked(UWidgetBlueprintGeneratedClass::StaticClass(), TEXT("Bindings")), reinterpret_cast(&WidgetClass->Bindings)); - Context.AddLine(FString::Printf(TEXT("UWidgetBlueprintGeneratedClass::%s(this, GetClass(), %s, %s, %s, %s, %s);") + Context.AddLine(FString::Printf(TEXT("UWidgetBlueprintGeneratedClass::%s(this, GetClass(), %s, %s, %s, %s);") , GET_FUNCTION_NAME_STRING_CHECKED(UWidgetBlueprintGeneratedClass, InitializeWidgetStatic) , WidgetClass->CanTemplate() ? TEXT("true") : TEXT("false") , *WidgetTreeStr diff --git a/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendUtils.cpp b/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendUtils.cpp index aaf1e447083a..3a3ec31f9059 100644 --- a/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendUtils.cpp +++ b/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendUtils.cpp @@ -44,6 +44,9 @@ FString FEmitterLocalContext::FindGloballyMappedObject(const UObject* Object, co UClass* OriginalActualClass = Dependencies.FindOriginalClass(ActualClass); UClass* OuterClass = Object ? Cast(Object->GetOuter()) : nullptr; // SCS component templates will have an Outer that equates to their owning BPGC; since they're not currently DSOs, we have to special-case them. + // The UsedAssets list is only applicable to UClass derivatives. + bTryUsedAssetsList &= (ActualClass != nullptr); + auto ClassString = [&]() -> FString { const UClass* ObjectClassToUse = ExpectedClass ? ExpectedClass : GetFirstNativeOrConvertedClass(Object->GetClass()); @@ -81,7 +84,7 @@ FString FEmitterLocalContext::FindGloballyMappedObject(const UObject* Object, co , ObjectsCreatedPerClassIdx); } - ObjectsCreatedPerClassIdx = ObjectsCreatedPerClassIdx = DynamicBindingObjects.IndexOfByKey(Object); + ObjectsCreatedPerClassIdx = DynamicBindingObjects.IndexOfByKey(Object); if (INDEX_NONE != ObjectsCreatedPerClassIdx) { return FString::Printf(TEXT("CastChecked<%s>(CastChecked(%s::StaticClass())->%s[%d])") @@ -291,7 +294,7 @@ FString FEmitterLocalContext::ExportCppDeclaration(const UProperty* Property, EE ExportCPPFlags = (ExportCPPFlags & ~CPPF_ArgumentOrReturnValue); } - if (auto ClassProperty = Cast(Property)) + if (const UClassProperty* ClassProperty = Cast(Property)) { GetActualNameCPP(ClassProperty, ClassProperty->MetaClass); } @@ -345,7 +348,7 @@ FString FEmitterLocalContext::ExportCppDeclaration(const UProperty* Property, EE FStringOutputDevice Out; const bool bSkipParameterName = (ParameterName == EPropertyNameInDeclaration::Skip); const FString ActualNativeName = bSkipParameterName ? FString() : (FEmitHelper::GetCppName(Property, false, ParameterName == EPropertyNameInDeclaration::ForceConverted) + NamePostfix); - Property->ExportCppDeclaration(Out, DeclarationType, nullptr, InExportCPPFlags, bSkipParameterName, ActualCppTypePtr, ActualExtendedTypePtr, &ActualNativeName); + Property->ExportCppDeclaration(Out, DeclarationType, nullptr, ExportCPPFlags, bSkipParameterName, ActualCppTypePtr, ActualExtendedTypePtr, &ActualNativeName); return FString(Out); } @@ -764,7 +767,7 @@ FString FEmitHelper::GenerateReplaceConvertedMD(UObject* Obj) return Result; } -FString FEmitHelper::GetBaseFilename(const UObject* AssetObj) +FString FEmitHelper::GetBaseFilename(const UObject* AssetObj, const FCompilerNativizationOptions& NativizationOptions) { FString AssetName = FPackageName::GetLongPackageAssetName(AssetObj->GetOutermost()->GetPathName()); // We have to sanitize the package path because UHT is going to generate header guards (preprocessor symbols) @@ -1151,13 +1154,13 @@ FString FEmitHelper::LiteralTerm(FEmitterLocalContext& EmitterContext, const FEd MetaClass = MetaClass ? MetaClass : UObject::StaticClass(); const FString ObjTypeStr = FEmitHelper::GetCppName(EmitterContext.GetFirstNativeOrConvertedClass(MetaClass)); - if (LiteralObject) + if (!CustomValue.IsEmpty()) { const bool bAssetSubclassOf = (UEdGraphSchema_K2::PC_AssetClass == Type.PinCategory); return FString::Printf(TEXT("%s<%s>(FStringAssetReference(TEXT(\"%s\")))") , bAssetSubclassOf ? TEXT("TAssetSubclassOf") : TEXT("TAssetPtr") , *ObjTypeStr - , *(LiteralObject->GetPathName().ReplaceCharWithEscapedChar())); + , *(CustomValue.ReplaceCharWithEscapedChar())); } return FString::Printf(TEXT("((%s*)nullptr)"), *ObjTypeStr); } @@ -1236,10 +1239,6 @@ FString FEmitHelper::PinTypeToNativeType(const FEdGraphPinType& Type) { return TEXT("float"); } - else if (UEdGraphSchema_K2::PC_Float == InType.PinCategory) - { - return TEXT("float"); - } else if (UEdGraphSchema_K2::PC_Name == InType.PinCategory) { return TEXT("FName"); @@ -1295,7 +1294,8 @@ FString FEmitHelper::PinTypeToNativeType(const FEdGraphPinType& Type) }; FString InnerTypeName = PinTypeToNativeTypeInner(Type); - return Type.bIsArray ? FString::Printf(TEXT("TArray<%s>"), *InnerTypeName) : InnerTypeName; + ensure(!Type.IsSet() && !Type.IsMap()); + return Type.IsArray() ? FString::Printf(TEXT("TArray<%s>"), *InnerTypeName) : InnerTypeName; } UFunction* FEmitHelper::GetOriginalFunction(UFunction* Function) @@ -1352,77 +1352,147 @@ bool FEmitHelper::ShouldHandleAsImplementableEvent(UFunction* Function) return false; } -bool FEmitHelper::GenerateAutomaticCast(FEmitterLocalContext& EmitterContext, const FEdGraphPinType& LType, const FEdGraphPinType& RType, FString& OutCastBegin, FString& OutCastEnd, bool bForceReference) +bool FEmitHelper::GenerateAutomaticCast(FEmitterLocalContext& EmitterContext, const FEdGraphPinType& LType, const FEdGraphPinType& RType, const UProperty* LProp, const UProperty* RProp, FString& OutCastBegin, FString& OutCastEnd, bool bForceReference) { - if ((RType.bIsArray != LType.bIsArray) || (LType.PinCategory != RType.PinCategory)) + if ((RType.ContainerType != LType.ContainerType) || (LType.PinCategory != RType.PinCategory)) { return false; } // BYTE to ENUM cast // ENUM to BYTE cast - if ((LType.PinCategory == UEdGraphSchema_K2::PC_Byte) && !RType.bIsArray) + if (LType.PinCategory == UEdGraphSchema_K2::PC_Byte) { - auto LTypeEnum = Cast(LType.PinSubCategoryObject.Get()); - auto RTypeEnum = Cast(RType.PinSubCategoryObject.Get()); - if (!RTypeEnum && LTypeEnum) + if (!RType.IsContainer()) { - ensure(!LTypeEnum->IsA() || LTypeEnum->CppType.IsEmpty()); - const FString EnumCppType = !LTypeEnum->CppType.IsEmpty() ? LTypeEnum->CppType : FEmitHelper::GetCppName(LTypeEnum); - OutCastBegin = bForceReference - ? FString::Printf(TEXT("*(%s*)(&("), *EnumCppType) - : FString::Printf(TEXT("static_cast<%s>("), *EnumCppType); - OutCastEnd = bForceReference ? TEXT("))") : TEXT(")"); - return true; - } - if (!LTypeEnum && RTypeEnum) - { - ensure(!RTypeEnum->IsA() || RTypeEnum->CppType.IsEmpty()); - const FString EnumCppType = !RTypeEnum->CppType.IsEmpty() ? RTypeEnum->CppType : FEmitHelper::GetCppName(RTypeEnum); - - if (bForceReference) + UEnum* LTypeEnum = Cast(LType.PinSubCategoryObject.Get()); + UEnum* RTypeEnum = Cast(RType.PinSubCategoryObject.Get()); + if (!RTypeEnum && LTypeEnum) { - OutCastBegin = TEXT("*static_cast(&("); + ensure(!LTypeEnum->IsA() || LTypeEnum->CppType.IsEmpty()); + const FString EnumCppType = !LTypeEnum->CppType.IsEmpty() ? LTypeEnum->CppType : FEmitHelper::GetCppName(LTypeEnum); + OutCastBegin = bForceReference + ? FString::Printf(TEXT("*(%s*)(&("), *EnumCppType) + : FString::Printf(TEXT("static_cast<%s>("), *EnumCppType); + OutCastEnd = bForceReference ? TEXT("))") : TEXT(")"); + return true; + } + if (!LTypeEnum && RTypeEnum) + { + ensure(!RTypeEnum->IsA() || RTypeEnum->CppType.IsEmpty()); + const FString EnumCppType = !RTypeEnum->CppType.IsEmpty() ? RTypeEnum->CppType : FEmitHelper::GetCppName(RTypeEnum); + + if (bForceReference) + { + OutCastBegin = TEXT("*static_cast(&("); + OutCastEnd = TEXT("))"); + } + else + { + OutCastBegin = TEXT("static_cast("); + OutCastEnd = TEXT(")"); + } + + return true; + } + } + } + else // UObject casts (UClass, etc.) + { + auto GetClassType = [&EmitterContext](const FEdGraphPinType& PinType)->UClass* + { + UClass* TypeClass = EmitterContext.Dependencies.FindOriginalClass(Cast(PinType.PinSubCategoryObject.Get())); + return TypeClass ? EmitterContext.GetFirstNativeOrConvertedClass(TypeClass) : nullptr; + }; + + auto RequiresArrayCast = [&RType](UClass* LClass, UClass* RClass)->bool + { + return RType.IsArray() && LClass && RClass && (LClass->IsChildOf(RClass) || RClass->IsChildOf(LClass)) && (LClass != RClass); + }; + + const bool bIsClassTerm = LType.PinCategory == UEdGraphSchema_K2::PC_Class; + auto GetTypeString = [bIsClassTerm](UClass* TermType, const UObjectProperty* AssociatedProperty)->FString + { + // favor the property's CPPType since it makes choices based off of things like CPF_UObjectWrapper (which + // adds things like TSubclassof<> to the decl)... however, if the property type doesn't match the term + // type, then ignore the property (this can happen for things like our array library, which uses wildcards + // and custom thunks to allow differing types) + const bool bPropertyMatch = AssociatedProperty && ((AssociatedProperty->PropertyClass == TermType) || + (bIsClassTerm && CastChecked(AssociatedProperty)->MetaClass == TermType)); + + if (bPropertyMatch) + { + // use GetCPPTypeCustom() so that it properly fills out nativized class names + return AssociatedProperty->GetCPPTypeCustom(/*ExtendedTypeText=*/nullptr, CPPF_None, FEmitHelper::GetCppName(TermType)); + } + else if (bIsClassTerm) + { + return TEXT("UClass*"); + } + return FEmitHelper::GetCppName(TermType) + TEXT("*"); + }; + + auto GetInnerTypeString = [GetTypeString](UClass* TermType, const UArrayProperty* ArrayProp) + { + const UObjectProperty* InnerProp = ArrayProp ? Cast(ArrayProp->Inner) : nullptr; + return GetTypeString(TermType, InnerProp); + }; + + auto GenerateArrayCast = [&OutCastBegin, &OutCastEnd](const FString& LTypeStr, const FString& RTypeStr) + { + OutCastBegin = FString::Printf(TEXT("TArrayCaster< %s >("), *RTypeStr); + OutCastEnd = FString::Printf(TEXT(").Get< %s >()"), *LTypeStr); + }; + // CLASS/TSubClassOf<> to CLASS/TSubClassOf<> + if (bIsClassTerm) + { + UClass* LClass = GetClassType(LType); + UClass* RClass = GetClassType(RType); + // it seems that we only need to cast class types when they're in arrays (TSubClassOf<> + // has built in conversions to/from other TSubClassOfs and raw UClasses) + if (RType.IsArray()) + { + const UArrayProperty* LArrayProp = Cast(LProp); + const UClassProperty* LInnerProp = LArrayProp ? Cast(LArrayProp->Inner) : nullptr; + const UArrayProperty* RArrayProp = Cast(RProp); + const UClassProperty* RInnerProp = RArrayProp ? Cast(RArrayProp->Inner) : nullptr; + + const bool bLHasWrapper = LInnerProp ? LInnerProp->HasAnyPropertyFlags(CPF_UObjectWrapper) : false; + const bool bRHasWrapper = RInnerProp ? RInnerProp->HasAnyPropertyFlags(CPF_UObjectWrapper) : false; + // if neither has a TSubClass<> wrapper, then they'll both be declared as a UClass*, and a cast is uneeded + if ((bLHasWrapper != bRHasWrapper) || (bLHasWrapper && RequiresArrayCast(LClass, RClass))) + { + GenerateArrayCast(GetTypeString(LClass, LInnerProp), GetTypeString(RClass, RInnerProp)); + return true; + } + } + } + // OBJECT to OBJECT + else if (LType.PinCategory == UEdGraphSchema_K2::PC_Object) + { + UClass* LClass = GetClassType(LType); + UClass* RClass = GetClassType(RType); + + if (!RType.IsContainer() && LClass && RClass && (LType.bIsReference || bForceReference) && (LClass != RClass) && RClass->IsChildOf(LClass)) + { + // when pointer is passed as reference, the type must be exactly the same + OutCastBegin = FString::Printf(TEXT("*(%s*)(&("), *GetTypeString(LClass, Cast(LProp))); OutCastEnd = TEXT("))"); + return true; } - else + if (!RType.IsContainer() && LClass && RClass && LClass->IsChildOf(RClass) && !RClass->IsChildOf(LClass)) { - OutCastBegin = TEXT("static_cast("); - OutCastEnd = TEXT(")"); + OutCastBegin = FString::Printf(TEXT("CastChecked<%s>("), *FEmitHelper::GetCppName(LClass)); + OutCastEnd = TEXT(", ECastCheckedType::NullAllowed)"); + return true; + } + else if (RequiresArrayCast(LClass, RClass)) + { + GenerateArrayCast(GetInnerTypeString(LClass, Cast(LProp)), GetInnerTypeString(RClass, Cast(RProp))); + return true; } - - return true; } } - - // OBJECT to OBJECT - if (LType.PinCategory == UEdGraphSchema_K2::PC_Object) - { - UClass* LClass = EmitterContext.Dependencies.FindOriginalClass( Cast(LType.PinSubCategoryObject.Get()) ); - LClass = LClass ? EmitterContext.GetFirstNativeOrConvertedClass(LClass) : nullptr; - UClass* RClass = EmitterContext.Dependencies.FindOriginalClass( Cast(RType.PinSubCategoryObject.Get()) ); - RClass = RClass ? EmitterContext.GetFirstNativeOrConvertedClass(RClass) : nullptr; - if (!RType.bIsArray && LClass && RClass && (LType.bIsReference || bForceReference) && (LClass != RClass) && RClass->IsChildOf(LClass)) - { - // when pointer is passed as reference, the type must be exactly the same - OutCastBegin = FString::Printf(TEXT("*(%s**)(&("), *FEmitHelper::GetCppName(LClass)); - OutCastEnd = TEXT("))"); - return true; - } - if (!RType.bIsArray && LClass && RClass && LClass->IsChildOf(RClass) && !RClass->IsChildOf(LClass)) - { - OutCastBegin = FString::Printf(TEXT("CastChecked<%s>("), *FEmitHelper::GetCppName(LClass)); - OutCastEnd = TEXT(", ECastCheckedType::NullAllowed)"); - return true; - } - else if (RType.bIsArray && LClass && RClass && (LClass->IsChildOf(RClass) || RClass->IsChildOf(LClass)) && (LClass != RClass)) - { - OutCastBegin = FString::Printf(TEXT("TArrayCaster<%s*>("), *FEmitHelper::GetCppName(RClass)); - OutCastEnd = FString::Printf(TEXT(").Get<%s*>()"), *FEmitHelper::GetCppName(LClass)); - return true; - } - } - return false; } diff --git a/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendUtils.h b/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendUtils.h index a2d8108a412a..32a9aca2490a 100644 --- a/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendUtils.h +++ b/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendUtils.h @@ -296,11 +296,11 @@ struct FEmitHelper static bool ShouldHandleAsImplementableEvent(UFunction* Function); - static bool GenerateAutomaticCast(FEmitterLocalContext& EmitterContext, const FEdGraphPinType& LType, const FEdGraphPinType& RType, FString& OutCastBegin, FString& OutCastEnd, bool bForceReference = false); + static bool GenerateAutomaticCast(FEmitterLocalContext& EmitterContext, const FEdGraphPinType& LType, const FEdGraphPinType& RType, const UProperty* LProp, const UProperty* RProp, FString& OutCastBegin, FString& OutCastEnd, bool bForceReference = false); static FString GenerateReplaceConvertedMD(UObject* Obj); - static FString GetBaseFilename(const UObject* AssetObj); + static FString GetBaseFilename(const UObject* AssetObj, const FCompilerNativizationOptions& NativizationOptions); static FString ReplaceConvertedMetaData(UObject* Obj); diff --git a/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendValueHelper.cpp b/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendValueHelper.cpp index 1b60f391edac..a49b55f93589 100644 --- a/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendValueHelper.cpp +++ b/Engine/Source/Developer/BlueprintCompilerCppBackend/Private/BlueprintCompilerCppBackendValueHelper.cpp @@ -179,14 +179,19 @@ void FEmitDefaultValueHelper::GenerateGetDefaultValue(const UUserDefinedStruct* { check(Struct); const FString StructName = FEmitHelper::GetCppName(Struct); - Context.Header.AddLine(FString::Printf(TEXT("static %s GetDefaultValue()"), *StructName)); - Context.Header.AddLine(TEXT("{")); - Context.Header.IncreaseIndent(); - Context.Header.AddLine(FString::Printf(TEXT("FStructOnScope StructOnScope(%s::StaticStruct());"), *StructName)); - Context.Header.AddLine(FString::Printf(TEXT("%s& DefaultData__ = *((%s*)StructOnScope.GetStructMemory());"), *StructName, *StructName)); + // Declaration + Context.Header.AddLine(FString::Printf(TEXT("static %s GetDefaultValue();"), *StructName)); + + // Definition + Context.Body.AddLine(FString::Printf(TEXT("%s %s::GetDefaultValue()"), *StructName, *StructName)); + Context.Body.AddLine(TEXT("{")); + + Context.Body.IncreaseIndent(); + Context.Body.AddLine(FString::Printf(TEXT("FStructOnScope StructOnScope(%s::StaticStruct());"), *StructName)); + Context.Body.AddLine(FString::Printf(TEXT("%s& DefaultData__ = *((%s*)StructOnScope.GetStructMemory());"), *StructName, *StructName)); { - TGuardValue OriginalDefaultTarget(Context.DefaultTarget, &Context.Header); + TGuardValue OriginalDefaultTarget(Context.DefaultTarget, &Context.Body); FStructOnScope StructData(Struct); FStructureEditorUtils::Fill_MakeStructureDefaultValue(Struct, StructData.GetStructMemory()); FStructOnScope RawDefaultStructOnScope(Struct); @@ -195,10 +200,10 @@ void FEmitDefaultValueHelper::GenerateGetDefaultValue(const UUserDefinedStruct* OuterGenerate(Context, Property, TEXT("DefaultData__"), StructData.GetStructMemory(), RawDefaultStructOnScope.GetStructMemory(), EPropertyAccessOperator::Dot); } } - Context.Header.AddLine(TEXT("return DefaultData__;")); - Context.Header.DecreaseIndent(); + Context.Body.AddLine(TEXT("return DefaultData__;")); + Context.Body.DecreaseIndent(); - Context.Header.AddLine(TEXT("}")); + Context.Body.AddLine(TEXT("}")); } void FEmitDefaultValueHelper::InnerGenerate(FEmitterLocalContext& Context, const UProperty* Property, const FString& PathToMember, const uint8* ValuePtr, const uint8* DefaultValuePtr, bool bWithoutFirstConstructionLine) @@ -1124,6 +1129,7 @@ struct FFakeImportTableHelper if (Subobject) { SerializeBeforeCreateCDODependencies.Add(Subobject->GetClass()); + SerializeBeforeCreateCDODependencies.Add(Subobject->GetClass()->GetDefaultObject()); } } }; @@ -1545,12 +1551,6 @@ void FEmitDefaultValueHelper::GenerateCustomDynamicClassInitialization(FEmitterL Context.AddLine(FString::Printf(TEXT("InDynamicClass->%s.Add(%s);"), GET_MEMBER_NAME_STRING_CHECKED(UDynamicClass, ReferencedConvertedFields), *StructConstructor)); } - ensure(0 == Context.MiscConvertedSubobjects.Num()); - for (UObject* LocalTemplate : Context.TemplateFromSubobjectsOfClass) - { - HandleClassSubobject(Context, LocalTemplate, FEmitterLocalContext::EClassSubobjectList::MiscConvertedSubobjects, true, true, true); - } - TArray ActorComponentTempatesOwnedByClass = BPGC->ComponentTemplates; // Gather all CT from SCS and IH, the remaining ones are generated for class.. if (auto SCS = BPGC->SimpleConstructionScript) @@ -1581,6 +1581,12 @@ void FEmitDefaultValueHelper::GenerateCustomDynamicClassInitialization(FEmitterL Context.AddLine(TEXT("FConvertedBlueprintsDependencies::FillUsedAssetsInDynamicClass(InDynamicClass, &__StaticDependencies_DirectlyUsedAssets);")); + ensure(0 == Context.MiscConvertedSubobjects.Num()); + for (UObject* LocalTemplate : Context.TemplateFromSubobjectsOfClass) + { + HandleClassSubobject(Context, LocalTemplate, FEmitterLocalContext::EClassSubobjectList::MiscConvertedSubobjects, true, true, true); + } + auto CreateAndInitializeClassSubobjects = [&](bool bCreate, bool bInitialize) { for (auto ComponentTemplate : ActorComponentTempatesOwnedByClass) diff --git a/Engine/Source/Developer/BlueprintCompilerCppBackend/Public/BlueprintCompilerCppBackendGatherDependencies.h b/Engine/Source/Developer/BlueprintCompilerCppBackend/Public/BlueprintCompilerCppBackendGatherDependencies.h index 9f56316ea661..9da7834a65a9 100644 --- a/Engine/Source/Developer/BlueprintCompilerCppBackend/Public/BlueprintCompilerCppBackendGatherDependencies.h +++ b/Engine/Source/Developer/BlueprintCompilerCppBackend/Public/BlueprintCompilerCppBackendGatherDependencies.h @@ -43,7 +43,7 @@ public: UClass* FindOriginalClass(const UClass* InClass) const; - UClass* GetFirstNativeOrConvertedClass(UClass* InClass, bool bExcludeBPDataOnly = false) const; + UClass* GetFirstNativeOrConvertedClass(UClass* InClass) const; TSet AllDependencies() const; diff --git a/Engine/Source/Developer/BlueprintCompilerCppBackend/Public/IBlueprintCompilerCppBackendModule.h b/Engine/Source/Developer/BlueprintCompilerCppBackend/Public/IBlueprintCompilerCppBackendModule.h index a5b624602be0..ac9d24b90567 100644 --- a/Engine/Source/Developer/BlueprintCompilerCppBackend/Public/IBlueprintCompilerCppBackendModule.h +++ b/Engine/Source/Developer/BlueprintCompilerCppBackend/Public/IBlueprintCompilerCppBackendModule.h @@ -61,7 +61,7 @@ public: * @param AssetObj The asset you want a source-file name for. * @return The filename (without an extension) for the target asset. */ - virtual FString ConstructBaseFilename(const UObject* AssetObj) = 0; + virtual FString ConstructBaseFilename(const UObject* AssetObj, const FCompilerNativizationOptions& NativizationOptions) = 0; DECLARE_DELEGATE_RetVal(FString, FPCHFilenameQuery); diff --git a/Engine/Source/Developer/BlueprintNativeCodeGen/Private/BlueprintNativeCodeGenManifest.cpp b/Engine/Source/Developer/BlueprintNativeCodeGen/Private/BlueprintNativeCodeGenManifest.cpp index efe6f07fd076..77e114319eda 100644 --- a/Engine/Source/Developer/BlueprintNativeCodeGen/Private/BlueprintNativeCodeGenManifest.cpp +++ b/Engine/Source/Developer/BlueprintNativeCodeGen/Private/BlueprintNativeCodeGenManifest.cpp @@ -81,7 +81,7 @@ namespace BlueprintNativeCodeGenManifestImpl * @param SourceType Defines the type of source file to generate for (header or cpp). * @return A target file path for the specified asset to save a header to. */ - static FString GenerateSourceFileSavePath(const FBlueprintNativeCodeGenPaths& TargetPaths, const FAssetData& Asset, const FBlueprintNativeCodeGenPaths::ESourceFileType SourceType); + static FString GenerateSourceFileSavePath(const FBlueprintNativeCodeGenPaths& TargetPaths, const FAssetData& Asset, const FCompilerNativizationOptions& NativizationOptions, const FBlueprintNativeCodeGenPaths::ESourceFileType SourceType); /** * @@ -90,7 +90,7 @@ namespace BlueprintNativeCodeGenManifestImpl * @param Asset * @return */ - static FString GenerateUnconvertedWrapperPath(const FBlueprintNativeCodeGenPaths& TargetPaths, const FAssetData& Asset); + static FString GenerateUnconvertedWrapperPath(const FBlueprintNativeCodeGenPaths& TargetPaths, const FAssetData& Asset, const FCompilerNativizationOptions& NativizationOptions); /** * Coordinates with the code-gen backend, to produce a base filename (one @@ -99,7 +99,7 @@ namespace BlueprintNativeCodeGenManifestImpl * @param Asset The asset you want a filename for. * @return A filename (without extension) that matches the #include statements generated by the backend. */ - static FString GetBaseFilename(const FAssetData& Asset); + static FString GetBaseFilename(const FAssetData& Asset, const FCompilerNativizationOptions& NativizationOptions); /** * Collects native packages (which reflect distinct modules) that the @@ -173,23 +173,23 @@ static const FString& BlueprintNativeCodeGenManifestImpl::GetSourceFileExt(const } //------------------------------------------------------------------------------ -static FString BlueprintNativeCodeGenManifestImpl::GenerateSourceFileSavePath(const FBlueprintNativeCodeGenPaths& TargetPaths, const FAssetData& Asset, const FBlueprintNativeCodeGenPaths::ESourceFileType SourceType) +static FString BlueprintNativeCodeGenManifestImpl::GenerateSourceFileSavePath(const FBlueprintNativeCodeGenPaths& TargetPaths, const FAssetData& Asset, const FCompilerNativizationOptions& NativizationOptions, const FBlueprintNativeCodeGenPaths::ESourceFileType SourceType) { - return FPaths::Combine(*TargetPaths.RuntimeSourceDir(SourceType), *GetBaseFilename(Asset)) + GetSourceFileExt(SourceType); + return FPaths::Combine(*TargetPaths.RuntimeSourceDir(SourceType), *GetBaseFilename(Asset, NativizationOptions)) + GetSourceFileExt(SourceType); } //------------------------------------------------------------------------------ -static FString BlueprintNativeCodeGenManifestImpl::GenerateUnconvertedWrapperPath(const FBlueprintNativeCodeGenPaths& TargetPaths, const FAssetData& Asset) +static FString BlueprintNativeCodeGenManifestImpl::GenerateUnconvertedWrapperPath(const FBlueprintNativeCodeGenPaths& TargetPaths, const FAssetData& Asset, const FCompilerNativizationOptions& NativizationOptions) { const FBlueprintNativeCodeGenPaths::ESourceFileType WrapperFileType = FBlueprintNativeCodeGenPaths::HFile; - return FPaths::Combine(*TargetPaths.RuntimeSourceDir(WrapperFileType), *GetBaseFilename(Asset)) + GetSourceFileExt(WrapperFileType); + return FPaths::Combine(*TargetPaths.RuntimeSourceDir(WrapperFileType), *GetBaseFilename(Asset, NativizationOptions)) + GetSourceFileExt(WrapperFileType); } //------------------------------------------------------------------------------ -static FString BlueprintNativeCodeGenManifestImpl::GetBaseFilename(const FAssetData& Asset) +static FString BlueprintNativeCodeGenManifestImpl::GetBaseFilename(const FAssetData& Asset, const FCompilerNativizationOptions& NativizationOptions) { IBlueprintCompilerCppBackendModule& CodeGenBackend = (IBlueprintCompilerCppBackendModule&)IBlueprintCompilerCppBackendModule::Get(); - return CodeGenBackend.ConstructBaseFilename(Asset.GetAsset()); + return CodeGenBackend.ConstructBaseFilename(Asset.GetAsset(), NativizationOptions); } //------------------------------------------------------------------------------ @@ -292,12 +292,12 @@ static FString BlueprintNativeCodeGenManifestImpl::GetTargetObjectPath(const FAs ******************************************************************************/ //------------------------------------------------------------------------------ -FConvertedAssetRecord::FConvertedAssetRecord(const FAssetData& AssetInfo, const FBlueprintNativeCodeGenPaths& TargetPaths) +FConvertedAssetRecord::FConvertedAssetRecord(const FAssetData& AssetInfo, const FBlueprintNativeCodeGenPaths& TargetPaths, const FCompilerNativizationOptions& NativizationOptions) : AssetType(AssetInfo.GetClass()) , TargetObjPath(BlueprintNativeCodeGenManifestImpl::GetTargetObjectPath(AssetInfo)) { - GeneratedCppPath = BlueprintNativeCodeGenManifestImpl::GenerateSourceFileSavePath(TargetPaths, AssetInfo, FBlueprintNativeCodeGenPaths::CppFile); - GeneratedHeaderPath = BlueprintNativeCodeGenManifestImpl::GenerateSourceFileSavePath(TargetPaths, AssetInfo, FBlueprintNativeCodeGenPaths::HFile); + GeneratedCppPath = BlueprintNativeCodeGenManifestImpl::GenerateSourceFileSavePath(TargetPaths, AssetInfo, NativizationOptions, FBlueprintNativeCodeGenPaths::CppFile); + GeneratedHeaderPath = BlueprintNativeCodeGenManifestImpl::GenerateSourceFileSavePath(TargetPaths, AssetInfo, NativizationOptions, FBlueprintNativeCodeGenPaths::HFile); } //------------------------------------------------------------------------------ @@ -323,6 +323,8 @@ FUnconvertedDependencyRecord::FUnconvertedDependencyRecord(const FString& InGene //------------------------------------------------------------------------------ FBlueprintNativeCodeGenPaths FBlueprintNativeCodeGenPaths::GetDefaultCodeGenPaths(const FName PlatformName) { + // NOTE: in UProjectPackagingSettings::PostEditChangeProperty() there are a hardcoded file path/name that are set to match these; + // if you alter these defaults then you need to update that and likely AddBlueprintPluginPathArgument() in UAT as well FString DefaultPluginName = TEXT("NativizedAssets"); FString DefaultPluginDir = FPaths::Combine(*FPaths::Combine(*FPaths::GameIntermediateDir(), TEXT("Plugins")), *DefaultPluginName); return FBlueprintNativeCodeGenPaths(DefaultPluginName, DefaultPluginDir, PlatformName); @@ -431,7 +433,8 @@ FString FBlueprintNativeCodeGenPaths::RuntimeSourceDir(ESourceFileType SourceTyp //------------------------------------------------------------------------------ FString FBlueprintNativeCodeGenPaths::RuntimeModuleFile(ESourceFileType SourceType) const { - return FPaths::Combine(*RuntimeSourceDir(SourceType), *RuntimeModuleName()) + BlueprintNativeCodeGenManifestImpl::GetSourceFileExt(SourceType); + // use the "cpp" (private) directory for the header too (which acts as a PCH) + return FPaths::Combine(*RuntimeSourceDir(ESourceFileType::CppFile), *RuntimeModuleName()) + BlueprintNativeCodeGenManifestImpl::GetSourceFileExt(SourceType); } //------------------------------------------------------------------------------ @@ -495,7 +498,7 @@ FConvertedAssetRecord& FBlueprintNativeCodeGenManifest::CreateConversionRecord(c UClass* AssetType = AssetInfo.GetClass(); // load the asset (if it isn't already) const UObject* AssetObj = AssetInfo.GetAsset(); - FConvertedAssetRecord* ConversionRecord = &ConvertedAssets.Add(Key, FConvertedAssetRecord(AssetInfo, TargetPaths)); + FConvertedAssetRecord* ConversionRecord = &ConvertedAssets.Add(Key, FConvertedAssetRecord(AssetInfo, TargetPaths, NativizationOptions)); return *ConversionRecord; } @@ -511,7 +514,7 @@ FUnconvertedDependencyRecord& FBlueprintNativeCodeGenManifest::CreateUnconverted } const FBlueprintNativeCodeGenPaths TargetPaths = GetTargetPaths(); - FUnconvertedDependencyRecord* RecordPtr = &UnconvertedDependencies.Add(UnconvertedAssetKey, FUnconvertedDependencyRecord(BlueprintNativeCodeGenManifestImpl::GenerateUnconvertedWrapperPath(TargetPaths, AssetInfo))); + FUnconvertedDependencyRecord* RecordPtr = &UnconvertedDependencies.Add(UnconvertedAssetKey, FUnconvertedDependencyRecord(BlueprintNativeCodeGenManifestImpl::GenerateUnconvertedWrapperPath(TargetPaths, AssetInfo, NativizationOptions))); return *RecordPtr; } diff --git a/Engine/Source/Developer/BlueprintNativeCodeGen/Private/BlueprintNativeCodeGenManifest.h b/Engine/Source/Developer/BlueprintNativeCodeGen/Private/BlueprintNativeCodeGenManifest.h index 546d2b435a1a..326b7483ae3b 100644 --- a/Engine/Source/Developer/BlueprintNativeCodeGen/Private/BlueprintNativeCodeGenManifest.h +++ b/Engine/Source/Developer/BlueprintNativeCodeGen/Private/BlueprintNativeCodeGenManifest.h @@ -22,7 +22,7 @@ struct FConvertedAssetRecord public: FConvertedAssetRecord() {} - FConvertedAssetRecord(const FAssetData& AssetInfo, const FBlueprintNativeCodeGenPaths& TargetPaths); + FConvertedAssetRecord(const FAssetData& AssetInfo, const FBlueprintNativeCodeGenPaths& TargetPaths, const FCompilerNativizationOptions& NativizationOptions); /** * @return diff --git a/Engine/Source/Developer/BlueprintNativeCodeGen/Private/BlueprintNativeCodeGenUtils.cpp b/Engine/Source/Developer/BlueprintNativeCodeGen/Private/BlueprintNativeCodeGenUtils.cpp index 8dfbc6b32062..396ce90538b5 100644 --- a/Engine/Source/Developer/BlueprintNativeCodeGen/Private/BlueprintNativeCodeGenUtils.cpp +++ b/Engine/Source/Developer/BlueprintNativeCodeGen/Private/BlueprintNativeCodeGenUtils.cpp @@ -93,6 +93,7 @@ static bool BlueprintNativeCodeGenUtilsImpl::GeneratePluginDescFile(const FBluep PluginDesc.bEnabledByDefault = true; PluginDesc.bCanContainContent = false; PluginDesc.bIsBetaVersion = true; // @TODO: change once we're confident in the feature + PluginDesc.bIsHidden = true; const FName ModuleName = *TargetPaths.RuntimeModuleName(); FModuleDescriptor* ModuleDesc = PluginDesc.Modules.FindByPredicate([ModuleName](const FModuleDescriptor& Module)->bool @@ -107,6 +108,7 @@ static bool BlueprintNativeCodeGenUtilsImpl::GeneratePluginDescFile(const FBluep else { ModuleDesc->WhitelistPlatforms.Empty(); + ModuleDesc->WhitelistTargets.Empty(); } if (ensure(ModuleDesc)) { @@ -123,6 +125,26 @@ static bool BlueprintNativeCodeGenUtilsImpl::GeneratePluginDescFile(const FBluep // We use the 'UBTTargetId' because this white-list expects the // string to correspond to UBT's UnrealTargetPlatform enum (and by proxy, FPlatformMisc::GetUBTPlatform) ModuleDesc->WhitelistPlatforms.AddUnique(PlatformIt->UBTTargetId.ToString()); + + // should correspond to UnrealBuildTool::TargetType in TargetRules.cs + switch (PlatformIt->PlatformType) + { + case PlatformInfo::EPlatformType::Game: + ModuleDesc->WhitelistTargets.AddUnique(TEXT("Game")); + break; + + case PlatformInfo::EPlatformType::Client: + ModuleDesc->WhitelistTargets.AddUnique(TEXT("Client")); + break; + + case PlatformInfo::EPlatformType::Server: + ModuleDesc->WhitelistTargets.AddUnique(TEXT("Server")); + break; + + case PlatformInfo::EPlatformType::Editor: + ensureMsgf(PlatformIt->PlatformType != PlatformInfo::EPlatformType::Editor, TEXT("Nativized Blueprint plugin is for cooked projects only - it isn't supported in editor builds.")); + break; + }; } } } @@ -172,14 +194,16 @@ static bool BlueprintNativeCodeGenUtilsImpl::GenerateNativizedDependenciesSource bool bSuccess = true; IBlueprintCompilerCppBackendModule& CodeGenBackend = (IBlueprintCompilerCppBackendModule&)IBlueprintCompilerCppBackendModule::Get(); + const FString BaseFilename = NativizedDependenciesFileName(); + { - const FString HeaderFilePath = FPaths::Combine(*TargetPaths.RuntimeSourceDir(FBlueprintNativeCodeGenPaths::HFile), *NativizedDependenciesFileName()) + TEXT(".h"); + const FString HeaderFilePath = FPaths::Combine(*TargetPaths.RuntimeSourceDir(FBlueprintNativeCodeGenPaths::HFile), *BaseFilename) + TEXT(".h"); const FString HeaderFileContent = CodeGenBackend.DependenciesGlobalMapHeaderCode(); bSuccess &= GameProjectUtils::WriteOutputFile(HeaderFilePath, HeaderFileContent, FailureReason); } { - const FString SourceFilePath = FPaths::Combine(*TargetPaths.RuntimeSourceDir(FBlueprintNativeCodeGenPaths::CppFile), *NativizedDependenciesFileName()) + TEXT(".cpp"); + const FString SourceFilePath = FPaths::Combine(*TargetPaths.RuntimeSourceDir(FBlueprintNativeCodeGenPaths::CppFile), *BaseFilename) + TEXT(".cpp"); const FString SourceFileContent = CodeGenBackend.DependenciesGlobalMapBodyCode(TargetPaths.RuntimeModuleName()); bSuccess &= GameProjectUtils::WriteOutputFile(SourceFilePath, SourceFileContent, FailureReason); } @@ -251,12 +275,11 @@ static bool BlueprintNativeCodeGenUtilsImpl::GenerateModuleBuildFile(const FBlue UE_LOG(LogBlueprintCodeGen, Warning, TEXT("Failed to find module for package: %s"), *PkgModuleName); } } - FBlueprintNativeCodeGenPaths TargetPaths = Manifest.GetTargetPaths(); - + FText ErrorMessage; - bool bSuccess = GameProjectUtils::GenerateGameModuleBuildFile(TargetPaths.RuntimeBuildFile(), TargetPaths.RuntimeModuleName(), - PublicDependencies, PrivateDependencies, ErrorMessage); + bool bSuccess = GameProjectUtils::GeneratePluginModuleBuildFile(TargetPaths.RuntimeBuildFile(), TargetPaths.RuntimeModuleName(), + PublicDependencies, PrivateDependencies, ErrorMessage, false); if (!bSuccess) { @@ -392,11 +415,11 @@ void FBlueprintNativeCodeGenUtils::GenerateCppCode(UObject* Obj, TSharedPtr(KISMET_COMPILER_MODULENAME); if (UDEnum) { - Compiler.GenerateCppCodeForEnum(UDEnum, *OutHeaderSource, *OutCppSource); + Compiler.GenerateCppCodeForEnum(UDEnum, NativizationOptions, *OutHeaderSource, *OutCppSource); } else if (UDStruct) { - *OutHeaderSource = Compiler.GenerateCppCodeForStruct(UDStruct, NativizationOptions); + Compiler.GenerateCppCodeForStruct(UDStruct, NativizationOptions, *OutHeaderSource, *OutCppSource); } } else diff --git a/Engine/Source/Developer/BlueprintNativeCodeGen/Private/NativeCodeGenerationTool.cpp b/Engine/Source/Developer/BlueprintNativeCodeGen/Private/NativeCodeGenerationTool.cpp index 1baa2b34314a..2e31eb36d4a5 100644 --- a/Engine/Source/Developer/BlueprintNativeCodeGen/Private/NativeCodeGenerationTool.cpp +++ b/Engine/Source/Developer/BlueprintNativeCodeGen/Private/NativeCodeGenerationTool.cpp @@ -50,7 +50,7 @@ struct FGeneratedCodeData ClassName = GeneratedClassName.ToString(); IBlueprintCompilerCppBackendModule& CodeGenBackend = (IBlueprintCompilerCppBackendModule&)IBlueprintCompilerCppBackendModule::Get(); - BaseFilename = CodeGenBackend.ConstructBaseFilename(&InBlueprint); + BaseFilename = CodeGenBackend.ConstructBaseFilename(&InBlueprint, FCompilerNativizationOptions{}); GatherUserDefinedDependencies(InBlueprint); } @@ -159,7 +159,7 @@ struct FGeneratedCodeData FBlueprintNativeCodeGenUtils::GenerateCppCode(Obj, HeaderSource, CppSource, NativizationSummary, FCompilerNativizationOptions{}); SlowTask.EnterProgressFrame(); - const FString BackendBaseFilename = CodeGenBackend.ConstructBaseFilename(Obj); + const FString BackendBaseFilename = CodeGenBackend.ConstructBaseFilename(Obj, FCompilerNativizationOptions{}); const FString FullHeaderFilename = FPaths::Combine(*HeaderDirPath, *(BackendBaseFilename + TEXT(".h"))); const bool bHeaderSaved = FFileHelper::SaveStringToFile(*HeaderSource, *FullHeaderFilename); diff --git a/Engine/Source/Developer/BlueprintProfiler/Private/ScriptInstrumentationPlayback.cpp b/Engine/Source/Developer/BlueprintProfiler/Private/ScriptInstrumentationPlayback.cpp index c09c444a7cf7..e83a63a01f8b 100644 --- a/Engine/Source/Developer/BlueprintProfiler/Private/ScriptInstrumentationPlayback.cpp +++ b/Engine/Source/Developer/BlueprintProfiler/Private/ScriptInstrumentationPlayback.cpp @@ -953,7 +953,7 @@ void FBlueprintFunctionContext::GetPinCustomizations(const UEdGraphPin* Pin, FSc const UEdGraphSchema* Schema = Pin->GetSchema(); PinParams.IconColor = Schema->GetPinTypeColor(Pin->PinType); // Determine pin icon - if (Pin->PinType.bIsArray) + if (Pin->PinType.IsArray()) { // Array pins PinParams.Icon = const_cast(FEditorStyle::GetBrush(TEXT("Graph.ArrayPin.Connected"))); diff --git a/Engine/Source/Developer/CollisionAnalyzer/Private/CollisionAnalyzer.h b/Engine/Source/Developer/CollisionAnalyzer/Private/CollisionAnalyzer.h index 17fc6248a572..ae24dd63680a 100644 --- a/Engine/Source/Developer/CollisionAnalyzer/Private/CollisionAnalyzer.h +++ b/Engine/Source/Developer/CollisionAnalyzer/Private/CollisionAnalyzer.h @@ -12,6 +12,11 @@ class SWidget; /** Stores information about one collision query */ struct FCAQuery { + FCAQuery(): + Params(NAME_None, FCollisionQueryParams::GetUnknownStatId()) + { + } + FVector Start; FVector End; FQuat Rot; diff --git a/Engine/Source/Developer/CrashDebugHelper/CrashDebugHelper.Build.cs b/Engine/Source/Developer/CrashDebugHelper/CrashDebugHelper.Build.cs index 3ac2069f1262..54882e708da3 100644 --- a/Engine/Source/Developer/CrashDebugHelper/CrashDebugHelper.Build.cs +++ b/Engine/Source/Developer/CrashDebugHelper/CrashDebugHelper.Build.cs @@ -6,21 +6,34 @@ public class CrashDebugHelper : ModuleRules { public CrashDebugHelper( ReadOnlyTargetRules Target ) : base(Target) { - PrivateIncludePaths.AddRange( + PrivateIncludePaths.AddRange( new string[] { "Developer/CrashDebugHelper/Private/", "Developer/CrashDebugHelper/Private/Linux", "Developer/CrashDebugHelper/Private/Mac", "Developer/CrashDebugHelper/Private/Windows", - } - ); + "Developer/CrashDebugHelper/Private/IOS", + } + ); PrivateIncludePaths.Add( "ThirdParty/PLCrashReporter/plcrashreporter-master-5ae3b0a/Source" ); - PublicDependencyModuleNames.AddRange( - new string[] { - "Core", - "SourceControl" - } - ); - } + if (Target.Type != TargetType.Game) + { + PublicDependencyModuleNames.AddRange( + new string[] { + "Core", + "SourceControl" + } + ); + } + else + { + IsRedistributableOverride = true; + PublicDependencyModuleNames.AddRange( + new string[] { + "Core", + } + ); + } + } } diff --git a/Engine/Source/Developer/CrashDebugHelper/Private/CrashDebugHelper.cpp b/Engine/Source/Developer/CrashDebugHelper/Private/CrashDebugHelper.cpp index 6f5d944353b0..f09f0464a8ac 100644 --- a/Engine/Source/Developer/CrashDebugHelper/Private/CrashDebugHelper.cpp +++ b/Engine/Source/Developer/CrashDebugHelper/Private/CrashDebugHelper.cpp @@ -13,12 +13,14 @@ #include "CrashDebugPDBCache.h" #include "Misc/EngineVersion.h" +#if UE_EDITOR || IS_PROGRAM #include "ISourceControlOperation.h" #include "SourceControlOperations.h" #include "ISourceControlRevision.h" #include "ISourceControlProvider.h" #include "ISourceControlModule.h" #include "ISourceControlLabel.h" +#endif #ifndef MINIDUMPDIAGNOSTICS #define MINIDUMPDIAGNOSTICS 0 @@ -270,6 +272,7 @@ bool ICrashDebugHelper::InitSourceControl(bool bShowLogin) return false; } +#if UE_EDITOR || IS_PROGRAM // Initialize the source control if it hasn't already been if( !ISourceControlModule::Get().IsEnabled() || !ISourceControlModule::Get().GetProvider().IsAvailable() ) { @@ -293,6 +296,7 @@ bool ICrashDebugHelper::InitSourceControl(bool bShowLogin) return false; } } +#endif return true; } @@ -302,7 +306,9 @@ bool ICrashDebugHelper::InitSourceControl(bool bShowLogin) */ void ICrashDebugHelper::ShutdownSourceControl() { +#if UE_EDITOR || IS_PROGRAM ISourceControlModule::Get().GetProvider().Close(); +#endif } @@ -372,6 +378,7 @@ bool ICrashDebugHelper::SyncModules(bool& bOutPDBCacheEntryValid) else { // Command line for blocking obsolete path +#if UE_EDITOR || IS_PROGRAM const bool bNoP4Symbols = FParse::Param(FCommandLine::Get(), TEXT("NoP4Symbols")); // Check source control @@ -546,6 +553,7 @@ bool ICrashDebugHelper::SyncModules(bool& bOutPDBCacheEntryValid) UE_LOG(LogCrashDebugHelper, Error, TEXT("Could not find label: %s"), *CrashInfo.LabelName); return false; } +#endif } bOutPDBCacheEntryValid = CrashInfo.PDBCacheEntry.IsValid() && CrashInfo.PDBCacheEntry->Files.Num() > 0; @@ -554,6 +562,7 @@ bool ICrashDebugHelper::SyncModules(bool& bOutPDBCacheEntryValid) bool ICrashDebugHelper::SyncSourceFile() { +#if UE_EDITOR || IS_PROGRAM // Check source control if( !ISourceControlModule::Get().IsEnabled() ) { @@ -565,6 +574,7 @@ bool ICrashDebugHelper::SyncSourceFile() ISourceControlModule::Get().GetProvider().Execute(ISourceControlOperation::Create(), DepotPath); UE_LOG( LogCrashDebugHelper, Warning, TEXT( "Syncing a single source file: %s"), *DepotPath ); +#endif return true; } @@ -644,6 +654,7 @@ bool ICrashDebugHelper::AddAnnotatedSourceToReport() // Make sure we have a source file to interrogate if( CrashInfo.SourceFile.Len() > 0 && CrashInfo.SourceLineNumber != 0 && !CrashInfo.LabelName.IsEmpty() ) { +#if UE_EDITOR || IS_PROGRAM // Check source control if( !ISourceControlModule::Get().IsEnabled() ) { @@ -671,6 +682,7 @@ bool ICrashDebugHelper::AddAnnotatedSourceToReport() CrashInfo.SourceContext.Add( FString::Printf( TEXT( "%5u %20s: %s" ), Line, *Lines[Line].UserName, *Lines[Line].Line ) ); } } +#endif return true; } @@ -915,6 +927,7 @@ void ICrashDebugHelper::FindSymbolsAndBinariesStorage() const FString LabelWithCL = SourceControlBuildLabelPattern.Replace( TEXT( "%CHANGELISTNUMBER%" ), *ChangelistString, ESearchCase::CaseSensitive ); UE_LOG( LogCrashDebugHelper, Log, TEXT( "Label matching pattern: %s" ), *LabelWithCL ); +#if UE_EDITOR || IS_PROGRAM TArray< TSharedRef > Labels = ISourceControlModule::Get().GetProvider().GetLabels( LabelWithCL ); if( Labels.Num() > 0 ) { @@ -931,5 +944,6 @@ void ICrashDebugHelper::FindSymbolsAndBinariesStorage() UE_LOG( LogCrashDebugHelper, Log, TEXT( "Using label: %s" ), *CrashInfo.LabelName ); } } +#endif } } diff --git a/Engine/Source/Developer/CrashDebugHelper/Private/CrashDebugHelperModule.cpp b/Engine/Source/Developer/CrashDebugHelper/Private/CrashDebugHelperModule.cpp index d9e20bad00ab..2679bbbed774 100644 --- a/Engine/Source/Developer/CrashDebugHelper/Private/CrashDebugHelperModule.cpp +++ b/Engine/Source/Developer/CrashDebugHelper/Private/CrashDebugHelperModule.cpp @@ -17,6 +17,9 @@ DEFINE_LOG_CATEGORY(LogCrashDebugHelper); #elif PLATFORM_MAC #include "CrashDebugHelperMac.h" +#elif PLATFORM_IOS + #include "CrashDebugHelperIOS.h" + #else #error "Unknown platform" #endif diff --git a/Engine/Source/Developer/CrashDebugHelper/Private/IOS/CrashDebugHelperIOS.cpp b/Engine/Source/Developer/CrashDebugHelper/Private/IOS/CrashDebugHelperIOS.cpp new file mode 100644 index 000000000000..d3745743c55c --- /dev/null +++ b/Engine/Source/Developer/CrashDebugHelper/Private/IOS/CrashDebugHelperIOS.cpp @@ -0,0 +1,813 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "CrashDebugHelperIOS.h" +#include "EngineVersion.h" +#include "Apple/ApplePlatformSymbolication.h" +//#include "CrashReporter.h" +#include "CrashDebugHelperPrivate.h" +#include "Misc/FileHelper.h" +#include "Misc/CommandLine.h" +#include "Misc/Paths.h" +#if PLATFORM_IOS +#include +#endif + +FString ExtractRelativePath( const TCHAR* BaseName, TCHAR const* FullName ) +{ + FString FullPath = FString( FullName ).ToLower(); + FullPath = FullPath.Replace( TEXT( "\\" ), TEXT( "/" ) ); + + TArray Components; + int32 Count = FullPath.ParseIntoArray( Components, TEXT( "/" ), true ); + FullPath = TEXT( "" ); + + for( int32 Index = 0; Index < Count; Index++ ) + { + if( Components[Index] == BaseName ) + { + if( Index > 0 ) + { + for( int32 Inner = Index - 1; Inner < Count; Inner++ ) + { + FullPath += Components[Inner]; + if( Inner < Count - 1 ) + { + FullPath += TEXT( "/" ); + } + } + } + break; + } + } + + return FullPath; +} + +static int32 ParseReportVersion(TCHAR const* CrashLog, int32& OutVersion) +{ + int32 Found = 0; + TCHAR const* VersionLine = FCStringWide::Strstr(CrashLog, TEXT("Report Version:")); + if (VersionLine) + { + Found = swscanf(VersionLine, TEXT("%*ls %*ls %d"), &OutVersion); + } + return Found; +} + +static int32 ParseVersion(TCHAR const* CrashLog, int32& OutMajor, int32& OutMinor, int32& OutBuild, int32& OutChangeList, FString& OutBranch) +{ + int32 Found = 0; + TCHAR const* VersionLine = FCStringWide::Strstr(CrashLog, TEXT("Version:")); + if (VersionLine) + { + TCHAR Branch[257] = {0}; + Found = swscanf(VersionLine, TEXT("%*s %d.%d.%d (%*d.%*d.%*d-%d+%256ls)"), &OutMajor, &OutMinor, &OutBuild, &OutChangeList, Branch); + if(Found == 5) + { + TCHAR* BranchEnd = FCStringWide::Strchr(Branch, TEXT(')')); + if(BranchEnd) + { + *BranchEnd = TEXT('\0'); + } + OutBranch = Branch; + } + } + return Found; +} + +static int32 ParseOS(TCHAR const* CrashLog, uint16& OutMajor, uint16& OutMinor, uint16& OutPatch, uint16& OutBuild) +{ + int32 Found = 0; + TCHAR const* VersionLine = FCStringWide::Strstr(CrashLog, TEXT("OS Version:")); + if (VersionLine) + { + Found = swscanf(VersionLine, TEXT("%*s %*s iPhone OS %hd.%hd.%hd (%hxd)"), &OutMajor, &OutMinor, &OutPatch, &OutBuild); + if ( Found == 2 ) + { + OutPatch = 0; + Found += swscanf(VersionLine, TEXT("%*s %*s iPhone OS %*hd.%*hd (%hxd)"), &OutBuild) + 1; + } + } + return Found; +} + +static bool ParseModel(TCHAR const* CrashLog, FString& OutModelDetails, uint32& OutProcessorNum) +{ + bool bFound = false; + TCHAR const* Line = FCStringWide::Strstr(CrashLog, TEXT("Model:")); + if (Line) + { + Line += FCStringWide::Strlen(TEXT("Model: ")); + TCHAR const* End = FCStringWide::Strchr(Line, TEXT('\r')); + if(!End) + { + End = FCStringWide::Strchr(Line, TEXT('\n')); + } + check(End); + + int32 Length = FMath::Min(256, (int32)((uintptr_t)(End - Line))); + OutModelDetails.Append(Line, Length); + + OutProcessorNum = 1; + int32 ProcessorPos = OutModelDetails.Find(TEXT(" processors")); + if( ProcessorPos != INDEX_NONE ) + { + int32 NumStart = ProcessorPos; + while(NumStart && OutModelDetails[NumStart] != TEXT(',')) + { + NumStart--; + } + if(NumStart >= 0 && OutModelDetails[NumStart] == TEXT(',')) + { + NumStart += 2; + FString NumProc = OutModelDetails.Mid(NumStart, ProcessorPos-NumStart); + if(NumProc.IsNumeric()) + { + TTypeFromString::FromString(OutProcessorNum, *NumProc); + } + } + } + + bFound = true; + } + return bFound; +} + +static int32 ParseGraphics(TCHAR const* CrashLog, FString& OutGPUDetails) +{ + bool bFound = false; + TCHAR const* Line = FCStringWide::Strstr(CrashLog, TEXT("Graphics:")); + int32 Output = 0; + while (Line) + { + Line += FCStringWide::Strlen(TEXT("Graphics:")); + TCHAR const* End = FCStringWide::Strchr(Line, TEXT('\r')); + if(!End) + { + End = FCStringWide::Strchr(Line, TEXT('\n')); + } + check(End); + + OutGPUDetails.Append(TEXT(", ")); + int32 Length = FMath::Min((256 - Output), (int32)((uintptr_t)(End - Line))); + OutGPUDetails.Append(Line, Length); + + Line = FCStringWide::Strstr(Line, TEXT("Graphics:")); + + bFound = true; + } + return bFound; +} + +static int32 ParseError(TCHAR const* CrashLog, FString& OutErrorDetails) +{ + bool bFound = false; + TCHAR const* Line = FCStringWide::Strstr(CrashLog, TEXT("Exception Codes:")); + if (Line) + { + Line += FCStringWide::Strlen(TEXT("Exception Codes:")); + check(Line); + TCHAR const* End = FCStringWide::Strchr(Line, TEXT('\r')); + if(!End) + { + End = FCStringWide::Strchr(Line, TEXT('\n')); + } + check(End); + + int32 Length = FMath::Min(PATH_MAX, (int32)((uintptr_t)(End - Line))); + OutErrorDetails.Append(Line, Length); + + bFound = true; + } + Line = FCStringWide::Strstr(CrashLog, TEXT("Application Specific Information:")); + if (Line) + { + Line = FCStringWide::Strchr(Line, TEXT('\n')); + check(Line); + Line += 1; + TCHAR const* End = FCStringWide::Strchr(Line, TEXT('\r')); + if(!End) + { + End = FCStringWide::Strchr(Line, TEXT('\n')); + } + check(End); + + int32 Length = FMath::Min(PATH_MAX, (int32)((uintptr_t)(End - Line))); + OutErrorDetails += TEXT(" "); + OutErrorDetails.Append(Line, Length); + + bFound = true; + } + return bFound; +} + +static int32 ParseExceptionCode(TCHAR const* CrashLog, uint32& OutExceptionCode) +{ + int32 Found = 0; + TCHAR const* Line = FCStringWide::Strstr(CrashLog, TEXT("Exception Type:")); + if(Line) + { + TCHAR Buffer[257] = {0}; + Found = swscanf(Line, TEXT("%*s %*s %*s (%256ls)"), Buffer); + if(!Found) + { + Found = swscanf(Line, TEXT("%*s %*s %256ls"), Buffer); + } + if(Found) + { + TCHAR* End = FCStringWide::Strchr(Buffer, TEXT(')')); + if(End) + { + *End = TEXT('\0'); + } + if(FCStringWide::Strcmp(Buffer, TEXT("SIGQUIT")) == 0) + { + OutExceptionCode = SIGQUIT; + } + else if(FCStringWide::Strcmp(Buffer, TEXT("SIGILL")) == 0) + { + OutExceptionCode = SIGILL; + } + else if(FCStringWide::Strcmp(Buffer, TEXT("SIGEMT")) == 0) + { + OutExceptionCode = SIGEMT; + } + else if(FCStringWide::Strcmp(Buffer, TEXT("SIGFPE")) == 0) + { + OutExceptionCode = SIGFPE; + } + else if(FCStringWide::Strcmp(Buffer, TEXT("SIGBUS")) == 0) + { + OutExceptionCode = SIGBUS; + } + else if(FCStringWide::Strcmp(Buffer, TEXT("SIGSEGV")) == 0) + { + OutExceptionCode = SIGSEGV; + } + else if(FCStringWide::Strcmp(Buffer, TEXT("SIGSYS")) == 0) + { + OutExceptionCode = SIGSYS; + } + else if(FCStringWide::Strcmp(Buffer, TEXT("SIGABRT")) == 0) + { + OutExceptionCode = SIGABRT; + } + else if(FCStringWide::Strcmp(Buffer, TEXT("SIGTRAP")) == 0) + { + OutExceptionCode = SIGTRAP; + } + else if(FString(Buffer).IsNumeric()) + { + Found = swscanf(Buffer, TEXT("%u"), &OutExceptionCode); + } + else + { + ensure(false); + OutExceptionCode = SIGUSR1; + } + } + } + return Found; +} + +static int32 ParseCrashedThread(TCHAR const* CrashLog, uint32& OutThreadNumber) +{ + int32 Found = 0; + TCHAR const* Line = FCStringWide::Strstr(CrashLog, TEXT("Crashed Thread:")); + if (Line) + { + Found = swscanf(Line, TEXT("%*s %*s %u"), &OutThreadNumber); + } + return Found; +} + +static int32 ParseProcessID(TCHAR const* CrashLog, uint32& OutPID) +{ + int32 Found = 0; + TCHAR const* Line = FCStringWide::Strstr(CrashLog, TEXT("Process:")); + if (Line) + { + Found = swscanf(Line, TEXT("%*s %*s [%u]"), &OutPID); + } + return Found; +} + +static TCHAR const* FindThreadStack(TCHAR const* CrashLog, uint32 const ThreadNumber) +{ + int32 Found = 0; + FString Format = FString::Printf(TEXT("Thread %u"), ThreadNumber); + TCHAR const* Line = FCStringWide::Strstr(CrashLog, *Format); + if (Line) + { + Line = FCStringWide::Strchr(Line, TEXT('\n')); + check(Line); + Line += 1; + } + return Line; +} + +static TCHAR const* FindCrashedThreadStack(TCHAR const* CrashLog) +{ + TCHAR const* Line = nullptr; + uint32 ThreadNumber = 0; + int32 Found = ParseCrashedThread(CrashLog, ThreadNumber); + if(Found) + { + Line = FindThreadStack(CrashLog, ThreadNumber); + } + return Line; +} + +static int32 ParseThreadStackLine(TCHAR const* StackLine, FString& OutModuleName, uint64& OutProgramCounter, FString& OutFunctionName, FString& OutFileName, int32& OutLineNumber) +{ + TCHAR ModuleName[257]; + TCHAR FunctionName[1025]; + TCHAR FileName[257]; + + int32 Found = swscanf(StackLine, TEXT("%*d %256ls 0x%lx"), ModuleName, &OutProgramCounter); + if(Found == 2) + { + uint64 FunctionAddress = 0; + uint32 FunctionOffset = 0; + if(swscanf(StackLine, TEXT("%*d %*ls %*lx 0x%lx + %d"), &FunctionAddress, &FunctionOffset) == 0) + { + Found += swscanf(StackLine, TEXT("%*d %*ls %*lx %1024ls + %*d (%256ls:%d)"), FunctionName, FileName, &OutLineNumber); + } + } + + switch(Found) + { + case 5: + case 4: + { + OutFileName = FileName; + } + case 3: + { +#if PLATFORM_IOS + int32 Status = -1; + ANSICHAR* DemangledName = abi::__cxa_demangle(TCHAR_TO_UTF8(FunctionName), nullptr, nullptr, &Status); + if (DemangledName && Status == 0) + { + // C++ function + OutFunctionName = FString::Printf(TEXT("%ls "), UTF8_TO_TCHAR(DemangledName)); + } + else +#endif + if (FCStringWide::Strlen(FunctionName) > 0 && FCStringWide::Strchr(FunctionName, ']')) + { + // ObjC function + OutFunctionName = FString::Printf(TEXT("%ls "), FunctionName); + } + else if (FCStringWide::Strlen(FunctionName) > 0) + { + // C Function + OutFunctionName = FString::Printf(TEXT("%ls() "), FunctionName); + } + } + case 2: + case 1: + { + OutModuleName = ModuleName; + } + default: + { + break; + } + } + return Found; +} + +static int32 SymboliseStackInfo(FPlatformSymbolDatabaseSet& SymbolCache, TArray const& ModuleInfo, FString ModuleName, uint64 const ProgramCounter, FString& OutFunctionName, FString& OutFileName, int32& OutLineNumber) +{ + FProgramCounterSymbolInfo Info; + int32 ValuesSymbolised = 0; + + FCrashModuleInfo Module; + for (auto Iterator : ModuleInfo) + { + if(Iterator.Name.EndsWith(ModuleName)) + { + Module = Iterator; + break; + } + } + + FApplePlatformSymbolDatabase* Db = SymbolCache.Find(Module.Report); + if(!Db) + { + FApplePlatformSymbolDatabase Database; + if(FPlatformSymbolication::LoadSymbolDatabaseForBinary(TEXT(""), Module.Name, Module.Report, Database)) + { + SymbolCache.Add(Database); + Db = SymbolCache.Find(Module.Report); + } + else + { + // add a dummy DB so we don't keep trying to load one that isn't correct. + FApplePlatformSymbolDatabase DB; + DB.GenericDB->Signature = Module.Report; + SymbolCache.Add(DB); + Db = SymbolCache.Find(Module.Report); + } + } + if((Module.Name.Len() > 0) && Db && FPlatformSymbolication::SymbolInfoForStrippedSymbol(*Db, ProgramCounter, Module.BaseOfImage, Module.Report, Info)) + { + if(FCStringAnsi::Strlen(Info.FunctionName) > 0) + { + OutFunctionName = Info.FunctionName; + ValuesSymbolised++; + } + if(ValuesSymbolised == 1 && FCStringAnsi::Strlen(Info.Filename) > 0) + { + OutFileName = Info.Filename; + ValuesSymbolised++; + } + if(ValuesSymbolised == 2 && Info.LineNumber > 0) + { + OutLineNumber = Info.LineNumber; + ValuesSymbolised++; + } + } + + return ValuesSymbolised; +} + +static TCHAR const* FindModules(TCHAR const* CrashLog) +{ + TCHAR const* Line = FCStringWide::Strstr(CrashLog, TEXT("Binary Images:")); + if (Line) + { + Line = FCStringWide::Strchr(Line, TEXT('\n')); + check(Line); + Line += 1; + } + return Line; +} + +static int32 ParseModuleVersion(TCHAR const* Version, uint16& OutMajor, uint16& OutMinor, uint16& OutPatch, uint16& OutBuild) +{ + OutMajor = OutMinor = OutPatch = OutBuild = 0; + int32 Found = swscanf(Version, TEXT("%hu.%hu.%hu"), &OutMajor, &OutMinor, &OutPatch); + TCHAR const* CurrentStart = FCStringWide::Strchr(Version, TEXT('-')); + if(CurrentStart) + { + int32 Components[3] = {0, 0, 0}; + int32 Result = swscanf(CurrentStart, TEXT("%*ls %d.%d.%d"), &Components[0], &Components[1], &Components[2]); + OutBuild = (uint16)(Components[0] * 10000) + (Components[1] * 100) + (Components[2]); + Found = 4; + } + return Found; +} + +static bool ParseModuleLine(TCHAR const* ModuleLine, FCrashModuleInfo& OutModule) +{ + bool bOK = false; + TCHAR ModuleName[257] = {0}; + uint64 ModuleBase = 0; + uint64 ModuleEnd = 0; + + int32 Found = swscanf(ModuleLine, TEXT("%lx %*ls %lx %256ls"), &ModuleBase, &ModuleEnd, ModuleName); + switch (Found) + { + case 3: + { + TCHAR const* VersionStart = FCStringWide::Strchr(ModuleLine, TEXT('(')); + TCHAR const* VersionEnd = FCStringWide::Strchr(ModuleLine, TEXT(')')); + if(VersionStart && VersionEnd) + { + ++VersionStart; + Found += ParseModuleVersion(VersionStart, OutModule.Major, OutModule.Minor, OutModule.Patch, OutModule.Revision); + } + + TCHAR const* UUIDStart = FCStringWide::Strchr(ModuleLine, TEXT('<')); + TCHAR const* UUIDEnd = FCStringWide::Strchr(ModuleLine, TEXT('>')); + if(UUIDStart && UUIDEnd) + { + ++UUIDStart; + int32 Length = FMath::Min(64, (int32)((uintptr_t)(UUIDEnd - UUIDStart))); + OutModule.Report.Append(UUIDStart, Length); + if(!OutModule.Report.Contains(TEXT("-"))) + { + OutModule.Report.InsertAt(8, TEXT('-')); + OutModule.Report.InsertAt(13, TEXT('-')); + OutModule.Report.InsertAt(18, TEXT('-')); + OutModule.Report.InsertAt(23, TEXT('-')); + } + OutModule.Report = OutModule.Report.ToUpper(); + Found++; + } + + TCHAR const* Path = FCStringWide::Strchr(ModuleLine, TEXT('/')); + if(Path) + { + TCHAR const* End = FCStringWide::Strchr(Path, TEXT('\r')); + if(!End) + { + End = FCStringWide::Strchr(Path, TEXT('\n')); + } + check(End); + + int32 Length = FMath::Min(PATH_MAX, (int32)((uintptr_t)(End - Path))); + OutModule.Name.Append(Path, Length); + Found++; + bOK = true; + } + } + case 2: + { + OutModule.SizeOfImage = (ModuleBase - ModuleEnd); + } + case 1: + { + OutModule.BaseOfImage = ModuleBase; + break; + } + default: + { + break; + } + } + return bOK; +} + +FCrashDebugHelperIOS::FCrashDebugHelperIOS() +{ +} + +FCrashDebugHelperIOS::~FCrashDebugHelperIOS() +{ +} + +bool FCrashDebugHelperIOS::ParseCrashDump(const FString& InCrashDumpName, FCrashDebugInfo& OutCrashDebugInfo) +{ + if (bInitialized == false) + { + UE_LOG(LogCrashDebugHelper, Warning, TEXT("ParseCrashDump: CrashDebugHelper not initialized")); + return false; + } + + FString CrashDump; + if ( FFileHelper::LoadFileToString( CrashDump, *InCrashDumpName ) ) + { + // Only supports Apple crash report version 11 + int32 ReportVersion = 0; + int32 Result = ParseReportVersion(*CrashDump, ReportVersion); + if(Result == 1 && (ReportVersion == 11 || ReportVersion == 104)) + { + int32 Major = 0; + int32 Minor = 0; + int32 Build = 0; + int32 CLNumber = 0; + FString Branch; + Result = ParseVersion(*CrashDump, Major, Minor, Build, CLNumber, Branch); + if(Result >= 1) + { + if (Result < 3) + { + OutCrashDebugInfo.EngineVersion = Major; + } + else if (Result < 5) + { + OutCrashDebugInfo.EngineVersion = Build; + } + else + { + OutCrashDebugInfo.EngineVersion = CLNumber; + } + if(Result == 5) + { + OutCrashDebugInfo.SourceControlLabel = Branch; + } + OutCrashDebugInfo.PlatformName = TEXT("IOS"); + OutCrashDebugInfo.CrashDumpName = InCrashDumpName; + return true; + } + } + } + + return false; +} + +bool FCrashDebugHelperIOS::CreateMinidumpDiagnosticReport( const FString& InCrashDumpName ) +{ + bool bOK = false; + const bool bSyncSymbols = FParse::Param( FCommandLine::Get(), TEXT( "SyncSymbols" ) ); + const bool bAnnotate = FParse::Param( FCommandLine::Get(), TEXT( "Annotate" ) ); + const bool bUseSCC = bSyncSymbols || bAnnotate; + + if( bUseSCC ) + { + InitSourceControl( false ); + } + + FString CrashDump; + if ( FFileHelper::LoadFileToString( CrashDump, *InCrashDumpName ) ) + { + int32 ReportVersion = 0; + int32 Result = ParseReportVersion(*CrashDump, ReportVersion); + if(Result == 1 && (ReportVersion == 11 || ReportVersion == 104)) + { + FString Error; + FString ModulePath; + FString ModuleName; + FString FunctionName; + FString FileName; + FString Branch; + FString Model; + FString Gpu; + + uint64 ProgramCounter = 0; + int32 Major = 0; + int32 Minor = 0; + int32 Build = 0; + int32 CLNumber = 0; + int32 LineNumber = 0;; + + Result = ParseVersion(*CrashDump, Major, Minor, Build, CLNumber, Branch); + if(Result >= 3) + { + CrashInfo.EngineVersion = FEngineVersion(Major, Minor, Build, CLNumber, Branch).ToString(); + } + + if(Result >= 4) + { + CrashInfo.BuiltFromCL = CLNumber; + } + + if(Result == 5 && Branch.Len() > 0) + { + CrashInfo.LabelName = Branch; + + if( bSyncSymbols ) + { + FindSymbolsAndBinariesStorage(); + + bool bPDBCacheEntryValid = false; + SyncModules(bPDBCacheEntryValid); + } + } + + Result = ParseOS(*CrashDump, CrashInfo.SystemInfo.OSMajor, CrashInfo.SystemInfo.OSMinor, CrashInfo.SystemInfo.OSBuild, CrashInfo.SystemInfo.OSRevision); + check(Result == 4); + + CrashInfo.SystemInfo.ProcessorArchitecture = PA_X64; + + ParseModel(*CrashDump, Model, CrashInfo.SystemInfo.ProcessorCount); + ParseGraphics(*CrashDump, Gpu); + CrashInfo.SystemInfo.Report = Model + Gpu; + + Result = ParseError(*CrashDump, CrashInfo.Exception.ExceptionString); + check(Result == 1); + + Result = ParseProcessID(*CrashDump, CrashInfo.Exception.ProcessId); + check(Result == 1); + + Result = ParseCrashedThread(*CrashDump, CrashInfo.Exception.ThreadId); + check(Result == 1); + + Result = ParseExceptionCode(*CrashDump, CrashInfo.Exception.Code); + check(Result == 1); + + FCrashThreadInfo ThreadInfo; + ThreadInfo.ThreadId = CrashInfo.Exception.ThreadId; + ThreadInfo.SuspendCount = 0; + + // Parse modules now for symbolication - if we don't have the running process we need to symbolicate by UUID + TCHAR const* ModuleLine = FindModules(*CrashDump); + while(ModuleLine) + { + FCrashModuleInfo Module; + if (ParseModuleLine(ModuleLine, Module)) + { + CrashInfo.Modules.Push(Module); + CrashInfo.ModuleNames.Push(FPaths::GetBaseFilename(Module.Name)); + + ModuleLine = FCStringWide::Strchr(ModuleLine, TEXT('\n')); + check(ModuleLine); + ModuleLine += 1; + } + else + { + ModuleLine = nullptr; + } + } + + + FPlatformSymbolDatabaseSet SymbolCache; + + bool bIsCrashLocation = true; + TCHAR const* ThreadStackLine = FindCrashedThreadStack(*CrashDump); + uint32 Index = 0; + while(ThreadStackLine) + { + if(CrashInfo.Exception.Code == SIGTRAP) + { + // For ensures strip the first three lines as they are PLCrashReporter nonsense + if(Index < 3) + { + ThreadStackLine = FCStringWide::Strchr(ThreadStackLine, TEXT('\n')); + if(ThreadStackLine) + { + ThreadStackLine += 1; + } + ++Index; + continue; + } + + // Crash location is the 5th entry in the stack. + bIsCrashLocation = (Index == 5); + } + + Result = ParseThreadStackLine(ThreadStackLine, ModuleName, ProgramCounter, FunctionName, FileName, LineNumber); + + // If we got the modulename & program counter but didn't parse the filename & linenumber we can resymbolise + if(Result > 1 && Result < 4) + { + // Attempt to resymbolise using CoreSymbolication + Result += SymboliseStackInfo(SymbolCache, CrashInfo.Modules, ModuleName, ProgramCounter, FunctionName, FileName, LineNumber); + } + + // Output in our format based on the fields we actually have + switch (Result) + { + case 2: + CrashInfo.Exception.CallStackString.Push( FString::Printf( TEXT( "Unknown() Address = 0x%lx (filename not found) [in %s]" ), ProgramCounter, *ModuleName ) ); + ThreadInfo.CallStack.Push(ProgramCounter); + + ThreadStackLine = FCStringWide::Strchr(ThreadStackLine, TEXT('\n')); + check(ThreadStackLine); + ThreadStackLine += 1; + break; + + case 3: + case 4: + CrashInfo.Exception.CallStackString.Push( FString::Printf( TEXT( "%s Address = 0x%lx (filename not found) [in %s]" ), *FunctionName, ProgramCounter, *ModuleName ) ); + ThreadInfo.CallStack.Push(ProgramCounter); + + ThreadStackLine = FCStringWide::Strchr(ThreadStackLine, TEXT('\n')); + check(ThreadStackLine); + ThreadStackLine += 1; + break; + + case 5: + case 6: // Function name might be parsed twice + if(bIsCrashLocation) + { + if( FileName.Len() > 0 && LineNumber > 0 ) + { + // Sync the source file where the crash occurred + CrashInfo.SourceFile = ExtractRelativePath( TEXT( "source" ), *FileName ); + CrashInfo.SourceLineNumber = LineNumber; + + if( bSyncSymbols && CrashInfo.BuiltFromCL > 0 ) + { + UE_LOG( LogCrashDebugHelper, Log, TEXT( "Using CL %i to sync crash source file" ), CrashInfo.BuiltFromCL ); + SyncSourceFile(); + } + + // Try to annotate the file if requested + bool bAnnotationSuccessful = false; + if( bAnnotate ) + { + bAnnotationSuccessful = AddAnnotatedSourceToReport(); + } + + // If annotation is not requested, or failed, add the standard source context + if( !bAnnotationSuccessful ) + { + AddSourceToReport(); + } + } + } + + CrashInfo.Exception.CallStackString.Push( FString::Printf( TEXT( "%s Address = 0x%lx [%s, line %d] [in %s]" ), *FunctionName, ProgramCounter, *FileName, LineNumber, *ModuleName ) ); + ThreadInfo.CallStack.Push(ProgramCounter); + + ThreadStackLine = FCStringWide::Strchr(ThreadStackLine, TEXT('\n')); + check(ThreadStackLine); + ThreadStackLine += 1; + break; + + default: + ThreadStackLine = nullptr; + break; + } + + ++Index; + bIsCrashLocation = false; + } + + CrashInfo.Threads.Push(ThreadInfo); + + bOK = true; + } + } + + if( bUseSCC ) + { + ShutdownSourceControl(); + } + + return bOK; +} diff --git a/Engine/Source/Developer/CrashDebugHelper/Private/IOS/CrashDebugHelperIOS.h b/Engine/Source/Developer/CrashDebugHelper/Private/IOS/CrashDebugHelperIOS.h new file mode 100644 index 000000000000..12d8210b763f --- /dev/null +++ b/Engine/Source/Developer/CrashDebugHelper/Private/IOS/CrashDebugHelperIOS.h @@ -0,0 +1,34 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CrashDebugHelper.h" + +class FCrashDebugHelperIOS : public ICrashDebugHelper +{ +public: + FCrashDebugHelperIOS(); + virtual ~FCrashDebugHelperIOS(); + + /** + * Parse the given crash dump, determining EngineVersion of the build that produced it - if possible. + * + * @param InCrashDumpName The crash dump file to process + * @param OutCrashDebugInfo The crash dump info extracted from the file + * + * @return bool true if successful, false if not + */ + virtual bool ParseCrashDump(const FString& InCrashDumpName, FCrashDebugInfo& OutCrashDebugInfo) override; + + + /** + * Parse the given crash dump, and generate a report. + * + * @param InCrashDumpName The crash dump file to process + * + * @return bool true if successful, false if not + */ + virtual bool CreateMinidumpDiagnosticReport( const FString& InCrashDumpName ) override; +}; + +typedef FCrashDebugHelperIOS FCrashDebugHelper; diff --git a/Engine/Source/Developer/CrashReportHelper/CrashReportHelper.Build.cs b/Engine/Source/Developer/CrashReportHelper/CrashReportHelper.Build.cs new file mode 100644 index 000000000000..60f67384d69f --- /dev/null +++ b/Engine/Source/Developer/CrashReportHelper/CrashReportHelper.Build.cs @@ -0,0 +1,41 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +using UnrealBuildTool; + +public class CrashReportHelper : ModuleRules +{ + public CrashReportHelper( ReadOnlyTargetRules Target ) : base(Target) + { + PrivateIncludePaths.AddRange( + new string[] { + "Developer/CrashReportHelper/Private/", + "Developer/CrashReportHelper/Private/Linux", + "Developer/CrashReportHelper/Private/Mac", + "Developer/CrashReportHelper/Private/Windows", + "Developer/CrashReportHelper/Private/IOS", + } + ); + + PublicDependencyModuleNames.AddRange( + new string[] { + "Core", + "CrashDebugHelper", + "XmlParser", + "Analytics", + "AnalyticsET", + "HTTP", + "Json", + } + ); + + if (Target.Type == TargetType.Game) + { + IsRedistributableOverride = true; + } + else + { + PrecompileForTargets = PrecompileTargetsType.None; + PublicDependencyModuleNames.Add("SourceControl"); + } + } +} diff --git a/Engine/Source/Developer/CrashReportHelper/Private/CrashDescription.cpp b/Engine/Source/Developer/CrashReportHelper/Private/CrashDescription.cpp new file mode 100644 index 000000000000..455a5e4256bf --- /dev/null +++ b/Engine/Source/Developer/CrashReportHelper/Private/CrashDescription.cpp @@ -0,0 +1,585 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "CrashDescription.h" +#include "Misc/DateTime.h" +#include "HAL/PlatformProcess.h" +#include "Misc/Paths.h" +#include "Misc/Guid.h" +#include "CrashReportConfig.h" + +#include "CrashReportAnalytics.h" +#include "AnalyticsEventAttribute.h" +#include "IAnalyticsProviderET.h" +#include "Misc/EngineBuildSettings.h" + +// #CrashReport: 2015-07-23 Move crashes from C:\Users\[USER]\AppData\Local\Microsoft\Windows\WER\ReportQueue to C:\Users\[USER]\AppData\Local\CrashReportClient\Saved + +/*----------------------------------------------------------------------------- + FCrashProperty +-----------------------------------------------------------------------------*/ + +FCrashProperty::FCrashProperty( const FString& InMainCategory, const FString& InSecondCategory, FPrimaryCrashProperties* InOwner ) +: Owner( InOwner ) +, CachedValue( TEXT("") ) +, MainCategory( InMainCategory ) +, SecondCategory( InSecondCategory ) +, bSet( false ) +{ + +} + +FCrashProperty& FCrashProperty::operator=(const FString& NewValue) +{ + bSet = true; + CachedValue = NewValue; + Owner->SetCrashProperty( MainCategory, SecondCategory, CachedValue ); + return *this; +} + +FCrashProperty& FCrashProperty::operator=(const TCHAR* NewValue) +{ + bSet = true; + CachedValue = NewValue; + Owner->SetCrashProperty( MainCategory, SecondCategory, CachedValue ); + return *this; +} + + +FCrashProperty& FCrashProperty::operator=(const TArray& NewValue) +{ + bSet = true; + CachedValue = Owner->EncodeArrayStringAsXMLString( NewValue ); + Owner->SetCrashProperty( MainCategory, SecondCategory, CachedValue ); + return *this; +} + + +FCrashProperty& FCrashProperty::operator=(const bool NewValue) +{ + bSet = true; + CachedValue = NewValue ? TEXT( "1" ) : TEXT( "0" ); + Owner->SetCrashProperty( MainCategory, SecondCategory, CachedValue ); + return *this; +} + +FCrashProperty& FCrashProperty::operator=(const int64 NewValue) +{ + bSet = true; + CachedValue = Lex::ToString( NewValue ); + Owner->SetCrashProperty( MainCategory, SecondCategory, CachedValue ); + return *this; +} + +const FString& FCrashProperty::AsString() const +{ + if (!bSet) + { + Owner->GetCrashProperty( CachedValue, MainCategory, SecondCategory ); + bSet = true; + } + return CachedValue; +} + + +bool FCrashProperty::AsBool() const +{ + return AsString().ToBool(); +} + +int64 FCrashProperty::AsInt64() const +{ + int64 Value = 0; + TTypeFromString::FromString( Value, *AsString() ); + return Value; +} + +/*----------------------------------------------------------------------------- + FPrimaryCrashProperties +-----------------------------------------------------------------------------*/ + +FPrimaryCrashProperties* FPrimaryCrashProperties::Singleton = nullptr; + +FPrimaryCrashProperties::FPrimaryCrashProperties() + // At this moment only these properties can be changed by the crash report client. + : EngineModeEx( FGenericCrashContext::RuntimePropertiesTag, TEXT("EngineModeEx"), this ) + , PlatformFullName( FGenericCrashContext::RuntimePropertiesTag, TEXT( "PlatformFullName" ), this ) + , CommandLine( FGenericCrashContext::RuntimePropertiesTag, TEXT( "CommandLine" ), this ) + , UserName( FGenericCrashContext::RuntimePropertiesTag, TEXT("UserName"), this ) + , LoginId( FGenericCrashContext::RuntimePropertiesTag, TEXT( "LoginId" ), this ) + , EpicAccountId( FGenericCrashContext::RuntimePropertiesTag, TEXT( "EpicAccountId" ), this ) + , GameSessionID( FGenericCrashContext::RuntimePropertiesTag, TEXT( "GameSessionID" ), this ) + // Multiline properties + , CallStack( FGenericCrashContext::RuntimePropertiesTag, TEXT( "CallStack" ), this ) + , SourceContext( FGenericCrashContext::RuntimePropertiesTag, TEXT( "SourceContext" ), this ) + , Modules( FGenericCrashContext::RuntimePropertiesTag, TEXT( "Modules" ), this ) + , UserDescription( FGenericCrashContext::RuntimePropertiesTag, TEXT( "UserDescription" ), this ) + , UserActivityHint( FGenericCrashContext::RuntimePropertiesTag, TEXT( "UserActivityHint" ), this ) + , ErrorMessage( FGenericCrashContext::RuntimePropertiesTag, TEXT( "ErrorMessage" ), this ) + , FullCrashDumpLocation( FGenericCrashContext::RuntimePropertiesTag, TEXT( "FullCrashDumpLocation" ), this ) + , TimeOfCrash( FGenericCrashContext::RuntimePropertiesTag, TEXT( "TimeOfCrash" ), this ) + , bAllowToBeContacted( FGenericCrashContext::RuntimePropertiesTag, TEXT( "bAllowToBeContacted" ), this ) + , CrashReporterMessage( FGenericCrashContext::RuntimePropertiesTag, TEXT( "CrashReporterMessage" ), this ) + , PlatformCallbackResult(FGenericCrashContext::PlatformPropertiesTag, TEXT("PlatformCallbackResult"), this) + , CrashReportClientVersion(FGenericCrashContext::RuntimePropertiesTag, TEXT("CrashReportClientVersion"), this) + , XmlFile( nullptr ) +{ + CrashVersion = ECrashDescVersions::VER_1_NewCrashFormat; + CrashDumpMode = ECrashDumpMode::Default; + bHasMiniDumpFile = false; + bHasLogFile = false; + bHasPrimaryData = false; +} + +void FPrimaryCrashProperties::Shutdown() +{ + delete Get(); +} + +void FPrimaryCrashProperties::UpdateIDs() +{ + const bool bAddPersonalData = FCrashReportConfig::Get().GetAllowToBeContacted() || FEngineBuildSettings::IsInternalBuild(); + bAllowToBeContacted = bAddPersonalData; + if (bAddPersonalData) + { + // The Epic ID can be looked up from this ID. + EpicAccountId = FPlatformMisc::GetEpicAccountId(); + } + else + { + EpicAccountId = FString(); + } + + // Add real user name only if log files were allowed since the user name is in the log file and the user consented to sending this information. + const bool bSendUserName = FCrashReportConfig::Get().GetSendLogFile() || FEngineBuildSettings::IsInternalBuild(); + if (bSendUserName) + { + // Remove periods from user names to match AutoReporter user names + // The name prefix is read by CrashRepository.AddNewCrash in the website code + UserName = FString( FPlatformProcess::UserName() ).Replace( TEXT( "." ), TEXT( "" ) ); + } + else + { + UserName = FString(); + } + + LoginId = FPlatformMisc::GetLoginId(); +} + +void FPrimaryCrashProperties::ReadXML( const FString& CrashContextFilepath ) +{ + XmlFilepath = CrashContextFilepath; + XmlFile = new FXmlFile( XmlFilepath ); + TimeOfCrash = FDateTime::UtcNow().GetTicks(); + UpdateIDs(); +} + +void FPrimaryCrashProperties::SetCrashGUID( const FString& Filepath ) +{ + FString CrashDirectory = FPaths::GetPath( Filepath ); + FPaths::NormalizeDirectoryName( CrashDirectory ); + // Grab the last component... + CrashGUID = FPaths::GetCleanFilename( CrashDirectory ); +} + +FString FPrimaryCrashProperties::EncodeArrayStringAsXMLString( const TArray& ArrayString ) const +{ + const FString Encoded = FString::Join( ArrayString, TEXT("\n") ); + return Encoded; +} + +/** + * @EventName CrashReportClient.ReportEnsure + * + * @Trigger Sends just before the CrashReportClient attempts to upload an ensure (a non-fatal error NOT a crash) report + * + * @Type Static + * @Owner Chris.Wood + * + * @EventParam bHasPrimaryData - Whether the crash loaded data successfully from a crash context or legacy metadata file that was saved by the crashed process ("true" or "false") + * @EventParam CrashVersion" - Describes the version of the crash data pipeline we used on the client side (1 = Legacy metadata based, 2 = unused, 3 = New crash context based) + * @EventParam CrashGUID - GUID for this event generated by the crashed process (e.g. Windows format is UE4CC-Windows-1F07494140C2669B52AC96A1C4D20F83_0000 with the last four digits representing the index of event within a single session) + * @EventParam PlatformCallbackResult - Platform-specific UE4 Core value. (integer) + * @EventParam GameName - The name of the game that crashed from FApp::GetGameName(). (e.g. UE4-QAGame) + * @EventParam EngineVersion - The engine version of the crashed process from FEngineVersion::Current(). (e.g. 4.13.1-3142249+++UE4+Release-4.13) + * @EventParam CrashReportClientVersion - CrashReportClient version, set in its config. (e.g. "1.0.0") + * @EventParam LoginID - Unique string associated with the login account of the current machine from FPlatformMisc::GetLoginId(). + * @EventParam UserName - Username of the user of the process that crashed from FPlatformProcess::UserName(). + * @EventParam EpicAccountId - Epic account ID for the user who last used the Launcher on this machine. + * @EventParam Platform - Detailed platform name string. (e.g. "Win64 [Windows 7 Service Pack 1 64b]") + * @EventParam TimeOfCrash - Time in UTC that the crash was read by the Crash Report Client in raw ticks (e.g. "636153351834530000", ticks are 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001) + * @EventParam EngineMode - The type of process that crashed ("Commandlet", "Game", "Editor" or "Server") + * @EventParam EngineModeEx - The "vanilla" status of the engine, whether it's a totally standard, unmodified Epic-distributed build. ("Unset", "Vanilla" or "Dirty") + * @EventParam AppDefaultLocale - The ICU default locale string or "en" if ICU is not enabled. + * @EventParam UserActivityHint - Application-specific user activity string, if set in the crashed process. The meaning is game/app-specific. + * @EventParam GameSessionID - Application-specific session Id, if set in the crashed process. + * @EventParam DeploymentName - Deployment name, also known as EpicApp. (e.g. "DevPlaytest", "PublicTest", "Live", etc) + */ + +/** + * @EventName CrashReportClient.ReportCrash + * + * @Trigger Sends just before the CrashReportClient attempts to upload a crash report + * + * @Type Static + * @Owner Chris.Wood + * + * @EventParam bHasPrimaryData - Whether the crash loaded data successfully from a crash context or legacy metadata file that was saved by the crashed process ("true" or "false") + * @EventParam CrashVersion" - Describes the version of the crash data pipeline we used on the client side (1 = Legacy metadata based, 2 = unused, 3 = New crash context based) + * @EventParam CrashGUID - GUID for this event generated by the crashed process (e.g. Windows format is UE4CC-Windows-1F07494140C2669B52AC96A1C4D20F83_0000 with the last four digits representing the index of event within a single session) + * @EventParam PlatformCallbackResult - Platform-specific UE4 Core value. (integer) + * @EventParam GameName - The name of the game that crashed from FApp::GetGameName(). (e.g. UE4-QAGame) + * @EventParam EngineVersion - The engine version of the crashed process from FEngineVersion::Current(). (e.g. 4.13.1-3142249+++UE4+Release-4.13) + * @EventParam CrashReportClientVersion - CrashReportClient version, set in its config. (e.g. "1.0.0") + * @EventParam LoginID - Unique string associated with the login account of the current machine from FPlatformMisc::GetLoginId(). + * @EventParam UserName - Username of the user of the process that crashed from FPlatformProcess::UserName(). + * @EventParam EpicAccountId - Epic account ID for the user who last used the Launcher on this machine. + * @EventParam Platform - Detailed platform name string. (e.g. "Win64 [Windows 7 Service Pack 1 64b]") + * @EventParam TimeOfCrash - Time in UTC that the crash was read by the Crash Report Client in raw ticks (e.g. "636153351834530000", ticks are 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001) + * @EventParam EngineMode - The type of process that crashed ("Commandlet", "Game", "Editor" or "Server") + * @EventParam EngineModeEx - The "vanilla" status of the engine, whether it's a totally standard, unmodified Epic-distributed build. ("Unset", "Vanilla" or "Dirty") + * @EventParam AppDefaultLocale - The ICU default locale string or "en" if ICU is not enabled. + * @EventParam UserActivityHint - Application-specific user activity string, if set in the crashed process. The meaning is game/app-specific. + * @EventParam GameSessionID - Application-specific session Id, if set in the crashed process. + * @EventParam DeploymentName - Deployment name, also known as EpicApp. (e.g. "DevPlaytest", "PublicTest", "Live", etc) + */ +void FPrimaryCrashProperties::SendPreUploadAnalytics() +{ + TArray CrashAttributes; + MakeCrashEventAttributes(CrashAttributes); + + if (FCrashReportAnalytics::IsAvailable()) + { + if (bIsEnsure) + { + FCrashReportAnalytics::GetProvider().RecordEvent(TEXT("CrashReportClient.ReportEnsure"), CrashAttributes); + } + else + { + FCrashReportAnalytics::GetProvider().RecordEvent(TEXT("CrashReportClient.ReportCrash"), CrashAttributes); + } + } +} + +/** + * @EventName CrashReportClient.ReportEnsureUploaded + * + * @Trigger Sends after the CrashReportClient successfully uploads an ensure (a non-fatal error NOT a crash) report. + * + * @Type Static + * @Owner Chris.Wood + * + * @EventParam bHasPrimaryData - Whether the crash loaded data successfully from a crash context or legacy metadata file that was saved by the crashed process ("true" or "false") + * @EventParam CrashVersion" - Describes the version of the crash data pipeline we used on the client side (1 = Legacy metadata based, 2 = unused, 3 = New crash context based) + * @EventParam CrashGUID - GUID for this event generated by the crashed process (e.g. Windows format is UE4CC-Windows-1F07494140C2669B52AC96A1C4D20F83_0000 with the last four digits representing the index of event within a single session) + * @EventParam PlatformCallbackResult - Platform-specific UE4 Core value. (integer) + * @EventParam GameName - The name of the game that crashed from FApp::GetGameName(). (e.g. UE4-QAGame) + * @EventParam EngineVersion - The engine version of the crashed process from FEngineVersion::Current(). (e.g. 4.13.1-3142249+++UE4+Release-4.13) + * @EventParam CrashReportClientVersion - CrashReportClient version, set in its config. (e.g. "1.0.0") + * @EventParam LoginID - Unique string associated with the login account of the current machine from FPlatformMisc::GetLoginId(). + * @EventParam UserName - Username of the user of the process that crashed from FPlatformProcess::UserName(). + * @EventParam EpicAccountId - Epic account ID for the user who last used the Launcher on this machine. + * @EventParam Platform - Detailed platform name string. (e.g. "Win64 [Windows 7 Service Pack 1 64b]") + * @EventParam TimeOfCrash - Time in UTC that the crash was read by the Crash Report Client in raw ticks (e.g. "636153351834530000", ticks are 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001) + * @EventParam EngineMode - The type of process that crashed ("Commandlet", "Game", "Editor" or "Server") + * @EventParam EngineModeEx - The "vanilla" status of the engine, whether it's a totally standard, unmodified Epic-distributed build. ("Unset", "Vanilla" or "Dirty") + * @EventParam AppDefaultLocale - The ICU default locale string or "en" if ICU is not enabled. + * @EventParam UserActivityHint - Application-specific user activity string, if set in the crashed process. The meaning is game/app-specific. + * @EventParam GameSessionID - Application-specific session Id, if set in the crashed process. + * @EventParam DeploymentName - Deployment name, also known as EpicApp. (e.g. "DevPlaytest", "PublicTest", "Live", etc) + * + * @Comments These events should exactly match corresponding CrashReportClient.ReportEnsure events that the CRC sent before the upload started. + * This event will be missing if the upload failed for any reason so the difference between the event counts should tell you the success rate. + */ + +/** + * @EventName CrashReportClient.ReportCrashUploaded + * + * @Trigger Sends after the CrashReportClient successfully uploads a crash report. + * + * @Type Static + * @Owner Chris.Wood + * + * @EventParam bHasPrimaryData - Whether the crash loaded data successfully from a crash context or legacy metadata file that was saved by the crashed process ("true" or "false") + * @EventParam CrashVersion" - Describes the version of the crash data pipeline we used on the client side (1 = Legacy metadata based, 2 = unused, 3 = New crash context based) + * @EventParam CrashGUID - GUID for this event generated by the crashed process (e.g. Windows format is UE4CC-Windows-1F07494140C2669B52AC96A1C4D20F83_0000 with the last four digits representing the index of event within a single session) + * @EventParam PlatformCallbackResult - Platform-specific UE4 Core value. (integer) + * @EventParam GameName - The name of the game that crashed from FApp::GetGameName(). (e.g. UE4-QAGame) + * @EventParam EngineVersion - The engine version of the crashed process from FEngineVersion::Current(). (e.g. 4.13.1-3142249+++UE4+Release-4.13) + * @EventParam CrashReportClientVersion - CrashReportClient version, set in its config. (e.g. "1.0.0") + * @EventParam LoginID - Unique string associated with the login account of the current machine from FPlatformMisc::GetLoginId(). + * @EventParam UserName - Username of the user of the process that crashed from FPlatformProcess::UserName(). + * @EventParam EpicAccountId - Epic account ID for the user who last used the Launcher on this machine. + * @EventParam Platform - Detailed platform name string. (e.g. "Win64 [Windows 7 Service Pack 1 64b]") + * @EventParam TimeOfCrash - Time in UTC that the crash was read by the Crash Report Client in raw ticks (e.g. "636153351834530000", ticks are 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001) + * @EventParam EngineMode - The type of process that crashed ("Commandlet", "Game", "Editor" or "Server") + * @EventParam EngineModeEx - The "vanilla" status of the engine, whether it's a totally standard, unmodified Epic-distributed build. ("Unset", "Vanilla" or "Dirty") + * @EventParam AppDefaultLocale - The ICU default locale string or "en" if ICU is not enabled. + * @EventParam UserActivityHint - Application-specific user activity string, if set in the crashed process. The meaning is game/app-specific. + * @EventParam GameSessionID - Application-specific session Id, if set in the crashed process. + * @EventParam DeploymentName - Deployment name, also known as EpicApp. (e.g. "DevPlaytest", "PublicTest", "Live", etc) + * + * @Comments These events should exactly match corresponding CrashReportClient.ReportCrash events that the CRC sent before the upload started. + * This event will be missing if the upload failed for any reason so the difference between the event counts should tell you the success rate. + */ +void FPrimaryCrashProperties::SendPostUploadAnalytics() +{ + TArray CrashAttributes; + MakeCrashEventAttributes(CrashAttributes); + + if (FCrashReportAnalytics::IsAvailable()) + { + // Connect the crash report client analytics provider. + IAnalyticsProvider& Analytics = FCrashReportAnalytics::GetProvider(); + + if (bIsEnsure) + { + Analytics.RecordEvent(TEXT("CrashReportClient.ReportEnsureUploaded"), CrashAttributes); + } + else + { + Analytics.RecordEvent(TEXT("CrashReportClient.ReportCrashUploaded"), CrashAttributes); + } + } +} + +void FPrimaryCrashProperties::MakeCrashEventAttributes(TArray& OutCrashAttributes) +{ + OutCrashAttributes.Add(FAnalyticsEventAttribute(TEXT("bHasPrimaryData"), bHasPrimaryData)); + OutCrashAttributes.Add(FAnalyticsEventAttribute(TEXT("CrashVersion"), (int32)CrashVersion)); + OutCrashAttributes.Add(FAnalyticsEventAttribute(TEXT("CrashGUID"), CrashGUID)); + OutCrashAttributes.Add(FAnalyticsEventAttribute(TEXT("PlatformCallbackResult"), PlatformCallbackResult.AsString())); + + // AppID = GameName + OutCrashAttributes.Add(FAnalyticsEventAttribute(TEXT("GameName"), GameName)); + + // AppVersion = EngineVersion + OutCrashAttributes.Add(FAnalyticsEventAttribute(TEXT("EngineVersion"), EngineVersion.ToString())); + + OutCrashAttributes.Add(FAnalyticsEventAttribute(TEXT("CrashReportClientVersion"), CrashReportClientVersion.AsString())); + + // @see UpdateIDs() + OutCrashAttributes.Add(FAnalyticsEventAttribute(TEXT("LoginID"), LoginId.AsString())); + OutCrashAttributes.Add(FAnalyticsEventAttribute(TEXT("UserName"), UserName.AsString())); + OutCrashAttributes.Add(FAnalyticsEventAttribute(TEXT("EpicAccountId"), EpicAccountId.AsString())); + + OutCrashAttributes.Add(FAnalyticsEventAttribute(TEXT("Platform"), PlatformFullName.AsString())); + OutCrashAttributes.Add(FAnalyticsEventAttribute(TEXT("TimeOfCrash"), TimeOfCrash.AsString())); + OutCrashAttributes.Add(FAnalyticsEventAttribute(TEXT("EngineMode"), EngineMode)); + OutCrashAttributes.Add(FAnalyticsEventAttribute(TEXT("EngineModeEx"), EngineModeEx.AsString())); + OutCrashAttributes.Add(FAnalyticsEventAttribute(TEXT("AppDefaultLocale"), AppDefaultLocale)); + + OutCrashAttributes.Add(FAnalyticsEventAttribute(TEXT("UserActivityHint"), UserActivityHint.AsString())); + OutCrashAttributes.Add(FAnalyticsEventAttribute(TEXT("GameSessionID"), GameSessionID.AsString())); + OutCrashAttributes.Add(FAnalyticsEventAttribute(TEXT("DeploymentName"), DeploymentName)); +} + +void FPrimaryCrashProperties::Save() +{ + XmlFile->Save( XmlFilepath ); +} + +/*----------------------------------------------------------------------------- + FCrashContextReader +-----------------------------------------------------------------------------*/ + +FCrashContext::FCrashContext( const FString& CrashContextFilepath ) +{ + ReadXML( CrashContextFilepath ); + + const bool bIsValid = XmlFile->IsValid(); + if (bIsValid) + { + RestartCommandLine = CommandLine.AsString(); + + // Setup properties required for the analytics. + GetCrashProperty(CrashVersion, FGenericCrashContext::RuntimePropertiesTag, TEXT("CrashVersion")); + GetCrashProperty(CrashGUID, FGenericCrashContext::RuntimePropertiesTag, TEXT("CrashGUID")); + GetCrashProperty(CrashDumpMode, FGenericCrashContext::RuntimePropertiesTag, TEXT("CrashDumpMode")); + GetCrashProperty(GameName, FGenericCrashContext::RuntimePropertiesTag, TEXT("GameName")); + GetCrashProperty(ExecutableName, FGenericCrashContext::RuntimePropertiesTag, TEXT("ExecutableName")); + GetCrashProperty(EngineVersion, FGenericCrashContext::RuntimePropertiesTag, TEXT("EngineVersion")); + + GetCrashProperty( BaseDir, FGenericCrashContext::RuntimePropertiesTag, TEXT( "BaseDir" ) ); + FString Misc_OSVersionMajor; + GetCrashProperty( Misc_OSVersionMajor, FGenericCrashContext::RuntimePropertiesTag, TEXT( "Misc.OSVersionMajor" ) ); + FString Misc_OSVersionMinor; + GetCrashProperty( Misc_OSVersionMinor, FGenericCrashContext::RuntimePropertiesTag, TEXT( "Misc.OSVersionMinor" ) ); + + bool Misc_Is64bitOperatingSystem = false; + GetCrashProperty( Misc_Is64bitOperatingSystem, FGenericCrashContext::RuntimePropertiesTag, TEXT( "Misc.Is64bitOperatingSystem" ) ); + + // Extract the Platform component. + TArray SubDirs; + BaseDir.ParseIntoArray( SubDirs, TEXT( "/" ), true ); + const int SubDirsNum = SubDirs.Num(); + const FString PlatformName = SubDirsNum > 0 ? SubDirs[SubDirsNum - 1] : TEXT( "" ); + if (Misc_OSVersionMajor.Len() > 0) + { + PlatformFullName = FString::Printf( TEXT( "%s [%s %s %s]" ), *PlatformName, *Misc_OSVersionMajor, *Misc_OSVersionMinor, Misc_Is64bitOperatingSystem ? TEXT( "64b" ) : TEXT( "32b" ) ); + } + else + { + PlatformFullName = PlatformName; + } + + GetCrashProperty( EngineMode, FGenericCrashContext::RuntimePropertiesTag, TEXT( "EngineMode" ) ); + GetCrashProperty( DeploymentName, FGenericCrashContext::RuntimePropertiesTag, TEXT( "DeploymentName" ) ); + GetCrashProperty( AppDefaultLocale, FGenericCrashContext::RuntimePropertiesTag, TEXT( "AppDefaultLocale" ) ); + GetCrashProperty( bIsEnsure, FGenericCrashContext::RuntimePropertiesTag, TEXT("IsEnsure")); + + if (CrashDumpMode == ECrashDumpMode::FullDump) + { + // Set the full dump crash location when we have a full dump. + const FString LocationForBranch = FCrashReportConfig::Get().GetFullCrashDumpLocationForBranch( EngineVersion.GetBranch() ); + if (!LocationForBranch.IsEmpty()) + { + FullCrashDumpLocation = LocationForBranch / CrashGUID + TEXT("_") + EngineVersion.ToString(); + } + } + + bHasPrimaryData = true; + } +} + +/*----------------------------------------------------------------------------- + FCrashDescription +-----------------------------------------------------------------------------*/ + +FCrashWERContext::FCrashWERContext( const FString& WERXMLFilepath ) + : FPrimaryCrashProperties() +{ + ReadXML( WERXMLFilepath ); + CrashGUID = FPaths::GetCleanFilename( FPaths::GetPath( WERXMLFilepath ) ); + + const bool bIsValid = XmlFile->IsValid(); + if (bIsValid) + { + FString BuildVersion; + FString BranchName; + uint32 BuiltFromCL = 0; + int EngineVersionComponents = 0; + + GetCrashProperty( GameName, TEXT( "ProblemSignatures" ), TEXT( "Parameter0" ) ); + + GetCrashProperty( BuildVersion, TEXT( "ProblemSignatures" ), TEXT( "Parameter1" ) ); + if (!BuildVersion.IsEmpty()) + { + EngineVersionComponents++; + } + + FString Parameter8Value; + GetCrashProperty( Parameter8Value, TEXT( "ProblemSignatures" ), TEXT( "Parameter8" ) ); + if (!Parameter8Value.IsEmpty()) + { + TArray ParsedParameters8; + Parameter8Value.ParseIntoArray( ParsedParameters8, TEXT( "!" ), false ); + + if (ParsedParameters8.Num() > 1) + { + CommandLine = FGenericCrashContext::UnescapeXMLString( ParsedParameters8[1] ); + CrashDumpMode = CommandLine.AsString().Contains( TEXT( "-fullcrashdump" ) ) ? ECrashDumpMode::FullDump : ECrashDumpMode::Default; + } + + if (ParsedParameters8.Num() > 2) + { + ErrorMessage = ParsedParameters8[2]; + } + } + + RestartCommandLine = CommandLine.AsString(); + + FString Parameter9Value; + GetCrashProperty( Parameter9Value, TEXT( "ProblemSignatures" ), TEXT( "Parameter9" ) ); + if (!Parameter9Value.IsEmpty()) + { + TArray ParsedParameters9; + Parameter9Value.ParseIntoArray( ParsedParameters9, TEXT( "!" ), false ); + + if (ParsedParameters9.Num() > 0) + { + BranchName = ParsedParameters9[0].Replace( TEXT( "+" ), TEXT( "/" ) ); + + const FString DepotRoot = TEXT( "//depot/" ); + if (BranchName.StartsWith( DepotRoot )) + { + BranchName = BranchName.Mid( DepotRoot.Len() ); + } + EngineVersionComponents++; + } + + if (ParsedParameters9.Num() > 1) + { + const FString BaseDirectory = ParsedParameters9[1]; + + TArray SubDirs; + BaseDirectory.ParseIntoArray( SubDirs, TEXT( "/" ), true ); + const int SubDirsNum = SubDirs.Num(); + const FString PlatformName = SubDirsNum > 0 ? SubDirs[SubDirsNum - 1] : TEXT( "" ); + + FString Product; + GetCrashProperty( Product, TEXT( "OSVersionInformation" ), TEXT( "Product" ) ); + if (Product.Len() > 0) + { + PlatformFullName = FString::Printf( TEXT( "%s [%s]" ), *PlatformName, *Product ); + } + else + { + PlatformFullName = PlatformName; + } + } + + if (ParsedParameters9.Num() > 2) + { + EngineMode = ParsedParameters9[2]; + } + + if (ParsedParameters9.Num() > 3) + { + TTypeFromString::FromString( BuiltFromCL, *ParsedParameters9[3] ); + EngineVersionComponents++; + } + } + + // We have all three components of the engine version, so initialize it. + if (EngineVersionComponents == 3) + { + InitializeEngineVersion( BuildVersion, BranchName, BuiltFromCL ); + } + + GetCrashProperty(DeploymentName, TEXT("DynamicSignatures"), TEXT("DeploymentName")); + GetCrashProperty(bIsEnsure, TEXT("DynamicSignatures"), TEXT("IsEnsure")); + + FString EngineModeExString; + GetCrashProperty(EngineModeExString, TEXT("DynamicSignatures"), TEXT("EngineModeEx")); + EngineModeEx = EngineModeExString; + + bHasPrimaryData = true; + } +} + +void FCrashWERContext::InitializeEngineVersion( const FString& BuildVersion, const FString& BranchName, uint32 BuiltFromCL ) +{ + uint16 Major = 0; + uint16 Minor = 0; + uint16 Patch = 0; + + TArray ParsedBuildVersion; + BuildVersion.ParseIntoArray( ParsedBuildVersion, TEXT( "." ), false ); + + if (ParsedBuildVersion.Num() >= 3) + { + TTypeFromString::FromString( Patch, *ParsedBuildVersion[2] ); + } + + if (ParsedBuildVersion.Num() >= 2) + { + TTypeFromString::FromString( Minor, *ParsedBuildVersion[1] ); + } + + if (ParsedBuildVersion.Num() >= 1) + { + TTypeFromString::FromString( Major, *ParsedBuildVersion[0] ); + } + + EngineVersion = FEngineVersion( Major, Minor, Patch, BuiltFromCL, BranchName ); +} diff --git a/Engine/Source/Developer/CrashReportHelper/Private/CrashReportAnalytics.cpp b/Engine/Source/Developer/CrashReportHelper/Private/CrashReportAnalytics.cpp new file mode 100644 index 000000000000..77e157072d17 --- /dev/null +++ b/Engine/Source/Developer/CrashReportHelper/Private/CrashReportAnalytics.cpp @@ -0,0 +1,64 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "CrashReportAnalytics.h" +#include "Misc/Guid.h" + +#include "AnalyticsET.h" +#include "IAnalyticsProviderET.h" + +bool FCrashReportAnalytics::bIsInitialized; +TSharedPtr FCrashReportAnalytics::Analytics; + +/** + * Default config func that essentially tells the crash reporter to disable analytics. + */ +FAnalyticsET::Config DefaultAnalyticsConfigFunc() +{ + return FAnalyticsET::Config(); +} + +/** +* Engine analytics config to initialize the crash reporter analytics provider. +* External code should bind this delegate if crash reporter analytics are desired, +* preferably in private code that won't be redistributed. +*/ +TFunction& GetCrashReportAnalyticsConfigFunc() +{ + static TFunction Config = &DefaultAnalyticsConfigFunc; + return Config; +} + +/** + * On-demand construction of the singleton. + */ +IAnalyticsProviderET& FCrashReportAnalytics::GetProvider() +{ + checkf(bIsInitialized && Analytics.IsValid(), TEXT("FCrashReportAnalytics::GetProvider called outside of Initialize/Shutdown.")); + return *Analytics.Get(); +} + +void FCrashReportAnalytics::Initialize() +{ + checkf(!bIsInitialized, TEXT("FCrashReportAnalytics::Initialize called more than once.")); + + FAnalyticsET::Config Config = GetCrashReportAnalyticsConfigFunc()(); + if (!Config.APIServerET.IsEmpty()) + { + // Connect the engine analytics provider (if there is a configuration delegate installed) + Analytics = FAnalyticsET::Get().CreateAnalyticsProvider(Config); + if( Analytics.IsValid() ) + { + Analytics->SetUserID(FString::Printf(TEXT("%s|%s|%s"), *FPlatformMisc::GetLoginId(), *FPlatformMisc::GetEpicAccountId(), *FPlatformMisc::GetOperatingSystemId())); + Analytics->StartSession(); + } + } + bIsInitialized = true; +} + + +void FCrashReportAnalytics::Shutdown() +{ + checkf(bIsInitialized, TEXT("FCrashReportAnalytics::Shutdown called outside of Initialize.")); + Analytics.Reset(); + bIsInitialized = false; +} diff --git a/Engine/Source/Developer/CrashReportHelper/Private/CrashReportAnalytics.h b/Engine/Source/Developer/CrashReportHelper/Private/CrashReportAnalytics.h new file mode 100644 index 000000000000..3107970ac9a7 --- /dev/null +++ b/Engine/Source/Developer/CrashReportHelper/Private/CrashReportAnalytics.h @@ -0,0 +1,40 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "Templates/UnrealTemplate.h" +#include "Templates/SharedPointer.h" + +class IAnalyticsProviderET; + +/** + * The public interface for the analytics provider singleton. + * For Epic builds, this will point to epic's internal analytics provider. + * For licensee builds, it will be NULL by default unless they provide their own + * configuration. + * + */ +class FCrashReportAnalytics : FNoncopyable +{ +public: + /** + * Return the provider instance. Not valid outside of Initialize/Shutdown calls. + * Note: must check IsAvailable() first else this code will assert if the provider is not valid. + */ + static IAnalyticsProviderET& GetProvider(); + /** Helper function to determine if the provider is valid. */ + static bool IsAvailable() + { + return Analytics.IsValid(); + } + /** Called to initialize the singleton. */ + static void Initialize(); + /** Called to shut down the singleton */ + static void Shutdown(); + +private: + static bool bIsInitialized; + static TSharedPtr Analytics; +}; + diff --git a/Engine/Source/Developer/CrashReportHelper/Private/CrashReportConfig.cpp b/Engine/Source/Developer/CrashReportHelper/Private/CrashReportConfig.cpp new file mode 100644 index 000000000000..74a2c544f364 --- /dev/null +++ b/Engine/Source/Developer/CrashReportHelper/Private/CrashReportConfig.cpp @@ -0,0 +1,171 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "CrashReportConfig.h" +#include "Logging/LogMacros.h" +#include "Misc/ConfigCacheIni.h" +#include "Misc/App.h" +#include "GenericPlatform/GenericPlatformCrashContext.h" + +DEFINE_LOG_CATEGORY(CrashReportLog); + +FCrashReportConfig::FCrashReportConfig() + : DiagnosticsFilename( TEXT( "Diagnostics.txt" ) ) + , SectionName( TEXT( "CrashReportConfig" ) ) +{ + const bool bUnattended = +#if CRASH_REPORT_UNATTENDED_ONLY + true; +#else + FApp::IsUnattended(); +#endif // CRASH_REPORT_UNATTENDED_ONLY + + if (!GConfig->GetString(*SectionName, TEXT("CrashReportVersion"), CrashReportVersion, GEngineIni)) + { + CrashReportVersion = TEXT("0.0.0"); + } + UE_LOG(CrashReportLog, Log, TEXT("CrashReportVersion=%s"), *CrashReportVersion); + + if (!GConfig->GetString( *SectionName, TEXT( "CrashReportReceiverIP" ), CrashReportReceiverIP, GEngineIni )) + { + // Use the default value (blank/disabled) + CrashReportReceiverIP = TEXT(""); + } + if (CrashReportReceiverIP.IsEmpty()) + { + UE_LOG(CrashReportLog, Log, TEXT("CrashReportReceiver disabled")); + } + else + { + UE_LOG(CrashReportLog, Log, TEXT("CrashReportReceiverIP: %s"), *CrashReportReceiverIP); + } + + if (!GConfig->GetString(*SectionName, TEXT("DataRouterUrl"), DataRouterUrl, GEngineIni)) + { + // Use the default value. + DataRouterUrl = TEXT(""); + } + if (DataRouterUrl.IsEmpty()) + { + UE_LOG(CrashReportLog, Log, TEXT("DataRouter disabled")); + } + else + { + UE_LOG(CrashReportLog, Log, TEXT("DataRouterUrl: %s"), *DataRouterUrl); + } + + if (!GConfig->GetBool( TEXT( "CrashReportClient" ), TEXT( "bAllowToBeContacted" ), bAllowToBeContacted, GEngineIni )) + { + // Default to true when unattended when config is missing. This is mostly for dedicated servers that do not have config files for CRC. + if (bUnattended) + { + bAllowToBeContacted = true; + } + } + + if (!GConfig->GetBool( TEXT( "CrashReportClient" ), TEXT( "bSendLogFile" ), bSendLogFile, GEngineIni )) + { + // Default to true when unattended when config is missing. This is mostly for dedicated servers that do not have config files for CRC. + if (bUnattended) + { + bSendLogFile = true; + } + } + + if (!GConfig->GetInt(TEXT("CrashReportClient"), TEXT("UserCommentSizeLimit"), UserCommentSizeLimit, GEngineIni)) + { + UserCommentSizeLimit = 4000; + } + + FConfigFile EmptyConfigFile; + SetProjectConfigOverrides(EmptyConfigFile); + + ReadFullCrashDumpConfigurations(); +} + +void FCrashReportConfig::SetAllowToBeContacted( bool bNewValue ) +{ + bAllowToBeContacted = bNewValue; + GConfig->SetBool( *SectionName, TEXT( "bAllowToBeContacted" ), bAllowToBeContacted, GEngineIni ); +} + +void FCrashReportConfig::SetSendLogFile( bool bNewValue ) +{ + bSendLogFile = bNewValue; + GConfig->SetBool( *SectionName, TEXT( "bSendLogFile" ), bSendLogFile, GEngineIni ); +} + +void FCrashReportConfig::SetProjectConfigOverrides(const FConfigFile& InConfigFile) +{ + const FConfigSection* Section = InConfigFile.Find(FGenericCrashContext::ConfigSectionName); + + // Default to false (show the option) when config is missing. + bHideLogFilesOption = false; + + // Default to true (Allow the user to close without sending) when config is missing. + bIsAllowedToCloseWithoutSending = true; + + // Try to read values from override config file + if (Section != nullptr) + { + const FConfigValue* HideLogFilesOptionValue = Section->Find(TEXT("bHideLogFilesOption")); + if (HideLogFilesOptionValue != nullptr) + { + bHideLogFilesOption = FCString::ToBool(*HideLogFilesOptionValue->GetValue()); + } + + const FConfigValue* IsAllowedToCloseWithoutSendingValue = Section->Find(TEXT("bIsAllowedToCloseWithoutSending")); + if (IsAllowedToCloseWithoutSendingValue != nullptr) + { + bIsAllowedToCloseWithoutSending = FCString::ToBool(*IsAllowedToCloseWithoutSendingValue->GetValue()); + } + } +} + +const FString FCrashReportConfig::GetFullCrashDumpLocationForBranch( const FString& BranchName ) const +{ + for (const auto& It : FullCrashDumpConfigurations) + { + const bool bExactMatch = It.bExactMatch; + const FString IterBranch = It.BranchName.Replace(TEXT("+"), TEXT("/")); + if (bExactMatch && BranchName == IterBranch) + { + return It.Location; + } + else if (!bExactMatch && BranchName.Contains(IterBranch)) + { + return It.Location; + } + } + + return TEXT( "" ); +} + +FString FCrashReportConfig::GetKey( const FString& KeyName ) +{ + FString Result; + if (!GConfig->GetString( *SectionName, *KeyName, Result, GEngineIni )) + { + return TEXT( "" ); + } + return Result; +} + +void FCrashReportConfig::ReadFullCrashDumpConfigurations() +{ + for (int32 NumEntries = 0;; ++NumEntries) + { + FString Branch = GetKey( FString::Printf( TEXT( "FullCrashDump_%i_Branch" ), NumEntries ) ); + if (Branch.IsEmpty()) + { + break; + } + + const FString NetworkLocation = GetKey( FString::Printf( TEXT( "FullCrashDump_%i_Location" ), NumEntries ) ); + const bool bExactMatch = !Branch.EndsWith( TEXT( "*" ) ); + Branch.ReplaceInline( TEXT( "*" ), TEXT( "" ) ); + + FullCrashDumpConfigurations.Add( FFullCrashDumpEntry( Branch, NetworkLocation, bExactMatch ) ); + + UE_LOG(CrashReportLog, Log, TEXT( "FullCrashDump: %s, NetworkLocation: %s, bExactMatch:%i" ), *Branch, *NetworkLocation, bExactMatch ); + } +} diff --git a/Engine/Source/Developer/CrashReportHelper/Private/CrashReportUnattended.cpp b/Engine/Source/Developer/CrashReportHelper/Private/CrashReportUnattended.cpp new file mode 100644 index 000000000000..8232a0aed745 --- /dev/null +++ b/Engine/Source/Developer/CrashReportHelper/Private/CrashReportUnattended.cpp @@ -0,0 +1,86 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "CrashReportUnattended.h" +#include "Containers/Ticker.h" +#include "CrashReportConfig.h" +#include "CrashDescription.h" +#include "CrashReportAnalytics.h" + +FCrashReportUnattended::FCrashReportUnattended(FPlatformErrorReport& InErrorReport, bool InDeleteFiles) + : ReceiverUploader(FCrashReportConfig::Get().GetReceiverAddress()) + , DataRouterUploader(FCrashReportConfig::Get().GetDataRouterURL()) + , ErrorReport(InErrorReport) + , bDeleteReportFiles(InDeleteFiles) +{ + ErrorReport.TryReadDiagnosticsFile(); + + // Process the report synchronously + ErrorReport.DiagnoseReport(); + + // Update properties for the crash. + ErrorReport.SetPrimaryCrashProperties( *FPrimaryCrashProperties::Get() ); + + FCrashReportAnalytics::Initialize(); + + StartTicker(); +} + +bool FCrashReportUnattended::Tick(float UnusedDeltaTime) +{ + if (!FCrashUploadBase::IsInitialized()) + { + FCrashUploadBase::StaticInitialize(ErrorReport); + } + + if (ReceiverUploader.IsEnabled()) + { + if (!ReceiverUploader.IsUploadCalled()) + { + // Can be called only when we have all files. + ReceiverUploader.BeginUpload(ErrorReport); + } + + // IsWorkDone will always return true here (since ReceiverUploader can't finish until the diagnosis has been sent), but it + // has the side effect of joining the worker thread. + if (!ReceiverUploader.IsFinished()) + { + // More ticks, please + return true; + } + } + + if (DataRouterUploader.IsEnabled()) + { + if (!DataRouterUploader.IsUploadCalled()) + { + // Can be called only when we have all files. + DataRouterUploader.BeginUpload(ErrorReport); + } + + // IsWorkDone will always return true here (since DataRouterUploader can't finish until the diagnosis has been sent), but it + // has the side effect of joining the worker thread. + if (!DataRouterUploader.IsFinished()) + { + // More ticks, please + return true; + } + } + + if (bDeleteReportFiles) + { + ErrorReport.DeleteFiles(); + } + + // Shutdown analytics. + FCrashReportAnalytics::Shutdown(); + + FPrimaryCrashProperties::Shutdown(); + FPlatformErrorReport::ShutDown(); + + return false; +} + +void FCrashReportUnattended::StartTicker() +{ + FTicker::GetCoreTicker().AddTicker(FTickerDelegate::CreateRaw(this, &FCrashReportUnattended::Tick), 1.f); +} diff --git a/Engine/Source/Developer/CrashReportHelper/Private/CrashReportUtil.h b/Engine/Source/Developer/CrashReportHelper/Private/CrashReportUtil.h new file mode 100644 index 000000000000..ce3d7ff2f511 --- /dev/null +++ b/Engine/Source/Developer/CrashReportHelper/Private/CrashReportUtil.h @@ -0,0 +1,49 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "GenericPlatform/GenericPlatformFile.h" + + +/** + * Helper class for MakeDirectoryVisitor + */ +template +class FunctorDirectoryVisitor : public IPlatformFile::FDirectoryVisitor +{ +public: + /** + * Pass a directory or filename on to the user-provided functor + * @param FilenameOrDirectory Full path to a file or directory + * @param bIsDirectory Whether the path refers to a file or directory + * @return Whether to carry on iterating + */ + virtual bool Visit(const TCHAR* FilenameOrDirectory, bool bIsDirectory) override + { + return Functor(FilenameOrDirectory, bIsDirectory); + } + + /** + * Move the provided functor into this object + */ + FunctorDirectoryVisitor(FunctorType&& FunctorInstance) + : Functor(MoveTemp(FunctorInstance)) + { + } + +private: + /** User-provided functor */ + FunctorType Functor; +}; + +/** + * Convert a C++ functor into a IPlatformFile visitor object + * @param FunctorInstance Function object to call for each directory item + * @return Visitor object to be passed to platform directory visiting functions + */ +template +FunctorDirectoryVisitor MakeDirectoryVisitor(Functor&& FunctorInstance) +{ + return FunctorDirectoryVisitor(MoveTemp(FunctorInstance)); +} diff --git a/Engine/Source/Developer/CrashReportHelper/Private/CrashUpload.cpp b/Engine/Source/Developer/CrashReportHelper/Private/CrashUpload.cpp new file mode 100644 index 000000000000..57c02ef7f564 --- /dev/null +++ b/Engine/Source/Developer/CrashReportHelper/Private/CrashUpload.cpp @@ -0,0 +1,829 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "CrashUpload.h" +#include "HAL/FileManager.h" +#include "Misc/FileHelper.h" +#include "Internationalization/Internationalization.h" +#include "Misc/Guid.h" +#include "Serialization/MemoryWriter.h" +#include "Containers/Ticker.h" +#include "CrashReportConfig.h" + +#include "Interfaces/IHttpResponse.h" +#include "HttpModule.h" +#include "GenericPlatform/GenericPlatformHttp.h" +#include "PendingReports.h" +#include "CrashDescription.h" +#include "Misc/EngineBuildSettings.h" + +// Switched off CRR upload - Jun 2016 +#define PRIMARY_UPLOAD_RECEIVER 0 +#define PRIMARY_UPLOAD_DATAROUTER 1 + +#define LOCTEXT_NAMESPACE "CrashReportClient" + +namespace CrashUploadDefs +{ + const float PingTimeoutSeconds = 5.f; + // Ignore files bigger than 100MB; mini-dumps are smaller than this, but heap dumps can be very large + const int MaxFileSizeToUpload = 100 * 1024 * 1024; + + const FString APIKey(TEXT("CrashReporter")); + const FString AppEnvironmentInternal(TEXT("Dev")); + const FString AppEnvironmentExternal(TEXT("Release")); + const FString UploadType(TEXT("crashreports")); +} + +enum class ECompressedCrashFileHeader +{ + MAGIC = 0x7E1B83C1, +}; + +struct FCompressedCrashFile : FNoncopyable +{ + int32 CurrentFileIndex; + FString Filename; + TArray Filedata; + + FCompressedCrashFile(int32 InCurrentFileIndex, const FString& InFilename, const TArray& InFiledata) + : CurrentFileIndex(InCurrentFileIndex) + , Filename(InFilename) + , Filedata(InFiledata) + { + } + + /** Serialization operator. */ + friend FArchive& operator << (FArchive& Ar, FCompressedCrashFile& Data) + { + Ar << Data.CurrentFileIndex; + Data.Filename.SerializeAsANSICharArray(Ar, 260); + Ar << Data.Filedata; + return Ar; + } +}; + +struct FCompressedHeader +{ + FString DirectoryName; + FString FileName; + int32 UncompressedSize; + int32 FileCount; + + /** Serialization operator. */ + friend FArchive& operator << (FArchive& Ar, FCompressedHeader& Data) + { + Data.DirectoryName.SerializeAsANSICharArray(Ar, 260); + Data.FileName.SerializeAsANSICharArray(Ar, 260); + Ar << Data.UncompressedSize; + Ar << Data.FileCount; + return Ar; + } +}; + +struct FCompressedData +{ + TArray Data; + int32 CompressedSize; + int32 UncompressedSize; + int32 FileCount; +}; + +bool FCrashUploadBase::bInitialized = false; +TArray FCrashUploadBase::PendingReportDirectories; +TArray FCrashUploadBase::FailedReportDirectories; + +FCrashUploadBase::FCrashUploadBase() + : bUploadCalled(false) + , State(EUploadState::NotSet) + , PauseState(EUploadState::Ready) + , PendingReportDirectoryIndex(0) +{ + +} + +FCrashUploadBase::~FCrashUploadBase() +{ + UE_LOG(CrashReportLog, Log, TEXT("Final state (Receiver) = %s"), ToString(State)); +} + +void FCrashUploadBase::StaticInitialize(const FPlatformErrorReport& PlatformErrorReport) +{ + FPendingReports PendingReports; + //PendingReports.Add(*PlatformErrorReport.GetReportDirectoryLeafName()); + PendingReportDirectories = PendingReports.GetReportDirectories(); + PendingReports.Clear(); + PendingReports.Save(); +} + +void FCrashUploadBase::StaticShutdown() +{ + // Write failed uploads back to disk + FPendingReports ReportsForNextTime; + for (const FString& FailedReport : FailedReportDirectories) + { + ReportsForNextTime.Add(FailedReport); + } + ReportsForNextTime.Save(); +} + +bool FCrashUploadBase::CompressData(const TArray& InPendingFiles, FCompressedData& OutCompressedData, TArray& OutPostData, FCompressedHeader* OptionalHeader) +{ + UE_LOG(CrashReportLog, Log, TEXT("CompressAndSendData have %d pending files"), InPendingFiles.Num()); + + // Compress all files into one archive. + const int32 BufferSize = 32 * 1024 * 1024; + + TArray UncompressedData; + UncompressedData.Reserve(BufferSize); + FMemoryWriter MemoryWriter(UncompressedData, false, true); + + if (OptionalHeader != nullptr) + { + // Write dummy to fill correct size + MemoryWriter << *OptionalHeader; + } + + int32 CurrentFileIndex = 0; + + const FString FullCrashDumpLocation = FPrimaryCrashProperties::Get()->FullCrashDumpLocation.AsString(); + + // Loop to keep trying files until a send succeeds or we run out of files + for (const FString& PathOfFileToUpload : InPendingFiles) + { + const FString Filename = FPaths::GetCleanFilename(PathOfFileToUpload); + + const bool bValidFullDumpForCopy = Filename == FGenericCrashContext::UE4MinidumpName && + (FPrimaryCrashProperties::Get()->CrashDumpMode == ECrashDumpMode::FullDump || FPrimaryCrashProperties::Get()->CrashDumpMode == ECrashDumpMode::FullDumpAlways) && + FPrimaryCrashProperties::Get()->CrashVersion >= ECrashDescVersions::VER_3_CrashContext && + !FullCrashDumpLocation.IsEmpty(); + + if (bValidFullDumpForCopy) + { + const FString DestinationPath = FullCrashDumpLocation / FGenericCrashContext::UE4MinidumpName; + const bool bCreated = IFileManager::Get().MakeDirectory(*FullCrashDumpLocation, true); + if (!bCreated) + { + UE_LOG(CrashReportLog, Error, TEXT("Couldn't create directory for full crash dump %s"), *DestinationPath); + } + else + { + UE_LOG(CrashReportLog, Warning, TEXT("Copying full crash minidump to %s"), *DestinationPath); + IFileManager::Get().Copy(*DestinationPath, *PathOfFileToUpload, false); + } + + continue; + } + + if (IFileManager::Get().FileSize(*PathOfFileToUpload) > CrashUploadDefs::MaxFileSizeToUpload) + { + UE_LOG(CrashReportLog, Warning, TEXT("Skipping large crash report file")); + continue; + } + + if (!FFileHelper::LoadFileToArray(OutPostData, *PathOfFileToUpload)) + { + UE_LOG(CrashReportLog, Warning, TEXT("Failed to load crash report file")); + continue; + } + + const bool bSkipLogFile = !FCrashReportConfig::Get().GetSendLogFile() && PathOfFileToUpload.EndsWith(TEXT(".log")); + if (bSkipLogFile) + { + UE_LOG(CrashReportLog, Warning, TEXT("Skipping the %s"), *Filename); + continue; + } + + // Disabled due to issues with Mac not using the crash context. + /* + // Skip old WERInternalMetadata. + const bool bSkipXMLFile = PathOfFileToUpload.EndsWith( TEXT( ".xml" ) ); + if (bSkipXMLFile) + { + UE_LOG( CrashReportLog, Warning, TEXT( "Skipping the %s" ), *Filename ); + continue; + }*/ + + // Skip old Report.wer file. + const bool bSkipWERFile = PathOfFileToUpload.Contains(TEXT("Report.wer")); + if (bSkipWERFile) + { + UE_LOG(CrashReportLog, Warning, TEXT("Skipping the %s"), *Filename); + continue; + } + + // Skip old diagnostics.txt file, all data is stored in the CrashContext.runtime-xml + // Disabled due to issues with Mac not using the crash context. + /* + const bool bSkipDiagnostics = Filename == FCrashReportClientConfig::Get().GetDiagnosticsFilename(); + if (bSkipDiagnostics) + { + UE_LOG( CrashReportLog, Warning, TEXT( "Skipping the %s" ), *Filename ); + continue; + }*/ + + UE_LOG(CrashReportLog, Log, TEXT("CompressAndSendData compressing %d bytes ('%s')"), OutPostData.Num(), *PathOfFileToUpload); + + FCompressedCrashFile FileToCompress(CurrentFileIndex, Filename, OutPostData); + CurrentFileIndex++; + + MemoryWriter << FileToCompress; + } + + if (OptionalHeader != nullptr) + { + FMemoryWriter MemoryHeaderWriter(UncompressedData, false, true); + + OptionalHeader->UncompressedSize = UncompressedData.Num(); + OptionalHeader->FileCount = CurrentFileIndex; + + MemoryHeaderWriter << *OptionalHeader; + } + + int UncompressedSize = UncompressedData.Num(); + + uint8* CompressedDataRaw = new uint8[UncompressedSize]; + + OutCompressedData.FileCount = CurrentFileIndex; + OutCompressedData.CompressedSize = UncompressedSize; + OutCompressedData.UncompressedSize = UncompressedSize; + const bool bResult = FCompression::CompressMemory(COMPRESS_ZLIB, CompressedDataRaw, OutCompressedData.CompressedSize, UncompressedData.GetData(), OutCompressedData.UncompressedSize); + if (bResult) + { + // Copy compressed data into the array. + OutCompressedData.Data.Append(CompressedDataRaw, OutCompressedData.CompressedSize); + delete[] CompressedDataRaw; + CompressedDataRaw = nullptr; + } + + return bResult; +} + +const TCHAR* FCrashUploadBase::ToString(EUploadState::Type State) +{ + switch (State) + { + case EUploadState::PingingServer: + return TEXT("PingingServer"); + + case EUploadState::Ready: + return TEXT("Ready"); + + case EUploadState::CheckingReport: + return TEXT("CheckingReport"); + + case EUploadState::CheckingReportDetail: + return TEXT("CheckingReportDetail"); + + case EUploadState::CompressAndSendData: + return TEXT("SendingFiles"); + + case EUploadState::WaitingToPostReportComplete: + return TEXT("WaitingToPostReportComplete"); + + case EUploadState::PostingReportComplete: + return TEXT("PostingReportComplete"); + + case EUploadState::Finished: + return TEXT("Finished"); + + case EUploadState::ServerNotAvailable: + return TEXT("ServerNotAvailable"); + + case EUploadState::UploadError: + return TEXT("UploadError"); + + case EUploadState::Cancelled: + return TEXT("Cancelled"); + + default: + break; + } + + return TEXT("Unknown UploadState value"); +} + +void FCrashUploadBase::SetCurrentState(EUploadState::Type InState) +{ + if (State == EUploadState::NotSet) + { + UE_LOG(CrashReportLog, Log, TEXT("Initial state = %s"), ToString(State)); + } + else + { + UE_LOG(CrashReportLog, Log, TEXT("State change from %s to %s"), ToString(State), ToString(InState)); + } + + State = InState; + + switch (State) + { + default: + break; + + case EUploadState::PingingServer: + UploadStateText = LOCTEXT("PingingServer", "Pinging server"); + break; + + case EUploadState::Ready: + UploadStateText = LOCTEXT("UploaderReady", "Ready to send to server"); + break; + + case EUploadState::ServerNotAvailable: + UploadStateText = LOCTEXT("ServerNotAvailable", "Server not available - report will be stored for later upload"); + break; + } +} + +void FCrashUploadBase::AddReportToFailedList() const +{ + if (PendingFiles.Num() > 0) + { + FailedReportDirectories.AddUnique(ErrorReport.GetReportDirectory()); + } +} + +// FCrashUploadToReceiver ////////////////////////////////////////////////////// + +FCrashUploadToReceiver::FCrashUploadToReceiver(const FString& InReceiverAddress) + : UrlPrefix(InReceiverAddress.IsEmpty() ? TEXT("") : InReceiverAddress / TEXT("CrashReporter")) +{ + if (!UrlPrefix.IsEmpty()) + { + // Sending to receiver + SendPingRequest(); + } + else + { + SetCurrentState(EUploadState::Disabled); + } +} + +FCrashUploadToReceiver::~FCrashUploadToReceiver() +{ +} + +bool FCrashUploadToReceiver::PingTimeout(float DeltaTime) +{ + if (EUploadState::PingingServer == State) + { + SetCurrentState(EUploadState::ServerNotAvailable); + + // PauseState will be Ready if user has not yet decided to send the report + if (PauseState > EUploadState::Ready) + { + AddReportToFailedList(); + } + } + + // One-shot + return false; +} + +void FCrashUploadToReceiver::BeginUpload(const FPlatformErrorReport& PlatformErrorReport) +{ + bUploadCalled = true; + + ErrorReport = PlatformErrorReport; + PendingFiles = FPlatformErrorReport( ErrorReport.GetReportDirectory() ).GetFilesToUpload(); + UE_LOG(CrashReportLog, Log, TEXT("Got %d pending files to upload from '%s'"), PendingFiles.Num(), *ErrorReport.GetReportDirectoryLeafName()); + + PauseState = EUploadState::Finished; + if (State == EUploadState::Ready) + { + BeginUploadImpl(); + } + else if (State == EUploadState::ServerNotAvailable) + { + AddReportToFailedList(); + } +} + +bool FCrashUploadToReceiver::SendCheckReportRequest() +{ + FString XMLString; + + auto Request = CreateHttpRequest(); + if (State == EUploadState::CheckingReport) + { +#if PRIMARY_UPLOAD_RECEIVER + // first stage of any upload to CRR so send analytics + FPrimaryCrashProperties::Get()->SendPreUploadAnalytics(); +#endif + AssignReportIdToPostDataBuffer(); + Request->SetURL(UrlPrefix / TEXT("CheckReport")); + Request->SetHeader(TEXT("Content-Type"), TEXT("text/plain; charset=us-ascii")); + + UE_LOG(CrashReportLog, Log, TEXT( "Sending HTTP request: %s" ), *Request->GetURL() ); + } + else + { + // This part is Windows-specific on the server + ErrorReport.LoadWindowsReportXmlFile( XMLString ); + + // Convert the XMLString into the UTF-8. + FTCHARToUTF8 Converter( (const TCHAR*)*XMLString, XMLString.Len() ); + const int32 Length = Converter.Length(); + PostData.Reset( Length ); + PostData.AddUninitialized( Length ); + CopyAssignItems( (ANSICHAR*)PostData.GetData(), Converter.Get(), Length ); + + Request->SetURL(UrlPrefix / TEXT("CheckReportDetail")); + Request->SetHeader(TEXT("Content-Type"), TEXT("text/plain; charset=utf-8")); + + UE_LOG(CrashReportLog, Log, TEXT( "Sending HTTP request: %s" ), *Request->GetURL() ); + } + + UE_LOG(CrashReportLog, Log, TEXT( "PostData Num: %i" ), PostData.Num() ); + Request->SetVerb(TEXT("POST")); + Request->SetContent(PostData); + + return Request->ProcessRequest(); +} + +void FCrashUploadToReceiver::CompressAndSendData() +{ + FCompressedData CompressedData; + if (!CompressData(PendingFiles, CompressedData, PostData)) + { + UE_LOG(CrashReportLog, Warning, TEXT("Couldn't compress the crash report files")); + SetCurrentState(EUploadState::Cancelled); + return; + } + + PendingFiles.Empty(); + + const FString Filename = ErrorReport.GetReportDirectoryLeafName() + TEXT(".ue4crash"); + + // Set up request for upload + auto Request = CreateHttpRequest(); + Request->SetVerb(TEXT("POST")); + Request->SetHeader(TEXT("Content-Type"), TEXT("application/octet-stream")); + Request->SetURL(UrlPrefix / TEXT("UploadReportFile")); + Request->SetContent(CompressedData.Data); + Request->SetHeader(TEXT("DirectoryName"), *ErrorReport.GetReportDirectoryLeafName()); + Request->SetHeader(TEXT("FileName"), Filename); + Request->SetHeader(TEXT("FileLength"), TTypeToString::ToString(CompressedData.Data.Num()) ); + Request->SetHeader(TEXT("CompressedSize"), TTypeToString::ToString(CompressedData.CompressedSize) ); + Request->SetHeader(TEXT("UncompressedSize"), TTypeToString::ToString(CompressedData.UncompressedSize) ); + Request->SetHeader(TEXT("NumberOfFiles"), TTypeToString::ToString(CompressedData.FileCount) ); + UE_LOG(CrashReportLog, Log, TEXT( "Sending HTTP request: %s" ), *Request->GetURL() ); + + if (Request->ProcessRequest()) + { + return; + } + else + { + UE_LOG(CrashReportLog, Warning, TEXT("Failed to send file upload request")); + SetCurrentState(EUploadState::Cancelled); + } +} + +void FCrashUploadToReceiver::AssignReportIdToPostDataBuffer() +{ + FString ReportDirectoryName = *ErrorReport.GetReportDirectoryLeafName(); + const int32 DirectoryNameLength = ReportDirectoryName.Len(); + PostData.SetNum(DirectoryNameLength); + for (int32 Index = 0; Index != DirectoryNameLength; ++Index) + { + PostData[Index] = ReportDirectoryName[Index]; + } +} + +void FCrashUploadToReceiver::PostReportComplete() +{ + if (PauseState == EUploadState::PostingReportComplete) + { + // Wait for confirmation + SetCurrentState(EUploadState::WaitingToPostReportComplete); + return; + } + + AssignReportIdToPostDataBuffer(); + + auto Request = CreateHttpRequest(); + Request->SetVerb( TEXT( "POST" ) ); + Request->SetURL(UrlPrefix / TEXT("UploadComplete")); + Request->SetHeader( TEXT( "Content-Type" ), TEXT( "text/plain; charset=us-ascii" ) ); + Request->SetContent(PostData); + UE_LOG(CrashReportLog, Log, TEXT( "Sending HTTP request: %s" ), *Request->GetURL() ); + + if (Request->ProcessRequest()) + { +#if PRIMARY_UPLOAD_RECEIVER + // completed upload to CRR so send analytics + FPrimaryCrashProperties::Get()->SendPostUploadAnalytics(); +#endif + SetCurrentState(EUploadState::PostingReportComplete); + } + else + { + CheckPendingReportsForFilesToUpload(); + } +} + +void FCrashUploadToReceiver::OnProcessRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded) +{ + UE_LOG(CrashReportLog, Log, TEXT("OnProcessRequestComplete(), State=%s bSucceeded=%i"), ToString(State), (int32)bSucceeded ); + switch (State) + { + default: + // May get here if response is received after time-out has passed + break; + + case EUploadState::PingingServer: + if (bSucceeded) + { + OnPingSuccess(); + } + else + { + PingTimeout(0); + } + break; + + case EUploadState::CheckingReport: + case EUploadState::CheckingReportDetail: + { + bool bCheckedOkay = false; + + if (!bSucceeded || !ParseServerResponse(HttpResponse, bCheckedOkay)) + { + if (!bSucceeded) + { + UE_LOG(CrashReportLog, Warning, TEXT("Request to server failed")); + } + else + { + UE_LOG(CrashReportLog, Warning, TEXT("Did not get a valid server response.")); + } + + // Failed to check with the server - skip this report for now + AddReportToFailedList(); + CheckPendingReportsForFilesToUpload(); + } + else if (!bCheckedOkay) + { + // Server rejected the report + UE_LOG(CrashReportLog, Warning, TEXT("Did not get a valid server response.")); + CheckPendingReportsForFilesToUpload(); + } + else + { + SetCurrentState(EUploadState::CompressAndSendData); + CompressAndSendData(); + } + } + break; + + case EUploadState::CompressAndSendData: + if (!bSucceeded) + { + UE_LOG(CrashReportLog, Warning, TEXT("File upload failed to receiver")); + AddReportToFailedList(); + SetCurrentState(EUploadState::Cancelled); + } + else + { + PostReportComplete(); + } + break; + + case EUploadState::PostingReportComplete: + CheckPendingReportsForFilesToUpload(); + break; + } +} + +void FCrashUploadToReceiver::OnPingSuccess() +{ + if (PauseState > EUploadState::Ready) + { + BeginUploadImpl(); + } + else + { + // Await instructions + SetCurrentState(EUploadState::Ready); + } +} + +void FCrashUploadToReceiver::CheckPendingReportsForFilesToUpload() +{ + SetCurrentState(EUploadState::CheckingReport); + + for (; PendingReportDirectoryIndex < PendingReportDirectories.Num(); PendingReportDirectoryIndex++) + { + ErrorReport = FPlatformErrorReport(PendingReportDirectories[PendingReportDirectoryIndex]); + PendingFiles = ErrorReport.GetFilesToUpload(); + + if (PendingFiles.Num() > 0 && SendCheckReportRequest()) + { + return; + } + } + + // Nothing left to upload + UE_LOG(CrashReportLog, Log, TEXT("All uploads done")); + SetCurrentState(EUploadState::Finished); +} + +void FCrashUploadToReceiver::BeginUploadImpl() +{ + SetCurrentState(EUploadState::CheckingReport); + if (!SendCheckReportRequest()) + { + CheckPendingReportsForFilesToUpload(); + } +} + +TSharedRef FCrashUploadToReceiver::CreateHttpRequest() +{ + auto Request = FHttpModule::Get().CreateRequest(); + Request->OnProcessRequestComplete().BindRaw(this, &FCrashUploadToReceiver::OnProcessRequestComplete); + return Request; +} + +void FCrashUploadToReceiver::SendPingRequest() +{ + SetCurrentState(EUploadState::PingingServer); + + auto Request = CreateHttpRequest(); + Request->SetVerb(TEXT("GET")); + Request->SetURL(UrlPrefix / TEXT("Ping")); + UE_LOG(CrashReportLog, Log, TEXT( "Sending HTTP request: %s" ), *Request->GetURL() ); + + if (Request->ProcessRequest()) + { + FTicker::GetCoreTicker().AddTicker(FTickerDelegate::CreateRaw(this, &FCrashUploadToReceiver::PingTimeout), CrashUploadDefs::PingTimeoutSeconds); + } + else + { + PingTimeout(0); + } +} + +bool FCrashUploadToReceiver::ParseServerResponse(FHttpResponsePtr Response, bool& OutValidReport) +{ + // Turn the snippet into a complete XML document, to keep the XML parser happy + FXmlFile ParsedResponse(FString(TEXT("")) + Response->GetContentAsString() + TEXT(""), EConstructMethod::ConstructFromBuffer); + UE_LOG(CrashReportLog, Log, TEXT("Response->GetContentAsString(): '%s'"), *Response->GetContentAsString()); + if (!ParsedResponse.IsValid()) + { + UE_LOG(CrashReportLog, Log, TEXT("Invalid response!")); + OutValidReport = false; + return false; + } + if (auto ResultNode = ParsedResponse.GetRootNode()->FindChildNode(TEXT("CrashReporterResult"))) + { + UE_LOG(CrashReportLog, Log, TEXT("ResultNode->GetAttribute(TEXT(\"bSuccess\")) = %s"), *ResultNode->GetAttribute(TEXT("bSuccess"))); + OutValidReport = ResultNode->GetAttribute(TEXT("bSuccess")) == TEXT("true"); + return true; + } + UE_LOG(CrashReportLog, Log, TEXT("Could not find CrashReporterResult")); + OutValidReport = false; + return false; +} + + +// FCrashUploadToDataRouter ////////////////////////////////////////////////////// + +FCrashUploadToDataRouter::FCrashUploadToDataRouter(const FString& InDataRouterUrl) + : DataRouterUrl(InDataRouterUrl) +{ + if (!DataRouterUrl.IsEmpty()) + { + SetCurrentState(EUploadState::Ready); + } + else + { + SetCurrentState(EUploadState::Disabled); + } +} + +FCrashUploadToDataRouter::~FCrashUploadToDataRouter() +{ +} + +void FCrashUploadToDataRouter::BeginUpload(const FPlatformErrorReport& PlatformErrorReport) +{ + bUploadCalled = true; + + ErrorReport = PlatformErrorReport; + PendingFiles = FPlatformErrorReport(ErrorReport.GetReportDirectory()).GetFilesToUpload(); + UE_LOG(CrashReportLog, Log, TEXT("Got %d pending files to upload from '%s'"), PendingFiles.Num(), *ErrorReport.GetReportDirectoryLeafName()); + + PauseState = EUploadState::Finished; + if (State == EUploadState::Ready) + { + SetCurrentState(EUploadState::CompressAndSendData); + CompressAndSendData(); + } +} + +void FCrashUploadToDataRouter::CompressAndSendData() +{ +#if PRIMARY_UPLOAD_DATAROUTER + // first stage of any upload to DR so send analytics + FPrimaryCrashProperties::Get()->SendPreUploadAnalytics(); +#endif + + FCompressedHeader CompressedHeader; + CompressedHeader.DirectoryName = ErrorReport.GetReportDirectoryLeafName(); + CompressedHeader.FileName = ErrorReport.GetReportDirectoryLeafName() + TEXT(".ue4crash"); + + FCompressedData CompressedData; + if (!CompressData(PendingFiles, CompressedData, PostData, &CompressedHeader)) + { + UE_LOG(CrashReportLog, Warning, TEXT("Couldn't compress the crash report files")); + SetCurrentState(EUploadState::Cancelled); + return; + } + + PendingFiles.Empty(); + + FString UserId = FString::Printf(TEXT("%s|%s|%s"), *FPlatformMisc::GetLoginId(), *FPlatformMisc::GetEpicAccountId(), *FPlatformMisc::GetOperatingSystemId()); + + FString UrlParams = FString::Printf(TEXT("?AppID=%s&AppVersion=%s&AppEnvironment=%s&UploadType=%s&UserID=%s"), + *FGenericPlatformHttp::UrlEncode(CrashUploadDefs::APIKey), + *FGenericPlatformHttp::UrlEncode(FEngineVersion::Current().ToString()), + *FGenericPlatformHttp::UrlEncode(FEngineBuildSettings::IsInternalBuild() ? CrashUploadDefs::AppEnvironmentInternal : CrashUploadDefs::AppEnvironmentExternal), + *FGenericPlatformHttp::UrlEncode(CrashUploadDefs::UploadType), + *FGenericPlatformHttp::UrlEncode(UserId)); + + // Set up request for upload + auto Request = CreateHttpRequest(); + Request->SetVerb(TEXT("POST")); + Request->SetHeader(TEXT("Content-Type"), TEXT("application/octet-stream")); + Request->SetURL(DataRouterUrl + UrlParams); + Request->SetContent(CompressedData.Data); + UE_LOG(CrashReportLog, Log, TEXT("Sending HTTP request: %s"), *Request->GetURL()); + + if (Request->ProcessRequest()) + { +#if PRIMARY_UPLOAD_DATAROUTER + // completed upload to DR so send analytics + FPrimaryCrashProperties::Get()->SendPostUploadAnalytics(); +#endif + return; + } + else + { + UE_LOG(CrashReportLog, Warning, TEXT("Failed to send file upload request")); + SetCurrentState(EUploadState::Cancelled); + } +} + +TSharedRef FCrashUploadToDataRouter::CreateHttpRequest() +{ + auto Request = FHttpModule::Get().CreateRequest(); + Request->OnProcessRequestComplete().BindRaw(this, &FCrashUploadToDataRouter::OnProcessRequestComplete); + return Request; +} + +void FCrashUploadToDataRouter::OnProcessRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded) +{ + UE_LOG(CrashReportLog, Log, TEXT("OnProcessRequestComplete(), State=%s bSucceeded=%i"), ToString(State), (int32)bSucceeded); + switch (State) + { + default: + // May get here if response is received after time-out has passed + break; + + case EUploadState::CompressAndSendData: + if (!bSucceeded) + { + UE_LOG(CrashReportLog, Warning, TEXT("File upload failed to data router")); + AddReportToFailedList(); + SetCurrentState(EUploadState::Cancelled); + } + else + { + CheckPendingReportsForFilesToUpload(); + } + break; + } +} + +void FCrashUploadToDataRouter::CheckPendingReportsForFilesToUpload() +{ + SetCurrentState(EUploadState::CompressAndSendData); + + for (; PendingReportDirectoryIndex < PendingReportDirectories.Num(); PendingReportDirectoryIndex++) + { + ErrorReport = FPlatformErrorReport(PendingReportDirectories[PendingReportDirectoryIndex]); + PendingFiles = ErrorReport.GetFilesToUpload(); + + if (PendingFiles.Num() > 0) + { + CompressAndSendData(); + return; + } + } + + // Nothing left to upload + UE_LOG(CrashReportLog, Log, TEXT("All uploads done")); + SetCurrentState(EUploadState::Finished); +} + +#undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Developer/CrashReportHelper/Private/GenericErrorReport.cpp b/Engine/Source/Developer/CrashReportHelper/Private/GenericErrorReport.cpp new file mode 100644 index 000000000000..84aa537b4a9c --- /dev/null +++ b/Engine/Source/Developer/CrashReportHelper/Private/GenericErrorReport.cpp @@ -0,0 +1,334 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "GenericErrorReport.h" +#include "HAL/PlatformProcess.h" +#include "HAL/PlatformFilemanager.h" +#include "UObject/NameTypes.h" +#include "Logging/LogMacros.h" +#include "Misc/Parse.h" +#include "Misc/FileHelper.h" +#include "Internationalization/Text.h" +#include "CrashReportConfig.h" +#include "Modules/ModuleManager.h" +#include "CrashDebugHelper.h" +#include "CrashDebugHelperModule.h" +#include "CrashReportUtil.h" + +// ---------------------------------------------------------------- +// Helpers + +namespace +{ + /** Enum specifying a particular part of a crash report text file */ + namespace EReportSection + { + enum Type + { + CallStack, + SourceContext, + Other + }; + } +} + + +// ---------------------------------------------------------------- +// FGenericErrorReport + +FGenericErrorReport::FGenericErrorReport(const FString& Directory) + : ReportDirectory(Directory) + , bValidCallstack(true) +{ + auto FilenamesVisitor = MakeDirectoryVisitor([this](const TCHAR* FilenameOrDirectory, bool bIsDirectory) { + if (!bIsDirectory) + { + ReportFilenames.Push(FPaths::GetCleanFilename(FilenameOrDirectory)); + } + return true; + }); + FPlatformFileManager::Get().GetPlatformFile().IterateDirectory(*ReportDirectory, FilenamesVisitor); +} + +bool FGenericErrorReport::SetUserComment(const FText& UserComment) +{ + const bool bAllowToBeContacted = FCrashReportConfig::Get().GetAllowToBeContacted(); + + const FString UserName1 = FPlatformProcess::UserName( false ); + const FString UserName2 = FPlatformProcess::UserName( true ); + const TCHAR* Anonymous = TEXT( "Anonymous" ); + + FPrimaryCrashProperties::Get()->UserDescription = UserComment.ToString(); + + // Load the file and remove all PII if bAllowToBeContacted is set to false. + const bool bRemovePersonalData = !bAllowToBeContacted; + if( bRemovePersonalData ) + { + FPrimaryCrashProperties::Get()->UserName = TEXT( "" ); + FPrimaryCrashProperties::Get()->EpicAccountId = TEXT( "" ); + // For now remove the command line completely, to hide the potential personal data. Need to revisit it later. + FPrimaryCrashProperties::Get()->CommandLine = TEXT( "CommandLineRemoved" ); + } + + // Save updated properties, including removed all PII if bAllowToBeContacted is set to false. + FPrimaryCrashProperties::Get()->Save(); + + // Remove it later, in the next iteration. + // Find .xml file + FString XmlFilename; + if (!FindFirstReportFileWithExtension(XmlFilename, TEXT(".xml"))) + { + return false; + } + + FString XmlFilePath = GetReportDirectory() / XmlFilename; + // FXmlFile's constructor loads the file to memory, closes the file and parses the data + FXmlFile XmlFile(XmlFilePath); + FXmlNode* DynamicSignaturesNode = XmlFile.IsValid() ? + XmlFile.GetRootNode()->FindChildNode(TEXT("DynamicSignatures")) : + nullptr; + + if (!DynamicSignaturesNode) + { + return false; + } + + if (bRemovePersonalData) + { + FXmlNode* ProblemNode = XmlFile.GetRootNode()->FindChildNode( TEXT( "ProblemSignatures" ) ); + if (ProblemNode) + { + FXmlNode* Parameter8Node = ProblemNode->FindChildNode( TEXT( "Parameter8" ) ); + if (Parameter8Node) + { + // Replace user name in assert message, command line etc. + FString Content = Parameter8Node->GetContent(); + Content = Content.Replace( *UserName1, Anonymous ); + Content = Content.Replace( *UserName2, Anonymous ); + + // Remove the command line. Command line is between first and second ! + TArray ParsedParameters8; + Content.ParseIntoArray( ParsedParameters8, TEXT( "!" ), false ); + if (ParsedParameters8.Num() > 1) + { + ParsedParameters8[1] = TEXT( "CommandLineRemoved" ); + } + + Content = FString::Join( ParsedParameters8, TEXT( "!" ) ); + + Parameter8Node->SetContent( Content ); + } + FXmlNode* Parameter9Node = ProblemNode->FindChildNode( TEXT( "Parameter9" ) ); + if (Parameter9Node) + { + // Replace user name in assert message, command line etc. + FString Content = Parameter9Node->GetContent(); + Content = Content.Replace( *UserName1, Anonymous ); + Content = Content.Replace( *UserName2, Anonymous ); + Parameter9Node->SetContent( Content ); + } + } + } + + // Add or update the user comment. + FXmlNode* Parameter3Node = DynamicSignaturesNode->FindChildNode(TEXT("Parameter3")); + if( Parameter3Node ) + { + Parameter3Node->SetContent(UserComment.ToString()); + } + else + { + DynamicSignaturesNode->AppendChildNode(TEXT("Parameter3"), UserComment.ToString()); + } + + // @see FCrashDescription::UpdateIDs + const FString EpicLoginAndUserNameIDs = FString::Printf( TEXT( "!LoginId:%s!EpicAccountId:%s!Name:%s" ), *FPrimaryCrashProperties::Get()->LoginId.AsString(), *FPrimaryCrashProperties::Get()->EpicAccountId.AsString(), *FPrimaryCrashProperties::Get()->UserName.AsString() ); + + // Add or update a user ID. + FXmlNode* Parameter4Node = DynamicSignaturesNode->FindChildNode(TEXT("Parameter4")); + if( Parameter4Node ) + { + Parameter4Node->SetContent(EpicLoginAndUserNameIDs); + } + else + { + DynamicSignaturesNode->AppendChildNode(TEXT("Parameter4"), EpicLoginAndUserNameIDs); + } + + // Add or update bAllowToBeContacted + const FString AllowToBeContacted = bAllowToBeContacted ? TEXT("true") : TEXT("false"); + FXmlNode* AllowToBeContactedNode = DynamicSignaturesNode->FindChildNode(TEXT("bAllowToBeContacted")); + if( AllowToBeContactedNode ) + { + AllowToBeContactedNode->SetContent(AllowToBeContacted); + } + else + { + DynamicSignaturesNode->AppendChildNode(TEXT("bAllowToBeContacted"), AllowToBeContacted); + } + + // Re-save over the top + return XmlFile.Save(XmlFilePath); +} + +void FGenericErrorReport::SetPrimaryCrashProperties( FPrimaryCrashProperties& out_PrimaryCrashProperties ) +{ + FCrashDebugHelperModule& CrashHelperModule = FModuleManager::LoadModuleChecked( FName( "CrashDebugHelper" ) ); + ICrashDebugHelper* Helper = CrashHelperModule.Get(); + if (Helper && bValidCallstack) + { + out_PrimaryCrashProperties.CallStack = Helper->CrashInfo.Exception.CallStackString; + out_PrimaryCrashProperties.Modules = Helper->CrashInfo.ModuleNames; + out_PrimaryCrashProperties.SourceContext = Helper->CrashInfo.SourceContext; + + // If error message is empty, it means general crash like accessing invalid memory ptr. + if (out_PrimaryCrashProperties.ErrorMessage.AsString().Len() == 0) + { + out_PrimaryCrashProperties.ErrorMessage = Helper->CrashInfo.Exception.ExceptionString; + } + + out_PrimaryCrashProperties.Save(); + } +} + +void FGenericErrorReport::SetCrashReportClientVersion(const FString& InVersion) +{ + FPrimaryCrashProperties::Get()->CrashReportClientVersion = InVersion; + FPrimaryCrashProperties::Get()->Save(); +} + +TArray FGenericErrorReport::GetFilesToUpload() const +{ + TArray FilesToUpload; + + for (const auto& Filename: ReportFilenames) + { + FilesToUpload.Push(ReportDirectory / Filename); + } + return FilesToUpload; +} + +void FGenericErrorReport::DeleteFiles() +{ + for (const auto& Filename: ReportFilenames) + { + IFileManager::Get().Delete(*(ReportDirectory / Filename)); + } + IFileManager::Get().DeleteDirectory(*ReportDirectory); +} + +bool FGenericErrorReport::LoadWindowsReportXmlFile( FString& OutString ) const +{ + // Find .xml file + FString XmlFilename; + if (!FindFirstReportFileWithExtension(XmlFilename, TEXT(".xml"))) + { + return false; + } + + return FFileHelper::LoadFileToString( OutString, *(ReportDirectory / XmlFilename) ); +} + +bool FGenericErrorReport::TryReadDiagnosticsFile() +{ + FString FileContent; + if (!FFileHelper::LoadFileToString(FileContent, *(ReportDirectory / FCrashReportConfig::Get().GetDiagnosticsFilename()))) + { + // No diagnostics file + return false; + } + + FString Exception; + TArray Callstack; + + static const TCHAR CallStackStartKey[] = TEXT(""); + static const TCHAR CallStackEndKey[] = TEXT(""); + static const TCHAR SourceContextStartKey[] = TEXT(""); + static const TCHAR SourceContextEndKey[] = TEXT(""); + static const TCHAR ExceptionLineStart[] = TEXT("Exception was "); + auto ReportSection = EReportSection::Other; + const TCHAR* Stream = *FileContent; + FString Line; + while (FParse::Line(&Stream, Line, true /* don't treat |s as new-lines! */)) + { + switch (ReportSection) + { + + case EReportSection::CallStack: + if (Line.StartsWith(CallStackEndKey)) + { + ReportSection = EReportSection::Other; + } + else + { + Callstack.Push(Line); + } + break; + case EReportSection::SourceContext: + if (Line.StartsWith(SourceContextEndKey)) + { + ReportSection = EReportSection::Other; + } + else + { + // Not doing anything with this at the moment + } + break; + case EReportSection::Other: + if (Line.StartsWith(CallStackStartKey)) + { + ReportSection = EReportSection::CallStack; + } + else if (Line.StartsWith(SourceContextStartKey)) + { + ReportSection = EReportSection::SourceContext; + } + else if (Line.StartsWith(ExceptionLineStart)) + { + // Not subtracting 1 from the array count so it gobbles the initial quote + Exception = Line.RightChop(ARRAY_COUNT(ExceptionLineStart)).LeftChop(1); + } + break; + } + } + + // Update properties for the crash. + FPrimaryCrashProperties::Get()->CallStack = Callstack; + // If error message is empty, it means general crash like accessing invalid memory ptr. + if (FPrimaryCrashProperties::Get()->ErrorMessage.AsString().Len() == 0) + { + FPrimaryCrashProperties::Get()->ErrorMessage = Exception; + } + + return true; +} + +bool FGenericErrorReport::FindFirstReportFileWithExtension( FString& OutFilename, const TCHAR* Extension ) const +{ + for (const auto& Filename: ReportFilenames) + { + if (Filename.EndsWith(Extension)) + { + OutFilename = Filename; + return true; + } + } + return false; +} + +FString FGenericErrorReport::FindCrashedAppName() const +{ + FString AppPath = FindCrashedAppPath(); + if (!AppPath.IsEmpty()) + { + return FPaths::GetCleanFilename(AppPath); + } + + return AppPath; +} + +FString FGenericErrorReport::FindCrashedAppPath() const +{ + UE_LOG( LogTemp, Warning, TEXT( "FGenericErrorReport::FindCrashedAppPath not implemented on this platform" ) ); + return FString( TEXT( "GenericAppPath" ) ); +} + diff --git a/Engine/Source/Developer/CrashReportHelper/Private/IOS/IOSErrorReport.cpp b/Engine/Source/Developer/CrashReportHelper/Private/IOS/IOSErrorReport.cpp new file mode 100644 index 000000000000..8d6e0520e801 --- /dev/null +++ b/Engine/Source/Developer/CrashReportHelper/Private/IOS/IOSErrorReport.cpp @@ -0,0 +1,147 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "IOSErrorReport.h" +#include "../CrashReportUtil.h" +#include "../CrashReportConfig.h" +#include "ModuleManager.h" +#include "CrashDebugHelperModule.h" +#include "CrashDebugHelper.h" +#include "FileHelper.h" +#include "PlatformFilemanager.h" + +#define LOCTEXT_NAMESPACE "CrashReport" + +namespace +{ + /** Pointer to dynamically loaded crash diagnosis module */ + FCrashDebugHelperModule* CrashHelperModule; +} + +FIOSErrorReport::FIOSErrorReport(const FString& Directory) + : FGenericErrorReport(Directory) +{ +} + +void FIOSErrorReport::Init() +{ + CrashHelperModule = &FModuleManager::LoadModuleChecked(FName("CrashDebugHelper")); +} + +void FIOSErrorReport::ShutDown() +{ + CrashHelperModule->ShutdownModule(); +} + +FString FIOSErrorReport::FindCrashedAppPath() const +{ + TArray Data; + if(FFileHelper::LoadFileToArray(Data, *(ReportDirectory / TEXT("Report.wer")))) + { + CFStringRef CFString = CFStringCreateWithBytes(NULL, Data.GetData(), Data.Num(), kCFStringEncodingUTF16LE, true); + FString FileData((NSString*)CFString); + CFRelease(CFString); + + static const TCHAR AppPathLineStart[] = TEXT("AppPath="); + static const int AppPathIdLength = ARRAY_COUNT(AppPathLineStart) - 1; + int32 AppPathStart = FileData.Find(AppPathLineStart); + if(AppPathStart >= 0) + { + FString PathData = FileData.Mid(AppPathStart + AppPathIdLength); + int32 LineEnd = -1; + if(PathData.FindChar( TCHAR('\r'), LineEnd )) + { + PathData = PathData.Left(LineEnd); + } + if(PathData.FindChar( TCHAR('\n'), LineEnd )) + { + PathData = PathData.Left(LineEnd); + } + return PathData; + } + } + else + { + UE_LOG(LogStreaming, Error, TEXT("Failed to read file '%s' error."),*(ReportDirectory / TEXT("Report.wer"))); + } + return ""; +} + +void FIOSErrorReport::FindMostRecentErrorReports(TArray& ErrorReportPaths, const FTimespan& MaxCrashReportAge) +{ + IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile(); + + FDateTime MinCreationTime = FDateTime::UtcNow() - MaxCrashReportAge; + auto ReportFinder = MakeDirectoryVisitor([&](const TCHAR* FilenameOrDirectory, bool bIsDirectory) + { + if (bIsDirectory) + { + auto TimeStamp = PlatformFile.GetTimeStamp(FilenameOrDirectory); + if (TimeStamp > MinCreationTime) + { + ErrorReportPaths.Add(FilenameOrDirectory); + } + } + return true; + }); + + FString AllReportsDirectory = FPaths::GameAgnosticSavedDir() / TEXT("Crashes"); + + PlatformFile.IterateDirectory( + *AllReportsDirectory, + ReportFinder); + + ErrorReportPaths.Sort([&](const FString& L, const FString& R) + { + auto TimeStampL = PlatformFile.GetTimeStamp(*L); + auto TimeStampR = PlatformFile.GetTimeStamp(*R); + + return TimeStampL > TimeStampR; + }); +} + +FText FIOSErrorReport::DiagnoseReport() const +{ + // Should check if there are local PDBs before doing anything + ICrashDebugHelper* CrashDebugHelper = CrashHelperModule ? CrashHelperModule->Get() : nullptr; + if (!CrashDebugHelper) + { + // Not localized: should never be seen + return FText::FromString(TEXT("Failed to load CrashDebugHelper.")); + } + + FString DumpFilename; + if (!FindFirstReportFileWithExtension(DumpFilename, TEXT(".dmp"))) + { + if (!FindFirstReportFileWithExtension(DumpFilename, TEXT(".mdmp"))) + { + return FText::FromString("No minidump found for this crash."); + } + } + + FCrashDebugInfo DebugInfo; + if (!CrashDebugHelper->ParseCrashDump(ReportDirectory / DumpFilename, DebugInfo)) + { + return FText::FromString("No minidump found for this crash."); + } + + if ( !CrashDebugHelper->CreateMinidumpDiagnosticReport(ReportDirectory / DumpFilename) ) + { + return LOCTEXT("NoDebuggingSymbols", "You do not have any debugging symbols required to display the callstack for this crash."); + } + else + { + FString CrashDump; + FString DiagnosticsPath = ReportDirectory / FCrashReportConfig::Get().GetDiagnosticsFilename(); + CrashDebugHelper->CrashInfo.GenerateReport( DiagnosticsPath ); + if ( FFileHelper::LoadFileToString( CrashDump, *(ReportDirectory / FCrashReportConfig::Get().GetDiagnosticsFilename() ) ) ) + { + return FText::FromString(CrashDump); + } + else + { + return FText::FromString("Failed to create diagnosis information."); + } + } +} + +#undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Developer/CrashReportHelper/Private/Mac/MacErrorReport.cpp b/Engine/Source/Developer/CrashReportHelper/Private/Mac/MacErrorReport.cpp new file mode 100644 index 000000000000..d6b594b54479 --- /dev/null +++ b/Engine/Source/Developer/CrashReportHelper/Private/Mac/MacErrorReport.cpp @@ -0,0 +1,146 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "MacErrorReport.h" +#include "CrashReportClientApp.h" +#include "../CrashReportUtil.h" +#include "CrashDebugHelperModule.h" +#include "CrashDebugHelper.h" +#include "FileHelper.h" +#include "PlatformFilemanager.h" + +#define LOCTEXT_NAMESPACE "CrashReportClient" + +namespace +{ + /** Pointer to dynamically loaded crash diagnosis module */ + FCrashDebugHelperModule* CrashHelperModule; +} + +FMacErrorReport::FMacErrorReport(const FString& Directory) + : FGenericErrorReport(Directory) +{ +} + +void FMacErrorReport::Init() +{ + CrashHelperModule = &FModuleManager::LoadModuleChecked(FName("CrashDebugHelper")); +} + +void FMacErrorReport::ShutDown() +{ + CrashHelperModule->ShutdownModule(); +} + +FString FMacErrorReport::FindCrashedAppPath() const +{ + TArray Data; + if(FFileHelper::LoadFileToArray(Data, *(ReportDirectory / TEXT("Report.wer")))) + { + CFStringRef CFString = CFStringCreateWithBytes(NULL, Data.GetData(), Data.Num(), kCFStringEncodingUTF16LE, true); + FString FileData((NSString*)CFString); + CFRelease(CFString); + + static const TCHAR AppPathLineStart[] = TEXT("AppPath="); + static const int AppPathIdLength = ARRAY_COUNT(AppPathLineStart) - 1; + int32 AppPathStart = FileData.Find(AppPathLineStart); + if(AppPathStart >= 0) + { + FString PathData = FileData.Mid(AppPathStart + AppPathIdLength); + int32 LineEnd = -1; + if(PathData.FindChar( TCHAR('\r'), LineEnd )) + { + PathData = PathData.Left(LineEnd); + } + if(PathData.FindChar( TCHAR('\n'), LineEnd )) + { + PathData = PathData.Left(LineEnd); + } + return PathData; + } + } + else + { + UE_LOG(LogStreaming, Error, TEXT("Failed to read file '%s' error."),*(ReportDirectory / TEXT("Report.wer"))); + } + return ""; +} + +void FMacErrorReport::FindMostRecentErrorReports(TArray& ErrorReportPaths, const FTimespan& MaxCrashReportAge) +{ + IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile(); + + FDateTime MinCreationTime = FDateTime::UtcNow() - MaxCrashReportAge; + auto ReportFinder = MakeDirectoryVisitor([&](const TCHAR* FilenameOrDirectory, bool bIsDirectory) + { + if (bIsDirectory) + { + auto TimeStamp = PlatformFile.GetTimeStamp(FilenameOrDirectory); + if (TimeStamp > MinCreationTime) + { + ErrorReportPaths.Add(FilenameOrDirectory); + } + } + return true; + }); + + FString AllReportsDirectory = FPaths::GameAgnosticSavedDir() / TEXT("Crashes"); + + PlatformFile.IterateDirectory( + *AllReportsDirectory, + ReportFinder); + + ErrorReportPaths.Sort([&](const FString& L, const FString& R) + { + auto TimeStampL = PlatformFile.GetTimeStamp(*L); + auto TimeStampR = PlatformFile.GetTimeStamp(*R); + + return TimeStampL > TimeStampR; + }); +} + +FText FMacErrorReport::DiagnoseReport() const +{ + // Should check if there are local PDBs before doing anything + ICrashDebugHelper* CrashDebugHelper = CrashHelperModule ? CrashHelperModule->Get() : nullptr; + if (!CrashDebugHelper) + { + // Not localized: should never be seen + return FText::FromString(TEXT("Failed to load CrashDebugHelper.")); + } + + FString DumpFilename; + if (!FindFirstReportFileWithExtension(DumpFilename, TEXT(".dmp"))) + { + if (!FindFirstReportFileWithExtension(DumpFilename, TEXT(".mdmp"))) + { + return FText::FromString("No minidump found for this crash."); + } + } + + FCrashDebugInfo DebugInfo; + if (!CrashDebugHelper->ParseCrashDump(ReportDirectory / DumpFilename, DebugInfo)) + { + return FText::FromString("No minidump found for this crash."); + } + + if ( !CrashDebugHelper->CreateMinidumpDiagnosticReport(ReportDirectory / DumpFilename) ) + { + return LOCTEXT("NoDebuggingSymbols", "You do not have any debugging symbols required to display the callstack for this crash."); + } + else + { + FString CrashDump; + FString DiagnosticsPath = ReportDirectory / FCrashReportClientConfig::Get().GetDiagnosticsFilename(); + CrashDebugHelper->CrashInfo.GenerateReport( DiagnosticsPath ); + if ( FFileHelper::LoadFileToString( CrashDump, *(ReportDirectory / FCrashReportClientConfig::Get().GetDiagnosticsFilename() ) ) ) + { + return FText::FromString(CrashDump); + } + else + { + return FText::FromString("Failed to create diagnosis information."); + } + } +} + +#undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Developer/CrashReportHelper/Private/PendingReports.cpp b/Engine/Source/Developer/CrashReportHelper/Private/PendingReports.cpp new file mode 100644 index 000000000000..6e6ddfcc7a72 --- /dev/null +++ b/Engine/Source/Developer/CrashReportHelper/Private/PendingReports.cpp @@ -0,0 +1,107 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "PendingReports.h" +#include "HAL/PlatformFilemanager.h" +#include "Logging/LogMacros.h" +#include "HAL/FileManager.h" +#include "Misc/Paths.h" +#include "Templates/UniquePtr.h" +#include "CrashReportConfig.h" +#include "Dom/JsonValue.h" +#include "Dom/JsonObject.h" +#include "Serialization/JsonSerializer.h" + +namespace +{ + typedef TJsonWriter> FPrettyJsonWriter; + typedef TArray> FJsonReportArray; + + const TCHAR ReportsArrayFieldName[] = TEXT("crash-reports"); +} + +FPendingReports::FPendingReports() +{ + Load(); +} + +void FPendingReports::Add( const FString& Path ) +{ + FString NormalizedPath = Path; + FPaths::NormalizeDirectoryName(NormalizedPath); + Reports.AddUnique(NormalizedPath); +} + +void FPendingReports::Forget(const FString& ReportDirectoryName) +{ + auto Index = Reports.IndexOfByPredicate([&](const FString& Path) { + return FPaths::GetCleanFilename(Path) == ReportDirectoryName; + }); + + if (Index != INDEX_NONE) + { + Reports.RemoveAt(Index, 1 /* single item */, false /* no need to shrink */); + } +} + +void FPendingReports::Save() const +{ + auto PendingReportsPath = GetPendingReportsJsonFilepath(); + + // Ensure directory structure exists + FPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(*FPaths::GetPath(PendingReportsPath)); + + FJsonReportArray JsonReports; + for (auto Path : Reports) + { + JsonReports.Push(MakeShareable(new FJsonValueString(Path))); + } + + TSharedRef JsonRootObject = MakeShareable(new FJsonObject); + JsonRootObject->SetArrayField(ReportsArrayFieldName, JsonReports); + + TUniquePtr FileWriter(IFileManager::Get().CreateFileWriter(*PendingReportsPath)); + if (!FileWriter) + { + UE_LOG(CrashReportLog, Warning, TEXT("Failed to save pending reports JSON file")); + return; + } + FJsonSerializer::Serialize(JsonRootObject, FPrettyJsonWriter::Create(FileWriter.Get())); +} + +const TArray& FPendingReports::GetReportDirectories() const +{ + return Reports; +} + +void FPendingReports::Load() +{ + TUniquePtr FileReader(IFileManager::Get().CreateFileReader(*GetPendingReportsJsonFilepath())); + if (!FileReader) + { + return; + } + + TSharedPtr JsonRootObject; + if (!FJsonSerializer::Deserialize(TJsonReader<>::Create(FileReader.Get()), JsonRootObject)) + { + return; + } + + // Array will be empty if there's a type mismatch + auto ReportArray = JsonRootObject->GetArrayField(ReportsArrayFieldName); + + for (auto PathValue: ReportArray) + { + auto Path = PathValue->AsString(); + if (!Path.IsEmpty()) + { + Reports.Add(Path); + } + } +} + +FString FPendingReports::GetPendingReportsJsonFilepath() +{ + return FString(FPaths::GameAgnosticSavedDir()) / TEXT("crash-reports/pending-reports.json"); +} + diff --git a/Engine/Source/Developer/CrashReportHelper/Private/PendingReports.h b/Engine/Source/Developer/CrashReportHelper/Private/PendingReports.h new file mode 100644 index 000000000000..dfee16aec27d --- /dev/null +++ b/Engine/Source/Developer/CrashReportHelper/Private/PendingReports.h @@ -0,0 +1,64 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "Containers/UnrealString.h" + +/** + * Manager for reports that weren't able to be sent on previous runs of the tool + */ +class FPendingReports +{ +public: + /** + * Load the list of reports + */ + FPendingReports(); + + /** + * Add a pending report directory + * @Path Full path to the directory containing the report + */ + void Add(const FString& Path); + + /** + * Remove a pending report directory if present + * @ReportDirectoryName Leaf name of report directory to remove + */ + void Forget(const FString& ReportDirectoryName); + + /** + * Clear out the list of reports + */ + void Clear() + { + Reports.Reset(); + } + + /** + * Save out the list of reports to the user's application settings folder + */ + void Save() const; + + /** + * Access to report directories + * @return Full paths to all pending report directories + */ + const TArray& GetReportDirectories() const; + +private: + /** + * Load the list of reports from the user's application settings folder + */ + void Load(); + + /** + * Get the application settings location of the pending reports file + * @return Full path to the file + */ + static FString GetPendingReportsJsonFilepath(); + + /** Full paths to reports not yet submitted */ + TArray Reports; +}; diff --git a/Engine/Source/Developer/CrashReportHelper/Private/Windows/WindowsErrorReport.cpp b/Engine/Source/Developer/CrashReportHelper/Private/Windows/WindowsErrorReport.cpp new file mode 100644 index 000000000000..0fa508fd3d60 --- /dev/null +++ b/Engine/Source/Developer/CrashReportHelper/Private/Windows/WindowsErrorReport.cpp @@ -0,0 +1,179 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "WindowsErrorReport.h" +#include "CrashDebugHelperModule.h" +#include "CrashReportUtil.h" +#include "CrashDescription.h" +#include "CrashDebugHelper.h" +#include "Misc/FileHelper.h" +#include "Modules/ModuleManager.h" +#include "Internationalization/Text.h" +#include "Internationalization/Internationalization.h" +#include "HAL/PlatformFileManager.h" + +#include "WindowsHWrapper.h" +#include "AllowWindowsPlatformTypes.h" +#include +#include "HideWindowsPlatformTypes.h" + +#define LOCTEXT_NAMESPACE "CrashReportClient" + +namespace +{ + /** Pointer to dynamically loaded crash diagnosis module */ + FCrashDebugHelperModule* CrashHelperModule; +} + +/** Helper class used to parse specified string value based on the marker. */ +struct FWindowsReportParser +{ + static FString Find( const FString& ReportDirectory, const TCHAR* Marker ) + { + FString Result; + + TArray FileData; + FFileHelper::LoadFileToArray( FileData, *(ReportDirectory / TEXT( "Report.wer" )) ); + FileData.Add( 0 ); + FileData.Add( 0 ); + + const FString FileAsString = reinterpret_cast(FileData.GetData()); + + TArray String; + FileAsString.ParseIntoArray( String, TEXT( "\r\n" ), true ); + + for( const auto& StringLine : String ) + { + if( StringLine.Contains( Marker ) ) + { + TArray SeparatedParameters; + StringLine.ParseIntoArray( SeparatedParameters, Marker, true ); + + Result = SeparatedParameters[SeparatedParameters.Num()-1]; + break; + } + } + + return Result; + } +}; + +FWindowsErrorReport::FWindowsErrorReport(const FString& Directory) + : FGenericErrorReport(Directory) +{ +} + +void FWindowsErrorReport::Init() +{ + CrashHelperModule = &FModuleManager::LoadModuleChecked(FName("CrashDebugHelper")); +} + +void FWindowsErrorReport::ShutDown() +{ + CrashHelperModule->ShutdownModule(); +} + +FString FWindowsErrorReport::FindCrashedAppPath() const +{ + FString AppPath = FPaths::Combine(FPrimaryCrashProperties::Get()->BaseDir, FPrimaryCrashProperties::Get()->ExecutableName); + AppPath += TEXT(".exe"); + return AppPath; +} + +FText FWindowsErrorReport::DiagnoseReport() const +{ + // Mark the callstack as invalid. + bValidCallstack = false; + + // Should check if there are local PDBs before doing anything + auto CrashDebugHelper = CrashHelperModule ? CrashHelperModule->Get() : nullptr; + if (!CrashDebugHelper) + { + // Not localized: should never be seen + return FText::FromString(TEXT("Failed to load CrashDebugHelper.")); + } + + FString DumpFilename; + if (!FindFirstReportFileWithExtension(DumpFilename, TEXT(".dmp"))) + { + if (!FindFirstReportFileWithExtension(DumpFilename, TEXT(".mdmp"))) + { + return LOCTEXT("MinidumpNotFound", "No minidump found for this crash."); + } + } + + if (!CrashDebugHelper->CreateMinidumpDiagnosticReport(ReportDirectory / DumpFilename)) + { + return LOCTEXT("NoDebuggingSymbols", "You do not have any debugging symbols required to display the callstack for this crash."); + } + + // No longer required, only for backward compatibility, mark the callstack as valid. + bValidCallstack = true; + return FText(); +} + +static bool TryGetDirectoryCreationTimeUtc(const FString& InDirectoryName, FDateTime& OutCreationTime) +{ + FString DirectoryName(InDirectoryName); + FPaths::MakePlatformFilename(DirectoryName); + + WIN32_FILE_ATTRIBUTE_DATA Info; + if (!GetFileAttributesExW(*DirectoryName, GetFileExInfoStandard, &Info)) + { + OutCreationTime = FDateTime(); + return false; + } + + SYSTEMTIME SysTime; + if (!FileTimeToSystemTime(&Info.ftCreationTime, &SysTime)) + { + OutCreationTime = FDateTime(); + return false; + } + + OutCreationTime = FDateTime(SysTime.wYear, SysTime.wMonth, SysTime.wDay, SysTime.wHour, SysTime.wMinute, SysTime.wSecond); + return true; +} + +void FWindowsErrorReport::FindMostRecentErrorReports(TArray& ErrorReportPaths, const FTimespan& MaxCrashReportAge) +{ + auto& PlatformFile = FPlatformFileManager::Get().GetPlatformFile(); + + FDateTime MinCreationTime = FDateTime::UtcNow() - MaxCrashReportAge; + auto ReportFinder = MakeDirectoryVisitor([&](const TCHAR* FilenameOrDirectory, bool bIsDirectory) + { + if (bIsDirectory) + { + FDateTime CreationTime; + if (TryGetDirectoryCreationTimeUtc(FilenameOrDirectory, CreationTime) && CreationTime > MinCreationTime && FCString::Strstr(FilenameOrDirectory, TEXT("UE4-"))) + { + ErrorReportPaths.Add(FilenameOrDirectory); + } + } + return true; + }); + + { + TCHAR LocalAppDataPath[MAX_PATH]; + SHGetFolderPath(0, CSIDL_LOCAL_APPDATA, NULL, 0, LocalAppDataPath); + PlatformFile.IterateDirectory(*(FString(LocalAppDataPath) / TEXT("Microsoft/Windows/WER/ReportQueue")), ReportFinder); + } + + if (ErrorReportPaths.Num() == 0) + { + TCHAR LocalAppDataPath[MAX_PATH]; + SHGetFolderPath( 0, CSIDL_COMMON_APPDATA, NULL, 0, LocalAppDataPath ); + PlatformFile.IterateDirectory( *(FString( LocalAppDataPath ) / TEXT( "Microsoft/Windows/WER/ReportQueue" )), ReportFinder ); + } + + ErrorReportPaths.Sort([](const FString& L, const FString& R) + { + FDateTime CreationTimeL; + TryGetDirectoryCreationTimeUtc(L, CreationTimeL); + FDateTime CreationTimeR; + TryGetDirectoryCreationTimeUtc(R, CreationTimeR); + + return CreationTimeL > CreationTimeR; + }); +} + +#undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Developer/CrashReportHelper/Public/CrashDescription.h b/Engine/Source/Developer/CrashReportHelper/Public/CrashDescription.h new file mode 100644 index 000000000000..5d0b9c77a254 --- /dev/null +++ b/Engine/Source/Developer/CrashReportHelper/Public/CrashDescription.h @@ -0,0 +1,526 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "Containers/UnrealString.h" +#include "GenericPlatform/GenericPlatformCrashContext.h" +#include "XmlFile.h" +#include "Misc/EngineVersion.h" + +enum class ECrashDescVersions : int32; +enum class ECrashDumpMode : int32; +class FXmlNode; +struct FPrimaryCrashProperties; +struct FAnalyticsEventAttribute; + +/** PrimaryCrashProperties. Extracted from: FGenericCrashContext::SerializeContentToBuffer */ +/* + "CrashVersion" + "ProcessId" + "CrashGUID" + "IsInternalBuild" + "IsPerforceBuild" + "IsSourceDistribution" + "IsEnsure" + "SecondsSinceStart" + "GameName" + "ExecutableName" + "BuildConfiguration" + "PlatformName" + "PlatformNameIni" + "PlatformFullName" + "EngineMode" + "EngineModeEx" + "EngineVersion" + "BuildVersion" + "CommandLine" + "LanguageLCID" + "AppDefaultLocale" + "IsUE4Release" + "UserName" + "BaseDir" + "RootDir" + "MachineId" + "LoginId" + "EpicAccountId" + "CallStack" + "SourceContext" + "UserDescription" + "UserActivityHint" + "ErrorMessage" + "CrashDumpMode" + "CrashReporterMessage" + "Misc.NumberOfCores" + "Misc.NumberOfCoresIncludingHyperthreads" + "Misc.Is64bitOperatingSystem" + "Misc.CPUVendor" + "Misc.CPUBrand" + "Misc.PrimaryGPUBrand" + "Misc.OSVersionMajor" + "Misc.OSVersionMinor" + "Misc.AppDiskTotalNumberOfBytes" + "Misc.AppDiskNumberOfFreeBytes" + "MemoryStats.TotalPhysical" + "MemoryStats.TotalVirtual" + "MemoryStats.PageSize" + "MemoryStats.TotalPhysicalGB" + "MemoryStats.AvailablePhysical" + "MemoryStats.AvailableVirtual" + "MemoryStats.UsedPhysical" + "MemoryStats.PeakUsedPhysical" + "MemoryStats.UsedVirtual" + "MemoryStats.PeakUsedVirtual" + "MemoryStats.bIsOOM" + "MemoryStats.OOMAllocationSize" + "MemoryStats.OOMAllocationAlignment" + "TimeofCrash" + "bAllowToBeContacted" + */ + +namespace Lex +{ + inline void FromString( ECrashDescVersions& OutValue, const TCHAR* Buffer ) + { + OutValue = (ECrashDescVersions)FCString::Atoi( Buffer ); + } + + inline void FromString( ECrashDumpMode& OutValue, const TCHAR* Buffer ) + { + OutValue = (ECrashDumpMode)FCString::Atoi( Buffer ); + } + + inline void FromString( FEngineVersion& OutValue, const TCHAR* Buffer ) + { + FEngineVersion::Parse( Buffer, OutValue ); + } +} + +/** Simple crash property. Only for string values. */ +struct FCrashProperty +{ + friend struct FPrimaryCrashProperties; + +protected: + /** Initialization constructor. */ + FCrashProperty( const FString& InMainCategory, const FString& InSecondCategory, FPrimaryCrashProperties* InOwner ); + +public: + /** Assignment operator for string. */ + FCrashProperty& operator=(const FString& NewValue); + + /** Assignment operator for TCHAR*. */ + FCrashProperty& operator=(const TCHAR* NewValue); + + /** Assignment operator for arrays. */ + FCrashProperty& operator=(const TArray& NewValue); + + /** Assignment operator for bool. */ + FCrashProperty& operator=(const bool NewValue); + + /** Assignment operator for int64. */ + FCrashProperty& operator=(const int64 NewValue); + + /** Getter for string, default. */ + const FString& AsString() const; + + /** Getter for bool. */ + bool AsBool() const; + + /** Getter for int64. */ + int64 AsInt64() const; + +protected: + /** Owner of the property. */ + FPrimaryCrashProperties* Owner; + + /** Cached value of the property. */ + mutable FString CachedValue; + + /** Main category in the crash context. */ + FString MainCategory; + + /** Second category in the crash context. */ + FString SecondCategory; + + mutable bool bSet; +}; + +/** Primary crash properties required by the crash report system. */ +struct FPrimaryCrashProperties +{ + friend struct FCrashProperty; + + /** Version. */ + ECrashDescVersions CrashVersion; + + /** Crash dump mode. */ + ECrashDumpMode CrashDumpMode; + + /** An unique report name that this crash belongs to. Folder name. */ + FString CrashGUID; + + /** + * The name of the game that crashed. (AppID) + * @GameName varchar(64) + * + * FApp::GetGameName() + */ + FString GameName; + + /** + * The name of the exe that crashed. (AppID) + * @GameName varchar(64) + */ + FString ExecutableName; + + /** + * The mode the game was in e.g. editor. + * @EngineMode varchar(64) + * + * FPlatformMisc::GetEngineMode() + */ + FString EngineMode; + + /** + * Deployment (also known as "EpicApp"), e.g. DevPlaytest, PublicTest, Live + * @DeploymentName varchar(64) + */ + FString DeploymentName; + + /** + * EngineModeEx e.g. Unset, Dirty, Vanilla + * @DeploymentName varchar(64) + */ + FCrashProperty EngineModeEx; + + /** + * The platform that crashed e.g. Win64. + * @PlatformName varchar(64) + * + * Last path of the directory + */ + FCrashProperty PlatformFullName; + + /** + * Encoded engine version. (AppVersion) + * E.g. 4.3.0.0-2215663+UE4-Releases+4.3 + * BuildVersion-BuiltFromCL-BranchName + * @EngineVersion varchar(64) + * + * FEngineVersion::Current().ToString() + * ENGINE_VERSION_STRING + */ + FEngineVersion EngineVersion; + + /** + * Built from changelist. + * @ChangeListVersion varchar(64) + * + * BUILT_FROM_CHANGELIST + */ + //EngineVersion.GetChangelist() + //uint32 BuiltFromCL; + + /** + * The name of the branch this game was built out of. + * @Branch varchar(32) + * + * BRANCH_NAME + */ + //EngineVersion.GetBranch(); + + /** + * The command line of the application that crashed. + * @CommandLine varchar(512) + * + * FCommandLine::Get() + */ + FCrashProperty CommandLine; + + /** + * The base directory where the app was running. + * @BaseDir varchar(512) + * + * FPlatformProcess::BaseDir() + */ + FString BaseDir; + + /** + * The language ID the application that crashed. + * @LanguageExt varchar(64) + * + * FPlatformMisc::GetDefaultLocale() + */ + FString AppDefaultLocale; + + /** + * The name of the user that caused this crash. + * @UserName varchar(64) + * + * FString( FPlatformProcess::UserName() ).Replace( TEXT( "." ), TEXT( "" ) ) + */ + FCrashProperty UserName; + + /** + * The unique ID used to identify the machine the crash occurred on. + * @ComputerName varchar(64) + * + * FPlatformMisc::GetLoginId() + */ + FCrashProperty LoginId; + + /** + * The Epic account ID for the user who last used the Launcher. + * @EpicAccountId varchar(64) + * + * FPlatformMisc::GetEpicAccountId() + */ + FCrashProperty EpicAccountId; + + /** + * The last game session id set by the application. Application specific meaning. Some might not set this. + * @EpicAccountId varchar(64) + * + */ + FCrashProperty GameSessionID; + + /** + * An array of FStrings representing the callstack of the crash. + * @RawCallStack varchar(MAX) + * + */ + FCrashProperty CallStack; + + /** + * An array of FStrings showing the source code around the crash. + * @SourceContext varchar(max) + * + */ + FCrashProperty SourceContext; + + /** + * An array of module's name used by the game that crashed. + * + */ + FCrashProperty Modules; + + /** + * An array of FStrings representing the user description of the crash. + * @Description varchar(512) + * + */ + FCrashProperty UserDescription; + + /** + * An FString representing the user activity, if known, when the error occurred. + * @UserActivityHint varchar(512) + * + */ + FCrashProperty UserActivityHint; + + /** + * The error message, can be assertion message, ensure message or message from the fatal error. + * @Summary varchar(512) + * + * GErrorMessage + */ + FCrashProperty ErrorMessage; + + /** Location of full crash dump. Displayed in the crash report frontend. */ + FCrashProperty FullCrashDumpLocation; + + /** + * The UTC time the crash occurred. + * @TimeOfCrash datetime + * + * FDateTime::UtcNow().GetTicks() + */ + FCrashProperty TimeOfCrash; + + /** + * Whether the user allowed us to be contacted. + * If true the following properties are retrieved from the system: UserName (for non-launcher build) and EpicAccountID. + * Otherwise they will be empty. + */ + FCrashProperty bAllowToBeContacted; + + /** + * Rich text string (should be localized by the crashing application) that will be displayed in the main CRC dialog + * Can be empty and the CRC's default text will be shown. + */ + FCrashProperty CrashReporterMessage; + + /** + * Platform-specific UE4 Core value (integer). + */ + FCrashProperty PlatformCallbackResult; + + /** + * CRC sets this to the current version of the software. + */ + FCrashProperty CrashReportClientVersion; + + /** + * Whether this crash has a minidump file. + * @HasMiniDumpFile bit + */ + bool bHasMiniDumpFile; + + /** + * Whether this crash has a log file. + * @HasLogFile bit + */ + bool bHasLogFile; + + /** Whether this crash contains primary usable data. */ + bool bHasPrimaryData; + + /** Copy of CommandLine that isn't anonymized so it can be used to restart the process */ + FString RestartCommandLine; + + /** + * Whether the report comes from a non-fatal event such as an ensure + */ + bool bIsEnsure; + +protected: + /** Default constructor. */ + FPrimaryCrashProperties(); + + /** Destructor. */ + ~FPrimaryCrashProperties() + { + delete XmlFile; + } + +public: + /** Sets new instance as the global. */ + static void Set( FPrimaryCrashProperties* NewInstance ) + { + Singleton = NewInstance; + } + + /** + * @return global instance of the primary crash properties for the currently processed/displayed crash + */ + static FPrimaryCrashProperties* Get() + { + return Singleton; + } + + /** + * @return false, if there is no crash + */ + static bool IsValid() + { + return Singleton != nullptr; + } + + /** Shutdowns the global instance. */ + static void Shutdown(); + + /** Whether this crash contains callstack, error message and source context thus it means that crash is complete. */ + bool HasProcessedData() const + { + return CallStack.AsString().Len() > 0 && ErrorMessage.AsString().Len() > 0; + } + + /** Updates following properties: UserName, LoginID and EpicAccountID. */ + void UpdateIDs(); + + /** Sends this crash for analytics (before upload). */ + void SendPreUploadAnalytics(); + + /** Sends this crash for analytics (after successful upload). */ + void SendPostUploadAnalytics(); + + /** Saves the data. */ + void Save(); + +protected: + /** Reads previously set XML file. */ + void ReadXML( const FString& CrashContextFilepath ); + + /** Sets the CrasgGUID based on the report's path. */ + void SetCrashGUID( const FString& Filepath ); + + /** Gets a crash property from the XML file. */ + template + void GetCrashProperty( Type& out_ReadValue, const FString& MainCategory, const FString& SecondCategory ) const + { + const FXmlNode* MainNode = XmlFile->GetRootNode()->FindChildNode( MainCategory ); + if (MainNode) + { + const FXmlNode* CategoryNode = MainNode->FindChildNode( SecondCategory ); + if (CategoryNode) + { + Lex::FromString( out_ReadValue, *FGenericCrashContext::UnescapeXMLString( CategoryNode->GetContent() ) ); + } + } + } + + /** Sets a crash property to a new value. */ + template + void SetCrashProperty( const FString& MainCategory, const FString& SecondCategory, const Type& Value ) + { + SetCrashProperty( MainCategory, SecondCategory, *TTypeToString::ToString( Value ) ); + } + + /** Sets a crash property to a new value. */ + void SetCrashProperty( const FString& MainCategory, const FString& SecondCategory, const FString& NewValue ) + { + FXmlNode* MainNode = XmlFile->GetRootNode()->FindChildNode( MainCategory ); + if (MainNode) + { + FXmlNode* CategoryNode = MainNode->FindChildNode( SecondCategory ); + const FString EscapedValue = FGenericCrashContext::EscapeXMLString( NewValue ); + if (CategoryNode) + { + CategoryNode->SetContent( EscapedValue ); + } + else + { + MainNode->AppendChildNode( SecondCategory, EscapedValue ); + } + } + } + + /** Encodes multi line property to be saved as single line. */ + FString EncodeArrayStringAsXMLString( const TArray& ArrayString ) const; + + void MakeCrashEventAttributes(TArray& OutCrashAttributes); + + /** Reader for the xml file. */ + FXmlFile* XmlFile; + + /** Cached filepath. */ + FString XmlFilepath; + + /** Global instance. */ + static FPrimaryCrashProperties* Singleton; +}; + +/** + * Describes a unified crash, should be used by all platforms. + * Based on FGenericCrashContext, reads all saved properties, accessed by looking into read XML. + * Still lacks some of the properties, they will be added later. + * Must contain the same properties as ...\CrashReportServer\CrashReportCommon\CrashDescription.cs. + * Contains all usable information about the crash. + * + */ +struct FCrashContext : public FPrimaryCrashProperties +{ + /** Initializes instance based on specified Crash Context filepath. */ + explicit FCrashContext( const FString& CrashContextFilepath ); +}; + +/** Crash context based on the Window Error Reporting WER files, obsolete, only for backward compatibility. */ +struct FCrashWERContext : public FPrimaryCrashProperties +{ + /** Initializes instance based on specified WER XML filepath. */ + explicit FCrashWERContext( const FString& WERXMLFilepath ); + + /** Initializes engine version from the separate components. */ + void InitializeEngineVersion( const FString& BuildVersion, const FString& BranchName, uint32 BuiltFromCL ); +}; diff --git a/Engine/Source/Developer/CrashReportHelper/Public/CrashReportConfig.h b/Engine/Source/Developer/CrashReportHelper/Public/CrashReportConfig.h new file mode 100644 index 000000000000..8e88496c80b4 --- /dev/null +++ b/Engine/Source/Developer/CrashReportHelper/Public/CrashReportConfig.h @@ -0,0 +1,157 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "Containers/UnrealString.h" + +#define CRASH_REPORT_UNATTENDED_ONLY PLATFORM_LINUX || PLATFORM_IOS + +DECLARE_LOG_CATEGORY_EXTERN(CrashReportLog, Log, All); + +class FConfigFile; + +/** +* Holds FullCrashDump properties from the config. +* +* FullCrashDump_0_Branch=UE4 +* FullCrashDump_0_Location=\\epicgames.net\root\Builds\UE4 +* FullCrashDump_1_Branch=... +* ... +*/ +struct FFullCrashDumpEntry +{ + /** Initialization constructor. */ + FFullCrashDumpEntry( const FString& InBranchName, const FString& InLocation, const bool bInExactMatch ) + : BranchName( InBranchName ) + , Location( InLocation ) + , bExactMatch( bInExactMatch ) + {} + + + /** Partial branch name. */ + const FString BranchName; + + /** Location where the full crash dump will be copied. Usually a network share. */ + const FString Location; + + /** + * Branch=UE4 means exact match + * Branch=UE4* means contain match + */ + const bool bExactMatch; +}; + +/** Holds basic configuration for the crash report client. */ +struct FCrashReportConfig +{ + /** Accesses the singleton. */ + static FCrashReportConfig& Get() + { + static FCrashReportConfig Instance; + return Instance; + } + + /** Initialization constructor. */ + FCrashReportConfig(); + + const FString& GetVersion() const + { + return CrashReportVersion; + } + + const FString& GetReceiverAddress() const + { + return CrashReportReceiverIP; + } + + const FString& GetDataRouterURL() const + { + return DataRouterUrl; + } + + const FString& GetDiagnosticsFilename() const + { + return DiagnosticsFilename; + } + + const bool& GetAllowToBeContacted() const + { + return bAllowToBeContacted; + } + + const bool& GetSendLogFile() const + { + return bSendLogFile; + } + + const bool& GetHideLogFilesOption() const + { + return bHideLogFilesOption; + } + + const bool& IsAllowedToCloseWithoutSending() const + { + return bIsAllowedToCloseWithoutSending; + } + + int GetUserCommentSizeLimit() const + { + return UserCommentSizeLimit; + } + + void SetAllowToBeContacted( bool bNewValue ); + void SetSendLogFile( bool bNewValue ); + + /** Set config values that are determined by the crashing application saving a config file to the crash folder */ + void SetProjectConfigOverrides(const FConfigFile& InConfigFile); + + /** + * @return location for full crash dump for the specified branch. + */ + const FString GetFullCrashDumpLocationForBranch( const FString& BranchName ) const; + +protected: + /** Returns empty string if couldn't read */ + FString GetKey( const FString& KeyName ); + + /** Reads FFullCrashDumpEntry config entries. */ + void ReadFullCrashDumpConfigurations(); + + /** Client version (two digit licensee built e.g. "1.0" - three digits for Epic builds e.g. "1.0.0") */ + FString CrashReportVersion; + + /** IP address of crash report receiver. */ + FString CrashReportReceiverIP; + + /** URL of Data Router service */ + FString DataRouterUrl; + + /** Filename to use when saving diagnostics report, if generated locally. */ + FString DiagnosticsFilename; + + /** Section for crash report client configuration. */ + FString SectionName; + + /** Configuration used for copying full dump crashes. */ + TArray FullCrashDumpConfigurations; + + /** + * Whether the user allowed us to be contacted. + * If true the following properties are retrieved from the system: UserName (for non-launcher build) and EpicAccountID. + * Otherwise they will be empty. + */ + bool bAllowToBeContacted; + + /** Whether the user allowed us to send the log file. */ + bool bSendLogFile; + + /** Whether the user is shown the option to enable/disable sending the log file. */ + bool bHideLogFilesOption; + + /** Whether the user is allowed to close the crash reporter without sending a report */ + bool bIsAllowedToCloseWithoutSending; + + /** Size limit for the description of multi-line text */ + int UserCommentSizeLimit; +}; diff --git a/Engine/Source/Developer/CrashReportHelper/Public/CrashReportUnattended.h b/Engine/Source/Developer/CrashReportHelper/Public/CrashReportUnattended.h new file mode 100644 index 000000000000..354587448dc5 --- /dev/null +++ b/Engine/Source/Developer/CrashReportHelper/Public/CrashReportUnattended.h @@ -0,0 +1,44 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "CrashUpload.h" + +/** + * Implementation of the crash report client used for unattended uploads + */ +class FCrashReportUnattended +{ +public: + /** + * Set up uploader object + * @param ErrorReport Error report to upload + */ + explicit FCrashReportUnattended(FPlatformErrorReport& InErrorReport, bool InDeleteFiles = false); + +private: + /** + * Update received every second + * @param DeltaTime Time since last update, unused + * @return Whether the updates should continue + */ + bool Tick(float DeltaTime); + + /** + * Begin calling Tick once a second + */ + void StartTicker(); + + /** Object that uploads report files to the server */ + FCrashUploadToReceiver ReceiverUploader; + + /** Object that uploads report files to the server */ + FCrashUploadToDataRouter DataRouterUploader; + + /** Platform code for accessing the report */ + FPlatformErrorReport ErrorReport; + + /** clean up the report when done */ + bool bDeleteReportFiles; +}; diff --git a/Engine/Source/Developer/CrashReportHelper/Public/CrashUpload.h b/Engine/Source/Developer/CrashReportHelper/Public/CrashUpload.h new file mode 100644 index 000000000000..aa998194754f --- /dev/null +++ b/Engine/Source/Developer/CrashReportHelper/Public/CrashUpload.h @@ -0,0 +1,280 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "Containers/UnrealString.h" +#include "Internationalization/Text.h" +#include "Interfaces/IHttpRequest.h" +#include "PlatformErrorReport.h" + +struct FCompressedData; +struct FCompressedHeader; + +class FCrashUploadBase +{ +public: + FCrashUploadBase(); + + virtual ~FCrashUploadBase(); + + /** + * Is this uploader enabled or disabled? + */ + bool IsEnabled() const { return State != EUploadState::Disabled; } + + /** + * Has BeginUpload been called? + */ + bool IsUploadCalled() const { return bUploadCalled; } + + /** + * Provide progress or error information for the UI + */ + const FText& GetStatusText() const { return UploadStateText; } + + /** + * Determine whether the upload has finished (successfully or otherwise) + * @return Whether the upload has finished + */ + bool IsFinished() const + { + return State >= EUploadState::FirstCompletedState; + } + + void Cancel() + { + SetCurrentState(EUploadState::Cancelled); + } + + static bool IsInitialized() { return bInitialized; } + + static void StaticInitialize(const FPlatformErrorReport& PlatformErrorReport); + + static void StaticShutdown(); + +protected: + /** State enum to keep track of what the uploader is doing */ + struct EUploadState + { + enum Type + { + NotSet, + + PingingServer, + Ready, + CheckingReport, + CheckingReportDetail, + CompressAndSendData, + WaitingToPostReportComplete, + PostingReportComplete, + Finished, + + ServerNotAvailable, + UploadError, + Cancelled, + Disabled, + + FirstCompletedState = Finished, + }; + }; + + static bool CompressData(const TArray& InPendingFiles, struct FCompressedData& OutCompressedData, TArray& OutPostData, struct FCompressedHeader* OptionalHeader = nullptr); + + /** + * Get a string representation of the state, for logging purposes + * @param State Value to stringize + * @return Literal string value + */ + static const TCHAR* ToString(EUploadState::Type InState); + + /** + * Set the current state, also updating the status text where necessary + * @param State State the uploader is now in + */ + void SetCurrentState(EUploadState::Type InState); + + /** + * When failed, add the report to a file list containing reports to upload next time + */ + void AddReportToFailedList() const; + +protected: + bool bUploadCalled; + + /** What this class is currently doing */ + EUploadState::Type State; + + /** Status of upload to display */ + FText UploadStateText; + + /** State to pause at until confirmation has been received to continue */ + EUploadState::Type PauseState; + + /** Full paths of files still to be uploaded */ + TArray PendingFiles; + + /** Error report being processed */ + FPlatformErrorReport ErrorReport; + + /** Buffer to keep reusing for file content and other messages */ + TArray PostData; + + int32 PendingReportDirectoryIndex; + +protected: + static bool bInitialized; + + /** Full paths of reports from previous runs still to be uploaded */ + static TArray PendingReportDirectories; + + /** Full paths of reports from this run that did not upload */ + static TArray FailedReportDirectories; +}; + + +/** + * Handles uploading files to the crash report server + */ +class FCrashUploadToReceiver : public FCrashUploadBase +{ +public: + /** + * Constructor: pings server + * @param ServerAddress Host IP of the crash report server + */ + explicit FCrashUploadToReceiver(const FString& InReceiverAddress); + + /** + * Destructor for logging + */ + virtual ~FCrashUploadToReceiver(); + + /** + * Commence upload when ready + * @param PlatformErrorReport Error report to upload files from + */ + void BeginUpload(const FPlatformErrorReport& PlatformErrorReport); + +private: + /** + * Send a request to see if the server will accept this report + * @return Whether request was successfully sent + */ + bool SendCheckReportRequest(); + + /** + * Compresses all crash report files and sends one compressed file. + */ + void CompressAndSendData(); + + /** + * Convert the report name to single byte non-zero-terminated HTTP post data + */ + void AssignReportIdToPostDataBuffer(); + + /** + * Send a POST request to the server indicating that all the files for the current report have been sent + */ + void PostReportComplete(); + + /** + * Callback from HTTP library when a request has completed + * @param HttpRequest The request object + * @param HttpResponse The response from the server + * @param bSucceeded Whether a response was successfully received + */ + void OnProcessRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded); + + /** + * Start uploading if BeginUpload has been called + */ + void OnPingSuccess(); + + /** + * Callback a set amount of time after ping request was sent + * @note Gets fired no matter whether ping response was received + * @param Unused time since last call + * @return Always returns false, meaning one-shot + */ + bool PingTimeout(float DeltaTime); + + /** + * If there a no pending files, look through pending reports for files to upload + */ + void CheckPendingReportsForFilesToUpload(); + + /** + * Start uploading files, either when user presses Submit or Ping request succeeds, whichever is later + */ + void BeginUploadImpl(); + + /** + * Create a request object and bind this class's response handler to it + */ + TSharedRef CreateHttpRequest(); + + /** + * Send a ping request to the server + */ + void SendPingRequest(); + + /** + * Parse an XML response from the server for the success field + * @param Response Response to get message to parse from + * @param OutValidReport Answer from the server on whether to continue with this report upload + * @return Whether a valid response was received from the server + */ + static bool ParseServerResponse(FHttpResponsePtr Response, bool& OutValidReport); + + /** Host, port and common prefix of all requests to the server */ + FString UrlPrefix; +}; + +/** +* Handles uploading files to the data router +*/ +class FCrashUploadToDataRouter : public FCrashUploadBase +{ +public: + /** + * Constructor: pings server + * @param ServerAddress Host IP of the crash report server + */ + explicit FCrashUploadToDataRouter(const FString& InDataRouterUrl); + + /** + * Destructor for logging + */ + virtual ~FCrashUploadToDataRouter(); + + void BeginUpload(const FPlatformErrorReport& PlatformErrorReport); + + /** + * Compresses all crash report files and sends one compressed file. + */ + void CompressAndSendData(); + + /** + * Create a request object and bind this class's response handler to it + */ + TSharedRef CreateHttpRequest(); + + /** + * Callback from HTTP library when a request has completed + * @param HttpRequest The request object + * @param HttpResponse The response from the server + * @param bSucceeded Whether a response was successfully received + */ + void OnProcessRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded); + +private: + /** + * If there a no pending files, look through pending reports for files to upload + */ + void CheckPendingReportsForFilesToUpload(); + +private: + /** Url for data router requests */ + FString DataRouterUrl; +}; diff --git a/Engine/Source/Developer/CrashReportHelper/Public/GenericErrorReport.h b/Engine/Source/Developer/CrashReportHelper/Public/GenericErrorReport.h new file mode 100644 index 000000000000..1fb8c389b783 --- /dev/null +++ b/Engine/Source/Developer/CrashReportHelper/Public/GenericErrorReport.h @@ -0,0 +1,136 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "Containers/UnrealString.h" +#include "Misc/Paths.h" +#include "CrashDescription.h" + +class FText; +class FCrashDebugHelperModule; +struct FPrimaryCrashProperties; + +/** + * Helper that works with Windows Error Reports + */ +class FGenericErrorReport +{ +public: + /** + * Default constructor: creates a report with no files + */ + FGenericErrorReport() + { + } + + /** + * Discover all files in the crash report directory + * @param Directory Full path to directory containing the report + */ + explicit FGenericErrorReport(const FString& Directory); + + /** + * One-time initialisation: does nothing by default + */ + static void Init() + { + } + + /** + * One-time clean-up: does nothing by default + */ + static void ShutDown() + { + } + + /** + * Write the provided comment into the error report + * @param UserComment Information provided by the user to add to the report + * @return Whether the comment was successfully written to the report + */ + bool SetUserComment(const FText& UserComment); + + /** Sets properties specific to the processed crash. Used to convert the old data into the crash context format. */ + void SetPrimaryCrashProperties( FPrimaryCrashProperties& out_PrimaryCrashProperties ); + + /** Sets the version string in the error report and saves the change */ + void SetCrashReportClientVersion(const FString& InVersion); + + /** + * Provide full paths to all the report files + * @return List of paths + */ + TArray GetFilesToUpload() const; + + /** + * Load the WER XML file for this report + * @note This is Windows specific and so shouldn't really be part of the public interface, but currently the server + * is Windows-specific in its checking of reports, so this is needed. + * @param OutString String to load the file into + * @return Whether finding and loading the file succeeded + */ + bool LoadWindowsReportXmlFile( FString& OutString ) const; + + /** + * @return Whether the file was found and successfully read + */ + bool TryReadDiagnosticsFile(); + + /** + * Provide the full path of the error report directory + */ + FString GetReportDirectory() const + { + return ReportDirectory; + } + + /** + * Provide the name of the error report directory + */ + FString GetReportDirectoryLeafName() const + { + // Using GetCleanFilename to actually get directory name + return FPaths::GetCleanFilename(ReportDirectory); + } + + /** + * Get the name of the crashed app from the report + */ + FString FindCrashedAppName() const; + + /** + * Get the full path of the crashed app from the report + */ + FString FindCrashedAppPath() const; + + /** + * Is there anything to upload? + */ + bool HasFilesToUpload() const + { + return ReportFilenames.Num() != 0; + } + + + /** + * Look thought the list of report files to find one with the given extension + * @return Whether a file with the extension was found + */ + bool FindFirstReportFileWithExtension(FString& OutFilename, const TCHAR* Extension) const; + + /** + * Deletes all of the files for the report + */ + void DeleteFiles(); + +protected: + /** Full path to the directory the report files are in */ + FString ReportDirectory; + + /** List of leaf filenames of all the files in the report folder */ + TArray ReportFilenames; + + /** Whether the error report generated an valid callstack. */ + mutable bool bValidCallstack; +}; diff --git a/Engine/Source/Developer/CrashReportHelper/Public/IOS/IOSErrorReport.h b/Engine/Source/Developer/CrashReportHelper/Public/IOS/IOSErrorReport.h new file mode 100644 index 000000000000..c711c18673c3 --- /dev/null +++ b/Engine/Source/Developer/CrashReportHelper/Public/IOS/IOSErrorReport.h @@ -0,0 +1,52 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "../GenericErrorReport.h" + +/** + * Helper that works with Mac Error Reports + */ +class FIOSErrorReport : public FGenericErrorReport +{ +public: + /** + * Default constructor: creates a report with no files + */ + FIOSErrorReport() + { + } + + /** + * Load helper modules + */ + static void Init(); + + /** + * Unload helper modules + */ + static void ShutDown(); + + /** + * Discover all files in the crash report directory + * @param Directory Full path to directory containing the report + */ + explicit FIOSErrorReport(const FString& Directory); + + /** + * Parse the callstack from the Apple-style crash report log + * @return UE4 crash diagnosis text + */ + FText DiagnoseReport() const; + + /** + * Get the full path of the crashed app from the report (hides implementation in FGenericErrorReport) + */ + FString FindCrashedAppPath() const; + + /** + * Look for the most recent Mac Error Report + * @return Full path to the most recent report, or an empty string if none found + */ + static void FindMostRecentErrorReports(TArray& ErrorReportPaths, const FTimespan& MaxCrashReportAge); +}; diff --git a/Engine/Source/Developer/CrashReportHelper/Public/Mac/MacErrorReport.h b/Engine/Source/Developer/CrashReportHelper/Public/Mac/MacErrorReport.h new file mode 100644 index 000000000000..8f63ebdb60ff --- /dev/null +++ b/Engine/Source/Developer/CrashReportHelper/Public/Mac/MacErrorReport.h @@ -0,0 +1,52 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "../GenericErrorReport.h" + +/** + * Helper that works with Mac Error Reports + */ +class FMacErrorReport : public FGenericErrorReport +{ +public: + /** + * Default constructor: creates a report with no files + */ + FMacErrorReport() + { + } + + /** + * Load helper modules + */ + static void Init(); + + /** + * Unload helper modules + */ + static void ShutDown(); + + /** + * Discover all files in the crash report directory + * @param Directory Full path to directory containing the report + */ + explicit FMacErrorReport(const FString& Directory); + + /** + * Parse the callstack from the Apple-style crash report log + * @return UE4 crash diagnosis text + */ + FText DiagnoseReport() const; + + /** + * Get the full path of the crashed app from the report (hides implementation in FGenericErrorReport) + */ + FString FindCrashedAppPath() const; + + /** + * Look for the most recent Mac Error Report + * @return Full path to the most recent report, or an empty string if none found + */ + static void FindMostRecentErrorReports(TArray& ErrorReportPaths, const FTimespan& MaxCrashReportAge); +}; diff --git a/Engine/Source/Developer/CrashReportHelper/Public/PlatformErrorReport.h b/Engine/Source/Developer/CrashReportHelper/Public/PlatformErrorReport.h new file mode 100644 index 000000000000..1e6d258c22f1 --- /dev/null +++ b/Engine/Source/Developer/CrashReportHelper/Public/PlatformErrorReport.h @@ -0,0 +1,31 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" + +#if PLATFORM_WINDOWS + +#include "Windows/WindowsErrorReport.h" + +typedef FWindowsErrorReport FPlatformErrorReport; + +#elif PLATFORM_LINUX + +#include "Linux/LinuxErrorReport.h" + +typedef FLinuxErrorReport FPlatformErrorReport; + +#elif PLATFORM_MAC + +#include "Mac/MacErrorReport.h" + +typedef FMacErrorReport FPlatformErrorReport; + +#elif PLATFORM_IOS + +#include "IOS/IOSErrorReport.h" + +typedef FIOSErrorReport FPlatformErrorReport; + +#endif // PLATFORM_LINUX diff --git a/Engine/Source/Developer/CrashReportHelper/Public/Windows/WindowsErrorReport.h b/Engine/Source/Developer/CrashReportHelper/Public/Windows/WindowsErrorReport.h new file mode 100644 index 000000000000..8cccac3f718a --- /dev/null +++ b/Engine/Source/Developer/CrashReportHelper/Public/Windows/WindowsErrorReport.h @@ -0,0 +1,52 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "../GenericErrorReport.h" + +/** + * Helper that works with Windows Error Reports + */ +class FWindowsErrorReport : public FGenericErrorReport +{ +public: + /** + * Default constructor: creates a report with no files + */ + FWindowsErrorReport() + { + } + + /** + * Load helper modules + */ + static void Init(); + + /** + * Unload helper modules + */ + static void ShutDown(); + + /** + * Discover all files in the crash report directory + * @param Directory Full path to directory containing the report + */ + explicit FWindowsErrorReport(const FString& Directory); + + /** + * Provide the exception and a call-stack as plain text if possible + * @note This can take quite a long time + */ + FText DiagnoseReport() const; + + /** + * Get the full path of the crashed app from the report + */ + FString FindCrashedAppPath() const; + + /** + * Look for the most recent Windows Error Reports + * @return Full path to the most recent report, or an empty string if none found + */ + static void FindMostRecentErrorReports(TArray& ErrorReportPaths, const FTimespan& MaxCrashReportAge); +}; diff --git a/Engine/Source/Developer/CrashTracker/CrashTracker.Build.cs b/Engine/Source/Developer/CrashTracker/CrashTracker.Build.cs deleted file mode 100644 index 4348bb218f6f..000000000000 --- a/Engine/Source/Developer/CrashTracker/CrashTracker.Build.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -using UnrealBuildTool; - -public class CrashTracker : ModuleRules -{ - public CrashTracker(ReadOnlyTargetRules Target) : base(Target) - { - PrivateIncludePaths.Add("Developer/CrashTracker/Private"); - - PublicDependencyModuleNames.Add("Core"); - - PrivateDependencyModuleNames.AddRange( - new string[] { - "Engine", - "ImageWrapper", - "RenderCore", - "RHI", - "ShaderCore", - "Slate", - "SlateCore", - } - ); - } -} diff --git a/Engine/Source/Developer/CrashTracker/Private/AVIHandler.cpp b/Engine/Source/Developer/CrashTracker/Private/AVIHandler.cpp deleted file mode 100644 index e00d8861edc0..000000000000 --- a/Engine/Source/Developer/CrashTracker/Private/AVIHandler.cpp +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#include "AVIHandler.h" -#include "HAL/FileManager.h" -#include "CrashVideoCapture.h" - - -// RIFF specific data structures: Lists and Chunks -template -struct FRIFFList -{ - uint8 ID[4]; - uint32 Size; - uint8 Type[4]; - DataType Data; - - FRIFFList(const TCHAR* InType, const DataType& InData) - : Size(sizeof(Type) + sizeof(Data)) - , Data(InData) - { - ID[0] = 'L'; - ID[1] = 'I'; - ID[2] = 'S'; - ID[3] = 'T'; - for (uint32 i = 0; i < 4; ++i) - { - Type[i] = InType[i]; - } - } -}; - - -template <> -struct FRIFFList -{ - uint8 ID[4]; - uint32 Size; - uint8 Type[4]; - - FRIFFList(const TCHAR* InType, uint32 InSize) - : Size(sizeof(Type) + InSize) - { - ID[0] = 'L'; - ID[1] = 'I'; - ID[2] = 'S'; - ID[3] = 'T'; - for (uint32 i = 0; i < 4; ++i) - { - Type[i] = InType[i]; - } - } -}; - - -template -struct FRIFFChunk -{ - uint8 ID[4]; - uint32 Size; - DataType Data; - - FRIFFChunk(const TCHAR* InType, const DataType& InData) - : Size(sizeof(Data)) - , Data(InData) - { - for (uint32 i = 0; i < 4; ++i) - { - ID[i] = InType[i]; - } - } -}; - - -template <> -struct FRIFFChunk -{ - uint8 ID[4]; - uint32 Size; - - FRIFFChunk(const TCHAR* InType, uint32 InSize) - : Size(InSize) - { - for (uint32 i = 0; i < 4; ++i) - { - ID[i] = InType[i]; - } - } -}; - - -// AVI Specific data structures for the RIFF AVI header -#define AVI_HAS_INDEX 0x00000010 - -struct FAVIMainHeader -{ - uint32 MicrosecondsPerFrame; - uint32 MaxBytesPerSec; - uint32 PaddingGranularity; - uint32 Flags; - uint32 TotalFrames; - uint32 InitialFrames; - uint32 Streams; - uint32 SuggestedBufferSize; - uint32 Width; - uint32 Height; - uint32 Reserved[4]; - - FAVIMainHeader(uint32 InFrames, uint32 InWidth, uint32 InHeight, uint32 InMicrosecondsPerFrame, uint32 JPEGSize) - : MicrosecondsPerFrame(InMicrosecondsPerFrame) - , MaxBytesPerSec(1000000 * (JPEGSize / InFrames) / InMicrosecondsPerFrame) - , PaddingGranularity(0) - , Flags(AVI_HAS_INDEX) - , TotalFrames(InFrames) - , InitialFrames(0) - , Streams(1) - , SuggestedBufferSize(0) - , Width(InWidth) - , Height(InHeight) - { - for (uint32 i = 0; i < 4; ++i) {Reserved[i] = 0;} - } -}; - - -struct FAVIStreamHeader -{ - uint8 Type[4]; - uint8 Handler[4]; - uint32 Flags; - uint16 Priority; - uint16 Language; - uint32 InitialFrames; - uint32 Scale; - uint32 Rate; - uint32 Start; - uint32 Length; - uint32 SuggestedBufferSize; - uint32 Quality; - uint32 SampleSize; - uint16 Left; - uint16 Top; - uint16 Right; - uint16 Bottom; - - FAVIStreamHeader(uint32 InWidth, uint32 InHeight, uint32 InFrames, uint32 InMicrosecondsPerFrame) - : Flags(0) - , Priority(0) - , Language(0) - , InitialFrames(0) - , Scale(InMicrosecondsPerFrame) - , Rate(1000000) - , Start(0) - , Length(InFrames) - , SuggestedBufferSize(0) - , Quality(0) - , SampleSize(0) - , Left(0) - , Top(0) - , Right(InWidth) - , Bottom(InHeight) - { - Type[0] = 'v'; - Type[1] = 'i'; - Type[2] = 'd'; - Type[3] = 's'; - Handler[0] = 'M'; - Handler[1] = 'J'; - Handler[2] = 'P'; - Handler[3] = 'G'; - } -}; - - -struct FAVIStreamFormat -{ - uint32 BufferSize; - uint32 Width; - uint32 Height; - uint16 Planes; - uint16 BitCount; - uint8 Compression[4]; - uint32 ImageSize; - uint32 XPixelsPerMeter; - uint32 YPixelsPerMeter; - uint32 UsedColors; - uint32 ImportantColors; - - FAVIStreamFormat(uint32 InWidth, uint32 InHeight) - : BufferSize(sizeof(FAVIStreamFormat)) - , Width(InWidth) - , Height(InHeight) - , Planes(1) - , BitCount(24) - , ImageSize(InWidth * InHeight * 3) - , XPixelsPerMeter(0) - , YPixelsPerMeter(0) - , UsedColors(0) - , ImportantColors(0) - { - Compression[0] = 'M'; - Compression[1] = 'J'; - Compression[2] = 'P'; - Compression[3] = 'G'; - } -}; - - -struct FAVIListStream -{ - FRIFFChunk StreamHeader; - FRIFFChunk StreamFormat; - - FAVIListStream(uint32 InFrames, uint32 InWidth, uint32 InHeight, uint32 InMicrosecondsPerFrame) - : StreamHeader(TEXT("strh"), FAVIStreamHeader(InWidth, InHeight, InFrames, InMicrosecondsPerFrame)) - , StreamFormat(TEXT("strf"), FAVIStreamFormat(InWidth, InHeight)) - { - } -}; - - -struct FAVIListHeader -{ - FRIFFChunk MainHeader; - FRIFFList StreamList; - - FAVIListHeader(uint32 InFrames, uint32 InWidth, uint32 InHeight, uint32 InMicrosecondsPerFrame, uint32 JPEGSize) - : MainHeader(TEXT("avih"), FAVIMainHeader(InFrames, InWidth, InHeight, InMicrosecondsPerFrame, JPEGSize)) - , StreamList(TEXT("strl"), FAVIListStream(InFrames, InWidth, InHeight, InMicrosecondsPerFrame)) - { - } -}; - - -void DumpOutMJPEGAVI(const TArray& CompressedFrames, FString OutputPath, int32 Width, int32 Height, int32 FPS) -{ - int32 FrameCount = CompressedFrames.Num(); - int32 MicrosecondsPerFrame = 1000000 / FPS; - - // pad out files with data first - int32 TotalJPEGSize = 0; - for (int32 i = 0; i < FrameCount; ++i) - { - FCompressedDataFrame* DataFrame = CompressedFrames[i]; - - check(DataFrame && DataFrame->Data && DataFrame->ActualSize <= DataFrame->BufferSize); - - int32 Padding = FMath::Min(DataFrame->BufferSize - DataFrame->ActualSize, - (4 - (DataFrame->ActualSize % 4)) % 4); - int32 TotalSize = DataFrame->ActualSize + Padding; - FMemory::Memset(DataFrame->Data + DataFrame->ActualSize, 0, Padding); - DataFrame->ActualSize = TotalSize; - - TotalJPEGSize += DataFrame->ActualSize; - } - - // write out the avi file - FArchive* Ar = IFileManager::Get().CreateFileWriter(*OutputPath, FILEWRITE_EvenIfReadOnly); - - if(Ar) - { - uint32 FileSize = 4 + - sizeof(FRIFFList) + - sizeof(FRIFFList) + TotalJPEGSize + 8 * FrameCount + - sizeof(FRIFFChunk) + 16 * FrameCount; - Ar->Serialize((void*)"RIFF", 4); - Ar->Serialize(&FileSize, sizeof(FileSize)); - Ar->Serialize((void*)"AVI ", 4); - - FRIFFList ListHeader = FRIFFList(TEXT("hdrl"), FAVIListHeader(FrameCount, Width, Height, MicrosecondsPerFrame, TotalJPEGSize)); - Ar->Serialize(&ListHeader, sizeof(ListHeader)); - - FRIFFList MoviList = FRIFFList(TEXT("movi"), TotalJPEGSize + 8 * FrameCount); - Ar->Serialize(&MoviList, sizeof(MoviList)); - for (int32 i = 0; i < FrameCount; ++i) - { - FCompressedDataFrame* DataFrame = CompressedFrames[i]; - - FRIFFChunk DataChunk = FRIFFChunk(TEXT("00dc"), DataFrame->ActualSize); - Ar->Serialize(&DataChunk, sizeof(DataChunk)); - - // replace bytes 7-10 (JFIF) with AVI1 - Ar->Serialize(DataFrame->Data, 6); - Ar->Serialize((void*)"AVI1", 4); - Ar->Serialize(DataFrame->Data + 10, DataFrame->ActualSize - 10); - } - - FRIFFChunk Idx1Chunk = FRIFFChunk(TEXT("idx1"), FrameCount * 16); - Ar->Serialize(&Idx1Chunk, sizeof(Idx1Chunk)); - int32 PreviousOffset = 0; - for (int32 i = 0; i < FrameCount; ++i) - { - FCompressedDataFrame* DataFrame = CompressedFrames[i]; - - int32 CurrentOffset = 4; - if (i > 0) - { - FCompressedDataFrame* PreviousFrame = CompressedFrames[i - 1]; - CurrentOffset = PreviousOffset + PreviousFrame->ActualSize + 8; - } - - int Flags = 0; - Ar->Serialize((void*)"00dc", 4); - Ar->Serialize(&Flags, sizeof(Flags)); - Ar->Serialize(&CurrentOffset, sizeof(CurrentOffset)); - Ar->Serialize(&DataFrame->ActualSize, sizeof(DataFrame->ActualSize)); - - PreviousOffset = CurrentOffset; - } - - delete Ar; - } -} diff --git a/Engine/Source/Developer/CrashTracker/Private/AVIHandler.h b/Engine/Source/Developer/CrashTracker/Private/AVIHandler.h deleted file mode 100644 index e530ba87c327..000000000000 --- a/Engine/Source/Developer/CrashTracker/Private/AVIHandler.h +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "CoreMinimal.h" - -/** - * Given a series of JPEG compressed images, this will wrap them with an AVI header - * and write them out as a Motion JPEG AVI video. - * - * @param CompressedFrames An ordered array of JPEG images - * @param OutputPath The path with which to dump out the video - * @param Width The width of the images - * @param Height The height of the images - * @param FPS The frame rate of the video - */ -void DumpOutMJPEGAVI(const TArray& CompressedFrames, FString OutputPath, int32 Width, int32 Height, int32 FPS); diff --git a/Engine/Source/Developer/CrashTracker/Private/CrashTrackerModule.cpp b/Engine/Source/Developer/CrashTracker/Private/CrashTrackerModule.cpp deleted file mode 100644 index 145bad7b7219..000000000000 --- a/Engine/Source/Developer/CrashTracker/Private/CrashTrackerModule.cpp +++ /dev/null @@ -1,268 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#include "CoreMinimal.h" -#include "Misc/CoreDelegates.h" -#include "Modules/ModuleManager.h" -#include "Interfaces/ICrashTrackerModule.h" -#include "HAL/FileManager.h" -#include "Misc/CommandLine.h" -#include "Misc/Paths.h" -#include "Logging/EventLogger.h" -#include "Framework/Application/SlateApplication.h" -#include "CrashVideoCapture.h" -#include "RHI.h" - -#if (PLATFORM_WINDOWS || PLATFORM_MAC) && !UE_BUILD_MINIMAL - #define CRASH_TRACKER_SUPPORTED 1 -#else - #define CRASH_TRACKER_SUPPORTED 0 -#endif - - -/** Logs keypresses to the crash tracker, as well as triggering it's completion upon a crash */ -class FCrashTrackerEventLogger : public FStabilityEventLogger -{ -public: - FCrashTrackerEventLogger(TSharedPtr InVideoCapture = NULL); - - virtual void Log(EEventLog::Type Event, const FString& AdditionalContent, TSharedPtr Widget) override; - - void OnHandleError(); - void OnHandleEnsure(); - -private: - TWeakPtr VideoCapture; -}; - - -FCrashTrackerEventLogger::FCrashTrackerEventLogger(TSharedPtr InVideoCapture) - : VideoCapture(InVideoCapture) -{ -} - - -void FCrashTrackerEventLogger::Log(EEventLog::Type Event, const FString& AdditionalContent, TSharedPtr Widget) -{ - FStabilityEventLogger::Log(Event, AdditionalContent, Widget); - - if (VideoCapture.IsValid()) - { - if (Event == EEventLog::KeyDown) - { - check(AdditionalContent.Len()); - VideoCapture.Pin()->BufferKeyPress(AdditionalContent); - } - } -} - - -void FCrashTrackerEventLogger::OnHandleError() -{ - UE_LOG(LogCrashTracker, Log, TEXT("%s"), *GetLog()); - - if (VideoCapture.IsValid()) - { - // Finish capturing video - VideoCapture.Pin()->EndCapture(/*bSaveCapture=*/true); - } -} - - -void FCrashTrackerEventLogger::OnHandleEnsure() -{ - if (VideoCapture.IsValid()) - { - // Capture video for the ensure - VideoCapture.Pin()->SaveCaptureNow(VideoCapture.Pin()->CaptureVideoPath); - } -} - - -class FCrashTrackerModule - : public ICrashTrackerModule -{ -public: - - // IModuleInterface interface - - virtual void StartupModule() override; - virtual void ShutdownModule() override; - -public: - - // ICrashTracker interface - - virtual void Update(float DeltaSeconds) override; - virtual void ForceCompleteCapture() override; - virtual void SetCrashTrackingEnabled(bool bEnabled) override; - virtual bool IsVideoCaptureAvailable() const override; - virtual bool IsCurrentlyCapturing() const override; - virtual void InvalidateCrashTrackerFrame() override; - virtual EWriteUserCaptureVideoError::Type WriteUserVideoNow( FString& OutFinalSaveName ) override; - -private: - - // The video capture instance - TSharedPtr VideoCapture; - - // The event logger instance - TSharedPtr EventLogger; -}; - - -void FCrashTrackerModule::StartupModule() -{ - FCrashVideoCapture::CaptureVideoPath = FPaths::GameLogDir() + TEXT("CrashVideo.avi"); - - // kill it just in case it's hanging around from last session's capture - IFileManager::Get().Delete(*FCrashVideoCapture::CaptureVideoPath); - - VideoCapture.Reset(); -#if CRASH_TRACKER_SUPPORTED - if (GIsEditor && - (GMaxRHIShaderPlatform == SP_PCD3D_SM4 || GMaxRHIShaderPlatform == SP_PCD3D_SM5 || GMaxRHIShaderPlatform == SP_OPENGL_SM4 || GMaxRHIShaderPlatform == SP_OPENGL_SM4_MAC)) - { - bool bCrashTrackerShouldBeEnabled = false; -#if UE_BUILD_DEVELOPMENT - // Disable crash tracker by default for now unless someone enables it. - // bCrashTrackerShouldBeEnabled = - // !GIsDemoMode && - // !FParse::Param( FCommandLine::Get(), TEXT("disablecrashtracker") ) && - // !FApp::IsBenchmarking() && - // !FPlatformMisc::IsDebuggerPresent(); -#endif - bool bForceEnableCrashTracker = FParse::Param( FCommandLine::Get(), TEXT("forceenablecrashtracker") ); - - if (bCrashTrackerShouldBeEnabled || bForceEnableCrashTracker) - { - VideoCapture = MakeShareable(new FCrashVideoCapture); - } - } -#endif //CRASH_TRACKER_SUPPORTED - - EventLogger = MakeShareable( new FCrashTrackerEventLogger(VideoCapture) ); - FSlateApplication::Get().SetSlateUILogger(EventLogger); - // hook up event logger to global assert/ensure hook - FCoreDelegates::OnHandleSystemEnsure.AddRaw(EventLogger.Get(), &FCrashTrackerEventLogger::OnHandleEnsure); - FCoreDelegates::OnHandleSystemError.AddRaw(EventLogger.Get(), &FCrashTrackerEventLogger::OnHandleError); - - if (VideoCapture.IsValid()) - { - UE_LOG(LogCrashTracker, Log, TEXT("Crashtracker beginning capture.")); - VideoCapture->BeginCapture(FSlateApplication::Get().GetRenderer().Get()); - } - else - { - UE_LOG(LogCrashTracker, Log, TEXT("Crashtracker disabled due to settings.")); - } -} - - -void FCrashTrackerModule::ShutdownModule() -{ - // Make sure we remove the hook to prevent calling this when it's garbage - FCoreDelegates::OnHandleSystemEnsure.RemoveAll(EventLogger.Get()); - FCoreDelegates::OnHandleSystemError.RemoveAll(EventLogger.Get()); - - VideoCapture.Reset(); -} - - -void FCrashTrackerModule::Update(float DeltaSeconds) -{ - if (VideoCapture.IsValid()) - { - VideoCapture->Update(DeltaSeconds); - } -} - - -void FCrashTrackerModule::ForceCompleteCapture() -{ - if (VideoCapture.IsValid()) - { - VideoCapture->EndCapture(/*bSaveCapture=*/true); - check(0); - } -} - - -void FCrashTrackerModule::SetCrashTrackingEnabled(bool bEnabled) -{ - if (VideoCapture.IsValid()) - { - VideoCapture->SetCrashTrackingEnabled(bEnabled); - } -} - - -bool FCrashTrackerModule::IsVideoCaptureAvailable() const -{ - return VideoCapture.IsValid(); -} - - -bool FCrashTrackerModule::IsCurrentlyCapturing() const -{ - return VideoCapture.IsValid() && VideoCapture->IsCapturing(); -} - - -void FCrashTrackerModule::InvalidateCrashTrackerFrame() -{ - if (VideoCapture.IsValid()) - { - VideoCapture->InvalidateFrame(); - } -} - - -EWriteUserCaptureVideoError::Type FCrashTrackerModule::WriteUserVideoNow( FString& OutFinalSaveName ) -{ - EWriteUserCaptureVideoError::Type WriteResult = EWriteUserCaptureVideoError::None; - if(VideoCapture.IsValid()) - { - // Check if the capture is running and try to create the video capture folder. - if( !VideoCapture->IsCapturing() ) - { - WriteResult = EWriteUserCaptureVideoError::CaptureNotRunning; - } - else if( !IFileManager::Get().MakeDirectory( *FPaths::VideoCaptureDir(), true ) ) - { - WriteResult = EWriteUserCaptureVideoError::FailedToCreateDirectory; - } - } - else - { - WriteResult = EWriteUserCaptureVideoError::VideoCaptureInvalid; - } - - // If there was no error find a suitable filename and write the file. - if( WriteResult == EWriteUserCaptureVideoError::None ) - { - // The final save name - OutFinalSaveName = ""; - // have we got a name - bool bGotName = false; - // Counter used to build filename - int32 SaveNameCount = 1; - while( bGotName == false ) - { - // Build a name from the video capture path and an incrementing count - OutFinalSaveName = FString::Printf(TEXT("%s_%02d.avi"), *(FPaths::VideoCaptureDir() + TEXT("CaptureVideo" ) ) , SaveNameCount ); - // FileSize returns INDEX_NONE if the file doesn't exist - if( IFileManager::Get().FileSize( *OutFinalSaveName ) == INDEX_NONE ) - { - bGotName = true; - } - // Try another filename - SaveNameCount++; - } - // We now have a filename - write the video. This can only return false if the capture is not running - and we already checked for that - VideoCapture->SaveCaptureNow( OutFinalSaveName ); - } - return WriteResult; -} - - -IMPLEMENT_MODULE(FCrashTrackerModule, CrashTracker); diff --git a/Engine/Source/Developer/CrashTracker/Private/CrashVideoCapture.cpp b/Engine/Source/Developer/CrashTracker/Private/CrashVideoCapture.cpp deleted file mode 100644 index 434f90df8c4b..000000000000 --- a/Engine/Source/Developer/CrashTracker/Private/CrashVideoCapture.cpp +++ /dev/null @@ -1,370 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#include "CrashVideoCapture.h" -#include "Modules/ModuleManager.h" -#include "Interfaces/IImageWrapperModule.h" -#include "HAL/FileManager.h" -#include "Misc/ScopeLock.h" -#include "AVIHandler.h" -#include "RenderingThread.h" - -DEFINE_LOG_CATEGORY(LogCrashTracker); - -/*----------------------------------------------------------------------------- - Stat declarations. ------------------------------------------------------------------------------*/ - -DECLARE_CYCLE_STAT(TEXT("Total Time"),STAT_TotalTime,STATGROUP_CrashTracker); -DECLARE_CYCLE_STAT(TEXT("Send Frame To Compressor"),STAT_SendFrameToCompressor,STATGROUP_CrashTracker); -DECLARE_CYCLE_STAT(TEXT("Wait For Previous Frame To Compress"),STAT_WaitForPreviousFrameToCompress,STATGROUP_CrashTracker); - -namespace CrashTrackerConstants -{ - static const int32 MaxVideoFrameCompressedSize = 400 * 1024; // 400 KB - - static const int32 JPEGQuality = 85; // high quality - - static const int32 VideoFramesToCapture = 200; - static const float CaptureFrequency = 0.1f; // 10 fps - - static const float SecondsToKeyPressFade = 2.f; - static const int32 MaxKeyPressesInBuffer = 15; - - // Crash tracker video stream is scaled down by 50% to reduce the about of system resources used while - // working in the editor during capture - static const float ScreenScaling = 0.5f; -} - - -FCompressedDataFrame::FCompressedDataFrame(int InBufferSize) - : Data(NULL) - , BufferSize(InBufferSize) - , ActualSize(0) -{ - Data = new uint8[BufferSize]; -} - - -FCompressedDataFrame::~FCompressedDataFrame() -{ - delete [] Data; -} - - -FAsyncImageCompress::FAsyncImageCompress(IImageWrapperPtr InImageWrapper, class FCompressedDataFrame* InDataFrame) - : ImageWrapper(InImageWrapper) - , DataFrame(InDataFrame) -{} - - -void FAsyncImageCompress::DoWork() -{ - TArray CompressedData = ImageWrapper->GetCompressed(CrashTrackerConstants::JPEGQuality); - int32 CompressedSize = CompressedData.Num(); - - if (CompressedSize <= CrashTrackerConstants::MaxVideoFrameCompressedSize) - { - DataFrame->ActualSize = CompressedSize; - - FMemory::Memcpy(DataFrame->Data, CompressedData.GetData(), CompressedSize); - } - else - { - UE_LOG(LogCrashTracker, Warning, TEXT("Crash Tracker Size of %i bytes was too large. Frame Dropped."), CompressedSize); - DataFrame->ActualSize = 0; - } -} - - -FString FCrashVideoCapture::CaptureVideoPath; - - -FCrashVideoCapture::FCrashVideoCapture() - : CurrentBufferIndex(0) - , Width(0) - , Height(0) - , CaptureSlateRenderer(NULL) - , CurrentAccumSeconds(0.f) - , CurrentFrameCaptureIndex(0) - , bIsRunning(false) - , KeypressBuffer() - , CompressedFrames() - , AsyncTask(NULL) - , CVarCrashTrackerIsRunning( - TEXT("CrashTracker.IsRunning"), - bIsRunning, - TEXT("Whether to toggle the running of crash video capturing in the background.")) -{ -} - - -FCrashVideoCapture::~FCrashVideoCapture() -{ - if (bIsRunning) - { - EndCapture(/*bSaveCapture=*/false); - } -} - - -void FCrashVideoCapture::BeginCapture(FSlateRenderer* SlateRenderer) -{ - IFileManager::Get().Delete(*CaptureVideoPath); - - CaptureSlateRenderer = SlateRenderer; - CurrentAccumSeconds = 0.f; - CurrentFrameCaptureIndex = 0; - - KeypressBuffer.Empty(); - - Buffer[0].Reset(); - Buffer[1].Reset(); - CurrentBufferIndex = 0; - - CompressedFrames.Empty(CrashTrackerConstants::VideoFramesToCapture); - for (int32 i = 0; i < CrashTrackerConstants::VideoFramesToCapture; ++i) - { - CompressedFrames.Add(new FCompressedDataFrame(CrashTrackerConstants::MaxVideoFrameCompressedSize)); - } - - bIsRunning = true; -} - - -void FCrashVideoCapture::EndCapture(bool bSaveCapture) -{ - UE_LOG(LogCrashTracker, Log, TEXT("Ending crash video capture.")); - - if (bSaveCapture && bIsRunning) - { - // ensure we capture the last frame - if (IsInGameThread() && IsRenderingThreadHealthy()) - { - Update(CrashTrackerConstants::CaptureFrequency); - } - else - { - UE_LOG(LogCrashTracker, Log, TEXT("Crashed outside of game thread; not drawing final frame")); - } - CleanupFinalFrame(); - SaveFinalCapture( CaptureVideoPath ); - } - else - { - CleanupFinalFrame(); - } - - for (int32 i = 0; i < 2; ++i) - { - Buffer[i].Reset(); - } - KeypressBuffer.Empty(); - for (int32 i = 0; i < CompressedFrames.Num(); ++i) - { - delete CompressedFrames[i]; - } - CompressedFrames.Empty(); - - bIsRunning = false; -} - - -void FCrashVideoCapture::CleanupFinalFrame() -{ - SyncWorkerThread(); - - if (IsInGameThread() && IsRenderingThreadHealthy()) - { - UE_LOG(LogCrashTracker, Log, TEXT("Attempting final rendering command flush...")); - - FlushRenderingCommands(); - - UE_LOG(LogCrashTracker, Log, TEXT("Finished final rendering command flush")); - } - else - { - UE_LOG(LogCrashTracker, Log, TEXT("Crashed outside of game thread; not flushing render commands")); - } -} - - -void FCrashVideoCapture::SetCrashTrackingEnabled(bool bEnabled) -{ - bIsRunning = bEnabled; -} - - -void FCrashVideoCapture::SaveFinalCapture( const FString& CapturePath ) -{ - int32 FinalFrameIndex = CurrentFrameCaptureIndex == 0 ? CrashTrackerConstants::VideoFramesToCapture - 1 : CurrentFrameCaptureIndex - 1; - - FCompressedDataFrame* FinalFrame = NULL; - TArray OrderedDataFrames; - for (int32 i = CurrentFrameCaptureIndex; i != FinalFrameIndex; i = (i + 1) % CrashTrackerConstants::VideoFramesToCapture) - { - FCompressedDataFrame* DataFrame = CompressedFrames[i]; - - if (DataFrame->ActualSize > 0) - { - OrderedDataFrames.Add(DataFrame); - FinalFrame = DataFrame; - } - } - - // duplicate the final frame at the end to fill 1 second so the end viewer - // can see what happened exactly at the very end - // this may not be useful with a crash on a non-game thread, because the final frame can't be drawn - if (FinalFrame) - { - int32 ExtraFramesAdded = FMath::TruncToInt(1.f / CrashTrackerConstants::CaptureFrequency); - for (int32 i = 0; i < ExtraFramesAdded; ++i) - { - OrderedDataFrames.Add(FinalFrame); - } - } - - DumpOutMJPEGAVI(OrderedDataFrames, CapturePath, Width, Height, FMath::TruncToInt(1.f / CrashTrackerConstants::CaptureFrequency)); - - UE_LOG(LogCrashTracker, Log, TEXT("Finished dumping out crash capture video. %i Frames at %ix%i"), OrderedDataFrames.Num(), Width, Height); -} - - -void FCrashVideoCapture::SyncWorkerThread() -{ - FScopeLock SyncWorkerThreadLock(&SyncWorkerThreadSection); - - if (AsyncTask) - { - AsyncTask->EnsureCompletion(/*bDoWorkOnThisThreadIfNotStarted=*/true); - delete AsyncTask; - AsyncTask = NULL; - } -} - - -void FCrashVideoCapture::Update(float DeltaSeconds) -{ - SCOPE_CYCLE_COUNTER(STAT_TotalTime); - - if (bIsRunning) - { - // Update the key press buffer times - for (int32 i = 0; i < KeypressBuffer.Num(); ++i) - { - KeypressBuffer[i].Value -= DeltaSeconds; - } - - // check to see if we need to render a new frame - bool bShouldUpdate = false; - CurrentAccumSeconds += DeltaSeconds; - if (CurrentAccumSeconds > CrashTrackerConstants::CaptureFrequency) - { - CurrentAccumSeconds -= FMath::TruncToFloat(CurrentAccumSeconds / CrashTrackerConstants::CaptureFrequency) * CrashTrackerConstants::CaptureFrequency; - bShouldUpdate = true; - } - - if (bShouldUpdate) - { - CleanupKeyPressBuffer(DeltaSeconds); - - TArray StrippedKeyPressBuffer; - for (int32 i = 0; i < KeypressBuffer.Num(); ++i) - { - StrippedKeyPressBuffer.Add(KeypressBuffer[i].Key); - } - - const FMappedTextureBuffer& CurrentBuffer = Buffer[CurrentBufferIndex]; - - if ( CurrentBuffer.IsValid() ) - { - IImageWrapperPtr ImageWrapper; - - { - SCOPE_CYCLE_COUNTER(STAT_SendFrameToCompressor); - - IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked( FName("ImageWrapper") ); - ImageWrapper = ImageWrapperModule.CreateImageWrapper( EImageFormat::JPEG ); - ImageWrapper->SetRaw(CurrentBuffer.Data, CurrentBuffer.Width * CurrentBuffer.Height * sizeof(FColor), CurrentBuffer.Width, CurrentBuffer.Height, ERGBFormat::RGBA, 8); - } - - { - SCOPE_CYCLE_COUNTER(STAT_WaitForPreviousFrameToCompress); - - SyncWorkerThread(); - - AsyncTask = new FAsyncTask(ImageWrapper, CompressedFrames[CurrentFrameCaptureIndex]); - AsyncTask->StartBackgroundTask(); - } - - CaptureSlateRenderer->UnmapVirtualScreenBuffer(); - } - - ++CurrentFrameCaptureIndex; - if (CurrentFrameCaptureIndex >= CrashTrackerConstants::VideoFramesToCapture) - { - CurrentFrameCaptureIndex = 0; - } - - const bool bPrimaryWorkAreaOnly = false; // We want all monitors captured for crash reporting - const FIntRect VirtualScreen = CaptureSlateRenderer->SetupVirtualScreenBuffer(bPrimaryWorkAreaOnly, CrashTrackerConstants::ScreenScaling, nullptr); - Width = VirtualScreen.Width(); - Height = VirtualScreen.Height(); - CaptureSlateRenderer->CopyWindowsToVirtualScreenBuffer(StrippedKeyPressBuffer); - CaptureSlateRenderer->MapVirtualScreenBuffer(&Buffer[CurrentBufferIndex]); - - CurrentBufferIndex = (CurrentBufferIndex + 1) % 2; - } - } -} - - -bool FCrashVideoCapture::IsCapturing() const -{ - return bIsRunning != 0; -} - - -void FCrashVideoCapture::InvalidateFrame() -{ - Buffer[0].Reset(); - Buffer[1].Reset(); -} - - -void FCrashVideoCapture::BufferKeyPress(const FString& KeyPress) -{ - KeypressBuffer.Add(TKeyValuePair(KeyPress, CrashTrackerConstants::SecondsToKeyPressFade)); -} - - -void FCrashVideoCapture::CleanupKeyPressBuffer(float DeltaSeconds) -{ - TArray< TKeyValuePair > NewKeyPressBuffer; - int32 StartKeyPressIndex = FMath::Max(0, KeypressBuffer.Num() - CrashTrackerConstants::MaxKeyPressesInBuffer); - for (int32 i = StartKeyPressIndex; i < KeypressBuffer.Num(); ++i) - { - if (KeypressBuffer[i].Value > 0) {NewKeyPressBuffer.Add(KeypressBuffer[i]);} - } - KeypressBuffer = NewKeyPressBuffer; -} - - -bool FCrashVideoCapture::SaveCaptureNow( const FString& CapturePath ) -{ - bool bSavedOk = false; - UE_LOG(LogCrashTracker, Log, TEXT("Forcing save of crash video capture to %s.") , *CapturePath ); - - if (bIsRunning) - { - SyncWorkerThread(); - - SaveFinalCapture( CapturePath ); - - bSavedOk = true; - } - return bSavedOk; -} - - - - diff --git a/Engine/Source/Developer/CrashTracker/Private/CrashVideoCapture.h b/Engine/Source/Developer/CrashTracker/Private/CrashVideoCapture.h deleted file mode 100644 index d5f6b14d3a16..000000000000 --- a/Engine/Source/Developer/CrashTracker/Private/CrashVideoCapture.h +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "CoreMinimal.h" -#include "Stats/Stats.h" -#include "HAL/IConsoleManager.h" -#include "Interfaces/IImageWrapper.h" -#include "Async/AsyncWork.h" -#include "Rendering/SlateRenderer.h" - -DECLARE_LOG_CATEGORY_EXTERN(LogCrashTracker, Log, All); - - -/** - * A buffer for holding a compressed video frame. - */ -class FCompressedDataFrame -{ -public: - FCompressedDataFrame(int InBufferSize); - ~FCompressedDataFrame(); - - // The data buffer - uint8* Data; - // The data buffer's size - int32 BufferSize; - // The actual size of the compressed data - int32 ActualSize; -}; - - - -/** - * An asynchronous task for compressing an image. - */ -class FAsyncImageCompress : public FNonAbandonableTask -{ -public: - FAsyncImageCompress(IImageWrapperPtr InImageWrapper, class FCompressedDataFrame* InDataFrame); - - void DoWork(); - - FORCEINLINE TStatId GetStatId() const - { - RETURN_QUICK_DECLARE_CYCLE_STAT(FAsyncImageCompress, STATGROUP_ThreadPoolAsyncTasks); - } - -private: - /** The image compression algorithm to use */ - IImageWrapperPtr ImageWrapper; - /** The data frame we are dumping our data out to */ - FCompressedDataFrame* DataFrame; -}; - - - -/** - * The crash tracker handles slate key logging and if CRASH_TRACKER_ENABLED, also crash video capture. - */ -class FCrashVideoCapture -{ -public: - FCrashVideoCapture(); - ~FCrashVideoCapture(); - - /** Initiates capture of video frames */ - void BeginCapture(class FSlateRenderer* SlateRenderer); - - /** Ends capture of video frames */ - void EndCapture(bool bSaveCapture); - - /** Updates the crash tracker, which may trigger the capture of a frame */ - void Update(float DeltaSeconds); - - /** Cleans up the final frame for capture, forces all async threads to sync */ - void CleanupFinalFrame(); - - /** Enables or disables crash tracking */ - void SetCrashTrackingEnabled(bool bEnabled); - - /** Whether or not the crash tracker is capturing anything */ - bool IsCapturing() const; - - void InvalidateFrame(); - - /** Sends a key press to the crash tracker */ - void BufferKeyPress(const FString& KeyPress); - - /** - * Force a save of the current capture buffer - * - * @param CapturePath filepath to save to - * @returns Returns true if video capture file was successfully written - */ - bool SaveCaptureNow( const FString& CapturePath ); - - /** The path that we output to */ - static FString CaptureVideoPath; - -private: - /** Clears up all key presses we have buffered */ - void CleanupKeyPressBuffer(float DeltaSeconds); - - /** - * Saves the final video capture - * - * @param CapturePath filepath to save to - */ - void SaveFinalCapture( const FString& CapturePath ); - - /** Syncs up the asynchronous image compression thread */ - void SyncWorkerThread(); - -private: - /** A temporary pair of buffers that we write our video frames to */ - FMappedTextureBuffer Buffer[2]; - /** We ping pong between the buffers in case the GPU is a frame behind (GSystemSettings.bAllowOneFrameThreadLag) */ - int32 CurrentBufferIndex; - /** The width and height of these frames */ - int32 Width; - int32 Height; - /** The slate renderer we are getting our frames from */ - FSlateRenderer* CaptureSlateRenderer; - - /** The current seconds accumulated from each Tick */ - float CurrentAccumSeconds; - /** The current frame index that we are capturing to */ - int CurrentFrameCaptureIndex; - /** Whether or not the video capture is running or not, this is an int32 for the autoconsolevariableref */ - int32 bIsRunning; - /** A buffer of all the key presses and their associated time to death */ - TArray< TKeyValuePair > KeypressBuffer; - - /** A ring buffer of all the compressed frames we have */ - TArray CompressedFrames; - /** The asynchronous task for compressing a single frame */ - FAsyncTask* AsyncTask; - - /** Console variable for toggling whether the capture is running */ - FAutoConsoleVariableRef CVarCrashTrackerIsRunning; - - /** Ensures only one thread will ever sync up with the image compression worker thread */ - FCriticalSection SyncWorkerThreadSection; -}; diff --git a/Engine/Source/Developer/CrashTracker/Public/CrashTracker.h b/Engine/Source/Developer/CrashTracker/Public/CrashTracker.h deleted file mode 100644 index 460812aac7fc..000000000000 --- a/Engine/Source/Developer/CrashTracker/Public/CrashTracker.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - - -/* Boilerplate - *****************************************************************************/ - -#include "Misc/MonolithicHeaderBoilerplate.h" -MONOLITHIC_HEADER_BOILERPLATE() - - -/* Dependencies - *****************************************************************************/ - -#include "Modules/ModuleManager.h" - - -/* Interfaces - *****************************************************************************/ - -#include "Interfaces/ICrashTrackerModule.h" diff --git a/Engine/Source/Developer/CrashTracker/Public/Interfaces/ICrashTrackerModule.h b/Engine/Source/Developer/CrashTracker/Public/Interfaces/ICrashTrackerModule.h deleted file mode 100644 index 90cf4c62c581..000000000000 --- a/Engine/Source/Developer/CrashTracker/Public/Interfaces/ICrashTrackerModule.h +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "CoreMinimal.h" -#include "Modules/ModuleInterface.h" - -namespace EWriteUserCaptureVideoError -{ - /** - * Enumerates video capture write error codes. - */ - enum Type - { - None, - - /** The video capture instance was invalid. */ - VideoCaptureInvalid, - - /** Video capture is not running. */ - CaptureNotRunning, - - /** Failed to create destination directory for the video. */ - FailedToCreateDirectory, - }; -} - - -/** - * Interface for crash tracker modules. - */ -class ICrashTrackerModule - : public IModuleInterface -{ -public: - - /** - * Forces the crash tracker to complete capturing as if the program had crashed. - */ - virtual void ForceCompleteCapture() = 0; - - /** - * Invalidates the current crash tracker frame being generated. - */ - virtual void InvalidateCrashTrackerFrame() = 0; - - /** - * Checks if the crash tracker is currently enabled. - */ - virtual bool IsCurrentlyCapturing() const = 0; - - /** - * Checks if the crash tracker is available. - */ - virtual bool IsVideoCaptureAvailable() const = 0; - - /** - * Enables or disables crash tracking while in flight. - */ - virtual void SetCrashTrackingEnabled(bool bEnabled) = 0; - - /** - * Updates the crash tracker, which may trigger the capture of a frame. - * Will also begin capturing if it hasn't begun already. - */ - virtual void Update(float DeltaSeconds) = 0; - - /** - * Write the current crash tracker as a user video. - * - * @param OutFinalSaveName The path and name of the file the video was saved as. - * @return If the video was successfully written will return EWriteUserCaptureVideoError::None, otherwise returns an error code. - */ - virtual EWriteUserCaptureVideoError::Type WriteUserVideoNow( FString& OutFinalSaveName ) = 0; - -public: - - /** - * Virtual destructor. - */ - virtual ~ICrashTrackerModule( ) { } -}; diff --git a/Engine/Source/Developer/DerivedDataCache/Private/DerivedDataBackends.cpp b/Engine/Source/Developer/DerivedDataCache/Private/DerivedDataBackends.cpp index 95c1147e6503..7e1e2a28c26b 100644 --- a/Engine/Source/Developer/DerivedDataCache/Private/DerivedDataBackends.cpp +++ b/Engine/Source/Developer/DerivedDataCache/Private/DerivedDataBackends.cpp @@ -648,7 +648,7 @@ public: return Cache; } - ~FDerivedDataBackendGraph() + virtual ~FDerivedDataBackendGraph() { RootCache = NULL; DestroyCreatedBackends(); diff --git a/Engine/Source/Developer/DerivedDataCache/Private/FileSystemDerivedDataBackend.cpp b/Engine/Source/Developer/DerivedDataCache/Private/FileSystemDerivedDataBackend.cpp index 17c95616adca..bb401268e154 100644 --- a/Engine/Source/Developer/DerivedDataCache/Private/FileSystemDerivedDataBackend.cpp +++ b/Engine/Source/Developer/DerivedDataCache/Private/FileSystemDerivedDataBackend.cpp @@ -155,9 +155,7 @@ public: { IFileManager::Get().SetTimeStamp(*Filename, FDateTime::UtcNow()); } - } - if (bExists) - { + COOK_STAT(Timer.AddHit(0)); } return bExists; diff --git a/Engine/Source/Developer/DesktopPlatform/Private/Linux/DesktopPlatformLinux.cpp b/Engine/Source/Developer/DesktopPlatform/Private/Linux/DesktopPlatformLinux.cpp index 13d2087c7748..31a8afb30c26 100644 --- a/Engine/Source/Developer/DesktopPlatform/Private/Linux/DesktopPlatformLinux.cpp +++ b/Engine/Source/Developer/DesktopPlatform/Private/Linux/DesktopPlatformLinux.cpp @@ -185,18 +185,6 @@ bool FDesktopPlatformLinux::OpenFontDialog(const void* ParentWindowHandle, FStri return false; } -bool FDesktopPlatformLinux::CanOpenLauncher(bool Install) -{ - // TODO: no launcher support at the moment - return false; -} - -bool FDesktopPlatformLinux::OpenLauncher(const FOpenLauncherOptions& Options) -{ - // TODO: support launcher for realz - return true; -} - bool FDesktopPlatformLinux::FileDialogShared(bool bSave, const void* ParentWindowHandle, const FString& DialogTitle, const FString& DefaultPath, const FString& DefaultFile, const FString& FileTypes, uint32 Flags, TArray& OutFilenames, int32& OutFilterIndex) { #if WITH_LINUX_NATIVE_DIALOGS diff --git a/Engine/Source/Developer/DesktopPlatform/Private/Linux/DesktopPlatformLinux.h b/Engine/Source/Developer/DesktopPlatform/Private/Linux/DesktopPlatformLinux.h index edabb0bcf97b..510efd54fb00 100644 --- a/Engine/Source/Developer/DesktopPlatform/Private/Linux/DesktopPlatformLinux.h +++ b/Engine/Source/Developer/DesktopPlatform/Private/Linux/DesktopPlatformLinux.h @@ -14,8 +14,6 @@ public: virtual bool SaveFileDialog(const void* ParentWindowHandle, const FString& DialogTitle, const FString& DefaultPath, const FString& DefaultFile, const FString& FileTypes, uint32 Flags, TArray& OutFilenames) override; virtual bool OpenDirectoryDialog(const void* ParentWindowHandle, const FString& DialogTitle, const FString& DefaultPath, FString& OutFolderName) override; virtual bool OpenFontDialog(const void* ParentWindowHandle, FString& OutFontName, float& OutHeight, EFontImportFlags& OutFlags) override; - virtual bool CanOpenLauncher(bool Install) override; - virtual bool OpenLauncher(const FOpenLauncherOptions& Options) override; virtual bool RegisterEngineInstallation(const FString &RootDir, FString &OutIdentifier) override; virtual void EnumerateEngineInstallations(TMap &OutInstallations) override; diff --git a/Engine/Source/Developer/DesktopPlatform/Private/Mac/DesktopPlatformMac.cpp b/Engine/Source/Developer/DesktopPlatform/Private/Mac/DesktopPlatformMac.cpp index 8856d32e993f..31f5a50bc2af 100644 --- a/Engine/Source/Developer/DesktopPlatform/Private/Mac/DesktopPlatformMac.cpp +++ b/Engine/Source/Developer/DesktopPlatform/Private/Mac/DesktopPlatformMac.cpp @@ -358,53 +358,6 @@ bool FDesktopPlatformMac::OpenFontDialog(const void* ParentWindowHandle, FString return bSuccess; } -bool FDesktopPlatformMac::CanOpenLauncher(bool Install) -{ - FString Path; - return IsLauncherInstalled() || (Install && GetLauncherInstallerPath(Path)); -} - -bool FDesktopPlatformMac::OpenLauncher(const FOpenLauncherOptions& Options) -{ - FString LauncherUriRequest = Options.GetLauncherUriRequest(); - - // If the launcher is already running, bring it to front - NSArray* RunningLaunchers = [NSRunningApplication runningApplicationsWithBundleIdentifier: @"com.epicgames.EpicGamesLauncher"]; - if ([RunningLaunchers count] == 0) - { - RunningLaunchers = [NSRunningApplication runningApplicationsWithBundleIdentifier: @"com.epicgames.UnrealEngineLauncher"]; - } - - if ([RunningLaunchers count] > 0) - { - NSRunningApplication* Launcher = [RunningLaunchers objectAtIndex: 0]; - if ( !Launcher.hidden || Options.bInstall ) // If the launcher is running, but hidden, don't activate on editor startup - { - [Launcher activateWithOptions : NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps]; - FString Error; - FPlatformProcess::LaunchURL(*LauncherUriRequest, nullptr, &Error); - } - return true; - } - - if (IsLauncherInstalled()) - { - FString Error; - FPlatformProcess::LaunchURL(*LauncherUriRequest, nullptr, &Error); - return true; - } - - // Try to install it - FString InstallerPath; - if (GetLauncherInstallerPath(InstallerPath)) - { - FPlatformProcess::LaunchFileInDefaultExternalApplication(*InstallerPath); - return true; - } - - return false; -} - bool FDesktopPlatformMac::FileDialogShared(bool bSave, const void* ParentWindowHandle, const FString& DialogTitle, const FString& DefaultPath, const FString& DefaultFile, const FString& FileTypes, uint32 Flags, TArray& OutFilenames, int32& OutFilterIndex) { MacApplication->SetCapture( NULL ); @@ -663,44 +616,6 @@ bool FDesktopPlatformMac::IsUnrealBuildToolRunning() return FPlatformProcess::IsApplicationRunning(TEXT("mono")); } -bool FDesktopPlatformMac::IsLauncherInstalled() const -{ - // Otherwise search for it... - NSWorkspace* Workspace = [NSWorkspace sharedWorkspace]; - NSString* Path = [Workspace fullPathForApplication:@"Epic Games Launcher"]; - if( Path ) - { - return true; - } - - // Otherwise search for the old Launcher... - Path = [Workspace fullPathForApplication:@"Unreal Engine"]; - if( Path ) - { - return true; - } - - return false; -} - -bool FDesktopPlatformMac::GetLauncherInstallerPath(FString& OutInstallerPath) const -{ - // Check if the installer exists - FString InstallerPath = FPaths::ConvertRelativePathToFull(FPaths::Combine(*FPaths::EngineDir(), TEXT("Extras/UnrealEngineLauncher/EpicGamesLauncher.dmg"))); - if (FPaths::FileExists(InstallerPath)) - { - OutInstallerPath = InstallerPath; - return true; - } - InstallerPath = FPaths::ConvertRelativePathToFull(FPaths::Combine(*FPaths::EngineDir(), TEXT("Extras/UnrealEngineLauncher/UnrealEngine.dmg"))); - if (FPaths::FileExists(InstallerPath)) - { - OutInstallerPath = InstallerPath; - return true; - } - return false; -} - FFeedbackContext* FDesktopPlatformMac::GetNativeFeedbackContext() { static FMacNativeFeedbackContext Warn; diff --git a/Engine/Source/Developer/DesktopPlatform/Private/Mac/DesktopPlatformMac.h b/Engine/Source/Developer/DesktopPlatform/Private/Mac/DesktopPlatformMac.h index 015260a6b714..7bcf1cb055d3 100644 --- a/Engine/Source/Developer/DesktopPlatform/Private/Mac/DesktopPlatformMac.h +++ b/Engine/Source/Developer/DesktopPlatform/Private/Mac/DesktopPlatformMac.h @@ -13,8 +13,6 @@ public: virtual bool SaveFileDialog(const void* ParentWindowHandle, const FString& DialogTitle, const FString& DefaultPath, const FString& DefaultFile, const FString& FileTypes, uint32 Flags, TArray& OutFilenames) override; virtual bool OpenDirectoryDialog(const void* ParentWindowHandle, const FString& DialogTitle, const FString& DefaultPath, FString& OutFolderName) override; virtual bool OpenFontDialog(const void* ParentWindowHandle, FString& OutFontName, float& OutHeight, EFontImportFlags& OutFlags) override; - virtual bool CanOpenLauncher(bool Install) override; - virtual bool OpenLauncher(const FOpenLauncherOptions& Options) override; virtual bool RegisterEngineInstallation(const FString &RootDir, FString &OutIdentifier) override; virtual void EnumerateEngineInstallations(TMap &OutInstallations) override; @@ -30,8 +28,6 @@ public: virtual FString GetUserTempPath() override; private: - bool IsLauncherInstalled() const; - bool GetLauncherInstallerPath(FString& OutInstallerPath) const; bool FileDialogShared(bool bSave, const void* ParentWindowHandle, const FString& DialogTitle, const FString& DefaultPath, const FString& DefaultFile, const FString& FileTypes, uint32 Flags, TArray& OutFilenames, int32& OutFilterIndex); }; diff --git a/Engine/Source/Developer/DesktopPlatform/Private/Windows/DesktopPlatformWindows.cpp b/Engine/Source/Developer/DesktopPlatform/Private/Windows/DesktopPlatformWindows.cpp index 26522a372051..68ae61dc0548 100644 --- a/Engine/Source/Developer/DesktopPlatform/Private/Windows/DesktopPlatformWindows.cpp +++ b/Engine/Source/Developer/DesktopPlatform/Private/Windows/DesktopPlatformWindows.cpp @@ -146,51 +146,6 @@ bool FDesktopPlatformWindows::OpenFontDialog(const void* ParentWindowHandle, FSt return bSuccess; } -bool FDesktopPlatformWindows::CanOpenLauncher(bool Install) -{ - FRegistryRootedKey UriProtocolKey(HKEY_CLASSES_ROOT, TEXT("com.epicgames.launcher")); - - // Check if the launcher exists, or (optionally) if the installer exists - FString Path; - return UriProtocolKey.Exists() || (Install && GetLauncherInstallerPath(Path)); -} - -bool FDesktopPlatformWindows::OpenLauncher(const FOpenLauncherOptions& Options) -{ - FRegistryRootedKey UriProtocolKey(HKEY_CLASSES_ROOT, TEXT("com.epicgames.launcher")); - FString InstallerPath; - - // Try to launch it directly - if (UriProtocolKey.Exists()) - { - FString LauncherUriRequest = Options.GetLauncherUriRequest(); - - FString Error; - FPlatformProcess::LaunchURL(*LauncherUriRequest, nullptr, &Error); - return true; - } - // Otherwise see if we can install it - else if(Options.bInstall && GetLauncherInstallerPath(InstallerPath)) - { - FPlatformProcess::LaunchFileInDefaultExternalApplication(*InstallerPath); - return true; - } - - return false; -} - -bool FDesktopPlatformWindows::GetLauncherInstallerPath(FString& OutInstallerPath) -{ - FString InstallerPath = FPaths::ConvertRelativePathToFull(FPaths::Combine(*FPaths::EngineDir(), TEXT("Extras/UnrealEngineLauncher/EpicGamesLauncherInstaller.msi"))); - if (FPaths::FileExists(InstallerPath)) - { - OutInstallerPath = InstallerPath; - return true; - } - - return false; -} - CA_SUPPRESS(6262) bool FDesktopPlatformWindows::FileDialogShared(bool bSave, const void* ParentWindowHandle, const FString& DialogTitle, const FString& DefaultPath, const FString& DefaultFile, const FString& FileTypes, uint32 Flags, TArray& OutFilenames, int32& OutFilterIndex) diff --git a/Engine/Source/Developer/DesktopPlatform/Private/Windows/DesktopPlatformWindows.h b/Engine/Source/Developer/DesktopPlatform/Private/Windows/DesktopPlatformWindows.h index cc1ca9618e83..dc408f29a337 100644 --- a/Engine/Source/Developer/DesktopPlatform/Private/Windows/DesktopPlatformWindows.h +++ b/Engine/Source/Developer/DesktopPlatform/Private/Windows/DesktopPlatformWindows.h @@ -17,8 +17,6 @@ public: virtual bool SaveFileDialog(const void* ParentWindowHandle, const FString& DialogTitle, const FString& DefaultPath, const FString& DefaultFile, const FString& FileTypes, uint32 Flags, TArray& OutFilenames) override; virtual bool OpenDirectoryDialog(const void* ParentWindowHandle, const FString& DialogTitle, const FString& DefaultPath, FString& OutFolderName) override; virtual bool OpenFontDialog(const void* ParentWindowHandle, FString& OutFontName, float& OutHeight, EFontImportFlags& OutFlags) override; - virtual bool CanOpenLauncher(bool Install) override; - virtual bool OpenLauncher(const FOpenLauncherOptions& Options) override; virtual bool RegisterEngineInstallation(const FString &RootDir, FString &OutIdentifier) override; virtual void EnumerateEngineInstallations(TMap &OutInstallations) override; @@ -38,7 +36,6 @@ public: virtual FString GetUserTempPath() override; private: - bool GetLauncherInstallerPath(FString& OutInstallerPath); bool FileDialogShared(bool bSave, const void* ParentWindowHandle, const FString& DialogTitle, const FString& DefaultPath, const FString& DefaultFile, const FString& FileTypes, uint32 Flags, TArray& OutFilenames, int32& OutFilterIndex); void GetRequiredRegistrySettings(TIndirectArray &RootedKeys); int32 GetShellIntegrationVersion(const FString &FileName); diff --git a/Engine/Source/Developer/DesktopPlatform/Public/IDesktopPlatform.h b/Engine/Source/Developer/DesktopPlatform/Public/IDesktopPlatform.h index 7c6e68b31566..72cc0e98879f 100644 --- a/Engine/Source/Developer/DesktopPlatform/Public/IDesktopPlatform.h +++ b/Engine/Source/Developer/DesktopPlatform/Public/IDesktopPlatform.h @@ -59,74 +59,6 @@ public: }; -class FOpenLauncherOptions -{ -public: - FOpenLauncherOptions() - : bInstall(false) - , bSilent(true) - , LauncherRelativeUrl() - { - } - - FOpenLauncherOptions(FString InLauncherRelativeUrl) - : bInstall(false) - , bSilent(true) - , LauncherRelativeUrl(InLauncherRelativeUrl) - { - if ( !LauncherRelativeUrl.IsEmpty() ) - { - bSilent = false; - } - } - - FOpenLauncherOptions(bool DoInstall, FString InLauncherRelativeUrl) - : bInstall(DoInstall) - , bSilent(true) - , LauncherRelativeUrl(InLauncherRelativeUrl) - { - if ( !LauncherRelativeUrl.IsEmpty() || bInstall ) - { - bSilent = false; - } - } - - FString GetLauncherUriRequest() const - { - FString LauncherUriRequest; - if ( LauncherRelativeUrl.IsEmpty() ) - { - LauncherUriRequest = TEXT("com.epicgames.launcher:"); - } - else - { - LauncherUriRequest = FString::Printf(TEXT("com.epicgames.launcher://%s"), *LauncherRelativeUrl); - } - - // Append silent query string arg. - if ( bSilent ) - { - if ( LauncherUriRequest.Contains("?") ) - { - LauncherUriRequest += TEXT("&silent=true"); - } - else - { - LauncherUriRequest += TEXT("?silent=true"); - } - } - - return LauncherUriRequest; - } - -public: - - bool bInstall; - bool bSilent; - FString LauncherRelativeUrl; -}; - - class IDesktopPlatform { public: @@ -198,24 +130,6 @@ public: */ virtual bool OpenFontDialog(const void* ParentWindowHandle, FString& OutFontName, float& OutHeight, EFontImportFlags& OutFlags) = 0; - /** - * Determines whether the launcher can be opened. - * - * @param Install Whether to include the possibility of installing the launcher in the check. - * @return true if the launcher can be opened (or installed). - */ - virtual bool CanOpenLauncher(bool Install) = 0; - - /** - * Opens the marketplace user interface. - * - * @param Install Whether to install the marketplace if it is missing. - * @param LauncherRelativeUrl A url relative to the launcher which you'd like the launcher to navigate to. Empty defaults to the UE homepage - * @param CommandLineParams Optional command to open the launcher with if it is not already open - * @return true if the marketplace was opened, false if it is not installed or could not be installed/opened. - */ - virtual bool OpenLauncher(const FOpenLauncherOptions& Options) = 0; - /** * Returns a description for the engine with the given identifier. * diff --git a/Engine/Source/Developer/DirectoryWatcher/Private/FileCache.cpp b/Engine/Source/Developer/DirectoryWatcher/Private/FileCache.cpp index 6b2f7bc7c470..28c62f313517 100644 --- a/Engine/Source/Developer/DirectoryWatcher/Private/FileCache.cpp +++ b/Engine/Source/Developer/DirectoryWatcher/Private/FileCache.cpp @@ -11,6 +11,8 @@ #include "DirectoryWatcherModule.h" #include "Modules/ModuleManager.h" +DEFINE_LOG_CATEGORY_STATIC(LogFileCache, Log, All); + namespace DirectoryWatcher { diff --git a/Engine/Source/Developer/DirectoryWatcher/Public/FileCacheUtilities.h b/Engine/Source/Developer/DirectoryWatcher/Public/FileCacheUtilities.h index 4a13bb17afbe..b50a5f2db714 100644 --- a/Engine/Source/Developer/DirectoryWatcher/Public/FileCacheUtilities.h +++ b/Engine/Source/Developer/DirectoryWatcher/Public/FileCacheUtilities.h @@ -7,8 +7,6 @@ class FWildcardString; -DEFINE_LOG_CATEGORY_STATIC(LogFileCache, Log, All); - namespace DirectoryWatcher { diff --git a/Engine/Source/Developer/FunctionalTesting/Classes/FunctionalAITest.h b/Engine/Source/Developer/FunctionalTesting/Classes/FunctionalAITest.h index dbd2876ebfe6..dd4ef364efe7 100644 --- a/Engine/Source/Developer/FunctionalTesting/Classes/FunctionalAITest.h +++ b/Engine/Source/Developer/FunctionalTesting/Classes/FunctionalAITest.h @@ -16,7 +16,7 @@ class AFunctionalAITest; DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FFunctionalTestAISpawned, AAIController*, Controller, APawn*, Pawn); -USTRUCT() +USTRUCT(BlueprintType) struct FAITestSpawnInfo { GENERATED_USTRUCT_BODY() @@ -79,7 +79,7 @@ struct FPendingDelayedSpawn : public FAITestSpawnInfo void Tick(float TimeDelta, AFunctionalAITest* AITest); }; -USTRUCT() +USTRUCT(BlueprintType) struct FAITestSpawnSet { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Developer/FunctionalTesting/Classes/FunctionalTest.h b/Engine/Source/Developer/FunctionalTesting/Classes/FunctionalTest.h index fd157c092f74..367f639c3108 100644 --- a/Engine/Source/Developer/FunctionalTesting/Classes/FunctionalTest.h +++ b/Engine/Source/Developer/FunctionalTesting/Classes/FunctionalTest.h @@ -13,6 +13,7 @@ class Error; class UBillboardComponent; +class UTraceQueryTestResults; //Experimental effort at automated cpu captures from the functional testing. class FFunctionalTestExternalProfiler : public FScopedExternalProfilerBase @@ -255,7 +256,7 @@ class FUNCTIONALTESTING_API AFunctionalTest : public AActor public: AFunctionalTest(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); -private_subobject: +private: UPROPERTY() UBillboardComponent* SpriteComponent; @@ -363,105 +364,133 @@ public: * @param Message The message to display if the assert fails ("Assertion Failed: 'Message' for context ''") */ UFUNCTION(BlueprintCallable, Category = "Asserts", meta = ( HidePin = "ContextObject", DefaultToSelf = "ContextObject")) - void AssertTrue(bool Condition, FString Message, const UObject* ContextObject = nullptr); + bool AssertTrue(bool Condition, FString Message, const UObject* ContextObject = nullptr); /** * Assert that a boolean value is false. * @param Message The message to display if the assert fails ("Assertion Failed: 'Message' for context ''") */ UFUNCTION(BlueprintCallable, Category = "Asserts", meta = ( HidePin = "ContextObject", DefaultToSelf = "ContextObject")) - void AssertFalse(bool Condition, FString Message, const UObject* ContextObject = nullptr); + bool AssertFalse(bool Condition, FString Message, const UObject* ContextObject = nullptr); /** * Assert that a UObject is valid * @param Message The message to display if the object is invalid ("Invalid object: 'Message' for context ''") */ UFUNCTION(BlueprintCallable, Category = "Asserts", meta = ( HidePin = "ContextObject", DefaultToSelf = "ContextObject")) - void AssertIsValid(UObject* Object, FString Message, const UObject* ContextObject = nullptr); + bool AssertIsValid(UObject* Object, FString Message, const UObject* ContextObject = nullptr); /** * Assert on a relationship between two integers. * @param What A name to use in the message if the assert fails (What: expected {Actual} to be {Expected} for context '') */ UFUNCTION(BlueprintCallable, Category = "Asserts", DisplayName = "Assert Value (int)", meta = ( HidePin = "ContextObject", DefaultToSelf = "ContextObject")) - void AssertValue_Int(int32 Actual, EComparisonMethod ShouldBe, int32 Expected, const FString& What, const UObject* ContextObject = nullptr); + bool AssertValue_Int(int32 Actual, EComparisonMethod ShouldBe, int32 Expected, const FString& What, const UObject* ContextObject = nullptr); /** * Assert on a relationship between two floats. * @param What A name to use in the message if the assert fails (What: expected {Actual} to be {Expected} for context '') */ UFUNCTION(BlueprintCallable, Category = "Asserts", DisplayName = "Assert Value (float)", meta = ( HidePin = "ContextObject", DefaultToSelf = "ContextObject")) - void AssertValue_Float(float Actual, EComparisonMethod ShouldBe, float Expected, const FString& What, const UObject* ContextObject = nullptr); + bool AssertValue_Float(float Actual, EComparisonMethod ShouldBe, float Expected, const FString& What, const UObject* ContextObject = nullptr); /** * Assert on a relationship between two DateTimes. * @param What A name to use in the message if the assert fails (What: expected {Actual} to be {Expected} for context '') */ UFUNCTION(BlueprintCallable, Category = "Asserts", DisplayName = "Assert Value (DateTime)", meta = ( HidePin = "ContextObject", DefaultToSelf = "ContextObject")) - void AssertValue_DateTime(FDateTime Actual, EComparisonMethod ShouldBe, FDateTime Expected, const FString& What, const UObject* ContextObject = nullptr); + bool AssertValue_DateTime(FDateTime Actual, EComparisonMethod ShouldBe, FDateTime Expected, const FString& What, const UObject* ContextObject = nullptr); /** * Assert that two transforms are (components memberwise - translation, rotation, scale) equal within a small tolerance. * @param What A name to use in the message if the assert fails ("Expected 'What' to be {Expected} but it was {Actual} for context ''") */ UFUNCTION(BlueprintCallable, Category = "Asserts", DisplayName = "Assert Equal (Transform)", meta = ( HidePin = "ContextObject", DefaultToSelf = "ContextObject")) - void AssertEqual_Transform(const FTransform Actual, const FTransform Expected, const FString& What, const UObject* ContextObject = nullptr); + bool AssertEqual_Transform(const FTransform& Actual, const FTransform& Expected, const FString& What, const UObject* ContextObject = nullptr); /** * Assert that two floats are equal within tolerance between two floats. * @param What A name to use in the message if the assert fails (What: expected {Actual} to be Equal To {Expected} within Tolerance for context '') */ UFUNCTION(BlueprintCallable, Category = "Asserts", DisplayName = "Assert Equal (Float)", meta = ( HidePin = "ContextObject", DefaultToSelf = "ContextObject")) - void AssertEqual_Float(const float Actual, const float Expected, const FString& What, float Tolerance = 1.e-4, const UObject* ContextObject = nullptr); + bool AssertEqual_Float(const float Actual, const float Expected, const FString& What, float Tolerance = 1.e-4, const UObject* ContextObject = nullptr); + + /** + * Assert that two bools are equal + * @param What A name to use in the message if the assert fails (What: expected {Actual} to be Equal To {Expected} for context '') + */ + UFUNCTION(BlueprintCallable, Category = "Asserts", DisplayName = "Assert Equal (Bool)", meta = (HidePin = "ContextObject", DefaultToSelf = "ContextObject")) + bool AssertEqual_Bool(const bool Actual, const bool Expected, const FString& What, const UObject* ContextObject = nullptr); + + /** + * Assert that two ints are equal + * @param What A name to use in the message if the assert fails (What: expected {Actual} to be Equal To {Expected} for context '') + */ + UFUNCTION(BlueprintCallable, Category = "Asserts", DisplayName = "Assert Equal (Int)", meta = (HidePin = "ContextObject", DefaultToSelf = "ContextObject")) + bool AssertEqual_Int(const int Actual, const int Expected, const FString& What, const UObject* ContextObject = nullptr); + + /** + * Assert that two FNames are equal + * @param What A name to use in the message if the assert fails (What: expected {Actual} to be Equal To {Expected} for context '') + */ + UFUNCTION(BlueprintCallable, Category = "Asserts", DisplayName = "Assert Equal (FName)", meta = (HidePin = "ContextObject", DefaultToSelf = "ContextObject")) + bool AssertEqual_Name(const FName Actual, const FName Expected, const FString& What, const UObject* ContextObject = nullptr); /** * Assert that two transforms are (components memberwise - translation, rotation, scale) not equal within a small tolerance. * @param What A name to use in the message if the assert fails ("Expected 'What' not to be {Expected} but it was {Actual} for context ''") */ UFUNCTION(BlueprintCallable, Category = "Asserts", DisplayName = "Assert Not Equal (Transform)", meta = ( HidePin = "ContextObject", DefaultToSelf = "ContextObject")) - void AssertNotEqual_Transform(const FTransform Actual, const FTransform NotExpected, const FString& What, const UObject* ContextObject = nullptr); + bool AssertNotEqual_Transform(const FTransform& Actual, const FTransform& NotExpected, const FString& What, const UObject* ContextObject = nullptr); /** * Assert that the component angles of two rotators are all equal within a small tolerance. * @param What A name to use in the message if the assert fails ("Expected 'What' to be {Expected} but it was {Actual} for context ''") */ UFUNCTION(BlueprintCallable, Category = "Asserts", DisplayName = "Assert Equal (Rotator)", meta = ( HidePin = "ContextObject", DefaultToSelf = "ContextObject")) - void AssertEqual_Rotator(const FRotator Actual, const FRotator Expected, const FString& What, const UObject* ContextObject = nullptr); + bool AssertEqual_Rotator(const FRotator Actual, const FRotator Expected, const FString& What, const UObject* ContextObject = nullptr); /** * Assert that the component angles of two rotators are all not equal within a small tolerance. * @param What A name to use in the message if the assert fails ("Expected 'What' not to be {Expected} but it was {Actual} for context ''") */ UFUNCTION(BlueprintCallable, Category = "Asserts", DisplayName = "Assert Not Equal (Rotator)", meta = ( HidePin = "ContextObject", DefaultToSelf = "ContextObject")) - void AssertNotEqual_Rotator(const FRotator Actual, const FRotator NotExpected, const FString& What, const UObject* ContextObject = nullptr); + bool AssertNotEqual_Rotator(const FRotator Actual, const FRotator NotExpected, const FString& What, const UObject* ContextObject = nullptr); /** * Assert that two vectors are (memberwise) equal within a small tolerance. * @param What A name to use in the message if the assert fails ("Expected 'What' to be {Expected} but it was {Actual} for context ''") */ UFUNCTION(BlueprintCallable, Category = "Asserts", DisplayName = "Assert Equal (Vector)", meta = ( HidePin = "ContextObject", DefaultToSelf = "ContextObject")) - void AssertEqual_Vector(const FVector Actual, const FVector Expected, const FString& What, const float Tolerance = 1.e-4f, const UObject* ContextObject = nullptr); + bool AssertEqual_Vector(const FVector Actual, const FVector Expected, const FString& What, const float Tolerance = 1.e-4f, const UObject* ContextObject = nullptr); /** * Assert that two vectors are (memberwise) not equal within a small tolerance. * @param What A name to use in the message if the assert fails ("Expected 'What' not to be {Expected} but it was {Actual} for context ''") */ UFUNCTION(BlueprintCallable, Category = "Asserts", DisplayName = "Assert Not Equal (Vector)", meta = ( HidePin = "ContextObject", DefaultToSelf = "ContextObject")) - void AssertNotEqual_Vector(const FVector Actual, const FVector NotExpected, const FString& What, const UObject* ContextObject = nullptr); + bool AssertNotEqual_Vector(const FVector Actual, const FVector NotExpected, const FString& What, const UObject* ContextObject = nullptr); /** * Assert that two Strings are equal. * @param What A name to use in the message if the assert fails ("Expected 'What' to be {Expected} but it was {Actual} for context ''") */ UFUNCTION(BlueprintCallable, Category = "Asserts", DisplayName = "Assert Equal (String)", meta = ( HidePin = "ContextObject", DefaultToSelf = "ContextObject")) - void AssertEqual_String(const FString Actual, const FString Expected, const FString& What, const UObject* ContextObject = nullptr); + bool AssertEqual_String(const FString Actual, const FString Expected, const FString& What, const UObject* ContextObject = nullptr); /** * Assert that two Strings are not equal. * @param What A name to use in the message if the assert fails ("Expected 'What' not to be {Expected} but it was {Actual} for context ''") */ UFUNCTION(BlueprintCallable, Category = "Asserts", DisplayName = "Assert Not Equal (String)", meta = ( HidePin = "ContextObject", DefaultToSelf = "ContextObject")) - void AssertNotEqual_String(const FString Actual, const FString NotExpected, const FString& What, const UObject* ContextObject = nullptr); + bool AssertNotEqual_String(const FString Actual, const FString NotExpected, const FString& What, const UObject* ContextObject = nullptr); + + /** + * Assert that two TraceQueryResults are equal. + * @param What A name to use in the message if the assert fails ("Expected 'What' not to be {Expected} but it was {Actual} for context ''") + */ + UFUNCTION(BlueprintCallable, Category = "Asserts", DisplayName = "Assert Equal (TraceQuery)", meta = (HidePin = "ContextObject", DefaultToSelf = "ContextObject")) + bool AssertEqual_TraceQueryResults(const UTraceQueryTestResults* Actual, const UTraceQueryTestResults* Expected, const FString& What, const UObject* ContextObject = nullptr); UFUNCTION(BlueprintCallable, Category = "Reporting") void AddWarning(const FString Message); @@ -469,7 +498,8 @@ public: UFUNCTION(BlueprintCallable, Category = "Reporting") void AddError(const FString Message); -protected: +//protected: + /** TODO: break this out into a library */ void LogStep(ELogVerbosity::Type Verbosity, const FString& Message); public: diff --git a/Engine/Source/Developer/FunctionalTesting/Classes/FunctionalTestUtilityLibrary.h b/Engine/Source/Developer/FunctionalTesting/Classes/FunctionalTestUtilityLibrary.h new file mode 100644 index 000000000000..4b3ba16a0fd4 --- /dev/null +++ b/Engine/Source/Developer/FunctionalTesting/Classes/FunctionalTestUtilityLibrary.h @@ -0,0 +1,24 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "Kismet/KismetSystemLibrary.h" +#include "Kismet/BlueprintFunctionLibrary.h" +#include "TraceQueryTestResults.h" +#include "FunctionalTestUtilityLibrary.generated.h" + +/** +* Used to expose C++ functions to tests that we don't want to make BP accessible +* in the engine itself. +*/ +UCLASS() +class FUNCTIONALTESTING_API UFunctionalTestUtilityLibrary : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() + +public: + + /** Helper function to trace and permute many options at once */ + UFUNCTION(BlueprintCallable, Category = "Utility|Collision", meta = (bIgnoreSelf = "true", WorldContext = "WorldContextObject", AutoCreateRefTerm = "ActorsToIgnore", AdvancedDisplay = "TraceColor,TraceHitColor,DrawTime", Keywords = "sweep")) + static UTraceQueryTestResults* TraceChannelTestUtil(UObject* WorldContextObject, const FTraceChannelTestBatchOptions& BatchOptions, const FVector Start, const FVector End, float SphereCapsuleRadius, float CapsuleHalfHeight, FVector BoxHalfSize, const FRotator Orientation, ETraceTypeQuery TraceChannel, TArray > ObjectTypes, FName ProfileName, bool bTraceComplex, const TArray& ActorsToIgnore, bool bIgnoreSelf, EDrawDebugTrace::Type DrawDebugType, FLinearColor TraceColor = FLinearColor::Red, FLinearColor TraceHitColor = FLinearColor::Green, float DrawTime = 5.0f); +}; diff --git a/Engine/Source/Developer/FunctionalTesting/Classes/FunctionalTestingManager.h b/Engine/Source/Developer/FunctionalTesting/Classes/FunctionalTestingManager.h index 610b8cd2aa7b..4c14f69f0f9c 100644 --- a/Engine/Source/Developer/FunctionalTesting/Classes/FunctionalTestingManager.h +++ b/Engine/Source/Developer/FunctionalTesting/Classes/FunctionalTestingManager.h @@ -42,8 +42,8 @@ class UFunctionalTestingManager : public UBlueprintFunctionLibrary * Triggers in sequence all functional tests found on the level. * @return true if any tests have been triggered */ - UFUNCTION(BlueprintCallable, Category="FunctionalTesting", meta=(WorldContext="WorldContext", CallableWithoutWorldContext ) ) - static bool RunAllFunctionalTests(UObject* WorldContext, bool bNewLog = true, bool bRunLooped = false, bool bWaitForNavigationBuildFinish = true, FString FailedTestsReproString = TEXT("")); + UFUNCTION(BlueprintCallable, Category="FunctionalTesting", meta=(WorldContext="WorldContextObject", CallableWithoutWorldContext ) ) + static bool RunAllFunctionalTests(UObject* WorldContextObject, bool bNewLog = true, bool bRunLooped = false, bool bWaitForNavigationBuildFinish = true, FString FailedTestsReproString = TEXT("")); bool IsRunning() const { return bIsRunning; } bool IsFinished() const { return bFinished; } @@ -76,7 +76,6 @@ protected: bool bIsRunning; bool bFinished; bool bLooped; - bool bWaitForNavigationBuildFinish; bool bInitialDelayApplied; uint32 CurrentIteration; diff --git a/Engine/Source/Developer/FunctionalTesting/Classes/TraceQueryTestResults.h b/Engine/Source/Developer/FunctionalTesting/Classes/TraceQueryTestResults.h new file mode 100644 index 000000000000..e8701cf7aa42 --- /dev/null +++ b/Engine/Source/Developer/FunctionalTesting/Classes/TraceQueryTestResults.h @@ -0,0 +1,181 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "UObject/UObjectGlobals.h" +#include "Engine/EngineTypes.h" +#include "TraceQueryTestResults.generated.h" + +class AFunctionalTest; + +USTRUCT(BlueprintType) +struct FUNCTIONALTESTING_API FTraceChannelTestBatchOptions +{ + GENERATED_BODY() + + FTraceChannelTestBatchOptions() + { + bLineTrace = true; + bSphereTrace = false; + bCapsuleTrace = false; + bBoxTrace = false; + + bChannelTrace = true; + bObjectsTrace = false; + bProfileTrace = false; + } + + bool operator==(const FTraceChannelTestBatchOptions& Other) const + { + return bLineTrace == Other.bLineTrace && bSphereTrace == Other.bSphereTrace && bCapsuleTrace == Other.bCapsuleTrace && bBoxTrace == Other.bBoxTrace + && bChannelTrace == Other.bChannelTrace && bObjectsTrace == Other.bObjectsTrace && bProfileTrace == Other.bProfileTrace; + } + + bool operator!=(const FTraceChannelTestBatchOptions& Other) const + { + return !(*this == Other); + } + + /** Whether to do line traces */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Utility|Collision") + bool bLineTrace; + + /** Whether to do sphere traces */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Utility|Collision") + bool bSphereTrace; + + /** Whether to do capsule traces */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Utility|Collision") + bool bCapsuleTrace; + + /** Whether to do box traces */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Utility|Collision") + bool bBoxTrace; + + /** Whether to do channel traces */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Utility|Collision") + bool bChannelTrace; + + /** Whether to do object traces */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Utility|Collision") + bool bObjectsTrace; + + /** Whether to do profile traces */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Utility|Collision") + bool bProfileTrace; + + FString ToString() const; +}; + +USTRUCT(BlueprintType) +struct FUNCTIONALTESTING_API FTraceQueryTestNames +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Utility|Collision") + FName ComponentName; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Utility|Collision") + FName PhysicalMaterialName; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Utility|Collision") + FName ActorName; + + FString ToString() const; +}; + +USTRUCT(BlueprintType) +struct FUNCTIONALTESTING_API FTraceQueryTestResultsInnerMost +{ + GENERATED_BODY() + + /** Result from doing a single sweep*/ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Utility|Collision") + FHitResult SingleHit; + + /** Names found from doing a single sweep*/ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Utility|Collision") + FTraceQueryTestNames SingleNames; + + /** The true/false value returned from the single sweep */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Utility|Collision") + bool bSingleResult; + + /** Result from doing a multi sweep */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Utility|Collision") + TArray MultiHits; + + /** Names found from doing a multi sweep*/ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Utility|Collision") + TArray MultiNames; + + /** The true/false value returned from the multi sweep */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Utility|Collision") + bool bMultiResult; + + FString ToString() const; + + void CaptureNames(); + + bool AssertEqual(const FTraceQueryTestResultsInnerMost& Expected, const FString& What, const UObject* ContextObject, AFunctionalTest& FunctionalTest) const; +}; + +USTRUCT(BlueprintType) +struct FUNCTIONALTESTING_API FTraceQueryTestResultsInner +{ + GENERATED_BODY() + + /** The results associated with the line trace */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Utility|Collision") + FTraceQueryTestResultsInnerMost LineResults; + + /** The results associated with the sphere */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Utility|Collision") + FTraceQueryTestResultsInnerMost SphereResults; + + /** The results associated with the capsule*/ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Utility|Collision") + FTraceQueryTestResultsInnerMost CapsuleResults; + + /** The results associated with the box*/ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Utility|Collision") + FTraceQueryTestResultsInnerMost BoxResults; + + FString ToString(const FTraceChannelTestBatchOptions& BatchOptions) const; + + void CaptureNames(); + + bool AssertEqual(const FTraceQueryTestResultsInner& Expected, const FString& What, const UObject* ContextObject, AFunctionalTest& FunctionalTest) const; +}; + +UCLASS(BlueprintType) +class FUNCTIONALTESTING_API UTraceQueryTestResults : public UObject +{ + GENERATED_BODY() +public: + /** Results for channel trace */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Utility|Collision") + FTraceQueryTestResultsInner ChannelResults; + + /** Results for object trace */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Utility|Collision") + FTraceQueryTestResultsInner ObjectResults; + + /** Results for profile trace */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Utility|Collision") + FTraceQueryTestResultsInner ProfileResults; + + FTraceChannelTestBatchOptions BatchOptions; + + /** Output string value */ + UFUNCTION(BlueprintCallable, Category = "Utility|Collision") + FString ToString(); + + bool AssertEqual(const UTraceQueryTestResults* Expected, const FString& What, const UObject* ContextObject, AFunctionalTest& FunctionalTest) const; + + void CaptureNames(); + + +}; \ No newline at end of file diff --git a/Engine/Source/Developer/FunctionalTesting/FunctionalTesting.Build.cs b/Engine/Source/Developer/FunctionalTesting/FunctionalTesting.Build.cs index c83fd8574f0f..8cbb585788ef 100644 --- a/Engine/Source/Developer/FunctionalTesting/FunctionalTesting.Build.cs +++ b/Engine/Source/Developer/FunctionalTesting/FunctionalTesting.Build.cs @@ -4,31 +4,40 @@ using UnrealBuildTool; public class FunctionalTesting : ModuleRules { - public FunctionalTesting(ReadOnlyTargetRules Target) : base(Target) - { - PrivateDependencyModuleNames.AddRange( - new string[] { - "Core", - "CoreUObject", - "Engine", + public FunctionalTesting(ReadOnlyTargetRules Target) : base(Target) + { + PrivateDependencyModuleNames.AddRange( + new string[] { + "Core", + "CoreUObject", + "Engine", "ShaderCore", - "Slate", + "Slate", "MessageLog", "AIModule", "RenderCore", "AssetRegistry", "RHI", - "UMG" - } - ); + "UMG" + } + ); - PrivateIncludePaths.AddRange( - new string[] - { - "MessageLog/Public", - "Stats/Public", - "Developer/FunctionalTesting/Private", - } - ); - } + PrivateIncludePaths.AddRange( + new string[] + { + "MessageLog/Public", + "Stats/Public", + "Developer/FunctionalTesting/Private", + } + ); + + if (UEBuildConfiguration.bBuildEditor == true) + { + PrivateDependencyModuleNames.AddRange( + new string[] { + "SourceControl" + } + ); + } + } } diff --git a/Engine/Source/Developer/FunctionalTesting/Private/AutomationBlueprintFunctionLibrary.cpp b/Engine/Source/Developer/FunctionalTesting/Private/AutomationBlueprintFunctionLibrary.cpp index d724fd8dfbf8..73d7da4df3bb 100644 --- a/Engine/Source/Developer/FunctionalTesting/Private/AutomationBlueprintFunctionLibrary.cpp +++ b/Engine/Source/Developer/FunctionalTesting/Private/AutomationBlueprintFunctionLibrary.cpp @@ -26,6 +26,8 @@ #include "BufferVisualizationData.h" #include "Engine/LocalPlayer.h" #include "ContentStreaming.h" +#include "Stats/StatsData.h" +#include "HAL/PlatformProperties.h" #define LOCTEXT_NAMESPACE "Automation" @@ -47,8 +49,11 @@ static TAutoConsoleVariable CVarAutomationScreenshotResolutionHeight( void FinishLoadingBeforeScreenshot() { - // Force all shader compiling to finish. - GShaderCompilingManager->FinishAllCompilation(); + // Finish compiling the shaders if the platform doesn't require cooked data. + if (!FPlatformProperties::RequiresCookedData()) + { + GShaderCompilingManager->FinishAllCompilation(); + } // Force all mip maps to load before taking the screenshot. UTexture::ForceUpdateTextureStreaming(); @@ -340,7 +345,7 @@ bool UAutomationBlueprintFunctionLibrary::TakeAutomationScreenshotInternal(UObje return false; } - return true; + return true; //-V773 } } @@ -439,7 +444,7 @@ void UAutomationBlueprintFunctionLibrary::TakeAutomationScreenshotOfUI(UObject* GEngine->GameViewport->OnScreenshotCaptured().Broadcast(OutSize.X, OutSize.Y, OutColorData); #endif - } + } //-V773 FLatentActionManager& LatentActionManager = World->GetLatentActionManager(); if ( LatentActionManager.FindExistingAction(LatentInfo.CallbackTarget, LatentInfo.UUID) == nullptr ) @@ -451,24 +456,130 @@ void UAutomationBlueprintFunctionLibrary::TakeAutomationScreenshotOfUI(UObject* } } -//void UAutomationBlueprintFunctionLibrary::BeginPerformanceCapture() -//{ -// //::BeginPerformanceCapture(); -//} -// -//void UAutomationBlueprintFunctionLibrary::EndPerformanceCapture() -//{ -// //::EndPerformanceCapture(); -//} +void UAutomationBlueprintFunctionLibrary::EnableStatGroup(UObject* WorldContextObject, FName GroupName) +{ +#if STATS + if (FGameThreadStatsData* StatsData = FLatestGameThreadStatsData::Get().Latest) + { + const FString GroupNameString = FString(TEXT("STATGROUP_")) + GroupName.ToString(); + const FName GroupNameFull = FName(*GroupNameString, EFindName::FNAME_Find); + if(StatsData->GroupNames.Contains(GroupNameFull)) + { + return; + } + } + + if (APlayerController* TargetPC = UGameplayStatics::GetPlayerController(WorldContextObject, 0)) + { + TargetPC->ConsoleCommand( FString(TEXT("stat ")) + GroupName.ToString() + FString(TEXT(" -nodisplay")), /*bWriteToLog=*/false); + } +#endif +} + +void UAutomationBlueprintFunctionLibrary::DisableStatGroup(UObject* WorldContextObject, FName GroupName) +{ +#if STATS + if (FGameThreadStatsData* StatsData = FLatestGameThreadStatsData::Get().Latest) + { + const FString GroupNameString = FString(TEXT("STATGROUP_")) + GroupName.ToString(); + const FName GroupNameFull = FName(*GroupNameString, EFindName::FNAME_Find); + + if (!StatsData->GroupNames.Contains(GroupNameFull)) + { + return; + } + } + + if (APlayerController* TargetPC = UGameplayStatics::GetPlayerController(WorldContextObject, 0)) + { + TargetPC->ConsoleCommand(FString(TEXT("stat ")) + GroupName.ToString() + FString(TEXT(" -nodisplay")), /*bWriteToLog=*/false); + } +#endif +} + +#if STATS +template +float HelperGetStat(FName StatName) +{ + if (FGameThreadStatsData* StatsData = FLatestGameThreadStatsData::Get().Latest) + { + if (const FComplexStatMessage* StatMessage = StatsData->GetStatData(StatName)) + { + if(bCallCount) + { + return StatMessage->GetValue_CallCount(ValueType); + } + else + { + return FPlatformTime::ToMilliseconds(StatMessage->GetValue_Duration(ValueType)); + } + } + } + +#if WITH_EDITOR + FText WarningOut = FText::Format(LOCTEXT("StatNotFound", "Could not find stat data for {0}, did you call ToggleStatGroup with enough time to capture data?"), FText::FromName(StatName)); + FMessageLog("PIE").Warning(WarningOut); + UE_LOG(AutomationFunctionLibrary, Warning, TEXT("%s"), *WarningOut.ToString()); +#endif + + return 0.f; +} +#endif + +float UAutomationBlueprintFunctionLibrary::GetStatIncAverage(FName StatName) +{ +#if STATS + return HelperGetStat(StatName); +#else + return 0.0f; +#endif +} + +float UAutomationBlueprintFunctionLibrary::GetStatIncMax(FName StatName) +{ +#if STATS + return HelperGetStat(StatName); +#else + return 0.0f; +#endif +} + +float UAutomationBlueprintFunctionLibrary::GetStatExcAverage(FName StatName) +{ +#if STATS + return HelperGetStat(StatName); +#else + return 0.0f; +#endif +} + +float UAutomationBlueprintFunctionLibrary::GetStatExcMax(FName StatName) +{ +#if STATS + return HelperGetStat(StatName); +#else + return 0.0f; +#endif +} + +float UAutomationBlueprintFunctionLibrary::GetStatCallCount(FName StatName) +{ +#if STATS + return HelperGetStat(StatName); +#else + return 0.0f; +#endif +} bool UAutomationBlueprintFunctionLibrary::AreAutomatedTestsRunning() { return GIsAutomationTesting; } -FAutomationScreenshotOptions UAutomationBlueprintFunctionLibrary::GetDefaultScreenshotOptionsForGameplay(EComparisonTolerance Tolerance) +FAutomationScreenshotOptions UAutomationBlueprintFunctionLibrary::GetDefaultScreenshotOptionsForGameplay(EComparisonTolerance Tolerance, float Delay) { FAutomationScreenshotOptions Options; + Options.Delay = Delay; Options.Tolerance = Tolerance; Options.bDisableNoisyRenderingFeatures = true; Options.bIgnoreAntiAliasing = true; @@ -477,9 +588,10 @@ FAutomationScreenshotOptions UAutomationBlueprintFunctionLibrary::GetDefaultScre return Options; } -FAutomationScreenshotOptions UAutomationBlueprintFunctionLibrary::GetDefaultScreenshotOptionsForRendering(EComparisonTolerance Tolerance) +FAutomationScreenshotOptions UAutomationBlueprintFunctionLibrary::GetDefaultScreenshotOptionsForRendering(EComparisonTolerance Tolerance, float Delay) { FAutomationScreenshotOptions Options; + Options.Delay = Delay; Options.Tolerance = Tolerance; Options.bDisableNoisyRenderingFeatures = true; Options.bIgnoreAntiAliasing = true; diff --git a/Engine/Source/Developer/FunctionalTesting/Private/FuncTestManager.cpp b/Engine/Source/Developer/FunctionalTesting/Private/FuncTestManager.cpp index 45a51dd26108..f69ba1364565 100644 --- a/Engine/Source/Developer/FunctionalTesting/Private/FuncTestManager.cpp +++ b/Engine/Source/Developer/FunctionalTesting/Private/FuncTestManager.cpp @@ -56,6 +56,11 @@ void FFuncTestManager::SetScript(class UFunctionalTestingManager* NewScript) TestScript = NewScript; } +UFunctionalTestingManager* FFuncTestManager::GetCurrentScript() +{ + return TestScript.Get(); +} + bool FFuncTestManager::IsRunning() const { return TestScript.IsValid() && TestScript->IsRunning(); diff --git a/Engine/Source/Developer/FunctionalTesting/Private/FuncTestManager.h b/Engine/Source/Developer/FunctionalTesting/Private/FuncTestManager.h index ba1050443b63..6a3e6c4401c9 100644 --- a/Engine/Source/Developer/FunctionalTesting/Private/FuncTestManager.h +++ b/Engine/Source/Developer/FunctionalTesting/Private/FuncTestManager.h @@ -33,7 +33,7 @@ public: virtual void SetScript(class UFunctionalTestingManager* NewScript) override; - virtual class UFunctionalTestingManager* GetCurrentScript() override { return TestScript.Get(); } + virtual class UFunctionalTestingManager* GetCurrentScript(); virtual void SetLooping(const bool bLoop) override; diff --git a/Engine/Source/Developer/FunctionalTesting/Private/FunctionalTest.cpp b/Engine/Source/Developer/FunctionalTesting/Private/FunctionalTest.cpp index 200ad06930ce..1874201f09d7 100644 --- a/Engine/Source/Developer/FunctionalTesting/Private/FunctionalTest.cpp +++ b/Engine/Source/Developer/FunctionalTesting/Private/FunctionalTest.cpp @@ -22,6 +22,7 @@ #include "Engine/Texture2D.h" #include "DelayForFramesLatentAction.h" #include "Engine/DebugCameraController.h" +#include "TraceQueryTestResults.h" namespace { @@ -99,6 +100,7 @@ AFunctionalTest::AFunctionalTest( const FObjectInitializer& ObjectInitializer ) { PrimaryActorTick.bCanEverTick = true; PrimaryActorTick.bStartWithTickEnabled = false; + PrimaryActorTick.bTickEvenWhenPaused = true; bCanBeDamaged = false; @@ -526,180 +528,255 @@ UBillboardComponent* AFunctionalTest::GetSpriteComponent() ////////////////////////////////////////////////////////////////////////// -void AFunctionalTest::AssertTrue(bool Condition, FString Message, const UObject* ContextObject) +bool AFunctionalTest::AssertTrue(bool Condition, FString Message, const UObject* ContextObject) { if ( !Condition ) { LogStep(ELogVerbosity::Error, FString::Printf(TEXT("Assertion failed: '%s' for context '%s'"), *Message, ContextObject ? *ContextObject->GetName() : TEXT(""))); + return false; } else { LogStep(ELogVerbosity::Log, FString::Printf(TEXT("Assertion passed (%s)"), *Message)); + return true; } } -void AFunctionalTest::AssertFalse(bool Condition, FString Message, const UObject* ContextObject) +bool AFunctionalTest::AssertFalse(bool Condition, FString Message, const UObject* ContextObject) { - AssertTrue(!Condition, Message, ContextObject); + return AssertTrue(!Condition, Message, ContextObject); } -void AFunctionalTest::AssertIsValid(UObject* Object, FString Message, const UObject* ContextObject) +bool AFunctionalTest::AssertIsValid(UObject* Object, FString Message, const UObject* ContextObject) { if ( !IsValid(Object) ) { LogStep(ELogVerbosity::Error, FString::Printf(TEXT("Invalid object: '%s' for context '%s'"), *Message, ContextObject ? *ContextObject->GetName() : TEXT(""))); + return false; } else { LogStep(ELogVerbosity::Log, FString::Printf(TEXT("Valid object: (%s)"), *Message)); + return true; } } -void AFunctionalTest::AssertValue_Int(int32 Actual, EComparisonMethod ShouldBe, int32 Expected, const FString& What, const UObject* ContextObject) +bool AFunctionalTest::AssertValue_Int(int32 Actual, EComparisonMethod ShouldBe, int32 Expected, const FString& What, const UObject* ContextObject) { if ( !PerformComparison(Actual, Expected, ShouldBe) ) { LogStep(ELogVerbosity::Error, FString::Printf(TEXT("%s: expected {%d} to be %s {%d} for context '%s'"), *What, Actual, *GetComparisonAsString(ShouldBe), Expected, ContextObject ? *ContextObject->GetName() : TEXT(""))); + return false; } else { - LogStep(ELogVerbosity::Log, FString::Printf(TEXT("Int assertion passed (%s)"), *What)); + LogStep(ELogVerbosity::Log, FString::Printf(TEXT("%s: expected {%d} to be %s {%d} for context '%s'"), *What, Actual, *GetComparisonAsString(ShouldBe), Expected, ContextObject ? *ContextObject->GetName() : TEXT(""))); + return true; } } -void AFunctionalTest::AssertValue_Float(float Actual, EComparisonMethod ShouldBe, float Expected, const FString& What, const UObject* ContextObject) +bool AFunctionalTest::AssertValue_Float(float Actual, EComparisonMethod ShouldBe, float Expected, const FString& What, const UObject* ContextObject) { if ( !PerformComparison(Actual, Expected, ShouldBe) ) { LogStep(ELogVerbosity::Error, FString::Printf(TEXT("%s: expected {%f} to be %s {%f} for context '%s'"), *What, Actual, *GetComparisonAsString(ShouldBe), Expected, ContextObject ? *ContextObject->GetName() : TEXT(""))); + return false; } else { - LogStep(ELogVerbosity::Log, FString::Printf(TEXT("Float assertion passed (%s)"), *What)); + LogStep(ELogVerbosity::Log, FString::Printf(TEXT("%s: expected {%f} to be %s {%f} for context '%s'"), *What, Actual, *GetComparisonAsString(ShouldBe), Expected, ContextObject ? *ContextObject->GetName() : TEXT(""))); + return true; } } -void AFunctionalTest::AssertValue_DateTime(FDateTime Actual, EComparisonMethod ShouldBe, FDateTime Expected, const FString& What, const UObject* ContextObject) +bool AFunctionalTest::AssertValue_DateTime(FDateTime Actual, EComparisonMethod ShouldBe, FDateTime Expected, const FString& What, const UObject* ContextObject) { if ( !PerformComparison(Actual, Expected, ShouldBe) ) { LogStep(ELogVerbosity::Error, FString::Printf(TEXT("%s: expected {%s} to be %s {%s} for context '%s'"), *What, *Actual.ToString(), *GetComparisonAsString(ShouldBe), *Expected.ToString(), ContextObject ? *ContextObject->GetName() : TEXT(""))); + return false; } else { LogStep(ELogVerbosity::Log, FString::Printf(TEXT("DateTime assertion passed (%s)"), *What)); + return true; } } - -void AFunctionalTest::AssertEqual_Float(const float Actual, const float Expected, const FString& What, const float Tolerance, const UObject* ContextObject) +bool AFunctionalTest::AssertEqual_Float(const float Actual, const float Expected, const FString& What, const float Tolerance, const UObject* ContextObject) { if ( !FMath::IsNearlyEqual(Actual, Expected, Tolerance) ) { LogStep(ELogVerbosity::Error, FString::Printf(TEXT("Expected '%s' to be {%f}, but it was {%f} within tolerance {%f} for context '%s'"), *What, Expected, Actual, Tolerance, ContextObject ? *ContextObject->GetName() : TEXT(""))); + return false; } else { LogStep(ELogVerbosity::Log, FString::Printf(TEXT("Float assertion passed (%s)"), *What)); + return true; } } -void AFunctionalTest::AssertEqual_Transform(const FTransform Actual, const FTransform Expected, const FString& What, const UObject* ContextObject) +bool AFunctionalTest::AssertEqual_Bool(const bool Actual, const bool Expected, const FString& What, const UObject* ContextObject) +{ + if (Actual != Expected) + { + LogStep(ELogVerbosity::Error, FString::Printf(TEXT("Expected '%d' to be {%d}, but it was {%d} for context '%s'"), *What, Expected, Actual, ContextObject ? *ContextObject->GetName() : TEXT(""))); + return false; + } + else + { + LogStep(ELogVerbosity::Log, FString::Printf(TEXT("Bool assertion passed (%s)"), *What)); + return true; + } +} + +bool AFunctionalTest::AssertEqual_Int(const int32 Actual, const int32 Expected, const FString& What, const UObject* ContextObject) +{ + if (Actual != Expected) + { + LogStep(ELogVerbosity::Error, FString::Printf(TEXT("Expected '%d' to be {%d}, but it was {%d} for context '%s'"), *What, Expected, Actual, ContextObject ? *ContextObject->GetName() : TEXT(""))); + return false; + } + else + { + LogStep(ELogVerbosity::Log, FString::Printf(TEXT("Bool assertion passed (%s)"), *What)); + return true; + } +} + +bool AFunctionalTest::AssertEqual_Name(const FName Actual, const FName Expected, const FString& What, const UObject* ContextObject) +{ + if (Actual != Expected) + { + LogStep(ELogVerbosity::Error, FString::Printf(TEXT("Expected '%s' to be {%s}, but it was {%s} for context '%s'"), *What, *Expected.ToString(), *Actual.ToString(), ContextObject ? *ContextObject->GetName() : TEXT(""))); + return false; + } + else + { + LogStep(ELogVerbosity::Log, FString::Printf(TEXT("Bool assertion passed (%s)"), *What)); + return true; + } +} + + +bool AFunctionalTest::AssertEqual_Transform(const FTransform& Actual, const FTransform& Expected, const FString& What, const UObject* ContextObject) { if ( !Expected.Equals(Actual) ) { LogStep(ELogVerbosity::Error, FString::Printf(TEXT("Expected '%s' to be {%s}, but it was {%s} for context '%s'"), *What, *TransformToString(Expected), *TransformToString(Actual), ContextObject ? *ContextObject->GetName() : TEXT(""))); + return false; } else { LogStep(ELogVerbosity::Log, FString::Printf(TEXT("Transform assertion passed (%s)"), *What)); + return true; } } -void AFunctionalTest::AssertNotEqual_Transform(const FTransform Actual, const FTransform NotExpected, const FString& What, const UObject* ContextObject) +bool AFunctionalTest::AssertNotEqual_Transform(const FTransform& Actual, const FTransform& NotExpected, const FString& What, const UObject* ContextObject) { if ( NotExpected.Equals(Actual) ) { LogStep(ELogVerbosity::Error, FString::Printf(TEXT("Expected '%s' not to be {%s} for context '%s'"), *What, *TransformToString(NotExpected), ContextObject ? *ContextObject->GetName() : TEXT(""))); + return false; } else { LogStep(ELogVerbosity::Log, FString::Printf(TEXT("Transform assertion passed (%s)"), *What)); + return true; } } -void AFunctionalTest::AssertEqual_Rotator(const FRotator Actual, const FRotator Expected, const FString& What, const UObject* ContextObject) +bool AFunctionalTest::AssertEqual_Rotator(const FRotator Actual, const FRotator Expected, const FString& What, const UObject* ContextObject) { if ( !Expected.Equals(Actual) ) { LogStep(ELogVerbosity::Error, FString::Printf(TEXT("Expected '%s' to be {%s} but it was {%s} for context '%s'"), *What, *Expected.ToString(), *Actual.ToString(), ContextObject ? *ContextObject->GetName() : TEXT(""))); + return false; } else { LogStep(ELogVerbosity::Log, FString::Printf(TEXT("Rotator assertion passed (%s)"), *What)); + return true; } } -void AFunctionalTest::AssertNotEqual_Rotator(const FRotator Actual, const FRotator NotExpected, const FString& What, const UObject* ContextObject) +bool AFunctionalTest::AssertNotEqual_Rotator(const FRotator Actual, const FRotator NotExpected, const FString& What, const UObject* ContextObject) { if ( NotExpected.Equals(Actual) ) { LogStep(ELogVerbosity::Error, FString::Printf(TEXT("Expected '%s' not to be {%s} for context '%s'"), *What, *NotExpected.ToString(), ContextObject ? *ContextObject->GetName() : TEXT(""))); + return false; } else { LogStep(ELogVerbosity::Log, FString::Printf(TEXT("Rotator assertion passed (%s)"), *What)); + return true; } } -void AFunctionalTest::AssertEqual_Vector(const FVector Actual, const FVector Expected, const FString& What, const float Tolerance, const UObject* ContextObject) +bool AFunctionalTest::AssertEqual_Vector(const FVector Actual, const FVector Expected, const FString& What, const float Tolerance, const UObject* ContextObject) { if ( !Expected.Equals(Actual, Tolerance) ) { LogStep(ELogVerbosity::Error, FString::Printf(TEXT("Expected '%s' to be {%s} but it was {%s} within tolerance {%f} for context '%s'"), *What, *Expected.ToString(), *Actual.ToString(), Tolerance, ContextObject ? *ContextObject->GetName() : TEXT(""))); + return false; } else { LogStep(ELogVerbosity::Log, FString::Printf(TEXT("Vector assertion passed (%s)"), *What)); + return true; } } -void AFunctionalTest::AssertNotEqual_Vector(const FVector Actual, const FVector NotExpected, const FString& What, const UObject* ContextObject) +bool AFunctionalTest::AssertNotEqual_Vector(const FVector Actual, const FVector NotExpected, const FString& What, const UObject* ContextObject) { if ( NotExpected.Equals(Actual) ) { LogStep(ELogVerbosity::Error, FString::Printf(TEXT("Expected '%s' not to be {%s} for context '%s'"), *What, *NotExpected.ToString(), ContextObject ? *ContextObject->GetName() : TEXT(""))); + return false; } else { LogStep(ELogVerbosity::Log, FString::Printf(TEXT("Vector assertion passed (%s)"), *What)); + return true; } } -void AFunctionalTest::AssertEqual_String(const FString Actual, const FString Expected, const FString& What, const UObject* ContextObject) +bool AFunctionalTest::AssertEqual_String(const FString Actual, const FString Expected, const FString& What, const UObject* ContextObject) { if ( !Expected.Equals(Actual) ) { LogStep(ELogVerbosity::Error, FString::Printf(TEXT("Expected '%s' to be {%s} but it was {%s} for context '%s'"), *What, *Expected, *Actual, ContextObject ? *ContextObject->GetName() : TEXT(""))); + return false; } else { LogStep(ELogVerbosity::Log, FString::Printf(TEXT("String assertion passed (%s)"), *What)); + return true; } } -void AFunctionalTest::AssertNotEqual_String(const FString Actual, const FString NotExpected, const FString& What, const UObject* ContextObject) +bool AFunctionalTest::AssertNotEqual_String(const FString Actual, const FString NotExpected, const FString& What, const UObject* ContextObject) { if ( NotExpected.Equals(Actual) ) { LogStep(ELogVerbosity::Error, FString::Printf(TEXT("Expected '%s' not to be {%s} for context '%s'"), *What, *NotExpected, ContextObject ? *ContextObject->GetName() : TEXT(""))); + return false; } else { LogStep(ELogVerbosity::Log, FString::Printf(TEXT("String assertion passed (%s)"), *What)); + return true; } } +bool AFunctionalTest::AssertEqual_TraceQueryResults(const UTraceQueryTestResults* Actual, const UTraceQueryTestResults* Expected, const FString& What, const UObject* ContextObject) +{ + return Actual->AssertEqual(Expected, What, ContextObject, *this); +} + void AFunctionalTest::AddWarning(const FString Message) { LogStep(ELogVerbosity::Warning, Message); @@ -726,9 +803,10 @@ void AFunctionalTest::LogStep(ELogVerbosity::Type Verbosity, const FString& Mess switch ( Verbosity ) { + case ELogVerbosity::Display: case ELogVerbosity::Log: - UE_VLOG(this, LogFunctionalTest, Log, TEXT("%s"), *FullMessage); - UE_LOG(LogFunctionalTest, Log, TEXT("%s"), *FullMessage); + UE_VLOG(this, LogFunctionalTest, Display, TEXT("%s"), *FullMessage); + UE_LOG(LogFunctionalTest, Display, TEXT("%s"), *FullMessage); break; case ELogVerbosity::Warning: UE_VLOG(this, LogFunctionalTest, Warning, TEXT("%s"), *FullMessage); diff --git a/Engine/Source/Developer/FunctionalTesting/Private/FunctionalTestUtilityLibrary.cpp b/Engine/Source/Developer/FunctionalTesting/Private/FunctionalTestUtilityLibrary.cpp new file mode 100644 index 000000000000..e0978d34da2e --- /dev/null +++ b/Engine/Source/Developer/FunctionalTesting/Private/FunctionalTestUtilityLibrary.cpp @@ -0,0 +1,105 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "FunctionalTestUtilityLibrary.h" +#include "TraceQueryTestResults.h" + +UTraceQueryTestResults* UFunctionalTestUtilityLibrary::TraceChannelTestUtil(UObject* WorldContextObject, const FTraceChannelTestBatchOptions& BatchOptions, const FVector Start, const FVector End, float SphereCapsuleRadius, float CapsuleHalfHeight, FVector BoxHalfSize, const FRotator Orientation, ETraceTypeQuery TraceChannel, TArray > ObjectTypes, FName ProfileName, bool bTraceComplex, const TArray& ActorsToIgnore, bool bIgnoreSelf, EDrawDebugTrace::Type DrawDebugType, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime) +{ + UTraceQueryTestResults* Results = NewObject(); + if(Results) + { + //line + Results->BatchOptions = BatchOptions; + if(BatchOptions.bLineTrace) + { + if(BatchOptions.bChannelTrace) + { + Results->ChannelResults.LineResults.bSingleResult = UKismetSystemLibrary::LineTraceSingle(WorldContextObject, Start, End, TraceChannel, bTraceComplex, ActorsToIgnore, DrawDebugType, Results->ChannelResults.LineResults.SingleHit, bIgnoreSelf, TraceColor, TraceHitColor, DrawTime); + Results->ChannelResults.LineResults.bMultiResult = UKismetSystemLibrary::LineTraceMulti(WorldContextObject, Start, End, TraceChannel, bTraceComplex, ActorsToIgnore, DrawDebugType, Results->ChannelResults.LineResults.MultiHits, bIgnoreSelf, TraceColor, TraceHitColor, DrawTime); + } + + if(BatchOptions.bObjectsTrace) + { + Results->ObjectResults.LineResults.bSingleResult = UKismetSystemLibrary::LineTraceSingleForObjects(WorldContextObject, Start, End, ObjectTypes, bTraceComplex, ActorsToIgnore, DrawDebugType, Results->ObjectResults.LineResults.SingleHit, bIgnoreSelf, TraceColor, TraceHitColor, DrawTime); + Results->ObjectResults.LineResults.bMultiResult = UKismetSystemLibrary::LineTraceMultiForObjects(WorldContextObject, Start, End, ObjectTypes, bTraceComplex, ActorsToIgnore, DrawDebugType, Results->ObjectResults.LineResults.MultiHits, bIgnoreSelf, TraceColor, TraceHitColor, DrawTime); + } + + if(BatchOptions.bProfileTrace) + { + Results->ProfileResults.LineResults.bSingleResult = UKismetSystemLibrary::LineTraceSingleByProfile(WorldContextObject, Start, End, ProfileName, bTraceComplex, ActorsToIgnore, DrawDebugType, Results->ProfileResults.LineResults.SingleHit, bIgnoreSelf, TraceColor, TraceHitColor, DrawTime); + Results->ProfileResults.LineResults.bMultiResult = UKismetSystemLibrary::LineTraceMultiByProfile(WorldContextObject, Start, End, ProfileName, bTraceComplex, ActorsToIgnore, DrawDebugType, Results->ProfileResults.LineResults.MultiHits, bIgnoreSelf, TraceColor, TraceHitColor, DrawTime); + } + } + + + //sphere + if(BatchOptions.bSphereTrace) + { + if (BatchOptions.bChannelTrace) + { + Results->ChannelResults.SphereResults.bSingleResult = UKismetSystemLibrary::SphereTraceSingle(WorldContextObject, Start, End, SphereCapsuleRadius, TraceChannel, bTraceComplex, ActorsToIgnore, DrawDebugType, Results->ChannelResults.SphereResults.SingleHit, bIgnoreSelf, TraceColor, TraceHitColor, DrawTime); + Results->ChannelResults.SphereResults.bMultiResult = UKismetSystemLibrary::SphereTraceMulti(WorldContextObject, Start, End, SphereCapsuleRadius, TraceChannel, bTraceComplex, ActorsToIgnore, DrawDebugType, Results->ChannelResults.SphereResults.MultiHits, bIgnoreSelf, TraceColor, TraceHitColor, DrawTime); + } + + if (BatchOptions.bObjectsTrace) + { + Results->ObjectResults.SphereResults.bSingleResult = UKismetSystemLibrary::SphereTraceSingleForObjects(WorldContextObject, Start, End, SphereCapsuleRadius, ObjectTypes, bTraceComplex, ActorsToIgnore, DrawDebugType, Results->ObjectResults.SphereResults.SingleHit, bIgnoreSelf, TraceColor, TraceHitColor, DrawTime); + Results->ObjectResults.SphereResults.bMultiResult = UKismetSystemLibrary::SphereTraceMultiForObjects(WorldContextObject, Start, End, SphereCapsuleRadius, ObjectTypes, bTraceComplex, ActorsToIgnore, DrawDebugType, Results->ObjectResults.SphereResults.MultiHits, bIgnoreSelf, TraceColor, TraceHitColor, DrawTime); + } + + if (BatchOptions.bProfileTrace) + { + Results->ProfileResults.SphereResults.bSingleResult = UKismetSystemLibrary::SphereTraceSingleByProfile(WorldContextObject, Start, End, SphereCapsuleRadius, ProfileName, bTraceComplex, ActorsToIgnore, DrawDebugType, Results->ProfileResults.SphereResults.SingleHit, bIgnoreSelf, TraceColor, TraceHitColor, DrawTime); + Results->ProfileResults.SphereResults.bMultiResult = UKismetSystemLibrary::SphereTraceMultiByProfile(WorldContextObject, Start, End, SphereCapsuleRadius, ProfileName, bTraceComplex, ActorsToIgnore, DrawDebugType, Results->ProfileResults.SphereResults.MultiHits, bIgnoreSelf, TraceColor, TraceHitColor, DrawTime); + } + } + + //capsule + if(BatchOptions.bCapsuleTrace) + { + if (BatchOptions.bChannelTrace) + { + Results->ChannelResults.CapsuleResults.bSingleResult = UKismetSystemLibrary::CapsuleTraceSingle(WorldContextObject, Start, End, SphereCapsuleRadius, CapsuleHalfHeight, TraceChannel, bTraceComplex, ActorsToIgnore, DrawDebugType, Results->ChannelResults.CapsuleResults.SingleHit, bIgnoreSelf, TraceColor, TraceHitColor, DrawTime); + Results->ChannelResults.CapsuleResults.bMultiResult = UKismetSystemLibrary::CapsuleTraceMulti(WorldContextObject, Start, End, SphereCapsuleRadius, CapsuleHalfHeight, TraceChannel, bTraceComplex, ActorsToIgnore, DrawDebugType, Results->ChannelResults.CapsuleResults.MultiHits, bIgnoreSelf, TraceColor, TraceHitColor, DrawTime); + } + + if (BatchOptions.bObjectsTrace) + { + Results->ObjectResults.CapsuleResults.bSingleResult = UKismetSystemLibrary::CapsuleTraceSingleForObjects(WorldContextObject, Start, End, SphereCapsuleRadius, CapsuleHalfHeight, ObjectTypes, bTraceComplex, ActorsToIgnore, DrawDebugType, Results->ObjectResults.CapsuleResults.SingleHit, bIgnoreSelf, TraceColor, TraceHitColor, DrawTime); + Results->ObjectResults.CapsuleResults.bMultiResult = UKismetSystemLibrary::CapsuleTraceMultiForObjects(WorldContextObject, Start, End, SphereCapsuleRadius, CapsuleHalfHeight, ObjectTypes, bTraceComplex, ActorsToIgnore, DrawDebugType, Results->ObjectResults.CapsuleResults.MultiHits, bIgnoreSelf, TraceColor, TraceHitColor, DrawTime); + } + + if (BatchOptions.bProfileTrace) + { + Results->ProfileResults.CapsuleResults.bSingleResult = UKismetSystemLibrary::CapsuleTraceSingleByProfile(WorldContextObject, Start, End, SphereCapsuleRadius, CapsuleHalfHeight, ProfileName, bTraceComplex, ActorsToIgnore, DrawDebugType, Results->ProfileResults.CapsuleResults.SingleHit, bIgnoreSelf, TraceColor, TraceHitColor, DrawTime); + Results->ProfileResults.CapsuleResults.bMultiResult = UKismetSystemLibrary::CapsuleTraceMultiByProfile(WorldContextObject, Start, End, SphereCapsuleRadius, CapsuleHalfHeight, ProfileName, bTraceComplex, ActorsToIgnore, DrawDebugType, Results->ProfileResults.CapsuleResults.MultiHits, bIgnoreSelf, TraceColor, TraceHitColor, DrawTime); + } + } + + //box + if(BatchOptions.bBoxTrace) + { + if (BatchOptions.bChannelTrace) + { + Results->ChannelResults.BoxResults.bSingleResult = UKismetSystemLibrary::BoxTraceSingle(WorldContextObject, Start, End, BoxHalfSize, Orientation, TraceChannel, bTraceComplex, ActorsToIgnore, DrawDebugType, Results->ChannelResults.BoxResults.SingleHit, bIgnoreSelf, TraceColor, TraceHitColor, DrawTime); + Results->ChannelResults.BoxResults.bMultiResult = UKismetSystemLibrary::BoxTraceMulti(WorldContextObject, Start, End, BoxHalfSize, Orientation, TraceChannel, bTraceComplex, ActorsToIgnore, DrawDebugType, Results->ChannelResults.BoxResults.MultiHits, bIgnoreSelf, TraceColor, TraceHitColor, DrawTime); + } + + if (BatchOptions.bObjectsTrace) + { + Results->ObjectResults.BoxResults.bSingleResult = UKismetSystemLibrary::BoxTraceSingleForObjects(WorldContextObject, Start, End, BoxHalfSize, Orientation, ObjectTypes, bTraceComplex, ActorsToIgnore, DrawDebugType, Results->ObjectResults.BoxResults.SingleHit, bIgnoreSelf, TraceColor, TraceHitColor, DrawTime); + Results->ObjectResults.BoxResults.bMultiResult = UKismetSystemLibrary::BoxTraceMultiForObjects(WorldContextObject, Start, End, BoxHalfSize, Orientation, ObjectTypes, bTraceComplex, ActorsToIgnore, DrawDebugType, Results->ObjectResults.BoxResults.MultiHits, bIgnoreSelf, TraceColor, TraceHitColor, DrawTime); + } + + if (BatchOptions.bProfileTrace) + { + Results->ProfileResults.BoxResults.bSingleResult = UKismetSystemLibrary::BoxTraceSingleByProfile(WorldContextObject, Start, End, BoxHalfSize, Orientation, ProfileName, bTraceComplex, ActorsToIgnore, DrawDebugType, Results->ProfileResults.BoxResults.SingleHit, bIgnoreSelf, TraceColor, TraceHitColor, DrawTime); + Results->ProfileResults.BoxResults.bMultiResult = UKismetSystemLibrary::BoxTraceMultiByProfile(WorldContextObject, Start, End, BoxHalfSize, Orientation, ProfileName, bTraceComplex, ActorsToIgnore, DrawDebugType, Results->ProfileResults.BoxResults.MultiHits, bIgnoreSelf, TraceColor, TraceHitColor, DrawTime); + } + } + + Results->CaptureNames(); + } + + return Results; +} \ No newline at end of file diff --git a/Engine/Source/Developer/FunctionalTesting/Private/FunctionalTestingManager.cpp b/Engine/Source/Developer/FunctionalTesting/Private/FunctionalTestingManager.cpp index 8dbf309cd3ce..ba1589b50d14 100644 --- a/Engine/Source/Developer/FunctionalTesting/Private/FunctionalTestingManager.cpp +++ b/Engine/Source/Developer/FunctionalTesting/Private/FunctionalTestingManager.cpp @@ -62,7 +62,6 @@ UFunctionalTestingManager::UFunctionalTestingManager( const FObjectInitializer& , bIsRunning(false) , bFinished(false) , bLooped(false) - , bWaitForNavigationBuildFinish(false) , bInitialDelayApplied(false) , CurrentIteration(INDEX_NONE) { @@ -85,9 +84,9 @@ struct FSortTestActorsByName } }; -bool UFunctionalTestingManager::RunAllFunctionalTests(UObject* WorldContext, bool bNewLog, bool bRunLooped, bool bInWaitForNavigationBuildFinish, FString ReproString) +bool UFunctionalTestingManager::RunAllFunctionalTests(UObject* WorldContextObject, bool bNewLog, bool bRunLooped, bool bInWaitForNavigationBuildFinish, FString ReproString) { - UFunctionalTestingManager* Manager = GetManager(WorldContext); + UFunctionalTestingManager* Manager = GetManager(WorldContextObject); if (Manager->bIsRunning) { @@ -95,11 +94,11 @@ bool UFunctionalTestingManager::RunAllFunctionalTests(UObject* WorldContext, boo return true; } - WorldContext->GetWorld()->ForceGarbageCollection(true); + UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject); + World->ForceGarbageCollection(true); Manager->bFinished = false; Manager->bLooped = bRunLooped; - Manager->bWaitForNavigationBuildFinish = bInWaitForNavigationBuildFinish; Manager->CurrentIteration = 0; Manager->TestsLeft.Reset(); Manager->AllTests.Reset(); @@ -114,14 +113,14 @@ bool UFunctionalTestingManager::RunAllFunctionalTests(UObject* WorldContext, boo } else { - for (TActorIterator It(WorldContext->GetWorld()); It; ++It) + for (TActorIterator It(World); It; ++It) { APhasedAutomationActorBase* PAA = (*It); Manager->OnTestsComplete.AddDynamic(PAA, &APhasedAutomationActorBase::OnFunctionalTestingComplete); Manager->OnTestsBegin.AddDynamic(PAA, &APhasedAutomationActorBase::OnFunctionalTestingBegin); } - for (TActorIterator It(WorldContext->GetWorld()); It; ++It) + for (TActorIterator It(World); It; ++It) { AFunctionalTest* Test = (*It); if (Test != nullptr && Test->IsEnabled() == true) @@ -157,7 +156,11 @@ void UFunctionalTestingManager::TriggerFirstValidTest() check(World); bIsRunning = World->GetNavigationSystem() != nullptr; - if (bInitialDelayApplied == true && (bWaitForNavigationBuildFinish == false || UNavigationSystem::IsNavigationBeingBuilt(World) == false) && World->AreActorsInitialized()) + const bool bIsWorldInitialized = + World->AreActorsInitialized() && + !UNavigationSystem::IsNavigationBeingBuilt(World); + + if (bInitialDelayApplied == true && bIsWorldInitialized) { bIsRunning = RunFirstValidTest(); if (bIsRunning == false) @@ -177,10 +180,11 @@ UFunctionalTestingManager* UFunctionalTestingManager::GetManager(UObject* WorldC { UFunctionalTestingManager* Manager = FFunctionalTestingModule::Get()->GetCurrentScript(); - if (Manager == NULL) + if (Manager == nullptr) { - UObject* Outer = WorldContext ? WorldContext : (UObject*)GetTransientPackage(); - Manager = NewObject(Outer); + check(WorldContext); + UObject* World = GEngine->GetWorldFromContextObject(WorldContext); + Manager = NewObject(World); FFunctionalTestingModule::Get()->SetScript(Manager); // add to root and get notified on world cleanup to remove from root on map cleanup @@ -202,6 +206,9 @@ void UFunctionalTestingManager::OnWorldCleanedUp(UWorld* World, bool bSessionEnd if (MyWorld == World) { RemoveFromRoot(); + + // Clear the functional test manager once the world is removed. + FFunctionalTestingModule::Get()->SetScript(nullptr); } } @@ -282,7 +289,12 @@ bool UFunctionalTestingManager::RunFirstValidTest() if (TestReproStrings.Num() > 0) { UWorld* World = GetWorld(); - UObject* TestsOuter = World ? (UObject*)(World->PersistentLevel) : (UObject*)(ANY_PACKAGE); + + if (World == nullptr) + { + UE_LOG(LogFunctionalTest, Warning, TEXT("Unable to find testing world!")); + return bTestSuccessfullyTriggered; + } while (TestReproStrings.Num() > 0) { @@ -301,7 +313,16 @@ bool UFunctionalTestingManager::RunFirstValidTest() // first param is the test name. Look for it const FString TestName = TestParams[0]; TestParams.RemoveAt(0, 1, /*bAllowShrinking=*/false); - AFunctionalTest* TestToRun = FindObject(TestsOuter, *TestName); + + AFunctionalTest* TestToRun = nullptr; + for (TActorIterator It(World); It; ++It) + { + if (It->GetName() == TestName) + { + TestToRun = *It; + } + } + if (TestToRun) { // Add the test we found to the tests left to run, so that if re-runs occur we continue to process this test until @@ -321,7 +342,13 @@ bool UFunctionalTestingManager::RunFirstValidTest() } else { - UE_LOG(LogFunctionalTest, Warning, TEXT("Unable to find test \'%s\'"), *TestName); + UE_LOG(LogFunctionalTest, Warning, TEXT("Unable to find test \'%s\' in world %s, the available tests are..."), *TestName, *World->GetFullName()); + + // Find Actors by type (needs a UWorld object) + for (TActorIterator It(World); It; ++It) + { + UE_LOG(LogFunctionalTest, Warning, TEXT("\'%s\'."), *It->GetName()); + } } } } diff --git a/Engine/Source/Developer/FunctionalTesting/Private/GroundTruthData.cpp b/Engine/Source/Developer/FunctionalTesting/Private/GroundTruthData.cpp new file mode 100644 index 000000000000..0b6b823d66fd --- /dev/null +++ b/Engine/Source/Developer/FunctionalTesting/Private/GroundTruthData.cpp @@ -0,0 +1,104 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "GroundTruthData.h" + +#include "UObject/UnrealType.h" +#include "UObject/Package.h" +#include "Misc/PackageName.h" +#include "AssetData.h" + +#if WITH_EDITOR +#include "ISourceControlModule.h" +#include "ISourceControlProvider.h" +#include "ISourceControlOperation.h" +#endif + +DEFINE_LOG_CATEGORY_STATIC(GroundTruthLog, Log, Log) + +UGroundTruthData::UGroundTruthData() + : bResetGroundTruth(false) +{ +} + +bool UGroundTruthData::CanModify() const +{ + return ObjectData == nullptr; +} + +UObject* UGroundTruthData::LoadObject() +{ + UE_LOG(GroundTruthLog, Log, TEXT("Loaded Ground Truth, '%s'."), *GetPathName()); + + return ObjectData; +} + +void UGroundTruthData::SaveObject(UObject* GroundTruth) +{ + FAssetData GroundTruthAssetData(this); + + UPackage* GroundTruthPackage = GetOutermost(); + FString GroundTruthPackageName = GroundTruthAssetData.PackageName.ToString(); + +#if WITH_EDITOR + if (!CanModify()) + { + UE_LOG(GroundTruthLog, Warning, TEXT("Ground Truth, '%s' already set, unable to save changes. Open and use bResetGroundTruth to reset the ground truth."), *GroundTruthPackageName); + return; + } + + if (GroundTruth == nullptr) + { + UE_LOG(GroundTruthLog, Error, TEXT("Ground Truth, '%s' can not store a null object."), *GroundTruthPackageName); + return; + } + + if (GIsBuildMachine) + { + UE_LOG(GroundTruthLog, Error, TEXT("Ground Truth, '%s' can not be modified on the build machine."), *GroundTruthPackageName); + return; + } + + if (ISourceControlModule::Get().IsEnabled()) + { + ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider(); + SourceControlProvider.Execute(ISourceControlOperation::Create(), GroundTruthPackage); + SourceControlProvider.Execute(ISourceControlOperation::Create(), GroundTruthPackage); + } + + ObjectData = GroundTruth; + GroundTruth->Rename(nullptr, this); + MarkPackageDirty(); + + if (!UPackage::SavePackage(GroundTruthPackage, NULL, RF_Standalone, *FPackageName::LongPackageNameToFilename(GroundTruthPackageName, FPackageName::GetAssetPackageExtension()), GError, nullptr, false, true, SAVE_NoError)) + { + UE_LOG(GroundTruthLog, Error, TEXT("Failed to save ground truth data! %s"), *GroundTruthPackageName); + } + + UE_LOG(GroundTruthLog, Log, TEXT("Saved Ground Truth, '%s'."), *GroundTruthPackageName); + +#else + UE_LOG(GroundTruthLog, Error, TEXT("Can't save ground truth data outside of the editor, '%s'."), *GroundTruthPackageName); +#endif +} + +#if WITH_EDITOR + +void UGroundTruthData::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) +{ + Super::PostEditChangeProperty(PropertyChangedEvent); + + if (PropertyChangedEvent.GetPropertyName() == GET_MEMBER_NAME_CHECKED(UGroundTruthData, bResetGroundTruth)) + { + bResetGroundTruth = false; + + if (ObjectData) + { + ObjectData->Rename(nullptr, GetTransientPackage()); + ObjectData = nullptr; + } + + MarkPackageDirty(); + } +} + +#endif \ No newline at end of file diff --git a/Engine/Source/Developer/FunctionalTesting/Private/TraceQueryTestResults.cpp b/Engine/Source/Developer/FunctionalTesting/Private/TraceQueryTestResults.cpp new file mode 100644 index 000000000000..f8642cd98dbc --- /dev/null +++ b/Engine/Source/Developer/FunctionalTesting/Private/TraceQueryTestResults.cpp @@ -0,0 +1,230 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "TraceQueryTestResults.h" +#include "FunctionalTest.h" +#include "Components/PrimitiveComponent.h" +#include "PhysicalMaterials/PhysicalMaterial.h" + +FString FTraceQueryTestNames::ToString() const +{ + return FString::Printf(TEXT("Component:%s, Actor:%s, PhysicalMaterial:%s"), *ComponentName.ToString(), *ActorName.ToString(), *PhysicalMaterialName.ToString()); +} + +FString FTraceQueryTestResultsInnerMost::ToString() const +{ + FString OutSingle = FString::Printf(TEXT("----SingleResult:%d %s {%s}"), bSingleResult, *SingleNames.ToString(), *SingleHit.ToString()); + FString OutMulti = FString::Printf(TEXT("\n----MultiResult:%d"), bMultiResult); + + for(int32 Counter = 0; Counter < MultiHits.Num(); ++Counter) + { + OutMulti.Append(FString::Printf(TEXT("\n----[%d] %s {%s}"), Counter, *MultiNames[Counter].ToString(), *MultiHits[Counter].ToString())); + } + + return OutSingle.Append(OutMulti); +} + +FString FTraceQueryTestResultsInner::ToString(const FTraceChannelTestBatchOptions& BatchOptions) const +{ + FString LineResultsStr = BatchOptions.bLineTrace ? FString::Printf(TEXT("--LineResults:\n%s\n\n"), *LineResults.ToString()) : ""; + FString SphereResultsStr = BatchOptions.bSphereTrace ? FString::Printf(TEXT("--SphereResults:\n%s\n\n"), *SphereResults.ToString()) : ""; + FString CapsuleResultsStr = BatchOptions.bCapsuleTrace ? FString::Printf(TEXT("--CapsuleResults:\n%s\n\n"), *CapsuleResults.ToString()) : ""; + FString BoxResultsStr = BatchOptions.bBoxTrace ? FString::Printf(TEXT("--BoxResults:\n%s\n\n"), *BoxResults.ToString()) : ""; + + return FString::Printf(TEXT("%s%s%s%s"), *LineResultsStr, *SphereResultsStr, *CapsuleResultsStr, *BoxResultsStr); +} + +FString UTraceQueryTestResults::ToString() +{ + CaptureNames(); + + FString ChannelResultsStr = BatchOptions.bChannelTrace ? FString::Printf(TEXT("ChannelResults:\n%s\n\n"), *ChannelResults.ToString(BatchOptions)) : ""; + FString ObjectResultsStr = BatchOptions.bObjectsTrace ? FString::Printf(TEXT("ObjectResults:\n%s\n\n"), *ObjectResults.ToString(BatchOptions)) : ""; + FString ProfileResultsStr = BatchOptions.bProfileTrace ? FString::Printf(TEXT("ProfileResults:\n%s\n\n"), *ProfileResults.ToString(BatchOptions)) : ""; + + return FString::Printf(TEXT("%s%s%s"), *ChannelResultsStr, *ObjectResultsStr, *ProfileResultsStr); +} + +void CaptureNameHelper(FTraceQueryTestNames& Names, FHitResult& HitResult) +{ + UPrimitiveComponent* HitComp = HitResult.GetComponent(); + AActor* HitActor = HitResult.GetActor(); + UPhysicalMaterial* PhysMat = HitResult.PhysMaterial.Get(); + + Names.ComponentName = HitComp ? HitComp->GetFName() : NAME_None; + Names.ActorName = HitActor ? HitActor->GetFName() : NAME_None; + Names.PhysicalMaterialName = PhysMat ? PhysMat->GetFName() : NAME_None; +} + +void FTraceQueryTestResultsInnerMost::CaptureNames() +{ + CaptureNameHelper(SingleNames, SingleHit); + + MultiNames.Reset(); + MultiNames.AddZeroed(MultiHits.Num()); + + for(int32 HitIdx = 0; HitIdx < MultiHits.Num(); ++HitIdx) + { + CaptureNameHelper(MultiNames[HitIdx], MultiHits[HitIdx]); + } +} + +void FTraceQueryTestResultsInner::CaptureNames() +{ + LineResults.CaptureNames(); + SphereResults.CaptureNames(); + CapsuleResults.CaptureNames(); + BoxResults.CaptureNames(); +} + +void UTraceQueryTestResults::CaptureNames() +{ + ChannelResults.CaptureNames(); + ObjectResults.CaptureNames(); + ProfileResults.CaptureNames(); +} + +FString FTraceChannelTestBatchOptions::ToString() const +{ + return FString::Printf(TEXT("bLineTrace:%d, bSphereTrace:%d, bCapsuleTrace:%d, bBoxTrace:%d, bChannelTrace:%d, bObjectsTrace:%d, bProfileTrace:%d"), bLineTrace, bSphereTrace, bCapsuleTrace, bBoxTrace, bChannelTrace, bObjectsTrace, bProfileTrace); +} + +#define TEST_IMPL(X, Type) FunctionalTest.AssertEqual_##Type(Actual.##X, Expected.##X, FString::Printf(TEXT("%s:"#X), *What), ContextObject) +#define TEST_IMPL_TOLERANCE(X, Type) FunctionalTest.AssertEqual_##Type(Actual.##X, Expected.##X, FString::Printf(TEXT("%s:"#X), *What), KINDA_SMALL_NUMBER, ContextObject) +#define TEST_BOOL(X) TEST_IMPL(X, Bool) +#define TEST_INT(X) TEST_IMPL(X, Int) +#define TEST_NAME(X) TEST_IMPL(X, Name) +#define TEST_FLOAT(X) TEST_IMPL_TOLERANCE(X, Float) +#define TEST_VECTOR(X) TEST_IMPL_TOLERANCE(X, Vector) + +bool HelperAssertNamesEqual(const FTraceQueryTestNames& Actual, const FTraceQueryTestNames& Expected, const FString& What, const UObject* ContextObject, AFunctionalTest& FunctionalTest) +{ +#if 0 + bool bResults[] = { + TEST_NAME(ComponentName), + TEST_NAME(ActorName), + TEST_NAME(PhysicalMaterialName) + }; + + for (bool bSuccess : bResults) + { + if (!bSuccess) + { + return false; + } + } +#endif + + return true; +} + +bool HelperAssertFHitResultEqual(const FHitResult& Actual, const FHitResult& Expected, const FString& What, const UObject* ContextObject, AFunctionalTest& FunctionalTest) +{ +#if 0 + bool bResults[] = { + TEST_BOOL(bBlockingHit), + TEST_BOOL(bStartPenetrating), + TEST_FLOAT(Time), + TEST_FLOAT(Distance), + TEST_VECTOR(Location), + TEST_VECTOR(ImpactPoint), + TEST_VECTOR(Normal), + TEST_VECTOR(ImpactNormal), + TEST_VECTOR(TraceStart), + TEST_VECTOR(TraceEnd), + TEST_FLOAT(PenetrationDepth), + TEST_INT(Item), + TEST_NAME(BoneName), + TEST_INT(FaceIndex) + }; + + for(bool bSuccess : bResults) + { + if(!bSuccess) + { + return false; + } + } +#endif + + return true; +} + +#undef TEST_IMPL +#undef TEST_IMPL_TOLERANCE +#undef TEST_BOOL +#undef TEST_INT +#undef TEST_FLOAT +#undef TEST_VECTOR + +bool FTraceQueryTestResultsInnerMost::AssertEqual(const FTraceQueryTestResultsInnerMost& Expected, const FString& What, const UObject* ContextObject, AFunctionalTest& FunctionalTest) const +{ + bool bSuccess = true; + if(FunctionalTest.AssertEqual_Bool(bSingleResult, Expected.bSingleResult, FString::Printf(TEXT("%s:bSingleResult"), *What), ContextObject)) + { + bSuccess = HelperAssertFHitResultEqual(SingleHit, Expected.SingleHit, FString::Printf(TEXT("%s_SingleHit"), *What), ContextObject, FunctionalTest); + bSuccess &= HelperAssertNamesEqual(SingleNames, Expected.SingleNames, FString::Printf(TEXT("%s_SingleHit"), *What), ContextObject, FunctionalTest); + } + else + { + bSuccess = false; + } + + if (FunctionalTest.AssertEqual_Bool(bMultiResult, Expected.bMultiResult, FString::Printf(TEXT("%s:bMultiResult"), *What), ContextObject)) + { + if(FunctionalTest.AssertValue_Int(MultiHits.Num(), EComparisonMethod::Equal_To, Expected.MultiHits.Num(), FString::Printf(TEXT("%s:MultiHitsNum"), *What), ContextObject)) + { + for (int32 HitIdx = 0; HitIdx < MultiHits.Num(); ++HitIdx) + { + bSuccess &= HelperAssertFHitResultEqual(MultiHits[HitIdx], Expected.MultiHits[HitIdx], FString::Printf(TEXT("%s_MultiHit[%d]"), *What, HitIdx), ContextObject, FunctionalTest); + bSuccess &= HelperAssertNamesEqual(MultiNames[HitIdx], Expected.MultiNames[HitIdx], FString::Printf(TEXT("%s_MultiHitHit[%d]"), *What, HitIdx), ContextObject, FunctionalTest); + } + } + else + { + bSuccess = false; + } + } + else + { + bSuccess = false; + } + + return bSuccess; +} + +bool FTraceQueryTestResultsInner::AssertEqual(const FTraceQueryTestResultsInner& Expected, const FString& What, const UObject* ContextObject, AFunctionalTest& FunctionalTest) const +{ + const bool bLineResults = LineResults.AssertEqual(Expected.LineResults, FString::Printf(TEXT("%s_Line"), *What), ContextObject, FunctionalTest); + const bool bSphereResults = SphereResults.AssertEqual(Expected.SphereResults, FString::Printf(TEXT("%s_Sphere"), *What), ContextObject, FunctionalTest); + const bool bCapsuleResults = CapsuleResults.AssertEqual(Expected.CapsuleResults, FString::Printf(TEXT("%s_Capsule"), *What), ContextObject, FunctionalTest); + const bool bBoxResults = BoxResults.AssertEqual(Expected.BoxResults, FString::Printf(TEXT("%s_Box"), *What), ContextObject, FunctionalTest); + + return bLineResults && bSphereResults && bCapsuleResults && bBoxResults; +} + +bool UTraceQueryTestResults::AssertEqual(const UTraceQueryTestResults* Expected, const FString& What, const UObject* ContextObject, AFunctionalTest& FunctionalTest) const +{ + if(Expected->BatchOptions != BatchOptions) + { + FunctionalTest.LogStep(ELogVerbosity::Error, FString::Printf(TEXT("Expected '%s' to be {%s} but it was {%s} for context '%s'"), *What, *Expected->BatchOptions.ToString(), *BatchOptions.ToString(), ContextObject ? *ContextObject->GetName() : TEXT(""))); + return false; + } + else + { + //Purposely do all 3 so we get errors for as much as possible + const bool bChannelResults = ChannelResults.AssertEqual(Expected->ChannelResults, FString::Printf(TEXT("%s_Channel"), *What), ContextObject, FunctionalTest); + const bool bObjectResults = ObjectResults.AssertEqual(Expected->ObjectResults, FString::Printf(TEXT("%s_Object"), *What), ContextObject, FunctionalTest); + const bool bProfileResults = ProfileResults.AssertEqual(Expected->ProfileResults, FString::Printf(TEXT("%s_Profile"), *What), ContextObject, FunctionalTest); + if( bChannelResults && bObjectResults && bProfileResults) + { + FunctionalTest.LogStep(ELogVerbosity::Log, FString::Printf(TEXT("TraceQueryTestResults assertion passed (%s)"), *What)); + return true; + } + else + { + FunctionalTest.LogStep(ELogVerbosity::Error, FString::Printf(TEXT("'%s' comparison failed for context '%s'"), *What, ContextObject ? *ContextObject->GetName() : TEXT(""))); + return false; + } + } +} + diff --git a/Engine/Source/Developer/FunctionalTesting/Public/AutomationBlueprintFunctionLibrary.h b/Engine/Source/Developer/FunctionalTesting/Public/AutomationBlueprintFunctionLibrary.h index cc0a29f82e90..2c51fa8e77d5 100644 --- a/Engine/Source/Developer/FunctionalTesting/Public/AutomationBlueprintFunctionLibrary.h +++ b/Engine/Source/Developer/FunctionalTesting/Public/AutomationBlueprintFunctionLibrary.h @@ -11,6 +11,9 @@ class ACameraActor; +/** + * + */ UCLASS() class FUNCTIONALTESTING_API UAutomationBlueprintFunctionLibrary : public UBlueprintFunctionLibrary { @@ -19,27 +22,60 @@ class FUNCTIONALTESTING_API UAutomationBlueprintFunctionLibrary : public UBluepr public: static bool TakeAutomationScreenshotInternal(UObject* WorldContextObject, const FString& Name, FAutomationScreenshotOptions Options); + /** + * Takes a screenshot of the game's viewport. Does not capture any UI. + */ UFUNCTION(BlueprintCallable, Category = "Automation", meta = (Latent, HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject", LatentInfo = "LatentInfo", Name = "" )) static void TakeAutomationScreenshot(UObject* WorldContextObject, FLatentActionInfo LatentInfo, const FString& Name, const FAutomationScreenshotOptions& Options); + /** + * Takes a screenshot of the game's viewport, from a particular camera actors POV. Does not capture any UI. + */ UFUNCTION(BlueprintCallable, Category = "Automation", meta = (Latent, HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject", LatentInfo = "LatentInfo", NameOverride = "" )) static void TakeAutomationScreenshotAtCamera(UObject* WorldContextObject, FLatentActionInfo LatentInfo, ACameraActor* Camera, const FString& NameOverride, const FAutomationScreenshotOptions& Options); + /** + * + */ UFUNCTION(BlueprintCallable, Category = "Automation", meta = ( Latent, HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject", LatentInfo = "LatentInfo", NameOverride = "" )) static void TakeAutomationScreenshotOfUI(UObject* WorldContextObject, FLatentActionInfo LatentInfo, const FString& Name, const FAutomationScreenshotOptions& Options); - //UFUNCTION(BlueprintCallable, Category = "Automation|Performance") - //static void BeginPerformanceCapture(); + UFUNCTION(BlueprintCallable, Category = "Automation", meta = (HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject")) + static void EnableStatGroup(UObject* WorldContextObject, FName GroupName); - //UFUNCTION(BlueprintCallable, Category = "Automation|Performance") - //static void EndPerformanceCapture(); + UFUNCTION(BlueprintCallable, Category = "Automation", meta = (HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject")) + static void DisableStatGroup(UObject* WorldContextObject, FName GroupName); + UFUNCTION(BlueprintCallable, Category = "Automation") + static float GetStatIncAverage(FName StatName); + + UFUNCTION(BlueprintCallable, Category = "Automation") + static float GetStatIncMax(FName StatName); + + UFUNCTION(BlueprintCallable, Category = "Automation") + static float GetStatExcAverage(FName StatName); + + UFUNCTION(BlueprintCallable, Category = "Automation") + static float GetStatExcMax(FName StatName); + + UFUNCTION(BlueprintCallable, Category = "Automation") + static float GetStatCallCount(FName StatName); + + /** + * Lets you know if any automated tests are running, or are about to run and the automation system is spinning up tests. + */ UFUNCTION(BlueprintPure, Category="Automation") static bool AreAutomatedTestsRunning(); + /** + * + */ UFUNCTION(BlueprintPure, Category="Automation") - static FAutomationScreenshotOptions GetDefaultScreenshotOptionsForGameplay(EComparisonTolerance Tolerance = EComparisonTolerance::Low); + static FAutomationScreenshotOptions GetDefaultScreenshotOptionsForGameplay(EComparisonTolerance Tolerance = EComparisonTolerance::Low, float Delay = 0.2); + /** + * + */ UFUNCTION(BlueprintPure, Category="Automation") - static FAutomationScreenshotOptions GetDefaultScreenshotOptionsForRendering(EComparisonTolerance Tolerance = EComparisonTolerance::Low); + static FAutomationScreenshotOptions GetDefaultScreenshotOptionsForRendering(EComparisonTolerance Tolerance = EComparisonTolerance::Low, float Delay = 0.2); }; diff --git a/Engine/Source/Developer/FunctionalTesting/Public/AutomationScreenshotOptions.h b/Engine/Source/Developer/FunctionalTesting/Public/AutomationScreenshotOptions.h index 0a7e74e859af..c0baf4f9f336 100644 --- a/Engine/Source/Developer/FunctionalTesting/Public/AutomationScreenshotOptions.h +++ b/Engine/Source/Developer/FunctionalTesting/Public/AutomationScreenshotOptions.h @@ -140,7 +140,7 @@ public: * essentially the same. Generally this is necessary as modern rendering techniques tend to introduce * noise constantly to hide aliasing. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Comparison") + UPROPERTY(EditAnywhere, Category="Comparison") FComparisonToleranceAmount ToleranceAmount; /** diff --git a/Engine/Source/Developer/FunctionalTesting/Public/GroundTruthData.h b/Engine/Source/Developer/FunctionalTesting/Public/GroundTruthData.h new file mode 100644 index 000000000000..8a482bec66c6 --- /dev/null +++ b/Engine/Source/Developer/FunctionalTesting/Public/GroundTruthData.h @@ -0,0 +1,44 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "UObject/Object.h" +#include "UObject/ScriptMacros.h" +#include "GroundTruthData.generated.h" + +/** + * + */ +UCLASS(BlueprintType) +class FUNCTIONALTESTING_API UGroundTruthData : public UObject +{ + GENERATED_BODY() + +public: + UGroundTruthData(); + + UFUNCTION(BlueprintCallable, Category = "Automation") + void SaveObject(UObject* GroundTruth); + + UFUNCTION(BlueprintCallable, Category = "Automation") + UObject* LoadObject(); + + UFUNCTION(BlueprintCallable, Category = "Automation") + bool CanModify() const; + +#if WITH_EDITOR + virtual void PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) override; +#endif + +public: + + UPROPERTY(EditAnywhere, Category = Data) + bool bResetGroundTruth; + +protected: + + UPROPERTY(VisibleAnywhere, Instanced, Category=Data) + UObject* ObjectData; +}; diff --git a/Engine/Source/Developer/GameplayDebugger/Private/GameplayDebuggerCategoryReplicator.cpp b/Engine/Source/Developer/GameplayDebugger/Private/GameplayDebuggerCategoryReplicator.cpp index 2f2ccdcd3f48..04cb431c388f 100644 --- a/Engine/Source/Developer/GameplayDebugger/Private/GameplayDebuggerCategoryReplicator.cpp +++ b/Engine/Source/Developer/GameplayDebugger/Private/GameplayDebuggerCategoryReplicator.cpp @@ -469,6 +469,8 @@ bool AGameplayDebuggerCategoryReplicator::IsNetRelevantFor(const AActor* RealVie return (RealViewer == OwnerPC); } +/// @cond DOXYGEN_WARNINGS + void AGameplayDebuggerCategoryReplicator::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); @@ -529,6 +531,8 @@ void AGameplayDebuggerCategoryReplicator::ServerSendExtensionInputEvent_Implemen SendExtensionInputEvent(ExtensionId, HandlerId); } +/// @endcond + void AGameplayDebuggerCategoryReplicator::OnReceivedDataPackPacket(int32 CategoryId, int32 DataPackId, const FGameplayDebuggerDataPack& DataPacket) { if (Categories.IsValidIndex(CategoryId) && Categories[CategoryId]->ReplicatedDataPacks.IsValidIndex(DataPackId)) diff --git a/Engine/Source/Developer/GameplayDebugger/Private/GameplayDebuggerLocalController.cpp b/Engine/Source/Developer/GameplayDebugger/Private/GameplayDebuggerLocalController.cpp index d86d3a9995ff..92a3d07bf41c 100644 --- a/Engine/Source/Developer/GameplayDebugger/Private/GameplayDebuggerLocalController.cpp +++ b/Engine/Source/Developer/GameplayDebugger/Private/GameplayDebuggerLocalController.cpp @@ -397,7 +397,7 @@ void UGameplayDebuggerLocalController::BindInput(UInputComponent& InputComponent const int32 NumExtentions = bSimulateMode ? 0 : CachedReplicator->GetNumExtensions(); for (int32 Idx = 0; Idx < NumExtentions; Idx++) { - TSharedRef Extension = CachedReplicator->GetExtension(Idx); + TSharedRef Extension = CachedReplicator->GetExtension(Idx); //-V595 const int32 NumInputHandlers = Extension->GetNumInputHandlers(); for (int32 HandlerIdx = 0; HandlerIdx < NumInputHandlers; HandlerIdx++) diff --git a/Engine/Source/Developer/GameplayDebugger/Private/GameplayDebuggerTypes.cpp b/Engine/Source/Developer/GameplayDebugger/Private/GameplayDebuggerTypes.cpp index da92df079de7..d6da8c6b2118 100644 --- a/Engine/Source/Developer/GameplayDebugger/Private/GameplayDebuggerTypes.cpp +++ b/Engine/Source/Developer/GameplayDebugger/Private/GameplayDebuggerTypes.cpp @@ -491,7 +491,7 @@ void FGameplayDebuggerCanvasContext::MoveToNewLine() void FGameplayDebuggerCanvasContext::MeasureString(const FString& String, float& OutSizeX, float& OutSizeY) const { - OutSizeX = OutSizeX = 0.0f; + OutSizeX = OutSizeY = 0.0f; UCanvas* CanvasOb = Canvas.Get(); if (CanvasOb) diff --git a/Engine/Source/Developer/HTML5/HTML5PlatformEditor/Classes/HTML5TargetSettings.h b/Engine/Source/Developer/HTML5/HTML5PlatformEditor/Classes/HTML5TargetSettings.h index 204b0d7b7e57..f65c7a24498e 100644 --- a/Engine/Source/Developer/HTML5/HTML5PlatformEditor/Classes/HTML5TargetSettings.h +++ b/Engine/Source/Developer/HTML5/HTML5PlatformEditor/Classes/HTML5TargetSettings.h @@ -40,16 +40,25 @@ public: // ------------------------------------------------------------ /** - * Target Web Assembly builds + * Target ASMJS builds + * NOTE 1: to ensure this fits in memory space, build this for "Shipping" + * NOTE 2: ASMJS will be going away in future UE4 releases. */ - UPROPERTY(GlobalConfig, EditAnywhere, Category=Emscripten, Meta = (DisplayName = "WebAssembly Build (or else ASM.js)")) - bool TargetWasm; + UPROPERTY(GlobalConfig, EditAnywhere, Category=Emscripten, Meta = (DisplayName = "asmjs Build (else build WASM [EXPERIMENTAL])")) + bool TargetAsmjs; /** - * Target WebGL2 builds + * Target WebGL1 builds + * NOTE: WebGL1 target will be going away soon... */ - UPROPERTY(GlobalConfig, EditAnywhere, Category=Emscripten, Meta = (DisplayName = "WebGL2 Build (or else WebGL1)")) - bool TargetWebGL2; + UPROPERTY(GlobalConfig, EditAnywhere, Category=Emscripten, Meta = (DisplayName = "WebGL1 Build (else build WebGL2)")) + bool TargetWebGL1; + + /** + * Use IndexedDB storage + */ + UPROPERTY(GlobalConfig, EditAnywhere, Category=Emscripten, Meta = (DisplayName = "IndexedDB storage (WASM only - during shipping packaging [EXPERIMENTAL])")) + bool EnableIndexedDB; /** * Use Fixed TimeStep @@ -58,14 +67,17 @@ public: bool UseFixedTimeStep; // need to make a note of: answerhub 409629 /** - * Enable SIMD - NOTE: this does not currently work with WASM - it will be forced false in this case. - * SIMD will be supported during WASM builds in a future emscripten release. + * Enable SIMD + * NOTE 1: this does not currently work with WASM - it will be forced false in this case. + * NOTE 2: SIMD will be supported during WASM builds in a future emscripten release. */ UPROPERTY(GlobalConfig, EditAnywhere, Category=Emscripten, Meta = (DisplayName = "SIMD support (asm.js only)")) bool EnableSIMD; /** * Enable Multithreading + * NOTE 1: this is not supported currently in WASM - it will be forced false in this case. + * NOTE 2: Multithreading will be supported during WASM builds in a future emscripten release. */ UPROPERTY(GlobalConfig, EditAnywhere, Category=Emscripten, Meta = (DisplayName = "Multithreading support (asm.js only - experimental)")) bool EnableMultithreading; @@ -80,6 +92,8 @@ public: /** * Compress Files + * NOTE 1: it is also recommended to NOT enable PAK file packaging - this is currently redundant + * NOTE 2: future emscripten version will allow separate (asset) files in a new FileSystem feature - which will make use of this (as well as PAK file) option again */ UPROPERTY(GlobalConfig, EditAnywhere, Category=Packaging, Meta = (DisplayName = "Compress files during shipping packaging")) bool Compressed; diff --git a/Engine/Source/Developer/HTML5/HTML5PlatformEditor/Private/HTML5PlatformEditorModule.cpp b/Engine/Source/Developer/HTML5/HTML5PlatformEditor/Private/HTML5PlatformEditorModule.cpp index d7f62de99b53..d28de3d8835d 100644 --- a/Engine/Source/Developer/HTML5/HTML5PlatformEditor/Private/HTML5PlatformEditorModule.cpp +++ b/Engine/Source/Developer/HTML5/HTML5PlatformEditor/Private/HTML5PlatformEditorModule.cpp @@ -7,6 +7,7 @@ #include "Modules/ModuleManager.h" #include "PropertyEditorModule.h" #include "HTML5TargetSettings.h" +#include "HTML5TargetSettingsCustomization.h" #include "ISettingsModule.h" #include "HTML5SDKSettings.h" @@ -43,6 +44,13 @@ class FHTML5PlatformEditorModule // register settings static FName PropertyEditor("PropertyEditor"); FPropertyEditorModule& PropertyModule = FModuleManager::GetModuleChecked(PropertyEditor); + PropertyModule.RegisterCustomClassLayout( + "HTML5TargetSettings", + FOnGetDetailCustomizationInstance::CreateStatic(&FHTML5TargetSettingsCustomization::MakeInstance) + ); + + PropertyModule.NotifyCustomizationModuleChanged(); + ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings"); if (SettingsModule != nullptr) diff --git a/Engine/Source/Developer/HTML5/HTML5PlatformEditor/Private/HTML5TargetSettingsCustomization.cpp b/Engine/Source/Developer/HTML5/HTML5PlatformEditor/Private/HTML5TargetSettingsCustomization.cpp new file mode 100644 index 000000000000..ef6e3cb2f9aa --- /dev/null +++ b/Engine/Source/Developer/HTML5/HTML5PlatformEditor/Private/HTML5TargetSettingsCustomization.cpp @@ -0,0 +1,53 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "HTML5TargetSettingsCustomization.h" +#include "HTML5TargetSettings.h" +#include "PropertyHandle.h" +#include "IDetailPropertyRow.h" +#include "DetailLayoutBuilder.h" +#include "DetailCategoryBuilder.h" +#include "Misc/EngineBuildSettings.h" + +#define LOCTEXT_NAMESPACE "HTML5TargetSettings" +DEFINE_LOG_CATEGORY_STATIC(LogIOSTargetSettings, Log, All); + +////////////////////////////////////////////////////////////////////////// +// FHTML5TargetSettingsCustomization +namespace FHTML5TargetSettingsCustomizationConstants +{ + const FText DisabledTip = LOCTEXT("GitHubSourceRequiredToolTip", "This requires GitHub source."); +} + + +TSharedRef FHTML5TargetSettingsCustomization::MakeInstance() +{ + return MakeShareable(new FHTML5TargetSettingsCustomization); +} + +FHTML5TargetSettingsCustomization::FHTML5TargetSettingsCustomization() +{ +} + +FHTML5TargetSettingsCustomization::~FHTML5TargetSettingsCustomization() +{ +} + +void FHTML5TargetSettingsCustomization::CustomizeDetails(IDetailLayoutBuilder& DetailLayout) +{ + IDetailCategoryBuilder& EmscriptenCategory = DetailLayout.EditCategory(TEXT("Emscripten")); + +#define SETUP_SOURCEONLY_PROP(PropName, Category) \ + { \ + TSharedRef PropertyHandle = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UHTML5TargetSettings, PropName)); \ + Category.AddProperty(PropertyHandle) \ + .IsEnabled(FEngineBuildSettings::IsSourceDistribution()) \ + .ToolTip(FEngineBuildSettings::IsSourceDistribution() ? PropertyHandle->GetToolTipText() : FHTML5TargetSettingsCustomizationConstants::DisabledTip); \ + } + + SETUP_SOURCEONLY_PROP(TargetAsmjs, EmscriptenCategory); + SETUP_SOURCEONLY_PROP(EnableIndexedDB, EmscriptenCategory); +} + +////////////////////////////////////////////////////////////////////////// + +#undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Developer/HTML5/HTML5PlatformEditor/Private/HTML5TargetSettingsCustomization.h b/Engine/Source/Developer/HTML5/HTML5PlatformEditor/Private/HTML5TargetSettingsCustomization.h new file mode 100644 index 000000000000..f593845fc4af --- /dev/null +++ b/Engine/Source/Developer/HTML5/HTML5PlatformEditor/Private/HTML5TargetSettingsCustomization.h @@ -0,0 +1,33 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "SlateFwd.h" +#include "Misc/Attribute.h" +#include "Input/Reply.h" +#include "IDetailCustomization.h" + +class IPropertyHandle; +class SEditableTextBox; +class SErrorText; + + +////////////////////////////////////////////////////////////////////////// +// FHTML5TargetSettingsCustomization + +class FHTML5TargetSettingsCustomization : public IDetailCustomization +{ +public: + ~FHTML5TargetSettingsCustomization(); + + // Makes a new instance of this detail layout class for a specific detail view requesting it + static TSharedRef MakeInstance(); + + // IDetailCustomization interface + virtual void CustomizeDetails(IDetailLayoutBuilder& DetailLayout) override; + // End of IDetailCustomization interface + +private: + FHTML5TargetSettingsCustomization(); +}; diff --git a/Engine/Source/Developer/HierarchicalLODUtilities/Private/HierarchicalLODUtilities.cpp b/Engine/Source/Developer/HierarchicalLODUtilities/Private/HierarchicalLODUtilities.cpp index b412ecdf423a..592903852a98 100644 --- a/Engine/Source/Developer/HierarchicalLODUtilities/Private/HierarchicalLODUtilities.cpp +++ b/Engine/Source/Developer/HierarchicalLODUtilities/Private/HierarchicalLODUtilities.cpp @@ -245,7 +245,7 @@ bool FHierarchicalLODUtilities::BuildStaticMeshForLODActor(ALODActor* LODActor, static const FMatrix ProjectionMatrix = FPerspectiveMatrix(FOVRad, 1920, 1080, 0.01f); FBoxSphereBounds Bounds = LODActor->GetStaticMeshComponent()->CalcBounds(FTransform()); LODActor->LODDrawDistance = CalculateDrawDistanceFromScreenSize(Bounds.SphereRadius, LODSetup.TransitionScreenSize, ProjectionMatrix); - LODActor->StaticMeshComponent->MinDrawDistance = LODActor->LODDrawDistance; + LODActor->GetStaticMeshComponent()->MinDrawDistance = LODActor->LODDrawDistance; LODActor->UpdateSubActorLODParents(); // Freshly build so mark not dirty @@ -410,8 +410,7 @@ ALODActor* FHierarchicalLODUtilities::CreateNewClusterActor(UWorld* InWorld, con } // Spawn and setup actor - ALODActor* NewActor = nullptr; - NewActor = InWorld->SpawnActor(ALODActor::StaticClass(), FTransform()); + ALODActor* NewActor = InWorld->SpawnActor(ALODActor::StaticClass(), FTransform()); NewActor->LODLevel = InLODLevel + 1; NewActor->LODDrawDistance = 0.0f; NewActor->SetStaticMesh(nullptr); @@ -505,15 +504,7 @@ const bool FHierarchicalLODUtilities::AddActorToCluster(AActor* InActor, ALODAct InParentActor->AddSubActor(InActor); #if WITH_EDITOR - if (bActorWasClustered) - { - GEditor->BroadcastHLODActorAdded(InActor, InParentActor); - } - else - { - GEditor->BroadcastHLODActorAdded(InActor, InParentActor); - } - + GEditor->BroadcastHLODActorAdded(InActor, InParentActor); #endif // WITH_EDITOR return true; diff --git a/Engine/Source/Developer/HotReload/Private/HotReload.cpp b/Engine/Source/Developer/HotReload/Private/HotReload.cpp index 599709189a1b..1cd34ec49faa 100644 --- a/Engine/Source/Developer/HotReload/Private/HotReload.cpp +++ b/Engine/Source/Developer/HotReload/Private/HotReload.cpp @@ -1027,12 +1027,11 @@ void FHotReloadModule::ReplaceReferencesToReconstructedCDOs() { UObject* Obj = ObjRef; - if (Obj && Obj != PotentialReferencer && ReconstructedCDOsMap.Contains(Obj)) + if (Obj && Obj != PotentialReferencer) { - UProperty* SerializedProp = GetSerializedProperty(); - if (SerializedProp && SerializedProp->IsA()) + if (UObject* const* FoundObj = ReconstructedCDOsMap.Find(Obj)) { - ObjRef = ReconstructedCDOsMap[Obj]; + ObjRef = *FoundObj; } } @@ -1673,21 +1672,25 @@ bool FHotReloadModule::StartCompilingModuleDLLs(const FString& GameName, const T // Pass a module file suffix to UBT if we have one FString ModuleArg; - for( const FModuleToRecompile& Module : ModuleNames ) + if (ModuleNames.Num()) { - if( !Module.ModuleFileSuffix.IsEmpty() ) + Ar.Logf(TEXT("Candidate modules for hot reload:")); + for( const FModuleToRecompile& Module : ModuleNames ) { - ModuleArg += FString::Printf( TEXT( " -ModuleWithSuffix %s %s" ), *Module.ModuleName, *Module.ModuleFileSuffix ); - } - else - { - ModuleArg += FString::Printf( TEXT( " -Module %s" ), *Module.ModuleName ); - } - Ar.Logf( TEXT( "Recompiling %s..." ), *Module.ModuleName ); + if( !Module.ModuleFileSuffix.IsEmpty() ) + { + ModuleArg += FString::Printf( TEXT( " -ModuleWithSuffix %s %s" ), *Module.ModuleName, *Module.ModuleFileSuffix ); + } + else + { + ModuleArg += FString::Printf( TEXT( " -Module %s" ), *Module.ModuleName ); + } + Ar.Logf( TEXT( " %s" ), *Module.ModuleName ); - // prepare the compile info in the FModuleInfo so that it can be compared after compiling - FName ModuleFName(*Module.ModuleName); - UpdateModuleCompileData(ModuleFName); + // prepare the compile info in the FModuleInfo so that it can be compared after compiling + FName ModuleFName(*Module.ModuleName); + UpdateModuleCompileData(ModuleFName); + } } FString ExtraArg; diff --git a/Engine/Source/Developer/LauncherServices/Private/Launcher/LauncherUATTask.h b/Engine/Source/Developer/LauncherServices/Private/Launcher/LauncherUATTask.h index 6e98439b297b..6165198dea00 100644 --- a/Engine/Source/Developer/LauncherServices/Private/Launcher/LauncherUATTask.h +++ b/Engine/Source/Developer/LauncherServices/Private/Launcher/LauncherUATTask.h @@ -63,7 +63,12 @@ protected: // we expect to pass -nocompile to UAT here as we generally expect UAT to be fully compiled. Besides, installed builds don't even have the source to compile UAT scripts. // Only allow UAT to compile scripts dynamically if we pass -development or we have the IsBuildingUAT property set, the latter of which should not allow itself to be set in installed situations. - UATCommandLine += FParse::Param( FCommandLine::Get(), TEXT("development") ) || ChainState.Profile->IsBuildingUAT() ? TEXT("") : TEXT(" -nocompile"); +#if PLATFORM_WINDOWS + bool bAllowCompile = !FPlatformMisc::IsDebuggerPresent(); +#else + bool bAllowCompile = true; +#endif + UATCommandLine += (bAllowCompile && (FParse::Param( FCommandLine::Get(), TEXT("development") ) || ChainState.Profile->IsBuildingUAT())) ? TEXT("") : TEXT(" -nocompile"); // we never want to build the editor when launching from the editor or running with an installed engine (which can't rebuild itself) UATCommandLine += GIsEditor || FApp::IsEngineInstalled() ? TEXT(" -nocompileeditor") : TEXT(""); UATCommandLine += FApp::IsEngineInstalled() ? TEXT(" -installed") : TEXT(""); diff --git a/Engine/Source/Developer/LauncherServices/Private/Launcher/LauncherWorker.h b/Engine/Source/Developer/LauncherServices/Private/Launcher/LauncherWorker.h index 3583ba6ca223..9c704b5a4090 100644 --- a/Engine/Source/Developer/LauncherServices/Private/Launcher/LauncherWorker.h +++ b/Engine/Source/Developer/LauncherServices/Private/Launcher/LauncherWorker.h @@ -118,7 +118,7 @@ private: ILauncherProfilePtr Profile; // Holds the worker's current status. - ELauncherWorkerStatus::Type Status; + volatile ELauncherWorkerStatus::Type Status; // Holds the first task in the task chain. TSharedPtr TaskChain; diff --git a/Engine/Source/Developer/LauncherServices/Private/Profiles/LauncherProfileManager.cpp b/Engine/Source/Developer/LauncherServices/Private/Profiles/LauncherProfileManager.cpp index e0b56f8f9568..0397bf10621f 100644 --- a/Engine/Source/Developer/LauncherServices/Private/Profiles/LauncherProfileManager.cpp +++ b/Engine/Source/Developer/LauncherServices/Private/Profiles/LauncherProfileManager.cpp @@ -239,8 +239,6 @@ ILauncherProfilePtr FLauncherProfileManager::LoadProfile( FArchive& Archive ) ILauncherProfilePtr FLauncherProfileManager::LoadJSONProfile(FString ProfileFile) { - FLauncherProfile* Profile = new FLauncherProfile(AsShared()); - FString FileContents; if (!FFileHelper::LoadFileToString(FileContents, *ProfileFile)) { @@ -254,6 +252,8 @@ ILauncherProfilePtr FLauncherProfileManager::LoadJSONProfile(FString ProfileFile return nullptr; } + FLauncherProfile* Profile = new FLauncherProfile(AsShared()); + if (Profile->Load(*(Object.Get()))) { ILauncherDeviceGroupPtr DeviceGroup = GetDeviceGroup(Profile->GetDeployedDeviceGroupId()); diff --git a/Engine/Source/Developer/Linux/LinuxPlatformEditor/LinuxPlatformEditor.Build.cs b/Engine/Source/Developer/Linux/LinuxPlatformEditor/LinuxPlatformEditor.Build.cs new file mode 100644 index 000000000000..a320359b82d4 --- /dev/null +++ b/Engine/Source/Developer/Linux/LinuxPlatformEditor/LinuxPlatformEditor.Build.cs @@ -0,0 +1,43 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +using UnrealBuildTool; + +public class LinuxPlatformEditor : ModuleRules +{ + public LinuxPlatformEditor(ReadOnlyTargetRules Target) : base(Target) + { + PrivateDependencyModuleNames.AddRange( + new string[] { + "Core", + "CoreUObject", + "InputCore", + "DesktopPlatform", + "Engine", + "MainFrame", + "Slate", + "SlateCore", + "EditorStyle", + "PropertyEditor", + "SharedSettingsWidgets", + "SourceControl", + "LinuxTargetPlatform", + "TargetPlatform", + "MaterialShaderQualitySettings", + "RenderCore", + } + ); + + PrivateIncludePathModuleNames.AddRange( + new string[] { + "GameProjectGeneration", + "Settings", + } + ); + + DynamicallyLoadedModuleNames.AddRange( + new string[] { + "GameProjectGeneration", + } + ); + } +} diff --git a/Engine/Source/Developer/Linux/LinuxPlatformEditor/Private/LinuxPlatformEditorModule.cpp b/Engine/Source/Developer/Linux/LinuxPlatformEditor/Private/LinuxPlatformEditorModule.cpp new file mode 100644 index 000000000000..372613f421ea --- /dev/null +++ b/Engine/Source/Developer/Linux/LinuxPlatformEditor/Private/LinuxPlatformEditorModule.cpp @@ -0,0 +1,51 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "CoreMinimal.h" +#include "ModuleInterface.h" +#include "ISettingsModule.h" +#include "ModuleManager.h" +#include "LinuxTargetSettings.h" +#include "UObject/WeakObjectPtr.h" +#include "UObject/Class.h" + +#define LOCTEXT_NAMESPACE "LinuxPlatformEditorModule" + + +/** + * Module for Linux project settings + */ +class FLinuxPlatformEditorModule + : public IModuleInterface +{ + // IModuleInterface interface + + virtual void StartupModule() override + { + // register settings + ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings"); + + if (SettingsModule != nullptr) + { + SettingsModule->RegisterSettings("Project", "Platforms", "Linux", + LOCTEXT("TargetSettingsName", "Linux"), + LOCTEXT("TargetSettingsDescription", "Settings for Linux target platform"), + GetMutableDefault() + ); + } + } + + virtual void ShutdownModule() override + { + ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings"); + + if (SettingsModule != nullptr) + { + SettingsModule->UnregisterSettings("Project", "Platforms", "Linux"); + } + } +}; + + +IMPLEMENT_MODULE(FLinuxPlatformEditorModule, LinuxPlatformEditor); + +#undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Developer/Localization/Private/PortableObjectFormatDOM.cpp b/Engine/Source/Developer/Localization/Private/PortableObjectFormatDOM.cpp index e4aa20a5ae68..5d7678732554 100644 --- a/Engine/Source/Developer/Localization/Private/PortableObjectFormatDOM.cpp +++ b/Engine/Source/Developer/Localization/Private/PortableObjectFormatDOM.cpp @@ -6,171 +6,192 @@ static const TCHAR* NewLineDelimiter = TEXT("\n"); -/* Default culture plural rules. Culture names are in the following format: Language_Country@Variant - See references: http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html +/** + * Default culture plural rules. Culture names are in the following format: Language_Country@Variant + * See references: http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html http://docs.translatehouse.org/projects/localization-guide/en/latest/l10n/pluralforms.html */ -static const TMap< FString, FString > POCulturePluralForms = TMapBuilder< FString, FString >() - .Add( TEXT( "ach" ) , TEXT( "nplurals=2; plural=(n > 1);" ) ) - .Add( TEXT( "af" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "ak" ) , TEXT( "nplurals=2; plural=(n > 1);" ) ) - .Add( TEXT( "aln" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "am" ) , TEXT( "nplurals=2; plural=(n > 1);" ) ) - .Add( TEXT( "am_ET"), TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "an" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "ar" ) , TEXT( "nplurals=6; plural=(n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5);" ) ) - .Add( TEXT( "ar_SA"), TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "arn" ) , TEXT( "nplurals=2; plural=(n > 1);" ) ) - .Add( TEXT( "as" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "ast" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "ay" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "az" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "bal" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "be" ) , TEXT( "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" ) ) - .Add( TEXT( "bg" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "bn" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "bo" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "br" ) , TEXT( "nplurals=2; plural=(n > 1);" ) ) - .Add( TEXT( "brx" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "bs" ) , TEXT( "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" ) ) - .Add( TEXT( "ca" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "cgg" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "crh" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "cs" ) , TEXT( "nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;" ) ) - .Add( TEXT( "csb" ) , TEXT( "nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;" ) ) - .Add( TEXT( "cy" ) , TEXT( "nplurals=4; plural=(n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3;" ) ) - .Add( TEXT( "da" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "de" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "doi" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "dz" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "el" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "en" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "eo" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "es" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "es_ar"), TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "et" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "eu" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "fa" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "fi" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "fil" ) , TEXT( "nplurals=2; plural=(n > 1);" ) ) - .Add( TEXT( "fo" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "fr" ) , TEXT( "nplurals=2; plural=(n > 1);" ) ) - .Add( TEXT( "frp" ) , TEXT( "nplurals=2; plural=(n > 1);" ) ) - .Add( TEXT( "fur" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "fy" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "ga" ) , TEXT( "nplurals=5; plural=(n==1 ? 0 : n==2 ? 1 : n<7 ? 2 : n<11 ? 3 : 4);" ) ) - .Add( TEXT( "gd" ) , TEXT( "nplurals=3; plural=(n < 2 ? 0 : n == 2 ? 1 : 2);" ) ) - .Add( TEXT( "gl" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "gu" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "gun" ) , TEXT( "nplurals=2; plural=(n > 1);" ) ) - .Add( TEXT( "ha" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "he" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "hi" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "hne" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "hr" ) , TEXT( "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" ) ) - .Add( TEXT( "hsb" ) , TEXT( "nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);" ) ) - .Add( TEXT( "ht" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "hu" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "hy" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "ia" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "id" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "ig" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "ilo" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "is" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "it" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "ja" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "jv" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "ka" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "kk" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "km" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "kn" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "ko" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "ks" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "ku" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "kw" ) , TEXT( "nplurals=4; plural=(n==1) ? 0 : (n==2) ? 1 : (n == 3) ? 2 : 3;" ) ) - .Add( TEXT( "ky" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "la" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "lb" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "li" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "ln" ) , TEXT( "nplurals=2; plural=(n > 1);" ) ) - .Add( TEXT( "lo" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "lt" ) , TEXT( "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);" ) ) - .Add( TEXT( "lv" ) , TEXT( "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);" ) ) - .Add( TEXT( "mai" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "mg" ) , TEXT( "nplurals=2; plural=(n > 1);" ) ) - .Add( TEXT( "mi" ) , TEXT( "nplurals=2; plural=(n > 1);" ) ) - .Add( TEXT( "mk" ) , TEXT( "nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;" ) ) - .Add( TEXT( "ml" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "mn" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "mr" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "ms" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "mt" ) , TEXT( "nplurals=4; plural=(n==1 ? 0 : n==0 || ( n%100>1 && n%100<11) ? 1 : (n%100>10 && n%100<20 ) ? 2 : 3);" ) ) - .Add( TEXT( "my" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "nah" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "nap" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "nb" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "nds" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "ne" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "nl" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "nn" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "no" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "nr" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "nso" ) , TEXT( "nplurals=2; plural=(n > 1);" ) ) - .Add( TEXT( "oc" ) , TEXT( "nplurals=2; plural=(n > 1);" ) ) - .Add( TEXT( "or" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "pa" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "pap" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "pl" ) , TEXT( "nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" ) ) - .Add( TEXT( "pms" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "ps" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "pt" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "pt_BR"), TEXT( "nplurals=2; plural=(n > 1);" ) ) - .Add( TEXT( "rm" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "ro" ) , TEXT( "nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));" ) ) - .Add( TEXT( "ru" ) , TEXT( "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" ) ) - .Add( TEXT( "rw" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "sc" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "sco" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "se" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "si" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "sk" ) , TEXT( "nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;" ) ) - .Add( TEXT( "sl" ) , TEXT( "nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);" ) ) - .Add( TEXT( "sm" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "sn" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "so" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "son" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "sq" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "sr" ) , TEXT( "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" ) ) - .Add( TEXT( "st" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "su" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "sv" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "sw" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "ta" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "te" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "tg" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "th" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "ti" ) , TEXT( "nplurals=2; plural=(n > 1);" ) ) - .Add( TEXT( "tk" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "tl" ) , TEXT( "nplurals=2; plural=(n > 1);" ) ) - .Add( TEXT( "tlh" ) , TEXT( "nplurals=2; plural=(n > 1);" ) ) - .Add( TEXT( "to" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "tr" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "tt" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "udm" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "ug" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "uk" ) , TEXT( "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" ) ) - .Add( TEXT( "ur" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "uz" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "ve" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "vi" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "vls" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "wa" ) , TEXT( "nplurals=2; plural=(n > 1);" ) ) - .Add( TEXT( "wo" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "xh" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "yi" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "yo" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ) - .Add( TEXT( "zh" ) , TEXT( "nplurals=1; plural=0;" ) ) - .Add( TEXT( "zu" ) , TEXT( "nplurals=2; plural=(n != 1);" ) ); +const TCHAR* GetPluralForm(const TCHAR* InCulture) +{ + struct FPOCulturePluralForm + { + const TCHAR* CultureName; + const TCHAR* PluralForm; + }; + + static const FPOCulturePluralForm POCulturePluralForms[] = { + { TEXT("ach"), TEXT("nplurals=2; plural=(n > 1);") }, + { TEXT("af"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("ak"), TEXT("nplurals=2; plural=(n > 1);") }, + { TEXT("aln"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("am"), TEXT("nplurals=2; plural=(n > 1);") }, + { TEXT("am_ET"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("an"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("ar"), TEXT("nplurals=6; plural=(n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5);") }, + { TEXT("ar_SA"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("arn"), TEXT("nplurals=2; plural=(n > 1);") }, + { TEXT("as"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("ast"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("ay"), TEXT("nplurals=1; plural=0;") }, + { TEXT("az"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("bal"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("be"), TEXT("nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);") }, + { TEXT("bg"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("bn"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("bo"), TEXT("nplurals=1; plural=0;") }, + { TEXT("br"), TEXT("nplurals=2; plural=(n > 1);") }, + { TEXT("brx"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("bs"), TEXT("nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);") }, + { TEXT("ca"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("cgg"), TEXT("nplurals=1; plural=0;") }, + { TEXT("crh"), TEXT("nplurals=1; plural=0;") }, + { TEXT("cs"), TEXT("nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;") }, + { TEXT("csb"), TEXT("nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;") }, + { TEXT("cy"), TEXT("nplurals=4; plural=(n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3;") }, + { TEXT("da"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("de"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("doi"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("dz"), TEXT("nplurals=1; plural=0;") }, + { TEXT("el"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("en"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("eo"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("es"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("es_ar"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("et"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("eu"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("fa"), TEXT("nplurals=1; plural=0;") }, + { TEXT("fi"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("fil"), TEXT("nplurals=2; plural=(n > 1);") }, + { TEXT("fo"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("fr"), TEXT("nplurals=2; plural=(n > 1);") }, + { TEXT("frp"), TEXT("nplurals=2; plural=(n > 1);") }, + { TEXT("fur"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("fy"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("ga"), TEXT("nplurals=5; plural=(n==1 ? 0 : n==2 ? 1 : n<7 ? 2 : n<11 ? 3 : 4);") }, + { TEXT("gd"), TEXT("nplurals=3; plural=(n < 2 ? 0 : n == 2 ? 1 : 2);") }, + { TEXT("gl"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("gu"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("gun"), TEXT("nplurals=2; plural=(n > 1);") }, + { TEXT("ha"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("he"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("hi"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("hne"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("hr"), TEXT("nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);") }, + { TEXT("hsb"), TEXT("nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);") }, + { TEXT("ht"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("hu"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("hy"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("ia"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("id"), TEXT("nplurals=1; plural=0;") }, + { TEXT("ig"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("ilo"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("is"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("it"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("ja"), TEXT("nplurals=1; plural=0;") }, + { TEXT("jv"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("ka"), TEXT("nplurals=1; plural=0;") }, + { TEXT("kk"), TEXT("nplurals=1; plural=0;") }, + { TEXT("km"), TEXT("nplurals=1; plural=0;") }, + { TEXT("kn"), TEXT("nplurals=1; plural=0;") }, + { TEXT("ko"), TEXT("nplurals=1; plural=0;") }, + { TEXT("ks"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("ku"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("kw"), TEXT("nplurals=4; plural=(n==1) ? 0 : (n==2) ? 1 : (n == 3) ? 2 : 3;") }, + { TEXT("ky"), TEXT("nplurals=1; plural=0;") }, + { TEXT("la"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("lb"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("li"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("ln"), TEXT("nplurals=2; plural=(n > 1);") }, + { TEXT("lo"), TEXT("nplurals=1; plural=0;") }, + { TEXT("lt"), TEXT("nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);") }, + { TEXT("lv"), TEXT("nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);") }, + { TEXT("mai"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("mg"), TEXT("nplurals=2; plural=(n > 1);") }, + { TEXT("mi"), TEXT("nplurals=2; plural=(n > 1);") }, + { TEXT("mk"), TEXT("nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;") }, + { TEXT("ml"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("mn"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("mr"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("ms"), TEXT("nplurals=1; plural=0;") }, + { TEXT("mt"), TEXT("nplurals=4; plural=(n==1 ? 0 : n==0 || ( n%100>1 && n%100<11) ? 1 : (n%100>10 && n%100<20 ) ? 2 : 3);") }, + { TEXT("my"), TEXT("nplurals=1; plural=0;") }, + { TEXT("nah"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("nap"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("nb"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("nds"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("ne"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("nl"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("nn"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("no"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("nr"), TEXT("nplurals=1; plural=0;") }, + { TEXT("nso"), TEXT("nplurals=2; plural=(n > 1);") }, + { TEXT("oc"), TEXT("nplurals=2; plural=(n > 1);") }, + { TEXT("or"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("pa"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("pap"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("pl"), TEXT("nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);") }, + { TEXT("pms"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("ps"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("pt"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("pt_BR"), TEXT("nplurals=2; plural=(n > 1);") }, + { TEXT("rm"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("ro"), TEXT("nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));") }, + { TEXT("ru"), TEXT("nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);") }, + { TEXT("rw"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("sc"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("sco"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("se"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("si"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("sk"), TEXT("nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;") }, + { TEXT("sl"), TEXT("nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);") }, + { TEXT("sm"), TEXT("nplurals=1; plural=0;") }, + { TEXT("sn"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("so"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("son"), TEXT("nplurals=1; plural=0;") }, + { TEXT("sq"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("sr"), TEXT("nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);") }, + { TEXT("st"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("su"), TEXT("nplurals=1; plural=0;") }, + { TEXT("sv"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("sw"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("ta"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("te"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("tg"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("th"), TEXT("nplurals=1; plural=0;") }, + { TEXT("ti"), TEXT("nplurals=2; plural=(n > 1);") }, + { TEXT("tk"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("tl"), TEXT("nplurals=2; plural=(n > 1);") }, + { TEXT("tlh"), TEXT("nplurals=2; plural=(n > 1);") }, + { TEXT("to"), TEXT("nplurals=1; plural=0;") }, + { TEXT("tr"), TEXT("nplurals=1; plural=0;") }, + { TEXT("tt"), TEXT("nplurals=1; plural=0;") }, + { TEXT("udm"), TEXT("nplurals=1; plural=0;") }, + { TEXT("ug"), TEXT("nplurals=1; plural=0;") }, + { TEXT("uk"), TEXT("nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);") }, + { TEXT("ur"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("uz"), TEXT("nplurals=1; plural=0;") }, + { TEXT("ve"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("vi"), TEXT("nplurals=1; plural=0;") }, + { TEXT("vls"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("wa"), TEXT("nplurals=2; plural=(n > 1);") }, + { TEXT("wo"), TEXT("nplurals=1; plural=0;") }, + { TEXT("xh"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("yi"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("yo"), TEXT("nplurals=2; plural=(n != 1);") }, + { TEXT("zh"), TEXT("nplurals=1; plural=0;") }, + { TEXT("zu"), TEXT("nplurals=2; plural=(n != 1);") }, + }; + + for (const FPOCulturePluralForm& POCulturePluralForm : POCulturePluralForms) + { + if (FCString::Stricmp(POCulturePluralForm.CultureName, InCulture) == 0) + { + return POCulturePluralForm.PluralForm; + } + } + + return nullptr; +} bool FindDelimitedString(const FString& InStr, const FString& LeftDelim, const FString& RightDelim, FString& Result) { @@ -285,28 +306,28 @@ FString FPortableObjectCulture::GetDefaultPluralForms() const return Result; } - if( auto* LanguageCodePair = POCulturePluralForms.Find( GetLanguageCode() ) ) + if( const TCHAR* LanguageCodePair = GetPluralForm( *GetLanguageCode() ) ) { - Result = *LanguageCodePair; + Result = LanguageCodePair; } - else if( auto* LangCountryVariantPair = POCulturePluralForms.Find( Language() + TEXT("_") + Country() + TEXT("@") + Variant() )) + else if( const TCHAR* LangCountryVariantPair = GetPluralForm( *( Language() + TEXT("_") + Country() + TEXT("@") + Variant() ) ) ) { - Result = *LangCountryVariantPair; + Result = LangCountryVariantPair; } - else if( auto* LangCountryPair = POCulturePluralForms.Find( Language() + TEXT("_") + Country() ) ) + else if( const TCHAR* LangCountryPair = GetPluralForm( *( Language() + TEXT("_") + Country() ) ) ) { - Result = *LangCountryPair; + Result = LangCountryPair; } - else if( auto* LangPair = POCulturePluralForms.Find( Language() ) ) + else if( const TCHAR* LangPair = GetPluralForm( *Language() ) ) { - Result = *LangPair; + Result = LangPair; } else { - auto* Fallback = POCulturePluralForms.Find( TEXT("en") ); + const TCHAR* Fallback = GetPluralForm( TEXT("en") ); if( Fallback ) { - Result = *Fallback; + Result = Fallback; } else { @@ -978,4 +999,4 @@ FString FPortableObjectEntry::ToString() const } } return Result; -} +} \ No newline at end of file diff --git a/Engine/Source/Developer/LogVisualizer/Private/VisualLoggerHUD.cpp b/Engine/Source/Developer/LogVisualizer/Private/VisualLoggerHUD.cpp index 0b54cb540c7b..dff4fcea199b 100644 --- a/Engine/Source/Developer/LogVisualizer/Private/VisualLoggerHUD.cpp +++ b/Engine/Source/Developer/LogVisualizer/Private/VisualLoggerHUD.cpp @@ -46,7 +46,7 @@ void AVisualLoggerHUD::PostRender() FVector const CamLoc = DebugCamController->PlayerCameraManager->GetCameraLocation(); FRotator const CamRot = DebugCamController->PlayerCameraManager->GetCameraRotation(); - FCollisionQueryParams TraceParams(NAME_None, true, this); + FCollisionQueryParams TraceParams(NAME_None, FCollisionQueryParams::GetUnknownStatId(), true, this); FHitResult Hit; bool bHit = GetWorld()->LineTraceSingleByChannel(Hit, CamLoc, CamRot.Vector() * 100000.f + CamLoc, ECC_Pawn, TraceParams); if( bHit ) diff --git a/Engine/Source/Developer/Mac/MacPlatformEditor/MacPlatformEditor.Build.cs b/Engine/Source/Developer/Mac/MacPlatformEditor/MacPlatformEditor.Build.cs new file mode 100644 index 000000000000..bdbd37439787 --- /dev/null +++ b/Engine/Source/Developer/Mac/MacPlatformEditor/MacPlatformEditor.Build.cs @@ -0,0 +1,43 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +using UnrealBuildTool; + +public class MacPlatformEditor : ModuleRules +{ + public MacPlatformEditor(ReadOnlyTargetRules Target) : base(Target) + { + PrivateDependencyModuleNames.AddRange( + new string[] { + "Core", + "CoreUObject", + "InputCore", + "DesktopPlatform", + "Engine", + "MainFrame", + "Slate", + "SlateCore", + "EditorStyle", + "PropertyEditor", + "SharedSettingsWidgets", + "SourceControl", + "MacTargetPlatform", + "TargetPlatform", + "MaterialShaderQualitySettings", + "RenderCore", + } + ); + + PrivateIncludePathModuleNames.AddRange( + new string[] { + "GameProjectGeneration", + "Settings", + } + ); + + DynamicallyLoadedModuleNames.AddRange( + new string[] { + "GameProjectGeneration", + } + ); + } +} diff --git a/Engine/Source/Developer/Mac/MacPlatformEditor/Private/MacPlatformEditorModule.cpp b/Engine/Source/Developer/Mac/MacPlatformEditor/Private/MacPlatformEditorModule.cpp new file mode 100644 index 000000000000..6aae198f7699 --- /dev/null +++ b/Engine/Source/Developer/Mac/MacPlatformEditor/Private/MacPlatformEditorModule.cpp @@ -0,0 +1,51 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "CoreMinimal.h" +#include "ModuleInterface.h" +#include "ISettingsModule.h" +#include "ModuleManager.h" +#include "MacTargetSettings.h" +#include "UObject/WeakObjectPtr.h" +#include "UObject/Class.h" + +#define LOCTEXT_NAMESPACE "MacPlatformEditorModule" + + +/** + * Module for Mac project settings + */ +class FMacPlatformEditorModule + : public IModuleInterface +{ + // IModuleInterface interface + + virtual void StartupModule() override + { + // register settings + ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings"); + + if (SettingsModule != nullptr) + { + SettingsModule->RegisterSettings("Project", "Platforms", "Mac", + LOCTEXT("TargetSettingsName", "Mac"), + LOCTEXT("TargetSettingsDescription", "Settings for Mac target platform"), + GetMutableDefault() + ); + } + } + + virtual void ShutdownModule() override + { + ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings"); + + if (SettingsModule != nullptr) + { + SettingsModule->UnregisterSettings("Project", "Platforms", "Mac"); + } + } +}; + + +IMPLEMENT_MODULE(FMacPlatformEditorModule, MacPlatformEditor); + +#undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Developer/Mac/MacTargetPlatform/Classes/MacTargetSettings.h b/Engine/Source/Developer/Mac/MacTargetPlatform/Classes/MacTargetSettings.h index 0b33ab25772f..1593cb6f992c 100644 --- a/Engine/Source/Developer/Mac/MacTargetPlatform/Classes/MacTargetSettings.h +++ b/Engine/Source/Developer/Mac/MacTargetPlatform/Classes/MacTargetSettings.h @@ -44,4 +44,24 @@ public: */ UPROPERTY(EditAnywhere, config, Category=Rendering, meta = (DisplayName = "Max. Metal Shader Standard To Target", ConfigRestartRequired = true)) uint8 MaxShaderLanguageVersion; + + /** Sample rate to run the audio mixer with. */ + UPROPERTY(config, EditAnywhere, Category = "Audio", Meta = (DisplayName = "Audio Mixer Sample Rate")) + int32 AudioSampleRate; + + /** The amount of audio to compute each callback block. Lower values decrease latency but may increase CPU cost. */ + UPROPERTY(config, EditAnywhere, Category = "Audio", meta = (ClampMin = "512", ClampMax = "4096", DisplayName = "Callback Buffer Size")) + int32 AudioCallbackBufferFrameSize; + + /** The number of buffers to keep enqueued. More buffers increases latency, but can compensate for variable compute availability in audio callbacks on some platforms. */ + UPROPERTY(config, EditAnywhere, Category = "Audio", meta = (ClampMin = "1", UIMin = "1", DisplayName = "Number of Buffers To Enqueue")) + int32 AudioNumBuffersToEnqueue; + + /** The max number of channels (voices) to limit for this platform. The max channels used will be the minimum of this value and the global audio quality settings. A value of 0 will not apply a platform channel count max. */ + UPROPERTY(config, EditAnywhere, Category = "Audio", meta = (ClampMin = "0", UIMin = "0", DisplayName = "Max Channels")) + int32 AudioMaxChannels; + + /** The number of workers to use to compute source audio. Will only use up to the max number of sources. Will evenly divide sources to each source worker. */ + UPROPERTY(config, EditAnywhere, Category = "Audio", meta = (ClampMin = "0", UIMin = "0", DisplayName = "Number of Source Workers")) + int32 AudioNumSourceWorkers; }; diff --git a/Engine/Source/Developer/Mac/MacTargetPlatform/Private/MacTargetPlatformModule.cpp b/Engine/Source/Developer/Mac/MacTargetPlatform/Private/MacTargetPlatformModule.cpp index d88934dd8437..e9d7aa80861b 100644 --- a/Engine/Source/Developer/Mac/MacTargetPlatform/Private/MacTargetPlatformModule.cpp +++ b/Engine/Source/Developer/Mac/MacTargetPlatform/Private/MacTargetPlatformModule.cpp @@ -6,7 +6,6 @@ #include "ISettingsModule.h" #include "Interfaces/ITargetPlatformModule.h" #include "Modules/ModuleManager.h" -#include "MacTargetSettings.h" #include "UObject/Package.h" #include "UObject/WeakObjectPtr.h" @@ -59,55 +58,13 @@ public: virtual void StartupModule() override { - TargetSettings = NewObject(GetTransientPackage(), "MacTargetSettings", RF_Standalone); - - // We need to manually load the config properties here, as this module is loaded before the UObject system is setup to do this - GConfig->GetArray(TEXT("/Script/MacTargetPlatform.MacTargetSettings"), TEXT("TargetedRHIs"), TargetSettings->TargetedRHIs, GEngineIni); - int32 Value = 1; - GConfig->GetInt(TEXT("/Script/MacTargetPlatform.MacTargetSettings"), TEXT("MaxShaderLanguageVersion"), Value, GEngineIni); - TargetSettings->MaxShaderLanguageVersion = FMath::Max(Value, 1); - - TargetSettings->AddToRoot(); - - ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings"); - - if (SettingsModule != nullptr) - { - SettingsModule->RegisterSettings("Project", "Platforms", "Mac", - LOCTEXT("TargetSettingsName", "Mac"), - LOCTEXT("TargetSettingsDescription", "Settings and resources for Mac platform"), - TargetSettings - ); - } } virtual void ShutdownModule() override { - ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings"); - - if (SettingsModule != nullptr) - { - SettingsModule->UnregisterSettings("Project", "Platforms", "Mac"); - } - - if (!GExitPurge) - { - // If we're in exit purge, this object has already been destroyed - TargetSettings->RemoveFromRoot(); - } - else - { - TargetSettings = NULL; - } } // End IModuleInterface interface - - -private: - - // Holds the target settings. - UMacTargetSettings* TargetSettings; }; diff --git a/Engine/Source/Developer/MaterialUtilities/Private/MaterialUtilities.cpp b/Engine/Source/Developer/MaterialUtilities/Private/MaterialUtilities.cpp index 89d084d6b054..26d76dca1fa5 100644 --- a/Engine/Source/Developer/MaterialUtilities/Private/MaterialUtilities.cpp +++ b/Engine/Source/Developer/MaterialUtilities/Private/MaterialUtilities.cpp @@ -1580,15 +1580,12 @@ void FMaterialUtilities::RemapUniqueMaterialIndices(const TArray& TArray& NewMeshMaterialMap = OutMaterialMap.Add(FMeshIdAndLOD(MeshIndex, LODIndex)); UStaticMesh* StaticMesh = InMeshData[MeshIndex].SourceStaticMesh; - if (!OutMeshShouldBakeVertexData[MeshIndex]) + if (!OutMeshShouldBakeVertexData[MeshIndex]) { // No vertex data needed - could merge materials with other meshes. - if (!OutMeshShouldBakeVertexData[MeshIndex]) - { - // Set to 'nullptr' if don't need to bake vertex data to be able to merge materials with any meshes - // which don't require vertex data baking too. - StaticMesh = nullptr; - } + // Set to 'nullptr' if don't need to bake vertex data to be able to merge materials with any meshes + // which don't require vertex data baking too. + StaticMesh = nullptr; for (int32 LocalMaterialIndex = 0; LocalMaterialIndex < MeshMaterialMap.Num(); LocalMaterialIndex++) { diff --git a/Engine/Source/Developer/Merge/Private/MergeUtils.cpp b/Engine/Source/Developer/Merge/Private/MergeUtils.cpp index af81876ff3df..962964aa8b05 100644 --- a/Engine/Source/Developer/Merge/Private/MergeUtils.cpp +++ b/Engine/Source/Developer/Merge/Private/MergeUtils.cpp @@ -42,11 +42,8 @@ UObject const* FMergeToolUtils::LoadRevision(const FString& AssetName, const ISo FString TempFileName; if (DesiredRevision.Get(TempFileName)) { - // Forcibly disable compile on load in case we are loading old blueprints that might try to update/compile - TGuardValue DisableCompileOnLoad(GForceDisableBlueprintCompileOnLoad, true); - // Try and load that package - UPackage* TempPackage = LoadPackage(NULL, *TempFileName, LOAD_None); + UPackage* TempPackage = LoadPackage(NULL, *TempFileName, LOAD_DisableCompileOnLoad); if (TempPackage != NULL) { // Grab the old asset from that old package diff --git a/Engine/Source/Developer/MeshSimplifier/Private/BinaryHeap.h b/Engine/Source/Developer/MeshSimplifier/Private/BinaryHeap.h deleted file mode 100644 index 15e7744e98e0..000000000000 --- a/Engine/Source/Developer/MeshSimplifier/Private/BinaryHeap.h +++ /dev/null @@ -1,363 +0,0 @@ -// Copyright (C) 2009 Nine Realms, Inc -// - -#pragma once - -#include "CoreMinimal.h" - -/*----------------------------------------------------------------------------- - Binary Heap, used to index another data structure. - - Also known as a priority queue. Smallest key at top. - KeyType must implement operator< ------------------------------------------------------------------------------*/ -template< typename KeyType > -class FBinaryHeap -{ -public: - FBinaryHeap(); - FBinaryHeap( uint32 InHeapSize, uint32 InIndexSize ); - ~FBinaryHeap(); - - void Clear(); - void Free(); - void Resize( uint32 NewHeapSize, uint32 NewIndexSize ); - - uint32 Num() const { return HeapNum; } - uint32 GetHeapSize() const { return HeapSize; } - uint32 GetIndexSize() const { return IndexSize; } - - bool IsPresent( uint32 Index ) const; - KeyType GetKey( uint32 Index ) const; - - uint32 Top() const; - void Pop(); - - void Add( KeyType Key, uint32 Index ); - void Update( KeyType Key, uint32 Index ); - void Remove( uint32 Index ); - -protected: - void ResizeHeap( uint32 NewHeapSize ); - void ResizeIndexes( uint32 NewIndexSize ); - - void UpHeap( uint32 HeapIndex ); - void DownHeap( uint32 HeapIndex ); - - uint32 HeapNum; - uint32 HeapSize; - uint32 IndexSize; - - uint32* Heap; - - KeyType* Keys; - uint32* HeapIndexes; -}; - -template< typename KeyType > -FORCEINLINE FBinaryHeap< KeyType >::FBinaryHeap() - : HeapNum(0) - , HeapSize(0) - , IndexSize(0) - , Heap( NULL ) - , Keys( NULL ) - , HeapIndexes( NULL ) -{} - -template< typename KeyType > -FORCEINLINE FBinaryHeap< KeyType >::FBinaryHeap( uint32 InHeapSize, uint32 InIndexSize ) - : HeapNum(0) - , HeapSize( InHeapSize ) - , IndexSize( InIndexSize ) -{ - Heap = new uint32[ HeapSize ]; - Keys = new KeyType[ IndexSize ]; - HeapIndexes = new uint32[ IndexSize ]; - - FMemory::Memset( HeapIndexes, 0xff, IndexSize * 4 ); -} - -template< typename KeyType > -FORCEINLINE FBinaryHeap< KeyType >::~FBinaryHeap() -{ - Free(); -} - -template< typename KeyType > -FORCEINLINE void FBinaryHeap< KeyType >::Clear() -{ - HeapNum = 0; - FMemory::Memset( HeapIndexes, 0xff, IndexSize * 4 ); -} - -template< typename KeyType > -FORCEINLINE void FBinaryHeap< KeyType >::Free() -{ - HeapNum = 0; - HeapSize = 0; - IndexSize = 0; - - delete[] Heap; - delete[] Keys; - delete[] HeapIndexes; - - Heap = NULL; - Keys = NULL; - HeapIndexes = NULL; -} - -template< typename KeyType > -void FBinaryHeap< KeyType >::ResizeHeap( uint32 NewHeapSize ) -{ - checkSlow( NewHeapSize != HeapSize ); - - if( NewHeapSize == 0 ) - { - HeapNum = 0; - HeapSize = 0; - - delete[] Heap; - Heap = NULL; - - return; - } - - uint32* NewHeap = new uint32[ NewHeapSize ]; - - if( HeapSize != 0 ) - { - FMemory::Memcpy( NewHeap, Heap, HeapSize * 4 ); - delete[] Heap; - } - - HeapNum = FMath::Min( HeapNum, NewHeapSize ); - HeapSize = NewHeapSize; - Heap = NewHeap; -} - -template< typename KeyType > -void FBinaryHeap< KeyType >::ResizeIndexes( uint32 NewIndexSize ) -{ - checkSlow( NewIndexSize != IndexSize ); - - if( NewIndexSize == 0 ) - { - IndexSize = 0; - - delete[] Keys; - delete[] HeapIndexes; - - Keys = NULL; - HeapIndexes = NULL; - - return; - } - - KeyType* NewKeys = new KeyType[ NewIndexSize ]; - uint32* NewHeapIndexes = new uint32[ NewIndexSize ]; - - if( IndexSize != 0 ) - { - check( NewIndexSize >= IndexSize ); - - for( uint32 i = 0; i < IndexSize; i++ ) - { - NewKeys[i] = Keys[i]; - NewHeapIndexes[i] = HeapIndexes[i]; - } - delete[] Keys; - delete[] HeapIndexes; - } - - for( uint32 i = IndexSize; i < NewIndexSize; i++ ) - { - NewHeapIndexes[i] = ~0u; - } - - IndexSize = NewIndexSize; - Keys = NewKeys; - HeapIndexes = NewHeapIndexes; -} - -template< typename KeyType > -FORCEINLINE void FBinaryHeap< KeyType >::Resize( uint32 NewHeapSize, uint32 NewIndexSize ) -{ - if( NewHeapSize != HeapSize ) - { - ResizeHeap( NewHeapSize ); - } - - if( NewIndexSize != IndexSize ) - { - ResizeIndexes( NewIndexSize ); - } -} - -template< typename KeyType > -FORCEINLINE bool FBinaryHeap< KeyType >::IsPresent( uint32 Index ) const -{ - checkSlow( Index < IndexSize ); - return HeapIndexes[ Index ] != ~0u; -} - -template< typename KeyType > -FORCEINLINE KeyType FBinaryHeap< KeyType >::GetKey( uint32 Index ) const -{ - checkSlow( IsPresent( Index ) ); - return Keys[ Index ]; -} - -template< typename KeyType > -FORCEINLINE uint32 FBinaryHeap< KeyType >::Top() const -{ - checkSlow( Heap ); - checkSlow( HeapNum > 0 ); - return Heap[0]; -} - -template< typename KeyType > -FORCEINLINE void FBinaryHeap< KeyType >::Pop() -{ - checkSlow( Heap ); - checkSlow( HeapNum > 0 ); - - uint32 Index = Heap[0]; - - Heap[0] = Heap[ --HeapNum ]; - HeapIndexes[ Heap[0] ] = 0; - HeapIndexes[ Index ] = ~0u; - - DownHeap(0); -} - -template< typename KeyType > -FORCEINLINE void FBinaryHeap< KeyType >::Add( KeyType Key, uint32 Index ) -{ - if( HeapNum == HeapSize ) - { - ResizeHeap( FMath::Max( 32u, HeapSize * 2 ) ); - } - - if( Index >= IndexSize ) - { - ResizeIndexes( FMath::Max( 32u, FMath::RoundUpToPowerOfTwo( Index + 1 ) ) ); - } - - checkSlow( !IsPresent( Index ) ); - - uint32 HeapIndex = HeapNum++; - Heap[ HeapIndex ] = Index; - - Keys[ Index ] = Key; - HeapIndexes[ Index ] = HeapIndex; - - UpHeap( HeapIndex ); -} - -template< typename KeyType > -FORCEINLINE void FBinaryHeap< KeyType >::Update( KeyType Key, uint32 Index ) -{ - checkSlow( Heap ); - checkSlow( IsPresent( Index ) ); - - Keys[ Index ] = Key; - - uint32 HeapIndex = HeapIndexes[ Index ]; - uint32 Parent = (HeapIndex - 1) >> 1; - if( HeapIndex > 0 && Key < Keys[ Heap[ Parent ] ] ) - { - UpHeap( HeapIndex ); - } - else - { - DownHeap( HeapIndex ); - } -} - -template< typename KeyType > -FORCEINLINE void FBinaryHeap< KeyType >::Remove( uint32 Index ) -{ - checkSlow( Heap ); - - if( !IsPresent( Index ) ) - { - return; - } - - KeyType Key = Keys[ Index ]; - uint32 HeapIndex = HeapIndexes[ Index ]; - - Heap[ HeapIndex ] = Heap[ --HeapNum ]; - HeapIndexes[ Heap[ HeapIndex ] ] = HeapIndex; - HeapIndexes[ Index ] = ~0u; - - if( Key < Keys[ Heap[ HeapIndex ] ] ) - { - DownHeap( HeapIndex ); - } - else - { - UpHeap( HeapIndex ); - } -} - -template< typename KeyType > -void FBinaryHeap< KeyType >::UpHeap( uint32 HeapIndex ) -{ - uint32 Moving = Heap[ HeapIndex ]; - uint32 i = HeapIndex; - uint32 Parent = (i - 1) >> 1; - - while( i > 0 && Keys[ Moving ] < Keys[ Heap[ Parent ] ] ) - { - Heap[i] = Heap[ Parent ]; - HeapIndexes[ Heap[i] ] = i; - - i = Parent; - Parent = (i - 1) >> 1; - } - - if( i != HeapIndex ) - { - Heap[i] = Moving; - HeapIndexes[ Heap[i] ] = i; - } -} - -template< typename KeyType > -void FBinaryHeap< KeyType >::DownHeap( uint32 HeapIndex ) -{ - uint32 Moving = Heap[ HeapIndex ]; - uint32 i = HeapIndex; - uint32 Left = (i << 1) + 1; - uint32 Right = Left + 1; - - while( Left < HeapNum ) - { - uint32 Smallest = Left; - if( Right < HeapNum ) - { - Smallest = ( Keys[ Heap[Left] ] < Keys[ Heap[Right] ] ) ? Left : Right; - } - - if( Keys[ Heap[Smallest] ] < Keys[ Moving ] ) - { - Heap[i] = Heap[ Smallest ]; - HeapIndexes[ Heap[i] ] = i; - - i = Smallest; - Left = (i << 1) + 1; - Right = Left + 1; - } - else - { - break; - } - } - - if( i != HeapIndex ) - { - Heap[i] = Moving; - HeapIndexes[ Heap[i] ] = i; - } -} diff --git a/Engine/Source/Developer/MeshSimplifier/Private/HashTable.h b/Engine/Source/Developer/MeshSimplifier/Private/HashTable.h deleted file mode 100644 index 68d967b6fc49..000000000000 --- a/Engine/Source/Developer/MeshSimplifier/Private/HashTable.h +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "CoreMinimal.h" - -/*----------------------------------------------------------------------------- - Dynamically sized hash table, used to index another data structure. - Vastly simpler and faster than TMap. - - Example find: - - uint32 Key = HashFunction( ID ); - for( uint32 i = HashTable.First( Key ); HashTable.IsValid( i ); i = HashTable.Next( i ) ) - { - if( Array[i].ID == ID ) - { - return Array[i]; - } - } ------------------------------------------------------------------------------*/ -class FHashTable -{ -public: - FHashTable( uint16 InHashSize = 1024, uint32 InIndexSize = 0 ); - ~FHashTable(); - - void Clear(); - void Free(); - void Resize( uint32 NewIndexSize ); - - // Functions used to search - uint32 First( uint16 Key ) const; - uint32 Next( uint32 Index ) const; - bool IsValid( uint32 Index ) const; - - void Add( uint16 Key, uint32 Index ); - void Remove( uint16 Key, uint32 Index ); - -protected: - // Avoids allocating hash until first add - static uint32 EmptyHash[1]; - - uint16 HashSize; - uint16 HashMask; - uint32 IndexSize; - - uint32* Hash; - uint32* NextIndex; -}; - - -FORCEINLINE FHashTable::FHashTable( uint16 InHashSize, uint32 InIndexSize ) - : HashSize( InHashSize ) - , HashMask( 0 ) - , IndexSize( InIndexSize ) - , Hash( EmptyHash ) - , NextIndex( NULL ) -{ - check( FMath::IsPowerOfTwo( HashSize ) ); - - if( IndexSize ) - { - HashMask = HashSize - 1; - - Hash = new uint32[ HashSize ]; - NextIndex = new uint32[ IndexSize ]; - - FMemory::Memset( Hash, 0xff, HashSize * 4 ); - } -} - -FORCEINLINE FHashTable::~FHashTable() -{ - Free(); -} - -FORCEINLINE void FHashTable::Clear() -{ - if( IndexSize ) - { - FMemory::Memset( Hash, 0xff, HashSize * 4 ); - } -} - -FORCEINLINE void FHashTable::Free() -{ - if( IndexSize ) - { - HashMask = 0; - IndexSize = 0; - - delete[] Hash; - Hash = EmptyHash; - - delete[] NextIndex; - NextIndex = NULL; - } -} - -// First in hash chain -FORCEINLINE uint32 FHashTable::First( uint16 Key ) const -{ - Key &= HashMask; - return Hash[ Key ]; -} - -// Next in hash chain -FORCEINLINE uint32 FHashTable::Next( uint32 Index ) const -{ - checkSlow( Index < IndexSize ); - return NextIndex[ Index ]; -} - -FORCEINLINE bool FHashTable::IsValid( uint32 Index ) const -{ - return Index != ~0u; -} - -FORCEINLINE void FHashTable::Add( uint16 Key, uint32 Index ) -{ - if( Index >= IndexSize ) - { - Resize( FMath::Max( 32u, FMath::RoundUpToPowerOfTwo( Index + 1 ) ) ); - } - - Key &= HashMask; - NextIndex[ Index ] = Hash[ Key ]; - Hash[ Key ] = Index; -} - -inline void FHashTable::Remove( uint16 Key, uint32 Index ) -{ - if( Index >= IndexSize ) - { - return; - } - - Key &= HashMask; - - if( Hash[Key] == Index ) - { - // Head of chain - Hash[Key] = NextIndex[ Index ]; - } - else - { - for( uint32 i = Hash[Key]; IsValid(i); i = NextIndex[i] ) - { - if( NextIndex[i] == Index ) - { - // Next = Next->Next - NextIndex[i] = NextIndex[ Index ]; - break; - } - } - } -} diff --git a/Engine/Source/Developer/MeshSimplifier/Private/MeshSimplify.h b/Engine/Source/Developer/MeshSimplifier/Private/MeshSimplify.h index 819f74f5dbd9..b4a509a29ca6 100644 --- a/Engine/Source/Developer/MeshSimplifier/Private/MeshSimplify.h +++ b/Engine/Source/Developer/MeshSimplifier/Private/MeshSimplify.h @@ -7,10 +7,10 @@ #define SIMP_CACHE 1 -#include "Developer/MeshSimplifier/Private/HashTable.h" -#include "Developer/MeshSimplifier/Private/BinaryHeap.h" -#include "Developer/MeshSimplifier/Private/MeshSimplifyElements.h" -#include "Developer/MeshSimplifier/Private/Quadric.h" +#include "MeshSimplifyElements.h" +#include "Quadric.h" +#include "Containers/HashTable.h" +#include "Containers/BinaryHeap.h" //#include "Cache.h" template< typename T, uint32 NumAttributes > diff --git a/Engine/Source/Developer/MeshUtilities/Private/LayoutUV.cpp b/Engine/Source/Developer/MeshUtilities/Private/LayoutUV.cpp index e41a64c1aa99..889fdfdd9e99 100644 --- a/Engine/Source/Developer/MeshUtilities/Private/LayoutUV.cpp +++ b/Engine/Source/Developer/MeshUtilities/Private/LayoutUV.cpp @@ -3,6 +3,8 @@ #include "LayoutUV.h" #include "DisjointSet.h" +#include "Algo/IntroSort.h" + DEFINE_LOG_CATEGORY_STATIC(LogLayoutUV, Warning, All); #define CHART_JOINING 1 @@ -147,7 +149,8 @@ void FLayoutUV::FindCharts( const TMultiMap& OverlappingCorners ) return (*DisjointSet)[A] < (*DisjointSet)[B]; } }; - SortedTris.Sort( FCompareTris( &DisjointSet ) ); + + Algo::IntroSort( SortedTris, FCompareTris( &DisjointSet ) ); TMap< uint32, int32 > DisjointSetToChartMap; @@ -205,16 +208,7 @@ void FLayoutUV::FindCharts( const TMultiMap& OverlappingCorners ) Chart.LastTri = Tri; #if !CHART_JOINING - if( Chart.UVArea > 1e-4f ) - { - Chart.WorldScale /= Chart.UVArea; - } - else - { - Chart.WorldScale = FVector2D::ZeroVector; - } - - //Chart.WorldScale.Set(1,1); + Chart.WorldScale /= FMath::Max( Chart.UVArea, 1e-8f ); TotalUVArea += Chart.UVArea * Chart.WorldScale.X * Chart.WorldScale.Y; #endif @@ -519,14 +513,7 @@ void FLayoutUV::FindCharts( const TMultiMap& OverlappingCorners ) { FMeshChart& Chart = Charts[i]; - if( Chart.UVArea > 1e-4f ) - { - Chart.WorldScale /= Chart.UVArea; - } - else - { - Chart.WorldScale = FVector2D::ZeroVector; - } + Chart.WorldScale /= FMath::Max( Chart.UVArea, 1e-8f ); TotalUVArea += Chart.UVArea * Chart.WorldScale.X * Chart.WorldScale.Y; } @@ -724,7 +711,7 @@ void FLayoutUV::ScaleCharts( float UVScale ) return ChartRectA.X * ChartRectA.Y > ChartRectB.X * ChartRectB.Y; } }; - Charts.Sort( FCompareCharts() ); + Algo::IntroSort( Charts, FCompareCharts() ); } bool FLayoutUV::PackCharts() diff --git a/Engine/Source/Developer/MeshUtilities/Private/LayoutUV.h b/Engine/Source/Developer/MeshUtilities/Private/LayoutUV.h index 3534d7404e6e..a00a54c40a60 100644 --- a/Engine/Source/Developer/MeshUtilities/Private/LayoutUV.h +++ b/Engine/Source/Developer/MeshUtilities/Private/LayoutUV.h @@ -84,7 +84,7 @@ private: }; -#define THRESH_UVS_ARE_SAME (1.0f / 1024.0f) +#define THRESH_UVS_ARE_SAME THRESH_POINTS_ARE_SAME inline bool FLayoutUV::PositionsMatch( uint32 a, uint32 b ) const { diff --git a/Engine/Source/Developer/MeshUtilities/Private/MeshUtilities.cpp b/Engine/Source/Developer/MeshUtilities/Private/MeshUtilities.cpp index 3dddd9133409..81b32e66b3e2 100644 --- a/Engine/Source/Developer/MeshUtilities/Private/MeshUtilities.cpp +++ b/Engine/Source/Developer/MeshUtilities/Private/MeshUtilities.cpp @@ -91,6 +91,8 @@ #include "UnrealEdMisc.h" #endif +DEFINE_LOG_CATEGORY(LogMeshUtilities); + /*------------------------------------------------------------------------------ MeshUtilities module. ------------------------------------------------------------------------------*/ @@ -129,35 +131,37 @@ void FMeshUtilities::UpdateMeshReductionModule() FString String = CVarMeshReductionModule->GetString(); bool bIsChoosenModule = ModuleNames[Index].GetPlainNameString().Equals(String); - IMeshReductionModule& MeshReductionModule = FModuleManager::LoadModuleChecked(ModuleNames[Index]); - - // Look for MeshReduction interface - if(MeshReductionModule.GetStaticMeshReductionInterface()) + IMeshReductionModule* MeshReductionModule = FModuleManager::LoadModulePtr(ModuleNames[Index]); + if (MeshReductionModule != nullptr) { - if(bIsChoosenModule || StaticMeshReduction == NULL) + // Look for MeshReduction interface + if(MeshReductionModule->GetStaticMeshReductionInterface()) { - StaticMeshReduction = MeshReductionModule.GetStaticMeshReductionInterface(); - UE_LOG(LogMeshUtilities, Log, TEXT("Using %s for automatic static mesh reduction"), *ModuleNames[Index].ToString()); + if(bIsChoosenModule || StaticMeshReduction == NULL) + { + StaticMeshReduction = MeshReductionModule->GetStaticMeshReductionInterface(); + UE_LOG(LogMeshUtilities, Log, TEXT("Using %s for automatic static mesh reduction"), *ModuleNames[Index].ToString()); + } } - } - // Look for MeshReduction interface - if(MeshReductionModule.GetSkeletalMeshReductionInterface()) - { - if(bIsChoosenModule || SkeletalMeshReduction == NULL) + // Look for MeshReduction interface + if(MeshReductionModule->GetSkeletalMeshReductionInterface()) { - SkeletalMeshReduction = MeshReductionModule.GetSkeletalMeshReductionInterface(); - UE_LOG(LogMeshUtilities, Log, TEXT("Using %s for automatic skeletal mesh reduction"), *ModuleNames[Index].ToString()); + if(bIsChoosenModule || SkeletalMeshReduction == NULL) + { + SkeletalMeshReduction = MeshReductionModule->GetSkeletalMeshReductionInterface(); + UE_LOG(LogMeshUtilities, Log, TEXT("Using %s for automatic skeletal mesh reduction"), *ModuleNames[Index].ToString()); + } } - } - // Look for MeshMerging interface - if(MeshReductionModule.GetMeshMergingInterface()) - { - if(bIsChoosenModule || MeshMerging == NULL) + // Look for MeshMerging interface + if(MeshReductionModule->GetMeshMergingInterface()) { - MeshMerging = MeshReductionModule.GetMeshMergingInterface(); - UE_LOG(LogMeshUtilities, Log, TEXT("Using %s for automatic mesh merging"), *ModuleNames[Index].ToString()); + if(bIsChoosenModule || MeshMerging == NULL) + { + MeshMerging = MeshReductionModule->GetMeshMergingInterface(); + UE_LOG(LogMeshUtilities, Log, TEXT("Using %s for automatic mesh merging"), *ModuleNames[Index].ToString()); + } } } } @@ -2240,18 +2244,46 @@ static void ComputeTangents( uint32 TangentOptions ) { - const float ComparisonThreshold = (TangentOptions & ETangentOptions::IgnoreDegenerateTriangles) ? THRESH_POINTS_ARE_SAME : 0.0f; ComputeTangents(RawMesh.VertexPositions, RawMesh.WedgeIndices, RawMesh.WedgeTexCoords[0], RawMesh.FaceSmoothingMasks, OverlappingCorners, RawMesh.WedgeTangentX, RawMesh.WedgeTangentY, RawMesh.WedgeTangentZ, TangentOptions); } /*------------------------------------------------------------------------------ MikkTSpace for computing tangents. ------------------------------------------------------------------------------*/ +class MikkTSpace_Mesh +{ +public: + const TArray& Vertices; + const TArray& Indices; + const TArray& UVs; + + TArray& TangentsX; //Reference to newly created tangents list. + TArray& TangentsY; //Reference to newly created bitangents list. + TArray& TangentsZ; //Reference to computed normals, will be empty otherwise. + + MikkTSpace_Mesh( + const TArray &InVertices, + const TArray &InIndices, + const TArray &InUVs, + TArray &InVertexTangentsX, + TArray &InVertexTangentsY, + TArray &InVertexTangentsZ + ) + : + Vertices(InVertices), + Indices(InIndices), + UVs(InUVs), + TangentsX(InVertexTangentsX), + TangentsY(InVertexTangentsY), + TangentsZ(InVertexTangentsZ) + { + } +}; static int MikkGetNumFaces(const SMikkTSpaceContext* Context) { - FRawMesh *UserData = (FRawMesh*)(Context->m_pUserData); - return UserData->WedgeIndices.Num() / 3; + MikkTSpace_Mesh *UserData = (MikkTSpace_Mesh*)(Context->m_pUserData); + return UserData->Indices.Num() / 3; } static int MikkGetNumVertsOfFace(const SMikkTSpaceContext* Context, const int FaceIdx) @@ -2262,8 +2294,8 @@ static int MikkGetNumVertsOfFace(const SMikkTSpaceContext* Context, const int Fa static void MikkGetPosition(const SMikkTSpaceContext* Context, float Position[3], const int FaceIdx, const int VertIdx) { - FRawMesh *UserData = (FRawMesh*)(Context->m_pUserData); - FVector VertexPosition = UserData->GetWedgePosition(FaceIdx * 3 + VertIdx); + MikkTSpace_Mesh *UserData = (MikkTSpace_Mesh*)(Context->m_pUserData); + FVector VertexPosition = UserData->Vertices[ UserData->Indices[FaceIdx * 3 + VertIdx] ]; Position[0] = VertexPosition.X; Position[1] = VertexPosition.Y; Position[2] = VertexPosition.Z; @@ -2271,8 +2303,8 @@ static void MikkGetPosition(const SMikkTSpaceContext* Context, float Position[3] static void MikkGetNormal(const SMikkTSpaceContext* Context, float Normal[3], const int FaceIdx, const int VertIdx) { - FRawMesh *UserData = (FRawMesh*)(Context->m_pUserData); - FVector &VertexNormal = UserData->WedgeTangentZ[FaceIdx * 3 + VertIdx]; + MikkTSpace_Mesh *UserData = (MikkTSpace_Mesh*)(Context->m_pUserData); + FVector &VertexNormal = UserData->TangentsZ[FaceIdx * 3 + VertIdx]; for (int32 i = 0; i < 3; ++i) { Normal[i] = VertexNormal[i]; @@ -2281,14 +2313,14 @@ static void MikkGetNormal(const SMikkTSpaceContext* Context, float Normal[3], co static void MikkSetTSpaceBasic(const SMikkTSpaceContext* Context, const float Tangent[3], const float BitangentSign, const int FaceIdx, const int VertIdx) { - FRawMesh *UserData = (FRawMesh*)(Context->m_pUserData); - FVector &VertexTangent = UserData->WedgeTangentX[FaceIdx * 3 + VertIdx]; + MikkTSpace_Mesh *UserData = (MikkTSpace_Mesh*)(Context->m_pUserData); + FVector &VertexTangent = UserData->TangentsX[FaceIdx * 3 + VertIdx]; for (int32 i = 0; i < 3; ++i) { VertexTangent[i] = Tangent[i]; } - FVector Bitangent = BitangentSign * FVector::CrossProduct(UserData->WedgeTangentZ[FaceIdx * 3 + VertIdx], VertexTangent); - FVector &VertexBitangent = UserData->WedgeTangentY[FaceIdx * 3 + VertIdx]; + FVector Bitangent = BitangentSign * FVector::CrossProduct(UserData->TangentsZ[FaceIdx * 3 + VertIdx], VertexTangent); + FVector &VertexBitangent = UserData->TangentsY[FaceIdx * 3 + VertIdx]; for (int32 i = 0; i < 3; ++i) { VertexBitangent[i] = -Bitangent[i]; @@ -2297,8 +2329,8 @@ static void MikkSetTSpaceBasic(const SMikkTSpaceContext* Context, const float Ta static void MikkGetTexCoord(const SMikkTSpaceContext* Context, float UV[2], const int FaceIdx, const int VertIdx) { - FRawMesh *UserData = (FRawMesh*)(Context->m_pUserData); - FVector2D &TexCoord = UserData->WedgeTexCoords[0][FaceIdx * 3 + VertIdx]; + MikkTSpace_Mesh *UserData = (MikkTSpace_Mesh*)(Context->m_pUserData); + const FVector2D &TexCoord = UserData->UVs[FaceIdx * 3 + VertIdx]; UV[0] = TexCoord.X; UV[1] = TexCoord.Y; } @@ -2414,9 +2446,15 @@ static void MikkGetTexCoord_Skeletal(const SMikkTSpaceContext* Context, float UV } static void ComputeTangents_MikkTSpace( - FRawMesh& RawMesh, + const TArray& InVertices, + const TArray& InIndices, + const TArray& InUVs, + const TArray& SmoothingGroupIndices, TMultiMap const& OverlappingCorners, - uint32 TangentOptions + TArray& OutTangentX, + TArray& OutTangentY, + TArray& OutTangentZ, + const uint32 TangentOptions ) { bool bBlendOverlappingNormals = (TangentOptions & ETangentOptions::BlendOverlappingNormals) != 0; @@ -2429,10 +2467,12 @@ static void ComputeTangents_MikkTSpace( TArray TriangleTangentZ; ComputeTriangleTangents( + InVertices, + InIndices, + InUVs, TriangleTangentX, TriangleTangentY, TriangleTangentZ, - RawMesh, bIgnoreDegenerateTriangles ? SMALL_NUMBER : 0.0f ); @@ -2441,252 +2481,247 @@ static void ComputeTangents_MikkTSpace( TArray AdjacentFaces; TArray DupVerts; - int32 NumWedges = RawMesh.WedgeIndices.Num(); + int32 NumWedges = InIndices.Num(); int32 NumFaces = NumWedges / 3; - bool bWedgeNormals = true; bool bWedgeTSpace = false; - for (int32 WedgeIdx = 0; WedgeIdx < RawMesh.WedgeTangentZ.Num(); ++WedgeIdx) - { - bWedgeNormals = bWedgeNormals && (!RawMesh.WedgeTangentZ[WedgeIdx].IsNearlyZero()); - } - if (RawMesh.WedgeTangentX.Num() > 0 && RawMesh.WedgeTangentY.Num() > 0) + if (OutTangentX.Num() > 0 && OutTangentY.Num() > 0) { bWedgeTSpace = true; - for (int32 WedgeIdx = 0; WedgeIdx < RawMesh.WedgeTangentX.Num() - && WedgeIdx < RawMesh.WedgeTangentY.Num(); ++WedgeIdx) + for (int32 WedgeIdx = 0; WedgeIdx < OutTangentX.Num() + && WedgeIdx < OutTangentY.Num(); ++WedgeIdx) { - bWedgeTSpace = bWedgeTSpace && (!RawMesh.WedgeTangentX[WedgeIdx].IsNearlyZero()) && (!RawMesh.WedgeTangentY[WedgeIdx].IsNearlyZero()); + bWedgeTSpace = bWedgeTSpace && (!OutTangentX[WedgeIdx].IsNearlyZero()) && (!OutTangentY[WedgeIdx].IsNearlyZero()); } } // Allocate storage for tangents if none were provided, and calculate normals for MikkTSpace. - if (RawMesh.WedgeTangentZ.Num() != NumWedges || !bWedgeNormals) + if (OutTangentZ.Num() != NumWedges) { // normals are not included, so we should calculate them - RawMesh.WedgeTangentZ.Empty(NumWedges); - RawMesh.WedgeTangentZ.AddZeroed(NumWedges); + OutTangentZ.Empty(NumWedges); + OutTangentZ.AddZeroed(NumWedges); + } - // we need to calculate normals for MikkTSpace - UE_LOG(LogMeshUtilities, Log, TEXT("Invalid vertex normals found for mesh. Forcing recomputation of vertex normals for MikkTSpace. Fix mesh or disable \"Use MikkTSpace Tangent Space\" to avoid forced recomputation of normals.")); + // we need to calculate normals for MikkTSpace + for (int32 FaceIndex = 0; FaceIndex < NumFaces; FaceIndex++) + { + int32 WedgeOffset = FaceIndex * 3; + FVector CornerPositions[3]; + FVector CornerNormal[3]; - for (int32 FaceIndex = 0; FaceIndex < NumFaces; FaceIndex++) + for (int32 CornerIndex = 0; CornerIndex < 3; CornerIndex++) { - int32 WedgeOffset = FaceIndex * 3; - FVector CornerPositions[3]; - FVector CornerNormal[3]; + CornerNormal[CornerIndex] = FVector::ZeroVector; + CornerPositions[CornerIndex] = InVertices[InIndices[WedgeOffset + CornerIndex]]; + RelevantFacesForCorner[CornerIndex].Reset(); + } - for (int32 CornerIndex = 0; CornerIndex < 3; CornerIndex++) + // Don't process degenerate triangles. + if (PointsEqual(CornerPositions[0], CornerPositions[1], ComparisonThreshold) + || PointsEqual(CornerPositions[0], CornerPositions[2], ComparisonThreshold) + || PointsEqual(CornerPositions[1], CornerPositions[2], ComparisonThreshold)) + { + continue; + } + + // No need to process triangles if tangents already exist. + bool bCornerHasNormal[3] = { 0 }; + for (int32 CornerIndex = 0; CornerIndex < 3; CornerIndex++) + { + bCornerHasNormal[CornerIndex] = !OutTangentZ[WedgeOffset + CornerIndex].IsZero(); + } + if (bCornerHasNormal[0] && bCornerHasNormal[1] && bCornerHasNormal[2]) + { + continue; + } + + // Start building a list of faces adjacent to this face. + AdjacentFaces.Reset(); + for (int32 CornerIndex = 0; CornerIndex < 3; CornerIndex++) + { + int32 ThisCornerIndex = WedgeOffset + CornerIndex; + DupVerts.Reset(); + OverlappingCorners.MultiFind(ThisCornerIndex, DupVerts); + DupVerts.Add(ThisCornerIndex); // I am a "dup" of myself + for (int32 k = 0; k < DupVerts.Num(); k++) { - CornerNormal[CornerIndex] = FVector::ZeroVector; - CornerPositions[CornerIndex] = GetPositionForWedge(RawMesh, WedgeOffset + CornerIndex); - RelevantFacesForCorner[CornerIndex].Reset(); + AdjacentFaces.AddUnique(DupVerts[k] / 3); } + } - // Don't process degenerate triangles. - if (PointsEqual(CornerPositions[0], CornerPositions[1], ComparisonThreshold) - || PointsEqual(CornerPositions[0], CornerPositions[2], ComparisonThreshold) - || PointsEqual(CornerPositions[1], CornerPositions[2], ComparisonThreshold)) + // We need to sort these here because the criteria for point equality is + // exact, so we must ensure the exact same order for all dups. + AdjacentFaces.Sort(); + + // Process adjacent faces + for (int32 AdjacentFaceIndex = 0; AdjacentFaceIndex < AdjacentFaces.Num(); AdjacentFaceIndex++) + { + int32 OtherFaceIndex = AdjacentFaces[AdjacentFaceIndex]; + for (int32 OurCornerIndex = 0; OurCornerIndex < 3; OurCornerIndex++) { - continue; - } - - // No need to process triangles if tangents already exist. - bool bCornerHasNormal[3] = { 0 }; - for (int32 CornerIndex = 0; CornerIndex < 3; CornerIndex++) - { - bCornerHasNormal[CornerIndex] = !RawMesh.WedgeTangentZ[WedgeOffset + CornerIndex].IsZero(); - } - if (bCornerHasNormal[0] && bCornerHasNormal[1] && bCornerHasNormal[2]) - { - continue; - } - - // Start building a list of faces adjacent to this face. - AdjacentFaces.Reset(); - for (int32 CornerIndex = 0; CornerIndex < 3; CornerIndex++) - { - int32 ThisCornerIndex = WedgeOffset + CornerIndex; - DupVerts.Reset(); - OverlappingCorners.MultiFind(ThisCornerIndex, DupVerts); - DupVerts.Add(ThisCornerIndex); // I am a "dup" of myself - for (int32 k = 0; k < DupVerts.Num(); k++) - { - AdjacentFaces.AddUnique(DupVerts[k] / 3); - } - } - - // We need to sort these here because the criteria for point equality is - // exact, so we must ensure the exact same order for all dups. - AdjacentFaces.Sort(); - - // Process adjacent faces - for (int32 AdjacentFaceIndex = 0; AdjacentFaceIndex < AdjacentFaces.Num(); AdjacentFaceIndex++) - { - int32 OtherFaceIndex = AdjacentFaces[AdjacentFaceIndex]; - for (int32 OurCornerIndex = 0; OurCornerIndex < 3; OurCornerIndex++) - { - if (bCornerHasNormal[OurCornerIndex]) - continue; - - FFanFace NewFanFace; - int32 CommonIndexCount = 0; - - // Check for vertices in common. - if (FaceIndex == OtherFaceIndex) - { - CommonIndexCount = 3; - NewFanFace.LinkedVertexIndex = OurCornerIndex; - } - else - { - // Check matching vertices against main vertex . - for (int32 OtherCornerIndex = 0; OtherCornerIndex < 3; OtherCornerIndex++) - { - if (PointsEqual( - CornerPositions[OurCornerIndex], - GetPositionForWedge(RawMesh, OtherFaceIndex * 3 + OtherCornerIndex), - ComparisonThreshold - )) - { - CommonIndexCount++; - NewFanFace.LinkedVertexIndex = OtherCornerIndex; - } - } - } - - // Add if connected by at least one point. Smoothing matches are considered later. - if (CommonIndexCount > 0) - { - NewFanFace.FaceIndex = OtherFaceIndex; - NewFanFace.bFilled = (OtherFaceIndex == FaceIndex); // Starter face for smoothing floodfill. - NewFanFace.bBlendTangents = NewFanFace.bFilled; - NewFanFace.bBlendNormals = NewFanFace.bFilled; - RelevantFacesForCorner[OurCornerIndex].Add(NewFanFace); - } - } - } - - // Find true relevance of faces for a vertex normal by traversing - // smoothing-group-compatible connected triangle fans around common vertices. - for (int32 CornerIndex = 0; CornerIndex < 3; CornerIndex++) - { - if (bCornerHasNormal[CornerIndex]) + if (bCornerHasNormal[OurCornerIndex]) continue; - int32 NewConnections; - do + FFanFace NewFanFace; + int32 CommonIndexCount = 0; + + // Check for vertices in common. + if (FaceIndex == OtherFaceIndex) { - NewConnections = 0; - for (int32 OtherFaceIdx = 0; OtherFaceIdx < RelevantFacesForCorner[CornerIndex].Num(); OtherFaceIdx++) + CommonIndexCount = 3; + NewFanFace.LinkedVertexIndex = OurCornerIndex; + } + else + { + // Check matching vertices against main vertex . + for (int32 OtherCornerIndex = 0; OtherCornerIndex < 3; OtherCornerIndex++) { - FFanFace& OtherFace = RelevantFacesForCorner[CornerIndex][OtherFaceIdx]; - // The vertex' own face is initially the only face with bFilled == true. - if (OtherFace.bFilled) + if (PointsEqual( + CornerPositions[OurCornerIndex], + InVertices[InIndices[OtherFaceIndex * 3 + OtherCornerIndex]], + ComparisonThreshold + )) { - for (int32 NextFaceIndex = 0; NextFaceIndex < RelevantFacesForCorner[CornerIndex].Num(); NextFaceIndex++) + CommonIndexCount++; + NewFanFace.LinkedVertexIndex = OtherCornerIndex; + } + } + } + + // Add if connected by at least one point. Smoothing matches are considered later. + if (CommonIndexCount > 0) + { + NewFanFace.FaceIndex = OtherFaceIndex; + NewFanFace.bFilled = (OtherFaceIndex == FaceIndex); // Starter face for smoothing floodfill. + NewFanFace.bBlendTangents = NewFanFace.bFilled; + NewFanFace.bBlendNormals = NewFanFace.bFilled; + RelevantFacesForCorner[OurCornerIndex].Add(NewFanFace); + } + } + } + + // Find true relevance of faces for a vertex normal by traversing + // smoothing-group-compatible connected triangle fans around common vertices. + for (int32 CornerIndex = 0; CornerIndex < 3; CornerIndex++) + { + if (bCornerHasNormal[CornerIndex]) + continue; + + int32 NewConnections; + do + { + NewConnections = 0; + for (int32 OtherFaceIdx = 0; OtherFaceIdx < RelevantFacesForCorner[CornerIndex].Num(); OtherFaceIdx++) + { + FFanFace& OtherFace = RelevantFacesForCorner[CornerIndex][OtherFaceIdx]; + // The vertex' own face is initially the only face with bFilled == true. + if (OtherFace.bFilled) + { + for (int32 NextFaceIndex = 0; NextFaceIndex < RelevantFacesForCorner[CornerIndex].Num(); NextFaceIndex++) + { + FFanFace& NextFace = RelevantFacesForCorner[CornerIndex][NextFaceIndex]; + if (!NextFace.bFilled) // && !NextFace.bBlendTangents) { - FFanFace& NextFace = RelevantFacesForCorner[CornerIndex][NextFaceIndex]; - if (!NextFace.bFilled) // && !NextFace.bBlendTangents) + if ((NextFaceIndex != OtherFaceIdx) + && (SmoothingGroupIndices[NextFace.FaceIndex] & SmoothingGroupIndices[OtherFace.FaceIndex])) { - if ((NextFaceIndex != OtherFaceIdx) - && (RawMesh.FaceSmoothingMasks[NextFace.FaceIndex] & RawMesh.FaceSmoothingMasks[OtherFace.FaceIndex])) + int32 CommonVertices = 0; + int32 CommonNormalVertices = 0; + for (int32 OtherCornerIndex = 0; OtherCornerIndex < 3; OtherCornerIndex++) { - int32 CommonVertices = 0; - int32 CommonNormalVertices = 0; - for (int32 OtherCornerIndex = 0; OtherCornerIndex < 3; OtherCornerIndex++) + for (int32 NextCornerIndex = 0; NextCornerIndex < 3; NextCornerIndex++) { - for (int32 NextCornerIndex = 0; NextCornerIndex < 3; NextCornerIndex++) + int32 NextVertexIndex = InIndices[NextFace.FaceIndex * 3 + NextCornerIndex]; + int32 OtherVertexIndex = InIndices[OtherFace.FaceIndex * 3 + OtherCornerIndex]; + if (PointsEqual( + InVertices[NextVertexIndex], + InVertices[OtherVertexIndex], + ComparisonThreshold)) { - int32 NextVertexIndex = RawMesh.WedgeIndices[NextFace.FaceIndex * 3 + NextCornerIndex]; - int32 OtherVertexIndex = RawMesh.WedgeIndices[OtherFace.FaceIndex * 3 + OtherCornerIndex]; - if (PointsEqual( - RawMesh.VertexPositions[NextVertexIndex], - RawMesh.VertexPositions[OtherVertexIndex], - ComparisonThreshold)) + CommonVertices++; + if (bBlendOverlappingNormals + || NextVertexIndex == OtherVertexIndex) { - CommonVertices++; - if (bBlendOverlappingNormals - || NextVertexIndex == OtherVertexIndex) - { - CommonNormalVertices++; - } + CommonNormalVertices++; } } } - // Flood fill faces with more than one common vertices which must be touching edges. - if (CommonVertices > 1) - { - NextFace.bFilled = true; - NextFace.bBlendNormals = (CommonNormalVertices > 1); - NewConnections++; - } + } + // Flood fill faces with more than one common vertices which must be touching edges. + if (CommonVertices > 1) + { + NextFace.bFilled = true; + NextFace.bBlendNormals = (CommonNormalVertices > 1); + NewConnections++; } } } } } - } - while (NewConnections > 0); - } - - - // Vertex normal construction. - for (int32 CornerIndex = 0; CornerIndex < 3; CornerIndex++) - { - if (bCornerHasNormal[CornerIndex]) - { - CornerNormal[CornerIndex] = RawMesh.WedgeTangentZ[WedgeOffset + CornerIndex]; } - else + } + while (NewConnections > 0); + } + + + // Vertex normal construction. + for (int32 CornerIndex = 0; CornerIndex < 3; CornerIndex++) + { + if (bCornerHasNormal[CornerIndex]) + { + CornerNormal[CornerIndex] = OutTangentZ[WedgeOffset + CornerIndex]; + } + else + { + for (int32 RelevantFaceIdx = 0; RelevantFaceIdx < RelevantFacesForCorner[CornerIndex].Num(); RelevantFaceIdx++) { - for (int32 RelevantFaceIdx = 0; RelevantFaceIdx < RelevantFacesForCorner[CornerIndex].Num(); RelevantFaceIdx++) + FFanFace const& RelevantFace = RelevantFacesForCorner[CornerIndex][RelevantFaceIdx]; + if (RelevantFace.bFilled) { - FFanFace const& RelevantFace = RelevantFacesForCorner[CornerIndex][RelevantFaceIdx]; - if (RelevantFace.bFilled) + int32 OtherFaceIndex = RelevantFace.FaceIndex; + if (RelevantFace.bBlendNormals) { - int32 OtherFaceIndex = RelevantFace.FaceIndex; - if (RelevantFace.bBlendNormals) - { - CornerNormal[CornerIndex] += TriangleTangentZ[OtherFaceIndex]; - } + CornerNormal[CornerIndex] += TriangleTangentZ[OtherFaceIndex]; } } - if (!RawMesh.WedgeTangentZ[WedgeOffset + CornerIndex].IsZero()) - { - CornerNormal[CornerIndex] = RawMesh.WedgeTangentZ[WedgeOffset + CornerIndex]; - } + } + if (!OutTangentZ[WedgeOffset + CornerIndex].IsZero()) + { + CornerNormal[CornerIndex] = OutTangentZ[WedgeOffset + CornerIndex]; } } + } - // Normalization. - for (int32 CornerIndex = 0; CornerIndex < 3; CornerIndex++) - { - CornerNormal[CornerIndex].Normalize(); - } + // Normalization. + for (int32 CornerIndex = 0; CornerIndex < 3; CornerIndex++) + { + CornerNormal[CornerIndex].Normalize(); + } - // Copy back to the mesh. - for (int32 CornerIndex = 0; CornerIndex < 3; CornerIndex++) - { - RawMesh.WedgeTangentZ[WedgeOffset + CornerIndex] = CornerNormal[CornerIndex]; - } + // Copy back to the mesh. + for (int32 CornerIndex = 0; CornerIndex < 3; CornerIndex++) + { + OutTangentZ[WedgeOffset + CornerIndex] = CornerNormal[CornerIndex]; } } - if (RawMesh.WedgeTangentX.Num() != NumWedges) + if (OutTangentX.Num() != NumWedges) { - RawMesh.WedgeTangentX.Empty(NumWedges); - RawMesh.WedgeTangentX.AddZeroed(NumWedges); + OutTangentX.Empty(NumWedges); + OutTangentX.AddZeroed(NumWedges); } - if (RawMesh.WedgeTangentY.Num() != NumWedges) + if (OutTangentY.Num() != NumWedges) { - RawMesh.WedgeTangentY.Empty(NumWedges); - RawMesh.WedgeTangentY.AddZeroed(NumWedges); + OutTangentY.Empty(NumWedges); + OutTangentY.AddZeroed(NumWedges); } if (!bWedgeTSpace) { + MikkTSpace_Mesh MikkTSpaceMesh( InVertices, InIndices, InUVs, OutTangentX, OutTangentY, OutTangentZ ); + // we can use mikktspace to calculate the tangents SMikkTSpaceInterface MikkTInterface; MikkTInterface.m_getNormal = MikkGetNormal; @@ -2699,14 +2734,23 @@ static void ComputeTangents_MikkTSpace( SMikkTSpaceContext MikkTContext; MikkTContext.m_pInterface = &MikkTInterface; - MikkTContext.m_pUserData = (void*)(&RawMesh); + MikkTContext.m_pUserData = (void*)(&MikkTSpaceMesh); MikkTContext.m_bIgnoreDegenerates = bIgnoreDegenerateTriangles; genTangSpaceDefault(&MikkTContext); } - check(RawMesh.WedgeTangentX.Num() == NumWedges); - check(RawMesh.WedgeTangentY.Num() == NumWedges); - check(RawMesh.WedgeTangentZ.Num() == NumWedges); + check(OutTangentX.Num() == NumWedges); + check(OutTangentY.Num() == NumWedges); + check(OutTangentZ.Num() == NumWedges); +} + +static void ComputeTangents_MikkTSpace( + FRawMesh& RawMesh, + TMultiMap const& OverlappingCorners, + uint32 TangentOptions + ) +{ + ComputeTangents_MikkTSpace(RawMesh.VertexPositions, RawMesh.WedgeIndices, RawMesh.WedgeTexCoords[0], RawMesh.FaceSmoothingMasks, OverlappingCorners, RawMesh.WedgeTangentX, RawMesh.WedgeTangentY, RawMesh.WedgeTangentZ, TangentOptions); } static void BuildDepthOnlyIndexBuffer( @@ -3484,6 +3528,8 @@ bool FMeshUtilities::GenerateStaticMeshLODs(TArray& Mode class IMeshBuildData { public: + virtual ~IMeshBuildData() { } + virtual uint32 GetWedgeIndex(uint32 FaceIndex, uint32 TriIndex) = 0; virtual uint32 GetVertexIndex(uint32 WedgeIndex) = 0; virtual uint32 GetVertexIndex(uint32 FaceIndex, uint32 TriIndex) = 0; @@ -3519,7 +3565,7 @@ protected: } }; -class SkeletalMeshBuildData : public IMeshBuildData +class SkeletalMeshBuildData final : public IMeshBuildData { public: SkeletalMeshBuildData( @@ -4113,13 +4159,7 @@ public: int32 NumWedges = BuildData->GetNumWedges(); check(NumFaces * 3 == NumWedges); - bool bWedgeNormals = true; bool bWedgeTSpace = false; - for (int32 WedgeIdx = 0; WedgeIdx < WedgeTangentZ.Num(); ++WedgeIdx) - { - for (int32 VertexIndex = 0; VertexIndex < 3; VertexIndex++) - bWedgeNormals = bWedgeNormals && (!WedgeTangentZ[WedgeIdx].IsNearlyZero()); - } if (WedgeTangentX.Num() > 0 && WedgeTangentY.Num() > 0) { @@ -4132,212 +4172,213 @@ public: } // Allocate storage for tangents if none were provided, and calculate normals for MikkTSpace. - if (WedgeTangentZ.Num() != NumWedges || !bWedgeNormals) + if (WedgeTangentZ.Num() != NumWedges) { // normals are not included, so we should calculate them WedgeTangentZ.Empty(NumWedges); WedgeTangentZ.AddZeroed(NumWedges); - // we need to calculate normals for MikkTSpace + } - for (int32 FaceIndex = 0; FaceIndex < NumFaces; FaceIndex++) + // we need to calculate normals for MikkTSpace + + for (int32 FaceIndex = 0; FaceIndex < NumFaces; FaceIndex++) + { + int32 WedgeOffset = FaceIndex * 3; + FVector CornerPositions[3]; + FVector CornerNormal[3]; + + for (int32 CornerIndex = 0; CornerIndex < 3; CornerIndex++) { - int32 WedgeOffset = FaceIndex * 3; - FVector CornerPositions[3]; - FVector CornerNormal[3]; + CornerNormal[CornerIndex] = FVector::ZeroVector; + CornerPositions[CornerIndex] = BuildData->GetVertexPosition(FaceIndex, CornerIndex); + RelevantFacesForCorner[CornerIndex].Reset(); + } - for (int32 CornerIndex = 0; CornerIndex < 3; CornerIndex++) + // Don't process degenerate triangles. + if (PointsEqual(CornerPositions[0], CornerPositions[1], ComparisonThreshold) + || PointsEqual(CornerPositions[0], CornerPositions[2], ComparisonThreshold) + || PointsEqual(CornerPositions[1], CornerPositions[2], ComparisonThreshold)) + { + continue; + } + + // No need to process triangles if tangents already exist. + bool bCornerHasNormal[3] = { 0 }; + for (int32 CornerIndex = 0; CornerIndex < 3; CornerIndex++) + { + bCornerHasNormal[CornerIndex] = !WedgeTangentZ[WedgeOffset + CornerIndex].IsZero(); + } + if (bCornerHasNormal[0] && bCornerHasNormal[1] && bCornerHasNormal[2]) + { + continue; + } + + // Start building a list of faces adjacent to this face. + AdjacentFaces.Reset(); + for (int32 CornerIndex = 0; CornerIndex < 3; CornerIndex++) + { + int32 ThisCornerIndex = WedgeOffset + CornerIndex; + DupVerts.Reset(); + OverlappingCorners.MultiFind(ThisCornerIndex, DupVerts); + DupVerts.Add(ThisCornerIndex); // I am a "dup" of myself + for (int32 k = 0; k < DupVerts.Num(); k++) { - CornerNormal[CornerIndex] = FVector::ZeroVector; - CornerPositions[CornerIndex] = BuildData->GetVertexPosition(FaceIndex, CornerIndex); - RelevantFacesForCorner[CornerIndex].Reset(); + AdjacentFaces.AddUnique(DupVerts[k] / 3); } + } - // Don't process degenerate triangles. - if (PointsEqual(CornerPositions[0], CornerPositions[1], ComparisonThreshold) - || PointsEqual(CornerPositions[0], CornerPositions[2], ComparisonThreshold) - || PointsEqual(CornerPositions[1], CornerPositions[2], ComparisonThreshold)) + // We need to sort these here because the criteria for point equality is + // exact, so we must ensure the exact same order for all dups. + AdjacentFaces.Sort(); + + // Process adjacent faces + for (int32 AdjacentFaceIndex = 0; AdjacentFaceIndex < AdjacentFaces.Num(); AdjacentFaceIndex++) + { + int32 OtherFaceIndex = AdjacentFaces[AdjacentFaceIndex]; + for (int32 OurCornerIndex = 0; OurCornerIndex < 3; OurCornerIndex++) { - continue; - } - - // No need to process triangles if tangents already exist. - bool bCornerHasNormal[3] = { 0 }; - for (int32 CornerIndex = 0; CornerIndex < 3; CornerIndex++) - { - bCornerHasNormal[CornerIndex] = !WedgeTangentZ[WedgeOffset + CornerIndex].IsZero(); - } - if (bCornerHasNormal[0] && bCornerHasNormal[1] && bCornerHasNormal[2]) - { - continue; - } - - // Start building a list of faces adjacent to this face. - AdjacentFaces.Reset(); - for (int32 CornerIndex = 0; CornerIndex < 3; CornerIndex++) - { - int32 ThisCornerIndex = WedgeOffset + CornerIndex; - DupVerts.Reset(); - OverlappingCorners.MultiFind(ThisCornerIndex, DupVerts); - DupVerts.Add(ThisCornerIndex); // I am a "dup" of myself - for (int32 k = 0; k < DupVerts.Num(); k++) - { - AdjacentFaces.AddUnique(DupVerts[k] / 3); - } - } - - // We need to sort these here because the criteria for point equality is - // exact, so we must ensure the exact same order for all dups. - AdjacentFaces.Sort(); - - // Process adjacent faces - for (int32 AdjacentFaceIndex = 0; AdjacentFaceIndex < AdjacentFaces.Num(); AdjacentFaceIndex++) - { - int32 OtherFaceIndex = AdjacentFaces[AdjacentFaceIndex]; - for (int32 OurCornerIndex = 0; OurCornerIndex < 3; OurCornerIndex++) - { - if (bCornerHasNormal[OurCornerIndex]) - continue; - - FFanFace NewFanFace; - int32 CommonIndexCount = 0; - - // Check for vertices in common. - if (FaceIndex == OtherFaceIndex) - { - CommonIndexCount = 3; - NewFanFace.LinkedVertexIndex = OurCornerIndex; - } - else - { - // Check matching vertices against main vertex . - for (int32 OtherCornerIndex = 0; OtherCornerIndex < 3; OtherCornerIndex++) - { - if (PointsEqual( - CornerPositions[OurCornerIndex], - BuildData->GetVertexPosition(OtherFaceIndex, OtherCornerIndex), - ComparisonThreshold - )) - { - CommonIndexCount++; - NewFanFace.LinkedVertexIndex = OtherCornerIndex; - } - } - } - - // Add if connected by at least one point. Smoothing matches are considered later. - if (CommonIndexCount > 0) - { - NewFanFace.FaceIndex = OtherFaceIndex; - NewFanFace.bFilled = (OtherFaceIndex == FaceIndex); // Starter face for smoothing floodfill. - NewFanFace.bBlendTangents = NewFanFace.bFilled; - NewFanFace.bBlendNormals = NewFanFace.bFilled; - RelevantFacesForCorner[OurCornerIndex].Add(NewFanFace); - } - } - } - - // Find true relevance of faces for a vertex normal by traversing - // smoothing-group-compatible connected triangle fans around common vertices. - for (int32 CornerIndex = 0; CornerIndex < 3; CornerIndex++) - { - if (bCornerHasNormal[CornerIndex]) + if (bCornerHasNormal[OurCornerIndex]) continue; - int32 NewConnections; - do + FFanFace NewFanFace; + int32 CommonIndexCount = 0; + + // Check for vertices in common. + if (FaceIndex == OtherFaceIndex) { - NewConnections = 0; - for (int32 OtherFaceIdx = 0; OtherFaceIdx < RelevantFacesForCorner[CornerIndex].Num(); OtherFaceIdx++) + CommonIndexCount = 3; + NewFanFace.LinkedVertexIndex = OurCornerIndex; + } + else + { + // Check matching vertices against main vertex . + for (int32 OtherCornerIndex = 0; OtherCornerIndex < 3; OtherCornerIndex++) { - FFanFace& OtherFace = RelevantFacesForCorner[CornerIndex][OtherFaceIdx]; - // The vertex' own face is initially the only face with bFilled == true. - if (OtherFace.bFilled) + if (PointsEqual( + CornerPositions[OurCornerIndex], + BuildData->GetVertexPosition(OtherFaceIndex, OtherCornerIndex), + ComparisonThreshold + )) { - for (int32 NextFaceIndex = 0; NextFaceIndex < RelevantFacesForCorner[CornerIndex].Num(); NextFaceIndex++) + CommonIndexCount++; + NewFanFace.LinkedVertexIndex = OtherCornerIndex; + } + } + } + + // Add if connected by at least one point. Smoothing matches are considered later. + if (CommonIndexCount > 0) + { + NewFanFace.FaceIndex = OtherFaceIndex; + NewFanFace.bFilled = (OtherFaceIndex == FaceIndex); // Starter face for smoothing floodfill. + NewFanFace.bBlendTangents = NewFanFace.bFilled; + NewFanFace.bBlendNormals = NewFanFace.bFilled; + RelevantFacesForCorner[OurCornerIndex].Add(NewFanFace); + } + } + } + + // Find true relevance of faces for a vertex normal by traversing + // smoothing-group-compatible connected triangle fans around common vertices. + for (int32 CornerIndex = 0; CornerIndex < 3; CornerIndex++) + { + if (bCornerHasNormal[CornerIndex]) + continue; + + int32 NewConnections; + do + { + NewConnections = 0; + for (int32 OtherFaceIdx = 0; OtherFaceIdx < RelevantFacesForCorner[CornerIndex].Num(); OtherFaceIdx++) + { + FFanFace& OtherFace = RelevantFacesForCorner[CornerIndex][OtherFaceIdx]; + // The vertex' own face is initially the only face with bFilled == true. + if (OtherFace.bFilled) + { + for (int32 NextFaceIndex = 0; NextFaceIndex < RelevantFacesForCorner[CornerIndex].Num(); NextFaceIndex++) + { + FFanFace& NextFace = RelevantFacesForCorner[CornerIndex][NextFaceIndex]; + if (!NextFace.bFilled) // && !NextFace.bBlendTangents) { - FFanFace& NextFace = RelevantFacesForCorner[CornerIndex][NextFaceIndex]; - if (!NextFace.bFilled) // && !NextFace.bBlendTangents) + if ((NextFaceIndex != OtherFaceIdx) + && (BuildData->GetFaceSmoothingGroups(NextFace.FaceIndex) & BuildData->GetFaceSmoothingGroups(OtherFace.FaceIndex))) { - if ((NextFaceIndex != OtherFaceIdx) - && (BuildData->GetFaceSmoothingGroups(NextFace.FaceIndex) & BuildData->GetFaceSmoothingGroups(OtherFace.FaceIndex))) + int32 CommonVertices = 0; + int32 CommonNormalVertices = 0; + for (int32 OtherCornerIndex = 0; OtherCornerIndex < 3; OtherCornerIndex++) { - int32 CommonVertices = 0; - int32 CommonNormalVertices = 0; - for (int32 OtherCornerIndex = 0; OtherCornerIndex < 3; OtherCornerIndex++) + for (int32 NextCornerIndex = 0; NextCornerIndex < 3; NextCornerIndex++) { - for (int32 NextCornerIndex = 0; NextCornerIndex < 3; NextCornerIndex++) + int32 NextVertexIndex = BuildData->GetVertexIndex(NextFace.FaceIndex, NextCornerIndex); + int32 OtherVertexIndex = BuildData->GetVertexIndex(OtherFace.FaceIndex, OtherCornerIndex); + if (PointsEqual( + BuildData->GetVertexPosition(NextFace.FaceIndex, NextCornerIndex), + BuildData->GetVertexPosition(OtherFace.FaceIndex, OtherCornerIndex), + ComparisonThreshold)) { - int32 NextVertexIndex = BuildData->GetVertexIndex(NextFace.FaceIndex, NextCornerIndex); - int32 OtherVertexIndex = BuildData->GetVertexIndex(OtherFace.FaceIndex, OtherCornerIndex); - if (PointsEqual( - BuildData->GetVertexPosition(NextFace.FaceIndex, NextCornerIndex), - BuildData->GetVertexPosition(OtherFace.FaceIndex, OtherCornerIndex), - ComparisonThreshold)) + CommonVertices++; + if (bBlendOverlappingNormals + || NextVertexIndex == OtherVertexIndex) { - CommonVertices++; - if (bBlendOverlappingNormals - || NextVertexIndex == OtherVertexIndex) - { - CommonNormalVertices++; - } + CommonNormalVertices++; } } } - // Flood fill faces with more than one common vertices which must be touching edges. - if (CommonVertices > 1) - { - NextFace.bFilled = true; - NextFace.bBlendNormals = (CommonNormalVertices > 1); - NewConnections++; - } + } + // Flood fill faces with more than one common vertices which must be touching edges. + if (CommonVertices > 1) + { + NextFace.bFilled = true; + NextFace.bBlendNormals = (CommonNormalVertices > 1); + NewConnections++; } } } } } - } - while (NewConnections > 0); - } + } + } + while (NewConnections > 0); + } - // Vertex normal construction. - for (int32 CornerIndex = 0; CornerIndex < 3; CornerIndex++) + // Vertex normal construction. + for (int32 CornerIndex = 0; CornerIndex < 3; CornerIndex++) + { + if (bCornerHasNormal[CornerIndex]) { - if (bCornerHasNormal[CornerIndex]) + CornerNormal[CornerIndex] = WedgeTangentZ[WedgeOffset + CornerIndex]; + } + else + { + for (int32 RelevantFaceIdx = 0; RelevantFaceIdx < RelevantFacesForCorner[CornerIndex].Num(); RelevantFaceIdx++) + { + FFanFace const& RelevantFace = RelevantFacesForCorner[CornerIndex][RelevantFaceIdx]; + if (RelevantFace.bFilled) + { + int32 OtherFaceIndex = RelevantFace.FaceIndex; + if (RelevantFace.bBlendNormals) + { + CornerNormal[CornerIndex] += TriangleTangentZ[OtherFaceIndex]; + } + } + } + if (!WedgeTangentZ[WedgeOffset + CornerIndex].IsZero()) { CornerNormal[CornerIndex] = WedgeTangentZ[WedgeOffset + CornerIndex]; } - else - { - for (int32 RelevantFaceIdx = 0; RelevantFaceIdx < RelevantFacesForCorner[CornerIndex].Num(); RelevantFaceIdx++) - { - FFanFace const& RelevantFace = RelevantFacesForCorner[CornerIndex][RelevantFaceIdx]; - if (RelevantFace.bFilled) - { - int32 OtherFaceIndex = RelevantFace.FaceIndex; - if (RelevantFace.bBlendNormals) - { - CornerNormal[CornerIndex] += TriangleTangentZ[OtherFaceIndex]; - } - } - } - if (!WedgeTangentZ[WedgeOffset + CornerIndex].IsZero()) - { - CornerNormal[CornerIndex] = WedgeTangentZ[WedgeOffset + CornerIndex]; - } - } } + } - // Normalization. - for (int32 CornerIndex = 0; CornerIndex < 3; CornerIndex++) - { - CornerNormal[CornerIndex].Normalize(); - } + // Normalization. + for (int32 CornerIndex = 0; CornerIndex < 3; CornerIndex++) + { + CornerNormal[CornerIndex].Normalize(); + } - // Copy back to the mesh. - for (int32 CornerIndex = 0; CornerIndex < 3; CornerIndex++) - { - WedgeTangentZ[WedgeOffset + CornerIndex] = CornerNormal[CornerIndex]; - } + // Copy back to the mesh. + for (int32 CornerIndex = 0; CornerIndex < 3; CornerIndex++) + { + WedgeTangentZ[WedgeOffset + CornerIndex] = CornerNormal[CornerIndex]; } } @@ -5857,11 +5898,10 @@ void FMeshUtilities::ExportStaticMeshLOD(const FStaticMeshLODResources& StaticMe const bool IsLandscapeHit(const FVector& RayOrigin, const FVector& RayEndPoint, const UWorld* World, const TArray& LandscapeProxies, FVector& OutHitLocation) { - static FName TraceTag = FName(TEXT("LandscapeTrace")); TArray Results; // Each landscape component has 2 collision shapes, 1 of them is specific to landscape editor // Trace only ECC_Visibility channel, so we do hit only Editor specific shape - World->LineTraceMultiByObjectType(Results, RayOrigin, RayEndPoint, FCollisionObjectQueryParams(ECollisionChannel::ECC_Visibility), FCollisionQueryParams(TraceTag, true)); + World->LineTraceMultiByObjectType(Results, RayOrigin, RayEndPoint, FCollisionObjectQueryParams(ECollisionChannel::ECC_Visibility), FCollisionQueryParams(SCENE_QUERY_STAT(LandscapeTrace), true)); bool bHitLandscape = false; @@ -6253,7 +6293,7 @@ bool FMeshUtilities::ConstructRawMesh( const FMeshBuildSettings& BuildSettings = bImportedMesh ? SourceStaticMeshModel.BuildSettings : SourceStaticMesh->SourceModels[0].BuildSettings; // Transform raw mesh to world space - FTransform ComponentToWorldTransform = InMeshComponent->ComponentToWorld; + FTransform ComponentToWorldTransform = InMeshComponent->GetComponentTransform(); // Take into account build scale settings only for meshes imported from raw data // meshes reconstructed from render data already have build scale applied if (bImportedMesh) @@ -6578,7 +6618,7 @@ static void ExtractPhysicsGeometry(UStaticMeshComponent* InMeshComponent, FKAggr } // Transform geometry to world space - FTransform CtoM = InMeshComponent->ComponentToWorld; + FTransform CtoM = InMeshComponent->GetComponentTransform(); TransformPhysicsGeometry(CtoM, OutAggGeom); } @@ -6965,7 +7005,7 @@ void FMeshUtilities::MergeStaticMeshComponents(const TArrayComponentToWorld.GetLocation(); + MergedAssetPivot = InSettings.bPivotPointAtZero ? FVector::ZeroVector : MeshComponent->GetComponentTransform().GetLocation(); // Source mesh asset package name MergedAssetPackageName = MeshComponent->GetStaticMesh()->GetOutermost()->GetName(); } @@ -7956,7 +7996,21 @@ void FMeshUtilities::CalculateTangents(const TArray& InVertices, const TMultiMap OverlappingCorners; FindOverlappingCorners(OverlappingCorners, InVertices, InIndices, ComparisonThreshold); - ComputeTangents(InVertices, InIndices, InUVs, InSmoothingGroupIndices, OverlappingCorners, OutTangentX, OutTangentY, OutNormals, InTangentOptions); + + if ( InTangentOptions & ETangentOptions::UseMikkTSpace ) + { + ComputeTangents_MikkTSpace(InVertices, InIndices, InUVs, InSmoothingGroupIndices, OverlappingCorners, OutTangentX, OutTangentY, OutNormals, InTangentOptions); + } + else + { + ComputeTangents(InVertices, InIndices, InUVs, InSmoothingGroupIndices, OverlappingCorners, OutTangentX, OutTangentY, OutNormals, InTangentOptions); + } +} + +void FMeshUtilities::CalculateOverlappingCorners(const TArray& InVertices, const TArray& InIndices, bool bIgnoreDegenerateTriangles, TMultiMap& OutOverlappingCorners) const +{ + const float ComparisonThreshold = bIgnoreDegenerateTriangles ? THRESH_POINTS_ARE_SAME : 0.f; + FindOverlappingCorners(OutOverlappingCorners, InVertices, InIndices, ComparisonThreshold); } void FMeshUtilities::AddAnimationBlueprintEditorToolbarExtender() diff --git a/Engine/Source/Developer/MeshUtilities/Private/MeshUtilitiesPrivate.h b/Engine/Source/Developer/MeshUtilities/Private/MeshUtilitiesPrivate.h index 06088f64a566..8381a13f396e 100644 --- a/Engine/Source/Developer/MeshUtilities/Private/MeshUtilitiesPrivate.h +++ b/Engine/Source/Developer/MeshUtilities/Private/MeshUtilitiesPrivate.h @@ -225,6 +225,7 @@ private: virtual bool RemoveBonesFromMesh(USkeletalMesh* SkeletalMesh, int32 LODIndex, const TArray* BoneNamesToRemove) const override; virtual void CalculateTangents(const TArray& InVertices, const TArray& InIndices, const TArray& InUVs, const TArray& InSmoothingGroupIndices, const uint32 InTangentOptions, TArray& OutTangentX, TArray& OutTangentY, TArray& OutNormals) const override; + virtual void CalculateOverlappingCorners(const TArray& InVertices, const TArray& InIndices, bool bIgnoreDegenerateTriangles, TMultiMap& OutOverlappingCorners) const override; // Need to call some members from this class, (which is internal to this module) friend class FStaticMeshUtilityBuilder; @@ -272,4 +273,4 @@ protected: FDelegateHandle SkeletonEditorExtenderHandle; }; -DEFINE_LOG_CATEGORY_STATIC(LogMeshUtilities, Verbose, All); \ No newline at end of file +DECLARE_LOG_CATEGORY_EXTERN(LogMeshUtilities, Verbose, All); \ No newline at end of file diff --git a/Engine/Source/Developer/MeshUtilities/Public/MeshUtilities.h b/Engine/Source/Developer/MeshUtilities/Public/MeshUtilities.h index 8dae9952cea3..571100e62309 100644 --- a/Engine/Source/Developer/MeshUtilities/Public/MeshUtilities.h +++ b/Engine/Source/Developer/MeshUtilities/Public/MeshUtilities.h @@ -31,6 +31,7 @@ namespace ETangentOptions None = 0, BlendOverlappingNormals = 0x1, IgnoreDegenerateTriangles = 0x2, + UseMikkTSpace = 0x4, }; }; @@ -106,6 +107,8 @@ struct FMergeCompleteData class IMeshMerging { public: + virtual ~IMeshMerging() { } + virtual void ProxyLOD(const TArray& InData, const struct FMeshProxySettings& InProxySettings, const TArray& InputMaterials, @@ -477,4 +480,14 @@ public: * @param OutNormals Array to hold calculated normals (if already contains normals will use those instead for the tangent calculation */ virtual void CalculateTangents(const TArray& InVertices, const TArray& InIndices, const TArray& InUVs, const TArray& InSmoothingGroupIndices, const uint32 InTangentOptions, TArray& OutTangentX, TArray& OutTangentY, TArray& OutNormals) const = 0; + + /** + * Calculates the overlapping corners for a given set of vertex data + * + * @param InVertices Vertices that make up the mesh + * @param InIndices Indices for the Vertex array + * @param bIgnoreDegenerateTriangles Indicates if we should skip degenerate triangles + * @param OutOverlappingCorners MultiMap to hold the overlapping corners. For a vertex, lists all the overlapping vertices. + */ + virtual void CalculateOverlappingCorners(const TArray& InVertices, const TArray& InIndices, bool bIgnoreDegenerateTriangles, TMultiMap& OutOverlappingCorners) const = 0; }; diff --git a/Engine/Source/Developer/OutputLog/Private/SOutputLog.cpp b/Engine/Source/Developer/OutputLog/Private/SOutputLog.cpp index 3d693972691f..37bfcad5eade 100644 --- a/Engine/Source/Developer/OutputLog/Private/SOutputLog.cpp +++ b/Engine/Source/Developer/OutputLog/Private/SOutputLog.cpp @@ -941,16 +941,18 @@ bool SOutputLog::CreateLogMessages( const TCHAR* V, ELogVerbosity::Type Verbosit } else { + // Get the style for this message. When piping output from child processes (eg. when cooking through the editor), we want to highlight messages + // according to their original verbosity, so also check for "Error:" and "Warning:" substrings. This is consistent with how the build system processes logs. FName Style; if (Category == NAME_Cmd) { Style = FName(TEXT("Log.Command")); } - else if (Verbosity == ELogVerbosity::Error) + else if (Verbosity == ELogVerbosity::Error || FCString::Stristr(V, TEXT("Error:")) != nullptr) { Style = FName(TEXT("Log.Error")); } - else if (Verbosity == ELogVerbosity::Warning) + else if (Verbosity == ELogVerbosity::Warning || FCString::Stristr(V, TEXT("Warning:")) != nullptr) { Style = FName(TEXT("Log.Warning")); } diff --git a/Engine/Source/Developer/PackageDependencyInfo/Private/PackageDependencyInfo.cpp b/Engine/Source/Developer/PackageDependencyInfo/Private/PackageDependencyInfo.cpp index 64501c2d4fff..f2a80640c073 100644 --- a/Engine/Source/Developer/PackageDependencyInfo/Private/PackageDependencyInfo.cpp +++ b/Engine/Source/Developer/PackageDependencyInfo/Private/PackageDependencyInfo.cpp @@ -823,9 +823,6 @@ void FPackageDependencyInfo::DetermineShaderSourceTimeStamp() { ShaderSourceTimeStamp = FDateTime::MinValue(); - // Get all the shader source files - FString ShaderSourceDirectory = FPlatformProcess::ShaderDir(); - // use the timestamp grabbing visitor (include directories) TArray DirectoriesWildcards; TArray DirectoriesToIgnore; @@ -834,7 +831,10 @@ void FPackageDependencyInfo::DetermineShaderSourceTimeStamp() FileWildcards.Add(TEXT(".usf")); FPackageDependencyTimestampVisitor TimeStampVisitor(FPlatformFileManager::Get().GetPlatformFile(), DirectoriesWildcards, DirectoriesToIgnore, DirectoriesToNotRecurse, FileWildcards, false, true); - TimeStampVisitor.Visit(*ShaderSourceDirectory, true); + for (FString ShaderDir : FPlatformProcess::AllShaderDirs()) + { + TimeStampVisitor.Visit(*ShaderDir, true); + } FMD5 AllShaderHash; TimeStampVisitor.FileTimes.KeySort(TLess()); @@ -932,77 +932,6 @@ void FPackageDependencyInfo::DetermineScriptSourceTimeStamp() #endif } -void FPackageDependencyInfo::DetermineScriptSourceTimeStamp(FString PathName) -{ - FDateTime OutNewestTime = FDateTime::MinValue(); - - - FString ScriptLongPackageName = FString::Printf(TEXT("/Script%s"), *PathName); - - FString ScriptSourceDirectory; - if ( FPackageName::ConvertRootPathToContentPath(PathName, ScriptSourceDirectory) == false) - { - UE_LOG(LogPackageDependencyInfo, Display, TEXT("Unable to convert %s to source directory unable to register script source hashes"), *ScriptLongPackageName); - return; - } - ScriptSourceDirectory = ScriptSourceDirectory.Replace( TEXT("Content"), TEXT("Source")); - - if ( ScriptSourceDirectory.Contains(TEXT("Source")) == false ) - { - ScriptSourceDirectory /= TEXT("Source"); - } - - if ( FPlatformFileManager::Get().GetPlatformFile().DirectoryExists(*ScriptSourceDirectory) ) - { - UE_LOG(LogPackageDependencyInfo, Display, TEXT("Unable to find %s directory unable to register script source hashes for %s"), *ScriptSourceDirectory, *ScriptLongPackageName); - return; - } - - // use the timestamp grabbing visitor (include directories) - TArray DirectoriesWildcards; - DirectoriesWildcards.Add(TEXT("Classes/")); // @todo uht: Now scanning Public and Private folders, as well as Classes folder - DirectoriesWildcards.Add(TEXT("Public/")); - DirectoriesWildcards.Add(TEXT("Private/")); - TArray DirectoriesToIgnore; - TArray DirectoriesToNotRecurse; - TArray FileWildcards; - FileWildcards.Add(TEXT(".h")); - - FPackageDependencyTimestampVisitor TimeStampVisitor(FPlatformFileManager::Get().GetPlatformFile(), DirectoriesWildcards, DirectoriesToIgnore, DirectoriesToNotRecurse, FileWildcards, false, true); - - TimeStampVisitor.Visit(*ScriptSourceDirectory, true); - - if (TimeStampVisitor.FileTimes.Num() == 0) - { - return; - } - - TimeStampVisitor.FileTimes.KeySort(TLess()); - FMD5 ScriptMD5; - for (TMap::TIterator It(TimeStampVisitor.FileTimes); It; ++It) - { - FString ScriptFilename = It.Key(); - // It's a 'script' file - FDateTime ScriptTimestamp = It.Value().TimeStamp; - if (ScriptTimestamp > OutNewestTime) - { - OutNewestTime = ScriptTimestamp; - } - - FMD5Hash Hash = It.Value().Hash; - - ScriptMD5.Update(Hash.GetBytes(), Hash.GetSize()); - } - - FMD5Hash ScriptHash; - ScriptHash.Set(ScriptMD5); - FPackageDependencyTrackingInfo* ScriptSourceInfo = new FPackageDependencyTrackingInfo( ScriptLongPackageName, OutNewestTime ); - ScriptSourceInfo->DependentTimeStamp = OutNewestTime; - ScriptSourceInfo->FullPackageHash = ScriptHash; - - PackageInformation.Add(ScriptLongPackageName, ScriptSourceInfo); -} - void FPackageDependencyInfo::DetermineScriptSourceTimeStampForModule(const FString& ModuleName, const FString& ModuleSourcePath ) { #if 0 @@ -1199,7 +1128,8 @@ bool FPackageDependencyInfo::DeterminePackageDependencies(FPackageDependencyTrac } } // Start off with setting the dependent time to the package itself - PkgInfo->TimeStamp = PkgInfo->TimeStamp; + // PVS-Studio reports this as a warning because it's a no-op + // PkgInfo->TimeStamp = PkgInfo->TimeStamp; // Map? Code (ie blueprint)? PkgInfo->bContainsMap = Linker->ContainsMap(); diff --git a/Engine/Source/Developer/PackageDependencyInfo/Private/PackageDependencyInfoPrivate.h b/Engine/Source/Developer/PackageDependencyInfo/Private/PackageDependencyInfoPrivate.h index f01b266f2051..220383e90621 100644 --- a/Engine/Source/Developer/PackageDependencyInfo/Private/PackageDependencyInfoPrivate.h +++ b/Engine/Source/Developer/PackageDependencyInfo/Private/PackageDependencyInfoPrivate.h @@ -122,14 +122,6 @@ protected: bool DeterminePackageDependencies( FPackageDependencyTrackingInfo* PkgInfo, TSet& AllTouchedPackages ); - - /** - * Determine newest script source file in the path given (engine, game, uplugin) - * - * @param Path root path of the plugin / engine - */ - void DetermineScriptSourceTimeStamp(FString Path); - /** Prep the content package list - ie gather the list of all content files and their actual timestamps */ void PrepContentPackageTimeStamps(); diff --git a/Engine/Source/Developer/Profiler/Private/ProfilerRawStatsForThreadView.cpp b/Engine/Source/Developer/Profiler/Private/ProfilerRawStatsForThreadView.cpp index ca2680f2128a..ed69236d1142 100644 --- a/Engine/Source/Developer/Profiler/Private/ProfilerRawStatsForThreadView.cpp +++ b/Engine/Source/Developer/Profiler/Private/ProfilerRawStatsForThreadView.cpp @@ -70,16 +70,12 @@ static double GetSecondsPerCycle( const FStatPacketArray& Frame ) const FName SecondsPerCycleRawName = FStatConstants::RAW_SecondsPerCycle; double Result = 0; - for( int32 PacketIndex = 0; PacketIndex < Frame.Packets.Num(); PacketIndex++ ) + for( const FStatPacket* Packet : Frame.Packets ) { - const FStatPacket& Packet = *Frame.Packets[PacketIndex]; - const FStatMessagesArray& Data = Packet.StatMessages; - - if( Packet.ThreadType == EThreadType::Game ) + if( Packet->ThreadType == EThreadType::Game ) { - for( int32 Index = 0; Index < Data.Num(); Index++ ) + for( const FStatMessage& Item : Packet->StatMessages ) { - const FStatMessage& Item = Data[Index]; check( Item.NameAndInfo.GetFlag( EStatMetaFlags::DummyAlwaysOne ) ); const FName LongName = Item.NameAndInfo.GetEncodedName(); @@ -89,13 +85,13 @@ static double GetSecondsPerCycle( const FStatPacketArray& Frame ) Result = Item.GetValue_double(); UE_LOG( LogStats, Log, TEXT( "STAT_SecondsPerCycle is %f [ns]" ), Result*1000*1000 ); - PacketIndex = Frame.Packets.Num(); - break; + goto BreakPacketLoop; } - } + } } - } +BreakPacketLoop:; + return Result; } @@ -103,16 +99,13 @@ static int64 GetFastThreadFrameTimeInternal( const FStatPacketArray& Frame, EThr { int64 Result = 0; - for( int32 PacketIndex = 0; PacketIndex < Frame.Packets.Num(); PacketIndex++ ) + for( const FStatPacket* Packet : Frame.Packets ) { - const FStatPacket& Packet = *Frame.Packets[PacketIndex]; - - if( Packet.ThreadType == ThreadType ) + if( Packet->ThreadType == ThreadType ) { - const FStatMessagesArray& Data = Packet.StatMessages; - for (int32 Index = 0; Index < Data.Num(); Index++) + const FStatMessagesArray& Data = Packet->StatMessages; + for (FStatMessage const& Item : Data) { - FStatMessage const& Item = Data[Index]; EStatOperation::Type Op = Item.NameAndInfo.GetField(); FName LongName = Item.NameAndInfo.GetRawName(); if (Op == EStatOperation::CycleScopeStart) @@ -441,11 +434,8 @@ void FRawProfilerSession::ProcessStatPacketArray( const FStatPacketArray& StatPa Stack.Add( ThreadNode ); FProfilerStackNode* Current = Stack.Last(); - const FStatMessagesArray& Data = StatPacket.StatMessages; - for (int32 Index = 0; Index < Data.Num(); Index++) + for (const FStatMessage& Item : StatPacket.StatMessages) { - const FStatMessage& Item = Data[Index]; - const EStatOperation::Type Op = Item.NameAndInfo.GetField(); const FName LongName = Item.NameAndInfo.GetRawName(); const FName ShortName = Item.NameAndInfo.GetShortName(); diff --git a/Engine/Source/Developer/Profiler/Private/Widgets/SEventGraph.cpp b/Engine/Source/Developer/Profiler/Private/Widgets/SEventGraph.cpp index 2e3ad40ebd90..447a12023477 100644 --- a/Engine/Source/Developer/Profiler/Private/Widgets/SEventGraph.cpp +++ b/Engine/Source/Developer/Profiler/Private/Widgets/SEventGraph.cpp @@ -10,6 +10,7 @@ #include "Widgets/Images/SImage.h" #include "Framework/MultiBox/MultiBoxBuilder.h" #include "Widgets/Input/SButton.h" +#include "Widgets/Input/SComboBox.h" #include "Widgets/Input/SComboButton.h" #include "Widgets/Input/SCheckBox.h" #include "EditorStyleSet.h" @@ -647,27 +648,44 @@ void SEventGraph::Construct( const FArguments& InArgs ) .BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder")) .Padding(2.0f) [ - SNew(SHorizontalBox) + SNew(SVerticalBox) - + SHorizontalBox::Slot() - .AutoWidth() - [ - GetWidgetForEventGraphTypes() - ] + + SVerticalBox::Slot() + [ + SNew(SHorizontalBox) - + SHorizontalBox::Slot() - .AutoWidth() - .Padding(2.0f, 0.0f, 0.0f, 0.0f) - [ - GetWidgetForEventGraphViewModes() - ] + + SHorizontalBox::Slot() + .AutoWidth() + [ + GetWidgetForEventGraphTypes() + ] - + SHorizontalBox::Slot() + + SHorizontalBox::Slot() + .AutoWidth() + .Padding(2.0f, 0.0f, 0.0f, 0.0f) + [ + GetWidgetForEventGraphViewModes() + ] + + + SHorizontalBox::Slot() + .FillWidth(1.0f) + .Padding(2.0f, 0.0f, 0.0f, 0.0f) + [ + GetWidgetBoxForOptions() + ] + ] + + + SVerticalBox::Slot() + .Padding(0.0f, 2.0f, 0.0f, 0.0f) + [ + SNew(SHorizontalBox) + + + SHorizontalBox::Slot() .FillWidth(1.0f) - .Padding(2.0f, 0.0f, 0.0f, 0.0f) [ - GetWidgetBoxForOptions() + GetWidgetForThreadFilter() ] + ] ] ] @@ -988,6 +1006,113 @@ TSharedRef SEventGraph::GetWidgetForEventGraphViewModes() ]; } +TSharedRef SEventGraph::GetWidgetForThreadFilter() +{ + return SNew(SBorder) + .BorderImage(FEditorStyle::GetBrush("Profiler.Group.16")) + .Padding(FMargin(2.0f, 0.0)) + [ + SNew(SHorizontalBox) + + +SHorizontalBox::Slot() + .HAlign( HAlign_Center ) + .VAlign( VAlign_Center ) + .AutoWidth() + .Padding( 2.0f ) + [ + SNew ( STextBlock ) + .Text( LOCTEXT( "Toolbar_Thread", "Thread" ) ) + .TextStyle( FEditorStyle::Get(), TEXT( "Profiler.CaptionBold" ) ) + ] + + +SHorizontalBox::Slot() + .HAlign( HAlign_Center ) + .VAlign( VAlign_Fill ) + .AutoWidth() + .Padding( 2.0f ) + [ + SAssignNew( ThreadFilterComboBox, SComboBox> ) + .ContentPadding( FMargin( 6.0f, 2.0f ) ) + .OptionsSource( &ThreadNamesForCombo ) + .OnSelectionChanged( this, &SEventGraph::OnThreadFilterChanged ) + .OnGenerateWidget( this, &SEventGraph::OnGenerateWidgetForThreadFilter ) + [ + SNew( STextBlock ) + .Text( this, &SEventGraph::GenerateTextForThreadFilter, FName( TEXT( "SelectedThreadName" ) ) ) + ] + ] + ]; +} + +void SEventGraph::FillThreadFilterOptions() +{ + ThreadNamesForCombo.Empty(); + + // Allow None as an option + ThreadNamesForCombo.Add(MakeShareable(new FName())); + + if ( EventGraphStatesHistory.Num() == 0 ) + { + return; + } + + FEventGraphSamplePtr Root = GetCurrentState()->GetRoot(); + if ( !Root.IsValid() ) + { + return; + } + + // Add a thread filter entry for each root child + for ( const FEventGraphSamplePtr Child : Root->GetChildren() ) + { + ThreadNamesForCombo.Add( MakeShareable( new FName( Child->_ThreadName ) ) ); + } + + // Sort the thread names alphabetically + ThreadNamesForCombo.Sort([]( const TSharedPtr Lhs, const TSharedPtr Rhs ) + { + return Lhs->IsNone() || ( !Rhs->IsNone() && *Lhs < *Rhs ); + }); + + // Refresh the combo box + if ( ThreadFilterComboBox.IsValid() ) + { + ThreadFilterComboBox->RefreshOptions(); + } +} + +FText SEventGraph::GenerateTextForThreadFilter( FName ThreadName ) const +{ + static const FName SelectedThreadName( TEXT( "SelectedThreadName" ) ); + if ( ThreadName == SelectedThreadName ) + { + if ( EventGraphStatesHistory.Num() > 0 ) + { + ThreadName = GetCurrentState()->ThreadFilter; + } + else + { + ThreadName = NAME_None; + } + } + return FText::FromName( ThreadName ); +} + +void SEventGraph::OnThreadFilterChanged( TSharedPtr NewThread, ESelectInfo::Type SelectionType ) +{ + if ( NewThread.IsValid() ) + { + GetCurrentState()->ThreadFilter = *NewThread; + RestoreEventGraphStateFrom( GetCurrentState() ); + GetCurrentState()->GetRoot()->SetBooleanStateForAllChildren(true); + } +} + +TSharedRef SEventGraph::OnGenerateWidgetForThreadFilter( TSharedPtr ThreadName ) const +{ + return SNew( STextBlock ) + .Text( GenerateTextForThreadFilter( ThreadName.IsValid() ? *ThreadName : NAME_None ) ); +} TSharedRef SEventGraph::GetWidgetBoxForOptions() { @@ -2860,6 +2985,7 @@ void SEventGraph::SetNewEventGraphState( const FEventGraphDataRef AverageEventGr FEventGraphState* Op = new FEventGraphState( AverageEventGraph->DuplicateAsRef(), MaximumEventGraph->DuplicateAsRef() ); CurrentStateIndex = EventGraphStatesHistory.Add( MakeShareable(Op) ); RestoreEventGraphStateFrom( GetCurrentState(), bInitial ); + FillThreadFilterOptions(); } FReply SEventGraph::HistoryBack_OnClicked() diff --git a/Engine/Source/Developer/Profiler/Private/Widgets/SEventGraph.h b/Engine/Source/Developer/Profiler/Private/Widgets/SEventGraph.h index 08690fa20ba5..8b168960b181 100644 --- a/Engine/Source/Developer/Profiler/Private/Widgets/SEventGraph.h +++ b/Engine/Source/Developer/Profiler/Private/Widgets/SEventGraph.h @@ -28,6 +28,8 @@ typedef TSharedPtr FEventGraphColumnPtr; /** Type definition for shared references to instances of FEventGraphColumn. */ typedef TSharedRef FEventGraphColumnRef; +template +class SComboBox; /** Enumerates event graph view modes. */ @@ -756,6 +758,9 @@ protected: /** Whether aggressive filtering is currently on */ bool bAggressiveFiltering; + /** Event Filter by thread name */ + FName ThreadFilter; + void CreateOneToOneMapping(); const bool IsCulled() const @@ -1062,6 +1067,7 @@ protected: { FEventGraphData *NewData = new FEventGraphData(GetEventGraph().Get()); RebuildForFilter(NewData->GetRoot()->GetChildren()); + delete NewData; } else { @@ -1083,6 +1089,23 @@ protected: EEventCompareOps::Less ); } + else if (!ThreadFilter.IsNone()) + { + // Filter by event Thread name + struct FFilterByThreadName + { + FFilterByThreadName(const FName InThreadName) : ThreadName(InThreadName) {} + + void operator()(FEventGraphSample* InEventPtr) + { + InEventPtr->_bIsFiltered = InEventPtr->GetThread() != nullptr && InEventPtr->_ThreadName != ThreadName; + InEventPtr->_bIsCulled = InEventPtr->GetThread() != nullptr && InEventPtr->_ThreadName != ThreadName; + } + + FName ThreadName; + }; + GetRoot()->ExecuteOperationForAllChildren(FFilterByThreadName(ThreadFilter)); + } else { // Reset filtering. @@ -1245,4 +1268,14 @@ protected: /** Name of the event that should be drawn as highlighted. */ FName HighlightedEventName; + + /** ThreadName filter methods and data */ + void FillThreadFilterOptions(); + FText GenerateTextForThreadFilter( FName ThreadName ) const; + void OnThreadFilterChanged( TSharedPtr NewThread, ESelectInfo::Type SelectionType ); + TSharedRef GetWidgetForThreadFilter(); + TSharedRef OnGenerateWidgetForThreadFilter( TSharedPtr ThreadName ) const; + + TSharedPtr>> ThreadFilterComboBox; + TArray> ThreadNamesForCombo; }; diff --git a/Engine/Source/Developer/ProfilerClient/Private/ProfilerClientManager.cpp b/Engine/Source/Developer/ProfilerClient/Private/ProfilerClientManager.cpp index b5fdc54f1083..1683474052fb 100644 --- a/Engine/Source/Developer/ProfilerClient/Private/ProfilerClientManager.cpp +++ b/Engine/Source/Developer/ProfilerClient/Private/ProfilerClientManager.cpp @@ -166,11 +166,8 @@ void FProfilerClientManager::SetCaptureState(const bool bRequestedCaptureState, } else { - const FMessageAddress* MessageAddress = &Connections.Find(InstanceId)->ProfilerServiceAddress; - if(MessageAddress) - { - MessageEndpoint->Send(new FProfilerServiceCapture(bRequestedCaptureState), *MessageAddress); - } + const FMessageAddress& MessageAddress = Connections.Find(InstanceId)->ProfilerServiceAddress; + MessageEndpoint->Send(new FProfilerServiceCapture(bRequestedCaptureState), MessageAddress); UE_LOG(LogProfilerClient, Verbose, TEXT("SetCaptureState Session: %s, Instance: %s, State: %i"), *ActiveSessionId.ToString(), *InstanceId.ToString(), (int32)bRequestedCaptureState); } @@ -196,11 +193,8 @@ void FProfilerClientManager::SetPreviewState(const bool bRequestedPreviewState, } else { - const FMessageAddress* MessageAddress = &Connections.Find(InstanceId)->ProfilerServiceAddress; - if(MessageAddress) - { - MessageEndpoint->Send(new FProfilerServicePreview(bRequestedPreviewState), *MessageAddress); - } + const FMessageAddress& MessageAddress = Connections.Find(InstanceId)->ProfilerServiceAddress; + MessageEndpoint->Send(new FProfilerServicePreview(bRequestedPreviewState), MessageAddress); UE_LOG(LogProfilerClient, Verbose, TEXT("SetPreviewState Session: %s, Instance: %s, State: %i"), *ActiveSessionId.ToString(), *InstanceId.ToString(), (int32)bRequestedPreviewState); } } @@ -340,11 +334,8 @@ void FProfilerClientManager::RequestLastCapturedFile(const FGuid& InstanceId /*= } else { - const FMessageAddress* MessageAddress = &Connections.Find(InstanceId)->ProfilerServiceAddress; - if(MessageAddress) - { - MessageEndpoint->Send(new FProfilerServiceRequest(EProfilerRequestType::PRT_SendLastCapturedFile), *MessageAddress); - } + const FMessageAddress& MessageAddress = Connections.Find(InstanceId)->ProfilerServiceAddress; + MessageEndpoint->Send(new FProfilerServiceRequest(EProfilerRequestType::PRT_SendLastCapturedFile), MessageAddress); } } #endif diff --git a/Engine/Source/Developer/SettingsEditor/Private/SettingsEditorModule.cpp b/Engine/Source/Developer/SettingsEditor/Private/SettingsEditorModule.cpp index 35dab4d6f293..0435d6d340b4 100644 --- a/Engine/Source/Developer/SettingsEditor/Private/SettingsEditorModule.cpp +++ b/Engine/Source/Developer/SettingsEditor/Private/SettingsEditorModule.cpp @@ -230,10 +230,10 @@ private: if ( UDeveloperSettings* Settings = *SettingsIt ) { // Only Add the CDO of any UDeveloperSettings objects. - if ( Settings->HasAnyFlags(RF_ClassDefaultObject) && !Settings->GetClass()->HasAnyCastFlag(CLASS_Deprecated) ) + if ( Settings->HasAnyFlags(RF_ClassDefaultObject) && !Settings->GetClass()->HasAnyClassFlags(CLASS_Deprecated | CLASS_Abstract) ) { // Ignore the setting if it's specifically the UDeveloperSettings or other abstract settings classes - if ( Settings->GetClass()->HasAnyClassFlags(CLASS_Abstract) || !Settings->SupportsAutoRegistration()) + if ( Settings->GetClass()->HasAnyClassFlags(CLASS_Abstract) || !Settings->SupportsAutoRegistration() ) { continue; } diff --git a/Engine/Source/Developer/ShaderCompilerCommon/Private/HlslUtils.h b/Engine/Source/Developer/ShaderCompilerCommon/Private/HlslUtils.h index 5c859e62374c..90c6ea8d8a68 100644 --- a/Engine/Source/Developer/ShaderCompilerCommon/Private/HlslUtils.h +++ b/Engine/Source/Developer/ShaderCompilerCommon/Private/HlslUtils.h @@ -136,7 +136,7 @@ namespace CrossCompiler { // Allocate memory from the stack. Data = (ElementType*)LinearAllocator->Alloc(NumElements * NumBytesPerElement, - FMath::Max((uint32)sizeof(void*), (uint32)ALIGNOF(ElementType)) + FMath::Max((uint32)sizeof(void*), (uint32)alignof(ElementType)) ); // If the container previously held elements, copy them into the new allocation. diff --git a/Engine/Source/Developer/ShaderCompilerCommon/Public/ShaderCompilerCommon.h b/Engine/Source/Developer/ShaderCompilerCommon/Public/ShaderCompilerCommon.h index cf9e12964eda..46c316c6188d 100644 --- a/Engine/Source/Developer/ShaderCompilerCommon/Public/ShaderCompilerCommon.h +++ b/Engine/Source/Developer/ShaderCompilerCommon/Public/ShaderCompilerCommon.h @@ -93,6 +93,7 @@ namespace CrossCompiler struct SHADERCOMPILERCOMMON_API FHlslccHeader { FHlslccHeader(); + virtual ~FHlslccHeader() { } bool Read(const ANSICHAR*& ShaderSource, int32 SourceLen); diff --git a/Engine/Source/Developer/ShaderFormatOpenGL/Private/GlslBackend.cpp b/Engine/Source/Developer/ShaderFormatOpenGL/Private/GlslBackend.cpp index 93269961ddd9..dea8b49376c9 100644 --- a/Engine/Source/Developer/ShaderFormatOpenGL/Private/GlslBackend.cpp +++ b/Engine/Source/Developer/ShaderFormatOpenGL/Private/GlslBackend.cpp @@ -3431,7 +3431,7 @@ struct SPromoteSampleLevelES2 : public ir_hierarchical_visitor // Converts an array index expression using an integer input attribute, to a float input attribute using a conversion to int -struct SConvertIntVertexAttributeES2 : public ir_hierarchical_visitor +struct SConvertIntVertexAttributeES2 final : public ir_hierarchical_visitor { _mesa_glsl_parse_state* ParseState; exec_list* FunctionBody; @@ -3442,6 +3442,10 @@ struct SConvertIntVertexAttributeES2 : public ir_hierarchical_visitor { } + virtual ~SConvertIntVertexAttributeES2() + { + } + virtual ir_visitor_status visit_enter(ir_dereference_array* DeRefArray) override { // Break the array dereference so we know we want to modify the array index part diff --git a/Engine/Source/Developer/ShaderFormatOpenGL/Private/OpenGLShaderCompiler.cpp b/Engine/Source/Developer/ShaderFormatOpenGL/Private/OpenGLShaderCompiler.cpp index 041a64a6f0f5..c2987266a861 100644 --- a/Engine/Source/Developer/ShaderFormatOpenGL/Private/OpenGLShaderCompiler.cpp +++ b/Engine/Source/Developer/ShaderFormatOpenGL/Private/OpenGLShaderCompiler.cpp @@ -898,7 +898,7 @@ void FOpenGLFrontend::BuildShaderOutput( Header.ShaderName = CCHeader.Name; // perform any post processing this frontend class may need to do - ShaderOutput.bSucceeded = PostProcessShaderSource(Version, Frequency, USFSource, SourceLen + 1 - (USFSource - InShaderSource), ParameterMap, BindingNameMap, ShaderOutput.Errors); + ShaderOutput.bSucceeded = PostProcessShaderSource(Version, Frequency, USFSource, SourceLen + 1 - (USFSource - InShaderSource), ParameterMap, BindingNameMap, ShaderOutput.Errors, ShaderInput); // Build the SRT for this shader. { diff --git a/Engine/Source/Developer/ShaderFormatOpenGL/Public/ShaderFormatOpenGL.h b/Engine/Source/Developer/ShaderFormatOpenGL/Public/ShaderFormatOpenGL.h index 91e4fde63273..66141f24fce0 100644 --- a/Engine/Source/Developer/ShaderFormatOpenGL/Public/ShaderFormatOpenGL.h +++ b/Engine/Source/Developer/ShaderFormatOpenGL/Public/ShaderFormatOpenGL.h @@ -76,7 +76,8 @@ protected: // Allow a subclass to perform additional work on the cross compiled source code virtual bool PostProcessShaderSource(GLSLVersion Version, EShaderFrequency Frequency, const ANSICHAR* ShaderSource, - uint32 SourceLen, class FShaderParameterMap& ParameterMap, TMap& BindingNameMap, TArray& Errors) + uint32 SourceLen, class FShaderParameterMap& ParameterMap, TMap& BindingNameMap, TArray& Errors, + const FShaderCompilerInput& ShaderInput) { return true; } diff --git a/Engine/Source/Developer/ShaderFormatVectorVM/Private/ir_vm_flatten_branches_to_selects_visitor.cpp b/Engine/Source/Developer/ShaderFormatVectorVM/Private/ir_vm_flatten_branches_to_selects_visitor.cpp index 4113c7ba1848..249a8dca9827 100644 --- a/Engine/Source/Developer/ShaderFormatVectorVM/Private/ir_vm_flatten_branches_to_selects_visitor.cpp +++ b/Engine/Source/Developer/ShaderFormatVectorVM/Private/ir_vm_flatten_branches_to_selects_visitor.cpp @@ -20,7 +20,7 @@ PRAGMA_POP #include "ir.h" //Helper visitor to replace any flatten branches (currently all) with selection statements the VM can deal with. -class ir_flatten_branch_to_select_visitor : public ir_hierarchical_visitor +class ir_flatten_branch_to_select_visitor final : public ir_hierarchical_visitor { public: @@ -74,6 +74,10 @@ public: } } + virtual ~ir_flatten_branch_to_select_visitor() + { + } + ir_function_signature* get_select_signature(const glsl_type* type) { if (ir_function_signature** found = select_functions.Find(type)) diff --git a/Engine/Source/Developer/ShaderFormatVectorVM/Private/ir_vm_gen_bytecode_visitor.cpp b/Engine/Source/Developer/ShaderFormatVectorVM/Private/ir_vm_gen_bytecode_visitor.cpp index 6968c876fcf9..c44202cfea4b 100644 --- a/Engine/Source/Developer/ShaderFormatVectorVM/Private/ir_vm_gen_bytecode_visitor.cpp +++ b/Engine/Source/Developer/ShaderFormatVectorVM/Private/ir_vm_gen_bytecode_visitor.cpp @@ -1100,7 +1100,7 @@ class ir_gen_vvm_visitor : public ir_hierarchical_visitor { } - ~ir_gen_vvm_visitor() + virtual ~ir_gen_vvm_visitor() { for (int32 i = 0; i < ordered_ops.Num(); ++i) { diff --git a/Engine/Source/Developer/ShaderFormatVectorVM/Private/ir_vm_merge_op_visitor.cpp b/Engine/Source/Developer/ShaderFormatVectorVM/Private/ir_vm_merge_op_visitor.cpp index 6606a000ec0b..870435997424 100644 --- a/Engine/Source/Developer/ShaderFormatVectorVM/Private/ir_vm_merge_op_visitor.cpp +++ b/Engine/Source/Developer/ShaderFormatVectorVM/Private/ir_vm_merge_op_visitor.cpp @@ -25,7 +25,7 @@ PRAGMA_POP /** finds any group of ops than can be merged into a single compound operation. Mad for example. */ -class ir_merge_op_visitor : ir_hierarchical_visitor +class ir_merge_op_visitor final : ir_hierarchical_visitor { _mesa_glsl_parse_state* state; bool assign_has_expressions; @@ -48,6 +48,10 @@ public: expr_depth = 0; } + virtual ~ir_merge_op_visitor() + { + } + virtual ir_visitor_status visit_enter(ir_expression* expr) { ++expr_depth; diff --git a/Engine/Source/Developer/ShaderFormatVectorVM/Private/ir_vm_propagate_non_expressions_visitor.cpp b/Engine/Source/Developer/ShaderFormatVectorVM/Private/ir_vm_propagate_non_expressions_visitor.cpp index f64b58c5546d..ee17e3fdfea5 100644 --- a/Engine/Source/Developer/ShaderFormatVectorVM/Private/ir_vm_propagate_non_expressions_visitor.cpp +++ b/Engine/Source/Developer/ShaderFormatVectorVM/Private/ir_vm_propagate_non_expressions_visitor.cpp @@ -24,7 +24,7 @@ PRAGMA_POP #include "INiagaraCompiler.h" /** Removes any assignments that don't actually map to a VM op but just move some data around. We look for refs and grab the source data direct. */ -class ir_propagate_non_expressions_visitor : public ir_rvalue_visitor +class ir_propagate_non_expressions_visitor final : public ir_rvalue_visitor { _mesa_glsl_parse_state *parse_state; @@ -54,7 +54,7 @@ public: progress = false; } - ~ir_propagate_non_expressions_visitor() + virtual ~ir_propagate_non_expressions_visitor() { } @@ -207,7 +207,7 @@ void vm_propagate_non_expressions_visitor(exec_list* ir, _mesa_glsl_parse_state* ////////////////////////////////////////////////////////////////////////// /** Replaces any array accesses to matrices with the equivalant swizzle. */ -class ir_matrix_array_access_to_swizzles : public ir_rvalue_visitor +class ir_matrix_array_access_to_swizzles final : public ir_rvalue_visitor { public: @@ -217,7 +217,7 @@ public: progress = false; } - ~ir_matrix_array_access_to_swizzles() + virtual ~ir_matrix_array_access_to_swizzles() { } @@ -293,6 +293,10 @@ public: progress = false; } + virtual ~ir_matrices_to_vectors() + { + } + virtual void handle_rvalue(ir_rvalue **rvalue) { if (rvalue && *rvalue) diff --git a/Engine/Source/Developer/ShaderFormatVectorVM/Private/ir_vm_scalarize_visitor.cpp b/Engine/Source/Developer/ShaderFormatVectorVM/Private/ir_vm_scalarize_visitor.cpp index f1e21c0abb59..656c950e37f0 100644 --- a/Engine/Source/Developer/ShaderFormatVectorVM/Private/ir_vm_scalarize_visitor.cpp +++ b/Engine/Source/Developer/ShaderFormatVectorVM/Private/ir_vm_scalarize_visitor.cpp @@ -87,7 +87,7 @@ class ir_scalarize_visitor2 : public ir_hierarchical_visitor { } - ~ir_scalarize_visitor2() + virtual ~ir_scalarize_visitor2() { } diff --git a/Engine/Source/Developer/ShaderFormatVectorVM/Private/ir_vm_to_single_op_visitor.cpp b/Engine/Source/Developer/ShaderFormatVectorVM/Private/ir_vm_to_single_op_visitor.cpp index ee83485a79f6..98729c03f643 100644 --- a/Engine/Source/Developer/ShaderFormatVectorVM/Private/ir_vm_to_single_op_visitor.cpp +++ b/Engine/Source/Developer/ShaderFormatVectorVM/Private/ir_vm_to_single_op_visitor.cpp @@ -20,7 +20,7 @@ PRAGMA_POP #include "ir.h" -class ir_to_single_op_visitor2 : ir_hierarchical_visitor +class ir_to_single_op_visitor2 final : ir_hierarchical_visitor { _mesa_glsl_parse_state* state; bool assign_has_expressions; @@ -41,6 +41,10 @@ public: replacement = nullptr; } + virtual ~ir_to_single_op_visitor2() + { + } + virtual ir_visitor_status visit_enter(ir_swizzle* swiz) { expression_stack.Push(swiz); diff --git a/Engine/Source/Developer/ShaderPreprocessor/Private/PreprocessorFile.cpp b/Engine/Source/Developer/ShaderPreprocessor/Private/PreprocessorFile.cpp deleted file mode 100644 index a8657dd75027..000000000000 --- a/Engine/Source/Developer/ShaderPreprocessor/Private/PreprocessorFile.cpp +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#include "CoreMinimal.h" -#include "Misc/FileHelper.h" -#include "Misc/Paths.h" -#include "Misc/ScopeLock.h" -#include "ShaderCore.h" -#include "PreprocessorPrivate.h" - -/** - * Helper class used to load shader source files for MCPP. - */ -class FSimpleMcppFileLoader -{ -public: - /** Initialization constructor. */ - explicit FSimpleMcppFileLoader(const FString& InSourceFilename) - //: ShaderInput(InShaderInput) - { - FString ShaderDir = FPlatformProcess::ShaderDir(); - - InputShaderFile = ShaderDir / FPaths::GetCleanFilename(InSourceFilename); - - FString InputShaderSource; - if (FFileHelper::LoadFileToString(InputShaderSource, *InSourceFilename)) - { - InputShaderSource = FString::Printf(TEXT("#line 1 \"%s\"\n%s"), *FPaths::GetBaseFilename(InSourceFilename), *InputShaderSource); - CachedFileContents.Add(GetRelativeShaderFilename(InputShaderFile),StringToArray(*InputShaderSource, InputShaderSource.Len())); - } - } - - /** Returns the input shader filename to pass to MCPP. */ - const FString& GetInputShaderFilename() const - { - return InputShaderFile; - } - - /** Retrieves the MCPP file loader interface. */ - file_loader GetMcppInterface() - { - file_loader Loader; - Loader.get_file_contents = GetFileContents; - Loader.user_data = (void*)this; - return Loader; - } - -private: - /** Holder for shader contents (string + size). */ - typedef TArray FShaderContents; - - /** MCPP callback for retrieving file contents. */ - static int GetFileContents(void* InUserData, const ANSICHAR* InFilename, const ANSICHAR** OutContents, size_t* OutContentSize) - { - auto* This = (FSimpleMcppFileLoader*)InUserData; - FString Filename = GetRelativeShaderFilename(ANSI_TO_TCHAR(InFilename)); - - FShaderContents* CachedContents = This->CachedFileContents.Find(Filename); - if (!CachedContents) - { - FString FileContents; - FFileHelper::LoadFileToString(FileContents, *Filename); - - if (FileContents.Len() > 0) - { - CachedContents = &This->CachedFileContents.Add(Filename,StringToArray(*FileContents, FileContents.Len())); - } - } - - if (OutContents) - { - *OutContents = CachedContents ? CachedContents->GetData() : nullptr; - } - if (OutContentSize) - { - *OutContentSize = CachedContents ? CachedContents->Num() : 0; - } - - return !!CachedContents; - } - - /** Shader input data. */ - //const FShaderCompilerInput& ShaderInput; - /** File contents are cached as needed. */ - TMap CachedFileContents; - /** The input shader filename. */ - FString InputShaderFile; -}; - - -/** - * Preprocess a shader. - * @param OutPreprocessedShader - Upon return contains the preprocessed source code. - * @param ShaderOutput - ShaderOutput to which errors can be added. - * @param ShaderInput - The shader compiler input. - * @param AdditionalDefines - Additional defines with which to preprocess the shader. - * @returns true if the shader is preprocessed without error. - */ -SHADERPREPROCESSOR_API bool PreprocessShaderFile(FString& OutPreprocessedShader, TArray& OutShaderErrors, const FString& InShaderFile) -{ - FString McppOptions; - FString McppOutput, McppErrors; - ANSICHAR* McppOutAnsi = nullptr; - ANSICHAR* McppErrAnsi = nullptr; - bool bSuccess = false; - - // MCPP is not threadsafe. - static FCriticalSection McppCriticalSection; - FScopeLock McppLock(&McppCriticalSection); - - FSimpleMcppFileLoader FileLoader(InShaderFile); - - int32 Result = mcpp_run( - TCHAR_TO_ANSI(*McppOptions), - TCHAR_TO_ANSI(*FileLoader.GetInputShaderFilename()), - &McppOutAnsi, - &McppErrAnsi, - FileLoader.GetMcppInterface() - ); - - McppOutput = McppOutAnsi; - McppErrors = McppErrAnsi; - - if (ParseMcppErrors(OutShaderErrors, McppErrors, false)) - { - // exchange strings - FMemory::Memswap( &OutPreprocessedShader, &McppOutput, sizeof(FString) ); - bSuccess = true; - } - - return bSuccess; -} diff --git a/Engine/Source/Developer/ShaderPreprocessor/Private/ShaderPreprocessor.cpp b/Engine/Source/Developer/ShaderPreprocessor/Private/ShaderPreprocessor.cpp index a46954039e4d..b1ec1da078a8 100644 --- a/Engine/Source/Developer/ShaderPreprocessor/Private/ShaderPreprocessor.cpp +++ b/Engine/Source/Developer/ShaderPreprocessor/Private/ShaderPreprocessor.cpp @@ -32,19 +32,23 @@ public: explicit FMcppFileLoader(const FShaderCompilerInput& InShaderInput) : ShaderInput(InShaderInput) { - FString ShaderDir = FPlatformProcess::ShaderDir(); - - InputShaderFile = ShaderDir / FPaths::GetCleanFilename(ShaderInput.SourceFilename); + // SourceFilename is expected to be relative to the engine shader folder + InputShaderFile = ShaderInput.SourceFilename; + + // If there is no extension then we can end up with an extra version of this file if (FPaths::GetExtension(InputShaderFile) != TEXT("usf")) { InputShaderFile += TEXT(".usf"); } + // Attempt to keep filename reference and map add logic the same as the file contents callback + FString Filename = GetRelativeShaderFilename(InputShaderFile); FString InputShaderSource; - if (LoadShaderSourceFile(*ShaderInput.SourceFilename,InputShaderSource)) + + if (LoadShaderSourceFile(*Filename, InputShaderSource)) { InputShaderSource = FString::Printf(TEXT("%s\n#line 1\n%s"), *ShaderInput.SourceFilePrefix, *InputShaderSource); - CachedFileContents.Add(GetRelativeShaderFilename(InputShaderFile),StringToArray(*InputShaderSource, InputShaderSource.Len())); + CachedFileContents.Add(Filename, StringToArray(*InputShaderSource, InputShaderSource.Len())); } } diff --git a/Engine/Source/Developer/ShaderPreprocessor/Public/ShaderPreprocessor.h b/Engine/Source/Developer/ShaderPreprocessor/Public/ShaderPreprocessor.h index 23e3059fbadd..e3778f86084d 100644 --- a/Engine/Source/Developer/ShaderPreprocessor/Public/ShaderPreprocessor.h +++ b/Engine/Source/Developer/ShaderPreprocessor/Public/ShaderPreprocessor.h @@ -19,16 +19,3 @@ extern SHADERPREPROCESSOR_API bool PreprocessShader( const FShaderCompilerInput& ShaderInput, const FShaderCompilerDefinitions& AdditionalDefines ); - -/** - * Preprocess a shader file, for non-usf files. - * @param OutPreprocessedShader - Upon return contains the preprocessed source code. - * @param ShaderOutput - ShaderOutput to which errors can be added. - * @param ShaderInput - The shader compiler input. - * @returns true if the shader is preprocessed without error. - */ -extern SHADERPREPROCESSOR_API bool PreprocessShaderFile( - FString& OutPreprocessedShader, - TArray& OutShaderErrors, - const FString& InShaderFile - ); diff --git a/Engine/Source/Developer/SimplygonMeshReduction/Private/SimplygonMeshReduction.cpp b/Engine/Source/Developer/SimplygonMeshReduction/Private/SimplygonMeshReduction.cpp index 15c82d7c8890..320743a76f5b 100644 --- a/Engine/Source/Developer/SimplygonMeshReduction/Private/SimplygonMeshReduction.cpp +++ b/Engine/Source/Developer/SimplygonMeshReduction/Private/SimplygonMeshReduction.cpp @@ -705,7 +705,7 @@ public: if (InitResult != SimplygonSDK::SG_ERROR_NOERROR && InitResult != SimplygonSDK::SG_ERROR_ALREADYINITIALIZED) { - UE_LOG(LogSimplygon, Warning, TEXT("Failed to initialize Simplygon. Error: %d."), Result); + UE_LOG(LogSimplygon, Warning, TEXT("Failed to initialize Simplygon. Error: %d."), InitResult); FPlatformProcess::FreeDllHandle(GSimplygonSDKDLLHandle); GSimplygonSDKDLLHandle = nullptr; } diff --git a/Engine/Source/Developer/SimplygonSwarm/Private/SimplygonRESTClient.cpp b/Engine/Source/Developer/SimplygonSwarm/Private/SimplygonRESTClient.cpp index 611b8a779c59..c15954b58ce5 100644 --- a/Engine/Source/Developer/SimplygonSwarm/Private/SimplygonRESTClient.cpp +++ b/Engine/Source/Developer/SimplygonSwarm/Private/SimplygonRESTClient.cpp @@ -10,6 +10,8 @@ #define HOSTNAME "http://127.0.0.1" #define PORT ":55002" +DEFINE_LOG_CATEGORY_STATIC(LogSimplygonRESTClient, Verbose, All); + const TCHAR* SIMPLYGON_SWARM_REQUEST_DEBUG_TEMPALTE = TEXT("Error Processing Request %s"); FSimplygonSwarmTask::FSimplygonSwarmTask(const FSwarmTaskkData& InTaskData) diff --git a/Engine/Source/Developer/SimplygonSwarm/Private/SimplygonSwarm.cpp b/Engine/Source/Developer/SimplygonSwarm/Private/SimplygonSwarm.cpp index 526aa41f7e5e..498ed883ea9d 100644 --- a/Engine/Source/Developer/SimplygonSwarm/Private/SimplygonSwarm.cpp +++ b/Engine/Source/Developer/SimplygonSwarm/Private/SimplygonSwarm.cpp @@ -225,7 +225,7 @@ public: { UE_LOG(LogSimplygonSwarm, Error , TEXT("Could not find zip file for uploading %s"), *ZipFileName); FailedDelegate.ExecuteIfBound(InJobGUID, TEXT("Could not find zip file for uploading")); - return; + return; //-V773 } FSwarmTaskkData TaskData; diff --git a/Engine/Source/Developer/SimplygonSwarm/Public/SimplygonRESTClient.h b/Engine/Source/Developer/SimplygonSwarm/Public/SimplygonRESTClient.h index d9a0eddaa6cc..a02876e813fb 100644 --- a/Engine/Source/Developer/SimplygonSwarm/Public/SimplygonRESTClient.h +++ b/Engine/Source/Developer/SimplygonSwarm/Public/SimplygonRESTClient.h @@ -20,8 +20,6 @@ #include "Runtime/Online/HTTP/Public/Interfaces/IHttpRequest.h" #include "Runtime/Online/HTTP/Public/HttpModule.h" -DEFINE_LOG_CATEGORY_STATIC(LogSimplygonRESTClient, Verbose, All); - /** Enum representing state used by Simplygon Grid Server */ enum SimplygonRESTState { diff --git a/Engine/Source/Developer/SlateFileDialogs/Private/SlateFileDlgWindow.cpp b/Engine/Source/Developer/SlateFileDialogs/Private/SlateFileDlgWindow.cpp index 8ddfc07c0325..b40e30c853c4 100644 --- a/Engine/Source/Developer/SlateFileDialogs/Private/SlateFileDlgWindow.cpp +++ b/Engine/Source/Developer/SlateFileDialogs/Private/SlateFileDlgWindow.cpp @@ -34,11 +34,19 @@ class FSlateFileDialogVisitor : public IPlatformFile::FDirectoryVisitor { public: FSlateFileDialogVisitor(TArray> &InFileList, - TArray> &InFolderList, TSharedPtr InFilterList) + TArray> &InFolderList, const FString& InFilterList) : FileList(InFileList), - FolderList(InFolderList), - FilterList(InFilterList) - {} + FolderList(InFolderList) + { + // Process the filters once rather than once for each file encountered + InFilterList.ParseIntoArray(FilterList, TEXT(";"), true); + // Remove cruft from the extension list + for (int32 Index = 0; Index < FilterList.Num(); Index++) + { + FilterList[Index].ReplaceInline(TEXT(")"), TEXT("")); + FilterList[Index] = FilterList[Index].TrimQuotes().TrimTrailing().Trim(); + } + } virtual bool Visit(const TCHAR* FilenameOrDirectory, bool bIsDirectory) override @@ -49,7 +57,9 @@ public: for (i = FCString::Strlen(FilenameOrDirectory) - 1; i >= 0; i--) { if (FilenameOrDirectory[i] == TCHAR('/')) + { break; + } } #if HIDE_HIDDEN_FILES @@ -119,77 +129,29 @@ public: return true; } - bool PassesFilterTest(const TCHAR *Filename) + bool PassesFilterTest(const TCHAR* Filename) { - if (!FilterList.IsValid()) + if (FilterList.Num() == 0) { return true; // no filters. everything passes. } - int32 i; - const TCHAR *Extension = NULL; - - // get extension - for (i = FCString::Strlen(Filename) - 1; i >= 0; i--) + FString Extension = FPaths::GetExtension(FString(Filename), true); + // See if it matches any of the extensions + for (const FString& FilterExt : FilterList) { - if (Filename[i] == TCHAR('.')) + if (FilterExt == TEXT("*") || FilterExt == TEXT(".*") || FilterExt == TEXT("*.*") || FilterExt.EndsWith(Extension)) { - Extension = &Filename[i]; - break; + return true; } } - - if (Extension == NULL) - { - return false; // file has no extension. it fails filter test. - } - - TCHAR Temp[MAX_FILTER_LENGTH]; - FCString::Strcpy(Temp, FilterList->Len(), *(*FilterList.Get())); - - // break path into tokens - TCHAR *ContextStr = nullptr; - - TCHAR *FilterExt = FCString::Strtok(Temp, TEXT(";"), &ContextStr); - bool RC = false; - - while (FilterExt) - { - // strip leading spaces and '*' from beginning. - FilterExt = FCString::Strchr(FilterExt, '.'); - - // strip any trailing spaces - for (i = FCString::Strlen(FilterExt) - 1; i >= 0 && FilterExt[i] == TCHAR(' '); i--) - { - FilterExt[i] = 0; - } - - if (FCString::Strcmp(FilterExt, TEXT(".*")) == 0) - { - // *.* matches all - RC = true; - break; - } - - if (FCString::Stricmp(FilterExt, Extension) == 0) - { - // positive hit. - RC = true; - break; - } - - // next filter entry - FilterExt = FCString::Strtok(nullptr, TEXT(";"), &ContextStr); - } - - // cleanup and return failed. - return RC; + return false; } private: TArray>& FileList; TArray>& FolderList; - TSharedPtr FilterList; + TArray FilterList; }; @@ -1250,7 +1212,7 @@ void SSlateFileOpenDlg::ReadDir(bool bIsRefresh) FilesArray.Empty(); FoldersArray.Empty(); - TSharedPtr FilterList = nullptr; + FString FilterList; if (FilterListArray.Num() > 0 && FilterIndex >= 0) { @@ -1454,7 +1416,8 @@ void SSlateFileOpenDlg::OnFileNameCommitted(const FText& InText, ETextCommit::Ty if (!bDirectoriesOnly && GetFilterExtension(Extension)) { // append extension to filename if user left it off - if (!SaveFilename.EndsWith(Extension, ESearchCase::CaseSensitive) && Extension.Compare(".*") != 0) + if (!SaveFilename.EndsWith(Extension, ESearchCase::CaseSensitive) && + !IsWildcardExtension(Extension)) { SaveFilename = SaveFilename + Extension; } @@ -1525,7 +1488,7 @@ void SSlateFileOpenDlg::ParseFilters() FilterList = FCString::Strtok(nullptr, TEXT("|"), &ContextStr); FilterNameArray.Add(MakeShareable(new FString(FilterDescription))); - FilterListArray.Add(MakeShareable(new FString(FilterList))); + FilterListArray.Add(FString(FilterList)); // next filter entry FilterDescription = FCString::Strtok(nullptr, TEXT("|"), &ContextStr); @@ -1545,10 +1508,11 @@ void SSlateFileOpenDlg::ParseFilters() bool SSlateFileOpenDlg::GetFilterExtension(FString &OutString) { + OutString.Empty(); + // check to see if filters were given if (Filters.Len() == 0) { - OutString = ""; return false; } @@ -1558,24 +1522,34 @@ bool SSlateFileOpenDlg::GetFilterExtension(FString &OutString) // find start of extension TCHAR *FilterExt = FCString::Strchr(Temp, '.'); - - // strip any trailing junk - int32 i; - for (i = 0; i < FCString::Strlen(FilterExt); i++) + if (FilterExt != nullptr) { - if (FilterExt[i] == ' ' || FilterExt[i] == ')' || FilterExt[i] == ';') + // strip any trailing junk + int32 i; + for (i = 0; i < FCString::Strlen(FilterExt); i++) { - FilterExt[i] = 0; - break; + if (FilterExt[i] == ' ' || FilterExt[i] == ')' || FilterExt[i] == ';') + { + FilterExt[i] = 0; + break; + } } + + // store result and clean up + OutString = FilterExt; } - - // store result and clean up - OutString = FString(FilterExt); - - return (i > 0); + else if (Temp[0] == TEXT('*')) + { + OutString = Temp; + } + return !OutString.IsEmpty(); } +bool SSlateFileOpenDlg::IsWildcardExtension(const FString& Extension) +{ + return (Extension.Find(TEXT(".*")) >= 0) || + (Extension.Find(TEXT("*")) >= 0); +} void SSlateFileOpenDlg::OnNewDirectoryCommitted(const FText & InText, ETextCommit::Type InCommitType) { diff --git a/Engine/Source/Developer/SlateFileDialogs/Private/SlateFileDlgWindow.h b/Engine/Source/Developer/SlateFileDialogs/Private/SlateFileDlgWindow.h index 10a3d45a4fb9..71e8a9f747fb 100644 --- a/Engine/Source/Developer/SlateFileDialogs/Private/SlateFileDlgWindow.h +++ b/Engine/Source/Developer/SlateFileDialogs/Private/SlateFileDlgWindow.h @@ -182,6 +182,8 @@ private: bool GetFilterExtension(FString &OutString); void ParseFilters(); + /** @return true if the extension filter contains a wildcard or not */ + bool IsWildcardExtension(const FString& Extension); TArray< FDirNode > DirectoryNodesArray; TArray> FoldersArray; @@ -202,7 +204,7 @@ private: TSharedPtr DirErrorMsg; TArray> FilterNameArray; - TArray> FilterListArray; + TArray FilterListArray; int32 FilterIndex; diff --git a/Engine/Source/Developer/SourceCodeAccess/Public/ISourceCodeAccessor.h b/Engine/Source/Developer/SourceCodeAccess/Public/ISourceCodeAccessor.h index 57a17d602fb6..da5244d2cb80 100644 --- a/Engine/Source/Developer/SourceCodeAccess/Public/ISourceCodeAccessor.h +++ b/Engine/Source/Developer/SourceCodeAccess/Public/ISourceCodeAccessor.h @@ -11,6 +11,8 @@ class ISourceCodeAccessor : public IModularFeature { public: + virtual ~ISourceCodeAccessor() {} + /** * Not necessary to call unless you know you're changing the state of any installed compilers. * If that's the case, you should call this before checking the state the installed state of the diff --git a/Engine/Source/Developer/SourceControl/Private/DefaultSourceControlProvider.cpp b/Engine/Source/Developer/SourceControl/Private/DefaultSourceControlProvider.cpp index c9db32f9b44e..9845ef62b931 100644 --- a/Engine/Source/Developer/SourceControl/Private/DefaultSourceControlProvider.cpp +++ b/Engine/Source/Developer/SourceControl/Private/DefaultSourceControlProvider.cpp @@ -84,6 +84,11 @@ bool FDefaultSourceControlProvider::UsesChangelists() const return false; } +bool FDefaultSourceControlProvider::UsesCheckout() const +{ + return false; +} + void FDefaultSourceControlProvider::Tick() { diff --git a/Engine/Source/Developer/SourceControl/Private/DefaultSourceControlProvider.h b/Engine/Source/Developer/SourceControl/Private/DefaultSourceControlProvider.h index f93e24d0a44a..8b09c589a228 100644 --- a/Engine/Source/Developer/SourceControl/Private/DefaultSourceControlProvider.h +++ b/Engine/Source/Developer/SourceControl/Private/DefaultSourceControlProvider.h @@ -29,6 +29,7 @@ public: virtual void CancelOperation( const TSharedRef& InOperation ) override; virtual bool UsesLocalReadOnlyState() const override; virtual bool UsesChangelists() const override; + virtual bool UsesCheckout() const override; virtual void Tick() override; virtual TArray< TSharedRef > GetLabels( const FString& InMatchingSpec ) const override; #if SOURCE_CONTROL_WITH_SLATE diff --git a/Engine/Source/Developer/SourceControl/Private/SSourceControlLogin.cpp b/Engine/Source/Developer/SourceControl/Private/SSourceControlLogin.cpp index 07a1601a2271..2a03e1908b68 100644 --- a/Engine/Source/Developer/SourceControl/Private/SSourceControlLogin.cpp +++ b/Engine/Source/Developer/SourceControl/Private/SSourceControlLogin.cpp @@ -179,7 +179,7 @@ FReply SSourceControlLogin::OnAcceptSettings() } FSourceControlModule& SourceControlModule = FSourceControlModule::Get(); - if(!SourceControlModule.GetProvider().Login(FString(), EConcurrency::Asynchronous, FSourceControlOperationComplete::CreateSP(this, &SSourceControlLogin::SourceControlOperationComplete))) + if(SourceControlModule.GetProvider().Login(FString(), EConcurrency::Asynchronous, FSourceControlOperationComplete::CreateSP(this, &SSourceControlLogin::SourceControlOperationComplete)) == ECommandResult::Type::Failed) { DisplayConnectionError(); ConnectionState = ELoginConnectionState::Disconnected; diff --git a/Engine/Source/Developer/SourceControl/Private/SourceControlHelpers.cpp b/Engine/Source/Developer/SourceControl/Private/SourceControlHelpers.cpp index a5bda0ddc7b7..eb05ea07b85c 100644 --- a/Engine/Source/Developer/SourceControl/Private/SourceControlHelpers.cpp +++ b/Engine/Source/Developer/SourceControl/Private/SourceControlHelpers.cpp @@ -16,10 +16,7 @@ #define LOCTEXT_NAMESPACE "SourceControlHelpers" -namespace SourceControlHelpers -{ - -const FString& GetSettingsIni() +const FString& USourceControlHelpers::GetSettingsIni() { if(ISourceControlModule::Get().GetUseGlobalSettings()) { @@ -37,7 +34,7 @@ const FString& GetSettingsIni() } } -const FString& GetGlobalSettingsIni() +const FString& USourceControlHelpers::GetGlobalSettingsIni() { static FString SourceControlGlobalSettingsIni; if(SourceControlGlobalSettingsIni.Len() == 0) @@ -73,12 +70,12 @@ static FString PackageFilename_Internal( const FString& InPackageName ) return Filename; } -FString PackageFilename( const FString& InPackageName ) +FString USourceControlHelpers::PackageFilename( const FString& InPackageName ) { return FPaths::ConvertRelativePathToFull(PackageFilename_Internal(InPackageName)); } -FString PackageFilename( const UPackage* InPackage ) +FString USourceControlHelpers::PackageFilename( const UPackage* InPackage ) { FString Filename; if(InPackage != NULL) @@ -88,7 +85,7 @@ FString PackageFilename( const UPackage* InPackage ) return Filename; } -TArray PackageFilenames( const TArray& InPackages ) +TArray USourceControlHelpers::PackageFilenames( const TArray& InPackages ) { TArray OutNames; for (int32 PackageIndex = 0; PackageIndex < InPackages.Num(); PackageIndex++) @@ -99,7 +96,7 @@ TArray PackageFilenames( const TArray& InPackages ) return OutNames; } -TArray PackageFilenames( const TArray& InPackageNames ) +TArray USourceControlHelpers::PackageFilenames( const TArray& InPackageNames ) { TArray OutNames; for (int32 PackageIndex = 0; PackageIndex < InPackageNames.Num(); PackageIndex++) @@ -110,7 +107,7 @@ TArray PackageFilenames( const TArray& InPackageNames ) return OutNames; } -TArray AbsoluteFilenames( const TArray& InFileNames ) +TArray USourceControlHelpers::AbsoluteFilenames( const TArray& InFileNames ) { TArray AbsoluteFiles; for(const auto& FileName : InFileNames) @@ -130,7 +127,7 @@ TArray AbsoluteFilenames( const TArray& InFileNames ) return AbsoluteFiles; } -void RevertUnchangedFiles( ISourceControlProvider& InProvider, const TArray& InFiles ) +void USourceControlHelpers::RevertUnchangedFiles( ISourceControlProvider& InProvider, const TArray& InFiles ) { // Make sure we update the modified state of the files TSharedRef UpdateStatusOperation = ISourceControlOperation::Create(); @@ -156,7 +153,7 @@ void RevertUnchangedFiles( ISourceControlProvider& InProvider, const TArray& OutLines ) +bool USourceControlHelpers::AnnotateFile( ISourceControlProvider& InProvider, const FString& InLabel, const FString& InFile, TArray& OutLines ) { TArray< TSharedRef > Labels = InProvider.GetLabels( InLabel ); if(Labels.Num() > 0) @@ -177,7 +174,7 @@ bool AnnotateFile( ISourceControlProvider& InProvider, const FString& InLabel, c return false; } -bool AnnotateFile( ISourceControlProvider& InProvider, int32 InCheckInIdentifier, const FString& InFile, TArray& OutLines ) +bool USourceControlHelpers::AnnotateFile( ISourceControlProvider& InProvider, int32 InCheckInIdentifier, const FString& InFile, TArray& OutLines ) { TSharedRef UpdateStatusOperation = ISourceControlOperation::Create(); UpdateStatusOperation->SetUpdateHistory(true); @@ -204,7 +201,7 @@ bool AnnotateFile( ISourceControlProvider& InProvider, int32 InCheckInIdentifier return false; } -bool MarkFileForAdd( const FString& InFilePath ) +bool USourceControlHelpers::MarkFileForAdd( const FString& InFilePath ) { if (InFilePath.IsEmpty()) { @@ -252,7 +249,7 @@ bool MarkFileForAdd( const FString& InFilePath ) return true; } -bool CheckOutFile( const FString& InFilePath ) +bool USourceControlHelpers::CheckOutFile( const FString& InFilePath ) { if ( InFilePath.IsEmpty() ) { @@ -342,7 +339,7 @@ bool CheckOutFile( const FString& InFilePath ) return bSuccessfullyCheckedOut; } -bool CheckoutOrMarkForAdd( const FString& InDestFile, const FText& InFileDescription, const FOnPostCheckOut& OnPostCheckOut, FText& OutFailReason ) +bool USourceControlHelpers::CheckoutOrMarkForAdd( const FString& InDestFile, const FText& InFileDescription, const FOnPostCheckOut& OnPostCheckOut, FText& OutFailReason ) { bool bSucceeded = true; @@ -395,7 +392,7 @@ bool CheckoutOrMarkForAdd( const FString& InDestFile, const FText& InFileDescrip return bSucceeded; } -bool CopyFileUnderSourceControl( const FString& InDestFile, const FString& InSourceFile, const FText& InFileDescription, FText& OutFailReason) +bool USourceControlHelpers::CopyFileUnderSourceControl( const FString& InDestFile, const FString& InSourceFile, const FText& InFileDescription, FText& OutFailReason) { struct Local { @@ -416,7 +413,7 @@ bool CopyFileUnderSourceControl( const FString& InDestFile, const FString& InSou return CheckoutOrMarkForAdd(InDestFile, InFileDescription, FOnPostCheckOut::CreateStatic(&Local::CopyFile, InSourceFile), OutFailReason); } -bool BranchPackage( UPackage* DestPackage, UPackage* SourcePackage ) +bool USourceControlHelpers::BranchPackage( UPackage* DestPackage, UPackage* SourcePackage ) { if(ISourceControlModule::Get().IsEnabled()) { @@ -437,7 +434,6 @@ bool BranchPackage( UPackage* DestPackage, UPackage* SourcePackage ) return false; } -} FScopedSourceControl::FScopedSourceControl() { diff --git a/Engine/Source/Developer/SourceControl/Public/ISourceControlProvider.h b/Engine/Source/Developer/SourceControl/Public/ISourceControlProvider.h index 4209cd327a02..c937b407ddfe 100644 --- a/Engine/Source/Developer/SourceControl/Public/ISourceControlProvider.h +++ b/Engine/Source/Developer/SourceControl/Public/ISourceControlProvider.h @@ -272,6 +272,11 @@ public: */ virtual bool UsesChangelists() const = 0; + /** + * Whether the provider uses the checkout workflow + */ + virtual bool UsesCheckout() const = 0; + /** * Called every update. */ diff --git a/Engine/Source/Developer/SourceControl/Public/SourceControlHelpers.h b/Engine/Source/Developer/SourceControl/Public/SourceControlHelpers.h index 3ed84d5fa9ef..0b608cf56213 100644 --- a/Engine/Source/Developer/SourceControl/Public/SourceControlHelpers.h +++ b/Engine/Source/Developer/SourceControl/Public/SourceControlHelpers.h @@ -3,7 +3,12 @@ #pragma once #include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "UObject/UObjectGlobals.h" #include "ISourceControlRevision.h" +#include "TextProperty.h" +#include "SourceControlHelpers.generated.h" + class ISourceControlProvider; @@ -16,61 +21,70 @@ class ISourceControlProvider; */ DECLARE_DELEGATE_RetVal_ThreeParams(bool, FOnPostCheckOut, const FString& /*InDestFile*/, const FText& /*InFileDescription*/, FText& /*OutFailReason*/); -namespace SourceControlHelpers +// For backwards compatibility +typedef class USourceControlHelpers SourceControlHelpers; + +UCLASS(transient) +class USourceControlHelpers : public UObject { + GENERATED_BODY() +public: /** * Helper function to get the ini filename for storing source control settings * @return the filename */ - SOURCECONTROL_API extern const FString& GetSettingsIni(); + static SOURCECONTROL_API const FString& GetSettingsIni(); /** * Helper function to get the ini filename for storing global source control settings * @return the filename */ - SOURCECONTROL_API extern const FString& GetGlobalSettingsIni(); + static SOURCECONTROL_API const FString& GetGlobalSettingsIni(); /** * Helper function to get a filename for a package name. * @param InPackageName The package name to get the filename for * @return the filename */ - SOURCECONTROL_API extern FString PackageFilename( const FString& InPackageName ); + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Editor Source Control Helpers") + static SOURCECONTROL_API FString PackageFilename( const FString& InPackageName ); /** * Helper function to get a filename for a package. * @param InPackage The package to get the filename for * @return the filename */ - SOURCECONTROL_API extern FString PackageFilename( const UPackage* InPackage ); + static SOURCECONTROL_API FString PackageFilename( const UPackage* InPackage ); /** * Helper function to convert package array into filename array. * @param InPackages The package array * @return an array of filenames */ - SOURCECONTROL_API extern TArray PackageFilenames( const TArray& InPackages ); + static SOURCECONTROL_API TArray PackageFilenames( const TArray& InPackages ); /** * Helper function to convert package name array into a filename array. * @param InPackageNames The package name array * @return an array of filenames */ - SOURCECONTROL_API extern TArray PackageFilenames( const TArray& InPackageNames ); + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Editor Source Control Helpers") + static SOURCECONTROL_API TArray PackageFilenames( const TArray& InPackageNames ); /** * Helper function to convert a filename array to absolute paths. * @param InFileNames The filename array * @return an array of filenames, transformed into absolute paths */ - SOURCECONTROL_API extern TArray AbsoluteFilenames( const TArray& InFileNames ); + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Editor Source Control Helpers") + static SOURCECONTROL_API TArray AbsoluteFilenames( const TArray& InFileNames ); /** * Helper function to get a list of files that are unchanged & revert them. This runs synchronous commands. * @param InProvider The provider to use * @param InFiles The files to operate on */ - SOURCECONTROL_API extern void RevertUnchangedFiles( ISourceControlProvider& InProvider, const TArray& InFiles ); + static SOURCECONTROL_API void RevertUnchangedFiles( ISourceControlProvider& InProvider, const TArray& InFiles ); /** * Helper function to annotate a file using a label @@ -80,7 +94,7 @@ namespace SourceControlHelpers * @param OutLines Output array of annotated lines * @returns true if successful */ - SOURCECONTROL_API extern bool AnnotateFile( ISourceControlProvider& InProvider, const FString& InLabel, const FString& InFile, TArray& OutLines ); + static SOURCECONTROL_API bool AnnotateFile( ISourceControlProvider& InProvider, const FString& InLabel, const FString& InFile, TArray& OutLines ); /** * Helper function to annotate a file using a changelist/checkin identifier @@ -90,21 +104,23 @@ namespace SourceControlHelpers * @param OutLines Output array of annotated lines * @returns true if successful */ - SOURCECONTROL_API extern bool AnnotateFile( ISourceControlProvider& InProvider, int32 InCheckInIdentifier, const FString& InFile, TArray& OutLines ); + static SOURCECONTROL_API bool AnnotateFile( ISourceControlProvider& InProvider, int32 InCheckInIdentifier, const FString& InFile, TArray& OutLines ); /** * Helper function to check out a file * @param InFile The file path to check in * @return Success or failure of the checkout operation */ - SOURCECONTROL_API extern bool CheckOutFile( const FString& InFile ); + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Editor Source Control Helpers") + static SOURCECONTROL_API bool CheckOutFile( const FString& InFile ); /** * Helper function to mark a file for add. Does nothing (and returns true) if the file is already under SC * @param InFile The file path to check in * @return Success or failure of the mark for add operation */ - SOURCECONTROL_API extern bool MarkFileForAdd( const FString& InFile ); + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Editor Source Control Helpers") + static SOURCECONTROL_API bool MarkFileForAdd( const FString& InFile ); /** * Helper function perform an operation on files in our 'source controlled' directories, handling checkout/add etc. @@ -114,7 +130,7 @@ namespace SourceControlHelpers * @param OutFailReason Text describing why the operation failed * @return Success or failure of the operation */ - SOURCECONTROL_API extern bool CheckoutOrMarkForAdd( const FString& InDestFile, const FText& InFileDescription, const FOnPostCheckOut& OnPostCheckOut, FText& OutFailReason ); + static SOURCECONTROL_API bool CheckoutOrMarkForAdd( const FString& InDestFile, const FText& InFileDescription, const FOnPostCheckOut& OnPostCheckOut, FText& OutFailReason ); /** * Helper function to copy a file into our 'source controlled' directories, handling checkout/add etc. @@ -124,7 +140,8 @@ namespace SourceControlHelpers * @param OutFailReason Text describing why the operation failed * @return Success or failure of the operation */ - SOURCECONTROL_API extern bool CopyFileUnderSourceControl( const FString& InDestFile, const FString& InSourceFile, const FText& InFileDescription, FText& OutFailReason ); + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Editor Source Control Helpers") + static SOURCECONTROL_API bool CopyFileUnderSourceControl( const FString& InDestFile, const FString& InSourceFile, const FText& InFileDescription, FText& OutFailReason ); /** * Helper function to branch/integrate packages from one location to another @@ -132,8 +149,8 @@ namespace SourceControlHelpers * @param SourcePackage The source package * @return true if the file packages were successfully branched. */ - SOURCECONTROL_API extern bool BranchPackage( UPackage* DestPackage, UPackage* SourcePackage ); -} + static SOURCECONTROL_API bool BranchPackage( UPackage* DestPackage, UPackage* SourcePackage ); +}; /** * Helper class that ensures FSourceControl is properly initialized and shutdown by calling Init/Close in diff --git a/Engine/Source/Developer/StandaloneRenderer/Private/Windows/D3D/SlateD3DIndexBuffer.h b/Engine/Source/Developer/StandaloneRenderer/Private/Windows/D3D/SlateD3DIndexBuffer.h index 60ac405fc36f..60c4caaff734 100644 --- a/Engine/Source/Developer/StandaloneRenderer/Private/Windows/D3D/SlateD3DIndexBuffer.h +++ b/Engine/Source/Developer/StandaloneRenderer/Private/Windows/D3D/SlateD3DIndexBuffer.h @@ -10,7 +10,7 @@ class FSlateD3DIndexBuffer { public: FSlateD3DIndexBuffer(); - ~FSlateD3DIndexBuffer(); + virtual ~FSlateD3DIndexBuffer(); /** Initializes the index buffers resource. */ virtual void CreateBuffer(); diff --git a/Engine/Source/Developer/StandaloneRenderer/Private/Windows/D3D/SlateD3DShaders.cpp b/Engine/Source/Developer/StandaloneRenderer/Private/Windows/D3D/SlateD3DShaders.cpp index e2fc4d6aa29e..b82c239592da 100644 --- a/Engine/Source/Developer/StandaloneRenderer/Private/Windows/D3D/SlateD3DShaders.cpp +++ b/Engine/Source/Developer/StandaloneRenderer/Private/Windows/D3D/SlateD3DShaders.cpp @@ -34,9 +34,13 @@ static pD3DCompile GetD3DCompileFunc() return &D3DCompile; } -class StandaloneD3DIncluder: public ID3DInclude +class StandaloneD3DIncluder final : public ID3DInclude { public: + virtual ~StandaloneD3DIncluder() + { + } + STDMETHOD(Open)(D3D_INCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID* ppData, uint32* pBytes) override { FString FileName(ANSI_TO_TCHAR(pFileName)); diff --git a/Engine/Source/Developer/SuperSearch/Public/SuperSearchStyle.h b/Engine/Source/Developer/SuperSearch/Public/SuperSearchStyle.h index 19c372bec24a..fbec171d2ea5 100644 --- a/Engine/Source/Developer/SuperSearch/Public/SuperSearchStyle.h +++ b/Engine/Source/Developer/SuperSearch/Public/SuperSearchStyle.h @@ -17,7 +17,7 @@ enum class ESuperSearchEnginePlacement : uint8 None, }; -USTRUCT() +USTRUCT(BlueprintType) struct SUPERSEARCH_API FSuperSearchStyle : public FSlateWidgetStyle { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Developer/TargetDeviceServices/Public/Interfaces/ITargetDeviceProxyManager.h b/Engine/Source/Developer/TargetDeviceServices/Public/Interfaces/ITargetDeviceProxyManager.h index 731ed703ac46..58af0ca273ea 100644 --- a/Engine/Source/Developer/TargetDeviceServices/Public/Interfaces/ITargetDeviceProxyManager.h +++ b/Engine/Source/Developer/TargetDeviceServices/Public/Interfaces/ITargetDeviceProxyManager.h @@ -79,6 +79,6 @@ public: public: - /** Virtual constructor. */ - ~ITargetDeviceProxyManager() { } + /** Virtual destructor. */ + virtual ~ITargetDeviceProxyManager() { } }; diff --git a/Engine/Source/Developer/TargetPlatform/Private/InstalledPlatformInfo.cpp b/Engine/Source/Developer/TargetPlatform/Private/InstalledPlatformInfo.cpp index d56a6f37e603..e5a57a38f9b5 100644 --- a/Engine/Source/Developer/TargetPlatform/Private/InstalledPlatformInfo.cpp +++ b/Engine/Source/Developer/TargetPlatform/Private/InstalledPlatformInfo.cpp @@ -8,6 +8,8 @@ #include "PlatformInfo.h" #include "IDesktopPlatform.h" #include "DesktopPlatformModule.h" +#include "ILauncherPlatform.h" +#include "LauncherPlatformModule.h" #define LOCTEXT_NAMESPACE "InstalledPlatformInfo" @@ -199,8 +201,9 @@ bool FInstalledPlatformInfo::IsPlatformMissingRequiredFile(const FString& Platfo bool FInstalledPlatformInfo::OpenInstallerOptions() { IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get(); + ILauncherPlatform* LauncherPlatform = FLauncherPlatformModule::Get(); - if (DesktopPlatform != nullptr) + if (DesktopPlatform != nullptr && LauncherPlatform != nullptr) { FString CurrentIdentifier = DesktopPlatform->GetCurrentEngineIdentifier(); if (DesktopPlatform->IsStockEngineRelease(CurrentIdentifier)) @@ -210,7 +213,7 @@ bool FInstalledPlatformInfo::OpenInstallerOptions() // TODO: Ensure that this URL opens the launcher correctly before this is included in a release FString InstallerURL = FString::Printf(TEXT("ue/library/engines/UE_%s/installer"), *DesktopPlatform->GetEngineDescription(CurrentIdentifier)); FOpenLauncherOptions OpenOptions(InstallerURL); - if (DesktopPlatform->OpenLauncher(OpenOptions)) + if (LauncherPlatform->OpenLauncher(OpenOptions)) { return true; } diff --git a/Engine/Source/Developer/TargetPlatform/Private/TargetPlatformManagerModule.cpp b/Engine/Source/Developer/TargetPlatform/Private/TargetPlatformManagerModule.cpp index 6fe6d7132302..52a072c8d99a 100644 --- a/Engine/Source/Developer/TargetPlatform/Private/TargetPlatformManagerModule.cpp +++ b/Engine/Source/Developer/TargetPlatform/Private/TargetPlatformManagerModule.cpp @@ -21,8 +21,8 @@ #include "Interfaces/ITextureFormatModule.h" #include "PlatformInfo.h" #include "DesktopPlatformModule.h" -#include "IPhysXFormat.h" -#include "IPhysXFormatModule.h" +#include "IPhysXCooking.h" +#include "IPhysXCookingModule.h" DEFINE_LOG_CATEGORY_STATIC(LogTargetPlatformManager, Log, All); @@ -499,10 +499,10 @@ public: return *Result; } - virtual const TArray& GetPhysXFormats() override + virtual const TArray& GetPhysXCooking() override { static bool bInitialized = false; - static TArray Results; + static TArray Results; if (!bInitialized || bForceCacheUpdate) { @@ -510,7 +510,7 @@ public: Results.Empty(Results.Num()); TArray Modules; - FModuleManager::Get().FindModules(TEXT("PhysXFormat*"), Modules); + FModuleManager::Get().FindModules(TEXT("PhysXCooking*"), Modules); if (!Modules.Num()) { @@ -519,10 +519,10 @@ public: for (int32 Index = 0; Index < Modules.Num(); Index++) { - IPhysXFormatModule* Module = FModuleManager::LoadModulePtr(Modules[Index]); + IPhysXCookingModule* Module = FModuleManager::LoadModulePtr(Modules[Index]); if (Module) { - IPhysXFormat* Format = Module->GetPhysXFormat(); + IPhysXCooking* Format = Module->GetPhysXCooking(); if (Format != nullptr) { Results.Add(Format); @@ -534,21 +534,21 @@ public: return Results; } - virtual const IPhysXFormat* FindPhysXFormat(FName Name) override + virtual const IPhysXCooking* FindPhysXCooking(FName Name) override { - const TArray& PhysXFormats = GetPhysXFormats(); + const TArray& PhysXCooking = GetPhysXCooking(); - for (int32 Index = 0; Index < PhysXFormats.Num(); Index++) + for (int32 Index = 0; Index < PhysXCooking.Num(); Index++) { TArray Formats; - PhysXFormats[Index]->GetSupportedFormats(Formats); + PhysXCooking[Index]->GetSupportedFormats(Formats); for (int32 FormatIndex = 0; FormatIndex < Formats.Num(); FormatIndex++) { if (Formats[FormatIndex] == Name) { - return PhysXFormats[Index]; + return PhysXCooking[Index]; } } } diff --git a/Engine/Source/Developer/TargetPlatform/Public/Interfaces/ITargetPlatformManagerModule.h b/Engine/Source/Developer/TargetPlatform/Public/Interfaces/ITargetPlatformManagerModule.h index 27542a99f174..5edfd7a6fa1f 100644 --- a/Engine/Source/Developer/TargetPlatform/Public/Interfaces/ITargetPlatformManagerModule.h +++ b/Engine/Source/Developer/TargetPlatform/Public/Interfaces/ITargetPlatformManagerModule.h @@ -30,7 +30,7 @@ public: * @param Name Name of the format to find. * @return The PhysX format, or nullptr if not found. */ - virtual const class IPhysXFormat* FindPhysXFormat( FName Name ) = 0; + virtual const class IPhysXCooking* FindPhysXCooking( FName Name ) = 0; /** * Finds a shader format with the specified name. @@ -86,11 +86,11 @@ public: virtual const TArray& GetAudioFormats() = 0; /** - * Returns the list of all IPhysXFormats that were located in DLLs. + * Returns the list of all IPhysXCooking that were located in DLLs. * * @return Collection of PhysX formats. */ - virtual const TArray& GetPhysXFormats() = 0; + virtual const TArray& GetPhysXCooking() = 0; /** * Returns the target platform that is currently running. diff --git a/Engine/Source/Developer/TargetPlatform/TargetPlatform.Build.cs b/Engine/Source/Developer/TargetPlatform/TargetPlatform.Build.cs index 099714453bd4..5a13dd281e41 100644 --- a/Engine/Source/Developer/TargetPlatform/TargetPlatform.Build.cs +++ b/Engine/Source/Developer/TargetPlatform/TargetPlatform.Build.cs @@ -9,8 +9,9 @@ public class TargetPlatform : ModuleRules { PrivateDependencyModuleNames.Add("Core"); PublicDependencyModuleNames.Add("DesktopPlatform"); + PublicDependencyModuleNames.Add("LauncherPlatform"); - PrivateIncludePathModuleNames.Add("PhysXFormats"); + PrivateIncludePathModuleNames.Add("Engine"); // no need for all these modules if the program doesn't want developer tools at all (like UnrealFileServer) if (!UEBuildConfiguration.bBuildRequiresCookedData && UEBuildConfiguration.bBuildDeveloperTools) @@ -98,7 +99,6 @@ public class TargetPlatform : ModuleRules DynamicallyLoadedModuleNames.Add("Android_DXTTargetPlatform"); DynamicallyLoadedModuleNames.Add("Android_ETC1TargetPlatform"); DynamicallyLoadedModuleNames.Add("Android_ETC2TargetPlatform"); - DynamicallyLoadedModuleNames.Add("Android_ASTCTargetPlatform"); DynamicallyLoadedModuleNames.Add("IOSTargetPlatform"); DynamicallyLoadedModuleNames.Add("TVOSTargetPlatform"); DynamicallyLoadedModuleNames.Add("HTML5TargetPlatform"); @@ -113,7 +113,7 @@ public class TargetPlatform : ModuleRules DynamicallyLoadedModuleNames.Add("TextureFormatASTC"); } - DynamicallyLoadedModuleNames.Add("TextureFormatUncompressed"); + DynamicallyLoadedModuleNames.Add("TextureFormatUncompressed"); if (UEBuildConfiguration.bCompileAgainstEngine) { @@ -136,9 +136,9 @@ public class TargetPlatform : ModuleRules } } - if (UEBuildConfiguration.bBuildDeveloperTools == true && (UEBuildConfiguration.bBuildRequiresCookedData || UEBuildConfiguration.bRuntimePhysicsCooking) && UEBuildConfiguration.bCompileAgainstEngine && UEBuildConfiguration.bCompilePhysX) + if (UEBuildConfiguration.bBuildDeveloperTools == true && UEBuildConfiguration.bBuildRequiresCookedData && UEBuildConfiguration.bCompileAgainstEngine && UEBuildConfiguration.bCompilePhysX) { - DynamicallyLoadedModuleNames.Add("PhysXFormats"); + DynamicallyLoadedModuleNames.Add("PhysXCooking"); } } } diff --git a/Engine/Source/Developer/VulkanShaderFormat/Private/VulkanBackend.cpp b/Engine/Source/Developer/VulkanShaderFormat/Private/VulkanBackend.cpp index f1b6b5075e12..acaf904281fc 100644 --- a/Engine/Source/Developer/VulkanShaderFormat/Private/VulkanBackend.cpp +++ b/Engine/Source/Developer/VulkanShaderFormat/Private/VulkanBackend.cpp @@ -3477,7 +3477,7 @@ struct SPromoteSampleLevelES2 : public ir_hierarchical_visitor // Converts an array index expression using an integer input attribute, to a float input attribute using a conversion to int -struct SConvertIntVertexAttributeES2 : public ir_hierarchical_visitor +struct SConvertIntVertexAttributeES2 final : public ir_hierarchical_visitor { _mesa_glsl_parse_state* ParseState; exec_list* FunctionBody; @@ -3488,6 +3488,10 @@ struct SConvertIntVertexAttributeES2 : public ir_hierarchical_visitor { } + virtual ~SConvertIntVertexAttributeES2() + { + } + virtual ir_visitor_status visit_enter(ir_dereference_array* DeRefArray) override { // Break the array dereference so we know we want to modify the array index part diff --git a/Engine/Source/Developer/Windows/ShaderFormatD3D/Private/D3D11ShaderCompiler.cpp b/Engine/Source/Developer/Windows/ShaderFormatD3D/Private/D3D11ShaderCompiler.cpp index 54d92bd38445..d6e386c0de52 100644 --- a/Engine/Source/Developer/Windows/ShaderFormatD3D/Private/D3D11ShaderCompiler.cpp +++ b/Engine/Source/Developer/Windows/ShaderFormatD3D/Private/D3D11ShaderCompiler.cpp @@ -167,7 +167,7 @@ static FString D3D11CreateShaderCompileCommandLine( ) { // fxc is our command line compiler - FString FXCCommandline = FString(TEXT("\"%DXSDK_DIR%\\Utilities\\bin\\x86\\fxc\" ")) + ShaderPath; + FString FXCCommandline = FString(TEXT("%FXC% ")) + ShaderPath; // add the entry point reference FXCCommandline += FString(TEXT(" /E ")) + EntryFunction; @@ -258,7 +258,29 @@ static FString D3D11CreateShaderCompileCommandLine( // add a pause on a newline FXCCommandline += FString(TEXT(" \r\n pause")); - return FXCCommandline; + + // Batch file header: + /* + @ECHO OFF + SET FXC="C:\Program Files (x86)\Windows Kits\8.1\bin\x64\fxc.exe" + IF EXIST %FXC% ( + REM + ) ELSE ( + ECHO Couldn't find Windows 8.1 SDK, falling back to DXSDK... + SET FXC="%DXSDK_DIR%\Utilities\bin\x86\fxc.exe" + IF EXIST %FXC% ( + REM + ) ELSE ( + ECHO Couldn't find DXSDK! Exiting... + GOTO END + ) + ) + */ + FString BatchFileHeader = TEXT("@ECHO OFF\nSET FXC=\"C:\\Program Files (x86)\\Windows Kits\\8.1\\bin\\x64\\fxc.exe\"\n"\ + "IF EXIST %FXC% (\nREM\n) ELSE (\nECHO Couldn't find Windows 8.1 SDK, falling back to DXSDK...\n"\ + "SET FXC=\"%DXSDK_DIR%\\Utilities\\bin\\x86\\fxc.exe\"\nIF EXIST %FXC% (\nREM\n) ELSE (\nECHO Couldn't find DXSDK! Exiting...\n"\ + "GOTO END\n)\n)\n"); + return BatchFileHeader + FXCCommandline + TEXT("\n:END\nREM\n"); } /** Creates a batch file string to call the AMD shader analyzer. */ @@ -284,8 +306,37 @@ static FString CreateAMDCodeXLCommandLine( return Commandline; } -// @return pointer to the D3DCompile function -pD3DCompile GetD3DCompileFunc(const FString& NewCompilerPath) +// D3Dcompiler.h has function pointer typedefs for some functions, but not all +typedef HRESULT(WINAPI *pD3DReflect) + (__in_bcount(SrcDataSize) LPCVOID pSrcData, + __in SIZE_T SrcDataSize, + __in REFIID pInterface, + __out void** ppReflector); + +typedef HRESULT(WINAPI *pD3DStripShader) + (__in_bcount(BytecodeLength) LPCVOID pShaderBytecode, + __in SIZE_T BytecodeLength, + __in UINT uStripFlags, + __out ID3DBlob** ppStrippedBlob); + +#define DEFINE_GUID_FOR_CURRENT_COMPILER(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + static const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } + +// ShaderReflection IIDs may change between SDK versions if the reflection API changes. +// Define a GUID below that matches the desired IID for the DLL in CompilerPath. For example, +// look for IID_ID3D11ShaderReflection in d3d11shader.h for the SDK matching the compiler DLL. +DEFINE_GUID_FOR_CURRENT_COMPILER(IID_ID3D11ShaderReflectionForCurrentCompiler, 0x8d536ca1, 0x0cca, 0x4956, 0xa8, 0x37, 0x78, 0x69, 0x63, 0x75, 0x55, 0x84); + +/** + * GetD3DCompilerFuncs - gets function pointers from the dll at NewCompilerPath + * @param OutD3DCompile - function pointer for D3DCompile (0 if not found) + * @param OutD3DReflect - function pointer for D3DReflect (0 if not found) + * @param OutD3DDisassemble - function pointer for D3DDisassemble (0 if not found) + * @param OutD3DStripShader - function pointer for D3DStripShader (0 if not found) + * @return bool - true if functions were retrieved from NewCompilerPath + */ +static bool GetD3DCompilerFuncs(const FString& NewCompilerPath, pD3DCompile* OutD3DCompile, + pD3DReflect* OutD3DReflect, pD3DDisassemble* OutD3DDisassemble, pD3DStripShader* OutD3DStripShader) { static FString CurrentCompiler; static HMODULE CompilerDLL = 0; @@ -308,21 +359,33 @@ pD3DCompile GetD3DCompileFunc(const FString& NewCompilerPath) if(!CompilerDLL && NewCompilerPath.Len()) { // Couldn't find HLSL compiler in specified path. We fail the first compile. - return 0; - } + *OutD3DCompile = 0; + *OutD3DReflect = 0; + *OutD3DDisassemble = 0; + *OutD3DStripShader = 0; + return false; + } } if(CompilerDLL) { // from custom folder e.g. "C:/DXWin8/D3DCompiler_44.dll" - return (pD3DCompile)(void*)GetProcAddress(CompilerDLL, "D3DCompile"); + *OutD3DCompile = (pD3DCompile)(void*)GetProcAddress(CompilerDLL, "D3DCompile"); + *OutD3DReflect = (pD3DReflect)(void*)GetProcAddress(CompilerDLL, "D3DReflect"); + *OutD3DDisassemble = (pD3DDisassemble)(void*)GetProcAddress(CompilerDLL, "D3DDisassemble"); + *OutD3DStripShader = (pD3DStripShader)(void*)GetProcAddress(CompilerDLL, "D3DStripShader"); + return true; } // D3D SDK we compiled with (usually D3DCompiler_43.dll from windows folder) - return &D3DCompile; + *OutD3DCompile = &D3DCompile; + *OutD3DReflect = &D3DReflect; + *OutD3DDisassemble = &D3DDisassemble; + *OutD3DStripShader = &D3DStripShader; + return false; } -HRESULT D3DCompileWrapper( +static HRESULT D3DCompileWrapper( pD3DCompile D3DCompileFunc, bool& bException, LPCVOID pSrcData, @@ -405,7 +468,11 @@ static bool CompileAndProcessD3DShader(FString& PreprocessedShaderSource, const TRefCountPtr Errors; HRESULT Result; - pD3DCompile D3DCompileFunc = GetD3DCompileFunc(CompilerPath); + pD3DCompile D3DCompileFunc; + pD3DReflect D3DReflectFunc; + pD3DDisassemble D3DDisassembleFunc; + pD3DStripShader D3DStripShaderFunc; + const bool bCompilerPathFunctionsUsed = GetD3DCompilerFuncs(CompilerPath, &D3DCompileFunc, &D3DReflectFunc, &D3DDisassembleFunc, &D3DStripShaderFunc); if (D3DCompileFunc) { @@ -448,10 +515,10 @@ static bool CompileAndProcessD3DShader(FString& PreprocessedShaderSource, const // Fail the compilation if double operations are being used, since those are not supported on all D3D11 cards if (SUCCEEDED(Result)) { - if (GD3DCheckForDoubles || GD3DDumpD3DAsmFile) + if (D3DDisassembleFunc && (GD3DCheckForDoubles || GD3DDumpD3DAsmFile)) { TRefCountPtr Dissasembly; - if (SUCCEEDED(D3DDisassemble(Shader->GetBufferPointer(), Shader->GetBufferSize(), 0, "", Dissasembly.GetInitReference()))) + if (SUCCEEDED(D3DDisassembleFunc(Shader->GetBufferPointer(), Shader->GetBufferSize(), 0, "", Dissasembly.GetInitReference()))) { ANSICHAR* DissasemblyString = new ANSICHAR[Dissasembly->GetBufferSize() + 1]; FMemory::Memcpy(DissasemblyString, Dissasembly->GetBufferPointer(), Dissasembly->GetBufferSize()); @@ -474,17 +541,23 @@ static bool CompileAndProcessD3DShader(FString& PreprocessedShaderSource, const } } } + } - // Gather reflection information - int32 NumInterpolants = 0; - TIndirectArray InterpolantNames; - TArray ShaderInputs; - if (SUCCEEDED(Result)) + // Gather reflection information + int32 NumInterpolants = 0; + TIndirectArray InterpolantNames; + TArray ShaderInputs; + if (SUCCEEDED(Result)) + { + if (D3DReflectFunc) { Output.bSucceeded = true; - ID3D11ShaderReflection* Reflector = NULL; - Result = D3DReflect(Shader->GetBufferPointer(), Shader->GetBufferSize(), IID_ID3D11ShaderReflection, (void**)&Reflector); + + // IID_ID3D11ShaderReflectionForCurrentCompiler is defined in this file and needs to match the IID from the dll in CompilerPath + // if the function pointers from that dll are being used + const IID ShaderReflectionInterfaceID = bCompilerPathFunctionsUsed ? IID_ID3D11ShaderReflectionForCurrentCompiler : IID_ID3D11ShaderReflection; + Result = D3DReflectFunc(Shader->GetBufferPointer(), Shader->GetBufferSize(), ShaderReflectionInterfaceID, (void**)&Reflector); if (FAILED(Result)) { UE_LOG(LogD3D11ShaderCompiler, Fatal, TEXT("D3DReflect failed: Result=%08x"), Result); @@ -738,13 +811,13 @@ static bool CompileAndProcessD3DShader(FString& PreprocessedShaderSource, const { CompressedData = Shader; } - else + else if (D3DStripShaderFunc) { // Strip shader reflection and debug info D3D_SHADER_DATA ShaderData; ShaderData.pBytecode = Shader->GetBufferPointer(); ShaderData.BytecodeLength = Shader->GetBufferSize(); - Result = D3DStripShader(Shader->GetBufferPointer(), + Result = D3DStripShaderFunc(Shader->GetBufferPointer(), Shader->GetBufferSize(), D3DCOMPILER_STRIP_REFLECTION_DATA | D3DCOMPILER_STRIP_DEBUG_INFO | D3DCOMPILER_STRIP_TEST_BLOBS, CompressedData.GetInitReference()); @@ -754,6 +827,12 @@ static bool CompileAndProcessD3DShader(FString& PreprocessedShaderSource, const UE_LOG(LogD3D11ShaderCompiler, Fatal, TEXT("D3DStripShader failed: Result=%08x"), Result); } } + else + { + // D3DStripShader is not guaranteed to exist + // e.g. the open-source DXIL shader compiler does not currently implement it + CompressedData = Shader; + } // Build the SRT for this shader. FD3D11ShaderResourceTable SRT; @@ -833,7 +912,16 @@ static bool CompileAndProcessD3DShader(FString& PreprocessedShaderSource, const // Pass the target through to the output. Output.Target = Input.Target; } + else + { + FilteredErrors.Add(FString::Printf(TEXT("Couldn't find shader reflection function in %s"), *CompilerPath)); + Result = E_FAIL; + Output.bSucceeded = false; + } + } + if (SUCCEEDED(Result)) + { if (Input.Target.Platform == SP_PCD3D_ES2) { if (Output.NumTextureSamplers > 8) @@ -858,7 +946,8 @@ static bool CompileAndProcessD3DShader(FString& PreprocessedShaderSource, const } } } - else + + if (FAILED(Result)) { ++GBreakpoint; } diff --git a/Engine/Source/Developer/Windows/WindowsPlatformEditor/Private/WindowsPlatformEditorModule.cpp b/Engine/Source/Developer/Windows/WindowsPlatformEditor/Private/WindowsPlatformEditorModule.cpp new file mode 100644 index 000000000000..99e23e9903e7 --- /dev/null +++ b/Engine/Source/Developer/Windows/WindowsPlatformEditor/Private/WindowsPlatformEditorModule.cpp @@ -0,0 +1,51 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "CoreMinimal.h" +#include "ModuleInterface.h" +#include "ISettingsModule.h" +#include "ModuleManager.h" +#include "WindowsTargetSettings.h" +#include "UObject/WeakObjectPtr.h" +#include "UObject/Class.h" + +#define LOCTEXT_NAMESPACE "WindowsPlatformEditorModule" + + +/** + * Module for Windows project settings + */ +class FWindowsPlatformEditorModule + : public IModuleInterface +{ + // IModuleInterface interface + + virtual void StartupModule() override + { + // register settings + ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings"); + + if (SettingsModule != nullptr) + { + SettingsModule->RegisterSettings("Project", "Platforms", "Windows", + LOCTEXT("TargetSettingsName", "Windows"), + LOCTEXT("TargetSettingsDescription", "Settings for Windows target platform"), + GetMutableDefault() + ); + } + } + + virtual void ShutdownModule() override + { + ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings"); + + if (SettingsModule != nullptr) + { + SettingsModule->UnregisterSettings("Project", "Platforms", "Windows"); + } + } +}; + + +IMPLEMENT_MODULE(FWindowsPlatformEditorModule, WindowsPlatformEditor); + +#undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Developer/Windows/WindowsPlatformEditor/WindowsPlatformEditor.Build.cs b/Engine/Source/Developer/Windows/WindowsPlatformEditor/WindowsPlatformEditor.Build.cs new file mode 100644 index 000000000000..bc7d70279f5f --- /dev/null +++ b/Engine/Source/Developer/Windows/WindowsPlatformEditor/WindowsPlatformEditor.Build.cs @@ -0,0 +1,43 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +using UnrealBuildTool; + +public class WindowsPlatformEditor : ModuleRules +{ + public WindowsPlatformEditor(ReadOnlyTargetRules Target) : base(Target) + { + PrivateDependencyModuleNames.AddRange( + new string[] { + "Core", + "CoreUObject", + "InputCore", + "DesktopPlatform", + "Engine", + "MainFrame", + "Slate", + "SlateCore", + "EditorStyle", + "PropertyEditor", + "SharedSettingsWidgets", + "SourceControl", + "WindowsTargetPlatform", + "TargetPlatform", + "MaterialShaderQualitySettings", + "RenderCore", + } + ); + + PrivateIncludePathModuleNames.AddRange( + new string[] { + "GameProjectGeneration", + "Settings", + } + ); + + DynamicallyLoadedModuleNames.AddRange( + new string[] { + "GameProjectGeneration", + } + ); + } +} diff --git a/Engine/Source/Developer/Windows/WindowsTargetPlatform/Classes/WindowsTargetSettings.h b/Engine/Source/Developer/Windows/WindowsTargetPlatform/Classes/WindowsTargetSettings.h index 3c16b6a28741..313854d9761d 100644 --- a/Engine/Source/Developer/Windows/WindowsTargetPlatform/Classes/WindowsTargetSettings.h +++ b/Engine/Source/Developer/Windows/WindowsTargetPlatform/Classes/WindowsTargetSettings.h @@ -58,4 +58,24 @@ public: UPROPERTY(config, EditAnywhere, Category = "Audio") FString AudioDevice; + /** Sample rate to run the audio mixer with. */ + UPROPERTY(config, EditAnywhere, Category = "Audio", Meta = (DisplayName = "Audio Mixer Sample Rate")) + int32 AudioSampleRate; + + /** The amount of audio to compute each callback block. Lower values decrease latency but may increase CPU cost. */ + UPROPERTY(config, EditAnywhere, Category = "Audio", meta = (ClampMin = "512", ClampMax = "4096", DisplayName = "Callback Buffer Size")) + int32 AudioCallbackBufferFrameSize; + + /** The number of buffers to keep enqueued. More buffers increases latency, but can compensate for variable compute availability in audio callbacks on some platforms. */ + UPROPERTY(config, EditAnywhere, Category = "Audio", meta = (ClampMin = "1", UIMin = "1", DisplayName = "Number of Buffers To Enqueue")) + int32 AudioNumBuffersToEnqueue; + + /** The max number of channels (voices) to limit for this platform. The max channels used will be the minimum of this value and the global audio quality settings. A value of 0 will not apply a platform channel count max. */ + UPROPERTY(config, EditAnywhere, Category = "Audio", meta = (ClampMin = "0", UIMin = "0", DisplayName = "Max Channels")) + int32 AudioMaxChannels; + + /** The number of workers to use to compute source audio. Will only use up to the max number of sources. Will evenly divide sources to each source worker. */ + UPROPERTY(config, EditAnywhere, Category = "Audio", meta = (ClampMin = "0", UIMin = "0", DisplayName = "Number of Source Workers")) + int32 AudioNumSourceWorkers; + }; diff --git a/Engine/Source/Developer/Windows/WindowsTargetPlatform/Private/GenericWindowsTargetPlatform.h b/Engine/Source/Developer/Windows/WindowsTargetPlatform/Private/GenericWindowsTargetPlatform.h index e027cd6aa597..8eb89814119c 100644 --- a/Engine/Source/Developer/Windows/WindowsTargetPlatform/Private/GenericWindowsTargetPlatform.h +++ b/Engine/Source/Developer/Windows/WindowsTargetPlatform/Private/GenericWindowsTargetPlatform.h @@ -37,7 +37,7 @@ public: #endif #if WITH_ENGINE - FConfigCacheIni::LoadLocalIniFile(EngineSettings, TEXT("Engine"), true, *PlatformName()); + FConfigCacheIni::LoadLocalIniFile(EngineSettings, TEXT("Engine"), true, *this->PlatformName()); TextureLODSettings = nullptr; // These are registered by the device profile system. StaticMeshLODSettings.Initialize(EngineSettings); @@ -139,8 +139,6 @@ public: static FName NAME_VULKAN_ES31(TEXT("SF_VULKAN_ES31")); static FName NAME_OPENGL_150_ES2(TEXT("GLSL_150_ES2")); static FName NAME_OPENGL_150_ES3_1(TEXT("GLSL_150_ES31")); - static FName NAME_OPENGL_SWITCH(TEXT("GLSL_SWITCH")); - static FName NAME_OPENGL_SWITCH_FORWARD(TEXT("GLSL_SWITCH_FORWARD")); static FName NAME_VULKAN_SM4(TEXT("SF_VULKAN_SM4")); OutFormats.AddUnique(NAME_PCD3D_SM5); @@ -150,8 +148,6 @@ public: OutFormats.AddUnique(NAME_VULKAN_ES31); OutFormats.AddUnique(NAME_OPENGL_150_ES2); OutFormats.AddUnique(NAME_OPENGL_150_ES3_1); - OutFormats.AddUnique(NAME_OPENGL_SWITCH_FORWARD); - OutFormats.AddUnique(NAME_OPENGL_SWITCH); OutFormats.AddUnique(NAME_VULKAN_SM4); } } diff --git a/Engine/Source/Developer/Windows/WindowsTargetPlatform/Private/WindowsTargetPlatformClasses.cpp b/Engine/Source/Developer/Windows/WindowsTargetPlatform/Private/WindowsTargetPlatformClasses.cpp index 383a5017a069..b8cd776304ad 100644 --- a/Engine/Source/Developer/Windows/WindowsTargetPlatform/Private/WindowsTargetPlatformClasses.cpp +++ b/Engine/Source/Developer/Windows/WindowsTargetPlatform/Private/WindowsTargetPlatformClasses.cpp @@ -9,4 +9,10 @@ UWindowsTargetSettings::UWindowsTargetSettings( const FObjectInitializer& Object : Super(ObjectInitializer) { MinimumOSVersion = EMinimumSupportedOS::MSOS_Vista; + + // Default windows settings + AudioSampleRate = 48000; + AudioCallbackBufferFrameSize = 1024; + AudioNumBuffersToEnqueue = 1; + AudioNumSourceWorkers = 4; } diff --git a/Engine/Source/Developer/Windows/WindowsTargetPlatform/Private/WindowsTargetPlatformModule.cpp b/Engine/Source/Developer/Windows/WindowsTargetPlatform/Private/WindowsTargetPlatformModule.cpp index 4bb524a191a3..4641e2ada9cd 100644 --- a/Engine/Source/Developer/Windows/WindowsTargetPlatform/Private/WindowsTargetPlatformModule.cpp +++ b/Engine/Source/Developer/Windows/WindowsTargetPlatform/Private/WindowsTargetPlatformModule.cpp @@ -1,6 +1,6 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "WindowsTargetSettings.h" +#include "CoreMinimal.h" #include "ISettingsModule.h" #include "Interfaces/ITargetPlatformModule.h" #include "GenericWindowsTargetPlatform.h" @@ -67,41 +67,6 @@ public: #if 0 FCoreDelegates::GetHotfixDelegate(EHotfixDelegates::Test).BindRaw(this, &FWindowsTargetPlatformModule::HotfixTest); #endif - - TargetSettings = NewObject(GetTransientPackage(), "WindowsTargetSettings", RF_Standalone); - - FString Compiler; - if (GConfig->GetString(TEXT("/Script/WindowsTargetPlatform.WindowsTargetSettings"), TEXT("Compiler"), Compiler, GEngineIni)) - { - if (Compiler == TEXT("VisualStudio2015")) - { - TargetSettings->Compiler = ECompilerVersion::VisualStudio2015; - } - else if (Compiler == TEXT("VisualStudio2017")) - { - TargetSettings->Compiler = ECompilerVersion::VisualStudio2017; - } - } - - // We need to manually load the config properties here, as this module is loaded before the UObject system is setup to do this - GConfig->GetArray(TEXT("/Script/WindowsTargetPlatform.WindowsTargetSettings"), TEXT("TargetedRHIs"), TargetSettings->TargetedRHIs, GEngineIni); - - // When this is initialized the UEnum for EMinimumSupportedOS hasn't been registered. - TargetSettings->MinimumOSVersion = EMinimumSupportedOS::MSOS_Vista; - - - TargetSettings->AddToRoot(); - - ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings"); - - if (SettingsModule != nullptr) - { - SettingsModule->RegisterSettings("Project", "Platforms", "Windows", - LOCTEXT("TargetSettingsName", "Windows"), - LOCTEXT("TargetSettingsDescription", "Settings for Windows target platform"), - TargetSettings - ); - } } virtual void ShutdownModule() override @@ -112,27 +77,8 @@ public: #endif ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings"); - - if (SettingsModule != nullptr) - { - SettingsModule->UnregisterSettings("Project", "Platforms", "Windows"); - } - - if (!GExitPurge) - { - // If we're in exit purge, this object has already been destroyed - TargetSettings->RemoveFromRoot(); - } - else - { - TargetSettings = nullptr; - } } -private: - - // Holds the target settings. - UWindowsTargetSettings* TargetSettings; }; diff --git a/Engine/Source/Developer/iOS/IOSPlatformEditor/Private/IOSTargetSettingsCustomization.cpp b/Engine/Source/Developer/iOS/IOSPlatformEditor/Private/IOSTargetSettingsCustomization.cpp index 14843d3bca61..1f63ec74ba2b 100644 --- a/Engine/Source/Developer/iOS/IOSPlatformEditor/Private/IOSTargetSettingsCustomization.cpp +++ b/Engine/Source/Developer/iOS/IOSPlatformEditor/Private/IOSTargetSettingsCustomization.cpp @@ -878,7 +878,6 @@ void FIOSTargetSettingsCustomization::BuildPListSection(IDetailLayoutBuilder& De UpdateGLVersionWarning(); } - ITargetPlatform* TargetPlatform = FModuleManager::GetModuleChecked("IOSTargetPlatform").GetTargetPlatform(); SETUP_PLIST_PROP(bSupportsIPad, DeviceCategory); SETUP_PLIST_PROP(bSupportsIPhone, DeviceCategory); diff --git a/Engine/Source/Developer/iOS/IOSTargetPlatform/Private/IOSTargetPlatform.cpp b/Engine/Source/Developer/iOS/IOSTargetPlatform/Private/IOSTargetPlatform.cpp index 238f183fa82d..3c2d8d9db499 100644 --- a/Engine/Source/Developer/iOS/IOSTargetPlatform/Private/IOSTargetPlatform.cpp +++ b/Engine/Source/Developer/iOS/IOSTargetPlatform/Private/IOSTargetPlatform.cpp @@ -512,7 +512,7 @@ void FIOSTargetPlatform::GetTextureFormats( const UTexture* Texture, TArraySource.IsPowerOfTwo()) + if (!Texture->Source.IsPowerOfTwo() && Texture->PowerOfTwoMode == ETexturePowerOfTwoSetting::None) { // option 1: Uncompress, but users will get very large textures unknowningly // OutFormats.AddUnique(NameBGRA8); diff --git a/Engine/Source/Editor/AIGraph/Classes/AIGraphNode.h b/Engine/Source/Editor/AIGraph/Classes/AIGraphNode.h index 61a8b3a4c77c..6302a65b8dff 100644 --- a/Engine/Source/Editor/AIGraph/Classes/AIGraphNode.h +++ b/Engine/Source/Editor/AIGraph/Classes/AIGraphNode.h @@ -60,6 +60,7 @@ class AIGRAPH_API UAIGraphNode : public UEdGraphNode virtual void NodeConnectionListChanged() override; virtual bool CanCreateUnderSpecifiedSchema(const UEdGraphSchema* DesiredSchema) const override; virtual void FindDiffs(class UEdGraphNode* OtherNode, struct FDiffResults& Results) override; + virtual FString GetPropertyNameAndValueForDiff(const UProperty* Prop, const uint8* PropertyAddr) const override; //~ End UEdGraphNode Interface //~ Begin UObject Interface @@ -93,17 +94,6 @@ class AIGRAPH_API UAIGraphNode : public UEdGraphNode /** initialize instance object */ virtual void InitializeInstance(); - /** - * Finds the difference in properties of node instance - * - * @param Struct The struct of the class we are looking at - * @param Data The raw data for the UObject we are comparing LHS - * @param OtherData The raw data for the UObject we are comparing RHS - * @param Results The Results where differences are stored - * @param Diff The single result with default parameters setup - */ - void DiffProperties(UStruct* Struct, void* Data, void* OtherData, FDiffResults& Results, FDiffSingleResult& Diff); - /** reinitialize node instance */ virtual bool RefreshNodeClass(); diff --git a/Engine/Source/Editor/AIGraph/Private/AIGraphNode.cpp b/Engine/Source/Editor/AIGraph/Private/AIGraphNode.cpp index e819b3ed7282..ae1b5db0b241 100644 --- a/Engine/Source/Editor/AIGraph/Private/AIGraphNode.cpp +++ b/Engine/Source/Editor/AIGraph/Private/AIGraphNode.cpp @@ -28,8 +28,10 @@ void UAIGraphNode::InitializeInstance() void UAIGraphNode::PostPlacedNewNode() { + // NodeInstance can be already spawned by paste operation, don't override it + UClass* NodeClass = ClassData.GetClass(true); - if (NodeClass) + if (NodeClass && (NodeInstance == nullptr)) { UEdGraph* MyGraph = GetGraph(); UObject* GraphOwner = MyGraph ? MyGraph->GetOuter() : nullptr; @@ -244,56 +246,27 @@ bool UAIGraphNode::CanCreateUnderSpecifiedSchema(const UEdGraphSchema* DesiredSc return false; } -void UAIGraphNode::DiffProperties(UStruct* Struct, void* DataA, void* DataB, FDiffResults& Results, FDiffSingleResult& Diff) +FString UAIGraphNode::GetPropertyNameAndValueForDiff(const UProperty* Prop, const uint8* PropertyAddr) const { - for (TFieldIterator PropertyIt(Struct, EFieldIteratorFlags::IncludeSuper); PropertyIt; ++PropertyIt) - { - UProperty* Prop = *PropertyIt; - // skip properties we cant see - if (!Prop->HasAnyPropertyFlags(CPF_Edit | CPF_BlueprintVisible) || - Prop->HasAnyPropertyFlags(CPF_Transient) || - Prop->HasAnyPropertyFlags(CPF_DisableEditOnInstance) || - Prop->IsA(UFunction::StaticClass()) || - Prop->IsA(UDelegateProperty::StaticClass()) || - Prop->IsA(UMulticastDelegateProperty::StaticClass())) - { - continue; - } - - FString ValueStringA = BlueprintNodeHelpers::DescribeProperty(Prop, Prop->ContainerPtrToValuePtr(DataA)); - FString ValueStringB = BlueprintNodeHelpers::DescribeProperty(Prop, Prop->ContainerPtrToValuePtr(DataB)); - - if (ValueStringA != ValueStringB) - { - // Only bother setting up the display data if we're storing the result - if(Results.CanStoreResults()) - { - Diff.DisplayString = FText::Format(LOCTEXT("DIF_NodePropertyFmt", "Property Changed: {0} "), FText::FromString(Prop->GetName())); - } - Results.Add(Diff); - } - } + return BlueprintNodeHelpers::DescribeProperty(Prop, PropertyAddr); } void UAIGraphNode::FindDiffs(UEdGraphNode* OtherNode, FDiffResults& Results) { Super::FindDiffs(OtherNode, Results); - FDiffSingleResult Diff; - Diff.Diff = EDiffType::NODE_PROPERTY; - Diff.Node1 = this; - Diff.Node2 = OtherNode; - Diff.ToolTip = LOCTEXT("DIF_NodePropertyToolTip", "A Property of the node has changed"); - Diff.DisplayColor = FLinearColor(0.25f, 0.71f, 0.85f); - - UAIGraphNode* OtherGraphNode = Cast(OtherNode); - if (OtherGraphNode) + if (UAIGraphNode* OtherGraphNode = Cast(OtherNode)) { - DiffProperties(GetClass(), this, OtherGraphNode, Results, Diff); - if (NodeInstance && OtherGraphNode->NodeInstance) { - DiffProperties(NodeInstance->GetClass(), NodeInstance, OtherGraphNode->NodeInstance, Results, Diff); + FDiffSingleResult Diff; + Diff.Diff = EDiffType::NODE_PROPERTY; + Diff.Node1 = this; + Diff.Node2 = OtherNode; + Diff.ToolTip = LOCTEXT("DIF_NodeInstancePropertyToolTip", "A property of the node instance has changed"); + Diff.DisplayColor = FLinearColor(0.25f, 0.71f, 0.85f); + + DiffProperties(NodeInstance->GetClass(), OtherGraphNode->NodeInstance->GetClass(), NodeInstance, OtherGraphNode->NodeInstance, Results, Diff); } } } diff --git a/Engine/Source/Editor/AddContentDialog/Private/ContentSourceProviders/FeaturePack/FeaturePackContentSource.cpp b/Engine/Source/Editor/AddContentDialog/Private/ContentSourceProviders/FeaturePack/FeaturePackContentSource.cpp index ff0c5602a102..d89fe7b0ab6a 100644 --- a/Engine/Source/Editor/AddContentDialog/Private/ContentSourceProviders/FeaturePack/FeaturePackContentSource.cpp +++ b/Engine/Source/Editor/AddContentDialog/Private/ContentSourceProviders/FeaturePack/FeaturePackContentSource.cpp @@ -213,8 +213,6 @@ FFeaturePackContentSource::FFeaturePackContentSource(FString InFeaturePackPath, FFeaturePackContentSource::FFeaturePackContentSource() { bPackValid = false; - TSharedPtr ManifestObject; - bPackValid = false; } bool FFeaturePackContentSource::LoadPakFileToBuffer(FPakPlatformFile& PakPlatformFile, FString Path, TArray& Buffer) diff --git a/Engine/Source/Editor/AdvancedPreviewScene/Private/AdvancedPreviewScene.cpp b/Engine/Source/Editor/AdvancedPreviewScene/Private/AdvancedPreviewScene.cpp index da2d71f9e02b..528039e139c0 100644 --- a/Engine/Source/Editor/AdvancedPreviewScene/Private/AdvancedPreviewScene.cpp +++ b/Engine/Source/Editor/AdvancedPreviewScene/Private/AdvancedPreviewScene.cpp @@ -69,6 +69,7 @@ FAdvancedPreviewScene::FAdvancedPreviewScene(ConstructionValues CVS, float InFlo InstancedSkyMaterial->Parent = SkyMaterial; UTextureCube* DefaultTexture = LoadObject(NULL, TEXT("/Engine/MapTemplates/Sky/SunsetAmbientCubemap.SunsetAmbientCubemap")); + InstancedSkyMaterial->SetTextureParameterValueEditorOnly(FName("SkyBox"), ( Profile.EnvironmentCubeMap.Get() != nullptr ) ? Profile.EnvironmentCubeMap.Get() : DefaultTexture ); InstancedSkyMaterial->SetScalarParameterValueEditorOnly(FName("CubemapRotation"), Profile.LightingRigRotation / 360.0f); InstancedSkyMaterial->SetScalarParameterValueEditorOnly(FName("Intensity"), Profile.SkyLightIntensity); @@ -454,12 +455,15 @@ void FAdvancedPreviewScene::HandleToggleFloor() void FAdvancedPreviewScene::OnAssetViewerSettingsRefresh(const FName& InPropertyName) { - const bool bNameNone = InPropertyName == NAME_None; + if (DefaultSettings->Profiles.IsValidIndex(CurrentProfileIndex)) + { + const bool bNameNone = InPropertyName == NAME_None; - const bool bUpdateEnvironment = (InPropertyName == GET_MEMBER_NAME_CHECKED(FPreviewSceneProfile, EnvironmentCubeMap)) || (InPropertyName == GET_MEMBER_NAME_CHECKED(FPreviewSceneProfile, LightingRigRotation) || (InPropertyName == GET_MEMBER_NAME_CHECKED(UAssetViewerSettings, Profiles))); - const bool bUpdateSkyLight = bUpdateEnvironment || (InPropertyName == GET_MEMBER_NAME_CHECKED(FPreviewSceneProfile, SkyLightIntensity) || (InPropertyName == GET_MEMBER_NAME_CHECKED(UAssetViewerSettings, Profiles))); - const bool bUpdateDirectionalLight = (InPropertyName == GET_MEMBER_NAME_CHECKED(FPreviewSceneProfile, DirectionalLightIntensity)) || (InPropertyName == GET_MEMBER_NAME_CHECKED(FPreviewSceneProfile, DirectionalLightColor)); - const bool bUpdatePostProcessing = (InPropertyName == GET_MEMBER_NAME_CHECKED(FPreviewSceneProfile, PostProcessingSettings)) || (InPropertyName == GET_MEMBER_NAME_CHECKED(FPreviewSceneProfile, bPostProcessingEnabled)); + const bool bUpdateEnvironment = (InPropertyName == GET_MEMBER_NAME_CHECKED(FPreviewSceneProfile, EnvironmentCubeMap)) || (InPropertyName == GET_MEMBER_NAME_CHECKED(FPreviewSceneProfile, LightingRigRotation) || (InPropertyName == GET_MEMBER_NAME_CHECKED(UAssetViewerSettings, Profiles))); + const bool bUpdateSkyLight = bUpdateEnvironment || (InPropertyName == GET_MEMBER_NAME_CHECKED(FPreviewSceneProfile, SkyLightIntensity) || (InPropertyName == GET_MEMBER_NAME_CHECKED(UAssetViewerSettings, Profiles))); + const bool bUpdateDirectionalLight = (InPropertyName == GET_MEMBER_NAME_CHECKED(FPreviewSceneProfile, DirectionalLightIntensity)) || (InPropertyName == GET_MEMBER_NAME_CHECKED(FPreviewSceneProfile, DirectionalLightColor)); + const bool bUpdatePostProcessing = (InPropertyName == GET_MEMBER_NAME_CHECKED(FPreviewSceneProfile, PostProcessingSettings)) || (InPropertyName == GET_MEMBER_NAME_CHECKED(FPreviewSceneProfile, bPostProcessingEnabled)); - UpdateScene(DefaultSettings->Profiles[CurrentProfileIndex], bUpdateSkyLight || bNameNone, bUpdateEnvironment || bNameNone, bUpdatePostProcessing || bNameNone, bUpdateDirectionalLight || bNameNone); + UpdateScene(DefaultSettings->Profiles[CurrentProfileIndex], bUpdateSkyLight || bNameNone, bUpdateEnvironment || bNameNone, bUpdatePostProcessing || bNameNone, bUpdateDirectionalLight || bNameNone); + } } \ No newline at end of file diff --git a/Engine/Source/Editor/AdvancedPreviewScene/Private/AssetViewerSettings.cpp b/Engine/Source/Editor/AdvancedPreviewScene/Private/AssetViewerSettings.cpp index cf1096fb75c2..130ff2b0c5e2 100644 --- a/Engine/Source/Editor/AdvancedPreviewScene/Private/AssetViewerSettings.cpp +++ b/Engine/Source/Editor/AdvancedPreviewScene/Private/AssetViewerSettings.cpp @@ -46,6 +46,12 @@ UAssetViewerSettings* UAssetViewerSettings::Get() void UAssetViewerSettings::Save() { + ULocalProfiles* LocalProfilesObject = GetMutableDefault(); + USharedProfiles* SharedProfilesObject = GetMutableDefault(); + + TArray& LocalProfiles = GetMutableDefault()->Profiles; + TArray& SharedProfiles = GetMutableDefault()->Profiles; + LocalProfiles.Empty(); SharedProfiles.Empty(); @@ -62,29 +68,10 @@ void UAssetViewerSettings::Save() } } - UClass* Class = GetClass(); - UField* Child = Class->Children; - const FString LocalFilename = GetConfigFilename(this); - const FString SharedFilename = GetDefaultConfigFilename(); + LocalProfilesObject->SaveConfig(); - // Store name for last selected profile - GetMutableDefault()->AssetViewerProfileName = Profiles[GetMutableDefault()->AssetViewerProfileIndex].ProfileName; - - UProperty* PropertyLink = Class->PropertyLink; - for (UProperty* Property = GetClass()->PropertyLink; Property; Property = Property->PropertyLinkNext) - { - const FName PropertyName = Property->GetFName(); - if (PropertyName == GET_MEMBER_NAME_CHECKED(UAssetViewerSettings, LocalProfiles)) - { - UArrayProperty* ArrayProperty = Cast(Property); - UpdateSinglePropertyInConfigFile(ArrayProperty->Inner, LocalFilename); - } - else if (PropertyName == GET_MEMBER_NAME_CHECKED(UAssetViewerSettings, SharedProfiles)) - { - UArrayProperty* ArrayProperty = Cast(Property); - UpdateSinglePropertyInConfigFile(ArrayProperty->Inner, SharedFilename); - } - } + SharedProfilesObject->SaveConfig(); + SharedProfilesObject->UpdateDefaultConfigFile(); } void UAssetViewerSettings::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) @@ -117,11 +104,14 @@ void UAssetViewerSettings::PostInitProperties() Super::PostInitProperties(); Profiles.Empty(); + + TArray& SharedProfiles = GetMutableDefault()->Profiles; for (FPreviewSceneProfile& Profile : SharedProfiles) { Profiles.Add(Profile); } + TArray& LocalProfiles = GetMutableDefault()->Profiles; for (FPreviewSceneProfile& Profile : LocalProfiles) { Profiles.Add(Profile); @@ -166,4 +156,4 @@ void UAssetViewerSettings::PostUndo(bool bSuccess) void UAssetViewerSettings::PostRedo(bool bSuccess) { PostUndo(bSuccess); -} +} \ No newline at end of file diff --git a/Engine/Source/Editor/AdvancedPreviewScene/Public/AssetViewerSettings.h b/Engine/Source/Editor/AdvancedPreviewScene/Public/AssetViewerSettings.h index 1918c7da54b3..c92981279c62 100644 --- a/Engine/Source/Editor/AdvancedPreviewScene/Public/AssetViewerSettings.h +++ b/Engine/Source/Editor/AdvancedPreviewScene/Public/AssetViewerSettings.h @@ -107,8 +107,7 @@ struct FPreviewSceneProfile if (EnvironmentCubeMap == nullptr) { // Load cube map from stored path - UObject* LoadedObject = nullptr; - LoadedObject = LoadObject(nullptr, *EnvironmentCubeMapPath); + UObject* LoadedObject = LoadObject(nullptr, *EnvironmentCubeMapPath); while (UObjectRedirector* Redirector = Cast(LoadedObject)) { LoadedObject = Redirector->DestinationObject; @@ -119,6 +118,27 @@ struct FPreviewSceneProfile } }; + +UCLASS(config = Editor) +class ULocalProfiles : public UObject +{ + GENERATED_BODY() +public: + /** Collection of local scene profiles */ + UPROPERTY(config) + TArray Profiles; +}; + +UCLASS(config = Editor, defaultconfig ) +class USharedProfiles : public UObject +{ + GENERATED_BODY() +public: + /** Collection of shared scene profiles */ + UPROPERTY(config) + TArray Profiles; +}; + /** * Default asset viewer settings. */ @@ -157,16 +177,8 @@ public: /** Collection of scene profiles */ UPROPERTY(EditAnywhere, transient, Category = Settings, meta=(ShowOnlyInnerProperties)) TArray Profiles; - - /** Collection of local scene profiles */ - UPROPERTY(config) - TArray SharedProfiles; - /** Collection of local scene profiles */ - UPROPERTY(config) - TArray LocalProfiles; - - /** Cached value to determine whether or not a profile was added or removed*/ + /** Cached value to determine whether or not a profile was added or removed */ int32 NumProfiles; protected: /** Broadcasts after an scene profile was added or deleted from the asset viewer singleton instance */ diff --git a/Engine/Source/Editor/AnimGraph/Classes/AnimBlueprintPostCompileValidation.h b/Engine/Source/Editor/AnimGraph/Classes/AnimBlueprintPostCompileValidation.h new file mode 100644 index 000000000000..653f4e90e60d --- /dev/null +++ b/Engine/Source/Editor/AnimGraph/Classes/AnimBlueprintPostCompileValidation.h @@ -0,0 +1,113 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "UObject/Object.h" +#include "Animation/AnimSequence.h" +#include "Animation/BlendSpace.h" +#include "Animation/AnimBlueprintGeneratedClass.h" +#include "CompilerResultsLog.h" + +#include "AnimBlueprintPostCompileValidation.generated.h" + +// Encapsulated Parameters, to upgrade these without changing function signature. +struct FAnimBPCompileValidationParams +{ + const class UAnimInstance* const DefaultAnimInstance; + const class UAnimBlueprintGeneratedClass* const NewAnimBlueprintClass; + FCompilerResultsLog& MessageLog; + const TMap& AllocatedNodePropertiesToNodes; + + FAnimBPCompileValidationParams + ( + const class UAnimInstance* const InDefaultAnimInstance, + const class UAnimBlueprintGeneratedClass* const InNewAnimBlueprintClass, + FCompilerResultsLog& InMessageLog, + const TMap& InAllocatedNodePropertiesToNodes + ) + : DefaultAnimInstance(InDefaultAnimInstance) + , NewAnimBlueprintClass(InNewAnimBlueprintClass) + , MessageLog(InMessageLog) + , AllocatedNodePropertiesToNodes(InAllocatedNodePropertiesToNodes) + {} +}; + +// This class is a base class for performing AnimBlueprint Post Compilation Validation. +UCLASS() +class ANIMGRAPH_API UAnimBlueprintPostCompileValidation : public UObject +{ + GENERATED_UCLASS_BODY() + +public: + virtual void DoPostCompileValidation(FAnimBPCompileValidationParams& InParams) const; + +protected: + static void PCV_PreloadObject(const UObject* const ReferencedObject); + + static void PCV_GatherAnimSequences(TArray& OutAnimSequences, const UAnimSequenceBase* const InAnimSequenceBase); + static void PCV_GatherAnimSequences(TArray& OutAnimSequences, const class UBlendSpaceBase* const InBlendSpace); + + struct FPCV_GatherParams + { + bool bFilterBySyncGroup; + int32 SyncGroupIndex; + bool bFilterByLoopingCondition; + bool bLoopingCondition; + + FPCV_GatherParams + ( + bool InbFilterBySyncGroup = false, + int32 InSyncGroupIndex = INDEX_NONE, + bool InbFilterByLoopingCondition = false, + bool InbLoopingCondition = false + ) + : bFilterBySyncGroup(InbFilterBySyncGroup) + , SyncGroupIndex(InSyncGroupIndex) + , bFilterByLoopingCondition(InbFilterByLoopingCondition) + , bLoopingCondition(InbLoopingCondition) + {} + }; + + static void PCV_GatherAnimSequencesFromGraph(TArray& OutAnimSequences, FAnimBPCompileValidationParams& PCV_Params, const FPCV_GatherParams& GatherParams); + static void PCV_GatherBlendSpacesFromGraph(TArray& OutBlendSpaces, FAnimBPCompileValidationParams& PCV_Params); + + struct FPCV_ReferencedAnimSequence + { + const UAnimSequence* AnimSequence; + const UObject* Referencer; + + FPCV_ReferencedAnimSequence + ( + const UAnimSequence* InAnimSequence, + const UObject* InReferencer + ) + : AnimSequence(InAnimSequence) + , Referencer(InReferencer) + {} + }; + + struct FPCV_PropertyAndValue + { + const UProperty* Property; + const void* Value; + + FPCV_PropertyAndValue + ( + const UProperty* InProperty, + const void* InValue + ) + : Property(InProperty) + , Value(InValue) + {} + }; + + static void PCV_GatherAllReferencedAnimSequences(TArray& OutRefAnimSequences, FAnimBPCompileValidationParams& PCV_Params); + static void PCV_GatherAnimSequencesFromStruct(TArray& OutRefAnimSequences, FAnimBPCompileValidationParams& PCV_Params, const UStruct* InStruct, const void* InData, TArray InPropertyCallChain); + static void PCV_GatherAnimSequencesFromProperty(TArray& OutRefAnimSequences, FAnimBPCompileValidationParams& PCV_Params, const UProperty* InProperty, const void* InData, TArray InPropertyCallChain); + +private: + virtual bool NeedsLoadForClient() const override { return false; } + virtual bool NeedsLoadForServer() const override { return false; } +}; diff --git a/Engine/Source/Editor/AnimGraph/Classes/AnimGraphNode_AssetPlayerBase.h b/Engine/Source/Editor/AnimGraph/Classes/AnimGraphNode_AssetPlayerBase.h index cbb3d2fa53cc..98b82d63c57b 100644 --- a/Engine/Source/Editor/AnimGraph/Classes/AnimGraphNode_AssetPlayerBase.h +++ b/Engine/Source/Editor/AnimGraph/Classes/AnimGraphNode_AssetPlayerBase.h @@ -30,15 +30,4 @@ public: ANIMGRAPH_API virtual void PinDefaultValueChanged(UEdGraphPin* Pin) override; virtual void SetAnimationAsset(UAnimationAsset* Asset) { check(false); /*Base function called*/ } - - /** Store off a string asset reference for later restoration */ - void SetAssetReferenceForPinRestoration(UObject* InAsset); - - /** Find an asset reference when restoring pins */ - UObject* GetAssetReferenceForPinRestoration(); - -private: - /** Non-concrete reference to asset that was being used, now potentially coming from a pin */ - UPROPERTY() - FStringAssetReference AssetReferenceForPinRestoration; }; diff --git a/Engine/Source/Editor/AnimGraph/Classes/AnimGraphNode_Base.h b/Engine/Source/Editor/AnimGraph/Classes/AnimGraphNode_Base.h index c283879059f5..6a07dcd0ab31 100644 --- a/Engine/Source/Editor/AnimGraph/Classes/AnimGraphNode_Base.h +++ b/Engine/Source/Editor/AnimGraph/Classes/AnimGraphNode_Base.h @@ -124,7 +124,7 @@ class ANIMGRAPH_API UAnimGraphNode_Base : public UK2Node { GENERATED_UCLASS_BODY() - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=PinOptions, EditFixedSize) + UPROPERTY(EditAnywhere, Category=PinOptions, EditFixedSize) TArray ShowPinForProperties; UPROPERTY(Transient) diff --git a/Engine/Source/Editor/AnimGraph/Classes/AnimGraphNode_BlendBoneByChannel.h b/Engine/Source/Editor/AnimGraph/Classes/AnimGraphNode_BlendBoneByChannel.h new file mode 100644 index 000000000000..0d5ecbc6e369 --- /dev/null +++ b/Engine/Source/Editor/AnimGraph/Classes/AnimGraphNode_BlendBoneByChannel.h @@ -0,0 +1,28 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "AnimGraphNode_Base.h" +#include "AnimNodes/AnimNode_BlendBoneByChannel.h" +#include "AnimGraphNode_BlendBoneByChannel.generated.h" + +UCLASS(MinimalAPI) +class UAnimGraphNode_BlendBoneByChannel : public UAnimGraphNode_Base +{ + GENERATED_UCLASS_BODY() + + UPROPERTY(EditAnywhere, Category = Settings) + FAnimNode_BlendBoneByChannel BlendNode; + + //~ Begin UEdGraphNode Interface. + virtual FLinearColor GetNodeTitleColor() const override; + virtual FText GetTooltipText() const override; + virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override; + //~ End UEdGraphNode Interface. + + //~ Begin UAnimGraphNode_Base Interface + virtual FString GetNodeCategory() const override; + //~ End UAnimGraphNode_Base Interface +}; diff --git a/Engine/Source/Editor/AnimGraph/Classes/AnimPreviewAttacheInstance.h b/Engine/Source/Editor/AnimGraph/Classes/AnimPreviewAttacheInstance.h new file mode 100644 index 000000000000..28a86871febd --- /dev/null +++ b/Engine/Source/Editor/AnimGraph/Classes/AnimPreviewAttacheInstance.h @@ -0,0 +1,53 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "AnimCustomInstance.h" +#include "AnimInstanceProxy.h" +#include "AnimNodes/AnimNode_CopyPoseFromMesh.h" +#include "AnimPreviewAttacheInstance.generated.h" + +/** Proxy override for this UAnimInstance-derived class */ +USTRUCT() +struct FAnimPreviewAttacheInstanceProxy : public FAnimInstanceProxy +{ + GENERATED_BODY() + +public: + FAnimPreviewAttacheInstanceProxy() + { + } + + FAnimPreviewAttacheInstanceProxy(UAnimInstance* InAnimInstance) + : FAnimInstanceProxy(InAnimInstance) + { + } + + virtual void Initialize(UAnimInstance* InAnimInstance) override; + virtual void Update(float DeltaSeconds) override; + virtual bool Evaluate(FPoseContext& Output) override; + +private: + /** Pose blend node for evaluating pose assets (for previewing curve sources) */ + FAnimNode_CopyPoseFromMesh CopyPoseFromMesh; +}; + +/** + * This Instance only contains one AnimationAsset, and produce poses + * Used by Preview in AnimGraph, Playing single animation in Kismet2 and etc + */ + +UCLASS(transient, NotBlueprintable, noteditinlinenew) +class ANIMGRAPH_API UAnimPreviewAttacheInstance : public UAnimCustomInstance +{ + GENERATED_UCLASS_BODY() + + //~ Begin UAnimInstance Interface + virtual FAnimInstanceProxy* CreateAnimInstanceProxy() override; + //~ End UAnimInstance Interface +}; + + + diff --git a/Engine/Source/Editor/AnimGraph/Classes/AnimPreviewInstance.h b/Engine/Source/Editor/AnimGraph/Classes/AnimPreviewInstance.h index 1e1be9227202..f63c7f250fb7 100644 --- a/Engine/Source/Editor/AnimGraph/Classes/AnimPreviewInstance.h +++ b/Engine/Source/Editor/AnimGraph/Classes/AnimPreviewInstance.h @@ -10,6 +10,7 @@ #include "Animation/AnimSingleNodeInstanceProxy.h" #include "AnimNodes/AnimNode_CurveSource.h" #include "AnimNodes/AnimNode_PoseBlendNode.h" +#include "AnimNodes/AnimNode_CopyPoseFromMesh.h" #include "AnimPreviewInstance.generated.h" /** Enum to know how montage is being played */ @@ -115,6 +116,12 @@ public: return CurveBoneControllers; } + /** Sets an external debug skeletal mesh component to use to debug */ + void SetDebugSkeletalMeshComponent(USkeletalMeshComponent* InSkeletalMeshComponent); + + /** Gets the external debug skeletal mesh component we are debugging */ + USkeletalMeshComponent* GetDebugSkeletalMeshComponent() const; + private: void UpdateCurveController(); @@ -137,6 +144,9 @@ private: /** Pose blend node for evaluating pose assets (for previewing curve sources) */ FAnimNode_PoseBlendNode PoseBlendNode; + /** Allows us to copy a pose from the mesh being debugged */ + FAnimNode_CopyPoseFromMesh CopyPoseNode; + /** * Delegate to call after Key is set */ @@ -284,6 +294,12 @@ class ANIMGRAPH_API UAnimPreviewInstance : public UAnimSingleNodeInstance * This is used by when editing, when controller has to be disabled */ void EnableControllers(bool bEnable); + + /** Sets an external debug skeletal mesh component to use to debug */ + void SetDebugSkeletalMeshComponent(USkeletalMeshComponent* InSkeletalMeshComponent); + + /** Gets the external debug skeletal mesh component we are debugging */ + USkeletalMeshComponent* GetDebugSkeletalMeshComponent() const; }; diff --git a/Engine/Source/Editor/AnimGraph/Private/AnimBlueprintNodeOptionalPinManager.cpp b/Engine/Source/Editor/AnimGraph/Private/AnimBlueprintNodeOptionalPinManager.cpp index 6ae33c6d966a..195bbdaa38b6 100644 --- a/Engine/Source/Editor/AnimGraph/Private/AnimBlueprintNodeOptionalPinManager.cpp +++ b/Engine/Source/Editor/AnimGraph/Private/AnimBlueprintNodeOptionalPinManager.cpp @@ -45,90 +45,84 @@ void FAnimBlueprintNodeOptionalPinManager::GetRecordDefaults(UProperty* TestProp void FAnimBlueprintNodeOptionalPinManager::CustomizePinData(UEdGraphPin* Pin, FName SourcePropertyName, int32 ArrayIndex, UProperty* Property) const { - if (BaseNode != NULL) + if (BaseNode != nullptr) { BaseNode->CustomizePinData(Pin, SourcePropertyName, ArrayIndex); } } -void FAnimBlueprintNodeOptionalPinManager::PostInitNewPin(UEdGraphPin* Pin, FOptionalPinFromProperty& Record, int32 ArrayIndex, UProperty* Property, uint8* PropertyAddress) const +void FAnimBlueprintNodeOptionalPinManager::PostInitNewPin(UEdGraphPin* Pin, FOptionalPinFromProperty& Record, int32 ArrayIndex, UProperty* Property, uint8* PropertyAddress, uint8* DefaultPropertyAddress) const { - check(PropertyAddress != NULL); + check(PropertyAddress != nullptr); check(Record.bShowPin); - + + const UAnimationGraphSchema* Schema = GetDefault(); + // In all cases set autogenerated default value from node defaults + if (DefaultPropertyAddress) + { + FString LiteralValue; + FBlueprintEditorUtils::PropertyValueToString_Direct(Property, DefaultPropertyAddress, LiteralValue); - if (OldPins == NULL) + Schema->SetPinAutogeneratedDefaultValue(Pin, LiteralValue); + } + else + { + Schema->SetPinAutogeneratedDefaultValueBasedOnType(Pin); + } + + if (OldPins == nullptr) { // Initial construction of a visible pin; copy values from the struct - FBlueprintEditorUtils::ExportPropertyToKismetDefaultValue(Pin, Property, PropertyAddress, BaseNode); + FString LiteralValue; + FBlueprintEditorUtils::PropertyValueToString_Direct(Property, PropertyAddress, LiteralValue); + + Schema->SetPinDefaultValueAtConstruction(Pin, LiteralValue); } else if (Record.bCanToggleVisibility) { if (UEdGraphPin* OldPin = OldPinMap.FindRef(Pin->PinName)) { - // Was already visible + // Was already visible, values will get copied over in pin reconstruction code } else { - // Showing a pin that was previously hidden, during a reconstruction - - UObjectProperty* ObjectProperty = Cast(Property); - UAnimGraphNode_AssetPlayerBase* AssetPlayerNode = Cast(BaseNode); - const bool bIsAnimationAsset = AssetPlayerNode != nullptr && ObjectProperty != nullptr && ObjectProperty->PropertyClass->IsChildOf(); - - // Store the old reference to an animation asset in the node's asset reference - if (bIsAnimationAsset) - { - AssetPlayerNode->SetAssetReferenceForPinRestoration(ObjectProperty->GetObjectPropertyValue(PropertyAddress)); - } - // Convert the struct property into DefaultValue/DefaultValueObject - FBlueprintEditorUtils::ExportPropertyToKismetDefaultValue(Pin, Property, PropertyAddress, BaseNode); + FString LiteralValue; + FBlueprintEditorUtils::PropertyValueToString_Direct(Property, PropertyAddress, LiteralValue); - // clear the asset reference on the node - if (bIsAnimationAsset) - { - ObjectProperty->SetObjectPropertyValue(PropertyAddress, nullptr); - } + Schema->SetPinDefaultValueAtConstruction(Pin, LiteralValue); + } + + // Clear the asset reference on the node if the pin exists + // In theory this is only needed for pins that are newly created but there are a lot of existing nodes that have dead asset references + UObjectProperty* ObjectProperty = Cast(Property); + if (ObjectProperty) + { + ObjectProperty->SetObjectPropertyValue(PropertyAddress, nullptr); } } } -void FAnimBlueprintNodeOptionalPinManager::PostRemovedOldPin(FOptionalPinFromProperty& Record, int32 ArrayIndex, UProperty* Property, uint8* PropertyAddress) const +void FAnimBlueprintNodeOptionalPinManager::PostRemovedOldPin(FOptionalPinFromProperty& Record, int32 ArrayIndex, UProperty* Property, uint8* PropertyAddress, uint8* DefaultPropertyAddress) const { - check(PropertyAddress != NULL); + check(PropertyAddress != nullptr); check(!Record.bShowPin); - if (Record.bCanToggleVisibility && (OldPins != NULL)) + if (Record.bCanToggleVisibility && (OldPins != nullptr)) { const FString OldPinName = (ArrayIndex != INDEX_NONE) ? FString::Printf(TEXT("%s_%d"), *(Record.PropertyName.ToString()), ArrayIndex) : Record.PropertyName.ToString(); + // Pin was visible but it's now hidden if (UEdGraphPin* OldPin = OldPinMap.FindRef(OldPinName)) { - // Pin was visible but it's now hidden - UObjectProperty* ObjectProperty = Cast(Property); - UAnimGraphNode_AssetPlayerBase* AssetPlayerNode = Cast(BaseNode); - if (AssetPlayerNode && ObjectProperty && ObjectProperty->PropertyClass->IsChildOf()) - { - // If this is an anim asset pin, dont store a hard reference to the asset in the node, as this ends up referencing things we might not want to load any more - UObject* AssetReference = AssetPlayerNode->GetAssetReferenceForPinRestoration(); - if (AssetReference) - { - ObjectProperty->SetObjectPropertyValue(PropertyAddress, AssetReference); - } - - } - else - { - // Convert DefaultValue/DefaultValueObject and push back into the struct - FBlueprintEditorUtils::ImportKismetDefaultValueToProperty(OldPin, Property, PropertyAddress, BaseNode); - } + // Convert DefaultValue/DefaultValueObject and push back into the struct + FBlueprintEditorUtils::PropertyValueFromString_Direct(Property, OldPin->GetDefaultAsString(), PropertyAddress); } } } -void FAnimBlueprintNodeOptionalPinManager::AllocateDefaultPins(UStruct* SourceStruct, uint8* StructBasePtr) +void FAnimBlueprintNodeOptionalPinManager::AllocateDefaultPins(UStruct* SourceStruct, uint8* StructBasePtr, uint8* DefaultsPtr) { RebuildPropertyList(BaseNode->ShowPinForProperties, SourceStruct); - CreateVisiblePins(BaseNode->ShowPinForProperties, SourceStruct, EGPD_Input, BaseNode, StructBasePtr); + CreateVisiblePins(BaseNode->ShowPinForProperties, SourceStruct, EGPD_Input, BaseNode, StructBasePtr, DefaultsPtr); } diff --git a/Engine/Source/Editor/AnimGraph/Private/AnimBlueprintNodeOptionalPinManager.h b/Engine/Source/Editor/AnimGraph/Private/AnimBlueprintNodeOptionalPinManager.h index 7a91834351a2..aefcb2fe2f56 100644 --- a/Engine/Source/Editor/AnimGraph/Private/AnimBlueprintNodeOptionalPinManager.h +++ b/Engine/Source/Editor/AnimGraph/Private/AnimBlueprintNodeOptionalPinManager.h @@ -21,8 +21,8 @@ public: /** FOptionalPinManager interface */ virtual void GetRecordDefaults(UProperty* TestProperty, FOptionalPinFromProperty& Record) const override; virtual void CustomizePinData(UEdGraphPin* Pin, FName SourcePropertyName, int32 ArrayIndex, UProperty* Property) const override; - virtual void PostInitNewPin(UEdGraphPin* Pin, FOptionalPinFromProperty& Record, int32 ArrayIndex, UProperty* Property, uint8* PropertyAddress) const override; - virtual void PostRemovedOldPin(FOptionalPinFromProperty& Record, int32 ArrayIndex, UProperty* Property, uint8* PropertyAddress) const override; + virtual void PostInitNewPin(UEdGraphPin* Pin, FOptionalPinFromProperty& Record, int32 ArrayIndex, UProperty* Property, uint8* PropertyAddress, uint8* DefaultPropertyAddress) const override; + virtual void PostRemovedOldPin(FOptionalPinFromProperty& Record, int32 ArrayIndex, UProperty* Property, uint8* PropertyAddress, uint8* DefaultPropertyAddress) const override; - void AllocateDefaultPins(UStruct* SourceStruct, uint8* StructBasePtr); + void AllocateDefaultPins(UStruct* SourceStruct, uint8* StructBasePtr, uint8* DefaultsPtr); }; diff --git a/Engine/Source/Editor/AnimGraph/Private/AnimBlueprintPostCompileValidation.cpp b/Engine/Source/Editor/AnimGraph/Private/AnimBlueprintPostCompileValidation.cpp new file mode 100644 index 000000000000..8c0389d83991 --- /dev/null +++ b/Engine/Source/Editor/AnimGraph/Private/AnimBlueprintPostCompileValidation.cpp @@ -0,0 +1,183 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "AnimBlueprintPostCompileValidation.h" +#include "AnimNodes/AnimNode_BlendSpacePlayer.h" +#include "Animation/BlendSpaceBase.h" +#include "Animation/AnimNode_SequencePlayer.h" +#include "Animation/AnimInstance.h" +#include "Editor/AnimGraph/Classes/AnimGraphNode_Base.h" + +UAnimBlueprintPostCompileValidation::UAnimBlueprintPostCompileValidation(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ +} + +void UAnimBlueprintPostCompileValidation::DoPostCompileValidation(FAnimBPCompileValidationParams& InParams) const +{ + +} + +// Ensures the specified object is preloaded. ReferencedObject can be NULL. +void UAnimBlueprintPostCompileValidation::PCV_PreloadObject(const UObject* const ReferencedObject) +{ + if ((ReferencedObject != nullptr) && ReferencedObject->HasAnyFlags(RF_NeedLoad)) + { + ReferencedObject->GetLinker()->Preload(const_cast(ReferencedObject)); + } +} + +void UAnimBlueprintPostCompileValidation::PCV_GatherAllReferencedAnimSequences(TArray& OutRefAnimSequences, FAnimBPCompileValidationParams& PCV_Params) +{ + PCV_PreloadObject(PCV_Params.DefaultAnimInstance); + TArray PropertyCallChain; + PCV_GatherAnimSequencesFromStruct(OutRefAnimSequences, PCV_Params, PCV_Params.NewAnimBlueprintClass, PCV_Params.DefaultAnimInstance, PropertyCallChain); +} + +void UAnimBlueprintPostCompileValidation::PCV_GatherAnimSequencesFromStruct(TArray& OutRefAnimSequences, FAnimBPCompileValidationParams& PCV_Params, const UStruct* InStruct, const void* InData, TArray InPropertyCallChain) +{ + for (TFieldIterator PropIt(InStruct, EFieldIteratorFlags::IncludeSuper); PropIt; ++PropIt) + { + if (const UProperty* Property = *PropIt) + { + const void* PropertyData = Property->ContainerPtrToValuePtr(InData); + PCV_GatherAnimSequencesFromProperty(OutRefAnimSequences, PCV_Params, Property, PropertyData, InPropertyCallChain); + } + } +} + +void UAnimBlueprintPostCompileValidation::PCV_GatherAnimSequencesFromProperty(TArray& OutRefAnimSequences, FAnimBPCompileValidationParams& PCV_Params, const UProperty* InProperty, const void* InData, TArray InPropertyCallChain) +{ + InPropertyCallChain.Add(FPCV_PropertyAndValue(InProperty, InData)); + + // Always recurse into arrays and structs + if (const UArrayProperty* ArrayProperty = Cast(InProperty)) + { + FScriptArrayHelper ArrayHelper(ArrayProperty, InData); + const int32 NumElements = ArrayHelper.Num(); + for (int32 Index = 0; Index < NumElements; Index++) + { + const void* const ArrayData = ArrayHelper.GetRawPtr(Index); + PCV_GatherAnimSequencesFromProperty(OutRefAnimSequences, PCV_Params, ArrayProperty->Inner, ArrayData, InPropertyCallChain); + } + } + else if (const UStructProperty* StructProperty = Cast(InProperty)) + { + PCV_GatherAnimSequencesFromStruct(OutRefAnimSequences, PCV_Params, StructProperty->Struct, InData, InPropertyCallChain); + } + + // Leaf Properties + else if (const UObjectProperty* ObjectProperty = Cast(InProperty)) + { + const UObject* const ObjectPropertyValue = ObjectProperty->GetObjectPropertyValue(InData); + if (const UAnimSequence* const AnimSequence = Cast(ObjectPropertyValue)) + { + // make sure we don't have duplicates + for (const FPCV_ReferencedAnimSequence& AnimSequenceRef : OutRefAnimSequences) + { + if (AnimSequenceRef.AnimSequence == AnimSequence) + { + return; + } + } + + // Find Parent Referencer. + const UObject* Referencer = PCV_Params.DefaultAnimInstance; + for (int32 Index = InPropertyCallChain.Num() - 2; Index >= 0; Index--) + { + const FPCV_PropertyAndValue& Parent = InPropertyCallChain[Index]; + if (const UStructProperty* ParentStructProperty = Cast(Parent.Property)) + { + if (const UAnimGraphNode_Base* AnimGraphVisualNode = PCV_Params.AllocatedNodePropertiesToNodes.FindRef(ParentStructProperty)) + { + Referencer = AnimGraphVisualNode; + break; + } + } + else if (const UObjectProperty* ParentObjectProperty = Cast(Parent.Property)) + { + if (ParentObjectProperty->PropertyClass && ParentObjectProperty->PropertyClass->IsChildOf(UBlendSpaceBase::StaticClass())) + { + Referencer = ParentObjectProperty->GetObjectPropertyValue(Parent.Value); + break; + } + } + } + + OutRefAnimSequences.Add(FPCV_ReferencedAnimSequence(AnimSequence, Referencer)); + } + else if (const UBlendSpaceBase* const BlendSpace = Cast(ObjectPropertyValue)) + { + PCV_PreloadObject(BlendSpace); + + // recurse into BlendSpaces to grab referenced animations. + PCV_GatherAnimSequencesFromStruct(OutRefAnimSequences, PCV_Params, BlendSpace->GetClass(), BlendSpace, InPropertyCallChain); + } + } +} + +void UAnimBlueprintPostCompileValidation::PCV_GatherAnimSequences(TArray& OutAnimSequences, const UAnimSequenceBase* const InAnimSequenceBase) +{ + if (const UAnimSequence* const AnimSeq = Cast(InAnimSequenceBase)) + { + OutAnimSequences.AddUnique(AnimSeq); + } +} + +void UAnimBlueprintPostCompileValidation::PCV_GatherAnimSequences(TArray& OutAnimSequences, const class UBlendSpaceBase* const InBlendSpace) +{ + // Make sure BlendSpace is loaded, so we can access referenced AnimSequences. + PCV_PreloadObject(InBlendSpace); + + if (InBlendSpace) + { + for (const FBlendSample& BlendSample : InBlendSpace->GetBlendSamples()) + { + PCV_GatherAnimSequences(OutAnimSequences, BlendSample.Animation); + } + } +} + +void UAnimBlueprintPostCompileValidation::PCV_GatherAnimSequencesFromGraph(TArray& OutAnimSequences, FAnimBPCompileValidationParams& PCV_Params, const FPCV_GatherParams& GatherParams) +{ + for (UStructProperty* Property : TFieldRange(PCV_Params.NewAnimBlueprintClass, EFieldIteratorFlags::IncludeSuper)) + { + if (Property->Struct->IsChildOf(FAnimNode_BlendSpacePlayer::StaticStruct())) + { + if (const FAnimNode_BlendSpacePlayer* const BlendSpacePlayer = Property->ContainerPtrToValuePtr(PCV_Params.DefaultAnimInstance)) + { + const bool bPassSyncGroupFilter = !GatherParams.bFilterBySyncGroup || (BlendSpacePlayer->GroupIndex == GatherParams.SyncGroupIndex); + const bool bPassLoopingFilter = !GatherParams.bFilterByLoopingCondition || (BlendSpacePlayer->bLoop == GatherParams.bLoopingCondition); + if (bPassSyncGroupFilter && bPassLoopingFilter) + { + PCV_GatherAnimSequences(OutAnimSequences, BlendSpacePlayer->BlendSpace); + } + } + } + else if (Property->Struct->IsChildOf(FAnimNode_SequencePlayer::StaticStruct())) + { + if (const FAnimNode_SequencePlayer* const SequencePlayer = Property->ContainerPtrToValuePtr(PCV_Params.DefaultAnimInstance)) + { + const bool bPassSyncGroupFilter = !GatherParams.bFilterBySyncGroup || (SequencePlayer->GroupIndex == GatherParams.SyncGroupIndex); + const bool bPassLoopingFilter = !GatherParams.bFilterByLoopingCondition || (SequencePlayer->bLoopAnimation == GatherParams.bLoopingCondition); + if (bPassSyncGroupFilter && bPassLoopingFilter) + { + PCV_GatherAnimSequences(OutAnimSequences, SequencePlayer->Sequence); + } + } + } + } +} + +void UAnimBlueprintPostCompileValidation::PCV_GatherBlendSpacesFromGraph(TArray& OutBlendSpaces, FAnimBPCompileValidationParams& PCV_Params) +{ + for (UStructProperty* Property : TFieldRange(PCV_Params.NewAnimBlueprintClass, EFieldIteratorFlags::IncludeSuper)) + { + if (Property->Struct->IsChildOf(FAnimNode_BlendSpacePlayer::StaticStruct())) + { + if (const FAnimNode_BlendSpacePlayer* const BlendSpacePlayer = Property->ContainerPtrToValuePtr(PCV_Params.DefaultAnimInstance)) + { + OutBlendSpaces.AddUnique(BlendSpacePlayer->BlendSpace); + } + } + } +} diff --git a/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_AnimDynamics.cpp b/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_AnimDynamics.cpp index 94ed99083550..57f486bc8391 100644 --- a/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_AnimDynamics.cpp +++ b/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_AnimDynamics.cpp @@ -131,7 +131,7 @@ void UAnimGraphNode_AnimDynamics::Draw(FPrimitiveDrawInterface* PDI, USkeletalMe SphereTransform *= PreviewSkelMeshComp->GetComponentSpaceTransforms()[DrivingBoneIdx]; } - DrawSphere(PDI, SphereTransform.GetLocation(), FVector(SphericalLimit.LimitRadius), 24, 6, GEngine->ConstraintLimitMaterialY->GetRenderProxy(false), SDPG_World); + DrawSphere(PDI, SphereTransform.GetLocation(), FRotator::ZeroRotator, FVector(SphericalLimit.LimitRadius), 24, 6, GEngine->ConstraintLimitMaterialY->GetRenderProxy(false), SDPG_World); DrawWireSphere(PDI, SphereTransform, FLinearColor::Black, SphericalLimit.LimitRadius, 24, SDPG_World); } } diff --git a/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_AssetPlayerBase.cpp b/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_AssetPlayerBase.cpp index 9375b5001007..3fed94098674 100644 --- a/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_AssetPlayerBase.cpp +++ b/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_AssetPlayerBase.cpp @@ -23,16 +23,6 @@ void UAnimGraphNode_AssetPlayerBase::PinConnectionListChanged(UEdGraphPin* Pin) if (Pin->PinType.PinCategory == UEdGraphSchema_K2::PC_Object) { - // if pin has no connections, we may need to restore the default - if (Pin->LinkedTo.Num() == 0) - { - UObject* Asset = GetAssetReferenceForPinRestoration(); - if (Asset != nullptr) - { - Pin->DefaultObject = Asset; - } - } - // recache visualization now an asset pin's connection is changed if (const UEdGraphSchema* Schema = GetSchema()) { @@ -55,18 +45,6 @@ void UAnimGraphNode_AssetPlayerBase::PinDefaultValueChanged(UEdGraphPin* Pin) } } -void UAnimGraphNode_AssetPlayerBase::SetAssetReferenceForPinRestoration(UObject* InAsset) -{ - AssetReferenceForPinRestoration = InAsset; -} - -UObject* UAnimGraphNode_AssetPlayerBase::GetAssetReferenceForPinRestoration() -{ - return AssetReferenceForPinRestoration.TryLoad(); -} - - - UClass* GetNodeClassForAsset(const UClass* AssetClass) { UClass* NodeClass = nullptr; diff --git a/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_Base.cpp b/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_Base.cpp index 8b0e2fd9cfee..c099551737ae 100644 --- a/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_Base.cpp +++ b/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_Base.cpp @@ -40,7 +40,7 @@ void UAnimGraphNode_Base::CreateOutputPins() if (!IsSinkNode()) { const UAnimationGraphSchema* Schema = GetDefault(); - CreatePin(EGPD_Output, Schema->PC_Struct, TEXT(""), FPoseLink::StaticStruct(), /*bIsArray=*/ false, /*bIsReference=*/ false, TEXT("Pose")); + CreatePin(EGPD_Output, Schema->PC_Struct, FString(), FPoseLink::StaticStruct(), TEXT("Pose")); } } @@ -54,8 +54,9 @@ void UAnimGraphNode_Base::InternalPinCreation(TArray* OldPins) { // Display any currently visible optional pins { + UObject* NodeDefaults = GetArchetype(); FAnimBlueprintNodeOptionalPinManager OptionalPinManager(this, OldPins); - OptionalPinManager.AllocateDefaultPins(NodeStruct->Struct, NodeStruct->ContainerPtrToValuePtr(this)); + OptionalPinManager.AllocateDefaultPins(NodeStruct->Struct, NodeStruct->ContainerPtrToValuePtr(this), NodeDefaults ? NodeStruct->ContainerPtrToValuePtr(NodeDefaults) : nullptr); } // Create the output pin, if needed @@ -229,7 +230,7 @@ void UAnimGraphNode_Base::CreatePinsForPoseLink(UProperty* PoseProperty, int32 A // pose input const FString NewPinName = (ArrayIndex == INDEX_NONE) ? PoseProperty->GetName() : FString::Printf(TEXT("%s_%d"), *(PoseProperty->GetName()), ArrayIndex); - CreatePin(EGPD_Input, Schema->PC_Struct, TEXT(""), A2PoseStruct, /*bIsArray=*/ false, /*bIsReference=*/ false, NewPinName); + CreatePin(EGPD_Input, Schema->PC_Struct, FString(), A2PoseStruct, NewPinName); } void UAnimGraphNode_Base::PostProcessPinName(const UEdGraphPin* Pin, FString& DisplayName) const @@ -238,7 +239,7 @@ void UAnimGraphNode_Base::PostProcessPinName(const UEdGraphPin* Pin, FString& Di { if (Pin->PinName == TEXT("Pose")) { - DisplayName = TEXT(""); + DisplayName.Reset(); } } } diff --git a/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_BlendBoneByChannel.cpp b/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_BlendBoneByChannel.cpp new file mode 100644 index 000000000000..c3bab79f002a --- /dev/null +++ b/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_BlendBoneByChannel.cpp @@ -0,0 +1,36 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "AnimGraphNode_BlendBoneByChannel.h" + +///////////////////////////////////////////////////// +// UAnimGraphNode_BlendBoneByChannel + +#define LOCTEXT_NAMESPACE "AnimGraphNode_BlendBoneByChannel" + +UAnimGraphNode_BlendBoneByChannel::UAnimGraphNode_BlendBoneByChannel(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ +} + +FString UAnimGraphNode_BlendBoneByChannel::GetNodeCategory() const +{ + return TEXT("Blends"); +} + +FLinearColor UAnimGraphNode_BlendBoneByChannel::GetNodeTitleColor() const +{ + return FLinearColor(0.75f, 0.75f, 0.75f); +} + +FText UAnimGraphNode_BlendBoneByChannel::GetTooltipText() const +{ + return LOCTEXT("BlendBoneByChannelTooltip", "Blend bones by channel from two poses together."); +} + +FText UAnimGraphNode_BlendBoneByChannel::GetNodeTitle(ENodeTitleType::Type TitleType) const +{ + return LOCTEXT("BlendBoneByChannel", "Blend Bone By Channel"); +} + +#undef LOCTEXT_NAMESPACE + diff --git a/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_BoneDrivenController.cpp b/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_BoneDrivenController.cpp index 838517161d82..62af1a7ac7b4 100644 --- a/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_BoneDrivenController.cpp +++ b/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_BoneDrivenController.cpp @@ -168,8 +168,8 @@ void UAnimGraphNode_BoneDrivenController::Draw(FPrimitiveDrawInterface* PDI, USk if ((SourceIdx != INDEX_NONE) && (TargetIdx != INDEX_NONE)) { - const FTransform SourceTM = SkelMeshComp->GetComponentSpaceTransforms()[SourceIdx] * SkelMeshComp->ComponentToWorld; - const FTransform TargetTM = SkelMeshComp->GetComponentSpaceTransforms()[TargetIdx] * SkelMeshComp->ComponentToWorld; + const FTransform SourceTM = SkelMeshComp->GetComponentSpaceTransforms()[SourceIdx] * SkelMeshComp->GetComponentTransform(); + const FTransform TargetTM = SkelMeshComp->GetComponentSpaceTransforms()[TargetIdx] * SkelMeshComp->GetComponentTransform(); PDI->DrawLine(TargetTM.GetLocation(), SourceTM.GetLocation(), FLinearColor(0.0f, 0.0f, 1.0f), SDPG_Foreground, 0.5f); @@ -193,19 +193,19 @@ void UAnimGraphNode_BoneDrivenController::ValidateAnimNodeDuringCompilation(USke { if (ForSkeleton->GetReferenceSkeleton().FindBoneIndex(Node.SourceBone.BoneName) == INDEX_NONE) { - MessageLog.Warning(*LOCTEXT("NoSourceBone", "@@ - You must pick a source bone as the Driver joint").ToString(), this); + MessageLog.Warning(*LOCTEXT("DriverJoint_NoSourceBone", "@@ - You must pick a source bone as the Driver joint").ToString(), this); } if (Node.SourceComponent == EComponentType::None) { - MessageLog.Warning(*LOCTEXT("NoSourceComponent", "@@ - You must pick a source component on the Driver joint").ToString(), this); + MessageLog.Warning(*LOCTEXT("DriverJoint_NoSourceComponent", "@@ - You must pick a source component on the Driver joint").ToString(), this); } if (Node.DestinationMode == EDrivenDestinationMode::Bone) { if (ForSkeleton->GetReferenceSkeleton().FindBoneIndex(Node.TargetBone.BoneName) == INDEX_NONE) { - MessageLog.Warning(*LOCTEXT("NoTargetBone", "@@ - You must pick a target bone as the Driven joint").ToString(), this); + MessageLog.Warning(*LOCTEXT("DriverJoint_NoTargetBone", "@@ - You must pick a target bone as the Driven joint").ToString(), this); } const bool bAffectsTranslation = Node.bAffectTargetTranslationX || Node.bAffectTargetTranslationY || Node.bAffectTargetTranslationZ; @@ -214,7 +214,7 @@ void UAnimGraphNode_BoneDrivenController::ValidateAnimNodeDuringCompilation(USke if (!bAffectsTranslation && !bAffectsRotation && !bAffectsScale) { - MessageLog.Warning(*LOCTEXT("NoTargetComponent", "@@ - You must pick one or more target components on the Driven joint").ToString(), this); + MessageLog.Warning(*LOCTEXT("DriverJoint_NoTargetComponent", "@@ - You must pick one or more target components on the Driven joint").ToString(), this); } } diff --git a/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_LocalToComponentSpace.cpp b/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_LocalToComponentSpace.cpp index 5f7401a3fdc2..d825fe5e0bdc 100644 --- a/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_LocalToComponentSpace.cpp +++ b/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_LocalToComponentSpace.cpp @@ -36,12 +36,12 @@ FString UAnimGraphNode_LocalToComponentSpace::GetNodeCategory() const void UAnimGraphNode_LocalToComponentSpace::CreateOutputPins() { const UAnimationGraphSchema* Schema = GetDefault(); - CreatePin(EGPD_Output, Schema->PC_Struct, TEXT(""), FComponentSpacePoseLink::StaticStruct(), /*bIsArray=*/ false, /*bIsReference=*/ false, TEXT("ComponentPose")); + CreatePin(EGPD_Output, Schema->PC_Struct, FString(), FComponentSpacePoseLink::StaticStruct(), TEXT("ComponentPose")); } void UAnimGraphNode_LocalToComponentSpace::PostProcessPinName(const UEdGraphPin* Pin, FString& DisplayName) const { - DisplayName = TEXT(""); + DisplayName.Reset(); } #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_MeshRefPose.cpp b/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_MeshRefPose.cpp index 4652e1c74562..7482c6c71c66 100644 --- a/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_MeshRefPose.cpp +++ b/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_MeshRefPose.cpp @@ -36,7 +36,7 @@ FText UAnimGraphNode_MeshRefPose::GetNodeTitle(ENodeTitleType::Type TitleType) c void UAnimGraphNode_MeshRefPose::CreateOutputPins() { const UAnimationGraphSchema* Schema = GetDefault(); - CreatePin(EGPD_Output, Schema->PC_Struct, TEXT(""), FComponentSpacePoseLink::StaticStruct(), /*bIsArray=*/ false, /*bIsReference=*/ false, TEXT("ComponentPose")); + CreatePin(EGPD_Output, Schema->PC_Struct, FString(), FComponentSpacePoseLink::StaticStruct(), TEXT("ComponentPose")); } #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_PoseDriver.cpp b/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_PoseDriver.cpp index 2524b1892440..f8e004b27799 100644 --- a/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_PoseDriver.cpp +++ b/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_PoseDriver.cpp @@ -64,7 +64,7 @@ void UAnimGraphNode_PoseDriver::ValidateAnimNodeDuringCompilation(USkeleton* For { if (Node.SourceBones.Num() == 0) { - MessageLog.Warning(*LOCTEXT("NoSourceBone", "@@ - You must specify at least one Source Bone").ToString(), this); + MessageLog.Warning(*LOCTEXT("PoseDriver_NoSourceBone", "You must specify at least one Source Bone").ToString(), this); } FName MissingBoneName = NAME_None; @@ -79,7 +79,7 @@ void UAnimGraphNode_PoseDriver::ValidateAnimNodeDuringCompilation(USkeleton* For if(MissingBoneName != NAME_None) { - MessageLog.Warning(*LOCTEXT("NoSourceBone", "@@ - Entry in SourceBones not found").ToString(), this); + MessageLog.Warning(*LOCTEXT("SourceBoneNotFound", "Entry in SourceBones not found").ToString(), this); } Super::ValidateAnimNodeDuringCompilation(ForSkeleton, MessageLog); diff --git a/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_SkeletalControlBase.cpp b/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_SkeletalControlBase.cpp index bf1ed5c1759e..fe497ed1dec5 100644 --- a/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_SkeletalControlBase.cpp +++ b/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_SkeletalControlBase.cpp @@ -73,7 +73,7 @@ FText UAnimGraphNode_SkeletalControlBase::GetTooltipText() const void UAnimGraphNode_SkeletalControlBase::CreateOutputPins() { const UAnimationGraphSchema* Schema = GetDefault(); - CreatePin(EGPD_Output, Schema->PC_Struct, TEXT(""), FComponentSpacePoseLink::StaticStruct(), /*bIsArray=*/ false, /*bIsReference=*/ false, TEXT("Pose")); + CreatePin(EGPD_Output, Schema->PC_Struct, FString(), FComponentSpacePoseLink::StaticStruct(), TEXT("Pose")); } @@ -86,7 +86,7 @@ void UAnimGraphNode_SkeletalControlBase::ConvertToComponentSpaceTransform(const case BCS_WorldSpace: { OutCSTransform = InTransform; - OutCSTransform.SetToRelativeTransform(SkelComp->ComponentToWorld); + OutCSTransform.SetToRelativeTransform(SkelComp->GetComponentTransform()); } break; @@ -254,7 +254,7 @@ FVector UAnimGraphNode_SkeletalControlBase::ConvertWidgetLocation(const USkeleta switch (Space) { - // ComponentToWorld must be Identity in preview window so same as ComponentSpace + // GetComponentTransform() must be Identity in preview window so same as ComponentSpace case BCS_WorldSpace: case BCS_ComponentSpace: { diff --git a/Engine/Source/Editor/AnimGraph/Private/AnimPreviewAttacheInstance.cpp b/Engine/Source/Editor/AnimGraph/Private/AnimPreviewAttacheInstance.cpp new file mode 100644 index 000000000000..de68eabea38b --- /dev/null +++ b/Engine/Source/Editor/AnimGraph/Private/AnimPreviewAttacheInstance.cpp @@ -0,0 +1,47 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + + +#include "AnimPreviewAttacheInstance.h" + +#define LOCTEXT_NAMESPACE "AnimPreviewAttacheInstance" + +void FAnimPreviewAttacheInstanceProxy::Initialize(UAnimInstance* InAnimInstance) +{ + FAnimInstanceProxy::Initialize(InAnimInstance); + + FAnimationInitializeContext InitContext(this); + CopyPoseFromMesh.bUseAttachedParent = true; + CopyPoseFromMesh.Initialize(InitContext); +} + +void FAnimPreviewAttacheInstanceProxy::Update(float DeltaSeconds) +{ + // we cant update on a worker thread here because of the key delegate needing to be fired + check(IsInGameThread()); + + FAnimationUpdateContext UpdateContext(this, DeltaSeconds); + CopyPoseFromMesh.Update(UpdateContext); + + FAnimInstanceProxy::Update(DeltaSeconds); +} + +bool FAnimPreviewAttacheInstanceProxy::Evaluate(FPoseContext& Output) +{ + // we cant evaluate on a worker thread here because of the key delegate needing to be fired + CopyPoseFromMesh.Evaluate(Output); + return true; +} + +UAnimPreviewAttacheInstance::UAnimPreviewAttacheInstance(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + RootMotionMode = ERootMotionMode::RootMotionFromEverything; + bUseMultiThreadedAnimationUpdate = false; +} + +FAnimInstanceProxy* UAnimPreviewAttacheInstance::CreateAnimInstanceProxy() +{ + return new FAnimPreviewAttacheInstanceProxy(this); +} + +#undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Editor/AnimGraph/Private/AnimPreviewInstance.cpp b/Engine/Source/Editor/AnimGraph/Private/AnimPreviewInstance.cpp index 0b7dfdf0fcdb..1442055a4318 100644 --- a/Engine/Source/Editor/AnimGraph/Private/AnimPreviewInstance.cpp +++ b/Engine/Source/Editor/AnimGraph/Private/AnimPreviewInstance.cpp @@ -107,7 +107,12 @@ void FAnimPreviewInstanceProxy::Update(float DeltaSeconds) } #endif // #if WITH_EDITORONLY_DATA - if (UPoseAsset* PoseAsset = Cast(CurrentAsset)) + if (CopyPoseNode.SourceMeshComponent.IsValid()) + { + FAnimationUpdateContext UpdateContext(this, DeltaSeconds); + CopyPoseNode.Update(UpdateContext); + } + else if (UPoseAsset* PoseAsset = Cast(CurrentAsset)) { PoseBlendNode.PoseAsset = PoseAsset; @@ -135,87 +140,94 @@ bool FAnimPreviewInstanceProxy::Evaluate(FPoseContext& Output) // we cant evaluate on a worker thread here because of the key delegate needing to be fired check(IsInGameThread()); -#if WITH_EDITORONLY_DATA - if(bForceRetargetBasePose) + if (CopyPoseNode.SourceMeshComponent.IsValid()) { - USkeletalMeshComponent* MeshComponent = Output.AnimInstanceProxy->GetSkelMeshComponent(); - if(MeshComponent && MeshComponent->SkeletalMesh) - { - FAnimationRuntime::FillWithRetargetBaseRefPose(Output.Pose, GetSkelMeshComponent()->SkeletalMesh); - } - else - { - // ideally we'll return just ref pose, but not sure if this will work with LODs - Output.Pose.ResetToRefPose(); - } + CopyPoseNode.Evaluate(Output); } else -#endif // #if WITH_EDITORONLY_DATA { - if (UPoseAsset* PoseAsset = Cast(CurrentAsset)) +#if WITH_EDITORONLY_DATA + if(bForceRetargetBasePose) { - PoseBlendNode.Evaluate(Output); + USkeletalMeshComponent* MeshComponent = Output.AnimInstanceProxy->GetSkelMeshComponent(); + if(MeshComponent && MeshComponent->SkeletalMesh) + { + FAnimationRuntime::FillWithRetargetBaseRefPose(Output.Pose, GetSkelMeshComponent()->SkeletalMesh); + } + else + { + // ideally we'll return just ref pose, but not sure if this will work with LODs + Output.Pose.ResetToRefPose(); + } } else +#endif // #if WITH_EDITORONLY_DATA { - FAnimSingleNodeInstanceProxy::Evaluate(Output); - } - } - - if (bEnableControllers) - { - UDebugSkelMeshComponent* Component = Cast(GetSkelMeshComponent()); - if(Component) - { - // update curve controllers - UpdateCurveController(); - - // create bone controllers from - if(BoneControllers.Num() > 0 || CurveBoneControllers.Num() > 0) + if (UPoseAsset* PoseAsset = Cast(CurrentAsset)) { - FPoseContext PreController(Output), PostController(Output); - // if set key is true, we should save pre controller local space transform - // so that we can calculate the delta correctly - if(bSetKey) - { - PreController = Output; - } - - FComponentSpacePoseContext ComponentSpacePoseContext(Output.AnimInstanceProxy); - ComponentSpacePoseContext.Pose.InitPose(Output.Pose); - - // apply curve data first - ApplyBoneControllers(CurveBoneControllers, ComponentSpacePoseContext); - - // and now apply bone controllers data - // it is possible they can be overlapping, but then bone controllers will overwrite - ApplyBoneControllers(BoneControllers, ComponentSpacePoseContext); - - // convert back to local @todo check this - ComponentSpacePoseContext.Pose.ConvertToLocalPoses(Output.Pose); - - if(bSetKey) - { - // now we have post controller, and calculate delta now - PostController = Output; - SetKeyImplementation(PreController.Pose, PostController.Pose); - } + PoseBlendNode.Evaluate(Output); } - // if any other bone is selected, still go for set key even if nothing changed - else if(Component->BonesOfInterest.Num() > 0) + else { - if(bSetKey) - { - // in this case, pose is same - SetKeyImplementation(Output.Pose, Output.Pose); - } + FAnimSingleNodeInstanceProxy::Evaluate(Output); } } - // we should unset here, just in case somebody clicks the key when it's not valid - if(bSetKey) + if (bEnableControllers) { - bSetKey = false; + UDebugSkelMeshComponent* Component = Cast(GetSkelMeshComponent()); + if(Component) + { + // update curve controllers + UpdateCurveController(); + + // create bone controllers from + if(BoneControllers.Num() > 0 || CurveBoneControllers.Num() > 0) + { + FPoseContext PreController(Output), PostController(Output); + // if set key is true, we should save pre controller local space transform + // so that we can calculate the delta correctly + if(bSetKey) + { + PreController = Output; + } + + FComponentSpacePoseContext ComponentSpacePoseContext(Output.AnimInstanceProxy); + ComponentSpacePoseContext.Pose.InitPose(Output.Pose); + + // apply curve data first + ApplyBoneControllers(CurveBoneControllers, ComponentSpacePoseContext); + + // and now apply bone controllers data + // it is possible they can be overlapping, but then bone controllers will overwrite + ApplyBoneControllers(BoneControllers, ComponentSpacePoseContext); + + // convert back to local @todo check this + ComponentSpacePoseContext.Pose.ConvertToLocalPoses(Output.Pose); + + if(bSetKey) + { + // now we have post controller, and calculate delta now + PostController = Output; + SetKeyImplementation(PreController.Pose, PostController.Pose); + } + } + // if any other bone is selected, still go for set key even if nothing changed + else if(Component->BonesOfInterest.Num() > 0) + { + if(bSetKey) + { + // in this case, pose is same + SetKeyImplementation(Output.Pose, Output.Pose); + } + } + } + + // we should unset here, just in case somebody clicks the key when it's not valid + if(bSetKey) + { + bSetKey = false; + } } } @@ -397,6 +409,17 @@ void FAnimPreviewInstanceProxy::AddKeyToSequence(UAnimSequence* Sequence, float GetRequiredBones().SetUseSourceData(true); } +void FAnimPreviewInstanceProxy::SetDebugSkeletalMeshComponent(USkeletalMeshComponent* InSkeletalMeshComponent) +{ + CopyPoseNode.SourceMeshComponent = InSkeletalMeshComponent; + CopyPoseNode.Initialize(FAnimationInitializeContext(this)); +} + +USkeletalMeshComponent* FAnimPreviewInstanceProxy::GetDebugSkeletalMeshComponent() const +{ + return CopyPoseNode.SourceMeshComponent.Get(); +} + UAnimPreviewInstance::UAnimPreviewInstance(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { @@ -1140,4 +1163,18 @@ FAnimInstanceProxy* UAnimPreviewInstance::CreateAnimInstanceProxy() return new FAnimPreviewInstanceProxy(this); } +void UAnimPreviewInstance::SetDebugSkeletalMeshComponent(USkeletalMeshComponent* InSkeletalMeshComponent) +{ + FAnimPreviewInstanceProxy& Proxy = GetProxyOnGameThread(); + + Proxy.InitializeObjects(this); + Proxy.SetDebugSkeletalMeshComponent(InSkeletalMeshComponent); + Proxy.ClearObjects(); +} + +USkeletalMeshComponent* UAnimPreviewInstance::GetDebugSkeletalMeshComponent() const +{ + return GetProxyOnGameThread().GetDebugSkeletalMeshComponent(); +} + #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Editor/AnimGraph/Private/AnimStateConduitNode.cpp b/Engine/Source/Editor/AnimGraph/Private/AnimStateConduitNode.cpp index 0580a76e2486..6a35c0f39ea2 100644 --- a/Engine/Source/Editor/AnimGraph/Private/AnimStateConduitNode.cpp +++ b/Engine/Source/Editor/AnimGraph/Private/AnimStateConduitNode.cpp @@ -22,15 +22,15 @@ UAnimStateConduitNode::UAnimStateConduitNode(const FObjectInitializer& ObjectIni void UAnimStateConduitNode::AllocateDefaultPins() { - CreatePin(EGPD_Input, TEXT("Transition"), TEXT(""), NULL, false, false, TEXT("In")); - CreatePin(EGPD_Output, TEXT("Transition"), TEXT(""), NULL, false, false, TEXT("Out")); + CreatePin(EGPD_Input, TEXT("Transition"), FString(), nullptr, TEXT("In")); + CreatePin(EGPD_Output, TEXT("Transition"), FString(), nullptr, TEXT("Out")); } void UAnimStateConduitNode::AutowireNewNode(UEdGraphPin* FromPin) { Super::AutowireNewNode(FromPin); - if (FromPin != NULL) + if (FromPin) { if (GetSchema()->TryCreateConnection(FromPin, GetInputPin())) { @@ -135,6 +135,8 @@ void UAnimStateConduitNode::DestroyNode() void UAnimStateConduitNode::ValidateNodeDuringCompilation(class FCompilerResultsLog& MessageLog) const { + Super::ValidateNodeDuringCompilation(MessageLog); + UAnimationTransitionGraph* TransGraph = CastChecked(BoundGraph); UAnimGraphNode_TransitionResult* ResultNode = TransGraph->GetResultNode(); check(ResultNode); diff --git a/Engine/Source/Editor/AnimGraph/Private/AnimStateEntryNode.cpp b/Engine/Source/Editor/AnimGraph/Private/AnimStateEntryNode.cpp index e88a9867923d..2d8b13bc0f00 100644 --- a/Engine/Source/Editor/AnimGraph/Private/AnimStateEntryNode.cpp +++ b/Engine/Source/Editor/AnimGraph/Private/AnimStateEntryNode.cpp @@ -21,7 +21,7 @@ UAnimStateEntryNode::UAnimStateEntryNode(const FObjectInitializer& ObjectInitial void UAnimStateEntryNode::AllocateDefaultPins() { const UAnimationStateMachineSchema* Schema = GetDefault(); - UEdGraphPin* Outputs = CreatePin(EGPD_Output, Schema->PC_Exec, TEXT(""), NULL, false, false, TEXT("Entry")); + UEdGraphPin* Outputs = CreatePin(EGPD_Output, Schema->PC_Exec, FString(), nullptr, TEXT("Entry")); } FText UAnimStateEntryNode::GetNodeTitle(ENodeTitleType::Type TitleType) const diff --git a/Engine/Source/Editor/AnimGraph/Private/AnimStateNode.cpp b/Engine/Source/Editor/AnimGraph/Private/AnimStateNode.cpp index 1f2688aaa530..fc20dc9dc2fb 100644 --- a/Engine/Source/Editor/AnimGraph/Private/AnimStateNode.cpp +++ b/Engine/Source/Editor/AnimGraph/Private/AnimStateNode.cpp @@ -25,8 +25,8 @@ UAnimStateNode::UAnimStateNode(const FObjectInitializer& ObjectInitializer) void UAnimStateNode::AllocateDefaultPins() { - UEdGraphPin* Inputs = CreatePin(EGPD_Input, TEXT("Transition"), TEXT(""), NULL, false, false, TEXT("In")); - UEdGraphPin* Outputs = CreatePin(EGPD_Output, TEXT("Transition"), TEXT(""), NULL, false, false, TEXT("Out")); + UEdGraphPin* Inputs = CreatePin(EGPD_Input, TEXT("Transition"), FString(), nullptr, TEXT("In")); + UEdGraphPin* Outputs = CreatePin(EGPD_Output, TEXT("Transition"), FString(), nullptr, TEXT("Out")); } void UAnimStateNode::AutowireNewNode(UEdGraphPin* FromPin) @@ -34,7 +34,7 @@ void UAnimStateNode::AutowireNewNode(UEdGraphPin* FromPin) Super::AutowireNewNode(FromPin); //@TODO: If the FromPin is a state, create a transition between us - if (FromPin != NULL) + if (FromPin) { if (GetSchema()->TryCreateConnection(FromPin, GetInputPin())) { diff --git a/Engine/Source/Editor/AnimGraph/Private/AnimStateTransitionNode.cpp b/Engine/Source/Editor/AnimGraph/Private/AnimStateTransitionNode.cpp index f8870785b3b8..b22b62b67835 100644 --- a/Engine/Source/Editor/AnimGraph/Private/AnimStateTransitionNode.cpp +++ b/Engine/Source/Editor/AnimGraph/Private/AnimStateTransitionNode.cpp @@ -82,9 +82,9 @@ UAnimStateTransitionNode::UAnimStateTransitionNode(const FObjectInitializer& Obj void UAnimStateTransitionNode::AllocateDefaultPins() { - UEdGraphPin* Inputs = CreatePin(EGPD_Input, TEXT("Transition"), TEXT(""), NULL, false, false, TEXT("In")); + UEdGraphPin* Inputs = CreatePin(EGPD_Input, TEXT("Transition"), FString(), nullptr, TEXT("In")); Inputs->bHidden = true; - UEdGraphPin* Outputs = CreatePin(EGPD_Output, TEXT("Transition"), TEXT(""), NULL, false, false, TEXT("Out")); + UEdGraphPin* Outputs = CreatePin(EGPD_Output, TEXT("Transition"), FString(), nullptr, TEXT("Out")); Outputs->bHidden = true; } @@ -522,6 +522,8 @@ bool UAnimStateTransitionNode::IsBoundGraphShared() void UAnimStateTransitionNode::ValidateNodeDuringCompilation(class FCompilerResultsLog& MessageLog) const { + Super::ValidateNodeDuringCompilation(MessageLog); + if (UAnimationTransitionGraph* TransGraph = Cast(BoundGraph)) { UAnimGraphNode_TransitionResult* ResultNode = TransGraph->GetResultNode(); diff --git a/Engine/Source/Editor/AnimGraph/Private/EditModes/AnimNodeEditMode.cpp b/Engine/Source/Editor/AnimGraph/Private/EditModes/AnimNodeEditMode.cpp index 4abed191da9d..8ae6f8a929d4 100644 --- a/Engine/Source/Editor/AnimGraph/Private/EditModes/AnimNodeEditMode.cpp +++ b/Engine/Source/Editor/AnimGraph/Private/EditModes/AnimNodeEditMode.cpp @@ -364,7 +364,7 @@ void FAnimNodeEditMode::ConvertToComponentSpaceTransform(const USkeletalMeshComp case BCS_WorldSpace: { OutCSTransform = InTransform; - OutCSTransform.SetToRelativeTransform(SkelComp->ComponentToWorld); + OutCSTransform.SetToRelativeTransform(SkelComp->GetComponentTransform()); } break; @@ -433,7 +433,7 @@ void FAnimNodeEditMode::ConvertToBoneSpaceTransform(const USkeletalMeshComponent { case BCS_WorldSpace: { - OutBSTransform = InCSTransform * SkelComp->ComponentToWorld; + OutBSTransform = InCSTransform * SkelComp->GetComponentTransform(); break; } @@ -609,7 +609,7 @@ FVector FAnimNodeEditMode::ConvertWidgetLocation(const USkeletalMeshComponent* S switch (Space) { - // ComponentToWorld must be Identity in preview window so same as ComponentSpace + // GetComponentTransform() must be Identity in preview window so same as ComponentSpace case BCS_WorldSpace: case BCS_ComponentSpace: { diff --git a/Engine/Source/Editor/AnimGraph/Private/EditModes/SplineIKEditMode.cpp b/Engine/Source/Editor/AnimGraph/Private/EditModes/SplineIKEditMode.cpp index cb2c39d3a8b5..8725da7799c9 100644 --- a/Engine/Source/Editor/AnimGraph/Private/EditModes/SplineIKEditMode.cpp +++ b/Engine/Source/Editor/AnimGraph/Private/EditModes/SplineIKEditMode.cpp @@ -62,14 +62,14 @@ void FSplineIKEditMode::Render(const FSceneView* View, FViewport* Viewport, FPri { UDebugSkelMeshComponent* SkelComp = GetAnimPreviewScene().GetPreviewMeshComponent(); - USplineComponent::Draw(PDI, View, SplineIKRuntimeNode->GetTransformedSplineCurves().Position, SkelComp->ComponentToWorld.ToMatrixWithScale(), FLinearColor::Yellow, SDPG_Foreground); + USplineComponent::Draw(PDI, View, SplineIKRuntimeNode->GetTransformedSplineCurves().Position, SkelComp->GetComponentTransform().ToMatrixWithScale(), FLinearColor::Yellow, SDPG_Foreground); for (int32 SplineHandleIndex = 0; SplineHandleIndex < SplineIKRuntimeNode->GetNumControlPoints(); SplineHandleIndex++) { PDI->SetHitProxy(new HSplineHandleHitProxy(SplineHandleIndex)); FTransform StartTransform = SplineIKRuntimeNode->GetTransformedSplinePoint(SplineHandleIndex); const float Scale = View->WorldToScreen(StartTransform.GetLocation()).W * (4.0f / View->UnscaledViewRect.Width() / View->ViewMatrices.GetProjectionMatrix().M[0][0]); - DrawSphere(PDI, StartTransform.GetLocation(), FVector(4.0f) * Scale, 64, 64, GEngine->ArrowMaterial->GetRenderProxy(SelectedSplinePoint == SplineHandleIndex), SDPG_Foreground); + DrawSphere(PDI, StartTransform.GetLocation(), FRotator::ZeroRotator, FVector(4.0f) * Scale, 64, 64, GEngine->ArrowMaterial->GetRenderProxy(SelectedSplinePoint == SplineHandleIndex), SDPG_Foreground); DrawCoordinateSystem(PDI, StartTransform.GetLocation(), StartTransform.GetRotation().Rotator(), 30.0f * Scale, SDPG_Foreground); } @@ -83,7 +83,7 @@ FVector FSplineIKEditMode::GetWidgetLocation() const FVector Location = SplineIKRuntimeNode->GetTransformedSplinePoint(SelectedSplinePoint).GetLocation(); UDebugSkelMeshComponent* SkelComp = GetAnimPreviewScene().GetPreviewMeshComponent(); - return SkelComp->ComponentToWorld.TransformPosition(Location); + return SkelComp->GetComponentTransform().TransformPosition(Location); } return FVector::ZeroVector; @@ -96,11 +96,8 @@ FWidget::EWidgetMode FSplineIKEditMode::GetWidgetMode() const bool FSplineIKEditMode::IsModeValid(FWidget::EWidgetMode InWidgetMode) const { - UEdGraphPin* Pin = nullptr; - // @TODO: when transforms are exposed as pin, deny editing via widget - - return Pin == nullptr || Pin->LinkedTo.Num() == 0; + return true; } @@ -191,7 +188,7 @@ bool FSplineIKEditMode::GetCustomDrawingCoordinateSystem(FMatrix& InMatrix, void if (SelectedSplinePoint != INDEX_NONE) { FTransform Transform = SplineIKRuntimeNode->GetTransformedSplinePoint(SelectedSplinePoint); - FTransform WorldTransform = Transform * SkelMeshComp->ComponentToWorld; + FTransform WorldTransform = Transform * SkelMeshComp->GetComponentTransform(); InMatrix = WorldTransform.ToMatrixNoScale().RemoveTranslation(); } diff --git a/Engine/Source/Editor/AnimGraph/Private/K2Node_AnimGetter.cpp b/Engine/Source/Editor/AnimGraph/Private/K2Node_AnimGetter.cpp index bf2eb799e66c..64d993141160 100644 --- a/Engine/Source/Editor/AnimGraph/Private/K2Node_AnimGetter.cpp +++ b/Engine/Source/Editor/AnimGraph/Private/K2Node_AnimGetter.cpp @@ -63,7 +63,7 @@ void UK2Node_AnimGetter::GetMenuActions(FBlueprintActionDatabaseRegistrar& Actio const UAnimBlueprint* AnimBlueprint = Cast(ActionRegistrar.GetActionKeyFilter()); if(AnimBlueprint && ActionRegistrar.IsOpenForRegistration(AnimBlueprint)) { - UClass* BPClass = (AnimBlueprint) ? *AnimBlueprint->ParentClass : UAnimInstance::StaticClass(); + UClass* BPClass = *AnimBlueprint->ParentClass; while(BPClass && !BPClass->HasAnyClassFlags(CLASS_Native)) { BPClass = BPClass->GetSuperClass(); diff --git a/Engine/Source/Editor/AnimGraph/Private/K2Node_TransitionRuleGetter.cpp b/Engine/Source/Editor/AnimGraph/Private/K2Node_TransitionRuleGetter.cpp index 59cc7b6263a6..2c01e2cad8b9 100644 --- a/Engine/Source/Editor/AnimGraph/Private/K2Node_TransitionRuleGetter.cpp +++ b/Engine/Source/Editor/AnimGraph/Private/K2Node_TransitionRuleGetter.cpp @@ -28,7 +28,7 @@ void UK2Node_TransitionRuleGetter::AllocateDefaultPins() { const UEdGraphSchema_K2* Schema = GetDefault(); - UEdGraphPin* OutputPin = CreatePin(EGPD_Output, Schema->PC_Float, /*PSC=*/ TEXT(""), /*PSC object=*/ NULL, /*bIsArray=*/ false, /*bIsReference=*/ false, TEXT("Output")); + UEdGraphPin* OutputPin = CreatePin(EGPD_Output, Schema->PC_Float, /*PSC=*/ FString(), /*PSC object=*/ nullptr, TEXT("Output")); OutputPin->PinFriendlyName = GetFriendlyName(GetterType); PreloadObject(AssociatedAnimAssetPlayerNode); diff --git a/Engine/Source/Editor/AnimationBlueprintEditor/Private/AnimationBlueprintEditor.cpp b/Engine/Source/Editor/AnimationBlueprintEditor/Private/AnimationBlueprintEditor.cpp index 7f1a65de4d59..e33d35379bb6 100644 --- a/Engine/Source/Editor/AnimationBlueprintEditor/Private/AnimationBlueprintEditor.cpp +++ b/Engine/Source/Editor/AnimationBlueprintEditor/Private/AnimationBlueprintEditor.cpp @@ -16,7 +16,7 @@ #include "IAnimationBlueprintEditorModule.h" #include "AnimationBlueprintEditorModule.h" - +#include "BlueprintEditorTabs.h" #include "SKismetInspector.h" @@ -201,6 +201,8 @@ void FAnimationBlueprintEditor::InitAnimationBlueprintEditor(const EToolkitMode: FPersonaModule& PersonaModule = FModuleManager::GetModuleChecked("Persona"); PersonaToolkit = PersonaModule.CreatePersonaToolkit(InAnimBlueprint); + PersonaToolkit->GetPreviewScene()->SetDefaultAnimationMode(EPreviewSceneDefaultAnimationMode::AnimationBlueprint); + TSharedRef AssetFamily = PersonaModule.CreatePersonaAssetFamily(InAnimBlueprint); AssetFamily->RecordAssetOpened(FAssetData(InAnimBlueprint)); @@ -253,6 +255,16 @@ void FAnimationBlueprintEditor::InitAnimationBlueprintEditor(const EToolkitMode: // register customization of Slot node for this Animation Blueprint Editor // this is so that you can open the manage window per Animation Blueprint Editor PersonaModule.CustomizeSlotNodeDetails(Inspector->GetPropertyView().ToSharedRef(), FOnInvokeTab::CreateSP(this, &FAssetEditorToolkit::InvokeTab)); + + if (UBlueprint* Blueprint = GetBlueprintObj()) + { + // If we have a warning/error, open output log and recompile to show log output. + if (!Blueprint->IsUpToDate() || (Blueprint->Status == BS_UpToDateWithWarnings)) + { + TabManager->InvokeTab(FBlueprintEditorTabs::CompilerResultsID); + Compile(); + } + } } void FAnimationBlueprintEditor::BindCommands() @@ -1024,32 +1036,31 @@ void FAnimationBlueprintEditor::RecompileAnimBlueprintIfDirty() void FAnimationBlueprintEditor::Compile() { - // Note if we were debugging the preview - UObject* CurrentDebugObject = GetBlueprintObj()->GetObjectBeingDebugged(); - UDebugSkelMeshComponent* PreviewMeshComponent = PersonaToolkit->GetPreviewMeshComponent(); - const bool bIsDebuggingPreview = (PreviewMeshComponent != NULL) && PreviewMeshComponent->IsAnimBlueprintInstanced() && (PreviewMeshComponent->GetAnimInstance() == CurrentDebugObject); - - if (PreviewMeshComponent != NULL) + // Grab the currently debugged object, so we can re-set it below + USkeletalMeshComponent* DebuggedMeshComponent = nullptr; + if (UBlueprint* Blueprint = GetBlueprintObj()) { - // Force close any asset editors that are using the AnimScriptInstance (such as the Property Matrix), the class will be garbage collected - FAssetEditorManager::Get().CloseOtherEditors(PreviewMeshComponent->GetAnimInstance(), nullptr); + UAnimInstance* CurrentDebugObject = Cast(Blueprint->GetObjectBeingDebugged()); + if(CurrentDebugObject) + { + // Force close any asset editors that are using the AnimScriptInstance (such as the Property Matrix), the class will be garbage collected + FAssetEditorManager::Get().CloseOtherEditors(CurrentDebugObject, nullptr); + DebuggedMeshComponent = CurrentDebugObject->GetSkelMeshComponent(); + } } // Compile the blueprint FBlueprintEditor::Compile(); - if (PreviewMeshComponent != NULL) + if (DebuggedMeshComponent != nullptr) { - if (PreviewMeshComponent->GetAnimInstance() == NULL) + if (DebuggedMeshComponent->GetAnimInstance() == nullptr) { // try reinitialize animation if it doesn't exist - PreviewMeshComponent->InitAnim(true); + DebuggedMeshComponent->InitAnim(true); } - if (bIsDebuggingPreview) - { - GetBlueprintObj()->SetObjectBeingDebugged(PreviewMeshComponent->GetAnimInstance()); - } + GetBlueprintObj()->SetObjectBeingDebugged(DebuggedMeshComponent->GetAnimInstance()); } // reset the selected skeletal control node @@ -1303,22 +1314,6 @@ void FAnimationBlueprintEditor::OnBlueprintChangedImpl(UBlueprint* InBlueprint, { FBlueprintEditor::OnBlueprintChangedImpl(InBlueprint, bIsJustBeingCompiled); - UObject* CurrentDebugObject = GetBlueprintObj()->GetObjectBeingDebugged(); - UDebugSkelMeshComponent* PreviewMeshComponent = PersonaToolkit->GetPreviewMeshComponent(); - - if(PreviewMeshComponent != NULL) - { - // Reinitialize the animation, anything we reference could have changed triggering - // the blueprint change - PreviewMeshComponent->InitAnim(true); - - const bool bIsDebuggingPreview = (PreviewMeshComponent != NULL) && PreviewMeshComponent->IsAnimBlueprintInstanced() && (PreviewMeshComponent->GetAnimInstance() == CurrentDebugObject); - if(bIsDebuggingPreview) - { - GetBlueprintObj()->SetObjectBeingDebugged(PreviewMeshComponent->GetAnimInstance()); - } - } - // calls PostCompile to copy proper values between anim nodes OnPostCompile(); } @@ -1441,5 +1436,36 @@ void FAnimationBlueprintEditor::HandlePinDefaultValueChanged(UEdGraphPin* InPinT } } +void FAnimationBlueprintEditor::HandleSetObjectBeingDebugged(UObject* InObject) +{ + FBlueprintEditor::HandleSetObjectBeingDebugged(InObject); + + if (UAnimInstance* AnimInstance = Cast(InObject)) + { + USkeletalMeshComponent* SkeletalMeshComponent = AnimInstance->GetSkelMeshComponent(); + if (SkeletalMeshComponent) + { + // If we are selecting the preview instance, reset us back to 'normal' + if (InObject->GetWorld()->IsPreviewWorld()) + { + GetPreviewScene()->ShowDefaultMode(); + GetPreviewScene()->GetPreviewMeshComponent()->PreviewInstance->SetDebugSkeletalMeshComponent(nullptr); + } + else + { + // Otherwise eet us to display the debugged instance via copy-pose + GetPreviewScene()->GetPreviewMeshComponent()->EnablePreview(true, nullptr); + GetPreviewScene()->GetPreviewMeshComponent()->PreviewInstance->SetDebugSkeletalMeshComponent(SkeletalMeshComponent); + } + } + } + else + { + // Clear the copy-pose component and set us back to 'normal' + GetPreviewScene()->ShowDefaultMode(); + GetPreviewScene()->GetPreviewMeshComponent()->PreviewInstance->SetDebugSkeletalMeshComponent(nullptr); + } +} + #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Editor/AnimationBlueprintEditor/Private/AnimationBlueprintEditor.h b/Engine/Source/Editor/AnimationBlueprintEditor/Private/AnimationBlueprintEditor.h index 455924f8d0ca..7819bc703130 100644 --- a/Engine/Source/Editor/AnimationBlueprintEditor/Private/AnimationBlueprintEditor.h +++ b/Engine/Source/Editor/AnimationBlueprintEditor/Private/AnimationBlueprintEditor.h @@ -86,6 +86,7 @@ public: /** FBlueprintEdi1tor interface */ virtual void OnActiveTabChanged(TSharedPtr PreviouslyActive, TSharedPtr NewlyActivated) override; virtual void OnSelectedNodesChangedImpl(const TSet& NewSelection) override; + virtual void HandleSetObjectBeingDebugged(UObject* InObject) override; // Gets the Anim Blueprint being edited/viewed by this Persona instance UAnimBlueprint* GetAnimBlueprint() const; diff --git a/Engine/Source/Editor/AnimationEditor/Private/AnimationEditor.cpp b/Engine/Source/Editor/AnimationEditor/Private/AnimationEditor.cpp index c81644bcdc9b..bcea0d549f90 100644 --- a/Engine/Source/Editor/AnimationEditor/Private/AnimationEditor.cpp +++ b/Engine/Source/Editor/AnimationEditor/Private/AnimationEditor.cpp @@ -194,12 +194,12 @@ void FAnimationEditor::BindCommands() FExecuteAction::CreateSP(this, &FAnimationEditor::OnApplyRawAnimChanges), FCanExecuteAction::CreateSP(this, &FAnimationEditor::CanApplyRawAnimChanges)); - ToolkitCommands->MapAction(FAnimationEditorCommands::Get().ExportToFBX_Source, - FExecuteAction::CreateSP(this, &FAnimationEditor::OnExportToFBX, EPoseSourceOption::CurrentAnimation_Source), + ToolkitCommands->MapAction(FAnimationEditorCommands::Get().ExportToFBX_AnimData, + FExecuteAction::CreateSP(this, &FAnimationEditor::OnExportToFBX, EPoseSourceOption::CurrentAnimation_AnimData), FCanExecuteAction::CreateSP(this, &FAnimationEditor::HasValidAnimationSequence)); - ToolkitCommands->MapAction(FAnimationEditorCommands::Get().ExportToFBX_Play, - FExecuteAction::CreateSP(this, &FAnimationEditor::OnExportToFBX, EPoseSourceOption::CurrentAnimation_Play), + ToolkitCommands->MapAction(FAnimationEditorCommands::Get().ExportToFBX_PreviewMesh, + FExecuteAction::CreateSP(this, &FAnimationEditor::OnExportToFBX, EPoseSourceOption::CurrentAnimation_PreviewMesh), FCanExecuteAction::CreateSP(this, &FAnimationEditor::HasValidAnimationSequence)); ToolkitCommands->MapAction(FAnimationEditorCommands::Get().AddLoopingInterpolation, @@ -387,11 +387,8 @@ TSharedPtr FAnimationEditor::OpenNewAnimationDocumentTab(UAnimationAss RemoveEditingObject(AnimationAsset); } - if (InAnimAsset != nullptr) - { - AddEditingObject(InAnimAsset); - AnimationAsset = InAnimAsset; - } + AddEditingObject(InAnimAsset); + AnimationAsset = InAnimAsset; GetPersonaToolkit()->GetPreviewScene()->SetPreviewAnimationAsset(InAnimAsset); GetPersonaToolkit()->SetAnimationAsset(InAnimAsset); @@ -548,18 +545,18 @@ void FAnimationEditor::OnApplyCompression() void FAnimationEditor::OnExportToFBX(const EPoseSourceOption Option) { UAnimSequence* AnimSequenceToRecord = nullptr; - if (Option == EPoseSourceOption::CurrentAnimation_Source) + if (Option == EPoseSourceOption::CurrentAnimation_AnimData) { TArray AssetsToExport; AssetsToExport.Add(AnimationAsset); ExportToFBX(AssetsToExport, false); } - else if (Option == EPoseSourceOption::CurrentAnimation_Play) + else if (Option == EPoseSourceOption::CurrentAnimation_PreviewMesh) { TArray> Skeletons; Skeletons.Add(PersonaToolkit->GetSkeleton()); - AnimationEditorUtils::CreateAnimationAssets(Skeletons, UAnimSequence::StaticClass(), FString("_Play"), FAnimAssetCreated::CreateSP(this, &FAnimationEditor::ExportToFBX, true), AnimationAsset, true); + AnimationEditorUtils::CreateAnimationAssets(Skeletons, UAnimSequence::StaticClass(), FString("_PreviewMesh"), FAnimAssetCreated::CreateSP(this, &FAnimationEditor::ExportToFBX, true), AnimationAsset, true); } else { @@ -720,21 +717,21 @@ void FAnimationEditor::FillCreateAnimationFromCurrentAnimationMenu(FMenuBuilder& MenuBuilder.BeginSection("CreateAnimationSubMenu", LOCTEXT("CreateAnimationFromCurrentAnimationSubmenuHeading", "Create Animation")); { MenuBuilder.AddMenuEntry( - LOCTEXT("CreateAnimation_CurrentAnimation_Source", "Source"), - LOCTEXT("CreateAnimation_CurrentAnimation_Source_Tooltip", "Create Animation from Source Data."), + LOCTEXT("CreateAnimation_CurrentAnimation_AnimData", "Animation Data"), + LOCTEXT("CreateAnimation_CurrentAnimation_AnimData_Tooltip", "Create Animation from Animation Source Data."), FSlateIcon(), FUIAction( - FExecuteAction::CreateStatic(&AnimationEditorUtils::ExecuteNewAnimAsset, Objects, FString("_Sequence"), FAnimAssetCreated::CreateSP(this, &FAnimationEditor::CreateAnimation, EPoseSourceOption::CurrentAnimation_Source), false), + FExecuteAction::CreateStatic(&AnimationEditorUtils::ExecuteNewAnimAsset, Objects, FString("_Sequence"), FAnimAssetCreated::CreateSP(this, &FAnimationEditor::CreateAnimation, EPoseSourceOption::CurrentAnimation_AnimData), false), FCanExecuteAction::CreateSP(this, &FAnimationEditor::HasValidAnimationSequence) ) ); MenuBuilder.AddMenuEntry( - LOCTEXT("CreateAnimation_CurrentAnimation_Play", "Play"), - LOCTEXT("CreateAnimation_CurrentAnimation_Play_Tooltip", "Create Animation from Play on the Current Preview Mesh, including Retargeting, Post Process Graph, or anything you see on the preview mesh."), + LOCTEXT("CreateAnimation_CurrentAnimation_PreviewMesh", "Preview Mesh"), + LOCTEXT("CreateAnimation_CurrentAnimation_PreviewMesh_Tooltip", "Create Animation by playing on the Current Preview Mesh, including Retargeting, Post Process Graph, or anything you see on the preview mesh."), FSlateIcon(), FUIAction( - FExecuteAction::CreateStatic(&AnimationEditorUtils::ExecuteNewAnimAsset, Objects, FString("_Sequence"), FAnimAssetCreated::CreateSP(this, &FAnimationEditor::CreateAnimation, EPoseSourceOption::CurrentAnimation_Play), false), + FExecuteAction::CreateStatic(&AnimationEditorUtils::ExecuteNewAnimAsset, Objects, FString("_Sequence"), FAnimAssetCreated::CreateSP(this, &FAnimationEditor::CreateAnimation, EPoseSourceOption::CurrentAnimation_PreviewMesh), false), FCanExecuteAction::CreateSP(this, &FAnimationEditor::HasValidAnimationSequence) ) ); @@ -774,7 +771,7 @@ void FAnimationEditor::FillCreatePoseAssetMenu(FMenuBuilder& MenuBuilder) const LOCTEXT("CreatePoseAsset_CurrentAnimation_Tooltip", "Create Animation from current animation."), FSlateIcon(), FUIAction( - FExecuteAction::CreateStatic(&AnimationEditorUtils::ExecuteNewAnimAsset, Objects, FString("_PoseAsset"), FAnimAssetCreated::CreateSP(this, &FAnimationEditor::CreatePoseAsset, EPoseSourceOption::CurrentAnimation_Source), false), + FExecuteAction::CreateStatic(&AnimationEditorUtils::ExecuteNewAnimAsset, Objects, FString("_PoseAsset"), FAnimAssetCreated::CreateSP(this, &FAnimationEditor::CreatePoseAsset, EPoseSourceOption::CurrentAnimation_AnimData), false), FCanExecuteAction() ) ); @@ -893,8 +890,8 @@ void FAnimationEditor::FillExportAssetMenu(FMenuBuilder& MenuBuilder) const { MenuBuilder.BeginSection("AnimationExport", LOCTEXT("ExportAssetMenuHeading", "Export")); { - MenuBuilder.AddMenuEntry(FAnimationEditorCommands::Get().ExportToFBX_Source); - MenuBuilder.AddMenuEntry(FAnimationEditorCommands::Get().ExportToFBX_Play); + MenuBuilder.AddMenuEntry(FAnimationEditorCommands::Get().ExportToFBX_AnimData); + MenuBuilder.AddMenuEntry(FAnimationEditorCommands::Get().ExportToFBX_PreviewMesh); } MenuBuilder.EndSection(); } @@ -990,10 +987,10 @@ void FAnimationEditor::CreateAnimation(const TArray NewAssets, const E case EPoseSourceOption::CurrentPose: bResult &= NewAnimSequence->CreateAnimation(MeshComponent); break; - case EPoseSourceOption::CurrentAnimation_Source: + case EPoseSourceOption::CurrentAnimation_AnimData: bResult &= NewAnimSequence->CreateAnimation(Sequence); break; - case EPoseSourceOption::CurrentAnimation_Play: + case EPoseSourceOption::CurrentAnimation_PreviewMesh: bResult &= RecordMeshToAnimation(MeshComponent, NewAnimSequence); break; default: @@ -1039,7 +1036,7 @@ void FAnimationEditor::CreatePoseAsset(const TArray NewAssets, const E NewPoseAsset->AddOrUpdatePoseWithUniqueName(PreviewComponent); bResult = true; break; - case EPoseSourceOption::CurrentAnimation_Source: + case EPoseSourceOption::CurrentAnimation_AnimData: NewPoseAsset->CreatePoseFromAnimation(Sequence); bResult = true; break; diff --git a/Engine/Source/Editor/AnimationEditor/Private/AnimationEditor.h b/Engine/Source/Editor/AnimationEditor/Private/AnimationEditor.h index 9933a32b5510..c4ec56547d1f 100644 --- a/Engine/Source/Editor/AnimationEditor/Private/AnimationEditor.h +++ b/Engine/Source/Editor/AnimationEditor/Private/AnimationEditor.h @@ -105,8 +105,8 @@ private: { ReferencePose, CurrentPose, - CurrentAnimation_Source, - CurrentAnimation_Play, + CurrentAnimation_AnimData, + CurrentAnimation_PreviewMesh, Max }; diff --git a/Engine/Source/Editor/AnimationEditor/Private/AnimationEditorCommands.cpp b/Engine/Source/Editor/AnimationEditor/Private/AnimationEditorCommands.cpp index 661a0f430c43..b142a4d23b4b 100644 --- a/Engine/Source/Editor/AnimationEditor/Private/AnimationEditorCommands.cpp +++ b/Engine/Source/Editor/AnimationEditor/Private/AnimationEditorCommands.cpp @@ -9,8 +9,8 @@ void FAnimationEditorCommands::RegisterCommands() UI_COMMAND(ImportAnimation, "Import Animation", "Import new animation for the skeleton.", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(ReimportAnimation, "Reimport Animation", "Reimport current animation.", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(ApplyCompression, "Apply Compression", "Apply compression to current animation", EUserInterfaceActionType::Button, FInputChord()); - UI_COMMAND(ExportToFBX_Source, "Source", "Export current animation source to FBX", EUserInterfaceActionType::Button, FInputChord()); - UI_COMMAND(ExportToFBX_Play, "Play", "Export current animation from from Play on the current preview mesh, including retargeting, post process graph, or anything you see on the preview mesh.", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(ExportToFBX_AnimData, "Animation Data", "Export current animation source data to FBX", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(ExportToFBX_PreviewMesh, "Preview Mesh", "Export current animation by playing on the current preview mesh, including retargeting, post process graph, or anything you see on the preview mesh.", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(AddLoopingInterpolation, "Add Looping Interpolation", "Add an extra first frame at the end of the animation to create interpolation when looping", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(SetKey, "Set Key", "Add Bone Transform to Additive Layer Tracks", EUserInterfaceActionType::Button, FInputChord(EKeys::S)); UI_COMMAND(ApplyAnimation, "Apply Animation", "Apply Additive Layer Tracks to Runtime Animation Data", EUserInterfaceActionType::Button, FInputChord()); diff --git a/Engine/Source/Editor/AnimationEditor/Private/AnimationEditorCommands.h b/Engine/Source/Editor/AnimationEditor/Private/AnimationEditorCommands.h index 25cf4e804ade..943f12c46bd2 100644 --- a/Engine/Source/Editor/AnimationEditor/Private/AnimationEditorCommands.h +++ b/Engine/Source/Editor/AnimationEditor/Private/AnimationEditorCommands.h @@ -24,9 +24,9 @@ public: // apply compression TSharedPtr ApplyCompression; // export to FBX - TSharedPtr ExportToFBX_Source; + TSharedPtr ExportToFBX_AnimData; // export to FBX - TSharedPtr ExportToFBX_Play; + TSharedPtr ExportToFBX_PreviewMesh; // Add looping interpolation TSharedPtr AddLoopingInterpolation; // set key for bone track diff --git a/Engine/Source/Editor/AnimationModifiers/Public/AnimationModifier.h b/Engine/Source/Editor/AnimationModifiers/Public/AnimationModifier.h index 812dbe58eb2e..f15199adfc05 100644 --- a/Engine/Source/Editor/AnimationModifiers/Public/AnimationModifier.h +++ b/Engine/Source/Editor/AnimationModifiers/Public/AnimationModifier.h @@ -10,7 +10,7 @@ class USkeleton; -UCLASS(Blueprintable, config = Editor, defaultconfig) +UCLASS(Blueprintable, Experimental, config = Editor, defaultconfig) class ANIMATIONMODIFIERS_API UAnimationModifier : public UObject { GENERATED_BODY() diff --git a/Engine/Source/Editor/AudioEditor/Private/AssetTypeActions/AssetTypeActions_SoundBase.cpp b/Engine/Source/Editor/AudioEditor/Private/AssetTypeActions/AssetTypeActions_SoundBase.cpp index bc5f35f3b89c..27d3a4b742ab 100644 --- a/Engine/Source/Editor/AudioEditor/Private/AssetTypeActions/AssetTypeActions_SoundBase.cpp +++ b/Engine/Source/Editor/AudioEditor/Private/AssetTypeActions/AssetTypeActions_SoundBase.cpp @@ -206,6 +206,7 @@ TSharedPtr FAssetTypeActions_SoundBase::GetThumbnailOverlay(const FAsse .ToolTipText_Lambda(OnToolTipTextLambda) .Cursor(EMouseCursor::Default) // The outer widget can specify a DragHand cursor, so we need to override that here .ForegroundColor(FSlateColor::UseForeground()) + .IsFocusable(false) .OnClicked_Lambda(OnClickedLambda) .Visibility_Lambda(OnGetVisibilityLambda) [ diff --git a/Engine/Source/Editor/AudioEditor/Private/AssetTypeActions/AssetTypeActions_SoundWave.cpp b/Engine/Source/Editor/AudioEditor/Private/AssetTypeActions/AssetTypeActions_SoundWave.cpp index 264816108dda..00cfabdef606 100644 --- a/Engine/Source/Editor/AudioEditor/Private/AssetTypeActions/AssetTypeActions_SoundWave.cpp +++ b/Engine/Source/Editor/AudioEditor/Private/AssetTypeActions/AssetTypeActions_SoundWave.cpp @@ -287,6 +287,7 @@ TSharedPtr FAssetTypeActions_SoundWave::GetThumbnailOverlay(const FAsse .ToolTipText_Lambda(OnToolTipTextLambda) .Cursor(EMouseCursor::Default) // The outer widget can specify a DragHand cursor, so we need to override that here .ForegroundColor(FSlateColor::UseForeground()) + .IsFocusable(false) .OnClicked_Lambda(OnClickedLambda) .Visibility_Lambda(OnGetVisibilityLambda) [ diff --git a/Engine/Source/Editor/AudioEditor/Private/AudioEditorModule.cpp b/Engine/Source/Editor/AudioEditor/Private/AudioEditorModule.cpp index 9db8bba9dbbc..ff81b8b9425d 100644 --- a/Engine/Source/Editor/AudioEditor/Private/AudioEditorModule.cpp +++ b/Engine/Source/Editor/AudioEditor/Private/AudioEditorModule.cpp @@ -18,7 +18,7 @@ #include "Sound/SoundEffectPreset.h" #include "SoundCueEditor.h" #include "SoundSubmixEditor.h" -#include "Settings/EditorExperimentalSettings.h" +#include "Classes/Sound/AudioSettings.h" #include "AssetTypeActions/AssetTypeActions_DialogueVoice.h" #include "AssetTypeActions/AssetTypeActions_DialogueWave.h" #include "AssetTypeActions/AssetTypeActions_SoundAttenuation.h" @@ -92,10 +92,14 @@ public: AssetTools.RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_SoundMix)); AssetTools.RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_SoundWave)); AssetTools.RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_ReverbEffect)); + } + virtual void RegisterAudioMixerAssetActions() override + { // Only register asset actions for when audio mixer data is enabled - if (GetDefault()->bShowAudioMixerData) + if (GetDefault()->IsAudioMixerEnabled()) { + IAssetTools& AssetTools = FModuleManager::LoadModuleChecked("AssetTools").Get(); AssetTools.RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_SoundSubmix)); AssetTools.RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_SoundEffectSubmixPreset)); AssetTools.RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_SoundEffectSourcePreset)); @@ -119,7 +123,7 @@ public: virtual void RegisterEffectPresetAssetActions() override { // Only register asset actions for the case where audio mixer data is enabled - if (GetDefault()->bShowAudioMixerData) + if (GetDefault()->IsAudioMixerEnabled()) { // Register the audio editor asset type actions IAssetTools& AssetTools = FModuleManager::LoadModuleChecked("AssetTools").Get(); diff --git a/Engine/Source/Editor/AudioEditor/Private/Factories/SoundFactoryUtility.h b/Engine/Source/Editor/AudioEditor/Private/Factories/SoundFactoryUtility.h index 7cc1a0200ffe..7be1967bb499 100644 --- a/Engine/Source/Editor/AudioEditor/Private/Factories/SoundFactoryUtility.h +++ b/Engine/Source/Editor/AudioEditor/Private/Factories/SoundFactoryUtility.h @@ -13,7 +13,7 @@ public: TSet< const UClass* > AllowedChildrenOfClasses; /** Disallowed class flags. */ - uint32 DisallowedClassFlags; + EClassFlags DisallowedClassFlags; virtual bool IsClassAllowed(const FClassViewerInitializationOptions& InInitOptions, const UClass* InClass, TSharedRef< FClassViewerFilterFuncs > InFilterFuncs) override { diff --git a/Engine/Source/Editor/AudioEditor/Private/SoundClassGraphNode.cpp b/Engine/Source/Editor/AudioEditor/Private/SoundClassGraphNode.cpp index 6e2576ebed21..c763fb297584 100644 --- a/Engine/Source/Editor/AudioEditor/Private/SoundClassGraphNode.cpp +++ b/Engine/Source/Editor/AudioEditor/Private/SoundClassGraphNode.cpp @@ -71,13 +71,13 @@ void USoundClassGraphNode::AllocateDefaultPins() { check(Pins.Num() == 0); - ChildPin = CreatePin(EGPD_Output, TEXT("SoundClass"), TEXT(""), NULL, /*bIsArray=*/ false, /*bIsReference=*/ false, LOCTEXT("SoundClassChildren", "Children").ToString()); - ParentPin = CreatePin(EGPD_Input, TEXT("SoundClass"), TEXT(""), NULL, /*bIsArray=*/ false, /*bIsReference=*/ false, TEXT("")); + ChildPin = CreatePin(EGPD_Output, TEXT("SoundClass"), FString(), nullptr, LOCTEXT("SoundClassChildren", "Children").ToString()); + ParentPin = CreatePin(EGPD_Input, TEXT("SoundClass"), FString(), nullptr, FString()); } void USoundClassGraphNode::AutowireNewNode(UEdGraphPin* FromPin) { - if (FromPin != NULL) + if (FromPin) { const USoundClassGraphSchema* Schema = CastChecked(GetSchema()); diff --git a/Engine/Source/Editor/AudioEditor/Private/SoundCueEditor.cpp b/Engine/Source/Editor/AudioEditor/Private/SoundCueEditor.cpp index 12654dd2ac87..fa004bb70e82 100644 --- a/Engine/Source/Editor/AudioEditor/Private/SoundCueEditor.cpp +++ b/Engine/Source/Editor/AudioEditor/Private/SoundCueEditor.cpp @@ -340,6 +340,21 @@ void FSoundCueEditor::BindGraphCommands() void FSoundCueEditor::PlayCue() { GEditor->PlayPreviewSound(SoundCue); + + SoundCueGraphEditor->RegisterActiveTimer(0.0f, + FWidgetActiveTimerDelegate::CreateLambda( + [](double InCurrentTime, float InDeltaTime) + { + UAudioComponent* PreviewComp = GEditor->GetPreviewAudioComponent(); + if (PreviewComp && PreviewComp->IsPlaying()) + { + return EActiveTimerReturnType::Continue; + } + else + { + return EActiveTimerReturnType::Stop; + } + })); } void FSoundCueEditor::PlayNode() diff --git a/Engine/Source/Editor/AudioEditor/Private/SoundCueGraphNode.cpp b/Engine/Source/Editor/AudioEditor/Private/SoundCueGraphNode.cpp index 08d0891a2635..edfe00fd56e9 100644 --- a/Engine/Source/Editor/AudioEditor/Private/SoundCueGraphNode.cpp +++ b/Engine/Source/Editor/AudioEditor/Private/SoundCueGraphNode.cpp @@ -60,7 +60,7 @@ void USoundCueGraphNode::SetSoundNode(USoundNode* InSoundNode) void USoundCueGraphNode::CreateInputPin() { - UEdGraphPin* NewPin = CreatePin(EGPD_Input, TEXT("SoundNode"), TEXT(""), NULL, /*bIsArray=*/ false, /*bIsReference=*/ false, SoundNode->GetInputPinName(GetInputCount()).ToString()); + UEdGraphPin* NewPin = CreatePin(EGPD_Input, TEXT("SoundNode"), FString(), nullptr, SoundNode->GetInputPinName(GetInputCount()).ToString()); if (NewPin->PinName.IsEmpty()) { // Makes sure pin has a name for lookup purposes but user will never see it diff --git a/Engine/Source/Editor/AudioEditor/Private/SoundCueGraphNode_Base.cpp b/Engine/Source/Editor/AudioEditor/Private/SoundCueGraphNode_Base.cpp index 9805f14e43d6..387d18e16726 100644 --- a/Engine/Source/Editor/AudioEditor/Private/SoundCueGraphNode_Base.cpp +++ b/Engine/Source/Editor/AudioEditor/Private/SoundCueGraphNode_Base.cpp @@ -124,7 +124,7 @@ void USoundCueGraphNode_Base::AllocateDefaultPins() if (!IsRootNode()) { - CreatePin(EGPD_Output, TEXT("SoundNode"), TEXT(""), NULL, /*bIsArray=*/ false, /*bIsReference=*/ false, TEXT("Output")); + CreatePin(EGPD_Output, TEXT("SoundNode"), FString(), nullptr, TEXT("Output")); } } diff --git a/Engine/Source/Editor/AudioEditor/Private/SoundCueGraphNode_Root.cpp b/Engine/Source/Editor/AudioEditor/Private/SoundCueGraphNode_Root.cpp index a4311e0c5339..5492b87dcc3f 100644 --- a/Engine/Source/Editor/AudioEditor/Private/SoundCueGraphNode_Root.cpp +++ b/Engine/Source/Editor/AudioEditor/Private/SoundCueGraphNode_Root.cpp @@ -36,7 +36,7 @@ FText USoundCueGraphNode_Root::GetTooltipText() const void USoundCueGraphNode_Root::CreateInputPins() { - CreatePin(EGPD_Input, TEXT("SoundNode"), TEXT("Root"), NULL, /*bIsArray=*/ false, /*bIsReference=*/ false, TEXT("")); + CreatePin(EGPD_Input, TEXT("SoundNode"), TEXT("Root"), nullptr, FString()); } void USoundCueGraphNode_Root::GetContextMenuActions(const FGraphNodeContextMenuBuilder& Context) const diff --git a/Engine/Source/Editor/AudioEditor/Private/SoundSubmixGraphNode.cpp b/Engine/Source/Editor/AudioEditor/Private/SoundSubmixGraphNode.cpp index 7fa437b3103f..1d20c2d41c5b 100644 --- a/Engine/Source/Editor/AudioEditor/Private/SoundSubmixGraphNode.cpp +++ b/Engine/Source/Editor/AudioEditor/Private/SoundSubmixGraphNode.cpp @@ -61,13 +61,13 @@ void USoundSubmixGraphNode::AllocateDefaultPins() { check(Pins.Num() == 0); - ChildPin = CreatePin(EGPD_Output, TEXT("SoundSubmix"), TEXT(""), NULL, /*bIsArray=*/ false, /*bIsReference=*/ false, LOCTEXT("SoundSubmixChildren", "Children").ToString()); - ParentPin = CreatePin(EGPD_Input, TEXT("SoundSubmix"), TEXT(""), NULL, /*bIsArray=*/ false, /*bIsReference=*/ false, TEXT("")); + ChildPin = CreatePin(EGPD_Output, TEXT("SoundSubmix"), FString(), nullptr, LOCTEXT("SoundSubmixChildren", "Children").ToString()); + ParentPin = CreatePin(EGPD_Input, TEXT("SoundSubmix"), FString(), nullptr, FString()); } void USoundSubmixGraphNode::AutowireNewNode(UEdGraphPin* FromPin) { - if (FromPin != NULL) + if (FromPin) { const USoundSubmixGraphSchema* Schema = CastChecked(GetSchema()); diff --git a/Engine/Source/Editor/AudioEditor/Public/AudioEditorModule.h b/Engine/Source/Editor/AudioEditor/Public/AudioEditorModule.h index 95d1e7edb5dc..c91291f360d1 100644 --- a/Engine/Source/Editor/AudioEditor/Public/AudioEditorModule.h +++ b/Engine/Source/Editor/AudioEditor/Public/AudioEditorModule.h @@ -35,6 +35,9 @@ public: /** Registers audio editor asset actions. */ virtual void RegisterAssetActions() = 0; + /** Registers audio editor asset actions specific to audio mixer functionality. */ + virtual void RegisterAudioMixerAssetActions() = 0; + /** Registers effect preset asset actions. */ virtual void RegisterEffectPresetAssetActions() {} diff --git a/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeDecoratorGraphNode_Decorator.cpp b/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeDecoratorGraphNode_Decorator.cpp index 04a9c44eab59..df9f824983ab 100644 --- a/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeDecoratorGraphNode_Decorator.cpp +++ b/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeDecoratorGraphNode_Decorator.cpp @@ -15,7 +15,7 @@ UBehaviorTreeDecoratorGraphNode_Decorator::UBehaviorTreeDecoratorGraphNode_Decor void UBehaviorTreeDecoratorGraphNode_Decorator::AllocateDefaultPins() { - CreatePin(EGPD_Output, TEXT("Transition"), TEXT(""), NULL, false, false, TEXT("Out")); + CreatePin(EGPD_Output, TEXT("Transition"), FString(), nullptr, TEXT("Out")); } void UBehaviorTreeDecoratorGraphNode_Decorator::PostPlacedNewNode() diff --git a/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeDecoratorGraphNode_Logic.cpp b/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeDecoratorGraphNode_Logic.cpp index aeccde9ec451..f381151dba2a 100644 --- a/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeDecoratorGraphNode_Logic.cpp +++ b/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeDecoratorGraphNode_Logic.cpp @@ -23,7 +23,7 @@ void UBehaviorTreeDecoratorGraphNode_Logic::AllocateDefaultPins() if (LogicMode != EDecoratorLogicMode::Sink) { - CreatePin(EGPD_Output, TEXT("Transition"), TEXT(""), NULL, false, false, TEXT("Out")); + CreatePin(EGPD_Output, TEXT("Transition"), FString(), nullptr, TEXT("Out")); } } @@ -73,7 +73,7 @@ bool UBehaviorTreeDecoratorGraphNode_Logic::CanRemovePins() const UEdGraphPin* UBehaviorTreeDecoratorGraphNode_Logic::AddInputPin() { - return CreatePin(EGPD_Input, TEXT("Transition"), TEXT(""), NULL, false, false, TEXT("In")); + return CreatePin(EGPD_Input, TEXT("Transition"), FString(), nullptr, TEXT("In")); } void UBehaviorTreeDecoratorGraphNode_Logic::RemoveInputPin(class UEdGraphPin* Pin) diff --git a/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeGraph.cpp b/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeGraph.cpp index 40b5ae5afbaa..134317f7fbb7 100644 --- a/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeGraph.cpp +++ b/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeGraph.cpp @@ -912,7 +912,7 @@ void UBehaviorTreeGraph::CreateBTFromGraph(UBehaviorTreeGraphNode* RootEdNode) BTGraphHelpers::CollectDecorators(BTAsset, RootEdNode, BTAsset->RootDecorators, BTAsset->RootDecoratorOps, false, NULL, &DummyIndex, 0, 0); // connect tree nodes - BTGraphHelpers::CreateChildren(BTAsset, BTAsset->RootNode, RootEdNode, &ExecutionIndex, TreeDepth + 1); + BTGraphHelpers::CreateChildren(BTAsset, BTAsset->RootNode, RootEdNode, &ExecutionIndex, TreeDepth + 1); //-V595 // mark root level nodes BTGraphHelpers::ClearRootLevelFlags(this); diff --git a/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeGraphNode.cpp b/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeGraphNode.cpp index 8d16117849fb..3ee7475bbe79 100644 --- a/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeGraphNode.cpp +++ b/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeGraphNode.cpp @@ -44,8 +44,8 @@ UBehaviorTreeGraphNode::UBehaviorTreeGraphNode(const FObjectInitializer& ObjectI void UBehaviorTreeGraphNode::AllocateDefaultPins() { - CreatePin(EGPD_Input, UBehaviorTreeEditorTypes::PinCategory_MultipleNodes, TEXT(""), NULL, false, false, TEXT("In")); - CreatePin(EGPD_Output, UBehaviorTreeEditorTypes::PinCategory_MultipleNodes, TEXT(""), NULL, false, false, TEXT("Out")); + CreatePin(EGPD_Input, UBehaviorTreeEditorTypes::PinCategory_MultipleNodes, FString(), nullptr, TEXT("In")); + CreatePin(EGPD_Output, UBehaviorTreeEditorTypes::PinCategory_MultipleNodes, FString(), nullptr, TEXT("Out")); } void UBehaviorTreeGraphNode::InitializeInstance() diff --git a/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeGraphNode_Root.cpp b/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeGraphNode_Root.cpp index 43c77f5efc1a..df48e1176100 100644 --- a/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeGraphNode_Root.cpp +++ b/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeGraphNode_Root.cpp @@ -31,7 +31,7 @@ void UBehaviorTreeGraphNode_Root::PostPlacedNewNode() void UBehaviorTreeGraphNode_Root::AllocateDefaultPins() { - CreatePin(EGPD_Output, UBehaviorTreeEditorTypes::PinCategory_SingleComposite, TEXT(""), NULL, false, false, TEXT("In")); + CreatePin(EGPD_Output, UBehaviorTreeEditorTypes::PinCategory_SingleComposite, FString(), nullptr, TEXT("In")); } FText UBehaviorTreeGraphNode_Root::GetNodeTitle(ENodeTitleType::Type TitleType) const diff --git a/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeGraphNode_SimpleParallel.cpp b/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeGraphNode_SimpleParallel.cpp index cd7d8d13708d..32932cf2d8da 100644 --- a/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeGraphNode_SimpleParallel.cpp +++ b/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeGraphNode_SimpleParallel.cpp @@ -11,10 +11,10 @@ UBehaviorTreeGraphNode_SimpleParallel::UBehaviorTreeGraphNode_SimpleParallel(con void UBehaviorTreeGraphNode_SimpleParallel::AllocateDefaultPins() { - CreatePin(EGPD_Input, UBehaviorTreeEditorTypes::PinCategory_MultipleNodes, TEXT(""), NULL, false, false, TEXT("In")); + CreatePin(EGPD_Input, UBehaviorTreeEditorTypes::PinCategory_MultipleNodes, FString(), nullptr, TEXT("In")); - CreatePin(EGPD_Output, UBehaviorTreeEditorTypes::PinCategory_SingleTask, TEXT(""), NULL, false, false, TEXT("Task")); - CreatePin(EGPD_Output, UBehaviorTreeEditorTypes::PinCategory_SingleNode, TEXT(""), NULL, false, false, TEXT("Out")); + CreatePin(EGPD_Output, UBehaviorTreeEditorTypes::PinCategory_SingleTask, FString(), nullptr, TEXT("Task")); + CreatePin(EGPD_Output, UBehaviorTreeEditorTypes::PinCategory_SingleNode, FString(), nullptr, TEXT("Out")); } void UBehaviorTreeGraphNode_SimpleParallel::GetPinHoverText(const UEdGraphPin& Pin, FString& HoverTextOut) const diff --git a/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeGraphNode_Task.cpp b/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeGraphNode_Task.cpp index c4f4019215b9..491b90100718 100644 --- a/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeGraphNode_Task.cpp +++ b/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeGraphNode_Task.cpp @@ -10,7 +10,7 @@ UBehaviorTreeGraphNode_Task::UBehaviorTreeGraphNode_Task(const FObjectInitialize void UBehaviorTreeGraphNode_Task::AllocateDefaultPins() { - CreatePin(EGPD_Input, UBehaviorTreeEditorTypes::PinCategory_SingleComposite, TEXT(""), NULL, false, false, TEXT("In")); + CreatePin(EGPD_Input, UBehaviorTreeEditorTypes::PinCategory_SingleComposite, FString(), nullptr, TEXT("In")); } FText UBehaviorTreeGraphNode_Task::GetNodeTitle(ENodeTitleType::Type TitleType) const diff --git a/Engine/Source/Editor/BehaviorTreeEditor/Private/SBehaviorTreeBlackboardView.cpp b/Engine/Source/Editor/BehaviorTreeEditor/Private/SBehaviorTreeBlackboardView.cpp index 6fc9b15b0c02..9e4267a830d7 100644 --- a/Engine/Source/Editor/BehaviorTreeEditor/Private/SBehaviorTreeBlackboardView.cpp +++ b/Engine/Source/Editor/BehaviorTreeEditor/Private/SBehaviorTreeBlackboardView.cpp @@ -147,7 +147,7 @@ private: } } - virtual TSharedRef CreateTextSlotWidget( const FSlateFontInfo& NameFont, FCreateWidgetForActionData* const InCreateData, bool bInIsReadOnly ) override + virtual TSharedRef CreateTextSlotWidget( const FSlateFontInfo& NameFont, FCreateWidgetForActionData* const InCreateData, TAttribute bInIsReadOnly ) override { check(InCreateData); @@ -160,7 +160,7 @@ private: } // If the creation data says read only, then it must be read only - bIsReadOnly = InCreateData->bIsReadOnly || bInIsReadOnly; + bIsReadOnly = InCreateData->bIsReadOnly || bInIsReadOnly.Get(); InlineRenameWidget = SAssignNew(DisplayWidget, SInlineEditableTextBlock) @@ -173,10 +173,7 @@ private: .IsSelected( InCreateData->IsRowSelectedDelegate ) .IsReadOnly(this, &SBehaviorTreeBlackboardItem::IsReadOnly); - if(!bIsReadOnly) - { - InCreateData->OnRenameRequest->BindSP( InlineRenameWidget.Get(), &SInlineEditableTextBlock::EnterEditingMode ); - } + InCreateData->OnRenameRequest->BindSP( InlineRenameWidget.Get(), &SInlineEditableTextBlock::EnterEditingMode ); return DisplayWidget.ToSharedRef(); } diff --git a/Engine/Source/Editor/BlueprintGraph/Classes/EdGraphSchema_K2.h b/Engine/Source/Editor/BlueprintGraph/Classes/EdGraphSchema_K2.h index 821a00bad663..35a39f3f93e1 100644 --- a/Engine/Source/Editor/BlueprintGraph/Classes/EdGraphSchema_K2.h +++ b/Engine/Source/Editor/BlueprintGraph/Classes/EdGraphSchema_K2.h @@ -119,6 +119,12 @@ public: /** UPROPERTY will be exposed on "Spawn Blueprint" nodes as an input */ static const FName MD_ExposeOnSpawn; + /** UPROPERTY uses the specified function as a getter rather than reading from the property directly */ + static const FName MD_PropertyGetFunction; + + /** UPROPERTY uses the specified function as a setter rather than writing to the property directly */ + static const FName MD_PropertySetFunction; + /** UPROPERTY cannot be modified by other blueprints */ static const FName MD_Private; @@ -536,8 +542,11 @@ public: If the CompilerContext is specified this will be created as an intermediate node */ class UK2Node* CreateSplitPinNode(UEdGraphPin* Pin, class FKismetCompilerContext* CompilerContext = NULL, UEdGraph* SourceGraph = NULL) const; - // Do validation, that doesn't require a knowledge about actual pin. - virtual bool DefaultValueSimpleValidation(const FEdGraphPinType& PinType, const FString& PinName, const FString& NewDefaultValue, UObject* NewDefaultObject, const FText& InText, FString* OutMsg = NULL) const; + /** Reads in a FString and gets the values of the pin defaults for that type. This can be passed to DefaultValueSimpleValidation to validate. OwningObject can be null */ + virtual void GetPinDefaultValuesFromString(const FEdGraphPinType& PinType, UObject* OwningObject, const FString& NewValue, FString& UseDefaultValue, UObject*& UseDefaultObject, FText& UseDefaultText) const; + + /** Do validation, that doesn't require a knowledge about actual pin */ + virtual bool DefaultValueSimpleValidation(const FEdGraphPinType& PinType, const FString& PinName, const FString& NewDefaultValue, UObject* NewDefaultObject, const FText& InText, FString* OutMsg = nullptr) const; /** Returns true if the owning node is a function with AutoCreateRefTerm meta data */ bool IsAutoCreateRefTerm(const UEdGraphPin* Pin) const; @@ -551,7 +560,7 @@ public: * @param TestEdGraph Graph to test * @return true if this is a construction script */ - bool IsConstructionScript(const UEdGraph* TestEdGraph) const; + static bool IsConstructionScript(const UEdGraph* TestEdGraph); /** * Checks to see if the specified graph is a composite graph @@ -584,7 +593,7 @@ public: * @param Pin The pin to check. * @return true if it is an execution pin. */ - inline bool IsExecPin(const UEdGraphPin& Pin) const + static inline bool IsExecPin(const UEdGraphPin& Pin) { return Pin.PinType.PinCategory == PC_Exec; } @@ -605,7 +614,7 @@ public: */ inline bool IsMetaPin(const UEdGraphPin& Pin) const { - return IsSelfPin(Pin) || IsExecPin(Pin); + return IsExecPin(Pin) || IsSelfPin(Pin); } /** Is given string a delegate category name ? */ @@ -614,7 +623,7 @@ public: /** Returns whether a pin category is compatible with an Index Wildcard (PC_Wildcard and PSC_Index) */ inline bool IsIndexWildcardCompatible(const FEdGraphPinType& PinType) const { - return (!PinType.bIsArray) && + return (!PinType.IsContainer()) && ( PinType.PinCategory == PC_Boolean || PinType.PinCategory == PC_Int || @@ -695,6 +704,9 @@ public: */ bool ConvertPropertyToPinType(const UProperty* Property, /*out*/ FEdGraphPinType& TypeOut) const; + /** Determines if the specified param property is intended to be used as a wildcard (for custom thunk functions, like in our array library, etc.)*/ + static bool IsWildcardProperty(const UProperty* ParamProperty); + /** Flags to indicate different types of blueprint callable functions */ enum EFunctionType { @@ -940,14 +952,30 @@ public: */ virtual bool ArePinTypesCompatible(const FEdGraphPinType& Output, const FEdGraphPinType& Input, const UClass* CallingContext = NULL, bool bIgnoreArray = false) const; - // Sets the Pin default property potentially using the default value set in metadata of the param - virtual void SetPinDefaultValue(UEdGraphPin* Pin, const UFunction* Function = NULL, const UProperty* Param = NULL) const; + /** Sets the autogenerated default value for a pin, optionally using the passed in function and parameter. This will also reset the current default value to the autogenerated one */ + virtual void SetPinAutogeneratedDefaultValue(UEdGraphPin* Pin, const FString& NewValue) const; - /** - * Sets the default value of a pin based on the type of the pin (0 for int, false for boolean, etc...) - */ + /** Sets the autogenerated default value for a pin using the default for that type. This will also reset the current default value to the autogenerated one */ + virtual void SetPinAutogeneratedDefaultValueBasedOnType(UEdGraphPin* Pin) const; + + /** Resets a pin back to it's autogenerated default value, optionally calling the default value change callbacks */ + virtual void ResetPinToAutogeneratedDefaultValue(UEdGraphPin* Pin, bool bCallModifyCallbacks = true) const; + + /** Sets the pin defaults, but not autogenerated defaults, at pin construction time. This is like TrySetDefaultValue but does not do validation or callbacks */ + virtual void SetPinDefaultValueAtConstruction(UEdGraphPin* Pin, const FString& DefaultValueString) const; + + /** Call to let blueprint and UI know that parameters have changed for a function/macro/etc */ + virtual void HandleParameterDefaultValueChanged(UK2Node* TargetNode) const; + + DEPRECATED(4.17, "SetPinDefaultValue is deprecated due to confusing name, call SetPinAutogeneratedDefaultValue") + virtual void SetPinDefaultValue(UEdGraphPin* Pin, const UFunction* Function = nullptr, const UProperty* Param = nullptr) const; + + DEPRECATED(4.17, "SetPinDefaultValueBasedOnType is deprecated due to confusing name, call SetPinAutogeneratedDefaultValue") virtual void SetPinDefaultValueBasedOnType(UEdGraphPin* Pin) const; + /** Given a function and property, return the default value */ + static bool FindFunctionParameterDefaultValue(const UFunction* Function, const UProperty* Param, FString& OutString); + /** Utility that makes sure existing connections are valid, breaking any that are now illegal. */ static void ValidateExistingConnections(UEdGraphPin* Pin); @@ -1065,6 +1093,7 @@ public: static void GetReplaceVariableMenu(class FMenuBuilder& MenuBuilder, class UK2Node_Variable* Variable, UBlueprint* OwnerBlueprint, bool bReplaceExistingVariable = false); private: + /** * Returns true if the specified function has any out parameters * @param [in] Function The function to check for out parameters diff --git a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node.h b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node.h index 5dec8806b165..3eab7660f7fe 100644 --- a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node.h +++ b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node.h @@ -43,44 +43,44 @@ struct FOptionalPinFromProperty { GENERATED_USTRUCT_BODY() - UPROPERTY(EditAnywhere, Category= OptionalPin, BlueprintReadOnly) + UPROPERTY(EditAnywhere, Category= OptionalPin) FName PropertyName; - UPROPERTY(EditAnywhere, Category= OptionalPin, BlueprintReadOnly) + UPROPERTY(EditAnywhere, Category= OptionalPin) FString PropertyFriendlyName; - UPROPERTY(EditAnywhere, Category= OptionalPin, BlueprintReadOnly) + UPROPERTY(EditAnywhere, Category= OptionalPin) FText PropertyTooltip; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=OptionalPin) - bool bShowPin; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=OptionalPin) - bool bCanToggleVisibility; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=OptionalPin) - bool bPropertyIsCustomized; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=OptionalPin) + UPROPERTY(EditAnywhere, Category=OptionalPin) FName CategoryName; UPROPERTY(EditAnywhere, Category=OptionalPin) - bool bHasOverridePin; + uint8 bShowPin:1; UPROPERTY(EditAnywhere, Category=OptionalPin) - bool bIsMarkedForAdvancedDisplay; + uint8 bCanToggleVisibility:1; + + UPROPERTY(EditAnywhere, Category=OptionalPin) + uint8 bPropertyIsCustomized:1; + + UPROPERTY(EditAnywhere, Category=OptionalPin) + uint8 bHasOverridePin:1; + + UPROPERTY(EditAnywhere, Category=OptionalPin) + uint8 bIsMarkedForAdvancedDisplay:1; /** TRUE if the override value is enabled for use */ UPROPERTY(EditAnywhere, Category = OptionalPin) - bool bIsOverrideEnabled; + uint8 bIsOverrideEnabled:1; /** TRUE if the override value should be set through this pin */ UPROPERTY(EditAnywhere, Category = OptionalPin) - bool bIsSetValuePinVisible; + uint8 bIsSetValuePinVisible:1; /** TRUE if the override pin is visible */ UPROPERTY(EditAnywhere, Category = OptionalPin) - bool bIsOverridePinVisible; + uint8 bIsOverridePinVisible:1; FOptionalPinFromProperty() : bIsMarkedForAdvancedDisplay(false) @@ -96,10 +96,10 @@ struct FOptionalPinFromProperty #if WITH_EDITORONLY_DATA , PropertyTooltip(InTooltip) #endif + , CategoryName(InCategoryName) , bShowPin(bInShowPin) , bCanToggleVisibility(bInCanToggleVisibility) , bPropertyIsCustomized(bInPropertyIsCustomized) - , CategoryName(InCategoryName) , bHasOverridePin(bInHasOverridePin) , bIsMarkedForAdvancedDisplay(false) , bIsOverrideEnabled(true) @@ -113,26 +113,38 @@ struct FOptionalPinFromProperty struct BLUEPRINTGRAPH_API FOptionalPinManager { public: - // Should the specified property be displayed by default + virtual ~FOptionalPinManager() { } + + /** Should the specified property be displayed by default */ virtual void GetRecordDefaults(UProperty* TestProperty, FOptionalPinFromProperty& Record) const; - // Can this property be managed as an optional pin (with the ability to be shown or hidden) + /** Can this property be managed as an optional pin (with the ability to be shown or hidden) */ virtual bool CanTreatPropertyAsOptional(UProperty* TestProperty) const; - // Reconstructs the specified property array using the SourceStruct - // @param [in,out] Properties The property array - // @param SourceStruct The source structure to update the properties array from - // @param bDefaultVisibility + /** + * Reconstructs the specified property array using the SourceStruct + * @param [in,out] Properties The property array + * @param SourceStruct The source structure to update the properties array from + * @param bDefaultVisibility + */ void RebuildPropertyList(TArray& Properties, UStruct* SourceStruct); - // Creates a pin for each visible property on the specified node - void CreateVisiblePins(TArray& Properties, UStruct* SourceStruct, EEdGraphPinDirection Direction, class UK2Node* TargetNode, uint8* StructBasePtr = NULL); + /** + * Creates a pin for each visible property on the specified node + * @param Properties The property array + * @param SourceStruct The source structure to update the properties array from + * @param Direction Direction of pins to create + * @param TargetNode Node to generate pins for + * @param StructBasePtr Struct that is iterated over, to represent the current version of the data + * @param DefaultsPtr Struct that is iterated over, to represent the default version of the data, used for delta serialization + */ + void CreateVisiblePins(TArray& Properties, UStruct* SourceStruct, EEdGraphPinDirection Direction, class UK2Node* TargetNode, uint8* StructBasePtr = nullptr, uint8* DefaultsPtr = nullptr); // Customize automatically created pins if desired virtual void CustomizePinData(UEdGraphPin* Pin, FName SourcePropertyName, int32 ArrayIndex, UProperty* Property = NULL) const {} protected: - virtual void PostInitNewPin(UEdGraphPin* Pin, FOptionalPinFromProperty& Record, int32 ArrayIndex, UProperty* Property, uint8* PropertyAddress) const {} - virtual void PostRemovedOldPin(FOptionalPinFromProperty& Record, int32 ArrayIndex, UProperty* Property, uint8* PropertyAddress) const {} + virtual void PostInitNewPin(UEdGraphPin* Pin, FOptionalPinFromProperty& Record, int32 ArrayIndex, UProperty* Property, uint8* PropertyAddress, uint8* DefaultPropertyAddress) const {} + virtual void PostRemovedOldPin(FOptionalPinFromProperty& Record, int32 ArrayIndex, UProperty* Property, uint8* PropertyAddress, uint8* DefaultPropertyAddress) const {} void RebuildProperty(UProperty* TestProperty, FName CategoryName, TArray& Properties, UStruct* SourceStruct, TMap& OldSettings); }; diff --git a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_Composite.h b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_Composite.h index 8cdd9a7a901d..e6418cb412f0 100644 --- a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_Composite.h +++ b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_Composite.h @@ -9,8 +9,8 @@ class INameValidatorInterface; -UCLASS(MinimalAPI) -class UK2Node_Composite : public UK2Node_Tunnel +UCLASS() +class BLUEPRINTGRAPH_API UK2Node_Composite : public UK2Node_Tunnel { GENERATED_UCLASS_BODY() @@ -23,15 +23,15 @@ class UK2Node_Composite : public UK2Node_Tunnel //~ End UObject Interface //~ Begin UEdGraphNode Interface - BLUEPRINTGRAPH_API virtual void AllocateDefaultPins() override; - BLUEPRINTGRAPH_API virtual void DestroyNode() override; - BLUEPRINTGRAPH_API virtual void PostPasteNode() override; - BLUEPRINTGRAPH_API virtual FText GetTooltipText() const override; - BLUEPRINTGRAPH_API virtual FLinearColor GetNodeTitleColor() const override; - BLUEPRINTGRAPH_API virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override; - BLUEPRINTGRAPH_API virtual bool CanUserDeleteNode() const override; - BLUEPRINTGRAPH_API virtual UObject* GetJumpTargetForDoubleClick() const override; - BLUEPRINTGRAPH_API virtual void PostPlacedNewNode() override; + virtual void AllocateDefaultPins() override; + virtual void DestroyNode() override; + virtual void PostPasteNode() override; + virtual FText GetTooltipText() const override; + virtual FLinearColor GetNodeTitleColor() const override; + virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override; + virtual bool CanUserDeleteNode() const override; + virtual UObject* GetJumpTargetForDoubleClick() const override; + virtual void PostPlacedNewNode() override; virtual void OnRenameNode(const FString& NewName) override; virtual TSharedPtr MakeNameValidator() const override; //~ End UEdGraphNode Interface @@ -43,8 +43,8 @@ class UK2Node_Composite : public UK2Node_Tunnel //~ End UK2Node Interface // Get the entry/exit nodes inside this collapsed graph - BLUEPRINTGRAPH_API UK2Node_Tunnel* GetEntryNode() const; - BLUEPRINTGRAPH_API UK2Node_Tunnel* GetExitNode() const; + UK2Node_Tunnel* GetEntryNode() const; + UK2Node_Tunnel* GetExitNode() const; protected: /** Fixes up the input and output sink when needed, useful after PostEditUndo which changes which graph these nodes point to */ diff --git a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_ConvertAsset.h b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_ConvertAsset.h index 925ec595d05b..b6b7079cabea 100644 --- a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_ConvertAsset.h +++ b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_ConvertAsset.h @@ -18,12 +18,17 @@ class UK2Node_ConvertAsset : public UK2Node GENERATED_BODY() public: + /** Returns the class for the object being converted */ UClass* GetTargetClass() const; + /** True if this is converting an Asset Class, false for Asset Id */ bool IsAssetClassType() const; + /** True if this is going from object to asset, false for default of asset to object */ + bool IsConvertToAsset() const; // UEdGraphNode interface virtual void AllocateDefaultPins() override; virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override; + virtual FText GetKeywords() const override; virtual FText GetTooltipText() const override; // End of UEdGraphNode interface @@ -40,6 +45,7 @@ public: virtual void NotifyPinConnectionListChanged(UEdGraphPin* Pin) override; virtual void GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const override; virtual FText GetMenuCategory() const override; + virtual ERedirectType DoPinsMatchForReconstruction(const UEdGraphPin* NewPin, int32 NewPinIndex, const UEdGraphPin* OldPin, int32 OldPinIndex) const override; // End of UK2Node interface protected: diff --git a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_CustomEvent.h b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_CustomEvent.h index aae11e5fe202..0c3cfa9d7fdc 100644 --- a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_CustomEvent.h +++ b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_CustomEvent.h @@ -52,6 +52,7 @@ class UK2Node_CustomEvent : public UK2Node_Event //~ Begin UK2Node_EditablePinBase Interface virtual UEdGraphPin* CreatePinFromUserDefinition(const TSharedPtr NewPinInfo) override; virtual bool CanCreateUserDefinedPin(const FEdGraphPinType& InPinType, EEdGraphPinDirection InDesiredDirection, FText& OutErrorMessage) override; + virtual bool ModifyUserDefinedPinDefaultValue(TSharedPtr PinInfo, const FString& NewDefaultValue) override; //~ Begin UK2Node_EditablePinBase Interface virtual bool IsUsedByAuthorityOnlyDelegate() const override; diff --git a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_EditablePinBase.h b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_EditablePinBase.h index c1f69b77e396..e6fa6ec806f0 100644 --- a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_EditablePinBase.h +++ b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_EditablePinBase.h @@ -33,31 +33,8 @@ struct FUserPinInfo UPROPERTY() FString PinDefaultValue; - friend FArchive& operator <<(FArchive& Ar, FUserPinInfo& Info) - { - Ar << Info.PinName; + friend FArchive& operator <<(FArchive& Ar, FUserPinInfo& Info); - if (Ar.UE4Ver() >= VER_UE4_SERIALIZE_PINTYPE_CONST) - { - Info.PinType.Serialize(Ar); - Ar << Info.DesiredPinDirection; - } - else - { - Ar << Info.PinType.bIsArray; - Ar << Info.PinType.bIsReference; - - Ar << Info.PinType.PinCategory; - Ar << Info.PinType.PinSubCategory; - - Ar << Info.PinType.PinSubCategoryObject; - } - - Ar << Info.PinDefaultValue; - - return Ar; - } - }; // This structure describes metadata associated with a user declared function or macro @@ -120,6 +97,7 @@ class UK2Node_EditablePinBase : public UK2Node // UEdGraphNode interface BLUEPRINTGRAPH_API virtual void AllocateDefaultPins() override; + BLUEPRINTGRAPH_API virtual void PinDefaultValueChanged(UEdGraphPin* Pin) override; // End of UEdGraphNode interface // UK2Node interface diff --git a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_FunctionEntry.h b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_FunctionEntry.h index 72b914abe02a..3e525d745c57 100644 --- a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_FunctionEntry.h +++ b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_FunctionEntry.h @@ -5,6 +5,7 @@ #include "CoreMinimal.h" #include "UObject/ObjectMacros.h" #include "K2Node_FunctionTerminator.h" +#include "Engine/Blueprint.h" #include "K2Node_FunctionEntry.generated.h" class UEdGraph; @@ -24,7 +25,7 @@ class UK2Node_FunctionEntry : public UK2Node_FunctionTerminator /** Array of local variables to be added to generated function */ UPROPERTY() - TArray LocalVariables; + TArray LocalVariables; /** Whether or not to enforce const-correctness for const function overrides */ UPROPERTY() @@ -53,6 +54,7 @@ class UK2Node_FunctionEntry : public UK2Node_FunctionTerminator //~ Begin UK2Node_EditablePinBase Interface virtual bool CanUseRefParams() const override { return true; } + virtual bool ModifyUserDefinedPinDefaultValue(TSharedPtr PinInfo, const FString& NewDefaultValue) override; //~ End UK2Node_EditablePinBase Interface //~ Begin K2Node_FunctionTerminator Interface diff --git a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_GenericCreateObject.h b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_GenericCreateObject.h index c019c964d2a7..d1363c433500 100644 --- a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_GenericCreateObject.h +++ b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_GenericCreateObject.h @@ -16,7 +16,6 @@ class BLUEPRINTGRAPH_API UK2Node_GenericCreateObject : public UK2Node_ConstructO //~ Begin UEdGraphNode Interface. virtual void ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) override; - virtual void ValidateNodeDuringCompilation(class FCompilerResultsLog& MessageLog) const override; virtual void EarlyValidation(class FCompilerResultsLog& MessageLog) const override; virtual bool IsCompatibleWithGraph(const UEdGraph* TargetGraph) const override; //~ End UEdGraphNode Interface. diff --git a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_LoadAsset.h b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_LoadAsset.h index 917cb585e0d6..faae54d0a113 100644 --- a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_LoadAsset.h +++ b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_LoadAsset.h @@ -30,6 +30,7 @@ public: virtual void GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const override; virtual FText GetMenuCategory() const override; virtual bool NodeCausesStructuralBlueprintChange() const { return true; } + virtual void ReallocatePinsDuringReconstruction(TArray& OldPins) override; // End of UK2Node interface protected: diff --git a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_StructOperation.h b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_StructOperation.h index 79c0d5c582cc..a28035d9c682 100644 --- a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_StructOperation.h +++ b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_StructOperation.h @@ -25,8 +25,8 @@ class UK2Node_StructOperation : public UK2Node_Variable //~ Begin UK2Node Interface //virtual bool DrawNodeAsVariable() const override { return true; } virtual bool ShouldShowNodeProperties() const override { return true; } - virtual void ValidateNodeDuringCompilation(class FCompilerResultsLog& MessageLog) const override {} - virtual bool HasExternalDependencies(TArray* OptionalOutput = NULL) const override; + virtual void ValidateNodeDuringCompilation(class FCompilerResultsLog& MessageLog) const override; + virtual bool HasExternalDependencies(TArray* OptionalOutput = nullptr) const override; virtual FString GetFindReferenceSearchString() const override; virtual bool IsActionFilteredOut(class FBlueprintActionFilter const& Filter) override; //~ End UK2Node Interface diff --git a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_Switch.h b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_Switch.h index 872fcf3b1e3c..0ace489bee5f 100644 --- a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_Switch.h +++ b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_Switch.h @@ -67,6 +67,9 @@ class UK2Node_Switch : public UK2Node */ BLUEPRINTGRAPH_API virtual void RemovePinFromSwitchNode(UEdGraphPin* TargetPin); + /** Whether an execution pin can be removed from the node or not */ + BLUEPRINTGRAPH_API virtual bool CanRemoveExecutionPin(UEdGraphPin* TargetPin) const; + /** Getting pin access */ BLUEPRINTGRAPH_API UEdGraphPin* GetSelectionPin() const; BLUEPRINTGRAPH_API UEdGraphPin* GetDefaultPin() const; diff --git a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_SwitchInteger.h b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_SwitchInteger.h index 377403ce50a7..8db6808fa625 100644 --- a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_SwitchInteger.h +++ b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_SwitchInteger.h @@ -39,6 +39,7 @@ class UK2Node_SwitchInteger : public UK2Node_Switch virtual FString GetPinNameGivenIndex(int32 Index) override; virtual void ReallocatePinsDuringReconstruction(TArray& OldPins) override; virtual FEdGraphPinType GetPinType() const override; + virtual bool CanRemoveExecutionPin(UEdGraphPin* TargetPin) const override; // End of UK2Node_Switch Interface protected: diff --git a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_SwitchString.h b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_SwitchString.h index 41f037ce373a..18124b2d76f9 100644 --- a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_SwitchString.h +++ b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_SwitchString.h @@ -30,6 +30,7 @@ class UK2Node_SwitchString : public UK2Node_Switch virtual FText GetTooltipText() const override; virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override; virtual bool ShouldShowNodeProperties() const override { return true; } + virtual void ValidateNodeDuringCompilation(class FCompilerResultsLog& MessageLog) const override; // End of UEdGraphNode interface // UK2Node interface diff --git a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_Tunnel.h b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_Tunnel.h index d5e5d2316d7c..02a7179b2fa0 100644 --- a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_Tunnel.h +++ b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_Tunnel.h @@ -7,8 +7,8 @@ #include "K2Node_EditablePinBase.h" #include "K2Node_Tunnel.generated.h" -UCLASS(MinimalAPI) -class UK2Node_Tunnel : public UK2Node_EditablePinBase +UCLASS() +class BLUEPRINTGRAPH_API UK2Node_Tunnel : public UK2Node_EditablePinBase { GENERATED_UCLASS_BODY() @@ -42,25 +42,26 @@ class UK2Node_Tunnel : public UK2Node_EditablePinBase virtual FText GetTooltipText() const override; virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override; virtual bool CanUserDeleteNode() const override; - BLUEPRINTGRAPH_API virtual bool CanDuplicateNode() const override; + virtual bool CanDuplicateNode() const override; virtual UObject* GetJumpTargetForDoubleClick() const override; virtual FString CreateUniquePinName(FString SourcePinName) const override; virtual void ReallocatePinsDuringReconstruction(TArray& OldPins) override; //~ End UEdGraphNode Interface //~ Begin UK2Node Interface. - BLUEPRINTGRAPH_API virtual bool IsNodeSafeToIgnore() const override; + virtual bool IsNodeSafeToIgnore() const override; virtual bool DrawNodeAsEntry() const override; virtual bool DrawNodeAsExit() const override; virtual bool NodeCausesStructuralBlueprintChange() const override { return true; } //~ End UK2Node Interface //~ Begin UK2Node_EditablePinBase Interface. - BLUEPRINTGRAPH_API virtual UEdGraphPin* CreatePinFromUserDefinition(const TSharedPtr NewPinInfo) override; - BLUEPRINTGRAPH_API virtual bool CanModifyExecutionWires() override; - BLUEPRINTGRAPH_API virtual ERenamePinResult RenameUserDefinedPin(const FString& OldName, const FString& NewName, bool bTest = false) override; + virtual UEdGraphPin* CreatePinFromUserDefinition(const TSharedPtr NewPinInfo) override; + virtual bool CanModifyExecutionWires() override; + virtual ERenamePinResult RenameUserDefinedPin(const FString& OldName, const FString& NewName, bool bTest = false) override; virtual bool CanUseRefParams() const override { return true; } virtual bool CanCreateUserDefinedPin(const FEdGraphPinType& InPinType, EEdGraphPinDirection InDesiredDirection, FText& OutErrorMessage) override; + virtual bool ModifyUserDefinedPinDefaultValue(TSharedPtr PinInfo, const FString& NewDefaultValue) override; //~ End UK2Node_EditablePinBase Interface protected: @@ -72,10 +73,10 @@ protected: virtual void PostFixupAllWildcardPins(bool bInAllWildcardPinsUnlinked) {} public: // The input pins of this tunnel go to the output pins of InputSinkNode (can be NULL). - BLUEPRINTGRAPH_API virtual UK2Node_Tunnel* GetInputSink() const; + virtual UK2Node_Tunnel* GetInputSink() const; // The output pins of this tunnel node came from the input pins of OutputSourceNode (can be NULL). - BLUEPRINTGRAPH_API virtual UK2Node_Tunnel* GetOutputSource() const; + virtual UK2Node_Tunnel* GetOutputSource() const; }; diff --git a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_TunnelBoundary.h b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_TunnelBoundary.h index 42814691555e..262d8d65532d 100644 --- a/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_TunnelBoundary.h +++ b/Engine/Source/Editor/BlueprintGraph/Classes/K2Node_TunnelBoundary.h @@ -65,10 +65,10 @@ protected: void WireUpTunnelExit(UK2Node_Tunnel* TunnelInstance, UEdGraphPin* TunnelPin, FCompilerResultsLog& MessageLog); /** Wires up the entry boundries */ - void WireUpEntry(UEdGraphNode* SourceNode, UEdGraphPin* SourcePin, TArray& EntryPins, FCompilerResultsLog& MessageLog); + void WireUpEntry(UEdGraphNode* SourceNode, UEdGraphPin* SourcePin, const TArray& EntryPins, FCompilerResultsLog& MessageLog); /** Wires up the exit boundries */ - void WireUpExit(UEdGraphNode* SourceNode, UEdGraphPin* SourcePin, TArray& ExitPins, FCompilerResultsLog& MessageLog); + void WireUpExit(UEdGraphNode* SourceNode, UEdGraphPin* SourcePin, const TArray& ExitPins, FCompilerResultsLog& MessageLog); /** Create base node name */ void CreateBaseNodeName(UEdGraphNode* SourceNode); diff --git a/Engine/Source/Editor/BlueprintGraph/Private/BasicTokenParser.cpp b/Engine/Source/Editor/BlueprintGraph/Private/BasicTokenParser.cpp index b4c8a2fe5cb6..9ec0892fc286 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/BasicTokenParser.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/BasicTokenParser.cpp @@ -40,19 +40,19 @@ void FBasicToken::Clone(const FBasicToken& Other) } //------------------------------------------------------------------------------ -bool FBasicToken::Matches(TCHAR const* Str, ESearchCase::Type SearchCase) const +bool FBasicToken::Matches(const TCHAR* Str, ESearchCase::Type SearchCase) const { return (TokenType==TOKEN_Identifier || TokenType==TOKEN_Symbol) && ((SearchCase == ESearchCase::CaseSensitive) ? !FCString::Strcmp(Identifier, Str) : !FCString::Stricmp(Identifier, Str)); } //------------------------------------------------------------------------------ -bool FBasicToken::Matches(FName const& Name) const +bool FBasicToken::Matches(const FName& Name) const { return TokenType==TOKEN_Identifier && TokenName==Name; } //------------------------------------------------------------------------------ -bool FBasicToken::StartsWith(TCHAR const* Str, bool bCaseSensitive) const +bool FBasicToken::StartsWith(const TCHAR* Str, bool bCaseSensitive) const { const int32 StrLength = FCString::Strlen(Str); return (TokenType==TOKEN_Identifier || TokenType==TOKEN_Symbol) && (bCaseSensitive ? (!FCString::Strncmp(Identifier, Str, StrLength)) : (!FCString::Strnicmp(Identifier, Str, StrLength))); @@ -136,7 +136,7 @@ FString FBasicToken::GetConstantValue() const return String; // unsupported (parsing never produces a constant token of these types: - // CPT_Vector, ..., CPT_Int8, CPT_Int16, CPT_Int64, ..., CPT_Bool8, etc) + // ..., CPT_Int8, CPT_Int16, CPT_Int64, ..., CPT_Bool8, etc) default: return TEXT("InvalidTypeForAToken"); } @@ -284,7 +284,7 @@ namespace BasicTokenParserImpl } //------------------------------------------------------------------------------ -void FBasicTokenParser::ResetParser(TCHAR const* SourceBuffer, int32 StartingLineNumber) +void FBasicTokenParser::ResetParser(const TCHAR* SourceBuffer, int32 StartingLineNumber) { Input = SourceBuffer; InputLen = FCString::Strlen(Input); @@ -706,7 +706,7 @@ bool FBasicTokenParser::GetSymbol(FBasicToken& Token) } //------------------------------------------------------------------------------ -bool FBasicTokenParser::GetConstInt(int32& Result, TCHAR const* ErrorContext) +bool FBasicTokenParser::GetConstInt(int32& Result, const TCHAR* ErrorContext) { FBasicToken Token; if (GetToken(Token)) @@ -910,7 +910,7 @@ bool FBasicTokenParser::MatchIdentifier(FName Match) } //------------------------------------------------------------------------------ -bool FBasicTokenParser::MatchIdentifier(TCHAR const* Match) +bool FBasicTokenParser::MatchIdentifier(const TCHAR* Match) { FBasicToken Token; if (GetToken(Token)) @@ -953,7 +953,7 @@ bool FBasicTokenParser::PeekIdentifier(const TCHAR* Match) } //------------------------------------------------------------------------------ -bool FBasicTokenParser::MatchSymbol(TCHAR const* Match) +bool FBasicTokenParser::MatchSymbol(const TCHAR* Match) { FBasicToken Token; @@ -973,7 +973,7 @@ bool FBasicTokenParser::MatchSymbol(TCHAR const* Match) } //------------------------------------------------------------------------------ -bool FBasicTokenParser::PeekSymbol(TCHAR const* Match) +bool FBasicTokenParser::PeekSymbol(const TCHAR* Match) { FBasicToken Token; if (!GetToken(Token, true)) @@ -986,7 +986,7 @@ bool FBasicTokenParser::PeekSymbol(TCHAR const* Match) } //------------------------------------------------------------------------------ -bool FBasicTokenParser::RequireIdentifier(FName Match, TCHAR const* ErrorContext) +bool FBasicTokenParser::RequireIdentifier(FName Match, const TCHAR* ErrorContext) { if (!MatchIdentifier(Match)) { @@ -997,7 +997,7 @@ bool FBasicTokenParser::RequireIdentifier(FName Match, TCHAR const* ErrorContext } //------------------------------------------------------------------------------ -bool FBasicTokenParser::RequireIdentifier(TCHAR const* Match, TCHAR const* ErrorContext) +bool FBasicTokenParser::RequireIdentifier(const TCHAR* Match, const TCHAR* ErrorContext) { if (!MatchIdentifier(Match)) { @@ -1008,7 +1008,7 @@ bool FBasicTokenParser::RequireIdentifier(TCHAR const* Match, TCHAR const* Error } //------------------------------------------------------------------------------ -bool FBasicTokenParser::RequireSymbol(TCHAR const* Match, TCHAR const* ErrorContext) +bool FBasicTokenParser::RequireSymbol(const TCHAR* Match, const TCHAR* ErrorContext) { if (!MatchSymbol(Match)) { diff --git a/Engine/Source/Editor/BlueprintGraph/Private/BasicTokenParser.h b/Engine/Source/Editor/BlueprintGraph/Private/BasicTokenParser.h index 05e7b7d59100..37294821f6b2 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/BasicTokenParser.h +++ b/Engine/Source/Editor/BlueprintGraph/Private/BasicTokenParser.h @@ -44,7 +44,7 @@ public: bool Matches(const TCHAR* Str, ESearchCase::Type SearchCase = ESearchCase::IgnoreCase) const; /** Determines if this token has the specified string as a prefix. */ - bool StartsWith( TCHAR const* Str, bool bCaseSensitive = false) const; + bool StartsWith(const TCHAR* Str, bool bCaseSensitive = false) const; /** Determines if this token has a boolean ConstantType.*/ bool IsBool() const; @@ -211,7 +211,7 @@ protected: * * @return True if a int was successfully processed, false otherwise. */ - bool GetConstInt(int32& Result, TCHAR const* ErrorContext = NULL); + bool GetConstInt(int32& Result, const TCHAR* ErrorContext = NULL); /** * Rolls back the line number and moves the parsing pointer back to where @@ -262,7 +262,7 @@ protected: * Determines if the next token in the stream is an identifier that matches * the specified string (and consumes it if it does). */ - bool MatchIdentifier(TCHAR const* Match); + bool MatchIdentifier(const TCHAR* Match); /** * Determines if the next token in the stream is an identifier that matches @@ -274,19 +274,19 @@ protected: * Determines if the next token in the stream is an identifier that matches * the specified string (does NOT consume it). */ - bool PeekIdentifier(TCHAR const* Match); + bool PeekIdentifier(const TCHAR* Match); /** * Determines if the next token in the stream is a symbol that matches * the specified string (and consumes it if it does). */ - bool MatchSymbol(TCHAR const* Match); + bool MatchSymbol(const TCHAR* Match); /** * Determines if the next token in the stream is a symbol that matches * the specified string (does NOT consume it). */ - bool PeekSymbol(TCHAR const* Match); + bool PeekSymbol(const TCHAR* Match); //-------------------------------------- // Requiring checks @@ -296,19 +296,19 @@ protected: * Ensures that the next token in the stream is an identifier that matches * the specified name (and errors out if it isn't). */ - bool RequireIdentifier(FName Match, TCHAR const* ErrorContext); + bool RequireIdentifier(FName Match, const TCHAR* ErrorContext); /** * Ensures that the next token in the stream is an identifier that matches * the specified string (and errors out if it isn't). */ - bool RequireIdentifier(TCHAR const* Match, TCHAR const* ErrorContext); + bool RequireIdentifier(const TCHAR* Match, const TCHAR* ErrorContext); /** * Ensures that the next token in the stream is a symbol that matches * the specified string (and errors out if it isn't). */ - bool RequireSymbol(TCHAR const* Match, TCHAR const* ErrorContext); + bool RequireSymbol(const TCHAR* Match, const TCHAR* ErrorContext); /** * Ensures that the next token in the stream is a semi-colon character (and @@ -381,7 +381,7 @@ protected: protected: /** Input text */ - TCHAR const* Input; + const TCHAR* Input; /** Length of input text */ int32 InputLen; diff --git a/Engine/Source/Editor/BlueprintGraph/Private/BlueprintActionDatabase.cpp b/Engine/Source/Editor/BlueprintGraph/Private/BlueprintActionDatabase.cpp index 36c40ca248c2..76163d8f98a3 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/BlueprintActionDatabase.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/BlueprintActionDatabase.cpp @@ -755,12 +755,7 @@ static void BlueprintActionDatabaseImpl::AddBlueprintGraphActions(UBlueprint con for (UK2Node_FunctionEntry* FunctionEntry : GraphEntryNodes) { - // Find the initial place where the function was defined, so we use the most generous scope UFunction* SkeletonFunction = FindField(Blueprint->SkeletonGeneratedClass, FunctionGraph->GetFName()); - for (UFunction* ParentFunction = SkeletonFunction; ParentFunction != nullptr; ParentFunction = ParentFunction->GetSuperFunction()) - { - SkeletonFunction = ParentFunction; - } // Create entries for function parameters if (SkeletonFunction != nullptr) diff --git a/Engine/Source/Editor/BlueprintGraph/Private/BlueprintActionFilter.cpp b/Engine/Source/Editor/BlueprintGraph/Private/BlueprintActionFilter.cpp index f269859c9df8..35d1a99b1f5c 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/BlueprintActionFilter.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/BlueprintActionFilter.cpp @@ -171,6 +171,16 @@ namespace BlueprintActionFilterImpl */ static bool IsDeprecated(FBlueprintActionFilter const& Filter, FBlueprintActionInfo& BlueprintAction); + /** + * Rejection test that checks to see if the supplied node-spawner would + * produce a node (or comes from an associated class) that is deprecated. + * + * @param Filter Filter context (unused) for this test. + * @param BlueprintAction The action you wish to query. + * @return True if the action would spawn a node that is deprecated. + */ + static bool IsPropertyAccessorNode(FBlueprintActionFilter const& Filter, FBlueprintActionInfo& BlueprintAction); + /** * Rejection test that checks to see if the supplied node-spawner would * produce an impure node, incompatible with the specified graphs. @@ -946,6 +956,19 @@ static bool BlueprintActionFilterImpl::IsActionHiddenByConfig(FBlueprintActionFi return bIsFilteredOut; } +//------------------------------------------------------------------------------ +static bool BlueprintActionFilterImpl::IsPropertyAccessorNode(FBlueprintActionFilter const& Filter, FBlueprintActionInfo& BlueprintAction) +{ + bool bIsAccessor = false; + + if (UFunction const* Function = BlueprintAction.GetAssociatedFunction()) + { + bIsAccessor = (Function->HasMetaData(FBlueprintMetadata::MD_PropertySetFunction) || Function->HasMetaData(FBlueprintMetadata::MD_PropertyGetFunction)); + } + + return bIsAccessor; +} + //------------------------------------------------------------------------------ static bool BlueprintActionFilterImpl::IsIncompatibleImpureNode(FBlueprintActionFilter const& Filter, FBlueprintActionInfo& BlueprintAction) { @@ -1260,7 +1283,7 @@ static bool BlueprintActionFilterImpl::IsPinCompatibleWithTargetSelf(UEdGraphPin if (IsClassOfType(PinObjClass, TargetClass)) { bIsCompatible = true; - if (PinType.bIsArray) + if (PinType.IsArray()) { if (UFunction const* Function = BlueprintAction.GetAssociatedFunction()) { @@ -1276,7 +1299,7 @@ static bool BlueprintActionFilterImpl::IsPinCompatibleWithTargetSelf(UEdGraphPin } } } - else if (!PinType.bIsArray && (BlueprintAction.GetNodeClass() == UK2Node_CallFunction::StaticClass())) + else if (!PinType.IsArray() && (BlueprintAction.GetNodeClass() == UK2Node_CallFunction::StaticClass())) { // if this is a bound CallFunction action, then we make the // assumption that it will be turned into a UK2Node_CallFunctionOnMember @@ -1359,7 +1382,7 @@ static bool BlueprintActionFilterImpl::ArrayFunctionHasParamOfType(const UFuncti FBlueprintEditorUtils::GetHiddenPinsForFunction(InGraph, ArrayFunction, HiddenPins); FName ParamTag = FBlueprintMetadata::MD_ArrayDependentParam; - if (DesiredPinType.bIsArray) + if (DesiredPinType.IsArray()) { ParamTag = FBlueprintMetadata::MD_ArrayParam; } @@ -1594,8 +1617,7 @@ static bool BlueprintActionFilterImpl::IsExtraneousInterfaceCall(FBlueprintActio UClass* InterfaceClass = Function->GetOwnerClass(); checkSlow(InterfaceClass->IsChildOf()); - bool const bIsAbstractCppClass = InterfaceClass->GetCppTypeInfo()->IsAbstract(); - bool const bCanBeAddedToBlueprints = !bIsAbstractCppClass && !InterfaceClass->HasMetaData(FBlueprintMetadata::MD_CannotImplementInterfaceInBlueprint); + bool const bCanBeAddedToBlueprints = !InterfaceClass->HasMetaData(FBlueprintMetadata::MD_CannotImplementInterfaceInBlueprint); bIsFilteredOut = (Filter.TargetClasses.Num() > 0); for (const auto& ClassData : Filter.TargetClasses) @@ -1762,7 +1784,7 @@ FBlueprintActionInfo::FBlueprintActionInfo(FBlueprintActionInfo const& Rhs, IBlu //------------------------------------------------------------------------------ UObject const* FBlueprintActionInfo::GetActionOwner() { - return ActionOwner; + return ActionOwner.Get(); } //------------------------------------------------------------------------------ @@ -1776,19 +1798,22 @@ UClass const* FBlueprintActionInfo::GetOwnerClass() { if ((CacheFlags & EBlueprintActionInfoFlags::CachedClass) == 0) { - CachedOwnerClass = Cast(ActionOwner); + CachedOwnerClass = Cast(ActionOwner.Get()); if (CachedOwnerClass == GetNodeClass()) { CachedOwnerClass = nullptr; } - else if (const UBlueprint* AsBlueprint = Cast(ActionOwner)) + else if (const UBlueprint* AsBlueprint = Cast(ActionOwner.Get())) { CachedOwnerClass = AsBlueprint->SkeletonGeneratedClass; } if (CachedOwnerClass == nullptr) { - CachedOwnerClass = GetAssociatedMemberField()->GetOwnerClass(); + if (UField const* AssociatedMemberField = GetAssociatedMemberField()) + { + CachedOwnerClass = AssociatedMemberField->GetOwnerClass(); + } } CacheFlags |= EBlueprintActionInfoFlags::CachedClass; @@ -1890,6 +1915,7 @@ FBlueprintActionFilter::FBlueprintActionFilter(uint32 Flags/*= 0x00*/) AddRejectionTest(FRejectionTestDelegate::CreateStatic(IsFunctionMissingPinParam)); AddRejectionTest(FRejectionTestDelegate::CreateStatic(IsIncompatibleLatentNode)); AddRejectionTest(FRejectionTestDelegate::CreateStatic(IsIncompatibleImpureNode)); + AddRejectionTest(FRejectionTestDelegate::CreateStatic(IsPropertyAccessorNode)); AddRejectionTest(FRejectionTestDelegate::CreateStatic(IsActionHiddenByConfig)); AddRejectionTest(FRejectionTestDelegate::CreateStatic(IsFieldCategoryHidden)); diff --git a/Engine/Source/Editor/BlueprintGraph/Private/BlueprintNodeSpawner.cpp b/Engine/Source/Editor/BlueprintGraph/Private/BlueprintNodeSpawner.cpp index 8a844aa83cc9..ef1436475403 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/BlueprintNodeSpawner.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/BlueprintNodeSpawner.cpp @@ -173,11 +173,6 @@ FBlueprintActionUiSpec const& UBlueprintNodeSpawner::PrimeDefaultUiSpec(UEdGraph NodeTemplate = bTemplateNodeFetched ? NodeTemplate : GetTemplateNode(TargetGraph); if (NodeTemplate != nullptr) { - if (NodeClass == UK2Node_IfThenElse::StaticClass()) - { - bool bIsAvail = true; - bIsAvail = false; - } MenuSignature.Keywords = NodeTemplate->GetKeywords(); } // if a target graph was provided, then we've done all we can to spawn a diff --git a/Engine/Source/Editor/BlueprintGraph/Private/CallFunctionHandler.cpp b/Engine/Source/Editor/BlueprintGraph/Private/CallFunctionHandler.cpp index 8c493f7577c9..16557f48930d 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/CallFunctionHandler.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/CallFunctionHandler.cpp @@ -120,31 +120,7 @@ void FKCHandler_CallFunction::CreateFunctionCallStatement(FKismetFunctionContext { check((*Term)->bIsLiteral); - int32 LatentUUID = INDEX_NONE; - UEdGraphNode* AssociatedNode = LatentInfoPin->GetOwningNode(); - if (AssociatedNode && AssociatedNode->NodeGuid.IsValid()) - { - LatentUUID = GetTypeHash(AssociatedNode->NodeGuid); - - UEdGraphNode* ResultNode = AssociatedNode; - UEdGraphNode* SourceNode = Cast(Context.MessageLog.GetIntermediateTunnelInstance(AssociatedNode)); - while (SourceNode && SourceNode != ResultNode) - { - if (SourceNode->NodeGuid.IsValid()) - { - LatentUUID = HashCombine(LatentUUID, GetTypeHash(SourceNode->NodeGuid)); - } - ResultNode = SourceNode; - SourceNode = Cast(Context.MessageLog.GetIntermediateTunnelInstance(ResultNode)); - } - } - else - { - static int32 FallbackUUID = 0; - LatentUUID = FallbackUUID++; - - CompilerContext.MessageLog.Warning(*LOCTEXT("UUIDDeterministicCookWarn", "Failed to produce a deterministic UUID for a node's latent action: @@. Cooking this Blueprint (@@) asset will non-deterministic.").ToString(), LatentInfoPin, Context.Blueprint); - } + int32 LatentUUID = CompilerContext.MessageLog.CalculateStableIdentifierForLatentActionManager(LatentInfoPin->GetOwningNode()); const FString ExecutionFunctionName = CompilerContext.GetSchema()->FN_ExecuteUbergraphBase.ToString() + TEXT("_") + Context.Blueprint->GetName(); (*Term)->Name = FString::Printf(TEXT("(Linkage=%s,UUID=%s,ExecutionFunction=%s,CallbackTarget=None)"), *FString::FromInt(INDEX_NONE), *FString::FromInt(LatentUUID), *ExecutionFunctionName); diff --git a/Engine/Source/Editor/BlueprintGraph/Private/DelegateNodeHandlers.cpp b/Engine/Source/Editor/BlueprintGraph/Private/DelegateNodeHandlers.cpp index 2222a14503d0..1a77972a13a9 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/DelegateNodeHandlers.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/DelegateNodeHandlers.cpp @@ -109,25 +109,28 @@ struct FKCHandlerDelegateHelper static void RegisterMultipleSelfAndMCDelegateProperty(FKismetFunctionContext& Context, UK2Node_BaseMCDelegate * DelegateNode, FCompilerResultsLog& MessageLog, const UEdGraphSchema_K2* Schema, FDelegateOwnerId::FInnerTermMap& InnerTermMap) { - UMulticastDelegateProperty* BoundProperty = FindAndCheckDelegateProperty(Context, DelegateNode, MessageLog, Schema); - if(BoundProperty && DelegateNode && Schema) + if (DelegateNode && Schema) { - UEdGraphPin* SelfPin = Schema->FindSelfPin(*DelegateNode, EEdGraphPinDirection::EGPD_Input); - check(SelfPin); - - if(0 == SelfPin->LinkedTo.Num()) + UMulticastDelegateProperty* BoundProperty = FindAndCheckDelegateProperty(Context, DelegateNode, MessageLog, Schema); + if (BoundProperty) { - FBPTerminal* Term = CreateInnerTerm(Context, SelfPin, FEdGraphUtilities::GetNetFromPin(SelfPin), BoundProperty, DelegateNode, MessageLog); - Context.NetMap.Add(SelfPin, Term); - InnerTermMap.Add(FDelegateOwnerId(SelfPin, DelegateNode), Term); - return; - } + UEdGraphPin* SelfPin = Schema->FindSelfPin(*DelegateNode, EEdGraphPinDirection::EGPD_Input); + check(SelfPin); - for(int32 LinkIndex = 0; LinkIndex < SelfPin->LinkedTo.Num(); ++LinkIndex) - { - UEdGraphPin* NetPin = SelfPin->LinkedTo[LinkIndex]; - FBPTerminal* Term = CreateInnerTerm(Context, SelfPin, NetPin, BoundProperty, DelegateNode, MessageLog); - InnerTermMap.Add(FDelegateOwnerId(NetPin, DelegateNode), Term); + if (0 == SelfPin->LinkedTo.Num()) + { + FBPTerminal* Term = CreateInnerTerm(Context, SelfPin, FEdGraphUtilities::GetNetFromPin(SelfPin), BoundProperty, DelegateNode, MessageLog); + Context.NetMap.Add(SelfPin, Term); + InnerTermMap.Add(FDelegateOwnerId(SelfPin, DelegateNode), Term); + return; + } + + for (int32 LinkIndex = 0; LinkIndex < SelfPin->LinkedTo.Num(); ++LinkIndex) + { + UEdGraphPin* NetPin = SelfPin->LinkedTo[LinkIndex]; + FBPTerminal* Term = CreateInnerTerm(Context, SelfPin, NetPin, BoundProperty, DelegateNode, MessageLog); + InnerTermMap.Add(FDelegateOwnerId(NetPin, DelegateNode), Term); + } } } } diff --git a/Engine/Source/Editor/BlueprintGraph/Private/EdGraphSchema_K2.cpp b/Engine/Source/Editor/BlueprintGraph/Private/EdGraphSchema_K2.cpp index cd1199211765..aa97cc920e96 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/EdGraphSchema_K2.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/EdGraphSchema_K2.cpp @@ -116,6 +116,9 @@ const FName FBlueprintMetadata::MD_CompactNodeTitle(TEXT("CompactNodeTitle")); const FName FBlueprintMetadata::MD_DisplayName(TEXT("DisplayName")); const FName FBlueprintMetadata::MD_InternalUseParam(TEXT("InternalUseParam")); +const FName FBlueprintMetadata::MD_PropertyGetFunction(TEXT("BlueprintGetter")); +const FName FBlueprintMetadata::MD_PropertySetFunction(TEXT("BlueprintSetter")); + const FName FBlueprintMetadata::MD_ExposeOnSpawn(TEXT("ExposeOnSpawn")); const FName FBlueprintMetadata::MD_HideSelfPin(TEXT("HideSelfPin")); const FName FBlueprintMetadata::MD_DefaultToSelf(TEXT("DefaultToSelf")); @@ -1493,6 +1496,11 @@ void UEdGraphSchema_K2::GetContextMenuActions(const UEdGraph* CurrentGraph, cons MenuBuilder->AddMenuEntry(FGraphEditorCommands::Get().RemoveThisStructVarPin); MenuBuilder->AddMenuEntry(FGraphEditorCommands::Get().RemoveOtherStructVarPins); } + + if (InGraphPin->PinType.PinCategory != PC_Exec && InGraphPin->Direction == EGPD_Input && InGraphPin->LinkedTo.Num() == 0 && !ShouldHidePinDefaultValue(const_cast(InGraphPin))) + { + MenuBuilder->AddMenuEntry(FGraphEditorCommands::Get().ResetPinToDefaultValue); + } } } MenuBuilder->EndSection(); @@ -2252,11 +2260,9 @@ const FPinConnectionResponse UEdGraphSchema_K2::CanCreateConnection(const UEdGra if(const UK2Node* OwningNode = Cast(InputPin->GetOwningNode())) { const bool bAllowMultipleSelfs = OwningNode->AllowMultipleSelfs(true); // it applies also to ForEachCall - const bool bNotAnArrayFunction = !InputPin->PinType.bIsArray; - const bool bNotAMapFunction = !InputPin->PinType.bIsMap; - const bool bNotASetFunction = !InputPin->PinType.bIsSet; + const bool bNotAContainer = !InputPin->PinType.IsContainer(); const bool bSelfPin = IsSelfPin(*InputPin); - bIgnoreArray = bAllowMultipleSelfs && bNotAnArrayFunction && bNotAMapFunction && bNotASetFunction && bSelfPin; + bIgnoreArray = bAllowMultipleSelfs && bNotAContainer && bSelfPin; } // Find the calling context in case one of the pins is of type object and has a value of Self @@ -2493,11 +2499,9 @@ bool UEdGraphSchema_K2::SearchForAutocastFunction(const UEdGraphPin* OutputPin, TargetFunction = NAME_None; FunctionOwner = nullptr; - if (OutputPin->PinType.bIsArray != InputPin->PinType.bIsArray || - OutputPin->PinType.bIsMap != InputPin->PinType.bIsMap || - OutputPin->PinType.bIsSet != InputPin->PinType.bIsSet) + if (OutputPin->PinType.ContainerType != InputPin->PinType.ContainerType) { - if (OutputPin->PinType.bIsSet && InputPin->PinType.bIsArray) + if (OutputPin->PinType.IsSet() && InputPin->PinType.IsArray()) { UFunction* Function = UBlueprintSetLibrary::StaticClass()->FindFunctionByName(GET_MEMBER_NAME_CHECKED(UBlueprintSetLibrary, Set_ToArray)); TargetFunction = Function->GetFName(); @@ -2512,7 +2516,7 @@ bool UEdGraphSchema_K2::SearchForAutocastFunction(const UEdGraphPin* OutputPin, { UClass const* InputClass = Cast(InputPin->PinType.PinSubCategoryObject.Get()); - bool const bInputIsUObject = ((InputClass != NULL) && (InputClass == UObject::StaticClass())); + bool const bInputIsUObject = (InputClass && (InputClass == UObject::StaticClass())); if (bInputIsUObject) { UFunction* Function = UKismetSystemLibrary::StaticClass()->FindFunctionByName(GET_MEMBER_NAME_CHECKED(UKismetSystemLibrary, Conv_InterfaceToObject)); @@ -2576,7 +2580,7 @@ bool UEdGraphSchema_K2::FindSpecializedConversionNode(const UEdGraphPin* OutputP TargetNode = nullptr; // Conversion for scalar -> array - if( (!OutputPin->PinType.IsContainer() && InputPin->PinType.bIsArray) && ArePinTypesCompatible(OutputPin->PinType, InputPin->PinType, NULL, true)) + if( (!OutputPin->PinType.IsContainer() && InputPin->PinType.IsArray()) && ArePinTypesCompatible(OutputPin->PinType, InputPin->PinType, nullptr, true)) { bCanConvert = true; if(bCreateNode) @@ -2646,8 +2650,8 @@ bool UEdGraphSchema_K2::FindSpecializedConversionNode(const UEdGraphPin* OutputP // CHECK BYTE TO ENUM CAST UEnum* Enum = Cast(InputType.PinSubCategoryObject.Get()); - const bool bInputIsEnum = !InputType.bIsArray && (PC_Byte == InputType.PinCategory) && Enum; - const bool bOutputIsByte = !OutputType.bIsArray && (PC_Byte == OutputType.PinCategory); + const bool bInputIsEnum = !InputType.IsContainer() && (PC_Byte == InputType.PinCategory) && Enum; + const bool bOutputIsByte = !OutputType.IsContainer() && (PC_Byte == OutputType.PinCategory); if (bInputIsEnum && bOutputIsByte) { bCanConvert = true; @@ -2689,7 +2693,10 @@ bool UEdGraphSchema_K2::FindSpecializedConversionNode(const UEdGraphPin* OutputP { const bool bConvertAsset = (OutputType.PinCategory == PC_Asset) && (InputType.PinCategory == PC_Object); const bool bConvertAssetClass = (OutputType.PinCategory == PC_AssetClass) && (InputType.PinCategory == PC_Class); - if (bConvertAsset || bConvertAssetClass) + const bool bConvertToAsset = (OutputType.PinCategory == PC_Object) && (InputType.PinCategory == PC_Asset); + const bool bConvertToAssetClass = (OutputType.PinCategory == PC_Class) && (InputType.PinCategory == PC_AssetClass); + + if (bConvertAsset || bConvertAssetClass || bConvertToAsset || bConvertToAssetClass) { bCanConvert = true; if (bCreateNode) @@ -2804,9 +2811,9 @@ FString UEdGraphSchema_K2::IsPinDefaultValid(const UEdGraphPin* Pin, const FStri return FText::Format(MsgFormat, MessageArgs).ToString(); } - const bool bIsArray = Pin->PinType.bIsArray; - const bool bIsSet = Pin->PinType.bIsSet; - const bool bIsMap = Pin->PinType.bIsMap; + const bool bIsArray = Pin->PinType.IsArray(); + const bool bIsSet = Pin->PinType.IsSet(); + const bool bIsMap = Pin->PinType.IsMap(); const bool bIsReference = Pin->PinType.bIsReference; const bool bIsAutoCreateRefTerm = IsAutoCreateRefTerm(Pin); @@ -2975,7 +2982,7 @@ FLinearColor UEdGraphSchema_K2::GetPinTypeColor(const FEdGraphPinType& PinType) FLinearColor UEdGraphSchema_K2::GetSecondaryPinTypeColor(const FEdGraphPinType& PinType) const { - if (PinType.bIsMap) + if (PinType.IsMap()) { FEdGraphPinType FakePrimary = PinType; FakePrimary.PinCategory = FakePrimary.PinValueType.TerminalCategory; @@ -3320,11 +3327,11 @@ bool UEdGraphSchema_K2::GetPropertyCategoryInfo(const UProperty* TestProperty, F OutCategory = PC_Struct; OutSubCategoryObject = StructProperty->Struct; } - else if (Cast(TestProperty) != NULL) + else if (TestProperty->IsA()) { OutCategory = PC_Float; } - else if (Cast(TestProperty) != NULL) + else if (TestProperty->IsA()) { OutCategory = PC_Int; @@ -3366,19 +3373,19 @@ bool UEdGraphSchema_K2::GetPropertyCategoryInfo(const UProperty* TestProperty, F OutSubCategoryObject = EnumProperty->GetEnum(); } } - else if (Cast(TestProperty) != NULL) + else if (TestProperty->IsA()) { OutCategory = PC_Name; } - else if (Cast(TestProperty) != NULL) + else if (TestProperty->IsA()) { OutCategory = PC_Boolean; } - else if (Cast(TestProperty) != NULL) + else if (TestProperty->IsA()) { OutCategory = PC_String; } - else if (Cast(TestProperty) != NULL) + else if (TestProperty->IsA()) { OutCategory = PC_Text; } @@ -3434,18 +3441,12 @@ bool UEdGraphSchema_K2::ConvertPropertyToPinType(const UProperty* Property, /*ou { TestProperty = ArrayProperty->Inner; } - TypeOut.bIsMap = (MapProperty != NULL); - TypeOut.bIsSet = (SetProperty != NULL); - TypeOut.bIsArray = (ArrayProperty != NULL); + TypeOut.ContainerType = FEdGraphPinType::ToPinContainerType(ArrayProperty != nullptr, SetProperty != nullptr, MapProperty != nullptr); TypeOut.bIsReference = Property->HasAllPropertyFlags(CPF_OutParm|CPF_ReferenceParm); TypeOut.bIsConst = Property->HasAllPropertyFlags(CPF_ConstParm); - // Check to see if this is the wildcard property for the target array type - UFunction* Function = Cast(Property->GetOuter()); - - if( UK2Node_CallArrayFunction::IsWildcardProperty(Function, Property) - || UK2Node_CallFunction::IsStructureWildcardProperty(Function, Property->GetName()) - || UK2Node_CallFunction::IsWildcardProperty(Function, Property)) + // Check to see if this is the wildcard property for the target container type + if(IsWildcardProperty(Property)) { TypeOut.PinCategory = PC_Wildcard; if(MapProperty) @@ -3466,7 +3467,9 @@ bool UEdGraphSchema_K2::ConvertPropertyToPinType(const UProperty* Property, /*ou else { UObject* SubCategoryObject = nullptr; - bool bResult = GetPropertyCategoryInfo(TestProperty, TypeOut.PinCategory, TypeOut.PinSubCategory, SubCategoryObject, TypeOut.bIsWeakPointer); + bool bIsWeakPointer = false; + bool bResult = GetPropertyCategoryInfo(TestProperty, TypeOut.PinCategory, TypeOut.PinSubCategory, SubCategoryObject, bIsWeakPointer); + TypeOut.bIsWeakPointer = bIsWeakPointer; TypeOut.PinSubCategoryObject = SubCategoryObject; if (!bResult) { @@ -3487,6 +3490,16 @@ bool UEdGraphSchema_K2::ConvertPropertyToPinType(const UProperty* Property, /*ou return true; } +bool UEdGraphSchema_K2::IsWildcardProperty(const UProperty* Property) +{ + UFunction* Function = Cast(Property->GetOuter()); + + return Function && ( UK2Node_CallArrayFunction::IsWildcardProperty(Function, Property) + || UK2Node_CallFunction::IsStructureWildcardProperty(Function, Property->GetName()) + || UK2Node_CallFunction::IsWildcardProperty(Function, Property) + || FEdGraphUtilities::IsArrayDependentParam(Function, Property->GetName()) ); +} + FString UEdGraphSchema_K2::TypeToString(const FEdGraphPinType& Type) { return TypeToText(Type).ToString(); @@ -3587,32 +3600,24 @@ FText UEdGraphSchema_K2::GetCategoryText(const FString& Category, const bool bFo CategoryDescriptions.Add(PC_Exec, LOCTEXT("Exec", "Exec")); CategoryDescriptions.Add(PC_Boolean, LOCTEXT("BoolCategory","Boolean")); CategoryDescriptions.Add(PC_Byte, LOCTEXT("ByteCategory","Byte")); - CategoryDescriptions.Add(PC_Class, LOCTEXT("ClassCategory","Class")); + CategoryDescriptions.Add(PC_Class, LOCTEXT("ClassCategory","Class Reference")); CategoryDescriptions.Add(PC_Int, LOCTEXT("IntCategory","Integer")); CategoryDescriptions.Add(PC_Float, LOCTEXT("FloatCategory","Float")); CategoryDescriptions.Add(PC_Name, LOCTEXT("NameCategory","Name")); CategoryDescriptions.Add(PC_Delegate, LOCTEXT("DelegateCategory","Delegate")); CategoryDescriptions.Add(PC_MCDelegate, LOCTEXT("MulticastDelegateCategory","Multicast Delegate")); - CategoryDescriptions.Add(PC_Object, LOCTEXT("ObjectCategory","Reference")); + CategoryDescriptions.Add(PC_Object, LOCTEXT("ObjectCategory","Object Reference")); CategoryDescriptions.Add(PC_Interface, LOCTEXT("InterfaceCategory","Interface")); CategoryDescriptions.Add(PC_String, LOCTEXT("StringCategory","String")); CategoryDescriptions.Add(PC_Text, LOCTEXT("TextCategory","Text")); CategoryDescriptions.Add(PC_Struct, LOCTEXT("StructCategory","Structure")); CategoryDescriptions.Add(PC_Wildcard, LOCTEXT("WildcardCategory","Wildcard")); CategoryDescriptions.Add(PC_Enum, LOCTEXT("EnumCategory","Enum")); - CategoryDescriptions.Add(PC_Asset, LOCTEXT("AssetCategory", "Asset ID")); - CategoryDescriptions.Add(PC_AssetClass, LOCTEXT("AssetClassCategory", "Class Asset ID")); + CategoryDescriptions.Add(PC_Asset, LOCTEXT("SoftObjectReferenceCategory", "Soft Object Reference")); + CategoryDescriptions.Add(PC_AssetClass, LOCTEXT("SoftClassReferenceCategory", "Soft Class Reference")); CategoryDescriptions.Add(AllObjectTypes, LOCTEXT("AllObjectTypes", "Object Types")); } - if (bForMenu) - { - if (Category == PC_Object) - { - return LOCTEXT("ObjectCategoryForMenu", "Object Reference"); - } - } - if (FText const* TypeDesc = CategoryDescriptions.Find(Category)) { return *TypeDesc; @@ -3691,7 +3696,7 @@ FText UEdGraphSchema_K2::TypeToText(const FEdGraphPinType& Type) { FText PropertyText = TerminalTypeToText(Type.PinCategory, Type.PinSubCategory, Type.PinSubCategoryObject.Get(), Type.bIsWeakPointer); - if ( Type.bIsMap ) + if (Type.IsMap()) { FFormatNamedArguments Args; Args.Add(TEXT("KeyTitle"), PropertyText); @@ -3699,13 +3704,13 @@ FText UEdGraphSchema_K2::TypeToText(const FEdGraphPinType& Type) Args.Add(TEXT("ValueTitle"), ValueText); PropertyText = FText::Format(LOCTEXT("MapAsText", "Map of {KeyTitle}s to {ValueTitle}s"), Args); } - else if ( Type.bIsSet ) + else if (Type.IsSet()) { FFormatNamedArguments Args; Args.Add(TEXT("PropertyTitle"), PropertyText); PropertyText = FText::Format(LOCTEXT("SetAsText", "Set of {PropertyTitle}s"), Args); } - else if (Type.bIsArray) + else if (Type.IsArray()) { FFormatNamedArguments Args; Args.Add(TEXT("PropertyTitle"), PropertyText); @@ -3787,25 +3792,25 @@ void UEdGraphSchema_K2::GetVariableTypeTree(TArray< TSharedPtr // Add wildcard type if (bAllowWildCard) { - TypeTree.Add( MakeShareable( new FPinTypeTreeInfo(GetCategoryText(PC_Wildcard, true), PC_Wildcard, this, LOCTEXT("WildcardType", "Wildcard type (unspecified).")) ) ); + TypeTree.Add( MakeShareable( new FPinTypeTreeInfo(GetCategoryText(PC_Wildcard, true), PC_Wildcard, this, LOCTEXT("WildcardType", "Wildcard type (unspecified)")) ) ); } // Add the types that have subtrees if (!bIndexTypesOnly) { - TypeTree.Add(MakeShareable(new FPinTypeTreeInfo(GetCategoryText(PC_Struct, true), PC_Struct, this, LOCTEXT("StructType", "Struct (value) types."), true, TypesDatabasePtr))); - TypeTree.Add(MakeShareable(new FPinTypeTreeInfo(GetCategoryText(PC_Interface, true), PC_Interface, this, LOCTEXT("InterfaceType", "Interface pointer."), true, TypesDatabasePtr))); + TypeTree.Add(MakeShareable(new FPinTypeTreeInfo(GetCategoryText(PC_Struct, true), PC_Struct, this, LOCTEXT("StructType", "Struct (value) types"), true, TypesDatabasePtr))); + TypeTree.Add(MakeShareable(new FPinTypeTreeInfo(GetCategoryText(PC_Interface, true), PC_Interface, this, LOCTEXT("InterfaceType", "Interface types"), true, TypesDatabasePtr))); if (!bRootTypesOnly) { - TypeTree.Add(MakeShareable(new FPinTypeTreeInfo(GetCategoryText(AllObjectTypes, true), AllObjectTypes, this, LOCTEXT("ObjectType", "Object pointer."), true, TypesDatabasePtr))); + TypeTree.Add(MakeShareable(new FPinTypeTreeInfo(GetCategoryText(AllObjectTypes, true), AllObjectTypes, this, LOCTEXT("ObjectType", "Object types"), true, TypesDatabasePtr))); } else { - TypeTree.Add(MakeShareable(new FPinTypeTreeInfo(GetCategoryText(PC_Object, true), PC_Object, this, LOCTEXT("ObjectType", "Object pointer."), true, TypesDatabasePtr))); - TypeTree.Add(MakeShareable(new FPinTypeTreeInfo(GetCategoryText(PC_Class, true), PC_Class, this, LOCTEXT("ClassType", "Class pointer."), true, TypesDatabasePtr))); - TypeTree.Add(MakeShareable(new FPinTypeTreeInfo(GetCategoryText(PC_AssetClass, true), PC_AssetClass, this, LOCTEXT("AssetClassType", "Class ID."), true, TypesDatabasePtr))); - TypeTree.Add(MakeShareable(new FPinTypeTreeInfo(GetCategoryText(PC_Asset, true), PC_Asset, this, LOCTEXT("AssetType", "Asset ID."), true, TypesDatabasePtr))); + TypeTree.Add(MakeShareable(new FPinTypeTreeInfo(GetCategoryText(PC_Object, true), PC_Object, this, LOCTEXT("ObjectTypeHardReference", "Hard reference to an Object"), true, TypesDatabasePtr))); + TypeTree.Add(MakeShareable(new FPinTypeTreeInfo(GetCategoryText(PC_Class, true), PC_Class, this, LOCTEXT("ClassType", "Hard reference to a Class"), true, TypesDatabasePtr))); + TypeTree.Add(MakeShareable(new FPinTypeTreeInfo(GetCategoryText(PC_Asset, true), PC_Asset, this, LOCTEXT("AssetType", "Soft reference to an Object"), true, TypesDatabasePtr))); + TypeTree.Add(MakeShareable(new FPinTypeTreeInfo(GetCategoryText(PC_AssetClass, true), PC_AssetClass, this, LOCTEXT("AssetClassType", "Soft reference to a Class"), true, TypesDatabasePtr))); } } TypeTree.Add( MakeShareable( new FPinTypeTreeInfo(GetCategoryText(PC_Enum, true), PC_Enum, this, LOCTEXT("EnumType", "Enumeration types."), true, TypesDatabasePtr) ) ); @@ -3831,15 +3836,15 @@ struct FWildcardArrayPinHelper return true; } - const UK2Node* OwningNode = InputPin ? Cast(InputPin->GetOwningNode()) : NULL; + const UK2Node* OwningNode = InputPin ? Cast(InputPin->GetOwningNode()) : nullptr; const bool bInputWildcardPinAcceptsArray = !OwningNode || OwningNode->DoesInputWildcardPinAcceptArray(InputPin); if (bInputWildcardPinAcceptsArray) { return true; } - const bool bCheckInputPin = (InputPin->PinType.PinCategory == GetDefault()->PC_Wildcard) && !InputPin->PinType.bIsArray; - const bool bArrayOutputPin = OutputPin && OutputPin->PinType.bIsArray; + const bool bCheckInputPin = (InputPin->PinType.PinCategory == GetDefault()->PC_Wildcard) && !InputPin->PinType.IsArray(); + const bool bArrayOutputPin = OutputPin && OutputPin->PinType.IsArray(); return !(bCheckInputPin && bArrayOutputPin); } }; @@ -3877,7 +3882,7 @@ namespace { bool bResult = false; bool bIsNonNativeClass = false; - if(UClass* TargetAsClass = const_cast(Cast(InTargetStruct))) + if (const UClass* TargetAsClass = Cast(InTargetStruct)) { InTargetStruct = TargetAsClass->GetAuthoritativeClass(); } @@ -3999,7 +4004,7 @@ bool UEdGraphSchema_K2::DefaultValueSimpleValidation(const FEdGraphPinType& PinT } } } - else if ((PinCategory == PC_Class) || (PinCategory == PC_AssetClass)) + else if ((PinCategory == PC_Class)) { // Should have an object set but no string if (!NewDefaultValue.IsEmpty()) @@ -4062,7 +4067,7 @@ bool UEdGraphSchema_K2::DefaultValueSimpleValidation(const FEdGraphPinType& PinT { // Anything is allowed } - else if ((PinCategory == PC_Object) || (PinCategory == PC_Interface) || (PinCategory == PC_Asset)) + else if ((PinCategory == PC_Object) || (PinCategory == PC_Interface)) { if (PinSubCategoryObject == NULL && (PinSubCategory != PSC_Self)) { @@ -4090,10 +4095,25 @@ bool UEdGraphSchema_K2::DefaultValueSimpleValidation(const FEdGraphPinType& PinT { DVSV_RETURN_MSG(FString::Printf(TEXT("%s isn't a %s (specified on pin %s)"), *NewDefaultObject->GetPathName(), *ObjectClass->GetName(), *(PinName))); } - - if ((PinCategory == PC_Asset) && NewDefaultObject && !NewDefaultObject->IsAsset()) + } + else if ((PinCategory == PC_Asset) || (PinCategory == PC_AssetClass)) + { + // Should not have an object set, should be converted to string before getting here + if (NewDefaultObject) { - DVSV_RETURN_MSG(FString::Printf(TEXT("%s is not an asset (specified on pin %s)"), *NewDefaultObject->GetPathName(), *(PinName))); + DVSV_RETURN_MSG(FString::Printf(TEXT("NewDefaultObject '%s' specified on object pin '%s'"), *NewDefaultObject->GetPathName(), *(PinName))); + } + + if (!NewDefaultValue.IsEmpty()) + { + FText PathReason; + + if (!FPackageName::IsValidObjectPath(NewDefaultValue, &PathReason)) + { + DVSV_RETURN_MSG(FString::Printf(TEXT("Soft Reference '%s' is invalid format for object pin '%s':"), *NewDefaultValue, *(PinName), *PathReason.ToString())); + } + + // Class and IsAsset validation is not foolproof for soft references, skip } } else if (PinCategory == PC_String) @@ -4181,7 +4201,7 @@ bool UEdGraphSchema_K2::DefaultValueSimpleValidation(const FEdGraphPinType& PinT bool UEdGraphSchema_K2::ArePinTypesCompatible(const FEdGraphPinType& Output, const FEdGraphPinType& Input, const UClass* CallingContext, bool bIgnoreArray /*= false*/) const { - if( !bIgnoreArray && ( Output.bIsMap != Input.bIsMap || Output.bIsSet != Input.bIsSet || Output.bIsArray != Input.bIsArray ) && (Input.PinCategory != PC_Wildcard || Input.IsContainer()) ) + if( !bIgnoreArray && ( Output.ContainerType != Input.ContainerType ) && (Input.PinCategory != PC_Wildcard || Input.IsContainer()) ) { return false; } @@ -4191,7 +4211,7 @@ bool UEdGraphSchema_K2::ArePinTypesCompatible(const FEdGraphPinType& Output, con && (Output.PinSubCategoryObject == Input.PinSubCategoryObject) && (Output.PinSubCategoryMemberReference == Input.PinSubCategoryMemberReference)) { - if(Input.bIsMap) + if(Input.IsMap()) { return Input.PinValueType.TerminalCategory == PC_Wildcard || @@ -4221,7 +4241,7 @@ bool UEdGraphSchema_K2::ArePinTypesCompatible(const FEdGraphPinType& Output, con { const UClass* OutputObject = (Output.PinSubCategory == PSC_Self) ? CallingContext : Cast(Output.PinSubCategoryObject.Get()); const UClass* InputObject = (Input.PinSubCategory == PSC_Self) ? CallingContext : Cast(Input.PinSubCategoryObject.Get()); - if ((OutputObject != NULL) && (InputObject != NULL)) + if (OutputObject && InputObject) { return ExtendedIsChildOf(OutputObject ,InputObject); } @@ -4233,7 +4253,7 @@ bool UEdGraphSchema_K2::ArePinTypesCompatible(const FEdGraphPinType& Output, con UStruct const* OutputObject = (Output.PinSubCategory == PSC_Self) ? CallingContext : Cast(Output.PinSubCategoryObject.Get()); UStruct const* InputObject = (Input.PinSubCategory == PSC_Self) ? CallingContext : Cast(Input.PinSubCategoryObject.Get()); - if ((OutputObject != NULL) && (InputObject != NULL)) + if (OutputObject && InputObject) { if (Output.PinCategory == PC_Struct) { @@ -4435,57 +4455,90 @@ void UEdGraphSchema_K2::HandleGraphBeingDeleted(UEdGraph& GraphBeingRemoved) con } } +void UEdGraphSchema_K2::GetPinDefaultValuesFromString(const FEdGraphPinType& PinType, UObject* OwningObject, const FString& NewDefaultValue, FString& UseDefaultValue, UObject*& UseDefaultObject, FText& UseDefaultText) const +{ + if ((PinType.PinCategory == PC_Object) + || (PinType.PinCategory == PC_Class) + || (PinType.PinCategory == PC_Interface)) + { + FString ObjectPathLocal = NewDefaultValue; + ConstructorHelpers::StripObjectClass(ObjectPathLocal); + + // If this is not a full object path it's a relative path so should be saved as a string + if (FPackageName::IsValidObjectPath(ObjectPathLocal)) + { + FStringAssetReference AssetRef = ObjectPathLocal; + UseDefaultValue.Empty(); + UseDefaultObject = AssetRef.TryLoad(); + UseDefaultText = FText::GetEmpty(); + } + else + { + // "None" should be saved as empty string + if (ObjectPathLocal == TEXT("None")) + { + ObjectPathLocal.Empty(); + } + + UseDefaultValue = ObjectPathLocal; + UseDefaultObject = nullptr; + UseDefaultText = FText::GetEmpty(); + } + } + else if (PinType.PinCategory == PC_Text) + { + FString PackageNamespace; +#if USE_STABLE_LOCALIZATION_KEYS + if (GIsEditor) + { + PackageNamespace = TextNamespaceUtil::EnsurePackageNamespace(OwningObject); + } +#endif // USE_STABLE_LOCALIZATION_KEYS + if (!FTextStringHelper::ReadFromString(*NewDefaultValue, UseDefaultText, nullptr, *PackageNamespace)) + { + UseDefaultText = FText::FromString(NewDefaultValue); + } + UseDefaultObject = nullptr; + UseDefaultValue.Empty(); + } + else + { + UseDefaultValue = NewDefaultValue; + UseDefaultObject = nullptr; + UseDefaultText = FText::GetEmpty(); + + if (PinType.PinCategory == PC_Byte && UseDefaultValue.IsEmpty()) + { + UEnum* EnumPtr = Cast(PinType.PinSubCategoryObject.Get()); + if (EnumPtr) + { + // Enums are stored as empty string in autogenerated defaults, but should turn into the first value in array + UseDefaultValue = EnumPtr->GetNameStringByIndex(0); + } + } + else if ((PinType.PinCategory == PC_Asset) || (PinType.PinCategory == PC_AssetClass)) + { + ConstructorHelpers::StripObjectClass(UseDefaultValue); + } + } +} + void UEdGraphSchema_K2::TrySetDefaultValue(UEdGraphPin& Pin, const FString& NewDefaultValue) const { FString UseDefaultValue; UObject* UseDefaultObject = nullptr; FText UseDefaultText; - if ((Pin.PinType.PinCategory == PC_Object) - || (Pin.PinType.PinCategory == PC_Class) - || (Pin.PinType.PinCategory == PC_Interface) - || (Pin.PinType.PinCategory == PC_Asset) - || (Pin.PinType.PinCategory == PC_AssetClass)) - { - FString ObjectPathLocal = NewDefaultValue; - ConstructorHelpers::StripObjectClass(ObjectPathLocal); - UseDefaultObject = FindObject(ANY_PACKAGE, *ObjectPathLocal); - UseDefaultValue.Empty(); - } - else if(Pin.PinType.PinCategory == PC_Text) - { - FString PackageNamespace; -#if USE_STABLE_LOCALIZATION_KEYS - if (GIsEditor) - { - PackageNamespace = TextNamespaceUtil::EnsurePackageNamespace(Pin.GetOwningNodeUnchecked()); - } -#endif // USE_STABLE_LOCALIZATION_KEYS - FText NewTextValue; - if (!FTextStringHelper::ReadFromString(*NewDefaultValue, NewTextValue, nullptr, *PackageNamespace)) - { - NewTextValue = FText::FromString(NewDefaultValue); - } - TrySetDefaultText(Pin, NewTextValue); - UseDefaultObject = nullptr; - UseDefaultValue.Empty(); - return; - } - else - { - UseDefaultObject = nullptr; - UseDefaultValue = NewDefaultValue; - } + GetPinDefaultValuesFromString(Pin.PinType, Pin.GetOwningNodeUnchecked(), NewDefaultValue, UseDefaultValue, UseDefaultObject, UseDefaultText); // Check the default value and make it an error if it's bogus - if (IsPinDefaultValid(&Pin, UseDefaultValue, UseDefaultObject, UseDefaultText) == TEXT("")) + if (IsPinDefaultValid(&Pin, UseDefaultValue, UseDefaultObject, UseDefaultText).IsEmpty()) { Pin.DefaultObject = UseDefaultObject; Pin.DefaultValue = UseDefaultValue; Pin.DefaultTextValue = UseDefaultText; UEdGraphNode* Node = Pin.GetOwningNode(); - check(Node); Node->PinDefaultValueChanged(&Pin); UBlueprint* Blueprint = FBlueprintEditorUtils::FindBlueprintForNodeChecked(Node); @@ -4497,16 +4550,21 @@ void UEdGraphSchema_K2::TrySetDefaultObject(UEdGraphPin& Pin, UObject* NewDefaul { FText UseDefaultText; + if ((Pin.PinType.PinCategory == PC_Asset) || (Pin.PinType.PinCategory == PC_AssetClass)) + { + TrySetDefaultValue(Pin, NewDefaultObject ? NewDefaultObject->GetPathName() : FString()); + return; + } + // Check the default value and make it an error if it's bogus - if (IsPinDefaultValid(&Pin, FString(TEXT("")), NewDefaultObject, UseDefaultText) == TEXT("")) + if (IsPinDefaultValid(&Pin, FString(), NewDefaultObject, UseDefaultText).IsEmpty()) { Pin.DefaultObject = NewDefaultObject; - Pin.DefaultValue = NULL; + Pin.DefaultValue.Empty(); Pin.DefaultTextValue = UseDefaultText; } UEdGraphNode* Node = Pin.GetOwningNode(); - check(Node); Node->PinDefaultValueChanged(&Pin); UBlueprint* Blueprint = FBlueprintEditorUtils::FindBlueprintForNodeChecked(Node); @@ -4519,15 +4577,14 @@ void UEdGraphSchema_K2::TrySetDefaultText(UEdGraphPin& InPin, const FText& InNew if(InPin.PinType.PinCategory == PC_Text) { // Check the default value and make it an error if it's bogus - if (IsPinDefaultValid(&InPin, TEXT(""), NULL, InNewDefaultText) == TEXT("")) + if (IsPinDefaultValid(&InPin, FString(), nullptr, InNewDefaultText).IsEmpty()) { - InPin.DefaultObject = NULL; - InPin.DefaultValue = NULL; + InPin.DefaultObject = nullptr; + InPin.DefaultValue.Empty(); InPin.DefaultTextValue = InNewDefaultText; } UEdGraphNode* Node = InPin.GetOwningNode(); - check(Node); Node->PinDefaultValueChanged(&InPin); UBlueprint* Blueprint = FBlueprintEditorUtils::FindBlueprintForNodeChecked(Node); @@ -4606,70 +4663,50 @@ bool UEdGraphSchema_K2::ShouldShowAssetPickerForPin(UEdGraphPin* Pin) const return bShow; } -void UEdGraphSchema_K2::SetPinDefaultValue(UEdGraphPin* Pin, const UFunction* Function, const UProperty* Param) const +bool UEdGraphSchema_K2::FindFunctionParameterDefaultValue(const UFunction* Function, const UProperty* Param, FString& OutString) { - if ((Function != nullptr) && (Param != nullptr)) - { - bool bHasAutomaticValue = false; + bool bHasAutomaticValue = false; - const FString MetadataDefaultValue = Function->GetMetaData(*Param->GetName()); - if (!MetadataDefaultValue.IsEmpty()) + const FString MetadataDefaultValue = Function->GetMetaData(*Param->GetName()); + if (!MetadataDefaultValue.IsEmpty()) + { + // Specified default value in the metadata + OutString = MetadataDefaultValue; + bHasAutomaticValue = true; + } + else + { + const FName MetadataCppDefaultValueKey(*(FString(TEXT("CPP_Default_")) + Param->GetName())); + const FString MetadataCppDefaultValue = Function->GetMetaData(MetadataCppDefaultValueKey); + if (!MetadataCppDefaultValue.IsEmpty()) { - // Specified default value in the metadata - Pin->AutogeneratedDefaultValue = MetadataDefaultValue; + OutString = MetadataCppDefaultValue; bHasAutomaticValue = true; } - else - { - const FName MetadataCppDefaultValueKey( *(FString(TEXT("CPP_Default_")) + Param->GetName()) ); - const FString MetadataCppDefaultValue = Function->GetMetaData(MetadataCppDefaultValueKey); - if (!MetadataCppDefaultValue.IsEmpty()) - { - Pin->AutogeneratedDefaultValue = MetadataCppDefaultValue; - bHasAutomaticValue = true; - } - } + } - if (bHasAutomaticValue) - { - if (Pin->PinType.PinCategory == PC_Text) - { - FString PackageNamespace; -#if USE_STABLE_LOCALIZATION_KEYS - if (GIsEditor) - { - PackageNamespace = TextNamespaceUtil::EnsurePackageNamespace(Pin->GetOwningNodeUnchecked()); - } -#endif // USE_STABLE_LOCALIZATION_KEYS - if (!FTextStringHelper::ReadFromString(*Pin->AutogeneratedDefaultValue, Pin->DefaultTextValue, nullptr, *PackageNamespace)) - { - Pin->DefaultTextValue = FText::FromString(Pin->AutogeneratedDefaultValue); - } - } - else - { - Pin->DefaultValue = Pin->AutogeneratedDefaultValue; - } - } - } - - if (Pin->DefaultValue.Len() == 0) - { - // Set the default value to (T)0 - SetPinDefaultValueBasedOnType(Pin); - } + return bHasAutomaticValue; } -void UEdGraphSchema_K2::SetPinDefaultValueBasedOnType(UEdGraphPin* Pin) const +void UEdGraphSchema_K2::SetPinAutogeneratedDefaultValue(UEdGraphPin* Pin, const FString& NewValue) const { + Pin->AutogeneratedDefaultValue = NewValue; + + ResetPinToAutogeneratedDefaultValue(Pin, false); +} + +void UEdGraphSchema_K2::SetPinAutogeneratedDefaultValueBasedOnType(UEdGraphPin* Pin) const +{ + FString NewValue; + // Create a useful default value based on the pin type if(Pin->PinType.IsContainer() ) { - Pin->AutogeneratedDefaultValue = TEXT(""); + NewValue = TEXT(""); } else if (Pin->PinType.PinCategory == PC_Int) { - Pin->AutogeneratedDefaultValue = TEXT("0"); + NewValue = TEXT("0"); } else if(Pin->PinType.PinCategory == PC_Byte) { @@ -4678,37 +4715,73 @@ void UEdGraphSchema_K2::SetPinDefaultValueBasedOnType(UEdGraphPin* Pin) const { // First element of enum can change. If the enum is { A, B, C } and the default value is A, // the defult value should not change when enum will be changed into { N, A, B, C } - Pin->AutogeneratedDefaultValue = TEXT(""); - Pin->DefaultValue = EnumPtr->GetNameStringByIndex(0); - return; + NewValue = TEXT(""); } else { - Pin->AutogeneratedDefaultValue = TEXT("0"); + NewValue = TEXT("0"); } } else if (Pin->PinType.PinCategory == PC_Float) { - Pin->AutogeneratedDefaultValue = TEXT("0.0"); + // This is a slightly different format than is produced by PropertyValueToString, but changing it has backward compatibility issues + NewValue = TEXT("0.0"); } else if (Pin->PinType.PinCategory == PC_Boolean) { - Pin->AutogeneratedDefaultValue = TEXT("false"); + NewValue = TEXT("false"); } else if (Pin->PinType.PinCategory == PC_Name) { - Pin->AutogeneratedDefaultValue = TEXT("None"); + NewValue = TEXT("None"); } else if ((Pin->PinType.PinCategory == PC_Struct) && ((Pin->PinType.PinSubCategoryObject == VectorStruct) || (Pin->PinType.PinSubCategoryObject == RotatorStruct))) { - Pin->AutogeneratedDefaultValue = TEXT("0, 0, 0"); + // This is a slightly different format than is produced by PropertyValueToString, but changing it has backward compatibility issues + NewValue = TEXT("0, 0, 0"); + } + + // PropertyValueToString also has cases for LinerColor and Transform, LinearColor is identical to export text so is fine, the Transform case is specially handled in the vm + + SetPinAutogeneratedDefaultValue(Pin, NewValue); +} + +void UEdGraphSchema_K2::ResetPinToAutogeneratedDefaultValue(UEdGraphPin* Pin, bool bCallModifyCallbacks) const +{ + GetPinDefaultValuesFromString(Pin->PinType, Pin->GetOwningNodeUnchecked(), Pin->AutogeneratedDefaultValue, Pin->DefaultValue, Pin->DefaultObject, Pin->DefaultTextValue); + + if (bCallModifyCallbacks) + { + UEdGraphNode* Node = Pin->GetOwningNode(); + Node->PinDefaultValueChanged(Pin); + + UBlueprint* Blueprint = FBlueprintEditorUtils::FindBlueprintForNodeChecked(Node); + FBlueprintEditorUtils::MarkBlueprintAsModified(Blueprint); + } +} + +void UEdGraphSchema_K2::SetPinDefaultValueAtConstruction(UEdGraphPin* Pin, const FString& DefaultValueString) const +{ + GetPinDefaultValuesFromString(Pin->PinType, Pin->GetOwningNodeUnchecked(), DefaultValueString, Pin->DefaultValue, Pin->DefaultObject, Pin->DefaultTextValue); +} + +void UEdGraphSchema_K2::SetPinDefaultValue(UEdGraphPin* Pin, const UFunction* Function, const UProperty* Param) const +{ + if (Function != nullptr && Param != nullptr) + { + FString NewValue; + FindFunctionParameterDefaultValue(Function, Param, NewValue); + SetPinAutogeneratedDefaultValue(Pin, NewValue); } else { - Pin->AutogeneratedDefaultValue = TEXT(""); + SetPinAutogeneratedDefaultValueBasedOnType(Pin); } +} - Pin->DefaultValue = Pin->AutogeneratedDefaultValue; +void UEdGraphSchema_K2::SetPinDefaultValueBasedOnType(UEdGraphPin* Pin) const +{ + SetPinAutogeneratedDefaultValueBasedOnType(Pin); } void UEdGraphSchema_K2::ValidateExistingConnections(UEdGraphPin* Pin) @@ -4857,7 +4930,7 @@ UFunction* UEdGraphSchema_K2::FindSetVariableByNameFunction(const FEdGraphPinTyp UFunction* Function = NULL; if(SetFunctionName != NAME_None) { - if(PinType.bIsArray) + if(PinType.IsArray()) { static FName SetArrayName(GET_FUNCTION_NAME_CHECKED(UKismetArrayLibrary, SetArrayPropertyByName)); Function = FindField(UKismetArrayLibrary::StaticClass(), SetArrayName); @@ -5085,7 +5158,7 @@ FVector2D UEdGraphSchema_K2::CalculateAveragePositionBetweenNodes(UEdGraphPin* I return (InputCorner + OutputCorner) * 0.5f; } -bool UEdGraphSchema_K2::IsConstructionScript(const UEdGraph* TestEdGraph) const +bool UEdGraphSchema_K2::IsConstructionScript(const UEdGraph* TestEdGraph) { TArray EntryNodes; TestEdGraph->GetNodesOfClass(EntryNodes); @@ -6371,7 +6444,7 @@ void UEdGraphSchema_K2::SplitPin(UEdGraphPin* Pin) const { const FString PinName = FString::Printf(TEXT("%s_%s"), *Pin->PinName, *ProtoPin->PinName); const FEdGraphPinType& ProtoPinType = ProtoPin->PinType; - UEdGraphPin* SubPin = GraphNode->CreatePin(Pin->Direction, ProtoPinType.PinCategory, ProtoPinType.PinSubCategory, ProtoPinType.PinSubCategoryObject.Get(), ProtoPinType.bIsArray, false, PinName); + UEdGraphPin* SubPin = GraphNode->CreatePin(Pin->Direction, ProtoPinType.PinCategory, ProtoPinType.PinSubCategory, ProtoPinType.PinSubCategoryObject.Get(), PinName, ProtoPinType.ContainerType, false, false, INDEX_NONE, ProtoPinType.PinValueType); if (K2Node != nullptr && K2Node->ShouldDrawCompact() && !Pin->ParentPin) { @@ -6667,8 +6740,7 @@ UEdGraphPin* UEdGraphSchema_K2::DropPinOnNode(UEdGraphNode* InTargetNode, const for (UK2Node_EditablePinBase* CurrentEditablePinNode : EditablePinNodes) { CurrentEditablePinNode->Modify(); - UEdGraphPin* CreatedPin = nullptr; - CreatedPin = CurrentEditablePinNode->CreateUserDefinedPin(NewPinName, InSourcePinType, (InSourcePinDirection == EGPD_Input)? EGPD_Output : EGPD_Input); + UEdGraphPin* CreatedPin = CurrentEditablePinNode->CreateUserDefinedPin(NewPinName, InSourcePinType, (InSourcePinDirection == EGPD_Input) ? EGPD_Output : EGPD_Input); // The final ResultPin is from the node the user dragged and dropped to if (EditablePinNode == CurrentEditablePinNode) @@ -6677,6 +6749,15 @@ UEdGraphPin* UEdGraphSchema_K2::DropPinOnNode(UEdGraphNode* InTargetNode, const } } + HandleParameterDefaultValueChanged(EditablePinNode); + } + return ResultPin; +} + +void UEdGraphSchema_K2::HandleParameterDefaultValueChanged(UK2Node* InTargetNode) const +{ + if (UK2Node_EditablePinBase* EditablePinNode = Cast(InTargetNode)) + { FParamsChangedHelper ParamsChangedHelper; ParamsChangedHelper.ModifiedBlueprints.Add(FBlueprintEditorUtils::FindBlueprintForNode(InTargetNode)); FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(FBlueprintEditorUtils::FindBlueprintForNode(InTargetNode)); @@ -6692,7 +6773,7 @@ UEdGraphPin* UEdGraphSchema_K2::DropPinOnNode(UEdGraphNode* InTargetNode, const } // Now update all the blueprints that got modified - for (UBlueprint* Blueprint : ParamsChangedHelper.ModifiedBlueprints) + for (UBlueprint* Blueprint : ParamsChangedHelper.ModifiedBlueprints) { if (Blueprint) { @@ -6700,7 +6781,6 @@ UEdGraphPin* UEdGraphSchema_K2::DropPinOnNode(UEdGraphNode* InTargetNode, const } } } - return ResultPin; } bool UEdGraphSchema_K2::SupportsDropPinOnNode(UEdGraphNode* InTargetNode, const FEdGraphPinType& InSourcePinType, EEdGraphPinDirection InSourcePinDirection, FText& OutErrorMessage) const diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node.cpp index e9b620e14079..5db53d4384cd 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node.cpp @@ -23,6 +23,7 @@ #include "PropertyCustomizationHelpers.h" #include "ObjectEditorUtils.h" +#include "FrameworkObjectVersion.h" #define LOCTEXT_NAMESPACE "K2Node" @@ -66,47 +67,63 @@ void UK2Node::PostLoad() #endif // WITH_EDITORONLY_DATA Super::PostLoad(); - - // fix up pin default values - FixupPinDefaultValues(); } void UK2Node::Serialize(FArchive& Ar) { - Super::Serialize(Ar); - - if (Ar.IsObjectReferenceCollector() && Ar.IsSaving()) - { - // If looking for references during save, expand any default values on the pins - - for (const UEdGraphPin* Pin : Pins) + if (Ar.IsSaving()) + { + for (UEdGraphPin* Pin : Pins) { - if (!Pin->bDefaultValueIsIgnored && !Pin->DefaultValue.IsEmpty() && Pin->PinType.PinCategory == UEdGraphSchema_K2::PC_Struct && Pin->PinType.PinSubCategoryObject.IsValid()) + if (!Pin->bDefaultValueIsIgnored && !Pin->DefaultValue.IsEmpty() ) { - UScriptStruct* Struct = Cast(Pin->PinType.PinSubCategoryObject.Get()); - - if (Struct) + // If looking for references during save, expand any default values on the pins + if (Ar.IsObjectReferenceCollector() && Pin->PinType.PinCategory == UEdGraphSchema_K2::PC_Struct && Pin->PinType.PinSubCategoryObject.IsValid()) { - int32 StructSize = Struct->GetStructureSize(); - uint8* StructData = (uint8*)FMemory::Malloc(StructSize); - - // Import the literal text to a dummy struct and then serialize that - FOutputDeviceNull NullOutput; - Struct->InitializeStruct(StructData); - Struct->ImportText(*Pin->DefaultValue, StructData, nullptr, PPF_None, &NullOutput, Pin->PinName); - Struct->SerializeItem(Ar, StructData, nullptr); - Struct->DestroyStruct(StructData); + UScriptStruct* Struct = Cast(Pin->PinType.PinSubCategoryObject.Get()); - FMemory::Free(StructData); + if (Struct) + { + int32 StructSize = Struct->GetStructureSize(); + uint8* StructData = (uint8*)FMemory::Malloc(StructSize); + + // Import the literal text to a dummy struct and then serialize that + FOutputDeviceNull NullOutput; + Struct->InitializeStruct(StructData); + Struct->ImportText(*Pin->DefaultValue, StructData, nullptr, PPF_None, &NullOutput, Pin->PinName); + Struct->SerializeItem(Ar, StructData, nullptr); + Struct->DestroyStruct(StructData); + + FMemory::Free(StructData); + } + } + + if (Pin->PinType.PinCategory == UEdGraphSchema_K2::PC_Asset || Pin->PinType.PinCategory == UEdGraphSchema_K2::PC_AssetClass) + { + FStringAssetReference TempRef(Pin->DefaultValue); + + // Serialize the asset reference, this will do the save fixup. It won't actually serialize the string if this is a real archive like linkersave + TempRef.SerializePath(Ar, true); + + Pin->DefaultValue = MoveTemp(TempRef.ToString()); } } } } + + Super::Serialize(Ar); + + if (Ar.IsLoading()) + { + // Fix up pin default values, must be done before post load + FixupPinDefaultValues(); + } } void UK2Node::FixupPinDefaultValues() { const int32 LinkerUE4Version = GetLinkerUE4Version(); + const int32 LinkerFrameworkVersion = GetLinkerCustomVersion(FFrameworkObjectVersion::GUID); const UEdGraphSchema_K2* K2Schema = GetDefault(); // Swap "new" default error tolerance value with zero on vector/rotator equality nodes, in order to preserve current behavior in existing blueprints. @@ -140,6 +157,26 @@ void UK2Node::FixupPinDefaultValues() } } } + + // Fix asset ptr pins + if (LinkerFrameworkVersion < FFrameworkObjectVersion::ChangeAssetPinsToString) + { + bool bFoundPin = false; + for (int32 i = 0; i < Pins.Num() && !bFoundPin; ++i) + { + UEdGraphPin* Pin = Pins[i]; + + if (Pin->PinType.PinCategory == K2Schema->PC_Asset || Pin->PinType.PinCategory == K2Schema->PC_AssetClass) + { + if (Pin->DefaultObject && Pin->DefaultValue.IsEmpty()) + { + Pin->DefaultValue = Pin->DefaultObject->GetPathName(); + Pin->DefaultObject = nullptr; + } + } + } + } + } FText UK2Node::GetToolTipHeading() const @@ -186,9 +223,9 @@ bool UK2Node::CreatePinsForFunctionEntryExit(const UFunction* Function, bool bFo { const EEdGraphPinDirection Direction = bForFunctionEntry ? EGPD_Output : EGPD_Input; - UEdGraphPin* Pin = CreatePin(Direction, TEXT(""), TEXT(""), NULL, false, false, Param->GetName()); + UEdGraphPin* Pin = CreatePin(Direction, FString(), FString(), nullptr, Param->GetName()); const bool bPinGood = K2Schema->ConvertPropertyToPinType(Param, /*out*/ Pin->PinType); - K2Schema->SetPinDefaultValueBasedOnType(Pin); + K2Schema->SetPinAutogeneratedDefaultValueBasedOnType(Pin); UK2Node_CallFunction::GeneratePinTooltipFromFunction(*Pin, Function); @@ -339,10 +376,10 @@ void UK2Node::PinConnectionListChanged(UEdGraphPin* Pin) { const UEdGraphSchema_K2* Schema = Cast(GetSchema()); - Pin->ResetDefaultValue(); - if (EEdGraphPinDirection::EGPD_Input == Pin->Direction) + // We don't want to reset Output pin defaults, that breaks Function entry nodes + if (Pin->Direction == EEdGraphPinDirection::EGPD_Input) { - Schema->SetPinDefaultValueBasedOnType(Pin); + Schema->ResetPinToAutogeneratedDefaultValue(Pin); } } } @@ -1007,7 +1044,7 @@ void FOptionalPinManager::RebuildProperty(UProperty* TestProperty, FName Categor } } -void FOptionalPinManager::CreateVisiblePins(TArray& Properties, UStruct* SourceStruct, EEdGraphPinDirection Direction, UK2Node* TargetNode, uint8* StructBasePtr) +void FOptionalPinManager::CreateVisiblePins(TArray& Properties, UStruct* SourceStruct, EEdGraphPinDirection Direction, UK2Node* TargetNode, uint8* StructBasePtr, uint8* DefaultsPtr) { const UEdGraphSchema_K2* Schema = GetDefault(); @@ -1020,7 +1057,7 @@ void FOptionalPinManager::CreateVisiblePins(TArray& Pr // Do we treat an array property as one pin, or a pin per entry in the array? // Depends on if we have an instance of the struct to work with. UArrayProperty* ArrayProperty = Cast(OuterProperty); - if ((ArrayProperty != NULL) && (StructBasePtr != NULL)) + if ((ArrayProperty != nullptr) && (StructBasePtr != nullptr)) { UProperty* InnerProperty = ArrayProperty->Inner; @@ -1054,13 +1091,24 @@ void FOptionalPinManager::CreateVisiblePins(TArray& Pr // Let derived classes take a crack at transferring default values uint8* ValuePtr = ArrayHelper.GetRawPtr(Index); - if (NewPin != NULL) + uint8* DefaultValuePtr = nullptr; + + if (DefaultsPtr) { - PostInitNewPin(NewPin, PropertyEntry, Index, ArrayProperty->Inner, ValuePtr); + FScriptArrayHelper_InContainer DefaultsArrayHelper(ArrayProperty, DefaultsPtr); + + if (DefaultsArrayHelper.IsValidIndex(Index)) + { + DefaultValuePtr = DefaultsArrayHelper.GetRawPtr(Index); + } + } + if (NewPin != nullptr) + { + PostInitNewPin(NewPin, PropertyEntry, Index, ArrayProperty->Inner, ValuePtr, DefaultValuePtr); } else { - PostRemovedOldPin(PropertyEntry, Index, ArrayProperty->Inner, ValuePtr); + PostRemovedOldPin(PropertyEntry, Index, ArrayProperty->Inner, ValuePtr, DefaultValuePtr); } } } @@ -1073,7 +1121,7 @@ void FOptionalPinManager::CreateVisiblePins(TArray& Pr if (Schema->ConvertPropertyToPinType(OuterProperty, /*out*/ PinType)) { // Create the pin - UEdGraphPin* NewPin = NULL; + UEdGraphPin* NewPin = nullptr; if (PropertyEntry.bShowPin) { const FString PinName = PropertyEntry.PropertyName.ToString(); @@ -1088,16 +1136,17 @@ void FOptionalPinManager::CreateVisiblePins(TArray& Pr } // Let derived classes take a crack at transferring default values - if (StructBasePtr != NULL) + if (StructBasePtr != nullptr) { uint8* ValuePtr = OuterProperty->ContainerPtrToValuePtr(StructBasePtr); - if (NewPin != NULL) + uint8* DefaultValuePtr = DefaultsPtr ? OuterProperty->ContainerPtrToValuePtr(DefaultsPtr) : nullptr; + if (NewPin != nullptr) { - PostInitNewPin(NewPin, PropertyEntry, INDEX_NONE, OuterProperty, ValuePtr); + PostInitNewPin(NewPin, PropertyEntry, INDEX_NONE, OuterProperty, ValuePtr, DefaultValuePtr); } else { - PostRemovedOldPin(PropertyEntry, INDEX_NONE, OuterProperty, ValuePtr); + PostRemovedOldPin(PropertyEntry, INDEX_NONE, OuterProperty, ValuePtr, DefaultValuePtr); } } } @@ -1249,8 +1298,8 @@ void UK2Node::GetPinHoverText(const UEdGraphPin& Pin, FString& HoverTextOut) con // grab the debug value of the pin FString WatchText; const FKismetDebugUtilities::EWatchTextResult WatchStatus = FKismetDebugUtilities::GetWatchText(/*inout*/ WatchText, Blueprint, ActiveObject, &Pin); - // if this is an array pin, then we possibly have too many lines (too many entries) - if (Pin.PinType.bIsArray) + // if this is an container pin, then we possibly have too many lines (too many entries) + if (Pin.PinType.IsContainer()) { int32 LineCounter = 0; int32 OriginalWatchTextLen = WatchText.Len(); @@ -1283,7 +1332,7 @@ void UK2Node::GetPinHoverText(const UEdGraphPin& Pin, FString& HoverTextOut) con break; } } - } // if Pin.PinType.bIsArray... + } // if Pin.PinType.IsContainer()... switch (WatchStatus) diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_AddComponent.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_AddComponent.cpp index 86dc60e1950f..19eb60d02e22 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_AddComponent.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_AddComponent.cpp @@ -104,7 +104,7 @@ void UK2Node_AddComponent::AllocatePinsForExposedVariables() const UClass* ComponentClass = GetSpawnedType(); if (ComponentClass != nullptr) { - const UObject* ClassDefaultObject = ComponentClass ? ComponentClass->ClassDefaultObject : nullptr; + const UObject* ClassDefaultObject = ComponentClass->ClassDefaultObject; for (TFieldIterator PropertyIt(ComponentClass, EFieldIteratorFlags::IncludeSuper); PropertyIt; ++PropertyIt) { @@ -120,7 +120,7 @@ void UK2Node_AddComponent::AllocatePinsForExposedVariables() const bool bIsUnique = (NULL == FindPin(Property->GetName())); if (K2Schema->FindSetVariableByNameFunction(PinType) && bIsUnique) { - UEdGraphPin* Pin = CreatePin(EGPD_Input, TEXT(""), TEXT(""), NULL, false, false, Property->GetName()); + UEdGraphPin* Pin = CreatePin(EGPD_Input, FString(), FString(), nullptr, Property->GetName()); Pin->PinType = PinType; bHasExposedVariable = true; @@ -129,7 +129,7 @@ void UK2Node_AddComponent::AllocatePinsForExposedVariables() FString DefaultValueAsString; const bool bDefaultValueSet = FBlueprintEditorUtils::PropertyValueToString(Property, reinterpret_cast(ClassDefaultObject), DefaultValueAsString); check(bDefaultValueSet); - K2Schema->TrySetDefaultValue(*Pin, DefaultValueAsString); + K2Schema->SetPinAutogeneratedDefaultValue(Pin, DefaultValueAsString); } // Copy tooltip from the property. diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_AssignmentStatement.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_AssignmentStatement.cpp index 8bec5c04ff5c..6d534bab046e 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_AssignmentStatement.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_AssignmentStatement.cpp @@ -68,11 +68,11 @@ void UK2Node_AssignmentStatement::AllocateDefaultPins() { const UEdGraphSchema_K2* Schema = GetDefault(); - CreatePin(EGPD_Input, Schema->PC_Exec, TEXT(""), NULL, false, false, Schema->PN_Execute); - CreatePin(EGPD_Output, Schema->PC_Exec, TEXT(""), NULL, false, false, Schema->PN_Then); + CreatePin(EGPD_Input, Schema->PC_Exec, FString(), nullptr, Schema->PN_Execute); + CreatePin(EGPD_Output, Schema->PC_Exec, FString(), nullptr, Schema->PN_Then); - UEdGraphPin* VariablePin = CreatePin(EGPD_Input, Schema->PC_Wildcard, TEXT(""), NULL, false, false, VariablePinName); - UEdGraphPin* ValuePin = CreatePin(EGPD_Input, Schema->PC_Wildcard, TEXT(""), NULL, false, false, ValuePinName); + UEdGraphPin* VariablePin = CreatePin(EGPD_Input, Schema->PC_Wildcard, FString(), nullptr, VariablePinName); + UEdGraphPin* ValuePin = CreatePin(EGPD_Input, Schema->PC_Wildcard, FString(), nullptr, ValuePinName); Super::AllocateDefaultPins(); } diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_BaseAsyncTask.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_BaseAsyncTask.cpp index 54d3de876177..886708b9a418 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_BaseAsyncTask.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_BaseAsyncTask.cpp @@ -65,17 +65,24 @@ void UK2Node_BaseAsyncTask::AllocateDefaultPins() { const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Execute); - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Then); + CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Execute); bool bExposeProxy = false; - for (const UStruct* TestStruct = ProxyClass; TestStruct && !bExposeProxy; TestStruct = TestStruct->GetSuperStruct()) + bool bHideThen = false; + for (const UStruct* TestStruct = ProxyClass; TestStruct; TestStruct = TestStruct->GetSuperStruct()) { - bExposeProxy = TestStruct->HasMetaData(TEXT("ExposedAsyncProxy")); + bExposeProxy |= TestStruct->HasMetaData(TEXT("ExposedAsyncProxy")); + bHideThen |= TestStruct->HasMetaData(TEXT("HideThen")); } + + if (!bHideThen) + { + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Then); + } + if (bExposeProxy) { - CreatePin(EGPD_Output, K2Schema->PC_Object, TEXT(""), ProxyClass, false, false, FBaseAsyncTaskHelper::GetAsyncTaskProxyName()); + CreatePin(EGPD_Output, K2Schema->PC_Object, FString(), ProxyClass, FBaseAsyncTaskHelper::GetAsyncTaskProxyName()); } UFunction* DelegateSignatureFunction = NULL; @@ -83,7 +90,7 @@ void UK2Node_BaseAsyncTask::AllocateDefaultPins() { if (UMulticastDelegateProperty* Property = Cast(*PropertyIt)) { - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, *Property->GetName()); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, *Property->GetName()); if (!DelegateSignatureFunction) { DelegateSignatureFunction = Property->SignatureFunction; @@ -99,7 +106,7 @@ void UK2Node_BaseAsyncTask::AllocateDefaultPins() const bool bIsFunctionInput = !Param->HasAnyPropertyFlags(CPF_OutParm) || Param->HasAnyPropertyFlags(CPF_ReferenceParm); if (bIsFunctionInput) { - UEdGraphPin* Pin = CreatePin(EGPD_Output, TEXT(""), TEXT(""), NULL, false, false, Param->GetName()); + UEdGraphPin* Pin = CreatePin(EGPD_Output, FString(), FString(), nullptr, Param->GetName()); K2Schema->ConvertPropertyToPinType(Param, /*out*/ Pin->PinType); } } @@ -122,13 +129,13 @@ void UK2Node_BaseAsyncTask::AllocateDefaultPins() } const bool bIsRefParam = Param->HasAnyPropertyFlags(CPF_ReferenceParm) && bIsFunctionInput; - UEdGraphPin* Pin = CreatePin(EGPD_Input, TEXT(""), TEXT(""), NULL, false, bIsRefParam, Param->GetName()); + UEdGraphPin* Pin = CreatePin(EGPD_Input, FString(), FString(), nullptr, Param->GetName(), EPinContainerType::None, bIsRefParam); const bool bPinGood = (Pin != NULL) && K2Schema->ConvertPropertyToPinType(Param, /*out*/ Pin->PinType); if (bPinGood) { //Flag pin as read only for const reference property - Pin->bDefaultValueIsIgnored = Param->HasAllPropertyFlags(CPF_ConstParm | CPF_ReferenceParm) && (!Function->HasMetaData(FBlueprintMetadata::MD_AutoCreateRefTerm) || Pin->PinType.bIsArray); + Pin->bDefaultValueIsIgnored = Param->HasAllPropertyFlags(CPF_ConstParm | CPF_ReferenceParm) && (!Function->HasMetaData(FBlueprintMetadata::MD_AutoCreateRefTerm) || Pin->PinType.IsContainer()); const bool bAdvancedPin = Param->HasAllPropertyFlags(CPF_AdvancedDisplay); Pin->bAdvancedView = bAdvancedPin; @@ -137,7 +144,15 @@ void UK2Node_BaseAsyncTask::AllocateDefaultPins() AdvancedPinDisplay = ENodeAdvancedPins::Hidden; } - K2Schema->SetPinDefaultValue(Pin, Function, Param); + FString ParamValue; + if (K2Schema->FindFunctionParameterDefaultValue(Function, Param, ParamValue)) + { + K2Schema->SetPinAutogeneratedDefaultValue(Pin, ParamValue); + } + else + { + K2Schema->SetPinAutogeneratedDefaultValueBasedOnType(Pin); + } if (PinsToHide.Contains(Pin->PinName)) { @@ -316,7 +331,7 @@ void UK2Node_BaseAsyncTask::ExpandNode(class FKismetCompilerContext& CompilerCon { const FEdGraphPinType& PinType = CurrentPin->PinType; UK2Node_TemporaryVariable* TempVarOutput = CompilerContext.SpawnInternalVariable( - this, PinType.PinCategory, PinType.PinSubCategory, PinType.PinSubCategoryObject.Get(), PinType.bIsArray, PinType.bIsSet, PinType.bIsMap, PinType.PinValueType); + this, PinType.PinCategory, PinType.PinSubCategory, PinType.PinSubCategoryObject.Get(), PinType.ContainerType, PinType.PinValueType); bIsErrorFree &= TempVarOutput->GetVariablePin() && CompilerContext.MovePinLinksToIntermediate(*CurrentPin, *TempVarOutput->GetVariablePin()).CanSafeConnect(); VariableOutputs.Add(FBaseAsyncTaskHelper::FOutputPinAndLocalVariable(CurrentPin, TempVarOutput)); } @@ -374,7 +389,13 @@ void UK2Node_BaseAsyncTask::ExpandNode(class FKismetCompilerContext& CompilerCon } // Move the connections from the original node then pin to the last internal then pin - bIsErrorFree &= CompilerContext.MovePinLinksToIntermediate(*FindPinChecked(Schema->PN_Then), *LastThenPin).CanSafeConnect(); + + UEdGraphPin* OriginalThenPin = FindPin(Schema->PN_Then); + + if (OriginalThenPin) + { + bIsErrorFree &= CompilerContext.MovePinLinksToIntermediate(*OriginalThenPin, *LastThenPin).CanSafeConnect(); + } bIsErrorFree &= CompilerContext.CopyPinLinksToIntermediate(*LastThenPin, *ValidateProxyNode->GetElsePin()).CanSafeConnect(); if (!bIsErrorFree) @@ -446,12 +467,20 @@ UFunction* UK2Node_BaseAsyncTask::GetFactoryFunction() const } UFunction* FactoryFunction = ProxyFactoryClass->FindFunctionByName(ProxyFactoryFunctionName); - check(FactoryFunction); + + if (FactoryFunction == nullptr) + { + UE_LOG(LogBlueprint, Error, TEXT("FactoryFunction %s null in %s. Was a class deleted or saved on a non promoted build?"), *ProxyFactoryFunctionName.ToString(), *GetFullName()); + return nullptr; + } + return FactoryFunction; } void UK2Node_BaseAsyncTask::ValidateNodeDuringCompilation(class FCompilerResultsLog& MessageLog) const { + Super::ValidateNodeDuringCompilation(MessageLog); + UEdGraphSchema_K2 const* K2Schema = GetDefault(); if(UObject const* SourceObject = MessageLog.FindSourceObject(this)) diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_BitmaskLiteral.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_BitmaskLiteral.cpp index b7e98d4447a5..33eabf8d3a7c 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_BitmaskLiteral.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_BitmaskLiteral.cpp @@ -29,6 +29,7 @@ UK2Node_BitmaskLiteral::UK2Node_BitmaskLiteral(const FObjectInitializer& ObjectI void UK2Node_BitmaskLiteral::ValidateBitflagsEnumType() { + const UEdGraphSchema_K2* Schema = GetDefault(); if (BitflagsEnum != nullptr) { // Reset enum type reference if it no longer has the proper meta data. @@ -71,7 +72,7 @@ void UK2Node_BitmaskLiteral::ValidateBitflagsEnumType() const int32 NewDefaultValue = OldDefaultValue & ValidBitflagsMask; if (NewDefaultValue != OldDefaultValue) { - InputPin->GetSchema()->TrySetDefaultValue(*InputPin, FString::FromInt(NewDefaultValue)); + Schema->SetPinAutogeneratedDefaultValue(InputPin, FString::FromInt(NewDefaultValue)); } } } @@ -84,6 +85,12 @@ void UK2Node_BitmaskLiteral::Serialize(FArchive& Ar) // Post-load validation of the enum type. if (Ar.IsLoading() && Ar.IsPersistent() && !Ar.HasAnyPortFlags(PPF_Duplicate | PPF_DuplicateForPIE)) { + // If valid, ensure that the enum type is loaded. + if (BitflagsEnum != nullptr) + { + Ar.Preload(BitflagsEnum); + } + ValidateBitflagsEnumType(); } } @@ -92,10 +99,10 @@ void UK2Node_BitmaskLiteral::AllocateDefaultPins() { const UEdGraphSchema_K2* Schema = GetDefault(); - UEdGraphPin* InputPin = CreatePin(EGPD_Input, Schema->PC_Int, Schema->PSC_Bitmask, BitflagsEnum, false, false, GetBitmaskInputPinName()); - Schema->SetPinDefaultValueBasedOnType(InputPin); + UEdGraphPin* InputPin = CreatePin(EGPD_Input, Schema->PC_Int, Schema->PSC_Bitmask, BitflagsEnum, GetBitmaskInputPinName()); + Schema->SetPinAutogeneratedDefaultValueBasedOnType(InputPin); - CreatePin(EGPD_Output, Schema->PC_Int, Schema->PSC_Bitmask, BitflagsEnum, false, false, Schema->PN_ReturnValue); + CreatePin(EGPD_Output, Schema->PC_Int, Schema->PSC_Bitmask, BitflagsEnum, Schema->PN_ReturnValue); Super::AllocateDefaultPins(); } diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_BreakStruct.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_BreakStruct.cpp index e04dc8be5923..f64c885ecf72 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_BreakStruct.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_BreakStruct.cpp @@ -182,7 +182,7 @@ void UK2Node_BreakStruct::AllocateDefaultPins() if(Schema && StructType) { PreloadObject(StructType); - CreatePin(EGPD_Input, Schema->PC_Struct, TEXT(""), StructType, false, true, StructType->GetName(), true); + CreatePin(EGPD_Input, Schema->PC_Struct, FString(), StructType, StructType->GetName(), EPinContainerType::None, true, true); struct FBreakStructPinManager : public FStructOperationOptionalPinManager { diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CallArrayFunction.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CallArrayFunction.cpp index 397ba8d785e5..79c8c6a265f1 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CallArrayFunction.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CallArrayFunction.cpp @@ -21,11 +21,11 @@ void UK2Node_CallArrayFunction::AllocateDefaultPins() UEdGraphPin* TargetArrayPin = GetTargetArrayPin(); if (ensure(TargetArrayPin)) { - TargetArrayPin->PinType.bIsArray = true; + TargetArrayPin->PinType.ContainerType = EPinContainerType::Array; TargetArrayPin->PinType.bIsReference = true; TargetArrayPin->PinType.PinCategory = Schema->PC_Wildcard; - TargetArrayPin->PinType.PinSubCategory = TEXT(""); - TargetArrayPin->PinType.PinSubCategoryObject = NULL; + TargetArrayPin->PinType.PinSubCategory.Reset(); + TargetArrayPin->PinType.PinSubCategoryObject = nullptr; } TArray< FArrayPropertyPinCombo > ArrayPins; @@ -88,7 +88,7 @@ void UK2Node_CallArrayFunction::NotifyPinConnectionListChanged(UEdGraphPin* Pin) { UEdGraphPin* LinkedTo = Pin->LinkedTo[0]; check(LinkedTo); - check(Pin->PinType.bIsArray == LinkedTo->PinType.bIsArray); + check(Pin->PinType.ContainerType == LinkedTo->PinType.ContainerType); Pin->PinType.PinCategory = LinkedTo->PinType.PinCategory; Pin->PinType.PinSubCategory = LinkedTo->PinType.PinSubCategory; @@ -121,6 +121,7 @@ void UK2Node_CallArrayFunction::NotifyPinConnectionListChanged(UEdGraphPin* Pin) if (bNeedToPropagate) { PropagateArrayTypeInfo(Pin); + GetGraph()->NotifyGraphChanged(); } } } @@ -159,9 +160,9 @@ void UK2Node_CallArrayFunction::ConvertDeprecatedNode(UEdGraph* Graph, bool bOnl else if (Pin->PinName == UEdGraphSchema_K2::PN_Self) { // there's no analogous pin, signal that we're expecting this - OldToNewPinMap.Add(Pin->PinName, TEXT("")); + OldToNewPinMap.Add(Pin->PinName, FString()); } - else if (Pin->PinType.bIsArray) + else if (Pin->PinType.IsArray()) { OldToNewPinMap.Add(Pin->PinName, GetItemNode->GetTargetArrayPin()->PinName); } @@ -312,7 +313,7 @@ void UK2Node_CallArrayFunction::PropagateArrayTypeInfo(const UEdGraphPin* Source // Reset default values if (!Schema->IsPinDefaultValid(CurrentPin, CurrentPin->DefaultValue, CurrentPin->DefaultObject, CurrentPin->DefaultTextValue).IsEmpty()) { - CurrentPin->ResetDefaultValue(); + Schema->ResetPinToAutogeneratedDefaultValue(CurrentPin); } } } diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CallFunction.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CallFunction.cpp index 61af89a7cf4e..9ad2037fed24 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CallFunction.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CallFunction.cpp @@ -68,16 +68,15 @@ struct FCustomStructureParamHelper { UEdGraphPin* LinkedTo = Pin->LinkedTo[0]; check(LinkedTo); - ensure(!LinkedTo->PinType.bIsArray); + ensure(!LinkedTo->PinType.IsContainer()); Pin->PinType = LinkedTo->PinType; } else { - const UEdGraphSchema_K2* Schema = GetDefault(); - Pin->PinType.PinCategory = Schema->PC_Wildcard; - Pin->PinType.PinSubCategory = TEXT(""); - Pin->PinType.PinSubCategoryObject = NULL; + Pin->PinType.PinCategory = UEdGraphSchema_K2::PC_Wildcard; + Pin->PinType.PinSubCategory.Reset(); + Pin->PinType.PinSubCategoryObject = nullptr; } } } @@ -97,9 +96,9 @@ struct FCustomStructureParamHelper } else { - for (auto& Name : Names) + for (const FString& Name : Names) { - if (auto Pin = Node->FindPin(Name)) + if (UEdGraphPin* Pin = Node->FindPin(Name)) { HandleSinglePin(Pin); } @@ -549,7 +548,7 @@ void UK2Node_CallFunction::GetPinHoverText(const UEdGraphPin& Pin, FString& Hove { if (!bPinTooltipsValid) { - for (auto& P : Pins) + for (UEdGraphPin* P : Pins) { P->PinToolTip.Empty(); GeneratePinTooltip(*P); @@ -643,10 +642,9 @@ void UK2Node_CallFunction::AllocateDefaultPins() /** Util to find self pin in an array */ UEdGraphPin* FindSelfPin(TArray& Pins) { - const UEdGraphSchema_K2* K2Schema = GetDefault(); for(int32 PinIdx=0; PinIdxPinName == K2Schema->PN_Self) + if(Pins[PinIdx]->PinName == UEdGraphSchema_K2::PN_Self) { return Pins[PinIdx]; } @@ -682,11 +680,9 @@ void UK2Node_CallFunction::ReallocatePinsDuringReconstruction(TArray(); - // Chase up the function's Super chain, the function can be called on any object that is at least that specific const UFunction* FirstDeclaredFunction = Function; - while (FirstDeclaredFunction->GetSuperFunction() != NULL) + while (FirstDeclaredFunction->GetSuperFunction() != nullptr) { FirstDeclaredFunction = FirstDeclaredFunction->GetSuperFunction(); } @@ -707,18 +703,18 @@ UEdGraphPin* UK2Node_CallFunction::CreateSelfPin(const UFunction* Function) if (FunctionClass == GetBlueprint()->GeneratedClass) { // This means the function is defined within the blueprint, so the pin should be a true "self" pin - SelfPin = CreatePin(EGPD_Input, K2Schema->PC_Object, K2Schema->PSC_Self, NULL, false, false, K2Schema->PN_Self); + SelfPin = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Object, UEdGraphSchema_K2::PSC_Self, nullptr, UEdGraphSchema_K2::PN_Self); } else if (FunctionClass->IsChildOf(UInterface::StaticClass())) { - SelfPin = CreatePin(EGPD_Input, K2Schema->PC_Interface, TEXT(""), FunctionClass, false, false, K2Schema->PN_Self); + SelfPin = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Interface, FString(), FunctionClass, UEdGraphSchema_K2::PN_Self); } else { // This means that the function is declared in an external class, and should reference that class - SelfPin = CreatePin(EGPD_Input, K2Schema->PC_Object, TEXT(""), FunctionClass, false, false, K2Schema->PN_Self); + SelfPin = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Object, FString(), FunctionClass, UEdGraphSchema_K2::PN_Self); } - check(SelfPin != NULL); + check(SelfPin != nullptr); return SelfPin; } @@ -731,8 +727,6 @@ void UK2Node_CallFunction::CreateExecPinsForFunctionCall(const UFunction* Functi // If not pure, create exec pins if (!bIsPureFunc) { - const UEdGraphSchema_K2* K2Schema = GetDefault(); - // If we want enum->exec expansion, and it is not disabled, do it now if(bWantsEnumToExecExpansion) { @@ -767,7 +761,7 @@ void UK2Node_CallFunction::CreateExecPinsForFunctionCall(const UFunction* Functi if (!bShouldBeHidden) { FString ExecName = Enum->GetNameStringByIndex(ExecIdx); - CreatePin(Direction, K2Schema->PC_Exec, TEXT(""), NULL, false, false, ExecName); + CreatePin(Direction, UEdGraphSchema_K2::PC_Exec, FString(), nullptr, ExecName); } } @@ -787,16 +781,16 @@ void UK2Node_CallFunction::CreateExecPinsForFunctionCall(const UFunction* Functi if (bCreateSingleExecInputPin) { // Single input exec pin - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Execute); + CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Exec, FString(), nullptr, UEdGraphSchema_K2::PN_Execute); } if (bCreateThenPin) { - UEdGraphPin* OutputExecPin = CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Then); + UEdGraphPin* OutputExecPin = CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, FString(), nullptr, UEdGraphSchema_K2::PN_Then); // Use 'completed' name for output pins on latent functions if (Function->HasMetaData(FBlueprintMetadata::MD_Latent)) { - OutputExecPin->PinFriendlyName = FText::FromString(K2Schema->PN_Completed); + OutputExecPin->PinFriendlyName = FText::FromString(UEdGraphSchema_K2::PN_Completed); } } } @@ -926,7 +920,7 @@ bool UK2Node_CallFunction::CreatePinsForFunctionCall(const UFunction* Function) const EEdGraphPinDirection Direction = bIsFunctionInput ? EGPD_Input : EGPD_Output; - UEdGraphPin* Pin = CreatePin(Direction, TEXT(""), TEXT(""), NULL, false, bIsRefParam, Param->GetName()); + UEdGraphPin* Pin = CreatePin(Direction, FString(), FString(), nullptr, Param->GetName(), EPinContainerType::None, bIsRefParam); const bool bPinGood = (Pin != NULL) && K2Schema->ConvertPropertyToPinType(Param, /*out*/ Pin->PinType); if (bPinGood) @@ -939,7 +933,7 @@ bool UK2Node_CallFunction::CreatePinsForFunctionCall(const UFunction* Function) } //Flag pin as read only for const reference property - Pin->bDefaultValueIsIgnored = Param->HasAllPropertyFlags(CPF_ConstParm | CPF_ReferenceParm) && (!Function->HasMetaData(FBlueprintMetadata::MD_AutoCreateRefTerm) || Pin->PinType.bIsArray); + Pin->bDefaultValueIsIgnored = Param->HasAllPropertyFlags(CPF_ConstParm | CPF_ReferenceParm) && (!Function->HasMetaData(FBlueprintMetadata::MD_AutoCreateRefTerm) || Pin->PinType.IsContainer()); const bool bAdvancedPin = Param->HasAllPropertyFlags(CPF_AdvancedDisplay); Pin->bAdvancedView = bAdvancedPin; @@ -948,7 +942,15 @@ bool UK2Node_CallFunction::CreatePinsForFunctionCall(const UFunction* Function) AdvancedPinDisplay = ENodeAdvancedPins::Hidden; } - K2Schema->SetPinDefaultValue(Pin, Function, Param); + FString ParamValue; + if (K2Schema->FindFunctionParameterDefaultValue(Function, Param, ParamValue)) + { + K2Schema->SetPinAutogeneratedDefaultValue(Pin, ParamValue); + } + else + { + K2Schema->SetPinAutogeneratedDefaultValueBasedOnType(Pin); + } if (PinsToHide.Contains(Pin->PinName)) { @@ -993,12 +995,11 @@ void UK2Node_CallFunction::PostReconstructNode() FCustomStructureParamHelper::UpdateCustomStructurePins(GetTargetFunction(), this); - const UEdGraphSchema_K2* K2Schema = GetDefault(); // Fixup self node, may have been overridden from old self node UFunction* Function = GetTargetFunction(); const bool bIsStaticFunc = Function ? Function->HasAllFunctionFlags(FUNC_Static) : false; - UEdGraphPin* SelfPin = FindPin(K2Schema->PN_Self); + UEdGraphPin* SelfPin = FindPin(UEdGraphSchema_K2::PN_Self); if (bIsStaticFunc && SelfPin) { // Wire up the self to the CDO of the class if it's not us @@ -1102,19 +1103,15 @@ UFunction* UK2Node_CallFunction::GetTargetFunctionFromSkeletonClass() const UEdGraphPin* UK2Node_CallFunction::GetThenPin() const { - const UEdGraphSchema_K2* K2Schema = GetDefault(); - - UEdGraphPin* Pin = FindPin(K2Schema->PN_Then); - check(Pin == NULL || Pin->Direction == EGPD_Output); // If pin exists, it must be output + UEdGraphPin* Pin = FindPin(UEdGraphSchema_K2::PN_Then); + check(Pin == nullptr || Pin->Direction == EGPD_Output); // If pin exists, it must be output return Pin; } UEdGraphPin* UK2Node_CallFunction::GetReturnValuePin() const { - const UEdGraphSchema_K2* K2Schema = GetDefault(); - - UEdGraphPin* Pin = FindPin(K2Schema->PN_ReturnValue); - check(Pin == NULL || Pin->Direction == EGPD_Output); // If pin exists, it must be output + UEdGraphPin* Pin = FindPin(UEdGraphSchema_K2::PN_ReturnValue); + check(Pin == nullptr || Pin->Direction == EGPD_Output); // If pin exists, it must be output return Pin; } @@ -1762,7 +1759,7 @@ void UK2Node_CallFunction::PostPasteNode() if (bPinShouldBeHidden && !Pin->bHidden) { Pin->BreakAllPinLinks(); - K2Schema->SetPinDefaultValueBasedOnType(Pin); + K2Schema->SetPinAutogeneratedDefaultValueBasedOnType(Pin); } Pin->bHidden = bPinShouldBeHidden; } @@ -1814,8 +1811,7 @@ void UK2Node_CallFunction::ValidateNodeDuringCompilation(class FCompilerResultsL { // emit warning if we are in a construction script UEdGraph const* const Graph = GetGraph(); - UEdGraphSchema_K2 const* const Schema = Cast(GetSchema()); - bool bNodeIsInConstructionScript = Schema && Schema->IsConstructionScript(Graph); + bool bNodeIsInConstructionScript = UEdGraphSchema_K2::IsConstructionScript(Graph); if (bNodeIsInConstructionScript == false) { @@ -1830,7 +1826,7 @@ void UK2Node_CallFunction::ValidateNodeDuringCompilation(class FCompilerResultsL if (Node) { UFunction* const SignatureFunction = FindField(Node->SignatureClass, Node->SignatureName); - bNodeIsInConstructionScript = SignatureFunction && (SignatureFunction->GetFName() == Schema->FN_UserConstructionScript); + bNodeIsInConstructionScript = SignatureFunction && (SignatureFunction->GetFName() == UEdGraphSchema_K2::FN_UserConstructionScript); } } } @@ -1963,7 +1959,7 @@ void UK2Node_CallFunction::ExpandNode(class FKismetCompilerContext& CompilerCont { CompilerContext.MessageLog.Warning(*FString::Printf(*LOCTEXT("WrongEntryPointsNum", "%i entry points found while expanding node @@").ToString(), EntryPoints.Num()), this); } - else if (auto BetterSelfPin = EntryPoints[0]->GetAutoWorldContextPin()) + else if (UEdGraphPin* BetterSelfPin = EntryPoints[0]->GetAutoWorldContextPin()) { FString const DefaultToSelfMetaValue = Function->GetMetaData(FBlueprintMetadata::MD_DefaultToSelf); FString const WorldContextMetaValue = Function->GetMetaData(FBlueprintMetadata::MD_WorldContext); @@ -1972,7 +1968,7 @@ void UK2Node_CallFunction::ExpandNode(class FKismetCompilerContext& CompilerCont { static void Connect(const FString& PinName, UK2Node* Node, UEdGraphPin* BetterSelf, const UEdGraphSchema_K2* InSchema, FCompilerResultsLog& MessageLog) { - auto Pin = Node->FindPin(PinName); + UEdGraphPin* Pin = Node->FindPin(PinName); if (!PinName.IsEmpty() && Pin && !Pin->LinkedTo.Num()) { const bool bConnected = InSchema->TryCreateConnection(Pin, BetterSelf); @@ -2017,7 +2013,7 @@ void UK2Node_CallFunction::ExpandNode(class FKismetCompilerContext& CompilerCont if (EnumParamPin->Direction == EGPD_Input) { // Create normal exec input - UEdGraphPin* ExecutePin = CreatePin(EGPD_Input, Schema->PC_Exec, TEXT(""), NULL, false, false, Schema->PN_Execute); + UEdGraphPin* ExecutePin = CreatePin(EGPD_Input, Schema->PC_Exec, FString(), nullptr, Schema->PN_Execute); // Create temp enum variable UK2Node_TemporaryVariable* TempEnumVarNode = CompilerContext.SpawnIntermediateNode(this, SourceGraph); @@ -2065,7 +2061,7 @@ void UK2Node_CallFunction::ExpandNode(class FKismetCompilerContext& CompilerCont else if (EnumParamPin->Direction == EGPD_Output) { // Create normal exec output - UEdGraphPin* ExecutePin = CreatePin(EGPD_Output, Schema->PC_Exec, TEXT(""), NULL, false, false, Schema->PN_Execute); + UEdGraphPin* ExecutePin = CreatePin(EGPD_Output, Schema->PC_Exec, FString(), nullptr, Schema->PN_Execute); // Create a SwitchEnum node to switch on the output enum UK2Node_SwitchEnum* SwitchEnumNode = CompilerContext.SpawnIntermediateNode(this, SourceGraph); @@ -2127,19 +2123,19 @@ void UK2Node_CallFunction::ExpandNode(class FKismetCompilerContext& CompilerCont { const bool bHasDefaultValue = !Pin->DefaultValue.IsEmpty() || Pin->DefaultObject || !Pin->DefaultTextValue.IsEmpty(); - //default values can be reset when the pin is connected - const auto DefaultValue = Pin->DefaultValue; - const auto DefaultObject = Pin->DefaultObject; - const auto DefaultTextValue = Pin->DefaultTextValue; - const auto AutogeneratedDefaultValue = Pin->AutogeneratedDefaultValue; + // copy defaults as default values can be reset when the pin is connected + const FString DefaultValue = Pin->DefaultValue; + UObject* DefaultObject = Pin->DefaultObject; + const FText DefaultTextValue = Pin->DefaultTextValue; + bool bMatchesDefaults = Pin->DoesDefaultValueMatchAutogenerated(); UEdGraphPin* ValuePin = InnerHandleAutoCreateRef(this, Pin, CompilerContext, SourceGraph, bHasDefaultValue); if ( ValuePin ) { - if (!DefaultObject && DefaultTextValue.IsEmpty() && DefaultValue.Equals(AutogeneratedDefaultValue, ESearchCase::CaseSensitive)) + if (bMatchesDefaults) { // Use the latest code to set default value - Schema->SetPinDefaultValueBasedOnType(ValuePin); + Schema->SetPinAutogeneratedDefaultValueBasedOnType(ValuePin); } else { @@ -2163,12 +2159,12 @@ void UK2Node_CallFunction::ExpandNode(class FKismetCompilerContext& CompilerCont // Then we go through and expand out array iteration if necessary const bool bAllowMultipleSelfs = AllowMultipleSelfs(true); UEdGraphPin* MultiSelf = Schema->FindSelfPin(*this, EEdGraphPinDirection::EGPD_Input); - if(bAllowMultipleSelfs && MultiSelf && !MultiSelf->PinType.bIsArray) + if(bAllowMultipleSelfs && MultiSelf && !MultiSelf->PinType.IsArray()) { const bool bProperInputToExpandForEach = (1 == MultiSelf->LinkedTo.Num()) && (NULL != MultiSelf->LinkedTo[0]) && - (MultiSelf->LinkedTo[0]->PinType.bIsArray); + (MultiSelf->LinkedTo[0]->PinType.IsArray()); if(bProperInputToExpandForEach) { CallForEachElementInArrayExpansion(this, MultiSelf, CompilerContext, SourceGraph); @@ -2178,7 +2174,7 @@ void UK2Node_CallFunction::ExpandNode(class FKismetCompilerContext& CompilerCont UEdGraphPin* UK2Node_CallFunction::InnerHandleAutoCreateRef(UK2Node* Node, UEdGraphPin* Pin, FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph, bool bForceAssignment) { - const bool bAddAssigment = !Pin->PinType.bIsArray && bForceAssignment; + const bool bAddAssigment = !Pin->PinType.IsContainer() && bForceAssignment; // ADD LOCAL VARIABLE UK2Node_TemporaryVariable* LocalVariable = CompilerContext.SpawnIntermediateNode(Node, SourceGraph); @@ -2190,7 +2186,7 @@ UEdGraphPin* UK2Node_CallFunction::InnerHandleAutoCreateRef(UK2Node* Node, UEdGr if (!CompilerContext.GetSchema()->TryCreateConnection(LocalVariable->GetVariablePin(), Pin)) { CompilerContext.MessageLog.Error(*LOCTEXT("AutoCreateRefTermPin_NotConnected", "AutoCreateRefTerm Expansion: Pin @@ cannot be connected to @@").ToString(), LocalVariable->GetVariablePin(), Pin); - return NULL; + return nullptr; } } // ADD ASSIGMENT @@ -2200,18 +2196,18 @@ UEdGraphPin* UK2Node_CallFunction::InnerHandleAutoCreateRef(UK2Node* Node, UEdGr UK2Node_PureAssignmentStatement* AssignDefaultValue = CompilerContext.SpawnIntermediateNode(Node, SourceGraph); AssignDefaultValue->AllocateDefaultPins(); const bool bVariableConnected = CompilerContext.GetSchema()->TryCreateConnection(AssignDefaultValue->GetVariablePin(), LocalVariable->GetVariablePin()); - auto AssignInputPit = AssignDefaultValue->GetValuePin(); + UEdGraphPin* AssignInputPit = AssignDefaultValue->GetValuePin(); const bool bPreviousInputSaved = AssignInputPit && CompilerContext.MovePinLinksToIntermediate(*Pin, *AssignInputPit).CanSafeConnect(); const bool bOutputConnected = CompilerContext.GetSchema()->TryCreateConnection(AssignDefaultValue->GetOutputPin(), Pin); if (!bVariableConnected || !bOutputConnected || !bPreviousInputSaved) { CompilerContext.MessageLog.Error(*LOCTEXT("AutoCreateRefTermPin_AssignmentError", "AutoCreateRefTerm Expansion: Assignment Error @@").ToString(), AssignDefaultValue); - return NULL; + return nullptr; } - CompilerContext.GetSchema()->SetPinDefaultValueBasedOnType(AssignDefaultValue->GetValuePin()); + CompilerContext.GetSchema()->SetPinAutogeneratedDefaultValueBasedOnType(AssignDefaultValue->GetValuePin()); return AssignInputPit; } - return NULL; + return nullptr; } void UK2Node_CallFunction::CallForEachElementInArrayExpansion(UK2Node* Node, UEdGraphPin* MultiSelf, FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) @@ -2221,7 +2217,7 @@ void UK2Node_CallFunction::CallForEachElementInArrayExpansion(UK2Node* Node, UEd const bool bProperInputToExpandForEach = (1 == MultiSelf->LinkedTo.Num()) && (NULL != MultiSelf->LinkedTo[0]) && - (MultiSelf->LinkedTo[0]->PinType.bIsArray); + (MultiSelf->LinkedTo[0]->PinType.IsArray()); ensure(bProperInputToExpandForEach); UEdGraphPin* ThenPin = Node->FindPinChecked(Schema->PN_Then); @@ -2317,11 +2313,10 @@ bool UK2Node_CallFunction::ReconnectPureExecPins(TArray& OldPins) if (IsNodePure()) { // look for an old exec pin - const UEdGraphSchema_K2* K2Schema = GetDefault(); UEdGraphPin* PinExec = nullptr; for (int32 PinIdx = 0; PinIdx < OldPins.Num(); PinIdx++) { - if (OldPins[PinIdx]->PinName == K2Schema->PN_Execute) + if (OldPins[PinIdx]->PinName == UEdGraphSchema_K2::PN_Execute) { PinExec = OldPins[PinIdx]; break; @@ -2333,7 +2328,7 @@ bool UK2Node_CallFunction::ReconnectPureExecPins(TArray& OldPins) UEdGraphPin* PinThen = nullptr; for (int32 PinIdx = 0; PinIdx < OldPins.Num(); PinIdx++) { - if (OldPins[PinIdx]->PinName == K2Schema->PN_Then) + if (OldPins[PinIdx]->PinName == UEdGraphSchema_K2::PN_Then) { PinThen = OldPins[PinIdx]; break; @@ -2371,7 +2366,7 @@ void UK2Node_CallFunction::ConformContainerPins() { if (Pin && !bOutPropagated) { - if (Pin->LinkedTo.Num() != 0 || Pin->DefaultValue != Pin->AutogeneratedDefaultValue) + if (Pin->LinkedTo.Num() != 0 || !Pin->DoesDefaultValueMatchAutogenerated()) { bOutPropagated = true; if (Pin->LinkedTo.Num() != 0) @@ -2390,7 +2385,7 @@ void UK2Node_CallFunction::ConformContainerPins() { if (Pin && !bOutPropagated) { - if (Pin->LinkedTo.Num() != 0 || Pin->DefaultValue != Pin->AutogeneratedDefaultValue) + if (Pin->LinkedTo.Num() != 0 || !Pin->DoesDefaultValueMatchAutogenerated()) { bOutPropagated = true; if (Pin->LinkedTo.Num() != 0) @@ -2597,7 +2592,7 @@ bool UK2Node_CallFunction::HasExternalDependencies(TArray* Optio } // All structures, that are required for the BP compilation, should be gathered - for(auto Pin : Pins) + for (UEdGraphPin* Pin : Pins) { UStruct* DepStruct = Pin ? Cast(Pin->PinType.PinSubCategoryObject.Get()) : nullptr; @@ -2743,21 +2738,15 @@ bool UK2Node_CallFunction::IsConnectionDisallowed(const UEdGraphPin* MyPin, cons } else if (UFunction* TargetFunction = GetTargetFunction()) { - if( - // Strictly speaking this first check is not needed, but by not disabling the connection here we get a better reason later: - ( ( FEdGraphUtilities::IsSetParam(TargetFunction, MyPin->PinName) && - (OtherPin->PinType.IsContainer() && !MyPin->PinType.bIsSet) ) || - ( FEdGraphUtilities::IsMapParam(TargetFunction, MyPin->PinName) && - (OtherPin->PinType.IsContainer() && !MyPin->PinType.bIsMap) ) || - ( FEdGraphUtilities::IsArrayDependentParam(TargetFunction, MyPin->PinName) && - (OtherPin->PinType.IsContainer() && !MyPin->PinType.bIsArray) ) + if (// Strictly speaking this first check is not needed, but by not disabling the connection here we get a better reason later: + ( OtherPin->PinType.IsContainer() + // make sure we don't allow connections of mismatched container types (e.g. maps to arrays) + && (OtherPin->PinType.ContainerType != MyPin->PinType.ContainerType) + && ( + (FEdGraphUtilities::IsSetParam(TargetFunction, MyPin->PinName) && !MyPin->PinType.IsSet()) || + (FEdGraphUtilities::IsMapParam(TargetFunction, MyPin->PinName) && !MyPin->PinType.IsMap()) || + (FEdGraphUtilities::IsArrayDependentParam(TargetFunction, MyPin->PinName) && !MyPin->PinType.IsArray()) ) - && - // make sure we don't allow connections of mismatched container types (e.g. maps to arrays) - ( - OtherPin->PinType.bIsMap != MyPin->PinType.bIsMap || - OtherPin->PinType.bIsSet != MyPin->PinType.bIsSet || - OtherPin->PinType.bIsArray != MyPin->PinType.bIsArray ) ) { diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CallFunctionOnMember.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CallFunctionOnMember.cpp index 86e6a9027493..0bc947566f68 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CallFunctionOnMember.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CallFunctionOnMember.cpp @@ -20,18 +20,18 @@ UEdGraphPin* UK2Node_CallFunctionOnMember::CreateSelfPin(const UFunction* Functi { const UEdGraphSchema_K2* K2Schema = GetDefault(); - UEdGraphPin* SelfPin = NULL; + UEdGraphPin* SelfPin = nullptr; if (MemberVariableToCallOn.IsSelfContext()) { // This means the function is defined within the blueprint, so the pin should be a true "self" pin - SelfPin = CreatePin(EGPD_Input, K2Schema->PC_Object, K2Schema->PSC_Self, NULL, false, false, K2Schema->PN_Self); + SelfPin = CreatePin(EGPD_Input, K2Schema->PC_Object, K2Schema->PSC_Self, nullptr, K2Schema->PN_Self); } else { // This means that the function is declared in an external class, and should reference that class - SelfPin = CreatePin(EGPD_Input, K2Schema->PC_Object, TEXT(""), MemberVariableToCallOn.GetMemberParentClass(GetBlueprintClassFromNode()), false, false, K2Schema->PN_Self); + SelfPin = CreatePin(EGPD_Input, K2Schema->PC_Object, FString(), MemberVariableToCallOn.GetMemberParentClass(GetBlueprintClassFromNode()), K2Schema->PN_Self); } - check(SelfPin != NULL); + check(SelfPin); return SelfPin; } diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CastByteToEnum.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CastByteToEnum.cpp index 2fdd6e5344a0..463850efdc8b 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CastByteToEnum.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CastByteToEnum.cpp @@ -32,8 +32,8 @@ void UK2Node_CastByteToEnum::AllocateDefaultPins() { const UEdGraphSchema_K2* Schema = GetDefault(); - CreatePin(EGPD_Input, Schema->PC_Byte, TEXT(""), NULL, false, false, ByteInputPinName); - CreatePin(EGPD_Output, Schema->PC_Byte, TEXT(""), Enum, false, false, Schema->PN_ReturnValue); + CreatePin(EGPD_Input, Schema->PC_Byte, FString(), nullptr, ByteInputPinName); + CreatePin(EGPD_Output, Schema->PC_Byte, FString(), Enum, Schema->PN_ReturnValue); } FText UK2Node_CastByteToEnum::GetTooltipText() const diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_ClassDynamicCast.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_ClassDynamicCast.cpp index 90d389faeb94..4632af44590a 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_ClassDynamicCast.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_ClassDynamicCast.cpp @@ -42,24 +42,24 @@ void UK2Node_ClassDynamicCast::AllocateDefaultPins() if (!bIsPureCast) { // Input - Execution Pin - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Execute); + CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Execute); // Output - Execution Pins - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_CastSucceeded); - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_CastFailed); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_CastSucceeded); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_CastFailed); } // Input - Source type Pin - CreatePin(EGPD_Input, K2Schema->PC_Class, TEXT(""), UObject::StaticClass(), false, false, FClassDynamicCastHelper::GetClassToCastName()); + CreatePin(EGPD_Input, K2Schema->PC_Class, FString(), UObject::StaticClass(), FClassDynamicCastHelper::GetClassToCastName()); // Output - Data Pin if (TargetType != NULL) { const FString CastResultPinName = K2Schema->PN_CastedValuePrefix + TargetType->GetDisplayNameText().ToString(); - CreatePin(EGPD_Output, K2Schema->PC_Class, TEXT(""), *TargetType, false, false, CastResultPinName); + CreatePin(EGPD_Output, K2Schema->PC_Class, FString(), *TargetType, CastResultPinName); } - UEdGraphPin* BoolSuccessPin = CreatePin(EGPD_Output, K2Schema->PC_Boolean, TEXT(""), nullptr, /*bIsArray =*/false, /*bIsReference =*/false, FClassDynamicCastHelper::CastSuccessPinName); + UEdGraphPin* BoolSuccessPin = CreatePin(EGPD_Output, K2Schema->PC_Boolean, FString(), nullptr, FClassDynamicCastHelper::CastSuccessPinName); BoolSuccessPin->bHidden = !bIsPureCast; UK2Node::AllocateDefaultPins(); diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CommutativeAssociativeBinaryOperator.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CommutativeAssociativeBinaryOperator.cpp index da77d35d068f..c0976cca1d85 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CommutativeAssociativeBinaryOperator.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CommutativeAssociativeBinaryOperator.cpp @@ -156,13 +156,11 @@ void UK2Node_CommutativeAssociativeBinaryOperator::AddInputPinInner(int32 Additi InputType.PinCategory, InputType.PinSubCategory, InputType.PinSubCategoryObject.Get(), - InputType.bIsArray, - InputType.bIsReference, *GetNameForPin(AdditionalPinIndex + BinaryOperatorInputsNum), + InputType.ContainerType, + InputType.bIsReference, false, INDEX_NONE, - InputType.bIsSet, - InputType.bIsMap, InputType.PinValueType ); } @@ -278,7 +276,7 @@ void UK2Node_CommutativeAssociativeBinaryOperator::ExpandNode(FKismetCompilerCon continue; } - UK2Node_CommutativeAssociativeBinaryOperator* NewOperator = SourceGraph->CreateBlankNode(); + UK2Node_CommutativeAssociativeBinaryOperator* NewOperator = SourceGraph->CreateIntermediateNode(); NewOperator->SetFromFunction(Function); NewOperator->AllocateDefaultPins(); CompilerContext.MessageLog.NotifyIntermediateObjectCreation(NewOperator, this); diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Composite.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Composite.cpp index ccec4bcfcda6..81efe0da9ae3 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Composite.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Composite.cpp @@ -21,6 +21,7 @@ UK2Node_Composite::UK2Node_Composite(const FObjectInitializer& ObjectInitializer void UK2Node_Composite::AllocateDefaultPins() { UK2Node::AllocateDefaultPins(); + const UEdGraphSchema_K2* Schema = GetDefault(); if (OutputSourceNode) { @@ -30,7 +31,7 @@ void UK2Node_Composite::AllocateDefaultPins() if (PortPin->Direction == EGPD_Input) { UEdGraphPin* NewPin = CreatePin(UEdGraphPin::GetComplementaryDirection(PortPin->Direction), PortPin->PinType, PortPin->PinName); - NewPin->DefaultValue = NewPin->AutogeneratedDefaultValue = PortPin->DefaultValue; + Schema->SetPinAutogeneratedDefaultValue(NewPin, PortPin->GetDefaultAsString()); } } } @@ -43,7 +44,7 @@ void UK2Node_Composite::AllocateDefaultPins() if (PortPin->Direction == EGPD_Output) { UEdGraphPin* NewPin = CreatePin(UEdGraphPin::GetComplementaryDirection(PortPin->Direction), PortPin->PinType, PortPin->PinName); - NewPin->DefaultValue = NewPin->AutogeneratedDefaultValue = PortPin->DefaultValue; + Schema->SetPinAutogeneratedDefaultValue(NewPin, PortPin->GetDefaultAsString()); } } } diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_ConstructObjectFromClass.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_ConstructObjectFromClass.cpp index cfcf03209eb9..142e37d8bd68 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_ConstructObjectFromClass.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_ConstructObjectFromClass.cpp @@ -44,24 +44,24 @@ void UK2Node_ConstructObjectFromClass::AllocateDefaultPins() const UEdGraphSchema_K2* K2Schema = GetDefault(); // Add execution pins - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Execute); - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Then); + CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Execute); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Then); // If required add the world context pin if (UseWorldContext()) { - CreatePin(EGPD_Input, K2Schema->PC_Object, TEXT(""), UObject::StaticClass(), false, false, FK2Node_ConstructObjectFromClassHelper::WorldContextPinName); + CreatePin(EGPD_Input, K2Schema->PC_Object, FString(), UObject::StaticClass(), FK2Node_ConstructObjectFromClassHelper::WorldContextPinName); } // Add blueprint pin - UEdGraphPin* ClassPin = CreatePin(EGPD_Input, K2Schema->PC_Class, TEXT(""), GetClassPinBaseClass(), false, false, FK2Node_ConstructObjectFromClassHelper::ClassPinName); + UEdGraphPin* ClassPin = CreatePin(EGPD_Input, K2Schema->PC_Class, FString(), GetClassPinBaseClass(), FK2Node_ConstructObjectFromClassHelper::ClassPinName); // Result pin - UEdGraphPin* ResultPin = CreatePin(EGPD_Output, K2Schema->PC_Object, TEXT(""), GetClassPinBaseClass(), false, false, K2Schema->PN_ReturnValue); + UEdGraphPin* ResultPin = CreatePin(EGPD_Output, K2Schema->PC_Object, FString(), GetClassPinBaseClass(), K2Schema->PN_ReturnValue); if (UseOuter()) { - UEdGraphPin* OuterPin = CreatePin(EGPD_Input, K2Schema->PC_Object, TEXT(""), UObject::StaticClass(), false, false, FK2Node_ConstructObjectFromClassHelper::OuterPinName); + UEdGraphPin* OuterPin = CreatePin(EGPD_Input, K2Schema->PC_Object, FString(), UObject::StaticClass(), FK2Node_ConstructObjectFromClassHelper::OuterPinName); } Super::AllocateDefaultPins(); @@ -111,7 +111,7 @@ void UK2Node_ConstructObjectFromClass::CreatePinsForClass(UClass* InClass, TArra !bIsDelegate && (NULL == FindPin(Property->GetName()) ) ) { - UEdGraphPin* Pin = CreatePin(EGPD_Input, TEXT(""), TEXT(""), NULL, false, false, Property->GetName()); + UEdGraphPin* Pin = CreatePin(EGPD_Input, FString(), FString(), nullptr, Property->GetName()); const bool bPinGood = (Pin != NULL) && K2Schema->ConvertPropertyToPinType(Property, /*out*/ Pin->PinType); if (OutClassPins && Pin) @@ -124,7 +124,7 @@ void UK2Node_ConstructObjectFromClass::CreatePinsForClass(UClass* InClass, TArra FString DefaultValueAsString; const bool bDefaultValueSet = FBlueprintEditorUtils::PropertyValueToString(Property, reinterpret_cast(ClassDefaultObject), DefaultValueAsString); check( bDefaultValueSet ); - K2Schema->TrySetDefaultValue(*Pin, DefaultValueAsString); + K2Schema->SetPinAutogeneratedDefaultValue(Pin, DefaultValueAsString); } // Copy tooltip from the property. diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_ConvertAsset.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_ConvertAsset.cpp index 84218674cf47..3b8c14f90fa8 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_ConvertAsset.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_ConvertAsset.cpp @@ -17,41 +17,45 @@ namespace UK2Node_ConvertAssetImpl { - static const FString InputPinName("Asset"); - static const FString OutputPinName("Object"); + static const FString InputPinName("Input"); + static const FString OutputPinName("Output"); } UClass* UK2Node_ConvertAsset::GetTargetClass() const { - auto InutPin = FindPin(UK2Node_ConvertAssetImpl::InputPinName); - bool bIsConnected = InutPin && InutPin->LinkedTo.Num() && InutPin->LinkedTo[0]; - auto SourcePin = bIsConnected ? InutPin->LinkedTo[0] : nullptr; - return SourcePin - ? Cast(SourcePin->PinType.PinSubCategoryObject.Get()) - : nullptr; + UEdGraphPin* InputPin = FindPin(UK2Node_ConvertAssetImpl::InputPinName); + bool bIsConnected = InputPin && InputPin->LinkedTo.Num() && InputPin->LinkedTo[0]; + UEdGraphPin* SourcePin = bIsConnected ? InputPin->LinkedTo[0] : nullptr; + return SourcePin ? Cast(SourcePin->PinType.PinSubCategoryObject.Get()) : nullptr; } bool UK2Node_ConvertAsset::IsAssetClassType() const { - const UEdGraphSchema_K2* K2Schema = Cast(GetSchema()); - // get first input, return if class asset - auto InutPin = FindPin(UK2Node_ConvertAssetImpl::InputPinName); - bool bIsConnected = InutPin && InutPin->LinkedTo.Num() && InutPin->LinkedTo[0]; - auto SourcePin = bIsConnected ? InutPin->LinkedTo[0] : nullptr; - return (SourcePin && K2Schema) - ? (SourcePin->PinType.PinCategory == K2Schema->PC_AssetClass) - : false; + UEdGraphPin* InputPin = FindPin(UK2Node_ConvertAssetImpl::InputPinName); + bool bIsConnected = InputPin && InputPin->LinkedTo.Num() && InputPin->LinkedTo[0]; + UEdGraphPin* SourcePin = bIsConnected ? InputPin->LinkedTo[0] : nullptr; + return SourcePin ? (SourcePin->PinType.PinCategory == UEdGraphSchema_K2::PC_AssetClass || SourcePin->PinType.PinCategory == UEdGraphSchema_K2::PC_Class) : false; +} + +bool UK2Node_ConvertAsset::IsConvertToAsset() const +{ + // get first input, return if class asset + UEdGraphPin* InputPin = FindPin(UK2Node_ConvertAssetImpl::InputPinName); + bool bIsConnected = InputPin && InputPin->LinkedTo.Num() && InputPin->LinkedTo[0]; + UEdGraphPin* SourcePin = bIsConnected ? InputPin->LinkedTo[0] : nullptr; + return SourcePin ? (SourcePin->PinType.PinCategory == UEdGraphSchema_K2::PC_Class || SourcePin->PinType.PinCategory == UEdGraphSchema_K2::PC_Object) : false; } bool UK2Node_ConvertAsset::IsConnectionDisallowed(const UEdGraphPin* MyPin, const UEdGraphPin* OtherPin, FString& OutReason) const { - const UEdGraphSchema_K2* K2Schema = Cast(GetSchema()); - auto InutPin = FindPin(UK2Node_ConvertAssetImpl::InputPinName); - if (K2Schema && InutPin && OtherPin && (InutPin == MyPin) && (MyPin->PinType.PinCategory == K2Schema->PC_Wildcard)) + UEdGraphPin* InputPin = FindPin(UK2Node_ConvertAssetImpl::InputPinName); + if (InputPin && OtherPin && (InputPin == MyPin) && (MyPin->PinType.PinCategory == UEdGraphSchema_K2::PC_Wildcard)) { - if ((OtherPin->PinType.PinCategory != K2Schema->PC_Asset) && - (OtherPin->PinType.PinCategory != K2Schema->PC_AssetClass)) + if ((OtherPin->PinType.PinCategory != UEdGraphSchema_K2::PC_Asset) && + (OtherPin->PinType.PinCategory != UEdGraphSchema_K2::PC_AssetClass) && + (OtherPin->PinType.PinCategory != UEdGraphSchema_K2::PC_Object) && + (OtherPin->PinType.PinCategory != UEdGraphSchema_K2::PC_Class)) { return true; } @@ -62,30 +66,42 @@ bool UK2Node_ConvertAsset::IsConnectionDisallowed(const UEdGraphPin* MyPin, cons void UK2Node_ConvertAsset::RefreshPinTypes() { const UEdGraphSchema_K2* K2Schema = CastChecked(GetSchema()); - auto InutPin = FindPin(UK2Node_ConvertAssetImpl::InputPinName); - auto OutputPin = FindPin(UK2Node_ConvertAssetImpl::OutputPinName); - ensure(InutPin && OutputPin); - if (InutPin && OutputPin) + UEdGraphPin* InputPin = FindPin(UK2Node_ConvertAssetImpl::InputPinName); + UEdGraphPin* OutputPin = FindPin(UK2Node_ConvertAssetImpl::OutputPinName); + ensure(InputPin && OutputPin); + if (InputPin && OutputPin) { - const bool bIsConnected = InutPin->LinkedTo.Num() > 0; + const bool bIsConnected = InputPin->LinkedTo.Num() > 0; UClass* TargetType = bIsConnected ? GetTargetClass() : nullptr; const bool bIsAssetClass = bIsConnected ? IsAssetClassType() : false; + const bool bIsConvertToAsset = bIsConnected ? IsConvertToAsset() : false; - const FString InputCategory = bIsConnected - ? (bIsAssetClass ? K2Schema->PC_AssetClass : K2Schema->PC_Asset) - : K2Schema->PC_Wildcard; - InutPin->PinType = FEdGraphPinType(InputCategory, FString(), TargetType, false, false, false, false, FEdGraphTerminalType() ); + FString InputCategory = UEdGraphSchema_K2::PC_Wildcard; + FString OutputCategory = UEdGraphSchema_K2::PC_Wildcard; + if (bIsConnected) + { + if (bIsConvertToAsset) + { + InputCategory = (bIsAssetClass ? UEdGraphSchema_K2::PC_Class : UEdGraphSchema_K2::PC_Object); + OutputCategory = (bIsAssetClass ? UEdGraphSchema_K2::PC_AssetClass : UEdGraphSchema_K2::PC_Asset); + } + else + { + InputCategory = (bIsAssetClass ? UEdGraphSchema_K2::PC_AssetClass : UEdGraphSchema_K2::PC_Asset); + OutputCategory = (bIsAssetClass ? UEdGraphSchema_K2::PC_Class : UEdGraphSchema_K2::PC_Object); + } + } + + InputPin->PinType = FEdGraphPinType(InputCategory, FString(), TargetType, EPinContainerType::None, false, FEdGraphTerminalType() ); + OutputPin->PinType = FEdGraphPinType(OutputCategory, FString(), TargetType, EPinContainerType::None, false, FEdGraphTerminalType() ); - const FString OutputCategory = bIsConnected - ? (bIsAssetClass ? K2Schema->PC_Class : K2Schema->PC_Object) - : K2Schema->PC_Wildcard; - OutputPin->PinType = FEdGraphPinType(OutputCategory, FString(), TargetType, false, false, false, false, FEdGraphTerminalType() ); - - PinTypeChanged(InutPin); + PinTypeChanged(InputPin); PinTypeChanged(OutputPin); if (OutputPin->LinkedTo.Num()) { + TArray PinsToUnlink = OutputPin->LinkedTo; + UClass const* CallingContext = NULL; if (UBlueprint const* Blueprint = GetBlueprint()) { @@ -96,7 +112,7 @@ void UK2Node_ConvertAsset::RefreshPinTypes() } } - for (auto TargetPin : OutputPin->LinkedTo) + for (UEdGraphPin* TargetPin : PinsToUnlink) { if (TargetPin && !K2Schema->ArePinsCompatible(OutputPin, TargetPin, CallingContext)) { @@ -120,14 +136,25 @@ void UK2Node_ConvertAsset::NotifyPinConnectionListChanged(UEdGraphPin* Pin) if (Pin && (UK2Node_ConvertAssetImpl::InputPinName == Pin->PinName)) { RefreshPinTypes(); + + GetGraph()->NotifyGraphChanged(); } } void UK2Node_ConvertAsset::AllocateDefaultPins() { - const UEdGraphSchema_K2* K2Schema = CastChecked(GetSchema()); - CreatePin(EGPD_Input, K2Schema->PC_Wildcard, TEXT(""), nullptr, false, false, UK2Node_ConvertAssetImpl::InputPinName); - CreatePin(EGPD_Output, K2Schema->PC_Wildcard, TEXT(""), nullptr, false, false, UK2Node_ConvertAssetImpl::OutputPinName); + CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Wildcard, FString(), nullptr, UK2Node_ConvertAssetImpl::InputPinName); + CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Wildcard, FString(), nullptr, UK2Node_ConvertAssetImpl::OutputPinName); +} + +UK2Node::ERedirectType UK2Node_ConvertAsset::DoPinsMatchForReconstruction(const UEdGraphPin* NewPin, int32 NewPinIndex, const UEdGraphPin* OldPin, int32 OldPinIndex) const +{ + // Names changed, only thing that matters is the direction + if (NewPin->Direction == OldPin->Direction) + { + return UK2Node::ERedirectType_Name; + } + return UK2Node::ERedirectType_None; } void UK2Node_ConvertAsset::GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const @@ -159,49 +186,87 @@ void UK2Node_ConvertAsset::ExpandNode(class FKismetCompilerContext& CompilerCont if (TargetType && Schema && (2 == Pins.Num())) { const bool bIsAssetClass = IsAssetClassType(); + UClass *TargetClass = GetTargetClass(); + bool bIsErrorFree = true; - //Create Convert Function - auto ConvertToObjectFunc = CompilerContext.SpawnIntermediateNode(this, SourceGraph); - const FName ConvertFunctionName = bIsAssetClass - ? GET_FUNCTION_NAME_CHECKED(UKismetSystemLibrary, Conv_AssetClassToClass) - : GET_FUNCTION_NAME_CHECKED(UKismetSystemLibrary, Conv_AssetToObject); - ConvertToObjectFunc->FunctionReference.SetExternalMember(ConvertFunctionName, UKismetSystemLibrary::StaticClass()); - ConvertToObjectFunc->AllocateDefaultPins(); - - //Connect input to convert - auto InputPin = FindPin(UK2Node_ConvertAssetImpl::InputPinName); - const FString ConvertInputName = bIsAssetClass - ? FString(TEXT("AssetClass")) - : FString(TEXT("Asset")); - auto ConvertInput = ConvertToObjectFunc->FindPin(ConvertInputName); - bool bIsErrorFree = InputPin && ConvertInput && CompilerContext.MovePinLinksToIntermediate(*InputPin, *ConvertInput).CanSafeConnect(); - - auto ConvertOutput = ConvertToObjectFunc->GetReturnValuePin(); - UEdGraphPin* InnerOutput = nullptr; - if (UObject::StaticClass() != TargetType) + if (IsConvertToAsset()) { - //Create Cast Node - UK2Node_DynamicCast* CastNode = bIsAssetClass - ? CompilerContext.SpawnIntermediateNode(this, SourceGraph) - : CompilerContext.SpawnIntermediateNode(this, SourceGraph); - CastNode->SetPurity(true); - CastNode->TargetType = TargetType; - CastNode->AllocateDefaultPins(); + //Create Convert Function + UK2Node_CallFunction* ConvertToObjectFunc = CompilerContext.SpawnIntermediateNode(this, SourceGraph); + FName ConvertFunctionName = bIsAssetClass + ? GET_FUNCTION_NAME_CHECKED(UKismetSystemLibrary, Conv_ClassToSoftClassReference) + : GET_FUNCTION_NAME_CHECKED(UKismetSystemLibrary, Conv_ObjectToSoftObjectReference); - // Connect Object/Class to Cast - auto CastInput = CastNode->GetCastSourcePin(); - bIsErrorFree &= ConvertOutput && CastInput && Schema->TryCreateConnection(ConvertOutput, CastInput); + ConvertToObjectFunc->FunctionReference.SetExternalMember(ConvertFunctionName, UKismetSystemLibrary::StaticClass()); + ConvertToObjectFunc->AllocateDefaultPins(); - // Connect output to cast - InnerOutput = CastNode->GetCastResultPin(); + //Connect input to convert + UEdGraphPin* InputPin = FindPin(UK2Node_ConvertAssetImpl::InputPinName); + const FString ConvertInputName = bIsAssetClass + ? FString(TEXT("Class")) + : FString(TEXT("Object")); + UEdGraphPin* ConvertInput = ConvertToObjectFunc->FindPin(ConvertInputName); + bIsErrorFree = InputPin && ConvertInput && CompilerContext.MovePinLinksToIntermediate(*InputPin, *ConvertInput).CanSafeConnect(); + + if (UEdGraphPin* ConvertOutput = ConvertToObjectFunc->GetReturnValuePin()) + { + // Force the convert output pin to the right type. This is only safe because all asset ptrs are type-compatible, the cast is done at resolution time + ConvertOutput->PinType.PinSubCategoryObject = TargetClass; + + UEdGraphPin* OutputPin = FindPin(UK2Node_ConvertAssetImpl::OutputPinName); + bIsErrorFree &= OutputPin && CompilerContext.MovePinLinksToIntermediate(*OutputPin, *ConvertOutput).CanSafeConnect(); + } + else + { + bIsErrorFree = false; + } } else { - InnerOutput = ConvertOutput; - } + //Create Convert Function + UK2Node_CallFunction* ConvertToObjectFunc = CompilerContext.SpawnIntermediateNode(this, SourceGraph); + FName ConvertFunctionName = bIsAssetClass + ? GET_FUNCTION_NAME_CHECKED(UKismetSystemLibrary, Conv_SoftClassReferenceToClass) + : GET_FUNCTION_NAME_CHECKED(UKismetSystemLibrary, Conv_SoftObjectReferenceToObject); - auto OutputPin = FindPin(UK2Node_ConvertAssetImpl::OutputPinName); - bIsErrorFree &= OutputPin && InnerOutput && CompilerContext.MovePinLinksToIntermediate(*OutputPin, *InnerOutput).CanSafeConnect(); + ConvertToObjectFunc->FunctionReference.SetExternalMember(ConvertFunctionName, UKismetSystemLibrary::StaticClass()); + ConvertToObjectFunc->AllocateDefaultPins(); + + //Connect input to convert + UEdGraphPin* InputPin = FindPin(UK2Node_ConvertAssetImpl::InputPinName); + const FString ConvertInputName = bIsAssetClass + ? FString(TEXT("AssetClass")) + : FString(TEXT("Asset")); + UEdGraphPin* ConvertInput = ConvertToObjectFunc->FindPin(ConvertInputName); + bIsErrorFree = InputPin && ConvertInput && CompilerContext.MovePinLinksToIntermediate(*InputPin, *ConvertInput).CanSafeConnect(); + + UEdGraphPin* ConvertOutput = ConvertToObjectFunc->GetReturnValuePin(); + UEdGraphPin* InnerOutput = nullptr; + if (UObject::StaticClass() != TargetType) + { + //Create Cast Node + UK2Node_DynamicCast* CastNode = bIsAssetClass + ? CompilerContext.SpawnIntermediateNode(this, SourceGraph) + : CompilerContext.SpawnIntermediateNode(this, SourceGraph); + CastNode->SetPurity(true); + CastNode->TargetType = TargetType; + CastNode->AllocateDefaultPins(); + + // Connect Object/Class to Cast + UEdGraphPin* CastInput = CastNode->GetCastSourcePin(); + bIsErrorFree &= ConvertOutput && CastInput && Schema->TryCreateConnection(ConvertOutput, CastInput); + + // Connect output to cast + InnerOutput = CastNode->GetCastResultPin(); + } + else + { + InnerOutput = ConvertOutput; + } + + UEdGraphPin* OutputPin = FindPin(UK2Node_ConvertAssetImpl::OutputPinName); + bIsErrorFree &= OutputPin && InnerOutput && CompilerContext.MovePinLinksToIntermediate(*OutputPin, *InnerOutput).CanSafeConnect(); + } if (!bIsErrorFree) { @@ -224,12 +289,18 @@ FText UK2Node_ConvertAsset::GetMenuCategory() const FText UK2Node_ConvertAsset::GetNodeTitle(ENodeTitleType::Type TitleType) const { - return FText(LOCTEXT("UK2Node_ConvertAssetGetNodeTitle", "Resolve Asset ID")); + return FText(LOCTEXT("UK2Node_ConvertAssetGetNodeTitle", "Resolve Soft Reference")); +} + +FText UK2Node_ConvertAsset::GetKeywords() const +{ + // Return old name here + return FText(LOCTEXT("UK2Node_ConvertAssetGetKeywords", "Resolve Asset ID")); } FText UK2Node_ConvertAsset::GetTooltipText() const { - return FText(LOCTEXT("UK2Node_ConvertAssetGetTooltipText", "Resolves an Asset ID or Class Asset ID into an object/class. If the asset wasn't loaded it returns none.")); + return FText(LOCTEXT("UK2Node_ConvertAssetGetTooltipText", "Resolves a Soft Reference or Soft Class Reference into an object/class or vice versa. If the object isn't already loaded it returns none.")); } #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Copy.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Copy.cpp index 0fa42554a802..f39d91295f4b 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Copy.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Copy.cpp @@ -66,8 +66,8 @@ void UK2Node_Copy::AllocateDefaultPins() { const UEdGraphSchema_K2* Schema = GetDefault(); - CreatePin(EGPD_Input, Schema->PC_Wildcard, TEXT(""), NULL, false, false, Schema->PN_Item); - CreatePin(EGPD_Output, Schema->PC_Wildcard, TEXT(""), NULL, false, false, Schema->PN_ReturnValue); + CreatePin(EGPD_Input, Schema->PC_Wildcard, FString(), nullptr, Schema->PN_Item); + CreatePin(EGPD_Output, Schema->PC_Wildcard, FString(), nullptr, Schema->PN_ReturnValue); Super::AllocateDefaultPins(); } @@ -158,7 +158,7 @@ void UK2Node_Copy::PinTypeChanged(UEdGraphPin* Pin) Schema->RecombinePin(ReturnPin->SubPins[0]); } ReturnPin->PinType = Pin->PinType; - Schema->SetPinDefaultValueBasedOnType(ReturnPin); + Schema->SetPinAutogeneratedDefaultValueBasedOnType(ReturnPin); } } @@ -248,10 +248,10 @@ void UK2Node_Copy::PropagatePinType(FEdGraphPinType& InType) InputPin->PinType = InType; ResultPin->PinType = InType; - InputPin->PinType.bIsArray = false; + InputPin->PinType.ContainerType = EPinContainerType::None; InputPin->PinType.bIsReference = false; - ResultPin->PinType.bIsArray = false; + ResultPin->PinType.ContainerType = EPinContainerType::None; ResultPin->PinType.bIsReference = false; const UEdGraphSchema_K2* Schema = GetDefault(); diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CreateDelegate.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CreateDelegate.cpp index a8e73c7ca447..30845ca7bc65 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CreateDelegate.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CreateDelegate.cpp @@ -32,12 +32,12 @@ void UK2Node_CreateDelegate::AllocateDefaultPins() { const UEdGraphSchema_K2* K2Schema = GetDefault(); - if (UEdGraphPin* ObjPin = CreatePin(EGPD_Input, K2Schema->PC_Object, TEXT(""), UObject::StaticClass(), false, false, K2Schema->PN_Self)) + if (UEdGraphPin* ObjPin = CreatePin(EGPD_Input, K2Schema->PC_Object, FString(), UObject::StaticClass(), K2Schema->PN_Self)) { ObjPin->PinFriendlyName = NSLOCTEXT("K2Node", "CreateDelegate_ObjectInputName", "Object"); } - if(UEdGraphPin* DelegatePin = CreatePin(EGPD_Output, K2Schema->PC_Delegate, TEXT(""), NULL, false, false, FK2Node_CreateDelegate_Helper::DelegateOutputName)) + if(UEdGraphPin* DelegatePin = CreatePin(EGPD_Output, K2Schema->PC_Delegate, FString(), nullptr, FK2Node_CreateDelegate_Helper::DelegateOutputName)) { DelegatePin->PinFriendlyName = NSLOCTEXT("K2Node", "CreateDelegate_DelegateOutName", "Event"); } diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CustomEvent.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CustomEvent.cpp index 17a33586a296..7908e9d20bd8 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CustomEvent.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_CustomEvent.cpp @@ -144,7 +144,7 @@ void UK2Node_CustomEvent::Serialize(FArchive& Ar) { if (PinInfo->PinName == Pin->PinName) { - Pin->PinType.bIsConst = PinInfo->PinType.bIsConst = PinInfo->PinType.bIsArray || PinInfo->PinType.bIsReference; + Pin->PinType.bIsConst = PinInfo->PinType.bIsConst = (PinInfo->PinType.IsContainer() || PinInfo->PinType.bIsReference); break; } } @@ -224,10 +224,23 @@ bool UK2Node_CustomEvent::CanCreateUserDefinedPin(const FEdGraphPinType& InPinTy UEdGraphPin* UK2Node_CustomEvent::CreatePinFromUserDefinition(const TSharedPtr NewPinInfo) { UEdGraphPin* NewPin = CreatePin(EGPD_Output, NewPinInfo->PinType, NewPinInfo->PinName); - NewPin->DefaultValue = NewPin->AutogeneratedDefaultValue = NewPinInfo->PinDefaultValue; + const UEdGraphSchema_K2* K2Schema = GetDefault(); + K2Schema->SetPinAutogeneratedDefaultValue(NewPin, NewPinInfo->PinDefaultValue); return NewPin; } +bool UK2Node_CustomEvent::ModifyUserDefinedPinDefaultValue(TSharedPtr PinInfo, const FString& NewDefaultValue) +{ + if (Super::ModifyUserDefinedPinDefaultValue(PinInfo, NewDefaultValue)) + { + const UEdGraphSchema_K2* K2Schema = GetDefault(); + K2Schema->HandleParameterDefaultValueChanged(this); + + return true; + } + return false; +} + void UK2Node_CustomEvent::RenameCustomEventCloseToName(int32 StartIndex) { bool bFoundName = false; diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_DelegateSet.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_DelegateSet.cpp index 4bad0e2c2bee..114ca93fc493 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_DelegateSet.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_DelegateSet.cpp @@ -141,11 +141,11 @@ void UK2Node_DelegateSet::AllocateDefaultPins() // Cache off the delegate signature, which will update the DelegatePropertyName as well, if it's been redirected UFunction* DelegateSignature = GetDelegateSignature(); - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Execute); - CreatePin(EGPD_Input, K2Schema->PC_Object, TEXT(""), DelegatePropertyClass, false, false, DelegatePropertyName.ToString()); + CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Execute); + CreatePin(EGPD_Input, K2Schema->PC_Object, FString(), DelegatePropertyClass, DelegatePropertyName.ToString()); - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Then); - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_DelegateEntry); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Then); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_DelegateEntry); CreatePinsForFunctionEntryExit(DelegateSignature, true); diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_DoOnceMultiInput.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_DoOnceMultiInput.cpp index a1e95d2b8dd7..9c27a20bb3cc 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_DoOnceMultiInput.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_DoOnceMultiInput.cpp @@ -185,17 +185,17 @@ void UK2Node_DoOnceMultiInput::AllocateDefaultPins() const UEdGraphSchema_K2* K2Schema = GetDefault(); FText InputPinAName = GetNameForPin(0, true); - UEdGraphPin* InputPinA = CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, InputPinAName.BuildSourceString()); + UEdGraphPin* InputPinA = CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, InputPinAName.BuildSourceString()); InputPinA->PinFriendlyName = InputPinAName; FText OutputPinAName = GetNameForPin(0, false); - UEdGraphPin* OutputPinA = CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, OutputPinAName.BuildSourceString()); + UEdGraphPin* OutputPinA = CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, OutputPinAName.BuildSourceString()); OutputPinA->PinFriendlyName = OutputPinAName; - UEdGraphPin* DoOnceResetIn = CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, TEXT("Reset In")); + UEdGraphPin* DoOnceResetIn = CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, TEXT("Reset In")); DoOnceResetIn->PinFriendlyName = LOCTEXT("DoOnceResetIn", "Reset In"); - UEdGraphPin* DoOnceResetOut = CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, TEXT("Reset Out")); + UEdGraphPin* DoOnceResetOut = CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, TEXT("Reset Out")); DoOnceResetOut->PinFriendlyName = LOCTEXT("DoOnceResetOut", "Reset Out"); for (int32 i = 0; i < NumAdditionalInputs; ++i) @@ -322,7 +322,7 @@ void UK2Node_DoOnceMultiInput::ExpandNode(FKismetCompilerContext& CompilerContex ///////////////////////////// // Create the node - UK2Node_TemporaryVariable* TempVarNode = SourceGraph->CreateBlankNode(); + UK2Node_TemporaryVariable* TempVarNode = SourceGraph->CreateIntermediateNode(); TempVarNode->VariableType.PinCategory = Schema->PC_Boolean; TempVarNode->AllocateDefaultPins(); CompilerContext.MessageLog.NotifyIntermediateObjectCreation(TempVarNode, this); @@ -340,7 +340,7 @@ void UK2Node_DoOnceMultiInput::ExpandNode(FKismetCompilerContext& CompilerContex check(ThenPin); // AssignmentNode - UK2Node_AssignmentStatement* AssignmentNode = SourceGraph->CreateBlankNode(); + UK2Node_AssignmentStatement* AssignmentNode = SourceGraph->CreateIntermediateNode(); AssignmentNode->AllocateDefaultPins(); CompilerContext.MessageLog.NotifyIntermediateObjectCreation(AssignmentNode, this); AssignmentNode->GetVariablePin()->PinType = TempVarNode->GetVariablePin()->PinType; @@ -350,7 +350,7 @@ void UK2Node_DoOnceMultiInput::ExpandNode(FKismetCompilerContext& CompilerContex if (!ExecPin->PinName.Contains(TEXT("Reset"))) // Fixme this wont work for localization { // BranchNode - UK2Node_IfThenElse* BranchNode = SourceGraph->CreateBlankNode(); + UK2Node_IfThenElse* BranchNode = SourceGraph->CreateIntermediateNode(); BranchNode->AllocateDefaultPins(); CompilerContext.MessageLog.NotifyIntermediateObjectCreation(BranchNode, this); diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_DynamicCast.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_DynamicCast.cpp index 0c6e1b89e6e3..6ed65e15fd76 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_DynamicCast.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_DynamicCast.cpp @@ -47,15 +47,15 @@ void UK2Node_DynamicCast::AllocateDefaultPins() if (!bIsPureCast) { // Input - Execution Pin - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Execute); + CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Execute); // Output - Execution Pins - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_CastSucceeded); - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_CastFailed); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_CastSucceeded); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_CastFailed); } // Input - Source type Pin - CreatePin(EGPD_Input, K2Schema->PC_Wildcard, TEXT(""), UObject::StaticClass(), false, false, K2Schema->PN_ObjectToCast); + CreatePin(EGPD_Input, K2Schema->PC_Wildcard, FString(), UObject::StaticClass(), K2Schema->PN_ObjectToCast); // Output - Data Pin if (TargetType != NULL) @@ -63,15 +63,15 @@ void UK2Node_DynamicCast::AllocateDefaultPins() FString CastResultPinName = K2Schema->PN_CastedValuePrefix + TargetType->GetDisplayNameText().ToString(); if (TargetType->IsChildOf(UInterface::StaticClass())) { - CreatePin(EGPD_Output, K2Schema->PC_Interface, TEXT(""), *TargetType, false, false, CastResultPinName); + CreatePin(EGPD_Output, K2Schema->PC_Interface, FString(), *TargetType, CastResultPinName); } else { - CreatePin(EGPD_Output, K2Schema->PC_Object, TEXT(""), *TargetType, false, false, CastResultPinName); + CreatePin(EGPD_Output, K2Schema->PC_Object, FString(), *TargetType, CastResultPinName); } } - UEdGraphPin* BoolSuccessPin = CreatePin(EGPD_Output, K2Schema->PC_Boolean, TEXT(""), nullptr, /*bIsArray =*/false, /*bIsReference =*/false, UK2Node_DynamicCastImpl::CastSuccessPinName); + UEdGraphPin* BoolSuccessPin = CreatePin(EGPD_Output, K2Schema->PC_Boolean, FString(), nullptr, UK2Node_DynamicCastImpl::CastSuccessPinName); BoolSuccessPin->bHidden = !bIsPureCast; Super::AllocateDefaultPins(); diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_EaseFunction.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_EaseFunction.cpp index c997cf986393..f87ec173a5aa 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_EaseFunction.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_EaseFunction.cpp @@ -86,36 +86,36 @@ void UK2Node_EaseFunction::AllocateDefaultPins() // Add the first pin representing all available easing functions. If EEasingFunc changes its name this will fail a runtime check! UEnum * EaseFuncEnum = FindObject(ANY_PACKAGE, TEXT("EEasingFunc"), true); check(EaseFuncEnum != NULL); - CachedEaseFuncPin = CreatePin(EGPD_Input, K2Schema->PC_Byte, TEXT(""), EaseFuncEnum, false, false, FEaseFunctionNodeHelper::GetEaseFuncPinName()); + CachedEaseFuncPin = CreatePin(EGPD_Input, K2Schema->PC_Byte, FString(), EaseFuncEnum, FEaseFunctionNodeHelper::GetEaseFuncPinName()); SetPinToolTip(*CachedEaseFuncPin, LOCTEXT("EaseFunsPinDescription", "Specifies the desired ease function to be applied. If connected no customization is possible.")); // Make sure that the default value is set correctly if none has been set - K2Schema->SetPinDefaultValue(CachedEaseFuncPin); + K2Schema->SetPinAutogeneratedDefaultValueBasedOnType(CachedEaseFuncPin); - UEdGraphPin* AlphaPin = CreatePin(EGPD_Input, K2Schema->PC_Float, TEXT(""), NULL, false, false, FEaseFunctionNodeHelper::GetAlphaPinName()); + UEdGraphPin* AlphaPin = CreatePin(EGPD_Input, K2Schema->PC_Float, FString(), nullptr, FEaseFunctionNodeHelper::GetAlphaPinName()); SetPinToolTip(*AlphaPin, LOCTEXT("AlphaPinTooltip", "Alpha value used to specify the easing in time.")); // Add wildcard pins for A, B and the return Pin - UEdGraphPin* APin = CreatePin(EGPD_Input, K2Schema->PC_Wildcard, TEXT(""), NULL, false, false, FEaseFunctionNodeHelper::GetAPinName()); + UEdGraphPin* APin = CreatePin(EGPD_Input, K2Schema->PC_Wildcard, FString(), nullptr, FEaseFunctionNodeHelper::GetAPinName()); SetPinToolTip(*APin, LOCTEXT("APinDescription", "Easing start value")); - UEdGraphPin* BPin = CreatePin(EGPD_Input, K2Schema->PC_Wildcard, TEXT(""), NULL, false, false, FEaseFunctionNodeHelper::GetBPinName()); + UEdGraphPin* BPin = CreatePin(EGPD_Input, K2Schema->PC_Wildcard, FString(), nullptr, FEaseFunctionNodeHelper::GetBPinName()); SetPinToolTip(*BPin, LOCTEXT("BPinDescription", "Easing end value")); - UEdGraphPin* ResultPin = CreatePin(EGPD_Output, K2Schema->PC_Wildcard, TEXT(""), NULL, false, false, FEaseFunctionNodeHelper::GetResultPinName()); + UEdGraphPin* ResultPin = CreatePin(EGPD_Output, K2Schema->PC_Wildcard, FString(), nullptr, FEaseFunctionNodeHelper::GetResultPinName()); SetPinToolTip(*ResultPin, LOCTEXT("ResultPinDescription", "Easing result value")); - UEdGraphPin* ShortestPathPin = CreatePin(EGPD_Input, K2Schema->PC_Boolean, TEXT(""), NULL, false, false, FEaseFunctionNodeHelper::GetShortestPathPinName()); + UEdGraphPin* ShortestPathPin = CreatePin(EGPD_Input, K2Schema->PC_Boolean, FString(), nullptr, FEaseFunctionNodeHelper::GetShortestPathPinName()); SetPinToolTip(*ShortestPathPin, LOCTEXT("ShortestPathPinTooltip", "When interpolating the shortest path should be taken.")); - ShortestPathPin->DefaultValue = ShortestPathPin->AutogeneratedDefaultValue = TEXT("true"); + K2Schema->SetPinAutogeneratedDefaultValue(ShortestPathPin, TEXT("true")); - UEdGraphPin* BlendExpPin = CreatePin(EGPD_Input, K2Schema->PC_Float, TEXT(""), NULL, false, false, FEaseFunctionNodeHelper::GetBlendExpPinName()); + UEdGraphPin* BlendExpPin = CreatePin(EGPD_Input, K2Schema->PC_Float, FString(), nullptr, FEaseFunctionNodeHelper::GetBlendExpPinName()); SetPinToolTip(*BlendExpPin, LOCTEXT("BlendExpPinDescription", "Blend Exponent for basic ease functions")); - BlendExpPin->DefaultValue = BlendExpPin->AutogeneratedDefaultValue = TEXT("2.0"); + K2Schema->SetPinAutogeneratedDefaultValue(BlendExpPin, TEXT("2.0")); - UEdGraphPin* StepsPin = CreatePin(EGPD_Input, K2Schema->PC_Int, TEXT(""), NULL, false, false, FEaseFunctionNodeHelper::GetStepsPinName()); + UEdGraphPin* StepsPin = CreatePin(EGPD_Input, K2Schema->PC_Int, FString(), nullptr, FEaseFunctionNodeHelper::GetStepsPinName()); SetPinToolTip(*StepsPin, LOCTEXT("StepsPinDescription", "Number of steps required to go from A to B")); - StepsPin->DefaultValue = StepsPin->AutogeneratedDefaultValue = TEXT("2"); + K2Schema->SetPinAutogeneratedDefaultValue(StepsPin, TEXT("2")); RefreshPinVisibility(); } @@ -299,7 +299,7 @@ void UK2Node_EaseFunction::PinTypeChanged(UEdGraphPin* Pin) if (bChanged) { // Just in case we switch to an invalid function clean it first - EaseFunctionName = TEXT(""); + EaseFunctionName.Reset(); // Generate the right function name if (InstigatorPin->PinType.PinCategory == Schema->PC_Float) diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_EditablePinBase.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_EditablePinBase.cpp index e545df8db953..ae745365564a 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_EditablePinBase.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_EditablePinBase.cpp @@ -6,6 +6,41 @@ #include "EdGraphSchema_K2.h" #include "Kismet2/KismetDebugUtilities.h" +FArchive& operator<<(FArchive& Ar, FUserPinInfo& Info) +{ + Ar << Info.PinName; + + if (Ar.UE4Ver() >= VER_UE4_SERIALIZE_PINTYPE_CONST) + { + Info.PinType.Serialize(Ar); + Ar << Info.DesiredPinDirection; + } + else + { + bool bIsArray = (Info.PinType.ContainerType == EPinContainerType::Array); + Ar << bIsArray; + + bool bIsReference = Info.PinType.bIsReference; + Ar << bIsReference; + + if (Ar.IsLoading()) + { + Info.PinType.ContainerType = (bIsArray ? EPinContainerType::Array : EPinContainerType::None); + Info.PinType.bIsReference = bIsReference; + } + + Ar << Info.PinType.PinCategory; + Ar << Info.PinType.PinSubCategory; + + Ar << Info.PinType.PinSubCategoryObject; + } + + Ar << Info.PinDefaultValue; + + return Ar; +} + + UK2Node_EditablePinBase::UK2Node_EditablePinBase(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { @@ -105,12 +140,20 @@ void UK2Node_EditablePinBase::ExportCustomProperties(FOutputDevice& Out, uint32 Out.Logf( TEXT("%sCustomProperties UserDefinedPin "), FCString::Spc(Indent)); Out.Logf( TEXT("Name=\"%s\" "), *PinInfo.PinName); - Out.Logf( TEXT("IsArray=%s "), (PinInfo.PinType.bIsArray ? TEXT("1") : TEXT("0"))); Out.Logf( TEXT("IsReference=%s "), (PinInfo.PinType.bIsReference ? TEXT("1") : TEXT("0"))); + if (UEnum* PinContainerType = FindObject(ANY_PACKAGE, TEXT("EPinContainerType"))) + { + const FString ValueName = PinContainerType->GetNameStringByValue((uint8)PinInfo.PinType.ContainerType); + if (!ValueName.IsEmpty()) + { + Out.Logf(TEXT("PinContainerType=\"%s\" "), *ValueName); + } + } + if (UEnum* PinDirEnum = FindObject(ANY_PACKAGE, TEXT("EEdGraphPinDirection"))) { - FString ValueName = PinDirEnum->GetNameStringByValue(PinInfo.DesiredPinDirection); + const FString ValueName = PinDirEnum->GetNameStringByValue(PinInfo.DesiredPinDirection); if (!ValueName.IsEmpty()) { Out.Logf(TEXT("PinDir=\"%s\" "), *ValueName); @@ -156,7 +199,20 @@ void UK2Node_EditablePinBase::ImportCustomProperties(const TCHAR* SourceText, FF int32 BoolAsInt = 0; if (FParse::Value(SourceText, TEXT("IsArray="), BoolAsInt)) { - PinInfo->PinType.bIsArray = (BoolAsInt != 0); + PinInfo->PinType.ContainerType = (BoolAsInt != 0 ? EPinContainerType::Array : EPinContainerType::None); + } + + if (UEnum* PinContainerType = FindObject(ANY_PACKAGE, TEXT("EPinContainerType"))) + { + FString DesiredContainerType; + if (FParse::Value(SourceText, TEXT("PinContainerType="), DesiredContainerType)) + { + const int32 DesiredContainerTypeVal = PinContainerType->GetValueByName(*DesiredContainerType); + if (DesiredContainerTypeVal != INDEX_NONE) + { + PinInfo->PinType.ContainerType = (EPinContainerType)DesiredContainerTypeVal; + } + } } if (FParse::Value(SourceText, TEXT("IsReference="), BoolAsInt)) @@ -169,7 +225,7 @@ void UK2Node_EditablePinBase::ImportCustomProperties(const TCHAR* SourceText, FF FString DesiredDirection; if (FParse::Value(SourceText, TEXT("PinDir="), DesiredDirection)) { - int32 DesiredDirectionVal = PinDirEnum->GetValueByName(*DesiredDirection); + const int32 DesiredDirectionVal = PinDirEnum->GetValueByName(*DesiredDirection); if (DesiredDirectionVal != INDEX_NONE) { PinInfo->DesiredPinDirection = (EEdGraphPinDirection)DesiredDirectionVal; @@ -268,24 +324,53 @@ void UK2Node_EditablePinBase::AddReferencedObjects(UObject* InThis, FReferenceCo Super::AddReferencedObjects( This, Collector ); } +void UK2Node_EditablePinBase::PinDefaultValueChanged(UEdGraphPin* Pin) +{ + static bool bRecursivelyChangingDefaultValue = false; + + // Only do this if we're editable and not already calling this code + if (!bIsEditable || bRecursivelyChangingDefaultValue) + { + return; + } + + // See if this is a user defined pin + for (int32 Index = 0; Index < UserDefinedPins.Num(); ++Index) + { + TSharedPtr PinInfo = UserDefinedPins[Index]; + if (Pin->PinName == PinInfo->PinName && Pin->Direction == PinInfo->DesiredPinDirection) + { + FString DefaultsString = Pin->GetDefaultAsString(); + + if (DefaultsString != PinInfo->PinDefaultValue) + { + // Make sure this doesn't get called recursively + TGuardValue CircularGuard(bRecursivelyChangingDefaultValue, true); + ModifyUserDefinedPinDefaultValue(PinInfo, Pin->GetDefaultAsString()); + } + } + } +} + bool UK2Node_EditablePinBase::ModifyUserDefinedPinDefaultValue(TSharedPtr PinInfo, const FString& InDefaultValue) { + const UEdGraphSchema_K2* K2Schema = GetDefault(); FString NewDefaultValue = InDefaultValue; // Find and modify the current pin if (UEdGraphPin* OldPin = FindPin(PinInfo->PinName)) { FString SavedDefaultValue = OldPin->DefaultValue; - OldPin->DefaultValue = OldPin->AutogeneratedDefaultValue = NewDefaultValue; + + K2Schema->SetPinAutogeneratedDefaultValue(OldPin, NewDefaultValue); // Validate the new default value - const UEdGraphSchema* Schema = GetSchema(); - FString ErrorString = Schema->IsCurrentPinDefaultValid(OldPin); + FString ErrorString = K2Schema->IsCurrentPinDefaultValid(OldPin); if (!ErrorString.IsEmpty()) { NewDefaultValue = SavedDefaultValue; - OldPin->DefaultValue = OldPin->AutogeneratedDefaultValue = SavedDefaultValue; + K2Schema->SetPinAutogeneratedDefaultValue(OldPin, SavedDefaultValue); return false; } diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_EnumEquality.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_EnumEquality.cpp index e6d03bcd2aff..0f7a84db281e 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_EnumEquality.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_EnumEquality.cpp @@ -23,11 +23,11 @@ void UK2Node_EnumEquality::AllocateDefaultPins() const UEdGraphSchema_K2* Schema = GetDefault(); // Create the return value pin - CreatePin(EGPD_Output, Schema->PC_Boolean, TEXT(""), NULL, false, false, Schema->PN_ReturnValue); + CreatePin(EGPD_Output, Schema->PC_Boolean, FString(), nullptr, Schema->PN_ReturnValue); // Create the input pins - CreatePin(EGPD_Input, Schema->PC_Wildcard, TEXT(""), NULL, false, false, "A"); - CreatePin(EGPD_Input, Schema->PC_Wildcard, TEXT(""), NULL, false, false, "B"); + CreatePin(EGPD_Input, Schema->PC_Wildcard, FString(), nullptr, TEXT("A")); + CreatePin(EGPD_Input, Schema->PC_Wildcard, FString(), nullptr, TEXT("B")); Super::AllocateDefaultPins(); } @@ -58,11 +58,11 @@ void UK2Node_EnumEquality::PostReconstructNode() // { // // Restore the wildcard status // Input1Pin->PinType.PinCategory = Schema->PC_Wildcard; -// Input1Pin->PinType.PinSubCategory = TEXT(""); -// Input1Pin->PinType.PinSubCategoryObject = NULL; +// Input1Pin->PinType.PinSubCategory.Reset(); +// Input1Pin->PinType.PinSubCategoryObject = nullptr; // Input2Pin->PinType.PinCategory = Schema->PC_Wildcard; -// Input2Pin->PinType.PinSubCategory = TEXT(""); -// Input2Pin->PinType.PinSubCategoryObject = NULL; +// Input2Pin->PinType.PinSubCategory.Reset(); +// Input2Pin->PinType.PinSubCategoryObject = nullptr; // } } @@ -82,13 +82,13 @@ void UK2Node_EnumEquality::NotifyPinConnectionListChanged(UEdGraphPin* Pin) { // Restore the wildcard status Input1Pin->PinType.PinCategory = Schema->PC_Wildcard; - Input1Pin->PinType.PinSubCategory = TEXT(""); - Input1Pin->PinType.PinSubCategoryObject = NULL; + Input1Pin->PinType.PinSubCategory.Reset(); + Input1Pin->PinType.PinSubCategoryObject = nullptr; Input2Pin->PinType.PinCategory = Schema->PC_Wildcard; - Input2Pin->PinType.PinSubCategory = TEXT(""); - Input2Pin->PinType.PinSubCategoryObject = NULL; - Schema->SetPinDefaultValueBasedOnType(Input1Pin); - Schema->SetPinDefaultValueBasedOnType(Input2Pin); + Input2Pin->PinType.PinSubCategory.Reset(); + Input2Pin->PinType.PinSubCategoryObject = nullptr; + Schema->SetPinAutogeneratedDefaultValueBasedOnType(Input1Pin); + Schema->SetPinAutogeneratedDefaultValueBasedOnType(Input2Pin); // We have to refresh the graph to get the enum dropdowns to go away GetGraph()->NotifyGraphChanged(); } @@ -109,7 +109,7 @@ void UK2Node_EnumEquality::NotifyPinConnectionListChanged(UEdGraphPin* Pin) // If we copied the pin type to a wildcard we have to refresh the graph to get the enum dropdown if (OtherPin->LinkedTo.Num() <= 0 && OtherPin->DefaultValue.IsEmpty()) { - Schema->SetPinDefaultValueBasedOnType(OtherPin); + Schema->SetPinAutogeneratedDefaultValueBasedOnType(OtherPin); GetGraph()->NotifyGraphChanged(); } } @@ -121,7 +121,7 @@ void UK2Node_EnumEquality::NotifyPinConnectionListChanged(UEdGraphPin* Pin) } else if(Pin->DefaultValue.IsEmpty()) { - Schema->SetPinDefaultValueBasedOnType(Pin); + Schema->SetPinAutogeneratedDefaultValueBasedOnType(Pin); } } } @@ -194,7 +194,7 @@ void UK2Node_EnumEquality::ExpandNode(class FKismetCompilerContext& CompilerCont GetConditionalFunction(ConditionalFunctionName, &ConditionalFunctionClass); // Create the conditional node we're replacing the enum node for - UK2Node_CallFunction* ConditionalNode = SourceGraph->CreateBlankNode(); + UK2Node_CallFunction* ConditionalNode = SourceGraph->CreateIntermediateNode(); ConditionalNode->FunctionReference.SetExternalMember(ConditionalFunctionName, ConditionalFunctionClass); ConditionalNode->AllocateDefaultPins(); CompilerContext.MessageLog.NotifyIntermediateObjectCreation(ConditionalNode, this); diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_EnumLiteral.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_EnumLiteral.cpp index a69915fc38e5..404cf3401f9d 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_EnumLiteral.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_EnumLiteral.cpp @@ -34,10 +34,10 @@ void UK2Node_EnumLiteral::AllocateDefaultPins() { const UEdGraphSchema_K2* Schema = GetDefault(); - auto InputPin = CreatePin(EGPD_Input, Schema->PC_Byte, TEXT(""), Enum, false, false, GetEnumInputPinName()); - Schema->SetPinDefaultValueBasedOnType(InputPin); + auto InputPin = CreatePin(EGPD_Input, Schema->PC_Byte, FString(), Enum, GetEnumInputPinName()); + Schema->SetPinAutogeneratedDefaultValueBasedOnType(InputPin); - CreatePin(EGPD_Output, Schema->PC_Byte, TEXT(""), Enum, false, false, Schema->PN_ReturnValue); + CreatePin(EGPD_Output, Schema->PC_Byte, FString(), Enum, Schema->PN_ReturnValue); Super::AllocateDefaultPins(); } diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Event.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Event.cpp index a33813bf9b9c..8fa8c2023993 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Event.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Event.cpp @@ -76,7 +76,7 @@ void UK2Node_Event::PostLoad() if (!FindPin(DelegateOutputName)) { const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Output, K2Schema->PC_Delegate, TEXT(""), NULL, false, false, DelegateOutputName); + CreatePin(EGPD_Output, K2Schema->PC_Delegate, FString(), nullptr, DelegateOutputName); } } @@ -191,7 +191,7 @@ FString UK2Node_Event::GetDocumentationLink() const return FString::Printf(TEXT("Shared/Types/%s%s"), EventSignatureClass->GetPrefixCPP(), *EventSignatureClass->GetName()); } - return TEXT(""); + return FString(); } FString UK2Node_Event::GetDocumentationExcerptName() const @@ -308,11 +308,11 @@ void UK2Node_Event::AllocateDefaultPins() { const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Output, K2Schema->PC_Delegate, TEXT(""), NULL, false, false, DelegateOutputName); - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Then); + CreatePin(EGPD_Output, K2Schema->PC_Delegate, FString(), nullptr, DelegateOutputName); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Then); const UFunction* Function = FindEventSignatureFunction(); - if (Function != NULL) + if (Function) { CreatePinsForFunctionEntryExit(Function, /*bIsFunctionEntry=*/ true); } diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_ExecutionSequence.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_ExecutionSequence.cpp index b92c11ad512b..5167376ad6ac 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_ExecutionSequence.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_ExecutionSequence.cpp @@ -163,13 +163,11 @@ void UK2Node_ExecutionSequence::AllocateDefaultPins() { const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Execute); + CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Execute); // Add two default pins - for (int32 i = 0; i < 2; ++i) - { - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, GetPinNameGivenIndex(i)); - } + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, GetPinNameGivenIndex(0)); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, GetPinNameGivenIndex(1)); Super::AllocateDefaultPins(); } @@ -216,7 +214,7 @@ FString UK2Node_ExecutionSequence::GetUniquePinName() void UK2Node_ExecutionSequence::AddPinToExecutionNode() { const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, GetUniquePinName()); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, GetUniquePinName()); } void UK2Node_ExecutionSequence::RemovePinFromExecutionNode(UEdGraphPin* TargetPin) @@ -272,7 +270,7 @@ void UK2Node_ExecutionSequence::ReallocatePinsDuringReconstruction(TArray(); - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Execute); + CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Execute); // Create a new pin for each old execution output pin, and coerce the names to match on both sides int32 ExecOutPinCount = 0; @@ -288,7 +286,7 @@ void UK2Node_ExecutionSequence::ReallocatePinsDuringReconstruction(TArrayPinName = NewPinName; // Create the new output pin to match - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, NewPinName); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, NewPinName); } } } diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_ForEachElementInEnum.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_ForEachElementInEnum.cpp index a0946132411e..5b5b3913e806 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_ForEachElementInEnum.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_ForEachElementInEnum.cpp @@ -144,15 +144,15 @@ void UK2Node_ForEachElementInEnum::AllocateDefaultPins() const UEdGraphSchema_K2* K2Schema = GetDefault(); check(K2Schema); - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Execute); + CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Execute); if (Enum) { - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, InsideLoopPinName); - CreatePin(EGPD_Output, K2Schema->PC_Byte, TEXT(""), Enum, false, false, EnumOuputPinName); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, InsideLoopPinName); + CreatePin(EGPD_Output, K2Schema->PC_Byte, FString(), Enum, EnumOuputPinName); } - if (auto CompletedPin = CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Then)) + if (UEdGraphPin* CompletedPin = CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Then)) { CompletedPin->PinFriendlyName = LOCTEXT("Completed", "Completed"); } @@ -160,6 +160,8 @@ void UK2Node_ForEachElementInEnum::AllocateDefaultPins() void UK2Node_ForEachElementInEnum::ValidateNodeDuringCompilation(FCompilerResultsLog& MessageLog) const { + Super::ValidateNodeDuringCompilation(MessageLog); + if (!Enum) { MessageLog.Error(*NSLOCTEXT("K2Node", "ForEachElementInEnum_NoEnumError", "No Enum in @@").ToString(), this); diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_FormatText.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_FormatText.cpp index 421ce4b07000..89156a347aa7 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_FormatText.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_FormatText.cpp @@ -44,12 +44,12 @@ void UK2Node_FormatText::AllocateDefaultPins() Super::AllocateDefaultPins(); const UEdGraphSchema_K2* K2Schema = GetDefault(); - CachedFormatPin = CreatePin(EGPD_Input, K2Schema->PC_Text, TEXT(""), NULL, false, false, FFormatTextNodeHelper::GetFormatPinName()); - CreatePin(EGPD_Output, K2Schema->PC_Text, TEXT(""), NULL, false, false, TEXT("Result")); + CachedFormatPin = CreatePin(EGPD_Input, K2Schema->PC_Text, FString(), nullptr, FFormatTextNodeHelper::GetFormatPinName()); + CreatePin(EGPD_Output, K2Schema->PC_Text, FString(), nullptr, TEXT("Result")); - for(auto It = PinNames.CreateConstIterator(); It; ++It) + for (const FString& PinName : PinNames) { - CreatePin(EGPD_Input, K2Schema->PC_Wildcard, TEXT(""), NULL, false, false, *It); + CreatePin(EGPD_Input, K2Schema->PC_Wildcard, FString(), nullptr, PinName); } } @@ -63,7 +63,7 @@ void UK2Node_FormatText::SynchronizeArgumentPinType(UEdGraphPin* Pin) bool bPinTypeChanged = false; if (Pin->LinkedTo.Num() == 0) { - static const FEdGraphPinType WildcardPinType = FEdGraphPinType(K2Schema->PC_Wildcard, TEXT(""), nullptr, false, false, false, false, FEdGraphTerminalType()); + static const FEdGraphPinType WildcardPinType = FEdGraphPinType(K2Schema->PC_Wildcard, FString(), nullptr, EPinContainerType::None, false, FEdGraphTerminalType()); // Ensure wildcard if (Pin->PinType != WildcardPinType) @@ -137,7 +137,7 @@ void UK2Node_FormatText::PostEditChangeProperty(struct FPropertyChangedEvent& Pr void UK2Node_FormatText::PinConnectionListChanged(UEdGraphPin* Pin) { - const auto FormatPin = GetFormatPin(); + UEdGraphPin* FormatPin = GetFormatPin(); Modify(); @@ -168,7 +168,7 @@ void UK2Node_FormatText::PinConnectionListChanged(UEdGraphPin* Pin) void UK2Node_FormatText::PinDefaultValueChanged(UEdGraphPin* Pin) { - const auto FormatPin = GetFormatPin(); + const UEdGraphPin* FormatPin = GetFormatPin(); if(Pin == FormatPin && FormatPin->LinkedTo.Num() == 0) { const UEdGraphSchema_K2* K2Schema = GetDefault(); @@ -178,13 +178,13 @@ void UK2Node_FormatText::PinDefaultValueChanged(UEdGraphPin* Pin) PinNames.Empty(); - for(auto It = ArgumentParams.CreateConstIterator(); It; ++It) + for (const FString& Param : ArgumentParams) { - if(!FindArgumentPin(*It)) + if(!FindArgumentPin(Param)) { - CreatePin(EGPD_Input, K2Schema->PC_Wildcard, TEXT(""), NULL, false, false, *It); + CreatePin(EGPD_Input, K2Schema->PC_Wildcard, FString(), nullptr, Param); } - PinNames.Add(*It); + PinNames.Add(Param); } for(auto It = Pins.CreateConstIterator(); It; ++It) @@ -301,7 +301,7 @@ void UK2Node_FormatText::ExpandNode(class FKismetCompilerContext& CompilerContex const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema(); // Create a "Make Array" node to compile the list of arguments into an array for the Format function being called - UK2Node_MakeArray* MakeArrayNode = CompilerContext.SpawnIntermediateNode(this, SourceGraph); //SourceGraph->CreateBlankNode(); + UK2Node_MakeArray* MakeArrayNode = CompilerContext.SpawnIntermediateNode(this, SourceGraph); MakeArrayNode->AllocateDefaultPins(); CompilerContext.MessageLog.NotifyIntermediateObjectCreation(MakeArrayNode, this); @@ -421,7 +421,7 @@ void UK2Node_FormatText::ExpandNode(class FKismetCompilerContext& CompilerContex UEdGraphPin* UK2Node_FormatText::FindArgumentPin(const FString& InPinName) const { - const auto FormatPin = GetFormatPin(); + const UEdGraphPin* FormatPin = GetFormatPin(); for(int32 PinIdx=0; PinIdxDirection != EGPD_Output && Pins[PinIdx]->PinName.Equals(InPinName) ) @@ -527,7 +527,7 @@ void UK2Node_FormatText::AddArgumentPin() const UEdGraphSchema_K2* K2Schema = Cast(GetSchema()); FString PinName = GetUniquePinName(); - CreatePin(EGPD_Input, K2Schema->PC_Wildcard, TEXT(""), NULL, false, false, PinName); + CreatePin(EGPD_Input, K2Schema->PC_Wildcard, FString(), nullptr, PinName); PinNames.Add(PinName); FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(GetBlueprint()); diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_FunctionEntry.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_FunctionEntry.cpp index 3bee4c8e3a63..22ddbf5e7e8c 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_FunctionEntry.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_FunctionEntry.cpp @@ -3,8 +3,10 @@ #include "K2Node_FunctionEntry.h" #include "Engine/Blueprint.h" +#include "Animation/AnimBlueprint.h" #include "UObject/UnrealType.h" #include "UObject/BlueprintsObjectVersion.h" +#include "UObject/FrameworkObjectVersion.h" #include "UObject/StructOnScope.h" #include "Engine/UserDefinedStruct.h" #include "EdGraph/EdGraphSchema.h" @@ -195,10 +197,20 @@ void UK2Node_FunctionEntry::Serialize(FArchive& Ar) Super::Serialize(Ar); Ar.UsingCustomVersion(FBlueprintsObjectVersion::GUID); + Ar.UsingCustomVersion(FFrameworkObjectVersion::GUID); if (Ar.IsLoading()) { - if (Ar.UE4Ver() < VER_UE4_BLUEPRINT_ENFORCE_CONST_IN_FUNCTION_OVERRIDES) + if (Ar.CustomVer(FFrameworkObjectVersion::GUID) < FFrameworkObjectVersion::LocalVariablesBlueprintVisible) + { + for (FBPVariableDescription& LocalVariable : LocalVariables) + { + LocalVariable.PropertyFlags |= CPF_BlueprintVisible; + } + } + + if (Ar.UE4Ver() < VER_UE4_BLUEPRINT_ENFORCE_CONST_IN_FUNCTION_OVERRIDES + || ((Ar.CustomVer(FFrameworkObjectVersion::GUID) < FFrameworkObjectVersion::EnforceConstInAnimBlueprintFunctionGraphs) && GetBlueprint()->IsA())) { // Allow legacy implementations to violate const-correctness bEnforceConstCorrectness = false; @@ -219,6 +231,33 @@ void UK2Node_FunctionEntry::Serialize(FArchive& Ar) FUNC_Delegate | FUNC_HasOutParms | FUNC_HasDefaults | FUNC_DLLImport | FUNC_NetValidate; ExtraFlags &= ~InvalidExtraFlagsMask; } + + if (Ar.CustomVer(FFrameworkObjectVersion::GUID) < FFrameworkObjectVersion::ChangeAssetPinsToString) + { + const UEdGraphSchema_K2* K2Schema = GetDefault(); + + // Prior to this version, changing the type of a local variable would lead to corrupt default value strings + for (FBPVariableDescription& LocalVar : LocalVariables) + { + FString UseDefaultValue; + UObject* UseDefaultObject = nullptr; + FText UseDefaultText; + + if (!LocalVar.DefaultValue.IsEmpty()) + { + K2Schema->GetPinDefaultValuesFromString(LocalVar.VarType, this, LocalVar.DefaultValue, UseDefaultValue, UseDefaultObject, UseDefaultText); + FString ErrorMessage; + + if (!K2Schema->DefaultValueSimpleValidation(LocalVar.VarType, LocalVar.VarName.ToString(), UseDefaultValue, UseDefaultObject, UseDefaultText, &ErrorMessage)) + { + const UBlueprint* Blueprint = GetBlueprint(); + UE_LOG(LogBlueprint, Log, TEXT("Clearing invalid default value for local variable %s on blueprint %s: %s"), *LocalVar.VarName.ToString(), Blueprint ? *Blueprint->GetName() : TEXT("Unknown"), *ErrorMessage); + + LocalVar.DefaultValue.Reset(); + } + } + } + } } } @@ -234,7 +273,7 @@ FText UK2Node_FunctionEntry::GetNodeTitle(ENodeTitleType::Type TitleType) const void UK2Node_FunctionEntry::AllocateDefaultPins() { const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Then); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Then); UFunction* Function = FindField(SignatureClass, SignatureName); @@ -258,8 +297,6 @@ void UK2Node_FunctionEntry::AllocateDefaultPins() K2Schema->PC_Object, FString(), UObject::StaticClass(), - false, - false, FFunctionEntryHelper::GetWorldContextPinName()); WorldContextPin->bHidden = true; } @@ -304,7 +341,7 @@ UEdGraphPin* UK2Node_FunctionEntry::CreatePinFromUserDefinition(const TSharedPtr } UEdGraphPin* NewPin = CreatePin(EGPD_Output, NewPinInfo->PinType, NewPinInfo->PinName); - NewPin->DefaultValue = NewPin->AutogeneratedDefaultValue = NewPinInfo->PinDefaultValue; + Schema->SetPinAutogeneratedDefaultValue(NewPin, NewPinInfo->PinDefaultValue); return NewPin; } @@ -426,7 +463,7 @@ void UK2Node_FunctionEntry::ExpandNode(class FKismetCompilerContext& CompilerCon //UDS requires default data even when the LocalVariable value is empty const bool bUDSProperty = PotentialUDSProperty && Cast(PotentialUDSProperty->Struct); - for (auto& LocalVar : LocalVariables) + for (const FBPVariableDescription& LocalVar : LocalVariables) { if (LocalVar.VarName == Property->GetFName() && (bUDSProperty || !LocalVar.DefaultValue.IsEmpty())) { @@ -438,7 +475,7 @@ void UK2Node_FunctionEntry::ExpandNode(class FKismetCompilerContext& CompilerCon if(UEdGraphPin* SetPin = VariableSetNode->FindPin(Property->GetName())) { - if(LocalVar.VarType.bIsArray) + if(LocalVar.VarType.IsArray()) { TSharedPtr StructData = MakeShareable(new FStructOnScope(Function)); FBlueprintEditorUtils::PropertyValueFromString(Property, LocalVar.DefaultValue, StructData->GetStructMemory()); @@ -473,7 +510,7 @@ void UK2Node_FunctionEntry::ExpandNode(class FKismetCompilerContext& CompilerCon Schema->TrySetDefaultValue(*MakeArray->Pins[ArrayIndex + 1], DefaultValue); } } - else if(LocalVar.VarType.bIsSet || LocalVar.VarType.bIsMap) + else if(LocalVar.VarType.IsSet() || LocalVar.VarType.IsMap()) { UK2Node_MakeVariable* MakeVariableNode = CompilerContext.SpawnIntermediateNode(this, SourceGraph); MakeVariableNode->SetupVariable(LocalVar, SetPin, CompilerContext, Function, Property); @@ -513,7 +550,8 @@ void UK2Node_FunctionEntry::ExpandNode(class FKismetCompilerContext& CompilerCon static void RefreshUDSValuesStoredAsString(const FEdGraphPinType& VarType, FString& Value) { - if (!Value.IsEmpty() && VarType.PinCategory == UEdGraphSchema_K2::PC_Struct) + // For container structs just keep the value from before, container structs do not delta serialize + if (!Value.IsEmpty() && VarType.PinCategory == UEdGraphSchema_K2::PC_Struct && !VarType.IsContainer()) { UUserDefinedStruct* UDS = Cast(VarType.PinSubCategoryObject.Get()); if (UDS) @@ -546,5 +584,17 @@ void UK2Node_FunctionEntry::PostReconstructNode() } } +bool UK2Node_FunctionEntry::ModifyUserDefinedPinDefaultValue(TSharedPtr PinInfo, const FString& NewDefaultValue) +{ + if (Super::ModifyUserDefinedPinDefaultValue(PinInfo, NewDefaultValue)) + { + const UEdGraphSchema_K2* K2Schema = GetDefault(); + K2Schema->HandleParameterDefaultValueChanged(this); + + return true; + } + return false; +} + #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_FunctionResult.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_FunctionResult.cpp index 6f36b02de8be..b48ed966e68d 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_FunctionResult.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_FunctionResult.cpp @@ -23,7 +23,7 @@ private: const bool bNeedToResetDefaultValue = (Pin->DefaultValue.IsEmpty() && Pin->DefaultObject == nullptr && Pin->DefaultTextValue.IsEmpty()) || !(K2Schema->IsPinDefaultValid(Pin, Pin->DefaultValue, Pin->DefaultObject, Pin->DefaultTextValue).IsEmpty()); if (bValuePin && bNotConnected && bNeedToResetDefaultValue) { - K2Schema->SetPinDefaultValueBasedOnType(Pin); + K2Schema->SetPinAutogeneratedDefaultValueBasedOnType(Pin); } } } @@ -133,7 +133,7 @@ FText UK2Node_FunctionResult::GetNodeTitle(ENodeTitleType::Type TitleType) const void UK2Node_FunctionResult::AllocateDefaultPins() { const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Execute); + CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Execute); UFunction* Function = FindField(SignatureClass, SignatureName); if (Function != NULL) diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GenericCreateObject.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GenericCreateObject.cpp index 23b270d5d91c..46b2d2837624 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GenericCreateObject.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GenericCreateObject.cpp @@ -17,29 +17,29 @@ void UK2Node_GenericCreateObject::ExpandNode(class FKismetCompilerContext& Compi bool bSucceeded = true; //connect exe { - auto SpawnExecPin = GetExecPin(); - auto CallExecPin = CallCreateNode->GetExecPin(); + UEdGraphPin* SpawnExecPin = GetExecPin(); + UEdGraphPin* CallExecPin = CallCreateNode->GetExecPin(); bSucceeded &= SpawnExecPin && CallExecPin && CompilerContext.MovePinLinksToIntermediate(*SpawnExecPin, *CallExecPin).CanSafeConnect(); } //connect class { - auto SpawnClassPin = GetClassPin(); - auto CallClassPin = CallCreateNode->FindPin(TEXT("ObjectClass")); + UEdGraphPin* SpawnClassPin = GetClassPin(); + UEdGraphPin* CallClassPin = CallCreateNode->FindPin(TEXT("ObjectClass")); bSucceeded &= SpawnClassPin && CallClassPin && CompilerContext.MovePinLinksToIntermediate(*SpawnClassPin, *CallClassPin).CanSafeConnect(); } //connect outer { - auto SpawnOuterPin = GetOuterPin(); - auto CallOuterPin = CallCreateNode->FindPin(TEXT("Outer")); + UEdGraphPin* SpawnOuterPin = GetOuterPin(); + UEdGraphPin* CallOuterPin = CallCreateNode->FindPin(TEXT("Outer")); bSucceeded &= SpawnOuterPin && CallOuterPin && CompilerContext.MovePinLinksToIntermediate(*SpawnOuterPin, *CallOuterPin).CanSafeConnect(); } UEdGraphPin* CallResultPin = nullptr; //connect result { - auto SpawnResultPin = GetResultPin(); + UEdGraphPin* SpawnResultPin = GetResultPin(); CallResultPin = CallCreateNode->GetReturnValuePin(); // cast HACK. It should be safe. The only problem is native code generation. @@ -52,8 +52,8 @@ void UK2Node_GenericCreateObject::ExpandNode(class FKismetCompilerContext& Compi //assign exposed values and connect then { - auto LastThen = FKismetCompilerUtilities::GenerateAssignmentNodes(CompilerContext, SourceGraph, CallCreateNode, this, CallResultPin, GetClassToSpawn()); - auto SpawnNodeThen = GetThenPin(); + UEdGraphPin* LastThen = FKismetCompilerUtilities::GenerateAssignmentNodes(CompilerContext, SourceGraph, CallCreateNode, this, CallResultPin, GetClassToSpawn()); + UEdGraphPin* SpawnNodeThen = GetThenPin(); bSucceeded &= SpawnNodeThen && LastThen && CompilerContext.MovePinLinksToIntermediate(*SpawnNodeThen, *LastThen).CanSafeConnect(); } @@ -65,23 +65,18 @@ void UK2Node_GenericCreateObject::ExpandNode(class FKismetCompilerContext& Compi } } -void UK2Node_GenericCreateObject::ValidateNodeDuringCompilation(class FCompilerResultsLog& MessageLog) const -{ - Super::ValidateNodeDuringCompilation(MessageLog); -} - void UK2Node_GenericCreateObject::EarlyValidation(class FCompilerResultsLog& MessageLog) const { Super::EarlyValidation(MessageLog); - auto ClassPin = GetClassPin(&Pins); + UEdGraphPin* ClassPin = GetClassPin(&Pins); const bool bAllowAbstract = ClassPin && ClassPin->LinkedTo.Num(); - auto ClassToSpawn = GetClassToSpawn(); + UClass* ClassToSpawn = GetClassToSpawn(); if (!UGameplayStatics::CanSpawnObjectOfClass(ClassToSpawn, bAllowAbstract)) { MessageLog.Error(*FString::Printf(*LOCTEXT("GenericCreateObject_WrongClass", "Wrong class to spawn '%s' in @@").ToString(), *GetPathNameSafe(ClassToSpawn)), this); } - auto OuterPin = GetOuterPin(); + UEdGraphPin* OuterPin = GetOuterPin(); if (!OuterPin || (!OuterPin->DefaultObject && !OuterPin->LinkedTo.Num())) { MessageLog.Error(*LOCTEXT("GenericCreateObject_NoOuter", "Outer object is required in @@").ToString(), this); diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetArrayItem.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetArrayItem.cpp index e4263be5e9bd..8e0a0b2696f5 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetArrayItem.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetArrayItem.cpp @@ -61,9 +61,8 @@ public: { UK2Node_GetArrayItem* ArrayNode = CastChecked(Node); - FBlueprintCompiledStatement* SelectStatementPtr = new FBlueprintCompiledStatement(); - FBlueprintCompiledStatement& ArrayGetFunction = *SelectStatementPtr; - ArrayGetFunction.Type = KCST_ArrayGetByRef; + FBlueprintCompiledStatement* ArrayGetFunction = new FBlueprintCompiledStatement(); + ArrayGetFunction->Type = KCST_ArrayGetByRef; UEdGraphPin* ArrayPinNet = FEdGraphUtilities::GetNetFromPin(Node->Pins[0]); UEdGraphPin* ReturnValueNet = FEdGraphUtilities::GetNetFromPin(Node->Pins[2]); @@ -77,10 +76,10 @@ public: FBPTerminal** ReturnValue = Context.NetMap.Find(ReturnValueNet); FBPTerminal** ReturnValueOrig = Context.NetMap.Find(Node->Pins[2]); - ArrayGetFunction.RHS.Add(*ArrayTerm); - ArrayGetFunction.RHS.Add(*IndexTermPtr); + ArrayGetFunction->RHS.Add(*ArrayTerm); + ArrayGetFunction->RHS.Add(*IndexTermPtr); - (*ReturnValue)->InlineGeneratedParameter = &ArrayGetFunction; + (*ReturnValue)->InlineGeneratedParameter = ArrayGetFunction; } }; @@ -120,12 +119,12 @@ UK2Node_GetArrayItem::UK2Node_GetArrayItem(const FObjectInitializer& ObjectIniti void UK2Node_GetArrayItem::AllocateDefaultPins() { // Create the output pin - CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Wildcard, TEXT(""), NULL, true, false, TEXT("Array")); - UEdGraphPin* IndexPin = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Int, TEXT(""), NULL, false, false, TEXT("Dimension 1")); - GetDefault()->SetPinDefaultValueBasedOnType(IndexPin); + CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Wildcard, FString(), nullptr, TEXT("Array"), EPinContainerType::Array); + UEdGraphPin* IndexPin = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Int, FString(), nullptr, TEXT("Dimension 1")); + GetDefault()->SetPinAutogeneratedDefaultValueBasedOnType(IndexPin); // Create the input pins to create the arrays from - CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Wildcard, TEXT(""), NULL, false, bReturnByRefDesired, TEXT("Output")); + CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Wildcard, FString(), nullptr, TEXT("Output"), EPinContainerType::None, bReturnByRefDesired); } void UK2Node_GetArrayItem::PostReconstructNode() @@ -268,6 +267,7 @@ void UK2Node_GetArrayItem::NotifyPinConnectionListChanged(UEdGraphPin* Pin) if (NewType.PinCategory != UEdGraphSchema_K2::PC_Wildcard) { PropagatePinType(NewType); + GetGraph()->NotifyGraphChanged(); } } } @@ -411,7 +411,7 @@ void UK2Node_GetArrayItem::PropagatePinType(FEdGraphPinType& InType) UEdGraphPin* ResultPin = Pins[2]; ArrayPin->PinType = InType; - ArrayPin->PinType.bIsArray = true; + ArrayPin->PinType.ContainerType = EPinContainerType::Array; ArrayPin->PinType.bIsReference = false; // IsSetToReturnRef() has to be called after the ArrayPin's type is set, since it uses that to determine the result @@ -427,7 +427,7 @@ void UK2Node_GetArrayItem::PropagatePinType(FEdGraphPinType& InType) } ResultPin->PinType = InType; - ResultPin->PinType.bIsArray = false; + ResultPin->PinType.ContainerType = EPinContainerType::None; ResultPin->PinType.bIsReference = bMakeOutputRef; ResultPin->PinType.bIsConst = false; diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetClassDefaults.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetClassDefaults.cpp index 3c000cfc6ab2..6ffb062e758e 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetClassDefaults.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetClassDefaults.cpp @@ -212,7 +212,7 @@ void UK2Node_GetClassDefaults::AllocateDefaultPins() const UEdGraphSchema_K2* K2Schema = GetDefault(); // Create the class input type selector pin - UEdGraphPin* ClassPin = CreatePin(EGPD_Input, K2Schema->PC_Class, TEXT(""), UObject::StaticClass(), false, false, ClassPinName); + UEdGraphPin* ClassPin = CreatePin(EGPD_Input, K2Schema->PC_Class, FString(), UObject::StaticClass(), ClassPinName); K2Schema->ConstructBasicPinTooltip(*ClassPin, LOCTEXT("ClassPinDescription", "The class from which to access one or more default values."), ClassPin->PinToolTip); } diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetDataTableRow.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetDataTableRow.cpp index 0af42f1c4666..cd6970ac87ed 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetDataTableRow.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetDataTableRow.cpp @@ -37,21 +37,21 @@ void UK2Node_GetDataTableRow::AllocateDefaultPins() const UEdGraphSchema_K2* K2Schema = GetDefault(); // Add execution pins - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Execute); - UEdGraphPin* RowFoundPin = CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Then); + CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Execute); + UEdGraphPin* RowFoundPin = CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Then); RowFoundPin->PinFriendlyName = LOCTEXT("GetDataTableRow Row Found Exec pin", "Row Found"); - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, UK2Node_GetDataTableRowHelper::RowNotFoundPinName); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, UK2Node_GetDataTableRowHelper::RowNotFoundPinName); // Add DataTable pin - UEdGraphPin* DataTablePin = CreatePin(EGPD_Input, K2Schema->PC_Object, TEXT(""), UDataTable::StaticClass(), false, false, UK2Node_GetDataTableRowHelper::DataTablePinName); + UEdGraphPin* DataTablePin = CreatePin(EGPD_Input, K2Schema->PC_Object, FString(), UDataTable::StaticClass(), UK2Node_GetDataTableRowHelper::DataTablePinName); SetPinToolTip(*DataTablePin, LOCTEXT("DataTablePinDescription", "The DataTable you want to retreive a row from")); // Row Name pin - UEdGraphPin* RowNamePin = CreatePin(EGPD_Input, K2Schema->PC_Name, TEXT(""), NULL, false, false, UK2Node_GetDataTableRowHelper::RowNamePinName); + UEdGraphPin* RowNamePin = CreatePin(EGPD_Input, K2Schema->PC_Name, FString(), nullptr, UK2Node_GetDataTableRowHelper::RowNamePinName); SetPinToolTip(*RowNamePin, LOCTEXT("RowNamePinDescription", "The name of the row to retrieve from the DataTable")); // Result pin - UEdGraphPin* ResultPin = CreatePin(EGPD_Output, K2Schema->PC_Wildcard, TEXT(""), nullptr, false, false, K2Schema->PN_ReturnValue); + UEdGraphPin* ResultPin = CreatePin(EGPD_Output, K2Schema->PC_Wildcard, FString(), nullptr, K2Schema->PN_ReturnValue); ResultPin->PinFriendlyName = LOCTEXT("GetDataTableRow Output Row", "Out Row"); SetPinToolTip(*ResultPin, LOCTEXT("ResultPinDescription", "The returned TableRow, if found")); @@ -149,12 +149,12 @@ void UK2Node_GetDataTableRow::OnDataTableRowListChanged(const UDataTable* DataTa UEdGraphPin* DataTablePin = GetDataTablePin(); if (DataTable && DataTablePin && DataTable == DataTablePin->DefaultObject) { - auto RowNamePin = GetRowNamePin(); + UEdGraphPin* RowNamePin = GetRowNamePin(); const bool TryRefresh = RowNamePin && !RowNamePin->LinkedTo.Num(); const FName CurrentName = RowNamePin ? FName(*RowNamePin->GetDefaultAsString()) : NAME_None; if (TryRefresh && RowNamePin && !DataTable->GetRowNames().Contains(CurrentName)) { - if (auto BP = GetBlueprint()) + if (UBlueprint* BP = GetBlueprint()) { FBlueprintEditorUtils::MarkBlueprintAsModified(BP); } @@ -269,17 +269,16 @@ UEdGraphPin* UK2Node_GetDataTableRow::GetDataTablePin(const TArray { const TArray* PinsToSearch = InPinsToSearch ? InPinsToSearch : &Pins; - UEdGraphPin* Pin = NULL; - for( auto PinIt = PinsToSearch->CreateConstIterator(); PinIt; ++PinIt ) + UEdGraphPin* Pin = nullptr; + for (UEdGraphPin* TestPin : *PinsToSearch) { - UEdGraphPin* TestPin = *PinIt; - if( TestPin && TestPin->PinName == UK2Node_GetDataTableRowHelper::DataTablePinName) + if (TestPin && TestPin->PinName == UK2Node_GetDataTableRowHelper::DataTablePinName) { Pin = TestPin; break; } } - check(Pin == NULL || Pin->Direction == EGPD_Input); + check(Pin == nullptr || Pin->Direction == EGPD_Input); return Pin; } @@ -418,8 +417,10 @@ void UK2Node_GetDataTableRow::PostReconstructNode() void UK2Node_GetDataTableRow::EarlyValidation(class FCompilerResultsLog& MessageLog) const { - const auto DataTablePin = GetDataTablePin(); - const auto RowNamePin = GetRowNamePin(); + Super::EarlyValidation(MessageLog); + + const UEdGraphPin* DataTablePin = GetDataTablePin(); + const UEdGraphPin* RowNamePin = GetRowNamePin(); if (!DataTablePin || !RowNamePin) { MessageLog.Error(*LOCTEXT("MissingPins", "Missing pins in @@").ToString(), this); @@ -428,7 +429,7 @@ void UK2Node_GetDataTableRow::EarlyValidation(class FCompilerResultsLog& Message if (DataTablePin->LinkedTo.Num() == 0) { - const auto DataTable = Cast(DataTablePin->DefaultObject); + const UDataTable* DataTable = Cast(DataTablePin->DefaultObject); if (!DataTable) { MessageLog.Error(*LOCTEXT("NoDataTable", "No DataTable in @@").ToString(), this); diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetEnumeratorName.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetEnumeratorName.cpp index 348fb3ff370d..76889c147dc2 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetEnumeratorName.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetEnumeratorName.cpp @@ -22,8 +22,8 @@ void UK2Node_GetEnumeratorName::AllocateDefaultPins() { const UEdGraphSchema_K2* Schema = GetDefault(); - CreatePin(EGPD_Input, Schema->PC_Byte, TEXT(""), NULL, false, false, EnumeratorPinName); - CreatePin(EGPD_Output, Schema->PC_Name, TEXT(""), NULL, false, false, Schema->PN_ReturnValue); + CreatePin(EGPD_Input, Schema->PC_Byte, FString(), nullptr, EnumeratorPinName); + CreatePin(EGPD_Output, Schema->PC_Name, FString(), nullptr, Schema->PN_ReturnValue); } FText UK2Node_GetEnumeratorName::GetTooltipText() const @@ -45,11 +45,13 @@ UEnum* UK2Node_GetEnumeratorName::GetEnum() const { const UEdGraphPin* InputPin = FindPinChecked(EnumeratorPinName); const UEdGraphPin* EnumPin = InputPin->LinkedTo.Num() ? InputPin->LinkedTo[0] : InputPin; - return EnumPin ? Cast(EnumPin->PinType.PinSubCategoryObject.Get()) : NULL; + return EnumPin ? Cast(EnumPin->PinType.PinSubCategoryObject.Get()) : nullptr; } void UK2Node_GetEnumeratorName::ValidateNodeDuringCompilation(class FCompilerResultsLog& MessageLog) const { + Super::ValidateNodeDuringCompilation(MessageLog); + const UEdGraphSchema_K2* Schema = GetDefault(); const UEdGraphPin* OutputPin = FindPinChecked(Schema->PN_ReturnValue); /*Don't validate isolated nodes */ @@ -67,8 +69,10 @@ FSlateIcon UK2Node_GetEnumeratorName::GetIconAndTint(FLinearColor& OutColor) con void UK2Node_GetEnumeratorName::EarlyValidation(class FCompilerResultsLog& MessageLog) const { + Super::EarlyValidation(MessageLog); + const UEnum* Enum = GetEnum(); - if (NULL == Enum) + if (nullptr == Enum) { MessageLog.Error(*NSLOCTEXT("K2Node", "GetNumEnumEntries_NoIntput_Error", "@@ Must have non-default Enum input").ToString(), this); } diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetEnumeratorNameAsString.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetEnumeratorNameAsString.cpp index d6e9a299dd34..4675a2358004 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetEnumeratorNameAsString.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetEnumeratorNameAsString.cpp @@ -17,8 +17,8 @@ void UK2Node_GetEnumeratorNameAsString::AllocateDefaultPins() { const UEdGraphSchema_K2* Schema = GetDefault(); - CreatePin(EGPD_Input, Schema->PC_Byte, TEXT(""), NULL, false, false, EnumeratorPinName); - CreatePin(EGPD_Output, Schema->PC_String, TEXT(""), NULL, false, false, Schema->PN_ReturnValue); + CreatePin(EGPD_Input, Schema->PC_Byte, FString(), nullptr, EnumeratorPinName); + CreatePin(EGPD_Output, Schema->PC_String, FString(), nullptr, Schema->PN_ReturnValue); } FText UK2Node_GetEnumeratorNameAsString::GetTooltipText() const diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetNumEnumEntries.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetNumEnumEntries.cpp index d541d0f2ff23..11ecebf0b2ea 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetNumEnumEntries.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_GetNumEnumEntries.cpp @@ -20,7 +20,7 @@ void UK2Node_GetNumEnumEntries::AllocateDefaultPins() const UEdGraphSchema_K2* Schema = GetDefault(); // Create the return value pin - CreatePin(EGPD_Output, Schema->PC_Int, TEXT(""), NULL, false, false, Schema->PN_ReturnValue); + CreatePin(EGPD_Output, Schema->PC_Int, FString(), nullptr, Schema->PN_ReturnValue); Super::AllocateDefaultPins(); } diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_IfThenElse.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_IfThenElse.cpp index cd7c0e7560ac..5dac4d4e20b0 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_IfThenElse.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_IfThenElse.cpp @@ -93,14 +93,14 @@ void UK2Node_IfThenElse::AllocateDefaultPins() { const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Execute); - UEdGraphPin* ConditionPin = CreatePin(EGPD_Input, K2Schema->PC_Boolean, TEXT(""), NULL, false, false, K2Schema->PN_Condition); - ConditionPin->DefaultValue = ConditionPin->AutogeneratedDefaultValue = TEXT("true"); + CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Execute); + UEdGraphPin* ConditionPin = CreatePin(EGPD_Input, K2Schema->PC_Boolean, FString(), nullptr, K2Schema->PN_Condition); + K2Schema->SetPinAutogeneratedDefaultValue(ConditionPin, TEXT("true")); - UEdGraphPin* TruePin = CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Then); + UEdGraphPin* TruePin = CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Then); TruePin->PinFriendlyName =LOCTEXT("true", "true"); - UEdGraphPin* FalsePin = CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Else); + UEdGraphPin* FalsePin = CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Else); FalsePin->PinFriendlyName = LOCTEXT("false", "false"); Super::AllocateDefaultPins(); diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_InputAction.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_InputAction.cpp index d5fc76fd0a8e..833d26c4efc2 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_InputAction.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_InputAction.cpp @@ -40,9 +40,9 @@ void UK2Node_InputAction::AllocateDefaultPins() { const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, TEXT("Pressed")); - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, TEXT("Released")); - CreatePin(EGPD_Output, K2Schema->PC_Struct, TEXT(""), FKey::StaticStruct(), false, false, TEXT("Key")); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, TEXT("Pressed")); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, TEXT("Released")); + CreatePin(EGPD_Output, K2Schema->PC_Struct, FString(), FKey::StaticStruct(), TEXT("Key")); Super::AllocateDefaultPins(); } diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_InputKey.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_InputKey.cpp index f7118767f24e..fbad09a5d621 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_InputKey.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_InputKey.cpp @@ -55,9 +55,9 @@ void UK2Node_InputKey::AllocateDefaultPins() { const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, TEXT("Pressed")); - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, TEXT("Released")); - CreatePin(EGPD_Output, K2Schema->PC_Struct, TEXT(""), FKey::StaticStruct(), false, false, TEXT("Key")); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, TEXT("Pressed")); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, TEXT("Released")); + CreatePin(EGPD_Output, K2Schema->PC_Struct, FString(), FKey::StaticStruct(), TEXT("Key")); Super::AllocateDefaultPins(); } diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_InputTouch.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_InputTouch.cpp index ca20863dad4d..2167310b22c0 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_InputTouch.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_InputTouch.cpp @@ -46,14 +46,14 @@ void UK2Node_InputTouch::AllocateDefaultPins() { const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, TEXT("Pressed")); - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, TEXT("Released")); - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, TEXT("Moved")); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, TEXT("Pressed")); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, TEXT("Released")); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, TEXT("Moved")); UScriptStruct* VectorStruct = TBaseStructure::Get(); - CreatePin(EGPD_Output, K2Schema->PC_Struct, TEXT(""), VectorStruct, false, false, TEXT("Location")); + CreatePin(EGPD_Output, K2Schema->PC_Struct, FString(), VectorStruct, TEXT("Location")); - CreatePin(EGPD_Output, K2Schema->PC_Byte, TEXT(""), GetTouchIndexEnum(), false, false, TEXT("FingerIndex")); + CreatePin(EGPD_Output, K2Schema->PC_Byte, FString(), GetTouchIndexEnum(), TEXT("FingerIndex")); Super::AllocateDefaultPins(); } diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Knot.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Knot.cpp index 563f7654ed43..4b9e0168508b 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Knot.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Knot.cpp @@ -24,10 +24,10 @@ void UK2Node_Knot::AllocateDefaultPins() const FString InputPinName(TEXT("InputPin")); const FString OutputPinName(TEXT("OutputPin")); - UEdGraphPin* MyInputPin = CreatePin(EGPD_Input, Schema->PC_Wildcard, FString(), nullptr, /*bIsArray=*/ false, /*bIsReference=*/ false, InputPinName); + UEdGraphPin* MyInputPin = CreatePin(EGPD_Input, Schema->PC_Wildcard, FString(), nullptr, InputPinName); MyInputPin->bDefaultValueIsIgnored = true; - UEdGraphPin* MyOutputPin = CreatePin(EGPD_Output, Schema->PC_Wildcard, FString(), nullptr, /*bIsArray=*/ false, /*bIsReference=*/ false, OutputPinName); + UEdGraphPin* MyOutputPin = CreatePin(EGPD_Output, Schema->PC_Wildcard, FString(), nullptr, OutputPinName); } FText UK2Node_Knot::GetTooltipText() const diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Literal.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Literal.cpp index 71b42d8dbc98..f356787afbeb 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Literal.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Literal.cpp @@ -77,7 +77,7 @@ void UK2Node_Literal::AllocateDefaultPins() { // The literal node only has one pin: an output of the desired value, on a wildcard pin type const UEdGraphSchema_K2* Schema = GetDefault(); - CreatePin(EGPD_Output, Schema->PC_Object, TEXT(""), NULL, false, false, *ValuePinName); + CreatePin(EGPD_Output, Schema->PC_Object, FString(), nullptr, *ValuePinName); // After allocating the pins, try to coerce pin type SetObjectRef( ObjectRef ); @@ -268,7 +268,7 @@ void UK2Node_Literal::SetObjectRef(UObject* NewValue) { ValuePin->Modify(); ValuePin->PinType.PinCategory = Schema->PC_Object; - ValuePin->PinType.PinSubCategory = TEXT(""); + ValuePin->PinType.PinSubCategory.Reset(); ValuePin->PinType.PinSubCategoryObject = ObjectRef->GetClass(); } } diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_LoadAsset.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_LoadAsset.cpp index 510a54bf7833..0dad982758b1 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_LoadAsset.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_LoadAsset.cpp @@ -10,6 +10,7 @@ #include "K2Node_AssignmentStatement.h" #include "K2Node_CustomEvent.h" #include "K2Node_TemporaryVariable.h" +#include "K2Node_ExecutionSequence.h" #include "KismetCompiler.h" #include "BlueprintNodeSpawner.h" #include "BlueprintActionDatabaseRegistrar.h" @@ -18,19 +19,41 @@ void UK2Node_LoadAsset::AllocateDefaultPins() { - const UEdGraphSchema_K2* K2Schema = Cast(GetSchema()); + CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Exec, FString(), nullptr, UEdGraphSchema_K2::PN_Execute); - if (K2Schema) + // The immediate continue pin + CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, FString(), nullptr, UEdGraphSchema_K2::PN_Then); + + // The delayed completed pin, this used to be called Then + CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, FString(), nullptr, UEdGraphSchema_K2::PN_Completed); + + CreatePin(EGPD_Input, GetInputCategory(), FString(), UObject::StaticClass(), GetInputPinName()); + CreatePin(EGPD_Output, GetOutputCategory(), FString(), UObject::StaticClass(), GetOutputPinName()); +} + +void UK2Node_LoadAsset::ReallocatePinsDuringReconstruction(TArray& OldPins) +{ + Super::ReallocatePinsDuringReconstruction(OldPins); + + UEdGraphPin* OldThenPin = nullptr; + UEdGraphPin* OldCompletedPin = nullptr; + + for (UEdGraphPin* CurrentPin : OldPins) { - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), nullptr, false, false, K2Schema->PN_Execute); - UEdGraphPin* OutputExecPin = CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), nullptr, false, false, K2Schema->PN_Then); - if (OutputExecPin) + if (CurrentPin->PinName == UEdGraphSchema_K2::PN_Then) { - OutputExecPin->PinFriendlyName = FText::FromString(K2Schema->PN_Completed); + OldThenPin = CurrentPin; } + else if (CurrentPin->PinName == UEdGraphSchema_K2::PN_Completed) + { + OldCompletedPin = CurrentPin; + } + } - CreatePin(EGPD_Input, GetInputCategory(), TEXT(""), UObject::StaticClass(), false, false, GetInputPinName()); - CreatePin(EGPD_Output, GetOutputCategory(), TEXT(""), UObject::StaticClass(), false, false, GetOutputPinName()); + if (OldThenPin && !OldCompletedPin) + { + // This is an old node from when Completed was called then, rename the node to Completed and allow normal rewire to take place + OldThenPin->PinName = UEdGraphSchema_K2::PN_Completed; } } @@ -41,64 +64,82 @@ void UK2Node_LoadAsset::ExpandNode(class FKismetCompilerContext& CompilerContext check(Schema); bool bIsErrorFree = true; - // Create LoadAsset function call - auto CallLoadAssetNode = CompilerContext.SpawnIntermediateNode(this, SourceGraph); - CallLoadAssetNode->FunctionReference.SetExternalMember(NativeFunctionName(), UKismetSystemLibrary::StaticClass()); - CallLoadAssetNode->AllocateDefaultPins(); + // Sequence node, defaults to two output pins + UK2Node_ExecutionSequence* SequenceNode = CompilerContext.SpawnIntermediateNode(this, SourceGraph); + SequenceNode->AllocateDefaultPins(); // connect to input exe { - auto InputExePin = GetExecPin(); - auto CallFunctionInputExePin = CallLoadAssetNode->GetExecPin(); - bIsErrorFree &= InputExePin && CallFunctionInputExePin && CompilerContext.MovePinLinksToIntermediate(*InputExePin, *CallFunctionInputExePin).CanSafeConnect(); + UEdGraphPin* InputExePin = GetExecPin(); + UEdGraphPin* SequenceInputExePin = SequenceNode->GetExecPin(); + bIsErrorFree &= InputExePin && SequenceInputExePin && CompilerContext.MovePinLinksToIntermediate(*InputExePin, *SequenceInputExePin).CanSafeConnect(); + } + + // Create LoadAsset function call + UK2Node_CallFunction* CallLoadAssetNode = CompilerContext.SpawnIntermediateNode(this, SourceGraph); + CallLoadAssetNode->FunctionReference.SetExternalMember(NativeFunctionName(), UKismetSystemLibrary::StaticClass()); + CallLoadAssetNode->AllocateDefaultPins(); + + // connect load to first sequence pin + { + UEdGraphPin* CallFunctionInputExePin = CallLoadAssetNode->GetExecPin(); + UEdGraphPin* SequenceFirstExePin = SequenceNode->GetThenPinGivenIndex(0); + bIsErrorFree &= SequenceFirstExePin && CallFunctionInputExePin && Schema->TryCreateConnection(CallFunctionInputExePin, SequenceFirstExePin); + } + + // connect then to second sequence pin + { + UEdGraphPin* OutputThenPin = FindPin(Schema->PN_Then); + UEdGraphPin* SequenceSecondExePin = SequenceNode->GetThenPinGivenIndex(1); + bIsErrorFree &= OutputThenPin && SequenceSecondExePin && CompilerContext.MovePinLinksToIntermediate(*OutputThenPin, *SequenceSecondExePin).CanSafeConnect(); } // Create Local Variable - UK2Node_TemporaryVariable* TempVarOutput = CompilerContext.SpawnInternalVariable(this, GetOutputCategory(), FString(), UObject::StaticClass(), false); + UK2Node_TemporaryVariable* TempVarOutput = CompilerContext.SpawnInternalVariable(this, GetOutputCategory(), FString(), UObject::StaticClass()); // Create assign node - auto AssignNode = CompilerContext.SpawnIntermediateNode(this, SourceGraph); + UK2Node_AssignmentStatement* AssignNode = CompilerContext.SpawnIntermediateNode(this, SourceGraph); AssignNode->AllocateDefaultPins(); - auto LoadedObjectVariablePin = TempVarOutput->GetVariablePin(); + UEdGraphPin* LoadedObjectVariablePin = TempVarOutput->GetVariablePin(); // connect local variable to assign node { - auto AssignLHSPPin = AssignNode->GetVariablePin(); + UEdGraphPin* AssignLHSPPin = AssignNode->GetVariablePin(); bIsErrorFree &= AssignLHSPPin && LoadedObjectVariablePin && Schema->TryCreateConnection(AssignLHSPPin, LoadedObjectVariablePin); } // connect local variable to output { - auto OutputObjectPinPin = FindPin(GetOutputPinName()); + UEdGraphPin* OutputObjectPinPin = FindPin(GetOutputPinName()); bIsErrorFree &= LoadedObjectVariablePin && OutputObjectPinPin && CompilerContext.MovePinLinksToIntermediate(*OutputObjectPinPin, *LoadedObjectVariablePin).CanSafeConnect(); } // connect assign exec input to function output { - auto CallFunctionOutputExePin = CallLoadAssetNode->FindPin(Schema->PN_Then); - auto AssignInputExePin = AssignNode->GetExecPin(); + UEdGraphPin* CallFunctionOutputExePin = CallLoadAssetNode->FindPin(Schema->PN_Then); + UEdGraphPin* AssignInputExePin = AssignNode->GetExecPin(); bIsErrorFree &= AssignInputExePin && CallFunctionOutputExePin && Schema->TryCreateConnection(AssignInputExePin, CallFunctionOutputExePin); } // connect assign exec output to output { - auto OutputExePin = FindPin(Schema->PN_Then); - auto AssignOutputExePin = AssignNode->GetThenPin(); - bIsErrorFree &= OutputExePin && AssignOutputExePin && CompilerContext.MovePinLinksToIntermediate(*OutputExePin, *AssignOutputExePin).CanSafeConnect(); + UEdGraphPin* OutputCompletedPin = FindPin(Schema->PN_Completed); + UEdGraphPin* AssignOutputExePin = AssignNode->GetThenPin(); + bIsErrorFree &= OutputCompletedPin && AssignOutputExePin && CompilerContext.MovePinLinksToIntermediate(*OutputCompletedPin, *AssignOutputExePin).CanSafeConnect(); } // connect to asset - auto CallFunctionAssetPin = CallLoadAssetNode->FindPin(GetInputPinName()); + UEdGraphPin* CallFunctionAssetPin = CallLoadAssetNode->FindPin(GetInputPinName()); { - auto AssetPin = FindPin(GetInputPinName()); + UEdGraphPin* AssetPin = FindPin(GetInputPinName()); ensure(CallFunctionAssetPin); bIsErrorFree &= AssetPin && CallFunctionAssetPin && CompilerContext.MovePinLinksToIntermediate(*AssetPin, *CallFunctionAssetPin).CanSafeConnect(); } // Create OnLoadEvent const FString DelegateOnLoadedParamName(TEXT("OnLoaded")); - auto OnLoadEventNode = CompilerContext.SpawnIntermediateEventNode(this, CallFunctionAssetPin, SourceGraph); + UK2Node_CustomEvent* OnLoadEventNode = CompilerContext.SpawnIntermediateEventNode(this, CallFunctionAssetPin, SourceGraph); OnLoadEventNode->CustomFunctionName = *FString::Printf(TEXT("OnLoaded_%s"), *CompilerContext.GetGuid(this)); OnLoadEventNode->AllocateDefaultPins(); { @@ -120,17 +161,17 @@ void UK2Node_LoadAsset::ExpandNode(class FKismetCompilerContext& CompilerContext // connect delegate { - auto CallFunctionDelegatePin = CallLoadAssetNode->FindPin(DelegateOnLoadedParamName); + UEdGraphPin* CallFunctionDelegatePin = CallLoadAssetNode->FindPin(DelegateOnLoadedParamName); ensure(CallFunctionDelegatePin); - auto EventDelegatePin = OnLoadEventNode->FindPin(UK2Node_CustomEvent::DelegateOutputName); + UEdGraphPin* EventDelegatePin = OnLoadEventNode->FindPin(UK2Node_CustomEvent::DelegateOutputName); bIsErrorFree &= CallFunctionDelegatePin && EventDelegatePin && Schema->TryCreateConnection(CallFunctionDelegatePin, EventDelegatePin); } // connect loaded object from event to assign { - auto LoadedAssetEventPin = OnLoadEventNode->FindPin(TEXT("Loaded")); + UEdGraphPin* LoadedAssetEventPin = OnLoadEventNode->FindPin(TEXT("Loaded")); ensure(LoadedAssetEventPin); - auto AssignRHSPPin = AssignNode->GetValuePin(); + UEdGraphPin* AssignRHSPPin = AssignNode->GetValuePin(); bIsErrorFree &= AssignRHSPPin && LoadedAssetEventPin && Schema->TryCreateConnection(LoadedAssetEventPin, AssignRHSPPin); } @@ -149,7 +190,7 @@ FText UK2Node_LoadAsset::GetTooltipText() const FText UK2Node_LoadAsset::GetNodeTitle(ENodeTitleType::Type TitleType) const { - return FText(LOCTEXT("UK2Node_LoadAssetGetNodeTitle", "Load Asset")); + return FText(LOCTEXT("UK2Node_LoadAssetGetNodeTitle", "Async Load Asset")); } bool UK2Node_LoadAsset::IsCompatibleWithGraph(const UEdGraph* TargetGraph) const @@ -196,14 +237,12 @@ FText UK2Node_LoadAsset::GetMenuCategory() const const FString& UK2Node_LoadAsset::GetInputCategory() const { - const UEdGraphSchema_K2* K2Schema = CastChecked(GetSchema()); - return K2Schema->PC_Asset; + return UEdGraphSchema_K2::PC_Asset; } const FString& UK2Node_LoadAsset::GetOutputCategory() const { - const UEdGraphSchema_K2* K2Schema = CastChecked(GetSchema()); - return K2Schema->PC_Object; + return UEdGraphSchema_K2::PC_Object; } const FString& UK2Node_LoadAsset::GetInputPinName() const @@ -238,19 +277,17 @@ FText UK2Node_LoadAssetClass::GetTooltipText() const FText UK2Node_LoadAssetClass::GetNodeTitle(ENodeTitleType::Type TitleType) const { - return FText(LOCTEXT("UK2Node_LoadAssetClassGetNodeTitle", "Load Class Asset")); + return FText(LOCTEXT("UK2Node_LoadAssetClassGetNodeTitle", "Async Load Class Asset")); } const FString& UK2Node_LoadAssetClass::GetInputCategory() const { - const UEdGraphSchema_K2* K2Schema = CastChecked(GetSchema()); - return K2Schema->PC_AssetClass; + return UEdGraphSchema_K2::PC_AssetClass; } const FString& UK2Node_LoadAssetClass::GetOutputCategory() const { - const UEdGraphSchema_K2* K2Schema = CastChecked(GetSchema()); - return K2Schema->PC_Class; + return UEdGraphSchema_K2::PC_Class; } const FString& UK2Node_LoadAssetClass::GetInputPinName() const diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_LocalVariable.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_LocalVariable.cpp index c4847be22da4..ec6a7d9d075b 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_LocalVariable.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_LocalVariable.cpp @@ -111,6 +111,7 @@ void UDEPRECATED_K2Node_LocalVariable::ReconstructNode() NewVar.VarName = *GetNodeTitle(ENodeTitleType::EditableTitle).ToString(); NewVar.VarGuid = FGuid::NewGuid(); NewVar.VarType = GetVariablePin()->PinType; + NewVar.PropertyFlags |= CPF_BlueprintVisible; NewVar.FriendlyName = FName::NameToDisplayString( NewVar.VarName.ToString(), (NewVar.VarType.PinCategory == K2Schema->PC_Boolean) ? true : false ); NewVar.Category = K2Schema->VR_DefaultCategory; @@ -142,9 +143,9 @@ void UDEPRECATED_K2Node_LocalVariable::ReconstructNode() SetNode->PostPlacedNewNode(); // Locally re-construct the pins, can't allow the node to do it because the property does not yet exist - UEdGraphPin* ExecPin = SetNode->CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Execute); - UEdGraphPin* ThenPin = SetNode->CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Then); - UEdGraphPin* ValuePin = SetNode->CreatePin(EGPD_Input, TEXT(""), TEXT(""), NULL, false, false, NewVar.VarName.ToString()); + UEdGraphPin* ExecPin = SetNode->CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Execute); + UEdGraphPin* ThenPin = SetNode->CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Then); + UEdGraphPin* ValuePin = SetNode->CreatePin(EGPD_Input, FString(), FString(), nullptr, NewVar.VarName.ToString()); ValuePin->PinType = NewVar.VarType; // Move the pin links over to the new node @@ -173,9 +174,9 @@ void UDEPRECATED_K2Node_LocalVariable::ReconstructNode() GetNode->PostPlacedNewNode(); // Locally re-construct the pins, can't allow the node to do it because the property does not yet exist - UEdGraphPin* VariablePin = GetNode->CreatePin(EGPD_Output, TEXT(""), TEXT(""), NULL, false, false, NewVar.VarName.ToString()); + UEdGraphPin* VariablePin = GetNode->CreatePin(EGPD_Output, FString(), FString(), nullptr, NewVar.VarName.ToString()); VariablePin->PinType = NewVar.VarType; - K2Schema->SetPinDefaultValueBasedOnType(VariablePin); + K2Schema->SetPinAutogeneratedDefaultValueBasedOnType(VariablePin); // Position the new node GetNode->NodePosX = NodePosX; diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MCDelegate.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MCDelegate.cpp index 46a3f80c4356..42258cf6c600 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MCDelegate.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MCDelegate.cpp @@ -77,8 +77,8 @@ void UK2Node_BaseMCDelegate::AllocateDefaultPins() const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Execute); - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Then); + CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Execute); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Then); UClass* PropertyOwnerClass = DelegateReference.GetMemberParentClass(GetBlueprintClassFromNode()); if (PropertyOwnerClass != nullptr) @@ -92,11 +92,11 @@ void UK2Node_BaseMCDelegate::AllocateDefaultPins() UEdGraphPin* SelfPin = NULL; if (bUseSelf) { - SelfPin = CreatePin(EGPD_Input, K2Schema->PC_Object, K2Schema->PSC_Self, NULL, false, false, K2Schema->PN_Self); + SelfPin = CreatePin(EGPD_Input, K2Schema->PC_Object, K2Schema->PSC_Self, nullptr, K2Schema->PN_Self); } else { - SelfPin = CreatePin(EGPD_Input, K2Schema->PC_Object, TEXT(""), PropertyOwnerClass, false, false, K2Schema->PN_Self); + SelfPin = CreatePin(EGPD_Input, K2Schema->PC_Object, FString(), PropertyOwnerClass, K2Schema->PN_Self); } if(SelfPin) @@ -136,13 +136,13 @@ UEdGraphPin* UK2Node_BaseMCDelegate::GetDelegatePin() const FString UK2Node_BaseMCDelegate::GetDocumentationLink() const { - UClass* ParentClass = NULL; + UClass* ParentClass = nullptr; if (DelegateReference.IsSelfContext()) { if (HasValidBlueprint()) { UField* Delegate = FindField(GetBlueprint()->GeneratedClass, DelegateReference.GetMemberName()); - if (Delegate != NULL) + if (Delegate) { ParentClass = Delegate->GetOwnerClass(); } @@ -153,12 +153,12 @@ FString UK2Node_BaseMCDelegate::GetDocumentationLink() const ParentClass = DelegateReference.GetMemberParentClass(GetBlueprintClassFromNode()); } - if ( ParentClass != NULL ) + if (ParentClass) { return FString( TEXT("Shared/") ) + ParentClass->GetName(); } - return TEXT(""); + return FString(); } FString UK2Node_BaseMCDelegate::GetDocumentationExcerptName() const @@ -181,7 +181,7 @@ void UK2Node_BaseMCDelegate::ExpandNode(class FKismetCompilerContext& CompilerCo const bool bProperInputToExpandForEach = (MultiSelf->LinkedTo.Num()) && (NULL != MultiSelf->LinkedTo[0]) && - (MultiSelf->LinkedTo[0]->PinType.bIsArray); + (MultiSelf->LinkedTo[0]->PinType.IsArray()); if(bProperInputToExpandForEach) { if(MultiSelf->LinkedTo.Num() > 1) @@ -296,7 +296,7 @@ void UK2Node_AddDelegate::AllocateDefaultPins() const UEdGraphSchema_K2* K2Schema = GetDefault(); - if(UEdGraphPin* DelegatePin = CreatePin(EGPD_Input, K2Schema->PC_Delegate, TEXT(""), NULL, false, true, FK2Node_BaseMCDelegateHelper::DelegatePinName, true)) + if(UEdGraphPin* DelegatePin = CreatePin(EGPD_Input, K2Schema->PC_Delegate, FString(), nullptr, FK2Node_BaseMCDelegateHelper::DelegatePinName, EPinContainerType::None, true, true)) { FMemberReference::FillSimpleMemberReference(GetDelegateSignature(), DelegatePin->PinType.PinSubCategoryMemberReference); DelegatePin->PinFriendlyName = NSLOCTEXT("K2Node", "PinFriendlyDelegatetName", "Event"); @@ -364,7 +364,7 @@ void UK2Node_RemoveDelegate::AllocateDefaultPins() const UEdGraphSchema_K2* K2Schema = GetDefault(); - if(UEdGraphPin* DelegatePin = CreatePin(EGPD_Input, K2Schema->PC_Delegate, TEXT(""), NULL, false, true, FK2Node_BaseMCDelegateHelper::DelegatePinName, true)) + if(UEdGraphPin* DelegatePin = CreatePin(EGPD_Input, K2Schema->PC_Delegate, FString(), nullptr, FK2Node_BaseMCDelegateHelper::DelegatePinName, EPinContainerType::None, true, true)) { FMemberReference::FillSimpleMemberReference(GetDelegateSignature(), DelegatePin->PinType.PinSubCategoryMemberReference); DelegatePin->PinFriendlyName = NSLOCTEXT("K2Node", "PinFriendlyDelegatetName", "Event"); @@ -407,7 +407,7 @@ bool UK2Node_CallDelegate::CreatePinsForFunctionInputs(const UFunction* Function const bool bIsFunctionInput = !Param->HasAnyPropertyFlags(CPF_OutParm) || Param->HasAnyPropertyFlags(CPF_ReferenceParm); if (bIsFunctionInput) { - UEdGraphPin* Pin = CreatePin(EGPD_Input, TEXT(""), TEXT(""), NULL, false, false, Param->GetName()); + UEdGraphPin* Pin = CreatePin(EGPD_Input, FString(), FString(), nullptr, Param->GetName()); const bool bPinGood = K2Schema->ConvertPropertyToPinType(Param, /*out*/ Pin->PinType); bAllPinsGood = bAllPinsGood && bPinGood; diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MacroInstance.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MacroInstance.cpp index a616f409efaa..cf78e716d4e7 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MacroInstance.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MacroInstance.cpp @@ -79,6 +79,7 @@ void UK2Node_MacroInstance::AllocateDefaultPins() { UK2Node::AllocateDefaultPins(); + const UEdGraphSchema_K2* Schema = GetDefault(); PreloadObject(MacroGraphReference.GetBlueprint()); UEdGraph* MacroGraph = MacroGraphReference.GetGraph(); @@ -108,7 +109,7 @@ void UK2Node_MacroInstance::AllocateDefaultPins() if (PortPin->ParentPin == NULL) { UEdGraphPin* NewLocalPin = CreatePin(UEdGraphPin::GetComplementaryDirection(PortPin->Direction), PortPin->PinType, PortPin->PinName); - NewLocalPin->DefaultValue = NewLocalPin->AutogeneratedDefaultValue = PortPin->DefaultValue; + Schema->SetPinAutogeneratedDefaultValue(NewLocalPin, PortPin->GetDefaultAsString()); } } } diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MakeArray.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MakeArray.cpp index f269af43053c..da94f3933412 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MakeArray.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MakeArray.cpp @@ -59,9 +59,8 @@ public: CreateArrayStatement.Type = KCST_CreateArray; CreateArrayStatement.LHS = *ArrayTerm; - for(auto PinIt = Node->Pins.CreateIterator(); PinIt; ++PinIt) + for (UEdGraphPin* Pin : Node->Pins) { - UEdGraphPin* Pin = *PinIt; if(Pin && Pin->Direction == EGPD_Input) { FBPTerminal** InputTerm = Context.NetMap.Find(FEdGraphUtilities::GetNetFromPin(Pin)); @@ -128,12 +127,12 @@ void UK2Node_MakeArray::ReallocatePinsDuringReconstruction(TArray& void UK2Node_MakeArray::AllocateDefaultPins() { // Create the output pin - CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Wildcard, TEXT(""), NULL, true, false, *OutputPinName); + CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Wildcard, FString(), nullptr, *OutputPinName, EPinContainerType::Array); // Create the input pins to create the arrays from for (int32 i = 0; i < NumInputs; ++i) { - CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Wildcard, TEXT(""), NULL, false, false, *FString::Printf(TEXT("[%d]"), i)); + CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Wildcard, FString(), nullptr, *FString::Printf(TEXT("[%d]"), i)); } } @@ -161,8 +160,8 @@ void UK2Node_MakeArray::ClearPinTypeToWildcard() { UEdGraphPin* OutputPin = GetOutputPin(); OutputPin->PinType.PinCategory = UEdGraphSchema_K2::PC_Wildcard; - OutputPin->PinType.PinSubCategory = TEXT(""); - OutputPin->PinType.PinSubCategoryObject = NULL; + OutputPin->PinType.PinSubCategory.Reset(); + OutputPin->PinType.PinSubCategoryObject = nullptr; PropagatePinType(); } @@ -194,8 +193,9 @@ void UK2Node_MakeArray::NotifyPinConnectionListChanged(UEdGraphPin* Pin) { // Update the types on all the pins OutputPin->PinType = Pin->LinkedTo[0]->PinType; - OutputPin->PinType.bIsArray = true; + OutputPin->PinType.ContainerType = EPinContainerType::Array; PropagatePinType(); + GetGraph()->NotifyGraphChanged(); } } else @@ -208,7 +208,7 @@ void UK2Node_MakeArray::NotifyPinConnectionListChanged(UEdGraphPin* Pin) for (int32 PinIndex = 0; PinIndex < InputPins.Num(); ++PinIndex) { UEdGraphPin*& CurrentPin = InputPins[PinIndex]; - if (CurrentPin->GetDefaultAsString() != CurrentPin->AutogeneratedDefaultValue) + if (!CurrentPin->DoesDefaultValueMatchAutogenerated()) { bResetOutputPin = false; } @@ -217,10 +217,11 @@ void UK2Node_MakeArray::NotifyPinConnectionListChanged(UEdGraphPin* Pin) if( bResetOutputPin == true ) { OutputPin->PinType.PinCategory = UEdGraphSchema_K2::PC_Wildcard; - OutputPin->PinType.PinSubCategory = TEXT(""); - OutputPin->PinType.PinSubCategoryObject = NULL; + OutputPin->PinType.PinSubCategory.Reset(); + OutputPin->PinType.PinSubCategoryObject = nullptr; PropagatePinType(); + GetGraph()->NotifyGraphChanged(); } } } @@ -275,14 +276,10 @@ void UK2Node_MakeArray::PropagatePinType() CurrentPin->PinType.PinSubCategoryObject = OutputPin->PinType.PinSubCategoryObject; } - if (CurrentPin->PinType.PinCategory == UEdGraphSchema_K2::PC_Wildcard) + if (CurrentPin->PinType.PinCategory == UEdGraphSchema_K2::PC_Wildcard || CurrentPin->GetDefaultAsString().IsEmpty() == true) { - CurrentPin->ResetDefaultValue(); - } - else if (CurrentPin->GetDefaultAsString().IsEmpty() == true) - { - // Only reset default value if there isn't one set. Otherwise this deletes data! - Schema->SetPinDefaultValueBasedOnType(CurrentPin); + // Only reset default value if there isn't one set or it is a wildcard. Otherwise this deletes data! + Schema->SetPinAutogeneratedDefaultValueBasedOnType(CurrentPin); } // Verify that all previous connections to this pin are still valid with the new type @@ -341,12 +338,12 @@ void UK2Node_MakeArray::PostReconstructNode() { OutputPin->PinType = Pins[PinIndex]->LinkedTo[0]->PinType; } - OutputPin->PinType.bIsArray = true; + OutputPin->PinType.ContainerType = EPinContainerType::Array; PropagatePinType(); bResetToWildcard = false; break; } - else if(Pins[PinIndex]->GetDefaultAsString() != Pins[PinIndex]->AutogeneratedDefaultValue) + else if(!Pins[PinIndex]->DoesDefaultValueMatchAutogenerated()) { // The pin has user data in it, continue to use its type as the type for all pins. @@ -361,7 +358,7 @@ void UK2Node_MakeArray::PostReconstructNode() { OutputPin->PinType = Pins[PinIndex]->PinType; } - OutputPin->PinType.bIsArray = true; + OutputPin->PinType.ContainerType = EPinContainerType::Array; PropagatePinType(); bResetToWildcard = false; break; @@ -394,8 +391,8 @@ void UK2Node_MakeArray::AddInputPin() ++NumInputs; FEdGraphPinType OutputPinType = GetOutputPin()->PinType; - UEdGraphPin* Pin = CreatePin(EGPD_Input, OutputPinType.PinCategory, OutputPinType.PinSubCategory, OutputPinType.PinSubCategoryObject.Get(), false, false, *FString::Printf(TEXT("[%d]"), (NumInputs-1))); - GetDefault()->SetPinDefaultValueBasedOnType(Pin); + UEdGraphPin* Pin = CreatePin(EGPD_Input, OutputPinType.PinCategory, OutputPinType.PinSubCategory, OutputPinType.PinSubCategoryObject.Get(), *FString::Printf(TEXT("[%d]"), (NumInputs-1))); + GetDefault()->SetPinAutogeneratedDefaultValueBasedOnType(Pin); const bool bIsCompiling = GetBlueprint()->bBeingCompiled; if( !bIsCompiling ) @@ -527,13 +524,13 @@ void UK2Node_MakeArray::GetContextMenuActions(const FGraphNodeContextMenuBuilder bool UK2Node_MakeArray::IsConnectionDisallowed(const UEdGraphPin* MyPin, const UEdGraphPin* OtherPin, FString& OutReason) const { // if MyPin has a ParentPin then we are dealing with a split pin and we should evaluate it with default behavior - if(MyPin->ParentPin == nullptr && OtherPin->PinType.IsContainer() == true && MyPin->Direction == EGPD_Input) + if(MyPin->ParentPin == nullptr && OtherPin->PinType.IsContainer() == true && MyPin->Direction == EGPD_Input) //-V595 { OutReason = NSLOCTEXT("K2Node", "MakeArray_InputIsContainer", "Cannot make an array with an input of a container!").ToString(); return true; } - auto Schema = Cast(GetSchema()); + const UEdGraphSchema_K2* Schema = Cast(GetSchema()); if (!ensure(Schema) || (ensure(OtherPin) && Schema->IsExecPin(*OtherPin))) { OutReason = NSLOCTEXT("K2Node", "MakeArray_InputIsExec", "Cannot make an array with an execution input!").ToString(); @@ -545,8 +542,10 @@ bool UK2Node_MakeArray::IsConnectionDisallowed(const UEdGraphPin* MyPin, const U void UK2Node_MakeArray::ValidateNodeDuringCompilation(class FCompilerResultsLog& MessageLog) const { - auto Schema = Cast(GetSchema()); - auto OutputPin = GetOutputPin(); + Super::ValidateNodeDuringCompilation(MessageLog); + + const UEdGraphSchema_K2* Schema = Cast(GetSchema()); + UEdGraphPin* OutputPin = GetOutputPin(); if (!ensure(Schema) || !ensure(OutputPin) || Schema->IsExecPin(*OutputPin)) { MessageLog.Error(*NSLOCTEXT("K2Node", "MakeArray_OutputIsExec", "Uaccepted array type in @@").ToString(), this); diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MakeStruct.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MakeStruct.cpp index 9cefa0ff5bfa..113fd39d5fe1 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MakeStruct.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MakeStruct.cpp @@ -39,36 +39,6 @@ void UK2Node_MakeStruct::FMakeStructPinManager::GetRecordDefaults(UProperty* Tes void UK2Node_MakeStruct::FMakeStructPinManager::CustomizePinData(UEdGraphPin* Pin, FName SourcePropertyName, int32 ArrayIndex, UProperty* Property) const { - struct FPinDefaultValueHelper - { - static void Set(UEdGraphPin& InPin, const FString& Value, bool bIsText, bool bIsObject) - { - InPin.AutogeneratedDefaultValue = Value; - if (bIsText) - { - FString PackageNamespace; -#if USE_STABLE_LOCALIZATION_KEYS - if (GIsEditor) - { - PackageNamespace = TextNamespaceUtil::EnsurePackageNamespace(InPin.GetOwningNodeUnchecked()); - } -#endif // USE_STABLE_LOCALIZATION_KEYS - if (!FTextStringHelper::ReadFromString(*Value, InPin.DefaultTextValue, nullptr, *PackageNamespace)) - { - InPin.DefaultTextValue = FText::FromString(Value); - } - } - else if (bIsObject) - { - InPin.DefaultObject = StaticFindObject(UObject::StaticClass(), nullptr, *Value); - } - else - { - InPin.DefaultValue = Value; - } - } - }; - UK2Node_StructOperation::FStructOperationOptionalPinManager::CustomizePinData(Pin, SourcePropertyName, ArrayIndex, Property); if (Pin && Property) { @@ -77,11 +47,11 @@ void UK2Node_MakeStruct::FMakeStructPinManager::CustomizePinData(UEdGraphPin* Pi // Should pin default value be filled as FText? const bool bIsText = Property->IsA(); - checkSlow(bIsText == ((Schema->PC_Text == Pin->PinType.PinCategory) && !Pin->PinType.bIsArray)); + checkSlow(bIsText == ((Schema->PC_Text == Pin->PinType.PinCategory) && !Pin->PinType.IsContainer())); const bool bIsObject = Property->IsA(); checkSlow(bIsObject == ((Schema->PC_Object == Pin->PinType.PinCategory || Schema->PC_Class == Pin->PinType.PinCategory || - Schema->PC_Asset == Pin->PinType.PinCategory || Schema->PC_AssetClass == Pin->PinType.PinCategory) && !Pin->PinType.bIsArray)); + Schema->PC_Asset == Pin->PinType.PinCategory || Schema->PC_AssetClass == Pin->PinType.PinCategory) && !Pin->PinType.IsContainer())); if (Property->HasAnyPropertyFlags(CPF_AdvancedDisplay)) { @@ -92,24 +62,24 @@ void UK2Node_MakeStruct::FMakeStructPinManager::CustomizePinData(UEdGraphPin* Pi const FString& MetadataDefaultValue = Property->GetMetaData(TEXT("MakeStructureDefaultValue")); if (!MetadataDefaultValue.IsEmpty()) { - FPinDefaultValueHelper::Set(*Pin, MetadataDefaultValue, bIsText, bIsObject); + Schema->SetPinAutogeneratedDefaultValue(Pin, MetadataDefaultValue); return; } - if (NULL != SampleStructMemory) + if (nullptr != SampleStructMemory) { FString NewDefaultValue; - if (Property->ExportText_InContainer(0, NewDefaultValue, SampleStructMemory, SampleStructMemory, NULL, PPF_None)) + if (Property->ExportText_InContainer(0, NewDefaultValue, SampleStructMemory, SampleStructMemory, nullptr, PPF_None)) { - if (Schema->IsPinDefaultValid(Pin, NewDefaultValue, NULL, FText::GetEmpty()).IsEmpty()) + if (Schema->IsPinDefaultValid(Pin, NewDefaultValue, nullptr, FText::GetEmpty()).IsEmpty()) { - FPinDefaultValueHelper::Set(*Pin, NewDefaultValue, bIsText, bIsObject); + Schema->SetPinAutogeneratedDefaultValue(Pin, NewDefaultValue); return; } } } - Schema->SetPinDefaultValueBasedOnType(Pin); + Schema->SetPinAutogeneratedDefaultValueBasedOnType(Pin); } } @@ -151,7 +121,7 @@ void UK2Node_MakeStruct::AllocateDefaultPins() if(Schema && StructType) { PreloadObject(StructType); - CreatePin(EGPD_Output, Schema->PC_Struct, TEXT(""), StructType, false, false, StructType->GetName()); + CreatePin(EGPD_Output, Schema->PC_Struct, FString(), StructType, StructType->GetName()); bool bHasAdvancedPins = false; { diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MakeVariable.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MakeVariable.cpp index 0e6ffe1b49ff..0867c78f4f90 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MakeVariable.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MakeVariable.cpp @@ -52,15 +52,15 @@ public: // This node only supports containers at the moment, it could be extended to support any type: const FBPVariableDescription& VariableType = MakeVariableNode->GetVariableType(); - if(VariableType.VarType.bIsArray) + if(VariableType.VarType.IsArray()) { CreateVariableStatement.Type = KCST_CreateArray; } - else if(VariableType.VarType.bIsSet) + else if(VariableType.VarType.IsSet()) { CreateVariableStatement.Type = KCST_CreateSet; } - else if( VariableType.VarType.bIsMap) + else if( VariableType.VarType.IsMap()) { CreateVariableStatement.Type = KCST_CreateMap; } @@ -102,7 +102,7 @@ void UK2Node_MakeVariable::SetupVariable(const FBPVariableDescription& InVariabl TSharedPtr StructData = MakeShareable(new FStructOnScope(Scope)); FBlueprintEditorUtils::PropertyValueFromString(Property, VariableType.DefaultValue, StructData->GetStructMemory()); - if(VariableType.VarType.bIsArray) + if(VariableType.VarType.IsArray()) { const UArrayProperty* ArrayProperty = CastChecked(Property); FScriptArrayHelper ArrayHelper(ArrayProperty, ArrayProperty->ContainerPtrToValuePtr(StructData->GetStructMemory())); @@ -118,10 +118,10 @@ void UK2Node_MakeVariable::SetupVariable(const FBPVariableDescription& InVariabl UEdGraphPin* VariableInputPin = CreatePin(EGPD_Input, ContainedType, *FString::FromInt(ArrayIndex)); // Add one to the index for the pin to set the default on to skip the output pin - Schema->TrySetDefaultValue(*VariableInputPin , DefaultValue); + Schema->SetPinAutogeneratedDefaultValue(VariableInputPin, DefaultValue); } } - else if( VariableType.VarType.bIsSet) + else if( VariableType.VarType.IsSet()) { const USetProperty* SetProperty = CastChecked(Property); FScriptSetHelper SetHelper(SetProperty, SetProperty->ContainerPtrToValuePtr(StructData->GetStructMemory())); @@ -140,11 +140,11 @@ void UK2Node_MakeVariable::SetupVariable(const FBPVariableDescription& InVariabl FBlueprintEditorUtils::PropertyValueToString_Direct(SetProperty->ElementProp, PropData, DefaultValue); UEdGraphPin* VariableInputPin = CreatePin(EGPD_Input, ContainedType, *FString::FromInt(I)); // Add one to the index for the pin to set the default on to skip the output pin - Schema->TrySetDefaultValue(*VariableInputPin , DefaultValue); + Schema->SetPinAutogeneratedDefaultValue(VariableInputPin, DefaultValue); } } } - else if( VariableType.VarType.bIsMap) + else if( VariableType.VarType.IsMap()) { const UMapProperty* MapProperty = CastChecked(Property); FScriptMapHelper MapHelper(MapProperty, MapProperty->ContainerPtrToValuePtr(StructData->GetStructMemory())); @@ -165,7 +165,7 @@ void UK2Node_MakeVariable::SetupVariable(const FBPVariableDescription& InVariabl FBlueprintEditorUtils::PropertyValueToString_Direct(MapProperty->KeyProp, KeyData, KeyDefaultValue); UEdGraphPin* VariableInputPin = CreatePin(EGPD_Input, ContainedType, *FString::FromInt(I).Append(TEXT("_Key"))); // Add one to the index for the pin to set the default on to skip the output pin - Schema->TrySetDefaultValue(*VariableInputPin , KeyDefaultValue); + Schema->SetPinAutogeneratedDefaultValue(VariableInputPin, KeyDefaultValue); const uint8* ValueData = MapHelper.GetValuePtr(I); @@ -173,7 +173,7 @@ void UK2Node_MakeVariable::SetupVariable(const FBPVariableDescription& InVariabl FBlueprintEditorUtils::PropertyValueToString_Direct(MapProperty->ValueProp, ValueData, ValueDefaultValue); VariableInputPin = CreatePin(EGPD_Input, ValueType, *FString::FromInt(I).Append(TEXT("_Value"))); // Add one to the index for the pin to set the default on to skip the output pin - Schema->TrySetDefaultValue(*VariableInputPin , ValueDefaultValue); + Schema->SetPinAutogeneratedDefaultValue(VariableInputPin, ValueDefaultValue); } } } diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MathExpression.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MathExpression.cpp index b8b3cf8dce64..15c138f51aa5 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MathExpression.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MathExpression.cpp @@ -129,6 +129,8 @@ static void SetNodeError(UEdGraphNode* Node, FText const& ErrorText) class FExpressionVisitor { public: + virtual ~FExpressionVisitor() { } + /** * FExpressionNodes determine when a traverser (FExpressionVisitor) has access * to the node. There are a couple hook points, allowing the traverser to pick @@ -1061,6 +1063,10 @@ public: { } + virtual ~FCodeGenFragment() + { + } + /** * Takes the input to some other fragment, and plugs the result of this one * into it. @@ -1262,7 +1268,7 @@ private: * for the specified UK2Node_MathExpression (which is a tunnel node, similar to * how collapsed composite nodes work). */ -class FMathGraphGenerator : public FExpressionVisitor +class FMathGraphGenerator final : public FExpressionVisitor { public: FMathGraphGenerator(UK2Node_MathExpression* InNode) @@ -2690,6 +2696,8 @@ void UK2Node_MathExpression::ClearExpression() //------------------------------------------------------------------------------ void UK2Node_MathExpression::ValidateNodeDuringCompilation(FCompilerResultsLog& MessageLog) const { + Super::ValidateNodeDuringCompilation(MessageLog); + if (CachedMessageLog.IsValid()) { MessageLog.Append(*CachedMessageLog); diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MatineeController.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MatineeController.cpp index 794e5f1e9325..17a5a7a8e09a 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MatineeController.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MatineeController.cpp @@ -39,17 +39,17 @@ void UK2Node_MatineeController::AllocateDefaultPins() const UEdGraphSchema_K2* K2Schema = GetDefault(); // Preload the matinee data, if needed, so that we can have all the event tracks we need - if (MatineeActor != NULL) + if (MatineeActor) { PreloadObject(MatineeActor); PreloadObject(MatineeActor->MatineeData); } // Create the "finished" playing pin - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_MatineeFinished); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_MatineeFinished); // Create pins for each event - if(MatineeActor != NULL && MatineeActor->MatineeData != NULL) + if (MatineeActor && MatineeActor->MatineeData) { TArray EventNames; MatineeActor->MatineeData->GetAllEventNames(EventNames); @@ -57,7 +57,7 @@ void UK2Node_MatineeController::AllocateDefaultPins() for(int32 i=0; iPC_Exec, TEXT(""), NULL, false, false, EventName.ToString()); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, EventName.ToString()); } } @@ -213,7 +213,7 @@ void UK2Node_MatineeController::OnEventKeyframeAdded(const AMatineeActor* InMati const UEdGraphSchema_K2* K2Schema = GetDefault(); // Add one to the index as we insert "finished" at index 0 - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, InPinName.ToString(), false, InIndex + 1); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, InPinName.ToString(), EPinContainerType::None, false, false, InIndex + 1); // Update and refresh the blueprint FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(GetBlueprint()); diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Message.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Message.cpp index b7b99d77f428..84780a02a6f3 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Message.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Message.cpp @@ -62,9 +62,9 @@ void UK2Node_Message::AllocateDefaultPins() if (MessageNodeFunction && MessageNodeFunction->HasAnyFunctionFlags(FUNC_BlueprintPure)) { // Input - Execution Pin - CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Exec, TEXT(""), NULL, false, false, UEdGraphSchema_K2::PN_Execute); + CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Exec, FString(), nullptr, UEdGraphSchema_K2::PN_Execute); // Output - Execution Pin - CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, TEXT(""), NULL, false, false, UEdGraphSchema_K2::PN_Then); + CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, FString(), nullptr, UEdGraphSchema_K2::PN_Then); } Super::AllocateDefaultPins(); @@ -73,7 +73,7 @@ void UK2Node_Message::AllocateDefaultPins() UEdGraphPin* UK2Node_Message::CreateSelfPin(const UFunction* Function) { const UEdGraphSchema_K2* K2Schema = GetDefault(); - UEdGraphPin* SelfPin = CreatePin(EGPD_Input, K2Schema->PC_Object, TEXT(""), UObject::StaticClass(), false, false, K2Schema->PN_Self); + UEdGraphPin* SelfPin = CreatePin(EGPD_Input, K2Schema->PC_Object, FString(), UObject::StaticClass(), K2Schema->PN_Self); SelfPin->bDefaultValueIsIgnored = true; return SelfPin; } @@ -188,7 +188,7 @@ void UK2Node_Message::ExpandNode(class FKismetCompilerContext& CompilerContext, // First, create an internal cast-to-interface node UK2Node_DynamicCast* CastToInterfaceNode = CompilerContext.SpawnIntermediateNode(this, SourceGraph); - CastToInterfaceNode->TargetType = MessageNodeFunction->GetOuterUClass(); + CastToInterfaceNode->TargetType = MessageNodeFunction->GetOuterUClass()->GetAuthoritativeClass(); CastToInterfaceNode->SetPurity(false); CastToInterfaceNode->AllocateDefaultPins(); @@ -308,9 +308,9 @@ void UK2Node_Message::ExpandNode(class FKismetCompilerContext& CompilerContext, LastOutCastSuccessPin = AssignTempVar->GetThenPin(); } - UK2Node* DefaultValueNode = NULL; - UEdGraphPin* DefaultValueThenPin = NULL; - if (CurrentPin->PinType.bIsArray) + UK2Node* DefaultValueNode = nullptr; + UEdGraphPin* DefaultValueThenPin = nullptr; + if (CurrentPin->PinType.IsArray()) { UK2Node_CallArrayFunction* ClearArray = CompilerContext.SpawnIntermediateNode(this, SourceGraph); DefaultValueNode = ClearArray; @@ -332,7 +332,7 @@ void UK2Node_Message::ExpandNode(class FKismetCompilerContext& CompilerContext, Schema->TryCreateConnection(AssignDefaultValue->GetVariablePin(), VarOutPin); AssignDefaultValue->PinConnectionListChanged(AssignDefaultValue->GetVariablePin()); - Schema->SetPinDefaultValueBasedOnType(AssignDefaultValue->GetValuePin()); + Schema->SetPinAutogeneratedDefaultValueBasedOnType(AssignDefaultValue->GetValuePin()); DefaultValueThenPin = AssignDefaultValue->GetThenPin(); } diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MultiGate.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MultiGate.cpp index 0c98a1c6f2f2..c0502e585056 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MultiGate.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_MultiGate.cpp @@ -498,12 +498,11 @@ void UK2Node_MultiGate::AllocateDefaultPins() Super::AllocateDefaultPins(); const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, TEXT("Reset")); - CreatePin(EGPD_Input, K2Schema->PC_Boolean, TEXT(""), NULL, false, false, TEXT("IsRandom")); - CreatePin(EGPD_Input, K2Schema->PC_Boolean, TEXT(""), NULL, false, false, TEXT("Loop")); - UEdGraphPin* IndexPin = CreatePin(EGPD_Input, K2Schema->PC_Int, TEXT(""), NULL, false, false, TEXT("StartIndex")); - IndexPin->DefaultValue = TEXT("-1"); - IndexPin->AutogeneratedDefaultValue = TEXT("-1"); + CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, TEXT("Reset")); + CreatePin(EGPD_Input, K2Schema->PC_Boolean, FString(), nullptr, TEXT("IsRandom")); + CreatePin(EGPD_Input, K2Schema->PC_Boolean, FString(), nullptr, TEXT("Loop")); + UEdGraphPin* IndexPin = CreatePin(EGPD_Input, K2Schema->PC_Int, FString(), nullptr, TEXT("StartIndex")); + K2Schema->SetPinAutogeneratedDefaultValue(IndexPin, TEXT("-1")); } void UK2Node_MultiGate::ReallocatePinsDuringReconstruction(TArray& OldPins) @@ -511,12 +510,11 @@ void UK2Node_MultiGate::ReallocatePinsDuringReconstruction(TArray& Super::ReallocatePinsDuringReconstruction(OldPins); const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, TEXT("Reset")); - CreatePin(EGPD_Input, K2Schema->PC_Boolean, TEXT(""), NULL, false, false, TEXT("IsRandom")); - CreatePin(EGPD_Input, K2Schema->PC_Boolean, TEXT(""), NULL, false, false, TEXT("Loop")); - UEdGraphPin* IndexPin = CreatePin(EGPD_Input, K2Schema->PC_Int, TEXT(""), NULL, false, false, TEXT("StartIndex")); - IndexPin->DefaultValue = TEXT("-1"); - IndexPin->AutogeneratedDefaultValue = TEXT("-1"); + CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, TEXT("Reset")); + CreatePin(EGPD_Input, K2Schema->PC_Boolean, FString(), nullptr, TEXT("IsRandom")); + CreatePin(EGPD_Input, K2Schema->PC_Boolean, FString(), nullptr, TEXT("Loop")); + UEdGraphPin* IndexPin = CreatePin(EGPD_Input, K2Schema->PC_Int, FString(), nullptr, TEXT("StartIndex")); + K2Schema->SetPinAutogeneratedDefaultValue(IndexPin, TEXT("-1")); } UEdGraphPin* UK2Node_MultiGate::GetResetPin() const @@ -643,7 +641,7 @@ void UK2Node_MultiGate::ExpandNode(class FKismetCompilerContext& CompilerContext ///////////////////////////// // Create the node - UK2Node_TemporaryVariable* TempVarNode = SourceGraph->CreateBlankNode(); + UK2Node_TemporaryVariable* TempVarNode = SourceGraph->CreateIntermediateNode(); TempVarNode->VariableType.PinCategory = Schema->PC_Int; TempVarNode->AllocateDefaultPins(); CompilerContext.MessageLog.NotifyIntermediateObjectCreation(TempVarNode, this); @@ -655,7 +653,7 @@ void UK2Node_MultiGate::ExpandNode(class FKismetCompilerContext& CompilerContext ///////////////////////////// // Create the node - UK2Node_AssignmentStatement* AssignmentNode = SourceGraph->CreateBlankNode(); + UK2Node_AssignmentStatement* AssignmentNode = SourceGraph->CreateIntermediateNode(); AssignmentNode->AllocateDefaultPins(); CompilerContext.MessageLog.NotifyIntermediateObjectCreation(AssignmentNode, this); diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_PureAssignmentStatement.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_PureAssignmentStatement.cpp index 396231f9cd24..2bc4d4b9fc09 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_PureAssignmentStatement.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_PureAssignmentStatement.cpp @@ -79,9 +79,9 @@ void UK2Node_PureAssignmentStatement::AllocateDefaultPins() { const UEdGraphSchema_K2* Schema = GetDefault(); - CreatePin(EGPD_Input, Schema->PC_Wildcard, TEXT(""), NULL, false, false, VariablePinName); - CreatePin(EGPD_Input, Schema->PC_Wildcard, TEXT(""), NULL, false, false, ValuePinName); - CreatePin(EGPD_Output, Schema->PC_Wildcard, TEXT(""), NULL, false, false, OutputPinName); + CreatePin(EGPD_Input, Schema->PC_Wildcard, FString(), nullptr, VariablePinName); + CreatePin(EGPD_Input, Schema->PC_Wildcard, FString(), nullptr, ValuePinName); + CreatePin(EGPD_Output, Schema->PC_Wildcard, FString(), nullptr, OutputPinName); Super::AllocateDefaultPins(); } diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Select.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Select.cpp index fb5eae7283da..acf272968ab7 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Select.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Select.cpp @@ -117,7 +117,7 @@ public: LiteralTerm->Type = IndexTerm->Type; LiteralTerm->bIsLiteral = true; const UEnum* NodeEnum = SelectNode->GetEnum(); - LiteralTerm->Name = NodeEnum ? OptionPins[OptionIdx]->PinName : FString::Printf(TEXT("%d"), OptionIdx); + LiteralTerm->Name = NodeEnum ? OptionPins[OptionIdx]->PinName : FString::Printf(TEXT("%d"), OptionIdx); //-V595 if (!CompilerContext.GetSchema()->DefaultValueSimpleValidation(LiteralTerm->Type, LiteralTerm->Name, LiteralTerm->Name, nullptr, FText())) { @@ -320,9 +320,9 @@ public: NopStatement.Type = KCST_Nop; NopStatement.bIsJumpTarget = true; // Loop through the unconditional goto statements and fix their jump targets - for (auto It = GotoStatementList.CreateConstIterator(); It; It++) + for (FBlueprintCompiledStatement* GotoStatement : GotoStatementList) { - (*It)->TargetLabel = &NopStatement; + GotoStatement->TargetLabel = &NopStatement; } } } @@ -360,7 +360,7 @@ void UK2Node_Select::AllocateDefaultPins() // Create the option pins for (int32 Idx = 0; Idx < NumOptionPins; Idx++) { - UEdGraphPin* NewPin = NULL; + UEdGraphPin* NewPin = nullptr; if (Enum) { @@ -368,13 +368,13 @@ void UK2Node_Select::AllocateDefaultPins() UEdGraphPin* TempPin = FindPin(PinName); if (!TempPin) { - NewPin = CreatePin(EGPD_Input, Schema->PC_Wildcard, TEXT(""), NULL, false, false, PinName); + NewPin = CreatePin(EGPD_Input, Schema->PC_Wildcard, FString(), nullptr, PinName); } } else { const FString PinName = FString::Printf(TEXT("Option %d"), Idx); - NewPin = CreatePin(EGPD_Input, Schema->PC_Wildcard, TEXT(""), NULL, false, false, PinName); + NewPin = CreatePin(EGPD_Input, Schema->PC_Wildcard, FString(), nullptr, PinName); } if (NewPin) @@ -392,10 +392,10 @@ void UK2Node_Select::AllocateDefaultPins() } // Create the index wildcard pin - CreatePin(EGPD_Input, IndexPinType.PinCategory, IndexPinType.PinSubCategory, IndexPinType.PinSubCategoryObject.Get(), false, false, "Index"); + CreatePin(EGPD_Input, IndexPinType.PinCategory, IndexPinType.PinSubCategory, IndexPinType.PinSubCategoryObject.Get(), TEXT("Index")); // Create the return value - auto ReturnPin = CreatePin(EGPD_Output, Schema->PC_Wildcard, TEXT(""), NULL, false, false, Schema->PN_ReturnValue); + UEdGraphPin* ReturnPin = CreatePin(EGPD_Output, Schema->PC_Wildcard, FString(), nullptr, Schema->PN_ReturnValue); ReturnPin->bDisplayAsMutableRef = UseSelectRef; Super::AllocateDefaultPins(); @@ -465,68 +465,44 @@ void UK2Node_Select::ReallocatePinsDuringReconstruction(TArray& Ol const UEdGraphSchema_K2* Schema = GetDefault(); // See if this node was saved in the old version with a boolean as the condition - UEdGraphPin* OldConditionPin = NULL; - UEdGraphPin* OldIndexPin = NULL; - UEdGraphPin* OldReturnPin = NULL; - for (auto It = OldPins.CreateConstIterator(); It; It++) + UEdGraphPin* OldConditionPin = nullptr; + UEdGraphPin* OldIndexPin = nullptr; + UEdGraphPin* OldReturnPin = nullptr; + for (UEdGraphPin* OldPin : OldPins) { - if ((*It)->PinName == TEXT("bPickOption0")) + if (OldPin->PinName == TEXT("bPickOption0")) { - OldConditionPin = (*It); + OldConditionPin = OldPin; } - else if ((*It)->PinName == TEXT("Index")) + else if (OldPin->PinName == TEXT("Index")) { - OldIndexPin = (*It); + OldIndexPin = OldPin; } - else if ((*It)->PinName == Schema->PN_ReturnValue) + else if (OldPin->PinName == Schema->PN_ReturnValue) { - OldReturnPin = (*It); + OldReturnPin = OldPin; } } - bool bIsAnyOptionOrReturnConnected = false; - for (auto OldPin : OldPins) + UEdGraphPin* ReturnPin = GetReturnValuePin(); + check(ReturnPin); + + if (OldReturnPin && (ReturnPin->PinType.PinCategory == Schema->PC_Wildcard)) { - if ((OldPin != OldConditionPin) && (OldPin != OldIndexPin) && OldPin->LinkedTo.Num()) - { - bIsAnyOptionOrReturnConnected = true; - break; - } - } - auto NewReturn = GetReturnValuePin(); - if (!bIsAnyOptionOrReturnConnected && OldReturnPin && NewReturn - && (NewReturn->PinType.PinCategory == Schema->PC_Wildcard)) - { - NewReturn->PinType = OldReturnPin->PinType; - } - else if (OldReturnPin && NewReturn && OldReturnPin->LinkedTo.Num()) - { - auto BP = GetBlueprint(); - UClass* SelfClass = BP ? BP->GeneratedClass : nullptr; - bool OldTypeIsValid = true; - for (auto OutPin : OldReturnPin->LinkedTo) - { - if (OutPin && !Schema->ArePinTypesCompatible(OldReturnPin->PinType, OutPin->PinType, SelfClass)) - { - OldTypeIsValid = false; - break; - } - } - if (OldTypeIsValid) - { - NewReturn->PinType = OldReturnPin->PinType; - } + // Always copy type from node prior, if pins have changed those will error at compilation time + ReturnPin->PinType = OldReturnPin->PinType; } UEdGraphPin* IndexPin = GetIndexPin(); + check(IndexPin); // If we are fixing up an old bool node (swap the options and copy the condition links) if (OldConditionPin) { // Set the index pin type IndexPinType.PinCategory = Schema->PC_Boolean; - IndexPinType.PinSubCategory = TEXT(""); - IndexPinType.PinSubCategoryObject = NULL; + IndexPinType.PinSubCategory.Reset(); + IndexPinType.PinSubCategoryObject = nullptr; // Set the pin type and Copy the pin IndexPin->PinType = IndexPinType; @@ -540,9 +516,8 @@ void UK2Node_Select::ReallocatePinsDuringReconstruction(TArray& Ol UEdGraphPin* OptionPin0 = FindPin("Option 0"); UEdGraphPin* OptionPin1 = FindPin("Option 1"); - for (auto It = OldPins.CreateConstIterator(); It; It++) + for (UEdGraphPin* OldPin : OldPins) { - UEdGraphPin* OldPin = (*It); if (OldPin->PinName == OptionPin0->PinName) { Schema->MovePinLinks(*OldPin, *OptionPin1); @@ -557,44 +532,65 @@ void UK2Node_Select::ReallocatePinsDuringReconstruction(TArray& Ol // If the index pin has links or a default value but is a wildcard, this is an old int pin so convert it if (OldIndexPin && IndexPinType.PinCategory == Schema->PC_Wildcard && - (OldIndexPin->LinkedTo.Num() > 0 || OldIndexPin->DefaultValue != TEXT(""))) + (OldIndexPin->LinkedTo.Num() > 0 || !OldIndexPin->DefaultValue.IsEmpty())) { IndexPinType.PinCategory = Schema->PC_Int; - IndexPinType.PinSubCategory = TEXT(""); - IndexPinType.PinSubCategoryObject = NULL; + IndexPinType.PinSubCategory.Reset(); + IndexPinType.PinSubCategoryObject = nullptr; IndexPin->PinType = IndexPinType; } + + // Set up default values for index and option pins now that the information is available + Schema->SetPinAutogeneratedDefaultValueBasedOnType(IndexPin); + + const bool bFillTypeFromReturn = ReturnPin->PinType.PinCategory != Schema->PC_Wildcard; + TArray OptionPins; + GetOptionPins(OptionPins); + for (UEdGraphPin* Pin : OptionPins) + { + const bool bTypeShouldBeFilled = Pin && (Pin->PinType.PinCategory == Schema->PC_Wildcard); + if (bTypeShouldBeFilled && bFillTypeFromReturn) + { + Pin->PinType = ReturnPin->PinType; + } + Schema->SetPinAutogeneratedDefaultValueBasedOnType(Pin); + } } void UK2Node_Select::PostReconstructNode() { + // After ReconstructNode we must be sure that no additional reconstruction is required bReconstructNode = false; - const UEdGraphSchema_K2* Schema = Cast(GetSchema()); - UEdGraphPin* ReturnPin = GetReturnValuePin(); - PinConnectionListChanged(ReturnPin); - const bool bFillTypeFromReturn = Schema && ReturnPin && (ReturnPin->PinType.PinCategory != Schema->PC_Wildcard); + const bool bFillTypeFromConnected = ReturnPin && (ReturnPin->PinType.PinCategory == UEdGraphSchema_K2::PC_Wildcard); - TArray OptionPins; - GetOptionPins(OptionPins); - for (auto It = OptionPins.CreateConstIterator(); It; It++) + if (bFillTypeFromConnected) { - UEdGraphPin* Pin = *It; - const bool bTypeShouldBeFilled = Schema && Pin && (Pin->PinType.PinCategory == Schema->PC_Wildcard); - if (bTypeShouldBeFilled && bFillTypeFromReturn) + FEdGraphPinType PinType = ReturnPin->PinType; + + if (ReturnPin->LinkedTo.Num() > 0) { - Pin->Modify(); - Pin->PinType = ReturnPin->PinType; - UEdGraphSchema_K2::ValidateExistingConnections(Pin); + PinType = ReturnPin->LinkedTo[0]->PinType; + } + else + { + TArray OptionPins; + GetOptionPins(OptionPins); + for (UEdGraphPin* Pin : OptionPins) + { + if (Pin && Pin->LinkedTo.Num() > 0) + { + PinType = Pin->LinkedTo[0]->PinType; + break; + } + } } - PinConnectionListChanged(*It); + ReturnPin->PinType = PinType; + PinTypeChanged(ReturnPin); } - //After ReconstructNode we must be sure, that no additional reconstruction is required - bReconstructNode = false; - Super::PostReconstructNode(); } @@ -609,40 +605,15 @@ void UK2Node_Select::NotifyPinConnectionListChanged(UEdGraphPin* Pin) if (Pin == GetIndexPin()) { // If the index pin was just linked to another pin - if (Pin->LinkedTo.Num() > 0) + if (Pin->LinkedTo.Num() > 0 && Pin->PinType.PinCategory == Schema->PC_Wildcard) { UEdGraphPin* LinkPin = Pin->LinkedTo[0]; - IndexPinType = LinkPin->PinType; - Pin->PinType = IndexPinType; - // See if it was an enum pin - if (LinkPin->PinType.PinCategory == Schema->PC_Byte && - LinkPin->PinType.PinSubCategoryObject != NULL && - LinkPin->PinType.PinSubCategoryObject->IsA(UEnum::StaticClass())) + if (Pin->PinType != LinkPin->PinType) { - UEnum* EnumPtr = Cast(LinkPin->PinType.PinSubCategoryObject.Get()); - SetEnum(EnumPtr); - } - else - { - SetEnum(NULL); - } + Pin->PinType = LinkPin->PinType; - Schema->SetPinDefaultValueBasedOnType(Pin); - - GetGraph()->NotifyGraphChanged(); - UBlueprint* Blueprint = GetBlueprint(); - if(!Blueprint->bBeingCompiled) - { - FBlueprintEditorUtils::MarkBlueprintAsModified(Blueprint); - Blueprint->BroadcastChanged(); - } - - // If the index pin is a boolean, we need to remove all but 2 options - if (IndexPinType.PinCategory == Schema->PC_Boolean) - { - NumOptionPins = 2; - bReconstructNode = true; + PinTypeChanged(Pin); } } } @@ -662,32 +633,14 @@ void UK2Node_Select::NotifyPinConnectionListChanged(UEdGraphPin* Pin) // If the pin is linked, make sure the other wildcard pins match if (Pin->LinkedTo.Num() > 0) { - // Set pin type on the pin - Pin->PinType = Pin->LinkedTo[0]->PinType; + UEdGraphPin* LinkPin = Pin->LinkedTo[0]; - // Make sure the return pin is the same pin type - if (ReturnPin != Pin) + if (Pin->PinType != LinkPin->PinType) { - ReturnPin->Modify(); + Pin->PinType = LinkPin->PinType; - ReturnPin->PinType = Pin->PinType; - UEdGraphSchema_K2::ValidateExistingConnections(ReturnPin); + PinTypeChanged(Pin); } - - // Make sure all options are of the same pin type - for (auto It = OptionPins.CreateConstIterator(); It; It++) - { - UEdGraphPin* OptionPin = (*It); - if (*It && *It != Pin) - { - (*It)->Modify(); - - (*It)->PinType = Pin->PinType; - UEdGraphSchema_K2::ValidateExistingConnections(*It); - } - } - - bReconstructNode = true; } } } @@ -722,13 +675,12 @@ void UK2Node_Select::GetOptionPins(TArray& OptionPins) const // If the select node is currently dealing with an enum if (IndexPinType.PinCategory == K2Schema->PC_Byte && - IndexPinType.PinSubCategory == TEXT("") && - IndexPinType.PinSubCategoryObject != NULL && + IndexPinType.PinSubCategory.IsEmpty() && + IndexPinType.PinSubCategoryObject != nullptr && IndexPinType.PinSubCategoryObject->IsA(UEnum::StaticClass())) { - for (auto It = Pins.CreateConstIterator(); It; It++) + for (UEdGraphPin* Pin : Pins) { - UEdGraphPin* Pin = (*It); if (EnumEntries.Contains(FName(*Pin->PinName))) { OptionPins.Add(Pin); @@ -737,9 +689,8 @@ void UK2Node_Select::GetOptionPins(TArray& OptionPins) const } else { - for (auto It = Pins.CreateConstIterator(); It; It++) + for (UEdGraphPin* Pin : Pins) { - UEdGraphPin* Pin = (*It); if (Pin->PinName.Left(6) == "Option") { OptionPins.Add(Pin); @@ -887,6 +838,18 @@ bool UK2Node_Select::CanRemoveOptionPinToNode() const void UK2Node_Select::ChangePinType(UEdGraphPin* Pin) { PinTypeChanged(Pin); + + if (bReconstructNode) + { + ReconstructNode(); + } + + UBlueprint* Blueprint = GetBlueprint(); + if (!Blueprint->bBeingCompiled) + { + FBlueprintEditorUtils::MarkBlueprintAsModified(Blueprint); + Blueprint->BroadcastChanged(); + } } bool UK2Node_Select::CanChangePinType(UEdGraphPin* Pin) const @@ -910,9 +873,8 @@ bool UK2Node_Select::CanChangePinType(UEdGraphPin* Pin) const { TArray OptionPins; GetOptionPins(OptionPins); - for (auto It = OptionPins.CreateConstIterator(); It; It++) + for (UEdGraphPin* OptionPin : OptionPins) { - UEdGraphPin* OptionPin = (*It); if (OptionPin && OptionPin->LinkedTo.Num() > 0) { return false; @@ -946,27 +908,27 @@ void UK2Node_Select::PinTypeChanged(UEdGraphPin* Pin) if (IndexPinType.PinCategory == Schema->PC_Boolean) { NumOptionPins = 2; - bReconstructNode = true; } - // Reset the default value - Schema->SetPinDefaultValueBasedOnType(Pin); + if (!Schema->IsPinDefaultValid(Pin, Pin->DefaultValue, Pin->DefaultObject, Pin->DefaultTextValue).IsEmpty()) + { + Schema->ResetPinToAutogeneratedDefaultValue(Pin); + } + + bReconstructNode = true; } } else { // Set the return value UEdGraphPin* ReturnPin = GetReturnValuePin(); - if (ReturnPin->PinType != Pin->PinType) + + // Recombine the sub pins back into the ReturnPin + if (ReturnPin->SubPins.Num() > 0) { - // Recombine the sub pins back into the ReturnPin - if (ReturnPin->SubPins.Num() > 0) - { - Schema->RecombinePin(ReturnPin->SubPins[0]); - } - ReturnPin->PinType = Pin->PinType; - Schema->SetPinDefaultValueBasedOnType(ReturnPin); + Schema->RecombinePin(ReturnPin->SubPins[0]); } + ReturnPin->PinType = Pin->PinType; // Recombine all option pins back into their root TArray OptionPins; @@ -982,33 +944,21 @@ void UK2Node_Select::PinTypeChanged(UEdGraphPin* Pin) // Get the options again and set them GetOptionPins(OptionPins); - for (auto It = OptionPins.CreateConstIterator(); It; It++) + for (UEdGraphPin* OptionPin : OptionPins) { - UEdGraphPin* OptionPin = (*It); if (OptionPin->PinType != Pin->PinType || OptionPin == Pin) { OptionPin->PinType = Pin->PinType; - Schema->SetPinDefaultValueBasedOnType(OptionPin); + } + + if (!Schema->IsPinDefaultValid(OptionPin, OptionPin->DefaultValue, OptionPin->DefaultObject, OptionPin->DefaultTextValue).IsEmpty()) + { + Schema->ResetPinToAutogeneratedDefaultValue(OptionPin); } } - } - - // Reconstruct the node since the options could change - if (bReconstructNode) - { - ReconstructNode(); - } - - // Let the graph know to refresh - GetGraph()->NotifyGraphChanged(); - - UBlueprint* Blueprint = GetBlueprint(); - if(!Blueprint->bBeingCompiled) - { - FBlueprintEditorUtils::MarkBlueprintAsModified(Blueprint); - Blueprint->BroadcastChanged(); + bReconstructNode = true; } } @@ -1091,8 +1041,8 @@ void UK2Node_Select::ExpandNode(class FKismetCompilerContext& CompilerContext, U } bool bSuccess = false; - auto Schema = CompilerContext.GetSchema(); - for (auto Pin : Pins) + const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema(); + for (UEdGraphPin* Pin : Pins) { const bool bValidAutoRefPin = Pin && !Schema->IsMetaPin(*Pin) && (Pin->Direction == EGPD_Input) && (!Pin->LinkedTo.Num() || (GetIndexPin() == Pin)); if (!bValidAutoRefPin) @@ -1100,19 +1050,19 @@ void UK2Node_Select::ExpandNode(class FKismetCompilerContext& CompilerContext, U continue; } - //default values can be reset when the pin is connected - const auto DefaultValue = Pin->DefaultValue; - const auto DefaultObject = Pin->DefaultObject; - const auto DefaultTextValue = Pin->DefaultTextValue; - const auto AutogeneratedDefaultValue = Pin->AutogeneratedDefaultValue; + // copy defaults as default values can be reset when the pin is connected + const FString DefaultValue = Pin->DefaultValue; + UObject* DefaultObject = Pin->DefaultObject; + const FText DefaultTextValue = Pin->DefaultTextValue; + bool bMatchesDefaults = Pin->DoesDefaultValueMatchAutogenerated(); - auto ValuePin = UK2Node_CallFunction::InnerHandleAutoCreateRef(this, Pin, CompilerContext, SourceGraph, true); + UEdGraphPin* ValuePin = UK2Node_CallFunction::InnerHandleAutoCreateRef(this, Pin, CompilerContext, SourceGraph, true); if (ValuePin) { - if (!DefaultObject && DefaultTextValue.IsEmpty() && DefaultValue.Equals(AutogeneratedDefaultValue, ESearchCase::CaseSensitive)) + if (bMatchesDefaults) { // Use the latest code to set default value - Schema->SetPinDefaultValueBasedOnType(ValuePin); + Schema->SetPinAutogeneratedDefaultValueBasedOnType(ValuePin); } else { diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Self.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Self.cpp index c2a0346f9ed1..120f3edda567 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Self.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Self.cpp @@ -43,7 +43,7 @@ UK2Node_Self::UK2Node_Self(const FObjectInitializer& ObjectInitializer) void UK2Node_Self::AllocateDefaultPins() { const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Output, K2Schema->PC_Object, K2Schema->PSC_Self, NULL, false, false, K2Schema->PN_Self); + CreatePin(EGPD_Output, K2Schema->PC_Object, K2Schema->PSC_Self, nullptr, K2Schema->PN_Self); Super::AllocateDefaultPins(); } diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SetFieldsInStruct.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SetFieldsInStruct.cpp index ae79796fd267..c1c5eba21254 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SetFieldsInStruct.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SetFieldsInStruct.cpp @@ -126,12 +126,12 @@ void UK2Node_SetFieldsInStruct::AllocateDefaultPins() const UEdGraphSchema_K2* Schema = GetDefault(); if (Schema && StructType) { - CreatePin(EGPD_Input, Schema->PC_Exec, TEXT(""), NULL, false, false, Schema->PN_Execute); - CreatePin(EGPD_Output, Schema->PC_Exec, TEXT(""), NULL, false, false, Schema->PN_Then); + CreatePin(EGPD_Input, Schema->PC_Exec, FString(), nullptr, Schema->PN_Execute); + CreatePin(EGPD_Output, Schema->PC_Exec, FString(), nullptr, Schema->PN_Then); - UEdGraphPin* InPin = CreatePin(EGPD_Input, Schema->PC_Struct, TEXT(""), StructType, false, true, SetFieldsInStructHelper::StructRefPinName()); + UEdGraphPin* InPin = CreatePin(EGPD_Input, Schema->PC_Struct, FString(), StructType, SetFieldsInStructHelper::StructRefPinName(), EPinContainerType::None, true); - UEdGraphPin* OutPin = CreatePin(EGPD_Output, Schema->PC_Struct, TEXT(""), StructType, false, true, SetFieldsInStructHelper::StructOutPinName()); + UEdGraphPin* OutPin = CreatePin(EGPD_Output, Schema->PC_Struct, FString(), StructType, SetFieldsInStructHelper::StructOutPinName(), EPinContainerType::None, true); // Input pin will forward the ref to the output, if the input value is not a reference connection, a copy is made and modified instead and provided as a reference until the function is called again. InPin->AssignByRefPassThroughConnection(OutPin); diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SetVariableOnPersistentFrame.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SetVariableOnPersistentFrame.cpp index 56ee7fe8b889..f7b36a85ccd3 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SetVariableOnPersistentFrame.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SetVariableOnPersistentFrame.cpp @@ -84,8 +84,8 @@ void UK2Node_SetVariableOnPersistentFrame::AllocateDefaultPins() { const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Execute); - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Then); + CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Execute); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Then); Super::AllocateDefaultPins(); } diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SpawnActor.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SpawnActor.cpp index 68fb098846ea..e2ac5dfee126 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SpawnActor.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SpawnActor.cpp @@ -31,30 +31,30 @@ void UK2Node_SpawnActor::AllocateDefaultPins() UEdGraphSchema_K2 const* K2Schema = GetDefault(); // Add execution pins - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Execute); - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Then); + CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Execute); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Then); // If required add the world context pin if (GetBlueprint()->ParentClass->HasMetaDataHierarchical(FBlueprintMetadata::MD_ShowWorldContextPin)) { - CreatePin(EGPD_Input, K2Schema->PC_Object, TEXT(""), UObject::StaticClass(), false, false, WorldContextPinName); + CreatePin(EGPD_Input, K2Schema->PC_Object, FString(), UObject::StaticClass(), WorldContextPinName); } // Add blueprint pin - UEdGraphPin* BlueprintPin = CreatePin(EGPD_Input, K2Schema->PC_Object, TEXT(""), UBlueprint::StaticClass(), false, false, BlueprintPinName); + UEdGraphPin* BlueprintPin = CreatePin(EGPD_Input, K2Schema->PC_Object, FString(), UBlueprint::StaticClass(), BlueprintPinName); K2Schema->ConstructBasicPinTooltip(*BlueprintPin, LOCTEXT("BlueprintPinDescription", "The blueprint Actor you want to spawn"), BlueprintPin->PinToolTip); // Transform pin UScriptStruct* TransformStruct = TBaseStructure::Get(); - UEdGraphPin* TransformPin = CreatePin(EGPD_Input, K2Schema->PC_Struct, TEXT(""), TransformStruct, false, false, SpawnTransformPinName); + UEdGraphPin* TransformPin = CreatePin(EGPD_Input, K2Schema->PC_Struct, FString(), TransformStruct, SpawnTransformPinName); K2Schema->ConstructBasicPinTooltip(*TransformPin, LOCTEXT("TransformPinDescription", "The transform to spawn the Actor with"), TransformPin->PinToolTip); // bNoCollisionFail pin - UEdGraphPin* NoCollisionFailPin = CreatePin(EGPD_Input, K2Schema->PC_Boolean, TEXT(""), NULL, false, false, NoCollisionFailPinName); + UEdGraphPin* NoCollisionFailPin = CreatePin(EGPD_Input, K2Schema->PC_Boolean, FString(), nullptr, NoCollisionFailPinName); K2Schema->ConstructBasicPinTooltip(*NoCollisionFailPin, LOCTEXT("NoCollisionFailPinDescription", "Determines if the Actor should be spawned when the location is blocked by a collision"), NoCollisionFailPin->PinToolTip); // Result pin - UEdGraphPin* ResultPin = CreatePin(EGPD_Output, K2Schema->PC_Object, TEXT(""), AActor::StaticClass(), false, false, K2Schema->PN_ReturnValue); + UEdGraphPin* ResultPin = CreatePin(EGPD_Output, K2Schema->PC_Object, FString(), AActor::StaticClass(), K2Schema->PN_ReturnValue); K2Schema->ConstructBasicPinTooltip(*ResultPin, LOCTEXT("ResultPinDescription", "The spawned Actor"), ResultPin->PinToolTip); Super::AllocateDefaultPins(); @@ -80,8 +80,8 @@ void UK2Node_SpawnActor::CreatePinsForClass(UClass* InClass) Property->HasAllPropertyFlags(CPF_BlueprintVisible) && !bIsDelegate ) { - UEdGraphPin* Pin = CreatePin(EGPD_Input, TEXT(""), TEXT(""), NULL, false, false, Property->GetName()); - const bool bPinGood = (Pin != NULL) && K2Schema->ConvertPropertyToPinType(Property, /*out*/ Pin->PinType); + UEdGraphPin* Pin = CreatePin(EGPD_Input, FString(), FString(), nullptr, Property->GetName()); + const bool bPinGood = (Pin != nullptr) && K2Schema->ConvertPropertyToPinType(Property, /*out*/ Pin->PinType); // Copy tooltip from the property. if (Pin != nullptr) @@ -425,7 +425,7 @@ void UK2Node_SpawnActor::ExpandNode(class FKismetCompilerContext& CompilerContex if(SetByNameFunction) { UK2Node_CallFunction* SetVarNode = NULL; - if(SpawnVarPin->PinType.bIsArray) + if(SpawnVarPin->PinType.IsArray()) { SetVarNode = CompilerContext.SpawnIntermediateNode(this, SourceGraph); } @@ -452,7 +452,7 @@ void UK2Node_SpawnActor::ExpandNode(class FKismetCompilerContext& CompilerContex // Move connection from the variable pin on the spawn node to the 'value' pin UEdGraphPin* ValuePin = SetVarNode->FindPinChecked(ValueParamName); CompilerContext.MovePinLinksToIntermediate(*SpawnVarPin, *ValuePin); - if(SpawnVarPin->PinType.bIsArray) + if(SpawnVarPin->PinType.IsArray()) { SetVarNode->PinConnectionListChanged(ValuePin); } diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SpawnActorFromClass.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SpawnActorFromClass.cpp index 9c45aaad4c48..08818500d929 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SpawnActorFromClass.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SpawnActorFromClass.cpp @@ -49,28 +49,28 @@ void UK2Node_SpawnActorFromClass::AllocateDefaultPins() const UEdGraphSchema_K2* K2Schema = GetDefault(); // Add execution pins - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Execute); - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Then); + CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Execute); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Then); // If required add the world context pin if (GetBlueprint()->ParentClass->HasMetaDataHierarchical(FBlueprintMetadata::MD_ShowWorldContextPin)) { - CreatePin(EGPD_Input, K2Schema->PC_Object, TEXT(""), UObject::StaticClass(), false, false, FK2Node_SpawnActorFromClassHelper::WorldContextPinName); + CreatePin(EGPD_Input, K2Schema->PC_Object, FString(), UObject::StaticClass(), FK2Node_SpawnActorFromClassHelper::WorldContextPinName); } // Add blueprint pin - UEdGraphPin* ClassPin = CreatePin(EGPD_Input, K2Schema->PC_Class, TEXT(""), AActor::StaticClass(), false, false, FK2Node_SpawnActorFromClassHelper::ClassPinName); + UEdGraphPin* ClassPin = CreatePin(EGPD_Input, K2Schema->PC_Class, FString(), AActor::StaticClass(), FK2Node_SpawnActorFromClassHelper::ClassPinName); // Transform pin UScriptStruct* TransformStruct = TBaseStructure::Get(); - UEdGraphPin* TransformPin = CreatePin(EGPD_Input, K2Schema->PC_Struct, TEXT(""), TransformStruct, false, false, FK2Node_SpawnActorFromClassHelper::SpawnTransformPinName); + UEdGraphPin* TransformPin = CreatePin(EGPD_Input, K2Schema->PC_Struct, FString(), TransformStruct, FK2Node_SpawnActorFromClassHelper::SpawnTransformPinName); // Collision handling method pin UEnum* const MethodEnum = FindObjectChecked(ANY_PACKAGE, TEXT("ESpawnActorCollisionHandlingMethod"), true); - UEdGraphPin* const CollisionHandlingOverridePin = CreatePin(EGPD_Input, K2Schema->PC_Byte, TEXT(""), MethodEnum, false, false, FK2Node_SpawnActorFromClassHelper::CollisionHandlingOverridePinName); + UEdGraphPin* const CollisionHandlingOverridePin = CreatePin(EGPD_Input, K2Schema->PC_Byte, FString(), MethodEnum, FK2Node_SpawnActorFromClassHelper::CollisionHandlingOverridePinName); CollisionHandlingOverridePin->DefaultValue = MethodEnum->GetNameStringByValue(static_cast(ESpawnActorCollisionHandlingMethod::Undefined)); - UEdGraphPin* OwnerPin = CreatePin(EGPD_Input, K2Schema->PC_Object, TEXT(""), AActor::StaticClass(),/*bIsArray =*/false, /*bIsReference =*/false, FK2Node_SpawnActorFromClassHelper::OwnerPinName); + UEdGraphPin* OwnerPin = CreatePin(EGPD_Input, K2Schema->PC_Object, FString(), AActor::StaticClass(), FK2Node_SpawnActorFromClassHelper::OwnerPinName); OwnerPin->bAdvancedView = true; if (ENodeAdvancedPins::NoPins == AdvancedPinDisplay) { @@ -78,7 +78,7 @@ void UK2Node_SpawnActorFromClass::AllocateDefaultPins() } // Result pin - UEdGraphPin* ResultPin = CreatePin(EGPD_Output, K2Schema->PC_Object, TEXT(""), AActor::StaticClass(), false, false, K2Schema->PN_ReturnValue); + UEdGraphPin* ResultPin = CreatePin(EGPD_Output, K2Schema->PC_Object, FString(), AActor::StaticClass(), K2Schema->PN_ReturnValue); Super::AllocateDefaultPins(); } @@ -106,16 +106,16 @@ void UK2Node_SpawnActorFromClass::CreatePinsForClass(UClass* InClass, TArrayGetName()) ) ) { - UEdGraphPin* Pin = CreatePin(EGPD_Input, TEXT(""), TEXT(""), NULL, false, false, Property->GetName()); - const bool bPinGood = (Pin != NULL) && K2Schema->ConvertPropertyToPinType(Property, /*out*/ Pin->PinType); + UEdGraphPin* Pin = CreatePin(EGPD_Input, FString(), FString(), nullptr, Property->GetName()); + const bool bPinGood = (Pin != nullptr) && K2Schema->ConvertPropertyToPinType(Property, /*out*/ Pin->PinType); OutClassPins.Add(Pin); - if (ClassDefaultObject && Pin != NULL && K2Schema->PinDefaultValueIsEditable(*Pin)) + if (ClassDefaultObject && Pin != nullptr && K2Schema->PinDefaultValueIsEditable(*Pin)) { FString DefaultValueAsString; const bool bDefaultValueSet = FBlueprintEditorUtils::PropertyValueToString(Property, reinterpret_cast(ClassDefaultObject), DefaultValueAsString); check( bDefaultValueSet ); - K2Schema->TrySetDefaultValue(*Pin, DefaultValueAsString); + K2Schema->SetPinAutogeneratedDefaultValue(Pin, DefaultValueAsString); } // Copy tooltip from the property. diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_StructMemberSet.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_StructMemberSet.cpp index 4d2d928d32da..e3c7424e5089 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_StructMemberSet.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_StructMemberSet.cpp @@ -31,8 +31,8 @@ void UK2Node_StructMemberSet::AllocateDefaultPins() const UEdGraphSchema_K2* Schema = GetDefault(); // Add the execution sequencing pin - CreatePin(EGPD_Input, Schema->PC_Exec, TEXT(""), NULL, false, false, Schema->PN_Execute); - CreatePin(EGPD_Output, Schema->PC_Exec, TEXT(""), NULL, false, false, Schema->PN_Then); + CreatePin(EGPD_Input, Schema->PC_Exec, FString(), nullptr, Schema->PN_Execute); + CreatePin(EGPD_Output, Schema->PC_Exec, FString(), nullptr, Schema->PN_Then); // Display any currently visible optional pins { diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_StructOperation.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_StructOperation.cpp index 40cda7115f4b..4361710a4619 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_StructOperation.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_StructOperation.cpp @@ -14,6 +14,13 @@ UK2Node_StructOperation::UK2Node_StructOperation(const FObjectInitializer& Objec : Super(ObjectInitializer) { } + +void UK2Node_StructOperation::ValidateNodeDuringCompilation(class FCompilerResultsLog& MessageLog) const +{ + // Skip UK2Node_Variable's validation because it doesn't need a property (see CL# 1756451) + Super::Super::ValidateNodeDuringCompilation(MessageLog); +} + bool UK2Node_StructOperation::HasExternalDependencies(TArray* OptionalOutput) const { const bool bResult = nullptr != StructType; @@ -32,10 +39,10 @@ void UK2Node_StructOperation::FStructOperationOptionalPinManager::CustomizePinDa if (Pin && Property) { - const auto UDStructure = Cast(Property->GetOwnerStruct()); + const UUserDefinedStruct* UDStructure = Cast(Property->GetOwnerStruct()); if (UDStructure) { - const auto VarDesc = FStructureEditorUtils::GetVarDesc(UDStructure).FindByPredicate( + const FStructVariableDescription* VarDesc = FStructureEditorUtils::GetVarDesc(UDStructure).FindByPredicate( FStructureEditorUtils::FFindByNameHelper(Property->GetFName())); if (VarDesc) { diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Switch.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Switch.cpp index 38f8b43b1ff0..67c3f4add347 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Switch.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Switch.cpp @@ -184,11 +184,11 @@ void UK2Node_Switch::AllocateDefaultPins() // Add default pin if (bHasDefaultPin) { - CreatePin(EGPD_Output, K2Schema->PC_Exec,TEXT(""), NULL, false, false, DefaultPinName); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, DefaultPinName); } // Add exec input pin - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Execute); + CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Execute); // Create selection pin based on type CreateSelectionPin(); @@ -237,7 +237,7 @@ void UK2Node_Switch::AddPinToSwitchNode() FString NewPinName = GetUniquePinName(); if (NewPinName.Len() > 0) { - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, NewPinName); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, NewPinName); } } @@ -247,7 +247,7 @@ void UK2Node_Switch::RemovePinFromSwitchNode(UEdGraphPin* TargetPin) if(bHasDefaultPin && TargetPin == GetDefaultPin()) { UProperty* HasDefaultPinProperty = FindField(GetClass(), "bHasDefaultPin"); - if(HasDefaultPinProperty != NULL) + if(HasDefaultPinProperty) { PreEditChange(HasDefaultPinProperty); @@ -266,6 +266,23 @@ void UK2Node_Switch::RemovePinFromSwitchNode(UEdGraphPin* TargetPin) } } +bool UK2Node_Switch::CanRemoveExecutionPin(UEdGraphPin* TargetPin) const +{ + const UEdGraphSchema_K2* K2Schema = GetDefault(); + // Don't allow removing last pin + int32 NumExecPins = 0; + for (int32 i = 0; i < Pins.Num(); ++i) + { + UEdGraphPin* PotentialPin = Pins[i]; + if (K2Schema->IsExecPin(*PotentialPin) && (PotentialPin->Direction == EGPD_Output)) + { + NumExecPins++; + } + } + + return NumExecPins > 1; +} + // Returns the exec output pin name for a given 0-based index FString UK2Node_Switch::GetPinNameGivenIndex(int32 Index) { @@ -277,7 +294,7 @@ void UK2Node_Switch::CreateFunctionPin() { // Set properties on the function pin const UEdGraphSchema_K2* K2Schema = GetDefault(); - UEdGraphPin* FunctionPin = CreatePin(EGPD_Input, K2Schema->PC_Object, TEXT(""), FunctionClass, false, false, FunctionName.ToString()); + UEdGraphPin* FunctionPin = CreatePin(EGPD_Input, K2Schema->PC_Object, FString(), FunctionClass, FunctionName.ToString()); FunctionPin->bDefaultValueIsReadOnly = true; FunctionPin->bNotConnectable = true; FunctionPin->bHidden = true; diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SwitchEnum.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SwitchEnum.cpp index 5ce76e8804cc..408c8138aee9 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SwitchEnum.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SwitchEnum.cpp @@ -106,8 +106,8 @@ void UK2Node_SwitchEnum::GetMenuActions(FBlueprintActionDatabaseRegistrar& Actio void UK2Node_SwitchEnum::CreateSelectionPin() { const UEdGraphSchema_K2* K2Schema = GetDefault(); - UEdGraphPin* Pin = CreatePin(EGPD_Input, K2Schema->PC_Byte, TEXT(""), Enum, false, false, TEXT("Selection")); - K2Schema->SetPinDefaultValueBasedOnType(Pin); + UEdGraphPin* Pin = CreatePin(EGPD_Input, K2Schema->PC_Byte, FString(), Enum, TEXT("Selection")); + K2Schema->SetPinAutogeneratedDefaultValueBasedOnType(Pin); } FEdGraphPinType UK2Node_SwitchEnum::GetPinType() const @@ -149,7 +149,7 @@ void UK2Node_SwitchEnum::CreateCasePins() for (auto EnumIt = EnumEntries.CreateConstIterator(); EnumIt; ++EnumIt) { FName EnumEntry = *EnumIt; - UEdGraphPin * NewPin = CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, EnumEntry.ToString()); + UEdGraphPin * NewPin = CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, EnumEntry.ToString()); int32 Index = EnumIt.GetIndex(); if (EnumFriendlyNames.IsValidIndex(Index)) { diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SwitchInteger.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SwitchInteger.cpp index 3bf147d85cf2..4dad74f6452a 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SwitchInteger.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SwitchInteger.cpp @@ -48,8 +48,8 @@ void UK2Node_SwitchInteger::GetMenuActions(FBlueprintActionDatabaseRegistrar& Ac void UK2Node_SwitchInteger::CreateSelectionPin() { const UEdGraphSchema_K2* K2Schema = GetDefault(); - UEdGraphPin* Pin = CreatePin(EGPD_Input, K2Schema->PC_Int, TEXT(""), NULL, false, false, TEXT("Selection")); - K2Schema->SetPinDefaultValueBasedOnType(Pin); + UEdGraphPin* Pin = CreatePin(EGPD_Input, K2Schema->PC_Int, FString(), nullptr, TEXT("Selection")); + K2Schema->SetPinAutogeneratedDefaultValueBasedOnType(Pin); } FEdGraphPinType UK2Node_SwitchInteger::GetPinType() const @@ -110,12 +110,52 @@ void UK2Node_SwitchInteger::ReallocatePinsDuringReconstruction(TArrayPinName = NewPinName; // Create the new output pin to match - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, NewPinName); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, NewPinName); } } } } +bool UK2Node_SwitchInteger::CanRemoveExecutionPin(UEdGraphPin* TargetPin) const +{ + if (!Super::CanRemoveExecutionPin(TargetPin)) + { + return false; + } + + const UEdGraphSchema_K2* K2Schema = GetDefault(); + int32 PinIndex = (StartIndex >= 0) ? StartIndex : 0; + int32 FoundIndex = INDEX_NONE; + + UEdGraphPin* DefaultPin = GetDefaultPin(); + + if (TargetPin == DefaultPin) + { + return true; + } + + for (int32 i = 0; i < Pins.Num(); ++i) + { + UEdGraphPin* PotentialPin = Pins[i]; + if (K2Schema->IsExecPin(*PotentialPin) && (PotentialPin->Direction == EGPD_Output) && (PotentialPin != DefaultPin)) + { + if (PotentialPin == TargetPin) + { + FoundIndex = PinIndex; + } + + ++PinIndex; + } + } + + // Only allow removing last pin + if (FoundIndex != PinIndex - 1) + { + return false; + } + return true; +} + void UK2Node_SwitchInteger::RemovePin(UEdGraphPin* TargetPin) { const UEdGraphSchema_K2* K2Schema = GetDefault(); diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SwitchName.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SwitchName.cpp index 6ce6fdf73e4d..3633a437bd71 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SwitchName.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SwitchName.cpp @@ -63,8 +63,8 @@ void UK2Node_SwitchName::GetMenuActions(FBlueprintActionDatabaseRegistrar& Actio void UK2Node_SwitchName::CreateSelectionPin() { const UEdGraphSchema_K2* K2Schema = GetDefault(); - UEdGraphPin* Pin = CreatePin(EGPD_Input, K2Schema->PC_Name, TEXT(""), NULL, false, false, TEXT("Selection")); - K2Schema->SetPinDefaultValueBasedOnType(Pin); + UEdGraphPin* Pin = CreatePin(EGPD_Input, K2Schema->PC_Name, FString(), nullptr, TEXT("Selection")); + K2Schema->SetPinAutogeneratedDefaultValueBasedOnType(Pin); } FEdGraphPinType UK2Node_SwitchName::GetPinType() const @@ -83,9 +83,9 @@ FString UK2Node_SwitchName::GetPinNameGivenIndex(int32 Index) void UK2Node_SwitchName::CreateCasePins() { const UEdGraphSchema_K2* K2Schema = GetDefault(); - for( TArray::TIterator it(PinNames); it; ++it ) + for ( FName PinName : PinNames) { - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, (*it).ToString()); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, PinName.ToString()); } } @@ -110,7 +110,7 @@ void UK2Node_SwitchName::AddPinToSwitchNode() PinNames.Add(FName(*PinName)); const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, PinName); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, PinName); } void UK2Node_SwitchName::RemovePin(UEdGraphPin* TargetPin) diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SwitchString.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SwitchString.cpp index 8550a90d426a..07d572c33c54 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SwitchString.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_SwitchString.cpp @@ -5,6 +5,7 @@ #include "Kismet/KismetStringLibrary.h" #include "BlueprintNodeSpawner.h" #include "BlueprintActionDatabaseRegistrar.h" +#include "Kismet2/CompilerResultsLog.h" UK2Node_SwitchString::UK2Node_SwitchString(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) @@ -79,8 +80,8 @@ void UK2Node_SwitchString::GetMenuActions(FBlueprintActionDatabaseRegistrar& Act void UK2Node_SwitchString::CreateSelectionPin() { const UEdGraphSchema_K2* K2Schema = GetDefault(); - UEdGraphPin* Pin = CreatePin(EGPD_Input, K2Schema->PC_String, TEXT(""), NULL, false, false, TEXT("Selection")); - K2Schema->SetPinDefaultValueBasedOnType(Pin); + UEdGraphPin* Pin = CreatePin(EGPD_Input, K2Schema->PC_String, FString(), nullptr, TEXT("Selection")); + K2Schema->SetPinAutogeneratedDefaultValueBasedOnType(Pin); } FEdGraphPinType UK2Node_SwitchString::GetPinType() const @@ -100,9 +101,9 @@ FString UK2Node_SwitchString::GetPinNameGivenIndex(int32 Index) void UK2Node_SwitchString::CreateCasePins() { const UEdGraphSchema_K2* K2Schema = GetDefault(); - for( TArray::TIterator it(PinNames); it; ++it ) + for( const FString& PinName : PinNames) { - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, *it); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, PinName); } } @@ -127,7 +128,7 @@ void UK2Node_SwitchString::AddPinToSwitchNode() PinNames.Add(PinName); const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, PinName); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, PinName); } void UK2Node_SwitchString::RemovePin(UEdGraphPin* TargetPin) @@ -137,3 +138,15 @@ void UK2Node_SwitchString::RemovePin(UEdGraphPin* TargetPin) // Clean-up pin name array PinNames.Remove(TargetPin->PinName); } + +void UK2Node_SwitchString::ValidateNodeDuringCompilation(FCompilerResultsLog& MessageLog) const +{ + Super::ValidateNodeDuringCompilation(MessageLog); + + TSet UniquePinNames(PinNames); + + if (UniquePinNames.Num() != PinNames.Num()) + { + MessageLog.Error(*NSLOCTEXT("K2Node", "SwitchString_DuplicateCases", "@@ contains duplicate cases.").ToString(), this); + } +} \ No newline at end of file diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_TemporaryVariable.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_TemporaryVariable.cpp index e47f78fbffd2..84d5385beee9 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_TemporaryVariable.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_TemporaryVariable.cpp @@ -43,7 +43,7 @@ void UK2Node_TemporaryVariable::AllocateDefaultPins() { const UEdGraphSchema_K2* K2Schema = GetDefault(); - UEdGraphPin* VariablePin = CreatePin(EGPD_Output, TEXT(""), TEXT(""), NULL, false, false, TEXT("Variable")); + UEdGraphPin* VariablePin = CreatePin(EGPD_Output, FString(), FString(), nullptr, TEXT("Variable")); VariablePin->PinType = VariableType; Super::AllocateDefaultPins(); @@ -171,39 +171,39 @@ void UK2Node_TemporaryVariable::GetMenuActions(FBlueprintActionDatabaseRegistrar UEdGraphSchema_K2 const* K2Schema = GetDefault(); - ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Int, TEXT(""), nullptr, /*bIsArray =*/false, /*bIsReference =*/false, /*bIsSet=*/false, /*bIsMap=*/false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); - ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Int, TEXT(""), nullptr, /*bIsArray =*/ true, /*bIsReference =*/false, /*bIsSet=*/false, /*bIsMap=*/false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); - ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Float, TEXT(""), nullptr, /*bIsArray =*/false, /*bIsReference =*/false, /*bIsSet=*/false, /*bIsMap=*/false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); - ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Float, TEXT(""), nullptr, /*bIsArray =*/ true, /*bIsReference =*/false, /*bIsSet=*/false, /*bIsMap=*/false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); - ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Boolean, TEXT(""), nullptr, /*bIsArray =*/false, /*bIsReference =*/false, /*bIsSet=*/false, /*bIsMap=*/false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); - ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Boolean, TEXT(""), nullptr, /*bIsArray =*/ true, /*bIsReference =*/false, /*bIsSet=*/false, /*bIsMap=*/false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); - ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_String, TEXT(""), nullptr, /*bIsArray =*/false, /*bIsReference =*/false, /*bIsSet=*/false, /*bIsMap=*/false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); - ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_String, TEXT(""), nullptr, /*bIsArray =*/ true, /*bIsReference =*/false, /*bIsSet=*/false, /*bIsMap=*/false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); - ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Text, TEXT(""), nullptr, /*bIsArray =*/false, /*bIsReference =*/false, /*bIsSet=*/false, /*bIsMap=*/false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); - ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Text, TEXT(""), nullptr, /*bIsArray =*/ true, /*bIsReference =*/false, /*bIsSet=*/false, /*bIsMap=*/false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); + ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Int, FString(), nullptr, EPinContainerType::None, /*bIsReference =*/ false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); + ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Int, FString(), nullptr, EPinContainerType::Array, /*bIsReference =*/ false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); + ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Float, FString(), nullptr, EPinContainerType::None, /*bIsReference =*/ false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); + ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Float, FString(), nullptr, EPinContainerType::Array, /*bIsReference =*/ false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); + ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Boolean, FString(), nullptr, EPinContainerType::None, /*bIsReference =*/ false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); + ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Boolean, FString(), nullptr, EPinContainerType::Array, /*bIsReference =*/ false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); + ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_String, FString(), nullptr, EPinContainerType::None, /*bIsReference =*/ false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); + ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_String, FString(), nullptr, EPinContainerType::Array, /*bIsReference =*/ false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); + ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Text, FString(), nullptr, EPinContainerType::None, /*bIsReference =*/ false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); + ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Text, FString(), nullptr, EPinContainerType::Array, /*bIsReference =*/ false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); - ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Wildcard, TEXT(""), nullptr, /*bIsArray =*/false, /*bIsReference =*/false, /*bIsSet=*/false, /*bIsMap=*/false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); - ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Wildcard, TEXT(""), nullptr, /*bIsArray =*/ true, /*bIsReference =*/false, /*bIsSet=*/false, /*bIsMap=*/false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); + ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Wildcard, FString(), nullptr, EPinContainerType::None, /*bIsReference =*/ false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); + ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Wildcard, FString(), nullptr, EPinContainerType::Array, /*bIsReference =*/ false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); UScriptStruct* VectorStruct = TBaseStructure::Get(); - ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Struct, TEXT("Vector"), VectorStruct, /*bIsArray =*/false, /*bIsReference =*/false, /*bIsSet=*/false, /*bIsMap=*/false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); - ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Struct, TEXT("Vector"), VectorStruct, /*bIsArray =*/ true, /*bIsReference =*/false, /*bIsSet=*/false, /*bIsMap=*/false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); + ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Struct, TEXT("Vector"), VectorStruct, EPinContainerType::None, /*bIsReference =*/ false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); + ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Struct, TEXT("Vector"), VectorStruct, EPinContainerType::Array, /*bIsReference =*/ false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); UScriptStruct* RotatorStruct = TBaseStructure::Get(); - ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Struct, TEXT("Rotator"), RotatorStruct, /*bIsArray =*/false, /*bIsReference =*/false, /*bIsSet=*/false, /*bIsMap=*/false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); - ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Struct, TEXT("Rotator"), RotatorStruct, /*bIsArray =*/ true, /*bIsReference =*/false, /*bIsSet=*/false, /*bIsMap=*/false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); + ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Struct, TEXT("Rotator"), RotatorStruct, EPinContainerType::None, /*bIsReference =*/ false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); + ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Struct, TEXT("Rotator"), RotatorStruct, EPinContainerType::Array, /*bIsReference =*/ false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); UScriptStruct* TransformStruct = TBaseStructure::Get(); - ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Struct, TEXT("Transform"), TransformStruct, /*bIsArray =*/false, /*bIsReference =*/false, /*bIsSet=*/false, /*bIsMap=*/false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); - ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Struct, TEXT("Transform"), TransformStruct, /*bIsArray =*/ true, /*bIsReference =*/false, /*bIsSet=*/false, /*bIsMap=*/false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); + ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Struct, TEXT("Transform"), TransformStruct, EPinContainerType::None, /*bIsReference =*/ false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); + ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Struct, TEXT("Transform"), TransformStruct, EPinContainerType::Array, /*bIsReference =*/ false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); UScriptStruct* BlendSampleStruct = FindObjectChecked(ANY_PACKAGE, TEXT("BlendSampleData")); - ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Struct, TEXT("BlendSampleData"), BlendSampleStruct, /*bIsArray =*/false, /*bIsReference =*/false, /*bIsSet=*/false, /*bIsMap=*/false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); - ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Struct, TEXT("BlendSampleData"), BlendSampleStruct, /*bIsArray =*/ true, /*bIsReference =*/false, /*bIsSet=*/false, /*bIsMap=*/false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); + ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Struct, TEXT("BlendSampleData"), BlendSampleStruct, EPinContainerType::None, /*bIsReference =*/ false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); + ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Struct, TEXT("BlendSampleData"), BlendSampleStruct, EPinContainerType::Array, /*bIsReference =*/ false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/false)); // add persistent bool and int types (for macro graphs) - ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Int, TEXT(""), nullptr, /*bIsArray =*/false, /*bIsReference =*/false, /*bIsSet=*/false, /*bIsMap=*/false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/true)); - ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Boolean, TEXT(""), nullptr, /*bIsArray =*/false, /*bIsReference =*/false, /*bIsSet=*/false, /*bIsMap=*/false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/true)); + ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Int, FString(), nullptr, EPinContainerType::None, /*bIsReference =*/ false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/true)); + ActionRegistrar.AddBlueprintAction(ActionKey, MakeTempVarNodeSpawner(FEdGraphPinType(K2Schema->PC_Boolean, FString(), nullptr, EPinContainerType::None, /*bIsReference =*/ false, /*InValueTerminalType=*/FEdGraphTerminalType()), /*bIsPersistent =*/true)); } FText UK2Node_TemporaryVariable::GetMenuCategory() const diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Timeline.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Timeline.cpp index 7f7619ca3f63..0ec9b8c1a086 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Timeline.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Timeline.cpp @@ -64,21 +64,21 @@ void UK2Node_Timeline::AllocateDefaultPins() const UEdGraphSchema_K2* K2Schema = GetDefault(); bCanRenameNode = 1; - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, PlayPinName); - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, PlayFromStartPinName); - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, StopPinName); - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, ReversePinName); - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, ReverseFromEndPinName); + CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, PlayPinName); + CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, PlayFromStartPinName); + CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, StopPinName); + CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, ReversePinName); + CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, ReverseFromEndPinName); - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, UpdatePinName); - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, FinishedPinName); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, UpdatePinName); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, FinishedPinName); - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, SetNewTimePinName); + CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, SetNewTimePinName); - UEdGraphPin* NewPositionPin = CreatePin(EGPD_Input, K2Schema->PC_Float, TEXT(""), NULL, false, false, NewTimePinName); - NewPositionPin->DefaultValue = NewPositionPin->AutogeneratedDefaultValue = TEXT("0.0"); + UEdGraphPin* NewPositionPin = CreatePin(EGPD_Input, K2Schema->PC_Float, FString(), nullptr, NewTimePinName); + K2Schema->SetPinAutogeneratedDefaultValue(NewPositionPin, TEXT("0.0")); - CreatePin(EGPD_Output, K2Schema->PC_Byte, TEXT(""), FTimeline::GetTimelineDirectionEnum(), false, false, DirectionPinName); + CreatePin(EGPD_Output, K2Schema->PC_Byte, FString(), FTimeline::GetTimelineDirectionEnum(), DirectionPinName); UBlueprint* Blueprint = GetBlueprint(); check(Blueprint); @@ -92,27 +92,27 @@ void UK2Node_Timeline::AllocateDefaultPins() for(int32 i=0; iFloatTracks.Num(); i++) { FTTFloatTrack& FloatTrack = Timeline->FloatTracks[i]; - CreatePin(EGPD_Output, K2Schema->PC_Float, TEXT(""), NULL, false, false, FloatTrack.TrackName.ToString()); + CreatePin(EGPD_Output, K2Schema->PC_Float, FString(), nullptr, FloatTrack.TrackName.ToString()); } for(int32 i=0; iVectorTracks.Num(); i++) { FTTVectorTrack& VectorTrack = Timeline->VectorTracks[i]; UScriptStruct* VectorStruct = TBaseStructure::Get(); - CreatePin(EGPD_Output, K2Schema->PC_Struct, TEXT(""), VectorStruct, false, false, VectorTrack.TrackName.ToString()); + CreatePin(EGPD_Output, K2Schema->PC_Struct, FString(), VectorStruct, VectorTrack.TrackName.ToString()); } for(int32 i=0; iLinearColorTracks.Num(); i++) { FTTLinearColorTrack& LinearColorTrack = Timeline->LinearColorTracks[i]; UScriptStruct* LinearColorStruct = TBaseStructure::Get(); - CreatePin(EGPD_Output, K2Schema->PC_Struct, TEXT(""), LinearColorStruct, false, false, LinearColorTrack.TrackName.ToString()); + CreatePin(EGPD_Output, K2Schema->PC_Struct, FString(), LinearColorStruct, LinearColorTrack.TrackName.ToString()); } for(int32 i=0; iEventTracks.Num(); i++) { FTTEventTrack& EventTrack = Timeline->EventTracks[i]; - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, EventTrack.TrackName.ToString()); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, EventTrack.TrackName.ToString()); } // cache play status diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Tunnel.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Tunnel.cpp index 582e27eff6f9..254282812e5f 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Tunnel.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Tunnel.cpp @@ -189,8 +189,9 @@ UEdGraphPin* UK2Node_Tunnel::CreatePinFromUserDefinition(const TSharedPtrDesiredPinDirection; } + const UEdGraphSchema_K2* const Schema = GetDefault(); UEdGraphPin* Result = CreatePin(Direction, NewPinInfo->PinType, NewPinInfo->PinName); - Result->DefaultValue = Result->AutogeneratedDefaultValue = NewPinInfo->PinDefaultValue; + Schema->SetPinAutogeneratedDefaultValue(Result, NewPinInfo->PinDefaultValue); // Make sure it mirrors onto the associated node UEdGraphNode* TargetNode = ((InputSinkNode != NULL) ? InputSinkNode : OutputSourceNode); @@ -212,6 +213,18 @@ UEdGraphPin* UK2Node_Tunnel::CreatePinFromUserDefinition(const TSharedPtr PinInfo, const FString& NewDefaultValue) +{ + if (Super::ModifyUserDefinedPinDefaultValue(PinInfo, NewDefaultValue)) + { + const UEdGraphSchema_K2* K2Schema = GetDefault(); + K2Schema->HandleParameterDefaultValueChanged(this); + + return true; + } + return false; +} + bool UK2Node_Tunnel::CanModifyExecutionWires() { return true; diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_TunnelBoundary.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_TunnelBoundary.cpp index 14a78553ce29..7cc4516768f5 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_TunnelBoundary.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_TunnelBoundary.cpp @@ -109,7 +109,7 @@ void UK2Node_TunnelBoundary::CreateBoundaryNodesForTunnelInstance(UK2Node_Tunnel UEdGraphNode* TunnelExitNode = nullptr; TArray Tunnels; TunnelGraph->GetNodesOfClass(Tunnels); - for (auto TunnelNode : Tunnels) + for (UK2Node_Tunnel* TunnelNode : Tunnels) { if (IsPureTunnel(TunnelNode)) { @@ -139,12 +139,12 @@ void UK2Node_TunnelBoundary::CreateBoundaryNodesForTunnelInstance(UK2Node_Tunnel TArray VisitedPins; for (UEdGraphPin* EntryPin : TunnelEntryPins) { - UK2Node_TunnelBoundary* TunnelBoundaryNode = TunnelGraph->CreateBlankNode(); + UK2Node_TunnelBoundary* TunnelBoundaryNode = TunnelGraph->CreateIntermediateNode(); MessageLog.NotifyIntermediateObjectCreation(TunnelBoundaryNode, TunnelInstance); TunnelBoundaryNode->CreateNewGuid(); MessageLog.RegisterIntermediateTunnelNode(TunnelBoundaryNode, RegistrantTunnelInstance); TunnelBoundaryNode->WireUpTunnelEntry(TunnelInstance, EntryPin, MessageLog); - for (auto LinkedPin : EntryPin->LinkedTo) + for (UEdGraphPin* LinkedPin : EntryPin->LinkedTo) { FindTunnelExitSiteInstances(LinkedPin, ExecutionEndpointPins, VisitedPins, TunnelExitNode); } @@ -152,13 +152,13 @@ void UK2Node_TunnelBoundary::CreateBoundaryNodesForTunnelInstance(UK2Node_Tunnel if (ExecutionEndpointPins.Num()) { // Create boundary node. - UK2Node_TunnelBoundary* TunnelBoundaryNode = TunnelGraph->CreateBlankNode(); + UK2Node_TunnelBoundary* TunnelBoundaryNode = TunnelGraph->CreateIntermediateNode(); MessageLog.NotifyIntermediateObjectCreation(TunnelBoundaryNode, TunnelInstance); TunnelBoundaryNode->CreateNewGuid(); TunnelBoundaryNode->TunnelBoundaryType = TBT_EndOfThread; MessageLog.RegisterIntermediateTunnelNode(TunnelBoundaryNode, RegistrantTunnelInstance); // Create exit point pin - UEdGraphPin* BoundaryTerminalPin = TunnelBoundaryNode->CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Exec, TEXT(""), NULL, false, false, TEXT("TunnelEndOfThread")); + UEdGraphPin* BoundaryTerminalPin = TunnelBoundaryNode->CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Exec, FString(), nullptr, TEXT("TunnelEndOfThread")); // Wire up the endpoint unwired links to the boundary node. for (UEdGraphPin* TerminationPin : ExecutionEndpointPins) { @@ -167,7 +167,7 @@ void UK2Node_TunnelBoundary::CreateBoundaryNodesForTunnelInstance(UK2Node_Tunnel } for (UEdGraphPin* ExitPin : TunnelExitPins) { - UK2Node_TunnelBoundary* TunnelBoundaryNode = TunnelGraph->CreateBlankNode(); + UK2Node_TunnelBoundary* TunnelBoundaryNode = TunnelGraph->CreateIntermediateNode(); MessageLog.NotifyIntermediateObjectCreation(TunnelBoundaryNode, TunnelInstance); TunnelBoundaryNode->CreateNewGuid(); MessageLog.RegisterIntermediateTunnelNode(TunnelBoundaryNode, RegistrantTunnelInstance); @@ -184,7 +184,7 @@ void UK2Node_TunnelBoundary::CreateBoundariesForExpansionNodes(UEdGraphNode* Sou UEdGraph* TargetGraph = nullptr; TMap> EntryPins; TMap> ExitPins; - for (auto ExpansionNode : ExpansionNodes) + for (UEdGraphNode* ExpansionNode : ExpansionNodes) { if (!TargetGraph) { @@ -220,10 +220,10 @@ void UK2Node_TunnelBoundary::CreateBoundariesForExpansionNodes(UEdGraphNode* Sou { if (EntryPins.Num() > 0) { - for (auto PinEntry : EntryPins) + for (const auto& PinEntry : EntryPins) { // Create entry node and pins - UK2Node_TunnelBoundary* EntryBoundaryNode = TargetGraph->CreateBlankNode(); + UK2Node_TunnelBoundary* EntryBoundaryNode = TargetGraph->CreateIntermediateNode(); MessageLog.NotifyIntermediateObjectCreation(EntryBoundaryNode, SourceNode); EntryBoundaryNode->CreateNewGuid(); EntryBoundaryNode->WireUpEntry(SourceNode, PinEntry.Key, PinEntry.Value, MessageLog); @@ -231,10 +231,10 @@ void UK2Node_TunnelBoundary::CreateBoundariesForExpansionNodes(UEdGraphNode* Sou } if (ExitPins.Num() > 0) { - for (auto PinExit : ExitPins) + for (const auto& PinExit : ExitPins) { // Create exit node and pins - UK2Node_TunnelBoundary* ExitBoundaryNode = TargetGraph->CreateBlankNode(); + UK2Node_TunnelBoundary* ExitBoundaryNode = TargetGraph->CreateIntermediateNode(); MessageLog.NotifyIntermediateObjectCreation(ExitBoundaryNode, SourceNode); ExitBoundaryNode->CreateNewGuid(); ExitBoundaryNode->WireUpExit(SourceNode, PinExit.Key, PinExit.Value, MessageLog); @@ -259,12 +259,12 @@ void UK2Node_TunnelBoundary::WireUpTunnelEntry(UK2Node_Tunnel* TunnelInstance, U // Find the true source pin UEdGraphPin* SourcePin = TunnelInstance->FindPin(TunnelPin->PinName); // Wire in the node - UEdGraphPin* OutputPin = CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, TEXT(""), NULL, false, false, TEXT("TunnelEntryExec")); - for (auto LinkedPin : TunnelPin->LinkedTo) + UEdGraphPin* OutputPin = CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, FString(), nullptr, TEXT("TunnelEntryExec")); + for (UEdGraphPin* LinkedPin : TunnelPin->LinkedTo) { LinkedPin->MakeLinkTo(OutputPin); } - UEdGraphPin* InputPin = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Exec, TEXT(""), NULL, false, false, SourcePin->PinName); + UEdGraphPin* InputPin = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Exec, FString(), nullptr, SourcePin->PinName); MessageLog.NotifyIntermediatePinCreation(InputPin, SourcePin); TunnelPin->BreakAllPinLinks(); TunnelPin->MakeLinkTo(InputPin); @@ -282,19 +282,19 @@ void UK2Node_TunnelBoundary::WireUpTunnelExit(UK2Node_Tunnel* TunnelInstance, UE // Find the true source pin UEdGraphPin* SourcePin = TunnelInstance->FindPin(TunnelPin->PinName); // Wire in the node - UEdGraphPin* InputPin = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Exec, TEXT(""), NULL, false, false, SourcePin->PinName); - for (auto LinkedPin : TunnelPin->LinkedTo) + UEdGraphPin* InputPin = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Exec, FString(), nullptr, SourcePin->PinName); + for (UEdGraphPin* LinkedPin : TunnelPin->LinkedTo) { LinkedPin->MakeLinkTo(InputPin); } - UEdGraphPin* OutputPin = CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, TEXT(""), NULL, false, false, TEXT("TunnelExitExec")); + UEdGraphPin* OutputPin = CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, FString(), nullptr, TEXT("TunnelExitExec")); MessageLog.NotifyIntermediatePinCreation(OutputPin, SourcePin); TunnelPin->BreakAllPinLinks(); TunnelPin->MakeLinkTo(OutputPin); } } -void UK2Node_TunnelBoundary::WireUpEntry(UEdGraphNode* SourceNode, UEdGraphPin* SourcePin, TArray& EntryPins, FCompilerResultsLog& MessageLog) +void UK2Node_TunnelBoundary::WireUpEntry(UEdGraphNode* SourceNode, UEdGraphPin* SourcePin, const TArray& EntryPins, FCompilerResultsLog& MessageLog) { if (SourceNode && SourcePin && EntryPins.Num()) { @@ -303,13 +303,13 @@ void UK2Node_TunnelBoundary::WireUpEntry(UEdGraphNode* SourceNode, UEdGraphPin* // Create the pin base name CreateBaseNodeName(SourceNode); // Wire in the node - UEdGraphPin* InputPin = CreatePin(EGPD_Input, SourcePin->PinType.PinCategory, SourcePin->PinType.PinSubCategory, SourcePin->PinType.PinSubCategoryObject.Get(), SourcePin->PinType.bIsArray, SourcePin->PinType.bIsReference, TEXT("EntryBoundary"), SourcePin->PinType.bIsConst, INDEX_NONE, SourcePin->PinType.bIsSet, SourcePin->PinType.bIsMap, SourcePin->PinType.PinValueType); + UEdGraphPin* InputPin = CreatePin(EGPD_Input, SourcePin->PinType.PinCategory, SourcePin->PinType.PinSubCategory, SourcePin->PinType.PinSubCategoryObject.Get(), TEXT("EntryBoundary"), SourcePin->PinType.ContainerType, SourcePin->PinType.bIsReference, SourcePin->PinType.bIsConst, INDEX_NONE, SourcePin->PinType.PinValueType); MessageLog.NotifyIntermediatePinCreation(InputPin, SourcePin); - UEdGraphPin* OutputPin = CreatePin(EGPD_Output, SourcePin->PinType.PinCategory, SourcePin->PinType.PinSubCategory, SourcePin->PinType.PinSubCategoryObject.Get(), SourcePin->PinType.bIsArray, SourcePin->PinType.bIsReference, SourcePin->PinName, SourcePin->PinType.bIsConst, INDEX_NONE, SourcePin->PinType.bIsSet, SourcePin->PinType.bIsMap, SourcePin->PinType.PinValueType); + UEdGraphPin* OutputPin = CreatePin(EGPD_Output, SourcePin->PinType.PinCategory, SourcePin->PinType.PinSubCategory, SourcePin->PinType.PinSubCategoryObject.Get(), SourcePin->PinName, SourcePin->PinType.ContainerType, SourcePin->PinType.bIsReference, SourcePin->PinType.bIsConst, INDEX_NONE, SourcePin->PinType.PinValueType); MessageLog.AddPinTraceFilter(OutputPin); - for (auto EntryPin : EntryPins) + for (UEdGraphPin* EntryPin : EntryPins) { - for (auto LinkedPin : EntryPin->LinkedTo) + for (UEdGraphPin* LinkedPin : EntryPin->LinkedTo) { check (LinkedPin->Direction != InputPin->Direction); LinkedPin->MakeLinkTo(InputPin); @@ -321,7 +321,7 @@ void UK2Node_TunnelBoundary::WireUpEntry(UEdGraphNode* SourceNode, UEdGraphPin* } } -void UK2Node_TunnelBoundary::WireUpExit(UEdGraphNode* SourceNode, UEdGraphPin* SourcePin, TArray& ExitPins, FCompilerResultsLog& MessageLog) +void UK2Node_TunnelBoundary::WireUpExit(UEdGraphNode* SourceNode, UEdGraphPin* SourcePin, const TArray& ExitPins, FCompilerResultsLog& MessageLog) { if (SourceNode && SourcePin && ExitPins.Num()) { @@ -330,13 +330,13 @@ void UK2Node_TunnelBoundary::WireUpExit(UEdGraphNode* SourceNode, UEdGraphPin* S // Create the pin base name CreateBaseNodeName(SourceNode); // Wire in the node - UEdGraphPin* OutputPin = CreatePin(EGPD_Output, SourcePin->PinType.PinCategory, SourcePin->PinType.PinSubCategory, SourcePin->PinType.PinSubCategoryObject.Get(), SourcePin->PinType.bIsArray, SourcePin->PinType.bIsReference, SourcePin->PinName, SourcePin->PinType.bIsConst, INDEX_NONE, SourcePin->PinType.bIsSet, SourcePin->PinType.bIsMap, SourcePin->PinType.PinValueType); + UEdGraphPin* OutputPin = CreatePin(EGPD_Output, SourcePin->PinType.PinCategory, SourcePin->PinType.PinSubCategory, SourcePin->PinType.PinSubCategoryObject.Get(), SourcePin->PinName, SourcePin->PinType.ContainerType, SourcePin->PinType.bIsReference, SourcePin->PinType.bIsConst, INDEX_NONE, SourcePin->PinType.PinValueType); MessageLog.NotifyIntermediatePinCreation(OutputPin, SourcePin); - UEdGraphPin* InputPin = CreatePin(EGPD_Input, SourcePin->PinType.PinCategory, SourcePin->PinType.PinSubCategory, SourcePin->PinType.PinSubCategoryObject.Get(), SourcePin->PinType.bIsArray, SourcePin->PinType.bIsReference, TEXT("ExitBoundary"), SourcePin->PinType.bIsConst, INDEX_NONE, SourcePin->PinType.bIsSet, SourcePin->PinType.bIsMap, SourcePin->PinType.PinValueType); + UEdGraphPin* InputPin = CreatePin(EGPD_Input, SourcePin->PinType.PinCategory, SourcePin->PinType.PinSubCategory, SourcePin->PinType.PinSubCategoryObject.Get(), TEXT("ExitBoundary"), SourcePin->PinType.ContainerType, SourcePin->PinType.bIsReference, SourcePin->PinType.bIsConst, INDEX_NONE, SourcePin->PinType.PinValueType); MessageLog.AddPinTraceFilter(InputPin); - for (auto ExitPin : ExitPins) + for (UEdGraphPin* ExitPin : ExitPins) { - for (auto LinkedPin : ExitPin->LinkedTo) + for (UEdGraphPin* LinkedPin : ExitPin->LinkedTo) { check (LinkedPin->Direction != OutputPin->Direction); LinkedPin->MakeLinkTo(OutputPin); @@ -381,7 +381,7 @@ void UK2Node_TunnelBoundary::BuildSourceNodeMap(UEdGraphNode* Tunnel, TMapNodes) + for (UEdGraphNode* GraphNode : TunnelGraph->Nodes) { SourceNodeMap.Add(GraphNode->NodeGuid) = GraphNode; } @@ -410,7 +410,7 @@ UEdGraphNode* UK2Node_TunnelBoundary::FindTrueSourceTunnelInstance(UEdGraphNode* } if (TunnelGraph) { - for (auto GraphNode : TunnelGraph->Nodes) + for (UEdGraphNode* GraphNode : TunnelGraph->Nodes) { if (GraphNode->NodeGuid == Tunnel->NodeGuid) { @@ -445,7 +445,7 @@ void UK2Node_TunnelBoundary::FindTunnelExitSiteInstances(UEdGraphPin* NodeEntryP // Find all exec out pins TArray ExecPins; TArray ConnectedExecPins; - for (auto Pin : PinNode->Pins) + for (UEdGraphPin* Pin : PinNode->Pins) { if (Pin->Direction == EGPD_Output && Pin->PinType.PinCategory == UEdGraphSchema_K2::PC_Exec) { @@ -458,11 +458,10 @@ void UK2Node_TunnelBoundary::FindTunnelExitSiteInstances(UEdGraphPin* NodeEntryP } if (ConnectedExecPins.Num() > 1) { -// if (FEdGraphUtilities::IsExecutionSequence(PinNode)) if (PinNode->IsA()) { // Execution sequence style nodes, follow the last connected pin - for (auto LinkedPin : ConnectedExecPins.Last()->LinkedTo) + for (UEdGraphPin* LinkedPin : ConnectedExecPins.Last()->LinkedTo) { FindTunnelExitSiteInstances(LinkedPin, ExitPins, VisitedPins); } @@ -470,9 +469,9 @@ void UK2Node_TunnelBoundary::FindTunnelExitSiteInstances(UEdGraphPin* NodeEntryP else { // Branch style nodes, more tricky - for (auto ExecPin : ConnectedExecPins) + for (UEdGraphPin* ExecPin : ConnectedExecPins) { - for (auto LinkedPin : ExecPin->LinkedTo) + for (UEdGraphPin* LinkedPin : ExecPin->LinkedTo) { FindTunnelExitSiteInstances(LinkedPin, ExitPins, VisitedPins); } @@ -481,7 +480,7 @@ void UK2Node_TunnelBoundary::FindTunnelExitSiteInstances(UEdGraphPin* NodeEntryP } else if (ConnectedExecPins.Num() == 1) { - for (auto LinkedPin : ConnectedExecPins[0]->LinkedTo) + for (UEdGraphPin* LinkedPin : ConnectedExecPins[0]->LinkedTo) { FindTunnelExitSiteInstances(LinkedPin, ExitPins, VisitedPins); } diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Variable.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Variable.cpp index d1ae4b9ca0aa..6b65f6bebdc1 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Variable.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_Variable.cpp @@ -85,13 +85,13 @@ bool UK2Node_Variable::CreatePinForVariable(EEdGraphPinDirection Direction, FStr } } - if (VariableProperty != NULL) + if (VariableProperty != nullptr) { const FString PinName = InPinName.IsEmpty()? GetVarNameString() : InPinName; // Create the pin - UEdGraphPin* VariablePin = CreatePin(Direction, TEXT(""), TEXT(""), NULL, false, false, PinName); + UEdGraphPin* VariablePin = CreatePin(Direction, FString(), FString(), nullptr, PinName); K2Schema->ConvertPropertyToPinType(VariableProperty, /*out*/ VariablePin->PinType); - K2Schema->SetPinDefaultValueBasedOnType(VariablePin); + K2Schema->SetPinAutogeneratedDefaultValueBasedOnType(VariablePin); } else { @@ -159,7 +159,7 @@ void UK2Node_Variable::CreatePinForSelf() TargetClass = TargetClass->GetAuthoritativeClass(); } - UEdGraphPin* TargetPin = CreatePin(EGPD_Input, K2Schema->PC_Object, TEXT(""), TargetClass, false, false, K2Schema->PN_Self); + UEdGraphPin* TargetPin = CreatePin(EGPD_Input, K2Schema->PC_Object, FString(), TargetClass, K2Schema->PN_Self); TargetPin->PinFriendlyName = LOCTEXT("Target", "Target"); if (bSelfTarget) @@ -194,14 +194,14 @@ bool UK2Node_Variable::RecreatePinForVariable(EEdGraphPinDirection Direction, TA } } - if(NULL != OldVariablePin) + if(nullptr != OldVariablePin) { // create new pin from old one - UEdGraphPin* VariablePin = CreatePin(Direction, TEXT(""), TEXT(""), NULL, false, false, PinName); + UEdGraphPin* VariablePin = CreatePin(Direction, FString(), FString(), nullptr, PinName); VariablePin->PinType = OldVariablePin->PinType; const UEdGraphSchema_K2* K2Schema = GetDefault(); - K2Schema->SetPinDefaultValueBasedOnType(VariablePin); + K2Schema->SetPinAutogeneratedDefaultValueBasedOnType(VariablePin); Message_Note(*FString::Printf(TEXT("Pin for variable '%s' recreated, but the variable is missing."), *PinName)); return true; @@ -515,11 +515,20 @@ FSlateIcon UK2Node_Variable::GetVarIconFromPinType(const FEdGraphPinType& InPinT const UEdGraphSchema_K2* K2Schema = GetDefault(); IconColorOut = K2Schema->GetPinTypeColor(InPinType); - if(InPinType.bIsArray) + if (InPinType.IsArray()) { return FSlateIcon("EditorStyle", "Kismet.AllClasses.ArrayVariableIcon"); } - else if(InPinType.PinSubCategoryObject.IsValid()) + else if (InPinType.IsSet()) + { + return FSlateIcon("EditorStyle", "Kismet.AllClasses.SetVariableIcon"); + } + else if (InPinType.IsMap()) + { + // TODO: Need to properly deal with Key/Value stuff + return FSlateIcon("EditorStyle", "Kismet.AllClasses.MapVariableKeyIcon"); + } + else if (InPinType.PinSubCategoryObject.IsValid()) { if(UClass* Class = Cast(InPinType.PinSubCategoryObject.Get())) { diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_VariableGet.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_VariableGet.cpp index 80af399754fb..12b386319770 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_VariableGet.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_VariableGet.cpp @@ -132,13 +132,13 @@ void UK2Node_VariableGet::CreateNonPurePins(TArray* InOldPinsPtr) if (IsValidTypeForNonPure(PinType)) { // Input - Execution Pin - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Execute); + CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Execute); // Output - Execution Pins - UEdGraphPin* ValidPin = CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Then); + UEdGraphPin* ValidPin = CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Then); ValidPin->PinFriendlyName = LOCTEXT("Valid", "Is Valid"); - UEdGraphPin* InvalidPin = CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Else); + UEdGraphPin* InvalidPin = CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Else); InvalidPin->PinFriendlyName = LOCTEXT("Invalid", "Is Not Valid"); } else @@ -320,7 +320,7 @@ FNodeHandlingFunctor* UK2Node_VariableGet::CreateNodeHandler(FKismetCompilerCont bool UK2Node_VariableGet::IsValidTypeForNonPure(const FEdGraphPinType& InPinType) { - return InPinType.bIsArray == false && (InPinType.PinCategory == UObject::StaticClass()->GetName() ||InPinType.PinCategory == UClass::StaticClass()->GetName()); + return !InPinType.IsContainer() && (InPinType.PinCategory == UObject::StaticClass()->GetName() ||InPinType.PinCategory == UClass::StaticClass()->GetName()); } void UK2Node_VariableGet::GetContextMenuActions(const FGraphNodeContextMenuBuilder& Context) const @@ -411,19 +411,22 @@ void UK2Node_VariableGet::ExpandNode(class FKismetCompilerContext& CompilerConte { Super::ExpandNode(CompilerContext, SourceGraph); + UProperty* VariableProperty = GetPropertyForVariable(); + + UK2Node_VariableGet* VariableGetNode = this; + // Do not attempt to expand the node when not a pure get nor when there is no property. Normal compilation error detection will detect the missing property. - if (!bIsPureGet && GetPropertyForVariable() != nullptr) + if (!bIsPureGet && VariableProperty) { - const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema(); UEdGraphPin* ValuePin = GetValuePin(); // Impure Get nodes convert into three nodes: // 1. A pure Get node // 2. An IsValid node - // 3. A Branch node (only impure part + // 3. A Branch node (only impure part) - // Create the impure Get node - UK2Node_VariableGet* VariableGetNode = CompilerContext.SpawnIntermediateNode(this, SourceGraph); + // Create the pure Get node + VariableGetNode = CompilerContext.SpawnIntermediateNode(this, SourceGraph); VariableGetNode->VariableReference = VariableReference; VariableGetNode->AllocateDefaultPins(); CompilerContext.MessageLog.NotifyIntermediateObjectCreation(VariableGetNode, this); @@ -432,7 +435,7 @@ void UK2Node_VariableGet::ExpandNode(class FKismetCompilerContext& CompilerConte CompilerContext.MovePinLinksToIntermediate(*ValuePin, *VariableGetNode->GetValuePin()); if (!VariableReference.IsLocalScope()) { - CompilerContext.MovePinLinksToIntermediate(*FindPin(Schema->PN_Self), *VariableGetNode->FindPin(Schema->PN_Self)); + CompilerContext.MovePinLinksToIntermediate(*FindPin(UEdGraphSchema_K2::PN_Self), *VariableGetNode->FindPin(UEdGraphSchema_K2::PN_Self)); } // Create the IsValid node @@ -469,11 +472,35 @@ void UK2Node_VariableGet::ExpandNode(class FKismetCompilerContext& CompilerConte CompilerContext.MovePinLinksToIntermediate(*GetExecPin(), *BranchNode->GetExecPin()); // Move the two Branch pins to the Branch node - CompilerContext.MovePinLinksToIntermediate(*FindPin(Schema->PN_Then), *BranchNode->FindPin(Schema->PN_Then)); - CompilerContext.MovePinLinksToIntermediate(*FindPin(Schema->PN_Else), *BranchNode->FindPin(Schema->PN_Else)); + CompilerContext.MovePinLinksToIntermediate(*FindPin(UEdGraphSchema_K2::PN_Then), *BranchNode->FindPin(UEdGraphSchema_K2::PN_Then)); + CompilerContext.MovePinLinksToIntermediate(*FindPin(UEdGraphSchema_K2::PN_Else), *BranchNode->FindPin(UEdGraphSchema_K2::PN_Else)); BreakAllNodeLinks(); } + + // If property has a BlueprintGetter accessor, then replace the variable get node with a call function + if (VariableProperty) + { + const FString& GetFunctionName = VariableProperty->GetMetaData(FBlueprintMetadata::MD_PropertyGetFunction); + if (!GetFunctionName.IsEmpty()) + { + UClass* OwnerClass = VariableProperty->GetOwnerClass(); + UFunction* GetFunction = OwnerClass->FindFunctionByName(*GetFunctionName); + check(GetFunction); + + UK2Node_CallFunction* CallFuncNode = CompilerContext.SpawnIntermediateNode(this, SourceGraph); + CallFuncNode->SetFromFunction(GetFunction); + CallFuncNode->AllocateDefaultPins(); + + const UEdGraphSchema_K2* K2Schema = CompilerContext.GetSchema(); + + // Move Self pin connections + CompilerContext.MovePinLinksToIntermediate(*K2Schema->FindSelfPin(*this, EGPD_Input), *K2Schema->FindSelfPin(*CallFuncNode, EGPD_Input)); + + // Move Value pin connections + CompilerContext.MovePinLinksToIntermediate(*GetValuePin(), *CallFuncNode->GetReturnValuePin()); + } + } } void UK2Node_VariableGet::Serialize(FArchive& Ar) diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_VariableSet.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_VariableSet.cpp index cca0f88a2a82..71439b9cd203 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_VariableSet.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_VariableSet.cpp @@ -6,6 +6,7 @@ #include "Engine/BlueprintGeneratedClass.h" #include "EdGraphSchema_K2.h" #include "K2Node_VariableGet.h" +#include "K2Node_CallFunction.h" #include "Kismet2/BlueprintEditorUtils.h" #include "KismetCompiler.h" #include "VariableSetHandler.h" @@ -80,10 +81,8 @@ UK2Node_VariableSet::UK2Node_VariableSet(const FObjectInitializer& ObjectInitial void UK2Node_VariableSet::AllocateDefaultPins() { - const UEdGraphSchema_K2* K2Schema = GetDefault(); - - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Execute); - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Then); + CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Exec, FString(), nullptr, UEdGraphSchema_K2::PN_Execute); + CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, FString(), nullptr, UEdGraphSchema_K2::PN_Then); if (GetVarName() != NAME_None) { @@ -103,10 +102,8 @@ void UK2Node_VariableSet::AllocateDefaultPins() void UK2Node_VariableSet::ReallocatePinsDuringReconstruction(TArray& OldPins) { - const UEdGraphSchema_K2* K2Schema = GetDefault(); - - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Execute); - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Then); + CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Exec, FString(), nullptr, UEdGraphSchema_K2::PN_Execute); + CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, FString(), nullptr, UEdGraphSchema_K2::PN_Then); if (GetVarName() != NAME_None) { @@ -342,8 +339,7 @@ void UK2Node_VariableSet::CreateOutputPinTooltip() FText UK2Node_VariableSet::GetPinNameOverride(const UEdGraphPin& Pin) const { // Stop the output pin for the variable, effectively the "get" pin, from displaying a name. - const UEdGraphSchema_K2* K2Schema = GetDefault(); - if(Pin.ParentPin == nullptr && (Pin.Direction == EGPD_Output || Pin.PinType.PinCategory == K2Schema->PC_Exec)) + if(Pin.ParentPin == nullptr && (Pin.Direction == EGPD_Output || Pin.PinType.PinCategory == UEdGraphSchema_K2::PC_Exec)) { return FText::GetEmpty(); } @@ -357,37 +353,75 @@ void UK2Node_VariableSet::ExpandNode(class FKismetCompilerContext& CompilerConte if (CompilerContext.bIsFullCompile) { + UProperty* VariableProperty = GetPropertyForVariable(); + const UEdGraphSchema_K2* K2Schema = CompilerContext.GetSchema(); - UEdGraphPin* Pin = FindPin(GetVariableOutputPinName()); - if(Pin) + if (UEdGraphPin* VariableGetPin = FindPin(GetVariableOutputPinName())) { // If the output pin is linked, we need to spawn a separate "Get" node and hook it up. - if(Pin->LinkedTo.Num()) + if (VariableGetPin->LinkedTo.Num()) { - UProperty* VariableProperty = GetPropertyForVariable(); - - if(VariableProperty) + if (VariableProperty) { UK2Node_VariableGet* VariableGetNode = CompilerContext.SpawnIntermediateNode(this, SourceGraph); VariableGetNode->VariableReference = VariableReference; VariableGetNode->AllocateDefaultPins(); CompilerContext.MessageLog.NotifyIntermediateObjectCreation(VariableGetNode, this); - CompilerContext.MovePinLinksToIntermediate(*Pin, *VariableGetNode->FindPin(GetVarNameString())); + CompilerContext.MovePinLinksToIntermediate(*VariableGetPin, *VariableGetNode->FindPin(GetVarNameString())); // Duplicate the connection to the self pin. UEdGraphPin* SetSelfPin = K2Schema->FindSelfPin(*this, EGPD_Input); UEdGraphPin* GetSelfPin = K2Schema->FindSelfPin(*VariableGetNode, EGPD_Input); - if(SetSelfPin && GetSelfPin) + if (SetSelfPin && GetSelfPin) { CompilerContext.CopyPinLinksToIntermediate(*SetSelfPin, *GetSelfPin); } } } - Pins.Remove(Pin); - Pin->MarkPendingKill(); + Pins.Remove(VariableGetPin); + VariableGetPin->MarkPendingKill(); + } + + // If property has a BlueprintSetter accessor, then replace the variable get node with a call function + if (VariableProperty) + { + const FString& SetFunctionName = VariableProperty->GetMetaData(FBlueprintMetadata::MD_PropertySetFunction); + if (!SetFunctionName.IsEmpty()) + { + UClass* OwnerClass = VariableProperty->GetOwnerClass(); + UFunction* SetFunction = OwnerClass->FindFunctionByName(*SetFunctionName); + check(SetFunction); + + UK2Node_CallFunction* CallFuncNode = CompilerContext.SpawnIntermediateNode(this, SourceGraph); + CallFuncNode->SetFromFunction(SetFunction); + CallFuncNode->AllocateDefaultPins(); + + // Move Exec pin connections + CompilerContext.MovePinLinksToIntermediate(*GetExecPin(), *CallFuncNode->GetExecPin()); + + // Move Then pin connections + CompilerContext.MovePinLinksToIntermediate(*FindPinChecked(UEdGraphSchema_K2::PN_Then, EGPD_Output), *CallFuncNode->GetThenPin()); + + // Move Self pin connections + CompilerContext.MovePinLinksToIntermediate(*K2Schema->FindSelfPin(*this, EGPD_Input), *K2Schema->FindSelfPin(*CallFuncNode, EGPD_Input)); + + // Move Value pin connections + UEdGraphPin* SetFunctionValuePin = nullptr; + for (UEdGraphPin* CallFuncPin : CallFuncNode->Pins) + { + if (!K2Schema->IsMetaPin(*CallFuncPin)) + { + check(CallFuncPin->Direction == EGPD_Input); + SetFunctionValuePin = CallFuncPin; + break; + } + } + check(SetFunctionValuePin); + + CompilerContext.MovePinLinksToIntermediate(*FindPin(GetVarNameString(), EGPD_Input), *SetFunctionValuePin); + } } - } } diff --git a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_VariableSetRef.cpp b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_VariableSetRef.cpp index f5d2cfa0ef42..70c78d5a1691 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/K2Node_VariableSetRef.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/K2Node_VariableSetRef.cpp @@ -93,11 +93,11 @@ void UK2Node_VariableSetRef::AllocateDefaultPins() { const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Execute); - CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Then); + CreatePin(EGPD_Input, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Execute); + CreatePin(EGPD_Output, K2Schema->PC_Exec, FString(), nullptr, K2Schema->PN_Then); - CreatePin(EGPD_Input, K2Schema->PC_Wildcard, TEXT(""), NULL, false, true, TargetVarPinName); - UEdGraphPin* ValuePin = CreatePin(EGPD_Input, K2Schema->PC_Wildcard, TEXT(""), NULL, false, false, VarValuePinName); + CreatePin(EGPD_Input, K2Schema->PC_Wildcard, FString(), nullptr, TargetVarPinName, EPinContainerType::None, true); + UEdGraphPin* ValuePin = CreatePin(EGPD_Input, K2Schema->PC_Wildcard, FString(), nullptr, VarValuePinName); } void UK2Node_VariableSetRef::ReallocatePinsDuringReconstruction(TArray& OldPins) @@ -192,7 +192,7 @@ void UK2Node_VariableSetRef::CoerceTypeFromPin(const UEdGraphPin* Pin) if( Pin ) { - check((Pin != TargetPin) || (Pin->PinType.bIsReference && !Pin->PinType.bIsArray)); + check((Pin != TargetPin) || (Pin->PinType.bIsReference && !Pin->PinType.IsContainer())); TargetPin->PinType = Pin->PinType; TargetPin->PinType.bIsReference = true; @@ -204,13 +204,13 @@ void UK2Node_VariableSetRef::CoerceTypeFromPin(const UEdGraphPin* Pin) { // Pin disconnected...revert to wildcard TargetPin->PinType.PinCategory = K2Schema->PC_Wildcard; - TargetPin->PinType.PinSubCategory = TEXT(""); - TargetPin->PinType.PinSubCategoryObject = NULL; + TargetPin->PinType.PinSubCategory.Reset(); + TargetPin->PinType.PinSubCategoryObject = nullptr; TargetPin->BreakAllPinLinks(); ValuePin->PinType.PinCategory = K2Schema->PC_Wildcard; - ValuePin->PinType.PinSubCategory = TEXT(""); - ValuePin->PinType.PinSubCategoryObject = NULL; + ValuePin->PinType.PinSubCategory.Reset(); + ValuePin->PinType.PinSubCategoryObject = nullptr; ValuePin->BreakAllPinLinks(); CachedNodeTitle.MarkDirty(); diff --git a/Engine/Source/Editor/BlueprintGraph/Private/MathExpressionHandler.cpp b/Engine/Source/Editor/BlueprintGraph/Private/MathExpressionHandler.cpp index 1edc1e8c4a9d..b1a70f1072bf 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/MathExpressionHandler.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/MathExpressionHandler.cpp @@ -14,7 +14,7 @@ struct KCHandler_MathExpressionHelper { - static bool CreateMap(UEdGraphNode& KeyNode, UEdGraphNode& ValueNode, EEdGraphPinDirection KeyPinDirection, UEdGraphSchema_K2* Schema, TMap& OutMap) + static bool CreateMap(UEdGraphNode& KeyNode, UEdGraphNode& ValueNode, EEdGraphPinDirection KeyPinDirection, const UEdGraphSchema_K2* Schema, TMap& OutMap) { check(Schema); for (auto InnerInputPin : KeyNode.Pins) @@ -69,12 +69,11 @@ FBlueprintCompiledStatement* FKCHandler_MathExpression::GenerateFunctionRPN(UEdG return nullptr; } - FBlueprintCompiledStatement* NewDetachedStatement = new FBlueprintCompiledStatement(); - FBlueprintCompiledStatement& Statement = *NewDetachedStatement; - Statement.FunctionToCall = Function; - Statement.FunctionContext = nullptr; - Statement.Type = KCST_CallFunction; - Statement.LHS = ResultTerm; // required only for the first node + FBlueprintCompiledStatement* Statement = new FBlueprintCompiledStatement(); + Statement->FunctionToCall = Function; + Statement->FunctionContext = nullptr; + Statement->Type = KCST_CallFunction; + Statement->LHS = ResultTerm; // required only for the first node check(CallFunctionNode); @@ -138,8 +137,8 @@ FBlueprintCompiledStatement* FKCHandler_MathExpression::GenerateFunctionRPN(UEdG } } } - Statement.RHS = RHSTerms; - return &Statement; + Statement->RHS = RHSTerms; + return Statement; } void FKCHandler_MathExpression::RegisterNets(FKismetFunctionContext& Context, UEdGraphNode* InNode) diff --git a/Engine/Source/Editor/BlueprintGraph/Private/VariableSetHandler.cpp b/Engine/Source/Editor/BlueprintGraph/Private/VariableSetHandler.cpp index 8a996ccc97a1..20e5dc74eea8 100644 --- a/Engine/Source/Editor/BlueprintGraph/Private/VariableSetHandler.cpp +++ b/Engine/Source/Editor/BlueprintGraph/Private/VariableSetHandler.cpp @@ -156,7 +156,7 @@ void FKCHandler_VariableSet::Transform(FKismetFunctionContext& Context, UEdGraph if (SetNotify->ShouldFlushDormancyOnSet()) { // Create CallFuncNode - UK2Node_CallFunction* CallFuncNode = Node->GetGraph()->CreateBlankNode(); + UK2Node_CallFunction* CallFuncNode = Node->GetGraph()->CreateIntermediateNode(); CallFuncNode->FunctionReference.SetExternalMember(NAME_FlushNetDormancy, AActor::StaticClass() ); CallFuncNode->AllocateDefaultPins(); @@ -180,7 +180,7 @@ void FKCHandler_VariableSet::Transform(FKismetFunctionContext& Context, UEdGraph if (SetNotify->HasLocalRepNotify()) { - UK2Node_CallFunction* CallFuncNode = Node->GetGraph()->CreateBlankNode(); + UK2Node_CallFunction* CallFuncNode = Node->GetGraph()->CreateIntermediateNode(); CallFuncNode->FunctionReference.SetExternalMember(SetNotify->GetRepNotifyName(), SetNotify->GetVariableSourceClass() ); CallFuncNode->AllocateDefaultPins(); diff --git a/Engine/Source/Editor/BlueprintGraph/Public/BlueprintActionFilter.h b/Engine/Source/Editor/BlueprintGraph/Public/BlueprintActionFilter.h index 83fc508d39d2..39691d143bd3 100644 --- a/Engine/Source/Editor/BlueprintGraph/Public/BlueprintActionFilter.h +++ b/Engine/Source/Editor/BlueprintGraph/Public/BlueprintActionFilter.h @@ -134,7 +134,7 @@ struct BLUEPRINTGRAPH_API FBlueprintActionInfo private: /** The class or asset-object that the NodeSpawner action is keyed to (in the action database)*/ - UObject const* ActionOwner; + const TWeakObjectPtr ActionOwner; /** Keeps track of the fields we've cached (needed in case one turns out to be null) */ uint32 CacheFlags; diff --git a/Engine/Source/Editor/Blutility/Classes/GlobalEditorUtilityBase.h b/Engine/Source/Editor/Blutility/Classes/GlobalEditorUtilityBase.h index dfa33aa0881d..555f0dd9411f 100644 --- a/Engine/Source/Editor/Blutility/Classes/GlobalEditorUtilityBase.h +++ b/Engine/Source/Editor/Blutility/Classes/GlobalEditorUtilityBase.h @@ -30,6 +30,9 @@ class BLUTILITY_API UGlobalEditorUtilityBase : public UObject UPROPERTY(Transient) bool bDirtiedSelectionSet; + /** UObject interface */ + virtual UWorld* GetWorld() const override; + UFUNCTION(BlueprintCallable, Category="Development|Editor") TArray GetSelectionSet(); diff --git a/Engine/Source/Editor/Blutility/Private/BlutilityDetailsPanel.cpp b/Engine/Source/Editor/Blutility/Private/BlutilityDetailsPanel.cpp index 1ed868794db0..39b556d977e3 100644 --- a/Engine/Source/Editor/Blutility/Private/BlutilityDetailsPanel.cpp +++ b/Engine/Source/Editor/Blutility/Private/BlutilityDetailsPanel.cpp @@ -150,6 +150,8 @@ FReply FEditorUtilityInstanceDetails::OnExecuteAction(TWeakObjectPtr { if (UFunction* Function = WeakFunctionPtr.Get()) { + // @todo Editor Scripting - This should not be called here. Internal operations may have transactions created and this prevents them from being created. + // Also if the blutility opens a level or similar, the transaction buffer gets reset because there is an active transaction on level load. FScopedTransaction Transaction( NSLOCTEXT("UnrealEd", "BlutilityAction", "Blutility Action") ); FEditorScriptExecutionGuard ScriptGuard; diff --git a/Engine/Source/Editor/Blutility/Private/GlobalEditorUtilityBase.cpp b/Engine/Source/Editor/Blutility/Private/GlobalEditorUtilityBase.cpp index 4a15409ad304..5bf2939ead9f 100644 --- a/Engine/Source/Editor/Blutility/Private/GlobalEditorUtilityBase.cpp +++ b/Engine/Source/Editor/Blutility/Private/GlobalEditorUtilityBase.cpp @@ -21,6 +21,11 @@ UGlobalEditorUtilityBase::UGlobalEditorUtilityBase(const FObjectInitializer& Obj { } +UWorld* UGlobalEditorUtilityBase::GetWorld() const +{ + return GEditor->GetEditorWorldContext().World(); +} + TArray UGlobalEditorUtilityBase::GetSelectionSet() { TArray Result; diff --git a/Engine/Source/Editor/Cascade/Private/Cascade.cpp b/Engine/Source/Editor/Cascade/Private/Cascade.cpp index c5fa2732001f..dff0ef4bbd4c 100644 --- a/Engine/Source/Editor/Cascade/Private/Cascade.cpp +++ b/Engine/Source/Editor/Cascade/Private/Cascade.cpp @@ -1588,7 +1588,7 @@ void FCascade::Tick(float DeltaTime) Position.X = MotionModeRadius * FMath::Sin(AccumulatedMotionTime); Position.Y = MotionModeRadius * FMath::Cos(AccumulatedMotionTime); Position.Z = 0.0f; - ParticleSystemComponent->ComponentToWorld = FTransform(Position); + ParticleSystemComponent->SetComponentToWorld(FTransform(Position)); } if (ParticleSystemComponent->IsComponentTickEnabled()) @@ -2436,6 +2436,22 @@ void FCascade::BindCommands() Commands.DeleteLOD, FExecuteAction::CreateSP(this, &FCascade::OnDeleteLOD)); + ToolkitCommands->MapAction( + Commands.JumpToLOD0, + FExecuteAction::CreateSP(this, &FCascade::OnJumpToLODIndex, 0)); + + ToolkitCommands->MapAction( + Commands.JumpToLOD1, + FExecuteAction::CreateSP(this, &FCascade::OnJumpToLODIndex, 1)); + + ToolkitCommands->MapAction( + Commands.JumpToLOD2, + FExecuteAction::CreateSP(this, &FCascade::OnJumpToLODIndex, 2)); + + ToolkitCommands->MapAction( + Commands.JumpToLOD3, + FExecuteAction::CreateSP(this, &FCascade::OnJumpToLODIndex, 3)); + ToolkitCommands->MapAction( Commands.DeleteModule, FExecuteAction::CreateSP(this, &FCascade::OnDeleteModule, true)); @@ -3445,6 +3461,9 @@ void FCascade::AddLOD(bool bBeforeCurrent) } } + //This should probably have fixed size and behave like LODDistances but for now just avoid the crash. + ParticleSystem->LODSettings.SetNumZeroed(FMath::Max(CurrentLODIndex, ParticleSystem->LODSettings.Num())); + ParticleSystem->LODDistances.InsertZeroed(CurrentLODIndex, 1); if (CurrentLODIndex == 0) { @@ -4289,7 +4308,30 @@ void FCascade::OnJumpToHighestLOD() SetLODValue(Value); SetSelectedModule(SelectedEmitter, SelectedModule); - + + if (PreviewViewport.IsValid()) + { + PreviewViewport->RefreshViewport(); + } + + if (EmitterCanvas.IsValid()) + { + EmitterCanvas->RefreshViewport(); + } +} + +void FCascade::OnJumpToLODIndex(int32 LODLevel) +{ + if (ParticleSystem->Emitters.Num() == 0) + { + return; + } + + int32 Value = FMath::Clamp(LODLevel, 0, ParticleSystem->Emitters[0]->LODLevels.Num() - 1); + + SetLODValue(Value); + SetSelectedModule(SelectedEmitter, SelectedModule); + if (PreviewViewport.IsValid()) { PreviewViewport->RefreshViewport(); diff --git a/Engine/Source/Editor/Cascade/Private/Cascade.h b/Engine/Source/Editor/Cascade/Private/Cascade.h index e90a7978e94e..98f000a36a0f 100644 --- a/Engine/Source/Editor/Cascade/Private/Cascade.h +++ b/Engine/Source/Editor/Cascade/Private/Cascade.h @@ -370,6 +370,7 @@ private: void OnAddLODBeforeCurrent(); void OnJumpToLowestLOD(); void OnDeleteLOD(); + void OnJumpToLODIndex(int32 LODLevel); void OnRefreshModule(); void OnSyncMaterial(); void OnUseMaterial(); diff --git a/Engine/Source/Editor/Cascade/Private/CascadeActions.cpp b/Engine/Source/Editor/Cascade/Private/CascadeActions.cpp index d38935d41b05..f43aefb3f04f 100644 --- a/Engine/Source/Editor/Cascade/Private/CascadeActions.cpp +++ b/Engine/Source/Editor/Cascade/Private/CascadeActions.cpp @@ -26,6 +26,10 @@ void FCascadeCommands::RegisterCommands() UI_COMMAND(JumpToLowerLOD, "Lower LOD", "Select Lower LOD", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(JumpToLowestLOD, "Lowest LOD", "Select Lowest LOD", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(DeleteLOD, "Delete LOD", "Delete Selected LOD", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(JumpToLOD0, "Jump To LOD0", "LOD0", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Control, EKeys::M)); + UI_COMMAND(JumpToLOD1, "Jump To LOD1", "LOD1", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Control, EKeys::Comma)); + UI_COMMAND(JumpToLOD2, "Jump To LOD2", "LOD2", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Control, EKeys::Period)); + UI_COMMAND(JumpToLOD3, "Jump To LOD3", "LOD3", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Control, EKeys::Slash)); UI_COMMAND(ToggleOriginAxis, "Origin Axis", "Display Origin Axis", EUserInterfaceActionType::ToggleButton, FInputChord()); UI_COMMAND(View_ParticleCounts, "Particle Counts", "Display Particle Counts", EUserInterfaceActionType::ToggleButton, FInputChord()); diff --git a/Engine/Source/Editor/Cascade/Private/CascadeActions.h b/Engine/Source/Editor/Cascade/Private/CascadeActions.h index fa23771a02e1..6e79ff22bfae 100644 --- a/Engine/Source/Editor/Cascade/Private/CascadeActions.h +++ b/Engine/Source/Editor/Cascade/Private/CascadeActions.h @@ -70,6 +70,10 @@ public: TSharedPtr AddLODBeforeCurrent; TSharedPtr JumpToLowerLOD; TSharedPtr JumpToLowestLOD; + TSharedPtr JumpToLOD0; + TSharedPtr JumpToLOD1; + TSharedPtr JumpToLOD2; + TSharedPtr JumpToLOD3; TSharedPtr DeleteLOD; TSharedPtr DeleteModule; TSharedPtr RefreshModule; diff --git a/Engine/Source/Editor/Cascade/Private/CascadeEmitterCanvasClient.cpp b/Engine/Source/Editor/Cascade/Private/CascadeEmitterCanvasClient.cpp index 98a7f035c843..931dd718845f 100644 --- a/Engine/Source/Editor/Cascade/Private/CascadeEmitterCanvasClient.cpp +++ b/Engine/Source/Editor/Cascade/Private/CascadeEmitterCanvasClient.cpp @@ -1802,12 +1802,9 @@ TSharedRef FCascadeEmitterCanvasClient::BuildMenuWidgetModule() if (CurrLODLevel > 0) { bool bAddDuplicateOptions = true; - if (SelectedModule) + if (CascadePtr.Pin()->GetIsModuleShared(SelectedModule) == true) { - if (CascadePtr.Pin()->GetIsModuleShared(SelectedModule) == true) - { - bAddDuplicateOptions = false; - } + bAddDuplicateOptions = false; } if (bAddDuplicateOptions == true) diff --git a/Engine/Source/Editor/ClassViewer/Private/SClassViewer.cpp b/Engine/Source/Editor/ClassViewer/Private/SClassViewer.cpp index 094539df118a..f1d52d3ef254 100644 --- a/Engine/Source/Editor/ClassViewer/Private/SClassViewer.cpp +++ b/Engine/Source/Editor/ClassViewer/Private/SClassViewer.cpp @@ -2662,8 +2662,7 @@ FText SClassViewer::GetClassCountText() const const int32 NumAssets = GetNumItems(); const int32 NumSelectedAssets = GetSelectedItems().Num(); - FText AssetCount = FText::GetEmpty(); - AssetCount = LOCTEXT("AssetCountLabelSingular", "1 item"); + FText AssetCount = LOCTEXT("AssetCountLabelSingular", "1 item"); if (NumSelectedAssets == 0) { diff --git a/Engine/Source/Editor/ClothPainter/Private/ClothMeshAdapter.cpp b/Engine/Source/Editor/ClothPainter/Private/ClothMeshAdapter.cpp index aa250395fa6e..26ce84e2a27b 100644 --- a/Engine/Source/Editor/ClothPainter/Private/ClothMeshAdapter.cpp +++ b/Engine/Source/Editor/ClothPainter/Private/ClothMeshAdapter.cpp @@ -37,7 +37,8 @@ bool FClothMeshPaintAdapter::Construct(UMeshComponent* InComponent, int32 InPain { ReferencedSkeletalMesh = SkeletalMeshComponent->SkeletalMesh; PaintingClothLODIndex = InPaintingClothLODIndex; - + PaintingClothMaskIndex = INDEX_NONE; + const bool bSuccess = Initialize(); return bSuccess; } @@ -112,6 +113,7 @@ void FClothMeshPaintAdapter::ApplyOrRemoveTextureOverride(UTexture* SourceTextur void FClothMeshPaintAdapter::PreEdit() { + ReferencedSkeletalMesh->Modify(); SelectedAsset->Modify(); } @@ -251,19 +253,26 @@ TArray FClothMeshPaintAdapter::SphereIntersectVertices(const float Comp return InRangeVertices; } -void FClothMeshPaintAdapter::SetSelectedClothingAsset(const FGuid& InAssetGuid, int32 InAssetLod) +void FClothMeshPaintAdapter::SetSelectedClothingAsset(const FGuid& InAssetGuid, int32 InAssetLod, int32 InMaskIndex) { SelectedAsset = nullptr; if(InAssetGuid.IsValid() && ReferencedSkeletalMesh) { for(UClothingAssetBase* Asset : ReferencedSkeletalMesh->MeshClothingAssets) { - if(Asset->GetAssetGuid() == InAssetGuid) + UClothingAsset* ConcreteAsset = CastChecked(Asset); + if(ConcreteAsset->GetAssetGuid() == InAssetGuid) { - if(Asset->IsValidLod(InAssetLod)) + if(ConcreteAsset->IsValidLod(InAssetLod)) { - PaintingClothLODIndex = InAssetLod; - SelectedAsset = Asset; + FClothLODData& LodData = ConcreteAsset->LodData[InAssetLod]; + + if(LodData.ParameterMasks.IsValidIndex(InMaskIndex)) + { + PaintingClothLODIndex = InAssetLod; + PaintingClothMaskIndex = InMaskIndex; + SelectedAsset = Asset; + } } break; @@ -277,6 +286,19 @@ void FClothMeshPaintAdapter::SetSelectedClothingAsset(const FGuid& InAssetGuid, } } +const TArray* FClothMeshPaintAdapter::GetVertexNeighbors(int32 InVertexIndex) const +{ + for(const FClothAssetInfo& Info : AssetInfoMap) + { + if(InVertexIndex >= Info.VertexStart && InVertexIndex < Info.VertexEnd) + { + return &Info.NeighborMap[InVertexIndex - Info.VertexStart]; + } + } + + return nullptr; +} + bool FClothMeshPaintAdapter::InitializeVertexData() { int32 VertexOffset = 0; @@ -316,6 +338,33 @@ bool FClothMeshPaintAdapter::InitializeVertexData() Info.VertexEnd = VertexOffset; Info.Asset = ConcreteAsset; + // Set up the edge map / neighbor map + + // Pre fill the map, 1 per index + Info.NeighborMap.AddDefaulted(Info.VertexEnd - Info.VertexStart); + + // Fill in neighbors defined by triangles + const int32 NumTris = MeshIndices.Num() / 3; + for(int32 TriIndex = 0; TriIndex < NumTris; ++TriIndex) + { + const int32 I0 = MeshIndices[TriIndex * 3]; + const int32 I1 = MeshIndices[TriIndex * 3 + 1]; + const int32 I2 = MeshIndices[TriIndex * 3 + 2]; + + TArray& I0Neighbors = Info.NeighborMap[I0]; + TArray& I1Neighbors = Info.NeighborMap[I1]; + TArray& I2Neighbors = Info.NeighborMap[I2]; + + I0Neighbors.AddUnique(I1); + I0Neighbors.AddUnique(I2); + + I1Neighbors.AddUnique(I0); + I1Neighbors.AddUnique(I2); + + I2Neighbors.AddUnique(I0); + I2Neighbors.AddUnique(I1); + } + AssetInfoMap.Add(Info); } } @@ -324,3 +373,31 @@ bool FClothMeshPaintAdapter::InitializeVertexData() return true; } +FClothParameterMask_PhysMesh* FClothMeshPaintAdapter::GetCurrentMask() const +{ + if(HasValidSelection()) + { + UClothingAsset* ConcreteAsset = CastChecked(SelectedAsset); + + return &ConcreteAsset->LodData[PaintingClothLODIndex].ParameterMasks[PaintingClothMaskIndex]; + } + + return nullptr; +} + +bool FClothMeshPaintAdapter::HasValidSelection() const +{ + if(SelectedAsset) + { + UClothingAsset* ConcreteAsset = Cast(SelectedAsset); + + // Only valid selection if we have a valid asset, asset LOD and a mask + if(ConcreteAsset->LodData.IsValidIndex(PaintingClothLODIndex) && + ConcreteAsset->LodData[PaintingClothLODIndex].ParameterMasks.IsValidIndex(PaintingClothMaskIndex)) + { + return true; + } + } + + return false; +} diff --git a/Engine/Source/Editor/ClothPainter/Private/ClothMeshAdapter.h b/Engine/Source/Editor/ClothPainter/Private/ClothMeshAdapter.h index 28404aa00a73..e130fff459fb 100644 --- a/Engine/Source/Editor/ClothPainter/Private/ClothMeshAdapter.h +++ b/Engine/Source/Editor/ClothPainter/Private/ClothMeshAdapter.h @@ -7,6 +7,7 @@ #include "BaseMeshPaintGeometryAdapter.h" #include "IMeshPaintGeometryAdapterFactory.h" +struct FClothParameterMask_PhysMesh; class FReferenceCollector; class UMeshComponent; class UClothingAssetBase; @@ -20,11 +21,18 @@ class FClothMeshPaintAdapter : public FBaseMeshPaintGeometryAdapter protected: struct FClothAssetInfo { + /** Begin/End for this asset's verts in the provided buffer. */ int32 VertexStart; int32 VertexEnd; + + /** Begin/End for this asset's indices in the provided buffer. */ int32 IndexStart; int32 IndexEnd; + /** Map of index to neigbor indices */ + TArray> NeighborMap; + + /** The actual clothing asset relating to this data */ UClothingAsset* Asset; }; public: @@ -70,9 +78,22 @@ public: virtual void SetMaxDistanceValue(int32 VertexIndex, float Value); /** Sets the represented clothing asset to the UClothingAssetBase retrieved from the AssetGUID */ - virtual void SetSelectedClothingAsset(const FGuid& InAssetGuid, int32 InAssetLod); + virtual void SetSelectedClothingAsset(const FGuid& InAssetGuid, int32 InAssetLod, int32 InMaskIndex); + + /** Gets a list of the neighbors of the specified vertex */ + const TArray* GetVertexNeighbors(int32 InVertexIndex) const; + + /** Get the current mask we're editing */ + FClothParameterMask_PhysMesh* GetCurrentMask() const; + protected: + + /** Initialize adapter data ready for painting */ virtual bool InitializeVertexData(); + + /** Whether or not our current asset/lod/mask selection has a valid paintable surface */ + bool HasValidSelection() const; + protected: /** (Debug) Skeletal Mesh Component this adapter represents */ USkeletalMeshComponent* SkeletalMeshComponent; @@ -82,6 +103,9 @@ protected: /** LOD index to paint to (cloth LOD data) */ int32 PaintingClothLODIndex; + /** Mask inside the current LOD to paint */ + int32 PaintingClothMaskIndex; + /** Currently selected clothing asset object to paint to */ UClothingAssetBase* SelectedAsset; diff --git a/Engine/Source/Editor/ClothPainter/Private/ClothPaintSettings.h b/Engine/Source/Editor/ClothPainter/Private/ClothPaintSettings.h index 7e5fd1c07fc4..bffa59fdeb67 100644 --- a/Engine/Source/Editor/ClothPainter/Private/ClothPaintSettings.h +++ b/Engine/Source/Editor/ClothPainter/Private/ClothPaintSettings.h @@ -9,7 +9,7 @@ class UClothingAsset; -DECLARE_MULTICAST_DELEGATE_TwoParams(FOnClothingAssetSelectionChangedMulticaster, UClothingAsset*, int32); +DECLARE_MULTICAST_DELEGATE_ThreeParams(FOnClothingAssetSelectionChangedMulticaster, UClothingAsset*, int32, int32); typedef FOnClothingAssetSelectionChangedMulticaster::FDelegate FOnClothingAssetSelectionChanged; UENUM() @@ -23,50 +23,44 @@ enum class EPaintableClothProperty BackstopRadius }; - -UENUM() -enum class EClothPaintTool -{ - /** Brush paint tool to directly paint vertices */ - Brush, - /** Gradient paint tool to create a gradient between two sets of vertices */ - Gradient -}; - UCLASS() class UClothPainterSettings : public UMeshPaintSettings { GENERATED_BODY() public: + + UClothPainterSettings() + : UMeshPaintSettings() + , ViewMin(0.0f) + , ViewMax(100.0f) + {} + + float GetViewMin() + { + // Zero is reserved, but conceptually we should allow it as that's an + // implementation detail the user is unlikely to care about + return FMath::Clamp(ViewMin, SMALL_NUMBER, MAX_flt); + } + + float GetViewMax() + { + return ViewMax; + } + // Delegates to communicate with objects concerned with the settings changing FOnClothingAssetSelectionChangedMulticaster OnAssetSelectionChanged; - /** Current Clothing Property which should be visualized and painted */ - UPROPERTY(EditAnywhere, Category = ClothPainting) - EPaintableClothProperty PaintingProperty; - - /** Type of paint tool to use*/ - UPROPERTY(EditAnywhere, Category = ClothPainting) - EClothPaintTool PaintTool; - - /** Value to paint for the currently selected PaintingProperty */ - UPROPERTY(EditAnywhere, Category = ClothPainting) - float PaintValue; - - /** Value of (green) points defined at the start of the gradient */ - UPROPERTY(EditAnywhere, Category = ClothPainting) - float GradientStartValue; - - /** Value of (red) points defined at the end of the gradient */ - UPROPERTY(EditAnywhere, Category = ClothPainting) - float GradientEndValue; - - /** Toggle for using the regular brush size for painting the Start and End points */ - UPROPERTY(EditAnywhere, Category = ClothPainting) - bool bUseRegularBrushForGradient; - /** Array of Clothing assets */ UPROPERTY() TArray ClothingAssets; + +protected: + /** When painting float/1D values, this is considered the zero or black point */ + UPROPERTY(EditAnywhere, Category = View) + float ViewMin; + + /** When painting float/1D values, this is considered the one or white point */ + UPROPERTY(EditAnywhere, Category = View) + float ViewMax; }; diff --git a/Engine/Source/Editor/ClothPainter/Private/ClothPaintSettingsCustomization.cpp b/Engine/Source/Editor/ClothPainter/Private/ClothPaintSettingsCustomization.cpp index 82c54c17e1e3..f036a6efc53f 100644 --- a/Engine/Source/Editor/ClothPainter/Private/ClothPaintSettingsCustomization.cpp +++ b/Engine/Source/Editor/ClothPainter/Private/ClothPaintSettingsCustomization.cpp @@ -8,6 +8,8 @@ #include "ClothPaintSettings.h" #include "ClothingAsset.h" #include "SComboBox.h" +#include "ClothPainter.h" +#include "ClothPaintToolBase.h" #define LOCTEXT_NAMESPACE "ClothPaintSettingsCustomization" @@ -46,22 +48,74 @@ void FClothPaintSettingsCustomization::CustomizeDetails(IDetailLayoutBuilder& De const FName ClothCategory = "ClothPainting"; IDetailCategoryBuilder& CategoryBuilder = DetailBuilder.EditCategory(ClothCategory); - // Hide gradient/brush settings according to which tool is being used - if (PainterSettings) - { - DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UClothPainterSettings, PaintTool))->SetOnPropertyValueChanged(FSimpleDelegate::CreateLambda([&]() { DetailBuilder.ForceRefreshDetails(); })); - if (PainterSettings->PaintTool == EClothPaintTool::Brush) - { - DetailBuilder.HideProperty(GET_MEMBER_NAME_CHECKED(UClothPainterSettings, GradientStartValue)); - DetailBuilder.HideProperty(GET_MEMBER_NAME_CHECKED(UClothPainterSettings, GradientEndValue)); - DetailBuilder.HideProperty(GET_MEMBER_NAME_CHECKED(UClothPainterSettings, bUseRegularBrushForGradient)); - } - else - { - DetailBuilder.HideProperty(GET_MEMBER_NAME_CHECKED(UClothPainterSettings, PaintValue)); - } + // Add tool selection from the tools array on the painter + FText ToolText = LOCTEXT("ToolSelectionRow", "Tool"); + FDetailWidgetRow& ToolSelectionRow = CategoryBuilder.AddCustomRow(ToolText); + + ToolSelectionRow.NameContent() + [ + SNew(STextBlock) + .Text(ToolText) + .Font(IDetailLayoutBuilder::GetDetailFont()) + ]; + + ToolSelectionRow.ValueContent() + [ + SNew(SComboBox>) + .OptionsSource(&Painter->Tools) + .OnGenerateWidget(this, &FClothPaintSettingsCustomization::OnGenerateToolComboRow) + .OnSelectionChanged(this, &FClothPaintSettingsCustomization::OnHandleToolSelection, &DetailBuilder) + [ + SNew(STextBlock) + .Text(this, &FClothPaintSettingsCustomization::GetToolComboText) + .Font(IDetailLayoutBuilder::GetDetailFont()) + ] + ]; +} + +TSharedRef FClothPaintSettingsCustomization::OnGenerateToolComboRow(TSharedPtr InItem) +{ + FText RowText = LOCTEXT("ToolComboRow_Error", "Invalid"); + + if(InItem.IsValid()) + { + RowText = InItem->GetDisplayName(); + } + + return SNew(STextBlock).Text(RowText); +} + +void FClothPaintSettingsCustomization::OnHandleToolSelection(TSharedPtr InItem, ESelectInfo::Type InSelectInfo, IDetailLayoutBuilder* DetailBuider) +{ + if(InItem.IsValid() && Painter && Painter->SelectedTool != InItem) + { + // Update selection + Painter->SetTool(InItem); + Painter->Refresh(); } } +FText FClothPaintSettingsCustomization::GetToolComboText() const +{ + if(Painter && Painter->SelectedTool.IsValid()) + { + return Painter->SelectedTool->GetDisplayName(); + } + + return LOCTEXT("ToolComboRow_Error", "Invalid"); +} + #undef LOCTEXT_NAMESPACE + +TSharedRef FClothPaintBrushSettingsCustomization::MakeInstance() +{ + return MakeShareable(new FClothPaintBrushSettingsCustomization()); +} + +void FClothPaintBrushSettingsCustomization::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) +{ + TSharedRef ColorViewProp = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UPaintBrushSettings, ColorViewMode)); + + ColorViewProp->MarkHiddenByCustomization(); +} diff --git a/Engine/Source/Editor/ClothPainter/Private/ClothPaintSettingsCustomization.h b/Engine/Source/Editor/ClothPainter/Private/ClothPaintSettingsCustomization.h index fdb8103d97ca..c61af72532b3 100644 --- a/Engine/Source/Editor/ClothPainter/Private/ClothPaintSettingsCustomization.h +++ b/Engine/Source/Editor/ClothPainter/Private/ClothPaintSettingsCustomization.h @@ -10,6 +10,7 @@ class FClothPainter; class UClothingAsset; class UClothPainterSettings; +class FClothPaintToolBase; class FClothPaintSettingsCustomization : public IDetailCustomization { @@ -27,6 +28,12 @@ public: private: + /** Handlers for SCombobox, generation of row widgets, combo text and handling selection change */ + TSharedRef OnGenerateToolComboRow(TSharedPtr InItem); + void OnHandleToolSelection(TSharedPtr InItem, ESelectInfo::Type InSelectInfo, IDetailLayoutBuilder* DetailBuider); + FText GetToolComboText() const; + + /** The painter containing the paint settings we are customizing */ FClothPainter* Painter; }; @@ -40,3 +47,14 @@ public: virtual bool IsObjectVisible(const UObject* InRootObject) const override { return true; } virtual bool ShouldDisplayHeader(const UObject* InRootObject) const override { return false; } }; + + +class FClothPaintBrushSettingsCustomization : public IDetailCustomization +{ +public: + + static TSharedRef MakeInstance(); + + /** IDetailCustomization interface */ + virtual void CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) override; +}; diff --git a/Engine/Source/Editor/ClothPainter/Private/ClothPaintToolBase.cpp b/Engine/Source/Editor/ClothPainter/Private/ClothPaintToolBase.cpp new file mode 100644 index 000000000000..a1f72f35ecf5 --- /dev/null +++ b/Engine/Source/Editor/ClothPainter/Private/ClothPaintToolBase.cpp @@ -0,0 +1 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. \ No newline at end of file diff --git a/Engine/Source/Editor/ClothPainter/Private/ClothPaintToolBase.h b/Engine/Source/Editor/ClothPainter/Private/ClothPaintToolBase.h new file mode 100644 index 000000000000..d7275e716864 --- /dev/null +++ b/Engine/Source/Editor/ClothPainter/Private/ClothPaintToolBase.h @@ -0,0 +1,60 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "MeshPaintHelpers.h" +#include "ClothPainter.h" + +/** + * Base object for tools used to paint clothing + * Derive from this and register a new tool in FClothPainter::Init to add to the available tools + */ +class FClothPaintToolBase +{ +public: + + FClothPaintToolBase() = delete; + FClothPaintToolBase(const FClothPaintToolBase& Other) = delete; + + explicit FClothPaintToolBase(TWeakPtr InPainter) + : Painter(InPainter) + {} + + virtual ~FClothPaintToolBase() {}; + + /** Used by the painter to request a delegate to call to apply this tool to the current mesh */ + virtual FPerVertexPaintAction GetPaintAction(const FMeshPaintParameters& InPaintParams, UClothPainterSettings* InPainterSettings) { return FPerVertexPaintAction(); } + + /** Called when the user presses a key when this tool is selected */ + virtual bool InputKey(IMeshPaintGeometryAdapter* Adapter, FEditorViewportClient* InViewportClient, FViewport* InViewport, FKey InKey, EInputEvent InEvent) { return false; } + + /** Whether or not the brush interactor should be drawn */ + virtual bool ShouldRenderInteractors() const { return true; } + + /** Display name for UI purposes */ + virtual FText GetDisplayName() const = 0; + + /** Whether this action should be executed once for each vertex in the brush or just once per operation */ + virtual bool IsPerVertex() const { return true; } + + /** Optionally render extra data to the viewport */ + virtual void Render(USkeletalMeshComponent* InComponent, IMeshPaintGeometryAdapter* InAdapter, const FSceneView* View, FViewport* Viewport, FPrimitiveDrawInterface* PDI) {} + + /** Called as tool is selected, can be used to initialize and bind actions */ + virtual void Activate(TWeakPtr InCommands) {}; + + /** Called as tool is deselected, can be used to shutdown and unbind actions */ + virtual void Deactivate(TWeakPtr InCommands) {}; + + /** + * Optionally return a UObject that will be displayed in the details panel when the tool is selected. + * This is intended for settings unique to the tool, common settings (brush size etc) are available from + * the brush settings in the Painter. + */ + virtual UObject* GetSettingsObject() { return nullptr; } + +protected: + + /** The painter instance that owns this tool */ + TWeakPtr Painter; +}; \ No newline at end of file diff --git a/Engine/Source/Editor/ClothPainter/Private/ClothPaintToolCommands.cpp b/Engine/Source/Editor/ClothPainter/Private/ClothPaintToolCommands.cpp new file mode 100644 index 000000000000..3cd91a89f5fd --- /dev/null +++ b/Engine/Source/Editor/ClothPainter/Private/ClothPaintToolCommands.cpp @@ -0,0 +1,22 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "ClothPaintToolCommands.h" + +#define LOCTEXT_NAMESPACE "ClothPaintToolCommands" + +void ClothPaintToolCommands::RegisterClothPaintToolCommands() +{ + FClothPaintToolCommands_Gradient::Register(); +} + +void FClothPaintToolCommands_Gradient::RegisterCommands() +{ + UI_COMMAND(ApplyGradient, "Apply gradient", "Apply the gradient when the clothing paint gradient tool is active.", EUserInterfaceActionType::Button, FInputChord(EKeys::Enter)); +} + +const FClothPaintToolCommands_Gradient& FClothPaintToolCommands_Gradient::Get() +{ + return TCommands::Get(); +} + +#undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Editor/ClothPainter/Private/ClothPaintToolCommands.h b/Engine/Source/Editor/ClothPainter/Private/ClothPaintToolCommands.h new file mode 100644 index 000000000000..a9fadc70c6bc --- /dev/null +++ b/Engine/Source/Editor/ClothPainter/Private/ClothPaintToolCommands.h @@ -0,0 +1,29 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "EditorStyleSet.h" +#include "Framework/Commands/Commands.h" + +namespace ClothPaintToolCommands +{ + void RegisterClothPaintToolCommands(); +} + +class FClothPaintToolCommands_Gradient : public TCommands +{ +public: + + FClothPaintToolCommands_Gradient() + : TCommands(TEXT("ClothPainter"), NSLOCTEXT("Contexts", "ClothFillTool", "Cloth Painter - Fill Tool"), NAME_None, FEditorStyle::GetStyleSetName()) + { + + } + + virtual void RegisterCommands() override; + static const FClothPaintToolCommands_Gradient& Get(); + + /** Applies the gradient when using the gradient cloth paint tool */ + TSharedPtr ApplyGradient; +}; \ No newline at end of file diff --git a/Engine/Source/Editor/ClothPainter/Private/ClothPaintTools.cpp b/Engine/Source/Editor/ClothPainter/Private/ClothPaintTools.cpp new file mode 100644 index 000000000000..da4072339263 --- /dev/null +++ b/Engine/Source/Editor/ClothPainter/Private/ClothPaintTools.cpp @@ -0,0 +1,638 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "ClothPaintTools.h" +#include "ClothPaintSettings.h" +#include "ClothMeshAdapter.h" +#include "Components/PrimitiveComponent.h" +#include "Components/SkeletalMeshComponent.h" +#include "ScopedTransaction.h" +#include "SceneManagement.h" +#include "Package.h" +#include "Queue.h" +#include "InputChord.h" +#include "ClothPaintToolCommands.h" +#include "UICommandInfo.h" +#include "UICommandList.h" + +#define LOCTEXT_NAMESPACE "ClothTools" + +FClothPaintTool_Brush::~FClothPaintTool_Brush() +{ + if(Settings) + { + Settings->RemoveFromRoot(); + } +} + +FText FClothPaintTool_Brush::GetDisplayName() const +{ + return LOCTEXT("ToolName_Brush", "Brush"); +} + +FPerVertexPaintAction FClothPaintTool_Brush::GetPaintAction(const FMeshPaintParameters& InPaintParams, UClothPainterSettings* InPainterSettings) +{ + return FPerVertexPaintAction::CreateRaw(this, &FClothPaintTool_Brush::PaintAction, InPaintParams.InverseBrushToWorldMatrix); +} + +UObject* FClothPaintTool_Brush::GetSettingsObject() +{ + if(!Settings) + { + Settings = DuplicateObject(GetMutableDefault(), GetTransientPackage()); + Settings->AddToRoot(); + } + + return Settings; +} + +void FClothPaintTool_Brush::PaintAction(FPerVertexPaintActionArgs& InArgs, int32 VertexIndex, FMatrix InverseBrushMatrix) +{ + FClothMeshPaintAdapter* ClothAdapter = (FClothMeshPaintAdapter*)InArgs.Adapter; + if(ClothAdapter) + { + TSharedPtr SharedPainter = Painter.Pin(); + if(SharedPainter.IsValid()) + { + UPaintBrushSettings* BrushSettings = SharedPainter->GetBrushSettings(); + UClothPainterSettings* PaintSettings = Cast(SharedPainter->GetPainterSettings()); + + FVector Position; + ClothAdapter->GetVertexPosition(VertexIndex, Position); + Position = ClothAdapter->GetComponentToWorldMatrix().TransformPosition(Position); + + float Value = SharedPainter->GetPropertyValue(VertexIndex); + const float BrushRadius = BrushSettings->GetBrushRadius(); + MeshPaintHelpers::ApplyBrushToVertex(Position, InverseBrushMatrix, BrushRadius * BrushRadius, BrushSettings->BrushFalloffAmount, Settings->PaintValue, Value); + SharedPainter->SetPropertyValue(VertexIndex, Value); + } + } +} + +FClothPaintTool_Gradient::~FClothPaintTool_Gradient() +{ + if(Settings) + { + Settings->RemoveFromRoot(); + } +} + +FText FClothPaintTool_Gradient::GetDisplayName() const +{ + return LOCTEXT("ToolName_Gradient", "Gradient"); +} + +bool FClothPaintTool_Gradient::InputKey(IMeshPaintGeometryAdapter* Adapter, FEditorViewportClient* InViewportClient, FViewport* InViewport, FKey InKey, EInputEvent InEvent) +{ + bool bHandled = false; + + if(InKey == EKeys::LeftControl || InKey == EKeys::RightControl) + { + if(InEvent == IE_Pressed) + { + bSelectingBeginPoints = false; + bHandled = true; + } + else if(InEvent == IE_Released) + { + bSelectingBeginPoints = true; + bHandled = true; + } + } + + return bHandled; +} + +FPerVertexPaintAction FClothPaintTool_Gradient::GetPaintAction(const FMeshPaintParameters& InPaintParams, UClothPainterSettings* InPainterSettings) +{ + return FPerVertexPaintAction::CreateRaw(this, &FClothPaintTool_Gradient::PaintAction, InPaintParams.InverseBrushToWorldMatrix); +} + +bool FClothPaintTool_Gradient::IsPerVertex() const +{ + return false; +} + +void FClothPaintTool_Gradient::Render(USkeletalMeshComponent* InComponent, IMeshPaintGeometryAdapter* InAdapter, const FSceneView* View, FViewport* Viewport, FPrimitiveDrawInterface* PDI) +{ + TSharedPtr SharedPainter = Painter.Pin(); + + if(!SharedPainter.IsValid()) + { + return; + } + + const float VertexPointSize = 3.0f; + const UClothPainterSettings* PaintSettings = CastChecked(SharedPainter->GetPainterSettings()); + const UPaintBrushSettings* BrushSettings = SharedPainter->GetBrushSettings(); + + TArray PaintRays; + MeshPaintHelpers::RetrieveViewportPaintRays(View, Viewport, PDI, PaintRays); + + const FMatrix ComponentToWorldMatrix = InComponent->ComponentToWorld.ToMatrixWithScale(); + + for (const MeshPaintHelpers::FPaintRay& PaintRay : PaintRays) + { + for (const int32& Index : GradientStartIndices) + { + FVector Vertex; + InAdapter->GetVertexPosition(Index, Vertex); + + const FVector WorldPositionVertex = ComponentToWorldMatrix.TransformPosition(Vertex); + PDI->DrawPoint(WorldPositionVertex, FLinearColor::Green, VertexPointSize * 2.0f, SDPG_World); + } + + for (const int32& Index : GradientEndIndices) + { + FVector Vertex; + InAdapter->GetVertexPosition(Index, Vertex); + + const FVector WorldPositionVertex = ComponentToWorldMatrix.TransformPosition(Vertex); + PDI->DrawPoint(WorldPositionVertex, FLinearColor::Red, VertexPointSize * 2.0f, SDPG_World); + } + + + const FHitResult& HitResult = SharedPainter->GetHitResult(PaintRay.RayStart, PaintRay.RayDirection); + if (HitResult.Component == InComponent) + { + const FVector ComponentSpaceCameraPosition(ComponentToWorldMatrix.InverseTransformPosition(PaintRay.CameraLocation)); + const FVector ComponentSpaceBrushPosition(ComponentToWorldMatrix.InverseTransformPosition(HitResult.Location)); + const float ComponentSpaceBrushRadius = ComponentToWorldMatrix.InverseTransformVector(FVector(Settings->bUseRegularBrush ? BrushSettings->GetBrushRadius() : 2.0f, 0.0f, 0.0f)).Size(); + const float ComponentSpaceSquaredBrushRadius = ComponentSpaceBrushRadius * ComponentSpaceBrushRadius; + + // Draw hovered vertex + TArray InRangeVertices = InAdapter->SphereIntersectVertices(ComponentSpaceSquaredBrushRadius, ComponentSpaceBrushPosition, ComponentSpaceCameraPosition, BrushSettings->bOnlyFrontFacingTriangles); + InRangeVertices.Sort([=](const FVector& PointOne, const FVector& PointTwo) + { + return (PointOne - ComponentSpaceBrushPosition).SizeSquared() < (PointTwo - ComponentSpaceBrushPosition).SizeSquared(); + }); + + + if (InRangeVertices.Num()) + { + if (!Settings->bUseRegularBrush) + { + InRangeVertices.SetNum(1); + } + + for (const FVector& Vertex : InRangeVertices) + { + const FVector WorldPositionVertex = ComponentToWorldMatrix.TransformPosition(Vertex); + PDI->DrawPoint(WorldPositionVertex, bSelectingBeginPoints ? FLinearColor::Green : FLinearColor::Red, VertexPointSize * 2.0f, SDPG_Foreground); + } + } + } + } +} + +bool FClothPaintTool_Gradient::ShouldRenderInteractors() const +{ + return Settings->bUseRegularBrush; +} + +UObject* FClothPaintTool_Gradient::GetSettingsObject() +{ + if(!Settings) + { + Settings = DuplicateObject(GetMutableDefault(), GetTransientPackage()); + Settings->AddToRoot(); + } + + return Settings; +} + +void FClothPaintTool_Gradient::Activate(TWeakPtr InCommands) +{ + TSharedPtr SharedCommands = InCommands.Pin(); + if(SharedCommands.IsValid()) + { + const FClothPaintToolCommands_Gradient& Commands = FClothPaintToolCommands_Gradient::Get(); + + SharedCommands->MapAction(Commands.ApplyGradient, + FExecuteAction::CreateRaw(this, &FClothPaintTool_Gradient::ApplyGradient), + FCanExecuteAction::CreateRaw(this, &FClothPaintTool_Gradient::CanApplyGradient) + ); + } +} + +void FClothPaintTool_Gradient::Deactivate(TWeakPtr InCommands) +{ + TSharedPtr SharedCommands = InCommands.Pin(); + if(SharedCommands.IsValid()) + { + const FClothPaintToolCommands_Gradient& Commands = FClothPaintToolCommands_Gradient::Get(); + + SharedCommands->UnmapAction(Commands.ApplyGradient); + } +} + +void FClothPaintTool_Gradient::PaintAction(FPerVertexPaintActionArgs& InArgs, int32 VertexIndex, FMatrix InverseBrushMatrix) +{ + TSharedPtr SharedPainter = Painter.Pin(); + if(!SharedPainter.IsValid()) + { + return; + } + + const FHitResult HitResult = InArgs.HitResult; + UClothPainterSettings* PaintSettings = CastChecked(SharedPainter->GetPainterSettings()); + const UPaintBrushSettings* BrushSettings = InArgs.BrushSettings; + FClothMeshPaintAdapter* Adapter = (FClothMeshPaintAdapter*)InArgs.Adapter; + + const FMatrix ComponentToWorldMatrix = HitResult.Component->ComponentToWorld.ToMatrixWithScale(); + const FVector ComponentSpaceCameraPosition(ComponentToWorldMatrix.InverseTransformPosition(InArgs.CameraPosition)); + const FVector ComponentSpaceBrushPosition(ComponentToWorldMatrix.InverseTransformPosition(HitResult.Location)); + const float ComponentSpaceBrushRadius = ComponentToWorldMatrix.InverseTransformVector(FVector(Settings->bUseRegularBrush ? BrushSettings->GetBrushRadius() : 2.0f, 0.0f, 0.0f)).Size(); + const float ComponentSpaceSquaredBrushRadius = ComponentSpaceBrushRadius * ComponentSpaceBrushRadius; + + // Override these flags becuase we're not actually "painting" so the state would be incorrect + SharedPainter->SetIsPainting(true); + + TArray InRangeVertices = Adapter->SphereIntersectVertices(ComponentSpaceSquaredBrushRadius, ComponentSpaceBrushPosition, ComponentSpaceCameraPosition, BrushSettings->bOnlyFrontFacingTriangles); + + TSet InRangeIndicesSet; + Adapter->GetInfluencedVertexIndices(ComponentSpaceSquaredBrushRadius, ComponentSpaceBrushPosition, ComponentSpaceCameraPosition, BrushSettings->bOnlyFrontFacingTriangles, InRangeIndicesSet); + + // Must have an array for sorting/counting + TArray InRangeIndices = InRangeIndicesSet.Array(); + + if (InRangeIndices.Num()) + { + // Sort based on distance from brush centre + InRangeIndices.Sort([=](const int32& Idx0, const int32& Idx1) + { + FVector PointOne; + FVector PointTwo; + + Adapter->GetVertexPosition(Idx0, PointOne); + Adapter->GetVertexPosition(Idx1, PointTwo); + + return (PointOne - ComponentSpaceBrushPosition).SizeSquared() < (PointTwo - ComponentSpaceBrushPosition).SizeSquared(); + }); + + // Selection mode + if (!Settings->bUseRegularBrush) + { + InRangeIndices.SetNum(1); + } + + TArray& CurrentList = bSelectingBeginPoints ? GradientStartIndices : GradientEndIndices; + TArray& OtherList = bSelectingBeginPoints ? GradientEndIndices : GradientStartIndices; + + // Add selected verts to current list + for (const int32& Index : InRangeIndices) + { + if (InArgs.Action == EMeshPaintAction::Erase && CurrentList.Contains(Index)) + { + CurrentList.Remove(Index); + } + else if (InArgs.Action == EMeshPaintAction::Paint) + { + CurrentList.AddUnique(Index); + OtherList.Remove(Index); + } + } + } +} + +void FClothPaintTool_Gradient::ApplyGradient() +{ + TSharedPtr SharedPainter = Painter.Pin(); + if(!SharedPainter.IsValid()) + { + return; + } + + TSharedPtr SharedAdapter = SharedPainter->GetAdapter(); + + if(!SharedAdapter.IsValid()) + { + return; + } + + FClothMeshPaintAdapter* Adapter = (FClothMeshPaintAdapter*)SharedAdapter.Get(); + + { + FScopedTransaction Transaction(LOCTEXT("ApplyGradientTransaction", "Apply gradient")); + + Adapter->PreEdit(); + + const TArray Verts = Adapter->GetMeshVertices(); + + const int32 NumVerts = Verts.Num(); + for(int32 VertIndex = 0; VertIndex < NumVerts; ++VertIndex) + { + const FVector& Vert = Verts[VertIndex]; + + // Get distances + // TODO: Look into surface distance instead of 3D distance? May be necessary for some complex shapes + float DistanceToStartSq = MAX_flt; + for(const int32& StartIndex : GradientStartIndices) + { + FVector StartPoint; + Adapter->GetVertexPosition(StartIndex, StartPoint); + const float DistanceSq = (StartPoint - Vert).SizeSquared(); + if(DistanceSq < DistanceToStartSq) + { + DistanceToStartSq = DistanceSq; + } + } + + float DistanceToEndSq = MAX_flt; + for(const int32& EndIndex : GradientEndIndices) + { + FVector EndPoint; + Adapter->GetVertexPosition(EndIndex, EndPoint); + const float DistanceSq = (EndPoint - Vert).SizeSquared(); + if(DistanceSq < DistanceToEndSq) + { + DistanceToEndSq = DistanceSq; + } + } + + // Apply to the mesh + UClothPainterSettings* PaintSettings = CastChecked(SharedPainter->GetPainterSettings()); + const float Value = FMath::LerpStable(Settings->GradientStartValue, Settings->GradientEndValue, DistanceToStartSq / (DistanceToStartSq + DistanceToEndSq)); + SharedPainter->SetPropertyValue(VertIndex, Value); + } + + // Finished edit + Adapter->PostEdit(); + } + + // Empty the point lists as the operation is complete + GradientStartIndices.Reset(); + GradientEndIndices.Reset(); + + // Move back to selecting begin points + bSelectingBeginPoints = true; +} + +bool FClothPaintTool_Gradient::CanApplyGradient() +{ + return GradientEndIndices.Num() > 0 && GradientStartIndices.Num() > 0; +} + +FClothPaintTool_Smooth::~FClothPaintTool_Smooth() +{ + if(Settings) + { + Settings->RemoveFromRoot(); + } +} + +FPerVertexPaintAction FClothPaintTool_Smooth::GetPaintAction(const FMeshPaintParameters& InPaintParams, UClothPainterSettings* InPainterSettings) +{ + return FPerVertexPaintAction::CreateRaw(this, &FClothPaintTool_Smooth::PaintAction, InPaintParams.InverseBrushToWorldMatrix); +} + +FText FClothPaintTool_Smooth::GetDisplayName() const +{ + return LOCTEXT("ToolName_Smooth", "Smooth"); +} + +UObject* FClothPaintTool_Smooth::GetSettingsObject() +{ + if(!Settings) + { + Settings = DuplicateObject(GetMutableDefault(), GetTransientPackage()); + Settings->AddToRoot(); + } + + return Settings; +} + +bool FClothPaintTool_Smooth::IsPerVertex() const +{ + return false; +} + +void FClothPaintTool_Smooth::PaintAction(FPerVertexPaintActionArgs& InArgs, int32 VertexIndex, FMatrix InverseBrushMatrix) +{ + TSharedPtr SharedPainter = Painter.Pin(); + if(!SharedPainter.IsValid()) + { + return; + } + + const FHitResult HitResult = InArgs.HitResult; + UClothPainterSettings* PaintSettings = CastChecked(SharedPainter->GetPainterSettings()); + const UPaintBrushSettings* BrushSettings = InArgs.BrushSettings; + FClothMeshPaintAdapter* Adapter = (FClothMeshPaintAdapter*)InArgs.Adapter; + + const FMatrix ComponentToWorldMatrix = HitResult.Component->ComponentToWorld.ToMatrixWithScale(); + const FVector ComponentSpaceCameraPosition(ComponentToWorldMatrix.InverseTransformPosition(InArgs.CameraPosition)); + const FVector ComponentSpaceBrushPosition(ComponentToWorldMatrix.InverseTransformPosition(HitResult.Location)); + const float ComponentSpaceBrushRadius = ComponentToWorldMatrix.InverseTransformVector(FVector(BrushSettings->GetBrushRadius(), 0.0f, 0.0f)).Size(); + const float ComponentSpaceSquaredBrushRadius = ComponentSpaceBrushRadius * ComponentSpaceBrushRadius; + + // Override these flags becuase we're not actually "painting" so the state would be incorrect + SharedPainter->SetIsPainting(true); + + TSet InfluencedVertices; + Adapter->GetInfluencedVertexIndices(ComponentSpaceSquaredBrushRadius, ComponentSpaceBrushPosition, ComponentSpaceCameraPosition, BrushSettings->bOnlyFrontFacingTriangles, InfluencedVertices); + const int32 NumVerts = InfluencedVertices.Num(); + if(NumVerts > 0) + { + TArray NewValues; + NewValues.AddZeroed(NumVerts); + + int32 InfluencedIndex = 0; + for(int32 Index : InfluencedVertices) + { + const TArray* Neighbors = Adapter->GetVertexNeighbors(Index); + if(Neighbors && Neighbors->Num() > 0) + { + float Accumulator = 0.0f; + + for(int32 NeighborIndex : (*Neighbors)) + { + Accumulator += SharedPainter->GetPropertyValue(NeighborIndex); + } + + NewValues[InfluencedIndex] = Accumulator / Neighbors->Num(); + } + else + { + NewValues[InfluencedIndex] = SharedPainter->GetPropertyValue(Index); + } + + ++InfluencedIndex; + } + + int32 ValueIndex = 0; + for(int32 Index : InfluencedVertices) + { + float Current = SharedPainter->GetPropertyValue(Index); + float Difference = NewValues[ValueIndex] - Current; + + SharedPainter->SetPropertyValue(Index, Current + Difference * Settings->Strength); + ++ValueIndex; + } + } +} + +FClothPaintTool_Fill::~FClothPaintTool_Fill() +{ + if(Settings) + { + Settings->RemoveFromRoot(); + } +} + +FPerVertexPaintAction FClothPaintTool_Fill::GetPaintAction(const FMeshPaintParameters& InPaintParams, UClothPainterSettings* InPainterSettings) +{ + return FPerVertexPaintAction::CreateRaw(this, &FClothPaintTool_Fill::PaintAction, InPaintParams.InverseBrushToWorldMatrix); +} + +FText FClothPaintTool_Fill::GetDisplayName() const +{ + return LOCTEXT("ToolName_Fill", "Fill"); +} + +UObject* FClothPaintTool_Fill::GetSettingsObject() +{ + if(!Settings) + { + Settings = DuplicateObject(GetMutableDefault(), GetTransientPackage()); + Settings->AddToRoot(); + } + + return Settings; +} + +bool FClothPaintTool_Fill::IsPerVertex() const +{ + return false; +} + +bool FClothPaintTool_Fill::ShouldRenderInteractors() const +{ + return false; +} + +void FClothPaintTool_Fill::Render(USkeletalMeshComponent* InComponent, IMeshPaintGeometryAdapter* InAdapter, const FSceneView* View, FViewport* Viewport, FPrimitiveDrawInterface* PDI) +{ + TSharedPtr SharedPainter = Painter.Pin(); + + if(!SharedPainter.IsValid()) + { + return; + } + + const float VertexPointSize = 3.0f; + const UClothPainterSettings* PaintSettings = CastChecked(SharedPainter->GetPainterSettings()); + const UPaintBrushSettings* BrushSettings = SharedPainter->GetBrushSettings(); + + TArray PaintRays; + MeshPaintHelpers::RetrieveViewportPaintRays(View, Viewport, PDI, PaintRays); + + const FMatrix ComponentToWorldMatrix = InComponent->ComponentToWorld.ToMatrixWithScale(); + + for(const MeshPaintHelpers::FPaintRay& PaintRay : PaintRays) + { + const FHitResult& HitResult = SharedPainter->GetHitResult(PaintRay.RayStart, PaintRay.RayDirection); + if(HitResult.Component == InComponent) + { + const FVector ComponentSpaceCameraPosition(ComponentToWorldMatrix.InverseTransformPosition(PaintRay.CameraLocation)); + const FVector ComponentSpaceBrushPosition(ComponentToWorldMatrix.InverseTransformPosition(HitResult.Location)); + const float ComponentSpaceBrushRadius = ComponentToWorldMatrix.InverseTransformVector(FVector(QueryRadius, 0.0f, 0.0f)).Size(); + const float ComponentSpaceSquaredBrushRadius = ComponentSpaceBrushRadius * ComponentSpaceBrushRadius; + + // Draw hovered vertex + TArray InRangeVertices = InAdapter->SphereIntersectVertices(ComponentSpaceSquaredBrushRadius, ComponentSpaceBrushPosition, ComponentSpaceCameraPosition, BrushSettings->bOnlyFrontFacingTriangles); + InRangeVertices.Sort([=](const FVector& PointOne, const FVector& PointTwo) + { + return (PointOne - ComponentSpaceBrushPosition).SizeSquared() < (PointTwo - ComponentSpaceBrushPosition).SizeSquared(); + }); + + + if(InRangeVertices.Num()) + { + InRangeVertices.SetNum(1); + // reduce this + for(const FVector& Vertex : InRangeVertices) + { + const FVector WorldPositionVertex = ComponentToWorldMatrix.TransformPosition(Vertex); + PDI->DrawPoint(WorldPositionVertex, FLinearColor::Green, VertexPointSize * 2.0f, SDPG_Foreground); + } + } + } + } +} + +void FClothPaintTool_Fill::PaintAction(FPerVertexPaintActionArgs& InArgs, int32 VertexIndex, FMatrix InverseBrushMatrix) +{ + TSharedPtr SharedPainter = Painter.Pin(); + if(!SharedPainter.IsValid()) + { + return; + } + + const FHitResult HitResult = InArgs.HitResult; + UClothPainterSettings* PaintSettings = CastChecked(SharedPainter->GetPainterSettings()); + const UPaintBrushSettings* BrushSettings = InArgs.BrushSettings; + FClothMeshPaintAdapter* Adapter = (FClothMeshPaintAdapter*)InArgs.Adapter; + + const FMatrix ComponentToWorldMatrix = HitResult.Component->ComponentToWorld.ToMatrixWithScale(); + const FVector ComponentSpaceCameraPosition(ComponentToWorldMatrix.InverseTransformPosition(InArgs.CameraPosition)); + const FVector ComponentSpaceBrushPosition(ComponentToWorldMatrix.InverseTransformPosition(HitResult.Location)); + const float ComponentSpaceBrushRadius = ComponentToWorldMatrix.InverseTransformVector(FVector(QueryRadius, 0.0f, 0.0f)).Size(); + const float ComponentSpaceSquaredBrushRadius = ComponentSpaceBrushRadius * ComponentSpaceBrushRadius; + + // Override these flags becuase we're not actually "painting" so the state would be incorrect + SharedPainter->SetIsPainting(true); + + TArray> Verts; + Adapter->GetInfluencedVertexData(ComponentSpaceSquaredBrushRadius, ComponentSpaceBrushPosition, ComponentSpaceCameraPosition, BrushSettings->bOnlyFrontFacingTriangles, Verts); + + if(Verts.Num() > 0) + { + // Sort based on distance from brush centre + Verts.Sort([=](const TPair& Vert0, const TPair& Vert1) + { + return (Vert0.Value - ComponentSpaceBrushPosition).SizeSquared() < (Vert1.Value - ComponentSpaceBrushPosition).SizeSquared(); + }); + + // Fill operates on one vertex only, the closest + int32 ChosenIndex = Verts[0].Key; + + // An expansion queue to handle the fill operation + TQueue VertQueue; + + // Query values to account for the threshold around the selected value + const float QueryValue = SharedPainter->GetPropertyValue(ChosenIndex); + const float MinQueryValue = QueryValue - Settings->Threshold; + const float MaxQueryValue = QueryValue + Settings->Threshold; + + // Set the selected vert to the new vaue and add it to the expansion queue + SharedPainter->SetPropertyValue(ChosenIndex, Settings->FillValue); + VertQueue.Enqueue(ChosenIndex); + + int32 CurrIndex = 0; + while(!VertQueue.IsEmpty()) + { + // Remove the current vert from the queue + VertQueue.Dequeue(CurrIndex); + + // Grab the neighbors of the current vertex + const TArray* Neighbors = Adapter->GetVertexNeighbors(CurrIndex); + + if(Neighbors && Neighbors->Num() > 0) + { + for(int32 NeighborIndex : (*Neighbors)) + { + // For each neighbor, get its current value and if it's not the correct final + // value, set it and then add to the queue for expansion on the next loop + const float NeighborValue = SharedPainter->GetPropertyValue(NeighborIndex); + if(NeighborValue != Settings->FillValue && NeighborValue >= MinQueryValue && NeighborValue <= MaxQueryValue) + { + SharedPainter->SetPropertyValue(NeighborIndex, Settings->FillValue); + VertQueue.Enqueue(NeighborIndex); + } + } + } + } + } +} + +#undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Editor/ClothPainter/Private/ClothPaintTools.h b/Engine/Source/Editor/ClothPainter/Private/ClothPaintTools.h new file mode 100644 index 000000000000..9001f25d69c1 --- /dev/null +++ b/Engine/Source/Editor/ClothPainter/Private/ClothPaintTools.h @@ -0,0 +1,245 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "ClothPaintToolBase.h" +#include "ClothPaintTools.generated.h" + +/** Unique settings for the Brush tool */ +UCLASS() +class UClothPaintTool_BrushSettings : public UObject +{ + GENERATED_BODY() + +public: + + UClothPaintTool_BrushSettings() + : PaintValue(100.0f) + { + + } + + /** Value to paint onto the mesh for this parameter */ + UPROPERTY(EditAnywhere, Category = ToolSettings) + float PaintValue; +}; + + +/** Standard brush tool for painting onto the mesh */ +class FClothPaintTool_Brush : public FClothPaintToolBase +{ +public: + + FClothPaintTool_Brush(TWeakPtr InPainter) + : FClothPaintToolBase(InPainter) + , Settings(nullptr) + { + + } + + virtual ~FClothPaintTool_Brush(); + + /** FClothPaintToolBase interface */ + virtual FText GetDisplayName() const override; + virtual FPerVertexPaintAction GetPaintAction(const FMeshPaintParameters& InPaintParams, UClothPainterSettings* InPainterSettings) override; + virtual UObject* GetSettingsObject() override; + /** End FClothPaintToolBase interface */ + +protected: + + /** The settings object shown in the details panel */ + UClothPaintTool_BrushSettings* Settings; + + /** Called when the paint action is applied */ + void PaintAction(FPerVertexPaintActionArgs& InArgs, int32 VertexIndex, FMatrix InverseBrushMatrix); + +}; + +/** Unique settings for the Gradient tool */ +UCLASS() +class UClothPaintTool_GradientSettings : public UObject +{ + + GENERATED_BODY() + +public: + + UClothPaintTool_GradientSettings() + : GradientStartValue(0.0f) + , GradientEndValue(100.0f) + , bUseRegularBrush(false) + { + + } + + /** Value of the gradient at the start points */ + UPROPERTY(EditAnywhere, Category = ToolSettings) + float GradientStartValue; + + /** Value of the gradient at the end points */ + UPROPERTY(EditAnywhere, Category = ToolSettings) + float GradientEndValue; + + /** Enables the painting of selected points using a brush rather than just a point */ + UPROPERTY(EditAnywhere, Category = ToolSettings) + bool bUseRegularBrush; +}; + +/** + * Gradient tool - Allows the user to select begin and end points to apply a gradient to. + * Pressing Enter will move from selecting begin points, to selecting end points and finally + * applying the operation to the mesh + */ +class FClothPaintTool_Gradient : public FClothPaintToolBase +{ +public: + + FClothPaintTool_Gradient(TWeakPtr InPainter) + : FClothPaintToolBase(InPainter) + , bSelectingBeginPoints(true) + , Settings(nullptr) + { + + } + + virtual ~FClothPaintTool_Gradient(); + + /* FClothPaintToolBase interface */ + virtual FText GetDisplayName() const override; + virtual bool InputKey(IMeshPaintGeometryAdapter* Adapter, FEditorViewportClient* InViewportClient, FViewport* InViewport, FKey InKey, EInputEvent InEvent) override; + virtual FPerVertexPaintAction GetPaintAction(const FMeshPaintParameters& InPaintParams, UClothPainterSettings* InPainterSettings) override; + virtual bool IsPerVertex() const override; + virtual void Render(USkeletalMeshComponent* InComponent, IMeshPaintGeometryAdapter* InAdapter, const FSceneView* View, FViewport* Viewport, FPrimitiveDrawInterface* PDI) override; + virtual bool ShouldRenderInteractors() const override; + virtual UObject* GetSettingsObject() override; + virtual void Activate(TWeakPtr InCommands) override; + virtual void Deactivate(TWeakPtr InCommands) override; + /* End FClothPaintToolBase interface */ + +protected: + + /** Whether we're selecting the start points or end points */ + bool bSelectingBeginPoints; + + /** List of vert indices to consider the start of the gradient */ + TArray GradientStartIndices; + + /** List of vert indices to consider the end of the gradient */ + TArray GradientEndIndices; + + /** The settings object shown in the details panel */ + UClothPaintTool_GradientSettings* Settings; + + /** Called when the paint action is applied */ + void PaintAction(FPerVertexPaintActionArgs& InArgs, int32 VertexIndex, FMatrix InverseBrushMatrix); + + /** Applies the gradient to the currently selected points */ + void ApplyGradient(); + + /** Whether we can currently apply a gradient */ + bool CanApplyGradient(); + +}; + +/** Unique settings for the smoothing tool */ +UCLASS() +class UClothPaintTool_SmoothSettings : public UObject +{ + GENERATED_BODY() + +public: + + UClothPaintTool_SmoothSettings() + : Strength(0.2f) + { + + } + + /** Strength of the smoothing effect */ + UPROPERTY(EditAnywhere, Category = ToolSettings, meta=(UIMin="0.0", UIMax="1.0", ClampMin="0.0", ClampMax="1.0")) + float Strength; +}; + +/** + * Smoothing tool, applies a blur similar to a box blur (even distribution of neighbors) + * Modulated by strength from settings object + */ +class FClothPaintTool_Smooth : public FClothPaintToolBase +{ +public: + + FClothPaintTool_Smooth(TWeakPtr InPainter) + : FClothPaintToolBase(InPainter) + , Settings(nullptr) + { + + } + + virtual ~FClothPaintTool_Smooth(); + + virtual FPerVertexPaintAction GetPaintAction(const FMeshPaintParameters& InPaintParams, UClothPainterSettings* InPainterSettings) override; + virtual FText GetDisplayName() const override; + virtual UObject* GetSettingsObject() override; + virtual bool IsPerVertex() const override; + +protected: + + void PaintAction(FPerVertexPaintActionArgs& InArgs, int32 VertexIndex, FMatrix InverseBrushMatrix); + + UClothPaintTool_SmoothSettings* Settings; +}; + +/** Unique settings for the fill tool */ +UCLASS() +class UClothPaintTool_FillSettings : public UObject +{ + GENERATED_BODY() + +public: + + /** Threshold for fill operation, will keep filling until sampled verts aren't within this range of the original vertex */ + UPROPERTY(EditAnywhere, Category = ToolSettings) + float Threshold; + + /** The value to fill all selected verts to */ + UPROPERTY(EditAnywhere, Category = ToolSettings) + float FillValue; +}; + +/** + * Basic fill tool with thresholding for changing the parameter values for a large area of similar cloth + */ +class FClothPaintTool_Fill : public FClothPaintToolBase +{ +public: + + FClothPaintTool_Fill(TWeakPtr InPainter) + : FClothPaintToolBase(InPainter) + , Settings(nullptr) + , QueryRadius(20.0f) // No brush available for fill, gives decent range to get closest point to cursor. + { + + } + + virtual ~FClothPaintTool_Fill(); + + /* FClothPaintToolBase interface */ + virtual FPerVertexPaintAction GetPaintAction(const FMeshPaintParameters& InPaintParams, UClothPainterSettings* InPainterSettings) override; + virtual FText GetDisplayName() const override; + virtual UObject* GetSettingsObject() override; + virtual bool IsPerVertex() const override; + virtual bool ShouldRenderInteractors() const override; + virtual void Render(USkeletalMeshComponent* InComponent, IMeshPaintGeometryAdapter* InAdapter, const FSceneView* View, FViewport* Viewport, FPrimitiveDrawInterface* PDI) override; + /* End FClothPaintToolBase interface */ + +protected: + + /** Called to apply the fill action */ + void PaintAction(FPerVertexPaintActionArgs& InArgs, int32 VertexIndex, FMatrix InverseBrushMatrix); + + /** Settings for the paint operation */ + UClothPaintTool_FillSettings* Settings; + + /** Radius to query for points (will choose nearest point in this set) */ + float QueryRadius; +}; diff --git a/Engine/Source/Editor/ClothPainter/Private/ClothPainter.cpp b/Engine/Source/Editor/ClothPainter/Private/ClothPainter.cpp index 4e5581d836fc..4b26aadb0d2e 100644 --- a/Engine/Source/Editor/ClothPainter/Private/ClothPainter.cpp +++ b/Engine/Source/Editor/ClothPainter/Private/ClothPainter.cpp @@ -15,13 +15,18 @@ #include "EditorViewportClient.h" #include "ComponentReregisterContext.h" #include "Package.h" +#include "ClothPaintTools.h" +#include "UICommandList.h" +#include "SlateApplication.h" #define LOCTEXT_NAMESPACE "ClothPainter" FClothPainter::FClothPainter() - : IMeshPainter(), SkeletalMeshComponent(nullptr), PaintSettings(nullptr), BrushSettings(nullptr), bSelectingFirstPoint(true) + : IMeshPainter() + , SkeletalMeshComponent(nullptr) + , PaintSettings(nullptr) + , BrushSettings(nullptr) { - Init(); VertexPointSize = 3.0f; VertexPointColor = FLinearColor::White; WidgetLineThickness = .5f; @@ -49,6 +54,16 @@ void FClothPainter::Init() PaintSettings->OnAssetSelectionChanged.AddRaw(this, &FClothPainter::OnAssetSelectionChanged); + CommandList = MakeShareable(new FUICommandList); + + Tools.Add(MakeShared(AsShared())); + Tools.Add(MakeShared(AsShared())); + Tools.Add(MakeShared(AsShared())); + Tools.Add(MakeShared(AsShared())); + + SelectedTool = Tools[0]; + SelectedTool->Activate(CommandList); + Widget = SNew(SClothPaintWidget, this); } @@ -64,9 +79,8 @@ bool FClothPainter::PaintInternal(const FVector& InCameraOrigin, const FVector& if (HitResult.bBlockingHit) { - if (PaintSettings->PaintTool == EClothPaintTool::Brush) - { - if (!IsPainting()) + // Generic per-vertex painting operations + if(!IsPainting()) { BeginTransaction(LOCTEXT("MeshPaint", "Painting Cloth Property Values")); bArePainting = true; @@ -74,52 +88,22 @@ bool FClothPainter::PaintInternal(const FVector& InCameraOrigin, const FVector& } const FMeshPaintParameters Parameters = CreatePaintParameters(HitResult, InCameraOrigin, InRayOrigin, InRayDirection, PaintStrength); - bApplied = MeshPaintHelpers::ApplyPerVertexPaintAction(Adapter.Get(), InCameraOrigin, HitResult.Location, GetBrushSettings(), FPerVertexPaintAction::CreateRaw(this, &FClothPainter::ApplyPropertyPaint, Parameters.InverseBrushToWorldMatrix, PaintSettings->PaintingProperty)); - } - else if (PaintSettings->PaintTool == EClothPaintTool::Gradient) - { - const FMatrix ComponentToWorldMatrix = HitResult.Component->ComponentToWorld.ToMatrixWithScale(); - const FVector ComponentSpaceCameraPosition(ComponentToWorldMatrix.InverseTransformPosition(InCameraOrigin)); - const FVector ComponentSpaceBrushPosition(ComponentToWorldMatrix.InverseTransformPosition(HitResult.Location)); - const float ComponentSpaceBrushRadius = ComponentToWorldMatrix.InverseTransformVector(FVector(PaintSettings->bUseRegularBrushForGradient ? BrushSettings->GetBrushRadius() : 2.0f, 0.0f, 0.0f)).Size(); - const float ComponentSpaceSquaredBrushRadius = ComponentSpaceBrushRadius * ComponentSpaceBrushRadius; + FPerVertexPaintActionArgs Args; + Args.Adapter = Adapter.Get(); + Args.CameraPosition = InCameraOrigin; + Args.HitResult = HitResult; + Args.BrushSettings = GetBrushSettings(); + Args.Action = PaintAction; + + if(SelectedTool->IsPerVertex()) + { + bApplied = MeshPaintHelpers::ApplyPerVertexPaintAction(Args, GetPaintAction(Parameters)); + } + else + { bApplied = true; - bArePainting = true; - - TArray InRangeVertices = Adapter->SphereIntersectVertices(ComponentSpaceSquaredBrushRadius, ComponentSpaceBrushPosition, ComponentSpaceCameraPosition, GetBrushSettings()->bOnlyFrontFacingTriangles); - if (InRangeVertices.Num()) - { - InRangeVertices.Sort([=](const FVector& PointOne, const FVector& PointTwo) - { - return (PointOne - ComponentSpaceBrushPosition).SizeSquared() < (PointTwo - ComponentSpaceBrushPosition).SizeSquared(); - }); - - - InRangeVertices.Sort([=](const FVector& PointOne, const FVector& PointTwo) - { - return (PointOne - ComponentSpaceBrushPosition).SizeSquared() < (PointTwo - ComponentSpaceBrushPosition).SizeSquared(); - }); - - if (!PaintSettings->bUseRegularBrushForGradient) - { - InRangeVertices.SetNum(1); - } - - TArray& GradientPoints = bSelectingFirstPoint ? GradientStartPoints : GradientEndPoints; - - for (const FVector& Vertex : InRangeVertices) - { - if (PaintAction == EMeshPaintAction::Erase && GradientPoints.Contains(Vertex)) - { - GradientPoints.Remove(Vertex); - } - else if (PaintAction == EMeshPaintAction::Paint) - { - GradientPoints.Add(Vertex); - } - } - } + GetPaintAction(Parameters).ExecuteIfBound(Args, INDEX_NONE); } } } @@ -127,65 +111,34 @@ bool FClothPainter::PaintInternal(const FVector& InCameraOrigin, const FVector& return bApplied; } -void FClothPainter::ApplyGradient() +FPerVertexPaintAction FClothPainter::GetPaintAction(const FMeshPaintParameters& InPaintParams) { - BeginTransaction(LOCTEXT("MeshPaintGradientApply", "Gradient Property Painting")); - Adapter->PreEdit(); - - // Apply gradient - const TArray Vertices = Adapter->GetMeshVertices(); - for (int32 VertexIndex = 0; VertexIndex < Vertices.Num(); ++VertexIndex) + if(SelectedTool.IsValid()) { - const FVector& Vertex = Vertices[VertexIndex]; - - // Find distances to closest begin and end gradient vert - float DistanceToStart = FLT_MAX; - for (int32 GradientIndex = 0; GradientIndex < GradientStartPoints.Num(); ++GradientIndex) - { - const float CurrentDistance = (GradientStartPoints[GradientIndex] - Vertex).SizeSquared(); - if (CurrentDistance < DistanceToStart) - { - DistanceToStart = CurrentDistance; - } - } - - float DistanceToEnd = FLT_MAX; - for (int32 GradientIndex = 0; GradientIndex < GradientEndPoints.Num(); ++GradientIndex) - { - const float CurrentDistance = (GradientEndPoints[GradientIndex] - Vertex).SizeSquared(); - if (CurrentDistance < DistanceToEnd) - { - DistanceToEnd = CurrentDistance; - } - } - - // Lerp between the two gradient values according to the distances - const float Value = FMath::LerpStable(PaintSettings->GradientStartValue, PaintSettings->GradientEndValue, DistanceToStart / (DistanceToStart + DistanceToEnd)); - SetPropertyValue(VertexIndex, Value, PaintSettings->PaintingProperty); + return SelectedTool->GetPaintAction(InPaintParams, PaintSettings); } - - EndTransaction(); - Adapter->PostEdit(); + return FPerVertexPaintAction(); +} - GradientStartPoints.Empty(); - GradientEndPoints.Empty(); +void FClothPainter::SetTool(TSharedPtr InTool) +{ + if(InTool.IsValid() && Tools.Contains(InTool)) + { + if(SelectedTool.IsValid()) + { + SelectedTool->Deactivate(CommandList); + } - bSelectingFirstPoint = true; + SelectedTool = InTool; + SelectedTool->Activate(CommandList); + } } void FClothPainter::SetSkeletalMeshComponent(UDebugSkelMeshComponent* InSkeletalMeshComponent) { TSharedPtr Result = MakeShareable(new FClothMeshPaintAdapter()); - if (Result->Construct(InSkeletalMeshComponent, 0)) - { - Adapter = Result; - } - else - { - Adapter = nullptr; - } - + Result->Construct(InSkeletalMeshComponent, 0); Adapter = Result; SkeletalMeshComponent = InSkeletalMeshComponent; @@ -222,10 +175,26 @@ void FClothPainter::RefreshClothingAssets() void FClothPainter::Tick(FEditorViewportClient* ViewportClient, float DeltaTime) { IMeshPainter::Tick(ViewportClient, DeltaTime); - SkeletalMeshComponent->SetVisibleClothProperty((int32)PaintSettings->PaintingProperty); + + SkeletalMeshComponent->MinClothPropertyView = PaintSettings->GetViewMin(); + SkeletalMeshComponent->MaxClothPropertyView = PaintSettings->GetViewMax(); if ((bShouldSimulate && SkeletalMeshComponent->bDisableClothSimulation) || (!bShouldSimulate && !SkeletalMeshComponent->bDisableClothSimulation)) { + if(bShouldSimulate) + { + // Need to re-apply our masks here, as they have likely been edited + for(UClothingAsset* Asset : PaintSettings->ClothingAssets) + { + if(Asset) + { + Asset->ApplyParameterMasks(); + } + } + + SkeletalMeshComponent->RebuildClothingSectionsFixedVerts(); + } + FComponentReregisterContext ReregisterContext(SkeletalMeshComponent); SkeletalMeshComponent->ToggleMeshSectionForCloth(SkeletalMeshComponent->SelectedClothingGuidForPainting); SkeletalMeshComponent->bDisableClothSimulation = !bShouldSimulate; @@ -243,7 +212,7 @@ void FClothPainter::Tick(FEditorViewportClient* ViewportClient, float DeltaTime) void FClothPainter::FinishPainting() { - if (IsPainting() && PaintSettings->PaintTool == EClothPaintTool::Brush) + if (IsPainting()) { EndTransaction(); Adapter->PostEdit(); @@ -267,6 +236,11 @@ void FClothPainter::FinishPainting() void FClothPainter::Reset() { + if(Widget.IsValid()) + { + Widget->Reset(); + } + bArePainting = false; SkeletalMeshComponent->ToggleMeshSectionForCloth(SkeletalMeshComponent->SelectedClothingGuidForPainting); SkeletalMeshComponent->SelectedClothingGuidForPainting = FGuid(); @@ -312,8 +286,7 @@ const FHitResult FClothPainter::GetHitResult(const FVector& Origin, const FVecto if (Adapter.IsValid()) { - static FName TraceName(TEXT("FClothPainter::GetHitResult")); - Adapter->LineTraceComponent(HitResult, TraceStart, TraceEnd, FCollisionQueryParams(TraceName, true)); + Adapter->LineTraceComponent(HitResult, TraceStart, TraceEnd, FCollisionQueryParams(SCENE_QUERY_STAT(FClothPainter_GetHitResult), true)); } return HitResult; @@ -322,7 +295,6 @@ const FHitResult FClothPainter::GetHitResult(const FVector& Origin, const FVecto void FClothPainter::Refresh() { RefreshClothingAssets(); - if(Widget.IsValid()) { Widget->OnRefresh(); @@ -331,75 +303,28 @@ void FClothPainter::Refresh() void FClothPainter::Render(const FSceneView* View, FViewport* Viewport, FPrimitiveDrawInterface* PDI) { - if (PaintSettings->PaintTool == EClothPaintTool::Brush || (PaintSettings->PaintTool == EClothPaintTool::Gradient && PaintSettings->bUseRegularBrushForGradient)) + if(SelectedTool.IsValid() && SelectedTool->ShouldRenderInteractors()) { - RenderInteractors(View, Viewport, PDI, true, ( bShowHiddenVerts && PaintSettings->PaintTool == EClothPaintTool::Brush) ? SDPG_Foreground : SDPG_World); + RenderInteractors(View, Viewport, PDI, true, SDPG_Foreground); } const ESceneDepthPriorityGroup DepthPriority = bShowHiddenVerts ? SDPG_Foreground : SDPG_World; // Render simulation mesh vertices if not simulating - if (SkeletalMeshComponent && !bShouldSimulate) + if(SkeletalMeshComponent) { - const FMatrix ComponentToWorldMatrix = SkeletalMeshComponent->ComponentToWorld.ToMatrixWithScale(); + if(!bShouldSimulate) + { + const FMatrix ComponentToWorldMatrix = SkeletalMeshComponent->GetComponentTransform().ToMatrixWithScale(); const TArray& AllVertices = Adapter->GetMeshVertices(); - for (const FVector& Vertex : AllVertices) + for(const FVector& Vertex : AllVertices) { const FVector WorldPositionVertex = ComponentToWorldMatrix.TransformPosition(Vertex); PDI->DrawPoint(WorldPositionVertex, VertexPointColor, VertexPointSize, DepthPriority); } - } - if (SkeletalMeshComponent && PaintSettings->PaintTool == EClothPaintTool::Gradient && !bShouldSimulate) - { - TArray PaintRays; - MeshPaintHelpers::RetrieveViewportPaintRays(View, Viewport, PDI, PaintRays); - - const FMatrix ComponentToWorldMatrix = SkeletalMeshComponent->ComponentToWorld.ToMatrixWithScale(); - - for (const MeshPaintHelpers::FPaintRay& PaintRay : PaintRays) - { - for (const FVector& Vertex : GradientStartPoints) - { - const FVector WorldPositionVertex = ComponentToWorldMatrix.TransformPosition(Vertex); - PDI->DrawPoint(WorldPositionVertex, FLinearColor::Green, VertexPointSize * 2.0f, DepthPriority); - } - - for (const FVector& Vertex : GradientEndPoints) - { - const FVector WorldPositionVertex = ComponentToWorldMatrix.TransformPosition(Vertex); - PDI->DrawPoint(WorldPositionVertex, FLinearColor::Red, VertexPointSize * 2.0f, DepthPriority); - } - - - const FHitResult& HitResult = GetHitResult(PaintRay.RayStart, PaintRay.RayDirection); - if (HitResult.Component == SkeletalMeshComponent) - { - const FVector ComponentSpaceCameraPosition(ComponentToWorldMatrix.InverseTransformPosition(PaintRay.CameraLocation)); - const FVector ComponentSpaceBrushPosition(ComponentToWorldMatrix.InverseTransformPosition(HitResult.Location)); - const float ComponentSpaceBrushRadius = ComponentToWorldMatrix.InverseTransformVector(FVector(PaintSettings->bUseRegularBrushForGradient ? BrushSettings->GetBrushRadius() : 2.0f, 0.0f, 0.0f)).Size(); - const float ComponentSpaceSquaredBrushRadius = ComponentSpaceBrushRadius * ComponentSpaceBrushRadius; - - // Draw hovered vertex - TArray InRangeVertices = Adapter->SphereIntersectVertices(ComponentSpaceSquaredBrushRadius, ComponentSpaceBrushPosition, ComponentSpaceCameraPosition, GetBrushSettings()->bOnlyFrontFacingTriangles); - InRangeVertices.Sort([=](const FVector& PointOne, const FVector& PointTwo) - { - return (PointOne - ComponentSpaceBrushPosition).SizeSquared() < (PointTwo - ComponentSpaceBrushPosition).SizeSquared(); - }); - - - if (InRangeVertices.Num()) - { - if (!PaintSettings->bUseRegularBrushForGradient) + if(SelectedTool.IsValid()) { - InRangeVertices.SetNum(1); - } - - for (const FVector& Vertex : InRangeVertices) - { - const FVector WorldPositionVertex = ComponentToWorldMatrix.TransformPosition(Vertex); - PDI->DrawPoint(WorldPositionVertex, bSelectingFirstPoint ? FLinearColor::Green : FLinearColor::Red, VertexPointSize * 2.0f, SDPG_Foreground); - } - } + SelectedTool->Render(SkeletalMeshComponent, Adapter.Get(), View, Viewport, PDI); } } } @@ -411,21 +336,17 @@ void FClothPainter::Render(const FSceneView* View, FViewport* Viewport, FPrimiti bool FClothPainter::InputKey(FEditorViewportClient* InViewportClient, FViewport* InViewport, FKey InKey, EInputEvent InEvent) { bool bHandled = IMeshPainter::InputKey(InViewportClient, InViewport, InKey, InEvent); - if (InKey == EKeys::Enter) + + if(SelectedTool.IsValid()) { - if (PaintSettings->PaintTool == EClothPaintTool::Gradient) + if(CommandList->ProcessCommandBindings(InKey, FSlateApplication::Get().GetModifierKeys(), InEvent == IE_Repeat)) { - if (bSelectingFirstPoint == true && GradientStartPoints.Num() > 0) - { - bSelectingFirstPoint = false; - bHandled = true; - } - else if (GradientEndPoints.Num() > 0) - { - // Apply gradient? - ApplyGradient(); - bHandled = true; - } + bHandled = true; + } + else + { + // Handle non-action based key actions (holds etc.) + bHandled |= SelectedTool->InputKey(Adapter.Get(), InViewportClient, InViewport, InKey, InEvent); } } @@ -464,85 +385,49 @@ FMeshPaintParameters FClothPainter::CreatePaintParameters(const FHitResult& HitR return Params; } -void FClothPainter::ApplyPropertyPaint(IMeshPaintGeometryAdapter* InAdapter, int32 VertexIndex, FMatrix InverseBrushMatrix, EPaintableClothProperty Property) -{ - FClothMeshPaintAdapter* ClothAdapter = (FClothMeshPaintAdapter*)InAdapter; - if (ClothAdapter) - { - FVector Position; - Adapter->GetVertexPosition(VertexIndex, Position); - Position = Adapter->GetComponentToWorldMatrix().TransformPosition(Position); - - float Value = GetPropertyValue(VertexIndex, Property); - const float BrushRadius = BrushSettings->GetBrushRadius(); - MeshPaintHelpers::ApplyBrushToVertex(Position, InverseBrushMatrix, BrushRadius * BrushRadius, BrushSettings->BrushFalloffAmount, PaintSettings->PaintValue, Value); - SetPropertyValue(VertexIndex, Value, Property); - } -} - -float FClothPainter::GetPropertyValue(int32 VertexIndex, EPaintableClothProperty Property) +float FClothPainter::GetPropertyValue(int32 VertexIndex) { FClothMeshPaintAdapter* ClothAdapter = (FClothMeshPaintAdapter*)Adapter.Get(); - switch (Property) + + if(FClothParameterMask_PhysMesh* Mask = ClothAdapter->GetCurrentMask()) { - case EPaintableClothProperty::MaxDistances: - { - return ClothAdapter->GetMaxDistanceValue(VertexIndex); - } - - case EPaintableClothProperty::BackstopDistances: - { - return ClothAdapter->GetBackstopDistanceValue(VertexIndex); - } - - case EPaintableClothProperty::BackstopRadius: - { - return ClothAdapter->GetBackstopRadiusValue(VertexIndex); - } + return Mask->GetValue(VertexIndex); } return 0.0f; } -void FClothPainter::SetPropertyValue(int32 VertexIndex, const float Value, EPaintableClothProperty Property) +void FClothPainter::SetPropertyValue(int32 VertexIndex, const float Value) { - FClothMeshPaintAdapter* ClothAdapter = (FClothMeshPaintAdapter*)Adapter.Get(); - switch (Property) + FClothMeshPaintAdapter* ClothAdapter = (FClothMeshPaintAdapter*)Adapter.Get(); + + if(FClothParameterMask_PhysMesh* Mask = ClothAdapter->GetCurrentMask()) { - case EPaintableClothProperty::MaxDistances: - { - ClothAdapter->SetMaxDistanceValue(VertexIndex, Value); - break; - } - - case EPaintableClothProperty::BackstopDistances: - { - ClothAdapter->SetBackstopDistanceValue(VertexIndex, Value); - break; - } - - case EPaintableClothProperty::BackstopRadius: - { - ClothAdapter->SetBackstopRadiusValue(VertexIndex, Value); - break; - } + Mask->SetValue(VertexIndex, Value); } } -void FClothPainter::OnAssetSelectionChanged(UClothingAsset* InNewSelectedAsset, int32 InAssetLod) +void FClothPainter::OnAssetSelectionChanged(UClothingAsset* InNewSelectedAsset, int32 InAssetLod, int32 InMaskIndex) { TSharedPtr ClothAdapter = StaticCastSharedPtr(Adapter); if(ClothAdapter.IsValid() && InNewSelectedAsset && InNewSelectedAsset->IsValidLod(InAssetLod)) { - const FGuid NewGuid = InNewSelectedAsset ? InNewSelectedAsset->GetAssetGuid() : FGuid(); - SkeletalMeshComponent->ToggleMeshSectionForCloth(SkeletalMeshComponent->SelectedClothingGuidForPainting); - SkeletalMeshComponent->ToggleMeshSectionForCloth(NewGuid); + // Validate the incoming parameters, to make sure we only set a selection if we're going + // to get a valid paintable surface + if(InNewSelectedAsset->LodData.IsValidIndex(InAssetLod) && + InNewSelectedAsset->LodData[InAssetLod].ParameterMasks.IsValidIndex(InMaskIndex)) + { + const FGuid NewGuid = InNewSelectedAsset->GetAssetGuid(); + SkeletalMeshComponent->ToggleMeshSectionForCloth(SkeletalMeshComponent->SelectedClothingGuidForPainting); + SkeletalMeshComponent->ToggleMeshSectionForCloth(NewGuid); - SkeletalMeshComponent->SelectedClothingGuidForPainting = NewGuid; - SkeletalMeshComponent->SelectedClothingLodForPainting = InAssetLod; - SkeletalMeshComponent->RefreshSelectedClothingSkinnedPositions(); + SkeletalMeshComponent->SelectedClothingGuidForPainting = NewGuid; + SkeletalMeshComponent->SelectedClothingLodForPainting = InAssetLod; + SkeletalMeshComponent->SelectedClothingLodMaskForPainting = InMaskIndex; + SkeletalMeshComponent->RefreshSelectedClothingSkinnedPositions(); - ClothAdapter->SetSelectedClothingAsset(NewGuid, InAssetLod); + ClothAdapter->SetSelectedClothingAsset(NewGuid, InAssetLod, InMaskIndex); + } } } diff --git a/Engine/Source/Editor/ClothPainter/Private/ClothPainter.h b/Engine/Source/Editor/ClothPainter/Private/ClothPainter.h index eee7e1c92535..5df6701a0816 100644 --- a/Engine/Source/Editor/ClothPainter/Private/ClothPainter.h +++ b/Engine/Source/Editor/ClothPainter/Private/ClothPainter.h @@ -5,6 +5,7 @@ #include "IMeshPainter.h" #include "MeshPaintTypes.h" +#include "MeshPaintHelpers.h" class SClothPaintWidget; class UClothPainterSettings; @@ -12,16 +13,24 @@ class UPaintBrushSettings; class UClothingAsset; class UDebugSkelMeshComponent; enum class EPaintableClothProperty; +class FClothPaintToolBase; -class FClothPainter : public IMeshPainter +class FClothPainter : public IMeshPainter, public TSharedFromThis { public: + FClothPainter(); ~FClothPainter(); + void Init(); + protected: + virtual bool PaintInternal(const FVector& InCameraOrigin, const FVector& InRayOrigin, const FVector& InRayDirection, EMeshPaintAction PaintAction, float PaintStrength) override; + public: + + /** IMeshPainter interface */ virtual void Tick(FEditorViewportClient* ViewportClient, float DeltaTime) override; virtual void FinishPainting() override; virtual void ActorSelected(AActor* Actor) override {}; @@ -36,6 +45,7 @@ public: virtual void Refresh() override; virtual void Render(const FSceneView* View, FViewport* Viewport, FPrimitiveDrawInterface* PDI) override; virtual bool InputKey(FEditorViewportClient* InViewportClient, FViewport* InViewport, FKey InKey, EInputEvent InEvent) override; + /** End IMeshPainter interface */ /** Sets the debug skeletal mesh to which we should currently paint */ void SetSkeletalMeshComponent(UDebugSkelMeshComponent* SkeletalMeshComponent); @@ -43,25 +53,38 @@ public: /** Creates paint parameters for the current setup */ FMeshPaintParameters CreatePaintParameters(const struct FHitResult& HitResult, const FVector& InCameraOrigin, const FVector& InRayOrigin, const FVector& InRayDirection, float PaintStrength); -protected: - /** Apply per vertex painting of the given Clothing Property */ - void ApplyPropertyPaint(IMeshPaintGeometryAdapter* InAdapter, int32 Vertexindex, FMatrix InverseBrushMatrix, EPaintableClothProperty Property); - /** Retrieves the property value from the Cloth asset for the given EPaintableClothProperty */ - float GetPropertyValue(int32 VertexIndex, EPaintableClothProperty Property); + float GetPropertyValue(int32 VertexIndex); /** Sets the EPaintableClothProperty property within the Clothing asset to Value */ - void SetPropertyValue(int32 VertexIndex, const float Value, EPaintableClothProperty Property); + void SetPropertyValue(int32 VertexIndex, const float Value); + + /** Some complex clothing tools (gradients) require the ability to override these flags in different ways */ + void SetIsPainting(bool bInPainting) { bArePainting = bInPainting; } + + /** Get the selected paint tool */ + const TSharedPtr GetSelectedTool() const { return SelectedTool; } + + /** Gets the current geometry adapter */ + TSharedPtr GetAdapter() const { return Adapter; } + +protected: /** When a different clothing asset is selected in the UI the painter should refresh the adapter */ - void OnAssetSelectionChanged(UClothingAsset* InNewSelectedAsset, int32 InAssetLod); + void OnAssetSelectionChanged(UClothingAsset* InNewSelectedAsset, int32 InAssetLod, int32 MaskIndex); void OnAssetMaskSelectionChanged() {}; /** Rebuild the list of editable clothing assets from the current mesh */ void RefreshClothingAssets(); - /** Applies a gradient to all sim points between GradientStartPoints and GradientEndPoints */ - void ApplyGradient(); + /** Get the action defined by the selected tool that we should run when we paint */ + FPerVertexPaintAction GetPaintAction(const FMeshPaintParameters& InPaintParams); + + /** + * Sets the currently selected paint tool + * NOTE: InTool *must* have been registered by adding it to the Tools array + */ + void SetTool(TSharedPtr InTool); protected: /** Current adapter used to paint the clothing properties */ @@ -75,15 +98,20 @@ protected: /** Cloth brush settings instance */ UPaintBrushSettings* BrushSettings; - /** Array of points which define the start of the gradient */ - TArray GradientStartPoints; - /** Array of points which define the end of the gradient */ - TArray GradientEndPoints; - /** Toggle for selecting start and end gradient points*/ - bool bSelectingFirstPoint; - /** Flag whether or not the simulation should run */ bool bShouldSimulate; /** Flag to render (hidden) sim verts during gradient painting */ bool bShowHiddenVerts; + + /** The currently selected painting tool */ + TSharedPtr SelectedTool; + + /** List of currently registered paint tools */ + TArray> Tools; + + /** List of commands for the painter, tools can bind to this in activate */ + TSharedPtr CommandList; + + /** Our customization class can access private painter state */ + friend class FClothPaintSettingsCustomization; }; \ No newline at end of file diff --git a/Engine/Source/Editor/ClothPainter/Private/ClothPainterCommands.cpp b/Engine/Source/Editor/ClothPainter/Private/ClothPainterCommands.cpp new file mode 100644 index 000000000000..7b7d0c787363 --- /dev/null +++ b/Engine/Source/Editor/ClothPainter/Private/ClothPainterCommands.cpp @@ -0,0 +1,14 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "ClothPainterCommands.h" + +void FClothPainterCommands::RegisterCommands() +{ + +} + +const FClothPainterCommands& FClothPainterCommands::Get() +{ + return TCommands::Get(); +} + diff --git a/Engine/Source/Editor/ClothPainter/Private/ClothPainterCommands.h b/Engine/Source/Editor/ClothPainter/Private/ClothPainterCommands.h new file mode 100644 index 000000000000..547bc9829ba1 --- /dev/null +++ b/Engine/Source/Editor/ClothPainter/Private/ClothPainterCommands.h @@ -0,0 +1,22 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "EditorStyleSet.h" +#include "Framework/Commands/Commands.h" + +class FClothPainterCommands : public TCommands +{ +public: + FClothPainterCommands() + : TCommands(TEXT("ClothPainter"), NSLOCTEXT("Contexts", "ClothPainter", "Cloth Painter"), NAME_None, FEditorStyle::GetStyleSetName()) + { + + } + + virtual void RegisterCommands() override; + static const FClothPainterCommands& Get(); + + /** Clothing commands */ +}; \ No newline at end of file diff --git a/Engine/Source/Editor/ClothPainter/Private/ClothPaintingModule.cpp b/Engine/Source/Editor/ClothPainter/Private/ClothPaintingModule.cpp index ece2c7dad2d0..9e33cff946a8 100644 --- a/Engine/Source/Editor/ClothPainter/Private/ClothPaintingModule.cpp +++ b/Engine/Source/Editor/ClothPainter/Private/ClothPaintingModule.cpp @@ -15,6 +15,7 @@ #include "PropertyEditorModule.h" #include "ClothPaintSettingsCustomization.h" #include "Settings/EditorExperimentalSettings.h" +#include "ClothPaintToolCommands.h" #define LOCTEXT_NAMESPACE "ClothPaintingModule" @@ -59,6 +60,9 @@ void FClothPaintingModule::StartupModule() { SetupMode(); } + + // Register any commands for the cloth painter + ClothPaintToolCommands::RegisterClothPaintToolCommands(); } void FClothPaintingModule::SetupMode() diff --git a/Engine/Source/Editor/ClothPainter/Private/ClothingPaintEditMode.cpp b/Engine/Source/Editor/ClothPainter/Private/ClothingPaintEditMode.cpp index 4d58b356b417..cc0653fcac54 100644 --- a/Engine/Source/Editor/ClothPainter/Private/ClothingPaintEditMode.cpp +++ b/Engine/Source/Editor/ClothPainter/Private/ClothingPaintEditMode.cpp @@ -12,12 +12,22 @@ #include "ClothingAssetInterface.h" #include "ComponentRecreateRenderStateContext.h" #include "IPersonaToolkit.h" +#include "ClothingAsset.h" FClothingPaintEditMode::FClothingPaintEditMode() { } +FClothingPaintEditMode::~FClothingPaintEditMode() +{ + if(ClothPainter.IsValid()) + { + // Drop the reference + ClothPainter = nullptr; + } +} + class IPersonaPreviewScene* FClothingPaintEditMode::GetAnimPreviewScene() const { return static_cast(static_cast(Owner)->GetPreviewScene()); @@ -25,7 +35,10 @@ class IPersonaPreviewScene* FClothingPaintEditMode::GetAnimPreviewScene() const void FClothingPaintEditMode::Initialize() { - MeshPainter = ClothPainter = new FClothPainter(); + ClothPainter = MakeShared(); + MeshPainter = ClothPainter.Get(); + + ClothPainter->Init(); } TSharedPtr FClothingPaintEditMode::GetToolkit() @@ -47,6 +60,7 @@ void FClothingPaintEditMode::Enter() ClothPainter->SetSkeletalMeshComponent(Scene->GetPreviewMeshComponent()); } + ClothPainter->Reset(); } void FClothingPaintEditMode::Exit() @@ -64,13 +78,16 @@ void FClothingPaintEditMode::Exit() { for(UClothingAssetBase* AssetBase : SkelMesh->MeshClothingAssets) { - AssetBase->InvalidateCachedData(); + UClothingAsset* ConcreteAsset = CastChecked(AssetBase); + ConcreteAsset->ApplyParameterMasks(); } } MeshComponent->RebuildClothingSectionsFixedVerts(); MeshComponent->ResetMeshSectionVisibility(); MeshComponent->SelectedClothingGuidForPainting = FGuid(); + MeshComponent->SelectedClothingLodForPainting = INDEX_NONE; + MeshComponent->SelectedClothingLodMaskForPainting = INDEX_NONE; } } diff --git a/Engine/Source/Editor/ClothPainter/Private/ClothingPaintEditMode.h b/Engine/Source/Editor/ClothPainter/Private/ClothingPaintEditMode.h index a47c9b04e099..61820d960c0f 100644 --- a/Engine/Source/Editor/ClothPainter/Private/ClothingPaintEditMode.h +++ b/Engine/Source/Editor/ClothPainter/Private/ClothingPaintEditMode.h @@ -15,6 +15,7 @@ class FClothingPaintEditMode : public IMeshPaintEdMode { public: FClothingPaintEditMode(); + virtual ~FClothingPaintEditMode(); virtual void Initialize() override; virtual bool UsesToolkits() const override { return false; } @@ -27,7 +28,7 @@ public: protected: - FClothPainter* ClothPainter; + TSharedPtr ClothPainter; class IPersonaPreviewScene* GetAnimPreviewScene() const; class TSharedPtr PersonaToolkit; diff --git a/Engine/Source/Editor/ClothPainter/Private/SClothPaintTab.cpp b/Engine/Source/Editor/ClothPainter/Private/SClothPaintTab.cpp index a107b21bda7c..b91c98ef2257 100644 --- a/Engine/Source/Editor/ClothPainter/Private/SClothPaintTab.cpp +++ b/Engine/Source/Editor/ClothPainter/Private/SClothPaintTab.cpp @@ -117,9 +117,10 @@ void SClothPaintTab::UpdatePaintTools() SkeletalMeshEditor->GetAssetEditorModeManager()->ActivateMode(PaintModeID, true); FClothingPaintEditMode* PaintMode = (FClothingPaintEditMode*)SkeletalMeshEditor->GetAssetEditorModeManager()->FindMode(PaintModeID); - ModeWidget = PaintMode->GetMeshPainter()->GetWidget(); if (PaintMode) { + PaintMode->GetMeshPainter()->Reset(); + ModeWidget = PaintMode->GetMeshPainter()->GetWidget(); PaintMode->SetPersonaToolKit(SkeletalMeshEditor->GetPersonaToolkit()); ContentBox->AddSlot() diff --git a/Engine/Source/Editor/ClothPainter/Private/SClothPaintWidget.cpp b/Engine/Source/Editor/ClothPainter/Private/SClothPaintWidget.cpp index 2a1c9465f66e..3a15f5a675c0 100644 --- a/Engine/Source/Editor/ClothPainter/Private/SClothPaintWidget.cpp +++ b/Engine/Source/Editor/ClothPainter/Private/SClothPaintWidget.cpp @@ -12,12 +12,13 @@ #include "MeshPaintSettings.h" #include "ClothPainter.h" #include "ClothPaintSettings.h" -#include "SComboBox.h" #include "ClothingAsset.h" #include "SUniformGridPanel.h" #include "SInlineEditableTextBlock.h" #include "MultiBoxBuilder.h" #include "SButton.h" +#include "ClothPaintToolBase.h" +#include "SCheckBox.h" #define LOCTEXT_NAMESPACE "ClothPaintWidget" @@ -40,11 +41,20 @@ public: SMultiColumnTableRow>::Construct(FSuperRowType::FArguments(), InOwnerTable); } + static FName Column_Enabled; static FName Column_MaskName; static FName Column_CurrentTarget; virtual TSharedRef GenerateWidgetForColumn(const FName& InColumnName) override { + if(InColumnName == Column_Enabled) + { + return SNew(SCheckBox) + .IsEnabled(this, &SMaskListRow::IsMaskCheckboxEnabled, Item) + .IsChecked(this, &SMaskListRow::IsMaskEnabledChecked, Item) + .OnCheckStateChanged(this, &SMaskListRow::OnMaskEnabledCheckboxChanged, Item); + } + if(InColumnName == Column_MaskName) { return SAssignNew(InlineText, SInlineEditableTextBlock) @@ -230,6 +240,12 @@ private: { Mask->CurrentTarget = (MaskTarget_PhysMesh)InTargetEntryIndex; + if(Mask->CurrentTarget == MaskTarget_PhysMesh::None) + { + // Make sure to disable this mask if it has no valid target + Mask->bEnabled = false; + } + OnInvalidateList.ExecuteIfBound(); } } @@ -258,17 +274,95 @@ private: Builder.EndSection(); } + // Mask enabled checkbox handling + ECheckBoxState IsMaskEnabledChecked(TSharedPtr InItem) const + { + if(InItem.IsValid()) + { + if(FClothParameterMask_PhysMesh* Mask = InItem->GetMask()) + { + return Mask->bEnabled ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; + } + } + + return ECheckBoxState::Unchecked; + } + + bool IsMaskCheckboxEnabled(TSharedPtr InItem) const + { + if(InItem.IsValid()) + { + if(FClothParameterMask_PhysMesh* Mask = InItem->GetMask()) + { + return Mask->CurrentTarget != MaskTarget_PhysMesh::None; + } + } + + return false; + } + + void OnMaskEnabledCheckboxChanged(ECheckBoxState InState, TSharedPtr InItem) + { + if(InItem.IsValid()) + { + if(FClothParameterMask_PhysMesh* Mask = InItem->GetMask()) + { + bool bNewEnableState = InState == ECheckBoxState::Checked; + + if(Mask->bEnabled != bNewEnableState) + { + if(bNewEnableState) + { + // Disable all other masks that affect this target + if(UClothingAsset* Asset = InItem->ClothingAsset.Get()) + { + if(Asset->LodData.IsValidIndex(InItem->LodIndex)) + { + FClothLODData& LodData = Asset->LodData[InItem->LodIndex]; + + TArray AllTargetMasks; + LodData.GetParameterMasksForTarget(Mask->CurrentTarget, AllTargetMasks); + + for(FClothParameterMask_PhysMesh* TargetMask : AllTargetMasks) + { + if(TargetMask && TargetMask != Mask) + { + TargetMask->bEnabled = false; + } + } + } + } + } + + // Set the flag + Mask->bEnabled = bNewEnableState; + } + } + } + } + FSimpleDelegate OnInvalidateList; TSharedPtr Item; TSharedPtr InlineText; }; + +FName SMaskListRow::Column_Enabled(TEXT("Enabled")); FName SMaskListRow::Column_MaskName(TEXT("MaskName")); FName SMaskListRow::Column_CurrentTarget(TEXT("CurrentTarget")); void SClothPaintWidget::Construct(const FArguments& InArgs, FClothPainter* InPainter) { - Objects.Add(InPainter->GetBrushSettings()); - Objects.Add(InPainter->GetPainterSettings()); + Painter = InPainter; + + Objects.Add(Painter->GetBrushSettings()); + Objects.Add(Painter->GetPainterSettings()); + + UObject* ToolSettings = Painter->GetSelectedTool()->GetSettingsObject(); + if(ToolSettings) + { + Objects.Add(ToolSettings); + } + ClothPainterSettings = Cast(InPainter->GetPainterSettings()); CreateDetailsView(InPainter); @@ -303,6 +397,8 @@ void SClothPaintWidget::Construct(const FArguments& InArgs, FClothPainter* InPai .ListItemsSource(&AssetListItems) .OnGenerateRow(this, &SClothPaintWidget::OnGenerateWidgetForClothingAssetItem) .OnSelectionChanged(this, &SClothPaintWidget::OnAssetListSelectionChanged) + .ClearSelectionOnClick(false) + .SelectionMode(ESelectionMode::Single) .HeaderRow ( SNew(SHeaderRow) @@ -329,7 +425,7 @@ void SClothPaintWidget::Construct(const FArguments& InArgs, FClothPainter* InPai + SHorizontalBox::Slot() .HAlign(HAlign_Left) [ - SNew(SComboBox>) + SAssignNew(LodList, SLodList) .OnGenerateWidget(this, &SClothPaintWidget::OnGenerateWidgetForLodItem) .OnSelectionChanged(this, &SClothPaintWidget::OnClothingLodChanged) .OptionsSource(&LodListItems) @@ -375,14 +471,19 @@ void SClothPaintWidget::Construct(const FArguments& InArgs, FClothPainter* InPai .ListItemsSource(&MaskListItems) .OnGenerateRow(this, &SClothPaintWidget::OnGenerateWidgetForMaskItem) .OnSelectionChanged(this, &SClothPaintWidget::OnMaskSelectionChanged) + .ClearSelectionOnClick(false) + .SelectionMode(ESelectionMode::Single) .HeaderRow ( SNew(SHeaderRow) + + SHeaderRow::Column(SMaskListRow::Column_Enabled) + .FixedWidth(24) + .DefaultLabel(LOCTEXT("MaskListHeader_Enabled", "Enabled")) + SHeaderRow::Column(SMaskListRow::Column_MaskName) - .FillWidth(0.6f) + .FillWidth(0.5f) .DefaultLabel(LOCTEXT("MaskListHeader_Name", "Mask")) + SHeaderRow::Column(SMaskListRow::Column_CurrentTarget) - .FillWidth(0.4f) + .FillWidth(0.3f) .DefaultLabel(LOCTEXT("MaskListHeader_Target", "Target")) ) ] @@ -431,6 +532,8 @@ void SClothPaintWidget::CreateDetailsView(FClothPainter* InPainter) DetailsView = EditModule.CreateDetailView(DetailsViewArgs); DetailsView->SetRootObjectCustomizationInstance(MakeShareable(new FClothPaintSettingsRootObjectCustomization)); DetailsView->RegisterInstancedCustomPropertyLayout(UClothPainterSettings::StaticClass(), FOnGetDetailCustomizationInstance::CreateStatic(&FClothPaintSettingsCustomization::MakeInstance, InPainter)); + DetailsView->RegisterInstancedCustomPropertyLayout(UPaintBrushSettings::StaticClass(), FOnGetDetailCustomizationInstance::CreateStatic(&FClothPaintBrushSettingsCustomization::MakeInstance)); + DetailsView->SetObjects(Objects, true); } @@ -440,24 +543,155 @@ void SClothPaintWidget::OnRefresh() RefreshClothingLodItems(); RefreshMaskListItems(); - if(AssetList.IsValid()) - { - AssetList->RequestListRefresh(); - } - - if(MaskList.IsValid()) - { - MaskList->RequestListRefresh(); - } - if(DetailsView.IsValid()) { + Objects.Reset(); + + Objects.Add(Painter->GetPainterSettings()); + + UObject* ToolSettings = Painter->GetSelectedTool()->GetSettingsObject(); + if(ToolSettings) + { + Objects.Add(ToolSettings); + } + + Objects.Add(Painter->GetBrushSettings()); + DetailsView->SetObjects(Objects, true); } } +void SClothPaintWidget::Reset() +{ + SelectedAsset = nullptr; + SelectedLod = INDEX_NONE; + SelectedMask = INDEX_NONE; + + if(MaskList.IsValid()) + { + MaskList->ClearSelection(); + } + + if(LodList.IsValid()) + { + LodList->ClearSelection(); + } + + if(AssetList.IsValid()) + { + AssetList->ClearSelection(); + } + + OnRefresh(); +} + +void SClothPaintWidget::SetSelectedAsset(TWeakObjectPtr InSelectedAsset) +{ + SelectedAsset = InSelectedAsset; + + RefreshClothingLodItems(); + + if(UClothingAsset* NewAsset = SelectedAsset.Get()) + { + if(NewAsset->LodData.Num() > 0) + { + SetSelectedLod(0); + + FClothLODData& LodData = NewAsset->LodData[SelectedLod]; + if(LodData.ParameterMasks.Num() > 0) + { + SetSelectedMask(0); + } + else + { + SetSelectedMask(INDEX_NONE); + } + } + else + { + SetSelectedLod(INDEX_NONE); + SetSelectedMask(INDEX_NONE); + } + + ClothPainterSettings->OnAssetSelectionChanged.Broadcast(NewAsset, SelectedLod, SelectedMask); + } +} + +void SClothPaintWidget::SetSelectedMask(int32 InMaskIndex) +{ + if(MaskList.IsValid()) + { + TSharedPtr* FoundItem = nullptr; + if(InMaskIndex != INDEX_NONE) + { + // Find the item so we can select it in the list + FoundItem = MaskListItems.FindByPredicate([&](const TSharedPtr& InItem) + { + return InItem->MaskIndex == InMaskIndex; + }); + } + + if(FoundItem) + { + MaskList->SetSelection(*FoundItem); + } + else + { + MaskList->ClearSelection(); + } + } + + SelectedMask = InMaskIndex; +} + +void SClothPaintWidget::SetSelectedLod(int32 InLodIndex, bool bRefreshMasks) +{ + if(LodList.IsValid()) + { + TSharedPtr* FoundItem = nullptr; + if(InLodIndex != INDEX_NONE) + { + FoundItem = LodListItems.FindByPredicate([&](const TSharedPtr& InItem) + { + return InItem->Lod == InLodIndex; + }); + } + + if(FoundItem) + { + LodList->SetSelectedItem(*FoundItem); + } + else + { + LodList->ClearSelection(); + } + } + + SelectedLod = InLodIndex; + + if(MaskList.IsValid() && bRefreshMasks) + { + // New LOD means new set of masks, refresh that list + RefreshMaskListItems(); + } +} + void SClothPaintWidget::RefreshClothingAssetListItems() { + UClothingAsset* CurrSelectedAsset = nullptr; + int32 SelectedItem = INDEX_NONE; + + if(AssetList.IsValid()) + { + TArray> SelectedItems; + AssetList->GetSelectedItems(SelectedItems); + + if(SelectedItems.Num() > 0) + { + CurrSelectedAsset = SelectedItems[0]->ClothingAsset.Get(); + } + } + AssetListItems.Empty(); for(UClothingAsset* Asset : ClothPainterSettings->ClothingAssets) @@ -467,6 +701,11 @@ void SClothPaintWidget::RefreshClothingAssetListItems() Entry->ClothingAsset = Asset; AssetListItems.Add(Entry); + + if(Asset == CurrSelectedAsset) + { + SelectedItem = AssetListItems.Num() - 1; + } } if(AssetListItems.Num() == 0) @@ -474,6 +713,16 @@ void SClothPaintWidget::RefreshClothingAssetListItems() // Add an invalid entry so we can show a "none" line AssetListItems.Add(MakeShareable(new FClothingAssetListItem)); } + + if(AssetList.IsValid()) + { + AssetList->RequestListRefresh(); + + if(SelectedItem != INDEX_NONE) + { + AssetList->SetSelection(AssetListItems[SelectedItem]); + } + } } TSharedRef SClothPaintWidget::OnGenerateWidgetForClothingAssetItem(TSharedPtr InItem, const TSharedRef& OwnerTable) @@ -498,24 +747,8 @@ void SClothPaintWidget::OnAssetListSelectionChanged(TSharedPtrClothingAsset; - - if(UClothingAsset* NewAsset = SelectedAsset.Get()) - { - if(NewAsset->LodData.Num() > 0) - { - SelectedLod = 0; - } - else - { - SelectedLod = INDEX_NONE; - } - - ClothPainterSettings->OnAssetSelectionChanged.Broadcast(NewAsset, SelectedLod); - } + SetSelectedAsset(InSelectedItem->ClothingAsset); } - - RefreshClothingLodItems(); } void SClothPaintWidget::RefreshClothingLodItems() @@ -543,6 +776,11 @@ void SClothPaintWidget::RefreshClothingLodItems() LodListItems.Add(NewItem); } + + if(LodList.IsValid()) + { + LodList->RefreshOptions(); + } } TSharedRef SClothPaintWidget::OnGenerateWidgetForLodItem(TSharedPtr InItem) @@ -573,19 +811,49 @@ void SClothPaintWidget::OnClothingLodChanged(TSharedPtr I { if(InSelectedItem.IsValid()) { - SelectedLod = InSelectedItem->Lod; + SetSelectedLod(InSelectedItem->Lod); + + int32 NewMaskSelection = INDEX_NONE; + if(SelectedAsset->LodData.IsValidIndex(SelectedLod)) + { + FClothLODData& LodData = SelectedAsset->LodData[SelectedLod]; + + if(LodData.ParameterMasks.Num() > 0) + { + NewMaskSelection = 0; + } + } + + SetSelectedMask(NewMaskSelection); } else { - SelectedLod = INDEX_NONE; + SetSelectedLod(INDEX_NONE); } - ClothPainterSettings->OnAssetSelectionChanged.Broadcast(SelectedAsset.Get(), SelectedLod); + ClothPainterSettings->OnAssetSelectionChanged.Broadcast(SelectedAsset.Get(), SelectedLod, SelectedMask); } } void SClothPaintWidget::RefreshMaskListItems() { + int32 CurrSelectedLod = INDEX_NONE; + int32 CurrSelectedMask = INDEX_NONE; + int32 SelectedItem = INDEX_NONE; + + if(MaskList.IsValid()) + { + TArray> SelectedItems; + + MaskList->GetSelectedItems(SelectedItems); + + if(SelectedItems.Num() > 0) + { + CurrSelectedLod = SelectedItems[0]->LodIndex; + CurrSelectedMask = SelectedItems[0]->MaskIndex; + } + } + MaskListItems.Empty(); UClothingAsset* Asset = SelectedAsset.Get(); @@ -601,6 +869,12 @@ void SClothPaintWidget::RefreshMaskListItems() NewItem->LodIndex = SelectedLod; NewItem->MaskIndex = Index; MaskListItems.Add(NewItem); + + if(NewItem->LodIndex == CurrSelectedLod && + NewItem->MaskIndex == CurrSelectedMask) + { + SelectedItem = MaskListItems.Num() - 1; + } } } @@ -610,6 +884,16 @@ void SClothPaintWidget::RefreshMaskListItems() TSharedPtr NewItem = MakeShareable(new FClothingMaskListItem); MaskListItems.Add(NewItem); } + + if(MaskList.IsValid()) + { + MaskList->RequestListRefresh(); + + if(SelectedItem != INDEX_NONE) + { + MaskList->SetSelection(MaskListItems[SelectedItem]); + } + } } TSharedRef SClothPaintWidget::OnGenerateWidgetForMaskItem(TSharedPtr InItem, const TSharedRef& OwnerTable) @@ -628,7 +912,10 @@ TSharedRef SClothPaintWidget::OnGenerateWidgetForMaskItem(TSharedPtr< void SClothPaintWidget::OnMaskSelectionChanged(TSharedPtr InSelectedItem, ESelectInfo::Type InSelectInfo) { - // To be implemented for mask hookup to painter + if(InSelectedItem.IsValid() && InSelectedItem->ClothingAsset.IsValid() && InSelectedItem->LodIndex != INDEX_NONE && InSelectedItem->MaskIndex != INDEX_NONE) + { + ClothPainterSettings->OnAssetSelectionChanged.Broadcast(InSelectedItem->ClothingAsset.Get(), InSelectedItem->LodIndex, InSelectedItem->MaskIndex); + } } FReply SClothPaintWidget::AddNewMask() diff --git a/Engine/Source/Editor/ClothPainter/Private/SClothPaintWidget.h b/Engine/Source/Editor/ClothPainter/Private/SClothPaintWidget.h index cdc691537099..6d50ec80d1ba 100644 --- a/Engine/Source/Editor/ClothPainter/Private/SClothPaintWidget.h +++ b/Engine/Source/Editor/ClothPainter/Private/SClothPaintWidget.h @@ -5,6 +5,7 @@ #include "DeclarativeSyntaxSupport.h" #include "Widgets/SCompoundWidget.h" #include "SListView.h" +#include "SComboBox.h" class IDetailsView; class FClothPainter; @@ -49,14 +50,39 @@ public: // Refresh the widget such as when entering the paint mode void OnRefresh(); + // Resets the selections and puts the widget back to starting state + void Reset(); + + // Currently selected clothing asset, Lod Index and Mask index + TWeakObjectPtr SelectedAsset; + int32 SelectedLod; + int32 SelectedMask; + protected: + + // Details view placed below asset selection TSharedPtr DetailsView; + + // Objects observed in the details view TArray Objects; + // The painter instance this widget is using + FClothPainter* Painter; + + // Settings for the painter instance UClothPainterSettings* ClothPainterSettings; - // Asset List handling + // Setters for the list selections so we can handle list selections changing properly + void SetSelectedAsset(TWeakObjectPtr InSelectedAsset); + void SetSelectedLod(int32 InLodIndex, bool bRefreshMasks = true); + void SetSelectedMask(int32 InMaskIndex); + + // List types for this panel typedef SListView> SAssetList; + typedef SListView> SMaskList; + typedef SComboBox> SLodList; + + // Asset List handling void RefreshClothingAssetListItems(); TSharedRef OnGenerateWidgetForClothingAssetItem(TSharedPtr InItem, const TSharedRef& OwnerTable); void OnAssetListSelectionChanged(TSharedPtr InSelectedItem, ESelectInfo::Type InSelectInfo); @@ -70,7 +96,6 @@ protected: void OnClothingLodChanged(TSharedPtr InSelectedItem, ESelectInfo::Type InSelectInfo); // Mask list handling - typedef SListView> SMaskList; void RefreshMaskListItems(); TSharedRef OnGenerateWidgetForMaskItem(TSharedPtr InItem, const TSharedRef& OwnerTable); void OnMaskSelectionChanged(TSharedPtr InSelectedItem, ESelectInfo::Type InSelectInfo); @@ -80,9 +105,8 @@ protected: FReply AddNewMask(); bool CanAddNewMask() const; - TWeakObjectPtr SelectedAsset; - int32 SelectedLod; - + // List widgets for asset, lod and mask tracked for refreshing TSharedPtr AssetList; TSharedPtr MaskList; + TSharedPtr LodList; }; \ No newline at end of file diff --git a/Engine/Source/Editor/ClothingSystemEditor/Private/ClothingAssetFactory.cpp b/Engine/Source/Editor/ClothingSystemEditor/Private/ClothingAssetFactory.cpp index 9161a90c35b1..38e2ca809910 100644 --- a/Engine/Source/Editor/ClothingSystemEditor/Private/ClothingAssetFactory.cpp +++ b/Engine/Source/Editor/ClothingSystemEditor/Private/ClothingAssetFactory.cpp @@ -17,6 +17,8 @@ #include "PhysicsEngine/SphereElem.h" #include "ComponentReregisterContext.h" #include "Components/SkeletalMeshComponent.h" +#include "SNotificationList.h" +#include "NotificationManager.h" #define LOCTEXT_NAMESPACE "ClothingAssetFactory" DEFINE_LOG_CATEGORY(LogClothingAssetFactory) @@ -255,6 +257,7 @@ UClothingAssetBase* UClothingAssetFactory::CreateFromSkeletalMesh(USkeletalMesh* FString SanitizedName = ObjectTools::SanitizeObjectName(Params.AssetName); FName ObjectName = MakeUniqueObjectName(TargetMesh, UClothingAsset::StaticClass(), FName(*SanitizedName)); UClothingAsset* NewAsset = NewObject(TargetMesh, ObjectName); + NewAsset->SetFlags(RF_Transactional); // Adding a new LOD from this skeletal mesh NewAsset->LodData.AddDefaulted(); @@ -368,6 +371,12 @@ UClothingAssetBase* UClothingAssetFactory::CreateFromSkeletalMesh(USkeletalMesh* } } + // Add a max distance parameter mask to begin with + LodData.ParameterMasks.AddDefaulted(); + FClothParameterMask_PhysMesh& Mask = LodData.ParameterMasks.Last(); + Mask.CopyFromPhysMesh(PhysMesh, MaskTarget_PhysMesh::MaxDistance); + Mask.bEnabled = true; + PhysMesh.MaxBoneWeights = SourceSection.MaxBoneInfluences; FMultiSizeIndexContainerData IndexData; @@ -378,6 +387,31 @@ UClothingAssetBase* UClothingAssetFactory::CreateFromSkeletalMesh(USkeletalMesh* PhysMesh.Indices[IndexIndex] = IndexRemap[PhysMesh.Indices[IndexIndex]]; } + // Validate the generated triangles. If the source mesh has colinear triangles then clothing simulation will fail + const int32 NumTriangles = PhysMesh.Indices.Num() / 3; + for(int32 TriIndex = 0; TriIndex < NumTriangles; ++TriIndex) + { + FVector A = PhysMesh.Vertices[PhysMesh.Indices[TriIndex * 3 + 0]]; + FVector B = PhysMesh.Vertices[PhysMesh.Indices[TriIndex * 3 + 1]]; + FVector C = PhysMesh.Vertices[PhysMesh.Indices[TriIndex * 3 + 2]]; + + FVector TriNormal = (B - A) ^ (C - A); + if(TriNormal.SizeSquared() <= SMALL_NUMBER) + { + // This triangle is colinear + FText ErrorText = FText::Format(LOCTEXT("Colinear_Error", "Failed to generate clothing sim mesh due to degenerate triangle, found conincident vertices in triangle A={0} B={1} C={2}"), FText::FromString(A.ToString()), FText::FromString(B.ToString()), FText::FromString(C.ToString())); + + FNotificationInfo Info(ErrorText); + Info.bFireAndForget = true; + Info.ExpireDuration = 5.0f; + + FSlateNotificationManager::Get().AddNotification(Info); + UE_LOG(LogClothingAssetFactory, Warning, TEXT("%s"), *ErrorText.ToString()); + + return nullptr; + } + } + // Set asset guid NewAsset->AssetGuid = FGuid::NewGuid(); @@ -387,12 +421,8 @@ UClothingAssetBase* UClothingAssetFactory::CreateFromSkeletalMesh(USkeletalMesh* TargetMesh->RemoveMeshSection(Params.LodIndex, Params.SourceSection); } - if(UPhysicsAsset* PhysAsset = Params.PhysicsAsset.LoadSynchronous()) - { - FClothCollisionData& CollisionData = LodData.CollisionData; - - ExtractPhysicsAssetBodies(PhysAsset, TargetMesh, NewAsset, CollisionData); - } + // Set physics asset, will be used when building actors for cloth collisions + NewAsset->PhysicsAsset = Params.PhysicsAsset.LoadSynchronous(); // Build the final bone map NewAsset->RefreshBoneMapping(TargetMesh); @@ -407,6 +437,7 @@ UClothingAssetBase* UClothingAssetFactory::CreateFromApexAsset(nvidia::apex::Clo { #if WITH_APEX_CLOTHING UClothingAsset* NewClothingAsset = NewObject(TargetMesh, InName); + NewClothingAsset->SetFlags(RF_Transactional); const NvParameterized::Interface* AssetParams = InApexAsset->getAssetNvParameterized(); NvParameterized::Handle GraphicalLodArrayHandle(*AssetParams, "graphicalLods"); @@ -467,8 +498,41 @@ UClothingAssetBase* UClothingAssetFactory::CreateFromApexAsset(nvidia::apex::Clo NewClothingAsset->AssetGuid = FGuid::NewGuid(); NewClothingAsset->InvalidateCachedData(); + NewClothingAsset->BuildLodTransitionData(); - NewClothingAsset->InvalidateCachedData(); + NewClothingAsset->BuildSelfCollisionData(); + NewClothingAsset->CalculateReferenceBoneIndex(); + + // Add masks for parameters + for(FClothLODData& Lod : NewClothingAsset->LodData) + { + FClothPhysicalMeshData& PhysMesh = Lod.PhysicalMeshData; + + // Didn't do anything previously - clear out incase there's something in there + // so we can use it correctly now. + Lod.ParameterMasks.Reset(3); + + // Max distances + Lod.ParameterMasks.AddDefaulted(); + FClothParameterMask_PhysMesh& MaxDistanceMask = Lod.ParameterMasks.Last(); + MaxDistanceMask.CopyFromPhysMesh(PhysMesh, MaskTarget_PhysMesh::MaxDistance); + MaxDistanceMask.bEnabled = true; + + if(PhysMesh.BackstopRadiuses.FindByPredicate([](const float& A) {return A != 0.0f; })) + { + // Backstop radii + Lod.ParameterMasks.AddDefaulted(); + FClothParameterMask_PhysMesh& BackstopRadiusMask = Lod.ParameterMasks.Last(); + BackstopRadiusMask.CopyFromPhysMesh(PhysMesh, MaskTarget_PhysMesh::BackstopRadius); + BackstopRadiusMask.bEnabled = true; + + // Backstop distances + Lod.ParameterMasks.AddDefaulted(); + FClothParameterMask_PhysMesh& BackstopDistanceMask = Lod.ParameterMasks.Last(); + BackstopDistanceMask.CopyFromPhysMesh(PhysMesh, MaskTarget_PhysMesh::BackstopDistance); + BackstopDistanceMask.bEnabled = true; + } + } return NewClothingAsset; #endif @@ -1088,67 +1152,6 @@ void UClothingAssetFactory::ExtractMaterialParameters(UClothingAsset* NewAsset, } } -void UClothingAssetFactory::ExtractPhysicsAssetBodies(UPhysicsAsset* InPhysicsAsset, USkeletalMesh* TargetMesh, UClothingAsset* TargetClothingAsset, FClothCollisionData& OutCollisionData) -{ - if(InPhysicsAsset && TargetClothingAsset && TargetMesh) - { - USkeletalMesh* PhysAssetMesh = InPhysicsAsset->PreviewSkeletalMesh.LoadSynchronous(); - - // Validate compatibility. If we don't have a mesh for the physics asset - // We'll continue and just trust it. - if(PhysAssetMesh && PhysAssetMesh->Skeleton != TargetMesh->Skeleton) - { - UE_LOG(LogClothingAssetFactory, Warning, TEXT("Physics Asset %s is incompatible with target skeletal mesh %s, aborting physics data extraction."), *InPhysicsAsset->GetName(), *TargetMesh->GetName()); - return; - } - - // A physics asset was specified, extract compatible bodies - for(const USkeletalBodySetup* BodySetup : InPhysicsAsset->SkeletalBodySetups) - { - int32 MeshBoneIndex = TargetMesh->RefSkeleton.FindBoneIndex(BodySetup->BoneName); - int32 MappedBoneIndex = INDEX_NONE; - - if(MeshBoneIndex != INDEX_NONE) - { - MappedBoneIndex = TargetClothingAsset->UsedBoneNames.AddUnique(BodySetup->BoneName); - } - - for(const FKSphereElem& Sphere : BodySetup->AggGeom.SphereElems) - { - FClothCollisionPrim_Sphere NewSphere; - NewSphere.LocalPosition = Sphere.Center; - NewSphere.Radius = Sphere.Radius; - NewSphere.BoneIndex = MappedBoneIndex; - - OutCollisionData.Spheres.Add(NewSphere); - } - - for(const FKSphylElem& Sphyl : BodySetup->AggGeom.SphylElems) - { - FClothCollisionPrim_Sphere Sphere0; - FClothCollisionPrim_Sphere Sphere1; - FVector OrientedDirection = Sphyl.Rotation.RotateVector(FVector(0.0f, 0.0f, 1.0f)); - FVector HalfDim = OrientedDirection * (Sphyl.Length / 2.0f); - Sphere0.LocalPosition = Sphyl.Center - HalfDim; - Sphere1.LocalPosition = Sphyl.Center + HalfDim; - Sphere0.Radius = Sphyl.Radius; - Sphere1.Radius = Sphyl.Radius; - Sphere0.BoneIndex = MappedBoneIndex; - Sphere1.BoneIndex = MappedBoneIndex; - - OutCollisionData.Spheres.Add(Sphere0); - OutCollisionData.Spheres.Add(Sphere1); - - FClothCollisionPrim_SphereConnection Connection; - Connection.SphereIndices[0] = OutCollisionData.Spheres.Num() - 2; - Connection.SphereIndices[1] = OutCollisionData.Spheres.Num() - 1; - - OutCollisionData.SphereConnections.Add(Connection); - } - } - } -} - void UClothingAssetFactory::PopulateAutoFixOctree(FQueryTriOctree& OutOctree, const FStaticLODModel& InLodModel, int32 InExcludeSectionIndex /*= INDEX_NONE*/) { TArray LodVerts; diff --git a/Engine/Source/Editor/ClothingSystemEditorInterface/Public/SimulationEditorExtender.h b/Engine/Source/Editor/ClothingSystemEditorInterface/Public/SimulationEditorExtender.h index 1fd74a0cd433..74ec08f233b6 100644 --- a/Engine/Source/Editor/ClothingSystemEditorInterface/Public/SimulationEditorExtender.h +++ b/Engine/Source/Editor/ClothingSystemEditorInterface/Public/SimulationEditorExtender.h @@ -23,6 +23,7 @@ class ISimulationEditorExtender : public IModularFeature { public: + virtual ~ISimulationEditorExtender() { } /** * Called to identify the type of clothing simulation this editor extender can support. @@ -45,5 +46,4 @@ public: * @param PDI - The drawing interface to use */ virtual void DebugDrawSimulation(const IClothingSimulation* InSimulation, USkeletalMeshComponent* InOwnerComponent, FPrimitiveDrawInterface* PDI) = 0; - }; \ No newline at end of file diff --git a/Engine/Source/Editor/ComponentVisualizers/Private/ConstraintComponentVisualizer.cpp b/Engine/Source/Editor/ComponentVisualizers/Private/ConstraintComponentVisualizer.cpp index bff938431b45..5d6db5becf23 100644 --- a/Engine/Source/Editor/ComponentVisualizers/Private/ConstraintComponentVisualizer.cpp +++ b/Engine/Source/Editor/ComponentVisualizers/Private/ConstraintComponentVisualizer.cpp @@ -49,9 +49,9 @@ void FConstraintComponentVisualizer::DrawVisualization( const UActorComponent* C // Otherwise use the component frame else { - Con1Frame = ConstraintComp->ComponentToWorld; + Con1Frame = ConstraintComp->GetComponentTransform(); Con1Frame.RemoveScaling(); - Con2Frame = ConstraintComp->ComponentToWorld; + Con2Frame = ConstraintComp->GetComponentTransform(); Con2Frame.SetRotation(Con2Frame.GetRotation() * ConstraintComp->ConstraintInstance.AngularRotationOffset.Quaternion()); Con1Frame.RemoveScaling(); } diff --git a/Engine/Source/Editor/ComponentVisualizers/Private/DecalComponentVisualizer.cpp b/Engine/Source/Editor/ComponentVisualizers/Private/DecalComponentVisualizer.cpp index 828d125301d4..a497b38325f1 100644 --- a/Engine/Source/Editor/ComponentVisualizers/Private/DecalComponentVisualizer.cpp +++ b/Engine/Source/Editor/ComponentVisualizers/Private/DecalComponentVisualizer.cpp @@ -11,7 +11,7 @@ void FDecalComponentVisualizer::DrawVisualization( const UActorComponent* Compon const UDecalComponent* DecalComponent = Cast(Component); if(DecalComponent) { - const FMatrix LocalToWorld = DecalComponent->ComponentToWorld.ToMatrixWithScale(); + const FMatrix LocalToWorld = DecalComponent->GetComponentTransform().ToMatrixWithScale(); const FLinearColor DrawColor = FColor(0, 157, 0, 255); diff --git a/Engine/Source/Editor/ComponentVisualizers/Private/PointLightComponentVisualizer.cpp b/Engine/Source/Editor/ComponentVisualizers/Private/PointLightComponentVisualizer.cpp index 8766c520c5ce..faafae855d4a 100644 --- a/Engine/Source/Editor/ComponentVisualizers/Private/PointLightComponentVisualizer.cpp +++ b/Engine/Source/Editor/ComponentVisualizers/Private/PointLightComponentVisualizer.cpp @@ -13,7 +13,7 @@ void FPointLightComponentVisualizer::DrawVisualization( const UActorComponent* C const UPointLightComponent* PointLightComp = Cast(Component); if(PointLightComp != NULL) { - FTransform LightTM = PointLightComp->ComponentToWorld; + FTransform LightTM = PointLightComp->GetComponentTransform(); LightTM.RemoveScaling(); // Draw light radius diff --git a/Engine/Source/Editor/ComponentVisualizers/Private/RadialForceComponentVisualizer.cpp b/Engine/Source/Editor/ComponentVisualizers/Private/RadialForceComponentVisualizer.cpp index b08b59305989..116ded3c4ab9 100644 --- a/Engine/Source/Editor/ComponentVisualizers/Private/RadialForceComponentVisualizer.cpp +++ b/Engine/Source/Editor/ComponentVisualizers/Private/RadialForceComponentVisualizer.cpp @@ -11,7 +11,7 @@ void FRadialForceComponentVisualizer::DrawVisualization( const UActorComponent* const URadialForceComponent* ForceComp = Cast(Component); if(ForceComp != NULL) { - FTransform TM = ForceComp->ComponentToWorld; + FTransform TM = ForceComp->GetComponentTransform(); TM.RemoveScaling(); // Draw light radius diff --git a/Engine/Source/Editor/ComponentVisualizers/Private/SplineComponentVisualizer.cpp b/Engine/Source/Editor/ComponentVisualizers/Private/SplineComponentVisualizer.cpp index 498dcf4999d6..0eeb52955f8f 100644 --- a/Engine/Source/Editor/ComponentVisualizers/Private/SplineComponentVisualizer.cpp +++ b/Engine/Source/Editor/ComponentVisualizers/Private/SplineComponentVisualizer.cpp @@ -550,11 +550,11 @@ bool FSplineComponentVisualizer::GetWidgetLocation(const FEditorViewportClient* check(SelectedTangentHandleType != ESelectedTangentHandle::None); if (SelectedTangentHandleType == ESelectedTangentHandle::Leave) { - OutLocation = SplineComp->ComponentToWorld.TransformPosition(Point.OutVal + Point.LeaveTangent); + OutLocation = SplineComp->GetComponentTransform().TransformPosition(Point.OutVal + Point.LeaveTangent); } else if (SelectedTangentHandleType == ESelectedTangentHandle::Arrive) { - OutLocation = SplineComp->ComponentToWorld.TransformPosition(Point.OutVal - Point.ArriveTangent); + OutLocation = SplineComp->GetComponentTransform().TransformPosition(Point.OutVal - Point.ArriveTangent); } return true; @@ -565,7 +565,7 @@ bool FSplineComponentVisualizer::GetWidgetLocation(const FEditorViewportClient* check(LastKeyIndexSelected < Position.Points.Num()); check(SelectedKeys.Contains(LastKeyIndexSelected)); const auto& Point = Position.Points[LastKeyIndexSelected]; - OutLocation = SplineComp->ComponentToWorld.TransformPosition(Point.OutVal); + OutLocation = SplineComp->GetComponentTransform().TransformPosition(Point.OutVal); return true; } } @@ -625,17 +625,17 @@ bool FSplineComponentVisualizer::HandleInputDelta(FEditorViewportClient* Viewpor { if (SelectedTangentHandleType == ESelectedTangentHandle::Leave) { - EditedPoint.LeaveTangent += SplineComp->ComponentToWorld.InverseTransformVector(DeltaTranslate); + EditedPoint.LeaveTangent += SplineComp->GetComponentTransform().InverseTransformVector(DeltaTranslate); } else { - EditedPoint.ArriveTangent += SplineComp->ComponentToWorld.InverseTransformVector(-DeltaTranslate); + EditedPoint.ArriveTangent += SplineComp->GetComponentTransform().InverseTransformVector(-DeltaTranslate); } } else { const FVector Delta = (SelectedTangentHandleType == ESelectedTangentHandle::Leave) ? DeltaTranslate : -DeltaTranslate; - const FVector Tangent = EditedPoint.LeaveTangent + SplineComp->ComponentToWorld.InverseTransformVector(Delta); + const FVector Tangent = EditedPoint.LeaveTangent + SplineComp->GetComponentTransform().InverseTransformVector(Delta); EditedPoint.LeaveTangent = Tangent; EditedPoint.ArriveTangent = Tangent; @@ -671,11 +671,11 @@ bool FSplineComponentVisualizer::HandleInputDelta(FEditorViewportClient* Viewpor if (!DeltaTranslate.IsZero()) { // Find key position in world space - const FVector CurrentWorldPos = SplineComp->ComponentToWorld.TransformPosition(EditedPoint.OutVal); + const FVector CurrentWorldPos = SplineComp->GetComponentTransform().TransformPosition(EditedPoint.OutVal); // Move in world space const FVector NewWorldPos = CurrentWorldPos + DeltaTranslate; // Convert back to local space - EditedPoint.OutVal = SplineComp->ComponentToWorld.InverseTransformPosition(NewWorldPos); + EditedPoint.OutVal = SplineComp->GetComponentTransform().InverseTransformPosition(NewWorldPos); } if (!DeltaRotate.IsZero()) @@ -684,16 +684,16 @@ bool FSplineComponentVisualizer::HandleInputDelta(FEditorViewportClient* Viewpor EditedPoint.InterpMode = CIM_CurveUser; // Rotate tangent according to delta rotation - FVector NewTangent = SplineComp->ComponentToWorld.GetRotation().RotateVector(EditedPoint.LeaveTangent); // convert local-space tangent vector to world-space + FVector NewTangent = SplineComp->GetComponentTransform().GetRotation().RotateVector(EditedPoint.LeaveTangent); // convert local-space tangent vector to world-space NewTangent = DeltaRotate.RotateVector(NewTangent); // apply world-space delta rotation to world-space tangent - NewTangent = SplineComp->ComponentToWorld.GetRotation().Inverse().RotateVector(NewTangent); // convert world-space tangent vector back into local-space + NewTangent = SplineComp->GetComponentTransform().GetRotation().Inverse().RotateVector(NewTangent); // convert world-space tangent vector back into local-space EditedPoint.LeaveTangent = NewTangent; EditedPoint.ArriveTangent = NewTangent; // Rotate spline rotation according to delta rotation - FQuat NewRot = SplineComp->ComponentToWorld.GetRotation() * EditedRotPoint.OutVal; // convert local-space rotation to world-space + FQuat NewRot = SplineComp->GetComponentTransform().GetRotation() * EditedRotPoint.OutVal; // convert local-space rotation to world-space NewRot = DeltaRotate.Quaternion() * NewRot; // apply world-space rotation - NewRot = SplineComp->ComponentToWorld.GetRotation().Inverse() * NewRot; // convert world-space rotation to local-space + NewRot = SplineComp->GetComponentTransform().GetRotation().Inverse() * NewRot; // convert world-space rotation to local-space EditedRotPoint.OutVal = NewRot; } @@ -894,7 +894,7 @@ void FSplineComponentVisualizer::OnAddKey() FInterpCurvePoint NewPoint( SelectedSegmentIndex, - SplineComp->ComponentToWorld.InverseTransformPosition(SelectedSplinePosition), + SplineComp->GetComponentTransform().InverseTransformPosition(SelectedSplinePosition), FVector::ZeroVector, FVector::ZeroVector, CIM_CurveAuto); diff --git a/Engine/Source/Editor/ComponentVisualizers/Private/SplineMeshComponentVisualizer.cpp b/Engine/Source/Editor/ComponentVisualizers/Private/SplineMeshComponentVisualizer.cpp index 67ea6acf761f..0daf587e8a49 100644 --- a/Engine/Source/Editor/ComponentVisualizers/Private/SplineMeshComponentVisualizer.cpp +++ b/Engine/Source/Editor/ComponentVisualizers/Private/SplineMeshComponentVisualizer.cpp @@ -52,8 +52,8 @@ void FSplineMeshComponentVisualizer::DrawVisualization(const UActorComponent* Co // Draw the tangent handles before anything else so they will not overdraw the rest of the spline for (int32 PointIndex = 0; PointIndex < 2; PointIndex++) { - const FVector KeyPos = SplineMeshComp->ComponentToWorld.TransformPosition(Spline.Points[PointIndex].OutVal); - const FVector TangentWorldDirection = SplineMeshComp->ComponentToWorld.TransformVector(Spline.Points[PointIndex].LeaveTangent); + const FVector KeyPos = SplineMeshComp->GetComponentTransform().TransformPosition(Spline.Points[PointIndex].OutVal); + const FVector TangentWorldDirection = SplineMeshComp->GetComponentTransform().TransformVector(Spline.Points[PointIndex].LeaveTangent); PDI->SetHitProxy(NULL); DrawDashedLine(PDI, KeyPos, KeyPos + TangentWorldDirection, Color, 5, SDPG_Foreground); @@ -68,17 +68,17 @@ void FSplineMeshComponentVisualizer::DrawVisualization(const UActorComponent* Co // Draw the keypoints for (int32 PointIndex = 0; PointIndex < 2; PointIndex++) { - const FVector NewKeyPos = SplineMeshComp->ComponentToWorld.TransformPosition(Spline.Points[PointIndex].OutVal); + const FVector NewKeyPos = SplineMeshComp->GetComponentTransform().TransformPosition(Spline.Points[PointIndex].OutVal); PDI->SetHitProxy(new HSplineMeshKeyProxy(Component, PointIndex)); PDI->DrawPoint(NewKeyPos, Color, GrabHandleSize, SDPG_Foreground); PDI->SetHitProxy(NULL); } // Draw the spline - FVector StartPos = SplineMeshComp->ComponentToWorld.TransformPosition(Spline.Points[0].OutVal); + FVector StartPos = SplineMeshComp->GetComponentTransform().TransformPosition(Spline.Points[0].OutVal); for (int32 Step = 1; Step < 32; Step++) { - const FVector EndPos = SplineMeshComp->ComponentToWorld.TransformPosition(Spline.Eval(Step / 32.0f, FVector::ZeroVector)); + const FVector EndPos = SplineMeshComp->GetComponentTransform().TransformPosition(Spline.Eval(Step / 32.0f, FVector::ZeroVector)); PDI->DrawLine(StartPos, EndPos, Color, SDPG_Foreground); StartPos = EndPos; } @@ -170,11 +170,11 @@ bool FSplineMeshComponentVisualizer::GetWidgetLocation(const FEditorViewportClie check(SelectedTangentHandleType != ESelectedTangentHandle::None); if (SelectedTangentHandleType == ESelectedTangentHandle::Leave) { - OutLocation = SplineMeshComp->ComponentToWorld.TransformPosition(Point.OutVal + Point.LeaveTangent); + OutLocation = SplineMeshComp->GetComponentTransform().TransformPosition(Point.OutVal + Point.LeaveTangent); } else if (SelectedTangentHandleType == ESelectedTangentHandle::Arrive) { - OutLocation = SplineMeshComp->ComponentToWorld.TransformPosition(Point.OutVal - Point.ArriveTangent); + OutLocation = SplineMeshComp->GetComponentTransform().TransformPosition(Point.OutVal - Point.ArriveTangent); } return true; @@ -184,7 +184,7 @@ bool FSplineMeshComponentVisualizer::GetWidgetLocation(const FEditorViewportClie // Otherwise use the last key index set check(SelectedKey < 2); const auto& Point = Spline.Points[SelectedKey]; - OutLocation = SplineMeshComp->ComponentToWorld.TransformPosition(Point.OutVal); + OutLocation = SplineMeshComp->GetComponentTransform().TransformPosition(Point.OutVal); return true; } } @@ -220,7 +220,7 @@ bool FSplineMeshComponentVisualizer::GetCustomInputCoordinateSystem(const FEdito const FVector Bitangent = (Tangent.Z == 1.0f) ? FVector(1.0f, 0.0f, 0.0f) : FVector(-Tangent.Y, Tangent.X, 0.0f).GetSafeNormal(); const FVector Normal = FVector::CrossProduct(Tangent, Bitangent); - OutMatrix = FMatrix(Tangent, Bitangent, Normal, FVector::ZeroVector) * FQuatRotationTranslationMatrix(SplineMeshComp->ComponentToWorld.GetRotation(), FVector::ZeroVector); + OutMatrix = FMatrix(Tangent, Bitangent, Normal, FVector::ZeroVector) * FQuatRotationTranslationMatrix(SplineMeshComp->GetComponentTransform().GetRotation(), FVector::ZeroVector); return true; } } @@ -247,7 +247,7 @@ bool FSplineMeshComponentVisualizer::HandleInputDelta(FEditorViewportClient* Vie check(SelectedTangentHandleType != ESelectedTangentHandle::None); const FVector Delta = (SelectedTangentHandleType == ESelectedTangentHandle::Leave) ? DeltaTranslate : -DeltaTranslate; - const FVector NewTangent = OldTangent + SplineMeshComp->ComponentToWorld.InverseTransformVector(Delta); + const FVector NewTangent = OldTangent + SplineMeshComp->GetComponentTransform().InverseTransformVector(Delta); SplineMeshComp->Modify(); @@ -279,11 +279,11 @@ bool FSplineMeshComponentVisualizer::HandleInputDelta(FEditorViewportClient* Vie if (!DeltaTranslate.IsZero()) { // Find key position in world space - const FVector CurrentWorldPos = SplineMeshComp->ComponentToWorld.TransformPosition(KeyPosition); + const FVector CurrentWorldPos = SplineMeshComp->GetComponentTransform().TransformPosition(KeyPosition); // Move in world space const FVector NewWorldPos = CurrentWorldPos + DeltaTranslate; // Convert back to local space - KeyPosition = SplineMeshComp->ComponentToWorld.InverseTransformPosition(NewWorldPos); + KeyPosition = SplineMeshComp->GetComponentTransform().InverseTransformPosition(NewWorldPos); bModifiedPosition = true; } diff --git a/Engine/Source/Editor/ComponentVisualizers/Private/SpotLightComponentVisualizer.cpp b/Engine/Source/Editor/ComponentVisualizers/Private/SpotLightComponentVisualizer.cpp index 61044ca4d1b0..a00e3b226813 100644 --- a/Engine/Source/Editor/ComponentVisualizers/Private/SpotLightComponentVisualizer.cpp +++ b/Engine/Source/Editor/ComponentVisualizers/Private/SpotLightComponentVisualizer.cpp @@ -13,7 +13,7 @@ void FSpotLightComponentVisualizer::DrawVisualization( const UActorComponent* Co const USpotLightComponent* SpotLightComp = Cast(Component); if(SpotLightComp != NULL) { - FTransform TransformNoScale = SpotLightComp->ComponentToWorld; + FTransform TransformNoScale = SpotLightComp->GetComponentTransform(); TransformNoScale.RemoveScaling(); // Draw point light source shape diff --git a/Engine/Source/Editor/ComponentVisualizers/Private/StereoLayerComponentVisualizer.cpp b/Engine/Source/Editor/ComponentVisualizers/Private/StereoLayerComponentVisualizer.cpp index 5d5701a9ec7d..81eb83dded52 100644 --- a/Engine/Source/Editor/ComponentVisualizers/Private/StereoLayerComponentVisualizer.cpp +++ b/Engine/Source/Editor/ComponentVisualizers/Private/StereoLayerComponentVisualizer.cpp @@ -17,15 +17,15 @@ void FStereoLayerComponentVisualizer::DrawVisualization( const UActorComponent* const FVector2D QuadSize = StereoLayerComp->GetQuadSize() / 2.0f; const FBox QuadBox(FVector(0.0f, -QuadSize.X, -QuadSize.Y), FVector(0.0f, QuadSize.X, QuadSize.Y)); - DrawWireBox(PDI, StereoLayerComp->ComponentToWorld.ToMatrixWithScale(), QuadBox, YellowColor, 0); + DrawWireBox(PDI, StereoLayerComp->GetComponentTransform().ToMatrixWithScale(), QuadBox, YellowColor, 0); } else if(StereoLayerComp->StereoLayerShape == EStereoLayerShape::SLSH_CylinderLayer) { float ArcAngle = StereoLayerComp->CylinderOverlayArc * 180 / (StereoLayerComp->CylinderRadius * PI); - FVector X = StereoLayerComp->ComponentToWorld.GetUnitAxis(EAxis::Type::X); - FVector Y = StereoLayerComp->ComponentToWorld.GetUnitAxis(EAxis::Type::Y); - FVector Base = StereoLayerComp->ComponentToWorld.GetLocation(); + FVector X = StereoLayerComp->GetComponentTransform().GetUnitAxis(EAxis::Type::X); + FVector Y = StereoLayerComp->GetComponentTransform().GetUnitAxis(EAxis::Type::Y); + FVector Base = StereoLayerComp->GetComponentTransform().GetLocation(); FVector HalfHeight = FVector(0, 0, StereoLayerComp->CylinderHeight/2); FVector LeftVertex = Base + StereoLayerComp->CylinderRadius * ( FMath::Cos(ArcAngle/2 * (PI/180.0f)) * X + FMath::Sin(ArcAngle/2 * (PI/180.0f)) * Y ); diff --git a/Engine/Source/Editor/ContentBrowser/Private/AssetContextMenu.cpp b/Engine/Source/Editor/ContentBrowser/Private/AssetContextMenu.cpp index 7b0598ba2e48..09da4ea80b08 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/AssetContextMenu.cpp +++ b/Engine/Source/Editor/ContentBrowser/Private/AssetContextMenu.cpp @@ -2668,7 +2668,7 @@ void FAssetContextMenu::ExecuteAssignChunkID() const FVector2D CursorPos = FSlateApplication::Get().GetCursorPos(); FSlateRect Anchor(CursorPos.X, CursorPos.Y, CursorPos.X, CursorPos.Y); - FVector2D AdjustedSummonLocation = FSlateApplication::Get().CalculatePopupWindowPosition(Anchor, SColorPicker::DEFAULT_WINDOW_SIZE, Orient_Horizontal); + FVector2D AdjustedSummonLocation = FSlateApplication::Get().CalculatePopupWindowPosition(Anchor, SColorPicker::DEFAULT_WINDOW_SIZE, FVector2D::ZeroVector, Orient_Horizontal); TSharedPtr Window = SNew(SWindow) .AutoCenter(EAutoCenter::None) diff --git a/Engine/Source/Editor/ContentBrowser/Private/AssetViewWidgets.cpp b/Engine/Source/Editor/ContentBrowser/Private/AssetViewWidgets.cpp index 3c4f3e4111e6..e34c2a02fdc9 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/AssetViewWidgets.cpp +++ b/Engine/Source/Editor/ContentBrowser/Private/AssetViewWidgets.cpp @@ -25,7 +25,6 @@ #include "AutoReimport/AssetSourceFilenameCache.h" #include "CollectionViewUtils.h" #include "DragAndDrop/AssetDragDropOp.h" -#include "DragAndDrop/AssetPathDragDropOp.h" #include "DragDropHandler.h" #include "Internationalization/BreakIterator.h" #include "Widgets/Text/SInlineEditableTextBlock.h" @@ -380,8 +379,7 @@ void SAssetViewItem::Construct( const FArguments& InArgs ) ShouldAllowToolTip = InArgs._ShouldAllowToolTip; ThumbnailEditMode = InArgs._ThumbnailEditMode; HighlightText = InArgs._HighlightText; - OnAssetsDragDropped = InArgs._OnAssetsDragDropped; - OnPathsDragDropped = InArgs._OnPathsDragDropped; + OnAssetsOrPathsDragDropped = InArgs._OnAssetsOrPathsDragDropped; OnFilesDragDropped = InArgs._OnFilesDragDropped; OnGetCustomAssetToolTip = InArgs._OnGetCustomAssetToolTip; OnVisualizeAssetToolTip = InArgs._OnVisualizeAssetToolTip; @@ -463,8 +461,6 @@ void SAssetViewItem::OnDragLeave( const FDragDropEvent& DragDropEvent ) DragDropOp->ResetToDefaultToolTip(); } } - - bDraggedOver = false; } bDraggedOver = false; @@ -496,16 +492,11 @@ FReply SAssetViewItem::OnDrop( const FGeometry& MyGeometry, const FDragDropEvent OnFilesDragDropped.ExecuteIfBound(DragDropOp->GetFiles(), StaticCastSharedPtr(AssetItem)->FolderPath); return FReply::Handled(); } - else if (Operation->IsOfType()) - { - TSharedPtr DragDropOp = StaticCastSharedPtr(Operation); - OnPathsDragDropped.ExecuteIfBound(DragDropOp->PathNames, StaticCastSharedPtr(AssetItem)->FolderPath); - return FReply::Handled(); - } - else if (Operation->IsOfType()) + + if (Operation->IsOfType()) { TSharedPtr DragDropOp = StaticCastSharedPtr(Operation); - OnAssetsDragDropped.ExecuteIfBound(DragDropOp->AssetData, StaticCastSharedPtr(AssetItem)->FolderPath); + OnAssetsOrPathsDragDropped.ExecuteIfBound(DragDropOp->GetAssets(), DragDropOp->GetAssetPaths(), StaticCastSharedPtr(AssetItem)->FolderPath); return FReply::Handled(); } } @@ -585,7 +576,7 @@ void SAssetViewItem::OnAssetDataChanged() InlineRenameWidget->SetText( GetNameText() ); } - CacheToolTipTags(); + CacheDisplayTags(); } void SAssetViewItem::DirtyStateChanged() @@ -700,13 +691,13 @@ TSharedRef SAssetViewItem::CreateToolTipWidget() const } // Add tags - for (const auto& ToolTipTagItem : CachedToolTipTags) + for (const auto& DisplayTagItem : CachedDisplayTags) { - AddToToolTipInfoBox(InfoBox, ToolTipTagItem.Key, ToolTipTagItem.Value, ToolTipTagItem.bImportant); + AddToToolTipInfoBox(InfoBox, DisplayTagItem.DisplayKey, DisplayTagItem.DisplayValue, DisplayTagItem.bImportant); } // Add asset source files - TOptional ImportInfo = FAssetSourceFilenameCache::ExtractAssetImportInfo(AssetData.TagsAndValues); + TOptional ImportInfo = FAssetSourceFilenameCache::ExtractAssetImportInfo(AssetData); if (ImportInfo.IsSet()) { for (const auto& File : ImportInfo->SourceFiles) @@ -1004,119 +995,302 @@ void SAssetViewItem::CachePackageName() } } -void SAssetViewItem::CacheToolTipTags() +void SAssetViewItem::CacheDisplayTags() { - CachedToolTipTags.Reset(); + CachedDisplayTags.Reset(); - if(AssetItem->GetType() != EAssetItemType::Folder) + if (AssetItem->GetType() == EAssetItemType::Folder) { - const FAssetData& AssetData = StaticCastSharedPtr(AssetItem)->Data; - UClass* AssetClass = FindObject(ANY_PACKAGE, *AssetData.AssetClass.ToString()); + return; + } - // If we are using a loaded class, find all the hidden tags so we don't display them - TMap MetadataMap; - TSet ShownTags; - if ( AssetClass != NULL && AssetClass->GetDefaultObject() != NULL ) + const FAssetData& AssetData = StaticCastSharedPtr(AssetItem)->Data; + + // Find the asset CDO so we can get the meta-data for the tags + UClass* AssetClass = FindObject(ANY_PACKAGE, *AssetData.AssetClass.ToString()); + const UObject* AssetCDO = AssetClass ? GetDefault(AssetClass) : nullptr; + + // If no asset CDO is available then we cannot determine the meta-data for the tags, so just bail + if (!AssetCDO) + { + return; + } + + struct FTagDisplayMetaData + { + FTagDisplayMetaData() + : MetaData() + , Type(UObject::FAssetRegistryTag::TT_Hidden) + , DisplayFlags(UObject::FAssetRegistryTag::TD_None) { - AssetClass->GetDefaultObject()->GetAssetRegistryTagMetadata(MetadataMap); + } - TArray Tags; - AssetClass->GetDefaultObject()->GetAssetRegistryTags(Tags); + UObject::FAssetRegistryTagMetadata MetaData; + UObject::FAssetRegistryTag::ETagType Type; + uint32 DisplayFlags; + }; - for ( auto TagIt = Tags.CreateConstIterator(); TagIt; ++TagIt ) + // Build up the meta-data needed to correctly process the tags for display + TMap TagMetaDataMap; + { + // Add the internal meta-data + { + TMap TmpMetaData; + AssetCDO->GetAssetRegistryTagMetadata(TmpMetaData); + + for (const auto& TmpMetaDataPair : TmpMetaData) { - if (TagIt->Type != UObject::FAssetRegistryTag::TT_Hidden ) - { - ShownTags.Add(TagIt->Name); - } + FTagDisplayMetaData& TagMetaData = TagMetaDataMap.FindOrAdd(TmpMetaDataPair.Key); + TagMetaData.MetaData = TmpMetaDataPair.Value; } } - // If an asset class could not be loaded we cannot determine hidden tags so display no tags. - if( AssetClass != NULL ) + // Add the type and display flags { - // Add all asset registry tags and values - for (const auto& KeyValue: AssetData.TagsAndValues) + TArray TmpTags; + AssetCDO->GetAssetRegistryTags(TmpTags); + + for (const UObject::FAssetRegistryTag& TmpTag : TmpTags) { - // Skip tags that are set to be hidden - if ( ShownTags.Contains(KeyValue.Key) ) + FTagDisplayMetaData& TagMetaData = TagMetaDataMap.FindOrAdd(TmpTag.Name); + TagMetaData.Type = TmpTag.Type; + TagMetaData.DisplayFlags = TmpTag.DisplayFlags; + } + } + } + + // Add all asset registry tags and values + for (const auto& TagAndValuePair : AssetData.TagsAndValues) + { + const FTagDisplayMetaData TagMetaData = TagMetaDataMap.FindRef(TagAndValuePair.Key); + + // Skip tags that are set to be hidden + if (TagMetaData.Type == UObject::FAssetRegistryTag::TT_Hidden) + { + continue; + } + + UProperty* TagField = FindField(AssetClass, TagAndValuePair.Key); + + // Build the display name for this tag + FText DisplayName; + if (!TagMetaData.MetaData.DisplayName.IsEmpty()) + { + DisplayName = TagMetaData.MetaData.DisplayName; + } + else if (TagField) + { + DisplayName = TagField->GetDisplayNameText(); + } + else + { + // We have no type information by this point, so no idea if it's a bool :( + const bool bIsBool = false; + DisplayName = FText::FromString(FName::NameToDisplayString(TagAndValuePair.Key.ToString(), bIsBool)); + } + + // Build the display value for this tag + FText DisplayValue; + { + auto ReformatNumberStringForDisplay = [](const FString& InNumberString) -> FText + { + // Respect the number of decimal places in the source string when converting for display + int32 NumDecimalPlaces = 0; { - const UObject::FAssetRegistryTagMetadata* Metadata = MetadataMap.Find(KeyValue.Key); - - const bool bImportant = (Metadata != nullptr && !Metadata->ImportantValue.IsEmpty() && Metadata->ImportantValue == KeyValue.Value); - - // The string value might be localizable text, so we need to stringify it for display - FString ValueString = KeyValue.Value; - if (FTextStringHelper::IsComplexText(*ValueString)) + int32 DotIndex = INDEX_NONE; + if (InNumberString.FindChar(TEXT('.'), DotIndex)) { - FText TmpText; - if (FTextStringHelper::ReadFromString(*ValueString, TmpText)) - { - ValueString = TmpText.ToString(); - } + NumDecimalPlaces = InNumberString.Len() - DotIndex - 1; } + } - // Since all we have at this point is a string, we can't be very smart here. - // We need to strip some noise off class paths in some cases, but can't load the asset to inspect its UPROPERTYs manually due to performance concerns. - const TCHAR StringToRemove[] = TEXT("Class'/Script/"); - if (ValueString.StartsWith(StringToRemove) && ValueString.EndsWith(TEXT("'"))) + if (NumDecimalPlaces > 0) + { + // Convert the number as a double + double Num = 0.0; + Lex::FromString(Num, *InNumberString); + + const FNumberFormattingOptions NumFormatOpts = FNumberFormattingOptions() + .SetMinimumFractionalDigits(NumDecimalPlaces) + .SetMaximumFractionalDigits(NumDecimalPlaces); + + return FText::AsNumber(Num, &NumFormatOpts); + } + else + { + const bool bIsSigned = InNumberString.Len() > 0 && (InNumberString[0] == TEXT('-') || InNumberString[0] == TEXT('+')); + + if (bIsSigned) { - // Remove the class path for native classes, and also remove Engine. for engine classes - const int32 SizeOfPrefix = ARRAY_COUNT(StringToRemove); - ValueString = ValueString.Mid(SizeOfPrefix - 1, ValueString.Len() - SizeOfPrefix).Replace(TEXT("Engine."), TEXT("")); - } - - // Check for DisplayName metadata - FText DisplayName; - if (UProperty* Field = FindField(AssetClass, KeyValue.Key)) - { - DisplayName = Field->GetDisplayNameText(); + // Convert the number as a signed int + int64 Num = 0; + Lex::FromString(Num, *InNumberString); - UProperty* Prop = nullptr; - UEnum* Enum = nullptr; - if (UByteProperty* ByteProp = Cast(Field)) - { - Prop = ByteProp; - Enum = ByteProp->Enum; - } - else if (UEnumProperty* EnumProp = Cast(Field)) - { - Prop = EnumProp; - Enum = EnumProp->GetEnum(); - } - - // Strip off enum prefixes if they exist - if (Prop) - { - if (Enum) - { - const FString EnumPrefix = Enum->GenerateEnumPrefix(); - if (EnumPrefix.Len() && ValueString.StartsWith(EnumPrefix)) - { - ValueString = ValueString.RightChop(EnumPrefix.Len() + 1); // +1 to skip over the underscore - } - } - - ValueString = FName::NameToDisplayString(ValueString, false); - } + return FText::AsNumber(Num); } else { - // We have no type information by this point, so no idea if it's a bool :( - const bool bIsBool = false; - DisplayName = FText::FromString(FName::NameToDisplayString(KeyValue.Key.ToString(), bIsBool)); - } - - // Add suffix to the value string, if one is defined for this tag - if (Metadata != nullptr && !Metadata->Suffix.IsEmpty()) - { - ValueString += TEXT(" "); - ValueString += Metadata->Suffix.ToString(); - } + // Convert the number as an unsigned int + uint64 Num = 0; + Lex::FromString(Num, *InNumberString); - CachedToolTipTags.Add(FToolTipTagItem(DisplayName, FText::FromString(ValueString), bImportant)); + return FText::AsNumber(Num); + } + } + + return FText::GetEmpty(); + }; + + bool bHasSetDisplayValue = false; + + // Numerical tags need to format the specified number based on the display flags + if (!bHasSetDisplayValue && TagMetaData.Type == UObject::FAssetRegistryTag::TT_Numerical && TagAndValuePair.Value.IsNumeric()) + { + bHasSetDisplayValue = true; + + const bool bAsMemory = !!(TagMetaData.DisplayFlags & UObject::FAssetRegistryTag::TD_Memory); + + if (bAsMemory) + { + // Memory should be a 64-bit unsigned number of bytes + uint64 NumBytes = 0; + Lex::FromString(NumBytes, *TagAndValuePair.Value); + + DisplayValue = FText::AsMemory(NumBytes); + } + else + { + DisplayValue = ReformatNumberStringForDisplay(TagAndValuePair.Value); } } + + // Dimensional tags need to be split into their component numbers, with each component number re-format + if (!bHasSetDisplayValue && TagMetaData.Type == UObject::FAssetRegistryTag::TT_Dimensional) + { + TArray NumberStrTokens; + TagAndValuePair.Value.ParseIntoArray(NumberStrTokens, TEXT("x"), true); + + if (NumberStrTokens.Num() > 0 && NumberStrTokens.Num() <= 3) + { + bHasSetDisplayValue = true; + + switch (NumberStrTokens.Num()) + { + case 1: + DisplayValue = ReformatNumberStringForDisplay(NumberStrTokens[0]); + break; + + case 2: + DisplayValue = FText::Format(LOCTEXT("DisplayTag2xFmt", "{0} \u00D7 {1}"), ReformatNumberStringForDisplay(NumberStrTokens[0]), ReformatNumberStringForDisplay(NumberStrTokens[1])); + break; + + case 3: + DisplayValue = FText::Format(LOCTEXT("DisplayTag3xFmt", "{0} \u00D7 {1} \u00D7 {2}"), ReformatNumberStringForDisplay(NumberStrTokens[0]), ReformatNumberStringForDisplay(NumberStrTokens[1]), ReformatNumberStringForDisplay(NumberStrTokens[2])); + break; + + default: + break; + } + } + } + + // Chronological tags need to format the specified timestamp based on the display flags + if (!bHasSetDisplayValue && TagMetaData.Type == UObject::FAssetRegistryTag::TT_Chronological) + { + bHasSetDisplayValue = true; + + FDateTime Timestamp; + if (FDateTime::Parse(TagAndValuePair.Value, Timestamp)) + { + const bool bDisplayDate = !!(TagMetaData.DisplayFlags & UObject::FAssetRegistryTag::TD_Date); + const bool bDisplayTime = !!(TagMetaData.DisplayFlags & UObject::FAssetRegistryTag::TD_Time); + const FString TimeZone = (TagMetaData.DisplayFlags & UObject::FAssetRegistryTag::TD_InvariantTz) ? FText::GetInvariantTimeZone() : FString(); + + if (bDisplayDate && bDisplayTime) + { + DisplayValue = FText::AsDateTime(Timestamp, EDateTimeStyle::Short, EDateTimeStyle::Short, TimeZone); + } + else if (bDisplayDate) + { + DisplayValue = FText::AsDate(Timestamp, EDateTimeStyle::Short, TimeZone); + } + else if (bDisplayTime) + { + DisplayValue = FText::AsTime(Timestamp, EDateTimeStyle::Short, TimeZone); + } + } + } + + // The tag value might be localized text, so we need to parse it for display + if (!bHasSetDisplayValue && FTextStringHelper::IsComplexText(*TagAndValuePair.Value)) + { + bHasSetDisplayValue = true; + + FTextStringHelper::ReadFromString(*TagAndValuePair.Value, DisplayValue); + } + + // Do our best to build something valid from the string value + if (!bHasSetDisplayValue) + { + bHasSetDisplayValue = true; + + FString ValueString = TagAndValuePair.Value; + + // Since all we have at this point is a string, we can't be very smart here. + // We need to strip some noise off class paths in some cases, but can't load the asset to inspect its UPROPERTYs manually due to performance concerns. + const TCHAR StringToRemove[] = TEXT("Class'/Script/"); + if (ValueString.StartsWith(StringToRemove) && ValueString.EndsWith(TEXT("'"))) + { + // Remove the class path for native classes, and also remove Engine. for engine classes + const int32 SizeOfPrefix = ARRAY_COUNT(StringToRemove); + ValueString = ValueString.Mid(SizeOfPrefix - 1, ValueString.Len() - SizeOfPrefix).Replace(TEXT("Engine."), TEXT("")); + } + + if (TagField) + { + UProperty* TagProp = nullptr; + UEnum* TagEnum = nullptr; + if (UByteProperty* ByteProp = Cast(TagField)) + { + TagProp = ByteProp; + TagEnum = ByteProp->Enum; + } + else if (UEnumProperty* EnumProp = Cast(TagField)) + { + TagProp = EnumProp; + TagEnum = EnumProp->GetEnum(); + } + + // Strip off enum prefixes if they exist + if (TagProp) + { + if (TagEnum) + { + const FString EnumPrefix = TagEnum->GenerateEnumPrefix(); + if (EnumPrefix.Len() && ValueString.StartsWith(EnumPrefix)) + { + ValueString = ValueString.RightChop(EnumPrefix.Len() + 1); // +1 to skip over the underscore + } + } + + ValueString = FName::NameToDisplayString(ValueString, false); + } + } + + DisplayValue = FText::FromString(MoveTemp(ValueString)); + } + + // Add suffix to the value, if one is defined for this tag + if (!TagMetaData.MetaData.Suffix.IsEmpty()) + { + DisplayValue = FText::Format(LOCTEXT("DisplayTagSuffixFmt", "{0} {1}"), DisplayValue, TagMetaData.MetaData.Suffix); + } + } + + if (!DisplayValue.IsEmpty()) + { + const bool bImportant = !TagMetaData.MetaData.ImportantValue.IsEmpty() && TagMetaData.MetaData.ImportantValue == TagAndValuePair.Value; + CachedDisplayTags.Add(FTagDisplayItem(TagAndValuePair.Key, DisplayName, DisplayValue, bImportant)); } } } @@ -1262,8 +1436,7 @@ void SAssetListItem::Construct( const FArguments& InArgs ) .ShouldAllowToolTip(InArgs._ShouldAllowToolTip) .ThumbnailEditMode(InArgs._ThumbnailEditMode) .HighlightText(InArgs._HighlightText) - .OnAssetsDragDropped(InArgs._OnAssetsDragDropped) - .OnPathsDragDropped(InArgs._OnPathsDragDropped) + .OnAssetsOrPathsDragDropped(InArgs._OnAssetsOrPathsDragDropped) .OnFilesDragDropped(InArgs._OnFilesDragDropped) .OnGetCustomAssetToolTip(InArgs._OnGetCustomAssetToolTip) .OnVisualizeAssetToolTip(InArgs._OnVisualizeAssetToolTip) @@ -1415,8 +1588,7 @@ void SAssetTileItem::Construct( const FArguments& InArgs ) .ShouldAllowToolTip(InArgs._ShouldAllowToolTip) .ThumbnailEditMode(InArgs._ThumbnailEditMode) .HighlightText(InArgs._HighlightText) - .OnAssetsDragDropped(InArgs._OnAssetsDragDropped) - .OnPathsDragDropped(InArgs._OnPathsDragDropped) + .OnAssetsOrPathsDragDropped(InArgs._OnAssetsOrPathsDragDropped) .OnFilesDragDropped(InArgs._OnFilesDragDropped) .OnGetCustomAssetToolTip(InArgs._OnGetCustomAssetToolTip) .OnVisualizeAssetToolTip(InArgs._OnVisualizeAssetToolTip) @@ -1617,8 +1789,7 @@ void SAssetColumnItem::Construct( const FArguments& InArgs ) .OnVerifyRenameCommit(InArgs._OnVerifyRenameCommit) .OnItemDestroyed(InArgs._OnItemDestroyed) .HighlightText(InArgs._HighlightText) - .OnAssetsDragDropped(InArgs._OnAssetsDragDropped) - .OnPathsDragDropped(InArgs._OnPathsDragDropped) + .OnAssetsOrPathsDragDropped(InArgs._OnAssetsOrPathsDragDropped) .OnFilesDragDropped(InArgs._OnFilesDragDropped) .OnGetCustomAssetToolTip(InArgs._OnGetCustomAssetToolTip) .OnVisualizeAssetToolTip(InArgs._OnVisualizeAssetToolTip) @@ -1838,14 +2009,28 @@ FText SAssetColumnItem::GetAssetTagText(FName AssetTag) const if(AssetItem->GetType() != EAssetItemType::Folder) { const TSharedPtr& ItemAsAsset = StaticCastSharedPtr(AssetItem); - // Check custom type - FString* FoundString = ItemAsAsset->CustomColumnData.Find(AssetTag); - if (FoundString) + // Check custom type { - return FText::FromString(*FoundString); + FString* FoundString = ItemAsAsset->CustomColumnData.Find(AssetTag); + if (FoundString) + { + return FText::FromString(*FoundString); + } + } + + // Check display tags + { + const FTagDisplayItem* FoundTagItem = CachedDisplayTags.FindByPredicate([AssetTag](const FTagDisplayItem& TagItem) + { + return TagItem.TagKey == AssetTag; + }); + + if (FoundTagItem) + { + return FoundTagItem->DisplayValue; + } } - return ItemAsAsset->Data.GetTagValueRef(AssetTag); } } diff --git a/Engine/Source/Editor/ContentBrowser/Private/AssetViewWidgets.h b/Engine/Source/Editor/ContentBrowser/Private/AssetViewWidgets.h index 29697eee80d3..9efa41c9e811 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/AssetViewWidgets.h +++ b/Engine/Source/Editor/ContentBrowser/Private/AssetViewWidgets.h @@ -89,8 +89,7 @@ class SAssetViewItem : public SCompoundWidget friend class SAssetViewItemToolTip; public: - DECLARE_DELEGATE_TwoParams( FOnAssetsDragDropped, const TArray& /*AssetList*/, const FString& /*DestinationPath*/); - DECLARE_DELEGATE_TwoParams( FOnPathsDragDropped, const TArray& /*PathNames*/, const FString& /*DestinationPath*/); + DECLARE_DELEGATE_ThreeParams( FOnAssetsOrPathsDragDropped, const TArray& /*AssetList*/, const TArray& /*AssetPaths*/, const FString& /*DestinationPath*/); DECLARE_DELEGATE_TwoParams( FOnFilesDragDropped, const TArray& /*FileNames*/, const FString& /*DestinationPath*/); SLATE_BEGIN_ARGS( SAssetViewItem ) @@ -122,11 +121,8 @@ public: /** The string in the title to highlight (used when searching by string) */ SLATE_ATTRIBUTE(FText, HighlightText) - /** Delegate for when assets are dropped on this item, if it is a folder */ - SLATE_EVENT( FOnAssetsDragDropped, OnAssetsDragDropped ) - - /** Delegate for when asset paths are dropped on this folder, if it is a folder */ - SLATE_EVENT( FOnPathsDragDropped, OnPathsDragDropped ) + /** Delegate for when assets or asset paths are dropped on this item, if it is a folder */ + SLATE_EVENT( FOnAssetsOrPathsDragDropped, OnAssetsOrPathsDragDropped ) /** Delegate for when a list of files is dropped on this folder (if it is a folder) from an external source */ SLATE_EVENT( FOnFilesDragDropped, OnFilesDragDropped ) @@ -231,8 +227,8 @@ protected: /** Cache the package name from the asset we are representing */ void CachePackageName(); - /** Cache the tags that should appear in the tooltip for this item */ - void CacheToolTipTags(); + /** Cache the display tags for this item */ + void CacheDisplayTags(); /** Whether this item is a folder */ bool IsFolder() const; @@ -250,18 +246,20 @@ protected: virtual float GetNameTextWrapWidth() const { return 0.0f; } protected: - /** Data for a cached tag used in the tooltip for this item */ - struct FToolTipTagItem + /** Data for a cached display tag for this item (used in the tooltip, and also as the display string in column views) */ + struct FTagDisplayItem { - FToolTipTagItem(FText InKey, FText InValue, const bool InImportant) - : Key(MoveTemp(InKey)) - , Value(MoveTemp(InValue)) + FTagDisplayItem(FName InTagKey, FText InDisplayKey, FText InDisplayValue, const bool InImportant) + : TagKey(InTagKey) + , DisplayKey(MoveTemp(InDisplayKey)) + , DisplayValue(MoveTemp(InDisplayValue)) , bImportant(InImportant) { } - FText Key; - FText Value; + FName TagKey; + FText DisplayKey; + FText DisplayValue; bool bImportant; }; @@ -282,8 +280,8 @@ protected: /** The cached filename of the package containing the asset that this item represents */ FString CachedPackageFileName; - /** The cached tags that should appear in the tooltip for this item */ - TArray CachedToolTipTags; + /** The cached display tags for this item */ + TArray CachedDisplayTags; /** Delegate for when an asset name has entered a rename state */ FOnRenameBegin OnRenameBegin; @@ -330,11 +328,8 @@ protected: /** Delay timer before we request a source control state update, to prevent spam */ float SourceControlStateDelay; - /** Delegate for when a list of assets is dropped on this item, if it is a folder */ - FOnAssetsDragDropped OnAssetsDragDropped; - - /** Delegate for when a list of folder paths is dropped on this item, if it is a folder */ - FOnPathsDragDropped OnPathsDragDropped; + /** Delegate for when a list of assets or asset paths are dropped on this item, if it is a folder */ + FOnAssetsOrPathsDragDropped OnAssetsOrPathsDragDropped; /** Delegate for when a list of files is dropped on this item (if it is a folder) from an external source */ FOnFilesDragDropped OnFilesDragDropped; @@ -411,11 +406,8 @@ public: /** Whether the item is selected in the view */ SLATE_ARGUMENT( FIsSelected, IsSelected ) - /** Delegate for when assets are dropped on this item, if it is a folder */ - SLATE_EVENT( FOnAssetsDragDropped, OnAssetsDragDropped ) - - /** Delegate for when asset paths are dropped on this folder, if it is a folder */ - SLATE_EVENT( FOnPathsDragDropped, OnPathsDragDropped ) + /** Delegate for when assets or asset paths are dropped on this item, if it is a folder */ + SLATE_EVENT( FOnAssetsOrPathsDragDropped, OnAssetsOrPathsDragDropped ) /** Delegate for when a list of files is dropped on this folder (if it is a folder) from an external source */ SLATE_EVENT( FOnFilesDragDropped, OnFilesDragDropped ) @@ -522,11 +514,8 @@ public: /** Whether the item is selected in the view */ SLATE_ARGUMENT( FIsSelected, IsSelected ) - /** Delegate for when assets are dropped on this item, if it is a folder */ - SLATE_EVENT( FOnAssetsDragDropped, OnAssetsDragDropped ) - - /** Delegate for when asset paths are dropped on this folder, if it is a folder */ - SLATE_EVENT( FOnPathsDragDropped, OnPathsDragDropped ) + /** Delegate for when assets or asset paths are dropped on this item, if it is a folder */ + SLATE_EVENT( FOnAssetsOrPathsDragDropped, OnAssetsOrPathsDragDropped ) /** Delegate for when a list of files is dropped on this folder (if it is a folder) from an external source */ SLATE_EVENT( FOnFilesDragDropped, OnFilesDragDropped ) @@ -602,11 +591,8 @@ public: /** The string in the title to highlight (used when searching by string) */ SLATE_ATTRIBUTE( FText, HighlightText ) - /** Delegate for when assets are dropped on this item, if it is a folder */ - SLATE_EVENT( FOnAssetsDragDropped, OnAssetsDragDropped ) - - /** Delegate for when asset paths are dropped on this folder, if it is a folder */ - SLATE_EVENT( FOnPathsDragDropped, OnPathsDragDropped ) + /** Delegate for when assets or asset paths are dropped on this item, if it is a folder */ + SLATE_EVENT( FOnAssetsOrPathsDragDropped, OnAssetsOrPathsDragDropped ) /** Delegate for when a list of files is dropped on this folder (if it is a folder) from an external source */ SLATE_EVENT( FOnFilesDragDropped, OnFilesDragDropped ) diff --git a/Engine/Source/Editor/ContentBrowser/Private/ContentBrowserSingleton.cpp b/Engine/Source/Editor/ContentBrowser/Private/ContentBrowserSingleton.cpp index 7b2579cb9362..2fa9629c7918 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/ContentBrowserSingleton.cpp +++ b/Engine/Source/Editor/ContentBrowser/Private/ContentBrowserSingleton.cpp @@ -26,12 +26,15 @@ #include "TutorialMetaData.h" #include "Widgets/Docking/SDockTab.h" #include "NativeClassHierarchy.h" +#include "EmptyFolderVisibilityManager.h" #include "CollectionAssetRegistryBridge.h" +#include "ContentBrowserCommands.h" #define LOCTEXT_NAMESPACE "ContentBrowser" FContentBrowserSingleton::FContentBrowserSingleton() - : CollectionAssetRegistryBridge(MakeShareable(new FCollectionAssetRegistryBridge())) + : EmptyFolderVisibilityManager(MakeShared()) + , CollectionAssetRegistryBridge(MakeShared()) , SettingsStringID(0) { // Register the tab spawners for all content browsers @@ -63,6 +66,8 @@ FContentBrowserSingleton::FContentBrowserSingleton() // Register to be notified when properties are edited FEditorDelegates::LoadSelectedAssetsIfNeeded.AddRaw(this, &FContentBrowserSingleton::OnEditorLoadSelectedAssetsIfNeeded); + + FContentBrowserCommands::Register(); } FContentBrowserSingleton::~FContentBrowserSingleton() @@ -225,7 +230,7 @@ void FContentBrowserSingleton::CreateNewAsset(const FString& DefaultAssetName, c } } -void FContentBrowserSingleton::SyncBrowserToAssets(const TArray& AssetDataList, bool bAllowLockedBrowsers, bool bFocusContentBrowser) +TSharedPtr FContentBrowserSingleton::FindContentBrowserToSync(bool bAllowLockedBrowsers) { TSharedPtr ContentBrowserToSync; @@ -268,6 +273,18 @@ void FContentBrowserSingleton::SyncBrowserToAssets(const TArray& Ass } } + if ( !ContentBrowserToSync.IsValid() ) + { + UE_LOG( LogContentBrowser, Log, TEXT( "Unable to sync content browser, all browsers appear to be locked" ) ); + } + + return ContentBrowserToSync; +} + +void FContentBrowserSingleton::SyncBrowserToAssets(const TArray& AssetDataList, bool bAllowLockedBrowsers, bool bFocusContentBrowser) +{ + TSharedPtr ContentBrowserToSync = FindContentBrowserToSync(bAllowLockedBrowsers); + if ( ContentBrowserToSync.IsValid() ) { // Finally, focus and sync the browser that was found @@ -277,10 +294,6 @@ void FContentBrowserSingleton::SyncBrowserToAssets(const TArray& Ass } ContentBrowserToSync->SyncToAssets(AssetDataList); } - else - { - UE_LOG( LogContentBrowser, Log, TEXT( "Unable to sync content browser, all browsers appear to be locked" ) ); - } } void FContentBrowserSingleton::SyncBrowserToAssets(const TArray& AssetList, bool bAllowLockedBrowsers, bool bFocusContentBrowser) @@ -298,6 +311,36 @@ void FContentBrowserSingleton::SyncBrowserToAssets(const TArray& Asset SyncBrowserToAssets(AssetDataList, bAllowLockedBrowsers, bFocusContentBrowser); } +void FContentBrowserSingleton::SyncBrowserToFolders(const TArray& FolderList, bool bAllowLockedBrowsers, bool bFocusContentBrowser) +{ + TSharedPtr ContentBrowserToSync = FindContentBrowserToSync(bAllowLockedBrowsers); + + if ( ContentBrowserToSync.IsValid() ) + { + // Finally, focus and sync the browser that was found + if (bFocusContentBrowser) + { + FocusContentBrowser(ContentBrowserToSync); + } + ContentBrowserToSync->SyncToFolders(FolderList); + } +} + +void FContentBrowserSingleton::SyncBrowserTo(const FContentBrowserSelection& ItemSelection, bool bAllowLockedBrowsers, bool bFocusContentBrowser) +{ + TSharedPtr ContentBrowserToSync = FindContentBrowserToSync(bAllowLockedBrowsers); + + if ( ContentBrowserToSync.IsValid() ) + { + // Finally, focus and sync the browser that was found + if (bFocusContentBrowser) + { + FocusContentBrowser(ContentBrowserToSync); + } + ContentBrowserToSync->SyncTo(ItemSelection); + } +} + void FContentBrowserSingleton::GetSelectedAssets(TArray& SelectedAssets) { if ( PrimaryContentBrowser.IsValid() ) @@ -372,6 +415,11 @@ TSharedRef FContentBrowserSingleton::GetNativeClassHierar return NativeClassHierarchy.ToSharedRef(); } +TSharedRef FContentBrowserSingleton::GetEmptyFolderVisibilityManager() +{ + return EmptyFolderVisibilityManager; +} + void FContentBrowserSingleton::SharedCreateAssetDialogWindow(const TSharedRef& AssetDialog, const FSharedAssetDialogConfig& InConfig, bool bModal) const { const FVector2D DefaultWindowSize(1152.0f, 648.0f); diff --git a/Engine/Source/Editor/ContentBrowser/Private/ContentBrowserSingleton.h b/Engine/Source/Editor/ContentBrowser/Private/ContentBrowserSingleton.h index 8061692dcb4a..f680701d26b5 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/ContentBrowserSingleton.h +++ b/Engine/Source/Editor/ContentBrowser/Private/ContentBrowserSingleton.h @@ -8,6 +8,7 @@ #include "IContentBrowserSingleton.h" class FCollectionAssetRegistryBridge; +class FEmptyFolderVisibilityManager; class FNativeClassHierarchy; class FSpawnTabArgs; class FTabManager; @@ -41,6 +42,8 @@ public: virtual void CreateNewAsset(const FString& DefaultAssetName, const FString& PackagePath, UClass* AssetClass, UFactory* Factory) override; virtual void SyncBrowserToAssets(const TArray& AssetDataList, bool bAllowLockedBrowsers = false, bool bFocusContentBrowser = true) override; virtual void SyncBrowserToAssets(const TArray& AssetList, bool bAllowLockedBrowsers = false, bool bFocusContentBrowser = true) override; + virtual void SyncBrowserToFolders(const TArray& FolderList, bool bAllowLockedBrowsers = false, bool bFocusContentBrowser = true) override; + virtual void SyncBrowserTo(const FContentBrowserSelection& ItemSelection, bool bAllowLockedBrowsers = false, bool bFocusContentBrowser = true) override; virtual void GetSelectedAssets(TArray& SelectedAssets) override; virtual void CaptureThumbnailFromViewport(FViewport* InViewport, TArray& SelectedAssets) override; virtual void SetSelectedPaths(const TArray& FolderPaths, bool bNeedsRefresh = false) override; @@ -58,8 +61,13 @@ public: TSharedRef GetNativeClassHierarchy(); + TSharedRef GetEmptyFolderVisibilityManager(); + private: + /** Util to get or create the content browser that should be used by the various Sync functions */ + TSharedPtr FindContentBrowserToSync(bool bAllowLockedBrowsers); + /** Shared code to open an asset dialog window with a config */ void SharedCreateAssetDialogWindow(const TSharedRef& AssetDialog, const FSharedAssetDialogConfig& InConfig, bool bModal) const; @@ -102,6 +110,8 @@ private: TSharedPtr NativeClassHierarchy; + TSharedRef EmptyFolderVisibilityManager; + TSharedRef CollectionAssetRegistryBridge; /** An incrementing int32 which is used when making unique settings strings */ diff --git a/Engine/Source/Editor/ContentBrowser/Private/ContentBrowserUtils.cpp b/Engine/Source/Editor/ContentBrowser/Private/ContentBrowserUtils.cpp index 39d13a9b5e84..a0bb1bdd5dbe 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/ContentBrowserUtils.cpp +++ b/Engine/Source/Editor/ContentBrowser/Private/ContentBrowserUtils.cpp @@ -2,6 +2,7 @@ #include "ContentBrowserUtils.h" +#include "ContentBrowserSingleton.h" #include "HAL/IConsoleManager.h" #include "Misc/MessageDialog.h" #include "HAL/FileManager.h" @@ -36,6 +37,8 @@ #include "AssetRegistryModule.h" #include "IAssetTools.h" #include "AssetToolsModule.h" +#include "NativeClassHierarchy.h" +#include "EmptyFolderVisibilityManager.h" #include "Toolkits/AssetEditorManager.h" #include "PackagesDialog.h" @@ -346,9 +349,6 @@ bool ContentBrowserUtils::LoadAssetsIfNeeded(const TArray& ObjectPaths, } } } - - // prompt and load assets - GetUnloadedAssets(ObjectPaths, UnloadedObjectPaths); // Make sure all selected objects are loaded, where possible if ( UnloadedObjectPaths.Num() > 0 ) @@ -796,6 +796,10 @@ bool ContentBrowserUtils::CopyFolders(const TArray& InSourcePathNames, FString Destination = DestPath + TEXT("/") + SubFolderName; // Add the new path to notify sources views + { + TSharedRef EmptyFolderVisibilityManager = FContentBrowserSingleton::Get().GetEmptyFolderVisibilityManager(); + EmptyFolderVisibilityManager->SetAlwaysShowPath(Destination); + } AssetRegistryModule.Get().AddPath(Destination); // If any assets were in this path... @@ -847,6 +851,10 @@ bool ContentBrowserUtils::MoveFolders(const TArray& InSourcePathNames, const FString Destination = DestPathWithTrailingSlash + SubFolderName; // Add the new path to notify sources views + { + TSharedRef EmptyFolderVisibilityManager = FContentBrowserSingleton::Get().GetEmptyFolderVisibilityManager(); + EmptyFolderVisibilityManager->SetAlwaysShowPath(Destination); + } AssetRegistryModule.Get().AddPath(Destination); // If any assets were in this path... @@ -888,9 +896,6 @@ bool ContentBrowserUtils::PrepareFoldersForDragDrop(const TArray& Sourc } } - TArray UnloadedObjects; - GetUnloadedAssets(ObjectPathsToWarnAbout, UnloadedObjects); - GWarn->BeginSlowTask(LOCTEXT("FolderDragDrop_Loading", "Loading folders"), true); // For every source path, load every package in the path (if necessary) and keep track of the assets that were loaded @@ -925,7 +930,6 @@ bool ContentBrowserUtils::PrepareFoldersForDragDrop(const TArray& Sourc { UObject* Asset = *AssetIt; if ( (Asset->GetClass() != UObjectRedirector::StaticClass() && // Skip object redirectors - !Asset->GetOutermost()->ContainsMap() && // Skip assets in maps !AllFoundObjects.Contains(Asset) // Skip assets we have already found to avoid processing them twice ) ) { @@ -1301,6 +1305,22 @@ bool ContentBrowserUtils::DoesFolderExist(const FString& FolderPath) return false; } +bool ContentBrowserUtils::IsEmptyFolder(const FString& FolderPath, const bool bRecursive) +{ + if (ContentBrowserUtils::IsClassPath(FolderPath)) + { + TSharedRef NativeClassHierarchy = FContentBrowserSingleton::Get().GetNativeClassHierarchy(); + return !NativeClassHierarchy->HasClasses(*FolderPath, bRecursive); + } + else + { + FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(TEXT("AssetRegistry")); + return !AssetRegistryModule.Get().HasAssets(*FolderPath, bRecursive); + } + + return false; +} + bool ContentBrowserUtils::IsRootDir(const FString& FolderPath) { return IsAssetRootDir(FolderPath) || IsClassRootDir(FolderPath); diff --git a/Engine/Source/Editor/ContentBrowser/Private/ContentBrowserUtils.h b/Engine/Source/Editor/ContentBrowser/Private/ContentBrowserUtils.h index dbaa785a6410..880035fff510 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/ContentBrowserUtils.h +++ b/Engine/Source/Editor/ContentBrowser/Private/ContentBrowserUtils.h @@ -37,7 +37,7 @@ namespace ContentBrowserUtils bool OpenEditorForAsset(const TArray& Assets); /** - * Makes sure the specified assets are loaded into memory.6666 + * Makes sure the specified assets are loaded into memory. * * @param ObjectPaths The paths to the objects to load. * @param LoadedObjects The returned list of objects that were already loaded or loaded by this method. @@ -173,6 +173,12 @@ namespace ContentBrowserUtils /** Returns true if the path specified exists as a folder in the asset registry */ bool DoesFolderExist(const FString& FolderPath); + /** + * @return true if the path specified is an empty folder (contains no assets or classes). + * @note Does *not* test whether the folder is empty on disk, so do not use it to validate filesystem deletion! + */ + bool IsEmptyFolder(const FString& FolderPath, const bool bRecursive = false); + /** Check to see whether the given path is a root directory (either for asset or classes) */ bool IsRootDir(const FString& FolderPath); diff --git a/Engine/Source/Editor/ContentBrowser/Private/DragDropHandler.cpp b/Engine/Source/Editor/ContentBrowser/Private/DragDropHandler.cpp index 2483e40d29bb..b33ddfd38fbc 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/DragDropHandler.cpp +++ b/Engine/Source/Editor/ContentBrowser/Private/DragDropHandler.cpp @@ -10,7 +10,6 @@ #include "EditorStyleSet.h" #include "DragAndDrop/AssetDragDropOp.h" -#include "DragAndDrop/AssetPathDragDropOp.h" #include "ContentBrowserUtils.h" #define LOCTEXT_NAMESPACE "ContentBrowser" @@ -33,81 +32,52 @@ bool DragDropHandler::ValidateDragDropOnAssetFolder(const FGeometry& MyGeometry, if (Operation->IsOfType()) { TSharedPtr DragDropOp = StaticCastSharedPtr(Operation); + const TArray& DroppedAssets = DragDropOp->GetAssets(); + const TArray& DroppedAssetPaths = DragDropOp->GetAssetPaths(); OutIsKnownDragOperation = true; - if (bIsAssetPath) - { - int32 NumAssetItems, NumClassItems; - ContentBrowserUtils::CountItemTypes(DragDropOp->AssetData, NumAssetItems, NumClassItems); + int32 NumAssetItems, NumClassItems; + ContentBrowserUtils::CountItemTypes(DroppedAssets, NumAssetItems, NumClassItems); - if (NumAssetItems > 0) - { - const FText MoveOrCopyText = (NumAssetItems > 1) - ? FText::Format(LOCTEXT("OnDragAssetsOverFolder_MultipleAssets", "Move or copy '{0}' and {1} other(s)"), FText::FromName(DragDropOp->AssetData[0].AssetName), FText::AsNumber(NumAssetItems - 1)) - : FText::Format(LOCTEXT("OnDragAssetsOverFolder_SingularAsset", "Move or copy '{0}'"), FText::FromName(DragDropOp->AssetData[0].AssetName)); + int32 NumAssetPaths, NumClassPaths; + ContentBrowserUtils::CountPathTypes(DroppedAssetPaths, NumAssetPaths, NumClassPaths); - if (NumClassItems > 0) - { - DragDropOp->SetToolTip(FText::Format(LOCTEXT("OnDragAssetsOverFolder_AssetsAndClasses", "{0}\n\n{1} C++ class(es) will be ignored as they cannot be moved or copied"), MoveOrCopyText, FText::AsNumber(NumClassItems)), FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.OKWarn"))); - bIsValidDrag = true; - } - else - { - DragDropOp->SetToolTip(MoveOrCopyText, FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.OK"))); - bIsValidDrag = true; - } - } - else if (NumClassItems > 0) - { - DragDropOp->SetToolTip(LOCTEXT("OnDragAssetsOverFolder_OnlyClasses", "C++ classes cannot be moved or copied"), FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error"))); - } - } - else - { - DragDropOp->SetToolTip(FText::Format(LOCTEXT("OnDragAssetsOverFolder_InvalidFolder", "'{0}' is not a valid place to drop assets"), FText::FromString(TargetPath)), FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error"))); - } - } - else if (Operation->IsOfType()) - { - TSharedPtr DragDropOp = StaticCastSharedPtr(Operation); - - OutIsKnownDragOperation = true; - - if (DragDropOp->PathNames.Num() == 1 && DragDropOp->PathNames[0] == TargetPath) + if (DroppedAssetPaths.Num() == 1 && DroppedAssetPaths[0] == TargetPath) { DragDropOp->SetToolTip(LOCTEXT("OnDragFoldersOverFolder_CannotSelfDrop", "Cannot move or copy a folder onto itself"), FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error"))); } else if (bIsAssetPath) { - int32 NumAssetPaths, NumClassPaths; - ContentBrowserUtils::CountPathTypes(DragDropOp->PathNames, NumAssetPaths, NumClassPaths); + const int32 TotalAssetDropItems = NumAssetItems + NumAssetPaths; + const int32 TotalClassDropItems = NumClassItems + NumClassPaths; - if (NumAssetPaths > 0) + if (TotalAssetDropItems > 0) { - const FText MoveOrCopyText = (NumAssetPaths > 1) - ? FText::Format(LOCTEXT("OnDragFoldersOverFolder_MultipleFolders", "Move or copy '{0}' and {1} other(s)"), FText::FromString(DragDropOp->PathNames[0]), FText::AsNumber(NumAssetPaths - 1)) - : FText::Format(LOCTEXT("OnDragFoldersOverFolder_SingularFolder", "Move or copy '{0}'"), FText::FromString(DragDropOp->PathNames[0])); + bIsValidDrag = true; - if (NumClassPaths > 0) + const FText FirstItemText = DroppedAssets.Num() > 0 ? FText::FromName(DroppedAssets[0].AssetName) : FText::FromString(DroppedAssetPaths[0]); + const FText MoveOrCopyText = (TotalAssetDropItems > 1) + ? FText::Format(LOCTEXT("OnDragAssetsOverFolder_MultipleAssetItems", "Move or copy '{0}' and {1} {1}|plural(one=other,other=others)"), FirstItemText, TotalAssetDropItems - 1) + : FText::Format(LOCTEXT("OnDragAssetsOverFolder_SingularAssetItems", "Move or copy '{0}'"), FirstItemText); + + if (TotalClassDropItems > 0) { - DragDropOp->SetToolTip(FText::Format(LOCTEXT("OnDragFoldersOverFolder_AssetsAndClasses", "{0}\n\n{1} C++ class folder(s) will be ignored as they cannot be moved or copied"), MoveOrCopyText, FText::AsNumber(NumClassPaths)), FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.OKWarn"))); - bIsValidDrag = true; + DragDropOp->SetToolTip(FText::Format(LOCTEXT("OnDragAssetsOverFolder_AssetAndClassItems", "{0}\n\n{1} C++ {1}|plural(one=item,other=items) will be ignored as they cannot be moved or copied"), MoveOrCopyText, NumClassItems), FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.OKWarn"))); } else { DragDropOp->SetToolTip(MoveOrCopyText, FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.OK"))); - bIsValidDrag = true; } } - else if (NumClassPaths > 0) + else if (TotalClassDropItems > 0) { - DragDropOp->SetToolTip(LOCTEXT("OnDragFoldersOverFolder_OnlyClasses", "C++ class folders cannot be moved or copied"), FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error"))); + DragDropOp->SetToolTip(LOCTEXT("OnDragAssetsOverFolder_OnlyClassItems", "C++ items cannot be moved or copied"), FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error"))); } } else { - DragDropOp->SetToolTip(FText::Format(LOCTEXT("OnDragFoldersOverFolder_InvalidFolder", "'{0}' is not a valid place to drop folders"), FText::FromString(TargetPath)), FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error"))); + DragDropOp->SetToolTip(FText::Format(LOCTEXT("OnDragAssetsOverFolder_InvalidFolder", "'{0}' is not a valid place to drop assets or folders"), FText::FromString(TargetPath)), FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error"))); } } else if (Operation->IsOfType()) @@ -127,19 +97,21 @@ bool DragDropHandler::ValidateDragDropOnAssetFolder(const FGeometry& MyGeometry, return bIsValidDrag; } -void DragDropHandler::HandleAssetsDroppedOnAssetFolder(const TSharedRef& ParentWidget, const TArray& AssetList, const FString& TargetPath, const FText& TargetDisplayName, FExecuteCopyOrMoveAssets CopyActionHandler, FExecuteCopyOrMoveAssets MoveActionHandler) +void DragDropHandler::HandleDropOnAssetFolder(const TSharedRef& ParentWidget, const TArray& AssetList, const TArray& AssetPaths, const FString& TargetPath, const FText& TargetDisplayName, FExecuteCopyOrMove CopyActionHandler, FExecuteCopyOrMove MoveActionHandler) { - TArray FinalAssetList; - FinalAssetList.Reserve(AssetList.Num()); - // Remove any classes from the asset list - for (const FAssetData& AssetData : AssetList) + TArray FinalAssetList = AssetList; + FinalAssetList.RemoveAll([](const FAssetData& AssetData) { - if (AssetData.AssetClass != NAME_Class) - { - FinalAssetList.Add(AssetData); - } - } + return AssetData.AssetClass == NAME_Class; + }); + + // Remove any class paths from the list + TArray FinalAssetPaths = AssetPaths; + FinalAssetPaths.RemoveAll([](const FString& AssetPath) + { + return ContentBrowserUtils::IsClassPath(AssetPath); + }); FMenuBuilder MenuBuilder(/*bInShouldCloseWindowAfterMenuSelection=*/true, nullptr); const FText MoveCopyHeaderString = FText::Format(LOCTEXT("AssetViewDropMenuHeading", "Move/Copy to {0}"), TargetDisplayName); @@ -147,58 +119,16 @@ void DragDropHandler::HandleAssetsDroppedOnAssetFolder(const TSharedRef { MenuBuilder.AddMenuEntry( LOCTEXT("DragDropCopy", "Copy Here"), - LOCTEXT("DragDropCopyTooltip", "Creates a copy of all dragged files in this folder."), + LOCTEXT("DragDropCopyTooltip", "Copy the dragged items to this folder, preserving the structure of any copied folders."), FSlateIcon(), - FUIAction(FExecuteAction::CreateLambda([=]() { CopyActionHandler.ExecuteIfBound(FinalAssetList, TargetPath); })) + FUIAction(FExecuteAction::CreateLambda([=]() { CopyActionHandler.ExecuteIfBound(FinalAssetList, FinalAssetPaths, TargetPath); })) ); MenuBuilder.AddMenuEntry( LOCTEXT("DragDropMove", "Move Here"), - LOCTEXT("DragDropMoveTooltip", "Moves all dragged files to this folder."), + LOCTEXT("DragDropMoveTooltip", "Move the dragged items to this folder, preserving the structure of any copied folders."), FSlateIcon(), - FUIAction(FExecuteAction::CreateLambda([=]() { MoveActionHandler.ExecuteIfBound(FinalAssetList, TargetPath); })) - ); - } - MenuBuilder.EndSection(); - - FSlateApplication::Get().PushMenu( - ParentWidget, - FWidgetPath(), - MenuBuilder.MakeWidget(), - FSlateApplication::Get().GetCursorPos(), - FPopupTransitionEffect(FPopupTransitionEffect::ContextMenu) - ); -} - -void DragDropHandler::HandleFoldersDroppedOnAssetFolder(const TSharedRef& ParentWidget, const TArray& PathNames, const FString& TargetPath, const FText& TargetDisplayName, FExecuteCopyOrMoveFolders CopyActionHandler, FExecuteCopyOrMoveFolders MoveActionHandler) -{ - TArray FinalPathNames; - FinalPathNames.Reserve(PathNames.Num()); - - // Remove any class paths from the list - for (const FString& PathName : PathNames) - { - if (!ContentBrowserUtils::IsClassPath(PathName)) - { - FinalPathNames.Add(PathName); - } - } - - FMenuBuilder MenuBuilder(/*bInShouldCloseWindowAfterMenuSelection=*/true, nullptr); - MenuBuilder.BeginSection("PathFolderMoveCopy", FText::Format(LOCTEXT("AssetViewDropMenuHeading", "Move/Copy to {0}"), TargetDisplayName)); - { - MenuBuilder.AddMenuEntry( - LOCTEXT("DragDropCopyFolder", "Copy Folder Here"), - LOCTEXT("DragDropCopyFolderTooltip", "Creates a copy of all assets in the dragged folders to this folder, preserving folder structure."), - FSlateIcon(), - FUIAction(FExecuteAction::CreateLambda([=]() { CopyActionHandler.ExecuteIfBound(FinalPathNames, TargetPath); })) - ); - - MenuBuilder.AddMenuEntry( - LOCTEXT("DragDropMoveFolder", "Move Folder Here"), - LOCTEXT("DragDropMoveFolderTooltip", "Moves all assets in the dragged folders to this folder, preserving folder structure."), - FSlateIcon(), - FUIAction(FExecuteAction::CreateLambda([=]() { MoveActionHandler.ExecuteIfBound(FinalPathNames, TargetPath); })) + FUIAction(FExecuteAction::CreateLambda([=]() { MoveActionHandler.ExecuteIfBound(FinalAssetList, FinalAssetPaths, TargetPath); })) ); } MenuBuilder.EndSection(); diff --git a/Engine/Source/Editor/ContentBrowser/Private/DragDropHandler.h b/Engine/Source/Editor/ContentBrowser/Private/DragDropHandler.h index 413e36bda62c..5dd850701e7f 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/DragDropHandler.h +++ b/Engine/Source/Editor/ContentBrowser/Private/DragDropHandler.h @@ -9,15 +9,11 @@ /** Common Content Browser drag-drop handler logic */ namespace DragDropHandler { - DECLARE_DELEGATE_TwoParams(FExecuteCopyOrMoveAssets, TArray /*AssetList*/, FString /*TargetPath*/); - DECLARE_DELEGATE_TwoParams(FExecuteCopyOrMoveFolders, TArray /*PathNames*/, FString /*TargetPath*/); + DECLARE_DELEGATE_ThreeParams(FExecuteCopyOrMove, TArray /*AssetList*/, TArray /*AssetPaths*/, FString /*TargetPath*/); /** Used by OnDragEnter, OnDragOver, and OnDrop to check and update the validity of a drag-drop operation on an asset folder in the Content Browser */ bool ValidateDragDropOnAssetFolder(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent, const FString& TargetPath, bool& OutIsKnownDragOperation); - /** Handle assets being dropped onto an asset folder in the Content Browser - this drop should have been externally validated by ValidateDragDropOnAssetFolder */ - void HandleAssetsDroppedOnAssetFolder(const TSharedRef& ParentWidget, const TArray& AssetList, const FString& TargetPath, const FText& TargetDisplayName, FExecuteCopyOrMoveAssets CopyActionHandler, FExecuteCopyOrMoveAssets MoveActionHandler); - - /** Handle folders being dropped onto an asset folder in the Content Browser - this drop should have been externally validated by ValidateDragDropOnAssetFolder */ - void HandleFoldersDroppedOnAssetFolder(const TSharedRef& ParentWidget, const TArray& PathNames, const FString& TargetPath, const FText& TargetDisplayName, FExecuteCopyOrMoveFolders CopyActionHandler, FExecuteCopyOrMoveFolders MoveActionHandler); + /** Handle assets or asset paths being dropped onto an asset folder in the Content Browser - this drop should have been externally validated by ValidateDragDropOnAssetFolder */ + void HandleDropOnAssetFolder(const TSharedRef& ParentWidget, const TArray& AssetList, const TArray& AssetPaths, const FString& TargetPath, const FText& TargetDisplayName, FExecuteCopyOrMove CopyActionHandler, FExecuteCopyOrMove MoveActionHandler); } diff --git a/Engine/Source/Editor/ContentBrowser/Private/EmptyFolderVisibilityManager.cpp b/Engine/Source/Editor/ContentBrowser/Private/EmptyFolderVisibilityManager.cpp new file mode 100644 index 000000000000..1df6e78d5e78 --- /dev/null +++ b/Engine/Source/Editor/ContentBrowser/Private/EmptyFolderVisibilityManager.cpp @@ -0,0 +1,85 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "EmptyFolderVisibilityManager.h" +#include "AssetRegistryModule.h" +#include "ContentBrowserUtils.h" +#include "Settings/ContentBrowserSettings.h" +#include "Paths.h" + +FEmptyFolderVisibilityManager::FEmptyFolderVisibilityManager() +{ + // Load the asset registry module to listen for updates + FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(TEXT("AssetRegistry")); + AssetRegistryModule.Get().OnPathRemoved().AddRaw(this, &FEmptyFolderVisibilityManager::OnAssetRegistryPathRemoved); + AssetRegistryModule.Get().OnAssetAdded().AddRaw(this, &FEmptyFolderVisibilityManager::OnAssetRegistryAssetAdded); + + // Query all paths currently gathered from the asset registry + TArray PathList; + AssetRegistryModule.Get().GetAllCachedPaths(PathList); + for (const FString& Path : PathList) + { + const bool bPathIsEmpty = ContentBrowserUtils::IsEmptyFolder(Path, true); + if (!bPathIsEmpty) + { + PathsToAlwaysShow.Add(Path); + } + } +} + +FEmptyFolderVisibilityManager::~FEmptyFolderVisibilityManager() +{ + if (FModuleManager::Get().IsModuleLoaded(TEXT("AssetRegistry"))) + { + // Load the asset registry module to stop listening for updates + FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(TEXT("AssetRegistry")); + AssetRegistryModule.Get().OnPathRemoved().RemoveAll(this); + AssetRegistryModule.Get().OnAssetAdded().RemoveAll(this); + } +} + +bool FEmptyFolderVisibilityManager::ShouldShowPath(const FString& InPath) const +{ + const bool bDisplayEmpty = GetDefault()->DisplayEmptyFolders; + if (bDisplayEmpty) + { + return true; + } + + const bool bPathIsEmpty = ContentBrowserUtils::IsEmptyFolder(InPath, true); + return !bPathIsEmpty || PathsToAlwaysShow.Contains(InPath); +} + +void FEmptyFolderVisibilityManager::SetAlwaysShowPath(const FString& InPath) +{ + if (InPath.IsEmpty()) + { + return; + } + + FString PathToAdd = InPath; + + bool bWasAlreadyShown = false; + if (PathToAdd[PathToAdd.Len() - 1] == TEXT('/')) + { + PathToAdd = PathToAdd.Mid(0, PathToAdd.Len() - 1); + } + PathsToAlwaysShow.Add(PathToAdd, &bWasAlreadyShown); + + if (!bWasAlreadyShown) + { + OnFolderPopulatedDelegate.Broadcast(PathToAdd); + + // We also need to make sure the parents of this path are on the visible list too + SetAlwaysShowPath(FPaths::GetPath(PathToAdd)); + } +} + +void FEmptyFolderVisibilityManager::OnAssetRegistryPathRemoved(const FString& InPath) +{ + PathsToAlwaysShow.Remove(InPath); +} + +void FEmptyFolderVisibilityManager::OnAssetRegistryAssetAdded(const FAssetData& InAssetData) +{ + SetAlwaysShowPath(InAssetData.PackagePath.ToString()); +} diff --git a/Engine/Source/Editor/ContentBrowser/Private/EmptyFolderVisibilityManager.h b/Engine/Source/Editor/ContentBrowser/Private/EmptyFolderVisibilityManager.h new file mode 100644 index 000000000000..102af6cb15a8 --- /dev/null +++ b/Engine/Source/Editor/ContentBrowser/Private/EmptyFolderVisibilityManager.h @@ -0,0 +1,41 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "AssetData.h" + +/** Class that controls which empty folders should be visible in the Content Browser */ +class FEmptyFolderVisibilityManager +{ +public: + DECLARE_MULTICAST_DELEGATE_OneParam(FOnFolderPopulated, const FString& /*InPath*/); + + FEmptyFolderVisibilityManager(); + ~FEmptyFolderVisibilityManager(); + + /** Check to see whether the given path should be shown in the Content Browser */ + bool ShouldShowPath(const FString& InPath) const; + + /** Set whether the given path should always be shown, even if it's currently empty */ + void SetAlwaysShowPath(const FString& InPath); + + /** Delegate called when a folder is populated and should appear in the Content Browser */ + FOnFolderPopulated& OnFolderPopulated() + { + return OnFolderPopulatedDelegate; + } + +private: + /** Handles updating the content browser when an asset path is removed from the asset registry */ + void OnAssetRegistryPathRemoved(const FString& InPath); + + /** Handles updating the content browser when an asset is added to the asset registry */ + void OnAssetRegistryAssetAdded(const FAssetData& InAssetData); + + /** Set set of paths that should always be shown, even if they're currently empty */ + TSet PathsToAlwaysShow; + + /** Delegate called when a folder is populated and should appear in the Content Browser */ + FOnFolderPopulated OnFolderPopulatedDelegate; +}; diff --git a/Engine/Source/Editor/ContentBrowser/Private/FrontendFilters.cpp b/Engine/Source/Editor/ContentBrowser/Private/FrontendFilters.cpp index 5504afc4a1ac..f8f620159b57 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/FrontendFilters.cpp +++ b/Engine/Source/Editor/ContentBrowser/Private/FrontendFilters.cpp @@ -17,6 +17,63 @@ // FFrontendFilter_Text ///////////////////////////////////////// +/** Mapping of asset property tag aliases that can be used by text searches */ +class FFrontendFilter_AssetPropertyTagAliases +{ +public: + static FFrontendFilter_AssetPropertyTagAliases& Get() + { + static FFrontendFilter_AssetPropertyTagAliases Singleton; + return Singleton; + } + + /** Get the source tag for the given asset data and alias, or none if there is no match */ + FName GetSourceTagFromAlias(const FAssetData& InAssetData, const FName InAlias) + { + TSharedPtr>& AliasToSourceTagMapping = ClassToAliasTagsMapping.FindOrAdd(InAssetData.AssetClass); + + if (!AliasToSourceTagMapping.IsValid()) + { + static const FName NAME_DisplayName(TEXT("DisplayName")); + + UClass* AssetClass = InAssetData.GetClass(); + + TMap AssetTagMetaData; + AssetClass->GetDefaultObject()->GetAssetRegistryTagMetadata(AssetTagMetaData); + + AliasToSourceTagMapping = MakeShared>(); + + for (const auto& AssetTagMetaDataPair : AssetTagMetaData) + { + if (!AssetTagMetaDataPair.Value.DisplayName.IsEmpty()) + { + const FName DisplayName = MakeObjectNameFromDisplayLabel(AssetTagMetaDataPair.Value.DisplayName.ToString(), NAME_None); + AliasToSourceTagMapping->Add(DisplayName, AssetTagMetaDataPair.Key); + } + } + + for (const auto& KeyValuePair : InAssetData.TagsAndValues) + { + if (UProperty* Field = FindField(AssetClass, KeyValuePair.Key)) + { + if (Field->HasMetaData(NAME_DisplayName)) + { + const FName DisplayName = MakeObjectNameFromDisplayLabel(Field->GetMetaData(NAME_DisplayName), NAME_None); + AliasToSourceTagMapping->Add(DisplayName, KeyValuePair.Key); + } + } + } + } + + check(AliasToSourceTagMapping.IsValid()); + return AliasToSourceTagMapping->FindRef(InAlias); + } + +private: + /** Mapping from class name -> (alias -> source) */ + TMap>> ClassToAliasTagsMapping; +}; + /** Expression context which gathers up the names of any dynamic collections being referenced by the current query */ class FFrontendFilter_GatherDynamicCollectionsExpressionContext : public ITextFilterExpressionContext { @@ -362,10 +419,30 @@ public: } // Generic handling for anything in the asset meta-data - FString MetaDataValue; - if (AssetPtr->GetTagValue(InKey, MetaDataValue)) { - return TextFilterUtils::TestComplexExpression(MetaDataValue, InValue, InComparisonOperation, InTextComparisonMode); + auto GetMetaDataValue = [this, &InKey](FString& OutMetaDataValue) -> bool + { + // Check for a literal key + if (AssetPtr->GetTagValue(InKey, OutMetaDataValue)) + { + return true; + } + + // Check for an alias key + const FName LiteralKey = FFrontendFilter_AssetPropertyTagAliases::Get().GetSourceTagFromAlias(*AssetPtr, InKey); + if (!LiteralKey.IsNone() && AssetPtr->GetTagValue(LiteralKey, OutMetaDataValue)) + { + return true; + } + + return false; + }; + + FString MetaDataValue; + if (GetMetaDataValue(MetaDataValue)) + { + return TextFilterUtils::TestComplexExpression(MetaDataValue, InValue, InComparisonOperation, InTextComparisonMode); + } } return false; diff --git a/Engine/Source/Editor/ContentBrowser/Private/HistoryManager.h b/Engine/Source/Editor/ContentBrowser/Private/HistoryManager.h index c0b0e3840f28..0cf884afa67f 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/HistoryManager.h +++ b/Engine/Source/Editor/ContentBrowser/Private/HistoryManager.h @@ -7,6 +7,29 @@ class FMenuBuilder; +struct FSelectionData +{ + TSet SelectedAssets; + TSet SelectedFolders; + + int32 Num() const + { + return SelectedAssets.Num() + SelectedFolders.Num(); + } + + void Reset() + { + SelectedAssets.Reset(); + SelectedFolders.Reset(); + } + + void Empty() + { + SelectedAssets.Empty(); + SelectedFolders.Empty(); + } +}; + /** The history data object, storing all important history data */ struct FHistoryData { @@ -16,8 +39,8 @@ struct FHistoryData /** The base set of filters on the asset view which includes selected paths and collections */ FSourcesData SourcesData; - /** The object paths for selected assets before the sources changed */ - TSet SelectedAssets; + /** The selection data from before the sources changed */ + FSelectionData SelectionData; }; /** The delegate for when history data should be applied */ diff --git a/Engine/Source/Editor/ContentBrowser/Private/NativeClassHierarchy.cpp b/Engine/Source/Editor/ContentBrowser/Private/NativeClassHierarchy.cpp index 32227e3195b8..94ae67750682 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/NativeClassHierarchy.cpp +++ b/Engine/Source/Editor/ContentBrowser/Private/NativeClassHierarchy.cpp @@ -65,9 +65,41 @@ FNativeClassHierarchy::~FNativeClassHierarchy() } } +bool FNativeClassHierarchy::HasClasses(const FName InClassPath, const bool bRecursive) const +{ + TArray, TInlineAllocator<4>> NodesToSearch; + GatherMatchingNodesForPaths(TArrayView(&InClassPath, 1), NodesToSearch); + + for(const auto& NodeToSearch : NodesToSearch) + { + if(HasClassesRecursive(NodeToSearch, bRecursive)) + { + return true; + } + } + + return false; +} + +bool FNativeClassHierarchy::HasFolders(const FName InClassPath, const bool bRecursive) const +{ + TArray, TInlineAllocator<4>> NodesToSearch; + GatherMatchingNodesForPaths(TArrayView(&InClassPath, 1), NodesToSearch); + + for(const auto& NodeToSearch : NodesToSearch) + { + if(HasFoldersRecursive(NodeToSearch, bRecursive)) + { + return true; + } + } + + return false; +} + void FNativeClassHierarchy::GetMatchingClasses(const FNativeClassHierarchyFilter& Filter, TArray& OutClasses) const { - TArray> NodesToSearch; + TArray, TInlineAllocator<4>> NodesToSearch; GatherMatchingNodesForPaths(Filter.ClassPaths, NodesToSearch); for(const auto& NodeToSearch : NodesToSearch) @@ -78,7 +110,7 @@ void FNativeClassHierarchy::GetMatchingClasses(const FNativeClassHierarchyFilter void FNativeClassHierarchy::GetMatchingFolders(const FNativeClassHierarchyFilter& Filter, TArray& OutFolders) const { - TArray> NodesToSearch; + TArray, TInlineAllocator<4>> NodesToSearch; GatherMatchingNodesForPaths(Filter.ClassPaths, NodesToSearch); for(const auto& NodeToSearch : NodesToSearch) @@ -108,6 +140,42 @@ void FNativeClassHierarchy::GetClassFolders(TArray& OutClassRoots, TArray } } +bool FNativeClassHierarchy::HasClassesRecursive(const TSharedRef& HierarchyNode, const bool bRecurse) +{ + for(const auto& ChildNode : HierarchyNode->Children) + { + if(ChildNode.Value->Type == ENativeClassHierarchyNodeType::Class) + { + return true; + } + + if(bRecurse && HasClassesRecursive(ChildNode.Value.ToSharedRef())) + { + return true; + } + } + + return false; +} + +bool FNativeClassHierarchy::HasFoldersRecursive(const TSharedRef& HierarchyNode, const bool bRecurse) +{ + for(const auto& ChildNode : HierarchyNode->Children) + { + if(ChildNode.Value->Type == ENativeClassHierarchyNodeType::Folder) + { + return true; + } + + if(bRecurse && HasFoldersRecursive(ChildNode.Value.ToSharedRef())) + { + return true; + } + } + + return false; +} + void FNativeClassHierarchy::GetClassesRecursive(const TSharedRef& HierarchyNode, TArray& OutClasses, const bool bRecurse) { for(const auto& ChildNode : HierarchyNode->Children) @@ -140,7 +208,7 @@ void FNativeClassHierarchy::GetFoldersRecursive(const TSharedRef& InClassPaths, TArray>& OutMatchingNodes) const +void FNativeClassHierarchy::GatherMatchingNodesForPaths(const TArrayView& InClassPaths, TArray, TInlineAllocator<4>>& OutMatchingNodes) const { if(InClassPaths.Num() == 0) { diff --git a/Engine/Source/Editor/ContentBrowser/Private/NativeClassHierarchy.h b/Engine/Source/Editor/ContentBrowser/Private/NativeClassHierarchy.h index 7e6050b00ad4..b52e1d32a12c 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/NativeClassHierarchy.h +++ b/Engine/Source/Editor/ContentBrowser/Private/NativeClassHierarchy.h @@ -3,6 +3,7 @@ #pragma once #include "CoreMinimal.h" +#include "Containers/ArrayView.h" #include "HAL/PlatformTime.h" #include "IPluginManager.h" @@ -159,6 +160,22 @@ public: return ClassHierarchyUpdatedDelegate; } + /** + * Does the given path contain classes, optionally also testing sub-paths? + * + * @param InClassPath - The path to query classes in + * @param bRecursive - If true, the supplied path will be tested recursively + */ + bool HasClasses(const FName InClassPath, const bool bRecursive = false) const; + + /** + * Does the given path contain folders, optionally also testing sub-paths? + * + * @param InClassPath - The path to query classes in + * @param bRecursive - If true, the supplied path will be tested recursively + */ + bool HasFolders(const FName InClassPath, const bool bRecursive = false) const; + /** * Work out which classes known to the class hierarchy match the given filter * @@ -230,6 +247,26 @@ private: int32 NumFoldersAdded; }; + /** + * Test to see whether the given node has any child classes + * + * @param HierarchyNode - The node to test the children of + * @param bRecurse - True to recurse into sub-folders, false to only check the given node + * + * @return True if the node has child classes, false otherwise + */ + static bool HasClassesRecursive(const TSharedRef& HierarchyNode, const bool bRecurse = true); + + /** + * Test to see whether the given node has any child folders + * + * @param HierarchyNode - The node to test the children of + * @param bRecurse - True to recurse into sub-folders, false to only check the given node + * + * @return True if the node has child folders, false otherwise + */ + static bool HasFoldersRecursive(const TSharedRef& HierarchyNode, const bool bRecurse = true); + /** * Update OutClasses with any classes that are children of the given node * @@ -254,7 +291,7 @@ private: * @param InClassPaths - The class paths to find the nodes for, or an empty list to get all root nodes * @param OutMatchingNodes - Array to be populated the nodes that correspond to the given class paths */ - void GatherMatchingNodesForPaths(const TArray& InClassPaths, TArray>& OutMatchingNodes) const; + void GatherMatchingNodesForPaths(const TArrayView& InClassPaths, TArray, TInlineAllocator<4>>& OutMatchingNodes) const; /** * Completely clear and re-populate the known class hierarchy diff --git a/Engine/Source/Editor/ContentBrowser/Private/SAssetDialog.cpp b/Engine/Source/Editor/ContentBrowser/Private/SAssetDialog.cpp index c3d5a6c9124b..67b950221d5e 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/SAssetDialog.cpp +++ b/Engine/Source/Editor/ContentBrowser/Private/SAssetDialog.cpp @@ -124,6 +124,7 @@ void SAssetDialog::Construct(const FArguments& InArgs, const FSharedAssetDialogC PathPicker = StaticCastSharedRef(FContentBrowserSingleton::Get().CreatePathPicker(PathPickerConfig)); AssetPicker = StaticCastSharedRef(FContentBrowserSingleton::Get().CreateAssetPicker(AssetPickerConfig)); + FContentBrowserCommands::Register(); BindCommands(); // The root widget in this dialog. diff --git a/Engine/Source/Editor/ContentBrowser/Private/SAssetPicker.cpp b/Engine/Source/Editor/ContentBrowser/Private/SAssetPicker.cpp index 8c4499020ac3..4770a50847cd 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/SAssetPicker.cpp +++ b/Engine/Source/Editor/ContentBrowser/Private/SAssetPicker.cpp @@ -384,7 +384,10 @@ void SAssetPicker::OnSearchBoxCommitted(const FText& InSearchText, ETextCommit:: void SAssetPicker::SetNewBackendFilter(const FARFilter& NewFilter) { CurrentSourcesData.PackagePaths = NewFilter.PackagePaths; - AssetViewPtr->SetSourcesData(CurrentSourcesData); + if(AssetViewPtr.IsValid()) + { + AssetViewPtr->SetSourcesData(CurrentSourcesData); + } CurrentBackendFilter = NewFilter; CurrentBackendFilter.PackagePaths.Reset(); @@ -410,7 +413,10 @@ void SAssetPicker::OnFilterChanged() } Filter.Append(CurrentBackendFilter); - AssetViewPtr->SetBackendFilter( Filter ); + if (AssetViewPtr.IsValid()) + { + AssetViewPtr->SetBackendFilter( Filter ); + } } FReply SAssetPicker::OnNoneButtonClicked() diff --git a/Engine/Source/Editor/ContentBrowser/Private/SAssetView.cpp b/Engine/Source/Editor/ContentBrowser/Private/SAssetView.cpp index 4626a829a07c..cb14d21e63e4 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/SAssetView.cpp +++ b/Engine/Source/Editor/ContentBrowser/Private/SAssetView.cpp @@ -1,6 +1,7 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "SAssetView.h" +#include "HAL/FileManager.h" #include "UObject/UnrealType.h" #include "Widgets/SOverlay.h" #include "Engine/GameViewportClient.h" @@ -33,16 +34,15 @@ #include "ContentBrowserLog.h" #include "FrontendFilterBase.h" #include "ContentBrowserSingleton.h" -#include "HistoryManager.h" #include "EditorWidgetsModule.h" #include "AssetViewTypes.h" #include "DragAndDrop/AssetDragDropOp.h" -#include "DragAndDrop/AssetPathDragDropOp.h" #include "DragDropHandler.h" #include "AssetViewWidgets.h" #include "ContentBrowserModule.h" #include "ObjectTools.h" #include "NativeClassHierarchy.h" +#include "EmptyFolderVisibilityManager.h" #include "Framework/Notifications/NotificationManager.h" #include "Widgets/Notifications/SNotificationList.h" #include "SSplitter.h" @@ -77,6 +77,12 @@ SAssetView::~SAssetView() FCoreUObjectDelegates::OnAssetLoaded.RemoveAll(this); FCoreUObjectDelegates::OnObjectPropertyChanged.RemoveAll(this); + // Unsubscribe from folder population events + { + TSharedRef EmptyFolderVisibilityManager = FContentBrowserSingleton::Get().GetEmptyFolderVisibilityManager(); + EmptyFolderVisibilityManager->OnFolderPopulated().RemoveAll(this); + } + // Unsubscribe from class events if ( bCanShowClasses ) { @@ -136,6 +142,12 @@ void SAssetView::Construct( const FArguments& InArgs ) NativeClassHierarchy->OnClassHierarchyUpdated().AddSP( this, &SAssetView::OnClassHierarchyUpdated ); } + // Listen to find out when previously empty paths are populated with content + { + TSharedRef EmptyFolderVisibilityManager = FContentBrowserSingleton::Get().GetEmptyFolderVisibilityManager(); + EmptyFolderVisibilityManager->OnFolderPopulated().AddSP(this, &SAssetView::OnFolderPopulated); + } + // Listen for when view settings are changed UContentBrowserSettings::OnSettingChanged().AddSP(this, &SAssetView::HandleSettingChanged); @@ -551,11 +563,8 @@ void SAssetView::DeferredCreateNewAsset() FName PackagePathFName = FName(*DeferredAssetToCreate->PackagePath); FName AssetName = FName(*DeferredAssetToCreate->DefaultAssetName); FName AssetClassName = DeferredAssetToCreate->AssetClass->GetFName(); - TMap EmptyTags; - TArray EmptyChunkIDs; - const uint32 EmptyPackageFlags = 0; - FAssetData NewAssetData(PackageName, PackagePathFName, NAME_None, AssetName, AssetClassName, EmptyTags, EmptyChunkIDs, EmptyPackageFlags); + FAssetData NewAssetData(PackageName, PackagePathFName, AssetName, AssetClassName); TSharedPtr NewItem = MakeShareable(new FAssetViewCreation(NewAssetData, DeferredAssetToCreate->AssetClass, DeferredAssetToCreate->Factory)); NewItem->bRenameWhenScrolledIntoview = true; @@ -590,11 +599,8 @@ void SAssetView::DuplicateAsset(const FString& PackagePath, const TWeakObjectPtr FName PackagePathFName = FName(*PackagePath); FName AssetName = FName(*AssetNameStr); FName AssetClass = OriginalObject->GetClass()->GetFName(); - TMap EmptyTags; - TArray EmptyChunkIDs; - const uint32 EmptyPackageFlags = 0; - - FAssetData NewAssetData(PackageName, PackagePathFName, NAME_None, AssetName, AssetClass, EmptyTags, EmptyChunkIDs, EmptyPackageFlags); + + FAssetData NewAssetData(PackageName, PackagePathFName, AssetName, AssetClass); TSharedPtr NewItem = MakeShareable(new FAssetViewDuplication(NewAssetData, OriginalObject)); NewItem->bRenameWhenScrolledIntoview = true; @@ -648,19 +654,62 @@ void SAssetView::RenameFolder(const FString& FolderToRename) void SAssetView::SyncToAssets( const TArray& AssetDataList, const bool bFocusOnSync ) { - PendingSyncAssets.Empty(); - for ( auto AssetIt = AssetDataList.CreateConstIterator(); AssetIt; ++AssetIt ) + PendingSyncItems.Reset(); + for (const FAssetData& AssetData : AssetDataList) { - PendingSyncAssets.Add(AssetIt->ObjectPath); + PendingSyncItems.SelectedAssets.Add(AssetData.ObjectPath); } bPendingFocusOnSync = bFocusOnSync; } -void SAssetView::ApplyHistoryData ( const FHistoryData& History ) +void SAssetView::SyncToFolders(const TArray& FolderList, const bool bFocusOnSync) +{ + PendingSyncItems.Reset(); + PendingSyncItems.SelectedFolders = TSet(FolderList); + + bPendingFocusOnSync = bFocusOnSync; +} + +void SAssetView::SyncTo(const FContentBrowserSelection& ItemSelection, const bool bFocusOnSync) +{ + PendingSyncItems.Reset(); + PendingSyncItems.SelectedFolders = TSet(ItemSelection.SelectedFolders); + for (const FAssetData& AssetData : ItemSelection.SelectedAssets) + { + PendingSyncItems.SelectedAssets.Add(AssetData.ObjectPath); + } + + bPendingFocusOnSync = bFocusOnSync; +} + +void SAssetView::SyncToSelection( const bool bFocusOnSync ) +{ + PendingSyncItems.Reset(); + + TArray> SelectedItems = GetSelectedItems(); + for (const TSharedPtr& Item : SelectedItems) + { + if (Item.IsValid()) + { + if (Item->GetType() == EAssetItemType::Folder) + { + PendingSyncItems.SelectedFolders.Add(StaticCastSharedPtr(Item)->FolderPath); + } + else + { + PendingSyncItems.SelectedAssets.Add(StaticCastSharedPtr(Item)->Data.ObjectPath); + } + } + } + + bPendingFocusOnSync = bFocusOnSync; +} + +void SAssetView::ApplyHistoryData( const FHistoryData& History ) { SetSourcesData(History.SourcesData); - PendingSyncAssets = History.SelectedAssets; + PendingSyncItems = History.SelectionData; bPendingFocusOnSync = true; } @@ -951,12 +1000,12 @@ void SAssetView::Tick( const FGeometry& AllottedGeometry, const double InCurrent RefreshFilteredItems(); RefreshFolders(); // Don't sync to selection if we are just going to do it below - SortList(!PendingSyncAssets.Num()); + SortList(!PendingSyncItems.Num()); bQuickFrontendListRefreshRequested = false; } - if ( PendingSyncAssets.Num() ) + if ( PendingSyncItems.Num() > 0 ) { if (bPendingSortFilteredItems) { @@ -971,18 +1020,36 @@ void SAssetView::Tick( const FGeometry& AllottedGeometry, const double InCurrent for ( auto ItemIt = FilteredAssetItems.CreateConstIterator(); ItemIt; ++ItemIt ) { const auto& Item = *ItemIt; - if(Item.IsValid() && Item->GetType() != EAssetItemType::Folder) + if(Item.IsValid()) { - const TSharedPtr& ItemAsAsset = StaticCastSharedPtr(Item); - if ( PendingSyncAssets.Contains(ItemAsAsset->Data.ObjectPath) ) + if(Item->GetType() == EAssetItemType::Folder) { - SetItemSelection(*ItemIt, true, ESelectInfo::OnNavigation); - - // Scroll the first item in the list that can be shown into view - if ( !bFoundScrollIntoViewTarget ) + const TSharedPtr& ItemAsFolder = StaticCastSharedPtr(Item); + if ( PendingSyncItems.SelectedFolders.Contains(ItemAsFolder->FolderPath) ) { - RequestScrollIntoView(Item); - bFoundScrollIntoViewTarget = true; + SetItemSelection(*ItemIt, true, ESelectInfo::OnNavigation); + + // Scroll the first item in the list that can be shown into view + if ( !bFoundScrollIntoViewTarget ) + { + RequestScrollIntoView(Item); + bFoundScrollIntoViewTarget = true; + } + } + } + else + { + const TSharedPtr& ItemAsAsset = StaticCastSharedPtr(Item); + if ( PendingSyncItems.SelectedAssets.Contains(ItemAsAsset->Data.ObjectPath) ) + { + SetItemSelection(*ItemIt, true, ESelectInfo::OnNavigation); + + // Scroll the first item in the list that can be shown into view + if ( !bFoundScrollIntoViewTarget ) + { + RequestScrollIntoView(Item); + bFoundScrollIntoViewTarget = true; + } } } } @@ -998,7 +1065,7 @@ void SAssetView::Tick( const FGeometry& AllottedGeometry, const double InCurrent // Default to always notifying bShouldNotifyNextAssetSync = true; - PendingSyncAssets.Empty(); + PendingSyncItems.Reset(); if (bAllowFocusOnSync && bPendingFocusOnSync) { @@ -1643,7 +1710,7 @@ void SAssetView::RefreshSourceItems() if ( bShowAll ) { AssetRegistryModule.Get().GetAllAssets(Items); - bShowClasses = true; + bShowClasses = IsShowingCppContent(); bWereItemsRecursivelyFiltered = true; } else @@ -1672,7 +1739,7 @@ void SAssetView::RefreshSourceItems() }); // Only show classes if we have class paths, and the filter allows classes to be shown - const bool bFilterAllowsClasses = Filter.ClassNames.Num() == 0 || Filter.ClassNames.Contains(NAME_Class); + const bool bFilterAllowsClasses = IsShowingCppContent() && (Filter.ClassNames.Num() == 0 || Filter.ClassNames.Contains(NAME_Class)); bShowClasses = (ClassPathsToShow.Num() > 0 || bIsDynamicCollection) && bFilterAllowsClasses; if ( SourcesData.HasCollections() && Filter.ObjectPaths.Num() == 0 && !bIsDynamicCollection ) @@ -1715,7 +1782,7 @@ void SAssetView::RefreshSourceItems() } // If we are showing classes in the asset list... - if (bShowClasses && bCanShowClasses) + if (bShowClasses) { // Load the native class hierarchy TSharedRef NativeClassHierarchy = FContentBrowserSingleton::Get().GetNativeClassHierarchy(); @@ -1734,9 +1801,9 @@ void SAssetView::RefreshSourceItems() } // Remove any assets that should be filtered out any redirectors and non-assets - const bool bDisplayEngine = GetDefault()->GetDisplayEngineFolder(); - const bool bDisplayPlugins = GetDefault()->GetDisplayPluginFolders(); - const bool bDisplayL10N = GetDefault()->GetDisplayL10NFolder(); + const bool bDisplayEngine = IsShowingEngineContent(); + const bool bDisplayPlugins = IsShowingPluginContent(); + const bool bDisplayL10N = IsShowingLocalizedContent(); for (int32 AssetIdx = Items.Num() - 1; AssetIdx >= 0; --AssetIdx) { const FAssetData& Item = Items[AssetIdx]; @@ -1988,8 +2055,11 @@ void SAssetView::RefreshFolders() TArray FoldersToAdd; - const bool bDisplayDev = GetDefault()->GetDisplayDevelopersFolder(); - const bool bDisplayL10N = GetDefault()->GetDisplayL10NFolder(); + TSharedRef EmptyFolderVisibilityManager = FContentBrowserSingleton::Get().GetEmptyFolderVisibilityManager(); + + const bool bDisplayEmpty = IsShowingEmptyFolders(); + const bool bDisplayDev = IsShowingDevelopersContent(); + const bool bDisplayL10N = IsShowingLocalizedContent(); FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(TEXT("AssetRegistry")); { TArray SubPaths; @@ -2000,8 +2070,12 @@ void SAssetView::RefreshFolders() for(const FString& SubPath : SubPaths) { - // If this is a developer folder, and we don't want to show them try the next path - if(!bDisplayDev && ContentBrowserUtils::IsDevelopersFolder(SubPath)) + if (!bDisplayEmpty && !EmptyFolderVisibilityManager->ShouldShowPath(SubPath)) + { + continue; + } + + if (!bDisplayDev && ContentBrowserUtils::IsDevelopersFolder(SubPath)) { continue; } @@ -2020,7 +2094,7 @@ void SAssetView::RefreshFolders() } // If we are showing classes in the asset list then we need to show their folders too - if(bCanShowClasses && ClassPathsToShow.Num() > 0) + if(IsShowingCppContent() && ClassPathsToShow.Num() > 0) { // Load the native class hierarchy TSharedRef NativeClassHierarchy = FContentBrowserSingleton::Get().GetNativeClassHierarchy(); @@ -2389,9 +2463,16 @@ void SAssetView::OnAssetRegistryPathAdded(const FString& Path) { if(IsShowingFolders() && !ShouldFilterRecursively()) { + TSharedRef EmptyFolderVisibilityManager = FContentBrowserSingleton::Get().GetEmptyFolderVisibilityManager(); + // If this isn't a developer folder or we want to show them, continue - const bool bDisplayDev = GetDefault()->GetDisplayDevelopersFolder(); - if ( bDisplayDev || !ContentBrowserUtils::IsDevelopersFolder(Path) ) + const bool bDisplayEmpty = IsShowingEmptyFolders(); + const bool bDisplayDev = IsShowingDevelopersContent(); + const bool bDisplayL10N = IsShowingLocalizedContent(); + if ((bDisplayEmpty || EmptyFolderVisibilityManager->ShouldShowPath(Path)) && + (bDisplayDev || !ContentBrowserUtils::IsDevelopersFolder(Path)) && + (bDisplayL10N || !ContentBrowserUtils::IsLocalizationFolder(Path)) + ) { for (const FName& SourcePathName : SourcesData.PackagePaths) { @@ -2417,7 +2498,7 @@ void SAssetView::OnAssetRegistryPathAdded(const FString& Path) } } } - } + } } void SAssetView::OnAssetRegistryPathRemoved(const FString& Path) @@ -2443,6 +2524,11 @@ void SAssetView::OnAssetRegistryPathRemoved(const FString& Path) } } +void SAssetView::OnFolderPopulated(const FString& Path) +{ + OnAssetRegistryPathAdded(Path); +} + void SAssetView::RemoveAssetByPath( const FName& ObjectPath ) { bool bFoundAsset = false; @@ -2624,12 +2710,8 @@ void SAssetView::SortList(bool bSyncToSelection) if ( bSyncToSelection ) { // Make sure the selection is in view - TArray SelectedAssets = GetSelectedAssets(); - if ( SelectedAssets.Num() > 0 ) - { - const bool bFocusOnSync = false; - SyncToAssets(SelectedAssets, bFocusOnSync); - } + const bool bFocusOnSync = false; + SyncToSelection(bFocusOnSync); } RefreshList(); @@ -2717,97 +2799,117 @@ TSharedRef SAssetView::GetViewButtonContent() } MenuBuilder.EndSection(); - MenuBuilder.BeginSection("Folders", LOCTEXT("FoldersHeading", "Folders")); + MenuBuilder.BeginSection("View", LOCTEXT("ViewHeading", "View")); { - MenuBuilder.AddMenuEntry( + auto CreateShowFoldersSubMenu = [this](FMenuBuilder& SubMenuBuilder) + { + SubMenuBuilder.AddMenuEntry( + LOCTEXT("ShowEmptyFoldersOption", "Show Empty Folders"), + LOCTEXT("ShowEmptyFoldersOptionToolTip", "Show empty folders in the view as well as assets?"), + FSlateIcon(), + FUIAction( + FExecuteAction::CreateSP( this, &SAssetView::ToggleShowEmptyFolders ), + FCanExecuteAction::CreateSP( this, &SAssetView::IsToggleShowEmptyFoldersAllowed ), + FIsActionChecked::CreateSP( this, &SAssetView::IsShowingEmptyFolders ) + ), + NAME_None, + EUserInterfaceActionType::ToggleButton + ); + }; + + MenuBuilder.AddSubMenu( LOCTEXT("ShowFoldersOption", "Show Folders"), - LOCTEXT("ShowFoldersOptionToolTip", "Show folders in the view as well as assets."), - FSlateIcon(), + LOCTEXT("ShowFoldersOptionToolTip", "Show folders in the view as well as assets?"), + FNewMenuDelegate::CreateLambda(CreateShowFoldersSubMenu), FUIAction( FExecuteAction::CreateSP( this, &SAssetView::ToggleShowFolders ), FCanExecuteAction::CreateSP( this, &SAssetView::IsToggleShowFoldersAllowed ), FIsActionChecked::CreateSP( this, &SAssetView::IsShowingFolders ) - ), - NAME_None, - EUserInterfaceActionType::ToggleButton - ); - - MenuBuilder.AddMenuEntry( - LOCTEXT("ShowL10NFolderOption", "Show Localized Assets"), - LOCTEXT("ShowL10NFolderOptionToolTip", "Show assets within the localized asset directory."), - FSlateIcon(), - FUIAction( - FExecuteAction::CreateSP(this, &SAssetView::ToggleShowL10NFolder), - FCanExecuteAction::CreateSP(this, &SAssetView::IsToggleShowL10NFolderAllowed), - FIsActionChecked::CreateSP(this, &SAssetView::IsShowingL10NFolder) ), NAME_None, EUserInterfaceActionType::ToggleButton - ); - - MenuBuilder.AddMenuEntry( - LOCTEXT("ShowDevelopersFolderOption", "Show Developers Folder"), - LOCTEXT("ShowDevelopersFolderOptionToolTip", "Show the developers folder in the view."), - FSlateIcon(), - FUIAction( - FExecuteAction::CreateSP( this, &SAssetView::ToggleShowDevelopersFolder ), - FCanExecuteAction::CreateSP( this, &SAssetView::IsToggleShowDevelopersFolderAllowed ), - FIsActionChecked::CreateSP( this, &SAssetView::IsShowingDevelopersFolder ) - ), - NAME_None, - EUserInterfaceActionType::ToggleButton - ); - - MenuBuilder.AddMenuEntry( - LOCTEXT("ShowPluginFolderOption", "Show Plugin Content"), - LOCTEXT("ShowPluginFolderOptionToolTip", "Shows plugin content in the view."), - FSlateIcon(), - FUIAction( - FExecuteAction::CreateSP( this, &SAssetView::ToggleShowPluginFolders ), - FCanExecuteAction(), - FIsActionChecked::CreateSP( this, &SAssetView::IsShowingPluginFolders ) - ), - NAME_None, - EUserInterfaceActionType::ToggleButton - ); - - MenuBuilder.AddMenuEntry( - LOCTEXT("ShowEngineFolderOption", "Show Engine Content"), - LOCTEXT("ShowEngineFolderOptionToolTip", "Show the engine content in the view."), - FSlateIcon(), - FUIAction( - FExecuteAction::CreateSP( this, &SAssetView::ToggleShowEngineFolder ), - FCanExecuteAction(), - FIsActionChecked::CreateSP( this, &SAssetView::IsShowingEngineFolder ) - ), - NAME_None, - EUserInterfaceActionType::ToggleButton - ); + ); MenuBuilder.AddMenuEntry( LOCTEXT("ShowCollectionOption", "Show Collections"), - LOCTEXT("ShowCollectionOptionToolTip", "Show the collections list in the view."), + LOCTEXT("ShowCollectionOptionToolTip", "Show the collections list in the view?"), FSlateIcon(), FUIAction( - FExecuteAction::CreateSP( this, &SAssetView::ToggleShowCollections ), - FCanExecuteAction::CreateSP( this, &SAssetView::IsToggleShowCollectionsAllowed ), - FIsActionChecked::CreateSP( this, &SAssetView::IsShowingCollections ) + FExecuteAction::CreateSP( this, &SAssetView::ToggleShowCollections ), + FCanExecuteAction::CreateSP( this, &SAssetView::IsToggleShowCollectionsAllowed ), + FIsActionChecked::CreateSP( this, &SAssetView::IsShowingCollections ) ), NAME_None, EUserInterfaceActionType::ToggleButton - ); + ); + } + MenuBuilder.EndSection(); + MenuBuilder.BeginSection("Content", LOCTEXT("ContentHeading", "Content")); + { MenuBuilder.AddMenuEntry( LOCTEXT("ShowCppClassesOption", "Show C++ Classes"), - LOCTEXT("ShowCppClassesOptionToolTip", "Shows C++ Class folders in the folder browser."), + LOCTEXT("ShowCppClassesOptionToolTip", "Show C++ classes in the view?"), FSlateIcon(), FUIAction( - FExecuteAction::CreateSP( this, &SAssetView::ToggleShowCppFolders ), - FCanExecuteAction(), - FIsActionChecked::CreateSP( this, &SAssetView::IsShowingCppFolders ) + FExecuteAction::CreateSP( this, &SAssetView::ToggleShowCppContent ), + FCanExecuteAction::CreateSP( this, &SAssetView::IsToggleShowCppContentAllowed ), + FIsActionChecked::CreateSP( this, &SAssetView::IsShowingCppContent ) ), NAME_None, EUserInterfaceActionType::ToggleButton + ); + + MenuBuilder.AddMenuEntry( + LOCTEXT("ShowDevelopersContentOption", "Show Developers Content"), + LOCTEXT("ShowDevelopersContentOptionToolTip", "Show developers content in the view?"), + FSlateIcon(), + FUIAction( + FExecuteAction::CreateSP( this, &SAssetView::ToggleShowDevelopersContent ), + FCanExecuteAction::CreateSP( this, &SAssetView::IsToggleShowDevelopersContentAllowed ), + FIsActionChecked::CreateSP( this, &SAssetView::IsShowingDevelopersContent ) + ), + NAME_None, + EUserInterfaceActionType::ToggleButton + ); + + MenuBuilder.AddMenuEntry( + LOCTEXT("ShowEngineFolderOption", "Show Engine Content"), + LOCTEXT("ShowEngineFolderOptionToolTip", "Show engine content in the view?"), + FSlateIcon(), + FUIAction( + FExecuteAction::CreateSP( this, &SAssetView::ToggleShowEngineContent ), + FCanExecuteAction(), + FIsActionChecked::CreateSP( this, &SAssetView::IsShowingEngineContent ) + ), + NAME_None, + EUserInterfaceActionType::ToggleButton + ); + + MenuBuilder.AddMenuEntry( + LOCTEXT("ShowPluginFolderOption", "Show Plugin Content"), + LOCTEXT("ShowPluginFolderOptionToolTip", "Show plugin content in the view?"), + FSlateIcon(), + FUIAction( + FExecuteAction::CreateSP( this, &SAssetView::ToggleShowPluginContent ), + FCanExecuteAction(), + FIsActionChecked::CreateSP( this, &SAssetView::IsShowingPluginContent ) + ), + NAME_None, + EUserInterfaceActionType::ToggleButton + ); + + MenuBuilder.AddMenuEntry( + LOCTEXT("ShowLocalizedContentOption", "Show Localized Content"), + LOCTEXT("ShowLocalizedContentOptionToolTip", "Show localized content in the view?"), + FSlateIcon(), + FUIAction( + FExecuteAction::CreateSP(this, &SAssetView::ToggleShowLocalizedContent), + FCanExecuteAction::CreateSP(this, &SAssetView::IsToggleShowLocalizedContentAllowed), + FIsActionChecked::CreateSP(this, &SAssetView::IsShowingLocalizedContent) + ), + NAME_None, + EUserInterfaceActionType::ToggleButton ); } MenuBuilder.EndSection(); @@ -2894,7 +2996,24 @@ bool SAssetView::IsToggleShowFoldersAllowed() const bool SAssetView::IsShowingFolders() const { - return IsToggleShowFoldersAllowed() ? GetDefault()->DisplayFolders : false; + return IsToggleShowFoldersAllowed() && GetDefault()->DisplayFolders; +} + +void SAssetView::ToggleShowEmptyFolders() +{ + check( IsToggleShowEmptyFoldersAllowed() ); + GetMutableDefault()->DisplayEmptyFolders = !GetDefault()->DisplayEmptyFolders; + GetMutableDefault()->PostEditChange(); +} + +bool SAssetView::IsToggleShowEmptyFoldersAllowed() const +{ + return bCanShowFolders; +} + +bool SAssetView::IsShowingEmptyFolders() const +{ + return IsToggleShowEmptyFoldersAllowed() && GetDefault()->DisplayEmptyFolders; } void SAssetView::ToggleRealTimeThumbnails() @@ -2911,10 +3030,10 @@ bool SAssetView::CanShowRealTimeThumbnails() const bool SAssetView::IsShowingRealTimeThumbnails() const { - return CanShowRealTimeThumbnails() ? GetDefault()->RealTimeThumbnails : false; + return CanShowRealTimeThumbnails() && GetDefault()->RealTimeThumbnails; } -void SAssetView::ToggleShowPluginFolders() +void SAssetView::ToggleShowPluginContent() { bool bDisplayPlugins = GetDefault()->GetDisplayPluginFolders(); bool bRawDisplayPlugins = GetDefault()->GetDisplayPluginFolders( true ); @@ -2932,12 +3051,12 @@ void SAssetView::ToggleShowPluginFolders() GetMutableDefault()->PostEditChange(); } -bool SAssetView::IsShowingPluginFolders() const +bool SAssetView::IsShowingPluginContent() const { return GetDefault()->GetDisplayPluginFolders(); } -void SAssetView::ToggleShowEngineFolder() +void SAssetView::ToggleShowEngineContent() { bool bDisplayEngine = GetDefault()->GetDisplayEngineFolder(); bool bRawDisplayEngine = GetDefault()->GetDisplayEngineFolder( true ); @@ -2955,12 +3074,12 @@ void SAssetView::ToggleShowEngineFolder() GetMutableDefault()->PostEditChange(); } -bool SAssetView::IsShowingEngineFolder() const +bool SAssetView::IsShowingEngineContent() const { return GetDefault()->GetDisplayEngineFolder(); } -void SAssetView::ToggleShowDevelopersFolder() +void SAssetView::ToggleShowDevelopersContent() { bool bDisplayDev = GetDefault()->GetDisplayDevelopersFolder(); bool bRawDisplayDev = GetDefault()->GetDisplayDevelopersFolder( true ); @@ -2978,30 +3097,30 @@ void SAssetView::ToggleShowDevelopersFolder() GetMutableDefault()->PostEditChange(); } -bool SAssetView::IsToggleShowDevelopersFolderAllowed() const +bool SAssetView::IsToggleShowDevelopersContentAllowed() const { return bCanShowDevelopersFolder; } -bool SAssetView::IsShowingDevelopersFolder() const +bool SAssetView::IsShowingDevelopersContent() const { - return GetDefault()->GetDisplayDevelopersFolder(); + return IsToggleShowDevelopersContentAllowed() && GetDefault()->GetDisplayDevelopersFolder(); } -void SAssetView::ToggleShowL10NFolder() +void SAssetView::ToggleShowLocalizedContent() { GetMutableDefault()->SetDisplayL10NFolder(!GetDefault()->GetDisplayL10NFolder()); GetMutableDefault()->PostEditChange(); } -bool SAssetView::IsToggleShowL10NFolderAllowed() const +bool SAssetView::IsToggleShowLocalizedContentAllowed() const { return true; } -bool SAssetView::IsShowingL10NFolder() const +bool SAssetView::IsShowingLocalizedContent() const { - return GetDefault()->GetDisplayL10NFolder(); + return IsToggleShowLocalizedContentAllowed() && GetDefault()->GetDisplayL10NFolder(); } void SAssetView::ToggleShowCollections() @@ -3018,33 +3137,36 @@ bool SAssetView::IsToggleShowCollectionsAllowed() const bool SAssetView::IsShowingCollections() const { - return GetDefault()->GetDisplayCollections(); + return IsToggleShowCollectionsAllowed() && GetDefault()->GetDisplayCollections(); } -void SAssetView::ToggleShowCppFolders() +void SAssetView::ToggleShowCppContent() { const bool bDisplayCppFolders = GetDefault()->GetDisplayCppFolders(); GetMutableDefault()->SetDisplayCppFolders(!bDisplayCppFolders); GetMutableDefault()->PostEditChange(); } -bool SAssetView::IsShowingCppFolders() const +bool SAssetView::IsToggleShowCppContentAllowed() const { - return GetDefault()->GetDisplayCppFolders(); + return bCanShowClasses; +} + +bool SAssetView::IsShowingCppContent() const +{ + return IsToggleShowCppContentAllowed() && GetDefault()->GetDisplayCppFolders(); } void SAssetView::SetCurrentViewType(EAssetViewType::Type NewType) { if ( ensure(NewType != EAssetViewType::MAX) && NewType != CurrentViewType ) { - TArray SelectedAssets = GetSelectedAssets(); - ResetQuickJump(); CurrentViewType = NewType; CreateCurrentView(); - SyncToAssets(SelectedAssets); + SyncToSelection(); // Clear relevant thumbnails to render fresh ones in the new view if needed RelevantThumbnails.Empty(); @@ -3225,8 +3347,7 @@ TSharedRef SAssetView::MakeListViewWidget(TSharedPtr .ShouldAllowToolTip(this, &SAssetView::ShouldAllowToolTips) .HighlightText(HighlightedText) .IsSelected( FIsSelected::CreateSP(TableRowWidget.Get(), &STableRow>::IsSelectedExclusively) ) - .OnAssetsDragDropped(this, &SAssetView::OnAssetsDragDropped) - .OnPathsDragDropped(this, &SAssetView::OnPathsDragDropped) + .OnAssetsOrPathsDragDropped(this, &SAssetView::OnAssetsOrPathsDragDropped) .OnFilesDragDropped(this, &SAssetView::OnFilesDragDropped); TableRowWidget->SetContent(Item); @@ -3313,8 +3434,7 @@ TSharedRef SAssetView::MakeTileViewWidget(TSharedPtr .ShouldAllowToolTip(this, &SAssetView::ShouldAllowToolTips) .HighlightText( HighlightedText ) .IsSelected( FIsSelected::CreateSP(TableRowWidget.Get(), &STableRow>::IsSelectedExclusively) ) - .OnAssetsDragDropped(this, &SAssetView::OnAssetsDragDropped) - .OnPathsDragDropped(this, &SAssetView::OnPathsDragDropped) + .OnAssetsOrPathsDragDropped(this, &SAssetView::OnAssetsOrPathsDragDropped) .OnFilesDragDropped(this, &SAssetView::OnFilesDragDropped); TableRowWidget->SetContent(Item); @@ -3405,8 +3525,7 @@ TSharedRef SAssetView::MakeColumnViewWidget(TSharedPtr UnloadedObjects; - ContentBrowserUtils::GetUnloadedAssets(ObjectPaths, UnloadedObjects); - TArray LoadedObjects; const bool bAllowedToPrompt = false; bLoadSuccessful = ContentBrowserUtils::LoadAssetsIfNeeded(ObjectPaths, LoadedObjects, bAllowedToPrompt); @@ -3757,56 +3872,45 @@ void SAssetView::OnListMouseButtonDoubleClick(TSharedPtr AssetIt FReply SAssetView::OnDraggingAssetItem( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) { - if ( bAllowDragging ) + if (bAllowDragging) { - TArray AssetDataList = GetSelectedAssets(); + TArray DraggedAssets; + TArray DraggedAssetPaths; - if (AssetDataList.Num()) + // Work out which assets to drag { - // We have some items selected, start a drag-drop - TArray InAssetData; - - for (int32 AssetIdx = 0; AssetIdx < AssetDataList.Num(); ++AssetIdx) + TArray AssetDataList = GetSelectedAssets(); + for (const FAssetData& AssetData : AssetDataList) { - const FAssetData& AssetData = AssetDataList[AssetIdx]; - - if ( !AssetData.IsValid() || AssetData.AssetClass == UObjectRedirector::StaticClass()->GetFName() ) + // Skip invalid assets and redirectors + if (AssetData.IsValid() && AssetData.AssetClass != UObjectRedirector::StaticClass()->GetFName()) { - // Skip invalid assets and redirectors - continue; - } - - // If dragging a class, send though an FAssetData whose name is null and class is this class' name - InAssetData.Add(AssetData); - } - - if( InAssetData.Num() > 0 ) - { - UActorFactory* FactoryToUse = nullptr; - if( FEditorDelegates::OnAssetDragStarted.IsBound() ) - { - FEditorDelegates::OnAssetDragStarted.Broadcast( InAssetData, FactoryToUse ); - return FReply::Handled(); - } - else if( MouseEvent.IsMouseButtonDown( EKeys::LeftMouseButton ) ) - { - return FReply::Handled().BeginDragDrop( FAssetDragDropOp::New( InAssetData ) ); - } - else - { - return FReply::Handled(); + DraggedAssets.Add(AssetData); } } } - else + + // Work out which asset paths to drag { - // are we dragging some folders? TArray SelectedFolders = GetSelectedFolders(); - if(SelectedFolders.Num() > 0 && !SourcesData.HasCollections()) + if (SelectedFolders.Num() > 0 && !SourcesData.HasCollections()) { - return FReply::Handled().BeginDragDrop(FAssetPathDragDropOp::New(SelectedFolders)); + DraggedAssetPaths = MoveTemp(SelectedFolders); } } + + // Use the custom drag handler? + if (DraggedAssets.Num() > 0 && FEditorDelegates::OnAssetDragStarted.IsBound()) + { + FEditorDelegates::OnAssetDragStarted.Broadcast(DraggedAssets, nullptr); + return FReply::Handled(); + } + + // Use the standard drag handler? + if ((DraggedAssets.Num() > 0 || DraggedAssetPaths.Num() > 0) && MouseEvent.IsMouseButtonDown(EKeys::LeftMouseButton)) + { + return FReply::Handled().BeginDragDrop(FAssetDragDropOp::New(MoveTemp(DraggedAssets), MoveTemp(DraggedAssetPaths))); + } } return FReply::Unhandled(); @@ -3921,22 +4025,41 @@ void SAssetView::AssetRenameCommit(const TSharedPtr& Item, const { ItemAsFolder->bNewFolder = false; - const FString NewPath = FPaths::GetPath(ItemAsFolder->FolderPath) / NewName; - FText ErrorText; - if( ContentBrowserUtils::IsValidFolderName(NewName, ErrorText) && - !ContentBrowserUtils::DoesFolderExist(NewPath)) + if (CommitType == ETextCommit::OnCleared) { - FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(TEXT("AssetRegistry")); - bSuccess = AssetRegistryModule.Get().AddPath(NewPath); + // Clearing the rename box on a newly created folder cancels the entire creation process + FilteredAssetItems.Remove(Item); + RefreshList(); } - - // remove this temp item - a new one will have been added by the asset registry callback - FilteredAssetItems.Remove(Item); - RefreshList(); - - if(!bSuccess) + else { - ErrorMessage = LOCTEXT("CreateFolderFailed", "Failed to create folder."); + const FString NewPath = FPaths::GetPath(ItemAsFolder->FolderPath) / NewName; + FText ErrorText; + if( ContentBrowserUtils::IsValidFolderName(NewName, ErrorText) && + !ContentBrowserUtils::DoesFolderExist(NewPath)) + { + // ensure the folder exists on disk + FString NewPathOnDisk; + bSuccess = FPackageName::TryConvertLongPackageNameToFilename(NewPath, NewPathOnDisk) && IFileManager::Get().MakeDirectory(*NewPathOnDisk, true); + + if (bSuccess) + { + TSharedRef EmptyFolderVisibilityManager = FContentBrowserSingleton::Get().GetEmptyFolderVisibilityManager(); + EmptyFolderVisibilityManager->SetAlwaysShowPath(NewPath); + + FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(TEXT("AssetRegistry")); + bSuccess = AssetRegistryModule.Get().AddPath(NewPath); + } + } + + // remove this temp item - a new one will have been added by the asset registry callback + FilteredAssetItems.Remove(Item); + RefreshList(); + + if(!bSuccess) + { + ErrorMessage = LOCTEXT("CreateFolderFailed", "Failed to create folder."); + } } } else if(NewName != ItemAsFolder->FolderName.ToString()) @@ -3949,7 +4072,14 @@ void SAssetView::AssetRenameCommit(const TSharedPtr& Item, const if( ContentBrowserUtils::IsValidFolderName(NewName, ErrorText) && !ContentBrowserUtils::DoesFolderExist(NewPath)) { - bSuccess = AssetRegistryModule.Get().AddPath(NewPath); + // ensure the folder exists on disk + FString NewPathOnDisk; + bSuccess = FPackageName::TryConvertLongPackageNameToFilename(NewPath, NewPathOnDisk) && IFileManager::Get().MakeDirectory(*NewPathOnDisk, true); + + if (bSuccess) + { + bSuccess = AssetRegistryModule.Get().AddPath(NewPath); + } } if(bSuccess) @@ -3981,34 +4111,47 @@ void SAssetView::AssetRenameCommit(const TSharedPtr& Item, const ensure(0); } - if ( bSuccess && ItemType != EAssetItemType::Folder ) + if ( bSuccess ) { - if ( ensure(Asset != NULL) ) + // Sort in the new item + bPendingSortFilteredItems = true; + RequestQuickFrontendListRefresh(); + + if ( ItemType == EAssetItemType::Folder ) { - // Sort in the new item - bPendingSortFilteredItems = true; - RequestQuickFrontendListRefresh(); + const TSharedPtr& ItemAsFolder = StaticCastSharedPtr(Item); + const FString NewPath = FPaths::GetPath(ItemAsFolder->FolderPath) / NewName; - // Refresh the thumbnail - const TSharedPtr* AssetThumbnail = RelevantThumbnails.Find(StaticCastSharedPtr(Item)); - if ( AssetThumbnail ) + // Sync the view to the new folder + TArray FolderList; + FolderList.Add(NewPath); + SyncToFolders(FolderList); + } + else + { + if ( ensure(Asset != NULL) ) { - AssetThumbnailPool->RefreshThumbnail(*AssetThumbnail); - } + // Refresh the thumbnail + const TSharedPtr* AssetThumbnail = RelevantThumbnails.Find(StaticCastSharedPtr(Item)); + if ( AssetThumbnail ) + { + AssetThumbnailPool->RefreshThumbnail(*AssetThumbnail); + } - // Sync to its location - TArray AssetDataList; - new(AssetDataList) FAssetData(Asset); + // Sync to its location + TArray AssetDataList; + new(AssetDataList) FAssetData(Asset); - if ( OnAssetRenameCommitted.IsBound() ) - { - // If our parent wants to potentially handle the sync, let it - OnAssetRenameCommitted.Execute(AssetDataList); - } - else - { - // Otherwise, sync just the view - SyncToAssets(AssetDataList); + if ( OnAssetRenameCommitted.IsBound() ) + { + // If our parent wants to potentially handle the sync, let it + OnAssetRenameCommitted.Execute(AssetDataList); + } + else + { + // Otherwise, sync just the view + SyncToAssets(AssetDataList); + } } } } @@ -4234,27 +4377,16 @@ bool SAssetView::HasSingleCollectionSource() const return ( SourcesData.Collections.Num() == 1 && SourcesData.PackagePaths.Num() == 0 ); } -void SAssetView::OnAssetsDragDropped(const TArray& AssetList, const FString& DestinationPath) +void SAssetView::OnAssetsOrPathsDragDropped(const TArray& AssetList, const TArray& AssetPaths, const FString& DestinationPath) { - DragDropHandler::HandleAssetsDroppedOnAssetFolder( + DragDropHandler::HandleDropOnAssetFolder( SharedThis(this), AssetList, + AssetPaths, DestinationPath, FText::FromString(FPaths::GetCleanFilename(DestinationPath)), - DragDropHandler::FExecuteCopyOrMoveAssets::CreateSP(this, &SAssetView::ExecuteDropCopy), - DragDropHandler::FExecuteCopyOrMoveAssets::CreateSP(this, &SAssetView::ExecuteDropMove) - ); -} - -void SAssetView::OnPathsDragDropped(const TArray& PathNames, const FString& DestinationPath) -{ - DragDropHandler::HandleFoldersDroppedOnAssetFolder( - SharedThis(this), - PathNames, - DestinationPath, - FText::FromString(FPaths::GetCleanFilename(DestinationPath)), - DragDropHandler::FExecuteCopyOrMoveFolders::CreateSP(this, &SAssetView::ExecuteDropCopyFolder), - DragDropHandler::FExecuteCopyOrMoveFolders::CreateSP(this, &SAssetView::ExecuteDropMoveFolder) + DragDropHandler::FExecuteCopyOrMove::CreateSP(this, &SAssetView::ExecuteDropCopy), + DragDropHandler::FExecuteCopyOrMove::CreateSP(this, &SAssetView::ExecuteDropMove) ); } @@ -4264,42 +4396,53 @@ void SAssetView::OnFilesDragDropped(const TArray& AssetList, const FStr AssetToolsModule.Get().ImportAssets( AssetList, DestinationPath ); } -void SAssetView::ExecuteDropCopy(TArray AssetList, FString DestinationPath) +void SAssetView::ExecuteDropCopy(TArray AssetList, TArray AssetPaths, FString DestinationPath) { - TArray DroppedObjects; - ContentBrowserUtils::GetObjectsInAssetData(AssetList, DroppedObjects); + int32 NumItemsCopied = 0; - TArray NewObjects; - ObjectTools::DuplicateObjects(DroppedObjects, TEXT(""), DestinationPath, /*bOpenDialog=*/false, &NewObjects); - - // If any objects were duplicated, report the success - if ( NewObjects.Num() ) + if (AssetList.Num() > 0) { - FFormatNamedArguments Args; - Args.Add( TEXT("Number"), NewObjects.Num() ); - const FText Message = FText::Format( LOCTEXT("AssetsDroppedCopy", "{Number} asset(s) copied"), Args ); + TArray DroppedObjects; + ContentBrowserUtils::GetObjectsInAssetData(AssetList, DroppedObjects); + + TArray NewObjects; + ObjectTools::DuplicateObjects(DroppedObjects, TEXT(""), DestinationPath, /*bOpenDialog=*/false, &NewObjects); + + NumItemsCopied += NewObjects.Num(); + } + + if (AssetPaths.Num() > 0) + { + if (ContentBrowserUtils::CopyFolders(AssetPaths, DestinationPath)) + { + NumItemsCopied += AssetPaths.Num(); + } + } + + // If any items were duplicated, report the success + if (NumItemsCopied > 0) + { + const FText Message = FText::Format(LOCTEXT("AssetItemsDroppedCopy", "{0} {0}|plural(one=item,other=items) copied"), NumItemsCopied); const FVector2D& CursorPos = FSlateApplication::Get().GetCursorPos(); FSlateRect MessageAnchor(CursorPos.X, CursorPos.Y, CursorPos.X, CursorPos.Y); ContentBrowserUtils::DisplayMessage(Message, MessageAnchor, SharedThis(this)); } } -void SAssetView::ExecuteDropMove(TArray AssetList, FString DestinationPath) +void SAssetView::ExecuteDropMove(TArray AssetList, TArray AssetPaths, FString DestinationPath) { - TArray DroppedObjects; - ContentBrowserUtils::GetObjectsInAssetData(AssetList, DroppedObjects); + if (AssetList.Num() > 0) + { + TArray DroppedObjects; + ContentBrowserUtils::GetObjectsInAssetData(AssetList, DroppedObjects); - ContentBrowserUtils::MoveAssets(DroppedObjects, DestinationPath); -} + ContentBrowserUtils::MoveAssets(DroppedObjects, DestinationPath); + } -void SAssetView::ExecuteDropCopyFolder(TArray PathNames, FString DestinationPath) -{ - ContentBrowserUtils::CopyFolders(PathNames, DestinationPath); -} - -void SAssetView::ExecuteDropMoveFolder(TArray PathNames, FString DestinationPath) -{ - ContentBrowserUtils::MoveFolders(PathNames, DestinationPath); + if (AssetPaths.Num() > 0) + { + ContentBrowserUtils::MoveFolders(AssetPaths, DestinationPath); + } } void SAssetView::SetUserSearching(bool bInSearching) @@ -4313,7 +4456,8 @@ void SAssetView::SetUserSearching(bool bInSearching) void SAssetView::HandleSettingChanged(FName PropertyName) { - if ((PropertyName == "DisplayFolders") || + if ((PropertyName == GET_MEMBER_NAME_CHECKED(UContentBrowserSettings, DisplayFolders)) || + (PropertyName == GET_MEMBER_NAME_CHECKED(UContentBrowserSettings, DisplayEmptyFolders)) || (PropertyName == "DisplayDevelopersFolder") || (PropertyName == "DisplayEngineFolder") || (PropertyName == NAME_None)) // @todo: Needed if PostEditChange was called manually, for now @@ -4545,14 +4689,14 @@ TSharedRef SAssetView::CreateRowHeaderMenuContent(const FString ColumnN void SAssetView::ForceShowPluginFolder(bool bEnginePlugin) { - if (bEnginePlugin && !IsShowingEngineFolder()) + if (bEnginePlugin && !IsShowingEngineContent()) { - ToggleShowEngineFolder(); + ToggleShowEngineContent(); } - if (!IsShowingPluginFolders()) + if (!IsShowingPluginContent()) { - ToggleShowPluginFolders(); + ToggleShowPluginContent(); } } diff --git a/Engine/Source/Editor/ContentBrowser/Private/SAssetView.h b/Engine/Source/Editor/ContentBrowser/Private/SAssetView.h index acf4bb2b8033..b1e4bf6655fa 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/SAssetView.h +++ b/Engine/Source/Editor/ContentBrowser/Private/SAssetView.h @@ -20,6 +20,7 @@ #include "Widgets/Views/STableRow.h" #include "Editor/ContentBrowser/Private/AssetViewSortManager.h" #include "AssetViewTypes.h" +#include "HistoryManager.h" class FMenuBuilder; class FWeakWidgetPath; @@ -29,7 +30,6 @@ class SAssetListView; class SAssetTileView; class SComboButton; class UFactory; -struct FHistoryData; struct FPropertyChangedEvent; /** @@ -222,8 +222,14 @@ public: /** Selects the paths containing the specified assets. */ void SyncToAssets( const TArray& AssetDataList, const bool bFocusOnSync = true ); + /** Selects the specified paths. */ + void SyncToFolders( const TArray& FolderList, const bool bFocusOnSync = true ); + + /** Selects the paths containing the specified items. */ + void SyncTo( const FContentBrowserSelection& ItemSelection, const bool bFocusOnSync = true ); + /** Sets the state of the asset view to the one described by the history data */ - void ApplyHistoryData ( const FHistoryData& History ); + void ApplyHistoryData( const FHistoryData& History ); /** Returns all the items currently selected in the view */ TArray> GetSelectedItems() const; @@ -295,6 +301,9 @@ public: /** Called when a folder is removed from the asset registry */ void OnAssetRegistryPathRemoved(const FString& Path); + /** Handles updating the content browser when a path is populated with an asset for the first time */ + void OnFolderPopulated(const FString& Path); + /** * Forces the plugin content folder to be shown. * @@ -304,6 +313,9 @@ public: private: + /** Sets the pending selection to the current selection (used when changing views or refreshing the view). */ + void SyncToSelection( const bool bFocusOnSync = true ); + /** @return the thumbnail scale setting path to use when looking up the setting in an ini. */ FString GetThumbnailScaleSettingPath(const FString& SettingsString) const; @@ -415,14 +427,23 @@ private: /** @return true when we are showing folders */ bool IsShowingFolders() const; - /** Toggle whether folders should be shown or not */ - void ToggleShowL10NFolder(); + /** Toggle whether empty folders should be shown or not */ + void ToggleShowEmptyFolders(); - /** Whether or not it's possible to show folders */ - bool IsToggleShowL10NFolderAllowed() const; + /** Whether or not it's possible to show empty folders */ + bool IsToggleShowEmptyFoldersAllowed() const; + + /** @return true when we are showing empty folders */ + bool IsShowingEmptyFolders() const; + + /** Toggle whether localized content should be shown or not */ + void ToggleShowLocalizedContent(); + + /** Whether or not it's possible to show localized content */ + bool IsToggleShowLocalizedContentAllowed() const; /** @return true when we are showing folders */ - bool IsShowingL10NFolder() const; + bool IsShowingLocalizedContent() const; /** Toggle whether to show real-time thumbnails */ void ToggleRealTimeThumbnails(); @@ -433,26 +454,26 @@ private: /** @return true if we are showing real-time thumbnails */ bool IsShowingRealTimeThumbnails() const; - /** Toggle whether plugin content folders should be shown or not */ - void ToggleShowPluginFolders(); + /** Toggle whether plugin content should be shown or not */ + void ToggleShowPluginContent(); - /** @return true when we are showing plugin content folders */ - bool IsShowingPluginFolders() const; + /** @return true when we are showing plugin content */ + bool IsShowingPluginContent() const; - /** Toggle whether the engine folder should be shown or not */ - void ToggleShowEngineFolder(); + /** Toggle whether engine content should be shown or not */ + void ToggleShowEngineContent(); - /** @return true when we are showing the engine folder */ - bool IsShowingEngineFolder() const; + /** @return true when we are showing engine content */ + bool IsShowingEngineContent() const; - /** Toggle whether the developers folder should be shown or not */ - void ToggleShowDevelopersFolder(); + /** Toggle whether developers content should be shown or not */ + void ToggleShowDevelopersContent(); - /** Whether or not it's possible to toggle the developers folder */ - bool IsToggleShowDevelopersFolderAllowed() const; + /** Whether or not it's possible to toggle developers content */ + bool IsToggleShowDevelopersContentAllowed() const; - /** @return true when we are showing the developers folder */ - bool IsShowingDevelopersFolder() const; + /** @return true when we are showing the developers content */ + bool IsShowingDevelopersContent() const; /** Toggle whether collections should be shown or not */ void ToggleShowCollections(); @@ -463,11 +484,14 @@ private: /** @return true when we are showing collections */ bool IsShowingCollections() const; - /** Toggle whether C++ content folders should be shown or not */ - void ToggleShowCppFolders(); + /** Toggle whether C++ content should be shown or not */ + void ToggleShowCppContent(); - /** @return true when we are showing c++ content folders */ - bool IsShowingCppFolders() const; + /** Whether or not it's possible to show C++ content */ + bool IsToggleShowCppContentAllowed() const; + + /** @return true when we are showing C++ content */ + bool IsShowingCppContent() const; /** Sets the view type and updates lists accordingly */ void SetCurrentViewType(EAssetViewType::Type NewType); @@ -626,26 +650,17 @@ private: /** Whether we have a single source collection selected */ bool HasSingleCollectionSource() const; - /** Delegate for when assets are dragged onto a folder */ - void OnAssetsDragDropped(const TArray& AssetList, const FString& DestinationPath); - - /** Delegate for when folder(s) are dragged onto a folder */ - void OnPathsDragDropped(const TArray& PathNames, const FString& DestinationPath); + /** Delegate for when assets or asset paths are dragged onto a folder */ + void OnAssetsOrPathsDragDropped(const TArray& AssetList, const TArray& AssetPaths, const FString& DestinationPath); /** Delegate for when external assets are dragged onto a folder */ void OnFilesDragDropped(const TArray& AssetList, const FString& DestinationPath); - /** Delegate to respond to drop of assets onto a folder */ - void ExecuteDropCopy(TArray AssetList, FString DestinationPath); + /** Delegate to respond to drop of assets or asset paths onto a folder */ + void ExecuteDropCopy(TArray AssetList, TArray AssetPaths, FString DestinationPath); - /** Delegate to respond to drop of assets onto a folder */ - void ExecuteDropMove(TArray AssetList, FString DestinationPath); - - /** Delegate to respond to drop of folder(s) onto a folder */ - void ExecuteDropCopyFolder(TArray PathNames, FString DestinationPath); - - /** Delegate to respond to drop of folder(s) onto a folder */ - void ExecuteDropMoveFolder(TArray PathNames, FString DestinationPath); + /** Delegate to respond to drop of assets or asset paths onto a folder */ + void ExecuteDropMove(TArray AssetList, TArray AssetPaths, FString DestinationPath); /** Creates a new asset from deferred data */ void DeferredCreateNewAsset(); @@ -743,8 +758,8 @@ private: /** If true, the frontend items will be refreshed next frame. Much faster. */ bool bQuickFrontendListRefreshRequested; - /** The list of assets to sync next frame */ - TSet PendingSyncAssets; + /** The list of items to sync next frame */ + FSelectionData PendingSyncItems; /** Should we take focus when the PendingSyncAssets are processed? */ bool bPendingFocusOnSync; diff --git a/Engine/Source/Editor/ContentBrowser/Private/SCollectionView.cpp b/Engine/Source/Editor/ContentBrowser/Private/SCollectionView.cpp index 70c1aa3798e8..d3d50629c2d5 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/SCollectionView.cpp +++ b/Engine/Source/Editor/ContentBrowser/Private/SCollectionView.cpp @@ -1259,7 +1259,7 @@ bool SCollectionView::ValidateDragDropOnCollectionItem(TSharedRef DragDropOp = StaticCastSharedPtr(Operation); OutIsKnownDragOperation = true; - bIsValidDrag = DragDropOp->AssetData.Num() > 0; + bIsValidDrag = DragDropOp->HasAssets(); } // Set the default slashed circle if this drag is invalid and a drag operation hasn't set NewDragCursor to something custom @@ -1304,10 +1304,11 @@ FReply SCollectionView::HandleDragDropOnCollectionItem(TSharedRefIsOfType()) { TSharedPtr DragDropOp = StaticCastSharedPtr(Operation); - + const TArray& DroppedAssets = DragDropOp->GetAssets(); + TArray ObjectPaths; - ObjectPaths.Reserve(DragDropOp->AssetData.Num()); - for (const FAssetData& AssetData : DragDropOp->AssetData) + ObjectPaths.Reserve(DroppedAssets.Num()); + for (const FAssetData& AssetData : DroppedAssets) { ObjectPaths.Add(AssetData.ObjectPath); } @@ -1316,10 +1317,10 @@ FReply SCollectionView::HandleDragDropOnCollectionItem(TSharedRefCollectionName, CollectionItem->CollectionType, ObjectPaths, &NumAdded)) { - if (DragDropOp->AssetData.Num() == 1) + if (DroppedAssets.Num() == 1) { FFormatNamedArguments Args; - Args.Add(TEXT("AssetName"), FText::FromName(DragDropOp->AssetData[0].AssetName)); + Args.Add(TEXT("AssetName"), FText::FromName(DroppedAssets[0].AssetName)); Args.Add(TEXT("CollectionName"), FText::FromName(CollectionItem->CollectionName)); Message = FText::Format(LOCTEXT("CollectionAssetAdded", "Added {AssetName} to {CollectionName}"), Args); } diff --git a/Engine/Source/Editor/ContentBrowser/Private/SContentBrowser.cpp b/Engine/Source/Editor/ContentBrowser/Private/SContentBrowser.cpp index 4cf869c80c8c..0601fca9c3f2 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/SContentBrowser.cpp +++ b/Engine/Source/Editor/ContentBrowser/Private/SContentBrowser.cpp @@ -54,6 +54,8 @@ #include "NativeClassHierarchy.h" #include "AddToProjectConfig.h" #include "GameProjectGenerationModule.h" +#include "GlobalEditorCommonCommands.h" +#include "ReferenceViewer.h" #define LOCTEXT_NAMESPACE "ContentBrowser" @@ -110,8 +112,6 @@ void SContentBrowser::Construct( const FArguments& InArgs, const FName& InInstan static const FName DefaultForegroundName("DefaultForeground"); - FContentBrowserCommands::Register(); - BindCommands(); ChildSlot @@ -756,7 +756,7 @@ void SContentBrowser::BindCommands() )); Commands->MapAction(FContentBrowserCommands::Get().PreviewAssets, FUIAction( - FExecuteAction::CreateSP(this, &SContentBrowser::HandlePreviewAssetsCommandEecute) + FExecuteAction::CreateSP(this, &SContentBrowser::HandlePreviewAssetsCommandExecute) )); Commands->MapAction(FContentBrowserCommands::Get().CreateNewFolder, FUIAction( @@ -779,6 +779,11 @@ void SContentBrowser::BindCommands() Commands->MapAction(FContentBrowserCommands::Get().ResaveAllCurrentFolder, FUIAction( FExecuteAction::CreateSP(this, &SContentBrowser::HandleResaveAllCurrentFolderCommand) )); + + Commands->MapAction(FGlobalEditorCommonCommands::Get().ViewReferences, FUIAction( + FExecuteAction::CreateSP(this, &SContentBrowser::HandleViewReferencesCommand), + FCanExecuteAction::CreateSP(this, &SContentBrowser::HandleViewReferencesCanExecute) + )); } EVisibility SContentBrowser::GetCollectionViewVisibility() const @@ -837,38 +842,41 @@ void SContentBrowser::ImportAsset( const FString& InPath ) if ( ensure( !InPath.IsEmpty() ) ) { FAssetToolsModule& AssetToolsModule = FModuleManager::Get().LoadModuleChecked( "AssetTools" ); - AssetToolsModule.Get().ImportAssets( InPath ); + AssetToolsModule.Get().ImportAssetsWithDialog( InPath ); } } -void SContentBrowser::SyncToAssets( const TArray& AssetDataList, const bool bAllowImplicitSync, const bool bDisableFiltersThatHideAssets ) +void SContentBrowser::PrepareToSync( const TArray& AssetDataList, const TArray& FolderPaths, const bool bDisableFiltersThatHideAssets ) { // Check to see if any of the assets require certain folders to be visible - const UContentBrowserSettings* tmp = GetDefault(); bool bDisplayDev = GetDefault()->GetDisplayDevelopersFolder(); bool bDisplayEngine = GetDefault()->GetDisplayEngineFolder(); bool bDisplayPlugins = GetDefault()->GetDisplayPluginFolders(); bool bDisplayLocalized = GetDefault()->GetDisplayL10NFolder(); if ( !bDisplayDev || !bDisplayEngine || !bDisplayPlugins || !bDisplayLocalized ) { - bool bRepopulate = false; - for (int32 AssetIdx = AssetDataList.Num() - 1; AssetIdx >= 0 && ( !bDisplayDev || !bDisplayEngine || !bDisplayPlugins || !bDisplayLocalized ); --AssetIdx) + TSet PackagePaths = TSet(FolderPaths); + for (const FAssetData& AssetData : AssetDataList) { - const FAssetData& Item = AssetDataList[AssetIdx]; - FString PackagePath; - if ( Item.AssetClass == NAME_Class ) + if (AssetData.AssetClass == NAME_Class) { // Classes are found in the /Classes_ roots TSharedRef NativeClassHierarchy = FContentBrowserSingleton::Get().GetNativeClassHierarchy(); - NativeClassHierarchy->GetClassPath(Cast(Item.GetAsset()), PackagePath, false/*bIncludeClassName*/); + NativeClassHierarchy->GetClassPath(Cast(AssetData.GetAsset()), PackagePath, false/*bIncludeClassName*/); } else { // All other assets are found by their package path - PackagePath = Item.PackagePath.ToString(); + PackagePath = AssetData.PackagePath.ToString(); } + PackagePaths.Add(PackagePath); + } + + bool bRepopulate = false; + for (const FString& PackagePath : PackagePaths) + { const ContentBrowserUtils::ECBFolderCategory FolderCategory = ContentBrowserUtils::GetFolderCategory( PackagePath ); if ( !bDisplayDev && FolderCategory == ContentBrowserUtils::ECBFolderCategory::DeveloperContent ) { @@ -895,6 +903,11 @@ void SContentBrowser::SyncToAssets( const TArray& AssetDataList, con GetMutableDefault()->SetDisplayL10NFolder(true); bRepopulate = true; } + + if (bDisplayDev && bDisplayEngine && bDisplayPlugins && bDisplayLocalized) + { + break; + } } // If we have auto-enabled any flags, force a refresh @@ -915,13 +928,36 @@ void SContentBrowser::SyncToAssets( const TArray& AssetDataList, con SetSearchBoxText(FText::GetEmpty()); SearchBoxPtr->SetText(FText::GetEmpty()); SearchBoxPtr->SetError(FText::GetEmpty()); +} + +void SContentBrowser::SyncToAssets( const TArray& AssetDataList, const bool bAllowImplicitSync, const bool bDisableFiltersThatHideAssets ) +{ + PrepareToSync(AssetDataList, TArray(), bDisableFiltersThatHideAssets); // Tell the sources view first so the asset view will be up to date by the time we request the sync PathViewPtr->SyncToAssets(AssetDataList, bAllowImplicitSync); AssetViewPtr->SyncToAssets(AssetDataList); } -void SContentBrowser::SetIsPrimaryContentBrowser (bool NewIsPrimary) +void SContentBrowser::SyncToFolders( const TArray& FolderList, const bool bAllowImplicitSync ) +{ + PrepareToSync(TArray(), FolderList, false); + + // Tell the sources view first so the asset view will be up to date by the time we request the sync + PathViewPtr->SyncToFolders(FolderList, bAllowImplicitSync); + AssetViewPtr->SyncToFolders(FolderList); +} + +void SContentBrowser::SyncTo( const FContentBrowserSelection& ItemSelection, const bool bAllowImplicitSync, const bool bDisableFiltersThatHideAssets ) +{ + PrepareToSync(ItemSelection.SelectedAssets, ItemSelection.SelectedFolders, bDisableFiltersThatHideAssets); + + // Tell the sources view first so the asset view will be up to date by the time we request the sync + PathViewPtr->SyncTo(ItemSelection, bAllowImplicitSync); + AssetViewPtr->SyncTo(ItemSelection); +} + +void SContentBrowser::SetIsPrimaryContentBrowser(bool NewIsPrimary) { bIsPrimaryBrowser = NewIsPrimary; @@ -1353,11 +1389,12 @@ void SContentBrowser::OnUpdateHistoryData(FHistoryData& HistoryData) const HistoryData.HistoryDesc = NewSource; HistoryData.SourcesData = SourcesData; - HistoryData.SelectedAssets.Empty(); - for ( auto AssetIt = SelectedAssets.CreateConstIterator(); AssetIt; ++AssetIt ) + HistoryData.SelectionData.Reset(); + HistoryData.SelectionData.SelectedFolders = TSet(AssetViewPtr->GetSelectedFolders()); + for (const FAssetData& SelectedAsset : SelectedAssets) { - HistoryData.SelectedAssets.Add(AssetIt->ObjectPath); + HistoryData.SelectionData.SelectedAssets.Add(SelectedAsset.ObjectPath); } } @@ -1700,16 +1737,28 @@ FString SContentBrowser::GetCurrentPath() const TSharedRef SContentBrowser::MakeAddNewContextMenu(bool bShowGetContent, bool bShowImport) { + const FSourcesData& SourcesData = AssetViewPtr->GetSourcesData(); + + int32 NumAssetPaths, NumClassPaths; + ContentBrowserUtils::CountPathTypes(SourcesData.PackagePaths, NumAssetPaths, NumClassPaths); + // Get all menu extenders for this context menu from the content browser module FContentBrowserModule& ContentBrowserModule = FModuleManager::GetModuleChecked( TEXT("ContentBrowser") ); - TArray MenuExtenderDelegates = ContentBrowserModule.GetAllAssetContextMenuExtenders(); + TArray MenuExtenderDelegates = ContentBrowserModule.GetAllAssetContextMenuExtenders(); + + // Delegate wants paths as FStrings + TArray SelectPaths; + for (FName PathName: SourcesData.PackagePaths) + { + SelectPaths.Add(PathName.ToString()); + } TArray> Extenders; for (int32 i = 0; i < MenuExtenderDelegates.Num(); ++i) { if (MenuExtenderDelegates[i].IsBound()) { - Extenders.Add(MenuExtenderDelegates[i].Execute()); + Extenders.Add(MenuExtenderDelegates[i].Execute(SelectPaths)); } } TSharedPtr MenuExtender = FExtender::Combine(Extenders); @@ -1723,10 +1772,6 @@ TSharedRef SContentBrowser::MakeAddNewContextMenu(bool bShowGetContent, OnNewFolderRequested = FNewAssetOrClassContextMenu::FOnNewFolderRequested::CreateSP(this, &SContentBrowser::NewFolderRequested); } - const FSourcesData& SourcesData = AssetViewPtr->GetSourcesData(); - - int32 NumAssetPaths, NumClassPaths; - ContentBrowserUtils::CountPathTypes(SourcesData.PackagePaths, NumAssetPaths, NumClassPaths); // New feature packs don't depend on the current paths, so we always add this item if it was requested FNewAssetOrClassContextMenu::FOnGetContentRequested OnGetContentRequested; @@ -2096,7 +2141,7 @@ void SContentBrowser::HandleOpenAssetsOrFoldersCommandExecute() AssetViewPtr->OnOpenAssetsOrFolders(); } -void SContentBrowser::HandlePreviewAssetsCommandEecute() +void SContentBrowser::HandlePreviewAssetsCommandExecute() { AssetViewPtr->OnPreviewAssets(); } @@ -2129,6 +2174,81 @@ void SContentBrowser::HandleDirectoryUpCommandExecute() } } +void SContentBrowser::HandleViewReferencesCommand() +{ + TArray ViewableAssets; + + TArray SelectedAssets; + TArray SelectedPaths; + + // Get the list of selected assets and paths from the view that actually has focus + + if (AssetViewPtr->HasAnyUserFocusOrFocusedDescendants()) + { + SelectedAssets = AssetViewPtr->GetSelectedAssets(); + SelectedPaths = AssetViewPtr->GetSelectedFolders(); + } + else if (PathViewPtr->HasAnyUserFocusOrFocusedDescendants()) + { + SelectedPaths = PathViewPtr->GetSelectedPaths(); + } + + // For any selected assets, just get the package name from the asset data + for (const FAssetData& Asset : SelectedAssets) + { + ViewableAssets.Add(Asset.PackageName); + } + + // For any selected paths, get all assets that exist within that path + if (SelectedPaths.Num() > 0) + { + FARFilter Filter; + Filter.bRecursivePaths = true; + + for (const FString& Path : SelectedPaths) + { + new (Filter.PackagePaths) FName(*Path); + } + + FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(TEXT("AssetRegistry")); + + TArray AssetsInPaths; + AssetRegistryModule.Get().GetAssets(Filter, AssetsInPaths); + + for (const FAssetData& Asset : AssetsInPaths) + { + ViewableAssets.Add(Asset.PackageName); + } + } + + if (ViewableAssets.Num() > 0) + { + IReferenceViewerModule::Get().InvokeReferenceViewerTab(ViewableAssets); + } +} + +bool SContentBrowser::HandleViewReferencesCanExecute() +{ + bool bCanViewReferences = IReferenceViewerModule::IsAvailable(); + + if (bCanViewReferences) + { + // The reference viewer should be called if either the asset view or the path view have focus and have + // at least one item selected + + if (AssetViewPtr.IsValid() && AssetViewPtr->HasAnyUserFocusOrFocusedDescendants()) + { + bCanViewReferences = AssetViewPtr->GetSelectedItems().Num() > 0; + } + else if (PathViewPtr.IsValid() && PathViewPtr->HasAnyUserFocusOrFocusedDescendants()) + { + bCanViewReferences = PathViewPtr->GetSelectedPaths().Num() > 0; + } + } + + return bCanViewReferences; +} + bool SContentBrowser::IsBackEnabled() const { return HistoryManager.CanGoBack(); diff --git a/Engine/Source/Editor/ContentBrowser/Private/SContentBrowser.h b/Engine/Source/Editor/ContentBrowser/Private/SContentBrowser.h index 3f615427e65e..d907806aa45b 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/SContentBrowser.h +++ b/Engine/Source/Editor/ContentBrowser/Private/SContentBrowser.h @@ -56,7 +56,8 @@ public: /** Sets up an inline-name for the creation of a new asset using the specified path and the specified class and/or factory */ void CreateNewAsset(const FString& DefaultAssetName, const FString& PackagePath, UClass* AssetClass, UFactory* Factory); - /** Changes sources to show the specified assets and selects them in the asset view + /** + * Changes sources to show the specified assets and selects them in the asset view * * @param AssetDataList - A list of assets to sync the view to * @@ -65,8 +66,28 @@ public: */ void SyncToAssets( const TArray& AssetDataList, const bool bAllowImplicitSync = false, const bool bDisableFiltersThatHideAssets = true ); + /** + * Changes sources to show the specified folders and selects them in the asset view + * + * @param FolderList - A list of folders to sync the view to + * + * @param bAllowImplicitSync - true to allow the view to sync to parent folders if they are already selected, + * false to force the view to select the explicit Parent folders of each asset + */ + void SyncToFolders( const TArray& FolderList, const bool bAllowImplicitSync = false ); + + /** + * Changes sources to show the specified items and selects them in the asset view + * + * @param AssetDataList - A list of assets to sync the view to + * + * @param bAllowImplicitSync - true to allow the view to sync to parent folders if they are already selected, + * false to force the view to select the explicit Parent folders of each asset + */ + void SyncTo( const FContentBrowserSelection& ItemSelection, const bool bAllowImplicitSync = false, const bool bDisableFiltersThatHideAssets = true ); + /** Sets this content browser as the primary browser. The primary browser is the target for asset syncs and contributes to the global selection set. */ - void SetIsPrimaryContentBrowser (bool NewIsPrimary); + void SetIsPrimaryContentBrowser(bool NewIsPrimary); /** Gets the tab manager for the tab containing this browser */ TSharedPtr GetTabManager() const; @@ -106,6 +127,9 @@ public: private: + /** Called prior to syncing the selection in this Content Browser */ + void PrepareToSync( const TArray& AssetDataList, const TArray& FolderPaths, const bool bDisableFiltersThatHideAssets ); + /** Called to retrieve the text that should be highlighted on assets */ FText GetHighlightedText() const; @@ -152,10 +176,10 @@ private: void PathPickerCollectionSelected(const FCollectionNameType& SelectedCollection); /** Sets the state of the browser to the one described by the supplied history data */ - void OnApplyHistoryData (const FHistoryData& History); + void OnApplyHistoryData(const FHistoryData& History); /** Updates the supplied history data with current information */ - void OnUpdateHistoryData (FHistoryData& History) const; + void OnUpdateHistoryData(FHistoryData& History) const; /** Handler for when the path view requests an asset creation */ void NewAssetRequested(const FString& SelectedPath, TWeakObjectPtr FactoryClass); @@ -286,7 +310,7 @@ private: void HandleOpenAssetsOrFoldersCommandExecute(); /** Handler for previewing assets */ - void HandlePreviewAssetsCommandEecute(); + void HandlePreviewAssetsCommandExecute(); /** Handler for creating new folder */ void HandleCreateNewFolderCommandExecute(); @@ -294,6 +318,12 @@ private: /** Handler for clicking the directory up button */ void HandleDirectoryUpCommandExecute(); + /** Handler for the view references command */ + void HandleViewReferencesCommand(); + + /** Returns true if the view references command can be handled */ + bool HandleViewReferencesCanExecute(); + /** True if the user may use the history back button */ bool IsBackEnabled() const; diff --git a/Engine/Source/Editor/ContentBrowser/Private/SFilterList.cpp b/Engine/Source/Editor/ContentBrowser/Private/SFilterList.cpp index deec8747511c..f954d0f3c467 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/SFilterList.cpp +++ b/Engine/Source/Editor/ContentBrowser/Private/SFilterList.cpp @@ -415,7 +415,7 @@ void SFilterList::Construct( const FArguments& InArgs ) { if (UContentBrowserFrontEndFilterExtension* PotentialExtension = *ExtensionIt) { - if (PotentialExtension->HasAnyFlags(RF_ClassDefaultObject) && !PotentialExtension->GetClass()->HasAnyCastFlag(CLASS_Deprecated | CLASS_Abstract)) + if (PotentialExtension->HasAnyFlags(RF_ClassDefaultObject) && !PotentialExtension->GetClass()->HasAnyClassFlags(CLASS_Deprecated | CLASS_Abstract)) { // Grab the filters TArray< TSharedRef > ExtendedFrontendFilters; diff --git a/Engine/Source/Editor/ContentBrowser/Private/SPathView.cpp b/Engine/Source/Editor/ContentBrowser/Private/SPathView.cpp index 951f5607dcba..af8731cf462b 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/SPathView.cpp +++ b/Engine/Source/Editor/ContentBrowser/Private/SPathView.cpp @@ -1,6 +1,7 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "SPathView.h" +#include "HAL/FileManager.h" #include "Misc/ConfigCacheIni.h" #include "Layout/WidgetPath.h" #include "Framework/Application/SlateApplication.h" @@ -14,13 +15,14 @@ #include "ContentBrowserUtils.h" #include "HistoryManager.h" -#include "DragAndDrop/AssetPathDragDropOp.h" +#include "DragAndDrop/AssetDragDropOp.h" #include "DragDropHandler.h" #include "PathViewTypes.h" #include "SourcesViewWidgets.h" #include "Widgets/Input/SSearchBox.h" #include "NativeClassHierarchy.h" +#include "EmptyFolderVisibilityManager.h" #define LOCTEXT_NAMESPACE "ContentBrowser" @@ -37,6 +39,12 @@ SPathView::~SPathView() NativeClassHierarchy->OnClassHierarchyUpdated().RemoveAll( this ); } + // Unsubscribe from folder population events + { + TSharedRef EmptyFolderVisibilityManager = FContentBrowserSingleton::Get().GetEmptyFolderVisibilityManager(); + EmptyFolderVisibilityManager->OnFolderPopulated().RemoveAll(this); + } + // Load the asset registry module to stop listening for updates FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(TEXT("AssetRegistry")); AssetRegistryModule.Get().OnPathAdded().RemoveAll( this ); @@ -78,6 +86,12 @@ void SPathView::Construct( const FArguments& InArgs ) NativeClassHierarchy->OnClassHierarchyUpdated().AddSP( this, &SPathView::OnClassHierarchyUpdated ); } + // Listen to find out when previously empty paths are populated with content + { + TSharedRef EmptyFolderVisibilityManager = FContentBrowserSingleton::Get().GetEmptyFolderVisibilityManager(); + EmptyFolderVisibilityManager->OnFolderPopulated().AddSP(this, &SPathView::OnFolderPopulated); + } + ChildSlot [ SNew(SVerticalBox) @@ -321,8 +335,12 @@ TSharedPtr SPathView::AddPath(const FString& Path, bool bUserNamed) // Found or added the root item? if ( CurrentItem.IsValid() ) { + TSharedRef EmptyFolderVisibilityManager = FContentBrowserSingleton::Get().GetEmptyFolderVisibilityManager(); + // Now add children as necessary + const bool bDisplayEmpty = GetDefault()->DisplayEmptyFolders; const bool bDisplayDev = GetDefault()->GetDisplayDevelopersFolder(); + const bool bDisplayL10N = GetDefault()->GetDisplayL10NFolder(); for ( int32 PathItemIdx = 1; PathItemIdx < PathItemList.Num(); ++PathItemIdx ) { const FString& PathItemName = PathItemList[PathItemIdx]; @@ -334,10 +352,25 @@ TSharedPtr SPathView::AddPath(const FString& Path, bool bUserNamed) const FString FolderName = PathItemName; const FString FolderPath = CurrentItem->FolderPath + "/" + PathItemName; - // If this is a developer folder, and we don't want to show them break out here - if ( !bDisplayDev && ContentBrowserUtils::IsDevelopersFolder(FolderPath) ) + if (!bUserNamed) { - break; + // If this folder shouldn't be shown, break out here + if ( !bDisplayEmpty && !EmptyFolderVisibilityManager->ShouldShowPath(FolderPath) ) + { + break; + } + + // If this is a developer folder, and we don't want to show them break out here + if ( !bDisplayDev && ContentBrowserUtils::IsDevelopersFolder(FolderPath) ) + { + break; + } + + // If this is a localized folder, and we don't want to show them break out here + if ( !bDisplayL10N && ContentBrowserUtils::IsLocalizationFolder(FolderPath) ) + { + break; + } } ChildItem = MakeShareable( new FTreeItem(FText::FromString(FolderName), FolderName, FolderPath, CurrentItem, bUserNamed) ); @@ -445,33 +478,51 @@ void SPathView::RenameFolder(const FString& FolderToRename) } void SPathView::SyncToAssets( const TArray& AssetDataList, const bool bAllowImplicitSync ) +{ + SyncToInternal(AssetDataList, TArray(), bAllowImplicitSync); +} + +void SPathView::SyncToFolders( const TArray& FolderList, const bool bAllowImplicitSync ) +{ + SyncToInternal(TArray(), FolderList, bAllowImplicitSync); +} + +void SPathView::SyncTo( const FContentBrowserSelection& ItemSelection, const bool bAllowImplicitSync ) +{ + SyncToInternal(ItemSelection.SelectedAssets, ItemSelection.SelectedFolders, bAllowImplicitSync); +} + +void SPathView::SyncToInternal( const TArray& AssetDataList, const TArray& FolderPaths, const bool bAllowImplicitSync ) { TArray> SyncTreeItems; // Clear the filter SearchBoxPtr->SetText(FText::GetEmpty()); - for (auto AssetDataIt = AssetDataList.CreateConstIterator(); AssetDataIt; ++AssetDataIt) + TSet PackagePaths = TSet(FolderPaths); + for (const FAssetData& AssetData : AssetDataList) { - FString Path; - if ( AssetDataIt->AssetClass == NAME_Class ) + FString PackagePath; + if (AssetData.AssetClass == NAME_Class) { - if ( bAllowClassesFolder ) - { - // Classes are found in the /Classes_ roots - TSharedRef NativeClassHierarchy = FContentBrowserSingleton::Get().GetNativeClassHierarchy(); - NativeClassHierarchy->GetClassPath(Cast(AssetDataIt->GetAsset()), Path, false/*bIncludeClassName*/); - } + // Classes are found in the /Classes_ roots + TSharedRef NativeClassHierarchy = FContentBrowserSingleton::Get().GetNativeClassHierarchy(); + NativeClassHierarchy->GetClassPath(Cast(AssetData.GetAsset()), PackagePath, false/*bIncludeClassName*/); } else { // All other assets are found by their package path - Path = AssetDataIt->PackagePath.ToString(); + PackagePath = AssetData.PackagePath.ToString(); } - if ( !Path.IsEmpty() ) + PackagePaths.Add(PackagePath); + } + + for (const FString& PackagePath : PackagePaths) + { + if ( !PackagePath.IsEmpty() ) { - TSharedPtr Item = FindItemRecursive(Path); + TSharedPtr Item = FindItemRecursive(PackagePath); if ( Item.IsValid() ) { SyncTreeItems.Add(Item); @@ -804,8 +855,7 @@ TSharedRef SPathView::GenerateTreeRow( TSharedPtr TreeItem .TreeItem(TreeItem) .OnNameChanged(this, &SPathView::FolderNameChanged) .OnVerifyNameChanged(this, &SPathView::VerifyFolderNameChanged) - .OnAssetsDragDropped(this, &SPathView::TreeAssetsDropped) - .OnPathsDragDropped(this, &SPathView::TreeFoldersDropped) + .OnAssetsOrPathsDragDropped(this, &SPathView::TreeAssetsOrPathsDropped) .OnFilesDragDropped(this, &SPathView::TreeFilesDropped) .IsItemExpanded(this, &SPathView::IsTreeItemExpanded, TreeItem) .HighlightText(this, &SPathView::GetHighlightText) @@ -1122,7 +1172,7 @@ FReply SPathView::OnFolderDragDetected(const FGeometry& Geometry, const FPointer PathNames.Add((*ItemIt)->FolderPath); } - return FReply::Handled().BeginDragDrop(FAssetPathDragDropOp::New(PathNames)); + return FReply::Handled().BeginDragDrop(FAssetDragDropOp::New(PathNames)); } } @@ -1134,12 +1184,19 @@ bool SPathView::VerifyFolderNameChanged(const FString& InName, FText& OutErrorMe return ContentBrowserUtils::IsValidFolderPathForCreate(FPaths::GetPath(InFolderPath), InName, OutErrorMessage); } -void SPathView::FolderNameChanged( const TSharedPtr< FTreeItem >& TreeItem, const FString& OldPath, const FVector2D& MessageLocation ) +void SPathView::FolderNameChanged( const TSharedPtr< FTreeItem >& TreeItem, const FString& OldPath, const FVector2D& MessageLocation, const ETextCommit::Type CommitType ) { // Verify the name of the folder FText Reason; if ( ContentBrowserUtils::IsValidFolderName(TreeItem->FolderName, Reason) ) { + if (CommitType == ETextCommit::OnCleared) + { + // Clearing the rename box on a newly created folder cancels the entire creation process + RemoveFolderItem(TreeItem); + return; + } + TSharedPtr< FTreeItem > ExistingItem; if ( FolderAlreadyExists(TreeItem, ExistingItem) ) { @@ -1184,24 +1241,32 @@ void SPathView::FolderNameChanged( const TSharedPtr< FTreeItem >& TreeItem, cons else */ { - FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked("AssetRegistry"); - if (AssetRegistryModule.Get().AddPath(TreeItem->FolderPath) && TreeItem->FolderPath != OldPath) + // ensure the folder exists on disk + FString NewPathOnDisk; + if (FPackageName::TryConvertLongPackageNameToFilename(TreeItem->FolderPath, NewPathOnDisk) && IFileManager::Get().MakeDirectory(*NewPathOnDisk, true)) { - // move any assets in our folder - TArray AssetsInFolder; - AssetRegistryModule.Get().GetAssetsByPath(*OldPath, AssetsInFolder, true); - TArray ObjectsInFolder; - ContentBrowserUtils::GetObjectsInAssetData(AssetsInFolder, ObjectsInFolder); - ContentBrowserUtils::MoveAssets(ObjectsInFolder, TreeItem->FolderPath, OldPath); + TSharedRef EmptyFolderVisibilityManager = FContentBrowserSingleton::Get().GetEmptyFolderVisibilityManager(); + EmptyFolderVisibilityManager->SetAlwaysShowPath(TreeItem->FolderPath); - // Now check to see if the original folder is empty, if so we can delete it - TArray AssetsInOriginalFolder; - AssetRegistryModule.Get().GetAssetsByPath(*OldPath, AssetsInOriginalFolder, true); - if (AssetsInOriginalFolder.Num() == 0) + FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked("AssetRegistry"); + if (AssetRegistryModule.Get().AddPath(TreeItem->FolderPath) && TreeItem->FolderPath != OldPath) { - TArray FoldersToDelete; - FoldersToDelete.Add(OldPath); - ContentBrowserUtils::DeleteFolders(FoldersToDelete); + // move any assets in our folder + TArray AssetsInFolder; + AssetRegistryModule.Get().GetAssetsByPath(*OldPath, AssetsInFolder, true); + TArray ObjectsInFolder; + ContentBrowserUtils::GetObjectsInAssetData(AssetsInFolder, ObjectsInFolder); + ContentBrowserUtils::MoveAssets(ObjectsInFolder, TreeItem->FolderPath, OldPath); + + // Now check to see if the original folder is empty, if so we can delete it + TArray AssetsInOriginalFolder; + AssetRegistryModule.Get().GetAssetsByPath(*OldPath, AssetsInOriginalFolder, true); + if (AssetsInOriginalFolder.Num() == 0) + { + TArray FoldersToDelete; + FoldersToDelete.Add(OldPath); + ContentBrowserUtils::DeleteFolders(FoldersToDelete); + } } } } @@ -1279,27 +1344,16 @@ void SPathView::RemoveFolderItem(const TSharedPtr< FTreeItem >& TreeItem) } } -void SPathView::TreeAssetsDropped(const TArray& AssetList, const TSharedPtr& TreeItem) +void SPathView::TreeAssetsOrPathsDropped(const TArray& AssetList, const TArray& AssetPaths, const TSharedPtr& TreeItem) { - DragDropHandler::HandleAssetsDroppedOnAssetFolder( + DragDropHandler::HandleDropOnAssetFolder( SharedThis(this), AssetList, + AssetPaths, TreeItem->FolderPath, TreeItem->DisplayName, - DragDropHandler::FExecuteCopyOrMoveAssets::CreateSP(this, &SPathView::ExecuteTreeDropCopy), - DragDropHandler::FExecuteCopyOrMoveAssets::CreateSP(this, &SPathView::ExecuteTreeDropMove) - ); -} - -void SPathView::TreeFoldersDropped(const TArray& PathNames, const TSharedPtr& TreeItem) -{ - DragDropHandler::HandleFoldersDroppedOnAssetFolder( - SharedThis(this), - PathNames, - TreeItem->FolderPath, - TreeItem->DisplayName, - DragDropHandler::FExecuteCopyOrMoveFolders::CreateSP(this, &SPathView::ExecuteTreeDropCopyFolder), - DragDropHandler::FExecuteCopyOrMoveFolders::CreateSP(this, &SPathView::ExecuteTreeDropMoveFolder) + DragDropHandler::FExecuteCopyOrMove::CreateSP(this, &SPathView::ExecuteTreeDropCopy), + DragDropHandler::FExecuteCopyOrMove::CreateSP(this, &SPathView::ExecuteTreeDropMove) ); } @@ -1319,75 +1373,71 @@ bool SPathView::IsTreeItemSelected(TSharedPtr TreeItem) const return TreeViewPtr->IsItemSelected(TreeItem); } -void SPathView::ExecuteTreeDropCopy(TArray AssetList, FString DestinationPath) +void SPathView::ExecuteTreeDropCopy(TArray AssetList, TArray AssetPaths, FString DestinationPath) { - TArray DroppedObjects; - ContentBrowserUtils::GetObjectsInAssetData(AssetList, DroppedObjects); - - ContentBrowserUtils::CopyAssets(DroppedObjects, DestinationPath); -} - -void SPathView::ExecuteTreeDropMove(TArray AssetList, FString DestinationPath) -{ - TArray DroppedObjects; - ContentBrowserUtils::GetObjectsInAssetData(AssetList, DroppedObjects); - - ContentBrowserUtils::MoveAssets(DroppedObjects, DestinationPath); -} - -void SPathView::ExecuteTreeDropCopyFolder(TArray PathNames, FString DestinationPath) -{ - if (!ContentBrowserUtils::CopyFolders(PathNames, DestinationPath)) + if (AssetList.Num() > 0) { - return; + TArray DroppedObjects; + ContentBrowserUtils::GetObjectsInAssetData(AssetList, DroppedObjects); + + ContentBrowserUtils::CopyAssets(DroppedObjects, DestinationPath); } - TSharedPtr RootItem = FindItemRecursive(DestinationPath); - if (RootItem.IsValid()) + if (AssetPaths.Num() > 0 && ContentBrowserUtils::CopyFolders(AssetPaths, DestinationPath)) { - TreeViewPtr->SetItemExpansion(RootItem, true); - - // Select all the new folders - TreeViewPtr->ClearSelection(); - for ( auto PathIt = PathNames.CreateConstIterator(); PathIt; ++PathIt ) + TSharedPtr RootItem = FindItemRecursive(DestinationPath); + if (RootItem.IsValid()) { - const FString SubFolderName = FPackageName::GetLongPackageAssetName(*PathIt); - const FString NewPath = DestinationPath + TEXT("/") + SubFolderName; - - TSharedPtr Item = FindItemRecursive(NewPath); - if ( Item.IsValid() ) + TreeViewPtr->SetItemExpansion(RootItem, true); + + // Select all the new folders + TreeViewPtr->ClearSelection(); + for (const FString& AssetPath : AssetPaths) { - TreeViewPtr->SetItemSelection(Item, true); - TreeViewPtr->RequestScrollIntoView(Item); + const FString SubFolderName = FPackageName::GetLongPackageAssetName(AssetPath); + const FString NewPath = DestinationPath + TEXT("/") + SubFolderName; + + TSharedPtr Item = FindItemRecursive(NewPath); + if (Item.IsValid()) + { + TreeViewPtr->SetItemSelection(Item, true); + TreeViewPtr->RequestScrollIntoView(Item); + } } } } } -void SPathView::ExecuteTreeDropMoveFolder(TArray PathNames, FString DestinationPath) +void SPathView::ExecuteTreeDropMove(TArray AssetList, TArray AssetPaths, FString DestinationPath) { - if (!ContentBrowserUtils::MoveFolders(PathNames, DestinationPath)) + if (AssetList.Num() > 0) { - return; + TArray DroppedObjects; + ContentBrowserUtils::GetObjectsInAssetData(AssetList, DroppedObjects); + + ContentBrowserUtils::MoveAssets(DroppedObjects, DestinationPath); } - TSharedPtr RootItem = FindItemRecursive(DestinationPath); - if (RootItem.IsValid()) + if (AssetPaths.Num() > 0 && ContentBrowserUtils::MoveFolders(AssetPaths, DestinationPath)) { - TreeViewPtr->SetItemExpansion(RootItem, true); - - // Select all the new folders - TreeViewPtr->ClearSelection(); - for ( auto PathIt = PathNames.CreateConstIterator(); PathIt; ++PathIt ) + TSharedPtr RootItem = FindItemRecursive(DestinationPath); + if (RootItem.IsValid()) { - const FString SubFolderName = FPackageName::GetLongPackageAssetName(*PathIt); - const FString NewPath = DestinationPath + TEXT("/") + SubFolderName; + TreeViewPtr->SetItemExpansion(RootItem, true); - TSharedPtr Item = FindItemRecursive(NewPath); - if ( Item.IsValid() ) + // Select all the new folders + TreeViewPtr->ClearSelection(); + for (const FString& AssetPath : AssetPaths) { - TreeViewPtr->SetItemSelection(Item, true); - TreeViewPtr->RequestScrollIntoView(Item); + const FString SubFolderName = FPackageName::GetLongPackageAssetName(AssetPath); + const FString NewPath = DestinationPath + TEXT("/") + SubFolderName; + + TSharedPtr Item = FindItemRecursive(NewPath); + if (Item.IsValid()) + { + TreeViewPtr->SetItemSelection(Item, true); + TreeViewPtr->RequestScrollIntoView(Item); + } } } } @@ -1419,6 +1469,11 @@ void SPathView::OnAssetRegistrySearchCompleted() PendingInitialPaths.Empty(); } +void SPathView::OnFolderPopulated(const FString& Path) +{ + OnAssetRegistryPathAdded(Path); +} + void SPathView::OnContentPathMountedOrDismounted( const FString& AssetPath, const FString& FilesystemPath ) { // A new content path has appeared, so we should refresh out root set of paths @@ -1433,23 +1488,28 @@ void SPathView::OnClassHierarchyUpdated() void SPathView::HandleSettingChanged(FName PropertyName) { - if ((PropertyName == "DisplayDevelopersFolder") || + if ((PropertyName == GET_MEMBER_NAME_CHECKED(UContentBrowserSettings, DisplayEmptyFolders)) || + (PropertyName == "DisplayDevelopersFolder") || (PropertyName == "DisplayEngineFolder") || (PropertyName == "DisplayPluginFolders") || (PropertyName == "DisplayL10NFolder") || (PropertyName == NAME_None)) // @todo: Needed if PostEditChange was called manually, for now { + TSharedRef EmptyFolderVisibilityManager = FContentBrowserSingleton::Get().GetEmptyFolderVisibilityManager(); + // If the dev or engine folder is no longer visible but we're inside it... + const bool bDisplayEmpty = GetDefault()->DisplayEmptyFolders; const bool bDisplayDev = GetDefault()->GetDisplayDevelopersFolder(); const bool bDisplayEngine = GetDefault()->GetDisplayEngineFolder(); const bool bDisplayPlugins = GetDefault()->GetDisplayPluginFolders(); const bool bDisplayL10N = GetDefault()->GetDisplayL10NFolder(); - if (!bDisplayDev || !bDisplayEngine || !bDisplayPlugins || !bDisplayL10N) + if (!bDisplayEmpty || !bDisplayDev || !bDisplayEngine || !bDisplayPlugins || !bDisplayL10N) { const FString OldSelectedPath = GetSelectedPath(); const ContentBrowserUtils::ECBFolderCategory OldFolderCategory = ContentBrowserUtils::GetFolderCategory(OldSelectedPath); - if ((!bDisplayDev && OldFolderCategory == ContentBrowserUtils::ECBFolderCategory::DeveloperContent) || + if ((!bDisplayEmpty && !EmptyFolderVisibilityManager->ShouldShowPath(OldSelectedPath)) || + (!bDisplayDev && OldFolderCategory == ContentBrowserUtils::ECBFolderCategory::DeveloperContent) || (!bDisplayEngine && (OldFolderCategory == ContentBrowserUtils::ECBFolderCategory::EngineContent || OldFolderCategory == ContentBrowserUtils::ECBFolderCategory::EngineClasses)) || (!bDisplayPlugins && (OldFolderCategory == ContentBrowserUtils::ECBFolderCategory::PluginContent || OldFolderCategory == ContentBrowserUtils::ECBFolderCategory::PluginClasses)) || (!bDisplayL10N && ContentBrowserUtils::IsLocalizationFolder(OldSelectedPath))) @@ -1476,7 +1536,8 @@ void SPathView::HandleSettingChanged(FName PropertyName) const FString NewSelectedPath = GetSelectedPath(); const ContentBrowserUtils::ECBFolderCategory NewFolderCategory = ContentBrowserUtils::GetFolderCategory(NewSelectedPath); - if ((bDisplayDev && NewFolderCategory == ContentBrowserUtils::ECBFolderCategory::DeveloperContent) || + if ((bDisplayEmpty && EmptyFolderVisibilityManager->ShouldShowPath(NewSelectedPath)) || + (bDisplayDev && NewFolderCategory == ContentBrowserUtils::ECBFolderCategory::DeveloperContent) || (bDisplayEngine && (NewFolderCategory == ContentBrowserUtils::ECBFolderCategory::EngineContent || NewFolderCategory == ContentBrowserUtils::ECBFolderCategory::EngineClasses)) || (bDisplayPlugins && (NewFolderCategory == ContentBrowserUtils::ECBFolderCategory::PluginContent || NewFolderCategory == ContentBrowserUtils::ECBFolderCategory::PluginClasses)) || (bDisplayL10N && ContentBrowserUtils::IsLocalizationFolder(NewSelectedPath))) diff --git a/Engine/Source/Editor/ContentBrowser/Private/SPathView.h b/Engine/Source/Editor/ContentBrowser/Private/SPathView.h index 8f00f05691e7..68bcd8cff04a 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/SPathView.h +++ b/Engine/Source/Editor/ContentBrowser/Private/SPathView.h @@ -12,6 +12,7 @@ #include "Widgets/Views/STableRow.h" #include "Widgets/Views/STreeView.h" #include "Misc/TextFilter.h" +#include "IContentBrowserSingleton.h" #include "ContentBrowserDelegates.h" struct FHistoryData; @@ -100,7 +101,8 @@ public: /** Sets up an inline rename for the specified folder */ void RenameFolder(const FString& FolderToRename); - /** Selects the paths containing the specified assets. + /** + * Selects the paths containing the specified assets. * * @param AssetDataList - A list of assets to sync the view to * @@ -109,11 +111,31 @@ public: */ void SyncToAssets( const TArray& AssetDataList, const bool bAllowImplicitSync = false ); + /** + * Selects the given paths. + * + * @param FolderList - A list of folders to sync the view to + * + * @param bAllowImplicitSync - true to allow the view to sync to parent folders if they are already selected, + * false to force the view to select the explicit Parent folders of each asset + */ + void SyncToFolders( const TArray& FolderList, const bool bAllowImplicitSync = false ); + + /** + * Selects the given items. + * + * @param ItemSelection - A list of assets and folders to sync the view to + * + * @param bAllowImplicitSync - true to allow the view to sync to parent folders if they are already selected, + * false to force the view to select the explicit Parent folders of each asset + */ + void SyncTo( const FContentBrowserSelection& ItemSelection, const bool bAllowImplicitSync = false ); + /** Finds the item that represents the specified path, if it exists. */ TSharedPtr FindItemRecursive(const FString& Path) const; /** Sets the state of the path view to the one described by the history data */ - void ApplyHistoryData ( const FHistoryData& History ); + void ApplyHistoryData( const FHistoryData& History ); /** Saves any settings to config that should be persistent between editor sessions */ void SaveSettings(const FString& IniFilename, const FString& IniSection, const FString& SettingsString) const; @@ -125,6 +147,9 @@ public: void Populate(); private: + /** Internal sync implementation, syncs to the tree to the given array of items */ + void SyncToInternal( const TArray& AssetDataList, const TArray& FolderPaths, const bool bAllowImplicitSync ); + /** Sort the root items into the correct order */ void SortRootItems(); @@ -183,7 +208,7 @@ private: bool VerifyFolderNameChanged(const FString& InName, FText& OutErrorMessage, const FString& InFolderPath) const; /** Handler for when a name was given to a new folder */ - void FolderNameChanged( const TSharedPtr< FTreeItem >& TreeItem, const FString& OldPath, const FVector2D& MessageLocation ); + void FolderNameChanged( const TSharedPtr< FTreeItem >& TreeItem, const FString& OldPath, const FVector2D& MessageLocation, const ETextCommit::Type CommitType ); /** Returns true if the supplied folder item already exists in the tree. If so, ExistingItem will be set to the found item. */ bool FolderAlreadyExists(const TSharedPtr< FTreeItem >& TreeItem, TSharedPtr< FTreeItem >& ExistingItem); @@ -191,11 +216,8 @@ private: /** Removes the supplied folder from the tree. */ void RemoveFolderItem(const TSharedPtr< FTreeItem >& TreeItem); - /** Handler for when assets are dropped on a tree item */ - void TreeAssetsDropped(const TArray& AssetList, const TSharedPtr& TreeItem); - - /** Handler for when asset paths are dropped on a tree item */ - void TreeFoldersDropped(const TArray& PathNames, const TSharedPtr& TreeItem); + /** Handler for when assets or asset paths are dropped on a tree item */ + void TreeAssetsOrPathsDropped(const TArray& AssetList, const TArray& AssetPaths, const TSharedPtr& TreeItem); /** Handler for when asset paths are dropped on a tree item */ void TreeFilesDropped(const TArray& FileNames, const TSharedPtr& TreeItem); @@ -209,17 +231,11 @@ private: /** Gets all the UObjects represented by assets in the AssetList */ void GetDroppedObjects(const TArray& AssetList, TArray& OutDroppedObjects); - /** Handler for the user selecting to copy assets to the specified folder */ - void ExecuteTreeDropCopy(TArray AssetList, FString DestinationPath); + /** Handler for the user selecting to copy assets or asset paths to the specified folder */ + void ExecuteTreeDropCopy(TArray AssetList, TArray AssetPaths, FString DestinationPath); - /** Handler for the user selecting to move assets to the specified folder */ - void ExecuteTreeDropMove(TArray AssetList, FString DestinationPath); - - /** Handler for the user selecting to copy folders to the specified folder */ - void ExecuteTreeDropCopyFolder(TArray PathNames, FString DestinationPath); - - /** Handler for the user selecting to move folders to the specified folder */ - void ExecuteTreeDropMoveFolder(TArray PathNames, FString DestinationPath); + /** Handler for the user selecting to move assets or asset paths to the specified folder */ + void ExecuteTreeDropMove(TArray AssetList, TArray AssetPaths, FString DestinationPath); /** Handles updating the content browser when an asset path is added to the asset registry */ void OnAssetRegistryPathAdded(const FString& Path); @@ -230,6 +246,9 @@ private: /** Notification for when the Asset Registry has completed it's initial search */ void OnAssetRegistrySearchCompleted(); + /** Handles updating the content browser when a path is populated with an asset for the first time */ + void OnFolderPopulated(const FString& Path); + /** Called from an engine core event when a new content path has been added or removed, so that we can refresh our root set of paths */ void OnContentPathMountedOrDismounted( const FString& AssetPath, const FString& FileSystemPath ); diff --git a/Engine/Source/Editor/ContentBrowser/Private/SourcesViewWidgets.cpp b/Engine/Source/Editor/ContentBrowser/Private/SourcesViewWidgets.cpp index 41393563aea9..9671769e99b1 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/SourcesViewWidgets.cpp +++ b/Engine/Source/Editor/ContentBrowser/Private/SourcesViewWidgets.cpp @@ -8,7 +8,6 @@ #include "DragAndDrop/DecoratedDragDropOp.h" #include "DragAndDrop/AssetDragDropOp.h" -#include "DragAndDrop/AssetPathDragDropOp.h" #include "DragAndDrop/CollectionDragDropOp.h" #include "DragDropHandler.h" #include "ContentBrowserUtils.h" @@ -26,8 +25,7 @@ void SAssetTreeItem::Construct( const FArguments& InArgs ) TreeItem = InArgs._TreeItem; OnNameChanged = InArgs._OnNameChanged; OnVerifyNameChanged = InArgs._OnVerifyNameChanged; - OnAssetsDragDropped = InArgs._OnAssetsDragDropped; - OnPathsDragDropped = InArgs._OnPathsDragDropped; + OnAssetsOrPathsDragDropped = InArgs._OnAssetsOrPathsDragDropped; OnFilesDragDropped = InArgs._OnFilesDragDropped; IsItemExpanded = InArgs._IsItemExpanded; bDraggedOver = false; @@ -151,16 +149,11 @@ FReply SAssetTreeItem::OnDrop( const FGeometry& MyGeometry, const FDragDropEvent if (Operation->IsOfType()) { TSharedPtr DragDropOp = StaticCastSharedPtr( DragDropEvent.GetOperation() ); - OnAssetsDragDropped.ExecuteIfBound(DragDropOp->AssetData, TreeItem.Pin()); + OnAssetsOrPathsDragDropped.ExecuteIfBound(DragDropOp->GetAssets(), DragDropOp->GetAssetPaths(), TreeItem.Pin()); return FReply::Handled(); } - else if (Operation->IsOfType()) - { - TSharedPtr DragDropOp = StaticCastSharedPtr( DragDropEvent.GetOperation() ); - OnPathsDragDropped.ExecuteIfBound(DragDropOp->PathNames, TreeItem.Pin()); - return FReply::Handled(); - } - else if (Operation->IsOfType()) + + if (Operation->IsOfType()) { TSharedPtr DragDropOp = StaticCastSharedPtr( DragDropEvent.GetOperation() ); OnFilesDragDropped.ExecuteIfBound(DragDropOp->GetFiles(), TreeItem.Pin()); @@ -197,7 +190,7 @@ bool SAssetTreeItem::VerifyNameChanged(const FText& InName, FText& OutError) con return true; } -void SAssetTreeItem::HandleNameCommitted( const FText& NewText, ETextCommit::Type /*CommitInfo*/ ) +void SAssetTreeItem::HandleNameCommitted( const FText& NewText, ETextCommit::Type CommitInfo ) { if ( TreeItem.IsValid() ) { @@ -218,7 +211,7 @@ void SAssetTreeItem::HandleNameCommitted( const FText& NewText, ETextCommit::Typ MessageLoc.X = LastGeometry.AbsolutePosition.X; MessageLoc.Y = LastGeometry.AbsolutePosition.Y + LastGeometry.Size.Y * LastGeometry.Scale; - OnNameChanged.ExecuteIfBound(TreeItemPtr, OldPath, MessageLoc); + OnNameChanged.ExecuteIfBound(TreeItemPtr, OldPath, MessageLoc, CommitInfo); } } } diff --git a/Engine/Source/Editor/ContentBrowser/Private/SourcesViewWidgets.h b/Engine/Source/Editor/ContentBrowser/Private/SourcesViewWidgets.h index d80596e9bbe0..8dabde836c61 100644 --- a/Engine/Source/Editor/ContentBrowser/Private/SourcesViewWidgets.h +++ b/Engine/Source/Editor/ContentBrowser/Private/SourcesViewWidgets.h @@ -22,10 +22,9 @@ struct FTreeItem; class SAssetTreeItem : public SCompoundWidget { public: - DECLARE_DELEGATE_ThreeParams( FOnNameChanged, const TSharedPtr& /*TreeItem*/, const FString& /*OldPath*/, const FVector2D& /*MessageLocation*/); + DECLARE_DELEGATE_FourParams( FOnNameChanged, const TSharedPtr& /*TreeItem*/, const FString& /*OldPath*/, const FVector2D& /*MessageLocation*/, const ETextCommit::Type /*CommitType*/); DECLARE_DELEGATE_RetVal_ThreeParams( bool, FOnVerifyNameChanged, const FString& /*InName*/, FText& /*OutErrorMessage*/, const FString& /*FolderPath*/); - DECLARE_DELEGATE_TwoParams( FOnAssetsDragDropped, const TArray& /*AssetList*/, const TSharedPtr& /*TreeItem*/); - DECLARE_DELEGATE_TwoParams( FOnPathsDragDropped, const TArray& /*PathNames*/, const TSharedPtr& /*TreeItem*/); + DECLARE_DELEGATE_ThreeParams( FOnAssetsOrPathsDragDropped, const TArray& /*AssetList*/, const TArray& /*AssetPaths*/, const TSharedPtr& /*TreeItem*/); DECLARE_DELEGATE_TwoParams( FOnFilesDragDropped, const TArray& /*FileNames*/, const TSharedPtr& /*TreeItem*/); SLATE_BEGIN_ARGS( SAssetTreeItem ) @@ -42,11 +41,8 @@ public: /** Delegate for when the user is typing a new name for the folder */ SLATE_EVENT( FOnVerifyNameChanged, OnVerifyNameChanged ) - /** Delegate for when assets are dropped on this folder */ - SLATE_EVENT( FOnAssetsDragDropped, OnAssetsDragDropped ) - - /** Delegate for when asset paths are dropped on this folder */ - SLATE_EVENT( FOnPathsDragDropped, OnPathsDragDropped ) + /** Delegate for when assets or asset paths are dropped on this folder */ + SLATE_EVENT( FOnAssetsOrPathsDragDropped, OnAssetsOrPathsDragDropped ) /** Delegate for when a list of files is dropped on this folder from an external source */ SLATE_EVENT( FOnFilesDragDropped, OnFilesDragDropped ) @@ -123,11 +119,8 @@ private: /** The name of the asset as an editable text box */ TSharedPtr EditableName; - /** Delegate for when a list of assets is dropped on this folder */ - FOnAssetsDragDropped OnAssetsDragDropped; - - /** Delegate for when a list of folder paths is dropped on this folder */ - FOnPathsDragDropped OnPathsDragDropped; + /** Delegate for when a list of assets or asset paths are dropped on this folder */ + FOnAssetsOrPathsDragDropped OnAssetsOrPathsDragDropped; /** Delegate for when a list of files is dropped on this folder from an external source */ FOnFilesDragDropped OnFilesDragDropped; diff --git a/Engine/Source/Editor/ContentBrowser/Public/ContentBrowserModule.h b/Engine/Source/Editor/ContentBrowser/Public/ContentBrowserModule.h index fbd539583582..1f9e568c5a60 100644 --- a/Engine/Source/Editor/ContentBrowser/Public/ContentBrowserModule.h +++ b/Engine/Source/Editor/ContentBrowser/Public/ContentBrowserModule.h @@ -44,7 +44,7 @@ public: virtual IContentBrowserSingleton& Get() const; /** Delegates to be called to extend the content browser menus */ - virtual TArray& GetAllAssetContextMenuExtenders() {return AssetContextMenuExtenders;} + virtual TArray& GetAllAssetContextMenuExtenders() {return AssetContextMenuExtenders;} virtual TArray& GetAllPathViewContextMenuExtenders() {return PathViewContextMenuExtenders;} virtual TArray& GetAllCollectionListContextMenuExtenders() {return CollectionListContextMenuExtenders;} virtual TArray& GetAllCollectionViewContextMenuExtenders() {return CollectionViewContextMenuExtenders;} @@ -66,7 +66,7 @@ private: TSharedPtr ContentBrowserSpawner; /** All extender delegates for the content browser menus */ - TArray AssetContextMenuExtenders; + TArray AssetContextMenuExtenders; TArray PathViewContextMenuExtenders; TArray CollectionListContextMenuExtenders; TArray CollectionViewContextMenuExtenders; diff --git a/Engine/Source/Editor/ContentBrowser/Public/IContentBrowserSingleton.h b/Engine/Source/Editor/ContentBrowser/Public/IContentBrowserSingleton.h index 30f27fbaae81..accc46155c36 100644 --- a/Engine/Source/Editor/ContentBrowser/Public/IContentBrowserSingleton.h +++ b/Engine/Source/Editor/ContentBrowser/Public/IContentBrowserSingleton.h @@ -37,6 +37,31 @@ namespace EAssetViewType } +/** A selection of items in the Content Browser */ +struct FContentBrowserSelection +{ + TArray SelectedAssets; + TArray SelectedFolders; + + int32 Num() const + { + return SelectedAssets.Num() + SelectedFolders.Num(); + } + + void Reset() + { + SelectedAssets.Reset(); + SelectedFolders.Reset(); + } + + void Empty() + { + SelectedAssets.Empty(); + SelectedFolders.Empty(); + } +}; + + /** A struct containing details about how the content browser should behave */ struct FContentBrowserConfig { @@ -257,7 +282,7 @@ struct FAssetPickerConfig , bCanShowClasses(true) , bCanShowFolders(false) , bCanShowRealTimeThumbnails(false) - , bCanShowDevelopersFolder(false) + , bCanShowDevelopersFolder(true) , bPreloadAssetsForContextMenu(true) , bAddFilterUI(false) , bShowPathInColumnView(false) @@ -346,6 +371,9 @@ struct FSharedAssetDialogConfig FSharedAssetDialogConfig() : WindowSizeOverride(EForceInit::ForceInitToZero) {} + + virtual ~FSharedAssetDialogConfig() + {} }; /** A struct containing details about how the open asset dialog should behave. */ @@ -479,6 +507,12 @@ public: virtual void SyncBrowserToAssets(const TArray& AssetDataList, bool bAllowLockedBrowsers = false, bool bFocusContentBrowser = true) = 0; virtual void SyncBrowserToAssets(const TArray& AssetList, bool bAllowLockedBrowsers = false, bool bFocusContentBrowser = true) = 0; + /** Selects the supplied folders in all content browsers. If bAllowLockedBrowsers is true, even locked browsers may handle the sync. Only set to true if the sync doesn't seem external to the content browser. */ + virtual void SyncBrowserToFolders(const TArray& FolderList, bool bAllowLockedBrowsers = false, bool bFocusContentBrowser = true) = 0; + + /** Selects the supplied items in all content browsers. If bAllowLockedBrowsers is true, even locked browsers may handle the sync. Only set to true if the sync doesn't seem external to the content browser. */ + virtual void SyncBrowserTo(const FContentBrowserSelection& ItemSelection, bool bAllowLockedBrowsers = false, bool bFocusContentBrowser = true) = 0; + /** Generates a list of assets that are selected in the primary content browser */ virtual void GetSelectedAssets(TArray& SelectedAssets) = 0; diff --git a/Engine/Source/Editor/DataTableEditor/Private/DataTableEditor.cpp b/Engine/Source/Editor/DataTableEditor/Private/DataTableEditor.cpp index a4f816b895dc..11c77992d0c0 100644 --- a/Engine/Source/Editor/DataTableEditor/Private/DataTableEditor.cpp +++ b/Engine/Source/Editor/DataTableEditor/Private/DataTableEditor.cpp @@ -69,9 +69,11 @@ void FDataTableEditor::RegisterTabSpawners(const TSharedRef& { WorkspaceMenuCategory = InTabManager->AddLocalWorkspaceMenuCategory(LOCTEXT("WorkspaceMenu_Data Table Editor", "Data Table Editor")); - InTabManager->RegisterTabSpawner( DataTableTabId, FOnSpawnTab::CreateSP(this, &FDataTableEditor::SpawnTab_DataTable) ) - .SetDisplayName( LOCTEXT("DataTableTab", "Data Table") ) - .SetGroup( WorkspaceMenuCategory.ToSharedRef() ); + FAssetEditorToolkit::RegisterTabSpawners(InTabManager); + + InTabManager->RegisterTabSpawner(DataTableTabId, FOnSpawnTab::CreateSP(this, &FDataTableEditor::SpawnTab_DataTable)) + .SetDisplayName(LOCTEXT("DataTableTab", "Data Table")) + .SetGroup(WorkspaceMenuCategory.ToSharedRef()); InTabManager->RegisterTabSpawner(RowEditorTabId, FOnSpawnTab::CreateSP(this, &FDataTableEditor::SpawnTab_RowEditor)) .SetDisplayName(LOCTEXT("RowEditorTab", "Row Editor")) @@ -80,7 +82,9 @@ void FDataTableEditor::RegisterTabSpawners(const TSharedRef& void FDataTableEditor::UnregisterTabSpawners(const TSharedRef& InTabManager) { - InTabManager->UnregisterTabSpawner( DataTableTabId ); + FAssetEditorToolkit::UnregisterTabSpawners(InTabManager); + + InTabManager->UnregisterTabSpawner(DataTableTabId); InTabManager->UnregisterTabSpawner(RowEditorTabId); } @@ -132,6 +136,21 @@ void FDataTableEditor::PostChange(const class UUserDefinedStruct* Struct, FStruc } } +void FDataTableEditor::SelectionChange(const UDataTable* Changed, FName RowName) +{ + const UDataTable* Table = GetDataTable(); + if (Changed == Table) + { + const bool bSelectionChanged = HighlightedRowName != RowName; + SetHighlightedRow(RowName); + + if (bSelectionChanged) + { + CallbackOnRowHighlighted.ExecuteIfBound(HighlightedRowName); + } + } +} + void FDataTableEditor::PreChange(const UDataTable* Changed, FDataTableEditorUtils::EDataTableChangeInfo Info) { } @@ -160,14 +179,21 @@ void FDataTableEditor::HandlePostChange() void FDataTableEditor::InitDataTableEditor( const EToolkitMode::Type Mode, const TSharedPtr< class IToolkitHost >& InitToolkitHost, UDataTable* Table ) { - TSharedRef StandaloneDefaultLayout = FTabManager::NewLayout( "Standalone_DataTableEditor_Layout" ) + TSharedRef StandaloneDefaultLayout = FTabManager::NewLayout( "Standalone_DataTableEditor_Layout_v2" ) ->AddArea ( FTabManager::NewPrimaryArea()->SetOrientation(Orient_Vertical) ->Split ( FTabManager::NewStack() - ->AddTab( DataTableTabId, ETabState::OpenedTab ) + ->SetSizeCoefficient(0.1f) + ->SetHideTabWell(true) + ->AddTab(GetToolbarTabId(), ETabState::OpenedTab) + ) + ->Split + ( + FTabManager::NewStack() + ->AddTab(DataTableTabId, ETabState::OpenedTab) ) ->Split ( @@ -177,7 +203,7 @@ void FDataTableEditor::InitDataTableEditor( const EToolkitMode::Type Mode, const ); const bool bCreateDefaultStandaloneMenu = true; - const bool bCreateDefaultToolbar = false; + const bool bCreateDefaultToolbar = true; FAssetEditorToolkit::InitAssetEditor( Mode, InitToolkitHost, FDataTableEditorModule::DataTableEditorAppIdentifier, StandaloneDefaultLayout, bCreateDefaultStandaloneMenu, bCreateDefaultToolbar, Table ); FDataTableEditorModule& DataTableEditorModule = FModuleManager::LoadModuleChecked( "DataTableEditor" ); diff --git a/Engine/Source/Editor/DataTableEditor/Private/DataTableEditor.h b/Engine/Source/Editor/DataTableEditor/Private/DataTableEditor.h index 5671b0b4d1d4..b3cda29db568 100644 --- a/Engine/Source/Editor/DataTableEditor/Private/DataTableEditor.h +++ b/Engine/Source/Editor/DataTableEditor/Private/DataTableEditor.h @@ -65,6 +65,7 @@ public: // INotifyOnDataTableChanged virtual void PreChange(const UDataTable* Changed, FDataTableEditorUtils::EDataTableChangeInfo Info) override; virtual void PostChange(const UDataTable* Changed, FDataTableEditorUtils::EDataTableChangeInfo Info) override; + virtual void SelectionChange(const UDataTable* Changed, FName RowName) override; /** Get the data table being edited */ const UDataTable* GetDataTable() const; diff --git a/Engine/Source/Editor/DestructibleMeshEditor/Private/SDestructibleMeshEditorViewport.cpp b/Engine/Source/Editor/DestructibleMeshEditor/Private/SDestructibleMeshEditorViewport.cpp index a88a5de1a34c..41954f6298e8 100644 --- a/Engine/Source/Editor/DestructibleMeshEditor/Private/SDestructibleMeshEditorViewport.cpp +++ b/Engine/Source/Editor/DestructibleMeshEditor/Private/SDestructibleMeshEditorViewport.cpp @@ -454,7 +454,9 @@ void FDestructibleMeshEditorViewportClient::ImportFBXChunks() { UStaticMesh* TempStaticMesh = NULL; TempStaticMesh = (UStaticMesh*)FFbxImporter->ImportStaticMesh(GetTransientPackage(), FbxMeshArray[i], NAME_None, RF_NoFlags, ImportData, 0); - + TArray TempFbxMeshArray; + TempFbxMeshArray.Add(FbxMeshArray[i]); + FFbxImporter->PostImportStaticMesh(TempStaticMesh, TempFbxMeshArray); ChunkMeshes.Add(TempStaticMesh); } diff --git a/Engine/Source/Editor/DetailCustomizations/Private/AssetViewerSettingsCustomization.cpp b/Engine/Source/Editor/DetailCustomizations/Private/AssetViewerSettingsCustomization.cpp index fef0208de426..092c3cd99fc5 100644 --- a/Engine/Source/Editor/DetailCustomizations/Private/AssetViewerSettingsCustomization.cpp +++ b/Engine/Source/Editor/DetailCustomizations/Private/AssetViewerSettingsCustomization.cpp @@ -43,9 +43,9 @@ void FAssetViewerSettingsCustomization::CustomizeDetails(IDetailLayoutBuilder& D IDetailCategoryBuilder& CategoryBuilder = DetailBuilder.EditCategory("Settings", LOCTEXT("AssetViewerSettingsCategory", "Settings"), ECategoryPriority::Important); const UEditorPerProjectUserSettings* PerProjectUserSettings = GetDefault(); - ProfileIndex = ViewerSettings->Profiles.IsValidIndex(PerProjectUserSettings->AssetViewerProfileIndex) ? PerProjectUserSettings->AssetViewerProfileIndex : 0; - ensureMsgf(ViewerSettings && ViewerSettings->Profiles.IsValidIndex(PerProjectUserSettings->AssetViewerProfileIndex), TEXT("Invalid default settings pointer or current profile index")); + check(ViewerSettings != nullptr); + ProfileIndex = ViewerSettings->Profiles.IsValidIndex(PerProjectUserSettings->AssetViewerProfileIndex) ? PerProjectUserSettings->AssetViewerProfileIndex : 0; // Add current active profile property child nodes (rest of profiles remain hidden) TSharedPtr ProfilePropertyHandle = ProfileHandle->GetChildHandle(ProfileIndex); diff --git a/Engine/Source/Editor/DetailCustomizations/Private/AttenuationSettingsCustomizations.cpp b/Engine/Source/Editor/DetailCustomizations/Private/AttenuationSettingsCustomizations.cpp index 54c81a28c943..5f61659b4f9b 100644 --- a/Engine/Source/Editor/DetailCustomizations/Private/AttenuationSettingsCustomizations.cpp +++ b/Engine/Source/Editor/DetailCustomizations/Private/AttenuationSettingsCustomizations.cpp @@ -9,7 +9,7 @@ #include "DetailWidgetRow.h" #include "IDetailPropertyRow.h" #include "AudioDevice.h" -#include "Settings/EditorExperimentalSettings.h" +#include "Classes/Sound/AudioSettings.h" TSharedRef FSoundAttenuationSettingsCustomization::MakeInstance() { @@ -227,7 +227,7 @@ void FSoundAttenuationSettingsCustomization::CustomizeChildren( TSharedRef()->bShowAudioMixerData) + if (GetDefault()->IsAudioMixerEnabled()) { if (IsAudioPluginEnabled(EAudioPlugin::REVERB)) { @@ -241,7 +241,6 @@ void FSoundAttenuationSettingsCustomization::CustomizeChildren( TSharedRef()->bShowAudioMixerData && IsAudioPluginEnabled(EAudioPlugin::OCCLUSION)) + if (GetDefault()->IsAudioMixerEnabled() && IsAudioPluginEnabled(EAudioPlugin::OCCLUSION)) { ChildBuilder.AddChildProperty(PropertyHandles.FindChecked(GET_MEMBER_NAME_CHECKED(FSoundAttenuationSettings, OcclusionPluginSettings)).ToSharedRef()) .EditCondition(GetIsOcclusionEnabledAttribute(), nullptr); diff --git a/Engine/Source/Editor/DetailCustomizations/Private/CollisionProfileDetails.cpp b/Engine/Source/Editor/DetailCustomizations/Private/CollisionProfileDetails.cpp index ff83c933e5ce..127c12bac875 100644 --- a/Engine/Source/Editor/DetailCustomizations/Private/CollisionProfileDetails.cpp +++ b/Engine/Source/Editor/DetailCustomizations/Private/CollisionProfileDetails.cpp @@ -1925,7 +1925,7 @@ FReply FCollisionProfileDetails::OnNewChannel(bool bTraceType) // find empty channel and see if we can add it. ECollisionChannel NewChannel = FindAvailableChannel(); - if (ensure(NewChannel >= ECC_GameTraceChannel1 && NewChannel <= ECC_GameTraceChannel18)) + if (ensure(NewChannel >= ECC_GameTraceChannel1 && NewChannel <= ECC_GameTraceChannel18)) //-V547 { // Create modal window for modification TSharedRef WidgetWindow = SNew(SWindow) diff --git a/Engine/Source/Editor/DetailCustomizations/Private/ColorGradingVectorCustomization.cpp b/Engine/Source/Editor/DetailCustomizations/Private/ColorGradingVectorCustomization.cpp index 8e40c754222c..0b4f2007f168 100644 --- a/Engine/Source/Editor/DetailCustomizations/Private/ColorGradingVectorCustomization.cpp +++ b/Engine/Source/Editor/DetailCustomizations/Private/ColorGradingVectorCustomization.cpp @@ -224,19 +224,24 @@ void FColorGradingVectorCustomizationBase::OnSliderValueChanged(float NewValue, TOptional FColorGradingVectorCustomizationBase::OnSliderGetValue(int32 ColorIndex) const { FVector4 ValueVector; - verifySlow(ColorGradingPropertyHandle.Pin()->GetValue(ValueVector) == FPropertyAccess::Success); - float Value = 0.0f; + + if (ColorGradingPropertyHandle.Pin()->GetValue(ValueVector) == FPropertyAccess::Success) + { + float Value = 0.0f; - if (IsRGBMode) - { - Value = ValueVector[ColorIndex]; - } - else - { - Value = ColorIndex < 3 ? CurrentHSVColor.Component(ColorIndex) : ValueVector.W; + if (IsRGBMode) + { + Value = ValueVector[ColorIndex]; + } + else + { + Value = ColorIndex < 3 ? CurrentHSVColor.Component(ColorIndex) : ValueVector.W; + } + + return Value; } - return Value; + return TOptional(); } void FColorGradingVectorCustomizationBase::OnCurrentHSVColorChangedDelegate(FLinearColor NewHSVColor, bool Originator) @@ -252,82 +257,93 @@ void FColorGradingVectorCustomizationBase::OnCurrentHSVColorChangedDelegate(FLin FLinearColor FColorGradingVectorCustomizationBase::GetGradientFillerColor(int32 ColorIndex) const { FVector4 ValueVector; - verifySlow(ColorGradingPropertyHandle.Pin()->GetValue(ValueVector) == FPropertyAccess::Success); - if (IsRGBMode) + if (ColorGradingPropertyHandle.Pin()->GetValue(ValueVector) == FPropertyAccess::Success) { + if (IsRGBMode) + { + switch (ColorIndex) + { + case 0: return FLinearColor(SpinBoxMinMaxSliderValues.CurrentMaxSliderValue.GetValue(), ValueVector.Y, ValueVector.Z, 1.0f); + case 1: return FLinearColor(ValueVector.X, SpinBoxMinMaxSliderValues.CurrentMaxSliderValue.GetValue(), ValueVector.Z, 1.0f); + case 2: return FLinearColor(ValueVector.X, ValueVector.Y, SpinBoxMinMaxSliderValues.CurrentMaxSliderValue.GetValue(), 1.0f); + case 3: return FLinearColor(ValueVector.X, ValueVector.Y, ValueVector.Z, 1.0f); + default: return FLinearColor(ForceInit); + } + } + switch (ColorIndex) { - case 0: return FLinearColor(SpinBoxMinMaxSliderValues.CurrentMaxSliderValue.GetValue(), ValueVector.Y, ValueVector.Z, 1.0f); - case 1: return FLinearColor(ValueVector.X, SpinBoxMinMaxSliderValues.CurrentMaxSliderValue.GetValue(), ValueVector.Z, 1.0f); - case 2: return FLinearColor(ValueVector.X, ValueVector.Y, SpinBoxMinMaxSliderValues.CurrentMaxSliderValue.GetValue(), 1.0f); - case 3: return FLinearColor(ValueVector.X, ValueVector.Y, ValueVector.Z, 1.0f); - default: return FLinearColor(); + case 0: return FLinearColor(CurrentHSVColor.R, CurrentHSVColor.G, CurrentHSVColor.B, 1.0f); + case 1: return FLinearColor(CurrentHSVColor.R, 1.0f, CurrentHSVColor.B, 1.0f).HSVToLinearRGB(); + case 2: return FLinearColor(CurrentHSVColor.R, CurrentHSVColor.G, SpinBoxMinMaxSliderValues.CurrentMaxSliderValue.GetValue(), 1.0f).HSVToLinearRGB(); + case 3: return FLinearColor(CurrentHSVColor.R, CurrentHSVColor.G, CurrentHSVColor.B, 1.0f).HSVToLinearRGB(); + default: return FLinearColor(ForceInit); } } - switch (ColorIndex) - { - case 0: return FLinearColor(CurrentHSVColor.R, CurrentHSVColor.G, CurrentHSVColor.B, 1.0f); - case 1: return FLinearColor(CurrentHSVColor.R, 1.0f, CurrentHSVColor.B, 1.0f).HSVToLinearRGB(); - case 2: return FLinearColor(CurrentHSVColor.R, CurrentHSVColor.G, SpinBoxMinMaxSliderValues.CurrentMaxSliderValue.GetValue(), 1.0f).HSVToLinearRGB(); - case 3: return FLinearColor(CurrentHSVColor.R, CurrentHSVColor.G, CurrentHSVColor.B, 1.0f).HSVToLinearRGB(); - default: return FLinearColor(); - } + return FLinearColor(ForceInit); } FLinearColor FColorGradingVectorCustomizationBase::GetGradientEndColor(int32 ColorIndex) const { FVector4 ValueVector; - verifySlow(ColorGradingPropertyHandle.Pin()->GetValue(ValueVector) == FPropertyAccess::Success); - - if (IsRGBMode) + if (ColorGradingPropertyHandle.Pin()->GetValue(ValueVector) == FPropertyAccess::Success) { + if (IsRGBMode) + { + switch (ColorIndex) + { + case 0: return FLinearColor(1.0f, ValueVector.Y, ValueVector.Z, 1.0f); + case 1: return FLinearColor(ValueVector.X, 1.0f, ValueVector.Z, 1.0f); + case 2: return FLinearColor(ValueVector.X, ValueVector.Y, 1.0f, 1.0f); + case 3: return FLinearColor(ValueVector.X, ValueVector.Y, ValueVector.Z, 1.0f); + default: return FLinearColor(ForceInit); + } + } + switch (ColorIndex) { - case 0: return FLinearColor(1.0f, ValueVector.Y, ValueVector.Z, 1.0f); - case 1: return FLinearColor(ValueVector.X, 1.0f, ValueVector.Z, 1.0f); - case 2: return FLinearColor(ValueVector.X, ValueVector.Y, 1.0f, 1.0f); - case 3: return FLinearColor(ValueVector.X, ValueVector.Y, ValueVector.Z, 1.0f); - default: return FLinearColor(); + case 0: return FLinearColor(CurrentHSVColor.R, CurrentHSVColor.G, CurrentHSVColor.B, 1.0f); + case 1: return FLinearColor(CurrentHSVColor.R, 1.0f, CurrentHSVColor.B, 1.0f).HSVToLinearRGB(); + case 2: return FLinearColor(CurrentHSVColor.R, CurrentHSVColor.G, 1.0f, 1.0f).HSVToLinearRGB(); + case 3: return FLinearColor(CurrentHSVColor.R, CurrentHSVColor.G, CurrentHSVColor.B, 1.0f).HSVToLinearRGB(); + default: return FLinearColor(ForceInit); } } - - switch (ColorIndex) - { - case 0: return FLinearColor(CurrentHSVColor.R, CurrentHSVColor.G, CurrentHSVColor.B, 1.0f); - case 1: return FLinearColor(CurrentHSVColor.R, 1.0f, CurrentHSVColor.B, 1.0f).HSVToLinearRGB(); - case 2: return FLinearColor(CurrentHSVColor.R, CurrentHSVColor.G, 1.0f, 1.0f).HSVToLinearRGB(); - case 3: return FLinearColor(CurrentHSVColor.R, CurrentHSVColor.G, CurrentHSVColor.B, 1.0f).HSVToLinearRGB(); - default: return FLinearColor(); - } + + return FLinearColor(ForceInit); } FLinearColor FColorGradingVectorCustomizationBase::GetGradientStartColor(int32 ColorIndex) const { FVector4 ValueVector; - verifySlow(ColorGradingPropertyHandle.Pin()->GetValue(ValueVector) == FPropertyAccess::Success); - if (IsRGBMode) + if (ColorGradingPropertyHandle.Pin()->GetValue(ValueVector) == FPropertyAccess::Success) { - switch (ColorIndex) + if (IsRGBMode) { + switch (ColorIndex) + { case 0: return FLinearColor(0.0f, ValueVector.Y, ValueVector.Z, 1.0f); case 1: return FLinearColor(ValueVector.X, 0.0f, ValueVector.Z, 1.0f); case 2: return FLinearColor(ValueVector.X, ValueVector.Y, 0.0f, 1.0f); case 3: return FLinearColor(0.0f, 0.0f, 0.0f, 1.0f); - default: return FLinearColor(); + default: return FLinearColor(ForceInit); + } } - } - - switch (ColorIndex) - { + + switch (ColorIndex) + { case 0: return FLinearColor(CurrentHSVColor.R, CurrentHSVColor.G, CurrentHSVColor.B, 1.0f); case 1: return FLinearColor(CurrentHSVColor.R, 0.0f, CurrentHSVColor.B, 1.0f).HSVToLinearRGB(); case 2: return FLinearColor(CurrentHSVColor.R, CurrentHSVColor.G, 0.0f, 1.0f).HSVToLinearRGB(); case 3: return FLinearColor(0.0f, 0.0f, 0.0f, 1.0f); - default: return FLinearColor(); + default: return FLinearColor(ForceInit); + } } + + return FLinearColor(ForceInit); } TArray FColorGradingVectorCustomizationBase::GetGradientColor(int32 ColorIndex) const @@ -409,6 +425,11 @@ bool FColorGradingVectorCustomizationBase::GetSupportDynamicSliderMinValue(bool return DefaultValue; } +bool FColorGradingVectorCustomizationBase::IsEntryBoxEnabled(int32 ColorIndex) const +{ + return OnSliderGetValue(ColorIndex) != TOptional(); +} + TSharedRef> FColorGradingVectorCustomizationBase::MakeNumericEntryBox(int32 ColorIndex, TOptional& MinValue, TOptional& MaxValue, TOptional& SliderMinValue, TOptional& SliderMaxValue, float& SliderExponent, float& Delta, int32 &ShiftMouseMovePixelPerDelta, bool& SupportDynamicSliderMaxValue, bool& SupportDynamicSliderMinValue) { TAttribute TextGetter = TAttribute::Create(TAttribute::FGetter::CreateSP(this, &FColorGradingVectorCustomizationBase::OnGetColorLabelText, ColorGradingPropertyHandle.Pin()->GetPropertyDisplayName(), ColorIndex)); @@ -438,6 +459,7 @@ TSharedRef> FColorGradingVectorCustomizationBase::MakeNu .Delta(this, &FColorGradingVectorCustomizationBase::OnGetSliderDeltaValue, Delta, ColorIndex) .ToolTipText(this, &FColorGradingVectorCustomizationBase::OnGetColorLabelToolTipsText, ColorGradingPropertyHandle.Pin()->GetPropertyDisplayName(), ColorIndex) .LabelPadding(FMargin(0)) + .IsEnabled(this, &FColorGradingVectorCustomizationBase::IsEntryBoxEnabled, ColorIndex) .Label() [ LabelWidget @@ -503,13 +525,16 @@ void FColorGradingVectorCustomization::MakeHeaderRow(FDetailWidgetRow& Row, TSha NumericEntryBoxWidgetList.Add(NumericEntryBox); - float MinSliderValue = NumericEntrySpinBox->GetMinSliderValue(); - float MaxSliderValue = NumericEntrySpinBox->GetMaxSliderValue(); + if (NumericEntrySpinBox.IsValid()) + { + float MinSliderValue = NumericEntrySpinBox->GetMinSliderValue(); + float MaxSliderValue = NumericEntrySpinBox->GetMaxSliderValue(); - SpinBoxMinMaxSliderValues.CurrentMinSliderValue = MinSliderValue == TNumericLimits::Lowest() ? TOptional() : MinSliderValue; - SpinBoxMinMaxSliderValues.CurrentMaxSliderValue = MaxSliderValue == TNumericLimits::Max() ? TOptional() : MaxSliderValue; - SpinBoxMinMaxSliderValues.DefaultMinSliderValue = SpinBoxMinMaxSliderValues.CurrentMinSliderValue; - SpinBoxMinMaxSliderValues.DefaultMaxSliderValue = SpinBoxMinMaxSliderValues.CurrentMaxSliderValue; + SpinBoxMinMaxSliderValues.CurrentMinSliderValue = MinSliderValue == TNumericLimits::Lowest() ? TOptional() : MinSliderValue; + SpinBoxMinMaxSliderValues.CurrentMaxSliderValue = MaxSliderValue == TNumericLimits::Max() ? TOptional() : MaxSliderValue; + SpinBoxMinMaxSliderValues.DefaultMinSliderValue = SpinBoxMinMaxSliderValues.CurrentMinSliderValue; + SpinBoxMinMaxSliderValues.DefaultMaxSliderValue = SpinBoxMinMaxSliderValues.CurrentMaxSliderValue; + } ContentHorizontalBox->AddSlot() .Padding(FMargin(0.0f, 2.0f, 3.0f, 0.0f)) @@ -532,16 +557,36 @@ void FColorGradingVectorCustomization::MakeHeaderRow(FDetailWidgetRow& Row, TSha .VAlign(VAlign_Center) .Padding(FMargin(0.0f, 2.0f, 3.0f, 0.0f)) [ - SNew(SColorBlock) - .Color(this, &FColorGradingVectorCustomization::OnGetHeaderColorBlock) - .ShowBackgroundForAlpha(false) - .IgnoreAlpha(true) - .ColorIsHSV(false) - .Size(FVector2D(70.0f, 12.0f)) + SNew(SOverlay) + + SOverlay::Slot() + [ + SNew(SColorBlock) + .Color(this, &FColorGradingVectorCustomization::OnGetHeaderColorBlock) + .ShowBackgroundForAlpha(false) + .IgnoreAlpha(true) + .ColorIsHSV(false) + .Size(FVector2D(70.0f, 12.0f)) + ] + + SOverlay::Slot() + .HAlign(HAlign_Center) + .VAlign(VAlign_Center) + [ + SNew(STextBlock) + .Text(NSLOCTEXT("PropertyEditor", "MultipleValues", "Multiple Values")) + .Font(IDetailLayoutBuilder::GetDetailFont()) + .ColorAndOpacity(FSlateColor(FLinearColor::Black)) // we know the background is always white, so can safely set this to black + .Visibility(this, &FColorGradingVectorCustomization::GetMultipleValuesTextVisibility) + ] ]; } } +EVisibility FColorGradingVectorCustomization::GetMultipleValuesTextVisibility() const +{ + FVector4 VectorValue; + return (ColorGradingPropertyHandle.Pin()->GetValue(VectorValue) == FPropertyAccess::MultipleValues) ? EVisibility::Visible : EVisibility::Collapsed; +} + FLinearColor FColorGradingVectorCustomization::OnGetHeaderColorBlock() const { FLinearColor ColorValue(0.0f, 0.0f, 0.0f); @@ -552,6 +597,10 @@ FLinearColor FColorGradingVectorCustomization::OnGetHeaderColorBlock() const ColorValue.G = VectorValue.Y * VectorValue.W; ColorValue.B = VectorValue.Z * VectorValue.W; } + else + { + ColorValue = FLinearColor::White; + } return ColorValue; } @@ -729,6 +778,7 @@ void FColorGradingCustomBuilder::GenerateHeaderRowContent(FDetailWidgetRow& Node .ColorGradingModes(ColorGradingMode) .OnColorCommitted(this, &FColorGradingCustomBuilder::OnColorGradingPickerChanged) .OnQueryCurrentColor(this, &FColorGradingCustomBuilder::GetCurrentColorGradingValue) + .AllowSpin(ColorGradingPropertyHandle.Pin()->GetNumOuterObjects() == 1) ] ]; @@ -787,20 +837,22 @@ void FColorGradingCustomBuilder::GenerateHeaderRowContent(FDetailWidgetRow& Node for (int32 ColorIndex = 0; ColorIndex < SortedChildArray.Num(); ++ColorIndex) { TWeakPtr WeakHandlePtr = SortedChildArray[ColorIndex]; - const bool bLastChild = SortedChildArray.Num() - 1 == ColorIndex; TSharedRef> NumericEntryBox = MakeNumericEntryBox(ColorIndex, MinValue, MaxValue, SliderMinValue, SliderMaxValue, SliderExponent, Delta, ShiftMouseMovePixelPerDelta, SupportDynamicSliderMaxValue, SupportDynamicSliderMinValue); TSharedPtr> NumericEntrySpinBox = StaticCastSharedPtr>(NumericEntryBox->GetSpinBox()); NumericEntryBoxWidgetList.Add(NumericEntryBox); - float MinSliderValue = NumericEntrySpinBox->GetMinSliderValue(); - float MaxSliderValue = NumericEntrySpinBox->GetMaxSliderValue(); + if (NumericEntrySpinBox.IsValid()) + { + float MinSliderValue = NumericEntrySpinBox->GetMinSliderValue(); + float MaxSliderValue = NumericEntrySpinBox->GetMaxSliderValue(); - SpinBoxMinMaxSliderValues.CurrentMinSliderValue = MinSliderValue == TNumericLimits::Lowest() ? TOptional() : MinSliderValue; - SpinBoxMinMaxSliderValues.CurrentMaxSliderValue = MaxSliderValue == TNumericLimits::Max() ? TOptional() : MaxSliderValue; - SpinBoxMinMaxSliderValues.DefaultMinSliderValue = SpinBoxMinMaxSliderValues.CurrentMinSliderValue; - SpinBoxMinMaxSliderValues.DefaultMaxSliderValue = SpinBoxMinMaxSliderValues.CurrentMaxSliderValue; + SpinBoxMinMaxSliderValues.CurrentMinSliderValue = MinSliderValue == TNumericLimits::Lowest() ? TOptional() : MinSliderValue; + SpinBoxMinMaxSliderValues.CurrentMaxSliderValue = MaxSliderValue == TNumericLimits::Max() ? TOptional() : MaxSliderValue; + SpinBoxMinMaxSliderValues.DefaultMinSliderValue = SpinBoxMinMaxSliderValues.CurrentMinSliderValue; + SpinBoxMinMaxSliderValues.DefaultMaxSliderValue = SpinBoxMinMaxSliderValues.CurrentMaxSliderValue; + } VerticalBox->AddSlot() .Padding(FMargin(0.0f, 2.0f, 3.0f, 0.0f)) @@ -872,12 +924,6 @@ void FColorGradingCustomBuilder::GenerateHeaderRowContent(FDetailWidgetRow& Node OnCurrentHSVColorChanged.AddSP(this, &FColorGradingVectorCustomizationBase::OnCurrentHSVColorChangedDelegate); bool RGBMode = true; - FString ParentGroupName = ParentGroup->GetGroupName().ToString(); - ParentGroupName.ReplaceInline(TEXT(" "), TEXT("_")); - ParentGroupName.ReplaceInline(TEXT("|"), TEXT("_")); - - GConfig->GetBool(TEXT("ColorGrading"), *FString::Printf(TEXT("%s_%s_IsRGB"), *ParentGroupName, *ColorGradingPropertyHandle.Pin()->GetPropertyDisplayName().ToString()), RGBMode, GEditorPerProjectIni); - OnChangeColorModeClicked(ECheckBoxState::Checked, RGBMode ? ColorModeType::RGB : ColorModeType::HSV); // Find the highest current value and propagate it to all others so they all matches float BestMaxSliderValue = 0.0f; @@ -908,6 +954,14 @@ void FColorGradingCustomBuilder::GenerateHeaderRowContent(FDetailWidgetRow& Node OnDynamicSliderMaxValueChanged(BestMaxSliderValue, nullptr, true, true); OnDynamicSliderMinValueChanged(BestMinSliderValue, nullptr, true, true); + + FString ParentGroupName = ParentGroup->GetGroupName().ToString(); + ParentGroupName.ReplaceInline(TEXT(" "), TEXT("_")); + ParentGroupName.ReplaceInline(TEXT("|"), TEXT("_")); + + GConfig->GetBool(TEXT("ColorGrading"), *FString::Printf(TEXT("%s_%s_IsRGB"), *ParentGroupName, *ColorGradingPropertyHandle.Pin()->GetPropertyDisplayName().ToString()), RGBMode, GEditorPerProjectIni); + OnChangeColorModeClicked(ECheckBoxState::Checked, RGBMode ? ColorModeType::RGB : ColorModeType::HSV); + } FText FColorGradingCustomBuilder::OnChangeColorModeText(ColorModeType ModeType) const @@ -948,6 +1002,12 @@ EVisibility FColorGradingCustomBuilder::OnGetGradientVisibility() const void FColorGradingCustomBuilder::OnChangeColorModeClicked(ECheckBoxState NewValue, ColorModeType ModeType) { + FVector4 CurrentValueVector; + if (ColorGradingPropertyHandle.Pin()->GetValue(CurrentValueVector) != FPropertyAccess::Success) + { + return; + } + bool NewIsRGBMode = true; switch (ModeType) @@ -966,8 +1026,6 @@ void FColorGradingCustomBuilder::OnChangeColorModeClicked(ECheckBoxState NewValu GConfig->SetBool(TEXT("ColorGrading"), *FString::Printf(TEXT("%s_%s_IsRGB"), *ParentGroupName, *ColorGradingPropertyHandle.Pin()->GetPropertyDisplayName().ToString()), IsRGBMode, GEditorPerProjectIni); - FVector4 CurrentValueVector; - verifySlow(ColorGradingPropertyHandle.Pin()->GetValue(CurrentValueVector) == FPropertyAccess::Success); CurrentHSVColor = FLinearColor(CurrentValueVector.X, CurrentValueVector.Y, CurrentValueVector.Z).LinearRGBToHSV(); OnCurrentHSVColorChanged.Broadcast(CurrentHSVColor, true); @@ -1017,9 +1075,9 @@ void FColorGradingCustomBuilder::OnColorGradingPickerChanged(FVector4& NewValue, OnCurrentHSVColorChangedDelegate(NewHSVColor, true); } -void FColorGradingCustomBuilder::GetCurrentColorGradingValue(FVector4& OutCurrentValue) +bool FColorGradingCustomBuilder::GetCurrentColorGradingValue(FVector4& OutCurrentValue) { - verifySlow(ColorGradingPropertyHandle.Pin()->GetValue(OutCurrentValue) == FPropertyAccess::Success); + return ColorGradingPropertyHandle.Pin()->GetValue(OutCurrentValue) == FPropertyAccess::Success; } void FColorGradingCustomBuilder::GenerateChildContent(IDetailChildrenBuilder& ChildrenBuilder) diff --git a/Engine/Source/Editor/DetailCustomizations/Private/ColorGradingVectorCustomization.h b/Engine/Source/Editor/DetailCustomizations/Private/ColorGradingVectorCustomization.h index 243df7c7e88b..950a16c76c82 100644 --- a/Engine/Source/Editor/DetailCustomizations/Private/ColorGradingVectorCustomization.h +++ b/Engine/Source/Editor/DetailCustomizations/Private/ColorGradingVectorCustomization.h @@ -78,6 +78,9 @@ protected: bool GetSupportDynamicSliderMaxValue(bool DefaultValue, int32 ColorIndex) const; bool GetSupportDynamicSliderMinValue(bool DefaultValue, int32 ColorIndex) const; + /** Callback returning if an entry box should be enabled */ + bool IsEntryBoxEnabled(int32 ColorIndex) const; + /** Helper function used to compute desired gradient color for a requested color index */ FLinearColor GetGradientEndColor(int32 ColorIndex) const; FLinearColor GetGradientStartColor(int32 ColorIndex) const; @@ -130,6 +133,7 @@ public: private: /** Will return the color of the color block displayed in the header */ FLinearColor OnGetHeaderColorBlock() const; + EVisibility GetMultipleValuesTextVisibility() const; /** Represent the custom builder associated with the color grading property */ TSharedPtr CustomColorGradingBuilder; @@ -172,7 +176,7 @@ private: /* Local UI Handlers */ void OnColorGradingPickerChanged(FVector4 &NewValue, bool ShouldCommitValueChanges); - void GetCurrentColorGradingValue(FVector4 &OutCurrentValue); + bool GetCurrentColorGradingValue(FVector4 &OutCurrentValue); /** Callback when user click the Group reset button */ void OnDetailGroupReset(); diff --git a/Engine/Source/Editor/DetailCustomizations/Private/ComponentTransformDetails.cpp b/Engine/Source/Editor/DetailCustomizations/Private/ComponentTransformDetails.cpp index bfa7c61e1677..49145e9a32fb 100644 --- a/Engine/Source/Editor/DetailCustomizations/Private/ComponentTransformDetails.cpp +++ b/Engine/Source/Editor/DetailCustomizations/Private/ComponentTransformDetails.cpp @@ -29,9 +29,9 @@ #include "Widgets/Input/SRotatorInputBox.h" #include "ScopedTransaction.h" #include "IPropertyUtilities.h" - #include "Math/UnitConversion.h" #include "Widgets/Input/NumericUnitTypeInterface.inl" +#include "EditorProjectSettings.h" #define LOCTEXT_NAMESPACE "FComponentTransformDetails" @@ -78,7 +78,7 @@ static USceneComponent* GetSceneComponentFromDetailsObject(UObject* InObject) } FComponentTransformDetails::FComponentTransformDetails( const TArray< TWeakObjectPtr >& InSelectedObjects, const FSelectedActorInfo& InSelectedActorInfo, IDetailLayoutBuilder& DetailBuilder ) - : TNumericUnitTypeInterface(EUnit::Centimeters) + : TNumericUnitTypeInterface(GetDefault()->bDisplayUnitsOnComponentTransforms ? EUnit::Centimeters : EUnit::Unspecified) , SelectedActorInfo( InSelectedActorInfo ) , SelectedObjects( InSelectedObjects ) , NotifyHook( DetailBuilder.GetPropertyUtilities()->GetNotifyHook() ) @@ -693,12 +693,12 @@ void FComponentTransformDetails::OnToggleAbsoluteLocation( bool bEnable ) { if (SceneComponent->bAbsoluteLocation) { - SceneComponent->RelativeLocation = SceneComponent->ComponentToWorld.GetTranslation(); + SceneComponent->RelativeLocation = SceneComponent->GetComponentTransform().GetTranslation(); } else { FTransform ParentToWorld = SceneComponent->GetAttachParent()->GetSocketTransform(SceneComponent->GetAttachSocketName()); - FTransform RelativeTM = SceneComponent->ComponentToWorld.GetRelativeTransform(ParentToWorld); + FTransform RelativeTM = SceneComponent->GetComponentTransform().GetRelativeTransform(ParentToWorld); SceneComponent->RelativeLocation = RelativeTM.GetTranslation(); } } diff --git a/Engine/Source/Editor/DetailCustomizations/Private/CurveColorCustomization.cpp b/Engine/Source/Editor/DetailCustomizations/Private/CurveColorCustomization.cpp index b4781540abb1..a6cd9495fc23 100644 --- a/Engine/Source/Editor/DetailCustomizations/Private/CurveColorCustomization.cpp +++ b/Engine/Source/Editor/DetailCustomizations/Private/CurveColorCustomization.cpp @@ -410,7 +410,7 @@ FReply FCurveColorCustomization::OnCurvePreviewDoubleClick(const FGeometry& InMy const FVector2D CursorPos = FSlateApplication::Get().GetCursorPos(); FSlateRect Anchor(CursorPos.X, CursorPos.Y, CursorPos.X, CursorPos.Y); - FVector2D AdjustedSummonLocation = FSlateApplication::Get().CalculatePopupWindowPosition( Anchor, FCurveColorCustomization::DEFAULT_WINDOW_SIZE, Orient_Horizontal ); + FVector2D AdjustedSummonLocation = FSlateApplication::Get().CalculatePopupWindowPosition( Anchor, FCurveColorCustomization::DEFAULT_WINDOW_SIZE, FVector2D::ZeroVector, Orient_Horizontal ); TSharedPtr Window = SNew(SWindow) .Title( FText::Format( LOCTEXT("WindowHeader", "{0} - Internal Color Curve Editor"), StructPropertyHandle->GetPropertyDisplayName()) ) diff --git a/Engine/Source/Editor/DetailCustomizations/Private/CurveStructCustomization.cpp b/Engine/Source/Editor/DetailCustomizations/Private/CurveStructCustomization.cpp index b9bb43bc03f9..d0c110d9ff65 100644 --- a/Engine/Source/Editor/DetailCustomizations/Private/CurveStructCustomization.cpp +++ b/Engine/Source/Editor/DetailCustomizations/Private/CurveStructCustomization.cpp @@ -390,7 +390,7 @@ FReply FCurveStructCustomization::OnCurvePreviewDoubleClick( const FGeometry& In const FVector2D CursorPos = FSlateApplication::Get().GetCursorPos(); FSlateRect Anchor(CursorPos.X, CursorPos.Y, CursorPos.X, CursorPos.Y); - FVector2D AdjustedSummonLocation = FSlateApplication::Get().CalculatePopupWindowPosition( Anchor, FCurveStructCustomization::DEFAULT_WINDOW_SIZE, Orient_Horizontal ); + FVector2D AdjustedSummonLocation = FSlateApplication::Get().CalculatePopupWindowPosition( Anchor, FCurveStructCustomization::DEFAULT_WINDOW_SIZE, FVector2D::ZeroVector, Orient_Horizontal ); TSharedPtr Window = SNew(SWindow) .Title( FText::Format( LOCTEXT("WindowHeader", "{0} - Internal Curve Editor"), StructPropertyHandle->GetPropertyDisplayName()) ) diff --git a/Engine/Source/Editor/DetailCustomizations/Private/DetailCustomizations.cpp b/Engine/Source/Editor/DetailCustomizations/Private/DetailCustomizations.cpp index 70383f94ccee..e79077bd0139 100644 --- a/Engine/Source/Editor/DetailCustomizations/Private/DetailCustomizations.cpp +++ b/Engine/Source/Editor/DetailCustomizations/Private/DetailCustomizations.cpp @@ -110,7 +110,6 @@ #include "MovieSceneCurveInterfaceKeyEditStructCustomization.h" #include "LevelSequenceBurnInOptionsCustomization.h" #include "MovieSceneBindingOverrideDataCustomization.h" -#include "MovieSceneObjectBindingIDCustomization.h" #include "TextCustomization.h" #include "AnimTrailNodeDetails.h" #include "MaterialProxySettingsCustomizations.h" @@ -240,7 +239,6 @@ void FDetailCustomizationsModule::RegisterPropertyTypeCustomizations() RegisterCustomPropertyTypeLayout("CameraFocusSettings", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FCameraFocusSettingsCustomization::MakeInstance)); RegisterCustomPropertyTypeLayout("MovieSceneSequencePlaybackSettings", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FMovieSceneSequencePlaybackSettingsCustomization::MakeInstance)); RegisterCustomPropertyTypeLayout("MovieSceneBindingOverrideData", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FMovieSceneBindingOverrideDataCustomization::MakeInstance)); - RegisterCustomPropertyTypeLayout("MovieSceneObjectBindingID", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FMovieSceneObjectBindingIDCustomization::MakeInstance)); RegisterCustomPropertyTypeLayout("MovieSceneTrackEvalOptions", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FMovieSceneTrackEvalOptionsCustomization::MakeInstance)); RegisterCustomPropertyTypeLayout("MovieSceneSectionEvalOptions", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FMovieSceneSectionEvalOptionsCustomization::MakeInstance)); RegisterCustomPropertyTypeLayout("MovieSceneEventParameters", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FMovieSceneEventParametersCustomization::MakeInstance)); diff --git a/Engine/Source/Editor/DetailCustomizations/Private/DirectoryPathStructCustomization.cpp b/Engine/Source/Editor/DetailCustomizations/Private/DirectoryPathStructCustomization.cpp index 724a49745dd9..49225fe2a8e4 100644 --- a/Engine/Source/Editor/DetailCustomizations/Private/DirectoryPathStructCustomization.cpp +++ b/Engine/Source/Editor/DetailCustomizations/Private/DirectoryPathStructCustomization.cpp @@ -30,8 +30,7 @@ void FDirectoryPathStructCustomization::CustomizeHeader( TSharedRefHasMetaData( TEXT("RelativeToGameContentDir") ); const bool bUseRelativePath = StructPropertyHandle->HasMetaData( TEXT("RelativePath") ); - const bool bLongPackageName = StructPropertyHandle->HasMetaData( TEXT("LongPackageName") ); - const bool bContentDir = StructPropertyHandle->HasMetaData( TEXT("ContentDir") ); + const bool bContentDir = StructPropertyHandle->HasMetaData( TEXT("ContentDir") ) || StructPropertyHandle->HasMetaData(TEXT("LongPackageName")); AbsoluteGameContentDir = FPaths::ConvertRelativePathToFull(FPaths::GameContentDir()); @@ -60,7 +59,7 @@ void FDirectoryPathStructCustomization::CustomizeHeader( TSharedRef PropertyHandle, const bool bRelativeToGameContentDir, const bool bUseRelativePath, const bool bLongPackageName) const +FReply FDirectoryPathStructCustomization::OnPickDirectory(TSharedRef PropertyHandle, const bool bRelativeToGameContentDir, const bool bUseRelativePath) const { FString Directory; IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get(); @@ -153,25 +152,11 @@ FReply FDirectoryPathStructCustomization::OnPickDirectory(TSharedRef PropertyHandle) ; /** Delegate used to display a directory picker */ - FReply OnPickDirectory(TSharedRef PropertyHandle, const bool bRelativeToGameContentDir, const bool bUseRelativePaths, const bool bLongPackageName) const; + FReply OnPickDirectory(TSharedRef PropertyHandle, const bool bRelativeToGameContentDir, const bool bUseRelativePaths) const; /** Check whether that the chosen path is valid */ bool IsValidPath(const FString& AbsolutePath, const bool bRelativeToGameContentDir, FText* const OutReason = nullptr) const; diff --git a/Engine/Source/Editor/DetailCustomizations/Private/FbxImportUIDetails.cpp b/Engine/Source/Editor/DetailCustomizations/Private/FbxImportUIDetails.cpp index bb638d36217d..7718dccdb92f 100644 --- a/Engine/Source/Editor/DetailCustomizations/Private/FbxImportUIDetails.cpp +++ b/Engine/Source/Editor/DetailCustomizations/Private/FbxImportUIDetails.cpp @@ -83,6 +83,7 @@ void FFbxImportUIDetails::CustomizeDetails( IDetailLayoutBuilder& DetailBuilder MeshCategory.GetDefaultProperties(CategoryDefaultProperties); + switch(ImportUI->MeshTypeToImport) { case FBXIT_StaticMesh: @@ -130,13 +131,20 @@ void FFbxImportUIDetails::CustomizeDetails( IDetailLayoutBuilder& DetailBuilder { { TSharedRef Prop = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UFbxImportUI, bImportAsSkeletal)); - Prop->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FFbxImportUIDetails::MeshImportModeChanged)); - MeshCategory.AddProperty(Prop); + if (!ImportUI->bIsReimport) + { + Prop->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FFbxImportUIDetails::MeshImportModeChanged)); + MeshCategory.AddProperty(Prop); + } + else + { + DetailBuilder.HideProperty(Prop); + } } } TSharedRef ImportMeshProp = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UFbxImportUI, bImportMesh)); - if(ImportUI->OriginalImportType == FBXIT_SkeletalMesh && ImportType != FBXIT_StaticMesh) + if(ImportUI->OriginalImportType == FBXIT_SkeletalMesh && ImportType != FBXIT_StaticMesh && !ImportUI->bIsReimport) { ImportMeshProp->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FFbxImportUIDetails::ImportMeshToggleChanged)); MeshCategory.AddProperty(ImportMeshProp); @@ -269,6 +277,13 @@ void FFbxImportUIDetails::CustomizeDetails( IDetailLayoutBuilder& DetailBuilder } else { + //Show the reset Material slot only when re importing + TSharedRef ResetMaterialSlotHandle = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UFbxImportUI, bResetMaterialSlots)); + if (!ImportUI->bIsReimport) + { + DetailBuilder.HideProperty(ResetMaterialSlotHandle); + } + TSharedRef TextureDataProp = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UFbxImportUI, TextureImportData)); DetailBuilder.HideProperty(TextureDataProp); @@ -280,216 +295,229 @@ void FFbxImportUIDetails::CustomizeDetails( IDetailLayoutBuilder& DetailBuilder // We ignore base import data for this window. if(Handle->GetProperty()->GetOuter() == UFbxTextureImportData::StaticClass()) { - if (Handle->GetPropertyDisplayName().ToString() != FString(TEXT("Base Material Name"))) + if (Handle->GetPropertyDisplayName().ToString() == FString(TEXT("Base Material Name"))) + { + if (ImportUI->bImportMaterials) + { + ConstructBaseMaterialUI(Handle, MaterialCategory); + } + } + else { MaterialCategory.AddProperty(Handle); } - else if (ImportUI->bImportMaterials) - { - IDetailPropertyRow &MaterialPropertyRow = MaterialCategory.AddProperty(Handle); - Handle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FFbxImportUIDetails::BaseMaterialChanged)); - UMaterialInterface *MaterialInstanceProperty = Cast(ImportUI->TextureImportData->BaseMaterialName.TryLoad()); - if (MaterialInstanceProperty) - { - UMaterial *Material = MaterialInstanceProperty->GetMaterial(); - if (Material) { - BaseColorNames.Empty(); - BaseTextureNames.Empty(); - BaseColorNames.Add(MakeShareable(new FString())); - BaseTextureNames.Add(MakeShareable(new FString())); - TArray ParameterNames; - TArray Guids; - float MinDesiredWidth = 150.0f; - TSharedPtr NameWidget; - TSharedPtr ValueWidget; - FDetailWidgetRow Row; - MaterialPropertyRow.GetDefaultWidgets(NameWidget, ValueWidget, Row); - - // base color properties, only used when there is no texture in the diffuse map - Material->GetAllVectorParameterNames(ParameterNames, Guids); - for (FName &ParameterName : ParameterNames) - { - BaseColorNames.Add(MakeShareable(new FString(ParameterName.ToString()))); - } - int InitialSelect = FindString(BaseColorNames, ImportUI->TextureImportData->BaseColorName); - InitialSelect = InitialSelect == INDEX_NONE ? 0 : InitialSelect; // default to the empty string located at index 0 - MaterialCategory.AddCustomRow(LOCTEXT("BaseColorProperty", "Base Color Property")) - .NameContent() - [ - SNew(STextBlock) - .Text(LOCTEXT("BaseColorProperty", "Base Color Property")) - .Font(IDetailLayoutBuilder::GetDetailFont()) - ] - .ValueContent() - .MaxDesiredWidth(Row.ValueWidget.MaxWidth) - [ - SNew(SHorizontalBox) - + SHorizontalBox::Slot() - .AutoWidth() - [ - SNew(SBox) - .MinDesiredWidth(MinDesiredWidth) - [ - SNew(STextComboBox) - .OptionsSource(&BaseColorNames) - .ToolTip(SNew(SToolTip).Text(LOCTEXT("BaseColorFBXImportToolTip", "When there is no diffuse texture in the imported material this color property will be used to fill a contant color value instead."))) - .OnSelectionChanged(this, &FFbxImportUIDetails::OnBaseColor) - .InitiallySelectedItem(BaseColorNames[InitialSelect]) - ] - ] - ]; - - // base texture properties - ParameterNames.Empty(); - Guids.Empty(); - Material->GetAllTextureParameterNames(ParameterNames, Guids); - for (FName &ParameterName : ParameterNames) - { - BaseTextureNames.Add(MakeShareable(new FString(ParameterName.ToString()))); - } - InitialSelect = FindString(BaseTextureNames, ImportUI->TextureImportData->BaseDiffuseTextureName); - InitialSelect = InitialSelect == INDEX_NONE ? 0 : InitialSelect; // default to the empty string located at index 0 - MaterialCategory.AddCustomRow(LOCTEXT("BaseTextureProperty", "Base Texture Property")).NameContent() - [ - SNew(STextBlock) - .Text(LOCTEXT("BaseTextureProperty", "Base Texture Property")) - .Font(IDetailLayoutBuilder::GetDetailFont()) - ] - .ValueContent() - .MaxDesiredWidth(Row.ValueWidget.MaxWidth) - [ - SNew(SHorizontalBox) - + SHorizontalBox::Slot() - .AutoWidth() - [ - SNew(SBox) - .MinDesiredWidth(MinDesiredWidth) - [ - SNew(STextComboBox) - .OptionsSource(&BaseTextureNames) - .OnSelectionChanged(this, &FFbxImportUIDetails::OnDiffuseTextureColor) - .InitiallySelectedItem(BaseTextureNames[InitialSelect]) - ] - ] - ]; - - // base normal properties - InitialSelect = FindString(BaseTextureNames, ImportUI->TextureImportData->BaseNormalTextureName); - InitialSelect = InitialSelect == INDEX_NONE ? 0 : InitialSelect; // default to the empty string located at index 0 - MaterialCategory.AddCustomRow(LOCTEXT("BaseNormalTextureProperty", "Base Normal Texture Property")).NameContent() - [ - SNew(STextBlock) - .Text(LOCTEXT("BaseNormalTextureProperty", "Base Normal Texture Property")) - .Font(IDetailLayoutBuilder::GetDetailFont()) - ] - .ValueContent() - .MaxDesiredWidth(Row.ValueWidget.MaxWidth) - [ - SNew(SHorizontalBox) - + SHorizontalBox::Slot() - .AutoWidth() - [ - SNew(SBox) - .MinDesiredWidth(MinDesiredWidth) - [ - SNew(STextComboBox) - .OptionsSource(&BaseTextureNames) - .OnSelectionChanged(this, &FFbxImportUIDetails::OnNormalTextureColor) - .InitiallySelectedItem(BaseTextureNames[InitialSelect]) - ] - ] - ]; - - // base emissive color properties, only used when there is no texture in the emissive map - InitialSelect = FindString(BaseColorNames, ImportUI->TextureImportData->BaseEmissiveColorName); - InitialSelect = InitialSelect == INDEX_NONE ? 0 : InitialSelect; // default to the empty string located at index 0 - MaterialCategory.AddCustomRow(LOCTEXT("BaseEmissiveColorProperty", "Base Emissive Color Property")) - .NameContent() - [ - SNew(STextBlock) - .Text(LOCTEXT("BaseEmissiveColorProperty", "Base Emissive Color Property")) - .Font(IDetailLayoutBuilder::GetDetailFont()) - ] - .ValueContent() - .MaxDesiredWidth(Row.ValueWidget.MaxWidth) - [ - SNew(SHorizontalBox) - + SHorizontalBox::Slot() - .AutoWidth() - [ - SNew(SBox) - .MinDesiredWidth(MinDesiredWidth) - [ - SNew(STextComboBox) - .OptionsSource(&BaseColorNames) - .ToolTip(SNew(SToolTip).Text(LOCTEXT("BaseEmissiveColorFBXImportToolTip", "When there is no emissive texture in the imported material this emissive color property will be used to fill a contant color value instead."))) - .OnSelectionChanged(this, &FFbxImportUIDetails::OnEmissiveColor) - .InitiallySelectedItem(BaseColorNames[InitialSelect]) - ] - ] - ]; - - // base emmisive properties - InitialSelect = FindString(BaseTextureNames, ImportUI->TextureImportData->BaseEmmisiveTextureName); - InitialSelect = InitialSelect == INDEX_NONE ? 0 : InitialSelect; // default to the empty string located at index 0 - MaterialCategory.AddCustomRow(LOCTEXT("BaseEmmisiveTextureProperty", "Base Emmisive Texture Property")).NameContent() - [ - SNew(STextBlock) - .Text(LOCTEXT("BaseEmmisiveTextureProperty", "Base Emmisive Texture Property")) - .Font(IDetailLayoutBuilder::GetDetailFont()) - ] - .ValueContent() - .MaxDesiredWidth(Row.ValueWidget.MaxWidth) - [ - SNew(SHorizontalBox) - + SHorizontalBox::Slot() - .AutoWidth() - [ - SNew(SBox) - .MinDesiredWidth(MinDesiredWidth) - [ - SNew(STextComboBox) - .OptionsSource(&BaseTextureNames) - .OnSelectionChanged(this, &FFbxImportUIDetails::OnEmmisiveTextureColor) - .InitiallySelectedItem(BaseTextureNames[InitialSelect]) - ] - ] - ]; - - // base specular properties - InitialSelect = FindString(BaseTextureNames, ImportUI->TextureImportData->BaseSpecularTextureName); - InitialSelect = InitialSelect == INDEX_NONE ? 0 : InitialSelect; // default to the empty string located at index 0 - MaterialCategory.AddCustomRow(LOCTEXT("BaseSpecularTextureProperty", "Base Specular Texture Property")).NameContent() - [ - SNew(STextBlock) - .Text(LOCTEXT("BaseSpecularTextureProperty", "Base Specular Texture Property")) - .Font(IDetailLayoutBuilder::GetDetailFont()) - ] - .ValueContent() - .MaxDesiredWidth(Row.ValueWidget.MaxWidth) - [ - SNew(SHorizontalBox) - + SHorizontalBox::Slot() - .AutoWidth() - [ - SNew(SBox) - .MinDesiredWidth(MinDesiredWidth) - [ - SNew(STextComboBox) - .OptionsSource(&BaseTextureNames) - .OnSelectionChanged(this, &FFbxImportUIDetails::OnSpecularTextureColor) - .InitiallySelectedItem(BaseTextureNames[InitialSelect]) - ] - ] - ]; - } - } - } } } } } + +void FFbxImportUIDetails::ConstructBaseMaterialUI(TSharedPtr Handle, IDetailCategoryBuilder& MaterialCategory) +{ + IDetailPropertyRow &MaterialPropertyRow = MaterialCategory.AddProperty(Handle); + Handle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FFbxImportUIDetails::BaseMaterialChanged)); + UMaterialInterface *MaterialInstanceProperty = Cast(ImportUI->TextureImportData->BaseMaterialName.TryLoad()); + if (MaterialInstanceProperty == nullptr) + { + return; + } + UMaterial *Material = MaterialInstanceProperty->GetMaterial(); + if (Material == nullptr) + { + return; + } + + BaseColorNames.Empty(); + BaseTextureNames.Empty(); + BaseColorNames.Add(MakeShareable(new FString())); + BaseTextureNames.Add(MakeShareable(new FString())); + TArray ParameterNames; + TArray Guids; + float MinDesiredWidth = 150.0f; + TSharedPtr NameWidget; + TSharedPtr ValueWidget; + FDetailWidgetRow Row; + MaterialPropertyRow.GetDefaultWidgets(NameWidget, ValueWidget, Row); + + // base color properties, only used when there is no texture in the diffuse map + Material->GetAllVectorParameterNames(ParameterNames, Guids); + for (FName &ParameterName : ParameterNames) + { + BaseColorNames.Add(MakeShareable(new FString(ParameterName.ToString()))); + } + int InitialSelect = FindString(BaseColorNames, ImportUI->TextureImportData->BaseColorName); + InitialSelect = InitialSelect == INDEX_NONE ? 0 : InitialSelect; // default to the empty string located at index 0 + MaterialCategory.AddCustomRow(LOCTEXT("BaseColorProperty", "Base Color Property")) + .NameContent() + [ + SNew(STextBlock) + .Text(LOCTEXT("BaseColorProperty", "Base Color Property")) + .Font(IDetailLayoutBuilder::GetDetailFont()) + ] + .ValueContent() + .MaxDesiredWidth(Row.ValueWidget.MaxWidth) + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(SBox) + .MinDesiredWidth(MinDesiredWidth) + [ + SNew(STextComboBox) + .OptionsSource(&BaseColorNames) + .ToolTip(SNew(SToolTip).Text(LOCTEXT("BaseColorFBXImportToolTip", "When there is no diffuse texture in the imported material this color property will be used to fill a contant color value instead."))) + .OnSelectionChanged(this, &FFbxImportUIDetails::OnBaseColor) + .InitiallySelectedItem(BaseColorNames[InitialSelect]) + ] + ] + ]; + + // base texture properties + ParameterNames.Empty(); + Guids.Empty(); + Material->GetAllTextureParameterNames(ParameterNames, Guids); + for (FName &ParameterName : ParameterNames) + { + BaseTextureNames.Add(MakeShareable(new FString(ParameterName.ToString()))); + } + InitialSelect = FindString(BaseTextureNames, ImportUI->TextureImportData->BaseDiffuseTextureName); + InitialSelect = InitialSelect == INDEX_NONE ? 0 : InitialSelect; // default to the empty string located at index 0 + MaterialCategory.AddCustomRow(LOCTEXT("BaseTextureProperty", "Base Texture Property")).NameContent() + [ + SNew(STextBlock) + .Text(LOCTEXT("BaseTextureProperty", "Base Texture Property")) + .Font(IDetailLayoutBuilder::GetDetailFont()) + ] + .ValueContent() + .MaxDesiredWidth(Row.ValueWidget.MaxWidth) + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(SBox) + .MinDesiredWidth(MinDesiredWidth) + [ + SNew(STextComboBox) + .OptionsSource(&BaseTextureNames) + .OnSelectionChanged(this, &FFbxImportUIDetails::OnDiffuseTextureColor) + .InitiallySelectedItem(BaseTextureNames[InitialSelect]) + ] + ] + ]; + + // base normal properties + InitialSelect = FindString(BaseTextureNames, ImportUI->TextureImportData->BaseNormalTextureName); + InitialSelect = InitialSelect == INDEX_NONE ? 0 : InitialSelect; // default to the empty string located at index 0 + MaterialCategory.AddCustomRow(LOCTEXT("BaseNormalTextureProperty", "Base Normal Texture Property")).NameContent() + [ + SNew(STextBlock) + .Text(LOCTEXT("BaseNormalTextureProperty", "Base Normal Texture Property")) + .Font(IDetailLayoutBuilder::GetDetailFont()) + ] + .ValueContent() + .MaxDesiredWidth(Row.ValueWidget.MaxWidth) + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(SBox) + .MinDesiredWidth(MinDesiredWidth) + [ + SNew(STextComboBox) + .OptionsSource(&BaseTextureNames) + .OnSelectionChanged(this, &FFbxImportUIDetails::OnNormalTextureColor) + .InitiallySelectedItem(BaseTextureNames[InitialSelect]) + ] + ] + ]; + + // base emissive color properties, only used when there is no texture in the emissive map + InitialSelect = FindString(BaseColorNames, ImportUI->TextureImportData->BaseEmissiveColorName); + InitialSelect = InitialSelect == INDEX_NONE ? 0 : InitialSelect; // default to the empty string located at index 0 + MaterialCategory.AddCustomRow(LOCTEXT("BaseEmissiveColorProperty", "Base Emissive Color Property")) + .NameContent() + [ + SNew(STextBlock) + .Text(LOCTEXT("BaseEmissiveColorProperty", "Base Emissive Color Property")) + .Font(IDetailLayoutBuilder::GetDetailFont()) + ] + .ValueContent() + .MaxDesiredWidth(Row.ValueWidget.MaxWidth) + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(SBox) + .MinDesiredWidth(MinDesiredWidth) + [ + SNew(STextComboBox) + .OptionsSource(&BaseColorNames) + .ToolTip(SNew(SToolTip).Text(LOCTEXT("BaseEmissiveColorFBXImportToolTip", "When there is no emissive texture in the imported material this emissive color property will be used to fill a contant color value instead."))) + .OnSelectionChanged(this, &FFbxImportUIDetails::OnEmissiveColor) + .InitiallySelectedItem(BaseColorNames[InitialSelect]) + ] + ] + ]; + + // base emmisive properties + InitialSelect = FindString(BaseTextureNames, ImportUI->TextureImportData->BaseEmmisiveTextureName); + InitialSelect = InitialSelect == INDEX_NONE ? 0 : InitialSelect; // default to the empty string located at index 0 + MaterialCategory.AddCustomRow(LOCTEXT("BaseEmmisiveTextureProperty", "Base Emmisive Texture Property")).NameContent() + [ + SNew(STextBlock) + .Text(LOCTEXT("BaseEmmisiveTextureProperty", "Base Emmisive Texture Property")) + .Font(IDetailLayoutBuilder::GetDetailFont()) + ] + .ValueContent() + .MaxDesiredWidth(Row.ValueWidget.MaxWidth) + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(SBox) + .MinDesiredWidth(MinDesiredWidth) + [ + SNew(STextComboBox) + .OptionsSource(&BaseTextureNames) + .OnSelectionChanged(this, &FFbxImportUIDetails::OnEmmisiveTextureColor) + .InitiallySelectedItem(BaseTextureNames[InitialSelect]) + ] + ] + ]; + + // base specular properties + InitialSelect = FindString(BaseTextureNames, ImportUI->TextureImportData->BaseSpecularTextureName); + InitialSelect = InitialSelect == INDEX_NONE ? 0 : InitialSelect; // default to the empty string located at index 0 + MaterialCategory.AddCustomRow(LOCTEXT("BaseSpecularTextureProperty", "Base Specular Texture Property")).NameContent() + [ + SNew(STextBlock) + .Text(LOCTEXT("BaseSpecularTextureProperty", "Base Specular Texture Property")) + .Font(IDetailLayoutBuilder::GetDetailFont()) + ] + .ValueContent() + .MaxDesiredWidth(Row.ValueWidget.MaxWidth) + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(SBox) + .MinDesiredWidth(MinDesiredWidth) + [ + SNew(STextComboBox) + .OptionsSource(&BaseTextureNames) + .OnSelectionChanged(this, &FFbxImportUIDetails::OnSpecularTextureColor) + .InitiallySelectedItem(BaseTextureNames[InitialSelect]) + ] + ] + ]; +} + void FFbxImportUIDetails::SetStaticMeshLODGroupWidget(IDetailPropertyRow& PropertyRow, const TSharedPtr& Handle) { TSharedPtr NameWidget; diff --git a/Engine/Source/Editor/DetailCustomizations/Private/FbxImportUIDetails.h b/Engine/Source/Editor/DetailCustomizations/Private/FbxImportUIDetails.h index 2f240b59953f..c58a05c341bd 100644 --- a/Engine/Source/Editor/DetailCustomizations/Private/FbxImportUIDetails.h +++ b/Engine/Source/Editor/DetailCustomizations/Private/FbxImportUIDetails.h @@ -24,6 +24,8 @@ public: void CollectChildPropertiesRecursive(TSharedPtr Node, TArray>& OutProperties); + void ConstructBaseMaterialUI(TSharedPtr Handle, class IDetailCategoryBuilder& MaterialCategory); + /** Checks whether a metadata string is valid for a given import type * @param ImportType the type of mesh being imported * @param MetaData the metadata string to validate diff --git a/Engine/Source/Editor/DetailCustomizations/Private/MaterialProxySettingsCustomizations.cpp b/Engine/Source/Editor/DetailCustomizations/Private/MaterialProxySettingsCustomizations.cpp index d14de2786ec0..5daf1bbebb97 100644 --- a/Engine/Source/Editor/DetailCustomizations/Private/MaterialProxySettingsCustomizations.cpp +++ b/Engine/Source/Editor/DetailCustomizations/Private/MaterialProxySettingsCustomizations.cpp @@ -67,7 +67,6 @@ void FMaterialProxySettingsCustomizations::CustomizeChildren(TSharedRef - static void ExtractNumericMetadata(TSharedRef& PropertyHandle, TOptional& MinValue, TOptional& MaxValue, TOptional& SliderMinValue, TOptional& SliderMaxValue, NumericType& SliderExponent, NumericType& Delta, int32 &ShiftMouseMovePixelPerDelta, bool& SupportDynamicSliderMaxValue, bool& SupportDynamicSliderMinValue); + DETAILCUSTOMIZATIONS_API static void ExtractNumericMetadata(TSharedRef& PropertyHandle, TOptional& MinValue, TOptional& MaxValue, TOptional& SliderMinValue, TOptional& SliderMaxValue, NumericType& SliderExponent, NumericType& Delta, int32 &ShiftMouseMovePixelPerDelta, bool& SupportDynamicSliderMaxValue, bool& SupportDynamicSliderMinValue); protected: diff --git a/Engine/Source/Editor/DetailCustomizations/Private/MovieSceneSequencePlaybackSettingsCustomization.cpp b/Engine/Source/Editor/DetailCustomizations/Private/MovieSceneSequencePlaybackSettingsCustomization.cpp index d7d6b2479134..14cbb9e42471 100644 --- a/Engine/Source/Editor/DetailCustomizations/Private/MovieSceneSequencePlaybackSettingsCustomization.cpp +++ b/Engine/Source/Editor/DetailCustomizations/Private/MovieSceneSequencePlaybackSettingsCustomization.cpp @@ -135,6 +135,10 @@ void FMovieSceneSequencePlaybackSettingsCustomization::CustomizeChildren(TShared ChildBuilder.AddChildProperty(StructPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FMovieSceneSequencePlaybackSettings, bRandomStartTime)).ToSharedRef()); ChildBuilder.AddChildProperty(StructPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FMovieSceneSequencePlaybackSettings, StartTime)).ToSharedRef()); ChildBuilder.AddChildProperty(StructPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FMovieSceneSequencePlaybackSettings, bRestoreState)).ToSharedRef()); + ChildBuilder.AddChildProperty(StructPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FMovieSceneSequencePlaybackSettings, bDisableMovementInput)).ToSharedRef()); + ChildBuilder.AddChildProperty(StructPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FMovieSceneSequencePlaybackSettings, bDisableLookAtInput)).ToSharedRef()); + ChildBuilder.AddChildProperty(StructPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FMovieSceneSequencePlaybackSettings, bHidePlayer)).ToSharedRef()); + ChildBuilder.AddChildProperty(StructPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FMovieSceneSequencePlaybackSettings, bHideHud)).ToSharedRef()); } diff --git a/Engine/Source/Editor/DetailCustomizations/Private/PhysicsConstraintComponentDetails.cpp b/Engine/Source/Editor/DetailCustomizations/Private/PhysicsConstraintComponentDetails.cpp index 91ff1212133e..d2dfbbbefb1c 100644 --- a/Engine/Source/Editor/DetailCustomizations/Private/PhysicsConstraintComponentDetails.cpp +++ b/Engine/Source/Editor/DetailCustomizations/Private/PhysicsConstraintComponentDetails.cpp @@ -36,7 +36,7 @@ namespace ConstraintDetails { bool bIsEnabled = false; - if (Prop->GetValue(bIsEnabled)) + if (Prop->GetValue(bIsEnabled) == FPropertyAccess::Result::Success) { return bIsEnabled; } @@ -51,14 +51,14 @@ namespace ConstraintDetails TargetWidget->SetEnabled(TAttribute::Create(TAttribute::FGetter::CreateLambda([StoreCheckProperty]() { bool bSet; - if (StoreCheckProperty->GetValue(bSet)) + if (StoreCheckProperty->GetValue(bSet) == FPropertyAccess::Result::Success) { return bSet; } return false; }))); - + return SNew(SHorizontalBox) + SHorizontalBox::Slot() .AutoWidth() @@ -81,13 +81,12 @@ namespace ConstraintDetails // and will cause GetValue to fail. Skip checking the values in that case. if (Prop1->GetNumPerObjectValues()) { - UE_LOG(LogTemp, Warning, TEXT("Running Get")); float Val1, Val2, Val3; ensure(Prop1->GetValue(Val1) != FPropertyAccess::Fail); ensure(Prop2->GetValue(Val2) != FPropertyAccess::Fail); ensure(Prop3->GetValue(Val3) != FPropertyAccess::Fail); - + if (Val1 == Val2 && Val2 == Val3) { return TOptional(Val1); @@ -106,7 +105,7 @@ namespace ConstraintDetails // This prevents an issue where multiple sets fail when using BlueprintComponents // due to RerunConstructionScripts destroying the edit list. FScopedTransaction Transaction(TransactionName); - ensure(Prop1->SetValue(NewValue)); + ensure(Prop1->SetValue(NewValue) == FPropertyAccess::Result::Success); } }; @@ -147,7 +146,7 @@ namespace ConstraintDetails bool IsAngularPropertyEqual(TSharedPtr Prop, EAngularConstraintMotion CheckMotion) { uint8 Val; - if (Prop->GetValue(Val)) + if (Prop->GetValue(Val) == FPropertyAccess::Result::Success) { return Val == CheckMotion; } @@ -177,7 +176,7 @@ void FPhysicsConstraintComponentDetails::AddConstraintBehaviorProperties(IDetail ConstraintCat.AddProperty(ProfilePropertiesProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FConstraintProfileProperties, bDisableCollision))); ConstraintCat.AddProperty(ProfilePropertiesProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FConstraintProfileProperties, bEnableProjection))); - + //Add the rest uint32 NumProfileProperties = 0; ProfilePropertiesProperty->GetNumChildren(NumProfileProperties); @@ -284,11 +283,13 @@ void FPhysicsConstraintComponentDetails::AddLinearLimits(IDetailLayoutBuilder& D ] ]; } - + auto IsLinearMotionLimited = [LinearXMotionProperty, LinearYMotionProperty, LinearZMotionProperty]() { uint8 XMotion, YMotion, ZMotion; - if (LinearXMotionProperty->GetValue(XMotion) && LinearYMotionProperty->GetValue(YMotion) && LinearZMotionProperty->GetValue(ZMotion)) + if (LinearXMotionProperty->GetValue(XMotion) == FPropertyAccess::Result::Success && + LinearYMotionProperty->GetValue(YMotion) == FPropertyAccess::Result::Success && + LinearZMotionProperty->GetValue(ZMotion) == FPropertyAccess::Result::Success) { return XMotion == LCM_Limited || YMotion == LCM_Limited || ZMotion == LCM_Limited; } @@ -462,9 +463,9 @@ void FPhysicsConstraintComponentDetails::AddLinearDrive(IDetailLayoutBuilder& De TSharedPtr LinearDriveProperty = ProfilePropertiesProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FConstraintProfileProperties, LinearDrive)); IDetailGroup& PositionGroup = LinearMotorCat.AddGroup("Linear Position Drive", LOCTEXT("LinearPositionDrive", "Linear Position Drive"), false, true); - + TSharedRef LinearPositionTargetProperty = LinearDriveProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLinearDriveConstraint, PositionTarget)).ToSharedRef(); - + TSharedPtr XDriveProperty = LinearDriveProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLinearDriveConstraint, XDrive)); TSharedPtr YDriveProperty = LinearDriveProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLinearDriveConstraint, YDrive)); TSharedPtr ZDriveProperty = LinearDriveProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLinearDriveConstraint, ZDrive)); @@ -520,7 +521,7 @@ void FPhysicsConstraintComponentDetails::AddLinearDrive(IDetailLayoutBuilder& De [ StiffnessWidget ]; - + // VELOCITY IDetailGroup& VelocityGroup = LinearMotorCat.AddGroup("Linear Velocity Drive", LOCTEXT("LinearVelocityDrive", "Linear Velocity Drive"), false, true); @@ -613,11 +614,11 @@ void FPhysicsConstraintComponentDetails::AddAngularDrive(IDetailLayoutBuilder& D TSharedPtr SwingVelocityDriveProperty = SwingDriveProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FConstraintDrive, bEnableVelocityDrive)); TSharedPtr TwistPositionDriveProperty = TwistDriveProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FConstraintDrive, bEnablePositionDrive)); TSharedPtr TwistVelocityDriveProperty = TwistDriveProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FConstraintDrive, bEnableVelocityDrive)); - + auto IsAngularMode = [AngularDriveModeProperty](EAngularDriveMode::Type CheckMode) { uint8 DriveMode; - if (AngularDriveModeProperty->GetValue(DriveMode)) + if (AngularDriveModeProperty->GetValue(DriveMode) == FPropertyAccess::Result::Success) { return DriveMode == CheckMode; } @@ -665,7 +666,7 @@ void FPhysicsConstraintComponentDetails::AddAngularDrive(IDetailLayoutBuilder& D { return VelocityEnabled() || OrientationEnabled(); }; - + AngularMotorCat.AddProperty(AngularDriveModeProperty); IDetailGroup& OrientationGroup = AngularMotorCat.AddGroup("Orientation Drive", LOCTEXT("OrientrationDrive", "Orientation Drive"), false, true); @@ -820,7 +821,7 @@ void FPhysicsConstraintComponentDetails::AddAngularDrive(IDetailLayoutBuilder& D [ DampingSlerpWidget ]; - + // max force limit TSharedPtr MaxForcePropertySlerp = SlerpDriveProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FConstraintDrive, MaxForce)); TSharedRef MaxForceWidget = ConstraintDetails::CreateTriFloatWidget(MaxForcePropertySlerp, TwistDriveProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FConstraintDrive, MaxForce)), SwingDriveProperty->GetChildHandle(GET_MEMBER_NAME_CHECKED(FConstraintDrive, MaxForce)), LOCTEXT("EditMaxForce", "Edit Max Force")); @@ -836,7 +837,7 @@ void FPhysicsConstraintComponentDetails::AddAngularDrive(IDetailLayoutBuilder& D MaxForceWidget ]; - + } void FPhysicsConstraintComponentDetails::CustomizeDetails( IDetailLayoutBuilder& DetailBuilder ) @@ -871,13 +872,13 @@ void FPhysicsConstraintComponentDetails::CustomizeDetails( IDetailLayoutBuilder& DetailBuilder.EditCategory("Constraint"); //Create this category first so it's at the top DetailBuilder.EditCategory("Constraint Behavior"); //Create this category first so it's at the top - + TSharedPtr ProfileInstance = ConstraintInstance->GetChildHandle(GET_MEMBER_NAME_CHECKED(FConstraintInstance, ProfileInstance)); AddLinearLimits(DetailBuilder, ConstraintInstance, ProfileInstance); AddAngularLimits(DetailBuilder, ConstraintInstance, ProfileInstance); AddLinearDrive(DetailBuilder, ConstraintInstance, ProfileInstance); AddAngularDrive(DetailBuilder, ConstraintInstance, ProfileInstance); - + AddConstraintBehaviorProperties(DetailBuilder, ConstraintInstance, ProfileInstance); //Now we've added all the complex UI, just dump the rest into Constraint category } @@ -903,7 +904,7 @@ bool FPhysicsConstraintComponentDetails::IsPropertyEnabled( EPropertyType::Type case EPropertyType::AngularSwingLimit: return ConstraintDetails::IsAngularPropertyEqual(AngularSwing1MotionProperty, ACM_Limited) || ConstraintDetails::IsAngularPropertyEqual(AngularSwing2MotionProperty, ACM_Limited); case EPropertyType::AngularTwistLimit: return ConstraintDetails::IsAngularPropertyEqual(AngularTwistMotionProperty, ACM_Limited); case EPropertyType::AngularAnyLimit: return ConstraintDetails::IsAngularPropertyEqual(AngularSwing1MotionProperty, ACM_Limited) || ConstraintDetails::IsAngularPropertyEqual(AngularSwing2MotionProperty, ACM_Limited) || ConstraintDetails::IsAngularPropertyEqual(AngularTwistMotionProperty, ACM_Limited); - } + } return bIsVisible; } @@ -911,7 +912,7 @@ bool FPhysicsConstraintComponentDetails::IsPropertyEnabled( EPropertyType::Type ECheckBoxState FPhysicsConstraintComponentDetails::IsLimitRadioChecked( TSharedPtr Property, uint8 Value ) const { uint8 PropertyEnumValue = 0; - if (Property.IsValid() && Property->GetValue(PropertyEnumValue)) + if (Property.IsValid() && Property->GetValue(PropertyEnumValue) == FPropertyAccess::Result::Success) { return PropertyEnumValue == Value ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; } diff --git a/Engine/Source/Editor/DetailCustomizations/Private/SkeletonNotifyDetails.cpp b/Engine/Source/Editor/DetailCustomizations/Private/SkeletonNotifyDetails.cpp index 4c97c0dacdd0..4a7a3b4edec6 100644 --- a/Engine/Source/Editor/DetailCustomizations/Private/SkeletonNotifyDetails.cpp +++ b/Engine/Source/Editor/DetailCustomizations/Private/SkeletonNotifyDetails.cpp @@ -35,7 +35,7 @@ void FSkeletonNotifyDetails::CustomizeDetails( IDetailLayoutBuilder& DetailBuild UEditorSkeletonNotifyObj* EdObj = NULL; for(int i = 0; i < SelectedObjects.Num(); ++i) { - UObject* Obj = SelectedObjects[0].Get(); + UObject* Obj = SelectedObjects[i].Get(); EdObj = Cast(Obj); if(EdObj) { diff --git a/Engine/Source/Editor/DetailCustomizations/Private/SkyLightComponentDetails.cpp b/Engine/Source/Editor/DetailCustomizations/Private/SkyLightComponentDetails.cpp index 43bc6c452e3f..cc899d737e81 100644 --- a/Engine/Source/Editor/DetailCustomizations/Private/SkyLightComponentDetails.cpp +++ b/Engine/Source/Editor/DetailCustomizations/Private/SkyLightComponentDetails.cpp @@ -14,7 +14,6 @@ #include "DetailWidgetRow.h" #include "DetailCategoryBuilder.h" #include "IDetailsView.h" -#include "Editor.h" #define LOCTEXT_NAMESPACE "SkyLightComponentDetails" @@ -84,20 +83,11 @@ void FSkyLightComponentDetails::CustomizeDetails( IDetailLayoutBuilder& DetailLa FReply FSkyLightComponentDetails::OnUpdateSkyCapture() { - if( SkyLight.IsValid() ) + if (SkyLight.IsValid()) { if (UWorld* SkyLightWorld = SkyLight->GetWorld()) { - const ERHIFeatureLevel::Type ActiveFeatureLevel = SkyLightWorld->FeatureLevel; - if (ActiveFeatureLevel < ERHIFeatureLevel::SM4 && GMaxRHIFeatureLevel >= ERHIFeatureLevel::SM4) - { - // Trigger a switch to GMaxRHIFeatureLevel for a full reflection capture update (including sky) if we're in mobile preview. - GEditor->UpdateReflectionCaptures(SkyLightWorld); - } - else - { - SkyLightWorld->UpdateAllSkyCaptures(); - } + SkyLightWorld->UpdateAllSkyCaptures(); } } diff --git a/Engine/Source/Editor/DetailCustomizations/Private/SoundBaseDetails.cpp b/Engine/Source/Editor/DetailCustomizations/Private/SoundBaseDetails.cpp index e04379912c7a..ec370edd768b 100644 --- a/Engine/Source/Editor/DetailCustomizations/Private/SoundBaseDetails.cpp +++ b/Engine/Source/Editor/DetailCustomizations/Private/SoundBaseDetails.cpp @@ -2,7 +2,7 @@ #include "SoundBaseDetails.h" #include "Sound/SoundBase.h" -#include "Settings/EditorExperimentalSettings.h" +#include "Classes/Sound/AudioSettings.h" #include "PropertyHandle.h" #include "DetailLayoutBuilder.h" @@ -13,7 +13,7 @@ TSharedRef FSoundBaseDetails::MakeInstance() void FSoundBaseDetails::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) { - if (!GetDefault()->bShowAudioMixerData) + if (!GetDefault()->IsAudioMixerEnabled()) { TSharedRef Property = DetailBuilder.GetProperty("SoundSubmixObject", USoundBase::StaticClass()); Property->MarkHiddenByCustomization(); diff --git a/Engine/Source/Editor/EditorLiveStreaming/EditorLiveStreaming.Build.cs b/Engine/Source/Editor/EditorLiveStreaming/EditorLiveStreaming.Build.cs deleted file mode 100644 index 979eaa2ff308..000000000000 --- a/Engine/Source/Editor/EditorLiveStreaming/EditorLiveStreaming.Build.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -namespace UnrealBuildTool.Rules -{ - public class EditorLiveStreaming : ModuleRules - { - public EditorLiveStreaming( ReadOnlyTargetRules Target ) : base(Target) - { - PublicDependencyModuleNames.AddRange( - new string[] - { - "Core", - } - ); - - PrivateDependencyModuleNames.AddRange( - new string[] - { - "CoreUObject", - "Engine", - "Slate", - "SlateCore", - "UnrealEd", - } - ); - - DynamicallyLoadedModuleNames.AddRange( - new string[] - { - "Settings", - "MainFrame", - "GameLiveStreaming" - } - ); - - PrivateIncludePathModuleNames.AddRange( - new string[] - { - "Settings", - "MainFrame" - } - ); - } - } -} diff --git a/Engine/Source/Editor/EditorLiveStreaming/EditorLiveStreaming.cpp b/Engine/Source/Editor/EditorLiveStreaming/EditorLiveStreaming.cpp deleted file mode 100644 index 20468e587184..000000000000 --- a/Engine/Source/Editor/EditorLiveStreaming/EditorLiveStreaming.cpp +++ /dev/null @@ -1,450 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "EditorLiveStreaming.h" -#include "Framework/Application/SlateApplication.h" -#include "Widgets/Images/SImage.h" -#include "Settings/EditorExperimentalSettings.h" -#include "Engine/Texture2D.h" -#include "EditorLiveStreamingSettings.h" -#include "Features/IModularFeatures.h" -#include "Features/ILiveStreamingService.h" -#include "Interfaces/IMainFrameModule.h" -#include "Runtime/GameLiveStreaming/Public/IGameLiveStreaming.h" -#include "ISettingsModule.h" -#include "Framework/Notifications/NotificationManager.h" -#include "Widgets/Notifications/SNotificationList.h" - - -IMPLEMENT_MODULE( FEditorLiveStreaming, EditorLiveStreaming ); - -#define LOCTEXT_NAMESPACE "EditorLiveStreaming" - - -FEditorLiveStreaming::FEditorLiveStreaming() - : bIsBroadcasting( false ), - LiveStreamer( nullptr ), - SubmittedVideoFrameCount( 0 ), - ReadbackBufferIndex( 0 ) -{ - ReadbackBuffers[0].Reset(); - ReadbackBuffers[1].Reset(); -} - - -void FEditorLiveStreaming::StartupModule() -{ - // Register settings - ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings"); - - if( ensure( SettingsModule != nullptr ) ) - { - SettingsModule->RegisterSettings( "Editor", "Advanced", "EditorLiveStreaming", - LOCTEXT( "EditorLiveStreamingSettingsName", "Live Streaming"), - LOCTEXT( "EditorLiveStreamingSettingsDescription", "Settings for broadcasting live from the editor"), - GetMutableDefault< UEditorLiveStreamingSettings >() - ); - } -} - - -void FEditorLiveStreaming::ShutdownModule() -{ - // Unregister settings - ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings"); - - if( SettingsModule != nullptr ) - { - SettingsModule->UnregisterSettings( "Editor", "General", "EditorLiveStreaming" ); - } -} - - -bool FEditorLiveStreaming::IsLiveStreamingAvailable() const -{ - bool bIsAvailable = false; - - // This feature is currently "experimental" and disabled by default, even if you have a valid live streaming plugin installed - if( GetDefault()->bLiveStreamingFromEditor ) - { - // We are not available if the game is already streaming - if( !IGameLiveStreaming::Get().IsBroadcastingGame() ) - { - static const FName LiveStreamingFeatureName( "LiveStreaming" ); - if( IModularFeatures::Get().IsModularFeatureAvailable( LiveStreamingFeatureName ) ) - { - // Only if not already broadcasting - bIsAvailable = true; - } - } - } - - return bIsAvailable; -} - - -bool FEditorLiveStreaming::IsBroadcastingEditor() const -{ - return bIsBroadcasting; -} - - -void FEditorLiveStreaming::StartBroadcastingEditor() -{ - if( !IsBroadcastingEditor() && IsLiveStreamingAvailable() ) - { - // Select a live streaming service - { - static const FName LiveStreamingFeatureName( "LiveStreaming" ); - LiveStreamer = &IModularFeatures::Get().GetModularFeature( LiveStreamingFeatureName ); - } - - // Register to find out about status changes - LiveStreamer->OnStatusChanged().AddRaw( this, &FEditorLiveStreaming::BroadcastStatusCallback ); - - // @todo livestream: Allow connection to chat independently from broadcasting? (see removing delegate too) - LiveStreamer->OnChatMessage().AddRaw( this, &FEditorLiveStreaming::OnChatMessage ); - - - // Tell our live streaming plugin to start broadcasting - { - const auto& Settings = *GetDefault< UEditorLiveStreamingSettings >(); - FSlateRenderer* SlateRenderer = FSlateApplication::Get().GetRenderer().Get(); - const FIntRect VirtualScreen = SlateRenderer->SetupVirtualScreenBuffer( Settings.bPrimaryMonitorOnly, Settings.ScreenScaling, LiveStreamer ); - - bIsBroadcasting = true; - SubmittedVideoFrameCount = 0; - - // @todo livestream: What about if virtual screen size changes while we are still broadcasting? For example, if the user changes their - // desktop resolution while the editor is running. We'd need to stop and restart the broadcast. - FBroadcastConfig BroadcastConfig; - BroadcastConfig.VideoBufferWidth = VirtualScreen.Width(); - BroadcastConfig.VideoBufferHeight = VirtualScreen.Height(); - BroadcastConfig.FramesPerSecond = Settings.FrameRate; - BroadcastConfig.PixelFormat = FBroadcastConfig::EBroadcastPixelFormat::R8G8B8A8; - BroadcastConfig.bCaptureAudioFromComputer = Settings.bCaptureAudioFromComputer; - BroadcastConfig.bCaptureAudioFromMicrophone = Settings.bCaptureAudioFromMicrophone; - LiveStreamer->StartBroadcasting( BroadcastConfig ); - - if( Settings.bEnableWebCam ) - { - FWebCamConfig WebCamConfig; - switch( Settings.WebCamResolution ) - { - case EEditorLiveStreamingWebCamResolution::Normal_320x240: - WebCamConfig.DesiredWebCamWidth = 320; - WebCamConfig.DesiredWebCamHeight = 240; - break; - case EEditorLiveStreamingWebCamResolution::Wide_320x180: - WebCamConfig.DesiredWebCamWidth = 320; - WebCamConfig.DesiredWebCamHeight = 180; - break; - case EEditorLiveStreamingWebCamResolution::Normal_640x480: - WebCamConfig.DesiredWebCamWidth = 640; - WebCamConfig.DesiredWebCamHeight = 480; - break; - case EEditorLiveStreamingWebCamResolution::Wide_640x360: - WebCamConfig.DesiredWebCamWidth = 640; - WebCamConfig.DesiredWebCamHeight = 360; - break; - case EEditorLiveStreamingWebCamResolution::Normal_800x600: - WebCamConfig.DesiredWebCamWidth = 800; - WebCamConfig.DesiredWebCamHeight = 600; - break; - case EEditorLiveStreamingWebCamResolution::Wide_800x450: - WebCamConfig.DesiredWebCamWidth = 800; - WebCamConfig.DesiredWebCamHeight = 450; - break; - case EEditorLiveStreamingWebCamResolution::Normal_1024x768: - WebCamConfig.DesiredWebCamWidth = 1024; - WebCamConfig.DesiredWebCamHeight = 768; - break; - case EEditorLiveStreamingWebCamResolution::Wide_1024x576: - WebCamConfig.DesiredWebCamWidth = 1024; - WebCamConfig.DesiredWebCamHeight = 576; - break; - case EEditorLiveStreamingWebCamResolution::Normal_1080x810: - WebCamConfig.DesiredWebCamWidth = 1080; - WebCamConfig.DesiredWebCamHeight = 810; - break; - case EEditorLiveStreamingWebCamResolution::Wide_1080x720: - WebCamConfig.DesiredWebCamWidth = 1080; - WebCamConfig.DesiredWebCamHeight = 720; - break; - case EEditorLiveStreamingWebCamResolution::Normal_1280x960: - WebCamConfig.DesiredWebCamWidth = 1280; - WebCamConfig.DesiredWebCamHeight = 960; - break; - case EEditorLiveStreamingWebCamResolution::Wide_1280x720: - WebCamConfig.DesiredWebCamWidth = 1280; - WebCamConfig.DesiredWebCamHeight = 720; - break; - case EEditorLiveStreamingWebCamResolution::Normal_1920x1440: - WebCamConfig.DesiredWebCamWidth = 1920; - WebCamConfig.DesiredWebCamHeight = 1440; - break; - case EEditorLiveStreamingWebCamResolution::Wide_1920x1080: - WebCamConfig.DesiredWebCamWidth = 1920; - WebCamConfig.DesiredWebCamHeight = 1080; - break; - - default: - check(0); - break; - } - - // @todo livestream: Allow web cam to be started/stopped independently from the broadcast itself, so users can setup their web cam - LiveStreamer->StartWebCam( WebCamConfig ); - } - } - } -} - - -void FEditorLiveStreaming::StopBroadcastingEditor() -{ - if( IsBroadcastingEditor() ) - { - CloseBroadcastStatusWindow(); - - LiveStreamer->StopWebCam(); - LiveStreamer->StopBroadcasting(); - - // Unregister for status changes - LiveStreamer->OnStatusChanged().RemoveAll( this ); - LiveStreamer->OnChatMessage().RemoveAll( this ); - - LiveStreamer = nullptr; - - // Tell our notification to start expiring - TSharedPtr< SNotificationItem > Notification( NotificationWeakPtr.Pin() ); - if( Notification.IsValid() ) - { - Notification->ExpireAndFadeout(); - } - - bIsBroadcasting = false; - for( int32 BufferIndex = 0; BufferIndex < 2; ++BufferIndex ) - { - ReadbackBuffers[BufferIndex].Reset(); - } - ReadbackBufferIndex = 0; - SubmittedVideoFrameCount = 0; - } -} - - -void FEditorLiveStreaming::BroadcastEditorVideoFrame() -{ - if( ensure( IsBroadcastingEditor() ) ) - { - // Check to see if we're streaming live video. If so, we'll want to push new frames to be broadcast. - if( LiveStreamer->IsBroadcasting() ) - { - // Is this live streamer ready to accept new frames? - if( LiveStreamer->IsReadyForVideoFrames() ) - { - FSlateRenderer* SlateRenderer = FSlateApplication::Get().GetRenderer().Get(); - - const FMappedTextureBuffer& CurrentBuffer = ReadbackBuffers[ReadbackBufferIndex]; - - if ( CurrentBuffer.IsValid() ) - { - //TODO PushVideoFrame Needs to Take Width and Height - LiveStreamer->PushVideoFrame((FColor*)CurrentBuffer.Data/*, CurrentBuffer.Width, CurrentBuffer.Height*/); - ++SubmittedVideoFrameCount; - - // If this is the first frame we've submitted, then we can fade out our notification UI, since broadcasting is in progress - if( SubmittedVideoFrameCount == 1 ) - { - TSharedPtr< SNotificationItem > Notification( NotificationWeakPtr.Pin() ); - if( Notification.IsValid() ) - { - Notification->ExpireAndFadeout(); - } - } - - SlateRenderer->UnmapVirtualScreenBuffer(); - } - - TArray UnusedKeypressBuffer; - SlateRenderer->CopyWindowsToVirtualScreenBuffer( UnusedKeypressBuffer ); - SlateRenderer->MapVirtualScreenBuffer(&ReadbackBuffers[ReadbackBufferIndex]); - - // Ping pong between buffers - ReadbackBufferIndex = ( ReadbackBufferIndex + 1 ) % 2; - } - } - else - { - // If our streaming service has stopped broadcasting for some reason, then we'll cancel our broadcast - StopBroadcastingEditor(); - } - } -} - - -void FEditorLiveStreaming::BroadcastStatusCallback( const FLiveStreamingStatus& Status ) -{ - TSharedPtr< SNotificationItem > Notification( NotificationWeakPtr.Pin() ); - if( Notification.IsValid() ) - { - // Don't bother clobbering existing message with text about web cam starting/stopping, unless we're already broadcasting. - // We want to make sure people see the persistent text about login state. - if( SubmittedVideoFrameCount > 0 || - ( Status.StatusType != FLiveStreamingStatus::EStatusType::WebCamStarted && - Status.StatusType != FLiveStreamingStatus::EStatusType::WebCamStopped && - Status.StatusType != FLiveStreamingStatus::EStatusType::WebCamTextureNotReady && - Status.StatusType != FLiveStreamingStatus::EStatusType::WebCamTextureReady && - Status.StatusType != FLiveStreamingStatus::EStatusType::ChatConnected && - Status.StatusType != FLiveStreamingStatus::EStatusType::ChatDisconnected ) ) - { - Notification->SetText( Status.CustomStatusDescription ); - } - } - else - { - // Only spawn a notification if we're actually still trying to broadcast, not if we're stopping broadcasting. We don't want - // to revive our notification that we intentionally expired. - if( bIsBroadcasting ) - { - FNotificationInfo Info( Status.CustomStatusDescription ); - Info.FadeInDuration = 0.1f; - Info.FadeOutDuration = 0.5f; - Info.ExpireDuration = 1.5f; - Info.bUseThrobber = false; - Info.bUseSuccessFailIcons = true; - Info.bUseLargeFont = true; - Info.bFireAndForget = false; - Info.bAllowThrottleWhenFrameRateIsLow = false; - NotificationWeakPtr = FSlateNotificationManager::Get().AddNotification( Info ); - } - } - - Notification = NotificationWeakPtr.Pin(); - if( Notification.IsValid() ) - { - SNotificationItem::ECompletionState State = SNotificationItem::CS_Pending; - if( Status.StatusType == FLiveStreamingStatus::EStatusType::Failure ) - { - State = SNotificationItem::CS_Fail; - } - else if( Status.StatusType == FLiveStreamingStatus::EStatusType::BroadcastStarted || - Status.StatusType == FLiveStreamingStatus::EStatusType::WebCamStarted || - Status.StatusType == FLiveStreamingStatus::EStatusType::ChatConnected ) - { - State = SNotificationItem::CS_Success; - } - - Notification->SetCompletionState( State ); - } - - // If the web cam just turned on, then we'll go ahead and show it - if( Status.StatusType == FLiveStreamingStatus::EStatusType::WebCamTextureReady ) - { - bool bIsImageFlippedHorizontally = false; - bool bIsImageFlippedVertically = false; - UTexture2D* WebCamTexture = LiveStreamer->GetWebCamTexture( bIsImageFlippedHorizontally, bIsImageFlippedVertically ); - if( ensure( WebCamTexture != nullptr ) ) - { - IMainFrameModule& MainFrameModule = FModuleManager::LoadModuleChecked( TEXT( "MainFrame" ) ); - check( MainFrameModule.IsWindowInitialized() ); - auto RootWindow = MainFrameModule.GetParentWindow(); - check( RootWindow.IsValid() ); - - // Allow the user to customize the image mirroring, too! - const auto& Settings = *GetDefault< UEditorLiveStreamingSettings >(); - if( Settings.bMirrorWebCamImage ) - { - bIsImageFlippedHorizontally = !bIsImageFlippedHorizontally; - } - - // How many pixels from the edge of the main frame window to where the broadcast status window appears - const int WindowBorderPadding = 50; - - // @todo livestream: Currently this window is not created as "topmost". We don't really want it to be OS-topmost, but we do want it to be the most - // topmost "regular" window in our application (not on top of tooltips, etc.) - - // Create a window that will show the web cam video feed - BroadcastStatusWindow = SNew( SWindow ) - .Title( LOCTEXT( "StreamingWindowTitle", "Web Camera" ) ) - .ClientSize( FVector2D( WebCamTexture->GetSizeX(), WebCamTexture->GetSizeY() ) ) - .ScreenPosition( FVector2D( - RootWindow->GetRectInScreen().Right - WebCamTexture->GetSizeX() - WindowBorderPadding, - RootWindow->GetRectInScreen().Top + WindowBorderPadding ) ) - - // @todo livestream: Ideally the user could freely resize the window, but it gets a bit tricky to preserve the web cam aspect. Plus, we don't really like how letterboxing/columnboxing looks with this. - .SizingRule( ESizingRule::FixedSize ) - - .AutoCenter( EAutoCenter::None ) - .bDragAnywhere( true ) - .SupportsMaximize( true ) - .SupportsMinimize( true ) - .FocusWhenFirstShown( false ) - .ActivationPolicy( EWindowActivationPolicy::Never ) - .SaneWindowPlacement( false ); - - WebCamDynamicImageBrush = MakeShareable( new FSlateDynamicImageBrush( - WebCamTexture, - FVector2D( WebCamTexture->GetSizeX(), WebCamTexture->GetSizeY() ), - WebCamTexture->GetFName() ) ); - - // If the web cam image is coming in flipped, we'll apply mirroring to the Slate brush - if( bIsImageFlippedHorizontally && bIsImageFlippedVertically ) - { - WebCamDynamicImageBrush->Mirroring = ESlateBrushMirrorType::Both; - } - else if( bIsImageFlippedHorizontally ) - { - WebCamDynamicImageBrush->Mirroring = ESlateBrushMirrorType::Horizontal; - } - else if( bIsImageFlippedVertically ) - { - WebCamDynamicImageBrush->Mirroring = ESlateBrushMirrorType::Vertical; - } - - // @todo livestream: Currently if the user closes the window, the camera is deactivated and it doesn't turn back on unless the broadcast is restarted. We could allow the camera to be reactivated though. - BroadcastStatusWindow->SetOnWindowClosed( - FOnWindowClosed::CreateStatic( []( const TSharedRef& Window, FEditorLiveStreaming* This ) - { - // User closed the broadcast status window, so go ahead and shut down the web cam - This->LiveStreamer->StopWebCam(); - This->BroadcastStatusWindow.Reset(); - This->WebCamDynamicImageBrush.Reset(); - }, - this ) ); - - BroadcastStatusWindow->SetContent( - SNew( SImage ) - .Image( WebCamDynamicImageBrush.Get() ) - ); - - FSlateApplication::Get().AddWindowAsNativeChild( - BroadcastStatusWindow.ToSharedRef(), - RootWindow.ToSharedRef() ); - } - - } - else if( Status.StatusType == FLiveStreamingStatus::EStatusType::WebCamTextureNotReady ) - { - CloseBroadcastStatusWindow(); - } -} - - -void FEditorLiveStreaming::CloseBroadcastStatusWindow() -{ - if( BroadcastStatusWindow.IsValid() ) - { - FSlateApplication::Get().DestroyWindowImmediately( BroadcastStatusWindow.ToSharedRef() ); - BroadcastStatusWindow.Reset(); - WebCamDynamicImageBrush.Reset(); - } -} - - -void FEditorLiveStreaming::OnChatMessage( const FText& UserName, const FText& ChatMessage ) -{ - // @todo livestream: Currently no chat UI is supported in the editor -} - - -#undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Editor/EditorLiveStreaming/EditorLiveStreaming.h b/Engine/Source/Editor/EditorLiveStreaming/EditorLiveStreaming.h deleted file mode 100644 index a5a87587d991..000000000000 --- a/Engine/Source/Editor/EditorLiveStreaming/EditorLiveStreaming.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#pragma once - -#include "CoreMinimal.h" -#include "SlateFwd.h" -#include "Brushes/SlateDynamicImageBrush.h" -#include "Rendering/SlateRenderer.h" -#include "Widgets/SWindow.h" -#include "IEditorLiveStreaming.h" - -/** - * Handles broadcasting of the editor to a live internet stream - */ -class FEditorLiveStreaming - : public IEditorLiveStreaming -{ - -public: - - /** Default constructor */ - FEditorLiveStreaming(); - - /** IModuleInterface overrides */ - virtual void StartupModule() override; - virtual void ShutdownModule() override; - - /** IEditorLiveStreaming overrides */ - virtual bool IsLiveStreamingAvailable() const override; - virtual bool IsBroadcastingEditor() const override; - virtual void StartBroadcastingEditor() override; - virtual void StopBroadcastingEditor() override; - virtual void BroadcastEditorVideoFrame() override; - -protected: - - /** Called by the live streaming service when streaming status has changed or an error has occurred */ - void BroadcastStatusCallback( const struct FLiveStreamingStatus& Status ); - - /** Closes the window that shows the current status of the broadcast */ - void CloseBroadcastStatusWindow(); - - /** Called by the live streaming service when we get a new chat message to display */ - void OnChatMessage( const FText& UserName, const FText& ChatMessage ); - - -private: - - /** True if we're currently broadcasting anything */ - bool bIsBroadcasting; - - /** The live streaming implementation we're using for editor broadcasting */ - class ILiveStreamingService* LiveStreamer; - - /** Number of video frames we've submitted since we started broadcasting */ - uint32 SubmittedVideoFrameCount; - - /** A temporary pair of buffers that we write our video frames to */ - FMappedTextureBuffer ReadbackBuffers[2]; - - /** The current buffer index. We bounce between them to avoid stalls. */ - int32 ReadbackBufferIndex; - - /** Persistent Slate notification for live streaming status */ - TWeakPtr< class SNotificationItem > NotificationWeakPtr; - - /** Dynamic slate image brush for our web cam texture */ - TSharedPtr< struct FSlateDynamicImageBrush > WebCamDynamicImageBrush; - - /** Window for broadcast status */ - TSharedPtr< class SWindow > BroadcastStatusWindow; -}; diff --git a/Engine/Source/Editor/EditorLiveStreaming/EditorLiveStreamingSettings.cpp b/Engine/Source/Editor/EditorLiveStreaming/EditorLiveStreamingSettings.cpp deleted file mode 100644 index 0506ae981cd6..000000000000 --- a/Engine/Source/Editor/EditorLiveStreaming/EditorLiveStreamingSettings.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "EditorLiveStreamingSettings.h" -#include "UObject/UnrealType.h" - - -UEditorLiveStreamingSettings::UEditorLiveStreamingSettings( const FObjectInitializer& ObjectInitializer ) - : Super( ObjectInitializer ) -{ -} - - -void UEditorLiveStreamingSettings::PostEditChangeProperty( struct FPropertyChangedEvent& PropertyChangedEvent ) -{ - UProperty* PropertyThatChanged = PropertyChangedEvent.Property; - - const FName Name = PropertyThatChanged ? PropertyThatChanged->GetFName() : NAME_None; -// if( Name == ??? ) -// { -// ... -// } - - this->SaveConfig(); -} diff --git a/Engine/Source/Editor/EditorLiveStreaming/EditorLiveStreamingSettings.h b/Engine/Source/Editor/EditorLiveStreaming/EditorLiveStreamingSettings.h deleted file mode 100644 index 0b58655c4cf4..000000000000 --- a/Engine/Source/Editor/EditorLiveStreaming/EditorLiveStreamingSettings.h +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "CoreMinimal.h" -#include "UObject/ObjectMacros.h" -#include "UObject/Object.h" -#include "EditorLiveStreamingSettings.generated.h" - -/** Describes the available preset resolutions for web camera video with the editor's live streaming feature */ -UENUM() -namespace EEditorLiveStreamingWebCamResolution -{ - enum Type - { - Normal_320x240 UMETA( DisplayName="320 x 240 (4:3)" ), - Wide_320x180 UMETA( DisplayName="320 x 180 (16:9)" ), - - Normal_640x480 UMETA( DisplayName="640 x 480 (4:3)" ), - Wide_640x360 UMETA( DisplayName="640 x 360 (16:9)" ), - - Normal_800x600 UMETA( DisplayName="800 x 600 (4:3)" ), - Wide_800x450 UMETA( DisplayName="800 x 450 (16:9)" ), - - Normal_1024x768 UMETA( DisplayName="1024 x 768 (4:3)" ), - Wide_1024x576 UMETA( DisplayName="1024 x 576 (16:9)" ), - - Normal_1080x810 UMETA( DisplayName="1080 x 810 (4:3)" ), - Wide_1080x720 UMETA( DisplayName="1080 x 720 (16:9)" ), - - Normal_1280x960 UMETA( DisplayName="1280 x 960 (4:3)" ), - Wide_1280x720 UMETA( DisplayName="1280 x 720 (16:9, 720p)" ), - - Normal_1920x1440 UMETA( DisplayName="1920 x 1440 (4:3)" ), - Wide_1920x1080 UMETA( DisplayName="1920 x 1080 (16:9, 1080p)" ), - }; -} - - -/** Holds preferences for the editor live streaming features */ -UCLASS(config=EditorSettings) -class UEditorLiveStreamingSettings : public UObject -{ - GENERATED_UCLASS_BODY() - -public: - - /** Frame rate to stream video from the editor at when broadcasting to services like Twitch. */ - UPROPERTY(Config, EditAnywhere, Category=EditorLiveStreaming, Meta=(UIMin=5,ClampMin=1,UIMax=60)) - int32 FrameRate; - - /** How much to scale the broadcast video resolution down to reduce streaming bandwidth. We recommend broadcasting at resolutions of 1280x720 or lower. Some live streaming providers will not be able to transcode your video to a lower resolution, so using a high resolution stream may prevent low-bandwidth users from having a good viewing experience.*/ - UPROPERTY(Config, EditAnywhere, Category=EditorLiveStreaming, Meta=(ClampMin=0.1,ClampMax=1.0)) - float ScreenScaling; - - /** By default, we only broadcast video from your primary monitor's work area (excludes the task bar area.) Turning off this feature enables broadcasting from all monitors, covering your entire usable desktop area. This may greatly increase the video resolution of your stream, so we recommend leaving this option turned off. */ - UPROPERTY(Config, EditAnywhere, Category=EditorLiveStreaming ) - bool bPrimaryMonitorOnly; - - /** If enabled, video from your web camera will be captured and displayed in the editor while broadcasting, so that your viewers can see your presence. */ - UPROPERTY(Config, EditAnywhere, Category=EditorLiveStreaming ) - bool bEnableWebCam; - - /** The camera video resolution that you'd prefer. The camera may not support the exact resolution you specify, so we'll try to find the best match automatically */ - UPROPERTY(Config, EditAnywhere, Category=EditorLiveStreaming, Meta=(EditCondition="bEnableWebCam") ) - TEnumAsByte WebCamResolution; - - /** You can enable this to flip the web cam image horizontally so that it looks more like a mirror */ - UPROPERTY(Config, EditAnywhere, Category=EditorLiveStreaming ) - bool bMirrorWebCamImage; - - /** Enables broadcast of audio being played by your computer, such as in-game sounds */ - UPROPERTY(Config, EditAnywhere, Category=EditorLiveStreaming ) - bool bCaptureAudioFromComputer; - - /** Enables broadcast of audio from your default microphone recording device */ - UPROPERTY(Config, EditAnywhere, Category=EditorLiveStreaming ) - bool bCaptureAudioFromMicrophone; - - -protected: - - /** UObject overrides */ - virtual void PostEditChangeProperty( struct FPropertyChangedEvent& PropertyChangedEvent) override; -}; - - diff --git a/Engine/Source/Editor/EditorLiveStreaming/Public/IEditorLiveStreaming.h b/Engine/Source/Editor/EditorLiveStreaming/Public/IEditorLiveStreaming.h deleted file mode 100644 index bb7187cc3455..000000000000 --- a/Engine/Source/Editor/EditorLiveStreaming/Public/IEditorLiveStreaming.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#pragma once - -#include "CoreMinimal.h" -#include "Modules/ModuleInterface.h" -#include "Modules/ModuleManager.h" - - -/** - * Interface to the EditorLiveStreaming module's functionality that enables live broadcasting of video and audio from editor sessions - */ -class IEditorLiveStreaming - : public IModuleInterface -{ - -public: - - /** - * Checks to see if live streaming is currently available for the editor - * - * @return True if live streaming is possible to start - */ - virtual bool IsLiveStreamingAvailable() const = 0; - - /** - * Returns true if we're currently broadcasting - * - * @return True if broadcasting is currently active - */ - virtual bool IsBroadcastingEditor() const = 0; - - /** Starts broadcasting frames */ - virtual void StartBroadcastingEditor() = 0; - - /** Stops broadcasting frames */ - virtual void StopBroadcastingEditor() = 0; - - /** Pushes latest video from the editor to a live stream. The editor's rendering system will call this each frame. */ - virtual void BroadcastEditorVideoFrame() = 0; - - -public: - - /** - * Singleton-like access to IEditorLiveStreaming - * - * @return Returns instance of IEditorLiveStreaming object - */ - static inline IEditorLiveStreaming& Get() - { - static FName LiveStreamingModule("EditorLiveStreaming"); - - return FModuleManager::LoadModuleChecked< IEditorLiveStreaming >( LiveStreamingModule ); - } - -}; - - diff --git a/Engine/Source/Editor/EditorStyle/Private/EditorStyleClasses.cpp b/Engine/Source/Editor/EditorStyle/Private/EditorStyleClasses.cpp index 21f8e6718877..f567f455c0ce 100644 --- a/Engine/Source/Editor/EditorStyle/Private/EditorStyleClasses.cpp +++ b/Engine/Source/Editor/EditorStyle/Private/EditorStyleClasses.cpp @@ -21,6 +21,7 @@ UEditorStyleSettings::UEditorStyleSettings( const FObjectInitializer& ObjectInit EditorWindowBackgroundColor = FLinearColor::White; AssetEditorOpenLocation = EAssetEditorOpenLocation::Default; + bEnableColorizedEditorTabs = true; bUseGrid = true; diff --git a/Engine/Source/Editor/EditorStyle/Private/SlateEditorStyle.cpp b/Engine/Source/Editor/EditorStyle/Private/SlateEditorStyle.cpp index 1e0e1cb97f0d..9c1d929e601f 100644 --- a/Engine/Source/Editor/EditorStyle/Private/SlateEditorStyle.cpp +++ b/Engine/Source/Editor/EditorStyle/Private/SlateEditorStyle.cpp @@ -365,6 +365,7 @@ void FSlateEditorStyle::FStyle::SetupGeneralStyles() Set( "Symbols.DoubleUpArrow", new IMAGE_BRUSH( "Common/UpArrow2", Icon8x8 ) ); Set( "Symbols.DownArrow", new IMAGE_BRUSH( "Common/DownArrow", Icon8x8 ) ); Set( "Symbols.DoubleDownArrow", new IMAGE_BRUSH( "Common/DownArrow2", Icon8x8 ) ); + Set( "Symbols.RightArrow", new IMAGE_BRUSH("Common/SubmenuArrow", Icon8x8)); Set( "Symbols.Check", new IMAGE_BRUSH( "Common/Check", Icon16x16 ) ); } @@ -1393,6 +1394,10 @@ void FSlateEditorStyle::FStyle::SetupGeneralStyles() Set( "WorldBrowser.DetailsButtonBrush", new IMAGE_BRUSH( "Icons/icon_levels_detailsbutton_40x", Icon16x16 ) ); Set( "WorldBrowser.CompositionButtonBrush", new IMAGE_BRUSH( "Icons/icon_levels_compositionbutton_16x", Icon16x16 ) ); + Set( "WorldBrowser.FolderClosed", new IMAGE_BRUSH( "Icons/FolderClosed", Icon16x16 ) ); + Set( "WorldBrowser.FolderOpen", new IMAGE_BRUSH( "Icons/FolderOpen", Icon16x16 ) ); + Set( "WorldBrowser.NewFolderIcon", new IMAGE_BRUSH( "Icons/icon_AddFolder_16x", Icon16x16 ) ); + Set( "WorldBrowser.StatusBarText", FTextBlockStyle(NormalText) .SetFont( TTF_FONT( "Fonts/Roboto-BoldCondensed", 12 ) ) .SetColorAndOpacity( FLinearColor(0.9, 0.9f, 0.9f, 0.5f) ) @@ -2017,23 +2022,6 @@ void FSlateEditorStyle::FStyle::SetupGeneralStyles() } #endif // WITH_EDITOR || IS_PROGRAM - // Crash Tracker - { - Set( "CrashTracker", FTextBlockStyle(NormalText) - .SetFont( TTF_CORE_FONT( "Fonts/Roboto-Bold", 18 ) ) - .SetShadowOffset( FVector2D::ZeroVector ) ); - - Set( "CrashTracker.Cursor", new IMAGE_BRUSH( "Common/MouseCursor", Icon32x32, FLinearColor(1,1,1,1), ESlateBrushTileType::Both ) ); - Set( "CrashTracker.Record", new IMAGE_BRUSH( "Animation/Record", Icon20x20 ) ); - } - -#if WITH_EDITOR || IS_PROGRAM - // Editor live streaming - { - Set( "EditorLiveStreaming.BroadcastButton", new IMAGE_BRUSH( "Animation/Record", Icon20x20 ) ); - } - -#endif // WITH_EDITOR || IS_PROGRAM #if WITH_EDITOR // Surface Props @@ -2949,7 +2937,7 @@ void FSlateEditorStyle::FStyle::SetupDockingStyles() // Legacy styles used by other editor specific widgets; see "Docking.MajorTab" in FCoreStyle for the current tab style Set( "Docking.MajorTab.Normal", new BOX_BRUSH( "/Docking/AppTab_Inactive", FMargin(24.0f/64.0f, 4/32.0f) ) ); Set( "Docking.MajorTab.Active", new BOX_BRUSH( "/Docking/AppTab_Active", FMargin(24.0f/64.0f, 4/32.0f) ) ); - Set( "Docking.MajorTab.ColorOverlay", new BOX_BRUSH( "/Docking/AppTab_ColorOverlay", FMargin(24.0f/64.0f, 4/32.0f) ) ); + Set( "Docking.MajorTab.ColorOverlay", new BOX_BRUSH( "/Docking/AppTab_ColorOverlayIcon", FMargin(24.0f/64.0f, 4/32.0f) ) ); Set( "Docking.MajorTab.Foreground", new BOX_BRUSH( "/Docking/AppTab_Foreground", FMargin(24.0f/64.0f, 4/32.0f) ) ); Set( "Docking.MajorTab.Hovered", new BOX_BRUSH( "/Docking/AppTab_Hovered", FMargin(24.0f/64.0f, 4/32.0f) ) ); Set( "Docking.MajorTab.Padding", FMargin(17, 4, 15, 4) ); @@ -4662,8 +4650,11 @@ void FSlateEditorStyle::FStyle::SetupLevelEditorStyle() Set( "LevelEditor.MeshPaintMode.Selected.Small", new IMAGE_BRUSH( "Icons/icon_Mode_Meshpaint_selected_40x", Icon20x20 ) ); Set("LevelEditor.MeshPaintMode.TexturePaint", new IMAGE_BRUSH("Icons/TexturePaint_40x", Icon40x40)); + Set("LevelEditor.MeshPaintMode.TexturePaint.Small", new IMAGE_BRUSH("Icons/TexturePaint_40x", Icon20x20)); Set("LevelEditor.MeshPaintMode.ColorPaint", new IMAGE_BRUSH("Icons/VertexColorPaint_40x", Icon40x40)); + Set("LevelEditor.MeshPaintMode.ColorPaint.Small", new IMAGE_BRUSH("Icons/VertexColorPaint_40x", Icon20x20)); Set("LevelEditor.MeshPaintMode.WeightPaint", new IMAGE_BRUSH("Icons/WeightPaint_40x", Icon40x40)); + Set("LevelEditor.MeshPaintMode.WeightPaint.Small", new IMAGE_BRUSH("Icons/WeightPaint_40x", Icon20x20)); Set( "LevelEditor.LandscapeMode", new IMAGE_BRUSH( "Icons/icon_Mode_Landscape_40x", Icon40x40 ) ); Set( "LevelEditor.LandscapeMode.Small", new IMAGE_BRUSH( "Icons/icon_Mode_Landscape_40x", Icon20x20 ) ); @@ -5475,6 +5466,9 @@ void FSlateEditorStyle::FStyle::SetupPersonaStyle() Set( "Kismet.AllClasses.VariableIcon", new IMAGE_BRUSH( "/Icons/pill_16x", Icon16x16 ) ); Set( "Kismet.AllClasses.ArrayVariableIcon", new IMAGE_BRUSH( "/Icons/pillarray_16x", Icon16x16 ) ); + Set( "Kismet.AllClasses.SetVariableIcon", new IMAGE_BRUSH( "/Icons/pillset_16x", Icon16x16 ) ); + Set( "Kismet.AllClasses.MapValueVariableIcon", new IMAGE_BRUSH( "/Icons/pillmapvalue_16x", Icon16x16 ) ); + Set( "Kismet.AllClasses.MapKeyVariableIcon", new IMAGE_BRUSH( "/Icons/pillmapkey_16x", Icon16x16 ) ); Set( "Kismet.AllClasses.FunctionIcon", new IMAGE_BRUSH( "/Icons/icon_BluePrintEditor_Function_16px", Icon16x16 ) ); Set( "BlueprintEditor.ResetCamera", new IMAGE_BRUSH( "Icons/icon_Camera_Reset_40px", Icon16x16)); @@ -7115,6 +7109,9 @@ void FSlateEditorStyle::FStyle::SetupAutomationStyles() Set("FBXIcon.ReimportSameContent", new IMAGE_BRUSH("Icons/FBX/FbxReimportSameContent_16x16px", Icon16x16)); Set("FBXIcon.ReimportError", new IMAGE_BRUSH("Icons/FBX/FbxReimportError_16x16px", Icon16x16)); + Set("FBXIcon.ReimportCompareAdd", new IMAGE_BRUSH("Icons/FBX/FbxReimportCompare-Add_16x16px", Icon16x16)); + Set("FBXIcon.ReimportCompareRemoved", new IMAGE_BRUSH("Icons/FBX/FbxReimportCompare-Remove_16x16px", Icon16x16)); + const FTextBlockStyle FBXLargeFont = FTextBlockStyle(NormalText) .SetFont(TTF_CORE_FONT("Fonts/Roboto-Regular", 12)) @@ -7160,6 +7157,8 @@ void FSlateEditorStyle::FStyle::SetupUMGEditorStyles() Set("WidgetDesigner.RenderTransform.Small", new IMAGE_BRUSH("Icons/UMG/Render_TransformMode_16x", Icon16x16)); Set("WidgetDesigner.ToggleOutlines", new IMAGE_BRUSH("Icons/UMG/ToggleOutlines.Small", Icon16x16)); Set("WidgetDesigner.ToggleOutlines.Small", new IMAGE_BRUSH("Icons/UMG/ToggleOutlines.Small", Icon16x16)); + Set("WidgetDesigner.ToggleRespectLocks", new IMAGE_BRUSH("Icons/UMG/ToggleRespectLocks.Small", Icon16x16)); + Set("WidgetDesigner.ToggleRespectLocks.Small", new IMAGE_BRUSH("Icons/UMG/ToggleRespectLocks.Small", Icon16x16)); Set("WidgetDesigner.LocationGridSnap", new IMAGE_BRUSH("Old/LevelEditor/LocationGridSnap", Icon14x14, IconColor)); Set("WidgetDesigner.RotationGridSnap", new IMAGE_BRUSH("Old/LevelEditor/RotationGridSnap", Icon14x14, IconColor)); diff --git a/Engine/Source/Editor/EditorStyle/Public/Classes/EditorStyleSettings.h b/Engine/Source/Editor/EditorStyle/Public/Classes/EditorStyleSettings.h index c5a7f60ca9f6..6299dbb2428d 100644 --- a/Engine/Source/Editor/EditorStyle/Public/Classes/EditorStyleSettings.h +++ b/Engine/Source/Editor/EditorStyle/Public/Classes/EditorStyleSettings.h @@ -187,6 +187,10 @@ public: UPROPERTY(EditAnywhere, config, Category=UserInterface) EAssetEditorOpenLocation AssetEditorOpenLocation; + /** Should editor tabs be colorized according to the asset type */ + UPROPERTY(EditAnywhere, config, Category=UserInterface) + uint32 bEnableColorizedEditorTabs : 1; + public: /** diff --git a/Engine/Source/Editor/EditorWidgets/Private/SAssetDropTarget.cpp b/Engine/Source/Editor/EditorWidgets/Private/SAssetDropTarget.cpp index 2ecd2d259cb3..d5cec607acab 100644 --- a/Engine/Source/Editor/EditorWidgets/Private/SAssetDropTarget.cpp +++ b/Engine/Source/Editor/EditorWidgets/Private/SAssetDropTarget.cpp @@ -74,12 +74,13 @@ UObject* SAssetDropTarget::GetDroppedObject(TSharedPtr DragD { bOutRecognizedEvent = true; TSharedPtr DragDropOp = StaticCastSharedPtr(DragDropOperation); + const TArray& DroppedAssets = DragDropOp->GetAssets(); - bool bCanDrop = DragDropOp->AssetData.Num() == 1; + bool bCanDrop = DroppedAssets.Num() == 1; if( bCanDrop ) { - const FAssetData& AssetData = DragDropOp->AssetData[0]; + const FAssetData& AssetData = DroppedAssets[0]; // Make sure the asset is loaded DroppedObject = AssetData.GetAsset(); diff --git a/Engine/Source/Editor/EnvironmentQueryEditor/Private/EnvironmentQueryGraphNode_Option.cpp b/Engine/Source/Editor/EnvironmentQueryEditor/Private/EnvironmentQueryGraphNode_Option.cpp index c494fdc0cb82..7fa40d13b8da 100644 --- a/Engine/Source/Editor/EnvironmentQueryEditor/Private/EnvironmentQueryGraphNode_Option.cpp +++ b/Engine/Source/Editor/EnvironmentQueryEditor/Private/EnvironmentQueryGraphNode_Option.cpp @@ -21,7 +21,7 @@ UEnvironmentQueryGraphNode_Option::UEnvironmentQueryGraphNode_Option(const FObje void UEnvironmentQueryGraphNode_Option::AllocateDefaultPins() { - UEdGraphPin* Inputs = CreatePin(EGPD_Input, TEXT("Transition"), TEXT(""), NULL, false, false, TEXT("Out")); + UEdGraphPin* Inputs = CreatePin(EGPD_Input, TEXT("Transition"), FString(), nullptr, TEXT("Out")); } void UEnvironmentQueryGraphNode_Option::PostPlacedNewNode() @@ -161,7 +161,7 @@ void UEnvironmentQueryGraphNode_Option::UpdateNodeData() { CompositeGenerator->VerifyItemTypes(); - ErrorMessage = CompositeGenerator->bHasMatchingItemType ? TEXT("") : LOCTEXT("NestedGeneratorMismatch", "Nested generators must work on exactly the same item types!").ToString(); + ErrorMessage = CompositeGenerator->bHasMatchingItemType ? FString() : LOCTEXT("NestedGeneratorMismatch", "Nested generators must work on exactly the same item types!").ToString(); } } diff --git a/Engine/Source/Editor/EnvironmentQueryEditor/Private/EnvironmentQueryGraphNode_Root.cpp b/Engine/Source/Editor/EnvironmentQueryEditor/Private/EnvironmentQueryGraphNode_Root.cpp index 5f2f808e6646..9ce1a94a4e56 100644 --- a/Engine/Source/Editor/EnvironmentQueryEditor/Private/EnvironmentQueryGraphNode_Root.cpp +++ b/Engine/Source/Editor/EnvironmentQueryEditor/Private/EnvironmentQueryGraphNode_Root.cpp @@ -9,7 +9,7 @@ UEnvironmentQueryGraphNode_Root::UEnvironmentQueryGraphNode_Root(const FObjectIn void UEnvironmentQueryGraphNode_Root::AllocateDefaultPins() { - UEdGraphPin* Outputs = CreatePin(EGPD_Output, TEXT("Transition"), TEXT(""), NULL, false, false, TEXT("In")); + UEdGraphPin* Outputs = CreatePin(EGPD_Output, TEXT("Transition"), FString(), nullptr, TEXT("In")); } FText UEnvironmentQueryGraphNode_Root::GetNodeTitle(ENodeTitleType::Type TitleType) const diff --git a/Engine/Source/Editor/FoliageEdit/Private/ActorFactoryProceduralFoliage.cpp b/Engine/Source/Editor/FoliageEdit/Private/ActorFactoryProceduralFoliage.cpp index f8bcb41726bb..c1fc5b31bdf9 100644 --- a/Engine/Source/Editor/FoliageEdit/Private/ActorFactoryProceduralFoliage.cpp +++ b/Engine/Source/Editor/FoliageEdit/Private/ActorFactoryProceduralFoliage.cpp @@ -11,8 +11,6 @@ ActorFactory.cpp: #include "ProceduralFoliageComponent.h" #include "AssetData.h" -DEFINE_LOG_CATEGORY_STATIC(LogActorFactory, Log, All); - #define LOCTEXT_NAMESPACE "ActorFactoryProceduralFoliage" /*----------------------------------------------------------------------------- diff --git a/Engine/Source/Editor/FoliageEdit/Private/FoliageEdMode.cpp b/Engine/Source/Editor/FoliageEdit/Private/FoliageEdMode.cpp index ee14da3cb66e..690cd75403ef 100644 --- a/Engine/Source/Editor/FoliageEdit/Private/FoliageEdMode.cpp +++ b/Engine/Source/Editor/FoliageEdit/Private/FoliageEdMode.cpp @@ -47,6 +47,9 @@ #include "VREditorMode.h" #include "ViewportWorldInteraction.h" #include "VREditorInteractor.h" +#include "LevelUtils.h" +#include "SNotificationList.h" +#include "NotificationManager.h" #define LOCTEXT_NAMESPACE "FoliageEdMode" @@ -347,6 +350,8 @@ void FEdModeFoliage::Enter() ApplySelectionToComponents(GetWorld(), true); } + TArray InstanceFoliageActorList; + // Subscribe to mesh changed events (for existing and future IFA's) UWorld* World = GetWorld(); OnActorSpawnedHandle = World->AddOnActorSpawnedHandler(FOnActorSpawned::FDelegate::CreateRaw(this, &FEdModeFoliage::HandleOnActorSpawned)); @@ -357,9 +362,12 @@ void FEdModeFoliage::Enter() if (Level && Level->bIsVisible) { AInstancedFoliageActor* IFA = AInstancedFoliageActor::GetInstancedFoliageActorForLevel(Level); + if (IFA) { IFA->OnFoliageTypeMeshChanged().AddSP(this, &FEdModeFoliage::HandleOnFoliageTypeMeshChanged); + + InstanceFoliageActorList.Add(IFA); } } } @@ -367,6 +375,22 @@ void FEdModeFoliage::Enter() // Update UI NotifyNewCurrentLevel(); + // Make sure we're up to date and register static mesh bounds changes + for (FFoliageMeshUIInfoPtr MeshUIInfo : FoliageMeshList) + { + for (AInstancedFoliageActor* Actor : InstanceFoliageActorList) + { + FFoliageMeshInfo* MeshInfo = Actor->FindMesh(MeshUIInfo->Settings); + + if (MeshInfo != nullptr && MeshInfo->Component != nullptr) + { + MeshInfo->Component->GetStaticMesh()->GetOnExtendedBoundsChanged().AddRaw(MeshInfo, &FFoliageMeshInfo::HandleComponentMeshBoundsChanged); + + MeshInfo->Component->BuildTreeIfOutdated(true, true); + } + } + } + // Register for VR input events UViewportWorldInteraction* ViewportWorldInteraction = Cast( GEditor->GetEditorWorldExtensionsManager()->GetEditorWorldExtensions( GetWorld() )->FindExtension( UViewportWorldInteraction::StaticClass() ) ); if (ViewportWorldInteraction != nullptr) @@ -423,7 +447,6 @@ void FEdModeFoliage::Exit() GEditor->OnObjectsReplaced().RemoveAll(this); - FoliageMeshList.Empty(); // Remove the brush SphereBrushComponent->UnregisterComponent(); @@ -443,6 +466,8 @@ void FEdModeFoliage::Exit() ApplySelectionToComponents(GetWorld(), false); // Remove all event subscriptions + TArray InstanceFoliageActorList; + UWorld* World = GetWorld(); World->RemoveOnActorSpawnedHandler(OnActorSpawnedHandle); const int32 NumLevels = World->GetNumLevels(); @@ -455,10 +480,28 @@ void FEdModeFoliage::Exit() if (IFA) { IFA->OnFoliageTypeMeshChanged().RemoveAll(this); + + InstanceFoliageActorList.Add(IFA); } } } + // Make sure we're up to date and register static mesh bounds changes + for (FFoliageMeshUIInfoPtr MeshUIInfo : FoliageMeshList) + { + for (AInstancedFoliageActor* Actor : InstanceFoliageActorList) + { + FFoliageMeshInfo* MeshInfo = Actor->FindMesh(MeshUIInfo->Settings); + + if (MeshInfo != nullptr && MeshInfo->Component != nullptr) + { + MeshInfo->Component->GetStaticMesh()->GetOnExtendedBoundsChanged().RemoveAll(MeshInfo); + } + } + } + + FoliageMeshList.Empty(); + // Call base Exit method to ensure proper cleanup FEdMode::Exit(); } @@ -776,6 +819,8 @@ void FEdModeFoliage::Tick(FEditorViewportClient* ViewportClient, float DeltaTime } } +static TArray CurrentFoliageTraceBrushAffectedLevels; + void FEdModeFoliage::StartFoliageBrushTrace(FEditorViewportClient* ViewportClient, class UViewportInteractor* Interactor) { if (!bToolActive) @@ -806,6 +851,20 @@ void FEdModeFoliage::EndFoliageBrushTrace() LandscapeLayerCaches.Empty(); bToolActive = false; bBrushTraceValid = false; + + for (auto& FoliageMeshUI : FoliageMeshList) + { + UFoliageType* Settings = FoliageMeshUI->Settings; + + if (!Settings->IsSelected) + { + continue; + } + + RebuildFoliageTree(Settings); + } + + CurrentFoliageTraceBrushAffectedLevels.Empty(); } /** Trace and update brush position */ @@ -827,7 +886,7 @@ void FEdModeFoliage::FoliageBrushTrace(FEditorViewportClient* ViewportClient, co if (AInstancedFoliageActor::FoliageTrace(World, Hit, FDesiredFoliageInstance(TraceStart, TraceEnd), NAME_FoliageBrush, false, FilterFunc)) { UPrimitiveComponent* PrimComp = Hit.Component.Get(); - if (CanPaint(PrimComp->GetComponentLevel())) + if (PrimComp != nullptr && CanPaint(PrimComp->GetComponentLevel())) { if (!bAdjustBrushRadius) { @@ -1293,12 +1352,32 @@ static void SpawnFoliageInstance(UWorld* InWorld, const UFoliageType* Settings, { // We always spawn instances in base component level ULevel* TargetLevel = (UISettings != nullptr && UISettings->GetIsInSpawnInCurrentLevelMode()) ? InWorld->GetCurrentLevel() : BaseComponent->GetComponentLevel(); + CurrentFoliageTraceBrushAffectedLevels.AddUnique(TargetLevel); + AInstancedFoliageActor* IFA = AInstancedFoliageActor::GetInstancedFoliageActorForLevel(TargetLevel, true); FFoliageMeshInfo* MeshInfo; UFoliageType* FoliageSettings = IFA->AddFoliageType(Settings, &MeshInfo); - MeshInfo->AddInstance(IFA, FoliageSettings, Instance, BaseComponent); + MeshInfo->AddInstance(IFA, FoliageSettings, Instance, BaseComponent, false); +} + +void FEdModeFoliage::RebuildFoliageTree(const UFoliageType* Settings) +{ + for (ULevel* AffectedLevel : CurrentFoliageTraceBrushAffectedLevels) + { + AInstancedFoliageActor* IFA = AInstancedFoliageActor::GetInstancedFoliageActorForLevel(AffectedLevel, false); + + if (IFA != nullptr) + { + FFoliageMeshInfo* MeshInfo = IFA->FindMesh(Settings); + + if (MeshInfo != nullptr && MeshInfo->Component != nullptr) + { + MeshInfo->Component->BuildTreeIfOutdated(true, false); + } + } + } } void FEdModeFoliage::AddInstancesImp(UWorld* InWorld, const UFoliageType* Settings, const TArray& DesiredInstances, const TArray& ExistingInstanceBuckets, const float Pressure, LandscapeLayerCacheData* LandscapeLayerCachesPtr, const FFoliageUISettings* UISettings, const FFoliagePaintingGeometryFilter* OverrideGeometryFilter) @@ -1486,7 +1565,9 @@ void FEdModeFoliage::RemoveInstancesForBrush(UWorld* InWorld, const UFoliageType // Remove PotentialInstancesToRemove to reduce it to desired count if (PotentialInstancesToRemove.Num() > 0) { - MeshInfo->RemoveInstances(IFA, PotentialInstancesToRemove); + CurrentFoliageTraceBrushAffectedLevels.AddUnique(IFA->GetLevel()); + + MeshInfo->RemoveInstances(IFA, PotentialInstancesToRemove, false); } } } @@ -1697,7 +1778,7 @@ void FEdModeFoliage::RemoveSelectedInstances(UWorld* InWorld) if (Mesh.SelectedIndices.Num() > 0) { TArray InstancesToDelete = Mesh.SelectedIndices.Array(); - Mesh.RemoveInstances(IFA, InstancesToDelete); + Mesh.RemoveInstances(IFA, InstancesToDelete, true); OnInstanceCountUpdated(MeshPair.Key); } @@ -1718,8 +1799,7 @@ void FEdModeFoliage::SelectInvalidInstances(const UFoliageType* Settings) { UWorld* InWorld = GetWorld(); - static FName NAME_FoliageGroundCheck = FName("FoliageGroundCheck"); - FCollisionQueryParams QueryParams(NAME_FoliageGroundCheck, true); + FCollisionQueryParams QueryParams(SCENE_QUERY_STAT(FoliageGroundCheck), true); QueryParams.bReturnFaceIndex = false; FCollisionShape SphereShape; SphereShape.SetSphere(0.f); @@ -2105,7 +2185,7 @@ void FEdModeFoliage::ReapplyInstancesForBrush(UWorld* InWorld, AInstancedFoliage FVector End = Instance.Location - FVector(0.f, 0.f, 16.f); if (AInstancedFoliageActor::FoliageTrace(InWorld, Hit, FDesiredFoliageInstance(Start, End), NAME_ReapplyInstancesForBrush)) { - if (!AInstancedFoliageActor::CheckCollisionWithWorld(InWorld, Settings, Instance, Hit.Normal, Hit.Location)) + if (!AInstancedFoliageActor::CheckCollisionWithWorld(InWorld, Settings, Instance, Hit.Normal, Hit.Location, Hit.Component.Get())) { InstancesToDelete.Add(InstanceIndex); continue; @@ -2132,7 +2212,7 @@ void FEdModeFoliage::ReapplyInstancesForBrush(UWorld* InWorld, AInstancedFoliage if (InstancesToDelete.Num()) { - MeshInfo->RemoveInstances(IFA, InstancesToDelete.Array()); + MeshInfo->RemoveInstances(IFA, InstancesToDelete.Array(), true); } } @@ -2378,7 +2458,7 @@ void FEdModeFoliage::ApplyPaintBucket_Add(AActor* Actor) const bool bHasColorData = bHasInstancedColorData || LODModel.ColorVertexBuffer.GetNumVertices(); // Get the raw triangle data for this static mesh - FTransform LocalToWorld = StaticMeshComponent->ComponentToWorld; + FTransform LocalToWorld = StaticMeshComponent->GetComponentTransform(); FIndexArrayView Indices = LODModel.IndexBuffer.GetArrayView(); const FPositionVertexBuffer& PositionVertexBuffer = LODModel.PositionVertexBuffer; const FColorVertexBuffer& ColorVertexBuffer = LODModel.ColorVertexBuffer; @@ -2493,6 +2573,8 @@ void FEdModeFoliage::ApplyPaintBucket_Add(AActor* Actor) } } + RebuildFoliageTree(Settings); + // OnInstanceCountUpdated(Settings); } @@ -2547,9 +2629,9 @@ bool FEdModeFoliage::GetStaticMeshVertexColorForHit(const UStaticMeshComponent* int32 Index2 = Indices[IndexBufferIdx + 2]; // Lookup the triangle world positions and colors. - FVector WorldVert0 = InStaticMeshComponent->ComponentToWorld.TransformPosition(PositionVertexBuffer.VertexPosition(Index0)); - FVector WorldVert1 = InStaticMeshComponent->ComponentToWorld.TransformPosition(PositionVertexBuffer.VertexPosition(Index1)); - FVector WorldVert2 = InStaticMeshComponent->ComponentToWorld.TransformPosition(PositionVertexBuffer.VertexPosition(Index2)); + FVector WorldVert0 = InStaticMeshComponent->GetComponentTransform().TransformPosition(PositionVertexBuffer.VertexPosition(Index0)); + FVector WorldVert1 = InStaticMeshComponent->GetComponentTransform().TransformPosition(PositionVertexBuffer.VertexPosition(Index1)); + FVector WorldVert2 = InStaticMeshComponent->GetComponentTransform().TransformPosition(PositionVertexBuffer.VertexPosition(Index2)); FLinearColor Color0; FLinearColor Color1; @@ -2892,6 +2974,86 @@ bool FEdModeFoliage::IsModifierButtonPressed(const FEditorViewportClient* Viewpo return IsShiftDown(ViewportClient->Viewport) || bIsModifierPressed; } +void FEdModeFoliage::MoveSelectedFoliageToLevel(ULevel* InTargetLevel) +{ + // Can't move into a locked level + if (FLevelUtils::IsLevelLocked(InTargetLevel)) + { + FNotificationInfo NotificatioInfo(NSLOCTEXT("UnrealEd", "CannotMoveFoliageIntoLockedLevel", "Cannot move the selected foliage into a locked level")); + NotificatioInfo.bUseThrobber = false; + FSlateNotificationManager::Get().AddNotification(NotificatioInfo)->SetCompletionState(SNotificationItem::CS_Fail); + return; + } + + // Get a world context + UWorld* World = InTargetLevel->OwningWorld; + bool PromptToMoveFoliageTypeToAsset = World->StreamingLevels.Num() > 0; + bool ShouldPopulateMeshList = false; + + const FScopedTransaction Transaction(NSLOCTEXT("UnrealEd", "MoveSelectedFoliageToSelectedLevel", "Move Selected Foliage to Level")); + + // Iterate over all foliage actors in the world and move selected instances to a foliage actor in the target level + const int32 NumLevels = World->GetNumLevels(); + for (int32 LevelIdx = 0; LevelIdx < NumLevels; ++LevelIdx) + { + ULevel* Level = World->GetLevel(LevelIdx); + if (Level != InTargetLevel) + { + AInstancedFoliageActor* IFA = AInstancedFoliageActor::GetInstancedFoliageActorForLevel(Level, /*bCreateIfNone*/ false); + + if (IFA && IFA->HasSelectedInstances()) + { + bool CanMoveInstanceType = true; + + // Make sure all our foliage type used by our selected instances are asset otherwise promote them to assets + TMap SelectedInstanceFoliageTypes = IFA->GetSelectedInstancesFoliageType(); + + for (auto& MeshPair : SelectedInstanceFoliageTypes) + { + if (!MeshPair.Key->IsAsset()) + { + // Keep previous selection + TSet PreviousSelectionSet = MeshPair.Value->SelectedIndices; + TArray PreviousSelectionArray; + PreviousSelectionArray.Reserve(PreviousSelectionSet.Num()); + + for (int32& Value : PreviousSelectionSet) + { + PreviousSelectionArray.Add(Value); + } + + UFoliageType* NewFoliageType = SaveFoliageTypeObject(MeshPair.Key); + CanMoveInstanceType = NewFoliageType != nullptr; + + if (NewFoliageType != nullptr) + { + // Restore previous selection for move operation + FFoliageMeshInfo* MeshInfo = IFA->FindMesh(NewFoliageType); + MeshInfo->SelectInstances(IFA, true, PreviousSelectionArray); + } + } + } + + // Update our actor if we saved some foliage type as asset + if (CanMoveInstanceType) + { + IFA = AInstancedFoliageActor::GetInstancedFoliageActorForLevel(Level, /*bCreateIfNone*/ false); + ensure(IFA != nullptr && IFA->HasSelectedInstances()); + + IFA->MoveSelectedInstancesToLevel(InTargetLevel); + ShouldPopulateMeshList = true; + } + } + } + } + + // Update foliage usages + if (ShouldPopulateMeshList) + { + PopulateFoliageMeshList(); + } +} + UFoliageType* FEdModeFoliage::AddFoliageAsset(UObject* InAsset) { UFoliageType* FoliageType = nullptr; @@ -3013,7 +3175,7 @@ void FEdModeFoliage::BakeFoliage(UFoliageType* Settings, bool bSelectedOnly) } // Remove - MeshInfo->RemoveInstances(IFA, InstancesToConvert); + MeshInfo->RemoveInstances(IFA, InstancesToConvert, true); } } diff --git a/Engine/Source/Editor/FoliageEdit/Private/FoliageEdMode.h b/Engine/Source/Editor/FoliageEdit/Private/FoliageEdMode.h index 47602f0a65f9..94b45742a8a2 100644 --- a/Engine/Source/Editor/FoliageEdit/Private/FoliageEdMode.h +++ b/Engine/Source/Editor/FoliageEdit/Private/FoliageEdMode.h @@ -352,6 +352,9 @@ public: /** Notifies all active modes of mouse click messages. */ bool HandleClick(FEditorViewportClient* InViewportClient, HHitProxy *HitProxy, const FViewportClick &Click) override; + /** Moves selected foliage instances to the target level. */ + void MoveSelectedFoliageToLevel(ULevel* InTargetLevel); + /** FEdMode: widget handling */ virtual FVector GetWidgetLocation() const override; virtual bool AllowWidgetMove() override; @@ -562,6 +565,9 @@ private: /** Set the brush mesh opacity */ void SetBrushOpacity(const float InOpacity); + /** Called if the foliage tree is outdated */ + void RebuildFoliageTree(const UFoliageType* Settings); + bool bBrushTraceValid; FVector BrushLocation; FVector BrushNormal; diff --git a/Engine/Source/Editor/FoliageEdit/Private/FoliageEditModule.cpp b/Engine/Source/Editor/FoliageEdit/Private/FoliageEditModule.cpp index db1fd4db3394..f0da0e55839a 100644 --- a/Engine/Source/Editor/FoliageEdit/Private/FoliageEditModule.cpp +++ b/Engine/Source/Editor/FoliageEdit/Private/FoliageEditModule.cpp @@ -28,6 +28,7 @@ const FName FoliageEditAppIdentifier = FName(TEXT("FoliageEdApp")); #include "ProceduralFoliageBlockingVolume.h" #include "FoliageTypeObjectCustomization.h" #include "FoliageType_ISMThumbnailRenderer.h" +#include "EditorModeManager.h" /** * Foliage Edit Mode module @@ -164,6 +165,15 @@ public: } } + virtual void MoveSelectedFoliageToLevel(ULevel* InTargetLevel) override + { + ensure(GLevelEditorModeTools().IsModeActive(FBuiltinEditorModes::EM_Foliage)); + + FEdModeFoliage* FoliageMode = (FEdModeFoliage*)GLevelEditorModeTools().GetActiveMode(FBuiltinEditorModes::EM_Foliage); + + FoliageMode->MoveSelectedFoliageToLevel(InTargetLevel); + } + FDelegateHandle OnLevelActorDeletedDelegateHandle; FDelegateHandle OnExperimentalSettingChangedDelegateHandle; #endif diff --git a/Engine/Source/Editor/FoliageEdit/Public/FoliageEditModule.h b/Engine/Source/Editor/FoliageEdit/Public/FoliageEditModule.h index 86a0059c51c4..bef5f76aa16b 100644 --- a/Engine/Source/Editor/FoliageEdit/Public/FoliageEditModule.h +++ b/Engine/Source/Editor/FoliageEdit/Public/FoliageEditModule.h @@ -7,10 +7,17 @@ extern const FName FoliageEditAppIdentifier; +class ULevel; + /** * Foliage Edit mode module interface */ class IFoliageEditModule : public IModuleInterface { public: + +#if WITH_EDITOR + /** Move the selected foliage to the specified level */ + virtual void MoveSelectedFoliageToLevel(ULevel* InTargetLevel) = 0; +#endif }; diff --git a/Engine/Source/Editor/FontEditor/Private/SCompositeFontEditor.cpp b/Engine/Source/Editor/FontEditor/Private/SCompositeFontEditor.cpp index f48a164ee5b2..f08b4531ed87 100644 --- a/Engine/Source/Editor/FontEditor/Private/SCompositeFontEditor.cpp +++ b/Engine/Source/Editor/FontEditor/Private/SCompositeFontEditor.cpp @@ -1017,7 +1017,7 @@ void SSubTypefaceEditor::Construct(const FArguments& InArgs) .ListItemsSource(&CharacterRangeEntries) .SelectionMode(ESelectionMode::None) .ItemWidth(160) - .ItemHeight(120) + .ItemHeight(144) .ItemAlignment(EListItemAlignment::LeftAligned) .OnGenerateTile(this, &SSubTypefaceEditor::MakeCharacterRangesEntryWidget) ] @@ -1216,7 +1216,6 @@ TSharedRef SSubTypefaceEditor::MakeCharacterRangesEntryWidget(FCharac +SVerticalBox::Slot() .VAlign(VAlign_Center) - .HAlign(HAlign_Center) [ SNew(SCharacterRangeEditor) .CompositeFontEditor(CompositeFontEditorPtr) @@ -1324,74 +1323,128 @@ void SCharacterRangeEditor::Construct(const FArguments& InArgs) CompositeFontEditorPtr = InArgs._CompositeFontEditor; CharacterRange = InArgs._CharacterRange; + CacheCurrentRangeSelection(); + + // Copy the data so we can sort it by display name (it's usually ordered by ascending block range, and the sort happens when opening the combo) + TSharedPtr CurrentRangeSelectionItem; + { + TArrayView UnicodeBlockRanges = FUnicodeBlockRange::GetUnicodeBlockRanges(); + RangeSelectionComboData.Reserve(UnicodeBlockRanges.Num()); + for(const FUnicodeBlockRange& UnicodeBlockRange : UnicodeBlockRanges) + { + RangeSelectionComboData.Emplace(MakeShared(UnicodeBlockRange)); + + if(CurrentRangeSelection.IsSet() && CurrentRangeSelection->Range == UnicodeBlockRange.Range) + { + CurrentRangeSelectionItem = RangeSelectionComboData.Last(); + } + } + } + ChildSlot [ - SNew(SGridPanel) + SNew(SVerticalBox) - // Minimum column - +SGridPanel::Slot(0, 0) - .Padding(2.0f) + // Block selector + +SVerticalBox::Slot() + .AutoHeight() + .Padding(FMargin(0.0f, 2.0f)) [ - SNew(SEditableTextBox) - .Text(this, &SCharacterRangeEditor::GetRangeComponentAsTCHAR, 0) - .OnTextCommitted(this, &SCharacterRangeEditor::OnRangeComponentCommittedAsTCHAR, 0) - .ToolTipText(LOCTEXT("MinCharacterRangeEditCharTooltip", "Specifies the lower inclusive boundary of this character range as a literal unicode character.\nExample: If you wanted to use the range 'A-Z', this would be set to 'A'.")) + SAssignNew(RangeSelectionCombo, SComboBox>) + .OptionsSource(&RangeSelectionComboData) + .InitiallySelectedItem(CurrentRangeSelectionItem) + .ContentPadding(FMargin(4.0, 2.0)) + .OnComboBoxOpening(this, &SCharacterRangeEditor::OnRangeSelectionComboOpening) + .OnSelectionChanged(this, &SCharacterRangeEditor::OnRangeSelectionChanged) + .OnGenerateWidget(this, &SCharacterRangeEditor::MakeRangeSelectionWidget) + [ + SNew(STextBlock) + .Text(this, &SCharacterRangeEditor::GetCurrentRangeSelectionDisplayName) + .ToolTipText(this, &SCharacterRangeEditor::GetCurrentRangeSelectionDisplayName) + ] ] - +SGridPanel::Slot(0, 1) - .Padding(2.0f) + +SVerticalBox::Slot() [ - SNew(SEditableTextBox) - .Text(this, &SCharacterRangeEditor::GetRangeComponentAsHexString, 0) - .OnTextCommitted(this, &SCharacterRangeEditor::OnRangeComponentCommittedAsHexString, 0) - .ToolTipText(LOCTEXT("MinCharacterRangeEditHexTooltip", "Specifies the lower inclusive boundary of this character range as the hexadecimal value of a unicode character.\nExample: If you wanted to use the range '0x41-0x5A' (A-Z), this would be set to '0x41'.")) - ] + SNew(SHorizontalBox) - +SGridPanel::Slot(0, 2) - .Padding(2.0f) - [ - SNew(SNumericEntryBox) - .Value(this, &SCharacterRangeEditor::GetRangeComponentAsOptional, 0) - .OnValueCommitted(this, &SCharacterRangeEditor::OnRangeComponentCommittedAsNumeric, 0) - .ToolTipText(LOCTEXT("MinCharacterRangeEditDecTooltip", "Specifies the lower inclusive boundary of this character range as the decimal value of a unicode character.\nExample: If you wanted to use the range '65-90' (A-Z), this would be set to '65'.")) - ] + // Minimum column + +SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(SVerticalBox) - // Separator - +SGridPanel::Slot(1, 0) - .RowSpan(3) - .VAlign(VAlign_Center) - [ - SNew(STextBlock) - .Text(FText::FromString(TEXT(" - "))) - .Font(FEditorStyle::GetFontStyle("DetailsView.CategoryFontStyle")) - ] + +SVerticalBox::Slot() + .Padding(2.0f) + [ + SNew(SEditableTextBox) + .Text(this, &SCharacterRangeEditor::GetRangeComponentAsTCHAR, 0) + .OnTextCommitted(this, &SCharacterRangeEditor::OnRangeComponentCommittedAsTCHAR, 0) + .ToolTipText(LOCTEXT("MinCharacterRangeEditCharTooltip", "Specifies the lower inclusive boundary of this character range as a literal unicode character.\nExample: If you wanted to use the range 'A-Z', this would be set to 'A'.")) + ] - // Maximum column - +SGridPanel::Slot(2, 0) - .Padding(2.0f) - [ - SNew(SEditableTextBox) - .Text(this, &SCharacterRangeEditor::GetRangeComponentAsTCHAR, 1) - .OnTextCommitted(this, &SCharacterRangeEditor::OnRangeComponentCommittedAsTCHAR, 1) - .ToolTipText(LOCTEXT("MaxCharacterRangeEditCharTooltip", "Specifies the upper inclusive boundary of this character range as a literal unicode character.\nExample: If you wanted to use the range 'A-Z', this would be set to 'Z'.")) - ] + +SVerticalBox::Slot() + .Padding(2.0f) + [ + SNew(SEditableTextBox) + .Text(this, &SCharacterRangeEditor::GetRangeComponentAsHexString, 0) + .OnTextCommitted(this, &SCharacterRangeEditor::OnRangeComponentCommittedAsHexString, 0) + .ToolTipText(LOCTEXT("MinCharacterRangeEditHexTooltip", "Specifies the lower inclusive boundary of this character range as the hexadecimal value of a unicode character.\nExample: If you wanted to use the range '0x41-0x5A' (A-Z), this would be set to '0x41'.")) + ] - +SGridPanel::Slot(2, 1) - .Padding(2.0f) - [ - SNew(SEditableTextBox) - .Text(this, &SCharacterRangeEditor::GetRangeComponentAsHexString, 1) - .OnTextCommitted(this, &SCharacterRangeEditor::OnRangeComponentCommittedAsHexString, 1) - .ToolTipText(LOCTEXT("MaxCharacterRangeEditHexTooltip", "Specifies the upper inclusive boundary of this character range as the hexadecimal value of a unicode character.\nExample: If you wanted to use the range '0x41-0x5A' (A-Z), this would be set to '0x5A'.")) - ] + +SVerticalBox::Slot() + .Padding(2.0f) + [ + SNew(SNumericEntryBox) + .Value(this, &SCharacterRangeEditor::GetRangeComponentAsOptional, 0) + .OnValueCommitted(this, &SCharacterRangeEditor::OnRangeComponentCommittedAsNumeric, 0) + .ToolTipText(LOCTEXT("MinCharacterRangeEditDecTooltip", "Specifies the lower inclusive boundary of this character range as the decimal value of a unicode character.\nExample: If you wanted to use the range '65-90' (A-Z), this would be set to '65'.")) + ] + ] - +SGridPanel::Slot(2, 2) - .Padding(2.0f) - [ - SNew(SNumericEntryBox) - .Value(this, &SCharacterRangeEditor::GetRangeComponentAsOptional, 1) - .OnValueCommitted(this, &SCharacterRangeEditor::OnRangeComponentCommittedAsNumeric, 1) - .ToolTipText(LOCTEXT("MaxCharacterRangeEditDecTooltip", "Specifies the upper inclusive boundary of this character range as the decimal value of a unicode character.\nExample: If you wanted to use the range '65-90' (A-Z), this would be set to '90'.")) + // Separator + +SHorizontalBox::Slot() + .VAlign(VAlign_Center) + .HAlign(HAlign_Center) + [ + SNew(STextBlock) + .Text(FText::AsCultureInvariant(TEXT(" - "))) + .Font(FEditorStyle::GetFontStyle("DetailsView.CategoryFontStyle")) + ] + + // Maximum column + +SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(SVerticalBox) + + +SVerticalBox::Slot() + .Padding(2.0f) + [ + SNew(SEditableTextBox) + .Text(this, &SCharacterRangeEditor::GetRangeComponentAsTCHAR, 1) + .OnTextCommitted(this, &SCharacterRangeEditor::OnRangeComponentCommittedAsTCHAR, 1) + .ToolTipText(LOCTEXT("MaxCharacterRangeEditCharTooltip", "Specifies the upper inclusive boundary of this character range as a literal unicode character.\nExample: If you wanted to use the range 'A-Z', this would be set to 'Z'.")) + ] + + +SVerticalBox::Slot() + .Padding(2.0f) + [ + SNew(SEditableTextBox) + .Text(this, &SCharacterRangeEditor::GetRangeComponentAsHexString, 1) + .OnTextCommitted(this, &SCharacterRangeEditor::OnRangeComponentCommittedAsHexString, 1) + .ToolTipText(LOCTEXT("MaxCharacterRangeEditHexTooltip", "Specifies the upper inclusive boundary of this character range as the hexadecimal value of a unicode character.\nExample: If you wanted to use the range '0x41-0x5A' (A-Z), this would be set to '0x5A'.")) + ] + + +SVerticalBox::Slot() + .Padding(2.0f) + [ + SNew(SNumericEntryBox) + .Value(this, &SCharacterRangeEditor::GetRangeComponentAsOptional, 1) + .OnValueCommitted(this, &SCharacterRangeEditor::OnRangeComponentCommittedAsNumeric, 1) + .ToolTipText(LOCTEXT("MaxCharacterRangeEditDecTooltip", "Specifies the upper inclusive boundary of this character range as the decimal value of a unicode character.\nExample: If you wanted to use the range '65-90' (A-Z), this would be set to '90'.")) + ] + ] ] ]; } @@ -1400,13 +1453,13 @@ FText SCharacterRangeEditor::GetRangeComponentAsTCHAR(int32 InComponentIndex) co { const int32 RangeComponent = GetRangeComponent(InComponentIndex); const TCHAR RangeComponentStr[] = { static_cast(RangeComponent), 0 }; - return FText::FromString(RangeComponentStr); + return FText::AsCultureInvariant(RangeComponentStr); } FText SCharacterRangeEditor::GetRangeComponentAsHexString(int32 InComponentIndex) const { const int32 RangeComponent = GetRangeComponent(InComponentIndex); - return FText::FromString(FString::Printf(TEXT("0x%04x"), RangeComponent)); + return FText::AsCultureInvariant(FString::Printf(TEXT("0x%04x"), RangeComponent)); } TOptional SCharacterRangeEditor::GetRangeComponentAsOptional(int32 InComponentIndex) const @@ -1473,8 +1526,73 @@ void SCharacterRangeEditor::SetRangeComponent(const int32 InNewValue, const int3 ? FInt32Range(FInt32Range::BoundsType::Inclusive(InNewValue), FInt32Range::BoundsType::Inclusive(CharacterRangePtr->GetUpperBoundValue())) : FInt32Range(FInt32Range::BoundsType::Inclusive(CharacterRangePtr->GetLowerBoundValue()), FInt32Range::BoundsType::Inclusive(InNewValue)); + CacheCurrentRangeSelection(); + CompositeFontEditorPtr->FlushCachedFont(); } } +void SCharacterRangeEditor::CacheCurrentRangeSelection() +{ + CurrentRangeSelection.Reset(); + + TArrayView UnicodeBlockRanges = FUnicodeBlockRange::GetUnicodeBlockRanges(); + + // todo: could binary search on the lower bound since they're sorted in ascending order; need the Algo for it to come back from Main + FInt32Range* const CharacterRangePtr = CharacterRange->GetRange(); + if(CharacterRangePtr) + { + for(const FUnicodeBlockRange& UnicodeBlockRange : UnicodeBlockRanges) + { + if(UnicodeBlockRange.Range == *CharacterRangePtr) + { + CurrentRangeSelection = UnicodeBlockRange; + } + } + } +} + +FText SCharacterRangeEditor::GetCurrentRangeSelectionDisplayName() const +{ + return CurrentRangeSelection.IsSet() ? CurrentRangeSelection->DisplayName : LOCTEXT("UnicodeBlock_CustomSelection", "Custom"); +} + +void SCharacterRangeEditor::OnRangeSelectionComboOpening() +{ + RangeSelectionComboData.Sort([](const TSharedPtr& One, const TSharedPtr& Two) + { + return One->DisplayName.CompareTo(Two->DisplayName) < 0; + }); + + if(RangeSelectionCombo.IsValid()) + { + RangeSelectionCombo->RefreshOptions(); + } +} + +void SCharacterRangeEditor::OnRangeSelectionChanged(TSharedPtr InNewRangeSelection, ESelectInfo::Type) +{ + if(InNewRangeSelection.IsValid()) + { + FInt32Range* const CharacterRangePtr = CharacterRange->GetRange(); + if(CharacterRangePtr) + { + const FScopedTransaction Transaction(LOCTEXT("UpdateCharacterRange", "Update Character Range")); + CompositeFontEditorPtr->GetFontObject()->Modify(); + + *CharacterRangePtr = InNewRangeSelection->Range; + CurrentRangeSelection = *InNewRangeSelection; + + CompositeFontEditorPtr->FlushCachedFont(); + } + } +} + +TSharedRef SCharacterRangeEditor::MakeRangeSelectionWidget(TSharedPtr InRangeSelection) +{ + return SNew(STextBlock) + .Text(InRangeSelection->DisplayName) + .ToolTipText(FText::Format(LOCTEXT("RangeSelectionTooltipFmt", "{0} ({1} - {2})"), InRangeSelection->DisplayName, FText::AsCultureInvariant(FString::Printf(TEXT("0x%04x"), InRangeSelection->Range.GetLowerBoundValue())), FText::AsCultureInvariant(FString::Printf(TEXT("0x%04x"), InRangeSelection->Range.GetUpperBoundValue())))); +} + #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Editor/FontEditor/Private/SCompositeFontEditor.h b/Engine/Source/Editor/FontEditor/Private/SCompositeFontEditor.h index 3882a6e759f3..6a7f8e0bf8e2 100644 --- a/Engine/Source/Editor/FontEditor/Private/SCompositeFontEditor.h +++ b/Engine/Source/Editor/FontEditor/Private/SCompositeFontEditor.h @@ -11,6 +11,7 @@ #include "Widgets/SWidget.h" #include "Widgets/SCompoundWidget.h" #include "Fonts/SlateFontInfo.h" +#include "Fonts/UnicodeBlockRange.h" #include "Widgets/Views/STableViewBase.h" #include "Widgets/Views/STableRow.h" #include "Widgets/Views/STileView.h" @@ -413,9 +414,33 @@ private: /** Set the given range component from its numeric form (0 for min, 1 for max) */ void SetRangeComponent(const int32 InNewValue, const int32 InComponentIndex); + /** Cache the current range selection (calculated based on the current range) */ + void CacheCurrentRangeSelection(); + + /** Get the display name of the current range selection (or "Custom" if there is no range selection) */ + FText GetCurrentRangeSelectionDisplayName() const; + + /** Called before the range selection combo is opened - used to sort the list of available range selections */ + void OnRangeSelectionComboOpening(); + + /** Called when the selection of the range selection combo is changed */ + void OnRangeSelectionChanged(TSharedPtr InNewRangeSelection, ESelectInfo::Type); + + /** Make the widget for an entry in the range selection combo */ + TSharedRef MakeRangeSelectionWidget(TSharedPtr InRangeSelection); + /** Pointer back to the composite font editor that owns us */ SCompositeFontEditor* CompositeFontEditorPtr; /** Character range to edit (may be invalid, or change in response to an undo/redo) */ FCharacterRangeTileViewEntryPtr CharacterRange; + + /** Range selection combo box widget */ + TSharedPtr>> RangeSelectionCombo; + + /** Source data for the range selection combo widget */ + TArray> RangeSelectionComboData; + + /** The currently selected range selection preset */ + TOptional CurrentRangeSelection; }; diff --git a/Engine/Source/Editor/GameProjectGeneration/GameProjectGeneration.Build.cs b/Engine/Source/Editor/GameProjectGeneration/GameProjectGeneration.Build.cs index 49e8233b8814..c6bbc3a480a7 100644 --- a/Engine/Source/Editor/GameProjectGeneration/GameProjectGeneration.Build.cs +++ b/Engine/Source/Editor/GameProjectGeneration/GameProjectGeneration.Build.cs @@ -18,8 +18,9 @@ public class GameProjectGeneration : ModuleRules new string[] { "AssetRegistry", "ContentBrowser", - "DesktopPlatform", - "MainFrame", + "DesktopPlatform", + "LauncherPlatform", + "MainFrame", "AddContentDialog", "HardwareTargeting", } @@ -28,23 +29,24 @@ public class GameProjectGeneration : ModuleRules PrivateDependencyModuleNames.AddRange( new string[] { "Analytics", - "AppFramework", + "AppFramework", "ClassViewer", "Core", "CoreUObject", "Engine", "EngineSettings", - "InputCore", + "InputCore", "Projects", - "RenderCore", + "RenderCore", "Slate", "SlateCore", - "EditorStyle", - "SourceControl", + "EditorStyle", + "SourceControl", "TargetPlatform", "UnrealEd", "DesktopPlatform", - "HardwareTargeting", + "LauncherPlatform", + "HardwareTargeting", "AddContentDialog", "AudioMixer" } diff --git a/Engine/Source/Editor/GameProjectGeneration/Private/GameProjectUtils.cpp b/Engine/Source/Editor/GameProjectGeneration/Private/GameProjectUtils.cpp index b5a11303b97f..4371b801c5bf 100644 --- a/Engine/Source/Editor/GameProjectGeneration/Private/GameProjectUtils.cpp +++ b/Engine/Source/Editor/GameProjectGeneration/Private/GameProjectUtils.cpp @@ -1002,7 +1002,7 @@ bool GameProjectUtils::IsValidClassNameForCreation(const FString& NewClassName, { FFormatNamedArguments Args; Args.Add( TEXT("IllegalNameCharacters"), FText::FromString( IllegalNameCharacters ) ); - OutFailReason = FText::Format( LOCTEXT( "ClassNameContainsIllegalCharacters", "The class name may not contain the following characters: {IllegalNameCharacters}" ), Args ); + OutFailReason = FText::Format( LOCTEXT( "ClassNameContainsIllegalCharacters", "The class name may not contain the following characters: '{IllegalNameCharacters}'" ), Args ); return false; } @@ -1943,7 +1943,6 @@ bool GameProjectUtils::GenerateBasicSourceCode(const FString& NewProjectSourcePa { const FString NewHeaderFilename = GameModulePath / NewProjectName + TEXT(".h"); TArray PublicHeaderIncludes; - PublicHeaderIncludes.Add(TEXT("Engine.h")); if ( GenerateGameModuleHeaderFile(NewHeaderFilename, PublicHeaderIncludes, OutFailReason) ) { OutCreatedFiles.Add(NewHeaderFilename); @@ -2701,7 +2700,7 @@ bool GameProjectUtils::GenerateClassHeaderFile(const FString& NewHeaderFileName, FString BaseClassIncludePath; if(ParentClassInfo.GetIncludePath(BaseClassIncludePath)) { - BaseClassIncludeDirective = FString::Printf(LINE_TERMINATOR TEXT("#include \"%s\""), *BaseClassIncludePath); + BaseClassIncludeDirective = FString::Printf(TEXT("#include \"%s\""), *BaseClassIncludePath); } FString ModuleAPIMacro; @@ -2736,6 +2735,10 @@ bool GameProjectUtils::GenerateClassHeaderFile(const FString& NewHeaderFileName, FinalOutput = FinalOutput.Replace(TEXT("%EVENTUAL_CONSTRUCTOR_DECLARATION%"), *EventualConstructorDeclaration, ESearchCase::CaseSensitive); FinalOutput = FinalOutput.Replace(TEXT("%CLASS_PROPERTIES%"), *ClassProperties, ESearchCase::CaseSensitive); FinalOutput = FinalOutput.Replace(TEXT("%CLASS_FUNCTION_DECLARATIONS%"), *ClassFunctionDeclarations, ESearchCase::CaseSensitive); + if (BaseClassIncludeDirective.Len() == 0) + { + FinalOutput = FinalOutput.Replace(TEXT("%BASE_CLASS_INCLUDE_DIRECTIVE%") LINE_TERMINATOR, TEXT(""), ESearchCase::CaseSensitive); + } FinalOutput = FinalOutput.Replace(TEXT("%BASE_CLASS_INCLUDE_DIRECTIVE%"), *BaseClassIncludeDirective, ESearchCase::CaseSensitive); HarvestCursorSyncLocation( FinalOutput, OutSyncLocation ); @@ -2743,6 +2746,87 @@ bool GameProjectUtils::GenerateClassHeaderFile(const FString& NewHeaderFileName, return WriteOutputFile(NewHeaderFileName, FinalOutput, OutFailReason); } +static bool TryParseIncludeDirective(const FString& Text, int StartPos, int EndPos, FString& IncludePath) +{ + // Check if the line starts with a # character + int Pos = StartPos; + while (Pos < EndPos && FChar::IsWhitespace(Text[Pos])) + { + Pos++; + } + if (Pos == EndPos || Text[Pos++] != '#') + { + return false; + } + while (Pos < EndPos && FChar::IsWhitespace(Text[Pos])) + { + Pos++; + } + + // Check it's an include directive + const TCHAR* IncludeText = TEXT("include"); + for (int Idx = 0; IncludeText[Idx] != 0; Idx++) + { + if (Pos == EndPos || Text[Pos] != IncludeText[Idx]) + { + return false; + } + Pos++; + } + while (Pos < EndPos && FChar::IsWhitespace(Text[Pos])) + { + Pos++; + } + + // Parse out the quoted include path + if (Pos == EndPos || Text[Pos++] != '"') + { + return false; + } + int IncludePathPos = Pos; + while (Pos < EndPos && Text[Pos] != '"') + { + Pos++; + } + IncludePath = Text.Mid(IncludePathPos, Pos - IncludePathPos); + return true; +} + +static bool IsUsingOldStylePch(FString BaseDir) +{ + // Find all the cpp files under the base directory + TArray Files; + IFileManager::Get().FindFilesRecursive(Files, *BaseDir, TEXT("*.cpp"), true, false, false); + + // Parse the first include directive for up to 16 include paths + TArray FirstIncludedFiles; + for (int Idx = 0; Idx < Files.Num() && Idx < 16; Idx++) + { + FString Text; + FFileHelper::LoadFileToString(Text, *Files[Idx]); + + int LinePos = 0; + while(LinePos < Text.Len()) + { + int EndOfLinePos = LinePos; + while (EndOfLinePos < Text.Len() && Text[EndOfLinePos] != '\n') + { + EndOfLinePos++; + } + + FString IncludePath; + if (TryParseIncludeDirective(Text, LinePos, EndOfLinePos, IncludePath)) + { + FirstIncludedFiles.AddUnique(FPaths::GetCleanFilename(IncludePath)); + break; + } + + LinePos = EndOfLinePos + 1; + } + } + return FirstIncludedFiles.Num() == 1 && Files.Num() > 1; +} + bool GameProjectUtils::GenerateClassCPPFile(const FString& NewCPPFileName, const FString UnPrefixedClassName, const FNewClassInfo ParentClassInfo, const TArray& AdditionalIncludes, const TArray& PropertyOverrides, const FString& AdditionalMemberDefinitions, FString& OutSyncLocation, const FModuleContextInfo& ModuleInfo, FText& OutFailReason) { FString Template; @@ -2785,8 +2869,15 @@ bool GameProjectUtils::GenerateClassCPPFile(const FString& NewCPPFileName, const } // Calculate the correct include path for the module header - const FString ModuleIncludePath = DetermineModuleIncludePath(ModuleInfo, NewCPPFileName); - + FString PchIncludeDirective; + if (IsUsingOldStylePch(ModuleInfo.ModuleSourcePath)) + { + const FString ModuleIncludePath = DetermineModuleIncludePath(ModuleInfo, NewCPPFileName); + if (ModuleIncludePath.Len() > 0) + { + PchIncludeDirective = FString::Printf(TEXT("#include \"%s\""), *ModuleIncludePath); + } + } FString EventualConstructorDefinition; if (PropertyOverrides.Num() != 0) @@ -2801,7 +2892,11 @@ bool GameProjectUtils::GenerateClassCPPFile(const FString& NewCPPFileName, const FString FinalOutput = Template.Replace(TEXT("%COPYRIGHT_LINE%"), *MakeCopyrightLine(), ESearchCase::CaseSensitive); FinalOutput = FinalOutput.Replace(TEXT("%UNPREFIXED_CLASS_NAME%"), *UnPrefixedClassName, ESearchCase::CaseSensitive); FinalOutput = FinalOutput.Replace(TEXT("%MODULE_NAME%"), *ModuleInfo.ModuleName, ESearchCase::CaseSensitive); - FinalOutput = FinalOutput.Replace(TEXT("%MODULE_INCLUDE_PATH%"), *ModuleIncludePath, ESearchCase::CaseSensitive); + if (PchIncludeDirective.Len() == 0) + { + FinalOutput = FinalOutput.Replace(TEXT("%PCH_INCLUDE_DIRECTIVE%") LINE_TERMINATOR, TEXT(""), ESearchCase::CaseSensitive); + } + FinalOutput = FinalOutput.Replace(TEXT("%PCH_INCLUDE_DIRECTIVE%"), *PchIncludeDirective, ESearchCase::CaseSensitive); FinalOutput = FinalOutput.Replace(TEXT("%PREFIXED_CLASS_NAME%"), *PrefixedClassName, ESearchCase::CaseSensitive); FinalOutput = FinalOutput.Replace(TEXT("%EVENTUAL_CONSTRUCTOR_DEFINITION%"), *EventualConstructorDefinition, ESearchCase::CaseSensitive); FinalOutput = FinalOutput.Replace(TEXT("%ADDITIONAL_MEMBER_DEFINITIONS%"), *AdditionalMemberDefinitions, ESearchCase::CaseSensitive); @@ -2815,7 +2910,7 @@ bool GameProjectUtils::GenerateClassCPPFile(const FString& NewCPPFileName, const bool GameProjectUtils::GenerateGameModuleBuildFile(const FString& NewBuildFileName, const FString& ModuleName, const TArray& PublicDependencyModuleNames, const TArray& PrivateDependencyModuleNames, FText& OutFailReason) { FString Template; - if ( !ReadTemplateFile(TEXT("GameModule.Build.cs.template"), Template, OutFailReason) ) + if (!ReadTemplateFile(TEXT("GameModule.Build.cs.template"), Template, OutFailReason)) { return false; } @@ -2828,6 +2923,25 @@ bool GameProjectUtils::GenerateGameModuleBuildFile(const FString& NewBuildFileNa return WriteOutputFile(NewBuildFileName, FinalOutput, OutFailReason); } +bool GameProjectUtils::GeneratePluginModuleBuildFile(const FString& NewBuildFileName, const FString& ModuleName, const TArray& PublicDependencyModuleNames, const TArray& PrivateDependencyModuleNames, FText& OutFailReason, bool bUseExplicitOrSharedPCHs/* = true*/) +{ + FString Template; + if ( !ReadTemplateFile(TEXT("PluginModule.Build.cs.template"), Template, OutFailReason) ) + { + return false; + } + + FString FinalOutput = Template.Replace(TEXT("%COPYRIGHT_LINE%"), *MakeCopyrightLine(), ESearchCase::CaseSensitive); + FinalOutput = FinalOutput.Replace(TEXT("%PUBLIC_DEPENDENCY_MODULE_NAMES%"), *MakeCommaDelimitedList(PublicDependencyModuleNames), ESearchCase::CaseSensitive); + FinalOutput = FinalOutput.Replace(TEXT("%PRIVATE_DEPENDENCY_MODULE_NAMES%"), *MakeCommaDelimitedList(PrivateDependencyModuleNames), ESearchCase::CaseSensitive); + FinalOutput = FinalOutput.Replace(TEXT("%MODULE_NAME%"), *ModuleName, ESearchCase::CaseSensitive); + + const FString PCHUsage = bUseExplicitOrSharedPCHs ? TEXT("UseExplicitOrSharedPCHs") : TEXT("UseSharedPCHs"); + FinalOutput = FinalOutput.Replace(TEXT("%PCH_USAGE%"), *PCHUsage, ESearchCase::CaseSensitive); + + return WriteOutputFile(NewBuildFileName, FinalOutput, OutFailReason); +} + bool GameProjectUtils::GenerateGameModuleTargetFile(const FString& NewBuildFileName, const FString& ModuleName, const TArray& ExtraModuleNames, FText& OutFailReason) { FString Template; diff --git a/Engine/Source/Editor/GameProjectGeneration/Private/SGetSuggestedIDEWidget.cpp b/Engine/Source/Editor/GameProjectGeneration/Private/SGetSuggestedIDEWidget.cpp index f36d0b31a0e1..a81e1a036c25 100644 --- a/Engine/Source/Editor/GameProjectGeneration/Private/SGetSuggestedIDEWidget.cpp +++ b/Engine/Source/Editor/GameProjectGeneration/Private/SGetSuggestedIDEWidget.cpp @@ -9,6 +9,7 @@ #include "Widgets/Notifications/SNotificationList.h" #include "Widgets/Input/SHyperlink.h" #include "EngineAnalytics.h" +#include "SlateApplication.h" #include "Interfaces/IAnalyticsProvider.h" #define LOCTEXT_NAMESPACE "GameProjectGeneration" @@ -91,6 +92,16 @@ FReply SGetSuggestedIDEWidget::OnInstallIDEClicked() } } + + TSharedPtr ThisWindow = FSlateApplication::Get().FindWidgetWindow(AsShared()); + + if (ThisWindow.IsValid() && ThisWindow->IsModalWindow()) + { + // If this window is modal, close it to unblock the IDE request and allow it to finish...as long as another + // modal window isn't opened on top of it + ThisWindow->RequestDestroyWindow(); + } + return FReply::Handled(); } diff --git a/Engine/Source/Editor/GameProjectGeneration/Private/SProjectBrowser.cpp b/Engine/Source/Editor/GameProjectGeneration/Private/SProjectBrowser.cpp index 3bea4ec93e96..81ead2244866 100644 --- a/Engine/Source/Editor/GameProjectGeneration/Private/SProjectBrowser.cpp +++ b/Engine/Source/Editor/GameProjectGeneration/Private/SProjectBrowser.cpp @@ -47,6 +47,9 @@ #include "EngineAnalytics.h" #include "Interfaces/IAnalyticsProvider.h" #include "Framework/Application/SlateApplication.h" +#include "ILauncherPlatform.h" +#include "LauncherPlatformModule.h" +#include "IMainFrameModule.h" #define LOCTEXT_NAMESPACE "ProjectBrowser" @@ -244,7 +247,7 @@ void SProjectBrowser::Construct( const FArguments& InArgs ) .AutoWidth() [ SNew(SButton) - .Visibility( FDesktopPlatformModule::Get()->CanOpenLauncher(true) ? EVisibility::Visible : EVisibility::Collapsed ) + .Visibility( FLauncherPlatformModule::Get()->CanOpenLauncher(true) ? EVisibility::Visible : EVisibility::Collapsed ) .ButtonStyle(FEditorStyle::Get(), "ToggleButton") .OnClicked(this, &SProjectBrowser::HandleMarketplaceTabButtonClicked) .ForegroundColor(FSlateColor::UseForeground()) @@ -1278,8 +1281,17 @@ FReply SProjectBrowser::OnBrowseToProjectClicked() bool bOpened = false; if ( DesktopPlatform ) { + void* ParentWindowWindowHandle = NULL; + + IMainFrameModule& MainFrameModule = FModuleManager::LoadModuleChecked(TEXT("MainFrame")); + const TSharedPtr& MainFrameParentWindow = MainFrameModule.GetParentWindow(); + if ( MainFrameParentWindow.IsValid() && MainFrameParentWindow->GetNativeWindow().IsValid() ) + { + ParentWindowWindowHandle = MainFrameParentWindow->GetNativeWindow()->GetOSWindowHandle(); + } + bOpened = DesktopPlatform->OpenFileDialog( - FSlateApplication::Get().FindBestParentWindowHandleForDialogs(AsShared()), + ParentWindowWindowHandle, LOCTEXT("OpenProjectBrowseTitle", "Open Project").ToString(), DefaultFolder, TEXT(""), @@ -1334,14 +1346,14 @@ void SProjectBrowser::HandleProjectViewSelectionChanged(TSharedPtr FReply SProjectBrowser::HandleMarketplaceTabButtonClicked() { - IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get(); + ILauncherPlatform* LauncherPlatform = FLauncherPlatformModule::Get(); - if (DesktopPlatform != nullptr) + if (LauncherPlatform != nullptr) { TArray EventAttributes; FOpenLauncherOptions OpenOptions(TEXT("ue/marketplace")); - if ( DesktopPlatform->OpenLauncher(OpenOptions) ) + if (LauncherPlatform->OpenLauncher(OpenOptions) ) { EventAttributes.Add(FAnalyticsEventAttribute(TEXT("OpenSucceeded"), TEXT("TRUE"))); } @@ -1352,7 +1364,7 @@ FReply SProjectBrowser::HandleMarketplaceTabButtonClicked() if (EAppReturnType::Yes == FMessageDialog::Open(EAppMsgType::YesNo, LOCTEXT("InstallMarketplacePrompt", "The Marketplace requires the Epic Games Launcher, which does not seem to be installed on your computer. Would you like to install it now?"))) { FOpenLauncherOptions InstallOptions(true, TEXT("ue/marketplace")); - if ( !DesktopPlatform->OpenLauncher(InstallOptions) ) + if (!LauncherPlatform->OpenLauncher(InstallOptions)) { EventAttributes.Add(FAnalyticsEventAttribute(TEXT("InstallSucceeded"), TEXT("FALSE"))); FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(TEXT("Sorry, there was a problem installing the Launcher.\nPlease try to install it manually!"))); diff --git a/Engine/Source/Editor/GameProjectGeneration/Private/Tests/GameProjectAutomationTests.cpp b/Engine/Source/Editor/GameProjectGeneration/Private/Tests/GameProjectAutomationTests.cpp index 65526c4d99c8..79c18384dfb2 100644 --- a/Engine/Source/Editor/GameProjectGeneration/Private/Tests/GameProjectAutomationTests.cpp +++ b/Engine/Source/Editor/GameProjectGeneration/Private/Tests/GameProjectAutomationTests.cpp @@ -78,7 +78,7 @@ namespace GameProjectAutomationUtils * @param OutMatchedProjects Total projects matching criteria * @param OutCreatedProjects Total projects succesfully created */ - static void CreateProjectSet(TMap> >& InTemplates, EHardwareClass::Type InTargetedHardware, EGraphicsPreset::Type InGraphicPreset, EContentSourceCategory InCategory, bool bInCopyStarterContent, int32 OutMatchedProjects, int32 OutCreatedProjects) + static void CreateProjectSet(TMap> >& InTemplates, EHardwareClass::Type InTargetedHardware, EGraphicsPreset::Type InGraphicPreset, EContentSourceCategory InCategory, bool bInCopyStarterContent, int32 &OutCreatedProjects, int32 &OutMatchedProjects) { // If this is empty, it will use the same name for each project, otherwise it will create a project based on target platform and source template FString TestRootFolder;// = "ProjectTests"; @@ -333,7 +333,7 @@ bool FBuildPromotionNewProjectMapTest::RunTest(const FString& Parameters) /* * Template project creation test */ -IMPLEMENT_SIMPLE_AUTOMATION_TEST(FCreateBPTemplateProjectAutomationTests, "System.Promotion.Project Promotion Pass.Step 3 NewProjectCreationTests.CreateBlueprintProjects", EAutomationTestFlags::Disabled | EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter | EAutomationTestFlags::Disabled) +IMPLEMENT_SIMPLE_AUTOMATION_TEST(FCreateBPTemplateProjectAutomationTests, "System.Promotion.Project Promotion Pass.Step 3 NewProjectCreationTests.CreateBlueprintProjects", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter | EAutomationTestFlags::Disabled) /** * Uses the new project wizard to locate all templates available for new blueprint project creation and verifies creation succeeds. @@ -361,7 +361,7 @@ bool FCreateBPTemplateProjectAutomationTests::RunTest(const FString& Parameters) /* * Template project creation test */ -IMPLEMENT_SIMPLE_AUTOMATION_TEST(FCreateCPPTemplateProjectAutomationTests, "System.Promotion.Project Promotion Pass.Step 3 NewProjectCreationTests.CreateCodeProjects", EAutomationTestFlags::Disabled | EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter | EAutomationTestFlags::Disabled) +IMPLEMENT_SIMPLE_AUTOMATION_TEST(FCreateCPPTemplateProjectAutomationTests, "System.Promotion.Project Promotion Pass.Step 3 NewProjectCreationTests.CreateCodeProjects", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter | EAutomationTestFlags::Disabled) /** * Uses the new project wizard to locate all templates available for new code project creation and verifies creation succeeds. diff --git a/Engine/Source/Editor/GameProjectGeneration/Public/GameProjectUtils.h b/Engine/Source/Editor/GameProjectGeneration/Public/GameProjectUtils.h index 27656d06d162..192ed420f8bf 100644 --- a/Engine/Source/Editor/GameProjectGeneration/Public/GameProjectUtils.h +++ b/Engine/Source/Editor/GameProjectGeneration/Public/GameProjectUtils.h @@ -226,6 +226,9 @@ public: /** Generates a Build.cs file for a game module */ static bool GenerateGameModuleBuildFile(const FString& NewBuildFileName, const FString& ModuleName, const TArray& PublicDependencyModuleNames, const TArray& PrivateDependencyModuleNames, FText& OutFailReason); + /** Generates a Build.cs file for a plugin module. Set 'bUseExplicitOrSharedPCHs' to false to disable IWYU conventions. */ + static bool GeneratePluginModuleBuildFile(const FString& NewBuildFileName, const FString& ModuleName, const TArray& PublicDependencyModuleNames, const TArray& PrivateDependencyModuleNames, FText& OutFailReason, bool bUseExplicitOrSharedPCHs = true); + /** Generates a module .cpp file, intended for plugin use */ static bool GeneratePluginModuleCPPFile(const FString& CPPFileName, const FString& ModuleName, const FString& StartupSourceCode, FText& OutFailReason); diff --git a/Engine/Source/Editor/GameplayTasksEditor/Private/K2Node_LatentGameplayTaskCall.cpp b/Engine/Source/Editor/GameplayTasksEditor/Private/K2Node_LatentGameplayTaskCall.cpp index be12e8ad06ec..f970455f670c 100644 --- a/Engine/Source/Editor/GameplayTasksEditor/Private/K2Node_LatentGameplayTaskCall.cpp +++ b/Engine/Source/Editor/GameplayTasksEditor/Private/K2Node_LatentGameplayTaskCall.cpp @@ -211,7 +211,7 @@ void UK2Node_LatentGameplayTaskCall::CreatePinsForClass(UClass* InClass) { - UEdGraphPin* Pin = CreatePin(EGPD_Input, TEXT(""), TEXT(""), NULL, false, false, Property->GetName()); + UEdGraphPin* Pin = CreatePin(EGPD_Input, FString(), FString(), nullptr, Property->GetName()); check(Pin); const bool bPinGood = K2Schema->ConvertPropertyToPinType(Property, /*out*/ Pin->PinType); SpawnParamPins.Add(Pin->PinName); @@ -221,7 +221,7 @@ void UK2Node_LatentGameplayTaskCall::CreatePinsForClass(UClass* InClass) FString DefaultValueAsString; const bool bDefaultValueSet = FBlueprintEditorUtils::PropertyValueToString(Property, reinterpret_cast(ClassDefaultObject), DefaultValueAsString); check(bDefaultValueSet); - K2Schema->TrySetDefaultValue(*Pin, DefaultValueAsString); + K2Schema->SetPinAutogeneratedDefaultValue(Pin, DefaultValueAsString); } // Copy tooltip from the property. @@ -433,6 +433,7 @@ bool UK2Node_LatentGameplayTaskCall::ConnectSpawnProperties(UClass* ClassToSpawn continue; } + // This is sloppy, we should be comparing to defaults mutch later in the compile process: if (ClassToSpawn->ClassDefaultObject != nullptr) { // We don't want to generate an assignment node unless the default value @@ -450,8 +451,8 @@ bool UK2Node_LatentGameplayTaskCall::ConnectSpawnProperties(UClass* ClassToSpawn UFunction* SetByNameFunction = Schema->FindSetVariableByNameFunction(SpawnVarPin->PinType); if (SetByNameFunction) { - UK2Node_CallFunction* SetVarNode = NULL; - if (SpawnVarPin->PinType.bIsArray) + UK2Node_CallFunction* SetVarNode = nullptr; + if (SpawnVarPin->PinType.IsArray()) { SetVarNode = CompilerContext.SpawnIntermediateNode(this, SourceGraph); } @@ -496,9 +497,20 @@ bool UK2Node_LatentGameplayTaskCall::ConnectSpawnProperties(UClass* ClassToSpawn } else { - // Move connection from the variable pin on the spawn node to the 'value' pin - CompilerContext.MovePinLinksToIntermediate(*SpawnVarPin, *ValuePin); - SetVarNode->PinConnectionListChanged(ValuePin); + // For non-array struct pins that are not linked, transfer the pin type so that the node will expand an auto-ref that will assign the value by-ref. + if (SpawnVarPin->PinType.IsArray() == false && SpawnVarPin->PinType.PinCategory == Schema->PC_Struct && SpawnVarPin->LinkedTo.Num() == 0) + { + ValuePin->PinType.PinCategory = SpawnVarPin->PinType.PinCategory; + ValuePin->PinType.PinSubCategory = SpawnVarPin->PinType.PinSubCategory; + ValuePin->PinType.PinSubCategoryObject = SpawnVarPin->PinType.PinSubCategoryObject; + CompilerContext.MovePinLinksToIntermediate(*SpawnVarPin, *ValuePin); + } + else + { + // Move connection from the variable pin on the spawn node to the 'value' pin + CompilerContext.MovePinLinksToIntermediate(*SpawnVarPin, *ValuePin); + SetVarNode->PinConnectionListChanged(ValuePin); + } } } } @@ -587,7 +599,7 @@ void UK2Node_LatentGameplayTaskCall::ExpandNode(class FKismetCompilerContext& Co { const FEdGraphPinType& PinType = CurrentPin->PinType; UK2Node_TemporaryVariable* TempVarOutput = CompilerContext.SpawnInternalVariable( - this, PinType.PinCategory, PinType.PinSubCategory, PinType.PinSubCategoryObject.Get(), PinType.bIsArray, PinType.bIsSet, PinType.bIsMap, PinType.PinValueType); + this, PinType.PinCategory, PinType.PinSubCategory, PinType.PinSubCategoryObject.Get(), PinType.ContainerType, PinType.PinValueType); bIsErrorFree &= TempVarOutput->GetVariablePin() && CompilerContext.MovePinLinksToIntermediate(*CurrentPin, *TempVarOutput->GetVariablePin()).CanSafeConnect(); VariableOutputs.Add(FBaseAsyncTaskHelper::FOutputPinAndLocalVariable(CurrentPin, TempVarOutput)); } @@ -699,7 +711,7 @@ void UK2Node_LatentGameplayTaskCall::ExpandNode(class FKismetCompilerContext& Co // Branch based on return value of Prespawn // ------------------------------------------- - UK2Node_IfThenElse* BranchNode = SourceGraph->CreateBlankNode(); + UK2Node_IfThenElse* BranchNode = SourceGraph->CreateIntermediateNode(); BranchNode->AllocateDefaultPins(); CompilerContext.MessageLog.NotifyIntermediateObjectCreation(BranchNode, this); diff --git a/Engine/Source/Editor/GeometryMode/Public/EditorGeometry.h b/Engine/Source/Editor/GeometryMode/Public/EditorGeometry.h index c655fcbc0ad4..a4088a421e95 100644 --- a/Engine/Source/Editor/GeometryMode/Public/EditorGeometry.h +++ b/Engine/Source/Editor/GeometryMode/Public/EditorGeometry.h @@ -19,6 +19,7 @@ class FGeomBase { public: FGeomBase(); + virtual ~FGeomBase() {} /** Does nothing if not in geometry mode.*/ virtual void Select( bool InSelect = 1 ); diff --git a/Engine/Source/Editor/GraphEditor/Private/BlueprintConnectionDrawingPolicy.cpp b/Engine/Source/Editor/GraphEditor/Private/BlueprintConnectionDrawingPolicy.cpp index ac8eb7e90d61..7ca08236ec98 100644 --- a/Engine/Source/Editor/GraphEditor/Private/BlueprintConnectionDrawingPolicy.cpp +++ b/Engine/Source/Editor/GraphEditor/Private/BlueprintConnectionDrawingPolicy.cpp @@ -442,8 +442,7 @@ void FKismetConnectionDrawingPolicy::DetermineWiringStyle(UEdGraphPin* OutputPin const bool bDeemphasizeUnhoveredPins = HoveredPins.Num() > 0; // If this is a K2 graph, try to be a little more specific - const UEdGraphSchema_K2* K2Schema = Cast(Schema); - if (K2Schema != NULL) + if (const UEdGraphSchema_K2* K2Schema = Cast(Schema)) { // If the output or input connect to a knot that is going backwards, we will flip the direction on values going into them { @@ -512,8 +511,8 @@ void FKismetConnectionDrawingPolicy::DetermineWiringStyle(UEdGraphPin* OutputPin } else { - // Array types should draw thicker - if ((InputPin && InputPin->PinType.bIsArray) || (OutputPin && OutputPin->PinType.bIsArray)) + // Container types should draw thicker + if ((InputPin && InputPin->PinType.IsContainer()) || (OutputPin && OutputPin->PinType.IsContainer())) { Params.WireThickness = 3.0f; } diff --git a/Engine/Source/Editor/GraphEditor/Private/GraphDiffControl.cpp b/Engine/Source/Editor/GraphEditor/Private/GraphDiffControl.cpp index 0fc3f904323f..7d2d80266d91 100644 --- a/Engine/Source/Editor/GraphEditor/Private/GraphDiffControl.cpp +++ b/Engine/Source/Editor/GraphEditor/Private/GraphDiffControl.cpp @@ -153,15 +153,16 @@ static void DiffR_PinTypeChanged(FDiffResults& Results, class UEdGraphPin* Pin2, Diff.DisplayString = FText::Format(LOCTEXT("DIF_PinSubCategoryObjFmt", "Pin SubCategoryObject '{0}' ['{1}' -> '{2}']"), FText::FromString(Pin2->PinName), FText::FromString(Obj1), FText::FromString(Obj2)); } } - else if(Type1.bIsArray != Type2.bIsArray) + else if(Type1.ContainerType != Type2.ContainerType) { + // TODO: Make the messaging correct about the nature of the diff Diff.Diff = EDiffType::PIN_TYPE_IS_ARRAY; // Only bother setting up the display data if we're storing the result if(Results.CanStoreResults()) { - FText IsArray1 = Pin1->PinType.bIsArray ? LOCTEXT("true", "true") : LOCTEXT("false", "false"); - FText IsArray2 = Pin2->PinType.bIsArray ? LOCTEXT("true", "true") : LOCTEXT("false", "false"); + FText IsArray1 = Pin1->PinType.IsArray() ? LOCTEXT("true", "true") : LOCTEXT("false", "false"); + FText IsArray2 = Pin2->PinType.IsArray() ? LOCTEXT("true", "true") : LOCTEXT("false", "false"); Diff.ToolTip = FText::Format(LOCTEXT("DIF_PinIsArrayToolTipFmt", "PinType IsArray for '{0}' modified. Was '{1}', but is now '{2}"), FText::FromString(Pin2->PinName), IsArray1, IsArray2); Diff.DisplayString = FText::Format(LOCTEXT("DIF_PinIsArrayFmt", "Pin IsArray '{0}' ['{1}' -> '{2}']"), FText::FromString(Pin2->PinName), IsArray1, IsArray2); @@ -410,7 +411,7 @@ static bool IsPinTypeDifferent(const FEdGraphPinType& T1, const FEdGraphPinType& { bool bIsDifferent = (T1.PinCategory != T2.PinCategory) || (T1.PinSubCategory != T2.PinSubCategory) - || (T1.bIsArray != T2.bIsArray) + || (T1.ContainerType != T2.ContainerType) || (T1.bIsReference != T2.bIsReference); const UObject* T1Obj = T1.PinSubCategoryObject.Get(); diff --git a/Engine/Source/Editor/GraphEditor/Private/GraphEditorActions.cpp b/Engine/Source/Editor/GraphEditor/Private/GraphEditorActions.cpp index d8fd9a3fcfbb..a2c56ce92393 100644 --- a/Engine/Source/Editor/GraphEditor/Private/GraphEditorActions.cpp +++ b/Engine/Source/Editor/GraphEditor/Private/GraphEditorActions.cpp @@ -75,6 +75,7 @@ void FGraphEditorCommandsImpl::RegisterCommands() UI_COMMAND( RecombineStructPin, "Recombine Struct Pin", "Takes struct pins that have been broken in to composite elements and combines them back to a single struct pin", EUserInterfaceActionType::Button, FInputChord() ) UI_COMMAND( StartWatchingPin, "Watch this value", "Adds this pin or variable to the watch list", EUserInterfaceActionType::Button, FInputChord() ) UI_COMMAND( StopWatchingPin, "Stop watching this value", "Removes this pin or variable from the watch list ", EUserInterfaceActionType::Button, FInputChord() ) + UI_COMMAND( ResetPinToDefaultValue, "Reset to Default Value", "Reset value of this pin to the default", EUserInterfaceActionType::Button, FInputChord() ) UI_COMMAND( SelectBone, "Select Bone", "Assign or change the bone for SkeletalControls", EUserInterfaceActionType::Button, FInputChord() ) UI_COMMAND( AddBlendListPin, "Add Blend Pin", "Add Blend Pin to BlendList", EUserInterfaceActionType::Button, FInputChord() ) diff --git a/Engine/Source/Editor/GraphEditor/Private/GraphEditorDragDropAction.cpp b/Engine/Source/Editor/GraphEditor/Private/GraphEditorDragDropAction.cpp index a8ac343658dc..64a81d7fdba7 100644 --- a/Engine/Source/Editor/GraphEditor/Private/GraphEditorDragDropAction.cpp +++ b/Engine/Source/Editor/GraphEditor/Private/GraphEditorDragDropAction.cpp @@ -22,7 +22,7 @@ UEdGraphPin* FGraphEditorDragDropAction::GetHoveredPin() const UEdGraphNode* FGraphEditorDragDropAction::GetHoveredNode() const { - return HoveredNode.IsValid() ? HoveredNode->GetNodeObj() : NULL; + return HoveredNode.Get(); } UEdGraph* FGraphEditorDragDropAction::GetHoveredGraph() const @@ -55,6 +55,11 @@ void FGraphEditorDragDropAction::SetHoveredPin(UEdGraphPin* InPin) } void FGraphEditorDragDropAction::SetHoveredNode(const TSharedPtr& InNode) +{ + SetHoveredNode(InNode.IsValid() ? InNode->GetNodeObj() : nullptr); +} + +void FGraphEditorDragDropAction::SetHoveredNode(UEdGraphNode* InNode) { if (HoveredNode != InNode) { @@ -210,3 +215,23 @@ FReply FGraphSchemaActionDragDropAction::DroppedOnPanel( const TSharedRef< SWidg } return FReply::Unhandled(); } + +FReply FGraphSchemaActionDragDropAction::DroppedOnPin(FVector2D ScreenPosition, FVector2D GraphPosition) +{ + if (UEdGraph* Graph = GetHoveredGraph()) + { + if (ActionNode.IsValid()) + { + TArray DummyPins; + if (UEdGraphPin* Pin = GetHoveredPin()) + { + DummyPins.Add(Pin); + } + + ActionNode->PerformAction(Graph, DummyPins, GraphPosition); + + return FReply::Handled(); + } + } + return FReply::Unhandled(); +} diff --git a/Engine/Source/Editor/GraphEditor/Private/KismetNodes/SGraphNodeSwitchStatement.cpp b/Engine/Source/Editor/GraphEditor/Private/KismetNodes/SGraphNodeSwitchStatement.cpp index 48d5c82c2389..0a74ebe5b240 100644 --- a/Engine/Source/Editor/GraphEditor/Private/KismetNodes/SGraphNodeSwitchStatement.cpp +++ b/Engine/Source/Editor/GraphEditor/Private/KismetNodes/SGraphNodeSwitchStatement.cpp @@ -26,7 +26,7 @@ public: { SGraphPin::Construct(SGraphPin::FArguments().PinLabelStyle(FName("Graph.Node.DefaultPinName")), InPin); - bWasEventPin = false; + CachePinIcons(); } }; diff --git a/Engine/Source/Editor/GraphEditor/Private/KismetPins/SGraphPinClass.cpp b/Engine/Source/Editor/GraphEditor/Private/KismetPins/SGraphPinClass.cpp index a2f21c75e8ca..8e99a887f8a1 100644 --- a/Engine/Source/Editor/GraphEditor/Private/KismetPins/SGraphPinClass.cpp +++ b/Engine/Source/Editor/GraphEditor/Private/KismetPins/SGraphPinClass.cpp @@ -9,6 +9,7 @@ #include "ClassViewerModule.h" #include "ClassViewerFilter.h" #include "ScopedTransaction.h" +#include "AssetRegistryModule.h" #define LOCTEXT_NAMESPACE "SGraphPinClass" @@ -136,4 +137,54 @@ FText SGraphPinClass::GetDefaultComboText() const return LOCTEXT( "DefaultComboText", "Select Class" ); } +const FAssetData& SGraphPinClass::GetAssetData(bool bRuntimePath) const +{ + if (bRuntimePath) + { + // For runtime use the default path + return SGraphPinObject::GetAssetData(bRuntimePath); + } + + FString CachedRuntimePath = CachedEditorAssetData.ObjectPath.ToString() + TEXT("_C"); + + if (GraphPinObj->DefaultObject) + { + if (!GraphPinObj->DefaultObject->GetPathName().Equals(CachedRuntimePath, ESearchCase::CaseSensitive)) + { + // This will cause it to use the UBlueprint + CachedEditorAssetData = FAssetData(GraphPinObj->DefaultObject, false); + } + } + else if (!GraphPinObj->DefaultValue.IsEmpty()) + { + if (!GraphPinObj->DefaultValue.Equals(CachedRuntimePath, ESearchCase::CaseSensitive)) + { + FString EditorPath = GraphPinObj->DefaultValue; + EditorPath.RemoveFromEnd(TEXT("_C")); + const FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(TEXT("AssetRegistry")); + + CachedEditorAssetData = AssetRegistryModule.Get().GetAssetByObjectPath(FName(*EditorPath)); + + if (!CachedEditorAssetData.IsValid()) + { + FString PackageName = FPackageName::ObjectPathToPackageName(EditorPath); + FString PackagePath = FPackageName::GetLongPackagePath(PackageName); + FString ObjectName = FPackageName::ObjectPathToObjectName(EditorPath); + + // Fake one + CachedEditorAssetData = FAssetData(FName(*PackageName), FName(*PackagePath), FName(*ObjectName), UObject::StaticClass()->GetFName()); + } + } + } + else + { + if (CachedEditorAssetData.IsValid()) + { + CachedEditorAssetData = FAssetData(); + } + } + + return CachedEditorAssetData; +} + #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Editor/GraphEditor/Private/KismetPins/SGraphPinClass.h b/Engine/Source/Editor/GraphEditor/Private/KismetPins/SGraphPinClass.h index 2d0f190f8051..a1029afabdc9 100644 --- a/Engine/Source/Editor/GraphEditor/Private/KismetPins/SGraphPinClass.h +++ b/Engine/Source/Editor/GraphEditor/Private/KismetPins/SGraphPinClass.h @@ -29,6 +29,9 @@ protected: virtual TSharedRef GenerateAssetPicker() override; virtual FText GetDefaultComboText() const override; virtual FOnClicked GetOnUseButtonDelegate() override; + virtual const FAssetData& GetAssetData(bool bRuntimePath) const override; //~ End SGraphPinObject Interface + /** Cached AssetData without the _C */ + mutable FAssetData CachedEditorAssetData; }; diff --git a/Engine/Source/Editor/GraphEditor/Private/KismetPins/SGraphPinExec.cpp b/Engine/Source/Editor/GraphEditor/Private/KismetPins/SGraphPinExec.cpp index 24ec39ff0e59..df8a5090fecc 100644 --- a/Engine/Source/Editor/GraphEditor/Private/KismetPins/SGraphPinExec.cpp +++ b/Engine/Source/Editor/GraphEditor/Private/KismetPins/SGraphPinExec.cpp @@ -8,8 +8,12 @@ void SGraphPinExec::Construct(const FArguments& InArgs, UEdGraphPin* InPin) { SGraphPin::Construct(SGraphPin::FArguments(), InPin); - bWasEventPin = false; + // Call utility function so inheritors can also call it since arguments can't be passed through + CachePinIcons(); +} +void SGraphPinExec::CachePinIcons() +{ CachedImg_Pin_ConnectedHovered = FEditorStyle::GetBrush(TEXT("Graph.ExecPin.ConnectedHovered")); CachedImg_Pin_Connected = FEditorStyle::GetBrush(TEXT("Graph.ExecPin.Connected")); CachedImg_Pin_DisconnectedHovered = FEditorStyle::GetBrush(TEXT("Graph.ExecPin.DisconnectedHovered")); diff --git a/Engine/Source/Editor/GraphEditor/Private/KismetPins/SGraphPinObject.cpp b/Engine/Source/Editor/GraphEditor/Private/KismetPins/SGraphPinObject.cpp index 711091eb96ff..528ed74c5f88 100644 --- a/Engine/Source/Editor/GraphEditor/Private/KismetPins/SGraphPinObject.cpp +++ b/Engine/Source/Editor/GraphEditor/Private/KismetPins/SGraphPinObject.cpp @@ -13,6 +13,7 @@ #include "ContentBrowserModule.h" #include "ScopedTransaction.h" #include "Engine/Selection.h" +#include "AssetRegistryModule.h" #define LOCTEXT_NAMESPACE "SGraphPinObject" @@ -41,8 +42,6 @@ TSharedRef SGraphPinObject::GetDefaultValueWidget() { if( AllowSelfPinWidget() ) { - UObject* DefaultObject = GraphPinObj->DefaultObject; - if(GraphPinObj->GetSchema()->IsSelfPin(*GraphPinObj)) { return SNew(SEditableTextBox) @@ -162,10 +161,11 @@ FReply SGraphPinObject::OnClickUse() FReply SGraphPinObject::OnClickBrowse() { - if (GraphPinObj->DefaultObject != NULL) + const FAssetData& AssetData = GetAssetData(false); + if (AssetData.IsValid()) { - TArray Objects; - Objects.Add(GraphPinObj->DefaultObject); + TArray Objects; + Objects.Add(AssetData); GEditor->SyncBrowserToObjects(Objects); } @@ -223,8 +223,8 @@ TSharedRef SGraphPinObject::GenerateAssetPicker() void SGraphPinObject::OnAssetSelectedFromPicker(const class FAssetData& AssetData) { - UObject* AssetObject = AssetData.GetAsset(); - if(GraphPinObj->DefaultObject != AssetObject) + const FAssetData& CurrentAssetData = GetAssetData(true); + if(CurrentAssetData != AssetData) { const FScopedTransaction Transaction( NSLOCTEXT("GraphEditor", "ChangeObjectPinValue", "Change Object Pin Value" ) ); GraphPinObj->Modify(); @@ -233,18 +233,18 @@ void SGraphPinObject::OnAssetSelectedFromPicker(const class FAssetData& AssetDat AssetPickerAnchor->SetIsOpen(false); // Set the object found from the asset picker - GraphPinObj->GetSchema()->TrySetDefaultObject(*GraphPinObj, AssetObject); + GraphPinObj->GetSchema()->TrySetDefaultValue(*GraphPinObj, AssetData.ObjectPath.ToString()); } } FText SGraphPinObject::GetValue() const { - UObject* DefaultObject = GraphPinObj->DefaultObject; + const FAssetData& CurrentAssetData = GetAssetData(true); FText Value; - if (DefaultObject != NULL) + if (CurrentAssetData.IsValid()) { - Value = FText::FromString(DefaultObject->GetFullName()); + Value = FText::FromString(CurrentAssetData.GetFullName()); } else { @@ -266,10 +266,10 @@ FText SGraphPinObject::GetObjectName() const if (GraphPinObj != NULL) { - UObject* DefaultObject = GraphPinObj->DefaultObject; - if (DefaultObject != NULL) + const FAssetData& CurrentAssetData = GetAssetData(true); + if (CurrentAssetData.IsValid()) { - Value = FText::FromString(DefaultObject->GetName()); + Value = FText::FromString(CurrentAssetData.AssetName.ToString()); int32 StringLen = Value.ToString().Len(); //If string is too long, then truncate (eg. "abcdefgijklmnopq" is converted as "abcd...nopq") @@ -298,16 +298,18 @@ FText SGraphPinObject::OnGetComboTextValue() const { FText Value = GetDefaultComboText(); - if (GraphPinObj != NULL) + if (GraphPinObj != nullptr) { + const FAssetData& CurrentAssetData = GetAssetData(true); + UObject* DefaultObject = GraphPinObj->DefaultObject; if (UField* Field = Cast(DefaultObject)) { Value = Field->GetDisplayNameText(); } - else if (DefaultObject != NULL) + else if (CurrentAssetData.IsValid()) { - Value = FText::FromString(DefaultObject->GetName()); + Value = FText::FromString(CurrentAssetData.AssetName.ToString()); } } return Value; @@ -315,20 +317,62 @@ FText SGraphPinObject::OnGetComboTextValue() const FSlateColor SGraphPinObject::OnGetComboForeground() const { - float Alpha = IsHovered() ? GraphPinObjectDefs::ActiveComboAlpha : GraphPinObjectDefs::InActiveComboAlpha; + float Alpha = (IsHovered() || bOnlyShowDefaultValue) ? GraphPinObjectDefs::ActiveComboAlpha : GraphPinObjectDefs::InActiveComboAlpha; return FSlateColor( FLinearColor( 1.f, 1.f, 1.f, Alpha ) ); } FSlateColor SGraphPinObject::OnGetWidgetForeground() const { - float Alpha = IsHovered() ? GraphPinObjectDefs::ActivePinForegroundAlpha : GraphPinObjectDefs::InactivePinForegroundAlpha; + float Alpha = (IsHovered() || bOnlyShowDefaultValue) ? GraphPinObjectDefs::ActivePinForegroundAlpha : GraphPinObjectDefs::InactivePinForegroundAlpha; return FSlateColor( FLinearColor( 1.f, 1.f, 1.f, Alpha ) ); } FSlateColor SGraphPinObject::OnGetWidgetBackground() const { - float Alpha = IsHovered() ? GraphPinObjectDefs::ActivePinBackgroundAlpha : GraphPinObjectDefs::InactivePinBackgroundAlpha; + float Alpha = (IsHovered() || bOnlyShowDefaultValue) ? GraphPinObjectDefs::ActivePinBackgroundAlpha : GraphPinObjectDefs::InactivePinBackgroundAlpha; return FSlateColor( FLinearColor( 1.f, 1.f, 1.f, Alpha ) ); } +const FAssetData& SGraphPinObject::GetAssetData(bool bRuntimePath) const +{ + // For normal assets, the editor and runtime path are the same + if (GraphPinObj->DefaultObject) + { + if (!GraphPinObj->DefaultObject->GetPathName().Equals(CachedAssetData.ObjectPath.ToString(), ESearchCase::CaseSensitive)) + { + // This always uses the exact object pointed at + CachedAssetData = FAssetData(GraphPinObj->DefaultObject, true); + } + } + else if (!GraphPinObj->DefaultValue.IsEmpty()) + { + FName ObjectPath = FName(*GraphPinObj->DefaultValue); + if (ObjectPath != CachedAssetData.ObjectPath) + { + const FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(TEXT("AssetRegistry")); + + CachedAssetData = AssetRegistryModule.Get().GetAssetByObjectPath(ObjectPath); + + if (!CachedAssetData.IsValid()) + { + FString PackageName = FPackageName::ObjectPathToPackageName(GraphPinObj->DefaultValue); + FString PackagePath = FPackageName::GetLongPackagePath(PackageName); + FString ObjectName = FPackageName::ObjectPathToObjectName(GraphPinObj->DefaultValue); + + // Fake one + CachedAssetData = FAssetData(FName(*PackageName), FName(*PackagePath), FName(*ObjectName), UObject::StaticClass()->GetFName()); + } + } + } + else + { + if (CachedAssetData.IsValid()) + { + CachedAssetData = FAssetData(); + } + } + + return CachedAssetData; +} + #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Editor/GraphEditor/Private/SGraphEditorImpl.cpp b/Engine/Source/Editor/GraphEditor/Private/SGraphEditorImpl.cpp index 08280bfc7c8d..0fc1e70a23f7 100644 --- a/Engine/Source/Editor/GraphEditor/Private/SGraphEditorImpl.cpp +++ b/Engine/Source/Editor/GraphEditor/Private/SGraphEditorImpl.cpp @@ -725,6 +725,11 @@ void SGraphEditorImpl::SetPinVisibility( SGraphEditor::EPinVisibility InVisibili } } +TSharedRef SGraphEditorImpl::RegisterActiveTimer(float TickPeriod, FWidgetActiveTimerDelegate TickFunction) +{ + return SWidget::RegisterActiveTimer(TickPeriod, TickFunction); +} + EVisibility SGraphEditorImpl::ReadOnlyVisibility() const { if(ShowGraphStateOverlay.Get() && PIENotification() == EVisibility::Hidden && !IsEditable.Get()) diff --git a/Engine/Source/Editor/GraphEditor/Private/SGraphEditorImpl.h b/Engine/Source/Editor/GraphEditor/Private/SGraphEditorImpl.h index 131769b06c9e..4fe81d1b7f26 100644 --- a/Engine/Source/Editor/GraphEditor/Private/SGraphEditorImpl.h +++ b/Engine/Source/Editor/GraphEditor/Private/SGraphEditorImpl.h @@ -152,6 +152,7 @@ public: virtual void UnlockFromGraphEditor(TWeakPtr Other) override; virtual void AddNotification ( FNotificationInfo& Info, bool bSuccess ) override; virtual void SetPinVisibility(SGraphEditor::EPinVisibility Visibility) override; + virtual TSharedRef RegisterActiveTimer(float TickPeriod, FWidgetActiveTimerDelegate TickFunction) override; virtual void StraightenConnections() override; virtual void StraightenConnections(UEdGraphPin* SourcePin, UEdGraphPin* PinToAlign) override; virtual void CaptureKeyboard() override; diff --git a/Engine/Source/Editor/GraphEditor/Private/SGraphNode.cpp b/Engine/Source/Editor/GraphEditor/Private/SGraphNode.cpp index f2943813cff3..bffb2d44e593 100644 --- a/Engine/Source/Editor/GraphEditor/Private/SGraphNode.cpp +++ b/Engine/Source/Editor/GraphEditor/Private/SGraphNode.cpp @@ -291,7 +291,10 @@ FReply SGraphNode::OnDragOver( const FGeometry& MyGeometry, const FDragDropEvent { bool bOkIcon = false; FString TooltipText; - GraphNode->GetSchema()->GetAssetsNodeHoverMessage(AssetOp->AssetData, GraphNode, TooltipText, bOkIcon); + if (AssetOp->HasAssets()) + { + GraphNode->GetSchema()->GetAssetsNodeHoverMessage(AssetOp->GetAssets(), GraphNode, TooltipText, bOkIcon); + } bool bReadOnly = OwnerGraphPanelPtr.IsValid() ? !OwnerGraphPanelPtr.Pin()->IsGraphEditable() : false; bOkIcon = bReadOnly ? false : bOkIcon; const FSlateBrush* TooltipIcon = bOkIcon ? FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.OK")) : FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error"));; @@ -370,7 +373,10 @@ FReply SGraphNode::OnDrop( const FGeometry& MyGeometry, const FDragDropEvent& Dr if(Node != NULL && Node->GetSchema() != NULL) { TSharedPtr AssetOp = StaticCastSharedPtr(Operation); - Node->GetSchema()->DroppedAssetsOnNode(AssetOp->AssetData, DragDropEvent.GetScreenSpacePosition(), Node); + if (AssetOp->HasAssets()) + { + Node->GetSchema()->DroppedAssetsOnNode(AssetOp->GetAssets(), DragDropEvent.GetScreenSpacePosition(), Node); + } } return FReply::Handled(); } diff --git a/Engine/Source/Editor/GraphEditor/Private/SGraphPalette.cpp b/Engine/Source/Editor/GraphEditor/Private/SGraphPalette.cpp index 5d8612b91646..1b14dd411114 100644 --- a/Engine/Source/Editor/GraphEditor/Private/SGraphPalette.cpp +++ b/Engine/Source/Editor/GraphEditor/Private/SGraphPalette.cpp @@ -115,7 +115,7 @@ TSharedRef SGraphPaletteItem::CreateIconWidget(const FText& IconToolTip IDocumentation::Get()->CreateToolTip(IconToolTip, NULL, DocLink, DocExcerpt)); } -TSharedRef SGraphPaletteItem::CreateTextSlotWidget( const FSlateFontInfo& NameFont, FCreateWidgetForActionData* const InCreateData, bool bIsReadOnly ) +TSharedRef SGraphPaletteItem::CreateTextSlotWidget( const FSlateFontInfo& NameFont, FCreateWidgetForActionData* const InCreateData, TAttribute bIsReadOnly ) { TSharedPtr< SWidget > DisplayWidget; @@ -142,10 +142,7 @@ TSharedRef SGraphPaletteItem::CreateTextSlotWidget( const FSlateFontInf .IsSelected( InCreateData->IsRowSelectedDelegate ) .IsReadOnly( bIsReadOnly ); - if(!bIsReadOnly) - { - InCreateData->OnRenameRequest->BindSP( InlineRenameWidget.Get(), &SInlineEditableTextBlock::EnterEditingMode ); - } + InCreateData->OnRenameRequest->BindSP( InlineRenameWidget.Get(), &SInlineEditableTextBlock::EnterEditingMode ); return DisplayWidget.ToSharedRef(); } diff --git a/Engine/Source/Editor/GraphEditor/Private/SGraphPanel.cpp b/Engine/Source/Editor/GraphEditor/Private/SGraphPanel.cpp index fb2a9152e78d..e9bbda1d04ae 100644 --- a/Engine/Source/Editor/GraphEditor/Private/SGraphPanel.cpp +++ b/Engine/Source/Editor/GraphEditor/Private/SGraphPanel.cpp @@ -908,7 +908,10 @@ FReply SGraphPanel::OnDragOver( const FGeometry& MyGeometry, const FDragDropEven TSharedPtr AssetOp = StaticCastSharedPtr(Operation); bool bOkIcon = false; FString TooltipText; - GraphObj->GetSchema()->GetAssetsGraphHoverMessage(AssetOp->AssetData, GraphObj, TooltipText, bOkIcon); + if (AssetOp->HasAssets()) + { + GraphObj->GetSchema()->GetAssetsGraphHoverMessage(AssetOp->GetAssets(), GraphObj, TooltipText, bOkIcon); + } const FSlateBrush* TooltipIcon = bOkIcon ? FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.OK")) : FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error"));; AssetOp->SetToolTip(FText::FromString(TooltipText), TooltipIcon); } diff --git a/Engine/Source/Editor/GraphEditor/Private/SGraphPin.cpp b/Engine/Source/Editor/GraphEditor/Private/SGraphPin.cpp index 1849433cc176..965958dcc551 100644 --- a/Engine/Source/Editor/GraphEditor/Private/SGraphPin.cpp +++ b/Engine/Source/Editor/GraphEditor/Private/SGraphPin.cpp @@ -68,6 +68,7 @@ TSharedPtr FGraphPinHandle::FindInGraphPanel(const SGraphPanel& InPan SGraphPin::SGraphPin() : GraphPinObj(nullptr) , bShowLabel(true) + , bOnlyShowDefaultValue(false) , bIsMovingLinks(false) , PinColorModifier(FLinearColor::White) , CachedNodeOffset(FVector2D::ZeroVector) @@ -154,11 +155,18 @@ void SGraphPin::Construct(const FArguments& InArgs, UEdGraphPin* InPin) const bool bIsInput = (GetDirection() == EGPD_Input); // Create the pin icon widget - TSharedRef ActualPinWidget = SPinTypeSelector::ConstructPinTypeImage( + TSharedRef PinWidgetRef = SPinTypeSelector::ConstructPinTypeImage( TAttribute::Create( TAttribute::FGetter::CreateRaw(this, &SGraphPin::GetPinIcon ) ), TAttribute::Create( TAttribute::FGetter::CreateRaw(this, &SGraphPin::GetPinColor) ), TAttribute::Create( TAttribute::FGetter::CreateRaw(this, &SGraphPin::GetSecondaryPinIcon ) ), TAttribute::Create( TAttribute::FGetter::CreateRaw(this, &SGraphPin::GetSecondaryPinColor) )); + PinImage = PinWidgetRef; + + PinWidgetRef->SetCursor( + TAttribute >::Create ( + TAttribute >::FGetter::CreateRaw( this, &SGraphPin::GetPinCursor ) + ) + ); // Create the pin indicator widget (used for watched values) static const FName NAME_NoBorder("NoBorder"); @@ -241,7 +249,7 @@ void SGraphPin::Construct(const FArguments& InArgs, UEdGraphPin* InPin) .VAlign(VAlign_Center) .Padding(0, 0, InArgs._SideToSideMargin, 0) [ - ActualPinWidget + PinWidgetRef ] +SHorizontalBox::Slot() .AutoWidth() @@ -265,7 +273,7 @@ void SGraphPin::Construct(const FArguments& InArgs, UEdGraphPin* InPin) .VAlign(VAlign_Center) .Padding(InArgs._SideToSideMargin, 0, 0, 0) [ - ActualPinWidget + PinWidgetRef ]; } @@ -280,7 +288,7 @@ void SGraphPin::Construct(const FArguments& InArgs, UEdGraphPin* InPin) .LowDetail() [ //@TODO: Try creating a pin-colored line replacement that doesn't measure text / call delegates but still renders - ActualPinWidget + PinWidgetRef ] .HighDetail() [ @@ -295,16 +303,14 @@ void SGraphPin::Construct(const FArguments& InArgs, UEdGraphPin* InPin) TSharedRef SGraphPin::GetDefaultValueWidget() { - return SNew(SBox); + return SNullWidget::NullWidget; } - void SGraphPin::SetIsEditable(TAttribute InIsEditable) { IsEditable = InIsEditable; } - FReply SGraphPin::OnPinMouseDown( const FGeometry& SenderGeometry, const FPointerEvent& MouseEvent ) { bIsMovingLinks = false; @@ -655,7 +661,10 @@ void SGraphPin::OnDragEnter( const FGeometry& MyGeometry, const FDragDropEvent& TSharedPtr AssetOp = StaticCastSharedPtr(Operation); bool bOkIcon = false; FString TooltipText; - Node->GetSchema()->GetAssetsPinHoverMessage(AssetOp->AssetData, GraphPinObj, TooltipText, bOkIcon); + if (AssetOp->HasAssets()) + { + Node->GetSchema()->GetAssetsPinHoverMessage(AssetOp->GetAssets(), GraphPinObj, TooltipText, bOkIcon); + } const FSlateBrush* TooltipIcon = bOkIcon ? FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.OK")) : FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error"));; AssetOp->SetToolTip(FText::FromString(TooltipText), TooltipIcon); } @@ -754,8 +763,10 @@ FReply SGraphPin::OnDrop( const FGeometry& MyGeometry, const FDragDropEvent& Dra if(Node != NULL && Node->GetSchema() != NULL) { TSharedPtr AssetOp = StaticCastSharedPtr(Operation); - - Node->GetSchema()->DroppedAssetsOnPin(AssetOp->AssetData, DragDropEvent.GetScreenSpacePosition(), GraphPinObj); + if (AssetOp->HasAssets()) + { + Node->GetSchema()->DroppedAssetsOnPin(AssetOp->GetAssets(), DragDropEvent.GetScreenSpacePosition(), GraphPinObj); + } } return FReply::Handled(); } @@ -820,22 +831,17 @@ EEdGraphPinDirection SGraphPin::GetDirection() const bool SGraphPin::IsArray() const { - return GraphPinObj->PinType.bIsArray; + return GraphPinObj->PinType.IsArray(); } bool SGraphPin::IsSet() const { - return GraphPinObj->PinType.bIsSet; + return GraphPinObj->PinType.IsSet(); } bool SGraphPin::IsMap() const { - return GraphPinObj->PinType.bIsMap; -} - -bool SGraphPin::IsByRef() const -{ - return GraphPinObj->PinType.bIsReference; + return GraphPinObj->PinType.IsMap(); } bool SGraphPin::IsByMutableRef() const @@ -849,11 +855,6 @@ bool SGraphPin::IsDelegate() const return Schema && Schema->IsDelegateCategory(GraphPinObj->PinType.PinCategory); } -bool SGraphPin::IsByConstRef() const -{ - return GraphPinObj->PinType.bIsReference && GraphPinObj->PinType.bIsConst; -} - /** @return whether this pin is connected to another pin */ bool SGraphPin::IsConnected() const { @@ -920,7 +921,7 @@ const FSlateBrush* SGraphPin::GetPinIcon() const const FSlateBrush* SGraphPin::GetSecondaryPinIcon() const { - if( !GraphPinObj->IsPendingKill() && GraphPinObj->PinType.bIsMap ) + if( !GraphPinObj->IsPendingKill() && GraphPinObj->PinType.IsMap() ) { return CachedImg_MapPinValue; } @@ -937,7 +938,7 @@ const FSlateBrush* SGraphPin::GetPinBorder() const bIsMarkedPin = (OwnerPanelPtr->MarkedPin.Pin() == SharedThis(this)); } - return (IsHovered() || bIsMarkedPin || GraphPinObj->bIsDiffing) ? CachedImg_Pin_BackgroundHovered : CachedImg_Pin_Background; + return (IsHovered() || bIsMarkedPin || GraphPinObj->bIsDiffing || bOnlyShowDefaultValue) ? CachedImg_Pin_BackgroundHovered : CachedImg_Pin_Background; } @@ -1037,6 +1038,12 @@ FReply SGraphPin::ClickedOnPinStatusIcon() EVisibility SGraphPin::GetDefaultValueVisibility() const { + // If this is only for showing default value, always show + if (bOnlyShowDefaultValue) + { + return EVisibility::Visible; + } + // First ask schema const UEdGraphSchema* Schema = !GraphPinObj->IsPendingKill() ? GraphPinObj->GetSchema() : nullptr; if (Schema == nullptr || Schema->ShouldHidePinDefaultValue(GraphPinObj)) @@ -1066,6 +1073,11 @@ void SGraphPin::SetShowLabel(bool bNewShowLabel) bShowLabel = bNewShowLabel; } +void SGraphPin::SetOnlyShowDefaultValue(bool bNewOnlyShowDefaultValue) +{ + bOnlyShowDefaultValue = bNewOnlyShowDefaultValue; +} + FText SGraphPin::GetTooltipText() const { FText HoverText = FText::GetEmpty(); diff --git a/Engine/Source/Editor/GraphEditor/Public/GraphEditorActions.h b/Engine/Source/Editor/GraphEditor/Public/GraphEditorActions.h index ce39218e2c1f..00ff489fe3a2 100644 --- a/Engine/Source/Editor/GraphEditor/Public/GraphEditorActions.h +++ b/Engine/Source/Editor/GraphEditor/Public/GraphEditorActions.h @@ -104,6 +104,7 @@ public: TSharedPtr< FUICommandInfo > RecombineStructPin; TSharedPtr< FUICommandInfo > StartWatchingPin; TSharedPtr< FUICommandInfo > StopWatchingPin; + TSharedPtr< FUICommandInfo > ResetPinToDefaultValue; // SkeletalControl specific commands TSharedPtr< FUICommandInfo > SelectBone; diff --git a/Engine/Source/Editor/GraphEditor/Public/GraphEditorDragDropAction.h b/Engine/Source/Editor/GraphEditor/Public/GraphEditorDragDropAction.h index 10fdd35aa996..0441a8f06291 100644 --- a/Engine/Source/Editor/GraphEditor/Public/GraphEditorDragDropAction.h +++ b/Engine/Source/Editor/GraphEditor/Public/GraphEditorDragDropAction.h @@ -15,6 +15,9 @@ class SGraphPanel; class SWidget; class UEdGraph; struct FSlateBrush; +class UEdGraphPin; +class UEdGraphNode; +class UEdGraphSchema; // Base class for drag-drop actions that pass into the graph editor and perform an action when dropped class GRAPHEDITOR_API FGraphEditorDragDropAction : public FDragDropOperation @@ -22,9 +25,10 @@ class GRAPHEDITOR_API FGraphEditorDragDropAction : public FDragDropOperation public: DRAG_DROP_OPERATOR_TYPE(FGraphEditorDragDropAction, FDragDropOperation) - void SetHoveredPin(class UEdGraphPin* InPin); - void SetHoveredNode(const TSharedPtr& InNode); - void SetHoveredGraph(const TSharedPtr& InGraph); + void SetHoveredPin(UEdGraphPin* InPin); + void SetHoveredNode(const TSharedPtr& InNode); + void SetHoveredNode(UEdGraphNode* InNode); + void SetHoveredGraph(const TSharedPtr& InGraph); void SetHoveredCategoryName(const FText& InHoverCategoryName); void SetHoveredAction(TSharedPtr Action); void SetDropTargetValid( bool bValid ) { bDropTargetValid = bValid; } @@ -33,12 +37,12 @@ public: virtual void HoverTargetChanged() {} virtual FReply DroppedOnPin(FVector2D ScreenPosition, FVector2D GraphPosition) { return FReply::Unhandled(); } virtual FReply DroppedOnNode(FVector2D ScreenPosition, FVector2D GraphPosition) { return FReply::Unhandled(); } - virtual FReply DroppedOnPanel( const TSharedRef< class SWidget >& Panel, FVector2D ScreenPosition, FVector2D GraphPosition, UEdGraph& Graph) { return FReply::Unhandled(); } + virtual FReply DroppedOnPanel( const TSharedRef< SWidget >& Panel, FVector2D ScreenPosition, FVector2D GraphPosition, UEdGraph& Graph) { return FReply::Unhandled(); } virtual FReply DroppedOnAction(TSharedRef Action) { return FReply::Unhandled(); } virtual FReply DroppedOnCategory(FText Category) { return FReply::Unhandled(); } // End of interface to override - virtual bool IsSupportedBySchema(const class UEdGraphSchema* Schema) const { return true; } + virtual bool IsSupportedBySchema(const UEdGraphSchema* Schema) const { return true; } bool HasFeedbackMessage(); void SetFeedbackMessage(const TSharedPtr& Message); @@ -61,10 +65,10 @@ private: FEdGraphPinReference HoveredPin; // The node that the drag action is currently hovering over - TSharedPtr HoveredNode; + TWeakObjectPtr HoveredNode; // The graph that the drag action is currently hovering over - TSharedPtr HoveredGraph; + TSharedPtr HoveredGraph; protected: @@ -87,7 +91,8 @@ public: // FGraphEditorDragDropAction interface virtual void HoverTargetChanged() override; - virtual FReply DroppedOnPanel( const TSharedRef< class SWidget >& Panel, FVector2D ScreenPosition, FVector2D GraphPosition, UEdGraph& Graph) override; + virtual FReply DroppedOnPanel(const TSharedRef< SWidget >& Panel, FVector2D ScreenPosition, FVector2D GraphPosition, UEdGraph& Graph) override; + virtual FReply DroppedOnPin(FVector2D ScreenPosition, FVector2D GraphPosition) override; // End of FGraphEditorDragDropAction static TSharedRef New(TSharedPtr InActionNode ) diff --git a/Engine/Source/Editor/GraphEditor/Public/KismetPins/SGraphPinExec.h b/Engine/Source/Editor/GraphEditor/Public/KismetPins/SGraphPinExec.h index 37e9669a8b67..4c7a5d8e24f1 100644 --- a/Engine/Source/Editor/GraphEditor/Public/KismetPins/SGraphPinExec.h +++ b/Engine/Source/Editor/GraphEditor/Public/KismetPins/SGraphPinExec.h @@ -21,9 +21,8 @@ protected: virtual const FSlateBrush* GetPinIcon() const override; //~ End SGraphPin Interface -protected: - mutable bool bWasEventPin; + void CachePinIcons(); - mutable const FSlateBrush* CachedImg_Pin_ConnectedHovered; - mutable const FSlateBrush* CachedImg_Pin_DisconnectedHovered; + const FSlateBrush* CachedImg_Pin_ConnectedHovered; + const FSlateBrush* CachedImg_Pin_DisconnectedHovered; }; diff --git a/Engine/Source/Editor/GraphEditor/Public/KismetPins/SGraphPinObject.h b/Engine/Source/Editor/GraphEditor/Public/KismetPins/SGraphPinObject.h index 6a34da42b367..18e7188224ba 100644 --- a/Engine/Source/Editor/GraphEditor/Public/KismetPins/SGraphPinObject.h +++ b/Engine/Source/Editor/GraphEditor/Public/KismetPins/SGraphPinObject.h @@ -60,6 +60,9 @@ protected: /** Button Color and Opacity delegate */ FSlateColor OnGetWidgetBackground() const; + /** Returns asset data of currently selected object, if bRuntimePath is true this will include _C for blueprint classes, for false it will point to UBlueprint instead */ + virtual const FAssetData& GetAssetData(bool bRuntimePath) const; + protected: /** Object manipulator buttons. */ TSharedPtr UseButton; @@ -67,4 +70,7 @@ protected: /** Menu anchor for opening and closing the asset picker */ TSharedPtr AssetPickerAnchor; + + /** Cached AssetData of object selected */ + mutable FAssetData CachedAssetData; }; diff --git a/Engine/Source/Editor/GraphEditor/Private/NodeFactory.h b/Engine/Source/Editor/GraphEditor/Public/NodeFactory.h similarity index 100% rename from Engine/Source/Editor/GraphEditor/Private/NodeFactory.h rename to Engine/Source/Editor/GraphEditor/Public/NodeFactory.h diff --git a/Engine/Source/Editor/GraphEditor/Public/SGraphPalette.h b/Engine/Source/Editor/GraphEditor/Public/SGraphPalette.h index e18080e83a2b..abc54b80d636 100644 --- a/Engine/Source/Editor/GraphEditor/Public/SGraphPalette.h +++ b/Engine/Source/Editor/GraphEditor/Public/SGraphPalette.h @@ -43,7 +43,7 @@ protected: TSharedRef CreateIconWidget(const FText& IconToolTip, const FSlateBrush* IconBrush, const FSlateColor& IconColor); /* Create the text widget */ - virtual TSharedRef CreateTextSlotWidget( const FSlateFontInfo& NameFont, FCreateWidgetForActionData* const InCreateData, bool bIsReadOnly ); + virtual TSharedRef CreateTextSlotWidget( const FSlateFontInfo& NameFont, FCreateWidgetForActionData* const InCreateData, TAttribute bIsReadOnly ); /** Callback when rename text is being verified on text changed */ virtual bool OnNameTextVerifyChanged(const FText& InNewText, FText& OutErrorMessage); diff --git a/Engine/Source/Editor/GraphEditor/Public/SGraphPin.h b/Engine/Source/Editor/GraphEditor/Public/SGraphPin.h index a1d44edd21fc..f20b1186249b 100644 --- a/Engine/Source/Editor/GraphEditor/Public/SGraphPin.h +++ b/Engine/Source/Editor/GraphEditor/Public/SGraphPin.h @@ -137,18 +137,12 @@ public: /** @return whether this pin is a map value */ bool IsMap() const; - /** @return whether this pin is passed by ref */ - bool IsByRef() const; - /** @return whether this pin is passed by mutable ref */ bool IsByMutableRef() const; /** @return whether this pin is passed by mutable ref */ bool IsDelegate() const; - /** @return whether this pin is passed by const ref */ - bool IsByConstRef() const; - /** @return whether this pin is connected to another pin */ bool IsConnected() const; @@ -172,6 +166,9 @@ public: PinColorModifier = InColor; } + /** Set this pin to only be used to display default value */ + void SetOnlyShowDefaultValue(bool bNewOnlyShowDefaultValue); + /** If pin in node is visible at all */ EVisibility IsPinVisibleAsAdvanced() const; @@ -181,6 +178,9 @@ public: /** Returns whether or not this pin is currently connectable */ bool GetIsConnectable() const; + /** Get the widget we should put into the 'default value' space, shown when nothing connected */ + virtual TSharedRef GetDefaultValueWidget(); + protected: FText GetPinLabel() const; @@ -190,9 +190,6 @@ protected: return bShowLabel ? EVisibility::Visible : EVisibility::Collapsed; } - /** Get the widget we should put into the 'default value' space, shown when nothing connected */ - virtual TSharedRef GetDefaultValueWidget(); - /** @return The brush with which to paint this graph pin's incoming/outgoing bullet point */ virtual const FSlateBrush* GetPinIcon() const; @@ -241,7 +238,7 @@ protected: TWeakPtr OwnerNodePtr; /** Image of pin */ - TSharedPtr PinImage; + TSharedPtr PinImage; /** Horizontal box that holds the full detail pin widget, useful for outsiders to inject widgets into the pin */ TWeakPtr FullPinHorizontalRowWidget; @@ -255,6 +252,9 @@ protected: /** If we should draw the label on this pin */ bool bShowLabel; + /** If we should draw the label on this pin */ + bool bOnlyShowDefaultValue; + /** true when we're moving links between pins. */ bool bIsMovingLinks; diff --git a/Engine/Source/Editor/HierarchicalLODOutliner/Private/LODActorItem.cpp b/Engine/Source/Editor/HierarchicalLODOutliner/Private/LODActorItem.cpp index d61fb21018f9..eb205f7e6598 100644 --- a/Engine/Source/Editor/HierarchicalLODOutliner/Private/LODActorItem.cpp +++ b/Engine/Source/Editor/HierarchicalLODOutliner/Private/LODActorItem.cpp @@ -185,7 +185,7 @@ HLODOutliner::FDragValidationInfo HLODOutliner::FLODActorDropTarget::ValidateDro { if (DraggedObjects.StaticMeshActors.IsSet() && DraggedObjects.StaticMeshActors->Num() > 0) { - if (DraggedObjects.StaticMeshActors->Num() > 0 && DraggedObjects.LODActors->Num() == 0) + if (DraggedObjects.LODActors->Num() == 0) { if (DraggedObjects.bSceneOutliner == false) { diff --git a/Engine/Source/Editor/IntroTutorials/Private/IntroTutorials.cpp b/Engine/Source/Editor/IntroTutorials/Private/IntroTutorials.cpp index 5fdda0bd58e0..554a8c9b70df 100644 --- a/Engine/Source/Editor/IntroTutorials/Private/IntroTutorials.cpp +++ b/Engine/Source/Editor/IntroTutorials/Private/IntroTutorials.cpp @@ -327,14 +327,18 @@ bool FIntroTutorials::MaybeOpenWelcomeTutorial() } // Try project startup tutorial - TSubclassOf ProjectStartupTutorialClass = LoadClass(NULL, *GetDefault()->StartupTutorial.ToString(), NULL, LOAD_None, NULL); - if(ProjectStartupTutorialClass != nullptr) + const FString ProjectStartupTutorialPathStr = GetDefault()->StartupTutorial.ToString(); + if (!ProjectStartupTutorialPathStr.IsEmpty()) { - UEditorTutorial* Tutorial = ProjectStartupTutorialClass->GetDefaultObject(); - if (!GetDefault()->HaveSeenTutorial(Tutorial)) + TSubclassOf ProjectStartupTutorialClass = LoadClass(NULL, *ProjectStartupTutorialPathStr, NULL, LOAD_None, NULL); + if (ProjectStartupTutorialClass != nullptr) { - LaunchTutorial(Tutorial); - return true; + UEditorTutorial* Tutorial = ProjectStartupTutorialClass->GetDefaultObject(); + if (!GetDefault()->HaveSeenTutorial(Tutorial)) + { + LaunchTutorial(Tutorial); + return true; + } } } } diff --git a/Engine/Source/Editor/Kismet/Private/BPFunctionDragDropAction.cpp b/Engine/Source/Editor/Kismet/Private/BPFunctionDragDropAction.cpp index e7dec6292721..7042f8222ccc 100644 --- a/Engine/Source/Editor/Kismet/Private/BPFunctionDragDropAction.cpp +++ b/Engine/Source/Editor/Kismet/Private/BPFunctionDragDropAction.cpp @@ -221,27 +221,44 @@ void FKismetFunctionDragDropAction::HoverTargetChanged() //------------------------------------------------------------------------------ FReply FKismetFunctionDragDropAction::DroppedOnPanel(TSharedRef const& Panel, FVector2D ScreenPosition, FVector2D GraphPosition, UEdGraph& Graph) -{ +{ + return DroppedOnPin(ScreenPosition, GraphPosition); +} + +//------------------------------------------------------------------------------ +FReply FKismetFunctionDragDropAction::DroppedOnPin(FVector2D ScreenPosition, FVector2D GraphPosition) +{ FReply Reply = FReply::Unhandled(); + UEdGraph* Graph = GetHoveredGraph(); + check(Graph); + // The ActionNode set during construction points to the Graph, this is suitable for displaying the mouse decorator but needs to be more complete based on the current graph - UBlueprintFunctionNodeSpawner* FunctionNodeSpawner = nullptr; - FunctionNodeSpawner = GetDropAction(Graph); + UBlueprintFunctionNodeSpawner* FunctionNodeSpawner = GetDropAction(*Graph); if (FunctionNodeSpawner) { FText CannotDropReason = FText::GetEmpty(); - if (!CanBeDroppedDelegate.IsBound() || CanBeDroppedDelegate.Execute(nullptr, GetHoveredGraph(), CannotDropReason)) + if (!CanBeDroppedDelegate.IsBound() || CanBeDroppedDelegate.Execute(nullptr, Graph, CannotDropReason)) { UFunction const* Function = GetFunctionProperty(); if ((Function != NULL) && UEdGraphSchema_K2::CanUserKismetCallFunction(Function)) { AnalyticCallback.ExecuteIfBound(); - const FScopedTransaction Transaction( LOCTEXT("KismetFunction_DroppedOnPanel", "Function Dropped on Graph") ); + const FScopedTransaction Transaction(LOCTEXT("KismetFunction_DroppedOnPanel", "Function Dropped on Graph")); IBlueprintNodeBinder::FBindingSet Bindings; - FunctionNodeSpawner->Invoke(&Graph, Bindings, GraphPosition); + UEdGraphNode* ResultNode = FunctionNodeSpawner->Invoke(Graph, Bindings, GraphPosition); + + // Autowire the node if we were dragging on top of a pin + if (ResultNode != nullptr) + { + if (UEdGraphPin* FromPin = GetHoveredPin()) + { + ResultNode->AutowireNewNode(FromPin); + } + } Reply = FReply::Handled(); } diff --git a/Engine/Source/Editor/Kismet/Private/BPFunctionDragDropAction.h b/Engine/Source/Editor/Kismet/Private/BPFunctionDragDropAction.h index 65008cc272eb..ea600eb690ad 100644 --- a/Engine/Source/Editor/Kismet/Private/BPFunctionDragDropAction.h +++ b/Engine/Source/Editor/Kismet/Private/BPFunctionDragDropAction.h @@ -62,6 +62,7 @@ public: // FGraphEditorDragDropAction interface virtual void HoverTargetChanged() override; virtual FReply DroppedOnPanel( const TSharedRef< class SWidget >& Panel, FVector2D ScreenPosition, FVector2D GraphPosition, UEdGraph& Graph) override; + virtual FReply DroppedOnPin(FVector2D ScreenPosition, FVector2D GraphPosition) override; // End of FGraphEditorDragDropAction static TSharedRef New(TSharedPtr InActionNode, FName InFunctionName, UClass* InOwningClass, const FMemberReference& InCallOnMember, FNodeCreationAnalytic AnalyticCallback, FCanBeDroppedDelegate CanBeDroppedDelegate = FCanBeDroppedDelegate()); diff --git a/Engine/Source/Editor/Kismet/Private/BPVariableDragDropAction.cpp b/Engine/Source/Editor/Kismet/Private/BPVariableDragDropAction.cpp index 8fb241526e51..d92937013a40 100644 --- a/Engine/Source/Editor/Kismet/Private/BPVariableDragDropAction.cpp +++ b/Engine/Source/Editor/Kismet/Private/BPVariableDragDropAction.cpp @@ -126,15 +126,16 @@ void FKismetVariableDragDropAction::HoverTargetChanged() if(CanVariableBeDropped(VariableProperty, *PinUnderCursor->GetOwningNode()->GetGraph())) { const UEdGraphSchema_K2* Schema = CastChecked(PinUnderCursor->GetSchema()); + const bool bIsExecPin = Schema->IsExecPin(*PinUnderCursor); - const bool bIsRead = PinUnderCursor->Direction == EGPD_Input; + const bool bIsRead = (PinUnderCursor->Direction == EGPD_Input) && !bIsExecPin; const UBlueprint* Blueprint = FBlueprintEditorUtils::FindBlueprintForNode(PinUnderCursor->GetOwningNode()); const bool bReadOnlyProperty = FBlueprintEditorUtils::IsPropertyReadOnlyInCurrentBlueprint(Blueprint, VariableProperty); const bool bCanWriteIfNeeded = bIsRead || !bReadOnlyProperty; FEdGraphPinType VariablePinType; Schema->ConvertPropertyToPinType(VariableProperty, VariablePinType); - const bool bTypeMatch = Schema->ArePinTypesCompatible(VariablePinType, PinUnderCursor->PinType); + const bool bTypeMatch = Schema->ArePinTypesCompatible(VariablePinType, PinUnderCursor->PinType) || bIsExecPin; Args.Add(TEXT("PinUnderCursor"), FText::FromString(PinUnderCursor->PinName)); @@ -329,18 +330,20 @@ FReply FKismetVariableDragDropAction::DroppedOnPin(FVector2D ScreenPosition, FVe { if (const UEdGraphSchema_K2* Schema = CastChecked(TargetPin->GetSchema())) { + const bool bIsExecPin = Schema->IsExecPin(*TargetPin); + UProperty* VariableProperty = GetVariableProperty(); if(CanVariableBeDropped(VariableProperty, *TargetPin->GetOwningNode()->GetGraph())) { - const bool bIsRead = TargetPin->Direction == EGPD_Input; + const bool bIsRead = (TargetPin->Direction == EGPD_Input) && !bIsExecPin; const UBlueprint* Blueprint = FBlueprintEditorUtils::FindBlueprintForNode(TargetPin->GetOwningNode()); const bool bReadOnlyProperty = FBlueprintEditorUtils::IsPropertyReadOnlyInCurrentBlueprint(Blueprint, VariableProperty); const bool bCanWriteIfNeeded = bIsRead || !bReadOnlyProperty; FEdGraphPinType VariablePinType; Schema->ConvertPropertyToPinType(VariableProperty, VariablePinType); - const bool bTypeMatch = Schema->ArePinTypesCompatible(VariablePinType, TargetPin->PinType); + const bool bTypeMatch = Schema->ArePinTypesCompatible(VariablePinType, TargetPin->PinType) || bIsExecPin; if (bTypeMatch && bCanWriteIfNeeded) { diff --git a/Engine/Source/Editor/Kismet/Private/BitmaskLiteralDetails.cpp b/Engine/Source/Editor/Kismet/Private/BitmaskLiteralDetails.cpp index 4204a2d25f7c..971bebccaa6c 100644 --- a/Engine/Source/Editor/Kismet/Private/BitmaskLiteralDetails.cpp +++ b/Engine/Source/Editor/Kismet/Private/BitmaskLiteralDetails.cpp @@ -96,7 +96,7 @@ void FBitmaskLiteralDetails::OnBitmaskEnumTypeChanged(TSharedPtr ItemSe { if (const UEdGraphSchema_K2* K2Schema = Cast(InputPin->GetSchema())) { - K2Schema->SetPinDefaultValueBasedOnType(InputPin); + K2Schema->SetPinAutogeneratedDefaultValueBasedOnType(InputPin); } } } diff --git a/Engine/Source/Editor/Kismet/Private/BlueprintCompilationManager.cpp b/Engine/Source/Editor/Kismet/Private/BlueprintCompilationManager.cpp index a49370af9432..4efa1288004b 100644 --- a/Engine/Source/Editor/Kismet/Private/BlueprintCompilationManager.cpp +++ b/Engine/Source/Editor/Kismet/Private/BlueprintCompilationManager.cpp @@ -6,10 +6,13 @@ #include "Blueprint/BlueprintSupport.h" #include "CompilerResultsLog.h" #include "Components/TimelineComponent.h" +#include "Editor.h" #include "Engine/Engine.h" +#include "Engine/LevelScriptBlueprint.h" #include "Engine/SCS_Node.h" #include "Engine/SimpleConstructionScript.h" #include "Engine/TimelineTemplate.h" +#include "FindInBlueprintManager.h" #include "K2Node_CustomEvent.h" #include "K2Node_FunctionEntry.h" #include "K2Node_FunctionResult.h" @@ -24,119 +27,49 @@ #include "UObject/UObjectHash.h" #include "WidgetBlueprint.h" +/* + BLUEPRINT COMPILATION MANAGER IMPLEMENTATION NOTES + + INPUTS: UBlueprint, UEdGraph, UEdGraphNode, UEdGraphPin, references to UClass, UProperties + INTERMEDIATES: Cloned Graph, Nodes, Pins + OUPUTS: UClass, UProperties + + The blueprint compilation manager addresses shortcomings of compilation + behavior (performance, correctness) that occur when compiling blueprints + that are inter-dependent. If you are using blueprints and there are no dependencies + between blueprint compilation outputs and inputs, then this code is completely + unnecessary and you can directly interface with FKismetCompilerContext and its + derivatives. + + In order to handle compilation correctly the manager splits compilation into + the following stages (implemented below in FlushCompilationQueueImpl): + + STAGE I: GATHER + STAGE II: FILTER + STAGE III: SORT + STAGE IV: SET TEMPORARY BLUEPRINT FLAGS + STAGE V: VALIDATE + STAGE VI: PURGE (LOAD ONLY) + STAGE VII: DISCARD SKELETON CDO + STAGE VIII: RECOMPILE SKELETON + STAGE IX: RECONSTRUCT NODES, REPLACE DEPRECATED NODES (LOAD ONLY) + STAGE X: CREATE REINSTANCER (DISCARD 'OLD' CLASS) + STAGE XI: CREATE UPDATED CLASS HIERARCHY + STAGE XII: COMPILE CLASS LAYOUT + STAGE XIII: COMPILE CLASS FUNCTIONS + STAGE XIV: REINSTANCE + STAGE XV: CLEAR TEMPORARY FLAGS + + The code that implements these stages are labeled below. At some later point a final + reinstancing operation will occur, unless the client is using CompileSynchronously, + in which case the expensive object graph find and replace will occur immediately +*/ + // Debugging switches: #define VERIFY_NO_STALE_CLASS_REFERENCES 0 #define VERIFY_NO_BAD_SKELETON_REFERENCES 0 -class FFixupBytecodeReferences : public FArchiveUObject -{ -public: - FFixupBytecodeReferences(UObject* InObject) - { - ArIsObjectReferenceCollector = true; - - InObject->Serialize(*this); - class FArchiveProxyCollector : public FReferenceCollector - { - /** Archive we are a proxy for */ - FArchive& Archive; - public: - FArchiveProxyCollector(FArchive& InArchive) - : Archive(InArchive) - { - } - virtual void HandleObjectReference(UObject*& Object, const UObject* ReferencingObject, const UProperty* ReferencingProperty) override - { - Archive << Object; - } - virtual void HandleObjectReferences(UObject** InObjects, const int32 ObjectNum, const UObject* InReferencingObject, const UProperty* InReferencingProperty) override - { - for (int32 ObjectIndex = 0; ObjectIndex < ObjectNum; ++ObjectIndex) - { - UObject*& Object = InObjects[ObjectIndex]; - Archive << Object; - } - } - virtual bool IsIgnoringArchetypeRef() const override - { - return false; - } - virtual bool IsIgnoringTransient() const override - { - return false; - } - } ArchiveProxyCollector(*this); - - InObject->GetClass()->CallAddReferencedObjects(InObject, ArchiveProxyCollector); - } - - FArchive& operator<<( UObject*& Obj ) - { - if (Obj != NULL) - { - if(UClass* RelatedClass = Cast(Obj)) - { - UClass* NewClass = RelatedClass->GetAuthoritativeClass(); - ensure(NewClass); - if(NewClass != RelatedClass) - { - Obj = NewClass; - } - } - else if(UField* AsField = Cast(Obj)) - { - UClass* OwningClass = AsField->GetOwnerClass(); - if(OwningClass) - { - UClass* NewClass = OwningClass->GetAuthoritativeClass(); - ensure(NewClass); - if(NewClass != OwningClass) - { - // drill into new class finding equivalent object: - TArray Names; - UObject* Iter = Obj; - while (Iter && Iter != OwningClass) - { - Names.Add(Iter->GetFName()); - Iter = Iter->GetOuter(); - } - - UObject* Owner = NewClass; - UObject* Match = nullptr; - for(int32 I = Names.Num() - 1; I >= 0; --I) - { - UObject* Next = StaticFindObjectFast( UObject::StaticClass(), Owner, Names[I]); - if( Next ) - { - if(I == 0) - { - Match = Next; - } - else - { - Owner = Match; - } - } - else - { - break; - } - } - - if(Match) - { - Obj = Match; - } - } - } - } - } - return *this; - } -}; - -// free function that we use to cross a module boundary (from CoreUObject to here) -void FlushReinstancingQueueImplWrapper(); +struct FReinstancingJob; struct FBlueprintCompilationManagerImpl : public FGCObject { @@ -146,19 +79,40 @@ struct FBlueprintCompilationManagerImpl : public FGCObject // FGCObject: virtual void AddReferencedObjects(FReferenceCollector& Collector); - void QueueForCompilation(UBlueprint* BPToCompile); - void FlushCompilationQueueImpl(TArray* ObjLoaded); + void QueueForCompilation(const FBPCompileRequest& CompileJob); + void CompileSynchronouslyImpl(const FBPCompileRequest& Request); + void FlushCompilationQueueImpl(TArray* ObjLoaded, bool bSuppressBroadcastCompiled); void FlushReinstancingQueueImpl(); bool HasBlueprintsToCompile() const; bool IsGeneratedClassLayoutReady() const; - static void ReinstanceBatch(TArray>& Reinstancers, TMap< UClass*, UClass* >& InOutOldToNewClassMap, TArray* ObjLoaded); + static void ReinstanceBatch(TArray& Reinstancers, TMap< UClass*, UClass* >& InOutOldToNewClassMap, TArray* ObjLoaded); static UClass* FastGenerateSkeletonClass(UBlueprint* BP, FKismetCompilerContext& CompilerContext); + static bool IsQueuedForCompilation(UBlueprint* BP); + + // Declaration of archive to fix up bytecode references of blueprints that are actively compiled: + class FFixupBytecodeReferences : public FArchiveUObject + { + public: + FFixupBytecodeReferences(UObject* InObject); - TArray QueuedBPs; + private: + virtual FArchive& operator<<( UObject*& Obj ) override; + }; + + // Queued requests to be processed in the next FlushCompilationQueueImpl call: + TArray QueuedRequests; + + // Data stored for reinstancing, which finishes much later than compilation, + // populated by FlushCompilationQueueImpl, cleared by FlushReinstancingQueueImpl: TMap ClassesToReinstance; + + // State stored so that we can check what stage of compilation we're in: bool bGeneratedClassLayoutReady; }; +// free function that we use to cross a module boundary (from CoreUObject to here) +void FlushReinstancingQueueImplWrapper(); + FBlueprintCompilationManagerImpl::FBlueprintCompilationManagerImpl() { FBlueprintSupport::SetFlushReinstancingQueueFPtr(&FlushReinstancingQueueImplWrapper); @@ -172,80 +126,213 @@ FBlueprintCompilationManagerImpl::~FBlueprintCompilationManagerImpl() void FBlueprintCompilationManagerImpl::AddReferencedObjects(FReferenceCollector& Collector) { - Collector.AddReferencedObjects(QueuedBPs); + for( FBPCompileRequest& Job : QueuedRequests ) + { + Collector.AddReferencedObject(Job.BPToCompile); + } + + Collector.AddReferencedObjects(ClassesToReinstance); } -void FBlueprintCompilationManagerImpl::QueueForCompilation(UBlueprint* BPToCompile) +void FBlueprintCompilationManagerImpl::QueueForCompilation(const FBPCompileRequest& CompileJob) { - QueuedBPs.Add(BPToCompile); + if(!CompileJob.BPToCompile->bQueuedForCompilation) + { + CompileJob.BPToCompile->bQueuedForCompilation = true; + QueuedRequests.Add(CompileJob); + } +} + +void FBlueprintCompilationManagerImpl::CompileSynchronouslyImpl(const FBPCompileRequest& Request) +{ + Request.BPToCompile->bQueuedForCompilation = true; + + const bool bIsRegeneratingOnLoad = (Request.CompileOptions & EBlueprintCompileOptions::IsRegeneratingOnLoad ) != EBlueprintCompileOptions::None; + const bool bSkipGarbageCollection = (Request.CompileOptions & EBlueprintCompileOptions::SkipGarbageCollection ) != EBlueprintCompileOptions::None; + const bool bBatchCompile = (Request.CompileOptions & EBlueprintCompileOptions::BatchCompile ) != EBlueprintCompileOptions::None; + const bool bSkipReinstancing = (Request.CompileOptions & EBlueprintCompileOptions::SkipReinstancing ) != EBlueprintCompileOptions::None; + + // Wipe the PreCompile log, any generated messages are now irrelevant + Request.BPToCompile->PreCompileLog.Reset(); + + // Reset the flag, so if the user tries to use PIE it will warn them if the BP did not compile + Request.BPToCompile->bDisplayCompilePIEWarning = true; + + // Do not want to run this code without the editor present nor when running commandlets. + if (GEditor && GIsEditor) + { + // We do not want to regenerate a search Guid during loads, nothing has changed in the Blueprint and it is cached elsewhere + if (!bIsRegeneratingOnLoad) + { + FFindInBlueprintSearchManager::Get().AddOrUpdateBlueprintSearchMetadata(Request.BPToCompile); + } + } + + ensure(!bIsRegeneratingOnLoad); // unexpected code path, compile on load handled with different function call + ensure(!bSkipReinstancing); // This is an internal option, should not go through CompileSynchronouslyImpl + + ensure(QueuedRequests.Num() == 0); + QueuedRequests.Add(Request); + // We suppress normal compilation boradcasts because the old code path + // did this after GC and we want to match the old behavior: + const bool bSuppressBroadcastCompiled = true; + FlushCompilationQueueImpl(nullptr, bSuppressBroadcastCompiled); + FlushReinstancingQueueImpl(); + + ensure(Request.BPToCompile->bQueuedForCompilation == false); + + if(!bSkipGarbageCollection) + { + CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS); + } + + if (!bBatchCompile) + { + if(GEditor) + { + GEditor->BroadcastBlueprintCompiled(); + } + } } static double GTimeCompiling = 0.f; static double GTimeReinstancing = 0.f; -enum class ECompilationManagerFlags +enum class ECompilationManagerJobType { - None = 0x0, - - SkeletonOnly = 0x1, + Normal, + SkeletonOnly, + RelinkOnly, }; -ENUM_CLASS_FLAGS(ECompilationManagerFlags) - struct FCompilerData { - FCompilerData(UBlueprint* InBP, ECompilationManagerFlags InFlags) + explicit FCompilerData(UBlueprint* InBP, ECompilationManagerJobType InJobType, FCompilerResultsLog* InResultsLogOverride, EBlueprintCompileOptions UserOptions, bool bBytecodeOnly) { check(InBP); BP = InBP; - Flags = InFlags; - ResultsLog = MakeUnique(); - ResultsLog->BeginEvent(TEXT("BlueprintCompilationManager Compile")); - ResultsLog->SetSourcePath(InBP->GetPathName()); - Options.bRegenerateSkelton = false; - Options.bReinstanceAndStubOnFailure = false; + JobType = InJobType; + UPackage* Package = Cast(BP->GetOutermost()); + bPackageWasDirty = Package ? Package->IsDirty() : false; + + ActiveResultsLog = InResultsLogOverride; + if(InResultsLogOverride == nullptr) + { + ResultsLog = MakeUnique(); + ResultsLog->BeginEvent(TEXT("BlueprintCompilationManager Compile")); + ResultsLog->SetSourcePath(InBP->GetPathName()); + ActiveResultsLog = ResultsLog.Get(); + } + + static const FBoolConfigValueHelper IgnoreCompileOnLoadErrorsOnBuildMachine(TEXT("Kismet"), TEXT("bIgnoreCompileOnLoadErrorsOnBuildMachine"), GEngineIni); + ActiveResultsLog->bLogInfoOnly = !BP->bHasBeenRegenerated && GIsBuildMachine && IgnoreCompileOnLoadErrorsOnBuildMachine; + + InternalOptions.bRegenerateSkelton = false; + InternalOptions.bReinstanceAndStubOnFailure = false; + InternalOptions.bSaveIntermediateProducts = (UserOptions & EBlueprintCompileOptions::SaveIntermediateProducts ) != EBlueprintCompileOptions::None; + InternalOptions.CompileType = bBytecodeOnly ? EKismetCompileType::BytecodeOnly : EKismetCompileType::Full; + if( UWidgetBlueprint* WidgetBP = Cast(BP)) { - Compiler = UWidgetBlueprint::GetCompilerForWidgetBP(WidgetBP, *ResultsLog, Options); + Compiler = UWidgetBlueprint::GetCompilerForWidgetBP(WidgetBP, *ActiveResultsLog, InternalOptions); } else { - Compiler = FKismetCompilerContext::GetCompilerForBP(BP, *ResultsLog, Options); + Compiler = FKismetCompilerContext::GetCompilerForBP(BP, *ActiveResultsLog, InternalOptions); } } - bool IsSkeletonOnly() const { return !!(Flags & ECompilationManagerFlags::SkeletonOnly); } + bool IsSkeletonOnly() const { return JobType == ECompilationManagerJobType::SkeletonOnly; } + bool ShouldResetClassMembers() const { return JobType != ECompilationManagerJobType::RelinkOnly; } + bool ShouldSetTemporaryBlueprintFlags() const { return JobType != ECompilationManagerJobType::RelinkOnly; } + bool ShouldValidateVariableNames() const { return JobType == ECompilationManagerJobType::Normal; } + bool ShouldRegenerateSkeleton() const { return JobType != ECompilationManagerJobType::RelinkOnly; } + bool ShouldMarkUpToDateAfterSkeletonStage() const { return IsSkeletonOnly(); } + bool ShouldReconstructNodes() const { return JobType == ECompilationManagerJobType::Normal; } + bool ShouldSkipReinstancerCreation() const { return (IsSkeletonOnly() && BP->ParentClass->IsNative()); } + bool ShouldCompileClassLayout() const { return JobType == ECompilationManagerJobType::Normal; } + bool ShouldCompileClassFunctions() const { return JobType == ECompilationManagerJobType::Normal; } + bool ShouldRelinkAfterSkippingCompile() const { return JobType == ECompilationManagerJobType::RelinkOnly; } UBlueprint* BP; + FCompilerResultsLog* ActiveResultsLog; TUniquePtr ResultsLog; - TUniquePtr Compiler; - FKismetCompilerOptions Options; + TSharedPtr Compiler; + FKismetCompilerOptions InternalOptions; + TSharedPtr Reinstancer; - ECompilationManagerFlags Flags; + ECompilationManagerJobType JobType; + bool bPackageWasDirty; +}; + +struct FReinstancingJob +{ + TSharedPtr Reinstancer; + TSharedPtr Compiler; }; -void FBlueprintCompilationManagerImpl::FlushCompilationQueueImpl(TArray* ObjLoaded) +void FBlueprintCompilationManagerImpl::FlushCompilationQueueImpl(TArray* ObjLoaded, bool bSuppressBroadcastCompiled) { + TGuardValue GuardTemplateNameFlag(GCompilingBlueprint, true); ensure(bGeneratedClassLayoutReady); - if( QueuedBPs.Num() == 0 ) + if( QueuedRequests.Num() == 0 ) { return; } TArray CurrentlyCompilingBPs; - TArray> Reinstancers; { // begin GTimeCompiling scope FScopedDurationTimer SetupTimer(GTimeCompiling); - - for(int32 I = 0; I < QueuedBPs.Num(); ++I) + + // STAGE I: Add any child blueprints that were not compiled, we will need to run a link pass on them: + for(const FBPCompileRequest& ComplieJob : QueuedRequests) + { + if(UClass* OldSkeletonClass = ComplieJob.BPToCompile->SkeletonGeneratedClass) + { + TArray SkeletonClassesToReparentList; + GetDerivedClasses(OldSkeletonClass, SkeletonClassesToReparentList); + + for(UClass* ChildClass : SkeletonClassesToReparentList) + { + if(UBlueprint* ChildBlueprint = UBlueprint::GetBlueprintFromClass(ChildClass)) + { + if(!IsQueuedForCompilation(ChildBlueprint)) + { + ChildBlueprint->bQueuedForCompilation = true; + ensure(ChildBlueprint->bHasBeenRegenerated); + CurrentlyCompilingBPs.Add(FCompilerData(ChildBlueprint, ECompilationManagerJobType::RelinkOnly, nullptr, EBlueprintCompileOptions::None, false)); + } + } + } + } + + // Add any dependent blueprints for a bytecode compile, this is needed because we + // have no way to keep bytecode safe when a function is renamed or parameters are + // added or removed - strictly speaking we only need to do this when function + // parameters changed, but that's a somewhat dubious optmization - ideally this + // work *never* needs to happen: + TArray DependentBlueprints; + FBlueprintEditorUtils::GetDependentBlueprints(ComplieJob.BPToCompile, DependentBlueprints); + for(UBlueprint* DependentBlueprint : DependentBlueprints) + { + if(!IsQueuedForCompilation(DependentBlueprint)) + { + DependentBlueprint->bQueuedForCompilation = true; + CurrentlyCompilingBPs.Add(FCompilerData(DependentBlueprint, ECompilationManagerJobType::Normal, nullptr, EBlueprintCompileOptions::None, true)); + } + } + } + + // STAGE II: Filter out data only and interface blueprints: + for(int32 I = 0; I < QueuedRequests.Num(); ++I) { - // filter out data only and interface blueprints: bool bSkipCompile = false; - UBlueprint* QueuedBP = QueuedBPs[I]; + FBPCompileRequest& QueuedJob = QueuedRequests[I]; + UBlueprint* QueuedBP = QueuedJob.BPToCompile; ensure(!(QueuedBP->GeneratedClass->ClassDefaultObject->HasAnyFlags(RF_NeedLoad))); - if( FBlueprintEditorUtils::IsDataOnlyBlueprint(QueuedBP) ) + if( FBlueprintEditorUtils::IsDataOnlyBlueprint(QueuedBP) && !QueuedBP->bHasBeenRegenerated) { const UClass* ParentClass = QueuedBP->ParentClass; if (ParentClass && ParentClass->HasAllClassFlags(CLASS_Native)) @@ -264,7 +351,7 @@ void FBlueprintCompilationManagerImpl::FlushCompilationQueueImpl(TArrayIsGeneratedClassAuthoritative() && (QueuedBP->GeneratedClass != nullptr)) { // set bIsRegeneratingOnLoad so that we don't reset loaders: @@ -281,18 +368,18 @@ void FBlueprintCompilationManagerImpl::FlushCompilationQueueImpl(TArrayGeneratedClass, true); } - QueuedBPs.RemoveAtSwap(I); + QueuedRequests.RemoveAtSwap(I); --I; } else { - CurrentlyCompilingBPs.Add(FCompilerData(QueuedBP, ECompilationManagerFlags::None)); + CurrentlyCompilingBPs.Add(FCompilerData(QueuedBP, ECompilationManagerJobType::Normal, QueuedJob.ClientResultsLog, QueuedJob.CompileOptions, false)); } } - - QueuedBPs.Empty(); - // sort into sane compilation order. Not needed if we introduce compilation phases: + QueuedRequests.Empty(); + + // STAGE III: Sort into correct compilation order. We want to compile root types before their derived (child) types: auto HierarchyDepthSortFn = [](const FCompilerData& CompilerDataA, const FCompilerData& CompilerDataB) { UBlueprint& A = *(CompilerDataA.BP); @@ -334,92 +421,150 @@ void FBlueprintCompilationManagerImpl::FlushCompilationQueueImpl(TArraybBeingCompiled = true; + BP->bIsRegeneratingOnLoad = !BP->bHasBeenRegenerated && BP->GetLinker(); + } + } + + // STAGE V: Validate Variable Names + for (FCompilerData& CompilerData : CurrentlyCompilingBPs) + { + if(!CompilerData.ShouldValidateVariableNames()) { continue; } - UBlueprint* BP = CompilerData.BP; - - // even ValidateVariableNames will trigger compilation if - // it thinks the BP is not being compiled: - BP->bBeingCompiled = true; CompilerData.Compiler->ValidateVariableNames(); - BP->bBeingCompiled = false; } - // purge null graphs, could be done only on load + // STAGE VI: Purge null graphs, could be done only on load for (FCompilerData& CompilerData : CurrentlyCompilingBPs) { UBlueprint* BP = CompilerData.BP; - UPackage* Package = Cast(BP->GetOutermost()); - bool bIsPackageDirty = Package ? Package->IsDirty() : false; - FBlueprintEditorUtils::PurgeNullGraphs(BP); - - if( Package ) - { - Package->SetDirtyFlag(bIsPackageDirty); - } } - // recompile skeleton - for (FCompilerData& CompilerData : CurrentlyCompilingBPs) + // STAGE VII: safely throw away old skeleton CDOs: { - UBlueprint* BP = CompilerData.BP; - UPackage* Package = Cast(BP->GetOutermost()); - bool bIsPackageDirty = Package ? Package->IsDirty() : false; + TMap OldSkeletonToNewSkeleton; + for (FCompilerData& CompilerData : CurrentlyCompilingBPs) + { + UBlueprint* BP = CompilerData.BP; + if(BP->SkeletonGeneratedClass) + { + UClass* CopyOfOldClass = FBlueprintCompileReinstancer::MoveCDOToNewClass(BP->SkeletonGeneratedClass, OldSkeletonToNewSkeleton, true); + OldSkeletonToNewSkeleton.Add(BP->SkeletonGeneratedClass, CopyOfOldClass); + // Child types will need to use CopyOfOldClass + } + } + } - BP->SkeletonGeneratedClass = FastGenerateSkeletonClass(BP, *(CompilerData.Compiler) ); - - if(CompilerData.IsSkeletonOnly()) + // STAGE VIII: recompile skeleton + { + TMap OldSkeletonToNewSkeleton; + for (FCompilerData& CompilerData : CurrentlyCompilingBPs) { - // Flag data only blueprints as being up-to-date - BP->Status = BS_UpToDate; - BP->bHasBeenRegenerated = true; - BP->GeneratedClass->ClearFunctionMapsCaches(); - } + UBlueprint* BP = CompilerData.BP; + + if(CompilerData.ShouldRegenerateSkeleton()) + { + UClass* OldSkeleton = BP->SkeletonGeneratedClass; + BP->SkeletonGeneratedClass = FastGenerateSkeletonClass(BP, *(CompilerData.Compiler) ); + OldSkeletonToNewSkeleton.Add(OldSkeleton, BP->SkeletonGeneratedClass); + } + else + { + // Just relink, note that UProperties that reference *other* types may be stale until + // we fixup below: + UClass* SkeletonToRelink = BP->SkeletonGeneratedClass; - if( Package ) - { - Package->SetDirtyFlag(bIsPackageDirty); + // CDO needs to be moved aside already: + ensure(SkeletonToRelink->ClassDefaultObject == nullptr); + + UClass * const* OverridenParent = OldSkeletonToNewSkeleton.Find(SkeletonToRelink->GetSuperClass()); + if(OverridenParent && *OverridenParent) + { + SkeletonToRelink->SetSuperStruct(*OverridenParent); + } + + SkeletonToRelink->Bind(); + SkeletonToRelink->StaticLink(true); + } + + if(CompilerData.ShouldMarkUpToDateAfterSkeletonStage()) + { + // Flag data only blueprints as being up-to-date + BP->Status = BS_UpToDate; + BP->bHasBeenRegenerated = true; + BP->GeneratedClass->ClearFunctionMapsCaches(); + } } } - // reconstruct nodes + // STAGE IX: Reconstruct nodes and replace deprecated nodes, then broadcast 'precompile for (FCompilerData& CompilerData : CurrentlyCompilingBPs) { - if(CompilerData.IsSkeletonOnly()) + if(!CompilerData.ShouldReconstructNodes()) { continue; } UBlueprint* BP = CompilerData.BP; - UPackage* Package = Cast(BP->GetOutermost()); - bool bIsPackageDirty = Package ? Package->IsDirty() : false; - // Setting bBeingCompiled to make sure that FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified - // doesn't run skeleton compile while the compilation manager is compiling things: - BP->bBeingCompiled = true; - FBlueprintEditorUtils::ReconstructAllNodes(BP); - FBlueprintEditorUtils::ReplaceDeprecatedNodes(BP); - BP->bBeingCompiled = false; + // Some nodes are set up to do things during reconstruction only when this flag is NOT set. + if(BP->bIsRegeneratingOnLoad) + { + FBlueprintEditorUtils::ReconstructAllNodes(BP); + FBlueprintEditorUtils::ReplaceDeprecatedNodes(BP); + } + else + { + // matching existing behavior, when compiling a BP not on load we refresh nodes + // before compiling: + FBlueprintCompileReinstancer::OptionallyRefreshNodes(BP); + TArray DependentBlueprints; + FBlueprintEditorUtils::GetDependentBlueprints(BP, DependentBlueprints); + + for (UBlueprint* CurrentBP : DependentBlueprints) + { + const EBlueprintStatus OriginalStatus = CurrentBP->Status; + FBlueprintEditorUtils::RefreshExternalBlueprintDependencyNodes(CurrentBP, BP->GeneratedClass); + CurrentBP->Status = OriginalStatus; + } + } + + // Broadcast pre-compile + { + if(GEditor && GIsEditor) + { + GEditor->BroadcastBlueprintPreCompile(BP); + } + } + + // Do not want to run this code without the editor present nor when running commandlets. + if (GEditor && GIsEditor) + { + // We do not want to regenerate a search Guid during loads, nothing has changed in the Blueprint and it is cached elsewhere + if (!BP->bIsRegeneratingOnLoad) + { + FFindInBlueprintSearchManager::Get().AddOrUpdateBlueprintSearchMetadata(BP); + } + } // we are regenerated, tag ourself as such so that // old logic to 'fix' circular dependencies doesn't // cause redundant regeneration (e.g. bForceRegenNodes // in ExpandTunnelsAndMacros): BP->bHasBeenRegenerated = true; - - if( Package ) - { - Package->SetDirtyFlag(bIsPackageDirty); - } } - // reinstance every blueprint that is queued, note that this means classes in the hierarchy that are *not* being + // STAGE X: reinstance every blueprint that is queued, note that this means classes in the hierarchy that are *not* being // compiled will be parented to REINST versions of the class, so type checks (IsA, etc) involving those types // will be incoherent! TMap OldCDOs; @@ -429,134 +574,187 @@ void FBlueprintCompilationManagerImpl::FlushCompilationQueueImpl(TArrayParentClass->IsNative()) + if(CompilerData.ShouldSkipReinstancerCreation()) { continue; } UBlueprint* BP = CompilerData.BP; - UPackage* Package = Cast(BP->GetOutermost()); - bool bIsPackageDirty = Package ? Package->IsDirty() : false; OldCDOs.Add(BP, BP->GeneratedClass->ClassDefaultObject); - Reinstancers.Emplace(TUniquePtr( + CompilerData.Reinstancer = TSharedPtr( new FBlueprintCompileReinstancer( BP->GeneratedClass, EBlueprintCompileReinstancerFlags::AutoInferSaveOnCompile|EBlueprintCompileReinstancerFlags::AvoidCDODuplication ) - )); - - if( Package ) - { - Package->SetDirtyFlag(bIsPackageDirty); - } + ); } } - // Reinstancing done, lets fix up child->parent pointers: + // STAGE XI: Reinstancing done, lets fix up child->parent pointers for (FCompilerData& CompilerData : CurrentlyCompilingBPs) { UBlueprint* BP = CompilerData.BP; if(BP->GeneratedClass->GetSuperClass()->HasAnyClassFlags(CLASS_NewerVersionExists)) { BP->GeneratedClass->SetSuperStruct(BP->GeneratedClass->GetSuperClass()->GetAuthoritativeClass()); - BP->GeneratedClass->Children = NULL; - BP->GeneratedClass->Script.Empty(); - BP->GeneratedClass->MinAlignment = 0; - BP->GeneratedClass->RefLink = NULL; - BP->GeneratedClass->PropertyLink = NULL; - BP->GeneratedClass->DestructorLink = NULL; - BP->GeneratedClass->ScriptObjectReferences.Empty(); - BP->GeneratedClass->PropertyLink = NULL; + if(CompilerData.ShouldResetClassMembers()) + { + BP->GeneratedClass->Children = NULL; + BP->GeneratedClass->Script.Empty(); + BP->GeneratedClass->MinAlignment = 0; + BP->GeneratedClass->RefLink = NULL; + BP->GeneratedClass->PropertyLink = NULL; + BP->GeneratedClass->DestructorLink = NULL; + BP->GeneratedClass->ScriptObjectReferences.Empty(); + BP->GeneratedClass->PropertyLink = NULL; + } } } - // recompile every blueprint + // STAGE XII: Recompile every blueprint bGeneratedClassLayoutReady = false; for (FCompilerData& CompilerData : CurrentlyCompilingBPs) { - if(CompilerData.IsSkeletonOnly()) - { - continue; - } - UBlueprint* BP = CompilerData.BP; - UPackage* Package = Cast(BP->GetOutermost()); - bool bIsPackageDirty = Package ? Package->IsDirty() : false; - - ensure(BP->GeneratedClass->ClassDefaultObject == nullptr || - BP->GeneratedClass->ClassDefaultObject->GetClass() != BP->GeneratedClass); - // default value propagation occurrs below: - BP->GeneratedClass->ClassDefaultObject = nullptr; - BP->bIsRegeneratingOnLoad = true; - BP->bBeingCompiled = true; - // Reset the flag, so if the user tries to use PIE it will warn them if the BP did not compile - BP->bDisplayCompilePIEWarning = true; - - FKismetCompilerContext& CompilerContext = *(CompilerData.Compiler); - CompilerContext.CompileClassLayout(EInternalCompilerFlags::PostponeLocalsGenerationUntilPhaseTwo); - BP->bIsRegeneratingOnLoad = false; - - if( Package ) + if(CompilerData.ShouldCompileClassLayout()) { - Package->SetDirtyFlag(bIsPackageDirty); + ensure( BP->GeneratedClass->ClassDefaultObject == nullptr || + BP->GeneratedClass->ClassDefaultObject->GetClass() != BP->GeneratedClass); + // default value propagation occurs in ReinstaneBatch, CDO will be created via CompileFunctions call: + BP->GeneratedClass->ClassDefaultObject = nullptr; + // Reset the flag, so if the user tries to use PIE it will warn them if the BP did not compile + BP->bDisplayCompilePIEWarning = true; + + FKismetCompilerContext& CompilerContext = *(CompilerData.Compiler); + CompilerContext.CompileClassLayout(EInternalCompilerFlags::PostponeLocalsGenerationUntilPhaseTwo); + } + else if(CompilerData.Compiler.IsValid()) + { + CompilerData.Compiler->NewClass = CastChecked(BP->GeneratedClass); } } bGeneratedClassLayoutReady = true; + // STAGE XIII: Compile functions for (FCompilerData& CompilerData : CurrentlyCompilingBPs) { - if(CompilerData.IsSkeletonOnly()) - { - continue; - } - UBlueprint* BP = CompilerData.BP; - UPackage* Package = Cast(BP->GetOutermost()); - bool bIsPackageDirty = Package ? Package->IsDirty() : false; - - ensure(BP->GeneratedClass->ClassDefaultObject == nullptr || - BP->GeneratedClass->ClassDefaultObject->GetClass() != BP->GeneratedClass); - // default value propagation occurrs below: - BP->GeneratedClass->ClassDefaultObject = nullptr; - BP->bIsRegeneratingOnLoad = true; - - FKismetCompilerContext& CompilerContext = *(CompilerData.Compiler); - CompilerContext.CompileFunctions(EInternalCompilerFlags::PostponeLocalsGenerationUntilPhaseTwo); - - BP->bBeingCompiled = false; - - if (CompilerData.ResultsLog->NumErrors == 0) + if(!CompilerData.ShouldCompileClassFunctions()) { - // Blueprint is error free. Go ahead and fix up debug info - BP->Status = (0 == CompilerData.ResultsLog->NumWarnings) ? BS_UpToDate : BS_UpToDateWithWarnings; + if( BP->GeneratedClass->ClassDefaultObject == nullptr || + BP->GeneratedClass->ClassDefaultObject->GetClass() != BP->GeneratedClass) + { + // relink, generate CDO: + UClass* BPGC = BP->GeneratedClass; + BPGC->Bind(); + BPGC->StaticLink(true); + BPGC->ClassDefaultObject = nullptr; + BPGC->GetDefaultObject(true); + } } else { - BP->Status = BS_Error; // do we still have the old version of the class? + ensure( BP->GeneratedClass->ClassDefaultObject == nullptr || + BP->GeneratedClass->ClassDefaultObject->GetClass() != BP->GeneratedClass); + // default value propagation occurrs below: + BP->GeneratedClass->ClassDefaultObject = nullptr; + + FKismetCompilerContext& CompilerContext = *(CompilerData.Compiler); + CompilerContext.CompileFunctions( + EInternalCompilerFlags::PostponeLocalsGenerationUntilPhaseTwo + |EInternalCompilerFlags::PostponeDefaultObjectAssignmentUntilReinstancing + |EInternalCompilerFlags::SkipRefreshExternalBlueprintDependencyNodes + ); + + if (CompilerData.ActiveResultsLog->NumErrors == 0) + { + // Blueprint is error free. Go ahead and fix up debug info + BP->Status = (0 == CompilerData.ActiveResultsLog->NumWarnings) ? BS_UpToDate : BS_UpToDateWithWarnings; + } + else + { + BP->Status = BS_Error; // do we still have the old version of the class? + } } - BP->bIsRegeneratingOnLoad = false; ensure(BP->GeneratedClass->ClassDefaultObject->GetClass() == *(BP->GeneratedClass)); - - if( Package ) - { - Package->SetDirtyFlag(bIsPackageDirty); - } } } // end GTimeCompiling scope - // and now we can finish the first stage of the reinstancing operation, moving old classes to new classes: + // STAGE XIV: Now we can finish the first stage of the reinstancing operation, moving old classes to new classes: { - FScopedDurationTimer ReinstTimer(GTimeReinstancing); - ReinstanceBatch(Reinstancers, ClassesToReinstance, ObjLoaded); + { + TArray Reinstancers; + // Set up reinstancing jobs - we need a reference to the compiler in order to honor + // CopyTermDefaultsToDefaultObject + for (FCompilerData& CompilerData : CurrentlyCompilingBPs) + { + if(CompilerData.Reinstancer.IsValid()) + { + Reinstancers.Push( + FReinstancingJob { + CompilerData.Reinstancer, + CompilerData.Compiler + } + ); + } + } + + FScopedDurationTimer ReinstTimer(GTimeReinstancing); + ReinstanceBatch(Reinstancers, ClassesToReinstance, ObjLoaded); + } - // make sure no junk in bytecode, this can happen only for blueprints that were in QueuedBPsLocal because + // STAGE XV: CLEAR TEMPORARY FLAGS + for (FCompilerData& CompilerData : CurrentlyCompilingBPs) + { + UBlueprint* BP = CompilerData.BP; + FBlueprintEditorUtils::UpdateDelegatesInBlueprint(BP); + + if (FBlueprintEditorUtils::IsLevelScriptBlueprint(BP)) + { + // When the Blueprint is recompiled, then update the bound events for level scripting + ULevelScriptBlueprint* LevelScriptBP = CastChecked(BP); + + // ULevel::OnLevelScriptBlueprintChanged needs to be run after the CDO has + // been updated as it respawns the actor: + if (ULevel* BPLevel = LevelScriptBP->GetLevel()) + { + BPLevel->OnLevelScriptBlueprintChanged(LevelScriptBP); + } + } + + if(!BP->bIsRegeneratingOnLoad) + { + FKismetEditorUtilities::StripExternalComponents(BP); + + if(BP->SimpleConstructionScript) + { + BP->SimpleConstructionScript->FixupRootNodeParentReferences(); + } + + UBlueprint::ValidateGeneratedClass(BP->GeneratedClass); + } + + if(CompilerData.ShouldSetTemporaryBlueprintFlags()) + { + BP->bBeingCompiled = false; + BP->bIsRegeneratingOnLoad = false; + } + + if(UPackage* Package = Cast(BP->GetOutermost())) + { + Package->SetDirtyFlag(CompilerData.bPackageWasDirty); + } + } + + // Make sure no junk in bytecode, this can happen only for blueprints that were in CurrentlyCompilingBPs because // the reinstancer can detect all other references (see UpdateBytecodeReferences): for (FCompilerData& CompilerData : CurrentlyCompilingBPs) { - if(CompilerData.IsSkeletonOnly()) + if(CompilerData.ShouldCompileClassFunctions()) { + CompilerData.BP->BroadcastCompiled(); continue; } @@ -570,21 +768,41 @@ void FBlueprintCompilationManagerImpl::FlushCompilationQueueImpl(TArrayBroadcastBlueprintReinstanced(); + } + + if (!bSuppressBroadcastCompiled) + { + if(GEditor) + { + GEditor->BroadcastBlueprintCompiled(); + } + } } for (FCompilerData& CompilerData : CurrentlyCompilingBPs) { - CompilerData.ResultsLog->EndEvent(); + if(CompilerData.ResultsLog) + { + CompilerData.ResultsLog->EndEvent(); + } + CompilerData.BP->bQueuedForCompilation = false; } + UEdGraphPin::Purge(); + UE_LOG(LogBlueprint, Display, TEXT("Time Compiling: %f, Time Reinstancing: %f"), GTimeCompiling, GTimeReinstancing); //GTimeCompiling = 0.0; //GTimeReinstancing = 0.0; - ensure(QueuedBPs.Num() == 0); + ensure(QueuedRequests.Num() == 0); } void FBlueprintCompilationManagerImpl::FlushReinstancingQueueImpl() { + TGuardValue GuardTemplateNameFlag(GCompilingBlueprint, true); // we can finalize reinstancing now: if(ClassesToReinstance.Num() == 0) { @@ -593,7 +811,8 @@ void FBlueprintCompilationManagerImpl::FlushReinstancingQueueImpl() { FScopedDurationTimer ReinstTimer(GTimeReinstancing); - + + TGuardValue ReinstancingGuard(GIsReinstancing, true); FBlueprintCompileReinstancer::BatchReplaceInstancesOfClass(ClassesToReinstance); ClassesToReinstance.Empty(); } @@ -611,7 +830,7 @@ void FBlueprintCompilationManagerImpl::FlushReinstancingQueueImpl() bool FBlueprintCompilationManagerImpl::HasBlueprintsToCompile() const { - return QueuedBPs.Num() != 0; + return QueuedRequests.Num() != 0; } bool FBlueprintCompilationManagerImpl::IsGeneratedClassLayoutReady() const @@ -619,7 +838,7 @@ bool FBlueprintCompilationManagerImpl::IsGeneratedClassLayoutReady() const return bGeneratedClassLayoutReady; } -void FBlueprintCompilationManagerImpl::ReinstanceBatch(TArray>& Reinstancers, TMap< UClass*, UClass* >& InOutOldToNewClassMap, TArray* ObjLoaded) +void FBlueprintCompilationManagerImpl::ReinstanceBatch(TArray& Reinstancers, TMap< UClass*, UClass* >& InOutOldToNewClassMap, TArray* ObjLoaded) { const auto FilterOutOfDateClasses = [](TArray& ClassList) { @@ -639,10 +858,11 @@ void FBlueprintCompilationManagerImpl::ReinstanceBatch(TArray& Reinstancer : Reinstancers) + for (const FReinstancingJob& ReinstancingJob : Reinstancers) { - UClass* OldClass = Reinstancer->DuplicatedClass; - InOutOldToNewClassMap.Add(Reinstancer->DuplicatedClass, Reinstancer->ClassToReinstance); + const TSharedPtr& CurrentReinstancer = ReinstancingJob.Reinstancer; + UClass* OldClass = CurrentReinstancer->DuplicatedClass; + InOutOldToNewClassMap.Add(CurrentReinstancer->DuplicatedClass, CurrentReinstancer->ClassToReinstance); if(!OldClass) { continue; @@ -653,7 +873,7 @@ void FBlueprintCompilationManagerImpl::ReinstanceBatch(TArrayClassToReinstance); + bool bParentLayoutChanged = FStructUtils::TheSameLayout(OldClass, CurrentReinstancer->ClassToReinstance); if(bParentLayoutChanged) { // we need *all* derived types: @@ -699,15 +919,20 @@ void FBlueprintCompilationManagerImpl::ReinstanceBatch(TArrayClassDefaultObject; - Reinstancers.Emplace(TUniquePtr( - new FBlueprintCompileReinstancer( - Class, - EBlueprintCompileReinstancerFlags::AutoInferSaveOnCompile|EBlueprintCompileReinstancerFlags::AvoidCDODuplication - ) - )); + Reinstancers.Emplace( + FReinstancingJob { + TSharedPtr( + new FBlueprintCompileReinstancer( + Class, + EBlueprintCompileReinstancerFlags::AutoInferSaveOnCompile|EBlueprintCompileReinstancerFlags::AvoidCDODuplication + ) + ), + TSharedPtr() + } + ); // make sure we have the newest parent now that CDO has been moved to duplicate class: - TUniquePtr& NewestReinstancer = Reinstancers.Last(); + TSharedPtr& NewestReinstancer = Reinstancers.Last().Reinstancer; UClass* SuperClass = NewestReinstancer->ClassToReinstance->GetSuperClass(); if(ensure(SuperClass)) @@ -724,15 +949,13 @@ void FBlueprintCompilationManagerImpl::ReinstanceBatch(TArray& Reinstancer : Reinstancers) + for (const FReinstancingJob& ReinstancingJob : Reinstancers) { - InOutOldToNewClassMap.Add( Reinstancer->DuplicatedClass, Reinstancer->ClassToReinstance ); + const TSharedPtr& CurrentReinstancer = ReinstancingJob.Reinstancer; + InOutOldToNewClassMap.Add( CurrentReinstancer->DuplicatedClass, CurrentReinstancer->ClassToReinstance ); - UBlueprint* CompiledBlueprint = UBlueprint::GetBlueprintFromClass(Reinstancer->ClassToReinstance); - CompiledBlueprint->bIsRegeneratingOnLoad = true; - Reinstancer->UpdateBytecodeReferences(); - - CompiledBlueprint->bIsRegeneratingOnLoad = false; + UBlueprint* CompiledBlueprint = UBlueprint::GetBlueprintFromClass(CurrentReinstancer->ClassToReinstance); + CurrentReinstancer->UpdateBytecodeReferences(); } // Now we can update templates and archetypes - note that we don't look for direct references to archetypes - doing @@ -743,8 +966,11 @@ void FBlueprintCompilationManagerImpl::ReinstanceBatch(TArray& CompilerDataA, const TUniquePtr& CompilerDataB) + [](const FReinstancingJob& ReinstancingDataA, const FReinstancingJob& ReinstancingDataB) { + const TSharedPtr& CompilerDataA = ReinstancingDataA.Reinstancer; + const TSharedPtr& CompilerDataB = ReinstancingDataB.Reinstancer; + UClass* A = CompilerDataA->ClassToReinstance; UClass* B = CompilerDataB->ClassToReinstance; int32 DepthA = 0; @@ -773,14 +999,21 @@ void FBlueprintCompilationManagerImpl::ReinstanceBatch(TArray& Reinstancer : Reinstancers ) + for (const FReinstancingJob& ReinstancingJob : Reinstancers) { - UObject* OldCDO = Reinstancer->DuplicatedClass->ClassDefaultObject; + const TSharedPtr& CurrentReinstancer = ReinstancingJob.Reinstancer; + UObject* OldCDO = CurrentReinstancer->DuplicatedClass->ClassDefaultObject; if(OldCDO) { - FBlueprintCompileReinstancer::CopyPropertiesForUnrelatedObjects(OldCDO, Reinstancer->ClassToReinstance->GetDefaultObject(true)); - - if (UBlueprintGeneratedClass* BPGClass = CastChecked(Reinstancer->ClassToReinstance)) + UObject* NewCDO = CurrentReinstancer->ClassToReinstance->GetDefaultObject(true); + FBlueprintCompileReinstancer::CopyPropertiesForUnrelatedObjects(OldCDO, NewCDO); + + if(ReinstancingJob.Compiler.IsValid()) + { + ReinstancingJob.Compiler->PropagateValuesToCDO(NewCDO, OldCDO); + } + + if (UBlueprintGeneratedClass* BPGClass = CastChecked(CurrentReinstancer->ClassToReinstance)) { BPGClass->UpdateCustomPropertyListForPostConstruction(); @@ -818,9 +1051,11 @@ void FBlueprintCompilationManagerImpl::ReinstanceBatch(TArray& Reinstancer : Reinstancers ) + TSet ArchetypeReferencers; + for (const FReinstancingJob& ReinstancingJob : Reinstancers) { - UClass* OldClass = Reinstancer->DuplicatedClass; + const TSharedPtr& CurrentReinstancer = ReinstancingJob.Reinstancer; + UClass* OldClass = CurrentReinstancer->DuplicatedClass; if(ensure(OldClass)) { TArray ArchetypeObjects; @@ -845,6 +1080,26 @@ void FBlueprintCompilationManagerImpl::ReinstanceBatch(TArrayGetOuter(); + while(Iter) + { + if(Iter->HasAnyFlags(RF_ClassDefaultObject) + || Cast(Iter) + || Cast(Iter) ) + { + ArchetypeReferencers.Add(Iter); + + // this handles nested subobjects: + TArray ContainedObjects; + GetObjectsWithOuter(Iter, ContainedObjects); + ArchetypeReferencers.Append(ContainedObjects); + } + Iter = Iter->GetOuter(); + } + } + // move aside: FName OriginalName = Archetype->GetFName(); UObject* OriginalOuter = Archetype->GetOuter(); @@ -858,14 +1113,15 @@ void FBlueprintCompilationManagerImpl::ReinstanceBatch(TArrayClassToReinstance); + FMakeClassSpawnableOnScope TemporarilySpawnable(CurrentReinstancer->ClassToReinstance); const EObjectFlags FlagMask = RF_Public | RF_ArchetypeObject | RF_Transactional | RF_Transient | RF_TextExportTransient | RF_InheritableComponentTemplate | RF_Standalone; //TODO: what about RF_RootSet? - UObject* NewArchetype = NewObject(OriginalOuter, Reinstancer->ClassToReinstance, OriginalName, OriginalFlags & FlagMask); + UObject* NewArchetype = NewObject(OriginalOuter, CurrentReinstancer->ClassToReinstance, OriginalName, OriginalFlags & FlagMask); // copy old data: FBlueprintCompileReinstancer::CopyPropertiesForUnrelatedObjects(Archetype, NewArchetype); OldArchetypeToNewArchetype.Add(Archetype, NewArchetype); + ArchetypeReferencers.Add(Archetype); ObjectsThatShouldUseOldStuff.Add(Archetype); Archetype->MarkPendingKill(); @@ -876,13 +1132,14 @@ void FBlueprintCompilationManagerImpl::ReinstanceBatch(TArray ArchetypeReferencers; - for( const TUniquePtr& Reinstancer : Reinstancers ) + for (const FReinstancingJob& ReinstancingJob : Reinstancers) { - ArchetypeReferencers.Add(Reinstancer->ClassToReinstance); - ArchetypeReferencers.Add(Reinstancer->ClassToReinstance->ClassGeneratedBy); - if(UBlueprint* BP = Cast(Reinstancer->ClassToReinstance->ClassGeneratedBy)) + const TSharedPtr& CurrentReinstancer = ReinstancingJob.Reinstancer; + ArchetypeReferencers.Add(CurrentReinstancer->ClassToReinstance); + ArchetypeReferencers.Add(CurrentReinstancer->ClassToReinstance->ClassGeneratedBy); + if(UBlueprint* BP = Cast(CurrentReinstancer->ClassToReinstance->ClassGeneratedBy)) { + ArchetypeReferencers.Add(BP->SkeletonGeneratedClass); ensure(BP->bCachedDependenciesUpToDate); for(TWeakObjectPtr Dependendency : BP->CachedDependencies) { @@ -897,7 +1154,13 @@ void FBlueprintCompilationManagerImpl::ReinstanceBatch(TArray(); @@ -916,14 +1179,25 @@ UClass* FBlueprintCompilationManagerImpl::FastGenerateSkeletonClass(UBlueprint* } } - ensure(BP->SkeletonGeneratedClass == nullptr); + UBlueprintGeneratedClass* Ret = nullptr; UBlueprintGeneratedClass* OriginalNewClass = CompilerContext.NewClass; - CompilerContext.SpawnNewClass(FString::Printf(TEXT("SKEL_%s_C"), *BP->GetName())); - UBlueprintGeneratedClass* Ret = CompilerContext.NewClass; - CompilerContext.NewClass = OriginalNewClass; - Ret->ClassGeneratedBy = BP; + if(BP->SkeletonGeneratedClass == nullptr ) + { + CompilerContext.SpawnNewClass(FString::Printf(TEXT("SKEL_%s_C"), *BP->GetName())); + Ret = CompilerContext.NewClass; + Ret->SetFlags(RF_Transient); + CompilerContext.NewClass = OriginalNewClass; + } + else + { + Ret = CastChecked(*(BP->SkeletonGeneratedClass)); + CompilerContext.CleanAndSanitizeClass(Ret, Ret->ClassDefaultObject); + } - const auto MakeFunction = [Ret, ParentClass, Schema, BP, &MessageLog](FName FunctionNameFName, UField**& InCurrentFieldStorageLocation, UField**& InCurrentParamStorageLocation, bool bIsStaticFunction, uint32 InFunctionFlags, const TArray& ReturnNodes, const TArray& InputPins) -> UFunction* + Ret->ClassGeneratedBy = BP; + + // This is a version of PrecompileFunction that does not require 'terms' and graph cloning: + const auto MakeFunction = [Ret, ParentClass, Schema, BP, &MessageLog](FName FunctionNameFName, UField**& InCurrentFieldStorageLocation, UField**& InCurrentParamStorageLocation, bool bIsStaticFunction, EFunctionFlags InFunctionFlags, const TArray& ReturnNodes, const TArray& InputPins, bool bForceArrayStructRefsConst) -> UFunction* { if(!ensure(FunctionNameFName != FName()) || FindObjectFast(Ret, FunctionNameFName, true )) @@ -931,7 +1205,7 @@ UClass* FBlueprintCompilationManagerImpl::FastGenerateSkeletonClass(UBlueprint* return nullptr; } - UFunction* NewFunction = NewObject(Ret, FunctionNameFName, RF_Public); + UFunction* NewFunction = NewObject(Ret, FunctionNameFName, RF_Public|RF_Transient); Ret->AddFunctionToFunctionMap(NewFunction); @@ -991,43 +1265,48 @@ UClass* FBlueprintCompilationManagerImpl::FastGenerateSkeletonClass(UBlueprint* { // Reimplmentation of FKismetCompilerContext::CreatePropertiesFromList without dependence on 'terms' UProperty* Param = FKismetCompilerUtilities::CreatePropertyOnScope(NewFunction, *(Pin->PinName), Pin->PinType, Ret, 0, Schema, MessageLog); - Param->PropertyFlags |= CPF_Parm; - if(Pin->PinType.bIsReference) + if(Param) { - Param->PropertyFlags |= CPF_ReferenceParm | CPF_OutParm; - } - if(Pin->PinType.bIsConst) - { - Param->PropertyFlags |= CPF_ConstParm; - } - - if (UObjectProperty* ObjProp = Cast(Param)) - { - UClass* EffectiveClass = nullptr; - if (ObjProp->PropertyClass != nullptr) + Param->SetFlags(RF_Transient); + Param->PropertyFlags |= CPF_Parm; + if(Pin->PinType.bIsReference) { - EffectiveClass = ObjProp->PropertyClass; - } - else if (UClassProperty* ClassProp = Cast(ObjProp)) - { - EffectiveClass = ClassProp->MetaClass; + Param->PropertyFlags |= CPF_ReferenceParm | CPF_OutParm; } - if ((EffectiveClass != nullptr) && (EffectiveClass->HasAnyClassFlags(CLASS_Const))) + if(Pin->PinType.bIsConst || (bForceArrayStructRefsConst && (Pin->PinType.IsArray() || Pin->PinType.PinCategory == UEdGraphSchema_K2::PC_Struct) && Pin->PinType.bIsReference)) { Param->PropertyFlags |= CPF_ConstParm; } - } - else if (UArrayProperty* ArrayProp = Cast(Param)) - { - Param->PropertyFlags |= CPF_ReferenceParm; - // ALWAYS pass array parameters as out params, so they're set up as passed by ref - Param->PropertyFlags |= CPF_OutParm; - } + if (UObjectProperty* ObjProp = Cast(Param)) + { + UClass* EffectiveClass = nullptr; + if (ObjProp->PropertyClass != nullptr) + { + EffectiveClass = ObjProp->PropertyClass; + } + else if (UClassProperty* ClassProp = Cast(ObjProp)) + { + EffectiveClass = ClassProp->MetaClass; + } - *InCurrentParamStorageLocation = Param; - InCurrentParamStorageLocation = &Param->Next; + if ((EffectiveClass != nullptr) && (EffectiveClass->HasAnyClassFlags(CLASS_Const))) + { + Param->PropertyFlags |= CPF_ConstParm; + } + } + else if (UArrayProperty* ArrayProp = Cast(Param)) + { + Param->PropertyFlags |= CPF_ReferenceParm; + + // ALWAYS pass array parameters as out params, so they're set up as passed by ref + Param->PropertyFlags |= CPF_OutParm; + } + + *InCurrentParamStorageLocation = Param; + InCurrentParamStorageLocation = &Param->Next; + } } } @@ -1036,6 +1315,7 @@ UClass* FBlueprintCompilationManagerImpl::FastGenerateSkeletonClass(UBlueprint* // Gather all input pins on these nodes, these are // the outputs of the function: TSet UsedPinNames; + static const FName RetValName = FName(TEXT("ReturnValue")); for(UK2Node_FunctionResult* Node : ReturnNodes) { for(UEdGraphPin* Pin : Node->Pins) @@ -1047,15 +1327,30 @@ UClass* FBlueprintCompilationManagerImpl::FastGenerateSkeletonClass(UBlueprint* UsedPinNames.Add(Pin->PinName); UProperty* Param = FKismetCompilerUtilities::CreatePropertyOnScope(NewFunction, *(Pin->PinName), Pin->PinType, Ret, 0, Schema, MessageLog); - Param->PropertyFlags |= CPF_Parm|CPF_ReturnParm; - *InCurrentParamStorageLocation = Param; - InCurrentParamStorageLocation = &Param->Next; + if(Param) + { + Param->SetFlags(RF_Transient); + // we only tag things as CPF_ReturnParm if the value is named ReturnValue.... this is *terrible* behavior: + if(Param->GetFName() == RetValName) + { + Param->PropertyFlags |= CPF_ReturnParm; + } + Param->PropertyFlags |= CPF_Parm|CPF_OutParm; + *InCurrentParamStorageLocation = Param; + InCurrentParamStorageLocation = &Param->Next; + } } } } } } } + + // We're linking the skeleton function because TProperty::LinkInternal + // will assign add TTypeFundamentals::GetComputedFlagsPropertyFlags() + // to PropertyFlags. PropertyFlags must (mostly) match in order for + // functions to be compatible: + NewFunction->StaticLink(true); return NewFunction; }; @@ -1074,13 +1369,14 @@ UClass* FBlueprintCompilationManagerImpl::FastGenerateSkeletonClass(UBlueprint* UField** CurrentParamStorageLocation = nullptr; UFunction* NewFunction = MakeFunction( - FName(*(Graph->GetName() + FunctionNamePostfix)), - InCurrentFieldStorageLocation, - CurrentParamStorageLocation, - bIsStaticFunction, - EntryNode->GetFunctionFlags(), - ReturnNodes, - EntryNode->Pins + FName(*(Graph->GetName() + FunctionNamePostfix)), + InCurrentFieldStorageLocation, + CurrentParamStorageLocation, + bIsStaticFunction, + (EFunctionFlags)(EntryNode->GetFunctionFlags() & ~FUNC_Native), + ReturnNodes, + EntryNode->Pins, + false ); if(NewFunction) @@ -1088,23 +1384,33 @@ UClass* FBlueprintCompilationManagerImpl::FastGenerateSkeletonClass(UBlueprint* // locals: for( const FBPVariableDescription& BPVD : EntryNode->LocalVariables ) { - UProperty* NewProperty = FKismetCompilerUtilities::CreatePropertyOnScope(NewFunction, BPVD.VarName, BPVD.VarType, Ret, 0, Schema, MessageLog); - *CurrentParamStorageLocation = NewProperty; - CurrentParamStorageLocation = &NewProperty->Next; + if(UProperty* LocalVariable = FKismetCompilerContext::CreateUserDefinedLocalVariableForFunction(BPVD, NewFunction, Ret, CurrentParamStorageLocation, Schema, MessageLog) ) + { + LocalVariable->SetFlags(RF_Transient); + } } // __WorldContext: - if(bIsStaticFunction && FindField(NewFunction, TEXT("__WorldContext")) == nullptr) + if(bIsStaticFunction) { - FEdGraphPinType WorldContextPinType(Schema->PC_Object, FString(), UObject::StaticClass(), false, false, false, false, FEdGraphTerminalType()); - UProperty* Param = FKismetCompilerUtilities::CreatePropertyOnScope(NewFunction, TEXT("__WorldContext"), WorldContextPinType, Ret, 0, Schema, MessageLog); - Param->PropertyFlags |= CPF_Parm; - *CurrentParamStorageLocation = Param; - CurrentParamStorageLocation = &Param->Next; + if( FindField(NewFunction, TEXT("__WorldContext")) == nullptr ) + { + FEdGraphPinType WorldContextPinType(Schema->PC_Object, FString(), UObject::StaticClass(), EPinContainerType::None, false, FEdGraphTerminalType()); + UProperty* Param = FKismetCompilerUtilities::CreatePropertyOnScope(NewFunction, TEXT("__WorldContext"), WorldContextPinType, Ret, 0, Schema, MessageLog); + if(Param) + { + Param->SetFlags(RF_Transient); + Param->PropertyFlags |= CPF_Parm; + *CurrentParamStorageLocation = Param; + CurrentParamStorageLocation = &Param->Next; + } + } + + // set the metdata: + NewFunction->SetMetaData(FBlueprintMetadata::MD_WorldContext, TEXT("__WorldContext")); } - NewFunction->Bind(); - NewFunction->StaticLink(true); + FKismetCompilerContext::SetCalculatedMetaDataAndFlags(NewFunction, EntryNode, Schema); } } } @@ -1114,8 +1420,8 @@ UClass* FBlueprintCompilationManagerImpl::FastGenerateSkeletonClass(UBlueprint* Ret->SetSuperStruct(ParentClass); - /*Ret->ClassFlags |= (ParentClass->ClassFlags & CLASS_Inherit); - Ret->ClassCastFlags |= ParentClass->ClassCastFlags;*/ + Ret->ClassFlags |= (ParentClass->ClassFlags & CLASS_Inherit); + Ret->ClassCastFlags |= ParentClass->ClassCastFlags; if (FBlueprintEditorUtils::IsInterfaceBlueprint(BP)) { @@ -1146,13 +1452,14 @@ UClass* FBlueprintCompilationManagerImpl::FastGenerateSkeletonClass(UBlueprint* UField** CurrentParamStorageLocation = nullptr; UFunction* NewFunction = MakeFunction( - EventNodeName, - CurrentFieldStorageLocation, - CurrentParamStorageLocation, - false, - Event->FunctionFlags|FUNC_BlueprintCallable, - TArray(), - Event->Pins + EventNodeName, + CurrentFieldStorageLocation, + CurrentParamStorageLocation, + false, + (EFunctionFlags)(Event->FunctionFlags|FUNC_BlueprintCallable), + TArray(), + Event->Pins, + true ); if(NewFunction) @@ -1179,19 +1486,160 @@ UClass* FBlueprintCompilationManagerImpl::FastGenerateSkeletonClass(UBlueprint* AddFunctionForGraphs(TEXT(""), BP->FunctionGraphs, CurrentFieldStorageLocation, BPTYPE_FunctionLibrary == BP->BlueprintType); + // Add interface functions, often these are added by normal detection of implemented functions, but they won't be + // if the interface is added but the function is not implemented: + for(const FBPInterfaceDescription& BPID : BP->ImplementedInterfaces) + { + UClass* InterfaceClass = BPID.Interface; + if(UBlueprint* Owner = Cast(InterfaceClass->ClassGeneratedBy)) + { + if( ensure(Owner->SkeletonGeneratedClass) ) + { + InterfaceClass = Owner->SkeletonGeneratedClass; + } + } + + for (TFieldIterator FunctionIt(InterfaceClass, EFieldIteratorFlags::ExcludeSuper); FunctionIt; ++FunctionIt) + { + UFunction* Fn = *FunctionIt; + + UField** CurrentParamStorageLocation = nullptr; + + // Note that MakeFunction will early out if the function was created above: + MakeFunction( + Fn->GetFName(), + CurrentFieldStorageLocation, + CurrentParamStorageLocation, + false, + Fn->FunctionFlags & ~FUNC_Native, + TArray(), + TArray(), + false + ); + } + } + CompilerContext.NewClass = Ret; CompilerContext.bAssignDelegateSignatureFunction = true; CompilerContext.FinishCompilingClass(Ret); CompilerContext.bAssignDelegateSignatureFunction = false; CompilerContext.NewClass = OriginalNewClass; - Ret->Bind(); - Ret->StaticLink(/*bRelinkExistingProperties =*/true); + Ret->GetDefaultObject()->SetFlags(RF_Transient); return Ret; } -// Singleton boilperplate: +bool FBlueprintCompilationManagerImpl::IsQueuedForCompilation(UBlueprint* BP) +{ + return BP->bQueuedForCompilation; +} + +// FFixupBytecodeReferences Implementation: +FBlueprintCompilationManagerImpl::FFixupBytecodeReferences::FFixupBytecodeReferences(UObject* InObject) +{ + ArIsObjectReferenceCollector = true; + + InObject->Serialize(*this); + class FArchiveProxyCollector : public FReferenceCollector + { + /** Archive we are a proxy for */ + FArchive& Archive; + public: + FArchiveProxyCollector(FArchive& InArchive) + : Archive(InArchive) + { + } + virtual void HandleObjectReference(UObject*& Object, const UObject* ReferencingObject, const UProperty* ReferencingProperty) override + { + Archive << Object; + } + virtual void HandleObjectReferences(UObject** InObjects, const int32 ObjectNum, const UObject* InReferencingObject, const UProperty* InReferencingProperty) override + { + for (int32 ObjectIndex = 0; ObjectIndex < ObjectNum; ++ObjectIndex) + { + UObject*& Object = InObjects[ObjectIndex]; + Archive << Object; + } + } + virtual bool IsIgnoringArchetypeRef() const override + { + return false; + } + virtual bool IsIgnoringTransient() const override + { + return false; + } + } ArchiveProxyCollector(*this); + + InObject->GetClass()->CallAddReferencedObjects(InObject, ArchiveProxyCollector); +} + +FArchive& FBlueprintCompilationManagerImpl::FFixupBytecodeReferences::operator<<( UObject*& Obj ) +{ + if (Obj != NULL) + { + if(UClass* RelatedClass = Cast(Obj)) + { + UClass* NewClass = RelatedClass->GetAuthoritativeClass(); + ensure(NewClass); + if(NewClass != RelatedClass) + { + Obj = NewClass; + } + } + else if(UField* AsField = Cast(Obj)) + { + UClass* OwningClass = AsField->GetOwnerClass(); + if(OwningClass) + { + UClass* NewClass = OwningClass->GetAuthoritativeClass(); + ensure(NewClass); + if(NewClass != OwningClass) + { + // drill into new class finding equivalent object: + TArray Names; + UObject* Iter = Obj; + while (Iter && Iter != OwningClass) + { + Names.Add(Iter->GetFName()); + Iter = Iter->GetOuter(); + } + + UObject* Owner = NewClass; + UObject* Match = nullptr; + for(int32 I = Names.Num() - 1; I >= 0; --I) + { + UObject* Next = StaticFindObjectFast( UObject::StaticClass(), Owner, Names[I]); + if( Next ) + { + if(I == 0) + { + Match = Next; + } + else + { + Owner = Match; + } + } + else + { + break; + } + } + + if(Match) + { + Obj = Match; + } + } + } + } + } + return *this; +} + +// Singleton boilerplate, simply forwarding to the implementation above: FBlueprintCompilationManagerImpl* BPCMImpl = nullptr; void FlushReinstancingQueueImplWrapper() @@ -1218,14 +1666,16 @@ void FBlueprintCompilationManager::FlushCompilationQueue(TArray* ObjLo { if(BPCMImpl) { - BPCMImpl->FlushCompilationQueueImpl(ObjLoaded); + BPCMImpl->FlushCompilationQueueImpl(ObjLoaded, false); } } -void FBlueprintCompilationManager::QueueForCompilation(UBlueprint* BPToCompile) +void FBlueprintCompilationManager::CompileSynchronously(const FBPCompileRequest& Request) { - check(BPToCompile->GetLinker()); - BPCMImpl->QueueForCompilation(BPToCompile); + if(BPCMImpl) + { + BPCMImpl->CompileSynchronouslyImpl(Request); + } } void FBlueprintCompilationManager::NotifyBlueprintLoaded(UBlueprint* BPLoaded) @@ -1235,8 +1685,14 @@ void FBlueprintCompilationManager::NotifyBlueprintLoaded(UBlueprint* BPLoaded) { FBlueprintCompilationManager::Initialize(); } + + if(FBlueprintEditorUtils::IsCompileOnLoadDisabled(BPLoaded)) + { + return; + } + check(BPLoaded->GetLinker()); - BPCMImpl->QueueForCompilation(BPLoaded); + BPCMImpl->QueueForCompilation(FBPCompileRequest(BPLoaded, EBlueprintCompileOptions::IsRegeneratingOnLoad, nullptr)); } bool FBlueprintCompilationManager::IsGeneratedClassLayoutReady() diff --git a/Engine/Source/Editor/Kismet/Private/BlueprintDetailsCustomization.cpp b/Engine/Source/Editor/Kismet/Private/BlueprintDetailsCustomization.cpp index 3a62deff7537..d6f2f9c8edcf 100644 --- a/Engine/Source/Editor/Kismet/Private/BlueprintDetailsCustomization.cpp +++ b/Engine/Source/Editor/Kismet/Private/BlueprintDetailsCustomization.cpp @@ -54,6 +54,7 @@ #include "SKismetInspector.h" #include "SSCSEditor.h" #include "SPinTypeSelector.h" +#include "NodeFactory.h" #include "Kismet2/Kismet2NameValidators.h" #include "Widgets/Layout/SWidgetSwitcher.h" @@ -445,16 +446,24 @@ void FBlueprintVarActionDetails::CustomizeDetails( IDetailLayoutBuilder& DetailL .ToolTip(ExposeToCinematicsTooltip) ]; - // Build the property specific config variable tool tip - FFormatNamedArguments ConfigTooltipArgs; - if (UClass* OwnerClass = VariableProperty->GetOwnerClass()) + FText LocalisedTooltip; + if (IsConfigCheckBoxEnabled()) { - OwnerClass = OwnerClass->GetAuthoritativeClass(); - ConfigTooltipArgs.Add(TEXT("ConfigPath"), FText::FromString(OwnerClass->GetConfigName())); - ConfigTooltipArgs.Add(TEXT("ConfigSection"), FText::FromString(OwnerClass->GetPathName())); + // Build the property specific config variable tool tip + FFormatNamedArguments ConfigTooltipArgs; + if (UClass* OwnerClass = VariableProperty->GetOwnerClass()) + { + OwnerClass = OwnerClass->GetAuthoritativeClass(); + ConfigTooltipArgs.Add(TEXT("ConfigPath"), FText::FromString(OwnerClass->GetConfigName())); + ConfigTooltipArgs.Add(TEXT("ConfigSection"), FText::FromString(OwnerClass->GetPathName())); + } + LocalisedTooltip = FText::Format(LOCTEXT("VariableExposeToConfig_Tooltip", "Should this variable read its default value from a config file if it is present?\r\n\r\nThis is used for customising variable default values and behavior between different projects and configurations.\r\n\r\nConfig file [{ConfigPath}]\r\nConfig section [{ConfigSection}]"), ConfigTooltipArgs); + } + else if (IsVariableInBlueprint()) + { + // mimics the error that UHT would throw + LocalisedTooltip = LOCTEXT("ObjectVariableConfig_Tooltip", "Not allowed to use 'config' with object variables"); } - const FText LocalisedTooltip = FText::Format(LOCTEXT("VariableExposeToConfig_Tooltip", "Should this variable read its default value from a config file if it is present?\r\n\r\nThis is used for customising variable default values and behavior between different projects and configurations.\r\n\r\nConfig file [{ConfigPath}]\r\nConfig section [{ConfigSection}]"), ConfigTooltipArgs); - TSharedPtr ExposeToConfigTooltip = IDocumentation::Get()->CreateToolTip(LocalisedTooltip, NULL, DocLink, TEXT("ExposeToConfig")); Category.AddCustomRow( LOCTEXT("VariableExposeToConfig", "Config Variable"), true ) @@ -472,7 +481,7 @@ void FBlueprintVarActionDetails::CustomizeDetails( IDetailLayoutBuilder& DetailL .ToolTip( ExposeToConfigTooltip ) .IsChecked( this, &FBlueprintVarActionDetails::OnGetConfigVariableCheckboxState ) .OnCheckStateChanged( this, &FBlueprintVarActionDetails::OnSetConfigVariableState ) - .IsEnabled(IsVariableInBlueprint()) + .IsEnabled(this, &FBlueprintVarActionDetails::IsConfigCheckBoxEnabled) ]; PopulateCategories(MyBlueprint.Pin().Get(), CategorySource); @@ -767,15 +776,15 @@ void FBlueprintVarActionDetails::CustomizeDetails( IDetailLayoutBuilder& DetailL OriginalProperty = VariableProperty; } - if (OriginalProperty == NULL || bVariableRenamed) + if (OriginalProperty == nullptr || bVariableRenamed) { // Prevent editing the default value of a skeleton property - VariableProperty = NULL; + VariableProperty = nullptr; } - else if (auto StructProperty = Cast(OriginalProperty)) + else if (const UStructProperty* StructProperty = Cast(OriginalProperty)) { // Prevent editing the default value of a stale struct - auto BGStruct = Cast(StructProperty->Struct); + const UUserDefinedStruct* BGStruct = Cast(StructProperty->Struct); if (BGStruct && (EUserDefinedStructureStatus::UDSS_UpToDate != BGStruct->Status)) { VariableProperty = nullptr; @@ -784,7 +793,7 @@ void FBlueprintVarActionDetails::CustomizeDetails( IDetailLayoutBuilder& DetailL } // Find the class containing the variable - UClass* VariableClass = (VariableProperty != NULL) ? VariableProperty->GetTypedOuter() : nullptr; + UClass* VariableClass = (VariableProperty ? VariableProperty->GetTypedOuter() : nullptr); FText ErrorMessage; IDetailCategoryBuilder& DefaultValueCategory = DetailLayout.EditCategory(TEXT("DefaultValueCategory"), LOCTEXT("DefaultValueCategoryHeading", "Default Value")); @@ -834,7 +843,7 @@ void FBlueprintVarActionDetails::CustomizeDetails( IDetailLayoutBuilder& DetailL const bool bUDSProperty = PotentialUDSProperty && Cast(PotentialUDSProperty->Struct); UK2Node_FunctionEntry* FuncEntry = EntryNodes[0]; - for(auto& LocalVar : FuncEntry->LocalVariables) + for (const FBPVariableDescription& LocalVar : FuncEntry->LocalVariables) { if(LocalVar.VarName == VariableProperty->GetFName()) //Property->GetFName()) { @@ -1346,11 +1355,11 @@ void FBlueprintVarActionDetails::PopulateCategories(SMyBlueprint* MyBlueprint, T } } - CategorySource.Empty(); + CategorySource.Reset(); CategorySource.Add(MakeShareable(new FText(LOCTEXT("Default", "Default")))); for (int32 i = 0; i < VisibleVariables.Num(); ++i) { - FText Category = FBlueprintEditorUtils::GetBlueprintVariableCategory(Blueprint, VisibleVariables[i], NULL); + FText Category = FBlueprintEditorUtils::GetBlueprintVariableCategory(Blueprint, VisibleVariables[i], nullptr); if (!Category.IsEmpty() && !Category.EqualTo(FText::FromString(Blueprint->GetName()))) { bool bNewCategory = true; @@ -1387,7 +1396,7 @@ void FBlueprintVarActionDetails::PopulateCategories(SMyBlueprint* MyBlueprint, T } } - auto EntryNode = FBlueprintEditorUtils::GetEntryNode(FunctionGraph); + UK2Node_EditablePinBase* EntryNode = FBlueprintEditorUtils::GetEntryNode(FunctionGraph); if (UK2Node_FunctionEntry* FunctionEntryNode = Cast(EntryNode)) { for (FBPVariableDescription& Variable : FunctionEntryNode->LocalVariables) @@ -1407,7 +1416,7 @@ void FBlueprintVarActionDetails::PopulateCategories(SMyBlueprint* MyBlueprint, T for (UEdGraph* MacroGraph : Blueprint->MacroGraphs) { - auto EntryNode = FBlueprintEditorUtils::GetEntryNode(MacroGraph); + UK2Node_EditablePinBase* EntryNode = FBlueprintEditorUtils::GetEntryNode(MacroGraph); if (UK2Node_Tunnel* TypedEntryNode = ExactCast(EntryNode)) { bool bNewCategory = true; @@ -1973,6 +1982,21 @@ EVisibility FBlueprintVarActionDetails::ExposeConfigVisibility() const return EVisibility::Collapsed; } +bool FBlueprintVarActionDetails::IsConfigCheckBoxEnabled() const +{ + bool bEnabled = IsVariableInBlueprint(); + if (bEnabled && CachedVariableProperty.IsValid()) + { + if (UProperty* VariableProperty = CachedVariableProperty.Get()) + { + // meant to match up with UHT's FPropertyBase::IsObject(), which it uses to block object properties from being marked with CPF_Config + bEnabled = VariableProperty->IsA() || VariableProperty->IsA() || VariableProperty->IsA() || + (!VariableProperty->IsA() && !VariableProperty->IsA()); + } + } + return bEnabled; +} + FText FBlueprintVarActionDetails::OnGetMetaKeyValue(FName Key) const { FName VarName = CachedVariableName; @@ -2488,10 +2512,14 @@ void FBlueprintVarActionDetails::OnFinishedChangingProperties(const FPropertyCha UK2Node_FunctionEntry* FuncEntry = Cast(InEntryNode.Get()); // Search out the correct local variable in the Function Entry Node and set the default value - for(auto& LocalVar : FuncEntry->LocalVariables) + for (FBPVariableDescription& LocalVar : FuncEntry->LocalVariables) { - if(LocalVar.VarName == DirectProperty->GetFName()) + if (LocalVar.VarName == DirectProperty->GetFName() && LocalVar.DefaultValue != DefaultValueString) { + const FScopedTransaction Transaction(LOCTEXT("ChangeDefaults", "Change Defaults")); + + FuncEntry->Modify(); + GetBlueprintObj()->Modify(); LocalVar.DefaultValue = DefaultValueString; FBlueprintEditorUtils::MarkBlueprintAsModified(GetBlueprintObj()); break; @@ -2678,22 +2706,39 @@ void FBlueprintGraphArgumentLayout::GenerateChildContent( IDetailChildrenBuilder { if (bHasDefaultValue) { - ChildrenBuilder.AddChildContent( LOCTEXT( "FunctionArgDetailsDefaultValue", "Default Value" ) ) - .NameContent() - [ - SNew(STextBlock) - .Text( LOCTEXT( "FunctionArgDetailsDefaultValue", "Default Value" ) ) - .ToolTipText( LOCTEXT("FunctionArgDetailsDefaultValueParamTooltip", "The default value of the parameter.") ) - .Font( IDetailLayoutBuilder::GetDetailFont() ) - ] - .ValueContent() - [ - SNew(SEditableTextBox) - .Text( this, &FBlueprintGraphArgumentLayout::OnGetArgDefaultValueText ) - .OnTextCommitted( this, &FBlueprintGraphArgumentLayout::OnArgDefaultValueCommitted ) - .IsEnabled(!ShouldPinBeReadOnly()) - .Font( IDetailLayoutBuilder::GetDetailFont() ) - ]; + if (UEdGraphPin* FoundPin = GetPin()) + { + // Certain types are outlawed at the compiler level + bool bTypeWithNoDefaults = (FoundPin->PinType.PinCategory == UEdGraphSchema_K2::PC_Object) || (FoundPin->PinType.PinCategory == UEdGraphSchema_K2::PC_Class) || (FoundPin->PinType.PinCategory == UEdGraphSchema_K2::PC_Interface); + + if (!FoundPin->PinType.bIsReference && !bTypeWithNoDefaults) + { + DefaultValuePinWidget = FNodeFactory::CreatePinWidget(FoundPin); + DefaultValuePinWidget->SetOnlyShowDefaultValue(true); + TSharedRef DefaultValueWidget = DefaultValuePinWidget->GetDefaultValueWidget(); + + if (DefaultValueWidget != SNullWidget::NullWidget) + { + ChildrenBuilder.AddChildContent(LOCTEXT("FunctionArgDetailsDefaultValue", "Default Value")) + .NameContent() + [ + SNew(STextBlock) + .Text(LOCTEXT("FunctionArgDetailsDefaultValue", "Default Value")) + .ToolTipText(LOCTEXT("FunctionArgDetailsDefaultValueParamTooltip", "The default value of the parameter.")) + .Font(IDetailLayoutBuilder::GetDetailFont()) + ] + .ValueContent() + .MaxDesiredWidth(512) + [ + DefaultValueWidget + ]; + } + else + { + DefaultValuePinWidget.Reset(); + } + } + } ChildrenBuilder.AddChildContent( LOCTEXT( "FunctionArgDetailsPassByReference", "Pass-by-Reference" ) ) .NameContent() @@ -2715,11 +2760,11 @@ void FBlueprintGraphArgumentLayout::GenerateChildContent( IDetailChildrenBuilder } -namespace { - +namespace +{ static TArray GatherAllResultNodes(UK2Node_EditablePinBase* TargetNode) { - if (auto ResultNode = Cast(TargetNode)) + if (UK2Node_FunctionResult* ResultNode = Cast(TargetNode)) { return (TArray)ResultNode->GetAllResultNodes(); } @@ -2735,14 +2780,14 @@ namespace { void FBlueprintGraphArgumentLayout::OnRemoveClicked() { - auto ParamItem = ParamItemPtr.Pin(); + TSharedPtr ParamItem = ParamItemPtr.Pin(); if (ParamItem.IsValid()) { const FScopedTransaction Transaction( LOCTEXT( "RemoveParam", "Remove Parameter" ) ); - auto GraphActionDetails = GraphActionDetailsPtr.Pin(); - auto TargetNodes = GatherAllResultNodes(TargetNode); - for (auto Node : TargetNodes) + TSharedPtr GraphActionDetails = GraphActionDetailsPtr.Pin(); + TArray TargetNodes = GatherAllResultNodes(TargetNode); + for (UK2Node_EditablePinBase* Node : TargetNodes) { Node->Modify(); Node->RemoveUserDefinedPinByName(ParamItem->PinName); @@ -2762,13 +2807,13 @@ FReply FBlueprintGraphArgumentLayout::OnArgMoveUp() if (ThisParamIndex != INDEX_NONE && NewParamIndex >= 0) { const FScopedTransaction Transaction( LOCTEXT("K2_MovePinUp", "Move Pin Up") ); - auto TargetNodes = GatherAllResultNodes(TargetNode); - for (auto Node : TargetNodes) + TArray TargetNodes = GatherAllResultNodes(TargetNode); + for (UK2Node_EditablePinBase* Node : TargetNodes) { Node->Modify(); Node->UserDefinedPins.Swap(ThisParamIndex, NewParamIndex); - auto GraphActionDetails = GraphActionDetailsPtr.Pin(); + TSharedPtr GraphActionDetails = GraphActionDetailsPtr.Pin(); if (GraphActionDetails.IsValid()) { GraphActionDetails->OnParamsChanged(Node, true); @@ -2785,13 +2830,13 @@ FReply FBlueprintGraphArgumentLayout::OnArgMoveDown() if (ThisParamIndex != INDEX_NONE && NewParamIndex < TargetNode->UserDefinedPins.Num()) { const FScopedTransaction Transaction( LOCTEXT("K2_MovePinDown", "Move Pin Down") ); - auto TargetNodes = GatherAllResultNodes(TargetNode); - for (auto Node : TargetNodes) + TArray TargetNodes = GatherAllResultNodes(TargetNode); + for (UK2Node_EditablePinBase* Node : TargetNodes) { Node->Modify(); Node->UserDefinedPins.Swap(ThisParamIndex, NewParamIndex); - auto GraphActionDetails = GraphActionDetailsPtr.Pin(); + TSharedPtr GraphActionDetails = GraphActionDetailsPtr.Pin(); if (GraphActionDetails.IsValid()) { GraphActionDetails->OnParamsChanged(Node, true); @@ -2903,6 +2948,15 @@ FEdGraphPinType FBlueprintGraphArgumentLayout::OnGetPinInfo() const return FEdGraphPinType(); } +UEdGraphPin* FBlueprintGraphArgumentLayout::GetPin() const +{ + if (ParamItemPtr.IsValid() && TargetNode) + { + return TargetNode->FindPin(ParamItemPtr.Pin()->PinName, ParamItemPtr.Pin()->DesiredPinDirection); + } + return nullptr; +} + ECheckBoxState FBlueprintGraphArgumentLayout::IsRefChecked() const { FEdGraphPinType PinType = OnGetPinInfo(); @@ -2913,9 +2967,9 @@ void FBlueprintGraphArgumentLayout::OnRefCheckStateChanged(ECheckBoxState InStat { FEdGraphPinType PinType = OnGetPinInfo(); PinType.bIsReference = (InState == ECheckBoxState::Checked)? true : false; - // Note: Array types are implicitly passed by reference. For custom event nodes, the reference flag is essentially - // treated as being redundant on array inputs, but we also need to implicitly set the 'const' flag to avoid a compiler note. - PinType.bIsConst = (PinType.bIsArray || PinType.bIsReference) && TargetNode && TargetNode->IsA(); + // Note: Container types are implicitly passed by reference. For custom event nodes, the reference flag is essentially + // treated as being redundant on container inputs, but we also need to implicitly set the 'const' flag to avoid a compiler note. + PinType.bIsConst = (PinType.IsContainer() || PinType.bIsReference) && TargetNode && TargetNode->IsA(); PinInfoChanged(PinType); } @@ -2939,7 +2993,7 @@ void FBlueprintGraphArgumentLayout::PinInfoChanged(const FEdGraphPinType& PinTyp { if (Node) { - auto UDPinPtr = Node->UserDefinedPins.FindByPredicate([&](TSharedPtr& UDPin) + TSharedPtr* UDPinPtr = Node->UserDefinedPins.FindByPredicate([&](TSharedPtr& UDPin) { return UDPin.IsValid() && (UDPin->PinName == PinName); }); @@ -2947,8 +3001,11 @@ void FBlueprintGraphArgumentLayout::PinInfoChanged(const FEdGraphPinType& PinTyp { (*UDPinPtr)->PinType = PinType; - // Array types are implicitly passed by reference. For custom event nodes, since they are inputs, also implicitly treat them as 'const' so that they don't result in a compiler note. - (*UDPinPtr)->PinType.bIsConst = PinType.bIsArray && Node->IsA(); + // Container types are implicitly passed by reference. For custom event nodes, since they are inputs, also implicitly treat them as 'const' so that they don't result in a compiler note. + (*UDPinPtr)->PinType.bIsConst = PinType.IsContainer() && Node->IsA(); + + // Reset default value, it probably doesn't match + (*UDPinPtr)->PinDefaultValue.Reset(); } GraphActionDetailsPinned->OnParamsChanged(Node); } @@ -2960,10 +3017,10 @@ void FBlueprintGraphArgumentLayout::PinInfoChanged(const FEdGraphPinType& PinTyp void FBlueprintGraphArgumentLayout::OnPrePinInfoChange(const FEdGraphPinType& PinType) { - if( !ShouldPinBeReadOnly(true)) + if (!ShouldPinBeReadOnly(true)) { - auto TargetNodes = GatherAllResultNodes(TargetNode); - for (auto Node : TargetNodes) + TArray TargetNodes = GatherAllResultNodes(TargetNode); + for (UK2Node_EditablePinBase* Node : TargetNodes) { if (Node) { @@ -2973,33 +3030,6 @@ void FBlueprintGraphArgumentLayout::OnPrePinInfoChange(const FEdGraphPinType& Pi } } -FText FBlueprintGraphArgumentLayout::OnGetArgDefaultValueText() const -{ - if (ParamItemPtr.IsValid()) - { - return FText::FromString(ParamItemPtr.Pin()->PinDefaultValue); - } - return FText(); -} - -void FBlueprintGraphArgumentLayout::OnArgDefaultValueCommitted(const FText& NewText, ETextCommit::Type InTextCommit) -{ - auto GraphActionDetailsPinned = GraphActionDetailsPtr.Pin(); - if (!NewText.IsEmpty() - && !ShouldPinBeReadOnly() - && (InTextCommit == ETextCommit::OnEnter || InTextCommit == ETextCommit::OnUserMovedFocus) - && ParamItemPtr.IsValid() - && GraphActionDetailsPinned.IsValid()) - { - bool bSuccess = TargetNode->ModifyUserDefinedPinDefaultValue(ParamItemPtr.Pin(), NewText.ToString()); - if (bSuccess) - { - GraphActionDetailsPinned->OnParamsChanged(TargetNode); - } - } -} - - BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION void FBlueprintGraphActionDetails::CustomizeDetails( IDetailLayoutBuilder& DetailLayout ) { @@ -3490,6 +3520,11 @@ void FBlueprintGraphActionDetails::CustomizeDetails( IDetailLayoutBuilder& Detai ]; } } + + if (bHasAGraph) + { + MyRegisteredGraphChangedDelegateHandle = GetGraph()->AddOnGraphChangedHandler(FOnGraphChanged::FDelegate::CreateSP(this, &FBaseBlueprintGraphActionDetails::OnGraphChanged)); + } } END_SLATE_FUNCTION_BUILD_OPTIMIZATION @@ -3574,6 +3609,21 @@ bool FBaseBlueprintGraphActionDetails::AttemptToCreateResultNode() return FunctionResultNodePtr.IsValid(); } +FBaseBlueprintGraphActionDetails::~FBaseBlueprintGraphActionDetails() +{ + UEdGraph* MyGraph = GetGraph(); + if (MyRegisteredGraphChangedDelegateHandle.IsValid() && MyGraph) + { + MyGraph->RemoveOnGraphChangedHandler(MyRegisteredGraphChangedDelegateHandle); + } +} + +void FBaseBlueprintGraphActionDetails::OnGraphChanged(const FEdGraphEditAction& Action) +{ + /** Graph changed, need to refresh inputs in case pin UI changed */ + RegenerateInputsChildrenDelegate.ExecuteIfBound(); +} + void FBaseBlueprintGraphActionDetails::SetRefreshDelegate(FSimpleDelegate RefreshDelegate, bool bForInputs) { ((bForInputs) ? RegenerateInputsChildrenDelegate : RegenerateOutputsChildrenDelegate) = RefreshDelegate; @@ -3909,7 +3959,7 @@ void FBlueprintDelegateActionDetails::OnFunctionSelected(TSharedPtr Fun { while (FunctionEntryNode->UserDefinedPins.Num()) { - auto Pin = FunctionEntryNode->UserDefinedPins[0]; + TSharedPtr Pin = FunctionEntryNode->UserDefinedPins[0]; FunctionEntryNode->RemoveUserDefinedPin(Pin); } @@ -3939,28 +3989,10 @@ void FBaseBlueprintGraphActionDetails::OnParamsChanged(UK2Node_EditablePinBase* // Reconstruct the entry/exit definition and recompile the blueprint to make sure the signature has changed before any fixups TargetNode->ReconstructNode(); - FParamsChangedHelper ParamsChangedHelper; - ParamsChangedHelper.ModifiedBlueprints.Add(GetBlueprintObj()); - FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(GetBlueprintObj()); - ParamsChangedHelper.Broadcast(GetBlueprintObj(), TargetNode, Graph); + const UEdGraphSchema_K2* K2Schema = GetDefault(); - for (auto GraphIt = ParamsChangedHelper.ModifiedGraphs.CreateIterator(); GraphIt; ++GraphIt) - { - if(UEdGraph* ModifiedGraph = *GraphIt) - { - ModifiedGraph->NotifyGraphChanged(); - } - } - - // Now update all the blueprints that got modified - for (auto BlueprintIt = ParamsChangedHelper.ModifiedBlueprints.CreateIterator(); BlueprintIt; ++BlueprintIt) - { - if(UBlueprint* Blueprint = *BlueprintIt) - { - Blueprint->BroadcastChanged(); - } - } + K2Schema->HandleParameterDefaultValueChanged(TargetNode); } } @@ -4005,8 +4037,8 @@ bool FBaseBlueprintGraphActionDetails::OnVerifyPinRename(UK2Node_EditablePinBase if (InTargetNode) { // Check if the name conflicts with any of the other internal UFunction's property names (local variables and parameters). - const auto FoundFunction = FFunctionFromNodeHelper::FunctionFromNode(InTargetNode); - const auto ExistingProperty = FindField(FoundFunction, *InNewName); + const UFunction* FoundFunction = FFunctionFromNodeHelper::FunctionFromNode(InTargetNode); + const UProperty* ExistingProperty = FindField(FoundFunction, *InNewName); if (ExistingProperty) { OutErrorMessage = LOCTEXT("ConflictsWithProperty", "Conflicts with another another local variable or function parameter!"); @@ -4033,12 +4065,12 @@ bool FBaseBlueprintGraphActionDetails::OnPinRenamed(UK2Node_EditablePinBase* Tar const FScopedTransaction Transaction(LOCTEXT("RenameParam", "Rename Parameter")); - auto TerminalNodes = GatherAllResultNodes(FunctionResultNodePtr.Get()); - if (auto EntryNode = FunctionEntryNodePtr.Get()) + TArray TerminalNodes = GatherAllResultNodes(FunctionResultNodePtr.Get()); + if (UK2Node_EditablePinBase* EntryNode = FunctionEntryNodePtr.Get()) { TerminalNodes.Add(EntryNode); } - for (auto TerminalNode : TerminalNodes) + for (UK2Node_EditablePinBase* TerminalNode : TerminalNodes) { TerminalNode->Modify(); PinRenamedHelper.NodesToRename.Add(TerminalNode); @@ -4050,24 +4082,23 @@ bool FBaseBlueprintGraphActionDetails::OnPinRenamed(UK2Node_EditablePinBase* Tar PinRenamedHelper.Broadcast(GetBlueprintObj(), TargetNode, Graph); // TEST - for(auto NodeIter = PinRenamedHelper.NodesToRename.CreateIterator(); NodeIter; ++NodeIter) + for (UK2Node* NodeToRename : PinRenamedHelper.NodesToRename) { - if(ERenamePinResult::ERenamePinResult_NameCollision == (*NodeIter)->RenameUserDefinedPin(OldName, NewName, true)) + if (ERenamePinResult::ERenamePinResult_NameCollision == NodeToRename->RenameUserDefinedPin(OldName, NewName, true)) { - // log return false; } } // UPDATE - for(auto NodeIter = PinRenamedHelper.NodesToRename.CreateIterator(); NodeIter; ++NodeIter) + for (UK2Node* NodeToRename : PinRenamedHelper.NodesToRename) { - (*NodeIter)->RenameUserDefinedPin(OldName, NewName, false); + NodeToRename->RenameUserDefinedPin(OldName, NewName, false); } - for (auto TerminalNode : TerminalNodes) + for (UK2Node_EditablePinBase* TerminalNode : TerminalNodes) { - auto UDPinPtr = TerminalNode->UserDefinedPins.FindByPredicate([&](TSharedPtr& Pin) + TSharedPtr* UDPinPtr = TerminalNode->UserDefinedPins.FindByPredicate([&](TSharedPtr& Pin) { return Pin.IsValid() && (Pin->PinName == OldName); }); @@ -4205,7 +4236,7 @@ void FBlueprintGraphActionDetails::OnTooltipTextCommitted(const FText& NewText, if (FKismetUserDeclaredFunctionMetadata* Metadata = GetMetadataBlock()) { Metadata->ToolTip = NewText; - if(auto Function = FindFunction()) + if (UFunction* Function = FindFunction()) { Function->Modify(); Function->SetMetaData(FBlueprintMetadata::MD_Tooltip, *NewText.ToString()); @@ -4250,7 +4281,7 @@ void FBlueprintGraphActionDetails::OnCategoryTextCommitted(const FText& NewText, Metadata->Category = CategoryName; } - if(auto Function = FindFunction()) + if (UFunction* Function = FindFunction()) { Function->Modify(); Function->SetMetaData(FBlueprintMetadata::MD_FunctionCategory, *CategoryName.ToString()); @@ -4268,7 +4299,7 @@ void FBlueprintGraphActionDetails::OnCategorySelectionChanged( TSharedPtr if (FKismetUserDeclaredFunctionMetadata* Metadata = GetMetadataBlock()) { Metadata->Category = *ProposedSelection.Get(); - if(auto Function = FindFunction()) + if (UFunction* Function = FindFunction()) { Function->Modify(); Function->SetMetaData(FBlueprintMetadata::MD_FunctionCategory, *ProposedSelection.Get()->ToString()); @@ -4314,7 +4345,7 @@ void FBlueprintGraphActionDetails::OnKeywordsTextCommitted(const FText& NewText, { Metadata->Keywords = Keywords; - if(auto Function = FindFunction()) + if (UFunction* Function = FindFunction()) { Function->Modify(); Function->SetMetaData(FBlueprintMetadata::MD_FunctionKeywords, *Keywords.ToString()); @@ -4349,7 +4380,7 @@ void FBlueprintGraphActionDetails::OnCompactNodeTitleTextCommitted(const FText& { Metadata->CompactNodeTitle = CompactNodeTitle; - if(auto Function = FindFunction()) + if (UFunction* Function = FindFunction()) { Function->Modify(); @@ -4456,13 +4487,13 @@ void FBlueprintGraphActionDetails::OnAccessSpecifierSelected( TSharedPtrModify(); - auto Function = FindFunction(); + UFunction* Function = FindFunction(); if(Function) { Function->Modify(); } - const uint32 ClearAccessSpecifierMask = ~FUNC_AccessSpecifiers; + const EFunctionFlags ClearAccessSpecifierMask = ~FUNC_AccessSpecifiers; if(UK2Node_FunctionEntry* EntryNode = Cast(FunctionEntryNode)) { int32 ExtraFlags = EntryNode->GetExtraFlags(); @@ -4619,9 +4650,9 @@ bool FBlueprintGraphActionDetails::IsPureFunctionVisible() const void FBlueprintGraphActionDetails::OnIsPureFunctionModified( const ECheckBoxState NewCheckedState ) { UK2Node_EditablePinBase * FunctionEntryNode = FunctionEntryNodePtr.Get(); - auto Function = FindFunction(); - auto EntryNode = Cast(FunctionEntryNode); - if(EntryNode && Function) + UFunction* Function = FindFunction(); + UK2Node_FunctionEntry* EntryNode = Cast(FunctionEntryNode); + if (EntryNode && Function) { const FScopedTransaction Transaction( LOCTEXT( "ChangePure", "Change Pure" ) ); EntryNode->Modify(); @@ -4636,8 +4667,8 @@ void FBlueprintGraphActionDetails::OnIsPureFunctionModified( const ECheckBoxStat ECheckBoxState FBlueprintGraphActionDetails::GetIsPureFunction() const { - UK2Node_EditablePinBase * FunctionEntryNode = FunctionEntryNodePtr.Get(); - auto EntryNode = Cast(FunctionEntryNode); + UK2Node_EditablePinBase* FunctionEntryNode = FunctionEntryNodePtr.Get(); + UK2Node_FunctionEntry* EntryNode = Cast(FunctionEntryNode); if(!EntryNode) { return ECheckBoxState::Undetermined; @@ -4663,8 +4694,8 @@ bool FBlueprintGraphActionDetails::IsConstFunctionVisible() const void FBlueprintGraphActionDetails::OnIsConstFunctionModified( const ECheckBoxState NewCheckedState ) { UK2Node_EditablePinBase * FunctionEntryNode = FunctionEntryNodePtr.Get(); - auto Function = FindFunction(); - auto EntryNode = Cast(FunctionEntryNode); + UFunction* Function = FindFunction(); + UK2Node_FunctionEntry* EntryNode = Cast(FunctionEntryNode); if(EntryNode && Function) { const FScopedTransaction Transaction( LOCTEXT( "ChangeConst", "Change Const" ) ); @@ -4680,8 +4711,8 @@ void FBlueprintGraphActionDetails::OnIsConstFunctionModified( const ECheckBoxSta ECheckBoxState FBlueprintGraphActionDetails::GetIsConstFunction() const { - UK2Node_EditablePinBase * FunctionEntryNode = FunctionEntryNodePtr.Get(); - auto EntryNode = Cast(FunctionEntryNode); + UK2Node_EditablePinBase* FunctionEntryNode = FunctionEntryNodePtr.Get(); + UK2Node_FunctionEntry* EntryNode = Cast(FunctionEntryNode); if(!EntryNode) { return ECheckBoxState::Undetermined; @@ -4784,13 +4815,13 @@ FReply FBlueprintGraphActionDetails::OnAddNewOutputClicked() } const FString NewPinName = FunctionResultNode->CreateUniquePinName(TEXT("NewParam")); - auto TargetNodes = GatherAllResultNodes(FunctionResultNode); + TArray TargetNodes = GatherAllResultNodes(FunctionResultNode); bool bAllChanged = TargetNodes.Num() > 0; - for (auto Node : TargetNodes) + for (UK2Node_EditablePinBase* Node : TargetNodes) { Node->Modify(); - auto NewPin = Node->CreateUserDefinedPin(NewPinName, PinType, EGPD_Input, false); - bAllChanged &= nullptr != NewPin; + UEdGraphPin* NewPin = Node->CreateUserDefinedPin(NewPinName, PinType, EGPD_Input, false); + bAllChanged &= (nullptr != NewPin); if (bAllChanged) { @@ -4844,10 +4875,9 @@ void FBlueprintInterfaceLayout::GenerateChildContent( IDetailChildrenBuilder& Ch if (!bShowsInheritedInterfaces) { // Generate a list of interfaces already implemented - for (TArray::TConstIterator It(Blueprint->ImplementedInterfaces); It; ++It) + for (const FBPInterfaceDescription& ImplementedInterface : Blueprint->ImplementedInterfaces) { - auto Interface = (*It).Interface; - if (Interface) + if (const TSubclassOf Interface = ImplementedInterface.Interface) { Interfaces.AddUnique(FInterfaceName(Interface->GetFName(), Interface->GetDisplayNameText())); } @@ -6020,14 +6050,6 @@ void FChildActorComponentDetails::CustomizeDetails(IDetailLayoutBuilder& DetailB } } - - auto TemplatesVisible = [](const TArray>& WeakObjects) - { - bool bResult = true; - - return bResult; - }; - TArray> ObjectsBeingCustomized; DetailBuilder.GetObjectsBeingCustomized(ObjectsBeingCustomized); @@ -6203,9 +6225,9 @@ TSharedRef FBlueprintDocumentationDetails::GenerateExcerptList() TArray Excerpts; DocumentationPage->GetExcerpts( Excerpts ); - for( auto ExcerptIter = Excerpts.CreateConstIterator(); ExcerptIter; ++ExcerptIter ) + for (const FExcerpt& Excerpt : Excerpts) { - ExcerptList.Add( MakeShareable( new FString( ExcerptIter->Name ))); + ExcerptList.Add( MakeShareable( new FString( Excerpt.Name ))); } } diff --git a/Engine/Source/Editor/Kismet/Private/BlueprintDetailsCustomization.h b/Engine/Source/Editor/Kismet/Private/BlueprintDetailsCustomization.h index b1be6e8947f4..8938cdf376c3 100644 --- a/Engine/Source/Editor/Kismet/Private/BlueprintDetailsCustomization.h +++ b/Engine/Source/Editor/Kismet/Private/BlueprintDetailsCustomization.h @@ -15,6 +15,7 @@ #include "Widgets/Views/STableViewBase.h" #include "Widgets/Views/STableRow.h" #include "SMyBlueprint.h" +#include "SGraphPin.h" class Error; class FBlueprintGlobalOptionsDetails; @@ -179,6 +180,7 @@ private: ECheckBoxState OnGetConfigVariableCheckboxState() const; void OnSetConfigVariableState(ECheckBoxState InNewState); EVisibility ExposeConfigVisibility() const; + bool IsConfigCheckBoxEnabled() const; FText OnGetMetaKeyValue(FName Key) const; void OnMetaKeyValueChanged(const FText& NewMinValue, ETextCommit::Type CommitInfo, FName Key); @@ -284,7 +286,7 @@ private: class FBaseBlueprintGraphActionDetails : public IDetailCustomization { public: - virtual ~FBaseBlueprintGraphActionDetails(){}; + virtual ~FBaseBlueprintGraphActionDetails(); FBaseBlueprintGraphActionDetails(TWeakPtr InMyBlueprint) : MyBlueprint(InMyBlueprint) @@ -323,14 +325,13 @@ public: FReply OnAddNewInputClicked(); + /** Called when blueprint graph changes */ + void OnGraphChanged(const FEdGraphEditAction& Action); + protected: /** Tries to create the result node (if there are output args) */ bool AttemptToCreateResultNode(); - /** Toggles the ability to be called in editor */ - void OnToggleEditorCallableEvent( const ECheckBoxState NewCheckedState, TWeakObjectPtr SelectedNode ) const; - -protected: /** Pointer to the parent */ TWeakPtr MyBlueprint; @@ -346,6 +347,9 @@ protected: /** Details layout builder we need to hold on to to refresh it at times */ IDetailLayoutBuilder* DetailsLayoutPtr; + + /** Handle for graph refresh delegate */ + FDelegateHandle MyRegisteredGraphChangedDelegateHandle; /** Array of nodes were were constructed to represent */ TArray< TWeakObjectPtr > ObjectsBeingEdited; @@ -468,15 +472,15 @@ private: void PinInfoChanged(const FEdGraphPinType& PinType); void OnPrePinInfoChange(const FEdGraphPinType& PinType); + /** Returns the graph pin representing this variable */ + UEdGraphPin* GetPin() const; + /** Returns whether the "Pass-by-Reference" checkbox is checked or not */ ECheckBoxState IsRefChecked() const; /** Handles toggling the "Pass-by-Reference" checkbox */ void OnRefCheckStateChanged(ECheckBoxState InState); - FText OnGetArgDefaultValueText() const; - void OnArgDefaultValueCommitted(const FText& NewText, ETextCommit::Type InTextCommit); - private: /** The parent graph action details customization */ TWeakPtr GraphActionDetailsPtr; @@ -495,6 +499,9 @@ private: /** Holds a weak pointer to the argument name widget, used for error notifications */ TWeakPtr ArgumentNameWidget; + + /** The SGraphPin widget created to show/edit default value */ + TSharedPtr DefaultValuePinWidget; }; /** Details customization for functions and graphs selected in the MyBlueprint panel */ diff --git a/Engine/Source/Editor/Kismet/Private/BlueprintEditor.cpp b/Engine/Source/Editor/Kismet/Private/BlueprintEditor.cpp index fdbb3ddac07c..4e6a287f190e 100644 --- a/Engine/Source/Editor/Kismet/Private/BlueprintEditor.cpp +++ b/Engine/Source/Editor/Kismet/Private/BlueprintEditor.cpp @@ -586,7 +586,8 @@ bool FBlueprintEditor::OnRequestClose() bool FBlueprintEditor::InEditingMode() const { - return !InDebuggingMode(); + UBlueprint* Blueprint = GetBlueprintObj(); + return !FSlateApplication::Get().InKismetDebuggingMode() && (!InDebuggingMode() || (Blueprint && Blueprint->CanRecompileWhilePlayingInEditor())); } bool FBlueprintEditor::IsCompilingEnabled() const @@ -996,6 +997,11 @@ TSharedRef FBlueprintEditor::CreateGraphEditorWidget(TSharedRefMapAction(FGraphEditorCommands::Get().ResetPinToDefaultValue, + FExecuteAction::CreateSP(this, &FBlueprintEditor::OnResetPinToDefaultValue), + FCanExecuteAction::CreateSP(this, &FBlueprintEditor::CanResetPinToDefaultValue) + ); + GraphEditorCommands->MapAction( FGraphEditorCommands::Get().AddOptionPin, FExecuteAction::CreateSP( this, &FBlueprintEditor::OnAddOptionPin ), FCanExecuteAction::CreateSP( this, &FBlueprintEditor::CanAddOptionPin ) @@ -1612,6 +1618,7 @@ void FBlueprintEditor::CommonInitialization(const TArray& InitBluep // When the blueprint that we are observing changes, it will notify this wrapper widget. InitBlueprint->OnChanged().AddSP(this, &FBlueprintEditor::OnBlueprintChanged); InitBlueprint->OnCompiled().AddSP(this, &FBlueprintEditor::OnBlueprintCompiled); + InitBlueprint->OnSetObjectBeingDebugged().AddSP(this, &FBlueprintEditor::HandleSetObjectBeingDebugged); } CreateDefaultCommands(); @@ -2180,6 +2187,8 @@ FBlueprintEditor::~FBlueprintEditor() if (GetBlueprintObj()) { GetBlueprintObj()->OnChanged().RemoveAll( this ); + GetBlueprintObj()->OnCompiled().RemoveAll( this ); + GetBlueprintObj()->OnSetObjectBeingDebugged().RemoveAll( this ); } FGlobalTabmanager::Get()->OnActiveTabChanged_Unsubscribe( OnActiveTabChangedDelegateHandle ); @@ -2921,7 +2930,7 @@ void FBlueprintEditor::NavigateToChildGraph_Clicked() { UEdGraph* CurrentGraph = FocusedGraphEdPtr.Pin()->GetCurrentGraph(); - if (CurrentGraph->SubGraphs.Num() > 0) + if (CurrentGraph->SubGraphs.Num() > 1) { // Display a child jump list FSlateApplication::Get().PushMenu( @@ -3556,9 +3565,13 @@ void FBlueprintEditor::JumpToHyperlink(const UObject* ObjectReference, bool bReq OpenDocument(const_cast(FunctionGraph), FDocumentTracker::OpenNewDocument); } } + else if ((ObjectReference != nullptr) && ObjectReference->IsAsset()) + { + FAssetEditorManager::Get().OpenEditorForAsset(const_cast(ObjectReference)); + } else { - UE_LOG(LogBlueprint, Warning, TEXT("Unknown type of hyperlinked object")); + UE_LOG(LogBlueprint, Warning, TEXT("Unknown type of hyperlinked object (%s)"), *GetNameSafe(ObjectReference)); } //@TODO: Hacky way to ensure a message is seen when hitting an exception and doing intraframe debugging @@ -3983,25 +3996,24 @@ void FBlueprintEditor::OnRemoveExecutionPin() bool FBlueprintEditor::CanRemoveExecutionPin() const { - bool bReturnValue = true; - - const FGraphPanelSelectionSet& SelectedNodes = GetSelectedNodes(); - - // Iterate over all nodes, and make sure all execution sequence nodes will always have at least 2 outs - for (FGraphPanelSelectionSet::TConstIterator It(SelectedNodes); It; ++It) + TSharedPtr FocusedGraphEd = FocusedGraphEdPtr.Pin(); + if (FocusedGraphEd.IsValid()) { - UK2Node_ExecutionSequence* SeqNode = Cast(*It); - if (SeqNode != NULL) + const FScopedTransaction Transaction(LOCTEXT("RemoveExecutionPin", "Remove Execution Pin")); + + UEdGraphPin* SelectedPin = FocusedGraphEd->GetGraphPinForMenu(); + UEdGraphNode* OwningNode = SelectedPin->GetOwningNode(); + + if (UK2Node_ExecutionSequence* SeqNode = Cast(OwningNode)) { - bReturnValue = SeqNode->CanRemoveExecutionPin(); - if (!bReturnValue) - { - break; - } + return SeqNode->CanRemoveExecutionPin(); + } + else if (UK2Node_Switch* SwitchNode = Cast(OwningNode)) + { + return SwitchNode->CanRemoveExecutionPin(SelectedPin); } } - - return bReturnValue; + return false; } void FBlueprintEditor::OnRemoveThisStructVarPin() @@ -4094,6 +4106,39 @@ bool FBlueprintEditor::CanRestoreAllStructVarPins() const return Node && !Node->AllPinsAreShown(); } +void FBlueprintEditor::OnResetPinToDefaultValue() +{ + TSharedPtr FocusedGraphEd = FocusedGraphEdPtr.Pin(); + if (FocusedGraphEd.IsValid()) + { + UEdGraphPin* TargetPin = FocusedGraphEd->GetGraphPinForMenu(); + + check(TargetPin); + + const FScopedTransaction Transaction(LOCTEXT("ResetPinToDefaultValue", "Reset Pin To Default Value")); + + const UEdGraphSchema_K2* K2Schema = GetDefault(); + K2Schema->ResetPinToAutogeneratedDefaultValue(TargetPin); + } +} + +bool FBlueprintEditor::CanResetPinToDefaultValue() const +{ + const UEdGraphSchema_K2* K2Schema = GetDefault(); + + bool bCanRecombine = false; + TSharedPtr FocusedGraphEd = FocusedGraphEdPtr.Pin(); + if (FocusedGraphEd.IsValid()) + { + if (UEdGraphPin* Pin = FocusedGraphEd->GetGraphPinForMenu()) + { + return !Pin->DoesDefaultValueMatchAutogenerated(); + } + } + + return false; +} + void FBlueprintEditor::OnAddOptionPin() { const FGraphPanelSelectionSet& SelectedNodes = GetSelectedNodes(); @@ -5006,58 +5051,43 @@ bool FBlueprintEditor::CanPromoteSelectionToMacro() const void FBlueprintEditor::OnExpandNodes() { - const FScopedTransaction Transaction( FGraphEditorCommands::Get().ExpandNodes->GetDescription() ); + const FScopedTransaction Transaction( FGraphEditorCommands::Get().ExpandNodes->GetLabel() ); GetBlueprintObj()->Modify(); - // Expand all composite nodes back in place TSet ExpandedNodes; - TSharedPtr FocusedGraphEd = FocusedGraphEdPtr.Pin(); + // Expand selected nodes into the focused graph context. const FGraphPanelSelectionSet SelectedNodes = GetSelectedNodes(); for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt) { + ExpandedNodes.Empty(); + bool bExpandedNodesNeedUniqueGuid = true; + + DocumentManager->CleanInvalidTabs(); + if (UK2Node_MacroInstance* SelectedMacroInstanceNode = Cast(*NodeIt)) { UEdGraph* MacroGraph = SelectedMacroInstanceNode->GetMacroGraph(); if(MacroGraph) { - DocumentManager->CleanInvalidTabs(); - // Clone the graph so that we do not delete the original UEdGraph* ClonedGraph = FEdGraphUtilities::CloneGraph(MacroGraph, NULL); ExpandNode(SelectedMacroInstanceNode, ClonedGraph, /*inout*/ ExpandedNodes); - //Remove this node from selection - FocusedGraphEd->SetNodeSelection(SelectedMacroInstanceNode, false); - ClonedGraph->MarkPendingKill(); - - //Add expanded nodes to selection - for (UEdGraphNode* ExpandedNode : ExpandedNodes) - { - FocusedGraphEd->SetNodeSelection(ExpandedNode, true); - } } } else if (UK2Node_Composite* SelectedCompositeNode = Cast(*NodeIt)) { - DocumentManager->CleanInvalidTabs(); + // No need to assign unique GUIDs since the source graph will be removed. + bExpandedNodesNeedUniqueGuid = false; // Expand the composite node back into the world UEdGraph* SourceGraph = SelectedCompositeNode->BoundGraph; - ExpandNode(SelectedCompositeNode, SourceGraph, /*inout*/ ExpandedNodes); + FBlueprintEditorUtils::RemoveGraph(GetBlueprintObj(), SourceGraph, EGraphRemoveFlags::Recompile); - - //Remove this node from selection - FocusedGraphEd->SetNodeSelection(SelectedCompositeNode, false); - - //Add expanded nodes to selection - for (UEdGraphNode* ExpandedNode : ExpandedNodes) - { - FocusedGraphEd->SetNodeSelection(ExpandedNode, true); - } } else if (UK2Node_CallFunction* SelectedCallFunctionNode = Cast(*NodeIt)) { @@ -5069,22 +5099,47 @@ void FBlueprintEditor::OnExpandNodes() if(FunctionGraph) { - DocumentManager->CleanInvalidTabs(); - // Clone the graph so that we do not delete the original UEdGraph* ClonedGraph = FEdGraphUtilities::CloneGraph(FunctionGraph, NULL); ExpandNode(SelectedCallFunctionNode, ClonedGraph, ExpandedNodes); - //Remove this node from selection - FocusedGraphEd->SetNodeSelection(SelectedCallFunctionNode, false); - ClonedGraph->MarkPendingKill(); + } + } - //Add expanded nodes to selection - for (UEdGraphNode* ExpandedNode : ExpandedNodes) + if (ExpandedNodes.Num() > 0) + { + FVector2D AvgNodePosition(0.0f, 0.0f); + + for (TSet::TIterator It(ExpandedNodes); It; ++It) + { + UEdGraphNode* Node = *It; + AvgNodePosition.X += Node->NodePosX; + AvgNodePosition.Y += Node->NodePosY; + } + + float InvNumNodes = 1.0f / float(ExpandedNodes.Num()); + AvgNodePosition.X *= InvNumNodes; + AvgNodePosition.Y *= InvNumNodes; + + //Remove source node from selection + UEdGraphNode* SourceNode = CastChecked(*NodeIt); + FocusedGraphEd->SetNodeSelection(SourceNode, false); + + for (UEdGraphNode* ExpandedNode : ExpandedNodes) + { + ExpandedNode->NodePosX = (ExpandedNode->NodePosX - AvgNodePosition.X) + SourceNode->NodePosX; + ExpandedNode->NodePosY = (ExpandedNode->NodePosY - AvgNodePosition.Y) + SourceNode->NodePosY; + + ExpandedNode->SnapToGrid(SNodePanel::GetSnapGridSize()); + + if (bExpandedNodesNeedUniqueGuid) { - FocusedGraphEd->SetNodeSelection(ExpandedNode, true); + ExpandedNode->CreateNewGuid(); } + + //Add expanded node to selection + FocusedGraphEd->SetNodeSelection(ExpandedNode, true); } } } @@ -6197,11 +6252,11 @@ void FBlueprintEditor::OnDisallowedPinConnection(const UEdGraphPin* PinA, const { FDisallowedPinConnection NewRecord; NewRecord.PinTypeCategoryA = PinA->PinType.PinCategory; - NewRecord.bPinIsArrayA = PinA->PinType.bIsArray; + NewRecord.bPinIsArrayA = PinA->PinType.IsArray(); NewRecord.bPinIsReferenceA = PinA->PinType.bIsReference; NewRecord.bPinIsWeakPointerA = PinA->PinType.bIsWeakPointer; NewRecord.PinTypeCategoryB = PinB->PinType.PinCategory; - NewRecord.bPinIsArrayB = PinB->PinType.bIsArray; + NewRecord.bPinIsArrayB = PinB->PinType.IsArray(); NewRecord.bPinIsReferenceB = PinB->PinType.bIsReference; NewRecord.bPinIsWeakPointerB = PinB->PinType.bIsWeakPointer; AnalyticsStats.GraphDisallowedPinConnections.Add(NewRecord); diff --git a/Engine/Source/Editor/Kismet/Private/DiffUtils.cpp b/Engine/Source/Editor/Kismet/Private/DiffUtils.cpp index 890af5bf7bfe..3445b206b52f 100644 --- a/Engine/Source/Editor/Kismet/Private/DiffUtils.cpp +++ b/Engine/Source/Editor/Kismet/Private/DiffUtils.cpp @@ -336,13 +336,33 @@ void DiffUtils::CompareUnrelatedSCS(const UBlueprint* Old, const TArray< FSCSRes if (NewEntry != nullptr) { - // did a property change? - TArray DifferingProperties; - DiffUtils::CompareUnrelatedObjects(OldNode.Object, NewEntry->Object, DifferingProperties); - for (const auto& Property : DifferingProperties) + bool bShouldDiffProperties = true; + + // did it change class? + const bool bObjectTypesDiffer = OldNode.Object != nullptr && NewEntry->Object != nullptr && OldNode.Object->GetClass() != NewEntry->Object->GetClass(); + if (bObjectTypesDiffer) { - FSCSDiffEntry Diff = { OldNode.Identifier, ETreeDiffType::NODE_PROPERTY_CHANGED, Property }; + FSCSDiffEntry Diff = { OldNode.Identifier, ETreeDiffType::NODE_TYPE_CHANGED, FSingleObjectDiffEntry() }; OutDifferingEntries.Entries.Push(Diff); + + // Only diff properties if we're still within the same class inheritance hierarchy. + bShouldDiffProperties = OldNode.Object->GetClass()->IsChildOf(NewEntry->Object->GetClass()) || NewEntry->Object->GetClass()->IsChildOf(OldNode.Object->GetClass()); + } + + // did a property change? + if(bShouldDiffProperties) + { + TArray DifferingProperties; + DiffUtils::CompareUnrelatedObjects(OldNode.Object, NewEntry->Object, DifferingProperties); + for (const auto& Property : DifferingProperties) + { + // Only include property value change entries if the object types differ. + if (!bObjectTypesDiffer || Property.DiffType == EPropertyDiffType::PropertyValueChanged) + { + FSCSDiffEntry Diff = { OldNode.Identifier, ETreeDiffType::NODE_PROPERTY_CHANGED, Property }; + OutDifferingEntries.Entries.Push(Diff); + } + } } // did it move? @@ -481,8 +501,8 @@ static void IdenticalHelper(const UProperty* AProperty, const UProperty* BProper } // note any differences in contained elements: - int32 SetSizeA = SetHelperA.Num(); - int32 SetSizeB = SetHelperA.Num(); + const int32 SetSizeA = SetHelperA.Num(); + const int32 SetSizeB = SetHelperB.Num(); int32 SetIndexA = 0; int32 SetIndexB = 0; @@ -983,8 +1003,11 @@ FText DiffViewUtils::SCSDiffMessage(const FSCSDiffEntry& Difference, FText Objec case ETreeDiffType::NODE_REMOVED: Text = FText::Format(NSLOCTEXT("DiffViewUtils", "NodeRemoved", "Removed Node {0} from {1}"), NodeName, ObjectName); break; + case ETreeDiffType::NODE_TYPE_CHANGED: + Text = FText::Format(NSLOCTEXT("DiffViewUtils", "NodeTypeChanged", "Node {0} changed type in {1}"), NodeName, ObjectName); + break; case ETreeDiffType::NODE_PROPERTY_CHANGED: - Text = FText::Format(NSLOCTEXT("DiffViewUtils", "NodeChanged", "{0} on {1}"), DiffViewUtils::PropertyDiffMessage(Difference.PropertyDiff, NodeName), ObjectName); + Text = FText::Format(NSLOCTEXT("DiffViewUtils", "NodePropertyChanged", "{0} on {1}"), DiffViewUtils::PropertyDiffMessage(Difference.PropertyDiff, NodeName), ObjectName); break; case ETreeDiffType::NODE_MOVED: Text = FText::Format(NSLOCTEXT("DiffViewUtils", "NodeMoved", "Moved Node {0} in {1}"), NodeName, ObjectName); diff --git a/Engine/Source/Editor/Kismet/Private/FindInBlueprintManager.cpp b/Engine/Source/Editor/Kismet/Private/FindInBlueprintManager.cpp index 3d66f5b92345..32c51b77589d 100644 --- a/Engine/Source/Editor/Kismet/Private/FindInBlueprintManager.cpp +++ b/Engine/Source/Editor/Kismet/Private/FindInBlueprintManager.cpp @@ -635,7 +635,7 @@ namespace BlueprintSearchMetaDataHelpers { InWriter->WriteValue(FFindInBlueprintSearchTags::FiB_ObjectClass, FText::FromString(InPinType.PinSubCategoryObject->GetName())); } - InWriter->WriteValue(FFindInBlueprintSearchTags::FiB_IsArray, InPinType.bIsArray); + InWriter->WriteValue(FFindInBlueprintSearchTags::FiB_IsArray, InPinType.IsArray()); InWriter->WriteValue(FFindInBlueprintSearchTags::FiB_IsReference, InPinType.bIsReference); } diff --git a/Engine/Source/Editor/Kismet/Private/FindInBlueprints.cpp b/Engine/Source/Editor/Kismet/Private/FindInBlueprints.cpp index 2887cd7638fd..90f2708e9731 100644 --- a/Engine/Source/Editor/Kismet/Private/FindInBlueprints.cpp +++ b/Engine/Source/Editor/Kismet/Private/FindInBlueprints.cpp @@ -92,7 +92,7 @@ bool FindInBlueprintsHelpers::ParsePinType(FText InKey, FText InValue, FEdGraphP } else if(InKey.CompareTo(FFindInBlueprintSearchTags::FiB_IsArray) == 0) { - InOutPinType.bIsArray = InValue.ToString().ToBool(); + InOutPinType.ContainerType = (InValue.ToString().ToBool() ? EPinContainerType::Array : EPinContainerType::None); } else if(InKey.CompareTo(FFindInBlueprintSearchTags::FiB_IsReference) == 0) { @@ -332,9 +332,9 @@ FFindInBlueprintsPin::FFindInBlueprintsPin(const FText& InValue, TSharedPtr FFindInBlueprintsPin::CreateIcon() const { - const FSlateBrush* Brush = NULL; + const FSlateBrush* Brush = nullptr; - if( PinType.bIsArray ) + if( PinType.IsArray() ) { Brush = FEditorStyle::GetBrush( TEXT("GraphEditor.ArrayPinIcon") ); } diff --git a/Engine/Source/Editor/Kismet/Private/SBlueprintActionMenu.cpp b/Engine/Source/Editor/Kismet/Private/SBlueprintActionMenu.cpp index bed10acdc653..14bf33887f2e 100644 --- a/Engine/Source/Editor/Kismet/Private/SBlueprintActionMenu.cpp +++ b/Engine/Source/Editor/Kismet/Private/SBlueprintActionMenu.cpp @@ -228,7 +228,7 @@ void SBlueprintActionMenu::Construct( const FArguments& InArgs, TSharedPtrGetPinTypeColor(OnePin->PinType); - ContextIcon = FEditorStyle::GetBrush( OnePin->PinType.bIsArray ? TEXT("Graph.ArrayPin.Connected") : TEXT("Graph.Pin.Connected") ); + ContextIcon = FEditorStyle::GetBrush( OnePin->PinType.IsArray() ? TEXT("Graph.ArrayPin.Connected") : TEXT("Graph.Pin.Connected") ); } } diff --git a/Engine/Source/Editor/Kismet/Private/SBlueprintEditorSelectedDebugObjectWidget.cpp b/Engine/Source/Editor/Kismet/Private/SBlueprintEditorSelectedDebugObjectWidget.cpp index 835cdcab3d77..4dcafb8d62bc 100644 --- a/Engine/Source/Editor/Kismet/Private/SBlueprintEditorSelectedDebugObjectWidget.cpp +++ b/Engine/Source/Editor/Kismet/Private/SBlueprintEditorSelectedDebugObjectWidget.cpp @@ -596,13 +596,16 @@ void SBlueprintEditorSelectedDebugObjectWidget::DebugWorldSelectionChanged(TShar void SBlueprintEditorSelectedDebugObjectWidget::DebugObjectSelectionChanged(TSharedPtr NewSelection, ESelectInfo::Type SelectInfo) { - check(DebugObjects.Num() == DebugObjectNames.Num()); - for (int32 ObjectIndex = 0; ObjectIndex < DebugObjectNames.Num(); ++ObjectIndex) + if (SelectInfo != ESelectInfo::Direct) { - if (*DebugObjectNames[ObjectIndex] == *NewSelection) + check(DebugObjects.Num() == DebugObjectNames.Num()); + for (int32 ObjectIndex = 0; ObjectIndex < DebugObjectNames.Num(); ++ObjectIndex) { - UObject* DebugObj = DebugObjects[ObjectIndex].IsValid() ? DebugObjects[ObjectIndex].Get() : nullptr; - GetBlueprintObj()->SetObjectBeingDebugged(DebugObj); + if (*DebugObjectNames[ObjectIndex] == *NewSelection) + { + UObject* DebugObj = DebugObjects[ObjectIndex].IsValid() ? DebugObjects[ObjectIndex].Get() : nullptr; + GetBlueprintObj()->SetObjectBeingDebugged(DebugObj); + } } } } diff --git a/Engine/Source/Editor/Kismet/Private/SBlueprintEditorToolbar.cpp b/Engine/Source/Editor/Kismet/Private/SBlueprintEditorToolbar.cpp index ef24e8db00b4..59a4dcae4e2b 100644 --- a/Engine/Source/Editor/Kismet/Private/SBlueprintEditorToolbar.cpp +++ b/Engine/Source/Editor/Kismet/Private/SBlueprintEditorToolbar.cpp @@ -254,11 +254,8 @@ static void OnDiffRevisionPicked(FRevisionInfo const& RevisionInfo, TWeakObjectP FString PreviousTempPkgName; if (Revision->Get(PreviousTempPkgName)) { - // Forcibly disable compile on load in case we are loading old blueprints that might try to update/compile - TGuardValue DisableCompileOnLoad(GForceDisableBlueprintCompileOnLoad, true); - // Try and load that package - UPackage* PreviousTempPkg = LoadPackage(NULL, *PreviousTempPkgName, LOAD_None); + UPackage* PreviousTempPkg = LoadPackage(NULL, *PreviousTempPkgName, LOAD_DisableCompileOnLoad); if (PreviousTempPkg != NULL) { diff --git a/Engine/Source/Editor/Kismet/Private/SBlueprintPalette.cpp b/Engine/Source/Editor/Kismet/Private/SBlueprintPalette.cpp index 772e14d5be2c..f36ed33af165 100644 --- a/Engine/Source/Editor/Kismet/Private/SBlueprintPalette.cpp +++ b/Engine/Source/Editor/Kismet/Private/SBlueprintPalette.cpp @@ -101,14 +101,7 @@ static FString GetVarType(UStruct* VarScope, FName VarName, bool bUseObjToolTip, FEdGraphPinType PinType; if (K2Schema->ConvertPropertyToPinType(Property, PinType)) // use schema to get the color { - if (bDetailed && PinType.PinSubCategoryObject.IsValid()) - { - VarDesc = FString::Printf(TEXT("%s '%s'"), *PinType.PinCategory, *PinType.PinSubCategoryObject->GetName()); - } - else - { - VarDesc = UEdGraphSchema_K2::TypeToText(PinType).ToString(); - } + VarDesc = UEdGraphSchema_K2::TypeToText(PinType).ToString(); } } } @@ -272,7 +265,7 @@ static void GetSubGraphIcon(FEdGraphSchemaAction_K2Graph const* const ActionIn, if ( OverrideFunc == NULL ) { IconOut = FEditorStyle::GetBrush(TEXT("GraphEditor.Function_16x")); - if ( ActionIn->EdGraph != NULL && ActionIn->EdGraph->IsA(UAnimationGraph::StaticClass()) ) + if ( ActionIn->EdGraph->IsA(UAnimationGraph::StaticClass()) ) { ToolTipOut = LOCTEXT("AnimationGraph_Tooltip", "Animation Graph"); } @@ -737,15 +730,15 @@ private: { if (FBlueprintEditorUtils::IsPinTypeValid(InNewPinType)) { - FName VarName = VariableProperty->GetFName(); - - if (VarName != NAME_None) + if (VariableProperty) { - // Set the MyBP tab's last pin type used as this, for adding lots of variables of the same type - BlueprintEditorPtr.Pin()->GetMyBlueprintWidget()->GetLastPinTypeUsed() = InNewPinType; + FName VarName = VariableProperty->GetFName(); - if (VariableProperty) + if (VarName != NAME_None) { + // Set the MyBP tab's last pin type used as this, for adding lots of variables of the same type + BlueprintEditorPtr.Pin()->GetMyBlueprintWidget()->GetLastPinTypeUsed() = InNewPinType; + if (UFunction* LocalVariableScope = Cast(VariableProperty->GetOuter())) { FBlueprintEditorUtils::ChangeLocalVariableType(BlueprintObj, LocalVariableScope, VarName, InNewPinType); @@ -1004,8 +997,22 @@ void SBlueprintPaletteItem::Construct(const FArguments& InArgs, FCreateWidgetFor ActionPtr = InCreateData->Action; BlueprintEditorPtr = InBlueprintEditor; - const bool bIsFullyReadOnly = !InBlueprintEditor.IsValid(); + const bool bIsFullyReadOnly = !InBlueprintEditor.IsValid() || InCreateData->bIsReadOnly; + TWeakPtr WeakGraphAction = GraphAction; + auto IsReadOnlyLambda = [WeakGraphAction, InBlueprintEditor, bIsFullyReadOnly]() + { + if(WeakGraphAction.IsValid() && InBlueprintEditor.IsValid()) + { + return bIsFullyReadOnly || FBlueprintEditorUtils::IsPaletteActionReadOnly(WeakGraphAction.Pin(), InBlueprintEditor.Pin()); + } + + return true; + }; + + TAttribute bIsReadOnly = TAttribute::Create(TAttribute::FGetter::CreateLambda(IsReadOnlyLambda)); + TAttribute bIsEnabled = TAttribute::Create(TAttribute::FGetter::CreateLambda([IsReadOnlyLambda]() { return !IsReadOnlyLambda(); })); + // construct the icon widget FSlateBrush const* IconBrush = FEditorStyle::GetBrush(TEXT("NoBrush")); FSlateBrush const* SecondaryBrush = FEditorStyle::GetBrush(TEXT("NoBrush")); @@ -1015,7 +1022,7 @@ void SBlueprintPaletteItem::Construct(const FArguments& InArgs, FCreateWidgetFor FString IconDocLink, IconDocExcerpt; GetPaletteItemIcon(GraphAction, Blueprint, IconBrush, IconColor, IconToolTip, IconDocLink, IconDocExcerpt, SecondaryBrush, SecondaryIconColor); TSharedRef IconWidget = CreateIconWidget(IconToolTip, IconBrush, IconColor, IconDocLink, IconDocExcerpt, SecondaryBrush, SecondaryIconColor); - IconWidget->SetEnabled(!bIsFullyReadOnly); + IconWidget->SetEnabled(bIsEnabled); // Setup a meta tag for this node FTutorialMetaData TagMeta("PaletteItem"); @@ -1026,7 +1033,6 @@ void SBlueprintPaletteItem::Construct(const FArguments& InArgs, FCreateWidgetFor } // construct the text widget FSlateFontInfo NameFont = FSlateFontInfo(FPaths::EngineContentDir() / TEXT("Slate/Fonts/Roboto-Regular.ttf"), 10); - const bool bIsReadOnly = bIsFullyReadOnly || FBlueprintEditorUtils::IsPaletteActionReadOnly(GraphAction, InBlueprintEditor.Pin()); TSharedRef NameSlotWidget = CreateTextSlotWidget( NameFont, InCreateData, bIsReadOnly ); // For Variables and Local Variables, we will convert the icon widget into a pin type selector. @@ -1050,7 +1056,7 @@ void SBlueprintPaletteItem::Construct(const FArguments& InArgs, FCreateWidgetFor { const UEdGraphSchema_K2* Schema = GetDefault(); IconWidget = SNew(SPinTypeSelectorHelper, VariableProp, Blueprint, BlueprintEditorPtr) - .IsEnabled(!bIsFullyReadOnly); + .IsEnabled(bIsEnabled); } } } @@ -1081,7 +1087,7 @@ void SBlueprintPaletteItem::Construct(const FArguments& InArgs, FCreateWidgetFor .VAlign(VAlign_Center) [ SNew(SPaletteItemVisibilityToggle, ActionPtr, InBlueprintEditor, InBlueprint) - .IsEnabled(!bIsFullyReadOnly) + .IsEnabled(bIsEnabled) ] ]; } @@ -1101,7 +1107,7 @@ void SBlueprintPaletteItem::OnDragEnter(const FGeometry& MyGeometry, const FDrag *******************************************************************************/ //------------------------------------------------------------------------------ -TSharedRef SBlueprintPaletteItem::CreateTextSlotWidget(const FSlateFontInfo& NameFont, FCreateWidgetForActionData* const InCreateData, bool const bIsReadOnlyIn) +TSharedRef SBlueprintPaletteItem::CreateTextSlotWidget(const FSlateFontInfo& NameFont, FCreateWidgetForActionData* const InCreateData, TAttribute bIsReadOnlyIn) { FName const ActionTypeId = InCreateData->Action->GetTypeId(); @@ -1143,8 +1149,6 @@ TSharedRef SBlueprintPaletteItem::CreateTextSlotWidget(const FSlateFont } TSharedPtr ToolTipWidget = ConstructToolTipWidget(); - // If the creation data says read only, then it must be read only - bool bIsReadOnly = (bIsReadOnlyIn || InCreateData->bIsReadOnly); TSharedPtr DisplayWidget; TSharedPtr EditableTextElement; @@ -1159,14 +1163,11 @@ TSharedRef SBlueprintPaletteItem::CreateTextSlotWidget(const FSlateFont .OnVerifyTextChanged(OnVerifyTextChanged) .OnTextCommitted(OnTextCommitted) .IsSelected(InCreateData->IsRowSelectedDelegate) - .IsReadOnly(bIsReadOnly) + .IsReadOnly(bIsReadOnlyIn) ]; InlineRenameWidget = EditableTextElement.ToSharedRef(); - if(!bIsReadOnly) - { - InCreateData->OnRenameRequest->BindSP(InlineRenameWidget.Get(), &SInlineEditableTextBlock::EnterEditingMode); - } + InCreateData->OnRenameRequest->BindSP(InlineRenameWidget.Get(), &SInlineEditableTextBlock::EnterEditingMode); if (GetDefault()->bShowActionMenuItemSignatures && ActionPtr.IsValid()) { @@ -1332,6 +1333,11 @@ void SBlueprintPaletteItem::OnNameTextCommitted(const FText& NewText, ETextCommi // Search through all function entry nodes for local variables to update their scope name TArray VariableNodes; Graph->GetNodesOfClass(VariableNodes); + for (const UEdGraph* SubGraph : Graph->SubGraphs) + { + check(SubGraph != nullptr); + SubGraph->GetNodesOfClass(VariableNodes); + } for (UK2Node_Variable* const VariableNode : VariableNodes) { @@ -1353,16 +1359,13 @@ void SBlueprintPaletteItem::OnNameTextCommitted(const FText& NewText, ETextCommi UEdGraph* Graph = DelegateAction->EdGraph; if ((Graph != NULL) && (Graph->bAllowDeletion || Graph->bAllowRenaming)) { - if (Graph) - { - FGraphDisplayInfo DisplayInfo; - Graph->GetSchema()->GetGraphDisplayInformation(*Graph, DisplayInfo); + FGraphDisplayInfo DisplayInfo; + Graph->GetSchema()->GetGraphDisplayInformation(*Graph, DisplayInfo); - // Check if the name is unchanged - if( NewText.EqualTo( DisplayInfo.PlainName ) ) - { - return; - } + // Check if the name is unchanged + if( NewText.EqualTo( DisplayInfo.PlainName ) ) + { + return; } // Make sure we aren't renaming the graph into something that already exists diff --git a/Engine/Source/Editor/Kismet/Private/SBlueprintPalette.h b/Engine/Source/Editor/Kismet/Private/SBlueprintPalette.h index c5fa01c426f3..db6951045974 100644 --- a/Engine/Source/Editor/Kismet/Private/SBlueprintPalette.h +++ b/Engine/Source/Editor/Kismet/Private/SBlueprintPalette.h @@ -48,7 +48,7 @@ private: // End of SWidget Interface // SGraphPaletteItem Interface - virtual TSharedRef CreateTextSlotWidget( const FSlateFontInfo& NameFont, FCreateWidgetForActionData* const InCreateData, bool bIsReadOnly ) override; + virtual TSharedRef CreateTextSlotWidget( const FSlateFontInfo& NameFont, FCreateWidgetForActionData* const InCreateData, TAttribute bIsReadOnly ) override; virtual FText GetDisplayText() const override; virtual bool OnNameTextVerifyChanged(const FText& InNewText, FText& OutErrorMessage) override; virtual void OnNameTextCommitted(const FText& NewText, ETextCommit::Type InTextCommit) override; diff --git a/Engine/Source/Editor/Kismet/Private/SSCSEditor.cpp b/Engine/Source/Editor/Kismet/Private/SSCSEditor.cpp index 023112e24601..14e6aa101674 100644 --- a/Engine/Source/Editor/Kismet/Private/SSCSEditor.cpp +++ b/Engine/Source/Editor/Kismet/Private/SSCSEditor.cpp @@ -26,13 +26,15 @@ #include "UnrealEdGlobals.h" #include "Kismet2/KismetEditorUtilities.h" #include "EdGraphSchema_K2.h" +#include "GraphEditorActions.h" +#include "ToolkitManager.h" #include "K2Node_Variable.h" #include "K2Node_ComponentBoundEvent.h" #include "K2Node_VariableGet.h" #include "Kismet2/BlueprintEditorUtils.h" #include "ComponentAssetBroker.h" #include "ClassViewerFilter.h" - +#include "SSearchBox.h" #include "PropertyPath.h" #include "AssetSelection.h" @@ -118,7 +120,7 @@ FReply SSCSEditorDragDropTree::OnDragOver( const FGeometry& MyGeometry, const FD { const auto& AssetDragDropOp = StaticCastSharedPtr(Operation); - for (const FAssetData& AssetData : AssetDragDropOp->AssetData) + for (const FAssetData& AssetData : AssetDragDropOp->GetAssets()) { if (UClass* AssetClass = AssetData.GetClass()) { @@ -190,23 +192,26 @@ FReply SSCSEditor::TryHandleAssetDragDropOperation(const FDragDropEvent& DragDro } } + // Only set focus to the last item created + const bool bSetFocusToNewItem = (DroppedAssetIdx == NumAssets - 1); + TSubclassOf MatchingComponentClassForAsset = FComponentAssetBrokerage::GetPrimaryComponentForAsset(AssetClass); if (MatchingComponentClassForAsset != nullptr) { - AddNewComponent(MatchingComponentClassForAsset, Asset, true ); + AddNewComponent(MatchingComponentClassForAsset, Asset, true, bSetFocusToNewItem ); bMarkBlueprintAsModified = true; } else if ((PotentialComponentClass != nullptr) && !PotentialComponentClass->HasAnyClassFlags(CLASS_Deprecated | CLASS_Abstract | CLASS_NewerVersionExists)) { if (PotentialComponentClass->HasMetaData(FBlueprintMetadata::MD_BlueprintSpawnableComponent)) { - AddNewComponent(PotentialComponentClass, nullptr, true ); + AddNewComponent(PotentialComponentClass, nullptr, true, bSetFocusToNewItem ); bMarkBlueprintAsModified = true; } } else if ((PotentialActorClass != nullptr) && !PotentialActorClass->HasAnyClassFlags(CLASS_Deprecated | CLASS_Abstract | CLASS_NewerVersionExists)) { - AddNewComponent(UChildActorComponent::StaticClass(), PotentialActorClass, true ); + AddNewComponent(UChildActorComponent::StaticClass(), PotentialActorClass, true, bSetFocusToNewItem ); bMarkBlueprintAsModified = true; } } @@ -376,6 +381,7 @@ FSCSEditorTreeNode::FSCSEditorTreeNode(FSCSEditorTreeNode::ENodeType InNodeType) : ComponentTemplatePtr(nullptr) , NodeType(InNodeType) , bNonTransactionalRename(false) + , FilterFlags((uint8)EFilteredState::Unknown) { } @@ -476,6 +482,105 @@ bool FSCSEditorTreeNode::IsAttachedTo(FSCSEditorTreeNodePtrType InNodePtr) const return false; } +void FSCSEditorTreeNode::UpdateCachedFilterState(bool bMatchesFilter, bool bUpdateParent) +{ + bool bFlagsChanged = false; + if ((FilterFlags & EFilteredState::Unknown) == EFilteredState::Unknown) + { + FilterFlags = 0x00; + bFlagsChanged = true; + } + + if (bMatchesFilter) + { + bFlagsChanged |= (FilterFlags & EFilteredState::MatchesFilter) == 0; + FilterFlags |= EFilteredState::MatchesFilter; + } + else + { + bFlagsChanged |= (FilterFlags & EFilteredState::MatchesFilter) != 0; + FilterFlags &= ~EFilteredState::MatchesFilter; + } + + const bool bHadChildMatch = (FilterFlags & EFilteredState::ChildMatches) != 0; + // refresh the cached child state (don't update the parent, we'll do that below if it's needed) + RefreshCachedChildFilterState(/*bUpdateParent =*/false); + + bFlagsChanged |= bHadChildMatch != ((FilterFlags & EFilteredState::ChildMatches) != 0); + if (bUpdateParent && bFlagsChanged) + { + ApplyFilteredStateToParent(); + } +} + +void FSCSEditorTreeNode::RefreshCachedChildFilterState(bool bUpdateParent) +{ + const bool bCointainedMatch = !IsFlaggedForFiltration(); + + FilterFlags &= ~EFilteredState::ChildMatches; + for (FSCSEditorTreeNodePtrType Child : Children) + { + if (!Child->IsFlaggedForFiltration()) + { + FilterFlags |= EFilteredState::ChildMatches; + break; + } + } + const bool bCointainsMatch = !IsFlaggedForFiltration(); + + const bool bStateChange = bCointainedMatch != bCointainsMatch; + if (bUpdateParent && bStateChange) + { + ApplyFilteredStateToParent(); + } +} + +void FSCSEditorTreeNode::ApplyFilteredStateToParent() +{ + FSCSEditorTreeNode* Child = this; + while (Child->ParentNodePtr.IsValid()) + { + FSCSEditorTreeNode* Parent = Child->ParentNodePtr.Get(); + + if ( !IsFlaggedForFiltration() ) + { + if ((Parent->FilterFlags & EFilteredState::ChildMatches) == 0) + { + Parent->FilterFlags |= EFilteredState::ChildMatches; + } + else + { + // all parents from here on up should have the flag + break; + } + } + // have to see if this was the only child contributing to this flag + else if (Parent->FilterFlags & EFilteredState::ChildMatches) + { + Parent->FilterFlags &= ~EFilteredState::ChildMatches; + for (const FSCSEditorTreeNodePtrType& Sibling : Parent->Children) + { + if (Sibling.Get() == Child) + { + continue; + } + + if (Sibling->FilterFlags & EFilteredState::FilteredInMask) + { + Parent->FilterFlags |= EFilteredState::ChildMatches; + break; + } + } + + if (Parent->FilterFlags & EFilteredState::ChildMatches) + { + // another child added the flag back + break; + } + } + Child = Parent; + } +} FSCSEditorTreeNodePtrType FSCSEditorTreeNode::FindClosestParent(TArray InNodes) { @@ -516,6 +621,16 @@ void FSCSEditorTreeNode::AddChild(FSCSEditorTreeNodePtrType InChildNodePtr) Children.AddUnique(InChildNodePtr); InChildNodePtr->ParentNodePtr = AsShared(); + if (InChildNodePtr->FilterFlags != EFilteredState::Unknown && !InChildNodePtr->IsFlaggedForFiltration()) + { + FSCSEditorTreeNodePtrType AncestorPtr = InChildNodePtr->ParentNodePtr; + while (AncestorPtr.IsValid() && (AncestorPtr->FilterFlags & EFilteredState::ChildMatches) == 0) + { + AncestorPtr->FilterFlags |= EFilteredState::ChildMatches; + AncestorPtr = AncestorPtr->GetParent(); + } + } + // Add a child node to the SCS tree node if not already present USCS_Node* SCS_ChildNode = InChildNodePtr->GetSCSNode(); if(SCS_ChildNode != NULL) @@ -769,6 +884,11 @@ void FSCSEditorTreeNode::RemoveChild(FSCSEditorTreeNodePtrType InChildNodePtr) Children.Remove(InChildNodePtr); InChildNodePtr->ParentNodePtr.Reset(); InChildNodePtr->RemoveMeAsChild(); + + if (InChildNodePtr->IsFlaggedForFiltration()) + { + RefreshCachedChildFilterState(/*bUpdateParent =*/true); + } } void FSCSEditorTreeNode::OnRequestRename(bool bTransactional) @@ -1299,8 +1419,8 @@ void SSCS_RowWidget::Construct( const FArguments& InArgs, TSharedPtr auto Args = FSuperRowType::FArguments() .Style(bIsSeparator ? - &FEditorStyle::Get().GetWidgetStyle("TableView.NoHoverTableRow") : - &FEditorStyle::Get().GetWidgetStyle("SceneOutliner.TableViewRow")) //@todo create editor style for the SCS tree + &FEditorStyle::Get().GetWidgetStyle("TableView.NoHoverTableRow") : + &FEditorStyle::Get().GetWidgetStyle("SceneOutliner.TableViewRow")) //@todo create editor style for the SCS tree .Padding(FMargin(0.f, 0.f, 0.f, 4.f)) .ShowSelection(!bIsSeparator) .OnDragDetected(this, &SSCS_RowWidget::HandleOnDragDetected) @@ -2355,7 +2475,7 @@ void SSCS_RowWidget::OnAttachToDropAction(const TArrayAddNewComponent(ComponentTemplate->GetClass(), NULL); + UActorComponent* ClonedComponent = SCSEditorPtr->AddNewComponent(ComponentTemplate->GetClass(), nullptr); check(ClonedComponent); //Serialize object properties using write/read operations. @@ -2650,7 +2770,7 @@ void SSCS_RowWidget::OnMakeNewRootDropAction(FSCSEditorTreeNodePtrType DroppedNo { // Get the current Blueprint context UBlueprint* Blueprint = GetBlueprint(); - check(Blueprint != NULL && Blueprint->SimpleConstructionScript != nullptr); + check(Blueprint && Blueprint->SimpleConstructionScript); // Clone the component if it's being dropped into a different SCS if(DroppedNodePtr->GetBlueprint() != Blueprint) @@ -2659,7 +2779,7 @@ void SSCS_RowWidget::OnMakeNewRootDropAction(FSCSEditorTreeNodePtrType DroppedNo check(ComponentTemplate); // Note: This will mark the Blueprint as structurally modified - UActorComponent* ClonedComponent = SCSEditorPtr->AddNewComponent(ComponentTemplate->GetClass(), NULL); + UActorComponent* ClonedComponent = SCSEditorPtr->AddNewComponent(ComponentTemplate->GetClass(), nullptr); check(ClonedComponent); //Serialize object properties using write/read operations. @@ -2951,7 +3071,7 @@ bool SSCS_RowWidget::OnNameTextVerifyChanged(const FText& InNewText, FText& OutE { FFormatNamedArguments Arguments; Arguments.Add(TEXT("CharCount"), NAME_SIZE); - OutErrorMessage = FText::Format(LOCTEXT("RenameFailed_TooLong", "Component name must be less than {CharCount} characters long."), Arguments); + OutErrorMessage = FText::Format(LOCTEXT("ComponentRenameFailed_TooLong", "Component name must be less than {CharCount} characters long."), Arguments); return false; } else if (!FComponentEditorUtils::IsComponentNameAvailable(InNewText.ToString(), ExistingNameSearchScope, NodePtr->GetComponentTemplate())) @@ -3328,6 +3448,10 @@ void SSCSEditor::Construct( const FArguments& InArgs ) FCanExecuteAction::CreateSP( this, &SSCSEditor::CanRenameComponent ) ) ); + CommandList->MapAction( FGraphEditorCommands::Get().FindReferences, + FUIAction( FExecuteAction::CreateSP( this, &SSCSEditor::OnFindReferences ) ) + ); + FSlateBrush const* MobilityHeaderBrush = FEditorStyle::GetBrush(TEXT("ClassIcon.ComponentMobilityHeaderIcon")); TSharedPtr HeaderRow = SNew(SHeaderRow) @@ -3338,7 +3462,7 @@ void SSCSEditor::Construct( const FArguments& InArgs ) SCSTreeWidget = SNew(SSCSTreeType) .ToolTipText(LOCTEXT("DropAssetToAddComponent", "Drop asset here to add a component.")) .SCSEditor(this) - .TreeItemsSource(&RootNodes) + .TreeItemsSource(&FilteredRootNodes) .SelectionMode(ESelectionMode::Multi) .OnGenerateRow(this, &SSCSEditor::MakeTableRowWidget) .OnGetChildren(this, &SSCSEditor::OnGetChildrenForTree) @@ -3408,6 +3532,12 @@ void SSCSEditor::Construct( const FArguments& InArgs ) FUIAction(FExecuteAction::CreateSP(this, &SSCSEditor::PromoteToBlueprint)) ); + TSharedPtr ButtonBox; + TSharedPtr HeaderBox; + TSharedPtr SearchBar = SAssignNew(FilterBox, SSearchBox) + .OnTextChanged(this, &SSCSEditor::OnFilterTextChanged); + const bool bInlineSearchBarWithButtons = (EditorMode == EComponentEditorMode::BlueprintSCS); + bool bHideComponentClassCombo = InArgs._HideComponentClassCombo.Get(); Contents = SNew(SVerticalBox) @@ -3426,103 +3556,115 @@ void SSCSEditor::Construct( const FArguments& InArgs ) .AddMetaData(FTagMetaData(TEXT("ComponentsPanel"))) .BorderBackgroundColor( FLinearColor( .6,.6,.6, 1.0f ) ) [ - SNew(SHorizontalBox) + SAssignNew(HeaderBox, SVerticalBox) + + SVerticalBox::Slot() + .AutoHeight() + .VAlign(VAlign_Top) + [ + SAssignNew(ButtonBox, SHorizontalBox) - + SHorizontalBox::Slot() - .Padding( 3.0f, 3.0f ) - .AutoWidth() - .HAlign(HAlign_Left) - [ - SNew(SComponentClassCombo) - .AddMetaData(FTagMetaData(TEXT("Actor.AddComponent"))) - .Visibility(bHideComponentClassCombo ? EVisibility::Hidden : EVisibility::Visible) - .OnComponentClassSelected(this, &SSCSEditor::PerformComboAddClass) - .ToolTipText(LOCTEXT("AddComponent_Tooltip", "Adds a new component to this actor")) - .IsEnabled(AllowEditing) - ] + + SHorizontalBox::Slot() + .Padding( 3.0f, 3.0f ) + .AutoWidth() + .HAlign(HAlign_Left) + [ + SNew(SComponentClassCombo) + .AddMetaData(FTagMetaData(TEXT("Actor.AddComponent"))) + .Visibility(bHideComponentClassCombo ? EVisibility::Hidden : EVisibility::Visible) + .OnComponentClassSelected(this, &SSCSEditor::PerformComboAddClass) + .ToolTipText(LOCTEXT("AddComponent_Tooltip", "Adds a new component to this actor")) + .IsEnabled(AllowEditing) + ] - + SHorizontalBox::Slot() - .FillWidth(1.0f) - .HAlign(HAlign_Right) - .Padding( 3.0f, 3.0f ) - [ - SNew( SButton ) - .AddMetaData(FTagMetaData(TEXT("Actor.ConvertToBlueprint"))) - .Visibility( this, &SSCSEditor::GetPromoteToBlueprintButtonVisibility ) - .OnClicked( this, &SSCSEditor::OnPromoteToBlueprintClicked ) - .ButtonStyle(FEditorStyle::Get(), "FlatButton.Primary") - .ContentPadding(FMargin(10,0)) - .ToolTip(IDocumentation::Get()->CreateToolTip( - LOCTEXT("PromoteToBluerprintTooltip","Converts this actor into a reusable Blueprint Class that can have script behavior" ), - NULL, - TEXT("Shared/LevelEditor"), - TEXT("ConvertToBlueprint"))) - [ - SNew(SHorizontalBox) + // + // horizontal slot (index) #1 => reserved for BP-editor search bar (see 'ButtonBox' usage below) + + + SHorizontalBox::Slot() + .FillWidth(1.0f) + .HAlign(HAlign_Right) + .Padding( 3.0f, 3.0f ) + [ + SNew( SButton ) + .AddMetaData(FTagMetaData(TEXT("Actor.ConvertToBlueprint"))) + .Visibility( this, &SSCSEditor::GetPromoteToBlueprintButtonVisibility ) + .OnClicked( this, &SSCSEditor::OnPromoteToBlueprintClicked ) + .ButtonStyle(FEditorStyle::Get(), "FlatButton.Primary") + .ContentPadding(FMargin(10,0)) + .ToolTip(IDocumentation::Get()->CreateToolTip( + LOCTEXT("PromoteToBluerprintTooltip","Converts this actor into a reusable Blueprint Class that can have script behavior" ), + NULL, + TEXT("Shared/LevelEditor"), + TEXT("ConvertToBlueprint"))) + [ + SNew(SHorizontalBox) - + SHorizontalBox::Slot() - .VAlign(VAlign_Center) - .Padding(3.f) - .AutoWidth() - [ - SNew(STextBlock) - .TextStyle(FEditorStyle::Get(), "ContentBrowser.TopBar.Font") - .Font( FEditorStyle::Get().GetFontStyle( "FontAwesome.10" ) ) - .Text(FText::FromString(FString(TEXT("\xf085"))) /*fa-cogs*/) - ] + + SHorizontalBox::Slot() + .VAlign(VAlign_Center) + .Padding(3.f) + .AutoWidth() + [ + SNew(STextBlock) + .TextStyle(FEditorStyle::Get(), "ContentBrowser.TopBar.Font") + .Font( FEditorStyle::Get().GetFontStyle( "FontAwesome.10" ) ) + .Text(FText::FromString(FString(TEXT("\xf085"))) /*fa-cogs*/) + ] - + SHorizontalBox::Slot() - .VAlign(VAlign_Center) - .Padding(3.f) - .AutoWidth() - [ - SNew(STextBlock) - .TextStyle(FEditorStyle::Get(), "ContentBrowser.TopBar.Font") - //.Text( LOCTEXT("PromoteToBlueprint", "Add Script") ) - .Text(LOCTEXT("PromoteToBlueprint", "Blueprint/Add Script")) + + SHorizontalBox::Slot() + .VAlign(VAlign_Center) + .Padding(3.f) + .AutoWidth() + [ + SNew(STextBlock) + .TextStyle(FEditorStyle::Get(), "ContentBrowser.TopBar.Font") + //.Text( LOCTEXT("PromoteToBlueprint", "Add Script") ) + .Text(LOCTEXT("PromoteToBlueprint", "Blueprint/Add Script")) + ] + ] ] - ] - ] - + SHorizontalBox::Slot() - .FillWidth(1.0f) - .Padding( 3.0f, 3.0f ) - .HAlign(HAlign_Right) - .Padding(3.0f, 3.0f) - [ - SNew(SComboButton) - .AddMetaData(FTagMetaData(TEXT("Actor.EditBlueprint"))) - .Visibility(this, &SSCSEditor::GetEditBlueprintButtonVisibility) - .ContentPadding(FMargin(10, 0)) - .ComboButtonStyle(FEditorStyle::Get(), "ToolbarComboButton") - .ButtonStyle(FEditorStyle::Get(), "FlatButton.Primary") - .ForegroundColor(FLinearColor::White) - .ButtonContent() - [ - SNew( SHorizontalBox ) + + SHorizontalBox::Slot() + .FillWidth(1.0f) + .Padding( 3.0f, 3.0f ) + .HAlign(HAlign_Right) + .Padding(3.0f, 3.0f) + [ + SNew(SComboButton) + .AddMetaData(FTagMetaData(TEXT("Actor.EditBlueprint"))) + .Visibility(this, &SSCSEditor::GetEditBlueprintButtonVisibility) + .ContentPadding(FMargin(10, 0)) + .ComboButtonStyle(FEditorStyle::Get(), "ToolbarComboButton") + .ButtonStyle(FEditorStyle::Get(), "FlatButton.Primary") + .ForegroundColor(FLinearColor::White) + .ButtonContent() + [ + SNew( SHorizontalBox ) - + SHorizontalBox::Slot() - .AutoWidth() - .VAlign(VAlign_Center) - .Padding(3.f) - [ - SNew(STextBlock) - .TextStyle(FEditorStyle::Get(), "ContentBrowser.TopBar.Font") - .Font(FEditorStyle::Get().GetFontStyle("FontAwesome.10")) - .Text(FText::FromString(FString(TEXT("\xf085"))) /*fa-cogs*/) - ] + + SHorizontalBox::Slot() + .AutoWidth() + .VAlign(VAlign_Center) + .Padding(3.f) + [ + SNew(STextBlock) + .TextStyle(FEditorStyle::Get(), "ContentBrowser.TopBar.Font") + .Font(FEditorStyle::Get().GetFontStyle("FontAwesome.10")) + .Text(FText::FromString(FString(TEXT("\xf085"))) /*fa-cogs*/) + ] - + SHorizontalBox::Slot() - [ - SNew(STextBlock) - .TextStyle(FEditorStyle::Get(), "ContentBrowser.TopBar.Font") - .Text(LOCTEXT("EditBlueprint", "Edit Blueprint")) + + SHorizontalBox::Slot() + [ + SNew(STextBlock) + .TextStyle(FEditorStyle::Get(), "ContentBrowser.TopBar.Font") + .Text(LOCTEXT("EditBlueprint", "Edit Blueprint")) + ] + ] + .MenuContent() + [ + EditBlueprintMenuBuilder.MakeWidget() + ] ] ] - .MenuContent() - [ - EditBlueprintMenuBuilder.MakeWidget() - ] - ] + + // + // vertical slot (index) #1 => reserved for instance-editor search bar (see 'HeaderBox' usage below) ] ] @@ -3539,6 +3681,32 @@ void SSCSEditor::Construct( const FArguments& InArgs ) ] ]; + // insert the search bar, depending on which editor this widget is in (depending on convert/edit button visibility) + if (bInlineSearchBarWithButtons) + { + const int32 SearchBarHorizontalSlotIndex = 1; + + ButtonBox->InsertSlot(SearchBarHorizontalSlotIndex) + .FillWidth(1.0f) + .VAlign(VAlign_Center) + .Padding(3.0f, 3.0f) + [ + SearchBar.ToSharedRef() + ]; + } + else + { + const int32 SearchBarVerticalSlotIndex = 1; + + HeaderBox->InsertSlot(SearchBarVerticalSlotIndex) + .VAlign(VAlign_Center) + .Padding(3.0f, 1.0f) + [ + SearchBar.ToSharedRef() + ]; + } + + this->ChildSlot [ Contents.ToSharedRef() @@ -3703,6 +3871,11 @@ TSharedPtr< SWidget > SSCSEditor::CreateContextMenu() if (EditorMode == EComponentEditorMode::BlueprintSCS) { + if (SelectedItems.Num() == 1) + { + MenuBuilder.AddMenuEntry(FGraphEditorCommands::Get().FindReferences); + } + // Collect the classes of all selected objects TArray SelectionClasses; for( auto NodeIter = SelectedNodes.CreateConstIterator(); NodeIter; ++NodeIter ) @@ -3865,6 +4038,23 @@ void SSCSEditor::ViewEvent(UBlueprint* Blueprint, const FName EventName, const F } } +void SSCSEditor::OnFindReferences() +{ + TArray SelectedNodes = SCSTreeWidget->GetSelectedItems(); + if (SelectedNodes.Num() == 1) + { + TSharedPtr FoundAssetEditor = FToolkitManager::Get().FindEditorForAsset(GetBlueprint()); + if (FoundAssetEditor.IsValid()) + { + const FString VariableName = SelectedNodes[0]->GetVariableName().ToString(); + const FString SearchTerm = FString::Printf(TEXT("Nodes(VariableReference(MemberName=+\"%s\"))"), *VariableName); + + TSharedRef BlueprintEditor = StaticCastSharedRef(FoundAssetEditor.ToSharedRef()); + BlueprintEditor->SummonSearchUI(true, SearchTerm); + } + } +} + bool SSCSEditor::CanDuplicateComponent() const { if(!IsEditingAllowed()) @@ -3884,8 +4074,7 @@ void SSCSEditor::OnDuplicateComponent() for (int32 i = 0; i < SelectedNodes.Num(); ++i) { - UActorComponent* ComponentTemplate = SelectedNodes[i]->GetComponentTemplate(); - if(ComponentTemplate != NULL) + if (UActorComponent* ComponentTemplate = SelectedNodes[i]->GetComponentTemplate()) { UActorComponent* CloneComponent = AddNewComponent(ComponentTemplate->GetClass(), ComponentTemplate); UActorComponent* OriginalComponent = ComponentTemplate; @@ -3905,16 +4094,25 @@ void SSCSEditor::OnDuplicateComponent() FSCSEditorTreeNodePtrType OriginalNodePtr = FindTreeNode(OriginalComponent); if(OriginalNodePtr.IsValid()) { - // If the original node was parented, attempt to add the duplicate as a child of the same parent node - FSCSEditorTreeNodePtrType ParentNodePtr = OriginalNodePtr->GetParent(); - if(ParentNodePtr.IsValid() && ParentNodePtr != SceneRootNodePtr) + // If we're duplicating the root then we're already a child of it so need to reparent, but we do need to reset the scale + // otherwise we'll end up with the square of the root's scale instead of being the same size. + if (OriginalNodePtr == SceneRootNodePtr) { - // Locate the duplicate node (as a child of the current scene root node), and switch it to be a child of the original node's parent - FSCSEditorTreeNodePtrType NewChildNodePtr = SceneRootNodePtr->FindChild(NewSceneComponent); - if(NewChildNodePtr.IsValid()) + NewSceneComponent->RelativeScale3D = FVector(1.f); + } + else + { + // If the original node was parented, attempt to add the duplicate as a child of the same parent node + FSCSEditorTreeNodePtrType ParentNodePtr = OriginalNodePtr->GetParent(); + if (ParentNodePtr.IsValid()) { - // Note: This method will handle removal from the scene root node as well - ParentNodePtr->AddChild(NewChildNodePtr); + // Locate the duplicate node (as a child of the current scene root node), and switch it to be a child of the original node's parent + FSCSEditorTreeNodePtrType NewChildNodePtr = SceneRootNodePtr->FindChild(NewSceneComponent, true); + if (NewChildNodePtr.IsValid()) + { + // Note: This method will handle removal from the scene root node as well + ParentNodePtr->AddChild(NewChildNodePtr); + } } } } @@ -3926,11 +4124,29 @@ void SSCSEditor::OnDuplicateComponent() void SSCSEditor::OnGetChildrenForTree( FSCSEditorTreeNodePtrType InNodePtr, TArray& OutChildren ) { - OutChildren.Empty(); - - if(InNodePtr.IsValid()) + if (InNodePtr.IsValid()) { - OutChildren = InNodePtr->GetChildren(); + const TArray& Children = InNodePtr->GetChildren(); + OutChildren.Reserve(Children.Num()); + + if (!GetFilterText().IsEmpty()) + { + for (FSCSEditorTreeNodePtrType Child : Children) + { + if (!Child->IsFlaggedForFiltration()) + { + OutChildren.Add(Child); + } + } + } + else + { + OutChildren = Children; + } + } + else + { + OutChildren.Empty(); } } @@ -4263,7 +4479,7 @@ void SSCSEditor::UpdateTree(bool bRegenerateTreeNodes) } for (UActorComponent* Component : Components) - { + { if (USceneComponent* SceneComp = Cast(Component)) { // Add the rest of the native base class SceneComponent hierarchy @@ -4434,6 +4650,8 @@ void SSCSEditor::UpdateTree(bool bRegenerateTreeNodes) SCSTreeWidget->RequestScrollIntoView(NodeToRenamePtr); } } + + RebuildFilteredRootList(); } // refresh widget @@ -4614,11 +4832,18 @@ TSharedPtr SSCSEditor::AddRootComponentTreeNode(UActorCompon if (RootTreeNode.IsValid()) { NewTreeNode = RootTreeNode->AddChildFromComponent(ActorComp); + RefreshFilteredState(NewTreeNode, /*bRecursive =*/false); } else { NewTreeNode = FSCSEditorTreeNode::FactoryNodeFromComponent(ActorComp); RootNodes.Add(NewTreeNode); + + bool bIsFilteredOut = RefreshFilteredState(NewTreeNode, /*bRecursive =*/false); + if (!bIsFilteredOut) + { + FilteredRootNodes.Add(NewTreeNode); + } } RootComponentNodes.Add(NewTreeNode); @@ -4724,6 +4949,36 @@ UClass* SSCSEditor::CreateNewBPComponent(TSubclassOf ComponentC return NewClass; } +void SSCSEditor::RebuildFilteredRootList() +{ + FilteredRootNodes.Empty(RootNodes.Num()); + + FSCSEditorTreeNodePtrType PendingSeparator; + for (const FSCSEditorTreeNodePtrType& Node : RootNodes) + { + switch (Node->GetNodeType()) + { + case FSCSEditorTreeNode::ENodeType::ComponentNode: + if (Node->IsFlaggedForFiltration()) + { + break; + } + case FSCSEditorTreeNode::ENodeType::RootActorNode: + if (PendingSeparator.IsValid()) + { + FilteredRootNodes.Add(PendingSeparator); + PendingSeparator.Reset(); + } + FilteredRootNodes.Add(Node); + break; + + case FSCSEditorTreeNode::ENodeType::SeparatorNode: + PendingSeparator = Node; + break; + } + } +} + void SSCSEditor::ClearSelection() { if ( bUpdatingSelection == false ) @@ -4765,7 +5020,7 @@ bool SSCSEditor::IsEditingAllowed() const return AllowEditing.Get() && nullptr == GEditor->PlayWorld; } -UActorComponent* SSCSEditor::AddNewComponent( UClass* NewComponentClass, UObject* Asset, const bool bSkipMarkBlueprintModified ) +UActorComponent* SSCSEditor::AddNewComponent( UClass* NewComponentClass, UObject* Asset, const bool bSkipMarkBlueprintModified, const bool bSetFocusToNewItem ) { if (NewComponentClass->ClassWithin && NewComponentClass->ClassWithin != UObject::StaticClass()) { @@ -4805,7 +5060,7 @@ UActorComponent* SSCSEditor::AddNewComponent( UClass* NewComponentClass, UObject } const FName NewVariableName = (Asset ? FName(*FComponentEditorUtils::GenerateValidVariableNameFromAsset(Asset, nullptr)) : NAME_None); - NewComponent = AddNewNode(Blueprint->SimpleConstructionScript->CreateNode(NewComponentClass, NewVariableName), Asset, bMarkBlueprintModified); + NewComponent = AddNewNode(Blueprint->SimpleConstructionScript->CreateNode(NewComponentClass, NewVariableName), Asset, bMarkBlueprintModified, bSetFocusToNewItem); if (ComponentTemplate) { @@ -4828,7 +5083,7 @@ UActorComponent* SSCSEditor::AddNewComponent( UClass* NewComponentClass, UObject if (ComponentTemplate) { // Create a duplicate of the provided template - NewComponent = AddNewNodeForInstancedComponent(FComponentEditorUtils::DuplicateComponent(ComponentTemplate), nullptr); + NewComponent = AddNewNodeForInstancedComponent(FComponentEditorUtils::DuplicateComponent(ComponentTemplate), nullptr, bSetFocusToNewItem); } else if (AActor* ActorInstance = GetActorContext()) { @@ -4890,7 +5145,7 @@ UActorComponent* SSCSEditor::AddNewComponent( UClass* NewComponentClass, UObject // Rerun construction scripts ActorInstance->RerunConstructionScripts(); - NewComponent = AddNewNodeForInstancedComponent(NewInstanceComponent, Asset); + NewComponent = AddNewNodeForInstancedComponent(NewInstanceComponent, Asset, bSetFocusToNewItem); } } @@ -5139,7 +5394,12 @@ void SSCSEditor::PasteNodes() Blueprint->Modify(); SaveSCSCurrentState(Blueprint->SimpleConstructionScript); + // stop allowing tree updates + bool bRestoreAllowTreeUpdates = bAllowTreeUpdates; + bAllowTreeUpdates = false; + // Create a new tree node for each new (pasted) component + FSCSEditorTreeNodePtrType FirstNode; TMap NewNodeMap; for (const TPair& NewObjectPair : NewObjectMap) { @@ -5161,6 +5421,11 @@ void SSCSEditor::PasteNodes() // Update the selection to include the new node SCSTreeWidget->SetItemSelection(NewNodePtr, true); + + if (!FirstNode.IsValid()) + { + FirstNode = NewNodePtr; + } } } } @@ -5184,6 +5449,15 @@ void SSCSEditor::PasteNodes() } } + // allow tree updates again + bAllowTreeUpdates = bRestoreAllowTreeUpdates; + + // scroll the first node into view + if (FirstNode.IsValid()) + { + SCSTreeWidget->RequestScrollIntoView(FirstNode); + } + // Modify the Blueprint generated class structure (this will also call UpdateTree() as a result) FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(Blueprint); } @@ -5467,6 +5741,7 @@ FSCSEditorTreeNodePtrType SSCSEditor::AddTreeNode(USCS_Node* InSCSNode, FSCSEdit { // do this first, because we need a FSCSEditorTreeNodePtrType for the new node NewNodePtr = ParentPtr->AddChild(InSCSNode, bIsInheritedSCS); + RefreshFilteredState(NewNodePtr, /*bRecursive =*/false); bool bParentIsEditorOnly = ParentPtr->GetComponentTemplate()->IsEditorOnly(); // if you can't nest this new node under the proposed parent (then swap the two) @@ -5509,6 +5784,12 @@ FSCSEditorTreeNodePtrType SSCSEditor::AddTreeNode(USCS_Node* InSCSNode, FSCSEdit { NewNodePtr = MakeShareable(new FSCSEditorTreeNodeComponent(InSCSNode, bIsInheritedSCS)); RootNodes.Add(NewNodePtr); + + bool bIsFilteredOut = RefreshFilteredState(NewNodePtr, /*bRecursive =*/false); + if (!bIsFilteredOut) + { + FilteredRootNodes.Add(NewNodePtr); + } } NodeSCS->AddNode(InSCSNode); @@ -5534,6 +5815,12 @@ FSCSEditorTreeNodePtrType SSCSEditor::AddTreeNode(USCS_Node* InSCSNode, FSCSEdit { NewNodePtr = MakeShareable(new FSCSEditorTreeNodeComponent(InSCSNode, bIsInheritedSCS)); RootNodes.Add(NewNodePtr); + + bool bIsFilteredOut = RefreshFilteredState(NewNodePtr, /*bRecursive =*/false); + if (!bIsFilteredOut) + { + FilteredRootNodes.Add(NewNodePtr); + } } RootComponentNodes.Add(NewNodePtr); @@ -5583,6 +5870,7 @@ FSCSEditorTreeNodePtrType SSCSEditor::AddTreeNodeFromComponent(USceneComponent* // Add a new tree node for the given scene component check(ParentNodePtr.IsValid()); NewNodePtr = ParentNodePtr->AddChildFromComponent(InSceneComponent); + RefreshFilteredState(NewNodePtr, /*bRecursive =*/false); // Expand parent nodes by default SCSTreeWidget->SetItemExpansion(ParentNodePtr, true); @@ -5604,6 +5892,7 @@ FSCSEditorTreeNodePtrType SSCSEditor::AddTreeNodeFromComponent(USceneComponent* else if (SceneRootNodePtr->GetComponentTemplate() != InSceneComponent) { NewNodePtr = SceneRootNodePtr->AddChildFromComponent(InSceneComponent); + RefreshFilteredState(NewNodePtr, /*bRecursive =*/false); } } @@ -6160,5 +6449,114 @@ void SSCSEditor::SetItemExpansionRecursive(FSCSEditorTreeNodePtrType Model, bool } } +FText SSCSEditor::GetFilterText() const +{ + return FilterBox->GetText(); +} + +void SSCSEditor::OnFilterTextChanged(const FText& InFilterText) +{ + struct OnFilterTextChanged_Inner + { + static FSCSEditorTreeNodePtrType ExpandToFilteredChildren(SSCSEditor* SCSEditor, FSCSEditorTreeNodePtrType TreeNode) + { + FSCSEditorTreeNodePtrType NodeToFocus; + + const TArray& Children = TreeNode->GetChildren(); + // iterate backwards so we select from the top down + for (int32 ChildIndex = Children.Num() - 1; ChildIndex >= 0; --ChildIndex) + { + const FSCSEditorTreeNodePtrType& Child = Children[ChildIndex]; + if (!Child->IsFlaggedForFiltration()) + { + SCSEditor->SetNodeExpansionState(TreeNode, /*bIsExpanded =*/true); + NodeToFocus = ExpandToFilteredChildren(SCSEditor, Child); + } + } + + if (!NodeToFocus.IsValid() && !TreeNode->IsFlaggedForFiltration()) + { + NodeToFocus = TreeNode; + } + return NodeToFocus; + } + }; + + FSCSEditorTreeNodePtrType NewSelection; + const bool bIsFilterBlank = GetFilterText().IsEmpty(); + + bool bRootItemFilteredBackIn = false; + // iterate backwards so we select from the top down + for (int32 ComponentIndex = RootComponentNodes.Num() - 1; ComponentIndex >= 0; --ComponentIndex) + { + FSCSEditorTreeNodePtrType Component = RootComponentNodes[ComponentIndex]; + + const bool bWasFilteredOut = Component->IsFlaggedForFiltration(); + bool bFilteredOut = RefreshFilteredState(Component, /*bRecursive =*/true); + + if (!bFilteredOut) + { + if (!bIsFilterBlank) + { + NewSelection = OnFilterTextChanged_Inner::ExpandToFilteredChildren(this, Component); + } + bRootItemFilteredBackIn |= bWasFilteredOut; + } + else + { + FilteredRootNodes.Remove(Component); + } + } + + if (NewSelection.IsValid() && !SCSTreeWidget->IsItemSelected(NewSelection)) + { + SelectNode(NewSelection, /*IsCntrlDown =*/false); + } + + if (bRootItemFilteredBackIn) + { + RebuildFilteredRootList(); + } + UpdateTree(/*bRegenerateTreeNodes =*/false); +} + +bool SSCSEditor::RefreshFilteredState(FSCSEditorTreeNodePtrType TreeNode, bool bRecursive) +{ + FString FilterText = FText::TrimPrecedingAndTrailing( GetFilterText() ).ToString(); + TArray FilterTerms; + FilterText.ParseIntoArray(FilterTerms, TEXT(" "), /*CullEmpty =*/true); + + struct RefreshFilteredState_Inner + { + static void RefreshFilteredState(FSCSEditorTreeNodePtrType TreeNodeIn, const TArray& FilterTermsIn, bool bRecursiveIn) + { + if (bRecursiveIn) + { + for (FSCSEditorTreeNodePtrType Child : TreeNodeIn->GetChildren()) + { + RefreshFilteredState(Child, FilterTermsIn, bRecursiveIn); + } + } + + FString DisplayStr = TreeNodeIn->GetDisplayString(); + + bool bIsFilteredOut = false; + for (const FString& FilterTerm : FilterTermsIn) + { + if (!DisplayStr.Contains(FilterTerm)) + { + bIsFilteredOut = true; + } + } + // if we're not recursing, then assume this is for a new node and we need to update the parent + // otherwise, assume the parent was hit as part of the recursion + TreeNodeIn->UpdateCachedFilterState(!bIsFilteredOut, /*bUpdateParent =*/!bRecursiveIn); + } + }; + + RefreshFilteredState_Inner::RefreshFilteredState(TreeNode, FilterTerms, bRecursive); + return TreeNode->IsFlaggedForFiltration(); +} + #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Editor/Kismet/Private/Tests/BlueprintEditorTests.cpp b/Engine/Source/Editor/Kismet/Private/Tests/BlueprintEditorTests.cpp index 4cea3ab90b81..a59ae6375e81 100644 --- a/Engine/Source/Editor/Kismet/Private/Tests/BlueprintEditorTests.cpp +++ b/Engine/Source/Editor/Kismet/Private/Tests/BlueprintEditorTests.cpp @@ -607,7 +607,7 @@ namespace BlueprintEditorPromotionUtils static void AddStringMemberValue(UBlueprint* InBlueprint, const FName& VariableName) { const UEdGraphSchema_K2* K2Schema = GetDefault(); - FEdGraphPinType StringPinType(K2Schema->PC_String, TEXT(""), NULL, false, false, false, false, FEdGraphTerminalType()); + FEdGraphPinType StringPinType(K2Schema->PC_String, FString(), nullptr, EPinContainerType::None, false, FEdGraphTerminalType()); FBlueprintEditorUtils::AddMemberVariable(InBlueprint, VariableName, StringPinType); } diff --git a/Engine/Source/Editor/Kismet/Private/UserDefinedStructureEditor.cpp b/Engine/Source/Editor/Kismet/Private/UserDefinedStructureEditor.cpp index b06b82be6db0..435c5ec8571a 100644 --- a/Engine/Source/Editor/Kismet/Private/UserDefinedStructureEditor.cpp +++ b/Engine/Source/Editor/Kismet/Private/UserDefinedStructureEditor.cpp @@ -435,7 +435,7 @@ class FUserDefinedStructureLayout : public IDetailCustomNodeBuilder, public TSha public: FUserDefinedStructureLayout(TWeakPtr InStructureDetails) : StructureDetails(InStructureDetails) - , InitialPinType(GetDefault()->PC_Boolean, TEXT(""), NULL, false, false, false, false, FEdGraphTerminalType()) + , InitialPinType(GetDefault()->PC_Boolean, FString(), nullptr, EPinContainerType::None, false, FEdGraphTerminalType()) {} void OnChanged() diff --git a/Engine/Source/Editor/Kismet/Public/BlueprintCompilationManager.h b/Engine/Source/Editor/Kismet/Public/BlueprintCompilationManager.h index 7fa44ff5c7fd..879dbefc3695 100644 --- a/Engine/Source/Editor/Kismet/Public/BlueprintCompilationManager.h +++ b/Engine/Source/Editor/Kismet/Public/BlueprintCompilationManager.h @@ -4,7 +4,30 @@ #include "CoreMinimal.h" // for DLLEXPORT (KISMET_API) +#include "Kismet2/KismetEditorUtilities.h" + class UBlueprint; +class FCompilerResultsLog; + +struct FBPCompileRequest +{ + explicit FBPCompileRequest(UBlueprint* InBPToCompile, EBlueprintCompileOptions InCompileOptions, FCompilerResultsLog* InClientResultsLog ) + : BPToCompile(InBPToCompile) + , CompileOptions(InCompileOptions) + , ClientResultsLog(InClientResultsLog) + { + } + + // BP that needs to be compiled: + UBlueprint* BPToCompile; + + // Legacy options for blueprint compilation: + EBlueprintCompileOptions CompileOptions; + + // Clients can give us a results log if they want to parse or display it themselves, otherwise + // we will use a transient one: + FCompilerResultsLog* ClientResultsLog; +}; struct KISMET_API FBlueprintCompilationManager { @@ -21,9 +44,11 @@ struct KISMET_API FBlueprintCompilationManager static void FlushCompilationQueue(TArray* ObjLoaded = nullptr); /** - * Adds the blueprint to the compilation queue + * Immediately compiles the blueprint, no expectation that related blueprints be subsequently compiled. + * It will be significantly more efficient to queue blueprints and then flush the compilation queue + * if there are several blueprints that require compilation (e.g. typical case on PIE): */ - static void QueueForCompilation(UBlueprint* BPToCompile); + static void CompileSynchronously(const FBPCompileRequest& Request); /** * Adds a newly loaded blueprint to the compilation queue diff --git a/Engine/Source/Editor/Kismet/Public/BlueprintEditor.h b/Engine/Source/Editor/Kismet/Public/BlueprintEditor.h index e775421a9a13..f50cc5019f66 100644 --- a/Engine/Source/Editor/Kismet/Public/BlueprintEditor.h +++ b/Engine/Source/Editor/Kismet/Public/BlueprintEditor.h @@ -573,6 +573,9 @@ public: /* Selects an item in "My Blueprint" by name. */ void SelectGraphActionItemByName(const FName& ItemName, ESelectInfo::Type SelectInfo = ESelectInfo::Direct, int32 SectionId = INDEX_NONE, bool bIsCategory = false); + /** Handle when the debug object is changed in the UI */ + virtual void HandleSetObjectBeingDebugged(UObject* InObject) {} + protected: virtual void AppendExtraCompilerResults(TSharedPtr ResultsListing); @@ -714,6 +717,9 @@ protected: void OnRestoreAllStructVarPins(); bool CanRestoreAllStructVarPins() const; + void OnResetPinToDefaultValue(); + bool CanResetPinToDefaultValue() const; + void OnAddOptionPin(); bool CanAddOptionPin() const; diff --git a/Engine/Source/Editor/Kismet/Public/DiffUtils.h b/Engine/Source/Editor/Kismet/Public/DiffUtils.h index 0866cad315eb..bce3059ae11d 100644 --- a/Engine/Source/Editor/Kismet/Public/DiffUtils.h +++ b/Engine/Source/Editor/Kismet/Public/DiffUtils.h @@ -178,6 +178,7 @@ namespace ETreeDiffType { NODE_ADDED, NODE_REMOVED, + NODE_TYPE_CHANGED, NODE_PROPERTY_CHANGED, NODE_MOVED, /** We could potentially try to identify hierarchy reorders separately from add/remove */ @@ -267,7 +268,7 @@ namespace DiffViewUtils KISMET_API FText PropertyDiffMessage(FSingleObjectDiffEntry Difference, FText ObjectName); KISMET_API FText SCSDiffMessage(const FSCSDiffEntry& Difference, FText ObjectName); - KISMET_API FText GetPanelLabel(const UBlueprint* Blueprint, FRevisionInfo const& Revision, FText Label); + KISMET_API FText GetPanelLabel(const UBlueprint* Blueprint, const FRevisionInfo& Revision, FText Label); KISMET_API SHorizontalBox::FSlot& Box(bool bIsPresent, FLinearColor Color); } diff --git a/Engine/Source/Editor/Kismet/Public/Profiler/EventExecution.h b/Engine/Source/Editor/Kismet/Public/Profiler/EventExecution.h index ccd98d71bec5..30b9b93ac04e 100644 --- a/Engine/Source/Editor/Kismet/Public/Profiler/EventExecution.h +++ b/Engine/Source/Editor/Kismet/Public/Profiler/EventExecution.h @@ -147,6 +147,10 @@ public: { } + virtual ~FScriptNodePerfData() + { + } + /** Returns a TSet containing all valid instance names */ void GetValidInstanceNames(TSet& ValidInstances) const; diff --git a/Engine/Source/Editor/Kismet/Public/SSCSEditor.h b/Engine/Source/Editor/Kismet/Public/SSCSEditor.h index adb95ee19d13..92a0ea99f6f3 100644 --- a/Engine/Source/Editor/Kismet/Public/SSCSEditor.h +++ b/Engine/Source/Editor/Kismet/Public/SSCSEditor.h @@ -121,7 +121,7 @@ public: /** * @return Whether or not this node is a child (direct or indirect) of the given node. */ - bool IsAttachedTo(FSCSEditorTreeNodePtrType InNodePtr) const; + bool IsAttachedTo(FSCSEditorTreeNodePtrType InNodePtr) const; /** * Finds the closest ancestor node in the given node set. @@ -288,8 +288,22 @@ public: /** Sets up the delegate for renaming a component */ void SetRenameRequestedDelegate(FOnRenameRequested InRenameRequested) { RenameRequestedDelegate = InRenameRequested; } + /** Query that determines if this item should be filtered out or not */ + bool IsFlaggedForFiltration() const + { + return ensureMsgf(FilterFlags != EFilteredState::Unknown, TEXT("Querying a bad filtration state.")) ? + (FilterFlags & EFilteredState::FilteredInMask) == 0 : false; + } + + /** Refreshes this item's filtration state. Use bUpdateParent to make sure the parent's EFilteredState::ChildMatches flag is properly updated based off the new state */ + void UpdateCachedFilterState(bool bMatchesFilter, bool bUpdateParent); protected: + /** Updates the EFilteredState::ChildMatches flag, based off of children's current state */ + void RefreshCachedChildFilterState(bool bUpdateParent); + /** Used to update the EFilteredState::ChildMatches flag for parent nodes, when this item's filtration state has changed */ + void ApplyFilteredStateToParent(); + bool GetAndClearNonTransactionalRenameFlag() { const bool bResult = bNonTransactionalRename; @@ -311,6 +325,17 @@ private: /** Handles rename requests */ bool bNonTransactionalRename; FOnRenameRequested RenameRequestedDelegate; + + enum EFilteredState + { + FilteredOut = 0x00, + MatchesFilter = (1 << 0), + ChildMatches = (1 << 1), + + FilteredInMask = (MatchesFilter | ChildMatches), + Unknown = 0xFC // ~FilteredInMask + }; + uint8 FilterFlags; }; ////////////////////////////////////////////////////////////////////////// @@ -784,7 +809,7 @@ public: @param Asset (In) Optional asset to assign to the component @param bSkipMarkBlueprintModified (In) Optionally skip marking this blueprint as modified (e.g. if we're handling that externally) @return The reference of the newly created ActorComponent */ - UActorComponent* AddNewComponent(UClass* NewComponentClass, UObject* Asset, const bool bSkipMarkBlueprintModified = false ); + UActorComponent* AddNewComponent(UClass* NewComponentClass, UObject* Asset, const bool bSkipMarkBlueprintModified = false, bool bSetFocusToNewItem = true); /** Adds a new SCS Node to the component Table @param NewNode (In) The SCS node to add @@ -827,6 +852,9 @@ public: void OnDeleteNodes(); bool CanDeleteNodes() const; + /** Callbacks to find references of the selected component */ + void OnFindReferences(); + /** Removes an existing component node from the tree */ void RemoveComponentNode(FSCSEditorTreeNodePtrType InNodePtr); @@ -944,6 +972,9 @@ public: /** Handler for recursively expanding/collapsing items */ void SetItemExpansionRecursive(FSCSEditorTreeNodePtrType Model, bool bInExpansionState); + /** Callback for the action trees to get the filter text */ + FText GetFilterText() const; + protected: FString GetSelectedClassText() const; @@ -1059,7 +1090,6 @@ protected: * @return The new class that was created */ UClass* CreateNewCPPComponent(TSubclassOf ComponentClass); - /** * Creates a new Blueprint component from the specified class type @@ -1069,6 +1099,22 @@ protected: */ UClass* CreateNewBPComponent(TSubclassOf ComponentClass); + /** Recursively updates the filtered state for each component item */ + void OnFilterTextChanged(const FText& InFilterText); + + /** + * Compares the filter bar's text with the item's component name. Use + * bRecursive to refresh the state of child nodes as well. Returns true if + * the node is set to be filtered out + */ + bool RefreshFilteredState(FSCSEditorTreeNodePtrType TreeNode, bool bRecursive); + + /** + * Iterates the RootNodes list, and uses the cached filtered state to + * determine what items should be listed in the tree view. + */ + void RebuildFilteredRootList(); + public: /** Tree widget */ TSharedPtr SCSTreeWidget; @@ -1115,6 +1161,9 @@ private: /** Root set of components (contains the root scene component and any non-scene component nodes) */ TArray RootComponentNodes; + /** The list of nodes used for the UI (a filtered version of RootNodes) */ + TArray FilteredRootNodes; + /* Root Tree Node (for scene components) */ TSharedPtr RootTreeNode; @@ -1135,4 +1184,7 @@ private: /** TRUE if this SCSEditor is currently the target of a diff */ bool bIsDiffing; + + /** The filter box that handles filtering for the tree. */ + TSharedPtr< SSearchBox > FilterBox; }; diff --git a/Engine/Source/Editor/KismetCompiler/Private/AnimBlueprintCompiler.cpp b/Engine/Source/Editor/KismetCompiler/Private/AnimBlueprintCompiler.cpp index 23cb85ef67c1..87e7ca0af177 100644 --- a/Engine/Source/Editor/KismetCompiler/Private/AnimBlueprintCompiler.cpp +++ b/Engine/Source/Editor/KismetCompiler/Private/AnimBlueprintCompiler.cpp @@ -48,6 +48,8 @@ #include "AnimGraphNode_Slot.h" #include "AnimationEditorUtils.h" +#include "AnimBlueprintPostCompileValidation.h" + #define LOCTEXT_NAMESPACE "AnimBlueprintCompiler" // @@ -82,7 +84,7 @@ bool FAnimBlueprintCompiler::FEffectiveConstantRecord::Apply(UObject* Object) if (ArrayHelper.IsValidIndex(ArrayIndex)) { - FBlueprintEditorUtils::ImportKismetDefaultValueToProperty(LiteralSourcePin, ArrayProperty->Inner, ArrayHelper.GetRawPtr(ArrayIndex), Object); + FBlueprintEditorUtils::PropertyValueFromString_Direct(ArrayProperty->Inner, LiteralSourcePin->GetDefaultAsString(), ArrayHelper.GetRawPtr(ArrayIndex)); } else { @@ -91,7 +93,7 @@ bool FAnimBlueprintCompiler::FEffectiveConstantRecord::Apply(UObject* Object) } else { - FBlueprintEditorUtils::ImportKismetDefaultValueToProperty(LiteralSourcePin, ConstantProperty, PropertyPtr, Object); + FBlueprintEditorUtils::PropertyValueFromString_Direct(ConstantProperty, LiteralSourcePin->GetDefaultAsString(), PropertyPtr); } return true; @@ -225,7 +227,7 @@ void FAnimBlueprintCompiler::CreateEvaluationHandlerStruct(UAnimGraphNode_Base* // Does it get serviced by this handler? if (FAnimNodeSinglePropertyHandler* SourceInfo = Record.ServicedProperties.Find(PropertyName)) { - if (TargetPin->PinType.bIsArray) + if (TargetPin->PinType.IsArray()) { // Grab the array that we need to set members for UK2Node_StructMemberGet* FetchArrayNode = SpawnIntermediateNode(VisualAnimNode, ConsolidatedEventGraph); @@ -271,6 +273,7 @@ void FAnimBlueprintCompiler::CreateEvaluationHandlerStruct(UAnimGraphNode_Base* } else { + check(!TargetPin->PinType.IsContainer()) // Single property if (SourceInfo->CopyRecords.Num() > 0 && SourceInfo->CopyRecords[0].DestPin != nullptr) { @@ -351,7 +354,7 @@ void FAnimBlueprintCompiler::CreateEvaluationHandlerInstance(UAnimGraphNode_Base // Find the property pin on the set node and configure for(UEdGraphPin* TargetPin : VarAssignNode->Pins) { - if(TargetPin->PinType.bIsArray) + if(TargetPin->PinType.IsContainer()) { // Currently unsupported continue; @@ -659,7 +662,7 @@ void FAnimBlueprintCompiler::ProcessSubInstance(UAnimGraphNode_SubInstance* SubI FString PrefixedName = SubInstance->GetPinTargetVariableName(Pin); // Create a property on the new class to hold the pin data - UProperty* NewProperty = FKismetCompilerUtilities::CreatePropertyOnScope(NewAnimBlueprintClass, FName(*PrefixedName), Pin->PinType, NewAnimBlueprintClass, 0, GetSchema(), MessageLog); + UProperty* NewProperty = FKismetCompilerUtilities::CreatePropertyOnScope(NewAnimBlueprintClass, FName(*PrefixedName), Pin->PinType, NewAnimBlueprintClass, CPF_BlueprintVisible, GetSchema(), MessageLog); if(NewProperty) { NewProperty->SetMetaData(TEXT("Category"), TEXT("SubInstance")); @@ -1995,7 +1998,12 @@ void FAnimBlueprintCompiler::PostCompile() FExposedValueHandler* HandlerPtr = EvaluationHandler.EvaluationHandlerProperty->ContainerPtrToValuePtr(EvaluationHandler.NodeVariableProperty->ContainerPtrToValuePtr(DefaultAnimInstance)); TrueNode->BlueprintUsage = HandlerPtr->BoundFunction != NAME_None ? EBlueprintUsage::UsesBlueprint : EBlueprintUsage::DoesNotUseBlueprint; - if(TrueNode->BlueprintUsage == EBlueprintUsage::UsesBlueprint && AnimBlueprint->bWarnAboutBlueprintUsage) +#if WITH_EDITORONLY_DATA // ANIMINST_PostCompileValidation + const bool bWarnAboutBlueprintUsage = AnimBlueprint->bWarnAboutBlueprintUsage || DefaultAnimInstance->PCV_ShouldWarnAboutNodesNotUsingFastPath(); +#else + const bool bWarnAboutBlueprintUsage = AnimBlueprint->bWarnAboutBlueprintUsage; +#endif + if (bWarnAboutBlueprintUsage && (TrueNode->BlueprintUsage == EBlueprintUsage::UsesBlueprint)) { MessageLog.Warning(*LOCTEXT("BlueprintUsageWarning", "Node @@ uses Blueprint to update its values, access member variables directly or use a constant value for better performance.").ToString(), Node); } @@ -2362,6 +2370,27 @@ void FAnimBlueprintCompiler::PostCompileDiagnostics() { FKismetCompilerContext::PostCompileDiagnostics(); +#if WITH_EDITORONLY_DATA // ANIMINST_PostCompileValidation + // See if AnimInstance implements a PostCompileValidation Class. + // If so, instantiate it, and let it perform Validation of our newly compiled AnimBlueprint. + if (const UAnimInstance* const DefaultAnimInstance = CastChecked(NewAnimBlueprintClass->GetDefaultObject())) + { + if (DefaultAnimInstance->PostCompileValidationClassName.IsValid()) + { + UClass* PostCompileValidationClass = LoadClass(nullptr, *DefaultAnimInstance->PostCompileValidationClassName.ToString()); + if (PostCompileValidationClass) + { + UAnimBlueprintPostCompileValidation* PostCompileValidation = NewObject(GetTransientPackage(), PostCompileValidationClass); + if (PostCompileValidation) + { + FAnimBPCompileValidationParams PCV_Params(DefaultAnimInstance, NewAnimBlueprintClass, MessageLog, AllocatedNodePropertiesToNodes); + PostCompileValidation->DoPostCompileValidation(PCV_Params); + } + } + } + } +#endif // WITH_EDITORONLY_DATA + if (!bIsDerivedAnimBlueprint) { // Run thru all nodes and make sure they like the final results diff --git a/Engine/Source/Editor/KismetCompiler/Private/KismetCompiler.cpp b/Engine/Source/Editor/KismetCompiler/Private/KismetCompiler.cpp index 2333f5be7db9..9135227f2be1 100644 --- a/Engine/Source/Editor/KismetCompiler/Private/KismetCompiler.cpp +++ b/Engine/Source/Editor/KismetCompiler/Private/KismetCompiler.cpp @@ -287,7 +287,8 @@ void FKismetCompilerContext::CleanAndSanitizeClass(UBlueprintGeneratedClass* Cla // Set properties we need to regenerate the class with ClassToClean->PropertyLink = ParentClass->PropertyLink; - ClassToClean->ClassWithin = ParentClass; + ClassToClean->SetSuperStruct(ParentClass); + ClassToClean->ClassWithin = ParentClass->ClassWithin ? ParentClass->ClassWithin : UObject::StaticClass(); ClassToClean->ClassConfigName = ClassToClean->IsNative() ? FName(ClassToClean->StaticConfigName()) : ParentClass->ClassConfigName; ClassToClean->DebugData = FBlueprintDebugData(); } @@ -547,6 +548,7 @@ void FKismetCompilerContext::ValidateVariableNames() if (OldVarName != NewVarName) { MessageLog.Warning(*FString::Printf(*LOCTEXT("MemberVariableConflictWarning", "Found a member variable with a conflicting name (%s) - changed to %s.").ToString(), *VarNameStr, *NewVarName.ToString())); + TGuardValue LockDependencies(Blueprint->bCachedDependenciesUpToDate, Blueprint->bCachedDependenciesUpToDate); FBlueprintEditorUtils::RenameMemberVariable(Blueprint, OldVarName, NewVarName); } } @@ -672,7 +674,7 @@ void FKismetCompilerContext::CreateClassVariablesFromBlueprint() continue; } - FEdGraphPinType TimelinePinType(Schema->PC_Object, TEXT(""), UTimelineComponent::StaticClass(), false, false, false, false, FEdGraphTerminalType()); + FEdGraphPinType TimelinePinType(Schema->PC_Object, FString(), UTimelineComponent::StaticClass(), EPinContainerType::None, false, FEdGraphTerminalType()); // Previously UTimelineComponent object has exactly the same name as UTimelineTemplate object (that obj was in blueprint) const FString TimelineVariableName = UTimelineTemplate::TimelineTemplateNameToVariableName(Timeline->GetFName()); @@ -685,30 +687,30 @@ void FKismetCompilerContext::CreateClassVariablesFromBlueprint() TimelineToMemberVariableMap.Add(Timeline, TimelineProperty); } - FEdGraphPinType DirectionPinType(Schema->PC_Byte, TEXT(""), FTimeline::GetTimelineDirectionEnum(), false, false, false, false, FEdGraphTerminalType()); + FEdGraphPinType DirectionPinType(Schema->PC_Byte, FString(), FTimeline::GetTimelineDirectionEnum(), EPinContainerType::None, false, FEdGraphTerminalType()); CreateVariable(Timeline->GetDirectionPropertyName(), DirectionPinType); - FEdGraphPinType FloatPinType(Schema->PC_Float, TEXT(""), NULL, false, false, false, false, FEdGraphTerminalType()); - for(int32 i=0; iFloatTracks.Num(); i++) + FEdGraphPinType FloatPinType(Schema->PC_Float, FString(), nullptr, EPinContainerType::None, false, FEdGraphTerminalType()); + for (const FTTFloatTrack& FloatTrack : Timeline->FloatTracks) { - CreateVariable(Timeline->GetTrackPropertyName(Timeline->FloatTracks[i].TrackName), FloatPinType); + CreateVariable(Timeline->GetTrackPropertyName(FloatTrack.TrackName), FloatPinType); } - FEdGraphPinType VectorPinType(Schema->PC_Struct, TEXT(""), VectorStruct, false, false, false, false, FEdGraphTerminalType()); - for(int32 i=0; iVectorTracks.Num(); i++) + FEdGraphPinType VectorPinType(Schema->PC_Struct, FString(), VectorStruct, EPinContainerType::None, false, FEdGraphTerminalType()); + for (const FTTVectorTrack& VectorTrack : Timeline->VectorTracks) { - CreateVariable(Timeline->GetTrackPropertyName(Timeline->VectorTracks[i].TrackName), VectorPinType); + CreateVariable(Timeline->GetTrackPropertyName(VectorTrack.TrackName), VectorPinType); } - FEdGraphPinType LinearColorPinType(Schema->PC_Struct, TEXT(""), LinearColorStruct, false, false, false, false, FEdGraphTerminalType()); - for(int32 i=0; iLinearColorTracks.Num(); i++) + FEdGraphPinType LinearColorPinType(Schema->PC_Struct, FString(), LinearColorStruct, EPinContainerType::None, false, FEdGraphTerminalType()); + for (const FTTLinearColorTrack& LinearColorTrack : Timeline->LinearColorTracks) { - CreateVariable(Timeline->GetTrackPropertyName(Timeline->LinearColorTracks[i].TrackName), LinearColorPinType); + CreateVariable(Timeline->GetTrackPropertyName(LinearColorTrack.TrackName), LinearColorPinType); } } // Create a class property for any simple-construction-script created components that should be exposed - if (Blueprint->SimpleConstructionScript != NULL) + if (Blueprint->SimpleConstructionScript) { // Ensure that nodes have valid templates (This will remove nodes that have had the classes the inherited from removed Blueprint->SimpleConstructionScript->ValidateNodeTemplates(MessageLog); @@ -723,9 +725,8 @@ void FKismetCompilerContext::CreateClassVariablesFromBlueprint() FName VarName = Node->GetVariableName(); if ((VarName != NAME_None) && (Node->ComponentClass != nullptr)) { - FEdGraphPinType Type(Schema->PC_Object, TEXT(""), Node->ComponentClass, false, false, false, false, FEdGraphTerminalType()); - UProperty* NewProperty = CreateVariable(VarName, Type); - if (NewProperty != NULL) + FEdGraphPinType Type(Schema->PC_Object, FString(), Node->ComponentClass, EPinContainerType::None, false, FEdGraphTerminalType()); + if (UProperty* NewProperty = CreateVariable(VarName, Type)) { const FText CategoryName = Node->CategoryName.IsEmpty() ? FText::FromString(Blueprint->GetName()) : Node->CategoryName ; @@ -740,11 +741,9 @@ void FKismetCompilerContext::CreateClassVariablesFromBlueprint() void FKismetCompilerContext::CreatePropertiesFromList(UStruct* Scope, UField**& PropertyStorageLocation, TIndirectArray& Terms, uint64 PropertyFlags, bool bPropertiesAreLocal, bool bPropertiesAreParameters) { - for (int32 i = 0; i < Terms.Num(); ++i) + for (FBPTerminal& Term : Terms) { - FBPTerminal& Term = Terms[i]; - - if(NULL != Term.AssociatedVarProperty) + if (Term.AssociatedVarProperty) { if(Term.Context && !Term.Context->IsObjectContextType()) { @@ -758,11 +757,8 @@ void FKismetCompilerContext::CreatePropertiesFromList(UStruct* Scope, UField**& MessageLog.Error(*FString::Printf(*LOCTEXT("PropertyForLiteral_Error", "Cannot create property for a literal: %s from @@ type (%s)").ToString(), *Term.Name, *UEdGraphSchema_K2::TypeToText(Term.Type).ToString()), Term.Source); } - UProperty* NewProperty = FKismetCompilerUtilities::CreatePropertyOnScope(Scope, FName(*Term.Name), Term.Type, NewClass, PropertyFlags, Schema, MessageLog); - if (NewProperty != NULL) + if (UProperty* NewProperty = FKismetCompilerUtilities::CreatePropertyOnScope(Scope, FName(*Term.Name), Term.Type, NewClass, PropertyFlags, Schema, MessageLog)) { - NewProperty->PropertyFlags |= PropertyFlags; - if (bPropertiesAreParameters && Term.Type.bIsConst) { NewProperty->SetPropertyFlags(CPF_ConstParm); @@ -1021,24 +1017,10 @@ void FKismetCompilerContext::CreateUserDefinedLocalVariablesForFunction(FKismetF for (int32 i = 0; i < Context.EntryPoint->LocalVariables.Num(); ++i) { FBPVariableDescription& Variable = Context.EntryPoint->LocalVariables[Context.EntryPoint->LocalVariables.Num() - (i + 1)]; - - // Create the property based on the variable description, scoped to the function - UProperty* NewProperty = FKismetCompilerUtilities::CreatePropertyOnScope(Context.Function, Variable.VarName, Variable.VarType, NewClass, 0, Schema, MessageLog); - if (NewProperty != NULL) - { - // Link this object to the tail of the list (so properties remain in the desired order) - *FunctionPropertyStorageLocation = NewProperty; - FunctionPropertyStorageLocation = &(NewProperty->Next); - } + UProperty* NewProperty = CreateUserDefinedLocalVariableForFunction(Variable, Context.Function, NewClass, FunctionPropertyStorageLocation, Schema, MessageLog); if (NewProperty != NULL) { - NewProperty->SetPropertyFlags(Variable.PropertyFlags); - NewProperty->SetMetaData(TEXT("FriendlyName"), *Variable.FriendlyName); - NewProperty->SetMetaData(TEXT("Category"), *Variable.Category.ToString()); - NewProperty->RepNotifyFunc = Variable.RepNotifyFunc; - NewProperty->SetPropertyFlags(Variable.PropertyFlags); - if(!Variable.DefaultValue.IsEmpty()) { SetPropertyDefaultValue(NewProperty, Variable.DefaultValue); @@ -1047,6 +1029,26 @@ void FKismetCompilerContext::CreateUserDefinedLocalVariablesForFunction(FKismetF } } +UProperty* FKismetCompilerContext::CreateUserDefinedLocalVariableForFunction(const FBPVariableDescription& Variable, UFunction* Function, UBlueprintGeneratedClass* OwningClass, UField**& FunctionPropertyStorageLocation, const UEdGraphSchema_K2* Schema, FCompilerResultsLog& MessageLog) +{ + UProperty* NewProperty = FKismetCompilerUtilities::CreatePropertyOnScope(Function, Variable.VarName, Variable.VarType, OwningClass, 0, Schema, MessageLog); + + if(NewProperty) + { + // Link this object to the tail of the list (so properties remain in the desired order) + *FunctionPropertyStorageLocation = NewProperty; + FunctionPropertyStorageLocation = &(NewProperty->Next); + + NewProperty->SetPropertyFlags(Variable.PropertyFlags); + NewProperty->SetMetaData(TEXT("FriendlyName"), *Variable.FriendlyName); + NewProperty->SetMetaData(TEXT("Category"), *Variable.Category.ToString()); + NewProperty->RepNotifyFunc = Variable.RepNotifyFunc; + NewProperty->SetPropertyFlags(Variable.PropertyFlags); + } + + return NewProperty; +} + void FKismetCompilerContext::SetPropertyDefaultValue(const UProperty* PropertyToSet, FString& Value) { DefaultPropertyValueMap.Add(PropertyToSet->GetFName(), Value); @@ -1088,6 +1090,13 @@ void FKismetCompilerContext::CopyTermDefaultsToDefaultObject(UObject* DefaultObj } } +void FKismetCompilerContext::PropagateValuesToCDO(UObject* InNewCDO, UObject* InOldCDO) +{ + ensure(InNewCDO); + CopyTermDefaultsToDefaultObject(InNewCDO); + SetCanEverTick(); +} + void FKismetCompilerContext::PrintVerboseInfoStruct(UStruct* Struct) const { for (TFieldIterator PropIt(Struct); PropIt; ++PropIt) @@ -1536,7 +1545,7 @@ void FKismetCompilerContext::PrecompileFunction(FKismetFunctionContext& Context, // Inherit extra flags from the entry node if (Context.EntryPoint) { - Context.Function->FunctionFlags |= Context.EntryPoint->GetExtraFlags(); + Context.Function->FunctionFlags |= (EFunctionFlags)Context.EntryPoint->GetExtraFlags(); } // First try to get the overriden function from the super class @@ -1683,7 +1692,7 @@ void FKismetCompilerContext::PrecompileFunction(FKismetFunctionContext& Context, } Context.LastFunctionPropertyStorageLocation = FunctionPropertyStorageLocation; - Context.Function->FunctionFlags |= Context.GetNetFlags(); + Context.Function->FunctionFlags |= (EFunctionFlags)Context.GetNetFlags(); // Parameter list needs to be linked before signatures are compared. Context.Function->StaticLink(true); @@ -1708,7 +1717,7 @@ void FKismetCompilerContext::PrecompileFunction(FKismetFunctionContext& Context, MessageLog.Warning(*LOCTEXT("IncompatibleAccessSpecifier_Error", "Access specifier is not compatible the parent function @@").ToString(), Context.EntryPoint); } - uint32 const ParentNetFlags = (ParentFunction->FunctionFlags & FUNC_NetFuncFlags); + EFunctionFlags const ParentNetFlags = (ParentFunction->FunctionFlags & FUNC_NetFuncFlags); if (ParentNetFlags != Context.GetNetFlags()) { MessageLog.Error(*LOCTEXT("MismatchedNetFlags_Error", "@@ function's net flags don't match parent function's flags").ToString(), Context.EntryPoint); @@ -1981,7 +1990,16 @@ void FKismetCompilerContext::PostcompileFunction(FKismetFunctionContext& Context */ void FKismetCompilerContext::FinishCompilingFunction(FKismetFunctionContext& Context) { - UFunction* Function = Context.Function; + SetCalculatedMetaDataAndFlags( Context.Function, CastChecked(Context.EntryPoint), Schema ); +} + +void FKismetCompilerContext::SetCalculatedMetaDataAndFlags(UFunction* Function, UK2Node_FunctionEntry* EntryNode, const UEdGraphSchema_K2* K2Schema) +{ + if(!ensure(Function) || !ensure(EntryNode)) + { + return; + } + Function->Bind(); Function->StaticLink(true); @@ -2012,15 +2030,32 @@ void FKismetCompilerContext::FinishCompilingFunction(FKismetFunctionContext& Con { if (!Property->HasAnyPropertyFlags(CPF_ZeroConstructor)) { - Function->FirstPropertyToInit = Property; - Function->FunctionFlags |= FUNC_HasDefaults; + Function->FirstPropertyToInit = Property; + Function->FunctionFlags |= FUNC_HasDefaults; break; - } + } } } + FKismetUserDeclaredFunctionMetadata& FunctionMetaData = EntryNode->MetaData; + if (!FunctionMetaData.Category.IsEmpty()) + { + Function->SetMetaData(FBlueprintMetadata::MD_FunctionCategory, *FunctionMetaData.Category.ToString()); + } + + // Set up the function keywords + if (!FunctionMetaData.Keywords.IsEmpty()) + { + Function->SetMetaData(FBlueprintMetadata::MD_FunctionKeywords, *FunctionMetaData.Keywords.ToString()); + } + + // Set up the function compact node title + if (!FunctionMetaData.CompactNodeTitle.IsEmpty()) + { + Function->SetMetaData(FBlueprintMetadata::MD_CompactNodeTitle, *FunctionMetaData.CompactNodeTitle.ToString()); + } + // Add in any extra user-defined metadata, like tooltip - UK2Node_FunctionEntry* EntryNode = CastChecked(Context.EntryPoint); if (!EntryNode->MetaData.ToolTip.IsEmpty()) { Function->SetMetaData(FBlueprintMetadata::MD_Tooltip, *EntryNode->MetaData.ToolTip.ToString()); @@ -2038,15 +2073,21 @@ void FKismetCompilerContext::FinishCompilingFunction(FKismetFunctionContext& Con { UEdGraphPin* EntryPin = EntryNode->Pins[EntryPinIndex]; // No defaults for object/class pins - if( !Schema->IsMetaPin(*EntryPin) && - (EntryPin->PinType.PinCategory != Schema->PC_Object) && - (EntryPin->PinType.PinCategory != Schema->PC_Class) && - (EntryPin->PinType.PinCategory != Schema->PC_Interface) && + if( !K2Schema->IsMetaPin(*EntryPin) && + (EntryPin->PinType.PinCategory != UEdGraphSchema_K2::PC_Object) && + (EntryPin->PinType.PinCategory != UEdGraphSchema_K2::PC_Class) && + (EntryPin->PinType.PinCategory != UEdGraphSchema_K2::PC_Interface) && !EntryPin->DefaultValue.IsEmpty() ) { Function->SetMetaData(*EntryPin->PinName, *EntryPin->DefaultValue); } } + + if(UFunction* OverriddenFunction = Function->GetSuperFunction()) + { + // Copy metadata from parent function as well + UMetaData::CopyMetadata(OverriddenFunction, Function); + } } /** @@ -2096,7 +2137,6 @@ void FKismetCompilerContext::FinishCompilingClass(UClass* Class) Class->ClassFlags &= ~CLASS_RecompilerClear; Class->ClassFlags |= (ParentClass->ClassFlags & CLASS_ScriptInherit);//@TODO: ChangeParentClass had this, but I don't think I want it: | UClass::StaticClassFlags; // will end up with CLASS_Intrinsic Class->ClassCastFlags |= ParentClass->ClassCastFlags; - Class->ClassWithin = ParentClass->ClassWithin ? ParentClass->ClassWithin : UObject::StaticClass(); Class->ClassConfigName = ParentClass->ClassConfigName; // If the Blueprint was marked as deprecated, then flag the class as deprecated. @@ -2413,7 +2453,7 @@ void FKismetCompilerContext::ExpandTimelineNodes(UEdGraph* SourceGraph) // This might fail if this is the first compile after adding the timeline (property doesn't exist yet) - in that case, manually add the output pin if (TimelineVarPin == NULL) { - TimelineVarPin = GetTimelineNode->CreatePin(EGPD_Output, Schema->PC_Object, TEXT(""), UTimelineComponent::StaticClass(), false, false, TimelineNode->TimelineName.ToString()); + TimelineVarPin = GetTimelineNode->CreatePin(EGPD_Output, Schema->PC_Object, FString(), UTimelineComponent::StaticClass(), TimelineNode->TimelineName.ToString()); } if (bPlayPinConnected) @@ -2503,10 +2543,15 @@ FPinConnectionResponse FKismetCompilerContext::CopyPinLinksToIntermediate(UEdGra } UK2Node_TemporaryVariable* FKismetCompilerContext::SpawnInternalVariable(UEdGraphNode* SourceNode, FString Category, FString SubCategory, UObject* SubcategoryObject, bool bIsArray, bool bIsSet, bool bIsMap, const FEdGraphTerminalType& ValueTerminalType) +{ + return SpawnInternalVariable(SourceNode, MoveTemp(Category), MoveTemp(SubCategory), SubcategoryObject, FEdGraphPinType::ToPinContainerType(bIsArray, bIsSet, bIsMap), ValueTerminalType); +} + +UK2Node_TemporaryVariable* FKismetCompilerContext::SpawnInternalVariable(UEdGraphNode* SourceNode, FString Category, FString SubCategory, UObject* SubcategoryObject, EPinContainerType PinContainerType, const FEdGraphTerminalType& ValueTerminalType) { UK2Node_TemporaryVariable* Result = SpawnIntermediateNode(SourceNode); - Result->VariableType = FEdGraphPinType(Category, SubCategory, SubcategoryObject, bIsArray, false, bIsSet, bIsMap, ValueTerminalType); + Result->VariableType = FEdGraphPinType(MoveTemp(Category), MoveTemp(SubCategory), SubcategoryObject, PinContainerType, false, ValueTerminalType); Result->AllocateDefaultPins(); return Result; @@ -3245,7 +3290,7 @@ void FKismetCompilerContext::ExpandTunnelsAndMacros(UEdGraph* SourceGraph) if (Pin) { // Since we don't support array literals, drop a make array node on any unconnected array pins, which will allow macro expansion to succeed even if disconnected - if (Pin->PinType.bIsArray + if (Pin->PinType.IsArray() && (Pin->Direction == EGPD_Input) && (Pin->LinkedTo.Num() == 0)) { @@ -3427,7 +3472,8 @@ void FKismetCompilerContext::ProcessOneFunctionGraph(UEdGraph* SourceGraph, bool // been added to the class yet, etc.) if ((CompileOptions.CompileType == EKismetCompileType::SkeletonOnly) || ValidateGraphIsWellFormed(FunctionGraph)) { - FKismetFunctionContext& Context = *new (FunctionList)FKismetFunctionContext(MessageLog, Schema, NewClass, Blueprint, CompileOptions.DoesRequireCppCodeGeneration(), CompileOptions.IsInstrumentationActive()); + const UEdGraphSchema_K2* FunctionGraphSchema = CastChecked(FunctionGraph->GetSchema()); + FKismetFunctionContext& Context = *new (FunctionList)FKismetFunctionContext(MessageLog, FunctionGraphSchema, NewClass, Blueprint, CompileOptions.DoesRequireCppCodeGeneration(), CompileOptions.IsInstrumentationActive()); Context.SourceGraph = FunctionGraph; if(FBlueprintEditorUtils::IsDelegateSignatureGraph(SourceGraph)) @@ -3442,7 +3488,7 @@ void FKismetCompilerContext::ProcessOneFunctionGraph(UEdGraph* SourceGraph, bool } bool bEnforceConstCorrectness = true; - if (FBlueprintEditorUtils::IsBlueprintConst(Blueprint) || Schema->IsConstFunctionGraph(Context.SourceGraph, &bEnforceConstCorrectness)) + if (FBlueprintEditorUtils::IsBlueprintConst(Blueprint) || Context.Schema->IsConstFunctionGraph(Context.SourceGraph, &bEnforceConstCorrectness)) { Context.MarkAsConstFunction(bEnforceConstCorrectness); } @@ -3712,8 +3758,7 @@ void FKismetCompilerContext::CompileClassLayout(EInternalCompilerFlags InternalF NewClass->ClassGeneratedBy = Blueprint; // Set class metadata as needed - UClass* ParentClass = NewClass->ClassWithin; - NewClass->SetSuperStruct(ParentClass); + UClass* ParentClass = NewClass->GetSuperClass(); NewClass->ClassFlags |= (ParentClass->ClassFlags & CLASS_Inherit); NewClass->ClassCastFlags |= ParentClass->ClassCastFlags; @@ -3776,7 +3821,7 @@ void FKismetCompilerContext::CompileClassLayout(EInternalCompilerFlags InternalF if (UsePersistentUberGraphFrame() && UbergraphContext) { //UBER GRAPH PERSISTENT FRAME - FEdGraphPinType Type(TEXT("struct"), TEXT(""), FPointerToUberGraphFrame::StaticStruct(), false, false, false, false, FEdGraphTerminalType()); + FEdGraphPinType Type(TEXT("struct"), FString(), FPointerToUberGraphFrame::StaticStruct(), EPinContainerType::None, false, FEdGraphTerminalType()); UProperty* Property = CreateVariable(UBlueprintGeneratedClass::GetUberGraphFrameName(), Type); Property->SetPropertyFlags(CPF_DuplicateTransient | CPF_Transient); } @@ -3791,7 +3836,12 @@ void FKismetCompilerContext::CompileClassLayout(EInternalCompilerFlags InternalF void FKismetCompilerContext::CompileFunctions(EInternalCompilerFlags InternalFlags) { + // This is phase two, so we want to generated locals if PostponeLocalsGenerationUntilPhaseTwo is set: const bool bGenerateLocals = !!(InternalFlags & EInternalCompilerFlags::PostponeLocalsGenerationUntilPhaseTwo); + // Don't propagate values to CDO if we're going to do that in reinstancing: + const bool bPropagateValuesToCDO = !(InternalFlags & EInternalCompilerFlags::PostponeDefaultObjectAssignmentUntilReinstancing); + // Don't RefreshExternalBlueprintDependencyNodes if the calling code has done so already: + const bool bSkipRefreshExternalBlueprintDependencyNodes = !!(InternalFlags & EInternalCompilerFlags::SkipRefreshExternalBlueprintDependencyNodes); FKismetCompilerVMBackend Backend_VM(Blueprint, Schema, *this); if( bGenerateLocals ) @@ -3926,9 +3976,10 @@ void FKismetCompilerContext::CompileFunctions(EInternalCompilerFlags InternalFla Blueprint->PRIVATE_InnermostPreviousCDO = OldCDO; } } - else + + if(bPropagateValuesToCDO) { - if( NewCDO ) + if( !Blueprint->HasAnyFlags(RF_BeingRegenerated) ) { // Propagate the old CDO's properties to the new if( OldCDO ) @@ -3963,10 +4014,9 @@ void FKismetCompilerContext::CompileFunctions(EInternalCompilerFlags InternalFla } // <<< End Backwards Compatibility } - } - CopyTermDefaultsToDefaultObject(NewCDO); - SetCanEverTick(); + PropagateValuesToCDO(NewCDO, OldCDO); + } // Note: The old->new CDO copy is deferred when regenerating, so we skip this step in that case. if (!Blueprint->HasAnyFlags(RF_BeingRegenerated)) @@ -4105,7 +4155,7 @@ void FKismetCompilerContext::CompileFunctions(EInternalCompilerFlags InternalFla } // For full compiles, find other blueprints that may need refreshing, and mark them dirty, in case they try to run - if( bIsFullCompile && !Blueprint->bIsRegeneratingOnLoad ) + if( bIsFullCompile && !Blueprint->bIsRegeneratingOnLoad && !bSkipRefreshExternalBlueprintDependencyNodes ) { TArray DependentBlueprints; FBlueprintEditorUtils::GetDependentBlueprints(Blueprint, DependentBlueprints); @@ -4255,7 +4305,7 @@ void FKismetCompilerContext::CompileFunctions(EInternalCompilerFlags InternalFla if (UClass* AsClass = Cast(Struct)) { - Ar << AsClass->ClassFlags; + Ar << (uint32&)AsClass->ClassFlags; Ar << AsClass->Interfaces; } @@ -4425,15 +4475,15 @@ FString FKismetCompilerContext::GetGuid(const UEdGraphNode* Node) const return Ret.ToString(); } -TUniquePtr FKismetCompilerContext::GetCompilerForBP(UBlueprint* BP, FCompilerResultsLog& InMessageLog, const FKismetCompilerOptions& InCompileOptions) +TSharedPtr FKismetCompilerContext::GetCompilerForBP(UBlueprint* BP, FCompilerResultsLog& InMessageLog, const FKismetCompilerOptions& InCompileOptions) { if(UAnimBlueprint* AnimBP = Cast(BP)) { - return TUniquePtr(new FAnimBlueprintCompiler(AnimBP, InMessageLog, InCompileOptions, nullptr)); + return TSharedPtr(new FAnimBlueprintCompiler(AnimBP, InMessageLog, InCompileOptions, nullptr)); } else { - return TUniquePtr(new FKismetCompilerContext(BP, InMessageLog, InCompileOptions, nullptr)); + return TSharedPtr(new FKismetCompilerContext(BP, InMessageLog, InCompileOptions, nullptr)); } } diff --git a/Engine/Source/Editor/KismetCompiler/Private/KismetCompilerMisc.cpp b/Engine/Source/Editor/KismetCompiler/Private/KismetCompilerMisc.cpp index 444f71629ae0..f434363ab755 100644 --- a/Engine/Source/Editor/KismetCompiler/Private/KismetCompilerMisc.cpp +++ b/Engine/Source/Editor/KismetCompiler/Private/KismetCompilerMisc.cpp @@ -277,7 +277,7 @@ bool FKismetCompilerUtilities::IsTypeCompatibleWithProperty(UEdGraphPin* SourceP int32 NumErrorsAtStart = MessageLog.NumErrors; bool bTypeMismatch = false; - if( Type.bIsArray ) + if( Type.IsArray() ) { // For arrays, the property we want to test against is the inner property if( UArrayProperty* ArrayProp = Cast(Property) ) @@ -309,7 +309,7 @@ bool FKismetCompilerUtilities::IsTypeCompatibleWithProperty(UEdGraphPin* SourceP return false; } } - else if (Type.bIsSet) + else if (Type.IsSet()) { if (USetProperty* SetProperty = Cast(Property)) { @@ -326,7 +326,7 @@ bool FKismetCompilerUtilities::IsTypeCompatibleWithProperty(UEdGraphPin* SourceP return false; } } - else if (Type.bIsMap) + else if (Type.IsMap()) { if (UMapProperty* MapProperty = Cast(Property)) { @@ -662,7 +662,7 @@ bool FKismetCompilerUtilities::ValidateSelfCompatibility(const UEdGraphPin* Pin, { const UBlueprint* Blueprint = Context.Blueprint; const UEdGraph* SourceGraph = Context.SourceGraph; - UEdGraphSchema_K2* K2Schema = Context.Schema; + const UEdGraphSchema_K2* K2Schema = Context.Schema; const UBlueprintGeneratedClass* BPClass = Context.NewClass; FString ErrorMsg; @@ -757,8 +757,8 @@ UEdGraphPin* FKismetCompilerUtilities::GenerateAssignmentNodes(class FKismetComp UFunction* SetByNameFunction = Schema->FindSetVariableByNameFunction(OrgPin->PinType); if (SetByNameFunction) { - UK2Node_CallFunction* SetVarNode = NULL; - if (OrgPin->PinType.bIsArray) + UK2Node_CallFunction* SetVarNode = nullptr; + if (OrgPin->PinType.IsArray()) { SetVarNode = CompilerContext.SpawnIntermediateNode(SpawnNode, SourceGraph); } @@ -801,7 +801,7 @@ UEdGraphPin* FKismetCompilerUtilities::GenerateAssignmentNodes(class FKismetComp else { // For non-array struct pins that are not linked, transfer the pin type so that the node will expand an auto-ref that will assign the value by-ref. - if (OrgPin->PinType.bIsArray == false && OrgPin->PinType.PinCategory == Schema->PC_Struct && OrgPin->LinkedTo.Num() == 0) + if (OrgPin->PinType.IsArray() == false && OrgPin->PinType.PinCategory == Schema->PC_Struct && OrgPin->LinkedTo.Num() == 0) { ValuePin->PinType.PinCategory = OrgPin->PinType.PinCategory; ValuePin->PinType.PinSubCategory = OrgPin->PinType.PinSubCategory; @@ -1057,9 +1057,6 @@ UProperty* FKismetCompilerUtilities::CreatePropertyOnScope(UStruct* Scope, const { const EObjectFlags ObjectFlags = RF_Public; - UProperty* NewProperty = NULL; - UObject* PropertyScope = NULL; - FName ValidatedPropertyName = PropertyName; // Check to see if there's already a object on this scope with the same name, and throw an internal compiler error if so @@ -1079,20 +1076,19 @@ UProperty* FKismetCompilerUtilities::CreatePropertyOnScope(UStruct* Scope, const FString TestNameString = PropertyName.ToString() + FString::Printf(TEXT("_ERROR_DUPLICATE_%d"), Counter++); TestName = FName(*TestNameString); - } while (CheckPropertyNameOnScope(Scope, TestName) != NULL); + } while (CheckPropertyNameOnScope(Scope, TestName) != nullptr); ValidatedPropertyName = TestName; } } - // Handle creating an array property, if necessary - const bool bIsMapProperty = Type.bIsMap; - const bool bIsSetProperty = Type.bIsSet; - const bool bIsArrayProperty = Type.bIsArray; - // only one of these should be set (or none): - ensure( !(bIsMapProperty || bIsSetProperty || bIsArrayProperty) || - ( !(bIsMapProperty && bIsSetProperty && bIsArrayProperty) && (bIsMapProperty ^ bIsSetProperty ^ bIsArrayProperty) ) - ); + UProperty* NewProperty = nullptr; + UObject* PropertyScope = nullptr; + + // Handle creating a container property, if necessary + const bool bIsMapProperty = Type.IsMap(); + const bool bIsSetProperty = Type.IsSet(); + const bool bIsArrayProperty = Type.IsArray(); UMapProperty* NewMapProperty = nullptr; USetProperty* NewSetProperty = nullptr; UArrayProperty* NewArrayProperty = nullptr; @@ -1152,7 +1148,6 @@ UProperty* FKismetCompilerUtilities::CreatePropertyOnScope(UStruct* Scope, const { if (!NewProperty->HasAnyPropertyFlags(CPF_HasGetValueTypeHash)) { - MessageLog.Error( *FString::Printf( *LOCTEXT("MapKeyTypeUnhashable_Error", "Map Property @@ has key type of %s which cannot be hashed and is therefore invalid").ToString(), @@ -1161,7 +1156,7 @@ UProperty* FKismetCompilerUtilities::CreatePropertyOnScope(UStruct* Scope, const ); } // make the value property: - // not feelign good about myself.. + // not feeling good about myself.. // Fix up the array property to have the new type-specific property as its inner, and return the new UArrayProperty NewMapProperty->KeyProp = NewProperty; // make sure the value property does not collide with the key property: @@ -1225,6 +1220,11 @@ UProperty* FKismetCompilerUtilities::CreatePropertyOnScope(UStruct* Scope, const } } + if (NewProperty) + { + NewProperty->SetPropertyFlags(PropertyFlags); + } + return NewProperty; } @@ -1239,7 +1239,7 @@ UObject* FKismetCompilerUtilities::CheckPropertyNameOnScope(UStruct* Scope, cons if (Scope && !Scope->IsA() && (UBlueprintGeneratedClass::GetUberGraphFrameName() != PropertyName)) { - if (auto Field = FindField(Scope ? Scope->GetSuperStruct() : nullptr, *NameStr)) + if (auto Field = FindField(Scope->GetSuperStruct(), *NameStr)) { return Field; } @@ -1634,8 +1634,8 @@ FBPTerminal* FNodeHandlingFunctor::RegisterLiteral(FKismetFunctionContext& Conte FString ErrorString = FText::Format(ErrorFormat, InvalidReasonText, DefaultValue).ToString(); CompilerContext.MessageLog.Error(*ErrorString, Net); - // Skip over these properties if they are array or ref properties, because the backend can't emit valid code for them - if (Net->PinType.bIsArray || Net->PinType.bIsReference) + // Skip over these properties if they are container or ref properties, because the backend can't emit valid code for them + if (Net->PinType.IsContainer() || Net->PinType.bIsReference) { return nullptr; } @@ -1699,7 +1699,7 @@ FString FNetNameMapping::MakeBaseName(const UAnimGraphNode_Base* Net) ////////////////////////////////////////////////////////////////////////// // FKismetFunctionContext -FKismetFunctionContext::FKismetFunctionContext(FCompilerResultsLog& InMessageLog, UEdGraphSchema_K2* InSchema, UBlueprintGeneratedClass* InNewClass, UBlueprint* InBlueprint, bool bInGeneratingCpp, bool bInWantsInstrumentation) +FKismetFunctionContext::FKismetFunctionContext(FCompilerResultsLog& InMessageLog, const UEdGraphSchema_K2* InSchema, UBlueprintGeneratedClass* InNewClass, UBlueprint* InBlueprint, bool bInGeneratingCpp, bool bInWantsInstrumentation) : Blueprint(InBlueprint) , SourceGraph(nullptr) , EntryPoint(nullptr) @@ -2103,7 +2103,7 @@ struct FEventGraphUtils { // TODO: Strange cases.. if ((Net.Direction != EEdGraphPinDirection::EGPD_Output) - || Net.PinType.bIsArray + || Net.PinType.IsContainer() || Net.PinType.bIsReference || Net.PinType.bIsConst || Net.SubPins.Num()) diff --git a/Engine/Source/Editor/KismetCompiler/Private/KismetCompilerModule.cpp b/Engine/Source/Editor/KismetCompiler/Private/KismetCompilerModule.cpp index eb80409c08e0..8d24d5ea6217 100644 --- a/Engine/Source/Editor/KismetCompiler/Private/KismetCompilerModule.cpp +++ b/Engine/Source/Editor/KismetCompiler/Private/KismetCompilerModule.cpp @@ -49,8 +49,8 @@ public: virtual void RemoveBlueprintGeneratedClasses(class UBlueprint* Blueprint) override; virtual TArray& GetCompilers() override { return Compilers; } virtual void GetBlueprintTypesForClass(UClass* ParentClass, UClass*& OutBlueprintClass, UClass*& OutBlueprintGeneratedClass) const override; - virtual void GenerateCppCodeForEnum(UUserDefinedEnum* UDEnum, FString& OutHeaderCode, FString& OutCPPCode) override; - virtual FString GenerateCppCodeForStruct(UUserDefinedStruct* UDStruct, const FCompilerNativizationOptions& NativizationOptions) override; + virtual void GenerateCppCodeForEnum(UUserDefinedEnum* UDEnum, const FCompilerNativizationOptions& NativizationOptions, FString& OutHeaderCode, FString& OutCPPCode) override; + virtual void GenerateCppCodeForStruct(UUserDefinedStruct* UDStruct, const FCompilerNativizationOptions& NativizationOptions, FString& OutHeaderCode, FString& OutCPPCode) override; virtual FString GenerateCppWrapper(UBlueprintGeneratedClass* BPGC, const FCompilerNativizationOptions& NativizationOptions) override; // End implementation private: @@ -179,16 +179,16 @@ void FKismet2CompilerModule::CompileStructure(UUserDefinedStruct* Struct, FCompi FUserDefinedStructureCompilerUtils::CompileStruct(Struct, Results, true); } -void FKismet2CompilerModule::GenerateCppCodeForEnum(UUserDefinedEnum* UDEnum, FString& OutHeaderCode, FString& OutCPPCode) +void FKismet2CompilerModule::GenerateCppCodeForEnum(UUserDefinedEnum* UDEnum, const FCompilerNativizationOptions& NativizationOptions, FString& OutHeaderCode, FString& OutCPPCode) { TUniquePtr Backend_CPP(IBlueprintCompilerCppBackendModuleInterface::Get().Create()); - Backend_CPP->GenerateCodeFromEnum(UDEnum, OutHeaderCode, OutCPPCode); + Backend_CPP->GenerateCodeFromEnum(UDEnum, NativizationOptions, OutHeaderCode, OutCPPCode); } -FString FKismet2CompilerModule::GenerateCppCodeForStruct(UUserDefinedStruct* UDStruct, const FCompilerNativizationOptions& NativizationOptions) +void FKismet2CompilerModule::GenerateCppCodeForStruct(UUserDefinedStruct* UDStruct, const FCompilerNativizationOptions& NativizationOptions, FString& OutHeaderCode, FString& OutCPPCode) { TUniquePtr Backend_CPP(IBlueprintCompilerCppBackendModuleInterface::Get().Create()); - return Backend_CPP->GenerateCodeFromStruct(UDStruct, NativizationOptions); + Backend_CPP->GenerateCodeFromStruct(UDStruct, NativizationOptions, OutHeaderCode, OutCPPCode); } FString FKismet2CompilerModule::GenerateCppWrapper(UBlueprintGeneratedClass* BPGC, const FCompilerNativizationOptions& NativizationOptions) @@ -360,8 +360,11 @@ void FKismet2CompilerModule::RefreshVariables(UBlueprint* Blueprint) K2Schema, MessageLog); - NewProperty->PropertyLinkNext = Blueprint->GeneratedClass->PropertyLink; - Blueprint->GeneratedClass->PropertyLink = NewProperty; + if(NewProperty) + { + NewProperty->PropertyLinkNext = Blueprint->GeneratedClass->PropertyLink; + Blueprint->GeneratedClass->PropertyLink = NewProperty; + } } Blueprint->GeneratedClass->Bind(); diff --git a/Engine/Source/Editor/KismetCompiler/Private/KismetCompilerVMBackend.cpp b/Engine/Source/Editor/KismetCompiler/Private/KismetCompilerVMBackend.cpp index 5538119a7f9a..22199cf5885f 100644 --- a/Engine/Source/Editor/KismetCompiler/Private/KismetCompilerVMBackend.cpp +++ b/Engine/Source/Editor/KismetCompiler/Private/KismetCompilerVMBackend.cpp @@ -578,42 +578,43 @@ public: { if (Term->bIsLiteral) { - check(!Term->Type.bIsArray || CoerceProperty); + check(!Term->Type.IsContainer() || CoerceProperty); // Additional Validation, since we cannot trust custom k2nodes - const bool bSecialCaseSelf = (Term->Type.PinSubCategory == Schema->PN_Self); - if (CoerceProperty && ensure(Schema) && ensure(CurrentCompilerContext) && !bSecialCaseSelf) + if (CoerceProperty && ensure(Schema) && ensure(CurrentCompilerContext)) { - FEdGraphPinType TrueType; - const bool bValidProperty = Schema->ConvertPropertyToPinType(CoerceProperty, TrueType); - - auto AreTypesBinaryCompatible = [](const FEdGraphPinType& TypeA, const FEdGraphPinType& TypeB) -> bool - { - if (TypeA.PinCategory != TypeB.PinCategory) - { - return false; - } - if ((TypeA.bIsMap != TypeB.bIsMap) - || (TypeA.bIsSet != TypeB.bIsSet) - || (TypeA.bIsArray != TypeB.bIsArray) - || (TypeA.bIsWeakPointer != TypeB.bIsWeakPointer)) - { - return false; - } - if (TypeA.PinCategory == UEdGraphSchema_K2::PC_Struct) - { - if (TypeA.PinSubCategoryObject != TypeB.PinSubCategoryObject) - { - return false; - } - } - return true; - }; - - if (!bValidProperty || !AreTypesBinaryCompatible(Term->Type, TrueType)) - { - const FString ErrorMessage = FString::Printf(TEXT("ICE: The type of property %s doesn't match a term. @@"), *CoerceProperty->GetPathName()); - CurrentCompilerContext->MessageLog.Error(*ErrorMessage, Term->SourcePin); + const bool bSecialCaseSelf = (Term->Type.PinSubCategory == Schema->PN_Self); + if(!bSecialCaseSelf) + { + FEdGraphPinType TrueType; + const bool bValidProperty = Schema->ConvertPropertyToPinType(CoerceProperty, TrueType); + + auto AreTypesBinaryCompatible = [](const FEdGraphPinType& TypeA, const FEdGraphPinType& TypeB) -> bool + { + if (TypeA.PinCategory != TypeB.PinCategory) + { + return false; + } + if ((TypeA.ContainerType != TypeB.ContainerType) + || (TypeA.bIsWeakPointer != TypeB.bIsWeakPointer)) + { + return false; + } + if (TypeA.PinCategory == UEdGraphSchema_K2::PC_Struct) + { + if (TypeA.PinSubCategoryObject != TypeB.PinSubCategoryObject) + { + return false; + } + } + return true; + }; + + if (!bValidProperty || !AreTypesBinaryCompatible(Term->Type, TrueType)) + { + const FString ErrorMessage = FString::Printf(TEXT("ICE: The type of property %s doesn't match a term. @@"), *CoerceProperty->GetPathName()); + CurrentCompilerContext->MessageLog.Error(*ErrorMessage, Term->SourcePin); + } } } @@ -788,10 +789,13 @@ public: if (Struct == VectorStruct) { FVector V = FVector::ZeroVector; - const bool bParsedUsingCustomFormat = FDefaultValueHelper::ParseVector(Term->Name, /*out*/ V); - if (!bParsedUsingCustomFormat) + if (!Term->Name.IsEmpty()) { - Struct->ImportText(*Term->Name, &V, nullptr, PPF_None, GWarn, GetPathNameSafe(StructProperty)); + const bool bParsedUsingCustomFormat = FDefaultValueHelper::ParseVector(Term->Name, /*out*/ V); + if (!bParsedUsingCustomFormat) + { + Struct->ImportText(*Term->Name, &V, nullptr, PPF_None, GWarn, GetPathNameSafe(StructProperty)); + } } Writer << EX_VectorConst; Writer << V; @@ -799,10 +803,13 @@ public: else if (Struct == RotatorStruct) { FRotator R = FRotator::ZeroRotator; - const bool bParsedUsingCustomFormat = FDefaultValueHelper::ParseRotator(Term->Name, /*out*/ R); - if (!bParsedUsingCustomFormat) + if (!Term->Name.IsEmpty()) { - Struct->ImportText(*Term->Name, &R, nullptr, PPF_None, GWarn, GetPathNameSafe(StructProperty)); + const bool bParsedUsingCustomFormat = FDefaultValueHelper::ParseRotator(Term->Name, /*out*/ R); + if (!bParsedUsingCustomFormat) + { + Struct->ImportText(*Term->Name, &R, nullptr, PPF_None, GWarn, GetPathNameSafe(StructProperty)); + } } Writer << EX_RotationConst; Writer << R; @@ -872,7 +879,7 @@ public: Writer << EX_EndStructConst; } } - else if (auto ArrayPropr = Cast(CoerceProperty)) + else if (UArrayProperty* ArrayPropr = Cast(CoerceProperty)) { UProperty* InnerProp = ArrayPropr->Inner; ensure(InnerProp); @@ -887,26 +894,67 @@ public: Writer << ElementNum; for (int32 ElemIdx = 0; ElemIdx < ElementNum; ++ElemIdx) { - FBPTerminal NewTerm; - Schema->ConvertPropertyToPinType(InnerProp, NewTerm.Type); - NewTerm.bIsLiteral = true; - NewTerm.Source = Term->Source; - NewTerm.SourcePin = Term->SourcePin; uint8* RawElemData = ScriptArrayHelper.GetRawPtr(ElemIdx); - InnerProp->ExportText_Direct(NewTerm.Name, RawElemData, RawElemData, NULL, PPF_None); - if (InnerProp->IsA(UTextProperty::StaticClass())) - { - NewTerm.TextLiteral = Cast(InnerProp)->GetPropertyValue(RawElemData); - NewTerm.Name = NewTerm.TextLiteral.ToString(); - } - else if (InnerProp->IsA(UObjectPropertyBase::StaticClass())) - { - NewTerm.ObjectLiteral = Cast(InnerProp)->GetObjectPropertyValue(RawElemData); - } - EmitTermExpr(&NewTerm, InnerProp); + EmitInnerElementExpr(Term, InnerProp, RawElemData); } Writer << EX_EndArrayConst; } + else if (USetProperty* SetPropr = Cast(CoerceProperty)) + { + UProperty* InnerProp = SetPropr->ElementProp; + ensure(InnerProp); + + FScriptSet ScriptSet; + SetPropr->ImportText(*Term->Name, &ScriptSet, 0, NULL, GLog); + int32 ElementNum = ScriptSet.Num(); + + FScriptSetHelper ScriptSetHelper(SetPropr, &ScriptSet); + + Writer << EX_SetConst; + Writer << InnerProp; + Writer << ElementNum; + + for (int32 ElemIdx = 0, SparseIndex = 0; ElemIdx < ElementNum; ++SparseIndex) + { + if (ScriptSet.IsValidIndex(SparseIndex)) + { + uint8* RawElemData = ScriptSetHelper.GetElementPtr(SparseIndex); + EmitInnerElementExpr(Term, InnerProp, RawElemData); + + ++ElemIdx; + } + } + Writer << EX_EndSetConst; + } + else if (UMapProperty* MapPropr = Cast(CoerceProperty)) + { + UProperty* KeyProp = MapPropr->KeyProp; + UProperty* ValProp = MapPropr->ValueProp; + ensure(KeyProp && ValProp); + + FScriptMap ScriptMap; + MapPropr->ImportText(*Term->Name, &ScriptMap, 0, NULL, GLog); + int32 ElementNum = ScriptMap.Num(); + + FScriptMapHelper ScriptMapHelper(MapPropr, &ScriptMap); + + Writer << EX_MapConst; + Writer << KeyProp; + Writer << ValProp; + Writer << ElementNum; + + for (int32 ElemIdx = 0, SparseIndex = 0; ElemIdx < ElementNum; ++SparseIndex) + { + if (ScriptMap.IsValidIndex(SparseIndex)) + { + EmitInnerElementExpr(Term, KeyProp, ScriptMapHelper.GetKeyPtr(SparseIndex)); + EmitInnerElementExpr(Term, ValProp, ScriptMapHelper.GetValuePtr(SparseIndex)); + + ++ElemIdx; + } + } + Writer << EX_EndMapConst; + } else if (FLiteralTypeHelper::IsDelegate(&Term->Type, CoerceProperty)) { if (Term->Name == TEXT("")) @@ -924,8 +972,7 @@ public: else if (FLiteralTypeHelper::IsAsset(&Term->Type, CoerceProperty)) { Writer << EX_AssetConst; - FAssetPtr AssetPtr(Term->ObjectLiteral); - EmitStringLiteral(AssetPtr.GetUniqueID().ToString()); + EmitStringLiteral(Term->Name); } else if (FLiteralTypeHelper::IsObject(&Term->Type, CoerceProperty) || FLiteralTypeHelper::IsClass(&Term->Type, CoerceProperty)) { @@ -995,6 +1042,28 @@ public: } } + void EmitInnerElementExpr(FBPTerminal* OuterTerm, UProperty* InnerProp, uint8* RawElemPtr) + { + FBPTerminal NewTerm; + Schema->ConvertPropertyToPinType(InnerProp, NewTerm.Type); + NewTerm.bIsLiteral = true; + NewTerm.Source = OuterTerm->Source; + NewTerm.SourcePin = OuterTerm->SourcePin; + + InnerProp->ExportText_Direct(NewTerm.Name, RawElemPtr, RawElemPtr, NULL, PPF_None); + if (InnerProp->IsA(UTextProperty::StaticClass())) + { + NewTerm.TextLiteral = Cast(InnerProp)->GetPropertyValue(RawElemPtr); + NewTerm.Name = NewTerm.TextLiteral.ToString(); + } + else if (InnerProp->IsA(UObjectPropertyBase::StaticClass())) + { + NewTerm.ObjectLiteral = Cast(InnerProp)->GetObjectPropertyValue(RawElemPtr); + } + + EmitTermExpr(&NewTerm, InnerProp); + } + void EmitLatentInfoTerm(FBPTerminal* Term, UProperty* LatentInfoProperty, FBlueprintCompiledStatement* TargetLabel) { // Special case of the struct property emitter. Needs to emit a linkage property for fixup @@ -1163,25 +1232,7 @@ public: Writer << FunctionName; } - TArray WildcardParams; const bool bIsCustomThunk = FunctionToCall->HasMetaData(TEXT("CustomThunk")); - if (bIsCustomThunk) - { - // collect all parameters that (should) have wildcard type. - auto CollectWildcards = [&](FName MetaDataName) - { - const FString DependentPinMetaData = FunctionToCall->GetMetaData(MetaDataName); - TArray TypeDependentPinNames; - DependentPinMetaData.ParseIntoArray(TypeDependentPinNames, TEXT(","), true); - for (FString& Iter : TypeDependentPinNames) - { - WildcardParams.Add(FName(*Iter)); - } - }; - CollectWildcards(FBlueprintMetadata::MD_ArrayDependentParam); - CollectWildcards(FName(TEXT("CustomStructureParam"))); - } - // Emit function parameters int32 NumParams = 0; for (TFieldIterator PropIt(FunctionToCall); PropIt && (PropIt->PropertyFlags & CPF_Parm); ++PropIt) @@ -1200,10 +1251,10 @@ public: } else { - const bool bWildcard = WildcardParams.Contains(FuncParamProperty->GetFName()); // Native type of a wildcard parameter should be ignored. + const bool bBadCoerceProperty = bIsCustomThunk && !Term->Type.IsContainer() && UEdGraphSchema_K2::IsWildcardProperty(FuncParamProperty); // When no coerce property is passed, a type of literal will be retrieved from the term. - EmitTerm(Term, bWildcard ? nullptr : FuncParamProperty); + EmitTerm(Term, bBadCoerceProperty ? nullptr : FuncParamProperty); } NumParams++; } @@ -1295,7 +1346,7 @@ public: { check(Schema && DestinationExpression && !DestinationExpression->Type.PinCategory.IsEmpty()); - const bool bIsContainer = DestinationExpression->Type.bIsArray || DestinationExpression->Type.bIsSet || DestinationExpression->Type.bIsMap; + const bool bIsContainer = DestinationExpression->Type.IsContainer(); const bool bIsDelegate = Schema->PC_Delegate == DestinationExpression->Type.PinCategory; const bool bIsMulticastDelegate = Schema->PC_MCDelegate == DestinationExpression->Type.PinCategory; const bool bIsBoolean = Schema->PC_Boolean == DestinationExpression->Type.PinCategory; @@ -1335,9 +1386,7 @@ public: else { Writer << EX_Let; - ensure(DestinationExpression->AssociatedVarProperty); Writer << DestinationExpression->AssociatedVarProperty; - } EmitTerm(DestinationExpression); } @@ -1771,7 +1820,7 @@ public: { CodeSkipSizeType PatchUpNeededAtOffset = Writer.EmitPlaceholderSkip(); FCodeSkipInfo CodeSkipInfo(FCodeSkipInfo::InstrumentedDelegateFixup, Statement.TargetLabel->TargetLabel, &Statement); - if (Statement.TargetLabel && Statement.TargetLabel->FunctionToCall) + if (Statement.TargetLabel->FunctionToCall) { CodeSkipInfo.DelegateName = Statement.TargetLabel->FunctionToCall->GetFName(); } diff --git a/Engine/Source/Editor/KismetCompiler/Public/BlueprintCompilerCppBackendInterface.h b/Engine/Source/Editor/KismetCompiler/Public/BlueprintCompilerCppBackendInterface.h index 909eec874ac4..30c478bef7bf 100644 --- a/Engine/Source/Editor/KismetCompiler/Public/BlueprintCompilerCppBackendInterface.h +++ b/Engine/Source/Editor/KismetCompiler/Public/BlueprintCompilerCppBackendInterface.h @@ -15,8 +15,8 @@ class IBlueprintCompilerCppBackend { public: virtual FString GenerateCodeFromClass(UClass* SourceClass, TIndirectArray& Functions, bool bGenerateStubsOnly, const FCompilerNativizationOptions& NativizationOptions, FString& OutCppBody) = 0; - virtual void GenerateCodeFromEnum(UUserDefinedEnum* SourceEnum, FString& OutHeaderCode, FString& OutCPPCode) = 0; - virtual FString GenerateCodeFromStruct(UUserDefinedStruct* SourceStruct, const FCompilerNativizationOptions& NativizationOptions) = 0; + virtual void GenerateCodeFromEnum(UUserDefinedEnum* SourceEnum, const FCompilerNativizationOptions& NativizationOptions, FString& OutHeaderCode, FString& OutCPPCode) = 0; + virtual void GenerateCodeFromStruct(UUserDefinedStruct* SourceStruct, const FCompilerNativizationOptions& NativizationOptions, FString& OutHeaderCode, FString& OutCPPCode) = 0; // Generate a wrapper class, that helps accessing non-native properties and calling non-native functions virtual FString GenerateWrapperForClass(UClass* SourceClass, const FCompilerNativizationOptions& NativizationOptions) = 0; diff --git a/Engine/Source/Editor/KismetCompiler/Public/KismetCompiledFunctionContext.h b/Engine/Source/Editor/KismetCompiler/Public/KismetCompiledFunctionContext.h index 426144a276ff..e0eb0ceafba8 100644 --- a/Engine/Source/Editor/KismetCompiler/Public/KismetCompiledFunctionContext.h +++ b/Engine/Source/Editor/KismetCompiler/Public/KismetCompiledFunctionContext.h @@ -54,7 +54,7 @@ public: TArray LinearExecutionList; FCompilerResultsLog& MessageLog; - UEdGraphSchema_K2* Schema; + const UEdGraphSchema_K2* Schema; // An UNORDERED listing of all statements (used for cleaning up the dynamically allocated statements) TArray< FBlueprintCompiledStatement* > AllGeneratedStatements; @@ -105,7 +105,7 @@ public: //Does this function use requires FlowStack ? bool bUseFlowStack; public: - FKismetFunctionContext(FCompilerResultsLog& InMessageLog, UEdGraphSchema_K2* InSchema, UBlueprintGeneratedClass* InNewClass, UBlueprint* InBlueprint, bool bInGeneratingCpp, bool bInWantsInstrumentation); + FKismetFunctionContext(FCompilerResultsLog& InMessageLog, const UEdGraphSchema_K2* InSchema, UBlueprintGeneratedClass* InNewClass, UBlueprint* InBlueprint, bool bInGeneratingCpp, bool bInWantsInstrumentation); ~FKismetFunctionContext(); diff --git a/Engine/Source/Editor/KismetCompiler/Public/KismetCompiler.h b/Engine/Source/Editor/KismetCompiler/Public/KismetCompiler.h index 591f722541cc..6888956337d0 100644 --- a/Engine/Source/Editor/KismetCompiler/Public/KismetCompiler.h +++ b/Engine/Source/Editor/KismetCompiler/Public/KismetCompiler.h @@ -30,6 +30,8 @@ enum class EInternalCompilerFlags None = 0x0, PostponeLocalsGenerationUntilPhaseTwo = 0x1, + PostponeDefaultObjectAssignmentUntilReinstancing = 0x2, + SkipRefreshExternalBlueprintDependencyNodes = 0x4, }; ENUM_CLASS_FLAGS(EInternalCompilerFlags) @@ -151,7 +153,7 @@ public: ParentGraph = SourceNode->GetGraph(); } - NodeType* Result = ParentGraph->CreateBlankNode(); + NodeType* Result = ParentGraph->CreateIntermediateNode(); //check (Cast(Result) == nullptr); -- Removed to avoid any fallout, will replace with care later MessageLog.NotifyIntermediateObjectCreation(Result, SourceNode); // this might be useful to track back function entry nodes to events. Result->CreateNewGuid(); @@ -165,12 +167,12 @@ public: template NodeType* SpawnIntermediateEventNode(UEdGraphNode* SourceNode, UEdGraphPin* SourcePin = nullptr, UEdGraph* ParentGraph = nullptr) { - if (ParentGraph == nullptr) + if (ParentGraph == nullptr && SourceNode != nullptr) { ParentGraph = SourceNode->GetGraph(); } - NodeType* Result = ParentGraph->CreateBlankNode(); + NodeType* Result = ParentGraph->CreateIntermediateNode(); //check (Cast(Result) != nullptr); -- Removed to avoid any fallout, will replace with care later MessageLog.NotifyIntermediateObjectCreation(Result, SourceNode); // this might be useful to track back function entry nodes to events. Result->CreateNewGuid(); @@ -216,13 +218,16 @@ public: */ FPinConnectionResponse CopyPinLinksToIntermediate(UEdGraphPin& SourcePin, UEdGraphPin& IntermediatePin); - UK2Node_TemporaryVariable* SpawnInternalVariable(UEdGraphNode* SourceNode, FString Category, FString SubCategory = TEXT(""), UObject* SubcategoryObject = NULL, bool bIsArray = false, bool bIsSet = false, bool bIsMap = false, const FEdGraphTerminalType& ValueTerminalType = FEdGraphTerminalType()); + DEPRECATED(4.17, "Use version that takes PinContainerType instead of separate booleans for array, set, and map") + UK2Node_TemporaryVariable* SpawnInternalVariable(UEdGraphNode* SourceNode, FString Category, FString SubCategory, UObject* SubcategoryObject, bool bIsArray, bool bIsSet = false, bool bIsMap = false, const FEdGraphTerminalType& ValueTerminalType = FEdGraphTerminalType()); + + UK2Node_TemporaryVariable* SpawnInternalVariable(UEdGraphNode* SourceNode, FString Category, FString SubCategory = FString(), UObject* SubcategoryObject = nullptr, EPinContainerType PinContainerType = EPinContainerType::None, const FEdGraphTerminalType& ValueTerminalType = FEdGraphTerminalType()); bool UsePersistentUberGraphFrame() const; FString GetGuid(const UEdGraphNode* Node) const; - static TUniquePtr GetCompilerForBP(UBlueprint* BP, FCompilerResultsLog& InMessageLog, const FKismetCompilerOptions& InCompileOptions); + static TSharedPtr GetCompilerForBP(UBlueprint* BP, FCompilerResultsLog& InMessageLog, const FKismetCompilerOptions& InCompileOptions); /** Ensures that all variables have valid names for compilation/replication */ void ValidateVariableNames(); @@ -332,12 +337,18 @@ protected: /** Creates user defined local variables for function */ void CreateUserDefinedLocalVariablesForFunction(FKismetFunctionContext& Context, UField**& FunctionPropertyStorageLocation); + /** Helper function for CreateUserDefinedLocalVariablesForFunction and compilation manager's FastGenerateSkeletonClass: */ + static UProperty* CreateUserDefinedLocalVariableForFunction(const FBPVariableDescription& Variable, UFunction* Function, UBlueprintGeneratedClass* OwningClass, UField**& FunctionPropertyStorageLocation, const UEdGraphSchema_K2* Schema, FCompilerResultsLog& MessageLog); + /** Adds a default value entry into the DefaultPropertyValueMap for the property specified */ void SetPropertyDefaultValue(const UProperty* PropertyToSet, FString& Value); /** Copies default values cached for the terms in the DefaultPropertyValueMap to the final CDO */ virtual void CopyTermDefaultsToDefaultObject(UObject* DefaultObject); + /** Non virtual wrapper to encapsulate functions that occur when the CDO is ready for values: */ + void PropagateValuesToCDO(UObject* NewCDO, UObject* OldCDO); + /** * Function works only if subclass of AActor or UActorComponent. * If ReceiveTick event is defined, force CanEverTick. @@ -428,6 +439,8 @@ protected: */ void FinishCompilingFunction(FKismetFunctionContext& Context); + static void SetCalculatedMetaDataAndFlags(UFunction* Function, UK2Node_FunctionEntry* EntryNode, const UEdGraphSchema_K2* Schema ); + /** * Handles adding the implemented interface information to the class */ diff --git a/Engine/Source/Editor/KismetCompiler/Public/KismetCompilerModule.h b/Engine/Source/Editor/KismetCompiler/Public/KismetCompilerModule.h index e954c42c4234..0e6ab2ac880b 100644 --- a/Engine/Source/Editor/KismetCompiler/Public/KismetCompilerModule.h +++ b/Engine/Source/Editor/KismetCompiler/Public/KismetCompilerModule.h @@ -100,8 +100,8 @@ public: */ virtual void GetBlueprintTypesForClass(UClass* ParentClass, UClass*& OutBlueprintClass, UClass*& OutBlueprintGeneratedClass) const = 0; - virtual void GenerateCppCodeForEnum(UUserDefinedEnum* UDEnum, FString& OutHeaderCode, FString& OutCPPCode) = 0; - virtual FString GenerateCppCodeForStruct(UUserDefinedStruct* UDStruct, const FCompilerNativizationOptions& NativizationOptions) = 0; + virtual void GenerateCppCodeForEnum(UUserDefinedEnum* UDEnum, const FCompilerNativizationOptions& NativizationOptions, FString& OutHeaderCode, FString& OutCPPCode) = 0; + virtual void GenerateCppCodeForStruct(UUserDefinedStruct* UDStruct, const FCompilerNativizationOptions& NativizationOptions, FString& OutHeaderCode, FString& OutCPPCode) = 0; // Generate a wrapper class, that helps accessing non-native properties and calling non-native functions virtual FString GenerateCppWrapper(UBlueprintGeneratedClass* BPGC, const FCompilerNativizationOptions& NativizationOptions) = 0; }; diff --git a/Engine/Source/Editor/KismetWidgets/Private/CreateBlueprintFromActorDialog.cpp b/Engine/Source/Editor/KismetWidgets/Private/CreateBlueprintFromActorDialog.cpp index e7297f4c56ae..192d7bbfc834 100644 --- a/Engine/Source/Editor/KismetWidgets/Private/CreateBlueprintFromActorDialog.cpp +++ b/Engine/Source/Editor/KismetWidgets/Private/CreateBlueprintFromActorDialog.cpp @@ -17,7 +17,7 @@ #define LOCTEXT_NAMESPACE "CreateBlueprintFromActorDialog" -TWeakObjectPtr FCreateBlueprintFromActorDialog::ActorOverride; +TWeakObjectPtr FCreateBlueprintFromActorDialog::ActorOverride = nullptr; void FCreateBlueprintFromActorDialog::OpenDialog(bool bInHarvest, AActor* InActorOverride ) { diff --git a/Engine/Source/Editor/KismetWidgets/Private/SPinTypeSelector.cpp b/Engine/Source/Editor/KismetWidgets/Private/SPinTypeSelector.cpp index d98f354fc7b0..7fdf8a2ee232 100644 --- a/Engine/Source/Editor/KismetWidgets/Private/SPinTypeSelector.cpp +++ b/Engine/Source/Editor/KismetWidgets/Private/SPinTypeSelector.cpp @@ -131,14 +131,6 @@ private: TWeakPtr SubMenuHandler; }; -enum class EPinContainerType -{ - SingleValue, - Array, - Set, - Map, -}; - static bool ContainerRequiresGetTypeHash(EPinContainerType InType) { return InType == EPinContainerType::Set || InType == EPinContainerType::Map; @@ -234,7 +226,7 @@ void SPinTypeSelector::Construct(const FArguments& InArgs, FGetPinTypeTree GetPi static TArray> PinTypes; if (PinTypes.Num() == 0) { - PinTypes.Add(MakeShareable(new EPinContainerType(EPinContainerType::SingleValue))); + PinTypes.Add(MakeShareable(new EPinContainerType(EPinContainerType::None))); PinTypes.Add(MakeShareable(new EPinContainerType(EPinContainerType::Array))); PinTypes.Add(MakeShareable(new EPinContainerType(EPinContainerType::Set))); PinTypes.Add(MakeShareable(new EPinContainerType(EPinContainerType::Map))); @@ -301,6 +293,7 @@ void SPinTypeSelector::Construct(const FArguments& InArgs, FGetPinTypeTree GetPi TSharedPtr ContainerControl = SNew(SComboButton) .ButtonStyle(FCoreStyle::Get(), "NoBorder") .HasDownArrow(false) + .MenuPlacement(EMenuPlacement::MenuPlacement_ComboBoxRight) .OnGetMenuContent( FOnGetContent::CreateLambda( [this]() @@ -372,6 +365,7 @@ void SPinTypeSelector::Construct(const FArguments& InArgs, FGetPinTypeTree GetPi .WidthOverride(100.f) [ SAssignNew( TypeComboButton, SComboButton ) + .MenuPlacement(EMenuPlacement::MenuPlacement_ComboBoxRight) .OnGetMenuContent(this, &SPinTypeSelector::GetMenuContent, false) .ContentPadding(0) .ToolTipText(this, &SPinTypeSelector::GetToolTipForComboBoxType) @@ -419,12 +413,12 @@ void SPinTypeSelector::Construct(const FArguments& InArgs, FGetPinTypeTree GetPi .Visibility( TAttribute::Create( TAttribute::FGetter::CreateLambda( - [this]() {return this->TargetPinType.Get().bIsMap == true ? EVisibility::Visible : EVisibility::Collapsed; } + [this]() {return this->TargetPinType.Get().IsMap() == true ? EVisibility::Visible : EVisibility::Collapsed; } ) ) ) [ - SNew( SComboButton ) + SAssignNew( SecondaryTypeComboButton, SComboButton ) .OnGetMenuContent(this, &SPinTypeSelector::GetMenuContent, true ) .ContentPadding(0) .ToolTipText(this, &SPinTypeSelector::GetToolTipForComboBoxSecondaryType) @@ -521,16 +515,13 @@ FSlateColor SPinTypeSelector::GetSecondaryTypeIconColor() const ECheckBoxState SPinTypeSelector::IsArrayChecked() const { - return TargetPinType.Get().bIsArray ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; + return TargetPinType.Get().IsArray() ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; } void SPinTypeSelector::OnArrayCheckStateChanged(ECheckBoxState NewState) { FEdGraphPinType NewTargetPinType = TargetPinType.Get(); - NewTargetPinType.bIsArray = (NewState == ECheckBoxState::Checked) ? true : false; - // just in case someone has been experimenting with experimental features: - NewTargetPinType.bIsMap = false; - NewTargetPinType.bIsSet = false; + NewTargetPinType.ContainerType = (NewState == ECheckBoxState::Checked) ? EPinContainerType::Array : EPinContainerType::None; OnTypeChanged.ExecuteIfBound(NewTargetPinType); } @@ -543,30 +534,7 @@ void SPinTypeSelector::OnArrayStateToggled() void SPinTypeSelector::OnContainerTypeSelectionChanged( EPinContainerType PinContainerType) { FEdGraphPinType NewTargetPinType = TargetPinType.Get(); - - switch (PinContainerType) - { - case EPinContainerType::SingleValue: - NewTargetPinType.bIsArray = false; - NewTargetPinType.bIsMap = false; - NewTargetPinType.bIsSet = false; - break; - case EPinContainerType::Array: - NewTargetPinType.bIsArray = true; - NewTargetPinType.bIsMap = false; - NewTargetPinType.bIsSet = false; - break; - case EPinContainerType::Set: - NewTargetPinType.bIsArray = false; - NewTargetPinType.bIsMap = false; - NewTargetPinType.bIsSet = true; - break; - case EPinContainerType::Map: - NewTargetPinType.bIsArray = false; - NewTargetPinType.bIsMap = true; - NewTargetPinType.bIsSet = false; - break; - } + NewTargetPinType.ContainerType = PinContainerType; OnTypeChanged.ExecuteIfBound(NewTargetPinType); } @@ -817,26 +785,27 @@ void SPinTypeSelector::OnSelectPinType(FPinTypeTreeItem InItem, FString InPinCat TypeComboButton->SetIsOpen(false); + if (SecondaryTypeComboButton.IsValid()) + { + SecondaryTypeComboButton->SetIsOpen(false); + } if( NewTargetPinType.PinCategory == Schema->PC_Exec ) { - NewTargetPinType.bIsMap = false; - NewTargetPinType.bIsSet = false; - NewTargetPinType.bIsArray = false; + NewTargetPinType.ContainerType = EPinContainerType::None; NewTargetPinType.PinValueType.TerminalCategory = FString(); NewTargetPinType.PinValueType.TerminalSubCategory = FString(); NewTargetPinType.PinValueType.TerminalSubCategoryObject = nullptr; } - if ((NewTargetPinType.bIsMap || NewTargetPinType.bIsSet) && !FBlueprintEditorUtils::HasGetTypeHash(NewTargetPinType)) + if ((NewTargetPinType.IsMap() || NewTargetPinType.IsSet()) && !FBlueprintEditorUtils::HasGetTypeHash(NewTargetPinType)) { FEdGraphPinType HashedType = NewTargetPinType; // clear the container-ness for messaging, we want to explain that the contained type is not hashable, // not message about the container type (e.g. "Container type cleared because 'bool' does not have a GetTypeHash..." // instead of "Container Type cleared because 'map of bool to float'..."). We also need to clear this because // the type cannot be a container: - NewTargetPinType.bIsMap = false; - NewTargetPinType.bIsSet = false; + NewTargetPinType.ContainerType = EPinContainerType::None; // inform user via toast why the type change was exceptional and clear IsMap/IsSetness because this type cannot be hashed: const FText NotificationText = FText::Format(LOCTEXT("TypeCannotBeHashed", "Container type cleared because '{0}' does not have a GetTypeHash function. Maps and Sets require a hash function to insert and find elements"), UEdGraphSchema_K2::TypeToText(NewTargetPinType)); @@ -965,6 +934,10 @@ TSharedRef SPinTypeSelector::GetMenuContent(bool bForSecondaryType) TypeComboButton->SetMenuContentWidgetToFocus(FilterTextBox); + if (SecondaryTypeComboButton.IsValid()) + { + SecondaryTypeComboButton->SetMenuContentWidgetToFocus(FilterTextBox); + } } else { diff --git a/Engine/Source/Editor/KismetWidgets/Public/CreateBlueprintFromActorDialog.h b/Engine/Source/Editor/KismetWidgets/Public/CreateBlueprintFromActorDialog.h index 612445c90545..b81414ba566d 100644 --- a/Engine/Source/Editor/KismetWidgets/Public/CreateBlueprintFromActorDialog.h +++ b/Engine/Source/Editor/KismetWidgets/Public/CreateBlueprintFromActorDialog.h @@ -3,8 +3,7 @@ #pragma once #include "CoreMinimal.h" - -class AActor; +#include "GameFramework/Actor.h" ////////////////////////////////////////////////////////////////////////// // FCreateBlueprintFromActorDialog diff --git a/Engine/Source/Editor/KismetWidgets/Public/SPinTypeSelector.h b/Engine/Source/Editor/KismetWidgets/Public/SPinTypeSelector.h index 70264b00f010..7c197c567021 100644 --- a/Engine/Source/Editor/KismetWidgets/Public/SPinTypeSelector.h +++ b/Engine/Source/Editor/KismetWidgets/Public/SPinTypeSelector.h @@ -48,7 +48,7 @@ public: SLATE_BEGIN_ARGS( SPinTypeSelector ) : _TargetPinType() - , _Schema(NULL) + , _Schema(nullptr) , _TypeTreeFilter(ETypeTreeFilter::None) , _bAllowArrays(true) , _TreeViewWidth(300.f) @@ -96,6 +96,7 @@ protected: FText GetSecondaryTypeDescription() const; TSharedPtr TypeComboButton; + TSharedPtr SecondaryTypeComboButton; TSharedPtr FilterTextBox; TSharedPtr TypeTreeView; @@ -140,7 +141,7 @@ protected: void OnArrayStateToggled(); /** Updates the variable container type: */ - void OnContainerTypeSelectionChanged(enum class EPinContainerType PinContainerType); + void OnContainerTypeSelectionChanged(EPinContainerType PinContainerType); /** Array containing the unfiltered list of all supported types this pin could possibly have */ TArray TypeTreeRoot; diff --git a/Engine/Source/Editor/LandscapeEditor/Private/LandscapeEdMode.cpp b/Engine/Source/Editor/LandscapeEditor/Private/LandscapeEdMode.cpp index 3c2209b89410..54a2bdbe4d9d 100644 --- a/Engine/Source/Editor/LandscapeEditor/Private/LandscapeEdMode.cpp +++ b/Engine/Source/Editor/LandscapeEditor/Private/LandscapeEdMode.cpp @@ -529,10 +529,7 @@ void FEdModeLandscape::Exit() if (CurrentTool) { CurrentTool->PreviousBrushIndex = CurrentBrushSetIndex; - if (CurrentTool) - { - CurrentTool->ExitTool(); - } + CurrentTool->ExitTool(); } CurrentTool = NULL; // Leave CurrentToolIndex set so we can restore the active tool on re-opening the landscape editor @@ -927,11 +924,10 @@ bool FEdModeLandscape::LandscapeTrace(const FVector& InRayOrigin, const FVector& // Cache a copy of the world pointer UWorld* World = GetWorld(); - static FName TraceTag = FName(TEXT("LandscapeTrace")); TArray Results; // Each landscape component has 2 collision shapes, 1 of them is specific to landscape editor // Trace only ECC_Visibility channel, so we do hit only Editor specific shape - World->LineTraceMultiByObjectType(Results, Start, End, FCollisionObjectQueryParams(ECollisionChannel::ECC_Visibility), FCollisionQueryParams(TraceTag, true)); + World->LineTraceMultiByObjectType(Results, Start, End, FCollisionObjectQueryParams(ECollisionChannel::ECC_Visibility), FCollisionQueryParams(SCENE_QUERY_STAT(LandscapeTrace), true)); for (int32 i = 0; i < Results.Num(); i++) { @@ -1408,7 +1404,7 @@ bool FEdModeLandscape::InputKey(FEditorViewportClient* ViewportClient, FViewport // When debugging it's possible to miss the "mouse released" event, if we get a "mouse pressed" event when we think it's already pressed then treat it as release first if (ToolActiveViewport) { - CurrentTool->EndTool(ViewportClient); + CurrentTool->EndTool(ViewportClient); //-V595 Viewport->CaptureMouse(false); ToolActiveViewport = nullptr; } @@ -1735,10 +1731,7 @@ void FEdModeLandscape::SetCurrentTool(int32 ToolIndex) if (CurrentTool) { CurrentTool->PreviousBrushIndex = CurrentBrushSetIndex; - if (CurrentTool) - { - CurrentTool->ExitTool(); - } + CurrentTool->ExitTool(); } CurrentToolIndex = LandscapeTools.IsValidIndex(ToolIndex) ? ToolIndex : 0; CurrentTool = LandscapeTools[CurrentToolIndex].Get(); diff --git a/Engine/Source/Editor/LandscapeEditor/Private/LandscapeEdModeComponentTools.cpp b/Engine/Source/Editor/LandscapeEditor/Private/LandscapeEdModeComponentTools.cpp index 335aa6060004..af5270473dbf 100644 --- a/Engine/Source/Editor/LandscapeEditor/Private/LandscapeEdModeComponentTools.cpp +++ b/Engine/Source/Editor/LandscapeEditor/Private/LandscapeEdModeComponentTools.cpp @@ -446,7 +446,7 @@ public: if (FMessageDialog::Open(EAppMsgType::OkCancel, FText::Format( NSLOCTEXT("UnrealEd", "LandscapeMoveToStreamingLevel_SharedResources", "The following items must be moved out of the persistent level and into a package that can be shared between multiple levels:\n\n{0}"), - FText::FromString(MsgBoxList)))) + FText::FromString(MsgBoxList))) == EAppReturnType::Type::Ok) { FString Path = Landscape->GetOutermost()->GetName() + TEXT("_sharedassets/"); bool bSucceed = ObjectTools::RenameObjects(RenameObjects, false, TEXT(""), Path); diff --git a/Engine/Source/Editor/LandscapeEditor/Private/LandscapeEdModeSplineTools.cpp b/Engine/Source/Editor/LandscapeEditor/Private/LandscapeEdModeSplineTools.cpp index 174772c62bfc..00060f8c60e8 100644 --- a/Engine/Source/Editor/LandscapeEditor/Private/LandscapeEdModeSplineTools.cpp +++ b/Engine/Source/Editor/LandscapeEditor/Private/LandscapeEdModeSplineTools.cpp @@ -615,7 +615,7 @@ public: FHitResult Hit; UWorld* World = SplinesComponent->GetWorld(); check(World); - if (World->LineTraceSingleByObjectType(Hit, Start, End, FCollisionObjectQueryParams(ECC_WorldStatic), FCollisionQueryParams(NAME_None,true))) + if (World->LineTraceSingleByObjectType(Hit, Start, End, FCollisionObjectQueryParams(ECC_WorldStatic), FCollisionQueryParams(NAME_None, FCollisionQueryParams::GetUnknownStatId(),true))) { ControlPoint->Location = LocalToWorld.InverseTransformPosition(Hit.Location); ControlPoint->UpdateSplinePoints(); @@ -657,7 +657,7 @@ public: ToLandscape->SplineComponent->Modify(); const FTransform OldToNewTransform = - FromProxy->SplineComponent->ComponentToWorld.GetRelativeTransform(ToLandscape->SplineComponent->ComponentToWorld); + FromProxy->SplineComponent->GetComponentTransform().GetRelativeTransform(ToLandscape->SplineComponent->GetComponentTransform()); if (FromProxies.Find(FromProxy) == nullptr) { @@ -862,7 +862,7 @@ public: SplinesComponent = Landscape->SplineComponent; } - const FTransform LandscapeToSpline = Landscape->LandscapeActorToWorld().GetRelativeTransform(SplinesComponent->ComponentToWorld); + const FTransform LandscapeToSpline = Landscape->LandscapeActorToWorld().GetRelativeTransform(SplinesComponent->GetComponentTransform()); AddControlPoint(SplinesComponent, LandscapeToSpline.TransformPosition(InHitLocation)); @@ -1172,7 +1172,7 @@ public: ClickedSplineSegment = SplineProxy->SplineSegment; ALandscapeProxy* LandscapeProxy = ClickedSplineSegment->GetTypedOuter(); check(LandscapeProxy); - LandscapeToSpline = LandscapeProxy->LandscapeActorToWorld().GetRelativeTransform(ClickedSplineSegment->GetOuterULandscapeSplinesComponent()->ComponentToWorld); + LandscapeToSpline = LandscapeProxy->LandscapeActorToWorld().GetRelativeTransform(ClickedSplineSegment->GetOuterULandscapeSplinesComponent()->GetComponentTransform()); } else if (HitProxy->IsA(HActor::StaticGetType())) { @@ -1191,7 +1191,7 @@ public: { ClickedSplineSegment = SplineSegment; ALandscapeProxy* LandscapeProxy = CastChecked(SplineComponent->GetOwner()); - LandscapeToSpline = LandscapeProxy->LandscapeActorToWorld().GetRelativeTransform(SplineComponent->ComponentToWorld); + LandscapeToSpline = LandscapeProxy->LandscapeActorToWorld().GetRelativeTransform(SplineComponent->GetComponentTransform()); } } } @@ -1300,7 +1300,7 @@ public: Connection.ControlPoint->GetConnectionLocationAndRotation(Connection.SocketName, StartLocation, StartRotation); float OldTangentLen = Connection.TangentLen; - Connection.TangentLen += SplinesComponent->ComponentToWorld.InverseTransformVector(-Drag) | StartRotation.Vector(); + Connection.TangentLen += SplinesComponent->GetComponentTransform().InverseTransformVector(-Drag) | StartRotation.Vector(); // Disallow a tangent of exactly 0 if (Connection.TangentLen == 0) @@ -1332,11 +1332,11 @@ public: { const ULandscapeSplinesComponent* SplinesComponent = ControlPoint->GetOuterULandscapeSplinesComponent(); - ControlPoint->Location += SplinesComponent->ComponentToWorld.InverseTransformVector(Drag); + ControlPoint->Location += SplinesComponent->GetComponentTransform().InverseTransformVector(Drag); FVector RotAxis; float RotAngle; InRot.Quaternion().ToAxisAndAngle(RotAxis, RotAngle); - RotAxis = (SplinesComponent->ComponentToWorld.GetRotation().Inverse() * ControlPoint->Rotation.Quaternion().Inverse()).RotateVector(RotAxis); + RotAxis = (SplinesComponent->GetComponentTransform().GetRotation().Inverse() * ControlPoint->Rotation.Quaternion().Inverse()).RotateVector(RotAxis); // Hack: for some reason FQuat.Rotator() Clamps to 0-360 range, so use .GetNormalized() to recover the original negative rotation. ControlPoint->Rotation += FQuat(RotAxis, RotAngle).Rotator().GetNormalized(); @@ -1450,8 +1450,8 @@ public: { const ULandscapeSplinesComponent* SplinesComponent = ControlPoint->GetOuterULandscapeSplinesComponent(); - FVector HandlePos0 = SplinesComponent->ComponentToWorld.TransformPosition(ControlPoint->Location + ControlPoint->Rotation.Vector() * -20); - FVector HandlePos1 = SplinesComponent->ComponentToWorld.TransformPosition(ControlPoint->Location + ControlPoint->Rotation.Vector() * 20); + FVector HandlePos0 = SplinesComponent->GetComponentTransform().TransformPosition(ControlPoint->Location + ControlPoint->Rotation.Vector() * -20); + FVector HandlePos1 = SplinesComponent->GetComponentTransform().TransformPosition(ControlPoint->Location + ControlPoint->Rotation.Vector() * 20); DrawDashedLine(PDI, HandlePos0, HandlePos1, FColor::White, 20, SDPG_Foreground); if (GLevelEditorModeTools().GetWidgetMode() == FWidget::WM_Scale) @@ -1461,8 +1461,8 @@ public: FVector StartLocation; FRotator StartRotation; Connection.GetNearConnection().ControlPoint->GetConnectionLocationAndRotation(Connection.GetNearConnection().SocketName, StartLocation, StartRotation); - FVector StartPos = SplinesComponent->ComponentToWorld.TransformPosition(StartLocation); - FVector HandlePos = SplinesComponent->ComponentToWorld.TransformPosition(StartLocation + StartRotation.Vector() * Connection.GetNearConnection().TangentLen / 2); + FVector StartPos = SplinesComponent->GetComponentTransform().TransformPosition(StartLocation); + FVector HandlePos = SplinesComponent->GetComponentTransform().TransformPosition(StartLocation + StartRotation.Vector() * Connection.GetNearConnection().TangentLen / 2); PDI->DrawLine(StartPos, HandlePos, FColor::White, SDPG_Foreground); if (PDI->IsHitTesting()) PDI->SetHitProxy(new HLandscapeSplineProxy_Tangent(Connection.Segment, Connection.End)); @@ -1484,8 +1484,8 @@ public: FVector StartLocation; FRotator StartRotation; Connection.ControlPoint->GetConnectionLocationAndRotation(Connection.SocketName, StartLocation, StartRotation); - FVector EndPos = SplinesComponent->ComponentToWorld.TransformPosition(StartLocation); - FVector EndHandlePos = SplinesComponent->ComponentToWorld.TransformPosition(StartLocation + StartRotation.Vector() * Connection.TangentLen / 2); + FVector EndPos = SplinesComponent->GetComponentTransform().TransformPosition(StartLocation); + FVector EndHandlePos = SplinesComponent->GetComponentTransform().TransformPosition(StartLocation + StartRotation.Vector() * Connection.TangentLen / 2); PDI->DrawLine(EndPos, EndHandlePos, FColor::White, SDPG_Foreground); if (PDI->IsHitTesting()) PDI->SetHitProxy(new HLandscapeSplineProxy_Tangent(Segment, !!End)); @@ -1560,7 +1560,7 @@ public: { ULandscapeSplineControlPoint* FirstPoint = *SelectedSplineControlPoints.CreateConstIterator(); ULandscapeSplinesComponent* SplinesComponent = FirstPoint->GetOuterULandscapeSplinesComponent(); - return SplinesComponent->ComponentToWorld.TransformPosition(FirstPoint->Location); + return SplinesComponent->GetComponentTransform().TransformPosition(FirstPoint->Location); } } @@ -1576,7 +1576,7 @@ public: { ULandscapeSplineControlPoint* FirstPoint = *SelectedSplineControlPoints.CreateConstIterator(); ULandscapeSplinesComponent* SplinesComponent = FirstPoint->GetOuterULandscapeSplinesComponent(); - return FQuatRotationTranslationMatrix(FirstPoint->Rotation.Quaternion() * SplinesComponent->ComponentToWorld.GetRotation(), FVector::ZeroVector); + return FQuatRotationTranslationMatrix(FirstPoint->Rotation.Quaternion() * SplinesComponent->GetComponentTransform().GetRotation(), FVector::ZeroVector); } } diff --git a/Engine/Source/Editor/LevelEditor/LevelEditor.Build.cs b/Engine/Source/Editor/LevelEditor/LevelEditor.Build.cs index 5dff8c7576f5..1cc225aa671b 100644 --- a/Engine/Source/Editor/LevelEditor/LevelEditor.Build.cs +++ b/Engine/Source/Editor/LevelEditor/LevelEditor.Build.cs @@ -37,37 +37,37 @@ public class LevelEditor : ModuleRules "Analytics", "Core", "CoreUObject", - "DesktopPlatform", - "InputCore", + "LauncherPlatform", + "InputCore", "Slate", "SlateCore", - "EditorStyle", + "EditorStyle", "Engine", "MessageLog", - "SourceControl", - "SourceControlWindows", - "StatsViewer", + "SourceControl", + "SourceControlWindows", + "StatsViewer", "UnrealEd", "RenderCore", "DeviceProfileServices", "ContentBrowser", - "SceneOutliner", - "ActorPickerMode", - "RHI", + "SceneOutliner", + "ActorPickerMode", + "RHI", "Projects", "TargetPlatform", "EngineSettings", "PropertyEditor", - "Persona", - "Kismet", + "Persona", + "Kismet", "KismetWidgets", "Sequencer", - "Foliage", - "HierarchicalLODOutliner", - "HierarchicalLODUtilities", + "Foliage", + "HierarchicalLODOutliner", + "HierarchicalLODUtilities", "MaterialShaderQualitySettings", - "PixelInspectorModule", - "FunctionalTesting" + "PixelInspectorModule", + "FunctionalTesting" } ); diff --git a/Engine/Source/Editor/LevelEditor/Private/LevelEditor.cpp b/Engine/Source/Editor/LevelEditor/Private/LevelEditor.cpp index 25009677823e..0c4e13e71683 100644 --- a/Engine/Source/Editor/LevelEditor/Private/LevelEditor.cpp +++ b/Engine/Source/Editor/LevelEditor/Private/LevelEditor.cpp @@ -171,6 +171,8 @@ TSharedRef FLevelEditorModule::SpawnLevelEditor( const FSpawnTabArgs& GLevelEditorModeTools().RemoveDefaultMode( FBuiltinEditorModes::EM_Default ); GLevelEditorModeTools().AddDefaultMode( FBuiltinEditorModes::EM_Placement ); GLevelEditorModeTools().DeactivateAllModes(); + GLevelEditorModeTools().ActivateDefaultMode(); + } IUserFeedbackModule& UserFeedback = FModuleManager::LoadModuleChecked(TEXT("UserFeedback")); @@ -617,7 +619,8 @@ void FLevelEditorModule::BindGlobalLevelEditorCommands() FCanExecuteAction::CreateStatic( &FLevelEditorActionCallbacks::ExportSelected_CanExecute ) ); ActionList.MapAction( Commands.Build, - FExecuteAction::CreateStatic( &FLevelEditorActionCallbacks::Build_Execute ) ); + FExecuteAction::CreateStatic( &FLevelEditorActionCallbacks::Build_Execute ), + FCanExecuteAction::CreateStatic( &FLevelEditorActionCallbacks::Build_CanExecute ) ); ActionList.MapAction( Commands.ConnectToSourceControl, diff --git a/Engine/Source/Editor/LevelEditor/Private/LevelEditorActions.cpp b/Engine/Source/Editor/LevelEditor/Private/LevelEditorActions.cpp index 15883176a80f..d40f4d86bae6 100644 --- a/Engine/Source/Editor/LevelEditor/Private/LevelEditorActions.cpp +++ b/Engine/Source/Editor/LevelEditor/Private/LevelEditorActions.cpp @@ -60,7 +60,6 @@ #include "AssetSelection.h" #include "IDocumentation.h" #include "SourceCodeNavigation.h" -#include "DesktopPlatformModule.h" #include "EngineAnalytics.h" #include "Interfaces/IAnalyticsProvider.h" #include "ReferenceViewer.h" @@ -87,6 +86,8 @@ #include "Engine/LevelStreaming.h" #include "Engine/LevelStreamingKismet.h" #include "EditorLevelUtils.h" +#include "ActorGroupingUtils.h" +#include "LevelUtils.h" DEFINE_LOG_CATEGORY_STATIC(LevelEditorActions, Log, All); @@ -421,10 +422,10 @@ void FLevelEditorActionCallbacks::SaveCurrentAs() FString PackageName; if (FPackageName::TryConvertFilenameToLongPackageName(SavedFilename, PackageName)) { - ULevel* Level = EditorLevelUtils::AddLevelToWorld(World, *PackageName, CurrentStreamingLevelClass); + ULevelStreaming* StreamingLevel = UEditorLevelUtils::AddLevelToWorld(World, *PackageName, CurrentStreamingLevelClass); // Make the level we just added current because the expectation is that the new level replaces the existing current level - EditorLevelUtils::MakeLevelCurrent(Level); + EditorLevelUtils::MakeLevelCurrent(StreamingLevel->GetLoadedLevel()); } FEditorDelegates::RefreshLevelBrowser.Broadcast(); @@ -629,6 +630,10 @@ void FLevelEditorActionCallbacks::Build_Execute() FEditorBuildUtils::EditorBuild( GetWorld(), FBuildOptions::BuildAll ); } +bool FLevelEditorActionCallbacks::Build_CanExecute() +{ + return !(GEditor->PlayWorld || GUnrealEd->bIsSimulatingInEditor); +} void FLevelEditorActionCallbacks::BuildAndSubmitToSourceControl_Execute() { @@ -651,7 +656,7 @@ bool FLevelEditorActionCallbacks::BuildLighting_CanExecute() { static const auto AllowStaticLightingVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.AllowStaticLighting")); const bool bAllowStaticLighting = (!AllowStaticLightingVar || AllowStaticLightingVar->GetValueOnGameThread() != 0); - return bAllowStaticLighting; + return bAllowStaticLighting && !(GEditor->PlayWorld || GUnrealEd->bIsSimulatingInEditor); } void FLevelEditorActionCallbacks::BuildReflectionCapturesOnly_Execute() @@ -1278,8 +1283,7 @@ void FLevelEditorActionCallbacks::GoHere_Clicked( const FVector* Point ) FHitResult HitResult; - static FName FocusOnPoint = FName(TEXT("FocusOnPoint")); - FCollisionQueryParams LineParams(FocusOnPoint, true); + FCollisionQueryParams LineParams(SCENE_QUERY_STAT(FocusOnPoint), true); if(GCurrentLevelEditingViewportClient->GetWorld()->LineTraceSingleByObjectType(HitResult, WorldOrigin, WorldOrigin + WorldDirection * HALF_WORLD_MAX, FCollisionObjectQueryParams(ECC_WorldStatic), LineParams)) { @@ -1654,9 +1658,11 @@ bool FLevelEditorActionCallbacks::Paste_CanExecute() bool bCanPaste = false; if (GEditor->GetSelectedComponentCount() > 0) { - check(GEditor->GetSelectedActorCount() == 1); - auto SelectedActor = CastChecked(*GEditor->GetSelectedActorIterator()); - bCanPaste = FComponentEditorUtils::CanPasteComponents(SelectedActor->GetRootComponent()); + if(ensureMsgf(GEditor->GetSelectedActorCount() == 1, TEXT("Expected SelectedActorCount to be 1 but was %d"), GEditor->GetSelectedActorCount())) + { + auto SelectedActor = CastChecked(*GEditor->GetSelectedActorIterator()); + bCanPaste = FComponentEditorUtils::CanPasteComponents(SelectedActor->GetRootComponent()); + } } else { @@ -1811,32 +1817,32 @@ void FLevelEditorActionCallbacks::OnSurfaceAlignment( ETexAlign AlignmentMode ) void FLevelEditorActionCallbacks::RegroupActor_Clicked() { - GUnrealEd->edactRegroupFromSelected(); + UActorGroupingUtils::Get()->GroupSelected(); } void FLevelEditorActionCallbacks::UngroupActor_Clicked() { - GUnrealEd->edactUngroupFromSelected(); + UActorGroupingUtils::Get()->UngroupSelected(); } void FLevelEditorActionCallbacks::LockGroup_Clicked() { - GUnrealEd->edactLockSelectedGroups(); + UActorGroupingUtils::Get()->LockSelectedGroups(); } void FLevelEditorActionCallbacks::UnlockGroup_Clicked() { - GUnrealEd->edactUnlockSelectedGroups(); + UActorGroupingUtils::Get()->UnlockSelectedGroups(); } void FLevelEditorActionCallbacks::AddActorsToGroup_Clicked() { - GUnrealEd->edactAddToGroup(); + UActorGroupingUtils::Get()->AddSelectedToGroup(); } void FLevelEditorActionCallbacks::RemoveActorsFromGroup_Clicked() { - GUnrealEd->edactRemoveFromGroup(); + UActorGroupingUtils::Get()->RemoveSelectedFromGroup(); } @@ -2059,7 +2065,7 @@ void FLevelEditorActionCallbacks::OnMakeSelectedActorLevelCurrent() void FLevelEditorActionCallbacks::OnMoveSelectedToCurrentLevel() { - GEditor->MoveSelectedActorsToLevel( GetWorld()->GetCurrentLevel() ); + UEditorLevelUtils::MoveSelectedActorsToLevel(GetWorld()->GetCurrentLevel()); } void FLevelEditorActionCallbacks::OnFindActorLevelInContentBrowser() @@ -2282,7 +2288,7 @@ void FLevelEditorActionCallbacks::OnAllowGroupSelection() bool FLevelEditorActionCallbacks::OnIsAllowGroupSelectionEnabled() { - return GUnrealEd->bGroupingActive; + return UActorGroupingUtils::IsGroupingActive(); } void FLevelEditorActionCallbacks::OnToggleStrictBoxSelect() @@ -2877,7 +2883,7 @@ void FLevelEditorActionCallbacks::SnapTo_Clicked( const bool InAlign, const bool { GEditor->SetPivot(Actor->GetActorLocation(), false, true); - if(GEditor->bGroupingActive) + if(UActorGroupingUtils::IsGroupingActive()) { // set group pivot for the root-most group AGroupActor* ActorGroupRoot = AGroupActor::GetRootForActor(Actor, true, true); @@ -2919,8 +2925,8 @@ void FLevelEditorCommands::RegisterCommands() UI_COMMAND( BrowseViewportControls, "Viewport Controls...", "Opens the viewport controls cheat sheet", EUserInterfaceActionType::Button, FInputChord() ); UI_COMMAND( NewLevel, "New Level...", "Create a new level, or choose a level template to start from.", EUserInterfaceActionType::Button, FInputChord( EModifierKey::Control, EKeys::N ) ); UI_COMMAND( OpenLevel, "Open Level...", "Loads an existing level", EUserInterfaceActionType::Button, FInputChord( EModifierKey::Control, EKeys::O ) ); - UI_COMMAND( Save, "Save Current", "Saves the current level to disk", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Control, EKeys::S) ); - UI_COMMAND( SaveAs, "Save Current As...", "Save the current level as...", EUserInterfaceActionType::Button, FInputChord( EModifierKey::Control|EModifierKey::Alt, EKeys::S ) ); + UI_COMMAND( Save, "Save", "Saves the current level to disk", EUserInterfaceActionType::Button, FInputChord() ); + UI_COMMAND( SaveAs, "Save As...", "Save the current level as...", EUserInterfaceActionType::Button, FInputChord( EModifierKey::Control|EModifierKey::Alt, EKeys::S ) ); UI_COMMAND( SaveAllLevels, "Save All Levels", "Saves all unsaved levels to disk", EUserInterfaceActionType::Button, FInputChord() ); UI_COMMAND( ToggleFavorite, "Toggle Favorite", "Sets whether the currently loaded level will appear in the list of favorite levels", EUserInterfaceActionType::Button, FInputChord() ); @@ -2951,7 +2957,7 @@ void FLevelEditorCommands::RegisterCommands() UI_COMMAND( LightingBuildOptions_UseErrorColoring, "Use Error Coloring", "When enabled, errors during lighting precomputation will be baked as colors into light map data", EUserInterfaceActionType::ToggleButton, FInputChord() ); UI_COMMAND( LightingBuildOptions_ShowLightingStats, "Show Lighting Stats", "When enabled, a window containing metrics about lighting performance and memory will be displayed after a successful build.", EUserInterfaceActionType::ToggleButton, FInputChord() ); UI_COMMAND( BuildGeometryOnly, "Build Geometry", "Only builds geometry (all levels.)", EUserInterfaceActionType::Button, FInputChord() ); - UI_COMMAND( BuildGeometryOnly_OnlyCurrentLevel, "Build Geometry (Current Level)", "Builds geometry, only for the current level", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Control | EModifierKey::Shift, EKeys::B) ); + UI_COMMAND( BuildGeometryOnly_OnlyCurrentLevel, "Build Geometry (Current Level)", "Builds geometry, only for the current level", EUserInterfaceActionType::Button, FInputChord() ); UI_COMMAND( BuildPathsOnly, "Build Paths", "Only builds paths (all levels.)", EUserInterfaceActionType::Button, FInputChord() ); UI_COMMAND( BuildLODsOnly, "Build LODs", "Only builds LODs (all levels.)", EUserInterfaceActionType::Button, FInputChord() ); UI_COMMAND( BuildTextureStreamingOnly, "Build Texture Streaming", "Build texture streaming data", EUserInterfaceActionType::Button, FInputChord() ); diff --git a/Engine/Source/Editor/LevelEditor/Private/LevelEditorContextMenu.cpp b/Engine/Source/Editor/LevelEditor/Private/LevelEditorContextMenu.cpp index 1871350ed755..7deb2dc80b93 100644 --- a/Engine/Source/Editor/LevelEditor/Private/LevelEditorContextMenu.cpp +++ b/Engine/Source/Editor/LevelEditor/Private/LevelEditorContextMenu.cpp @@ -46,6 +46,7 @@ #include "EditorClassUtils.h" #include "Framework/Commands/GenericCommands.h" #include "LevelViewportActions.h" +#include "ActorGroupingUtils.h" #define LOCTEXT_NAMESPACE "LevelViewportContextMenu" @@ -601,7 +602,7 @@ FSlateColor InvertOnHover( const TWeakPtr< SWidget > WidgetPtr ) void FLevelEditorContextMenu::BuildGroupMenu( FMenuBuilder& MenuBuilder, const FSelectedActorInfo& SelectedActorInfo ) { - if( GEditor->bGroupingActive ) + if( UActorGroupingUtils::IsGroupingActive() ) { // Whether or not we added a grouping sub-menu bool bNeedGroupSubMenu = SelectedActorInfo.bHaveSelectedLockedGroup || SelectedActorInfo.bHaveSelectedUnlockedGroup; diff --git a/Engine/Source/Editor/LevelEditor/Private/LevelEditorCreateActorMenu.cpp b/Engine/Source/Editor/LevelEditor/Private/LevelEditorCreateActorMenu.cpp index 15dc6acd377f..cbf1ea322b03 100644 --- a/Engine/Source/Editor/LevelEditor/Private/LevelEditorCreateActorMenu.cpp +++ b/Engine/Source/Editor/LevelEditor/Private/LevelEditorCreateActorMenu.cpp @@ -223,6 +223,8 @@ static void GetContentBrowserSelectionFactoryMenuEntries( FAssetData& TargetAsse TArray SelectedAssets; AssetSelectionUtils::GetSelectedAssets( SelectedAssets ); + bool bPlaceable = true; + if ( SelectedAssets.Num() > 0 ) { TargetAssetData = SelectedAssets.Top(); @@ -232,13 +234,43 @@ static void GetContentBrowserSelectionFactoryMenuEntries( FAssetData& TargetAsse { UClass* Class = Cast( TargetAssetData.GetAsset() ); - if ( !AssetSelectionUtils::IsClassPlaceable( Class ) ) + bPlaceable = AssetSelectionUtils::IsClassPlaceable( Class ); + } + else if ( TargetAssetData.GetClass() == UBlueprint::StaticClass() ) + { + // For blueprints, attempt to determine placeability from its tag information + + const FName NativeParentClassTag = TEXT("NativeParentClass"); + const FName ClassFlagsTag = TEXT("ClassFlags"); + + FString TagValue; + + if ( TargetAssetData.GetTagValue( NativeParentClassTag, TagValue ) && !TagValue.IsEmpty() ) { - return; + // If the native parent class can't be placed, neither can the blueprint + + UObject* Outer = nullptr; + ResolveName( Outer, TagValue, false, false ); + UClass* NativeParentClass = FindObject( ANY_PACKAGE, *TagValue ); + + bPlaceable = AssetSelectionUtils::IsClassPlaceable( NativeParentClass ); + } + + if ( bPlaceable && TargetAssetData.GetTagValue( ClassFlagsTag, TagValue ) && !TagValue.IsEmpty() ) + { + // Check to see if this class is placeable from its class flags + + const int32 NotPlaceableFlags = CLASS_NotPlaceable | CLASS_Deprecated | CLASS_Abstract; + uint32 ClassFlags = FCString::Atoi( *TagValue ); + + bPlaceable = ( ClassFlags & NotPlaceableFlags ) == CLASS_None; } } - FActorFactoryAssetProxy::GenerateActorFactoryMenuItems( TargetAssetData, &AssetMenuOptions, true ); + if ( bPlaceable ) + { + FActorFactoryAssetProxy::GenerateActorFactoryMenuItems( TargetAssetData, &AssetMenuOptions, true ); + } } diff --git a/Engine/Source/Editor/LevelEditor/Private/LevelEditorToolBar.cpp b/Engine/Source/Editor/LevelEditor/Private/LevelEditorToolBar.cpp index 80d107e22f88..ff010127eae8 100644 --- a/Engine/Source/Editor/LevelEditor/Private/LevelEditorToolBar.cpp +++ b/Engine/Source/Editor/LevelEditor/Private/LevelEditorToolBar.cpp @@ -43,7 +43,6 @@ #include "ISettingsContainer.h" #include "ISettingsModule.h" #include "ISettingsSection.h" -#include "DesktopPlatformModule.h" #include "ClassViewerModule.h" #include "ClassViewerFilter.h" #include "Kismet2/KismetEditorUtilities.h" @@ -54,6 +53,8 @@ #include "ScopedTransaction.h" #include "Features/EditorFeatures.h" #include "ConfigCacheIni.h" +#include "ILauncherPlatform.h" +#include "LauncherPlatformModule.h" namespace LevelEditorActionHelpers { @@ -315,9 +316,7 @@ namespace LevelEditorActionHelpers FText RootClassName = FText::FromString(InRootClass->GetName()); TSharedRef ClassViewer = FModuleManager::LoadModuleChecked("ClassViewer").CreateClassViewer(Options, InOnClassPicked); - FFormatNamedArguments FormatArgs; - FormatArgs.Add(TEXT("RootClass"), RootClassName); - InMenuBuilder.BeginSection(NAME_None, FText::Format( NSLOCTEXT("LevelToolBarViewMenu", "SelectGameModeLabel", "Select {RootClass} class"), FormatArgs )); + InMenuBuilder.BeginSection(NAME_None, FText::Format( NSLOCTEXT("LevelToolBarViewMenu", "SelectGameModeLabel", "Select {RootClass} class"), RootClassName )); InMenuBuilder.AddWidget(ClassViewer, FText::GetEmpty(), true); InMenuBuilder.EndSection(); } @@ -348,9 +347,7 @@ namespace LevelEditorActionHelpers FText RootClassName = FText::FromString(InRootClass->GetName()); TSharedRef ClassViewer = FModuleManager::LoadModuleChecked("ClassViewer").CreateClassViewer(Options, InOnClassPicked); - FFormatNamedArguments FormatArgs; - FormatArgs.Add(TEXT("RootClass"), RootClassName); - InMenuBuilder.BeginSection(NAME_None, FText::Format( NSLOCTEXT("LevelToolBarViewMenu", "CreateGameModeLabel", "Select {RootClass} parent class"), FormatArgs )); + InMenuBuilder.BeginSection(NAME_None, FText::Format( NSLOCTEXT("LevelToolBarViewMenu", "CreateGameModeLabel", "Select {RootClass} parent class"), RootClassName )); InMenuBuilder.AddWidget(ClassViewer, FText::GetEmpty(), true); InMenuBuilder.EndSection(); } @@ -703,7 +700,7 @@ void LevelEditorActionHelpers::GetBlueprintSettingsSubMenu(FMenuBuilder& InMenuB FNewMenuDelegate::CreateStatic( &LevelEditorActionHelpers::GetCreateSettingsClassSubMenu, InSettingsData.RootClass, InSettingsData.OnCreateClassPicked ), FUIAction( FExecuteAction(), - InSettingsData.RootClass == AGameModeBase::StaticClass()? + InSettingsData.RootClass == AGameModeBase::StaticClass()? FCanExecuteAction::CreateStatic(CannotCreateSelectNativeProjectGameMode, InSettingsData.bIsProjectSettings) : FCanExecuteAction::CreateStatic( &CanCreateSelectSubClass, GetGameModeClass(InSettingsData.LevelEditor, InSettingsData.bIsProjectSettings), InSettingsData.bIsProjectSettings ) ), @@ -711,9 +708,7 @@ void LevelEditorActionHelpers::GetBlueprintSettingsSubMenu(FMenuBuilder& InMenuB ); // Select a game mode, this is always available so the user can switch his selection - FFormatNamedArguments Args; - Args.Add(TEXT("RootClass"),RootClassName); - InMenuBuilder.AddSubMenu( FText::Format( LOCTEXT("SelectGameModeClass", "Select {RootClass} Class"), Args ), + InMenuBuilder.AddSubMenu( FText::Format( LOCTEXT("SelectGameModeClass", "Select {RootClass} Class"), RootClassName ), GetSelectMenuTooltip(GetGameModeClass(InSettingsData.LevelEditor, InSettingsData.bIsProjectSettings), InSettingsData.RootClass, InSettingsData.bIsProjectSettings), FNewMenuDelegate::CreateStatic( &LevelEditorActionHelpers::GetSelectSettingsClassSubMenu, InSettingsData.RootClass, InSettingsData.OnSelectClassPicked ), FUIAction( @@ -865,15 +860,12 @@ FText LevelEditorActionHelpers::GetOpenGameStateBlueprintLabel(TWeakPtr< SLevelE #define LOCTEXT_NAMESPACE "LevelToolBarViewMenu" if(UClass* GameStateClass = GetGameStateClass(InLevelEditor, bInIsProjectSettings)) { - FFormatNamedArguments FormatArgs; if(GameStateClass->ClassGeneratedBy) { - FormatArgs.Add(TEXT("GameStateName"), FText::FromString(GameStateClass->ClassGeneratedBy->GetName())); - return FText::Format( LOCTEXT("GameStateEditBlueprint", "GameState: Edit {GameStateName}"), FormatArgs); + return FText::Format( LOCTEXT("GameStateEditBlueprint", "GameState: Edit {GameStateName}"), FText::FromString(GameStateClass->ClassGeneratedBy->GetName())); } - FormatArgs.Add(TEXT("GameStateName"), FText::FromString(GameStateClass->GetName())); - return FText::Format( LOCTEXT("GameStateBlueprint", "GameState: {GameStateName}"), FormatArgs); + return FText::Format( LOCTEXT("GameStateBlueprint", "GameState: {GameStateName}"), FText::FromString(GameStateClass->GetName())); } return LOCTEXT("GameStateCreateBlueprint", "GameState: New..."); @@ -939,15 +931,12 @@ FText LevelEditorActionHelpers::GetOpenPawnBlueprintLabel(TWeakPtr< SLevelEditor #define LOCTEXT_NAMESPACE "LevelToolBarViewMenu" if(UClass* PawnClass = GetPawnClass(InLevelEditor, bInIsProjectSettings)) { - FFormatNamedArguments FormatArgs; if(PawnClass->ClassGeneratedBy) { - FormatArgs.Add(TEXT("PawnName"), FText::FromString(PawnClass->ClassGeneratedBy->GetName())); - return FText::Format( LOCTEXT("PawnEditBlueprint", "Pawn: Edit {PawnName}"), FormatArgs); + return FText::Format( LOCTEXT("PawnEditBlueprint", "Pawn: Edit {PawnName}"), FText::FromString(PawnClass->ClassGeneratedBy->GetName())); } - FormatArgs.Add(TEXT("PawnName"), FText::FromString(PawnClass->GetName())); - return FText::Format( LOCTEXT("PawnBlueprint", "Pawn: {PawnName}"), FormatArgs); + return FText::Format( LOCTEXT("PawnBlueprint", "Pawn: {PawnName}"), FText::FromString(PawnClass->GetName())); } return LOCTEXT("PawnCreateBlueprint", "Pawn: New..."); @@ -1013,15 +1002,12 @@ FText LevelEditorActionHelpers::GetOpenHUDBlueprintLabel(TWeakPtr< SLevelEditor #define LOCTEXT_NAMESPACE "LevelToolBarViewMenu" if(UClass* HUDClass = GetHUDClass(InLevelEditor, bInIsProjectSettings)) { - FFormatNamedArguments FormatArgs; if(HUDClass->ClassGeneratedBy) { - FormatArgs.Add(TEXT("HUDName"), FText::FromString(HUDClass->ClassGeneratedBy->GetName())); - return FText::Format( LOCTEXT("HUDEditBlueprint", "HUD: Edit {HUDName}"), FormatArgs); + return FText::Format( LOCTEXT("HUDEditBlueprint", "HUD: Edit {HUDName}"), FText::FromString(HUDClass->ClassGeneratedBy->GetName())); } - FormatArgs.Add(TEXT("HUDName"), FText::FromString(HUDClass->GetName())); - return FText::Format( LOCTEXT("HUDBlueprint", "HUD: {HUDName}"), FormatArgs); + return FText::Format( LOCTEXT("HUDBlueprint", "HUD: {HUDName}"), FText::FromString(HUDClass->GetName())); } return LOCTEXT("HUDCreateBlueprint", "HUD: New..."); @@ -1087,15 +1073,12 @@ FText LevelEditorActionHelpers::GetOpenPlayerControllerBlueprintLabel(TWeakPtr< #define LOCTEXT_NAMESPACE "LevelToolBarViewMenu" if(UClass* PlayerControllerClass = GetPlayerControllerClass(InLevelEditor, bInIsProjectSettings)) { - FFormatNamedArguments FormatArgs; if(PlayerControllerClass->ClassGeneratedBy) { - FormatArgs.Add(TEXT("PlayerControllerName"), FText::FromString(PlayerControllerClass->ClassGeneratedBy->GetName())); - return FText::Format( LOCTEXT("PlayerControllerEditBlueprint", "PlayerController: Edit {PlayerControllerName}"), FormatArgs); + return FText::Format( LOCTEXT("PlayerControllerEditBlueprint", "PlayerController: Edit {PlayerControllerName}"), FText::FromString(PlayerControllerClass->ClassGeneratedBy->GetName())); } - FormatArgs.Add(TEXT("PlayerControllerName"), FText::FromString(PlayerControllerClass->GetName())); - return FText::Format( LOCTEXT("PlayerControllerBlueprint", "PlayerController: {PlayerControllerName}"), FormatArgs); + return FText::Format( LOCTEXT("PlayerControllerBlueprint", "PlayerController: {PlayerControllerName}"), FText::FromString(PlayerControllerClass->GetName())); } return LOCTEXT("PlayerControllerCreateBlueprint", "PlayerController: New..."); @@ -1250,7 +1233,7 @@ TSharedRef< SWidget > FLevelEditorToolBar::MakeLevelEditorToolBar( const TShared ToolbarBuilder.BeginSection("Content"); { ToolbarBuilder.AddToolBarButton( FLevelEditorCommands::Get().OpenContentBrowser, NAME_None, LOCTEXT( "ContentBrowser_Override", "Content" ), TAttribute(), TAttribute(), "LevelToolbarContent" ); - if (FDesktopPlatformModule::Get()->CanOpenLauncher(true)) + if (FLauncherPlatformModule::Get()->CanOpenLauncher(true)) { ToolbarBuilder.AddToolBarButton(FLevelEditorCommands::Get().OpenMarketplace, NAME_None, LOCTEXT("Marketplace_Override", "Marketplace"), TAttribute(), TAttribute(), "LevelToolbarMarketplace"); } @@ -1987,7 +1970,7 @@ TSharedRef< SWidget > FLevelEditorToolBar::GenerateOpenBlueprintMenuContent( TSh FExecuteAction::CreateStatic(&FLevelEditorToolBar::OnOpenSubLevelBlueprint, Level) ); - FText DisplayName = FText::Format(LOCTEXT("SubLevelBlueprintItem", "Edit {0}"), FText::FromString(FPaths::GetCleanFilename(Level->GetOutermost()->GetName()))); + FText DisplayName = FText::Format(LOCTEXT("SubLevelBlueprintItem", "Edit {LevelName}"), FText::FromString(FPaths::GetCleanFilename(Level->GetOutermost()->GetName()))); InMenuBuilder.AddMenuEntry(DisplayName, FText::GetEmpty(), EditBP, UIAction); } } diff --git a/Engine/Source/Editor/LevelEditor/Private/LevelViewportTabContent.cpp b/Engine/Source/Editor/LevelEditor/Private/LevelViewportTabContent.cpp index f6afcd357e98..1a7bf593c8b9 100644 --- a/Engine/Source/Editor/LevelEditor/Private/LevelViewportTabContent.cpp +++ b/Engine/Source/Editor/LevelEditor/Private/LevelViewportTabContent.cpp @@ -3,6 +3,8 @@ #include "LevelViewportTabContent.h" #include "Misc/ConfigCacheIni.h" #include "Framework/Docking/LayoutService.h" +#include "Modules/ModuleManager.h" +#include "LevelEditor.h" #include "LevelViewportLayout2x2.h" #include "LevelViewportLayoutOnePane.h" #include "LevelViewportLayoutTwoPanes.h" @@ -166,4 +168,6 @@ void FLevelViewportTabContent::UpdateViewportTabWidget() PreviouslyFocusedViewport = TOptional(); } } + FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked("LevelEditor"); + LevelEditorModule.OnTabContentChanged().Broadcast(); } diff --git a/Engine/Source/Editor/LevelEditor/Private/LightmapResRatioAdjust.cpp b/Engine/Source/Editor/LevelEditor/Private/LightmapResRatioAdjust.cpp index d8a2bd9e181f..37ed0f6cbb71 100644 --- a/Engine/Source/Editor/LevelEditor/Private/LightmapResRatioAdjust.cpp +++ b/Engine/Source/Editor/LevelEditor/Private/LightmapResRatioAdjust.cpp @@ -171,7 +171,7 @@ bool FLightmapResRatioAdjustSettings::ApplyRatioAdjustment() { bConvertIt = false; } - else if( SMComp->GetWorld() && SMComp->GetWorld()->WorldType == EWorldType::EditorPreview && SMComp->GetWorld()->WorldType != EWorldType::Inactive ) + else if( SMComp->GetWorld() && (SMComp->GetWorld()->WorldType == EWorldType::EditorPreview || SMComp->GetWorld()->WorldType == EWorldType::Inactive) ) { // Don't do objects with an editor preview or inactive world bConvertIt = false; diff --git a/Engine/Source/Editor/LevelEditor/Private/SLevelEditor.cpp b/Engine/Source/Editor/LevelEditor/Private/SLevelEditor.cpp index dca389507574..ce14c4e18601 100644 --- a/Engine/Source/Editor/LevelEditor/Private/SLevelEditor.cpp +++ b/Engine/Source/Editor/LevelEditor/Private/SLevelEditor.cpp @@ -129,7 +129,8 @@ void SLevelEditor::BindCommands() Actions.ToggleVR, FExecuteAction::CreateStatic( &FLevelEditorActionCallbacks::ToggleVR ), FCanExecuteAction::CreateStatic( &FLevelEditorActionCallbacks::ToggleVR_CanExecute ), - FIsActionChecked::CreateStatic( &FLevelEditorActionCallbacks::ToggleVR_IsChecked ) ); + FIsActionChecked::CreateStatic( &FLevelEditorActionCallbacks::ToggleVR_IsChecked ), + FIsActionButtonVisible::CreateStatic(&FLevelEditorActionCallbacks::ToggleVR_CanExecute)); LevelEditorCommands->MapAction( Actions.WorldProperties, diff --git a/Engine/Source/Editor/LevelEditor/Private/SLevelViewport.cpp b/Engine/Source/Editor/LevelEditor/Private/SLevelViewport.cpp index 5d4dfcb23fc6..23eda99abf11 100644 --- a/Engine/Source/Editor/LevelEditor/Private/SLevelViewport.cpp +++ b/Engine/Source/Editor/LevelEditor/Private/SLevelViewport.cpp @@ -64,6 +64,7 @@ #include "Engine/LocalPlayer.h" #include "Slate/SGameLayerManager.h" #include "FoliageType.h" +#include "IVREditorModule.h" static const FName LevelEditorName("LevelEditor"); @@ -722,13 +723,11 @@ bool SLevelViewport::HandlePlaceDraggedObjects(const FGeometry& MyGeometry, cons TSharedPtr DragDropOp = StaticCastSharedPtr( Operation ); - ActorFactory = DragDropOp->ActorFactory.Get(); + ActorFactory = DragDropOp->GetActorFactory(); bAllAssetWereLoaded = true; - for (int32 AssetIdx = 0; AssetIdx < DragDropOp->AssetData.Num(); ++AssetIdx) + for (const FAssetData& AssetData : DragDropOp->GetAssets()) { - const FAssetData& AssetData = DragDropOp->AssetData[AssetIdx]; - UObject* Asset = AssetData.GetAsset(); if ( Asset != NULL ) { @@ -1714,7 +1713,7 @@ void SLevelViewport::OnCreateCameraActor() ACameraActor* pNewCamera = ViewportClient->GetWorld()->SpawnActor(); pNewCamera->SetActorLocation( ViewportClient->GetViewLocation(), false ); pNewCamera->SetActorRotation( ViewportClient->GetViewRotation() ); - pNewCamera->CameraComponent->FieldOfView = ViewportClient->ViewFOV; + pNewCamera->GetCameraComponent()->FieldOfView = ViewportClient->ViewFOV; // Deselect any currently selected actors GUnrealEd->SelectNone( true, true ); @@ -3120,7 +3119,7 @@ void SLevelViewport::PreviewActors( const TArray< AActor* >& ActorsToPreview ) // Push actor transform to view. From here on out, this will happen automatically in FLevelEditorViewportClient::Tick. // The reason we allow the viewport client to update this is to avoid off-by-one-frame issues when dragging actors around. ActorPreviewLevelViewportClient->SetActorLock( CurActor ); - ActorPreviewLevelViewportClient->UpdateViewForLockedActor(); + ActorPreviewLevelViewportClient->UpdateViewForLockedActor(); } TSharedPtr< SActorPreview > ActorPreviewWidget = SNew(SActorPreview) @@ -3129,7 +3128,7 @@ void SLevelViewport::PreviewActors( const TArray< AActor* >& ActorsToPreview ) auto ActorPreviewViewportWidget = ActorPreviewWidget->GetViewportWidget(); - TSharedPtr< FSceneViewport > ActorPreviewSceneViewport = MakeShareable( new FSceneViewport( ActorPreviewLevelViewportClient.Get(), ViewportWidget ) ); + TSharedPtr< FSceneViewport > ActorPreviewSceneViewport = MakeShareable( new FSceneViewport( ActorPreviewLevelViewportClient.Get(), ActorPreviewViewportWidget) ); { ActorPreviewLevelViewportClient->Viewport = ActorPreviewSceneViewport.Get(); ActorPreviewViewportWidget->SetViewportInterface( ActorPreviewSceneViewport.ToSharedRef() ); @@ -3144,11 +3143,20 @@ void SLevelViewport::PreviewActors( const TArray< AActor* >& ActorsToPreview ) // Add our new widget to our viewport's overlay // @todo camerapip: Consider using a canvas instead of an overlay widget -- our viewports get SQUASHED when the view shrinks! - ActorPreviewHorizontalBox->AddSlot() - .AutoWidth() - [ - ActorPreviewWidget.ToSharedRef() - ]; + IVREditorModule& VREditorModule = IVREditorModule::Get(); + if (VREditorModule.IsVREditorEnabled()) + { + NewActorPreview.SceneViewport->SetGammaOverride(1.0f); + VREditorModule.UpdateActorPreview( NewActorPreview.PreviewWidget.ToSharedRef()); + } + else + { + ActorPreviewHorizontalBox->AddSlot() + .AutoWidth() + [ + ActorPreviewWidget.ToSharedRef() + ]; + } } // OK, at least one new preview viewport was added, so update settings for all views immediately. @@ -3846,9 +3854,16 @@ UWorld* SLevelViewport::GetWorld() const void SLevelViewport::RemoveActorPreview( int32 PreviewIndex ) { - // Remove widget from viewport overlay - ActorPreviewHorizontalBox->RemoveSlot( ActorPreviews[PreviewIndex].PreviewWidget.ToSharedRef() ); - + IVREditorModule& VREditorModule = IVREditorModule::Get(); + if (VREditorModule.IsVREditorEnabled()) + { + VREditorModule.UpdateActorPreview(SNullWidget::NullWidget); + } + else + { + // Remove widget from viewport overlay + ActorPreviewHorizontalBox->RemoveSlot(ActorPreviews[PreviewIndex].PreviewWidget.ToSharedRef()); + } // Clean up our level viewport client if( ActorPreviews[PreviewIndex].LevelViewportClient.IsValid() ) { @@ -3902,34 +3917,16 @@ void SLevelViewport::LockActorInternal(AActor* NewActorToLock) bool SLevelViewport::GetCameraInformationFromActor(AActor* Actor, FMinimalViewInfo& out_CameraInfo) { - // @todo camerapip: Could support actors other than cameras too! (Character views?) + // //@TODO: CAMERA: Support richer camera interactions in SIE; this may shake out naturally if everything uses camera components though - TArray CamComps; - Actor->GetComponents(CamComps); - for (UCameraComponent* CamComp : CamComps) - { - if (CamComp->bIsActive) - { - // first active camera, use it and be done - CamComp->GetCameraView(0.0f, out_CameraInfo); - return true; - } - } - // see if any actors are attached to us, directly or indirectly, that have an active camera component we might want to use - // #note: assumption here that attachment cannot be circular - TArray AttachedActors; - Actor->GetAttachedActors(AttachedActors); - for (AActor* AttachedActor : AttachedActors) + bool bFoundCamInfo = false; + if (USceneComponent* ViewComponent = FLevelEditorViewportClient::FindViewComponentForActor(Actor)) { - if (GetCameraInformationFromActor(AttachedActor, out_CameraInfo)) - { - return true; - } + bFoundCamInfo = ViewComponent->GetEditorPreviewInfo(/*DeltaTime =*/0.0f, out_CameraInfo); + ensure(bFoundCamInfo); } - - // no active cameras - return false; + return bFoundCamInfo; } bool SLevelViewport::CanGetCameraInformationFromActor(AActor* Actor) @@ -3953,4 +3950,14 @@ void SLevelViewport::OnFloatingButtonClicked() LevelViewportClient->SetLastKeyViewport(); } +void SLevelViewport::RemoveAllPreviews() +{ + // Clean up any actor preview viewports + for (FViewportActorPreview& ActorPreview : ActorPreviews) + { + ActorPreview.bIsPinned = false; + } + PreviewActors(TArray< AActor* >()); +} + #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Editor/LevelEditor/Public/LevelEditor.h b/Engine/Source/Editor/LevelEditor/Public/LevelEditor.h index 32554cd43cfc..fc1c0fba433d 100644 --- a/Engine/Source/Editor/LevelEditor/Public/LevelEditor.h +++ b/Engine/Source/Editor/LevelEditor/Public/LevelEditor.h @@ -167,6 +167,10 @@ public: DECLARE_EVENT(FLevelEditorModule, FTabManagerChangedEvent); virtual FTabManagerChangedEvent& OnTabManagerChanged() { return TabManagerChangedEvent; } + /** Called when the tab content is changed */ + DECLARE_EVENT(FLevelEditorModule, FTabContentChangedEvent); + virtual FTabContentChangedEvent& OnTabContentChanged() { return TabContentChangedEvent; } + /** * Called when actor selection changes @@ -344,6 +348,9 @@ private: /** Multicast delegate executed when the tab manager is changed */ FTabManagerChangedEvent TabManagerChangedEvent; + /** Multicast delegate executed when the tab content is changed */ + FTabContentChangedEvent TabContentChangedEvent; + /** Multicast delegate executed when actor selection changes */ FActorSelectionChangedEvent ActorSelectionChangedEvent; diff --git a/Engine/Source/Editor/LevelEditor/Public/LevelEditorActions.h b/Engine/Source/Editor/LevelEditor/Public/LevelEditorActions.h index 142fe2f2ff4e..7a826b95581d 100644 --- a/Engine/Source/Editor/LevelEditor/Public/LevelEditorActions.h +++ b/Engine/Source/Editor/LevelEditor/Public/LevelEditorActions.h @@ -727,6 +727,7 @@ public: * Build callbacks */ static void Build_Execute(); + static bool Build_CanExecute(); static void BuildAndSubmitToSourceControl_Execute(); static void BuildLightingOnly_Execute(); static bool BuildLighting_CanExecute(); diff --git a/Engine/Source/Editor/LevelEditor/Public/SLevelViewport.h b/Engine/Source/Editor/LevelEditor/Public/SLevelViewport.h index beae0e031d9e..2bea14613fcc 100644 --- a/Engine/Source/Editor/LevelEditor/Public/SLevelViewport.h +++ b/Engine/Source/Editor/LevelEditor/Public/SLevelViewport.h @@ -341,6 +341,9 @@ public: /** Get the visibility for items considered to be part of the 'full' viewport toolbar */ EVisibility GetFullToolbarVisibility() const { return bShowFullToolbar ? EVisibility::Visible : EVisibility::Collapsed; } + /** Unpin and close all actor preview windows */ + void RemoveAllPreviews(); + protected: /** SEditorViewport interface */ virtual TSharedRef MakeEditorViewportClient() override; diff --git a/Engine/Source/Editor/LiveLinkInterface/Public/ILiveLinkClient.h b/Engine/Source/Editor/LiveLinkInterface/Public/ILiveLinkClient.h index 617bf43cb063..c2e3b3aeb8e1 100644 --- a/Engine/Source/Editor/LiveLinkInterface/Public/ILiveLinkClient.h +++ b/Engine/Source/Editor/LiveLinkInterface/Public/ILiveLinkClient.h @@ -4,6 +4,8 @@ #include "LiveLinkRefSkeleton.h" #include "Features/IModularFeature.h" +#include "LiveLinkTypes.h" +#include "Guid.h" class LIVELINKINTERFACE_API ILiveLinkClient : public IModularFeature { @@ -12,8 +14,13 @@ public: static FName ModularFeatureName; - virtual void PushSubjectSkeleton(FName SubjectName, const FLiveLinkRefSkeleton& RefSkeleton) = 0; - virtual void PushSubjectData(FName SubjectName, const TArray& Transforms) = 0; + // Helper functions for making time codes for new frames + virtual FLiveLinkTimeCode MakeTimeCode(double InTime, int32 InFrameNum) const = 0; + virtual FLiveLinkTimeCode MakeTimeCodeFromTimeOnly(double InTime) const = 0; - virtual bool GetSubjectData(FName SubjectName, TArray& OutTransforms, FLiveLinkRefSkeleton& OutRefSkeleton) = 0; + virtual void PushSubjectSkeleton(FName SubjectName, const FLiveLinkRefSkeleton& RefSkeleton) = 0; + virtual void PushSubjectData(FGuid SourceGuid, FName SubjectName, const TArray& Transforms, const TArray& CurveElements, const FLiveLinkTimeCode& TimeCode) = 0; + virtual void ClearSubject(FName SubjectName) = 0; + + virtual const FLiveLinkSubjectFrame* GetSubjectData(FName SubjectName) = 0; }; \ No newline at end of file diff --git a/Engine/Source/Editor/LiveLinkInterface/Public/ILiveLinkSource.h b/Engine/Source/Editor/LiveLinkInterface/Public/ILiveLinkSource.h index 0aa6a433577f..61e62ba62f73 100644 --- a/Engine/Source/Editor/LiveLinkInterface/Public/ILiveLinkSource.h +++ b/Engine/Source/Editor/LiveLinkInterface/Public/ILiveLinkSource.h @@ -3,6 +3,7 @@ #pragma once #include "CoreMinimal.h" +#include "Guid.h" class ILiveLinkClient; @@ -10,7 +11,7 @@ class ILiveLinkSource { public: virtual ~ILiveLinkSource() {} - virtual void ReceiveClient(ILiveLinkClient* InClient) = 0; + virtual void ReceiveClient(ILiveLinkClient* InClient, FGuid InSourceGuid) = 0; virtual bool IsSourceStillValid() = 0; diff --git a/Engine/Source/Editor/LiveLinkInterface/Public/LiveLinkRefSkeleton.h b/Engine/Source/Editor/LiveLinkInterface/Public/LiveLinkRefSkeleton.h index e49c7da8db13..132b0910c73f 100644 --- a/Engine/Source/Editor/LiveLinkInterface/Public/LiveLinkRefSkeleton.h +++ b/Engine/Source/Editor/LiveLinkInterface/Public/LiveLinkRefSkeleton.h @@ -12,12 +12,26 @@ struct FLiveLinkRefSkeleton { GENERATED_USTRUCT_BODY() + // Set the bone names for this skeleton void SetBoneNames(const TArray& InBoneNames) { BoneNames = InBoneNames; } + // Get the bone names for this skeleton const TArray& GetBoneNames() const { return BoneNames; } + // Set the parent bones for this skeleton (Array of indices to parent) + void SetBoneParents(const TArray InBoneParents) { BoneParents = InBoneParents; } + + //Get skeleton's parent bones array + const TArray& GetBoneParents() const { return BoneParents; } + private: + // Names of each bone in the skeleton UPROPERTY() TArray BoneNames; + + // Parent Indices: For each bone it specifies the index of its parent + UPROPERTY() + TArray BoneParents; + }; \ No newline at end of file diff --git a/Engine/Source/Editor/LiveLinkInterface/Public/LiveLinkSourceFactory.h b/Engine/Source/Editor/LiveLinkInterface/Public/LiveLinkSourceFactory.h index e0fa1ce748c9..66728d3e91bf 100644 --- a/Engine/Source/Editor/LiveLinkInterface/Public/LiveLinkSourceFactory.h +++ b/Engine/Source/Editor/LiveLinkInterface/Public/LiveLinkSourceFactory.h @@ -21,5 +21,5 @@ public: virtual FText GetSourceTooltip() const PURE_VIRTUAL(ULiveLinkSourceFactory::GetSourceTooltip, return FText(); ); virtual TSharedPtr CreateSourceCreationPanel() PURE_VIRTUAL(ULiveLinkSourceFactory::CreateSourceCreationPanel, return nullptr;); - virtual ILiveLinkSource* OnSourceCreationPanelClosed(bool bCreateSource) PURE_VIRTUAL(ULiveLinkSourceFactory::OnSourceCreationPanelClosed, return nullptr;); + virtual TSharedPtr OnSourceCreationPanelClosed(bool bCreateSource) PURE_VIRTUAL(ULiveLinkSourceFactory::OnSourceCreationPanelClosed, return nullptr;); }; \ No newline at end of file diff --git a/Engine/Source/Editor/LiveLinkInterface/Public/LiveLinkTypes.h b/Engine/Source/Editor/LiveLinkInterface/Public/LiveLinkTypes.h new file mode 100644 index 000000000000..8d079c086aef --- /dev/null +++ b/Engine/Source/Editor/LiveLinkInterface/Public/LiveLinkTypes.h @@ -0,0 +1,96 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "LiveLinkRefSkeleton.h" +#include "LiveLinkTypes.generated.h" + +USTRUCT() +struct FLiveLinkCurveElement +{ +public: + GENERATED_USTRUCT_BODY() + + UPROPERTY() + FName CurveName; + + UPROPERTY() + float CurveValue; +}; + +struct FOptionalCurveElement +{ + /** Curve Value */ + float Value; + /** Whether this value is set or not */ + bool bValid; + + FOptionalCurveElement(float InValue) + : Value(InValue) + , bValid(true) + {} + + FOptionalCurveElement() + : Value(0.f) + , bValid(false) + {} + + bool IsValid() const + { + return bValid; + } + + void SetValue(float InValue) + { + Value = InValue; + bValid = true; + } +}; + +//Helper struct for updating curve data across multiple frames of live link data +struct FLiveLinkCurveIntegrationData +{ +public: + + // Number of new curves that need to be added to existing frames + int32 NumNewCurves; + + // Built curve buffer for current frame in existing curve key format + TArray CurveValues; +}; + +struct FLiveLinkCurveKey +{ + TArray CurveNames; + + FLiveLinkCurveIntegrationData UpdateCurveKey(const TArray& CurveElements); +}; + +struct FLiveLinkTimeCode +{ + // Time for this frame. Used during interpolation. If this goes backwards we will dump already stored frames. + double Time; + + // Frame number for this data. + int32 FrameNum; + + // Value calculated on create to represent the different between the source time and client time + double Offset; +}; + +struct FLiveLinkSubjectFrame +{ + // Ref Skeleton for transforms + FLiveLinkRefSkeleton RefSkeleton; + + // Key for storing curve data (Names) + FLiveLinkCurveKey CurveKeyData; + + // Transforms for this frame + TArray Transforms; + + // Curve data for this frame + TArray Curves; +}; \ No newline at end of file diff --git a/Engine/Source/Editor/LiveLinkMessageBusFramework/Private/LiveLinkProvider.cpp b/Engine/Source/Editor/LiveLinkMessageBusFramework/Private/LiveLinkProvider.cpp index ecaf7730c3d6..3c8f743e0ebb 100644 --- a/Engine/Source/Editor/LiveLinkMessageBusFramework/Private/LiveLinkProvider.cpp +++ b/Engine/Source/Editor/LiveLinkMessageBusFramework/Private/LiveLinkProvider.cpp @@ -5,65 +5,201 @@ #include "MessageEndpoint.h" #include "MessageEndpointBuilder.h" #include "LiveLinkMessages.h" +#include "LiveLinkTypes.h" #include "HAL/PlatformProcess.h" +// Subject that the application has told us about +struct FTrackedSubject +{ + // Ref skeleton to go with transform data + FLiveLinkRefSkeleton RefSkeleton; + + // Bone transform data + TArray Transforms; + + // Curve data + TArray Curves; + + // Incrementing time (application time) for interpolation purposes + double Time; + + // Frame number of current data + int32 FrameNum; +}; + +// Address that we have had a connection request from +struct FTrackedAddress +{ + FTrackedAddress(FMessageAddress InAddress) + : Address(InAddress) + , LastHeartbeatTime(FPlatformTime::Seconds()) + {} + + FMessageAddress Address; + double LastHeartbeatTime; +}; + struct FLiveLinkProvider : public ILiveLinkProvider { private: + // How long we give connections before we decide they are dead + static const double CONNECTION_TIMEOUT; + const FString ProviderName; const FString MachineName; - int32 SubjectID; - FMessageEndpointPtr MessageEndpoint; - FMessageAddress ConnectionAddress; + // Array of our current connections + TArray ConnectedAddresses; - void HandlePingMessage(const FLiveLinkPing& Message, const IMessageContextRef& Context); - void HandleConnectMessage(const FLiveLinkConnect& Message, const IMessageContextRef& Context); + // Cache of our current subject state + TMap Subjects; + + //Message bus message handlers + void HandlePingMessage(const FLiveLinkPingMessage& Message, const IMessageContextRef& Context); + void HandleConnectMessage(const FLiveLinkConnectMessage& Message, const IMessageContextRef& Context); + void HandleHeartbeat(const FLiveLinkHeartbeatMessage& Message, const IMessageContextRef& Context); + // End message bus message handlers + + // Validate our current connections + void ValidateConnections() + { + double CutOffTime = FPlatformTime::Seconds() - CONNECTION_TIMEOUT; + + ConnectedAddresses.RemoveAll([=](const FTrackedAddress& Address) { return Address.LastHeartbeatTime < CutOffTime; }); + } + + // Get the cached data for the named subject + FTrackedSubject& GetTrackedSubject(const FName& SubjectName) + { + return Subjects.FindOrAdd(SubjectName); + } + + // Clear a existing track subject + void ClearTrackedSubject(const FName& SubjectName) + { + Subjects.Remove(SubjectName); + } + + // Send hierarchy data for named subject to supplied address + void SendSubjectToAddress(FName SubjectName, const FTrackedSubject& Subject, FMessageAddress Address) + { + FLiveLinkSubjectDataMessage* SubjectData = new FLiveLinkSubjectDataMessage; + SubjectData->RefSkeleton = Subject.RefSkeleton; + SubjectData->SubjectName = SubjectName; + + MessageEndpoint->Send(SubjectData, Address); + } + + // Send hierarchy data for named subject to supplied address + void SendSubjectToAddress(FName SubjectName, FMessageAddress Address) + { + SendSubjectToAddress(SubjectName, GetTrackedSubject(SubjectName), Address); + } + + // Send frame data for named subject to supplied address + void SendSubjectFrameToAddress(FName SubjectName, const FTrackedSubject& Subject, FMessageAddress Address) + { + FLiveLinkSubjectFrameMessage* SubjectFrame = new FLiveLinkSubjectFrameMessage; + SubjectFrame->Transforms = Subject.Transforms; + SubjectFrame->SubjectName = SubjectName; + SubjectFrame->Curves = Subject.Curves; + SubjectFrame->Time = Subject.Time; + SubjectFrame->FrameNum = Subject.FrameNum; + + MessageEndpoint->Send(SubjectFrame, Address); + } + + // Send frame data for named subject to supplied address + void SendSubjectFrameToAddress(FName SubjectName, FMessageAddress Address) + { + SendSubjectFrameToAddress(SubjectName, GetTrackedSubject(SubjectName), Address); + } + + void SendClearSubjectToAddress(FName SubjectName, FMessageAddress Address) + { + FLiveLinkClearSubject* ClearSubject = new FLiveLinkClearSubject(SubjectName); + MessageEndpoint->Send(ClearSubject, Address); + } + + // Send hierarchy data for named subject to current connections + void SendSubjectToConnections(FName SubjectName) + { + ValidateConnections(); + + for (const FTrackedAddress& Address : ConnectedAddresses) + { + SendSubjectToAddress(SubjectName, Address.Address); + } + } + + // Send frame data for named subject to current connections + void SendSubjectFrameToConnections(FName SubjectName) + { + ValidateConnections(); + + for (const FTrackedAddress& Address : ConnectedAddresses) + { + SendSubjectFrameToAddress(SubjectName, Address.Address); + } + } + + void SendClearSubjectToConnections(FName SubjectName) + { + ValidateConnections(); + + for (const FTrackedAddress& Address : ConnectedAddresses) + { + SendClearSubjectToAddress(SubjectName, Address.Address); + } + } public: FLiveLinkProvider(const FString& InProviderName) : ProviderName(InProviderName) , MachineName(FPlatformProcess::ComputerName()) - , SubjectID(0) { MessageEndpoint = FMessageEndpoint::Builder(*InProviderName) .ReceivingOnAnyThread() - .Handling(this, &FLiveLinkProvider::HandlePingMessage) - .Handling(this, &FLiveLinkProvider::HandleConnectMessage); + .Handling(this, &FLiveLinkProvider::HandlePingMessage) + .Handling(this, &FLiveLinkProvider::HandleConnectMessage) + .Handling(this, &FLiveLinkProvider::HandleHeartbeat); if (MessageEndpoint.IsValid()) { - MessageEndpoint->Subscribe(); + MessageEndpoint->Subscribe(); } } - virtual void SendSubject(const FString& SubjectName, const TArray& BoneNames, const TArray& BoneTransforms) + virtual void UpdateSubject(const FName& SubjectName, const TArray& BoneNames, const TArray& BoneParents) { - static bool bSentNames = false; - if (ConnectionAddress.IsValid()) - { - ++SubjectID; - if(!bSentNames) - { - bSentNames = true; - FLiveLinkSubjectData* SubjectData = new FLiveLinkSubjectData; - SubjectData->RefSkeleton.SetBoneNames(BoneNames); - SubjectData->SubjectName = SubjectName; - SubjectData->BoneID = SubjectID; + FTrackedSubject& Subject = GetTrackedSubject(SubjectName); + Subject.RefSkeleton.SetBoneNames(BoneNames); + Subject.RefSkeleton.SetBoneParents(BoneParents); + Subject.Transforms.Empty(); + + SendSubjectToConnections(SubjectName); + } - MessageEndpoint->Send(SubjectData, ConnectionAddress); - } + virtual void ClearSubject(const FName& SubjectName) + { + ClearTrackedSubject(SubjectName); + SendClearSubjectToConnections(SubjectName); + } - FLiveLinkSubjectFrame* SubjectFrame = new FLiveLinkSubjectFrame; - SubjectFrame->Transforms = BoneTransforms; - SubjectFrame->BoneID = SubjectID; + virtual void UpdateSubjectFrame(const FName& SubjectName, const TArray& BoneTransforms, const TArray& CurveData, double Time, int32 FrameNum) + { + FTrackedSubject& Subject = GetTrackedSubject(SubjectName); - MessageEndpoint->Send(SubjectFrame, ConnectionAddress); - } + Subject.Transforms = BoneTransforms; + Subject.Curves = CurveData; + Subject.Time = Time; + Subject.FrameNum = FrameNum; + + SendSubjectFrameToConnections(SubjectName); } virtual ~FLiveLinkProvider() @@ -72,19 +208,38 @@ public: } }; -void FLiveLinkProvider::HandlePingMessage(const FLiveLinkPing& Message, const IMessageContextRef& Context) +const double FLiveLinkProvider::CONNECTION_TIMEOUT = 10.f; + +void FLiveLinkProvider::HandlePingMessage(const FLiveLinkPingMessage& Message, const IMessageContextRef& Context) { - //if (!ConnectionAddress.IsValid()) // Stop us getting locked out of Maya while address lifetime needs work + MessageEndpoint->Send(new FLiveLinkPongMessage(ProviderName, MachineName, Message.PollRequest), Context->GetSender()); +} + +void FLiveLinkProvider::HandleConnectMessage(const FLiveLinkConnectMessage& Message, const IMessageContextRef& Context) +{ + const FMessageAddress& ConnectionAddress = Context->GetSender(); + + if (!ConnectedAddresses.ContainsByPredicate([=](const FTrackedAddress& Address) { return Address.Address == ConnectionAddress; })) { - MessageEndpoint->Send(new FLiveLinkPong(ProviderName, MachineName, Message.PollRequest), Context->GetSender()); + ConnectedAddresses.Add(FTrackedAddress(ConnectionAddress)); + for (const auto& Subject : Subjects) + { + SendSubjectToAddress(Subject.Key, Subject.Value, ConnectionAddress); + FPlatformProcess::Sleep(0.1); //HACK: Try to help these go in order, editor needs extra buffering support to make sure this isn't needed in future. + SendSubjectFrameToAddress(Subject.Key, Subject.Value, ConnectionAddress); + } } } -void FLiveLinkProvider::HandleConnectMessage(const FLiveLinkConnect& Message, const IMessageContextRef& Context) +void FLiveLinkProvider::HandleHeartbeat(const FLiveLinkHeartbeatMessage& Message, const IMessageContextRef& Context) { - //if (!ConnectionAddress.IsValid()) + FTrackedAddress* TrackedAddress = ConnectedAddresses.FindByPredicate([=](const FTrackedAddress& ConAddress) { return ConAddress.Address == Context->GetSender(); }); + if (TrackedAddress) { - ConnectionAddress = Context->GetSender(); + TrackedAddress->LastHeartbeatTime = FPlatformTime::Seconds(); + + // Respond so editor gets heartbeat too + MessageEndpoint->Send(new FLiveLinkHeartbeatMessage(), Context->GetSender()); } } diff --git a/Engine/Source/Editor/LiveLinkMessageBusFramework/Public/LiveLinkMessages.h b/Engine/Source/Editor/LiveLinkMessageBusFramework/Public/LiveLinkMessages.h index ba6fed4cff5d..874d1d83ff1e 100644 --- a/Engine/Source/Editor/LiveLinkMessageBusFramework/Public/LiveLinkMessages.h +++ b/Engine/Source/Editor/LiveLinkMessageBusFramework/Public/LiveLinkMessages.h @@ -3,21 +3,11 @@ #pragma once #include "Object.h" #include "LiveLinkRefSkeleton.h" - +#include "LiveLinkTypes.h" #include "LiveLinkMessages.generated.h" -//Is this still needed? -UCLASS() -class UDummyObject : public UObject -{ - GENERATED_BODY() - - UPROPERTY() - int32 test; -}; - USTRUCT() -struct FLiveLinkSubjectData +struct FLiveLinkSubjectDataMessage { GENERATED_USTRUCT_BODY() @@ -25,26 +15,36 @@ struct FLiveLinkSubjectData FLiveLinkRefSkeleton RefSkeleton; UPROPERTY() - FString SubjectName; - - UPROPERTY() - int32 BoneID; + FName SubjectName; }; USTRUCT() -struct FLiveLinkSubjectFrame +struct FLiveLinkSubjectFrameMessage { GENERATED_USTRUCT_BODY() + UPROPERTY() + FName SubjectName; + + // Bone Transform data for this frame UPROPERTY() TArray Transforms; + // Curve data for this frame UPROPERTY() - int32 BoneID; + TArray Curves; + + // Incrementing time for interpolation + UPROPERTY() + double Time; + + // Frame number + UPROPERTY() + int32 FrameNum; }; USTRUCT() -struct FLiveLinkPing +struct FLiveLinkPingMessage { GENERATED_USTRUCT_BODY() @@ -52,13 +52,13 @@ struct FLiveLinkPing FGuid PollRequest; // default constructor for the receiver - FLiveLinkPing() = default; + FLiveLinkPingMessage() = default; - FLiveLinkPing(const FGuid& InPollRequest) : PollRequest(InPollRequest) {} + FLiveLinkPingMessage(const FGuid& InPollRequest) : PollRequest(InPollRequest) {} }; USTRUCT() -struct FLiveLinkPong +struct FLiveLinkPongMessage { GENERATED_USTRUCT_BODY() @@ -72,13 +72,32 @@ struct FLiveLinkPong FGuid PollRequest; // default constructor for the receiver - FLiveLinkPong() = default; + FLiveLinkPongMessage() = default; - FLiveLinkPong(const FString& InProviderName, const FString& InMachineName, const FGuid& InPollRequest) : ProviderName(InProviderName), MachineName(InMachineName), PollRequest(InPollRequest) {} + FLiveLinkPongMessage(const FString& InProviderName, const FString& InMachineName, const FGuid& InPollRequest) : ProviderName(InProviderName), MachineName(InMachineName), PollRequest(InPollRequest) {} }; USTRUCT() -struct FLiveLinkConnect +struct FLiveLinkConnectMessage { GENERATED_USTRUCT_BODY() }; + +USTRUCT() +struct FLiveLinkHeartbeatMessage +{ + GENERATED_USTRUCT_BODY() +}; + +USTRUCT() +struct FLiveLinkClearSubject +{ + GENERATED_USTRUCT_BODY() + + // Name of the subject to clear + UPROPERTY() + FName SubjectName; + + FLiveLinkClearSubject() {} + FLiveLinkClearSubject(const FName& InSubjectName) : SubjectName(InSubjectName) {} +}; diff --git a/Engine/Source/Editor/LiveLinkMessageBusFramework/Public/LiveLinkProvider.h b/Engine/Source/Editor/LiveLinkMessageBusFramework/Public/LiveLinkProvider.h index c078e3eddca6..9933f9e170df 100644 --- a/Engine/Source/Editor/LiveLinkMessageBusFramework/Public/LiveLinkProvider.h +++ b/Engine/Source/Editor/LiveLinkMessageBusFramework/Public/LiveLinkProvider.h @@ -3,13 +3,21 @@ #pragma once #include "SharedPointer.h" +#include "LiveLinkTypes.h" struct ILiveLinkProvider { public: LIVELINKMESSAGEBUSFRAMEWORK_API static TSharedPtr CreateLiveLinkProvider(const FString& ProviderName); - virtual void SendSubject(const FString& SubjectName, const TArray& BoneNames, const TArray& BoneTransforms) = 0; + // Update hierarchy for named subject + virtual void UpdateSubject(const FName& SubjectName, const TArray& BoneNames, const TArray& BoneParents) = 0; + + // Remove named subject + virtual void ClearSubject(const FName& SubjectName) = 0; + + // Update subject with transform data + virtual void UpdateSubjectFrame(const FName& SubjectName, const TArray& BoneTransforms, const TArray& CurveData, double Time, int32 FrameNum) = 0; virtual ~ILiveLinkProvider() {} }; \ No newline at end of file diff --git a/Engine/Source/Editor/MainFrame/MainFrame.Build.cs b/Engine/Source/Editor/MainFrame/MainFrame.Build.cs index 1bf85705f91e..9b757258ca5b 100644 --- a/Engine/Source/Editor/MainFrame/MainFrame.Build.cs +++ b/Engine/Source/Editor/MainFrame/MainFrame.Build.cs @@ -18,7 +18,6 @@ public class MainFrame : ModuleRules new string[] { "Core", "CoreUObject", - "CrashTracker", "Engine", "EngineSettings", "InputCore", @@ -34,7 +33,6 @@ public class MainFrame : ModuleRules "UnrealEd", "WorkspaceMenuStructure", "MessageLog", -// "SearchUI", "UATHelper", "TranslationEditor", "Projects", @@ -77,7 +75,6 @@ public class MainFrame : ModuleRules "OutputLog", "SuperSearch", "SourceCodeAccess", - "EditorLiveStreaming", "HotReload", "LocalizationDashboard", } diff --git a/Engine/Source/Editor/MainFrame/Private/Frame/MainFrameActions.cpp b/Engine/Source/Editor/MainFrame/Private/Frame/MainFrameActions.cpp index 22bea19c3475..7aedd248a300 100644 --- a/Engine/Source/Editor/MainFrame/Private/Frame/MainFrameActions.cpp +++ b/Engine/Source/Editor/MainFrame/Private/Frame/MainFrameActions.cpp @@ -75,7 +75,8 @@ FMainFrameCommands::FMainFrameCommands() void FMainFrameCommands::RegisterCommands() { - if ( !IsRunningCommandlet() ) + // Some commands cannot be processed in a commandlet or if the editor is started without a project + if ( !IsRunningCommandlet() && FApp::HasGameName() ) { // The global action list was created at static initialization time. Create a handler for otherwise unhandled keyboard input to route key commands through this list. FSlateApplication::Get().SetUnhandledKeyDownEventHandler( FOnKeyEvent::CreateStatic( &FMainFrameActionCallbacks::OnUnhandledKeyDownEvent ) ); @@ -331,7 +332,7 @@ const TCHAR* GetUATCompilationFlags() { // We never want to compile editor targets when invoking UAT in this context. // If we are installed or don't have a compiler, we must assume we have a precompiled UAT. - return (FApp::GetEngineIsPromotedBuild() || FApp::IsEngineInstalled()) + return (FApp::GetEngineIsPromotedBuild() || FApp::IsEngineInstalled() || FPlatformMisc::IsDebuggerPresent()) ? TEXT("-nocompile -nocompileeditor") : TEXT("-nocompileeditor"); } @@ -613,6 +614,10 @@ void FMainFrameActionCallbacks::PackageProject( const FName InPlatformInfoName ) { OptionalParams += FString::Printf(TEXT(" -applocaldirectory=\"%s\""), *(PackagingSettings->ApplocalPrerequisitesDirectory.Path)); } + else if (PackagingSettings->IncludeAppLocalPrerequisites) + { + OptionalParams += TEXT(" -applocaldirectory=\"$(EngineDir)/Binaries/ThirdParty/AppLocalDependencies\""); + } if (PackagingSettings->ForDistribution) { diff --git a/Engine/Source/Editor/MainFrame/Private/Frame/MainFrameHandler.cpp b/Engine/Source/Editor/MainFrame/Private/Frame/MainFrameHandler.cpp index cf38b304dc2e..ad947363cda6 100644 --- a/Engine/Source/Editor/MainFrame/Private/Frame/MainFrameHandler.cpp +++ b/Engine/Source/Editor/MainFrame/Private/Frame/MainFrameHandler.cpp @@ -31,6 +31,16 @@ void FMainFrameHandler::ShutDownEditor() if (RootWindow.IsValid()) { FSlateRect WindowRect = RootWindow->GetNonMaximizedRectInScreen(); + + if (!RootWindow->HasOSWindowBorder()) + { + // If the window has a specified border size, shrink its screen size by that amount to prevent it from growing + // over multiple shutdowns + const FMargin WindowBorder = RootWindow->GetNonMaximizedWindowBorderSize(); + WindowRect.Right -= WindowBorder.Left + WindowBorder.Right; + WindowRect.Bottom -= WindowBorder.Top + WindowBorder.Bottom; + } + FRootWindowLocation RootWindowLocation(FVector2D(WindowRect.Left, WindowRect.Top), WindowRect.GetSize(), RootWindow->IsWindowMaximized()); RootWindowLocation.SaveToIni(); } diff --git a/Engine/Source/Editor/MainFrame/Private/MainFrameModule.cpp b/Engine/Source/Editor/MainFrame/Private/MainFrameModule.cpp index 81d0274f5dc8..a0ae4c0b8bd1 100644 --- a/Engine/Source/Editor/MainFrame/Private/MainFrameModule.cpp +++ b/Engine/Source/Editor/MainFrame/Private/MainFrameModule.cpp @@ -7,7 +7,6 @@ #include "Widgets/Images/SImage.h" #include "Widgets/Layout/SBox.h" #include "Widgets/Input/SButton.h" -#include "Interfaces/ICrashTrackerModule.h" #include "GameProjectGenerationModule.h" #include "MessageLogModule.h" #include "MRUFavoritesList.h" @@ -21,7 +20,6 @@ #include "Menus/MainMenu.h" #include "Frame/RootWindowLocation.h" #include "Kismet2/CompilerResultsLog.h" -#include "Editor/EditorLiveStreaming/Public/IEditorLiveStreaming.h" #include "Developer/HotReload/Public/IHotReload.h" #include "Framework/Notifications/NotificationManager.h" #include "Widgets/Notifications/SNotificationList.h" @@ -310,70 +308,6 @@ TSharedRef FMainFrameModule::MakeDeveloperTools() const FPlatformProcess::ExploreFolder( *( FPaths::GetPath(SourceFilePath) ) ); } - /** Clicked the SaveVideo button available */ - static FReply OnClickSaveVideo() - { - // Default the result to fail it will be set to SNotificationItem::CS_Success if saved ok - SNotificationItem::ECompletionState SaveResultState = SNotificationItem::CS_Fail; - // The string we will use to tell the user the result of the save - FText VideoSaveResultText; - FString HyperLinkText; - - // Capture unavailable or inactive error string - ICrashTrackerModule* CrashTracker = FModuleManager::LoadModulePtr("CrashTracker"); - if(CrashTracker) - { - FString VideoSaveName; - EWriteUserCaptureVideoError::Type WriteResult = CrashTracker->WriteUserVideoNow( VideoSaveName ); - // If this returns None the capture was successful, otherwise report the error - if( WriteResult == EWriteUserCaptureVideoError::None ) - { - // Setup the string with the path and name of the file - VideoSaveResultText = LOCTEXT( "VideoSavedAs", "Video capture saved as" ); - HyperLinkText = FPaths::ConvertRelativePathToFull(VideoSaveName); - // Flag success - SaveResultState = SNotificationItem::CS_Success; - } - else - { - // Write returned an error - differentiate between directory creation failure and the capture unavailable - if( WriteResult == EWriteUserCaptureVideoError::FailedToCreateDirectory ) - { - FFormatNamedArguments Args; - Args.Add( TEXT("VideoCaptureDirectory"), FText::FromString( FPaths::ConvertRelativePathToFull(FPaths::VideoCaptureDir()) ) ); - VideoSaveResultText = LOCTEXT( "VideoSavedFailedFailedToCreateDir", "Video capture save failed - Failed to create directory\n{VideoCaptureDirectory}" ); - } - else - { - VideoSaveResultText = LOCTEXT( "VideoSavedFailedNotRunning", "Video capture save failed - Capture not active or unavailable" ); - } - } - } - else - { - // This shouldn't happen as the button is hidden when there is no crash tracker - VideoSaveResultText = LOCTEXT( "VideoSavedFailedNoTracker", "Video capture failed - CrashTracker inactive" ); - } - - // Inform the user of the result of the operation - FNotificationInfo Info( VideoSaveResultText ); - Info.ExpireDuration = 5.0f; - Info.FadeOutDuration = 0.5f; - Info.bUseSuccessFailIcons = false; - Info.bUseLargeFont = false; - if( HyperLinkText != "" ) - { - Info.Hyperlink = FSimpleDelegate::CreateStatic(&Local::OpenVideo, HyperLinkText ); - Info.HyperlinkText = FText::FromString( HyperLinkText ); - } - - TWeakPtr SaveMessagePtr; - SaveMessagePtr = FSlateNotificationManager::Get().AddNotification(Info); - SaveMessagePtr.Pin()->SetCompletionState(SaveResultState); - - return FReply::Handled(); - } - /** @return Returns true if frame rate and memory should be displayed in the UI */ static EVisibility ShouldShowFrameRateAndMemory() @@ -396,13 +330,6 @@ TSharedRef FMainFrameModule::MakeDeveloperTools() const TSharedPtr< SWidget > DeveloperTools; TSharedPtr< SEditableTextBox > ExposedEditableTextBox; - ICrashTrackerModule* CrashTracker = FModuleManager::LoadModulePtr("CrashTracker"); - bool bCrashTrackerVideoAvailable = false; - if (CrashTracker) - { - bCrashTrackerVideoAvailable = CrashTracker->IsVideoCaptureAvailable(); - } - TSharedRef FrameRateAndMemoryWidget = SNew( SHorizontalBox ) .Visibility_Static( &Local::ShouldShowFrameRateAndMemory ) @@ -539,61 +466,6 @@ TSharedRef FMainFrameModule::MakeDeveloperTools() const bUseSuperSearch ? SuperSearchModule.MakeSearchBox( ExposedEditableTextBox ) : OutputLogModule.MakeConsoleInputBox( ExposedEditableTextBox ) ] ] - // Editor live streaming toggle button - +SHorizontalBox::Slot() - .AutoWidth() - .VAlign( VAlign_Bottom ) - [ - SNew(SButton) - .Visibility_Static( []() -> EVisibility { return IEditorLiveStreaming::Get().IsLiveStreamingAvailable() ? EVisibility::Visible : EVisibility::Collapsed; } ) - .ToolTipText( LOCTEXT( "BroadcastTooltip", "Starts or stops broadcasting of this editor session to a live internet streaming service." ) ) - .OnClicked_Static( [] - { - // Toggle broadcasting on or off - if( IEditorLiveStreaming::Get().IsBroadcastingEditor() ) - { - IEditorLiveStreaming::Get().StopBroadcastingEditor(); - } - else - { - IEditorLiveStreaming::Get().StartBroadcastingEditor(); - } - return FReply::Handled(); - } ) - .ButtonStyle( FEditorStyle::Get(), "NoBorder" ) - .ContentPadding(FMargin(1,0)) - [ - SNew(SImage) - .Image( FEditorStyle::GetBrush("EditorLiveStreaming.BroadcastButton") ) - .ColorAndOpacity_Static( [] - { - // Pulsate the button graphics while we're broadcasting - FSlateColor Color( FLinearColor::White ); - if( IEditorLiveStreaming::Get().IsBroadcastingEditor() ) - { - Color = FLinearColor( 1.0f, 1.0f, 1.0f, FMath::MakePulsatingValue( FSlateApplication::Get().GetCurrentTime(), 2.0f ) ); - } - return Color; - } ) - ] - ] - - // Crash report "save video" button - +SHorizontalBox::Slot() - .AutoWidth() - .VAlign( VAlign_Bottom ) - [ - SNew(SButton) - .Visibility( bCrashTrackerVideoAvailable ? EVisibility::Visible : EVisibility::Collapsed ) - .ToolTipText( LOCTEXT( "SaveReplayTooltip", "Saves a video of the last 20 seconds of your work." ) ) - .OnClicked_Static( &Local::OnClickSaveVideo ) - .ButtonStyle( FEditorStyle::Get(), "NoBorder" ) - .ContentPadding(FMargin(1,0)) - [ - SNew(SImage) - . Image( FEditorStyle::GetBrush("CrashTracker.Record") ) - ] - ] ]; } END_SLATE_FUNCTION_BUILD_OPTIMIZATION diff --git a/Engine/Source/Editor/MaterialEditor/Private/FindInMaterial.cpp b/Engine/Source/Editor/MaterialEditor/Private/FindInMaterial.cpp index bb1f2d13b990..d16d1495325e 100644 --- a/Engine/Source/Editor/MaterialEditor/Private/FindInMaterial.cpp +++ b/Engine/Source/Editor/MaterialEditor/Private/FindInMaterial.cpp @@ -71,7 +71,7 @@ TSharedRef FFindInMaterialResult::CreateIcon() const const FSlateBrush* Brush = NULL; if (UEdGraphPin* ResolvedPin = Pin.Get()) { - if (ResolvedPin->PinType.bIsArray) + if (ResolvedPin->PinType.IsArray()) { Brush = FEditorStyle::GetBrush(TEXT("GraphEditor.ArrayPinIcon")); } diff --git a/Engine/Source/Editor/MaterialEditor/Private/MaterialEditingLibrary.cpp b/Engine/Source/Editor/MaterialEditor/Private/MaterialEditingLibrary.cpp new file mode 100644 index 000000000000..d8b26ab38aa6 --- /dev/null +++ b/Engine/Source/Editor/MaterialEditor/Private/MaterialEditingLibrary.cpp @@ -0,0 +1,299 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + + +#include "MaterialEditingLibrary.h" +#include "MaterialEditor.h" +#include "MaterialGraph/MaterialGraphNode.h" +#include "Materials/MaterialExpressionTextureBase.h" +#include "Materials/MaterialExpressionCollectionParameter.h" +#include "Materials/MaterialExpressionFunctionInput.h" +#include "Materials/MaterialExpressionFunctionOutput.h" +#include "Materials/MaterialExpressionComponentMask.h" +#include "Materials/MaterialExpressionStaticComponentMaskParameter.h" +#include "Materials/MaterialExpressionTransformPosition.h" +#include "Materials/MaterialExpressionDynamicParameter.h" +#include "Materials/MaterialParameterCollection.h" + + +DEFINE_LOG_CATEGORY_STATIC(LogMaterialEditingLibrary, Warning, All); + +/** Util to find expression */ +static FExpressionInput* GetExpressionInputByName(UMaterialExpression* Expression, const FString& InputName) +{ + check(Expression); + FExpressionInput* Result = nullptr; + + TArray Inputs = Expression->GetInputs(); + + // Return first input if no name specified + if (InputName.IsEmpty()) + { + if (Inputs.Num() > 0) + { + return Inputs[0]; + } + } + else + { + // Get all inputs + // Get name of each input, see if its the one we want + for (int InputIdx = 0; InputIdx < Inputs.Num(); InputIdx++) + { + FString TestName = Expression->GetInputName(InputIdx); + TestName = UMaterialGraphNode::GetShortenPinName(TestName); + if (TestName == InputName) + { + Result = Inputs[InputIdx]; + break; + } + } + } + + return Result; +} + +static int32 GetExpressionOutputIndexByName(UMaterialExpression* Expression, const FString& OutputName) +{ + check(Expression); + + int32 Result = INDEX_NONE; + + if (Expression->Outputs.Num() == 0) + { + // leave as INDEX_NONE + } + // Return first output if no name specified + else if (OutputName.IsEmpty()) + { + Result = 0; + } + else + { + // Iterate over outputs and look for name match + for (int OutIdx = 0; OutIdx < Expression->Outputs.Num(); OutIdx++) + { + bool bFoundMatch = false; + + FExpressionOutput& Output = Expression->Outputs[OutIdx]; + // If output name is no empty - see if it matches + if(!Output.OutputName.IsEmpty()) + { + if (OutputName == Output.OutputName) + { + bFoundMatch = true; + } + } + // if it is empty we look for R/G/B/A + else + { + if (OutputName == TEXT("R") && Output.MaskR && !Output.MaskG && !Output.MaskB && !Output.MaskA) + { + bFoundMatch = true; + } + else if (OutputName == TEXT("G") && !Output.MaskR && Output.MaskG && !Output.MaskB && !Output.MaskA) + { + bFoundMatch = true; + } + else if (OutputName == TEXT("B") && !Output.MaskR && !Output.MaskG && Output.MaskB && !Output.MaskA) + { + bFoundMatch = true; + } + else if (OutputName == TEXT("A") && !Output.MaskR && !Output.MaskG && !Output.MaskB && Output.MaskA) + { + bFoundMatch = true; + } + } + + // Got a match, remember the index, exit iteration + if (bFoundMatch) + { + Result = OutIdx; + break; + } + } + } + + return Result; +} + +int32 UMaterialEditingLibrary::GetNumExpressions(const UMaterial* Material) +{ + int32 Result = 0; + if (Material) + { + Result = Material->Expressions.Num(); + } + return Result; +} + +UMaterialExpression* UMaterialEditingLibrary::CreateMaterialExpression(UMaterial* Material, TSubclassOf ExpressionClass, int32 NodePosX, int32 NodePosY) +{ + return CreateMaterialExpressionEx(Material, nullptr, ExpressionClass, nullptr, NodePosX, NodePosY); +} + +UMaterialExpression* UMaterialEditingLibrary::CreateMaterialExpressionEx(UMaterial* Material, UMaterialFunction* MaterialFunction, TSubclassOf ExpressionClass, UObject* SelectedAsset, int32 NodePosX, int32 NodePosY) +{ + UMaterialExpression* NewExpression = nullptr; + if (Material) + { + UObject* ExpressionOuter = Material; + if (MaterialFunction) + { + ExpressionOuter = MaterialFunction; + } + + NewExpression = NewObject(ExpressionOuter, ExpressionClass.Get(), NAME_None, RF_Transactional); + Material->Expressions.Add(NewExpression); + NewExpression->Material = Material; + + NewExpression->MaterialExpressionEditorX = NodePosX; + NewExpression->MaterialExpressionEditorY = NodePosY; + + // Create a GUID for the node + NewExpression->UpdateMaterialExpressionGuid(true, true); + + if (SelectedAsset) + { + // If the user is adding a texture, automatically assign the currently selected texture to it. + UMaterialExpressionTextureBase* METextureBase = Cast(NewExpression); + if (METextureBase) + { + if (UTexture* SelectedTexture = Cast(SelectedAsset)) + { + METextureBase->Texture = SelectedTexture; + } + METextureBase->AutoSetSampleType(); + } + + UMaterialExpressionMaterialFunctionCall* MEMaterialFunction = Cast(NewExpression); + if (MEMaterialFunction) + { + MEMaterialFunction->SetMaterialFunction(MaterialFunction, NULL, Cast(SelectedAsset)); + } + + UMaterialExpressionCollectionParameter* MECollectionParameter = Cast(NewExpression); + if (MECollectionParameter) + { + MECollectionParameter->Collection = Cast(SelectedAsset); + } + } + + UMaterialExpressionFunctionInput* FunctionInput = Cast(NewExpression); + if (FunctionInput) + { + FunctionInput->ConditionallyGenerateId(true); + FunctionInput->ValidateName(); + } + + UMaterialExpressionFunctionOutput* FunctionOutput = Cast(NewExpression); + if (FunctionOutput) + { + FunctionOutput->ConditionallyGenerateId(true); + FunctionOutput->ValidateName(); + } + + NewExpression->UpdateParameterGuid(true, true); + + if (NewExpression->HasAParameterName()) + { + NewExpression->ValidateParameterName(); + } + + UMaterialExpressionComponentMask* ComponentMaskExpression = Cast(NewExpression); + // Setup defaults for the most likely use case + // Can't change default properties as that will affect existing content + if (ComponentMaskExpression) + { + ComponentMaskExpression->R = true; + ComponentMaskExpression->G = true; + } + + UMaterialExpressionStaticComponentMaskParameter* StaticComponentMaskExpression = Cast(NewExpression); + // Setup defaults for the most likely use case + // Can't change default properties as that will affect existing content + if (StaticComponentMaskExpression) + { + StaticComponentMaskExpression->DefaultR = true; + } + + // Setup defaults for the most likely use case + // Can't change default properties as that will affect existing content + UMaterialExpressionTransformPosition* PositionTransform = Cast(NewExpression); + if (PositionTransform) + { + PositionTransform->TransformSourceType = TRANSFORMPOSSOURCE_Local; + PositionTransform->TransformType = TRANSFORMPOSSOURCE_World; + } + + // Make sure the dynamic parameters are named based on existing ones + UMaterialExpressionDynamicParameter* DynamicExpression = Cast(NewExpression); + if (DynamicExpression) + { + DynamicExpression->UpdateDynamicParameterProperties(); + } + + Material->AddExpressionParameter(NewExpression, Material->EditorParameters); + + Material->MarkPackageDirty(); + } + return NewExpression; +} + +bool UMaterialEditingLibrary::SetMaterialUsage(UMaterial* Material, EMaterialUsage Usage, bool& bNeedsRecompile) +{ + bool bResult = false; + bNeedsRecompile = false; + if (Material) + { + bResult = Material->SetMaterialUsage(bNeedsRecompile, Usage); + } + return bResult; +} + +bool UMaterialEditingLibrary::ConnectMaterialProperty(UMaterialExpression* FromExpression, FString FromOutputName, EMaterialProperty Property) +{ + bool bResult = false; + if (FromExpression) + { + // Get material that owns this expression + UMaterial* Material = Cast(FromExpression->GetOuter()); + if (Material) + { + FExpressionInput* Input = Material->GetExpressionInputForProperty(Property); + int32 FromIndex = GetExpressionOutputIndexByName(FromExpression, FromOutputName); + if (Input && FromIndex != INDEX_NONE) + { + Input->Connect(FromIndex, FromExpression); + bResult = true; + } + } + } + return bResult; +} + +bool UMaterialEditingLibrary::ConnectMaterialExpressions(UMaterialExpression* FromExpression, FString FromOutputName, UMaterialExpression* ToExpression, FString ToInputName) +{ + bool bResult = false; + if (FromExpression && ToExpression) + { + FExpressionInput* Input = GetExpressionInputByName(ToExpression, ToInputName); + int32 FromIndex = GetExpressionOutputIndexByName(FromExpression, FromOutputName); + if (Input && FromIndex != INDEX_NONE) + { + Input->Connect(FromIndex, FromExpression); + bResult = true; + } + } + return bResult; +} + +void UMaterialEditingLibrary::RecompileMaterial(UMaterial* Material) +{ + FMaterialUpdateContext UpdateContext; + + UpdateContext.AddMaterial(Material); + + // Propagate the change to this material + Material->PreEditChange(NULL); + Material->PostEditChange(); +} \ No newline at end of file diff --git a/Engine/Source/Editor/MaterialEditor/Private/MaterialEditor.cpp b/Engine/Source/Editor/MaterialEditor/Private/MaterialEditor.cpp index 5478eabe02be..7d570453348b 100644 --- a/Engine/Source/Editor/MaterialEditor/Private/MaterialEditor.cpp +++ b/Engine/Source/Editor/MaterialEditor/Private/MaterialEditor.cpp @@ -34,6 +34,7 @@ #include "UnrealEdGlobals.h" #include "Editor.h" #include "MaterialEditorModule.h" +#include "MaterialEditingLibrary.h" #include "Materials/MaterialExpressionBreakMaterialAttributes.h" @@ -303,6 +304,9 @@ void FMaterialEditor::InitEditorForMaterial(UMaterial* InMaterial) Material->Expressions.RemoveAt(ExpressionIndex); } } + + TArray Groups; + GetAllMaterialExpressionGroups(&Groups); } void FMaterialEditor::InitEditorForMaterialFunction(UMaterialFunction* InMaterialFunction) @@ -330,6 +334,9 @@ void FMaterialEditor::InitEditorForMaterialFunction(UMaterialFunction* InMateria MaterialFunction->ParentFunction = InMaterialFunction; OriginalMaterial = Material; + + TArray Groups; + GetAllMaterialExpressionGroups(&Groups); } void FMaterialEditor::InitMaterialEditor( const EToolkitMode::Type Mode, const TSharedPtr< class IToolkitHost >& InitToolkitHost, UObject* ObjectToEdit ) @@ -639,14 +646,17 @@ void FMaterialEditor::GetAllMaterialExpressionGroups(TArray* OutGroups) if(Switch) { OutGroups->AddUnique(Switch->Group.ToString()); + Material->AttemptInsertNewGroupName(Switch->Group.ToString()); } if(TextureS) { OutGroups->AddUnique(TextureS->Group.ToString()); + Material->AttemptInsertNewGroupName(TextureS->Group.ToString()); } if(FontS) { OutGroups->AddUnique(FontS->Group.ToString()); + Material->AttemptInsertNewGroupName(FontS->Group.ToString()); } } } @@ -2749,7 +2759,7 @@ void FMaterialEditor::OnMaterialUsageFlagsChanged(UMaterial* MaterialThatChanged if(MaterialThatChanged == OriginalMaterial) { bool bNeedsRecompile = false; - Material->SetMaterialUsage(bNeedsRecompile, Flag, MaterialThatChanged->GetUsageByFlag(Flag)); + Material->SetMaterialUsage(bNeedsRecompile, Flag); UpdateStatsMaterials(); } } @@ -3055,7 +3065,7 @@ void FMaterialEditor::SetPreviewExpression(UMaterialExpression* NewPreviewExpres // Recompile the preview material to get changes that might have been made during previewing UpdatePreviewMaterial(); } - else if (NewPreviewExpression) + else { if( ExpressionPreviewMaterial == NULL ) { @@ -3124,107 +3134,13 @@ UMaterialExpression* FMaterialEditor::CreateNewMaterialExpression(UClass* NewExp const FScopedTransaction Transaction( NSLOCTEXT("UnrealEd", "MaterialEditorNewExpression", "Material Editor: New Expression") ); Material->Modify(); - UObject* ExpressionOuter = Material; - if (MaterialFunction) - { - ExpressionOuter = MaterialFunction; - } - - NewExpression = NewObject(ExpressionOuter, NewExpressionClass, NAME_None, RF_Transactional); - Material->Expressions.Add( NewExpression ); - NewExpression->Material = Material; - - // Set the expression location. - NewExpression->MaterialExpressionEditorX = NodePos.X; - NewExpression->MaterialExpressionEditorY = NodePos.Y; - - // Create a GUID for the node - NewExpression->UpdateMaterialExpressionGuid(true, true); - + UObject* SelectedAsset = nullptr; if (bAutoAssignResource) { - // If the user is adding a texture, automatically assign the currently selected texture to it. - UMaterialExpressionTextureBase* METextureBase = Cast( NewExpression ); - if( METextureBase ) - { - FEditorDelegates::LoadSelectedAssetsIfNeeded.Broadcast(); - if( UTexture* SelectedTexture = GEditor->GetSelectedObjects()->GetTop() ) - { - METextureBase->Texture = SelectedTexture; - } - METextureBase->AutoSetSampleType(); - } - - UMaterialExpressionMaterialFunctionCall* MEMaterialFunction = Cast( NewExpression ); - if( MEMaterialFunction ) - { - FEditorDelegates::LoadSelectedAssetsIfNeeded.Broadcast(); - MEMaterialFunction->SetMaterialFunction(MaterialFunction, NULL, GEditor->GetSelectedObjects()->GetTop()); - } - - UMaterialExpressionCollectionParameter* MECollectionParameter = Cast( NewExpression ); - if( MECollectionParameter ) - { - FEditorDelegates::LoadSelectedAssetsIfNeeded.Broadcast(); - MECollectionParameter->Collection = GEditor->GetSelectedObjects()->GetTop(); - } + SelectedAsset = GEditor->GetSelectedObjects()->GetTop(); } - UMaterialExpressionFunctionInput* FunctionInput = Cast( NewExpression ); - if( FunctionInput ) - { - FunctionInput->ConditionallyGenerateId(true); - FunctionInput->ValidateName(); - } - - UMaterialExpressionFunctionOutput* FunctionOutput = Cast( NewExpression ); - if( FunctionOutput ) - { - FunctionOutput->ConditionallyGenerateId(true); - FunctionOutput->ValidateName(); - } - - NewExpression->UpdateParameterGuid(true, true); - - if (NewExpression->HasAParameterName()) - { - NewExpression->ValidateParameterName(); - } - - UMaterialExpressionComponentMask* ComponentMaskExpression = Cast( NewExpression ); - // Setup defaults for the most likely use case - // Can't change default properties as that will affect existing content - if( ComponentMaskExpression ) - { - ComponentMaskExpression->R = true; - ComponentMaskExpression->G = true; - } - - UMaterialExpressionStaticComponentMaskParameter* StaticComponentMaskExpression = Cast( NewExpression ); - // Setup defaults for the most likely use case - // Can't change default properties as that will affect existing content - if( StaticComponentMaskExpression ) - { - StaticComponentMaskExpression->DefaultR = true; - } - - // Setup defaults for the most likely use case - // Can't change default properties as that will affect existing content - UMaterialExpressionTransformPosition* PositionTransform = Cast(NewExpression); - if (PositionTransform) - { - PositionTransform->TransformSourceType = TRANSFORMPOSSOURCE_Local; - PositionTransform->TransformType = TRANSFORMPOSSOURCE_World; - } - - // Make sure the dynamic parameters are named based on existing ones - UMaterialExpressionDynamicParameter* DynamicExpression = Cast(NewExpression); - if (DynamicExpression) - { - DynamicExpression->UpdateDynamicParameterProperties(); - } - - Material->AddExpressionParameter(NewExpression, Material->EditorParameters); + NewExpression = UMaterialEditingLibrary::CreateMaterialExpressionEx(Material, MaterialFunction, NewExpressionClass, SelectedAsset, NodePos.X, NodePos.Y); if (NewExpression) { diff --git a/Engine/Source/Editor/MaterialEditor/Private/MaterialEditorDetailCustomization.cpp b/Engine/Source/Editor/MaterialEditor/Private/MaterialEditorDetailCustomization.cpp index ecf3f5cb9dbd..01dad9589ee3 100644 --- a/Engine/Source/Editor/MaterialEditor/Private/MaterialEditorDetailCustomization.cpp +++ b/Engine/Source/Editor/MaterialEditor/Private/MaterialEditorDetailCustomization.cpp @@ -96,7 +96,7 @@ void FMaterialExpressionParameterDetails::CustomizeDetails( IDetailLayoutBuilder .ValueContent() [ SAssignNew(NewComboButton, SComboButton) - .ContentPadding(0) + .ContentPadding(FMargin(2.0f, 2.0f)) .ButtonContent() [ SAssignNew(NewEditBox, SEditableText) @@ -118,6 +118,9 @@ void FMaterialExpressionParameterDetails::CustomizeDetails( IDetailLayoutBuilder ] ]; + + Category.AddProperty("SortPriority"); + GroupComboButton = NewComboButton; GroupEditBox = NewEditBox; GroupListView = NewListView; @@ -127,6 +130,9 @@ void FMaterialExpressionParameterDetails::PopulateGroups() { TArray Groups; CollectGroupsDelegate.ExecuteIfBound(&Groups); + Groups.Sort([&](const FString& A, const FString& B) { + return A.ToLower() < B.ToLower(); + }); GroupsSource.Empty(); for (int32 GroupIdx = 0; GroupIdx < Groups.Num(); ++GroupIdx) diff --git a/Engine/Source/Editor/MaterialEditor/Private/MaterialEditorInstanceDetailCustomization.cpp b/Engine/Source/Editor/MaterialEditor/Private/MaterialEditorInstanceDetailCustomization.cpp index 8831ceb7677a..5246cd762344 100644 --- a/Engine/Source/Editor/MaterialEditor/Private/MaterialEditorInstanceDetailCustomization.cpp +++ b/Engine/Source/Editor/MaterialEditor/Private/MaterialEditorInstanceDetailCustomization.cpp @@ -208,13 +208,17 @@ void FMaterialInstanceParameterDetails::CreateParameterValueWidget(UDEditorParam IDetailPropertyRow& PropertyRow = DetailGroup.AddPropertyRow( ParameterValueProperty.ToSharedRef() ); + FIsResetToDefaultVisible IsResetVisible = FIsResetToDefaultVisible::CreateSP(this, &FMaterialInstanceParameterDetails::ShouldShowResetToDefault, Parameter); + FResetToDefaultHandler ResetHandler = FResetToDefaultHandler::CreateSP(this, &FMaterialInstanceParameterDetails::ResetToDefault, Parameter); + FResetToDefaultOverride ResetOverride = FResetToDefaultOverride::Create(IsResetVisible, ResetHandler); + PropertyRow .DisplayName( FText::FromName(Parameter->ParameterName) ) .ToolTip( GetParameterExpressionDescription(Parameter) ) .EditCondition( IsParamEnabled, FOnBooleanValueChanged::CreateSP( this, &FMaterialInstanceParameterDetails::OnOverrideParameter, Parameter ) ) .Visibility( TAttribute::Create(TAttribute::FGetter::CreateSP(this, &FMaterialInstanceParameterDetails::ShouldShowExpression, Parameter)) ) // Handle reset to default manually - .OverrideResetToDefault(FResetToDefaultOverride::Create(FResetToDefaultHandler::CreateSP(this, &FMaterialInstanceParameterDetails::ResetToDefault, Parameter))); + .OverrideResetToDefault(ResetOverride); } } @@ -454,6 +458,93 @@ void FMaterialInstanceParameterDetails::ResetToDefault(TSharedRef PropertyHandle, class UDEditorParameterValue* Parameter) +{ + FName ParameterName = Parameter->ParameterName; + + UDEditorFontParameterValue* FontParam = Cast(Parameter); + UDEditorScalarParameterValue* ScalarParam = Cast(Parameter); + UDEditorStaticComponentMaskParameterValue* CompMaskParam = Cast(Parameter); + UDEditorStaticSwitchParameterValue* SwitchParam = Cast(Parameter); + UDEditorTextureParameterValue* TextureParam = Cast(Parameter); + UDEditorVectorParameterValue* VectorParam = Cast(Parameter); + + if (ScalarParam) + { + float OutValue; + if (MaterialEditorInstance->Parent->GetScalarParameterValue(ParameterName, OutValue)) + { + if (ScalarParam->ParameterValue != OutValue) + { + return true; + } + } + } + else if (FontParam) + { + UFont* OutFontValue; + int32 OutFontPage; + if (MaterialEditorInstance->Parent->GetFontParameterValue(ParameterName, OutFontValue, OutFontPage)) + { + if (FontParam->ParameterValue.FontValue != OutFontValue || + FontParam->ParameterValue.FontPage != OutFontPage) + { + return true; + } + } + } + else if (TextureParam) + { + UTexture* OutValue; + if (MaterialEditorInstance->Parent->GetTextureParameterValue(ParameterName, OutValue)) + { + if (TextureParam->ParameterValue != OutValue) + { + return true; + } + } + } + else if (VectorParam) + { + FLinearColor OutValue; + if (MaterialEditorInstance->Parent->GetVectorParameterValue(ParameterName, OutValue)) + { + if (VectorParam->ParameterValue != OutValue) + { + return true; + } + } + } + else if (SwitchParam) + { + bool OutValue; + FGuid TempGuid(0, 0, 0, 0); + if (MaterialEditorInstance->Parent->GetStaticSwitchParameterValue(ParameterName, OutValue, TempGuid)) + { + if (SwitchParam->ParameterValue != OutValue) + { + return true; + } + } + } + else if (CompMaskParam) + { + bool OutValue[4]; + FGuid TempGuid(0, 0, 0, 0); + if (MaterialEditorInstance->Parent->GetStaticComponentMaskParameterValue(ParameterName, OutValue[0], OutValue[1], OutValue[2], OutValue[3], TempGuid)) + { + if (CompMaskParam->ParameterValue.R != OutValue[0] || + CompMaskParam->ParameterValue.G != OutValue[1] || + CompMaskParam->ParameterValue.B != OutValue[2] || + CompMaskParam->ParameterValue.A != OutValue[3]) + { + return true; + } + } + } + return false; +} + EVisibility FMaterialInstanceParameterDetails::ShouldShowMaterialRefractionSettings() const { return (MaterialEditorInstance->SourceInstance->GetMaterial()->bUsesDistortion && IsTranslucentBlendMode(MaterialEditorInstance->SourceInstance->GetBlendMode())) ? EVisibility::Visible : EVisibility::Collapsed; diff --git a/Engine/Source/Editor/MaterialEditor/Private/MaterialEditorInstanceDetailCustomization.h b/Engine/Source/Editor/MaterialEditor/Private/MaterialEditorInstanceDetailCustomization.h index e7949dc1de62..8abd5d624b01 100644 --- a/Engine/Source/Editor/MaterialEditor/Private/MaterialEditorInstanceDetailCustomization.h +++ b/Engine/Source/Editor/MaterialEditor/Private/MaterialEditorInstanceDetailCustomization.h @@ -69,6 +69,9 @@ private: /** Reset to default implementation. Resets Parameter to default */ void ResetToDefault(TSharedRef PropertyHandle, class UDEditorParameterValue* Parameter); + /** If reset to default button should show */ + bool ShouldShowResetToDefault(TSharedRef PropertyHandle, class UDEditorParameterValue* Parameter); + /** Returns true if the refraction options should be displayed */ EVisibility ShouldShowMaterialRefractionSettings() const; diff --git a/Engine/Source/Editor/MaterialEditor/Private/MaterialExpressionClasses.cpp b/Engine/Source/Editor/MaterialEditor/Private/MaterialExpressionClasses.cpp index 578bf11c6430..ddd96897ebf9 100644 --- a/Engine/Source/Editor/MaterialEditor/Private/MaterialExpressionClasses.cpp +++ b/Engine/Source/Editor/MaterialEditor/Private/MaterialExpressionClasses.cpp @@ -51,13 +51,10 @@ FCategorizedMaterialExpressionNode* MaterialExpressionClasses::GetCategoryNode(c { for (int32 CheckIndex = 0; CheckIndex < CategorizedExpressionClasses.Num(); CheckIndex++) { - FCategorizedMaterialExpressionNode* CheckNode = &(CategorizedExpressionClasses[CheckIndex]); - if (CheckNode) + FCategorizedMaterialExpressionNode& CheckNode = CategorizedExpressionClasses[CheckIndex]; + if (CheckNode.CategoryName.EqualTo(InCategoryName)) { - if (CheckNode->CategoryName.EqualTo(InCategoryName)) - { - return CheckNode; - } + return &CheckNode; } } diff --git a/Engine/Source/Editor/MaterialEditor/Private/MaterialInstanceEditor.cpp b/Engine/Source/Editor/MaterialEditor/Private/MaterialInstanceEditor.cpp index 0558b098ba04..e8ee13fb450b 100644 --- a/Engine/Source/Editor/MaterialEditor/Private/MaterialInstanceEditor.cpp +++ b/Engine/Source/Editor/MaterialEditor/Private/MaterialInstanceEditor.cpp @@ -246,13 +246,26 @@ void FMaterialInstanceEditor::InitMaterialInstanceEditor( const EToolkitMode::Ty LoadSettings(); // Set the preview mesh for the material. This call must occur after the toolbar is initialized. - USceneThumbnailInfoWithPrimitive* ThumbnailInfoWithPrim = Cast(InstanceConstant->ThumbnailInfo); - if ( ThumbnailInfoWithPrim ) + + if ( !SetPreviewAssetByName( *InstanceConstant->PreviewMesh.ToString() ) ) { - InstanceConstant->PreviewMesh = ThumbnailInfoWithPrim->PreviewMesh; + // If the preview mesh could not be found for this instance, attempt to use the preview mesh for the parent material if one exists, + // or use a default instead if the parent's preview mesh cannot be used + + if ( InstanceConstant->Parent == nullptr || !SetPreviewAssetByName( *InstanceConstant->Parent->PreviewMesh.ToString() ) ) + { + USceneThumbnailInfoWithPrimitive* ThumbnailInfoWithPrim = Cast( InstanceConstant->ThumbnailInfo ); + + if ( ThumbnailInfoWithPrim != nullptr ) + { + SetPreviewAssetByName( *ThumbnailInfoWithPrim->PreviewMesh.ToString() ); + } + } } - SetPreviewAssetByName(*InstanceConstant->PreviewMesh.ToString()); + + Refresh(); } + FMaterialInstanceEditor::FMaterialInstanceEditor() : MaterialEditorInstance(nullptr) , MenuExtensibilityManager(new FExtensibilityManager) @@ -705,20 +718,7 @@ void FMaterialInstanceEditor::NotifyPostChange( const FPropertyChangedEvent& Pro } else if(PropertyThatChanged->GetName() == TEXT("PreviewMesh")) { - UObject* PreviewAsset = MaterialEditorInstance->SourceInstance->PreviewMesh.TryLoad(); - if(!PreviewAsset) - { - // Just default to the sphere if the preview asset is null or missing - PreviewAsset = GUnrealEd->GetThumbnailManager()->EditorSphere; - - USceneThumbnailInfoWithPrimitive* ThumbnailInfo = Cast(MaterialEditorInstance->SourceInstance->ThumbnailInfo); - if (ThumbnailInfo) - { - ThumbnailInfo->PreviewMesh.Reset(); - } - - } - PreviewVC->SetPreviewAsset(PreviewAsset); + RefreshPreviewAsset(); } //rebuild the property window to account for the possibility that the item changed was @@ -736,6 +736,28 @@ void FMaterialInstanceEditor::NotifyPostChange( const FPropertyChangedEvent& Pro PreviewVC->RefreshViewport(); } +void FMaterialInstanceEditor::RefreshPreviewAsset() +{ + UObject* PreviewAsset = MaterialEditorInstance->SourceInstance->PreviewMesh.TryLoad(); + if (!PreviewAsset) + { + // Attempt to use the parent material's preview mesh if the instance's preview mesh is invalid, and use a default + // sphere instead if the parent's mesh is also invalid + UMaterialInterface* ParentMaterial = MaterialEditorInstance->SourceInstance->Parent; + + UObject* ParentPreview = ParentMaterial != nullptr ? ParentMaterial->PreviewMesh.TryLoad() : nullptr; + PreviewAsset = ParentPreview != nullptr ? ParentPreview : GUnrealEd->GetThumbnailManager()->EditorSphere; + + USceneThumbnailInfoWithPrimitive* ThumbnailInfo = Cast(MaterialEditorInstance->SourceInstance->ThumbnailInfo); + if (ThumbnailInfo) + { + ThumbnailInfo->PreviewMesh.Reset(); + } + + } + PreviewVC->SetPreviewAsset(PreviewAsset); +} + void FMaterialInstanceEditor::PreSavePackage(UPackage* Package) { // The streaming data will be null if there were any edits @@ -1041,12 +1063,14 @@ void FMaterialInstanceEditor::Refresh() void FMaterialInstanceEditor::PostUndo( bool bSuccess ) { MaterialEditorInstance->CopyToSourceInstance(); + RefreshPreviewAsset(); Refresh(); } void FMaterialInstanceEditor::PostRedo( bool bSuccess ) { MaterialEditorInstance->CopyToSourceInstance(); + RefreshPreviewAsset(); Refresh(); } diff --git a/Engine/Source/Editor/MaterialEditor/Private/MaterialInstanceEditor.h b/Engine/Source/Editor/MaterialEditor/Private/MaterialInstanceEditor.h index 775efc24d919..49380cadb77b 100644 --- a/Engine/Source/Editor/MaterialEditor/Private/MaterialInstanceEditor.h +++ b/Engine/Source/Editor/MaterialEditor/Private/MaterialInstanceEditor.h @@ -162,6 +162,9 @@ private: /** Refresh the viewport and property window */ void Refresh(); + /** Refreshes the preview asset */ + void RefreshPreviewAsset(); + //~ Begin FEditorUndoClient Interface virtual void PostUndo( bool bSuccess ) override; virtual void PostRedo( bool bSuccess ) override; diff --git a/Engine/Source/Editor/MaterialEditor/Public/MaterialEditingLibrary.h b/Engine/Source/Editor/MaterialEditor/Public/MaterialEditingLibrary.h new file mode 100644 index 000000000000..7332bd14e395 --- /dev/null +++ b/Engine/Source/Editor/MaterialEditor/Public/MaterialEditingLibrary.h @@ -0,0 +1,80 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "Classes/Kismet/BlueprintFunctionLibrary.h" +#include "Materials/MaterialInterface.h" +#include "SceneTypes.h" + +#include "MaterialEditingLibrary.generated.h" + +class UMaterialFunction; + +/** Blueprint library for creating/editing Materials */ +UCLASS() +class MATERIALEDITOR_API UMaterialEditingLibrary : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() + +public: + /** Returns number of material expressions in the supplied material */ + UFUNCTION(BlueprintPure, Category = "MaterialEditing") + static int32 GetNumExpressions(const UMaterial* Material); + + /** + * Create a new material expression node within the supplied material + * @param Material Material asset to add an expression to + * @param ExpressionClass Class of expression to add + * @param NodePosX X position of new expression node + * @param NodePosY Y position of new expression node + */ + UFUNCTION(BlueprintCallable, Category = "MaterialEditing") + static UMaterialExpression* CreateMaterialExpression(UMaterial* Material, TSubclassOf ExpressionClass, int32 NodePosX=0, int32 NodePosY=0); + + /** + * Create a new material expression node within the supplied material, optionally specifying asset to use + * @param Material Material asset to add an expression to + * @param MaterialFunction Specified if adding an expression to a MaterialFunction, used as Outer for new expression object + * @param SelectedAsset If specified, new node will attempt to use this asset, if of the appropriate type (e.g. Texture for a TextureSampler) + * @param ExpressionClass Class of expression to add + * @param NodePosX X position of new expression node + * @param NodePosY Y position of new expression node + */ + static UMaterialExpression* CreateMaterialExpressionEx(UMaterial* Material, UMaterialFunction* MaterialFunction, TSubclassOf ExpressionClass, UObject* SelectedAsset = nullptr, int32 NodePosX=0, int32 NodePosY=0); + + /** + * Enable a particular usage for the supplied material (e.g. SkeletalMesh, ParticleSprite etc) + * @param Material Material to change usage for + * @param Usage New usage type to enable for this material + * @param bNeedsRecompile Returned to indicate if material needs recompiling after this change + */ + UFUNCTION(BlueprintCallable, Category = "MaterialEditing") + static bool SetMaterialUsage(UMaterial* Material, EMaterialUsage Usage, bool& bNeedsRecompile); + + /** + * Connect a material expression output to one of the material property inputs (e.g. diffuse color, opacity etc) + * @param FromExpression Expression to make connection from + * @param FromOutputName Name of output of FromExpression to make connection from + * @param Property Property input on material to make connection to + */ + UFUNCTION(BlueprintCallable, Category = "MaterialEditing") + static bool ConnectMaterialProperty(UMaterialExpression* FromExpression, FString FromOutputName, EMaterialProperty Property); + + /** + * Create connection between two material expressions + * @param FromExpression Expression to make connection from + * @param FromOutputName Name of output of FromExpression to make connection from. Leave empty to use first output. + * @param ToExpression Expression to make connection to + * @param ToInputName Name of input of ToExpression to make connection to. Leave empty to use first input. + */ + UFUNCTION(BlueprintCallable, Category = "MaterialEditing") + static bool ConnectMaterialExpressions(UMaterialExpression* FromExpression, FString FromOutputName, UMaterialExpression* ToExpression, FString ToInputName); + + /** + * Trigger a recompile of a material. Must be performed after making changes to the graph to have changes reflected. + */ + UFUNCTION(BlueprintCallable, Category = "MaterialEditing") + static void RecompileMaterial(UMaterial* Material); + + +}; \ No newline at end of file diff --git a/Engine/Source/Editor/MeshPaint/Private/BaseMeshPaintGeometryAdapter.cpp b/Engine/Source/Editor/MeshPaint/Private/BaseMeshPaintGeometryAdapter.cpp index a9b3d63ec935..483eccf4596a 100644 --- a/Engine/Source/Editor/MeshPaint/Private/BaseMeshPaintGeometryAdapter.cpp +++ b/Engine/Source/Editor/MeshPaint/Private/BaseMeshPaintGeometryAdapter.cpp @@ -95,7 +95,7 @@ TArray FBaseMeshPaintGeometryAdapter::SphereIntersectTriangles(const flo void FBaseMeshPaintGeometryAdapter::GetInfluencedVertexIndices(const float ComponentSpaceSquaredBrushRadius, const FVector& ComponentSpaceBrushPosition, const FVector& ComponentSpaceCameraPosition, const bool bOnlyFrontFacing, TSet &InfluencedVertices) const { // Get a list of (optionally front-facing) triangles that are within a reasonable distance to the brush - TArray InfluencedTriangles = SphereIntersectTriangles( + const TArray InfluencedTriangles = SphereIntersectTriangles( ComponentSpaceSquaredBrushRadius, ComponentSpaceBrushPosition, ComponentSpaceCameraPosition, @@ -106,7 +106,7 @@ void FBaseMeshPaintGeometryAdapter::GetInfluencedVertexIndices(const float Compo check(NumIndexBufferIndices % 3 == 0); InfluencedVertices.Reserve(InfluencedTriangles.Num()); - for (int32 InfluencedTriangle : InfluencedTriangles) + for (const int32 InfluencedTriangle : InfluencedTriangles) { for (int32 Index = 0; Index < 3; ++Index) { @@ -119,6 +119,36 @@ void FBaseMeshPaintGeometryAdapter::GetInfluencedVertexIndices(const float Compo } } +void FBaseMeshPaintGeometryAdapter::GetInfluencedVertexData(const float ComponentSpaceSquaredBrushRadius, const FVector& ComponentSpaceBrushPosition, const FVector& ComponentSpaceCameraPosition, const bool bOnlyFrontFacing, TArray>& OutData) const +{ + // Get a list of (optionally front-facing) triangles that are within a reasonable distance to the brush + TArray InfluencedTriangles = SphereIntersectTriangles( + ComponentSpaceSquaredBrushRadius, + ComponentSpaceBrushPosition, + ComponentSpaceCameraPosition, + bOnlyFrontFacing); + + // Make sure we're dealing with triangle lists + const int32 NumIndexBufferIndices = MeshIndices.Num(); + check(NumIndexBufferIndices % 3 == 0); + + OutData.Reserve(InfluencedTriangles.Num() * 3); + for(int32 InfluencedTriangle : InfluencedTriangles) + { + for(int32 Index = 0; Index < 3; ++Index) + { + const FVector& VertexPosition = MeshVertices[MeshIndices[InfluencedTriangle * 3 + Index]]; + if((VertexPosition - ComponentSpaceBrushPosition).SizeSquared() <= ComponentSpaceSquaredBrushRadius) + { + OutData.AddDefaulted(); + TPair& OutPair = OutData.Last(); + OutPair.Key = MeshIndices[InfluencedTriangle * 3 + Index]; + OutPair.Value = MeshVertices[OutPair.Key]; + } + } + } +} + TArray FBaseMeshPaintGeometryAdapter::SphereIntersectVertices(const float ComponentSpaceSquaredBrushRadius, const FVector& ComponentSpaceBrushPosition, const FVector& ComponentSpaceCameraPosition, const bool bOnlyFrontFacing) const { // Get list of intersecting triangles with given sphere data diff --git a/Engine/Source/Editor/MeshPaint/Private/IMeshPainter.cpp b/Engine/Source/Editor/MeshPaint/Private/IMeshPainter.cpp index 6d8338ca5342..b98beb3e62df 100644 --- a/Engine/Source/Editor/MeshPaint/Private/IMeshPainter.cpp +++ b/Engine/Source/Editor/MeshPaint/Private/IMeshPainter.cpp @@ -27,6 +27,10 @@ IMeshPainter::IMeshPainter() FMeshPainterCommands::Register(); } +IMeshPainter::~IMeshPainter() +{ +} + void IMeshPainter::RenderInteractors(const FSceneView* View, FViewport* Viewport, FPrimitiveDrawInterface* PDI, bool bRenderVertices, ESceneDepthPriorityGroup DepthGroup/* = SDPG_World*/) { TArray PaintRays; @@ -90,7 +94,7 @@ void IMeshPainter::UnregisterCommands(TSharedRef CommandList) bool IMeshPainter::Paint(FViewport* Viewport, const FVector& InCameraOrigin, const FVector& InRayOrigin, const FVector& InRayDirection) { // Determine paint action according to whether or not shift is held down - const EMeshPaintAction PaintAction = (Viewport->KeyState(EKeys::LeftShift) || Viewport->KeyState(EKeys::LeftShift)) ? EMeshPaintAction::Erase : EMeshPaintAction::Paint; + const EMeshPaintAction PaintAction = (Viewport->KeyState(EKeys::LeftShift) || Viewport->KeyState(EKeys::RightShift)) ? EMeshPaintAction::Erase : EMeshPaintAction::Paint; const float PaintStrength = Viewport->IsPenActive() ? Viewport->GetTabletPressure() : 1.f; // Handle internal painting functionality diff --git a/Engine/Source/Editor/MeshPaint/Private/MeshPaintHelpers.cpp b/Engine/Source/Editor/MeshPaint/Private/MeshPaintHelpers.cpp index 370e0861351e..94648ab32acd 100644 --- a/Engine/Source/Editor/MeshPaint/Private/MeshPaintHelpers.cpp +++ b/Engine/Source/Editor/MeshPaint/Private/MeshPaintHelpers.cpp @@ -132,7 +132,7 @@ bool MeshPaintHelpers::PropagateColorsToRawMesh(UStaticMesh* StaticMesh, int32 L else { // If there's no raw mesh data, don't try to do any fixup here - if (SrcModel.RawMeshBulkData->IsEmpty()) + if (SrcModel.RawMeshBulkData->IsEmpty() || ComponentLODInfo.OverrideMapBuildData == nullptr) { return false; } @@ -819,7 +819,7 @@ void MeshPaintHelpers::FillVertexColors(UMeshComponent* MeshComponent, const FCo // allocated, and potentially accessing the UStaticMesh. Mesh->ReleaseResourcesFence.Wait(); - if (Mesh && Mesh->LODInfo.Num() > 0) + if (Mesh->LODInfo.Num() > 0) { RecreateRenderStateContext = MakeUnique(Mesh); const int32 NumLods = Mesh->LODInfo.Num(); @@ -1458,23 +1458,23 @@ FColor MeshPaintHelpers::PickVertexColorFromTextureData(const uint8* MipData, co return VertexColor; } -bool MeshPaintHelpers::ApplyPerVertexPaintAction(IMeshPaintGeometryAdapter* Adapter, const FVector& CameraPosition, const FVector& HitPosition, const UPaintBrushSettings* Settings, FPerVertexPaintAction Action) +bool MeshPaintHelpers::ApplyPerVertexPaintAction(FPerVertexPaintActionArgs& InArgs, FPerVertexPaintAction Action) { // Retrieve components world matrix - const FMatrix& ComponentToWorldMatrix = Adapter->GetComponentToWorldMatrix(); + const FMatrix& ComponentToWorldMatrix = InArgs.Adapter->GetComponentToWorldMatrix(); // Compute the camera position in actor space. We need this later to check for back facing triangles. - const FVector ComponentSpaceCameraPosition(ComponentToWorldMatrix.InverseTransformPosition(CameraPosition)); - const FVector ComponentSpaceBrushPosition(ComponentToWorldMatrix.InverseTransformPosition(HitPosition)); + const FVector ComponentSpaceCameraPosition(ComponentToWorldMatrix.InverseTransformPosition(InArgs.CameraPosition)); + const FVector ComponentSpaceBrushPosition(ComponentToWorldMatrix.InverseTransformPosition(InArgs.HitResult.Location)); // @todo MeshPaint: Input vector doesn't work well with non-uniform scale - const float BrushRadius = Settings->GetBrushRadius(); + const float BrushRadius = InArgs.BrushSettings->GetBrushRadius(); const float ComponentSpaceBrushRadius = ComponentToWorldMatrix.InverseTransformVector(FVector(BrushRadius, 0.0f, 0.0f)).Size(); const float ComponentSpaceSquaredBrushRadius = ComponentSpaceBrushRadius * ComponentSpaceBrushRadius; // Get a list of unique vertices indexed by the influenced triangles TSet InfluencedVertices; - Adapter->GetInfluencedVertexIndices(ComponentSpaceSquaredBrushRadius, ComponentSpaceBrushPosition, ComponentSpaceCameraPosition, Settings->bOnlyFrontFacingTriangles, InfluencedVertices); + InArgs.Adapter->GetInfluencedVertexIndices(ComponentSpaceSquaredBrushRadius, ComponentSpaceBrushPosition, ComponentSpaceCameraPosition, InArgs.BrushSettings->bOnlyFrontFacingTriangles, InfluencedVertices); const int32 NumParallelFors = 4; @@ -1488,14 +1488,18 @@ bool MeshPaintHelpers::ApplyPerVertexPaintAction(IMeshPaintGeometryAdapter* Adap for (int32 VertexIndex = Start; VertexIndex < End; ++VertexIndex) { - Action.Execute(Adapter, VertexIndex); + Action.ExecuteIfBound(Adapter, VertexIndex); } });*/ - - for (int32 VertexIndex : InfluencedVertices) + if (InfluencedVertices.Num()) { + InArgs.Adapter->PreEdit(); + for (const int32 VertexIndex : InfluencedVertices) + { // Apply the action! - Action.Execute(Adapter, VertexIndex); + Action.ExecuteIfBound(InArgs, VertexIndex); + } + InArgs.Adapter->PostEdit(); } return (InfluencedVertices.Num() > 0); diff --git a/Engine/Source/Editor/MeshPaint/Private/MeshPaintSkeletalMeshAdapter.cpp b/Engine/Source/Editor/MeshPaint/Private/MeshPaintSkeletalMeshAdapter.cpp index cc5a862f2f7d..3d57db0cc0e5 100644 --- a/Engine/Source/Editor/MeshPaint/Private/MeshPaintSkeletalMeshAdapter.cpp +++ b/Engine/Source/Editor/MeshPaint/Private/MeshPaintSkeletalMeshAdapter.cpp @@ -47,11 +47,8 @@ void FMeshPaintGeometryAdapterForSkeletalMeshes::OnSkeletalMeshChanged() if (SkeletalMeshComponent->SkeletalMesh != nullptr) { ReferencedSkeletalMesh = SkeletalMeshComponent->SkeletalMesh; - if (ReferencedSkeletalMesh) - { - Initialize(); - OnAdded(); - } + Initialize(); + OnAdded(); } } diff --git a/Engine/Source/Editor/MeshPaint/Private/MeshPaintStaticMeshAdapter.cpp b/Engine/Source/Editor/MeshPaint/Private/MeshPaintStaticMeshAdapter.cpp index fcc358b3d692..cc32b6d1d1a4 100644 --- a/Engine/Source/Editor/MeshPaint/Private/MeshPaintStaticMeshAdapter.cpp +++ b/Engine/Source/Editor/MeshPaint/Private/MeshPaintStaticMeshAdapter.cpp @@ -104,8 +104,8 @@ bool FMeshPaintGeometryAdapterForStaticMeshes::InitializeVertexData() void FMeshPaintGeometryAdapterForStaticMeshes::PostEdit() { - // Recreate all component states using the referenced static mesh - TUniquePtr RecreateRenderStateContext = MakeUnique(ReferencedStaticMesh); + // Lighting does not need to be invalidated when mesh painting + const bool bUnbuildLighting = false; const bool bUsingInstancedVertexColors = true; // Update gpu resource data @@ -116,6 +116,9 @@ void FMeshPaintGeometryAdapterForStaticMeshes::PostEdit() } else { + // Recreate all component states using the referenced static mesh + TUniquePtr RecreateRenderStateContext = MakeUnique(ReferencedStaticMesh, bUnbuildLighting); + // Reinitialize the static mesh's resources. ReferencedStaticMesh->InitResources(); } diff --git a/Engine/Source/Editor/MeshPaint/Public/BaseMeshPaintGeometryAdapter.h b/Engine/Source/Editor/MeshPaint/Public/BaseMeshPaintGeometryAdapter.h index 55b50e89d46a..297cf4d44814 100644 --- a/Engine/Source/Editor/MeshPaint/Public/BaseMeshPaintGeometryAdapter.h +++ b/Engine/Source/Editor/MeshPaint/Public/BaseMeshPaintGeometryAdapter.h @@ -11,12 +11,13 @@ class MESHPAINT_API FBaseMeshPaintGeometryAdapter : public IMeshPaintGeometryAda public: /** Start IMeshPaintGeometryAdapter Overrides */ virtual bool Initialize() override; - virtual const TArray& GetMeshVertices() const; - virtual const TArray& GetMeshIndices() const; - virtual void GetVertexPosition(int32 VertexIndex, FVector& OutVertex) const; - virtual TArray SphereIntersectTriangles(const float ComponentSpaceSquaredBrushRadius, const FVector& ComponentSpaceBrushPosition, const FVector& ComponentSpaceCameraPosition, const bool bOnlyFrontFacing) const; - virtual void GetInfluencedVertexIndices(const float ComponentSpaceSquaredBrushRadius, const FVector& ComponentSpaceBrushPosition, const FVector& ComponentSpaceCameraPosition, const bool bOnlyFrontFacing, TSet &InfluencedVertices) const; - virtual TArray SphereIntersectVertices(const float ComponentSpaceSquaredBrushRadius, const FVector& ComponentSpaceBrushPosition, const FVector& ComponentSpaceCameraPosition, const bool bOnlyFrontFacing) const; + virtual const TArray& GetMeshVertices() const override; + virtual const TArray& GetMeshIndices() const override; + virtual void GetVertexPosition(int32 VertexIndex, FVector& OutVertex) const override; + virtual TArray SphereIntersectTriangles(const float ComponentSpaceSquaredBrushRadius, const FVector& ComponentSpaceBrushPosition, const FVector& ComponentSpaceCameraPosition, const bool bOnlyFrontFacing) const override; + virtual void GetInfluencedVertexIndices(const float ComponentSpaceSquaredBrushRadius, const FVector& ComponentSpaceBrushPosition, const FVector& ComponentSpaceCameraPosition, const bool bOnlyFrontFacing, TSet &InfluencedVertices) const override; + virtual void GetInfluencedVertexData(const float ComponentSpaceSquaredBrushRadius, const FVector& ComponentSpaceBrushPosition, const FVector& ComponentSpaceCameraPosition, const bool bOnlyFrontFacing, TArray>& OutData) const override; + virtual TArray SphereIntersectVertices(const float ComponentSpaceSquaredBrushRadius, const FVector& ComponentSpaceBrushPosition, const FVector& ComponentSpaceCameraPosition, const bool bOnlyFrontFacing) const override; /** End IMeshPaintGeometryAdapter Overrides */ virtual bool InitializeVertexData() = 0; diff --git a/Engine/Source/Editor/MeshPaint/Public/IMeshPaintGeometryAdapter.h b/Engine/Source/Editor/MeshPaint/Public/IMeshPaintGeometryAdapter.h index 5ae1f532b770..0cf3d6e5321a 100644 --- a/Engine/Source/Editor/MeshPaint/Public/IMeshPaintGeometryAdapter.h +++ b/Engine/Source/Editor/MeshPaint/Public/IMeshPaintGeometryAdapter.h @@ -89,6 +89,9 @@ public: /** Retrieves the influenced vertex indices which intersect the given sphere */ virtual void GetInfluencedVertexIndices(const float ComponentSpaceSquaredBrushRadius, const FVector& ComponentSpaceBrushPosition, const FVector& ComponentSpaceCameraPosition, const bool bOnlyFrontFacing, TSet &InfluencedVertices) const = 0; + /** Retrieves the influenced vertex indices and positions that intersect the given sphere */ + virtual void GetInfluencedVertexData(const float ComponentSpaceSquaredBrushRadius, const FVector& ComponentSpaceBrushPosition, const FVector& ComponentSpaceCameraPosition, const bool bOnlyFrontFacing, TArray>& OutData) const = 0; + /** Returns the vertex positions which intersect the given sphere */ virtual TArray SphereIntersectVertices(const float ComponentSpaceSquaredBrushRadius, const FVector& ComponentSpaceBrushPosition, const FVector& ComponentSpaceCameraPosition, const bool bOnlyFrontFacing) const = 0; }; \ No newline at end of file diff --git a/Engine/Source/Editor/MeshPaint/Public/IMeshPainter.h b/Engine/Source/Editor/MeshPaint/Public/IMeshPainter.h index 95a6d8cf7d0f..b78353850d53 100644 --- a/Engine/Source/Editor/MeshPaint/Public/IMeshPainter.h +++ b/Engine/Source/Editor/MeshPaint/Public/IMeshPainter.h @@ -28,6 +28,7 @@ class MESHPAINT_API IMeshPainter { public: IMeshPainter(); + virtual ~IMeshPainter(); /** Renders ray widgets for the active viewport interactors */ virtual void Render(const FSceneView* View, FViewport* Viewport, FPrimitiveDrawInterface* PDI) = 0; diff --git a/Engine/Source/Editor/MeshPaint/Public/MeshPaintHelpers.h b/Engine/Source/Editor/MeshPaint/Public/MeshPaintHelpers.h index f70e5dd030fc..1c8170daead1 100644 --- a/Engine/Source/Editor/MeshPaint/Public/MeshPaintHelpers.h +++ b/Engine/Source/Editor/MeshPaint/Public/MeshPaintHelpers.h @@ -3,6 +3,8 @@ #pragma once #include "CoreMinimal.h" +#include "Engine/EngineTypes.h" +#include "MeshPaintTypes.h" class FMeshPaintParameters; class UVertexColorImportOptions; @@ -24,8 +26,18 @@ struct FStaticMeshComponentLODInfo; enum class EMeshPaintColorViewMode : uint8; +/** Parameters for paint actions, stored together for convenience */ +struct FPerVertexPaintActionArgs +{ + IMeshPaintGeometryAdapter* Adapter; + FVector CameraPosition; + FHitResult HitResult; + const UPaintBrushSettings* BrushSettings; + EMeshPaintAction Action; +}; + /** Delegates used to call per-vertex/triangle actions */ -DECLARE_DELEGATE_TwoParams(FPerVertexPaintAction, IMeshPaintGeometryAdapter* /*Adapter*/, int32 /*VertexIndex*/); +DECLARE_DELEGATE_TwoParams(FPerVertexPaintAction, FPerVertexPaintActionArgs& /*Args*/, int32 /*VertexIndex*/); DECLARE_DELEGATE_ThreeParams(FPerTrianglePaintAction, IMeshPaintGeometryAdapter* /*Adapter*/, int32 /*TriangleIndex*/, const int32[3] /*Vertex Indices*/); class MESHPAINT_API MeshPaintHelpers @@ -103,8 +115,8 @@ public: /** Retrieves the number of bytes used to store the per-instance LOD vertex color data from the static mesh component */ static void GetInstanceColorDataInfo(const UStaticMeshComponent* StaticMeshComponent, int32 LODIndex, int32& OutTotalInstanceVertexColorBytes); - /** Given the adapter, settings and view-information retrieves influences vertices and applies Action to them */ - static bool ApplyPerVertexPaintAction(IMeshPaintGeometryAdapter* Adapter, const FVector& CameraPosition, const FVector& HitPosition, const UPaintBrushSettings* Settings, FPerVertexPaintAction Action); + /** Given arguments for an action, and an action - retrieves influences vertices and applies Action to them */ + static bool ApplyPerVertexPaintAction(FPerVertexPaintActionArgs& InArgs, FPerVertexPaintAction Action); /** Given the adapter, settings and view-information retrieves influences triangles and applies Action to them */ static bool ApplyPerTrianglePaintAction(IMeshPaintGeometryAdapter* Adapter, const FVector& CameraPosition, const FVector& HitPosition, const UPaintBrushSettings* Settings, FPerTrianglePaintAction Action); diff --git a/Engine/Source/Editor/MeshPaintMode/Private/PaintModePainter.cpp b/Engine/Source/Editor/MeshPaintMode/Private/PaintModePainter.cpp index 9f61a91f82db..f07b6e77849d 100644 --- a/Engine/Source/Editor/MeshPaintMode/Private/PaintModePainter.cpp +++ b/Engine/Source/Editor/MeshPaintMode/Private/PaintModePainter.cpp @@ -66,6 +66,7 @@ void FPaintModePainter::Init() FPaintModeCommands::Register(); CachedLODIndex = PaintSettings->VertexPaintSettings.LODIndex; bCachedForceLOD = PaintSettings->VertexPaintSettings.bPaintOnSpecificLOD; + FCoreUObjectDelegates::OnObjectPropertyChanged.AddRaw(this, &FPaintModePainter::UpdatePaintTargets); } FPaintModePainter::FPaintModePainter() @@ -81,6 +82,7 @@ FPaintModePainter::FPaintModePainter() FPaintModePainter::~FPaintModePainter() { + FCoreUObjectDelegates::OnObjectPropertyChanged.RemoveAll(this); ComponentToAdapterMap.Empty(); ComponentToTexturePaintSettingsMap.Empty(); } @@ -775,8 +777,7 @@ const FHitResult FPaintModePainter::GetHitResult(const FVector& Origin, const FV // Ray trace FHitResult TraceHitResult(1.0f); - static FName DoPaintName(TEXT("Paint")); - if (MeshAdapter->LineTraceComponent(TraceHitResult, TraceStart, TraceEnd, FCollisionQueryParams(DoPaintName, true))) + if (MeshAdapter->LineTraceComponent(TraceHitResult, TraceStart, TraceEnd, FCollisionQueryParams(SCENE_QUERY_STAT(Paint), true))) { // Find the closest impact if ((BestTraceResult.GetComponent() == nullptr) || (TraceHitResult.Time < BestTraceResult.Time)) @@ -907,8 +908,7 @@ bool FPaintModePainter::PaintInternal(const FVector& InCameraOrigin, const FVect // Ray trace FHitResult TraceHitResult(1.0f); - static FName DoPaintName(TEXT("Paint")); - if (MeshAdapter->LineTraceComponent(TraceHitResult, TraceStart, TraceEnd, FCollisionQueryParams(DoPaintName, true))) + if (MeshAdapter->LineTraceComponent(TraceHitResult, TraceStart, TraceEnd, FCollisionQueryParams(SCENE_QUERY_STAT(Paint), true))) { // Find the closest impact if ((BestTraceResult.GetComponent() == nullptr) || (TraceHitResult.Time < BestTraceResult.Time)) @@ -1023,9 +1023,15 @@ bool FPaintModePainter::PaintInternal(const FVector& InCameraOrigin, const FVect if (PaintSettings->PaintMode == EPaintMode::Vertices && MeshAdapter->SupportsVertexPaint()) { - MeshAdapter->PreEdit(); - bPaintApplied |= MeshPaintHelpers::ApplyPerVertexPaintAction(MeshAdapter, InCameraOrigin, BestTraceResult.Location, BrushSettings, FPerVertexPaintAction::CreateRaw(this, &FPaintModePainter::ApplyVertexColor, Params)); - MeshAdapter->PostEdit(); + + FPerVertexPaintActionArgs Args; + Args.Adapter = MeshAdapter; + Args.CameraPosition = InCameraOrigin; + Args.HitResult = BestTraceResult; + Args.BrushSettings = BrushSettings; + Args.Action = PaintAction; + + bPaintApplied |= MeshPaintHelpers::ApplyPerVertexPaintAction(Args, FPerVertexPaintAction::CreateRaw(this, &FPaintModePainter::ApplyVertexColor, Params)); } else if (PaintSettings->PaintMode == EPaintMode::Textures&& MeshAdapter->SupportsTexturePaint()) { @@ -1076,16 +1082,16 @@ bool FPaintModePainter::PaintInternal(const FVector& InCameraOrigin, const FVect return bPaintApplied; } -void FPaintModePainter::ApplyVertexColor(IMeshPaintGeometryAdapter* Adapter, int32 VertexIndex, FMeshPaintParameters Parameters) +void FPaintModePainter::ApplyVertexColor(FPerVertexPaintActionArgs& InArgs, int32 VertexIndex, FMeshPaintParameters Parameters) { /** Retrieve vertex position and color for applying vertex painting */ FColor PaintColor; FVector Position; - Adapter->GetVertexPosition(VertexIndex, Position); - Position = Adapter->GetComponentToWorldMatrix().TransformPosition(Position); - Adapter->GetVertexColor(VertexIndex, PaintColor, true); + InArgs.Adapter->GetVertexPosition(VertexIndex, Position); + Position = InArgs.Adapter->GetComponentToWorldMatrix().TransformPosition(Position); + InArgs.Adapter->GetVertexColor(VertexIndex, PaintColor, true); MeshPaintHelpers::PaintVertex(Position, Parameters, PaintColor); - Adapter->SetVertexColor(VertexIndex, PaintColor, true); + InArgs.Adapter->SetVertexColor(VertexIndex, PaintColor, true); } void FPaintModePainter::GatherTextureTriangles(IMeshPaintGeometryAdapter* Adapter, int32 TriangleIndex, const int32 VertexIndices[3], TArray* TriangleInfo, TArray* SectionInfos, int32 UVChannelIndex) @@ -2083,6 +2089,16 @@ void FPaintModePainter::ApplyForcedLODIndex(int32 ForcedLODIndex) } } +void FPaintModePainter::UpdatePaintTargets(UObject* InObject, struct FPropertyChangedEvent& InPropertyChangedEvent) +{ + AActor* Actor = Cast(InObject); + if (InPropertyChangedEvent.Property && + InPropertyChangedEvent.Property->GetName() == GET_MEMBER_NAME_CHECKED(USceneComponent, bVisible).ToString()) + { + Refresh(); + } +} + void FPaintModePainter::Refresh() { // Ensure that we call OnRemoved while adapter/components are still valid @@ -2178,7 +2194,7 @@ void FPaintModePainter::CacheSelectionData() for (UMeshComponent* MeshComponent : SelectedMeshComponents) { TSharedPtr MeshAdapter = FMeshPaintAdapterFactory::CreateAdapterForMesh(MeshComponent, PaintLODIndex); - if (MeshAdapter.IsValid() && MeshAdapter->IsValid()) + if (MeshComponent->IsVisible() && MeshAdapter.IsValid() && MeshAdapter->IsValid()) { PaintableComponents.Add(MeshComponent); ComponentToAdapterMap.Add(MeshComponent, MeshAdapter); diff --git a/Engine/Source/Editor/MeshPaintMode/Private/PaintModePainter.h b/Engine/Source/Editor/MeshPaintMode/Private/PaintModePainter.h index 88a7c5bca02b..b7df3434d758 100644 --- a/Engine/Source/Editor/MeshPaintMode/Private/PaintModePainter.h +++ b/Engine/Source/Editor/MeshPaintMode/Private/PaintModePainter.h @@ -101,7 +101,7 @@ class SWidget; struct FPaintableTexture; struct FPaintTexture2DData; struct FTexturePaintMeshSectionInfo; - +struct FPerVertexPaintActionArgs; /** Painter class used by the level viewport mesh painting mode */ class FPaintModePainter : public IMeshPainter @@ -139,7 +139,7 @@ protected: virtual bool PaintInternal(const FVector& InCameraOrigin, const FVector& InRayOrigin, const FVector& InRayDirection, EMeshPaintAction PaintAction, float PaintStrength) override; /** Per vertex action function used for painting vertex colors */ - void ApplyVertexColor(IMeshPaintGeometryAdapter* Adapter, int32 VertexIndex, FMeshPaintParameters Parameters); + void ApplyVertexColor(FPerVertexPaintActionArgs& Args, int32 VertexIndex, FMeshPaintParameters Parameters); /** Per triangle action function used for retrieving triangle eligible for texture painting */ void GatherTextureTriangles(IMeshPaintGeometryAdapter* Adapter, int32 TriangleIndex, const int32 VertexIndices[3], TArray* TriangleInfo, TArray* SectionInfos, int32 UVChannelIndex); @@ -274,6 +274,9 @@ private: /** Forces a specific LOD level to be rendered for the selected mesh components */ void ApplyForcedLODIndex(int32 ForcedLODIndex); + + /** Updates the paint targets based on property changes on actors in the scene */ + void UpdatePaintTargets(UObject* InObject, struct FPropertyChangedEvent& InPropertyChangedEvent); protected: /** Texture paint state */ /** Textures eligible for painting retrieved from the current selection */ diff --git a/Engine/Source/Editor/MovieSceneTools/Private/K2Node_GetSequenceBinding.cpp b/Engine/Source/Editor/MovieSceneTools/Private/K2Node_GetSequenceBinding.cpp index 4e9e31958c04..07be052e18c9 100644 --- a/Engine/Source/Editor/MovieSceneTools/Private/K2Node_GetSequenceBinding.cpp +++ b/Engine/Source/Editor/MovieSceneTools/Private/K2Node_GetSequenceBinding.cpp @@ -29,31 +29,42 @@ static const FString SequencePinName(TEXT("Sequence")); void EnsureFullyLoaded(UObject* Object) { - if (!Object || Object->HasAnyFlags(RF_LoadCompleted)) + if (!Object) { return; } - check(!GEventDrivenLoaderEnabled || !EVENT_DRIVEN_ASYNC_LOAD_ACTIVE_AT_RUNTIME); - Object->SetFlags(RF_NeedLoad); - if (FLinkerLoad* Linker = Object->GetLinker()) + bool bLoadInternalReferences = false; + + if (Object->HasAnyFlags(RF_NeedLoad)) { - Linker->Preload(Object); + FLinkerLoad* Linker = Object->GetLinker(); + if (ensure(Linker)) + { + Linker->Preload(Object); + bLoadInternalReferences = true; + check(!Object->HasAnyFlags(RF_NeedLoad)); + } } + bLoadInternalReferences = bLoadInternalReferences || Object->HasAnyFlags(RF_NeedPostLoad | RF_NeedPostLoadSubobjects); + Object->ConditionalPostLoad(); Object->ConditionalPostLoadSubobjects(); - - // Collect a list of all things this element owns - TArray ObjectReferences; - FReferenceFinder(ObjectReferences, nullptr, false, true, false, true).FindReferences(Object); - - // Iterate over the list, and preload everything so it is valid for refreshing - for (UObject* Reference : ObjectReferences) + + if (bLoadInternalReferences) { - if (Reference->IsA() || Reference->IsA() || Reference->IsA() || Reference->IsA()) + // Collect a list of all things this element owns + TArray ObjectReferences; + FReferenceFinder(ObjectReferences, nullptr, false, true, false, true).FindReferences(Object); + + // Iterate over the list, and preload everything so it is valid for refreshing + for (UObject* Reference : ObjectReferences) { - EnsureFullyLoaded(Reference); + if (Reference->IsA() || Reference->IsA() || Reference->IsA() || Reference->IsA()) + { + EnsureFullyLoaded(Reference); + } } } } @@ -88,13 +99,15 @@ UMovieSceneSequence* UK2Node_GetSequenceBinding::GetSequence() const void UK2Node_GetSequenceBinding::ValidateNodeDuringCompilation(FCompilerResultsLog& MessageLog) const { + Super::ValidateNodeDuringCompilation(MessageLog); + UMovieScene* MovieScene = GetObjectMovieScene(); if (!MovieScene) { const FText MessageText = LOCTEXT("InvalidSequenceBinding_NoSequence", "Invalid sequence binding specified on node @@ (could not find sequence)."); MessageLog.Warning(*MessageText.ToString(), this); } - else if (!MovieScene->FindPossessable(Binding.GetObjectBindingID()) && !MovieScene->FindSpawnable(Binding.GetObjectBindingID())) + else if (!MovieScene->FindPossessable(Binding.GetGuid()) && !MovieScene->FindSpawnable(Binding.GetGuid())) { const FText MessageText = LOCTEXT("InvalidSequenceBinding_Unresolved", "Invalid sequence binding specified on node @@."); MessageLog.Warning(*MessageText.ToString(), this); @@ -105,10 +118,10 @@ void UK2Node_GetSequenceBinding::AllocateDefaultPins() { const UEdGraphSchema_K2* K2Schema = GetDefault(); - CreatePin(EGPD_Input, K2Schema->PC_Object, TEXT(""), UMovieSceneSequence::StaticClass(), false, false, SequencePinName); + CreatePin(EGPD_Input, K2Schema->PC_Object, FString(), UMovieSceneSequence::StaticClass(), SequencePinName); // Result pin - UEdGraphPin* ResultPin = CreatePin(EGPD_Output, K2Schema->PC_Struct, TEXT(""), FMovieSceneObjectBindingID::StaticStruct(), false, false, K2Schema->PN_ReturnValue); + UEdGraphPin* ResultPin = CreatePin(EGPD_Output, K2Schema->PC_Struct, FString(), FMovieSceneObjectBindingID::StaticStruct(), K2Schema->PN_ReturnValue); ResultPin->PinFriendlyName = LOCTEXT("SequenceBindingOutput", "Binding"); Super::AllocateDefaultPins(); @@ -117,7 +130,7 @@ void UK2Node_GetSequenceBinding::AllocateDefaultPins() UMovieScene* UK2Node_GetSequenceBinding::GetObjectMovieScene() const { UMovieSceneSequence* Sequence = GetSequence(); - if (Sequence && Binding.GetObjectBindingID().IsValid()) + if (Sequence && Binding.IsValid()) { // Ensure that the sequence data is as loaded as it can be - we many only be able to partially load the structural information as part of a blueprint compile as that may happen at Preload time EnsureFullyLoaded(Sequence); @@ -163,7 +176,7 @@ FText UK2Node_GetSequenceBinding::GetSequenceName() const FText UK2Node_GetSequenceBinding::GetBindingName() const { UMovieScene* MovieScene = GetObjectMovieScene(); - return MovieScene ? MovieScene->GetObjectDisplayName(Binding.GetObjectBindingID()) : FText(); + return MovieScene ? MovieScene->GetObjectDisplayName(Binding.GetGuid()) : FText(); } FText UK2Node_GetSequenceBinding::GetNodeTitle(ENodeTitleType::Type TitleType) const @@ -437,11 +450,12 @@ TSharedPtr UK2Node_GetSequenceBinding::CreateVisualWidget() .MenuPlacement(MenuPlacement_BelowAnchor) .ButtonContent() [ - SNew(STextBlock) - .TextStyle( FEditorStyle::Get(), "PropertyEditor.AssetClass" ) - .Font( FEditorStyle::GetFontStyle( "PropertyWindow.NormalFont" ) ) - .ColorAndOpacity(this, &SGraphNodeGetSequenceBinding::OnGetComboForeground) - .Text( this, &SGraphNodeGetSequenceBinding::GetCurrentText ) + GetCurrentItemWidget( + SNew(STextBlock) + .TextStyle( FEditorStyle::Get(), "PropertyEditor.AssetClass" ) + .Font( FEditorStyle::GetFontStyle( "PropertyWindow.NormalFont" ) ) + .ColorAndOpacity(this, &SGraphNodeGetSequenceBinding::OnGetComboForeground) + ) ] .OnGetMenuContent(this, &SGraphNodeGetSequenceBinding::GetPickerMenu) ] diff --git a/Engine/Source/Editor/MovieSceneTools/Private/K2Node_GetSequenceBindings.cpp b/Engine/Source/Editor/MovieSceneTools/Private/K2Node_GetSequenceBindings.cpp index 403b933210aa..e1527578ede9 100644 --- a/Engine/Source/Editor/MovieSceneTools/Private/K2Node_GetSequenceBindings.cpp +++ b/Engine/Source/Editor/MovieSceneTools/Private/K2Node_GetSequenceBindings.cpp @@ -139,7 +139,7 @@ void UDEPRECATED_K2Node_GetSequenceBindings::UpdatePins() } FString GuidString = Possessable.GetGuid().ToString(); - UEdGraphPin* NewPin = CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Struct, TEXT(""), FMovieSceneObjectBindingID::StaticStruct(), false, false, GuidString); + UEdGraphPin* NewPin = CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Struct, FString(), FMovieSceneObjectBindingID::StaticStruct(), GuidString); NewPin->PinFriendlyName = MovieScene->GetObjectDisplayName(Possessable.GetGuid()); NewPin->PersistentGuid = Possessable.GetGuid(); diff --git a/Engine/Source/Editor/DetailCustomizations/Private/MovieSceneObjectBindingIDCustomization.cpp b/Engine/Source/Editor/MovieSceneTools/Private/MovieSceneObjectBindingIDCustomization.cpp similarity index 95% rename from Engine/Source/Editor/DetailCustomizations/Private/MovieSceneObjectBindingIDCustomization.cpp rename to Engine/Source/Editor/MovieSceneTools/Private/MovieSceneObjectBindingIDCustomization.cpp index f534881d7581..0c01ed8d2ef3 100644 --- a/Engine/Source/Editor/DetailCustomizations/Private/MovieSceneObjectBindingIDCustomization.cpp +++ b/Engine/Source/Editor/MovieSceneTools/Private/MovieSceneObjectBindingIDCustomization.cpp @@ -44,9 +44,10 @@ void FMovieSceneObjectBindingIDCustomization::CustomizeHeader(TSharedRef Child) { Child->ParentID = BindingID; Children.Add(Child); } + /** This object's ID, and its parent's */ FMovieSceneObjectBindingID BindingID, ParentID; - + /** The display string that represents this node */ FText DisplayString; - + /** A representative icon for the node */ + FSlateIcon Icon; + /** Whether this is a spawnable or not */ + bool bIsSpawnable; + /** Array holding this node's children */ TArray> Children; }; +/** Stack of sequence IDs from parent to child */ +struct FSequenceIDStack +{ + /** Get the current accumulated sequence ID */ + FMovieSceneSequenceID GetCurrent() const + { + FMovieSceneSequenceID ID = MovieSceneSequenceID::Root; + for (int32 Index = IDs.Num() - 1; Index >= 0; --Index) + { + ID = ID.AccumulateParentID(IDs[Index]); + } + return ID; + } + + /** Push a sequence ID onto the stack */ + void Push(FMovieSceneSequenceID InSequenceID) { IDs.Add(InSequenceID); } + + /** Pop the last sequence ID off the stack */ + void Pop() { IDs.RemoveAt(IDs.Num() - 1, 1, false); } + +private: + TArray IDs; +}; + + +/** Data structure used internally to represent the bindings of a sequence recursively */ struct FSequenceBindingTree { - void Build(UMovieSceneSequence* InSequence) + /** + * Construct the tree structure from the specified sequence. + * + * @param InSequence The sequence to generate the tree for + * @param InActiveSequence A sequence at which point we can start to generate localally resolving IDs + * @param InActiveSequenceID The sequence ID for the above sequence within the root context + */ + void Build(UMovieSceneSequence* InSequence, FObjectKey InActiveSequence, FMovieSceneSequenceID InActiveSequenceID) { + // Reset state + ActiveSequenceID = InActiveSequenceID; + ActiveSequence = InActiveSequence; Hierarchy.Reset(); - FMovieSceneObjectBindingID ID; + ActiveSequenceNode = nullptr; - TSharedRef NewNode = MakeShared(FText(), ID); - Hierarchy.Add(ID, NewNode); + // Create a node for the root sequence + FMovieSceneObjectBindingID RootSequenceID; + TSharedRef RootSequenceNode = MakeShared(FText(), RootSequenceID, FSlateIcon()); + Hierarchy.Add(RootSequenceID, RootSequenceNode); + + TopLevelNode = RootSequenceNode; if (InSequence) { - Build(InSequence, MovieSceneSequenceID::Root); + RootSequenceNode->DisplayString = FText::FromString(InSequence->GetName()); + RootSequenceNode->Icon = FSlateIconFinder::FindIconForClass(InSequence->GetClass()); + + // Build the tree + FSequenceIDStack SequenceIDStack; + Build(InSequence, SequenceIDStack); + + // Sort the tree + Sort(RootSequenceNode); + + // We don't show cross-references to the same sequence since this would result in erroneous mixtures of absolute and local bindings + if (ActiveSequenceNode.IsValid() && ActiveSequenceNode != RootSequenceNode) + { + // Remove it from its parent, and put it at the root for quick access + TSharedPtr ActiveParent = Hierarchy.FindChecked(ActiveSequenceNode->ParentID); + ActiveParent->Children.Remove(ActiveSequenceNode.ToSharedRef()); + + // Make a new top level node (with an invalid ID) + FMovieSceneObjectBindingID TopLevelID = FMovieSceneObjectBindingID(FGuid(), FMovieSceneSequenceID()); + TopLevelNode = MakeShared(FText(), TopLevelID, FSlateIcon()); + + // Override the display string and icon + ActiveSequenceNode->DisplayString = LOCTEXT("ThisSequenceText", "This Sequence"); + ActiveSequenceNode->Icon = FSlateIcon(); + + TopLevelNode->Children.Add(ActiveSequenceNode.ToSharedRef()); + TopLevelNode->Children.Add(RootSequenceNode); + } } } + /** Get the root of the tree */ TSharedRef GetRootNode() const { - return Hierarchy.FindChecked(FMovieSceneObjectBindingID()).ToSharedRef(); + return TopLevelNode.ToSharedRef(); } + /** Find a node in the tree */ TSharedPtr FindNode(FMovieSceneObjectBindingID BindingID) const { return Hierarchy.FindRef(BindingID); } - FText GetTextForBinding(FMovieSceneObjectBindingID BindingID) const - { - TSharedPtr Object = BindingID.GetObjectBindingID().IsValid() ? Hierarchy.FindRef(BindingID) : nullptr; - return Object.IsValid() ? Object->DisplayString : LOCTEXT("UnresolvedBinding", "Unresolved Binding"); - } - - FText GetToolTipTextForBinding(FMovieSceneObjectBindingID BindingID) const - { - TSharedPtr Object = BindingID.GetObjectBindingID().IsValid() ? Hierarchy.FindRef(BindingID) : nullptr; - if (!Object.IsValid()) - { - return LOCTEXT("UnresolvedBinding_ToolTip", "The specified binding could not be located in the sequence"); - } - - FText NestedPath; - while (Object.IsValid() && Object->BindingID != FMovieSceneObjectBindingID()) - { - NestedPath = NestedPath.IsEmpty() ? Object->DisplayString : FText::Format(LOCTEXT("NestedPathFormat", "{0} -> {1}"), Object->DisplayString, NestedPath); - Object = Hierarchy.FindRef(Object->ParentID); - } - - return NestedPath; - } - private: - void Build(UMovieSceneSequence* InSequence, FMovieSceneSequenceID SequenceID) + /** Recursive sort helper for a sequence binding node */ + static void Sort(TSharedRef Node) + { + Node->Children.Sort( + [](TSharedRef A, TSharedRef B) + { + // Sort shots first + if (A->BindingID.IsValid() != B->BindingID.IsValid()) + { + return !A->BindingID.IsValid(); + } + return A->DisplayString.CompareToCaseIgnored(B->DisplayString) < 0; + } + ); + + for (TSharedRef Child : Node->Children) + { + Sort(Child); + } + } + + /** Recursive builder function that iterates into sub sequences */ + void Build(UMovieSceneSequence* InSequence, FSequenceIDStack& SequenceIDStack) { check(InSequence); @@ -99,33 +182,17 @@ private: { return; } - - const int32 PossessableCount = MovieScene->GetPossessableCount(); - for (int32 Index = 0; Index < PossessableCount; ++Index) + + if (ActiveSequence == InSequence) { - const FMovieScenePossessable& Possessable = MovieScene->GetPossessable(Index); - if (InSequence->CanRebindPossessable(Possessable)) + // Don't allow cross-references to the same sequence (ie, re-entrant references) + if (SequenceIDStack.GetCurrent() != ActiveSequenceID) { - FMovieSceneObjectBindingID ID(Possessable.GetGuid(), SequenceID); - - TSharedRef NewNode = MakeShared(MovieScene->GetObjectDisplayName(Possessable.GetGuid()), ID); - - EnsureParent(Possessable.GetParent(), MovieScene, SequenceID)->AddChild(NewNode); - Hierarchy.Add(ID, NewNode); + return; } - } - int32 SpawnableCount = MovieScene->GetSpawnableCount(); - for (int32 Index = 0; Index < SpawnableCount; ++Index) - { - const FMovieSceneSpawnable& Spawnable = MovieScene->GetSpawnable(Index); - - FMovieSceneObjectBindingID ID(Spawnable.GetGuid(), SequenceID); - - TSharedRef NewNode = MakeShared(MovieScene->GetObjectDisplayName(Spawnable.GetGuid()), ID); - - EnsureParent(FGuid(), MovieScene, SequenceID)->AddChild(NewNode); - Hierarchy.Add(ID, NewNode); + // Keep track of the active sequence node + ActiveSequenceNode = Hierarchy.FindChecked(FMovieSceneObjectBindingID(FGuid(), SequenceIDStack.GetCurrent())); } // Iterate all sub sections @@ -140,26 +207,69 @@ private: UMovieSceneSequence* SubSequence = SubSection ? SubSection->GetSequence() : nullptr; if (SubSequence) { - FMovieSceneSequenceID SubSequenceID = SubSection->GetSequenceID(); - if (SequenceID != MovieSceneSequenceID::Root) - { - SubSequenceID = SubSequenceID.AccumulateParentID(SequenceID); - } + // Hold onto the current parent ID before adding our ID onto the stack + FMovieSceneSequenceID ParentID = SequenceIDStack.GetCurrent(); + SequenceIDStack.Push(SubSection->GetSequenceID()); + + FMovieSceneObjectBindingID CurrentID(FGuid(), SequenceIDStack.GetCurrent()); - FMovieSceneObjectBindingID ID(FGuid(), SubSequenceID); - FText DisplayString = Section->IsA() ? Cast(Section)->GetShotDisplayName() : FText::FromName(SubSection->GetFName()); - TSharedRef NewNode = MakeShared(DisplayString, ID); + UMovieSceneCinematicShotSection* ShotSection = Cast(Section); + FText DisplayString = ShotSection ? ShotSection->GetShotDisplayName() : FText::FromName(SubSection->GetFName()); + FSlateIcon Icon(FEditorStyle::GetStyleSetName(), ShotSection ? "Sequencer.Tracks.CinematicShot" : "Sequencer.Tracks.Sub"); + + TSharedRef NewNode = MakeShared(DisplayString, CurrentID, Icon); + ensure(!Hierarchy.Contains(CurrentID)); + Hierarchy.Add(CurrentID, NewNode); - EnsureParent(FGuid(), MovieScene, SequenceID)->AddChild(NewNode); - Hierarchy.Add(ID, NewNode); + EnsureParent(FGuid(), MovieScene, ParentID)->AddChild(NewNode); - Build(SubSequence, SubSequenceID); + Build(SubSequence, SequenceIDStack); + + SequenceIDStack.Pop(); } } } } + + FMovieSceneSequenceID CurrentSequenceID = SequenceIDStack.GetCurrent(); + + // Add all spawnables first (since possessables can be children of spawnables) + int32 SpawnableCount = MovieScene->GetSpawnableCount(); + for (int32 Index = 0; Index < SpawnableCount; ++Index) + { + const FMovieSceneSpawnable& Spawnable = MovieScene->GetSpawnable(Index); + + FMovieSceneObjectBindingID ID(Spawnable.GetGuid(), CurrentSequenceID); + + FSlateIcon Icon = FSlateIconFinder::FindIconForClass(Spawnable.GetObjectTemplate()->GetClass()); + TSharedRef NewNode = MakeShared(MovieScene->GetObjectDisplayName(Spawnable.GetGuid()), ID, Icon); + NewNode->bIsSpawnable = true; + + EnsureParent(FGuid(), MovieScene, CurrentSequenceID)->AddChild(NewNode); + ensure(!Hierarchy.Contains(ID)); + Hierarchy.Add(ID, NewNode); + } + + // Add all possessables + const int32 PossessableCount = MovieScene->GetPossessableCount(); + for (int32 Index = 0; Index < PossessableCount; ++Index) + { + const FMovieScenePossessable& Possessable = MovieScene->GetPossessable(Index); + if (InSequence->CanRebindPossessable(Possessable)) + { + FMovieSceneObjectBindingID ID(Possessable.GetGuid(), CurrentSequenceID); + + FSlateIcon Icon = FSlateIconFinder::FindIconForClass(Possessable.GetPossessedObjectClass()); + TSharedRef NewNode = MakeShared(MovieScene->GetObjectDisplayName(Possessable.GetGuid()), ID, Icon); + + EnsureParent(Possessable.GetParent(), MovieScene, CurrentSequenceID)->AddChild(NewNode); + ensure(!Hierarchy.Contains(ID)); + Hierarchy.Add(ID, NewNode); + } + } } + /** Ensure that a parent node exists for the specified object */ TSharedRef EnsureParent(const FGuid& InParentGuid, UMovieScene* InMovieScene, FMovieSceneSequenceID SequenceID) { FMovieSceneObjectBindingID ParentPtr(InParentGuid, SequenceID); @@ -181,16 +291,42 @@ private: AddToGuid = GrandParentPossessable->GetGuid(); } - TSharedRef NewNode = MakeShared(InMovieScene->GetObjectDisplayName(InParentGuid), ParentPtr); - EnsureParent(AddToGuid, InMovieScene, SequenceID)->AddChild(NewNode); + // Deduce the icon for the node + FSlateIcon Icon; + bool bIsSpawnable = false; + { + const FMovieScenePossessable* Possessable = InMovieScene->FindPossessable(InParentGuid); + const FMovieSceneSpawnable* Spawnable = Possessable ? nullptr : InMovieScene->FindSpawnable(InParentGuid); + if (Possessable || Spawnable) + { + Icon = FSlateIconFinder::FindIconForClass(Possessable ? Possessable->GetPossessedObjectClass() : Spawnable->GetObjectTemplate()->GetClass()); + } + bIsSpawnable = Spawnable != nullptr; + } + + TSharedRef NewNode = MakeShared(InMovieScene->GetObjectDisplayName(InParentGuid), ParentPtr, Icon); + NewNode->bIsSpawnable = bIsSpawnable; + + ensure(!Hierarchy.Contains(ParentPtr)); Hierarchy.Add(ParentPtr, NewNode); + EnsureParent(AddToGuid, InMovieScene, SequenceID)->AddChild(NewNode); + return NewNode; } private: + /** The ID of the currently 'active' sequence from which to generate relative IDs */ + FMovieSceneSequenceID ActiveSequenceID; + /** The currently 'active' sequence from which to generate relative IDs */ + FObjectKey ActiveSequence; + /** The node relating to the currently active sequence ID (if any) */ + TSharedPtr ActiveSequenceNode; + /** The top level (root) node in the tree */ + TSharedPtr TopLevelNode; + /** Map of hierarchical information */ TMap> Hierarchy; }; @@ -201,22 +337,28 @@ void FMovieSceneObjectBindingIDPicker::Initialize() DataTree = MakeShared(); } - DataTree->Build(GetSequence()); + UMovieSceneSequence* Sequence = Sequencer.IsValid() ? Sequencer->GetRootMovieSceneSequence() : GetSequence(); + UMovieSceneSequence* ActiveSequence = Sequencer.IsValid() ? Sequencer->GetFocusedMovieSceneSequence() : GetSequence(); + FMovieSceneSequenceID ActiveSequenceID = Sequencer.IsValid() ? Sequencer->GetFocusedTemplateID() : MovieSceneSequenceID::Root; - CurrentText = DataTree->GetTextForBinding(GetCurrentValue()); - ToolTipText = DataTree->GetToolTipTextForBinding(GetCurrentValue()); + DataTree->Build(Sequence, ActiveSequence, ActiveSequenceID); + + UpdateCachedData(); } void FMovieSceneObjectBindingIDPicker::OnGetMenuContent(FMenuBuilder& MenuBuilder, TSharedPtr Node) { check(Node.IsValid()); - if (Node->BindingID.GetObjectBindingID().IsValid()) + bool bHadAnyEntries = false; + + if (Node->BindingID.GetGuid().IsValid()) { + bHadAnyEntries = true; MenuBuilder.AddMenuEntry( Node->DisplayString, FText(), - FSlateIcon(), + Node->Icon, FUIAction( FExecuteAction::CreateRaw(this, &FMovieSceneObjectBindingIDPicker::SetBindingId, Node->BindingID) ) @@ -227,42 +369,116 @@ void FMovieSceneObjectBindingIDPicker::OnGetMenuContent(FMenuBuilder& MenuBuilde { check(Child.IsValid()) - if (!Child->BindingID.GetObjectBindingID().IsValid()) + if (!Child->BindingID.GetGuid().IsValid()) { - MenuBuilder.AddSubMenu( - Child->DisplayString, - FText(), - FNewMenuDelegate::CreateRaw(this, &FMovieSceneObjectBindingIDPicker::OnGetMenuContent, Child) - ); + if (Child->Children.Num()) + { + bHadAnyEntries = true; + MenuBuilder.AddSubMenu( + Child->DisplayString, + FText(), + FNewMenuDelegate::CreateRaw(this, &FMovieSceneObjectBindingIDPicker::OnGetMenuContent, Child), + false, + Child->Icon + ); + } } else { + bHadAnyEntries = true; MenuBuilder.AddMenuEntry( Child->DisplayString, FText(), - FSlateIcon(), + Child->Icon, FUIAction( FExecuteAction::CreateRaw(this, &FMovieSceneObjectBindingIDPicker::SetBindingId, Child->BindingID) ) ); } } + + if (!bHadAnyEntries) + { + MenuBuilder.AddMenuEntry(LOCTEXT("NoEntries", "No Object Bindings"), FText(), FSlateIcon(), FUIAction()); + } } TSharedRef FMovieSceneObjectBindingIDPicker::GetPickerMenu() { FMenuBuilder MenuBuilder(true, nullptr); + Initialize(); OnGetMenuContent(MenuBuilder, DataTree->GetRootNode()); return MenuBuilder.MakeWidget(); } +TSharedRef FMovieSceneObjectBindingIDPicker::GetCurrentItemWidget(TSharedRef TextContent) +{ + TextContent->SetText(TAttribute::Create(TAttribute::FGetter::CreateRaw(this, &FMovieSceneObjectBindingIDPicker::GetCurrentText))); + + return SNew(SHorizontalBox) + + + SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(SOverlay) + + + SOverlay::Slot() + [ + SNew(SImage) + .Image_Raw(this, &FMovieSceneObjectBindingIDPicker::GetCurrentIconBrush) + ] + + + SOverlay::Slot() + .VAlign(VAlign_Top) + .HAlign(HAlign_Right) + [ + SNew(SImage) + .Visibility_Raw(this, &FMovieSceneObjectBindingIDPicker::GetSpawnableIconOverlayVisibility) + .Image(FEditorStyle::GetBrush("Sequencer.SpawnableIconOverlay")) + ] + ] + + + SHorizontalBox::Slot() + .Padding(4.f,0,0,0) + .VAlign(VAlign_Center) + [ + TextContent + ]; +} + void FMovieSceneObjectBindingIDPicker::SetBindingId(FMovieSceneObjectBindingID InBindingId) { - SetCurrentValue(InBindingId); - CurrentText = DataTree->GetTextForBinding(InBindingId); - ToolTipText = DataTree->GetToolTipTextForBinding(InBindingId); + SetRemappedCurrentValue(InBindingId); + UpdateCachedData(); +} + +void FMovieSceneObjectBindingIDPicker::UpdateCachedData() +{ + FMovieSceneObjectBindingID CurrentValue = GetRemappedCurrentValue(); + TSharedPtr Object = CurrentValue.IsValid() ? DataTree->FindNode(CurrentValue) : nullptr; + + if (!Object.IsValid()) + { + CurrentIcon = FSlateIcon(); + CurrentText = LOCTEXT("UnresolvedBinding", "Unresolved Binding"); + ToolTipText = LOCTEXT("UnresolvedBinding_ToolTip", "The specified binding could not be located in the sequence"); + bIsCurrentItemSpawnable = false; + } + else + { + CurrentText = Object->DisplayString; + CurrentIcon = Object->Icon; + bIsCurrentItemSpawnable = Object->bIsSpawnable; + + ToolTipText = FText(); + while (Object.IsValid() && Object->BindingID != FMovieSceneObjectBindingID()) + { + ToolTipText = ToolTipText.IsEmpty() ? Object->DisplayString : FText::Format(LOCTEXT("ToolTipFormat", "{0} -> {1}"), Object->DisplayString, ToolTipText); + Object = DataTree->FindNode(Object->ParentID); + } + } } FText FMovieSceneObjectBindingIDPicker::GetToolTipText() const @@ -275,4 +491,70 @@ FText FMovieSceneObjectBindingIDPicker::GetCurrentText() const return CurrentText; } +FSlateIcon FMovieSceneObjectBindingIDPicker::GetCurrentIcon() const +{ + return CurrentIcon; +} + +const FSlateBrush* FMovieSceneObjectBindingIDPicker::GetCurrentIconBrush() const +{ + return CurrentIcon.GetOptionalIcon(); +} + +EVisibility FMovieSceneObjectBindingIDPicker::GetSpawnableIconOverlayVisibility() const +{ + return bIsCurrentItemSpawnable ? EVisibility::Visible : EVisibility::Collapsed; +} + +FMovieSceneObjectBindingID FMovieSceneObjectBindingIDPicker::GetRemappedCurrentValue() const +{ + FMovieSceneObjectBindingID ID = GetCurrentValue(); + + // If the ID is in local space, remap it to the root space as according to the LocalSequenceID we were created with + if (Sequencer.IsValid() && LocalSequenceID != MovieSceneSequenceID::Root && ID.IsValid() && ID.GetBindingSpace() == EMovieSceneObjectBindingSpace::Local) + { + ID = ID.ResolveLocalToRoot(LocalSequenceID, Sequencer->GetEvaluationTemplate().GetHierarchy()); + } + + return ID; +} + +void FMovieSceneObjectBindingIDPicker::SetRemappedCurrentValue(FMovieSceneObjectBindingID InValue) +{ + // If we have a local sequence ID set, and the supplied binding is in root space, we attempt to remap it into the local sequence ID's space, and use a sequence ID + // that will resolve from LocalSequenceID instead of from the root. This ensures that you can work on sub sequences on their own, or within a master sequence + // and the binding will resolve correctly. + if (LocalSequenceID.IsValid() && Sequencer.IsValid() && InValue.GetGuid().IsValid() && InValue.GetBindingSpace() == EMovieSceneObjectBindingSpace::Root) + { + const FMovieSceneSequenceHierarchy& Hierarchy = Sequencer->GetEvaluationTemplate().GetHierarchy(); + + FMovieSceneSequenceID NewLocalSequenceID = MovieSceneSequenceID::Root; + FMovieSceneSequenceID CurrentSequenceID = InValue.GetSequenceID(); + + while (CurrentSequenceID.IsValid()) + { + if (LocalSequenceID == CurrentSequenceID) + { + // Found it + InValue = FMovieSceneObjectBindingID(InValue.GetGuid(), NewLocalSequenceID, EMovieSceneObjectBindingSpace::Local); + break; + } + + const FMovieSceneSequenceHierarchyNode* CurrentNode = Hierarchy.FindNode(CurrentSequenceID); + if (!ensureAlwaysMsgf(CurrentNode, TEXT("Malformed sequence hierarchy"))) + { + break; + } + else if (const FMovieSceneSubSequenceData* SubData = Hierarchy.FindSubData(CurrentSequenceID)) + { + NewLocalSequenceID = NewLocalSequenceID.AccumulateParentID(SubData->DeterministicSequenceID); + } + + CurrentSequenceID = CurrentNode->ParentID; + } + } + + SetCurrentValue(InValue); +} + #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Editor/MovieSceneTools/Private/MovieSceneToolsModule.cpp b/Engine/Source/Editor/MovieSceneTools/Private/MovieSceneToolsModule.cpp index ea5d69e23584..5ccb9e2de21b 100644 --- a/Engine/Source/Editor/MovieSceneTools/Private/MovieSceneToolsModule.cpp +++ b/Engine/Source/Editor/MovieSceneTools/Private/MovieSceneToolsModule.cpp @@ -37,6 +37,7 @@ #include "TrackEditors/CameraShakeTrackEditor.h" #include "TrackEditors/MaterialParameterCollectionTrackEditor.h" +#include "MovieSceneObjectBindingIDCustomization.h" #include "SequencerClipboardReconciler.h" #include "ClipboardTypes.h" #include "ISettingsModule.h" @@ -109,6 +110,7 @@ public: // register details customization FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked("PropertyEditor"); PropertyModule.RegisterCustomClassLayout("MovieSceneToolsProjectSettings", FOnGetDetailCustomizationInstance::CreateStatic(&FMovieSceneToolsProjectSettingsCustomization::MakeInstance)); + PropertyModule.RegisterCustomPropertyTypeLayout("MovieSceneObjectBindingID", FOnGetPropertyTypeCustomizationInstance::CreateLambda(&MakeShared)); } virtual void ShutdownModule() override @@ -160,6 +162,7 @@ public: { FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked("PropertyEditor"); PropertyModule.UnregisterCustomClassLayout("MovieSceneToolsProjectSettings"); + PropertyModule.UnregisterCustomPropertyTypeLayout("MovieSceneObjectBindingID"); } } diff --git a/Engine/Source/Editor/MovieSceneTools/Private/Sections/CinematicShotSection.cpp b/Engine/Source/Editor/MovieSceneTools/Private/Sections/CinematicShotSection.cpp index 1eef0e892a51..87a62f3f503a 100644 --- a/Engine/Source/Editor/MovieSceneTools/Private/Sections/CinematicShotSection.cpp +++ b/Engine/Source/Editor/MovieSceneTools/Private/Sections/CinematicShotSection.cpp @@ -162,9 +162,9 @@ int32 FCinematicShotSection::OnPaintSection(FSequencerSectionPainter& InPainter) } // add box for the working size - const float StartOffset = SectionObject.Parameters.TimeScale * SectionObject.Parameters.StartOffset; - const float WorkingStart = -SectionObject.Parameters.TimeScale * PlaybackRange.GetLowerBoundValue() - StartOffset; - const float WorkingSize = SectionObject.Parameters.TimeScale * (MovieScene != nullptr ? MovieScene->GetEditorData().WorkingRange.Size() : 1.0f); + const float StartOffset = 1.0f/SectionObject.Parameters.TimeScale * SectionObject.Parameters.StartOffset; + const float WorkingStart = -1.0f/SectionObject.Parameters.TimeScale * PlaybackRange.GetLowerBoundValue() - StartOffset; + const float WorkingSize = 1.0f/SectionObject.Parameters.TimeScale * (MovieScene != nullptr ? MovieScene->GetEditorData().WorkingRange.Size() : 1.0f); // add dark tint for left out-of-bounds & working range if (StartOffset < 0.0f) @@ -201,7 +201,7 @@ int32 FCinematicShotSection::OnPaintSection(FSequencerSectionPainter& InPainter) } // add dark tint for right out-of-bounds & working range - const float PlaybackEnd = SectionObject.Parameters.TimeScale * PlaybackRange.Size() - StartOffset; + const float PlaybackEnd = 1.0f/SectionObject.Parameters.TimeScale * PlaybackRange.Size() - StartOffset; if (PlaybackEnd < SectionSize) { diff --git a/Engine/Source/Editor/MovieSceneTools/Private/TrackEditors/CinematicShotTrackEditor.cpp b/Engine/Source/Editor/MovieSceneTools/Private/TrackEditors/CinematicShotTrackEditor.cpp index c10d76bc9564..243c2a862be0 100644 --- a/Engine/Source/Editor/MovieSceneTools/Private/TrackEditors/CinematicShotTrackEditor.cpp +++ b/Engine/Source/Editor/MovieSceneTools/Private/TrackEditors/CinematicShotTrackEditor.cpp @@ -404,14 +404,11 @@ void FCinematicShotTrackEditor::NewTake(UMovieSceneCinematicShotSection* Section UMovieSceneCinematicShotTrack* CinematicShotTrack = FindOrCreateCinematicShotTrack(); CinematicShotTrack->RemoveSection(*Section); - if (NewShot != nullptr) - { - NewShot->SetStartTime(NewShotStartTime); - NewShot->SetEndTime(NewShotEndTime); - NewShot->Parameters.StartOffset = NewShotStartOffset; - NewShot->Parameters.TimeScale = NewShotTimeScale; - NewShot->SetPreRollTime(NewShotPrerollTime); - } + NewShot->SetStartTime(NewShotStartTime); + NewShot->SetEndTime(NewShotEndTime); + NewShot->Parameters.StartOffset = NewShotStartOffset; + NewShot->Parameters.TimeScale = NewShotTimeScale; + NewShot->SetPreRollTime(NewShotPrerollTime); GetSequencer()->NotifyMovieSceneDataChanged( EMovieSceneDataChangeType::MovieSceneStructureItemsChanged ); } diff --git a/Engine/Source/Editor/MovieSceneTools/Private/TrackEditors/EventTrackEditor.cpp b/Engine/Source/Editor/MovieSceneTools/Private/TrackEditors/EventTrackEditor.cpp index b73bba0a1e17..777d44d4f47a 100644 --- a/Engine/Source/Editor/MovieSceneTools/Private/TrackEditors/EventTrackEditor.cpp +++ b/Engine/Source/Editor/MovieSceneTools/Private/TrackEditors/EventTrackEditor.cpp @@ -7,7 +7,14 @@ #include "Package.h" #include "Tracks/MovieSceneEventTrack.h" #include "Sections/EventTrackSection.h" - +#include "MovieSceneObjectBindingIDPicker.h" +#include "IDetailCustomization.h" +#include "PropertyEditorModule.h" +#include "ModuleManager.h" +#include "DetailLayoutBuilder.h" +#include "MovieSceneObjectBindingIDCustomization.h" +#include "DetailCategoryBuilder.h" +#include "IDetailPropertyRow.h" #define LOCTEXT_NAMESPACE "FEventTrackEditor" @@ -67,47 +74,64 @@ void FEventTrackEditor::BuildTrackContextMenu(FMenuBuilder& MenuBuilder, UMovieS UMovieSceneEventTrack* EventTrack = CastChecked(Track); UProperty* EventPositionProperty = FindField(Track->GetClass(), GET_MEMBER_NAME_STRING_CHECKED(UMovieSceneEventTrack, EventPosition)); - MenuBuilder.AddSubMenu( - EventPositionProperty->GetDisplayNameText(), - EventPositionProperty->GetToolTipText(), - FNewMenuDelegate::CreateLambda( - [EventTrack](FMenuBuilder& SubMenuBuilder) + /** Specific details customization for the event track */ + class FEventTrackCustomization : public IDetailCustomization + { + public: + FEventTrackCustomization(TSharedRef InDetailsView, TSharedPtr InSequencer) + : WeakDetailsView(InDetailsView) + { + FOnGetPropertyTypeCustomizationInstance Factory = FOnGetPropertyTypeCustomizationInstance::CreateLambda([=]{ return MakeShared(InSequencer->GetFocusedTemplateID(), InSequencer); }); + + // Register an object binding ID customization that can use the current sequencer interface + FPropertyEditorModule& PropertyEditor = FModuleManager::Get().LoadModuleChecked("PropertyEditor"); + PropertyEditor.RegisterCustomPropertyTypeLayout("MovieSceneObjectBindingID", Factory, nullptr, InDetailsView); + } + + ~FEventTrackCustomization() + { + FPropertyEditorModule* PropertyEditor = FModuleManager::Get().GetModulePtr("PropertyEditor"); + auto PinnedDetailsView = WeakDetailsView.Pin(); + if (PropertyEditor && PinnedDetailsView.IsValid()) { - UEnum* Enum = FindObject(ANY_PACKAGE, TEXT("EFireEventsAtPosition")); - check(Enum); - - for (int32 Index = 0; Index < Enum->NumEnums() - 1; ++Index) - { - EFireEventsAtPosition EnumValue = (EFireEventsAtPosition)Enum->GetValueByIndex(Index); - - SubMenuBuilder.AddMenuEntry( - Enum->GetDisplayNameTextByIndex(Index), - Enum->GetToolTipTextByIndex(Index), - FSlateIcon(), - FUIAction( - FExecuteAction::CreateLambda( - [=] - { - FScopedTransaction Transaction(NSLOCTEXT("Sequencer", "SetEventPosition", "Set Event Position")); - EventTrack->Modify(); - EventTrack->EventPosition = EnumValue; - } - ), - FCanExecuteAction(), - FIsActionChecked::CreateLambda( - [=] - { - return EventTrack->EventPosition == EnumValue; - } - ) - ), - NAME_None, - EUserInterfaceActionType::ToggleButton - ); - } + PropertyEditor->UnregisterCustomPropertyTypeLayout("MovieSceneObjectBindingID", nullptr, PinnedDetailsView); } - ) - ); + } + + virtual void CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) override + { + DetailBuilder.HideCategory("Track"); + DetailBuilder.HideCategory("General"); + + IDetailCategoryBuilder& Category = DetailBuilder.EditCategory("TrackEvent"); + Category.AddProperty("EventReceivers").ShouldAutoExpand(true); + } + + TWeakPtr WeakDetailsView; + }; + + auto PopulateSubMenu = [this, EventTrack](FMenuBuilder& SubMenuBuilder) + { + FPropertyEditorModule& PropertyEditor = FModuleManager::Get().LoadModuleChecked("PropertyEditor"); + + // Create a details view for the track + FDetailsViewArgs DetailsViewArgs(false,false,false,FDetailsViewArgs::HideNameArea,true); + DetailsViewArgs.DefaultsOnlyVisibility = FDetailsViewArgs::EEditDefaultsOnlyNodeVisibility::Automatic; + DetailsViewArgs.bShowOptions = false; + + TSharedRef DetailsView = PropertyEditor.CreateDetailView(DetailsViewArgs); + // Register the custom type layout for the class + FOnGetDetailCustomizationInstance CreateInstance = FOnGetDetailCustomizationInstance::CreateLambda([=]{ return MakeShared(DetailsView, GetSequencer()); }); + DetailsView->RegisterInstancedCustomPropertyLayout(UMovieSceneEventTrack::StaticClass(), CreateInstance); + + // Assign the object + DetailsView->SetObject(EventTrack, true); + + // Add it to the menu + SubMenuBuilder.AddWidget(DetailsView, FText(), true, false); + }; + + MenuBuilder.AddSubMenu(LOCTEXT("Properties_MenuText", "Properties"), FText(), FNewMenuDelegate::CreateLambda(PopulateSubMenu)); } diff --git a/Engine/Source/Editor/MovieSceneTools/Private/TrackEditors/SubTrackEditor.cpp b/Engine/Source/Editor/MovieSceneTools/Private/TrackEditors/SubTrackEditor.cpp index f840d61e63af..a9a2c6343d7b 100644 --- a/Engine/Source/Editor/MovieSceneTools/Private/TrackEditors/SubTrackEditor.cpp +++ b/Engine/Source/Editor/MovieSceneTools/Private/TrackEditors/SubTrackEditor.cpp @@ -107,7 +107,7 @@ public: } else { - return LOCTEXT("InvalidSequence", "No Sequence Selected"); + return LOCTEXT("NoSequenceSelected", "No Sequence Selected"); } } @@ -142,9 +142,9 @@ public: } // add box for the working size - const float StartOffset = SectionObject.Parameters.TimeScale * SectionObject.Parameters.StartOffset; - const float WorkingStart = -SectionObject.Parameters.TimeScale * PlaybackRange.GetLowerBoundValue() - StartOffset; - const float WorkingSize = SectionObject.Parameters.TimeScale * (MovieScene != nullptr ? MovieScene->GetEditorData().WorkingRange.Size() : 1.0f); + const float StartOffset = 1.0f/SectionObject.Parameters.TimeScale * SectionObject.Parameters.StartOffset; + const float WorkingStart = -1.0f/SectionObject.Parameters.TimeScale * PlaybackRange.GetLowerBoundValue() - StartOffset; + const float WorkingSize = 1.0f/SectionObject.Parameters.TimeScale * (MovieScene != nullptr ? MovieScene->GetEditorData().WorkingRange.Size() : 1.0f); if(UMovieSceneSubSection::GetRecordingSection() == &SectionObject) { @@ -205,7 +205,7 @@ public: } // add dark tint for right out-of-bounds & working range - const float PlaybackEnd = SectionObject.Parameters.TimeScale * PlaybackRange.Size() - StartOffset; + const float PlaybackEnd = 1.0f/SectionObject.Parameters.TimeScale * PlaybackRange.Size() - StartOffset; if (PlaybackEnd < SectionSize) { diff --git a/Engine/Source/Editor/DetailCustomizations/Private/MovieSceneObjectBindingIDCustomization.h b/Engine/Source/Editor/MovieSceneTools/Public/MovieSceneObjectBindingIDCustomization.h similarity index 79% rename from Engine/Source/Editor/DetailCustomizations/Private/MovieSceneObjectBindingIDCustomization.h rename to Engine/Source/Editor/MovieSceneTools/Public/MovieSceneObjectBindingIDCustomization.h index ba156bd385b0..54afe03fe192 100644 --- a/Engine/Source/Editor/DetailCustomizations/Private/MovieSceneObjectBindingIDCustomization.h +++ b/Engine/Source/Editor/MovieSceneTools/Public/MovieSceneObjectBindingIDCustomization.h @@ -4,11 +4,13 @@ #include "IPropertyTypeCustomization.h" #include "MovieSceneObjectBindingIDPicker.h" +#include "MovieSceneSequenceID.h" class FReply; class IPropertyHandle; class UMovieSceneSequence; class FDragDropOperation; +class ISequencer; struct FMovieSceneObjectBindingID; @@ -18,10 +20,12 @@ class FMovieSceneObjectBindingIDCustomization { public: - static TSharedRef MakeInstance() - { - return MakeShareable(new FMovieSceneObjectBindingIDCustomization); - } + FMovieSceneObjectBindingIDCustomization() + {} + + FMovieSceneObjectBindingIDCustomization(FMovieSceneSequenceID InLocalSequenceID, TSharedPtr InSequencer) + : FMovieSceneObjectBindingIDPicker(InLocalSequenceID, InSequencer) + {} virtual void CustomizeHeader(TSharedRef PropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& CustomizationUtils) override; virtual void CustomizeChildren(TSharedRef StructPropertyHandle, class IDetailChildrenBuilder& ChildBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils) override {} diff --git a/Engine/Source/Editor/MovieSceneTools/Public/MovieSceneObjectBindingIDPicker.h b/Engine/Source/Editor/MovieSceneTools/Public/MovieSceneObjectBindingIDPicker.h index b43912b65eba..451563e33e44 100644 --- a/Engine/Source/Editor/MovieSceneTools/Public/MovieSceneObjectBindingIDPicker.h +++ b/Engine/Source/Editor/MovieSceneTools/Public/MovieSceneObjectBindingIDPicker.h @@ -3,10 +3,16 @@ #pragma once #include "CoreMinimal.h" +#include "SlateIcon.h" +#include "MovieSceneSequenceID.h" class SWidget; class UMovieSceneSequence; class FMenuBuilder; +class STextBlock; +class ISequencer; +struct EVisibility; +struct FSlateBrush; struct FSequenceBindingTree; struct FSequenceBindingNode; struct FMovieSceneObjectBindingID; @@ -16,9 +22,27 @@ struct FMovieSceneObjectBindingID; */ class MOVIESCENETOOLS_API FMovieSceneObjectBindingIDPicker { -protected: +public: - /** Get the sequence to look up object bindings within */ + /** Default constructor used in contexts external to the sequencer interface. Always generates FMovieSceneObjectBindingIDs from the root of the sequence */ + FMovieSceneObjectBindingIDPicker() + : bIsCurrentItemSpawnable(false) + {} + + /** + * Constructor used from within the sequencer interface to generate IDs from the currently focused sequence if possible (else from the root sequence). + * This ensures that the bindings will resolve correctly in isolation only the the focused sequence is being used, or from the root sequence. + */ + FMovieSceneObjectBindingIDPicker(FMovieSceneSequenceID InLocalSequenceID, TSharedPtr InSequencer) + : Sequencer(InSequencer) + , LocalSequenceID(InLocalSequenceID) + , bIsCurrentItemSpawnable(false) + {} + +protected: + virtual ~FMovieSceneObjectBindingIDPicker() { } + + /** Get the sequence to look up object bindings within. Only used when no sequencer is available. */ virtual UMovieSceneSequence* GetSequence() const = 0; /** Set the current binding ID */ @@ -38,20 +62,51 @@ protected: /** Access the tooltip text that relates to the currently selected binding ID */ FText GetToolTipText() const; + /** Get the icon that represents the currently assigned binding */ + FSlateIcon GetCurrentIcon() const; + const FSlateBrush* GetCurrentIconBrush() const; + + /** Get the visibility for the spawnable icon overlap */ + EVisibility GetSpawnableIconOverlayVisibility() const; + /** Assign a new binding ID in response to user-input */ void SetBindingId(FMovieSceneObjectBindingID InBindingId); /** Build menu content that allows the user to choose a binding from inside the source sequence */ TSharedRef GetPickerMenu(); + /** Get a widget that represents the currently chosen item */ + TSharedRef GetCurrentItemWidget(TSharedRef TextContent); + + /** Optional sequencer ptr */ + TSharedPtr Sequencer; + + /** The ID of the sequence to generate IDs relative to */ + FMovieSceneSequenceID LocalSequenceID; + private: + /** Get the currently set binding ID, remapped to the root sequence if necessary */ + FMovieSceneObjectBindingID GetRemappedCurrentValue() const; + + /** Set the binding ID, remapped to the local sequence if possible */ + void SetRemappedCurrentValue(FMovieSceneObjectBindingID InValue); + + /** UPdate the cached text, tooltip and icon */ + void UpdateCachedData(); + /** Called when the combo box has been clicked to populate its menu content */ void OnGetMenuContent(FMenuBuilder& MenuBuilder, TSharedPtr Node); /** Cached current text and tooltips */ FText CurrentText, ToolTipText; + /** Cached current icon */ + FSlateIcon CurrentIcon; + + /** Cached value indicating whether the current item is a spawnable */ + bool bIsCurrentItemSpawnable; + /** Data tree that stores all the available bindings for the current sequence, and their identifiers */ TSharedPtr DataTree; }; \ No newline at end of file diff --git a/Engine/Source/Editor/NiagaraEditor/Private/Customizations/NiagaraComponentDetails.cpp b/Engine/Source/Editor/NiagaraEditor/Private/Customizations/NiagaraComponentDetails.cpp index a02ed6670daf..8fff670cb3d0 100644 --- a/Engine/Source/Editor/NiagaraEditor/Private/Customizations/NiagaraComponentDetails.cpp +++ b/Engine/Source/Editor/NiagaraEditor/Private/Customizations/NiagaraComponentDetails.cpp @@ -417,19 +417,12 @@ public: check(ObjectValue.DataInterface != nullptr); - if (ValueVariable) - { - check(ValueVariable->DataInterface->GetClass() == ObjectValue.DataInterface->GetClass()); - ensure(ValueVariable->DataInterface->CopyTo(ObjectValue.DataInterface)); + check(ValueVariable->DataInterface->GetClass() == ObjectValue.DataInterface->GetClass()); + ensure(ValueVariable->DataInterface->CopyTo(ObjectValue.DataInterface)); - if (DetailsView.IsValid()) - { - DetailsView->SetObject(ObjectValue.DataInterface); - } - } - else + if (DetailsView.IsValid()) { - UE_LOG(LogNiagaraEditor, Warning, TEXT("Data interface %s does not exist!"), *ValueVariable->Name.ToString()); + DetailsView->SetObject(ObjectValue.DataInterface); } } diff --git a/Engine/Source/Editor/NiagaraEditor/Private/EdGraphSchema_Niagara.cpp b/Engine/Source/Editor/NiagaraEditor/Private/EdGraphSchema_Niagara.cpp index ef4a6d55000a..a91865e885b3 100644 --- a/Engine/Source/Editor/NiagaraEditor/Private/EdGraphSchema_Niagara.cpp +++ b/Engine/Source/Editor/NiagaraEditor/Private/EdGraphSchema_Niagara.cpp @@ -571,7 +571,7 @@ void UEdGraphSchema_Niagara::GetGraphContextActions(FGraphContextMenuBuilder& Co } }; - GenSwizzles(TEXT("")); + GenSwizzles(FString()); for (FString Swiz : Swizzles) { @@ -773,7 +773,7 @@ const FPinConnectionResponse UEdGraphSchema_Niagara::CanCreateConnection(const U } else { - return FPinConnectionResponse(CONNECT_RESPONSE_MAKE, TEXT("")); + return FPinConnectionResponse(CONNECT_RESPONSE_MAKE, FString()); } } @@ -939,25 +939,22 @@ FNiagaraVariable UEdGraphSchema_Niagara::PinToNiagaraVariable(const UEdGraphPin* if (!Pin->DefaultValue.IsEmpty()) { //Having to do some very hacky and fragile messing with the default value. TODO: Our own pin type in which we can control the default value formatting so that we can just shove it right into hlsl. - if (!Pin->DefaultValue.IsEmpty()) + // The subsequent logic for alphanumeric constant testing won't work for bools, as we explicitly look for the string "true" below. + if (Var.GetType() == FNiagaraTypeDefinition::GetBoolDef()) { - // The subsequent logic for alphanumeric constant testing won't work for bools, as we explicitly look for the string "true" below. - if (Var.GetType() == FNiagaraTypeDefinition::GetBoolDef()) + if (Pin->DefaultValue.Equals(TEXT("true"))) { - if (Pin->DefaultValue.Equals(TEXT("true"))) - { - Default = Pin->DefaultValue; - } + Default = Pin->DefaultValue; } - else + } + else + { + Default.Reserve(Pin->DefaultValue.Len()); + for (int Pos = 0; Pos < Pin->DefaultValue.Len(); ++Pos) { - Default.Reserve(Pin->DefaultValue.Len()); - for (int Pos = 0; Pos < Pin->DefaultValue.Len(); ++Pos) + if ((FChar::IsAlnum(Pin->DefaultValue[Pos]) && !FChar::IsAlpha(Pin->DefaultValue[Pos])) || Pin->DefaultValue[Pos] == TEXT(',') || Pin->DefaultValue[Pos] == TEXT('.') || Pin->DefaultValue[Pos] == TEXT('-')) { - if ((FChar::IsAlnum(Pin->DefaultValue[Pos]) && !FChar::IsAlpha(Pin->DefaultValue[Pos])) || Pin->DefaultValue[Pos] == TEXT(',') || Pin->DefaultValue[Pos] == TEXT('.') || Pin->DefaultValue[Pos] == TEXT('-')) - { - Default.AppendChar(Pin->DefaultValue[Pos]); - } + Default.AppendChar(Pin->DefaultValue[Pos]); } } } @@ -1054,12 +1051,12 @@ FEdGraphPinType UEdGraphSchema_Niagara::TypeDefinitionToPinType(FNiagaraTypeDefi { if (TypeDef.GetClass()) { - return FEdGraphPinType(PinCategoryClass, TEXT(""), const_cast(TypeDef.GetClass()), false, false, false, false, FEdGraphTerminalType()); + return FEdGraphPinType(PinCategoryClass, FString(), const_cast(TypeDef.GetClass()), EPinContainerType::None, false, FEdGraphTerminalType()); } else { //TODO: Are base types better as structs or done like BPS as a special name? - return FEdGraphPinType(PinCategoryType, TEXT(""), const_cast(TypeDef.GetScriptStruct()), false, false, false, false, FEdGraphTerminalType()); + return FEdGraphPinType(PinCategoryType, FString(), const_cast(TypeDef.GetScriptStruct()), EPinContainerType::None, false, FEdGraphTerminalType()); } } @@ -1102,7 +1099,7 @@ void UEdGraphSchema_Niagara::GetBreakLinkToSubMenuActions(class FMenuBuilder& Me UEdGraphPin* Pin = *Links; FString TitleString = Pin->GetOwningNode()->GetNodeTitle(ENodeTitleType::ListView).ToString(); FText Title = FText::FromString(TitleString); - if (Pin->PinName != TEXT("")) + if (!Pin->PinName.IsEmpty()) { TitleString = FString::Printf(TEXT("%s (%s)"), *TitleString, *Pin->PinName); diff --git a/Engine/Source/Editor/NiagaraEditor/Private/NiagaraCompiler.cpp b/Engine/Source/Editor/NiagaraEditor/Private/NiagaraCompiler.cpp index 8a677d5f24bc..5395b344ea01 100644 --- a/Engine/Source/Editor/NiagaraEditor/Private/NiagaraCompiler.cpp +++ b/Engine/Source/Editor/NiagaraEditor/Private/NiagaraCompiler.cpp @@ -556,7 +556,7 @@ ENiagaraScriptCompileStatus FNiagaraEditorModule::CompileScript(UNiagaraScript* FNiagaraCompileResults Results; FHlslNiagaraCompiler Compiler; - if (ScriptToCompile && ScriptToCompile->Usage == ENiagaraScriptUsage::EffectScript) + if (ScriptToCompile->Usage == ENiagaraScriptUsage::EffectScript) { ENiagaraScriptCompileStatus Status = CompileEffectScript(ScriptToCompile, OutGraphLevelErrorMessages); Graph->MarkOtherSynchronized(ScriptToCompile->ChangeId); @@ -2001,7 +2001,7 @@ void FHlslNiagaraCompiler::Operation(class UNiagaraNodeOp* Operation, TArrayPinFriendlyName.IsEmpty() ? FText::FromString(OutputPins[OutputIndex]->PinName) : OutputPins[OutputIndex]->PinFriendlyName; - Error(FText::Format(LOCTEXT("GetConstantFail", "Cannot handle type {0}! Output Pin: {1}"), OutputType.GetNameText(), PinNameText), Operation, OutputPins[OutputIndex]); + Error(FText::Format(LOCTEXT("GetConstantFail_OutputPin", "Cannot handle type {0}! Output Pin: {1}"), OutputType.GetNameText(), PinNameText), Operation, OutputPins[OutputIndex]); } const FNiagaraOpInOutInfo& IOInfo = OpInfo->Outputs[OutputIndex]; diff --git a/Engine/Source/Editor/NiagaraEditor/Private/NiagaraEditorCommon.cpp b/Engine/Source/Editor/NiagaraEditor/Private/NiagaraEditorCommon.cpp index df034572c3f4..fd26d982f674 100644 --- a/Engine/Source/Editor/NiagaraEditor/Private/NiagaraEditorCommon.cpp +++ b/Engine/Source/Editor/NiagaraEditor/Private/NiagaraEditorCommon.cpp @@ -306,17 +306,6 @@ void FNiagaraOpInfo::Init() Op->BuildName(TEXT("ATan2"), CategoryName); OpInfoMap.Add(Op->Name) = Idx; - Idx = OpInfos.AddDefaulted(); - Op = &OpInfos[Idx]; - Op->Category = CategoryText; - Op->FriendlyName = NSLOCTEXT("NiagaraOpInfo", "ATan2 Name", "ATan2"); - Op->Description = NSLOCTEXT("NiagaraOpInfo", "ATan2 Desc", "Result = atan2(A, B)"); - Op->Inputs.Add(FNiagaraOpInOutInfo(A, Type, AText, AText, DefaultStr_One)); - Op->Inputs.Add(FNiagaraOpInOutInfo(B, Type, BText, BText, DefaultStr_One)); - Op->Outputs.Add(FNiagaraOpInOutInfo(Result, Type, ResultText, ResultText, DefaultStr_One, TEXT("atan2({0},{1})"))); - Op->BuildName(TEXT("ATan2"), CategoryName); - OpInfoMap.Add(Op->Name) = Idx; - Idx = OpInfos.AddDefaulted(); Op = &OpInfos[Idx]; Op->Category = CategoryText; diff --git a/Engine/Source/Editor/NiagaraEditor/Private/NiagaraEditorUtilities.cpp b/Engine/Source/Editor/NiagaraEditor/Private/NiagaraEditorUtilities.cpp index e317b7d87801..6cf2d013cb34 100644 --- a/Engine/Source/Editor/NiagaraEditor/Private/NiagaraEditorUtilities.cpp +++ b/Engine/Source/Editor/NiagaraEditor/Private/NiagaraEditorUtilities.cpp @@ -67,7 +67,7 @@ void FNiagaraEditorUtilities::ResetVariableToDefaultValue(FNiagaraVariable& Vari } } -void FNiagaraEditorUtilities::InitializeParameterInputNode(UNiagaraNodeInput& InputNode, const FNiagaraTypeDefinition& Type, const class UNiagaraGraph* InGraph, FName InputName) +void FNiagaraEditorUtilities::InitializeParameterInputNode(UNiagaraNodeInput& InputNode, const FNiagaraTypeDefinition& Type, const UNiagaraGraph* InGraph, FName InputName) { InputNode.Usage = ENiagaraInputNodeUsage::Parameter; InputNode.bCanRenameNode = true; diff --git a/Engine/Source/Editor/NiagaraEditor/Private/NiagaraNodeEmitter.cpp b/Engine/Source/Editor/NiagaraEditor/Private/NiagaraNodeEmitter.cpp index d6a70dd722ee..aade8af83f5d 100644 --- a/Engine/Source/Editor/NiagaraEditor/Private/NiagaraNodeEmitter.cpp +++ b/Engine/Source/Editor/NiagaraEditor/Private/NiagaraNodeEmitter.cpp @@ -61,11 +61,6 @@ void UNiagaraNodeEmitter::BuildNameList(TSet& ParameterNames, TSet return; } - if (Script == nullptr) - { - return; - } - if (Script->Source == nullptr || !Script->Source->IsA(UNiagaraScriptSource::StaticClass())) { return; diff --git a/Engine/Source/Editor/NiagaraEditor/Public/NiagaraNodeIf.h b/Engine/Source/Editor/NiagaraEditor/Private/NiagaraNodeIf.h similarity index 100% rename from Engine/Source/Editor/NiagaraEditor/Public/NiagaraNodeIf.h rename to Engine/Source/Editor/NiagaraEditor/Private/NiagaraNodeIf.h diff --git a/Engine/Source/Editor/NiagaraEditor/Private/NiagaraNodeInput.cpp b/Engine/Source/Editor/NiagaraEditor/Private/NiagaraNodeInput.cpp index baa322338e77..7dbc8dbbefaf 100644 --- a/Engine/Source/Editor/NiagaraEditor/Private/NiagaraNodeInput.cpp +++ b/Engine/Source/Editor/NiagaraEditor/Private/NiagaraNodeInput.cpp @@ -189,7 +189,7 @@ bool UNiagaraNodeInput::VerifyNodeRenameTextCommit(const FText& NewText, UNiagar // This should still allow case changes b/c we test to make sure that they aren't referencing the same node. if (bIsSame == false && Node->Input.GetName().IsEqual(NewName, ENameCase::IgnoreCase)) { - OutErrorMessage = FText::Format(LOCTEXT("NiagaraInputNameSameWarn", "\"{0}\" is the name of another parameter."), FText::FromName(NewName)); + OutErrorMessage = FText::Format(LOCTEXT("NiagaraInputNameSameParameterWarn", "\"{0}\" is the name of another parameter."), FText::FromName(NewName)); return false; } } @@ -211,7 +211,7 @@ bool UNiagaraNodeInput::VerifyNodeRenameTextCommit(const FText& NewText, UNiagar if (Output.GetName().IsEqual(NewName, ENameCase::IgnoreCase)) { - OutErrorMessage = FText::Format(LOCTEXT("NiagaraInputNameSameWarn", "\"{0}\" is the name of another attribute. Hit \"Escape\" to cancel edit."), FText::FromName(NewName)); + OutErrorMessage = FText::Format(LOCTEXT("NiagaraInputNameSameAttributeWarn", "\"{0}\" is the name of another attribute. Hit \"Escape\" to cancel edit."), FText::FromName(NewName)); return false; } } diff --git a/Engine/Source/Editor/NiagaraEditor/Private/NiagaraNodeWithDynamicPins.cpp b/Engine/Source/Editor/NiagaraEditor/Private/NiagaraNodeWithDynamicPins.cpp index b41f701a1cd2..2be0d382002c 100644 --- a/Engine/Source/Editor/NiagaraEditor/Private/NiagaraNodeWithDynamicPins.cpp +++ b/Engine/Source/Editor/NiagaraEditor/Private/NiagaraNodeWithDynamicPins.cpp @@ -79,7 +79,7 @@ UEdGraphPin* UNiagaraNodeWithDynamicPins::RequestNewTypedPin(EEdGraphPinDirectio void UNiagaraNodeWithDynamicPins::CreateAddPin(EEdGraphPinDirection Direction) { - CreatePin(Direction, FEdGraphPinType(UEdGraphSchema_Niagara::PinCategoryMisc, AddPinSubCategory, nullptr, false, false, false, false, FEdGraphTerminalType()), TEXT("Add")); + CreatePin(Direction, FEdGraphPinType(UEdGraphSchema_Niagara::PinCategoryMisc, AddPinSubCategory, nullptr, EPinContainerType::None, false, FEdGraphTerminalType()), TEXT("Add")); } bool IsAddPin(const UEdGraphPin* Pin) diff --git a/Engine/Source/Editor/NiagaraEditor/Private/Toolkits/NiagaraEmitterToolKit.cpp b/Engine/Source/Editor/NiagaraEditor/Private/Toolkits/NiagaraEmitterToolKit.cpp index 81cfb0e6e8b6..a876b264d7dc 100644 --- a/Engine/Source/Editor/NiagaraEditor/Private/Toolkits/NiagaraEmitterToolKit.cpp +++ b/Engine/Source/Editor/NiagaraEditor/Private/Toolkits/NiagaraEmitterToolKit.cpp @@ -469,7 +469,7 @@ bool FNiagaraEmitterToolkit::OnRequestClose() // find out the user wants to do with this dirty NiagaraScript EAppReturnType::Type YesNoCancelReply = FMessageDialog::Open(EAppMsgType::YesNoCancel, FText::Format( - NSLOCTEXT("UnrealEd", "Prompt_NiagaraScriptEditorClose", "Would you like to apply changes to this Emitter to the original Emitter?\n{0}\n(No will lose all changes!)"), + NSLOCTEXT("UnrealEd", "Prompt_NiagaraEmitterEditorClose", "Would you like to apply changes to this Emitter to the original Emitter?\n{0}\n(No will lose all changes!)"), FText::FromString(OriginalEmitter->GetPathName()))); // act on it diff --git a/Engine/Source/Editor/NiagaraEditor/Private/ViewModels/NiagaraEffectScriptViewModel.cpp b/Engine/Source/Editor/NiagaraEditor/Private/ViewModels/NiagaraEffectScriptViewModel.cpp index 1a8d458e8875..8b0f542ba06c 100644 --- a/Engine/Source/Editor/NiagaraEditor/Private/ViewModels/NiagaraEffectScriptViewModel.cpp +++ b/Engine/Source/Editor/NiagaraEditor/Private/ViewModels/NiagaraEffectScriptViewModel.cpp @@ -115,7 +115,7 @@ void FNiagaraEffectScriptViewModel::RefreshEmitterNodes() EmitterNode->SetOwnerEffect(&Effect); EmitterNode->SetEmitterHandleId(EmitterHandle.GetId()); - FVector2D NewLocation = CalculateNewEmitterNodePlacementPosition(EffectGraph, EmitterNode); + FVector2D NewLocation = CalculateNewEmitterNodePlacementPosition(EffectGraph, EmitterNode); //-V595 EmitterNode->NodePosX = NewLocation.X; EmitterNode->NodePosY = NewLocation.Y; diff --git a/Engine/Source/Editor/NiagaraEditor/Public/INiagaraCompiler.h b/Engine/Source/Editor/NiagaraEditor/Public/INiagaraCompiler.h index 7cb1aa932304..a8524a4fc1d3 100644 --- a/Engine/Source/Editor/NiagaraEditor/Public/INiagaraCompiler.h +++ b/Engine/Source/Editor/NiagaraEditor/Public/INiagaraCompiler.h @@ -39,6 +39,7 @@ struct FNiagaraCompileResults class INiagaraCompiler { public: + virtual ~INiagaraCompiler() { } /** Compiles a script. */ virtual const FNiagaraCompileResults& CompileScript(class UNiagaraScript* InScript) = 0; diff --git a/Engine/Source/Editor/Persona/Persona.Build.cs b/Engine/Source/Editor/Persona/Persona.Build.cs index e57935d11cf6..7c0d8c979c0d 100644 --- a/Engine/Source/Editor/Persona/Persona.Build.cs +++ b/Engine/Source/Editor/Persona/Persona.Build.cs @@ -55,6 +55,7 @@ public class Persona : ModuleRules "ClothingSystemRuntime", "ClothingSystemEditorInterface", "ClothingSystemRuntimeInterface", + "AnimGraphRuntime", } ); diff --git a/Engine/Source/Editor/Persona/Private/AnimationEditorPreviewScene.cpp b/Engine/Source/Editor/Persona/Private/AnimationEditorPreviewScene.cpp index 1ca615a8e217..f410daa7664f 100644 --- a/Engine/Source/Editor/Persona/Private/AnimationEditorPreviewScene.cpp +++ b/Engine/Source/Editor/Persona/Private/AnimationEditorPreviewScene.cpp @@ -22,6 +22,8 @@ #include "GameFramework/WorldSettings.h" #include "Particles/ParticleSystemComponent.h" #include "Factories/PreviewMeshCollectionFactory.h" +#include "AnimPreviewAttacheInstance.h" +#include "PreviewCollectionInterface.h" #define LOCTEXT_NAMESPACE "AnimationEditorPreviewScene" @@ -54,6 +56,9 @@ FAnimationEditorPreviewScene::FAnimationEditorPreviewScene(const ConstructionVal SkeletalMeshComponent = NewObject(Actor); AddComponent(SkeletalMeshComponent, FTransform::Identity); + // set root component, so we can attach to it. + Actor->SetRootComponent(SkeletalMeshComponent); + InEditableSkeleton->LoadAdditionalPreviewSkeletalMeshes(); // create the preview scene description @@ -68,7 +73,7 @@ FAnimationEditorPreviewScene::FAnimationEditorPreviewScene(const ConstructionVal // create a default additional mesh collection so we dont always have to create an asset to edit additional meshes UPreviewMeshCollectionFactory* FactoryToUse = NewObject(); FactoryToUse->CurrentSkeleton = &InEditableSkeleton->GetSkeleton(); - PreviewSceneDescription->DefaultAdditionalMeshes = CastChecked(FactoryToUse->FactoryCreateNew(UPreviewMeshCollection::StaticClass(), GetTransientPackage(), "UnsavedCollection", RF_Transient, nullptr, nullptr)); + PreviewSceneDescription->DefaultAdditionalMeshes = CastChecked(FactoryToUse->FactoryCreateNew(UPreviewMeshCollection::StaticClass(), PreviewSceneDescription, "UnsavedCollection", RF_Transient, nullptr, nullptr)); if (!PreviewSceneDescription->AdditionalMeshes.IsValid()) { @@ -134,6 +139,21 @@ void FAnimationEditorPreviewScene::SetPreviewMeshInternal(USkeletalMesh* NewPrev { USkeletalMesh* OldPreviewMesh = SkeletalMeshComponent->SkeletalMesh; + // Store off the old skel mesh we are debugging + USkeletalMeshComponent* DebuggedSkeletalMeshComponent = nullptr; + if(SkeletalMeshComponent->GetAnimInstance()) + { + UAnimBlueprint* SourceBlueprint = Cast(SkeletalMeshComponent->GetAnimInstance()->GetClass()->ClassGeneratedBy); + if(SourceBlueprint) + { + UAnimInstance* DebuggedAnimInstance = Cast(SourceBlueprint->GetObjectBeingDebugged()); + if(DebuggedAnimInstance) + { + DebuggedSkeletalMeshComponent = DebuggedAnimInstance->GetSkelMeshComponent(); + } + } + } + // Make sure the desc is up to date as this may have not come from a call to set the value in the desc PreviewSceneDescription->PreviewMesh = NewPreviewMesh; @@ -177,7 +197,7 @@ void FAnimationEditorPreviewScene::SetPreviewMeshInternal(USkeletalMesh* NewPrev AddComponent(SkeletalMeshComponent, FTransform::Identity); for (auto Iter = AdditionalMeshes.CreateIterator(); Iter; ++Iter) { - AddComponent((*Iter), FTransform::Identity); + AddComponent((*Iter), FTransform::Identity, true); } // Set up the mesh for transactions @@ -196,10 +216,10 @@ void FAnimationEditorPreviewScene::SetPreviewMeshInternal(USkeletalMesh* NewPrev // Setting the skeletal mesh to in the PreviewScene can change AnimScriptInstance so we must re register it // with the AnimBlueprint - if (SkeletalMeshComponent->IsAnimBlueprintInstanced()) + if (DebuggedSkeletalMeshComponent) { UAnimBlueprint* SourceBlueprint = CastChecked(SkeletalMeshComponent->GetAnimInstance()->GetClass()->ClassGeneratedBy); - SourceBlueprint->SetObjectBeingDebugged(SkeletalMeshComponent->GetAnimInstance()); + SourceBlueprint->SetObjectBeingDebugged(DebuggedSkeletalMeshComponent->GetAnimInstance()); } OnPreviewMeshChanged.Broadcast(OldPreviewMesh, NewPreviewMesh); @@ -232,7 +252,7 @@ void FAnimationEditorPreviewScene::ValidatePreviewAttachedAssets(USkeletalMesh* } } -void FAnimationEditorPreviewScene::SetAdditionalMeshes(class UPreviewMeshCollection* InAdditionalMeshes) +void FAnimationEditorPreviewScene::SetAdditionalMeshes(class UDataAsset* InAdditionalMeshes) { GetEditableSkeleton()->SetAdditionalPreviewSkeletalMeshes(InAdditionalMeshes); @@ -244,13 +264,14 @@ void FAnimationEditorPreviewScene::RefreshAdditionalMeshes() // remove all components for (USkeletalMeshComponent* Component : AdditionalMeshes) { + UAnimCustomInstance::UnbindFromSkeletalMeshComponent(Component); RemoveComponent(Component); } AdditionalMeshes.Empty(); // add new components - UPreviewMeshCollection* PreviewSceneAdditionalMeshes = GetEditableSkeleton()->GetSkeleton().GetAdditionalPreviewSkeletalMeshes(); + UDataAsset* PreviewSceneAdditionalMeshes = GetEditableSkeleton()->GetSkeleton().GetAdditionalPreviewSkeletalMeshes(); if (PreviewSceneAdditionalMeshes == nullptr) { PreviewSceneAdditionalMeshes = PreviewSceneDescription->DefaultAdditionalMeshes; @@ -258,57 +279,25 @@ void FAnimationEditorPreviewScene::RefreshAdditionalMeshes() if (PreviewSceneAdditionalMeshes != nullptr) { - // While loading our meshes, look for the one with the 'best' bone count. - // We will use this in lieu of a master if we have none set - int32 BestBoneCount = 0; - int32 BestMasterIndex = 0; TArray ValidMeshes; - for (int32 MeshIndex = 0; MeshIndex < PreviewSceneAdditionalMeshes->SkeletalMeshes.Num(); ++MeshIndex) + + // get preview interface + const IPreviewCollectionInterface* PreviewCollection = Cast(PreviewSceneAdditionalMeshes); + if (PreviewCollection) { - FPreviewMeshCollectionEntry& Entry = PreviewSceneAdditionalMeshes->SkeletalMeshes[MeshIndex]; - - // Load up our valid skeletal meshes - if (Entry.SkeletalMesh.LoadSynchronous()) - { - USkeletalMesh* SkeletalMesh = Entry.SkeletalMesh.Get(); - - int32 BoneCount = SkeletalMesh->RefSkeleton.GetNum(); - if (BoneCount > BestBoneCount) - { - BestMasterIndex = ValidMeshes.Num(); - BestBoneCount = BoneCount; - } - - ValidMeshes.Add(SkeletalMesh); - } - } - - const int32 NumMeshes = ValidMeshes.Num(); - if (NumMeshes > 0) - { - // if the master component has no skeletal mesh, we need to set up one of the additional meshes - // as the master instead - bool bSubstitutedMaster = false; - if (SkeletalMeshComponent->SkeletalMesh == nullptr) - { - SetPreviewMeshInternal(ValidMeshes[BestMasterIndex]); - bSubstitutedMaster = true; - } - + PreviewCollection->GetPreviewSkeletalMeshes(ValidMeshes); + const int32 NumMeshes = ValidMeshes.Num(); for (int32 MeshIndex = 0; MeshIndex < NumMeshes; ++MeshIndex) { - if (!(bSubstitutedMaster && MeshIndex == BestMasterIndex)) + USkeletalMesh* SkeletalMesh = ValidMeshes[MeshIndex]; + if (SkeletalMesh) { - USkeletalMesh* SkeletalMesh = ValidMeshes[MeshIndex]; - if (SkeletalMesh) - { - USkeletalMeshComponent* NewComp = NewObject(Actor); - NewComp->SetMasterPoseComponent(SkeletalMeshComponent); - NewComp->SetSkeletalMesh(SkeletalMesh); - NewComp->UpdateMasterBoneMap(); - AddComponent(NewComp, FTransform::Identity); - AdditionalMeshes.Add(NewComp); - } + USkeletalMeshComponent* NewComp = NewObject(Actor); + NewComp->RegisterComponent(); + NewComp->SetSkeletalMesh(SkeletalMesh); + UAnimCustomInstance::BindToSkeletalMeshComponent(NewComp); + AddComponent(NewComp, FTransform::Identity, true); + AdditionalMeshes.Add(NewComp); } } } @@ -463,6 +452,12 @@ void FAnimationEditorPreviewScene::RemoveAttachedComponent( bool bRemovePreviewA } } + // if this component is added by additional meshes, do not remove it. + if (AdditionalMeshes.Contains(ChildComponent)) + { + bRemove = false; + } + if(bRemove) { // PreviewComponet will be cleaned up by PreviewScene, @@ -489,6 +484,8 @@ void FAnimationEditorPreviewScene::CleanupComponent(USceneComponent* Component) } check(Component->GetAttachChildren().Num() == 0); + // make sure to remove from component list + RemoveComponent(Component); Component->DestroyComponent(); } } @@ -964,11 +961,14 @@ void FAnimationEditorPreviewScene::Tick(float InDeltaTime) } } -void FAnimationEditorPreviewScene::AddComponent(class UActorComponent* Component, const FTransform& LocalToWorld) +void FAnimationEditorPreviewScene::AddComponent(class UActorComponent* Component, const FTransform& LocalToWorld, bool bAttachToRoot /*= false*/) { - if (USceneComponent* SceneComponent = Cast(Component)) + if (bAttachToRoot) { - SceneComponent->AttachToComponent(Actor->GetRootComponent(), FAttachmentTransformRules::KeepWorldTransform); + if (USceneComponent* SceneComponent = Cast(Component)) + { + SceneComponent->AttachToComponent(Actor->GetRootComponent(), FAttachmentTransformRules::KeepWorldTransform); + } } Actor->AddOwnedComponent(Component); diff --git a/Engine/Source/Editor/Persona/Private/AnimationEditorPreviewScene.h b/Engine/Source/Editor/Persona/Private/AnimationEditorPreviewScene.h index 8a3c328a753a..79f7b83110b3 100644 --- a/Engine/Source/Editor/Persona/Private/AnimationEditorPreviewScene.h +++ b/Engine/Source/Editor/Persona/Private/AnimationEditorPreviewScene.h @@ -30,7 +30,7 @@ public: virtual void InvalidateViews() override; virtual void FocusViews() override; virtual UDebugSkelMeshComponent* GetPreviewMeshComponent() const override { return SkeletalMeshComponent; } - virtual void SetAdditionalMeshes(class UPreviewMeshCollection* InAdditionalMeshes) override; + virtual void SetAdditionalMeshes(class UDataAsset* InAdditionalMeshes) override; virtual void RefreshAdditionalMeshes() override; virtual void ShowReferencePose(bool bReferencePose) override; virtual bool IsShowReferencePoseEnabled() const override; @@ -118,9 +118,27 @@ public: virtual bool AllowMeshHitProxies() const override; virtual void SetAllowMeshHitProxies(bool bState) override; + virtual void RegisterOnSelectedLODChanged(const FOnSelectedLODChanged &Delegate) override + { + OnSelectedLODChanged.Add(Delegate); + } + + virtual void UnRegisterOnSelectedLODChanged(void* Thing) override + { + OnSelectedLODChanged.RemoveAll(Thing); + } + + virtual void BroadcastOnSelectedLODChanged() override + { + if (OnSelectedLODChanged.IsBound()) + { + OnSelectedLODChanged.Broadcast(); + } + } + /** FPreviewScene interface */ virtual void Tick(float InDeltaTime) override; - virtual void AddComponent(class UActorComponent* Component, const FTransform& LocalToWorld) override; + virtual void AddComponent(class UActorComponent* Component, const FTransform& LocalToWorld, bool bAttachToRoot = false) override; virtual void RemoveComponent(class UActorComponent* Component) override; /** FEditorUndoClient interface */ @@ -280,4 +298,7 @@ private: /** Whether or not mesh section hit proxies should be enabled or not */ bool bEnableMeshHitProxies; + + /* Selected LOD changed delegate */ + FOnSelectedLODChangedMulticaster OnSelectedLODChanged; }; diff --git a/Engine/Source/Editor/Persona/Private/AnimationEditorViewportClient.cpp b/Engine/Source/Editor/Persona/Private/AnimationEditorViewportClient.cpp index 1719fd9ee1ae..3c1f766f608c 100644 --- a/Engine/Source/Editor/Persona/Private/AnimationEditorViewportClient.cpp +++ b/Engine/Source/Editor/Persona/Private/AnimationEditorViewportClient.cpp @@ -578,7 +578,7 @@ void FAnimationViewportClient::ShowBoneNames( FCanvas* Canvas, FSceneView* View const FColor BoneColor = FColor::White; if (BoneColor.A != 0) { - const FVector BonePos = PreviewMeshComponent->ComponentToWorld.TransformPosition(PreviewMeshComponent->GetComponentSpaceTransforms()[BoneIndex].GetLocation()); + const FVector BonePos = PreviewMeshComponent->GetComponentTransform().TransformPosition(PreviewMeshComponent->GetComponentSpaceTransforms()[BoneIndex].GetLocation()); const FPlane proj = View->Project(BonePos); if (proj.W > 0.f) @@ -1102,7 +1102,7 @@ void FAnimationViewportClient::DrawBonesFromTransforms(TArray& Trans const int32 BoneIndex = MeshComponent->RequiredBones[Index]; const int32 ParentIndex = MeshComponent->SkeletalMesh->RefSkeleton.GetParentIndex(BoneIndex); - WorldTransforms[BoneIndex] = Transforms[BoneIndex] * MeshComponent->ComponentToWorld; + WorldTransforms[BoneIndex] = Transforms[BoneIndex] * MeshComponent->GetComponentTransform(); BoneColours[BoneIndex] = (ParentIndex >= 0) ? BoneColour : RootBoneColour; } @@ -1129,7 +1129,7 @@ void FAnimationViewportClient::DrawBonesFromCompactPose(const FCompactHeapPose& if (ParentIndex == INDEX_NONE) { - WorldTransforms[MeshBoneIndex.GetInt()] = Pose[BoneIndex] * MeshComponent->ComponentToWorld; + WorldTransforms[MeshBoneIndex.GetInt()] = Pose[BoneIndex] * MeshComponent->GetComponentTransform(); } else { @@ -1224,7 +1224,7 @@ void FAnimationViewportClient::DrawMeshBones(USkeletalMeshComponent * MeshCompon const int32 BoneIndex = MeshComponent->RequiredBones[Index]; const int32 ParentIndex = MeshComponent->SkeletalMesh->RefSkeleton.GetParentIndex(BoneIndex); - WorldTransforms[BoneIndex] = MeshComponent->GetComponentSpaceTransforms()[BoneIndex] * MeshComponent->ComponentToWorld; + WorldTransforms[BoneIndex] = MeshComponent->GetComponentSpaceTransforms()[BoneIndex] * MeshComponent->GetComponentTransform(); if(SelectedBones.Contains(BoneIndex)) { @@ -1375,7 +1375,7 @@ void FAnimationViewportClient::DrawMeshSubsetBones(const USkeletalMeshComponent* //found a bone we are interested in if(ParentIndex >= 0) { - WorldTransforms[ParentIndex] = MeshComponent->GetComponentSpaceTransforms()[ParentIndex]*MeshComponent->ComponentToWorld; + WorldTransforms[ParentIndex] = MeshComponent->GetComponentSpaceTransforms()[ParentIndex]*MeshComponent->GetComponentTransform(); } BoneColours[BoneIndex] = LinearSelectionColor; bDrawBone = true; @@ -1393,7 +1393,7 @@ void FAnimationViewportClient::DrawMeshSubsetBones(const USkeletalMeshComponent* { //add to the list RequiredBones.AddUnique(BoneIndex); - WorldTransforms[BoneIndex] = MeshComponent->GetComponentSpaceTransforms()[BoneIndex] * MeshComponent->ComponentToWorld; + WorldTransforms[BoneIndex] = MeshComponent->GetComponentSpaceTransforms()[BoneIndex] * MeshComponent->GetComponentTransform(); } } @@ -1420,7 +1420,7 @@ void FAnimationViewportClient::DrawSockets(const UDebugSkelMeshComponent* InPrev FVector Start, End; if (ParentIndex >=0) { - FTransform WorldTransformParent = InPreviewMeshComponent->GetComponentSpaceTransforms()[ParentIndex] * InPreviewMeshComponent->ComponentToWorld; + FTransform WorldTransformParent = InPreviewMeshComponent->GetComponentSpaceTransforms()[ParentIndex] * InPreviewMeshComponent->GetComponentTransform(); Start = WorldTransformParent.GetLocation(); End = WorldTransformSocket.GetLocation(); } @@ -1477,8 +1477,7 @@ FSphere FAnimationViewportClient::GetCameraTarget() UDebugSkelMeshComponent* PreviewMeshComponent = GetAnimPreviewScene()->GetPreviewMeshComponent(); if( PreviewMeshComponent != nullptr ) { - FTransform ComponentToWorld = PreviewMeshComponent->ComponentToWorld; - PreviewMeshComponent->CalcBounds(ComponentToWorld); + PreviewMeshComponent->CalcBounds(PreviewMeshComponent->GetComponentTransform()); // give the editor mode a chance to give us a camera target FSphere Target; @@ -1724,7 +1723,12 @@ void FAnimationViewportClient::OnAssetViewerSettingsChanged(const FName& InPrope { if (InPropertyName == GET_MEMBER_NAME_CHECKED(FPreviewSceneProfile, bPostProcessingEnabled) || InPropertyName == NAME_None) { - SetAdvancedShowFlagsForScene(UAssetViewerSettings::Get()->Profiles[GetPreviewScene()->GetCurrentProfileIndex()].bPostProcessingEnabled); + UAssetViewerSettings* Settings = UAssetViewerSettings::Get(); + const int32 ProfileIndex = GetPreviewScene()->GetCurrentProfileIndex(); + if (Settings->Profiles.IsValidIndex(ProfileIndex)) + { + SetAdvancedShowFlagsForScene(Settings->Profiles[ProfileIndex].bPostProcessingEnabled); + } } } diff --git a/Engine/Source/Editor/Persona/Private/BoneMappingHelper.cpp b/Engine/Source/Editor/Persona/Private/BoneMappingHelper.cpp index 645ba04f8dee..def50b61f4a6 100644 --- a/Engine/Source/Editor/Persona/Private/BoneMappingHelper.cpp +++ b/Engine/Source/Editor/Persona/Private/BoneMappingHelper.cpp @@ -62,7 +62,7 @@ float FBoneDescription::CalculateScore(const FBoneDescription& Other) const const int32 MaxNumChildren = FMath::Max(Other.NumChildren, NumChildren); if (MaxNumChildren > 0) { - Score_NumChildren = (1.f - (FMath::Abs(Other.NumChildren - NumChildren) / MaxNumChildren)); + Score_NumChildren = (1.f - ((float)(FMath::Abs(Other.NumChildren - NumChildren)) / MaxNumChildren)); } else { diff --git a/Engine/Source/Editor/Persona/Private/EditModes/SkeletonSelectionEditMode.cpp b/Engine/Source/Editor/Persona/Private/EditModes/SkeletonSelectionEditMode.cpp index 2b60239eeeaa..8a35467385f3 100644 --- a/Engine/Source/Editor/Persona/Private/EditModes/SkeletonSelectionEditMode.cpp +++ b/Engine/Source/Editor/Persona/Private/EditModes/SkeletonSelectionEditMode.cpp @@ -480,6 +480,7 @@ FVector FSkeletonSelectionEditMode::GetWidgetLocation() const bool FSkeletonSelectionEditMode::HandleClick(FEditorViewportClient* InViewportClient, HHitProxy *HitProxy, const FViewportClick &Click) { bool bHandled = false; + const bool bSelectingSections = GetAnimPreviewScene().AllowMeshHitProxies(); if ( HitProxy ) { @@ -495,19 +496,20 @@ bool FSkeletonSelectionEditMode::HandleClick(FEditorViewportClient* InViewportCl static_cast(InViewportClient)->GetSkeletonTree()->SetSelectedBone(static_cast(HitProxy)->BoneName); bHandled = true; } - else if ( HitProxy->IsA( HActor::StaticGetType() ) && GetAnimPreviewScene().AllowMeshHitProxies()) + else if ( HitProxy->IsA( HActor::StaticGetType() ) && bSelectingSections) { HActor* ActorHitProxy = static_cast(HitProxy); GetAnimPreviewScene().BroadcastMeshClick(ActorHitProxy, Click); bHandled = true; } } - else + + if ( !bHandled && !bSelectingSections ) { // Cast for phys bodies if we didn't get any hit proxies FHitResult Result(1.0f); UDebugSkelMeshComponent* PreviewMeshComponent = GetAnimPreviewScene().GetPreviewMeshComponent(); - bool bHit = PreviewMeshComponent->LineTraceComponent(Result, Click.GetOrigin(), Click.GetOrigin() + Click.GetDirection() * SkeletonSelectionModeConstants::BodyTraceDistance, FCollisionQueryParams(NAME_None,true)); + bool bHit = PreviewMeshComponent->LineTraceComponent(Result, Click.GetOrigin(), Click.GetOrigin() + Click.GetDirection() * SkeletonSelectionModeConstants::BodyTraceDistance, FCollisionQueryParams(NAME_None, FCollisionQueryParams::GetUnknownStatId(),true)); if(bHit) { diff --git a/Engine/Source/Editor/Persona/Private/PersonaMeshDetails.cpp b/Engine/Source/Editor/Persona/Private/PersonaMeshDetails.cpp index 4e53b5984332..516800fab2a9 100644 --- a/Engine/Source/Editor/Persona/Private/PersonaMeshDetails.cpp +++ b/Engine/Source/Editor/Persona/Private/PersonaMeshDetails.cpp @@ -26,6 +26,7 @@ #include "Widgets/Layout/SUniformGridPanel.h" #include "Widgets/Input/SButton.h" #include "Widgets/Input/SSpinBox.h" +#include "Widgets/Input/SComboButton.h" #include "Editor/UnrealEdEngine.h" #include "EditorDirectories.h" #include "UnrealEdGlobals.h" @@ -975,8 +976,17 @@ void FPersonaMeshDetails::OnPasteMaterialList() Mesh->PreEditChange(Property); FScopedTransaction Transaction(LOCTEXT("PersonaChangedPasteMaterialList", "Pasted material list")); Mesh->Modify(); - - FJsonObjectConverter::JsonValueToUProperty(RootJsonValue, Property, &Mesh->Materials, 0, 0); + TArray TempMaterials; + FJsonObjectConverter::JsonValueToUProperty(RootJsonValue, Property, &TempMaterials, 0, 0); + //Do not change the number of material in the array + for (int32 MaterialIndex = 0; MaterialIndex < TempMaterials.Num(); ++MaterialIndex) + { + if (Mesh->Materials.IsValidIndex(MaterialIndex)) + { + Mesh->Materials[MaterialIndex].MaterialInterface = TempMaterials[MaterialIndex].MaterialInterface; + } + } + Mesh->PostEditChange(); } @@ -1045,7 +1055,9 @@ void FPersonaMeshDetails::OnPasteMaterialItem(int32 CurrentSlot) if (Mesh->Materials.IsValidIndex(CurrentSlot)) { - FJsonObjectConverter::JsonObjectToUStruct(RootJsonObject.ToSharedRef(), FSkeletalMaterial::StaticStruct(), &Mesh->Materials[CurrentSlot], 0, 0); + FSkeletalMaterial TmpSkeletalMaterial; + FJsonObjectConverter::JsonObjectToUStruct(RootJsonObject.ToSharedRef(), FSkeletalMaterial::StaticStruct(), &TmpSkeletalMaterial, 0, 0); + Mesh->Materials[CurrentSlot].MaterialInterface = TmpSkeletalMaterial.MaterialInterface; } Mesh->PostEditChange(); @@ -1072,7 +1084,7 @@ void FPersonaMeshDetails::AddLODLevelCategories(IDetailLayoutBuilder& DetailLayo //Create material list panel to let users control the materials array { - FString MaterialCategoryName = FString(TEXT("Materials")); + FString MaterialCategoryName = FString(TEXT("Material Slots")); IDetailCategoryBuilder& MaterialCategory = DetailLayout.EditCategory(*MaterialCategoryName, FText::GetEmpty(), ECategoryPriority::Important); MaterialCategory.AddCustomRow(LOCTEXT("AddLODLevelCategories_MaterialArrayOperationAdd", "Materials Operation Add Material Slot")) .CopyAction(FUIAction(FExecuteAction::CreateSP(this, &FPersonaMeshDetails::OnCopyMaterialList), FCanExecuteAction::CreateSP(this, &FPersonaMeshDetails::OnCanCopyMaterialList))) @@ -1138,10 +1150,16 @@ void FPersonaMeshDetails::AddLODLevelCategories(IDetailLayoutBuilder& DetailLayo MaterialListDelegates.OnCanCopyMaterialItem.BindSP(this, &FPersonaMeshDetails::OnCanCopyMaterialItem); MaterialListDelegates.OnPasteMaterialItem.BindSP(this, &FPersonaMeshDetails::OnPasteMaterialItem); - MaterialCategory.AddCustomBuilder(MakeShareable(new FMaterialList(MaterialCategory.GetParentLayout(), MaterialListDelegates, false))); + MaterialCategory.AddCustomBuilder(MakeShareable(new FMaterialList(MaterialCategory.GetParentLayout(), MaterialListDelegates, false, true, true))); } } + int32 CurrentLodIndex = 0; + if (GetPersonaToolkit()->GetPreviewMeshComponent() != nullptr) + { + CurrentLodIndex = GetPersonaToolkit()->GetPreviewMeshComponent()->ForcedLodModel; + } + LodCategories.Empty(SkelMeshLODCount); // Create information panel for each LOD level. for (int32 LODIndex = 0; LODIndex < SkelMeshLODCount; ++LODIndex) { @@ -1182,9 +1200,10 @@ void FPersonaMeshDetails::AddLODLevelCategories(IDetailLayoutBuilder& DetailLayo FString CategoryName = FString(TEXT("LOD")); CategoryName.AppendInt(LODIndex); - FText LODLevelString = FText::Format(LOCTEXT("LODLevel", "LOD{0}"), FText::AsNumber(LODIndex)); + FText LODLevelString = FText::FromString(FString(TEXT("LOD Sections (LOD")) + FString::FromInt(LODIndex) + TEXT(")") ); IDetailCategoryBuilder& LODCategory = DetailLayout.EditCategory(*CategoryName, LODLevelString, ECategoryPriority::Important); + LodCategories.Add(&LODCategory); TSharedRef LODCategoryWidget = SNew(SBox) @@ -1204,6 +1223,7 @@ void FPersonaMeshDetails::AddLODLevelCategories(IDetailLayoutBuilder& DetailLayo SectionListDelegates.OnSectionChanged.BindSP(this, &FPersonaMeshDetails::OnSectionChanged); SectionListDelegates.OnGenerateCustomNameWidgets.BindSP(this, &FPersonaMeshDetails::OnGenerateCustomNameWidgetsForSection); SectionListDelegates.OnGenerateCustomSectionWidgets.BindSP(this, &FPersonaMeshDetails::OnGenerateCustomSectionWidgetsForSection); + SectionListDelegates.OnGenerateLodComboBox.BindSP(this, &FPersonaMeshDetails::OnGenerateLodComboBoxForSectionList); SectionListDelegates.OnCopySectionList.BindSP(this, &FPersonaMeshDetails::OnCopySectionList, LODIndex); SectionListDelegates.OnCanCopySectionList.BindSP(this, &FPersonaMeshDetails::OnCanCopySectionList, LODIndex); @@ -1212,7 +1232,9 @@ void FPersonaMeshDetails::AddLODLevelCategories(IDetailLayoutBuilder& DetailLayo SectionListDelegates.OnCanCopySectionItem.BindSP(this, &FPersonaMeshDetails::OnCanCopySectionItem); SectionListDelegates.OnPasteSectionItem.BindSP(this, &FPersonaMeshDetails::OnPasteSectionItem); - LODCategory.AddCustomBuilder(MakeShareable(new FSectionList(LODCategory.GetParentLayout(), SectionListDelegates, (LODIndex > 0)))); + LODCategory.AddCustomBuilder(MakeShareable(new FSectionList(LODCategory.GetParentLayout(), SectionListDelegates, false, 85, LODIndex))); + + GetPersonaToolkit()->GetPreviewScene()->RegisterOnSelectedLODChanged(FOnSelectedLODChanged::CreateSP(this, &FPersonaMeshDetails::UpdateLODCategoryVisibility)); } if (LODInfoProperty->IsValidHandle()) @@ -1260,6 +1282,7 @@ void FPersonaMeshDetails::AddLODLevelCategories(IDetailLayoutBuilder& DetailLayo .OnReimportNewFileClicked(this, &FPersonaMeshDetails::OnReimportLodClicked, &DetailLayout, EReimportButtonType::ReimportWithNewFile, LODIndex) ]; } + LODCategory.SetCategoryVisibility( (CurrentLodIndex == 0 ? 0 : CurrentLodIndex - 1) == LODIndex); } } } @@ -2230,36 +2253,7 @@ TSharedRef FPersonaMeshDetails::OnGenerateCustomSectionWidgetsForSectio { extern ENGINE_API bool IsGPUSkinCacheAvailable(); - TSharedRef SectionWidget - = SNew(SVerticalBox) - - + SVerticalBox::Slot() - .Padding(0, 2, 0, 0) - [ - SNew(SCheckBox) - .IsChecked(this, &FPersonaMeshDetails::IsSectionShadowCastingEnabled, LODIndex, SectionIndex) - .OnCheckStateChanged(this, &FPersonaMeshDetails::OnSectionShadowCastingChanged, LODIndex, SectionIndex) - [ - SNew(STextBlock) - .Font(FEditorStyle::GetFontStyle("StaticMeshEditor.NormalFont")) - .Text(LOCTEXT("Cast Shadows", "Cast Shadows")) - ] - ] - - + SVerticalBox::Slot() - .Padding(0, 2, 0, 0) - [ - SNew(SCheckBox) - .IsEnabled(IsGPUSkinCacheAvailable()) - .IsChecked(this, &FPersonaMeshDetails::IsSectionRecomputeTangentEnabled, LODIndex, SectionIndex) - .OnCheckStateChanged(this, &FPersonaMeshDetails::OnSectionRecomputeTangentChanged, LODIndex, SectionIndex) - [ - SNew(STextBlock) - .Font(FEditorStyle::GetFontStyle("StaticMeshEditor.NormalFont")) - .Text(LOCTEXT("RecomputeTangent_Title", "Recompute Tangent")) - .ToolTipText(LOCTEXT("RecomputeTangent_Tooltip", "This feature only works if you enable (Support Skincache Shaders) in the Project Settings. Please note that skin cache is an experimental feature and only works if you have compute shaders.")) - ] - ]; + TSharedRef SectionWidget = SNew(SVerticalBox); #if WITH_APEX_CLOTHING @@ -2270,19 +2264,25 @@ TSharedRef FPersonaMeshDetails::OnGenerateCustomSectionWidgetsForSectio SectionWidget->AddSlot() .AutoHeight() .Padding(0, 2, 0, 0) + .HAlign(HAlign_Fill) [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .AutoWidth() .VAlign(VAlign_Center) + [ + SNew(SBox) + .HAlign(HAlign_Right) + .MinDesiredWidth(65.0f) [ SNew(STextBlock) + .Font(IDetailLayoutBuilder::GetDetailFont()) .Text(LOCTEXT("Clothing", "Clothing")) ] - + ] + SHorizontalBox::Slot() - .AutoWidth() - .Padding(2, 2, 0, 0) + .FillWidth(1.0f) + .Padding(5, 2, 0, 0) [ SAssignNew(ClothComboBoxes.Last(), SClothComboBox) .OnGenerateWidget(this, &FPersonaMeshDetails::OnGenerateWidgetForClothingEntry) @@ -2296,8 +2296,165 @@ TSharedRef FPersonaMeshDetails::OnGenerateCustomSectionWidgetsForSectio ]; #endif// #if WITH_APEX_CLOTHING + SectionWidget->AddSlot() + .AutoHeight() + .Padding(0, 2, 0, 0) + [ + SNew(SHorizontalBox) + +SHorizontalBox::Slot() + .AutoWidth() + .Padding(2, 0, 2, 0) + [ + SNew(SCheckBox) + .IsChecked(this, &FPersonaMeshDetails::IsSectionShadowCastingEnabled, LODIndex, SectionIndex) + .OnCheckStateChanged(this, &FPersonaMeshDetails::OnSectionShadowCastingChanged, LODIndex, SectionIndex) + [ + SNew(STextBlock) + .Font(IDetailLayoutBuilder::GetDetailFont()) + .Text(LOCTEXT("Cast Shadows", "Cast Shadows")) + ] + ] + +SHorizontalBox::Slot() + .AutoWidth() + .Padding(2, 0, 2, 0) + [ + SNew(SCheckBox) + .IsEnabled(IsGPUSkinCacheAvailable()) + .IsChecked(this, &FPersonaMeshDetails::IsSectionRecomputeTangentEnabled, LODIndex, SectionIndex) + .OnCheckStateChanged(this, &FPersonaMeshDetails::OnSectionRecomputeTangentChanged, LODIndex, SectionIndex) + [ + SNew(STextBlock) + .Font(IDetailLayoutBuilder::GetDetailFont()) + .Text(LOCTEXT("RecomputeTangent_Title", "Recompute Tangent")) + .ToolTipText(LOCTEXT("RecomputeTangent_Tooltip", "This feature only works if you enable (Support Skincache Shaders) in the Project Settings. Please note that skin cache is an experimental feature and only works if you have compute shaders.")) + ] + ] + ]; return SectionWidget; } + +void FPersonaMeshDetails::SetCurrentLOD(int32 NewLodIndex) +{ + if (GetPersonaToolkit()->GetPreviewMeshComponent() == nullptr) + { + return; + } + int32 CurrentDisplayLOD = GetPersonaToolkit()->GetPreviewMeshComponent()->ForcedLodModel; + int32 RealCurrentDisplayLOD = CurrentDisplayLOD == 0 ? 0 : CurrentDisplayLOD - 1; + int32 RealNewLOD = NewLodIndex == 0 ? 0 : NewLodIndex - 1; + if (CurrentDisplayLOD == NewLodIndex || !LodCategories.IsValidIndex(RealCurrentDisplayLOD) || !LodCategories.IsValidIndex(RealNewLOD)) + { + return; + } + LodCategories[RealCurrentDisplayLOD]->SetCategoryVisibility(false); + LodCategories[RealNewLOD]->SetCategoryVisibility(true); + GetPersonaToolkit()->GetPreviewMeshComponent()->SetForcedLOD(NewLodIndex); + + //Reset the preview section since we do not edit the same LOD + if (GetPersonaToolkit()->GetMesh() != nullptr) + { + GetPersonaToolkit()->GetPreviewMeshComponent()->SetSectionPreview(INDEX_NONE); + GetPersonaToolkit()->GetMesh()->SelectedEditorSection = INDEX_NONE; + } + + GetPersonaToolkit()->GetPreviewScene()->BroadcastOnSelectedLODChanged(); +} + +void FPersonaMeshDetails::UpdateLODCategoryVisibility() const +{ + bool bAutoLod = false; + if (GetPersonaToolkit()->GetPreviewMeshComponent() != nullptr) + { + bAutoLod = GetPersonaToolkit()->GetPreviewMeshComponent()->ForcedLodModel == 0; + } + int32 CurrentDisplayLOD = bAutoLod ? 0 : GetPersonaToolkit()->GetPreviewMeshComponent()->ForcedLodModel - 1; + if (LodCategories.IsValidIndex(CurrentDisplayLOD) && GetPersonaToolkit()->GetMesh()) + { + int32 SkeletalMeshLodNumber = GetPersonaToolkit()->GetMesh()->LODInfo.Num(); + for (int32 LodCategoryIndex = 0; LodCategoryIndex < SkeletalMeshLodNumber; ++LodCategoryIndex) + { + LodCategories[LodCategoryIndex]->SetCategoryVisibility(CurrentDisplayLOD == LodCategoryIndex); + } + } + + //Reset the preview section since we do not edit the same LOD + if (GetPersonaToolkit()->GetMesh() != nullptr) + { + GetPersonaToolkit()->GetPreviewMeshComponent()->SetSectionPreview(INDEX_NONE); + GetPersonaToolkit()->GetMesh()->SelectedEditorSection = INDEX_NONE; + } +} + +FText FPersonaMeshDetails::GetCurrentLodName() const +{ + bool bAutoLod = false; + if (GetPersonaToolkit()->GetPreviewMeshComponent() != nullptr) + { + bAutoLod = GetPersonaToolkit()->GetPreviewMeshComponent()->ForcedLodModel == 0; + } + int32 CurrentDisplayLOD = bAutoLod ? 0 : GetPersonaToolkit()->GetPreviewMeshComponent()->ForcedLodModel - 1; + return FText::FromString(bAutoLod ? FString(TEXT("Auto (LOD0)")) : (FString(TEXT("LOD")) + FString::FromInt(CurrentDisplayLOD))); +} + +FText FPersonaMeshDetails::GetCurrentLodTooltip() const +{ + if (GetPersonaToolkit()->GetPreviewMeshComponent() != nullptr && GetPersonaToolkit()->GetPreviewMeshComponent()->ForcedLodModel == 0) + { + return FText::FromString(TEXT("LOD0 is edit when selecting Auto LOD")); + } + return FText::GetEmpty(); +} + +TSharedRef FPersonaMeshDetails::OnGenerateLodComboBoxForSectionList(int32 LodIndex) +{ + return SNew(SComboButton) + .OnGetMenuContent(this, &FPersonaMeshDetails::OnGenerateLodMenuForSectionList, LodIndex) + .VAlign(VAlign_Center) + .ContentPadding(2) + .ButtonContent() + [ + SNew(STextBlock) + .Font(IDetailLayoutBuilder::GetDetailFont()) + .Text(this, &FPersonaMeshDetails::GetCurrentLodName) + .ToolTipText(this, &FPersonaMeshDetails::GetCurrentLodTooltip) + ]; +} + +TSharedRef FPersonaMeshDetails::OnGenerateLodMenuForSectionList(int32 LodIndex) +{ + USkeletalMesh* SkelMesh = GetPersonaToolkit()->GetMesh(); + + if (SkelMesh == nullptr) + { + return SNullWidget::NullWidget; + } + + bool bAutoLod = false; + if (GetPersonaToolkit()->GetPreviewMeshComponent() != nullptr) + { + bAutoLod = GetPersonaToolkit()->GetPreviewMeshComponent()->ForcedLodModel == 0; + } + const int32 SkelMeshLODCount = SkelMesh->LODInfo.Num(); + if(SkelMeshLODCount < 2) + { + return SNullWidget::NullWidget; + } + FMenuBuilder MenuBuilder(true, NULL); + + FText AutoLodText = FText::FromString((TEXT("Auto LOD"))); + FUIAction AutoLodAction(FExecuteAction::CreateSP(this, &FPersonaMeshDetails::SetCurrentLOD, 0)); + MenuBuilder.AddMenuEntry(AutoLodText, LOCTEXT("OnGenerateLodMenuForSectionList_Auto_ToolTip", "LOD0 is edit when selecting Auto LOD"), FSlateIcon(), AutoLodAction); + // Add a menu item for each texture. Clicking on the texture will display it in the content browser + for (int32 AllLodIndex = 0; AllLodIndex < SkelMeshLODCount; ++AllLodIndex) + { + FText LODLevelString = FText::FromString((TEXT("LOD ") + FString::FromInt(AllLodIndex))); + FUIAction Action(FExecuteAction::CreateSP(this, &FPersonaMeshDetails::SetCurrentLOD, AllLodIndex+1)); + MenuBuilder.AddMenuEntry(LODLevelString, FText::GetEmpty(), FSlateIcon(), Action); + } + + return MenuBuilder.MakeWidget(); +} + ECheckBoxState FPersonaMeshDetails::IsMaterialSelected(int32 MaterialIndex) const { ECheckBoxState State = ECheckBoxState::Unchecked; @@ -3086,7 +3243,7 @@ void FPersonaMeshDetails::OnGenerateElementForClothingAsset( TSharedRef InNewEntry, ESelectInfo::Type InSelectType, int32 BoxIndex, int32 InLodIdx, int32 InSectionIdx) { - USkeletalMesh* Mesh = SkeletalMeshPtr.Get(); - - if(UClothingAsset* ClothingAsset = Cast(InNewEntry->Asset.Get())) + if(InNewEntry.IsValid()) { - // Look for a currently bound asset an unbind it if necessary first - if(UClothingAssetBase* CurrentAsset = Mesh->GetSectionClothingAsset(InLodIdx, InSectionIdx)) - { - CurrentAsset->UnbindFromSkeletalMesh(Mesh, InLodIdx); - } + USkeletalMesh* Mesh = SkeletalMeshPtr.Get(); - if(!ClothingAsset->BindToSkeletalMesh(Mesh, InLodIdx, InSectionIdx, InNewEntry->AssetLodIndex)) + if(UClothingAsset* ClothingAsset = Cast(InNewEntry->Asset.Get())) { - // We failed to bind the clothing asset, reset box selection to "None" - SClothComboBoxPtr BoxPtr = ClothComboBoxes[BoxIndex]; - if(BoxPtr.IsValid()) + // Look for a currently bound asset an unbind it if necessary first + if(UClothingAssetBase* CurrentAsset = Mesh->GetSectionClothingAsset(InLodIdx, InSectionIdx)) { - BoxPtr->SetSelectedItem(ClothingNoneEntry); + CurrentAsset->UnbindFromSkeletalMesh(Mesh, InLodIdx); + } + + if(!ClothingAsset->BindToSkeletalMesh(Mesh, InLodIdx, InSectionIdx, InNewEntry->AssetLodIndex)) + { + // We failed to bind the clothing asset, reset box selection to "None" + SClothComboBoxPtr BoxPtr = ClothComboBoxes[BoxIndex]; + if(BoxPtr.IsValid()) + { + BoxPtr->SetSelectedItem(ClothingNoneEntry); + } } } - } - else if(Mesh) - { - if(UClothingAssetBase* CurrentAsset = Mesh->GetSectionClothingAsset(InLodIdx, InSectionIdx)) + else if(Mesh) { - CurrentAsset->UnbindFromSkeletalMesh(Mesh, InLodIdx); + if(UClothingAssetBase* CurrentAsset = Mesh->GetSectionClothingAsset(InLodIdx, InSectionIdx)) + { + CurrentAsset->UnbindFromSkeletalMesh(Mesh, InLodIdx); + } } } } @@ -3458,8 +3618,23 @@ bool FPersonaMeshDetails::IsClothingPanelEnabled() const return !GEditor->bIsSimulatingInEditor && !GEditor->PlayWorld; } -void FPersonaMeshDetails::OnFinishedChangingClothingProperties(const FPropertyChangedEvent& Event) +void FPersonaMeshDetails::OnFinishedChangingClothingProperties(const FPropertyChangedEvent& Event, int32 InAssetIndex) { + if(Event.ChangeType != EPropertyChangeType::Interactive) + { + if(Event.Property->GetFName() == GET_MEMBER_NAME_CHECKED(FClothConfig, SelfCollisionRadius) || + Event.Property->GetFName() == GET_MEMBER_NAME_CHECKED(FClothConfig, SelfCollisionCullScale)) + { + USkeletalMesh* CurrentMesh = GetPersonaToolkit()->GetMesh(); + if(CurrentMesh->MeshClothingAssets.IsValidIndex(InAssetIndex)) + { + UClothingAsset* Asset = CastChecked(CurrentMesh->MeshClothingAssets[InAssetIndex]); + + Asset->BuildSelfCollisionData(); + } + } + } + if(UDebugSkelMeshComponent* PreviewComponent = GetPersonaToolkit()->GetPreviewMeshComponent()) { // Reregister our preview component to apply the change diff --git a/Engine/Source/Editor/Persona/Private/PersonaMeshDetails.h b/Engine/Source/Editor/Persona/Private/PersonaMeshDetails.h index 9e8b729eade2..e91fa695dced 100644 --- a/Engine/Source/Editor/Persona/Private/PersonaMeshDetails.h +++ b/Engine/Source/Editor/Persona/Private/PersonaMeshDetails.h @@ -211,6 +211,17 @@ private: */ TSharedRef OnGenerateCustomSectionWidgetsForSection(int32 LODIndex, int32 SectionIndex); + TSharedRef OnGenerateLodComboBoxForSectionList(int32 LodIndex); + /* + * Generate the context menu to choose the LOD we will display the section list + */ + TSharedRef OnGenerateLodMenuForSectionList(int32 LodIndex); + void UpdateLODCategoryVisibility() const; + FText GetCurrentLodName() const; + FText GetCurrentLodTooltip() const; + + void SetCurrentLOD(int32 NewLodIndex); + FText GetMaterialNameText(int32 MaterialIndex)const ; void OnMaterialNameCommitted(const FText& InValue, ETextCommit::Type CommitType, int32 MaterialIndex); void OnMaterialNameChanged(const FText& InValue, int32 MaterialIndex); @@ -481,6 +492,8 @@ private: /* This is to know if material are used by any LODs sections. */ TMap> MaterialUsedMap; + TArray LodCategories; + #if WITH_APEX_CLOTHING private: @@ -531,7 +544,7 @@ private: bool IsClothingPanelEnabled() const; // Callback after the clothing details are changed - void OnFinishedChangingClothingProperties(const FPropertyChangedEvent& Event); + void OnFinishedChangingClothingProperties(const FPropertyChangedEvent& Event, int32 InAssetIndex); /* Generate slate UI for Clothing category */ void CustomizeClothingProperties(class IDetailLayoutBuilder& DetailLayout, class IDetailCategoryBuilder& ClothingFilesCategory); diff --git a/Engine/Source/Editor/Persona/Private/PersonaModule.cpp b/Engine/Source/Editor/Persona/Private/PersonaModule.cpp index 503989152aff..81d72935f700 100644 --- a/Engine/Source/Editor/Persona/Private/PersonaModule.cpp +++ b/Engine/Source/Editor/Persona/Private/PersonaModule.cpp @@ -387,7 +387,7 @@ void FPersonaModule::ImportNewAsset(USkeleton* InSkeleton, EFBXImportType Defaul // now I have to set skeleton on it. FAssetToolsModule& AssetToolsModule = FModuleManager::GetModuleChecked("AssetTools"); - AssetToolsModule.Get().ImportAssets(AssetPath); + AssetToolsModule.Get().ImportAssetsWithDialog(AssetPath); } } diff --git a/Engine/Source/Editor/Persona/Private/PersonaPreviewSceneDescription.h b/Engine/Source/Editor/Persona/Private/PersonaPreviewSceneDescription.h index 3478d86868dc..02d4ed8cae03 100644 --- a/Engine/Source/Editor/Persona/Private/PersonaPreviewSceneDescription.h +++ b/Engine/Source/Editor/Persona/Private/PersonaPreviewSceneDescription.h @@ -11,6 +11,8 @@ class UAnimationAsset; class UPreviewMeshCollection; class USkeletalMesh; +class UDataAsset; +class UPreviewMeshCollection; UENUM() enum class EPreviewAnimationMode : uint8 @@ -44,7 +46,7 @@ public: TAssetPtr PreviewMesh; UPROPERTY(EditAnywhere, Category = "Additional Meshes") - TAssetPtr AdditionalMeshes; + TAssetPtr AdditionalMeshes; UPROPERTY() UPreviewMeshCollection* DefaultAdditionalMeshes; diff --git a/Engine/Source/Editor/Persona/Private/PreviewSceneCustomizations.cpp b/Engine/Source/Editor/Persona/Private/PreviewSceneCustomizations.cpp index 13b6ef9818d6..e1ce5ac65984 100644 --- a/Engine/Source/Editor/Persona/Private/PreviewSceneCustomizations.cpp +++ b/Engine/Source/Editor/Persona/Private/PreviewSceneCustomizations.cpp @@ -17,9 +17,15 @@ #include "AssetToolsModule.h" #include "IAssetTools.h" #include "Animation/AnimBlueprint.h" +#include "UObject/UObjectIterator.h" +#include "STextBlock.h" +#include "SCheckBox.h" #define LOCTEXT_NAMESPACE "PreviewSceneCustomizations" +// static list that contains available classes, so that we can only allow these classes +TArray FPreviewSceneDescriptionCustomization::AvailableClassNameList; + FPreviewSceneDescriptionCustomization::FPreviewSceneDescriptionCustomization(const FString& InSkeletonName, const TSharedRef& InPersonaToolkit) : SkeletonName(InSkeletonName) , PersonaToolkit(InPersonaToolkit) @@ -29,6 +35,18 @@ FPreviewSceneDescriptionCustomization::FPreviewSceneDescriptionCustomization(con // setup custom factory up-front so we can control its lifetime FactoryToUse = NewObject(); FactoryToUse->AddToRoot(); + + // only first time + if (AvailableClassNameList.Num() == 0) + { + for (TObjectIterator ClassIt; ClassIt; ++ClassIt) + { + if (ClassIt->IsChildOf(UDataAsset::StaticClass()) && ClassIt->ImplementsInterface(UPreviewCollectionInterface::StaticClass())) + { + AvailableClassNameList.Add(ClassIt->GetFName()); + } + } + } } FPreviewSceneDescriptionCustomization::~FPreviewSceneDescriptionCustomization() @@ -119,6 +137,23 @@ void FPreviewSceneDescriptionCustomization::CustomizeDetails(IDetailLayoutBuilde FAssetData AdditionalMeshesAsset; AdditionalMeshesProperty->GetValue(AdditionalMeshesAsset); + // bAllowPreviewMeshCollectionsToSelectFromDifferentSkeletons option + DetailBuilder.EditCategory("Additional Meshes") + .AddCustomRow(LOCTEXT("AdditvesMeshOption", "Additional Mesh Selection Option")) + .NameContent() + [ + SNew(STextBlock) + .Font(IDetailLayoutBuilder::GetDetailFont()) + .Text(LOCTEXT("AdditvesMeshSelectionFromDifferentSkeletons", "Allow Different Skeletons")) + .ToolTipText(LOCTEXT("AdditvesMeshSelectionFromDifferentSkeletons_ToolTip", "When selecting additional mesh, whether or not filter by the current skeleton.")) + ] + .ValueContent() + [ + SNew(SCheckBox) + .IsChecked(this, &FPreviewSceneDescriptionCustomization::HandleAllowDifferentSkeletonsIsChecked) + .OnCheckStateChanged(this, &FPreviewSceneDescriptionCustomization::HandleAllowDifferentSkeletonsCheckedStateChanged) + ]; + DetailBuilder.EditCategory("Additional Meshes") .AddProperty(AdditionalMeshesProperty) .CustomWidget() @@ -135,9 +170,11 @@ void FPreviewSceneDescriptionCustomization::CustomizeDetails(IDetailLayoutBuilde .FillWidth(1.0f) [ SNew(SObjectPropertyEntryBox) - .AllowedClass(UPreviewMeshCollection::StaticClass()) + // searching uobject is too much for a scale of Fortnite + // for now we just allow UDataAsset + .AllowedClass(UDataAsset::StaticClass()) .PropertyHandle(AdditionalMeshesProperty) - .OnShouldFilterAsset(this, &FPreviewSceneDescriptionCustomization::HandleShouldFilterAsset, true) + .OnShouldFilterAsset(this, &FPreviewSceneDescriptionCustomization::HandleShouldFilterAdditionalMesh, true) .OnObjectChanged(this, &FPreviewSceneDescriptionCustomization::HandleAdditionalMeshesChanged, &DetailBuilder) .ThumbnailPool(DetailBuilder.GetThumbnailPool()) .NewAssetFactories(FactoriesToUse) @@ -191,7 +228,7 @@ FReply FPreviewSceneDescriptionCustomization::OnSaveCollectionClicked(TSharedRef if (DefaultPreviewMeshCollection) { IAssetTools& AssetTools = FModuleManager::GetModuleChecked("AssetTools").Get(); - UPreviewMeshCollection* NewPreviewMeshCollection = Cast(AssetTools.CreateAsset(UPreviewMeshCollection::StaticClass(), FactoryToUse)); + UPreviewMeshCollection* NewPreviewMeshCollection = Cast(AssetTools.CreateAssetWithDialog(UPreviewMeshCollection::StaticClass(), FactoryToUse)); if (NewPreviewMeshCollection) { NewPreviewMeshCollection->Skeleton = DefaultPreviewMeshCollection->Skeleton; @@ -206,6 +243,30 @@ FReply FPreviewSceneDescriptionCustomization::OnSaveCollectionClicked(TSharedRef return FReply::Handled(); } +bool FPreviewSceneDescriptionCustomization::HandleShouldFilterAdditionalMesh(const FAssetData& InAssetData, bool bCanUseDifferentSkeleton) +{ + // see if it's in valid class set + bool bValidClass = false; + + // first to see if it's allowed class + for (FName& ClassName: AvailableClassNameList) + { + if (ClassName == InAssetData.AssetClass) + { + bValidClass = true; + break; + } + } + + // not valid class, filter it + if (!bValidClass) + { + return true; + } + + return HandleShouldFilterAsset(InAssetData, bCanUseDifferentSkeleton); +} + bool FPreviewSceneDescriptionCustomization::HandleShouldFilterAsset(const FAssetData& InAssetData, bool bCanUseDifferentSkeleton) { if (bCanUseDifferentSkeleton && GetDefault()->bAllowPreviewMeshCollectionsToSelectFromDifferentSkeletons) @@ -250,7 +311,7 @@ void FPreviewSceneDescriptionCustomization::HandleAnimationChanged(const FAssetD } } -void FPreviewSceneDescriptionCustomization::HandleMeshChanged(const FAssetData& InAssetData) +void FPreviewSceneDescriptionCustomization::HandleMeshChanged(const FAssetData& InAssetData) { USkeletalMesh* NewPreviewMesh = Cast(InAssetData.GetAsset()); PersonaToolkit.Pin()->SetPreviewMesh(NewPreviewMesh); @@ -258,10 +319,30 @@ void FPreviewSceneDescriptionCustomization::HandleMeshChanged(const FAssetData& void FPreviewSceneDescriptionCustomization::HandleAdditionalMeshesChanged(const FAssetData& InAssetData, IDetailLayoutBuilder* DetailLayoutBuilder) { - PreviewScene.Pin()->SetAdditionalMeshes(Cast(InAssetData.GetAsset())); + UDataAsset* MeshCollection = Cast(InAssetData.GetAsset()); + if (!MeshCollection || MeshCollection->GetClass()->ImplementsInterface(UPreviewCollectionInterface::StaticClass())) + { + PreviewScene.Pin()->SetAdditionalMeshes(MeshCollection); + } + DetailLayoutBuilder->ForceRefreshDetails(); } +void FPreviewSceneDescriptionCustomization::HandleAllowDifferentSkeletonsCheckedStateChanged(ECheckBoxState CheckState) +{ + GetMutableDefault()->bAllowPreviewMeshCollectionsToSelectFromDifferentSkeletons = (CheckState == ECheckBoxState::Checked); +} + +ECheckBoxState FPreviewSceneDescriptionCustomization::HandleAllowDifferentSkeletonsIsChecked() const +{ + return GetDefault()->bAllowPreviewMeshCollectionsToSelectFromDifferentSkeletons? ECheckBoxState::Checked : ECheckBoxState::Unchecked; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// FPreviewMeshCollectionEntryCustomization +// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void FPreviewMeshCollectionEntryCustomization::CustomizeHeader(TSharedRef PropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& CustomizationUtils) { // get the enclosing preview mesh collection to determine the skeleton we want diff --git a/Engine/Source/Editor/Persona/Private/PreviewSceneCustomizations.h b/Engine/Source/Editor/Persona/Private/PreviewSceneCustomizations.h index dec567dcaea7..b29963ae7073 100644 --- a/Engine/Source/Editor/Persona/Private/PreviewSceneCustomizations.h +++ b/Engine/Source/Editor/Persona/Private/PreviewSceneCustomizations.h @@ -34,6 +34,8 @@ private: bool HandleShouldFilterAsset(const FAssetData& InAssetData, bool bCanUseDifferentSkeleton); + bool HandleShouldFilterAdditionalMesh(const FAssetData& InAssetData, bool bCanUseDifferentSkeleton); + void HandleAnimationModeChanged(); void HandleAnimationChanged(const FAssetData& InAssetData); @@ -42,6 +44,10 @@ private: void HandleAdditionalMeshesChanged(const FAssetData& InAssetData, IDetailLayoutBuilder* DetailLayoutBuilder); + void HandleAllowDifferentSkeletonsCheckedStateChanged(ECheckBoxState CheckState); + + ECheckBoxState HandleAllowDifferentSkeletonsIsChecked() const; + private: /** Cached skeleton name to check for asset registry tags */ FString SkeletonName; @@ -57,6 +63,9 @@ private: /** Factory to use when creating mesh collections */ UPreviewMeshCollectionFactory* FactoryToUse; + + /** This is list of class available to filter asset by. This list doesn't change once loaded, so only collect once */ + static TArray AvailableClassNameList; }; class FPreviewMeshCollectionEntryCustomization : public IPropertyTypeCustomization diff --git a/Engine/Source/Editor/Persona/Private/SAnimCurveViewer.cpp b/Engine/Source/Editor/Persona/Private/SAnimCurveViewer.cpp index 3cb93bac3a05..4e23e542adac 100644 --- a/Engine/Source/Editor/Persona/Private/SAnimCurveViewer.cpp +++ b/Engine/Source/Editor/Persona/Private/SAnimCurveViewer.cpp @@ -538,8 +538,6 @@ void SAnimCurveViewer::Construct(const FArguments& InArgs, const TSharedRef AnimTypeBoxContainer = SNew(SHorizontalBox); @@ -635,11 +631,6 @@ SAnimCurveViewer::~SAnimCurveViewer() { if (PreviewScenePtr.IsValid() ) { - if (CachedPreviewInstance && OnAddAnimationCurveDelegate.IsBound()) - { - CachedPreviewInstance->RemoveDelegate_AddCustomAnimationCurve(OnAddAnimationCurveDelegate); - } - PreviewScenePtr.Pin()->UnregisterOnPreviewMeshChanged(this); PreviewScenePtr.Pin()->UnregisterOnAnimChanged(this); } @@ -705,24 +696,8 @@ void SAnimCurveViewer::BindCommands() FCanExecuteAction()); } -void SAnimCurveViewer::RefreshCachePreviewInstance() -{ - if (CachedPreviewInstance && OnAddAnimationCurveDelegate.IsBound()) - { - CachedPreviewInstance->RemoveDelegate_AddCustomAnimationCurve(OnAddAnimationCurveDelegate); - } - CachedPreviewInstance = Cast(PreviewScenePtr.Pin()->GetPreviewMeshComponent()->GetAnimInstance()); - - if (CachedPreviewInstance) - { - OnAddAnimationCurveDelegate.BindRaw(this, &SAnimCurveViewer::ApplyCustomCurveOverride); - CachedPreviewInstance->AddDelegate_AddCustomAnimationCurve(OnAddAnimationCurveDelegate); - } -} - void SAnimCurveViewer::OnPreviewMeshChanged(class USkeletalMesh* OldPreviewMesh, class USkeletalMesh* NewPreviewMesh) { - RefreshCachePreviewInstance(); RefreshCurveList(); } @@ -838,6 +813,11 @@ const FSmartNameMapping* SAnimCurveViewer::GetAnimCurveMapping() return EditableSkeletonPtr.Pin()->GetSkeleton().GetSmartNameContainer(ContainerName); } +UAnimInstance* SAnimCurveViewer::GetAnimInstance() const +{ + return PreviewScenePtr.Pin()->GetPreviewMeshComponent()->GetAnimInstance(); +} + int32 FindIndexOfAnimCurveInfo(TArray>& AnimCurveInfos, const FName& CurveName) { for (int32 CurveIdx = 0; CurveIdx < AnimCurveInfos.Num(); CurveIdx++) @@ -999,7 +979,7 @@ void SAnimCurveViewer::AddAnimCurveOverride( FName& Name, float Weight) float& Value = OverrideCurves.FindOrAdd(Name); Value = Weight; - UAnimSingleNodeInstance* SingleNodeInstance = Cast(CachedPreviewInstance); + UAnimSingleNodeInstance* SingleNodeInstance = Cast(GetAnimInstance()); if (SingleNodeInstance) { SingleNodeInstance->SetPreviewCurveOverride(Name, Value, false); @@ -1010,7 +990,7 @@ void SAnimCurveViewer::RemoveAnimCurveOverride(FName& Name) { OverrideCurves.Remove(Name); - UAnimSingleNodeInstance* SingleNodeInstance = Cast(CachedPreviewInstance); + UAnimSingleNodeInstance* SingleNodeInstance = Cast(GetAnimInstance()); if (SingleNodeInstance) { SingleNodeInstance->SetPreviewCurveOverride(Name, 0.f, true); diff --git a/Engine/Source/Editor/Persona/Private/SAnimCurveViewer.h b/Engine/Source/Editor/Persona/Private/SAnimCurveViewer.h index f6c8bb8290d6..394541c962c7 100644 --- a/Engine/Source/Editor/Persona/Private/SAnimCurveViewer.h +++ b/Engine/Source/Editor/Persona/Private/SAnimCurveViewer.h @@ -265,7 +265,6 @@ private: void CreateAnimCurveTypeList(TSharedRef HorizontalBox); void ApplyCustomCurveOverride(UAnimInstance* AnimInstance) const; - void RefreshCachePreviewInstance(); void OnDeleteNameClicked(); bool CanDelete(); @@ -290,6 +289,9 @@ private: /** Get the SmartNameMapping for anim curves */ const struct FSmartNameMapping* GetAnimCurveMapping(); + /** Get the anim instance we are viewing */ + UAnimInstance* GetAnimInstance() const; + /** Pointer to the preview scene we are bound to */ TWeakPtr PreviewScenePtr; @@ -323,9 +325,6 @@ private: /** Commands that are bound to delegates*/ TSharedPtr UICommandList; - /** Curve delegate */ - FOnAddCustomAnimationCurves OnAddAnimationCurveDelegate; - friend class SAnimCurveListRow; friend class SAnimCurveTypeList; diff --git a/Engine/Source/Editor/Persona/Private/SAnimMontagePanel.cpp b/Engine/Source/Editor/Persona/Private/SAnimMontagePanel.cpp index 0d38b1f233f0..a8f8bdfc3e51 100644 --- a/Engine/Source/Editor/Persona/Private/SAnimMontagePanel.cpp +++ b/Engine/Source/Editor/Persona/Private/SAnimMontagePanel.cpp @@ -357,6 +357,29 @@ void SAnimMontagePanel::SummonTrackContextMenu( FMenuBuilder& MenuBuilder, float { UIAction.ExecuteAction.BindRaw(MontageEditor.Pin().Get(), &SMontageEditor::RemoveSection, SectionIndex); MenuBuilder.AddMenuEntry(LOCTEXT("DeleteMontageSection", "Delete Montage Section"), LOCTEXT("DeleteMontageSectionToolTip", "Deletes Montage Section"), FSlateIcon(), UIAction); + + FCompositeSection& Section = Montage->CompositeSections[SectionIndex]; + + FNumberFormattingOptions Options; + Options.MinimumFractionalDigits = 5; + + // Add item to directly set section time + const FText CurrentTime = FText::AsNumber(Section.GetTime(), &Options); + const FText TimeMenuText = FText::Format(LOCTEXT("SectionTimeMenuText", "Set Section Time: {0}..."), CurrentTime); + + UIAction.ExecuteAction.BindRaw(this, &SAnimMontagePanel::OnSetSectionTimeClicked, SectionIndex); + UIAction.CanExecuteAction.Unbind(); + + MenuBuilder.AddMenuEntry(TimeMenuText, LOCTEXT("SetSectionTimeToolTip", "Set the time of this section directly"), FSlateIcon(), UIAction); + + // Add item to directly set section frame + const FText Frame = FText::AsNumber(Montage->GetFrameAtTime(Section.GetTime())); + const FText FrameMenuText = FText::Format(LOCTEXT("SectionFrameMenuText", "Set Section Frame: {0}..."), Frame); + + UIAction.ExecuteAction.BindRaw(this, &SAnimMontagePanel::OnSetSectionFrameClicked, SectionIndex); + UIAction.CanExecuteAction.Unbind(); + + MenuBuilder.AddMenuEntry(FrameMenuText, LOCTEXT("SetFrameToolTip", "Set the frame of this section directly"), FSlateIcon(), UIAction); } } MenuBuilder.EndSection(); @@ -458,6 +481,93 @@ void SAnimMontagePanel::CreateNewSection(const FText& NewSectionName, ETextCommi FSlateApplication::Get().DismissAllMenus(); } +void SAnimMontagePanel::OnSetSectionTimeClicked(int32 SectionIndex) +{ + if (Montage->CompositeSections.IsValidIndex(SectionIndex)) + { + FCompositeSection& Section = Montage->CompositeSections[SectionIndex]; + + FString DefaultText = FString::Printf(TEXT("%0.6f"), Section.GetTime()); + + // Show dialog to enter time + TSharedRef TextEntry = + SNew(STextEntryPopup) + .Label(LOCTEXT("SectionTimeClickedLabel", "Section Time")) + .DefaultText(FText::FromString(DefaultText)) + .OnTextCommitted(this, &SAnimMontagePanel::SetSectionTime, SectionIndex); + + FSlateApplication::Get().PushMenu( + AsShared(), + FWidgetPath(), + TextEntry, + FSlateApplication::Get().GetCursorPos(), + FPopupTransitionEffect(FPopupTransitionEffect::TypeInPopup) + ); + } +} + +void SAnimMontagePanel::SetSectionTime(const FText& SectionTimeText, ETextCommit::Type CommitInfo, int32 SectionIndex) +{ + if (CommitInfo == ETextCommit::OnEnter || CommitInfo == ETextCommit::OnUserMovedFocus) + { + if (Montage->CompositeSections.IsValidIndex(SectionIndex)) + { + FCompositeSection& Section = Montage->CompositeSections[SectionIndex]; + + float NewTime = FMath::Clamp(FCString::Atof(*SectionTimeText.ToString()), 0.0f, Montage->SequenceLength); + + MontageEditor.Pin()->SetSectionTime(SectionIndex, NewTime); + } + } + + FSlateApplication::Get().DismissAllMenus(); +} + +void SAnimMontagePanel::OnSetSectionFrameClicked(int32 SectionIndex) +{ + if (Montage->CompositeSections.IsValidIndex(SectionIndex)) + { + FCompositeSection& Section = Montage->CompositeSections[SectionIndex]; + + const FText Frame = FText::AsNumber(Montage->GetFrameAtTime(Section.GetTime())); + + FString DefaultText = FString::Printf(TEXT("%s"), *Frame.ToString()); + + // Show dialog to enter frame + TSharedRef TextEntry = + SNew(STextEntryPopup) + .Label(LOCTEXT("SectionFrameClickedLabel", "Section Frame")) + .DefaultText(FText::FromString(DefaultText)) + .OnTextCommitted(this, &SAnimMontagePanel::SetSectionFrame, SectionIndex); + + FSlateApplication::Get().PushMenu( + AsShared(), + FWidgetPath(), + TextEntry, + FSlateApplication::Get().GetCursorPos(), + FPopupTransitionEffect(FPopupTransitionEffect::TypeInPopup) + ); + } +} + +void SAnimMontagePanel::SetSectionFrame(const FText& SectionFrameText, ETextCommit::Type CommitInfo, int32 SectionIndex) +{ + if (CommitInfo == ETextCommit::OnEnter || CommitInfo == ETextCommit::OnUserMovedFocus) + { + if (Montage->CompositeSections.IsValidIndex(SectionIndex)) + { + FCompositeSection& Section = Montage->CompositeSections[SectionIndex]; + + int32 Frame = FCString::Atof(*SectionFrameText.ToString()); + float NewTime = FMath::Clamp(Montage->GetTimeAtFrame(Frame), 0.0f, Montage->SequenceLength); + + MontageEditor.Pin()->SetSectionTime(SectionIndex, NewTime); + } + } + + FSlateApplication::Get().DismissAllMenus(); +} + void SAnimMontagePanel::ShowSegmentInDetailsView(int32 AnimSegmentIndex, int32 AnimSlotIndex) { UEditorAnimSegment *Obj = Cast(MontageEditor.Pin()->ShowInDetailsView(UEditorAnimSegment::StaticClass())); diff --git a/Engine/Source/Editor/Persona/Private/SAnimMontagePanel.h b/Engine/Source/Editor/Persona/Private/SAnimMontagePanel.h index 85ca5c3b9df5..9b097b05190f 100644 --- a/Engine/Source/Editor/Persona/Private/SAnimMontagePanel.h +++ b/Engine/Source/Editor/Persona/Private/SAnimMontagePanel.h @@ -86,6 +86,13 @@ public: void OnNewSectionClicked(float DataPosX); bool CanAddNewSection(); + /** Functions for section time change via context menu*/ + void OnSetSectionTimeClicked(int32 SectionIndex); + void SetSectionTime(const FText& SectionTimeText, ETextCommit::Type CommitInfo, int32 SectionIndex); + /** Functions for section frame change via context menu*/ + void OnSetSectionFrameClicked(int32 SectionIndex); + void SetSectionFrame(const FText& SectionFrameText, ETextCommit::Type CommitInfo, int32 SectionIndex); + void ShowSegmentInDetailsView(int32 AnimSegmentIndex, int32 AnimSlotIndex); void ShowSectionInDetailsView(int32 SectionIndex); diff --git a/Engine/Source/Editor/Persona/Private/SAnimNotifyPanel.cpp b/Engine/Source/Editor/Persona/Private/SAnimNotifyPanel.cpp index bfb0e7c99128..7dada4a86f72 100644 --- a/Engine/Source/Editor/Persona/Private/SAnimNotifyPanel.cpp +++ b/Engine/Source/Editor/Persona/Private/SAnimNotifyPanel.cpp @@ -33,6 +33,7 @@ #include "Animation/AnimNotifies/AnimNotify.h" #include "Animation/BlendSpaceBase.h" #include "TabSpawners.h" +#include "SInlineEditableTextBlock.h" // Track Panel drawing const float NotificationTrackHeight = 20.0f; @@ -942,6 +943,10 @@ private: /** Pointer to notify panel for drawing*/ TWeakPtr AnimPanelPtr; + + /** Pointer to the track name UI */ + TSharedPtr TrackText; + public: SLATE_BEGIN_ARGS( SNotifyEdTrack ) : _TrackIndex(INDEX_NONE) @@ -990,6 +995,24 @@ public: /** Pointer to actual anim notify track */ TSharedPtr NotifyTrack; + + /** Return the tracks name as an FText */ + FText GetTrackName() const + { + if(Sequence->AnimNotifyTracks.IsValidIndex(TrackIndex)) + { + return FText::FromName(Sequence->AnimNotifyTracks[TrackIndex].TrackName); + } + + /** Should never be possible but better than crashing the editor */ + return LOCTEXT("TrackName_Invalid", "Invalid Track"); + } + + /** Activate the editable text box for the track name */ + void TriggerRename() + { + TrackText->EnterEditingMode(); + } }; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1584,7 +1607,7 @@ void SAnimNotifyNode::UpdateSizeAndPosition(const FGeometry& AllottedGeometry) if(EndMarkerNodeOverlay.IsValid()) { - FVector2D OverlaySize = EndMarkerNodeOverlay->ComputeDesiredSize(1.0f); + FVector2D OverlaySize = EndMarkerNodeOverlay->GetDesiredSize(); WidgetSize.X += OverlaySize.X; } @@ -1625,7 +1648,7 @@ int32 SAnimNotifyNode::OnPaint(const FPaintArgs& Args, const FGeometry& Allotted // Paint marker node if we have one if(EndMarkerNodeOverlay.IsValid()) { - FVector2D MarkerSize = EndMarkerNodeOverlay->ComputeDesiredSize(1.0f); + FVector2D MarkerSize = EndMarkerNodeOverlay->GetDesiredSize(); FVector2D MarkerOffset(NotifyDurationSizeX + MarkerSize.X * 0.5f + 5.0f, (NotifyHeight - MarkerSize.Y) * 0.5f); EndMarkerNodeOverlay->Paint(Args.WithNewParent(this), AllottedGeometry.MakeChild(MarkerOffset, MarkerSize, 1.0f), MyClippingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled); } @@ -3920,9 +3943,10 @@ void SNotifyEdTrack::Construct(const FArguments& InArgs) .FillWidth(1) [ // Name of track - SNew(STextBlock) - .Text( FText::FromName( Track.TrackName ) ) + SAssignNew(TrackText, SInlineEditableTextBlock) + .Text(this, &SNotifyEdTrack::GetTrackName) .ColorAndOpacity(Track.TrackColor) + .OnTextCommitted(PanelRef, &SAnimNotifyPanel::OnCommitTrackName, TrackIndex) ] +SHorizontalBox::Slot() @@ -4065,6 +4089,27 @@ SAnimNotifyPanel::~SAnimNotifyPanel() FCoreUObjectDelegates::OnObjectPropertyChanged.Remove(OnPropertyChangedHandleDelegateHandle); } +FName SAnimNotifyPanel::GetNewTrackName() const +{ + TArray TrackNames; + TrackNames.Reserve(50); + + for (const FAnimNotifyTrack& Track : Sequence->AnimNotifyTracks) + { + TrackNames.Add(Track.TrackName); + } + + FName NameToTest; + int32 TrackIndex = 1; + + do + { + NameToTest = *FString::FromInt(TrackIndex++); + } while (TrackNames.Contains(NameToTest)); + + return NameToTest; +} + FReply SAnimNotifyPanel::InsertTrack(int32 TrackIndexToInsert) { // before insert, make sure everything behind is fixed @@ -4085,22 +4130,29 @@ FReply SAnimNotifyPanel::InsertTrack(int32 TrackIndexToInsert) // fix notifies indices SyncMarker->TrackIndex = NewTrackIndex; } - - // fix track names, for now it's only index - Track.TrackName = *FString::FromInt(I+2); } FAnimNotifyTrack NewItem; - NewItem.TrackName = *FString::FromInt(TrackIndexToInsert+1); + NewItem.TrackName = GetNewTrackName(); NewItem.TrackColor = FLinearColor::White; Sequence->AnimNotifyTracks.Insert(NewItem, TrackIndexToInsert); Sequence->MarkPackageDirty(); Update(); + + //Now we have updated we can request rename on the track UI + int32 UITrackIndex = NotifyEditorTracks.Num() - 1 - TrackIndexToInsert; + RegisterActiveTimer(0.f, FWidgetActiveTimerDelegate::CreateSP(this, &SAnimNotifyPanel::TriggerRename, UITrackIndex)); return FReply::Handled(); } +EActiveTimerReturnType SAnimNotifyPanel::TriggerRename(double InCurrentTime, float InDeltaTime, int32 TrackIndex) +{ + NotifyEditorTracks[TrackIndex]->TriggerRename(); + return EActiveTimerReturnType::Stop; +} + FReply SAnimNotifyPanel::DeleteTrack(int32 TrackIndexToDelete) { if (Sequence->AnimNotifyTracks.IsValidIndex(TrackIndexToDelete)) @@ -4124,9 +4176,6 @@ FReply SAnimNotifyPanel::DeleteTrack(int32 TrackIndexToDelete) // fix notifies indices SyncMarker->TrackIndex = NewTrackIndex; } - - // fix track names, for now it's only index - Track.TrackName = *FString::FromInt(I); } Sequence->AnimNotifyTracks.RemoveAt(TrackIndexToDelete); @@ -4147,6 +4196,18 @@ bool SAnimNotifyPanel::CanDeleteTrack(int32 TrackIndexToDelete) return false; } +void SAnimNotifyPanel::OnCommitTrackName(const FText& InText, ETextCommit::Type CommitInfo, int32 TrackIndexToName) +{ + if (Sequence->AnimNotifyTracks.IsValidIndex(TrackIndexToName)) + { + FScopedTransaction Transaction(FText::Format(LOCTEXT("RenameNotifyTrack", "Rename Notify Track to '{0}'"), InText)); + Sequence->Modify(); + + FText TrimText = FText::TrimPrecedingAndTrailing(InText); + Sequence->AnimNotifyTracks[TrackIndexToName].TrackName = FName(*TrimText.ToString()); + } +} + void SAnimNotifyPanel::Update() { if(Sequence != NULL) @@ -4167,6 +4228,7 @@ void SAnimNotifyPanel::RefreshNotifyTracks() ); NotifyAnimTracks.Empty(); + NotifyEditorTracks.Empty(); for(int32 I=Sequence->AnimNotifyTracks.Num()-1; I>=0; --I) { @@ -4205,6 +4267,7 @@ void SAnimNotifyPanel::RefreshNotifyTracks() ]; NotifyAnimTracks.Add(EdTrack->NotifyTrack); + NotifyEditorTracks.Add(EdTrack); } } diff --git a/Engine/Source/Editor/Persona/Private/SAnimNotifyPanel.h b/Engine/Source/Editor/Persona/Private/SAnimNotifyPanel.h index 77b95c593f76..0be349b7d3f9 100644 --- a/Engine/Source/Editor/Persona/Private/SAnimNotifyPanel.h +++ b/Engine/Source/Editor/Persona/Private/SAnimNotifyPanel.h @@ -39,6 +39,7 @@ DECLARE_DELEGATE_OneParam( FOnGetNativeNotifyClasses, TArray&) class SAnimNotifyNode; class SAnimNotifyTrack; +class SNotifyEdTrack; class FNotifyDragDropOp; namespace ENotifyPasteMode @@ -191,9 +192,19 @@ public: void SetSequence(class UAnimSequenceBase * InSequence); + // Generate a new track name (smallest integer number that isn't currently used) + FName GetNewTrackName() const; + FReply InsertTrack(int32 TrackIndexToInsert); FReply DeleteTrack(int32 TrackIndexToDelete); bool CanDeleteTrack(int32 TrackIndexToDelete); + + /** Widget timer function to trigger notify track rename (cannot do it directly from add track code) */ + EActiveTimerReturnType TriggerRename(double InCurrentTime, float InDeltaTime, int32 TrackIndex); + + // Handler function for renaming a notify track + void OnCommitTrackName(const FText& InText, ETextCommit::Type CommitInfo, int32 TrackIndexToName); + void Update(); /** Returns the position of the notify node currently being dragged. Returns -1 if no node is being dragged */ @@ -256,6 +267,9 @@ private: /** Cached list of anim tracks for notify node drag drop */ TArray> NotifyAnimTracks; + /** Cached list of Notify editor tracks */ + TArray> NotifyEditorTracks; + // this just refresh notify tracks - UI purpose only // do not call this from here. This gets called by asset. void RefreshNotifyTracks(); diff --git a/Engine/Source/Editor/Persona/Private/SAnimSegmentsPanel.cpp b/Engine/Source/Editor/Persona/Private/SAnimSegmentsPanel.cpp index 779ce0768135..9b6e640af96a 100644 --- a/Engine/Source/Editor/Persona/Private/SAnimSegmentsPanel.cpp +++ b/Engine/Source/Editor/Persona/Private/SAnimSegmentsPanel.cpp @@ -462,22 +462,25 @@ void SAnimSegmentsPanel::OnTrackDragDrop( TSharedPtr DragDro if (DragDropOp.IsValid() && DragDropOp->IsOfType()) { TSharedPtr AssetOp = StaticCastSharedPtr(DragDropOp); - UAnimSequenceBase* DroppedSequence = FAssetData::GetFirstAsset(AssetOp->AssetData); - if (IsValidToAdd(DroppedSequence)) + if (AssetOp->HasAssets()) { - if (bChildAnimMontage) + UAnimSequenceBase* DroppedSequence = FAssetData::GetFirstAsset(AssetOp->GetAssets()); + if (IsValidToAdd(DroppedSequence)) { - ReplaceAnimSegment(DroppedSequence, DataPos); + if (bChildAnimMontage) + { + ReplaceAnimSegment(DroppedSequence, DataPos); + } + else + { + AddAnimSegment(DroppedSequence, DataPos); + } } else { - AddAnimSegment(DroppedSequence, DataPos); + FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("FailedToAdd", "Make sure the target animation is valid. Check to make sure if it's same additive type if additive.")); } } - else - { - FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("FailedToAdd", "Make sure the target animation is valid. Check to make sure if it's same additive type if additive.")); - } } } diff --git a/Engine/Source/Editor/Persona/Private/SAnimationBlendSpaceGridWidget.cpp b/Engine/Source/Editor/Persona/Private/SAnimationBlendSpaceGridWidget.cpp index d5956c073c66..0bc202dc8822 100644 --- a/Engine/Source/Editor/Persona/Private/SAnimationBlendSpaceGridWidget.cpp +++ b/Engine/Source/Editor/Persona/Private/SAnimationBlendSpaceGridWidget.cpp @@ -484,25 +484,21 @@ FReply SBlendSpaceGridWidget::OnDrop(const FGeometry& MyGeometry, const FDragDro { if (DragState == EDragState::DragDrop) { - const FVector2D GridPosition = SnapToClosestGridPoint(LocalMousePosition); - const FVector SampleValue = GridPositionToSampleValue(GridPosition); - + const FVector SampleValue = SnapToClosestSamplePoint(LocalMousePosition); TSharedPtr DragDropOperation = DragDropEvent.GetOperationAs(); if (DragDropOperation.IsValid()) { - UAnimSequence* Animation = FAssetData::GetFirstAsset(DragDropOperation->AssetData); + UAnimSequence* Animation = FAssetData::GetFirstAsset(DragDropOperation->GetAssets()); OnSampleAdded.ExecuteIfBound(Animation, SampleValue); } } else if (DragState == EDragState::DragDropOverride) { - const FVector2D GridPosition = SnapToClosestGridPoint(LocalMousePosition); - const FVector SampleValue = GridPositionToSampleValue(GridPosition); - + const FVector SampleValue = SnapToClosestSamplePoint(LocalMousePosition); TSharedPtr DragDropOperation = DragDropEvent.GetOperationAs(); if (DragDropOperation.IsValid()) { - UAnimSequence* Animation = FAssetData::GetFirstAsset(DragDropOperation->AssetData); + UAnimSequence* Animation = FAssetData::GetFirstAsset(DragDropOperation->GetAssets()); OnSampleAnimationChanged.ExecuteIfBound(Animation, SampleValue); } } @@ -819,27 +815,43 @@ FReply SBlendSpaceGridWidget::ToggleTriangulationVisibility() void SBlendSpaceGridWidget::CalculateGridPoints() { CachedGridPoints.Empty(SampleGridDivisions.X * SampleGridDivisions.Y); - for (int32 GridY = 0; GridY < ((GridType== EGridType::TwoAxis) ? SampleGridDivisions.Y + 1: 1); ++GridY) + CachedSamplePoints.Empty(SampleGridDivisions.X * SampleGridDivisions.Y); + for (int32 GridY = 0; GridY < ((GridType == EGridType::TwoAxis) ? SampleGridDivisions.Y + 1 : 1); ++GridY) { for (int32 GridX = 0; GridX < SampleGridDivisions.X + 1; ++GridX) { // Calculate grid point in 0-1 form - FVector2D GridPoint = FVector2D(GridX * (1.0f / SampleGridDivisions.X), (GridType == EGridType::TwoAxis) ? GridY * (1.0f / + FVector2D GridPoint = FVector2D(GridX * (1.0f / SampleGridDivisions.X), (GridType == EGridType::TwoAxis) ? GridY * (1.0f / SampleGridDivisions.Y) : 0.5f); // Multiply with size and offset according to the grid layout GridPoint *= CachedGridRectangle.GetSize(); GridPoint += CachedGridRectangle.GetTopLeft(); CachedGridPoints.Add(GridPoint); + + CachedSamplePoints.Add(FVector(SampleValueMin.X + (GridX * (SampleValueRange.X / SampleGridDivisions.X)), + (GridType == EGridType::TwoAxis) ? SampleValueMax.Y - (GridY * (SampleValueRange.Y / SampleGridDivisions.Y)) : 0.0f, 0.0f)); } } } const FVector2D SBlendSpaceGridWidget::SnapToClosestGridPoint(const FVector2D& InPosition) const +{ + const int32 GridPointIndex = FindClosestGridPointIndex(InPosition); + return CachedGridPoints[GridPointIndex]; +} + +const FVector SBlendSpaceGridWidget::SnapToClosestSamplePoint(const FVector2D& InPosition) const +{ + const int32 GridPointIndex = FindClosestGridPointIndex(InPosition); + return CachedSamplePoints[GridPointIndex]; +} + +int32 SBlendSpaceGridWidget::FindClosestGridPointIndex(const FVector2D& InPosition) const { // Clamp the screen position to the grid - const FVector2D GridPosition( FMath::Clamp(InPosition.X, CachedGridRectangle.Left, CachedGridRectangle.Right), - FMath::Clamp(InPosition.Y, CachedGridRectangle.Top, CachedGridRectangle.Bottom)); + const FVector2D GridPosition(FMath::Clamp(InPosition.X, CachedGridRectangle.Left, CachedGridRectangle.Right), + FMath::Clamp(InPosition.Y, CachedGridRectangle.Top, CachedGridRectangle.Bottom)); // Find the closest grid point float Distance = FLT_MAX; int32 GridPointIndex = INDEX_NONE; @@ -856,9 +868,8 @@ const FVector2D SBlendSpaceGridWidget::SnapToClosestGridPoint(const FVector2D& I checkf(GridPointIndex != INDEX_NONE, TEXT("Unable to find gridpoint")); - return CachedGridPoints[GridPointIndex]; + return GridPointIndex; } - const FVector2D SBlendSpaceGridWidget::SampleValueToGridPosition(const FVector& SampleValue) const { const FVector2D GridSize = CachedGridRectangle.GetSize(); @@ -1047,8 +1058,7 @@ FText SBlendSpaceGridWidget::GetToolTipSampleValue() const // If we are performing a drag and drop operation return the current sample value it is hovered at case EDragState::DragDrop: { - const FVector2D GridPoint = SnapToClosestGridPoint(LocalMousePosition); - const FVector SampleValue = GridPositionToSampleValue(GridPoint); + const FVector SampleValue = SnapToClosestSamplePoint(LocalMousePosition); ToolTipText = FText::Format(ValueFormattingText, ParameterXName, FText::FromString(FString::SanitizeFloat(SampleValue.X)), ParameterYName, FText::FromString(FString::SanitizeFloat(SampleValue.Y))); @@ -1385,8 +1395,7 @@ void SBlendSpaceGridWidget::Tick(const FGeometry& AllottedGeometry, const double { // If we are dragging a sample, find out whether or not it has actually moved to a different grid position since the last tick and update the blend space accordingly const FBlendSample& BlendSample = BlendSpace->GetBlendSample(DraggedSampleIndex); - const FVector2D GridPosition = SnapToClosestGridPoint(LocalMousePosition); - const FVector SampleValue = GridPositionToSampleValue(GridPosition); + const FVector SampleValue = SnapToClosestSamplePoint(LocalMousePosition); if (SampleValue != LastDragPosition) { @@ -1397,7 +1406,7 @@ void SBlendSpaceGridWidget::Tick(const FGeometry& AllottedGeometry, const double else if (DragState == EDragState::DragDrop || DragState == EDragState::InvalidDragDrop || DragState == EDragState::DragDropOverride) { // Validate that the sample is not overlapping with a current sample when doing a drag/drop operation and that we are dropping a valid animation for the blend space (type) - const FVector DropSampleValue = GridPositionToSampleValue(SnapToClosestGridPoint(LocalMousePosition)); + const FVector DropSampleValue = SnapToClosestSamplePoint(LocalMousePosition); const bool bValidPosition = BlendSpace->IsSampleWithinBounds(DropSampleValue); const bool bExistingSample = BlendSpace->IsTooCloseToExistingSamplePoint(DropSampleValue, INDEX_NONE); const bool bValidSequence = ValidateAnimationSequence(DragDropAnimationSequence, InvalidDragDropText); @@ -1493,7 +1502,7 @@ const bool SBlendSpaceGridWidget::IsValidDragDropOperation(const FDragDropEvent& if (DragDropOperation.IsValid()) { // Check whether or not this animation is compatible with the blend space - DragDropAnimationSequence = FAssetData::GetFirstAsset(DragDropOperation->AssetData); + DragDropAnimationSequence = FAssetData::GetFirstAsset(DragDropOperation->GetAssets()); if (DragDropAnimationSequence) { bResult = ValidateAnimationSequence(DragDropAnimationSequence, InvalidOperationText); diff --git a/Engine/Source/Editor/Persona/Private/SAnimationBlendSpaceGridWidget.h b/Engine/Source/Editor/Persona/Private/SAnimationBlendSpaceGridWidget.h index 5f1834b1bc42..1cd4862cc36c 100644 --- a/Engine/Source/Editor/Persona/Private/SAnimationBlendSpaceGridWidget.h +++ b/Engine/Source/Editor/Persona/Private/SAnimationBlendSpaceGridWidget.h @@ -145,6 +145,10 @@ protected: void CalculateGridPoints(); /** Snaps the given screen position to the closest grid point */ const FVector2D SnapToClosestGridPoint(const FVector2D& InPosition) const; + /** Snaps the given screen position to the sample value on the grid */ + const FVector SnapToClosestSamplePoint(const FVector2D& InPosition) const; + /** Returns the index of the closest grid point to the given mouse position */ + int32 FindClosestGridPointIndex(const FVector2D& InPosition) const; /** Converts the given sample value to a screen space position */ const FVector2D SampleValueToGridPosition(const FVector& SampleValue) const; /** Converst a screen space (grid) position to a valid sample value */ @@ -231,6 +235,7 @@ private: FText ParameterXName; FText ParameterYName; TArray CachedGridPoints; + TArray CachedSamplePoints; /** Whether or not the cached data should be refreshed on the next tick*/ bool bRefreshCachedData; diff --git a/Engine/Source/Editor/Persona/Private/SAnimationEditorViewport.cpp b/Engine/Source/Editor/Persona/Private/SAnimationEditorViewport.cpp index 31400c33c9df..d7b630db982a 100644 --- a/Engine/Source/Editor/Persona/Private/SAnimationEditorViewport.cpp +++ b/Engine/Source/Editor/Persona/Private/SAnimationEditorViewport.cpp @@ -308,7 +308,6 @@ void SAnimationEditorViewportTabBody::Construct(const FArguments& InArgs, const BlueprintEditorPtr = InArgs._BlueprintEditor; bShowTimeline = InArgs._ShowTimeline; OnInvokeTab = InArgs._OnInvokeTab; - LODSelection = 0; // register delegates for change notifications InPreviewScene->RegisterOnAnimChanged(FOnAnimChanged::CreateSP(this, &SAnimationEditorViewportTabBody::AnimChanged)); @@ -680,6 +679,7 @@ void SAnimationEditorViewportTabBody::BindCommands() #endif// #if WITH_APEX_CLOTHING + GetPreviewScene()->RegisterOnSelectedLODChanged(FOnSelectedLODChanged::CreateSP(this, &SAnimationEditorViewportTabBody::OnLODModelChanged)); //Bind LOD preview menu commands const FAnimViewportLODCommands& ViewportLODMenuCommands = FAnimViewportLODCommands::Get(); @@ -1325,19 +1325,48 @@ void SAnimationEditorViewportTabBody::UpdateShowFlagForMeshEdges() LevelViewportClient->EngineShowFlags.SetMeshEdges(bUseOverlayMaterial || bShowMeshEdgesViewMode); } +int32 SAnimationEditorViewportTabBody::GetLODSelection() const +{ + UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent(); + + if (PreviewComponent) + { + return PreviewComponent->ForcedLodModel; + } + return 0; +} + bool SAnimationEditorViewportTabBody::IsLODModelSelected(int32 LODSelectionType) const { - return (LODSelection == LODSelectionType) ? true : false; + UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent(); + + if (PreviewComponent) + { + return (PreviewComponent->ForcedLodModel == LODSelectionType) ? true : false; + } + return false; } void SAnimationEditorViewportTabBody::OnSetLODModel(int32 LODSelectionType) { - LODSelection = LODSelectionType; - UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent(); + if( PreviewComponent ) { - PreviewComponent->ForcedLodModel = LODSelection; + LODSelection = LODSelectionType; + PreviewComponent->ForcedLodModel = LODSelectionType; + PopulateUVChoices(); + GetPreviewScene()->BroadcastOnSelectedLODChanged(); + } +} + +void SAnimationEditorViewportTabBody::OnLODModelChanged() +{ + UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent(); + + if (PreviewComponent && LODSelection != PreviewComponent->ForcedLodModel) + { + LODSelection = PreviewComponent->ForcedLodModel; PopulateUVChoices(); } } diff --git a/Engine/Source/Editor/Persona/Private/SAnimationEditorViewport.h b/Engine/Source/Editor/Persona/Private/SAnimationEditorViewport.h index 25a490b61518..1ccbc171fc6f 100644 --- a/Engine/Source/Editor/Persona/Private/SAnimationEditorViewport.h +++ b/Engine/Source/Editor/Persona/Private/SAnimationEditorViewport.h @@ -121,7 +121,6 @@ public: /** SWidget interface */ virtual FReply OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) override; - void RefreshViewport(); /** @@ -137,7 +136,7 @@ public: /** LOD model selection checking function*/ bool IsLODModelSelected( int32 LODSelectionType ) const; - int32 GetLODSelection() const { return LODSelection; }; + int32 GetLODSelection() const; /** Function to set the current playback speed*/ void OnSetPlaybackSpeed(int32 PlaybackSpeedMode); @@ -198,6 +197,7 @@ public: /** Function to set LOD model selection*/ void OnSetLODModel(int32 LODSelectionType); + void OnLODModelChanged(); /** Get the skeleton tree we are bound to */ TSharedRef GetSkeletonTree() const { return SkeletonTreePtr.Pin().ToSharedRef(); } diff --git a/Engine/Source/Editor/Persona/Private/SAnimationScrubPanel.cpp b/Engine/Source/Editor/Persona/Private/SAnimationScrubPanel.cpp index 208ba06ba410..ccad3b3716bc 100644 --- a/Engine/Source/Editor/Persona/Private/SAnimationScrubPanel.cpp +++ b/Engine/Source/Editor/Persona/Private/SAnimationScrubPanel.cpp @@ -575,8 +575,8 @@ void SAnimationScrubPanel::OnReZeroAnimSequence(int32 FrameIndex) FVector ApplyTranslation = -1.f * FrameTransform; // Convert into world space - FVector WorldApplyTranslation = PreviewSkelComp->ComponentToWorld.TransformVector(ApplyTranslation); - ApplyTranslation = PreviewSkelComp->ComponentToWorld.InverseTransformVector(WorldApplyTranslation); + FVector WorldApplyTranslation = PreviewSkelComp->GetComponentTransform().TransformVector(ApplyTranslation); + ApplyTranslation = PreviewSkelComp->GetComponentTransform().InverseTransformVector(WorldApplyTranslation); for(int32 i=0; i InCategory, int32 InFolderIndex, FSimpleDelegate InOnActiveStateChanged) + : FFrontendFilter(InCategory) + , FolderIndex(InFolderIndex) + , OnActiveStateChanged(InOnActiveStateChanged) + {} + + // FFrontendFilter implementation + virtual FString GetName() const override + { + return FString::Printf(TEXT("ShowFolder%d"), FolderIndex); + } + + virtual FText GetDisplayName() const override + { + return Folder.IsEmpty() ? FText::Format(LOCTEXT("FolderFormatInvalid", "Show Specified Folder {0}"), FText::AsNumber(FolderIndex + 1)) : FText::Format(LOCTEXT("FolderFormatValid", "Folder: {0}"), FText::FromString(Folder)); + } + + virtual FText GetToolTipText() const override + { + return Folder.IsEmpty() ? LOCTEXT("FFrontendFilter_FolderToolTip", "Show assets in a specified folder") : FText::Format(LOCTEXT("FolderFormatValidToolTip", "Show assets in folder: {0}"), FText::FromString(Folder)); + } + + virtual FLinearColor GetColor() const override + { + return FLinearColor(0.6f, 0.6f, 0.0f, 1); + } + + virtual void ModifyContextMenu(FMenuBuilder& MenuBuilder) override + { + MenuBuilder.BeginSection(TEXT("FolderSection"), LOCTEXT("FolderSectionHeading", "Choose Folder")); + + FContentBrowserModule& ContentBrowserModule = FModuleManager::Get().LoadModuleChecked("ContentBrowser"); + FPathPickerConfig PathPickerConfig; + PathPickerConfig.DefaultPath = Folder; + PathPickerConfig.bAllowContextMenu = false; + PathPickerConfig.OnPathSelected = FOnPathSelected::CreateLambda([this](const FString& InPath) + { + Folder = InPath; + FSlateApplication::Get().DismissAllMenus(); + OnActiveStateChanged.ExecuteIfBound(); + }); + + TSharedRef FolderWidget = + SNew(SBox) + .HeightOverride(300.0f) + .WidthOverride(200.0f) + [ + ContentBrowserModule.Get().CreatePathPicker(PathPickerConfig) + ]; + + MenuBuilder.AddWidget(FolderWidget, FText(), true); + + MenuBuilder.EndSection(); + } + + virtual void SaveSettings(const FString& IniFilename, const FString& IniSection, const FString& SettingsString) const override + { + GConfig->SetString(*IniSection, *(SettingsString + TEXT(".Folder")), *Folder, IniFilename); + } + + virtual void LoadSettings(const FString& IniFilename, const FString& IniSection, const FString& SettingsString) override + { + GConfig->GetString(*IniSection, *(SettingsString + TEXT(".Folder")), Folder, IniFilename); + } + + virtual bool PassesFilter(FAssetFilterType InItem) const override + { + // Always pass this as a frontend filter, it acts as a backend filter + return true; + } + + virtual void ActiveStateChanged(bool bEnable) + { + bEnabled = bEnable; + OnActiveStateChanged.ExecuteIfBound(); + } + +public: + /** Folder string to use when filtering */ + FString Folder; + + /** The index of this filter, for uniquely identifying this filter */ + int32 FolderIndex; + + /** Delegate fired to refresh the filter */ + FSimpleDelegate OnActiveStateChanged; + + /** Whether this filter is currently enabled */ + bool bEnabled; +}; + //////////////////////////////////////////////////// const int32 SAnimationSequenceBrowser::MaxAssetsHistory = 10; @@ -485,10 +583,12 @@ void SAnimationSequenceBrowser::Construct(const FArguments& InArgs, const TShare CreateAssetTooltipResources(); // Configure filter for asset picker + Filter.bRecursiveClasses = true; + Filter.ClassNames.Add(UAnimationAsset::StaticClass()->GetFName()); + Filter.ClassNames.Add(USoundWave::StaticClass()->GetFName()); + FAssetPickerConfig Config; - Config.Filter.bRecursiveClasses = true; - Config.Filter.ClassNames.Add(UAnimationAsset::StaticClass()->GetFName()); - Config.Filter.ClassNames.Add(USoundWave::StaticClass()->GetFName()); + Config.Filter = Filter; Config.InitialAssetViewType = EAssetViewType::Column; Config.bAddFilterUI = true; Config.bShowPathInColumnView = true; @@ -501,6 +601,7 @@ void SAnimationSequenceBrowser::Construct(const FArguments& InArgs, const TShare Config.SyncToAssetsDelegates.Add(&SyncToAssetsDelegate); Config.OnShouldFilterAsset = FOnShouldFilterAsset::CreateSP(this, &SAnimationSequenceBrowser::HandleFilterAsset); Config.GetCurrentSelectionDelegates.Add(&GetCurrentSelectionDelegate); + Config.SetFilterDelegates.Add(&SetFilterDelegate); Config.bFocusSearchBoxWhenOpened = false; Config.DefaultFilterMenuExpansion = EAssetTypeCategories::Animation; @@ -510,7 +611,29 @@ void SAnimationSequenceBrowser::Construct(const FArguments& InArgs, const TShare Config.ExtraFrontendFilters.Add( MakeShareable(new FFrontendFilter_AdditiveAnimAssets(AnimCategory)) ); TSharedPtr AudioCategory = MakeShareable(new FFrontendFilterCategory(LOCTEXT("AudioFilters", "Audio Filters"), LOCTEXT("AudioFiltersTooltip", "Filter audio assets."))); Config.ExtraFrontendFilters.Add( MakeShareable(new FFrontendFilter_SoundWaves(AudioCategory)) ); - + TSharedPtr FolderCategory = MakeShareable(new FFrontendFilterCategory(LOCTEXT("FolderFilters", "Folder Filters"), LOCTEXT("FolderFiltersTooltip", "Filter by folders."))); + const uint32 NumFilters = GetDefault()->NumFolderFiltersInAssetBrowser; + for(uint32 FilterIndex = 0; FilterIndex < NumFilters; ++FilterIndex) + { + TSharedRef FolderFilter = MakeShared(FolderCategory, FilterIndex, + FSimpleDelegate::CreateLambda([this]() + { + Filter.PackagePaths.Empty(); + + for(TSharedPtr CurrentFolderFilter : FolderFilters) + { + if(CurrentFolderFilter->bEnabled) + { + Filter.PackagePaths.Add(*CurrentFolderFilter->Folder); + } + } + + SetFilterDelegate.ExecuteIfBound(Filter); + })); + FolderFilters.Add(FolderFilter); + Config.ExtraFrontendFilters.Add(FolderFilter); + } + Config.OnGetCustomAssetToolTip = FOnGetCustomAssetToolTip::CreateSP(this, &SAnimationSequenceBrowser::CreateCustomAssetToolTip); Config.OnVisualizeAssetToolTip = FOnVisualizeAssetToolTip::CreateSP(this, &SAnimationSequenceBrowser::OnVisualizeAssetToolTip); Config.OnAssetToolTipClosing = FOnAssetToolTipClosing::CreateSP( this, &SAnimationSequenceBrowser::OnAssetToolTipClosing ); diff --git a/Engine/Source/Editor/Persona/Private/SAnimationSequenceBrowser.h b/Engine/Source/Editor/Persona/Private/SAnimationSequenceBrowser.h index 41a147b5784a..c1b2269d3052 100644 --- a/Engine/Source/Editor/Persona/Private/SAnimationSequenceBrowser.h +++ b/Engine/Source/Editor/Persona/Private/SAnimationSequenceBrowser.h @@ -16,6 +16,7 @@ #include "Editor/ContentBrowser/Public/ContentBrowserDelegates.h" #include "EditorAnimUtils.h" #include "IAnimationSequenceBrowser.h" +#include "ARFilter.h" class FSceneViewport; class FUICommandList; @@ -25,6 +26,7 @@ class SViewport; class UAnimationAsset; class UDebugSkelMeshComponent; class USoundWave; +class FFrontendFilter_Folder; ////////////////////////////////////////////////////////////////////////// // FAnimationAssetViewportClient @@ -251,6 +253,15 @@ protected: FSyncToAssetsDelegate SyncToAssetsDelegate; FGetCurrentSelectionDelegate GetCurrentSelectionDelegate; + /** Delegate used to set the AR filter after the fact */ + FSetARFilterDelegate SetFilterDelegate; + + /** Keep the AR filter around so we can modify it */ + FARFilter Filter; + + /** All the folder filters we have */ + TArray> FolderFilters; + void RetargetAnimationHandler(USkeleton* OldSkeleton, USkeleton* NewSkeleton, bool bRemapReferencedAssets, bool bAllowRemapToExisting, bool bConvertSpaces, const EditorAnimUtils::FNameDuplicationRule* NameRule, TArray> InAnimAssets); private: diff --git a/Engine/Source/Editor/Persona/Private/SAssetFamilyShortcutBar.cpp b/Engine/Source/Editor/Persona/Private/SAssetFamilyShortcutBar.cpp index 4cc916c0a2b5..1b779768c24f 100644 --- a/Engine/Source/Editor/Persona/Private/SAssetFamilyShortcutBar.cpp +++ b/Engine/Source/Editor/Persona/Private/SAssetFamilyShortcutBar.cpp @@ -52,6 +52,7 @@ public: AssetRegistryModule.Get().OnFilesLoaded().AddSP(this, &SAssetShortcut::HandleFilesLoaded); AssetRegistryModule.Get().OnAssetAdded().AddSP(this, &SAssetShortcut::HandleAssetAdded); AssetRegistryModule.Get().OnAssetRemoved().AddSP(this, &SAssetShortcut::HandleAssetRemoved); + AssetRegistryModule.Get().OnAssetRenamed().AddSP(this, &SAssetShortcut::HandleAssetRenamed); FAssetEditorManager::Get().OnAssetEditorRequestedOpen().AddSP(this, &SAssetShortcut::HandleAssetOpened); AssetFamily->GetOnAssetOpened().AddSP(this, &SAssetShortcut::HandleAssetOpened); @@ -178,6 +179,7 @@ public: AssetRegistryModule.Get().OnFilesLoaded().RemoveAll(this); AssetRegistryModule.Get().OnAssetAdded().RemoveAll(this); AssetRegistryModule.Get().OnAssetRemoved().RemoveAll(this); + AssetRegistryModule.Get().OnAssetRenamed().RemoveAll(this); } AssetFamily->GetOnAssetOpened().RemoveAll(this); @@ -187,9 +189,12 @@ public: void HandleOpenAssetShortcut(ECheckBoxState InState) { - TArray Assets; - Assets.Add(AssetData.GetAsset()); - FAssetEditorManager::Get().OpenEditorForAssets(Assets); + if(AssetData.IsValid()) + { + TArray Assets; + Assets.Add(AssetData.GetAsset()); + FAssetEditorManager::Get().OpenEditorForAssets(Assets); + } } FText GetAssetText() const @@ -315,6 +320,19 @@ public: } } + void HandleAssetRenamed(const FAssetData& InAssetData, const FString& InOldObjectPath) + { + if (AssetFamily->IsAssetCompatible(InAssetData)) + { + if(InOldObjectPath == AssetData.ObjectPath.ToString()) + { + AssetData = InAssetData; + + RegenerateThumbnail(); + } + } + } + void HandleAssetAdded(const FAssetData& InAssetData) { if (AssetFamily->IsAssetCompatible(InAssetData)) @@ -376,7 +394,14 @@ public: { AssetData = NewAssetData; - // regenerate thumbnail + RegenerateThumbnail(); + } + } + + void RegenerateThumbnail() + { + if(AssetData.IsValid()) + { AssetThumbnail = MakeShareable(new FAssetThumbnail(AssetData, AssetShortcutConstants::ThumbnailSize, AssetShortcutConstants::ThumbnailSize, ThumbnailPoolPtr.Pin())); AssetThumbnailSmall = MakeShareable(new FAssetThumbnail(AssetData, AssetShortcutConstants::ThumbnailSizeSmall, AssetShortcutConstants::ThumbnailSizeSmall, ThumbnailPoolPtr.Pin())); diff --git a/Engine/Source/Editor/Persona/Private/SMontageEditor.cpp b/Engine/Source/Editor/Persona/Private/SMontageEditor.cpp index f3f26e32b585..827777e2fe4d 100644 --- a/Engine/Source/Editor/Persona/Private/SMontageEditor.cpp +++ b/Engine/Source/Editor/Persona/Private/SMontageEditor.cpp @@ -39,11 +39,8 @@ void SMontageEditor::Construct(const FArguments& InArgs, const FMontageEditorReq OnSectionsChanged = InArgs._OnSectionsChanged; MontageObj->RegisterOnMontageChanged(UAnimMontage::FOnMontageChanged::CreateSP(this, &SMontageEditor::RebuildMontagePanel, false)); - if (MontageObj) - { - EnsureStartingSection(); - EnsureSlotNode(); - } + EnsureStartingSection(); + EnsureSlotNode(); // set child montage if montage has parent bChildAnimMontage = MontageObj->HasParentAsset(); @@ -430,6 +427,21 @@ void SMontageEditor::OnEditSectionTimeFinish( int32 SectionIndex ) OnSectionsChanged.ExecuteIfBound(); } +void SMontageEditor::SetSectionTime(int32 SectionIndex, float NewTime) +{ + if(MontageObj && MontageObj->CompositeSections.IsValidIndex(SectionIndex)) + { + const FScopedTransaction Transaction(LOCTEXT("EditSection", "Edit Section Start Time")); + MontageObj->Modify(); + + FCompositeSection& Section = MontageObj->CompositeSections[SectionIndex]; + Section.SetTime(NewTime); + Section.LinkMontage(MontageObj, NewTime); + + OnEditSectionTimeFinish(SectionIndex); + } +} + void SMontageEditor::PreAnimUpdate() { MontageObj->Modify(); diff --git a/Engine/Source/Editor/Persona/Private/SMontageEditor.h b/Engine/Source/Editor/Persona/Private/SMontageEditor.h index 7ebbff15a2b5..29e7668c1a01 100644 --- a/Engine/Source/Editor/Persona/Private/SMontageEditor.h +++ b/Engine/Source/Editor/Persona/Private/SMontageEditor.h @@ -156,8 +156,11 @@ public: void AddNewSection(float StartTime, FString SectionName); void RemoveSection(int32 SectionIndex); - FString GetSectionName(int32 SectionIndex) const; + + // Set the time of the supplied section + void SetSectionTime(int32 SectionIndex, float NewTime); + void RenameSlotNode(int32 SlotIndex, FString NewSlotName); void AddNewMontageSlot(FString NewSlotName); diff --git a/Engine/Source/Editor/Persona/Private/SPoseEditor.cpp b/Engine/Source/Editor/Persona/Private/SPoseEditor.cpp index bdd1410c8c39..02c131282357 100644 --- a/Engine/Source/Editor/Persona/Private/SPoseEditor.cpp +++ b/Engine/Source/Editor/Persona/Private/SPoseEditor.cpp @@ -301,10 +301,7 @@ void SPoseViewer::Construct(const FArguments& InArgs, const TSharedRefRegisterOnPreviewMeshChanged(FOnPreviewMeshChanged::CreateSP(this, &SPoseViewer::OnPreviewMeshChanged)); - InPreviewScene->RegisterOnAnimChanged(FOnAnimChanged::CreateSP(this, &SPoseViewer::OnAssetChanged)); OnDelegatePoseListChangedDelegateHandle = PoseAssetPtr->RegisterOnPoseListChanged(UPoseAsset::FOnPoseListChanged::CreateSP(this, &SPoseViewer::OnPoseAssetModified)); @@ -312,8 +309,6 @@ void SPoseViewer::Construct(const FArguments& InArgs, const TSharedRefRemoveDelegate_AddCustomAnimationCurve(OnAddAnimationCurveDelegate); - } - CachedPreviewInstance = Cast(PreviewScenePtr.Pin()->GetPreviewMeshComponent()->GetAnimInstance()); - - if (CachedPreviewInstance.IsValid()) - { - OnAddAnimationCurveDelegate.Unbind(); - OnAddAnimationCurveDelegate.BindRaw(this, &SPoseViewer::ApplyCustomCurveOverride); - CachedPreviewInstance.Get()->AddDelegate_AddCustomAnimationCurve(OnAddAnimationCurveDelegate); - } -} - void SPoseViewer::OnPreviewMeshChanged(class USkeletalMesh* OldPreviewMesh, class USkeletalMesh* NewPreviewMesh) { - RefreshCachePreviewInstance(); CreatePoseList(NameFilterBox->GetText().ToString()); CreateCurveList(NameFilterBox->GetText().ToString()); } @@ -516,6 +485,7 @@ void SPoseViewer::OnDeletePoses() // reinit animation RestartAnimations(&(EditableSkeletonPtr.Pin()->GetSkeleton())); + RestartPreviewComponent(); CreatePoseList(NameFilterBox->GetText().ToString()); } @@ -767,14 +737,15 @@ void SPoseViewer::CreateCurveList(const FString& SearchText) CurveListView->RequestListRefresh(); } -void SPoseViewer::AddCurveOverride(FName& Name, float Weight) +void SPoseViewer::AddCurveOverride(const FName& Name, float Weight) { float& Value = OverrideCurves.FindOrAdd(Name); Value = Weight; - if (CachedPreviewInstance.IsValid()) + UAnimSingleNodeInstance* SingleNodeInstance = Cast(GetAnimInstance()); + if (SingleNodeInstance) { - CachedPreviewInstance->SetPreviewCurveOverride(Name, Value, false); + SingleNodeInstance->SetPreviewCurveOverride(Name, Value, false); } } @@ -782,9 +753,10 @@ void SPoseViewer::RemoveCurveOverride(FName& Name) { OverrideCurves.Remove(Name); - if (CachedPreviewInstance.IsValid()) + UAnimSingleNodeInstance* SingleNodeInstance = Cast(GetAnimInstance()); + if (SingleNodeInstance) { - CachedPreviewInstance->SetPreviewCurveOverride(Name, 0.f, true); + SingleNodeInstance->SetPreviewCurveOverride(Name, 0.f, true); } } @@ -792,14 +764,6 @@ SPoseViewer::~SPoseViewer() { if (PreviewScenePtr.IsValid()) { - // @Todo: change this in curve editor - // and it won't work with this one delegate idea, so just think of a better way to do - // if persona isn't there, we probably don't have the preview mesh either, so no valid anim instance - if (CachedPreviewInstance.IsValid() && OnAddAnimationCurveDelegate.IsBound()) - { - CachedPreviewInstance.Get()->RemoveDelegate_AddCustomAnimationCurve(OnAddAnimationCurveDelegate); - } - PreviewScenePtr.Pin()->UnregisterOnPreviewMeshChanged(this); PreviewScenePtr.Pin()->UnregisterOnAnimChanged(this); } @@ -810,11 +774,8 @@ SPoseViewer::~SPoseViewer() } } -void SPoseViewer::OnPoseAssetModified() +void SPoseViewer::RestartPreviewComponent() { - CreatePoseList(NameFilterBox->GetText().ToString()); - CreateCurveList(NameFilterBox->GetText().ToString()); - // it needs reinitialization of animation system // so that pose blender can reinitialize names and so on correctly if (PreviewScenePtr.IsValid()) @@ -823,9 +784,20 @@ void SPoseViewer::OnPoseAssetModified() if (PreviewComponent) { PreviewComponent->InitAnim(true); + for (auto Iter = OverrideCurves.CreateConstIterator(); Iter; ++Iter) + { + // refresh curve names that are active + AddCurveOverride(Iter.Key(), Iter.Value()); + } } } - +} + +void SPoseViewer::OnPoseAssetModified() +{ + CreatePoseList(NameFilterBox->GetText().ToString()); + CreateCurveList(NameFilterBox->GetText().ToString()); + RestartPreviewComponent(); } void SPoseViewer::ApplyCustomCurveOverride(UAnimInstance* AnimInstance) const @@ -837,6 +809,11 @@ void SPoseViewer::ApplyCustomCurveOverride(UAnimInstance* AnimInstance) const } } +UAnimInstance* SPoseViewer::GetAnimInstance() const +{ + return PreviewScenePtr.Pin()->GetPreviewMeshComponent()->GetAnimInstance(); +} + bool SPoseViewer::ModifyName(FName OldName, FName NewName, bool bSilence) { FScopedTransaction Transaction(LOCTEXT("RenamePoses", "Rename Pose")); diff --git a/Engine/Source/Editor/Persona/Private/SPoseEditor.h b/Engine/Source/Editor/Persona/Private/SPoseEditor.h index 624e9e18aa22..fa533263df06 100644 --- a/Engine/Source/Editor/Persona/Private/SPoseEditor.h +++ b/Engine/Source/Editor/Persona/Private/SPoseEditor.h @@ -282,7 +282,7 @@ public: * @param Name - Name of the morph target we want to override * @param Weight - How much of this morph target to apply (0.0 - 1.0) */ - void AddCurveOverride(FName& Name, float Weight); + void AddCurveOverride(const FName& Name, float Weight); /** Remove a named curve override */ void RemoveCurveOverride(FName& Name); @@ -304,6 +304,7 @@ public: private: void BindCommands(); + void RestartPreviewComponent(); /** Handler for context menus */ TSharedPtr OnGetContextMenuContent() const; @@ -323,8 +324,9 @@ private: void CreateCurveList(const FString& SearchText = FString()); void ApplyCustomCurveOverride(UAnimInstance* AnimInstance) const; - void RefreshCachePreviewInstance(); - void OnAssetChanged(UAnimationAsset* NewAsset); + + /** Get the anim instance we are viewing */ + UAnimInstance* GetAnimInstance() const; /** Pointer to the preview scene we are viewing */ TWeakPtr PreviewScenePtr; @@ -353,9 +355,6 @@ private: /** A list of animation curve. Used by the PoseListView. */ TArray< TSharedPtr > CurveList; - /** The skeletal mesh that we grab the animation curve from */ - TWeakObjectPtr CachedPreviewInstance; - /** Current text typed into NameFilterBox */ FText FilterText; diff --git a/Engine/Source/Editor/Persona/Private/SRigWindow.cpp b/Engine/Source/Editor/Persona/Private/SRigWindow.cpp index febc5985bea5..ef17e12feaa3 100644 --- a/Engine/Source/Editor/Persona/Private/SRigWindow.cpp +++ b/Engine/Source/Editor/Persona/Private/SRigWindow.cpp @@ -290,7 +290,7 @@ bool SRigWindow::OnTargetSkeletonSelected(USkeleton* SelectedSkeleton, URig* Ri } } - float BoneMatchedPercentage = BoneMatched / RefSkeleton.GetNum(); + float BoneMatchedPercentage = (float)(BoneMatched) / RefSkeleton.GetNum(); if (BoneMatchedPercentage > 0.5f) { Rig->SetSourceReferenceSkeleton(RefSkeleton); diff --git a/Engine/Source/Editor/Persona/Private/STimingTrack.cpp b/Engine/Source/Editor/Persona/Private/STimingTrack.cpp index 69abdf302b81..4a2649d0e513 100644 --- a/Engine/Source/Editor/Persona/Private/STimingTrack.cpp +++ b/Engine/Source/Editor/Persona/Private/STimingTrack.cpp @@ -83,8 +83,7 @@ void STimingTrack::OnArrangeChildren(const FGeometry& AllottedGeometry, FArrange { NodeData& CurrentNode = SortedNodeData[NodeIdx]; // Island generation - NodeIsland* CurrentIsland = nullptr; - CurrentIsland = &Islands[Islands.AddZeroed()]; + NodeIsland* CurrentIsland = &Islands[Islands.AddZeroed()]; int32 Direction = -1; int32 Next = NodeIdx + 1; diff --git a/Engine/Source/Editor/Persona/Private/STrack.h b/Engine/Source/Editor/Persona/Private/STrack.h index f361b8dc12a6..437fb7a36cb3 100644 --- a/Engine/Source/Editor/Persona/Private/STrack.h +++ b/Engine/Source/Editor/Persona/Private/STrack.h @@ -150,8 +150,7 @@ public: bool HitTest(const FGeometry& AllottedGeometry, FVector2D MouseLocalPose) const; virtual FVector2D GetSize() const; - virtual FVector2D ComputeDesiredSize(float) const override; - + float GetDataStartPos() const; /** Return whether this node should snap to the tracks draggable bars when being dragged */ @@ -168,6 +167,9 @@ public: bool IsBeingDragged() const {return bBeingDragged;} protected: + // Begin SWidget overrides. + virtual FVector2D ComputeDesiredSize(float) const override; + // End SWidget overrides. FSlateColor GetNodeColor() const; diff --git a/Engine/Source/Editor/Persona/Public/IPersonaPreviewScene.h b/Engine/Source/Editor/Persona/Public/IPersonaPreviewScene.h index fd6a9a96c906..6a0459c06cdf 100644 --- a/Engine/Source/Editor/Persona/Public/IPersonaPreviewScene.h +++ b/Engine/Source/Editor/Persona/Public/IPersonaPreviewScene.h @@ -29,6 +29,10 @@ DECLARE_MULTICAST_DELEGATE_TwoParams(FOnMeshClickMulticaster, HActor*, const FVi typedef FOnMeshClickMulticaster::FDelegate FOnMeshClick; +//The selected LOD changed +DECLARE_MULTICAST_DELEGATE(FOnSelectedLODChangedMulticaster); +typedef FOnSelectedLODChangedMulticaster::FDelegate FOnSelectedLODChanged; + /** Modes that the preview scene defaults to (usually depending on asset editor context) */ enum class EPreviewSceneDefaultAnimationMode : int32 { @@ -60,7 +64,7 @@ public: virtual UDebugSkelMeshComponent* GetPreviewMeshComponent() const = 0; /** Set the additional meshes used by this preview scene (sets the additional meshes on the skeleton) */ - virtual void SetAdditionalMeshes(class UPreviewMeshCollection* InAdditionalMeshes) = 0; + virtual void SetAdditionalMeshes(class UDataAsset* InAdditionalMeshes) = 0; /** Refreshes the additional meshes displayed in this preview scene */ virtual void RefreshAdditionalMeshes() = 0; @@ -190,4 +194,11 @@ public: /** Set whether or not to ignore mesh hit proxies */ virtual void SetAllowMeshHitProxies(bool bState) = 0; + + /** Register callback to be able to be notify when the select LOD is change */ + virtual void RegisterOnSelectedLODChanged(const FOnSelectedLODChanged &Delegate) = 0; + /** Unregister callback to free up the ressources */ + virtual void UnRegisterOnSelectedLODChanged(void* Thing) = 0; + /** Broadcast select LOD changed */ + virtual void BroadcastOnSelectedLODChanged() = 0; }; diff --git a/Engine/Source/Editor/PhAT/Private/PhATPreviewViewportClient.cpp b/Engine/Source/Editor/PhAT/Private/PhATPreviewViewportClient.cpp index 1302256b2f16..5545ee82ef93 100644 --- a/Engine/Source/Editor/PhAT/Private/PhATPreviewViewportClient.cpp +++ b/Engine/Source/Editor/PhAT/Private/PhATPreviewViewportClient.cpp @@ -61,7 +61,7 @@ FPhATEdPreviewViewportClient::FPhATEdPreviewViewportClient(TWeakPtr InPhA EngineShowFlags.SetCompositeEditorPrimitives(true); // Get actors asset collision bounding box, and move actor so its not intersection the floor plane at Z = 0. - FBox CollBox = SharedData->PhysicsAsset->CalcAABB(SharedData->EditorSkelComp, SharedData->EditorSkelComp->ComponentToWorld); + FBox CollBox = SharedData->PhysicsAsset->CalcAABB(SharedData->EditorSkelComp, SharedData->EditorSkelComp->GetComponentTransform()); FVector SkelCompLocation = FVector(0, 0, -CollBox.Min.Z + SharedData->EditorSimOptions->FloorGap); SharedData->EditorSkelComp->SetAbsolute(true, true, true); @@ -69,11 +69,11 @@ FPhATEdPreviewViewportClient::FPhATEdPreviewViewportClient(TWeakPtr InPhA SharedData->ResetTM = SharedData->EditorSkelComp->GetComponentToWorld(); // Get new bounding box and set view based on that. - CollBox = SharedData->PhysicsAsset->CalcAABB(SharedData->EditorSkelComp, SharedData->EditorSkelComp->ComponentToWorld); + CollBox = SharedData->PhysicsAsset->CalcAABB(SharedData->EditorSkelComp, SharedData->EditorSkelComp->GetComponentTransform()); FVector CollBoxExtent = CollBox.GetExtent(); // Take into account internal mesh translation/rotation/scaling etc. - FTransform LocalToWorld = SharedData->EditorSkelComp->ComponentToWorld; + FTransform LocalToWorld = SharedData->EditorSkelComp->GetComponentTransform(); FSphere WorldSphere = SharedData->EditorSkelMesh->GetImportedBounds().GetSphere().TransformBy(LocalToWorld); CollBoxExtent = CollBox.GetExtent(); @@ -178,7 +178,7 @@ void FPhATEdPreviewViewportClient::DrawCanvas( FViewport& InViewport, FSceneView // Iterate over each graphics bone. for (int32 i = 0; i < SharedData->EditorSkelComp->GetNumComponentSpaceTransforms(); ++i) { - FVector BonePos = SharedData->EditorSkelComp->ComponentToWorld.TransformPosition(SharedData->EditorSkelComp->GetComponentSpaceTransforms()[i].GetLocation()); + FVector BonePos = SharedData->EditorSkelComp->GetComponentTransform().TransformPosition(SharedData->EditorSkelComp->GetComponentSpaceTransforms()[i].GetLocation()); FPlane proj = View.Project(BonePos); if (proj.W > 0.f) // This avoids drawing bone names that are behind us. @@ -852,7 +852,7 @@ void FPhATEdPreviewViewportClient::SimMousePress(FViewport* InViewport, bool bCo #endif SharedData->LastClickPos = Click.GetClickPos(); FHitResult Result(1.f); - bool bHit = SharedData->EditorSkelComp->LineTraceComponent(Result, Click.GetOrigin() - Click.GetDirection() * SimGrabCheckDistance, Click.GetOrigin() + Click.GetDirection() * SimGrabCheckDistance, FCollisionQueryParams(NAME_None,true)); + bool bHit = SharedData->EditorSkelComp->LineTraceComponent(Result, Click.GetOrigin() - Click.GetDirection() * SimGrabCheckDistance, Click.GetOrigin() + Click.GetDirection() * SimGrabCheckDistance, FCollisionQueryParams(NAME_None, FCollisionQueryParams::GetUnknownStatId(),true)); if (bHit) { diff --git a/Engine/Source/Editor/PhAT/Private/PhATRender.cpp b/Engine/Source/Editor/PhAT/Private/PhATRender.cpp index 7c6dee42ead5..9020800e8b91 100644 --- a/Engine/Source/Editor/PhAT/Private/PhATRender.cpp +++ b/Engine/Source/Editor/PhAT/Private/PhATRender.cpp @@ -288,13 +288,13 @@ void UPhATEdSkeletalMeshComponent::DrawHierarchy(FPrimitiveDrawInterface* PDI, b FVector ParentPos, ChildPos; if (bAnimSkel) { - ParentPos = ComponentToWorld.TransformPosition(AnimationSpaceBases[ParentIndex].GetLocation()); - ChildPos = ComponentToWorld.TransformPosition(AnimationSpaceBases[i].GetLocation()); + ParentPos = GetComponentTransform().TransformPosition(AnimationSpaceBases[ParentIndex].GetLocation()); + ChildPos = GetComponentTransform().TransformPosition(AnimationSpaceBases[i].GetLocation()); } else { - ParentPos = ComponentToWorld.TransformPosition(GetComponentSpaceTransforms()[ParentIndex].GetLocation()); - ChildPos = ComponentToWorld.TransformPosition(GetComponentSpaceTransforms()[i].GetLocation()); + ParentPos = GetComponentTransform().TransformPosition(GetComponentSpaceTransforms()[ParentIndex].GetLocation()); + ChildPos = GetComponentTransform().TransformPosition(GetComponentSpaceTransforms()[i].GetLocation()); } FColor DrawColor = bAnimSkel ? AnimSkelDrawColor : HierarchyDrawColor; diff --git a/Engine/Source/Editor/PixelInspector/Private/PixelInspectorDetailsCustomization.cpp b/Engine/Source/Editor/PixelInspector/Private/PixelInspectorDetailsCustomization.cpp index 28fb597b515b..a0113c7e55a0 100644 --- a/Engine/Source/Editor/PixelInspector/Private/PixelInspectorDetailsCustomization.cpp +++ b/Engine/Source/Editor/PixelInspector/Private/PixelInspectorDetailsCustomization.cpp @@ -65,27 +65,24 @@ FReply FPixelInspectorDetailsCustomization::HandleColorCellMouseButtonDown(const if (DeltaX == 0 && DeltaY == 0) return FReply::Handled(); //Get the PixelInspector module - FPixelInspectorModule* PixelInspectorModule = &FModuleManager::LoadModuleChecked(TEXT("PixelInspectorModule")); - if (PixelInspectorModule != nullptr) + FPixelInspectorModule& PixelInspectorModule = FModuleManager::LoadModuleChecked(TEXT("PixelInspectorModule")); + FIntPoint InspectViewportPos = FIntPoint(-1, -1); + uint32 CoordinateViewportId = 0; + PixelInspectorModule.GetCoordinatePosition(InspectViewportPos, CoordinateViewportId); + if (InspectViewportPos == FIntPoint(-1, -1)) + return FReply::Handled(); + + InspectViewportPos.X += DeltaX; + InspectViewportPos.Y += DeltaY; + if (InspectViewportPos.X < 0 || InspectViewportPos.Y < 0) + return FReply::Handled(); + + bool IsInspectorActive = PixelInspectorModule.IsPixelInspectorEnable(); + if (!IsInspectorActive) { - FIntPoint InspectViewportPos = FIntPoint(-1, -1); - uint32 CoordinateViewportId = 0; - PixelInspectorModule->GetCoordinatePosition(InspectViewportPos, CoordinateViewportId); - if (InspectViewportPos == FIntPoint(-1, -1)) - return FReply::Handled(); - - InspectViewportPos.X += DeltaX; - InspectViewportPos.Y += DeltaY; - if (InspectViewportPos.X < 0 || InspectViewportPos.Y < 0) - return FReply::Handled(); - - bool IsInspectorActive = PixelInspectorModule->IsPixelInspectorEnable(); - if (!IsInspectorActive) - { - PixelInspectorModule->ActivateCoordinateMode(); - } - PixelInspectorModule->SetCoordinatePosition(InspectViewportPos, true); + PixelInspectorModule.ActivateCoordinateMode(); } + PixelInspectorModule.SetCoordinatePosition(InspectViewportPos, true); return FReply::Handled(); } diff --git a/Engine/Source/Editor/PlacementMode/PlacementMode.Build.cs b/Engine/Source/Editor/PlacementMode/PlacementMode.Build.cs index 169d53fb8579..0f0511876cf9 100644 --- a/Engine/Source/Editor/PlacementMode/PlacementMode.Build.cs +++ b/Engine/Source/Editor/PlacementMode/PlacementMode.Build.cs @@ -6,7 +6,7 @@ public class PlacementMode : ModuleRules { public PlacementMode(ReadOnlyTargetRules Target) : base(Target) { - PrivateIncludePathModuleNames.Add("AssetTools"); + PrivateIncludePathModuleNames.Add("AssetTools"); PrivateDependencyModuleNames.AddRange( new string[] { diff --git a/Engine/Source/Editor/PlacementMode/Private/PlacementModeModule.cpp b/Engine/Source/Editor/PlacementMode/Private/PlacementModeModule.cpp index 577827813451..1aa2e46b14a9 100644 --- a/Engine/Source/Editor/PlacementMode/Private/PlacementModeModule.cpp +++ b/Engine/Source/Editor/PlacementMode/Private/PlacementModeModule.cpp @@ -1,6 +1,6 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. +#include "PlacementModeModule.h" -#include "CoreMinimal.h" #include "Misc/ConfigCacheIni.h" #include "Modules/ModuleManager.h" #include "UObject/Object.h" @@ -9,7 +9,6 @@ #include "UObject/UObjectHash.h" #include "UObject/UObjectIterator.h" #include "Textures/SlateIcon.h" -#include "Framework/MultiBox/MultiBoxExtender.h" #include "EditorStyleSet.h" #include "GameFramework/Actor.h" #include "ActorFactories/ActorFactory.h" @@ -48,35 +47,13 @@ #include "Kismet2/KismetEditorUtilities.h" #include "ActorFactories/ActorFactoryPlanarReflection.h" -struct FPlacementCategory : FPlacementCategoryInfo -{ - FPlacementCategory(const FPlacementCategoryInfo& SourceInfo) - : FPlacementCategoryInfo(SourceInfo) - { - } - - FPlacementCategory(FPlacementCategory&& In) - : FPlacementCategoryInfo(MoveTemp(In)) - , Items(MoveTemp(In.Items)) - {} - - FPlacementCategory& operator=(FPlacementCategory&& In) - { - FPlacementCategoryInfo::operator=(MoveTemp(In)); - Items = MoveTemp(In.Items); - return *this; - } - - TMap> Items; -}; - -static TOptional GetBasicShapeColorOverride() +TOptional GetBasicShapeColorOverride() { // Get color for basic shapes. It should appear like all the other basic types static TOptional BasicShapeColorOverride; - - if( !BasicShapeColorOverride.IsSet() ) + + if (!BasicShapeColorOverride.IsSet()) { FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked(TEXT("AssetTools")); TSharedPtr AssetTypeActions; @@ -89,572 +66,485 @@ static TOptional GetBasicShapeColorOverride() return BasicShapeColorOverride; } -class FPlacementModeModule : public IPlacementModeModule +void FPlacementModeModule::StartupModule() { -public: - - /** - * Called right after the module's DLL has been loaded and the module object has been created - */ - virtual void StartupModule() override + TArray< FString > RecentlyPlacedAsStrings; + GConfig->GetArray(TEXT("PlacementMode"), TEXT("RecentlyPlaced"), RecentlyPlacedAsStrings, GEditorPerProjectIni); + + //FString ActivePaletteName; + //GConfig->GetString( TEXT( "PlacementMode" ), TEXT( "ActivePalette" ), ActivePaletteName, GEditorPerProjectIni ); + + for (int Index = 0; Index < RecentlyPlacedAsStrings.Num(); Index++) { - - TArray< FString > RecentlyPlacedAsStrings; - GConfig->GetArray(TEXT("PlacementMode"), TEXT("RecentlyPlaced"), RecentlyPlacedAsStrings, GEditorPerProjectIni); - - //FString ActivePaletteName; - //GConfig->GetString( TEXT( "PlacementMode" ), TEXT( "ActivePalette" ), ActivePaletteName, GEditorPerProjectIni ); - - for (int Index = 0; Index < RecentlyPlacedAsStrings.Num(); Index++) - { - RecentlyPlaced.Add(FActorPlacementInfo(RecentlyPlacedAsStrings[Index])); - } - - - FEditorModeRegistry::Get().RegisterMode( - FBuiltinEditorModes::EM_Placement, - NSLOCTEXT("PlacementMode", "DisplayName", "Place"), - FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.PlacementMode", "LevelEditor.PlacementMode.Small"), - true, 0); - - FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(TEXT("AssetRegistry")); - AssetRegistryModule.Get().OnAssetRemoved().AddRaw( this, &FPlacementModeModule::OnAssetRemoved ); - AssetRegistryModule.Get().OnAssetRenamed().AddRaw( this, &FPlacementModeModule::OnAssetRenamed ); - AssetRegistryModule.Get().OnAssetAdded().AddRaw( this, &FPlacementModeModule::OnAssetAdded ); - - TOptional BasicShapeColorOverride = GetBasicShapeColorOverride(); - - - RegisterPlacementCategory( - FPlacementCategoryInfo( - NSLOCTEXT( "PlacementMode", "RecentlyPlaced", "Recently Placed" ), - FBuiltInPlacementCategories::RecentlyPlaced(), - TEXT("PMRecentlyPlaced"), - TNumericLimits::Lowest(), - false - ) - ); - - { - int32 SortOrder = 0; - FName CategoryName = FBuiltInPlacementCategories::Basic(); - RegisterPlacementCategory( - FPlacementCategoryInfo( - NSLOCTEXT( "PlacementMode", "Basic", "Basic" ), - CategoryName, - TEXT("PMBasic"), - 10 - ) - ); - - FPlacementCategory* Category = Categories.Find(CategoryName); - Category->Items.Add(CreateID(), MakeShareable( new FPlaceableItem(*UActorFactoryEmptyActor::StaticClass(), SortOrder+=10)) ); - Category->Items.Add(CreateID(), MakeShareable( new FPlaceableItem(*UActorFactoryCharacter::StaticClass(), SortOrder+=10)) ); - Category->Items.Add(CreateID(), MakeShareable( new FPlaceableItem(*UActorFactoryPawn::StaticClass(), SortOrder+=10)) ); - Category->Items.Add(CreateID(), MakeShareable( new FPlaceableItem(*UActorFactoryPointLight::StaticClass(), SortOrder+=10)) ); - Category->Items.Add(CreateID(), MakeShareable( new FPlaceableItem(*UActorFactoryPlayerStart::StaticClass(), SortOrder+=10)) ); - // Cube - Category->Items.Add(CreateID(), MakeShareable( new FPlaceableItem(*UActorFactoryBasicShape::StaticClass(), FAssetData(LoadObject(nullptr,*UActorFactoryBasicShape::BasicCube.ToString())), FName("ClassThumbnail.Cube"), BasicShapeColorOverride, SortOrder+=10, NSLOCTEXT("PlacementMode", "Cube", "Cube") )) ); - // Sphere - Category->Items.Add(CreateID(), MakeShareable( new FPlaceableItem(*UActorFactoryBasicShape::StaticClass(), FAssetData(LoadObject(nullptr,*UActorFactoryBasicShape::BasicSphere.ToString())), FName("ClassThumbnail.Sphere"), BasicShapeColorOverride, SortOrder+=10, NSLOCTEXT("PlacementMode", "Sphere", "Sphere") )) ); - // Cylinder - Category->Items.Add(CreateID(), MakeShareable( new FPlaceableItem(*UActorFactoryBasicShape::StaticClass(), FAssetData(LoadObject(nullptr,*UActorFactoryBasicShape::BasicCylinder.ToString())), FName("ClassThumbnail.Cylinder"), BasicShapeColorOverride, SortOrder+=10, NSLOCTEXT("PlacementMode", "Cylinder", "Cylinder") )) ); - // Cone - Category->Items.Add(CreateID(), MakeShareable( new FPlaceableItem(*UActorFactoryBasicShape::StaticClass(), FAssetData(LoadObject(nullptr,*UActorFactoryBasicShape::BasicCone.ToString())), FName("ClassThumbnail.Cone"), BasicShapeColorOverride, SortOrder+=10, NSLOCTEXT("PlacementMode", "Cone", "Cone") )) ); - // Plane - Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryBasicShape::StaticClass(), FAssetData(LoadObject(nullptr, *UActorFactoryBasicShape::BasicPlane.ToString())), FName("ClassThumbnail.Plane"), BasicShapeColorOverride, SortOrder += 10, NSLOCTEXT("PlacementMode", "Plane", "Plane")))); - - Category->Items.Add(CreateID(), MakeShareable( new FPlaceableItem(*UActorFactoryTriggerBox::StaticClass(), SortOrder+=10)) ); - Category->Items.Add(CreateID(), MakeShareable( new FPlaceableItem(*UActorFactoryTriggerSphere::StaticClass(), SortOrder+=10)) ); - } - - { - int32 SortOrder = 0; - FName CategoryName = FBuiltInPlacementCategories::Lights(); - RegisterPlacementCategory( - FPlacementCategoryInfo( - NSLOCTEXT( "PlacementMode", "Lights", "Lights" ), - CategoryName, - TEXT("PMLights"), - 20 - ) - ); - - FPlacementCategory* Category = Categories.Find(CategoryName); - Category->Items.Add(CreateID(), MakeShareable( new FPlaceableItem(*UActorFactoryDirectionalLight::StaticClass(), SortOrder+=10)) ); - Category->Items.Add(CreateID(), MakeShareable( new FPlaceableItem(*UActorFactoryPointLight::StaticClass(), SortOrder+=10)) ); - Category->Items.Add(CreateID(), MakeShareable( new FPlaceableItem(*UActorFactorySpotLight::StaticClass(), SortOrder+=10)) ); - Category->Items.Add(CreateID(), MakeShareable( new FPlaceableItem(*UActorFactorySkyLight::StaticClass(), SortOrder+=10)) ); - } - - { - int32 SortOrder = 0; - FName CategoryName = FBuiltInPlacementCategories::Visual(); - RegisterPlacementCategory( - FPlacementCategoryInfo( - NSLOCTEXT( "PlacementMode", "VisualEffects", "Visual Effects" ), - CategoryName, - TEXT("PMVisual"), - 30 - ) - ); - - UActorFactory* PPFactory = GEditor->FindActorFactoryByClassForActorClass( UActorFactoryBoxVolume::StaticClass(), APostProcessVolume::StaticClass() ); - - FPlacementCategory* Category = Categories.Find(CategoryName); - Category->Items.Add(CreateID(), MakeShareable( new FPlaceableItem(PPFactory, FAssetData(APostProcessVolume::StaticClass()), SortOrder+=10)) ); - Category->Items.Add(CreateID(), MakeShareable( new FPlaceableItem(*UActorFactoryAtmosphericFog::StaticClass(), SortOrder+=10)) ); - Category->Items.Add(CreateID(), MakeShareable( new FPlaceableItem(*UActorFactoryExponentialHeightFog::StaticClass(), SortOrder+=10)) ); - Category->Items.Add(CreateID(), MakeShareable( new FPlaceableItem(*UActorFactorySphereReflectionCapture::StaticClass(), SortOrder+=10)) ); - Category->Items.Add(CreateID(), MakeShareable( new FPlaceableItem(*UActorFactoryBoxReflectionCapture::StaticClass(), SortOrder+=10)) ); - Category->Items.Add(CreateID(), MakeShareable( new FPlaceableItem(*UActorFactoryPlanarReflection::StaticClass(), SortOrder += 10))); - Category->Items.Add(CreateID(), MakeShareable( new FPlaceableItem(*UActorFactoryDeferredDecal::StaticClass(), SortOrder+=10)) ); - } - - RegisterPlacementCategory( - FPlacementCategoryInfo( - NSLOCTEXT( "PlacementMode", "Volumes", "Volumes" ), - FBuiltInPlacementCategories::Volumes(), - TEXT("PMVolumes"), - 40 - ) - ); - - RegisterPlacementCategory( - FPlacementCategoryInfo( - NSLOCTEXT( "PlacementMode", "AllClasses", "All Classes" ), - FBuiltInPlacementCategories::AllClasses(), - TEXT("PMAllClasses"), - 50 - ) - ); + RecentlyPlaced.Add(FActorPlacementInfo(RecentlyPlacedAsStrings[Index])); } - /** - * Called before the module is unloaded, right before the module object is destroyed. - */ - virtual void PreUnloadCallback() override - { - FEditorModeRegistry::Get().UnregisterMode( FBuiltinEditorModes::EM_Placement ); - FAssetRegistryModule& AssetRegistryModule = FModuleManager::GetModuleChecked(TEXT("AssetRegistry")); - AssetRegistryModule.Get().OnAssetRemoved().RemoveAll( this ); - AssetRegistryModule.Get().OnAssetRenamed().RemoveAll( this ); - AssetRegistryModule.Get().OnAssetAdded().RemoveAll( this ); + FEditorModeRegistry::Get().RegisterMode( + FBuiltinEditorModes::EM_Placement, + NSLOCTEXT("PlacementMode", "DisplayName", "Place"), + FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.PlacementMode", "LevelEditor.PlacementMode.Small"), + true, 0); + + FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(TEXT("AssetRegistry")); + AssetRegistryModule.Get().OnAssetRemoved().AddRaw(this, &FPlacementModeModule::OnAssetRemoved); + AssetRegistryModule.Get().OnAssetRenamed().AddRaw(this, &FPlacementModeModule::OnAssetRenamed); + AssetRegistryModule.Get().OnAssetAdded().AddRaw(this, &FPlacementModeModule::OnAssetAdded); + + TOptional BasicShapeColorOverride = GetBasicShapeColorOverride(); + + + RegisterPlacementCategory( + FPlacementCategoryInfo( + NSLOCTEXT("PlacementMode", "RecentlyPlaced", "Recently Placed"), + FBuiltInPlacementCategories::RecentlyPlaced(), + TEXT("PMRecentlyPlaced"), + TNumericLimits::Lowest(), + false + ) + ); + + { + int32 SortOrder = 0; + FName CategoryName = FBuiltInPlacementCategories::Basic(); + RegisterPlacementCategory( + FPlacementCategoryInfo( + NSLOCTEXT("PlacementMode", "Basic", "Basic"), + CategoryName, + TEXT("PMBasic"), + 10 + ) + ); + + FPlacementCategory* Category = Categories.Find(CategoryName); + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryEmptyActor::StaticClass(), SortOrder += 10))); + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryCharacter::StaticClass(), SortOrder += 10))); + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryPawn::StaticClass(), SortOrder += 10))); + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryPointLight::StaticClass(), SortOrder += 10))); + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryPlayerStart::StaticClass(), SortOrder += 10))); + // Cube + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryBasicShape::StaticClass(), FAssetData(LoadObject(nullptr, *UActorFactoryBasicShape::BasicCube.ToString())), FName("ClassThumbnail.Cube"), BasicShapeColorOverride, SortOrder += 10, NSLOCTEXT("PlacementMode", "Cube", "Cube")))); + // Sphere + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryBasicShape::StaticClass(), FAssetData(LoadObject(nullptr, *UActorFactoryBasicShape::BasicSphere.ToString())), FName("ClassThumbnail.Sphere"), BasicShapeColorOverride, SortOrder += 10, NSLOCTEXT("PlacementMode", "Sphere", "Sphere")))); + // Cylinder + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryBasicShape::StaticClass(), FAssetData(LoadObject(nullptr, *UActorFactoryBasicShape::BasicCylinder.ToString())), FName("ClassThumbnail.Cylinder"), BasicShapeColorOverride, SortOrder += 10, NSLOCTEXT("PlacementMode", "Cylinder", "Cylinder")))); + // Cone + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryBasicShape::StaticClass(), FAssetData(LoadObject(nullptr, *UActorFactoryBasicShape::BasicCone.ToString())), FName("ClassThumbnail.Cone"), BasicShapeColorOverride, SortOrder += 10, NSLOCTEXT("PlacementMode", "Cone", "Cone")))); + // Plane + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryBasicShape::StaticClass(), FAssetData(LoadObject(nullptr, *UActorFactoryBasicShape::BasicPlane.ToString())), FName("ClassThumbnail.Plane"), BasicShapeColorOverride, SortOrder += 10, NSLOCTEXT("PlacementMode", "Plane", "Plane")))); + + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryTriggerBox::StaticClass(), SortOrder += 10))); + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryTriggerSphere::StaticClass(), SortOrder += 10))); } - DECLARE_DERIVED_EVENT( FPlacementModeModule, IPlacementModeModule::FOnRecentlyPlacedChanged, FOnRecentlyPlacedChanged ); - virtual FOnRecentlyPlacedChanged& OnRecentlyPlacedChanged() override { return RecentlyPlacedChanged; } - - DECLARE_DERIVED_EVENT( FPlacementModeModule, IPlacementModeModule::FOnAllPlaceableAssetsChanged, FOnAllPlaceableAssetsChanged ); - virtual FOnAllPlaceableAssetsChanged& OnAllPlaceableAssetsChanged() override { return AllPlaceableAssetsChanged; } - - /** - * Add the specified assets to the recently placed items list - */ - virtual void AddToRecentlyPlaced( const TArray< UObject* >& PlacedObjects, UActorFactory* FactoryUsed = NULL ) override { - FString FactoryPath; - if (FactoryUsed != NULL) + int32 SortOrder = 0; + FName CategoryName = FBuiltInPlacementCategories::Lights(); + RegisterPlacementCategory( + FPlacementCategoryInfo( + NSLOCTEXT("PlacementMode", "Lights", "Lights"), + CategoryName, + TEXT("PMLights"), + 20 + ) + ); + + FPlacementCategory* Category = Categories.Find(CategoryName); + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryDirectionalLight::StaticClass(), SortOrder += 10))); + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryPointLight::StaticClass(), SortOrder += 10))); + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactorySpotLight::StaticClass(), SortOrder += 10))); + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactorySkyLight::StaticClass(), SortOrder += 10))); + } + + { + int32 SortOrder = 0; + FName CategoryName = FBuiltInPlacementCategories::Visual(); + RegisterPlacementCategory( + FPlacementCategoryInfo( + NSLOCTEXT("PlacementMode", "VisualEffects", "Visual Effects"), + CategoryName, + TEXT("PMVisual"), + 30 + ) + ); + + UActorFactory* PPFactory = GEditor->FindActorFactoryByClassForActorClass(UActorFactoryBoxVolume::StaticClass(), APostProcessVolume::StaticClass()); + + FPlacementCategory* Category = Categories.Find(CategoryName); + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(PPFactory, FAssetData(APostProcessVolume::StaticClass()), SortOrder += 10))); + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryAtmosphericFog::StaticClass(), SortOrder += 10))); + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryExponentialHeightFog::StaticClass(), SortOrder += 10))); + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactorySphereReflectionCapture::StaticClass(), SortOrder += 10))); + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryBoxReflectionCapture::StaticClass(), SortOrder += 10))); + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryPlanarReflection::StaticClass(), SortOrder += 10))); + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryDeferredDecal::StaticClass(), SortOrder += 10))); + } + + RegisterPlacementCategory( + FPlacementCategoryInfo( + NSLOCTEXT("PlacementMode", "Volumes", "Volumes"), + FBuiltInPlacementCategories::Volumes(), + TEXT("PMVolumes"), + 40 + ) + ); + + RegisterPlacementCategory( + FPlacementCategoryInfo( + NSLOCTEXT("PlacementMode", "AllClasses", "All Classes"), + FBuiltInPlacementCategories::AllClasses(), + TEXT("PMAllClasses"), + 50 + ) + ); +} + +void FPlacementModeModule::PreUnloadCallback() +{ + FEditorModeRegistry::Get().UnregisterMode(FBuiltinEditorModes::EM_Placement); + + FAssetRegistryModule& AssetRegistryModule = FModuleManager::GetModuleChecked(TEXT("AssetRegistry")); + AssetRegistryModule.Get().OnAssetRemoved().RemoveAll(this); + AssetRegistryModule.Get().OnAssetRenamed().RemoveAll(this); + AssetRegistryModule.Get().OnAssetAdded().RemoveAll(this); +} + +void FPlacementModeModule::AddToRecentlyPlaced(const TArray& PlacedObjects, UActorFactory* FactoryUsed /* = NULL */) +{ + FString FactoryPath; + if (FactoryUsed != NULL) + { + FactoryPath = FactoryUsed->GetPathName(); + } + + TArray< UObject* > FilteredPlacedObjects; + for (UObject* PlacedObject : PlacedObjects) + { + // Don't include null placed objects that just have factories. + if (PlacedObject == NULL) { - FactoryPath = FactoryUsed->GetPathName(); + continue; } - TArray< UObject* > FilteredPlacedObjects; - for (UObject* PlacedObject : PlacedObjects) + // Don't add brush builders to the recently placed. + if (PlacedObject->IsA(UBrushBuilder::StaticClass())) { - // Don't include null placed objects that just have factories. - if (PlacedObject == NULL) - { - continue; - } - - // Don't add brush builders to the recently placed. - if (PlacedObject->IsA(UBrushBuilder::StaticClass())) - { - continue; - } - - FilteredPlacedObjects.Add(PlacedObject); + continue; } - // Don't change the recently placed if nothing passed the filter. - if (FilteredPlacedObjects.Num() == 0) - { - return; - } + FilteredPlacedObjects.Add(PlacedObject); + } - bool Changed = false; - for (int Index = 0; Index < FilteredPlacedObjects.Num(); Index++) - { - Changed |= RecentlyPlaced.Remove(FActorPlacementInfo(FilteredPlacedObjects[Index]->GetPathName(), FactoryPath)) > 0; - } + // Don't change the recently placed if nothing passed the filter. + if (FilteredPlacedObjects.Num() == 0) + { + return; + } - for (int Index = 0; Index < FilteredPlacedObjects.Num(); Index++) - { - if (FilteredPlacedObjects[Index] != NULL) - { - RecentlyPlaced.Insert(FActorPlacementInfo(FilteredPlacedObjects[Index]->GetPathName(), FactoryPath), 0); - Changed = true; - } - } + bool Changed = false; + for (int Index = 0; Index < FilteredPlacedObjects.Num(); Index++) + { + Changed |= RecentlyPlaced.Remove(FActorPlacementInfo(FilteredPlacedObjects[Index]->GetPathName(), FactoryPath)) > 0; + } - for (int Index = RecentlyPlaced.Num() - 1; Index >= 20; Index--) + for (int Index = 0; Index < FilteredPlacedObjects.Num(); Index++) + { + if (FilteredPlacedObjects[Index] != NULL) { - RecentlyPlaced.RemoveAt(Index); + RecentlyPlaced.Insert(FActorPlacementInfo(FilteredPlacedObjects[Index]->GetPathName(), FactoryPath), 0); Changed = true; } - - if (Changed) - { - TArray< FString > RecentlyPlacedAsStrings; - for (int Index = 0; Index < RecentlyPlaced.Num(); Index++) - { - RecentlyPlacedAsStrings.Add(RecentlyPlaced[Index].ToString()); - } - - GConfig->SetArray(TEXT("PlacementMode"), TEXT("RecentlyPlaced"), RecentlyPlacedAsStrings, GEditorPerProjectIni); - RecentlyPlacedChanged.Broadcast(RecentlyPlaced); - } } - void OnAssetRemoved(const FAssetData& /*InRemovedAssetData*/) + for (int Index = RecentlyPlaced.Num() - 1; Index >= 20; Index--) { + RecentlyPlaced.RemoveAt(Index); + Changed = true; + } + + if (Changed) + { + TArray< FString > RecentlyPlacedAsStrings; + for (int Index = 0; Index < RecentlyPlaced.Num(); Index++) + { + RecentlyPlacedAsStrings.Add(RecentlyPlaced[Index].ToString()); + } + + GConfig->SetArray(TEXT("PlacementMode"), TEXT("RecentlyPlaced"), RecentlyPlacedAsStrings, GEditorPerProjectIni); RecentlyPlacedChanged.Broadcast(RecentlyPlaced); - AllPlaceableAssetsChanged.Broadcast(); } +} - void OnAssetRenamed(const FAssetData& AssetData, const FString& OldObjectPath) +void FPlacementModeModule::OnAssetRemoved(const FAssetData&) +{ + RecentlyPlacedChanged.Broadcast(RecentlyPlaced); + AllPlaceableAssetsChanged.Broadcast(); +} + +void FPlacementModeModule::OnAssetRenamed(const FAssetData& AssetData, const FString& OldObjectPath) +{ + for (auto& RecentlyPlacedItem : RecentlyPlaced) { - for (auto& RecentlyPlacedItem : RecentlyPlaced) + if (RecentlyPlacedItem.ObjectPath == OldObjectPath) { - if (RecentlyPlacedItem.ObjectPath == OldObjectPath) - { - RecentlyPlacedItem.ObjectPath = AssetData.ObjectPath.ToString(); - break; - } - } - - RecentlyPlacedChanged.Broadcast(RecentlyPlaced); - AllPlaceableAssetsChanged.Broadcast(); - } - - void OnAssetAdded(const FAssetData& AssetData) - { - AllPlaceableAssetsChanged.Broadcast(); - } - - /** - * Add the specified asset to the recently placed items list - */ - virtual void AddToRecentlyPlaced( UObject* Asset, UActorFactory* FactoryUsed = NULL ) override - { - TArray< UObject* > Assets; - Assets.Add( Asset ); - AddToRecentlyPlaced( Assets, FactoryUsed ); - } - - /** - * Get a copy of the recently placed items list - */ - virtual const TArray< FActorPlacementInfo >& GetRecentlyPlaced() const override - { - return RecentlyPlaced; - } - - /** @return the event that is broadcast whenever the placement mode enters a placing session */ - DECLARE_DERIVED_EVENT( FPlacementModeModule, IPlacementModeModule::FOnStartedPlacingEvent, FOnStartedPlacingEvent ); - virtual FOnStartedPlacingEvent& OnStartedPlacing() override - { - return StartedPlacingEvent; - } - virtual void BroadcastStartedPlacing( const TArray< UObject* >& Assets ) override - { - StartedPlacingEvent.Broadcast( Assets ); - } - - /** @return the event that is broadcast whenever the placement mode exits a placing session */ - DECLARE_DERIVED_EVENT( FPlacementModeModule, IPlacementModeModule::FOnStoppedPlacingEvent, FOnStoppedPlacingEvent ); - virtual FOnStoppedPlacingEvent& OnStoppedPlacing() override - { - return StoppedPlacingEvent; - } - virtual void BroadcastStoppedPlacing( bool bWasSuccessfullyPlaced ) override - { - StoppedPlacingEvent.Broadcast( bWasSuccessfullyPlaced ); - } - -public: - - virtual bool RegisterPlacementCategory(const FPlacementCategoryInfo& Info) - { - if (Categories.Contains(Info.UniqueHandle)) - { - return false; - } - - Categories.Add(Info.UniqueHandle, Info); - return true; - } - - virtual const FPlacementCategoryInfo* GetRegisteredPlacementCategory(FName CategoryName) const override - { - return Categories.Find(CategoryName); - } - - virtual void UnregisterPlacementCategory(FName Handle) - { - Categories.Remove(Handle); - } - - virtual void GetSortedCategories(TArray& OutCategories) const - { - TArray SortedNames; - Categories.GenerateKeyArray(SortedNames); - - SortedNames.Sort([&](const FName& A, const FName& B){ - return Categories[A].SortOrder < Categories[B].SortOrder; - }); - - OutCategories.Reset(Categories.Num()); - for (const FName& Name : SortedNames) - { - OutCategories.Add(Categories[Name]); + RecentlyPlacedItem.ObjectPath = AssetData.ObjectPath.ToString(); + break; } } - virtual TOptional RegisterPlaceableItem(FName CategoryName, const TSharedRef& InItem) + RecentlyPlacedChanged.Broadcast(RecentlyPlaced); + AllPlaceableAssetsChanged.Broadcast(); +} + +void FPlacementModeModule::OnAssetAdded(const FAssetData& AssetData) +{ + AllPlaceableAssetsChanged.Broadcast(); +} + +void FPlacementModeModule::AddToRecentlyPlaced(UObject* Asset, UActorFactory* FactoryUsed /* = NULL */) +{ + TArray< UObject* > Assets; + Assets.Add(Asset); + AddToRecentlyPlaced(Assets, FactoryUsed); +} + +bool FPlacementModeModule::RegisterPlacementCategory(const FPlacementCategoryInfo& Info) +{ + if (Categories.Contains(Info.UniqueHandle)) { - FPlacementCategory* Category = Categories.Find(CategoryName); - if (Category && !Category->CustomGenerator) - { - FPlacementModeID ID = CreateID(CategoryName); - Category->Items.Add(ID.UniqueID, InItem); - return ID; - } - return TOptional(); + return false; } - virtual void UnregisterPlaceableItem(FPlacementModeID ID) + Categories.Add(Info.UniqueHandle, Info); + return true; +} + +void FPlacementModeModule::UnregisterPlacementCategory(FName Handle) +{ + Categories.Remove(Handle); +} + +void FPlacementModeModule::GetSortedCategories(TArray& OutCategories) const +{ + TArray SortedNames; + Categories.GenerateKeyArray(SortedNames); + + SortedNames.Sort([&](const FName& A, const FName& B) { + return Categories[A].SortOrder < Categories[B].SortOrder; + }); + + OutCategories.Reset(Categories.Num()); + for (const FName& Name : SortedNames) { - FPlacementCategory* Category = Categories.Find(ID.Category); - if (Category) + OutCategories.Add(Categories[Name]); + } +} + +TOptional FPlacementModeModule::RegisterPlaceableItem(FName CategoryName, const TSharedRef& InItem) +{ + FPlacementCategory* Category = Categories.Find(CategoryName); + if (Category && !Category->CustomGenerator) + { + FPlacementModeID ID = CreateID(CategoryName); + Category->Items.Add(ID.UniqueID, InItem); + return ID; + } + return TOptional(); +} + +void FPlacementModeModule::UnregisterPlaceableItem(FPlacementModeID ID) +{ + FPlacementCategory* Category = Categories.Find(ID.Category); + if (Category) + { + Category->Items.Remove(ID.UniqueID); + } +} + +void FPlacementModeModule::GetItemsForCategory(FName CategoryName, TArray>& OutItems) const +{ + const FPlacementCategory* Category = Categories.Find(CategoryName); + if (Category) + { + for (auto& Pair : Category->Items) { - Category->Items.Remove(ID.UniqueID); + OutItems.Add(Pair.Value); } } +} - virtual void GetItemsForCategory(FName CategoryName, TArray>& OutItems) const +void FPlacementModeModule::GetFilteredItemsForCategory(FName CategoryName, TArray>& OutItems, TFunctionRef &)> Filter) const +{ + const FPlacementCategory* Category = Categories.Find(CategoryName); + if (Category) { - const FPlacementCategory* Category = Categories.Find(CategoryName); - if (Category) + for (auto& Pair : Category->Items) { - for (auto& Pair : Category->Items) + if (Filter(Pair.Value)) { OutItems.Add(Pair.Value); } } } +} - virtual void GetFilteredItemsForCategory(FName CategoryName, TArray>& OutItems, TFunctionRef&)> Filter) const +void FPlacementModeModule::RegenerateItemsForCategory(FName Category) +{ + if (Category == FBuiltInPlacementCategories::RecentlyPlaced()) { - const FPlacementCategory* Category = Categories.Find(CategoryName); - if (Category) + RefreshRecentlyPlaced(); + } + else if (Category == FBuiltInPlacementCategories::Volumes()) + { + RefreshVolumes(); + } + else if (Category == FBuiltInPlacementCategories::AllClasses()) + { + RefreshAllPlaceableClasses(); + } + + BroadcastPlacementModeCategoryRefreshed(Category); +} + +void FPlacementModeModule::RefreshRecentlyPlaced() +{ + FName CategoryName = FBuiltInPlacementCategories::RecentlyPlaced(); + + FPlacementCategory* Category = Categories.Find(CategoryName); + if (!Category) + { + return; + } + + Category->Items.Reset(); + + + FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(TEXT("AssetRegistry")); + + for (const FActorPlacementInfo& RecentlyPlacedItem : RecentlyPlaced) + { + UObject* Asset = FindObject(nullptr, *RecentlyPlacedItem.ObjectPath); + + // If asset is pending delete, it will not be marked as RF_Standalone, in which case we skip it + if (Asset != nullptr && Asset->HasAnyFlags(RF_Standalone)) { - for (auto& Pair : Category->Items) + FAssetData AssetData = AssetRegistryModule.Get().GetAssetByObjectPath(*RecentlyPlacedItem.ObjectPath); + + if (AssetData.IsValid()) { - if (Filter(Pair.Value)) - { - OutItems.Add(Pair.Value); - } + UActorFactory* Factory = FindObject(nullptr, *RecentlyPlacedItem.Factory); + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(Factory, AssetData))); } } } +} - virtual void RegenerateItemsForCategory(FName Category) override +void FPlacementModeModule::RefreshVolumes() +{ + FName CategoryName = FBuiltInPlacementCategories::Volumes(); + + FPlacementCategory* Category = Categories.Find(CategoryName); + if (!Category) { - if (Category == FBuiltInPlacementCategories::RecentlyPlaced()) - { - RefreshRecentlyPlaced(); - } - else if (Category == FBuiltInPlacementCategories::Volumes()) - { - RefreshVolumes(); - } - else if (Category == FBuiltInPlacementCategories::AllClasses()) - { - RefreshAllPlaceableClasses(); - } - - // @todo: Broadcast so clients can update dynamic lists? + return; } - void RefreshRecentlyPlaced() + Category->Items.Reset(); + + // Add loaded classes + for (TObjectIterator ClassIt; ClassIt; ++ClassIt) { - FName CategoryName = FBuiltInPlacementCategories::RecentlyPlaced(); + const UClass* Class = *ClassIt; - FPlacementCategory* Category = Categories.Find(CategoryName); - if (!Category) + if (!Class->HasAllClassFlags(CLASS_NotPlaceable) && + !Class->HasAnyClassFlags(CLASS_Abstract | CLASS_Deprecated | CLASS_NewerVersionExists) && + Class->IsChildOf(AVolume::StaticClass()) && + Class->ClassGeneratedBy == nullptr) { - return; + UActorFactory* Factory = GEditor->FindActorFactoryByClassForActorClass(UActorFactoryBoxVolume::StaticClass(), Class); + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(Factory, FAssetData(Class)))); } + } +} - Category->Items.Reset(); +void FPlacementModeModule::RefreshAllPlaceableClasses() +{ + FName CategoryName = FBuiltInPlacementCategories::AllClasses(); + // Unregister old stuff + FPlacementCategory* Category = Categories.Find(CategoryName); + if (!Category) + { + return; + } - FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked( TEXT( "AssetRegistry" ) ); + Category->Items.Reset(); - for (const FActorPlacementInfo& RecentlyPlacedItem : RecentlyPlaced) + // Manually add some special cases that aren't added below + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryEmptyActor::StaticClass()))); + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryCharacter::StaticClass()))); + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryPawn::StaticClass()))); + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryBasicShape::StaticClass(), FAssetData(LoadObject(nullptr, *UActorFactoryBasicShape::BasicCube.ToString())), FName("ClassThumbnail.Cube"), GetBasicShapeColorOverride()))); + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryBasicShape::StaticClass(), FAssetData(LoadObject(nullptr, *UActorFactoryBasicShape::BasicSphere.ToString())), FName("ClassThumbnail.Sphere"), GetBasicShapeColorOverride()))); + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryBasicShape::StaticClass(), FAssetData(LoadObject(nullptr, *UActorFactoryBasicShape::BasicCylinder.ToString())), FName("ClassThumbnail.Cylinder"), GetBasicShapeColorOverride()))); + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryBasicShape::StaticClass(), FAssetData(LoadObject(nullptr, *UActorFactoryBasicShape::BasicCone.ToString())), FName("ClassThumbnail.Cone"), GetBasicShapeColorOverride()))); + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryBasicShape::StaticClass(), FAssetData(LoadObject(nullptr, *UActorFactoryBasicShape::BasicPlane.ToString())), FName("ClassThumbnail.Plane"), GetBasicShapeColorOverride()))); + + // Make a map of UClasses to ActorFactories that support them + const TArray< UActorFactory *>& ActorFactories = GEditor->ActorFactories; + TMap ActorFactoryMap; + for (int32 FactoryIdx = 0; FactoryIdx < ActorFactories.Num(); ++FactoryIdx) + { + UActorFactory* ActorFactory = ActorFactories[FactoryIdx]; + + if (ActorFactory) { - UObject* Asset = FindObject(nullptr, *RecentlyPlacedItem.ObjectPath); + ActorFactoryMap.Add(ActorFactory->GetDefaultActorClass(FAssetData()), ActorFactory); + } + } - // If asset is pending delete, it will not be marked as RF_Standalone, in which case we skip it - if (Asset != nullptr && Asset->HasAnyFlags(RF_Standalone)) + FAssetData NoAssetData; + FText UnusedErrorMessage; + + // Add loaded classes + for (TObjectIterator ClassIt; ClassIt; ++ClassIt) + { + // Don't offer skeleton classes + bool bIsSkeletonClass = FKismetEditorUtilities::IsClassABlueprintSkeleton(*ClassIt); + + if (!ClassIt->HasAllClassFlags(CLASS_NotPlaceable) && + !ClassIt->HasAnyClassFlags(CLASS_Abstract | CLASS_Deprecated | CLASS_NewerVersionExists) && + ClassIt->IsChildOf(AActor::StaticClass()) && + (!ClassIt->IsChildOf(ABrush::StaticClass()) || ClassIt->IsChildOf(AVolume::StaticClass())) && + !bIsSkeletonClass) + { + UActorFactory* ActorFactory = ActorFactoryMap.FindRef(*ClassIt); + + const bool IsVolume = ClassIt->IsChildOf(AVolume::StaticClass()); + + if (IsVolume) { - FAssetData AssetData = AssetRegistryModule.Get().GetAssetByObjectPath(*RecentlyPlacedItem.ObjectPath); - - if (AssetData.IsValid()) - { - UActorFactory* Factory = FindObject(nullptr, *RecentlyPlacedItem.Factory); - Category->Items.Add(CreateID(), MakeShareable( new FPlaceableItem(Factory, AssetData) )); - } + ActorFactory = GEditor->FindActorFactoryByClassForActorClass(UActorFactoryBoxVolume::StaticClass(), *ClassIt); } - } - - // Broadcast? - } - - void RefreshVolumes() - { - FName CategoryName = FBuiltInPlacementCategories::Volumes(); - - FPlacementCategory* Category = Categories.Find(CategoryName); - if (!Category) - { - return; - } - - Category->Items.Reset(); - - // Add loaded classes - for ( TObjectIterator ClassIt; ClassIt; ++ClassIt ) - { - const UClass* Class = *ClassIt; - - if (!Class->HasAllClassFlags(CLASS_NotPlaceable) && - !Class->HasAnyClassFlags(CLASS_Abstract | CLASS_Deprecated | CLASS_NewerVersionExists) && - Class->IsChildOf(AVolume::StaticClass()) && - Class->ClassGeneratedBy == nullptr ) + else if (ActorFactory && !ActorFactory->CanCreateActorFrom(NoAssetData, UnusedErrorMessage)) { - UActorFactory* Factory = GEditor->FindActorFactoryByClassForActorClass(UActorFactoryBoxVolume::StaticClass(), Class); - Category->Items.Add(CreateID(), MakeShareable( new FPlaceableItem(Factory, FAssetData(Class)) )); + continue; } + + Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(ActorFactory, FAssetData(*ClassIt)))); } - - // Broadcast? } +} - void RefreshAllPlaceableClasses() - { - FName CategoryName = FBuiltInPlacementCategories::AllClasses(); - - // Unregister old stuff - FPlacementCategory* Category = Categories.Find(CategoryName); - if (!Category) - { - return; - } - - Category->Items.Reset(); - - // Manually add some special cases that aren't added below - Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryEmptyActor::StaticClass()))); - Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryCharacter::StaticClass()))); - Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryPawn::StaticClass()))); - Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryBasicShape::StaticClass(), FAssetData(LoadObject(nullptr, *UActorFactoryBasicShape::BasicCube.ToString())), FName("ClassThumbnail.Cube"), GetBasicShapeColorOverride()))); - Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryBasicShape::StaticClass(), FAssetData(LoadObject(nullptr, *UActorFactoryBasicShape::BasicSphere.ToString())), FName("ClassThumbnail.Sphere"), GetBasicShapeColorOverride()))); - Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryBasicShape::StaticClass(), FAssetData(LoadObject(nullptr, *UActorFactoryBasicShape::BasicCylinder.ToString())), FName("ClassThumbnail.Cylinder"), GetBasicShapeColorOverride()))); - Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryBasicShape::StaticClass(), FAssetData(LoadObject(nullptr, *UActorFactoryBasicShape::BasicCone.ToString())), FName("ClassThumbnail.Cone"), GetBasicShapeColorOverride()))); - Category->Items.Add(CreateID(), MakeShareable(new FPlaceableItem(*UActorFactoryBasicShape::StaticClass(), FAssetData(LoadObject(nullptr, *UActorFactoryBasicShape::BasicPlane.ToString())), FName("ClassThumbnail.Plane"), GetBasicShapeColorOverride()))); - - // Make a map of UClasses to ActorFactories that support them - const TArray< UActorFactory *>& ActorFactories = GEditor->ActorFactories; - TMap ActorFactoryMap; - for ( int32 FactoryIdx = 0; FactoryIdx < ActorFactories.Num(); ++FactoryIdx ) - { - UActorFactory* ActorFactory = ActorFactories[FactoryIdx]; - - if ( ActorFactory ) - { - ActorFactoryMap.Add(ActorFactory->GetDefaultActorClass(FAssetData()), ActorFactory); - } - } - - FAssetData NoAssetData; - FText UnusedErrorMessage; - - // Add loaded classes - for ( TObjectIterator ClassIt; ClassIt; ++ClassIt ) - { - // Don't offer skeleton classes - bool bIsSkeletonClass = FKismetEditorUtilities::IsClassABlueprintSkeleton(*ClassIt); - - if ( !ClassIt->HasAllClassFlags(CLASS_NotPlaceable) && - !ClassIt->HasAnyClassFlags(CLASS_Abstract | CLASS_Deprecated | CLASS_NewerVersionExists) && - ClassIt->IsChildOf(AActor::StaticClass()) && - ( !ClassIt->IsChildOf(ABrush::StaticClass()) || ClassIt->IsChildOf(AVolume::StaticClass()) ) && - !bIsSkeletonClass ) - { - UActorFactory* ActorFactory = ActorFactoryMap.FindRef(*ClassIt); - - const bool IsVolume = ClassIt->IsChildOf(AVolume::StaticClass()); - - if ( IsVolume ) - { - ActorFactory = GEditor->FindActorFactoryByClassForActorClass(UActorFactoryBoxVolume::StaticClass(), *ClassIt); - } - else if (ActorFactory && !ActorFactory->CanCreateActorFrom(NoAssetData, UnusedErrorMessage)) - { - continue; - } - - Category->Items.Add(CreateID(), MakeShareable( new FPlaceableItem(ActorFactory, FAssetData(*ClassIt)) )); - } - } - - // Broadcast? - } - -private: - - FGuid CreateID() - { - return FGuid::NewGuid(); - } - - FPlacementModeID CreateID(FName InCategory) - { - FPlacementModeID NewID; - NewID.UniqueID = CreateID(); - NewID.Category = InCategory; - return NewID; - } - -private: - - TMap Categories; - - TArray< FActorPlacementInfo > RecentlyPlaced; - FOnRecentlyPlacedChanged RecentlyPlacedChanged; - - FOnAllPlaceableAssetsChanged AllPlaceableAssetsChanged; - - FOnStartedPlacingEvent StartedPlacingEvent; - FOnStoppedPlacingEvent StoppedPlacingEvent; - - TArray< TSharedPtr > ContentPaletteFiltersExtenders; - TArray< TSharedPtr > PaletteExtenders; -}; - -IMPLEMENT_MODULE( FPlacementModeModule, PlacementMode ); +FGuid FPlacementModeModule::CreateID() +{ + return FGuid::NewGuid(); +} +FPlacementModeID FPlacementModeModule::CreateID(FName InCategory) +{ + FPlacementModeID NewID; + NewID.UniqueID = CreateID(); + NewID.Category = InCategory; + return NewID; +} \ No newline at end of file diff --git a/Engine/Source/Editor/PlacementMode/Private/SPlacementModeTools.cpp b/Engine/Source/Editor/PlacementMode/Private/SPlacementModeTools.cpp index 37095f098824..e1ab61bde15f 100644 --- a/Engine/Source/Editor/PlacementMode/Private/SPlacementModeTools.cpp +++ b/Engine/Source/Editor/PlacementMode/Private/SPlacementModeTools.cpp @@ -243,9 +243,13 @@ FReply SPlacementAssetEntry::OnDragDetected(const FGeometry& MyGeometry, const F { bIsPressed = false; - TArray DraggedAssetDatas; - DraggedAssetDatas.Add( Item->AssetData ); - FEditorDelegates::OnAssetDragStarted.Broadcast( DraggedAssetDatas, Item->Factory ); + if (FEditorDelegates::OnAssetDragStarted.IsBound()) + { + TArray DraggedAssetDatas; + DraggedAssetDatas.Add( Item->AssetData ); + FEditorDelegates::OnAssetDragStarted.Broadcast( DraggedAssetDatas, Item->Factory ); + return FReply::Handled(); + } if( MouseEvent.IsMouseButtonDown( EKeys::LeftMouseButton ) ) { diff --git a/Engine/Source/Editor/PlacementMode/Public/PlacementModeModule.h b/Engine/Source/Editor/PlacementMode/Public/PlacementModeModule.h new file mode 100644 index 000000000000..ab28f2c8eb04 --- /dev/null +++ b/Engine/Source/Editor/PlacementMode/Public/PlacementModeModule.h @@ -0,0 +1,159 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "IPlacementModeModule.h" + +#include "Framework/MultiBox/MultiBoxExtender.h" + +DECLARE_MULTICAST_DELEGATE_OneParam(FOnPlacementModeCategoryRefreshed, FName /*CategoryName*/) + +struct FPlacementCategory : FPlacementCategoryInfo +{ + FPlacementCategory(const FPlacementCategoryInfo& SourceInfo) + : FPlacementCategoryInfo(SourceInfo) + { + + } + + FPlacementCategory(FPlacementCategory&& In) + : FPlacementCategoryInfo(MoveTemp(In)) + , Items(MoveTemp(In.Items)) + {} + + FPlacementCategory& operator=(FPlacementCategory&& In) + { + FPlacementCategoryInfo::operator=(MoveTemp(In)); + Items = MoveTemp(In.Items); + return *this; + } + + TMap> Items; +}; + +static TOptional GetBasicShapeColorOverride(); + +class FPlacementModeModule : public IPlacementModeModule +{ +public: + + /** + * Called right after the module's DLL has been loaded and the module object has been created + */ + virtual void StartupModule() override; + + /** + * Called before the module is unloaded, right before the module object is destroyed. + */ + virtual void PreUnloadCallback() override; + + DECLARE_DERIVED_EVENT(FPlacementModeModule, IPlacementModeModule::FOnRecentlyPlacedChanged, FOnRecentlyPlacedChanged); + virtual FOnRecentlyPlacedChanged& OnRecentlyPlacedChanged() override { return RecentlyPlacedChanged; } + + DECLARE_DERIVED_EVENT(FPlacementModeModule, IPlacementModeModule::FOnAllPlaceableAssetsChanged, FOnAllPlaceableAssetsChanged); + virtual FOnAllPlaceableAssetsChanged& OnAllPlaceableAssetsChanged() override { return AllPlaceableAssetsChanged; } + + FOnPlacementModeCategoryRefreshed& OnPlacementModeCategoryRefreshed() { return PlacementModeCategoryRefreshed; } + + void BroadcastPlacementModeCategoryRefreshed(FName CategoryName) { PlacementModeCategoryRefreshed.Broadcast(CategoryName); } + + /** + * Add the specified assets to the recently placed items list + */ + virtual void AddToRecentlyPlaced(const TArray< UObject* >& PlacedObjects, UActorFactory* FactoryUsed = NULL) override; + + void OnAssetRemoved(const FAssetData& /*InRemovedAssetData*/); + + void OnAssetRenamed(const FAssetData& AssetData, const FString& OldObjectPath); + + void OnAssetAdded(const FAssetData& AssetData); + + /** + * Add the specified asset to the recently placed items list + */ + virtual void AddToRecentlyPlaced(UObject* Asset, UActorFactory* FactoryUsed = NULL) override; + + /** + * Get a copy of the recently placed items list + */ + virtual const TArray< FActorPlacementInfo >& GetRecentlyPlaced() const override + { + return RecentlyPlaced; + } + + /** @return the event that is broadcast whenever the placement mode enters a placing session */ + DECLARE_DERIVED_EVENT(FPlacementModeModule, IPlacementModeModule::FOnStartedPlacingEvent, FOnStartedPlacingEvent); + virtual FOnStartedPlacingEvent& OnStartedPlacing() override + { + return StartedPlacingEvent; + } + virtual void BroadcastStartedPlacing(const TArray< UObject* >& Assets) override + { + StartedPlacingEvent.Broadcast(Assets); + } + + /** @return the event that is broadcast whenever the placement mode exits a placing session */ + DECLARE_DERIVED_EVENT(FPlacementModeModule, IPlacementModeModule::FOnStoppedPlacingEvent, FOnStoppedPlacingEvent); + virtual FOnStoppedPlacingEvent& OnStoppedPlacing() override + { + return StoppedPlacingEvent; + } + virtual void BroadcastStoppedPlacing(bool bWasSuccessfullyPlaced) override + { + StoppedPlacingEvent.Broadcast(bWasSuccessfullyPlaced); + } + +public: + + virtual bool RegisterPlacementCategory(const FPlacementCategoryInfo& Info); + + virtual const FPlacementCategoryInfo* GetRegisteredPlacementCategory(FName CategoryName) const override + { + return Categories.Find(CategoryName); + } + + virtual void UnregisterPlacementCategory(FName Handle); + + virtual void GetSortedCategories(TArray& OutCategories) const; + + virtual TOptional RegisterPlaceableItem(FName CategoryName, const TSharedRef& InItem); + + virtual void UnregisterPlaceableItem(FPlacementModeID ID); + + virtual void GetItemsForCategory(FName CategoryName, TArray>& OutItems) const; + + virtual void GetFilteredItemsForCategory(FName CategoryName, TArray>& OutItems, TFunctionRef&)> Filter) const; + + virtual void RegenerateItemsForCategory(FName Category) override; + +private: + + void RefreshRecentlyPlaced(); + + void RefreshVolumes(); + + void RefreshAllPlaceableClasses(); + + FGuid CreateID(); + + FPlacementModeID CreateID(FName InCategory); + +private: + + TMap Categories; + + TArray< FActorPlacementInfo > RecentlyPlaced; + FOnRecentlyPlacedChanged RecentlyPlacedChanged; + + FOnAllPlaceableAssetsChanged AllPlaceableAssetsChanged; + FOnPlacementModeCategoryRefreshed PlacementModeCategoryRefreshed; + + FOnStartedPlacingEvent StartedPlacingEvent; + FOnStoppedPlacingEvent StoppedPlacingEvent; + + TArray< TSharedPtr > ContentPaletteFiltersExtenders; + TArray< TSharedPtr > PaletteExtenders; +}; + +IMPLEMENT_MODULE(FPlacementModeModule, PlacementMode); \ No newline at end of file diff --git a/Engine/Source/Editor/PluginWarden/PluginWarden.Build.cs b/Engine/Source/Editor/PluginWarden/PluginWarden.Build.cs index 31f23a5c247a..6d1b88a99001 100644 --- a/Engine/Source/Editor/PluginWarden/PluginWarden.Build.cs +++ b/Engine/Source/Editor/PluginWarden/PluginWarden.Build.cs @@ -17,13 +17,13 @@ public class PluginWarden : ModuleRules "Core", "CoreUObject", "Engine", - "InputCore", + "InputCore", "Slate", "SlateCore", - "EditorStyle", - "UnrealEd", - "PortalServices", - "DesktopPlatform", + "EditorStyle", + "UnrealEd", + "PortalServices", + "LauncherPlatform", } ); diff --git a/Engine/Source/Editor/PluginWarden/Private/SAuthorizingPlugin.cpp b/Engine/Source/Editor/PluginWarden/Private/SAuthorizingPlugin.cpp index 82d4e4a60d70..dfc3ba3aa8ef 100644 --- a/Engine/Source/Editor/PluginWarden/Private/SAuthorizingPlugin.cpp +++ b/Engine/Source/Editor/PluginWarden/Private/SAuthorizingPlugin.cpp @@ -11,13 +11,14 @@ #include "EditorStyleSet.h" #include "Editor.h" #include "Widgets/Images/SThrobber.h" -#include "IDesktopPlatform.h" -#include "DesktopPlatformModule.h" #include "IPortalServiceLocator.h" #include "Account/IPortalUserLogin.h" #include "Application/IPortalApplicationWindow.h" +#include "ILauncherPlatform.h" +#include "LauncherPlatformModule.h" + #define LOCTEXT_NAMESPACE "PluginWarden" void SAuthorizingPlugin::Construct(const FArguments& InArgs, const TSharedRef& InParentWindow, const FText& InPluginFriendlyName, const FString& InPluginItemId, const FString& InPluginOfferId, TFunction InAuthorizedCallback) @@ -138,15 +139,15 @@ EActiveTimerReturnType SAuthorizingPlugin::RefreshStatus(double InCurrentTime, f case EPluginAuthorizationState::StartLauncher: { WaitingTime = 0; - IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get(); + ILauncherPlatform* LauncherPlatform = FLauncherPlatformModule::Get(); - if ( DesktopPlatform != nullptr ) + if (LauncherPlatform != nullptr ) { if ( !FPlatformProcess::IsApplicationRunning(TEXT("EpicGamesLauncher")) && !FPlatformProcess::IsApplicationRunning(TEXT("EpicGamesLauncher-Mac-Shipping")) ) { FOpenLauncherOptions SilentOpen; - if ( DesktopPlatform->OpenLauncher(SilentOpen) ) + if (LauncherPlatform->OpenLauncher(SilentOpen) ) { CurrentState = EPluginAuthorizationState::StartLauncher_Waiting; } @@ -396,12 +397,12 @@ void SAuthorizingPlugin::OnWindowClosed(const TSharedRef& InWindow) void SAuthorizingPlugin::ShowStorePageForPlugin() { - IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get(); + ILauncherPlatform* LauncherPlatform = FLauncherPlatformModule::Get(); - if ( DesktopPlatform != nullptr ) + if (LauncherPlatform != nullptr ) { FOpenLauncherOptions StorePageOpen(FString(TEXT("/ue/marketplace/content/")) + PluginOfferId); - DesktopPlatform->OpenLauncher(StorePageOpen); + LauncherPlatform->OpenLauncher(StorePageOpen); } } diff --git a/Engine/Source/Editor/PropertyEditor/Private/DetailPropertyRow.cpp b/Engine/Source/Editor/PropertyEditor/Private/DetailPropertyRow.cpp index 180e7958acdb..b1df2b329fe6 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/DetailPropertyRow.cpp +++ b/Engine/Source/Editor/PropertyEditor/Private/DetailPropertyRow.cpp @@ -511,11 +511,22 @@ void FDetailPropertyRow::MakeValueWidget( FDetailWidgetRow& Row, const TSharedPt SNew( SHorizontalBox ) .IsEnabled( IsEnabledAttrib ); + TSharedPtr ResetButton = nullptr; + if (!PropertyHandle->HasMetaData(TEXT("NoResetToDefault"))) + { + SAssignNew(ResetButton, SResetToDefaultPropertyEditor, PropertyEditor->GetPropertyHandle()) + .IsEnabled(IsEnabledAttrib) + .CustomResetToDefault(CustomResetToDefault); + }; + + TSharedRef ResetWidget = ResetButton.IsValid() ? ResetButton.ToSharedRef() : SNullWidget::NullWidget; + + TSharedPtr PropertyValue; + if( InCustomRow.IsValid() ) { MinWidth = InCustomRow->ValueWidget.MinWidth; MaxWidth = InCustomRow->ValueWidget.MaxWidth; - ValueWidget->AddSlot() [ InCustomRow->ValueWidget.Widget @@ -523,15 +534,13 @@ void FDetailPropertyRow::MakeValueWidget( FDetailWidgetRow& Row, const TSharedPt } else { - TSharedPtr PropertyValue; - ValueWidget->AddSlot() .Padding( 0.0f, 0.0f, 4.0f, 0.0f ) [ SAssignNew( PropertyValue, SPropertyValueWidget, PropertyEditor, GetPropertyUtilities() ) .ShowPropertyButtons( false ) // We handle this ourselves + .OptionalResetWidget(ResetWidget) ]; - MinWidth = PropertyValue->GetMinDesiredWidth(); MaxWidth = PropertyValue->GetMaxDesiredWidth(); } @@ -568,17 +577,15 @@ void FDetailPropertyRow::MakeValueWidget( FDetailWidgetRow& Row, const TSharedPt ]; } - if (!PropertyHandle->HasMetaData(TEXT("NoResetToDefault"))) + if (PropertyValue.IsValid() && !PropertyValue->CreatedResetButton() && ResetButton.IsValid()) { ValueWidget->AddSlot() - .Padding( 2.0f, 0.0f ) + .Padding(4.0f, 0.0f) .AutoWidth() .VAlign(VAlign_Center) .HAlign(HAlign_Left) [ - SNew( SResetToDefaultPropertyEditor, PropertyEditor.ToSharedRef() ) - .IsEnabled( IsEnabledAttrib ) - .CustomResetToDefault(CustomResetToDefault) + ResetWidget ]; } } diff --git a/Engine/Source/Editor/PropertyEditor/Private/Presentation/PropertyEditor/PropertyEditor.cpp b/Engine/Source/Editor/PropertyEditor/Private/Presentation/PropertyEditor/PropertyEditor.cpp index bfb5c3976252..301084e61a4b 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/Presentation/PropertyEditor/PropertyEditor.cpp +++ b/Engine/Source/Editor/PropertyEditor/Private/Presentation/PropertyEditor/PropertyEditor.cpp @@ -779,7 +779,7 @@ void FPropertyEditor::SyncToObjectsInNode( const TWeakPtr< FPropertyNode >& Weak uint8* Address = ReadAddresses.GetAddress(AddrIndex); if( Address ) { - NodeProperty->ExportText_Direct(ObjectNames[AddrIndex], Address, Address, NULL, PPF_Localized ); + NodeProperty->ExportText_Direct(ObjectNames[AddrIndex], Address, Address, NULL, PPF_None ); } } diff --git a/Engine/Source/Editor/PropertyEditor/Private/PropertyCustomizationHelpers.cpp b/Engine/Source/Editor/PropertyEditor/Private/PropertyCustomizationHelpers.cpp index 9e140fcc962c..fe07a2c94810 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/PropertyCustomizationHelpers.cpp +++ b/Engine/Source/Editor/PropertyEditor/Private/PropertyCustomizationHelpers.cpp @@ -29,6 +29,7 @@ #include "Widgets/Input/SHyperlink.h" #include "Widgets/Layout/SWidgetSwitcher.h" #include "IDocumentation.h" +#include "SResetToDefaultPropertyEditor.h" #define LOCTEXT_NAMESPACE "PropertyCustomizationHelpers" @@ -403,6 +404,17 @@ void SObjectPropertyEntryBox::Construct( const FArguments& InArgs ) } } + TSharedPtr ResetButton = nullptr; + + if (PropertyHandle.IsValid() && !PropertyHandle->HasMetaData(TEXT("NoResetToDefault"))) + { + SAssignNew(ResetButton, SResetToDefaultPropertyEditor, PropertyHandle) + .IsEnabled(true) + .CustomResetToDefault(InArgs._CustomResetToDefault); + }; + + TSharedRef ResetWidget = ResetButton.IsValid() ? ResetButton.ToSharedRef() : SNullWidget::NullWidget; + ChildSlot [ SNew(SHorizontalBox) @@ -424,6 +436,10 @@ void SObjectPropertyEntryBox::Construct( const FArguments& InArgs ) .EnableContentPicker(InArgs._EnableContentPicker) .PropertyHandle(PropertyHandle) .ThumbnailSize(ThumbnailSize) + .ResetToDefaultSlot() + [ + ResetWidget + ] ] ]; } @@ -691,9 +707,10 @@ public: FOnGenerateWidgetsForMaterial InOnGenerateWidgetsForMaterial, FOnResetMaterialToDefaultClicked InOnResetToDefaultClicked, int32 InMultipleMaterialCount, - bool bShowUsedTextures) + bool bShowUsedTextures, + bool bDisplayCompactSize) { - return MakeShareable( new FMaterialItemView( Material, InOnMaterialChanged, InOnGenerateNameWidgetsForMaterial, InOnGenerateWidgetsForMaterial, InOnResetToDefaultClicked, InMultipleMaterialCount, bShowUsedTextures) ); + return MakeShareable( new FMaterialItemView( Material, InOnMaterialChanged, InOnGenerateNameWidgetsForMaterial, InOnGenerateWidgetsForMaterial, InOnResetToDefaultClicked, InMultipleMaterialCount, bShowUsedTextures, bDisplayCompactSize) ); } TSharedRef CreateNameContent() @@ -741,24 +758,38 @@ public: .OnSetObject(this, &FMaterialItemView::OnSetObject) .DisplayThumbnail(true) .ThumbnailPool(ThumbnailPool) + .ThumbnailSize(bDisplayCompactSize ? FIntPoint(48, 48) : FIntPoint(64, 64) ) + .DisplayCompactSize(bDisplayCompactSize) .CustomContentSlot() [ SNew( SBox ) .HAlign(HAlign_Left) [ - // Add a menu for displaying all textures - SNew( SComboButton ) - .OnGetMenuContent( this, &FMaterialItemView::OnGetTexturesMenuForMaterial ) - .VAlign( VAlign_Center ) - .ContentPadding(2) - .IsEnabled( this, &FMaterialItemView::IsTexturesMenuEnabled ) - .Visibility( bShowUsedTextures ? EVisibility::Visible : EVisibility::Hidden ) - .ButtonContent() + SNew(SHorizontalBox) + +SHorizontalBox::Slot() + .Padding(0.0f, 0.0f, 3.0f, 0.0f) + .AutoWidth() [ - SNew( STextBlock ) - .Font( IDetailLayoutBuilder::GetDetailFont() ) - .ToolTipText( LOCTEXT("ViewTexturesToolTip", "View the textures used by this material" ) ) - .Text( LOCTEXT("ViewTextures","Textures") ) + // Add a menu for displaying all textures + SNew( SComboButton ) + .OnGetMenuContent( this, &FMaterialItemView::OnGetTexturesMenuForMaterial ) + .VAlign( VAlign_Center ) + .ContentPadding(2) + .IsEnabled( this, &FMaterialItemView::IsTexturesMenuEnabled ) + .Visibility( bShowUsedTextures ? EVisibility::Visible : EVisibility::Hidden ) + .ButtonContent() + [ + SNew( STextBlock ) + .Font( IDetailLayoutBuilder::GetDetailFont() ) + .ToolTipText( LOCTEXT("ViewTexturesToolTip", "View the textures used by this material" ) ) + .Text( LOCTEXT("ViewTextures","Textures") ) + ] + ] + +SHorizontalBox::Slot() + .Padding(3.0f, 0.0f) + .FillWidth(1.0f) + [ + OnGenerateCustomMaterialWidgets.IsBound() && bDisplayCompactSize ? OnGenerateCustomMaterialWidgets.Execute(MaterialItem.Material.Get(), MaterialItem.SlotIndex) : StaticCastSharedRef(SNullWidget::NullWidget) ] ] ] @@ -786,7 +817,7 @@ public: .Padding(2) .VAlign( VAlign_Center ) [ - OnGenerateCustomMaterialWidgets.IsBound() ? OnGenerateCustomMaterialWidgets.Execute( MaterialItem.Material.Get(), MaterialItem.SlotIndex ) : StaticCastSharedRef( SNullWidget::NullWidget ) + OnGenerateCustomMaterialWidgets.IsBound() && !bDisplayCompactSize ? OnGenerateCustomMaterialWidgets.Execute( MaterialItem.Material.Get(), MaterialItem.SlotIndex ) : StaticCastSharedRef( SNullWidget::NullWidget ) ] ]; @@ -800,7 +831,8 @@ private: FOnGenerateWidgetsForMaterial& InOnGenerateMaterialWidgets, FOnResetMaterialToDefaultClicked& InOnResetToDefaultClicked, int32 InMultipleMaterialCount, - bool bInShowUsedTextures) + bool bInShowUsedTextures, + bool bInDisplayCompactSize) : MaterialItem( InMaterial ) , OnMaterialChanged( InOnMaterialChanged ) @@ -809,6 +841,7 @@ private: , OnResetToDefaultClicked( InOnResetToDefaultClicked ) , MultipleMaterialCount( InMultipleMaterialCount ) , bShowUsedTextures( bInShowUsedTextures ) + , bDisplayCompactSize(bInDisplayCompactSize) { } @@ -920,15 +953,17 @@ private: FOnResetMaterialToDefaultClicked OnResetToDefaultClicked; int32 MultipleMaterialCount; bool bShowUsedTextures; + bool bDisplayCompactSize; }; -FMaterialList::FMaterialList(IDetailLayoutBuilder& InDetailLayoutBuilder, FMaterialListDelegates& InMaterialListDelegates, bool bInAllowCollapse, bool bInShowUsedTextures) +FMaterialList::FMaterialList(IDetailLayoutBuilder& InDetailLayoutBuilder, FMaterialListDelegates& InMaterialListDelegates, bool bInAllowCollapse, bool bInShowUsedTextures, bool bInDisplayCompactSize) : MaterialListDelegates( InMaterialListDelegates ) , DetailLayoutBuilder( InDetailLayoutBuilder ) , MaterialListBuilder( new FMaterialListBuilder ) , bAllowCollpase(bInAllowCollapse) , bShowUsedTextures(bInShowUsedTextures) + , bDisplayCompactSize(bInDisplayCompactSize) { } @@ -1164,7 +1199,7 @@ void FMaterialList::AddMaterialItem( FDetailWidgetRow& Row, int32 CurrentSlot, c { uint32 NumMaterials = MaterialListBuilder->GetNumMaterialsInSlot(CurrentSlot); - TSharedRef NewView = FMaterialItemView::Create( Item, MaterialListDelegates.OnMaterialChanged, MaterialListDelegates.OnGenerateCustomNameWidgets, MaterialListDelegates.OnGenerateCustomMaterialWidgets, MaterialListDelegates.OnResetMaterialToDefaultClicked, NumMaterials, bShowUsedTextures ); + TSharedRef NewView = FMaterialItemView::Create( Item, MaterialListDelegates.OnMaterialChanged, MaterialListDelegates.OnGenerateCustomNameWidgets, MaterialListDelegates.OnGenerateCustomMaterialWidgets, MaterialListDelegates.OnResetMaterialToDefaultClicked, NumMaterials, bShowUsedTextures, bDisplayCompactSize); TSharedPtr RightSideContent; if( bDisplayLink ) @@ -1416,7 +1451,11 @@ class FSectionListBuilder : public ISectionListBuilder { friend class FSectionList; public: - + + FSectionListBuilder(int32 InThumbnailSize) + :ThumbnailSize(InThumbnailSize) + {} + /** * Adds a new Section to the list * @@ -1426,7 +1465,7 @@ public: */ virtual void AddSection(int32 LodIndex, int32 SectionIndex, FName InMaterialSlotName, int32 InMaterialSlotIndex, FName InOriginalMaterialSlotName, const TMap &InAvailableMaterialSlotName, const UMaterialInterface* Material, bool IsSectionUsingCloth) override { - FSectionListItem SectionItem(LodIndex, SectionIndex, InMaterialSlotName, InMaterialSlotIndex, InOriginalMaterialSlotName, InAvailableMaterialSlotName, Material, IsSectionUsingCloth); + FSectionListItem SectionItem(LodIndex, SectionIndex, InMaterialSlotName, InMaterialSlotIndex, InOriginalMaterialSlotName, InAvailableMaterialSlotName, Material, IsSectionUsingCloth, ThumbnailSize); if (!Sections.Contains(SectionItem)) { Sections.Add(SectionItem); @@ -1491,6 +1530,8 @@ private: TArray Sections; /** All Section items in the list */ TMap> SectionsByLOD; + + int32 ThumbnailSize; }; @@ -1512,9 +1553,10 @@ public: FOnGenerateWidgetsForSection InOnGenerateNameWidgetsForSection, FOnGenerateWidgetsForSection InOnGenerateWidgetsForSection, FOnResetSectionToDefaultClicked InOnResetToDefaultClicked, - int32 InMultipleSectionCount) + int32 InMultipleSectionCount, + int32 InThumbnailSize) { - return MakeShareable(new FSectionItemView(Section, InOnSectionChanged, InOnGenerateNameWidgetsForSection, InOnGenerateWidgetsForSection, InOnResetToDefaultClicked, InMultipleSectionCount)); + return MakeShareable(new FSectionItemView(Section, InOnSectionChanged, InOnGenerateNameWidgetsForSection, InOnGenerateWidgetsForSection, InOnResetToDefaultClicked, InMultipleSectionCount, InThumbnailSize)); } TSharedRef CreateNameContent() @@ -1544,6 +1586,7 @@ public: return SNew(SHorizontalBox) + SHorizontalBox::Slot() + .HAlign(HAlign_Fill) [ SNew(SVerticalBox) + SVerticalBox::Slot() @@ -1560,62 +1603,74 @@ public: .ObjectPath(SectionItem.Material->GetPathName()) .Class(UMaterialInterface::StaticClass()) .DisplayThumbnail(true) - .ThumbnailSize(FIntPoint(32,32)) + .ThumbnailSize(FIntPoint(ThumbnailSize, ThumbnailSize)) .DisplayUseSelected(false) .AllowClear(false) .DisplayBrowse(false) .EnableContentPicker(false) - .ThumbnailPool(ThumbnailPool) - ] - ] - + SVerticalBox::Slot() - .AutoHeight() - .Padding(2) - .VAlign(VAlign_Center) - [ - SNew(SHorizontalBox) - + SHorizontalBox::Slot() - .Padding(0) - .VAlign(VAlign_Center) - .AutoWidth() - [ - SNew(STextBlock) - .Font(IDetailLayoutBuilder::GetDetailFont()) - .Text(LOCTEXT("SectionListItemMaterialSlotNameLabel", "Material Slot")) - .ToolTipText(MaterialSlotNameTooltipText) - ] - + SHorizontalBox::Slot() - .VAlign(VAlign_Center) - .AutoWidth() - .Padding(5, 0, 0, 0) - [ - SNew(SBox) - .HAlign(HAlign_Left) - .VAlign(VAlign_Center) + .DisplayCompactSize(true) + .CustomContentSlot() [ - //Material Slot Name - SNew(SComboButton) - .OnGetMenuContent(this, &FSectionItemView::OnGetMaterialSlotNameMenuForSection) - .VAlign(VAlign_Center) - .ContentPadding(2) - .IsEnabled(!SectionItem.IsSectionUsingCloth) - .ButtonContent() + SNew( SBox ) + .HAlign(HAlign_Fill) [ - SNew(STextBlock) - .Font(IDetailLayoutBuilder::GetDetailFont()) - .Text(this, &FSectionItemView::GetCurrentMaterialSlotName) - .ToolTipText(MaterialSlotNameTooltipText) + SNew(SVerticalBox) + +SVerticalBox::Slot() + .AutoHeight() + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .Padding(0) + .VAlign(VAlign_Center) + .AutoWidth() + [ + SNew(SBox) + .HAlign(HAlign_Right) + .MinDesiredWidth(65.0f) + [ + SNew(STextBlock) + .Font(IDetailLayoutBuilder::GetDetailFont()) + .Text(LOCTEXT("SectionListItemMaterialSlotNameLabel", "Material Slot")) + .ToolTipText(MaterialSlotNameTooltipText) + ] + ] + + SHorizontalBox::Slot() + .VAlign(VAlign_Center) + .FillWidth(1.0f) + .Padding(5, 0, 0, 0) + [ + SNew(SBox) + .HAlign(HAlign_Fill) + .VAlign(VAlign_Center) + .MinDesiredWidth(210.0f) + [ + //Material Slot Name + SNew(SComboButton) + .OnGetMenuContent(this, &FSectionItemView::OnGetMaterialSlotNameMenuForSection) + .VAlign(VAlign_Center) + .ContentPadding(2) + .IsEnabled(!SectionItem.IsSectionUsingCloth) + .ButtonContent() + [ + SNew(STextBlock) + .Font(IDetailLayoutBuilder::GetDetailFont()) + .Text(this, &FSectionItemView::GetCurrentMaterialSlotName) + .ToolTipText(MaterialSlotNameTooltipText) + ] + ] + ] + ] + +SVerticalBox::Slot() + .AutoHeight() + .VAlign(VAlign_Center) + [ + OnGenerateCustomSectionWidgets.IsBound() ? OnGenerateCustomSectionWidgets.Execute(SectionItem.LodIndex, SectionItem.SectionIndex) : StaticCastSharedRef(SNullWidget::NullWidget) + ] ] ] ] ] - + SVerticalBox::Slot() - .AutoHeight() - .VAlign(VAlign_Center) - [ - OnGenerateCustomSectionWidgets.IsBound() ? OnGenerateCustomSectionWidgets.Execute(SectionItem.LodIndex, SectionItem.SectionIndex) : StaticCastSharedRef(SNullWidget::NullWidget) - ] ]; } @@ -1626,13 +1681,15 @@ private: FOnGenerateWidgetsForSection& InOnGenerateNameWidgets, FOnGenerateWidgetsForSection& InOnGenerateSectionWidgets, FOnResetSectionToDefaultClicked& InOnResetToDefaultClicked, - int32 InMultipleSectionCount) + int32 InMultipleSectionCount, + int32 InThumbnailSize) : SectionItem(InSection) , OnSectionChanged(InOnSectionChanged) , OnGenerateCustomNameWidgets(InOnGenerateNameWidgets) , OnGenerateCustomSectionWidgets(InOnGenerateSectionWidgets) , OnResetToDefaultClicked(InOnResetToDefaultClicked) , MultipleSectionCount(InMultipleSectionCount) + , ThumbnailSize(InThumbnailSize) { } @@ -1687,14 +1744,17 @@ private: FOnGenerateWidgetsForSection OnGenerateCustomSectionWidgets; FOnResetSectionToDefaultClicked OnResetToDefaultClicked; int32 MultipleSectionCount; + int32 ThumbnailSize; }; -FSectionList::FSectionList(IDetailLayoutBuilder& InDetailLayoutBuilder, FSectionListDelegates& InSectionListDelegates, bool bInAllowCollapse /*= false*/) +FSectionList::FSectionList(IDetailLayoutBuilder& InDetailLayoutBuilder, FSectionListDelegates& InSectionListDelegates, bool bInAllowCollapse, int32 InThumbnailSize, int32 InSectionsLodIndex) : SectionListDelegates(InSectionListDelegates) , DetailLayoutBuilder(InDetailLayoutBuilder) - , SectionListBuilder(new FSectionListBuilder) + , SectionListBuilder(new FSectionListBuilder(InThumbnailSize)) , bAllowCollpase(bInAllowCollapse) + , ThumbnailSize(InThumbnailSize) + , SectionsLodIndex(InSectionsLodIndex) { } @@ -1773,6 +1833,13 @@ void FSectionList::GenerateHeaderRowContent(FDetailWidgetRow& NodeRow) .Text(LOCTEXT("SectionHeaderTitle", "Sections")) .Font(IDetailLayoutBuilder::GetDetailFont()) ]; + if (SectionListDelegates.OnGenerateLodComboBox.IsBound()) + { + NodeRow.ValueContent() + [ + SectionListDelegates.OnGenerateLodComboBox.Execute(SectionsLodIndex) + ]; + } } void FSectionList::GenerateChildContent(IDetailChildrenBuilder& ChildrenBuilder) @@ -1798,7 +1865,7 @@ void FSectionList::GenerateChildContent(IDetailChildrenBuilder& ChildrenBuilder) if (bDisplayAllSectionsInSlot) { FDetailWidgetRow& ChildRow = ChildrenBuilder.AddChildContent(Section.Material.IsValid() ? FText::FromString(Section.Material->GetName()) : FText::GetEmpty()); - AddSectionItem(ChildRow, CurrentLODIndex, FSectionListItem(CurrentLODIndex, Section.SectionIndex, Section.MaterialSlotName, Section.MaterialSlotIndex, Section.OriginalMaterialSlotName, Section.AvailableMaterialSlotName, Section.Material.Get(), Section.IsSectionUsingCloth), !bDisplayAllSectionsInSlot); + AddSectionItem(ChildRow, CurrentLODIndex, FSectionListItem(CurrentLODIndex, Section.SectionIndex, Section.MaterialSlotName, Section.MaterialSlotIndex, Section.OriginalMaterialSlotName, Section.AvailableMaterialSlotName, Section.Material.Get(), Section.IsSectionUsingCloth, ThumbnailSize), !bDisplayAllSectionsInSlot); } } } @@ -1875,7 +1942,7 @@ void FSectionList::AddSectionItem(FDetailWidgetRow& Row, int32 LodIndex, const s { uint32 NumSections = SectionListBuilder->GetNumSections(LodIndex); - TSharedRef NewView = FSectionItemView::Create(Item, SectionListDelegates.OnSectionChanged, SectionListDelegates.OnGenerateCustomNameWidgets, SectionListDelegates.OnGenerateCustomSectionWidgets, SectionListDelegates.OnResetSectionToDefaultClicked, NumSections); + TSharedRef NewView = FSectionItemView::Create(Item, SectionListDelegates.OnSectionChanged, SectionListDelegates.OnGenerateCustomNameWidgets, SectionListDelegates.OnGenerateCustomSectionWidgets, SectionListDelegates.OnResetSectionToDefaultClicked, NumSections, ThumbnailSize); TSharedPtr RightSideContent; if (bDisplayLink) @@ -1927,11 +1994,6 @@ void SMaterialSlotWidget::Construct(const FArguments& InArgs, int32 SlotIndex, b LOCTEXT("CustomNameMaterialNotUsedDeleteTooltip", "Delete this material slot"), InArgs._CanDeleteMaterialSlot); - if(bIsMaterialUsed) - { - DeleteButton->SetVisibility(EVisibility::Hidden); - } - ChildSlot [ SAssignNew(SlotNameBox, SHorizontalBox) @@ -1942,22 +2004,20 @@ void SMaterialSlotWidget::Construct(const FArguments& InArgs, int32 SlotIndex, b [ SNew(SBox) .VAlign(VAlign_Center) - // Match the size of the thumbnail - .MinDesiredWidth(64.0f) [ SNew(STextBlock) .Font(IDetailLayoutBuilder::GetDetailFont()) - .Text(LOCTEXT("MaterialArrayNameLabelStringKey", "Slot name")) + .Text(LOCTEXT("MaterialArrayNameLabelStringKey", "Slot Name")) ] ] + SHorizontalBox::Slot() - .VAlign(VAlign_Center) - .AutoWidth() - .Padding(12.0f, 3.0f, 0.0f, 3.0f) + .FillWidth(1.0f) + .Padding(5.0f, 3.0f, 0.0f, 3.0f) [ SNew(SBox) .VAlign(VAlign_Center) - .MinDesiredWidth(125.0f) + .HAlign(HAlign_Fill) + .MinDesiredWidth(160.0f) [ SNew(SEditableTextBox) .Text(InArgs._MaterialName) @@ -1968,6 +2028,13 @@ void SMaterialSlotWidget::Construct(const FArguments& InArgs, int32 SlotIndex, b ] ]; + + if (bIsMaterialUsed) + { + DeleteButton->SetVisibility(EVisibility::Hidden); + } + + SlotNameBox->AddSlot() .AutoWidth() .VAlign(VAlign_Center) diff --git a/Engine/Source/Editor/PropertyEditor/Private/PropertyEditorHelpers.cpp b/Engine/Source/Editor/PropertyEditor/Private/PropertyEditorHelpers.cpp index 96f745561644..645ccbf7916b 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/PropertyEditorHelpers.cpp +++ b/Engine/Source/Editor/PropertyEditor/Private/PropertyEditorHelpers.cpp @@ -63,7 +63,7 @@ void SPropertyNameWidget::Construct( const FArguments& InArgs, TSharedPtrGetPropertyHandle()) ]; } } @@ -73,10 +73,11 @@ void SPropertyValueWidget::Construct( const FArguments& InArgs, TSharedPtr( PropertyEditor.ToSharedRef(), &FPropertyEditor::IsPropertyEditingEnabled ) ); - ValueEditorWidget = ConstructPropertyEditorWidget( PropertyEditor, InPropertyUtilities ); + ValueEditorWidget = ConstructPropertyEditorWidget( PropertyEditor, InPropertyUtilities, InArgs._OptionalResetWidget ); if ( !ValueEditorWidget->GetToolTip().IsValid() ) { @@ -128,7 +129,7 @@ void SPropertyValueWidget::Construct( const FArguments& InArgs, TSharedPtr SPropertyValueWidget::ConstructPropertyEditorWidget( TSharedPtr& PropertyEditor, TSharedPtr InPropertyUtilities ) +TSharedRef SPropertyValueWidget::ConstructPropertyEditorWidget( TSharedPtr& PropertyEditor, TSharedPtr InPropertyUtilities, TSharedRef InResetDefaultWidget) { const TSharedRef PropertyEditorRef = PropertyEditor.ToSharedRef(); const TSharedRef PropertyUtilitiesRef = InPropertyUtilities.ToSharedRef(); @@ -170,8 +171,15 @@ TSharedRef SPropertyValueWidget::ConstructPropertyEditorWidget( TShared { TSharedRef AssetWidget = SAssignNew( PropertyWidget, SPropertyEditorAsset, PropertyEditorRef ) - .ThumbnailPool( PropertyUtilitiesRef->GetThumbnailPool() ); - + .ThumbnailPool( PropertyUtilitiesRef->GetThumbnailPool() ) + .ResetToDefaultSlot() + [ + InResetDefaultWidget + ]; + if (InResetDefaultWidget != SNullWidget::NullWidget) + { + bCreatedResetButton = true; + } AssetWidget->GetDesiredWidth( MinDesiredWidth, MaxDesiredWidth ); } else if ( SPropertyEditorClass::Supports( PropertyEditorRef ) ) diff --git a/Engine/Source/Editor/PropertyEditor/Private/PropertyEditorHelpers.h b/Engine/Source/Editor/PropertyEditor/Private/PropertyEditorHelpers.h index 43d52529e971..9c680adbc6c1 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/PropertyEditorHelpers.h +++ b/Engine/Source/Editor/PropertyEditor/Private/PropertyEditorHelpers.h @@ -58,9 +58,11 @@ class SPropertyValueWidget : public SCompoundWidget { public: SLATE_BEGIN_ARGS( SPropertyValueWidget ) - : _ShowPropertyButtons( true ) + : _ShowPropertyButtons( true ), + _OptionalResetWidget(SNullWidget::NullWidget) {} SLATE_ARGUMENT( bool, ShowPropertyButtons ) + SLATE_ARGUMENT( TSharedRef, OptionalResetWidget) SLATE_END_ARGS() void Construct( const FArguments& InArgs, TSharedPtr InPropertyEditor, TSharedPtr InPropertyUtilities ); @@ -71,14 +73,19 @@ public: /** @return The maximum desired with if this property value */ float GetMaxDesiredWidth() const { return MaxDesiredWidth; } + /** @return Whether this widget handles its own reset button */ + bool CreatedResetButton() const { return bCreatedResetButton; } + private: - TSharedRef ConstructPropertyEditorWidget( TSharedPtr& PropertyEditor, TSharedPtr InPropertyUtilities ); + TSharedRef ConstructPropertyEditorWidget( TSharedPtr& PropertyEditor, TSharedPtr InPropertyUtilities, TSharedRef InOptionalResetDefaultWidget = SNullWidget::NullWidget); private: TSharedPtr< SWidget > ValueEditorWidget; /** The minimum desired with if this property value */ float MinDesiredWidth; /** The maximum desired with if this property value */ float MaxDesiredWidth; + /** Whether or not this value widget handled its own reset button */ + bool bCreatedResetButton; }; diff --git a/Engine/Source/Editor/PropertyEditor/Private/PropertyHandleImpl.cpp b/Engine/Source/Editor/PropertyEditor/Private/PropertyHandleImpl.cpp index 103ede54f117..a2a089bf8144 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/PropertyHandleImpl.cpp +++ b/Engine/Source/Editor/PropertyEditor/Private/PropertyHandleImpl.cpp @@ -22,6 +22,7 @@ #include "Framework/Notifications/NotificationManager.h" #include "Widgets/Notifications/SNotificationList.h" #include "EnumProperty.h" +#include "IDetailPropertyRow.h" #define LOCTEXT_NAMESPACE "PropertyHandleImplementation" @@ -272,11 +273,11 @@ FString FPropertyValueImpl::GetPropertyValueArray() const { String = FString::Printf( TEXT("%(%d)"), FScriptArrayHelper::Num(Addr) ); } - else if ( NodeProperty != nullptr && Cast(NodeProperty) != nullptr ) + else if ( Cast(NodeProperty) != nullptr ) { String = FString::Printf( TEXT("%(%d)"), FScriptSetHelper::Num(Addr) ); } - else if (NodeProperty != nullptr && Cast(NodeProperty) != nullptr) + else if (Cast(NodeProperty) != nullptr) { String = FString::Printf(TEXT("%(%d)"), FScriptMapHelper::Num(Addr)); } @@ -2218,6 +2219,20 @@ TSharedPtr FPropertyHandleBase::GetPropertyNode() const return Implementation->GetPropertyNode(); } +void FPropertyHandleBase::OnCustomResetToDefault(const FResetToDefaultOverride& OnCustomResetToDefault) +{ + if (OnCustomResetToDefault.OnResetToDefaultClicked().IsBound()) + { + Implementation->GetPropertyNode()->NotifyPreChange(Implementation->GetPropertyNode()->GetProperty(), Implementation->GetPropertyUtilities()->GetNotifyHook()); + + OnCustomResetToDefault.OnResetToDefaultClicked().Execute(SharedThis(this)); + + // Call PostEditchange on all the objects + FPropertyChangedEvent ChangeEvent(Implementation->GetPropertyNode()->GetProperty()); + Implementation->GetPropertyNode()->NotifyPostChange(ChangeEvent, Implementation->GetPropertyUtilities()->GetNotifyHook()); + } +} + int32 FPropertyHandleBase::GetIndexInArray() const { if( Implementation->GetPropertyNode().IsValid() ) @@ -2793,6 +2808,23 @@ TArray> FPropertyHandleBase::AddChildStructure( TSha return PropertyHandles; } +bool FPropertyHandleBase::IsResetToDefaultAvailable() +{ + UProperty* Property = GetProperty(); + + // Should not be able to reset fixed size arrays + const bool bFixedSized = Property && Property->PropertyFlags & CPF_EditFixedSize; + const bool bCanResetToDefault = !(Property && Property->PropertyFlags & CPF_Config); + + return Property && bCanResetToDefault && !bFixedSized && DiffersFromDefault(); +} + +void FPropertyHandleBase::CustomResetToDefault(const FResetToDefaultOverride& InOnCustomResetToDefault) +{ + // This action must be deferred until next tick so that we avoid accessing invalid data before we have a chance to tick + Implementation->GetPropertyUtilities()->EnqueueDeferredAction(FSimpleDelegate::CreateLambda([this, InOnCustomResetToDefault]() { OnCustomResetToDefault(InOnCustomResetToDefault); })); +} + /** Implements common property value functions */ #define IMPLEMENT_PROPERTY_VALUE( ClassName ) \ ClassName::ClassName( TSharedRef PropertyNode, FNotifyHook* NotifyHook, TSharedPtr PropertyUtilities ) \ diff --git a/Engine/Source/Editor/PropertyEditor/Private/PropertyHandleImpl.h b/Engine/Source/Editor/PropertyEditor/Private/PropertyHandleImpl.h index a7fde7a95e72..0ca8ab709039 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/PropertyHandleImpl.h +++ b/Engine/Source/Editor/PropertyEditor/Private/PropertyHandleImpl.h @@ -490,8 +490,11 @@ public: virtual bool GenerateRestrictionToolTip(const FString& Value, FText& OutTooltip) const override; virtual void SetIgnoreValidation(bool bInIgnore) override; virtual TArray> AddChildStructure( TSharedRef ChildStructure ) override; + virtual bool IsResetToDefaultAvailable() override; + virtual void CustomResetToDefault(const FResetToDefaultOverride& InOnCustomResetToDefault) override; TSharedPtr GetPropertyNode() const; + void OnCustomResetToDefault(const FResetToDefaultOverride& OnCustomResetToDefault); protected: TSharedPtr Implementation; }; @@ -629,7 +632,7 @@ private: }; -class FPropertyHandleArray : public FPropertyHandleBase, public IPropertyHandleArray, public TSharedFromThis +class FPropertyHandleArray : public FPropertyHandleBase, public IPropertyHandleArray { public: FPropertyHandleArray( TSharedRef PropertyNode, FNotifyHook* NotifyHook, TSharedPtr PropertyUtilities ); @@ -663,7 +666,7 @@ public: virtual FPropertyAccess::Result SetValue(const FString& InValue, EPropertyValueSetFlags::Type Flags = EPropertyValueSetFlags::DefaultFlags) override; }; -class FPropertyHandleSet : public FPropertyHandleBase, public IPropertyHandleSet, public TSharedFromThis +class FPropertyHandleSet : public FPropertyHandleBase, public IPropertyHandleSet { public: FPropertyHandleSet(TSharedRef PropertyNode, FNotifyHook* NotifyHook, TSharedPtr PropertyUtilities); @@ -687,7 +690,7 @@ private: bool IsEditable() const; }; -class FPropertyHandleMap : public FPropertyHandleBase, public IPropertyHandleMap, public TSharedFromThis +class FPropertyHandleMap : public FPropertyHandleBase, public IPropertyHandleMap { public: FPropertyHandleMap(TSharedRef PropertyNode, FNotifyHook* NotifyHook, TSharedPtr PropertyUtilities); diff --git a/Engine/Source/Editor/PropertyEditor/Private/PropertyNode.cpp b/Engine/Source/Editor/PropertyEditor/Private/PropertyNode.cpp index b8b4e6a873ee..b4641b23868e 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/PropertyNode.cpp +++ b/Engine/Source/Editor/PropertyEditor/Private/PropertyNode.cpp @@ -2707,7 +2707,7 @@ void FPropertyNode::PropagateContainerPropertyChange( UObject* ModifiedObject, c } FString OriginalContent; - ConvertedProperty->ExportText_Direct(OriginalContent, Addr, Addr, NULL, PPF_Localized); + ConvertedProperty->ExportText_Direct(OriginalContent, Addr, Addr, NULL, PPF_None); bool bIsDefaultContainerContent = OriginalContent == OriginalContainerContent; diff --git a/Engine/Source/Editor/PropertyEditor/Private/SDetailSingleItemRow.cpp b/Engine/Source/Editor/PropertyEditor/Private/SDetailSingleItemRow.cpp index 54ec7c2d3643..9a88e3a6ef80 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/SDetailSingleItemRow.cpp +++ b/Engine/Source/Editor/PropertyEditor/Private/SDetailSingleItemRow.cpp @@ -490,6 +490,12 @@ bool SDetailSingleItemRow::CanPasteProperty() const const FSlateBrush* SDetailSingleItemRow::GetBorderImage() const { + /*bool UseDarkTheme = false; + if (Customization->GetWidgetRow().IsDarkThemeAttr.IsSet()) + { + UseDarkTheme = Customization->GetWidgetRow().IsDarkThemeAttr.Get(); + }*/ + if( IsHighlighted() ) { return FEditorStyle::GetBrush("DetailsView.CategoryMiddle_Highlighted"); diff --git a/Engine/Source/Editor/PropertyEditor/Private/SSingleProperty.cpp b/Engine/Source/Editor/PropertyEditor/Private/SSingleProperty.cpp index 68bdeaccdb5d..31b6bb697934 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/SSingleProperty.cpp +++ b/Engine/Source/Editor/PropertyEditor/Private/SSingleProperty.cpp @@ -181,7 +181,7 @@ void SSingleProperty::SetObject( UObject* InObject ) .AutoWidth() .VAlign( VAlign_Center ) [ - SNew( SResetToDefaultPropertyEditor, PropertyEditor ) + SNew( SResetToDefaultPropertyEditor, PropertyEditor->GetPropertyHandle() ) ]; } } diff --git a/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyEditor/SPropertyEditorAsset.cpp b/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyEditor/SPropertyEditorAsset.cpp index 2c539f3c3828..ed6a43e8477c 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyEditor/SPropertyEditorAsset.cpp +++ b/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyEditor/SPropertyEditorAsset.cpp @@ -76,6 +76,7 @@ void SPropertyEditorAsset::Construct( const FArguments& InArgs, const TSharedPtr PropertyHandle = InArgs._PropertyHandle; OnSetObject = InArgs._OnSetObject; OnShouldFilterAsset = InArgs._OnShouldFilterAsset; + bool DisplayCompactedSize = InArgs._DisplayCompactSize; UProperty* Property = nullptr; if(PropertyEditor.IsValid()) @@ -289,29 +290,62 @@ void SPropertyEditorAsset::Construct( const FArguments& InArgs, const TSharedPtr ] ]; - - ValueContentBox->AddSlot() - [ - SNew( SBox ) - .VAlign( VAlign_Center ) + if(DisplayCompactedSize) + { + ValueContentBox->AddSlot() [ - SAssignNew( CustomContentBox, SVerticalBox ) - + SVerticalBox::Slot() - .Padding(0.0f, 4.0f, 0.0f, 0.0f) + SNew( SBox ) + .VAlign( VAlign_Center ) [ - AssetComboButton.ToSharedRef() - ] - + SVerticalBox::Slot() - .AutoHeight() - [ - SAssignNew(ButtonBoxWrapper, SBox) - .Padding( FMargin( 0.0f, 2.0f, 4.0f, 2.0f ) ) + SAssignNew( CustomContentBox, SVerticalBox ) + + SVerticalBox::Slot() + .AutoHeight() + .Padding(0.0f, 4.0f, 0.0f, 0.0f) [ - ButtonBox + SNew(SHorizontalBox) + +SHorizontalBox::Slot() + .FillWidth(1.0f) + [ + AssetComboButton.ToSharedRef() + ] + + SHorizontalBox::Slot() + .AutoWidth() + [ + SAssignNew(ButtonBoxWrapper, SBox) + .Padding(FMargin(0.0f, 2.0f, 4.0f, 2.0f)) + [ + ButtonBox + ] + ] ] ] - ] - ]; + ]; + } + else + { + ValueContentBox->AddSlot() + [ + SNew( SBox ) + .VAlign( VAlign_Center ) + [ + SAssignNew( CustomContentBox, SVerticalBox ) + + SVerticalBox::Slot() + .Padding(0.0f, 4.0f, 0.0f, 0.0f) + [ + AssetComboButton.ToSharedRef() + ] + + SVerticalBox::Slot() + .AutoHeight() + [ + SAssignNew(ButtonBoxWrapper, SBox) + .Padding( FMargin( 0.0f, 2.0f, 4.0f, 2.0f ) ) + [ + ButtonBox + ] + ] + ] + ]; + } } else { diff --git a/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyEditor/SPropertyEditorAsset.h b/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyEditor/SPropertyEditorAsset.h index 2a836cdf79f0..a9814c2a1e77 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyEditor/SPropertyEditorAsset.h +++ b/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyEditor/SPropertyEditorAsset.h @@ -37,6 +37,7 @@ public: , _DisplayUseSelected(true) , _DisplayBrowse(true) , _EnableContentPicker(true) + , _DisplayCompactSize(false) , _ThumbnailPool(NULL) , _ThumbnailSize( FIntPoint(64, 64) ) , _ObjectPath() @@ -51,6 +52,7 @@ public: SLATE_ARGUMENT( bool, DisplayUseSelected ) SLATE_ARGUMENT( bool, DisplayBrowse ) SLATE_ARGUMENT( bool, EnableContentPicker) + SLATE_ARGUMENT( bool, DisplayCompactSize) SLATE_ARGUMENT( TSharedPtr, ThumbnailPool ) SLATE_ARGUMENT( FIntPoint, ThumbnailSize ) SLATE_ATTRIBUTE( FString, ObjectPath ) diff --git a/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyEditor/SPropertyEditorColor.cpp b/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyEditor/SPropertyEditorColor.cpp index ee10f6c5e090..b5dc19c79c3e 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyEditor/SPropertyEditorColor.cpp +++ b/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyEditor/SPropertyEditorColor.cpp @@ -89,8 +89,10 @@ EVisibility SPropertyEditorColor::GetVisibilityForOpaqueDisplay() const { OpaqueDisplayVisibility = EVisibility::Collapsed; } - - OpaqueDisplayVisibility = EVisibility::Visible; + else + { + OpaqueDisplayVisibility = EVisibility::Visible; + } } return OpaqueDisplayVisibility; diff --git a/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyEditor/SPropertyMenuAssetPicker.cpp b/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyEditor/SPropertyMenuAssetPicker.cpp index 3ca1a0fff3fe..fc09e0b801cc 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyEditor/SPropertyMenuAssetPicker.cpp +++ b/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyEditor/SPropertyMenuAssetPicker.cpp @@ -260,7 +260,7 @@ void SPropertyMenuAssetPicker::OnCreateNewAssetSelected(TWeakObjectPtr { UFactory* FactoryInstance = DuplicateObject(FactoryPtr.Get(), GetTransientPackage()); FAssetToolsModule& AssetToolsModule = FAssetToolsModule::GetModule(); - UObject* NewAsset = AssetToolsModule.Get().CreateAsset(FactoryInstance->GetSupportedClass(), FactoryInstance); + UObject* NewAsset = AssetToolsModule.Get().CreateAssetWithDialog(FactoryInstance->GetSupportedClass(), FactoryInstance); if (NewAsset != nullptr) { SetValue(NewAsset); diff --git a/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyEditor/SResetToDefaultPropertyEditor.cpp b/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyEditor/SResetToDefaultPropertyEditor.cpp index 946f8b77ce60..2a26e689999e 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyEditor/SResetToDefaultPropertyEditor.cpp +++ b/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyEditor/SResetToDefaultPropertyEditor.cpp @@ -5,9 +5,9 @@ #define LOCTEXT_NAMESPACE "ResetToDefaultPropertyEditor" -void SResetToDefaultPropertyEditor::Construct( const FArguments& InArgs, const TSharedRef& InPropertyEditor ) +void SResetToDefaultPropertyEditor::Construct( const FArguments& InArgs, const TSharedPtr& InPropertyHandle ) { - PropertyEditor = InPropertyEditor; + PropertyHandle = InPropertyHandle; NonVisibleState = InArgs._NonVisibleState; bValueDiffersFromDefault = false; OptionalCustomResetToDefault = InArgs._CustomResetToDefault; @@ -53,7 +53,7 @@ void SResetToDefaultPropertyEditor::Construct( const FArguments& InArgs, const T UpdateDiffersFromDefaultState(); } -void SResetToDefaultPropertyEditor::Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime ) +void SResetToDefaultPropertyEditor::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) { UpdateDiffersFromDefaultState(); } @@ -63,9 +63,9 @@ FText SResetToDefaultPropertyEditor::GetResetToolTip() const FString Tooltip; Tooltip = NSLOCTEXT("PropertyEditor", "ResetToDefaultToolTip", "Reset to Default").ToString(); - if( !PropertyEditor->IsEditConst() && PropertyEditor->ValueDiffersFromDefault() ) + if( PropertyHandle.IsValid() && !PropertyHandle->IsEditConst() && PropertyHandle->DiffersFromDefault() ) { - FString DefaultLabel = PropertyEditor->GetResetToDefaultLabel().ToString(); + FString DefaultLabel = PropertyHandle->GetResetToDefaultLabel().ToString(); if (DefaultLabel.Len() > 0) { @@ -79,27 +79,34 @@ FText SResetToDefaultPropertyEditor::GetResetToolTip() const FReply SResetToDefaultPropertyEditor::OnDefaultResetClicked() { - PropertyEditor->ResetToDefault(); - + if (PropertyHandle.IsValid()) + { + PropertyHandle->ResetToDefault(); + } return FReply::Handled(); } FReply SResetToDefaultPropertyEditor::OnCustomResetClicked() { - PropertyEditor->CustomResetToDefault(OptionalCustomResetToDefault.GetValue()); - + if (PropertyHandle.IsValid()) + { + PropertyHandle->CustomResetToDefault(OptionalCustomResetToDefault.GetValue()); + } return FReply::Handled(); } void SResetToDefaultPropertyEditor::UpdateDiffersFromDefaultState() { - if(OptionalCustomResetToDefault.IsSet()) + if (PropertyHandle.IsValid()) { - bValueDiffersFromDefault = OptionalCustomResetToDefault.GetValue().IsResetToDefaultVisible(PropertyEditor->GetPropertyHandle()); - } - else - { - bValueDiffersFromDefault = PropertyEditor->IsResetToDefaultAvailable(); + if (OptionalCustomResetToDefault.IsSet()) + { + bValueDiffersFromDefault = OptionalCustomResetToDefault.GetValue().IsResetToDefaultVisible(PropertyHandle.ToSharedRef()); + } + else + { + bValueDiffersFromDefault = PropertyHandle->IsResetToDefaultAvailable(); + } } } diff --git a/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyEditor/SResetToDefaultPropertyEditor.h b/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyEditor/SResetToDefaultPropertyEditor.h index eef8652fd3b8..aa558c696cc9 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyEditor/SResetToDefaultPropertyEditor.h +++ b/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyEditor/SResetToDefaultPropertyEditor.h @@ -25,8 +25,7 @@ public: SLATE_ARGUMENT(TOptional, CustomResetToDefault) SLATE_END_ARGS() - void Construct( const FArguments& InArgs, const TSharedRef< class FPropertyEditor>& InPropertyEditor ); - + void Construct( const FArguments& InArgs, const TSharedPtr< class IPropertyHandle>& InPropertyHandle ); private: FText GetResetToolTip() const; @@ -42,7 +41,7 @@ private: private: TOptional OptionalCustomResetToDefault; - TSharedPtr< class FPropertyEditor > PropertyEditor; + TSharedPtr< class IPropertyHandle > PropertyHandle; EVisibility NonVisibleState; diff --git a/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyTable/BooleanPropertyTableCellPresenter.cpp b/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyTable/BooleanPropertyTableCellPresenter.cpp index 200824451929..effc9651c36d 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyTable/BooleanPropertyTableCellPresenter.cpp +++ b/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyTable/BooleanPropertyTableCellPresenter.cpp @@ -52,7 +52,7 @@ TSharedRef< class SWidget > FBooleanPropertyTableCellPresenter::ConstructDisplay .HAlign(HAlign_Center) .Padding(FMargin(0, 0, 2, 0)) [ - SNew(SResetToDefaultPropertyEditor, PropertyEditor) + SNew(SResetToDefaultPropertyEditor, PropertyEditor->GetPropertyHandle()) ]; } diff --git a/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyTable/ColorPropertyTableCellPresenter.cpp b/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyTable/ColorPropertyTableCellPresenter.cpp index 741343ac8b53..bba9cf56d3e4 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyTable/ColorPropertyTableCellPresenter.cpp +++ b/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyTable/ColorPropertyTableCellPresenter.cpp @@ -44,7 +44,7 @@ TSharedRef< class SWidget > FColorPropertyTableCellPresenter::ConstructDisplayWi .HAlign( HAlign_Center ) .Padding( FMargin( 0, 0, 2, 0 ) ) [ - SNew( SResetToDefaultPropertyEditor, PropertyEditor ) + SNew( SResetToDefaultPropertyEditor, PropertyEditor->GetPropertyHandle() ) ]; } diff --git a/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyTable/TextPropertyTableCellPresenter.cpp b/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyTable/TextPropertyTableCellPresenter.cpp index f3294ef288f6..a8ef2e648cc2 100644 --- a/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyTable/TextPropertyTableCellPresenter.cpp +++ b/Engine/Source/Editor/PropertyEditor/Private/UserInterface/PropertyTable/TextPropertyTableCellPresenter.cpp @@ -51,7 +51,7 @@ TSharedRef< class SWidget > FTextPropertyTableCellPresenter::ConstructDisplayWid .VAlign(VAlign_Center) .Padding(FMargin(0, 0, 2, 0)) [ - SNew(SResetToDefaultPropertyEditor, PropertyEditor) + SNew(SResetToDefaultPropertyEditor, PropertyEditor->GetPropertyHandle()) ]; } diff --git a/Engine/Source/Editor/PropertyEditor/Public/IPropertyTableCell.h b/Engine/Source/Editor/PropertyEditor/Public/IPropertyTableCell.h index 5059739f9958..6e7af57b69c1 100644 --- a/Engine/Source/Editor/PropertyEditor/Public/IPropertyTableCell.h +++ b/Engine/Source/Editor/PropertyEditor/Public/IPropertyTableCell.h @@ -8,6 +8,7 @@ class IPropertyTableCell { public: + virtual ~IPropertyTableCell() { } virtual void Refresh() = 0; diff --git a/Engine/Source/Editor/PropertyEditor/Public/IPropertyTableCellPresenter.h b/Engine/Source/Editor/PropertyEditor/Public/IPropertyTableCellPresenter.h index 0edc5422f036..6009485775f9 100644 --- a/Engine/Source/Editor/PropertyEditor/Public/IPropertyTableCellPresenter.h +++ b/Engine/Source/Editor/PropertyEditor/Public/IPropertyTableCellPresenter.h @@ -6,6 +6,7 @@ class IPropertyTableCellPresenter { public: + virtual ~IPropertyTableCellPresenter() { } virtual TSharedRef< class SWidget > ConstructDisplayWidget() = 0; diff --git a/Engine/Source/Editor/PropertyEditor/Public/PropertyCustomizationHelpers.h b/Engine/Source/Editor/PropertyEditor/Public/PropertyCustomizationHelpers.h index 201d7af8ffb4..4c22b1a13be9 100644 --- a/Engine/Source/Editor/PropertyEditor/Public/PropertyCustomizationHelpers.h +++ b/Engine/Source/Editor/PropertyEditor/Public/PropertyCustomizationHelpers.h @@ -18,6 +18,7 @@ #include "SResetToDefaultMenu.h" #include "ActorPickerMode.h" #include "SceneDepthPickerMode.h" +#include "IDetailPropertyRow.h" class AActor; class FAssetData; @@ -133,6 +134,8 @@ public: SLATE_ARGUMENT(bool, DisplayBrowse) /** Whether to enable the content Picker */ SLATE_ARGUMENT(bool, EnableContentPicker) + /** A custom reset to default override */ + SLATE_ARGUMENT(TOptional, CustomResetToDefault) SLATE_END_ARGS() PROPERTYEDITOR_API void Construct( const FArguments& InArgs ); @@ -519,7 +522,7 @@ class FMaterialList , public TSharedFromThis { public: - PROPERTYEDITOR_API FMaterialList( IDetailLayoutBuilder& InDetailLayoutBuilder, FMaterialListDelegates& MaterialListDelegates, bool bInAllowCollapse = false, bool bInShowUsedTextures = true); + PROPERTYEDITOR_API FMaterialList( IDetailLayoutBuilder& InDetailLayoutBuilder, FMaterialListDelegates& MaterialListDelegates, bool bInAllowCollapse = false, bool bInShowUsedTextures = true, bool bInDisplayCompactSize = false); /** * @return true if materials are being displayed. @@ -595,6 +598,8 @@ private: bool bAllowCollpase; /** Whether or not to use the used textures menu for each material entry */ bool bShowUsedTextures; + /** Whether or not to display a compact form of material entry*/ + bool bDisplayCompactSize; }; @@ -633,6 +638,8 @@ DECLARE_DELEGATE_RetVal_TwoParams(TSharedRef, FOnGenerateWidgetsForSect DECLARE_DELEGATE_TwoParams(FOnResetSectionToDefaultClicked, int32, int32); +DECLARE_DELEGATE_RetVal_OneParam(TSharedRef, FOnGenerateLODComboBox, int32); + DECLARE_DELEGATE_RetVal(bool, FOnCanCopySectionList); DECLARE_DELEGATE(FOnCopySectionList); DECLARE_DELEGATE(FOnPasteSectionList); @@ -649,6 +656,7 @@ struct FSectionListDelegates , OnGenerateCustomNameWidgets() , OnGenerateCustomSectionWidgets() , OnResetSectionToDefaultClicked() + , OnGenerateLodComboBox() {} /** Delegate called to populate the list with Sections */ @@ -662,6 +670,9 @@ struct FSectionListDelegates /** Delegate called when a Section list item should be reset to default */ FOnResetSectionToDefaultClicked OnResetSectionToDefaultClicked; + /** Delegate called when a Section list generate the LOD section combo box */ + FOnGenerateLODComboBox OnGenerateLodComboBox; + /** Delegate called Copying a section list */ FOnCopySectionList OnCopySectionList; /** Delegate called to know if we can copy a section list */ @@ -708,6 +719,9 @@ struct FSectionListItem /* Is this section is using cloth */ bool IsSectionUsingCloth; + /* Size of the preview material thumbnail */ + int32 ThumbnailSize; + /** Material being readonly view in the list */ TWeakObjectPtr Material; @@ -720,10 +734,11 @@ struct FSectionListItem TMap AvailableMaterialSlotName; - FSectionListItem(int32 InLodIndex, int32 InSectionIndex, FName InMaterialSlotName, int32 InMaterialSlotIndex, FName InOriginalMaterialSlotName, const TMap &InAvailableMaterialSlotName, const UMaterialInterface* InMaterial, bool InIsSectionUsingCloth) + FSectionListItem(int32 InLodIndex, int32 InSectionIndex, FName InMaterialSlotName, int32 InMaterialSlotIndex, FName InOriginalMaterialSlotName, const TMap &InAvailableMaterialSlotName, const UMaterialInterface* InMaterial, bool InIsSectionUsingCloth, int32 InThumbnailSize) : LodIndex(InLodIndex) , SectionIndex(InSectionIndex) , IsSectionUsingCloth(InIsSectionUsingCloth) + , ThumbnailSize(InThumbnailSize) , Material(InMaterial) , MaterialSlotName(InMaterialSlotName) , MaterialSlotIndex(InMaterialSlotIndex) @@ -764,7 +779,7 @@ struct FSectionListItem class FSectionList : public IDetailCustomNodeBuilder, public TSharedFromThis { public: - PROPERTYEDITOR_API FSectionList(IDetailLayoutBuilder& InDetailLayoutBuilder, FSectionListDelegates& SectionListDelegates, bool bInAllowCollapse = false); + PROPERTYEDITOR_API FSectionList(IDetailLayoutBuilder& InDetailLayoutBuilder, FSectionListDelegates& SectionListDelegates, bool bInAllowCollapse, int32 InThumbnailSize, int32 InSectionsLodIndex); /** * @return true if Sections are being displayed @@ -825,4 +840,7 @@ private: TSharedRef SectionListBuilder; /** Allow Collapse of Section header row. Right now if you allow collapse, it will initially collapse. */ bool bAllowCollpase; + + int32 ThumbnailSize; + int32 SectionsLodIndex; }; diff --git a/Engine/Source/Editor/PropertyEditor/Public/PropertyHandle.h b/Engine/Source/Editor/PropertyEditor/Public/PropertyHandle.h index 1ef015c24499..d5c680e71cc0 100644 --- a/Engine/Source/Editor/PropertyEditor/Public/PropertyHandle.h +++ b/Engine/Source/Editor/PropertyEditor/Public/PropertyHandle.h @@ -30,7 +30,7 @@ namespace EPropertyValueSetFlags * A handle to a property which is used to read and write the value without needing to handle Pre/PostEditChange, transactions, package modification * A handle also is used to identify the property in detail customization interfaces */ -class IPropertyHandle +class IPropertyHandle : public TSharedFromThis { public: virtual ~IPropertyHandle(){} @@ -551,6 +551,19 @@ public: * @return An array of interfaces to the properties that were added */ virtual TArray> AddChildStructure( TSharedRef ChildStructure ) = 0; + + /** + * Returns whether or not the property can be set to default + * + * @return If this property can be reset to default + */ + virtual bool IsResetToDefaultAvailable() = 0; + + + /** + * Sets an override for this property's reset to defautl behavior + */ + virtual void CustomResetToDefault( const class FResetToDefaultOverride& OnCustomResetToDefault ) = 0; }; /** diff --git a/Engine/Source/Editor/ReferenceViewer/Private/EdGraphNode_Reference.cpp b/Engine/Source/Editor/ReferenceViewer/Private/EdGraphNode_Reference.cpp index 7ae955338023..1092f2ff7e1b 100644 --- a/Engine/Source/Editor/ReferenceViewer/Private/EdGraphNode_Reference.cpp +++ b/Engine/Source/Editor/ReferenceViewer/Private/EdGraphNode_Reference.cpp @@ -165,8 +165,8 @@ FText UEdGraphNode_Reference::GetTooltipText() const void UEdGraphNode_Reference::AllocateDefaultPins() { - ReferencerPin = CreatePin( EEdGraphPinDirection::EGPD_Input, TEXT(""), TEXT(""), NULL, false, false, TEXT("") ); - DependencyPin = CreatePin( EEdGraphPinDirection::EGPD_Output, TEXT(""), TEXT(""), NULL, false, false, TEXT("") ); + ReferencerPin = CreatePin( EEdGraphPinDirection::EGPD_Input, FString(), FString(), nullptr, FString() ); + DependencyPin = CreatePin( EEdGraphPinDirection::EGPD_Output, FString(), FString(), nullptr, FString() ); ReferencerPin->bHidden = true; DependencyPin->bHidden = true; diff --git a/Engine/Source/Editor/ReferenceViewer/Private/EdGraph_ReferenceViewer.cpp b/Engine/Source/Editor/ReferenceViewer/Private/EdGraph_ReferenceViewer.cpp index 83a81a416dab..b3a3a7b444fd 100644 --- a/Engine/Source/Editor/ReferenceViewer/Private/EdGraph_ReferenceViewer.cpp +++ b/Engine/Source/Editor/ReferenceViewer/Private/EdGraph_ReferenceViewer.cpp @@ -461,7 +461,7 @@ UEdGraphNode_Reference* UEdGraph_ReferenceViewer::RecursivelyConstructNodes(bool } else { - ReferenceNode->GetReferencerPin()->PinType.PinCategory = TEXT("hard"); + ReferenceNode->GetReferencerPin()->PinType.PinCategory = TEXT("hard"); //-V595 } } diff --git a/Engine/Source/Editor/ReferenceViewer/Private/ReferenceViewerSchema.cpp b/Engine/Source/Editor/ReferenceViewer/Private/ReferenceViewerSchema.cpp index 06f39e5181cd..a7a08f4d9eb6 100644 --- a/Engine/Source/Editor/ReferenceViewer/Private/ReferenceViewerSchema.cpp +++ b/Engine/Source/Editor/ReferenceViewer/Private/ReferenceViewerSchema.cpp @@ -105,16 +105,16 @@ void UReferenceViewerSchema::BreakSinglePinLink(UEdGraphPin* SourcePin, UEdGraph // Don't allow breaking any links } -FPinConnectionResponse UReferenceViewerSchema::MovePinLinks(UEdGraphPin& MoveFromPin, UEdGraphPin& MoveToPin, bool bIsItermeadiateMove) const +FPinConnectionResponse UReferenceViewerSchema::MovePinLinks(UEdGraphPin& MoveFromPin, UEdGraphPin& MoveToPin, bool bIsItermediateMove) const { // Don't allow moving any links - return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, TEXT("")); + return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, FString()); } -FPinConnectionResponse UReferenceViewerSchema::CopyPinLinks(UEdGraphPin& CopyFromPin, UEdGraphPin& CopyToPin, bool bIsItermeadiateCopy) const +FPinConnectionResponse UReferenceViewerSchema::CopyPinLinks(UEdGraphPin& CopyFromPin, UEdGraphPin& CopyToPin, bool bIsItermediateCopy) const { // Don't allow copying any links - return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, TEXT("")); + return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, FString()); } FConnectionDrawingPolicy* UReferenceViewerSchema::CreateConnectionDrawingPolicy(int32 InBackLayerID, int32 InFrontLayerID, float InZoomFactor, const FSlateRect& InClippingRect, class FSlateWindowElementList& InDrawElements, class UEdGraph* InGraphObj) const diff --git a/Engine/Source/Editor/ReferenceViewer/Private/SReferenceNode.cpp b/Engine/Source/Editor/ReferenceViewer/Private/SReferenceNode.cpp index 18c341c041a0..e4bcbbb432f0 100644 --- a/Engine/Source/Editor/ReferenceViewer/Private/SReferenceNode.cpp +++ b/Engine/Source/Editor/ReferenceViewer/Private/SReferenceNode.cpp @@ -61,9 +61,11 @@ void SReferenceNode::UpdateGraphNode() TSharedRef ThumbnailWidget = SNullWidget::NullWidget; if ( AssetThumbnail.IsValid() ) { + UEdGraphNode_Reference* RefGraphNode = CastChecked(GraphNode); + FAssetThumbnailConfig ThumbnailConfig; - ThumbnailConfig.bAllowFadeIn = bUsesThumbnail; - ThumbnailConfig.bForceGenericThumbnail = !bUsesThumbnail; + ThumbnailConfig.bAllowFadeIn = RefGraphNode->UsesThumbnail(); + ThumbnailConfig.bForceGenericThumbnail = !RefGraphNode->UsesThumbnail(); ThumbnailWidget = SNew(SBox) diff --git a/Engine/Source/Editor/ReferenceViewer/Private/SReferenceNode.h b/Engine/Source/Editor/ReferenceViewer/Private/SReferenceNode.h index 687f706e9561..2af09bed1ea1 100644 --- a/Engine/Source/Editor/ReferenceViewer/Private/SReferenceNode.h +++ b/Engine/Source/Editor/ReferenceViewer/Private/SReferenceNode.h @@ -29,5 +29,4 @@ public: private: TSharedPtr AssetThumbnail; - bool bUsesThumbnail; }; diff --git a/Engine/Source/Editor/SceneOutliner/Private/SceneOutlinerStandaloneTypes.h b/Engine/Source/Editor/SceneOutliner/Private/SceneOutlinerStandaloneTypes.h index 2cde23b27a05..24cdd47867d1 100644 --- a/Engine/Source/Editor/SceneOutliner/Private/SceneOutlinerStandaloneTypes.h +++ b/Engine/Source/Editor/SceneOutliner/Private/SceneOutlinerStandaloneTypes.h @@ -5,13 +5,10 @@ #include "CoreMinimal.h" #include "Misc/Paths.h" #include "UObject/ObjectKey.h" +#include "Templates/MaxSizeof.h" namespace SceneOutliner { - template struct TMaxSizeof; - template <> struct TMaxSizeof<> { static const uint32 Value = 0; }; - template struct TMaxSizeof { static const uint32 Value = sizeof(T) > TMaxSizeof::Value ? sizeof(T) : TMaxSizeof::Value; }; - /** Variant type that defines an identifier for a tree item. Assumes 'trivial relocatability' as with many unreal containers. */ struct FTreeItemID { diff --git a/Engine/Source/Editor/SceneOutliner/Public/ISceneOutlinerColumn.h b/Engine/Source/Editor/SceneOutliner/Public/ISceneOutlinerColumn.h index b886ec77cf93..9d26c3ee8203 100644 --- a/Engine/Source/Editor/SceneOutliner/Public/ISceneOutlinerColumn.h +++ b/Engine/Source/Editor/SceneOutliner/Public/ISceneOutlinerColumn.h @@ -15,6 +15,7 @@ template class STableRow; class ISceneOutlinerColumn : public TSharedFromThis< ISceneOutlinerColumn > { public: + virtual ~ISceneOutlinerColumn() {} virtual FName GetColumnID() = 0; diff --git a/Engine/Source/Editor/SceneOutliner/Public/SceneOutlinerVisitorTypes.h b/Engine/Source/Editor/SceneOutliner/Public/SceneOutlinerVisitorTypes.h index 0d085f16651a..0fa391ce9e6f 100644 --- a/Engine/Source/Editor/SceneOutliner/Public/SceneOutlinerVisitorTypes.h +++ b/Engine/Source/Editor/SceneOutliner/Public/SceneOutlinerVisitorTypes.h @@ -12,6 +12,7 @@ namespace SceneOutliner /** A const tree item visitor. Derive to implement type-specific behaviour for tree items. */ struct ITreeItemVisitor { + virtual ~ITreeItemVisitor() {} virtual void Visit(const FActorTreeItem& Actor) const {} virtual void Visit(const FWorldTreeItem& World) const {} virtual void Visit(const FFolderTreeItem& Folder) const {} @@ -20,6 +21,7 @@ namespace SceneOutliner /** A non-const tree item visitor. Derive to implement type-specific behaviour for tree items. */ struct IMutableTreeItemVisitor { + virtual ~IMutableTreeItemVisitor() {} virtual void Visit(FActorTreeItem& Actor) const {} virtual void Visit(FWorldTreeItem& World) const {} virtual void Visit(FFolderTreeItem& Folder) const {} diff --git a/Engine/Source/Editor/SequenceRecorder/Private/ActorRecording.cpp b/Engine/Source/Editor/SequenceRecorder/Private/ActorRecording.cpp index a943215e130d..ab55e83c51ad 100644 --- a/Engine/Source/Editor/SequenceRecorder/Private/ActorRecording.cpp +++ b/Engine/Source/Editor/SequenceRecorder/Private/ActorRecording.cpp @@ -7,7 +7,7 @@ #include "Engine/SimpleConstructionScript.h" #include "Editor.h" #include "Animation/SkeletalMeshActor.h" -#include "LevelSequenceObjectReference.h" +#include "LevelSequenceBindingReference.h" #include "SequenceRecorderSettings.h" #include "Sections/MovieScene3DTransformSectionRecorderSettings.h" #include "MovieSceneFolder.h" @@ -396,10 +396,7 @@ TSharedPtr UActorRecording::StartRecordingC ParentSpawnable->AddChildPossessable(PossessableGuid); } - // BindingName must be the component's path relative to its owner Actor - FLevelSequenceObjectReference ObjectReference(FUniqueObjectGuid(), BindingName.ToString()); - - CurrentSequence->BindPossessableObject(PossessableGuid, ObjectReference); + CurrentSequence->BindPossessableObject(PossessableGuid, *SceneComponent, BindingContext); // First try built-in animation recorder... TSharedPtr AnimationRecorder = nullptr; @@ -675,20 +672,12 @@ void UActorRecording::StartRecordingNewComponents(ULevelSequence* CurrentSequenc for (USceneComponent* SceneComponent : NewComponents) { - // new component, so we need to add this to our BP if its not native + // new component, so we need to add this to our BP if it didn't come from SCS FName NewName; - if (SceneComponent->CreationMethod != EComponentCreationMethod::Native) + if (SceneComponent->CreationMethod != EComponentCreationMethod::SimpleConstructionScript) { // Give this component a unique name within its parent - if (SceneComponent->CreationMethod != EComponentCreationMethod::SimpleConstructionScript) - { - NewName = *FString::Printf(TEXT("Dynamic%s"), *SceneComponent->GetFName().GetPlainNameString()); - } - else - { - NewName = SceneComponent->GetFName(); - } - + NewName = *FString::Printf(TEXT("Dynamic%s"), *SceneComponent->GetFName().GetPlainNameString()); NewName.SetNumber(1); while (FindObjectFast(ObjectTemplate, NewName)) { diff --git a/Engine/Source/Editor/SequenceRecorder/Private/AnimationRecorder.cpp b/Engine/Source/Editor/SequenceRecorder/Private/AnimationRecorder.cpp index a0cf8c8c668e..e4a56a3ecaa3 100644 --- a/Engine/Source/Editor/SequenceRecorder/Private/AnimationRecorder.cpp +++ b/Engine/Source/Editor/SequenceRecorder/Private/AnimationRecorder.cpp @@ -212,7 +212,7 @@ void FAnimationRecorder::StartRecord(USkeletalMeshComponent* Component, UAnimSeq GetBoneTransforms(Component, PreviousSpacesBases); PreviousAnimCurves = Component->GetAnimationCurves(); - PreviousComponentToWorld = Component->ComponentToWorld; + PreviousComponentToWorld = Component->GetComponentTransform(); LastFrame = 0; AnimationObject->SequenceLength = 0.f; @@ -484,7 +484,7 @@ void FAnimationRecorder::UpdateRecord(USkeletalMeshComponent* Component, float D } FTransform BlendedComponentToWorld; - BlendedComponentToWorld.Blend(PreviousComponentToWorld, Component->ComponentToWorld, BlendAlpha); + BlendedComponentToWorld.Blend(PreviousComponentToWorld, Component->GetComponentTransform(), BlendAlpha); FBlendedHeapCurve BlendedCurve; if (AnimCurves.Elements.Num() > 0 && PreviousAnimCurves.Elements.Num() == AnimCurves.Elements.Num()) @@ -506,7 +506,7 @@ void FAnimationRecorder::UpdateRecord(USkeletalMeshComponent* Component, float D //save to current transform PreviousSpacesBases = SpaceBases; PreviousAnimCurves = Component->GetAnimationCurves(); - PreviousComponentToWorld = Component->ComponentToWorld; + PreviousComponentToWorld = Component->GetComponentTransform(); // if we passed MaxFrame, just stop it if (MaxFrame != UnBoundedFrameCount && FramesRecorded >= MaxFrame) diff --git a/Engine/Source/Editor/SequenceRecorder/Private/Sections/MovieScene3DTransformSectionRecorder.h b/Engine/Source/Editor/SequenceRecorder/Private/Sections/MovieScene3DTransformSectionRecorder.h index 678db8c1bf94..d73533a48cc0 100644 --- a/Engine/Source/Editor/SequenceRecorder/Private/Sections/MovieScene3DTransformSectionRecorder.h +++ b/Engine/Source/Editor/SequenceRecorder/Private/Sections/MovieScene3DTransformSectionRecorder.h @@ -12,6 +12,7 @@ class FMovieScene3DTransformSectionRecorder; class UMovieScene3DTransformSection; class UMovieScene3DTransformTrack; +struct FActorRecordingSettings; class FMovieScene3DTransformSectionRecorderFactory : public IMovieSceneSectionRecorderFactory { @@ -24,7 +25,7 @@ public: TSharedPtr CreateSectionRecorder(bool bRecordTransforms, TSharedPtr InAnimRecorder) const; private: - virtual TSharedPtr CreateSectionRecorder(const struct FActorRecordingSettings& InActorRecordingSettings) const override; + virtual TSharedPtr CreateSectionRecorder(const FActorRecordingSettings& InActorRecordingSettings) const override; }; /** Structure used to buffer up transform keys. Keys are inserted into tracks in FinalizeSection() */ diff --git a/Engine/Source/Editor/SequenceRecorder/Private/Sections/MovieSceneAnimationSectionRecorder.h b/Engine/Source/Editor/SequenceRecorder/Private/Sections/MovieSceneAnimationSectionRecorder.h index 07da1b70bfd0..fdb872bf0fc4 100644 --- a/Engine/Source/Editor/SequenceRecorder/Private/Sections/MovieSceneAnimationSectionRecorder.h +++ b/Engine/Source/Editor/SequenceRecorder/Private/Sections/MovieSceneAnimationSectionRecorder.h @@ -12,6 +12,8 @@ class FMovieSceneAnimationSectionRecorder; class UMovieSceneSkeletalAnimationSection; +class UActorRecording; +struct FActorRecordingSettings; class FMovieSceneAnimationSectionRecorderFactory : public IMovieSceneSectionRecorderFactory { @@ -20,10 +22,10 @@ public: virtual bool CanRecordObject(class UObject* InObjectToRecord) const override; - TSharedPtr CreateSectionRecorder(class UActorRecording* InActorRecording, const FAnimationRecordingSettings& InAnimationSettings) const; + TSharedPtr CreateSectionRecorder(UActorRecording* InActorRecording, const FAnimationRecordingSettings& InAnimationSettings) const; private: - virtual TSharedPtr CreateSectionRecorder(const struct FActorRecordingSettings& InActorRecordingSettings) const override; + virtual TSharedPtr CreateSectionRecorder(const FActorRecordingSettings& InActorRecordingSettings) const override; }; class FMovieSceneAnimationSectionRecorder : public IMovieSceneSectionRecorder diff --git a/Engine/Source/Editor/SequenceRecorder/Private/Sections/MovieScenePropertyRecorder.cpp b/Engine/Source/Editor/SequenceRecorder/Private/Sections/MovieScenePropertyRecorder.cpp index 0f8bc38d4143..c598fd5d2663 100644 --- a/Engine/Source/Editor/SequenceRecorder/Private/Sections/MovieScenePropertyRecorder.cpp +++ b/Engine/Source/Editor/SequenceRecorder/Private/Sections/MovieScenePropertyRecorder.cpp @@ -251,9 +251,9 @@ template <> UMovieSceneSection* FMovieScenePropertyRecorder::AddSection(UObject* InObjectToRecord, UMovieScene* InMovieScene, const FGuid& InGuid, float InTime) { UMovieSceneVectorTrack* Track = InMovieScene->AddTrack(InGuid); - Track->SetNumChannelsUsed(3); if (Track) { + Track->SetNumChannelsUsed(3); if (InObjectToRecord) { Track->SetPropertyNameAndPath(*Binding.GetProperty(*InObjectToRecord)->GetDisplayNameText().ToString(), Binding.GetPropertyPath()); diff --git a/Engine/Source/Editor/Sequencer/Private/DisplayNodes/SequencerDisplayNode.cpp b/Engine/Source/Editor/Sequencer/Private/DisplayNodes/SequencerDisplayNode.cpp index fb3f44406678..a0e773fb34dc 100644 --- a/Engine/Source/Editor/Sequencer/Private/DisplayNodes/SequencerDisplayNode.cpp +++ b/Engine/Source/Editor/Sequencer/Private/DisplayNodes/SequencerDisplayNode.cpp @@ -50,7 +50,6 @@ public: /** SLeafWidget Interface */ virtual int32 OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const override; - virtual FVector2D ComputeDesiredSize(float) const override; void Construct( const FArguments& InArgs, TSharedRef InRootNode ) { @@ -61,6 +60,11 @@ public: check(RootNode->GetType() == ESequencerNode::Object); } +protected: + // Begin SWidget overrides. + virtual FVector2D ComputeDesiredSize(float) const override; + // End SWidget overrides. + private: /** Collects all key times from the root node */ diff --git a/Engine/Source/Editor/Sequencer/Private/DisplayNodes/SequencerObjectBindingNode.cpp b/Engine/Source/Editor/Sequencer/Private/DisplayNodes/SequencerObjectBindingNode.cpp index 76a5007ee68f..89f95bb485e4 100644 --- a/Engine/Source/Editor/Sequencer/Private/DisplayNodes/SequencerObjectBindingNode.cpp +++ b/Engine/Source/Editor/Sequencer/Private/DisplayNodes/SequencerObjectBindingNode.cpp @@ -326,8 +326,15 @@ FLinearColor FSequencerObjectBindingNode::GetDisplayNameColor() const { FSequencer& Sequencer = ParentTree.GetSequencer(); - const bool bHasObjects = Sequencer.FindBoundObjects(ObjectBinding, Sequencer.GetFocusedTemplateID()).Num() != 0; - return bHasObjects ? FSequencerDisplayNode::GetDisplayNameColor() : FLinearColor::Red; + for (TWeakObjectPtr<> BoundObject : Sequencer.FindBoundObjects(ObjectBinding, Sequencer.GetFocusedTemplateID())) + { + if (BoundObject.IsValid()) + { + return FSequencerDisplayNode::GetDisplayNameColor(); + } + } + + return FLinearColor::Red; } FText FSequencerObjectBindingNode::GetDisplayNameToolTipText() const diff --git a/Engine/Source/Editor/Sequencer/Private/DisplayNodes/SequencerTrackNode.cpp b/Engine/Source/Editor/Sequencer/Private/DisplayNodes/SequencerTrackNode.cpp index 144f354397bc..11b74133bf62 100644 --- a/Engine/Source/Editor/Sequencer/Private/DisplayNodes/SequencerTrackNode.cpp +++ b/Engine/Source/Editor/Sequencer/Private/DisplayNodes/SequencerTrackNode.cpp @@ -111,6 +111,7 @@ TSharedRef FSequencerTrackNode::GetCustomOutlinerContent() if (KeyAreas[0]->CanCreateKeyEditor()) { BoxPanel->AddSlot() + .AutoWidth() .HAlign(HAlign_Right) .VAlign(VAlign_Center) [ @@ -126,13 +127,13 @@ TSharedRef FSequencerTrackNode::GetCustomOutlinerContent() else { BoxPanel->AddSlot() + .AutoWidth() [ SNew(SSpacer) ]; } BoxPanel->AddSlot() - .AutoWidth() .VAlign(VAlign_Center) [ SNew(SKeyNavigationButtons, AsShared()) @@ -182,6 +183,7 @@ TSharedRef FSequencerTrackNode::GetCustomOutlinerContent() if (Widget.IsValid()) { BoxPanel->AddSlot() + .AutoWidth() .VAlign(VAlign_Center) .HAlign(HAlign_Right) [ @@ -192,7 +194,6 @@ TSharedRef FSequencerTrackNode::GetCustomOutlinerContent() if (bHasKeyableAreas) { BoxPanel->AddSlot() - .AutoWidth() .VAlign(VAlign_Center) [ SNew(SKeyNavigationButtons, AsShared()) diff --git a/Engine/Source/Editor/Sequencer/Private/LevelEditorSequencerIntegration.cpp b/Engine/Source/Editor/Sequencer/Private/LevelEditorSequencerIntegration.cpp index b5c60f3cd215..fa8fe5cba93d 100644 --- a/Engine/Source/Editor/Sequencer/Private/LevelEditorSequencerIntegration.cpp +++ b/Engine/Source/Editor/Sequencer/Private/LevelEditorSequencerIntegration.cpp @@ -31,7 +31,6 @@ #include "Widgets/Layout/SBox.h" #include "Widgets/Text/STextBlock.h" - #define LOCTEXT_NAMESPACE "LevelEditorSequencerIntegration" class FDetailKeyframeHandlerWrapper : public IDetailKeyframeHandler @@ -166,7 +165,6 @@ void FLevelEditorSequencerIntegration::Initialize() FDelegateHandle Handle = FEditorDelegates::OnNewActorsDropped.AddRaw(this, &FLevelEditorSequencerIntegration::OnNewActorsDropped); AcquiredResources.Add([=]{ FEditorDelegates::OnNewActorsDropped.Remove(Handle); }); } - { FDelegateHandle Handle = USelection::SelectionChangedEvent.AddRaw( this, &FLevelEditorSequencerIntegration::OnActorSelectionChanged ); AcquiredResources.Add([=]{ USelection::SelectionChangedEvent.Remove(Handle); }); @@ -198,6 +196,21 @@ void FLevelEditorSequencerIntegration::Initialize() } ); } + + { + FLevelEditorModule& LevelEditorModule = FModuleManager::Get().GetModuleChecked("LevelEditor"); + + FDelegateHandle Handle = LevelEditorModule.OnTabContentChanged().AddRaw(this, &FLevelEditorSequencerIntegration::OnTabContentChanged); + AcquiredResources.Add( + [=]{ + FLevelEditorModule* LevelEditorModulePtr = FModuleManager::Get().GetModulePtr("LevelEditor"); + if (LevelEditorModulePtr) + { + LevelEditorModulePtr->OnTabContentChanged().Remove(Handle); + } + } + ); + } } void FLevelEditorSequencerIntegration::GetActorRecordingState( bool& bIsRecording ) const @@ -303,6 +316,25 @@ void FLevelEditorSequencerIntegration::OnNewActorsDropped(const TArray ); } +void FLevelEditorSequencerIntegration::OnSequencerEvaluated() +{ + // Redraw if not in PIE/simulate + const bool bIsInPIEOrSimulate = GEditor->PlayWorld != NULL || GEditor->bIsSimulatingInEditor; + if (bIsInPIEOrSimulate) + { + return; + } + + // Request a single real-time frame to be rendered to ensure that we tick the world and update the viewport + for (FEditorViewportClient* LevelVC : GEditor->AllViewportClients) + { + if (LevelVC && !LevelVC->IsRealtime()) + { + LevelVC->RequestRealTimeFrames(1); + } + } +} + void FLevelEditorSequencerIntegration::ActivateSequencerEditorMode() { // Release the sequencer mode if we already enabled it @@ -814,9 +846,12 @@ void FLevelEditorSequencerIntegration::AttachTransportControlsToViewports() for (TSharedPtr LevelViewport : LevelEditor->GetViewports()) { - TSharedRef TransportControl = SNew(SViewportTransportControls, LevelViewport); - LevelViewport->AddOverlayWidget(TransportControl); - TransportControls.Add(FTransportControl{ LevelViewport, TransportControl }); + if (LevelViewport->GetLevelViewportClient().CanAttachTransportControls()) + { + TSharedRef TransportControl = SNew(SViewportTransportControls, LevelViewport); + LevelViewport->AddOverlayWidget(TransportControl); + TransportControls.Add(FTransportControl{ LevelViewport, TransportControl }); + } } AcquiredResources.Add([=]{ this->DetachTransportControlsFromViewports(); }); @@ -889,6 +924,48 @@ void FLevelEditorSequencerIntegration::CreateTransportToggleMenuEntry(FMenuBuild EUserInterfaceActionType::ToggleButton); } +void FLevelEditorSequencerIntegration::OnTabContentChanged() +{ + for (const FTransportControl& Control : TransportControls) + { + TSharedPtr Viewport = Control.Viewport.Pin(); + if (Viewport.IsValid()) + { + Viewport->RemoveOverlayWidget(Control.Widget.ToSharedRef()); + } + } + TransportControls.Reset(); + + FLevelEditorModule* Module = FModuleManager::Get().LoadModulePtr("LevelEditor"); + + if (Module == nullptr) + { + return; + } + + TSharedPtr LevelEditor = Module->GetFirstLevelEditor(); + + for (TSharedPtr LevelViewport : LevelEditor->GetViewports()) + { + if (LevelViewport->GetLevelViewportClient().CanAttachTransportControls()) + { + TSharedRef TransportControl = SNew(SViewportTransportControls, LevelViewport); + LevelViewport->AddOverlayWidget(TransportControl); + + auto IsValidSequencer = [](const FSequencerAndOptions& In){ return In.Sequencer.IsValid(); }; + if (FSequencerAndOptions* FirstValidSequencer = BoundSequencers.FindByPredicate(IsValidSequencer)) + { + TSharedPtr SequencerPtr = FirstValidSequencer->Sequencer.Pin(); + check(SequencerPtr.IsValid()); + + TransportControl->AssignSequencer(SequencerPtr.ToSharedRef()); + } + + TransportControls.Add(FTransportControl{ LevelViewport, TransportControl }); + } + } +} + void FLevelEditorSequencerIntegration::AddSequencer(TSharedRef InSequencer, const FLevelEditorSequencerIntegrationOptions& Options) { if (!BoundSequencers.Num()) @@ -897,10 +974,26 @@ void FLevelEditorSequencerIntegration::AddSequencer(TSharedRef InSeq } KeyFrameHandler->Add(InSequencer); - + auto DerivedSequencerPtr = StaticCastSharedRef(InSequencer); BoundSequencers.Add(FSequencerAndOptions{ DerivedSequencerPtr, Options }); + { + // Set up a callback for when this sequencer changes its time to redraw any non-realtime viewports + TWeakPtr WeakSequencer = InSequencer; + FDelegateHandle Handle = InSequencer->OnGlobalTimeChanged().AddRaw(this, &FLevelEditorSequencerIntegration::OnSequencerEvaluated); + BoundSequencers.Last().AcquiredResources.Add( + [=] + { + TSharedPtr Pinned = WeakSequencer.Pin(); + if (Pinned.IsValid()) + { + Pinned->OnGlobalTimeChanged().Remove(Handle); + } + } + ); + } + FSequencerEdMode* SequencerEdMode = (FSequencerEdMode*)(GLevelEditorModeTools().GetActiveMode(FSequencerEdMode::EM_SequencerMode)); if (SequencerEdMode) { @@ -924,11 +1017,11 @@ void FLevelEditorSequencerIntegration::OnSequencerReceivedFocus(TSharedRefOnSequencerReceivedFocus(StaticCastSharedRef(InSequencer)); } - } void FLevelEditorSequencerIntegration::RemoveSequencer(TSharedRef InSequencer) { + // Remove any instances of this sequencer in the array of bound sequencers, along with its resources BoundSequencers.RemoveAll( [=](const FSequencerAndOptions& In) { @@ -958,7 +1051,6 @@ void FLevelEditorSequencerIntegration::RemoveSequencer(TSharedRef In Control.Widget->AssignSequencer(SequencerPtr.ToSharedRef()); } } - } else { diff --git a/Engine/Source/Editor/Sequencer/Private/SAnimationOutlinerTreeNode.cpp b/Engine/Source/Editor/Sequencer/Private/SAnimationOutlinerTreeNode.cpp index f6bacd4989ef..2d227e5d718c 100644 --- a/Engine/Source/Editor/Sequencer/Private/SAnimationOutlinerTreeNode.cpp +++ b/Engine/Source/Editor/Sequencer/Private/SAnimationOutlinerTreeNode.cpp @@ -209,13 +209,13 @@ void SAnimationOutlinerTreeNode::Construct( const FArguments& InArgs, TSharedRef + SHorizontalBox::Slot() .VAlign(VAlign_Center) .Padding(FMargin(0.f, 0.f, 4.f, 0.f)) - .AutoWidth() [ EditableLabel.ToSharedRef() ] // Arbitrary customization slot + SHorizontalBox::Slot() + .AutoWidth() [ InArgs._CustomContent.Widget ] diff --git a/Engine/Source/Editor/Sequencer/Private/SSequencer.cpp b/Engine/Source/Editor/Sequencer/Private/SSequencer.cpp index bfcd31d78a11..701a7a03533d 100644 --- a/Engine/Source/Editor/Sequencer/Private/SSequencer.cpp +++ b/Engine/Source/Editor/Sequencer/Private/SSequencer.cpp @@ -190,7 +190,7 @@ void SSequencer::Construct(const FArguments& InArgs, TSharedRef InSe bool bMirrorLabels = false; // Create the top and bottom sliders - TSharedRef TopTimeSlider = SequencerWidgets.CreateTimeSlider( TimeSliderControllerRef, bMirrorLabels ); + TopTimeSlider = SequencerWidgets.CreateTimeSlider( TimeSliderControllerRef, bMirrorLabels ); bMirrorLabels = true; TSharedRef BottomTimeSlider = SequencerWidgets.CreateTimeSlider( TimeSliderControllerRef, TAttribute(this, &SSequencer::GetBottomTimeSliderVisibility), bMirrorLabels ); @@ -437,7 +437,7 @@ void SSequencer::Construct(const FArguments& InArgs, TSharedRef InSe .BorderBackgroundColor( FLinearColor(.50f, .50f, .50f, 1.0f ) ) .Padding(0) [ - TopTimeSlider + TopTimeSlider.ToSharedRef() ] ] @@ -952,6 +952,7 @@ TSharedRef SSequencer::MakeGeneralMenu() if (SequencerPtr.Pin()->IsLevelEditorSequencer()) { MenuBuilder.AddMenuEntry(FSequencerCommands::Get().FixActorReferences); + MenuBuilder.AddMenuEntry(FSequencerCommands::Get().RebindPossessableReferences); } MenuBuilder.AddMenuEntry(FSequencerCommands::Get().FixFrameTiming); @@ -1203,6 +1204,11 @@ TSharedRef SSequencer::MakeTimeRange(const TSharedRef& InnerCo return SequencerWidgets.CreateTimeRange(Args, InnerContent); } +TSharedPtr SSequencer::GetTopTimeSliderWidget() const +{ + return TopTimeSlider; +} + SSequencer::~SSequencer() { USelection::SelectionChangedEvent.RemoveAll(this); @@ -1532,10 +1538,8 @@ void SSequencer::OnAssetsDropped( const FAssetDragDropOp& DragDropOp ) TArray< UObject* > DroppedObjects; bool bAllAssetsWereLoaded = true; - for( auto CurAssetData = DragDropOp.AssetData.CreateConstIterator(); CurAssetData; ++CurAssetData ) + for (const FAssetData& AssetData : DragDropOp.GetAssets()) { - const FAssetData& AssetData = *CurAssetData; - UObject* Object = AssetData.GetAsset(); if ( Object != nullptr ) diff --git a/Engine/Source/Editor/Sequencer/Private/SSequencer.h b/Engine/Source/Editor/Sequencer/Private/SSequencer.h index 4b953d7aa839..284c5ed87618 100644 --- a/Engine/Source/Editor/Sequencer/Private/SSequencer.h +++ b/Engine/Source/Editor/Sequencer/Private/SSequencer.h @@ -307,11 +307,14 @@ private: /** Makes the auto-key menu for the toolbar. */ TSharedRef MakeAutoKeyMenu(); -public: +public: /** Makes a time range widget with the specified inner content */ TSharedRef MakeTimeRange(const TSharedRef& InnerContent, bool bShowWorkingRange, bool bShowViewRange, bool bShowPlaybackRange); + /** Gets the top time sliders widget. */ + TSharedPtr GetTopTimeSliderWidget() const; + private: /** @@ -469,6 +472,9 @@ private: /** The main sequencer interface */ TWeakPtr SequencerPtr; + /** The top time slider widget */ + TSharedPtr TopTimeSlider; + /** Cached settings provided to the sequencer itself on creation */ USequencerSettings* Settings; diff --git a/Engine/Source/Editor/Sequencer/Private/Sequencer.cpp b/Engine/Source/Editor/Sequencer/Private/Sequencer.cpp index d230c1821b67..469a99c37ecb 100644 --- a/Engine/Source/Editor/Sequencer/Private/Sequencer.cpp +++ b/Engine/Source/Editor/Sequencer/Private/Sequencer.cpp @@ -102,6 +102,7 @@ #include "UnrealExporter.h" #include "ISequencerEditorObjectBinding.h" #include "LevelSequence.h" +#include "IVREditorModule.h" #define LOCTEXT_NAMESPACE "Sequencer" @@ -1689,13 +1690,6 @@ void FSequencer::EvaluateInternal(FMovieSceneEvaluationRange InRange) if (!IsInSilentMode()) { - // Redraw if not in PIE/simulate - const bool bIsInPIEOrSimulate = GEditor->PlayWorld != NULL || GEditor->bIsSimulatingInEditor; - if (!bIsInPIEOrSimulate) - { - FEditorSupportDelegates::RedrawAllViewports.Broadcast(); - } - OnGlobalTimeChangedDelegate.Broadcast(); } } @@ -2061,6 +2055,11 @@ void FSequencer::PossessPIEViewports(UObject* CameraObject, UObject* UnlockIfCam } } +TSharedPtr FSequencer::GetTopTimeSliderWidget() const +{ + return SequencerWidget->GetTopTimeSliderWidget(); +} + void FSequencer::UpdateCameraCut(UObject* CameraObject, UObject* UnlockIfCameraObject, bool bJumpCut) { OnCameraCutEvent.Broadcast(CameraObject, bJumpCut); @@ -3230,6 +3229,8 @@ FGuid FSequencer::AddSpawnable(UObject& Object) FGuid NewGuid = OwnerMovieScene->AddSpawnable(NewSpawnable.Name, *NewSpawnable.ObjectTemplate); + ForceEvaluate(); + UpdateRuntimeInstances(); return NewGuid; @@ -3522,7 +3523,7 @@ void FSequencer::OnNewActorsDropped(const TArray& DroppedObjects, cons { FMovieSceneSpawnable* Spawnable = ConvertToSpawnableInternal(PossessableGuid); - UpdateRuntimeInstances(); + ForceEvaluate(); for (TWeakObjectPtr<> WeakObject : FindBoundObjects(Spawnable->GetGuid(), ActiveTemplateIDs.Top())) { @@ -3561,7 +3562,7 @@ void FSequencer::OnNewActorsDropped(const TArray& DroppedObjects, cons { FMovieSceneSpawnable* Spawnable = ConvertToSpawnableInternal(NewCameraGuid); - UpdateRuntimeInstances(); + ForceEvaluate(); for (TWeakObjectPtr<> WeakObject : FindBoundObjects(Spawnable->GetGuid(), ActiveTemplateIDs.Top())) { @@ -4039,35 +4040,44 @@ void FSequencer::SynchronizeSequencerSelectionWithExternalSelection() for ( TWeakObjectPtr RuntimeObjectPtr : FindBoundObjects(ObjectBindingNode->GetObjectBinding(), ActiveTemplateIDs.Top()) ) { UObject* RuntimeObject = RuntimeObjectPtr.Get(); - if ( RuntimeObject != nullptr && - (GEditor->GetSelectedActors()->IsSelected( RuntimeObject ) || GEditor->GetSelectedComponents()->IsSelected( RuntimeObject) )) + if ( RuntimeObject != nullptr) { - NodesToSelect.Add( ObjectBindingNode ); + bool bActorSelected = GEditor->GetSelectedActors()->IsSelected( RuntimeObject ); + bool bComponentSelected = GEditor->GetSelectedComponents()->IsSelected( RuntimeObject); - if (bAllAlreadySelected) + if (bActorSelected || bComponentSelected) { - bool bAlreadySelected = Selection.IsSelected(ObjectBindingNode); + NodesToSelect.Add( ObjectBindingNode ); - if (!bAlreadySelected) + if (bAllAlreadySelected) { - TSet > DescendantNodes; - SequencerHelpers::GetDescendantNodes(ObjectBindingNode, DescendantNodes); + bool bAlreadySelected = Selection.IsSelected(ObjectBindingNode); - for (auto DescendantNode : DescendantNodes) + if (!bAlreadySelected) { - if (Selection.IsSelected(DescendantNode) || Selection.NodeHasSelectedKeysOrSections(DescendantNode)) + TSet > DescendantNodes; + SequencerHelpers::GetDescendantNodes(ObjectBindingNode, DescendantNodes); + + for (auto DescendantNode : DescendantNodes) { - bAlreadySelected = true; - break; + if (Selection.IsSelected(DescendantNode) || Selection.NodeHasSelectedKeysOrSections(DescendantNode)) + { + bAlreadySelected = true; + break; + } } } - } - if (!bAlreadySelected) - { - bAllAlreadySelected = false; + if (!bAlreadySelected) + { + bAllAlreadySelected = false; + } } } + else if (Selection.IsSelected(ObjectBindingNode)) + { + bAllAlreadySelected = false; + } } } } @@ -4824,7 +4834,7 @@ void FSequencer::ConvertSelectedNodesToSpawnables() if (Spawnable) { - UpdateRuntimeInstances(); + ForceEvaluate(); for (TWeakObjectPtr<> WeakObject : FindBoundObjects(Spawnable->GetGuid(), ActiveTemplateIDs.Top())) { @@ -4979,7 +4989,7 @@ void FSequencer::ConvertSelectedNodesToPossessables() { FMovieScenePossessable* Possessable = ConvertToPossessableInternal(Spawnable->GetGuid()); - UpdateRuntimeInstances(); + ForceEvaluate(); for (TWeakObjectPtr<> WeakObject : FindBoundObjects(Possessable->GetGuid(), ActiveTemplateIDs.Top())) { @@ -5943,6 +5953,40 @@ void FSequencer::FixActorReferences() } } +void FSequencer::RebindPossessableReferences() +{ + FScopedTransaction Transaction(LOCTEXT("RebindAllPossessables", "Rebind Possessable References")); + + UMovieSceneSequence* FocusedSequence = GetFocusedMovieSceneSequence(); + FocusedSequence->Modify(); + + UMovieScene* FocusedMovieScene = FocusedSequence->GetMovieScene(); + + TMap>> AllObjects; + + UObject* PlaybackContext = PlaybackContextAttribute.Get(nullptr); + + for (int32 Index = 0; Index < FocusedMovieScene->GetPossessableCount(); Index++) + { + const FMovieScenePossessable& Possessable = FocusedMovieScene->GetPossessable(Index); + + TArray>& References = AllObjects.FindOrAdd(Possessable.GetGuid()); + FocusedSequence->LocateBoundObjects(Possessable.GetGuid(), PlaybackContext, References); + } + + for (auto& Pair : AllObjects) + { + // Only rebind things if they exist + if (Pair.Value.Num() > 0) + { + FocusedSequence->UnbindPossessableObjects(Pair.Key); + for (UObject* Object : Pair.Value) + { + FocusedSequence->BindPossessableObject(Pair.Key, *Object, PlaybackContext); + } + } + } +} float SnapTime( float TimeValue, float TimeInterval ) { @@ -6707,7 +6751,7 @@ void FSequencer::BindCommands() FExecuteAction::CreateSP(this, &FSequencer::CreateCamera), FCanExecuteAction(), FIsActionChecked(), - FIsActionButtonVisible::CreateLambda([this] { return ExactCast(GetFocusedMovieSceneSequence()) != nullptr; }) + FIsActionButtonVisible::CreateLambda([this] { return ExactCast(GetFocusedMovieSceneSequence()) != nullptr && IVREditorModule::Get().IsVREditorModeActive() == false; }) //@todo VREditor: Creating a camera while in VR mode disrupts the hmd. This is a temporary fix by hiding the button when in VR mode. ); SequencerCommandBindings->MapAction( @@ -6722,7 +6766,7 @@ void FSequencer::BindCommands() UPackage* EditedPackage = EditedSequence->GetOutermost(); - return ((EditedSequence != nullptr) && (EditedPackage->FileSize != 0) && EditedPackage->IsDirty()); + return ((EditedPackage->FileSize != 0) && EditedPackage->IsDirty()); }) ); @@ -6731,6 +6775,11 @@ void FSequencer::BindCommands() FExecuteAction::CreateSP( this, &FSequencer::FixActorReferences ), FCanExecuteAction::CreateLambda( []{ return true; } ) ); + SequencerCommandBindings->MapAction( + Commands.RebindPossessableReferences, + FExecuteAction::CreateSP( this, &FSequencer::RebindPossessableReferences ), + FCanExecuteAction::CreateLambda( []{ return true; } ) ); + SequencerCommandBindings->MapAction( Commands.FixFrameTiming, FExecuteAction::CreateSP( this, &FSequencer::FixFrameTiming ), diff --git a/Engine/Source/Editor/Sequencer/Private/Sequencer.h b/Engine/Source/Editor/Sequencer/Private/Sequencer.h index ac03411e1fce..545c71a87795 100644 --- a/Engine/Source/Editor/Sequencer/Private/Sequencer.h +++ b/Engine/Source/Editor/Sequencer/Private/Sequencer.h @@ -517,6 +517,9 @@ public: /** Attempts to automatically fix up broken actor references in the current scene. */ void FixActorReferences(); + /** Rebinds all possessable references in the current sequence to update them to the latest referencing mechanism. */ + void RebindPossessableReferences(); + /** Moves all time data for the current scene onto a valid frame. */ void FixFrameTiming(); @@ -643,6 +646,7 @@ public: virtual bool IsReadOnly() const override; virtual void ExternalSelectionHasChanged() override { SynchronizeSequencerSelectionWithExternalSelection(); } virtual USequencerSettings* GetSequencerSettings() override { return Settings; } + virtual TSharedPtr GetTopTimeSliderWidget() const override; public: diff --git a/Engine/Source/Editor/Sequencer/Private/SequencerCommands.cpp b/Engine/Source/Editor/Sequencer/Private/SequencerCommands.cpp index b6a112a878e7..8dea204b9312 100644 --- a/Engine/Source/Editor/Sequencer/Private/SequencerCommands.cpp +++ b/Engine/Source/Editor/Sequencer/Private/SequencerCommands.cpp @@ -112,6 +112,7 @@ void FSequencerCommands::RegisterCommands() UI_COMMAND( DiscardChanges, "Discard All Changes", "Revert the currently edited movie scene to its last saved state.", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND( FixActorReferences, "Fix Actor References", "Try to automatically fix up broken actor bindings.", EUserInterfaceActionType::Button, FInputChord() ); + UI_COMMAND( RebindPossessableReferences, "Rebind Possesable References", "Rebinds all possessables in the current sequence to ensure they're using the most robust referencing mechanism.", EUserInterfaceActionType::Button, FInputChord() ); UI_COMMAND( FixFrameTiming, "Fix Frame Timing", "Moves all time data for this sequence to a valid frame time.", EUserInterfaceActionType::Button, FInputChord() ); diff --git a/Engine/Source/Editor/Sequencer/Private/SequencerEdMode.cpp b/Engine/Source/Editor/Sequencer/Private/SequencerEdMode.cpp index 52b3cab10b9f..c99c4cdbcdcc 100644 --- a/Engine/Source/Editor/Sequencer/Private/SequencerEdMode.cpp +++ b/Engine/Source/Editor/Sequencer/Private/SequencerEdMode.cpp @@ -134,13 +134,16 @@ void FSequencerEdMode::OnKeySelected(FViewport* Viewport, HMovieSceneKeyProxy* K bool bAltDown = Viewport->KeyState(EKeys::LeftAlt) || Viewport->KeyState(EKeys::RightAlt); bool bShiftDown = Viewport->KeyState(EKeys::LeftShift) || Viewport->KeyState(EKeys::RightShift); - for (TWeakPtr WeakSequencer : Sequencers) + if (KeyProxy->MovieSceneSection.IsValid() && KeyProxy->MovieSceneSection.Get() != nullptr) { - TSharedPtr Sequencer = WeakSequencer.Pin(); - if (Sequencer.IsValid()) + for (TWeakPtr WeakSequencer : Sequencers) { - Sequencer->SetLocalTimeDirectly(KeyProxy->Time); - Sequencer->SelectTrackKeys(KeyProxy->MovieSceneSection, KeyProxy->Time, bShiftDown, bCtrlDown); + TSharedPtr Sequencer = WeakSequencer.Pin(); + if (Sequencer.IsValid()) + { + Sequencer->SetLocalTimeDirectly(KeyProxy->Time); + Sequencer->SelectTrackKeys(KeyProxy->MovieSceneSection.Get(), KeyProxy->Time, bShiftDown, bCtrlDown); + } } } } diff --git a/Engine/Source/Editor/Sequencer/Private/SequencerNodeTree.cpp b/Engine/Source/Editor/Sequencer/Private/SequencerNodeTree.cpp index c5f1f823df5b..4c722bdefe97 100644 --- a/Engine/Source/Editor/Sequencer/Private/SequencerNodeTree.cpp +++ b/Engine/Source/Editor/Sequencer/Private/SequencerNodeTree.cpp @@ -192,12 +192,11 @@ void FSequencerNodeTree::Update() RootNodes.Append( FolderAndObjectNodes ); - RootNodes.Reserve(RootNodes.Num()*2); - for (int32 Index = 0; Index < RootNodes.Num(); Index += 2) + RootNodes.Reserve((RootNodes.Num()-1)*2); + for (int32 Index = 1; Index < RootNodes.Num(); Index += 2) { RootNodes.Insert(MakeShareable(new FSequencerSpacerNode(1.f, nullptr, *this)), Index); } - RootNodes.Add(MakeShareable(new FSequencerSpacerNode(1.f, nullptr, *this))); // Set up virtual offsets, expansion states, and tints float VerticalOffset = 0.f; @@ -513,6 +512,16 @@ static void AddFilteredNode(const TSharedRef& StartNode, } } +static void AddParentNodes(const TSharedRef& StartNode, TSet>& OutFilteredNodes) +{ + TSharedPtr ParentNode = StartNode->GetParent(); + if (ParentNode.IsValid()) + { + OutFilteredNodes.Add(ParentNode.ToSharedRef()); + AddParentNodes(ParentNode.ToSharedRef(), OutFilteredNodes); + } +} + /** * Recursively filters nodes * @@ -590,7 +599,7 @@ static bool FilterNodesRecursive( FSequencer& Sequencer, const TSharedRef 0 && Property != nullptr) { - FPropertyChangedParams Params(KeyableObjects, PropertyPath, Property->GetFName(), KeyPropertyParams.KeyMode); + // If the property path is not truncated, then we are keying the leafmost property anyways, so set to NAME_None + // Otherwise always set to leafmost property of the non-truncated property path, so we correctly pick up struct members + const bool bTruncatedPropertyPath = PropertyPath.GetNumProperties() != KeyPropertyParams.PropertyPath.GetNumProperties(); + FName StructPropertyNameToKey = !bTruncatedPropertyPath ? NAME_None : KeyPropertyParams.PropertyPath.GetLeafMostProperty().Property->GetFName(); + FPropertyChangedParams Params(KeyableObjects, PropertyPath, StructPropertyNameToKey, KeyPropertyParams.KeyMode); Delegate.Broadcast(Params); } } diff --git a/Engine/Source/Editor/Sequencer/Private/SequencerSectionPainter.cpp b/Engine/Source/Editor/Sequencer/Private/SequencerSectionPainter.cpp index 76c2dc1d7754..f2e2963a6e84 100644 --- a/Engine/Source/Editor/Sequencer/Private/SequencerSectionPainter.cpp +++ b/Engine/Source/Editor/Sequencer/Private/SequencerSectionPainter.cpp @@ -12,6 +12,10 @@ FSequencerSectionPainter::FSequencerSectionPainter(FSlateWindowElementList& OutD { } +FSequencerSectionPainter::~FSequencerSectionPainter() +{ +} + int32 FSequencerSectionPainter::PaintSectionBackground() { return PaintSectionBackground(GetTrack()->GetColorTint()); diff --git a/Engine/Source/Editor/Sequencer/Private/SequencerTimeSliderController.cpp b/Engine/Source/Editor/Sequencer/Private/SequencerTimeSliderController.cpp index 949c788d6b5f..86f55b09468d 100644 --- a/Engine/Source/Editor/Sequencer/Private/SequencerTimeSliderController.cpp +++ b/Engine/Source/Editor/Sequencer/Private/SequencerTimeSliderController.cpp @@ -952,6 +952,12 @@ FCursorReply FSequencerTimeSliderController::OnCursorQuery( TSharedRef LocalHitPositionX) { return false; } @@ -1262,13 +1270,15 @@ bool FSequencerTimeSliderController::HitTestScrubberEnd(const FScrubRangeToScree { static float BrushSizeInStateUnits = 6.f, DragToleranceSlateUnits = 2.f, MouseTolerance = 2.f; float LocalPlaybackEndPos = RangeToScreen.InputToLocalX(PlaybackRange.GetUpperBoundValue()); + float LocalScrubPos = RangeToScreen.InputToLocalX(ScrubPosition); // We favor hit testing the scrub bar over hit testing the playback range bounds - if (FMath::IsNearlyEqual(LocalPlaybackEndPos, RangeToScreen.InputToLocalX(ScrubPosition), ScrubHandleSize/2.f)) + if ((LocalScrubPos - ScrubHandleSize/2.f) < LocalHitPositionX && + (LocalScrubPos + ScrubHandleSize/2.f) > LocalHitPositionX) { return false; } - + // Hit test against the brush region to the left of the playback end position, +/- DragToleranceSlateUnits return LocalHitPositionX >= LocalPlaybackEndPos - MouseTolerance - BrushSizeInStateUnits - DragToleranceSlateUnits && LocalHitPositionX <= LocalPlaybackEndPos + MouseTolerance + DragToleranceSlateUnits; diff --git a/Engine/Source/Editor/Sequencer/Private/Tools/SequencerEditTool_Selection.cpp b/Engine/Source/Editor/Sequencer/Private/Tools/SequencerEditTool_Selection.cpp index cdef30c60bef..edda815f0375 100644 --- a/Engine/Source/Editor/Sequencer/Private/Tools/SequencerEditTool_Selection.cpp +++ b/Engine/Source/Editor/Sequencer/Private/Tools/SequencerEditTool_Selection.cpp @@ -10,7 +10,7 @@ #include "VirtualTrackArea.h" -struct FSelectionPreviewVisitor +struct FSelectionPreviewVisitor final : ISequencerEntityVisitor { FSelectionPreviewVisitor(FSequencerSelectionPreview& InSelectionPreview, FSequencerSelection& InSelection, ESelectionPreviewState InSetStateTo) diff --git a/Engine/Source/Editor/Sequencer/Private/Tools/SequencerEntityVisitor.h b/Engine/Source/Editor/Sequencer/Private/Tools/SequencerEntityVisitor.h index 667c0a09d95d..8b81579b9cb5 100644 --- a/Engine/Source/Editor/Sequencer/Private/Tools/SequencerEntityVisitor.h +++ b/Engine/Source/Editor/Sequencer/Private/Tools/SequencerEntityVisitor.h @@ -35,6 +35,7 @@ struct ISequencerEntityVisitor bool CheckEntityMask(ESequencerEntity::Type Type) const { return (EntityMask & Type) != 0; } protected: + virtual ~ISequencerEntityVisitor() { } /** Bitmask of allowable entities */ uint32 EntityMask; diff --git a/Engine/Source/Editor/Sequencer/Private/Tools/SequencerSnapField.h b/Engine/Source/Editor/Sequencer/Private/Tools/SequencerSnapField.h index d5d398fb15f5..8515d230e912 100644 --- a/Engine/Source/Editor/Sequencer/Private/Tools/SequencerSnapField.h +++ b/Engine/Source/Editor/Sequencer/Private/Tools/SequencerSnapField.h @@ -32,6 +32,9 @@ struct ISequencerSnapCandidate /** Return true to include the specified section's custom snap points in the snap field */ virtual bool AreSectionCustomSnapsApplicable(UMovieSceneSection* Section) { return true; } + +protected: + virtual ~ISequencerSnapCandidate() { } }; /** A snapping field that provides efficient snapping calculations on a range of values */ diff --git a/Engine/Source/Editor/Sequencer/Public/AcquiredResources.h b/Engine/Source/Editor/Sequencer/Public/AcquiredResources.h index 4749796925c8..8505871f3552 100644 --- a/Engine/Source/Editor/Sequencer/Public/AcquiredResources.h +++ b/Engine/Source/Editor/Sequencer/Public/AcquiredResources.h @@ -10,6 +10,17 @@ class FAcquiredResources { public: + /** Default construction */ + FAcquiredResources() = default; + + /** Copy construction is disabled */ + FAcquiredResources(const FAcquiredResources&) = delete; + FAcquiredResources& operator=(const FAcquiredResources&) = delete; + + /** Move construction/assignment implies a transfer of ownership of the acquired resources */ + FAcquiredResources(FAcquiredResources&&) = default; + FAcquiredResources& operator=(FAcquiredResources&&) = default; + /** * Destructor that releases any acquired resources */ diff --git a/Engine/Source/Editor/Sequencer/Public/ISectionLayoutBuilder.h b/Engine/Source/Editor/Sequencer/Public/ISectionLayoutBuilder.h index 9d9a881bca33..1fc0c1861132 100644 --- a/Engine/Source/Editor/Sequencer/Public/ISectionLayoutBuilder.h +++ b/Engine/Source/Editor/Sequencer/Public/ISectionLayoutBuilder.h @@ -10,6 +10,8 @@ class ISectionLayoutBuilder { public: + virtual ~ISectionLayoutBuilder() { } + /** * Pushes a new category onto the layout. If there is a current category, this category will appear as a child of the current category * diff --git a/Engine/Source/Editor/Sequencer/Public/ISequencer.h b/Engine/Source/Editor/Sequencer/Public/ISequencer.h index 109cd7ead590..9255972a03e8 100644 --- a/Engine/Source/Editor/Sequencer/Public/ISequencer.h +++ b/Engine/Source/Editor/Sequencer/Public/ISequencer.h @@ -405,4 +405,11 @@ public: * @return the widget */ virtual TSharedRef MakeTimeRange(const TSharedRef& InnerContent, bool bShowWorkingRange, bool bShowViewRange, bool bShowPlaybackRange) = 0; + + /** + * Get the top time slider from the main widget. + * + * @return the widget + */ + virtual TSharedPtr GetTopTimeSliderWidget() const = 0; }; diff --git a/Engine/Source/Editor/Sequencer/Public/LevelEditorSequencerIntegration.h b/Engine/Source/Editor/Sequencer/Public/LevelEditorSequencerIntegration.h index df9fef5898d5..f93f9e185fd9 100644 --- a/Engine/Source/Editor/Sequencer/Public/LevelEditorSequencerIntegration.h +++ b/Engine/Source/Editor/Sequencer/Public/LevelEditorSequencerIntegration.h @@ -73,6 +73,9 @@ private: /** Called when new actors are dropped in the viewport. */ void OnNewActorsDropped(const TArray& DroppedObjects, const TArray& DroppedActors); + /** Called when viewport tab content changes. */ + void OnTabContentChanged(); + /** Called before a PIE session begins. */ void OnPreBeginPIE(bool bIsSimulating); @@ -88,6 +91,9 @@ private: /** Called via UEditorEngine::GetActorRecordingStateEvent to check to see whether we need to record actor state */ void GetActorRecordingState( bool& bIsRecording ) const; + /** Called when sequencer has been evaluated */ + void OnSequencerEvaluated(); + void OnPropertyEditorOpened(); TSharedRef GetLevelViewportExtender(const TSharedRef CommandList, const TArray InActors); @@ -124,6 +130,7 @@ private: { TWeakPtr Sequencer; FLevelEditorSequencerIntegrationOptions Options; + FAcquiredResources AcquiredResources; }; TArray BoundSequencers; diff --git a/Engine/Source/Editor/Sequencer/Public/SequencerCommands.h b/Engine/Source/Editor/Sequencer/Public/SequencerCommands.h index 88ed0e4e2661..03bfa454341e 100644 --- a/Engine/Source/Editor/Sequencer/Public/SequencerCommands.h +++ b/Engine/Source/Editor/Sequencer/Public/SequencerCommands.h @@ -268,6 +268,9 @@ public: /** Attempts to fix broken actor references. */ TSharedPtr< FUICommandInfo > FixActorReferences; + /** Rebinds all possessable references with their current bindings. */ + TSharedPtr< FUICommandInfo > RebindPossessableReferences; + /** Attempts to move all time data for this sequence on to a valid frame */ TSharedPtr< FUICommandInfo > FixFrameTiming; diff --git a/Engine/Source/Editor/Sequencer/Public/SequencerSectionPainter.h b/Engine/Source/Editor/Sequencer/Public/SequencerSectionPainter.h index 5e10a6918789..4e47283ace1b 100644 --- a/Engine/Source/Editor/Sequencer/Public/SequencerSectionPainter.h +++ b/Engine/Source/Editor/Sequencer/Public/SequencerSectionPainter.h @@ -18,6 +18,9 @@ public: /** Constructor */ FSequencerSectionPainter(FSlateWindowElementList& OutDrawElements, const FGeometry& InSectionGeometry, UMovieSceneSection& Section); + /** Virtual destructor */ + virtual ~FSequencerSectionPainter(); + /** Paint the section background with the specified tint override */ virtual int32 PaintSectionBackground(const FLinearColor& Tint) = 0; diff --git a/Engine/Source/Editor/SkeletalMeshEditor/Private/SkeletalMeshEditor.cpp b/Engine/Source/Editor/SkeletalMeshEditor/Private/SkeletalMeshEditor.cpp index 173d3377c8cd..b973c750f296 100644 --- a/Engine/Source/Editor/SkeletalMeshEditor/Private/SkeletalMeshEditor.cpp +++ b/Engine/Source/Editor/SkeletalMeshEditor/Private/SkeletalMeshEditor.cpp @@ -321,7 +321,7 @@ void FSkeletalMeshEditor::FillMeshClickMenu(FMenuBuilder& MenuBuilder, HActor* H Action.CanExecuteAction = FCanExecuteAction::CreateSP(this, &FSkeletalMeshEditor::CanCreateClothing, LodIndex, SectionIndex); MenuBuilder.AddSubMenu( - LOCTEXT("MeshClickMenu_CreateClothing_ToolTip", "Create Clothing Asset from Section"), + LOCTEXT("MeshClickMenu_CreateClothing_Label", "Create Clothing Asset from Section"), LOCTEXT("MeshClickMenu_CreateClothing_ToolTip", "Create a new clothing asset using the selected section as a simulation mesh"), FNewMenuDelegate::CreateSP(this, &FSkeletalMeshEditor::FillCreateClothingMenu, LodIndex, SectionIndex), Action, diff --git a/Engine/Source/Editor/SkeletonEditor/Private/EditableSkeleton.cpp b/Engine/Source/Editor/SkeletonEditor/Private/EditableSkeleton.cpp index a91b39bae314..2f10ad04f578 100644 --- a/Engine/Source/Editor/SkeletonEditor/Private/EditableSkeleton.cpp +++ b/Engine/Source/Editor/SkeletonEditor/Private/EditableSkeleton.cpp @@ -25,6 +25,8 @@ #include "ARFilter.h" #include "AssetRegistryModule.h" #include "SSkeletonWidget.h" +#include "Engine/DataAsset.h" +#include "PreviewCollectionInterface.h" const FString FEditableSkeleton::SocketCopyPasteHeader = TEXT("SocketCopyPasteBuffer"); @@ -1050,10 +1052,13 @@ void FEditableSkeleton::LoadAdditionalPreviewSkeletalMeshes() Skeleton->LoadAdditionalPreviewSkeletalMeshes(); } -void FEditableSkeleton::SetAdditionalPreviewSkeletalMeshes(class UPreviewMeshCollection* InSkeletalMeshes) +void FEditableSkeleton::SetAdditionalPreviewSkeletalMeshes(class UDataAsset* InPreviewCollectionAsset) { - const FScopedTransaction Transaction(LOCTEXT("ChangeSkeletonAdditionalMeshes", "Change Skeleton Additional Meshes")); - Skeleton->SetAdditionalPreviewSkeletalMeshes(InSkeletalMeshes); + if (!InPreviewCollectionAsset || InPreviewCollectionAsset->GetClass()->ImplementsInterface(UPreviewCollectionInterface::StaticClass())) + { + const FScopedTransaction Transaction(LOCTEXT("ChangeSkeletonAdditionalMeshes", "Change Skeleton Additional Meshes")); + Skeleton->SetAdditionalPreviewSkeletalMeshes(InPreviewCollectionAsset); + } } void FEditableSkeleton::RenameRetargetSource(const FName& InOldName, const FName& InNewName) diff --git a/Engine/Source/Editor/SkeletonEditor/Private/EditableSkeleton.h b/Engine/Source/Editor/SkeletonEditor/Private/EditableSkeleton.h index dcbe90c848d0..fb7eeae67988 100644 --- a/Engine/Source/Editor/SkeletonEditor/Private/EditableSkeleton.h +++ b/Engine/Source/Editor/SkeletonEditor/Private/EditableSkeleton.h @@ -52,7 +52,7 @@ public: virtual void SetCurveMetaBoneLinks(const FSmartName& CurveName, TArray& BoneLinks) override; virtual void SetPreviewMesh(class USkeletalMesh* InSkeletalMesh) override; virtual void LoadAdditionalPreviewSkeletalMeshes() override; - virtual void SetAdditionalPreviewSkeletalMeshes(class UPreviewMeshCollection* InSkeletalMeshes) override; + virtual void SetAdditionalPreviewSkeletalMeshes(class UDataAsset* InPreviewCollectionAsset) override; virtual void RenameRetargetSource(const FName& InOldName, const FName& InNewName) override; virtual void AddRetargetSource(const FName& InName, USkeletalMesh* InReferenceMesh) override; virtual void DeleteRetargetSources(const TArray& InRetargetSourceNames) override; diff --git a/Engine/Source/Editor/SkeletonEditor/Private/SkeletonTreeBoneItem.cpp b/Engine/Source/Editor/SkeletonEditor/Private/SkeletonTreeBoneItem.cpp index f842cfc81357..c273aff3de69 100644 --- a/Engine/Source/Editor/SkeletonEditor/Private/SkeletonTreeBoneItem.cpp +++ b/Engine/Source/Editor/SkeletonEditor/Private/SkeletonTreeBoneItem.cpp @@ -381,9 +381,9 @@ FReply FSkeletonTreeBoneItem::HandleDrop(const FDragDropEvent& DragDropEvent) if (DragDropOp.IsValid()) { //Do we have some assets to attach? - if (DragDropOp->AssetData.Num() > 0) + if (DragDropOp->HasAssets()) { - GetSkeletonTree()->AttachAssets(SharedThis(this), DragDropOp->AssetData); + GetSkeletonTree()->AttachAssets(SharedThis(this), DragDropOp->GetAssets()); } return FReply::Handled(); } diff --git a/Engine/Source/Editor/SkeletonEditor/Public/IEditableSkeleton.h b/Engine/Source/Editor/SkeletonEditor/Public/IEditableSkeleton.h index e420947a5a63..29ae04a58d34 100644 --- a/Engine/Source/Editor/SkeletonEditor/Public/IEditableSkeleton.h +++ b/Engine/Source/Editor/SkeletonEditor/Public/IEditableSkeleton.h @@ -111,7 +111,7 @@ public: virtual void LoadAdditionalPreviewSkeletalMeshes() = 0; /** Set the additional skeletal meshes we use when previewing this skeleton */ - virtual void SetAdditionalPreviewSkeletalMeshes(class UPreviewMeshCollection* InSkeletalMeshes) = 0; + virtual void SetAdditionalPreviewSkeletalMeshes(class UDataAsset* InPreviewCollectionAsset) = 0; /** Rename the specified retarget source */ virtual void RenameRetargetSource(const FName& InOldName, const FName& InNewName) = 0; diff --git a/Engine/Source/Editor/SourceControlWindows/Private/SSourceControlHistory.cpp b/Engine/Source/Editor/SourceControlWindows/Private/SSourceControlHistory.cpp index 244cac5ddb7e..3f7c9e8fa416 100644 --- a/Engine/Source/Editor/SourceControlWindows/Private/SSourceControlHistory.cpp +++ b/Engine/Source/Editor/SourceControlWindows/Private/SSourceControlHistory.cpp @@ -206,11 +206,8 @@ static UObject* GetAssetRevisionObject(TSharedPtr HistoryTreeI FString TempPackageName; if (FileRevision.IsValid() && FileRevision->Get(TempPackageName)) // grab the path to a temporary package (where the revision item will be stored) { - // forcibly disable compile on load in case we are loading old blueprints that might try to update/compile - TGuardValue DisableCompileOnLoad(GForceDisableBlueprintCompileOnLoad, true); - // try and load the temporary package - AssetPackage = LoadPackage(NULL, *TempPackageName, LOAD_ForDiff); + AssetPackage = LoadPackage(NULL, *TempPackageName, LOAD_DisableCompileOnLoad); } } // if FileSourceControlState.IsValid() } diff --git a/Engine/Source/Editor/SourceControlWindows/Private/SSourceControlSubmit.cpp b/Engine/Source/Editor/SourceControlWindows/Private/SSourceControlSubmit.cpp index a2eb778a48c8..43827fedf14b 100644 --- a/Engine/Source/Editor/SourceControlWindows/Private/SSourceControlSubmit.cpp +++ b/Engine/Source/Editor/SourceControlWindows/Private/SSourceControlSubmit.cpp @@ -180,6 +180,7 @@ void SSourceControlSubmitWidget::Construct(const FArguments& InArgs) SNew(SCheckBox) .OnCheckStateChanged( this, &SSourceControlSubmitWidget::OnCheckStateChanged_KeepCheckedOut) .IsChecked( this, &SSourceControlSubmitWidget::GetKeepCheckedOut ) + .IsEnabled( this, &SSourceControlSubmitWidget::CanCheckOut ) [ SNew(STextBlock) .Text(NSLOCTEXT("SourceControl.SubmitPanel", "KeepCheckedOut", "Keep Files Checked Out") ) @@ -375,6 +376,13 @@ ECheckBoxState SSourceControlSubmitWidget::GetKeepCheckedOut() const } +bool SSourceControlSubmitWidget::CanCheckOut() const +{ + const ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider(); + return SourceControlProvider.UsesCheckout(); +} + + TSharedRef SSourceControlSubmitWidget::OnGenerateRowForList(TSharedPtr SubmitItem, const TSharedRef& OwnerTable) { TSharedRef Row = diff --git a/Engine/Source/Editor/SourceControlWindows/Private/SSourceControlSubmit.h b/Engine/Source/Editor/SourceControlWindows/Private/SSourceControlSubmit.h index d49f68afa2c0..84be5143c38c 100644 --- a/Engine/Source/Editor/SourceControlWindows/Private/SSourceControlSubmit.h +++ b/Engine/Source/Editor/SourceControlWindows/Private/SSourceControlSubmit.h @@ -146,6 +146,9 @@ private: /** Get the current state of the Keep Checked Out checkbox */ ECheckBoxState GetKeepCheckedOut() const; + /** Check if Provider can checkout files */ + bool CanCheckOut() const; + /** Called by SListView to get a widget corresponding to the supplied item */ TSharedRef OnGenerateRowForList(TSharedPtr SubmitItemData, const TSharedRef& OwnerTable); diff --git a/Engine/Source/Editor/StaticMeshEditor/Private/SStaticMeshEditorViewport.cpp b/Engine/Source/Editor/StaticMeshEditor/Private/SStaticMeshEditorViewport.cpp index 8ed60b935aa6..08d76da0764a 100644 --- a/Engine/Source/Editor/StaticMeshEditor/Private/SStaticMeshEditorViewport.cpp +++ b/Engine/Source/Editor/StaticMeshEditor/Private/SStaticMeshEditorViewport.cpp @@ -223,7 +223,7 @@ void SStaticMeshEditorViewport::UpdatePreviewSocketMeshes() SocketPreviewMeshComponent = NewObject(); PreviewScene->AddComponent(SocketPreviewMeshComponent, FTransform::Identity); SocketPreviewMeshComponents.Add(SocketPreviewMeshComponent); - SocketPreviewMeshComponent->SnapTo(PreviewMeshComponent, Socket->SocketName); + SocketPreviewMeshComponent->AttachToComponent(PreviewMeshComponent, FAttachmentTransformRules::SnapToTargetNotIncludingScale, Socket->SocketName); } else { @@ -232,7 +232,7 @@ void SStaticMeshEditorViewport::UpdatePreviewSocketMeshes() // In case of a socket rename, ensure our preview component is still snapping to the proper socket if (!SocketPreviewMeshComponent->GetAttachSocketName().IsEqual(Socket->SocketName)) { - SocketPreviewMeshComponent->SnapTo(PreviewMeshComponent, Socket->SocketName); + SocketPreviewMeshComponent->AttachToComponent(PreviewMeshComponent, FAttachmentTransformRules::SnapToTargetNotIncludingScale, Socket->SocketName); } // Force component to world update to take into account the new socket position. @@ -295,7 +295,7 @@ void SStaticMeshEditorViewport::UpdatePreviewMesh(UStaticMesh* InStaticMesh, boo { SocketPreviewMeshComponent = NewObject(); SocketPreviewMeshComponent->SetStaticMesh(Socket->PreviewStaticMesh); - SocketPreviewMeshComponent->SnapTo(PreviewMeshComponent, Socket->SocketName); + SocketPreviewMeshComponent->AttachToComponent(PreviewMeshComponent, FAttachmentTransformRules::SnapToTargetNotIncludingScale, Socket->SocketName); SocketPreviewMeshComponents.Add(SocketPreviewMeshComponent); PreviewScene->AddComponent(SocketPreviewMeshComponent, FTransform::Identity); } @@ -356,7 +356,7 @@ void SStaticMeshEditorViewport::SetViewModeVertexColor() } if (FEngineAnalytics::IsAvailable()) { - FEngineAnalytics::GetProvider().RecordEvent(TEXT("Editor.Usage.StaticMesh.Toolbar"), FAnalyticsEventAttribute(TEXT("VertexColors"), AnalyticsConversion::ToString(EditorViewportClient->EngineShowFlags.VertexColors))); + FEngineAnalytics::GetProvider().RecordEvent(TEXT("Editor.Usage.StaticMesh.Toolbar"), FAnalyticsEventAttribute(TEXT("VertexColors"), static_cast(EditorViewportClient->EngineShowFlags.VertexColors))); } SceneViewport->Invalidate(); } diff --git a/Engine/Source/Editor/StaticMeshEditor/Private/StaticMeshEditor.cpp b/Engine/Source/Editor/StaticMeshEditor/Private/StaticMeshEditor.cpp index 8011f47cbdcd..ee78018e8832 100644 --- a/Engine/Source/Editor/StaticMeshEditor/Private/StaticMeshEditor.cpp +++ b/Engine/Source/Editor/StaticMeshEditor/Private/StaticMeshEditor.cpp @@ -1099,6 +1099,7 @@ void FStaticMeshEditor::RefreshTool() UpdateLODStats(LODIndex); } + OnSelectedLODChangedResetOnRefresh.Clear(); bool bForceRefresh = true; StaticMeshDetailsView->SetObject( StaticMesh, bForceRefresh ); @@ -1206,11 +1207,22 @@ void FStaticMeshEditor::ComboBoxSelectionChanged( TSharedPtr NewSelecti void FStaticMeshEditor::LODLevelsSelectionChanged( TSharedPtr NewSelection, ESelectInfo::Type /*SelectInfo*/ ) { - int32 CurrentLOD = GetCurrentLODLevel(); - + int32 CurrentLOD = 0; + LODLevels.Find(LODLevelCombo->GetSelectedItem(), CurrentLOD); + if (GetStaticMeshComponent() != nullptr) + { + GetStaticMeshComponent()->ForcedLodModel = CurrentLOD; + } UpdateLODStats( CurrentLOD > 0? CurrentLOD - 1 : 0 ); - Viewport->ForceLODLevel(CurrentLOD); + if (OnSelectedLODChanged.IsBound()) + { + OnSelectedLODChanged.Broadcast(); + } + if (OnSelectedLODChangedResetOnRefresh.IsBound()) + { + OnSelectedLODChangedResetOnRefresh.Broadcast(); + } } int32 FStaticMeshEditor::GetCurrentUVChannel() @@ -1225,13 +1237,21 @@ int32 FStaticMeshEditor::GetCurrentLODLevel() { int32 Index = 0; LODLevels.Find(LODLevelCombo->GetSelectedItem(), Index); + if (GetStaticMeshComponent() != nullptr) + { + if (GetStaticMeshComponent()->ForcedLodModel != Index) + { + LODLevelCombo->SetSelectedItem(LODLevels[GetStaticMeshComponent()->ForcedLodModel]); + LODLevels.Find(LODLevelCombo->GetSelectedItem(), Index); + } + } return Index; } int32 FStaticMeshEditor::GetCurrentLODIndex() { - int32 Index = LODLevels.Find(LODLevelCombo->GetSelectedItem()); + int32 Index = GetCurrentLODLevel(); return Index == 0? 0 : Index - 1; } diff --git a/Engine/Source/Editor/StaticMeshEditor/Private/StaticMeshEditor.h b/Engine/Source/Editor/StaticMeshEditor/Private/StaticMeshEditor.h index 55af55c0c208..15c4fe349fee 100644 --- a/Engine/Source/Editor/StaticMeshEditor/Private/StaticMeshEditor.h +++ b/Engine/Source/Editor/StaticMeshEditor/Private/StaticMeshEditor.h @@ -129,6 +129,24 @@ public: /** Get the active view mode */ virtual EViewModeIndex GetViewMode() const override; + virtual void RegisterOnSelectedLODChanged(const FOnSelectedLODChanged &Delegate, bool UnregisterOnRefresh) override + { + if (!UnregisterOnRefresh) + { + OnSelectedLODChanged.Add(Delegate); + } + else + { + OnSelectedLODChangedResetOnRefresh.Add(Delegate); + } + } + + virtual void UnRegisterOnSelectedLODChanged(void* Thing) override + { + OnSelectedLODChanged.RemoveAll(Thing); + OnSelectedLODChangedResetOnRefresh.RemoveAll(Thing); + } + private: TSharedRef SpawnTab_Viewport(const FSpawnTabArgs& Args); TSharedRef SpawnTab_Properties(const FSpawnTabArgs& Args); @@ -331,6 +349,9 @@ private: const float MinPrimSize; const FVector OverlapNudge; + FOnSelectedLODChangedMulticaster OnSelectedLODChanged; + FOnSelectedLODChangedMulticaster OnSelectedLODChangedResetOnRefresh; + /** The tab ids for all the tabs used */ static const FName ViewportTabId; static const FName PropertiesTabId; diff --git a/Engine/Source/Editor/StaticMeshEditor/Private/StaticMeshEditorTools.cpp b/Engine/Source/Editor/StaticMeshEditor/Private/StaticMeshEditorTools.cpp index f9779d4e51ed..b2e29ce34112 100644 --- a/Engine/Source/Editor/StaticMeshEditor/Private/StaticMeshEditorTools.cpp +++ b/Engine/Source/Editor/StaticMeshEditor/Private/StaticMeshEditorTools.cpp @@ -1337,6 +1337,7 @@ void FMeshSectionSettingsLayout::AddToCategory( IDetailCategoryBuilder& Category SectionListDelegates.OnSectionChanged.BindSP(this, &FMeshSectionSettingsLayout::OnSectionChanged); SectionListDelegates.OnGenerateCustomNameWidgets.BindSP(this, &FMeshSectionSettingsLayout::OnGenerateCustomNameWidgetsForSection); SectionListDelegates.OnGenerateCustomSectionWidgets.BindSP(this, &FMeshSectionSettingsLayout::OnGenerateCustomSectionWidgetsForSection); + SectionListDelegates.OnGenerateLodComboBox.BindSP(this, &FMeshSectionSettingsLayout::OnGenerateLodComboBoxForSectionList); SectionListDelegates.OnCopySectionList.BindSP(this, &FMeshSectionSettingsLayout::OnCopySectionList, LODIndex); SectionListDelegates.OnCanCopySectionList.BindSP(this, &FMeshSectionSettingsLayout::OnCanCopySectionList, LODIndex); @@ -1345,7 +1346,9 @@ void FMeshSectionSettingsLayout::AddToCategory( IDetailCategoryBuilder& Category SectionListDelegates.OnCanCopySectionItem.BindSP(this, &FMeshSectionSettingsLayout::OnCanCopySectionItem); SectionListDelegates.OnPasteSectionItem.BindSP(this, &FMeshSectionSettingsLayout::OnPasteSectionItem); - CategoryBuilder.AddCustomBuilder(MakeShareable(new FSectionList(CategoryBuilder.GetParentLayout(), SectionListDelegates, (LODIndex > 0)))); + CategoryBuilder.AddCustomBuilder(MakeShareable(new FSectionList(CategoryBuilder.GetParentLayout(), SectionListDelegates, false, 61, LODIndex))); + + StaticMeshEditor.RegisterOnSelectedLODChanged(FOnSelectedLODChanged::CreateSP(this, &FMeshSectionSettingsLayout::UpdateLODCategoryVisibility), true); } void FMeshSectionSettingsLayout::OnCopySectionList(int32 CurrentLODIndex) @@ -1656,9 +1659,10 @@ TSharedRef FMeshSectionSettingsLayout::OnGenerateCustomNameWidgetsForSe TSharedRef FMeshSectionSettingsLayout::OnGenerateCustomSectionWidgetsForSection(int32 ForLODIndex, int32 SectionIndex) { - return SNew(SVerticalBox) - +SVerticalBox::Slot() - .AutoHeight() + return SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + .Padding(2, 0, 2, 0) [ SNew(SCheckBox) .IsChecked(this, &FMeshSectionSettingsLayout::DoesSectionCastShadow, SectionIndex) @@ -1669,9 +1673,9 @@ TSharedRef FMeshSectionSettingsLayout::OnGenerateCustomSectionWidgetsFo .Text(LOCTEXT("CastShadow", "Cast Shadow")) ] ] - +SVerticalBox::Slot() - .AutoHeight() - .Padding(0,2,0,0) + +SHorizontalBox::Slot() + .AutoWidth() + .Padding(2,0,2,0) [ SNew(SCheckBox) .IsEnabled(this, &FMeshSectionSettingsLayout::SectionCollisionEnabled) @@ -1832,6 +1836,121 @@ void FMeshSectionSettingsLayout::CallPostEditChange(UProperty* PropertyChanged/* StaticMeshEditor.RefreshViewport(); } +void FMeshSectionSettingsLayout::SetCurrentLOD(int32 NewLodIndex) +{ + if (StaticMeshEditor.GetStaticMeshComponent() == nullptr || LodCategoriesPtr == nullptr) + { + return; + } + int32 CurrentDisplayLOD = StaticMeshEditor.GetStaticMeshComponent()->ForcedLodModel; + int32 RealCurrentDisplayLOD = CurrentDisplayLOD == 0 ? 0 : CurrentDisplayLOD - 1; + int32 RealNewLOD = NewLodIndex == 0 ? 0 : NewLodIndex - 1; + + if (CurrentDisplayLOD == NewLodIndex || !LodCategoriesPtr->IsValidIndex(RealCurrentDisplayLOD) || !LodCategoriesPtr->IsValidIndex(RealNewLOD)) + { + return; + } + (*LodCategoriesPtr)[RealCurrentDisplayLOD]->SetCategoryVisibility(false); + (*LodCategoriesPtr)[RealNewLOD]->SetCategoryVisibility(true); + StaticMeshEditor.GetStaticMeshComponent()->SetForcedLodModel(NewLodIndex); + + //Reset the preview section since we do not edit the same LOD + StaticMeshEditor.GetStaticMeshComponent()->SetSectionPreview(INDEX_NONE); + StaticMeshEditor.GetStaticMeshComponent()->SelectedEditorSection = INDEX_NONE; +} + +void FMeshSectionSettingsLayout::UpdateLODCategoryVisibility() +{ + bool bAutoLod = false; + if (StaticMeshEditor.GetStaticMeshComponent() != nullptr) + { + bAutoLod = StaticMeshEditor.GetStaticMeshComponent()->ForcedLodModel == 0; + } + int32 CurrentDisplayLOD = bAutoLod ? 0 : StaticMeshEditor.GetStaticMeshComponent()->ForcedLodModel - 1; + + if (LodCategoriesPtr != nullptr && LodCategoriesPtr->IsValidIndex(CurrentDisplayLOD) && StaticMeshEditor.GetStaticMesh()) + { + int32 StaticMeshLodNumber = StaticMeshEditor.GetStaticMesh()->GetNumLODs(); + for (int32 LodCategoryIndex = 0; LodCategoryIndex < StaticMeshLodNumber; ++LodCategoryIndex) + { + if (!LodCategoriesPtr->IsValidIndex(LodCategoryIndex)) + { + break; + } + (*LodCategoriesPtr)[LodCategoryIndex]->SetCategoryVisibility(CurrentDisplayLOD == LodCategoryIndex); + } + } +} + +FText FMeshSectionSettingsLayout::GetCurrentLodName() const +{ + bool bAutoLod = false; + if (StaticMeshEditor.GetStaticMeshComponent() != nullptr) + { + bAutoLod = StaticMeshEditor.GetStaticMeshComponent()->ForcedLodModel == 0; + } + int32 CurrentDisplayLOD = bAutoLod ? 0 : StaticMeshEditor.GetStaticMeshComponent()->ForcedLodModel - 1; + return FText::FromString(bAutoLod ? FString(TEXT("Auto (LOD0)")) : (FString(TEXT("LOD")) + FString::FromInt(CurrentDisplayLOD))); +} + +FText FMeshSectionSettingsLayout::GetCurrentLodTooltip() const +{ + if (StaticMeshEditor.GetStaticMeshComponent() != nullptr && StaticMeshEditor.GetStaticMeshComponent()->ForcedLodModel == 0) + { + return FText::FromString(TEXT("LOD0 is edit when selecting Auto LOD")); + } + return FText::GetEmpty(); +} + +TSharedRef FMeshSectionSettingsLayout::OnGenerateLodComboBoxForSectionList(int32 LodIndex) +{ + return SNew(SComboButton) + .OnGetMenuContent(this, &FMeshSectionSettingsLayout::OnGenerateLodMenuForSectionList, LodIndex) + .VAlign(VAlign_Center) + .ContentPadding(2) + .ButtonContent() + [ + SNew(STextBlock) + .Font(IDetailLayoutBuilder::GetDetailFont()) + .Text(this, &FMeshSectionSettingsLayout::GetCurrentLodName) + .ToolTipText(this, &FMeshSectionSettingsLayout::GetCurrentLodTooltip) + ]; +} + +TSharedRef FMeshSectionSettingsLayout::OnGenerateLodMenuForSectionList(int32 LodIndex) +{ + UStaticMesh* StaticMesh = StaticMeshEditor.GetStaticMesh(); + + if (StaticMesh == nullptr) + { + return SNullWidget::NullWidget; + } + + bool bAutoLod = false; + if (StaticMeshEditor.GetStaticMeshComponent() != nullptr) + { + bAutoLod = StaticMeshEditor.GetStaticMeshComponent()->ForcedLodModel == 0; + } + const int32 StaticMeshLODCount = StaticMesh->GetNumLODs(); + if (StaticMeshLODCount < 2) + { + return SNullWidget::NullWidget; + } + FMenuBuilder MenuBuilder(true, NULL); + + FText AutoLodText = FText::FromString((TEXT("Auto LOD"))); + FUIAction AutoLodAction(FExecuteAction::CreateSP(this, &FMeshSectionSettingsLayout::SetCurrentLOD, 0)); + MenuBuilder.AddMenuEntry(AutoLodText, LOCTEXT("OnGenerateLodMenuForSectionList_Auto_ToolTip", "LOD0 is edit when selecting Auto LOD"), FSlateIcon(), AutoLodAction); + // Add a menu item for each texture. Clicking on the texture will display it in the content browser + for (int32 AllLodIndex = 0; AllLodIndex < StaticMeshLODCount; ++AllLodIndex) + { + FText LODLevelString = FText::FromString((TEXT("LOD ") + FString::FromInt(AllLodIndex))); + FUIAction Action(FExecuteAction::CreateSP(this, &FMeshSectionSettingsLayout::SetCurrentLOD, AllLodIndex + 1)); + MenuBuilder.AddMenuEntry(LODLevelString, FText::GetEmpty(), FSlateIcon(), Action); + } + + return MenuBuilder.MakeWidget(); +} ////////////////////////////////////////////////////////////////////////// // FMeshMaterialLayout @@ -1914,7 +2033,7 @@ void FMeshMaterialsLayout::AddToCategory(IDetailCategoryBuilder& CategoryBuilder MaterialListDelegates.OnCanCopyMaterialItem.BindSP(this, &FMeshMaterialsLayout::OnCanCopyMaterialItem); MaterialListDelegates.OnPasteMaterialItem.BindSP(this, &FMeshMaterialsLayout::OnPasteMaterialItem); - CategoryBuilder.AddCustomBuilder(MakeShareable(new FMaterialList(CategoryBuilder.GetParentLayout(), MaterialListDelegates))); + CategoryBuilder.AddCustomBuilder(MakeShareable(new FMaterialList(CategoryBuilder.GetParentLayout(), MaterialListDelegates, false, true, true))); } void FMeshMaterialsLayout::OnCopyMaterialList() @@ -1960,7 +2079,16 @@ void FMeshMaterialsLayout::OnPasteMaterialList() FScopedTransaction Transaction(LOCTEXT("StaticMeshToolChangedPasteMaterialList", "Pasted material list")); GetStaticMesh().Modify(); - FJsonObjectConverter::JsonValueToUProperty(RootJsonValue, Property, &GetStaticMesh().StaticMaterials, 0, 0); + TArray TempMaterials; + FJsonObjectConverter::JsonValueToUProperty(RootJsonValue, Property, &TempMaterials, 0, 0); + //Do not change the number of material in the array + for (int32 MaterialIndex = 0; MaterialIndex < TempMaterials.Num(); ++MaterialIndex) + { + if (GetStaticMesh().StaticMaterials.IsValidIndex(MaterialIndex)) + { + GetStaticMesh().StaticMaterials[MaterialIndex].MaterialInterface = TempMaterials[MaterialIndex].MaterialInterface; + } + } CallPostEditChange(Property); } @@ -2016,7 +2144,9 @@ void FMeshMaterialsLayout::OnPasteMaterialItem(int32 CurrentSlot) if (GetStaticMesh().StaticMaterials.IsValidIndex(CurrentSlot)) { - FJsonObjectConverter::JsonObjectToUStruct(RootJsonObject.ToSharedRef(), FSkeletalMaterial::StaticStruct(), &GetStaticMesh().StaticMaterials[CurrentSlot], 0, 0); + FStaticMaterial TmpStaticMaterial; + FJsonObjectConverter::JsonObjectToUStruct(RootJsonObject.ToSharedRef(), FStaticMaterial::StaticStruct(), &TmpStaticMaterial, 0, 0); + GetStaticMesh().StaticMaterials[CurrentSlot].MaterialInterface = TmpStaticMaterial.MaterialInterface; } CallPostEditChange(Property); @@ -2074,15 +2204,18 @@ void FMeshMaterialsLayout::OnMaterialChanged(UMaterialInterface* NewMaterial, UM if (StaticMesh.StaticMaterials.IsValidIndex(MaterialIndex)) { StaticMesh.StaticMaterials[MaterialIndex].MaterialInterface = NewMaterial; - //Set the Material slot name to a good default one - if (StaticMesh.StaticMaterials[MaterialIndex].MaterialSlotName == NAME_None) + if (NewMaterial != nullptr) { - StaticMesh.StaticMaterials[MaterialIndex].MaterialSlotName = NewMaterial->GetFName(); - } - //Set the original fbx material name so we can re-import correctly - if (StaticMesh.StaticMaterials[MaterialIndex].ImportedMaterialSlotName == NAME_None) - { - StaticMesh.StaticMaterials[MaterialIndex].ImportedMaterialSlotName = NewMaterial->GetFName(); + //Set the Material slot name to a good default one + if (StaticMesh.StaticMaterials[MaterialIndex].MaterialSlotName == NAME_None) + { + StaticMesh.StaticMaterials[MaterialIndex].MaterialSlotName = NewMaterial->GetFName(); + } + //Set the original fbx material name so we can re-import correctly + if (StaticMesh.StaticMaterials[MaterialIndex].ImportedMaterialSlotName == NAME_None) + { + StaticMesh.StaticMaterials[MaterialIndex].ImportedMaterialSlotName = NewMaterial->GetFName(); + } } } @@ -2759,11 +2892,19 @@ void FLevelOfDetailSettingsLayout::AddLODLevelCategories( IDetailLayoutBuilder& { FString CategoryName = FString(TEXT("StaticMeshMaterials")); - IDetailCategoryBuilder& MaterialsCategory = DetailBuilder.EditCategory(*CategoryName, LOCTEXT("StaticMeshMaterialsLabel", "Materials"), ECategoryPriority::Important); + IDetailCategoryBuilder& MaterialsCategory = DetailBuilder.EditCategory(*CategoryName, LOCTEXT("StaticMeshMaterialsLabel", "Material Slots"), ECategoryPriority::Important); MaterialsLayoutWidget = MakeShareable(new FMeshMaterialsLayout(StaticMeshEditor)); MaterialsLayoutWidget->AddToCategory(MaterialsCategory); } + + int32 CurrentLodIndex = 0; + + if (StaticMeshEditor.GetStaticMeshComponent() != nullptr) + { + CurrentLodIndex = StaticMeshEditor.GetStaticMeshComponent()->ForcedLodModel; + } + LodCategories.Empty(StaticMeshLODCount); // Create information panel for each LOD level. for(int32 LODIndex = 0; LODIndex < StaticMeshLODCount; ++LODIndex) { @@ -2808,27 +2949,10 @@ void FLevelOfDetailSettingsLayout::AddLODLevelCategories( IDetailLayoutBuilder& FString CategoryName = FString(TEXT("LOD")); CategoryName.AppendInt( LODIndex ); - FText LODLevelString = FText::Format( LOCTEXT("LODLevel", "LOD{0}"), FText::AsNumber( LODIndex ) ); + FText LODLevelString = FText::FromString(FString(TEXT("LOD Sections (LOD")) + FString::FromInt(LODIndex) + TEXT(")") ); IDetailCategoryBuilder& LODCategory = DetailBuilder.EditCategory( *CategoryName, LODLevelString, ECategoryPriority::Important ); - - if (LODIndex != 0) - { - LODCategory.AddCustomRow( LOCTEXT("RemoveLOD", "Remove LOD") ) - .ValueContent() - .HAlign(HAlign_Left) - [ - SNew(SButton) - .OnClicked(this, &FLevelOfDetailSettingsLayout::OnRemoveLOD, LODIndex) - .IsEnabled(this, &FLevelOfDetailSettingsLayout::CanRemoveLOD, LODIndex) - .ToolTipText( LOCTEXT("RemoveLOD_ToolTip", "Removes this LOD from the Static Mesh") ) - [ - SNew(STextBlock) - .Text( LOCTEXT("RemoveLOD", "Remove LOD") ) - .Font( DetailBuilder.GetDetailFont() ) - ] - ]; - } + LodCategories.Add(&LODCategory); LODCategory.HeaderContent ( @@ -2865,7 +2989,7 @@ void FLevelOfDetailSettingsLayout::AddLODLevelCategories( IDetailLayoutBuilder& ); - SectionSettingsWidgets[ LODIndex ] = MakeShareable( new FMeshSectionSettingsLayout( StaticMeshEditor, LODIndex ) ); + SectionSettingsWidgets[ LODIndex ] = MakeShareable( new FMeshSectionSettingsLayout( StaticMeshEditor, LODIndex, LodCategories) ); SectionSettingsWidgets[ LODIndex ]->AddToCategory( LODCategory ); LODCategory.AddCustomRow(( LOCTEXT("ScreenSizeRow", "ScreenSize"))) @@ -2898,6 +3022,26 @@ void FLevelOfDetailSettingsLayout::AddLODLevelCategories( IDetailLayoutBuilder& LODCategory.AddCustomBuilder( ReductionSettingsWidgets[LODIndex].ToSharedRef() ); } + if (LODIndex != 0) + { + LODCategory.AddCustomRow( LOCTEXT("RemoveLOD", "Remove LOD") ) + .ValueContent() + .HAlign(HAlign_Left) + [ + SNew(SButton) + .OnClicked(this, &FLevelOfDetailSettingsLayout::OnRemoveLOD, LODIndex) + .IsEnabled(this, &FLevelOfDetailSettingsLayout::CanRemoveLOD, LODIndex) + .ToolTipText( LOCTEXT("RemoveLOD_ToolTip", "Removes this LOD from the Static Mesh") ) + [ + SNew(STextBlock) + .Text( LOCTEXT("RemoveLOD", "Remove LOD") ) + .Font( DetailBuilder.GetDetailFont() ) + ] + ]; + } + + LODCategory.SetCategoryVisibility((CurrentLodIndex == 0 ? 0 : CurrentLodIndex - 1) == LODIndex); + } } diff --git a/Engine/Source/Editor/StaticMeshEditor/Private/StaticMeshEditorTools.h b/Engine/Source/Editor/StaticMeshEditor/Private/StaticMeshEditorTools.h index e9f9382a3b35..4ae3e81d9917 100644 --- a/Engine/Source/Editor/StaticMeshEditor/Private/StaticMeshEditorTools.h +++ b/Engine/Source/Editor/StaticMeshEditor/Private/StaticMeshEditorTools.h @@ -252,9 +252,10 @@ private: class FMeshSectionSettingsLayout : public TSharedFromThis { public: - FMeshSectionSettingsLayout( IStaticMeshEditor& InStaticMeshEditor, int32 InLODIndex ) + FMeshSectionSettingsLayout( IStaticMeshEditor& InStaticMeshEditor, int32 InLODIndex, TArray &InLodCategories) : StaticMeshEditor( InStaticMeshEditor ) , LODIndex( InLODIndex ) + , LodCategoriesPtr(&InLodCategories) {} virtual ~FMeshSectionSettingsLayout(); @@ -319,9 +320,22 @@ private: void OnSectionIsolatedChanged(ECheckBoxState NewState, int32 SectionIndex); void CallPostEditChange(UProperty* PropertyChanged=nullptr); + + TSharedRef OnGenerateLodComboBoxForSectionList(int32 LodIndex); + /* + * Generate the context menu to choose the LOD we will display the section list + */ + TSharedRef OnGenerateLodMenuForSectionList(int32 LodIndex); + void UpdateLODCategoryVisibility(); + FText GetCurrentLodName() const; + FText GetCurrentLodTooltip() const; + + void SetCurrentLOD(int32 NewLodIndex); IStaticMeshEditor& StaticMeshEditor; int32 LODIndex; + + TArray *LodCategoriesPtr; }; struct FSectionLocalizer @@ -503,4 +517,6 @@ private: bool bBuildSettingsExpanded[MAX_STATIC_MESH_LODS]; bool bReductionSettingsExpanded[MAX_STATIC_MESH_LODS]; bool bSectionSettingsExpanded[MAX_STATIC_MESH_LODS]; + + TArray LodCategories; }; diff --git a/Engine/Source/Editor/StaticMeshEditor/Private/StaticMeshEditorViewportClient.cpp b/Engine/Source/Editor/StaticMeshEditor/Private/StaticMeshEditorViewportClient.cpp index fa2bb1cbbb4b..0b788a2b36ab 100644 --- a/Engine/Source/Editor/StaticMeshEditor/Private/StaticMeshEditorViewportClient.cpp +++ b/Engine/Source/Editor/StaticMeshEditor/Private/StaticMeshEditorViewportClient.cpp @@ -544,8 +544,8 @@ void FStaticMeshEditorViewportClient::Draw(const FSceneView* View,FPrimitiveDraw EdgeVertices[ 1 ] = SelectedEdgeVertices[VertexIndex + 1]; PDI->DrawLine( - StaticMeshComponent->ComponentToWorld.TransformPosition( EdgeVertices[ 0 ] ), - StaticMeshComponent->ComponentToWorld.TransformPosition( EdgeVertices[ 1 ] ), + StaticMeshComponent->GetComponentTransform().TransformPosition( EdgeVertices[ 0 ] ), + StaticMeshComponent->GetComponentTransform().TransformPosition( EdgeVertices[ 1 ] ), FColor( 255, 255, 0 ), SDPG_World ); } @@ -558,12 +558,12 @@ void FStaticMeshEditorViewportClient::Draw(const FSceneView* View,FPrimitiveDraw FIndexArrayView Indices = LODModel.IndexBuffer.GetArrayView(); uint32 NumIndices = Indices.Num(); - FMatrix LocalToWorldInverseTranspose = StaticMeshComponent->ComponentToWorld.ToMatrixWithScale().InverseFast().GetTransposed(); + FMatrix LocalToWorldInverseTranspose = StaticMeshComponent->GetComponentTransform().ToMatrixWithScale().InverseFast().GetTransposed(); for (uint32 i = 0; i < NumIndices; i++) { const FVector& VertexPos = LODModel.PositionVertexBuffer.VertexPosition( Indices[i] ); - const FVector WorldPos = StaticMeshComponent->ComponentToWorld.TransformPosition( VertexPos ); + const FVector WorldPos = StaticMeshComponent->GetComponentTransform().TransformPosition( VertexPos ); const FVector& Normal = LODModel.VertexBuffer.VertexTangentZ( Indices[i] ); const FVector& Binormal = LODModel.VertexBuffer.VertexTangentY( Indices[i] ); const FVector& Tangent = LODModel.VertexBuffer.VertexTangentX( Indices[i] ); @@ -599,7 +599,7 @@ void FStaticMeshEditorViewportClient::Draw(const FSceneView* View,FPrimitiveDraw if( bShowPivot ) { - FUnrealEdUtils::DrawWidget(View, PDI, StaticMeshComponent->ComponentToWorld.ToMatrixWithScale(), 0, 0, EAxisList::All, EWidgetMovementMode::WMM_Translate, false); + FUnrealEdUtils::DrawWidget(View, PDI, StaticMeshComponent->GetComponentTransform().ToMatrixWithScale(), 0, 0, EAxisList::All, EWidgetMovementMode::WMM_Translate, false); } if( bDrawAdditionalData ) @@ -620,7 +620,7 @@ void FStaticMeshEditorViewportClient::Draw(const FSceneView* View,FPrimitiveDraw if (StaticMesh->NavCollision && StaticMesh->NavCollision->bIsDynamicObstacle) { // Draw the static mesh's body setup (simple collision) - FTransform GeomTransform(StaticMeshComponent->ComponentToWorld); + FTransform GeomTransform(StaticMeshComponent->GetComponentTransform()); FColor NavCollisionColor = FColor(118, 84, 255, 255); StaticMesh->NavCollision->DrawSimpleGeom(PDI, GeomTransform, FColorList::LimeGreen); } @@ -1028,7 +1028,7 @@ void FStaticMeshEditorViewportClient::ProcessClick(class FSceneView& InView, cla const FVector TriangleNormal = (CA ^ BA).GetSafeNormal(); // Transform the view position from world to component space - const FVector ComponentSpaceViewOrigin = StaticMeshComponent->ComponentToWorld.InverseTransformPosition( View->ViewMatrices.GetViewOrigin()); + const FVector ComponentSpaceViewOrigin = StaticMeshComponent->GetComponentTransform().InverseTransformPosition( View->ViewMatrices.GetViewOrigin()); // Determine which side of the triangle's plane that the view position lies on. bIsBackFacing = (FVector::PointPlaneDist( ComponentSpaceViewOrigin, A, TriangleNormal) < 0.0f); @@ -1062,8 +1062,8 @@ void FStaticMeshEditorViewportClient::ProcessClick(class FSceneView& InView, cla } else { - FVector WorldSpaceEdgeStart( StaticMeshComponent->ComponentToWorld.TransformPosition( EdgeVertices[ 0 ] ) ); - FVector WorldSpaceEdgeEnd( StaticMeshComponent->ComponentToWorld.TransformPosition( EdgeVertices[ 1 ] ) ); + FVector WorldSpaceEdgeStart( StaticMeshComponent->GetComponentTransform().TransformPosition( EdgeVertices[ 0 ] ) ); + FVector WorldSpaceEdgeEnd( StaticMeshComponent->GetComponentTransform().TransformPosition( EdgeVertices[ 1 ] ) ); // Determine the mesh edge that's closest to the ray cast through the eye towards the click location FVector ClosestPointToEdgeOnClickLine; @@ -1219,7 +1219,12 @@ void FStaticMeshEditorViewportClient::OnAssetViewerSettingsChanged(const FName& { if (InPropertyName == GET_MEMBER_NAME_CHECKED(FPreviewSceneProfile, bPostProcessingEnabled) || InPropertyName == NAME_None) { - SetAdvancedShowFlagsForScene(UAssetViewerSettings::Get()->Profiles[AdvancedPreviewScene->GetCurrentProfileIndex()].bPostProcessingEnabled); + UAssetViewerSettings* Settings = UAssetViewerSettings::Get(); + const int32 ProfileIndex = AdvancedPreviewScene->GetCurrentProfileIndex(); + if (Settings->Profiles.IsValidIndex(ProfileIndex)) + { + SetAdvancedShowFlagsForScene(Settings->Profiles[ProfileIndex].bPostProcessingEnabled); + } } } diff --git a/Engine/Source/Editor/StaticMeshEditor/Public/IStaticMeshEditor.h b/Engine/Source/Editor/StaticMeshEditor/Public/IStaticMeshEditor.h index 861c7e2a0259..faa025ab019e 100644 --- a/Engine/Source/Editor/StaticMeshEditor/Public/IStaticMeshEditor.h +++ b/Engine/Source/Editor/StaticMeshEditor/Public/IStaticMeshEditor.h @@ -11,6 +11,11 @@ class UStaticMesh; class UStaticMeshComponent; class UStaticMeshSocket; + +DECLARE_MULTICAST_DELEGATE(FOnSelectedLODChangedMulticaster); + +typedef FOnSelectedLODChangedMulticaster::FDelegate FOnSelectedLODChanged; + /** * Public interface to Static Mesh Editor */ @@ -220,6 +225,11 @@ public: /** Get the active view mode */ virtual EViewModeIndex GetViewMode() const = 0; + + /* Register callback to be able to be notify when the select LOD is change */ + virtual void RegisterOnSelectedLODChanged(const FOnSelectedLODChanged &Delegate, bool UnregisterOnRefresh) = 0; + /* Unregister callback to free up the ressources */ + virtual void UnRegisterOnSelectedLODChanged(void* Thing) = 0; }; diff --git a/Engine/Source/Editor/StatsViewer/Private/SStatsViewer.cpp b/Engine/Source/Editor/StatsViewer/Private/SStatsViewer.cpp index b15bb72d1f59..e2185013c397 100644 --- a/Engine/Source/Editor/StatsViewer/Private/SStatsViewer.cpp +++ b/Engine/Source/Editor/StatsViewer/Private/SStatsViewer.cpp @@ -240,7 +240,7 @@ SStatsViewer::~SStatsViewer() } /** Helper function to get the string of a cell as it is being presented to the user */ -static FString GetCellString( const TSharedPtr Cell ) +static FString GetCellString( const TSharedPtr Cell, bool bGetRawValue = false ) { FString String = TEXT(""); @@ -262,7 +262,7 @@ static FString GetCellString( const TSharedPtr Cell ) // not an object, but maybe supported if( FStatsCustomColumn::SupportsProperty(PropertyHandle->GetProperty()) ) { - String = FStatsCustomColumn::GetPropertyAsText(PropertyHandle).ToString(); + String = FStatsCustomColumn::GetPropertyAsText(PropertyHandle, bGetRawValue).ToString(); } // still no name? will have to default to the 'value as string' @@ -476,7 +476,7 @@ FReply SStatsViewer::OnExportClicked() TSharedRef< IPropertyTableRow > Row = Rows[RowIndex]; for( TSharedPtr< IPropertyTableCell > Cell = PropertyTable->GetFirstCellInRow(Row); Cell.IsValid(); Cell = PropertyTable->GetNextCellInRow(Cell.ToSharedRef()) ) { - FString CellData = GetCellString( Cell ); + FString CellData = GetCellString( Cell , true ); CellData.ReplaceInline( *Delimiter, TEXT(" ") ); Data += CellData + Delimiter; } diff --git a/Engine/Source/Editor/StatsViewer/Private/StatsCustomColumn.cpp b/Engine/Source/Editor/StatsViewer/Private/StatsCustomColumn.cpp index 51471a0ff6e9..259d7244e387 100644 --- a/Engine/Source/Editor/StatsViewer/Private/StatsCustomColumn.cpp +++ b/Engine/Source/Editor/StatsViewer/Private/StatsCustomColumn.cpp @@ -135,10 +135,23 @@ bool FStatsCustomColumn::SupportsProperty( UProperty* Property ) return false; } -FText FStatsCustomColumn::GetPropertyAsText( const TSharedPtr< IPropertyHandle > PropertyHandle ) +FText FStatsCustomColumn::GetPropertyAsText( const TSharedPtr< IPropertyHandle > PropertyHandle , bool bGetRawValue ) { FText Text; + //Create a formatting option that doesn't group digits for readability. This will generate pure number strings. + FNumberFormattingOptions RawFormattingOptions; + FNumberFormattingOptions *RFOPointer = nullptr; + + RawFormattingOptions.SetUseGrouping(false); + + //Use ungrouped formatting option if requested by user. Leaving the pointer NULL will trigger usage of Locale default settings. + if (bGetRawValue) + { + RFOPointer = &RawFormattingOptions; + } + + if( PropertyHandle->GetProperty()->IsA( UIntProperty::StaticClass() ) ) { int32 IntValue = INT_MAX; @@ -149,7 +162,7 @@ FText FStatsCustomColumn::GetPropertyAsText( const TSharedPtr< IPropertyHandle > } else { - Text = FText::AsNumber( IntValue ); + Text = FText::AsNumber( IntValue, RFOPointer); } } else if( PropertyHandle->GetProperty()->IsA( UFloatProperty::StaticClass() ) ) @@ -162,7 +175,7 @@ FText FStatsCustomColumn::GetPropertyAsText( const TSharedPtr< IPropertyHandle > } else { - Text = FText::AsNumber( FloatValue ); + Text = FText::AsNumber( FloatValue, RFOPointer); } } else if( PropertyHandle->GetProperty()->IsA( UStructProperty::StaticClass() ) ) @@ -185,7 +198,7 @@ FText FStatsCustomColumn::GetPropertyAsText( const TSharedPtr< IPropertyHandle > } } - if( PropertyHandle->GetProperty()->HasMetaData("Unit") ) + if (PropertyHandle->GetProperty()->HasMetaData("Unit") && !bGetRawValue) { FFormatNamedArguments Args; Args.Add( TEXT("Value"), Text ); diff --git a/Engine/Source/Editor/StatsViewer/Private/StatsCustomColumn.h b/Engine/Source/Editor/StatsViewer/Private/StatsCustomColumn.h index d319644f8b3a..1177efbbcf3c 100644 --- a/Engine/Source/Editor/StatsViewer/Private/StatsCustomColumn.h +++ b/Engine/Source/Editor/StatsViewer/Private/StatsCustomColumn.h @@ -37,7 +37,7 @@ public: * @param PropertyHandle The property handle to retrieve the text from * returns a string representation of the properties data, or an empty string if the property is unsupported */ - static FText GetPropertyAsText( const TSharedPtr< IPropertyHandle > PropertyHandle ); + static FText GetPropertyAsText( const TSharedPtr< IPropertyHandle > PropertyHandle, bool bGetRawValue = false); public: diff --git a/Engine/Source/Editor/StatsViewer/Private/StatsPages/StaticMeshLightingInfoStatsPage.cpp b/Engine/Source/Editor/StatsViewer/Private/StatsPages/StaticMeshLightingInfoStatsPage.cpp index 783cd0e19c40..5108b3c745d0 100644 --- a/Engine/Source/Editor/StatsViewer/Private/StatsPages/StaticMeshLightingInfoStatsPage.cpp +++ b/Engine/Source/Editor/StatsViewer/Private/StatsPages/StaticMeshLightingInfoStatsPage.cpp @@ -124,7 +124,7 @@ struct StaticMeshLightingInfoStatsGenerator Entry->StaticMeshActor = InActor; Entry->StaticMeshComponent = InComponent; - Entry->StaticMesh = InComponent != nullptr ? InComponent->GetStaticMesh() : nullptr; + Entry->StaticMesh = InComponent->GetStaticMesh(); Entry->TextureLightMapMemoryUsage = (float)TextureLightMapMemoryUsage / 1024.0f; Entry->TextureShadowMapMemoryUsage = (float)TextureShadowMapMemoryUsage / 1024.0f; diff --git a/Engine/Source/Editor/SwarmInterface/Private/SwarmInterfaceLocal.cpp b/Engine/Source/Editor/SwarmInterface/Private/SwarmInterfaceLocal.cpp index d20db35ef880..99a1c0a62504 100644 --- a/Engine/Source/Editor/SwarmInterface/Private/SwarmInterfaceLocal.cpp +++ b/Engine/Source/Editor/SwarmInterface/Private/SwarmInterfaceLocal.cpp @@ -171,6 +171,7 @@ int32 FSwarmInterfaceLocalImpl::CloseConnection( void ) FPlatformProcess::CloseProc(LightmassProcHandle); } Recepient = FMessageAddress(); + FMessageEndpoint::SafeRelease(MessageEndpoint); bIsConnected = false; CallbackFunc = NULL; CallbackData = NULL; diff --git a/Engine/Source/Editor/TranslationEditor/Private/TranslationDataManager.cpp b/Engine/Source/Editor/TranslationEditor/Private/TranslationDataManager.cpp index 740081ebc5c7..4268312823c8 100644 --- a/Engine/Source/Editor/TranslationEditor/Private/TranslationDataManager.cpp +++ b/Engine/Source/Editor/TranslationEditor/Private/TranslationDataManager.cpp @@ -960,11 +960,7 @@ bool FTranslationDataManager::SaveSelectedTranslations(TArray FString UploadFilePath = FPaths::GameSavedDir() / "Temp" / CultureName / ManifestAndArchiveName + ".po"; FFileHelper::SaveStringToFile(PortableObjectDom.ToString(), *UploadFilePath); - FGuid LocalizationTargetGuid; - if (LocalizationTarget) - { - LocalizationTargetGuid = LocalizationTarget->Settings.Guid; - } + FGuid LocalizationTargetGuid = LocalizationTarget->Settings.Guid; ILocalizationServiceProvider& Provider = ILocalizationServiceModule::Get().GetProvider(); TSharedRef UploadTargetFileOp = ILocalizationServiceOperation::Create(); diff --git a/Engine/Source/Editor/TranslationEditor/Private/TranslationPickerFloatingWindow.cpp b/Engine/Source/Editor/TranslationEditor/Private/TranslationPickerFloatingWindow.cpp index 70a69f57a778..0c87a782d599 100644 --- a/Engine/Source/Editor/TranslationEditor/Private/TranslationPickerFloatingWindow.cpp +++ b/Engine/Source/Editor/TranslationEditor/Private/TranslationPickerFloatingWindow.cpp @@ -164,74 +164,56 @@ FText STranslationPickerFloatingWindow::GetTextFromWidget(TSharedRef Wi { FText OriginalText = FText::GetEmpty(); - STextBlock* TextBlock = (STextBlock*)&Widget.Get(); + STextBlock& TextBlock = (STextBlock&)Widget.Get(); // Have to parse the various widget types to find the FText - if ((Widget->GetTypeAsString() == "STextBlock" && TextBlock)) + if (Widget->GetTypeAsString() == "STextBlock") { - OriginalText = TextBlock->GetText(); + OriginalText = TextBlock.GetText(); } else if (Widget->GetTypeAsString() == "SToolTip") { - SToolTip* ToolTipWidget = ((SToolTip*)&Widget.Get()); - if (ToolTipWidget != nullptr) + SToolTip& ToolTipWidget = (SToolTip&)Widget.Get(); + OriginalText = GetTextFromWidget(ToolTipWidget.GetContentWidget()); + if (OriginalText.IsEmpty()) { - OriginalText = GetTextFromWidget(ToolTipWidget->GetContentWidget()); - if (OriginalText.IsEmpty()) - { - OriginalText = ToolTipWidget->GetTextTooltip(); - } + OriginalText = ToolTipWidget.GetTextTooltip(); } } else if (Widget->GetTypeAsString() == "SDocumentationToolTip") { - SDocumentationToolTip* DocumentationToolTip = (SDocumentationToolTip*)&Widget.Get(); - if (DocumentationToolTip != nullptr) - { - OriginalText = DocumentationToolTip->GetTextTooltip(); - } + SDocumentationToolTip& DocumentationToolTip = (SDocumentationToolTip&)Widget.Get(); + OriginalText = DocumentationToolTip.GetTextTooltip(); } else if (Widget->GetTypeAsString() == "SEditableText") { - SEditableText* EditableText = (SEditableText*)&Widget.Get(); - if (EditableText != nullptr) - { - // Always return the hint text because that's the only thing that will be translatable - OriginalText = EditableText->GetHintText(); - } + SEditableText& EditableText = (SEditableText&)Widget.Get(); + // Always return the hint text because that's the only thing that will be translatable + OriginalText = EditableText.GetHintText(); } else if (Widget->GetTypeAsString() == "SRichTextBlock") { - SRichTextBlock* RichTextBlock = (SRichTextBlock*)&Widget.Get(); - if (RichTextBlock != nullptr) - { - OriginalText = RichTextBlock->GetText(); - } + SRichTextBlock& RichTextBlock = (SRichTextBlock&)Widget.Get(); + OriginalText = RichTextBlock.GetText(); } else if (Widget->GetTypeAsString() == "SMultiLineEditableText") { - SMultiLineEditableText* MultiLineEditableText = (SMultiLineEditableText*)&Widget.Get(); - if (MultiLineEditableText != nullptr) - { - // Always return the hint text because that's the only thing that will be translatable - OriginalText = MultiLineEditableText->GetHintText(); - } + SMultiLineEditableText& MultiLineEditableText = (SMultiLineEditableText&)Widget.Get(); + // Always return the hint text because that's the only thing that will be translatable + OriginalText = MultiLineEditableText.GetHintText(); } else if (Widget->GetTypeAsString() == "SMultiLineEditableTextBox") { - SMultiLineEditableTextBox* MultiLineEditableTextBox = (SMultiLineEditableTextBox*)&Widget.Get(); - if (MultiLineEditableTextBox != nullptr) - { - OriginalText = MultiLineEditableTextBox->GetText(); - } + SMultiLineEditableTextBox& MultiLineEditableTextBox = (SMultiLineEditableTextBox&)Widget.Get(); + OriginalText = MultiLineEditableTextBox.GetText(); } else if (Widget->GetTypeAsString() == "SButton") { - SButton* Button = (SButton*)&Widget.Get(); + SButton& Button = (SButton&)Widget.Get(); // It seems like the LocateWindowUnderMouse() function will sometimes return an SButton but not the FText inside the button? // So try to find the first FText child of a button just in case - FChildren* Children = Button->GetChildren(); + FChildren* Children = Button.GetChildren(); for (int ChildIndex = 0; ChildIndex < Children->Num(); ++ChildIndex) { TSharedRef ChildWidget = Children->GetChildAt(ChildIndex); diff --git a/Engine/Source/Editor/UMGEditor/Private/BlueprintModes/WidgetDesignerApplicationMode.cpp b/Engine/Source/Editor/UMGEditor/Private/BlueprintModes/WidgetDesignerApplicationMode.cpp index 194386303404..c80c5cc55d2a 100644 --- a/Engine/Source/Editor/UMGEditor/Private/BlueprintModes/WidgetDesignerApplicationMode.cpp +++ b/Engine/Source/Editor/UMGEditor/Private/BlueprintModes/WidgetDesignerApplicationMode.cpp @@ -118,12 +118,9 @@ FWidgetDesignerApplicationMode::FWidgetDesignerApplicationMode(TSharedPtrGetWidgetToolbarBuilder()->AddWidgetBlueprintEditorModesToolbar(ToolbarExtender); + InWidgetEditor->GetWidgetToolbarBuilder()->AddWidgetReflector(ToolbarExtender); InWidgetEditor->GetToolbarBuilder()->AddCompileToolbar(ToolbarExtender); - //InWidgetEditor->GetToolbarBuilder()->AddComponentsToolbar(ToolbarExtender); InWidgetEditor->GetToolbarBuilder()->AddDebuggingToolbar(ToolbarExtender); - - //InWidgetEditor->GetToolbarBuilder()->AddScriptingToolbar(ToolbarExtender); - //InWidgetEditor->GetToolbarBuilder()->AddBlueprintGlobalOptionsToolbar(ToolbarExtender); } void FWidgetDesignerApplicationMode::RegisterTabFactories(TSharedPtr InTabManager) diff --git a/Engine/Source/Editor/UMGEditor/Private/Customizations/HorizontalAlignmentCustomization.cpp b/Engine/Source/Editor/UMGEditor/Private/Customizations/HorizontalAlignmentCustomization.cpp index 0683773e4743..ff25d8554769 100644 --- a/Engine/Source/Editor/UMGEditor/Private/Customizations/HorizontalAlignmentCustomization.cpp +++ b/Engine/Source/Editor/UMGEditor/Private/Customizations/HorizontalAlignmentCustomization.cpp @@ -100,7 +100,7 @@ void FHorizontalAlignmentCustomization::HandleCheckStateChanged(ECheckBoxState I ECheckBoxState FHorizontalAlignmentCustomization::GetCheckState(TSharedRef PropertyHandle, EHorizontalAlignment ForAlignment) const { uint8 Value; - if ( PropertyHandle->GetValue(Value) ) + if ( PropertyHandle->GetValue(Value) == FPropertyAccess::Result::Success ) { return Value == ForAlignment ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; } diff --git a/Engine/Source/Editor/UMGEditor/Private/Customizations/SlateChildSizeCustomization.cpp b/Engine/Source/Editor/UMGEditor/Private/Customizations/SlateChildSizeCustomization.cpp index 5fb8181d6a72..30691571c53e 100644 --- a/Engine/Source/Editor/UMGEditor/Private/Customizations/SlateChildSizeCustomization.cpp +++ b/Engine/Source/Editor/UMGEditor/Private/Customizations/SlateChildSizeCustomization.cpp @@ -102,7 +102,7 @@ void FSlateChildSizeCustomization::HandleCheckStateChanged(ECheckBoxState InChec ECheckBoxState FSlateChildSizeCustomization::GetCheckState(TSharedPtr PropertyHandle, ESlateSizeRule::Type ForRule) const { uint8 Value; - if ( PropertyHandle->GetValue(Value) ) + if ( PropertyHandle->GetValue(Value) == FPropertyAccess::Result::Success ) { return Value == ForRule ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; } @@ -113,7 +113,7 @@ ECheckBoxState FSlateChildSizeCustomization::GetCheckState(TSharedPtr FSlateChildSizeCustomization::GetValue(TSharedPtr ValueHandle) const { float Value; - if ( ValueHandle->GetValue(Value) ) + if ( ValueHandle->GetValue(Value) == FPropertyAccess::Result::Success) { return Value; } @@ -129,7 +129,7 @@ void FSlateChildSizeCustomization::HandleValueComitted(float NewValue, ETextComm EVisibility FSlateChildSizeCustomization::GetValueVisiblity(TSharedPtr RuleHandle) const { uint8 Value; - if ( RuleHandle->GetValue(Value) ) + if ( RuleHandle->GetValue(Value) == FPropertyAccess::Result::Success) { return Value == ESlateSizeRule::Fill ? EVisibility::Visible : EVisibility::Collapsed; } diff --git a/Engine/Source/Editor/UMGEditor/Private/Customizations/TextJustifyCustomization.cpp b/Engine/Source/Editor/UMGEditor/Private/Customizations/TextJustifyCustomization.cpp index b0b2c0e0d49c..cec0990cea7f 100644 --- a/Engine/Source/Editor/UMGEditor/Private/Customizations/TextJustifyCustomization.cpp +++ b/Engine/Source/Editor/UMGEditor/Private/Customizations/TextJustifyCustomization.cpp @@ -84,7 +84,7 @@ void FTextJustifyCustomization::HandleCheckStateChanged(ECheckBoxState InCheckbo ECheckBoxState FTextJustifyCustomization::GetCheckState(TSharedRef PropertyHandle, ETextJustify::Type ForAlignment) const { uint8 Value; - if ( PropertyHandle->GetValue(Value) ) + if ( PropertyHandle->GetValue(Value) == FPropertyAccess::Result::Success) { return Value == ForAlignment ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; } diff --git a/Engine/Source/Editor/UMGEditor/Private/Customizations/VerticalAlignmentCustomization.cpp b/Engine/Source/Editor/UMGEditor/Private/Customizations/VerticalAlignmentCustomization.cpp index 8b07a5d83edc..4d2dd7ade489 100644 --- a/Engine/Source/Editor/UMGEditor/Private/Customizations/VerticalAlignmentCustomization.cpp +++ b/Engine/Source/Editor/UMGEditor/Private/Customizations/VerticalAlignmentCustomization.cpp @@ -105,7 +105,7 @@ void FVerticalAlignmentCustomization::HandleCheckStateChanged(ECheckBoxState InC ECheckBoxState FVerticalAlignmentCustomization::GetCheckState(TSharedRef PropertyHandle, EVerticalAlignment ForAlignment) const { uint8 Value; - if ( PropertyHandle->GetValue(Value) ) + if ( PropertyHandle->GetValue(Value) == FPropertyAccess::Result::Success) { return Value == ForAlignment ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; } diff --git a/Engine/Source/Editor/UMGEditor/Private/Designer/DesignerCommands.cpp b/Engine/Source/Editor/UMGEditor/Private/Designer/DesignerCommands.cpp index 7434d1bce73f..f928ed7682a0 100644 --- a/Engine/Source/Editor/UMGEditor/Private/Designer/DesignerCommands.cpp +++ b/Engine/Source/Editor/UMGEditor/Private/Designer/DesignerCommands.cpp @@ -13,6 +13,7 @@ void FDesignerCommands::RegisterCommands() UI_COMMAND( RotationGridSnap, "Rotation Snap", "Enables or disables snapping objects to a rotation grid", EUserInterfaceActionType::ToggleButton, FInputChord() ); UI_COMMAND( ToggleOutlines, "Show Outlines", "Enables or disables showing the dashed outlines", EUserInterfaceActionType::ToggleButton, FInputChord(EKeys::G) ); + UI_COMMAND( ToggleRespectLocks, "Respect Locks", "Enables or disables respecting locks placed on widgets. Normally locked widgets prevent being selected in the designer.", EUserInterfaceActionType::ToggleButton, FInputChord(EKeys::L) ); } #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Editor/UMGEditor/Private/Designer/DesignerCommands.h b/Engine/Source/Editor/UMGEditor/Private/Designer/DesignerCommands.h index 1362af259c4d..976195a88402 100644 --- a/Engine/Source/Editor/UMGEditor/Private/Designer/DesignerCommands.h +++ b/Engine/Source/Editor/UMGEditor/Private/Designer/DesignerCommands.h @@ -38,6 +38,9 @@ public: /** Toggle Showing Outlines */ TSharedPtr< FUICommandInfo > ToggleOutlines; + /** Toggle if we care about locking */ + TSharedPtr< FUICommandInfo > ToggleRespectLocks; + public: /** Registers our commands with the binding system */ virtual void RegisterCommands() override; diff --git a/Engine/Source/Editor/UMGEditor/Private/Designer/SDesignerToolBar.cpp b/Engine/Source/Editor/UMGEditor/Private/Designer/SDesignerToolBar.cpp index 7882d929a8b8..2718dfd6fb17 100644 --- a/Engine/Source/Editor/UMGEditor/Private/Designer/SDesignerToolBar.cpp +++ b/Engine/Source/Editor/UMGEditor/Private/Designer/SDesignerToolBar.cpp @@ -43,6 +43,7 @@ TSharedRef< SWidget > SDesignerToolBar::MakeToolBar(const TSharedPtr< FExtender ToolbarBuilder.BeginSection("View"); ToolbarBuilder.AddToolBarButton(FDesignerCommands::Get().ToggleOutlines, NAME_None, TAttribute(), TAttribute(), TAttribute(), "ToggleOutlines"); + ToolbarBuilder.AddToolBarButton(FDesignerCommands::Get().ToggleRespectLocks, NAME_None, TAttribute(), TAttribute(), TAttribute(), "ToggleRespectLocks"); ToolbarBuilder.EndSection(); ToolbarBuilder.BeginSection("Transform"); diff --git a/Engine/Source/Editor/UMGEditor/Private/Designer/SDesignerView.cpp b/Engine/Source/Editor/UMGEditor/Private/Designer/SDesignerView.cpp index 6dc950e37c61..0ca2ebd37c90 100644 --- a/Engine/Source/Editor/UMGEditor/Private/Designer/SDesignerView.cpp +++ b/Engine/Source/Editor/UMGEditor/Private/Designer/SDesignerView.cpp @@ -60,6 +60,8 @@ #include "ScopedTransaction.h" #include "Components/NamedSlot.h" +#include "Types/ReflectionMetadata.h" + #include "Math/TransformCalculus2D.h" #define LOCTEXT_NAMESPACE "UMG" @@ -192,7 +194,26 @@ TSharedRef FSelectedWidgetDragDropOp::New(TSharedPtr< ////////////////////////////////////////////////////////////////////////// -static bool LocateWidgetsUnderCursor_Helper(FArrangedWidget& Candidate, FVector2D InAbsoluteCursorLocation, FArrangedChildren& OutWidgetsUnderCursor, bool bIgnoreEnabledStatus) +UWidget* SDesignerView::GetWidgetInDesignScopeFromSlateWidget(TSharedRef& InWidget) +{ + TSharedPtr ReflectionMetadata = InWidget->GetMetaData(); + if ( ReflectionMetadata.IsValid() ) + { + if ( UObject* SourceWidget = ReflectionMetadata->SourceObject.Get() ) + { + // The first UUserWidget outer of the source widget should be equal to the PreviewWidget for + // it to be part of the scope of the design area we're dealing with. + if ( SourceWidget->GetTypedOuter() == PreviewWidget ) + { + return Cast(SourceWidget); + } + } + } + + return nullptr; +} + +bool SDesignerView::LocateWidgetsUnderCursor_Helper(FArrangedWidget& Candidate, FVector2D InAbsoluteCursorLocation, FArrangedChildren& OutWidgetsUnderCursor, bool bIgnoreEnabledStatus, bool bIgnoreLockedState) { const bool bCandidateUnderCursor = // Candidate is physically under the cursor @@ -207,7 +228,7 @@ static bool LocateWidgetsUnderCursor_Helper(FArrangedWidget& Candidate, FVector2 // Check to see if we were asked to still allow children to be hit test visible bool bHitChildWidget = false; - if ( Candidate.Widget->GetVisibility().AreChildrenHitTestVisible() )//!= 0 || OutWidgetsUnderCursor. ) + if ( Candidate.Widget->GetVisibility().AreChildrenHitTestVisible() ) { FArrangedChildren ArrangedChildren(OutWidgetsUnderCursor.GetFilter()); Candidate.Widget->ArrangeChildren(Candidate.Geometry, ArrangedChildren); @@ -216,13 +237,19 @@ static bool LocateWidgetsUnderCursor_Helper(FArrangedWidget& Candidate, FVector2 for ( int32 ChildIndex = ArrangedChildren.Num() - 1; !bHitChildWidget && ChildIndex >= 0; --ChildIndex ) { FArrangedWidget& SomeChild = ArrangedChildren[ChildIndex]; - bHitChildWidget = ( SomeChild.Widget->IsEnabled() || bIgnoreEnabledStatus ) && LocateWidgetsUnderCursor_Helper(SomeChild, InAbsoluteCursorLocation, OutWidgetsUnderCursor, bIgnoreEnabledStatus); + bHitChildWidget = ( SomeChild.Widget->IsEnabled() || bIgnoreEnabledStatus ) + && LocateWidgetsUnderCursor_Helper(SomeChild, InAbsoluteCursorLocation, OutWidgetsUnderCursor, bIgnoreEnabledStatus, bIgnoreLockedState); } } + // Widgets that are children of foreign userWidgets should not be considered selection candidates. + UWidget* CandidateUWidget = GetWidgetInDesignScopeFromSlateWidget(Candidate.Widget); + // If we hit a child widget or we hit our candidate widget then we'll append our widgets const bool bHitCandidateWidget = OutWidgetsUnderCursor.Accepts(Candidate.Widget->GetVisibility()) && - Candidate.Widget->GetVisibility().AreChildrenHitTestVisible(); + Candidate.Widget->GetVisibility().AreChildrenHitTestVisible() + && CandidateUWidget + && (bIgnoreLockedState || !CandidateUWidget->IsLockedInDesigner()); bHitAnyWidget = bHitChildWidget || bHitCandidateWidget; if ( !bHitAnyWidget ) @@ -685,6 +712,13 @@ void SDesignerView::BindCommands() FCanExecuteAction(), FIsActionChecked::CreateSP(this, &SDesignerView::IsShowingOutlines) ); + + CommandList->MapAction( + Commands.ToggleRespectLocks, + FExecuteAction::CreateSP(this, &SDesignerView::ToggleRespectingLocks), + FCanExecuteAction(), + FIsActionChecked::CreateSP(this, &SDesignerView::IsRespectingLocks) + ); } void SDesignerView::AddReferencedObjects(FReferenceCollector& Collector) @@ -738,6 +772,18 @@ bool SDesignerView::IsShowingOutlines() const return BlueprintEditor.Pin()->GetShowDashedOutlines(); } +void SDesignerView::ToggleRespectingLocks() +{ + TSharedPtr Editor = BlueprintEditor.Pin(); + + Editor->SetIsRespectingLocks(!Editor->GetIsRespectingLocks()); +} + +bool SDesignerView::IsRespectingLocks() const +{ + return BlueprintEditor.Pin()->GetIsRespectingLocks(); +} + void SDesignerView::SetStartupResolution() { // Use previously set resolution (or create new entries using default values) @@ -1247,7 +1293,7 @@ bool SDesignerView::FindWidgetUnderCursor(const FGeometry& MyGeometry, const FPo PreviewHitTestRoot->SetVisibility(EVisibility::Visible); FArrangedWidget WindowWidgetGeometry(PreviewHitTestRoot.ToSharedRef(), MyGeometry); - LocateWidgetsUnderCursor_Helper(WindowWidgetGeometry, MouseEvent.GetScreenSpacePosition(), Children, true); + LocateWidgetsUnderCursor_Helper(WindowWidgetGeometry, MouseEvent.GetScreenSpacePosition(), Children, true, !IsRespectingLocks()); PreviewHitTestRoot->SetVisibility(EVisibility::HitTestInvisible); @@ -2116,7 +2162,7 @@ void SDesignerView::DetermineDragDropPreviewWidgets(TArray& OutWidgets } else if (AssetDragDropOp.IsValid()) { - for (FAssetData AssetData : AssetDragDropOp->AssetData) + for (const FAssetData& AssetData : AssetDragDropOp->GetAssets()) { UWidget* Widget = nullptr; UClass* AssetClass = FindObjectChecked(ANY_PACKAGE, *AssetData.AssetClass.ToString()); diff --git a/Engine/Source/Editor/UMGEditor/Private/Designer/SDesignerView.h b/Engine/Source/Editor/UMGEditor/Private/Designer/SDesignerView.h index 911672dc49f1..36f65024a2d5 100644 --- a/Engine/Source/Editor/UMGEditor/Private/Designer/SDesignerView.h +++ b/Engine/Source/Editor/UMGEditor/Private/Designer/SDesignerView.h @@ -200,6 +200,9 @@ private: bool InTransaction() const; void EndTransaction(bool bCancel); + UWidget* GetWidgetInDesignScopeFromSlateWidget(TSharedRef& InWidget); + bool LocateWidgetsUnderCursor_Helper(FArrangedWidget& Candidate, FVector2D InAbsoluteCursorLocation, FArrangedChildren& OutWidgetsUnderCursor, bool bIgnoreEnabledStatus, bool bIgnoreLockedState); + private: struct FWidgetHitResult { @@ -239,6 +242,9 @@ private: void ToggleShowingOutlines(); bool IsShowingOutlines() const; + void ToggleRespectingLocks(); + bool IsRespectingLocks() const; + void ProcessDropAndAddWidget(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent, const bool bIsPreview); FVector2D GetExtensionPosition(TSharedRef ExtensionElement) const; diff --git a/Engine/Source/Editor/UMGEditor/Private/Hierarchy/SHierarchyViewItem.cpp b/Engine/Source/Editor/UMGEditor/Private/Hierarchy/SHierarchyViewItem.cpp index 9d6e3680badc..3d0533e2f5e0 100644 --- a/Engine/Source/Editor/UMGEditor/Private/Hierarchy/SHierarchyViewItem.cpp +++ b/Engine/Source/Editor/UMGEditor/Private/Hierarchy/SHierarchyViewItem.cpp @@ -9,6 +9,8 @@ #include "Widgets/Images/SImage.h" #include "Widgets/Input/SButton.h" #include "Widgets/Views/SListView.h" +#include "EditorFontGlyphs.h" +#include "Application/SlateApplication.h" #if WITH_EDITOR #include "EditorStyleSet.h" @@ -1093,6 +1095,32 @@ void SHierarchyViewItem::Construct(const FArguments& InArgs, const TSharedRef< S .IsSelected(this, &SHierarchyViewItem::IsSelectedExclusively) ] + // Locked Icon + + SHorizontalBox::Slot() + .AutoWidth() + .VAlign(VAlign_Center) + [ + SNew(SButton) + .ContentPadding(FMargin(3, 1)) + .ButtonStyle(FEditorStyle::Get(), "HoverHintOnly") + .ForegroundColor(FCoreStyle::Get().GetSlateColor("Foreground")) + .OnClicked(this, &SHierarchyViewItem::OnToggleLockedInDesigner) + .Visibility(Model->CanControlLockedInDesigner() ? EVisibility::Visible : EVisibility::Hidden) + .ToolTipText(LOCTEXT("WidgetLockedButtonToolTip", "Locks or Unlocks this widget and all children. Locking a widget prevents it from being selected in the designer view by clicking on them.\n\nHolding [Shift] will only affect this widget and no children.")) + .HAlign(HAlign_Center) + .VAlign(VAlign_Center) + [ + SNew(SBox) + .MinDesiredWidth(12.0f) + .HAlign(HAlign_Left) + [ + SNew(STextBlock) + .Font(FEditorStyle::Get().GetFontStyle("FontAwesome.10")) + .Text(this, &SHierarchyViewItem::GetLockBrushForWidget) + ] + ] + ] + // Visibility icon + SHorizontalBox::Slot() .AutoWidth() @@ -1216,9 +1244,23 @@ FReply SHierarchyViewItem::OnToggleVisibility() FText SHierarchyViewItem::GetVisibilityBrushForWidget() const { - return Model->IsVisible() ? - FText::FromString(FString(TEXT("\xf06e")) /*fa-eye*/) : - FText::FromString(FString(TEXT("\xf070")) /*fa-eye-slash*/); + return Model->IsVisible() ? FEditorFontGlyphs::Eye : FEditorFontGlyphs::Eye_Slash; +} + +FReply SHierarchyViewItem::OnToggleLockedInDesigner() +{ + if ( Model.IsValid() ) + { + const bool bRecursive = FSlateApplication::Get().GetModifierKeys().IsShiftDown() ? false : true; + Model->SetIsLockedInDesigner(!Model->IsLockedInDesigner(), bRecursive); + } + + return FReply::Handled(); +} + +FText SHierarchyViewItem::GetLockBrushForWidget() const +{ + return Model.IsValid() && Model->IsLockedInDesigner() ? FEditorFontGlyphs::Lock : FEditorFontGlyphs::Unlock; } #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Editor/UMGEditor/Private/Hierarchy/SHierarchyViewItem.h b/Engine/Source/Editor/UMGEditor/Private/Hierarchy/SHierarchyViewItem.h index 08c10193fa24..70d801a2bfb5 100644 --- a/Engine/Source/Editor/UMGEditor/Private/Hierarchy/SHierarchyViewItem.h +++ b/Engine/Source/Editor/UMGEditor/Private/Hierarchy/SHierarchyViewItem.h @@ -11,6 +11,7 @@ #include "Widgets/Views/STableViewBase.h" #include "Widgets/Views/STableRow.h" #include "WidgetReference.h" +#include "WidgetBlueprintEditor.h" class FWidgetBlueprintEditor; @@ -18,6 +19,7 @@ class FHierarchyModel : public TSharedFromThis < FHierarchyModel > { public: FHierarchyModel(TSharedPtr InBlueprintEditor); + virtual ~FHierarchyModel() { } /** Gets the unique name of the item used to restore item expansion. */ virtual FName GetUniqueName() const = 0; @@ -61,6 +63,24 @@ public: virtual bool IsVisible() const { return true; } virtual bool CanControlVisibility() const { return false; } virtual void SetIsVisible(bool IsVisible) { } + + virtual bool CanControlLockedInDesigner() const { return false; } + virtual bool IsLockedInDesigner() { return false; } + virtual void SetIsLockedInDesigner(bool NewIsLocked, bool bRecursive) + { + if ( bRecursive ) + { + TArray< TSharedPtr > Children; + GetChildren(Children); + for ( TSharedPtr& child : Children ) + { + if ( child.IsValid() ) + { + child->SetIsLockedInDesigner(NewIsLocked, bRecursive); + } + } + } + } virtual bool IsExpanded() const { return true; } virtual void SetExpanded(bool bIsExpanded) { } @@ -213,6 +233,33 @@ public: } } + virtual bool CanControlLockedInDesigner() const override + { + return true; + } + + virtual bool IsLockedInDesigner() override + { + UWidget* TemplateWidget = Item.GetTemplate(); + if (TemplateWidget) + { + return TemplateWidget->IsLockedInDesigner(); + } + + return false; + } + + virtual void SetIsLockedInDesigner(bool NewIsLocked, bool bRecursive) override + { + FHierarchyModel::SetIsLockedInDesigner(NewIsLocked, bRecursive); + + if(Item.GetTemplate() && Item.GetPreview()) + { + Item.GetTemplate()->SetLockedInDesigner(NewIsLocked); + Item.GetPreview()->SetLockedInDesigner(NewIsLocked); + } + } + virtual bool IsExpanded() const override { return Item.GetTemplate()->bExpandedInDesigner; @@ -285,6 +332,12 @@ private: /** Handles clicking the visibility toggle */ FReply OnToggleVisibility(); + /** Handles clicking the locked toggle */ + FReply OnToggleLockedInDesigner(); + + /** Returns a brush representing the lock item of the widget's lock button */ + FText GetLockBrushForWidget() const; + /** Returns a brush representing the visibility item of the widget's visibility button */ FText GetVisibilityBrushForWidget() const; diff --git a/Engine/Source/Editor/UMGEditor/Private/Nodes/K2Node_CreateWidget.cpp b/Engine/Source/Editor/UMGEditor/Private/Nodes/K2Node_CreateWidget.cpp index 3a7f72cc7c45..43450fa75036 100644 --- a/Engine/Source/Editor/UMGEditor/Private/Nodes/K2Node_CreateWidget.cpp +++ b/Engine/Source/Editor/UMGEditor/Private/Nodes/K2Node_CreateWidget.cpp @@ -37,7 +37,7 @@ void UK2Node_CreateWidget::AllocateDefaultPins() const UEdGraphSchema_K2* K2Schema = GetDefault(); // OwningPlayer pin - UEdGraphPin* OwningPlayerPin = CreatePin(EGPD_Input, K2Schema->PC_Object, TEXT(""), APlayerController::StaticClass(), false, false, FK2Node_CreateWidgetHelper::OwningPlayerPinName); + UEdGraphPin* OwningPlayerPin = CreatePin(EGPD_Input, K2Schema->PC_Object, FString(), APlayerController::StaticClass(), FK2Node_CreateWidgetHelper::OwningPlayerPinName); SetPinToolTip(*OwningPlayerPin, LOCTEXT("OwningPlayerPinDescription", "The player that 'owns' the widget.")); } diff --git a/Engine/Source/Editor/UMGEditor/Private/Palette/SPaletteView.h b/Engine/Source/Editor/UMGEditor/Private/Palette/SPaletteView.h index 364ad7ae0987..88fcc530ea8b 100644 --- a/Engine/Source/Editor/UMGEditor/Private/Palette/SPaletteView.h +++ b/Engine/Source/Editor/UMGEditor/Private/Palette/SPaletteView.h @@ -19,6 +19,8 @@ class UWidgetBlueprint; class FWidgetViewModel : public TSharedFromThis { public: + virtual ~FWidgetViewModel() { } + virtual FText GetName() const = 0; virtual bool IsTemplate() const = 0; diff --git a/Engine/Source/Editor/UMGEditor/Private/Settings/WidgetDesignerSettings.cpp b/Engine/Source/Editor/UMGEditor/Private/Settings/WidgetDesignerSettings.cpp index a0bf4327cd37..2deb3ceb8274 100644 --- a/Engine/Source/Editor/UMGEditor/Private/Settings/WidgetDesignerSettings.cpp +++ b/Engine/Source/Editor/UMGEditor/Private/Settings/WidgetDesignerSettings.cpp @@ -2,11 +2,11 @@ #include "Settings/WidgetDesignerSettings.h" -UWidgetDesignerSettings::UWidgetDesignerSettings(const FObjectInitializer& ObjectInitializer) - : Super(ObjectInitializer) +UWidgetDesignerSettings::UWidgetDesignerSettings() { GridSnapEnabled = true; GridSnapSize = 4; bShowOutlines = true; bExecutePreConstructEvent = true; + bRespectLocks = true; } diff --git a/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprint.cpp b/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprint.cpp index e9db6b4d5dd6..e07e7ad6b82d 100644 --- a/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprint.cpp +++ b/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprint.cpp @@ -699,9 +699,9 @@ bool UWidgetBlueprint::ValidateGeneratedClass(const UClass* InClass) return Result; } -TUniquePtr UWidgetBlueprint::GetCompilerForWidgetBP(UWidgetBlueprint* BP, FCompilerResultsLog& InMessageLog, const FKismetCompilerOptions& InCompileOptions) +TSharedPtr UWidgetBlueprint::GetCompilerForWidgetBP(UWidgetBlueprint* BP, FCompilerResultsLog& InMessageLog, const FKismetCompilerOptions& InCompileOptions) { - return TUniquePtr(new FWidgetBlueprintCompiler(BP, InMessageLog, InCompileOptions, nullptr)); + return TSharedPtr(new FWidgetBlueprintCompiler(BP, InMessageLog, InCompileOptions, nullptr)); } void UWidgetBlueprint::GetReparentingRules(TSet< const UClass* >& AllowedChildrenOfClasses, TSet< const UClass* >& DisallowedChildrenOfClasses) const @@ -740,9 +740,59 @@ bool UWidgetBlueprint::IsWidgetFreeFromCircularReferences(UUserWidget* UserWidge return true; } +TArray UWidgetBlueprint::GetAllSourceWidgets() +{ + TArray Ret; + ForEachSourceWidgetImpl( [&Ret](UWidget* Inner) { Ret.Push(Inner); } ); + return Ret; +} + +TArray UWidgetBlueprint::GetAllSourceWidgets() const +{ + TArray Ret; + ForEachSourceWidgetImpl( [&Ret](UWidget* Inner) { Ret.Push(Inner); } ); + return Ret; +} + +void UWidgetBlueprint::ForEachSourceWidget(TFunctionRef Fn) +{ + ForEachSourceWidgetImpl(Fn); +} + +void UWidgetBlueprint::ForEachSourceWidget(TFunctionRef Fn) const +{ + ForEachSourceWidgetImpl(Fn); +} + UPackage* UWidgetBlueprint::GetWidgetTemplatePackage() const { return GetOutermost(); } +void UWidgetBlueprint::ForEachSourceWidgetImpl (TFunctionRef Fn) const +{ + // This exists in order to facilitate working with collections of UWidgets wo/ + // relying on user implemented UWidget virtual functions. During blueprint compilation + // it is bad practice to call those virtual functions until the class is fully formed + // and reinstancing has finished. For instance, GetDefaultObject() calls in those user + // functions may create a CDO before the class has been linked, or even before + // all member variables have been generated: + UWidgetTree* WidgetTreeForCapture = WidgetTree; + ForEachObjectWithOuter( + WidgetTree, + [Fn, WidgetTreeForCapture](UObject* Inner) + { + if(UWidget* AsWidget = Cast(Inner)) + { + // Widgets owned by another UWidgetBlueprint aren't really 'source' widgets, E.g. widgets + // created by the user *in this blueprint* + if(AsWidget->GetTypedOuter() == WidgetTreeForCapture) + { + Fn(AsWidget); + } + } + } + ); +} + #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintCompiler.cpp b/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintCompiler.cpp index 4825a327de45..ec15ae285dbf 100644 --- a/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintCompiler.cpp +++ b/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintCompiler.cpp @@ -223,8 +223,7 @@ void FWidgetBlueprintCompiler::CreateClassVariablesFromBlueprint() ValidateWidgetNames(); // Build the set of variables based on the variable widgets in the widget tree. - TArray Widgets; - WidgetBP->WidgetTree->GetAllWidgets(Widgets); + TArray Widgets = WidgetBP->GetAllSourceWidgets(); // Sort the widgets alphabetically Widgets.Sort( []( const UWidget& Lhs, const UWidget& Rhs ) { return Rhs.GetFName() < Lhs.GetFName(); } ); @@ -267,7 +266,7 @@ void FWidgetBlueprintCompiler::CreateClassVariablesFromBlueprint() continue; } - FEdGraphPinType WidgetPinType(Schema->PC_Object, TEXT(""), WidgetClass, false, false, false, false, FEdGraphTerminalType()); + FEdGraphPinType WidgetPinType(Schema->PC_Object, FString(), WidgetClass, EPinContainerType::None, false, FEdGraphTerminalType()); // Always name the variable according to the underlying FName of the widget object UProperty* WidgetProperty = CreateVariable(Widget->GetFName(), WidgetPinType); @@ -275,12 +274,14 @@ void FWidgetBlueprintCompiler::CreateClassVariablesFromBlueprint() { const FString VariableName = Widget->IsGeneratedName() ? Widget->GetName() : Widget->GetLabelText().ToString(); WidgetProperty->SetMetaData(TEXT("DisplayName"), *VariableName); - WidgetProperty->SetMetaData(TEXT("Category"), *WidgetBP->GetName()); // Only show variables if they're explicitly marked as variables. if ( Widget->bIsVariable ) { WidgetProperty->SetPropertyFlags(CPF_BlueprintVisible); + + // Only include Category metadata for variables (i.e. a visible/editable property); otherwise, UHT will raise a warning if this Blueprint is nativized. + WidgetProperty->SetMetaData(TEXT("Category"), *WidgetBP->GetName()); } WidgetProperty->SetPropertyFlags(CPF_Instanced); @@ -293,7 +294,7 @@ void FWidgetBlueprintCompiler::CreateClassVariablesFromBlueprint() // Add movie scenes variables here for(UWidgetAnimation* Animation : WidgetBP->Animations) { - FEdGraphPinType WidgetPinType(Schema->PC_Object, TEXT(""), Animation->GetClass(), false, true, false, false, FEdGraphTerminalType()); + FEdGraphPinType WidgetPinType(Schema->PC_Object, FString(), Animation->GetClass(), EPinContainerType::None, true, FEdGraphTerminalType()); UProperty* AnimationProperty = CreateVariable(Animation->GetFName(), WidgetPinType); if ( AnimationProperty != nullptr ) @@ -401,11 +402,11 @@ bool FWidgetBlueprintCompiler::CanTemplateWidget(FCompilerResultsLog& MessageLog void FWidgetBlueprintCompiler::FinishCompilingClass(UClass* Class) { UWidgetBlueprint* WidgetBP = WidgetBlueprint(); + UWidgetBlueprintGeneratedClass* BPGClass = CastChecked(Class); // Don't do a bunch of extra work on the skeleton generated class if ( WidgetBP->SkeletonGeneratedClass != Class ) { - UWidgetBlueprintGeneratedClass* BPGClass = CastChecked(Class); if( !WidgetBP->bHasBeenRegenerated ) { UBlueprint::ForceLoadMembers(WidgetBP->WidgetTree); @@ -439,7 +440,7 @@ void FWidgetBlueprintCompiler::FinishCompilingClass(UClass* Class) // Add all the names of the named slot widgets to the slot names structure. BPGClass->NamedSlots.Reset(); - BPGClass->WidgetTree->ForEachWidget([&] (UWidget* Widget) { + WidgetBP->ForEachSourceWidget([&] (UWidget* Widget) { if ( Widget && Widget->IsA() ) { BPGClass->NamedSlots.Add(Widget->GetFName()); @@ -447,6 +448,22 @@ void FWidgetBlueprintCompiler::FinishCompilingClass(UClass* Class) }); } + // Make sure that we don't have dueling widget hierarchies + if (UWidgetBlueprintGeneratedClass* SuperBPGClass = Cast(BPGClass->GetSuperClass())) + { + if (SuperBPGClass->WidgetTree != nullptr) + { + if ((SuperBPGClass->WidgetTree->RootWidget != nullptr) && (BPGClass->WidgetTree->RootWidget != nullptr)) + { + // We both have a widget tree, terrible things will ensue + // @todo: nickd - we need to switch this back to a warning in engine, but note for games + MessageLog.Note(*LOCTEXT("ParentAndChildBothHaveWidgetTrees", "This widget @@ and parent class widget @@ both have a widget hierarchy, which is not supported. Only one of them should have a widget tree.").ToString(), + WidgetBP, SuperBPGClass->ClassGeneratedBy); + } + } + } + + // UClass* ParentClass = WidgetBP->ParentClass; for ( TUObjectPropertyBase* WidgetProperty : TFieldRange>( ParentClass ) ) { @@ -566,7 +583,7 @@ void FWidgetBlueprintCompiler::VerifyEventReplysAreNotEmpty(FKismetFunctionConte Context.SourceGraph->GetNodesOfClass(FunctionResults); UScriptStruct* EventReplyStruct = FEventReply::StaticStruct(); - FEdGraphPinType EventReplyPinType(Schema->PC_Struct, TEXT(""), EventReplyStruct, /*bIsArray =*/false, /*bIsReference =*/false, /*bIsSet =*/false, /*bIsMap =*/ false, /*InValueTerminalType =*/FEdGraphTerminalType()); + FEdGraphPinType EventReplyPinType(Schema->PC_Struct, FString(), EventReplyStruct, EPinContainerType::None, /*bIsReference =*/false, /*InValueTerminalType =*/FEdGraphTerminalType()); for ( UK2Node_FunctionResult* FunctionResult : FunctionResults ) { diff --git a/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintEditor.cpp b/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintEditor.cpp index 70924d2468b4..927caed4b076 100644 --- a/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintEditor.cpp +++ b/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintEditor.cpp @@ -105,6 +105,7 @@ FWidgetBlueprintEditor::~FWidgetBlueprintEditor() void FWidgetBlueprintEditor::InitWidgetBlueprintEditor(const EToolkitMode::Type Mode, const TSharedPtr< IToolkitHost >& InitToolkitHost, const TArray& InBlueprints, bool bShouldOpenInDefaultsMode) { bShowDashedOutlines = GetDefault()->bShowOutlines; + bRespectLocks = GetDefault()->bRespectLocks; TSharedPtr ThisPtr(SharedThis(this)); WidgetToolbar = MakeShareable(new FWidgetBlueprintEditorToolbar(ThisPtr)); @@ -972,6 +973,16 @@ void FWidgetBlueprintEditor::SetShowDashedOutlines(bool Value) bShowDashedOutlines = Value; } +bool FWidgetBlueprintEditor::GetIsRespectingLocks() const +{ + return bRespectLocks; +} + +void FWidgetBlueprintEditor::SetIsRespectingLocks(bool Value) +{ + bRespectLocks = Value; +} + class FObjectAndDisplayName { public: @@ -1222,7 +1233,7 @@ void FWidgetBlueprintEditor::ExtendSequencerObjectBindingMenu(FMenuBuilder& Obje if (SelectedWidget.IsValid()) { UWidget* BoundWidget = Cast(ContextObjects[0]); - if (BoundWidget) + if (BoundWidget && SelectedWidget.GetPreview()->GetTypedOuter() == BoundWidget->GetTypedOuter() ) { FUIAction ReplaceWithMenuAction(FExecuteAction::CreateRaw(this, &FWidgetBlueprintEditor::ReplaceTrackWithSelectedWidget, SelectedWidget, BoundWidget)); diff --git a/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintEditor.h b/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintEditor.h index 7055598c4b26..0dcd3c2d3eaf 100644 --- a/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintEditor.h +++ b/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintEditor.h @@ -169,6 +169,9 @@ public: bool GetShowDashedOutlines() const; void SetShowDashedOutlines(bool Value); + bool GetIsRespectingLocks() const; + void SetIsRespectingLocks(bool Value); + public: /** Fires whenever a new widget is being hovered over */ FOnHoveredWidgetSet OnHoveredWidgetSet; @@ -324,6 +327,9 @@ private: /** Should the designer show outlines when it creates widgets? */ bool bShowDashedOutlines; + /** */ + bool bRespectLocks; + TArray< TFunction > QueuedDesignerActions; /** The currently viewed animation, if any. */ diff --git a/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintEditorToolbar.cpp b/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintEditorToolbar.cpp index 43a8f1751db2..611d8966ba35 100644 --- a/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintEditorToolbar.cpp +++ b/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintEditorToolbar.cpp @@ -13,7 +13,7 @@ #include "Widgets/SToolTip.h" #include "IDocumentation.h" #include "BlueprintEditor.h" - +#include "Framework/MultiBox/MultiBoxBuilder.h" #include "WidgetBlueprintEditor.h" #include "WorkflowOrientedApp/SModeWidget.h" @@ -123,4 +123,33 @@ void FWidgetBlueprintEditorToolbar::FillWidgetBlueprintEditorModesToolbar(FToolB } } +void FWidgetBlueprintEditorToolbar::AddWidgetReflector(TSharedPtr Extender) +{ + TSharedPtr BlueprintEditorPtr = WidgetEditor.Pin(); + + Extender->AddToolBarExtension( + "Asset", + EExtensionHook::After, + BlueprintEditorPtr->GetToolkitCommands(), + FToolBarExtensionDelegate::CreateSP(this, &FWidgetBlueprintEditorToolbar::FillWidgetReflectorToolbar)); +} + +void FWidgetBlueprintEditorToolbar::FillWidgetReflectorToolbar(FToolBarBuilder& ToolbarBuilder) +{ + ToolbarBuilder.BeginSection("WidgetTools"); + + ToolbarBuilder.AddToolBarButton( + FUIAction( + FExecuteAction::CreateLambda([=] { FGlobalTabmanager::Get()->InvokeTab(FTabId("WidgetReflector")); }), + FCanExecuteAction() + ) + , NAME_None + , LOCTEXT("OpenWidgetReflector", "Widget Reflector") + , LOCTEXT("OpenWidgetReflectorToolTip", "Opens the Widget Reflector, a handy tool for diagnosing problems with live widgets.") + , FSlateIcon(FCoreStyle::Get().GetStyleSetName(), "WidgetReflector.Icon") + ); + + ToolbarBuilder.EndSection(); +} + #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintEditorToolbar.h b/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintEditorToolbar.h index f83f0fe76a29..c4943d82e986 100644 --- a/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintEditorToolbar.h +++ b/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintEditorToolbar.h @@ -23,9 +23,14 @@ public: */ void AddWidgetBlueprintEditorModesToolbar(TSharedPtr Extender); + void AddWidgetReflector(TSharedPtr Extender); + public: /** */ void FillWidgetBlueprintEditorModesToolbar(FToolBarBuilder& ToolbarBuilder); + /** */ + void FillWidgetReflectorToolbar(FToolBarBuilder& ToolbarBuilder); + TWeakPtr WidgetEditor; }; diff --git a/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintEditorUtils.cpp b/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintEditorUtils.cpp index d27153d4ea38..d7803d197fc8 100644 --- a/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintEditorUtils.cpp +++ b/Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintEditorUtils.cpp @@ -135,14 +135,11 @@ bool FWidgetBlueprintEditorUtils::VerifyWidgetRename(TSharedRefRename(*NewNameSlug.ToString(), nullptr, REN_Test)) { - // Dummy rename with flag REN_Test returns if rename is possible - if (!WidgetTemplate->Rename(*NewNameSlug.ToString(), nullptr, REN_Test)) - { - OutErrorMessage = LOCTEXT("ExistingObjectName", "Existing Object Name"); - return false; - } + OutErrorMessage = LOCTEXT("ExistingObjectName", "Existing Object Name"); + return false; } } @@ -189,7 +186,7 @@ bool FWidgetBlueprintEditorUtils::RenameWidget(TSharedRefIsValid( NewFName ) || bBindWidget ); - if ( Widget && bUniqueNameForTemplate ) + if ( bUniqueNameForTemplate ) { // Stringify the FNames const FString NewNameStr = NewFName.ToString(); diff --git a/Engine/Source/Editor/UMGEditor/Public/DesignerExtension.h b/Engine/Source/Editor/UMGEditor/Public/DesignerExtension.h index 19d9a8c76425..c75c2b9c27c7 100644 --- a/Engine/Source/Editor/UMGEditor/Public/DesignerExtension.h +++ b/Engine/Source/Editor/UMGEditor/Public/DesignerExtension.h @@ -105,6 +105,7 @@ class UMGEDITOR_API FDesignerExtension : public TSharedFromThis GetAllSourceWidgets(); + TArray GetAllSourceWidgets() const; + + /** Identical to GetAllSourceWidgets, but as an algorithm */ + void ForEachSourceWidget(TFunctionRef Fn); + void ForEachSourceWidget(TFunctionRef Fn) const; + static bool ValidateGeneratedClass(const UClass* InClass); - static TUniquePtr GetCompilerForWidgetBP(UWidgetBlueprint* BP, FCompilerResultsLog& InMessageLog, const FKismetCompilerOptions& InCompileOptions); + static TSharedPtr GetCompilerForWidgetBP(UWidgetBlueprint* BP, FCompilerResultsLog& InMessageLog, const FKismetCompilerOptions& InCompileOptions); + +private: + void ForEachSourceWidgetImpl(TFunctionRef Fn) const; }; diff --git a/Engine/Source/Editor/UMGEditor/Public/WidgetTemplate.h b/Engine/Source/Editor/UMGEditor/Public/WidgetTemplate.h index b5eb41326031..ab07ae749498 100644 --- a/Engine/Source/Editor/UMGEditor/Public/WidgetTemplate.h +++ b/Engine/Source/Editor/UMGEditor/Public/WidgetTemplate.h @@ -18,6 +18,7 @@ class UMGEDITOR_API FWidgetTemplate : public TSharedFromThis public: /** Constructor */ FWidgetTemplate(); + virtual ~FWidgetTemplate() { } /** The category this template fits into. */ virtual FText GetCategory() const = 0; diff --git a/Engine/Source/Editor/UnrealEd/Classes/ActorFactories/ActorFactory.h b/Engine/Source/Editor/UnrealEd/Classes/ActorFactories/ActorFactory.h index 609f83f7b9c3..f1191c3ebfdc 100644 --- a/Engine/Source/Editor/UnrealEd/Classes/ActorFactories/ActorFactory.h +++ b/Engine/Source/Editor/UnrealEd/Classes/ActorFactories/ActorFactory.h @@ -9,6 +9,8 @@ #include "Templates/SubclassOf.h" #include "ActorFactory.generated.h" +UNREALED_API DECLARE_LOG_CATEGORY_EXTERN(LogActorFactory, Log, All); + class AActor; class FAssetData; class UBlueprint; diff --git a/Engine/Source/Editor/UnrealEd/Classes/Animation/DebugSkelMeshComponent.h b/Engine/Source/Editor/UnrealEd/Classes/Animation/DebugSkelMeshComponent.h index edbe99830984..49dadc94a769 100644 --- a/Engine/Source/Editor/UnrealEd/Classes/Animation/DebugSkelMeshComponent.h +++ b/Engine/Source/Editor/UnrealEd/Classes/Animation/DebugSkelMeshComponent.h @@ -79,9 +79,10 @@ public: int32 ClothingSimDataIndexWhenPainting; TArray ClothingSimIndices; - int32 ClothingVisiblePropertyIndex; TArray ClothingVisiblePropertyValues; + float PropertyViewMin; + float PropertyViewMax; TArray SkinnedPositions; TArray SkinnedNormals; @@ -200,7 +201,10 @@ class UDebugSkelMeshComponent : public USkeletalMeshComponent uint32 bShowClothData : 1; UPROPERTY(transient) - int32 VisibleClothProperty; + float MinClothPropertyView; + + UPROPERTY(transient) + float MaxClothPropertyView; /** Non Compressed SpaceBases for when bDisplayRawAnimation == true **/ TArray UncompressedSpaceBases; @@ -229,7 +233,7 @@ class UDebugSkelMeshComponent : public USkeletalMeshComponent UPROPERTY(transient) TArray SkelMaterials; - UPROPERTY(transient) + UPROPERTY(transient, NonTransactional) class UAnimPreviewInstance* PreviewInstance; UPROPERTY(transient) @@ -322,10 +326,6 @@ class UDebugSkelMeshComponent : public USkeletalMeshComponent /** Sets the flag used to determine whether or not the current active cloth sim mesh should be rendered */ UNREALED_API void SetShowClothProperty(bool bState); - /** Sets the cloth propert which should be visualized on the rendered sim mesh */ - UNREALED_API void SetVisibleClothProperty(int32 ClothProperty); - - #if WITH_EDITOR //TODO - This is a really poor way to post errors to the user. Work out a better way. struct FAnimNotifyErrors @@ -378,6 +378,9 @@ class UDebugSkelMeshComponent : public USkeletalMeshComponent /** The currently selected LOD for painting */ int32 SelectedClothingLodForPainting; + /** The currently selected mask inside the above LOD to be painted */ + int32 SelectedClothingLodMaskForPainting; + UNREALED_API void ToggleMeshSectionForCloth(FGuid InClothGuid); // fixes up the disabled flags so clothing is enabled and originals are disabled as diff --git a/Engine/Source/Editor/UnrealEd/Classes/Animation/EditorSkeletonNotifyObj.h b/Engine/Source/Editor/UnrealEd/Classes/Animation/EditorSkeletonNotifyObj.h index 2ca7ec3e493e..927ef4783856 100644 --- a/Engine/Source/Editor/UnrealEd/Classes/Animation/EditorSkeletonNotifyObj.h +++ b/Engine/Source/Editor/UnrealEd/Classes/Animation/EditorSkeletonNotifyObj.h @@ -14,19 +14,6 @@ class UAnimSequenceBase; DECLARE_DELEGATE_TwoParams( FOnAnimObjectChange, class UObject*, bool) -USTRUCT() -struct FSkeletonNotifyDependentAnimations -{ - GENERATED_USTRUCT_BODY() - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=SkeletonNotifies) - TArray Animations; - - FSkeletonNotifyDependentAnimations() - { - } -}; - UCLASS(MinimalAPI) class UEditorSkeletonNotifyObj : public UObject { diff --git a/Engine/Source/Editor/UnrealEd/Classes/Commandlets/FixupRedirectsCommandlet.h b/Engine/Source/Editor/UnrealEd/Classes/Commandlets/FixupRedirectsCommandlet.h deleted file mode 100644 index c12511216781..000000000000 --- a/Engine/Source/Editor/UnrealEd/Classes/Commandlets/FixupRedirectsCommandlet.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "CoreMinimal.h" -#include "UObject/ObjectMacros.h" -#include "Commandlets/Commandlet.h" -#include "FixupRedirectsCommandlet.generated.h" - -UCLASS() -class UFixupRedirectsCommandlet : public UCommandlet -{ - GENERATED_UCLASS_BODY() - //~ Begin UCommandlet Interface - virtual void CreateCustomEngine(const FString& Params) override; - virtual int32 Main(const FString& Params) override; - //~ End UCommandlet Interface -}; - - diff --git a/Engine/Source/Editor/UnrealEd/Classes/Commandlets/ResavePackagesCommandlet.h b/Engine/Source/Editor/UnrealEd/Classes/Commandlets/ResavePackagesCommandlet.h index e2edb95cf440..96ace9d73fcb 100644 --- a/Engine/Source/Editor/UnrealEd/Classes/Commandlets/ResavePackagesCommandlet.h +++ b/Engine/Source/Editor/UnrealEd/Classes/Commandlets/ResavePackagesCommandlet.h @@ -81,18 +81,21 @@ protected: /** Ignore package version changelist **/ bool bIgnoreChangelist; - // Running count of packages that got modified and will need to be resaved + /** Running count of packages that got modified and will need to be resaved */ int32 PackagesRequiringResave; /** Only collect garbage after N packages */ int32 GarbageCollectionFrequency; - // List of files to submit + /** List of files to submit */ TArray FilesToSubmit; - // The list of switches that were passed on the commandline + /** The list of switches that were passed on the commandline */ TArray Switches; + /** List of redirector packages that should be fixed up at the end */ + TArray RedirectorsToFixup; + /** * Evaluates the command-line to determine which maps to check. By default all maps are checked * Provides child classes with a chance to initialize any variables, parse the command line, etc. @@ -104,12 +107,15 @@ protected: */ virtual int32 InitializeResaveParameters( const TArray& Tokens, TArray& MapPathNames ); - // Loads and saves a single package + /** Loads and saves a single package */ virtual void LoadAndSaveOnePackage(const FString& Filename); - // Checks to see if a package should be skipped + /** Checks to see if a package should be skipped */ virtual bool ShouldSkipPackage(const FString& Filename); + /** Deletes a single package */ + virtual void DeleteOnePackage(const FString& Filename); + /** * Allow the commandlet to perform any operations on the export/import table of the package before all objects in the package are loaded. * diff --git a/Engine/Source/Editor/UnrealEd/Classes/CookOnTheSide/CookOnTheFlyServer.h b/Engine/Source/Editor/UnrealEd/Classes/CookOnTheSide/CookOnTheFlyServer.h index 6e7af449f7ac..e641c7fa2ee6 100644 --- a/Engine/Source/Editor/UnrealEd/Classes/CookOnTheSide/CookOnTheFlyServer.h +++ b/Engine/Source/Editor/UnrealEd/Classes/CookOnTheSide/CookOnTheFlyServer.h @@ -18,8 +18,10 @@ CookOnTheFlyServer.h : handles polite cook requests via network ;) #include "HAL/PlatformProcess.h" #include "TickableEditorObject.h" #include "IPlatformFileSandboxWrapper.h" +#include "Interfaces/INetworkFileSystemModule.h" #include "CookOnTheFlyServer.generated.h" + class FAssetRegistryGenerator; class ITargetPlatform; struct FPropertyChangedEvent; @@ -103,7 +105,7 @@ class UNREALED_API UCookOnTheFlyServer : public UObject, public FTickableEditorO { GENERATED_BODY() - UCookOnTheFlyServer(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); + UCookOnTheFlyServer(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); private: @@ -857,6 +859,7 @@ private: // Cook on the fly options /** Cook on the fly server uses the NetworkFileServer */ TArray NetworkFileServers; + FOnFileModifiedDelegate FileModifiedDelegate; ////////////////////////////////////////////////////////////////////////// // General cook options @@ -881,6 +884,10 @@ private: mutable bool bIgnoreMarkupPackageAlreadyLoaded; // avoid marking up packages as already loaded (want to put this around some functionality as we want to load packages fully some times) bool bIsSavingPackage; // used to stop recursive mark package dirty functions + + TMap MaxAsyncCacheForType; // max number of objects of a specific type which are allowed to async cache at once + mutable TMap CurrentAsyncCacheForType; // max number of objects of a specific type which are allowed to async cache at once + /** List of additional plugin directories to remap into the sandbox as needed */ TArray > PluginsToRemap; @@ -893,6 +900,12 @@ private: int32 MaxPrecacheShaderJobs; void TickPrecacheObjectsForPlatforms(const float TimeSlice, const TArray& TargetPlatform); + // presave system + // call this to save packages which are in memory as cooked packages, useful when the editor is idle + // shouldn't consume additional resources + TArray PresaveTargetPlatforms; + void OpportunisticSaveInMemoryPackages(); + ////////////////////////////////////////////////////////////////////////// // data about the current packages being processed @@ -905,6 +918,7 @@ private: bool bFinishedCacheFinished; bool bIsValid; TArray CachedObjectsInOuter; + TMap BeginCacheCallCount; FReentryData() : FileName(NAME_None), bBeginCacheFinished(false), BeginCacheCount(0), bFinishedCacheFinished(false), bIsValid(false) { } @@ -918,9 +932,9 @@ private: } }; - TMap PackageReentryData; + mutable TMap PackageReentryData; - FReentryData& GetReentryData(const UPackage* Package); + FReentryData& GetReentryData(const UPackage* Package) const; FThreadSafeQueue RecompileRequests; FFilenameQueue CookRequests; // list of requested files @@ -959,7 +973,7 @@ private: /** Map of platform name to asset registry generators, which hold the state of asset registry data for a platform */ TMap RegistryGenerators; - + ////////////////////////////////////////////////////////////////////////// // iterative ini settings checking // growing list of ini settings which are accessed over the course of the cook @@ -982,6 +996,18 @@ private: * used to reset the cached cooked shaders */ void OnTargetPlatformChangedSupportedFormats(const ITargetPlatform* TargetPlatform); + + /** + * Returns the current set of cooking targetplatforms + * mostly used for cook on the fly or in situations where the cooker can't figure out what the target platform is + * + * @return Array of target platforms which are can be used + */ + const TArray& GetCookingTargetPlatforms() const; + + /** Cached cooking target platforms from the targetmanager, these are used when we don't know what platforms we should be targeting */ + mutable TArray CookingTargetPlatforms; + public: enum ECookOnTheSideResult @@ -1012,6 +1038,12 @@ public: */ virtual bool Exec(class UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) override; + /** + * Dumps cooking stats to the log + * run from the exec command "Cook stats" + */ + void DumpStats(); + /** * Initialize the CookServer so that either CookOnTheFly can be called or Cook on the side can be started and ticked */ @@ -1374,6 +1406,15 @@ private: ////////////////////////////////////////////////////////////////////////// // cook on the fly specific functions + + /** + * When we get a new connection from the network make sure the version is compatible + * Will terminate the connection if return false + * + * @return return false if not compatible, true if it is + */ + bool HandleNetworkFileServerNewConnection( const FString& VersionInfo, const FString& PlatformName ); + /** * Cook requests for a package from network * blocks until cook is complete @@ -1392,6 +1433,21 @@ private: */ void HandleNetworkFileServerRecompileShaders(const struct FShaderRecompileData& RecompileData); + /** + * Get the sandbox path we want the network file server to use + */ + FString HandleNetworkGetSandboxPath(); + + + /** + * HandleNetworkGetPrecookedList + * this is used specifically for cook on the fly with shared cooked builds + * returns the list of files which are still valid in the pak file which was initially loaded + * + * @param PrecookedFileList all the files which are still valid in the client pak file + */ + void HandleNetworkGetPrecookedList( const FString& PlatformName, TMap& PrecookedFileList ); + ////////////////////////////////////////////////////////////////////////// // general functions @@ -1404,12 +1460,46 @@ private: */ bool ShouldCook(const FString& InFileName, const FName& InPlatformName); + /** + * Tries to save all the UPackages in the PackagesToSave list + * uses the timer to time slice, any packages not saved are requeued in the CookRequests list + * internal function should not be used externally Call Tick / RequestPackage to initiate + * + * @param PackagesToSave packages requested save + * @param TargetPlatformNames list of target platforms names that we want to save this package for + * @param TargetPlatformsToCache list of target platforms that we want to cache uobjects for, might not be the same as the list of packages to save + * @param Timer FCookerTimer struct which defines the timeslicing behavior + * @param FirstUnsolicitedPackage first package which was not actually requested, unsolicited packages are prioritized differently, they are saved the same way + * @param Result (in+out) used to modify the result of the operation and add any relevant flags + * @return returns true if we saved all the packages false if we bailed early for any reason + */ + bool SaveCookedPackages(TArray& PackagesToSave, const TArray& TargetPlatformNames, const TArray& TargetPlatformsToCache, struct FCookerTimer& Timer, int32 FirstUnsolicitedPackage, uint32& CookedPackageCount, uint32& Result); + + /** + * Returns all packages which are found in memory which aren't cooked + * + * @param PackagesToSave (in+out) filled with all packages in memory + * @param TargetPlatformNames list of target platforms to find unsolicited packages for + * @param ContainsFullAssetGCClasses do these packages contain any of the assets which require a GC after cooking + * (this is mostly historical for when objects like UWorld were global, almost nothing should require a GC to work correctly after being cooked anymore). + */ + void GetAllUnsolicitedPackages(TArray& PackagesToSave, const TArray& TargetPlatformNames, bool& ContainsFullAssetGCClasses); + + + /** + * Loads a package and prepares it for cooking + * this is the same as a normal load but also ensures that the sublevels are loaded if they are streaming sublevels + * + * @param BuildFilename long package name of the package to load + * @return UPackage of the package loaded, null if the file didn't exist or other failure + */ + UPackage* LoadPackageForCooking(const FString& BuildFilename); /** * Makes sure a package is fully loaded before we save it out * returns true if it succeeded */ - bool MakePackageFullyLoaded(UPackage* Package); + bool MakePackageFullyLoaded(UPackage* Package) const; /** * Initialize the sandbox @@ -1457,6 +1547,7 @@ private: */ bool ContainsMap(const FName& PackageName) const; + /** * Returns true if this package contains a redirector, and fills in paths * @@ -1465,6 +1556,25 @@ private: * @return true if the Package contains a redirector false otherwise */ bool ContainsRedirector(const FName& PackageName, TMap& RedirectedPaths) const; + + /** + * Calls BeginCacheForCookedPlatformData on all UObjects in the package + * + * @param Package the package used to gather all uobjects from + * @param TargetPlatforms target platforms to cache for + * @return false if time slice was reached, true if all objects have had BeginCacheForCookedPlatformData called + */ + bool BeginPackageCacheForCookedPlatformData(UPackage* Package, const TArray& TargetPlatforms, struct FCookerTimer& Timer) const; + + /** + * Returns true when all objects in package have all their cooked platform data loaded + * confirms that BeginCacheForCookedPlatformData is called and will return true after all objects return IsCachedCookedPlatformDataLoaded true + * + * @param Package the package used to gather all uobjects from + * @param TargetPlatforms target platforms to cache for + * @return false if time slice was reached, true if all return true for IsCachedCookedPlatformDataLoaded + */ + bool FinishPackageCacheForCookedPlatformData(UPackage* Package, const TArray& TargetPlatforms, struct FCookerTimer& Timer) const; /** * GetCurrentIniVersionStrings gets the current ini version strings for compare against previous cook @@ -1581,7 +1691,7 @@ private: * * @return ESavePackageResult::Success if packages was cooked */ - void SaveCookedPackage(UPackage* Package, uint32 SaveFlags, bool& bOutWasUpToDate, TArray& SavePackageResults); + void SaveCookedPackage(UPackage* Package, uint32 SaveFlags, TArray& SavePackageResults); /** * Cook (save) the given package * @@ -1593,7 +1703,7 @@ private: * * @return ESavePackageResult::Success if packages was cooked */ - void SaveCookedPackage(UPackage* Package, uint32 SaveFlags, bool& bOutWasUpToDate, TArray &TargetPlatformNames, TArray& SavePackageResults); + void SaveCookedPackage(UPackage* Package, uint32 SaveFlags, TArray &TargetPlatformNames, TArray& SavePackageResults); /** diff --git a/Engine/Source/Editor/UnrealEd/Classes/Editor/EditorEngine.h b/Engine/Source/Editor/UnrealEd/Classes/Editor/EditorEngine.h index 72614cdf8cad..921e0c8d486c 100644 --- a/Engine/Source/Editor/UnrealEd/Classes/Editor/EditorEngine.h +++ b/Engine/Source/Editor/UnrealEd/Classes/Editor/EditorEngine.h @@ -440,7 +440,7 @@ public: uint32 bEnableLODLocking:1; /** If true, actors can be grouped and grouping rules will be maintained. When deactivated, any currently existing groups will still be preserved.*/ - UPROPERTY(EditAnywhere, config, Category=Advanced) + DEPRECATED(4.17, "bGroupingActive has been deprecated. Use UActorGroupingUtils::IsGroupingActive instead") uint32 bGroupingActive:1; UPROPERTY(config) @@ -708,11 +708,6 @@ public: DECLARE_EVENT_OneParam( UEditorEngine, FGetActorRecordingState, bool& /* bIsRecordingActive */ ); FGetActorRecordingState& GetActorRecordingState() { return GetActorRecordingStateEvent; } - - - - - /** Editor-only event triggered when a HLOD Actor is moved between clusters */ DECLARE_EVENT_TwoParams(UEngine, FHLODActorMovedEvent, const AActor*, const AActor*); FHLODActorMovedEvent& OnHLODActorMoved() { return HLODActorMovedEvent; } @@ -761,36 +756,32 @@ public: /** Called by internal engine systems after an Actor is removed from a cluster */ void BroadcastHLODActorRemovedFromCluster(const AActor* InActor, const AActor* ParentActor) { HLODActorRemovedFromClusterEvent.Broadcast(InActor, ParentActor); } - - - - /** - * Called before an actor or component is about to be translated, rotated, or scaled by the editor - * - * @param Object The actor or component that will be moved - */ + * Called before an actor or component is about to be translated, rotated, or scaled by the editor + * + * @param Object The actor or component that will be moved + */ void BroadcastBeginObjectMovement(UObject& Object) const { OnBeginObjectTransformEvent.Broadcast(Object); } /** - * Called when an actor or component has been translated, rotated, or scaled by the editor - * - * @param Object The actor or component that moved - */ + * Called when an actor or component has been translated, rotated, or scaled by the editor + * + * @param Object The actor or component that moved + */ void BroadcastEndObjectMovement(UObject& Object) const { OnEndObjectTransformEvent.Broadcast(Object); } /** - * Called before the camera viewed through the viewport is moved by the editor - * - * @param Object The camera that will be moved - */ + * Called before the camera viewed through the viewport is moved by the editor + * + * @param Object The camera that will be moved + */ void BroadcastBeginCameraMovement(UObject& Object) const { OnBeginCameraTransformEvent.Broadcast(Object); } /** - * Called when the camera viewed through the viewport has been moved by the editor - * - * @param Object The camera that moved - */ + * Called when the camera viewed through the viewport has been moved by the editor + * + * @param Object The camera that moved + */ void BroadcastEndCameraMovement(UObject& Object) const { OnEndCameraTransformEvent.Broadcast(Object); } /** Broadcasts that an object has been reimported. THIS SHOULD NOT BE PUBLIC */ @@ -1353,7 +1344,7 @@ public: /** * Paste selected actors from the clipboard. * - * @param InWorld World conext + * @param InWorld World context * @param bDuplicate Is this a duplicate operation (as opposed to a real paste)? * @param bOffsetLocations Should the actor locations be offset after they are created? * @param bWarnIfHidden If true displays a warning if the destination level is hidden @@ -1929,15 +1920,9 @@ public: * * @param InLevel The destination level. */ + DEPRECATED(4.17, "MoveSelectedActorsToLevel has been deprecated. Use UEditorLevelUtils::MoveSelectedActorsToLevel instead") void MoveSelectedActorsToLevel( ULevel* InLevel ); - /** - * Moves selected foliage instances to the target level. - * - * @param InLevel The target level. - */ - void MoveSelectedFoliageToLevel( ULevel* InTargetLevel ); - /** * Returns list of all foliage types used in the world * @@ -2526,6 +2511,11 @@ public: /** Sets the delegate for when the focused PIE window is changed */ void SetPIEInstanceWindowSwitchDelegate(FPIEInstanceWindowSwitch PIEInstanceWindowSwitchDelegate); + /** + * Returns the actor grouping utility class that performs all grouping related tasks + * This will create the class instance if it doesn't exist. + */ + class UActorGroupingUtils* GetActorGroupingUtils(); private: // @@ -2563,15 +2553,6 @@ private: * @return true if a static mesh was loaded; false, otherwise. */ bool LoadPreviewMesh( int32 Index ); - - /** - * Moves selected actors to the current level - NB. This is only intended to be called from MoveSelectedActorsToCurrentLevel() - * Note also that this contents of the copy buffer will be lost during the operation - * - * @param InLevel Destination level. - */ - void DoMoveSelectedActorsToLevel( ULevel* InLevel ); - public: /** Creates a PIE world by saving to a temp file and then reloading it */ UWorld* CreatePIEWorldBySavingToTemp(FWorldContext &WorldContext, UWorld* InWorld, FString &PlayWorldMapName); @@ -2889,7 +2870,7 @@ protected: * Launch a standalone instance on this PC. * * @param MapNameOverride Map name override - * @param WindowPos Postion we want to put the window we create. + * @param WindowPos Position we want to put the window we create. * @param PIENum PIE instance count * @param bIsServer Is this instance a server. */ @@ -2961,7 +2942,6 @@ public: /** Function to run the Play On command for automation testing. */ void AutomationPlayUsingLauncher(const FString& InLauncherDeviceId); -public: /** * Given a label, attempts to split this into its alpha/numeric parts. * @@ -2987,6 +2967,13 @@ public: void AutomationLoadMap(const FString& MapName, FString* OutError); +protected: + + UPROPERTY(EditAnywhere, config, Category = Advanced, meta = (MetaClass = "ActorGroupingUtils")) + FStringClassReference ActorGroupingUtilsClassName; + + UPROPERTY() + class UActorGroupingUtils* ActorGroupingUtils; private: FTimerHandle CleanupPIEOnlineSessionsTimerHandle; diff --git a/Engine/Source/Editor/UnrealEd/Classes/Editor/EditorPerProjectUserSettings.h b/Engine/Source/Editor/UnrealEd/Classes/Editor/EditorPerProjectUserSettings.h index 5d19e568909e..b16a763ac7d0 100644 --- a/Engine/Source/Editor/UnrealEd/Classes/Editor/EditorPerProjectUserSettings.h +++ b/Engine/Source/Editor/UnrealEd/Classes/Editor/EditorPerProjectUserSettings.h @@ -5,6 +5,7 @@ #include "CoreMinimal.h" #include "UObject/ObjectMacros.h" #include "UObject/Object.h" +#include "Engine/EngineTypes.h" #include "EditorPerProjectUserSettings.generated.h" // Fbx export compatibility @@ -96,6 +97,14 @@ class UEditorPerProjectUserSettings : public UObject UPROPERTY(EditAnywhere, config, Category=HotReload) uint32 bShowCompilerLogOnCompileError : 1; + /** If enabled, the fbx option dialog will show when user re-import a fbx */ + UPROPERTY(EditAnywhere, config, Category = Import) + uint32 bShowImportDialogAtReimport : 1; + + /** Specify a project data source folder to store relative source file path to ease the re-import process*/ + UPROPERTY(EditAnywhere, config, Category = Import) + FDirectoryPath DataSourceFolder; + /** If enabled, export level with attachment hierarchy set */ UPROPERTY(EditAnywhere, config, Category=Export) uint32 bKeepAttachHierarchy:1; @@ -185,7 +194,9 @@ public: FUserSettingChangedEvent& OnUserSettingChanged() { return UserSettingChangedEvent; } //~ Begin UObject Interface - virtual void PostEditChangeProperty( struct FPropertyChangedEvent& PropertyChangedEvent ) override; +#if WITH_EDITOR + virtual void PostEditChangeProperty( FPropertyChangedEvent& PropertyChangedEvent ) override; +#endif virtual void PostInitProperties() override; //~ End UObject Interface diff --git a/Engine/Source/Editor/UnrealEd/Classes/Editor/Transactor.h b/Engine/Source/Editor/UnrealEd/Classes/Editor/Transactor.h index 421888d3c7b6..2146f4529035 100644 --- a/Engine/Source/Editor/UnrealEd/Classes/Editor/Transactor.h +++ b/Engine/Source/Editor/UnrealEd/Classes/Editor/Transactor.h @@ -242,13 +242,6 @@ protected: } return *this; } - FArchive& operator<<(class FAssetPtr& AssetPtr) override - { - FStringAssetReference ID; - ID.Serialize(*this); - AssetPtr = ID; - return *this; - } void Preload( UObject* InObject ) override { if( Owner ) @@ -338,12 +331,6 @@ protected: } return (FArchive&)*this << ObjectIndex; } - FArchive& operator<<(class FAssetPtr& AssetPtr) - { - FStringAssetReference ID = AssetPtr.GetUniqueID(); - ID.Serialize(*this); - return *this; - } TArray& Data; ObjectMapType ObjectMap; TArray& ReferencedObjects; @@ -385,6 +372,10 @@ public: , Inc(-1) {} + virtual ~FTransaction() + { + } + private: // Non-copyable FTransaction( const FTransaction& ) = delete; diff --git a/Engine/Source/Editor/UnrealEd/Classes/Editor/UnrealEdEngine.h b/Engine/Source/Editor/UnrealEd/Classes/Editor/UnrealEdEngine.h index 7eda890dca30..7824a9aae154 100644 --- a/Engine/Source/Editor/UnrealEd/Classes/Editor/UnrealEdEngine.h +++ b/Engine/Source/Editor/UnrealEd/Classes/Editor/UnrealEdEngine.h @@ -432,32 +432,38 @@ public: /** * Creates a new group from the current selection removing any existing groups. */ + DEPRECATED(4.17, "edactRegroupFromSelected is deprecated, use UActorGroupingUtils::GroupSelected") virtual void edactRegroupFromSelected(); /** * Disbands any groups in the current selection, does not attempt to maintain any hierarchy */ + DEPRECATED(4.17, "edactUngroupFromSelected is deprecated, use UActorGroupingUtils::UngroupSelected") virtual void edactUngroupFromSelected(); /** * Locks any groups in the current selection */ + DEPRECATED(4.17, "edactLockSelectedGroups is deprecated, use UActorGroupingUtils::LockSelectedGroups") virtual void edactLockSelectedGroups(); /** * Unlocks any groups in the current selection */ + DEPRECATED(4.17, "edactUnlockSelectedGroups is deprecated, use UActorGroupingUtils::UnlockSelectedGroups") virtual void edactUnlockSelectedGroups(); /** * Activates "Add to Group" mode which allows the user to select a group to append current selection */ + DEPRECATED(4.17, "edactAddToGroup is deprecated, use UActorGroupingUtils::AddSelectedToGroup") virtual void edactAddToGroup(); /** * Removes any groups or actors in the current selection from their immediate parent. * If all actors/subgroups are removed, the parent group will be destroyed. */ + DEPRECATED(4.17, "edactRemoveFromGroup is deprecated, use UActorGroupingUtils::RemoveSelectedFromGroup") virtual void edactRemoveFromGroup(); /** diff --git a/Engine/Source/Editor/UnrealEd/Classes/Editor/UnrealEdTypes.h b/Engine/Source/Editor/UnrealEd/Classes/Editor/UnrealEdTypes.h index 478ed32a48cb..d9d8a227be23 100644 --- a/Engine/Source/Editor/UnrealEd/Classes/Editor/UnrealEdTypes.h +++ b/Engine/Source/Editor/UnrealEd/Classes/Editor/UnrealEdTypes.h @@ -21,7 +21,7 @@ struct FLightmassParameterValue GENERATED_USTRUCT_BODY() /** If true, override the given parameter with the given settings */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=LightmassParameterValue) + UPROPERTY(EditAnywhere, Category=LightmassParameterValue) uint32 bOverride:1; @@ -39,7 +39,7 @@ struct FLightmassBooleanParameterValue : public FLightmassParameterValue GENERATED_USTRUCT_BODY() /** The boolean value to override the parent value with */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=LightmassBooleanParameterValue) + UPROPERTY(EditAnywhere, Category=LightmassBooleanParameterValue) uint32 ParameterValue:1; @@ -57,7 +57,7 @@ struct FLightmassScalarParameterValue : public FLightmassParameterValue GENERATED_USTRUCT_BODY() /** The scalar value to override the parent value with */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=LightmassScalarParameterValue) + UPROPERTY(EditAnywhere, Category=LightmassScalarParameterValue) float ParameterValue; @@ -78,22 +78,22 @@ struct FLightmassParameterizedMaterialSettings GENERATED_USTRUCT_BODY() /** If true, forces translucency to cast static shadows as if the material were masked. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=LightmassParameterizedMaterialSettings) + UPROPERTY(EditAnywhere, Category=LightmassParameterizedMaterialSettings) struct FLightmassBooleanParameterValue CastShadowAsMasked; /** Scales the emissive contribution of this material to static lighting. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=LightmassParameterizedMaterialSettings) + UPROPERTY(EditAnywhere, Category=LightmassParameterizedMaterialSettings) struct FLightmassScalarParameterValue EmissiveBoost; /** Scales the diffuse contribution of this material to static lighting. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=LightmassParameterizedMaterialSettings) + UPROPERTY(EditAnywhere, Category=LightmassParameterizedMaterialSettings) struct FLightmassScalarParameterValue DiffuseBoost; /** * Scales the resolution that this material's attributes were exported at. * This is useful for increasing material resolution when details are needed. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=LightmassParameterizedMaterialSettings) + UPROPERTY(EditAnywhere, Category=LightmassParameterizedMaterialSettings) struct FLightmassScalarParameterValue ExportResolutionScale; FLightmassParameterizedMaterialSettings() diff --git a/Engine/Source/Editor/UnrealEd/Classes/Factories/FbxImportUI.h b/Engine/Source/Editor/UnrealEd/Classes/Factories/FbxImportUI.h index c90189e15ed3..6aa3bc6c7bfc 100644 --- a/Engine/Source/Editor/UnrealEd/Classes/Factories/FbxImportUI.h +++ b/Engine/Source/Editor/UnrealEd/Classes/Factories/FbxImportUI.h @@ -26,6 +26,8 @@ enum EFBXImportType FBXIT_MAX, }; +DECLARE_DELEGATE(FOnPreviewFbxImport); + UCLASS(config=EditorPerProjectUserSettings, AutoExpandCategories=(FTransform), HideCategories=Object, MinimalAPI) class UFbxImportUI : public UObject, public IImportSettingsParser { @@ -145,6 +147,12 @@ public: UPROPERTY() bool bAutomatedImportShouldDetectType; + /** If true the existing material array will be reset by the incoming fbx file. The matching "material import name" will be restore properly but, the entries that has no match will use the material instance of the existing data at the same index. (Never enable this option if you have gameplay code that use a material slot)*/ + UPROPERTY(EditAnywhere, config, AdvancedDisplay, Category = Material, meta = (OBJRestrict = "true", ImportType = "Mesh")) + uint32 bResetMaterialSlots : 1; + + void ResetToDefault(); + /** UObject Interface */ virtual bool CanEditChange( const UProperty* InProperty ) const override; @@ -156,6 +164,9 @@ public: { MeshTypeToImport = bImportAsSkeletal ? FBXIT_SkeletalMesh : FBXIT_StaticMesh; } + + /* Whether this UI is construct for a reimport */ + bool bIsReimport; }; diff --git a/Engine/Source/Editor/UnrealEd/Classes/Factories/FbxSceneImportFactory.h b/Engine/Source/Editor/UnrealEd/Classes/Factories/FbxSceneImportFactory.h index ab52cf85f35b..b67ad8cbfef7 100644 --- a/Engine/Source/Editor/UnrealEd/Classes/Factories/FbxSceneImportFactory.h +++ b/Engine/Source/Editor/UnrealEd/Classes/Factories/FbxSceneImportFactory.h @@ -381,6 +381,10 @@ class UNREALED_API UFbxSceneImportFactory : public USceneImportFactory /* Default Options always have the same name "Default" */ static FString DefaultOptionName; +public: + static TSharedPtr ConvertSceneInfo(void* VoidFbxImporter, void* VoidFbxSceneInfo); + static void ExtractMaterialInfo(void* FbxImporterVoid, TSharedPtr SceneInfoPtr); + protected: /** Convert the scene and remake all the transform for the SceneInfo pass in parameter. * We need this because EvaluateGlobal and EvaluateLocal are dependent of the scene conversion. @@ -428,8 +432,6 @@ protected: /** Create a package for the specified node. Package will be the concatenation of UFbxSceneImportFactory::Path and Node->GetName(). */ UPackage *CreatePackageForNode(FString PackageName, FString &StaticMeshName); - static TSharedPtr ConvertSceneInfo(void* VoidFbxImporter, void* VoidFbxSceneInfo); - static void ExtractMaterialInfo(void* FbxImporterVoid, TSharedPtr SceneInfoPtr); bool SetStaticMeshComponentOverrideMaterial(class UStaticMeshComponent* StaticMeshComponent, TSharedPtr NodeInfo); /** The path of the asset to import */ diff --git a/Engine/Source/Editor/UnrealEd/Classes/Factories/ForceFeedbackAttenuationFactory.h b/Engine/Source/Editor/UnrealEd/Classes/Factories/ForceFeedbackAttenuationFactory.h index 213b271f0b5b..4d184eab8b00 100644 --- a/Engine/Source/Editor/UnrealEd/Classes/Factories/ForceFeedbackAttenuationFactory.h +++ b/Engine/Source/Editor/UnrealEd/Classes/Factories/ForceFeedbackAttenuationFactory.h @@ -5,6 +5,7 @@ //~============================================================================= #pragma once +#include "Factories/Factory.h" #include "ForceFeedbackAttenuationFactory.generated.h" UCLASS(hidecategories=Object, MinimalAPI) diff --git a/Engine/Source/Editor/UnrealEd/Classes/MaterialEditor/DEditorParameterValue.h b/Engine/Source/Editor/UnrealEd/Classes/MaterialEditor/DEditorParameterValue.h index 4c50e6f1a48f..a5010d6ead74 100644 --- a/Engine/Source/Editor/UnrealEd/Classes/MaterialEditor/DEditorParameterValue.h +++ b/Engine/Source/Editor/UnrealEd/Classes/MaterialEditor/DEditorParameterValue.h @@ -23,5 +23,10 @@ class UNREALED_API UDEditorParameterValue : public UObject UPROPERTY() FGuid ExpressionId; +#if WITH_EDITORONLY_DATA + /** Controls where this parameter is displayed in a material instance parameter list. The lower the number the higher up in the parameter list. */ + UPROPERTY() + int32 SortPriority; +#endif }; diff --git a/Engine/Source/Editor/UnrealEd/Classes/MaterialEditor/MaterialEditorInstanceConstant.h b/Engine/Source/Editor/UnrealEd/Classes/MaterialEditor/MaterialEditorInstanceConstant.h index 107c7a53d354..44075039c55f 100644 --- a/Engine/Source/Editor/UnrealEd/Classes/MaterialEditor/MaterialEditorInstanceConstant.h +++ b/Engine/Source/Editor/UnrealEd/Classes/MaterialEditor/MaterialEditorInstanceConstant.h @@ -31,6 +31,9 @@ struct FEditorParameterGroup UPROPERTY(EditAnywhere, editfixedsize, Instanced, Category=EditorParameterGroup) TArray Parameters; + UPROPERTY() + int32 GroupSortPriority; + }; USTRUCT() diff --git a/Engine/Source/Editor/UnrealEd/Classes/MaterialGraph/MaterialGraphNode.h b/Engine/Source/Editor/UnrealEd/Classes/MaterialGraph/MaterialGraphNode.h index 3a626d8fd702..3b5312d12f5c 100644 --- a/Engine/Source/Editor/UnrealEd/Classes/MaterialGraph/MaterialGraphNode.h +++ b/Engine/Source/Editor/UnrealEd/Classes/MaterialGraph/MaterialGraphNode.h @@ -82,7 +82,7 @@ public: //~ End UMaterialGraphNode_Base Interface /** Will return the shorten pin name to use based on long pin name */ - FString UNREALED_API GetShortenPinName(const FString& PinName); + static FString UNREALED_API GetShortenPinName(const FString& PinName); private: /** Make sure the MaterialExpression is owned by the Material */ diff --git a/Engine/Source/Editor/UnrealEd/Classes/Preferences/PersonaOptions.h b/Engine/Source/Editor/UnrealEd/Classes/Preferences/PersonaOptions.h index ca129883ba07..22326d63752a 100644 --- a/Engine/Source/Editor/UnrealEd/Classes/Preferences/PersonaOptions.h +++ b/Engine/Source/Editor/UnrealEd/Classes/Preferences/PersonaOptions.h @@ -83,6 +83,10 @@ class UNREALED_API UPersonaOptions : public UObject UPROPERTY(EditAnywhere, config, Category = Options) bool bAllowMeshSectionSelection; + /** The number of folder filters to allow at any one time in the animation tool's asset browser */ + UPROPERTY(EditAnywhere, config, Category = Options, meta=(ClampMin ="1", ClampMax = "10", UIMin = "1", UIMax = "10")) + uint32 NumFolderFiltersInAssetBrowser; + public: void SetViewportBackgroundColor( const FLinearColor& InViewportBackgroundColor); void SetShowGrid( bool bInShowGrid ); diff --git a/Engine/Source/Editor/UnrealEd/Classes/Settings/ContentBrowserSettings.h b/Engine/Source/Editor/UnrealEd/Classes/Settings/ContentBrowserSettings.h index 0fd033384dfc..8029167cabe1 100644 --- a/Engine/Source/Editor/UnrealEd/Classes/Settings/ContentBrowserSettings.h +++ b/Engine/Source/Editor/UnrealEd/Classes/Settings/ContentBrowserSettings.h @@ -31,10 +31,14 @@ public: UPROPERTY(config) bool RealTimeThumbnails; - /** Whether to display folders in the assets view of the content browser. Note that this implies 'Show Only Assets in Selected Folders'. */ + /** Whether to display folders in the asset view of the content browser. Note that this implies 'Show Only Assets in Selected Folders'. */ UPROPERTY(config) bool DisplayFolders; + /** Whether to empty display folders in the asset view of the content browser. */ + UPROPERTY(config) + bool DisplayEmptyFolders; + public: /** Sets whether we are allowed to display the engine folder or not, optional flag for setting override instead */ diff --git a/Engine/Source/Editor/UnrealEd/Classes/Settings/EditorExperimentalSettings.h b/Engine/Source/Editor/UnrealEd/Classes/Settings/EditorExperimentalSettings.h index a6a64673d2b4..cb550bb245f9 100644 --- a/Engine/Source/Editor/UnrealEd/Classes/Settings/EditorExperimentalSettings.h +++ b/Engine/Source/Editor/UnrealEd/Classes/Settings/EditorExperimentalSettings.h @@ -75,10 +75,6 @@ public: UPROPERTY(EditAnywhere, config, Category=Audio) bool bShowAudioStreamingOptions; - /** Whether to show AudioMixer-dependent editor data. Only enable if also running with the -audiomixer. */ - UPROPERTY(EditAnywhere, config, Category = Audio) - bool bShowAudioMixerData; - /** Allows ChunkIDs to be assigned to assets to via the content browser context menu. */ UPROPERTY(EditAnywhere,config,Category=UserInterface,meta=(DisplayName="Allow ChunkID Assignments")) bool bContextMenuChunkAssignments; @@ -87,6 +83,9 @@ public: UPROPERTY(EditAnywhere, config, Category = Cooking, meta = (DisplayName = "Disable Cook In The Editor feature (cooks from launch on will be run in a separate process if disabled)", ConfigRestartRequired=true)) bool bDisableCookInEditor; + UPROPERTY(EditAnywhere, config, Category = Cooking, meta = (DisplayName = "Use shared cooked builds in launch on", ConfigRestartRequired = true)) + bool bSharedCookedBuilds; + UPROPERTY(EditAnywhere, config, Category = Cooking, meta = (DisplayName = "Use multiple processes when cooking (only affects File -> Package)")) int32 MultiProcessCooking; @@ -94,10 +93,6 @@ public: UPROPERTY(EditAnywhere, config, Category = AI, meta = (DisplayName = "Environment Querying System")) bool bEQSEditor; - /** This feature allows you to broadcast to a live streaming service directly from the editor. This requires you to have a live streaming plugin installed. */ - UPROPERTY(EditAnywhere, config, Category=Tools) - bool bLiveStreamingFromEditor; - /** Enable late joining in PIE */ UPROPERTY(EditAnywhere, config, Category = PIE, meta = (DisplayName = "Allow late joining")) bool bAllowLateJoinInPIE; @@ -127,9 +122,13 @@ public: bool bFacialAnimationImporter; /** Enable experimental clothing tools (parameter painting and simulation configuration) found in the skeletal mesh editor */ - UPROPERTY(EditAnywhere, config, Category = Tools) + UPROPERTY(EditAnywhere, config, Category = Tools, meta = (ConfigRestartRequired = true)) bool bClothingTools; + /** Allow animation blueprints to be recompiled while a PIE session is running */ + UPROPERTY(EditAnywhere, config, Category = Tools) + bool bEnableLiveRecompilationOfAnimationBlueprints; + /** * Returns an event delegate that is executed when a setting has changed. * diff --git a/Engine/Source/Editor/UnrealEd/Classes/Settings/LevelEditorMiscSettings.h b/Engine/Source/Editor/UnrealEd/Classes/Settings/LevelEditorMiscSettings.h index f263f6c3e93f..2db19be3c13d 100644 --- a/Engine/Source/Editor/UnrealEd/Classes/Settings/LevelEditorMiscSettings.h +++ b/Engine/Source/Editor/UnrealEd/Classes/Settings/LevelEditorMiscSettings.h @@ -6,6 +6,7 @@ #include "UObject/ObjectMacros.h" #include "Templates/SubclassOf.h" #include "Engine/DeveloperSettings.h" +#include "Engine/EngineTypes.h" #include "LevelEditorMiscSettings.generated.h" class ULevelStreaming; @@ -65,6 +66,12 @@ public: UPROPERTY(EditAnywhere, config, Category=Levels) TSubclassOf DefaultLevelStreamingClass; +public: + + /** The save directory for newly created screenshots */ + UPROPERTY(EditAnywhere, config, Category = Screenshots) + FDirectoryPath EditorScreenshotSaveDirectory; + protected: // UObject overrides diff --git a/Engine/Source/Editor/UnrealEd/Classes/Settings/ProjectPackagingSettings.h b/Engine/Source/Editor/UnrealEd/Classes/Settings/ProjectPackagingSettings.h index 46dc527683c4..563043492c7f 100644 --- a/Engine/Source/Editor/UnrealEd/Classes/Settings/ProjectPackagingSettings.h +++ b/Engine/Source/Editor/UnrealEd/Classes/Settings/ProjectPackagingSettings.h @@ -149,10 +149,14 @@ public: UPROPERTY(config, EditAnywhere, Category = Packaging) FString HttpChunkInstallDataVersion; - /** Specifies whether to include prerequisites of packaged games, such as redistributable operating system components, whenever possible. */ - UPROPERTY(config, EditAnywhere, Category=Packaging) + /** Specifies whether to include an installer for prerequisites of packaged games, such as redistributable operating system components, on platforms that support it. */ + UPROPERTY(config, EditAnywhere, Category=Prerequisites, meta=(DisplayName="Include prerequisites installer")) bool IncludePrerequisites; + /** Specifies whether to include prerequisites alongside the game executable. */ + UPROPERTY(config, EditAnywhere, Category = Prerequisites, meta = (DisplayName = "Include app-local prerequisites")) + bool IncludeAppLocalPrerequisites; + /** * By default shader code gets saved inline inside material assets, * enabling this option will store only shader code once as individual files @@ -169,8 +173,8 @@ public: UPROPERTY(config, EditAnywhere, Category=Packaging) bool bSharedMaterialNativeLibraries; - /** A directory containing prerequisite packages that should be staged in the executable directory. Can be relative to $(EngineDir) or $(ProjectDir) */ - UPROPERTY(config, EditAnywhere, Category = Packaging, AdvancedDisplay) + /** A directory containing additional prerequisite packages that should be staged in the executable directory. Can be relative to $(EngineDir) or $(ProjectDir) */ + UPROPERTY(config, EditAnywhere, Category=Prerequisites, AdvancedDisplay) FDirectoryPath ApplocalPrerequisitesDirectory; /** diff --git a/Engine/Source/Editor/UnrealEd/Classes/ThumbnailRendering/SoundWaveThumbnailRenderer.h b/Engine/Source/Editor/UnrealEd/Classes/ThumbnailRendering/SoundWaveThumbnailRenderer.h index 6481bc3c551f..4101f86c3f1e 100644 --- a/Engine/Source/Editor/UnrealEd/Classes/ThumbnailRendering/SoundWaveThumbnailRenderer.h +++ b/Engine/Source/Editor/UnrealEd/Classes/ThumbnailRendering/SoundWaveThumbnailRenderer.h @@ -22,6 +22,7 @@ class USoundWaveThumbnailRenderer : public UThumbnailRenderer // Begin UThumbnailRenderer Object virtual void Draw(UObject* Object, int32 X, int32 Y, uint32 Width, uint32 Height, FRenderTarget*, FCanvas* Canvas) override; + virtual bool AllowsRealtimeThumbnails(UObject* Object) const override { return false; } // End UThumbnailRenderer Object }; diff --git a/Engine/Source/Editor/UnrealEd/Classes/ThumbnailRendering/ThumbnailRenderer.h b/Engine/Source/Editor/UnrealEd/Classes/ThumbnailRendering/ThumbnailRenderer.h index 68b3e079d7bc..d4f9db3e40a1 100644 --- a/Engine/Source/Editor/UnrealEd/Classes/ThumbnailRendering/ThumbnailRenderer.h +++ b/Engine/Source/Editor/UnrealEd/Classes/ThumbnailRendering/ThumbnailRenderer.h @@ -53,5 +53,16 @@ public: * @param Canvas the render interface to draw with */ virtual void Draw(UObject* Object, int32 X, int32 Y, uint32 Width, uint32 Height, FRenderTarget* Viewport, FCanvas* Canvas) PURE_VIRTUAL(UThumbnailRenderer::Draw,); + + /** + * Checks to see if the specified asset supports realtime thumbnails, which will cause them to always be rerendered to reflect any changes + * made to the asset. If this is false, thumbnails should render once and then not update again. + * For most renderers, this should remain as true. + * + * @param Object The asset to draw the thumbnail for + * + * @return True if the thumbnail needs to always be redrawn, false if it can be just drawn once and then reused. + */ + virtual bool AllowsRealtimeThumbnails(UObject* Object) const { return true; } }; diff --git a/Engine/Source/Editor/UnrealEd/Classes/UserDefinedStructure/UserDefinedStructEditorData.h b/Engine/Source/Editor/UnrealEd/Classes/UserDefinedStructure/UserDefinedStructEditorData.h index 3b16b01711b9..323c145792fe 100644 --- a/Engine/Source/Editor/UnrealEd/Classes/UserDefinedStructure/UserDefinedStructEditorData.h +++ b/Engine/Source/Editor/UnrealEd/Classes/UserDefinedStructure/UserDefinedStructEditorData.h @@ -44,16 +44,31 @@ struct FStructVariableDescription FEdGraphTerminalType PinValueType; UPROPERTY() - bool bIsArray; + EPinContainerType ContainerType; + // DEPRECATED(4.17) UPROPERTY() - bool bIsSet; + uint8 bIsArray_DEPRECATED:1; + // DEPRECATED(4.17) UPROPERTY() - bool bIsMap; + uint8 bIsSet_DEPRECATED:1; + + // DEPRECATED(4.17) + UPROPERTY() + uint8 bIsMap_DEPRECATED:1; UPROPERTY(Transient) - bool bInvalidMember; + uint8 bInvalidMember:1; + + UPROPERTY() + uint8 bDontEditoOnInstance:1; + + UPROPERTY() + uint8 bEnableMultiLineText:1; + + UPROPERTY() + uint8 bEnable3dWidget:1; // CurrentDefaultValue stores the actual default value, after the DefaultValue was changed, and before the struct was recompiled UPROPERTY() @@ -62,23 +77,18 @@ struct FStructVariableDescription UPROPERTY() FString ToolTip; - UPROPERTY() - bool bDontEditoOnInstance; - - UPROPERTY() - bool bEnableMultiLineText; - - UPROPERTY() - bool bEnable3dWidget; - UNREALED_API bool SetPinType(const struct FEdGraphPinType& VarType); UNREALED_API FEdGraphPinType ToPinType() const; + // DEPRECATED(4.17) + void PostSerialize(const FArchive& Ar); + FStructVariableDescription() - : bIsArray(false) - , bIsSet(false) - , bIsMap(false) + : ContainerType(EPinContainerType::None) + , bIsArray_DEPRECATED(false) + , bIsSet_DEPRECATED(false) + , bIsMap_DEPRECATED(false) , bInvalidMember(false) , bDontEditoOnInstance(false) , bEnableMultiLineText(false) @@ -86,6 +96,15 @@ struct FStructVariableDescription { } }; +template<> +struct TStructOpsTypeTraits< FStructVariableDescription > : public TStructOpsTypeTraitsBase2< FStructVariableDescription > +{ + enum + { + WithPostSerialize = true, + }; +}; + class FStructOnScopeMember : public FStructOnScope { public: diff --git a/Engine/Source/Editor/UnrealEd/Private/ActorGroupingUtils.cpp b/Engine/Source/Editor/UnrealEd/Private/ActorGroupingUtils.cpp new file mode 100644 index 000000000000..14874688b716 --- /dev/null +++ b/Engine/Source/Editor/UnrealEd/Private/ActorGroupingUtils.cpp @@ -0,0 +1,249 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "ActorGroupingUtils.h" +#include "Editor.h" +#include "Engine/Selection.h" +#include "Editor/GroupActor.h" +#include "ScopedTransaction.h" +#include "MessageDialog.h" +#include "NotificationManager.h" +#include "SNotificationList.h" + +bool UActorGroupingUtils::bGroupingActive = true; + +void UActorGroupingUtils::SetGroupingActive(bool bInGroupingActive) +{ + bGroupingActive = bInGroupingActive; +} + +UActorGroupingUtils* UActorGroupingUtils::Get() +{ + // @todo ActorGrouping This should be moved off of GEditor + return GEditor->GetActorGroupingUtils(); +} + +void UActorGroupingUtils::GroupSelected() +{ + if (IsGroupingActive()) + { + TArray ActorsToAdd; + for (FSelectionIterator It(GEditor->GetSelectedActorIterator()); It; ++It) + { + ActorsToAdd.Add(CastChecked(*It)); + } + + if (ActorsToAdd.Num() > 0) + { + GroupActors(ActorsToAdd); + } + } +} + +void UActorGroupingUtils::GroupActors(const TArray& ActorsToGroup) +{ + if(IsGroupingActive()) + { + ULevel* ActorLevel = nullptr; + TArray FinalActorList; + + bool bActorsInSameLevel = true; + for (AActor* Actor : ActorsToGroup) + { + if (!ActorLevel) + { + ActorLevel = Actor->GetLevel(); + } + else if (ActorLevel != Actor->GetLevel()) + { + bActorsInSameLevel = false; + break; + } + + if (Actor->IsA(AActor::StaticClass()) && !Actor->IsA(AGroupActor::StaticClass())) + { + // Add each selected actor to our new group + // Adding an actor will remove it from any existing groups. + FinalActorList.Add(Actor); + + } + } + + if (bActorsInSameLevel) + { + if (FinalActorList.Num() > 1) + { + check(ActorLevel); + // Store off the current level and make the level that contain the actors to group as the current level + UWorld* World = ActorLevel->OwningWorld; + check(World); + { + const FScopedTransaction Transaction(NSLOCTEXT("UnrealEd", "Group_Regroup", "Regroup Ctrl+G")); + + FActorSpawnParameters SpawnInfo; + SpawnInfo.OverrideLevel = ActorLevel; + AGroupActor* SpawnedGroupActor = World->SpawnActor(SpawnInfo); + + for (int32 ActorIndex = 0; ActorIndex < FinalActorList.Num(); ++ActorIndex) + { + SpawnedGroupActor->Add(*FinalActorList[ActorIndex]); + } + + SpawnedGroupActor->CenterGroupLocation(); + SpawnedGroupActor->Lock(); + } + } + } + else + { + const FText NotificationErrorText = NSLOCTEXT("UnrealEd", "Group_CantCreateGroupMultipleLevels", "Can't group the selected actors because they are in different levels."); + FNotificationInfo Info(NotificationErrorText); + Info.ExpireDuration = 5.0f; + FSlateNotificationManager::Get().AddNotification(Info); + } + } +} + +void UActorGroupingUtils::UngroupSelected() +{ + if (IsGroupingActive()) + { + TArray ActorsToUngroup; + + for (FSelectionIterator It(GEditor->GetSelectedActorIterator()); It; ++It) + { + AActor* Actor = CastChecked(*It); + ActorsToUngroup.Add(Actor); + } + + if (ActorsToUngroup.Num()) + { + UngroupActors(ActorsToUngroup); + } + } +} + +void UActorGroupingUtils::UngroupActors(const TArray& ActorsToUngroup) +{ + if (IsGroupingActive()) + { + TArray OutermostGroupActors; + + for (AActor* Actor : ActorsToUngroup) + { + // Get the outermost locked group + AGroupActor* OutermostGroup = AGroupActor::GetRootForActor(Actor, true); + if (OutermostGroup == NULL) + { + // Failed to find locked root group, try to find the immediate parent + OutermostGroup = AGroupActor::GetParentForActor(Actor); + } + + if (OutermostGroup) + { + OutermostGroupActors.AddUnique(OutermostGroup); + } + } + + if (OutermostGroupActors.Num()) + { + const FScopedTransaction Transaction(NSLOCTEXT("UnrealEd", "Group_Disband", "Disband Group")); + for (int32 GroupIndex = 0; GroupIndex < OutermostGroupActors.Num(); ++GroupIndex) + { + AGroupActor* GroupActor = OutermostGroupActors[GroupIndex]; + GroupActor->ClearAndRemove(); + } + } + } +} + +void UActorGroupingUtils::LockSelectedGroups() +{ + if (IsGroupingActive()) + { + AGroupActor::LockSelectedGroups(); + } +} + +void UActorGroupingUtils::UnlockSelectedGroups() +{ + if (IsGroupingActive()) + { + AGroupActor::UnlockSelectedGroups(); + } +} + +void UActorGroupingUtils::AddSelectedToGroup() +{ + if (IsGroupingActive()) + { + AGroupActor::AddSelectedActorsToSelectedGroup(); + } +} + + +void UActorGroupingUtils::RemoveSelectedFromGroup() +{ + if (IsGroupingActive()) + { + TArray ActorsToRemove; + for (FSelectionIterator It(GEditor->GetSelectedActorIterator()); It; ++It) + { + AActor* Actor = static_cast(*It); + checkSlow(Actor->IsA(AActor::StaticClass())); + + // See if an entire group is being removed + AGroupActor* GroupActor = Cast(Actor); + if (GroupActor == NULL) + { + // See if the actor selected belongs to a locked group, if so remove the group in lieu of the actor + GroupActor = AGroupActor::GetParentForActor(Actor); + if (GroupActor && !GroupActor->IsLocked()) + { + GroupActor = NULL; + } + } + + if (GroupActor) + { + // If the GroupActor has no parent, do nothing, otherwise just add the group for removal + if (AGroupActor::GetParentForActor(GroupActor)) + { + ActorsToRemove.AddUnique(GroupActor); + } + } + else + { + ActorsToRemove.AddUnique(Actor); + } + } + + const FScopedTransaction Transaction(NSLOCTEXT("UnrealEd", "Group_Remove", "Remove from Group")); + for (int32 ActorIndex = 0; ActorIndex < ActorsToRemove.Num(); ++ActorIndex) + { + AActor* Actor = ActorsToRemove[ActorIndex]; + AGroupActor* ActorGroup = AGroupActor::GetParentForActor(Actor); + + if (ActorGroup) + { + AGroupActor* ActorGroupParent = AGroupActor::GetParentForActor(ActorGroup); + if (ActorGroupParent) + { + ActorGroupParent->Add(*Actor); + ActorGroupParent->CenterGroupLocation(); + } + else + { + ActorGroup->Remove(*Actor); + ActorGroup->CenterGroupLocation(); + } + } + } + // Do a re-selection of each actor, to maintain group selection rules + GEditor->SelectNone(true, true); + for (int32 ActorIndex = 0; ActorIndex < ActorsToRemove.Num(); ++ActorIndex) + { + GEditor->SelectActor(ActorsToRemove[ActorIndex], true, false); + } + } + +} diff --git a/Engine/Source/Editor/UnrealEd/Private/Animation/DebugSkelMeshComponent.cpp b/Engine/Source/Editor/UnrealEd/Private/Animation/DebugSkelMeshComponent.cpp index 6788c473eaf4..f40a47cb6bfb 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Animation/DebugSkelMeshComponent.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Animation/DebugSkelMeshComponent.cpp @@ -158,11 +158,6 @@ void UDebugSkelMeshComponent::ConsumeRootMotion(const FVector& FloorMin, const F } } -void UDebugSkelMeshComponent::SetVisibleClothProperty(int32 ClothProperty) -{ - VisibleClothProperty = ClothProperty; -} - FPrimitiveSceneProxy* UDebugSkelMeshComponent::CreateSceneProxy() { FDebugSkelMeshSceneProxy* Result = NULL; @@ -204,7 +199,12 @@ FString UDebugSkelMeshComponent::GetPreviewText() const if (IsPreviewOn()) { UAnimationAsset* CurrentAsset = PreviewInstance->GetCurrentAsset(); - if (UBlendSpaceBase* BlendSpace = Cast(CurrentAsset)) + if (USkeletalMeshComponent* SkeletalMeshComponent = PreviewInstance->GetDebugSkeletalMeshComponent()) + { + FText Label = SkeletalMeshComponent->GetOwner() ? FText::FromString(SkeletalMeshComponent->GetOwner()->GetActorLabel()) : LOCTEXT("NoActor", "None"); + return FText::Format(LOCTEXT("ExternalComponent", "External Instance on {0}"), Label).ToString(); + } + else if (UBlendSpaceBase* BlendSpace = Cast(CurrentAsset)) { return FText::Format( LOCTEXT("BlendSpace", "Blend Space {0}"), FText::FromString(BlendSpace->GetName()) ).ToString(); } @@ -302,6 +302,8 @@ void UDebugSkelMeshComponent::EnablePreview(bool bEnable, UAnimationAsset* Previ PreviewInstance->SetAnimationAsset(nullptr); } } + + ClothTeleportMode = EClothingTeleportMode::TeleportAndReset; } } @@ -886,8 +888,7 @@ void UDebugSkelMeshComponent::RefreshSelectedClothingSkinnedPositions() { if(SkeletalMesh && SelectedClothingGuidForPainting.IsValid()) { - UClothingAssetBase** Asset = nullptr; - Asset = SkeletalMesh->MeshClothingAssets.FindByPredicate([&](UClothingAssetBase* Item) + UClothingAssetBase** Asset = SkeletalMesh->MeshClothingAssets.FindByPredicate([&](UClothingAssetBase* Item) { return SelectedClothingGuidForPainting == Item->GetAssetGuid(); }); @@ -907,8 +908,7 @@ void UDebugSkelMeshComponent::RefreshSelectedClothingSkinnedPositions() FClothLODData& LodData = ConcreteAsset->LodData[SelectedClothingLodForPainting]; - FTransform RootBoneTransform = GetBoneTransform(ConcreteAsset->ReferenceBoneIndex); - FClothingSimulationBase::SkinPhysicsMesh(ConcreteAsset, LodData.PhysicalMeshData, RootBoneTransform, RefToLocals.GetData(), RefToLocals.Num(), SkinnedSelectedClothingPositions, SkinnedSelectedClothingNormals); + FClothingSimulationBase::SkinPhysicsMesh(ConcreteAsset, LodData.PhysicalMeshData, FTransform::Identity, RefToLocals.GetData(), RefToLocals.Num(), SkinnedSelectedClothingPositions, SkinnedSelectedClothingNormals); } } } @@ -967,7 +967,7 @@ void FDebugSkelMeshSceneProxy::GetDynamicMeshElements(const TArrayClothingSimDataIndexWhenPainting != INDEX_NONE && DynamicData->bDrawClothPaintPreview) { - if(DynamicData->SkinnedPositions.Num() > 0) + if(DynamicData->SkinnedPositions.Num() > 0 && DynamicData->ClothingVisiblePropertyValues.Num() > 0) { FDynamicMeshBuilder MeshBuilder; @@ -975,29 +975,9 @@ void FDebugSkelMeshSceneProxy::GetDynamicMeshElements(const TArray& Vertices = DynamicData->SkinnedPositions; const TArray& Normals = DynamicData->SkinnedNormals; - float MaxValue = MIN_flt; - float MinValue = MAX_flt; float* ValueArray = DynamicData->ClothingVisiblePropertyValues.GetData(); + const int32 NumVerts = Vertices.Num(); - for(int32 VertIndex = 0; VertIndex < NumVerts; ++VertIndex) - { - const float& Value = ValueArray[VertIndex]; - MaxValue = FMath::Max(MaxValue, Value); - - if(Value > 0.0f) - { - MinValue = FMath::Min(MinValue, ValueArray[VertIndex]); - } - } - - float Range = MaxValue - MinValue; - - // If we've only got really close values. - if(Range < 0.1f) - { - Range = MaxValue; - MinValue = 0; - } const FLinearColor Magenta = FLinearColor(1.0f, 0.0f, 1.0f); for(int32 VertIndex = 0; VertIndex < NumVerts; ++VertIndex) @@ -1008,7 +988,10 @@ void FDebugSkelMeshSceneProxy::GetDynamicMeshElements(const TArrayPropertyViewMax - DynamicData->PropertyViewMin; + float ClampedViewValue = FMath::Clamp(CurrValue, DynamicData->PropertyViewMin, DynamicData->PropertyViewMax); + const FLinearColor Color = CurrValue == 0.0f ? Magenta : (FLinearColor::White * ((ClampedViewValue - DynamicData->PropertyViewMin) / Range)); Vert.Color = Color.ToFColor(true); MeshBuilder.AddVertex(Vert); @@ -1042,7 +1025,8 @@ FDebugSkelMeshDynamicData::FDebugSkelMeshDynamicData(UDebugSkelMeshComponent* In , bDrawBinormals(InComponent->bDrawBinormals) , bDrawClothPaintPreview(InComponent->bShowClothData) , ClothingSimDataIndexWhenPainting(INDEX_NONE) - , ClothingVisiblePropertyIndex(InComponent->VisibleClothProperty) + , PropertyViewMin(InComponent->MinClothPropertyView) + , PropertyViewMax(InComponent->MaxClothPropertyView) { if(InComponent->SelectedClothingGuidForPainting.IsValid()) { @@ -1067,19 +1051,11 @@ FDebugSkelMeshDynamicData::FDebugSkelMeshDynamicData(UDebugSkelMeshComponent* In ClothingSimIndices = LodData.PhysicalMeshData.Indices; - switch(ClothingVisiblePropertyIndex) + if(LodData.ParameterMasks.IsValidIndex(InComponent->SelectedClothingLodMaskForPainting)) { - case 0: - ClothingVisiblePropertyValues = LodData.PhysicalMeshData.MaxDistances; - break; - case 1: - ClothingVisiblePropertyValues = LodData.PhysicalMeshData.BackstopDistances; - break; - case 2: - ClothingVisiblePropertyValues = LodData.PhysicalMeshData.BackstopRadiuses; - break; - default: - break; + FClothParameterMask_PhysMesh& Mask = LodData.ParameterMasks[InComponent->SelectedClothingLodMaskForPainting]; + + ClothingVisiblePropertyValues = Mask.GetValueArray(); } } } diff --git a/Engine/Source/Editor/UnrealEd/Private/AssetDeleteModel.cpp b/Engine/Source/Editor/UnrealEd/Private/AssetDeleteModel.cpp index 2e397e9f0a76..2e1473bd0bb6 100644 --- a/Engine/Source/Editor/UnrealEd/Private/AssetDeleteModel.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/AssetDeleteModel.cpp @@ -552,7 +552,6 @@ void FAssetDeleteModel::PrepareToDelete(UObject* InObject) TArray AssetsInRedirectorPackage; GetObjectsWithOuter(RedirectorPackage, AssetsInRedirectorPackage, /*bIncludeNestedObjects=*/false); - UMetaData* PackageMetaData = NULL; bool bContainsAtLeastOneOtherAsset = false; for ( auto ObjIt = AssetsInRedirectorPackage.CreateConstIterator(); ObjIt; ++ObjIt ) @@ -560,30 +559,21 @@ void FAssetDeleteModel::PrepareToDelete(UObject* InObject) if ( UObjectRedirector* Redirector = Cast(*ObjIt) ) { Redirector->RemoveFromRoot(); + continue; } - else if ( UMetaData* MetaData = Cast(*ObjIt) ) + + if ( UMetaData* MetaData = Cast(*ObjIt) ) { - PackageMetaData = MetaData; - } - else - { - bContainsAtLeastOneOtherAsset = true; + // Nothing to do; ObjectTools::CleanUpAfterSuccessfulDelete will take care of this if needed + continue; } + + bContainsAtLeastOneOtherAsset = true; } if ( !bContainsAtLeastOneOtherAsset ) { RedirectorPackage->RemoveFromRoot(); - - // @todo we shouldnt be worrying about metadata objects here, ObjectTools::CleanUpAfterSuccessfulDelete should - if ( PackageMetaData ) - { - PackageMetaData->RemoveFromRoot(); - if (!PendingDeletes.ContainsByPredicate([=](const TSharedPtr& A) { return A->GetObject() == PackageMetaData; })) - { - PendingDeletes.Add(MakeShareable(new FPendingDelete(PackageMetaData))); - } - } } } } diff --git a/Engine/Source/Editor/UnrealEd/Private/AssetEditorModeManager.cpp b/Engine/Source/Editor/UnrealEd/Private/AssetEditorModeManager.cpp index e9067c8717e6..6b1a1e4fdcd0 100644 --- a/Engine/Source/Editor/UnrealEd/Private/AssetEditorModeManager.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/AssetEditorModeManager.cpp @@ -13,14 +13,17 @@ FAssetEditorModeManager::FAssetEditorModeManager() ActorSet = NewObject(); ActorSet->SetFlags(RF_Transactional); ActorSet->AddToRoot(); + ActorSet->Initialize(nullptr); ObjectSet = NewObject(); ObjectSet->SetFlags(RF_Transactional); ObjectSet->AddToRoot(); + ObjectSet->Initialize(nullptr); ComponentSet = NewObject(); ComponentSet->SetFlags(RF_Transactional); ComponentSet->AddToRoot(); + ComponentSet->Initialize(nullptr); } FAssetEditorModeManager::~FAssetEditorModeManager() diff --git a/Engine/Source/Editor/UnrealEd/Private/AssetSelection.cpp b/Engine/Source/Editor/UnrealEd/Private/AssetSelection.cpp index 9e95d4bd1ac4..ec388f9dd5f7 100644 --- a/Engine/Source/Editor/UnrealEd/Private/AssetSelection.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/AssetSelection.cpp @@ -552,7 +552,7 @@ namespace AssetUtil else if (Operation->IsOfType()) { TSharedPtr DragDropOp = StaticCastSharedPtr( Operation ); - DroppedAssetData.Append( DragDropOp->AssetData ); + DroppedAssetData.Append( DragDropOp->GetAssets() ); } return DroppedAssetData; diff --git a/Engine/Source/Editor/UnrealEd/Private/AssetThumbnail.cpp b/Engine/Source/Editor/UnrealEd/Private/AssetThumbnail.cpp index 93bb77dcb90f..fd80f513c5d3 100644 --- a/Engine/Source/Editor/UnrealEd/Private/AssetThumbnail.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/AssetThumbnail.cpp @@ -987,14 +987,17 @@ void FAssetThumbnailPool::Tick( float DeltaTime ) } }); - //@todo: this should be done on the GPU only but it is not supported by thumbnail tools yet - ThumbnailTools::RenderThumbnail( - Asset, - InfoRef->Width, - InfoRef->Height, - ThumbnailTools::EThumbnailTextureFlushMode::NeverFlush, - InfoRef->ThumbnailRenderTarget - ); + if (InfoRef->LastUpdateTime <= 0.0f || RenderInfo->Renderer->AllowsRealtimeThumbnails(Asset)) + { + //@todo: this should be done on the GPU only but it is not supported by thumbnail tools yet + ThumbnailTools::RenderThumbnail( + Asset, + InfoRef->Width, + InfoRef->Height, + ThumbnailTools::EThumbnailTextureFlushMode::NeverFlush, + InfoRef->ThumbnailRenderTarget + ); + } bLoadedThumbnail = true; diff --git a/Engine/Source/Editor/UnrealEd/Private/AutoReimport/AssetSourceFilenameCache.cpp b/Engine/Source/Editor/UnrealEd/Private/AutoReimport/AssetSourceFilenameCache.cpp index 56661928021d..bd49f0c25df4 100644 --- a/Engine/Source/Editor/UnrealEd/Private/AutoReimport/AssetSourceFilenameCache.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/AutoReimport/AssetSourceFilenameCache.cpp @@ -7,6 +7,12 @@ FAssetSourceFilenameCache::FAssetSourceFilenameCache() { + if (GIsRequestingExit) + { + // This can get created for the first timeon shutdown, if so don't do anything + return; + } + IAssetRegistry& AssetRegistry = FModuleManager::LoadModuleChecked("AssetRegistry").Get(); AssetRegistry.OnAssetAdded().AddRaw(this, &FAssetSourceFilenameCache::HandleOnAssetAdded); @@ -46,41 +52,15 @@ void FAssetSourceFilenameCache::Shutdown() UAssetImportData::OnImportDataChanged.RemoveAll(this); } -TOptional FAssetSourceFilenameCache::ExtractAssetImportInfo(const TArray& InTags) +TOptional FAssetSourceFilenameCache::ExtractAssetImportInfo(const FAssetData& AssetData) { static const FName LegacySourceFilePathName("SourceFile"); - TOptional Info; - - for (const auto& Tag : InTags) - { - if (Tag.Name == UObject::SourceFileTagName()) - { - Info = FAssetImportInfo::FromJson(*Tag.Value); - // We're done - break; - } - else if (Tag.Name == LegacySourceFilePathName) - { - FAssetImportInfo Legacy; - Legacy.Insert(Tag.Value); - Info = Legacy; - // Keep looking for a newer json version - } - } - - return Info; -} - -TOptional FAssetSourceFilenameCache::ExtractAssetImportInfo(const TSharedMapView& InTags) -{ - static const FName LegacySourceFilePathName("SourceFile"); - - if (const FString* ImportDataString = InTags.Find(UObject::SourceFileTagName())) + if (const FString* ImportDataString = AssetData.TagsAndValues.Find(UObject::SourceFileTagName())) { return FAssetImportInfo::FromJson(*ImportDataString); } - else if (const FString* LegacyFilename = InTags.Find(LegacySourceFilePathName)) + else if (const FString* LegacyFilename = AssetData.TagsAndValues.Find(LegacySourceFilePathName)) { FAssetImportInfo Legacy; Legacy.Insert(*LegacyFilename); @@ -94,7 +74,7 @@ TOptional FAssetSourceFilenameCache::ExtractAssetImportInfo(co void FAssetSourceFilenameCache::HandleOnAssetAdded(const FAssetData& AssetData) { - TOptional ImportData = ExtractAssetImportInfo(AssetData.TagsAndValues); + TOptional ImportData = ExtractAssetImportInfo(AssetData); if (ImportData.IsSet()) { for (const auto& SourceFile : ImportData->SourceFiles) @@ -106,7 +86,7 @@ void FAssetSourceFilenameCache::HandleOnAssetAdded(const FAssetData& AssetData) void FAssetSourceFilenameCache::HandleOnAssetRemoved(const FAssetData& AssetData) { - TOptional ImportData = ExtractAssetImportInfo(AssetData.TagsAndValues); + TOptional ImportData = ExtractAssetImportInfo(AssetData); if (ImportData.IsSet()) { for (auto& SourceFile : ImportData->SourceFiles) @@ -126,7 +106,7 @@ void FAssetSourceFilenameCache::HandleOnAssetRemoved(const FAssetData& AssetData void FAssetSourceFilenameCache::HandleOnAssetRenamed(const FAssetData& AssetData, const FString& OldPath) { - TOptional ImportData = ExtractAssetImportInfo(AssetData.TagsAndValues); + TOptional ImportData = ExtractAssetImportInfo(AssetData); if (ImportData.IsSet()) { FName OldPathName = *OldPath; @@ -183,7 +163,7 @@ TArray FAssetSourceFilenameCache::GetAssetsPertainingToFile(const IA for (const FName& Path : *ObjectPaths) { FAssetData Asset = Registry.GetAssetByObjectPath(Path); - TOptional ImportInfo = ExtractAssetImportInfo(Asset.TagsAndValues); + TOptional ImportInfo = ExtractAssetImportInfo(Asset); if (ImportInfo.IsSet()) { auto AssetPackagePath = FPackageName::LongPackageNameToFilename(Asset.PackagePath.ToString() / TEXT("")); diff --git a/Engine/Source/Editor/UnrealEd/Private/AutoReimport/AutoReimportManager.cpp b/Engine/Source/Editor/UnrealEd/Private/AutoReimport/AutoReimportManager.cpp index 75b566c11033..270f097ca79e 100644 --- a/Engine/Source/Editor/UnrealEd/Private/AutoReimport/AutoReimportManager.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/AutoReimport/AutoReimportManager.cpp @@ -398,7 +398,7 @@ void FAutoReimportManager::OnAssetRenamed(const FAssetData& AssetData, const FSt // Additionally, we rename the source file if it matched the name of the asset before the rename/move. // - If we rename the source file, then we also update the reimport paths for the asset - TOptional ImportInfo = FAssetSourceFilenameCache::ExtractAssetImportInfo(AssetData.TagsAndValues); + TOptional ImportInfo = FAssetSourceFilenameCache::ExtractAssetImportInfo(AssetData); if (!ImportInfo.IsSet() || ImportInfo->SourceFiles.Num() != 1) { return; diff --git a/Engine/Source/Editor/UnrealEd/Private/AutoReimport/AutoReimportUtilities.cpp b/Engine/Source/Editor/UnrealEd/Private/AutoReimport/AutoReimportUtilities.cpp index c75bb0c0d65f..f418b704263e 100644 --- a/Engine/Source/Editor/UnrealEd/Private/AutoReimport/AutoReimportUtilities.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/AutoReimport/AutoReimportUtilities.cpp @@ -4,6 +4,8 @@ #include "EditorFramework/AssetImportData.h" #include "AutoReimport/AssetSourceFilenameCache.h" +DEFINE_LOG_CATEGORY(LogAutoReimportManager); + namespace Utils { TArray FindAssetsPertainingToFile(const IAssetRegistry& Registry, const FString& AbsoluteFilename) diff --git a/Engine/Source/Editor/UnrealEd/Private/AutoReimport/AutoReimportUtilities.h b/Engine/Source/Editor/UnrealEd/Private/AutoReimport/AutoReimportUtilities.h index 0eb29a9a4a1e..37934d2d953d 100644 --- a/Engine/Source/Editor/UnrealEd/Private/AutoReimport/AutoReimportUtilities.h +++ b/Engine/Source/Editor/UnrealEd/Private/AutoReimport/AutoReimportUtilities.h @@ -7,7 +7,7 @@ class IAssetRegistry; -DEFINE_LOG_CATEGORY_STATIC(LogAutoReimportManager, Log, All); +DECLARE_LOG_CATEGORY_EXTERN(LogAutoReimportManager, Log, All); namespace Utils { diff --git a/Engine/Source/Editor/UnrealEd/Private/AutoReimport/ContentDirectoryMonitor.cpp b/Engine/Source/Editor/UnrealEd/Private/AutoReimport/ContentDirectoryMonitor.cpp index 905f7e292c28..90ea6a560bee 100644 --- a/Engine/Source/Editor/UnrealEd/Private/AutoReimport/ContentDirectoryMonitor.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/AutoReimport/ContentDirectoryMonitor.cpp @@ -59,7 +59,7 @@ DirectoryWatcher::FFileCacheConfig GenerateFileCacheConfig(const FString& InPath // We need to consider this as a changed file if the hash doesn't match any asset imported from that file for (FAssetData& Asset : Assets) { - TOptional Info = FAssetSourceFilenameCache::ExtractAssetImportInfo(Asset.TagsAndValues); + TOptional Info = FAssetSourceFilenameCache::ExtractAssetImportInfo(Asset); // Check if the source file that this asset last imported was the same as the one we're going to reimport. // If it is, there's no reason to auto-reimport it diff --git a/Engine/Source/Editor/UnrealEd/Private/Commandlets/AssetRegistryGenerator.cpp b/Engine/Source/Editor/UnrealEd/Private/Commandlets/AssetRegistryGenerator.cpp index 3293a13c1e54..cb7f68656241 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Commandlets/AssetRegistryGenerator.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Commandlets/AssetRegistryGenerator.cpp @@ -1,6 +1,6 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "Commandlets/AssetRegistryGenerator.h" +#include "AssetRegistryGenerator.h" #include "HAL/FileManager.h" #include "Misc/FileHelper.h" #include "Serialization/ArrayReader.h" @@ -237,6 +237,7 @@ bool FAssetRegistryGenerator::GenerateStreamingInstallManifest() { FString Filename = ChunkFilenames[FilenameIndex]; FString PakListLine = FPaths::ConvertRelativePathToFull(Filename.Replace(TEXT("[Platform]"), *Platform)); + if (MaxChunkSize > 0) { TArray FoundFiles; FString FileSearchString = FString::Printf(TEXT("%s.*"), *PakListLine); @@ -247,14 +248,14 @@ bool FAssetRegistryGenerator::GenerateStreamingInstallManifest() int64 FileSize = IFileManager::Get().FileSize(*(FPaths::Combine(Path,FoundFile))); CurrentPakSize += FileSize > 0 ? FileSize : 0; } + if (MaxChunkSize < CurrentPakSize) + { + // early out if we are over memory limit + bFinishedAllFiles = false; + break; + } } - if ((MaxChunkSize > 0) && (MaxChunkSize < CurrentPakSize)) - { - // early out if we are over memory limit - bFinishedAllFiles = false; - break; - } - + PakListLine.ReplaceInline(TEXT("/"), TEXT("\\")); PakListLine += TEXT("\r\n"); PakListFile->Serialize(TCHAR_TO_ANSI(*PakListLine), PakListLine.Len()); @@ -353,17 +354,8 @@ void FAssetRegistryGenerator::CleanManifestDirectories() bool FAssetRegistryGenerator::LoadPreviousAssetRegistry(const FString& Filename) { // First try development asset registry - FString DevelopmentFilename = Filename.Replace(TEXT("AssetRegistry.bin"), TEXT("DevelopmentAssetRegistry.bin")); FArrayReader SerializedAssetData; - - if (IFileManager::Get().FileExists(*DevelopmentFilename) && FFileHelper::LoadFileToArray(SerializedAssetData, *DevelopmentFilename)) - { - FAssetRegistrySerializationOptions Options; - Options.ModifyForDevelopment(); - - return PreviousState.Serialize(SerializedAssetData, Options); - } - + if (IFileManager::Get().FileExists(*Filename) && FFileHelper::LoadFileToArray(SerializedAssetData, *Filename)) { FAssetRegistrySerializationOptions Options; @@ -427,17 +419,7 @@ bool FAssetRegistryGenerator::SaveManifests(FSandboxPlatformFile* InSandboxFile) bool FAssetRegistryGenerator::ContainsMap(const FName& PackageName) const { - const TArray& PackageAssets = State.GetAssetsByPackageName(PackageName); - - for (const FAssetData* AssetData : PackageAssets) - { - UClass* AssetClass = AssetData->GetClass(); - if (AssetClass->IsChildOf(UWorld::StaticClass()) || AssetClass->IsChildOf(ULevel::StaticClass())) - { - return true; - } - } - return false; + return PackagesContainingMaps.Contains(PackageName); } FAssetPackageData* FAssetRegistryGenerator::GetAssetPackageData(const FName& PackageName) @@ -482,6 +464,8 @@ void FAssetRegistryGenerator::UpdatePackageSourceHashes() State.GetDependencies(PackageName, Dependencies, EAssetRegistryDependencyType::Hard); + Dependencies.Sort([&](const FAssetIdentifier& A, const FAssetIdentifier& B) { return A.PackageName > B.PackageName; } ); + for (FAssetIdentifier& Dependency : Dependencies) { const FAssetPackageData* DependencyData = State.GetAssetPackageData(Dependency.PackageName); @@ -519,7 +503,7 @@ void FAssetRegistryGenerator::UpdatePackageSourceHashes() } } -void FAssetRegistryGenerator::ComputePackageDifferences(TSet& ModifiedPackages, TSet& NewPackages, TSet& RemovedPackages, TSet& IdenticalCookedPackages, TSet& IdenticalUncookedPackages) +void FAssetRegistryGenerator::ComputePackageDifferences(TSet& ModifiedPackages, TSet& NewPackages, TSet& RemovedPackages, TSet& IdenticalCookedPackages, TSet& IdenticalUncookedPackages, bool bRecurseModifications) { for (const TPair& PackagePair : State.GetAssetPackageDataMap()) { @@ -562,27 +546,29 @@ void FAssetRegistryGenerator::ComputePackageDifferences(TSet& ModifiedPac } } - // Recurse modified packages to their dependencies. In theory a small number of packages are modified at once so this is faster than computing the hashes recursively - TArray ModifiedPackagesToRecurse = ModifiedPackages.Array(); - - for (int32 RecurseIndex = 0; RecurseIndex < ModifiedPackagesToRecurse.Num(); RecurseIndex++) + if (bRecurseModifications) { - FName ModifiedPackage = ModifiedPackagesToRecurse[RecurseIndex]; - TArray Referencers; - State.GetReferencers(ModifiedPackage, Referencers, EAssetRegistryDependencyType::Hard); + // Recurse modified packages to their dependencies. In theory a small number of packages are modified at once so this is faster than computing the hashes recursively + TArray ModifiedPackagesToRecurse = ModifiedPackages.Array(); - for (const FAssetIdentifier& Referencer : Referencers) + for (int32 RecurseIndex = 0; RecurseIndex < ModifiedPackagesToRecurse.Num(); RecurseIndex++) { - FName ReferencerPackage = Referencer.PackageName; - if (!ModifiedPackages.Contains(ReferencerPackage)) - { - // Remove from identical/new list - IdenticalCookedPackages.Remove(ReferencerPackage); - IdenticalUncookedPackages.Remove(ReferencerPackage); - NewPackages.Remove(ReferencerPackage); + FName ModifiedPackage = ModifiedPackagesToRecurse[RecurseIndex]; + TArray Referencers; + State.GetReferencers(ModifiedPackage, Referencers, EAssetRegistryDependencyType::Hard); - ModifiedPackages.Add(ReferencerPackage); - ModifiedPackagesToRecurse.Add(ReferencerPackage); + for (const FAssetIdentifier& Referencer : Referencers) + { + FName ReferencerPackage = Referencer.PackageName; + if (!ModifiedPackages.Contains(ReferencerPackage) && (IdenticalCookedPackages.Contains(ReferencerPackage) || IdenticalUncookedPackages.Contains(ReferencerPackage))) + { + // Remove from identical list + IdenticalCookedPackages.Remove(ReferencerPackage); + IdenticalUncookedPackages.Remove(ReferencerPackage); + + ModifiedPackages.Add(ReferencerPackage); + ModifiedPackagesToRecurse.Add(ReferencerPackage); + } } } } @@ -759,7 +745,7 @@ void FAssetRegistryGenerator::AddAssetToFileOrderRecursive(FAssetData* InAsset, } } -bool FAssetRegistryGenerator::SaveAssetRegistry(const FString& SandboxPath) +bool FAssetRegistryGenerator::SaveAssetRegistry(const FString& SandboxPath, bool bSerializeDevelopmentAssetRegistry ) { UE_LOG(LogAssetRegistryGenerator, Display, TEXT("Saving asset registry.")); const TMap& ObjectToDataMap = State.GetObjectPathToAssetDataMap(); @@ -769,7 +755,16 @@ bool FAssetRegistryGenerator::SaveAssetRegistry(const FString& SandboxPath) AssetRegistry.InitializeSerializationOptions(DevelopmentSaveOptions, TargetPlatform->IniPlatformName()); DevelopmentSaveOptions.ModifyForDevelopment(); - if (DevelopmentSaveOptions.bSerializeAssetRegistry) + // Write runtime registry, this can be excluded per game/platform + FAssetRegistrySerializationOptions SaveOptions; + AssetRegistry.InitializeSerializationOptions(SaveOptions, TargetPlatform->IniPlatformName()); + + // Flush the asset registry and make sure the asset data is in sync, as it may have been updated during cook + AssetRegistry.Tick(-1.0f); + + AssetRegistry.InitializeTemporaryAssetRegistryState(State, SaveOptions, true); + + if (DevelopmentSaveOptions.bSerializeAssetRegistry && bSerializeDevelopmentAssetRegistry) { // Create development registry data, used for incremental cook and editor viewing FArrayWriter SerializedAssetRegistry; @@ -782,14 +777,10 @@ bool FAssetRegistryGenerator::SaveAssetRegistry(const FString& SandboxPath) FFileHelper::SaveArrayToFile(SerializedAssetRegistry, *PlatformSandboxPath); } - // Write runtime registry, this can be excluded per game/platform - FAssetRegistrySerializationOptions SaveOptions; - AssetRegistry.InitializeSerializationOptions(SaveOptions, TargetPlatform->IniPlatformName()); - if (SaveOptions.bSerializeAssetRegistry) { // Prune out the development only packages - State.PruneAssetData(CookedPackages, TSet()); + State.PruneAssetData(CookedPackages, TSet(), SaveOptions.bFilterAssetDataWithNoTags); // Create runtime registry data FArrayWriter SerializedAssetRegistry; @@ -1297,10 +1288,10 @@ void FAssetRegistryGenerator::FixupPackageDependenciesForChunks(FSandboxPlatform } } - if (!CheckChunkAssetsAreNotInChild(*ChunkDepGraph)) +/* if (!CheckChunkAssetsAreNotInChild(*ChunkDepGraph)) { - UE_LOG(LogAssetRegistryGenerator, Error, TEXT("Second Scan of chunks found duplicate asset entries in children.")); - } + UE_LOG(LogAssetRegistryGenerator, Log, TEXT("Second Scan of chunks found duplicate asset entries in children.")); + }*/ for (int32 ChunkID = 0, MaxChunk = ChunkManifests.Num(); ChunkID < MaxChunk; ++ChunkID) { diff --git a/Engine/Source/Editor/UnrealEd/Private/Commandlets/AudioMixerCommandlet.cpp b/Engine/Source/Editor/UnrealEd/Private/Commandlets/AudioMixerCommandlet.cpp index 0dd0ed65adf7..b375471f5d29 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Commandlets/AudioMixerCommandlet.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Commandlets/AudioMixerCommandlet.cpp @@ -215,6 +215,10 @@ public: Commands.Add(this); } + virtual ~FAudioMixerCommand() + { + } + // Return the name of the test const FString& GetName() const { return Name; } @@ -247,7 +251,7 @@ TArray FAudioMixerCommand::Commands; * FRunAudioDevice ************************************************************************/ -class FRunAudioDevice : public FAudioMixerCommand +class FRunAudioDevice final : public FAudioMixerCommand { public: FRunAudioDevice() @@ -314,7 +318,7 @@ FRunAudioDevice RunAudioDevice; * FPlaySoundWave2D ************************************************************************/ -class FPlaySoundWave2D : public FAudioMixerCommand +class FPlaySoundWave2D final : public FAudioMixerCommand { public: FPlaySoundWave2D() @@ -395,7 +399,7 @@ FPlaySoundWave2D PlaySoundWave2D; * FPlaySoundWaveLooping2D ************************************************************************/ -class FPlaySoundWaveLooping2D : public FAudioMixerCommand +class FPlaySoundWaveLooping2D final : public FAudioMixerCommand { public: FPlaySoundWaveLooping2D() @@ -470,7 +474,7 @@ FPlaySoundWaveLooping2D PlaySoundWaveLooping2D; * FPlayRealTimeSoundWaveLooping2D ************************************************************************/ -class FPlayRealTimeSoundWaveLooping2D : public FAudioMixerCommand +class FPlayRealTimeSoundWaveLooping2D final : public FAudioMixerCommand { public: FPlayRealTimeSoundWaveLooping2D() @@ -552,7 +556,7 @@ FPlayRealTimeSoundWaveLooping2D PlayRealTimeSoundWaveLooping2D; * FPlaySoundWaveLooping2DPitched ************************************************************************/ -class FPlaySoundWaveLooping2DPitched : public FAudioMixerCommand +class FPlaySoundWaveLooping2DPitched final : public FAudioMixerCommand { public: FPlaySoundWaveLooping2DPitched() @@ -668,7 +672,7 @@ FPlaySoundWaveLooping2DPitched PlaySoundWaveLooping2DPitched; * FPlaySoundWaveLooping2DPitched ************************************************************************/ -class FPlaySoundWaveLooping3DPitched : public FAudioMixerCommand +class FPlaySoundWaveLooping3DPitched final : public FAudioMixerCommand { public: diff --git a/Engine/Source/Editor/UnrealEd/Private/Commandlets/AudioTestCommandlet.cpp b/Engine/Source/Editor/UnrealEd/Private/Commandlets/AudioTestCommandlet.cpp index 5166eeee08a4..bc6ffd4cb7b1 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Commandlets/AudioTestCommandlet.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Commandlets/AudioTestCommandlet.cpp @@ -16,15 +16,20 @@ static UAudio::IUnrealAudioModule* UnrealAudioModule = nullptr; static bool UnrealAudioLoad(const FString* DeviceApi = nullptr) { UnrealAudioModule = FModuleManager::LoadModulePtr(FName("UnrealAudio")); - if (DeviceApi) + if (UnrealAudioModule != nullptr) { - UnrealAudioModule->Initialize(*DeviceApi); + if (DeviceApi) + { + UnrealAudioModule->Initialize(*DeviceApi); + return true; + } + else + { + UnrealAudioModule->Initialize(); + return true; + } } - else - { - UnrealAudioModule->Initialize(); - } - return UnrealAudioModule != nullptr; + return false; } static bool UnrealAudioUnload() diff --git a/Engine/Source/Editor/UnrealEd/Private/Commandlets/ContentCommandlets.cpp b/Engine/Source/Editor/UnrealEd/Private/Commandlets/ContentCommandlets.cpp index 4999d7ffc187..0a75bb411159 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Commandlets/ContentCommandlets.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Commandlets/ContentCommandlets.cpp @@ -48,8 +48,8 @@ DEFINE_LOG_CATEGORY(LogContentCommandlet); #include "AssetRegistryModule.h" - - +#include "IDirectoryWatcher.h" +#include "DirectoryWatcherModule.h" #include "Particles/Material/ParticleModuleMeshMaterial.h" #include "Particles/ParticleLODLevel.h" #include "Particles/ParticleModuleRequired.h" @@ -237,18 +237,32 @@ int32 UResavePackagesCommandlet::InitializeResaveParameters( const TArray(TEXT("AssetRegistry")); + IAssetRegistry& AssetRegistry = AssetRegistryModule.Get(); + + // This option works if a single package is specified, it will resave all packages that reference it, and all packages that it references + const bool bResaveDirectRefsAndDeps = Switches.Contains(TEXT("ResaveDirectRefsAndDeps")); + + // This option will filter the package list and only save packages that are redirectors, or that reference redirectors + const bool bFixupRedirects = (Switches.Contains(TEXT("FixupRedirects")) || Switches.Contains(TEXT("FixupRedirectors"))); + + if (bResaveDirectRefsAndDeps || bFixupRedirects) + { + AssetRegistry.SearchAllAssets(true); + + // Force directory watcher tick to register paths + FDirectoryWatcherModule& DirectoryWatcherModule = FModuleManager::Get().LoadModuleChecked(TEXT("DirectoryWatcher")); + DirectoryWatcherModule.Get()->Tick(-1.0f); + } + if (bExplicitPackages && PackageNames.Num() == 1 && bResaveDirectRefsAndDeps) { - FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked("AssetRegistry"); - AssetRegistryModule.Get().SearchAllAssets(true); - FName PackageName = FName(*FPackageName::FilenameToLongPackageName(PackageNames[0])); TArray Referencers; - AssetRegistryModule.Get().GetReferencers(PackageName, Referencers); + AssetRegistry.GetReferencers(PackageName, Referencers); TArray Dependencies; - AssetRegistryModule.Get().GetDependencies(PackageName, Dependencies); + AssetRegistry.GetDependencies(PackageName, Dependencies); for (FName Ref : Referencers) { @@ -263,6 +277,54 @@ int32 UResavePackagesCommandlet::InitializeResaveParameters( const TArray RedirectAssets; + TSet RedirectPackages; + TSet ReferencerPackages; + + AssetRegistry.GetAssetsByClass(UObjectRedirector::StaticClass()->GetFName(), RedirectAssets); + + for (const FAssetData& AssetData : RedirectAssets) + { + bool bIsAlreadyInSet = false; + FString RedirectFile; + FPackageName::SearchForPackageOnDisk(*AssetData.PackageName.ToString(), nullptr, &RedirectFile); + + RedirectPackages.Add(RedirectFile, &bIsAlreadyInSet); + + if (!bIsAlreadyInSet) + { + TArray Referencers; + AssetRegistry.GetReferencers(AssetData.PackageName, Referencers); + + for (FName Referencer : Referencers) + { + FString ReferencerFile; + FPackageName::SearchForPackageOnDisk(*Referencer.ToString(), nullptr, &ReferencerFile); + + ReferencerPackages.Add(ReferencerFile); + } + } + } + + // Filter packagenames list to packages that are pointing to redirectors, it will probably be much smaller + TArray OldArray = PackageNames; + PackageNames.Reset(); + for (FString& PackageName : OldArray) + { + if (RedirectPackages.Contains(PackageName)) + { + RedirectorsToFixup.Add(PackageName); + } + + if (ReferencerPackages.Contains(PackageName)) + { + PackageNames.Add(PackageName); + } + } + } // Check for the min and max versions MinResaveUE4Version = IGNORE_PACKAGE_VERSION; @@ -518,61 +580,11 @@ void UResavePackagesCommandlet::LoadAndSaveOnePackage(const FString& Filename) if (bIsEmpty) { bSavePackage = false; + Package = nullptr; - // get file SCC status UE_LOG(LogContentCommandlet, Display, TEXT("Package %s is empty and will be deleted"), *Filename); - FString PackageFilename = SourceControlHelpers::PackageFilename(Package); - ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider(); - FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState(PackageFilename, EStateCacheUsage::ForceUpdate); - - // Unload package so we can delete it - TArray PackagesToDelete; - PackagesToDelete.Add(Package); - PackageTools::UnloadPackages(PackagesToDelete); - PackagesToDelete.Empty(); - Package = NULL; - - if (bAutoCheckOut) - { - if (SourceControlState.IsValid() && (SourceControlState->IsCheckedOut() || SourceControlState->IsAdded())) - { - UE_LOG(LogContentCommandlet, Display, TEXT("Revert '%s' from source control..."), *Filename); - SourceControlProvider.Execute(ISourceControlOperation::Create(), PackageFilename); - - UE_LOG(LogContentCommandlet, Display, TEXT("Deleting '%s' from source control..."), *Filename); - SourceControlProvider.Execute(ISourceControlOperation::Create(), PackageFilename); - - FilesToSubmit.Add(Filename); - } - else if (SourceControlState.IsValid() && SourceControlState->CanCheckout()) - { - UE_LOG(LogContentCommandlet, Display, TEXT("Deleting '%s' from source control..."), *Filename); - SourceControlProvider.Execute(ISourceControlOperation::Create(), PackageFilename); - - FilesToSubmit.Add(Filename); - } - else if (SourceControlState.IsValid() && SourceControlState->IsCheckedOutOther()) - { - UE_LOG(LogContentCommandlet, Warning, TEXT("Couldn't delete '%s' from source control, someone has it checked out, skipping..."), *Filename); - } - else if (SourceControlState.IsValid() && !SourceControlState->IsSourceControlled()) - { - UE_LOG(LogContentCommandlet, Warning, TEXT("'%s' is not in source control, attempting to delete from disk..."), *Filename); - if (!IFileManager::Get().Delete(*Filename, false, true)) - { - UE_LOG(LogContentCommandlet, Warning, TEXT(" ... failed to delete from disk."), *Filename); - } - } - else - { - UE_LOG(LogContentCommandlet, Warning, TEXT("'%s' is in an unknown source control state, attempting to delete from disk..."), *Filename); - if (!IFileManager::Get().Delete(*Filename, false, true)) - { - UE_LOG(LogContentCommandlet, Warning, TEXT(" ... failed to delete from disk."), *Filename); - } - } - } + DeleteOnePackage(Filename); } } @@ -617,8 +629,7 @@ void UResavePackagesCommandlet::LoadAndSaveOnePackage(const FString& Filename) VerboseMessage(TEXT("Post CheckOut")); - FString PackageName(FPackageName::FilenameToLongPackageName(Filename)); - FilesToSubmit.Add(*PackageName); + FilesToSubmit.AddUnique(*Filename); } } VerboseMessage(TEXT("Post ForceGetStatus2")); @@ -667,6 +678,82 @@ void UResavePackagesCommandlet::LoadAndSaveOnePackage(const FString& Filename) } } +void UResavePackagesCommandlet::DeleteOnePackage(const FString& Filename) +{ + bool bIsReadOnly = IFileManager::Get().IsReadOnly(*Filename); + + if (bVerifyContent) + { + return; + } + + if (bIsReadOnly && !bAutoCheckOut) + { + if (Verbosity != ONLY_ERRORS) + { + UE_LOG(LogContentCommandlet, Warning, TEXT("Skipping read-only file %s"), *Filename); + } + return; + } + + FString PackageName; + FPackageName::TryConvertFilenameToLongPackageName(Filename, PackageName); + + UPackage* Package = FindPackage(nullptr, *PackageName); + + if (Package) + { + // Unload package so we can delete it + TArray PackagesToDelete; + PackagesToDelete.Add(Package); + PackageTools::UnloadPackages(PackagesToDelete); + PackagesToDelete.Empty(); + Package = nullptr; + } + + FString PackageFilename = SourceControlHelpers::PackageFilename(Filename); + ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider(); + FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState(PackageFilename, EStateCacheUsage::ForceUpdate); + + if (SourceControlState.IsValid() && (SourceControlState->IsCheckedOut() || SourceControlState->IsAdded())) + { + UE_LOG(LogContentCommandlet, Display, TEXT("Revert '%s' from source control..."), *Filename); + SourceControlProvider.Execute(ISourceControlOperation::Create(), PackageFilename); + + UE_LOG(LogContentCommandlet, Display, TEXT("Deleting '%s' from source control..."), *Filename); + SourceControlProvider.Execute(ISourceControlOperation::Create(), PackageFilename); + + FilesToSubmit.AddUnique(Filename); + } + else if (SourceControlState.IsValid() && SourceControlState->CanCheckout()) + { + UE_LOG(LogContentCommandlet, Display, TEXT("Deleting '%s' from source control..."), *Filename); + SourceControlProvider.Execute(ISourceControlOperation::Create(), PackageFilename); + + FilesToSubmit.AddUnique(Filename); + } + else if (SourceControlState.IsValid() && SourceControlState->IsCheckedOutOther()) + { + UE_LOG(LogContentCommandlet, Warning, TEXT("Couldn't delete '%s' from source control, someone has it checked out, skipping..."), *Filename); + } + else if (SourceControlState.IsValid() && !SourceControlState->IsSourceControlled()) + { + UE_LOG(LogContentCommandlet, Warning, TEXT("'%s' is not in source control, attempting to delete from disk..."), *Filename); + if (!IFileManager::Get().Delete(*Filename, false, true)) + { + UE_LOG(LogContentCommandlet, Warning, TEXT(" ... failed to delete from disk."), *Filename); + } + } + else + { + UE_LOG(LogContentCommandlet, Warning, TEXT("'%s' is in an unknown source control state, attempting to delete from disk..."), *Filename); + if (!IFileManager::Get().Delete(*Filename, false, true)) + { + UE_LOG(LogContentCommandlet, Warning, TEXT(" ... failed to delete from disk."), *Filename); + } + } +} + int32 UResavePackagesCommandlet::Main( const FString& Params ) { const TCHAR* Parms = *Params; @@ -685,9 +772,9 @@ int32 UResavePackagesCommandlet::Main( const FString& Params ) /** if we should only save dirty packages **/ bOnlySaveDirtyPackages = Switches.Contains(TEXT("OnlySaveDirtyPackages")); /** if we should auto checkout packages that need to be saved**/ - bAutoCheckOut = Switches.Contains(TEXT("AutoCheckOutPackages")); + bAutoCheckOut = Switches.Contains(TEXT("AutoCheckOutPackages")) || Switches.Contains(TEXT("AutoCheckOut")); /** if we should auto checkin packages that were checked out**/ - bAutoCheckIn = bAutoCheckOut && Switches.Contains(TEXT("AutoCheckIn")); + bAutoCheckIn = bAutoCheckOut && (Switches.Contains(TEXT("AutoCheckIn")) || Switches.Contains(TEXT("AutoSubmit"))); /** determine if we are building lighting for the map packages on the pass. **/ bShouldBuildLighting = Switches.Contains(TEXT("buildlighting")); /** determine if we are building lighting for the map packages on the pass. **/ @@ -708,7 +795,7 @@ int32 UResavePackagesCommandlet::Main( const FString& Params ) } // Retrieve list of all packages in .ini paths. - if( !PackageNames.Num() ) + if(!PackageNames.Num() && !RedirectorsToFixup.Num()) { return 0; } @@ -766,6 +853,41 @@ int32 UResavePackagesCommandlet::Main( const FString& Params ) } } + // Force a directory watcher and asset registry tick + FDirectoryWatcherModule& DirectoryWatcherModule = FModuleManager::Get().LoadModuleChecked(TEXT("DirectoryWatcher")); + DirectoryWatcherModule.Get()->Tick(-1.0f); + + FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(TEXT("AssetRegistry")); + IAssetRegistry& AssetRegistry = AssetRegistryModule.Get(); + AssetRegistry.Tick(-1.0f); + + // Delete unreferenced redirector packages + for (int32 PackageIndex = 0; PackageIndex < RedirectorsToFixup.Num(); PackageIndex++) + { + const FString& Filename = RedirectorsToFixup[PackageIndex]; + + FName PackageName = FName(*FPackageName::FilenameToLongPackageName(Filename)); + + // Load and save this package + TArray Referencers; + + AssetRegistry.GetReferencers(PackageName, Referencers); + + if (Referencers.Num() == 0) + { + if (Verbosity != ONLY_ERRORS) + { + UE_LOG(LogContentCommandlet, Display, TEXT("Deleting unreferenced redirector [%s]"), *Filename); + } + + DeleteOnePackage(Filename); + } + else if (Verbosity != ONLY_ERRORS) + { + UE_LOG(LogContentCommandlet, Display, TEXT("Can't delete redirector [%s], unsaved packages reference it"), *Filename); + } + } + // Submit the results to source control if( bAutoCheckIn ) { @@ -806,6 +928,10 @@ FText UResavePackagesCommandlet::GetChangelistDescription() const { ChangelistDescription = NSLOCTEXT("ContentCmdlets", "ChangelistDescriptionBuildTextureStreaming", "Rebuild texture streaming."); } + else if (RedirectorsToFixup.Num() > 0) + { + ChangelistDescription = NSLOCTEXT("ContentCmdlets", "ChangelistDescriptionRedirectors", "Fixing Redirectors"); + } else { ChangelistDescription = NSLOCTEXT("ContentCmdlets", "ChangelistDescription", "Resave Deprecated Packages"); @@ -1174,7 +1300,7 @@ void UResavePackagesCommandlet::PerformAdditionalOperations(class UWorld* World, { for(const auto& SublevelFilename : SublevelFilenames) { - FilesToSubmit.Add(SublevelFilename); + FilesToSubmit.AddUnique(SublevelFilename); } } diff --git a/Engine/Source/Editor/UnrealEd/Private/Commandlets/CookCommandlet.cpp b/Engine/Source/Editor/UnrealEd/Private/Commandlets/CookCommandlet.cpp index 43593effe55c..c31889f6e38b 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Commandlets/CookCommandlet.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Commandlets/CookCommandlet.cpp @@ -39,6 +39,7 @@ #include "ShaderCompiler.h" #include "HAL/MemoryMisc.h" #include "ProfilingDebugging/CookStats.h" +#include "AssetRegistryModule.h" DEFINE_LOG_CATEGORY_STATIC(LogCookCommandlet, Log, All); @@ -382,78 +383,109 @@ bool UCookCommandlet::CookOnTheFly( FGuid InstanceId, int32 Timeout, bool bForce // 2. We have cooked non-map packages and... // a. we have accumulated 50 (configurable) of these since the last GC. // b. we have been idle for 20 (configurable) seconds. - bool bShouldGC = true; - - // megamoth - uint32 NonMapPackageCountSinceLastGC = 0; - - const uint32 PackagesPerGC = CookOnTheFlyServer->GetPackagesPerGC(); - const double IdleTimeToGC = CookOnTheFlyServer->GetIdleTimeToGC(); - const uint64 MaxMemoryAllowance = CookOnTheFlyServer->GetMaxMemoryAllowance(); - - double LastCookActionTime = FPlatformTime::Seconds(); - - FDateTime LastConnectionTime = FDateTime::UtcNow(); - bool bHadConnection = false; - - bool bCookedAMapSinceLastGC = false; - while (!GIsRequestingExit) + struct FCookOnTheFlyGCController { - uint32 TickResults = 0; - static const float CookOnTheSideTimeSlice = 10.0f; - TickResults = CookOnTheFlyServer->TickCookOnTheSide(CookOnTheSideTimeSlice, NonMapPackageCountSinceLastGC); + public: + FCookOnTheFlyGCController(const UCookOnTheFlyServer* COtFServer) + : PackagesPerGC(COtFServer->GetPackagesPerGC()) + , IdleTimeToGC(COtFServer->GetIdleTimeToGC()) + , bShouldGC(true) + , PackagesCookedSinceLastGC(0) + , LastCookActionTime(FPlatformTime::Seconds()) + {} - bCookedAMapSinceLastGC |= ((TickResults & UCookOnTheFlyServer::COSR_RequiresGC) != 0); - if ( TickResults & (UCookOnTheFlyServer::COSR_CookedMap | UCookOnTheFlyServer::COSR_CookedPackage | UCookOnTheFlyServer::COSR_WaitingOnCache)) + /** Tntended to be called with stats from a UCookOnTheFlyServer::TickCookOnTheSide() call. Determines if we should be calling GC after TickCookOnTheSide(). */ + void Update(uint32 CookedCount, UCookOnTheFlyServer::ECookOnTheSideResult ResultFlags) { - LastCookActionTime = FPlatformTime::Seconds(); - } + if (ResultFlags & (UCookOnTheFlyServer::COSR_CookedMap | UCookOnTheFlyServer::COSR_CookedPackage | UCookOnTheFlyServer::COSR_WaitingOnCache)) + { + LastCookActionTime = FPlatformTime::Seconds(); + } + + if (ResultFlags & UCookOnTheFlyServer::COSR_RequiresGC) + { + UE_LOG(LogCookCommandlet, Display, TEXT("Cooker cooked a map since last gc... collecting garbage")); + bShouldGC |= true; + } - if (NonMapPackageCountSinceLastGC > 0) - { - if ((PackagesPerGC > 0) && (NonMapPackageCountSinceLastGC > PackagesPerGC)) + PackagesCookedSinceLastGC += CookedCount; + if ((PackagesPerGC > 0) && (PackagesCookedSinceLastGC > PackagesPerGC)) { UE_LOG(LogCookCommandlet, Display, TEXT("Cooker has exceeded max number of non map packages since last gc")); bShouldGC |= true; } - if ((IdleTimeToGC > 0) && ((FPlatformTime::Seconds() - LastCookActionTime) >= IdleTimeToGC)) + // we don't want to gc if we are waiting on cache of objects. this could clean up objects which we will need to reload next frame + bPosteponeGC = (ResultFlags & UCookOnTheFlyServer::COSR_WaitingOnCache) != 0; + } + + /** Runs GC if Update() determined it should happen. Also checks the idle time against the limit, and runs GC then if packages have been loaded. */ + void ConditionallyCollectGarbage(const UCookOnTheFlyServer* COtFServer) + { + if (!bShouldGC) { - UE_LOG(LogCookCommandlet, Display, TEXT("Cooker has been idle for long time gc")); - bShouldGC |= true; + if (PackagesCookedSinceLastGC > 0 && IdleTimeToGC > 0) + { + double IdleTime = FPlatformTime::Seconds() - LastCookActionTime; + if (IdleTime >= IdleTimeToGC) + { + UE_LOG(LogCookCommandlet, Display, TEXT("Cooker has been idle for long time gc")); + bShouldGC |= true; + } + } + + if (!bShouldGC && COtFServer->HasExceededMaxMemory()) + { + UE_LOG(LogCookCommandlet, Display, TEXT("Cooker has exceeded max memory usage collecting garbage")); + bShouldGC |= true; + } + } + + if (bShouldGC && !bPosteponeGC) + { + Reset(); + UE_LOG(LogCookCommandlet, Display, TEXT("GC...")); + CollectGarbage(RF_NoFlags); } } - if ( bCookedAMapSinceLastGC ) - { - UE_LOG(LogCookCommandlet, Display, TEXT("Cooker cooked a map since last gc collecting garbage")); - bShouldGC |= true; - } - - if ( !bShouldGC && CookOnTheFlyServer->HasExceededMaxMemory() ) - { - UE_LOG(LogCookCommandlet, Display, TEXT("Cooker has exceeded max memory usage collecting garbage")); - bShouldGC |= true; - } - - // we don't want to gc if we are waiting on cache of objects. this could clean up objects which we will need to reload next frame - if (bShouldGC && ((TickResults & UCookOnTheFlyServer::COSR_WaitingOnCache)==0) ) + private: + /** Resets counters and flags used to determine when we should GC. */ + void Reset() { bShouldGC = false; - bCookedAMapSinceLastGC = false; - NonMapPackageCountSinceLastGC = 0; - - UE_LOG(LogCookCommandlet, Display, TEXT("GC...")); - - CollectGarbage(RF_NoFlags); + PackagesCookedSinceLastGC = 0; } + private: + const uint32 PackagesPerGC; + const double IdleTimeToGC; + + bool bShouldGC; + uint32 PackagesCookedSinceLastGC; + double LastCookActionTime; + bool bPosteponeGC; + + } CookOnTheFlyGCController(CookOnTheFlyServer); + + FDateTime LastConnectionTime = FDateTime::UtcNow(); + bool bHadConnection = false; + + while (!GIsRequestingExit) + { + uint32 CookedPkgCount = 0; + uint32 TickResults = CookOnTheFlyServer->TickCookOnTheSide(/*TimeSlice =*/10.f, CookedPkgCount); + + // Flush the asset registry before GC + FAssetRegistryModule::TickAssetRegistry(-1.0f); + + CookOnTheFlyGCController.Update(CookedPkgCount, (UCookOnTheFlyServer::ECookOnTheSideResult)TickResults); + CookOnTheFlyGCController.ConditionallyCollectGarbage(CookOnTheFlyServer); // force at least a tick shader compilation even if we are requesting stuff CookOnTheFlyServer->TickRecompileShaderRequests(); GShaderCompilingManager->ProcessAsyncResults(true, false); - while ( (CookOnTheFlyServer->HasCookRequests() == false) && !GIsRequestingExit) { CookOnTheFlyServer->TickRecompileShaderRequests(); @@ -490,6 +522,8 @@ bool UCookCommandlet::CookOnTheFly( FGuid InstanceId, int32 Timeout, bool bForce GIsRequestingExit = true; } } + + CookOnTheFlyGCController.ConditionallyCollectGarbage(CookOnTheFlyServer); } } @@ -899,6 +933,9 @@ bool UCookCommandlet::CookByTheBook( const TArray& Platforms, GShaderCompilingManager->ProcessAsyncResults(true, false); } + // Flush the asset registry before GC + FAssetRegistryModule::TickAssetRegistry(-1.0f); + auto DumpMemStats = []() { FGenericMemoryStats MemStats; diff --git a/Engine/Source/Editor/UnrealEd/Private/Commandlets/DerivedDataCacheCommandlet.cpp b/Engine/Source/Editor/UnrealEd/Private/Commandlets/DerivedDataCacheCommandlet.cpp index b6dc05f2360c..a3211836679a 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Commandlets/DerivedDataCacheCommandlet.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Commandlets/DerivedDataCacheCommandlet.cpp @@ -201,8 +201,7 @@ int32 UDerivedDataCacheCommandlet::Main( const FString& Params ) } if (bDoSubset) { - const FString& SubPackageName = FPackageName::PackageFromPath(*Filename); - if (FCrc::StrCrc_DEPRECATED(*SubPackageName.ToUpper()) % SubsetMod != SubsetTarget) + if (FCrc::StrCrc_DEPRECATED(*PackageName.ToUpper()) % SubsetMod != SubsetTarget) { continue; } diff --git a/Engine/Source/Editor/UnrealEd/Private/Commandlets/DiffAssetsCommandlet.cpp b/Engine/Source/Editor/UnrealEd/Private/Commandlets/DiffAssetsCommandlet.cpp index 442de1d2378c..094738dd3e88 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Commandlets/DiffAssetsCommandlet.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Commandlets/DiffAssetsCommandlet.cpp @@ -35,7 +35,7 @@ bool UDiffAssetsCommandlet::ExportFilesToTextAndDiff(const FString& InParams) const FString AssetPackageExtension = FPackageName::GetAssetPackageExtension(); FString DiffCmd; - if (!FParse::Value(*Params, TEXT("DiffCmd="), DiffCmd) || Tokens.Num() != 2) + if (!FParse::Value(*Params, TEXT("DiffCmd="), DiffCmd) || Tokens.Num() < 2) { UE_LOG(LogDiffAssetsCommandlet, Warning, TEXT("Usage: UDiffAssets File1%s File2%s DiffCmd=\"C:/Program Files/Araxis/Araxis Merge/AraxisP4Diff.exe {1} {2}\""), *AssetPackageExtension, *AssetPackageExtension); return false; @@ -182,7 +182,7 @@ bool UDiffAssetsCommandlet::ExportFilesToTextAndDiff(const FString& InFilename1, FString ReplacedDiffCmd = DiffCommand.Replace(TEXT("{1}"), *TextFilename1).Replace(TEXT("{2}"), *TextFilename2); - int32 ArgsAt = ReplacedDiffCmd.Find(TEXT(" ")); + int32 ArgsAt = DiffCommand.Find(TEXT("{1}")) - 1; FString Args; if (ArgsAt > 0) { diff --git a/Engine/Source/Editor/UnrealEd/Private/Commandlets/DiffPackagesCommandlet.cpp b/Engine/Source/Editor/UnrealEd/Private/Commandlets/DiffPackagesCommandlet.cpp index 2cd0921b8501..c3677389cec3 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Commandlets/DiffPackagesCommandlet.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Commandlets/DiffPackagesCommandlet.cpp @@ -544,29 +544,31 @@ bool UDiffPackagesCommandlet::Initialize( const TCHAR* Parms ) break; //@} - if ( FilesInPath.Num() > 0 ) - { - // this means that the location/package name that the user specified is an existing file... - // eventually we'll probably allow this but for simplicity's sake, at this point it's an error - SET_WARN_COLOR(COLOR_RED); - UE_LOG(LogDiffPackagesCommandlet, Error, TEXT("Merge target file already exists: %s. Overwriting an existing file via merging is now allowed!"), *FilesInPath[0]); - bResult = false; - break; - } + /* + if ( FilesInPath.Num() > 0 ) + { + // this means that the location/package name that the user specified is an existing file... + // eventually we'll probably allow this but for simplicity's sake, at this point it's an error + SET_WARN_COLOR(COLOR_RED); + UE_LOG(LogDiffPackagesCommandlet, Error, TEXT("Merge target file already exists: %s. Overwriting an existing file via merging is now allowed!"), *FilesInPath[0]); + bResult = false; + break; + } - MergePackage = CreatePackage(NULL, TEXT("MergePackage")); - // diff all properties if we are merging ? - // todo: ?? - // bDiffAllProps = true; - // bDiffNonEditProps = true; - SET_WARN_COLOR_AND_BACKGROUND(COLOR_RED, COLOR_WHITE); - UE_LOG(LogDiffPackagesCommandlet, Warning, TEXT("\n")); - UE_LOG(LogDiffPackagesCommandlet, Warning, TEXT("==============================================================================")); - UE_LOG(LogDiffPackagesCommandlet, Warning, TEXT("WARNING: Merge functionality is not finished! (It only copies from Package 1!)")); - UE_LOG(LogDiffPackagesCommandlet, Warning, TEXT("==============================================================================")); - UE_LOG(LogDiffPackagesCommandlet, Warning, TEXT("\n")); - CLEAR_WARN_COLOR(); - //@todo - validation + MergePackage = CreatePackage(NULL, TEXT("MergePackage")); + // diff all properties if we are merging ? + // todo: ?? + // bDiffAllProps = true; + // bDiffNonEditProps = true; + SET_WARN_COLOR_AND_BACKGROUND(COLOR_RED, COLOR_WHITE); + UE_LOG(LogDiffPackagesCommandlet, Warning, TEXT("\n")); + UE_LOG(LogDiffPackagesCommandlet, Warning, TEXT("==============================================================================")); + UE_LOG(LogDiffPackagesCommandlet, Warning, TEXT("WARNING: Merge functionality is not finished! (It only copies from Package 1!)")); + UE_LOG(LogDiffPackagesCommandlet, Warning, TEXT("==============================================================================")); + UE_LOG(LogDiffPackagesCommandlet, Warning, TEXT("\n")); + CLEAR_WARN_COLOR(); + //@todo - validation + */ } else { @@ -1523,7 +1525,7 @@ EObjectDiff UDiffPackagesCommandlet::CompareNativePropertyValues( UObject* ObjA, // If we have no common base and the values from ObjA & ObjB are different, mark it as a conflict else if ( PropertyDataA && PropertyDataB ) { - FString ObjectPathName = ObjA ? ObjA->GetFullName(Packages[0]) : ObjB->GetFullName(Packages[1]); + FString ObjectPathName = ObjA->GetFullName(Packages[0]); // CurrentPropertyComparison.DiffType = OD_ABConflict; // AppendComparisonResultText(PropDiff.DiffText, FString::Printf(TEXT("(%s) %s::%s"), GetDiffTypeText(PropDiff.DiffType,NumPackages), *ObjectPathName, *PropName)); // AppendComparisonResultText(PropDiff.DiffText, FString::Printf(TEXT(" %s: %s"), *PackageFilenames[0], *PropTextA)); diff --git a/Engine/Source/Editor/UnrealEd/Private/Commandlets/DumpBlueprintsInfoCommandlet.cpp b/Engine/Source/Editor/UnrealEd/Private/Commandlets/DumpBlueprintsInfoCommandlet.cpp index 0ba460d6f048..972f3424c1f9 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Commandlets/DumpBlueprintsInfoCommandlet.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Commandlets/DumpBlueprintsInfoCommandlet.cpp @@ -382,7 +382,7 @@ DumpBlueprintsInfo commandlet params: \n\ * actions available to that pin (as if you dragged and spawned a context * menu from it). */ - static void DumpContextualPinTypeActions(uint32 Indent, UEdGraph* Graph, FEdGraphPinType const& PinType, FArchive* FileOutWriter); + static void DumpContextualPinTypeActions(uint32 Indent, UEdGraph* Graph, const FEdGraphPinType& PinType, FArchive* FileOutWriter); /** * Generic function that takes a contextual GraphActionList and calls down @@ -1946,7 +1946,15 @@ static bool DumpBlueprintInfoUtils::DumpPinContextActions(uint32 Indent, UEdGrap FileOutWriter->Serialize(TCHAR_TO_ANSI(TEXT(",\n")), 2); PinType.bIsReference = false; - PinType.bIsArray = true; + PinType.ContainerType = EPinContainerType::Array; + DumpContextualPinTypeActions(Indent, Graph, PinType, FileOutWriter); + FileOutWriter->Serialize(TCHAR_TO_ANSI(TEXT(",\n")), 2); + + PinType.ContainerType = EPinContainerType::Set; + DumpContextualPinTypeActions(Indent, Graph, PinType, FileOutWriter); + FileOutWriter->Serialize(TCHAR_TO_ANSI(TEXT(",\n")), 2); + + PinType.ContainerType = EPinContainerType::Map; DumpContextualPinTypeActions(Indent, Graph, PinType, FileOutWriter); bWroteToFile = true; @@ -1988,7 +1996,15 @@ static bool DumpBlueprintInfoUtils::DumpTypeTreeActions(uint32 Indent, UEdGraph* FileOutWriter->Serialize(TCHAR_TO_ANSI(TEXT(",\n")), 2); PinType.bIsReference = false; - PinType.bIsArray = true; + PinType.ContainerType = EPinContainerType::Array; + DumpContextualPinTypeActions(Indent, Graph, PinType, FileOutWriter); + FileOutWriter->Serialize(TCHAR_TO_ANSI(TEXT(",\n")), 2); + + PinType.ContainerType = EPinContainerType::Set; + DumpContextualPinTypeActions(Indent, Graph, PinType, FileOutWriter); + FileOutWriter->Serialize(TCHAR_TO_ANSI(TEXT(",\n")), 2); + + PinType.ContainerType = EPinContainerType::Map; DumpContextualPinTypeActions(Indent, Graph, PinType, FileOutWriter); PendingLineEnding = TEXT(",\n"); @@ -2019,7 +2035,7 @@ static bool DumpBlueprintInfoUtils::DumpTypeTreeActions(uint32 Indent, UEdGraph* } //------------------------------------------------------------------------------ -static void DumpBlueprintInfoUtils::DumpContextualPinTypeActions(uint32 Indent, UEdGraph* Graph, FEdGraphPinType const& PinType, FArchive* FileOutWriter) +static void DumpBlueprintInfoUtils::DumpContextualPinTypeActions(uint32 Indent, UEdGraph* Graph, const FEdGraphPinType& PinType, FArchive* FileOutWriter) { FGraphContextMenuBuilder ContextMenuBuilder(Graph); diff --git a/Engine/Source/Editor/UnrealEd/Private/Commandlets/FixupRedirectsCommandlet.cpp b/Engine/Source/Editor/UnrealEd/Private/Commandlets/FixupRedirectsCommandlet.cpp deleted file mode 100644 index 69f41d9ef12c..000000000000 --- a/Engine/Source/Editor/UnrealEd/Private/Commandlets/FixupRedirectsCommandlet.cpp +++ /dev/null @@ -1,804 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -/*============================================================================= - FixupRedirectsCommandlet.cpp: Object redirect cleaner commandlet -=============================================================================*/ - -#include "Commandlets/FixupRedirectsCommandlet.h" -#include "HAL/FileManager.h" -#include "Misc/Paths.h" -#include "Misc/FeedbackContext.h" -#include "Modules/ModuleManager.h" -#include "UObject/UObjectHash.h" -#include "UObject/Class.h" -#include "UObject/Package.h" -#include "UObject/MetaData.h" -#include "UObject/ObjectRedirector.h" -#include "Misc/PackageName.h" -#include "Misc/RedirectCollector.h" -#include "ISourceControlOperation.h" -#include "SourceControlOperations.h" -#include "ISourceControlModule.h" -#include "EngineGlobals.h" -#include "Engine/UserDefinedEnum.h" -#include "Editor.h" -#include "FileHelpers.h" -#include "AutoSaveUtils.h" -#include "AssetRegistryModule.h" - -DEFINE_LOG_CATEGORY_STATIC(LogFixupRedirectsCommandlet, Log, All); - -UFixupRedirectsCommandlet::UFixupRedirectsCommandlet(const FObjectInitializer& ObjectInitializer) - : Super(ObjectInitializer) -{ - LogToConsole = false; -} - - -void UFixupRedirectsCommandlet::CreateCustomEngine(const FString& Params) -{ - // by making sure these are NULL, the caller will create the default engine object - GEngine = GEditor = NULL; -} - -int32 UFixupRedirectsCommandlet::Main( const FString& Params ) -{ - // Loading asset registry during serialization below will assert - FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(TEXT("AssetRegistry")); - - // Retrieve list of all packages in .ini paths. - TArray PackageList; - FEditorFileUtils::FindAllPackageFiles(PackageList); - if( !PackageList.Num() ) - { - return 0; - } - - // process the commandline - FString Token; - const TCHAR* CommandLine = *Params; - bool bIsQuietMode = false; - bool bIsTestOnly = false; - bool bShouldRestoreProgress= false; - bool bIsSCCDisabled = false; - bool bUpdateEnginePackages = false; - bool bDeleteRedirects = true; - bool bDeleteOnlyReferencedRedirects = false; - bool bAutoSubmit = false; - bool bSandboxed = IFileManager::Get().IsSandboxEnabled(); - - while (FParse::Token(CommandLine, Token, 1)) - { - if (Token == TEXT("-nowarn")) - { - bIsQuietMode = true; - } - else if (Token == TEXT("-testonly")) - { - bIsTestOnly = true; - } - else if (Token == TEXT("-restore")) - { - bShouldRestoreProgress = true; - } - else if (Token == TEXT("-NoAutoCheckout")) - { - bIsSCCDisabled = true; - } - else if (Token == TEXT("-AutoSubmit")) - { - bAutoSubmit = true; - } - else if (Token == TEXT("-UpdateEnginePackages")) - { - bUpdateEnginePackages = true; - } - else if (Token == TEXT("-NoDelete")) - { - bDeleteRedirects = false; - } - else if (Token == TEXT("-NoDeleteUnreferenced")) - { - bDeleteOnlyReferencedRedirects = true; - } - else if ( Token.Left(1) != TEXT("-") ) - { - FPackageName::SearchForPackageOnDisk(Token, &GRedirectCollector.FileToFixup); - } - } - - if (bSandboxed) - { - UE_LOG(LogFixupRedirectsCommandlet, Display, TEXT("Running in a sandbox.")); - bIsSCCDisabled = true; - bAutoSubmit = false; - bDeleteRedirects = false; - } - - - bool bShouldSkipErrors = false; - - // Setup file Output log in the Saved Directory - const FString ProjectDir = FPaths::GetPath(FPaths::GetProjectFilePath()); - const FString LogFilename = FPaths::Combine(*ProjectDir, TEXT("Saved"), TEXT("FixupRedirect"), TEXT("FixupRedirect.log")); - FArchive* LogOutputFile = IFileManager::Get().CreateFileWriter(*LogFilename); - LogOutputFile->Logf(TEXT("[Redirects]")); - - ///////////////////////////////////////////////////////////////////// - // Display any script code referenced redirects - ///////////////////////////////////////////////////////////////////// - - TArray UpdatePackages; - TArray RedirectorsThatCantBeCleaned; - - if (!bShouldRestoreProgress) - { - // load all string asset reference targets, and add fake redirectors for them - GRedirectCollector.ResolveStringAssetReference(); - - for (const auto& Redir : GRedirectCollector.GetRedirections()) - { - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Boot redirector can't be cleaned: %s(%s) -> %s(%s)"), *Redir.RedirectorName, *Redir.RedirectorPackageFilename, *Redir.DestinationObjectName, *Redir.PackageFilename); - RedirectorsThatCantBeCleaned.AddUnique(Redir.RedirectorName); - } - - ///////////////////////////////////////////////////////////////////// - // Build a list of packages that need to be updated - ///////////////////////////////////////////////////////////////////// - - SET_WARN_COLOR(COLOR_WHITE); - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("")); - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Generating list of tasks:")); - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("-------------------------")); - CLEAR_WARN_COLOR(); - - int32 GCIndex = 0; - - // process script code first pass, then everything else - for( int32 PackageIndex = 0; PackageIndex < PackageList.Num(); PackageIndex++ ) - { - const FString& Filename = PackageList[PackageIndex]; - - // already loaded code, skip them, and skip autosave packages - if (Filename.StartsWith(AutoSaveUtils::GetAutoSaveDir(), ESearchCase::IgnoreCase)) - { - continue; - } - - UE_LOG(LogFixupRedirectsCommandlet, Display, TEXT("Looking for redirects in %s..."), *Filename); - - // Assert if package couldn't be opened so we have no chance of messing up saving later packages. - UPackage* Package = LoadPackage(NULL, *Filename, 0); - - // load all string asset reference targets, and add fake redirectors for them - GRedirectCollector.ResolveStringAssetReference(); - - if (!Package) - { - SET_WARN_COLOR(COLOR_RED); - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT(" ... failed to open %s"), *Filename); - CLEAR_WARN_COLOR(); - - // if we are not in quiet mode, and the user wants to continue, go on - const FText Message = FText::Format( NSLOCTEXT("Unreal", "PackageFailedToOpen", "The package '{0}' failed to open. Should this commandlet continue operation, ignoring further load errors? Continuing may have adverse effects (object references may be lost)."), FText::FromString( Filename ) ); - if (bShouldSkipErrors || (!bIsQuietMode && GWarn->YesNof( Message ))) - { - bShouldSkipErrors = true; - continue; - } - else - { - return 1; - } - } - - // all notices here about redirects get this color - SET_WARN_COLOR(COLOR_DARK_GREEN); - - // look for any redirects that were followed that are referenced by this package - // (may have been loaded earlier if this package was loaded by script code) - // any redirectors referenced by script code can't be cleaned up - for (const auto& Redir : GRedirectCollector.GetRedirections()) - { - if (Redir.PackageFilename == Filename) - { - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT(" ... references %s [-> %s]"), *Redir.RedirectorName, *Redir.DestinationObjectName); - - // put the source and dest packages in the list to be updated - UpdatePackages.AddUnique(Redir.PackageFilename); - UpdatePackages.AddUnique(Redir.RedirectorPackageFilename); - } - } - - // clear the flag for needing to collect garbage - bool bNeedToCollectGarbage = false; - - // if this package has any redirectors, make sure we update it - if (!GRedirectCollector.FileToFixup.Len() || GRedirectCollector.FileToFixup == FPackageName::FilenameToLongPackageName(Filename)) - { - TArray ObjectsInOuter; - GetObjectsWithOuter(Package, ObjectsInOuter); - for( int32 Index = 0; Index < ObjectsInOuter.Num(); Index++ ) - { - UObject* Obj = ObjectsInOuter[Index]; - UObjectRedirector* Redir = Cast(Obj); - if (Redir) - { - // make sure this package is in the list of packages to update - UpdatePackages.AddUnique(Filename); - - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT(" ... has redirect %s [-> %s]"), *Redir->GetPathName(), *Redir->DestinationObject->GetFullName()); - LogOutputFile->Logf(TEXT("%s = %s"), *Redir->GetPathName(), *Redir->DestinationObject->GetFullName()); - - // make sure we GC if we found a redirector - bNeedToCollectGarbage = true; - } - } - } - - CLEAR_WARN_COLOR(); - - // collect garbage every N packages, or if there was any redirectors in the package - // (to make sure that redirectors get reloaded properly and followed by the callback) - // also, GC after loading a map package, to make sure it's unloaded so that we can track - // other packages loading a map package as a dependency - if (((++GCIndex) % 50) == 0 || bNeedToCollectGarbage || Package->ContainsMap()) - { - // collect garbage to close the package - CollectGarbage(RF_NoFlags); - UE_LOG(LogFixupRedirectsCommandlet, Display, TEXT("GC...")); - // reset our counter - GCIndex = 0; - } - } - - // save off restore point - FArchive* Ar = IFileManager::Get().CreateFileWriter(*(FPaths::GameSavedDir() + TEXT("Fixup.bin"))); - *Ar << GRedirectCollector.Redirections; - *Ar << UpdatePackages; - *Ar << RedirectorsThatCantBeCleaned; - delete Ar; - } - else - { - // load restore point - FArchive* Ar = IFileManager::Get().CreateFileReader(*(FPaths::GameSavedDir() + TEXT("Fixup.bin"))); - if( Ar != NULL ) - { - *Ar << GRedirectCollector.Redirections; - *Ar << UpdatePackages; - *Ar << RedirectorsThatCantBeCleaned; - delete Ar; - } - } - - // unregister the callback so we stop getting redirections added - FCoreUObjectDelegates::RedirectorFollowed.RemoveAll(&GRedirectCollector); - - ///////////////////////////////////////////////////////////////////// - // Explain to user what is happening - ///////////////////////////////////////////////////////////////////// - SET_WARN_COLOR(COLOR_YELLOW); - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("")); - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Files that need to fixed up:")); - SET_WARN_COLOR(COLOR_DARK_YELLOW); - - // print out the working set of packages - for (int32 PackageIndex = 0; PackageIndex < UpdatePackages.Num(); PackageIndex++) - { - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT(" %s"), *UpdatePackages[PackageIndex]); - } - - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("")); - CLEAR_WARN_COLOR(); - - // if we are only testing, just just quiet before actually doing anything - if (bIsTestOnly) - { - LogOutputFile->Close(); - delete LogOutputFile; - LogOutputFile = NULL; - return 0; - } - - ///////////////////////////////////////////////////////////////////// - // Find redirectors that are referenced by packages we cant check out - ///////////////////////////////////////////////////////////////////// - - bool bEngineRedirectorCantBeCleaned = false; - - ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider(); - - // initialize source control if it hasn't been initialized yet - if(!bIsSCCDisabled) - { - SourceControlProvider.Init(); - - //Make sure we can check out all packages - update their state first - SourceControlProvider.Execute(ISourceControlOperation::Create(), UpdatePackages); - } - - for( int32 PackageIndex = 0; PackageIndex < UpdatePackages.Num(); PackageIndex++ ) - { - const FString& Filename = UpdatePackages[PackageIndex]; - - bool bCanEdit = true; - - if(!bIsSCCDisabled) - { - FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState(Filename, EStateCacheUsage::ForceUpdate); - if(SourceControlState.IsValid() && !SourceControlState->CanEdit()) - { - bCanEdit = false; - } - } - else if(IFileManager::Get().IsReadOnly(*Filename)) - { - bCanEdit = false; - } - - if(!bCanEdit) - { - const bool bAllowCheckout = bUpdateEnginePackages || !Filename.StartsWith( FPaths::EngineDir() ); - - if (!bIsSCCDisabled && bAllowCheckout) - { - FString PackageName(FPackageName::FilenameToLongPackageName(Filename)); - FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState(Filename, EStateCacheUsage::ForceUpdate); - if (SourceControlState.IsValid() && SourceControlState->CanCheckout()) - { - SourceControlProvider.Execute(ISourceControlOperation::Create(), SourceControlHelpers::PackageFilename(PackageName)); - FSourceControlStatePtr NewSourceControlState = SourceControlProvider.GetState(Filename, EStateCacheUsage::ForceUpdate); - bCanEdit = NewSourceControlState.IsValid() && NewSourceControlState->CanEdit(); - } - } - - // if the checkout failed for any reason, we can't clean it up - if (bAllowCheckout && !bCanEdit) - { - SET_WARN_COLOR(COLOR_RED); - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Couldn't check out/edit %s..."), *Filename); - CLEAR_WARN_COLOR(); - - // load all string asset reference targets, and add fake redirectors for them - GRedirectCollector.ResolveStringAssetReference(); - - // any redirectors that are pointed to by this read-only package can't be fixed up - for (int32 RedirIndex = 0; RedirIndex < GRedirectCollector.Redirections.Num(); RedirIndex++) - { - FRedirection& Redir = GRedirectCollector.Redirections[RedirIndex]; - - // any redirectors pointed to by this file we don't clean - if (Redir.PackageFilename == Filename) - { - RedirectorsThatCantBeCleaned.AddUnique(Redir.RedirectorName); - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT(" ... can't fixup references to %s"), *Redir.RedirectorName); - - // if this redirector is in an Engine package, we need to alert the user, because - // Engine packages are shared between games, so if one game still needs the redirector - // to be valid, then we can't check in Engine packages after another game has - // run that could - if (!bEngineRedirectorCantBeCleaned) - { - FString PackagePath; - FPackageName::DoesPackageExist(Redir.RedirectorPackageFilename, NULL, &PackagePath); - if (PackagePath.StartsWith(FPaths::EngineDir())) - { - bEngineRedirectorCantBeCleaned = true; - } - } - } - // any redirectors in this file can't be deleted - else if (Redir.RedirectorPackageFilename == Filename) - { - RedirectorsThatCantBeCleaned.AddUnique(Redir.RedirectorName); - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT(" ... can't delete %s"), *Redir.RedirectorName); - } - } - } - else - { - SET_WARN_COLOR(COLOR_DARK_GREEN); - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Checked out %s..."), *Filename); - CLEAR_WARN_COLOR(); - } - } - } - // warn about an engine package that can't be cleaned up (may want to revert engine packages) - if (bEngineRedirectorCantBeCleaned) - { - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("")); - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Engine package redirectors are referenced by packages that can't be cleaned. If you have multiple games, it's recommended you revert any checked out Engine packages.")); - bUpdateEnginePackages=false; - } - - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("")); - - ///////////////////////////////////////////////////////////////////// - // Load and save packages to save out the proper fixed up references - ///////////////////////////////////////////////////////////////////// - - SET_WARN_COLOR(COLOR_WHITE); - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Fixing references to point to proper objects:")); - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("---------------------------------------------")); - CLEAR_WARN_COLOR(); - - // keep a list of all packages that have ObjectRedirects in them. This is not needed if we aren't deleting redirects - TArray PackagesWithRedirects; - - // Delete these packages entirely because they are empty - TArray EmptyPackagesToDelete; - - if ( bDeleteRedirects ) - { - PackagesWithRedirects.AddZeroed(UpdatePackages.Num()); - EmptyPackagesToDelete.AddZeroed(PackageList.Num()); - } - - bool bSCCEnabled = ISourceControlModule::Get().IsEnabled(); - - // Iterate over all packages, loading and saving to remove all references to ObjectRedirectors (can't delete the Redirects yet) - for( int32 PackageIndex = 0; PackageIndex < UpdatePackages.Num(); PackageIndex++ ) - { - const FString& Filename = UpdatePackages[PackageIndex]; - - // we can't do anything with packages that are read-only or cant be edited due to source control (we don't want to fixup the redirects) - if(bSCCEnabled) - { - FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState(SourceControlHelpers::PackageFilename(Filename), EStateCacheUsage::ForceUpdate); - if(SourceControlState.IsValid() && !SourceControlState->CanEdit()) - { - continue; - } - } - else if(IFileManager::Get().IsReadOnly(*Filename)) - { - continue; - } - - // Assert if package couldn't be opened so we have no chance of messing up saving later packages. - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Cleaning %s"), *Filename); - UPackage* Package = LoadPackage( NULL, *Filename, LOAD_NoVerify ); - // load all string asset reference targets, and add fake redirectors for them - GRedirectCollector.ResolveStringAssetReference(); - - // if it failed to open, we have already dealt with quitting if we are going to, so just skip it - if (!Package) - { - continue; - } - - if ( bDeleteOnlyReferencedRedirects && bDeleteRedirects ) - { - TArray ObjectsInOuter; - GetObjectsWithOuter(Package, ObjectsInOuter); - for( int32 Index = 0; Index < ObjectsInOuter.Num(); Index++ ) - { - UObject* Obj = ObjectsInOuter[Index]; - UObjectRedirector* Redir = Cast(Obj); - if (Redir) - { - PackagesWithRedirects[PackageIndex] = 1; - break; - } - } - } - - // Don't save packages in the engine directory if we did not opt to update engine packages - if( bUpdateEnginePackages || !Filename.StartsWith( FPaths::EngineDir() ) ) - { - // save out the package - UWorld* World = UWorld::FindWorldInPackage(Package); - GEditor->SavePackage( Package, World, World ? RF_NoFlags : RF_Standalone, *Filename, GWarn ); - } - - // collect garbage to close the package - UE_LOG(LogFixupRedirectsCommandlet, Display, TEXT("Collecting Garbage...")); - CollectGarbage(RF_NoFlags); - } - - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("")); - - if ( bDeleteRedirects ) - { - ///////////////////////////////////////////////////////////////////// - // Delete all redirects that are no longer referenced - ///////////////////////////////////////////////////////////////////// - - SET_WARN_COLOR(COLOR_WHITE); - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Deleting redirector objects:")); - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("----------------------------")); - CLEAR_WARN_COLOR(); - - const TArray& PackagesToCleaseOfRedirects = bDeleteOnlyReferencedRedirects ? UpdatePackages : PackageList; - - int32 GCIndex = 0; - - // Again, iterate over all packages, loading and saving to and this time deleting all - for( int32 PackageIndex = 0; PackageIndex < PackagesToCleaseOfRedirects.Num(); PackageIndex++ ) - { - const FString& Filename = PackagesToCleaseOfRedirects[PackageIndex]; - - if (bDeleteOnlyReferencedRedirects && PackagesWithRedirects[PackageIndex] == 0) - { - continue; - } - - // When not updating engine packages, we don't need to spam the log about them. - if (!bUpdateEnginePackages && Filename.StartsWith(FPaths::EngineDir())) - { - continue; - } - - // The file should have already been checked out/be writable - // If it is read only that means the checkout failed or we are not using source control and we can not write this file. - if(bSCCEnabled) - { - FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState(SourceControlHelpers::PackageFilename(Filename), EStateCacheUsage::ForceUpdate); - if(SourceControlState.IsValid() && !SourceControlState->CanEdit()) - { - UE_LOG(LogFixupRedirectsCommandlet, Display, TEXT("Skipping file: source control says we cant edit the file %s..."), *Filename); - continue; - } - } - else if( IFileManager::Get().IsReadOnly( *Filename )) - { - UE_LOG(LogFixupRedirectsCommandlet, Display, TEXT("Skipping read-only file %s..."), *Filename); - continue; - } - - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Wiping %s..."), *Filename); - - UPackage* Package = LoadPackage( NULL, *Filename, 0 ); - // load all string asset reference targets, and add fake redirectors for them - GRedirectCollector.ResolveStringAssetReference(); - // if it failed to open, we have already dealt with quitting if we are going to, so just skip it - if (!Package) - { - continue; - } - - // assume that all redirs in this file are still-referenced - bool bIsDirty = false; - - // see if this package is completely empty other than purged redirectors and metadata - bool bIsEmpty = true; - - // delete all ObjectRedirects now - TArray Redirs; - // find all redirectors, put into an array so delete doesn't mess up the iterator - TArray ObjectsInOuter; - GetObjectsWithOuter(Package, ObjectsInOuter); - for( int32 Index = 0; Index < ObjectsInOuter.Num(); Index++ ) - { - UObject* Obj = ObjectsInOuter[Index]; - UObjectRedirector *Redir = Cast(Obj); - - if (Redir) - { - int32 Dummy; - // if the redirector was marked as uncleanable, skip it - if (RedirectorsThatCantBeCleaned.Find(Redir->GetFullName(), Dummy)) - { - SET_WARN_COLOR(COLOR_DARK_RED); - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT(" ... skipping still-referenced %s"), *Redir->GetFullName()); - CLEAR_WARN_COLOR(); - bIsEmpty = false; - continue; - } - - bIsDirty = true; - SET_WARN_COLOR(COLOR_DARK_GREEN); - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT(" ... deleting %s"), *Redir->GetFullName()); - CLEAR_WARN_COLOR(); - Redirs.Add(Redir); - } - else if ( (!Obj->IsA(UMetaData::StaticClass()) && !Obj->IsA(UField::StaticClass())) - || Obj->IsA(UUserDefinedEnum::StaticClass())) // UserDefinedEnum should not be deleted - { - // This package has a real object - bIsEmpty = false; - } - } - - if (bIsEmpty && !bDeleteOnlyReferencedRedirects) - { - EmptyPackagesToDelete[PackageIndex] = 1; - } - - // mark them for deletion. - for (int32 RedirIndex = 0; RedirIndex < Redirs.Num(); RedirIndex++) - { - UObjectRedirector* Redirector = Redirs[RedirIndex]; - // Remove standalone flag and mark as pending kill. - Redirector->ClearFlags( RF_Standalone | RF_Public ); - - // We don't need redirectors in the root set, the references should already be fixed up - if ( Redirector->IsRooted() ) - { - Redirector->RemoveFromRoot(); - } - - Redirector->MarkPendingKill(); - } - Redirs.Empty(); - - if (bIsDirty) - { - // Don't save packages in the engine directory if we did not opt to update engine packages - if( bUpdateEnginePackages || !Filename.StartsWith( FPaths::EngineDir() ) ) - { - // save the package - UWorld* World = UWorld::FindWorldInPackage(Package); - GEditor->SavePackage( Package, World, World ? RF_NoFlags : RF_Standalone, *Filename, GWarn ); - } - } - - // collect garbage every N packages, or if there was any redirectors in the package - if (((++GCIndex) % 50) == 0 || bIsDirty || Package->ContainsMap()) - { - // collect garbage to close the package - CollectGarbage(RF_NoFlags); - UE_LOG(LogFixupRedirectsCommandlet, Display, TEXT("GC...")); - // reset our counter - GCIndex = 0; - } - } - - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("")); - } - else - { - SET_WARN_COLOR(COLOR_WHITE); - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("----------------------------")); - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Not deleting any redirector objects:")); - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("----------------------------")); - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("")); - CLEAR_WARN_COLOR(); - } - - ///////////////////////////////////////////////////////////////////// - // Clean up any unused trash - ///////////////////////////////////////////////////////////////////// - - SET_WARN_COLOR(COLOR_WHITE); - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Deleting empty and unused packages:")); - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("---------------------------------------")); - CLEAR_WARN_COLOR(); - - LogOutputFile->Logf(TEXT("")); - LogOutputFile->Logf(TEXT("[Deleted]")); - - // Iterate over packages, attempting to delete unreferenced packages - for( int32 PackageIndex = 0; PackageIndex < PackageList.Num(); PackageIndex++ ) - { - bool bDelete = false; - const FString& Filename = PackageList[PackageIndex]; - - FString PackageName(FPackageName::FilenameToLongPackageName(Filename)); - - const bool bAllowDelete = bUpdateEnginePackages || !Filename.StartsWith( FPaths::EngineDir() ); - if (bDeleteRedirects && !bDeleteOnlyReferencedRedirects && EmptyPackagesToDelete[PackageIndex] && bAllowDelete) - { - // this package is completely empty, delete it - bDelete = true; - } - - if (bDelete == true) - { - struct Local - { - static bool DeleteFromDisk(const FString& InFilename, const FString& InMessage) - { - SET_WARN_COLOR(COLOR_GREEN); - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("%s"), *InMessage); - if (!IFileManager::Get().Delete(*InFilename, false, true)) - { - SET_WARN_COLOR(COLOR_RED); - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT(" ... failed to delete from disk."), *InFilename); - CLEAR_WARN_COLOR(); - return false; - } - CLEAR_WARN_COLOR(); - return true; - } - }; - - if (!bIsSCCDisabled) - { - // get file SCC status - FString FileName = SourceControlHelpers::PackageFilename(PackageName); - FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState(FileName, EStateCacheUsage::ForceUpdate); - - if(SourceControlState.IsValid() && (SourceControlState->IsCheckedOut() || SourceControlState->IsAdded()) ) - { - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Revert '%s' from source control..."), *Filename); - SourceControlProvider.Execute(ISourceControlOperation::Create(), FileName); - - SET_WARN_COLOR(COLOR_GREEN); - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Deleting '%s' from source control..."), *Filename); - CLEAR_WARN_COLOR(); - SourceControlProvider.Execute(ISourceControlOperation::Create(), FileName); - } - else if(SourceControlState.IsValid() && SourceControlState->CanCheckout()) - { - SET_WARN_COLOR(COLOR_GREEN); - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Deleting '%s' from source control..."), *Filename); - CLEAR_WARN_COLOR(); - SourceControlProvider.Execute(ISourceControlOperation::Create(), FileName); - } - else if(SourceControlState.IsValid() && SourceControlState->IsCheckedOutOther()) - { - SET_WARN_COLOR(COLOR_RED); - UE_LOG(LogFixupRedirectsCommandlet, Warning, TEXT("Couldn't delete '%s' from source control, someone has it checked out, skipping..."), *Filename); - CLEAR_WARN_COLOR(); - } - else if(SourceControlState.IsValid() && !SourceControlState->IsSourceControlled()) - { - if(Local::DeleteFromDisk(Filename, FString::Printf(TEXT("'%s' is not in source control, attempting to delete from disk..."), *Filename))) - { - LogOutputFile->Logf(*Filename); - } - } - else - { - if(Local::DeleteFromDisk(Filename, FString::Printf(TEXT("'%s' is in an unknown source control state, attempting to delete from disk..."), *Filename))) - { - LogOutputFile->Logf(*Filename); - } - } - } - else - { - if(Local::DeleteFromDisk(Filename, FString::Printf(TEXT("source control disabled while deleting '%s', attempting to delete from disk..."), *Filename))) - { - LogOutputFile->Logf(*Filename); - } - } - } - } - LogOutputFile->Close(); - delete LogOutputFile; - LogOutputFile = NULL; - - if (!bIsSCCDisabled && bAutoSubmit) - { - ///////////////////////////////////////////////////////////////////// - // Submit the results to source control - ///////////////////////////////////////////////////////////////////// - UE_LOG(LogFixupRedirectsCommandlet, Display, TEXT("Submiting the results to source control")); - - // Work out the list of file to check in - TArray FilesToSubmit; - - for( int32 PackageIndex = 0; PackageIndex < PackageList.Num(); PackageIndex++ ) - { - const FString& Filename = PackageList[PackageIndex]; - - FString PackageName(SourceControlHelpers::PackageFilename(Filename)); - FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState(PackageName, EStateCacheUsage::ForceUpdate); - - if( SourceControlState.IsValid() && (SourceControlState->IsCheckedOut() || SourceControlState->IsAdded() || SourceControlState->IsDeleted()) ) - { - // Only submit engine packages if we're requested to - if( bUpdateEnginePackages || !Filename.StartsWith( FPaths::EngineDir() ) ) - { - FilesToSubmit.Add(*PackageName); - } - } - } - - // Check in all changed files, but don't actually create a changelist if there's nothing to submit. - if (FilesToSubmit.Num() > 0) - { - const FText Description = NSLOCTEXT("FixupRedirectsCmdlet", "ChangelistDescription", "Fixed up Redirects"); - TSharedRef CheckInOperation = ISourceControlOperation::Create(); - CheckInOperation->SetDescription(Description); - SourceControlProvider.Execute(CheckInOperation, FilesToSubmit); - } - - // toss the SCC manager - ISourceControlModule::Get().GetProvider().Close(); - } - return 0; -} diff --git a/Engine/Source/Editor/UnrealEd/Private/Commandlets/GenerateBlueprintAPICommandlet.cpp b/Engine/Source/Editor/UnrealEd/Private/Commandlets/GenerateBlueprintAPICommandlet.cpp index 93ca84857028..68a46637cf1e 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Commandlets/GenerateBlueprintAPICommandlet.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Commandlets/GenerateBlueprintAPICommandlet.cpp @@ -932,10 +932,19 @@ static void GenerateBlueprintAPIUtils::DumpActionMenuItem(uint32 Indent, FGraphA ActionEntry += "," + PinDetailsIndentedNewline + "\"DefaultValue\" : \"" + MakeJsonString(Pin->DefaultValue) + "\""; } - if (Pin->PinType.bIsArray) + if (Pin->PinType.IsArray()) { ActionEntry += "," + PinDetailsIndentedNewline + "\"IsArray\" : \"true\""; } + else if (Pin->PinType.IsSet()) + { + ActionEntry += "," + PinDetailsIndentedNewline + "\"IsSet\" : \"true\""; + } + else if (Pin->PinType.IsMap()) + { + ActionEntry += "," + PinDetailsIndentedNewline + "\"IsMap\" : \"true\""; + // TODO: Send the Map value type as well + } if (Pin->PinType.bIsConst) { diff --git a/Engine/Source/Editor/UnrealEd/Private/Commandlets/ImportAssetsCommandlet.cpp b/Engine/Source/Editor/UnrealEd/Private/Commandlets/ImportAssetsCommandlet.cpp index 3c870840bbd4..b8edd1c6d3ed 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Commandlets/ImportAssetsCommandlet.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Commandlets/ImportAssetsCommandlet.cpp @@ -191,7 +191,7 @@ bool UImportAssetsCommandlet::ImportAndSave(const TArray ImportedAssets = AssetToolsModule.Get().ImportAssetsAutomated(*ImportData); + TArray ImportedAssets = AssetToolsModule.Get().ImportAssetsAutomated(ImportData); if(ImportedAssets.Num() > 0) { TArray DirtyPackages; diff --git a/Engine/Source/Editor/UnrealEd/Private/Commandlets/PackageUtilities.cpp b/Engine/Source/Editor/UnrealEd/Private/Commandlets/PackageUtilities.cpp index 64b97fd17c18..c53b950629be 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Commandlets/PackageUtilities.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Commandlets/PackageUtilities.cpp @@ -38,6 +38,7 @@ #include "FileHelpers.h" #include "Animation/AnimCompress_BitwiseCompressOnly.h" +#include "Animation/AnimCompress_Automatic.h" #include "CollectionManagerTypes.h" @@ -211,10 +212,10 @@ bool NormalizePackageNames( TArray PackageNames, TArray& Packa if ( (PackageFilter&NORMALIZE_ResetExistingLoaders) != 0 ) { // reset the loaders for the packages we want to load so that we don't find the wrong version of the file - for ( int32 PackageIndex = 0; PackageIndex < PackageNames.Num(); PackageIndex++ ) + for ( int32 PackageIndex = 0; PackageIndex < PackagePathNames.Num(); PackageIndex++ ) { // (otherwise, attempting to run a commandlet on e.g. Engine.xxx will always return results for Engine.u instead) - const FString& PackageName = FPackageName::PackageFromPath(*PackageNames[PackageIndex]); + const FString& PackageName = PackagePathNames[PackageIndex]; UPackage* ExistingPackage = FindObject(NULL, *PackageName, true); if ( ExistingPackage != NULL ) { @@ -723,24 +724,27 @@ int32 ULoadPackageCommandlet::Main( const FString& Params ) UE_LOG(LogPackageUtilities, Warning, TEXT("Loading %s"), *Filename ); - const FString& PackageName = FPackageName::PackageFromPath(*Filename); - UPackage* Package = FindObject(NULL, *PackageName, true); - if ( Package != NULL && !bLoadAllPackages ) + FString PackageName; + if (FPackageName::TryConvertFilenameToLongPackageName(Filename, PackageName)) { - ResetLoaders(Package); + UPackage* Package = FindObject(nullptr, *PackageName, true); + if (Package != NULL && !bLoadAllPackages) + { + ResetLoaders(Package); + } } if (bCheckForLegacyPackages) { BeginLoad(); - auto Linker = GetPackageLinker(NULL,*Filename,LOAD_NoVerify,NULL,NULL); + auto Linker = GetPackageLinker(nullptr, *Filename,LOAD_NoVerify,NULL,NULL); EndLoad(); MinVersion = FMath::Min(MinVersion, Linker->Summary.GetFileVersionUE4()); } else { - Package = LoadPackage( NULL, *Filename, LOAD_None ); - if( Package == NULL ) + UPackage* Package = LoadPackage(nullptr, *Filename, LOAD_None ); + if(Package == nullptr) { UE_LOG(LogPackageUtilities, Error, TEXT("Error loading %s!"), *Filename ); } @@ -1496,11 +1500,14 @@ int32 UPkgInfoCommandlet::Main( const FString& Params ) { // reset the loaders for the packages we want to load so that we don't find the wrong version of the file // (otherwise, attempting to run pkginfo on e.g. Engine.xxx will always return results for Engine.u instead) - const FString& PackageName = FPackageName::PackageFromPath(*Filename); - UPackage* ExistingPackage = FindObject(NULL, *PackageName, true); - if ( ExistingPackage != NULL ) + FString PackageName; + if (FPackageName::TryConvertFilenameToLongPackageName(Filename, PackageName)) { - ResetLoaders(ExistingPackage); + UPackage* ExistingPackage = FindObject(nullptr, *PackageName, true); + if (ExistingPackage != nullptr) + { + ResetLoaders(ExistingPackage); + } } } @@ -1552,6 +1559,25 @@ struct CompressAnimationsFunctor template< typename OBJECTYPE > void DoIt( UCommandlet* Commandlet, UPackage* Package, TArray& Tokens, TArray& Switches ) { + // Count the number of animations to provide some limited progress indication + int32 NumAnimationsInPackage = 0; + for (TObjectIterator It; It; ++It) + { + OBJECTYPE* AnimSeq = *It; + if (!AnimSeq->IsIn(Package)) + { + continue; + } + + ++NumAnimationsInPackage; + } + + // Skip packages that contain no Animations. + if (NumAnimationsInPackage == 0) + { + return; + } + // @todoanim: we expect this won't work properly since it won't have any skeletalmesh, // but soon, the compression will changed based on skeleton. // when that happens, this doesn't have to worry about skeletalmesh not loaded @@ -1625,25 +1651,17 @@ struct CompressAnimationsFunctor // Get version number. Bump this up every time you want to recompress all animations. const int32 CompressCommandletVersion = UAnimationSettings::Get()->CompressCommandletVersion; - // Count the number of animations to provide some limited progress indication - int32 NumAnimationsInPackage = 0; - for (TObjectIterator It; It; ++It) - { - ++NumAnimationsInPackage; - } - - int32 ActiveAnimationIndex = 0; for (TObjectIterator It; It; ++It) { OBJECTYPE* AnimSeq = *It; - ++ActiveAnimationIndex; - if (!AnimSeq->IsIn(Package)) { continue; } + ++ActiveAnimationIndex; + // If animation hasn't been compressed, force it. bool bForceCompression = (AnimSeq->CompressedTrackOffsets.Num() == 0); @@ -1663,6 +1681,10 @@ struct CompressAnimationsFunctor USkeleton* Skeleton = AnimSeq->GetSkeleton(); check (Skeleton); + if (Skeleton->HasAnyFlags(RF_NeedLoad)) + { + Skeleton->GetLinker()->Preload(Skeleton); + } if( bAnalyze ) { @@ -2066,12 +2088,11 @@ struct CompressAnimationsFunctor } } #endif - int32 OldSize; - int32 NewSize; + SIZE_T OldSize; + SIZE_T NewSize; { - FArchiveCountMem CountBytesSize( AnimSeq ); - OldSize = CountBytesSize.GetNum(); + OldSize = AnimSeq->GetResourceSizeBytes(EResourceSizeMode::Inclusive); } // Clear bDoNotOverrideCompression flag @@ -2095,6 +2116,20 @@ struct CompressAnimationsFunctor // Force an update. AnimSeq->CompressCommandletVersion = 0; } + + // Do not perform automatic recompression on animations marked as 'bDoNotOverrideCompression' + // Unless they have no compression scheme, or they're using automatic compression. + if (AnimSeq->bDoNotOverrideCompression && (AnimSeq->CompressionScheme != nullptr) && !AnimSeq->CompressionScheme->IsA(UAnimCompress_Automatic::StaticClass())) + { + continue; + } + + // Set version since we've checked this animation for recompression. + if (AnimSeq->CompressCommandletVersion != CompressCommandletVersion) + { + AnimSeq->CompressCommandletVersion = CompressCommandletVersion; + bDirtyPackage = true; + } UE_LOG(LogPackageUtilities, Warning, TEXT("Compressing animation '%s' [#%d / %d in package '%s']"), *AnimSeq->GetName(), @@ -2102,22 +2137,16 @@ struct CompressAnimationsFunctor NumAnimationsInPackage, *PackageFileName); - // @todoanim: expect this won't work - AnimSeq->RequestAnimCompression(false, true, false); + UAnimCompress* CompressionAlgorithm = NewObject(); + AnimSeq->CompressionScheme = static_cast(StaticDuplicateObject(CompressionAlgorithm, AnimSeq)); + AnimSeq->RequestAnimCompression(false, false, false); { - FArchiveCountMem CountBytesSize( AnimSeq ); - NewSize = CountBytesSize.GetNum(); - } - - // Set version since we've checked this animation for recompression. - if( AnimSeq->CompressCommandletVersion != CompressCommandletVersion ) - { - AnimSeq->CompressCommandletVersion = CompressCommandletVersion; - bDirtyPackage = true; + NewSize = AnimSeq->GetResourceSizeBytes(EResourceSizeMode::Inclusive); } // Only save package if size has changed. - bDirtyPackage = (bDirtyPackage || bForceCompression || (OldSize != NewSize)); + const int64 DeltaSize = NewSize - OldSize; + bDirtyPackage = (bDirtyPackage || bForceCompression || (DeltaSize != 0)); // if Dirty, then we need to be able to write to this package. // If we can't, abort, don't want to waste time!! @@ -2169,7 +2198,7 @@ struct CompressAnimationsFunctor // End of recompression // Does package need to be saved? - bDirtyPackage = bDirtyPackage || Package->IsDirty(); +/* bDirtyPackage = bDirtyPackage || Package->IsDirty();*/ // If we need to save package, do so. if( bDirtyPackage && !bAnalyze ) @@ -2239,27 +2268,6 @@ int32 UCompressAnimationsCommandlet::Main( const FString& Params ) } else { - // First scan all Skeletal Meshes - UE_LOG(LogPackageUtilities, Warning, TEXT("Scanning for all SkeletalMeshes...")); - - // If we have SKIPREADONLY, then override this, as we need to scan all packages for skeletal meshes. - FString SearchAllMeshesParams = ParamsUpperCase; - SearchAllMeshesParams += FString(TEXT(" -OVERRIDEREADONLY")); - SearchAllMeshesParams += FString(TEXT(" -OVERRIDELOADMAPS")); - // Prevent recompression here, we'll do it after we gathered all skeletal meshes - GDisableAnimationRecompression = true; - DoActionToAllPackages(this, SearchAllMeshesParams); - GDisableAnimationRecompression = false; - - int32 Count = 0; - for( TObjectIterator It; It; ++It ) - { - USkeletalMesh* SkelMesh = *It; - UE_LOG(LogPackageUtilities, Warning, TEXT("[%i] %s"), Count, *SkelMesh->GetFName().ToString()); - Count++; - } - UE_LOG(LogPackageUtilities, Warning, TEXT("%i SkeletalMeshes found!"), Count); - // Then do the animation recompression UE_LOG(LogPackageUtilities, Warning, TEXT("Recompressing all animations...")); DoActionToAllPackages(this, ParamsUpperCase); diff --git a/Engine/Source/Editor/UnrealEd/Private/CookOnTheFlyServer.cpp b/Engine/Source/Editor/UnrealEd/Private/CookOnTheFlyServer.cpp index 4dd459e63006..874d4b9f75c2 100644 --- a/Engine/Source/Editor/UnrealEd/Private/CookOnTheFlyServer.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/CookOnTheFlyServer.cpp @@ -101,6 +101,8 @@ DEFINE_LOG_CATEGORY_STATIC(LogCook, Log, All); #define DEBUG_COOKONTHEFLY 0 #define OUTPUT_TIMING 1 +#define PROFILE_NETWORK 0 + #if OUTPUT_TIMING #include "ProfilingDebugging/ScopedTimers.h" @@ -419,7 +421,10 @@ void OutputHierarchyTimers() } UE_LOG(LogCook, Display, TEXT("%s"), *Output); +} +void ClearHierarchyTimers() +{ RootTimerInfo.ClearChildren(); } #endif @@ -442,7 +447,7 @@ void OutputHierarchyTimers() #define OUTPUT_TIMERS() OutputTimers(); #define OUTPUT_HIERARCHYTIMERS() OutputHierarchyTimers(); - +#define CLEAR_HIERARCHYTIMERS() ClearHierarchyTimers(); #else #define CREATE_TIMER(name) @@ -457,6 +462,16 @@ void OutputHierarchyTimers() #define OUTPUT_TIMERS() #define OUTPUT_HIERARCHYTIMERS() +#define CLEAR_HIERARCHYTIMERS() +#endif + + +#if PROFILE_NETWORK +double TimeTillRequestStarted = 0.0; +double TimeTillRequestForfilled = 0.0; +double TimeTillRequestForfilledError = 0.0; +double WaitForAsyncFilesWrites = 0.0; +FEvent *NetworkRequestEvent = nullptr; #endif #if ENABLE_COOK_STATS @@ -539,7 +554,7 @@ DECLARE_CYCLE_STAT(TEXT("Tick cooking"), STAT_TickCooker, STATGROUP_Cooking); struct FRecompileRequest { struct FShaderRecompileData RecompileData; - bool bComplete; + volatile bool bComplete; }; @@ -585,6 +600,32 @@ public: } }; +class FAdditionalPackageSearchVisitor: public IPlatformFile::FDirectoryVisitor +{ + TSet& FoundMapFilesNoExt; + TArray& FoundOtherFiles; +public: + FAdditionalPackageSearchVisitor(TSet& InFoundMapFiles, TArray& InFoundOtherFiles) + : FoundMapFilesNoExt(InFoundMapFiles), FoundOtherFiles(InFoundOtherFiles) + {} + virtual bool Visit(const TCHAR* FilenameOrDirectory, bool bIsDirectory) + { + if (bIsDirectory == false) + { + FString Filename(FilenameOrDirectory); + if (Filename.EndsWith(TEXT(".uasset")) || Filename.EndsWith(TEXT(".umap"))) + { + FoundMapFilesNoExt.Add(FPaths::SetExtension(Filename, "")); + } + else if ( Filename.EndsWith(TEXT(".uexp")) || Filename.EndsWith(TEXT(".ubulk")) ) + { + FoundOtherFiles.Add(Filename); + } + } + return true; + } +}; + const FString& GetAssetRegistryPath() { static const FString AssetRegistryPath = FPaths::GameDir(); @@ -619,6 +660,12 @@ const FString& GetAssetRegistryFilename() return AssetRegistryFilename; } +const FString& GetDevelopmentAssetRegistryFilename() +{ + static const FString DevelopmentAssetRegistryFilename = FString(TEXT("DevelopmentAssetRegistry.bin")); + return DevelopmentAssetRegistryFilename; +} + /** * Uses the FMessageLog to log a message * @@ -681,16 +728,20 @@ FName UCookOnTheFlyServer::GetCachedStandardPackageFileFName( const UPackage* Pa bool UCookOnTheFlyServer::ClearPackageFilenameCacheForPackage( const FName& PackageName ) const { + check(IsInGameThread()); return PackageFilenameCache.Remove( PackageName ) >= 1; } bool UCookOnTheFlyServer::ClearPackageFilenameCacheForPackage( const UPackage* Package ) const { + check(IsInGameThread()); return PackageFilenameCache.Remove( Package->GetFName() ) >= 1; } const FString& UCookOnTheFlyServer::GetCachedSandboxFilename( const UPackage* Package, TUniquePtr& InSandboxFile ) const { + check(IsInGameThread()); + FName PackageFName = Package->GetFName(); static TMap CachedSandboxFilenames; FString* CachedSandboxFilename = CachedSandboxFilenames.Find(PackageFName); @@ -705,6 +756,7 @@ const FString& UCookOnTheFlyServer::GetCachedSandboxFilename( const UPackage* Pa const UCookOnTheFlyServer::FCachedPackageFilename& UCookOnTheFlyServer::Cache(const FName& PackageName) const { + check( IsInGameThread() ); FCachedPackageFilename *Cached = PackageFilenameCache.Find( PackageName ); if ( Cached != NULL ) { @@ -731,6 +783,7 @@ const UCookOnTheFlyServer::FCachedPackageFilename& UCookOnTheFlyServer::Cache(co const FName* UCookOnTheFlyServer::GetCachedPackageFilenameToPackageFName(const FName& StandardPackageFilename) const { + check(IsInGameThread()); const FName* Result = PackageFilenameToPackageFNameCache.Find(StandardPackageFilename); if ( Result ) { @@ -752,6 +805,7 @@ const FName* UCookOnTheFlyServer::GetCachedPackageFilenameToPackageFName(const F void UCookOnTheFlyServer::ClearPackageFilenameCache() const { + check(IsInGameThread()); PackageFilenameCache.Empty(); PackageFilenameToPackageFNameCache.Empty(); } @@ -812,6 +866,17 @@ void UCookOnTheFlyServer::Tick(float DeltaTime) } } + /* + // this is still being worked on + if ( IsCookOnTheFlyMode() ) + { + if ( !CookRequests.HasItems() ) + { + OpportunisticSaveInMemoryPackages(); + } + } + */ + uint32 CookedPackagesCount = 0; const static float CookOnTheSideTimeSlice = 0.1f; // seconds TickCookOnTheSide( CookOnTheSideTimeSlice, CookedPackagesCount); @@ -828,50 +893,103 @@ TStatId UCookOnTheFlyServer::GetStatId() const RETURN_QUICK_DECLARE_CYCLE_STAT(UCookServer, STATGROUP_Tickables); } +const TArray& UCookOnTheFlyServer::GetCookingTargetPlatforms() const +{ + ITargetPlatformManagerModule& TPM = GetTargetPlatformManagerRef(); + + FString PlatformStr; + if ( FParse::Value(FCommandLine::Get(), TEXT("TARGETPLATFORM="), PlatformStr) == false ) + { + FString ValueName = TEXT("DefaultTargetPlatform"); + + if ( IsCookingInEditor() ) + { + ValueName += TEXT("Editor"); + } + if ( IsCookOnTheFlyMode() ) + { + ValueName += TEXT("OnTheFly"); + } + + + TArray TargetPlatformNames; + // see if we have specified in an ini file which target platforms we should use + if ( GConfig->GetArray(TEXT("CookSettings"), *ValueName, TargetPlatformNames, GEditorIni) ) + { + for ( const FString& TargetPlatformName : TargetPlatformNames ) + { + ITargetPlatform* TargetPlatform = TPM.FindTargetPlatform(TargetPlatformName); + + if ( TargetPlatform ) + { + CookingTargetPlatforms.AddUnique(TargetPlatform); + } + else + { + UE_LOG(LogCook, Warning, TEXT("Unable to resolve targetplatform name %s"), *TargetPlatformName ); + } + } + } + } + + + if ( CookingTargetPlatforms.Num() == 0 ) + { + const TArray& Platforms = TPM.GetCookingTargetPlatforms(); + + CookingTargetPlatforms = Platforms; + } + + return CookingTargetPlatforms; +} + bool UCookOnTheFlyServer::StartNetworkFileServer( const bool BindAnyPort ) { check( IsCookOnTheFlyMode() ); //GetDerivedDataCacheRef().WaitForQuiescence(false); +#if PROFILE_NETWORK + NetworkRequestEvent = FPlatformProcess::GetSynchEventFromPool(); +#endif ValidateCookOnTheFlySettings(); - ITargetPlatformManagerModule& TPM = GetTargetPlatformManagerRef(); - const TArray& Platforms = TPM.GetCookingTargetPlatforms(); - - GenerateAssetRegistry(); InitializeSandbox(); - + const TArray& Platforms = GetCookingTargetPlatforms(); + + // When cooking on the fly the full registry is saved at the beginning + // in cook by the book asset registry is saved after the cook is finished + for (int32 Index = 0; Index < Platforms.Num(); Index++) { - // When cooking on the fly the full registry is saved at the beginning - // in cook by the book asset registry is saved after the cook is finished - - // write it out to a memory archive - FArrayWriter SerializedAssetRegistry; - SerializedAssetRegistry.SetFilterEditorOnly(true); - AssetRegistry->Serialize(SerializedAssetRegistry); - UE_LOG(LogCook, Display, TEXT("Generated asset registry size is %5.2fkb"), (float)SerializedAssetRegistry.Num() / 1024.f); - - // now save it in each cooked directory - FString RegistryFilename = FPaths::GameDir() / GetAssetRegistryFilename(); - // Use SandboxFile to do path conversion to properly handle sandbox paths (outside of standard paths in particular). - FString SandboxFilename = ConvertToFullSandboxPath(*RegistryFilename, true); - - for (int32 Index = 0; Index < Platforms.Num(); Index++) + FAssetRegistryGenerator* Generator = RegistryGenerators.FindRef(FName(*Platforms[Index]->PlatformName())); + if (Generator) { - FString PlatFilename = SandboxFilename.Replace(TEXT("[Platform]"), *Platforms[Index]->PlatformName()); - FFileHelper::SaveArrayToFile(SerializedAssetRegistry, *PlatFilename); + Generator->SaveAssetRegistry(GetSandboxAssetRegistryFilename(), false); } } // start the listening thread + FNewConnectionDelegate NewConnectionDelegate(FNewConnectionDelegate::CreateUObject(this, &UCookOnTheFlyServer::HandleNetworkFileServerNewConnection)); FFileRequestDelegate FileRequestDelegate(FFileRequestDelegate::CreateUObject(this, &UCookOnTheFlyServer::HandleNetworkFileServerFileRequest)); FRecompileShadersDelegate RecompileShadersDelegate(FRecompileShadersDelegate::CreateUObject(this, &UCookOnTheFlyServer::HandleNetworkFileServerRecompileShaders)); + FSandboxPathDelegate SandboxPathDelegate(FSandboxPathDelegate::CreateUObject(this, &UCookOnTheFlyServer::HandleNetworkGetSandboxPath)); + FInitialPrecookedListDelegate InitialPrecookedListDelegate(FInitialPrecookedListDelegate::CreateUObject(this, &UCookOnTheFlyServer::HandleNetworkGetPrecookedList)); + + + FNetworkFileDelegateContainer NetworkFileDelegateContainer; + NetworkFileDelegateContainer.NewConnectionDelegate = NewConnectionDelegate; + NetworkFileDelegateContainer.InitialPrecookedListDelegate = InitialPrecookedListDelegate; + NetworkFileDelegateContainer.FileRequestDelegate = FileRequestDelegate; + NetworkFileDelegateContainer.RecompileShadersDelegate = RecompileShadersDelegate; + NetworkFileDelegateContainer.SandboxPathOverrideDelegate = SandboxPathDelegate; + + NetworkFileDelegateContainer.OnFileModifiedCallback = &FileModifiedDelegate; + INetworkFileServer *TcpFileServer = FModuleManager::LoadModuleChecked("NetworkFileSystem") - .CreateNetworkFileServer(true, BindAnyPort ? 0 : -1, &FileRequestDelegate, &RecompileShadersDelegate, ENetworkFileServerProtocol::NFSP_Tcp); + .CreateNetworkFileServer(true, BindAnyPort ? 0 : -1, NetworkFileDelegateContainer, ENetworkFileServerProtocol::NFSP_Tcp); if ( TcpFileServer ) { NetworkFileServers.Add(TcpFileServer); @@ -880,7 +998,7 @@ bool UCookOnTheFlyServer::StartNetworkFileServer( const bool BindAnyPort ) // cookonthefly server for html5 -- NOTE: if this is crashing COTF servers, please ask for Nick.Shin (via Josh.Adams) #if 1 INetworkFileServer *HttpFileServer = FModuleManager::LoadModuleChecked("NetworkFileSystem") - .CreateNetworkFileServer(true, BindAnyPort ? 0 : -1, &FileRequestDelegate, &RecompileShadersDelegate, ENetworkFileServerProtocol::NFSP_Http); + .CreateNetworkFileServer(true, BindAnyPort ? 0 : -1, NetworkFileDelegateContainer, ENetworkFileServerProtocol::NFSP_Http); if ( HttpFileServer ) { NetworkFileServers.Add( HttpFileServer ); @@ -1345,7 +1463,7 @@ void UCookOnTheFlyServer::PreGarbageCollect() PackageReentryData.Empty(); } -UCookOnTheFlyServer::FReentryData& UCookOnTheFlyServer::GetReentryData(const UPackage* Package) +UCookOnTheFlyServer::FReentryData& UCookOnTheFlyServer::GetReentryData(const UPackage* Package) const { FReentryData& CurrentReentryData = PackageReentryData.FindOrAdd(Package->GetFName()); @@ -1368,7 +1486,7 @@ uint32 UCookOnTheFlyServer::TickCookOnTheSide( const float TimeSlice, uint32 &Co if (IsChildCooker() == false) { - if (AssetRegistry->IsLoadingAssets()) + if (AssetRegistry == nullptr || AssetRegistry->IsLoadingAssets()) { // early out return Result; @@ -1418,7 +1536,7 @@ uint32 UCookOnTheFlyServer::TickCookOnTheSide( const float TimeSlice, uint32 &Co } FFilePlatformRequest ToBuild; - + //bool bIsUnsolicitedRequest = false; if ( CookRequests.HasItems() ) { @@ -1430,6 +1548,13 @@ uint32 UCookOnTheFlyServer::TickCookOnTheSide( const float TimeSlice, uint32 &Co break; } +#if PROFILE_NETWORK + if (NetworkRequestEvent) + { + NetworkRequestEvent->Trigger(); + } +#endif + // prevent autosave from happening until we are finished cooking // causes really bad hitches if ( GUnrealEd ) @@ -1473,9 +1598,6 @@ uint32 UCookOnTheFlyServer::TickCookOnTheSide( const float TimeSlice, uint32 &Co } } - bool bWasUpToDate = false; - - const FString BuildFilename = ToBuild.GetFilename().ToString(); // if we have no target platforms then we want to cook because this will cook for all target platforms in that case @@ -1494,7 +1616,7 @@ uint32 UCookOnTheFlyServer::TickCookOnTheSide( const float TimeSlice, uint32 &Co FString DLCPath = GetDLCContentPath(); if ( ToBuild.GetFilename().ToString().StartsWith(DLCPath) == false ) // if we don't start with the dlc path then we shouldn't be cooking this data { - UE_LOG(LogCook, Error, TEXT("Engine content %s is being referenced by DLC!"), *ToBuild.GetFilename().ToString() ); + UE_LOG(LogCook, Error, TEXT("Engine or Game content %s is being referenced by DLC!"), *ToBuild.GetFilename().ToString() ); bShouldCook = false; } } @@ -1511,77 +1633,30 @@ uint32 UCookOnTheFlyServer::TickCookOnTheSide( const float TimeSlice, uint32 &Co if ( bShouldCook ) // if we should cook the package then cook it otherwise add it to the list of already cooked packages below { - COOK_STAT(FScopedDurationTimer LoadPackagesTimer(DetailedCookStats::TickCookOnTheSideLoadPackagesTimeSec)); - UPackage *Package = NULL; - { - FString PackageName; - if ( FPackageName::TryConvertFilenameToLongPackageName(BuildFilename, PackageName) ) - { - Package = FindObject( ANY_PACKAGE, *PackageName ); - } - } + UPackage* Package = LoadPackageForCooking(BuildFilename); -#if DEBUG_COOKONTHEFLY - UE_LOG( LogCook, Display, TEXT("Processing request %s"), *BuildFilename); -#endif - static TSet CookWarningsList; - if ( CookWarningsList.Contains(BuildFilename) == false ) + if ( Package ) { - CookWarningsList.Add( BuildFilename ); - GOutputCookingWarnings = IsCookFlagSet(ECookInitializationFlags::OutputVerboseCookerWarnings); - } - - // if the package is already loaded then try to avoid reloading it :) - if ( ( Package == NULL ) || ( Package->IsFullyLoaded() == false ) ) - { - GIsCookerLoadingPackage = true; - SCOPE_TIMER(LoadPackage); - Package = LoadPackage( NULL, *BuildFilename, LOAD_None ); - INC_INT_STAT(LoadPackage, 1); - - GIsCookerLoadingPackage = false; - } -#if DEBUG_COOKONTHEFLY - else - { - UE_LOG(LogCook, Display, TEXT("Package already loaded %s avoiding reload"), *BuildFilename ); - } -#endif - - if (Package == NULL) - { - if ((!IsCookOnTheFlyMode()) || (!IsCookingInEditor())) - { - LogCookerMessage(FString::Printf(TEXT("Error loading %s!"), *BuildFilename), EMessageSeverity::Error); - UE_LOG(LogCook, Error, TEXT("Error loading %s!"), *BuildFilename); - } - Result |= COSR_ErrorLoadingPackage; - } - else - { - check(Package); - FString Name = Package->GetPathName(); - FString PackageFilename( GetCachedStandardPackageFilename( Package ) ); - if ( PackageFilename != BuildFilename ) + FString PackageFilename(GetCachedStandardPackageFilename(Package)); + if (PackageFilename != BuildFilename) { // we have saved something which we didn't mean to load // sounds unpossible.... but it is due to searching for files and such // mark the original request as processed (if this isn't actually the file they were requesting then it will fail) // and then also save our new request as processed so we don't do it again - PackagesToSave.AddUnique( Package ); - UE_LOG( LogCook, Verbose, TEXT("Request for %s received going to save %s"), *BuildFilename, *PackageFilename ); + UE_LOG(LogCook, Verbose, TEXT("Request for %s received going to save %s"), *BuildFilename, *PackageFilename); - CookedPackages.Add( FFilePlatformCookedPackage(ToBuild.GetFilename(), TargetPlatformNames) ); - - ToBuild.SetFilename( PackageFilename ); - } - else - { - PackagesToSave.AddUnique( Package ); + CookedPackages.Add(FFilePlatformCookedPackage(ToBuild.GetFilename(), TargetPlatformNames)); + + ToBuild.SetFilename(PackageFilename); } + PackagesToSave.AddUnique(Package); + } + else + { + Result |= COSR_ErrorLoadingPackage; } - GOutputCookingWarnings = false; } @@ -1624,123 +1699,6 @@ uint32 UCookOnTheFlyServer::TickCookOnTheSide( const float TimeSlice, uint32 &Co } - auto BeginPackageCacheForCookedPlatformData = [&]( UPackage* Package ) - { - COOK_STAT(FScopedDurationTimer DurationTimer(DetailedCookStats::TickCookOnTheSideBeginPackageCacheForCookedPlatformDataTimeSec)); - -#if DEBUG_COOKONTHEFLY - UE_LOG(LogCook, Display, TEXT("Caching objects for package %s"), *Package->GetFName().ToString()); -#endif - MakePackageFullyLoaded(Package); - FReentryData& CurrentReentryData = GetReentryData(Package); - - if (CurrentReentryData.bIsValid == false) - return true; - - if ( CurrentReentryData.bBeginCacheFinished ) - return true; - - for (; CurrentReentryData.BeginCacheCount < CurrentReentryData.CachedObjectsInOuter.Num(); ++CurrentReentryData.BeginCacheCount) - { - UObject* Obj = CurrentReentryData.CachedObjectsInOuter[CurrentReentryData.BeginCacheCount]; - for ( const ITargetPlatform* TargetPlatform : TargetPlatforms ) - { - if ( Obj->IsA(UMaterialInterface::StaticClass() ) ) - { - if ( GShaderCompilingManager->GetNumRemainingJobs() > MaxConcurrentShaderJobs ) - { -#if DEBUG_COOKONTHEFLY - UE_LOG(LogCook, Display, TEXT("Delaying shader compilation of material %s"), *Obj->GetFullName()); -#endif - return false; - } - } - Obj->BeginCacheForCookedPlatformData(TargetPlatform); - } - - if ( Timer.IsTimeUp() ) - { -#if DEBUG_COOKONTHEFLY - UE_LOG(LogCook, Display, TEXT("Object %s took too long to cache"), *Obj->GetFullName()); -#endif - return false; - } - } - - CurrentReentryData.bBeginCacheFinished = true; - return true; - }; - - auto FinishPackageCacheForCookedPlatformData = [&]( UPackage* Package ) - { - COOK_STAT(FScopedDurationTimer DurationTimer(DetailedCookStats::TickCookOnTheSideFinishPackageCacheForCookedPlatformDataTimeSec)); - - MakePackageFullyLoaded(Package); - FReentryData& CurrentReentryData = GetReentryData(Package); - - if ( CurrentReentryData.bIsValid == false ) - return true; - - if ( CurrentReentryData.bFinishedCacheFinished ) - return true; - - for (UObject* Obj : CurrentReentryData.CachedObjectsInOuter) - { - for (const ITargetPlatform* TargetPlatform : TargetPlatforms) - { - COOK_STAT(double CookerStatSavedValue = DetailedCookStats::TickCookOnTheSideBeginPackageCacheForCookedPlatformDataTimeSec); - - if (Obj->IsA(UMaterialInterface::StaticClass())) - { - if ( Obj->IsCachedCookedPlatformDataLoaded(TargetPlatform) == false ) - { - if (GShaderCompilingManager->GetNumRemainingJobs() > MaxConcurrentShaderJobs) - { - return false; - } - } - } - - // These begin cache calls should be quick - // because they will just be checking that the data is already cached and kicking off new multithreaded requests if not - // all sync requests should have been caught in the first begincache call above - Obj->BeginCacheForCookedPlatformData(TargetPlatform); - // We want to measure inclusive time for this function, but not accumulate into the BeginXXX timer, so subtract these times out of the BeginTimer. - COOK_STAT(DetailedCookStats::TickCookOnTheSideBeginPackageCacheForCookedPlatformDataTimeSec = CookerStatSavedValue); - if (Obj->IsCachedCookedPlatformDataLoaded(TargetPlatform) == false) - { -#if DEBUG_COOKONTHEFLY - UE_LOG(LogCook, Display, TEXT("Object %s isn't cached yet"), *Obj->GetFullName()); -#endif - /*if ( Obj->IsA(UMaterial::StaticClass()) ) - { - if (GShaderCompilingManager->HasShaderJobs() == false) - { - UE_LOG(LogCook, Warning, TEXT("Shader compiler is in a bad state! Shader %s is finished compile but shader compiling manager did not notify shader. "), *Obj->GetPathName()); - } - }*/ - return false; - } - } - } - - for (UObject* Obj: CurrentReentryData.CachedObjectsInOuter) - { - // if this objects data is cached then we can call FinishedCookedPLatformDataCache - // we can only safely call this when we are finished caching this object completely. - // this doesn't ever happen for cook in editor or cook on the fly mode - if (CurrentCookMode == ECookMode::CookByTheBook) - { - check( !IsCookingInEditor() ); - // this might be run multiple times for a single object - Obj->WillNeverCacheCookedPlatformDataAgain(); - } - } - - CurrentReentryData.bFinishedCacheFinished = true; - return true; - }; - GShaderCompilingManager->ProcessAsyncResults(true, false); @@ -1749,10 +1707,10 @@ uint32 UCookOnTheFlyServer::TickCookOnTheSide( const float TimeSlice, uint32 &Co SCOPE_TIMER(CallBeginCacheForCookedPlatformData); // cache the resources for this package for each platform - bIsAllDataCached &= BeginPackageCacheForCookedPlatformData(PackagesToSave[0]); + bIsAllDataCached &= BeginPackageCacheForCookedPlatformData(PackagesToSave[0], TargetPlatforms, Timer); if( bIsAllDataCached ) { - bIsAllDataCached &= FinishPackageCacheForCookedPlatformData(PackagesToSave[0]); + bIsAllDataCached &= FinishPackageCacheForCookedPlatformData(PackagesToSave[0], TargetPlatforms, Timer); } } @@ -1797,375 +1755,33 @@ uint32 UCookOnTheFlyServer::TickCookOnTheSide( const float TimeSlice, uint32 &Co int32 FirstUnsolicitedPackage = PackagesToSave.Num(); - // generate a list of other packages which were loaded with this one - if ( !IsCookByTheBookMode() || (CookByTheBookOptions->bDisableUnsolicitedPackages == false)) + UE_LOG(LogCook, Verbose, TEXT("Finding unsolicited packages for package %s"), *ToBuild.GetFilename().ToString()); + bool ContainsFullAssetGCClasses = false; + GetAllUnsolicitedPackages(PackagesToSave, AllTargetPlatformNames, ContainsFullAssetGCClasses); + if (ContainsFullAssetGCClasses) { - { - SCOPE_TIMER(PostLoadPackageFixup); - for (TObjectIterator It; It; ++It ) - { - PostLoadPackageFixup(*It); - } - } - //GRedirectCollector.ResolveStringAssetReference(); - SCOPE_TIMER(UnsolicitedMarkup); - bool ContainsFullAssetGCClasses = false; - UE_LOG(LogCook, Verbose, TEXT("Finding unsolicited packages for package %s"), *ToBuild.GetFilename().ToString() ); - GetUnsolicitedPackages(PackagesToSave, ContainsFullAssetGCClasses, AllTargetPlatformNames); - if (ContainsFullAssetGCClasses) - { - Result |= COSR_RequiresGC; - } + Result |= COSR_RequiresGC; } - // if ( IsRealtimeMode() ) + + // in cook by the book bail out early because shaders and compiled for the primary package we are trying to save. + // note in this case we also put the package at the end of the queue that queue might be reordered if we do partial gc + if ((bIsAllDataCached == false) && IsCookByTheBookMode() && !IsRealtimeMode()) { - if ((bIsAllDataCached == false) && IsCookByTheBookMode() && !IsRealtimeMode()) + // don't load anymore stuff unless we have space and we don't already have enough stuff to save + if ((!(Result & COSR_RequiresGC)) && + (HasExceededMaxMemory() == false) && + ((Timer.NumPackagesSaved + PackagesToSave.Num()) < Timer.MaxNumPackagesToSave)) // if we don't need to GC and also we have memory then load some more packages ;) { - // don't load anymore stuff unless we have space and we don't already have enough stuff to save - if ((!(Result & COSR_RequiresGC)) && - (HasExceededMaxMemory()==false) && - ((Timer.NumPackagesSaved + PackagesToSave.Num()) < Timer.MaxNumPackagesToSave)) // if we don't need to GC and also we have memory then load some more packages ;) - { - GShaderCompilingManager->ProcessAsyncResults(true, false); // we can afford to do work here because we are essentually requing this package for processing later - Timer.SavedPackage(); // this is a special case to prevent infinite loop, if we only have one package we might fall through this and could loop forever. - CookRequests.EnqueueUnique(ToBuild, false); - continue; - } - else - { - //was gonna quit but didn't - // UE_LOG(LogCook, Display, TEXT("Was gonna exit out but didn't num packages to save %d"), PackagesToSave.Num()); - - // reque the current task and process it next tick - /* - CookRequests.EnqueueUnique(ToBuild, true); - Result |= COSR_WaitingOnCache; - break; // break out of the package tick loop - */ - } + GShaderCompilingManager->ProcessAsyncResults(true, false); // we can afford to do work here because we are essentually requing this package for processing later + Timer.SavedPackage(); // this is a special case to prevent infinite loop, if we only have one package we might fall through this and could loop forever. + CookRequests.EnqueueUnique(ToBuild, false); + continue; } } - bool bFinishedSave = true; - - if ( PackagesToSave.Num() ) - { - int32 OriginalPackagesToSaveCount = PackagesToSave.Num(); - SCOPE_TIMER(SavingPackages); - for ( int32 I = 0; I < PackagesToSave.Num(); ++I ) - { - UPackage* Package = PackagesToSave[I]; - if (Package->IsLoadedByEditorPropertiesOnly() && UncookedEditorOnlyPackages.Contains(Package->GetFName())) - { - // We already attempted to cook this package and it's still not referenced by any non editor-only properties. - continue; - } - - // This package is valid, so make sure it wasn't previously marked as being an uncooked editor only package or it would get removed from the - // asset registry at the end of the cook - UncookedEditorOnlyPackages.Remove(Package->GetFName()); - - const FName StandardPackageFilename = GetCachedStandardPackageFileFName(Package); - check(IsInGameThread()); - if (NeverCookPackageList.Contains(StandardPackageFilename)) - { - // refuse to save this package, it's clearly one of the undesirables - continue; - } - - - FName PackageFName = GetCachedStandardPackageFileFName(Package); - TArray SaveTargetPlatformNames = AllTargetPlatformNames; - TArray CookedTargetPlatforms; - if (CookedPackages.GetCookedPlatforms(PackageFName, CookedTargetPlatforms)) - { - for (const FName& CookedPlatform : CookedTargetPlatforms) - { - SaveTargetPlatformNames.Remove(CookedPlatform); - } - } - - // we somehow already cooked this package not sure how that can happen because the PackagesToSave list should have already filtered this - if (SaveTargetPlatformNames.Num() == 0) - { - UE_LOG(LogCook, Warning, TEXT("Allready saved this package not sure how this got here!")); - // already saved this package - continue; - } - - - // if we are processing unsolicited packages we can optionally not save these right now - // the unsolicited packages which we missed now will be picked up on next run - // we want to do this in cook on the fly also, if there is a new network package request instead of saving unsolicited packages we can process the requested package - - bool bShouldFinishTick = false; - - if (IsCookByTheBookMode() && Timer.IsTimeUp()) - { - bShouldFinishTick = true; - // our timeslice is up - } - - // if we are cook the fly then save the package which was requested as fast as we can because the client is waiting on it - - bool ProcessingUnsolicitedPackages = (I >= FirstUnsolicitedPackage); - bool ForceSavePackage = false; - - if ( IsCookOnTheFlyMode() ) - { - if (ProcessingUnsolicitedPackages) - { - SCOPE_TIMER(WaitingForCachedCookedPlatformData); - if ( CookRequests.HasItems() ) - { - bShouldFinishTick = true; - } - if (Timer.IsTimeUp()) - { - bShouldFinishTick = true; - // our timeslice is up - } - bool bFinishedCachingCookedPlatformData = false; - // if we are in realtime mode then don't wait forever for the package to be ready - while ( (!Timer.IsTimeUp()) && IsRealtimeMode() && (bShouldFinishTick == false) ) - { - if ( FinishPackageCacheForCookedPlatformData(Package) == true ) - { - bFinishedCachingCookedPlatformData = true; - break; - } - - GShaderCompilingManager->ProcessAsyncResults(true, false); - // sleep for a bit - FPlatformProcess::Sleep(0.0f); - } - bShouldFinishTick |= !bFinishedCachingCookedPlatformData; - } - else - { - ForceSavePackage = true; - } - } - - bool AllObjectsCookedDataCached = true; - bool HasCheckedAllPackagesAreCached = (I >= OriginalPackagesToSaveCount); - - MakePackageFullyLoaded(Package); - - if ( !bShouldFinishTick ) - { - AllObjectsCookedDataCached = FinishPackageCacheForCookedPlatformData(Package); - if ( AllObjectsCookedDataCached == false) - { - GShaderCompilingManager->ProcessAsyncResults(true, false); - AllObjectsCookedDataCached = FinishPackageCacheForCookedPlatformData(Package); - } - } - - // if we are in realtime mode and this package isn't ready to be saved then we should exit the tick here so we don't save it while in launch on - if ( IsRealtimeMode() && - (!IsCookOnTheFlyMode() || ProcessingUnsolicitedPackages) && // if we are in cook ont eh fly mode, EVEN if we are realtime we should force save if this is not an unsolicited package - (AllObjectsCookedDataCached == false) && - HasCheckedAllPackagesAreCached ) - { - bShouldFinishTick = true; - } - - if (bShouldFinishTick && (!ForceSavePackage)) - { - SCOPE_TIMER(EnqueueUnsavedPackages); - // enqueue all the packages which we were about to save - Timer.SavedPackage(); // this is a special case to prevent infinite loop, if we only have one package we might fall through this and could loop forever. - if (IsCookByTheBookMode()) - { - for (int32 RemainingIndex = I; RemainingIndex < PackagesToSave.Num(); ++RemainingIndex) - { - FName StandardFilename = GetCachedStandardPackageFileFName(PackagesToSave[RemainingIndex]); - CookRequests.EnqueueUnique(FFilePlatformRequest(StandardFilename, AllTargetPlatformNames)); - } - } - else - { - check(ProcessingUnsolicitedPackages == true); - } - Result |= COSR_WaitingOnCache; - - // break out of the loop - bFinishedSave = false; - break; - } - - - // don't precache other packages if our package isn't ready but we are going to save it. This will fill up the worker threads with extra shaders which we may need to flush on - if ( (!IsCookOnTheFlyMode()) && - (!IsRealtimeMode() || AllObjectsCookedDataCached == true) ) - { - // precache platform data for next package - UPackage *NextPackage = PackagesToSave[FMath::Min(PackagesToSave.Num() - 1, I + 1)]; - UPackage *NextNextPackage = PackagesToSave[FMath::Min(PackagesToSave.Num() - 1, I + 2)]; - if (NextPackage != Package) - { - SCOPE_TIMER(PrecachePlatformDataForNextPackage); - BeginPackageCacheForCookedPlatformData(NextPackage); - } - if (NextNextPackage != NextPackage) - { - SCOPE_TIMER(PrecachePlatformDataForNextNextPackage); - BeginPackageCacheForCookedPlatformData(NextNextPackage); - } - } - - // if we are running the cook commandlet - // if we already went through the entire package list then don't keep requeuing requests - if ( (HasCheckedAllPackagesAreCached == false) && - (AllObjectsCookedDataCached == false) && - (ForceSavePackage == false) ) - { - check(IsCookByTheBookMode() || ProcessingUnsolicitedPackages == true); - // add to back of queue - PackagesToSave.Add(Package); - // UE_LOG(LogCook, Display, TEXT("Delaying save for package %s"), *PackageFName.ToString()); - continue; - } - - if (HasCheckedAllPackagesAreCached) - { - UE_LOG(LogCook, Display, TEXT("Forcing save package %s because was already requeued once"), *PackageFName.ToString()); - } - - - bool bShouldSaveAsync = true; - FString Temp; - if ( FParse::Value( FCommandLine::Get(), TEXT("-diffagainstcookdirectory="), Temp ) || FParse::Value(FCommandLine::Get(), TEXT("-breakonfile="), Temp)) - { - // async save doesn't work with this flags - bShouldSaveAsync = false; - } - - TArray SucceededSavePackage; - TArray SavePackageResults; - { - COOK_STAT(FScopedDurationTimer TickCookOnTheSideSaveCookedPackageTimer(DetailedCookStats::TickCookOnTheSideSaveCookedPackageTimeSec)); - SCOPE_TIMER(SaveCookedPackage); - uint32 SaveFlags = SAVE_KeepGUID | (bShouldSaveAsync ? SAVE_Async : SAVE_None) | (IsCookFlagSet(ECookInitializationFlags::Unversioned) ? SAVE_Unversioned : 0); - - bool KeepEditorOnlyPackages = false; - // removing editor only packages only works when cooking in commandlet and non iterative cooking - // also doesn't work in multiprocess cooking - KeepEditorOnlyPackages = !(IsCookByTheBookMode() && !IsCookingInEditor()); - KeepEditorOnlyPackages |= IsCookFlagSet(ECookInitializationFlags::Iterative); - KeepEditorOnlyPackages |= IsChildCooker() || (CookByTheBookOptions && CookByTheBookOptions->ChildCookers.Num() > 0); - SaveFlags |= KeepEditorOnlyPackages ? SAVE_KeepEditorOnlyCookedPackages : SAVE_None; - - GOutputCookingWarnings = IsCookFlagSet(ECookInitializationFlags::OutputVerboseCookerWarnings); - SaveCookedPackage(Package, SaveFlags, bWasUpToDate, AllTargetPlatformNames, SavePackageResults); - GOutputCookingWarnings = false; - check(AllTargetPlatformNames.Num() == SavePackageResults.Num()); - for (int32 PlatformIndex = 0; PlatformIndex < AllTargetPlatformNames.Num(); PlatformIndex++) - { - const FSavePackageResultStruct& SavePackageResult = SavePackageResults[PlatformIndex]; - if (SavePackageResult == ESavePackageResult::Success || SavePackageResult == ESavePackageResult::GenerateStub || SavePackageResult == ESavePackageResult::ReplaceCompletely) - { - SucceededSavePackage.Add(true); - // Update flags used to determine garbage collection. - if (Package->ContainsMap()) - { - Result |= COSR_CookedMap; - } - else - { - ++CookedPackageCount; - Result |= COSR_CookedPackage; - } - - // Update asset registry - if (CookByTheBookOptions) - { - FAssetRegistryGenerator* Generator = RegistryGenerators.FindRef(AllTargetPlatformNames[PlatformIndex]); - if (Generator) - { - FAssetPackageData* PackageData = Generator->GetAssetPackageData(Package->GetFName()); - PackageData->DiskSize = SavePackageResult.TotalFileSize; - } - } - - } - else - { - SucceededSavePackage.Add(false); - } - } - check( SavePackageResults.Num() == SucceededSavePackage.Num() ); - Timer.SavedPackage(); - } - - if ( IsCookingInEditor() == false ) - { - SCOPE_TIMER(ClearAllCachedCookedPlatformData); - TArray ObjectsInPackage; - GetObjectsWithOuter(Package, ObjectsInPackage); - for ( UObject* Object : ObjectsInPackage ) - { - Object->ClearAllCachedCookedPlatformData(); - } - } - - //@todo ResetLoaders outside of this (ie when Package is NULL) causes problems w/ default materials - if (Package->IsRooted() == false && ((CurrentCookMode==ECookMode::CookOnTheFly)) ) - { - SCOPE_TIMER(ResetLoaders); - ResetLoaders(Package); - } - - FName StandardFilename = GetCachedStandardPackageFileFName(Package); - - // We always want to mark package as processed unless it wasn't saved because it was referenced by editor-only data - // in which case we may still need to save it later when new content loads it through non editor-only references - if (StandardFilename != NAME_None) - { - // mark the package as cooked - FFilePlatformCookedPackage FileRequest(StandardFilename, AllTargetPlatformNames, SucceededSavePackage); - bool bWasReferencedOnlyByEditorOnlyData = false; - for (const FSavePackageResultStruct& SavePackageResult : SavePackageResults) - { - if ( SavePackageResult == ESavePackageResult::ReferencedOnlyByEditorOnlyData ) - { - bWasReferencedOnlyByEditorOnlyData = true; - // if this is the case all of the packages should be referenced only by editor only data - } - } - if (!bWasReferencedOnlyByEditorOnlyData) - { - CookedPackages.Add(FileRequest); - if ((CurrentCookMode == ECookMode::CookOnTheFly) && (I >= FirstUnsolicitedPackage)) - { - // this is an unsolicited package - if ((FPaths::FileExists(FileRequest.GetFilename().ToString()) == true) && - (bWasUpToDate == false)) - { - UnsolicitedCookedPackages.AddCookedPackage(FileRequest); -#if DEBUG_COOKONTHEFLY - UE_LOG(LogCook, Display, TEXT("UnsolicitedCookedPackages: %s"), *FileRequest.GetFilename().ToString()); -#endif - } - } - } - else - { - UncookedEditorOnlyPackages.AddUnique(Package->GetFName()); - } - } - else - { - for ( const bool bSucceededSavePackage : SucceededSavePackage ) - { - check( bSucceededSavePackage == false ); - } - } - } - } + bool bFinishedSave = SaveCookedPackages( PackagesToSave, AllTargetPlatformNames, TargetPlatforms, Timer, FirstUnsolicitedPackage, CookedPackageCount, Result ); // TODO: Daniel: this is reference code needs to be reimplemented on the callee side. @@ -2188,13 +1804,31 @@ uint32 UCookOnTheFlyServer::TickCookOnTheSide( const float TimeSlice, uint32 &Co } - + // if we are cook on the fly (even in editor) and we have cook requests, try process them straight away + /*if ( IsCookOnTheFlyMode() && CookRequests.HasItems() ) + { + continue; + }*/ + if ( Timer.IsTimeUp() ) { break; } } - + + + if ( IsCookOnTheFlyMode() && (IsCookingInEditor() == false) ) + { + static int32 TickCounter = 0; + ++TickCounter; + if ( TickCounter > 50 ) + { + // dump stats every 50 ticks or so + DumpStats(); + TickCounter = 0; + } + } + OUTPUT_TIMERS(); if (CookByTheBookOptions) @@ -2215,6 +1849,580 @@ uint32 UCookOnTheFlyServer::TickCookOnTheSide( const float TimeSlice, uint32 &Co return Result; } +bool UCookOnTheFlyServer::BeginPackageCacheForCookedPlatformData(UPackage* Package, const TArray& TargetPlatforms, FCookerTimer& Timer) const +{ + COOK_STAT(FScopedDurationTimer DurationTimer(DetailedCookStats::TickCookOnTheSideBeginPackageCacheForCookedPlatformDataTimeSec)); + +#if DEBUG_COOKONTHEFLY + UE_LOG(LogCook, Display, TEXT("Caching objects for package %s"), *Package->GetFName().ToString()); +#endif + MakePackageFullyLoaded(Package); + FReentryData& CurrentReentryData = GetReentryData(Package); + + if (CurrentReentryData.bIsValid == false) + return true; + + if (CurrentReentryData.bBeginCacheFinished) + return true; + + for (; CurrentReentryData.BeginCacheCount < CurrentReentryData.CachedObjectsInOuter.Num(); ++CurrentReentryData.BeginCacheCount) + { + UObject* Obj = CurrentReentryData.CachedObjectsInOuter[CurrentReentryData.BeginCacheCount]; + for (const ITargetPlatform* TargetPlatform : TargetPlatforms) + { + const FName ClassFName = Obj->GetClass()->GetFName(); + int32* CurrentAsyncCache = CurrentAsyncCacheForType.Find(ClassFName); + if ( CurrentAsyncCache != nullptr ) + { + if ( *CurrentAsyncCache <= 0 ) + { + return false; + } + + int32* Value = CurrentReentryData.BeginCacheCallCount.Find(ClassFName); + if ( !Value ) + { + CurrentReentryData.BeginCacheCallCount.Add(ClassFName,1); + } + else + { + *Value += 1; + } + CurrentAsyncCache -= 1; + } + + if (Obj->IsA(UMaterialInterface::StaticClass())) + { + if (GShaderCompilingManager->GetNumRemainingJobs() > MaxConcurrentShaderJobs) + { +#if DEBUG_COOKONTHEFLY + UE_LOG(LogCook, Display, TEXT("Delaying shader compilation of material %s"), *Obj->GetFullName()); +#endif + return false; + } + } + Obj->BeginCacheForCookedPlatformData(TargetPlatform); + } + + if (Timer.IsTimeUp()) + { +#if DEBUG_COOKONTHEFLY + UE_LOG(LogCook, Display, TEXT("Object %s took too long to cache"), *Obj->GetFullName()); +#endif + return false; + } + } + + CurrentReentryData.bBeginCacheFinished = true; + return true; + +} + +bool UCookOnTheFlyServer::FinishPackageCacheForCookedPlatformData(UPackage* Package, const TArray& TargetPlatforms, FCookerTimer& Timer) const +{ + COOK_STAT(FScopedDurationTimer DurationTimer(DetailedCookStats::TickCookOnTheSideFinishPackageCacheForCookedPlatformDataTimeSec)); + + MakePackageFullyLoaded(Package); + FReentryData& CurrentReentryData = GetReentryData(Package); + + if (CurrentReentryData.bIsValid == false) + return true; + + if (CurrentReentryData.bFinishedCacheFinished) + return true; + + for (UObject* Obj : CurrentReentryData.CachedObjectsInOuter) + { + for (const ITargetPlatform* TargetPlatform : TargetPlatforms) + { + COOK_STAT(double CookerStatSavedValue = DetailedCookStats::TickCookOnTheSideBeginPackageCacheForCookedPlatformDataTimeSec); + + if (Obj->IsA(UMaterialInterface::StaticClass())) + { + if (Obj->IsCachedCookedPlatformDataLoaded(TargetPlatform) == false) + { + if (GShaderCompilingManager->GetNumRemainingJobs() > MaxConcurrentShaderJobs) + { + return false; + } + } + } + + // These begin cache calls should be quick + // because they will just be checking that the data is already cached and kicking off new multithreaded requests if not + // all sync requests should have been caught in the first begincache call above + Obj->BeginCacheForCookedPlatformData(TargetPlatform); + // We want to measure inclusive time for this function, but not accumulate into the BeginXXX timer, so subtract these times out of the BeginTimer. + COOK_STAT(DetailedCookStats::TickCookOnTheSideBeginPackageCacheForCookedPlatformDataTimeSec = CookerStatSavedValue); + if (Obj->IsCachedCookedPlatformDataLoaded(TargetPlatform) == false) + { +#if DEBUG_COOKONTHEFLY + UE_LOG(LogCook, Display, TEXT("Object %s isn't cached yet"), *Obj->GetFullName()); +#endif + /*if ( Obj->IsA(UMaterial::StaticClass()) ) + { + if (GShaderCompilingManager->HasShaderJobs() == false) + { + UE_LOG(LogCook, Warning, TEXT("Shader compiler is in a bad state! Shader %s is finished compile but shader compiling manager did not notify shader. "), *Obj->GetPathName()); + } + }*/ + return false; + } + } + } + + for (UObject* Obj : CurrentReentryData.CachedObjectsInOuter) + { + // if this objects data is cached then we can call FinishedCookedPLatformDataCache + // we can only safely call this when we are finished caching this object completely. + // this doesn't ever happen for cook in editor or cook on the fly mode + if (CurrentCookMode == ECookMode::CookByTheBook) + { + check(!IsCookingInEditor()); + // this might be run multiple times for a single object + Obj->WillNeverCacheCookedPlatformDataAgain(); + } + } + + // all these objects have finished so release their async begincache back to the pool + for (const auto& FinishedCached : CurrentReentryData.BeginCacheCallCount ) + { + int32* Value = CurrentAsyncCacheForType.Find( FinishedCached.Key ); + check( Value); + *Value += FinishedCached.Value; + } + CurrentReentryData.BeginCacheCallCount.Empty(); + + CurrentReentryData.bFinishedCacheFinished = true; + return true; +} + +UPackage* UCookOnTheFlyServer::LoadPackageForCooking(const FString& BuildFilename) +{ + COOK_STAT(FScopedDurationTimer LoadPackagesTimer(DetailedCookStats::TickCookOnTheSideLoadPackagesTimeSec)); + UPackage *Package = NULL; + { + FString PackageName; + if (FPackageName::TryConvertFilenameToLongPackageName(BuildFilename, PackageName)) + { + Package = FindObject(ANY_PACKAGE, *PackageName); + } + } + +#if DEBUG_COOKONTHEFLY + UE_LOG(LogCook, Display, TEXT("Processing request %s"), *BuildFilename); +#endif + static TSet CookWarningsList; + if (CookWarningsList.Contains(BuildFilename) == false) + { + CookWarningsList.Add(BuildFilename); + GOutputCookingWarnings = IsCookFlagSet(ECookInitializationFlags::OutputVerboseCookerWarnings); + } + + // if the package is already loaded then try to avoid reloading it :) + if ((Package == NULL) || (Package->IsFullyLoaded() == false)) + { + GIsCookerLoadingPackage = true; + SCOPE_TIMER(LoadPackage); + Package = LoadPackage(NULL, *BuildFilename, LOAD_None); + INC_INT_STAT(LoadPackage, 1); + + GIsCookerLoadingPackage = false; + } +#if DEBUG_COOKONTHEFLY + else + { + UE_LOG(LogCook, Display, TEXT("Package already loaded %s avoiding reload"), *BuildFilename); + } +#endif + + if (Package == NULL) + { + if ((!IsCookOnTheFlyMode()) || (!IsCookingInEditor())) + { + LogCookerMessage(FString::Printf(TEXT("Error loading %s!"), *BuildFilename), EMessageSeverity::Error); + UE_LOG(LogCook, Error, TEXT("Error loading %s!"), *BuildFilename); + } + } + GOutputCookingWarnings = false; + return Package; +} + + +void UCookOnTheFlyServer::OpportunisticSaveInMemoryPackages() +{ + const float TimeSlice = 0.01f; + FCookerTimer Timer(TimeSlice, IsRealtimeMode()); + TArray PackagesToSave; + bool ContainsFullAssetGCClasses = false; + + TArray TargetPlatformNames; + for (const auto& TargetPlatform : PresaveTargetPlatforms) + { + TargetPlatformNames.Add(FName(*TargetPlatform->PlatformName())); + } + + + GetAllUnsolicitedPackages(PackagesToSave, TargetPlatformNames, ContainsFullAssetGCClasses); + + + uint32 CookedPackageCount = 0; + uint32 Result = 0; + SaveCookedPackages( PackagesToSave, TargetPlatformNames, PresaveTargetPlatforms, Timer, 0, CookedPackageCount, Result); +} + +void UCookOnTheFlyServer::GetAllUnsolicitedPackages(TArray& PackagesToSave, const TArray& TargetPlatformNames, bool& ContainsFullAssetGCClasses ) +{ + // generate a list of other packages which were loaded with this one + if (!IsCookByTheBookMode() || (CookByTheBookOptions->bDisableUnsolicitedPackages == false)) + { + { + SCOPE_TIMER(PostLoadPackageFixup); + for (TObjectIterator It; It; ++It) + { + PostLoadPackageFixup(*It); + } + } + //GRedirectCollector.ResolveStringAssetReference(); + SCOPE_TIMER(UnsolicitedMarkup); + GetUnsolicitedPackages(PackagesToSave, ContainsFullAssetGCClasses, TargetPlatformNames); + + } +} + +bool UCookOnTheFlyServer::SaveCookedPackages(TArray& PackagesToSave, const TArray& TargetPlatformNames, const TArray& TargetPlatformsToCache, FCookerTimer& Timer, + int32 FirstUnsolicitedPackage, uint32& CookedPackageCount , uint32& Result) +{ + bool bIsAllDataCached = true; + + const TArray& AllTargetPlatformNames = TargetPlatformNames; + + + bool bFinishedSave = true; + + if (PackagesToSave.Num()) + { + int32 OriginalPackagesToSaveCount = PackagesToSave.Num(); + SCOPE_TIMER(SavingPackages); + for (int32 I = 0; I < PackagesToSave.Num(); ++I) + { + UPackage* Package = PackagesToSave[I]; + if (Package->IsLoadedByEditorPropertiesOnly() && UncookedEditorOnlyPackages.Contains(Package->GetFName())) + { + // We already attempted to cook this package and it's still not referenced by any non editor-only properties. + continue; + } + + // This package is valid, so make sure it wasn't previously marked as being an uncooked editor only package or it would get removed from the + // asset registry at the end of the cook + UncookedEditorOnlyPackages.Remove(Package->GetFName()); + + const FName StandardPackageFilename = GetCachedStandardPackageFileFName(Package); + check(IsInGameThread()); + if (NeverCookPackageList.Contains(StandardPackageFilename)) + { + // refuse to save this package, it's clearly one of the undesirables + continue; + } + + + FName PackageFName = GetCachedStandardPackageFileFName(Package); + TArray SaveTargetPlatformNames = AllTargetPlatformNames; + TArray CookedTargetPlatforms; + if (CookedPackages.GetCookedPlatforms(PackageFName, CookedTargetPlatforms)) + { + for (const FName& CookedPlatform : CookedTargetPlatforms) + { + SaveTargetPlatformNames.Remove(CookedPlatform); + } + } + + // we somehow already cooked this package not sure how that can happen because the PackagesToSave list should have already filtered this + if (SaveTargetPlatformNames.Num() == 0) + { + UE_LOG(LogCook, Warning, TEXT("Allready saved this package not sure how this got here!")); + // already saved this package + continue; + } + + + // if we are processing unsolicited packages we can optionally not save these right now + // the unsolicited packages which we missed now will be picked up on next run + // we want to do this in cook on the fly also, if there is a new network package request instead of saving unsolicited packages we can process the requested package + + bool bShouldFinishTick = false; + + if (Timer.IsTimeUp() && IsCookByTheBookMode() ) + { + bShouldFinishTick = true; + // our timeslice is up + } + + // if we are cook the fly then save the package which was requested as fast as we can because the client is waiting on it + + bool ProcessingUnsolicitedPackages = (I >= FirstUnsolicitedPackage); + bool bForceSavePackage = false; + + if (IsCookOnTheFlyMode()) + { + if (ProcessingUnsolicitedPackages) + { + SCOPE_TIMER(WaitingForCachedCookedPlatformData); + if (CookRequests.HasItems()) + { + bShouldFinishTick = true; + } + if (Timer.IsTimeUp()) + { + bShouldFinishTick = true; + // our timeslice is up + } + bool bFinishedCachingCookedPlatformData = false; + // if we are in realtime mode then don't wait forever for the package to be ready + while ((!Timer.IsTimeUp()) && IsRealtimeMode() && (bShouldFinishTick == false)) + { + if (FinishPackageCacheForCookedPlatformData(Package, TargetPlatformsToCache, Timer) == true) + { + bFinishedCachingCookedPlatformData = true; + break; + } + + GShaderCompilingManager->ProcessAsyncResults(true, false); + // sleep for a bit + FPlatformProcess::Sleep(0.0f); + } + bShouldFinishTick |= !bFinishedCachingCookedPlatformData; + } + else + { + if (!IsRealtimeMode()) + { + bForceSavePackage = true; + } + } + } + + bool AllObjectsCookedDataCached = true; + bool HasCheckedAllPackagesAreCached = (I >= OriginalPackagesToSaveCount); + + MakePackageFullyLoaded(Package); + + if ( IsCookOnTheFlyMode() ) + { + // never want to requeue packages + HasCheckedAllPackagesAreCached = true; + } + + // if we are forcing save the package then it doesn't matter if we call FinishPackageCacheForCookedPlatformData + if (!bShouldFinishTick && !bForceSavePackage) + { + AllObjectsCookedDataCached = FinishPackageCacheForCookedPlatformData(Package, TargetPlatformsToCache, Timer); + if (AllObjectsCookedDataCached == false) + { + GShaderCompilingManager->ProcessAsyncResults(true, false); + AllObjectsCookedDataCached = FinishPackageCacheForCookedPlatformData(Package, TargetPlatformsToCache, Timer); + } + } + + // if we are in realtime mode and this package isn't ready to be saved then we should exit the tick here so we don't save it while in launch on + if (IsRealtimeMode() && + (AllObjectsCookedDataCached == false) && + HasCheckedAllPackagesAreCached) + { + bShouldFinishTick = true; + } + + if (bShouldFinishTick && (!bForceSavePackage)) + { + SCOPE_TIMER(EnqueueUnsavedPackages); + // enqueue all the packages which we were about to save + Timer.SavedPackage(); // this is a special case to prevent infinite loop, if we only have one package we might fall through this and could loop forever. + int32 NumPackagesToRequeue = PackagesToSave.Num(); + + if (IsCookOnTheFlyMode()) + { + NumPackagesToRequeue = FirstUnsolicitedPackage; + } + + for (int32 RemainingIndex = I; RemainingIndex < NumPackagesToRequeue; ++RemainingIndex) + { + FName StandardFilename = GetCachedStandardPackageFileFName(PackagesToSave[RemainingIndex]); + CookRequests.EnqueueUnique(FFilePlatformRequest(StandardFilename, AllTargetPlatformNames)); + } + Result |= COSR_WaitingOnCache; + + // break out of the loop + bFinishedSave = false; + break; + } + + + // don't precache other packages if our package isn't ready but we are going to save it. This will fill up the worker threads with extra shaders which we may need to flush on + if ((!IsCookOnTheFlyMode()) && + (!IsRealtimeMode() || AllObjectsCookedDataCached == true)) + { + // precache platform data for next package + UPackage *NextPackage = PackagesToSave[FMath::Min(PackagesToSave.Num() - 1, I + 1)]; + UPackage *NextNextPackage = PackagesToSave[FMath::Min(PackagesToSave.Num() - 1, I + 2)]; + if (NextPackage != Package) + { + SCOPE_TIMER(PrecachePlatformDataForNextPackage); + BeginPackageCacheForCookedPlatformData(NextPackage, TargetPlatformsToCache, Timer); + } + if (NextNextPackage != NextPackage) + { + SCOPE_TIMER(PrecachePlatformDataForNextNextPackage); + BeginPackageCacheForCookedPlatformData(NextNextPackage, TargetPlatformsToCache, Timer); + } + } + + // if we are running the cook commandlet + // if we already went through the entire package list then don't keep requeuing requests + if ((HasCheckedAllPackagesAreCached == false) && + (AllObjectsCookedDataCached == false) && + (bForceSavePackage == false) && + IsCookByTheBookMode() ) + { + // check(IsCookByTheBookMode() || ProcessingUnsolicitedPackages == true); + // add to back of queue + PackagesToSave.Add(Package); + // UE_LOG(LogCook, Display, TEXT("Delaying save for package %s"), *PackageFName.ToString()); + continue; + } + + if ( HasCheckedAllPackagesAreCached && (AllObjectsCookedDataCached == false) ) + { + UE_LOG(LogCook, Display, TEXT("Forcing save package %s because was already requeued once"), *PackageFName.ToString()); + } + + + bool bShouldSaveAsync = true; + FString Temp; + if (FParse::Value(FCommandLine::Get(), TEXT("-diffagainstcookdirectory="), Temp) || FParse::Value(FCommandLine::Get(), TEXT("-breakonfile="), Temp)) + { + // async save doesn't work with this flags + bShouldSaveAsync = false; + } + + TArray SucceededSavePackage; + TArray SavePackageResults; + { + COOK_STAT(FScopedDurationTimer TickCookOnTheSideSaveCookedPackageTimer(DetailedCookStats::TickCookOnTheSideSaveCookedPackageTimeSec)); + SCOPE_TIMER(SaveCookedPackage); + uint32 SaveFlags = SAVE_KeepGUID | (bShouldSaveAsync ? SAVE_Async : SAVE_None) | (IsCookFlagSet(ECookInitializationFlags::Unversioned) ? SAVE_Unversioned : 0); + + bool KeepEditorOnlyPackages = false; + // removing editor only packages only works when cooking in commandlet and non iterative cooking + // also doesn't work in multiprocess cooking + KeepEditorOnlyPackages = !(IsCookByTheBookMode() && !IsCookingInEditor()); + KeepEditorOnlyPackages |= IsCookFlagSet(ECookInitializationFlags::Iterative); + KeepEditorOnlyPackages |= IsChildCooker() || (CookByTheBookOptions && CookByTheBookOptions->ChildCookers.Num() > 0); + SaveFlags |= KeepEditorOnlyPackages ? SAVE_KeepEditorOnlyCookedPackages : SAVE_None; + + GOutputCookingWarnings = IsCookFlagSet(ECookInitializationFlags::OutputVerboseCookerWarnings); + SaveCookedPackage(Package, SaveFlags, SaveTargetPlatformNames, SavePackageResults); + GOutputCookingWarnings = false; + check(SaveTargetPlatformNames.Num() == SavePackageResults.Num()); + for (int iResultIndex = 0; iResultIndex < SavePackageResults.Num(); iResultIndex++) + { + FSavePackageResultStruct& SavePackageResult = SavePackageResults[iResultIndex]; + + if (SavePackageResult == ESavePackageResult::Success || SavePackageResult == ESavePackageResult::GenerateStub || SavePackageResult == ESavePackageResult::ReplaceCompletely) + { + SucceededSavePackage.Add(true); + // Update flags used to determine garbage collection. + if (Package->ContainsMap()) + { + Result |= COSR_CookedMap; + } + else + { + ++CookedPackageCount; + Result |= COSR_CookedPackage; + } + + // Update asset registry + if (CookByTheBookOptions) + { + FAssetRegistryGenerator* Generator = RegistryGenerators.FindRef(SaveTargetPlatformNames[iResultIndex]); + if (Generator) + { + FAssetPackageData* PackageData = Generator->GetAssetPackageData(Package->GetFName()); + PackageData->DiskSize = SavePackageResult.TotalFileSize; + } + } + + } + else + { + SucceededSavePackage.Add(false); + } + } + check(SavePackageResults.Num() == SucceededSavePackage.Num()); + Timer.SavedPackage(); + } + + if (IsCookingInEditor() == false) + { + SCOPE_TIMER(ClearAllCachedCookedPlatformData); + TArray ObjectsInPackage; + GetObjectsWithOuter(Package, ObjectsInPackage); + for (UObject* Object : ObjectsInPackage) + { + Object->ClearAllCachedCookedPlatformData(); + } + } + + //@todo ResetLoaders outside of this (ie when Package is NULL) causes problems w/ default materials + FName StandardFilename = GetCachedStandardPackageFileFName(Package); + + // We always want to mark package as processed unless it wasn't saved because it was referenced by editor-only data + // in which case we may still need to save it later when new content loads it through non editor-only references + if (StandardFilename != NAME_None) + { + // mark the package as cooked + FFilePlatformCookedPackage FileRequest(StandardFilename, SaveTargetPlatformNames, SucceededSavePackage); + bool bWasReferencedOnlyByEditorOnlyData = false; + for (const FSavePackageResultStruct& SavePackageResult : SavePackageResults) + { + if (SavePackageResult == ESavePackageResult::ReferencedOnlyByEditorOnlyData) + { + bWasReferencedOnlyByEditorOnlyData = true; + // if this is the case all of the packages should be referenced only by editor only data + } + } + if (!bWasReferencedOnlyByEditorOnlyData) + { + CookedPackages.Add(FileRequest); + if ((CurrentCookMode == ECookMode::CookOnTheFly) && (I >= FirstUnsolicitedPackage)) + { + // this is an unsolicited package + if (FPaths::FileExists(FileRequest.GetFilename().ToString()) == true) + { + UnsolicitedCookedPackages.AddCookedPackage(FileRequest); +#if DEBUG_COOKONTHEFLY + UE_LOG(LogCook, Display, TEXT("UnsolicitedCookedPackages: %s"), *FileRequest.GetFilename().ToString()); +#endif + } + } + } + else + { + UncookedEditorOnlyPackages.AddUnique(Package->GetFName()); + } + } + else + { + for (const bool bSucceededSavePackage : SucceededSavePackage) + { + check(bSucceededSavePackage == false); + } + } + } + } + return true; +} + void UCookOnTheFlyServer::PostLoadPackageFixup(UPackage* Package) { @@ -2225,7 +2433,6 @@ void UCookOnTheFlyServer::PostLoadPackageFixup(UPackage* Package) return; } - if (Package->ContainsMap()) { // load sublevels @@ -2256,18 +2463,9 @@ void UCookOnTheFlyServer::PostLoadPackageFixup(UPackage* Package) for (const FString& PackageName : NewPackagesToCook) { -#if 0 // old way keeping for reference in case there are issues - FString Filename; - if (FPackageName::DoesPackageExist(PackageName, nullptr, &Filename)) - { - FString StandardFilename = FPaths::ConvertRelativePathToFull(Filename); - FPaths::MakeStandardFilename(StandardFilename); - FName StandardPackageFName = FName(*StandardFilename); -#else FName StandardPackageFName = GetCachedStandardPackageFileFName(FName(*PackageName)); if (StandardPackageFName != NAME_None) { -#endif if (IsChildCooker()) { check(IsCookByTheBookMode()); @@ -2523,6 +2721,12 @@ void UCookOnTheFlyServer::OnObjectPropertyChanged(UObject* ObjectBeingModified, { return; } + if ( PropertyChangedEvent.Property == nullptr && + PropertyChangedEvent.MemberProperty == nullptr ) + { + // probably nothing changed... + return; + } OnObjectUpdated( ObjectBeingModified ); } @@ -2546,6 +2750,20 @@ void UCookOnTheFlyServer::MarkPackageDirtyForCooker( UPackage *Package ) { return; } + if (Package->HasAnyPackageFlags(PKG_PlayInEditor | PKG_ContainsScript | PKG_CompiledIn) == true && !GetClass()->HasAnyClassFlags(CLASS_DefaultConfig | CLASS_Config)) + { + return; + } + + if (Package == GetTransientPackage()) + { + return; + } + + if ( FPackageName::IsMemoryPackage(Package->GetName())) + { + return; + } if ( !bIsSavingPackage ) { @@ -2560,6 +2778,7 @@ void UCookOnTheFlyServer::MarkPackageDirtyForCooker( UPackage *Package ) if ( PackageFFileName == NAME_None ) { ClearPackageFilenameCacheForPackage( Package ); + return; } // find all packages which depend on this one @@ -2567,23 +2786,45 @@ void UCookOnTheFlyServer::MarkPackageDirtyForCooker( UPackage *Package ) UE_LOG(LogCook, Verbose, TEXT("Modification detected to package %s"), *PackageFFileName.ToString()); - if ( CurrentCookMode == ECookMode::CookByTheBookFromTheEditor ) + if ( IsCookingInEditor() ) { - TArray CookedPlatforms; - // if we have already cooked this package and we have made changes then recook ;) - if ( CookedPackages.GetCookedPlatforms(PackageFFileName, CookedPlatforms) ) + if ( IsCookByTheBookMode() ) { - if (IsCookByTheBookRunning()) + TArray CookedPlatforms; + // if we have already cooked this package and we have made changes then recook ;) + if ( CookedPackages.GetCookedPlatforms(PackageFFileName, CookedPlatforms) ) { - // if this package was previously cooked and we are doing a cook by the book - // we need to recook this package before finishing cook by the book - CookRequests.EnqueueUnique(FFilePlatformRequest(PackageFFileName, CookedPlatforms)); + if (IsCookByTheBookRunning()) + { + // if this package was previously cooked and we are doing a cook by the book + // we need to recook this package before finishing cook by the book + CookRequests.EnqueueUnique(FFilePlatformRequest(PackageFFileName, CookedPlatforms)); + } + else + { + CookByTheBookOptions->PreviousCookRequests.Add(FFilePlatformRequest(PackageFFileName, CookedPlatforms)); + } } - else + } + else if ( IsCookOnTheFlyMode() ) + { + if ( FileModifiedDelegate.IsBound() ) { - CookByTheBookOptions->PreviousCookRequests.Add(FFilePlatformRequest(PackageFFileName, CookedPlatforms)); + const FString PackageName = PackageFFileName.ToString(); + FileModifiedDelegate.Broadcast(PackageName); + if ( PackageName.EndsWith(".uasset") || PackageName.EndsWith(".umap")) + { + FileModifiedDelegate.Broadcast( FPaths::ChangeExtension(PackageName, TEXT(".uexp")) ); + FileModifiedDelegate.Broadcast( FPaths::ChangeExtension(PackageName, TEXT(".ubulk")) ); + FileModifiedDelegate.Broadcast( FPaths::ChangeExtension(PackageName, TEXT(".ufont")) ); + } } } + else + { + // this is here if we add a new mode and don't implement this it will crash instead of doing undesireable behaviour + check( true); + } } CookedPackages.RemoveFile( PackageFFileName ); } @@ -2593,7 +2834,8 @@ void UCookOnTheFlyServer::MarkPackageDirtyForCooker( UPackage *Package ) void UCookOnTheFlyServer::MarkDependentPackagesDirtyForCooker( const FName& PackageName) { // mark all packages which are dependent on this package as need recooking - + // currently this is handled by the VerifyCookedPackagesAreUptoDate + // when a new cook by the book request starts it will call VerifyCookedPackagesAreUptodate. } void UCookOnTheFlyServer::EndNetworkFileServer() @@ -2645,11 +2887,6 @@ const TArray& UCookOnTheFlyServer::GetFullPackageDependencies(const FName TArray* PackageDependencies = CachedFullPackageDependencies.Find(PackageName); if ( !PackageDependencies ) { - if ( PackageName.ToString().Contains( TEXT("/Game/Sounds/Class/Interior"))) - { - static int i =0; - ++i; - } static const FName NAME_CircularReference(TEXT("CircularReference")); static int32 UniqueArrayCounter = 0; @@ -2668,27 +2905,27 @@ const TArray& UCookOnTheFlyServer::GetFullPackageDependencies(const FName TArray ChildDependencies; if ( AssetRegistry->GetDependencies(PackageName, ChildDependencies, EAssetRegistryDependencyType::All) ) { - TArray Dependencies = ChildDependencies; - Dependencies.AddUnique(PackageName); - for ( const FName& ChildDependency : ChildDependencies) - { - const TArray& ChildPackageDependencies = GetFullPackageDependencies(ChildDependency); - for ( const FName& ChildPackageDependency : ChildPackageDependencies ) + TArray Dependencies = ChildDependencies; + Dependencies.AddUnique(PackageName); + for ( const FName& ChildDependency : ChildDependencies) { - if ( ChildPackageDependency == CircularReferenceArrayName ) - { - continue; - } - if ( ChildPackageDependency.GetComparisonIndex() == NAME_CircularReference.GetComparisonIndex() ) - { - // add our self to the package which we are circular referencing - TArray& TempCircularReference = CachedFullPackageDependencies.FindChecked(ChildPackageDependency); - TempCircularReference.AddUnique(PackageName); // add this package name so that it's dependencies get fixed up when the outer loop returns - } + const TArray& ChildPackageDependencies = GetFullPackageDependencies(ChildDependency); + for ( const FName& ChildPackageDependency : ChildPackageDependencies ) + { + if ( ChildPackageDependency == CircularReferenceArrayName ) + { + continue; + } + if ( ChildPackageDependency.GetComparisonIndex() == NAME_CircularReference.GetComparisonIndex() ) + { + // add our self to the package which we are circular referencing + TArray& TempCircularReference = CachedFullPackageDependencies.FindChecked(ChildPackageDependency); + TempCircularReference.AddUnique(PackageName); // add this package name so that it's dependencies get fixed up when the outer loop returns + } - Dependencies.AddUnique(ChildPackageDependency); + Dependencies.AddUnique(ChildPackageDependency); + } } - } // all these packages referenced us apparently so fix them all up const TArray& PackagesForFixup = CachedFullPackageDependencies.FindChecked(CircularReferenceArrayName); @@ -2710,11 +2947,11 @@ const TArray& UCookOnTheFlyServer::GetFullPackageDependencies(const FName } CachedFullPackageDependencies.Remove(CircularReferenceArrayName); - PackageDependencies = CachedFullPackageDependencies.Find(PackageName); - check(PackageDependencies); + PackageDependencies = CachedFullPackageDependencies.Find(PackageName); + check(PackageDependencies); - Swap(*PackageDependencies, Dependencies); - } + Swap(*PackageDependencies, Dependencies); + } else { PackageDependencies = CachedFullPackageDependencies.Find(PackageName); @@ -2809,10 +3046,10 @@ void UCookOnTheFlyServer::TickRecompileShaderRequests() } -void UCookOnTheFlyServer::SaveCookedPackage(UPackage* Package, uint32 SaveFlags, bool& bOutWasUpToDate, TArray& SavePackageResults) +void UCookOnTheFlyServer::SaveCookedPackage(UPackage* Package, uint32 SaveFlags, TArray& SavePackageResults) { TArray TargetPlatformNames; - return SaveCookedPackage( Package, SaveFlags, bOutWasUpToDate, TargetPlatformNames, SavePackageResults); + return SaveCookedPackage( Package, SaveFlags, TargetPlatformNames, SavePackageResults); } bool UCookOnTheFlyServer::ShouldCook(const FString& InFileName, const FName &InPlatformName) @@ -2827,7 +3064,7 @@ bool UCookOnTheFlyServer::ShouldConsiderCompressedPackageFileLengthRequirements( return bConsiderCompressedPackageFileLengthRequirements; } -bool UCookOnTheFlyServer::MakePackageFullyLoaded(UPackage* Package) +bool UCookOnTheFlyServer::MakePackageFullyLoaded(UPackage* Package) const { if ( Package->IsFullyLoaded() ) return true; @@ -2856,7 +3093,7 @@ bool UCookOnTheFlyServer::MakePackageFullyLoaded(UPackage* Package) return bPackageFullyLoaded; } -void UCookOnTheFlyServer::SaveCookedPackage(UPackage* Package, uint32 SaveFlags, bool& bOutWasUpToDate, TArray &TargetPlatformNames, TArray& SavePackageResults) +void UCookOnTheFlyServer::SaveCookedPackage(UPackage* Package, uint32 SaveFlags, TArray &TargetPlatformNames, TArray& SavePackageResults) { check( SavePackageResults.Num() == 0); check( bIsSavingPackage == false ); @@ -2866,7 +3103,7 @@ void UCookOnTheFlyServer::SaveCookedPackage(UPackage* Package, uint32 SaveFlags, // Don't resolve, just add to request list as needed TSet StringAssetPackages; - GRedirectCollector.GetStringAssetReferencePackageList(Package->GetFName(), StringAssetPackages); + GRedirectCollector.ProcessStringAssetReferencePackageList(Package->GetFName(), false, StringAssetPackages); for (FName StringAssetPackage : StringAssetPackages) { @@ -2877,7 +3114,7 @@ void UCookOnTheFlyServer::SaveCookedPackage(UPackage* Package, uint32 SaveFlags, { for (TPair& RedirectedPath : RedirectedPaths) { - GRedirectCollector.AddStringAssetReferenceRedirection(RedirectedPath.Key, RedirectedPath.Value); + GRedirectCollector.AddAssetPathRedirection(RedirectedPath.Key, RedirectedPath.Value); } } @@ -2891,7 +3128,7 @@ void UCookOnTheFlyServer::SaveCookedPackage(UPackage* Package, uint32 SaveFlags, } } - if (Filename.Len()) + if (Filename.Len() != 0 ) { if (Package->HasAnyPackageFlags(PKG_ReloadingForCooker)) { @@ -2908,7 +3145,6 @@ void UCookOnTheFlyServer::SaveCookedPackage(UPackage* Package, uint32 SaveFlags, UWorld* World = nullptr; EObjectFlags FlagsToCook = RF_Public; - ITargetPlatformManagerModule& TPM = GetTargetPlatformManagerRef(); static TArray ActiveStartupPlatforms = TPM.GetCookingTargetPlatforms(); @@ -3033,8 +3269,6 @@ void UCookOnTheFlyServer::SaveCookedPackage(UPackage* Package, uint32 SaveFlags, } } } - - bOutWasUpToDate = false; } else { @@ -3043,11 +3277,6 @@ void UCookOnTheFlyServer::SaveCookedPackage(UPackage* Package, uint32 SaveFlags, Result = ESavePackageResult::Error; } } - else - { - UE_LOG(LogCook, Verbose, TEXT("Up to date: %s"), *PlatFilename); - bOutWasUpToDate = true; - } } Package->SetPackageFlagsTo(OriginalPackageFlags); @@ -3121,6 +3350,21 @@ void UCookOnTheFlyServer::Initialize( ECookMode::Type DesiredCookMode, ECookInit } } + + ITargetPlatformManagerModule& TPM = GetTargetPlatformManagerRef(); + TArray PresaveTargetPlatformNames; + if ( GConfig->GetArray(TEXT("CookSettings"), TEXT("PresaveTargetPlatforms"), PresaveTargetPlatformNames, GEditorIni ) ) + { + for ( const auto& PresaveTargetPlatformName : PresaveTargetPlatformNames ) + { + ITargetPlatform* TargetPlatform = TPM.FindTargetPlatform(PresaveTargetPlatformName); + if (TargetPlatform) + { + PresaveTargetPlatforms.Add(TargetPlatform); + } + } + } + PackagesPerGC = 500; int32 ConfigPackagesPerGC = 0; if (GConfig->GetInt( TEXT("CookSettings"), TEXT("PackagesPerGC"), ConfigPackagesPerGC, GEditorIni )) @@ -3166,6 +3410,24 @@ void UCookOnTheFlyServer::Initialize( ECookMode::Type DesiredCookMode, ECookInit UE_LOG(LogCook, Display, TEXT("Max memory allowance for cook %dmb min free memory %dmb"), MaxMemoryAllowanceInMB, MinFreeMemoryInMB); + + { + const FConfigSection* CacheSettings = GConfig->GetSectionPrivate(TEXT("CookPlatformDataCacheSettings"), false, true, GEditorIni); + if ( CacheSettings ) + { + for ( const auto& CacheSetting : *CacheSettings ) + { + + const FString& ReadString = CacheSetting.Value.GetValue(); + int32 ReadValue = FCString::Atoi(*ReadString); + int32 Count = FMath::Max( 2, ReadValue ); + MaxAsyncCacheForType.Add( CacheSetting.Key, Count ); + } + } + CurrentAsyncCacheForType = MaxAsyncCacheForType; + } + + if (IsCookByTheBookMode()) { CookByTheBookOptions = new FCookByTheBookOptions(); @@ -3178,7 +3440,8 @@ void UCookOnTheFlyServer::Initialize( ECookMode::Type DesiredCookMode, ECookInit } } } - + + UE_LOG(LogCook, Display, TEXT("Mobile HDR setting %d"), IsMobileHDR()); // See if there are any plugins that need to be remapped for the sandbox @@ -3266,11 +3529,31 @@ bool UCookOnTheFlyServer::Exec(class UWorld* InWorld, const TCHAR* Cmd, FOutputD { StopAndClearCookedData(); } + else if (FParse::Command(&Cmd, TEXT("stats"))) + { + DumpStats(); + } return false; } +void UCookOnTheFlyServer::DumpStats() +{ + OUTPUT_TIMERS(); + OUTPUT_HIERARCHYTIMERS(); +#if PROFILE_NETWORK + UE_LOG(LogCook, Display, TEXT("Network Stats \n" + "TimeTillRequestStarted %f\n" + "TimeTillRequestForfilled %f\n" + "TimeTillRequestForfilledError %f\n" + "WaitForAsyncFilesWrites %f\n"), + TimeTillRequestStarted, + TimeTillRequestForfilled, + TimeTillRequestForfilledError, + WaitForAsyncFilesWrites); +#endif +} uint32 UCookOnTheFlyServer::NumConnections() const { @@ -3315,8 +3598,7 @@ FString UCookOnTheFlyServer::GetOutputDirectoryOverride() const // Output directory needs to contain [Platform] token to be able to cook for multiple targets. if ( IsCookByTheBookMode() ) { - ITargetPlatformManagerModule& TPM = GetTargetPlatformManagerRef(); - const TArray& TargetPlatforms = TPM.GetCookingTargetPlatforms(); + const TArray& TargetPlatforms = GetCookingTargetPlatforms(); // more then one target platform specified append "[platform]" to output directory so that multiple platforms can be cooked check( TargetPlatforms.Num() == 1 ); @@ -3472,8 +3754,8 @@ void GetAdditionalCurrentIniVersionStrings( const ITargetPlatform* TargetPlatfor } - // TODO: Add support for physx version tracking, currently this happens so infrequently that invalidating a cook based on it is not essentual - //GetVersionFormatNumbersForIniVersionStrings(IniVersionMap, TEXT("PhysXFormat"), TPM->GetPhysXFormats()); + // TODO: Add support for physx version tracking, currently this happens so infrequently that invalidating a cook based on it is not essential + //GetVersionFormatNumbersForIniVersionStrings(IniVersionMap, TEXT("PhysXCooking"), TPM->GetPhysXCooking()); if ( FParse::Param( FCommandLine::Get(), TEXT("fastcook") ) ) @@ -3494,13 +3776,13 @@ void GetAdditionalCurrentIniVersionStrings( const ITargetPlatform* TargetPlatfor FString UE4Value = FString::Printf(TEXT("%d"), GPackageFileLicenseeUE4Version); IniVersionMap.Add(UE4Ver, UE4Value); - FString UE4EngineVersionCompatibleName = TEXT("EngineVersionCompatibleWith"); + /*FString UE4EngineVersionCompatibleName = TEXT("EngineVersionCompatibleWith"); FString UE4EngineVersionCompatible = FEngineVersion::CompatibleWith().ToString(); - if (UE4EngineVersionCompatible.Len()) + if ( UE4EngineVersionCompatible.Len() ) { IniVersionMap.Add(UE4EngineVersionCompatibleName, UE4EngineVersionCompatible); - } + }*/ IniVersionMap.Add(TEXT("MaterialShaderMapDDCVersion"), *GetMaterialShaderMapDDCKey()); IniVersionMap.Add(TEXT("GlobalDDCVersion"), *GetGlobalShaderMapDDCKey()); @@ -4230,7 +4512,7 @@ bool UCookOnTheFlyServer::SaveCookedAssetRegistry(const FString& InCookedAssetRe } { - SCOPE_TIMER(AsyncDetermineAllDependentPackageInfo); + SCOPE_TIMER(DetermineDependentTimeStamps); TArray RelativePaths; for ( const auto& FNamePath : AllCookedPackages ) @@ -4245,6 +4527,7 @@ bool UCookOnTheFlyServer::SaveCookedAssetRegistry(const FString& InCookedAssetRe bIgnoreMarkupPackageAlreadyLoaded = false; } + AllCookedPackages.StableSort(); TSet ProcessedCookedPackages; // keep track of which packages are processed for (const FName& Package : AllCookedPackages) @@ -4351,7 +4634,6 @@ bool UCookOnTheFlyServer::SaveCookedAssetRegistry(const FString& InCookedAssetRe Json->WriteValue(TEXT("ObjectPath"), AssetData.ObjectPath.ToString()); Json->WriteValue(TEXT("PackageName"), AssetData.PackageName.ToString()); Json->WriteValue(TEXT("PackagePath"), AssetData.PackagePath.ToString()); - Json->WriteValue(TEXT("GroupNames"), AssetData.GroupNames.ToString()); Json->WriteValue(TEXT("AssetName"), AssetData.AssetName.ToString()); Json->WriteValue(TEXT("AssetClass"), AssetData.AssetClass.ToString()); Json->WriteObjectStart("TagsAndValues"); @@ -4416,7 +4698,10 @@ bool UCookOnTheFlyServer::SaveCookedAssetRegistry(const FString& InCookedAssetRe } */ - for (const FName& EditorOnlyPackage : UncookedEditorPackages) + TArray SortedUncookedEditorPackages = UncookedEditorPackages; + SortedUncookedEditorPackages.StableSort(); + + for (const auto& EditorOnlyPackage : SortedUncookedEditorPackages) { const FString& RelativePath = EditorOnlyPackage.ToString(); @@ -4623,7 +4908,7 @@ void UCookOnTheFlyServer::PopulateCookedPackagesFromDisk(const TArrayPlatformName()); bool bIsIterateSharedBuild = IsCookFlagSet(ECookInitializationFlags::IterateSharedBuild); @@ -4634,11 +4919,14 @@ void UCookOnTheFlyServer::PopulateCookedPackagesFromDisk(const TArrayPlatformName(), TEXT("Cooked"), GetAssetRegistryFilename()); + FString SharedCookedAssetRegistry = FPaths::Combine(*FPaths::GameSavedDir(), TEXT("SharedIterativeBuild"), *Target->PlatformName(), TEXT("Cooked"), GetDevelopmentAssetRegistryFilename()); FDateTime CurrentIterativeCookedBuild = IFileManager::Get().GetTimeStamp(*SharedCookedAssetRegistry); - if (CurrentIterativeCookedBuild > CurrentLocalCookedBuild) + + + if ( (CurrentIterativeCookedBuild >= CurrentLocalCookedBuild) && + (CurrentIterativeCookedBuild != FDateTime::MinValue()) ) { // clean the sandbox ClearPlatformCookedData(FName(*Target->PlatformName())); @@ -4671,16 +4959,20 @@ void UCookOnTheFlyServer::PopulateCookedPackagesFromDisk(const TArrayLoadPreviousAssetRegistry(SandboxCookedAssetRegistryFilename); } - } - - PlatformAssetRegistry->LoadPreviousAssetRegistry(SandboxCookedAssetRegistryFilename); + else + { + PlatformAssetRegistry->LoadPreviousAssetRegistry(SandboxCookedAssetRegistryFilename); + } // Get list of changed packages TSet ModifiedPackages, NewPackages, RemovedPackages, IdenticalCookedPackages, IdenticalUncookedPackages; - PlatformAssetRegistry->ComputePackageDifferences(ModifiedPackages, NewPackages, RemovedPackages, IdenticalCookedPackages, IdenticalUncookedPackages); + // We recurse modifications up the reference chain because it is safer, if this ends up being a significant issue in some games we can add a command line flag + bool bRecurseModifications = true; + PlatformAssetRegistry->ComputePackageDifferences(ModifiedPackages, NewPackages, RemovedPackages, IdenticalCookedPackages, IdenticalUncookedPackages, bRecurseModifications); // check the files on disk TMap UncookedPathToCookedPath; @@ -4690,8 +4982,13 @@ void UCookOnTheFlyServer::PopulateCookedPackagesFromDisk(const TArray ExistingPackages = ModifiedPackages; + ExistingPackages.Append(RemovedPackages); + ExistingPackages.Append(IdenticalCookedPackages); + ExistingPackages.Append(IdenticalUncookedPackages); + // if we are iterating of a shared build the cooked files might not exist in the cooked directory because we assume they are packaged in the pak file (which we don't want to extract) - for (FName PackageName : IdenticalCookedPackages) + for (FName PackageName : ExistingPackages) { FString Filename; if (FPackageName::DoesPackageExist(PackageName.ToString(), nullptr, &Filename)) @@ -4706,12 +5003,17 @@ void UCookOnTheFlyServer::PopulateCookedPackagesFromDisk(const TArray PlatformNames; + PlatformNames.Add(PlatformFName); + CookRequests.EnqueueUnique(MoveTemp(FFilePlatformRequest(UncookedFilename, PlatformNames))); + } if ( CookedFile != NAME_DummyCookedFilename ) { // delete the old package @@ -5136,6 +5447,29 @@ void UCookOnTheFlyServer::PopulateCookedPackagesFromDisk(const TArray CookedFilesNoExt; + TArray OtherFiles; + FAdditionalPackageSearchVisitor AdditionalPackageSearch(CookedFilesNoExt, OtherFiles); + PlatformFile.IterateDirectoryRecursively(*SandboxPath, AdditionalPackageSearch); + + + auto DeleteOtherPackagesLambda = [&CookedFilesNoExt, &OtherFiles]( int32 PackageIndex ) + { + const FString& OtherFile = OtherFiles[PackageIndex]; + const FString NoExtOtherFile = FPaths::SetExtension(OtherFile, ""); + if ( CookedFilesNoExt.Contains(NoExtOtherFile) == false ) + { + // if we didn't keep the original package then get rid of this one + IFileManager::Get().Delete(*OtherFile, true, true, true); + } + }; + + ParallelFor(OtherFiles.Num(), DeleteOtherPackagesLambda ); + + /*for ( const FString& CookedFullPath : CookedPackagesToDelete ) { IFileManager::Get().Delete(*CookedFullPath, true, true, true); @@ -5249,7 +5583,13 @@ void UCookOnTheFlyServer::VerifyCookedPackagesAreUptodate(const TArray& Platforms = TPM.GetCookingTargetPlatforms(); + const TArray& Platforms = GetCookingTargetPlatforms(); // before we can delete any cooked files we need to make sure that we have finished writing them UPackage::WaitForAsyncFileWrites(); @@ -5557,16 +5902,20 @@ void UCookOnTheFlyServer::GenerateAssetRegistry() double GenerateAssetRegistryTime = 0.0; { SCOPE_TIMER(GenerateAssetRegistryTime); -#if DEBUG_COOKONTHEFLY - UE_LOG(LogCook, Display, TEXT("Creating asset registry [is editor: %d]"), GIsEditor); -#endif + UE_LOG(LogCook, Display, TEXT("Creating asset registry")); + // Perform a synchronous search of any .ini based asset paths (note that the per-game delegate may // have already scanned paths on its own) // We want the registry to be fully initialized when generating streaming manifests too. - bool bEditor = IsRealtimeMode(); // editor will scan asset registry automagically - if ( !bEditor ) + bool bCanDelayAssetregistryProcessing = IsRealtimeMode(); + + // if we are running in the editor we need the asset registry to be finished loaded before we process any iterative cook requests + bCanDelayAssetregistryProcessing &= !IsCookFlagSet(ECookInitializationFlags::Iterative); // + + + if ( !bCanDelayAssetregistryProcessing) { TArray ScanPaths; if (GConfig->GetArray(TEXT("AssetRegistry"), TEXT("PathsToScanForCook"), ScanPaths, GEngineIni) > 0) @@ -5580,8 +5929,7 @@ void UCookOnTheFlyServer::GenerateAssetRegistry() } } - ITargetPlatformManagerModule& TPM = GetTargetPlatformManagerRef(); - const TArray& Platforms = TPM.GetCookingTargetPlatforms(); + const TArray& Platforms = GetCookingTargetPlatforms(); for (ITargetPlatform* TargetPlatform : Platforms) { @@ -5775,7 +6123,19 @@ void UCookOnTheFlyServer::CollectFilesToCook(TArray& FilesInPath, const T if (UAssetManager::IsValid()) { - UAssetManager::Get().ModifyCook(FilesInPath); + TArray PackagesToNeverCook; + + UAssetManager::Get().ModifyCook(FilesInPath, PackagesToNeverCook); + + for (FName NeverCookPackage : PackagesToNeverCook) + { + const FName StandardPackageFilename = GetCachedStandardPackageFileFName(NeverCookPackage); + + if (StandardPackageFilename != NAME_None) + { + NeverCookPackageList.Add(StandardPackageFilename); + } + } } #if DEBUG_COOKMODIFICATIONDELEGATE for (TObjectIterator It; It; ++It) @@ -5889,42 +6249,6 @@ void UCookOnTheFlyServer::CollectFilesToCook(TArray& FilesInPath, const T } } - if ((FilesInPath.Num() == 0) || bCookAll) - { - TArray Tokens; - Tokens.Empty(2); - Tokens.Add(FString("*") + FPackageName::GetAssetPackageExtension()); - Tokens.Add(FString("*") + FPackageName::GetMapPackageExtension()); - - uint8 PackageFilter = NORMALIZE_DefaultFlags | NORMALIZE_ExcludeEnginePackages; - if ( bMapsOnly ) - { - PackageFilter |= NORMALIZE_ExcludeContentPackages; - } - - if ( bNoDev ) - { - PackageFilter |= NORMALIZE_ExcludeDeveloperPackages; - } - - // assume the first token is the map wildcard/pathname - TArray Unused; - for ( int32 TokenIndex = 0; TokenIndex < Tokens.Num(); TokenIndex++ ) - { - TArray TokenFiles; - if ( !NormalizePackageNames( Unused, TokenFiles, Tokens[TokenIndex], PackageFilter) ) - { - UE_LOG(LogCook, Display, TEXT("No packages found for parameter %i: '%s'"), TokenIndex, *Tokens[TokenIndex]); - continue; - } - - for (int32 TokenFileIndex = 0; TokenFileIndex < TokenFiles.Num(); ++TokenFileIndex) - { - AddFileToCook( FilesInPath, TokenFiles[TokenFileIndex]); - } - } - } - if (!(FilesToCookFlags & ECookByTheBookOptions::NoDefaultMaps)) { // make sure we cook the default maps @@ -5979,6 +6303,42 @@ void UCookOnTheFlyServer::CollectFilesToCook(TArray& FilesInPath, const T } } + if ((FilesInPath.Num() == 0) || bCookAll) + { + TArray Tokens; + Tokens.Empty(2); + Tokens.Add(FString("*") + FPackageName::GetAssetPackageExtension()); + Tokens.Add(FString("*") + FPackageName::GetMapPackageExtension()); + + uint8 PackageFilter = NORMALIZE_DefaultFlags | NORMALIZE_ExcludeEnginePackages; + if ( bMapsOnly ) + { + PackageFilter |= NORMALIZE_ExcludeContentPackages; + } + + if ( bNoDev ) + { + PackageFilter |= NORMALIZE_ExcludeDeveloperPackages; + } + + // assume the first token is the map wildcard/pathname + TArray Unused; + for ( int32 TokenIndex = 0; TokenIndex < Tokens.Num(); TokenIndex++ ) + { + TArray TokenFiles; + if ( !NormalizePackageNames( Unused, TokenFiles, Tokens[TokenIndex], PackageFilter) ) + { + UE_LOG(LogCook, Display, TEXT("No packages found for parameter %i: '%s'"), TokenIndex, *Tokens[TokenIndex]); + continue; + } + + for (int32 TokenFileIndex = 0; TokenFileIndex < TokenFiles.Num(); ++TokenFileIndex) + { + AddFileToCook( FilesInPath, TokenFiles[TokenFileIndex]); + } + } + } + if (!(FilesToCookFlags & ECookByTheBookOptions::NoInputPackages)) { @@ -6031,6 +6391,20 @@ void UCookOnTheFlyServer::CollectFilesToCook(TArray& FilesInPath, const T } } } + + if (CookByTheBookOptions && !(FilesToCookFlags & ECookByTheBookOptions::DisableUnsolicitedPackages)) + { + // Gather initial unsolicited package list, this is needed in iterative mode because it may skip cooking all explicit packages and never hit this code + TArray UnsolicitedPackages; + bool ContainsFullAssetGCClasses = false; + UE_LOG(LogCook, Verbose, TEXT("Finding initial unsolicited packages")); + GetUnsolicitedPackages(UnsolicitedPackages, ContainsFullAssetGCClasses, CookByTheBookOptions->TargetPlatformNames); + + for (UPackage* UnsolicitedPackage : UnsolicitedPackages) + { + AddFileToCook(FilesInPath, UnsolicitedPackage->GetName()); + } + } } bool UCookOnTheFlyServer::IsCookByTheBookRunning() const @@ -6407,6 +6781,7 @@ void UCookOnTheFlyServer::CookByTheBookFinished() UE_LOG(LogCook, Display, TEXT("Peak Used virtual %u Peak Used phsical %u"), MemStats.PeakUsedVirtual / 1024 / 1024, MemStats.PeakUsedPhysical / 1024 / 1024 ); OUTPUT_HIERARCHYTIMERS(); + CLEAR_HIERARCHYTIMERS(); } void UCookOnTheFlyServer::BuildMapDependencyGraph(const FName& PlatformName) @@ -6569,8 +6944,7 @@ void UCookOnTheFlyServer::InitializeSandbox() { if ( SandboxFile == nullptr ) { - ITargetPlatformManagerModule& TPM = GetTargetPlatformManagerRef(); - const TArray& TargetPlatforms = TPM.GetCookingTargetPlatforms(); + const TArray& TargetPlatforms = GetCookingTargetPlatforms(); CreateSandboxFile(); @@ -6593,7 +6967,6 @@ void UCookOnTheFlyServer::TermSandbox() void UCookOnTheFlyServer::ValidateCookOnTheFlySettings() const { - check( IsCookFlagSet(ECookInitializationFlags::IterateSharedBuild) == false ); } void UCookOnTheFlyServer::ValidateCookByTheBookSettings() const @@ -6806,6 +7179,7 @@ void UCookOnTheFlyServer::StartCookByTheBook( const FCookByTheBookStartupOptions if ( bSucceeded ) { TArray PlatformNames; + PlatformNames.Add(PlatformName); TArray Succeeded; Succeeded.Add(true); for (const FName& PackageFilename : PackageList) @@ -6827,11 +7201,11 @@ void UCookOnTheFlyServer::StartCookByTheBook( const FCookByTheBookStartupOptions TSet StartupStringAssetPackages; // Get the list of string asset references, for both empty package and all startup packages - GRedirectCollector.GetStringAssetReferencePackageList(NAME_None, StartupStringAssetPackages); + GRedirectCollector.ProcessStringAssetReferencePackageList(NAME_None, false, StartupStringAssetPackages); for (const FName& StartupPackage : CookByTheBookOptions->StartupPackages) { - GRedirectCollector.GetStringAssetReferencePackageList(StartupPackage, StartupStringAssetPackages); + GRedirectCollector.ProcessStringAssetReferencePackageList(StartupPackage, false, StartupStringAssetPackages); } for (FName StringAssetPackage : StartupStringAssetPackages) @@ -6843,7 +7217,7 @@ void UCookOnTheFlyServer::StartCookByTheBook( const FCookByTheBookStartupOptions { for (TPair& RedirectedPath : RedirectedPaths) { - GRedirectCollector.AddStringAssetReferenceRedirection(RedirectedPath.Key, RedirectedPath.Value); + GRedirectCollector.AddAssetPathRedirection(RedirectedPath.Key, RedirectedPath.Value); } } @@ -6935,7 +7309,6 @@ void UCookOnTheFlyServer::StartCookByTheBook( const FCookByTheBookStartupOptions } } - bool UCookOnTheFlyServer::RecompileChangedShaders(const TArray& TargetPlatforms) { bool bShadersRecompiled = false; @@ -6946,9 +7319,6 @@ bool UCookOnTheFlyServer::RecompileChangedShaders(const TArray& TargetPla return bShadersRecompiled; } - - - class FChildCookerRunnable : public FRunnable { private: @@ -7313,6 +7683,23 @@ void UCookOnTheFlyServer::MaybeMarkPackageAsAlreadyLoaded(UPackage *Package) } +bool UCookOnTheFlyServer::HandleNetworkFileServerNewConnection(const FString& VersionInfo, const FString& PlatformName) +{ + const uint32 CL = FEngineVersion::CompatibleWith().GetChangelist(); + const FString Branch = FEngineVersion::CompatibleWith().GetBranch(); + + const FString LocalVersionInfo = FString::Printf(TEXT("%s %d"), *Branch, CL); + + UE_LOG(LogCook, Display, TEXT("Connection received of version %s local version %s"), *VersionInfo, *LocalVersionInfo); + + if (LocalVersionInfo != VersionInfo) + { + UE_LOG(LogCook, Warning, TEXT("Connection tried to connect with incompatable version")); + // return false; + } + return true; +} + void UCookOnTheFlyServer::HandleNetworkFileServerFileRequest( const FString& Filename, const FString &PlatformName, TArray& UnsolicitedFiles ) { check( IsCookOnTheFlyMode() ); @@ -7331,7 +7718,21 @@ void UCookOnTheFlyServer::HandleNetworkFileServerFileRequest( const FString& Fil { FString StandardFilename = UnsolicitedFile.ToString(); FPaths::MakeStandardFilename( StandardFilename ); - UnsolicitedFiles.Add( StandardFilename ); + + // check that the sandboxed file exists... if it doesn't then don't send it back + // this can happen if the package was saved but the async writer thread hasn't finished writing it to disk yet + + FString SandboxFilename = ConvertToFullSandboxPath(*Filename, true); + SandboxFilename.ReplaceInline(TEXT("[Platform]"), *PlatformFname.ToString()); + if ( IFileManager::Get().FileExists(*SandboxFilename) ) + { + UnsolicitedFiles.Add(StandardFilename); + } + else + { + UE_LOG(LogCook, Warning, TEXT("Unsolicited file doesn't exist in sandbox, ignoring %s"), *Filename ); + } + } UPackage::WaitForAsyncFileWrites(); return; @@ -7344,14 +7745,52 @@ void UCookOnTheFlyServer::HandleNetworkFileServerFileRequest( const FString& Fil TArray Platforms; Platforms.Add( PlatformFname ); FFilePlatformRequest FileRequest( StandardFileFname, Platforms); + +#if PROFILE_NETWORK + double StartTime = FPlatformTime::Seconds(); + check(NetworkRequestEvent); + NetworkRequestEvent->Reset(); +#endif + + UE_LOG(LogCook, Display, TEXT("Requesting file from cooker %s"), *StandardFileName); + CookRequests.EnqueueUnique(FileRequest, true); - do - { - FPlatformProcess::Sleep(0.0f); - } - while (!CookedPackages.Exists(FileRequest)); +#if PROFILE_NETWORK + bool bFoundNetworkEventWait = true; + while (NetworkRequestEvent->Wait(1) == false) + { + // for some reason we missed the stat + if (CookedPackages.Exists(FileRequest)) + { + double DeltaTimeTillRequestForfilled = FPlatformTime::Seconds() - StartTime; + TimeTillRequestForfilled += DeltaTimeTillRequestForfilled; + TimeTillRequestForfilledError += DeltaTimeTillRequestForfilled; + StartTime = FPlatformTime::Seconds(); + bFoundNetworkEventWait = false; + break; + } + } + + + // wait for tick entry here + TimeTillRequestStarted += FPlatformTime::Seconds() - StartTime; + StartTime = FPlatformTime::Seconds(); +#endif + + while (!CookedPackages.Exists(FileRequest)) + { + FPlatformProcess::Sleep(0.0001f); + } + +#if PROFILE_NETWORK + if ( bFoundNetworkEventWait ) + { + TimeTillRequestForfilled += FPlatformTime::Seconds() - StartTime; + StartTime = FPlatformTime::Seconds(); + } +#endif UE_LOG( LogCook, Display, TEXT("Cook complete %s"), *FileRequest.GetFilename().ToString()) TArray UnsolicitedFilenames; @@ -7367,7 +7806,10 @@ void UCookOnTheFlyServer::HandleNetworkFileServerFileRequest( const FString& Fil UPackage::WaitForAsyncFileWrites(); - +#if PROFILE_NETWORK + WaitForAsyncFilesWrites += FPlatformTime::Seconds() - StartTime; + StartTime = FPlatformTime::Seconds(); +#endif #if DEBUG_COOKONTHEFLY UE_LOG( LogCook, Display, TEXT("Processed file request %s"), *Filename ); #endif @@ -7375,6 +7817,32 @@ void UCookOnTheFlyServer::HandleNetworkFileServerFileRequest( const FString& Fil } +FString UCookOnTheFlyServer::HandleNetworkGetSandboxPath() +{ + return SandboxFile->GetSandboxDirectory(); +} + +void UCookOnTheFlyServer::HandleNetworkGetPrecookedList(const FString& PlatformName, TMap& PrecookedFileList) +{ + FName PlatformFName = FName(*PlatformName); + + TArray CookedPlatformFiles; + CookedPackages.GetCookedFilesForPlatform(PlatformFName, CookedPlatformFiles); + + + for ( const FName& CookedFile : CookedPlatformFiles) + { + const FString SandboxFilename = ConvertToFullSandboxPath(CookedFile.ToString(), true, PlatformName); + if (IFileManager::Get().FileExists(*SandboxFilename)) + { + continue; + } + + PrecookedFileList.Add(CookedFile.ToString(),FDateTime::MinValue()); + } +} + + void UCookOnTheFlyServer::HandleNetworkFileServerRecompileShaders(const FShaderRecompileData& RecompileData) { // shouldn't receive network requests unless we are in cook on the fly mode diff --git a/Engine/Source/Editor/UnrealEd/Private/CookerSettings.cpp b/Engine/Source/Editor/UnrealEd/Private/CookerSettings.cpp index 1ff1c9f4517f..cc9e5cf2cda1 100644 --- a/Engine/Source/Editor/UnrealEd/Private/CookerSettings.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/CookerSettings.cpp @@ -28,8 +28,8 @@ void UCookerSettings::PostInitProperties() void UCookerSettings::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) { - static FName NAME_ClassesExcludedOnDedicatedServer(TEXT("ClassesExcludedOnDedicatedServer")); - static FName NAME_ClassesExcludedOnDedicatedClient(TEXT("ClassesExcludedOnDedicatedClient")); + static FName NAME_ClassesExcludedOnDedicatedServer = GET_MEMBER_NAME_CHECKED(UCookerSettings, ClassesExcludedOnDedicatedServer); + static FName NAME_ClassesExcludedOnDedicatedClient = GET_MEMBER_NAME_CHECKED(UCookerSettings, ClassesExcludedOnDedicatedClient); static FName NAME_ModulesExcludedOnDedicatedServer(TEXT("ModulesExcludedOnDedicatedServer")); static FName NAME_ModulesExcludedOnDedicatedClient(TEXT("ModulesExcludedOnDedicatedClient")); diff --git a/Engine/Source/Editor/UnrealEd/Private/DataTableEditorUtils.cpp b/Engine/Source/Editor/UnrealEd/Private/DataTableEditorUtils.cpp index 409ff314b485..c20987fe3e6b 100644 --- a/Engine/Source/Editor/UnrealEd/Private/DataTableEditorUtils.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/DataTableEditorUtils.cpp @@ -170,6 +170,15 @@ bool FDataTableEditorUtils::MoveRow(UDataTable* DataTable, FName RowName, ERowMo return true; } +bool FDataTableEditorUtils::SelectRow(UDataTable* DataTable, FName RowName) +{ + for (auto Listener : FDataTableEditorManager::Get().GetListeners()) + { + static_cast(Listener)->SelectionChange(DataTable, RowName); + } + return true; +} + bool FDataTableEditorUtils::DiffersFromDefault(UDataTable* DataTable, FName RowName) { bool bDiffers = false; @@ -247,7 +256,10 @@ void FDataTableEditorUtils::CacheDataTableForEditing(const UDataTable* DataTable { const UProperty* Prop = *It; check(Prop); - StructProps.Add(Prop); + if (!Prop->HasMetaData(FName(TEXT("HideFromDataTableEditorColumn")))) + { + StructProps.Add(Prop); + } } TSharedRef FontMeasure = FSlateApplication::Get().GetRenderer()->GetFontMeasureService(); diff --git a/Engine/Source/Editor/UnrealEd/Private/DebugToolExec.cpp b/Engine/Source/Editor/UnrealEd/Private/DebugToolExec.cpp index 823f34c545bd..308839b49492 100644 --- a/Engine/Source/Editor/UnrealEd/Private/DebugToolExec.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/DebugToolExec.cpp @@ -213,7 +213,7 @@ bool FDebugToolExec::Exec( UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar FRotator PlayerRotation; PlayerController->GetPlayerViewPoint(PlayerLocation, PlayerRotation); FHitResult Hit(1.0f); - PlayerController->GetWorld()->LineTraceSingleByChannel(Hit, PlayerLocation, PlayerLocation + PlayerRotation.Vector() * 10000.f, ECC_Pawn, FCollisionQueryParams(NAME_None, true, PlayerController->GetPawn())); + PlayerController->GetWorld()->LineTraceSingleByChannel(Hit, PlayerLocation, PlayerLocation + PlayerRotation.Vector() * 10000.f, ECC_Pawn, FCollisionQueryParams(NAME_None, FCollisionQueryParams::GetUnknownStatId(), true, PlayerController->GetPawn())); Found = Hit.GetActor(); } } diff --git a/Engine/Source/Editor/UnrealEd/Private/DragAndDrop/AssetDragDropOp.cpp b/Engine/Source/Editor/UnrealEd/Private/DragAndDrop/AssetDragDropOp.cpp index dcd39c1c02e9..1c4fcca04c54 100644 --- a/Engine/Source/Editor/UnrealEd/Private/DragAndDrop/AssetDragDropOp.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/DragAndDrop/AssetDragDropOp.cpp @@ -8,22 +8,40 @@ #include "AssetThumbnail.h" #include "ClassIconFinder.h" -TSharedRef FAssetDragDropOp::New(const FAssetData& InAssetData, UActorFactory* ActorFactory /*= NULL*/) +TSharedRef FAssetDragDropOp::New(const FAssetData& InAssetData, UActorFactory* ActorFactory) { TArray AssetDataArray; - AssetDataArray.Add(InAssetData); - return New(AssetDataArray, ActorFactory); + AssetDataArray.Emplace(InAssetData); + return New(MoveTemp(AssetDataArray), TArray(), ActorFactory); } -TSharedRef FAssetDragDropOp::New(const TArray& InAssetData, UActorFactory* ActorFactory /*= NULL*/) +TSharedRef FAssetDragDropOp::New(TArray InAssetData, UActorFactory* ActorFactory) { - TSharedRef Operation = MakeShareable(new FAssetDragDropOp); + return New(MoveTemp(InAssetData), TArray(), ActorFactory); +} + +TSharedRef FAssetDragDropOp::New(FString InAssetPath) +{ + TArray AssetPathsArray; + AssetPathsArray.Emplace(MoveTemp(InAssetPath)); + return New(TArray(), MoveTemp(AssetPathsArray), nullptr); +} + +TSharedRef FAssetDragDropOp::New(TArray InAssetPaths) +{ + return New(TArray(), MoveTemp(InAssetPaths), nullptr); +} + +TSharedRef FAssetDragDropOp::New(TArray InAssetData, TArray InAssetPaths, UActorFactory* ActorFactory) +{ + TSharedRef Operation = MakeShared(); Operation->MouseCursor = EMouseCursor::GrabHandClosed; Operation->ThumbnailSize = 64; - Operation->AssetData = InAssetData; + Operation->AssetData = MoveTemp(InAssetData); + Operation->AssetPaths = MoveTemp(InAssetPaths); Operation->ActorFactory = ActorFactory; Operation->Init(); @@ -34,7 +52,7 @@ TSharedRef FAssetDragDropOp::New(const TArray& InA FAssetDragDropOp::~FAssetDragDropOp() { - if ( ThumbnailPool.IsValid() ) + if (ThumbnailPool.IsValid()) { // Release all rendering resources being held onto ThumbnailPool->ReleaseResources(); @@ -43,22 +61,49 @@ FAssetDragDropOp::~FAssetDragDropOp() TSharedPtr FAssetDragDropOp::GetDefaultDecorator() const { - TSharedPtr ThumbnailWidget; + const int32 TotalCount = AssetData.Num() + AssetPaths.Num(); - if ( AssetThumbnail.IsValid() ) + TSharedPtr ThumbnailWidget; + if (AssetThumbnail.IsValid()) { ThumbnailWidget = AssetThumbnail->MakeThumbnailWidget(); } + else if (AssetPaths.Num() > 0) + { + ThumbnailWidget = + SNew(SOverlay) + + +SOverlay::Slot() + [ + SNew(SImage) + .Image(FEditorStyle::GetBrush("ContentBrowser.ListViewFolderIcon.Base")) + .ColorAndOpacity(FLinearColor::Gray) + ] + + +SOverlay::Slot() + [ + SNew(SImage) + .Image(FEditorStyle::GetBrush("ContentBrowser.ListViewFolderIcon.Mask")) + ]; + } else { - ThumbnailWidget = SNew(SImage) .Image( FEditorStyle::GetDefaultBrush() ); + ThumbnailWidget = + SNew(SImage) + .Image(FEditorStyle::GetDefaultBrush()); } - - const FSlateBrush* ActorTypeBrush = FEditorStyle::GetDefaultBrush(); - if ( ActorFactory.IsValid() && AssetData.Num() > 0 ) + + const FSlateBrush* SubTypeBrush = FEditorStyle::GetDefaultBrush(); + FLinearColor SubTypeColor = FLinearColor::White; + if (AssetThumbnail.IsValid() && AssetPaths.Num() > 0) { - AActor* DefaultActor = ActorFactory->GetDefaultActor( AssetData[0] ); - ActorTypeBrush = FClassIconFinder::FindIconForActor( DefaultActor ); + SubTypeBrush = FEditorStyle::GetBrush("ContentBrowser.AssetTreeFolderClosed"); + SubTypeColor = FLinearColor::Gray; + } + else if (ActorFactory.IsValid() && AssetData.Num() > 0) + { + AActor* DefaultActor = ActorFactory->GetDefaultActor(AssetData[0]); + SubTypeBrush = FClassIconFinder::FindIconForActor(DefaultActor); } return @@ -68,8 +113,8 @@ TSharedPtr FAssetDragDropOp::GetDefaultDecorator() const [ SNew(SHorizontalBox) - // Left slot is asset thumbnail - + SHorizontalBox::Slot() + // Left slot is for the thumbnail + +SHorizontalBox::Slot() .AutoWidth() .HAlign(HAlign_Left) [ @@ -92,10 +137,11 @@ TSharedPtr FAssetDragDropOp::GetDefaultDecorator() const [ SNew(SBorder) .BorderImage(FEditorStyle::GetBrush("Menu.Background")) - .Visibility(AssetData.Num() > 1 ? EVisibility::Visible : EVisibility::Collapsed) + .Visibility(TotalCount > 1 ? EVisibility::Visible : EVisibility::Collapsed) .Content() [ - SNew(STextBlock) .Text(FText::AsNumber(AssetData.Num())) + SNew(STextBlock) + .Text(FText::AsNumber(TotalCount)) ] ] @@ -105,24 +151,25 @@ TSharedPtr FAssetDragDropOp::GetDefaultDecorator() const .Padding(FMargin(4, 4)) [ SNew(SImage) - .Image( ActorTypeBrush ) - .Visibility( (ActorTypeBrush != FEditorStyle::GetDefaultBrush()) ? EVisibility::Visible : EVisibility::Collapsed) + .Image(SubTypeBrush) + .Visibility(SubTypeBrush != FEditorStyle::GetDefaultBrush() ? EVisibility::Visible : EVisibility::Collapsed) + .ColorAndOpacity(SubTypeColor) ] ] ] // Right slot is for optional tooltip - + SHorizontalBox::Slot() + +SHorizontalBox::Slot() .AutoWidth() .VAlign(VAlign_Center) [ SNew(SBox) - .Visibility(this, &FAssetDragDropOp::GetTooltipVisibility) + .MinDesiredWidth(80) .Content() [ SNew(SHorizontalBox) - + SHorizontalBox::Slot() + +SHorizontalBox::Slot() .AutoWidth() .Padding(3.0f) .VAlign(VAlign_Center) @@ -137,44 +184,49 @@ TSharedPtr FAssetDragDropOp::GetDefaultDecorator() const .VAlign(VAlign_Center) [ SNew(STextBlock) - .Text(this, &FAssetDragDropOp::GetHoverText) + .Text(this, &FAssetDragDropOp::GetDecoratorText) ] ] ] ]; } +FText FAssetDragDropOp::GetDecoratorText() const +{ + if (CurrentHoverText.IsEmpty()) + { + const int32 TotalCount = AssetData.Num() + AssetPaths.Num(); + if (TotalCount > 0) + { + const FText FirstItemText = AssetData.Num() > 0 ? FText::FromName(AssetData[0].AssetName) : FText::FromString(AssetPaths[0]); + return (TotalCount == 1) + ? FirstItemText + : FText::Format(NSLOCTEXT("ContentBrowser", "AssetDragDropOpDescriptionMulti", "'{0}' and {1} {1}|plural(one=other,other=others)"), FirstItemText, TotalCount - 1); + } + } + + return CurrentHoverText; +} + void FAssetDragDropOp::Init() { - if ( AssetData.Num() > 0 && ThumbnailSize > 0 ) + if (AssetData.Num() > 0 && ThumbnailSize > 0) { // Load all assets first so that there is no loading going on while attempting to drag // Can cause unsafe frame reentry - for( FAssetData& Data : AssetData ) + for (FAssetData& Data : AssetData) { Data.GetAsset(); } // Create a thumbnail pool to hold the single thumbnail rendered - ThumbnailPool = MakeShareable( new FAssetThumbnailPool(1, /*InAreRealTileThumbnailsAllowed=*/false) ); + ThumbnailPool = MakeShared(1, /*InAreRealTileThumbnailsAllowed=*/false); // Create the thumbnail handle - AssetThumbnail = MakeShareable( new FAssetThumbnail( AssetData[0], ThumbnailSize, ThumbnailSize, ThumbnailPool ) ); + AssetThumbnail = MakeShared(AssetData[0], ThumbnailSize, ThumbnailSize, ThumbnailPool); // Request the texture then tick the pool once to render the thumbnail AssetThumbnail->GetViewportRenderTargetTexture(); ThumbnailPool->Tick(0); } } - -EVisibility FAssetDragDropOp::GetTooltipVisibility() const -{ - if ( !CurrentHoverText.IsEmpty() ) - { - return EVisibility::Visible; - } - else - { - return EVisibility::Collapsed; - } -} diff --git a/Engine/Source/Editor/UnrealEd/Private/Editor/ActorPositioning.cpp b/Engine/Source/Editor/UnrealEd/Private/Editor/ActorPositioning.cpp index 6296cb0ab3fc..c9d0e50522d4 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Editor/ActorPositioning.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Editor/ActorPositioning.cpp @@ -102,7 +102,7 @@ FActorPositionTraceResult FActorPositioning::TraceWorldForPosition(const UWorld& { TArray Hits; - FCollisionQueryParams Param(TEXT("DragDropTrace"), true); + FCollisionQueryParams Param(SCENE_QUERY_STAT(DragDropTrace), true); Param.bTraceAsyncScene = true; if (IgnoreActors) diff --git a/Engine/Source/Editor/UnrealEd/Private/EditorActor.cpp b/Engine/Source/Editor/UnrealEd/Private/EditorActor.cpp index b1e77c43a7e0..4ecc20684e7b 100644 --- a/Engine/Source/Editor/UnrealEd/Private/EditorActor.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/EditorActor.cpp @@ -58,6 +58,7 @@ #include "LevelEditor.h" #include "Engine/LODActor.h" #include "Settings/LevelEditorMiscSettings.h" +#include "ActorGroupingUtils.h" #define LOCTEXT_NAMESPACE "UnrealEd.EditorActor" @@ -1787,8 +1788,8 @@ void UUnrealEdEngine::edactSelectInvert( UWorld* InWorld ) // or deselect them if they are currently selected // Turn off Grouping during this process to avoid double toggling of selected actors via group selection - const bool bGroupingActiveSaved = bGroupingActive; - bGroupingActive = false; + const bool bGroupingActiveSaved = UActorGroupingUtils::IsGroupingActive(); + UActorGroupingUtils::SetGroupingActive(false); for( FActorIterator It(InWorld); It; ++It ) { AActor* Actor = *It; @@ -1798,7 +1799,7 @@ void UUnrealEdEngine::edactSelectInvert( UWorld* InWorld ) } } // Restore bGroupingActive to its original value - bGroupingActive = bGroupingActiveSaved; + UActorGroupingUtils::SetGroupingActive(bGroupingActiveSaved); // Iterate through all of the BSP models and select them if they are not currently selected (and not hidden) // or deselect them if they are currently selected diff --git a/Engine/Source/Editor/UnrealEd/Private/EditorCategoryUtils.cpp b/Engine/Source/Editor/UnrealEd/Private/EditorCategoryUtils.cpp index e07514cab37a..e9f3599eb40d 100644 --- a/Engine/Source/Editor/UnrealEd/Private/EditorCategoryUtils.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/EditorCategoryUtils.cpp @@ -40,7 +40,7 @@ namespace FEditorCategoryUtilsImpl * @param Key The key you want a category path for. * @return The category display string associated with the specified key (an empty string if an entry wasn't found). */ - FText const& GetCategory(const FString& Key); + const FText& GetCategory(const FString& Key); /** * Performs a lookup into the category key table, retrieving a fully @@ -51,7 +51,7 @@ namespace FEditorCategoryUtilsImpl * @param DocExcerpt Name of the excerpt within the document page for this category * @return The tooltip (if any) stored at the doc path */ - FText GetTooltipForCategory(FString const& CategoryDisplayName, FString const& DocLink, FString const& DocExcerpt); + FText GetTooltipForCategory(const FString& CategoryDisplayName, const FString& DocLink, const FString& DocExcerpt); /** Metadata tags */ const FName ClassHideCategoriesMetaKey(TEXT("HideCategories")); @@ -103,7 +103,7 @@ FEditorCategoryUtilsImpl::FCategoryInfoMap& FEditorCategoryUtilsImpl::GetCategor } //------------------------------------------------------------------------------ -FText const& FEditorCategoryUtilsImpl::GetCategory(const FString& Key) +const FText& FEditorCategoryUtilsImpl::GetCategory(const FString& Key) { if (FEditorCategoryUtilsImpl::FCategoryInfo const* FoundCategory = GetCategoryTable().Find(Key)) { @@ -113,7 +113,7 @@ FText const& FEditorCategoryUtilsImpl::GetCategory(const FString& Key) } //------------------------------------------------------------------------------ -FText FEditorCategoryUtilsImpl::GetTooltipForCategory(FString const& CategoryDisplayName, FString const& DocLink, FString const& DocExcerpt) +FText FEditorCategoryUtilsImpl::GetTooltipForCategory(const FString& CategoryDisplayName, const FString& DocLink, const FString& DocExcerpt) { FText Tooltip; @@ -157,7 +157,7 @@ FText FEditorCategoryUtilsImpl::GetTooltipForCategory(FString const& CategoryDis ******************************************************************************/ //------------------------------------------------------------------------------ -void FEditorCategoryUtils::RegisterCategoryKey(FString const& Key, FText const& Category, FText const& Tooltip) +void FEditorCategoryUtils::RegisterCategoryKey(const FString& Key, const FText& Category, const FText& Tooltip) { FEditorCategoryUtilsImpl::FCategoryInfo& CategoryInfo = FEditorCategoryUtilsImpl::GetCategoryTable().Add(Key); @@ -167,7 +167,7 @@ void FEditorCategoryUtils::RegisterCategoryKey(FString const& Key, FText const& CategoryInfo.Tooltip = (Tooltip.IsEmpty() ? FEditorCategoryUtilsImpl::GetTooltipForCategory(CategoryInfo.DisplayName.ToString(), CategoryInfo.DocLink, CategoryInfo.DocExcerpt) : Tooltip); } -void FEditorCategoryUtils::RegisterCategoryKey(FString const& Key, FText const& Category, FString const& DocLink, FString const& DocExcerpt) +void FEditorCategoryUtils::RegisterCategoryKey(const FString& Key, const FText& Category, const FString& DocLink, const FString& DocExcerpt) { FEditorCategoryUtilsImpl::FCategoryInfo& CategoryInfo = FEditorCategoryUtilsImpl::GetCategoryTable().Add(Key); @@ -178,7 +178,7 @@ void FEditorCategoryUtils::RegisterCategoryKey(FString const& Key, FText const& } //------------------------------------------------------------------------------ -FText const& FEditorCategoryUtils::GetCommonCategory(const FCommonEditorCategory::EValue CategoryId) +const FText& FEditorCategoryUtils::GetCommonCategory(const FCommonEditorCategory::EValue CategoryId) { static TMap CommonCategoryKeys; if (CommonCategoryKeys.Num() == 0) @@ -220,11 +220,11 @@ FText const& FEditorCategoryUtils::GetCommonCategory(const FCommonEditorCategory } //------------------------------------------------------------------------------ -FText FEditorCategoryUtils::BuildCategoryString(FCommonEditorCategory::EValue RootId, FText const& SubCategory) +FText FEditorCategoryUtils::BuildCategoryString(FCommonEditorCategory::EValue RootId, const FText& SubCategory) { FText ConstructedCategory; - FText const& RootCategory = GetCommonCategory(RootId); + const FText& RootCategory = GetCommonCategory(RootId); if (RootCategory.IsEmpty()) { ConstructedCategory = SubCategory; @@ -243,13 +243,13 @@ FText FEditorCategoryUtils::BuildCategoryString(FCommonEditorCategory::EValue Ro } //------------------------------------------------------------------------------ -FText FEditorCategoryUtils::GetCategoryDisplayString(FText const& UnsanitizedCategory) +FText FEditorCategoryUtils::GetCategoryDisplayString(const FText& UnsanitizedCategory) { return FText::FromString(GetCategoryDisplayString(UnsanitizedCategory.ToString())); } //------------------------------------------------------------------------------ -FString FEditorCategoryUtils::GetCategoryDisplayString(FString const& UnsanitizedCategory) +FString FEditorCategoryUtils::GetCategoryDisplayString(const FString& UnsanitizedCategory) { FString DisplayString = UnsanitizedCategory; @@ -285,14 +285,14 @@ FString FEditorCategoryUtils::GetCategoryDisplayString(FString const& Unsanitize } //------------------------------------------------------------------------------ -void FEditorCategoryUtils::GetClassHideCategories(UClass const* Class, TArray& CategoriesOut, bool bHomogenize) +void FEditorCategoryUtils::GetClassHideCategories(const UClass* Class, TArray& CategoriesOut, bool bHomogenize) { CategoriesOut.Empty(); using namespace FEditorCategoryUtilsImpl; if (Class->HasMetaData(ClassHideCategoriesMetaKey)) { - FString const& HideCategories = Class->GetMetaData(ClassHideCategoriesMetaKey); + const FString& HideCategories = Class->GetMetaData(ClassHideCategoriesMetaKey); HideCategories.ParseIntoArray(CategoriesOut, TEXT(" "), /*InCullEmpty =*/true); @@ -307,14 +307,14 @@ void FEditorCategoryUtils::GetClassHideCategories(UClass const* Class, TArray& CategoriesOut) +void FEditorCategoryUtils::GetClassShowCategories(const UClass* Class, TArray& CategoriesOut) { CategoriesOut.Empty(); using namespace FEditorCategoryUtilsImpl; if (Class->HasMetaData(ClassShowCategoriesMetaKey)) { - FString const& ShowCategories = Class->GetMetaData(ClassShowCategoriesMetaKey); + const FString& ShowCategories = Class->GetMetaData(ClassShowCategoriesMetaKey); ShowCategories.ParseIntoArray(CategoriesOut, TEXT(" "), /*InCullEmpty =*/true); for (FString& Category : CategoriesOut) @@ -325,19 +325,19 @@ void FEditorCategoryUtils::GetClassShowCategories(UClass const* Class, TArray ClassHideCategories; GetClassHideCategories(Class, ClassHideCategories); @@ -345,12 +345,12 @@ bool FEditorCategoryUtils::IsCategoryHiddenFromClass(UClass const* Class, FStrin } //------------------------------------------------------------------------------ -bool FEditorCategoryUtils::IsCategoryHiddenFromClass(const TArray& ClassHideCategories, UClass const* Class, const FString& Category) +bool FEditorCategoryUtils::IsCategoryHiddenFromClass(const TArray& ClassHideCategories, const UClass* Class, const FString& Category) { bool bIsHidden = false; // run the category through sanitization so we can ensure compares will hit - FString const DisplayCategory = GetCategoryDisplayString(Category); + const FString DisplayCategory = GetCategoryDisplayString(Category); for (const FString& HideCategory : ClassHideCategories) { @@ -368,7 +368,7 @@ bool FEditorCategoryUtils::IsCategoryHiddenFromClass(const TArray& Clas DisplayCategory.ParseIntoArray(SubCategoryList, TEXT("|"), /*InCullEmpty =*/true); FString FullSubCategoryPath; - for (FString const& SubCategory : SubCategoryList) + for (const FString& SubCategory : SubCategoryList) { FullSubCategoryPath += SubCategory; if ((HideCategory == SubCategory) || (HideCategory == FullSubCategoryPath)) @@ -410,7 +410,7 @@ void FEditorCategoryUtils::GetCategoryTooltipInfo(const FString& Category, FText } //------------------------------------------------------------------------------ -TSet FEditorCategoryUtils::GetHiddenCategories(UClass const* Class) +TSet FEditorCategoryUtils::GetHiddenCategories(const UClass* Class) { TArray ClassHiddenCategories; GetClassHideCategories(Class, ClassHiddenCategories); diff --git a/Engine/Source/Editor/UnrealEd/Private/EditorEngine.cpp b/Engine/Source/Editor/UnrealEd/Private/EditorEngine.cpp index 0a72f2acbff6..89f32ebf82aa 100644 --- a/Engine/Source/Editor/UnrealEd/Private/EditorEngine.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/EditorEngine.cpp @@ -148,8 +148,9 @@ #include "Interfaces/IProjectManager.h" #include "Misc/RemoteConfigIni.h" -#include "IDesktopPlatform.h" -#include "DesktopPlatformModule.h" +#include "AssetToolsModule.h" +#include "ObjectTools.h" +#include "MessageLogModule.h" #include "ActorEditorUtils.h" #include "SnappingUtils.h" @@ -184,6 +185,12 @@ #include "SourceCodeNavigation.h" #include "GameProjectUtils.h" +#include "ActorGroupingUtils.h" + +#include "DesktopPlatformModule.h" + +#include "ILauncherPlatform.h" +#include "LauncherPlatformModule.h" DEFINE_LOG_CATEGORY_STATIC(LogEditor, Log, All); @@ -241,14 +248,17 @@ static void PrivateInitSelectedSets() { PrivateGetSelectedActors() = NewObject(GetTransientPackage(), TEXT("SelectedActors"), RF_Transactional); PrivateGetSelectedActors()->AddToRoot(); + PrivateGetSelectedActors()->Initialize(&GSelectedActorAnnotation); PrivateGetSelectedActors()->SelectObjectEvent.AddStatic(&OnObjectSelected); PrivateGetSelectedComponents() = NewObject(GetTransientPackage(), TEXT("SelectedComponents"), RF_Transactional); PrivateGetSelectedComponents()->AddToRoot(); + PrivateGetSelectedComponents()->Initialize(&GSelectedComponentAnnotation); PrivateGetSelectedObjects() = NewObject(GetTransientPackage(), TEXT("SelectedObjects"), RF_Transactional); PrivateGetSelectedObjects()->AddToRoot(); + PrivateGetSelectedObjects()->Initialize(&GSelectedObjectAnnotation); } static void PrivateDestroySelectedSets() @@ -319,6 +329,8 @@ UEditorEngine::UEditorEngine(const FObjectInitializer& ObjectInitializer) EditorWorldExtensionsManager = nullptr; + ActorGroupingUtilsClassName = UActorGroupingUtils::StaticClass(); + #if !UE_BUILD_SHIPPING if (!AutomationCommon::OnEditorAutomationMapLoadDelegate().IsBound()) { @@ -569,11 +581,11 @@ void UEditorEngine::InitEditor(IEngineLoop* InEngineLoop) !FPlatformProcess::IsApplicationRunning(TEXT("EpicGamesLauncher-Mac-Shipping")) )) { - IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get(); - if ( DesktopPlatform != NULL ) + ILauncherPlatform* LauncherPlatform = FLauncherPlatformModule::Get(); + if (LauncherPlatform != NULL ) { FOpenLauncherOptions SilentOpen; - DesktopPlatform->OpenLauncher(SilentOpen); + LauncherPlatform->OpenLauncher(SilentOpen); } } @@ -943,7 +955,6 @@ void UEditorEngine::Init(IEngineLoop* InEngineLoop) if (!IsRunningCommandlet()) { - FModuleManager::Get().LoadModule(TEXT("EditorLiveStreaming")); FModuleManager::Get().LoadModule(TEXT("IntroTutorials")); } @@ -1534,12 +1545,6 @@ void UEditorEngine::Tick( float DeltaSeconds, bool bIdleMode ) // Skip updating reflection captures on the first update as the level will not be ready to display if (!bFirstTick) { - if (UReflectionCaptureComponent::MobileReflectionCapturesNeedForcedUpdate(EditorContext.World()) - || USkyLightComponent::MobileSkyCapturesNeedForcedUpdate(EditorContext.World())) - { - UpdateReflectionCaptures(); - } - // Update sky light first because sky diffuse will be visible in reflection capture indirect specular USkyLightComponent::UpdateSkyCaptureContents(EditorContext.World()); UReflectionCaptureComponent::UpdateReflectionCaptureContents(EditorContext.World()); @@ -1589,14 +1594,7 @@ void UEditorEngine::Tick( float DeltaSeconds, bool bIdleMode ) { // Decide whether to drop high detail because of frame rate GameViewport->SetDropDetail(DeltaSeconds); - } - - if (!bFirstTick) - { - // Update sky light first because sky diffuse will be visible in reflection capture indirect specular - USkyLightComponent::UpdateSkyCaptureContents(PlayWorld); - UReflectionCaptureComponent::UpdateReflectionCaptureContents(PlayWorld); - } + } // Update the level. GameCycles=0; @@ -1639,6 +1637,13 @@ void UEditorEngine::Tick( float DeltaSeconds, bool bIdleMode ) bAWorldTicked = true; TickType = LEVELTICK_All; + if (!bFirstTick) + { + // Update sky light first because sky diffuse will be visible in reflection capture indirect specular + USkyLightComponent::UpdateSkyCaptureContents(PlayWorld); + UReflectionCaptureComponent::UpdateReflectionCaptureContents(PlayWorld); + } + if( bIsRecordingActive ) { for( auto RecordedActorIter( RecordedActors.CreateIterator() ); RecordedActorIter; ++RecordedActorIter ) @@ -1749,10 +1754,10 @@ void UEditorEngine::Tick( float DeltaSeconds, bool bIdleMode ) bool bAllWindowsHidden = !bHasFocus && GEditor->AreAllWindowsHidden(); if( !bAllWindowsHidden ) { - FPixelInspectorModule* PixelInspectorModule = &FModuleManager::LoadModuleChecked(TEXT("PixelInspectorModule")); - if (PixelInspectorModule != nullptr && PixelInspectorModule->IsPixelInspectorEnable()) + FPixelInspectorModule& PixelInspectorModule = FModuleManager::LoadModuleChecked(TEXT("PixelInspectorModule")); + if (PixelInspectorModule.IsPixelInspectorEnable()) { - PixelInspectorModule->ReadBackSync(); + PixelInspectorModule.ReadBackSync(); } // Render view parents, then view children. @@ -3323,6 +3328,7 @@ struct FConvertStaticMeshActorInfo UStaticMesh* StaticMesh; USkeletalMesh* SkeletalMesh; TArray OverrideMaterials; + TArray IrrelevantLights; float CachedMaxDrawDistance; bool CastShadow; @@ -3345,7 +3351,7 @@ struct FConvertStaticMeshActorInfo * We don't want to simply copy all properties, because classes with different defaults will have * their defaults hosed by other types. */ - bool bComponentPropsDifferFromDefaults[6]; + bool bComponentPropsDifferFromDefaults[7]; AGroupActor* ActorGroup; @@ -4525,6 +4531,22 @@ FString UEditorEngine::GetFriendlyName( const UProperty* Property, UStruct* Owne return FoundText.ToString(); } +UActorGroupingUtils* UEditorEngine::GetActorGroupingUtils() +{ + if (ActorGroupingUtils == nullptr) + { + UClass* ActorGroupingUtilsClass = ActorGroupingUtilsClassName.ResolveClass(); + if (!ActorGroupingUtilsClass) + { + ActorGroupingUtilsClass = UActorGroupingUtils::StaticClass(); + } + + ActorGroupingUtils = NewObject(this, ActorGroupingUtilsClass); + } + + return ActorGroupingUtils; +} + AActor* UEditorEngine::UseActorFactoryOnCurrentSelection( UActorFactory* Factory, const FTransform* InActorTransform, EObjectFlags InObjectFlags ) { // ensure that all selected assets are loaded @@ -4684,12 +4706,12 @@ namespace ReattachActorsHelper AActor* ChildActor = CurrentAttachmentInfo.AttachedActors[AttachedActorIdx].Actor; ChildActor->Modify(); - ChildActor->DetachRootComponentFromParent(true); + ChildActor->DetachFromActor(FDetachmentTransformRules::KeepWorldTransform); } // Modify the actor so undo will reattach it. ActorToReattach->Modify(); - ActorToReattach->DetachRootComponentFromParent(true); + ActorToReattach->DetachFromActor(FDetachmentTransformRules::KeepWorldTransform); } } @@ -5643,9 +5665,10 @@ void UEditorEngine::DoConvertActors( const TArray& ActorsToConvert, UCl if (bUseSpecialCases) { // Disable grouping temporarily as the following code assumes only one actor will be selected at any given time - const bool bGroupingActiveSaved = GEditor->bGroupingActive; + const bool bGroupingActiveSaved = UActorGroupingUtils::IsGroupingActive(); + + UActorGroupingUtils::SetGroupingActive(false); - GEditor->bGroupingActive = false; GEditor->SelectNone(true, true); GEditor->SelectActor(ActorToConvert, true, true); @@ -5679,7 +5702,7 @@ void UEditorEngine::DoConvertActors( const TArray& ActorsToConvert, UCl } // Restore previous grouping setting - GEditor->bGroupingActive = bGroupingActiveSaved; + UActorGroupingUtils::SetGroupingActive(bGroupingActiveSaved); } @@ -6216,8 +6239,7 @@ void UEditorEngine::UpdatePreviewMesh() // Perform a line check from the camera eye to the surface to place the preview mesh. FHitResult Hit(ForceInit); - static FName UpdatePreviewMeshTrace = FName(TEXT("UpdatePreviewMeshTrace")); - FCollisionQueryParams LineParams(UpdatePreviewMeshTrace, true); + FCollisionQueryParams LineParams(SCENE_QUERY_STAT(UpdatePreviewMeshTrace), true); LineParams.bTraceComplex = false; if ( GWorld->LineTraceSingleByObjectType(Hit, LineCheckStart, LineCheckEnd, FCollisionObjectQueryParams(ECC_WorldStatic), LineParams) ) { @@ -6448,22 +6470,6 @@ void UEditorEngine::UpdateAutoLoadProject() } } - if(!FPlatformMisc::HasPlatformFeature(TEXT("Metal"))) - { - if(FSlateApplication::IsInitialized()) - { - FSuppressableWarningDialog::FSetupInfo Info(NSLOCTEXT("MessageDialog", "MessageMacOpenGLDeprecated","Support for running Unreal Engine 4 using OpenGL on macOS is deprecated and will be removed in a future release. Unreal Engine 4 may not render correctly and may run at substantially reduced performance."), NSLOCTEXT("MessageDialog", "TitleMacOpenGLDeprecated", "WARNING: OpenGL on macOS Deprecated"), TEXT("MacOpenGLDeprecated"), GEditorSettingsIni ); - Info.ConfirmText = LOCTEXT( "OK", "OK"); - Info.bDefaultToSuppressInTheFuture = true; - FSuppressableWarningDialog OSUpdateWarning( Info ); - OSUpdateWarning.ShowModal(); - } - else - { - UE_LOG(LogEditor, Warning, TEXT("Support for running Unreal Engine 4 using OpenGL on macOS is deprecated and will be removed in a future release. Unreal Engine 4 may not render correctly and may run at substantially reduced performance.")); - } - } - NSOpenGLContext* Context = [NSOpenGLContext currentContext]; const bool bTemporaryContext = (!Context); if(bTemporaryContext) @@ -6975,16 +6981,18 @@ void UEditorEngine::AutomationLoadMap(const FString& MapName, FString* OutError) { if (Context.World()) { + FString WorldPackage = Context.World()->GetOutermost()->GetName(); + if (Context.WorldType == EWorldType::PIE) { //don't quit! This was triggered while pie was already running! - bNeedPieStart = !MapName.Contains(Context.World()->GetName()); + bNeedPieStart = MapName != UWorld::StripPIEPrefixFromPackageName(WorldPackage, Context.World()->StreamingLevelsPrefix); bPieRunning = true; break; } else if (Context.WorldType == EWorldType::Editor) { - bNeedLoadEditorMap = !MapName.Contains(Context.World()->GetName()); + bNeedLoadEditorMap = MapName != WorldPackage; } } } @@ -7008,10 +7016,7 @@ void UEditorEngine::AutomationLoadMap(const FString& MapName, FString* OutError) { *OutError = TEXT("Error encountered."); } - } - if (bNeedPieStart) - { ADD_LATENT_AUTOMATION_COMMAND(FWaitForMapToLoadCommand); } #endif diff --git a/Engine/Source/Editor/UnrealEd/Private/EditorExporters.cpp b/Engine/Source/Editor/UnrealEd/Private/EditorExporters.cpp index 270d93cd12b1..a87a63f3279d 100644 --- a/Engine/Source/Editor/UnrealEd/Private/EditorExporters.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/EditorExporters.cpp @@ -491,14 +491,14 @@ bool ULevelExporterT3D::ExportText( const FExportObjectInnerContext* Context, UO AActor* ParentActor = Actor->GetAttachParentActor(); FName SocketName = Actor->GetAttachParentSocketName(); - Actor->DetachRootComponentFromParent(true); + Actor->DetachFromActor(FDetachmentTransformRules::KeepWorldTransform); FString ParentActorString = ( ParentActor ? FString::Printf(TEXT(" ParentActor=%s"), *ParentActor->GetName() ) : TEXT("")); FString SocketNameString = ( (ParentActor && SocketName != NAME_None) ? FString::Printf(TEXT(" SocketName=%s"), *SocketName.ToString() ) : TEXT("")); FString GroupActor = (Actor->GroupActor? FString::Printf(TEXT(" GroupActor=%s"), *Actor->GroupActor->GetName() ) : TEXT("")); Ar.Logf( TEXT("%sBegin Actor Class=%s Name=%s Archetype=%s'%s'%s%s%s") LINE_TERMINATOR, - FCString::Spc(TextIndent), *Actor->GetClass()->GetName(), *Actor->GetName(), - *Actor->GetArchetype()->GetClass()->GetName(), *Actor->GetArchetype()->GetPathName(), *ParentActorString, *SocketNameString, *GroupActor ); + FCString::Spc(TextIndent), *Actor->GetClass()->GetPathName(), *Actor->GetName(), + *Actor->GetArchetype()->GetClass()->GetPathName(), *Actor->GetArchetype()->GetPathName(), *ParentActorString, *SocketNameString, *GroupActor ); ExportRootScope = Actor; ExportObjectInner( Context, Actor, Ar, PortFlags | PPF_ExportsNotFullyQualified ); @@ -912,7 +912,7 @@ static void AddActorToOBJs(AActor* Actor, TArray& Objects, TSetIsRegistered() && StaticMeshComponent->GetStaticMesh() && StaticMeshComponent->GetStaticMesh()->HasValidRenderData() ) { - LocalToWorld = StaticMeshComponent->ComponentToWorld.ToMatrixWithScale(); + LocalToWorld = StaticMeshComponent->GetComponentTransform().ToMatrixWithScale(); StaticMesh = StaticMeshComponent->GetStaticMesh(); if (StaticMesh) { diff --git a/Engine/Source/Editor/UnrealEd/Private/EditorGroup.cpp b/Engine/Source/Editor/UnrealEd/Private/EditorGroup.cpp index ea4d114f865f..16206d361cdd 100644 --- a/Engine/Source/Editor/UnrealEd/Private/EditorGroup.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/EditorGroup.cpp @@ -10,199 +10,41 @@ #include "Engine/Selection.h" #include "Editor.h" #include "ScopedTransaction.h" +#include "ActorGroupingUtils.h" void UUnrealEdEngine::edactRegroupFromSelected() { - if(GEditor->bGroupingActive) - { - TArray ActorsToAdd; - - ULevel* ActorLevel = NULL; - - bool bActorsInSameLevel = true; - for ( FSelectionIterator It( GEditor->GetSelectedActorIterator() ); It; ++It ) - { - AActor* Actor = CastChecked(*It); - if( !ActorLevel ) - { - ActorLevel = Actor->GetLevel(); - } - else if( ActorLevel != Actor->GetLevel() ) - { - bActorsInSameLevel = false; - break; - } - - if ( Actor->IsA(AActor::StaticClass()) && !Actor->IsA(AGroupActor::StaticClass()) ) - { - // Add each selected actor to our new group - // Adding an actor will remove it from any existing groups. - ActorsToAdd.Add( Actor ); - - } - } - - if( bActorsInSameLevel ) - { - if( ActorsToAdd.Num() > 1 ) - { - check(ActorLevel); - // Store off the current level and make the level that contain the actors to group as the current level - UWorld* World = ActorLevel->OwningWorld; - check( World ); - { - const FScopedTransaction Transaction( NSLOCTEXT("UnrealEd", "Group_Regroup", "Regroup Ctrl+G") ); - - FActorSpawnParameters SpawnInfo; - SpawnInfo.OverrideLevel = ActorLevel; - AGroupActor* SpawnedGroupActor = World->SpawnActor( SpawnInfo ); - - for( int32 ActorIndex = 0; ActorIndex < ActorsToAdd.Num(); ++ActorIndex ) - { - SpawnedGroupActor->Add( *ActorsToAdd[ActorIndex] ); - } - - SpawnedGroupActor->CenterGroupLocation(); - SpawnedGroupActor->Lock(); - } - } - } - else - { - FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "Group_CantCreateGroupMultipleLevels", "Can't group the selected actors because they are in different levels.") ); - } - } + UActorGroupingUtils::Get()->GroupSelected(); } void UUnrealEdEngine::edactUngroupFromSelected() { - if(GEditor->bGroupingActive) - { - TArray OutermostGroupActors; - - for ( FSelectionIterator It( GEditor->GetSelectedActorIterator() ) ; It ; ++It ) - { - AActor* Actor = CastChecked( *It ); - - // Get the outermost locked group - AGroupActor* OutermostGroup = AGroupActor::GetRootForActor( Actor, true ); - if( OutermostGroup == NULL ) - { - // Failed to find locked root group, try to find the immediate parent - OutermostGroup = AGroupActor::GetParentForActor( Actor ); - } - - if( OutermostGroup ) - { - OutermostGroupActors.AddUnique( OutermostGroup ); - } - } - - if( OutermostGroupActors.Num() ) - { - const FScopedTransaction Transaction( NSLOCTEXT("UnrealEd", "Group_Disband", "Disband Group") ); - for( int32 GroupIndex = 0; GroupIndex < OutermostGroupActors.Num(); ++GroupIndex ) - { - AGroupActor* GroupActor = OutermostGroupActors[GroupIndex]; - GroupActor->ClearAndRemove(); - } - } - } + UActorGroupingUtils::Get()->UngroupSelected(); } void UUnrealEdEngine::edactLockSelectedGroups() { - if(GEditor->bGroupingActive) - { - AGroupActor::LockSelectedGroups(); - } + UActorGroupingUtils::Get()->LockSelectedGroups(); } void UUnrealEdEngine::edactUnlockSelectedGroups() { - if(GEditor->bGroupingActive) - { - AGroupActor::UnlockSelectedGroups(); - } + UActorGroupingUtils::Get()->UnlockSelectedGroups(); } void UUnrealEdEngine::edactAddToGroup() { - if(GEditor->bGroupingActive) - { - AGroupActor::AddSelectedActorsToSelectedGroup(); - } + UActorGroupingUtils::Get()->AddSelectedToGroup(); } void UUnrealEdEngine::edactRemoveFromGroup() { - if(GEditor->bGroupingActive) - { - TArray ActorsToRemove; - for ( FSelectionIterator It( GEditor->GetSelectedActorIterator() ) ; It ; ++It ) - { - AActor* Actor = static_cast( *It ); - checkSlow( Actor->IsA(AActor::StaticClass()) ); - - // See if an entire group is being removed - AGroupActor* GroupActor = Cast(Actor); - if(GroupActor == NULL) - { - // See if the actor selected belongs to a locked group, if so remove the group in lieu of the actor - GroupActor = AGroupActor::GetParentForActor(Actor); - if(GroupActor && !GroupActor->IsLocked()) - { - GroupActor = NULL; - } - } - - if(GroupActor) - { - // If the GroupActor has no parent, do nothing, otherwise just add the group for removal - if(AGroupActor::GetParentForActor(GroupActor)) - { - ActorsToRemove.AddUnique(GroupActor); - } - } - else - { - ActorsToRemove.AddUnique(Actor); - } - } - - const FScopedTransaction Transaction( NSLOCTEXT("UnrealEd", "Group_Remove", "Remove from Group") ); - for ( int32 ActorIndex = 0; ActorIndex < ActorsToRemove.Num(); ++ActorIndex ) - { - AActor* Actor = ActorsToRemove[ActorIndex]; - AGroupActor* ActorGroup = AGroupActor::GetParentForActor(Actor); - - if(ActorGroup) - { - AGroupActor* ActorGroupParent = AGroupActor::GetParentForActor(ActorGroup); - if(ActorGroupParent) - { - ActorGroupParent->Add(*Actor); - ActorGroupParent->CenterGroupLocation(); - } - else - { - ActorGroup->Remove(*Actor); - ActorGroup->CenterGroupLocation(); - } - } - } - // Do a re-selection of each actor, to maintain group selection rules - GEditor->SelectNone(true, true); - for ( int32 ActorIndex = 0; ActorIndex < ActorsToRemove.Num(); ++ActorIndex ) - { - GEditor->SelectActor( ActorsToRemove[ActorIndex], true, false); - } - } + UActorGroupingUtils::Get()->RemoveSelectedFromGroup(); } diff --git a/Engine/Source/Editor/UnrealEd/Private/EditorLevelUtils.cpp b/Engine/Source/Editor/UnrealEd/Private/EditorLevelUtils.cpp index 5fdcff72a5d9..7ad6412fe936 100644 --- a/Engine/Source/Editor/UnrealEd/Private/EditorLevelUtils.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/EditorLevelUtils.cpp @@ -50,104 +50,142 @@ DEFINE_LOG_CATEGORY(LogLevelTools); #define LOCTEXT_NAMESPACE "EditorLevelUtils" -namespace EditorLevelUtils + +int32 UEditorLevelUtils::MoveActorsToLevel(const TArray& ActorsToMove, ULevelStreaming* DestStreamingLevel) { - /** - * Moves the specified list of actors to the specified level - * - * @param ActorsToMove List of actors to move - * @param DestLevelStreaming The level streaming object associated with the destination level - * @param OutNumMovedActors The number of actors that were successfully moved to the new level - */ - void MovesActorsToLevel( TArray< AActor* >& ActorsToMove, ULevelStreaming* DestLevelStreaming, int32& OutNumMovedActors ) + return MoveActorsToLevel(ActorsToMove, DestStreamingLevel->GetLoadedLevel()); +} + +int32 UEditorLevelUtils::MoveActorsToLevel(const TArray& ActorsToMove, ULevel* DestLevel) +{ + int32 NumMovedActors = 0; + + if (DestLevel) { + UWorld* OwningWorld = DestLevel->OwningWorld; + // Backup the current contents of the clipboard string as we'll be using cut/paste features to move actors // between levels and this will trample over the clipboard data. FString OriginalClipboardContent; FPlatformMisc::ClipboardPaste(OriginalClipboardContent); - check( DestLevelStreaming != NULL ); - ULevel* DestLevel = DestLevelStreaming->GetLoadedLevel(); - check( DestLevel != NULL ); - // Cache a the destination world - UWorld* World = DestLevel->OwningWorld; + // The final list of actors to move after invalid actors were removed + TArray FinalMoveList; + FinalMoveList.Reserve(ActorsToMove.Num()); - // Deselect all actors - GEditor->Exec( World, TEXT("ACTOR SELECT NONE")); - - const FString& NewLevelName = DestLevelStreaming->GetWorldAssetPackageName(); - - for( TArray< AActor* >::TIterator CurActorIt( ActorsToMove ); CurActorIt; ++CurActorIt ) + bool bIsDestLevelLocked = FLevelUtils::IsLevelLocked(DestLevel); + if (!bIsDestLevelLocked) { - AActor* CurActor = *CurActorIt; - check( CurActor != NULL ); - - if( !FLevelUtils::IsLevelLocked( DestLevel ) && !FLevelUtils::IsLevelLocked( CurActor ) ) + for (AActor* CurActor : ActorsToMove) { - ULevelStreaming* ActorPrevLevel = FLevelUtils::FindStreamingLevel( CurActor->GetLevel() ); - const FString& PrevLevelName = ActorPrevLevel != NULL ? ActorPrevLevel->GetWorldAssetPackageName() : CurActor->GetLevel()->GetName(); - UE_LOG(LogLevelTools, Warning, TEXT( "AutoLevel: Moving %s from %s to %s" ), *CurActor->GetName(), *PrevLevelName, *NewLevelName ); - - // Select this actor - GEditor->SelectActor( CurActor, true, false, true ); - // Cache the world the actor is in, or if we already did ensure its the same world. - check( World == CurActor->GetWorld() ); - } - else - { - // Either the source or destination level was locked! - // @todo: Display warning - } - } - - OutNumMovedActors = 0; - if( GEditor->GetSelectedActorCount() > 0 ) - { - // @todo: Perf: Not sure if this is needed here. - GEditor->NoteSelectionChange(); - - // Move the actors! - GEditor->MoveSelectedActorsToLevel( DestLevel ); - - // The moved (pasted) actors will now be selected - OutNumMovedActors += GEditor->GetSelectedActorCount(); - } - - // Restore the original clipboard contents - FPlatformMisc::ClipboardCopy( *OriginalClipboardContent ); - } - - static TArray GStreamingMethodStrings; - static TArray GStreamingMethodClassList; - - /** - * Initializes the list of possible level streaming methods. - * Does nothing if the lists are already initialized. - */ - void InitializeStreamingMethods() - { - check( GStreamingMethodStrings.Num() == GStreamingMethodClassList.Num() ); - if ( GStreamingMethodClassList.Num() == 0 ) - { - // Assemble a list of possible level streaming methods. - for ( TObjectIterator It ; It ; ++It ) - { - if ( It->IsChildOf( ULevelStreaming::StaticClass() ) && - (It->HasAnyClassFlags(CLASS_EditInlineNew)) && - !(It->HasAnyClassFlags(CLASS_Hidden | CLASS_Abstract | CLASS_Deprecated | CLASS_Transient))) + if (!CurActor) { - const FString ClassName( It->GetName() ); - // Strip the leading "LevelStreaming" text from the class name. - // @todo DB: This assumes the names of all ULevelStreaming-derived types begin with the string "LevelStreaming". - GStreamingMethodStrings.Add( ClassName.Mid( 14 ) ); - GStreamingMethodClassList.Add( *It ); + continue; + } + + bool bIsSourceLevelLocked = FLevelUtils::IsLevelLocked(CurActor); + + if (!bIsSourceLevelLocked) + { + if (CurActor->GetLevel() != DestLevel) + { + FinalMoveList.Add(CurActor); + } + else + { + UE_LOG(LogLevelTools, Warning, TEXT("%s is already in the destination level so it was ignored"), *CurActor->GetName()); + } + } + else + { + UE_LOG(LogLevelTools, Error, TEXT("The source level '%s' is locked so actors could not be moved"), *CurActor->GetLevel()->GetName()); } } } + else + { + UE_LOG(LogLevelTools, Error, TEXT("The destination level '%s' is locked so actors could not be moved"), *DestLevel->GetName()); + } + + + if (FinalMoveList.Num() > 0) + { + GEditor->SelectNone(false, true, false); + + USelection* ActorSelection = GEditor->GetSelectedActors(); + ActorSelection->BeginBatchSelectOperation(); + for (AActor* Actor : FinalMoveList) + { + GEditor->SelectActor(Actor, true, false); + } + ActorSelection->EndBatchSelectOperation(false); + + if (GEditor->GetSelectedActorCount() > 0) + { + // Start the transaction + FScopedTransaction Transaction(NSLOCTEXT("UnrealEd", "MoveSelectedActorsToSelectedLevel", "Move Actors To Level")); + + // Cache the old level + ULevel* OldCurrentLevel = OwningWorld->GetCurrentLevel(); + + // Copy the actors we have selected to the clipboard + GEditor->CopySelectedActorsToClipboard(OwningWorld, true); + + // Set the new level and force it visible while we do the paste + OwningWorld->SetCurrentLevel(DestLevel); + const bool bLevelVisible = DestLevel->bIsVisible; + if (!bLevelVisible) + { + UEditorLevelUtils::SetLevelVisibility(DestLevel, true, false); + } + + // Paste the actors into the new level + GEditor->edactPasteSelected(OwningWorld, false, false, false); + + // Restore new level visibility to previous state + if (!bLevelVisible) + { + UEditorLevelUtils::SetLevelVisibility(DestLevel, false, false); + } + + // Restore the original current level + OwningWorld->SetCurrentLevel(OldCurrentLevel); + } + + // The moved (pasted) actors will now be selected + NumMovedActors += FinalMoveList.Num(); + } + + // Restore the original clipboard contents + FPlatformMisc::ClipboardCopy(*OriginalClipboardContent); } - ULevel* AddLevelsToWorld(UWorld* InWorld, const TArray& LevelPackageNames, UClass* LevelStreamingClass) + + return NumMovedActors; +} + +int32 UEditorLevelUtils::MoveSelectedActorsToLevel(ULevelStreaming* DestStreamingLevel) + { + return MoveSelectedActorsToLevel(DestStreamingLevel->GetLoadedLevel()); +} + +int32 UEditorLevelUtils::MoveSelectedActorsToLevel(ULevel* DestLevel) + { + TArray ActorsToMove; + for (FSelectionIterator It(GEditor->GetSelectedActorIterator()); It; ++It) + { + if (AActor* Actor = Cast(*It)) + { + ActorsToMove.Add(Actor); + } + } + + return MoveActorsToLevel(ActorsToMove, DestLevel); + + } + +ULevel* UEditorLevelUtils::AddLevelsToWorld(UWorld* InWorld, const TArray& LevelPackageNames, UClass* LevelStreamingClass) { if ( !ensure(InWorld) ) { @@ -171,7 +209,8 @@ namespace EditorLevelUtils { SlowTask.EnterProgressFrame(); - NewLevel = AddLevelToWorld(InWorld, *PackageName, LevelStreamingClass); + ULevelStreaming* NewStreamingLevel = AddLevelToWorld(InWorld, *PackageName, LevelStreamingClass); + NewLevel = NewStreamingLevel->GetLoadedLevel(); if (NewLevel) { LevelDirtyCallback.Request(); @@ -203,9 +242,10 @@ namespace EditorLevelUtils return NewLevel; } - ULevel* AddLevelToWorld( UWorld* InWorld, const TCHAR* LevelPackageName, UClass* LevelStreamingClass) +ULevelStreaming* UEditorLevelUtils::AddLevelToWorld( UWorld* InWorld, const TCHAR* LevelPackageName, TSubclassOf LevelStreamingClass) { - ULevel* NewLevel = NULL; + ULevel* NewLevel = nullptr; + ULevelStreaming* StreamingLevel = nullptr; bool bIsPersistentLevel = (InWorld->PersistentLevel->GetOutermost()->GetName() == FString(LevelPackageName)); if ( bIsPersistentLevel || FLevelUtils::FindStreamingLevel( InWorld, LevelPackageName ) ) @@ -216,14 +256,14 @@ namespace EditorLevelUtils else { // If the selected class is still NULL, abort the operation. - if ( LevelStreamingClass == NULL ) + if ( LevelStreamingClass == nullptr) { - return NULL; + return nullptr; } const FScopedBusyCursor BusyCursor; - ULevelStreaming* StreamingLevel = NewObject(InWorld, LevelStreamingClass, NAME_None, RF_NoFlags, NULL); + StreamingLevel = NewObject(InWorld, LevelStreamingClass, NAME_None, RF_NoFlags, NULL); // Associate a package name. StreamingLevel->SetWorldAssetByPackageName(LevelPackageName); @@ -266,10 +306,10 @@ namespace EditorLevelUtils FEditorDelegates::OnAddLevelToWorld.Broadcast(NewLevel); } - return NewLevel; + return StreamingLevel; } - ULevelStreaming* SetStreamingClassForLevel(ULevelStreaming* InLevel, UClass* LevelStreamingClass) +ULevelStreaming* UEditorLevelUtils::SetStreamingClassForLevel(ULevelStreaming* InLevel, TSubclassOf LevelStreamingClass) { check(InLevel); @@ -304,7 +344,7 @@ namespace EditorLevelUtils return NewStreamingLevel; } - void MakeLevelCurrent(ULevel* InLevel) +void UEditorLevelUtils::MakeLevelCurrent(ULevel* InLevel) { // Locked levels can't be made current. if ( !FLevelUtils::IsLevelLocked( InLevel ) ) @@ -344,13 +384,12 @@ namespace EditorLevelUtils } } - /** - * Removes a LevelStreaming from the world. Returns true if the LevelStreaming was removed successfully. - * - * @param InLevelStreaming The LevelStreaming to remove. - * @return true if the LevelStreaming was removed successfully, false otherwise. - */ - bool PrivateRemoveInvalidLevelFromWorld(ULevelStreaming* InLevelStreaming) +void UEditorLevelUtils::MakeLevelCurrent(ULevelStreaming* InStreamingLevel) +{ + MakeLevelCurrent(InStreamingLevel->GetLoadedLevel()); +} + +bool UEditorLevelUtils::PrivateRemoveInvalidLevelFromWorld(ULevelStreaming* InLevelStreaming) { bool bRemovedLevelStreaming = false; if (InLevelStreaming != NULL) @@ -384,7 +423,7 @@ namespace EditorLevelUtils return bRemovedLevelStreaming; } - bool RemoveInvalidLevelFromWorld(ULevelStreaming* InLevelStreaming) +bool UEditorLevelUtils::RemoveInvalidLevelFromWorld(ULevelStreaming* InLevelStreaming) { bool bRemoveSuccessful = PrivateRemoveInvalidLevelFromWorld(InLevelStreaming); if (bRemoveSuccessful) @@ -404,7 +443,94 @@ namespace EditorLevelUtils return bRemoveSuccessful; } - bool RemoveLevelFromWorld(ULevel* InLevel) + +ULevelStreaming* UEditorLevelUtils::CreateNewStreamingLevel(TSubclassOf LevelStreamingClass, const FString& PackagePath /*= TEXT("")*/, bool bMoveSelectedActorsIntoNewLevel /*= false*/) +{ + FString Filename; + if (PackagePath.IsEmpty() || FPackageName::TryConvertLongPackageNameToFilename(PackagePath, Filename, FPackageName::GetMapPackageExtension())) + { + return CreateNewStreamingLevelForWorld(*GEditor->GetEditorWorldContext().World(), LevelStreamingClass, Filename, bMoveSelectedActorsIntoNewLevel); + } + + return nullptr; +} + + +ULevelStreaming* UEditorLevelUtils::CreateNewStreamingLevelForWorld(UWorld& InWorld, TSubclassOf LevelStreamingClass, const FString& DefaultFilename /* = TEXT( "" ) */, bool bMoveSelectedActorsIntoNewLevel /* = false */) +{ + // Editor modes cannot be active when any level saving occurs. + GLevelEditorModeTools().DeactivateAllModes(); + + // This is the world we are adding the new level to + UWorld* WorldToAddLevelTo = &InWorld; + + // This is the new streaming level's world not the persistent level world + UWorld* NewLevelWorld = nullptr; + if (UEditorEngine::IsUsingWorldAssets()) + { + // Create a new world + UWorldFactory* Factory = NewObject(); + Factory->WorldType = EWorldType::Inactive; + UPackage* Pkg = CreatePackage(NULL, NULL); + FName WorldName(TEXT("Untitled")); + EObjectFlags Flags = RF_Public | RF_Standalone; + NewLevelWorld = CastChecked(Factory->FactoryCreateNew(UWorld::StaticClass(), Pkg, WorldName, Flags, NULL, GWarn)); + if (NewLevelWorld) + { + FAssetRegistryModule::AssetCreated(NewLevelWorld); + } + } + else + { + // Create a new world - so we can 'borrow' its level + NewLevelWorld = UWorld::CreateWorld(EWorldType::None, false); + check(NewLevelWorld); + } + + // Save the new world to disk. + const bool bNewWorldSaved = FEditorFileUtils::SaveLevel(NewLevelWorld->PersistentLevel, DefaultFilename); + FString NewPackageName; + if (bNewWorldSaved) + { + NewPackageName = NewLevelWorld->GetOutermost()->GetName(); + } + + if (!UEditorEngine::IsUsingWorldAssets()) + { + // Destroy the new world we created and collect the garbage + NewLevelWorld->DestroyWorld(false); + CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS); + } + + // If the new world was saved successfully, import it as a streaming level. + ULevelStreaming* NewStreamingLevel = nullptr; + ULevel* NewLevel = nullptr; + if (bNewWorldSaved) + { + NewStreamingLevel = AddLevelToWorld(WorldToAddLevelTo, *NewPackageName, LevelStreamingClass); + NewLevel = NewStreamingLevel->GetLoadedLevel(); + // If we are moving the selected actors to the new level move them now + if (bMoveSelectedActorsIntoNewLevel) + { + MoveSelectedActorsToLevel(NewStreamingLevel); + } + + // Finally make the new level the current one + if (WorldToAddLevelTo->SetCurrentLevel(NewLevel)) + { + FEditorDelegates::NewCurrentLevel.Broadcast(); + } + } + + // Broadcast the levels have changed (new style) + WorldToAddLevelTo->BroadcastLevelsChanged(); + FEditorDelegates::RefreshLevelBrowser.Broadcast(); + + return NewStreamingLevel; +} + + +bool UEditorLevelUtils::RemoveLevelFromWorld(ULevel* InLevel) { if (GEditor->Layers.IsValid()) { @@ -454,13 +580,7 @@ namespace EditorLevelUtils } - /** - * Removes a level from the world. Returns true if the level was removed successfully. - * - * @param InLevel The level to remove from the world. - * @return true if the level was removed successfully, false otherwise. - */ - bool PrivateRemoveLevelFromWorld(ULevel* InLevel) +bool UEditorLevelUtils::PrivateRemoveLevelFromWorld(ULevel* InLevel) { if ( !InLevel || InLevel->IsPersistentLevel() ) { @@ -540,7 +660,7 @@ namespace EditorLevelUtils return true; } - bool EditorDestroyLevel(ULevel* InLevel) +bool UEditorLevelUtils::EditorDestroyLevel(ULevel* InLevel) { UWorld* World = InLevel->OwningWorld; @@ -565,72 +685,13 @@ namespace EditorLevelUtils return true; } - ULevel* CreateNewLevel( UWorld* InWorld, bool bMoveSelectedActorsIntoNewLevel, UClass* LevelStreamingClass, const FString& DefaultFilename ) - { - // Editor modes cannot be active when any level saving occurs. - GLevelEditorModeTools().DeactivateAllModes(); - - UWorld* NewWorld = nullptr; - if (UEditorEngine::IsUsingWorldAssets()) +ULevel* UEditorLevelUtils::CreateNewLevel( UWorld* InWorld, bool bMoveSelectedActorsIntoNewLevel, TSubclassOf LevelStreamingClass, const FString& DefaultFilename ) { - // Create a new world - UWorldFactory* Factory = NewObject(); - Factory->WorldType = EWorldType::Inactive; - UPackage* Pkg = CreatePackage(NULL, NULL); - FName WorldName(TEXT("Untitled")); - EObjectFlags Flags = RF_Public | RF_Standalone; - NewWorld = CastChecked(Factory->FactoryCreateNew(UWorld::StaticClass(), Pkg, WorldName, Flags, NULL, GWarn)); - if ( NewWorld ) - { - FAssetRegistryModule::AssetCreated(NewWorld); - } - } - else - { - // Create a new world - so we can 'borrow' its level - NewWorld = UWorld::CreateWorld(EWorldType::None, false ); - check(NewWorld); + ULevelStreaming* StreamingLevel = CreateNewStreamingLevelForWorld(*InWorld, LevelStreamingClass, DefaultFilename, bMoveSelectedActorsIntoNewLevel); + return StreamingLevel->GetLoadedLevel(); } - // Save the new world to disk. - const bool bNewWorldSaved = FEditorFileUtils::SaveLevel( NewWorld->PersistentLevel, DefaultFilename ); - FString NewPackageName; - if ( bNewWorldSaved ) - { - NewPackageName = NewWorld->GetOutermost()->GetName(); - } - - if (!UEditorEngine::IsUsingWorldAssets()) - { - // Destroy the new world we created and collect the garbage - NewWorld->DestroyWorld( false ); - CollectGarbage( GARBAGE_COLLECTION_KEEPFLAGS ); - } - - // If the new world was saved successfully, import it as a streaming level. - ULevel* NewLevel = NULL; - if ( bNewWorldSaved ) - { - NewLevel = AddLevelToWorld( InWorld, *NewPackageName, LevelStreamingClass ); - - // If we are moving the selected actors to the new level move them now - if ( bMoveSelectedActorsIntoNewLevel ) - { - GEditor->MoveSelectedActorsToLevel( NewLevel ); - } - // Finally make the new level the current one - if (InWorld->SetCurrentLevel(NewLevel)) - { - FEditorDelegates::NewCurrentLevel.Broadcast(); - } - } - - // Broadcast the levels have changed (new style) - InWorld->BroadcastLevelsChanged(); - return NewLevel; - } - - void DeselectAllSurfacesInLevel(ULevel* InLevel) +void UEditorLevelUtils::DeselectAllSurfacesInLevel(ULevel* InLevel) { if(InLevel) { @@ -647,7 +708,7 @@ namespace EditorLevelUtils } } - void SetLevelVisibility(ULevel* Level, bool bShouldBeVisible, bool bForceLayersVisible) +void UEditorLevelUtils::SetLevelVisibility(ULevel* Level, bool bShouldBeVisible, bool bForceLayersVisible) { // Nothing to do if ( Level == NULL ) @@ -855,18 +916,11 @@ namespace EditorLevelUtils if (Level->bIsLightingScenario) { - Level->OwningWorld->PropagateLightingScenarioChange(); + Level->OwningWorld->PropagateLightingScenarioChange(bShouldBeVisible); } } - /** - * Assembles the set of all referenced worlds. - * - * @param OutWorlds [out] The set of referenced worlds. - * @param bIncludeGWorld If true, include GWorld in the output list. - * @param bOnlyEditorVisible If true, only sub-levels that should be visible in-editor are included - */ - void GetWorlds(UWorld* InWorld, TArray& OutWorlds, bool bIncludeInWorld, bool bOnlyEditorVisible) +void UEditorLevelUtils::GetWorlds(UWorld* InWorld, TArray& OutWorlds, bool bIncludeInWorld, bool bOnlyEditorVisible) { OutWorlds.Empty(); @@ -922,6 +976,4 @@ namespace EditorLevelUtils } } -} - #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Editor/UnrealEd/Private/EditorModeInterpolation.cpp b/Engine/Source/Editor/UnrealEd/Private/EditorModeInterpolation.cpp index 11c6bae496b5..640a71b9ec11 100644 --- a/Engine/Source/Editor/UnrealEd/Private/EditorModeInterpolation.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/EditorModeInterpolation.cpp @@ -17,6 +17,7 @@ #include "Editor/Matinee/Public/IMatinee.h" #include "Framework/Notifications/NotificationManager.h" #include "Widgets/Notifications/SNotificationList.h" +#include "ActorGroupingUtils.h" static const float CurveHandleScale = 0.5f; @@ -65,8 +66,8 @@ void FEdModeInterpEdit::Enter() FEdMode::Enter(); // Disable Grouping while in InterpEdit mode - bGroupingActiveSaved = GEditor->bGroupingActive; - GEditor->bGroupingActive = false; + bGroupingActiveSaved = UActorGroupingUtils::IsGroupingActive(); + UActorGroupingUtils::SetGroupingActive(false); } void FEdModeInterpEdit::Exit() @@ -86,7 +87,7 @@ void FEdModeInterpEdit::Exit() InterpEd = NULL; // Grouping is always disabled while in InterpEdit Mode, re-enable the saved value on exit - GEditor->bGroupingActive = bGroupingActiveSaved; + UActorGroupingUtils::SetGroupingActive(bGroupingActiveSaved); AGroupActor::SelectGroupsInSelection(); FEdMode::Exit(); diff --git a/Engine/Source/Editor/UnrealEd/Private/EditorObject.cpp b/Engine/Source/Editor/UnrealEd/Private/EditorObject.cpp index eabd23cfa4c8..957b1f2590f7 100644 --- a/Engine/Source/Editor/UnrealEd/Private/EditorObject.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/EditorObject.cpp @@ -369,7 +369,7 @@ static const TCHAR* ImportProperties( FParse::Value(StrPtr, TEXT("Flags="), Instance.Flags); // Add the instance - MeshInfo->AddInstance(IFA, FoliageType, Instance, ActorComponent); + MeshInfo->AddInstance(IFA, FoliageType, Instance, ActorComponent, true); } } } @@ -496,13 +496,6 @@ static const TCHAR* ImportProperties( } else // handle the non-template case (subobjects and non-template components) { - // don't allow Actor-derived subobjects - if ( TemplateClass->IsChildOf(AActor::StaticClass()) ) - { - Warn->Logf(ELogVerbosity::Error,TEXT("Cannot create subobjects from Actor-derived classes: %s"), *StrLine); - return NULL; - } - ComponentTemplate = FindObject(SubobjectOuter, *TemplateName.ToString()); if (ComponentTemplate != NULL) { diff --git a/Engine/Source/Editor/UnrealEd/Private/EditorSelectUtils.cpp b/Engine/Source/Editor/UnrealEd/Private/EditorSelectUtils.cpp index 15dbd1129665..71da24bb929e 100644 --- a/Engine/Source/Editor/UnrealEd/Private/EditorSelectUtils.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/EditorSelectUtils.cpp @@ -25,6 +25,7 @@ #include "StatsViewerModule.h" #include "SnappingUtils.h" #include "Logging/MessageLog.h" +#include "ActorGroupingUtils.h" #define LOCTEXT_NAMESPACE "EditorSelectUtils" @@ -94,7 +95,7 @@ void UUnrealEdEngine::NoteActorMovement() Actor->Modify(); - if (GEditor->bGroupingActive) + if (UActorGroupingUtils::IsGroupingActive()) { // if this actor is in a group, add the GroupActor into a list to be modified shortly AGroupActor* ActorLockedRootGroup = AGroupActor::GetRootForActor(Actor, true); @@ -219,7 +220,7 @@ void UUnrealEdEngine::SetPivot( FVector NewPivot, bool bSnapPivotToGrid, bool bI ++SnapCount; } - if( bAssignPivot && LastSelectedActor && GEditor->bGroupingActive ) + if( bAssignPivot && LastSelectedActor && UActorGroupingUtils::IsGroupingActive()) { // set group pivot for the root-most group AGroupActor* ActorGroupRoot = AGroupActor::GetRootForActor(LastSelectedActor, true, true); @@ -364,7 +365,7 @@ void UUnrealEdEngine::UpdatePivotLocationForSelection( bool bOnChange ) FVector PivotPoint = SingleActor->GetTransform().TransformPosition(SingleActor->GetPivotOffset()); // If grouping is active, see if this actor is part of a locked group and use that pivot instead - if(GEditor->bGroupingActive) + if(UActorGroupingUtils::IsGroupingActive()) { AGroupActor* ActorGroupRoot = AGroupActor::GetRootForActor(SingleActor, true, true); if(ActorGroupRoot) @@ -523,7 +524,7 @@ bool UUnrealEdEngine::CanSelectActor(AActor* Actor, bool bInSelected, bool bSele // If grouping operations are not currently allowed, don't select groups. AGroupActor* SelectedGroupActor = Cast(Actor); - if( SelectedGroupActor && !GEditor->bGroupingActive ) + if( SelectedGroupActor && !UActorGroupingUtils::IsGroupingActive()) { return false; } @@ -569,7 +570,7 @@ void UUnrealEdEngine::SelectActor(AActor* Actor, bool bInSelected, bool bNotify, } } - if (GEditor->bGroupingActive) + if (UActorGroupingUtils::IsGroupingActive()) { // if this actor is a group, do a group select/deselect AGroupActor* SelectedGroupActor = Cast(Actor); diff --git a/Engine/Source/Editor/UnrealEd/Private/EditorServer.cpp b/Engine/Source/Editor/UnrealEd/Private/EditorServer.cpp index 3f737c6c9c1d..876d5d2f86ae 100644 --- a/Engine/Source/Editor/UnrealEd/Private/EditorServer.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/EditorServer.cpp @@ -144,7 +144,6 @@ #include "ShaderCompiler.h" #include "Framework/Notifications/NotificationManager.h" #include "Widgets/Notifications/SNotificationList.h" -#include "DesktopPlatformModule.h" #include "Animation/AnimNotifies/AnimNotify.h" #include "AI/Navigation/NavLinkRenderingComponent.h" #include "Analytics/AnalyticsPrivacySettings.h" @@ -152,6 +151,9 @@ #include "AnalyticsEventAttribute.h" #include "Developer/SlateReflector/Public/ISlateReflectorModule.h" #include "MaterialUtilities.h" +#include "ActorGroupingUtils.h" +#include "ILauncherPlatform.h" +#include "LauncherPlatformModule.h" DEFINE_LOG_CATEGORY_STATIC(LogEditorServer, Log, All); @@ -176,12 +178,12 @@ namespace FWaveCluster(const TCHAR* InName) : Name( InName ) , Num( 0 ) - , Size( ) + , Size( 0 ) {} FString Name; int32 Num; - FResourceSizeEx Size; + int32 Size; }; struct FAnimSequenceUsageInfo @@ -600,37 +602,6 @@ bool UEditorEngine::Exec_StaticMesh( UWorld* InWorld, const TCHAR* Str, FOutputD GetSelectedObjects()->Select( StaticMesh ); } } - else if (FParse::Command(&Str, TEXT("FORCELODGROUP"))) // STATICMESH FORCELODGROUP - { - FName NewGroup(Str); - if (NewGroup != NAME_None) - { - // get the selected meshes - TArray SelectedMeshes; - for (FSelectionIterator Iter(GetSelectedActorIterator()); Iter; ++Iter) - { - TInlineComponentArray SMComps(CastChecked(*Iter)); - for (UStaticMeshComponent* SMC : SMComps) - { - if (SMC->GetStaticMesh()) - { - SelectedMeshes.AddUnique(SMC->GetStaticMesh()); - } - } - - } - - // look at all loaded static meshes - for (UStaticMesh* SM : SelectedMeshes) - { - // update any mesh not already in a group - if (!SM->IsTemplate() && SM->LODGroup == NAME_None) - { - SM->SetLODGroup(NewGroup); - } - } - } - } #endif // UE_BUILD_SHIPPING return bResult; } @@ -810,10 +781,7 @@ bool UEditorEngine::Exec_Brush( UWorld* InWorld, const TCHAR* Str, FOutputDevice InWorld->GetModel()->Modify(); NewBrush->Modify(); - FlushRenderingCommands(); - ABrush::GGeometryRebuildCause = TEXT("Add Brush"); bspBrushCSG( NewBrush, InWorld->GetModel(), DWord1, Brush_Add, CSG_None, true, true, true ); - ABrush::GGeometryRebuildCause = nullptr; } InWorld->InvalidateModelGeometry( InWorld->GetCurrentLevel() ); } @@ -897,10 +865,7 @@ bool UEditorEngine::Exec_Brush( UWorld* InWorld, const TCHAR* Str, FOutputDevice { NewBrush->Modify(); InWorld->GetModel()->Modify(); - FlushRenderingCommands(); - ABrush::GGeometryRebuildCause = TEXT("Subtract Brush"); bspBrushCSG( NewBrush, InWorld->GetModel(), 0, Brush_Subtract, CSG_None, true, true, true ); - ABrush::GGeometryRebuildCause = nullptr; } InWorld->InvalidateModelGeometry( InWorld->GetCurrentLevel() ); } @@ -1233,13 +1198,13 @@ void UEditorEngine::CreateStartupAnalyticsAttributes( TArrayCanOpenLauncher(bIncludeLauncherInstaller); + bool bIsLauncherInstalled = LauncherPlatform->CanOpenLauncher(bIncludeLauncherInstaller); StartSessionAttributes.Add(FAnalyticsEventAttribute(TEXT("IsLauncherInstalled"), bIsLauncherInstalled)); } } @@ -1749,9 +1714,6 @@ void UEditorEngine::RebuildModelFromBrushes(UModel* Model, bool bSelectedBrushes const int32 NumVectors = Model->Vectors.Num(); const int32 NumSurfs = Model->Surfs.Num(); - // Debug purposes only; an attempt to catch the cause of UE-36265 - ABrush::GGeometryRebuildCause = TEXT("RebuildModelFromBrushes"); - Model->Modify(); Model->EmptyModel(1, 1); @@ -1842,9 +1804,6 @@ void UEditorEngine::RebuildModelFromBrushes(UModel* Model, bool bSelectedBrushes FBSPOps::csgPrepMovingBrush(DynamicBrush); } - // Debug purposes only; an attempt to catch the cause of UE-36265 - ABrush::GGeometryRebuildCause = nullptr; - FBspPointsGrid::GBspPoints = nullptr; FBspPointsGrid::GBspVectors = nullptr; } @@ -1947,9 +1906,7 @@ void UEditorEngine::BSPIntersectionHelper(UWorld* InWorld, ECsgOper Operation) DefaultBrush->Modify(); InWorld->GetModel()->Modify(); FinishAllSnaps(); - ABrush::GGeometryRebuildCause = TEXT("BSPIntersectionHelper"); bspBrushCSG(DefaultBrush, InWorld->GetModel(), 0, Brush_MAX, Operation, false, true, true); - ABrush::GGeometryRebuildCause = nullptr; } } @@ -2566,8 +2523,6 @@ bool UEditorEngine::Map_Load(const TCHAR* Str, FOutputDevice& Ar) World->WorldType = EWorldType::Editor; - Context.World()->PersistentLevel->HandleLegacyMapBuildData(); - // Parse requested feature level if supplied int32 FeatureLevelIndex = (int32)GMaxRHIFeatureLevel; FParse::Value(Str, TEXT("FEATURELEVEL="), FeatureLevelIndex); @@ -2743,6 +2698,9 @@ bool UEditorEngine::Map_Load(const TCHAR* Str, FOutputDevice& Ar) // Invalidate all the level viewport hit proxies RedrawLevelEditingViewports(); + + // Collect any stale components or other objects that are no longer required after loading the map + CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS, true); } } else @@ -2993,9 +2951,7 @@ public: *OutClipboardContents = *ScratchData; } - // Do not warn if we are only copying not pasint as we are not actually deleting anything from the real level - const bool bWarnAboutReferencedActors = !bCopyOnly; - GEditor->edactDeleteSelected( World, false, bWarnAboutReferencedActors); + GEditor->edactDeleteSelected( World, false ); } if( DestLevel ) @@ -3051,123 +3007,9 @@ public: void UEditorEngine::MoveSelectedActorsToLevel( ULevel* InDestLevel ) { // do the actual work... - DoMoveSelectedActorsToLevel( InDestLevel ); + UEditorLevelUtils::MoveSelectedActorsToLevel( InDestLevel ); } -void UEditorEngine::DoMoveSelectedActorsToLevel( ULevel* InDestLevel ) -{ - // Can't move into a locked level - if (FLevelUtils::IsLevelLocked(InDestLevel)) - { - FNotificationInfo Info(NSLOCTEXT("UnrealEd", "CannotMoveIntoLockedLevel", "Cannot move the selected actors into a locked level")); - Info.bUseThrobber = false; - FSlateNotificationManager::Get().AddNotification(Info)->SetCompletionState(SNotificationItem::CS_Fail); - return; - } - - // Find actors that are already in the destination level and deselect them - { - TArray ActorsToDeselect; - for (FSelectionIterator It(GetSelectedActorIterator()); It; ++It) - { - AActor* Actor = static_cast(*It); - if ( Actor && Actor->GetLevel() == InDestLevel ) - { - ActorsToDeselect.Add(Actor); - } - } - - for ( auto* Actor : ActorsToDeselect ) - { - const bool bInSelected = false; - const bool bNotify = false; - SelectActor(Actor, bInSelected, bNotify); - } - } - - if (GetSelectedActorCount() <= 0) - { - // Nothing to move, probably source level was hidden and actors lost selection mark or all actors were already in the destination level - return; - } - - // Start the transaction - GEditor->Trans->Begin( NULL, NSLOCTEXT("UnrealEd", "MoveSelectedActorsToSelectedLevel", "Move Actors To Level")); - - // Get a world context - UWorld* World = InDestLevel->OwningWorld; - - // Cache the old level - ULevel* OldCurrentLevel = World->GetCurrentLevel(); - - // Grab the location of the first selected actor. Even though there may be many actors selected - // we'll make sure we find an appropriately destination level for the first actor. The other - // actors will be moved to their appropriate levels automatically afterwards. - FVector FirstSelectedActorLocation = FVector::ZeroVector; - AActor* FirstActor = Cast< AActor >( *GetSelectedActorIterator() ); - if ( FirstActor ) - { - FirstSelectedActorLocation = FirstActor->GetActorLocation(); - } - - // Copy the actors we have selected to the clipboard - CopySelectedActorsToClipboard( World, true ); - - // Set the new level and force it visible while we do the paste - World->SetCurrentLevel( InDestLevel ); - const bool bLevelVisible = InDestLevel->bIsVisible; - if (!bLevelVisible) - { - EditorLevelUtils::SetLevelVisibility(InDestLevel, true, false); - } - - // Paste the actors into the new level - edactPasteSelected( World, false, false, false ); - - // Restore new level visibility to previous state - if (!bLevelVisible) - { - EditorLevelUtils::SetLevelVisibility(InDestLevel, false, false); - } - - // Restore the original current level - World->SetCurrentLevel( OldCurrentLevel ); - - // End the transaction - GEditor->Trans->End(); -} - -void UEditorEngine::MoveSelectedFoliageToLevel(ULevel* InTargetLevel) -{ - // Can't move into a locked level - if (FLevelUtils::IsLevelLocked(InTargetLevel)) - { - FNotificationInfo Info(NSLOCTEXT("UnrealEd", "CannotMoveFoliageIntoLockedLevel", "Cannot move the selected foliage into a locked level")); - Info.bUseThrobber = false; - FSlateNotificationManager::Get().AddNotification(Info)->SetCompletionState(SNotificationItem::CS_Fail); - return; - } - - const FScopedTransaction Transaction(NSLOCTEXT("UnrealEd", "MoveSelectedFoliageToSelectedLevel", "Move Selected Foliage to Level")); - - // Get a world context - UWorld* World = InTargetLevel->OwningWorld; - - // Iterate over all foliage actors in the world and move selected instances to a foliage actor in the target level - const int32 NumLevels = World->GetNumLevels(); - for (int32 LevelIdx = 0; LevelIdx < NumLevels; ++LevelIdx) - { - ULevel* Level = World->GetLevel(LevelIdx); - if (Level != InTargetLevel) - { - AInstancedFoliageActor* IFA = AInstancedFoliageActor::GetInstancedFoliageActorForLevel(Level, /*bCreateIfNone*/ false); - if (IFA && IFA->HasSelectedInstances()) - { - IFA->MoveSelectedInstancesToLevel(InTargetLevel); - } - } - } -} TArray UEditorEngine::GetFoliageTypesInWorld(UWorld* InWorld) { @@ -3572,11 +3414,11 @@ void UEditorEngine::PasteSelectedActorsFromClipboard( UWorld* InWorld, const FTe AActor* ParentActor = Actor->GetAttachParentActor(); FName SocketName = Actor->GetAttachParentSocketName(); - Actor->DetachRootComponentFromParent(true); + Actor->DetachFromActor(FDetachmentTransformRules::KeepWorldTransform); AttachData.Emplace(ParentActor, SocketName); // If this actor is in a group, add it to the list - if (GEditor->bGroupingActive) + if (UActorGroupingUtils::IsGroupingActive()) { AGroupActor* ActorGroupRoot = AGroupActor::GetRootForActor(Actor, true, true); if (ActorGroupRoot) @@ -3604,7 +3446,7 @@ void UEditorEngine::PasteSelectedActorsFromClipboard( UWorld* InWorld, const FTe SetPivot( SingleActor->GetActorLocation(), false, true ); // If grouping is active, go through the unique group actors and update the group actor location - if (GEditor->bGroupingActive) + if (UActorGroupingUtils::IsGroupingActive()) { for (AGroupActor* GroupActor : GroupActors) { @@ -4991,7 +4833,7 @@ bool UEditorEngine::SnapObjectTo( FActorOrComponent Object, const bool InAlign, // Do the actual actor->world check. We try to collide against the world, straight down from our current position. // If we hit anything, we will move the actor to a position that lets it rest on the floor. FHitResult Hit(1.0f); - FCollisionQueryParams Params(FName(TEXT("MoveActorToTrace")), false); + FCollisionQueryParams Params(SCENE_QUERY_STAT(MoveActorToTrace), false); if( Object.Actor ) { Params.AddIgnoredActor( Object.Actor ); @@ -6379,14 +6221,15 @@ bool UEditorEngine::HandleBugItGoCommand( const TCHAR* Str, FOutputDevice& Ar ) bool UEditorEngine::HandleTagSoundsCommand( const TCHAR* Str, FOutputDevice& Ar ) { int32 NumObjects = 0; - SIZE_T TotalSize = 0; + int32 TotalSize = 0; for( FObjectIterator It(USoundWave::StaticClass()); It; ++It ) { ++NumObjects; DebugSoundAnnotation.Set(*It); USoundWave* Wave = static_cast(*It); - TotalSize += Wave->GetResourceSizeBytes(EResourceSizeMode::Exclusive); + const SIZE_T Size = Wave->GetResourceSizeBytes(EResourceSizeMode::Exclusive); + TotalSize += Size; } UE_LOG(LogEditorServer, Log, TEXT("Marked %i sounds %10.2fMB"), NumObjects, ((float)TotalSize) /(1024.f*1024.f) ); return true; @@ -6425,20 +6268,19 @@ bool UEditorEngine::HandlecheckSoundsCommand( const TCHAR* Str, FOutputDevice& A const int32 NumCoreClusters = Clusters.Num(); // Output information. + int32 TotalSize = 0; UE_LOG(LogEditorServer, Log, TEXT("=================================================================================") ); UE_LOG(LogEditorServer, Log, TEXT("%60s %10s"), TEXT("Wave Name"), TEXT("Size") ); for ( int32 WaveIndex = 0 ; WaveIndex < WaveList.Num() ; ++WaveIndex ) { USoundWave* Wave = WaveList[WaveIndex]; + const SIZE_T WaveSize = Wave->GetResourceSizeBytes(EResourceSizeMode::Exclusive); UPackage* WavePackage = Wave->GetOutermost(); const FString PackageName( WavePackage->GetName() ); - FResourceSizeEx WaveResourceSize = FResourceSizeEx(EResourceSizeMode::Exclusive); - Wave->GetResourceSizeEx(WaveResourceSize); - // Totals. Clusters[0].Num++; - Clusters[0].Size += WaveResourceSize; + Clusters[0].Size += WaveSize; // Core clusters for ( int32 ClusterIndex = 1 ; ClusterIndex < NumCoreClusters ; ++ClusterIndex ) @@ -6447,7 +6289,7 @@ bool UEditorEngine::HandlecheckSoundsCommand( const TCHAR* Str, FOutputDevice& A if ( PackageName.Find( Cluster.Name ) != -1 ) { Cluster.Num++; - Cluster.Size += WaveResourceSize; + Cluster.Size += WaveSize; } } @@ -6460,7 +6302,7 @@ bool UEditorEngine::HandlecheckSoundsCommand( const TCHAR* Str, FOutputDevice& A { // Found a cluster with this package name. Cluster.Num++; - Cluster.Size += WaveResourceSize; + Cluster.Size += WaveSize; bFoundMatch = true; break; } @@ -6470,17 +6312,17 @@ bool UEditorEngine::HandlecheckSoundsCommand( const TCHAR* Str, FOutputDevice& A // Create a new cluster with the package name. FWaveCluster NewCluster( *PackageName ); NewCluster.Num = 1; - NewCluster.Size = WaveResourceSize; + NewCluster.Size = WaveSize; Clusters.Add( NewCluster ); } // Dump bulk sound list. - UE_LOG(LogEditorServer, Log, TEXT("%70s %10.2fk"), *Wave->GetPathName(), ((float)WaveResourceSize.GetTotalMemoryBytes())/1024.f ); + UE_LOG(LogEditorServer, Log, TEXT("%70s %10.2fk"), *Wave->GetPathName(), ((float)WaveSize)/1024.f ); } UE_LOG(LogEditorServer, Log, TEXT("=================================================================================") ); UE_LOG(LogEditorServer, Log, TEXT("%60s %10s %10s"), TEXT("Cluster Name"), TEXT("Num"), TEXT("Size") ); UE_LOG(LogEditorServer, Log, TEXT("=================================================================================") ); - FResourceSizeEx TotalClusteredSize; + int32 TotalClusteredSize = 0; for ( int32 ClusterIndex = 0 ; ClusterIndex < Clusters.Num() ; ++ClusterIndex ) { const FWaveCluster& Cluster = Clusters[ClusterIndex]; @@ -6489,10 +6331,10 @@ bool UEditorEngine::HandlecheckSoundsCommand( const TCHAR* Str, FOutputDevice& A UE_LOG(LogEditorServer, Log, TEXT("---------------------------------------------------------------------------------") ); TotalClusteredSize += Cluster.Size; } - UE_LOG(LogEditorServer, Log, TEXT("%60s %10i %10.2fMB"), *Cluster.Name, Cluster.Num, ((float)Cluster.Size.GetTotalMemoryBytes())/(1024.f*1024.f) ); + UE_LOG(LogEditorServer, Log, TEXT("%60s %10i %10.2fMB"), *Cluster.Name, Cluster.Num, ((float)Cluster.Size)/(1024.f*1024.f) ); } UE_LOG(LogEditorServer, Log, TEXT("=================================================================================") ); - UE_LOG(LogEditorServer, Log, TEXT("Total Clusterd: %10.2fMB"), ((float)TotalClusteredSize.GetTotalMemoryBytes())/(1024.f*1024.f) ); + UE_LOG(LogEditorServer, Log, TEXT("Total Clusterd: %10.2fMB"), ((float)TotalClusteredSize)/(1024.f*1024.f) ); return true; } @@ -6767,7 +6609,7 @@ bool IsComponentMergable(UStaticMeshComponent* Component) } // we need a static mesh to work - if (Component->GetStaticMesh() == nullptr || Component->GetStaticMesh()->RenderData == nullptr) + if (Component->GetStaticMesh() == NULL || Component->GetStaticMesh()->RenderData == NULL) { return false; } @@ -6978,7 +6820,7 @@ void UEditorEngine::AutoMergeStaticMeshes() UStaticMeshComponent* Component = MergeComponents[ComponentIndex]; // calculate a matrix to go from my component space to the owner's component's space - FMatrix TransformToOwnerSpace = Component->ComponentToWorld.ToMatrixWithScale() * OwnerComponent->ComponentToWorld.ToMatrixWithScale().Inverse(); + FMatrix TransformToOwnerSpace = Component->GetComponentTransform().ToMatrixWithScale() * OwnerComponent->GetComponentTransform().ToMatrixWithScale().Inverse(); // if we have negative scale, we need to munge the matrix and scaling if (TransformToOwnerSpace.Determinant() < 0.0f) diff --git a/Engine/Source/Editor/UnrealEd/Private/EditorViewportClient.cpp b/Engine/Source/Editor/UnrealEd/Private/EditorViewportClient.cpp index d4d3c426308c..b565d53fd8a6 100644 --- a/Engine/Source/Editor/UnrealEd/Private/EditorViewportClient.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/EditorViewportClient.cpp @@ -13,6 +13,7 @@ #include "CanvasItem.h" #include "Engine/Canvas.h" #include "Settings/LevelEditorViewportSettings.h" +#include "Settings/LevelEditorMiscSettings.h" #include "Components/DirectionalLightComponent.h" #include "Components/BillboardComponent.h" #include "Debug/DebugDrawService.h" @@ -77,15 +78,12 @@ float ComputeOrthoZoomFactor(const float ViewportWidth) void PixelInspectorRealtimeManagement(FEditorViewportClient *CurrentViewport, bool bMouseEnter) { - FPixelInspectorModule* PixelInspectorModule = &FModuleManager::LoadModuleChecked(TEXT("PixelInspectorModule")); - if (PixelInspectorModule != nullptr) + FPixelInspectorModule& PixelInspectorModule = FModuleManager::LoadModuleChecked(TEXT("PixelInspectorModule")); + bool bViewportIsRealtime = CurrentViewport->IsRealtime(); + bool bViewportShouldBeRealtime = PixelInspectorModule.GetViewportRealtime(CurrentViewport->ViewIndex, bViewportIsRealtime, bMouseEnter); + if (bViewportIsRealtime != bViewportShouldBeRealtime) { - bool bViewportIsRealtime = CurrentViewport->IsRealtime(); - bool bViewportShouldBeRealtime = PixelInspectorModule->GetViewportRealtime(CurrentViewport->ViewIndex, bViewportIsRealtime, bMouseEnter); - if (bViewportIsRealtime != bViewportShouldBeRealtime) - { - CurrentViewport->SetRealtime(bViewportShouldBeRealtime); - } + CurrentViewport->SetRealtime(bViewportShouldBeRealtime); } } @@ -299,6 +297,7 @@ FEditorViewportClient::FEditorViewportClient(FEditorModeTools* InModeTools, FPre , bOwnsModeTools(false) , ModeTools(InModeTools) , Widget(new FWidget) + , bShowWidget(true) , MouseDeltaTracker(new FMouseDeltaTracker) , RecordingInterpEd(NULL) , bHasMouseMovedSinceClick(false) @@ -318,6 +317,7 @@ FEditorViewportClient::FEditorViewportClient(FEditorModeTools* InModeTools, FPre , CurrentGestureRotDelta(FRotator::ZeroRotator) , GestureMoveForwardBackwardImpulse(0.0f) , bForceAudioRealtime(false) + , RealTimeFrameCount(0) , bIsRealtime(false) , bStoredRealtime(false) , bStoredShowStats(false) @@ -3190,9 +3190,9 @@ void FEditorViewportClient::DrawCanvas(FViewport& InViewport, FSceneView& View, ModeTools->DrawHUD(this, &InViewport, &View, &Canvas); } -void FEditorViewportClient::SetupViewForRendering( FSceneViewFamily& ViewFamily, FSceneView& View ) +void FEditorViewportClient::SetupViewForRendering(FSceneViewFamily& ViewFamily, FSceneView& View) { - if(ViewFamily.EngineShowFlags.Wireframe) + if (ViewFamily.EngineShowFlags.Wireframe) { // Wireframe color is emissive-only, and mesh-modifying materials do not use material substitution, hence... View.DiffuseOverrideParameter = FVector4(0.f, 0.f, 0.f, 0.f); @@ -3203,7 +3203,7 @@ void FEditorViewportClient::SetupViewForRendering( FSceneViewFamily& ViewFamily, View.DiffuseOverrideParameter = FVector4(GEngine->LightingOnlyBrightness.R, GEngine->LightingOnlyBrightness.G, GEngine->LightingOnlyBrightness.B, 0.0f); View.SpecularOverrideParameter = FVector4(.1f, .1f, .1f, 0.0f); } - else if( ViewFamily.EngineShowFlags.ReflectionOverride) + else if (ViewFamily.EngineShowFlags.ReflectionOverride) { View.DiffuseOverrideParameter = FVector4(0.f, 0.f, 0.f, 0.f); View.SpecularOverrideParameter = FVector4(1, 1, 1, 0.0f); @@ -3225,49 +3225,51 @@ void FEditorViewportClient::SetupViewForRendering( FSceneViewFamily& ViewFamily, //Look if the pixel inspector tool is on View.bUsePixelInspector = false; - FPixelInspectorModule* PixelInspectorModule = &FModuleManager::LoadModuleChecked(TEXT("PixelInspectorModule")); - if (PixelInspectorModule != nullptr) + FPixelInspectorModule& PixelInspectorModule = FModuleManager::LoadModuleChecked(TEXT("PixelInspectorModule")); + bool IsInspectorActive = PixelInspectorModule.IsPixelInspectorEnable(); + View.bUsePixelInspector = IsInspectorActive; + FIntPoint InspectViewportPos = FIntPoint(-1, -1); + if (IsInspectorActive) { - bool IsInspectorActive = PixelInspectorModule->IsPixelInspectorEnable(); - View.bUsePixelInspector = IsInspectorActive; - FIntPoint InspectViewportPos = FIntPoint(-1, -1); - if (IsInspectorActive) + if (CurrentMousePos == FIntPoint(-1, -1)) { - if (CurrentMousePos == FIntPoint(-1, -1)) + uint32 CoordinateViewportId = 0; + PixelInspectorModule.GetCoordinatePosition(InspectViewportPos, CoordinateViewportId); + bool IsCoordinateInViewport = InspectViewportPos.X <= Viewport->GetSizeXY().X && InspectViewportPos.Y <= Viewport->GetSizeXY().Y; + IsInspectorActive = IsCoordinateInViewport && (CoordinateViewportId == View.State->GetViewKey()); + if (IsInspectorActive) { - uint32 CoordinateViewportId = 0; - PixelInspectorModule->GetCoordinatePosition(InspectViewportPos, CoordinateViewportId); - bool IsCoordinateInViewport = InspectViewportPos.X <= Viewport->GetSizeXY().X && InspectViewportPos.Y <= Viewport->GetSizeXY().Y; - IsInspectorActive = IsCoordinateInViewport && (CoordinateViewportId == View.State->GetViewKey()); - if (IsInspectorActive) - { - PixelInspectorModule->SetViewportInformation(View.State->GetViewKey(), Viewport->GetSizeXY()); - } - } - else - { - InspectViewportPos = CurrentMousePos; - PixelInspectorModule->SetViewportInformation(View.State->GetViewKey(), Viewport->GetSizeXY()); - PixelInspectorModule->SetCoordinatePosition(CurrentMousePos, false); + PixelInspectorModule.SetViewportInformation(View.State->GetViewKey(), Viewport->GetSizeXY()); } } + else + { + InspectViewportPos = CurrentMousePos; + PixelInspectorModule.SetViewportInformation(View.State->GetViewKey(), Viewport->GetSizeXY()); + PixelInspectorModule.SetCoordinatePosition(CurrentMousePos, false); + } + } - if (IsInspectorActive) - { - // Ready to send a request - FSceneInterface *SceneInterface = GetScene(); - PixelInspectorModule->CreatePixelInspectorRequest(InspectViewportPos, View.State->GetViewKey(), SceneInterface); - } - else if (!View.bUsePixelInspector && CurrentMousePos != FIntPoint(-1, -1)) - { - //Track in case the user hit esc key to stop inspecting pixel - PixelInspectorRealtimeManagement(this, true); - } + if (IsInspectorActive) + { + // Ready to send a request + FSceneInterface *SceneInterface = GetScene(); + PixelInspectorModule.CreatePixelInspectorRequest(InspectViewportPos, View.State->GetViewKey(), SceneInterface); + } + else if (!View.bUsePixelInspector && CurrentMousePos != FIntPoint(-1, -1)) + { + //Track in case the user hit esc key to stop inspecting pixel + PixelInspectorRealtimeManagement(this, true); } } void FEditorViewportClient::Draw(FViewport* InViewport, FCanvas* Canvas) { + if (RealTimeFrameCount > 0) + { + --RealTimeFrameCount; + } + FViewport* ViewportBackup = Viewport; Viewport = InViewport ? InViewport : Viewport; @@ -3309,7 +3311,7 @@ void FEditorViewportClient::Draw(FViewport* InViewport, FCanvas* Canvas) GetScene(), EngineShowFlags) .SetWorldTimes( TimeSeconds, DeltaTimeSeconds, RealTimeSeconds ) - .SetRealtimeUpdate( IsRealtime() ) + .SetRealtimeUpdate( IsRealtime() && FSlateThrottleManager::Get().IsAllowingExpensiveTasks() ) .SetViewModeParam( ViewModeParam, ViewModeParamName ) ); ViewFamily.EngineShowFlags = EngineShowFlags; @@ -3408,7 +3410,7 @@ void FEditorViewportClient::Draw(FViewport* InViewport, FCanvas* Canvas) // Draw the widget. - if (Widget) + if (Widget && bShowWidget) { Widget->DrawHUD( Canvas ); } @@ -3505,7 +3507,10 @@ void FEditorViewportClient::Draw(const FSceneView* View, FPrimitiveDrawInterface MouseDeltaTracker->Render3DDragTool( View, PDI ); // Draw the widget. - Widget->Render( View, PDI, this ); + if (Widget && bShowWidget) + { + Widget->Render( View, PDI, this ); + } if( bUsesDrawHelper ) { @@ -4386,6 +4391,11 @@ FVector FEditorViewportClient::GetHitProxyObjectLocation(int32 X, int32 Y) } +void FEditorViewportClient::ShowWidget(const bool bShow) +{ + bShowWidget = bShow; +} + void FEditorViewportClient::MoveViewportCamera(const FVector& InDrag, const FRotator& InRot, bool bDollyCamera) { switch( GetViewportType() ) @@ -4892,14 +4902,15 @@ void FEditorViewportClient::TakeScreenshot(FViewport* InViewport, bool bInValida } // Create screenshot folder if not already present. - if ( IFileManager::Get().MakeDirectory( *FPaths::ScreenShotDir(), true ) ) + + if ( IFileManager::Get().MakeDirectory(*(GetDefault()->EditorScreenshotSaveDirectory.Path), true ) ) { // Save the contents of the array to a bitmap file. FHighResScreenshotConfig& HighResScreenshotConfig = GetHighResScreenshotConfig(); HighResScreenshotConfig.SetHDRCapture(false); FString ScreenshotSaveName; - if (FFileHelper::GenerateNextBitmapFilename(FPaths::ScreenShotDir() / TEXT("ScreenShot"), TEXT("png"), ScreenshotSaveName) && + if (FFileHelper::GenerateNextBitmapFilename(GetDefault()->EditorScreenshotSaveDirectory.Path / TEXT("ScreenShot"), TEXT("png"), ScreenshotSaveName) && HighResScreenshotConfig.SaveImage(ScreenshotSaveName, Bitmap, InViewport->GetSizeXY())) { // Setup the string with the path and name of the file @@ -4918,7 +4929,7 @@ void FEditorViewportClient::TakeScreenshot(FViewport* InViewport, bool bInValida { // Failed to make save directory ScreenshotSaveResultText = NSLOCTEXT( "UnrealEd", "ScreenshotFailedFolder", "Screenshot capture failed, unable to create save directory (see log)" ); - UE_LOG(LogEditorViewport, Warning, TEXT("Failed to create directory %s"), *FPaths::ConvertRelativePathToFull(FPaths::ScreenShotDir())); + UE_LOG(LogEditorViewport, Warning, TEXT("Failed to create directory %s"), *FPaths::ConvertRelativePathToFull(GetDefault()->EditorScreenshotSaveDirectory.Path)); } } else diff --git a/Engine/Source/Editor/UnrealEd/Private/EditorWorldExtension.cpp b/Engine/Source/Editor/UnrealEd/Private/EditorWorldExtension.cpp index e6083607bb1e..55e45643e2f7 100644 --- a/Engine/Source/Editor/UnrealEd/Private/EditorWorldExtension.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/EditorWorldExtension.cpp @@ -217,6 +217,23 @@ FWorldContext* UEditorWorldExtensionCollection::GetWorldContext() const return WorldContext; } +UEditorWorldExtension* UEditorWorldExtensionCollection::AddExtension(TSubclassOf EditorExtensionClass) +{ + UEditorWorldExtension* Extension = nullptr; + UEditorWorldExtension* FoundExtension = FindExtension(EditorExtensionClass); + if (FoundExtension != nullptr) + { + Extension = FoundExtension; + } + else + { + Extension = NewObject(this, EditorExtensionClass); + } + + AddExtension(Extension); + return Extension; +} + void UEditorWorldExtensionCollection::AddExtension( UEditorWorldExtension* EditorExtension ) { check( EditorExtension != nullptr ); @@ -335,6 +352,7 @@ void UEditorWorldExtensionCollection::ShowAllActors(const bool bShow) } } + void UEditorWorldExtensionCollection::PostPIEStarted( bool bIsSimulatingInEditor ) { if( bIsSimulatingInEditor && GEditor->EditorWorld != nullptr && GEditor->EditorWorld == WorldContext->World() ) @@ -370,6 +388,8 @@ void UEditorWorldExtensionCollection::OnEndPIE( bool bWasSimulatingInEditor ) { if( !GIsRequestingExit ) { + UWorld* SimulateWorld = WorldContext->World(); + // Revert back to the editor world before closing the play world, otherwise actors and objects will be destroyed. SetWorldContext( EditorWorldOnSimulate ); EditorWorldOnSimulate = nullptr; @@ -377,7 +397,7 @@ void UEditorWorldExtensionCollection::OnEndPIE( bool bWasSimulatingInEditor ) for( FEditorExtensionTuple& EditorExtensionTuple : EditorExtensions ) { UEditorWorldExtension* EditorExtension = EditorExtensionTuple.Get<0>(); - EditorExtension->LeftSimulateInEditor(); + EditorExtension->LeftSimulateInEditor(SimulateWorld); } } } diff --git a/Engine/Source/Editor/UnrealEd/Private/Factories/ActorFactory.cpp b/Engine/Source/Editor/UnrealEd/Private/Factories/ActorFactory.cpp index ab1913ba4fe1..6f66b8444b48 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Factories/ActorFactory.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Factories/ActorFactory.cpp @@ -128,7 +128,7 @@ ActorFactory.cpp: #include "LevelSequenceActor.h" #include "Factories/ActorFactoryMovieScene.h" -DEFINE_LOG_CATEGORY_STATIC(LogActorFactory, Log, All); +DEFINE_LOG_CATEGORY(LogActorFactory); #define LOCTEXT_NAMESPACE "ActorFactory" @@ -262,13 +262,12 @@ AActor* UActorFactory::CreateActor( UObject* Asset, ULevel* InLevel, FTransform if ( NewActor ) { PostSpawnActor(Asset, NewActor); - } - - // Only do this if the actor wasn't already given a name - if (Name == NAME_None && Asset) - { - FActorLabelUtilities::SetActorLabelUnique(NewActor, Asset->GetName()); + // Only do this if the actor wasn't already given a name + if (Name == NAME_None && Asset) + { + FActorLabelUtilities::SetActorLabelUnique(NewActor, Asset->GetName()); + } } } diff --git a/Engine/Source/Editor/UnrealEd/Private/Factories/ApexDestructibleAssetImport.cpp b/Engine/Source/Editor/UnrealEd/Private/Factories/ApexDestructibleAssetImport.cpp index 6ee0d224bc98..e0401e19f50f 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Factories/ApexDestructibleAssetImport.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Factories/ApexDestructibleAssetImport.cpp @@ -43,7 +43,7 @@ DEFINE_LOG_CATEGORY_STATIC(LogApexDestructibleAssetImport, Log, All); // Forward declarations and external processing functions struct ExistingSkelMeshData; extern ExistingSkelMeshData* SaveExistingSkelMeshData(USkeletalMesh* ExistingSkelMesh, bool bSaveMaterials, int32 ReimportLODIndex); -extern void RestoreExistingSkelMeshData(ExistingSkelMeshData* MeshData, USkeletalMesh* SkeletalMesh, int32 ReimportLODIndex); +extern void RestoreExistingSkelMeshData(ExistingSkelMeshData* MeshData, USkeletalMesh* SkeletalMesh, int32 ReimportLODIndex, bool bResetMaterialSlots, bool bIsReimportPreview); extern void ProcessImportMeshInfluences(FSkeletalMeshImportData& ImportData); extern void ProcessImportMeshMaterials(TArray& Materials, FSkeletalMeshImportData& ImportData); extern bool ProcessImportMeshSkeleton(const USkeleton* SkeletonAsset, FReferenceSkeleton& RefSkeleton, int32& SkeletalDepth, FSkeletalMeshImportData& ImportData); @@ -256,7 +256,7 @@ static void RestoreExistingDestMeshData(ExistingDestMeshData* MeshData, UDestruc // Restore old settings, but resize arrays to make sense with the new NxDestructibleAsset if (MeshData->SkelMeshData != NULL) { - RestoreExistingSkelMeshData(MeshData->SkelMeshData, DestructibleMesh, INDEX_NONE); + RestoreExistingSkelMeshData(MeshData->SkelMeshData, DestructibleMesh, INDEX_NONE, false, false); } DestructibleMesh->BodySetup = MeshData->BodySetup; DestructibleMesh->FractureEffects = MeshData->FractureEffects; diff --git a/Engine/Source/Editor/UnrealEd/Private/Factories/EditorFactories.cpp b/Engine/Source/Editor/UnrealEd/Private/Factories/EditorFactories.cpp index 7e7f20c7d0ad..f31601842b56 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Factories/EditorFactories.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Factories/EditorFactories.cpp @@ -237,7 +237,7 @@ #include "Haptics/HapticFeedbackEffect_Buffer.h" #include "Haptics/HapticFeedbackEffect_SoundWave.h" #include "DataTableEditorUtils.h" -#include "Editor/KismetCompiler/Public/KismetCompilerModule.h" +#include "KismetCompilerModule.h" #include "Factories/SubUVAnimationFactory.h" #include "Particles/SubUVAnimation.h" #include "Kismet2/BlueprintEditorUtils.h" @@ -247,8 +247,11 @@ #include "Factories/PreviewMeshCollectionFactory.h" #include "Factories/ForceFeedbackAttenuationFactory.h" #include "FileHelper.h" +#include "ActorGroupingUtils.h" -DEFINE_LOG_CATEGORY_STATIC(LogEditorFactories, Log, All); +#include "Editor/EditorPerProjectUserSettings.h" + +DEFINE_LOG_CATEGORY(LogEditorFactories); #define LOCTEXT_NAMESPACE "EditorFactories" @@ -260,14 +263,14 @@ class FAssetClassParentFilter : public IClassViewerFilter { public: FAssetClassParentFilter() - : DisallowedClassFlags(0), bDisallowBlueprintBase(false) + : DisallowedClassFlags(CLASS_None), bDisallowBlueprintBase(false) {} /** All children of these classes will be included unless filtered out by another setting. */ TSet< const UClass* > AllowedChildrenOfClasses; /** Disallowed class flags. */ - uint32 DisallowedClassFlags; + EClassFlags DisallowedClassFlags; /** Disallow blueprint base classes. */ bool bDisallowBlueprintBase; @@ -758,7 +761,7 @@ UObject* ULevelFactory::FactoryCreateText if( NewActor ) { - if( GEditor->bGroupingActive && !Cast(NewActor) ) + if( UActorGroupingUtils::IsGroupingActive() && !Cast(NewActor) ) { bool bGrouped = false; @@ -989,26 +992,18 @@ UObject* ULevelFactory::FactoryCreateText // Import properties if the new actor is bool bActorChanged = false; - FString* PropText = &(ActorMapElement.Value); - if( PropText ) + FString& PropText = ActorMapElement.Value; + if ( Actor->ShouldImport(&PropText, bIsMoveToStreamingLevel) ) { - if ( Actor->ShouldImport(PropText, bIsMoveToStreamingLevel) ) - { - Actor->PreEditChange(nullptr); - ImportObjectProperties( (uint8*)Actor, **PropText, Actor->GetClass(), Actor, Actor, Warn, 0, INDEX_NONE, NULL, &ExistingToNewMap ); - bActorChanged = true; + Actor->PreEditChange(nullptr); + ImportObjectProperties( (uint8*)Actor, *PropText, Actor->GetClass(), Actor, Actor, Warn, 0, INDEX_NONE, NULL, &ExistingToNewMap ); + bActorChanged = true; - GEditor->SelectActor( Actor, true, false, true ); - } - else // This actor is new, but rejected to import its properties, so just delete... - { - Actor->Destroy(); - } + GEditor->SelectActor( Actor, true, false, true ); } - else - if( !Actor->IsA(AInstancedFoliageActor::StaticClass()) ) + else // This actor is new, but rejected to import its properties, so just delete... { - // This actor is old + Actor->Destroy(); } // If this is a newly imported brush, validate it. If it's a newly imported dynamic brush, rebuild it first. @@ -4977,18 +4972,24 @@ EReimportResult::Type UReimportFbxStaticMeshFactory::Reimport( UObject* Obj ) { ImportUI = NewObject(this, NAME_None, RF_Public); } + const bool ShowImportDialogAtReimport = GetDefault()->bShowImportDialogAtReimport && !GIsAutomationTesting; - if( ImportData ) + if( ImportData && !ShowImportDialogAtReimport) { // Import data already exists, apply it to the fbx import options ReimportUI->StaticMeshImportData = ImportData; + ReimportUI->bResetMaterialSlots = false; ApplyImportUIToImportOptions(ReimportUI, *ImportOptions); } else { - // An existing import data object was not found, make one here and show the options dialog - ImportData = UFbxStaticMeshImportData::GetImportDataForStaticMesh(Mesh, ImportUI->StaticMeshImportData); - Mesh->AssetImportData = ImportData; + if (ImportData == nullptr) + { + // An existing import data object was not found, make one here and show the options dialog + ImportData = UFbxStaticMeshImportData::GetImportDataForStaticMesh(Mesh, ImportUI->StaticMeshImportData); + Mesh->AssetImportData = ImportData; + } + ReimportUI->bIsReimport = true; ReimportUI->StaticMeshImportData = ImportData; bool bImportOperationCanceled = false; @@ -4997,7 +4998,7 @@ EReimportResult::Type UReimportFbxStaticMeshFactory::Reimport( UObject* Obj ) bool bOutImportAll = false; bool bIsObjFormat = false; bool bIsAutomated = false; - GetImportOptions( FFbxImporter, ReimportUI, bShowOptionDialog, bIsAutomated, Obj->GetPathName(), bOperationCanceled, bOutImportAll, bIsObjFormat, bForceImportType, FBXIT_StaticMesh ); + GetImportOptions( FFbxImporter, ReimportUI, bShowOptionDialog, bIsAutomated, Obj->GetPathName(), bOperationCanceled, bOutImportAll, bIsObjFormat, bForceImportType, FBXIT_StaticMesh, Mesh); } //We do not touch bAutoComputeLodDistances when we re-import, setting it to true will make sure we do not change anything. @@ -5111,6 +5112,7 @@ EReimportResult::Type UReimportFbxStaticMeshFactory::Reimport( UObject* Obj ) } else { + FFbxImporter->ReleaseScene(); return EReimportResult::Cancelled; } } @@ -5155,7 +5157,7 @@ bool UReimportFbxSkeletalMeshFactory::CanReimport( UObject* Obj, TArray //This skeletal mesh was import with a scene import, we cannot reimport it here return false; } - else if (SkeletalMesh->AssetImportData != nullptr && (FPaths::GetExtension(SkeletalMesh->AssetImportData->GetFirstFilename()).ToLower() == "abc")) + else if (FPaths::GetExtension(SkeletalMesh->AssetImportData->GetFirstFilename()).ToLower() == "abc") { return false; } @@ -5219,21 +5221,26 @@ EReimportResult::Type UReimportFbxSkeletalMeshFactory::Reimport( UObject* Obj ) bool bSuccess = false; - if( ImportData ) + const bool ShowImportDialogAtReimport = GetDefault()->bShowImportDialogAtReimport && !GIsAutomationTesting; + if( ImportData && !ShowImportDialogAtReimport) { // Import data already exists, apply it to the fbx import options ReimportUI->SkeletalMeshImportData = ImportData; //Some options not supported with skeletal mesh ReimportUI->SkeletalMeshImportData->bBakePivotInVertex = false; ReimportUI->SkeletalMeshImportData->bTransformVertexToAbsolute = true; - + ReimportUI->bResetMaterialSlots = false; ApplyImportUIToImportOptions(ReimportUI, *ImportOptions); } else { - // An existing import data object was not found, make one here and show the options dialog - ImportData = UFbxSkeletalMeshImportData::GetImportDataForSkeletalMesh(SkeletalMesh, ImportUI->SkeletalMeshImportData); - SkeletalMesh->AssetImportData = ImportData; + if (ImportData == nullptr) + { + // An existing import data object was not found, make one here and show the options dialog + ImportData = UFbxSkeletalMeshImportData::GetImportDataForSkeletalMesh(SkeletalMesh, ImportUI->SkeletalMeshImportData); + SkeletalMesh->AssetImportData = ImportData; + } + ReimportUI->bIsReimport = true; ReimportUI->SkeletalMeshImportData = ImportData; bool bImportOperationCanceled = false; @@ -5247,7 +5254,7 @@ EReimportResult::Type UReimportFbxSkeletalMeshFactory::Reimport( UObject* Obj ) ImportOptions->bCreatePhysicsAsset = false; ImportOptions->PhysicsAsset = SkeletalMesh->PhysicsAsset; - ImportOptions = GetImportOptions( FFbxImporter, ReimportUI, bShowOptionDialog, bIsAutomated, Obj->GetPathName(), bOperationCanceled, bOutImportAll, bIsObjFormat, bForceImportType, FBXIT_SkeletalMesh ); + ImportOptions = GetImportOptions( FFbxImporter, ReimportUI, bShowOptionDialog, bIsAutomated, Obj->GetPathName(), bOperationCanceled, bOutImportAll, bIsObjFormat, bForceImportType, FBXIT_SkeletalMesh, Obj ); } if( !bOperationCanceled && ensure(ImportData) ) @@ -5306,6 +5313,7 @@ EReimportResult::Type UReimportFbxSkeletalMeshFactory::Reimport( UObject* Obj ) } else { + FFbxImporter->ReleaseScene(); return EReimportResult::Cancelled; } } @@ -6050,9 +6058,8 @@ bool UDataAssetFactory::ConfigureProperties() TSharedPtr Filter = MakeShareable(new FAssetClassParentFilter); Options.ClassFilter = Filter; - Filter->DisallowedClassFlags = CLASS_Abstract | CLASS_Deprecated | CLASS_NewerVersionExists; + Filter->DisallowedClassFlags = CLASS_Abstract | CLASS_Deprecated | CLASS_NewerVersionExists | CLASS_HideDropDown; Filter->AllowedChildrenOfClasses.Add(UDataAsset::StaticClass()); - Filter->bDisallowBlueprintBase = true; // If a DataAsset subclass is blueprintable, data blueprints should be made instead const FText TitleText = LOCTEXT("CreateDataAssetOptions", "Pick Data Asset Class"); UClass* ChosenClass = nullptr; diff --git a/Engine/Source/Editor/UnrealEd/Private/Factories/SkeletalMeshImport.cpp b/Engine/Source/Editor/UnrealEd/Private/Factories/SkeletalMeshImport.cpp index 59537af02e82..555d56846b17 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Factories/SkeletalMeshImport.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Factories/SkeletalMeshImport.cpp @@ -100,7 +100,7 @@ void FSkeletalMeshImportData::CopyLODImportData( TArray& LODWedges, TArray& LODFaces, TArray& LODInfluences, - TArray& LODPointToRawMap) + TArray& LODPointToRawMap) const { // Copy vertex data. LODPoints.Empty( Points.Num() ); @@ -176,11 +176,13 @@ void ProcessImportMeshMaterials(TArray& Materials, FSkeletalM // If direct linkup of materials is requested, try to find them here - to get a texture name from a // material name, cut off anything in front of the dot (beyond are special flags). Materials.Empty(); + int32 SkinOffset = INDEX_NONE; for( int32 MatIndex=0; MatIndex < ImportedMaterials.Num(); ++MatIndex) { const VMaterial& ImportedMaterial = ImportedMaterials[MatIndex]; UMaterialInterface* Material = NULL; + FString MaterialNameNoSkin = ImportedMaterial.MaterialImportName; if( ImportedMaterial.Material.IsValid() ) { Material = ImportedMaterial.Material.Get(); @@ -188,21 +190,25 @@ void ProcessImportMeshMaterials(TArray& Materials, FSkeletalM else { const FString& MaterialName = ImportedMaterial.MaterialImportName; + MaterialNameNoSkin = MaterialName; Material = FindObject(ANY_PACKAGE, *MaterialName); - if (Material == nullptr) { - int32 SkinOffset = MaterialName.Find(TEXT("_skin")); + SkinOffset = MaterialName.Find(TEXT("_skin"), ESearchCase::IgnoreCase, ESearchDir::FromEnd); if (SkinOffset != INDEX_NONE) { - const FString& MaterialNameNoSkin = MaterialName.LeftChop(MaterialName.Len() - SkinOffset); - Material = FindObject(ANY_PACKAGE, *MaterialNameNoSkin); + FString SkinXXNumber = MaterialName.Right(MaterialName.Len() - (SkinOffset + 1)).RightChop(4); + if (SkinXXNumber.IsNumeric()) + { + MaterialNameNoSkin = MaterialName.LeftChop(MaterialName.Len() - SkinOffset); + Material = FindObject(ANY_PACKAGE, *MaterialNameNoSkin); + } } } } const bool bEnableShadowCasting = true; - Materials.Add( FSkeletalMaterial( Material, bEnableShadowCasting, false, Material != nullptr ? Material->GetFName() : FName(*(ImportedMaterial.MaterialImportName)), FName(*(ImportedMaterial.MaterialImportName)) ) ); + Materials.Add( FSkeletalMaterial( Material, bEnableShadowCasting, false, Material != nullptr ? Material->GetFName() : FName(*MaterialNameNoSkin), FName(*(ImportedMaterial.MaterialImportName)) ) ); } int32 NumMaterialsToAdd = FMath::Max( ImportedMaterials.Num(), ImportData.MaxMaterialIndex + 1 ); @@ -808,7 +814,10 @@ ExistingSkelMeshData* SaveExistingSkelMeshData(USkeletalMesh* ExistingSkelMesh, int32 SectionMaterialIndex = ImportedResource->LODModels[LodIndex].Sections[SectionIndex].MaterialIndex; bool SectionCastShadow = ImportedResource->LODModels[LodIndex].Sections[SectionIndex].bCastShadow; bool SectionRecomputeTangents = ImportedResource->LODModels[LodIndex].Sections[SectionIndex].bRecomputeTangent; - ExistingMeshDataPtr->ExistingImportMeshLodSectionMaterialData[LodIndex].Add(ExistingMeshLodSectionData(ExistingMeshDataPtr->ExistingImportMaterialOriginalNameData[SectionMaterialIndex], SectionCastShadow, SectionRecomputeTangents)); + if (ExistingMeshDataPtr->ExistingImportMaterialOriginalNameData.IsValidIndex(SectionMaterialIndex)) + { + ExistingMeshDataPtr->ExistingImportMeshLodSectionMaterialData[LodIndex].Add(ExistingMeshLodSectionData(ExistingMeshDataPtr->ExistingImportMaterialOriginalNameData[SectionMaterialIndex], SectionCastShadow, SectionRecomputeTangents)); + } } } @@ -962,302 +971,332 @@ void TryRegenerateLODs(ExistingSkelMeshData* MeshData, USkeletalMesh* SkeletalMe } } -void RestoreExistingSkelMeshData(ExistingSkelMeshData* MeshData, USkeletalMesh* SkeletalMesh, int32 ReimportLODIndex) +void RestoreExistingSkelMeshData(ExistingSkelMeshData* MeshData, USkeletalMesh* SkeletalMesh, int32 ReimportLODIndex, bool bResetMaterialSlots, bool bIsReimportPreview) { - if(MeshData && SkeletalMesh) + if (!MeshData || !SkeletalMesh) + { + return; + } + + if (bResetMaterialSlots && MeshData->bSaveRestoreMaterials) + { + // If "Reset Material Slot" is enable we want to change the material array to reflect the incoming FBX + // But we want to try to keep material instance from the existing data, we will match the one that fit + // but simply put the same index material instance on the one that do not match. Because we will fill + // the material slot name, artist will be able to remap the material instance correctly + for (int32 MaterialIndex = 0; MaterialIndex < SkeletalMesh->Materials.Num(); ++MaterialIndex) + { + if (SkeletalMesh->Materials[MaterialIndex].MaterialInterface == nullptr) + { + bool bFoundMatch = false; + for (int32 ExistMaterialIndex = 0; ExistMaterialIndex < MeshData->ExistingMaterials.Num(); ++ExistMaterialIndex) + { + if (MeshData->ExistingMaterials[ExistMaterialIndex].ImportedMaterialSlotName == SkeletalMesh->Materials[MaterialIndex].ImportedMaterialSlotName) + { + bFoundMatch = true; + SkeletalMesh->Materials[MaterialIndex].MaterialInterface = MeshData->ExistingMaterials[ExistMaterialIndex].MaterialInterface; + } + } + + if (!bFoundMatch && MeshData->ExistingMaterials.IsValidIndex(MaterialIndex)) + { + SkeletalMesh->Materials[MaterialIndex].MaterialInterface = MeshData->ExistingMaterials[MaterialIndex].MaterialInterface; + } + } + } + } + else if (MeshData->bSaveRestoreMaterials) { // Fix Materials array to be the correct size. - if (MeshData->bSaveRestoreMaterials) + + if (MeshData->ExistingMaterials.Num() > SkeletalMesh->Materials.Num()) { - if (MeshData->ExistingMaterials.Num() > SkeletalMesh->Materials.Num()) + for (int32 i = 0; i < MeshData->ExistingLODModels.Num(); i++) { + FStaticLODModel& LODModel = MeshData->ExistingLODModels[i]; + FSkeletalMeshLODInfo& LODInfo = MeshData->ExistingLODInfo[i]; + for (int32 OldMaterialIndex : LODInfo.LODMaterialMap) + { + int32 MaterialNumber = SkeletalMesh->Materials.Num(); + if (OldMaterialIndex >= MaterialNumber && OldMaterialIndex < MeshData->ExistingMaterials.Num()) + { + SkeletalMesh->Materials.AddZeroed((OldMaterialIndex + 1) - MaterialNumber); + } + } + } + } + else if (SkeletalMesh->Materials.Num() > MeshData->ExistingMaterials.Num()) + { + int32 ExistingMaterialsCount = MeshData->ExistingMaterials.Num(); + MeshData->ExistingMaterials.AddZeroed(SkeletalMesh->Materials.Num() - MeshData->ExistingMaterials.Num()); + //Set the ImportedMaterialSlotName on new material slot to allow next reimport to reorder the array correctly + for (int32 MaterialIndex = ExistingMaterialsCount; MaterialIndex < SkeletalMesh->Materials.Num(); ++MaterialIndex) + { + MeshData->ExistingMaterials[MaterialIndex].ImportedMaterialSlotName = SkeletalMesh->Materials[MaterialIndex].ImportedMaterialSlotName; + } + } + + //Make sure the material array fit also with the LOD 0 restoration + //The save existing data is removing the LOD 0 model and info, so we must use the ExistingImportMeshLodSectionMaterialData + //to retrieve the user changes on the LOD 0. + if (MeshData->ExistingMaterials.Num() > SkeletalMesh->Materials.Num() && MeshData->ExistingImportMeshLodSectionMaterialData.Num() > 0) + { + for (int32 SectionIndex = 0; SectionIndex < MeshData->ExistingImportMeshLodSectionMaterialData[0].Num(); SectionIndex++) + { + FName ExistingMaterialSlotName = MeshData->ExistingImportMeshLodSectionMaterialData[0][SectionIndex].ImportedMaterialSlotName; + for (int32 MaterialIndex = 0; MaterialIndex < MeshData->ExistingMaterials.Num(); ++MaterialIndex) + { + if (ExistingMaterialSlotName == MeshData->ExistingMaterials[MaterialIndex].ImportedMaterialSlotName) + { + int32 MaterialNumber = SkeletalMesh->Materials.Num(); + if (MaterialIndex >= MaterialNumber && MaterialIndex < MeshData->ExistingMaterials.Num()) + { + SkeletalMesh->Materials.AddZeroed((MaterialIndex + 1) - MaterialNumber); + } + break; + } + } + + } + } + + for (int32 CopyIndex = 0; CopyIndex < SkeletalMesh->Materials.Num(); ++CopyIndex) + { + if (MeshData->ExistingMaterials[CopyIndex].ImportedMaterialSlotName == NAME_None) + { + MeshData->ExistingMaterials[CopyIndex].ImportedMaterialSlotName = SkeletalMesh->Materials[CopyIndex].ImportedMaterialSlotName; + //Set some default value for the MaterialSlotName + if (MeshData->ExistingMaterials[CopyIndex].MaterialSlotName == NAME_None) + { + MeshData->ExistingMaterials[CopyIndex].MaterialSlotName = SkeletalMesh->Materials[CopyIndex].MaterialSlotName; + } + } + SkeletalMesh->Materials[CopyIndex] = MeshData->ExistingMaterials[CopyIndex]; + } + } + + //Do everything we need for base LOD re-import + if (ReimportLODIndex < 1) + { + // this is not ideal. Ideally we'll have to save only diff with indicating which joints, + // but for now, we allow them to keep the previous pose IF the element count is same + if (MeshData->ExistingRetargetBasePose.Num() == SkeletalMesh->RefSkeleton.GetRawBoneNum()) + { + SkeletalMesh->RetargetBasePose = MeshData->ExistingRetargetBasePose; + } + + // Assign sockets from old version of this SkeletalMesh. + // Only copy ones for bones that exist in the new mesh. + for (int32 i = 0; i < MeshData->ExistingSockets.Num(); i++) + { + const int32 BoneIndex = SkeletalMesh->RefSkeleton.FindBoneIndex(MeshData->ExistingSockets[i]->BoneName); + if (BoneIndex != INDEX_NONE) + { + SkeletalMesh->GetMeshOnlySocketList().Add(MeshData->ExistingSockets[i]); + } + } + + // We copy back and fix-up the LODs that still work with this skeleton. + if (MeshData->ExistingLODModels.Num() > 0) + { + bool bRegenLODs = true; + if (SkeletonsAreCompatible(SkeletalMesh->RefSkeleton, MeshData->ExistingRefSkeleton)) + { + bRegenLODs = false; + // First create mapping table from old skeleton to new skeleton. + TArray OldToNewMap; + OldToNewMap.AddUninitialized(MeshData->ExistingRefSkeleton.GetRawBoneNum()); + for (int32 i = 0; i < MeshData->ExistingRefSkeleton.GetRawBoneNum(); i++) + { + OldToNewMap[i] = SkeletalMesh->RefSkeleton.FindBoneIndex(MeshData->ExistingRefSkeleton.GetBoneName(i)); + } + for (int32 i = 0; i < MeshData->ExistingLODModels.Num(); i++) { FStaticLODModel& LODModel = MeshData->ExistingLODModels[i]; FSkeletalMeshLODInfo& LODInfo = MeshData->ExistingLODInfo[i]; - for (int32 OldMaterialIndex : LODInfo.LODMaterialMap) + + + // Fix ActiveBoneIndices array. + bool bMissingBone = false; + FName MissingBoneName = NAME_None; + for (int32 j = 0; j < LODModel.ActiveBoneIndices.Num() && !bMissingBone; j++) { - int32 MaterialNumber = SkeletalMesh->Materials.Num(); - if (OldMaterialIndex >= MaterialNumber && OldMaterialIndex < MeshData->ExistingMaterials.Num()) + int32 NewBoneIndex = OldToNewMap[LODModel.ActiveBoneIndices[j]]; + if (NewBoneIndex == INDEX_NONE) { - SkeletalMesh->Materials.AddZeroed((OldMaterialIndex + 1) - MaterialNumber); + bMissingBone = true; + MissingBoneName = MeshData->ExistingRefSkeleton.GetBoneName(LODModel.ActiveBoneIndices[j]); + } + else + { + LODModel.ActiveBoneIndices[j] = NewBoneIndex; } } - } - } - else if (SkeletalMesh->Materials.Num() > MeshData->ExistingMaterials.Num()) - { - int32 ExistingMaterialsCount = MeshData->ExistingMaterials.Num(); - MeshData->ExistingMaterials.AddZeroed(SkeletalMesh->Materials.Num() - MeshData->ExistingMaterials.Num()); - //Set the ImportedMaterialSlotName on new material slot to allow next reimport to reorder the array correctly - for (int32 MaterialIndex = ExistingMaterialsCount; MaterialIndex < SkeletalMesh->Materials.Num(); ++MaterialIndex) - { - MeshData->ExistingMaterials[MaterialIndex].ImportedMaterialSlotName = SkeletalMesh->Materials[MaterialIndex].ImportedMaterialSlotName; - } - } - - //Make sure the material array fit also with the LOD 0 restoration - //The save existing data is removing the LOD 0 model and info, so we must use the ExistingImportMeshLodSectionMaterialData - //to retrieve the user changes on the LOD 0. - if (MeshData->ExistingMaterials.Num() > SkeletalMesh->Materials.Num() && MeshData->ExistingImportMeshLodSectionMaterialData.Num() > 0) - { - for (int32 SectionIndex = 0; SectionIndex < MeshData->ExistingImportMeshLodSectionMaterialData[0].Num(); SectionIndex++) - { - FName ExistingMaterialSlotName = MeshData->ExistingImportMeshLodSectionMaterialData[0][SectionIndex].ImportedMaterialSlotName; - for (int32 MaterialIndex = 0; MaterialIndex < MeshData->ExistingMaterials.Num(); ++MaterialIndex) + + // Fix RequiredBones array. + for (int32 j = 0; j < LODModel.RequiredBones.Num() && !bMissingBone; j++) { - if (ExistingMaterialSlotName == MeshData->ExistingMaterials[MaterialIndex].ImportedMaterialSlotName) - { - int32 MaterialNumber = SkeletalMesh->Materials.Num(); - if (MaterialIndex >= MaterialNumber && MaterialIndex < MeshData->ExistingMaterials.Num()) - { - SkeletalMesh->Materials.AddZeroed((MaterialIndex + 1) - MaterialNumber); - } - break; - } - } - - } - } - - for (int32 CopyIndex = 0; CopyIndex < SkeletalMesh->Materials.Num(); ++CopyIndex) - { - if (MeshData->ExistingMaterials[CopyIndex].ImportedMaterialSlotName == NAME_None) - { - MeshData->ExistingMaterials[CopyIndex].ImportedMaterialSlotName = SkeletalMesh->Materials[CopyIndex].ImportedMaterialSlotName; - //Set some default value for the MaterialSlotName - if (MeshData->ExistingMaterials[CopyIndex].MaterialSlotName == NAME_None) - { - MeshData->ExistingMaterials[CopyIndex].MaterialSlotName = SkeletalMesh->Materials[CopyIndex].MaterialSlotName; - } - } - SkeletalMesh->Materials[CopyIndex] = MeshData->ExistingMaterials[CopyIndex]; - } - } - - //Do everything we need for base LOD re-import - if (ReimportLODIndex < 1) - { - // this is not ideal. Ideally we'll have to save only diff with indicating which joints, - // but for now, we allow them to keep the previous pose IF the element count is same - if (MeshData->ExistingRetargetBasePose.Num() == SkeletalMesh->RefSkeleton.GetRawBoneNum()) - { - SkeletalMesh->RetargetBasePose = MeshData->ExistingRetargetBasePose; - } - - // Assign sockets from old version of this SkeletalMesh. - // Only copy ones for bones that exist in the new mesh. - for (int32 i = 0; i < MeshData->ExistingSockets.Num(); i++) - { - const int32 BoneIndex = SkeletalMesh->RefSkeleton.FindBoneIndex(MeshData->ExistingSockets[i]->BoneName); - if (BoneIndex != INDEX_NONE) - { - SkeletalMesh->GetMeshOnlySocketList().Add(MeshData->ExistingSockets[i]); - } - } - - // We copy back and fix-up the LODs that still work with this skeleton. - if (MeshData->ExistingLODModels.Num() > 0) - { - bool bRegenLODs = true; - if (SkeletonsAreCompatible(SkeletalMesh->RefSkeleton, MeshData->ExistingRefSkeleton)) - { - bRegenLODs = false; - // First create mapping table from old skeleton to new skeleton. - TArray OldToNewMap; - OldToNewMap.AddUninitialized(MeshData->ExistingRefSkeleton.GetRawBoneNum()); - for (int32 i = 0; i < MeshData->ExistingRefSkeleton.GetRawBoneNum(); i++) - { - OldToNewMap[i] = SkeletalMesh->RefSkeleton.FindBoneIndex(MeshData->ExistingRefSkeleton.GetBoneName(i)); - } - - for (int32 i = 0; i < MeshData->ExistingLODModels.Num(); i++) - { - FStaticLODModel& LODModel = MeshData->ExistingLODModels[i]; - FSkeletalMeshLODInfo& LODInfo = MeshData->ExistingLODInfo[i]; - - - // Fix ActiveBoneIndices array. - bool bMissingBone = false; - FName MissingBoneName = NAME_None; - for (int32 j = 0; j < LODModel.ActiveBoneIndices.Num() && !bMissingBone; j++) - { - int32 NewBoneIndex = OldToNewMap[LODModel.ActiveBoneIndices[j]]; - if (NewBoneIndex == INDEX_NONE) - { - bMissingBone = true; - MissingBoneName = MeshData->ExistingRefSkeleton.GetBoneName(LODModel.ActiveBoneIndices[j]); - } - else - { - LODModel.ActiveBoneIndices[j] = NewBoneIndex; - } - } - - // Fix RequiredBones array. - for (int32 j = 0; j < LODModel.RequiredBones.Num() && !bMissingBone; j++) - { const int32 OldBoneIndex = LODModel.RequiredBones[j]; if(OldToNewMap.IsValidIndex(OldBoneIndex)) //Previously virtual bones could end up in this array // Must validate against this { const int32 NewBoneIndex = OldToNewMap[OldBoneIndex]; - if (NewBoneIndex == INDEX_NONE) - { - bMissingBone = true; + if (NewBoneIndex == INDEX_NONE) + { + bMissingBone = true; MissingBoneName = MeshData->ExistingRefSkeleton.GetBoneName(OldBoneIndex); - } - else - { - LODModel.RequiredBones[j] = NewBoneIndex; - } } + else + { + LODModel.RequiredBones[j] = NewBoneIndex; + } + } else { //Bone didn't exist in our required bones, clean up. LODModel.RequiredBones.RemoveAt(j,1,false); --j; } - } + } - // Sort ascending for parent child relationship - LODModel.RequiredBones.Sort(); + // Sort ascending for parent child relationship + LODModel.RequiredBones.Sort(); SkeletalMesh->RefSkeleton.EnsureParentExists(LODModel.ActiveBoneIndices); - // Fix the sections' BoneMaps. - for (int32 SectionIndex = 0; SectionIndex < LODModel.Sections.Num(); SectionIndex++) + // Fix the sections' BoneMaps. + for (int32 SectionIndex = 0; SectionIndex < LODModel.Sections.Num(); SectionIndex++) + { + FSkelMeshSection& Section = LODModel.Sections[SectionIndex]; + for (int32 BoneIndex = 0; BoneIndex < Section.BoneMap.Num(); BoneIndex++) { - FSkelMeshSection& Section = LODModel.Sections[SectionIndex]; - for (int32 BoneIndex = 0; BoneIndex < Section.BoneMap.Num(); BoneIndex++) - { - int32 NewBoneIndex = OldToNewMap[Section.BoneMap[BoneIndex]]; - if (NewBoneIndex == INDEX_NONE) - { - bMissingBone = true; - MissingBoneName = MeshData->ExistingRefSkeleton.GetBoneName(Section.BoneMap[BoneIndex]); - break; - } - else - { - Section.BoneMap[BoneIndex] = NewBoneIndex; - } - } - if (bMissingBone) + int32 NewBoneIndex = OldToNewMap[Section.BoneMap[BoneIndex]]; + if (NewBoneIndex == INDEX_NONE) { + bMissingBone = true; + MissingBoneName = MeshData->ExistingRefSkeleton.GetBoneName(Section.BoneMap[BoneIndex]); break; } + else + { + Section.BoneMap[BoneIndex] = NewBoneIndex; + } } - if (bMissingBone) { - UnFbx::FFbxImporter* FFbxImporter = UnFbx::FFbxImporter::GetInstance(); - FFbxImporter->AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Warning, FText::Format(LOCTEXT("NewMeshMissingBoneFromLOD", "New mesh is missing bone '{0}' required by an LOD."), FText::FromName(MissingBoneName))), FFbxErrors::SkeletalMesh_LOD_MissingBone); - bRegenLODs = true; break; } - else - { - FStaticLODModel* NewLODModel = new(SkeletalMesh->GetImportedResource()->LODModels) FStaticLODModel(LODModel); - - NewLODModel->RebuildIndexBuffer(&MeshData->ExistingIndexBufferData[i], &MeshData->ExistingAdjacencyIndexBufferData[i]); - - SkeletalMesh->LODInfo.Add(LODInfo); - } } - } - if (bRegenLODs) - { - TryRegenerateLODs(MeshData, SkeletalMesh); - } - } - - for (int32 AssetIndex = 0; AssetIndex < MeshData->ExistingPhysicsAssets.Num(); ++AssetIndex) - { - UPhysicsAsset* PhysicsAsset = MeshData->ExistingPhysicsAssets[AssetIndex]; - if (AssetIndex == 0) - { - // First asset is the one that the skeletal mesh should point too - SkeletalMesh->PhysicsAsset = PhysicsAsset; - } - // No need to mark as modified here, because the asset hasn't actually changed - if (PhysicsAsset) - { - PhysicsAsset->PreviewSkeletalMesh = SkeletalMesh; - } - } - - SkeletalMesh->ShadowPhysicsAsset = MeshData->ExistingShadowPhysicsAsset; - - SkeletalMesh->Skeleton = MeshData->ExistingSkeleton; - - // Copy mirror table. - SkeletalMesh->ImportMirrorTable(MeshData->ExistingMirrorTable); - - SkeletalMesh->MorphTargets.Empty(MeshData->ExistingMorphTargets.Num()); - SkeletalMesh->MorphTargets.Append(MeshData->ExistingMorphTargets); - SkeletalMesh->InitMorphTargets(); - - SkeletalMesh->bUseFullPrecisionUVs = MeshData->bExistingUseFullPrecisionUVs; - - MeshData->ExistingSortInfo.Restore(SkeletalMesh, 0); - - SkeletalMesh->AssetImportData = MeshData->ExistingAssetImportData.Get(); - SkeletalMesh->ThumbnailInfo = MeshData->ExistingThumbnailInfo.Get(); - - SkeletalMesh->MeshClothingAssets = MeshData->ExistingClothingAssets; - - for(UClothingAssetBase* ClothingAsset : SkeletalMesh->MeshClothingAssets) - { - ClothingAsset->RefreshBoneMapping(SkeletalMesh); - } - - //Restore the section change only for the base LOD, other LOD will be restore when setting the LOD - if (MeshData->UseMaterialNameSlotWorkflow) - { - FStaticLODModel &NewSkelMeshLodModel = SkeletalMesh->GetImportedResource()->LODModels[0]; - //Restore the section changes from the old import data - for (int32 SectionIndex = 0; SectionIndex < NewSkelMeshLodModel.Sections.Num(); SectionIndex++) - { - if (MeshData->LastImportMeshLodSectionMaterialData.Num() < 1 || MeshData->LastImportMeshLodSectionMaterialData[0].Num() <= SectionIndex || - MeshData->ExistingImportMeshLodSectionMaterialData.Num() < 1 || MeshData->ExistingImportMeshLodSectionMaterialData[0].Num() <= SectionIndex) + if (bMissingBone) { + UnFbx::FFbxImporter* FFbxImporter = UnFbx::FFbxImporter::GetInstance(); + FFbxImporter->AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Warning, FText::Format(LOCTEXT("NewMeshMissingBoneFromLOD", "New mesh is missing bone '{0}' required by an LOD."), FText::FromName(MissingBoneName))), FFbxErrors::SkeletalMesh_LOD_MissingBone); + bRegenLODs = true; break; } - //Get the current skelmesh section slot import name - FName ExistMeshSectionSlotName = MeshData->ExistingImportMeshLodSectionMaterialData[0][SectionIndex].ImportedMaterialSlotName; - bool ExistingSectionCastShadow = MeshData->ExistingImportMeshLodSectionMaterialData[0][SectionIndex].bCastShadow; - bool ExistingSectionRecomputeTangents = MeshData->ExistingImportMeshLodSectionMaterialData[0][SectionIndex].bRecomputeTangents; - - //Get the new skelmesh section slot import name - int32 NewMeshSectionMaterialIndex = NewSkelMeshLodModel.Sections[SectionIndex].MaterialIndex; - FName NewMeshSectionSlotName = SkeletalMesh->Materials[NewMeshSectionMaterialIndex].ImportedMaterialSlotName; - - //Get the Last imported skelmesh section slot import name - FName OriginalImportMeshSectionSlotName = MeshData->LastImportMeshLodSectionMaterialData[0][SectionIndex]; - - if (OriginalImportMeshSectionSlotName == NewMeshSectionSlotName && ExistMeshSectionSlotName != OriginalImportMeshSectionSlotName) + else { - //The last import slot name match the New import slot name, but the Exist slot name is different then the last import slot name. - //This mean the user has change the section assign slot and the fbx file did not change it - //Override the new section material index to use the one that the user set - for (int32 RemapMaterialIndex = 0; RemapMaterialIndex < SkeletalMesh->Materials.Num(); ++RemapMaterialIndex) + FStaticLODModel* NewLODModel = new(SkeletalMesh->GetImportedResource()->LODModels) FStaticLODModel(LODModel); + + NewLODModel->RebuildIndexBuffer(&MeshData->ExistingIndexBufferData[i], &MeshData->ExistingAdjacencyIndexBufferData[i]); + + SkeletalMesh->LODInfo.Add(LODInfo); + } + } + } + + if (bRegenLODs && !bIsReimportPreview) + { + TryRegenerateLODs(MeshData, SkeletalMesh); + } + } + + for (int32 AssetIndex = 0; AssetIndex < MeshData->ExistingPhysicsAssets.Num(); ++AssetIndex) + { + UPhysicsAsset* PhysicsAsset = MeshData->ExistingPhysicsAssets[AssetIndex]; + if (AssetIndex == 0) + { + // First asset is the one that the skeletal mesh should point too + SkeletalMesh->PhysicsAsset = PhysicsAsset; + } + // No need to mark as modified here, because the asset hasn't actually changed + if (PhysicsAsset) + { + PhysicsAsset->PreviewSkeletalMesh = SkeletalMesh; + } + } + + SkeletalMesh->ShadowPhysicsAsset = MeshData->ExistingShadowPhysicsAsset; + + SkeletalMesh->Skeleton = MeshData->ExistingSkeleton; + + // Copy mirror table. + SkeletalMesh->ImportMirrorTable(MeshData->ExistingMirrorTable); + + SkeletalMesh->MorphTargets.Empty(MeshData->ExistingMorphTargets.Num()); + SkeletalMesh->MorphTargets.Append(MeshData->ExistingMorphTargets); + SkeletalMesh->InitMorphTargets(); + + SkeletalMesh->bUseFullPrecisionUVs = MeshData->bExistingUseFullPrecisionUVs; + + MeshData->ExistingSortInfo.Restore(SkeletalMesh, 0); + + SkeletalMesh->AssetImportData = MeshData->ExistingAssetImportData.Get(); + SkeletalMesh->ThumbnailInfo = MeshData->ExistingThumbnailInfo.Get(); + + SkeletalMesh->MeshClothingAssets = MeshData->ExistingClothingAssets; + + for(UClothingAssetBase* ClothingAsset : SkeletalMesh->MeshClothingAssets) + { + ClothingAsset->RefreshBoneMapping(SkeletalMesh); + } + + //Restore the section change only for the base LOD, other LOD will be restore when setting the LOD. + if (MeshData->UseMaterialNameSlotWorkflow) + { + FStaticLODModel &NewSkelMeshLodModel = SkeletalMesh->GetImportedResource()->LODModels[0]; + //Restore the section changes from the old import data + for (int32 SectionIndex = 0; SectionIndex < NewSkelMeshLodModel.Sections.Num(); SectionIndex++) + { + if (MeshData->LastImportMeshLodSectionMaterialData.Num() < 1 || MeshData->LastImportMeshLodSectionMaterialData[0].Num() <= SectionIndex || + MeshData->ExistingImportMeshLodSectionMaterialData.Num() < 1 || MeshData->ExistingImportMeshLodSectionMaterialData[0].Num() <= SectionIndex) + { + break; + } + //Get the current skelmesh section slot import name + FName ExistMeshSectionSlotName = MeshData->ExistingImportMeshLodSectionMaterialData[0][SectionIndex].ImportedMaterialSlotName; + bool ExistingSectionCastShadow = MeshData->ExistingImportMeshLodSectionMaterialData[0][SectionIndex].bCastShadow; + bool ExistingSectionRecomputeTangents = MeshData->ExistingImportMeshLodSectionMaterialData[0][SectionIndex].bRecomputeTangents; + + //Get the new skelmesh section slot import name + int32 NewMeshSectionMaterialIndex = NewSkelMeshLodModel.Sections[SectionIndex].MaterialIndex; + FName NewMeshSectionSlotName = SkeletalMesh->Materials[NewMeshSectionMaterialIndex].ImportedMaterialSlotName; + + //Get the Last imported skelmesh section slot import name + FName OriginalImportMeshSectionSlotName = MeshData->LastImportMeshLodSectionMaterialData[0][SectionIndex]; + + if (OriginalImportMeshSectionSlotName == NewMeshSectionSlotName && ExistMeshSectionSlotName != OriginalImportMeshSectionSlotName) + { + //The last import slot name match the New import slot name, but the Exist slot name is different then the last import slot name. + //This mean the user has change the section assign slot and the fbx file did not change it + //Override the new section material index to use the one that the user set + for (int32 RemapMaterialIndex = 0; RemapMaterialIndex < SkeletalMesh->Materials.Num(); ++RemapMaterialIndex) + { + const FSkeletalMaterial &NewSectionMaterial = SkeletalMesh->Materials[RemapMaterialIndex]; + if (NewSectionMaterial.ImportedMaterialSlotName == ExistMeshSectionSlotName) { - const FSkeletalMaterial &NewSectionMaterial = SkeletalMesh->Materials[RemapMaterialIndex]; - if (NewSectionMaterial.ImportedMaterialSlotName == ExistMeshSectionSlotName) - { - NewSkelMeshLodModel.Sections[SectionIndex].MaterialIndex = RemapMaterialIndex; - break; - } + NewSkelMeshLodModel.Sections[SectionIndex].MaterialIndex = RemapMaterialIndex; + break; } } - //Restore the cast shadow and the recompute tangents - if (NewMeshSectionSlotName == ExistMeshSectionSlotName) - { - NewSkelMeshLodModel.Sections[SectionIndex].bCastShadow = ExistingSectionCastShadow; - NewSkelMeshLodModel.Sections[SectionIndex].bRecomputeTangent = ExistingSectionRecomputeTangents; - } + } + //Restore the cast shadow and the recompute tangents + if (NewMeshSectionSlotName == ExistMeshSectionSlotName) + { + NewSkelMeshLodModel.Sections[SectionIndex].bCastShadow = ExistingSectionCastShadow; + NewSkelMeshLodModel.Sections[SectionIndex].bRecomputeTangent = ExistingSectionRecomputeTangents; } } } diff --git a/Engine/Source/Editor/UnrealEd/Private/Factories/SlateWidgetStyleAssetFactory.cpp b/Engine/Source/Editor/UnrealEd/Private/Factories/SlateWidgetStyleAssetFactory.cpp index b31499b8271d..347e2aadc38e 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Factories/SlateWidgetStyleAssetFactory.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Factories/SlateWidgetStyleAssetFactory.cpp @@ -18,7 +18,7 @@ public: TSet< const UClass* > DisallowedClasses; /** Disallowed class flags. */ - uint32 DisallowedClassFlags; + EClassFlags DisallowedClassFlags; virtual bool IsClassAllowed(const FClassViewerInitializationOptions& InInitOptions, const UClass* InClass, TSharedRef< FClassViewerFilterFuncs > InFilterFuncs ) override { diff --git a/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxCompareWindow.cpp b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxCompareWindow.cpp new file mode 100644 index 000000000000..8176a8145c10 --- /dev/null +++ b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxCompareWindow.cpp @@ -0,0 +1,1032 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. +#include "FbxCompareWindow.h" +#include "Modules/ModuleManager.h" +#include "Widgets/Layout/SBorder.h" +#include "Widgets/Text/STextBlock.h" +#include "Widgets/Layout/SBox.h" +#include "Widgets/Layout/SUniformGridPanel.h" +#include "Widgets/Layout/SScrollBox.h" +#include "Widgets/Layout/SSeparator.h" +#include "Widgets/Input/SButton.h" +#include "Widgets/Images/SImage.h" +#include "Widgets/Colors/SColorBlock.h" +#include "Widgets/Input/SCheckBox.h" +#include "Widgets/Views/SListView.h" +#include "Widgets/Views/STreeView.h" +#include "Widgets/Views/STableRow.h" +#include "EditorStyleSet.h" +#include "Factories/FbxAnimSequenceImportData.h" +#include "IDocumentation.h" +#include "PropertyEditorModule.h" +#include "IDetailsView.h" +#include "Framework/Commands/UIAction.h" +#include "Framework/MultiBox/MultiBoxBuilder.h" +#include "Factories/FbxSceneImportFactory.h" +#include "Toolkits/AssetEditorManager.h" +#include "Framework/Application/SlateApplication.h" +#include "Engine/SkeletalMesh.h" + + +#define LOCTEXT_NAMESPACE "FBXOption" + +void SFbxCompareWindow::Construct(const FArguments& InArgs) +{ + CurrentDisplayOption = FMaterialCompareData::All; + bShowSectionFlag[EFBXCompareSection_General] = true; + bShowSectionFlag[EFBXCompareSection_Materials] = true; + bShowSectionFlag[EFBXCompareSection_Skeleton] = true; + + WidgetWindow = InArgs._WidgetWindow; + FullFbxPath = InArgs._FullFbxPath.ToString(); + FbxSceneInfo = InArgs._FbxSceneInfo; + FbxGeneralInfo = InArgs._FbxGeneralInfo; + if (InArgs._AssetReferencingSkeleton != nullptr) + { + //Copy the aray + AssetReferencingSkeleton = *(InArgs._AssetReferencingSkeleton); + } + CurrentMeshData = InArgs._CurrentMeshData; + FbxMeshData = InArgs._FbxMeshData; + PreviewObject = InArgs._PreviewObject; + + FillGeneralListItem(); + FillMaterialListItem(); + if (PreviewObject->IsA(USkeletalMesh::StaticClass())) + { + FilSkeletonTreeItem(); + } + + SetMatchJointInfo(); + + // Material comparison + TSharedPtr MaterialCompareSection = ConstructMaterialComparison(); + // Skeleton comparison + TSharedPtr SkeletonCompareSection = ConstructSkeletonComparison(); + // General section + TSharedPtr GeneralInfoSection = ConstructGeneralInfo(); + + TSharedRef VerticalScrollBar = SNew(SScrollBar) + .Orientation(EOrientation::Orient_Vertical) + .AlwaysShowScrollbar(false); + + this->ChildSlot + [ + SNew(SBox) + [ + SNew(SVerticalBox) + +SVerticalBox::Slot() + .FillHeight(1.0f) + [ + SNew(SScrollBox) + + SScrollBox::Slot() + [ + SNew(SBorder) + .BorderImage(FEditorStyle::GetBrush("ToolPanel.DarkGroupBorder")) + [ + SNew(SVerticalBox) + +SVerticalBox::Slot() + .AutoHeight() + .Padding(2) + [ + // Header with the file path + SNew(SBorder) + .Padding(FMargin(3)) + .BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder")) + [ + SNew(SHorizontalBox) + +SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(STextBlock) + .Font(FEditorStyle::GetFontStyle("CurveEd.LabelFont")) + .Text(LOCTEXT("Import_CurrentFileTitle", "Current File: ")) + ] + +SHorizontalBox::Slot() + .Padding(5, 0, 0, 0) + .AutoWidth() + .VAlign(VAlign_Center) + [ + SNew(STextBlock) + .Font(FEditorStyle::GetFontStyle("CurveEd.InfoFont")) + .Text(InArgs._FullFbxPath) + ] + ] + ] + + SVerticalBox::Slot() + .FillHeight(1.0f) + .Padding(2) + [ + SNew(SVerticalBox) + + SVerticalBox::Slot() + .AutoHeight() + .Padding(2) + [ + // Material Compare section + MaterialCompareSection.ToSharedRef() + ] + + SVerticalBox::Slot() + .AutoHeight() + .Padding(2) + [ + // Skeleton Compare section + SkeletonCompareSection.ToSharedRef() + ] + + SVerticalBox::Slot() + .AutoHeight() + .Padding(2) + [ + GeneralInfoSection.ToSharedRef() + ] + ] + ] + ] + ] + + SVerticalBox::Slot() + .AutoHeight() + .HAlign(HAlign_Right) + .Padding(2) + [ + SNew(SButton) + .HAlign(HAlign_Center) + .Text(LOCTEXT("SFbxCompareWindow_Preview_Done", "Done")) + .OnClicked(this, &SFbxCompareWindow::OnDone) + ] + ] + ]; +} + +FReply SFbxCompareWindow::SetSectionVisible(EFBXCompareSection SectionIndex) +{ + bShowSectionFlag[SectionIndex] = !bShowSectionFlag[SectionIndex]; + return FReply::Handled(); +} + +EVisibility SFbxCompareWindow::IsSectionVisible(EFBXCompareSection SectionIndex) +{ + return bShowSectionFlag[SectionIndex] ? EVisibility::All : EVisibility::Collapsed; +} + +const FSlateBrush* SFbxCompareWindow::GetCollapsableArrow(EFBXCompareSection SectionIndex) const +{ + return bShowSectionFlag[SectionIndex] ? FEditorStyle::GetBrush("Symbols.DownArrow") : FEditorStyle::GetBrush("Symbols.RightArrow"); +} + +TSharedPtr SFbxCompareWindow::ConstructGeneralInfo() +{ + return SNew(SBox) + .MaxDesiredHeight(205) + [ + SNew(SBorder) + .Padding(FMargin(3)) + .BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder")) + [ + SNew(SVerticalBox) + +SVerticalBox::Slot() + .AutoHeight() + .Padding(2) + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(SButton) + .HAlign(HAlign_Center) + .VAlign(VAlign_Center) + .IsFocusable(false) + .ButtonStyle(FEditorStyle::Get(), "NoBorder") + .OnClicked(this, &SFbxCompareWindow::SetSectionVisible, EFBXCompareSection_General) + [ + SNew(SImage).Image(this, &SFbxCompareWindow::GetCollapsableArrow, EFBXCompareSection_General) + ] + ] + + SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(STextBlock) + .Font(FEditorStyle::GetFontStyle("DetailsView.CategoryFontStyle")) + .Text(LOCTEXT("SFbxCompareWindow_GeneralInfoHeader", "Fbx File Information")) + ] + + ] + +SVerticalBox::Slot() + .FillHeight(1.0f) + .Padding(2) + [ + SNew(SBox) + .Visibility(TAttribute::Create(TAttribute::FGetter::CreateSP(this, &SFbxCompareWindow::IsSectionVisible, EFBXCompareSection_General))) + [ + SNew(SBorder) + .BorderImage(FEditorStyle::GetBrush("ToolPanel.DarkGroupBorder")) + [ + //Show the general fbx information + SNew(SListView>) + .ListItemsSource(&GeneralListItem) + .OnGenerateRow(this, &SFbxCompareWindow::OnGenerateRowGeneralFbxInfo) + ] + ] + ] + ] + ]; +} + +TSharedPtr SFbxCompareWindow::ConstructMaterialComparison() +{ + return SNew(SBox) + .MaxDesiredHeight(500) + [ + SNew(SBorder) + .Padding(FMargin(3)) + .BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder")) + [ + SNew(SVerticalBox) + +SVerticalBox::Slot() + .AutoHeight() + .Padding(2) + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(SButton) + .HAlign(HAlign_Center) + .VAlign(VAlign_Center) + .IsFocusable(false) + .ButtonStyle(FEditorStyle::Get(), "NoBorder") + .OnClicked(this, &SFbxCompareWindow::SetSectionVisible, EFBXCompareSection_Materials) + [ + SNew(SImage).Image(this, &SFbxCompareWindow::GetCollapsableArrow, EFBXCompareSection_Materials) + ] + ] + + SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(STextBlock) + .Font(FEditorStyle::GetFontStyle("DetailsView.CategoryFontStyle")) + .Text(LOCTEXT("SFbxCompareWindow_MaterialCompareHeader", "Materials")) + ] + ] + +SVerticalBox::Slot() + .FillHeight(1.0f) + .Padding(2) + [ + SNew(SBox) + .Visibility(TAttribute::Create(TAttribute::FGetter::CreateSP(this, &SFbxCompareWindow::IsSectionVisible, EFBXCompareSection_Materials))) + [ + SNew(SVerticalBox) + +SVerticalBox::Slot() + .FillHeight(1.0f) + .Padding(2) + [ + //Show the Comparison of the meshes + SNew(SListView< TSharedPtr >) + .ItemHeight(24) + .ListItemsSource(&CompareMaterialListItem) + .OnGenerateRow(this, &SFbxCompareWindow::OnGenerateRowForCompareMaterialList) + .HeaderRow + ( + SNew(SHeaderRow) + + SHeaderRow::Column("RowIndex") + .DefaultLabel(LOCTEXT("SFbxCompareWindow_RowIndex_ColumnHeader", "")) + .FixedWidth(25) + + SHeaderRow::Column("Current") + .DefaultLabel(LOCTEXT("SFbxCompareWindow_Current_ColumnHeader", "Current Asset")) + .FillWidth(0.5f) + + SHeaderRow::Column("Fbx") + .DefaultLabel(LOCTEXT("SFbxCompareWindow_Fbx_ColumnHeader", "Reimport Asset (Preview)")) + .FillWidth(0.5f) + ) + ] + +SVerticalBox::Slot() + .AutoHeight() + .Padding(2) + [ + //Show the toggle button to display different re-import problem + SNew(SHorizontalBox) + +SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(SCheckBox) + .OnCheckStateChanged(this, &SFbxCompareWindow::ToggleMaterialDisplay, FMaterialCompareData::EMaterialCompareDisplayOption::All) + .IsChecked(this, &SFbxCompareWindow::IsToggleMaterialDisplayChecked, FMaterialCompareData::EMaterialCompareDisplayOption::All) + [ + SNew(STextBlock) + .Text(LOCTEXT("SFbxCompareWindow_Display_Option_All", "All")) + ] + + ] + +SHorizontalBox::Slot() + .Padding(5, 0, 0, 0) + .AutoWidth() + .VAlign(VAlign_Center) + [ + SNew(SCheckBox) + .OnCheckStateChanged(this, &SFbxCompareWindow::ToggleMaterialDisplay, FMaterialCompareData::EMaterialCompareDisplayOption::NoMatch) + .IsChecked(this, &SFbxCompareWindow::IsToggleMaterialDisplayChecked, FMaterialCompareData::EMaterialCompareDisplayOption::NoMatch) + [ + SNew(STextBlock) + .Text(LOCTEXT("SFbxCompareWindow_Display_Option_NoMatch", "No Match")) + .ColorAndOpacity(FSlateColor(FLinearColor(0.7f, 0.3f, 0.0f))) + .ToolTipText(LOCTEXT("SFbxCompareWindow_Display_Option_NoMatch_tooltip", "Can impact gameplay code using material slot name.")) + ] + ] + +SHorizontalBox::Slot() + .Padding(5, 0, 0, 0) + .AutoWidth() + .VAlign(VAlign_Center) + [ + SNew(SCheckBox) + .OnCheckStateChanged(this, &SFbxCompareWindow::ToggleMaterialDisplay, FMaterialCompareData::EMaterialCompareDisplayOption::IndexChanged) + .IsChecked(this, &SFbxCompareWindow::IsToggleMaterialDisplayChecked, FMaterialCompareData::EMaterialCompareDisplayOption::IndexChanged) + [ + SNew(STextBlock) + .Text(LOCTEXT("SFbxCompareWindow_Display_Option_IndexChanged", "Index Changed")) + .ColorAndOpacity(FSlateColor(FLinearColor::Yellow)) + .ToolTipText(LOCTEXT("SFbxCompareWindow_Display_Option_IndexChanged_tooltip", "Can impact gameplay code using index base material.")) + ] + ] + +SHorizontalBox::Slot() + .Padding(5, 0, 0, 0) + .AutoWidth() + .VAlign(VAlign_Center) + [ + SNew(SCheckBox) + .OnCheckStateChanged(this, &SFbxCompareWindow::ToggleMaterialDisplay, FMaterialCompareData::EMaterialCompareDisplayOption::SkinxxError) + .IsChecked(this, &SFbxCompareWindow::IsToggleMaterialDisplayChecked, FMaterialCompareData::EMaterialCompareDisplayOption::SkinxxError) + [ + SNew(STextBlock) + .Text(LOCTEXT("SFbxCompareWindow_Display_Option_SkinxxError", "SkinXX Error")) + .ColorAndOpacity(FSlateColor(FLinearColor::Red)) + .ToolTipText(LOCTEXT("SFbxCompareWindow_Display_Option_SkinxxError_tooltip", "The list of materials will not be re-order correctly.")) + ] + ] + ] + ] + ] + ] + ]; +} + +void SFbxCompareWindow::ToggleMaterialDisplay(ECheckBoxState InNewValue, FMaterialCompareData::EMaterialCompareDisplayOption InDisplayOption) +{ + //Cannot uncheck a radio button + if (InNewValue != ECheckBoxState::Checked) + { + return; + } + CurrentDisplayOption = InDisplayOption; + for (TSharedPtr CompareMaterial : CompareMaterialListItem) + { + CompareMaterial->CompareDisplayOption = CurrentDisplayOption; + } +} + +ECheckBoxState SFbxCompareWindow::IsToggleMaterialDisplayChecked(FMaterialCompareData::EMaterialCompareDisplayOption InDisplayOption) const +{ + return CurrentDisplayOption == InDisplayOption ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; +} + +TSharedRef SFbxCompareWindow::OnGenerateRowGeneralFbxInfo(TSharedPtr InItem, const TSharedRef& OwnerTable) +{ + int32 GeneralListIndex = GeneralListItem.Find(InItem); + bool LightBackgroundColor = GeneralListIndex % 2 == 1; + return SNew(STableRow >, OwnerTable) + [ + SNew(STextBlock).Text(FText::FromString(*(InItem.Get()))) + ]; +} + +TSharedRef SFbxCompareWindow::OnGenerateRowForCompareMaterialList(TSharedPtr RowData, const TSharedRef& Table) +{ + TSharedRef< SCompareRowDataTableListViewRow > ReturnRow = SNew(SCompareRowDataTableListViewRow, Table) + .CompareRowData(RowData); + return ReturnRow; +} + +FSlateColor FMaterialCompareData::GetCellColor(FCompMesh *DataA, int32 MaterialIndexA, int32 MaterialMatchA, FCompMesh *DataB, int32 MaterialIndexB, bool bSkinxxError) const +{ + if (!DataA->CompMaterials.IsValidIndex(MaterialIndexA)) + { + return FSlateColor::UseForeground(); + } + + bool bMatchIndexChanged = MaterialMatchA == INDEX_NONE || (DataA->CompMaterials.IsValidIndex(MaterialIndexA) && DataB->CompMaterials.IsValidIndex(MaterialIndexB) && MaterialMatchA == MaterialIndexB); + + if ((CompareDisplayOption == NoMatch || CompareDisplayOption == All) && MaterialMatchA == INDEX_NONE) + { + //There is no match for this material, so it will be add to the material array + return FSlateColor(FLinearColor(0.7f, 0.3f, 0.0f)); + } + if ((CompareDisplayOption == IndexChanged || CompareDisplayOption == All) && !bMatchIndexChanged) + { + //The match index has changed, so index base gameplay will be broken + return FSlateColor(FLinearColor::Yellow); + } + if ((CompareDisplayOption == SkinxxError || CompareDisplayOption == All) && bSkinxxError) + { + //Skinxx error + return FSlateColor(FLinearColor::Red); + } + return FSlateColor::UseForeground(); +} + +TSharedRef FMaterialCompareData::ConstructCell(FCompMesh *MeshData, int32 MeshMaterialIndex, bool bSkinxxDuplicate, bool bSkinxxMissing) +{ + if (!MeshData->CompMaterials.IsValidIndex(MeshMaterialIndex)) + { + return SNew(SBox) + .Padding(FMargin(5.0f, 0.0f, 0.0f, 0.0f)) + [ + SNew(STextBlock) + .Text(LOCTEXT("FMaterialCompareData_EmptyCell", "")) + ]; + } + FString CellContent = MeshData->CompMaterials[MeshMaterialIndex].ImportedMaterialSlotName.ToString(); + FString CellTooltip = TEXT("Material Slot Name: ") + MeshData->CompMaterials[MeshMaterialIndex].MaterialSlotName.ToString(); + if (bSkinxxDuplicate) + { + CellTooltip += TEXT(" (skinxx duplicate)"); + } + if (bSkinxxMissing) + { + CellTooltip += TEXT(" (skinxx missing)"); + } + + return SNew(SBox) + .Padding(FMargin(5.0f, 0.0f, 0.0f, 0.0f)) + [ + SNew(STextBlock) + .Text(FText::FromString(CellContent)) + .ToolTipText(FText::FromString(CellTooltip)) + .ColorAndOpacity(this, MeshData == CurrentData ? &FMaterialCompareData::GetCurrentCellColor : &FMaterialCompareData::GetFbxCellColor) + ]; +} + +FSlateColor FMaterialCompareData::GetCurrentCellColor() const +{ + return GetCellColor(CurrentData, CurrentMaterialIndex, CurrentMaterialMatch, FbxData, FbxMaterialIndex, bCurrentSkinxxDuplicate || bCurrentSkinxxMissing); +} + +TSharedRef FMaterialCompareData::ConstructCellCurrent() +{ + return ConstructCell(CurrentData, CurrentMaterialIndex, bCurrentSkinxxDuplicate, bCurrentSkinxxMissing); +} + +FSlateColor FMaterialCompareData::GetFbxCellColor() const +{ + return GetCellColor(FbxData, FbxMaterialIndex, FbxMaterialMatch, CurrentData, CurrentMaterialIndex, bFbxSkinxxDuplicate || bFbxSkinxxMissing); +} + +TSharedRef FMaterialCompareData::ConstructCellFbx() +{ + return ConstructCell(FbxData, FbxMaterialIndex, bFbxSkinxxDuplicate, bFbxSkinxxMissing); +} + +void SFbxCompareWindow::FillGeneralListItem() +{ + GeneralListItem.Add(MakeShareable(new FString(FbxGeneralInfo.UE4SdkVersion))); + GeneralListItem.Add(MakeShareable(new FString(FbxGeneralInfo.ApplicationCreator))); + GeneralListItem.Add(MakeShareable(new FString(FbxGeneralInfo.CreationDate))); + GeneralListItem.Add(MakeShareable(new FString(FbxGeneralInfo.FileVersion))); + GeneralListItem.Add(MakeShareable(new FString(FbxGeneralInfo.AxisSystem))); + GeneralListItem.Add(MakeShareable(new FString(FbxGeneralInfo.UnitSystem))); + GeneralListItem.Add(MakeShareable(new FString(TEXT("Unskinned Mesh Count: ") + FString::FromInt(FbxSceneInfo->NonSkinnedMeshNum)))); + GeneralListItem.Add(MakeShareable(new FString(TEXT("Skinned Count: ") + FString::FromInt(FbxSceneInfo->SkinnedMeshNum)))); + GeneralListItem.Add(MakeShareable(new FString(TEXT("Material Count: ") + FString::FromInt(FbxSceneInfo->TotalMaterialNum)))); + FString HasAnimationStr = TEXT("Has Animation: "); + HasAnimationStr += FbxSceneInfo->bHasAnimation ? TEXT("True") : TEXT("False"); + GeneralListItem.Add(MakeShareable(new FString(HasAnimationStr))); + if (FbxSceneInfo->bHasAnimation) + { + TArray Args; + Args.Add(FbxSceneInfo->TotalTime); + FString AnimationTimeStr = FString::Format(TEXT("Animation Time: {0}"), Args); + GeneralListItem.Add(MakeShareable(new FString(AnimationTimeStr))); + + Args.Empty(); + Args.Add(FbxSceneInfo->FrameRate); + FString AnimationRateStr = FString::Format(TEXT("Animation Rate: {0}"), Args); + GeneralListItem.Add(MakeShareable(new FString(AnimationRateStr))); + } +} + +/* +* Return true if there is some skinxx error. Both array will be allocate to the size of the materials array of MeshData +*/ +bool SFbxCompareWindow::FindSkinxxErrors(FCompMesh *MeshData, TArray &DuplicateSkinxxMaterialNames, TArray &MissingSkinxxSuffixeMaterialNames) +{ + MissingSkinxxSuffixeMaterialNames.Empty(); + MissingSkinxxSuffixeMaterialNames.AddZeroed(MeshData->CompMaterials.Num()); + DuplicateSkinxxMaterialNames.Empty(); + DuplicateSkinxxMaterialNames.AddZeroed(MeshData->CompMaterials.Num()); + TArray SkinxxErrorIndexes; + bool bContainSkinxxIndex = false; + for (FCompMaterial CompMaterial : MeshData->CompMaterials) + { + if (CompMaterial.ImportedMaterialSlotName == NAME_None) + { + continue; + } + FString ImportedMaterialName = CompMaterial.ImportedMaterialSlotName.ToString(); + int32 Offset = ImportedMaterialName.Find(TEXT("_SKIN"), ESearchCase::IgnoreCase, ESearchDir::FromEnd); + if (Offset != INDEX_NONE) + { + FString SkinXXNumber = ImportedMaterialName.Right(ImportedMaterialName.Len() - (Offset + 1)).RightChop(4); + if (SkinXXNumber.IsNumeric()) + { + bContainSkinxxIndex = true; + break; + } + } + } + + //There is no skinxx suffixe, so no skinxx error + if (!bContainSkinxxIndex) + { + return false; + } + + bool bContainSkinxxError = false; + for (int32 MaterialNamesIndex = 0; MaterialNamesIndex < MeshData->CompMaterials.Num(); ++MaterialNamesIndex) + { + FName MaterialName = MeshData->CompMaterials[MaterialNamesIndex].ImportedMaterialSlotName; + if (MaterialName == NAME_None) + { + MissingSkinxxSuffixeMaterialNames[MaterialNamesIndex] = true; + bContainSkinxxError = true; + continue; + } + + FString ImportedMaterialName = MaterialName.ToString(); + int32 Offset = ImportedMaterialName.Find(TEXT("_SKIN"), ESearchCase::IgnoreCase, ESearchDir::FromEnd); + if (Offset != INDEX_NONE) + { + FString SkinXXNumber = ImportedMaterialName.Right(ImportedMaterialName.Len() - (Offset + 1)).RightChop(4); + + if (SkinXXNumber.IsNumeric()) + { + int32 TmpIndex = FPlatformString::Atoi(*SkinXXNumber); + if (SkinxxErrorIndexes.Contains(TmpIndex)) + { + DuplicateSkinxxMaterialNames[MaterialNamesIndex] = true; + bContainSkinxxError = true; + } + SkinxxErrorIndexes.Add(TmpIndex); + } + else + { + MissingSkinxxSuffixeMaterialNames[MaterialNamesIndex] = true; + bContainSkinxxError = true; + } + } + else + { + MissingSkinxxSuffixeMaterialNames[MaterialNamesIndex] = true; + bContainSkinxxError = true; + } + } + return bContainSkinxxError; +} + +void SFbxCompareWindow::FillMaterialListItem() +{ + TArray CurrentDuplicateSkinxx; + TArray CurrentMissingSkinxxSuffixe; + FindSkinxxErrors(CurrentMeshData, CurrentDuplicateSkinxx, CurrentMissingSkinxxSuffixe); + + TArray FbxDuplicateSkinxx; + TArray FbxMissingSkinxxSuffixe; + FindSkinxxErrors(FbxMeshData, FbxDuplicateSkinxx, FbxMissingSkinxxSuffixe); + + //Build the compare data to show in the UI + int32 MaterialCompareRowNumber = FMath::Max(CurrentMeshData->CompMaterials.Num(), FbxMeshData->CompMaterials.Num()); + for (int32 RowIndex = 0; RowIndex < MaterialCompareRowNumber; ++RowIndex) + { + TSharedPtr CompareRowData = MakeShareable(new FMaterialCompareData()); + CompareRowData->RowIndex = CompareMaterialListItem.Add(CompareRowData); + CompareRowData->CurrentData = CurrentMeshData; + CompareRowData->FbxData = FbxMeshData; + + CompareRowData->bCurrentSkinxxDuplicate = CurrentDuplicateSkinxx.IsValidIndex(RowIndex) && CurrentDuplicateSkinxx[RowIndex]; + CompareRowData->bCurrentSkinxxMissing = CurrentMissingSkinxxSuffixe.IsValidIndex(RowIndex) && CurrentMissingSkinxxSuffixe[RowIndex]; + CompareRowData->bFbxSkinxxDuplicate = FbxDuplicateSkinxx.IsValidIndex(RowIndex) && FbxDuplicateSkinxx[RowIndex]; + CompareRowData->bFbxSkinxxDuplicate = FbxMissingSkinxxSuffixe.IsValidIndex(RowIndex) && FbxMissingSkinxxSuffixe[RowIndex]; + + CompareRowData->CompareDisplayOption = FMaterialCompareData::All; + if (CurrentMeshData->CompMaterials.IsValidIndex(RowIndex)) + { + CompareRowData->CurrentMaterialIndex = RowIndex; + for (int32 FbxMaterialIndex = 0; FbxMaterialIndex < FbxMeshData->CompMaterials.Num(); ++FbxMaterialIndex) + { + if (FbxMeshData->CompMaterials[FbxMaterialIndex].ImportedMaterialSlotName == CurrentMeshData->CompMaterials[RowIndex].ImportedMaterialSlotName) + { + CompareRowData->CurrentMaterialMatch = FbxMaterialIndex; + break; + } + } + } + if (FbxMeshData->CompMaterials.IsValidIndex(RowIndex)) + { + CompareRowData->FbxMaterialIndex = RowIndex; + for (int32 CurrentMaterialIndex = 0; CurrentMaterialIndex < CurrentMeshData->CompMaterials.Num(); ++CurrentMaterialIndex) + { + if (CurrentMeshData->CompMaterials[CurrentMaterialIndex].ImportedMaterialSlotName == FbxMeshData->CompMaterials[RowIndex].ImportedMaterialSlotName) + { + CompareRowData->FbxMaterialMatch = CurrentMaterialIndex; + break; + } + } + } + } +} + +TSharedPtr SFbxCompareWindow::ConstructSkeletonComparison() +{ + if (!PreviewObject->IsA(USkeletalMesh::StaticClass())) + { + //Return an empty widget, we do not show the skeleton when the mesh is not a skeletal mesh + return SNew(SBox); + } + + FString SkeletonStatusTooltip; + if (AssetReferencingSkeleton.Num() > 0) + { + SkeletonStatusTooltip += TEXT("Skeleton is references by ") + FString::FromInt(AssetReferencingSkeleton.Num()) + TEXT(" assets."); + } + + FText SkeletonStatus = FText(FbxMeshData->CompSkeleton.bSkeletonFitMesh ? LOCTEXT("SFbxCompareWindow_ConstructSkeletonComparison_MatchAndMerge", "The skeleton can be merged") : LOCTEXT("SFbxCompareWindow_ConstructSkeletonComparison_CannotMatchAndMerge", "The skeleton must be regenerated, it cannot be merged")); + + CompareTree = SNew(STreeView< TSharedPtr >) + .ItemHeight(24) + .SelectionMode(ESelectionMode::None) + .TreeItemsSource(&DisplaySkeletonTreeItem) + .OnGenerateRow(this, &SFbxCompareWindow::OnGenerateRowCompareTreeView) + .OnGetChildren(this, &SFbxCompareWindow::OnGetChildrenRowCompareTreeView); + + + return SNew(SBox) + .MaxDesiredHeight(600) + [ + SNew(SBorder) + .Padding(FMargin(3)) + .BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder")) + [ + SNew(SVerticalBox) + +SVerticalBox::Slot() + .AutoHeight() + .Padding(2) + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(SButton) + .HAlign(HAlign_Center) + .VAlign(VAlign_Center) + .IsFocusable(false) + .ButtonStyle(FEditorStyle::Get(), "NoBorder") + .OnClicked(this, &SFbxCompareWindow::SetSectionVisible, EFBXCompareSection_Skeleton) + [ + SNew(SImage).Image(this, &SFbxCompareWindow::GetCollapsableArrow, EFBXCompareSection_Skeleton) + ] + ] + + SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(STextBlock) + .Font(FEditorStyle::GetFontStyle("DetailsView.CategoryFontStyle")) + .Text(LOCTEXT("SFbxCompareWindow_SkeletonCompareHeader", "Skeleton")) + ] + ] + +SVerticalBox::Slot() + .FillHeight(1.0f) + .Padding(2) + [ + SNew(SBox) + .Visibility(TAttribute::Create(TAttribute::FGetter::CreateSP(this, &SFbxCompareWindow::IsSectionVisible, EFBXCompareSection_Skeleton))) + [ + SNew(SBorder) + .Padding(FMargin(3)) + .BorderImage(FEditorStyle::GetBrush("ToolPanel.DarkGroupBorder")) + [ + SNew(SVerticalBox) + +SVerticalBox::Slot() + .AutoHeight() + .Padding(2) + [ + SNew(STextBlock) + .Font(FEditorStyle::GetFontStyle("DetailsView.CategoryFontStyle")) + .Text(SkeletonStatus) + .ToolTipText(FText::FromString(SkeletonStatusTooltip)) + .ColorAndOpacity(FbxMeshData->CompSkeleton.bSkeletonFitMesh ? FSlateColor::UseForeground() : FSlateColor(FLinearColor(0.7f, 0.3f, 0.0f))) + ] + +SVerticalBox::Slot() + .AutoHeight() + .Padding(2) + [ + SNew(SSeparator) + .Orientation(EOrientation::Orient_Horizontal) + ] + +SVerticalBox::Slot() + .FillHeight(1.0f) + .Padding(2) + [ + SNew(SVerticalBox) + +SVerticalBox::Slot() + .FillHeight(1.0f) + [ + CompareTree.ToSharedRef() + ] + + SVerticalBox::Slot() + .AutoHeight() + .Padding(2) + [ + SNew(SSeparator) + .Orientation(EOrientation::Orient_Horizontal) + ] + +SVerticalBox::Slot() + .AutoHeight() + .MaxHeight(200.0f) + [ + //Show the general fbx information + SNew(SListView>) + .ListItemsSource(&AssetReferencingSkeleton) + .OnGenerateRow(this, &SFbxCompareWindow::OnGenerateRowAssetReferencingSkeleton) + ] + ] + ] + ] + ] + ] + ]; +} + +class SCompareSkeletonTreeViewItem : public STableRow< TSharedPtr > +{ +public: + + SLATE_BEGIN_ARGS(SCompareSkeletonTreeViewItem) + : _SkeletonCompareData(nullptr) + , _CurrentMeshData(nullptr) + , _FbxMeshData(nullptr) + {} + + /** The item content. */ + SLATE_ARGUMENT(TSharedPtr, SkeletonCompareData) + SLATE_ARGUMENT(FCompMesh*, CurrentMeshData) + SLATE_ARGUMENT(FCompMesh*, FbxMeshData) + SLATE_END_ARGS() + + /** + * Construct the widget + * + * @param InArgs A declaration from which to construct the widget + */ + void Construct(const FArguments& InArgs, const TSharedRef& InOwnerTableView) + { + SkeletonCompareData = InArgs._SkeletonCompareData; + CurrentMeshData = InArgs._CurrentMeshData; + FbxMeshData = InArgs._FbxMeshData; + + //This is suppose to always be valid + check(SkeletonCompareData.IsValid()); + check(CurrentMeshData != nullptr); + check(FbxMeshData != nullptr); + + const FSlateBrush* JointIcon = SkeletonCompareData->bMatchJoint ? FEditorStyle::GetDefaultBrush() : SkeletonCompareData->FbxJointIndex != INDEX_NONE ? FEditorStyle::GetBrush("FBXIcon.ReimportCompareAdd") : FEditorStyle::GetBrush("FBXIcon.ReimportCompareRemoved"); + + //Prepare the tooltip + FString Tooltip = SkeletonCompareData->bMatchJoint ? TEXT("") : FText(SkeletonCompareData->FbxJointIndex != INDEX_NONE ? LOCTEXT("SCompareSkeletonTreeViewItem_AddJoint_tooltip", "Fbx reimport will add this joint") : LOCTEXT("SCompareSkeletonTreeViewItem_RemoveJoint_tooltip", "Fbx reimport will remove this joint")).ToString(); + + this->ChildSlot + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(SExpanderArrow, SharedThis(this)) + ] + + + SHorizontalBox::Slot() + .AutoWidth() + .Padding(0.0f, 2.0f, 6.0f, 2.0f) + [ + SNew(SImage) + .Image(JointIcon) + .Visibility(JointIcon != FEditorStyle::GetDefaultBrush() ? EVisibility::Visible : EVisibility::Collapsed) + ] + + SHorizontalBox::Slot() + .FillWidth(1.0f) + .Padding(0.0f, 3.0f, 6.0f, 3.0f) + .VAlign(VAlign_Center) + [ + SNew(STextBlock) + .Text(FText::FromString(SkeletonCompareData->JointName.ToString())) + .ToolTipText(FText::FromString(Tooltip)) + .ColorAndOpacity(SkeletonCompareData->bMatchJoint && !SkeletonCompareData->bChildConflict ? FSlateColor::UseForeground() : FSlateColor(FLinearColor(0.7f, 0.3f, 0.0f))) + ] + ]; + + STableRow< TSharedPtr >::ConstructInternal( + STableRow::FArguments() + .ShowSelection(true), + InOwnerTableView + ); + } + +private: + /** The node info to build the tree view row from. */ + TSharedPtr SkeletonCompareData; + FCompMesh *CurrentMeshData; + FCompMesh *FbxMeshData; +}; + + +TSharedRef SFbxCompareWindow::OnGenerateRowCompareTreeView(TSharedPtr RowData, const TSharedRef& Table) +{ + TSharedRef< SCompareSkeletonTreeViewItem > ReturnRow = SNew(SCompareSkeletonTreeViewItem, Table) + .SkeletonCompareData(RowData) + .CurrentMeshData(CurrentMeshData) + .FbxMeshData(FbxMeshData); + return ReturnRow; +} + +void SFbxCompareWindow::OnGetChildrenRowCompareTreeView(TSharedPtr InParent, TArray< TSharedPtr >& OutChildren) +{ + for (int32 ChildIndex = 0; ChildIndex < InParent->ChildJoints.Num(); ++ChildIndex) + { + TSharedPtr ChildJoint = InParent->ChildJoints[ChildIndex]; + if (ChildJoint.IsValid()) + { + OutChildren.Add(ChildJoint); + } + } +} + +TSharedRef SFbxCompareWindow::OnGenerateRowAssetReferencingSkeleton(TSharedPtr InItem, const TSharedRef& OwnerTable) +{ + int32 AssetListIndex = AssetReferencingSkeleton.Find(InItem); + bool LightBackgroundColor = AssetListIndex % 2 == 1; + return SNew(STableRow >, OwnerTable) + [ + SNew(SBorder) + .BorderImage(LightBackgroundColor ? FEditorStyle::GetBrush("ToolPanel.GroupBorder") : FEditorStyle::GetBrush("ToolPanel.DarkGroupBorder")) + [ + SNew(STextBlock) + .Text(FText::FromString(*(InItem.Get()))) + //.ColorAndOpacity(LightBackgroundColor ? FSlateColor::UseSubduedForeground() : FSlateColor::UseForeground()) + ] + ]; +} + +void SFbxCompareWindow::FilSkeletonTreeItem() +{ + //Create all the entries + for (int32 RowIndex = 0; RowIndex < CurrentMeshData->CompSkeleton.Joints.Num(); ++RowIndex) + { + TSharedPtr CompareRowData = MakeShareable(new FSkeletonCompareData()); + int32 AddedIndex = CurrentSkeletonTreeItem.Add(CompareRowData); + check(AddedIndex == RowIndex); + CompareRowData->CurrentJointIndex = RowIndex; + CompareRowData->JointName = CurrentMeshData->CompSkeleton.Joints[RowIndex].Name; + CompareRowData->ChildJointIndexes = CurrentMeshData->CompSkeleton.Joints[RowIndex].ChildIndexes; + } + + //Set the childrens and parent pointer + for (int32 RowIndex = 0; RowIndex < CurrentMeshData->CompSkeleton.Joints.Num(); ++RowIndex) + { + check(CurrentSkeletonTreeItem.IsValidIndex(RowIndex)); + TSharedPtr CompareRowData = CurrentSkeletonTreeItem[RowIndex]; + if (CurrentSkeletonTreeItem.IsValidIndex(CurrentMeshData->CompSkeleton.Joints[RowIndex].ParentIndex)) + { + CompareRowData->ParentJoint = CurrentSkeletonTreeItem[CurrentMeshData->CompSkeleton.Joints[RowIndex].ParentIndex]; + } + + for (int32 ChildJointIndex = 0; ChildJointIndex < CompareRowData->ChildJointIndexes.Num(); ++ChildJointIndex) + { + if (CurrentSkeletonTreeItem.IsValidIndex(CompareRowData->ChildJointIndexes[ChildJointIndex])) + { + CompareRowData->ChildJoints.Add(CurrentSkeletonTreeItem[CompareRowData->ChildJointIndexes[ChildJointIndex]]); + } + } + } + + for (int32 RowIndex = 0; RowIndex < FbxMeshData->CompSkeleton.Joints.Num(); ++RowIndex) + { + TSharedPtr CompareRowData = MakeShareable(new FSkeletonCompareData()); + int32 AddedIndex = FbxSkeletonTreeItem.Add(CompareRowData); + check(AddedIndex == RowIndex); + CompareRowData->FbxJointIndex = RowIndex; + CompareRowData->JointName = FbxMeshData->CompSkeleton.Joints[RowIndex].Name; + CompareRowData->ChildJointIndexes = FbxMeshData->CompSkeleton.Joints[RowIndex].ChildIndexes; + } + + //Set the childrens and parent pointer + for (int32 RowIndex = 0; RowIndex < FbxMeshData->CompSkeleton.Joints.Num(); ++RowIndex) + { + check(FbxSkeletonTreeItem.IsValidIndex(RowIndex)); + TSharedPtr CompareRowData = FbxSkeletonTreeItem[RowIndex]; + if (FbxSkeletonTreeItem.IsValidIndex(FbxMeshData->CompSkeleton.Joints[RowIndex].ParentIndex)) + { + CompareRowData->ParentJoint = FbxSkeletonTreeItem[FbxMeshData->CompSkeleton.Joints[RowIndex].ParentIndex]; + } + + for (int32 ChildJointIndex = 0; ChildJointIndex < CompareRowData->ChildJointIndexes.Num(); ++ChildJointIndex) + { + if (FbxSkeletonTreeItem.IsValidIndex(CompareRowData->ChildJointIndexes[ChildJointIndex])) + { + CompareRowData->ChildJoints.Add(FbxSkeletonTreeItem[CompareRowData->ChildJointIndexes[ChildJointIndex]]); + } + } + } +} + +void SFbxCompareWindow::RecursiveMatchJointInfo(TSharedPtr SkeletonItem) +{ + TArray> DisplayChilds; + //Find the display child + if (CurrentSkeletonTreeItem.IsValidIndex(SkeletonItem->CurrentJointIndex)) + { + for (int32 ChildIndex = 0; ChildIndex < CurrentSkeletonTreeItem[SkeletonItem->CurrentJointIndex]->ChildJoints.Num(); ++ChildIndex) + { + DisplayChilds.Add(CurrentSkeletonTreeItem[SkeletonItem->CurrentJointIndex]->ChildJoints[ChildIndex]); + } + } + if (FbxSkeletonTreeItem.IsValidIndex(SkeletonItem->FbxJointIndex)) + { + for (int32 ChildIndex = 0; ChildIndex < FbxSkeletonTreeItem[SkeletonItem->FbxJointIndex]->ChildJoints.Num(); ++ChildIndex) + { + TSharedPtr FbxSkeletonItem = FbxSkeletonTreeItem[SkeletonItem->FbxJointIndex]->ChildJoints[ChildIndex]; + bool bFoundChildMatch = false; + for (TSharedPtr DisplayChildJoint : DisplayChilds) + { + if (DisplayChildJoint->JointName == FbxSkeletonItem->JointName) + { + bFoundChildMatch = true; + DisplayChildJoint->bMatchJoint = true; + DisplayChildJoint->FbxJointIndex = FbxSkeletonItem->FbxJointIndex; + break; + } + } + if (!bFoundChildMatch) + { + DisplayChilds.Add(FbxSkeletonItem); + } + } + } + + if (!SkeletonItem->bMatchJoint) + { + TSharedPtr ParentSkeletonItem = SkeletonItem->ParentJoint; + while (ParentSkeletonItem.IsValid() && ParentSkeletonItem->bChildConflict == false) + { + ParentSkeletonItem->bChildConflict = true; + ParentSkeletonItem = ParentSkeletonItem->ParentJoint; + } + } + //Set the new child list to the display joint + SkeletonItem->ChildJoints = DisplayChilds; + SkeletonItem->ChildJointIndexes.Empty(); + for (TSharedPtr ChildJoint : SkeletonItem->ChildJoints) + { + ChildJoint->ParentJoint = SkeletonItem; + RecursiveMatchJointInfo(ChildJoint); + } +} + +void SFbxCompareWindow::SetMatchJointInfo() +{ + TArray> RootJoint; + for (TSharedPtr CurrentSkeletonItem : CurrentSkeletonTreeItem) + { + if (!CurrentSkeletonItem->ParentJoint.IsValid()) + { + DisplaySkeletonTreeItem.Add(CurrentSkeletonItem); + } + } + for (TSharedPtr CurrentSkeletonItem : FbxSkeletonTreeItem) + { + if (!CurrentSkeletonItem->ParentJoint.IsValid()) + { + bool bInsertJoint = true; + for (TSharedPtr DisplayTreeItem : DisplaySkeletonTreeItem) + { + if(DisplayTreeItem->JointName == CurrentSkeletonItem->JointName) + { + DisplayTreeItem->FbxJointIndex = CurrentSkeletonItem->FbxJointIndex; + DisplayTreeItem->bMatchJoint = true; + bInsertJoint = false; + } + } + if (bInsertJoint) + { + DisplaySkeletonTreeItem.Add(CurrentSkeletonItem); + } + } + } + + for (int32 SkeletonTreeIndex = 0; SkeletonTreeIndex < DisplaySkeletonTreeItem.Num(); ++SkeletonTreeIndex) + { + RecursiveMatchJointInfo(DisplaySkeletonTreeItem[SkeletonTreeIndex]); + } +} +#undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxFactory.cpp b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxFactory.cpp index fc6a2cf50434..dc2464f3d249 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxFactory.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxFactory.cpp @@ -14,6 +14,8 @@ #include "Engine/StaticMesh.h" #include "Editor.h" +#include "EditorReimportHandler.h" + #include "Logging/TokenizedMessage.h" #include "FbxImporter.h" @@ -155,6 +157,8 @@ UObject* UFbxFactory::FactoryCreateBinary bool& bOutOperationCanceled ) { + CA_ASSUME(InParent); + if( bOperationCanceled ) { bOutOperationCanceled = true; @@ -165,8 +169,47 @@ UObject* UFbxFactory::FactoryCreateBinary FEditorDelegates::OnAssetPreImport.Broadcast(this, Class, InParent, Name, Type); UObject* NewObject = NULL; + + //Look if its a re-import, in that cazse we must call the re-import factory + UObject *ExistingObject = nullptr; + UFbxStaticMeshImportData* ExistingStaticMeshImportData = nullptr; + UFbxSkeletalMeshImportData* ExistingSkeletalMeshImportData = nullptr; + if (InParent != nullptr) + { + ExistingObject = StaticFindObject(UObject::StaticClass(), InParent, *(Name.ToString())); + if (ExistingObject) + { + UStaticMesh *ExistingStaticMesh = Cast(ExistingObject); + USkeletalMesh *ExistingSkeletalMesh = Cast(ExistingObject); + UObject *ObjectToReimport = nullptr; + if (ExistingStaticMesh) + { + ObjectToReimport = ExistingStaticMesh; + } + else if (ExistingSkeletalMesh) + { + ObjectToReimport = ExistingSkeletalMesh; + } - if ( bDetectImportTypeOnImport ) + if (ObjectToReimport != nullptr) + { + TArray ToReimportObjects; + ToReimportObjects.Add(ObjectToReimport); + TArray Filenames; + Filenames.Add(UFactory::CurrentFilename); + //Set the new fbx source path before starting the re-import + FReimportManager::Instance()->UpdateReimportPaths(ObjectToReimport, Filenames); + //Do the re-import and exit + FReimportManager::Instance()->ValidateAllSourceFileAndReimport(ToReimportObjects); + return ObjectToReimport; + } + } + } + + //We are not re-importing + ImportUI->bIsReimport = false; + + if ( bDetectImportTypeOnImport) { if ( !DetectImportType(UFactory::CurrentFilename) ) { @@ -200,7 +243,7 @@ UObject* UFbxFactory::FactoryCreateBinary bool bIsAutomated = IsAutomatedImport(); bool bShowImportDialog = bShowOption && !bIsAutomated; bool bImportAll = false; - ImportOptions = GetImportOptions(FbxImporter, ImportUI, bShowImportDialog, bIsAutomated, InParent->GetPathName(), bOperationCanceled, bImportAll, bIsObjFormat, bIsObjFormat, ForcedImportType ); + ImportOptions = GetImportOptions(FbxImporter, ImportUI, bShowImportDialog, bIsAutomated, InParent->GetPathName(), bOperationCanceled, bImportAll, bIsObjFormat, bIsObjFormat, ForcedImportType, ExistingObject); bOutOperationCanceled = bOperationCanceled; if( bImportAll ) @@ -763,6 +806,7 @@ IImportSettingsParser* UFbxFactory::GetImportSettingsParser() UFbxImportUI::UFbxImportUI(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { + bIsReimport = false; bAutomatedImportShouldDetectType = true; StaticMeshImportData = CreateDefaultSubobject(TEXT("StaticMeshImportData")); @@ -846,5 +890,13 @@ void UFbxImportUI::ParseFromJson(TSharedRef ImportSettingsJso } } +void UFbxImportUI::ResetToDefault() +{ + ReloadConfig(); + AnimSequenceImportData->ReloadConfig(); + StaticMeshImportData->ReloadConfig(); + SkeletalMeshImportData->ReloadConfig(); + TextureImportData->ReloadConfig(); +} #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxMainExport.cpp b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxMainExport.cpp index d0580571d92e..a98b50711812 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxMainExport.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxMainExport.cpp @@ -3213,8 +3213,7 @@ FbxNode* FFbxExporter::ExportCollisionMesh(const UStaticMesh* StaticMesh, const { return nullptr; } - FbxMesh* Mesh = nullptr; - Mesh = FbxMeshes.FindRef(StaticMesh); + FbxMesh* Mesh = FbxMeshes.FindRef(StaticMesh); if (!Mesh) { //We export collision only if the mesh is already exported @@ -3226,7 +3225,7 @@ FbxNode* FFbxExporter::ExportCollisionMesh(const UStaticMesh* StaticMesh, const Mesh = FbxMesh::Create(Scene, TCHAR_TO_UTF8(*MeshCollisionName)); //Name the node with the actor name MeshCollisionName = TEXT("UCX_"); - MeshCollisionName += UTF8_TO_TCHAR(ParentActor->GetName()); + MeshCollisionName += UTF8_TO_TCHAR(ParentActor->GetName()); //-V595 FbxNode* FbxActor = FbxNode::Create(Scene, TCHAR_TO_UTF8(*MeshCollisionName)); FbxNode *ParentOfParentMesh = nullptr; @@ -3999,9 +3998,9 @@ void FFbxExporter::ExportLandscapeToFbx(ALandscapeProxy* Landscape, const TCHAR* FVector Normal, TangentX, TangentY; CDI.GetLocalTangentVectors(VertX, VertY, TangentX, TangentY, Normal); - Normal /= Component->ComponentToWorld.GetScale3D(); Normal.Normalize(); - TangentX /= Component->ComponentToWorld.GetScale3D(); TangentX.Normalize(); - TangentY /= Component->ComponentToWorld.GetScale3D(); TangentY.Normalize(); + Normal /= Component->GetComponentTransform().GetScale3D(); Normal.Normalize(); + TangentX /= Component->GetComponentTransform().GetScale3D(); TangentX.Normalize(); + TangentY /= Component->GetComponentTransform().GetScale3D(); TangentY.Normalize(); FbxVector4 FbxNormal = FbxVector4(Normal.X, -Normal.Y, Normal.Z); FbxNormal.Normalize(); Normals.SetAt(BaseVertIndex + VertIndex, FbxNormal); FbxVector4 FbxTangent = FbxVector4(TangentX.X, -TangentX.Y, TangentX.Z); FbxTangent.Normalize(); diff --git a/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxMainImport.cpp b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxMainImport.cpp index ab44f40c111b..bdac690f4488 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxMainImport.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxMainImport.cpp @@ -37,9 +37,11 @@ namespace UnFbx TSharedPtr FFbxImporter::StaticInstance; +TSharedPtr FFbxImporter::StaticPreviewInstance; -FBXImportOptions* GetImportOptions( UnFbx::FFbxImporter* FbxImporter, UFbxImportUI* ImportUI, bool bShowOptionDialog, bool bIsAutomated, const FString& FullPath, bool& OutOperationCanceled, bool& bOutImportAll, bool bIsObjFormat, bool bForceImportType, EFBXImportType ImportType ) + +FBXImportOptions* GetImportOptions( UnFbx::FFbxImporter* FbxImporter, UFbxImportUI* ImportUI, bool bShowOptionDialog, bool bIsAutomated, const FString& FullPath, bool& OutOperationCanceled, bool& bOutImportAll, bool bIsObjFormat, bool bForceImportType, EFBXImportType ImportType, UObject* ReimportObject) { OutOperationCanceled = false; @@ -100,10 +102,17 @@ FBXImportOptions* GetImportOptions( UnFbx::FFbxImporter* FbxImporter, UFbxImport TSharedRef Window = SNew(SWindow) .Title(NSLOCTEXT("UnrealEd", "FBXImportOpionsTitle", "FBX Import Options")) - .SizingRule( ESizingRule::Autosized ) + .SizingRule(ESizingRule::Autosized) .AutoCenter(EAutoCenter::None) .ScreenPosition(WindowPosition); + auto OnPreviewFbxImportLambda = FOnPreviewFbxImport::CreateLambda([=] + { + UnFbx::FFbxImporter* PreviewFbxImporter = UnFbx::FFbxImporter::GetPreviewInstance(); + PreviewFbxImporter->ShowFbxReimportPreview(ReimportObject, ImportUI, FullPath); + UnFbx::FFbxImporter::DeletePreviewInstance(); + }); + TSharedPtr FbxOptionWindow; Window->SetContent ( @@ -115,6 +124,7 @@ FBXImportOptions* GetImportOptions( UnFbx::FFbxImporter* FbxImporter, UFbxImport .IsObjFormat( bIsObjFormat ) .MaxWindowHeight(FbxImportWindowHeight) .MaxWindowWidth(FbxImportWindowWidth) + .OnPreviewFbxImport(OnPreviewFbxImportLambda) ); // @todo: we can make this slow as showing progress bar later @@ -197,6 +207,7 @@ void ApplyImportUIToImportOptions(UFbxImportUI* ImportUI, FBXImportOptions& InOu { check(ImportUI); InOutImportOptions.bImportMaterials = ImportUI->bImportMaterials; + InOutImportOptions.bResetMaterialSlots = ImportUI->bResetMaterialSlots; InOutImportOptions.bInvertNormalMap = ImportUI->TextureImportData->bInvertNormalMaps; InOutImportOptions.MaterialSearchLocation = ImportUI->TextureImportData->MaterialSearchLocation; UMaterialInterface* BaseMaterialInterface = Cast(ImportUI->TextureImportData->BaseMaterialName.TryLoad()); @@ -394,6 +405,20 @@ void FFbxImporter::DeleteInstance() StaticInstance.Reset(); } +FFbxImporter* FFbxImporter::GetPreviewInstance() +{ + if (!StaticPreviewInstance.IsValid()) + { + StaticPreviewInstance = MakeShareable(new FFbxImporter()); + } + return StaticPreviewInstance.Get(); +} + +void FFbxImporter::DeletePreviewInstance() +{ + StaticPreviewInstance.Reset(); +} + //------------------------------------------------------------------------- // //------------------------------------------------------------------------- @@ -455,7 +480,7 @@ int32 FFbxImporter::GetImportType(const FString& InFilename) if (OpenFile(Filename, true)) { FbxStatistics Statistics; - Importer->GetStatistics(&Statistics); + Importer->GetStatistics(&Statistics); //-V595 int32 ItemIndex; FbxString ItemName; int32 ItemCount; @@ -990,10 +1015,6 @@ bool FFbxImporter::ImportFile(FString Filename, bool bPreventMaterialNameClash / { UE_LOG(LogFbx, Log, TEXT("FBX Scene Loaded Succesfully")); CurPhase = IMPORTED; - - // Release importer now as it is unneeded - Importer->Destroy(); - Importer = NULL; } else { @@ -1010,6 +1031,10 @@ bool FFbxImporter::ImportFile(FString Filename, bool bPreventMaterialNameClash / void FFbxImporter::ConvertScene() { + //Set the original file information + FileAxisSystem = Scene->GetGlobalSettings().GetAxisSystem(); + FileUnitSystem = Scene->GetGlobalSettings().GetSystemUnit(); + if (GetImportOptions()->bConvertScene) { // we use -Y as forward axis here when we import. This is odd considering our forward axis is technically +X @@ -1210,8 +1235,7 @@ FName FFbxImporter::MakeNameForMesh(FString InName, FbxObject* FbxObject) } // for mesh, replace ':' with '_' because Unreal doesn't support ':' in mesh name - char* NewName = nullptr; - NewName = FCStringAnsi::Strchr (Name, ':'); + char* NewName = FCStringAnsi::Strchr(Name, ':'); if (NewName) { diff --git a/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxMaterialImport.cpp b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxMaterialImport.cpp index 92ec12b2121a..214826e9c0a4 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxMaterialImport.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxMaterialImport.cpp @@ -482,7 +482,8 @@ bool CanUseMaterialWithInstance(FbxSurfaceMaterial& FbxMaterial, const char* Mat { return false; // no support for custom uv with instanced yet } - }if (TextureCount > 1) + } + else if (TextureCount > 1) { return false; // no support for multiple textures } diff --git a/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxOptionWindow.cpp b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxOptionWindow.cpp index 295312a6065c..4ab0a8372c4a 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxOptionWindow.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxOptionWindow.cpp @@ -19,9 +19,12 @@ void SFbxOptionWindow::Construct(const FArguments& InArgs) ImportUI = InArgs._ImportUI; WidgetWindow = InArgs._WidgetWindow; bIsObjFormat = InArgs._IsObjFormat; + OnPreviewFbxImport = InArgs._OnPreviewFbxImport; check (ImportUI); - + + TSharedPtr ImportTypeDisplay; + TSharedPtr FbxHeaderButtons; TSharedPtr InspectorBox; this->ChildSlot [ @@ -30,6 +33,12 @@ void SFbxOptionWindow::Construct(const FArguments& InArgs) .MaxDesiredWidth(InArgs._MaxWindowWidth) [ SNew(SVerticalBox) + + SVerticalBox::Slot() + .AutoHeight() + .Padding(2) + [ + SAssignNew(ImportTypeDisplay, SBox) + ] +SVerticalBox::Slot() .AutoHeight() .Padding(2) @@ -109,12 +118,86 @@ void SFbxOptionWindow::Construct(const FArguments& InArgs) FDetailsViewArgs DetailsViewArgs; DetailsViewArgs.bAllowSearch = false; DetailsViewArgs.NameAreaSettings = FDetailsViewArgs::HideNameArea; - TSharedPtr DetailsView = PropertyEditorModule.CreateDetailView(DetailsViewArgs); + DetailsView = PropertyEditorModule.CreateDetailView(DetailsViewArgs); InspectorBox->SetContent(DetailsView->AsShared()); + + ImportTypeDisplay->SetContent( + SNew(SBorder) + .Padding(FMargin(3)) + .BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder")) + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .VAlign(VAlign_Center) + [ + SNew(STextBlock) + .Text(this, &SFbxOptionWindow::GetImportTypeDisplayText) + ] + + SHorizontalBox::Slot() + [ + SNew(SBox) + .HAlign(HAlign_Right) + [ + SAssignNew(FbxHeaderButtons, SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + .Padding(FMargin(2.0f, 0.0f)) + [ + SNew(SButton) + .Text(LOCTEXT("FbxOptionWindow_ResetOptions", "Reset to Default")) + .OnClicked(this, &SFbxOptionWindow::OnResetToDefaultClick) + ] + ] + ] + ] + ); + + if (ImportUI->bIsReimport && OnPreviewFbxImport.IsBound()) + { + FbxHeaderButtons->AddSlot() + .AutoWidth() + .Padding(FMargin(2.0f, 0.0f)) + [ + //Create the fbx import preview button + SNew(SButton) + .Text(LOCTEXT("FbxOptionWindow_Preview", "Preview...")) + .OnClicked(this, &SFbxOptionWindow::OnPreviewClick) + ]; + } + DetailsView->SetObject(ImportUI); } +FReply SFbxOptionWindow::OnPreviewClick() const +{ + //Pop a preview window to let the user see the content of the fbx file + OnPreviewFbxImport.ExecuteIfBound(); + return FReply::Handled(); +} + +FReply SFbxOptionWindow::OnResetToDefaultClick() const +{ + ImportUI->ResetToDefault(); + //Refresh the view to make sure the custom UI are updating correctly + DetailsView->SetObject(ImportUI, true); + return FReply::Handled(); +} + +FText SFbxOptionWindow::GetImportTypeDisplayText() const +{ + switch (ImportUI->MeshTypeToImport) + { + case EFBXImportType::FBXIT_Animation : + return ImportUI->bIsReimport ? LOCTEXT("FbxOptionWindow_ReImportTypeAnim", "Reimport Animation") : LOCTEXT("FbxOptionWindow_ImportTypeAnim", "Import Animation"); + case EFBXImportType::FBXIT_SkeletalMesh: + return ImportUI->bIsReimport ? LOCTEXT("FbxOptionWindow_ReImportTypeSK", "Reimport Skeletal Mesh") : LOCTEXT("FbxOptionWindow_ImportTypeSK", "Import Skeletal Mesh"); + case EFBXImportType::FBXIT_StaticMesh: + return ImportUI->bIsReimport ? LOCTEXT("FbxOptionWindow_ReImportTypeSM", "Reimport Static Mesh") : LOCTEXT("FbxOptionWindow_ImportTypeSM", "Import Static Mesh"); + } + return FText::GetEmpty(); +} + bool SFbxOptionWindow::CanImport() const { // do test to see if we are ready to import diff --git a/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxPreviewReimport.cpp b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxPreviewReimport.cpp new file mode 100644 index 000000000000..5b5242db7974 --- /dev/null +++ b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxPreviewReimport.cpp @@ -0,0 +1,506 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +/*============================================================================= + Static mesh creation from FBX data. + Largely based on StaticMeshEdit.cpp +=============================================================================*/ + +#include "CoreMinimal.h" +#include "Misc/Guid.h" +#include "UObject/Object.h" +#include "UObject/GarbageCollection.h" +#include "UObject/Package.h" +#include "Misc/PackageName.h" +#include "Editor.h" +#include "ObjectTools.h" +#include "PackageTools.h" +#include "FbxImporter.h" +#include "Misc/FbxErrors.h" +#include "HAL/FileManager.h" +#include "Factories/FbxSceneImportFactory.h" +#include "Toolkits/AssetEditorManager.h" +#include "AssetRegistryModule.h" + +//Windows dialog popup +#include "Widgets/DeclarativeSyntaxSupport.h" +#include "Widgets/SWindow.h" +#include "Framework/Application/SlateApplication.h" +#include "Interfaces/IMainFrameModule.h" +#include "FbxCompareWindow.h" + +//Meshes includes +#include "MeshUtilities.h" +#include "RawMesh.h" +#include "Materials/MaterialInterface.h" +#include "Materials/Material.h" +#include "GeomFitUtils.h" +#include "PhysicsAssetUtils.h" +#include "PhysicsEngine/BodySetup.h" +#include "PhysicsEngine/PhysicsAsset.h" + +//Static mesh includes +#include "Engine/StaticMesh.h" +#include "Engine/StaticMeshSocket.h" +#include "StaticMeshResources.h" +#include "Factories/FbxStaticMeshImportData.h" + +//Skeletal mesh includes +#include "SkelImport.h" +#include "SkeletalMeshTypes.h" +#include "Animation/Skeleton.h" +#include "Engine/SkeletalMesh.h" +#include "Components/SkinnedMeshComponent.h" +#include "Components/SkeletalMeshComponent.h" +#include "AnimEncoding.h" +#include "ApexClothingUtils.h" +#include "Engine/SkeletalMeshSocket.h" +#include "Assets/ClothingAsset.h" +#include "Factories/FbxSkeletalMeshImportData.h" +#include "FbxCompareWindow.h" + + + +#define LOCTEXT_NAMESPACE "FbxPreviewReimport" + +using namespace UnFbx; + +struct FCreateCompFromFbxArg +{ + FString MeshName; + bool IsStaticMesh; + bool IsStaticHasLodGroup; +}; + +void CreateCompFromSkeletalMesh(USkeletalMesh* SkeletalMesh, FCompMesh &CurrentData) +{ + //Fill the material array + for (const FSkeletalMaterial &Material : SkeletalMesh->Materials) + { + FCompMaterial CompMaterial(Material.MaterialSlotName, Material.ImportedMaterialSlotName); + CurrentData.CompMaterials.Add(CompMaterial); + } + + //Fill the section topology + if (SkeletalMesh->GetResourceForRendering()) + { + CurrentData.CompLods.AddZeroed(SkeletalMesh->GetResourceForRendering()->LODModels.Num()); + //Fill sections data + for (int32 LodIndex = 0; LodIndex < SkeletalMesh->GetResourceForRendering()->LODModels.Num(); ++LodIndex) + { + //Find the LodMaterialMap, which must be use for all LOD except the base + TArray LODMaterialMap; + if(LodIndex > 0 && SkeletalMesh->LODInfo.IsValidIndex(LodIndex)) + { + const FSkeletalMeshLODInfo &SkeletalMeshLODInfo = SkeletalMesh->LODInfo[LodIndex]; + LODMaterialMap = SkeletalMeshLODInfo.LODMaterialMap; + } + + const FStaticLODModel &StaticLodModel = SkeletalMesh->GetResourceForRendering()->LODModels[LodIndex]; + CurrentData.CompLods[LodIndex].Sections.AddZeroed(StaticLodModel.Sections.Num()); + for (int32 SectionIndex = 0; SectionIndex < StaticLodModel.Sections.Num(); ++SectionIndex) + { + const FSkelMeshSection &SkelMeshSection = StaticLodModel.Sections[SectionIndex]; + int32 MaterialIndex = SkelMeshSection.MaterialIndex; + if (LodIndex > 0 && LODMaterialMap.IsValidIndex(MaterialIndex)) + { + MaterialIndex = LODMaterialMap[MaterialIndex]; + } + CurrentData.CompLods[LodIndex].Sections[SectionIndex].MaterialIndex = MaterialIndex; + } + } + } + + //Fill the skeleton joint + CurrentData.CompSkeleton.Joints.AddZeroed(SkeletalMesh->RefSkeleton.GetNum()); + for (int JointIndex = 0; JointIndex < CurrentData.CompSkeleton.Joints.Num(); ++JointIndex) + { + CurrentData.CompSkeleton.Joints[JointIndex].Name = SkeletalMesh->RefSkeleton.GetBoneName(JointIndex); + CurrentData.CompSkeleton.Joints[JointIndex].ParentIndex = SkeletalMesh->RefSkeleton.GetParentIndex(JointIndex); + int32 ParentIndex = CurrentData.CompSkeleton.Joints[JointIndex].ParentIndex; + if (CurrentData.CompSkeleton.Joints.IsValidIndex(ParentIndex)) + { + CurrentData.CompSkeleton.Joints[ParentIndex].ChildIndexes.Add(JointIndex); + } + } + + USkeleton* Skeleton = SkeletalMesh->Skeleton; + if (Skeleton != nullptr && !Skeleton->MergeAllBonesToBoneTree(SkeletalMesh)) + { + CurrentData.CompSkeleton.bSkeletonFitMesh = false; + } +} + +void CreateCompFromStaticMesh(UStaticMesh* StaticMesh, FCompMesh &CurrentData) +{ + //Fill the material array + for (const FStaticMaterial &Material : StaticMesh->StaticMaterials) + { + FCompMaterial CompMaterial(Material.MaterialSlotName, Material.ImportedMaterialSlotName); + CurrentData.CompMaterials.Add(CompMaterial); + } + + //Fill the section topology + if (StaticMesh->RenderData) + { + CurrentData.CompLods.AddZeroed(StaticMesh->RenderData->LODResources.Num()); + + //Fill sections data + for (int32 LodIndex = 0; LodIndex < StaticMesh->RenderData->LODResources.Num(); ++LodIndex) + { + //StaticMesh->SectionInfoMap.Get() + + const FStaticMeshLODResources &StaticLodRessources = StaticMesh->RenderData->LODResources[LodIndex]; + CurrentData.CompLods[LodIndex].Sections.AddZeroed(StaticLodRessources.Sections.Num()); + for (int32 SectionIndex = 0; SectionIndex < StaticLodRessources.Sections.Num(); ++SectionIndex) + { + const FStaticMeshSection &StaticMeshSection = StaticLodRessources.Sections[SectionIndex]; + int32 MaterialIndex = StaticMeshSection.MaterialIndex; + if (StaticMesh->SectionInfoMap.IsValidSection(LodIndex, SectionIndex)) + { + FMeshSectionInfo MeshSectionInfo = StaticMesh->SectionInfoMap.Get(LodIndex, SectionIndex); + MaterialIndex = MeshSectionInfo.MaterialIndex; + } + CurrentData.CompLods[LodIndex].Sections[SectionIndex].MaterialIndex = MaterialIndex; + } + } + } +} + +void GetSkeletalMeshCompData(FFbxImporter *FbxImporter, UFbxImportUI* ImportUI, const FCreateCompFromFbxArg &CreateCompFromFbxArg, FCompMesh &FbxData, const USkeletalMesh *SkeletalMeshRef, UObject **PreviewObject) +{ + USkeletalMesh *SkeletalMesh = Cast(StaticDuplicateObject(SkeletalMeshRef, GetTransientPackage())); + + if (SkeletalMesh != nullptr && FbxImporter->ReimportSkeletalMesh(SkeletalMesh, ImportUI->SkeletalMeshImportData)) + { + if (GEditor->IsObjectInTransactionBuffer(SkeletalMesh)) + { + GEditor->ResetTransaction(LOCTEXT("PreviewReimportSkeletalMeshTransactionReset", "Preview Reimporting a skeletal mesh which was in the undo buffer")); + } + CreateCompFromSkeletalMesh(SkeletalMesh, FbxData); + } + else + { + //Log an error here + } + + *PreviewObject = SkeletalMesh; +} + +void GetStaticMeshCompData(FFbxImporter *FbxImporter, UFbxImportUI* ImportUI, const FCreateCompFromFbxArg &CreateCompFromFbxArg, FCompMesh &FbxData, const UStaticMesh* StaticMeshRef, UObject **PreviewObject) +{ + UStaticMesh *StaticMesh = Cast(StaticDuplicateObject(StaticMeshRef, GetTransientPackage())); + + if (StaticMesh != nullptr && FbxImporter->ReimportStaticMesh(StaticMesh, ImportUI->StaticMeshImportData)) + { + FbxImporter->ImportStaticMeshGlobalSockets(StaticMesh); + CreateCompFromStaticMesh(StaticMesh, FbxData); + } + else + { + //Log an error here + } + *PreviewObject = StaticMesh; +} + +void CreateCompFromFbxData(FFbxImporter *FbxImporter, UFbxImportUI* ImportUI, const FString& FullPath, FCompMesh &FbxData, const FCreateCompFromFbxArg &CreateCompFromFbxArg, UStaticMesh *StaticMesh, USkeletalMesh *SkeletalMesh, UObject **PreviewObject) +{ + FbxImporter->ImportOptions->bIsReimportPreview = true; + ////////////////////////////////////////////////////////////////////////// + //Static mesh reimport + if (CreateCompFromFbxArg.IsStaticMesh) + { + GetStaticMeshCompData(FbxImporter, ImportUI, CreateCompFromFbxArg, FbxData, StaticMesh, PreviewObject); + + } + ////////////////////////////////////////////////////////////////////////// + else //Skeletal mesh reimport + { + GetSkeletalMeshCompData(FbxImporter, ImportUI, CreateCompFromFbxArg, FbxData, SkeletalMesh, PreviewObject); + } + FbxImporter->ImportOptions->bIsReimportPreview = false; +} + +void FFbxImporter::FillGeneralFbxFileInformation(void *GeneralInfoPtr) +{ + FGeneralFbxFileInfo &FbxGeneralInfo = *(FGeneralFbxFileInfo*)GeneralInfoPtr; + FbxAxisSystem SourceSetup = Scene->GetGlobalSettings().GetAxisSystem(); + + //Get the UE4 sdk version + int32 SDKMajor, SDKMinor, SDKRevision; + FbxManager::GetFileFormatVersion(SDKMajor, SDKMinor, SDKRevision); + + int32 FileMajor, FileMinor, FileRevision; + Importer->GetFileVersion(FileMajor, FileMinor, FileRevision); + + FString DateVersion = FString(FbxManager::GetVersion(false)); + FbxGeneralInfo.UE4SdkVersion = TEXT("UE4 Sdk Version: ") + FString::FromInt(SDKMajor) + TEXT(".") + FString::FromInt(SDKMinor) + TEXT(".") + FString::FromInt(SDKRevision) + TEXT(" (") + DateVersion + TEXT(")"); + + FbxIOFileHeaderInfo *FileHeaderInfo = Importer->GetFileHeaderInfo(); + if (FileHeaderInfo) + { + FbxGeneralInfo.ApplicationCreator = TEXT("Creator: ") + FString(FileHeaderInfo->mCreator.Buffer()); + FbxGeneralInfo.FileVersion = TEXT("Fbx File Version: ") + FString::FromInt(FileMajor) + TEXT(".") + FString::FromInt(FileMinor) + TEXT(".") + FString::FromInt(FileRevision) + TEXT(" (") + FString::FromInt(FileHeaderInfo->mFileVersion) + TEXT(")"); + FbxGeneralInfo.CreationDate = TEXT("Created Time: ") + FString::FromInt(FileHeaderInfo->mCreationTimeStamp.mYear) + TEXT("-") + FString::FromInt(FileHeaderInfo->mCreationTimeStamp.mMonth) + TEXT("-") + FString::FromInt(FileHeaderInfo->mCreationTimeStamp.mDay) + TEXT(" (Y-M-D)"); + } + int32 UpVectorSign = 1; + FbxAxisSystem::EUpVector UpVector = FileAxisSystem.GetUpVector(UpVectorSign); + + int32 FrontVectorSign = 1; + FbxAxisSystem::EFrontVector FrontVector = FileAxisSystem.GetFrontVector(FrontVectorSign); + + + FbxAxisSystem::ECoordSystem CoordSystem = FileAxisSystem.GetCoorSystem(); + + FbxGeneralInfo.AxisSystem = TEXT("File Axis System: UP: "); + if (UpVectorSign == -1) + { + FbxGeneralInfo.AxisSystem = TEXT("-"); + } + FbxGeneralInfo.AxisSystem += (UpVector == FbxAxisSystem::EUpVector::eXAxis) ? TEXT("X, Front: ") : (UpVector == FbxAxisSystem::EUpVector::eYAxis) ? TEXT("Y, Front: ") : TEXT("Z, Front: "); + if (FrontVectorSign == -1) + { + FbxGeneralInfo.AxisSystem = TEXT("-"); + } + + if (UpVector == FbxAxisSystem::EUpVector::eXAxis) + { + FbxGeneralInfo.AxisSystem += (FrontVector == FbxAxisSystem::EFrontVector::eParityEven) ? TEXT("Y") : TEXT("Z"); + } + else if (UpVector == FbxAxisSystem::EUpVector::eYAxis) + { + FbxGeneralInfo.AxisSystem += (FrontVector == FbxAxisSystem::EFrontVector::eParityEven) ? TEXT("X") : TEXT("Z"); + } + else if (UpVector == FbxAxisSystem::EUpVector::eZAxis) + { + FbxGeneralInfo.AxisSystem += (FrontVector == FbxAxisSystem::EFrontVector::eParityEven) ? TEXT("X") : TEXT("Y"); + } + + //Hand side + FbxGeneralInfo.AxisSystem += (CoordSystem == FbxAxisSystem::ECoordSystem::eLeftHanded) ? TEXT(" Left Handed") : TEXT(" Right Handed"); + + + if (FileAxisSystem == FbxAxisSystem::MayaZUp) + { + FbxGeneralInfo.AxisSystem += TEXT(" (Maya ZUp)"); + } + else if (FileAxisSystem == FbxAxisSystem::MayaYUp) + { + FbxGeneralInfo.AxisSystem += TEXT(" (Maya YUp)"); + } + else if (FileAxisSystem == FbxAxisSystem::Max) + { + FbxGeneralInfo.AxisSystem += TEXT(" (Max)"); + } + else if (FileAxisSystem == FbxAxisSystem::Motionbuilder) + { + FbxGeneralInfo.AxisSystem += TEXT(" (Motion Builder)"); + } + else if (FileAxisSystem == FbxAxisSystem::OpenGL) + { + FbxGeneralInfo.AxisSystem += TEXT(" (OpenGL)"); + } + else if (FileAxisSystem == FbxAxisSystem::DirectX) + { + FbxGeneralInfo.AxisSystem += TEXT(" (DirectX)"); + } + else if (FileAxisSystem == FbxAxisSystem::Lightwave) + { + FbxGeneralInfo.AxisSystem += TEXT(" (Lightwave)"); + } + + FbxGeneralInfo.UnitSystem = TEXT("Units: "); + if (FileUnitSystem == FbxSystemUnit::mm) + { + FbxGeneralInfo.UnitSystem += TEXT("mm (millimeter)"); + } + else if (FileUnitSystem == FbxSystemUnit::cm) + { + FbxGeneralInfo.UnitSystem += TEXT("cm (centimeter)"); + } + else if (FileUnitSystem == FbxSystemUnit::dm) + { + FbxGeneralInfo.UnitSystem += TEXT("dm (decimeter)"); + } + else if (FileUnitSystem == FbxSystemUnit::m) + { + FbxGeneralInfo.UnitSystem += TEXT("m (meter)"); + } + else if (FileUnitSystem == FbxSystemUnit::km) + { + FbxGeneralInfo.UnitSystem += TEXT("km (kilometer)"); + } + else if (FileUnitSystem == FbxSystemUnit::Inch) + { + FbxGeneralInfo.UnitSystem += TEXT("Inch"); + } + else if (FileUnitSystem == FbxSystemUnit::Foot) + { + FbxGeneralInfo.UnitSystem += TEXT("Foot"); + } + else if (FileUnitSystem == FbxSystemUnit::Yard) + { + FbxGeneralInfo.UnitSystem += TEXT("Yard"); + } + else if (FileUnitSystem == FbxSystemUnit::Mile) + { + FbxGeneralInfo.UnitSystem += TEXT("Mile"); + } +} + +void FFbxImporter::ShowFbxReimportPreview(UObject *ReimportObj, UFbxImportUI* ImportUI, const FString& FullPath) +{ + if (ReimportObj == nullptr || ImportUI == nullptr) + { + return; + } + //Show a dialog + UStaticMesh *StaticMesh = Cast(ReimportObj); + USkeletalMesh *SkeletalMesh = Cast(ReimportObj); + UObject *PreviewObject = nullptr; + FCompMesh CurrentData; + FCompMesh FbxData; + FCreateCompFromFbxArg CreateCompFromFbxArg; + FString Filename; + //Create the current data to compare from + if (StaticMesh) + { + CreateCompFromStaticMesh(StaticMesh, CurrentData); + CreateCompFromFbxArg.MeshName = StaticMesh->GetName(); + CreateCompFromFbxArg.IsStaticMesh = true; + CreateCompFromFbxArg.IsStaticHasLodGroup = StaticMesh->LODGroup != NAME_None; + Filename = ImportUI->StaticMeshImportData->GetFirstFilename(); + } + else if (SkeletalMesh) + { + CreateCompFromSkeletalMesh(SkeletalMesh, CurrentData); + CreateCompFromFbxArg.MeshName = SkeletalMesh->GetName(); + CreateCompFromFbxArg.IsStaticMesh = false; + Filename = ImportUI->SkeletalMeshImportData->GetFirstFilename(); + } + + ////////////////////////////////////////////////////////////////////////// + // Set the import options + ApplyImportUIToImportOptions(ImportUI, *ImportOptions); + + // Set all reimport options + ImportOptions->bAutoComputeLodDistances = true; + ImportOptions->LodNumber = 0; + ImportOptions->MinimumLodNumber = 0; + ImportOptions->bImportRigidMesh = true; + ImportOptions->bImportMaterials = false; + ImportOptions->bImportTextures = false; + ImportOptions->bImportAnimations = false; + + ////////////////////////////////////////////////////////////////////////// + // Open the fbx file + + const FString FileExtension = FPaths::GetExtension(Filename); + const bool bIsValidFile = FileExtension.Equals(TEXT("fbx"), ESearchCase::IgnoreCase) || FileExtension.Equals("obj", ESearchCase::IgnoreCase); + if (!bIsValidFile || !(Filename.Len()) || (IFileManager::Get().FileSize(*Filename) == INDEX_NONE) || + !ImportFromFile(*Filename, FPaths::GetExtension(Filename), true)) + { + return; + } + + //Query general information + FGeneralFbxFileInfo FbxGeneralInfo; + FillGeneralFbxFileInformation(&FbxGeneralInfo); + + //Apply the Transform to the scene + UFbxAssetImportData* ImportAssetData = nullptr; + if (CreateCompFromFbxArg.IsStaticMesh) + { + ImportAssetData = ImportUI->StaticMeshImportData; + } + else + { + ImportAssetData = ImportUI->SkeletalMeshImportData; + } + ApplyTransformSettingsToFbxNode(Scene->GetRootNode(), ImportAssetData); + + UnFbx::FbxSceneInfo SceneInfo; + //Read the scene and found all instance with their scene information. + GetSceneInfo(Filename, SceneInfo, true); + //Convert old structure to the new scene export structure + TSharedPtr SceneInfoPtr = UFbxSceneImportFactory::ConvertSceneInfo(this, &SceneInfo); + //Get import material info + UFbxSceneImportFactory::ExtractMaterialInfo(this, SceneInfoPtr); + + CreateCompFromFbxData(this, ImportUI, FullPath, FbxData, CreateCompFromFbxArg, StaticMesh, SkeletalMesh, &PreviewObject); + TArray> AssetReferencingSkeleton; + if (SkeletalMesh != nullptr && SkeletalMesh->Skeleton != nullptr && !FbxData.CompSkeleton.bSkeletonFitMesh) + { + UObject* SelectedObject = SkeletalMesh->Skeleton; + if (SelectedObject) + { + FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(TEXT("AssetRegistry")); + const FName SelectedPackageName = SelectedObject->GetOutermost()->GetFName(); + //Get the Hard dependencies + TArray HardDependencies; + AssetRegistryModule.Get().GetReferencers(SelectedPackageName, HardDependencies, EAssetRegistryDependencyType::Hard); + //Get the Soft dependencies + TArray SoftDependencies; + AssetRegistryModule.Get().GetReferencers(SelectedPackageName, SoftDependencies, EAssetRegistryDependencyType::Soft); + //Compose the All dependencies array + TArray AllDependencies = HardDependencies; + AllDependencies += SoftDependencies; + if (AllDependencies.Num() > 0) + { + for (const FName AssetDependencyName : AllDependencies) + { + const FString PackageString = AssetDependencyName.ToString(); + const FString FullAssetPathName = FString::Printf(TEXT("%s.%s"), *PackageString, *FPackageName::GetLongPackageAssetName(PackageString)); + + FAssetData AssetData = AssetRegistryModule.Get().GetAssetByObjectPath(FName(*FullAssetPathName)); + if (AssetData.GetClass() != nullptr) + { + TSharedPtr AssetReferencing = MakeShareable(new FString(AssetData.AssetClass.ToString() + TEXT(" ") + FullAssetPathName)); + AssetReferencingSkeleton.Add(AssetReferencing); + } + } + } + } + } + + //Create the modal dialog window to let the user see the result of the compare + TSharedPtr ParentWindow; + + if (FModuleManager::Get().IsModuleLoaded("MainFrame")) + { + IMainFrameModule& MainFrame = FModuleManager::LoadModuleChecked("MainFrame"); + ParentWindow = MainFrame.GetParentWindow(); + } + + TSharedRef Window = SNew(SWindow) + .Title(NSLOCTEXT("UnrealEd", "FbxMaterialConflictOpionsTitle", "FBX Import Conflict")) + .AutoCenter(EAutoCenter::PreferredWorkArea) + .SizingRule(ESizingRule::UserSized) + .ClientSize(FVector2D(700, 650)) + .MinWidth(700) + .MinHeight(650); + + TSharedPtr FbxMaterialConflictWindow; + Window->SetContent + ( + SNew(SFbxCompareWindow) + .WidgetWindow(Window) + .FullFbxPath(FText::FromString(Filename)) + .FbxSceneInfo(SceneInfoPtr) + .FbxGeneralInfo(FbxGeneralInfo) + .AssetReferencingSkeleton(&AssetReferencingSkeleton) + .CurrentMeshData(&CurrentData) + .FbxMeshData(&FbxData) + .PreviewObject(PreviewObject) + ); + + // @todo: we can make this slow as showing progress bar later + FSlateApplication::Get().AddModalWindow(Window, ParentWindow, false); + + if (PreviewObject != nullptr) + { + FAssetEditorManager::Get().CloseAllEditorsForAsset(PreviewObject); + PreviewObject->MarkPendingKill(); + PreviewObject = nullptr; + } +} +#undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxSceneImportData.cpp b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxSceneImportData.cpp index 2469f980be1b..ca9f3beb1560 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxSceneImportData.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxSceneImportData.cpp @@ -28,14 +28,15 @@ UnFbx::FBXImportOptions *JSONToFbxOption(TSharedPtr OptionJsonValue, if (!OptionObj.IsValid()) { return nullptr; - } - UnFbx::FBXImportOptions *Option = new UnFbx::FBXImportOptions(); + } if (!OptionObj->TryGetStringField("OptionName", OptionName)) { return nullptr; } + UnFbx::FBXImportOptions *Option = new UnFbx::FBXImportOptions(); + OptionObj->TryGetBoolField("bImportScene", Option->bImportScene); OptionObj->TryGetBoolField("bImportMaterials", Option->bImportMaterials); OptionObj->TryGetBoolField("bInvertNormalMap", Option->bInvertNormalMap); diff --git a/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxSceneImportFactory.cpp b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxSceneImportFactory.cpp index 45363d782928..a2d195f80272 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxSceneImportFactory.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxSceneImportFactory.cpp @@ -1085,9 +1085,7 @@ FFeedbackContext* Warn AnimSequenceImportData->FbxSceneImportDataReference = ReimportData; //Get the scene root node - FbxNode* RootNodeToImport = nullptr; - RootNodeToImport = FbxImporter->Scene->GetRootNode(); - + FbxNode* RootNodeToImport = FbxImporter->Scene->GetRootNode(); // For animation and static mesh we assume there is at lease one interesting node by default int32 InterestingNodeCount = 1; @@ -2234,17 +2232,18 @@ UObject* UFbxSceneImportFactory::ImportANode(void* VoidFbxImporter, TArrayImportStaticMeshAsSingle(Pkg, Nodes, StaticMeshFName, Flags, StaticMeshImportData, Cast(InMesh), LODIndex); OutNodeInfo->AttributeInfo->SetOriginalImportPath(PackageName); - OutNodeInfo->AttributeInfo->SetOriginalFullImportName(NewObject->GetPathName()); if (NewObject) { + OutNodeInfo->AttributeInfo->SetOriginalFullImportName(NewObject->GetPathName()); + NodeIndex++; FFormatNamedArguments Args; Args.Add(TEXT("NodeIndex"), NodeIndex); Args.Add(TEXT("ArrayLength"), Total); GWarn->StatusUpdate(NodeIndex, Total, FText::Format(NSLOCTEXT("UnrealEd", "Importingf", "Importing ({NodeIndex} of {ArrayLength})"), Args)); } - else if(Pkg != nullptr) + else { Pkg->RemoveFromRoot(); Pkg->ConditionalBeginDestroy(); diff --git a/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxSkeletalMeshImport.cpp b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxSkeletalMeshImport.cpp index b4372abf4cf2..d98efa40b1af 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxSkeletalMeshImport.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxSkeletalMeshImport.cpp @@ -59,7 +59,7 @@ using namespace UnFbx; struct ExistingSkelMeshData; extern ExistingSkelMeshData* SaveExistingSkelMeshData(USkeletalMesh* ExistingSkelMesh, bool bSaveMaterials, int32 ReimportLODIndex); -extern void RestoreExistingSkelMeshData(ExistingSkelMeshData* MeshData, USkeletalMesh* SkeletalMesh, int32 ReimportLODIndex); +extern void RestoreExistingSkelMeshData(ExistingSkelMeshData* MeshData, USkeletalMesh* SkeletalMesh, int32 ReimportLODIndex, bool bResetMaterialSlots, bool bIsReimportPreview); // Get the geometry deformation local to a node. It is never inherited by the // children. @@ -1129,14 +1129,13 @@ bool UnFbx::FFbxImporter::FillSkeletalMeshImportData(TArray& NodeArray FSkeletalMeshImportData* SkelMeshImportDataPtr = OutData; - bool bDiffPose; TArray SortedLinkArray; FbxArray GlobalsPerLink; - bool bUseTime0AsRefPose = ImportOptions->bUseT0AsRefPose; + SkelMeshImportDataPtr->bUseT0AsRefPose = ImportOptions->bUseT0AsRefPose; // Note: importing morph data causes additional passes through this function, so disable the warning dialogs // from popping up again on each additional pass. - if (!ImportBone(NodeArray, *SkelMeshImportDataPtr, TemplateImportData, SortedLinkArray, bDiffPose, (FbxShapeArray != nullptr), bUseTime0AsRefPose, Node)) + if (!ImportBone(NodeArray, *SkelMeshImportDataPtr, TemplateImportData, SortedLinkArray, SkelMeshImportDataPtr->bDiffPose, (FbxShapeArray != nullptr), SkelMeshImportDataPtr->bUseT0AsRefPose, Node)) { AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error, LOCTEXT("FbxSkeletaLMeshimport_MultipleRootFound", "Multiple roots found")), FFbxErrors::SkeletalMesh_MultipleRoots); return false; @@ -1191,7 +1190,7 @@ bool UnFbx::FFbxImporter::FillSkeletalMeshImportData(TArray& NodeArray return false; } - if (bUseTime0AsRefPose && bDiffPose && !ImportOptions->bImportScene) + if (SkelMeshImportDataPtr->bUseT0AsRefPose && SkelMeshImportDataPtr->bDiffPose && !ImportOptions->bImportScene) { // deform skin vertex to the frame 0 from bind pose SkinControlPointsToPose(*SkelMeshImportDataPtr, FbxMesh, FbxShape, true); @@ -1227,6 +1226,101 @@ bool UnFbx::FFbxImporter::FillSkeletalMeshImportData(TArray& NodeArray return true; } +bool UnFbx::FFbxImporter::FillSkeletalMeshImportPoints(FSkeletalMeshImportData* OutData, FbxNode* RootNode, FbxNode* Node, FbxShape* FbxShape) +{ + FbxMesh* FbxMesh = Node->GetMesh(); + + const int32 ControlPointsCount = FbxMesh->GetControlPointsCount(); + const int32 ExistPointNum = OutData->Points.Num(); + OutData->Points.AddUninitialized(ControlPointsCount); + + // Construct the matrices for the conversion from right handed to left handed system + FbxAMatrix TotalMatrix = ComputeSkeletalMeshTotalMatrix(Node, RootNode); + + int32 ControlPointsIndex; + bool bInvalidPositionFound = false; + for( ControlPointsIndex = 0 ; ControlPointsIndex < ControlPointsCount ;ControlPointsIndex++ ) + { + FbxVector4 Position; + if (FbxShape) + { + Position = FbxShape->GetControlPoints()[ControlPointsIndex]; + } + else + { + Position = FbxMesh->GetControlPoints()[ControlPointsIndex]; + } + + FbxVector4 FinalPosition; + FinalPosition = TotalMatrix.MultT(Position); + FVector ConvertedPosition = Converter.ConvertPos(FinalPosition); + + // ensure user when this happens if attached to debugger + if (!ensure(ConvertedPosition.ContainsNaN() == false)) + { + if (!bInvalidPositionFound) + { + bInvalidPositionFound = true; + } + + ConvertedPosition = FVector::ZeroVector; + } + + OutData->Points[ ControlPointsIndex + ExistPointNum ] = ConvertedPosition; + } + + if (bInvalidPositionFound) + { + AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Warning, + FText::Format(LOCTEXT("FbxSkeletaLMeshimport_InvalidPosition", "Invalid position (NaN or Inf) found from source position for mesh '{0}'. Please verify if the source asset contains valid position. "), + FText::FromString(FbxMesh->GetName()))), FFbxErrors::SkeletalMesh_InvalidPosition); + } + + return true; +} + +bool UnFbx::FFbxImporter::GatherPointsForMorphTarget(FSkeletalMeshImportData* OutData, TArray& NodeArray, TArray< FbxShape* >* FbxShapeArray, TSet& ModifiedPoints) +{ + FSkeletalMeshImportData NewImportData = *OutData; + NewImportData.Points.Empty(); + + FbxNode* const RootNode = NodeArray[0]; + + for ( int32 NodeIndex = 0; NodeIndex < NodeArray.Num(); ++NodeIndex ) + { + FbxNode* Node = NodeArray[NodeIndex]; + FbxMesh* FbxMesh = Node->GetMesh(); + + FbxShape* FbxShape = nullptr; + if (FbxShapeArray) + { + FbxShape = (*FbxShapeArray)[NodeIndex]; + } + + FillSkeletalMeshImportPoints( &NewImportData, RootNode, Node, FbxShape ); + + if (OutData->bUseT0AsRefPose && OutData->bDiffPose && !ImportOptions->bImportScene) + { + // deform skin vertex to the frame 0 from bind pose + SkinControlPointsToPose(NewImportData, FbxMesh, FbxShape, true); + } + } + + for ( int32 PointIdx = 0; PointIdx < OutData->Points.Num(); ++PointIdx ) + { + int32 OriginalPointIdx = OutData->PointToRawMap[ PointIdx ]; + + if ( ( NewImportData.Points[ OriginalPointIdx ] - OutData->Points[ PointIdx ] ).SizeSquared() > FMath::Square( THRESH_VECTORS_ARE_NEAR ) ) // THRESH_POINTS_ARE_NEAR is too big, we might not be recomputing some normals that can have changed significantly + { + ModifiedPoints.Add( PointIdx ); + } + + OutData->Points[ PointIdx ] = NewImportData.Points[ OriginalPointIdx ]; + } + + return true; +} + void UnFbx::FFbxImporter::FillLastImportMaterialNames(TArray &LastImportedMaterialNames, USkeletalMesh* BaseSkelMesh, TArray *OrderedMaterialNames) { if (OrderedMaterialNames == nullptr && BaseSkelMesh) @@ -1342,7 +1436,10 @@ USkeletalMesh* UnFbx::FFbxImporter::ImportSkeletalMesh(FImportSkeletalMeshArgs & } TArray LastImportedMaterialNames; - FillLastImportMaterialNames(LastImportedMaterialNames, ExistingSkelMesh, ImportSkeletalMeshArgs.OrderedMaterialNames); + if (!ImportOptions->bResetMaterialSlots) + { + FillLastImportMaterialNames(LastImportedMaterialNames, ExistingSkelMesh, ImportSkeletalMeshArgs.OrderedMaterialNames); + } ////////////////////////////////////////////////////////////////////////// // We must do a maximum of fail test before backing up the data since the backup is destructive on the existing skeletal mesh. @@ -1535,7 +1632,7 @@ USkeletalMesh* UnFbx::FFbxImporter::ImportSkeletalMesh(FImportSkeletalMeshArgs & if (ExistSkelMeshDataPtr) { - RestoreExistingSkelMeshData(ExistSkelMeshDataPtr, SkeletalMesh, ImportSkeletalMeshArgs.LodIndex); + RestoreExistingSkelMeshData(ExistSkelMeshDataPtr, SkeletalMesh, ImportSkeletalMeshArgs.LodIndex, ImportOptions->bResetMaterialSlots, ImportOptions->bIsReimportPreview); } SkeletalMesh->CalculateInvRefMatrices(); @@ -1584,10 +1681,17 @@ USkeletalMesh* UnFbx::FFbxImporter::ImportSkeletalMesh(FImportSkeletalMeshArgs & bool bToastSaveMessage = false; if(bFirstMesh || (LastMergeBonesChoice != EAppReturnType::NoAll && LastMergeBonesChoice != EAppReturnType::YesAll)) { - LastMergeBonesChoice = FMessageDialog::Open(EAppMsgType::YesNoYesAllNoAllCancel, - LOCTEXT("SkeletonFailed_BoneMerge", "FAILED TO MERGE BONES:\n\n This could happen if significant hierarchical changes have been made\n" - "e.g. inserting a bone between nodes.\nWould you like to regenerate the Skeleton from this mesh?\n\n" - "***WARNING: THIS MAY INVALIDATE OR REQUIRE RECOMPRESSION OF ANIMATION DATA.***\n")); + if (!ImportOptions->bIsReimportPreview) + { + LastMergeBonesChoice = FMessageDialog::Open(EAppMsgType::YesNoYesAllNoAllCancel, + LOCTEXT("SkeletonFailed_BoneMerge", "FAILED TO MERGE BONES:\n\n This could happen if significant hierarchical changes have been made\n" + "e.g. inserting a bone between nodes.\nWould you like to regenerate the Skeleton from this mesh?\n\n" + "***WARNING: THIS MAY INVALIDATE OR REQUIRE RECOMPRESSION OF ANIMATION DATA.***\n")); + } + else + { + LastMergeBonesChoice = EAppReturnType::NoAll; + } bToastSaveMessage = true; } @@ -1880,14 +1984,22 @@ void UnFbx::FFbxImporter::SetupAnimationDataFromMesh(USkeletalMesh* SkeletalMesh TArray FBXMeshNodeArray; FbxNode* SkeletonRoot = FindFBXMeshesByBone(SkeletalMesh->Skeleton->GetReferenceSkeleton().GetBoneName(0), true, FBXMeshNodeArray); - TArray SortedLinks; - RecursiveBuildSkeleton(SkeletonRoot, SortedLinks); + if (SkeletonRoot != nullptr) + { + TArray SortedLinks; + RecursiveBuildSkeleton(SkeletonRoot, SortedLinks); - // when importing animation from SkeletalMesh, add new Group Anim, a lot of times they're same name - UPackage * OuterPackage = InParent->GetOutermost(); - FString AnimName = (ImportOptions->AnimationName!="")? ImportOptions->AnimationName : Name+TEXT("_Anim"); - // give animouter as outer - ImportAnimations(Skeleton, OuterPackage, SortedLinks, AnimName, TemplateImportData, NodeArray); + // when importing animation from SkeletalMesh, add new Group Anim, a lot of times they're same name + UPackage * OuterPackage = InParent->GetOutermost(); + FString AnimName = (ImportOptions->AnimationName != "") ? ImportOptions->AnimationName : Name + TEXT("_Anim"); + // give animouter as outer + ImportAnimations(Skeleton, OuterPackage, SortedLinks, AnimName, TemplateImportData, NodeArray); + } + else + { + //Cannot import animations if the skeleton do not match + AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error, FText::Format(LOCTEXT("FbxSkeletaLMeshimport_SkeletonNotMatching_no_anim_import", "Specified Skeleton '{0}' do not match fbx imported skeleton. Cannot import animations with this skeleton."), FText::FromName(Skeleton->GetFName()) )), FFbxErrors::Animation_InvalidData); + } } } } @@ -2799,7 +2911,7 @@ bool UnFbx::FFbxImporter::FillSkelMeshImporterFromFbx( FSkeletalMeshImportData& // int32 ControlPointsCount = Mesh->GetControlPointsCount(); int32 ExistPointNum = ImportData.Points.Num(); - ImportData.Points.AddUninitialized(ControlPointsCount); + FillSkeletalMeshImportPoints( &ImportData, RootNode, Node, FbxShape ); // Construct the matrices for the conversion from right handed to left handed system FbxAMatrix TotalMatrix; @@ -2808,43 +2920,6 @@ bool UnFbx::FFbxImporter::FillSkelMeshImporterFromFbx( FSkeletalMeshImportData& TotalMatrixForNormal = TotalMatrix.Inverse(); TotalMatrixForNormal = TotalMatrixForNormal.Transpose(); - int32 ControlPointsIndex; - bool bInvalidPositionFound = false; - for( ControlPointsIndex = 0 ; ControlPointsIndex < ControlPointsCount ;ControlPointsIndex++ ) - { - FbxVector4 Position; - if (FbxShape) - { - Position = FbxShape->GetControlPoints()[ControlPointsIndex]; - } - else - { - Position = Mesh->GetControlPoints()[ControlPointsIndex]; - } - - FbxVector4 FinalPosition; - FinalPosition = TotalMatrix.MultT(Position); - FVector ConvertedPosition = Converter.ConvertPos(FinalPosition); - - // ensure user when this happens if attached to debugger - if (!ensure(ConvertedPosition.ContainsNaN() == false)) - { - if (!bInvalidPositionFound) - { - bInvalidPositionFound = true; - } - - ConvertedPosition = FVector::ZeroVector; - } - - ImportData.Points[ControlPointsIndex+ExistPointNum] = ConvertedPosition; - } - - if (bInvalidPositionFound) - { - AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Warning, FText::Format(LOCTEXT("FbxSkeletaLMeshimport_InvalidPosition", "Invalid position (NaN or Inf) found from source position for mesh '{0}'. Please verify if the source asset contains valid position. "), FText::FromString(Mesh->GetName()))), FFbxErrors::SkeletalMesh_InvalidPosition); - } - bool OddNegativeScale = IsOddNegativeScale(TotalMatrix); int32 TriangleCount = Mesh->GetPolygonCount(); @@ -3485,7 +3560,7 @@ bool UnFbx::FFbxImporter::ImportSkeletalMeshLOD(USkeletalMesh* InSkeletalMesh, U // Also sort the RequiredBones array to be strictly increasing. NewLODModel.RequiredBones.Sort(); - InSkeletalMesh->RefSkeleton.EnsureParentExists(NewLODModel.ActiveBoneIndices); + BaseSkeletalMesh->RefSkeleton.EnsureParentExists(NewLODModel.ActiveBoneIndices); // To be extra-nice, we apply the difference between the root transform of the meshes to the verts. FMatrix LODToBaseTransform = InSkeletalMesh->GetRefPoseMatrix(0).InverseFast() * BaseSkeletalMesh->GetRefPoseMatrix(0); @@ -3534,38 +3609,222 @@ bool UnFbx::FFbxImporter::ImportSkeletalMeshLOD(USkeletalMesh* InSkeletalMesh, U return true; } +static void ConvertSkeletonImportDataToMeshData( const FSkeletalMeshImportData& ImportData, TArray< FVector >& OutVertices, TArray< uint32 >& OutIndices, TArray< FVector2D >& OutUVs, TArray< uint32 >& OutSmoothingGroups ) +{ + for ( const VTriangle& Face : ImportData.Faces ) + { + for ( int32 i = 0; i < 3; ++i ) + { + const VVertex& Wedge = ImportData.Wedges[ Face.WedgeIndex[i] ]; + + OutIndices.Add( Wedge.VertexIndex ); + OutUVs.Add( Wedge.UVs[0] ); + } + + OutSmoothingGroups.Add( Face.SmoothingGroups ); + } + + OutVertices = ImportData.Points; +} + /** - * A class encapsulating morph target processing that occurs during import on a separate thread - */ +* A class encapsulating morph target processing that occurs during import on a separate thread +*/ class FAsyncImportMorphTargetWork : public FNonAbandonableTask { public: - FAsyncImportMorphTargetWork(FStaticLODModel* InLODModel, const FReferenceSkeleton& InRefSkeleton, FSkeletalMeshImportData& InImportData, bool bInKeepOverlappingVertices) + FAsyncImportMorphTargetWork(FStaticLODModel* InLODModel, const FReferenceSkeleton& InRefSkeleton, FSkeletalMeshImportData& InBaseImportData, TArray&& InMorphLODPoints, + FBXImportOptions* InImportOptions, TArray< FMorphTargetDelta >& InMorphDeltas, FMultiSizeIndexContainerData& InBaseIndexData, TArray< uint32 >& InBaseWedgePointIndices, + TMap& InWedgePointToVertexIndexMap, const TMultiMap& InOverlappingCorners, + const TSet InModifiedPoints, const TMultiMap< int32, int32 >& InWedgeToFaces, const TArray& InTangentX, const TArray& InTangentY, const TArray& InTangentZ) : LODModel(InLODModel) , RefSkeleton(InRefSkeleton) - , ImportData(InImportData) - , bKeepOverlappingVertices(bInKeepOverlappingVertices) + , BaseImportData(InBaseImportData) + , MorphLODPoints(InMorphLODPoints) + , ImportOptions(InImportOptions) + , MorphTargetDeltas(InMorphDeltas) + , BaseIndexData (InBaseIndexData) + , BaseWedgePointIndices(InBaseWedgePointIndices) + , WedgePointToVertexIndexMap(InWedgePointToVertexIndexMap) + , OverlappingCorners(InOverlappingCorners) + , ModifiedPoints(InModifiedPoints) + , WedgeToFaces(InWedgeToFaces) + , BaseTangentZ(InTangentZ) + , TangentX(InTangentX) + , TangentY(InTangentY) + , TangentZ(InTangentZ) { MeshUtilities = &FModuleManager::Get().LoadModuleChecked("MeshUtilities"); } + void PrepareTangents() + { + TArray WasProcessed; + WasProcessed.Empty( BaseImportData.Wedges.Num() ); + WasProcessed.AddZeroed( BaseImportData.Wedges.Num() ); + + TArray< int32 > OverlappingWedges; + TArray< int32 > WedgeFaces; + + // For each ModifiedPoints, reset the tangents for the affected wedges + for ( int32 WedgeIdx = 0; WedgeIdx < BaseImportData.Wedges.Num(); ++WedgeIdx ) + { + int32 PointIdx = BaseImportData.Wedges[ WedgeIdx ].VertexIndex; + + if ( ModifiedPoints.Find( PointIdx ) != nullptr ) + { + TangentX[ WedgeIdx ] = FVector::ZeroVector; + TangentY[ WedgeIdx ] = FVector::ZeroVector; + TangentZ[ WedgeIdx ] = FVector::ZeroVector; + + OverlappingWedges.Reset(); + OverlappingCorners.MultiFind( WedgeIdx, OverlappingWedges ); + OverlappingWedges.Add( WedgeIdx ); + + for ( const int32 OverlappingWedgeIndex : OverlappingWedges ) + { + if ( WasProcessed[ OverlappingWedgeIndex ] ) + { + continue; + } + + WasProcessed[ OverlappingWedgeIndex ] = true; + + WedgeFaces.Reset(); + WedgeToFaces.MultiFind( OverlappingWedgeIndex, WedgeFaces ); + + for ( const int32 FaceIndex : WedgeFaces ) + { + for ( int32 CornerIndex = 0; CornerIndex < 3; ++CornerIndex ) + { + int32 WedgeIndex = BaseImportData.Faces[ FaceIndex ].WedgeIndex[ CornerIndex ]; + + TangentX[ WedgeIndex ] = FVector::ZeroVector; + TangentY[ WedgeIndex ] = FVector::ZeroVector; + TangentZ[ WedgeIndex ] = FVector::ZeroVector; + + TArray< int32 > OtherOverlappingWedges; + OverlappingCorners.MultiFind( WedgeIndex, OtherOverlappingWedges ); + OtherOverlappingWedges.Add( WedgeIndex ); + + for ( const int32 OtherDupVert : OtherOverlappingWedges ) + { + TArray< int32 > OtherWedgeFaces; + WedgeToFaces.MultiFind( OtherDupVert, OtherWedgeFaces ); + + for ( const int32 OtherFaceIndex : OtherWedgeFaces ) + { + for ( int32 OtherCornerIndex = 0; OtherCornerIndex < 3; ++OtherCornerIndex ) + { + int32 OtherWedgeIndex = BaseImportData.Faces[ OtherFaceIndex ].WedgeIndex[ OtherCornerIndex ]; + + TangentX[ OtherWedgeIndex ] = FVector::ZeroVector; + TangentY[ OtherWedgeIndex ] = FVector::ZeroVector; + TangentZ[ OtherWedgeIndex ] = FVector::ZeroVector; + } + } + } + } + } + } + } + } + } + + void ComputeTangents() + { + bool bComputeNormals = !ImportOptions->ShouldImportNormals() || !BaseImportData.bHasNormals; + bool bComputeTangents = !ImportOptions->ShouldImportTangents() || !BaseImportData.bHasTangents; + bool bUseMikkTSpace = (ImportOptions->NormalGenerationMethod == EFBXNormalGenerationMethod::MikkTSpace) && (!ImportOptions->ShouldImportNormals() || !ImportOptions->ShouldImportTangents()); + + TArray DummyPoints; // Use MorphLODPoints instead + TArray Indices; + TArray UVs; + TArray SmoothingGroups; + + ConvertSkeletonImportDataToMeshData( BaseImportData, DummyPoints, Indices, UVs, SmoothingGroups ); + check(MorphLODPoints.Num() == DummyPoints.Num()); + + ETangentOptions::Type TangentOptions = ETangentOptions::BlendOverlappingNormals; + + // MikkTSpace should be use only when the user want to recompute the normals or tangents otherwise should always fallback on builtin + if ( bUseMikkTSpace && ( bComputeNormals || bComputeTangents ) ) + { + TangentOptions = (ETangentOptions::Type)(TangentOptions | ETangentOptions::UseMikkTSpace); + } + + MeshUtilities->CalculateTangents( MorphLODPoints, Indices, UVs, SmoothingGroups, TangentOptions, TangentX, TangentY, TangentZ ); + } + + void ComputeMorphDeltas() + { + TArray WasProcessed; + WasProcessed.Empty(LODModel->NumVertices ); + WasProcessed.AddZeroed(LODModel->NumVertices); + + for ( int32 Idx = 0; Idx < BaseIndexData.Indices.Num(); ++Idx ) + { + uint32 BaseVertIdx = BaseIndexData.Indices[Idx]; + // check for duplicate processing + if( !WasProcessed[BaseVertIdx] ) + { + // mark this base vertex as already processed + WasProcessed[BaseVertIdx] = true; + + // clothing can add extra verts, and we won't have source point, so we ignore those + if ( BaseWedgePointIndices.IsValidIndex(BaseVertIdx) ) + { + // get the base mesh's original wedge point index + uint32 BasePointIdx = BaseWedgePointIndices[ BaseVertIdx ]; + if (BaseImportData.Points.IsValidIndex(BasePointIdx)) + { + FVector BasePosition = BaseImportData.Points[BasePointIdx]; + FVector TargetPosition = MorphLODPoints[BasePointIdx]; + + FVector PositionDelta = TargetPosition - BasePosition; + + uint32* VertexIdx = WedgePointToVertexIndexMap.Find(BasePointIdx); + + FVector NormalDeltaZ = FVector::ZeroVector; + + if (VertexIdx != nullptr) + { + FVector BaseNormal = BaseTangentZ[*VertexIdx]; + FVector TargetNormal = TangentZ[*VertexIdx]; + + NormalDeltaZ = TargetNormal - BaseNormal; + } + + // check if position actually changed much + if (PositionDelta.SizeSquared() > FMath::Square(THRESH_POINTS_ARE_NEAR) || + // since we can't get imported morphtarget normal from FBX + // we can't compare normal unless it's calculated + // this is special flag to ignore normal diff + ((ImportOptions->ShouldImportNormals() == false) && NormalDeltaZ.SizeSquared() > 0.01f)) + { + // create a new entry + FMorphTargetDelta NewVertex; + // position delta + NewVertex.PositionDelta = PositionDelta; + // normal delta + NewVertex.TangentZDelta = NormalDeltaZ; + // index of base mesh vert this entry is to modify + NewVertex.SourceIdx = BaseVertIdx; + + // add it to the list of changed verts + MorphTargetDeltas.Add(NewVertex); + } + } + } + } + } + } + void DoWork() { - TArray LODPoints; - TArray LODWedges; - TArray LODFaces; - TArray LODInfluences; - TArray LODPointToRawMap; - ImportData.CopyLODImportData(LODPoints,LODWedges,LODFaces,LODInfluences,LODPointToRawMap); - - check(LODModel); - - IMeshUtilities::MeshBuildOptions BuildOptions; - BuildOptions.bKeepOverlappingVertices = bKeepOverlappingVertices; - - // @why we have to empty here? @todo: possibly we save this and reuse? - ImportData.Empty(); - MeshUtilities->BuildSkeletalMesh( *LODModel, RefSkeleton, LODInfluences, LODWedges, LODFaces, LODPoints, LODPointToRawMap, BuildOptions); + PrepareTangents(); + ComputeTangents(); + ComputeMorphDeltas(); } FORCEINLINE TStatId GetStatId() const @@ -3577,9 +3836,25 @@ private: FStaticLODModel* LODModel; // @todo not thread safe const FReferenceSkeleton& RefSkeleton; - FSkeletalMeshImportData ImportData; + const FSkeletalMeshImportData& BaseImportData; + const TArray MorphLODPoints; + IMeshUtilities* MeshUtilities; - bool bKeepOverlappingVertices; + FBXImportOptions* ImportOptions; + + TArray< FMorphTargetDelta >& MorphTargetDeltas; + FMultiSizeIndexContainerData& BaseIndexData; + TArray< uint32 >& BaseWedgePointIndices; + TMap& WedgePointToVertexIndexMap; + + const TMultiMap& OverlappingCorners; + const TSet ModifiedPoints; + const TMultiMap< int32, int32 >& WedgeToFaces; + + const TArray& BaseTangentZ; + TArray TangentX; + TArray TangentY; + TArray TangentZ; }; void UnFbx::FFbxImporter::ImportMorphTargetsInternal( TArray& SkelMeshNodeArray, USkeletalMesh* BaseSkelMesh, UObject* InParent, int32 LODIndex ) @@ -3588,7 +3863,7 @@ void UnFbx::FFbxImporter::ImportMorphTargetsInternal( TArray& SkelMesh TMap> ShapeNameToShapeArray; // Temp arrays to keep track of data being used by threads - TArray LODModels; + TArray< TArray< FMorphTargetDelta >* > Results; TArray MorphTargets; // Array of pending tasks that are not complete @@ -3636,7 +3911,7 @@ void UnFbx::FFbxImporter::ImportMorphTargetsInternal( TArray& SkelMesh for(int32 ShapeIndex = 0; ShapeIndexGetTargetShape(ShapeIndex); - + FString ShapeName; if( CurrentChannelShapeCount > 1 ) { @@ -3669,13 +3944,84 @@ void UnFbx::FFbxImporter::ImportMorphTargetsInternal( TArray& SkelMesh } } // for NodeIndex + // Prepare base data + TArray TangentX; + TArray TangentY; + TArray TangentZ; + + TArray LastImportedMaterialNames; + FillLastImportMaterialNames(LastImportedMaterialNames, BaseSkelMesh, nullptr); + + UFbxSkeletalMeshImportData* TmpMeshImportData = Cast(BaseSkelMesh->AssetImportData); + + FSkeletalMeshImportData BaseImportData; + FillSkeletalMeshImportData( SkelMeshNodeArray, TmpMeshImportData, nullptr, &BaseImportData, LastImportedMaterialNames ); + + FStaticLODModel& BaseLODModel = BaseSkelMesh->GetImportedResource()->LODModels[ LODIndex ]; + + // Calculate overlapping corners and tangents + bool bComputeNormals = !ImportOptions->ShouldImportNormals() || !BaseImportData.bHasNormals; + bool bComputeTangents = !ImportOptions->ShouldImportTangents() || !BaseImportData.bHasTangents; + bool bUseMikkTSpace = (ImportOptions->NormalGenerationMethod == EFBXNormalGenerationMethod::MikkTSpace) && (!ImportOptions->ShouldImportNormals() || !ImportOptions->ShouldImportTangents()); + + TArray Points; + TArray Indices; + TArray UVs; + TArray SmoothingGroups; + + ConvertSkeletonImportDataToMeshData( BaseImportData, Points, Indices, UVs, SmoothingGroups ); + + IMeshUtilities& MeshUtilities = FModuleManager::Get().LoadModuleChecked("MeshUtilities"); + + ETangentOptions::Type TangentOptions = ETangentOptions::BlendOverlappingNormals; + + // MikkTSpace should be use only when the user want to recompute the normals or tangents otherwise should always fallback on builtin + if ( bUseMikkTSpace && ( bComputeNormals || bComputeTangents ) ) + { + TangentOptions = (ETangentOptions::Type)(TangentOptions | ETangentOptions::UseMikkTSpace); + } + + TMultiMap OverlappingVertices; + MeshUtilities.CalculateOverlappingCorners( Points, Indices, false, OverlappingVertices ); + MeshUtilities.CalculateTangents( Points, Indices, UVs, SmoothingGroups, TangentOptions, TangentX, TangentY, TangentZ ); + + TArray< uint32 > BaseWedgePointIndices; + if (BaseLODModel.RawPointIndices.GetBulkDataSize()) + { + BaseWedgePointIndices.Empty(BaseLODModel.RawPointIndices.GetElementCount()); + BaseWedgePointIndices.AddUninitialized(BaseLODModel.RawPointIndices.GetElementCount()); + FMemory::Memcpy(BaseWedgePointIndices.GetData(), BaseLODModel.RawPointIndices.Lock(LOCK_READ_ONLY), BaseLODModel.RawPointIndices.GetBulkDataSize()); + BaseLODModel.RawPointIndices.Unlock(); + } + + FMultiSizeIndexContainerData BaseIndexData; + BaseLODModel.MultiSizeIndexContainer.GetIndexBufferData(BaseIndexData); + + TMap WedgePointToVertexIndexMap; + // Build a mapping of wedge point indices to vertex indices for fast lookup later. + for( int32 Idx = 0; Idx < BaseImportData.Wedges.Num(); ++Idx ) + { + WedgePointToVertexIndexMap.Add( BaseImportData.Wedges[Idx].VertexIndex, Idx); + } + + // Create a map from wedge indices to faces + TMultiMap< int32, int32 > WedgeToFaces; + for (int32 FaceIndex = 0; FaceIndex < BaseImportData.Faces.Num(); FaceIndex++) + { + const VTriangle& Face = BaseImportData.Faces[FaceIndex]; + for (int32 CornerIndex = 0; CornerIndex < 3; ++CornerIndex) + { + WedgeToFaces.AddUnique(Face.WedgeIndex[CornerIndex], FaceIndex); + } + } + int32 ShapeIndex = 0; int32 TotalShapeCount = ShapeNameToShapeArray.Num(); // iterate through shapename, and create morphtarget for (auto Iter = ShapeNameToShapeArray.CreateIterator(); Iter; ++Iter) { FString ShapeName = Iter.Key(); - TArray & ShapeArray = Iter.Value(); + TArray< FbxShape* >& ShapeArray = Iter.Value(); FFormatNamedArguments Args; Args.Add(TEXT("ShapeName"), FText::FromString(ShapeName)); @@ -3685,16 +4031,19 @@ void UnFbx::FFbxImporter::ImportMorphTargetsInternal( TArray& SkelMesh GWarn->StatusUpdate(ShapeIndex + 1, TotalShapeCount, StatusUpate); - FSkeletalMeshImportData ImportData; + FSkeletalMeshImportData ShapeImportData = BaseImportData; + + TSet ModifiedPoints; + GatherPointsForMorphTarget( &ShapeImportData, SkelMeshNodeArray, &ShapeArray, ModifiedPoints ); // See if this morph target already exists. - UMorphTarget * Result = FindObject(BaseSkelMesh, *ShapeName); + UMorphTarget * MorphTarget = FindObject(BaseSkelMesh, *ShapeName); // we only create new one for LOD0, otherwise don't create new one - if (!Result) + if (!MorphTarget) { if (LODIndex == 0) { - Result = NewObject(BaseSkelMesh, FName(*ShapeName)); + MorphTarget = NewObject(BaseSkelMesh, FName(*ShapeName)); } else { @@ -3704,49 +4053,40 @@ void UnFbx::FFbxImporter::ImportMorphTargetsInternal( TArray& SkelMesh } } - if (Result) + if (MorphTarget) { - TArray LastImportedMaterialNames; - FillLastImportMaterialNames(LastImportedMaterialNames, BaseSkelMesh, nullptr); - // now we get a shape for whole mesh, import to unreal as a morph target - // @todo AssetImportData do we need import data for this temp mesh? - UFbxSkeletalMeshImportData* TmpMeshImportData = NULL; - FillSkeletalMeshImportData(SkelMeshNodeArray, TmpMeshImportData, &ShapeArray, &ImportData, LastImportedMaterialNames); - FStaticLODModel* NewLODModel = new FStaticLODModel; - LODModels.Add(NewLODModel); - MorphTargets.Add(Result); + MorphTargets.Add( MorphTarget ); + int32 NewMorphDeltasIdx = Results.Add( new TArray< FMorphTargetDelta >() ); + + TArray< FMorphTargetDelta >* Deltas = Results[ NewMorphDeltasIdx ]; + + FAsyncTask* NewWork = new (PendingWork)FAsyncTask( &BaseLODModel, BaseSkelMesh->RefSkeleton, BaseImportData, + MoveTemp( ShapeImportData.Points ), ImportOptions, *Deltas, BaseIndexData, BaseWedgePointIndices, WedgePointToVertexIndexMap, OverlappingVertices, MoveTemp( ModifiedPoints ), WedgeToFaces, + TangentX, TangentY, TangentZ); - // Process the skeletal mesh on a separate thread - FAsyncTask* NewWork = new (PendingWork)FAsyncTask(NewLODModel, BaseSkelMesh->RefSkeleton, ImportData, ImportOptions->bKeepOverlappingVertices); NewWork->StartBackgroundTask(); - ++ShapeIndex; } + + ++ShapeIndex;; } // Wait for all importing tasks to complete int32 NumCompleted = 0; int32 NumTasks = PendingWork.Num(); - do + + for ( int32 TaskIndex = 0; TaskIndex < PendingWork.Num(); ++TaskIndex ) { - // Check for completed async compression tasks. - int32 NumNowCompleted = 0; - for ( int32 TaskIndex=0; TaskIndex < PendingWork.Num(); ++TaskIndex ) - { - if ( PendingWork[TaskIndex].IsDone() ) - { - NumNowCompleted++; - } - } - if (NumNowCompleted > NumCompleted) - { - NumCompleted = NumNowCompleted; - FFormatNamedArguments Args; - Args.Add( TEXT("NumCompleted"), NumCompleted ); - Args.Add( TEXT("NumTasks"), NumTasks ); - GWarn->StatusUpdate( NumCompleted, NumTasks, FText::Format( LOCTEXT("ImportingMorphTargetStatus", "Importing Morph Target: {NumCompleted} of {NumTasks}"), Args ) ); - } - FPlatformProcess::Sleep(0.1f); - } while ( NumCompleted < NumTasks ); + PendingWork[TaskIndex].EnsureCompletion(); + + ++NumCompleted; + + FFormatNamedArguments Args; + Args.Add( TEXT("NumCompleted"), NumCompleted ); + Args.Add( TEXT("NumTasks"), NumTasks ); + GWarn->StatusUpdate( NumCompleted, NumTasks, FText::Format( LOCTEXT("ImportingMorphTargetStatus", "Importing Morph Target: {NumCompleted} of {NumTasks}"), Args ) ); + } + + const FMorphMeshRawSource BaseMeshRawData( BaseSkelMesh, LODIndex ); // Create morph streams for each morph target we are importing. // This has to happen on a single thread since the skeletal meshes' bulk data is locked and cant be accessed by multiple threads simultaneously @@ -3759,17 +4099,17 @@ void UnFbx::FFbxImporter::ImportMorphTargetsInternal( TArray& SkelMesh UMorphTarget* MorphTarget = MorphTargets[Index]; - FMorphMeshRawSource TargetMeshRawData(*LODModels[Index]); - FMorphMeshRawSource BaseMeshRawData( BaseSkelMesh, LODIndex ); + MorphTarget->PopulateDeltas(*Results[Index], LODIndex, ImportOptions->ShouldImportNormals() == false); - MorphTarget->PostProcess( BaseSkelMesh, BaseMeshRawData, TargetMeshRawData, LODIndex, ImportOptions->ShouldImportNormals() == false ); + BaseSkelMesh->RegisterMorphTarget( MorphTarget ); + MorphTarget->MarkPackageDirty(); - delete LODModels[Index]; - LODModels[Index] = nullptr; + delete Results[Index]; + Results[Index] = nullptr; } GWarn->EndSlowTask(); -} +} // Import Morph target void UnFbx::FFbxImporter::ImportFbxMorphTarget(TArray &SkelMeshNodeArray, USkeletalMesh* BaseSkelMesh, UObject* InParent, int32 LODIndex) diff --git a/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxStaticMeshImport.cpp b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxStaticMeshImport.cpp index 707e91f6fe14..65f95e5784c8 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxStaticMeshImport.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxStaticMeshImport.cpp @@ -42,7 +42,7 @@ using namespace UnFbx; struct ExistingStaticMeshData; extern ExistingStaticMeshData* SaveExistingStaticMeshData(UStaticMesh* ExistingMesh, FBXImportOptions* ImportOptions, int32 LodIndex); extern void RestoreExistingMeshSettings(struct ExistingStaticMeshData* ExistingMesh, UStaticMesh* NewMesh, int32 LODIndex); -extern void RestoreExistingMeshData(struct ExistingStaticMeshData* ExistingMeshDataPtr, UStaticMesh* NewMesh, int32 LodLevel); +extern void RestoreExistingMeshData(struct ExistingStaticMeshData* ExistingMeshDataPtr, UStaticMesh* NewMesh, int32 LodLevel, bool bResetMaterialSlots); extern void UpdateSomeLodsImportMeshData(UStaticMesh* NewMesh, TArray *ReimportLodList); static FbxString GetNodeNameWithoutNamespace( FbxNode* Node ) @@ -886,7 +886,7 @@ UStaticMesh* UnFbx::FFbxImporter::ReimportSceneStaticMesh(uint64 FbxNodeUniqueId } } //Don't restore materials when reimporting scene - RestoreExistingMeshData(ExistMeshDataPtr, FirstBaseMesh, INDEX_NONE); + RestoreExistingMeshData(ExistMeshDataPtr, FirstBaseMesh, INDEX_NONE, false); return FirstBaseMesh; } @@ -1036,7 +1036,7 @@ UStaticMesh* UnFbx::FFbxImporter::ReimportStaticMesh(UStaticMesh* Mesh, UFbxStat } UpdateSomeLodsImportMeshData(NewMesh, &ReimportLodList); - RestoreExistingMeshData(ExistMeshDataPtr, NewMesh, INDEX_NONE); + RestoreExistingMeshData(ExistMeshDataPtr, NewMesh, INDEX_NONE, ImportOptions->bResetMaterialSlots); return NewMesh; } diff --git a/Engine/Source/Editor/UnrealEd/Private/Fbx/ReimportFbxSceneFactory.cpp b/Engine/Source/Editor/UnrealEd/Private/Fbx/ReimportFbxSceneFactory.cpp index 0fed2ec35d22..33c18cd8ef64 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Fbx/ReimportFbxSceneFactory.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Fbx/ReimportFbxSceneFactory.cpp @@ -532,8 +532,7 @@ EReimportResult::Type UReimportFbxSceneFactory::Reimport(UObject* Obj) AssetDataToDelete.Add(AssetRegistryModule.Get().GetAssetByObjectPath(FName(*(MeshInfo->GetFullImportName())))); } - FbxNode* RootNodeToImport = nullptr; - RootNodeToImport = FbxImporter->Scene->GetRootNode(); + FbxNode* RootNodeToImport = FbxImporter->Scene->GetRootNode(); AllNewAssets.Empty(); AssetToSyncContentBrowser.Empty(); diff --git a/Engine/Source/Editor/UnrealEd/Private/FbxCompareWindow.h b/Engine/Source/Editor/UnrealEd/Private/FbxCompareWindow.h new file mode 100644 index 000000000000..7c57be97c3f2 --- /dev/null +++ b/Engine/Source/Editor/UnrealEd/Private/FbxCompareWindow.h @@ -0,0 +1,390 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "InputCoreTypes.h" +#include "Widgets/DeclarativeSyntaxSupport.h" +#include "Input/Reply.h" +#include "Widgets/SCompoundWidget.h" +#include "Widgets/SWindow.h" +#include "Widgets/Views/STableViewBase.h" +#include "Widgets/Views/STableRow.h" +#include "Widgets/Views/STreeView.h" +#include "Widgets/SNullWidget.h" +#include "EditorStyleSet.h" + +class FFbxSceneInfo; + +enum EFBXCompareSection +{ + EFBXCompareSection_General = 0, + EFBXCompareSection_Materials, + EFBXCompareSection_Skeleton, + EFBXCompareSection_Count +}; + +class FCompMaterial +{ +public: + FCompMaterial(FName InMaterialSlotName, FName InImportedMaterialSlotName) + : MaterialSlotName(InMaterialSlotName) + , ImportedMaterialSlotName(InImportedMaterialSlotName) + {} + FName MaterialSlotName; + FName ImportedMaterialSlotName; +}; + +class FCompSection +{ +public: + FCompSection() + : MaterialIndex(INDEX_NONE) + {} + + int32 MaterialIndex; +}; + +class FCompLOD +{ +public: + ~FCompLOD() + { + Sections.Empty(); + } + + TArray Sections; +}; + +class FCompJoint +{ +public: + FCompJoint() + : Name(NAME_None) + , ParentIndex(INDEX_NONE) + { } + + ~FCompJoint() + { + ChildIndexes.Empty(); + } + + FName Name; + int32 ParentIndex; + TArray ChildIndexes; +}; + +class FCompSkeleton +{ +public: + FCompSkeleton() + : bSkeletonFitMesh(true) + {} + + ~FCompSkeleton() + { + Joints.Empty(); + } + + TArray Joints; + bool bSkeletonFitMesh; +}; + +class FCompMesh +{ +public: + ~FCompMesh() + { + CompMaterials.Empty(); + CompLods.Empty(); + } + + TArray CompMaterials; + TArray CompLods; + FCompSkeleton CompSkeleton; + TArray UVSetsName; + int32 LightMapUvIndex; + + TArray ErrorMessages; + TArray WarningMessages; +}; + +class FGeneralFbxFileInfo +{ +public: + FString ApplicationCreator; + FString UE4SdkVersion; + FString FileVersion; + FString AxisSystem; + FString UnitSystem; + FString CreationDate; +}; + +class FSkeletonCompareData : public TSharedFromThis +{ +public: + FSkeletonCompareData() + : CurrentJointIndex(INDEX_NONE) + , FbxJointIndex(INDEX_NONE) + , JointName(NAME_None) + , ParentJoint(nullptr) + , bMatchJoint(false) + , bChildConflict(false) + {} + int32 CurrentJointIndex; + int32 FbxJointIndex; + FName JointName; + TSharedPtr ParentJoint; + bool bMatchJoint; + bool bChildConflict; + TArray ChildJointIndexes; + TArray> ChildJoints; +}; + +class FCompareRowData : public TSharedFromThis +{ +public: + FCompareRowData() + : RowIndex(INDEX_NONE) + , CurrentData(nullptr) + , FbxData(nullptr) + {} + virtual ~FCompareRowData() {} + + int32 RowIndex; + FCompMesh *CurrentData; + FCompMesh *FbxData; + + virtual TSharedRef ConstructCellCurrent() + { + return SNullWidget::NullWidget; + }; + virtual TSharedRef ConstructCellFbx() + { + return SNullWidget::NullWidget; + }; +}; + +class FMaterialCompareData : public FCompareRowData +{ +public: + enum EMaterialCompareDisplayOption + { + NoMatch = 0, + IndexChanged, + SkinxxError, + All, + MaxOptionEnum + }; + + FMaterialCompareData() + : CurrentMaterialIndex(INDEX_NONE) + , FbxMaterialIndex(INDEX_NONE) + , CurrentMaterialMatch(INDEX_NONE) + , FbxMaterialMatch(INDEX_NONE) + , bCurrentSkinxxDuplicate(false) + , bCurrentSkinxxMissing(false) + , bFbxSkinxxDuplicate(false) + , bFbxSkinxxMissing(false) + , CompareDisplayOption(EMaterialCompareDisplayOption::All) + {} + + virtual ~FMaterialCompareData() {} + + int32 CurrentMaterialIndex; + int32 FbxMaterialIndex; + int32 CurrentMaterialMatch; + int32 FbxMaterialMatch; + bool bCurrentSkinxxDuplicate; + bool bCurrentSkinxxMissing; + bool bFbxSkinxxDuplicate; + bool bFbxSkinxxMissing; + EMaterialCompareDisplayOption CompareDisplayOption; + + FSlateColor GetCellColor(FCompMesh *DataA, int32 MaterialIndexA, int32 MaterialMatchA, FCompMesh *DataB, int32 MaterialIndexB, bool bSkinxxError) const; + FSlateColor GetCurrentCellColor() const; + FSlateColor GetFbxCellColor() const; + + TSharedRef ConstructCell(FCompMesh *MeshData, int32 MeshMaterialIndex, bool bSkinxxDuplicate, bool bSkinxxMissing); + virtual TSharedRef ConstructCellCurrent() override; + virtual TSharedRef ConstructCellFbx() override; +}; + +class SCompareRowDataTableListViewRow : public SMultiColumnTableRow> +{ +public: + + SLATE_BEGIN_ARGS(SCompareRowDataTableListViewRow) + : _CompareRowData(nullptr) + {} + + /** The item content. */ + SLATE_ARGUMENT(TSharedPtr, CompareRowData) + SLATE_END_ARGS() + + void Construct(const FArguments& InArgs, const TSharedRef& InOwnerTableView) + { + CompareRowData = InArgs._CompareRowData; + + //This is suppose to always be valid + check(CompareRowData.IsValid()); + + SMultiColumnTableRow>::Construct( + FSuperRowType::FArguments() + .Style(FEditorStyle::Get(), "DataTableEditor.CellListViewRow"), + InOwnerTableView + ); + } + + /** Overridden from SMultiColumnTableRow. Generates a widget for this column of the list view. */ + virtual TSharedRef GenerateWidgetForColumn(const FName& ColumnName) override + { + if (ColumnName == FName(TEXT("RowIndex"))) + { + return SNew(SBox) + .Padding(FMargin(5.0f, 0.0f, 0.0f, 0.0f)) + [ + SNew(STextBlock) + .Text(FText::FromString(FString::FromInt(CompareRowData->RowIndex))) + ]; + } + else if (ColumnName == FName(TEXT("Current"))) + { + return CompareRowData->ConstructCellCurrent(); + } + else if (ColumnName == FName(TEXT("Fbx"))) + { + return CompareRowData->ConstructCellFbx(); + } + return SNullWidget::NullWidget; + } +private: + + /** The node info to build the tree view row from. */ + TSharedPtr CompareRowData; +}; + +class SFbxCompareWindow : public SCompoundWidget +{ +public: + SLATE_BEGIN_ARGS(SFbxCompareWindow) + : _WidgetWindow() + , _FullFbxPath() + , _FbxSceneInfo() + , _FbxGeneralInfo() + , _AssetReferencingSkeleton(nullptr) + , _CurrentMeshData(nullptr) + , _FbxMeshData(nullptr) + , _PreviewObject(nullptr) + {} + + SLATE_ARGUMENT( TSharedPtr, WidgetWindow ) + SLATE_ARGUMENT( FText, FullFbxPath ) + SLATE_ARGUMENT( TSharedPtr, FbxSceneInfo ) + SLATE_ARGUMENT( FGeneralFbxFileInfo, FbxGeneralInfo ) + SLATE_ARGUMENT( TArray>*, AssetReferencingSkeleton) + SLATE_ARGUMENT( FCompMesh*, CurrentMeshData ) + SLATE_ARGUMENT( FCompMesh*, FbxMeshData ) + SLATE_ARGUMENT( UObject*, PreviewObject ) + + SLATE_END_ARGS() + +public: + void Construct(const FArguments& InArgs); + virtual bool SupportsKeyboardFocus() const override { return true; } + + FReply OnDone() + { + if ( WidgetWindow.IsValid() ) + { + WidgetWindow.Pin()->RequestDestroyWindow(); + } + return FReply::Handled(); + } + + virtual FReply OnKeyDown( const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent ) override + { + if( InKeyEvent.GetKey() == EKeys::Escape ) + { + return OnDone(); + } + + return FReply::Unhandled(); + } + + SFbxCompareWindow() + : FullFbxPath(TEXT("")) + , FbxSceneInfo() + + {} + +private: + TWeakPtr< SWindow > WidgetWindow; + FString FullFbxPath; + + //Preview Mesh + UObject *PreviewObject; + + ////////////////////////////////////////////////////////////////////////// + //Collapse generic + bool bShowSectionFlag[EFBXCompareSection_Count]; + FReply SetSectionVisible(EFBXCompareSection SectionIndex); + EVisibility IsSectionVisible(EFBXCompareSection SectionIndex); + const FSlateBrush* GetCollapsableArrow(EFBXCompareSection SectionIndex) const; + ////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////// + // General fbx data + FGeneralFbxFileInfo FbxGeneralInfo; + TSharedPtr FbxSceneInfo; + TArray> GeneralListItem; + + void FillGeneralListItem(); + //Construct slate + TSharedPtr ConstructGeneralInfo(); + //Slate events + TSharedRef OnGenerateRowGeneralFbxInfo(TSharedPtr InItem, const TSharedRef& OwnerTable); + ////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////// + // Compare data + FCompMesh *CurrentMeshData; + FCompMesh *FbxMeshData; + ////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////// + // Material Data + TArray> CompareMaterialListItem; + FMaterialCompareData::EMaterialCompareDisplayOption CurrentDisplayOption; + + void FillMaterialListItem(); + bool FindSkinxxErrors(FCompMesh *MeshData, TArray &DuplicateSkinxxMaterialNames, TArray &MissingSkinxxSuffixeMaterialNames); + //Construct slate + TSharedPtr ConstructMaterialComparison(); + //Slate events + TSharedRef OnGenerateRowForCompareMaterialList(TSharedPtr RowData, const TSharedRef& Table); + void ToggleMaterialDisplay(ECheckBoxState InNewValue, FMaterialCompareData::EMaterialCompareDisplayOption InDisplayOption); + ECheckBoxState IsToggleMaterialDisplayChecked(FMaterialCompareData::EMaterialCompareDisplayOption InDisplayOption) const; + ////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////// + // Skeleton Data + TSharedPtr>> CompareTree; + TArray> DisplaySkeletonTreeItem; + + TArray> CurrentSkeletonTreeItem; + TArray> FbxSkeletonTreeItem; + + TArray> AssetReferencingSkeleton; + + void FilSkeletonTreeItem(); + void RecursiveMatchJointInfo(TSharedPtr CurrentItem); + void SetMatchJointInfo(); + //Construct slate + TSharedPtr ConstructSkeletonComparison(); + //Slate events + TSharedRef OnGenerateRowCompareTreeView(TSharedPtr RowData, const TSharedRef& Table); + void OnGetChildrenRowCompareTreeView(TSharedPtr InParent, TArray< TSharedPtr >& OutChildren); + TSharedRef OnGenerateRowAssetReferencingSkeleton(TSharedPtr InItem, const TSharedRef& OwnerTable); + ////////////////////////////////////////////////////////////////////////// +}; diff --git a/Engine/Source/Editor/UnrealEd/Private/FbxImporter.h b/Engine/Source/Editor/UnrealEd/Private/FbxImporter.h index 25571140496c..54de3754ec6d 100644 --- a/Engine/Source/Editor/UnrealEd/Private/FbxImporter.h +++ b/Engine/Source/Editor/UnrealEd/Private/FbxImporter.h @@ -109,6 +109,7 @@ struct FBXImportOptions // General options bool bImportScene; bool bImportMaterials; + bool bResetMaterialSlots; bool bInvertNormalMap; bool bImportTextures; bool bImportLOD; @@ -186,6 +187,9 @@ struct FBXImportOptions //This data allow to override some fbx Material(point by the uint64 id) with existing unreal material asset TMap OverrideMaterials; + //The importer is importing a preview + bool bIsReimportPreview; + bool ShouldImportNormals() { return NormalImportMethod == FBXNIM_ImportNormals || NormalImportMethod == FBXNIM_ImportNormalsAndTangents; @@ -205,7 +209,7 @@ struct FBXImportOptions static void ResetOptions(FBXImportOptions *OptionsToReset) { check(OptionsToReset != nullptr); - FMemory::Memzero(OptionsToReset, sizeof(OptionsToReset)); + FMemory::Memzero(OptionsToReset, sizeof(*OptionsToReset)); } }; @@ -467,7 +471,7 @@ private: static FbxAMatrix JointPostConversionMatrix; }; -FBXImportOptions* GetImportOptions( class FFbxImporter* FbxImporter, UFbxImportUI* ImportUI, bool bShowOptionDialog, bool bIsAutomated, const FString& FullPath, bool& OutOperationCanceled, bool& OutImportAll, bool bIsObjFormat, bool bForceImportType = false, EFBXImportType ImportType = FBXIT_StaticMesh ); +FBXImportOptions* GetImportOptions( class FFbxImporter* FbxImporter, UFbxImportUI* ImportUI, bool bShowOptionDialog, bool bIsAutomated, const FString& FullPath, bool& OutOperationCanceled, bool& OutImportAll, bool bIsObjFormat, bool bForceImportType = false, EFBXImportType ImportType = FBXIT_StaticMesh, UObject* ReimportObject = nullptr); void ApplyImportUIToImportOptions(UFbxImportUI* ImportUI, FBXImportOptions& InOutImportOptions); struct FImportedMaterialData @@ -502,6 +506,9 @@ public: UNREALED_API static FFbxImporter* GetInstance(); static void DeleteInstance(); + static FFbxImporter* GetPreviewInstance(); + static void DeletePreviewInstance(); + /** * Detect if the FBX file has skeletal mesh model. If there is deformer definition, then there is skeletal mesh. * In this function, we don't need to import the scene. But the open process is time-consume if the file is large. @@ -899,6 +906,16 @@ public: */ UNREALED_API FBXImportOptions* GetImportOptions() const; + /* + * This function show a dialog to let the user know what will be change if the fbx is imported + */ + void ShowFbxReimportPreview(UObject *ReimportObj, UFbxImportUI* ImportUI, const FString& FullPath); + + /* + * Function use to retrieve general fbx information for the preview + */ + void FillGeneralFbxFileInformation(void *GeneralInfoPtr); + /** helper function **/ UNREALED_API static void DumpFBXNode(FbxNode* Node); @@ -1040,6 +1057,24 @@ public: //We cache the hash of the file when we open the file. This is to avoid calculating the hash many time when importing many asset in one fbx file. FMD5Hash Md5Hash; + struct FFbxMaterial + { + FbxSurfaceMaterial* FbxMaterial; + UMaterialInterface* Material; + + FString GetName() const { return FbxMaterial ? ANSI_TO_TCHAR(FbxMaterial->GetName()) : TEXT("None"); } + }; + + /** + * Make material Unreal asset name from the Fbx material + * + * @param FbxMaterial Material from the Fbx node + * @return Sanitized asset name + */ + FString GetMaterialFullName(FbxSurfaceMaterial& FbxMaterial); + + FbxGeometryConverter* GetGeometryConverter() { return GeometryConverter; } + protected: enum IMPORTPHASE { @@ -1049,14 +1084,7 @@ protected: }; static TSharedPtr StaticInstance; - - struct FFbxMaterial - { - FbxSurfaceMaterial* FbxMaterial; - UMaterialInterface* Material; - - FString GetName() const { return FbxMaterial ? ANSI_TO_TCHAR( FbxMaterial->GetName() ) : TEXT("None"); } - }; + static TSharedPtr StaticPreviewInstance; //make sure we are not applying two time the option transform to the same node TArray TransformSettingsToFbxApply; @@ -1073,6 +1101,10 @@ protected: TWeakObjectPtr Parent; FString FbxFileVersion; + //Original File Info + FbxAxisSystem FileAxisSystem; + FbxSystemUnit FileUnitSystem; + // Flag that the mesh is the first mesh to import in current FBX scene // FBX scene may contain multiple meshes, importer can import them at one time. // Initialized as true when start to import a FBX scene @@ -1177,6 +1209,8 @@ protected: */ bool FillSkelMeshImporterFromFbx(FSkeletalMeshImportData& ImportData, FbxMesh*& Mesh, FbxSkin* Skin, FbxShape* Shape, TArray &SortedLinks, const TArray& FbxMaterials, FbxNode *RootNode); +public: + /** * Fill FSkeletalMeshIMportData from Fbx Nodes and FbxShape Array if exists. * @@ -1188,7 +1222,32 @@ protected: * @returns bool* true if import successfully. */ bool FillSkeletalMeshImportData(TArray& NodeArray, UFbxSkeletalMeshImportData* TemplateImportData, TArray *FbxShapeArray, FSkeletalMeshImportData* OutData, TArray &LastImportedMaterialNames); - + +protected: + /** + * Fill the Points in FSkeletalMeshIMportData from a Fbx Node and a FbxShape if it exists. + * + * @param OutData FSkeletalMeshImportData output data + * @param RootNode The root node of the Fbx + * @param Node The node to get the points from + * @param FbxShape Fbx Morph object, if not NULL, we are importing a morph object. + * + * @returns bool true if import successfully. + */ + bool FillSkeletalMeshImportPoints(FSkeletalMeshImportData* OutData, FbxNode* RootNode, FbxNode* Node, FbxShape* FbxShape); + + /** + * Fill the Points in FSkeletalMeshIMportData from Fbx Nodes and FbxShape Array if it exists. + * + * @param OutData FSkeletalMeshImportData output data + * @param NodeArray Fbx node array to look at + * @param FbxShapeArray Fbx Morph object, if not NULL, we are importing a morph object. + * @param ModifiedPoints Set of points indices for which we've modified the value in OutData + * + * @returns bool true if import successfully. + */ + bool GatherPointsForMorphTarget(FSkeletalMeshImportData* OutData, TArray& NodeArray, TArray< FbxShape* >* FbxShapeArray, TSet& ModifiedPoints); + /** * Import bones from skeletons that NodeArray bind to. * @@ -1304,14 +1363,6 @@ protected: */ int32 CreateNodeMaterials(FbxNode* FbxNode, TArray& outMaterials, TArray& UVSets, bool bForSkeletalMesh); - /** - * Make material Unreal asset name from the Fbx material - * - * @param FbxMaterial Material from the Fbx node - * @return Sanitized asset name - */ - FString GetMaterialFullName(FbxSurfaceMaterial& FbxMaterial); - /** * Create Unreal material from Fbx material. * Only setup channels that connect to texture, and setup the UV coordinate of texture. diff --git a/Engine/Source/Editor/UnrealEd/Private/FbxMeshUtils.cpp b/Engine/Source/Editor/UnrealEd/Private/FbxMeshUtils.cpp index 83b1523b5ff8..ca08b5911a7b 100644 --- a/Engine/Source/Editor/UnrealEd/Private/FbxMeshUtils.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/FbxMeshUtils.cpp @@ -39,12 +39,12 @@ DEFINE_LOG_CATEGORY_STATIC(LogExportMeshUtils, Log, All); struct ExistingStaticMeshData; extern ExistingStaticMeshData* SaveExistingStaticMeshData(UStaticMesh* ExistingMesh, UnFbx::FBXImportOptions* ImportOptions, int32 LodIndex); extern void RestoreExistingMeshSettings(struct ExistingStaticMeshData* ExistingMesh, UStaticMesh* NewMesh, int32 LODIndex); -extern void RestoreExistingMeshData(struct ExistingStaticMeshData* ExistingMeshDataPtr, UStaticMesh* NewMesh, int32 LodLevel); +extern void RestoreExistingMeshData(struct ExistingStaticMeshData* ExistingMeshDataPtr, UStaticMesh* NewMesh, int32 LodLevel, bool bResetMaterialSlots); extern void UpdateSomeLodsImportMeshData(UStaticMesh* NewMesh, TArray *ReimportLodList); struct ExistingSkelMeshData; extern ExistingSkelMeshData* SaveExistingSkelMeshData(USkeletalMesh* ExistingSkelMesh, bool bSaveMaterials, int32 ReimportLODIndex); -extern void RestoreExistingSkelMeshData(ExistingSkelMeshData* MeshData, USkeletalMesh* SkeletalMesh, int32 ReimportLODIndex); +extern void RestoreExistingSkelMeshData(ExistingSkelMeshData* MeshData, USkeletalMesh* SkeletalMesh, int32 ReimportLODIndex, bool bResetMaterialSlots, bool bIsReimportPreview); namespace FbxMeshUtils { @@ -196,7 +196,7 @@ namespace FbxMeshUtils UpdateSomeLodsImportMeshData(BaseStaticMesh, &ReimportLodList); if(IsReimport) { - RestoreExistingMeshData(ExistMeshDataPtr, BaseStaticMesh, LODLevel); + RestoreExistingMeshData(ExistMeshDataPtr, BaseStaticMesh, LODLevel, false); } // Update mesh component @@ -460,7 +460,7 @@ namespace FbxMeshUtils if (SkelMeshDataPtr != nullptr) { - RestoreExistingSkelMeshData(SkelMeshDataPtr, SelectedSkelMesh, SelectedLOD); + RestoreExistingSkelMeshData(SkelMeshDataPtr, SelectedSkelMesh, SelectedLOD, false, ImportOptions->bIsReimportPreview); } SelectedSkelMesh->PostEditChange(); // Mark package containing skeletal mesh as dirty. diff --git a/Engine/Source/Editor/UnrealEd/Private/FbxOptionWindow.h b/Engine/Source/Editor/UnrealEd/Private/FbxOptionWindow.h index d62548fd82ea..01f051de6ef6 100644 --- a/Engine/Source/Editor/UnrealEd/Private/FbxOptionWindow.h +++ b/Engine/Source/Editor/UnrealEd/Private/FbxOptionWindow.h @@ -32,6 +32,7 @@ public: SLATE_ARGUMENT( bool, IsObjFormat ) SLATE_ARGUMENT( float, MaxWindowHeight) SLATE_ARGUMENT(float, MaxWindowWidth) + SLATE_EVENT(FOnPreviewFbxImport, OnPreviewFbxImport) SLATE_END_ARGS() public: @@ -94,12 +95,18 @@ public: private: bool CanImport() const; + FReply OnPreviewClick() const; + FReply OnResetToDefaultClick() const; + FText GetImportTypeDisplayText() const; private: UFbxImportUI* ImportUI; + TSharedPtr DetailsView; TWeakPtr< SWindow > WidgetWindow; TSharedPtr< SButton > ImportButton; bool bShouldImport; bool bShouldImportAll; bool bIsObjFormat; + + FOnPreviewFbxImport OnPreviewFbxImport; }; diff --git a/Engine/Source/Editor/UnrealEd/Private/FileHelpers.cpp b/Engine/Source/Editor/UnrealEd/Private/FileHelpers.cpp index c4c2e9c05c01..5b01b200285b 100644 --- a/Engine/Source/Editor/UnrealEd/Private/FileHelpers.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/FileHelpers.cpp @@ -392,7 +392,11 @@ static bool SaveWorld(UWorld* World, { // SaveWorld not reentrant - check that we are not already in the process of saving here (for example, via autosave) static bool bIsReentrant = false; - check(!bIsReentrant); + if (bIsReentrant) + { + return false; + } + TGuardValue ReentrantGuard(bIsReentrant, true); if ( !World ) @@ -1103,7 +1107,7 @@ void FEditorFileUtils::Import(const FString& InFilename) if (SceneFactory) { - FString Path = ""; + FString Path = "/Game"; //Ask the user for the root path where they want to any content to be placed if(SceneFactory->ImportsAssets()) @@ -2003,20 +2007,21 @@ bool FEditorFileUtils::AttemptUnloadInactiveWorldPackage(UPackage* PackageToUnlo * Prompts the user to save the current map if necessary, the presents a load dialog and * loads a new map if selected by the user. */ -void FEditorFileUtils::LoadMap() +bool FEditorFileUtils::LoadMap() { if (GUnrealEd->WarnIfLightingBuildIsCurrentlyRunning()) { - return; + return false; } + bool bResult = false; if (UEditorEngine::IsUsingWorldAssets()) { static bool bIsDialogOpen = false; struct FLocal { - static void HandleLevelsChosen(const TArray& SelectedAssets) + static void HandleLevelsChosen(const TArray& SelectedAssets, bool* OutResult) { bIsDialogOpen = false; @@ -2032,6 +2037,7 @@ void FEditorFileUtils::LoadMap() bool bSaveContentPackages = true; if (FEditorFileUtils::SaveDirtyPackages(bPromptUserToSave, bSaveMapPackages, bSaveContentPackages) == false) { + *OutResult = false; return; } } @@ -2039,7 +2045,7 @@ void FEditorFileUtils::LoadMap() const FString FileToOpen = FPackageName::LongPackageNameToFilename(AssetData.PackageName.ToString(), FPackageName::GetMapPackageExtension()); const bool bLoadAsTemplate = false; const bool bShowProgress = true; - FEditorFileUtils::LoadMap(FileToOpen, bLoadAsTemplate, bShowProgress); + *OutResult = FEditorFileUtils::LoadMap(FileToOpen, bLoadAsTemplate, bShowProgress); } } @@ -2053,7 +2059,7 @@ void FEditorFileUtils::LoadMap() { bIsDialogOpen = true; const bool bAllowMultipleSelection = false; - OpenLevelPickingDialog(FOnLevelsChosen::CreateStatic(&FLocal::HandleLevelsChosen), + OpenLevelPickingDialog(FOnLevelsChosen::CreateStatic(&FLocal::HandleLevelsChosen, &bResult), FOnLevelPickingCancelled::CreateStatic(&FLocal::HandleDialogCancelled), bAllowMultipleSelection); } @@ -2094,12 +2100,12 @@ void FEditorFileUtils::LoadMap() if( FEditorFileUtils::SaveDirtyPackages(bPromptUserToSave, bSaveMapPackages, bSaveContentPackages) == false ) { // something went wrong or the user pressed cancel. Return to the editor so the user doesn't lose their changes - return; + return false; } } FEditorDirectories::Get().SetLastDirectory(ELastDirectory::LEVEL, FPaths::GetPath(FileToOpen)); - LoadMap( FileToOpen, false, true ); + bResult = LoadMap( FileToOpen, false, true ); } else { @@ -2108,6 +2114,8 @@ void FEditorFileUtils::LoadMap() } } } + + return bResult; } static void NotifyBSPNeedsRebuild(const FString& PackageName) @@ -2193,13 +2201,13 @@ static void NotifyBSPNeedsRebuild(const FString& PackageName) * @param LoadAsTemplate Forces the map to load into an untitled outermost package * preventing the map saving over the original file. */ -void FEditorFileUtils::LoadMap(const FString& InFilename, bool LoadAsTemplate, bool bShowProgress) +bool FEditorFileUtils::LoadMap(const FString& InFilename, bool LoadAsTemplate, bool bShowProgress) { double LoadStartTime = FPlatformTime::Seconds(); if (GUnrealEd->WarnIfLightingBuildIsCurrentlyRunning()) { - return; + return false; } const FScopedBusyCursor BusyCursor; @@ -2230,7 +2238,7 @@ void FEditorFileUtils::LoadMap(const FString& InFilename, bool LoadAsTemplate, b if ( !FPackageName::TryConvertFilenameToLongPackageName(Filename, LongMapPackageName) ) { FMessageDialog::Open(EAppMsgType::Ok, FText::Format(NSLOCTEXT("Editor", "MapLoad_FriendlyBadFilename", "Map load failed. The filename '{0}' is not within the game or engine content folders found in '{1}'."), FText::FromString(Filename), FText::FromString(FPaths::RootDir()))); - return; + return false; } } @@ -2238,13 +2246,13 @@ void FEditorFileUtils::LoadMap(const FString& InFilename, bool LoadAsTemplate, b // Abort if the user refuses to terminate the PIE session. if ( GEditor->ShouldAbortBecauseOfPIEWorld() ) { - return; + return false; } // If a level is in memory but never saved to disk, warn the user that the level will be lost. if (GEditor->ShouldAbortBecauseOfUnsavedWorld()) { - return; + return false; } // Save last opened level name. @@ -2254,7 +2262,7 @@ void FEditorFileUtils::LoadMap(const FString& InFilename, bool LoadAsTemplate, b GLevelEditorModeTools().DeactivateAllModes(); FString LoadCommand = FString::Printf(TEXT("MAP LOAD FILE=\"%s\" TEMPLATE=%d SHOWPROGRESS=%d FEATURELEVEL=%d"), *Filename, LoadAsTemplate, bShowProgress, (int32)GEditor->DefaultWorldFeatureLevel); - bool bResult = GUnrealEd->Exec( NULL, *LoadCommand ); + const bool bResult = GUnrealEd->Exec( NULL, *LoadCommand ); UWorld* World = GWorld; // Incase the load failed after gworld was torn down, default to a new blank map @@ -2264,7 +2272,7 @@ void FEditorFileUtils::LoadMap(const FString& InFilename, bool LoadAsTemplate, b ResetLevelFilenames(); - return; + return false; } World->IssueEditorLoadWarnings(); @@ -2321,6 +2329,8 @@ void FEditorFileUtils::LoadMap(const FString& InFilename, bool LoadAsTemplate, b // Fire delegate when a new map is opened, with name of map FEditorDelegates::OnMapOpened.Broadcast(InFilename, LoadAsTemplate); + + return bResult; } /** @@ -3802,4 +3812,112 @@ void FEditorFileUtils::GetDirtyContentPackages(TArray& OutDirtyPackag } } +UWorld* UEditorLoadingAndSavingUtils::LoadMap(const FString& Filename) +{ + const bool bLoadAsTemplate = false; + const bool bShowProgress = true; + if (FEditorFileUtils::LoadMap(Filename, bLoadAsTemplate, bShowProgress)) + { + return GEditor->GetEditorWorldContext().World(); + } + + return nullptr; +} + +bool UEditorLoadingAndSavingUtils::SaveMap(UWorld* World, const FString& AssetPath) +{ + bool bSucceeded = false; + FString SaveFilename; + if( FPackageName::TryConvertLongPackageNameToFilename(AssetPath, SaveFilename, FPackageName::GetMapPackageExtension())) + { + bSucceeded = FEditorFileUtils::SaveMap(World, SaveFilename); + if (bSucceeded) + { + FAssetRegistryModule::AssetCreated(World); + } + } + + return bSucceeded; +} + +UWorld* UEditorLoadingAndSavingUtils::NewBlankMap(bool bSaveExistingMap) +{ + GLevelEditorModeTools().DeactivateAllModes(); + + const bool bPromptUserToSave = false; + const bool bFastSave = !bPromptUserToSave; + const bool bSaveMapPackages = true; + const bool bSaveContentPackages = false; + if (bSaveExistingMap && FEditorFileUtils::SaveDirtyPackages(bPromptUserToSave, bSaveMapPackages, bSaveContentPackages, bFastSave) == false) + { + // something went wrong or the user pressed cancel. Return to the editor so the user doesn't lose their changes + return nullptr; + } + + UWorld* World = GUnrealEd->NewMap(); + + FEditorFileUtils::ResetLevelFilenames(); + + return World; +} + +UWorld* UEditorLoadingAndSavingUtils::NewMapFromTemplate(const FString& PathToTemplateLevel, bool bSaveExistingMap) +{ + bool bPromptUserToSave = false; + bool bSaveMapPackages = true; + bool bSaveContentPackages = false; + if (bSaveExistingMap && SaveDirtyPackages(bPromptUserToSave, bSaveMapPackages, bSaveContentPackages) == false) + { + return nullptr; + } + + const bool bLoadAsTemplate = true; + // Load the template map file - passes LoadAsTemplate==true making the + // level load into an untitled package that won't save over the template + FEditorFileUtils::LoadMap(*PathToTemplateLevel, bLoadAsTemplate); + + return GEditor->GetEditorWorldContext().World(); +} + +UWorld* UEditorLoadingAndSavingUtils::LoadMapWithDialog() +{ + if (!FEditorFileUtils::LoadMap()) + { + return nullptr; + } + + return GEditor->GetEditorWorldContext().World(); +} + +bool UEditorLoadingAndSavingUtils::SaveDirtyPackages(const bool bSaveMapPackages, const bool bSaveContentPackages, const bool bPromptUser) +{ + return FEditorFileUtils::SaveDirtyPackages(bPromptUser, bSaveMapPackages, bSaveContentPackages, !bPromptUser); +} + +bool UEditorLoadingAndSavingUtils::SaveCurrentLevel() +{ + return FEditorFileUtils::SaveCurrentLevel(); +} + +void UEditorLoadingAndSavingUtils::GetDirtyMapPackages(TArray& OutDirtyPackages) +{ + FEditorFileUtils::GetDirtyWorldPackages(OutDirtyPackages); +} + +void UEditorLoadingAndSavingUtils::GetDirtyContentPackages(TArray& OutDirtyPackages) +{ + FEditorFileUtils::GetDirtyContentPackages(OutDirtyPackages); +} + +void UEditorLoadingAndSavingUtils::ImportScene(const FString& Filename) +{ + FEditorFileUtils::Import(Filename); +} + +void UEditorLoadingAndSavingUtils::ExportScene(bool bExportSelectedActorsOnly) +{ + FEditorFileUtils::Export(bExportSelectedActorsOnly); +} + #undef LOCTEXT_NAMESPACE + diff --git a/Engine/Source/Editor/UnrealEd/Private/GroupActor.cpp b/Engine/Source/Editor/UnrealEd/Private/GroupActor.cpp index d2e2092d8700..c322b55ee93f 100644 --- a/Engine/Source/Editor/UnrealEd/Private/GroupActor.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/GroupActor.cpp @@ -11,6 +11,7 @@ #include "ScopedTransaction.h" #include "LevelEditorViewport.h" #include "Layers/ILayers.h" +#include "ActorGroupingUtils.h" const FLinearColor BOXCOLOR_LOCKEDGROUPS( 0.0f, 1.0f, 0.0f ); const FLinearColor BOXCOLOR_UNLOCKEDGROUPS( 1.0f, 0.0f, 0.0f ); @@ -151,11 +152,14 @@ void AGroupActor::GroupApplyDelta(const FVector& InDrag, const FRotator& InRot, { for(int32 ActorIndex=0; ActorIndexApplyDeltaToActor( GroupActors[ActorIndex], true, &InDrag, &InRot, &InScale ); + // Check that we've not got a parent attachment within the group/selection + const bool bCanApplyDelta = !ActorHasParentInGroup(GroupActors, GroupActors[ActorIndex]) && !ActorHasParentInSelection(GroupActors[ActorIndex]); + if(bCanApplyDelta) + { + GEditor->ApplyDeltaToActor(GroupActors[ActorIndex], true, &InDrag, &InRot, &InScale); + } } } for(int32 SubGroupIndex=0; SubGroupIndexbGroupingActive ) + if( UActorGroupingUtils::IsGroupingActive() ) { check(PDI); @@ -673,7 +677,7 @@ void AGroupActor::ToggleGroupMode() // Group mode can only be toggled when not in InterpEdit mode if( !GLevelEditorModeTools().IsModeActive(FBuiltinEditorModes::EM_InterpEdit) ) { - GUnrealEd->bGroupingActive = !GUnrealEd->bGroupingActive; + UActorGroupingUtils::SetGroupingActive(!UActorGroupingUtils::IsGroupingActive()); // Update group selection in the editor to reflect the toggle SelectGroupsInSelection(); @@ -686,7 +690,7 @@ void AGroupActor::ToggleGroupMode() void AGroupActor::SelectGroupsInSelection() { - if( GUnrealEd->bGroupingActive ) + if( UActorGroupingUtils::IsGroupingActive() ) { TArray GroupsToSelect; for ( FSelectionIterator It( GEditor->GetSelectedActorIterator() ) ; It ; ++It ) diff --git a/Engine/Source/Editor/UnrealEd/Private/Kismet2/BlueprintEditorUtils.cpp b/Engine/Source/Editor/UnrealEd/Private/Kismet2/BlueprintEditorUtils.cpp index 94a0c47128d4..b49ef4d42431 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Kismet2/BlueprintEditorUtils.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Kismet2/BlueprintEditorUtils.cpp @@ -44,7 +44,7 @@ #include "Settings/ProjectPackagingSettings.h" #include "Matinee/MatineeActor.h" #include "Engine/LevelScriptBlueprint.h" - +#include "BlueprintsObjectVersion.h" #include "Kismet2/CompilerResultsLog.h" #include "Editor/KismetCompiler/Public/KismetCompilerModule.h" @@ -1793,6 +1793,7 @@ void FBlueprintEditorUtils::PostDuplicateBlueprint(UBlueprint* Blueprint, bool b Blueprint->GeneratedClass = NewClass; NewClass->ClassGeneratedBy = Blueprint; NewClass->SetSuperStruct(Blueprint->ParentClass); + Blueprint->bHasBeenRegenerated = true; // Set to true, similar to CreateBlueprint, since we've regerated the class by duplicating it // Since we just duplicated the generated class above, we don't need to do a full compile below CompileOptions.CompileType = EKismetCompileType::SkeletonOnly; @@ -2131,11 +2132,21 @@ void FBlueprintEditorUtils::MarkBlueprintAsModified(UBlueprint* Blueprint, FProp bool FBlueprintEditorUtils::ShouldRegenerateBlueprint(UBlueprint* Blueprint) { - return !GForceDisableBlueprintCompileOnLoad + return !IsCompileOnLoadDisabled(Blueprint) && Blueprint->bRecompileOnLoad && !Blueprint->bIsRegeneratingOnLoad; } +bool FBlueprintEditorUtils::IsCompileOnLoadDisabled(UBlueprint* Blueprint) +{ + bool bCompilationDisabled = false; + if(Blueprint->GetLinker()) + { + bCompilationDisabled = (Blueprint->GetLinker()->LoadFlags & LOAD_DisableCompileOnLoad) != LOAD_None; + } + return bCompilationDisabled; +} + // Helper function to get the blueprint that ultimately owns a node. UBlueprint* FBlueprintEditorUtils::FindBlueprintForNode(const UEdGraphNode* Node) { @@ -3974,8 +3985,10 @@ bool FBlueprintEditorUtils::IsPinTypeValid(const FEdGraphPinType& Type) // Gets the visible class variable list. This includes both variables introduced here and in all superclasses. void FBlueprintEditorUtils::GetClassVariableList(const UBlueprint* Blueprint, TArray& VisibleVariables, bool bIncludePrivateVars) { - // Existing variables in the parent class and above - check(!Blueprint->bHasBeenRegenerated || Blueprint->bIsRegeneratingOnLoad || (Blueprint->SkeletonGeneratedClass != nullptr)); + // Existing variables in the parent class and above, when using the compilation manager the previous SkeletonGeneratedClass will have been cleared when + // we're regenerating the SkeletonGeneratedClass. Using this function in the skeleton pass at all is highly dubious, but I am leaving it until the + // compilation manager is on full time: + check(!Blueprint->bHasBeenRegenerated || Blueprint->bIsRegeneratingOnLoad || (Blueprint->SkeletonGeneratedClass != nullptr) || GBlueprintUseCompilationManager); if (Blueprint->SkeletonGeneratedClass != nullptr) { for (TFieldIterator PropertyIt(Blueprint->SkeletonGeneratedClass, EFieldIteratorFlags::IncludeSuper); PropertyIt; ++PropertyIt) @@ -4501,7 +4514,7 @@ void FBlueprintEditorUtils::ChangeMemberVariableType(UBlueprint* Blueprint, cons { Variable.VarType = NewPinType; - if(Variable.VarType.bIsSet || Variable.VarType.bIsMap) + if(Variable.VarType.IsSet() || Variable.VarType.IsMap()) { // Make sure that the variable is no longer tagged for replication, and warn the user if the variable is no // longer goign to be replicated: @@ -4960,6 +4973,9 @@ void FBlueprintEditorUtils::ChangeLocalVariableType(UBlueprint* InBlueprint, con Variable.VarType = NewPinType; + // Reset the default value + Variable.DefaultValue.Empty(); + // Mark the Blueprint as structurally modified so we can reconstruct the node successfully FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(InBlueprint); @@ -5171,8 +5187,19 @@ bool FBlueprintEditorUtils::ValidateAllFunctionGraphs(UBlueprint* InBlueprint, U return false; } -void FBlueprintEditorUtils::ValidateBlueprintVariableMetadata(FBPVariableDescription& VarDesc) +void FBlueprintEditorUtils::FixupVariableDescription(UBlueprint* Blueprint, FBPVariableDescription& VarDesc) { + if ((VarDesc.PropertyFlags & CPF_Config) != 0 && Blueprint->GetLinkerCustomVersion(FBlueprintsObjectVersion::GUID) < FBlueprintsObjectVersion::DisallowObjectConfigVars) + { + // Synchronized with FBlueprintVarActionDetails::IsConfigCheckBoxEnabled + const FEdGraphPinType& VarType = VarDesc.VarType; + if (VarType.PinCategory == UEdGraphSchema_K2::PC_Object || + VarType.PinCategory == UEdGraphSchema_K2::PC_Interface) + { + VarDesc.PropertyFlags &= ~CPF_Config; + } + } + // Remove bitflag enum type metadata if the enum type name is missing or if the enum type is no longer a bitflags type. if (VarDesc.HasMetaData(FBlueprintMetadata::MD_BitmaskEnum)) { @@ -5243,86 +5270,6 @@ void FBlueprintEditorUtils::ValidateBlueprintChildVariables(UBlueprint* InBluepr ////////////////////////////////////////////////////////////////////////// -void FBlueprintEditorUtils::ImportKismetDefaultValueToProperty(UEdGraphPin* SourcePin, UProperty* DestinationProperty, uint8* DestinationAddress, UObject* OwnerObject) -{ - FString LiteralString = SourcePin->GetDefaultAsString(); - - const UEdGraphSchema_K2* K2Schema = GetDefault(); - - if (UStructProperty* StructProperty = Cast(DestinationProperty)) - { - static UScriptStruct* VectorStruct = TBaseStructure::Get(); - static UScriptStruct* RotatorStruct = TBaseStructure::Get(); - static UScriptStruct* TransformStruct = TBaseStructure::Get(); - - if (StructProperty->Struct == VectorStruct) - { - FDefaultValueHelper::ParseVector(LiteralString, *((FVector*)DestinationAddress)); - return; - } - else if (StructProperty->Struct == RotatorStruct) - { - FDefaultValueHelper::ParseRotator(LiteralString, *((FRotator*)DestinationAddress)); - return; - } - else if (StructProperty->Struct == TransformStruct) - { - (*(FTransform*)DestinationAddress).InitFromString( LiteralString ); - return; - } - } - else if (UObjectPropertyBase* ObjectProperty = Cast(DestinationProperty)) - { - ObjectProperty->SetObjectPropertyValue(DestinationAddress, SourcePin->DefaultObject); - return; - } - - const int32 PortFlags = 0; - DestinationProperty->ImportText(*LiteralString, DestinationAddress, PortFlags, OwnerObject); -} - -void FBlueprintEditorUtils::ExportPropertyToKismetDefaultValue(UEdGraphPin* TargetPin, UProperty* SourceProperty, uint8* SourceAddress, UObject* OwnerObject) -{ - FString LiteralString; - - if (UStructProperty* StructProperty = Cast(SourceProperty)) - { - static UScriptStruct* VectorStruct = TBaseStructure::Get(); - static UScriptStruct* RotatorStruct = TBaseStructure::Get(); - static UScriptStruct* TransformStruct = TBaseStructure::Get(); - - if (StructProperty->Struct == VectorStruct) - { - FVector& SourceVector = *((FVector*)SourceAddress); - TargetPin->DefaultValue = FString::Printf(TEXT("%f, %f, %f"), SourceVector.X, SourceVector.Y, SourceVector.Z); - return; - } - else if (StructProperty->Struct == RotatorStruct) - { - FRotator& SourceRotator = *((FRotator*)SourceAddress); - TargetPin->DefaultValue = FString::Printf(TEXT("%f, %f, %f"), SourceRotator.Pitch, SourceRotator.Yaw, SourceRotator.Roll); - return; - } - else if (StructProperty->Struct == TransformStruct) - { - TargetPin->DefaultValue = (*(FTransform*)SourceAddress).ToString(); - return; - } - } - else if (UObjectPropertyBase* ObjectProperty = Cast(SourceProperty)) - { - TargetPin->DefaultObject = ObjectProperty->GetObjectPropertyValue(SourceAddress); - return; - } - - //@TODO: Add support for object literals - - const int32 PortFlags = 0; - - TargetPin->DefaultValue.Empty(); - SourceProperty->ExportTextItem(TargetPin->DefaultValue, SourceAddress, nullptr, OwnerObject, PortFlags); -} - void FBlueprintEditorUtils::FindNativizationDependencies(UBlueprint* Blueprint, TArray& NativizeDependenciesOut) { FBlueprintEditorUtils::FindImplementedInterfaces(Blueprint, /*bGetAllInterfaces =*/false, NativizeDependenciesOut); @@ -7457,7 +7404,6 @@ public: return InFilterFuncs->IfInChildOfClassesSet( AllowedChildrenOfClasses, InClass) != EFilterReturn::Failed && InFilterFuncs->IfInChildOfClassesSet(DisallowedChildrenOfClasses, InClass) != EFilterReturn::Passed && InFilterFuncs->IfInClassesSet(DisallowedClasses, InClass) != EFilterReturn::Passed && - !InClass->GetCppTypeInfo()->IsAbstract() && !InClass->HasAnyClassFlags(CLASS_Deprecated | CLASS_NewerVersionExists) && InClass->HasAnyClassFlags(CLASS_Interface) && // Here is some loaded classes only logic, Blueprints will never have this info @@ -7753,89 +7699,93 @@ bool FBlueprintEditorUtils::IsObjectADebugCandidate( AActor* InActorObject, UBlu return bPassesFlags && bCanDebugThisObject; } -bool FBlueprintEditorUtils::PropertyValueFromString(const UProperty* Property, const FString& Value, uint8* DefaultObject) +bool FBlueprintEditorUtils::PropertyValueFromString(const UProperty* Property, const FString& StrValue, uint8* Container) +{ + return PropertyValueFromString_Direct(Property, StrValue, Property->ContainerPtrToValuePtr(Container)); +} + +bool FBlueprintEditorUtils::PropertyValueFromString_Direct(const UProperty* Property, const FString& StrValue, uint8* DirectValue) { bool bParseSucceeded = true; - if( !Property->IsA(UStructProperty::StaticClass()) ) + if (!Property->IsA(UStructProperty::StaticClass())) { - if( Property->IsA(UIntProperty::StaticClass()) ) + if (Property->IsA(UIntProperty::StaticClass())) { int32 IntValue = 0; - bParseSucceeded = FDefaultValueHelper::ParseInt(Value, IntValue); - CastChecked(Property)->SetPropertyValue_InContainer(DefaultObject, IntValue); + bParseSucceeded = FDefaultValueHelper::ParseInt(StrValue, IntValue); + CastChecked(Property)->SetPropertyValue(DirectValue, IntValue); } - else if( Property->IsA(UFloatProperty::StaticClass()) ) + else if (Property->IsA(UFloatProperty::StaticClass())) { float FloatValue = 0.0f; - bParseSucceeded = FDefaultValueHelper::ParseFloat(Value, FloatValue); - CastChecked(Property)->SetPropertyValue_InContainer(DefaultObject, FloatValue); + bParseSucceeded = FDefaultValueHelper::ParseFloat(StrValue, FloatValue); + CastChecked(Property)->SetPropertyValue(DirectValue, FloatValue); } else if (const UByteProperty* ByteProperty = Cast(Property)) { int32 IntValue = 0; if (const UEnum* Enum = ByteProperty->Enum) { - IntValue = Enum->GetValueByName(FName(*Value)); + IntValue = Enum->GetValueByName(FName(*StrValue)); bParseSucceeded = (INDEX_NONE != IntValue); // If the parse did not succeed, clear out the int to keep the enum value valid - if(!bParseSucceeded) + if (!bParseSucceeded) { IntValue = 0; } } else { - bParseSucceeded = FDefaultValueHelper::ParseInt(Value, IntValue); + bParseSucceeded = FDefaultValueHelper::ParseInt(StrValue, IntValue); } - bParseSucceeded = bParseSucceeded && ( IntValue <= 255 ) && ( IntValue >= 0 ); - ByteProperty->SetPropertyValue_InContainer(DefaultObject, IntValue); + bParseSucceeded = bParseSucceeded && (IntValue <= 255) && (IntValue >= 0); + ByteProperty->SetPropertyValue(DirectValue, IntValue); } else if (const UEnumProperty* EnumProperty = Cast(Property)) { - int64 IntValue = IntValue = EnumProperty->GetEnum()->GetValueByName(FName(*Value)); + int64 IntValue = EnumProperty->GetEnum()->GetValueByName(FName(*StrValue)); bParseSucceeded = (INDEX_NONE != IntValue); // If the parse did not succeed, clear out the int to keep the enum value valid - if(!bParseSucceeded) + if (!bParseSucceeded) { IntValue = 0; } - bParseSucceeded = bParseSucceeded && ( IntValue <= 255 ) && ( IntValue >= 0 ); - void* PropAddr = EnumProperty->ContainerPtrToValuePtr(DefaultObject); - EnumProperty->GetUnderlyingProperty()->SetIntPropertyValue(PropAddr, IntValue); + bParseSucceeded = bParseSucceeded && (IntValue <= 255) && (IntValue >= 0); + EnumProperty->GetUnderlyingProperty()->SetIntPropertyValue(DirectValue, IntValue); } - else if( Property->IsA(UStrProperty::StaticClass()) ) + else if (Property->IsA(UStrProperty::StaticClass())) { - CastChecked(Property)->SetPropertyValue_InContainer(DefaultObject, Value); + CastChecked(Property)->SetPropertyValue(DirectValue, StrValue); } - else if( Property->IsA(UBoolProperty::StaticClass()) ) + else if (Property->IsA(UBoolProperty::StaticClass())) { - CastChecked(Property)->SetPropertyValue_InContainer(DefaultObject, Value.ToBool()); + CastChecked(Property)->SetPropertyValue(DirectValue, StrValue.ToBool()); } - else if( Property->IsA(UNameProperty::StaticClass()) ) + else if (Property->IsA(UNameProperty::StaticClass())) { - CastChecked(Property)->SetPropertyValue_InContainer(DefaultObject, FName(*Value)); + CastChecked(Property)->SetPropertyValue(DirectValue, FName(*StrValue)); } - else if( Property->IsA(UTextProperty::StaticClass()) ) + else if (Property->IsA(UTextProperty::StaticClass())) { FStringOutputDevice ImportError; - const TCHAR* EndOfParsedBuff = Property->ImportText(*Value, Property->ContainerPtrToValuePtr(DefaultObject), 0, nullptr, &ImportError); + const TCHAR* EndOfParsedBuff = Property->ImportText(*StrValue, DirectValue, 0, nullptr, &ImportError); bParseSucceeded = EndOfParsedBuff && ImportError.IsEmpty(); } else { // Empty array-like properties need to use "()" in order to import correctly (as array properties export comma separated within a set of brackets) - const TCHAR* const ValueToImport = (Value.IsEmpty() && (Property->IsA(UArrayProperty::StaticClass()) || Property->IsA(UMulticastDelegateProperty::StaticClass()))) + const TCHAR* const ValueToImport = (StrValue.IsEmpty() && (Property->IsA(UArrayProperty::StaticClass()) || Property->IsA(UMulticastDelegateProperty::StaticClass()))) ? TEXT("()") - : *Value; + : *StrValue; FStringOutputDevice ImportError; - const TCHAR* EndOfParsedBuff = Property->ImportText(*Value, Property->ContainerPtrToValuePtr(DefaultObject), 0, nullptr, &ImportError); + const TCHAR* EndOfParsedBuff = Property->ImportText(*StrValue, DirectValue, 0, nullptr, &ImportError); bParseSucceeded = EndOfParsedBuff && ImportError.IsEmpty(); } } - else + else { static UScriptStruct* VectorStruct = TBaseStructure::Get(); static UScriptStruct* RotatorStruct = TBaseStructure::Get(); @@ -7845,42 +7795,41 @@ bool FBlueprintEditorUtils::PropertyValueFromString(const UProperty* Property, c const UStructProperty* StructProperty = CastChecked(Property); // Struct properties must be handled differently, unfortunately. We only support FVector, FRotator, and FTransform - if( StructProperty->Struct == VectorStruct ) + if (StructProperty->Struct == VectorStruct) { FVector V = FVector::ZeroVector; - bParseSucceeded = FDefaultValueHelper::ParseVector(Value, V); - Property->CopyCompleteValue( Property->ContainerPtrToValuePtr(DefaultObject), &V ); + bParseSucceeded = FDefaultValueHelper::ParseVector(StrValue, V); + Property->CopyCompleteValue(DirectValue, &V); } - else if( StructProperty->Struct == RotatorStruct ) + else if (StructProperty->Struct == RotatorStruct) { FRotator R = FRotator::ZeroRotator; - bParseSucceeded = FDefaultValueHelper::ParseRotator(Value, R); - Property->CopyCompleteValue( Property->ContainerPtrToValuePtr(DefaultObject), &R ); + bParseSucceeded = FDefaultValueHelper::ParseRotator(StrValue, R); + Property->CopyCompleteValue(DirectValue, &R); } - else if( StructProperty->Struct == TransformStruct ) + else if (StructProperty->Struct == TransformStruct) { FTransform T = FTransform::Identity; - bParseSucceeded = T.InitFromString( Value ); - Property->CopyCompleteValue( Property->ContainerPtrToValuePtr(DefaultObject), &T ); + bParseSucceeded = T.InitFromString(StrValue); + Property->CopyCompleteValue(DirectValue, &T); } - else if( StructProperty->Struct == LinearColorStruct ) + else if (StructProperty->Struct == LinearColorStruct) { FLinearColor Color; // Color form: "(R=%f,G=%f,B=%f,A=%f)" - bParseSucceeded = Color.InitFromString(Value); - Property->CopyCompleteValue( Property->ContainerPtrToValuePtr(DefaultObject), &Color ); + bParseSucceeded = Color.InitFromString(StrValue); + Property->CopyCompleteValue(DirectValue, &Color); } else if (StructProperty->Struct) { const UScriptStruct* Struct = StructProperty->Struct; const int32 StructSize = Struct->GetStructureSize() * StructProperty->ArrayDim; - uint8* StructData = Property->ContainerPtrToValuePtr(DefaultObject); - StructProperty->InitializeValue(StructData); + StructProperty->InitializeValue(DirectValue); ensure(1 == StructProperty->ArrayDim); - bParseSucceeded = FStructureEditorUtils::Fill_MakeStructureDefaultValue(Cast(Struct), StructData); + bParseSucceeded = FStructureEditorUtils::Fill_MakeStructureDefaultValue(Cast(Struct), DirectValue); FStringOutputDevice ImportError; - const TCHAR* EndOfParsedBuff = StructProperty->ImportText(Value.IsEmpty() ? TEXT("()") : *Value, StructData, 0, nullptr, &ImportError); + const TCHAR* EndOfParsedBuff = StructProperty->ImportText(StrValue.IsEmpty() ? TEXT("()") : *StrValue, DirectValue, 0, nullptr, &ImportError); bParseSucceeded &= EndOfParsedBuff && ImportError.IsEmpty(); } } @@ -8034,95 +7983,100 @@ bool FBlueprintEditorUtils::CheckIfSelectionIsCycling(const TSet& bool FBlueprintEditorUtils::IsPaletteActionReadOnly(TSharedPtr ActionIn, TSharedPtr const BlueprintEditorIn) { check(BlueprintEditorIn.IsValid()); - UBlueprint const* const BlueprintObj = BlueprintEditorIn->GetBlueprintObj(); - bool bIsReadOnly = false; - if(ActionIn->GetTypeId() == FEdGraphSchemaAction_K2Graph::StaticGetTypeId()) + if(!BlueprintEditorIn->InEditingMode()) { - FEdGraphSchemaAction_K2Graph* GraphAction = (FEdGraphSchemaAction_K2Graph*)ActionIn.Get(); - // No graph is evidence of an overridable function, don't let the user modify it - if(GraphAction->EdGraph == nullptr) + bIsReadOnly = true; + } + else + { + UBlueprint const* const BlueprintObj = BlueprintEditorIn->GetBlueprintObj(); + if(ActionIn->GetTypeId() == FEdGraphSchemaAction_K2Graph::StaticGetTypeId()) { - bIsReadOnly = true; - } - else - { - // Graphs that cannot be deleted or re-named are read-only - if ( !(GraphAction->EdGraph->bAllowDeletion || GraphAction->EdGraph->bAllowRenaming) ) + FEdGraphSchemaAction_K2Graph* GraphAction = (FEdGraphSchemaAction_K2Graph*)ActionIn.Get(); + // No graph is evidence of an overridable function, don't let the user modify it + if(GraphAction->EdGraph == nullptr) { bIsReadOnly = true; } else { - if(GraphAction->GraphType == EEdGraphSchemaAction_K2Graph::Function) + // Graphs that cannot be deleted or re-named are read-only + if ( !(GraphAction->EdGraph->bAllowDeletion || GraphAction->EdGraph->bAllowRenaming) ) { - // Check if the function is an override - UFunction* OverrideFunc = FindField(BlueprintObj->ParentClass, GraphAction->FuncName); - if ( OverrideFunc != nullptr ) + bIsReadOnly = true; + } + else + { + if(GraphAction->GraphType == EEdGraphSchemaAction_K2Graph::Function) { + // Check if the function is an override + UFunction* OverrideFunc = FindField(BlueprintObj->ParentClass, GraphAction->FuncName); + if ( OverrideFunc != nullptr ) + { + bIsReadOnly = true; + } + } + else if(GraphAction->GraphType == EEdGraphSchemaAction_K2Graph::Interface) + { + // Interfaces cannot be renamed bIsReadOnly = true; } } - else if(GraphAction->GraphType == EEdGraphSchemaAction_K2Graph::Interface) - { - // Interfaces cannot be renamed - bIsReadOnly = true; - } } } - } - else if(ActionIn->GetTypeId() == FEdGraphSchemaAction_K2Var::StaticGetTypeId()) - { - FEdGraphSchemaAction_K2Var* VarAction = (FEdGraphSchemaAction_K2Var*)ActionIn.Get(); + else if(ActionIn->GetTypeId() == FEdGraphSchemaAction_K2Var::StaticGetTypeId()) + { + FEdGraphSchemaAction_K2Var* VarAction = (FEdGraphSchemaAction_K2Var*)ActionIn.Get(); - bIsReadOnly = true; + bIsReadOnly = true; - if( FBlueprintEditorUtils::FindNewVariableIndex(BlueprintObj, VarAction->GetVariableName()) != INDEX_NONE) - { - bIsReadOnly = false; - } - else if(BlueprintObj->FindTimelineTemplateByVariableName(VarAction->GetVariableName())) - { - bIsReadOnly = false; - } - else if(BlueprintEditorIn->CanAccessComponentsMode()) - { - // Wasn't in the introduced variable list; try to find the associated SCS node - //@TODO: The SCS-generated variables should be in the variable list and have a link back; - // As it stands, you cannot do any metadata operations on a SCS variable, and you have to do icky code like the following - TArray Nodes = BlueprintObj->SimpleConstructionScript->GetAllNodes(); - for (TArray::TConstIterator NodeIt(Nodes); NodeIt; ++NodeIt) + if( FBlueprintEditorUtils::FindNewVariableIndex(BlueprintObj, VarAction->GetVariableName()) != INDEX_NONE) { - USCS_Node* CurrentNode = *NodeIt; - if (CurrentNode->GetVariableName() == VarAction->GetVariableName()) + bIsReadOnly = false; + } + else if(BlueprintObj->FindTimelineTemplateByVariableName(VarAction->GetVariableName())) + { + bIsReadOnly = false; + } + else if(BlueprintEditorIn->CanAccessComponentsMode()) + { + // Wasn't in the introduced variable list; try to find the associated SCS node + //@TODO: The SCS-generated variables should be in the variable list and have a link back; + // As it stands, you cannot do any metadata operations on a SCS variable, and you have to do icky code like the following + TArray Nodes = BlueprintObj->SimpleConstructionScript->GetAllNodes(); + for (TArray::TConstIterator NodeIt(Nodes); NodeIt; ++NodeIt) { - bIsReadOnly = false; - break; + USCS_Node* CurrentNode = *NodeIt; + if (CurrentNode->GetVariableName() == VarAction->GetVariableName()) + { + bIsReadOnly = false; + break; + } } } } - } - else if(ActionIn->GetTypeId() == FEdGraphSchemaAction_K2Delegate::StaticGetTypeId()) - { - FEdGraphSchemaAction_K2Delegate* DelegateAction = (FEdGraphSchemaAction_K2Delegate*)ActionIn.Get(); + else if(ActionIn->GetTypeId() == FEdGraphSchemaAction_K2Delegate::StaticGetTypeId()) + { + FEdGraphSchemaAction_K2Delegate* DelegateAction = (FEdGraphSchemaAction_K2Delegate*)ActionIn.Get(); - if( FBlueprintEditorUtils::FindNewVariableIndex(BlueprintObj, DelegateAction->GetDelegateName()) == INDEX_NONE) + if( FBlueprintEditorUtils::FindNewVariableIndex(BlueprintObj, DelegateAction->GetDelegateName()) == INDEX_NONE) + { + bIsReadOnly = true; + } + } + else if (ActionIn->GetTypeId() == FEdGraphSchemaAction_K2Event::StaticGetTypeId()) + { + FEdGraphSchemaAction_K2Event* EventAction = (FEdGraphSchemaAction_K2Event*)ActionIn.Get(); + UK2Node* AssociatedNode = EventAction->NodeTemplate; + + bIsReadOnly = (AssociatedNode == nullptr) || (!AssociatedNode->bCanRenameNode); + } + else if (ActionIn->GetTypeId() == FEdGraphSchemaAction_K2InputAction::StaticGetTypeId()) { bIsReadOnly = true; } } - else if (ActionIn->GetTypeId() == FEdGraphSchemaAction_K2Event::StaticGetTypeId()) - { - FEdGraphSchemaAction_K2Event* EventAction = (FEdGraphSchemaAction_K2Event*)ActionIn.Get(); - UK2Node* AssociatedNode = EventAction->NodeTemplate; - - bIsReadOnly = (AssociatedNode == nullptr) || (!AssociatedNode->bCanRenameNode); - } - else if (ActionIn->GetTypeId() == FEdGraphSchemaAction_K2InputAction::StaticGetTypeId()) - { - bIsReadOnly = true; - } - return bIsReadOnly; } @@ -8496,15 +8450,15 @@ const FSlateBrush* FBlueprintEditorUtils::GetIconFromPin( const FEdGraphPinType& const FSlateBrush* IconBrush = FEditorStyle::GetBrush(TEXT("Kismet.VariableList.TypeIcon")); const UObject* PinSubObject = PinType.PinSubCategoryObject.Get(); - if( PinType.bIsArray && PinType.PinCategory != K2Schema->PC_Exec ) + if( PinType.IsArray() && PinType.PinCategory != K2Schema->PC_Exec ) { IconBrush = FEditorStyle::GetBrush(TEXT("Kismet.VariableList.ArrayTypeIcon")); } - else if (PinType.bIsMap && PinType.PinCategory != K2Schema->PC_Exec) + else if (PinType.IsMap() && PinType.PinCategory != K2Schema->PC_Exec) { IconBrush = FEditorStyle::GetBrush(TEXT("Kismet.VariableList.MapKeyTypeIcon")); } - else if (PinType.bIsSet && PinType.PinCategory != K2Schema->PC_Exec) + else if (PinType.IsSet() && PinType.PinCategory != K2Schema->PC_Exec) { if( bIsLarge ) { @@ -8529,7 +8483,7 @@ const FSlateBrush* FBlueprintEditorUtils::GetIconFromPin( const FEdGraphPinType& const FSlateBrush* FBlueprintEditorUtils::GetSecondaryIconFromPin(const FEdGraphPinType& PinType) { const UEdGraphSchema_K2* K2Schema = GetDefault(); - if (PinType.bIsMap && PinType.PinCategory != K2Schema->PC_Exec) + if (PinType.IsMap() && PinType.PinCategory != K2Schema->PC_Exec) { return FEditorStyle::GetBrush(TEXT("Kismet.VariableList.MapValueTypeIcon")); } diff --git a/Engine/Source/Editor/UnrealEd/Private/Kismet2/CompilerResultsLog.cpp b/Engine/Source/Editor/UnrealEd/Private/Kismet2/CompilerResultsLog.cpp index 0adf39dee111..764280d73a6b 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Kismet2/CompilerResultsLog.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Kismet2/CompilerResultsLog.cpp @@ -1,6 +1,7 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "Kismet2/CompilerResultsLog.h" +#include "Engine/Blueprint.h" #include "Modules/ModuleManager.h" #include "Misc/PackageName.h" #include "Editor/EditorPerProjectUserSettings.h" @@ -238,6 +239,13 @@ void FCompilerResultsLog::InternalLogSummary() /** Update the source backtrack map to note that NewObject was most closely generated/caused by the SourceObject */ void FCompilerResultsLog::NotifyIntermediateObjectCreation(UObject* NewObject, UObject* SourceObject) { + if(UEdGraphNode* NewNode = Cast(NewObject)) + { + if(UEdGraphNode* OldNode = Cast(SourceObject)) + { + FullSourceBacktrackMap.Add(NewNode, OldNode); + } + } SourceBacktrackMap.NotifyIntermediateObjectCreation(NewObject, SourceObject); } @@ -257,6 +265,83 @@ UObject const* FCompilerResultsLog::FindSourceObject(UObject const* PossiblyDupl return SourceBacktrackMap.FindSourceObject(PossiblyDuplicatedObject); } +int32 FCompilerResultsLog::CalculateStableIdentifierForLatentActionManager( const UEdGraphNode* Node ) +{ + /* + The name of this function is meant to instill a bit of caution: + 1. The Latent Action Manager uses uint32s to identify actions, so there + is some risk of collision, increasing if we aren't able to distribute + keys across the whole range of uint32 + 2. We need these identifiers to be stable across blueprint compiles, meaning + we can't just create a GUID and hash it + + Meeting these two requirements has proved difficult. The edge cases involve + macros and nodes that implement UK2Node::ExpandNode, e.g. LoadAsset/LoadAssetClass + nodes in Macros. In order to handle that case we use the full source backtrack map. + Typically an intermediate node has a dynamic GUID, which is useless, but source + nodes that came from macros have stable GUIDs, and can be used + */ + + const UEdGraphNode* OriginalNode = Node; + + // first search for a node with a stable GUID (e.g., not a node that was created via SpawnIntermediateNode, + // but we want to include nodes that are created via macro instantiation): + bool bNodeHasStableGUID = false; + while(!bNodeHasStableGUID) + { + if(!Node->HasAnyFlags(RF_Transient) || + GetIntermediateTunnelInstance(Node)) + { + bNodeHasStableGUID = true; + } + else + { + UEdGraphNode* const* PreviousNode = FullSourceBacktrackMap.Find(Node); + if(PreviousNode && *PreviousNode) + { + Node = *PreviousNode; + } + else + { + // we failed to find a source node, bail + bNodeHasStableGUID = true; + Node = nullptr; + } + } + } + + int32 LatentUUID = 0; + + if(Node) + { + LatentUUID = GetTypeHash(Node->NodeGuid); + + const UEdGraphNode* ResultNode = Node; + const UEdGraphNode* SourceNode = Cast(GetIntermediateTunnelInstance(Node)); + while (SourceNode && SourceNode != ResultNode) + { + if (SourceNode->NodeGuid.IsValid()) + { + LatentUUID = HashCombine(LatentUUID, GetTypeHash(SourceNode->NodeGuid)); + } + ResultNode = SourceNode; + SourceNode = Cast(GetIntermediateTunnelInstance(ResultNode)); + } + } + else + { + Warning( + *LOCTEXT("UUIDDeterministicCookWarn", "Failed to produce a deterministic UUID for a node's latent action: @@").ToString(), + OriginalNode + ); + + static int32 FallbackUUID = 0; + LatentUUID = FallbackUUID++; + } + + return LatentUUID; +} + UEdGraphPin* FCompilerResultsLog::FindSourcePin(UEdGraphPin* PossiblyDuplicatedPin) { return SourceBacktrackMap.FindSourcePin(PossiblyDuplicatedPin); @@ -636,10 +721,10 @@ UEdGraphNode* FCompilerResultsLog::GetSourceNode(const UEdGraphNode* Intermediat return Result; } -UEdGraphNode* FCompilerResultsLog::GetIntermediateTunnelInstance(const UEdGraphNode* IntermediateNode) +UEdGraphNode* FCompilerResultsLog::GetIntermediateTunnelInstance(const UEdGraphNode* IntermediateNode) const { TWeakObjectPtr Result; - if (TWeakObjectPtr* IntermediateTunnelInstanceNode = IntermediateTunnelNodeToTunnelInstanceMap.Find(IntermediateNode)) + if (const TWeakObjectPtr* IntermediateTunnelInstanceNode = IntermediateTunnelNodeToTunnelInstanceMap.Find(IntermediateNode)) { Result = *IntermediateTunnelInstanceNode; } diff --git a/Engine/Source/Editor/UnrealEd/Private/Kismet2/ComponentEditorUtils.cpp b/Engine/Source/Editor/UnrealEd/Private/Kismet2/ComponentEditorUtils.cpp index d09ccb51d3ea..278e645b7b8f 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Kismet2/ComponentEditorUtils.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Kismet2/ComponentEditorUtils.cpp @@ -334,7 +334,6 @@ bool FComponentEditorUtils::CanCopyComponents(const TArray& Co void FComponentEditorUtils::CopyComponents(const TArray& ComponentsToCopy) { FStringOutputDevice Archive; - const FExportObjectInnerContext Context; // Clear the mark state for saving. UnMarkAllObjects(EObjectMark(OBJECTMARK_TagExp | OBJECTMARK_TagImp)); @@ -345,7 +344,7 @@ void FComponentEditorUtils::CopyComponents(const TArray& Compo for (UActorComponent* Component : ComponentsToCopy) { // Duplicate the component into a temporary object - UObject* DuplicatedComponent = StaticDuplicateObject(Component, GetTransientPackage(), Component->GetFName(), RF_AllFlags & ~RF_ArchetypeObject); + UObject* DuplicatedComponent = StaticDuplicateObject(Component, GetTransientPackage(), Component->GetFName()); if (DuplicatedComponent) { // If the duplicated component is a scene component, wipe its attach parent (to prevent log warnings for referencing a private object in an external package) @@ -367,6 +366,8 @@ void FComponentEditorUtils::CopyComponents(const TArray& Compo } } + const FExportObjectInnerContext Context; + // Export the component object(s) to text for copying for (auto ObjectIt = ObjectMap.CreateIterator(); ObjectIt; ++ObjectIt) { @@ -626,7 +627,7 @@ UActorComponent* FComponentEditorUtils::DuplicateComponent(UActorComponent* Temp USceneComponent* RootComponent = Actor->GetRootComponent(); check(RootComponent); - // ComponentToWorld is not a UPROPERTY, so make sure the clone has calculated it properly before attachment + // GetComponentTransform() is not a UPROPERTY, so make sure the clone has calculated it properly before attachment NewSceneComponent->UpdateComponentToWorld(); NewSceneComponent->SetupAttachment(RootComponent); diff --git a/Engine/Source/Editor/UnrealEd/Private/Kismet2/DebuggerCommands.cpp b/Engine/Source/Editor/UnrealEd/Private/Kismet2/DebuggerCommands.cpp index 32760e242e22..4c3b899dcfdf 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Kismet2/DebuggerCommands.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Kismet2/DebuggerCommands.cpp @@ -1196,7 +1196,7 @@ void FInternalPlayWorldCommandCallbacks::Simulate_Clicked() bool FInternalPlayWorldCommandCallbacks::Simulate_CanExecute() { // Can't simulate while already simulating; PIE is fine as we toggle to simulate - return !(HasPlayWorld() && GUnrealEd->bIsSimulatingInEditor); + return !(HasPlayWorld() && GUnrealEd->bIsSimulatingInEditor) && !GEditor->IsLightingBuildCurrentlyRunning(); } @@ -1334,7 +1334,7 @@ void FInternalPlayWorldCommandCallbacks::RepeatLastPlay_Clicked() // Grab the play command and execute it TSharedRef LastCommand = GetLastPlaySessionCommand(); - UE_LOG(LogTemp, Log, TEXT("Repeting last play command: %s"), *LastCommand->GetLabel().ToString()); + UE_LOG(LogTemp, Log, TEXT("Repeating last play command: %s"), *LastCommand->GetLabel().ToString()); FPlayWorldCommands::GlobalPlayWorldActions->ExecuteAction(LastCommand); } @@ -1415,7 +1415,7 @@ void FInternalPlayWorldCommandCallbacks::PlayInViewport_Clicked( ) bool FInternalPlayWorldCommandCallbacks::PlayInViewport_CanExecute() { // Allow PIE if we don't already have a play session or the play session is simulate in editor (which we can toggle to PIE) - return !HasPlayWorld() || GUnrealEd->bIsSimulatingInEditor; + return (!GEditor->bIsPlayWorldQueued && !HasPlayWorld() && !GEditor->IsLightingBuildCurrentlyRunning() ) || GUnrealEd->bIsSimulatingInEditor; } @@ -1465,7 +1465,7 @@ void FInternalPlayWorldCommandCallbacks::PlayInEditorFloating_Clicked( ) bool FInternalPlayWorldCommandCallbacks::PlayInEditorFloating_CanExecute() { - return !HasPlayWorld() || !GUnrealEd->bIsSimulatingInEditor; + return (!HasPlayWorld() || !GUnrealEd->bIsSimulatingInEditor) && !GEditor->IsLightingBuildCurrentlyRunning(); } void FInternalPlayWorldCommandCallbacks::PlayInVR_Clicked() @@ -1515,7 +1515,7 @@ void FInternalPlayWorldCommandCallbacks::PlayInVR_Clicked() bool FInternalPlayWorldCommandCallbacks::PlayInVR_CanExecute() { - return (!HasPlayWorld() || !GUnrealEd->bIsSimulatingInEditor) && GEngine && GEngine->HMDDevice.IsValid(); + return (!HasPlayWorld() || !GUnrealEd->bIsSimulatingInEditor) && !GEditor->IsLightingBuildCurrentlyRunning() && GEngine && GEngine->HMDDevice.IsValid(); } diff --git a/Engine/Source/Editor/UnrealEd/Private/Kismet2/Kismet2.cpp b/Engine/Source/Editor/UnrealEd/Private/Kismet2/Kismet2.cpp index a4e46f72120e..8a3ed74c1bac 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Kismet2/Kismet2.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Kismet2/Kismet2.cpp @@ -2,6 +2,8 @@ #include "CoreMinimal.h" + +#include "BlueprintCompilationManager.h" #include "Misc/CoreMisc.h" #include "Stats/StatsMisc.h" #include "Stats/Stats.h" @@ -89,6 +91,8 @@ DECLARE_CYCLE_STAT(TEXT("Validate Generated Class"), EKismetCompilerStats_Valida #define LOCTEXT_NAMESPACE "UnrealEd.Editor" +extern COREUOBJECT_API bool GBlueprintUseCompilationManager; + ////////////////////////////////////////////////////////////////////////// // FArchiveInvalidateTransientRefs @@ -740,6 +744,12 @@ bool FKismetEditorUtilities::IsReferencedByUndoBuffer(UBlueprint* Blueprint) void FKismetEditorUtilities::CompileBlueprint(UBlueprint* BlueprintObj, EBlueprintCompileOptions CompileFlags, FCompilerResultsLog* pResults) { + if(GBlueprintUseCompilationManager) + { + FBlueprintCompilationManager::CompileSynchronously(FBPCompileRequest(BlueprintObj, CompileFlags, pResults)); + return; + } + const bool bIsRegeneratingOnLoad = (CompileFlags & EBlueprintCompileOptions::IsRegeneratingOnLoad ) != EBlueprintCompileOptions::None; const bool bSkipGarbageCollection = (CompileFlags & EBlueprintCompileOptions::SkipGarbageCollection ) != EBlueprintCompileOptions::None; const bool bSaveIntermediateProducts = (CompileFlags & EBlueprintCompileOptions::SaveIntermediateProducts ) != EBlueprintCompileOptions::None; @@ -997,6 +1007,12 @@ bool FKismetEditorUtilities::GenerateBlueprintSkeleton(UBlueprint* BlueprintObj, void FKismetEditorUtilities::RecompileBlueprintBytecode(UBlueprint* BlueprintObj, TArray* ObjLoaded, EBlueprintBytecodeRecompileOptions Flags) { FSecondsCounterScope Timer(BlueprintCompileAndLoadTimerData); + + if(FBlueprintEditorUtils::IsCompileOnLoadDisabled(BlueprintObj)) + { + return; + } + bool bBatchCompile = (Flags & EBlueprintBytecodeRecompileOptions::BatchCompile) != EBlueprintBytecodeRecompileOptions::None; bool bSkipReinstancing = (Flags & EBlueprintBytecodeRecompileOptions::SkipReinstancing) != EBlueprintBytecodeRecompileOptions::None; @@ -2144,7 +2160,7 @@ bool FKismetEditorUtilities::CanBlueprintImplementInterface(UBlueprint const* Bl bool bCanImplementInterface = false; // if the class is an actual implementable interface - if (IsClassABlueprintInterface(Class) && !Class->GetCppTypeInfo()->IsAbstract() && !Class->HasMetaData(FBlueprintMetadata::MD_CannotImplementInterfaceInBlueprint)) + if (IsClassABlueprintInterface(Class) && !Class->HasMetaData(FBlueprintMetadata::MD_CannotImplementInterfaceInBlueprint)) { bCanImplementInterface = true; diff --git a/Engine/Source/Editor/UnrealEd/Private/Kismet2/KismetReinstanceUtilities.cpp b/Engine/Source/Editor/UnrealEd/Private/Kismet2/KismetReinstanceUtilities.cpp index f2581e6258d2..b4653cbe7f7f 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Kismet2/KismetReinstanceUtilities.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Kismet2/KismetReinstanceUtilities.cpp @@ -107,7 +107,7 @@ struct FReplaceReferenceHelper class ReferenceReplace : public FArchiveReplaceObjectRef < UObject > { public: - ReferenceReplace(UObject* InSearchObject, const TMap& InReplacementMap, TMap InWeakReferencesMap) + ReferenceReplace(UObject* InSearchObject, const TMap& InReplacementMap, const TMap& InWeakReferencesMap) : FArchiveReplaceObjectRef(InSearchObject, InReplacementMap, false, false, false, true), WeakReferencesMap(InWeakReferencesMap) { SerializeSearchObject(); @@ -247,51 +247,8 @@ FBlueprintCompileReinstancer::FBlueprintCompileReinstancer(UClass* InClassToRein // Remember the initial CDO for the class being resinstanced OriginalCDO = ClassToReinstance->GetDefaultObject(); - // Duplicate the class we're reinstancing into the transient package. We'll re-class all objects we find to point to this new class - GIsDuplicatingClassForReinstancing = true; - ClassToReinstance->ClassFlags |= CLASS_NewerVersionExists; + DuplicatedClass = MoveCDOToNewClass(ClassToReinstance, TMap(), bAvoidCDODuplication); - if(bAvoidCDODuplication) - { - // clear the CDO so that we don't duplicate it, it's stored in OriginalCDO now - ClassToReinstance->ClassDefaultObject = nullptr; - } - - const FName ReinstanceName = MakeUniqueObjectName(GetTransientPackage(), ClassToReinstance->GetClass(), *(FString(TEXT("REINST_")) + *ClassToReinstance->GetName())); - DuplicatedClass = (UClass*)StaticDuplicateObject(ClassToReinstance, GetTransientPackage(), ReinstanceName, ~RF_Transactional); - // If you compile a blueprint that is part of the rootset, there's no reason for the REINST version to be part of the rootset: - DuplicatedClass->RemoveFromRoot(); - - ClassToReinstance->ClassFlags &= ~CLASS_NewerVersionExists; - GIsDuplicatingClassForReinstancing = false; - - UBlueprintGeneratedClass* BPClassToReinstance = Cast(ClassToReinstance); - UBlueprintGeneratedClass* BPGDuplicatedClass = Cast(DuplicatedClass); - if (BPGDuplicatedClass && BPClassToReinstance && BPClassToReinstance->OverridenArchetypeForCDO) - { - BPGDuplicatedClass->OverridenArchetypeForCDO = BPClassToReinstance->OverridenArchetypeForCDO; - } - - UFunction* DuplicatedClassUberGraphFunction = BPGDuplicatedClass ? BPGDuplicatedClass->UberGraphFunction : nullptr; - if (DuplicatedClassUberGraphFunction) - { - DuplicatedClassUberGraphFunction->Bind(); - DuplicatedClassUberGraphFunction->StaticLink(true); - } - - // Bind and link the duplicate class, so that it has the proper duplicate property offsets - DuplicatedClass->Bind(); - DuplicatedClass->StaticLink(true); - - if(bAvoidCDODuplication) - { - // give the OriginalCDO to the DuplicatedClass: - OriginalCDO->Rename(*OriginalCDO->GetName(), DuplicatedClass, REN_DoNotDirty | REN_DontCreateRedirectors | REN_ForceNoResetLoaders); - DuplicatedClass->ClassDefaultObject = OriginalCDO; - } - - DuplicatedClass->ClassDefaultObject->SetClass(DuplicatedClass); - if(!bAvoidCDODuplication) { ensure( ClassToReinstance->ClassDefaultObject->GetClass() == DuplicatedClass ); @@ -533,7 +490,7 @@ public: Actor->ReregisterAllComponents(); Actor->RerunConstructionScripts(); - if (SelectedObjecs.Contains(Obj)) + if (SelectedObjecs.Contains(Obj) && GEditor) { GEditor->SelectActor(Actor, /*bInSelected =*/true, /*bNotify =*/true, false, true); } @@ -1170,7 +1127,7 @@ struct FActorReplacementHelper } // Save off transform - TargetWorldTransform = OldRootComponent->ComponentToWorld; + TargetWorldTransform = OldRootComponent->GetComponentTransform(); TargetWorldTransform.SetTranslation(OldRootComponent->GetComponentLocation()); // take into account any custom location } @@ -1259,7 +1216,7 @@ void FActorReplacementHelper::Finalize(const TMap& OldToNewI NewActor->MarkComponentsRenderStateDirty(); } - if (bSelectNewActor) + if (bSelectNewActor && GEditor) { GEditor->SelectActor(NewActor, /*bInSelected =*/true, /*bNotify =*/true); } @@ -1275,7 +1232,10 @@ void FActorReplacementHelper::Finalize(const TMap& OldToNewI } } } - GEditor->NotifyToolsOfObjectReplacement(ConstructedComponentReplacementMap); + if (GEditor) + { + GEditor->NotifyToolsOfObjectReplacement(ConstructedComponentReplacementMap); + } // Make array of component subobjects that have been reinstanced as part of the new Actor. TArray SourceObjects; @@ -1287,7 +1247,7 @@ void FActorReplacementHelper::Finalize(const TMap& OldToNewI // Destroy actor and clear references. NewActor->Modify(); - if (GEditor->Layers.IsValid()) + if (GEditor && GEditor->Layers.IsValid()) { GEditor->Layers->InitializeNewActorLayers(NewActor); } @@ -1516,6 +1476,58 @@ void FBlueprintCompileReinstancer::BatchReplaceInstancesOfClass(TMap& OldToNewMap, bool bAvoidCDODuplication) +{ + GIsDuplicatingClassForReinstancing = true; + OwnerClass->ClassFlags |= CLASS_NewerVersionExists; + + UObject* OldCDO = OwnerClass->ClassDefaultObject; + if(bAvoidCDODuplication) + { + // prevent duplication of CDO by hiding it from StaticDuplicateObject + OwnerClass->ClassDefaultObject = nullptr; + } + const FName ReinstanceName = MakeUniqueObjectName(GetTransientPackage(), OwnerClass->GetClass(), *(FString(TEXT("REINST_")) + *OwnerClass->GetName())); + UClass* CopyOfOwnerClass = CastChecked(StaticDuplicateObject(OwnerClass, GetTransientPackage(), ReinstanceName, ~RF_Transactional)); + + CopyOfOwnerClass->RemoveFromRoot(); + OwnerClass->ClassFlags &= ~CLASS_NewerVersionExists; + GIsDuplicatingClassForReinstancing = false; + + UClass * const* OverridenParent = OldToNewMap.Find(CopyOfOwnerClass->GetSuperClass()); + if(OverridenParent && *OverridenParent) + { + CopyOfOwnerClass->SetSuperStruct(*OverridenParent); + } + + UBlueprintGeneratedClass* BPClassToReinstance = Cast(OwnerClass); + UBlueprintGeneratedClass* BPGDuplicatedClass = Cast(CopyOfOwnerClass); + if (BPGDuplicatedClass && BPClassToReinstance && BPClassToReinstance->OverridenArchetypeForCDO) + { + BPGDuplicatedClass->OverridenArchetypeForCDO = BPClassToReinstance->OverridenArchetypeForCDO; + } + + UFunction* DuplicatedClassUberGraphFunction = BPGDuplicatedClass ? BPGDuplicatedClass->UberGraphFunction : nullptr; + if (DuplicatedClassUberGraphFunction) + { + DuplicatedClassUberGraphFunction->Bind(); + DuplicatedClassUberGraphFunction->StaticLink(true); + } + + CopyOfOwnerClass->Bind(); + CopyOfOwnerClass->StaticLink(true); + if(OldCDO) + { + if(bAvoidCDODuplication) + { + OldCDO->Rename(*OldCDO->GetName(), CopyOfOwnerClass, REN_DoNotDirty | REN_DontCreateRedirectors | REN_ForceNoResetLoaders); + CopyOfOwnerClass->ClassDefaultObject = OldCDO; + } + OldCDO->SetClass(CopyOfOwnerClass); + } + return CopyOfOwnerClass; +} + void FBlueprintCompileReinstancer::ReplaceInstancesOfClass_Inner(TMap& InOldToNewClassMap, UObject* InOriginalCDO, TSet* ObjectsThatShouldUseOldStuff, bool bClassObjectReplaced, bool bPreserveRootComponent) { // If there is an original CDO, we are only reinstancing a single class @@ -1655,16 +1667,16 @@ void FBlueprintCompileReinstancer::ReplaceInstancesOfClass_Inner(TMapGetRootComponent()) { - // We need to make sure that the ComponentToWorld transform is up to date, but we don't want to run any initialization logic + // We need to make sure that the GetComponentTransform() transform is up to date, but we don't want to run any initialization logic // so we silence the update, cache it off, revert the change (so no events are raised), and then directly update the transform // with the value calculated in ConditionalUpdateComponentToWorld: FScopedMovementUpdate SilenceMovement(OldRootComponent); OldRootComponent->ConditionalUpdateComponentToWorld(); - FTransform OldComponentToWorld = OldRootComponent->ComponentToWorld; + FTransform OldComponentToWorld = OldRootComponent->GetComponentTransform(); SilenceMovement.RevertMove(); - OldRootComponent->ComponentToWorld = OldComponentToWorld; + OldRootComponent->SetComponentToWorld(OldComponentToWorld); Location = OldActor->GetActorLocation(); Rotation = OldActor->GetActorRotation(); } @@ -1736,10 +1748,13 @@ void FBlueprintCompileReinstancer::ReplaceInstancesOfClass_Inner(TMapIsSelected()) { - GEditor->SelectActor(OldActor, /*bInSelected =*/false, /*bNotify =*/false); + if(GEditor) + { + GEditor->SelectActor(OldActor, /*bInSelected =*/false, /*bNotify =*/false); + } bSelectionChanged = true; } - if (GEditor->Layers.IsValid()) + if (GEditor && GEditor->Layers.IsValid()) { GEditor->Layers->DisassociateActorFromLayers(OldActor); } diff --git a/Engine/Source/Editor/UnrealEd/Private/Kismet2/StructureEditorUtils.cpp b/Engine/Source/Editor/UnrealEd/Private/Kismet2/StructureEditorUtils.cpp index 84629ae02494..dec60089377e 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Kismet2/StructureEditorUtils.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Kismet2/StructureEditorUtils.cpp @@ -49,7 +49,7 @@ UUserDefinedStruct* FStructureEditorUtils::CreateUserDefinedStruct(UObject* InPa { const UEdGraphSchema_K2* K2Schema = GetDefault(); - AddVariable(Struct, FEdGraphPinType(K2Schema->PC_Boolean, FString(), NULL, false, false, false, false, FEdGraphTerminalType())); + AddVariable(Struct, FEdGraphPinType(K2Schema->PC_Boolean, FString(), nullptr, EPinContainerType::None, false, FEdGraphTerminalType())); } } @@ -209,7 +209,7 @@ bool FStructureEditorUtils::CanHaveAMemberVariableOfType(const UUserDefinedStruc } else { - const auto PinSubCategoryClass = Cast(VarType.PinSubCategoryObject.Get()); + const UClass* PinSubCategoryClass = Cast(VarType.PinSubCategoryObject.Get()); if (PinSubCategoryClass && PinSubCategoryClass->IsChildOf(UBlueprint::StaticClass())) { if (OutMsg) @@ -317,7 +317,7 @@ bool FStructureEditorUtils::RemoveVariable(UUserDefinedStruct* Struct, FGuid Var { if(Struct) { - const auto OldNum = GetVarDesc(Struct).Num(); + const int32 OldNum = GetVarDesc(Struct).Num(); const bool bAllowToMakeEmpty = false; if (bAllowToMakeEmpty || (OldNum > 1)) { @@ -343,7 +343,7 @@ bool FStructureEditorUtils::RenameVariable(UUserDefinedStruct* Struct, FGuid Var { if (Struct) { - auto VarDesc = GetVarDescByGuid(Struct, VarGuid); + FStructVariableDescription* VarDesc = GetVarDescByGuid(Struct, VarGuid); if (VarDesc && !NewDisplayNameStr.IsEmpty() && IsUniqueVariableDisplayName(Struct, NewDisplayNameStr)) @@ -379,7 +379,7 @@ bool FStructureEditorUtils::ChangeVariableType(UUserDefinedStruct* Struct, FGuid return false; } - auto VarDesc = GetVarDescByGuid(Struct, VarGuid); + FStructVariableDescription* VarDesc = GetVarDescByGuid(Struct, VarGuid); if(VarDesc) { const bool bChangedType = (VarDesc->ToPinType() != NewType); @@ -429,7 +429,7 @@ bool FStructureEditorUtils::ChangeVariableDefaultValue(UUserDefinedStruct* Struc return bResult; }; - auto VarDesc = GetVarDescByGuid(Struct, VarGuid); + FStructVariableDescription* VarDesc = GetVarDescByGuid(Struct, VarGuid); if (VarDesc && (NewDefaultValue != VarDesc->DefaultValue) && ValidateDefaultValue(*VarDesc, NewDefaultValue)) @@ -437,7 +437,7 @@ bool FStructureEditorUtils::ChangeVariableDefaultValue(UUserDefinedStruct* Struc bool bAdvancedValidation = true; if (!NewDefaultValue.IsEmpty()) { - const auto Property = FindField(Struct, VarDesc->VarName); + const UProperty* Property = FindField(Struct, VarDesc->VarName); FStructOnScope StructDefaultMem(Struct); bAdvancedValidation = StructDefaultMem.IsValid() && Property && FBlueprintEditorUtils::PropertyValueFromString(Property, NewDefaultValue, StructDefaultMem.GetStructMemory()); @@ -463,7 +463,7 @@ bool FStructureEditorUtils::IsUniqueVariableDisplayName(const UUserDefinedStruct { if(Struct) { - for (auto& VarDesc : GetVarDesc(Struct)) + for (const FStructVariableDescription& VarDesc : GetVarDesc(Struct)) { if (VarDesc.FriendlyName == DisplayName) { @@ -477,7 +477,7 @@ bool FStructureEditorUtils::IsUniqueVariableDisplayName(const UUserDefinedStruct FString FStructureEditorUtils::GetVariableDisplayName(const UUserDefinedStruct* Struct, FGuid VarGuid) { - const auto VarDesc = GetVarDescByGuid(Struct, VarGuid); + const FStructVariableDescription* VarDesc = GetVarDescByGuid(Struct, VarGuid); return VarDesc ? VarDesc->FriendlyName : FString(); } @@ -489,7 +489,7 @@ bool FStructureEditorUtils::UserDefinedStructEnabled() void FStructureEditorUtils::RecreateDefaultInstanceInEditorData(UUserDefinedStruct* Struct) { - auto StructEditorData = Struct ? CastChecked(Struct->EditorData) : nullptr; + UUserDefinedStructEditorData* StructEditorData = Struct ? CastChecked(Struct->EditorData) : nullptr; if (StructEditorData) { StructEditorData->RecreateDefaultInstance(); @@ -501,7 +501,7 @@ bool FStructureEditorUtils::Fill_MakeStructureDefaultValue(const UUserDefinedStr bool bResult = true; if (Struct && StructData) { - auto StructEditorData = CastChecked(Struct->EditorData); + UUserDefinedStructEditorData* StructEditorData = CastChecked(Struct->EditorData); const uint8* DefaultInstance = StructEditorData->GetDefaultInstance(); if (DefaultInstance) { @@ -611,7 +611,7 @@ void FStructureEditorUtils::RemoveInvalidStructureMemberVariableFromBlueprint(UB if (ZombieMemberNames.Num()) { - auto Response = FMessageDialog::Open( + EAppReturnType::Type Response = FMessageDialog::Open( EAppMsgType::OkCancel, FText::Format( LOCTEXT("RemoveInvalidStructureMemberVariable_Msg", "The following member variables in blueprint '{0}' have invalid type. Would you like to remove them? \n\n{1}"), @@ -624,9 +624,8 @@ void FStructureEditorUtils::RemoveInvalidStructureMemberVariableFromBlueprint(UB { Blueprint->Modify(); - for (auto NameIter = ZombieMemberNames.CreateConstIterator(); NameIter; ++NameIter) + for (const FName Name : ZombieMemberNames) { - const FName Name = *NameIter; Blueprint->NewVariables.RemoveAll(FFindByNameHelper(Name)); //TODO: Add RemoveFirst to TArray FBlueprintEditorUtils::RemoveVariableNodes(Blueprint, Name); } @@ -661,13 +660,13 @@ const TArray* FStructureEditorUtils::GetVarDescPtr(c FString FStructureEditorUtils::GetTooltip(const UUserDefinedStruct* Struct) { - const auto StructEditorData = Struct ? Cast(Struct->EditorData) : NULL; + const UUserDefinedStructEditorData* StructEditorData = Struct ? Cast(Struct->EditorData) : NULL; return StructEditorData ? StructEditorData->ToolTip : FString(); } bool FStructureEditorUtils::ChangeTooltip(UUserDefinedStruct* Struct, const FString& InTooltip) { - auto StructEditorData = Struct ? Cast(Struct->EditorData) : NULL; + UUserDefinedStructEditorData* StructEditorData = Struct ? Cast(Struct->EditorData) : NULL; if (StructEditorData && (InTooltip != StructEditorData->ToolTip)) { const FScopedTransaction Transaction(LOCTEXT("ChangeTooltip", "Change UDS Tooltip")); @@ -683,20 +682,20 @@ bool FStructureEditorUtils::ChangeTooltip(UUserDefinedStruct* Struct, const FStr FString FStructureEditorUtils::GetVariableTooltip(const UUserDefinedStruct* Struct, FGuid VarGuid) { - const auto VarDesc = GetVarDescByGuid(Struct, VarGuid); + const FStructVariableDescription* VarDesc = GetVarDescByGuid(Struct, VarGuid); return VarDesc ? VarDesc->ToolTip : FString(); } bool FStructureEditorUtils::ChangeVariableTooltip(UUserDefinedStruct* Struct, FGuid VarGuid, const FString& InTooltip) { - auto VarDesc = GetVarDescByGuid(Struct, VarGuid); + FStructVariableDescription* VarDesc = GetVarDescByGuid(Struct, VarGuid); if (VarDesc && (InTooltip != VarDesc->ToolTip)) { const FScopedTransaction Transaction(LOCTEXT("ChangeVariableTooltip", "Change UDS Variable Tooltip")); ModifyStructData(Struct); VarDesc->ToolTip = InTooltip; - auto Property = FindField(Struct, VarDesc->VarName); + UProperty* Property = FindField(Struct, VarDesc->VarName); if (Property) { Property->SetMetaData(FBlueprintMetadata::MD_Tooltip, *VarDesc->ToolTip); @@ -710,7 +709,7 @@ bool FStructureEditorUtils::ChangeVariableTooltip(UUserDefinedStruct* Struct, FG bool FStructureEditorUtils::ChangeEditableOnBPInstance(UUserDefinedStruct* Struct, FGuid VarGuid, bool bInIsEditable) { const UEdGraphSchema_K2* K2Schema = GetDefault(); - auto VarDesc = GetVarDescByGuid(Struct, VarGuid); + FStructVariableDescription* VarDesc = GetVarDescByGuid(Struct, VarGuid); const bool bNewDontEditoOnInstance = !bInIsEditable; if (VarDesc && (bNewDontEditoOnInstance != VarDesc->bDontEditoOnInstance)) { @@ -729,7 +728,7 @@ bool FStructureEditorUtils::MoveVariable(UUserDefinedStruct* Struct, FGuid VarGu if (Struct) { const bool bMoveUp = (EMoveDirection::MD_Up == MoveDirection); - auto& DescArray = GetVarDesc(Struct); + TArray& DescArray = GetVarDesc(Struct); const int32 InitialIndex = bMoveUp ? 1 : 0; const int32 IndexLimit = DescArray.Num() - (bMoveUp ? 0 : 1); for (int32 Index = InitialIndex; Index < IndexLimit; ++Index) @@ -760,7 +759,7 @@ void FStructureEditorUtils::ModifyStructData(UUserDefinedStruct* Struct) bool FStructureEditorUtils::CanEnableMultiLineText(const UUserDefinedStruct* Struct, FGuid VarGuid) { - auto VarDesc = GetVarDescByGuid(Struct, VarGuid); + const FStructVariableDescription* VarDesc = GetVarDescByGuid(Struct, VarGuid); if (VarDesc) { UProperty* Property = FindField(Struct, VarDesc->VarName); @@ -783,14 +782,14 @@ bool FStructureEditorUtils::CanEnableMultiLineText(const UUserDefinedStruct* Str bool FStructureEditorUtils::ChangeMultiLineTextEnabled(UUserDefinedStruct* Struct, FGuid VarGuid, bool bIsEnabled) { - auto VarDesc = GetVarDescByGuid(Struct, VarGuid); + FStructVariableDescription* VarDesc = GetVarDescByGuid(Struct, VarGuid); if (CanEnableMultiLineText(Struct, VarGuid) && VarDesc->bEnableMultiLineText != bIsEnabled) { const FScopedTransaction Transaction(LOCTEXT("ChangeMultiLineTextEnabled", "Change Multi-line Text Enabled")); ModifyStructData(Struct); VarDesc->bEnableMultiLineText = bIsEnabled; - auto Property = FindField(Struct, VarDesc->VarName); + UProperty* Property = FindField(Struct, VarDesc->VarName); if (Property) { if (VarDesc->bEnableMultiLineText) @@ -810,7 +809,7 @@ bool FStructureEditorUtils::ChangeMultiLineTextEnabled(UUserDefinedStruct* Struc bool FStructureEditorUtils::IsMultiLineTextEnabled(const UUserDefinedStruct* Struct, FGuid VarGuid) { - auto VarDesc = GetVarDescByGuid(Struct, VarGuid); + const FStructVariableDescription* VarDesc = GetVarDescByGuid(Struct, VarGuid); if (CanEnableMultiLineText(Struct, VarGuid)) { return VarDesc->bEnableMultiLineText; @@ -820,8 +819,8 @@ bool FStructureEditorUtils::IsMultiLineTextEnabled(const UUserDefinedStruct* Str bool FStructureEditorUtils::CanEnable3dWidget(const UUserDefinedStruct* Struct, FGuid VarGuid) { - const auto VarDesc = GetVarDescByGuid(Struct, VarGuid); - const auto PropertyStruct = VarDesc ? Cast(VarDesc->SubCategoryObject.Get()) : NULL; + const FStructVariableDescription* VarDesc = GetVarDescByGuid(Struct, VarGuid); + const UStruct* PropertyStruct = VarDesc ? Cast(VarDesc->SubCategoryObject.Get()) : NULL; return FEdMode::CanCreateWidgetForStructure(PropertyStruct); } @@ -859,22 +858,22 @@ bool FStructureEditorUtils::Change3dWidgetEnabled(UUserDefinedStruct* Struct, FG bool FStructureEditorUtils::Is3dWidgetEnabled(const UUserDefinedStruct* Struct, FGuid VarGuid) { - const auto VarDesc = GetVarDescByGuid(Struct, VarGuid); - const auto PropertyStruct = VarDesc ? Cast(VarDesc->SubCategoryObject.Get()) : NULL; + const FStructVariableDescription* VarDesc = GetVarDescByGuid(Struct, VarGuid); + const UStruct* PropertyStruct = VarDesc ? Cast(VarDesc->SubCategoryObject.Get()) : nullptr; return VarDesc && VarDesc->bEnable3dWidget && FEdMode::CanCreateWidgetForStructure(PropertyStruct); } FGuid FStructureEditorUtils::GetGuidForProperty(const UProperty* Property) { - auto UDStruct = Property ? Cast(Property->GetOwnerStruct()) : NULL; - auto VarDesc = UDStruct ? GetVarDesc(UDStruct).FindByPredicate(FFindByNameHelper(Property->GetFName())) : NULL; + const UUserDefinedStruct* UDStruct = Property ? Cast(Property->GetOwnerStruct()) : nullptr; + const FStructVariableDescription* VarDesc = UDStruct ? GetVarDesc(UDStruct).FindByPredicate(FFindByNameHelper(Property->GetFName())) : nullptr; return VarDesc ? VarDesc->VarGuid : FGuid(); } UProperty* FStructureEditorUtils::GetPropertyByGuid(const UUserDefinedStruct* Struct, const FGuid VarGuid) { - const auto VarDesc = GetVarDescByGuid(Struct, VarGuid); - return VarDesc ? FindField(Struct, VarDesc->VarName) : NULL; + const FStructVariableDescription* VarDesc = GetVarDescByGuid(Struct, VarGuid); + return VarDesc ? FindField(Struct, VarDesc->VarName) : nullptr; } FGuid FStructureEditorUtils::GetGuidFromPropertyName(const FName Name) @@ -892,9 +891,9 @@ struct FReinstanceDataTableHelper { TArray DataTables; GetObjectsOfClass(UDataTable::StaticClass(), DataTables); - for (auto DataTableObj : DataTables) + for (UObject* DataTableObj : DataTables) { - auto DataTable = Cast(DataTableObj); + UDataTable* DataTable = Cast(DataTableObj); if (DataTable && (Struct == DataTable->RowStruct)) { Result.Add(DataTable); @@ -908,8 +907,8 @@ struct FReinstanceDataTableHelper void FStructureEditorUtils::BroadcastPreChange(UUserDefinedStruct* Struct) { FStructureEditorUtils::FStructEditorManager::Get().PreChange(Struct, FStructureEditorUtils::FStructEditorManager::ActiveChange); - auto DataTables = FReinstanceDataTableHelper::GetTablesDependentOnStruct(Struct); - for (auto DataTable : DataTables) + TArray DataTables = FReinstanceDataTableHelper::GetTablesDependentOnStruct(Struct); + for (UDataTable* DataTable : DataTables) { DataTable->CleanBeforeStructChange(); } @@ -917,8 +916,8 @@ void FStructureEditorUtils::BroadcastPreChange(UUserDefinedStruct* Struct) void FStructureEditorUtils::BroadcastPostChange(UUserDefinedStruct* Struct) { - auto DataTables = FReinstanceDataTableHelper::GetTablesDependentOnStruct(Struct); - for (auto DataTable : DataTables) + TArray DataTables = FReinstanceDataTableHelper::GetTablesDependentOnStruct(Struct); + for (UDataTable* DataTable : DataTables) { DataTable->RestoreAfterStructChange(); } diff --git a/Engine/Source/Editor/UnrealEd/Private/LevelEditorViewport.cpp b/Engine/Source/Editor/UnrealEd/Private/LevelEditorViewport.cpp index 8152b36a3d86..c59705554007 100644 --- a/Engine/Source/Editor/UnrealEd/Private/LevelEditorViewport.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/LevelEditorViewport.cpp @@ -72,6 +72,7 @@ #include "IContentBrowserSingleton.h" #include "ContentStreaming.h" #include "IHeadMountedDisplay.h" +#include "ActorGroupingUtils.h" DEFINE_LOG_CATEGORY(LogEditorViewport); @@ -120,6 +121,10 @@ FViewportCursorLocation::FViewportCursorLocation( const FSceneView* View, FEdito } } +FViewportCursorLocation::~FViewportCursorLocation() +{ +} + ELevelViewportType FViewportCursorLocation::GetViewportType() const { return ViewportClient->GetViewportType(); @@ -139,6 +144,10 @@ FViewportClick::FViewportClick(const FSceneView* View,FEditorViewportClient* Vie AltDown = ViewportClient->IsAltPressed(); } +FViewportClick::~FViewportClick() +{ +} + /** Helper function to compute a new location that is snapped to the origin plane given the users cursor location and camera angle */ static FVector4 AttemptToSnapLocationToOriginPlane( const FViewportCursorLocation& Cursor, FVector4 Location ) { @@ -598,12 +607,7 @@ static bool AttemptApplyObjToComponent(UObject* ObjToUse, USceneComponent* Compo UAnimSequenceBase* DroppedObjAsAnimSequence = Cast(ObjToUse); if (DroppedObjAsAnimSequence) { - USkeleton* AnimSkeleton = nullptr; - - if (DroppedObjAsAnimSequence) - { - AnimSkeleton = DroppedObjAsAnimSequence->GetSkeleton(); - } + USkeleton* AnimSkeleton = DroppedObjAsAnimSequence->GetSkeleton(); if (AnimSkeleton) { @@ -624,16 +628,13 @@ static bool AttemptApplyObjToComponent(UObject* ObjToUse, USceneComponent* Compo SkeletalMeshComponent->SetSkeletalMesh(AnimSkeleton->GetAssetPreviewMesh(DroppedObjAsAnimSequence)); } - if (DroppedObjAsAnimSequence) - { - SkeletalMeshComponent->SetAnimationMode(EAnimationMode::Type::AnimationSingleNode); - SkeletalMeshComponent->AnimationData.AnimToPlay = DroppedObjAsAnimSequence; + SkeletalMeshComponent->SetAnimationMode(EAnimationMode::Type::AnimationSingleNode); + SkeletalMeshComponent->AnimationData.AnimToPlay = DroppedObjAsAnimSequence; - // set runtime data - SkeletalMeshComponent->SetAnimation(DroppedObjAsAnimSequence); - } + // set runtime data + SkeletalMeshComponent->SetAnimation(DroppedObjAsAnimSequence); - if (SkeletalMeshComponent && SkeletalMeshComponent->SkeletalMesh) + if (SkeletalMeshComponent->SkeletalMesh) { bResult = true; SkeletalMeshComponent->InitAnim(true); @@ -1456,7 +1457,7 @@ void FTrackingTransaction::Begin(const FText& Description) Actor->Modify(); - if (GEditor->bGroupingActive) + if (UActorGroupingUtils::IsGroupingActive()) { // if this actor is in a group, add the GroupActor into a list to be modified shortly AGroupActor* ActorLockedRootGroup = AGroupActor::GetRootForActor(Actor, true); @@ -1875,7 +1876,6 @@ void FLevelEditorViewportClient::ReceivedFocus(FViewport* InViewport) // void FLevelEditorViewportClient::ProcessClick(FSceneView& View, HHitProxy* HitProxy, FKey Key, EInputEvent Event, uint32 HitX, uint32 HitY) { - static FName ProcessClickTrace = FName(TEXT("ProcessClickTrace")); const FViewportClick Click(&View,this,Key,Event,HitX,HitY); if (Click.GetKey() == EKeys::MiddleMouseButton && !Click.IsAltDown() && !Click.IsShiftDown()) @@ -1986,7 +1986,7 @@ void FLevelEditorViewportClient::ProcessClick(FSceneView& View, HHitProxy* HitPr if( GeomHitProxy->GetGeomObject() ) { FHitResult CheckResult(ForceInit); - FCollisionQueryParams BoxParams(ProcessClickTrace, false, GeomHitProxy->GetGeomObject()->ActualBrush); + FCollisionQueryParams BoxParams(SCENE_QUERY_STAT(ProcessClickTrace), false, GeomHitProxy->GetGeomObject()->ActualBrush); bool bHit = GWorld->SweepSingleByObjectType(CheckResult, Click.GetOrigin(), Click.GetOrigin() + Click.GetDirection() * HALF_WORLD_MAX, FQuat::Identity, FCollisionObjectQueryParams(ECC_WorldStatic), FCollisionShape::MakeBox(FVector(1.f)), BoxParams); if(bHit) @@ -2080,10 +2080,10 @@ void FLevelEditorViewportClient::Tick(float DeltaTime) GPerspViewMatrix = View->ViewMatrices.GetViewMatrix(); } - UpdateViewForLockedActor(); + UpdateViewForLockedActor(DeltaTime); } -void FLevelEditorViewportClient::UpdateViewForLockedActor() +void FLevelEditorViewportClient::UpdateViewForLockedActor(float DeltaTime) { // We can't be locked to a matinee actor if this viewport doesn't allow matinee control if ( !bAllowCinematicPreview && ActorLockedByMatinee.IsValid() ) @@ -2093,6 +2093,8 @@ void FLevelEditorViewportClient::UpdateViewForLockedActor() bUseControllingActorViewInfo = false; ControllingActorViewInfo = FMinimalViewInfo(); + ControllingActorExtraPostProcessBlends.Empty(); + ControllingActorExtraPostProcessBlendWeights.Empty(); AActor* Actor = ActorLockedByMatinee.IsValid() ? ActorLockedByMatinee.Get() : ActorLockedToCamera.Get(); if( Actor != NULL ) @@ -2119,18 +2121,23 @@ void FLevelEditorViewportClient::UpdateViewForLockedActor() if (bLockedCameraView) { // If this is a camera actor, then inherit some other settings - UCameraComponent* const CameraComponent = GetCameraComponentForLockedActor(Actor); - if (CameraComponent != nullptr) + USceneComponent* const ViewComponent = FindViewComponentForActor(Actor); + if (ViewComponent != nullptr) { - bUseControllingActorViewInfo = true; - CameraComponent->GetCameraView(0.0f, ControllingActorViewInfo); - CameraComponent->GetExtraPostProcessBlends(ControllingActorExtraPostProcessBlends, ControllingActorExtraPostProcessBlendWeights); - - // Post processing is handled by OverridePostProcessingSettings - ViewFOV = ControllingActorViewInfo.FOV; - AspectRatio = ControllingActorViewInfo.AspectRatio; - SetViewLocation(ControllingActorViewInfo.Location); - SetViewRotation(ControllingActorViewInfo.Rotation); + if ( ensure(ViewComponent->GetEditorPreviewInfo(DeltaTime, ControllingActorViewInfo)) ) + { + bUseControllingActorViewInfo = true; + if (UCameraComponent* CameraComponent = Cast(ViewComponent)) + { + CameraComponent->GetExtraPostProcessBlends(ControllingActorExtraPostProcessBlends, ControllingActorExtraPostProcessBlendWeights); + } + + // Post processing is handled by OverridePostProcessingSettings + ViewFOV = ControllingActorViewInfo.FOV; + AspectRatio = ControllingActorViewInfo.AspectRatio; + SetViewLocation(ControllingActorViewInfo.Location); + SetViewRotation(ControllingActorViewInfo.Rotation); + } } } } @@ -3143,6 +3150,67 @@ void FLevelEditorViewportClient::MoveCameraToLockedActor() } } +USceneComponent* FLevelEditorViewportClient::FindViewComponentForActor(AActor const* Actor) +{ + USceneComponent* PreviewComponent = nullptr; + if (Actor) + { + + // see if actor has a component with preview capabilities (prioritize camera components) + TArray SceneComps; + Actor->GetComponents(SceneComps); + + bool bChoseCamComponent = false; + for (USceneComponent* Comp : SceneComps) + { + FMinimalViewInfo DummyViewInfo; + if (Comp->bIsActive && Comp->GetEditorPreviewInfo(/*DeltaTime =*/0.0f, DummyViewInfo)) + { + if (Comp->IsSelected()) + { + PreviewComponent = Comp; + break; + } + else if (PreviewComponent) + { + if (bChoseCamComponent) + { + continue; + } + + UCameraComponent* AsCamComp = Cast(Comp); + if (AsCamComp != nullptr) + { + PreviewComponent = AsCamComp; + } + continue; + } + PreviewComponent = Comp; + } + } + + // now see if any actors are attached to us, directly or indirectly, that have an active camera component we might want to use + // we will just return the first one. + // #note: assumption here that attachment cannot be circular + if (PreviewComponent == nullptr) + { + TArray AttachedActors; + Actor->GetAttachedActors(AttachedActors); + for (AActor* AttachedActor : AttachedActors) + { + USceneComponent* const Comp = FindViewComponentForActor(AttachedActor); + if (Comp) + { + PreviewComponent = Comp; + break; + } + } + } + } + + return PreviewComponent; +} + void FLevelEditorViewportClient::SetActorLock(AActor* Actor) { if (ActorLockedToCamera != Actor) @@ -3313,7 +3381,7 @@ void FLevelEditorViewportClient::ApplyDeltaToActors(const FVector& InDrag, else { AGroupActor* ParentGroup = AGroupActor::GetRootForActor(Actor, true, true); - if (ParentGroup && GEditor->bGroupingActive) + if (ParentGroup && UActorGroupingUtils::IsGroupingActive()) { ActorGroups.AddUnique(ParentGroup); } @@ -3533,8 +3601,7 @@ static bool ApplyScalingOptions(const FVector& InOriginalPreDragScale, const boo SnapScaleAfter = false; } - float ScaleRatioMax = 1.0f; - ScaleRatioMax = AbsoluteScaleValue / InOriginalPreDragScale[MaxAxisIndex]; + float ScaleRatioMax = AbsoluteScaleValue / InOriginalPreDragScale[MaxAxisIndex]; for (int Axis = 0; Axis < 3; ++Axis) { if (bActiveAxes[Axis]) @@ -3748,7 +3815,7 @@ void FLevelEditorViewportClient::CheckHoveredHitProxy( HHitProxy* HoveredHitProx // Check to see if the actor under the cursor is part of a group. If so, we will how a hover cue the whole group AGroupActor* GroupActor = AGroupActor::GetRootForActor( ActorUnderCursor, true, false ); - if( GroupActor && GEditor->bGroupingActive) + if(GroupActor && UActorGroupingUtils::IsGroupingActive()) { // Get all the actors in the group and add them to the list of objects to show a hover cue for. TArray ActorsInGroup; diff --git a/Engine/Source/Editor/UnrealEd/Private/Lightmass/Lightmass.cpp b/Engine/Source/Editor/UnrealEd/Private/Lightmass/Lightmass.cpp index ae1c33ab8367..adc4719216c4 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Lightmass/Lightmass.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Lightmass/Lightmass.cpp @@ -943,6 +943,7 @@ void FLightmassExporter::WriteLights( int32 Channel ) Copy( Light, LightData ); LightData.IndirectLightingSaturation = Light->LightmassSettings.IndirectLightingSaturation; LightData.ShadowExponent = Light->LightmassSettings.ShadowExponent; + LightData.ShadowResolutionScale = Light->ShadowResolutionScale; LightData.LightSourceRadius = 0; LightData.LightSourceLength = 0; DirectionalData.LightSourceAngle = Light->LightmassSettings.LightSourceAngle * (float)PI / 180.0f; @@ -960,6 +961,7 @@ void FLightmassExporter::WriteLights( int32 Channel ) Copy( Light, LightData ); LightData.IndirectLightingSaturation = Light->LightmassSettings.IndirectLightingSaturation; LightData.ShadowExponent = Light->LightmassSettings.ShadowExponent; + LightData.ShadowResolutionScale = Light->ShadowResolutionScale; LightData.LightSourceRadius = Light->SourceRadius; LightData.LightSourceLength = Light->SourceLength; PointData.Radius = Light->AttenuationRadius; @@ -979,6 +981,7 @@ void FLightmassExporter::WriteLights( int32 Channel ) Copy( Light, LightData ); LightData.IndirectLightingSaturation = Light->LightmassSettings.IndirectLightingSaturation; LightData.ShadowExponent = Light->LightmassSettings.ShadowExponent; + LightData.ShadowResolutionScale = Light->ShadowResolutionScale; LightData.LightSourceRadius = Light->SourceRadius; LightData.LightSourceLength = Light->SourceLength; PointData.Radius = Light->AttenuationRadius; diff --git a/Engine/Source/Editor/UnrealEd/Private/Lightmass/Lightmass.h b/Engine/Source/Editor/UnrealEd/Private/Lightmass/Lightmass.h index 895c98d40bc4..cfd8532cdd61 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Lightmass/Lightmass.h +++ b/Engine/Source/Editor/UnrealEd/Private/Lightmass/Lightmass.h @@ -109,7 +109,7 @@ public: void AddPortal(const ULightmassPortalComponent* InPortalComponent) { - Portals.Add(InPortalComponent->ComponentToWorld.ToMatrixWithScale()); + Portals.Add(InPortalComponent->GetComponentTransform().ToMatrixWithScale()); } // if provided, InStaticLightingMesh is used to UV unwrap the material into the static lighting textures diff --git a/Engine/Source/Editor/UnrealEd/Private/MaterialGraph.cpp b/Engine/Source/Editor/UnrealEd/Private/MaterialGraph.cpp index e1545bfda876..6c5846b1dd64 100644 --- a/Engine/Source/Editor/UnrealEd/Private/MaterialGraph.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/MaterialGraph.cpp @@ -168,7 +168,8 @@ void UMaterialGraph::LinkGraphNodesFromMaterial() { UEdGraphPin* InputPin = CastChecked(Expression->GraphNode)->GetInputPin(InputIndex); - if ( ExpressionInputs[InputIndex]->Expression) + // InputPin can be null during a PostEditChange when there is a circular dependency between nodes, and nodes have pins that are dynamically created + if (InputPin != nullptr && ExpressionInputs[InputIndex]->Expression) { UMaterialGraphNode* GraphNode = CastChecked(ExpressionInputs[InputIndex]->Expression->GraphNode); InputPin->MakeLinkTo(GraphNode->GetOutputPin(GetValidOutputIndex(ExpressionInputs[InputIndex]))); diff --git a/Engine/Source/Editor/UnrealEd/Private/MaterialGraphNode.cpp b/Engine/Source/Editor/UnrealEd/Private/MaterialGraphNode.cpp index b2a13649c15f..211270583f34 100644 --- a/Engine/Source/Editor/UnrealEd/Private/MaterialGraphNode.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/MaterialGraphNode.cpp @@ -485,7 +485,7 @@ void UMaterialGraphNode::CreateInputPins() FString PinCategory = MaterialExpression->IsInputConnectionRequired(Index) ? Schema->PC_Required : Schema->PC_Optional; FString PinSubCategory = TEXT(""); - UEdGraphPin* NewPin = CreatePin(EGPD_Input, PinCategory, PinSubCategory, NULL, /*bIsArray=*/ false, /*bIsReference=*/ false, InputName); + UEdGraphPin* NewPin = CreatePin(EGPD_Input, PinCategory, PinSubCategory, nullptr, InputName); if (NewPin->PinName.IsEmpty()) { // Makes sure pin has a name for lookup purposes but user will never see it @@ -538,7 +538,7 @@ void UMaterialGraphNode::CreateOutputPins() OutputName = ExpressionOutput.OutputName; } - UEdGraphPin* NewPin = CreatePin(EGPD_Output, PinCategory, PinSubCategory, NULL, /*bIsArray=*/ false, /*bIsReference=*/ false, OutputName); + UEdGraphPin* NewPin = CreatePin(EGPD_Output, PinCategory, PinSubCategory, nullptr, OutputName); if (NewPin->PinName.IsEmpty()) { // Makes sure pin has a name for lookup purposes but user will never see it diff --git a/Engine/Source/Editor/UnrealEd/Private/MaterialGraphNode_Knot.cpp b/Engine/Source/Editor/UnrealEd/Private/MaterialGraphNode_Knot.cpp index 3a8ba9de5f35..8e149624b0da 100644 --- a/Engine/Source/Editor/UnrealEd/Private/MaterialGraphNode_Knot.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/MaterialGraphNode_Knot.cpp @@ -25,10 +25,10 @@ void UMaterialGraphNode_Knot::AllocateDefaultPins() const FString InputPinName(TEXT("InputPin")); const FString OutputPinName(TEXT("OutputPin")); - UEdGraphPin* MyInputPin = CreatePin(EGPD_Input, PC_Wildcard, FString(), nullptr, /*bIsArray=*/ false, /*bIsReference=*/ false, InputPinName); + UEdGraphPin* MyInputPin = CreatePin(EGPD_Input, PC_Wildcard, FString(), nullptr, InputPinName); MyInputPin->bDefaultValueIsIgnored = true; - UEdGraphPin* MyOutputPin = CreatePin(EGPD_Output, PC_Wildcard, FString(), nullptr, /*bIsArray=*/ false, /*bIsReference=*/ false, OutputPinName); + UEdGraphPin* MyOutputPin = CreatePin(EGPD_Output, PC_Wildcard, FString(), nullptr, OutputPinName); } FText UMaterialGraphNode_Knot::GetTooltipText() const diff --git a/Engine/Source/Editor/UnrealEd/Private/MaterialGraphNode_Root.cpp b/Engine/Source/Editor/UnrealEd/Private/MaterialGraphNode_Root.cpp index 50494dd91dda..9a48cab7d480 100644 --- a/Engine/Source/Editor/UnrealEd/Private/MaterialGraphNode_Root.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/MaterialGraphNode_Root.cpp @@ -50,9 +50,9 @@ void UMaterialGraphNode_Root::CreateInputPins() UMaterialGraph* MaterialGraph = CastChecked(GetGraph()); const UMaterialGraphSchema* Schema = CastChecked(GetSchema()); - for (int32 Index = 0; Index < MaterialGraph->MaterialInputs.Num(); ++Index) + for (const FMaterialInputInfo& MaterialInput : MaterialGraph->MaterialInputs) { - UEdGraphPin* InputPin = CreatePin(EGPD_Input, Schema->PC_MaterialInput, FString::Printf(TEXT("%d"), (int32)MaterialGraph->MaterialInputs[Index].GetProperty()), NULL, /*bIsArray=*/ false, /*bIsReference=*/ false, MaterialGraph->MaterialInputs[Index].GetName().ToString()); + UEdGraphPin* InputPin = CreatePin(EGPD_Input, Schema->PC_MaterialInput, FString::Printf(TEXT("%d"), (int32)MaterialInput.GetProperty()), nullptr, MaterialInput.GetName().ToString()); } } diff --git a/Engine/Source/Editor/UnrealEd/Private/ObjectTools.cpp b/Engine/Source/Editor/UnrealEd/Private/ObjectTools.cpp index 061670953cbe..a86862b02d39 100644 --- a/Engine/Source/Editor/UnrealEd/Private/ObjectTools.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/ObjectTools.cpp @@ -1300,7 +1300,7 @@ namespace ObjectTools Notification->SetCompletionState( CollectionCreated ? SNotificationItem::CS_Success : SNotificationItem::CS_Fail ); } } - } + } //-V773 } } else @@ -1581,6 +1581,12 @@ namespace ObjectTools GUnrealEd->GetPackageAutoSaver().OnPackagesDeleted(PackagesToDelete); } + // Let the asset registry know that these packages are being removed + for (UPackage* PackageToDelete : PackagesToDelete) + { + FAssetRegistryModule::PackageDeleted(PackageToDelete); + } + // Unload the packages and collect garbage. if ( PackagesToDelete.Num() > 0 || EmptyPackagesToUnload.Num() > 0 ) { @@ -1790,7 +1796,7 @@ namespace ObjectTools FNotificationInfo Info( NSLOCTEXT("UnrealEd", "Warning_CantDeleteRebuildingAssetRegistry", "Unable To Delete While Discovering Assets") ); Info.ExpireDuration = 3.0f; FSlateNotificationManager::Get().AddNotification(Info); - return false; + return 0; } // let systems clean up any unnecessary references that they may have @@ -2312,8 +2318,12 @@ namespace ObjectTools if( DeleteSingleObject( CurObject ) ) { - // Update return val - ++NumDeletedObjects; + // Only count the objects we were given to delete, as this function may have added more (eg, BP instances) + if (InObjectsToDelete.Contains(CurObject)) + { + // Update return val + ++NumDeletedObjects; + } } GWarn->StatusUpdate(Count, ReplaceableObjectsNum, NSLOCTEXT("UnrealEd", "ConsolidateAssetsUpdate_DeletingObjects", "Deleting Assets...")); @@ -2737,11 +2747,8 @@ namespace ObjectTools FPackageName::DoesPackageExist( ExistingOutermostPackage->GetName(), NULL, &ExistingOutermostPackageFilename ); } - if( Object ) - { - // Fully load the ref objects package - TopLevelPackages.Add( Object->GetOutermost() ); - } + // Fully load the ref objects package + TopLevelPackages.Add( Object->GetOutermost() ); // Used in the IsValidObjectName checks below FText Reason; @@ -2919,7 +2926,7 @@ namespace ObjectTools { if(bMoveRedirectorFailed) { - ErrorMessage += FText::Format( NSLOCTEXT("UnrealEd", "Error_CouldntRenameObjectRedirectorF", "Couldn't rename '{0}' object because there is an object redirector of the same name, please run FixupRedirects.\n"), + ErrorMessage += FText::Format( NSLOCTEXT("UnrealEd", "Error_CouldntRenameObjectRedirectorF", "Couldn't rename '{0}' object because there is an object redirector of the same name, please fixup redirect from editor by enabling Show Redirects in content browser.\n"), FText::FromString(Object->GetFullName()) ).ToString(); } else @@ -2957,7 +2964,7 @@ namespace ObjectTools bool RenameObjects( const TArray< UObject* >& SelectedObjects, bool bIncludeLocInstances, const FString& SourcePath, const FString& DestinationPath, bool bOpenDialog ) { // @todo asset: Find a proper location for localized files - bIncludeLocInstances = false; + bIncludeLocInstances = false; //-V763 if( !bIncludeLocInstances ) { return RenameObjectsInternal( SelectedObjects, bIncludeLocInstances, NULL, SourcePath, DestinationPath, bOpenDialog ); @@ -4113,10 +4120,13 @@ namespace ThumbnailTools { FObjectThumbnail* FoundThumbnail = NULL; + FString PackageName = InPackageFileName; + FPackageName::TryConvertFilenameToLongPackageName(PackageName, PackageName); + // First check to see if the package is already in memory. If it is, some or all of the thumbnails // may already be loaded and ready. UObject* PackageOuter = NULL; - UPackage* Package = FindPackage( PackageOuter, *FPackageName::PackageFromPath( *InPackageFileName ) ); + UPackage* Package = FindPackage( PackageOuter, *PackageName); if( Package != NULL ) { FoundThumbnail = FindCachedThumbnailInPackage( Package, InObjectFullName ); diff --git a/Engine/Source/Editor/UnrealEd/Private/PackageTools.cpp b/Engine/Source/Editor/UnrealEd/Private/PackageTools.cpp index 6a29124f2d70..077966a72f00 100644 --- a/Engine/Source/Editor/UnrealEd/Private/PackageTools.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/PackageTools.cpp @@ -933,6 +933,9 @@ namespace PackageTools } } + // Remove double-slashes + SanitizedName.ReplaceInline(TEXT("//"), TEXT("/")); + return SanitizedName; } } @@ -940,5 +943,3 @@ namespace PackageTools #undef LOCTEXT_NAMESPACE // EOF - - diff --git a/Engine/Source/Editor/UnrealEd/Private/PlayLevel.cpp b/Engine/Source/Editor/UnrealEd/Private/PlayLevel.cpp index 1a069bd3c9f8..e35c7a1acb64 100644 --- a/Engine/Source/Editor/UnrealEd/Private/PlayLevel.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/PlayLevel.cpp @@ -102,7 +102,6 @@ DEFINE_LOG_CATEGORY_STATIC(LogPlayLevel, Log, All); -DEFINE_LOG_CATEGORY_STATIC(LogHMD, Log, All); #define LOCTEXT_NAMESPACE "PlayLevel" @@ -2177,7 +2176,7 @@ void UEditorEngine::RequestEndPlayMap() { bRequestEndPlayMapQueued = true; - // Cache the postion and rotation of the camera (the controller may be destroyed before we end the pie session and we need them to preserve the camera position) + // Cache the position and rotation of the camera (the controller may be destroyed before we end the pie session and we need them to preserve the camera position) if (bLastViewAndLocationValid == false) { for (int32 WorldIdx = WorldList.Num() - 1; WorldIdx >= 0; --WorldIdx) diff --git a/Engine/Source/Editor/UnrealEd/Private/PreferenceStubs.cpp b/Engine/Source/Editor/UnrealEd/Private/PreferenceStubs.cpp index 55097bf0bd25..027beecd1e06 100644 --- a/Engine/Source/Editor/UnrealEd/Private/PreferenceStubs.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/PreferenceStubs.cpp @@ -47,6 +47,7 @@ UPersonaOptions::UPersonaOptions(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) , DefaultLocalAxesSelection(2) , DefaultBoneDrawSelection(1) + , bAllowPreviewMeshCollectionsToSelectFromDifferentSkeletons(true) { ViewModeIndex = VMI_Lit; @@ -55,6 +56,8 @@ UPersonaOptions::UPersonaOptions(const FObjectInitializer& ObjectInitializer) BranchingPointTimingNodeColor = FLinearColor(0.5f, 1.0f, 1.0f); bAutoAlignFloorToMesh = true; + + NumFolderFiltersInAssetBrowser = 2; } void UPersonaOptions::SetViewportBackgroundColor( const FLinearColor& InViewportBackgroundColor) diff --git a/Engine/Source/Editor/UnrealEd/Private/PreviewMaterial.cpp b/Engine/Source/Editor/UnrealEd/Private/PreviewMaterial.cpp index d9d3a3788b2c..ea2318f982b7 100644 --- a/Engine/Source/Editor/UnrealEd/Private/PreviewMaterial.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/PreviewMaterial.cpp @@ -310,6 +310,16 @@ FEditorParameterGroup& UMaterialEditorInstanceConstant::GetParameterGroup(FName int32 ind = ParameterGroups.AddZeroed(1); FEditorParameterGroup& Group= ParameterGroups[ind]; Group.GroupName = ParameterGroup; + UMaterial* ParentMaterial = Parent->GetMaterial(); + int32 NewSortPriority; + if (ParentMaterial->GetGroupSortPriority(ParameterGroup.ToString(), NewSortPriority)) + { + Group.GroupSortPriority = NewSortPriority; + } + else + { + Group.GroupSortPriority = 0; + } return Group; } @@ -335,7 +345,7 @@ void UMaterialEditorInstanceConstant::RegenerateArrays() UDEditorVectorParameterValue & ParameterValue = *(NewObject()); FName ParameterName = ParameterNames[ParameterIdx]; FLinearColor Value; - + int32 SortPriority; ParameterValue.bOverride = false; ParameterValue.ParameterName = ParameterName; ParameterValue.ExpressionId = Guids[ParameterIdx]; @@ -356,6 +366,14 @@ void UMaterialEditorInstanceConstant::RegenerateArrays() ParameterValue.ParameterValue = SourceParam.ParameterValue; } } + if (ParentMaterial->GetParameterSortPriority(ParameterName, SortPriority)) + { + ParameterValue.SortPriority = SortPriority; + } + else + { + ParameterValue.SortPriority = 0; + } AssignParameterToGroup(ParentMaterial, Cast(&ParameterValue)); } // Scalar Parameters. @@ -365,6 +383,7 @@ void UMaterialEditorInstanceConstant::RegenerateArrays() UDEditorScalarParameterValue& ParameterValue = *(NewObject()); FName ParameterName = ParameterNames[ParameterIdx]; float Value; + int32 SortPriority; ParameterValue.bOverride = false; ParameterValue.ParameterName = ParameterName; @@ -387,6 +406,14 @@ void UMaterialEditorInstanceConstant::RegenerateArrays() ParameterValue.ParameterValue = SourceParam.ParameterValue; } } + if (ParentMaterial->GetParameterSortPriority(ParameterName, SortPriority)) + { + ParameterValue.SortPriority = SortPriority; + } + else + { + ParameterValue.SortPriority = 0; + } AssignParameterToGroup(ParentMaterial, Cast(&ParameterValue)); } @@ -397,6 +424,7 @@ void UMaterialEditorInstanceConstant::RegenerateArrays() UDEditorTextureParameterValue& ParameterValue = *(NewObject()); FName ParameterName = ParameterNames[ParameterIdx]; UTexture* Value; + int32 SortPriority; ParameterValue.bOverride = false; ParameterValue.ParameterName = ParameterName; @@ -407,7 +435,6 @@ void UMaterialEditorInstanceConstant::RegenerateArrays() ParameterValue.ParameterValue = Value; } - // @todo: This is kind of slow, maybe store these in a map for lookup? // See if this keyname exists in the source instance. for(int32 TextureParameterIdx=0; TextureParameterIdxTextureParameterValues.Num(); TextureParameterIdx++) @@ -419,6 +446,14 @@ void UMaterialEditorInstanceConstant::RegenerateArrays() ParameterValue.ParameterValue = SourceParam.ParameterValue; } } + if (ParentMaterial->GetParameterSortPriority(ParameterName, SortPriority)) + { + ParameterValue.SortPriority = SortPriority; + } + else + { + ParameterValue.SortPriority = 0; + } AssignParameterToGroup(ParentMaterial, Cast(&ParameterValue)); } @@ -430,6 +465,7 @@ void UMaterialEditorInstanceConstant::RegenerateArrays() FName ParameterName = ParameterNames[ParameterIdx]; UFont* FontValue; int32 FontPage; + int32 SortPriority; ParameterValue.bOverride = false; ParameterValue.ParameterName = ParameterName; @@ -441,7 +477,6 @@ void UMaterialEditorInstanceConstant::RegenerateArrays() ParameterValue.ParameterValue.FontPage = FontPage; } - // @todo: This is kind of slow, maybe store these in a map for lookup? // See if this keyname exists in the source instance. for(int32 FontParameterIdx=0; FontParameterIdxFontParameterValues.Num(); FontParameterIdx++) @@ -454,6 +489,14 @@ void UMaterialEditorInstanceConstant::RegenerateArrays() ParameterValue.ParameterValue.FontPage = SourceParam.FontPage; } } + if (ParentMaterial->GetParameterSortPriority(ParameterName, SortPriority)) + { + ParameterValue.SortPriority = SortPriority; + } + else + { + ParameterValue.SortPriority = 0; + } AssignParameterToGroup(ParentMaterial, Cast(&ParameterValue)); } @@ -464,6 +507,7 @@ void UMaterialEditorInstanceConstant::RegenerateArrays() // Copy Static Switch Parameters for(int32 ParameterIdx=0; ParameterIdx()); ParameterValue.ParameterValue =StaticSwitchParameterValue.Value; @@ -471,6 +515,14 @@ void UMaterialEditorInstanceConstant::RegenerateArrays() ParameterValue.ParameterName =StaticSwitchParameterValue.ParameterName; ParameterValue.ExpressionId= StaticSwitchParameterValue.ExpressionGUID; + if (ParentMaterial->GetParameterSortPriority(StaticSwitchParameterValue.ParameterName, SortPriority)) + { + ParameterValue.SortPriority = SortPriority; + } + else + { + ParameterValue.SortPriority = 0; + } AssignParameterToGroup(ParentMaterial, Cast(&ParameterValue)); } @@ -478,6 +530,7 @@ void UMaterialEditorInstanceConstant::RegenerateArrays() for(int32 ParameterIdx=0; ParameterIdx()); ParameterValue.ParameterValue.R = StaticComponentMaskParameterValue.R; @@ -488,6 +541,14 @@ void UMaterialEditorInstanceConstant::RegenerateArrays() ParameterValue.ParameterName =StaticComponentMaskParameterValue.ParameterName; ParameterValue.ExpressionId= StaticComponentMaskParameterValue.ExpressionGUID; + if (ParentMaterial->GetParameterSortPriority(StaticComponentMaskParameterValue.ParameterName, SortPriority)) + { + ParameterValue.SortPriority = SortPriority; + } + else + { + ParameterValue.SortPriority = 0; + } AssignParameterToGroup(ParentMaterial, Cast(&ParameterValue)); } @@ -504,7 +565,7 @@ void UMaterialEditorInstanceConstant::RegenerateArrays() { FString AName = A.ParameterName.ToString().ToLower(); FString BName = B.ParameterName.ToString().ToLower(); - return AName < BName; + return A.SortPriority != B.SortPriority ? A.SortPriority < B.SortPriority : AName < BName; } }; ParamGroup.Parameters.Sort( FCompareUDEditorParameterValueByParameterName() ); @@ -525,7 +586,7 @@ void UMaterialEditorInstanceConstant::RegenerateArrays() { return false; } - return AName < BName; + return A.GroupSortPriority != B.GroupSortPriority ? A.GroupSortPriority < B.GroupSortPriority : AName < BName; } }; ParameterGroups.Sort( FCompareFEditorParameterGroupByName() ); diff --git a/Engine/Source/Editor/UnrealEd/Private/SSkeletonWidget.cpp b/Engine/Source/Editor/UnrealEd/Private/SSkeletonWidget.cpp index 70d16cba6b5d..880a23ca9c01 100644 --- a/Engine/Source/Editor/UnrealEd/Private/SSkeletonWidget.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/SSkeletonWidget.cpp @@ -1398,10 +1398,7 @@ void SBasePoseViewport::SetSkeleton(USkeleton* Skeleton) //Place the camera at a good viewer position FVector NewPosition = Client->GetViewLocation(); NewPosition.Normalize(); - if(PreviewSkeletalMesh) - { - NewPosition *= (PreviewSkeletalMesh->GetImportedBounds().SphereRadius*1.5f); - } + NewPosition *= (PreviewSkeletalMesh->GetImportedBounds().SphereRadius*1.5f); Client->SetViewLocation(NewPosition); } else diff --git a/Engine/Source/Editor/UnrealEd/Private/ScriptDisassembler.cpp b/Engine/Source/Editor/UnrealEd/Private/ScriptDisassembler.cpp index b4a953356baf..995f2f3413c4 100644 --- a/Engine/Source/Editor/UnrealEd/Private/ScriptDisassembler.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/ScriptDisassembler.cpp @@ -237,6 +237,22 @@ void FKismetBytecodeDisassembler::ProcessCommon(int32& ScriptIndex, EExprToken O Ar.Logf(TEXT("%s $%X: EX_EndSet"), *Indents, (int32)Opcode); break; } + case EX_SetConst: + { + UProperty* InnerProp = ReadPointer(ScriptIndex); + int32 Num = ReadINT(ScriptIndex); + Ar.Logf(TEXT("%s $%X: set set const - elements number: %d, inner property: %s"), *Indents, (int32)Opcode, Num, *GetNameSafe(InnerProp)); + while (SerializeExpr(ScriptIndex) != EX_EndSetConst) + { + // Set contents + } + break; + } + case EX_EndSetConst: + { + Ar.Logf(TEXT("%s $%X: EX_EndSetConst"), *Indents, (int32)Opcode); + break; + } case EX_SetMap: { Ar.Logf(TEXT("%s $%X: set map"), *Indents, (int32)Opcode); @@ -253,6 +269,23 @@ void FKismetBytecodeDisassembler::ProcessCommon(int32& ScriptIndex, EExprToken O Ar.Logf(TEXT("%s $%X: EX_EndMap"), *Indents, (int32)Opcode); break; } + case EX_MapConst: + { + UProperty* KeyProp = ReadPointer(ScriptIndex); + UProperty* ValProp = ReadPointer(ScriptIndex); + int32 Num = ReadINT(ScriptIndex); + Ar.Logf(TEXT("%s $%X: set map const - elements number: %d, key property: %s, val property: %s"), *Indents, (int32)Opcode, Num, *GetNameSafe(KeyProp), *GetNameSafe(ValProp)); + while (SerializeExpr(ScriptIndex) != EX_EndMapConst) + { + // Map contents + } + break; + } + case EX_EndMapConst: + { + Ar.Logf(TEXT("%s $%X: EX_EndMapConst"), *Indents, (int32)Opcode); + break; + } case EX_ObjToInterfaceCast: { // A conversion from an object variable to a native interface variable. diff --git a/Engine/Source/Editor/UnrealEd/Private/Settings/EditorPerProjectUserSettings.cpp b/Engine/Source/Editor/UnrealEd/Private/Settings/EditorPerProjectUserSettings.cpp index 536617cf2c07..6f8eb14d67f4 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Settings/EditorPerProjectUserSettings.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Settings/EditorPerProjectUserSettings.cpp @@ -8,6 +8,8 @@ #define LOCTEXT_NAMESPACE "EditorPerProjectUserSettings" +/// @cond DOXYGEN_WARNINGS + UEditorPerProjectUserSettings::UEditorPerProjectUserSettings(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { @@ -36,6 +38,7 @@ void UEditorPerProjectUserSettings::PostInitProperties() MaterialQualityLevelVar->Set(MaterialQualityLevel, ECVF_SetByScalability); } +#if WITH_EDITOR void UEditorPerProjectUserSettings::PostEditChangeProperty( FPropertyChangedEvent& PropertyChangedEvent ) { Super::PostEditChangeProperty(PropertyChangedEvent); @@ -56,6 +59,8 @@ void UEditorPerProjectUserSettings::PostEditChangeProperty( FPropertyChangedEven UserSettingChangedEvent.Broadcast(Name); } +#endif +/// @endcond #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Editor/UnrealEd/Private/Settings/EditorProjectSettings.cpp b/Engine/Source/Editor/UnrealEd/Private/Settings/EditorProjectSettings.cpp index f93eadfaef91..038b73d2fd5b 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Settings/EditorProjectSettings.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Settings/EditorProjectSettings.cpp @@ -25,6 +25,7 @@ EUnit ConvertDefaultInputUnits(EDefaultLocationUnit In) UEditorProjectAppearanceSettings::UEditorProjectAppearanceSettings(const FObjectInitializer& Initializer) : Super(Initializer) + , bDisplayUnitsOnComponentTransforms(false) , UnitDisplay_DEPRECATED(EUnitDisplay::Invalid) , DefaultInputUnits_DEPRECATED(EDefaultLocationUnit::Invalid) { diff --git a/Engine/Source/Editor/UnrealEd/Private/Settings/SettingsClasses.cpp b/Engine/Source/Editor/UnrealEd/Private/Settings/SettingsClasses.cpp index 1e16d1719fe2..307cf38a4f83 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Settings/SettingsClasses.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Settings/SettingsClasses.cpp @@ -33,6 +33,8 @@ #include "Misc/ConfigCacheIni.h" // for FConfigCacheIni::GetString() #include "SourceCodeNavigation.h" #include "Developer/BlueprintProfiler/Public/BlueprintProfilerModule.h" +#include "IProjectManager.h" +#include "ProjectDescriptor.h" #define LOCTEXT_NAMESPACE "SettingsClasses" @@ -349,6 +351,7 @@ ULevelEditorMiscSettings::ULevelEditorMiscSettings( const FObjectInitializer& Ob bAutoApplyLightingEnable = true; SectionName = TEXT("Misc"); CategoryName = TEXT("LevelEditor"); + EditorScreenshotSaveDirectory.Path = FPaths::ScreenShotDir(); } @@ -649,6 +652,36 @@ void UProjectPackagingSettings::PostEditChangeProperty( FPropertyChangedEvent& P } } } + else if (Name == FName((TEXT("BlueprintNativizationMethod")))) + { + IProjectManager& ProjManager = IProjectManager::Get(); + { + // NOTE: these are hardcoded to match the path constructed by AddBlueprintPluginPathArgument() on CookCommand.Automation.cs, and the defaults in + // FBlueprintNativeCodeGenPaths::GetDefaultCodeGenPaths(); if you alter this (or either of those) then you need to update the others + const FString NativizedPluginDir = TEXT("./Intermediate/Plugins"); + const FString NativizedPluginName = TEXT("NativizedAssets"); + const FString FullPluginPath = FPaths::ConvertRelativePathToFull( FPaths::ConvertRelativePathToFull(FPaths::GameDir()), NativizedPluginDir ); + + if (BlueprintNativizationMethod == EProjectPackagingBlueprintNativizationMethod::Disabled) + { + + ProjManager.UpdateAdditionalPluginDirectory(FullPluginPath, /*bAddOrRemove =*/false); + FText PluginDisableFailure; + ProjManager.SetPluginEnabled(NativizedPluginName, /*bEnabled =*/false, PluginDisableFailure); + } + else + { + ProjManager.UpdateAdditionalPluginDirectory(FullPluginPath, /*bAddOrRemove =*/true); + // plugin is enabled by default, so let's remove it from the uproject list entirely (else it causes problem in the packaged project) + // SetPluginEnabled() will only remove it if the plugin exists (it may not yet), so we rely on this explicit removal + FText PluginEnableFailure; + ProjManager.RemovePluginReference(NativizedPluginName, PluginEnableFailure); + } + + FText SaveFailure; + ProjManager.SaveCurrentProjectToDisk(SaveFailure); + } + } else if (Name == FName((TEXT("NativizeBlueprintAssets")))) { int32 AssetIndex; diff --git a/Engine/Source/Editor/UnrealEd/Private/SkeletalMeshEdit.cpp b/Engine/Source/Editor/UnrealEd/Private/SkeletalMeshEdit.cpp index 426051bbb310..b001dd8b5ab5 100644 --- a/Engine/Source/Editor/UnrealEd/Private/SkeletalMeshEdit.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/SkeletalMeshEdit.cpp @@ -648,8 +648,13 @@ int32 GetAnimationCurveRate(FbxAnimCurve* CurrentCurve) double KeyAnimLength = TimeInterval.GetDuration().GetSecondDouble(); if (KeyAnimLength != 0.0) { - // DEFAULT_SAMPLERATE(30) fps animation has (DEFAULT_SAMPLERATE + 1) keys because it includes index 0 key for 0.0 second - int32 SampleRate = 1;// FPlatformMath::RoundToInt((KeyCount - 1) / KeyAnimLength); + int32 SampleRate = FPlatformMath::RoundToInt((KeyCount - 1) / KeyAnimLength); + if (SampleRate >= DEFAULT_SAMPLERATE) + { + //We import a curve with more then 30 keys per frame + return SampleRate; + } + SampleRate = 1; //Find the least sample rate we can use to have at least on key to every fbx key position TArray KeyFrameSampleRates; @@ -779,11 +784,17 @@ int32 UnFbx::FFbxImporter::GetMaxSampleRate(TArray& SortedLinks, TArra //Find the lowest sample rate that will pass by all the keys from all curves for (int32 CurveSampleRate : CurveAnimSampleRates) { - MaxStackResampleRate = LeastCommonMultiplier(MaxStackResampleRate, CurveSampleRate); - if (MaxStackResampleRate >= DEFAULT_SAMPLERATE) + if (CurveSampleRate >= DEFAULT_SAMPLERATE && MaxStackResampleRate < CurveSampleRate) { - MaxStackResampleRate = DEFAULT_SAMPLERATE; - break; + MaxStackResampleRate = CurveSampleRate; + } + else if (MaxStackResampleRate < DEFAULT_SAMPLERATE) + { + MaxStackResampleRate = LeastCommonMultiplier(MaxStackResampleRate, CurveSampleRate); + if (MaxStackResampleRate >= DEFAULT_SAMPLERATE) + { + MaxStackResampleRate = DEFAULT_SAMPLERATE; + } } } diff --git a/Engine/Source/Editor/UnrealEd/Private/SnappingUtils.cpp b/Engine/Source/Editor/UnrealEd/Private/SnappingUtils.cpp index 08ff8583e0f1..146896b5c134 100644 --- a/Engine/Source/Editor/UnrealEd/Private/SnappingUtils.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/SnappingUtils.cpp @@ -19,6 +19,7 @@ #include "VertexSnapping.h" #include "ISnappingPolicy.h" #include "ViewportSnappingModule.h" +#include "ActorGroupingUtils.h" ////////////////////////////////////////////////////////////////////////// // FEditorViewportSnapping @@ -226,7 +227,7 @@ bool FEditorViewportSnapping::SnapActorsToNearestActor( FVector& Drag, FLevelEdi && !Selection->IsSelected( Actor ) ) { // Group Actors don't appear in the selected actors list! - if ( GEditor->bGroupingActive ) + if (UActorGroupingUtils::IsGroupingActive()) { // Valid snaps: locked groups (not self or actors within locked groups), actors within unlocked groups (not the group itself), other actors const AGroupActor* GroupActor = Cast( Actor ); // AGroupActor::GetRootForActor( Actor ); diff --git a/Engine/Source/Editor/UnrealEd/Private/StaticLightingSystem/StaticLightingDebug.cpp b/Engine/Source/Editor/UnrealEd/Private/StaticLightingSystem/StaticLightingDebug.cpp index 1227bb9ff57b..ced8abbe06db 100644 --- a/Engine/Source/Editor/UnrealEd/Private/StaticLightingSystem/StaticLightingDebug.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/StaticLightingSystem/StaticLightingDebug.cpp @@ -226,9 +226,9 @@ void SetDebugLightmapSample(TArray* Components, UModel* Model, uint32 Index2 = Indices[TriangleIndex + 2]; // Transform positions to world space - FVector Position0 = SMComponent->ComponentToWorld.TransformPosition(LODModel.PositionVertexBuffer.VertexPosition(Index0)); - FVector Position1 = SMComponent->ComponentToWorld.TransformPosition(LODModel.PositionVertexBuffer.VertexPosition(Index1)); - FVector Position2 = SMComponent->ComponentToWorld.TransformPosition(LODModel.PositionVertexBuffer.VertexPosition(Index2)); + FVector Position0 = SMComponent->GetComponentTransform().TransformPosition(LODModel.PositionVertexBuffer.VertexPosition(Index0)); + FVector Position1 = SMComponent->GetComponentTransform().TransformPosition(LODModel.PositionVertexBuffer.VertexPosition(Index1)); + FVector Position2 = SMComponent->GetComponentTransform().TransformPosition(LODModel.PositionVertexBuffer.VertexPosition(Index2)); float PlaneDistance; FVector BaryCentricWeights; diff --git a/Engine/Source/Editor/UnrealEd/Private/StaticLightingSystem/StaticLightingPrivate.h b/Engine/Source/Editor/UnrealEd/Private/StaticLightingSystem/StaticLightingPrivate.h index 66b1b9cfcda3..ac7d37094216 100644 --- a/Engine/Source/Editor/UnrealEd/Private/StaticLightingSystem/StaticLightingPrivate.h +++ b/Engine/Source/Editor/UnrealEd/Private/StaticLightingSystem/StaticLightingPrivate.h @@ -293,7 +293,7 @@ public: bool ShouldOperateOnLevel(ULevel* InLevel) const { - return !InLevel->bIsLightingScenario || InLevel == LightingScenario; + return InLevel && (!InLevel->bIsLightingScenario || InLevel == LightingScenario) && InLevel->bIsVisible; } private: @@ -411,14 +411,6 @@ private: }; FStaticLightingSystem::LightingStage CurrentBuildStage; - // Variable for storing the state of the crash tracker - // We disable it only for export, for everything else it shouldn't matter. - // This is a very special case, and doing this sort of thing - // is almost never recommended, especially without profiling heavily. - // The reason it works here is because amortized export flushes the render - // commands every tick, which is highly detrimental to the crash tracker's operation. - bool bCrashTrackerOriginallyEnabled; - /** Stats we must cache off because the process is async */ // A separate statistics structure for tracking the LightmassProcess routines times FLightmassStatistics LightmassProcessStatistics; diff --git a/Engine/Source/Editor/UnrealEd/Private/StaticLightingSystem/StaticLightingSystem.cpp b/Engine/Source/Editor/UnrealEd/Private/StaticLightingSystem/StaticLightingSystem.cpp index 5f1ad35742c1..5e9bb47cfcda 100644 --- a/Engine/Source/Editor/UnrealEd/Private/StaticLightingSystem/StaticLightingSystem.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/StaticLightingSystem/StaticLightingSystem.cpp @@ -55,7 +55,6 @@ FSwarmDebugOptions GSwarmDebugOptions; #include "ModelLight.h" #include "Engine/LevelStreaming.h" #include "LevelUtils.h" -#include "Interfaces/ICrashTrackerModule.h" #include "EngineModule.h" #include "LightMap.h" #include "ShadowMap.h" @@ -435,7 +434,6 @@ FStaticLightingSystem::FStaticLightingSystem(const FLightingBuildOptions& InOpti , DeterministicIndex(0) , NextVisibilityId(0) , CurrentBuildStage(FStaticLightingSystem::NotRunning) - , bCrashTrackerOriginallyEnabled(false) , World(InWorld) , LightingScenario(InLightingScenario) , LightmassProcessor(NULL) @@ -444,16 +442,6 @@ FStaticLightingSystem::FStaticLightingSystem(const FLightingBuildOptions& InOpti FStaticLightingSystem::~FStaticLightingSystem() { - if (bCrashTrackerOriginallyEnabled) - { - // Re-enable the crash tracker if we ever disabled it - ICrashTrackerModule* CrashTracker = FModuleManager::LoadModulePtr("CrashTracker"); - if (CrashTracker) - { - CrashTracker->SetCrashTrackingEnabled(true); - bCrashTrackerOriginallyEnabled = false; - } - } if (LightmassProcessor) { delete LightmassProcessor; @@ -621,19 +609,20 @@ bool FStaticLightingSystem::BeginLightmassProcess() if (bLightIsInWorld && ShouldOperateOnLevel(Light->GetOwner()->GetLevel())) { - if (Light->bAffectsWorld - && (Light->HasStaticShadowing() || Light->HasStaticLighting())) - { - // Make sure the light GUIDs are up-to-date. - Light->ValidateLightGUIDs(); + if (Light->bAffectsWorld + && Light->IsRegistered() + && (Light->HasStaticShadowing() || Light->HasStaticLighting())) + { + // Make sure the light GUIDs are up-to-date. + Light->ValidateLightGUIDs(); - // Add the light to the system's list of lights in the world. - Lights.Add(Light); + // Add the light to the system's list of lights in the world. + Lights.Add(Light); + } } } } } - } { FLightmassStatistics::FScopedGather GatherStatScope(LightmassStatistics.GatherLightingInfoTime); @@ -2053,25 +2042,6 @@ bool FStaticLightingSystem::InitiateLightmassProcessor() LightmassProcessor->InitiateExport(); bSuccessful = true; CurrentBuildStage = FStaticLightingSystem::AmortizedExport; - - if (!IsRunningCommandlet()) - { - // Crash tracker interferes with performance during export only. - // Disable it only for export, for everything else it shouldn't matter. - // This is a very special case, and doing this sort of thing - // is almost never recommended, especially without profiling heavily. - // The reason it works here is because amortized export flushes the render - // commands every tick, which is highly detrimental to the crash tracker's operation. - // ALSO NOTE: The reason this is set here rather than be a common API in the crashtracker - // module is to discourage people from doing this sort of thing all over the place. - ICrashTrackerModule* CrashTracker = FModuleManager::LoadModulePtr("CrashTracker"); - if (CrashTracker) - { - bCrashTrackerOriginallyEnabled = CrashTracker->IsCurrentlyCapturing(); - CrashTracker->SetCrashTrackingEnabled(false); - } - } - } } @@ -2190,16 +2160,6 @@ void FStaticLightingSystem::UpdateLightingBuild() if (bCompleted) { - if (bCrashTrackerOriginallyEnabled) - { - // Re-enable the crash tracker if we disabled it - ICrashTrackerModule* CrashTracker = FModuleManager::LoadModulePtr("CrashTracker"); - if (CrashTracker) - { - CrashTracker->SetCrashTrackingEnabled(true); - bCrashTrackerOriginallyEnabled = false; - } - } CurrentBuildStage = FStaticLightingSystem::SwarmKickoff; } } diff --git a/Engine/Source/Editor/UnrealEd/Private/StaticMeshEdit.cpp b/Engine/Source/Editor/UnrealEd/Private/StaticMeshEdit.cpp index 4a2e6165f685..55e2f8c6ef04 100644 --- a/Engine/Source/Editor/UnrealEd/Private/StaticMeshEdit.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/StaticMeshEdit.cpp @@ -23,6 +23,9 @@ #include "PhysicsEngine/BodySetup.h" #include "FbxImporter.h" +#include "Materials/MaterialInterface.h" +#include "Materials/Material.h" + bool GBuildStaticMeshCollision = 1; @@ -1236,7 +1239,7 @@ void UpdateSomeLodsImportMeshData(UStaticMesh* NewMesh, TArray *ReimportL } } -void RestoreExistingMeshData(ExistingStaticMeshData* ExistingMeshDataPtr, UStaticMesh* NewMesh, int32 LodLevel) +void RestoreExistingMeshData(ExistingStaticMeshData* ExistingMeshDataPtr, UStaticMesh* NewMesh, int32 LodLevel, bool bResetMaterialSlots) { if (!ExistingMeshDataPtr || !NewMesh) { @@ -1246,43 +1249,50 @@ void RestoreExistingMeshData(ExistingStaticMeshData* ExistingMeshDataPtr, UStati //Create a remap material Index use to find the matching section later TArray RemapMaterial; - TArray RemapMaterialName; - - //Avoid matching a material more then once - TArray MatchIndex; - RemapMaterial.AddZeroed(NewMesh->StaticMaterials.Num()); + TArray RemapMaterialName; RemapMaterialName.AddZeroed(NewMesh->StaticMaterials.Num()); - //Restore the material array - for (int32 MaterialIndex = 0; MaterialIndex < NewMesh->StaticMaterials.Num(); ++MaterialIndex) + + if (bResetMaterialSlots) { - RemapMaterial[MaterialIndex] = MaterialIndex; - FStaticMaterial &Material = NewMesh->StaticMaterials[MaterialIndex]; - RemapMaterialName[MaterialIndex] = Material.ImportedMaterialSlotName; - bool bFoundMatchingMaterial = false; - for (int32 ExistMaterialIndex = 0; ExistMaterialIndex < ExistingMeshDataPtr->ExistingMaterials.Num(); ++ExistMaterialIndex) + // If "Reset Material Slot" is enable we want to change the material array to reflect the incoming FBX + // But we want to try to keep material instance from the existing data, we will match the one that fit + // but simply put the same index material instance on the one that do not match. Because we will fill + // the material slot name, artist will be able to remap the material instance correctly + for (int32 MaterialIndex = 0; MaterialIndex < NewMesh->StaticMaterials.Num(); ++MaterialIndex) { - if (MatchIndex.Contains(ExistMaterialIndex)) + RemapMaterial[MaterialIndex] = MaterialIndex; + if (NewMesh->StaticMaterials[MaterialIndex].MaterialInterface == nullptr || NewMesh->StaticMaterials[MaterialIndex].MaterialInterface == UMaterial::GetDefaultMaterial(MD_Surface)) { - continue; - } + bool bFoundMatch = false; + for (int32 ExistMaterialIndex = 0; ExistMaterialIndex < ExistingMeshDataPtr->ExistingMaterials.Num(); ++ExistMaterialIndex) + { + if (ExistingMeshDataPtr->ExistingMaterials[ExistMaterialIndex].ImportedMaterialSlotName == NewMesh->StaticMaterials[MaterialIndex].ImportedMaterialSlotName) + { + bFoundMatch = true; + RemapMaterial[MaterialIndex] = ExistMaterialIndex; + NewMesh->StaticMaterials[MaterialIndex].MaterialInterface = ExistingMeshDataPtr->ExistingMaterials[ExistMaterialIndex].MaterialInterface; + } + } - const FStaticMaterial &ExistMaterial = ExistingMeshDataPtr->ExistingMaterials[ExistMaterialIndex]; - if (Material.ImportedMaterialSlotName == ExistMaterial.ImportedMaterialSlotName) - { - Material.MaterialInterface = ExistMaterial.MaterialInterface; - Material.MaterialSlotName = ExistMaterial.MaterialSlotName; - Material.UVChannelData = ExistMaterial.UVChannelData; - MatchIndex.Add(ExistMaterialIndex); - RemapMaterial[MaterialIndex] = ExistMaterialIndex; - RemapMaterialName[MaterialIndex] = ExistMaterial.ImportedMaterialSlotName; - bFoundMatchingMaterial = true; - break; + if (!bFoundMatch && ExistingMeshDataPtr->ExistingMaterials.IsValidIndex(MaterialIndex)) + { + NewMesh->StaticMaterials[MaterialIndex].MaterialInterface = ExistingMeshDataPtr->ExistingMaterials[MaterialIndex].MaterialInterface; + } } } - - if (!bFoundMatchingMaterial) + } + else + { + //Avoid matching a material more then once + TArray MatchIndex; + //Restore the material array + for (int32 MaterialIndex = 0; MaterialIndex < NewMesh->StaticMaterials.Num(); ++MaterialIndex) { + RemapMaterial[MaterialIndex] = MaterialIndex; + FStaticMaterial &Material = NewMesh->StaticMaterials[MaterialIndex]; + RemapMaterialName[MaterialIndex] = Material.ImportedMaterialSlotName; + bool bFoundMatchingMaterial = false; for (int32 ExistMaterialIndex = 0; ExistMaterialIndex < ExistingMeshDataPtr->ExistingMaterials.Num(); ++ExistMaterialIndex) { if (MatchIndex.Contains(ExistMaterialIndex)) @@ -1291,101 +1301,125 @@ void RestoreExistingMeshData(ExistingStaticMeshData* ExistingMeshDataPtr, UStati } const FStaticMaterial &ExistMaterial = ExistingMeshDataPtr->ExistingMaterials[ExistMaterialIndex]; - if (ExistMaterial.ImportedMaterialSlotName == NAME_None && Material.MaterialInterface == ExistMaterial.MaterialInterface) + if (Material.ImportedMaterialSlotName == ExistMaterial.ImportedMaterialSlotName) { - if (ExistMaterial.MaterialSlotName != NAME_None) - { - Material.MaterialSlotName = ExistMaterial.MaterialSlotName; - } + Material.MaterialInterface = ExistMaterial.MaterialInterface; + Material.MaterialSlotName = ExistMaterial.MaterialSlotName; Material.UVChannelData = ExistMaterial.UVChannelData; MatchIndex.Add(ExistMaterialIndex); RemapMaterial[MaterialIndex] = ExistMaterialIndex; - RemapMaterialName[MaterialIndex] = Material.ImportedMaterialSlotName; + RemapMaterialName[MaterialIndex] = ExistMaterial.ImportedMaterialSlotName; bFoundMatchingMaterial = true; break; } } - } - if (!bFoundMatchingMaterial && ExistingMeshDataPtr->ExistingMaterials.IsValidIndex(MaterialIndex)) - { - const FStaticMaterial &ExistMaterial = ExistingMeshDataPtr->ExistingMaterials[MaterialIndex]; - Material.MaterialInterface = ExistMaterial.MaterialInterface; - Material.MaterialSlotName = ExistMaterial.MaterialSlotName; - Material.UVChannelData = ExistMaterial.UVChannelData; - } - } - if(ExistingMeshDataPtr->UseMaterialNameSlotWorkflow) - { - FMeshSectionInfoMap TmpExistingSectionInfoMap = ExistingMeshDataPtr->ExistingSectionInfoMap; - //Add all existing material not in the new mesh materials list - for (int32 i = 0; i < ExistingMeshDataPtr->ExistingLODData.Num(); i++) - { - if (LodLevel != INDEX_NONE && LodLevel != 0 && LodLevel != i) + + if (!bFoundMatchingMaterial) { - continue; - } - ExistingLODMeshData& LODModel = ExistingMeshDataPtr->ExistingLODData[i]; - for (int32 OldMaterialIndex = 0; OldMaterialIndex < LODModel.ExistingMaterials.Num(); ++OldMaterialIndex) - { - const FStaticMaterial &OldLodMaterial = LODModel.ExistingMaterials[OldMaterialIndex]; - int32 MaterialNumber = NewMesh->StaticMaterials.Find(OldLodMaterial); - //If we did not found any perfect match then try to see if there is a material slot with the same material and the same name - //We do this after the perfect match in case there is two slot with the same name but not the same imported name - if (MaterialNumber == INDEX_NONE) + for (int32 ExistMaterialIndex = 0; ExistMaterialIndex < ExistingMeshDataPtr->ExistingMaterials.Num(); ++ExistMaterialIndex) { - for (int32 NewMeshMaterialIndex = 0; NewMeshMaterialIndex < NewMesh->StaticMaterials.Num(); ++NewMeshMaterialIndex) + if (MatchIndex.Contains(ExistMaterialIndex)) { - const FStaticMaterial &NewMeshMaterial = NewMesh->StaticMaterials[NewMeshMaterialIndex]; - if (NewMeshMaterial.MaterialInterface == OldLodMaterial.MaterialInterface && NewMeshMaterial.MaterialSlotName == OldLodMaterial.MaterialSlotName) + continue; + } + + const FStaticMaterial &ExistMaterial = ExistingMeshDataPtr->ExistingMaterials[ExistMaterialIndex]; + if (ExistMaterial.ImportedMaterialSlotName == NAME_None && Material.MaterialInterface == ExistMaterial.MaterialInterface) + { + if (ExistMaterial.MaterialSlotName != NAME_None) { - MaterialNumber = NewMeshMaterialIndex; - break; + Material.MaterialSlotName = ExistMaterial.MaterialSlotName; } - } - } - if (MaterialNumber == INDEX_NONE) - { - MaterialNumber = NewMesh->StaticMaterials.Add(OldLodMaterial); - } - //Update the section info MaterialIndex - int32 SectionNumber = TmpExistingSectionInfoMap.GetSectionNumber(i); - for (int32 SectionIndex = 0; SectionIndex < SectionNumber; ++SectionIndex) - { - FMeshSectionInfo SectionInfo = TmpExistingSectionInfoMap.Get(i, SectionIndex); - if (LODModel.ExistingMaterials[SectionInfo.MaterialIndex].ImportedMaterialSlotName == OldLodMaterial.ImportedMaterialSlotName) - { - SectionInfo.MaterialIndex = MaterialNumber; - ExistingMeshDataPtr->ExistingSectionInfoMap.Set(i, SectionIndex, SectionInfo); + Material.UVChannelData = ExistMaterial.UVChannelData; + MatchIndex.Add(ExistMaterialIndex); + RemapMaterial[MaterialIndex] = ExistMaterialIndex; + RemapMaterialName[MaterialIndex] = Material.ImportedMaterialSlotName; + bFoundMatchingMaterial = true; + break; } } } + if (!bFoundMatchingMaterial && ExistingMeshDataPtr->ExistingMaterials.IsValidIndex(MaterialIndex)) + { + const FStaticMaterial &ExistMaterial = ExistingMeshDataPtr->ExistingMaterials[MaterialIndex]; + Material.MaterialInterface = ExistMaterial.MaterialInterface; + Material.MaterialSlotName = ExistMaterial.MaterialSlotName; + Material.UVChannelData = ExistMaterial.UVChannelData; + } } - } - else - { - if (ExistingMeshDataPtr->ExistingMaterials.Num() > NewMesh->StaticMaterials.Num()) + if(ExistingMeshDataPtr->UseMaterialNameSlotWorkflow) { - int32 OriginalMaterialNumber = NewMesh->StaticMaterials.Num(); + FMeshSectionInfoMap TmpExistingSectionInfoMap = ExistingMeshDataPtr->ExistingSectionInfoMap; + //Add all existing material not in the new mesh materials list for (int32 i = 0; i < ExistingMeshDataPtr->ExistingLODData.Num(); i++) { + if (LodLevel != INDEX_NONE && LodLevel != 0 && LodLevel != i) + { + continue; + } ExistingLODMeshData& LODModel = ExistingMeshDataPtr->ExistingLODData[i]; for (int32 OldMaterialIndex = 0; OldMaterialIndex < LODModel.ExistingMaterials.Num(); ++OldMaterialIndex) { - int32 MaterialNumber = NewMesh->StaticMaterials.Num(); - if (OldMaterialIndex >= MaterialNumber && OldMaterialIndex < ExistingMeshDataPtr->ExistingMaterials.Num()) + const FStaticMaterial &OldLodMaterial = LODModel.ExistingMaterials[OldMaterialIndex]; + int32 MaterialNumber = NewMesh->StaticMaterials.Find(OldLodMaterial); + //If we did not found any perfect match then try to see if there is a material slot with the same material and the same name + //We do this after the perfect match in case there is two slot with the same name but not the same imported name + if (MaterialNumber == INDEX_NONE) { - NewMesh->StaticMaterials.AddZeroed((OldMaterialIndex + 1) - MaterialNumber); + for (int32 NewMeshMaterialIndex = 0; NewMeshMaterialIndex < NewMesh->StaticMaterials.Num(); ++NewMeshMaterialIndex) + { + const FStaticMaterial &NewMeshMaterial = NewMesh->StaticMaterials[NewMeshMaterialIndex]; + if (NewMeshMaterial.MaterialInterface == OldLodMaterial.MaterialInterface && NewMeshMaterial.MaterialSlotName == OldLodMaterial.MaterialSlotName) + { + MaterialNumber = NewMeshMaterialIndex; + break; + } + } + } + if (MaterialNumber == INDEX_NONE) + { + MaterialNumber = NewMesh->StaticMaterials.Add(OldLodMaterial); + } + //Update the section info MaterialIndex + int32 SectionNumber = TmpExistingSectionInfoMap.GetSectionNumber(i); + for (int32 SectionIndex = 0; SectionIndex < SectionNumber; ++SectionIndex) + { + FMeshSectionInfo SectionInfo = TmpExistingSectionInfoMap.Get(i, SectionIndex); + if (LODModel.ExistingMaterials[SectionInfo.MaterialIndex].ImportedMaterialSlotName == OldLodMaterial.ImportedMaterialSlotName) + { + SectionInfo.MaterialIndex = MaterialNumber; + ExistingMeshDataPtr->ExistingSectionInfoMap.Set(i, SectionIndex, SectionInfo); + } } } } - - //Assign the original value to the materials we just add - check(NewMesh->StaticMaterials.Num() <= ExistingMeshDataPtr->ExistingMaterials.Num()); - for (int32 MaterialIndex = OriginalMaterialNumber; MaterialIndex < NewMesh->StaticMaterials.Num(); ++MaterialIndex) + } + else + { + if (ExistingMeshDataPtr->ExistingMaterials.Num() > NewMesh->StaticMaterials.Num()) { - FStaticMaterial &Material = NewMesh->StaticMaterials[MaterialIndex]; - const FStaticMaterial &ExistMaterial = ExistingMeshDataPtr->ExistingMaterials[MaterialIndex]; - Material = ExistMaterial; + int32 OriginalMaterialNumber = NewMesh->StaticMaterials.Num(); + for (int32 i = 0; i < ExistingMeshDataPtr->ExistingLODData.Num(); i++) + { + ExistingLODMeshData& LODModel = ExistingMeshDataPtr->ExistingLODData[i]; + for (int32 OldMaterialIndex = 0; OldMaterialIndex < LODModel.ExistingMaterials.Num(); ++OldMaterialIndex) + { + int32 MaterialNumber = NewMesh->StaticMaterials.Num(); + if (OldMaterialIndex >= MaterialNumber && OldMaterialIndex < ExistingMeshDataPtr->ExistingMaterials.Num()) + { + NewMesh->StaticMaterials.AddZeroed((OldMaterialIndex + 1) - MaterialNumber); + } + } + } + + //Assign the original value to the materials we just add + check(NewMesh->StaticMaterials.Num() <= ExistingMeshDataPtr->ExistingMaterials.Num()); + for (int32 MaterialIndex = OriginalMaterialNumber; MaterialIndex < NewMesh->StaticMaterials.Num(); ++MaterialIndex) + { + FStaticMaterial &Material = NewMesh->StaticMaterials[MaterialIndex]; + const FStaticMaterial &ExistMaterial = ExistingMeshDataPtr->ExistingMaterials[MaterialIndex]; + Material = ExistMaterial; + } } } } diff --git a/Engine/Source/Editor/UnrealEd/Private/ThumbnailHelpers.cpp b/Engine/Source/Editor/UnrealEd/Private/ThumbnailHelpers.cpp index 8431c085021f..c2f492685b5d 100644 --- a/Engine/Source/Editor/UnrealEd/Private/ThumbnailHelpers.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/ThumbnailHelpers.cpp @@ -179,7 +179,7 @@ void FParticleSystemThumbnailScene::SetParticleSystem(UParticleSystem* ParticleS ParticleSystem->PreviewComponent = NewObject(); ParticleSystem->PreviewComponent->Template = ParticleSystem; - ParticleSystem->PreviewComponent->ComponentToWorld.SetIdentity(); + ParticleSystem->PreviewComponent->SetComponentToWorld(FTransform::Identity); bNewComponent = true; } @@ -256,6 +256,7 @@ FMaterialThumbnailScene::FMaterialThumbnailScene() PreviewActor = GetWorld()->SpawnActor( SpawnInfo ); PreviewActor->GetStaticMeshComponent()->SetMobility(EComponentMobility::Movable); + PreviewActor->GetStaticMeshComponent()->bSelectable = false; // avoid generating hit proxies PreviewActor->SetActorEnableCollision(false); } diff --git a/Engine/Source/Editor/UnrealEd/Private/Toolkits/AssetEditorToolkit.cpp b/Engine/Source/Editor/UnrealEd/Private/Toolkits/AssetEditorToolkit.cpp index f66263996f45..24631857e7d8 100644 --- a/Engine/Source/Editor/UnrealEd/Private/Toolkits/AssetEditorToolkit.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/Toolkits/AssetEditorToolkit.cpp @@ -28,6 +28,9 @@ #include "IIntroTutorials.h" #include "SuperSearchModule.h" #include "Widgets/Docking/SDockTab.h" +#include "IAssetTools.h" +#include "IAssetTypeActions.h" +#include "AssetToolsModule.h" #define LOCTEXT_NAMESPACE "AssetEditorToolkit" @@ -103,6 +106,7 @@ void FAssetEditorToolkit::InitAssetEditor( const EToolkitMode::Type Mode, const .TabRole(ETabRole::MajorTab) .ToolTip(IDocumentation::Get()->CreateToolTip(ToolTipText, nullptr, DocLink, GetToolkitFName().ToString())) .Icon( this, &FAssetEditorToolkit::GetDefaultTabIcon ) + .TabColorScale( this, &FAssetEditorToolkit::GetDefaultTabColor ) .Label( Label ); { @@ -636,14 +640,40 @@ const FSlateBrush* FAssetEditorToolkit::GetDefaultTabIcon() const } else if (IconBrush != ThisAssetBrush) { - // Different types - return nullptr; + // Fallback icon + return FEditorStyle::GetBrush(TEXT("ClassIcon.Default")); } } return IconBrush; } +FLinearColor FAssetEditorToolkit::GetDefaultTabColor() const +{ + FLinearColor TabColor = FLinearColor::Transparent; + if (EditingObjects.Num() == 0 || !GetDefault()->bEnableColorizedEditorTabs) + { + return TabColor; + } + + FAssetToolsModule& AssetToolsModule = FAssetToolsModule::GetModule(); + IAssetTools& AssetTools = AssetToolsModule.Get(); + for (auto ObjectIt = EditingObjects.CreateConstIterator(); ObjectIt; ++ObjectIt) + { + TWeakPtr AssetTypeActions = AssetTools.GetAssetTypeActionsForClass((*ObjectIt)->GetClass()); + if (AssetTypeActions.IsValid()) + { + const FLinearColor ThisAssetColor = AssetTypeActions.Pin()->GetTypeColor(); + if (ThisAssetColor != FLinearColor::Transparent) + { + return ThisAssetColor; + } + } + } + + return TabColor; +} + FAssetEditorModeManager* FAssetEditorToolkit::GetAssetEditorModeManager() const { return AssetEditorModeManager; diff --git a/Engine/Source/Editor/UnrealEd/Private/UnrealEdEngine.cpp b/Engine/Source/Editor/UnrealEd/Private/UnrealEdEngine.cpp index 369f5cebb731..828afb9ebf64 100644 --- a/Engine/Source/Editor/UnrealEd/Private/UnrealEdEngine.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/UnrealEdEngine.cpp @@ -43,7 +43,6 @@ #include "PropertyEditorModule.h" #include "LevelEditor.h" #include "Interfaces/IMainFrameModule.h" -#include "Interfaces/ICrashTrackerModule.h" #include "Settings/EditorLoadingSavingSettingsCustomization.h" #include "Settings/GameMapsSettingsCustomization.h" #include "Settings/LevelEditorPlaySettingsCustomization.h" @@ -53,7 +52,6 @@ #include "PackageAutoSaver.h" #include "PerformanceMonitor.h" #include "BSPOps.h" -#include "Editor/EditorLiveStreaming/Public/IEditorLiveStreaming.h" #include "SourceCodeNavigation.h" #include "AutoReimport/AutoReimportManager.h" #include "Framework/Notifications/NotificationManager.h" @@ -162,8 +160,14 @@ void UUnrealEdEngine::Init(IEngineLoop* InEngineLoop) BaseCookingFlags |= CookerSettings->bIterativeCookingForLaunchOn ? IterativeFlags : ECookInitializationFlags::None; BaseCookingFlags |= CookerSettings->bEnableBuildDDCInBackground ? ECookInitializationFlags::BuildDDCInBackground : ECookInitializationFlags::None; + if (CookerSettings->bEnableCookOnTheSide) { + if ( ExperimentalSettings->bSharedCookedBuilds ) + { + BaseCookingFlags |= ECookInitializationFlags::IterateSharedBuild | ECookInitializationFlags::IgnoreIniSettingsOutOfDate; + } + CookServer = NewObject(); CookServer->Initialize(ECookMode::CookOnTheFlyFromTheEditor, BaseCookingFlags); CookServer->StartNetworkFileServer(false); @@ -213,32 +217,34 @@ bool CanCookForPlatformInThisProcess( const FString& PlatformName ) bool UUnrealEdEngine::CanCookByTheBookInEditor(const FString& PlatformName) const { - if ( CanCookForPlatformInThisProcess(PlatformName) == false ) + if ( !CookServer ) + { + return false; + } + + if ( !CanCookForPlatformInThisProcess(PlatformName) ) { CookServer->ClearAllCookedData(); return false; } - if ( CookServer ) - { - return CookServer->GetCookMode() == ECookMode::CookByTheBookFromTheEditor; - } - return false; + return CookServer->GetCookMode() == ECookMode::CookByTheBookFromTheEditor; } bool UUnrealEdEngine::CanCookOnTheFlyInEditor(const FString& PlatformName) const { - if ( CanCookForPlatformInThisProcess(PlatformName) == false ) + if ( !CookServer ) + { + return false; + } + + if ( !CanCookForPlatformInThisProcess(PlatformName) ) { CookServer->ClearAllCookedData(); return false; } - if ( CookServer ) - { - return CookServer->GetCookMode() == ECookMode::CookOnTheFlyFromTheEditor; - } - return false; + return CookServer->GetCookMode() == ECookMode::CookOnTheFlyFromTheEditor; } void UUnrealEdEngine::StartCookByTheBookInEditor( const TArray &TargetPlatforms, const TArray &CookMaps, const TArray &CookDirectories, const TArray &CookCultures, const TArray &IniMapSections ) @@ -423,26 +429,6 @@ void UUnrealEdEngine::Tick(float DeltaSeconds, bool bIdleMode) // Update lightmass UpdateBuildLighting(); - - - ICrashTrackerModule* CrashTracker = FModuleManager::LoadModulePtr( FName("CrashTracker") ); - bool bCrashTrackerEnabled = false; - if (CrashTracker) - { - CrashTracker->Update(DeltaSeconds); - bCrashTrackerEnabled = CrashTracker->IsCurrentlyCapturing(); - } - - // Only allow live streaming if crash tracker is disabled. This is because the SlateRHIRenderer shares the same render targets - // for both crash tracker and live editor streaming, and we don't want them to be thrashed every frame. - if( !bCrashTrackerEnabled ) - { - // If the editor is configured to broadcast frames, do that now - if( IEditorLiveStreaming::Get().IsBroadcastingEditor() ) - { - IEditorLiveStreaming::Get().BroadcastEditorVideoFrame(); - } - } } @@ -1242,7 +1228,7 @@ void UUnrealEdEngine::FixAnyInvertedBrushes(UWorld* World) for (TActorIterator It(World); It; ++It) { ABrush* Brush = *It; - if (Brush->BrushComponent && Brush->BrushComponent->HasInvertedPolys()) + if (Brush->GetBrushComponent() && Brush->GetBrushComponent()->HasInvertedPolys()) { Brushes.Add(Brush); } @@ -1255,7 +1241,7 @@ void UUnrealEdEngine::FixAnyInvertedBrushes(UWorld* World) UE_LOG(LogUnrealEdEngine, Warning, TEXT("Brush '%s' appears to be inside out - fixing."), *Brush->GetName()); // Invert the polys of the brush - for (FPoly& Poly : Brush->BrushComponent->Brush->Polys->Element) + for (FPoly& Poly : Brush->GetBrushComponent()->Brush->Polys->Element) { Poly.Reverse(); Poly.CalcNormal(); @@ -1270,7 +1256,7 @@ void UUnrealEdEngine::FixAnyInvertedBrushes(UWorld* World) { // Dynamic brushes can be fixed up here FBSPOps::csgPrepMovingBrush(Brush); - Brush->BrushComponent->BuildSimpleBrushCollision(); + Brush->GetBrushComponent()->BuildSimpleBrushCollision(); } Brush->MarkPackageDirty(); diff --git a/Engine/Source/Editor/UnrealEd/Private/UnrealEdMisc.cpp b/Engine/Source/Editor/UnrealEd/Private/UnrealEdMisc.cpp index 61411e5bb162..ccccdf47b6e6 100644 --- a/Engine/Source/Editor/UnrealEd/Private/UnrealEdMisc.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/UnrealEdMisc.cpp @@ -78,6 +78,8 @@ #include "UserActivityTracking.h" #include "Widgets/Docking/SDockTab.h" #include "IVREditorModule.h" +#include "ILauncherPlatform.h" +#include "LauncherPlatformModule.h" #define USE_UNIT_TESTS 0 @@ -273,7 +275,7 @@ void FUnrealEdMisc::OnInit() FUserActivityTracking::SetActivity(FUserActivity(TEXT("EditorInit"), EUserActivityContext::Editor)); FEditorModeRegistry::Initialize(); - GLevelEditorModeTools().ActivateDefaultMode(); + // Are we in immersive mode? const TCHAR* ParsedCmdLine = FCommandLine::Get(); @@ -1788,12 +1790,12 @@ void FUnrealEdMisc::OpenMarketplace(const FString& CustomLocation) } else { - IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get(); + ILauncherPlatform* LauncherPlatform = FLauncherPlatformModule::Get(); - if(DesktopPlatform != nullptr) + if(LauncherPlatform != nullptr) { FOpenLauncherOptions OpenOptions(Location); - if(DesktopPlatform->OpenLauncher(OpenOptions)) + if(LauncherPlatform->OpenLauncher(OpenOptions)) { EventAttributes.Add(FAnalyticsEventAttribute(TEXT("OpenSucceeded"), TEXT("TRUE"))); } @@ -1804,7 +1806,7 @@ void FUnrealEdMisc::OpenMarketplace(const FString& CustomLocation) if(EAppReturnType::Yes == FMessageDialog::Open(EAppMsgType::YesNo, LOCTEXT("InstallMarketplacePrompt", "The Marketplace requires the Epic Games Launcher, which does not seem to be installed on your computer. Would you like to install it now?"))) { FOpenLauncherOptions InstallOptions(true, Location); - if(!DesktopPlatform->OpenLauncher(InstallOptions)) + if(!LauncherPlatform->OpenLauncher(InstallOptions)) { EventAttributes.Add(FAnalyticsEventAttribute(TEXT("InstallSucceeded"), TEXT("FALSE"))); FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(TEXT("Sorry, there was a problem installing the Launcher.\nPlease try to install it manually!"))); diff --git a/Engine/Source/Editor/UnrealEd/Private/UnrealEdPrivatePCH.h b/Engine/Source/Editor/UnrealEd/Private/UnrealEdPrivatePCH.h index c81d7629e8f2..b20cc118b0f0 100644 --- a/Engine/Source/Editor/UnrealEd/Private/UnrealEdPrivatePCH.h +++ b/Engine/Source/Editor/UnrealEd/Private/UnrealEdPrivatePCH.h @@ -34,7 +34,6 @@ #include "Templates/EnableIf.h" #include "Templates/RemoveReference.h" #include "Templates/TypeCompatibleBytes.h" -#include "Templates/AlignOf.h" #include "Templates/ChooseClass.h" #include "Templates/IntegralConstant.h" #include "Templates/IsClass.h" @@ -462,7 +461,6 @@ // From AssetRegistry: #include "AssetData.h" -#include "SharedMapView.h" #include "IAssetRegistry.h" #include "AssetRegistryModule.h" #include "ARFilter.h" diff --git a/Engine/Source/Editor/UnrealEd/Private/UnrealEdSrv.cpp b/Engine/Source/Editor/UnrealEd/Private/UnrealEdSrv.cpp index f1563b5fc14c..50d3e3d666ee 100644 --- a/Engine/Source/Editor/UnrealEd/Private/UnrealEdSrv.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/UnrealEdSrv.cpp @@ -37,6 +37,7 @@ #include "CookOnTheSide/CookOnTheFlyServer.h" #include "Builders/CubeBuilder.h" #include "Settings/LevelEditorViewportSettings.h" +#include "Settings/LevelEditorMiscSettings.h" #include "Engine/Brush.h" #include "AssetData.h" #include "Editor/EditorEngine.h" @@ -99,6 +100,7 @@ #if PLATFORM_WINDOWS #include "WindowsHWrapper.h" #endif +#include "ActorGroupingUtils.h" DEFINE_LOG_CATEGORY_STATIC(LogUnrealEdSrv, Log, All); @@ -661,8 +663,8 @@ bool UUnrealEdEngine::Exec( UWorld* InWorld, const TCHAR* Stream, FOutputDevice& Pkg = GeneratePackageThumbnailsIfRequired( Str, Ar, ThumbNamesToUnload ); } - // If we don't have a viewport specified to catch the stat commands (and there's no game viewport), use to the active viewport - if (GStatProcessingViewportClient == NULL && GameViewport == NULL) + // If we don't have a viewport specified to catch the stat commands, use to the active viewport. If there is a game viewport ignore this as we do not want + if (GStatProcessingViewportClient == NULL && (GameViewport == NULL || GameViewport->IsSimulateInEditorViewport() ) ) { GStatProcessingViewportClient = GLastKeyLevelEditingViewportClient ? GLastKeyLevelEditingViewportClient : GCurrentLevelEditingViewportClient; } @@ -1079,7 +1081,7 @@ bool UUnrealEdEngine::Exec( UWorld* InWorld, const TCHAR* Stream, FOutputDevice& SlowTask.EnterProgressFrame(); // Optimization - check the asset has import information before loading it - TOptional ImportInfo = FAssetSourceFilenameCache::ExtractAssetImportInfo(Asset.TagsAndValues); + TOptional ImportInfo = FAssetSourceFilenameCache::ExtractAssetImportInfo(Asset); if (ImportInfo.IsSet() && ImportInfo->SourceFiles.Num()) { RemoveSourcePath(ImportInfo.GetValue(), Asset, SearchTerms); @@ -1202,7 +1204,7 @@ bool UUnrealEdEngine::Exec( UWorld* InWorld, const TCHAR* Stream, FOutputDevice& if (FSlateApplication::Get().TakeScreenshot(InWidget, OutImageData, OutImageSize)) { FString FileName; - const FString BaseFileName = FPaths::ScreenShotDir() / TEXT("EditorScreenshot"); + const FString BaseFileName = GetDefault()->EditorScreenshotSaveDirectory.Path / TEXT("EditorScreenshot"); FFileHelper::GenerateNextBitmapFilename(BaseFileName, TEXT("bmp"), FileName); FFileHelper::CreateBitmap(*FileName, OutImageSize.X, OutImageSize.Y, OutImageData.GetData()); } @@ -1741,9 +1743,9 @@ static void MirrorActors(const FVector& MirrorScale) Actor->EditorApplyMirror( MirrorScale, PivotLocation ); ABrush* Brush = Cast< ABrush >(Actor); - if (Brush && Brush->BrushComponent) + if (Brush && Brush->GetBrushComponent()) { - Brush->BrushComponent->RequestUpdateBrushCollision(); + Brush->GetBrushComponent()->RequestUpdateBrushCollision(); } Actor->InvalidateLightingCache(); @@ -2762,7 +2764,7 @@ bool UUnrealEdEngine::Exec_Actor( UWorld* InWorld, const TCHAR* Str, FOutputDevi } else if( FParse::Command(&Str,TEXT("MOVETOCURRENT")) ) { - MoveSelectedActorsToLevel( InWorld->GetCurrentLevel() ); + UEditorLevelUtils::MoveSelectedActorsToLevel( InWorld->GetCurrentLevel() ); return true; } else if(FParse::Command(&Str, TEXT("DESELECT"))) @@ -3009,16 +3011,16 @@ bool UUnrealEdEngine::Exec_Mode( const TCHAR* Str, FOutputDevice& Ar ) bool UUnrealEdEngine::Exec_Group( const TCHAR* Str, FOutputDevice& Ar ) { - if(GEditor->bGroupingActive) + if(UActorGroupingUtils::IsGroupingActive()) { if( FParse::Command(&Str,TEXT("REGROUP")) ) { - GUnrealEd->edactRegroupFromSelected(); + UActorGroupingUtils::Get()->GroupSelected(); return true; } else if ( FParse::Command(&Str,TEXT("UNGROUP")) ) { - GUnrealEd->edactUngroupFromSelected(); + UActorGroupingUtils::Get()->UngroupSelected(); return true; } } diff --git a/Engine/Source/Editor/UnrealEd/Private/UnrealWidget.cpp b/Engine/Source/Editor/UnrealEd/Private/UnrealWidget.cpp index fdc2415cb147..479fa78a18e4 100644 --- a/Engine/Source/Editor/UnrealEd/Private/UnrealWidget.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/UnrealWidget.cpp @@ -630,7 +630,7 @@ void FWidget::Render_Translate( const FSceneView* View, FPrimitiveDrawInterface* const FVector CameraZAxis = View->ViewMatrices.GetViewMatrix().GetColumn(2); UMaterialInstanceDynamic* XYZMaterial = ( CurrentAxis&EAxisList::Screen) ? CurrentAxisMaterial : OpaquePlaneMaterialXY; - DrawSphere( PDI, InLocation, 4.0f * Space.Scale, 10, 5, XYZMaterial->GetRenderProxy(false), SDPG_Foreground ); + DrawSphere( PDI, InLocation, FRotator::ZeroRotator, 4.0f * Space.Scale, 10, 5, XYZMaterial->GetRenderProxy(false), SDPG_Foreground ); PDI->SetHitProxy( NULL ); } diff --git a/Engine/Source/Editor/UnrealEd/Private/UserDefinedStructEditorData.cpp b/Engine/Source/Editor/UnrealEd/Private/UserDefinedStructEditorData.cpp index 1ffafb476462..cf849f85e51c 100644 --- a/Engine/Source/Editor/UnrealEd/Private/UserDefinedStructEditorData.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/UserDefinedStructEditorData.cpp @@ -10,22 +10,28 @@ #define LOCTEXT_NAMESPACE "UserDefinedStructEditorData" +void FStructVariableDescription::PostSerialize(const FArchive& Ar) +{ + if (ContainerType == EPinContainerType::None) + { + ContainerType = FEdGraphPinType::ToPinContainerType(bIsArray_DEPRECATED, bIsSet_DEPRECATED, bIsMap_DEPRECATED); + } +} + bool FStructVariableDescription::SetPinType(const FEdGraphPinType& VarType) { Category = VarType.PinCategory; SubCategory = VarType.PinSubCategory; SubCategoryObject = VarType.PinSubCategoryObject.Get(); PinValueType = VarType.PinValueType; - bIsArray = VarType.bIsArray; - bIsSet = VarType.bIsSet; - bIsMap = VarType.bIsMap; + ContainerType = VarType.ContainerType; return !VarType.bIsReference && !VarType.bIsWeakPointer; } FEdGraphPinType FStructVariableDescription::ToPinType() const { - return FEdGraphPinType(Category, SubCategory, SubCategoryObject.Get(), bIsArray, false, bIsSet, bIsMap, PinValueType); + return FEdGraphPinType(Category, SubCategory, SubCategoryObject.LoadSynchronous(), ContainerType, false, PinValueType); } UUserDefinedStructEditorData::UUserDefinedStructEditorData(const FObjectInitializer& ObjectInitializer) @@ -138,7 +144,7 @@ void UUserDefinedStructEditorData::RecreateDefaultInstance(FString* OutLog) if (!FBlueprintEditorUtils::PropertyValueFromString(Property, VarDesc->CurrentDefaultValue, StructData)) { const FString Message = FString::Printf(TEXT("Cannot parse value. Property: %s String: \"%s\" ") - , (Property ? *Property->GetDisplayNameText().ToString() : TEXT("None")) + , *Property->GetDisplayNameText().ToString() , *VarDesc->CurrentDefaultValue); UE_LOG(LogClass, Warning, TEXT("UUserDefinedStructEditorData::RecreateDefaultInstance %s Struct: %s "), *Message, *GetPathNameSafe(ScriptStruct)); if (OutLog) diff --git a/Engine/Source/Editor/UnrealEd/Private/VertexSnapping.cpp b/Engine/Source/Editor/UnrealEd/Private/VertexSnapping.cpp index 033edf167687..7f747949d7c9 100644 --- a/Engine/Source/Editor/UnrealEd/Private/VertexSnapping.cpp +++ b/Engine/Source/Editor/UnrealEd/Private/VertexSnapping.cpp @@ -76,7 +76,7 @@ class FStaticMeshVertexIterator : public FVertexIterator { public: FStaticMeshVertexIterator( UStaticMeshComponent* SMC ) - : ComponentToWorldIT( SMC->ComponentToWorld.ToInverseMatrixWithScale().GetTransposed() ) + : ComponentToWorldIT( SMC->GetComponentTransform().ToInverseMatrixWithScale().GetTransposed() ) , StaticMeshComponent( SMC ) , PositionBuffer( SMC->GetStaticMesh()->RenderData->LODResources[0].PositionVertexBuffer ) , VertexBuffer( SMC->GetStaticMesh()->RenderData->LODResources[0].VertexBuffer ) @@ -88,7 +88,7 @@ public: /** FVertexIterator interface */ virtual FVector Position() override { - return StaticMeshComponent->ComponentToWorld.TransformPosition( PositionBuffer.VertexPosition( CurrentVertexIndex ) ); + return StaticMeshComponent->GetComponentTransform().TransformPosition( PositionBuffer.VertexPosition( CurrentVertexIndex ) ); } virtual FVector Normal() override @@ -144,7 +144,7 @@ public: /** FVertexIterator interface */ virtual FVector Position() override { - return BrushComponent->ComponentToWorld.TransformPosition( Vertices[CurrentVertexIndex] ); + return BrushComponent->GetComponentTransform().TransformPosition( Vertices[CurrentVertexIndex] ); } /** FVertexIterator interface */ @@ -181,7 +181,7 @@ class FSkeletalMeshVertexIterator : public FVertexIterator { public: FSkeletalMeshVertexIterator( USkinnedMeshComponent* InSkinnedMeshComp ) - : ComponentToWorldIT( InSkinnedMeshComp->ComponentToWorld.ToInverseMatrixWithScale().GetTransposed() ) + : ComponentToWorldIT( InSkinnedMeshComp->GetComponentTransform().ToInverseMatrixWithScale().GetTransposed() ) , SkinnedMeshComponent( InSkinnedMeshComp ) , LODModel( InSkinnedMeshComp->GetSkeletalMeshResource()->LODModels[0] ) , CurrentSectionIndex( 0 ) @@ -194,7 +194,7 @@ public: virtual FVector Position() override { const FSkelMeshSection& Section = LODModel.Sections[CurrentSectionIndex]; - return SkinnedMeshComponent->ComponentToWorld.TransformPosition(Section.SoftVertices[SoftVertexIndex].Position ); + return SkinnedMeshComponent->GetComponentTransform().TransformPosition(Section.SoftVertices[SoftVertexIndex].Position ); } virtual FVector Normal() override diff --git a/Engine/Source/Editor/UnrealEd/Public/ActorGroupingUtils.h b/Engine/Source/Editor/UnrealEd/Public/ActorGroupingUtils.h new file mode 100644 index 000000000000..3ee549a46ff9 --- /dev/null +++ b/Engine/Source/Editor/UnrealEd/Public/ActorGroupingUtils.h @@ -0,0 +1,83 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" + +#include "ActorGroupingUtils.generated.h" + +/** + * Helper class for grouping actors in the level editor + */ +UCLASS(transient) +class UNREALED_API UActorGroupingUtils : public UObject +{ + GENERATED_BODY() +public: + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Actor Grouping") + static bool IsGroupingActive() { return bGroupingActive; } + + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Actor Grouping") + static void SetGroupingActive(bool bInGroupingActive); + + /** + * Convenience method for accessing grouping utils in a blueprint or script + */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Actor Grouping", DisplayName="Get Actor Grouping Utils") + static UActorGroupingUtils* Get(); + + /** + * Creates a new group from the current selection removing the actors from any existing groups they are already in + */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Actor Grouping") + virtual void GroupSelected(); + + /** + * Creates a new group from the provided list of actors removing the actors from any existing groups they are already in + */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Actor Grouping") + virtual void GroupActors(const TArray& ActorsToGroup); + + /** + * Disbands any groups in the current selection, does not attempt to maintain any hierarchy + */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Actor Grouping") + virtual void UngroupSelected(); + + /** + * Disbands any groups that the provided actors belong to, does not attempt to maintain any hierarchy + */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Actor Grouping") + virtual void UngroupActors(const TArray& ActorsToUngroup); + + /** + * Locks any groups in the current selection + */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Actor Grouping") + virtual void LockSelectedGroups(); + + /** + * Unlocks any groups in the current selection + */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Actor Grouping") + virtual void UnlockSelectedGroups(); + + /** + * Activates "Add to Group" mode which allows the user to select a group to append current selection + */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Actor Grouping") + virtual void AddSelectedToGroup(); + + /** + * Removes any groups or actors in the current selection from their immediate parent. + * If all actors/subgroups are removed, the parent group will be destroyed. + */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Actor Grouping") + virtual void RemoveSelectedFromGroup(); + +protected: + static bool bGroupingActive; + static FStringClassReference ClassToUse; +}; + + diff --git a/Engine/Source/Editor/UnrealEd/Public/AutoReimport/AssetSourceFilenameCache.h b/Engine/Source/Editor/UnrealEd/Public/AutoReimport/AssetSourceFilenameCache.h index ac3c051815cf..0080f099d9ce 100644 --- a/Engine/Source/Editor/UnrealEd/Public/AutoReimport/AssetSourceFilenameCache.h +++ b/Engine/Source/Editor/UnrealEd/Public/AutoReimport/AssetSourceFilenameCache.h @@ -9,7 +9,6 @@ class IAssetRegistry; -template class TSharedMapView; /** Class responsible for maintaing a cache of clean source file names (bla.txt) to asset data */ class UNREALED_API FAssetSourceFilenameCache @@ -21,8 +20,7 @@ public: static FAssetSourceFilenameCache& Get(); /** Helper functions to extract asset import information from asset registry tags */ - static TOptional ExtractAssetImportInfo(const TSharedMapView& InTags); - static TOptional ExtractAssetImportInfo(const TArray& InTags); + static TOptional ExtractAssetImportInfo(const FAssetData& AssetData); /** Retrieve a list of assets that were imported from the specified filename */ TArray GetAssetsPertainingToFile(const IAssetRegistry& Registry, const FString& AbsoluteFilename) const; diff --git a/Engine/Source/Editor/UnrealEd/Public/AutomatedAssetImportData.h b/Engine/Source/Editor/UnrealEd/Public/AutomatedAssetImportData.h index 7e686fbf06bc..152621e32ef9 100644 --- a/Engine/Source/Editor/UnrealEd/Public/AutomatedAssetImportData.h +++ b/Engine/Source/Editor/UnrealEd/Public/AutomatedAssetImportData.h @@ -15,7 +15,7 @@ DECLARE_LOG_CATEGORY_EXTERN(LogAutomatedImport, Log, All); /** * Contains data for a group of assets to import */ -UCLASS(Transient) +UCLASS(Transient, BlueprintType) class UNREALED_API UAutomatedAssetImportData : public UObject { GENERATED_BODY() @@ -33,31 +33,31 @@ public: FString GetDisplayName() const; public: /** Display name of the group. This is for logging purposes only. */ - UPROPERTY() + UPROPERTY(BlueprintReadWrite, Category="Asset Import Data") FString GroupName; /** Filenames to import */ - UPROPERTY() + UPROPERTY(BlueprintReadWrite, Category = "Asset Import Data") TArray Filenames; /** Content path in the projects content directory where assets will be imported */ - UPROPERTY() + UPROPERTY(BlueprintReadWrite, Category = "Asset Import Data") FString DestinationPath; /** Name of the factory to use when importing these assets. If not specified the factory type will be auto detected */ - UPROPERTY() + UPROPERTY(BlueprintReadWrite, Category = "Asset Import Data") FString FactoryName; /** Whether or not to replace existing assets */ - UPROPERTY() + UPROPERTY(BlueprintReadWrite, Category = "Asset Import Data") bool bReplaceExisting; /** Whether or not to skip importing over read only assets that could not be checked out */ - UPROPERTY() + UPROPERTY(BlueprintReadWrite, Category = "Asset Import Data") bool bSkipReadOnly; /** Pointer to the factory currently being sued */ - UPROPERTY() + UPROPERTY(BlueprintReadWrite, Category = "Asset Import Data") UFactory* Factory; /** Json data to be read when importing this group */ diff --git a/Engine/Source/Editor/UnrealEd/Public/Commandlets/AssetRegistryGenerator.h b/Engine/Source/Editor/UnrealEd/Public/Commandlets/AssetRegistryGenerator.h index 136d57b95f47..876581cf4861 100644 --- a/Engine/Source/Editor/UnrealEd/Public/Commandlets/AssetRegistryGenerator.h +++ b/Engine/Source/Editor/UnrealEd/Public/Commandlets/AssetRegistryGenerator.h @@ -51,8 +51,9 @@ public: * @param RemovedPackages list of packages that existed before, but do not any more * @param IdenticalCookedPackages list of cooked packages that have not changed * @param IdenticalUncookedPackages list of uncooked packages that have not changed. These were filtered out by platform or editor only + * @param bRecurseModifications if true, modified packages are recursed to X in X->Y->Z chains. Otherwise, only Y and Z are seen as modified */ - void ComputePackageDifferences(TSet& ModifiedPackages, TSet& NewPackages, TSet& RemovedPackages, TSet& IdenticalCookedPackages, TSet& IdenticalUncookedPackages); + void ComputePackageDifferences(TSet& ModifiedPackages, TSet& NewPackages, TSet& RemovedPackages, TSet& IdenticalCookedPackages, TSet& IdenticalUncookedPackages, bool bRecurseModifications); /** * GenerateChunkManifest @@ -112,7 +113,7 @@ public: /** * Saves generated asset registry data for each platform. */ - bool SaveAssetRegistry(const FString& SandboxPath); + bool SaveAssetRegistry(const FString& SandboxPath, bool bSerializeDevelopmentAssetRegistry = true); /** * Writes out CookerOpenOrder.log file @@ -256,7 +257,7 @@ private: } } - if ( StartupPackages.Contains(PackageFName )) + if (StartupPackages.Contains(PackageFName)) { ExistingChunkIDs.AddUnique(0); } diff --git a/Engine/Source/Editor/UnrealEd/Public/DataTableEditorUtils.h b/Engine/Source/Editor/UnrealEd/Public/DataTableEditorUtils.h index e66a120ad301..bd6a6df10ba7 100644 --- a/Engine/Source/Editor/UnrealEd/Public/DataTableEditorUtils.h +++ b/Engine/Source/Editor/UnrealEd/Public/DataTableEditorUtils.h @@ -59,6 +59,8 @@ struct UNREALED_API FDataTableEditorUtils class UNREALED_API ListenerType : public InnerListenerType { + public: + virtual void SelectionChange(const UDataTable* DataTable, FName RowName) { } }; }; @@ -68,6 +70,7 @@ struct UNREALED_API FDataTableEditorUtils static uint8* AddRow(UDataTable* DataTable, FName RowName); static bool RenameRow(UDataTable* DataTable, FName OldName, FName NewName); static bool MoveRow(UDataTable* DataTable, FName RowName, ERowMoveDirection Direction, int32 NumRowsToMoveBy = 1); + static bool SelectRow(UDataTable* DataTable, FName RowName); static bool DiffersFromDefault(UDataTable* DataTable, FName RowName); static bool ResetToDefault(UDataTable* DataTable, FName RowName); diff --git a/Engine/Source/Editor/UnrealEd/Public/DragAndDrop/AssetDragDropOp.h b/Engine/Source/Editor/UnrealEd/Public/DragAndDrop/AssetDragDropOp.h index d6f2862db954..8429c8a5c10e 100644 --- a/Engine/Source/Editor/UnrealEd/Public/DragAndDrop/AssetDragDropOp.h +++ b/Engine/Source/Editor/UnrealEd/Public/DragAndDrop/AssetDragDropOp.h @@ -12,14 +12,67 @@ class FAssetThumbnail; class FAssetThumbnailPool; class UActorFactory; -class FAssetDragDropOp : public FDecoratedDragDropOp +class UNREALED_API FAssetDragDropOp : public FDecoratedDragDropOp { public: DRAG_DROP_OPERATOR_TYPE(FAssetDragDropOp, FDecoratedDragDropOp) - /** Data for the asset this item represents */ + static TSharedRef New(const FAssetData& InAssetData, UActorFactory* ActorFactory = nullptr); + + static TSharedRef New(TArray InAssetData, UActorFactory* ActorFactory = nullptr); + + static TSharedRef New(FString InAssetPath); + + static TSharedRef New(TArray InAssetPaths); + + static TSharedRef New(TArray InAssetData, TArray InAssetPaths, UActorFactory* ActorFactory = nullptr); + + /** @return true if this drag operation contains assets */ + bool HasAssets() const + { + return AssetData.Num() > 0; + } + + /** @return true if this drag operation contains asset paths */ + bool HasAssetPaths() const + { + return AssetPaths.Num() > 0; + } + + /** @return The assets from this drag operation */ + const TArray& GetAssets() const + { + return AssetData; + } + + /** @return The asset paths from this drag operation */ + const TArray& GetAssetPaths() const + { + return AssetPaths; + } + + /** @return The actor factory to use if converting this asset to an actor */ + UActorFactory* GetActorFactory() const + { + return ActorFactory.Get(); + } + +public: + virtual ~FAssetDragDropOp(); + + virtual TSharedPtr GetDefaultDecorator() const override; + + FText GetDecoratorText() const; + +private: + void Init(); + + /** Data for the assets this item represents */ TArray AssetData; + /** Data for the asset paths this item represents */ + TArray AssetPaths; + /** Pool for maintaining and rendering thumbnails */ TSharedPtr ThumbnailPool; @@ -27,21 +80,8 @@ public: TSharedPtr AssetThumbnail; /** The actor factory to use if converting this asset to an actor */ - TWeakObjectPtr< UActorFactory > ActorFactory; + TWeakObjectPtr ActorFactory; - UNREALED_API static TSharedRef New(const FAssetData& InAssetData, UActorFactory* ActorFactory = NULL); - - UNREALED_API static TSharedRef New(const TArray& InAssetData, UActorFactory* ActorFactory = NULL); - -public: - UNREALED_API virtual ~FAssetDragDropOp(); - - UNREALED_API virtual TSharedPtr GetDefaultDecorator() const override; - - UNREALED_API void Init(); - - UNREALED_API EVisibility GetTooltipVisibility() const; - -private: + /** The size of the thumbnail */ int32 ThumbnailSize; }; diff --git a/Engine/Source/Editor/UnrealEd/Public/DragAndDrop/AssetPathDragDropOp.h b/Engine/Source/Editor/UnrealEd/Public/DragAndDrop/AssetPathDragDropOp.h deleted file mode 100644 index c3c165278fea..000000000000 --- a/Engine/Source/Editor/UnrealEd/Public/DragAndDrop/AssetPathDragDropOp.h +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "CoreMinimal.h" -#include "Input/DragAndDrop.h" -#include "Widgets/DeclarativeSyntaxSupport.h" -#include "Widgets/SBoxPanel.h" -#include "EditorStyleSet.h" -#include "Widgets/Layout/SBorder.h" -#include "Widgets/Images/SImage.h" -#include "Widgets/Text/STextBlock.h" -#include "DragAndDrop/DecoratedDragDropOp.h" - -class FAssetPathDragDropOp : public FDecoratedDragDropOp -{ -public: - DRAG_DROP_OPERATOR_TYPE(FAssetPathDragDropOp, FDecoratedDragDropOp) - - /** Data for the asset this item represents */ - TArray PathNames; - - static TSharedRef New(const TArray& InPathNames) - { - TSharedRef Operation = MakeShareable(new FAssetPathDragDropOp); - - Operation->MouseCursor = EMouseCursor::GrabHandClosed; - Operation->PathNames = InPathNames; - Operation->Construct(); - - return Operation; - } - -public: - FText GetDecoratorText() const - { - if ( CurrentHoverText.IsEmpty() && PathNames.Num() > 0 ) - { - return (PathNames.Num() == 1) - ? FText::FromString(PathNames[0]) - : FText::Format(NSLOCTEXT("ContentBrowser", "FolderDescriptionMulti", "{0} and {1} {1}|plural(one=other,other=others)"), FText::FromString(PathNames[0]), PathNames.Num() - 1); - } - - return CurrentHoverText; - } - - virtual TSharedPtr GetDefaultDecorator() const override - { - return - SNew(SBorder) - .BorderImage(FEditorStyle::GetBrush("ContentBrowser.AssetDragDropTooltipBackground")) - .Content() - [ - SNew(SHorizontalBox) - - // Left slot is folder icon - + SHorizontalBox::Slot() - .AutoWidth() - .VAlign(VAlign_Center) - [ - SNew(SImage) - .Image(FEditorStyle::GetBrush("ContentBrowser.AssetTreeFolderClosed")) - ] - - // Right slot is for tooltip - + SHorizontalBox::Slot() - .AutoWidth() - .VAlign(VAlign_Center) - [ - SNew(SHorizontalBox) - - + SHorizontalBox::Slot() - .AutoWidth() - .Padding(3.0f) - .VAlign(VAlign_Center) - [ - SNew(SImage) - .Image(this, &FAssetPathDragDropOp::GetIcon) - ] - - +SHorizontalBox::Slot() - .AutoWidth() - .Padding(0,0,3,0) - .VAlign(VAlign_Center) - [ - SNew(STextBlock) - .Text(this, &FAssetPathDragDropOp::GetDecoratorText) - ] - ] - ]; - } -}; diff --git a/Engine/Source/Editor/UnrealEd/Public/DragAndDrop/LevelDragDropOp.h b/Engine/Source/Editor/UnrealEd/Public/DragAndDrop/LevelDragDropOp.h index a6ba0135e6a8..8516bfaaf14e 100644 --- a/Engine/Source/Editor/UnrealEd/Public/DragAndDrop/LevelDragDropOp.h +++ b/Engine/Source/Editor/UnrealEd/Public/DragAndDrop/LevelDragDropOp.h @@ -4,7 +4,7 @@ #include "CoreMinimal.h" #include "Engine/Level.h" #include "Widgets/DeclarativeSyntaxSupport.h" -#include "Input/DragAndDrop.h" +#include "DragAndDrop/DecoratedDragDropOp.h" #include "Engine/LevelStreaming.h" #include "EditorStyleSet.h" #include "UObject/Package.h" @@ -12,10 +12,10 @@ #include "Widgets/Text/STextBlock.h" #include "Widgets/SBoxPanel.h" -class FLevelDragDropOp : public FDragDropOperation +class FLevelDragDropOp : public FDecoratedDragDropOp { public: - DRAG_DROP_OPERATOR_TYPE(FLevelDragDropOp, FDragDropOperation) + DRAG_DROP_OPERATOR_TYPE(FLevelDragDropOp, FDecoratedDragDropOp) /** The levels to be dropped. */ TArray> LevelsToDrop; @@ -25,27 +25,31 @@ public: /** Whether content is good to drop on current site, used by decorator */ bool bGoodToDrop; - + + /** Inits the tooltip */ + void Init() + { + FString DefaultLevel(TEXT("None")); + + if (LevelsToDrop.Num() > 0 && LevelsToDrop[0].IsValid()) + { + DefaultLevel = LevelsToDrop[0]->GetOutermost()->GetName(); + } + else if (StreamingLevelsToDrop.Num() > 0 && StreamingLevelsToDrop[0].IsValid()) + { + DefaultLevel = StreamingLevelsToDrop[0]->GetWorldAssetPackageName(); + } + + CurrentHoverText = FText::FromString(DefaultLevel); + + bGoodToDrop = LevelsToDrop.Num() > 0 || StreamingLevelsToDrop.Num() > 0; + + SetupDefaults(); + } + /** The widget decorator to use */ virtual TSharedPtr GetDefaultDecorator() const override { - FString LevelName(TEXT("None")); - - if (LevelsToDrop.Num()) - { - if (LevelsToDrop[0].IsValid()) - { - LevelName = LevelsToDrop[0]->GetOutermost()->GetName(); - } - } - else if (StreamingLevelsToDrop.Num()) - { - if (StreamingLevelsToDrop[0].IsValid()) - { - LevelName = StreamingLevelsToDrop[0]->GetWorldAssetPackageName(); - } - } - return SNew(SBorder) .BorderImage(FEditorStyle::GetBrush("Graph.ConnectorFeedback.Border")) .Content() @@ -55,7 +59,7 @@ public: .AutoWidth() [ SNew(STextBlock) - .Text( FText::FromString(LevelName) ) + .Text( this, &FDecoratedDragDropOp::GetHoverText ) ] ]; } @@ -64,7 +68,7 @@ public: { TSharedRef Operation = MakeShareable(new FLevelDragDropOp); Operation->StreamingLevelsToDrop.Append(LevelsToDrop); - Operation->bGoodToDrop = true; + Operation->Init(); Operation->Construct(); return Operation; } @@ -73,7 +77,7 @@ public: { TSharedRef Operation = MakeShareable(new FLevelDragDropOp); Operation->LevelsToDrop.Append(LevelsToDrop); - Operation->bGoodToDrop = true; + Operation->Init(); Operation->Construct(); return Operation; } diff --git a/Engine/Source/Editor/UnrealEd/Public/EditorCategoryUtils.h b/Engine/Source/Editor/UnrealEd/Public/EditorCategoryUtils.h index 8cd7f2d48a97..634939b77b4e 100644 --- a/Engine/Source/Editor/UnrealEd/Public/EditorCategoryUtils.h +++ b/Engine/Source/Editor/UnrealEd/Public/EditorCategoryUtils.h @@ -74,7 +74,7 @@ namespace FEditorCategoryUtils * @param Category The qualified category path that you want the key expanded to. * @param Tooltip An optional tooltip text to use for the category. If not specified an attempt to find it from the NodeCategories UDN file will be made */ - UNREALED_API void RegisterCategoryKey(FString const& Key, FText const& Category, FText const& Tooltip = FText::GetEmpty()); + UNREALED_API void RegisterCategoryKey(const FString& Key, const FText& Category, const FText& Tooltip = FText::GetEmpty()); /** * @param Key A string key that people will use in metadata to reflect this category mapping. @@ -82,7 +82,7 @@ namespace FEditorCategoryUtils * @param DocLink Path to the document page that contains the excerpt for this category * @param DocExcerpt Name of the excerpt within the document page for this category */ - UNREALED_API void RegisterCategoryKey(FString const& Key, FText const& Category, FString const& DocLink, FString const& DocExcerpt); + UNREALED_API void RegisterCategoryKey(const FString& Key, const FText& Category, const FString& DocLink, const FString& DocExcerpt); /** * Retrieves a qualified category path for the desired common category. @@ -90,7 +90,7 @@ namespace FEditorCategoryUtils * @param CategoryId The common category you want a path for. * @return A text string, (empty if the common category was not registered) */ - UNREALED_API FText const& GetCommonCategory(const FCommonEditorCategory::EValue CategoryId); + UNREALED_API const FText& GetCommonCategory(const FCommonEditorCategory::EValue CategoryId); /** * Utility function that concatenates the supplied sub-category with one @@ -100,7 +100,7 @@ namespace FEditorCategoryUtils * @param SubCategory A sub-category that you want postfixed to the root category. * @return A concatenated text string, with the two categories separated by a pipe, '|', character. */ - UNREALED_API FText BuildCategoryString(const FCommonEditorCategory::EValue RootCategory, FText const& SubCategory); + UNREALED_API FText BuildCategoryString(const FCommonEditorCategory::EValue RootCategory, const FText& SubCategory); /** * Expands any keys found in the category string (any terms found in square @@ -110,7 +110,7 @@ namespace FEditorCategoryUtils * @param SubCategory A sub-category that you want postfixing the result. * @return A concatenated text string, with the two categories separated by a pipe, '|', character. */ - UNREALED_API FText GetCategoryDisplayString(FText const& UnsanitizedCategory); + UNREALED_API FText GetCategoryDisplayString(const FText& UnsanitizedCategory); /** * Expands any keys found in the category string (any terms found in square @@ -120,7 +120,7 @@ namespace FEditorCategoryUtils * @param SubCategory A sub-category that you want postfixing the result. * @return A concatenated string, with the two categories separated by a pipe, '|', character. */ - UNREALED_API FString GetCategoryDisplayString(FString const& UnsanitizedCategory); + UNREALED_API FString GetCategoryDisplayString(const FString& UnsanitizedCategory); /** * Parses out the class's "HideCategories" metadata, and returns it @@ -130,7 +130,7 @@ namespace FEditorCategoryUtils * @param CategoriesOut An array that will be filled with a list of hidden categories. * @param bHomogenize Determines if the categories should be ran through expansion and display sanitation (useful even when not being displayed, for comparisons) */ - UNREALED_API void GetClassHideCategories(UClass const* Class, TArray& CategoriesOut, bool bHomogenize = true); + UNREALED_API void GetClassHideCategories(const UClass* Class, TArray& CategoriesOut, bool bHomogenize = true); /** * Parses out the class's "ShowCategories" metadata, and returns it @@ -139,7 +139,7 @@ namespace FEditorCategoryUtils * @param Class The class you want to pull data from. * @param CategoriesOut An array that will be filled with a list of shown categories. */ - UNREALED_API void GetClassShowCategories(UClass const* Class, TArray& CategoriesOut); + UNREALED_API void GetClassShowCategories(const UClass* Class, TArray& CategoriesOut); /** * Checks to see if the category associated with the supplied common @@ -149,7 +149,7 @@ namespace FEditorCategoryUtils * @param CategoryId An id associated with a category that you want to check. * @return True if the common category is hidden, false if not. */ - UNREALED_API bool IsCategoryHiddenFromClass(UClass const* Class, const FCommonEditorCategory::EValue CategoryId); + UNREALED_API bool IsCategoryHiddenFromClass(const UClass* Class, const FCommonEditorCategory::EValue CategoryId); /** * Checks to see if the specified category is hidden from the supplied class. @@ -178,7 +178,7 @@ namespace FEditorCategoryUtils * @param Category A category path that you want to check. * @return True if the category is hidden, false if not. */ - UNREALED_API bool IsCategoryHiddenFromClass(const TArray& ClassHideCategories, UClass const* Class, const FString& Category); + UNREALED_API bool IsCategoryHiddenFromClass(const TArray& ClassHideCategories, const UClass* Class, const FString& Category); /** * Returns tooltip information for the specified category * @@ -198,5 +198,5 @@ namespace FEditorCategoryUtils * @param Class The class you want to query. * @return The set of categories that should be hidden. */ - UNREALED_API TSet GetHiddenCategories(UClass const* Class); + UNREALED_API TSet GetHiddenCategories(const UClass* Class); }; diff --git a/Engine/Source/Editor/UnrealEd/Public/EditorComponents.h b/Engine/Source/Editor/UnrealEd/Public/EditorComponents.h index bf8aaaa8faa3..4f9a8e270fb3 100644 --- a/Engine/Source/Editor/UnrealEd/Public/EditorComponents.h +++ b/Engine/Source/Editor/UnrealEd/Public/EditorComponents.h @@ -46,7 +46,7 @@ class FEditorCommonDrawHelper public: UNREALED_API FEditorCommonDrawHelper(); - virtual ~FEditorCommonDrawHelper(); + virtual UNREALED_API ~FEditorCommonDrawHelper(); /** Renders the grid, pivot, and base info. */ virtual void UNREALED_API Draw(const FSceneView* View,FPrimitiveDrawInterface* PDI); diff --git a/Engine/Source/Editor/UnrealEd/Public/EditorLevelUtils.h b/Engine/Source/Editor/UnrealEd/Public/EditorLevelUtils.h index 26fd3f84c965..cab0ac2a3a56 100644 --- a/Engine/Source/Editor/UnrealEd/Public/EditorLevelUtils.h +++ b/Engine/Source/Editor/UnrealEd/Public/EditorLevelUtils.h @@ -7,6 +7,9 @@ #pragma once #include "CoreMinimal.h" +#include "ObjectMacros.h" +#include "SubclassOf.h" +#include "EditorLevelUtils.generated.h" class AActor; class ULevel; @@ -14,18 +17,72 @@ class ULevelStreaming; DECLARE_LOG_CATEGORY_EXTERN(LogLevelTools, Warning, All); - -namespace EditorLevelUtils +UCLASS(transient) +class UEditorLevelUtils : public UObject { - + GENERATED_BODY() +public: /** - * Moves the specified list of actors to the specified level + * Creates a new streaming level in the current world + * + * @param LevelStreamingClass The streaming class type instead to use for the level. + * @param NewLevelPath Optional path to the level package path format ("e.g /Game/MyLevel"). If empty, the user will be prompted during the save process. + * @param bMoveSelectedActorsIntoNewLevel If true, move any selected actors into the new level. + * + * @return Returns the newly created level, or NULL on failure + */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Level Creation") + static UNREALED_API ULevelStreaming* CreateNewStreamingLevel(TSubclassOf LevelStreamingClass, const FString& NewLevelPath = TEXT(""), bool bMoveSelectedActorsIntoNewLevel = false); + + /** + * Makes the specified streaming level the current level for editing. + * The current level is where actors are spawned to when calling SpawnActor + * + * @return true If a level was removed. + */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Level Creation") + static UNREALED_API void MakeLevelCurrent(ULevelStreaming* InStreamingLevel); + + + /** + * Moves the specified list of actors to the specified streaming level. The new actors will be selected * * @param ActorsToMove List of actors to move - * @param DestLevelStreaming The level streaming object associated with the destination level - * @param OutNumMovedActors The number of actors that were successfully moved to the new level + * @param DestStreamingLevel The destination streaming level of the current world to move the actors to + * @return The number of actors that were successfully moved to the new level */ - void MovesActorsToLevel( TArray< AActor* >& ActorsToMove, ULevelStreaming* DestLevelStreaming, int32& OutNumMovedActors ); + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Level Creation") + static UNREALED_API int32 MoveActorsToLevel(const TArray& ActorsToMove, ULevelStreaming* DestStreamingLevel); + + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Level Creation") + static UNREALED_API int32 MoveSelectedActorsToLevel(ULevelStreaming* DestLevel); + + + /** + * Makes the specified level the current level for editing. + * The current level is where actors are spawned to when calling SpawnActor + * + * @return true If a level was removed. + */ + static UNREALED_API void MakeLevelCurrent(ULevel* InLevel); + + + static UNREALED_API int32 MoveActorsToLevel(const TArray& ActorsToMove, ULevel* DestLevel); + + static UNREALED_API int32 MoveSelectedActorsToLevel(ULevel* DestLevel); + + /** + * Creates a new streaming level and adds it to a world + * + * @param InWorld The world to add the streaming level to + * @param LevelStreamingClass The streaming class type instead to use for the level. + * @param DefaultFilename Optional file name for level. If empty, the user will be prompted during the save process. + * @param bMoveSelectedActorsIntoNewLevel If true, move any selected actors into the new level. + * + * @return Returns the newly created level, or NULL on failure + */ + static UNREALED_API ULevelStreaming* CreateNewStreamingLevelForWorld(UWorld& World, TSubclassOf LevelStreamingClass, const FString& DefaultFilename = TEXT(""), bool bMoveSelectedActorsIntoNewLevel = false); + /** * Adds the named level packages to the world. Does nothing if all the levels already exist in the world. @@ -36,7 +93,7 @@ namespace EditorLevelUtils * * @return The new level, or NULL if the level couldn't added. */ - UNREALED_API ULevel* AddLevelsToWorld(UWorld* InWorld, const TArray& LevelPackageNames, UClass* LevelStreamingClass); + static UNREALED_API ULevel* AddLevelsToWorld(UWorld* InWorld, const TArray& LevelPackageNames, UClass* LevelStreamingClass); /** @@ -48,7 +105,7 @@ namespace EditorLevelUtils * * @return The new level, or NULL if the level couldn't added. */ - UNREALED_API ULevel* AddLevelToWorld(UWorld* InWorld, const TCHAR* LevelPackageName, UClass* LevelStreamingClass); + static UNREALED_API ULevelStreaming* AddLevelToWorld(UWorld* InWorld, const TCHAR* LevelPackageName, TSubclassOf LevelStreamingClass); /** Sets the LevelStreamingClass for the specified Level * @param InLevel The level for which to change the streaming class @@ -56,14 +113,14 @@ namespace EditorLevelUtils * * @return The new streaming level object */ - UNREALED_API ULevelStreaming* SetStreamingClassForLevel(ULevelStreaming* InLevel, UClass* LevelStreamingClass); + static UNREALED_API ULevelStreaming* SetStreamingClassForLevel(ULevelStreaming* InLevel, TSubclassOf LevelStreamingClass); /** * Removes the specified level from the world. Refreshes. * * @return true If a level was removed. */ - UNREALED_API bool RemoveLevelFromWorld(ULevel* InLevel); + static UNREALED_API bool RemoveLevelFromWorld(ULevel* InLevel); /** * Removes the specified LevelStreaming from the world, and Refreshes. @@ -71,19 +128,7 @@ namespace EditorLevelUtils * * @return true If a level was removed. */ - UNREALED_API bool RemoveInvalidLevelFromWorld(ULevelStreaming* InLevelStreaming); - - /** - * Creates a new streaming level. - * - * @param InWorld World in which to create the level - * @param bMoveSelectedActorsIntoNewLevel If true, move any selected actors into the new level. - * @param LevelStreamingClass The streaming class type instead to use for the level. - * @param DefaultFilename Optional file name for level. If empty, the user will be prompted during the save process. - * - * @return Returns the newly created level, or NULL on failure - */ - UNREALED_API ULevel* CreateNewLevel(UWorld* InWorld, bool bMoveSelectedActorsIntoNewLevel, UClass* LevelStreamingClass, const FString& DefaultFilename = TEXT( "" ) ); + static UNREALED_API bool RemoveInvalidLevelFromWorld(ULevelStreaming* InLevelStreaming); /** @@ -93,25 +138,7 @@ namespace EditorLevelUtils * @param bShouldBeVisible The level's new visibility state. * @param bForceLayersVisible If true and the level is visible, force the level's layers to be visible. */ - UNREALED_API void SetLevelVisibility(ULevel* Level, bool bShouldBeVisible, bool bForceLayersVisible); - - /** - * Removes a level from the world. Returns true if the level was removed successfully. - * - * @param Level The level to remove from the world. - * @return true if the level was removed successfully, false otherwise. - */ - bool PrivateRemoveLevelFromWorld( ULevel* Level ); - - /** - * Completely removes the level from the world, unloads its package and forces garbage collection. - * - * @note: This function doesn't remove the associated streaming level. - * - * @param InLevel A non-NULL, non-Persistent Level that will be destroyed. - * @return true if the level was removed. - */ - bool EditorDestroyLevel( ULevel* InLevel ); + static UNREALED_API void SetLevelVisibility(ULevel* Level, bool bShouldBeVisible, bool bForceLayersVisible); /** * Deselects all BSP surfaces in this level @@ -119,14 +146,7 @@ namespace EditorLevelUtils * @param InLevel The level to deselect the surfaces of. * */ - UNREALED_API void DeselectAllSurfacesInLevel(ULevel* InLevel); - - /** - * Makes the specified level current. - * - * @return true If a level was removed. - */ - UNREALED_API void MakeLevelCurrent(ULevel* InLevel); + static UNREALED_API void DeselectAllSurfacesInLevel(ULevel* InLevel); /** * Assembles the set of all referenced worlds. @@ -136,6 +156,45 @@ namespace EditorLevelUtils * @param bIncludeInWorld If true, include the InWorld in the output list. * @param bOnlyEditorVisible If true, only sub-levels that should be visible in-editor are included */ - UNREALED_API void GetWorlds(UWorld* InWorld, TArray& OutWorlds, bool bIncludeInWorld, bool bOnlyEditorVisible = false); + static UNREALED_API void GetWorlds(UWorld* InWorld, TArray& OutWorlds, bool bIncludeInWorld, bool bOnlyEditorVisible = false); -} + DEPRECATED(4.17, "The CreateNewLevel method to create streaming levels has been deprecated. Use CreateNewStreamingLevelForWorld instead") + static UNREALED_API ULevel* CreateNewLevel(UWorld* InWorld, bool bMoveSelectedActorsIntoNewLevel, TSubclassOf LevelStreamingClass, const FString& DefaultFilename = TEXT("")); + + + /** + * Moves the specified list of actors to the specified level + * + * @param ActorsToMove List of actors to move + * @param DestLevelStreaming The level streaming object associated with the destination level + * @param OutNumMovedActors The number of actors that were successfully moved to the new level + */ + DEPRECATED(4.17, "The MovesActorsToLevel method has been deprecated. Use MoveActorsToLevel instead") + static void MovesActorsToLevel(TArray< AActor* >& ActorsToMove, ULevelStreaming* DestLevelStreaming, int32& OutNumMovedActors); + +private: + /** + * Removes a level from the world. Returns true if the level was removed successfully. + * + * @param Level The level to remove from the world. + * @return true if the level was removed successfully, false otherwise. + */ + static bool PrivateRemoveLevelFromWorld(ULevel* Level); + + static bool PrivateRemoveInvalidLevelFromWorld(ULevelStreaming* InLevelStreaming); + + /** + * Completely removes the level from the world, unloads its package and forces garbage collection. + * + * @note: This function doesn't remove the associated streaming level. + * + * @param InLevel A non-NULL, non-Persistent Level that will be destroyed. + * @return true if the level was removed. + */ + static bool EditorDestroyLevel(ULevel* InLevel); +private: + +}; + +// For backwards compatibility +typedef UEditorLevelUtils EditorLevelUtils; \ No newline at end of file diff --git a/Engine/Source/Editor/UnrealEd/Public/EditorViewportClient.h b/Engine/Source/Editor/UnrealEd/Public/EditorViewportClient.h index 1c43999f4ac1..d862076f5983 100644 --- a/Engine/Source/Editor/UnrealEd/Public/EditorViewportClient.h +++ b/Engine/Source/Editor/UnrealEd/Public/EditorViewportClient.h @@ -126,6 +126,7 @@ struct FViewportCursorLocation { public: UNREALED_API FViewportCursorLocation( const FSceneView* View, FEditorViewportClient* InViewportClient, int32 X, int32 Y ); + UNREALED_API virtual ~FViewportCursorLocation(); const FVector& GetOrigin() const { return Origin; } const FVector& GetDirection() const { return Direction; } @@ -144,6 +145,7 @@ struct FViewportClick : public FViewportCursorLocation { public: UNREALED_API FViewportClick( const FSceneView* View, FEditorViewportClient* ViewportClient, FKey InKey, EInputEvent InEvent, int32 X, int32 Y ); + UNREALED_API virtual ~FViewportClick(); /** @return The 2D screenspace cursor position of the mouse when it was clicked. */ const FIntPoint& GetClickPos() const { return GetCursorPos(); } @@ -282,9 +284,20 @@ public: void SetRealtime(bool bInRealtime, bool bStoreCurrentValue = false); /** @return True if viewport is in realtime mode, false otherwise. */ - bool IsRealtime() const + bool IsRealtime() const { - return bIsRealtime; + return bIsRealtime || RealTimeFrameCount != 0; + } + + /** + * Get the number of real-time frames to draw (overrides bRealtime) + * @note When non-zero, the viewport will render RealTimeFrameCount frames in real-time mode, then revert back to bIsRealtime + * this can be used to ensure that not only the viewport renders a frame, but also that the world ticks + * @param NumExtraFrames The number of extra real time frames to draw + */ + void RequestRealTimeFrames(uint32 NumRealTimeFrames = 1) + { + RealTimeFrameCount = FMath::Max(NumRealTimeFrames, RealTimeFrameCount); } /** @@ -1041,6 +1054,9 @@ public: /** Returns the map allowing to convert from the viewmode param to a name. */ TMap& GetViewModeParamNameMap() { return ViewModeParamNameMap; } + /** Show or hide the widget. */ + void ShowWidget(const bool bShow); + protected: /** Invalidates the viewport widget (if valid) to register its active timer */ void InvalidateViewportWidget(); @@ -1069,7 +1085,7 @@ protected: /** Should the software cursor be visible */ bool bSoftwareCursorVisible; - /** Should the hardware be visible */ + /** Should the hardware cursor be visible */ bool bHardwareCursorVisible; /** Should the software cursor position be reset to pre-drag */ @@ -1357,6 +1373,9 @@ protected: FWidget* Widget; + /** Whether the widget should be drawn. */ + bool bShowWidget; + FMouseDeltaTracker* MouseDeltaTracker; /**InterpEd, should only be set if used for matinee recording*/ @@ -1418,6 +1437,9 @@ protected: /** If true, force this viewport to use real time audio regardless of other settings */ bool bForceAudioRealtime; + /** Counter to force real-time mode for a number of frames. Overrides bIsRealtime when non-zero. */ + uint32 RealTimeFrameCount; + /** if the viewport is currently realtime */ bool bIsRealtime; diff --git a/Engine/Source/Editor/UnrealEd/Public/EditorWorldExtension.h b/Engine/Source/Editor/UnrealEd/Public/EditorWorldExtension.h index 67918b92c338..29338c4db501 100644 --- a/Engine/Source/Editor/UnrealEd/Public/EditorWorldExtension.h +++ b/Engine/Source/Editor/UnrealEd/Public/EditorWorldExtension.h @@ -81,7 +81,7 @@ protected: virtual void EnteredSimulateInEditor() {}; /** Give child class a chance to act on leaving simulate mode */ - virtual void LeftSimulateInEditor() {}; + virtual void LeftSimulateInEditor(UWorld* SimulateWorld) {}; /** The collection of extensions that is owning this extension */ UEditorWorldExtensionCollection* OwningExtensionsCollection; @@ -124,6 +124,12 @@ public: /** Gets the world context */ FWorldContext* GetWorldContext() const; + /** + * Checks if the passed extension already exists and creates one if it doesn't. + * @param EditorExtensionClass the subclass of an extension to create if necessary and add. + */ + UEditorWorldExtension* AddExtension(TSubclassOf EditorExtensionClass); + /** * Adds an extension to the collection * @param EditorExtension The UEditorExtension that will be created, initialized and added to the collection. diff --git a/Engine/Source/Editor/UnrealEd/Public/Factories.h b/Engine/Source/Editor/UnrealEd/Public/Factories.h index 92097e588619..8ae40e5d860b 100644 --- a/Engine/Source/Editor/UnrealEd/Public/Factories.h +++ b/Engine/Source/Editor/UnrealEd/Public/Factories.h @@ -10,6 +10,8 @@ #include "UObject/Class.h" #include "Animation/MorphTarget.h" +UNREALED_API DECLARE_LOG_CATEGORY_EXTERN(LogEditorFactories, Log, All); + class Error; class USkeletalMesh; class UStaticMesh; @@ -26,6 +28,7 @@ protected: public: /** Constructor for the factory; takes a context for emitting warnings such as GWarn */ FCustomizableTextObjectFactory(FFeedbackContext* InWarningContext); + virtual ~FCustomizableTextObjectFactory() {} /** * Parse a text buffer and factories objects from it, subject to the restrictions imposed by CanCreateClass() @@ -105,6 +108,7 @@ public: FMorphTargetBinaryImport( USkeletalMesh* InSrcMesh, int32 LODIndex=0, FFeedbackContext* InWarn=GWarn ); FMorphTargetBinaryImport( UStaticMesh* InSrcMesh, int32 LODIndex=0, FFeedbackContext* InWarn=GWarn ); + virtual ~FMorphTargetBinaryImport() {} void ImportMorphLODModel( UMorphTarget* MorphTarget, const TCHAR* SrcFilename, int32 LODIndex, EMorphImportError* Error=NULL ); virtual USkeletalMesh* CreateSkeletalMesh(const TCHAR* SrcFilename, EMorphImportError* Error ) = 0; diff --git a/Engine/Source/Editor/UnrealEd/Public/FileHelpers.h b/Engine/Source/Editor/UnrealEd/Public/FileHelpers.h index 7e4b174e2858..6eccd94d8d44 100644 --- a/Engine/Source/Editor/UnrealEd/Public/FileHelpers.h +++ b/Engine/Source/Editor/UnrealEd/Public/FileHelpers.h @@ -5,6 +5,7 @@ #include "CoreMinimal.h" #include "AssetData.h" #include "ISourceControlProvider.h" +#include "FileHelpers.generated.h" class ULevel; @@ -26,6 +27,101 @@ namespace EAutosaveContentPackagesResult }; } +/** + * This class is a wrapper for editor loading and saving functionality + * It is meant to contain only functions that can be executed in script (but are also allowed in C++). + * It is separated from FEditorFileUtils to ensure new easier to use methods can be created without breaking FEditorFileUtils backwards compatibility + * However this should be used in place of FEditorFileUtils wherever possible as the goal is to deprecate FEditorFileUtils eventually + */ +UCLASS(transient) +class UEditorLoadingAndSavingUtils : public UObject +{ + GENERATED_BODY() + +public: + UFUNCTION(BlueprintCallable, Category= "Editor Scripting | Editor Loading and Saving") + static UNREALED_API UWorld* NewBlankMap(bool bSaveExistingMap); + + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Editor Loading and Saving") + static UNREALED_API UWorld* NewMapFromTemplate(const FString& PathToTemplateLevel, bool bSaveExistingMap); + + /** + * Prompts the user to save the current map if necessary, the presents a load dialog and + * loads a new map if selected by the user. + */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Editor Loading and Saving") + static UNREALED_API UWorld* LoadMapWithDialog(); + + /** + * Loads the specified map. Does not prompt the user to save the current map. + * + * @param Filename Level package filename, including path. + * @return true if the map was loaded successfully. + */ + UFUNCTION(BlueprintCallable, Category="Editor Scripting | Editor Loading and Saving") + static UNREALED_API UWorld* LoadMap(const FString& Filename); + + /** + * Saves the specified map, returning true on success. + * + * @param World The world to save. + * @param AssetPath The valid content directory path and name for the asset. E.g "/Game/MyMap" + * + * @return true if the map was saved successfully. + */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Editor Loading and Saving") + static UNREALED_API bool SaveMap(UWorld* World, const FString& AssetPath); + + /** + * Looks at all currently loaded packages and saves them if their "bDirty" flag is set, optionally prompting the user to select which packages to save) + * + * @param bSaveMapPackages true if map packages should be saved + * @param bSaveContentPackages true if we should save content packages. + * @param bPromptUserToSave true if we should prompt the user to save dirty packages we found and check them out from source control(if enabled). False to assume all dirty packages should be saved and checked out + * @return true on success, false on fail. + */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Editor Loading and Saving") + static UNREALED_API bool SaveDirtyPackages(const bool bSaveMapPackages, const bool bSaveContentPackages, const bool bPromptUser); + + /** + * Saves the active level, prompting the use for checkout if necessary. + * + * @return true on success, False on fail + */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Editor Loading and Saving") + static UNREALED_API bool SaveCurrentLevel(); + + /** + * Appends array with all currently dirty map packages. + * + * @param OutDirtyPackages Array to append dirty packages to. + */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Editor Loading and Saving") + static UNREALED_API void GetDirtyMapPackages(TArray& OutDirtyPackages); + + /** + * Appends array with all currently dirty content packages. + * + * @param OutDirtyPackages Array to append dirty packages to. + */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Editor Loading and Saving") + static UNREALED_API void GetDirtyContentPackages(TArray& OutDirtyPackages); + + /** + * Imports a file such as (FBX or obj) and spawns actors f into the current level + */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Editor Loading and Saving") + static UNREALED_API void ImportScene(const FString& Filename); + + + /** + * Exports the current scene + */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Editor Loading and Saving") + static UNREALED_API void ExportScene(bool bExportSelectedActorsOnly); +}; + + /** * For saving map files through the main editor frame. */ @@ -84,7 +180,7 @@ public: * Prompts the user to save the current map if necessary, the presents a load dialog and * loads a new map if selected by the user. */ - static UNREALED_API void LoadMap(); + static UNREALED_API bool LoadMap(); /** * Loads the specified map. Does not prompt the user to save the current map. @@ -93,9 +189,10 @@ public: * * @param LoadAsTemplate Forces the map to load into an untitled outermost package * preventing the map saving over the original file. - * @param bShowProgress Whether to show a progress dialog as the map loads + * @param bShowProgress Whether to show a progress dialog as the map loads\ + * @return true on success, false otherwise */ - static UNREALED_API void LoadMap(const FString& Filename, bool LoadAsTemplate = false, const bool bShowProgress=true); + static UNREALED_API bool LoadMap(const FString& Filename, bool LoadAsTemplate = false, const bool bShowProgress=true); //////////////////////////////////////////////////////////////////////////// // Saving diff --git a/Engine/Source/Editor/UnrealEd/Public/GraphEditor.h b/Engine/Source/Editor/UnrealEd/Public/GraphEditor.h index 6eaa65f24dd1..4326c009daad 100644 --- a/Engine/Source/Editor/UnrealEd/Public/GraphEditor.h +++ b/Engine/Source/Editor/UnrealEd/Public/GraphEditor.h @@ -261,6 +261,16 @@ public: } } + /** Register an active timer on the graph editor. */ + virtual TSharedRef RegisterActiveTimer(float TickPeriod, FWidgetActiveTimerDelegate TickFunction) + { + if (Implementation.IsValid()) + { + return Implementation->RegisterActiveTimer(TickPeriod, TickFunction); + } + return TSharedPtr().ToSharedRef(); + } + /** @return a reference to the list of selected graph nodes */ virtual const TSet& GetSelectedNodes() const { diff --git a/Engine/Source/Editor/UnrealEd/Public/Kismet2/BlueprintEditorUtils.h b/Engine/Source/Editor/UnrealEd/Public/Kismet2/BlueprintEditorUtils.h index a299d3057bfb..208ee73aa294 100644 --- a/Engine/Source/Editor/UnrealEd/Public/Kismet2/BlueprintEditorUtils.h +++ b/Engine/Source/Editor/UnrealEd/Public/Kismet2/BlueprintEditorUtils.h @@ -70,6 +70,8 @@ public: && (NULL != Cast(Node->GetOuter())); } + virtual ~FBasePinChangeHelper() { } + virtual void EditCompositeTunnelNode(class UK2Node_Tunnel* TunnelNode) {} virtual void EditMacroInstance(class UK2Node_MacroInstance* MacroInstance, UBlueprint* Blueprint) {} @@ -255,6 +257,9 @@ public: */ static bool ShouldRegenerateBlueprint(UBlueprint* Blueprint); + /** Returns true if compilation for the given blueprint has been disabled */ + static bool IsCompileOnLoadDisabled(UBlueprint* Blueprint); + /** * Blueprint has structurally changed (added/removed functions, graphs, etc...). Performs the following actions: * - Recompiles the skeleton class. @@ -907,7 +912,7 @@ public: static void ReplaceVariableReferences(UBlueprint* Blueprint, const UProperty* OldVariable, const UProperty* NewVariable); /** Check blueprint variable metadata keys/values for validity and make adjustments if needed */ - static void ValidateBlueprintVariableMetadata(FBPVariableDescription& VarDesc); + static void FixupVariableDescription(UBlueprint* Blueprint, FBPVariableDescription& VarDesc); /** Validate child blueprint component member variables, member variables, and timelines, and function graphs against the given variable name */ static void ValidateBlueprintChildVariables(UBlueprint* InBlueprint, const FName InVariableName); @@ -1078,14 +1083,16 @@ public: /** Indicates if the variable is used on any graphs in this Blueprint*/ static bool IsVariableUsed(const UBlueprint* Blueprint, const FName& Name, UEdGraph* LocalGraphScope = nullptr); - static void ImportKismetDefaultValueToProperty(UEdGraphPin* SourcePin, UProperty* DestinationProperty, uint8* DestinationAddress, UObject* OwnerObject); - - static void ExportPropertyToKismetDefaultValue(UEdGraphPin* TargetPin, UProperty* SourceProperty, uint8* SourceAddress, UObject* OwnerObject); + /** Copies the value from the passed in string into a property. ContainerMem points to the Struct or Class containing Property */ + static bool PropertyValueFromString(const UProperty* Property, const FString& StrValue, uint8* Container); - static bool PropertyValueFromString(const UProperty* Property, const FString& StrValue, uint8* ContainerMem); + /** Copies the value from the passed in string into a property. DirectValue is the raw memory address of the property value */ + static bool PropertyValueFromString_Direct(const UProperty* Property, const FString& StrValue, uint8* DirectValue); + /** Copies the value from a property into the string OutForm. ContainerMem points to the Struct or Class containing Property */ static bool PropertyValueToString(const UProperty* Property, const uint8* Container, FString& OutForm); + /** Copies the value from a property into the string OutForm. DirectValue is the raw memory address of the property value */ static bool PropertyValueToString_Direct(const UProperty* Property, const uint8* DirectValue, FString& OutForm); /** Call PostEditChange() on all Actors based on the given Blueprint */ diff --git a/Engine/Source/Editor/UnrealEd/Public/Kismet2/CompilerResultsLog.h b/Engine/Source/Editor/UnrealEd/Public/Kismet2/CompilerResultsLog.h index 40744259225c..bc011bf1a23d 100644 --- a/Engine/Source/Editor/UnrealEd/Public/Kismet2/CompilerResultsLog.h +++ b/Engine/Source/Editor/UnrealEd/Public/Kismet2/CompilerResultsLog.h @@ -13,8 +13,6 @@ #include "EdGraphToken.h" #endif -class Error; - #if WITH_EDITOR /** This class maps from final objects to their original source object, across cloning, autoexpansion, etc... */ @@ -25,6 +23,7 @@ protected: TMap SourceBacktrackMap; // Maps from transient pins created during compiling to original 'source pin' object TMap PinSourceBacktrackMap; + public: /** Update the source backtrack map to note that NewObject was most closely generated/caused by the SourceObject */ void NotifyIntermediateObjectCreation(UObject* NewObject, UObject* SourceObject); @@ -110,6 +109,9 @@ public: protected: // Maps from transient object created during compiling to original 'source code' object FBacktrackMap SourceBacktrackMap; + + // Maps immediately back to source uobject, which may itself by an intermediate object: + TMap FullSourceBacktrackMap; // Name of the source object being compiled FString SourcePath; @@ -197,7 +199,7 @@ public: UEdGraphNode* GetSourceNode(const UEdGraphNode* IntermediateNode); /** Returns the intermediate tunnel instance that generated the node */ - UEdGraphNode* GetIntermediateTunnelInstance(const UEdGraphNode* IntermediateNode); + UEdGraphNode* GetIntermediateTunnelInstance(const UEdGraphNode* IntermediateNode) const; /** Returns the source tunnel node for the intermediate node */ UEdGraphNode* GetSourceTunnelNode(const UEdGraphNode* IntermediateNode); @@ -212,6 +214,9 @@ public: UObject* FindSourceObject(UObject* PossiblyDuplicatedObject); UObject const* FindSourceObject(UObject const* PossiblyDuplicatedObject) const; + /** Returns a int32 used to uniquely identify an action for the latent action manager */ + int32 CalculateStableIdentifierForLatentActionManager( const UEdGraphNode* Node ); + /** Returns the true source object for the passed in object; does type checking on the result */ template T* FindSourceObjectTypeChecked(UObject* PossiblyDuplicatedObject) diff --git a/Engine/Source/Editor/UnrealEd/Public/Kismet2/KismetReinstanceUtilities.h b/Engine/Source/Editor/UnrealEd/Public/Kismet2/KismetReinstanceUtilities.h index 2e75220ff17e..8be25ee0cddd 100644 --- a/Engine/Source/Editor/UnrealEd/Public/Kismet2/KismetReinstanceUtilities.h +++ b/Engine/Source/Editor/UnrealEd/Public/Kismet2/KismetReinstanceUtilities.h @@ -138,6 +138,9 @@ public: /** Batch replaces a mapping of one or more classes to their new class by leveraging ReplaceInstancesOfClass */ static void BatchReplaceInstancesOfClass(TMap& InOldToNewClassMap, TSet* ObjectsThatShouldUseOldStuff = NULL, bool bClassObjectReplaced = false, bool bPreserveRootComponent = true); + + /** Function used to safely discard a CDO, so that the class can have its layout changed, callers must move parent CDOs aside before moving child CDOs aside: */ + static UClass* MoveCDOToNewClass(UClass* OwnerClass, const TMap& OldToNewMap, bool bAvoidCDODuplication); /** * When re-instancing a component, we have to make sure all instance owners' diff --git a/Engine/Source/Editor/UnrealEd/Public/Kismet2/ListenerManager.h b/Engine/Source/Editor/UnrealEd/Public/Kismet2/ListenerManager.h index a78d77de764b..3f38d87775ec 100644 --- a/Engine/Source/Editor/UnrealEd/Public/Kismet2/ListenerManager.h +++ b/Engine/Source/Editor/UnrealEd/Public/Kismet2/ListenerManager.h @@ -64,4 +64,9 @@ public: Listener->PostChange(Changed, Info); } } + + const TSet& GetListeners() const + { + return Listeners; + } }; diff --git a/Engine/Source/Editor/UnrealEd/Public/Kismet2/StructureEditorUtils.h b/Engine/Source/Editor/UnrealEd/Public/Kismet2/StructureEditorUtils.h index e353ca718f87..352fcca01f62 100644 --- a/Engine/Source/Editor/UnrealEd/Public/Kismet2/StructureEditorUtils.h +++ b/Engine/Source/Editor/UnrealEd/Public/Kismet2/StructureEditorUtils.h @@ -129,7 +129,7 @@ public: { if (Struct) { - auto VarDescArray = GetVarDescPtr(Struct); + TArray* VarDescArray = GetVarDescPtr(Struct); return VarDescArray ? VarDescArray->FindByPredicate(FFindByGuidHelper(VarGuid)) : nullptr; } return nullptr; @@ -139,7 +139,7 @@ public: { if (Struct) { - auto VarDescArray = GetVarDescPtr(Struct); + const TArray* VarDescArray = GetVarDescPtr(Struct); return VarDescArray ? VarDescArray->FindByPredicate(FFindByGuidHelper(VarGuid)) : nullptr; } return nullptr; diff --git a/Engine/Source/Editor/UnrealEd/Public/LevelEditorViewport.h b/Engine/Source/Editor/UnrealEd/Public/LevelEditorViewport.h index 97f54c186728..b36628ce2f3d 100644 --- a/Engine/Source/Editor/UnrealEd/Public/LevelEditorViewport.h +++ b/Engine/Source/Editor/UnrealEd/Public/LevelEditorViewport.h @@ -223,7 +223,7 @@ public: /** * Updates or resets view properties such as aspect ratio, FOV, location etc to match that of any actor we are locked to */ - void UpdateViewForLockedActor(); + void UpdateViewForLockedActor(float DeltaTime=0.f); /** * Returns the horizontal axis for this viewport. @@ -436,41 +436,10 @@ public: } /** - * Find the camera component to use for a locked actor - * note this should return the same component as SLevelViewport::GetCameraInformationFromActor uses + * Find a view component to use for the specified actor. Prioritizes selected + * components first, followed by camera components (then falls through to the first component that implements GetEditorPreviewInfo) */ - UCameraComponent* GetCameraComponentForLockedActor(AActor const* Actor) const - { - if (Actor) - { - // see if actor has a camera component - TArray CamComps; - Actor->GetComponents(CamComps); - for (UCameraComponent* Comp : CamComps) - { - if (Comp->bIsActive) - { - return Comp; - } - } - - // now see if any actors are attached to us, directly or indirectly, that have an active camera component we might want to use - // we will just return the first one. - // #note: assumption here that attachment cannot be circular - TArray AttachedActors; - Actor->GetAttachedActors(AttachedActors); - for (AActor* AttachedActor : AttachedActors) - { - UCameraComponent* const Comp = GetCameraComponentForLockedActor(AttachedActor); - if (Comp) - { - return Comp; - } - } - } - - return nullptr; - } + static USceneComponent* FindViewComponentForActor(AActor const* Actor); /** * Find the camera component that is driving this viewport, in the following order of preference: @@ -488,7 +457,7 @@ public: LockedActor = ActorLockedToCamera.Get(); } - return GetCameraComponentForLockedActor(LockedActor); + return Cast(FindViewComponentForActor(LockedActor)); } /** @@ -565,6 +534,9 @@ public: */ static UObject* GetOrCreateMaterialFromTexture( UTexture* UnrealTexture ); + /** Whether transport controls can be attached */ + virtual bool CanAttachTransportControls() const { return true; } + protected: /** * Checks the viewport to see if the given blueprint asset can be dropped on the viewport. diff --git a/Engine/Source/Editor/UnrealEd/Public/Settings/EditorProjectSettings.h b/Engine/Source/Editor/UnrealEd/Public/Settings/EditorProjectSettings.h index 89f57faeb6ac..88f0554d3e6b 100644 --- a/Engine/Source/Editor/UnrealEd/Public/Settings/EditorProjectSettings.h +++ b/Engine/Source/Editor/UnrealEd/Public/Settings/EditorProjectSettings.h @@ -52,11 +52,14 @@ protected: virtual void PostEditChangeProperty( struct FPropertyChangedEvent& PropertyChangedEvent ) override; virtual void PostInitProperties() override; -private: +public: UPROPERTY(EditAnywhere, config, Category=Units, meta=(DisplayName="Display Units on Applicable Properties", Tooltip="Whether to display units on editor properties where the property has units set.")) bool bDisplayUnits; + UPROPERTY(EditAnywhere, config, Category = Units, meta = (EditCondition="bDisplayUnits", DisplayName = "Display Units on Component Transforms", Tooltip = "Whether to display units on component transform properties")) + bool bDisplayUnitsOnComponentTransforms; + UPROPERTY(EditAnywhere, config, Category=Units, AdvancedDisplay, meta=(DisplayName="Distance/Length", Tooltip="Choose a set of units in which to display distance/length values.")) TArray DistanceUnits; diff --git a/Engine/Source/Editor/UnrealEd/Public/SkelImport.h b/Engine/Source/Editor/UnrealEd/Public/SkelImport.h index 8dcc363546fa..55017b212b8b 100644 --- a/Engine/Source/Editor/UnrealEd/Public/SkelImport.h +++ b/Engine/Source/Editor/UnrealEd/Public/SkelImport.h @@ -196,6 +196,8 @@ public: bool bHasVertexColors; // If true there are vertex colors in the imported file bool bHasNormals; // If true there are normals in the imported file bool bHasTangents; // If true there are tangents in the imported file + bool bUseT0AsRefPose; // If true, then the pose at time=0 will be used instead of the ref pose + bool bDiffPose; // If true, one of the bones has a different pose at time=0 vs the ref pose FSkeletalMeshImportData() : NumTexCoords(0) @@ -203,6 +205,8 @@ public: , bHasVertexColors(false) , bHasNormals(false) , bHasTangents(false) + , bUseT0AsRefPose(false) + , bDiffPose(false) { } @@ -221,7 +225,7 @@ public: TArray& LODWedges, TArray& LODFaces, TArray& LODInfluences, - TArray& LODPointToRawMap); + TArray& LODPointToRawMap) const; static FString FixupBoneName( const FString& InBoneName ); diff --git a/Engine/Source/Editor/UnrealEd/Public/TickableEditorObject.h b/Engine/Source/Editor/UnrealEd/Public/TickableEditorObject.h index d25199b0b517..33c3bd22938b 100644 --- a/Engine/Source/Editor/UnrealEd/Public/TickableEditorObject.h +++ b/Engine/Source/Editor/UnrealEd/Public/TickableEditorObject.h @@ -60,7 +60,7 @@ private: friend class TTickableObjectsCollection; /** True if collection of tickable objects is still intact. */ - static bool bCollectionIntact; + UNREALED_API static bool bCollectionIntact; /** Avoids removal if the object outlived the collection. */ UNREALED_API static void UnregisterTickableObject(FTickableEditorObject* Obj) diff --git a/Engine/Source/Editor/UnrealEd/Public/Toolkits/AssetEditorToolkit.h b/Engine/Source/Editor/UnrealEd/Public/Toolkits/AssetEditorToolkit.h index 4059b441b4f9..c0b98a3532e8 100644 --- a/Engine/Source/Editor/UnrealEd/Public/Toolkits/AssetEditorToolkit.h +++ b/Engine/Source/Editor/UnrealEd/Public/Toolkits/AssetEditorToolkit.h @@ -256,6 +256,9 @@ protected: /** @return a pointer to the brush to use for the tab icon */ virtual const FSlateBrush* GetDefaultTabIcon() const; + /** @return the color to use for the tab color */ + virtual FLinearColor GetDefaultTabColor() const; + private: /** Spawns the toolbar tab */ TSharedRef SpawnTab_Toolbar(const FSpawnTabArgs& Args); diff --git a/Engine/Source/Editor/UnrealEd/Public/UnrealEd.h b/Engine/Source/Editor/UnrealEd/Public/UnrealEd.h index f35e928cc829..ed010a978524 100644 --- a/Engine/Source/Editor/UnrealEd/Public/UnrealEd.h +++ b/Engine/Source/Editor/UnrealEd/Public/UnrealEd.h @@ -189,7 +189,6 @@ MONOLITHIC_HEADER_BOILERPLATE() #include "Classes/Factories/FbxSceneImportOptionsSkeletalMesh.h" #include "Classes/Factories/FbxSceneImportOptionsStaticMesh.h" #include "Classes/Commandlets/FileServerCommandlet.h" -#include "Classes/Commandlets/FixupRedirectsCommandlet.h" #include "Classes/Commandlets/GatherTextCommandletBase.h" #include "Classes/Commandlets/GatherTextCommandlet.h" #include "Classes/Commandlets/GatherTextFromAssetsCommandlet.h" diff --git a/Engine/Source/Editor/UnrealEd/Public/UnrealEdSharedPCH.h b/Engine/Source/Editor/UnrealEd/Public/UnrealEdSharedPCH.h index 15ab89762eed..8c61dc259236 100644 --- a/Engine/Source/Editor/UnrealEd/Public/UnrealEdSharedPCH.h +++ b/Engine/Source/Editor/UnrealEd/Public/UnrealEdSharedPCH.h @@ -34,7 +34,6 @@ #include "Templates/EnableIf.h" #include "Templates/RemoveReference.h" #include "Templates/TypeCompatibleBytes.h" -#include "Templates/AlignOf.h" #include "Templates/ChooseClass.h" #include "Templates/IntegralConstant.h" #include "Templates/IsClass.h" @@ -402,7 +401,6 @@ #include "Framework/Docking/LayoutService.h" #include "Framework/Application/SlateApplication.h" #include "Framework/Application/MenuStack.h" -#include "Runtime/Slate/Private/Framework/Application/Menu.h" #include "Widgets/Views/SHeaderRow.h" #include "Framework/Layout/InertialScrollManager.h" #include "Widgets/Layout/SScrollBar.h" @@ -434,9 +432,6 @@ #include "Widgets/Notifications/SErrorText.h" #include "Framework/MarqueeRect.h" #include "Widgets/Docking/SDockTab.h" -#include "Runtime/Slate/Private/Framework/Docking/SDockingArea.h" -#include "Runtime/Slate/Private/Framework/Docking/SDockingNode.h" -#include "Runtime/Slate/Private/Framework/Docking/SDockingSplitter.h" // From RHI: #include "RHIDefinitions.h" @@ -463,7 +458,6 @@ // From AssetRegistry: #include "AssetData.h" -#include "SharedMapView.h" #include "ARFilter.h" // From Engine: diff --git a/Engine/Source/Editor/UnrealEd/UnrealEd.Build.cs b/Engine/Source/Editor/UnrealEd/UnrealEd.Build.cs index 439a729046dc..fc63b5c8570c 100644 --- a/Engine/Source/Editor/UnrealEd/UnrealEd.Build.cs +++ b/Engine/Source/Editor/UnrealEd/UnrealEd.Build.cs @@ -25,11 +25,9 @@ public class UnrealEd : ModuleRules PrivateIncludePathModuleNames.AddRange( new string[] { - "AssetTools", "BehaviorTreeEditor", "ClassViewer", "ContentBrowser", - "CrashTracker", "DerivedDataCache", "DesktopPlatform", "EnvironmentQueryEditor", @@ -95,6 +93,7 @@ public class UnrealEd : ModuleRules "AutomationController", "Localization", "AudioEditor", + "NetworkFileSystem", } ); @@ -115,7 +114,6 @@ public class UnrealEd : ModuleRules "LauncherServices", "MaterialEditor", "MessageLog", - "NetworkFileSystem", "PakFile", "PropertyEditor", "Projects", @@ -164,7 +162,6 @@ public class UnrealEd : ModuleRules DynamicallyLoadedModuleNames.AddRange( new string[] { - "CrashTracker", "FontEditor", "StaticMeshEditor", "TextureEditor", @@ -218,7 +215,6 @@ public class UnrealEd : ModuleRules "UndoHistory", "SourceCodeAccess", "ReferenceViewer", - "EditorLiveStreaming", "HotReload", "IOSPlatformEditor", "HTML5PlatformEditor", @@ -258,7 +254,9 @@ public class UnrealEd : ModuleRules "CollectionManager", "BlueprintGraph", "AddContentDialog", - "MeshUtilities" + "MeshUtilities", + "AssetTools", + "KismetCompiler", } ); diff --git a/Engine/Source/Editor/VREditor/Gizmo/VREditorPlaneTranslationGizmoHandle.cpp b/Engine/Source/Editor/VREditor/Gizmo/VREditorPlaneTranslationGizmoHandle.cpp deleted file mode 100644 index a568d085d763..000000000000 --- a/Engine/Source/Editor/VREditor/Gizmo/VREditorPlaneTranslationGizmoHandle.cpp +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#include "VREditorPlaneTranslationGizmoHandle.h" -#include "UObject/ConstructorHelpers.h" -#include "Components/StaticMeshComponent.h" -#include "Engine/StaticMesh.h" -#include "VIBaseTransformGizmo.h" - -UVREditorPlaneTranslationGizmoHandleGroup::UVREditorPlaneTranslationGizmoHandleGroup() - : Super() -{ - UStaticMesh* PlaneTranslationHandleMesh = nullptr; - { - static ConstructorHelpers::FObjectFinder ObjectFinder( TEXT( "/Engine/VREditor/TransformGizmo/PlaneTranslationHandle" ) ); - PlaneTranslationHandleMesh = ObjectFinder.Object; - check( PlaneTranslationHandleMesh != nullptr ); - } - - const bool bAllowGizmoLighting = false; // @todo vreditor: Not sure if we want this for gizmos or not yet. Needs feedback. Also they're translucent right now. - - for (int32 X = 0; X < 3; ++X) - { - for (int32 Y = 0; Y < 3; ++Y) - { - for (int32 Z = 0; Z < 3; ++Z) - { - FTransformGizmoHandlePlacement HandlePlacement = GetHandlePlacement( X, Y, Z ); - - int32 CenterHandleCount, FacingAxisIndex, CenterAxisIndex; - HandlePlacement.GetCenterHandleCountAndFacingAxisIndex( /* Out */ CenterHandleCount, /* Out */ FacingAxisIndex, /* Out */ CenterAxisIndex ); - - // Don't allow translation/stretching/rotation from the origin - if (CenterHandleCount < 3) - { - const FString HandleName = MakeHandleName( HandlePlacement ); - - // Plane translation only happens on the center of an axis. And we only bother drawing one for the "positive" direction. - if (CenterHandleCount == 2 && HandlePlacement.Axes[FacingAxisIndex] == ETransformGizmoHandleDirection::Positive) - { - // Plane translation handle - FString ComponentName = HandleName + TEXT( "PlaneTranslationHandle" ); - CreateAndAddMeshHandle( PlaneTranslationHandleMesh, ComponentName, HandlePlacement ); - } - } - } - } - } -} - -void UVREditorPlaneTranslationGizmoHandleGroup::UpdateGizmoHandleGroup(const FTransform& LocalToWorld, const FBox& LocalBounds, const FVector ViewLocation, const bool bAllHandlesVisible, class UActorComponent* DraggingHandle, const TArray< UActorComponent* >& HoveringOverHandles, float AnimationAlpha, float GizmoScale, const float GizmoHoverScale, const float GizmoHoverAnimationDuration, bool& bOutIsHoveringOrDraggingThisHandleGroup ) -{ - // Call parent implementation (updates hover animation) - Super::UpdateGizmoHandleGroup(LocalToWorld, LocalBounds, ViewLocation, bAllHandlesVisible, DraggingHandle, HoveringOverHandles, AnimationAlpha, - GizmoScale, GizmoHoverScale, GizmoHoverAnimationDuration, bOutIsHoveringOrDraggingThisHandleGroup ); - - for (int32 HandleIndex = 0; HandleIndex < Handles.Num(); ++HandleIndex) - { - FGizmoHandle& Handle = Handles[ HandleIndex ]; - UStaticMeshComponent* PlaneTranslationHandle = Handle.HandleMesh; - if (PlaneTranslationHandle != nullptr) // Can be null if no handle for this specific placement - { - const FTransformGizmoHandlePlacement HandlePlacement = MakeHandlePlacementForIndex( HandleIndex ); - - int32 CenterHandleCount, FacingAxisIndex, CenterAxisIndex; - HandlePlacement.GetCenterHandleCountAndFacingAxisIndex( /* Out */ CenterHandleCount, /* Out */ FacingAxisIndex, /* Out */ CenterAxisIndex ); - check( CenterHandleCount == 2 ); - - const FVector GizmoSpaceFacingAxisVector = GetAxisVector( FacingAxisIndex, HandlePlacement.Axes[FacingAxisIndex] ); - const FQuat GizmoSpaceOrientation = GizmoSpaceFacingAxisVector.ToOrientationQuat(); - - FVector HandleRelativeLocation = LocalBounds.GetCenter(); - - float GizmoHandleScale = GizmoScale; - - // Push toward the viewer (along our facing axis) a bit - const float GizmoSpaceOffsetAlongFacingAxis = - GizmoHandleScale * - (10.0f + - (1.0f - AnimationAlpha) * 6.0f); // @todo vreditor tweak: Animation offset - - // Make the handle bigger while hovered (but don't affect the offset -- we want it to scale about it's origin) - GizmoHandleScale *= FMath::Lerp( 1.0f, GizmoHoverScale, Handle.HoverAlpha ); - - const FVector WorldSpacePositiveOffsetLocation = LocalToWorld.TransformPosition( HandleRelativeLocation + GizmoSpaceOffsetAlongFacingAxis * GizmoSpaceFacingAxisVector ); - const FVector WorldSpaceNegativeOffsetLocation = LocalToWorld.TransformPosition( HandleRelativeLocation - GizmoSpaceOffsetAlongFacingAxis * GizmoSpaceFacingAxisVector ); - const bool bIsPositiveTowardViewer = - FVector::DistSquared( WorldSpacePositiveOffsetLocation, ViewLocation ) < - FVector::DistSquared( WorldSpaceNegativeOffsetLocation, ViewLocation ); - - if (bIsPositiveTowardViewer) - { - // Back it up - HandleRelativeLocation -= GizmoSpaceOffsetAlongFacingAxis * GizmoSpaceFacingAxisVector; - } - else - { - // Push it forward - HandleRelativeLocation += GizmoSpaceOffsetAlongFacingAxis * GizmoSpaceFacingAxisVector; - } - - PlaneTranslationHandle->SetRelativeLocation( HandleRelativeLocation ); - - PlaneTranslationHandle->SetRelativeRotation( GizmoSpaceOrientation ); - - PlaneTranslationHandle->SetRelativeScale3D( FVector( GizmoHandleScale ) ); - - // Update material - UpdateHandleColor( FacingAxisIndex, Handle, DraggingHandle, HoveringOverHandles ); - } - } -} - -ETransformGizmoInteractionType UVREditorPlaneTranslationGizmoHandleGroup::GetInteractionType() const -{ - return ETransformGizmoInteractionType::TranslateOnPlane; -} - -EGizmoHandleTypes UVREditorPlaneTranslationGizmoHandleGroup::GetHandleType() const -{ - return EGizmoHandleTypes::Translate; -} diff --git a/Engine/Source/Editor/VREditor/Gizmo/VREditorPlaneTranslationGizmoHandle.h b/Engine/Source/Editor/VREditor/Gizmo/VREditorPlaneTranslationGizmoHandle.h deleted file mode 100644 index 09fc98ec580b..000000000000 --- a/Engine/Source/Editor/VREditor/Gizmo/VREditorPlaneTranslationGizmoHandle.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "CoreMinimal.h" -#include "UObject/ObjectMacros.h" -#include "VIGizmoHandle.h" -#include "VREditorPlaneTranslationGizmoHandle.generated.h" - -enum class EGizmoHandleTypes : uint8; - -/** - * Gizmo handle for translating on a plane - */ -UCLASS() -class UVREditorPlaneTranslationGizmoHandleGroup : public UGizmoHandleGroup -{ - GENERATED_BODY() - -public: - - /** Default constructor that sets up CDO properties */ - UVREditorPlaneTranslationGizmoHandleGroup(); - - /** Updates the gizmo handles */ - void UpdateGizmoHandleGroup(const FTransform& LocalToWorld, const FBox& LocalBounds, const FVector ViewLocation, const bool bAllHandlesVisible, class UActorComponent* DraggingHandle, - const TArray< UActorComponent* >& HoveringOverHandles, float AnimationAlpha, float GizmoScale, const float GizmoHoverScale, const float GizmoHoverAnimationDuration, bool& bOutIsHoveringOrDraggingThisHandleGroup ) override; - - /** Gets the InteractionType for this Gizmo handle */ - virtual ETransformGizmoInteractionType GetInteractionType() const override; - - /** Gets the GizmoType for this Gizmo handle */ - virtual EGizmoHandleTypes GetHandleType() const override; -}; diff --git a/Engine/Source/Editor/VREditor/Gizmo/VREditorRotationGizmoHandle.cpp b/Engine/Source/Editor/VREditor/Gizmo/VREditorRotationGizmoHandle.cpp deleted file mode 100644 index df0a25dd92e1..000000000000 --- a/Engine/Source/Editor/VREditor/Gizmo/VREditorRotationGizmoHandle.cpp +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#include "VREditorRotationGizmoHandle.h" -#include "UObject/ConstructorHelpers.h" -#include "Components/StaticMeshComponent.h" -#include "Engine/StaticMesh.h" -#include "VIBaseTransformGizmo.h" - -UVREditorRotationGizmoHandleGroup::UVREditorRotationGizmoHandleGroup() - : Super() -{ - UStaticMesh* RotationHandleMesh = nullptr; - { - static ConstructorHelpers::FObjectFinder ObjectFinder( TEXT( "/Engine/VREditor/TransformGizmo/RotationHandle" ) ); - RotationHandleMesh = ObjectFinder.Object; - check( RotationHandleMesh != nullptr ); - } - - const bool bAllowGizmoLighting = false; // @todo vreditor: Not sure if we want this for gizmos or not yet. Needs feedback. Also they're translucent right now. - - for (int32 X = 0; X < 3; ++X) - { - for (int32 Y = 0; Y < 3; ++Y) - { - for (int32 Z = 0; Z < 3; ++Z) - { - FTransformGizmoHandlePlacement HandlePlacement = GetHandlePlacement( X, Y, Z ); - - int32 CenterHandleCount, FacingAxisIndex, CenterAxisIndex; - HandlePlacement.GetCenterHandleCountAndFacingAxisIndex( /* Out */ CenterHandleCount, /* Out */ FacingAxisIndex, /* Out */ CenterAxisIndex ); - - // Don't allow translation/stretching/rotation from the origin - if (CenterHandleCount < 3) - { - const FString HandleName = MakeHandleName( HandlePlacement ); - - // Rotation handle - // Don't bother with rotation handles on corners or faces. They don't make too much sense. Only edges. - if (CenterHandleCount == 1) // Edge? - { - FString ComponentName = HandleName + TEXT( "RotationHandle" ); - CreateAndAddMeshHandle( RotationHandleMesh, ComponentName, HandlePlacement ); - } - } - } - } - } -} - -void UVREditorRotationGizmoHandleGroup::UpdateGizmoHandleGroup( const FTransform& LocalToWorld, const FBox& LocalBounds, const FVector ViewLocation, const bool bAllHandlesVisible, class UActorComponent* DraggingHandle, - const TArray< UActorComponent* >& HoveringOverHandles, float AnimationAlpha, float GizmoScale, const float GizmoHoverScale, const float GizmoHoverAnimationDuration, bool& bOutIsHoveringOrDraggingThisHandleGroup ) -{ - // Call parent implementation (updates hover animation) - Super::UpdateGizmoHandleGroup(LocalToWorld, LocalBounds, ViewLocation, bAllHandlesVisible, DraggingHandle, HoveringOverHandles, - AnimationAlpha, GizmoScale, GizmoHoverScale, GizmoHoverAnimationDuration, bOutIsHoveringOrDraggingThisHandleGroup); - - // Place the rotation handles - for (int32 HandleIndex = 0; HandleIndex < Handles.Num(); ++HandleIndex) - { - FGizmoHandle& Handle = Handles[ HandleIndex ]; - - UStaticMeshComponent* RotationHandle = Handle.HandleMesh; - if (RotationHandle != nullptr) // Can be null if no handle for this specific placement - { - const FTransformGizmoHandlePlacement HandlePlacement = MakeHandlePlacementForIndex( HandleIndex ); - - float GizmoHandleScale = GizmoScale; - - const float OffsetFromSide = GizmoHandleScale * - (1.0f + // @todo vreditor tweak: Hard coded handle offset from side of primitive - (1.0f - AnimationAlpha) * 10.0f); // @todo vreditor tweak: Animation offset - - // Make the handle bigger while hovered (but don't affect the offset -- we want it to scale about it's origin) - GizmoHandleScale *= FMath::Lerp( 1.0f, GizmoHoverScale, Handle.HoverAlpha ); - - FVector HandleRelativeLocation = FVector::ZeroVector; - for (int32 AxisIndex = 0; AxisIndex < 3; ++AxisIndex) - { - if (HandlePlacement.Axes[AxisIndex] == ETransformGizmoHandleDirection::Negative) // Negative direction - { - HandleRelativeLocation[AxisIndex] = LocalBounds.Min[AxisIndex] - OffsetFromSide; - } - else if (HandlePlacement.Axes[AxisIndex] == ETransformGizmoHandleDirection::Positive) // Positive direction - { - HandleRelativeLocation[AxisIndex] = LocalBounds.Max[AxisIndex] + OffsetFromSide; - } - else // ETransformGizmoHandleDirection::Center - { - HandleRelativeLocation[AxisIndex] = LocalBounds.GetCenter()[AxisIndex]; - } - } - - RotationHandle->SetRelativeLocation( HandleRelativeLocation ); - - FRotator Rotator = FRotator::ZeroRotator; - - // Back bottom edge - if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Negative && HandlePlacement.Axes[2] == ETransformGizmoHandleDirection::Negative) - { - Rotator.Yaw = 0.0f; - Rotator.Pitch = 0.0f; - Rotator.Roll = 0.0f; - } - - // Back left edge - else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Negative && HandlePlacement.Axes[1] == ETransformGizmoHandleDirection::Negative) - { - Rotator.Yaw = 0.0f; - Rotator.Pitch = 0.0f; - Rotator.Roll = 90.0f; - } - - // Back top edge - else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Negative && HandlePlacement.Axes[2] == ETransformGizmoHandleDirection::Positive) - { - Rotator.Yaw = 0.0f; - Rotator.Pitch = -90.0f; - Rotator.Roll = 0.0f; - } - - // Back right edge - else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Negative && HandlePlacement.Axes[1] == ETransformGizmoHandleDirection::Positive) - { - Rotator.Yaw = 0.0f; - Rotator.Pitch = 0.0f; - Rotator.Roll = -90.0f; - } - - // Front bottom edge - else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Positive && HandlePlacement.Axes[2] == ETransformGizmoHandleDirection::Negative) - { - Rotator.Yaw = 180.0f; - Rotator.Pitch = 0.0f; - Rotator.Roll = 0.0f; - } - - // Front left edge - else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Positive && HandlePlacement.Axes[1] == ETransformGizmoHandleDirection::Negative) - { - Rotator.Yaw = 180.0f; - Rotator.Pitch = 0.0f; - Rotator.Roll = -90.0f; - } - - // Front top edge - else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Positive && HandlePlacement.Axes[2] == ETransformGizmoHandleDirection::Positive) - { - Rotator.Yaw = 180.0f; - Rotator.Pitch = -90.0f; - Rotator.Roll = 0.0f; - } - - // Front right edge - else if (HandlePlacement.Axes[0] == ETransformGizmoHandleDirection::Positive && HandlePlacement.Axes[1] == ETransformGizmoHandleDirection::Positive) - { - Rotator.Yaw = 180.0f; - Rotator.Pitch = 0.0f; - Rotator.Roll = 90.0f; - } - - // Left bottom edge - else if (HandlePlacement.Axes[1] == ETransformGizmoHandleDirection::Negative && HandlePlacement.Axes[2] == ETransformGizmoHandleDirection::Negative) - { - Rotator.Yaw = 90.0f; - Rotator.Pitch = 0.0f; - Rotator.Roll = 0.0f; - } - - // Left top edge - else if (HandlePlacement.Axes[1] == ETransformGizmoHandleDirection::Negative && HandlePlacement.Axes[2] == ETransformGizmoHandleDirection::Positive) - { - Rotator.Yaw = 90.0f; - Rotator.Pitch = -90.0f; - Rotator.Roll = 0.0f; - } - - // Right bottom edge - else if (HandlePlacement.Axes[1] == ETransformGizmoHandleDirection::Positive && HandlePlacement.Axes[2] == ETransformGizmoHandleDirection::Negative) - { - Rotator.Yaw = -90.0f; - Rotator.Pitch = 0.0f; - Rotator.Roll = 0.0f; - } - - // Right top edge - else if (HandlePlacement.Axes[1] == ETransformGizmoHandleDirection::Positive && HandlePlacement.Axes[2] == ETransformGizmoHandleDirection::Positive) - { - Rotator.Yaw = -90.0f; - Rotator.Pitch = -90.0f; - Rotator.Roll = 0.0f; - } - - else - { - // No other valid edges - ensure( 0 ); - } - - RotationHandle->SetRelativeRotation( Rotator ); - - RotationHandle->SetRelativeScale3D( FVector( GizmoHandleScale ) ); - - int32 CenterHandleCount, FacingAxisIndex, CenterAxisIndex; - HandlePlacement.GetCenterHandleCountAndFacingAxisIndex( /* Out */ CenterHandleCount, /* Out */ FacingAxisIndex, /* Out */ CenterAxisIndex ); - - // Update material - UpdateHandleColor( CenterAxisIndex, Handle, DraggingHandle, HoveringOverHandles); - } - } -} - -ETransformGizmoInteractionType UVREditorRotationGizmoHandleGroup::GetInteractionType() const -{ - return ETransformGizmoInteractionType::Rotate; -} - -EGizmoHandleTypes UVREditorRotationGizmoHandleGroup::GetHandleType() const -{ - return EGizmoHandleTypes::Rotate; -} diff --git a/Engine/Source/Editor/VREditor/Gizmo/VREditorRotationGizmoHandle.h b/Engine/Source/Editor/VREditor/Gizmo/VREditorRotationGizmoHandle.h deleted file mode 100644 index 16f222cd13a3..000000000000 --- a/Engine/Source/Editor/VREditor/Gizmo/VREditorRotationGizmoHandle.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "CoreMinimal.h" -#include "UObject/ObjectMacros.h" -#include "VIGizmoHandle.h" -#include "VREditorRotationGizmoHandle.generated.h" - -enum class EGizmoHandleTypes : uint8; - -/** - * Gizmo handle for rotation - */ -UCLASS() -class UVREditorRotationGizmoHandleGroup : public UGizmoHandleGroup -{ - GENERATED_BODY() - -public: - - /** Default constructor that sets up CDO properties */ - UVREditorRotationGizmoHandleGroup(); - - /** Updates the Gizmo handles */ - virtual void UpdateGizmoHandleGroup( const FTransform& LocalToWorld, const FBox& LocalBounds, const FVector ViewLocation, const bool bAllHandlesVisible, class UActorComponent* DraggingHandle, const TArray< UActorComponent* >& HoveringOverHandles, - float AnimationAlpha, float GizmoScale, const float GizmoHoverScale, const float GizmoHoverAnimationDuration, bool& bOutIsHoveringOrDraggingThisHandleGroup ) override; - - /** Gets the InteractionType for this Gizmo handle */ - virtual ETransformGizmoInteractionType GetInteractionType() const override; - - /** Gets the GizmoType for this Gizmo handle */ - virtual EGizmoHandleTypes GetHandleType() const override; -}; diff --git a/Engine/Source/Editor/VREditor/Gizmo/VREditorTransformGizmo.cpp b/Engine/Source/Editor/VREditor/Gizmo/VREditorTransformGizmo.cpp deleted file mode 100644 index 5501281fe131..000000000000 --- a/Engine/Source/Editor/VREditor/Gizmo/VREditorTransformGizmo.cpp +++ /dev/null @@ -1,294 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#include "VREditorTransformGizmo.h" -#include "Engine/World.h" -#include "UObject/ConstructorHelpers.h" -#include "Materials/Material.h" -#include "Engine/Font.h" -#include "Engine/CollisionProfile.h" -#include "GameFramework/WorldSettings.h" -#include "Components/TextRenderComponent.h" -#include "Math/UnitConversion.h" -#include "VIGizmoHandle.h" -#include "VREditorTranslationGizmoHandle.h" -#include "VREditorRotationGizmoHandle.h" -#include "VREditorPlaneTranslationGizmoHandle.h" -#include "VIStretchGizmoHandle.h" -#include "VIUniformScaleGizmoHandle.h" -#include "VRModeSettings.h" - -namespace VREd -{ - // @todo vreditor tweak: Tweak out console variables - static FAutoConsoleVariable GizmoDistanceScaleFactor( TEXT( "VREd.GizmoDistanceScaleFactor" ), 0.002f, TEXT( "How much the gizmo handles should increase in size with distance from the camera, to make it easier to select" ) ); - static FAutoConsoleVariable MinActorSizeForTransformGizmo( TEXT( "VREd.MinActorSizeForTransformGizmo" ), 50.0f, TEXT( "How big an object must be in scaled world units before we'll start to shrink the gizmo" ) ); -} - - -ATransformGizmo::ATransformGizmo() -{ - if (UNLIKELY(IsRunningDedicatedServer())) - { - return; - } - - TranslationGizmoHandleGroup = CreateDefaultSubobject( TEXT( "TranslationHandles" ), true ); - TranslationGizmoHandleGroup->SetTranslucentGizmoMaterial( TranslucentGizmoMaterial ); - TranslationGizmoHandleGroup->SetGizmoMaterial( GizmoMaterial ); - TranslationGizmoHandleGroup->SetupAttachment( SceneComponent ); - AllHandleGroups.Add( TranslationGizmoHandleGroup ); - - PlaneTranslationGizmoHandleGroup = CreateDefaultSubobject( TEXT( "PlaneTranslationHandles" ), true ); - PlaneTranslationGizmoHandleGroup->SetTranslucentGizmoMaterial( TranslucentGizmoMaterial ); - PlaneTranslationGizmoHandleGroup->SetGizmoMaterial( GizmoMaterial ); - PlaneTranslationGizmoHandleGroup->SetupAttachment( SceneComponent ); - AllHandleGroups.Add( PlaneTranslationGizmoHandleGroup ); - - RotationGizmoHandleGroup = CreateDefaultSubobject( TEXT( "RotationHandles" ), true ); - RotationGizmoHandleGroup->SetTranslucentGizmoMaterial( TranslucentGizmoMaterial ); - RotationGizmoHandleGroup->SetGizmoMaterial( GizmoMaterial ); - RotationGizmoHandleGroup->SetupAttachment( SceneComponent ); - AllHandleGroups.Add( RotationGizmoHandleGroup ); - - StretchGizmoHandleGroup = CreateDefaultSubobject( TEXT( "StretchHandles" ), true ); - StretchGizmoHandleGroup->SetTranslucentGizmoMaterial( TranslucentGizmoMaterial ); - StretchGizmoHandleGroup->SetGizmoMaterial( GizmoMaterial ); - StretchGizmoHandleGroup->SetupAttachment( SceneComponent ); - AllHandleGroups.Add( StretchGizmoHandleGroup ); - - UniformScaleGizmoHandleGroup = CreateDefaultSubobject( TEXT( "UniformScaleHandles" ), true ); - UniformScaleGizmoHandleGroup->SetTranslucentGizmoMaterial( TranslucentGizmoMaterial ); - UniformScaleGizmoHandleGroup->SetGizmoMaterial( GizmoMaterial ); - UniformScaleGizmoHandleGroup->SetUsePivotPointAsLocation( false ); - UniformScaleGizmoHandleGroup->SetupAttachment( SceneComponent ); - AllHandleGroups.Add( UniformScaleGizmoHandleGroup ); - - const bool bAllowGizmoLighting = false; // @todo vreditor: Not sure if we want this for gizmos or not yet. Needs feedback. Also they're translucent right now. - - // Setup measurements - { - UMaterialInterface* GizmoTextMaterial = nullptr; - { - static ConstructorHelpers::FObjectFinder ObjectFinder( TEXT( "/Engine/VREditor/Fonts/VRTextMaterial" ) ); - GizmoTextMaterial = ObjectFinder.Object; - check( GizmoTextMaterial != nullptr ); - } - - UFont* GizmoTextFont = nullptr; - { - static ConstructorHelpers::FObjectFinder ObjectFinder( TEXT( "/Engine/VREditor/Fonts/VRText_RobotoLarge" ) ); - GizmoTextFont = ObjectFinder.Object; - check( GizmoTextFont != nullptr ); - } - - for( int32 AxisIndex = 0; AxisIndex < 3; ++AxisIndex ) - { - const FString AxisName = AxisIndex == 0 ? TEXT( "X" ) : ( AxisIndex == 1 ? TEXT( "Y" ) : TEXT( "Z" ) ); - - FString ComponentName = AxisName + TEXT( "Measurement" ); - - UTextRenderComponent* MeasurementText = CreateDefaultSubobject( *ComponentName ); - check( MeasurementText != nullptr ); - - MeasurementText->SetMobility( EComponentMobility::Movable ); - MeasurementText->SetupAttachment( SceneComponent ); - - MeasurementText->SetCollisionProfileName( UCollisionProfile::NoCollision_ProfileName ); - - MeasurementText->bGenerateOverlapEvents = false; - MeasurementText->SetCanEverAffectNavigation( false ); - MeasurementText->bCastDynamicShadow = bAllowGizmoLighting; - MeasurementText->bCastStaticShadow = false; - MeasurementText->bAffectDistanceFieldLighting = bAllowGizmoLighting; - MeasurementText->bAffectDynamicIndirectLighting = bAllowGizmoLighting; - - // Use a custom font. The text will be visible up close. - MeasurementText->SetFont( GizmoTextFont ); - - MeasurementText->SetWorldSize( 8.0f ); // @todo vreditor tweak: Size of text in world units - - // Assign our custom text rendering material. It should be Unlit and have Depth Test disabled - // so that it draws on top of overlapping geometry. - MeasurementText->SetTextMaterial( GizmoTextMaterial ); - - // Color the text based on the axis it represents - switch( AxisIndex ) - { - case 0: - MeasurementText->SetTextRenderColor( FLinearColor( 0.4f, 0.075f, 0.075f ).ToFColor( false ) ); - break; - case 1: - MeasurementText->SetTextRenderColor( FLinearColor( 0.075f, 0.4f, 0.075f ).ToFColor( false ) ); - break; - case 2: - MeasurementText->SetTextRenderColor( FLinearColor( 0.075f, 0.075f, 0.4f ).ToFColor( false ) ); - break; - } - - // Center the text horizontally - MeasurementText->SetHorizontalAlignment( EHTA_Center ); - - FTransformGizmoMeasurement& Measurement = Measurements[ AxisIndex ]; - Measurement.MeasurementText = MeasurementText; - } - } - - // There may already be some objects selected as we switch into VR mode, so we'll pretend that just happened so - // that we can make sure all transitions complete properly - OnNewObjectsSelected(); -} - - -void ATransformGizmo::UpdateGizmo(const EGizmoHandleTypes InGizmoType, const ECoordSystem InGizmoCoordinateSpace, const FTransform& InLocalToWorld, const FBox& InLocalBounds, - const FVector& InViewLocation, const float InScaleMultiplier, bool bInAllHandlesVisible, const bool bInAllowRotationAndScaleHandles, class UActorComponent* DraggingHandle, - const TArray& InHoveringOverHandles, const float InGizmoHoverScale, const float InGizmoHoverAnimationDuration) -{ - Super::UpdateGizmo(InGizmoType, InGizmoCoordinateSpace, InLocalToWorld, InLocalBounds, InViewLocation, InScaleMultiplier, bInAllHandlesVisible, - bInAllowRotationAndScaleHandles, DraggingHandle, InHoveringOverHandles, InGizmoHoverScale, InGizmoHoverAnimationDuration); - - const float WorldScaleFactor = GetWorld()->GetWorldSettings()->WorldToMeters / 100.0f; - - // Position the gizmo at the location of the first selected actor - const bool bSweep = false; - this->SetActorTransform(InLocalToWorld, bSweep); - - const FBox WorldSpaceBounds = InLocalBounds.TransformBy(InLocalToWorld); - float ScaleCompensationForTinyGizmo = 1.0f; - { - const float AvgBounds = FMath::Lerp( WorldSpaceBounds.GetSize().GetAbsMin(), WorldSpaceBounds.GetSize().GetAbsMax(), 0.5f ); - const float GizmoSizeInRoomSpace = ( AvgBounds / WorldScaleFactor ); - if( GizmoSizeInRoomSpace < VREd::MinActorSizeForTransformGizmo->GetFloat() ) - { - ScaleCompensationForTinyGizmo = GizmoSizeInRoomSpace / VREd::MinActorSizeForTransformGizmo->GetFloat(); - } - } - - // Increase scale with distance, to make gizmo handles easier to click on - // @todo vreditor: Should probably be a curve, not linear - // @todo vreditor: Should take FOV into account (especially in non-stereo/HMD mode) - const float WorldSpaceDistanceToGizmoBounds = FMath::Sqrt(WorldSpaceBounds.ComputeSquaredDistanceToPoint(InViewLocation)); - const float GizmoScaleUpClose = GetDefault()->GizmoScale; - const float GizmoScale(InScaleMultiplier * (GizmoScaleUpClose + (WorldSpaceDistanceToGizmoBounds / WorldScaleFactor) * VREd::GizmoDistanceScaleFactor->GetFloat()) * ScaleCompensationForTinyGizmo * WorldScaleFactor); - - // Update animation - float AnimationAlpha = GetAnimationAlpha(); - - // Update all the handles - bool bIsHoveringOrDraggingScaleGizmo = false; - for ( UGizmoHandleGroup* HandleGroup : AllHandleGroups ) - { - if ( HandleGroup != nullptr ) - { - bool bIsHoveringOrDraggingThisHandleGroup = false; - HandleGroup->UpdateGizmoHandleGroup(InLocalToWorld, InLocalBounds, InViewLocation, bInAllHandlesVisible, DraggingHandle, - InHoveringOverHandles, AnimationAlpha, GizmoScale, InGizmoHoverScale, InGizmoHoverAnimationDuration, /* Out */ bIsHoveringOrDraggingThisHandleGroup); - - if( HandleGroup->GetHandleType() == EGizmoHandleTypes::Scale && bIsHoveringOrDraggingThisHandleGroup ) - { - bIsHoveringOrDraggingScaleGizmo = true; - } - } - } - - // Place measurements - { - for( int32 AxisIndex = 0; AxisIndex < 3; ++AxisIndex ) - { - FTransformGizmoMeasurement& Measurement = Measurements[ AxisIndex ]; - - // Update measurement text - { - const float LocalSpaceLengthOfBoundsAlongAxis = InLocalBounds.GetSize()[ AxisIndex ]; - - FVector LocalSpaceAxisLengthVector = FVector::ZeroVector; - LocalSpaceAxisLengthVector[ AxisIndex ] = LocalSpaceLengthOfBoundsAlongAxis; - - // Transform to world space - const FVector WorldSpaceAxisLengthVector = InLocalToWorld.TransformVector( LocalSpaceAxisLengthVector ); - const float WorldSpaceLengthOfBoundsAlongAxis = WorldSpaceAxisLengthVector.Size(); - - FText BestSizeString; - { - const FNumericUnit BestUnit = FUnitConversion::QuantizeUnitsToBestFit( WorldSpaceLengthOfBoundsAlongAxis, EUnit::Centimeters ); - - FNumberFormattingOptions NumberFormattingOptions; - NumberFormattingOptions.MaximumFractionalDigits = 2; // @todo sizemap: We could make the number of digits customizable in the UI - NumberFormattingOptions.MinimumFractionalDigits = 0; - NumberFormattingOptions.MinimumIntegralDigits = 1; - - BestSizeString = - FText::FromString( FString::Printf( TEXT( "%s %s" ), - *FText::AsNumber( BestUnit.Value, &NumberFormattingOptions ).ToString(), - FUnitConversion::GetUnitDisplayString( BestUnit.Units ) ) ); - } - - Measurement.MeasurementText->SetText( BestSizeString ); - } - - - // Position the measurement in the center of the axis along the top of the bounds - { - // Figure which bounding box edge on this axis is closest to the viewer. There are four edges to choose from! - FVector GizmoSpaceClosestEdge0, GizmoSpaceClosestEdge1; - { - float ClosestSquaredDistance = TNumericLimits::Max(); - for( int32 EdgeIndex = 0; EdgeIndex < 4; ++EdgeIndex ) - { - FVector GizmoSpaceEdge0, GizmoSpaceEdge1; - GetBoundingBoxEdge( InLocalBounds, AxisIndex, EdgeIndex, /* Out */ GizmoSpaceEdge0, /* Out */ GizmoSpaceEdge1 ); - - const FVector WorldSpaceEdge0 = InLocalToWorld.TransformPosition( GizmoSpaceEdge0 ); - const FVector WorldSpaceEdge1 = InLocalToWorld.TransformPosition( GizmoSpaceEdge1 ); - - const float SquaredDistance = FMath::PointDistToSegmentSquared( InViewLocation, WorldSpaceEdge0, WorldSpaceEdge1 ); - if( SquaredDistance < ClosestSquaredDistance ) - { - ClosestSquaredDistance = SquaredDistance; - - GizmoSpaceClosestEdge0 = GizmoSpaceEdge0; - GizmoSpaceClosestEdge1 = GizmoSpaceEdge1; - } - } - - } - - const FVector EdgeVector = GizmoSpaceClosestEdge1 - GizmoSpaceClosestEdge0; - const FVector GizmoSpaceEdgeCenter = GizmoSpaceClosestEdge0 + EdgeVector * 0.5f; - - const float UpOffsetAmount = GizmoScale * 5.0f; // Push the text up a bit so that it doesn't overlap so much with our handles - const FVector GizmoSpaceUpVector = InLocalToWorld.InverseTransformVectorNoScale( FVector::UpVector ); - - Measurement.MeasurementText->SetRelativeLocation( GizmoSpaceEdgeCenter + GizmoSpaceUpVector * UpOffsetAmount ); - - const int32 TextFacingAxisIndex = AxisIndex == 0 ? 1 : ( AxisIndex == 1 ? 0 : 0 ); - FVector TextFacingDirection = UGizmoHandleGroup::GetAxisVector( TextFacingAxisIndex, ETransformGizmoHandleDirection::Positive ); - - // Make sure to face the camera - const FVector WorldSpaceEdgeCenterToViewDirection = ( InLocalToWorld.TransformPosition( GizmoSpaceEdgeCenter ) - InViewLocation ).GetSafeNormal(); - if( FVector::DotProduct( InLocalToWorld.TransformVectorNoScale( TextFacingDirection ), WorldSpaceEdgeCenterToViewDirection ) > 0.0f ) - { - TextFacingDirection *= -1.0f; - } - - const FQuat GizmoSpaceOrientation = TextFacingDirection.ToOrientationQuat(); - Measurement.MeasurementText->SetRelativeRotation( GizmoSpaceOrientation ); - - Measurement.MeasurementText->SetRelativeScale3D( FVector( GizmoScale ) ); - } - } - } - - // Update visibility - { - const bool bShouldShowMeasurements = - GetShowMeasurementText() || - bIsHoveringOrDraggingScaleGizmo; - - for( int32 AxisIndex = 0; AxisIndex < 3; ++AxisIndex ) - { - FTransformGizmoMeasurement& Measurement = Measurements[ AxisIndex ]; - - Measurement.MeasurementText->SetVisibility( bShouldShowMeasurements ); - } - } -} \ No newline at end of file diff --git a/Engine/Source/Editor/VREditor/Gizmo/VREditorTransformGizmo.h b/Engine/Source/Editor/VREditor/Gizmo/VREditorTransformGizmo.h deleted file mode 100644 index 29b39c3ba052..000000000000 --- a/Engine/Source/Editor/VREditor/Gizmo/VREditorTransformGizmo.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "CoreMinimal.h" -#include "UObject/ObjectMacros.h" -#include "VIBaseTransformGizmo.h" -#include "VREditorTransformGizmo.generated.h" - -/** - * A transform gizmo that allows you to interact with selected objects by moving, scaling and rotating. - */ -UCLASS() -class ATransformGizmo : public ABaseTransformGizmo -{ - GENERATED_BODY() - -public: - - /** Default constructor that sets up CDO properties */ - ATransformGizmo(); - - /** Called by the world interaction system after we've been spawned into the world, to allow - us to create components and set everything up nicely for the selected objects that we'll be - used to manipulate */ - virtual void UpdateGizmo(const EGizmoHandleTypes InGizmoType, const ECoordSystem InGizmoCoordinateSpace, const FTransform& InLocalToWorld, const FBox& InLocalBounds, - const FVector& InViewLocation, const float InScaleMultiplier, bool bInAllHandlesVisible, const bool bInAllowRotationAndScaleHandles, class UActorComponent* DraggingHandle, - const TArray& InHoveringOverHandles, const float InGizmoHoverScale, const float InGizmoHoverAnimationDuration) override; - -private: - - /** Measurements, one for each axis */ - UPROPERTY() - FTransformGizmoMeasurement Measurements[ 3 ]; - - /** Bounding box translation handles */ - UPROPERTY() - class UVREditorTranslationGizmoHandleGroup* TranslationGizmoHandleGroup; - - /** Bounding box plane translation handles */ - UPROPERTY() - class UVREditorPlaneTranslationGizmoHandleGroup* PlaneTranslationGizmoHandleGroup; - - /** Bounding box rotation handles */ - UPROPERTY() - class UVREditorRotationGizmoHandleGroup* RotationGizmoHandleGroup; - - /** Bounding box stretch handles */ - UPROPERTY() - class UStretchGizmoHandleGroup* StretchGizmoHandleGroup; - - /** Bounding box uniform scale handle */ - UPROPERTY() - class UUniformScaleGizmoHandleGroup* UniformScaleGizmoHandleGroup; -}; diff --git a/Engine/Source/Editor/VREditor/Gizmo/VREditorTranslationGizmoHandle.cpp b/Engine/Source/Editor/VREditor/Gizmo/VREditorTranslationGizmoHandle.cpp deleted file mode 100644 index 732302bd2587..000000000000 --- a/Engine/Source/Editor/VREditor/Gizmo/VREditorTranslationGizmoHandle.cpp +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#include "VREditorTranslationGizmoHandle.h" -#include "UObject/ConstructorHelpers.h" -#include "Components/StaticMeshComponent.h" -#include "Engine/StaticMesh.h" -#include "VIBaseTransformGizmo.h" - -UVREditorTranslationGizmoHandleGroup::UVREditorTranslationGizmoHandleGroup() - : Super() -{ - UStaticMesh* TranslationHandleMesh = nullptr; - { - static ConstructorHelpers::FObjectFinder ObjectFinder( TEXT( "/Engine/VREditor/TransformGizmo/TranslationHandle" ) ); - TranslationHandleMesh = ObjectFinder.Object; - check( TranslationHandleMesh != nullptr ); - } - - const bool bAllowGizmoLighting = false; // @todo vreditor: Not sure if we want this for gizmos or not yet. Needs feedback. Also they're translucent right now. - - for (int32 X = 0; X < 3; ++X) - { - for (int32 Y = 0; Y < 3; ++Y) - { - for (int32 Z = 0; Z < 3; ++Z) - { - FTransformGizmoHandlePlacement HandlePlacement = GetHandlePlacement( X, Y, Z ); - - int32 CenterHandleCount, FacingAxisIndex, CenterAxisIndex; - HandlePlacement.GetCenterHandleCountAndFacingAxisIndex( /* Out */ CenterHandleCount, /* Out */ FacingAxisIndex, /* Out */ CenterAxisIndex ); - - // Don't allow translation/stretching/rotation from the origin - if (CenterHandleCount < 3) - { - const FString HandleName = MakeHandleName( HandlePlacement ); - - // Don't bother with translation handles on the corners. They don't make too much sense. - if (CenterHandleCount == 2) - { - // Translation handle - FString ComponentName = HandleName + TEXT( "TranslationHandle" ); - CreateAndAddMeshHandle( TranslationHandleMesh, ComponentName, HandlePlacement ); - } - } - } - } - } -} - -void UVREditorTranslationGizmoHandleGroup::UpdateGizmoHandleGroup( const FTransform& LocalToWorld, const FBox& LocalBounds, const FVector ViewLocation, const bool bAllHandlesVisible, class UActorComponent* DraggingHandle, - const TArray< UActorComponent* >& HoveringOverHandles, float AnimationAlpha, float GizmoScale, const float GizmoHoverScale, const float GizmoHoverAnimationDuration, bool& bOutIsHoveringOrDraggingThisHandleGroup ) -{ - // Call parent implementation (updates hover animation) - Super::UpdateGizmoHandleGroup(LocalToWorld, LocalBounds, ViewLocation, bAllHandlesVisible, DraggingHandle, HoveringOverHandles, - AnimationAlpha, GizmoScale, GizmoHoverScale, GizmoHoverAnimationDuration, bOutIsHoveringOrDraggingThisHandleGroup ); - - // Place the translation handles - for (int32 HandleIndex = 0; HandleIndex < Handles.Num(); ++HandleIndex) - { - FGizmoHandle& Handle = Handles[ HandleIndex ]; - - UStaticMeshComponent* TranslationHandle = Handle.HandleMesh; - if (TranslationHandle != nullptr) // Can be null if no handle for this specific placement - { - const FTransformGizmoHandlePlacement HandlePlacement = MakeHandlePlacementForIndex( HandleIndex ); - - float GizmoHandleScale = GizmoScale; - const float OffsetFromSide = GizmoHandleScale * - (10.0f + // @todo vreditor tweak: Hard coded handle offset from side of primitive - (1.0f - AnimationAlpha) * 4.0f); // @todo vreditor tweak: Animation offset - - // Make the handle bigger while hovered (but don't affect the offset -- we want it to scale about it's origin) - GizmoHandleScale *= FMath::Lerp( 1.0f, GizmoHoverScale, Handle.HoverAlpha ); - - FVector HandleRelativeLocation = FVector::ZeroVector; - for (int32 AxisIndex = 0; AxisIndex < 3; ++AxisIndex) - { - if (HandlePlacement.Axes[AxisIndex] == ETransformGizmoHandleDirection::Negative) // Negative direction - { - HandleRelativeLocation[AxisIndex] = LocalBounds.Min[AxisIndex] - OffsetFromSide; - } - else if (HandlePlacement.Axes[AxisIndex] == ETransformGizmoHandleDirection::Positive) // Positive direction - { - HandleRelativeLocation[AxisIndex] = LocalBounds.Max[AxisIndex] + OffsetFromSide; - } - else // ETransformGizmoHandleDirection::Center - { - HandleRelativeLocation[AxisIndex] = LocalBounds.GetCenter()[AxisIndex]; - } - } - - TranslationHandle->SetRelativeLocation( HandleRelativeLocation ); - - int32 CenterHandleCount, FacingAxisIndex, CenterAxisIndex; - HandlePlacement.GetCenterHandleCountAndFacingAxisIndex( /* Out */ CenterHandleCount, /* Out */ FacingAxisIndex, /* Out */ CenterAxisIndex ); - check( CenterHandleCount == 2 ); - - const FQuat GizmoSpaceOrientation = GetAxisVector( FacingAxisIndex, HandlePlacement.Axes[FacingAxisIndex] ).ToOrientationQuat(); - TranslationHandle->SetRelativeRotation( GizmoSpaceOrientation ); - - TranslationHandle->SetRelativeScale3D( FVector( GizmoHandleScale ) ); - - // Update material - UpdateHandleColor( FacingAxisIndex, Handle, DraggingHandle, HoveringOverHandles ); - } - } -} - -ETransformGizmoInteractionType UVREditorTranslationGizmoHandleGroup::GetInteractionType() const -{ - return ETransformGizmoInteractionType::Translate; -} - -EGizmoHandleTypes UVREditorTranslationGizmoHandleGroup::GetHandleType() const -{ - return EGizmoHandleTypes::Translate; -} diff --git a/Engine/Source/Editor/VREditor/Gizmo/VREditorTranslationGizmoHandle.h b/Engine/Source/Editor/VREditor/Gizmo/VREditorTranslationGizmoHandle.h deleted file mode 100644 index bb30972e24cf..000000000000 --- a/Engine/Source/Editor/VREditor/Gizmo/VREditorTranslationGizmoHandle.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "CoreMinimal.h" -#include "UObject/ObjectMacros.h" -#include "VIGizmoHandle.h" -#include "VREditorTranslationGizmoHandle.generated.h" - -enum class EGizmoHandleTypes : uint8; - -/** - * Gizmo handle for translating - */ -UCLASS() -class UVREditorTranslationGizmoHandleGroup : public UGizmoHandleGroup -{ - GENERATED_BODY() - -public: - - /** Default constructor that sets up CDO properties */ - UVREditorTranslationGizmoHandleGroup(); - - /** Updates the Gizmo handles */ - virtual void UpdateGizmoHandleGroup( const FTransform& LocalToWorld, const FBox& LocalBounds, const FVector ViewLocation, const bool bAllHandlesVisible, class UActorComponent* DraggingHandle, - const TArray< UActorComponent* >& HoveringOverHandles, float AnimationAlpha, float GizmoScale, const float GizmoHoverScale, const float GizmoHoverAnimationDuration, bool& bOutIsHoveringOrDraggingThisHandleGroup ) override; - - /** Gets the InteractionType for this Gizmo handle */ - virtual ETransformGizmoInteractionType GetInteractionType() const override; - - /** Gets the GizmoType for this Gizmo handle */ - virtual EGizmoHandleTypes GetHandleType() const override; -}; diff --git a/Engine/Source/Editor/VREditor/Interactables/VREditorButton.cpp b/Engine/Source/Editor/VREditor/Interactables/VREditorButton.cpp deleted file mode 100644 index dcb8aa4481a0..000000000000 --- a/Engine/Source/Editor/VREditor/Interactables/VREditorButton.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#include "VREditorButton.h" -#include "UObject/ConstructorHelpers.h" -#include "Components/StaticMeshComponent.h" -#include "Engine/StaticMesh.h" - -AVREditorButton::AVREditorButton() -{ - const bool bAllowGizmoLighting = false; - - // Setup uniform scaling - UStaticMesh* ButtonMesh = nullptr; - { - static ConstructorHelpers::FObjectFinder ObjectFinder( TEXT( "/Engine/VREditor/TransformGizmo/UniformScaleHandle" ) ); - ButtonMesh = ObjectFinder.Object; - check( ButtonMesh != nullptr ); - } - - ButtonMeshComponent = CreateDefaultSubobject( TEXT( "ButtonMeshComponent" ) ); - check( ButtonMeshComponent != nullptr ); - - ButtonMeshComponent->SetStaticMesh( ButtonMesh ); - ButtonMeshComponent->SetMobility( EComponentMobility::Movable ); - - ButtonMeshComponent->SetCollisionEnabled( ECollisionEnabled::QueryOnly ); - ButtonMeshComponent->SetCollisionResponseToAllChannels( ECR_Ignore ); - ButtonMeshComponent->SetCollisionResponseToChannel( COLLISION_GIZMO, ECollisionResponse::ECR_Block ); - ButtonMeshComponent->SetCollisionObjectType( COLLISION_GIZMO ); - - ButtonMeshComponent->bGenerateOverlapEvents = false; - ButtonMeshComponent->SetCanEverAffectNavigation( false ); - ButtonMeshComponent->bCastDynamicShadow = bAllowGizmoLighting; - ButtonMeshComponent->bCastStaticShadow = false; - ButtonMeshComponent->bAffectDistanceFieldLighting = bAllowGizmoLighting; - ButtonMeshComponent->bAffectDynamicIndirectLighting = bAllowGizmoLighting; -} - -void AVREditorButton::OnPressed( UViewportInteractor* Interactor, const FHitResult& InHitResult, bool& bOutResultedInDrag ) -{ - OnPressedEvent.Broadcast( this, Interactor ); -} - -void AVREditorButton::OnHover( UViewportInteractor* Interactor ) -{ - OnHoverEvent.Broadcast( this, Interactor ); -} - -void AVREditorButton::OnHoverEnter( UViewportInteractor* Interactor, const FHitResult& InHitResult ) -{ - OnHoverEnterEvent.Broadcast( this, Interactor ); -} - -void AVREditorButton::OnHoverLeave( UViewportInteractor* Interactor, const UActorComponent* NewComponent ) -{ - OnHoverLeaveEvent.Broadcast( this, Interactor ); -} - -void AVREditorButton::OnDragRelease( UViewportInteractor* Interactor ) -{ - OnReleaseEvent.Broadcast( this, Interactor ); -} diff --git a/Engine/Source/Editor/VREditor/Interactables/VREditorButton.h b/Engine/Source/Editor/VREditor/Interactables/VREditorButton.h deleted file mode 100644 index c4d44de8403b..000000000000 --- a/Engine/Source/Editor/VREditor/Interactables/VREditorButton.h +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "CoreMinimal.h" -#include "UObject/ObjectMacros.h" -#include "Editor/VREditor/VREditorBaseActor.h" -#include "ViewportInteractableInterface.h" -#include "VREditorButton.generated.h" - -class UStaticMeshComponent; -class UViewportInteractor; - -//Forward declarations -class UViewportInteractor; - - -/** -* A button for VR Editor -*/ -UCLASS() -class AVREditorButton : public AVREditorBaseActor, public IViewportInteractableInterface -{ - GENERATED_BODY() - -public: - - /** Default constructor which sets up safe defaults */ - AVREditorButton(); - - // Begin IViewportInteractableInterface - virtual void OnPressed( UViewportInteractor* Interactor, const FHitResult& InHitResult, bool& bOutResultedInDrag ) override; - virtual void OnHover( UViewportInteractor* Interactor ) override; - virtual void OnHoverEnter( UViewportInteractor* Interactor, const FHitResult& InHitResult ) override; - virtual void OnHoverLeave( UViewportInteractor* Interactor, const UActorComponent* NewComponent ) override; - virtual void OnDragRelease( UViewportInteractor* Interactor ) override; - virtual class UViewportDragOperationComponent* GetDragOperationComponent() override { return nullptr; }; - // End IViewportInteractableInterface - - /** Gets the on pressed event */ - DECLARE_EVENT_TwoParams( AVREditorButton, FOnPressedEvent, AVREditorButton*, UViewportInteractor* ); - FOnPressedEvent& GetOnPressed() { return OnPressedEvent; } - - /** Gets the on hover event */ - DECLARE_EVENT_TwoParams( AVREditorButton, FOnHoverEvent, AVREditorButton*, UViewportInteractor* ); - FOnHoverEvent& GetOnHover() { return OnHoverEvent; } - - /** Gets the on hover enter event */ - DECLARE_EVENT_TwoParams( AVREditorButton, FOnHoverEnterEvent, AVREditorButton*, UViewportInteractor* ); - FOnHoverEnterEvent& GetOnHoverEnter() { return OnHoverEnterEvent; } - - /** Gets the on hover leave event */ - DECLARE_EVENT_TwoParams( AVREditorButton, FOnHoverLeaveEvent, AVREditorButton*, UViewportInteractor* ); - FOnHoverLeaveEvent & GetOnHoverLeave() { return OnHoverLeaveEvent; } - - /** Gets the on release event */ - DECLARE_EVENT_TwoParams( AVREditorButton, FOnReleaseEvent, AVREditorButton*, UViewportInteractor* ); - FOnReleaseEvent& GetOnRelease() { return OnReleaseEvent; } - -private: - - /** Mesh for the button to interact with */ - UPROPERTY() - UStaticMeshComponent* ButtonMeshComponent; - - /** Broadcasted when pressed on this interactable by an interactor */ - FOnPressedEvent OnPressedEvent; - - /** Broadcasted when interactor is hovering over this interactable */ - FOnHoverEvent OnHoverEvent; - - /** Broadcasted when interactor started hovering over this interactable */ - FOnHoverEnterEvent OnHoverEnterEvent; - - /** Broadcasted when interactor stopped hovering over this interactable */ - FOnHoverLeaveEvent OnHoverLeaveEvent; - - /** Broadcasted when interactor released this interactable */ - FOnReleaseEvent OnReleaseEvent; -}; diff --git a/Engine/Source/Editor/VREditor/Public/IVREditorModule.h b/Engine/Source/Editor/VREditor/Public/IVREditorModule.h index b4401b5f81ad..87451249d7a0 100644 --- a/Engine/Source/Editor/VREditor/Public/IVREditorModule.h +++ b/Engine/Source/Editor/VREditor/Public/IVREditorModule.h @@ -65,6 +65,7 @@ public: * @return True if the VREditor is currently running */ virtual bool IsVREditorModeActive() = 0; + /** * Get the current VREditor running * @@ -72,6 +73,13 @@ public: */ virtual class UVREditorMode* GetVRMode() = 0; + /** + * Update the actor preview (for example, the view from a camera attached to a pawn) in VR mode + * + * @param The new actor preview widget + */ + virtual void UpdateActorPreview(TSharedRef InWidget) = 0; + /** Gets the radial menu extender. This can be used to add your own menu items to the VR radial menu */ virtual const TSharedRef& GetRadialMenuExtender() = 0; diff --git a/Engine/Source/Editor/VREditor/Public/VREditorAssetContainer.h b/Engine/Source/Editor/VREditor/Public/VREditorAssetContainer.h index 3cf026eef4fc..f0b79046bdb7 100644 --- a/Engine/Source/Editor/VREditor/Public/VREditorAssetContainer.h +++ b/Engine/Source/Editor/VREditor/Public/VREditorAssetContainer.h @@ -56,6 +56,9 @@ public: UPROPERTY(EditAnywhere, Category = Sound) USoundCue* ButtonPressSound; + UPROPERTY(EditAnywhere, Category = Sound) + USoundBase* AutoScaleSound; + // // Meshes // @@ -108,6 +111,9 @@ public: UPROPERTY(EditAnywhere, Category = Mesh) UStaticMesh* RadialMenuPointerMesh; + UPROPERTY(EditAnywhere, Category = Mesh) + UStaticMesh* PointerCursorMesh; + // // Materials // diff --git a/Engine/Source/Editor/VREditor/Public/VREditorInteractor.h b/Engine/Source/Editor/VREditor/Public/VREditorInteractor.h index 4398e56b14ff..8ab0a42b5057 100644 --- a/Engine/Source/Editor/VREditor/Public/VREditorInteractor.h +++ b/Engine/Source/Editor/VREditor/Public/VREditorInteractor.h @@ -27,11 +27,12 @@ enum class EControllerType : uint8 UCLASS() class VREDITOR_API UVREditorInteractor : public UViewportInteractor { - GENERATED_UCLASS_BODY() + GENERATED_BODY() public: - virtual ~UVREditorInteractor(); + /** Default constructor */ + UVREditorInteractor(); /** Initialize default values */ virtual void Init( class UVREditorMode* InVRMode ); diff --git a/Engine/Source/Editor/VREditor/Public/VREditorMode.h b/Engine/Source/Editor/VREditor/Public/VREditorMode.h index 26d2038c509f..7ff92aba68c5 100644 --- a/Engine/Source/Editor/VREditor/Public/VREditorMode.h +++ b/Engine/Source/Editor/VREditor/Public/VREditorMode.h @@ -56,9 +56,6 @@ public: /** Default constructor */ UVREditorMode(); - /** Cleans up this mode, called when the editor is shutting down */ - virtual ~UVREditorMode(); - /** Initialize the VREditor */ virtual void Init() override; @@ -305,7 +302,7 @@ public: protected: virtual void TransitionWorld(UWorld* NewWorld) override; - virtual void LeftSimulateInEditor() override; + virtual void LeftSimulateInEditor(UWorld* SimulateWorld) override; private: @@ -466,6 +463,9 @@ public: /** Runtime and plugin modules can force VR Editor to refresh using this function */ void RefreshVREditorSequencer(class ISequencer* InCurrentSequencer); + /** Refresh the current actor preview widget on an in-world UI panel */ + void RefreshActorPreviewWidget(TSharedRef InWidget); + /** Returns the currently active sequencer */ class ISequencer* GetCurrentSequencer(); diff --git a/Engine/Source/Editor/VREditor/Public/VRModeSettings.h b/Engine/Source/Editor/VREditor/Public/VRModeSettings.h index b79c4127dc74..958819e8cc4e 100644 --- a/Engine/Source/Editor/VREditor/Public/VRModeSettings.h +++ b/Engine/Source/Editor/VREditor/Public/VRModeSettings.h @@ -23,15 +23,19 @@ enum class EInteractorHand : uint8 UCLASS(config = EditorSettings) class VREDITOR_API UVRModeSettings : public UObject { + GENERATED_BODY() + public: - GENERATED_UCLASS_BODY() + + /** Default constructor that sets up CDO properties */ + UVRModeSettings(); /**If true, wearing a Vive or Oculus Rift headset will automatically enter VR Editing mode */ UPROPERTY(EditAnywhere, config, Category = "General", meta = (DisplayName = "Enable VR Mode Auto-Entry")) uint32 bEnableAutoVREditMode : 1; // Which hand should have the primary interactor laser on it - UPROPERTY(Category = "General", EditAnywhere) + UPROPERTY(EditAnywhere, config, Category = "General") EInteractorHand InteractorHand; /** Show the movement grid for orientation while moving through the world */ diff --git a/Engine/Source/Editor/VREditor/Teleporter/VREditorAutoScaler.cpp b/Engine/Source/Editor/VREditor/Teleporter/VREditorAutoScaler.cpp index 029fb5455576..bb027c4460b8 100644 --- a/Engine/Source/Editor/VREditor/Teleporter/VREditorAutoScaler.cpp +++ b/Engine/Source/Editor/VREditor/Teleporter/VREditorAutoScaler.cpp @@ -5,25 +5,20 @@ #include "ViewportInteractionTypes.h" #include "ViewportWorldInteraction.h" #include "ViewportInteractor.h" -#include "Kismet/GameplayStatics.h" -#include "GameFramework/WorldSettings.h" #include "Sound/SoundCue.h" +#include "VREditorAssetContainer.h" namespace VREd { static FAutoConsoleVariable AllowResetScale(TEXT("VREd.AllowResetScale"), 1, TEXT("Allowed to reset world to meters to default world to meters")); } -UVREditorAutoScaler::UVREditorAutoScaler( const FObjectInitializer& ObjectInitializer ) : - Super( ObjectInitializer ), - VRMode( nullptr ) +UVREditorAutoScaler::UVREditorAutoScaler() : + Super(), + VRMode(nullptr) { - // Load sounds - ScaleSound = LoadObject( nullptr, TEXT( "/Engine/VREditor/Sounds/VR_teleport_Cue" ) ); - check( ScaleSound != nullptr ); } - void UVREditorAutoScaler::Init( class UVREditorMode* InVRMode ) { VRMode = InVRMode; @@ -37,7 +32,6 @@ void UVREditorAutoScaler::Shutdown() VRMode = nullptr; } - void UVREditorAutoScaler::Scale( const float NewWorldToMetersScale ) { if (VREd::AllowResetScale->GetInt() != 0) @@ -47,7 +41,8 @@ void UVREditorAutoScaler::Scale( const float NewWorldToMetersScale ) // Set the new world to meters scale. WorldInteraction->SetWorldToMetersScale( NewWorldToMetersScale, true ); WorldInteraction->SkipInteractiveWorldMovementThisFrame(); - UGameplayStatics::PlaySound2D( VRMode->GetWorld(), ScaleSound ); + + VRMode->PlaySound(VRMode->GetAssetContainer().AutoScaleSound, VRMode->GetHeadTransform().GetLocation()); } } diff --git a/Engine/Source/Editor/VREditor/Teleporter/VREditorAutoScaler.h b/Engine/Source/Editor/VREditor/Teleporter/VREditorAutoScaler.h index e47b539547f0..b573c7c09ae9 100644 --- a/Engine/Source/Editor/VREditor/Teleporter/VREditorAutoScaler.h +++ b/Engine/Source/Editor/VREditor/Teleporter/VREditorAutoScaler.h @@ -15,10 +15,13 @@ class UVREditorMode; UCLASS() class UVREditorAutoScaler: public UObject { - GENERATED_UCLASS_BODY() + GENERATED_BODY() public: + /** Default constructor */ + UVREditorAutoScaler(); + /** Initializes the automatic scaler */ void Init( class UVREditorMode* InVRMode ); @@ -37,8 +40,4 @@ private: /** Owning mode */ UPROPERTY() UVREditorMode* VRMode; - - /** Teleport sound */ - UPROPERTY() - class USoundCue* ScaleSound; }; diff --git a/Engine/Source/Editor/VREditor/Teleporter/VREditorTeleporter.cpp b/Engine/Source/Editor/VREditor/Teleporter/VREditorTeleporter.cpp index df85e1ddfddd..bc84e607ae38 100644 --- a/Engine/Source/Editor/VREditor/Teleporter/VREditorTeleporter.cpp +++ b/Engine/Source/Editor/VREditor/Teleporter/VREditorTeleporter.cpp @@ -56,17 +56,6 @@ AVREditorTeleporter::AVREditorTeleporter(): { } -AVREditorTeleporter::~AVREditorTeleporter() -{ - TeleportDirectionMeshComponent = nullptr; - HMDMeshComponent = nullptr; - LeftMotionControllerMeshComponent = nullptr; - RightMotionControllerMeshComponent = nullptr; - TeleportMID = nullptr; - InteractorTryingTeleport = nullptr; - VRMode = nullptr; -} - void AVREditorTeleporter::Init(UVREditorMode* InMode) { VRMode = InMode; diff --git a/Engine/Source/Editor/VREditor/Teleporter/VREditorTeleporter.h b/Engine/Source/Editor/VREditor/Teleporter/VREditorTeleporter.h index 9ae7d688ecd5..816c8d6ebef5 100644 --- a/Engine/Source/Editor/VREditor/Teleporter/VREditorTeleporter.h +++ b/Engine/Source/Editor/VREditor/Teleporter/VREditorTeleporter.h @@ -25,9 +25,6 @@ public: /** Default constructor that sets up CDO properties */ AVREditorTeleporter(); - /** Deconstructor */ - virtual ~AVREditorTeleporter(); - /** Initializes the teleporter */ void Init(class UVREditorMode* InMode); diff --git a/Engine/Source/Editor/VREditor/UI/VREditorDockableWindow.cpp b/Engine/Source/Editor/VREditor/UI/VREditorDockableWindow.cpp index 3dbe2753bff9..44740583583b 100644 --- a/Engine/Source/Editor/VREditor/UI/VREditorDockableWindow.cpp +++ b/Engine/Source/Editor/VREditor/UI/VREditorDockableWindow.cpp @@ -103,18 +103,6 @@ AVREditorDockableWindow::AVREditorDockableWindow() : DragOperationComponent->SetDragOperationClass( UDockableWindowDragOperation::StaticClass() ); } - -AVREditorDockableWindow::~AVREditorDockableWindow() -{ - SelectionBarMeshComponent = nullptr; - CloseButtonMeshComponent = nullptr; - SelectionBarMID = nullptr; - SelectionBarTranslucentMID = nullptr; - CloseButtonMID = nullptr; - CloseButtonTranslucentMID = nullptr; - DragOperationComponent = nullptr; -} - void AVREditorDockableWindow::SetupWidgetComponent() { Super::SetupWidgetComponent(); diff --git a/Engine/Source/Editor/VREditor/UI/VREditorDockableWindow.h b/Engine/Source/Editor/VREditor/UI/VREditorDockableWindow.h index 929ad6a1c9ae..3e901b9442a1 100644 --- a/Engine/Source/Editor/VREditor/UI/VREditorDockableWindow.h +++ b/Engine/Source/Editor/VREditor/UI/VREditorDockableWindow.h @@ -25,9 +25,6 @@ public: /** Default constructor */ AVREditorDockableWindow(); - /** Destructor */ - ~AVREditorDockableWindow(); - /** Updates the meshes for the UI */ virtual void TickManually( float DeltaTime ) override; diff --git a/Engine/Source/Editor/VREditor/UI/VREditorFloatingUI.cpp b/Engine/Source/Editor/VREditor/UI/VREditorFloatingUI.cpp index e3e4bf439386..a544528dc516 100644 --- a/Engine/Source/Editor/VREditor/UI/VREditorFloatingUI.cpp +++ b/Engine/Source/Editor/VREditor/UI/VREditorFloatingUI.cpp @@ -26,7 +26,9 @@ AVREditorFloatingUI::AVREditorFloatingUI() bShouldBeVisible(), FadeAlpha( 1.0f ), FadeDelay( 0.0f ), - InitialScale( 1.0f ) + InitialScale( 1.0f ), + UISystemID(NAME_None), + bClearWidgetOnHide(false) { const bool bTransient = true; USceneComponent* SceneComponent = CreateDefaultSubobject( TEXT( "SceneComponent" ), bTransient ); @@ -118,11 +120,13 @@ void AVREditorFloatingUI::SetupWidgetComponent() } } -void AVREditorFloatingUI::SetSlateWidget( UVREditorUISystem& InitOwner, const TSharedRef& InitSlateWidget, const FIntPoint InitResolution, const float InitScale, const EDockedTo InitDockedTo ) +void AVREditorFloatingUI::SetSlateWidget( UVREditorUISystem& InitOwner, const VREditorPanelID& InID, const TSharedRef& InitSlateWidget, const FIntPoint InitResolution, const float InitScale, const EDockedTo InitDockedTo ) { Owner = &InitOwner; SetVRMode( &Owner->GetOwner() ); + UISystemID = InID; + SlateWidget = InitSlateWidget; Resolution = InitResolution; @@ -136,12 +140,19 @@ void AVREditorFloatingUI::SetSlateWidget( UVREditorUISystem& InitOwner, const TS SetupWidgetComponent(); } +void AVREditorFloatingUI::SetSlateWidget(const TSharedRef& InitSlateWidget) +{ + SlateWidget = InitSlateWidget; + SetupWidgetComponent(); +} -void AVREditorFloatingUI::SetUMGWidget( UVREditorUISystem& InitOwner, TSubclassOf InitUserWidgetClass, const FIntPoint InitResolution, const float InitScale, const EDockedTo InitDockedTo ) +void AVREditorFloatingUI::SetUMGWidget( UVREditorUISystem& InitOwner, const VREditorPanelID& InID, TSubclassOf InitUserWidgetClass, const FIntPoint InitResolution, const float InitScale, const EDockedTo InitDockedTo ) { Owner = &InitOwner; SetVRMode( &Owner->GetOwner() ); + UISystemID = InID; + check( InitUserWidgetClass != nullptr ); UserWidgetClass = InitUserWidgetClass; @@ -236,6 +247,12 @@ void AVREditorFloatingUI::UpdateFadingState( const float DeltaTime ) SetActorHiddenInGame( true ); WidgetComponent->SetVisibility( false ); FadeDelay = 0.0f; + + if (bClearWidgetOnHide) + { + SetSlateWidget(SNullWidget::NullWidget); + bClearWidgetOnHide = false; + } } } @@ -287,7 +304,7 @@ float AVREditorFloatingUI::GetInitialScale() const return InitialScale; } -void AVREditorFloatingUI::ShowUI( const bool bShow, const bool bAllowFading, const float InitFadeDelay ) +void AVREditorFloatingUI::ShowUI( const bool bShow, const bool bAllowFading, const float InitFadeDelay, const bool bInClearWidgetOnHide ) { if( !bShouldBeVisible.IsSet() || bShow != bShouldBeVisible.GetValue() ) { @@ -298,7 +315,19 @@ void AVREditorFloatingUI::ShowUI( const bool bShow, const bool bAllowFading, con SetActorHiddenInGame( !bShow ); WidgetComponent->SetVisibility( bShow ); FadeAlpha = bShow ? 1.0f : 0.0f; + if (bInClearWidgetOnHide ) + { + SetSlateWidget(SNullWidget::NullWidget); + } } + else + { + if (bInClearWidgetOnHide) + { + bClearWidgetOnHide = bInClearWidgetOnHide; + } + } + // Set collision on components if (bShow) @@ -316,6 +345,24 @@ void AVREditorFloatingUI::ShowUI( const bool bShow, const bool bAllowFading, con } +void AVREditorFloatingUI::SetResolution(const FIntPoint& InResolution) +{ + Resolution = InResolution; + check(Resolution.X > 0 && Resolution.Y > 0); + + WidgetComponent->SetDrawSize(FVector2D(Resolution.X, Resolution.Y)); // NOTE: Must be called before + + { + const float WindowMeshSize = 100.0f; // Size of imported mesh, we need to inverse compensate for + + const FVector WindowMeshScale = FVector( + 1.0f, + GetSize().X / WindowMeshSize, + GetSize().Y / WindowMeshSize) * GetOwner().GetOwner().GetWorldScaleFactor(); + WindowMeshComponent->SetRelativeScale3D(WindowMeshScale); + } +} + FVector2D AVREditorFloatingUI::GetSize() const { const float Aspect = (float)Resolution.X / (float)Resolution.Y; @@ -343,4 +390,20 @@ void AVREditorFloatingUI::SetWidgetComponentScale(const FVector& InScale) { const float Aspect = (float)Resolution.X / (float)Resolution.Y; WidgetComponent->SetWorldScale3D(FVector(1.0f / InScale.X, 1.0f / (float)Resolution.X, 1.0f / (float)Resolution.Y / Aspect) * InScale); -} \ No newline at end of file +} + +VREditorPanelID AVREditorFloatingUI::GetID() const +{ + return UISystemID; +} + +TSharedPtr AVREditorFloatingUI::GetSlateWidget() const +{ + return SlateWidget; +} + +void AVREditorFloatingUI::SetWindowMesh(class UStaticMesh* InWindowMesh) +{ + check(InWindowMesh != nullptr); + WindowMeshComponent->SetStaticMesh(InWindowMesh); +} diff --git a/Engine/Source/Editor/VREditor/UI/VREditorFloatingUI.h b/Engine/Source/Editor/VREditor/UI/VREditorFloatingUI.h index 73280eaf18f1..a7db1ce975f6 100644 --- a/Engine/Source/Editor/VREditor/UI/VREditorFloatingUI.h +++ b/Engine/Source/Editor/VREditor/UI/VREditorFloatingUI.h @@ -11,6 +11,8 @@ class UVREditorBaseUserWidget; class UVREditorUISystem; +typedef FName VREditorPanelID; + /** * Represents an interactive floating UI panel in the VR Editor */ @@ -25,10 +27,11 @@ public: AVREditorFloatingUI(); /** Creates a FVREditorFloatingUI using a Slate widget, and sets up safe defaults */ - void SetSlateWidget( class UVREditorUISystem& InitOwner, const TSharedRef& InitSlateWidget, const FIntPoint InitResolution, const float InitScale, const EDockedTo InitDockedTo ); + void SetSlateWidget( class UVREditorUISystem& InitOwner, const VREditorPanelID& InID, const TSharedRef& InitSlateWidget, const FIntPoint InitResolution, const float InitScale, const EDockedTo InitDockedTo ); + void SetSlateWidget(const TSharedRef& InitSlateWidget); /** Creates a FVREditorFloatingUI using a UMG user widget, and sets up safe defaults */ - void SetUMGWidget( class UVREditorUISystem& InitOwner, class TSubclassOf InitUserWidgetClass, const FIntPoint InitResolution, const float InitScale, const EDockedTo InitDockedTo ); + void SetUMGWidget(class UVREditorUISystem& InitOwner, const VREditorPanelID& InID, class TSubclassOf InitUserWidgetClass, const FIntPoint InitResolution, const float InitScale, const EDockedTo InitDockedTo); /** @return Returns true if the UI is visible (or wants to be visible -- it might be transitioning */ bool IsUIVisible() const @@ -37,7 +40,10 @@ public: } /** Shows or hides the UI (also enables collision, and performs a transition effect) */ - void ShowUI( const bool bShow, const bool bAllowFading = true, const float InitFadeDelay = 0.0f ); + void ShowUI( const bool bShow, const bool bAllowFading = true, const float InitFadeDelay = 0.0f, const bool bInClearWidgetOnHide = false ); + + /** Sets the resolution of this floating UI panel and resets the window mesh accordingly. */ + void SetResolution(const FIntPoint& InResolution); /** Returns the widget component for this UI, or nullptr if not spawned right now */ class UVREditorWidgetComponent* GetWidgetComponent() @@ -104,6 +110,15 @@ public: /** Called to finish setting everything up, after a widget has been assigned */ virtual void SetupWidgetComponent(); + /** Gets the ID of this panel. */ + VREditorPanelID GetID() const; + + /** Gets the current slate widget. */ + TSharedPtr GetSlateWidget() const; + + /** Set mesh on window mesh component. */ + void SetWindowMesh(class UStaticMesh* InWindowMesh); + protected: /** Returns a scale to use for this widget that takes into account animation */ @@ -157,5 +172,12 @@ private: /** The starting scale of this UI */ float InitialScale; + + /** The ID of this floating UI. */ + VREditorPanelID UISystemID; + + /** Null out the widget when hidden. */ + bool bClearWidgetOnHide; + }; diff --git a/Engine/Source/Editor/VREditor/UI/VREditorRadialFloatingUI.cpp b/Engine/Source/Editor/VREditor/UI/VREditorRadialFloatingUI.cpp index 7d5c9017bdfc..25ac7fa20928 100644 --- a/Engine/Source/Editor/VREditor/UI/VREditorRadialFloatingUI.cpp +++ b/Engine/Source/Editor/VREditor/UI/VREditorRadialFloatingUI.cpp @@ -165,7 +165,7 @@ void AVREditorRadialFloatingUI::Reset() } } - for (TSharedPtr SlateWidget : SlateWidgets) + for (TSharedPtr &SlateWidget : SlateWidgets) { SlateWidget = nullptr; } @@ -208,7 +208,7 @@ void AVREditorRadialFloatingUI::Destroyed() CentralWidgetComponent->SetSlateWidget(nullptr); CentralWidgetComponent = nullptr; - for(TSharedPtr SlateWidget : SlateWidgets) + for(TSharedPtr &SlateWidget : SlateWidgets) { SlateWidget = nullptr; } diff --git a/Engine/Source/Editor/VREditor/UI/VREditorUISystem.cpp b/Engine/Source/Editor/VREditor/UI/VREditorUISystem.cpp index 9f8bcb21d62e..83cb8c81498d 100644 --- a/Engine/Source/Editor/VREditor/UI/VREditorUISystem.cpp +++ b/Engine/Source/Editor/VREditor/UI/VREditorUISystem.cpp @@ -133,17 +133,29 @@ namespace VREd static FAutoConsoleVariable UIPanelOpenDistance( TEXT( "VREd.UIPanelOpenDistance" ), 20.f, TEXT( "Distance to spawn a panel from the hand in centimeters" ) ); static FAutoConsoleVariable UIPanelOpenRotationPitchOffset( TEXT( "VREd.UIPanelOpenRotationPitchOffset" ), 45.0f, TEXT( "The pitch rotation offset in degrees when spawning a panel in front of the motioncontroller" ) ); static FAutoConsoleVariable ColorPickerDockSpawnOffset( TEXT( "VREd.ColorPickerDockSpawnOffset" ), 3.f, TEXT( "Offset of where the color picker spawns" ) ); - static FAutoConsoleVariable EnableQuickMenu(TEXT("VREd.EnableQuickMenu"), 0, TEXT("Whether the quick menu should be enabled. Disabled by default.")); static FAutoConsoleVariable SteamVRTrackpadDeadzone(TEXT("VREd.SteamVRTrackpadDeadzone"), 0.3f, TEXT("The deadzone for the Vive motion controller trackpad")); static const FTransform DefaultColorPickerTransform( FRotator( -10, 180, 0), FVector( 30, 35, 0 ), FVector( 1 ) ); } +const VREditorPanelID UVREditorUISystem::ContentBrowserPanelID = VREditorPanelID("ContentBrowser"); +const VREditorPanelID UVREditorUISystem::WorldOutlinerPanelID = VREditorPanelID("WorldOutliner"); +const VREditorPanelID UVREditorUISystem::DetailsPanelID = VREditorPanelID("Details"); +const VREditorPanelID UVREditorUISystem::ModesPanelID = VREditorPanelID("Modes"); +const VREditorPanelID UVREditorUISystem::TutorialPanelID = VREditorPanelID("Tutorial"); +const VREditorPanelID UVREditorUISystem::AssetEditorPanelID = VREditorPanelID("AssetEditor"); +const VREditorPanelID UVREditorUISystem::WorldSettingsPanelID = VREditorPanelID("WorldSettings"); +const VREditorPanelID UVREditorUISystem::ColorPickerPanelID = VREditorPanelID("ColorPicker"); +const VREditorPanelID UVREditorUISystem::SequencerPanelID = VREditorPanelID("SequencerUI"); +const VREditorPanelID UVREditorUISystem::InfoDisplayPanelID = VREditorPanelID("InfoDisplay"); +const VREditorPanelID UVREditorUISystem::RadialMenuPanelID = VREditorPanelID("RadialMenu"); +const VREditorPanelID UVREditorUISystem::TabManagerPanelID = VREditorPanelID("TabManagerPanel"); +const VREditorPanelID UVREditorUISystem::ActorPreviewUIID = VREditorPanelID("ActorPreviewUI"); UVREditorUISystem::UVREditorUISystem() : Super(), VRMode( nullptr ), FloatingUIs(), - QuickMenuUI( nullptr ), + InfoDisplayPanel( nullptr ), QuickRadialMenu( nullptr ), RadialMenuHideDelayTime( 0.0f ), InteractorDraggingUI( nullptr ), @@ -157,7 +169,6 @@ UVREditorUISystem::UVREditorUISystem() : DragPanelFromOpenTime(0.0f), bPanelCanScale(true) { - EditorUIPanels.SetNumZeroed( (int32)EEditorUIPanel::TotalCount ); } void UVREditorUISystem::Init(UVREditorMode* InVRMode) @@ -215,13 +226,10 @@ void UVREditorUISystem::Shutdown() if (VRMode != nullptr) { - UViewportWorldInteraction* WorldInteraction = &VRMode->GetWorldInteraction(); - if (WorldInteraction != nullptr) - { - WorldInteraction->OnPreviewInputAction().RemoveAll(this); - WorldInteraction->OnViewportInteractionInputAction().RemoveAll(this); - WorldInteraction->OnViewportInteractionHoverUpdate().RemoveAll(this); - } + UViewportWorldInteraction& WorldInteraction = VRMode->GetWorldInteraction(); + WorldInteraction.OnPreviewInputAction().RemoveAll(this); + WorldInteraction.OnViewportInteractionInputAction().RemoveAll(this); + WorldInteraction.OnViewportInteractionHoverUpdate().RemoveAll(this); } GLevelEditorModeTools().OnEditorModeChanged().RemoveAll(this); @@ -234,24 +242,34 @@ void UVREditorUISystem::Shutdown() // If we have a sequence tab open, reset its widget and close the associated Sequencer if (GetOwner().GetCurrentSequencer() != nullptr) { - EditorUIPanels[(int32)EEditorUIPanel::SequencerUI]->SetSlateWidget(*this, SNullWidget::NullWidget, FIntPoint(VREd::SequencerUIResolutionX->GetFloat(), VREd::SequencerUIResolutionY->GetFloat()), VREd::EditorUISize->GetFloat(), AVREditorFloatingUI::EDockedTo::Nothing); + AVREditorFloatingUI* SequencerPanel = GetPanel(SequencerPanelID); + if (SequencerPanel != nullptr) + { + SequencerPanel->SetSlateWidget(*this, SequencerPanelID, SNullWidget::NullWidget, FIntPoint(VREd::SequencerUIResolutionX->GetFloat(), VREd::SequencerUIResolutionY->GetFloat()), VREd::EditorUISize->GetFloat(), AVREditorFloatingUI::EDockedTo::Nothing); + } FVREditorActionCallbacks::CloseSequencer(GetOwner().GetCurrentSequencer()->GetRootMovieSceneSequence()); } - for (AVREditorFloatingUI* FloatingUIPtr : FloatingUIs) + if (InfoDisplayPanel != nullptr) { - if (FloatingUIPtr != nullptr) - { - FloatingUIPtr->Destroy(false, false); - FloatingUIPtr = nullptr; - } + InfoDisplayPanel->SetSlateWidget(SNullWidget::NullWidget); } + for (auto& CurrentUI : FloatingUIs) + { + AVREditorFloatingUI* UIPanel = CurrentUI.Value; + if (UIPanel != nullptr) + { + UIPanel->Destroy(false, false); + UIPanel = nullptr; + } + } FloatingUIs.Reset(); - EditorUIPanels.Reset(); + QuickRadialMenu->Destroy(false, false); QuickRadialMenu = nullptr; - QuickMenuUI = nullptr; + InfoDisplayPanel = nullptr; + CurrentWidgetOnInfoDisplay.Reset(); ProxyTabManager.Reset(); @@ -415,7 +433,7 @@ void UVREditorUISystem::OnPreviewInputAction(FEditorViewportClient& ViewportClie } } } - else if (WidgetComponent != nullptr) + else { // Only allow clicks to our own widget components // Always mark the event as handled so that the editor doesn't try to select the widget component @@ -775,7 +793,7 @@ void UVREditorUISystem::Tick( FEditorViewportClient* ViewportClient, const float FSlateApplication::Get().SetUserFocus(0, ViewportClient->GetEditorViewportWidget()); } - const FTimespan CompareTime = FMath::Max(UIInteractor->GetLastActiveTrackpadUpdateTime(), RadialMenuModifierSpawnTime); + const FTimespan CompareTime = FMath::Max(UIInteractor->GetLastActiveTrackpadUpdateTime(), RadialMenuModifierSpawnTime); //-V595 if (!bRadialMenuIsNumpad && FTimespan::FromSeconds(FPlatformTime::Seconds()) - CompareTime > FTimespan::FromSeconds(1.5f)) { @@ -792,78 +810,7 @@ void UVREditorUISystem::Tick( FEditorViewportClient* ViewportClient, const float } } - // Figure out if one hand is "aiming toward" the other hand. We'll fade in a UI on the hand being - // aimed at when the user does this. - if( QuickMenuUI != nullptr && VREd::EnableQuickMenu->GetInt() == 1) - { - UVREditorInteractor* HandInteractorWithQuickMenu = nullptr; - if( QuickMenuUI->IsUIVisible() ) - { - HandInteractorWithQuickMenu = GetOwner().GetHandInteractor( QuickMenuUI->GetDockedTo() == AVREditorFloatingUI::EDockedTo::LeftArm ? EControllerHand::Left : EControllerHand::Right ); - } - const float WorldScaleFactor = GetOwner().GetWorldScaleFactor(); - - UViewportInteractor* HandInteractorThatNeedsQuickMenu = nullptr; - for( UViewportInteractor* Interactor : GetOwner().GetWorldInteraction().GetInteractors() ) - { - UViewportInteractor* OtherInteractor = Interactor->GetOtherInteractor(); - if( Interactor->GetDraggingMode() == EViewportInteractionDraggingMode::Nothing && - OtherInteractor != nullptr ) - { - // @todo vreditor tweak: Weird to hard code this here. Probably should be an accessor on the hand itself, and based on the actual device type - const FTransform UICapsuleTransform = OtherInteractor->GetTransform(); - const FVector UICapsuleStart = FVector( -16.0f, 0.0f, 0.0f ) * WorldScaleFactor; - const FVector UICapsuleEnd = FVector( -23.0f, 0.0f, 0.0f ) * WorldScaleFactor; - const float UICapsuleLocalRadius = 10.0f * WorldScaleFactor; - const float MinDistanceToUICapsule = 10.0f * WorldScaleFactor; // @todo vreditor tweak - const FVector UIForwardVector = FVector::UpVector; - const float MinDotForAimingAtOtherHand = 0.25f; // @todo vreditor tweak - - // Don't spawn a quick menu on a hand that has a radial menu visible -- they will cover each other up! - UVREditorInteractor* OtherVRInteractor = Cast( OtherInteractor ); - if( OtherVRInteractor != nullptr && !IsShowingRadialMenu( OtherVRInteractor ) ) - { - if( GetOwner().IsHandAimingTowardsCapsule( Interactor, UICapsuleTransform, UICapsuleStart, UICapsuleEnd, UICapsuleLocalRadius, MinDistanceToUICapsule, UIForwardVector, MinDotForAimingAtOtherHand ) ) - { - HandInteractorThatNeedsQuickMenu = OtherInteractor; - } - } - } - } - - // If we don't need a quick menu, or if a different hand needs to spawn it, then kill the existing menu - if( QuickMenuUI->IsUIVisible() && HandInteractorWithQuickMenu != nullptr && - ( HandInteractorThatNeedsQuickMenu == nullptr || HandInteractorThatNeedsQuickMenu != HandInteractorWithQuickMenu ) ) - { - // Despawn - HandInteractorWithQuickMenu->SetHasUIOnForearm( false ); - QuickMenuUI->ShowUI( false ); - // Reset all the currently animating buttons to their minimum scale and stop animating them - for (FVRButton& VRButton : VRButtons) - { - if(VRButton.AnimationDirection != EVREditorAnimationState::None) - { - VRButton.CurrentScale = VRButton.MinScale; - VRButton.ButtonWidget->SetRelativeScale3D(VRButton.CurrentScale*VRButton.OriginalRelativeScale*(GetOwner().GetWorldScaleFactor())); - VRButton.AnimationDirection = EVREditorAnimationState::None; - } - } - } - - - if( HandInteractorThatNeedsQuickMenu != nullptr && !QuickMenuUI->IsUIVisible() ) - { - UVREditorMotionControllerInteractor* MotionControllerHandInteractorThatNeedsQuickMenu = Cast( HandInteractorThatNeedsQuickMenu ); - if ( MotionControllerHandInteractorThatNeedsQuickMenu ) - { - const AVREditorFloatingUI::EDockedTo DockTo = ( MotionControllerHandInteractorThatNeedsQuickMenu->GetControllerSide() == EControllerHand::Left ) ? AVREditorFloatingUI::EDockedTo::LeftArm : AVREditorFloatingUI::EDockedTo::RightArm; - QuickMenuUI->SetDockedTo( DockTo ); - QuickMenuUI->ShowUI( true ); - MotionControllerHandInteractorThatNeedsQuickMenu->SetHasUIOnForearm( true ); - } - } - } // Iterate through all quick menu and radial menu buttons and animate any that need it for (FVRButton& VRButton : VRButtons) @@ -908,11 +855,12 @@ void UVREditorUISystem::Tick( FEditorViewportClient* ViewportClient, const float } // Tick all of our floating UIs - for( AVREditorFloatingUI* FloatingUIPtr : FloatingUIs ) + for(auto CurrentUI : FloatingUIs) { - if( FloatingUIPtr != nullptr ) + AVREditorFloatingUI* UIPanel = CurrentUI.Value; + if (UIPanel != nullptr) { - FloatingUIPtr->TickManually( DeltaTime ); + UIPanel->TickManually( DeltaTime ); } } QuickRadialMenu->TickManually(DeltaTime); @@ -928,24 +876,20 @@ void UVREditorUISystem::CreateUIs() const FIntPoint DefaultResolution( VREd::DefaultEditorUIResolutionX->GetInt(), VREd::DefaultEditorUIResolutionY->GetInt() ); { - const FIntPoint Resolution(VREd::QuickMenuUIResolutionX->GetInt(), VREd::QuickMenuUIResolutionY->GetInt()); const bool bWithSceneComponent = false; + // @todo vreditor: Tweak { - QuickMenuUI = GetOwner().SpawnTransientSceneActor(TEXT("QuickMenu"), bWithSceneComponent); - QuickMenuUI->SetSlateWidget(*this, BuildQuickMenuWidget(), Resolution, 40.0f, AVREditorFloatingUI::EDockedTo::Nothing); - QuickMenuUI->ShowUI(false); - QuickMenuUI->SetRelativeOffset(FVector(-20.0f, 0.0f, 5.0f)); - QuickMenuUI->GetWidgetComponent()->SetBackgroundColor(FLinearColor(0.15f, 0.15f, 0.15f)); - UStaticMesh* WindowMesh = nullptr; - { - WindowMesh = LoadObject(nullptr, TEXT("/Engine/VREditor/UI/SM_ContentWindow_01")); - check(WindowMesh != nullptr); - } - QuickMenuUI->GetMeshComponent()->SetStaticMesh(WindowMesh); - FloatingUIs.Add(QuickMenuUI); - + InfoDisplayPanel = GetOwner().SpawnTransientSceneActor(TEXT("QuickMenu"), bWithSceneComponent); + const FIntPoint Resolution(512, 64); + InfoDisplayPanel->SetSlateWidget(*this, InfoDisplayPanelID, SNullWidget::NullWidget, Resolution, 20.0f, AVREditorBaseActor::EDockedTo::Nothing); + InfoDisplayPanel->ShowUI(false); + FVector RelativeOffset = VRMode->GetHMDDeviceType() == EHMDDeviceType::Type::DT_SteamVR ? FVector(5.0f, 0.0f, 0.0f) : FVector(5.0f, 0.0f, 10.0f); + InfoDisplayPanel->SetRelativeOffset(RelativeOffset); + InfoDisplayPanel->SetWindowMesh(VRMode->GetAssetContainer().WindowMesh); + FloatingUIs.Add(InfoDisplayPanelID, InfoDisplayPanel); } + // Create the radial UI { QuickRadialMenu = GetOwner().SpawnTransientSceneActor(TEXT("QuickRadialmenu"), bWithSceneComponent); @@ -1009,11 +953,9 @@ void UVREditorUISystem::CreateUIs() const bool bWithSceneComponent = false; AVREditorFloatingUI* ContentBrowserUI = GetOwner().SpawnTransientSceneActor(TEXT( "ContentBrowserUI" ), bWithSceneComponent); - ContentBrowserUI->SetSlateWidget( *this, WidgetToDraw, Resolution, VREd::ContentBrowserUISize->GetFloat(), AVREditorFloatingUI::EDockedTo::Nothing ); + ContentBrowserUI->SetSlateWidget( *this, ContentBrowserPanelID, WidgetToDraw, Resolution, VREd::ContentBrowserUISize->GetFloat(), AVREditorFloatingUI::EDockedTo::Nothing ); ContentBrowserUI->ShowUI( false ); - FloatingUIs.Add( ContentBrowserUI ); - - EditorUIPanels[ (int32)EEditorUIPanel::ContentBrowser ] = ContentBrowserUI; + FloatingUIs.Add(ContentBrowserPanelID, ContentBrowserUI); } { @@ -1037,11 +979,9 @@ void UVREditorUISystem::CreateUIs() const bool bWithSceneComponent = false; AVREditorFloatingUI* WorldOutlinerUI = GetOwner().SpawnTransientSceneActor(TEXT("WorldOutlinerUI"), bWithSceneComponent); - WorldOutlinerUI->SetSlateWidget( *this, WidgetToDraw, DefaultResolution, VREd::EditorUISize->GetFloat(), AVREditorFloatingUI::EDockedTo::Nothing ); + WorldOutlinerUI->SetSlateWidget( *this, WorldOutlinerPanelID, WidgetToDraw, DefaultResolution, VREd::EditorUISize->GetFloat(), AVREditorFloatingUI::EDockedTo::Nothing ); WorldOutlinerUI->ShowUI( false ); - FloatingUIs.Add( WorldOutlinerUI ); - - EditorUIPanels[ (int32)EEditorUIPanel::WorldOutliner ] = WorldOutlinerUI; + FloatingUIs.Add(WorldOutlinerPanelID, WorldOutlinerUI); } { @@ -1060,11 +1000,9 @@ void UVREditorUISystem::CreateUIs() const bool bWithSceneComponent = false; AVREditorFloatingUI* ActorDetailsUI = GetOwner().SpawnTransientSceneActor(TEXT("ActorDetailsUI"), bWithSceneComponent); - ActorDetailsUI->SetSlateWidget( *this, WidgetToDraw, DefaultResolution, VREd::EditorUISize->GetFloat(), AVREditorFloatingUI::EDockedTo::Nothing ); + ActorDetailsUI->SetSlateWidget( *this, DetailsPanelID, WidgetToDraw, DefaultResolution, VREd::EditorUISize->GetFloat(), AVREditorFloatingUI::EDockedTo::Nothing ); ActorDetailsUI->ShowUI( false ); - FloatingUIs.Add( ActorDetailsUI ); - - EditorUIPanels[ (int32)EEditorUIPanel::ActorDetails ] = ActorDetailsUI; + FloatingUIs.Add(DetailsPanelID, ActorDetailsUI); } { @@ -1086,14 +1024,12 @@ void UVREditorUISystem::CreateUIs() const bool bWithSceneComponent = false; AVREditorFloatingUI* ModesUI = GetOwner().SpawnTransientSceneActor(TEXT("ModesUI"), bWithSceneComponent); - ModesUI->SetSlateWidget( *this, WidgetToDraw, DefaultResolution, VREd::EditorUISize->GetFloat(), AVREditorFloatingUI::EDockedTo::Nothing ); + ModesUI->SetSlateWidget( *this, ModesPanelID, WidgetToDraw, DefaultResolution, VREd::EditorUISize->GetFloat(), AVREditorFloatingUI::EDockedTo::Nothing ); ModesUI->ShowUI( false ); - FloatingUIs.Add( ModesUI ); + FloatingUIs.Add(ModesPanelID, ModesUI); // @todo vreditor placement: This is required to force the modes UI to refresh -- otherwise it looks empty GLevelEditorModeTools().ActivateDefaultMode(); - - EditorUIPanels[ (int32)EEditorUIPanel::Modes ] = ModesUI; } { @@ -1101,15 +1037,13 @@ void UVREditorUISystem::CreateUIs() const bool bWithSceneComponent = false; AVREditorDockableWindow* TabManagerUI = GetOwner().SpawnTransientSceneActor(TEXT("AssetEditor"), bWithSceneComponent); - TabManagerUI->SetSlateWidget( *this, SNullWidget::NullWidget, Resolution, VREd::EditorUISize->GetFloat(), AVREditorFloatingUI::EDockedTo::Nothing ); + TabManagerUI->SetSlateWidget( *this, TabManagerPanelID, SNullWidget::NullWidget, Resolution, VREd::EditorUISize->GetFloat(), AVREditorFloatingUI::EDockedTo::Nothing ); TabManagerUI->ShowUI( false ); // @todo vreditor: Could use "Hovering" instead for better performance with many UIs, but needs to be manually refreshed in some cases TabManagerUI->GetWidgetComponent()->SetDrawingPolicy( EVREditorWidgetDrawingPolicy::Always ); - FloatingUIs.Add( TabManagerUI ); - - EditorUIPanels[ (int32)EEditorUIPanel::AssetEditor ] = TabManagerUI; + FloatingUIs.Add(TabManagerPanelID, TabManagerUI); TSharedPtr TabManagerWindow = TabManagerUI->GetWidgetComponent()->GetSlateWindow(); TSharedRef TabManagerWindowRef = TabManagerWindow.ToSharedRef(); @@ -1149,11 +1083,9 @@ void UVREditorUISystem::CreateUIs() const bool bWithSceneComponent = false; AVREditorFloatingUI* WorldSettingsUI = GetOwner().SpawnTransientSceneActor(TEXT("WorldSettingsUI"), bWithSceneComponent); - WorldSettingsUI->SetSlateWidget( *this, WidgetToDraw, DefaultResolution, VREd::EditorUISize->GetFloat(), AVREditorFloatingUI::EDockedTo::Nothing ); + WorldSettingsUI->SetSlateWidget( *this, WorldSettingsPanelID, WidgetToDraw, DefaultResolution, VREd::EditorUISize->GetFloat(), AVREditorFloatingUI::EDockedTo::Nothing ); WorldSettingsUI->ShowUI( false ); - FloatingUIs.Add( WorldSettingsUI ); - - EditorUIPanels[ (int32)EEditorUIPanel::WorldSettings ] = WorldSettingsUI; + FloatingUIs.Add(WorldSettingsPanelID, WorldSettingsUI); } { @@ -1170,11 +1102,28 @@ void UVREditorUISystem::CreateUIs() const bool bWithSceneComponent = false; AVREditorFloatingUI* SequencerUI = GetOwner().SpawnTransientSceneActor(TEXT("SequencerUI"), bWithSceneComponent); - SequencerUI->SetSlateWidget(*this, WidgetToDraw, FIntPoint(VREd::SequencerUIResolutionX->GetFloat(), VREd::SequencerUIResolutionY->GetFloat()), VREd::ContentBrowserUISize->GetFloat(), AVREditorFloatingUI::EDockedTo::Nothing); + SequencerUI->SetSlateWidget(*this, SequencerPanelID, WidgetToDraw, FIntPoint(VREd::SequencerUIResolutionX->GetFloat(), VREd::SequencerUIResolutionY->GetFloat()), VREd::ContentBrowserUISize->GetFloat(), AVREditorFloatingUI::EDockedTo::Nothing); SequencerUI->ShowUI(false); - FloatingUIs.Add(SequencerUI); + FloatingUIs.Add(SequencerPanelID, SequencerUI); + } - EditorUIPanels[(int32)EEditorUIPanel::SequencerUI] = SequencerUI; + { + const FName TabIdentifier = NAME_None; // No tab for us! + const TSharedRef ActorPreviewWidget = SNullWidget::NullWidget; + + TSharedRef WidgetToDraw = + SNew(SDPIScaler) + .DPIScale(VREd::EditorUIScale->GetFloat()) + [ + ActorPreviewWidget + ] + ; + + const bool bWithSceneComponent = false; + AVREditorFloatingUI* ActorPreviewUI = GetOwner().SpawnTransientSceneActor(TEXT("ActorPreviewUI"), bWithSceneComponent); + ActorPreviewUI->SetSlateWidget(*this, ActorPreviewUIID, WidgetToDraw, FIntPoint(VREd::ContentBrowserUIResolutionX->GetFloat(), VREd::ContentBrowserUIResolutionY->GetFloat()), VREd::ContentBrowserUISize->GetFloat(), AVREditorFloatingUI::EDockedTo::Nothing); + ActorPreviewUI->ShowUI(false); + FloatingUIs.Add(ActorPreviewUIID, ActorPreviewUI); } } } @@ -1197,9 +1146,9 @@ void UVREditorUISystem::OnAssetEditorOpened(UObject* Asset) } } -bool UVREditorUISystem::IsShowingEditorUIPanel( const EEditorUIPanel EditorUIPanel ) const +bool UVREditorUISystem::IsShowingEditorUIPanel(const VREditorPanelID& InPanelID) const { - AVREditorFloatingUI* Panel = EditorUIPanels[ (int32)EditorUIPanel ]; + AVREditorFloatingUI* Panel = GetPanel(InPanelID); if( Panel != nullptr ) { return Panel->IsUIVisible(); @@ -1208,29 +1157,29 @@ bool UVREditorUISystem::IsShowingEditorUIPanel( const EEditorUIPanel EditorUIPan return false; } - void UVREditorUISystem::ShowEditorUIPanel(const UWidgetComponent* WidgetComponent, UVREditorInteractor* Interactor, const bool bShouldShow, const bool bSpawnInFront, const bool bDragFromOpen, const bool bPlaySound) { - AVREditorFloatingUI* Panel = nullptr; - for (AVREditorFloatingUI* CurrentPanel : EditorUIPanels) + AVREditorFloatingUI* ResultPanel = nullptr; + for (auto& CurrentUI : FloatingUIs) { - if (CurrentPanel && CurrentPanel->GetWidgetComponent() == WidgetComponent) + AVREditorFloatingUI* Panel = CurrentUI.Value; + if (Panel != nullptr && Panel->GetWidgetComponent() == WidgetComponent) { - Panel = CurrentPanel; + ResultPanel = Panel; break; } } - ShowEditorUIPanel(Panel, Interactor, bShouldShow, bSpawnInFront, bDragFromOpen, bPlaySound); + ShowEditorUIPanel(ResultPanel, Interactor, bShouldShow, bSpawnInFront, bDragFromOpen, bPlaySound); } - -void UVREditorUISystem::ShowEditorUIPanel(const EEditorUIPanel EditorUIPanel, UVREditorInteractor* Interactor, const bool bShouldShow, const bool bSpawnInFront, const bool bDragFromOpen, const bool bPlaySound) +void UVREditorUISystem::ShowEditorUIPanel(const VREditorPanelID& InPanelID, UVREditorInteractor* Interactor, const bool bShouldShow, const bool bSpawnInFront, const bool bDragFromOpen, const bool bPlaySound) { - AVREditorFloatingUI* Panel = EditorUIPanels[(int32)EditorUIPanel]; + AVREditorFloatingUI* Panel = GetPanel(InPanelID); ShowEditorUIPanel(Panel, Interactor, bShouldShow, bSpawnInFront, bDragFromOpen, bPlaySound); } + void UVREditorUISystem::ShowEditorUIPanel(AVREditorFloatingUI* Panel, UVREditorInteractor* Interactor, const bool bShouldShow, const bool bSpawnInFront, const bool bDragFromOpen, const bool bPlaySound) { if( Panel != nullptr ) @@ -1296,15 +1245,16 @@ void UVREditorUISystem::ShowEditorUIPanel(AVREditorFloatingUI* Panel, UVREditorI if (!bShouldShow) { // If we are closing the sequencer panel, then also null out the sequencer widget and close the Sequencer instance - if (Panel == EditorUIPanels[(int32)EEditorUIPanel::SequencerUI]) + const VREditorPanelID& PanelID = Panel->GetID(); + if (PanelID == SequencerPanelID) { if (GetOwner().GetCurrentSequencer() != nullptr) { - Panel->SetSlateWidget(*this, SNullWidget::NullWidget, FIntPoint(VREd::SequencerUIResolutionX->GetFloat(), VREd::SequencerUIResolutionY->GetFloat()), VREd::EditorUISize->GetFloat(), AVREditorFloatingUI::EDockedTo::Nothing); + Panel->SetSlateWidget(*this, SequencerPanelID, SNullWidget::NullWidget, FIntPoint(VREd::SequencerUIResolutionX->GetFloat(), VREd::SequencerUIResolutionY->GetFloat()), VREd::EditorUISize->GetFloat(), AVREditorFloatingUI::EDockedTo::Nothing); FVREditorActionCallbacks::CloseSequencer(GetOwner().GetCurrentSequencer()->GetRootMovieSceneSequence()); } } - else if(Panel == EditorUIPanels[ (int32)EEditorUIPanel::Modes ] ) + else if(PanelID == ModesPanelID) { // Quit active mode and go back to Placement Mode when closing the Modes panel. GLevelEditorModeTools().DeactivateAllModes(); @@ -1503,8 +1453,9 @@ void UVREditorUISystem::TogglePanelsVisibility() bool bAnyPanelsVisible = false; // Check if there is any panel visible and if any is docked to a hand - for (AVREditorFloatingUI* Panel : EditorUIPanels) + for (auto& CurrentUI : FloatingUIs) { + AVREditorFloatingUI* Panel = CurrentUI.Value; if (Panel && Panel->IsUIVisible()) { bAnyPanelsVisible = true; @@ -1515,8 +1466,9 @@ void UVREditorUISystem::TogglePanelsVisibility() // Hide if there is any UI visible const bool bShowUI = !bAnyPanelsVisible; - for (AVREditorFloatingUI* Panel : EditorUIPanels) + for (auto& CurrentUI : FloatingUIs) { + AVREditorFloatingUI* Panel = CurrentUI.Value; if (Panel != nullptr && Panel->IsUIVisible() != bShowUI) { Panel->ShowUI(bShowUI); @@ -1572,20 +1524,21 @@ void UVREditorUISystem::ShowAssetEditor() // A tab was opened, so make sure the "Asset" UI is visible. That's where the user can interact // with the newly-opened tab - if ( !IsShowingEditorUIPanel(EEditorUIPanel::AssetEditor) ) + AVREditorFloatingUI* AssetEditorPanel = GetPanel(AssetEditorPanelID); + if (AssetEditorPanel != nullptr && !AssetEditorPanel->IsUIVisible()) { const bool bShouldShow = true; const bool bSpawnInFront = true; - ShowEditorUIPanel( EEditorUIPanel::AssetEditor, UIInteractor, bShouldShow, bSpawnInFront ); + ShowEditorUIPanel(AssetEditorPanel, UIInteractor, bShouldShow, bSpawnInFront); // Play haptic effect so user knows to look at their hand that now has UI on it! UIInteractor->PlayHapticEffect( VREd::UIAssetEditorSummonedOnHandHapticFeedbackStrength->GetFloat() ); } } -void UVREditorUISystem::TogglePanelVisibility( const EEditorUIPanel EditorUIPanel ) +void UVREditorUISystem::TogglePanelVisibility(const VREditorPanelID& InPanelID) { - AVREditorFloatingUI* Panel = EditorUIPanels[(int32)EditorUIPanel]; + AVREditorFloatingUI* Panel = GetPanel(InPanelID); if (Panel != nullptr) { const bool bIsShowing = Panel->IsUIVisible(); @@ -1626,12 +1579,11 @@ void UVREditorUISystem::CreateVRColorPicker(const TSharedRef& Colo { const bool bWithSceneComponent = false; ColorPickerUI = GetOwner().SpawnTransientSceneActor(TEXT("ColorPickerUI"), bWithSceneComponent); - FloatingUIs.Add( ColorPickerUI ); - EditorUIPanels[ (int32)EEditorUIPanel::ColorPicker ] = ColorPickerUI; + FloatingUIs.Add(ColorPickerPanelID, ColorPickerUI); bJustSpawned = true; } - ColorPickerUI->SetSlateWidget( *this, WidgetToDraw, DefaultResolution, VREd::EditorUISize->GetFloat(), AVREditorFloatingUI::EDockedTo::Room ); + ColorPickerUI->SetSlateWidget( *this, ColorPickerPanelID, WidgetToDraw, DefaultResolution, VREd::EditorUISize->GetFloat(), AVREditorFloatingUI::EDockedTo::Room ); // Always spawn based on the location of the menu you are hovering over. To get this information, find the hand hovering over the UI. UVREditorInteractor* VREditorInteractor = GetOwner().GetHandInteractor(EControllerHand::Left); @@ -1694,7 +1646,7 @@ void UVREditorUISystem::DestroyVRColorPicker() const bool bSpawnInFront = false; const bool bDragFromOpen = false; const bool bPlaySound = true; - ShowEditorUIPanel(EEditorUIPanel::ColorPicker, VREditorInteractor, bShouldShow, bSpawnInFront, bDragFromOpen, bPlaySound); + ShowEditorUIPanel(ColorPickerPanelID, VREditorInteractor, bShouldShow, bSpawnInFront, bDragFromOpen, bPlaySound); } void UVREditorUISystem::MakeUniformGridMenu(const TSharedRef& MultiBox, const TSharedRef& MultiBoxWidget, int32 Columns) @@ -1883,444 +1835,6 @@ void UVREditorUISystem::MakeRadialBoxMenu(const TSharedRef& MultiBox, } } - -TSharedRef UVREditorUISystem::BuildQuickMenuWidget() -{ - FVREditorActionCallbacks::UpdateGizmoCoordinateSystemText(VRMode); - FVREditorActionCallbacks::UpdateGizmoModeText(VRMode); - - FMultiBox::FOnMakeMultiBoxBuilderOverride VREditorMenuBuilderOverride; - - VREditorMenuBuilderOverride.BindUObject(this, &UVREditorUISystem::MakeUniformGridMenu, 4); - const TSharedRef MenuExtender = MakeShareable(new FExtender()); - TSharedPtr CommandList = MakeShareable(new FUICommandList()); - FMenuBuilder GizmoMenuBuilder (false, CommandList, MenuExtender); - - - TAttribute DynamicGizmoModeLabel; - DynamicGizmoModeLabel.BindStatic(&FVREditorActionCallbacks::GetGizmoModeText); - GizmoMenuBuilder.AddMenuEntry( - DynamicGizmoModeLabel, - LOCTEXT("GizmoModeTooltip", "Toggle Gizmo Mode"), - FSlateIcon(FEditorStyle::GetStyleSetName(), "EditorViewport.TranslateRotateMode"), - FUIAction - ( - FExecuteAction::CreateStatic(&FVREditorActionCallbacks::OnGizmoModeButtonClicked, VRMode), - FCanExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::DefaultCanExecuteAction) - ), - NAME_None, - EUserInterfaceActionType::CollapsedButton - ); - TAttribute DynamicGizmoCoordinateSystemLabel; - DynamicGizmoCoordinateSystemLabel.BindStatic(&FVREditorActionCallbacks::GetGizmoCoordinateSystemText); - GizmoMenuBuilder.AddMenuEntry( - DynamicGizmoCoordinateSystemLabel, - LOCTEXT("GizmoCoordinateTooltip", "Toggle Gizmo Coordinates"), - FSlateIcon(FEditorStyle::GetStyleSetName(), "EditorViewport.RelativeCoordinateSystem_World"), - FUIAction - ( - FExecuteAction::CreateStatic(&FVREditorActionCallbacks::OnGizmoCoordinateSystemButtonClicked, VRMode), - FCanExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::DefaultCanExecuteAction) - ), - NAME_None, - EUserInterfaceActionType::CollapsedButton - ); - - GizmoMenuBuilder.AddMenuEntry( - LOCTEXT("AlignToActors", "Align To Actors"), - LOCTEXT("AlignToActorsTooltip", "Align to Actors as you transform an object"), - FSlateIcon(FVREditorStyle::GetStyleSetName(), "VREditorStyle.AlignActors"), - FUIAction - ( - FExecuteAction::CreateStatic(&FVREditorActionCallbacks::ToggleAligningToActors, VRMode), - FCanExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::DefaultCanExecuteAction), - FGetActionCheckState::CreateStatic(&FVREditorActionCallbacks::AreAligningToActors, VRMode) - ), - NAME_None, - EUserInterfaceActionType::ToggleButton - ); - - TAttribute DynamicAlignSelectionLabel; - DynamicAlignSelectionLabel.BindStatic(&FVREditorActionCallbacks::GetSelectingCandidateActorsText); - GizmoMenuBuilder.AddMenuEntry( - DynamicAlignSelectionLabel, - FText(), - FSlateIcon(FEditorStyle::GetStyleSetName(), "DeviceDetails.Share"), - FUIAction - ( - FExecuteAction::CreateStatic(&FVREditorActionCallbacks::ToggleSelectingCandidateActors, VRMode), - FCanExecuteAction::CreateStatic(&FVREditorActionCallbacks::CanSelectCandidateActors, VRMode) - ), - NAME_None, - EUserInterfaceActionType::CollapsedButton - ); - - TSharedRef GizmoMenuWidget = GizmoMenuBuilder.MakeWidget(&VREditorMenuBuilderOverride); - - VREditorMenuBuilderOverride.BindUObject(this, &UVREditorUISystem::MakeUniformGridMenu, 6); - CommandList = MakeShareable(new FUICommandList()); - FMenuBuilder SnapMenuBuilder(false, CommandList, MenuExtender); - - // Snap menu - - SnapMenuBuilder.AddMenuEntry( - FText(), - LOCTEXT("ToggleTranslationSnapTooltip", "Toggle Translation Snap"), - FSlateIcon(FEditorStyle::GetStyleSetName(), "EditorViewport.TranslateMode"), - FUIAction - ( - FExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::LocationGridSnap_Clicked), - FCanExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::DefaultCanExecuteAction), - FGetActionCheckState::CreateStatic(&FVREditorActionCallbacks::GetTranslationSnapState) - ), - NAME_None, - EUserInterfaceActionType::ToggleButton - ); - TAttribute DynamicTranslationSizeLabel; - DynamicTranslationSizeLabel.BindStatic(&FVREditorActionCallbacks::GetTranslationSnapSizeText); - SnapMenuBuilder.AddMenuEntry( - DynamicTranslationSizeLabel, - LOCTEXT("ToggleTranslationSnapSizeTooltip", "Toggle Translation Snap Size"), - FSlateIcon(FEditorStyle::GetStyleSetName(), "EditorViewport.LocationGridSnap"), - FUIAction - ( - FExecuteAction::CreateStatic(&FVREditorActionCallbacks::OnTranslationSnapSizeButtonClicked), - FCanExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::DefaultCanExecuteAction) - ), - NAME_None, - EUserInterfaceActionType::CollapsedButton - ); - SnapMenuBuilder.AddMenuEntry( - FText(), - LOCTEXT("ToggleRotationSnapTooltip", "Toggle Rotation Snap"), - FSlateIcon(FEditorStyle::GetStyleSetName(), "EditorViewport.RotateMode"), - FUIAction - ( - FExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::RotationGridSnap_Clicked), - FCanExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::DefaultCanExecuteAction), - FGetActionCheckState::CreateStatic(&FVREditorActionCallbacks::GetRotationSnapState) - ), - NAME_None, - EUserInterfaceActionType::ToggleButton - ); - TAttribute DynamicRotationSizeLabel; - DynamicRotationSizeLabel.BindStatic(&FVREditorActionCallbacks::GetRotationSnapSizeText); - SnapMenuBuilder.AddMenuEntry( - DynamicRotationSizeLabel, - LOCTEXT("ToggleRotationSnapSizeTooltip", "Toggle Rotation Snap Size"), - FSlateIcon(FEditorStyle::GetStyleSetName(), "EditorViewport.RotationGridSnap"), - FUIAction - ( - FExecuteAction::CreateStatic(&FVREditorActionCallbacks::OnRotationSnapSizeButtonClicked), - FCanExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::DefaultCanExecuteAction) - ), - NAME_None, - EUserInterfaceActionType::CollapsedButton - ); - SnapMenuBuilder.AddMenuEntry( - FText(), - LOCTEXT("ToggleScaleSnapTooltip", "Toggle Scale Snap"), - FSlateIcon(FEditorStyle::GetStyleSetName(), "EditorViewport.ScaleMode"), - FUIAction - ( - FExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::ScaleGridSnap_Clicked), - FCanExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::DefaultCanExecuteAction), - FGetActionCheckState::CreateStatic(&FVREditorActionCallbacks::GetScaleSnapState) - ), - NAME_None, - EUserInterfaceActionType::ToggleButton - ); - TAttribute DynamicScaleSizeLabel; - DynamicScaleSizeLabel.BindStatic(&FVREditorActionCallbacks::GetScaleSnapSizeText); - SnapMenuBuilder.AddMenuEntry( - DynamicScaleSizeLabel, - LOCTEXT("ToggleScaleSnapSizeTooltip", "Toggle Scale Snap Size"), - FSlateIcon(FEditorStyle::GetStyleSetName(), "EditorViewport.ScaleGridSnap"), - FUIAction - ( - FExecuteAction::CreateStatic(&FVREditorActionCallbacks::OnScaleSnapSizeButtonClicked), - FCanExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::DefaultCanExecuteAction) - ), - NAME_None, - EUserInterfaceActionType::CollapsedButton - ); - - - TSharedRef SnapMenuWidget = SnapMenuBuilder.MakeWidget(&VREditorMenuBuilderOverride); - - // Next Menu section: Interface - CommandList = MakeShareable(new FUICommandList()); - FMenuBuilder InterfaceMenuBuilder(false, CommandList, MenuExtender); - VREditorMenuBuilderOverride.BindUObject(this, &UVREditorUISystem::MakeUniformGridMenu, 4); - InterfaceMenuBuilder.AddMenuEntry( - LOCTEXT("ActorDetails", "Details"), - LOCTEXT("ActorDetailsTooltip", "Details"), - FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.Tabs.Details"), - FUIAction - ( - FExecuteAction::CreateStatic(&FVREditorActionCallbacks::OnUIToggleButtonClicked, VRMode, UVREditorUISystem::EEditorUIPanel::ActorDetails), - FCanExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::DefaultCanExecuteAction), - FGetActionCheckState::CreateStatic(&FVREditorActionCallbacks::GetUIToggledState, VRMode, UVREditorUISystem::EEditorUIPanel::ActorDetails) - ), - NAME_None, - EUserInterfaceActionType::ToggleButton - ); - InterfaceMenuBuilder.AddMenuEntry( - LOCTEXT("ContentBrowser", "Content Browser"), - LOCTEXT("ContentBrowserTooltip", "Content Browser"), - FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.Tabs.ContentBrowser"), - FUIAction - ( - FExecuteAction::CreateStatic(&FVREditorActionCallbacks::OnUIToggleButtonClicked, VRMode, UVREditorUISystem::EEditorUIPanel::ContentBrowser), - FCanExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::DefaultCanExecuteAction), - FGetActionCheckState::CreateStatic(&FVREditorActionCallbacks::GetUIToggledState, VRMode, UVREditorUISystem::EEditorUIPanel::ContentBrowser) - ), - NAME_None, - EUserInterfaceActionType::ToggleButton - ); - InterfaceMenuBuilder.AddMenuEntry( - LOCTEXT("LegacyModes", "Modes"), - LOCTEXT("ModesTooltip", "Modes"), - FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.Tabs.Modes"), - FUIAction - ( - FExecuteAction::CreateStatic(&FVREditorActionCallbacks::OnUIToggleButtonClicked, VRMode, UVREditorUISystem::EEditorUIPanel::Modes), - FCanExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::DefaultCanExecuteAction), - FGetActionCheckState::CreateStatic(&FVREditorActionCallbacks::GetUIToggledState, VRMode, UVREditorUISystem::EEditorUIPanel::Modes) - ), - NAME_None, - EUserInterfaceActionType::ToggleButton - ); - InterfaceMenuBuilder.AddMenuEntry( - LOCTEXT("WorldOutliner", "World Outliner"), - LOCTEXT("WorldOutlinerTooltip", "World Outliner"), - FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.Tabs.Outliner"), - FUIAction - ( - FExecuteAction::CreateStatic(&FVREditorActionCallbacks::OnUIToggleButtonClicked, VRMode, UVREditorUISystem::EEditorUIPanel::WorldOutliner), - FCanExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::DefaultCanExecuteAction), - FGetActionCheckState::CreateStatic(&FVREditorActionCallbacks::GetUIToggledState, VRMode, UVREditorUISystem::EEditorUIPanel::WorldOutliner) - ), - NAME_None, - EUserInterfaceActionType::ToggleButton - ); - InterfaceMenuBuilder.AddMenuEntry( - LOCTEXT("WorldSettings", "World Settings"), - LOCTEXT("WorldSettingsTooltip", "World Settings"), - FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.WorldProperties.Tab"), - FUIAction - ( - FExecuteAction::CreateStatic(&FVREditorActionCallbacks::OnUIToggleButtonClicked, VRMode, UVREditorUISystem::EEditorUIPanel::WorldSettings), - FCanExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::DefaultCanExecuteAction), - FGetActionCheckState::CreateStatic(&FVREditorActionCallbacks::GetUIToggledState, VRMode, UVREditorUISystem::EEditorUIPanel::WorldSettings) - ), - NAME_None, - EUserInterfaceActionType::ToggleButton - ); - InterfaceMenuBuilder.AddMenuEntry( - LOCTEXT("CreateNewSequence", "Create Sequence"), - LOCTEXT("CreateNewSequenceTooltip", "Create a new Level Sequence and open it"), - FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.EditMatinee"), - FUIAction - ( - FExecuteAction::CreateStatic(&FVREditorActionCallbacks::CreateNewSequence, VRMode), - FCanExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::DefaultCanExecuteAction) - ), - NAME_None, - EUserInterfaceActionType::ToggleButton - ); - TSharedRef InterfaceMenuWidget = InterfaceMenuBuilder.MakeWidget(&VREditorMenuBuilderOverride); - - // Next Menu section: Extras - CommandList = MakeShareable(new FUICommandList()); - FMenuBuilder ExtrasMenuBuilder(false, CommandList, MenuExtender); - VREditorMenuBuilderOverride.BindUObject(this, &UVREditorUISystem::MakeUniformGridMenu, 4); - - TAttribute DynamicSimulateLabel; - DynamicSimulateLabel.BindStatic( &FVREditorActionCallbacks::GetSimulateText ); - - ExtrasMenuBuilder.AddMenuEntry( - DynamicSimulateLabel, - LOCTEXT("SimulateTooltip", "Simulate"), - FSlateIcon(FEditorStyle::GetStyleSetName(), "PlayWorld.Simulate"), - FUIAction - ( - FExecuteAction::CreateStatic(&FVREditorActionCallbacks::OnSimulateButtonClicked, VRMode), - FCanExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::DefaultCanExecuteAction) - ), - NAME_None, - EUserInterfaceActionType::CollapsedButton - ); - - - ExtrasMenuBuilder.AddMenuEntry( - LOCTEXT("KeepSimulationChanges", "Save Simulation"), - LOCTEXT("KeepSimulationChangesTooltip", "Keep Simulation Changes"), - FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.Save"), - FUIAction - ( - FExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::OnKeepSimulationChanges), - FCanExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::CanExecuteKeepSimulationChanges) - ), - NAME_None, - EUserInterfaceActionType::CollapsedButton - ); - - - ExtrasMenuBuilder.AddMenuEntry( - LOCTEXT("PauseSimulationLegacy", "Pause Simulation"), - LOCTEXT("PauseSimulationTooltip", "Pause Simulation"), - FSlateIcon(FEditorStyle::GetStyleSetName(), "PlayWorld.Simulate"), - FUIAction - ( - FExecuteAction::CreateStatic(&FPlayWorldCommandCallbacks::PausePlaySession_Clicked), - FCanExecuteAction::CreateStatic(&FPlayWorldCommandCallbacks::HasPlayWorldAndRunning) - ), - NAME_None, - EUserInterfaceActionType::CollapsedButton - ); - - ExtrasMenuBuilder.AddMenuEntry( - LOCTEXT("ResumeSimulationLegacy", "Resume Simulation"), - LOCTEXT("ResumeSimulationTooltip", "Resume Simulation"), - FSlateIcon(FEditorStyle::GetStyleSetName(), "PlayWorld.Simulate"), - FUIAction - ( - FExecuteAction::CreateStatic(&FPlayWorldCommandCallbacks::ResumePlaySession_Clicked), - FCanExecuteAction::CreateStatic(&FPlayWorldCommandCallbacks::HasPlayWorldAndPaused) - ), - NAME_None, - EUserInterfaceActionType::CollapsedButton - ); - - ExtrasMenuBuilder.AddMenuEntry( - LOCTEXT("PlayInEditor", "Play"), - LOCTEXT("PlayTooltip", "Play"), - FSlateIcon(FEditorStyle::GetStyleSetName(), "PlayWorld.PlayInVR"), - FUIAction - ( - FExecuteAction::CreateStatic(&FVREditorActionCallbacks::OnPlayButtonClicked, VRMode), - FCanExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::DefaultCanExecuteAction) - ), - NAME_None, - EUserInterfaceActionType::CollapsedButton - ); - - ExtrasMenuBuilder.AddMenuEntry( - LOCTEXT("Screenshot", "Screenshot"), - LOCTEXT("ScreenshotTooltip", "Screenshot"), - FSlateIcon(FEditorStyle::GetStyleSetName(), "HighresScreenshot.Capture"), - FUIAction - ( - FExecuteAction::CreateStatic(&FVREditorActionCallbacks::OnScreenshotButtonClicked, VRMode), - FCanExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::DefaultCanExecuteAction) - ), - NAME_None, - EUserInterfaceActionType::CollapsedButton - ); - - ExtrasMenuBuilder.AddMenuEntry( - LOCTEXT("Flashlight", "Flashlight"), - LOCTEXT("FlashlightTooltip", "Flashlight"), - FSlateIcon(FEditorStyle::GetStyleSetName(), "EditorViewport.DetailLightingMode"), - FUIAction - ( - FExecuteAction::CreateStatic(&FVREditorActionCallbacks::OnLightButtonClicked, VRMode), - FCanExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::DefaultCanExecuteAction) - ), - NAME_None, - EUserInterfaceActionType::CollapsedButton - ); - - TSharedRef ExtrasMenuWidget = ExtrasMenuBuilder.MakeWidget(&VREditorMenuBuilderOverride); - const FSlateBrush* NoBorderBrush = FStyleDefaults::GetNoBrush(); - TSharedRef MenuWidget = SNew(SBox) - .VAlign(VAlign_Center) - .HAlign(HAlign_Center) - .MinDesiredWidth(1000.0f) - [ - SNew(SDPIScaler) - .DPIScale(3) - [ - SNew(SVerticalBox) - +SVerticalBox::Slot() - .HAlign(HAlign_Fill) - .VAlign(VAlign_Bottom) - .AutoHeight() - [ - SNew(STextBlock) - .Justification(ETextJustify::Center) - .Text(LOCTEXT("TransformControls", "Transform Controls")) - .TextStyle(FVREditorStyle::Get(),"VREditorStyle.Heading") - ] - + SVerticalBox::Slot() - .HAlign(HAlign_Fill) - .VAlign(VAlign_Top) - .AutoHeight() - .Padding(10.0f) - [ - SNew(SVerticalBox) - + SVerticalBox::Slot() - .HAlign(HAlign_Fill) - .VAlign(VAlign_Bottom) - .AutoHeight() - [ - GizmoMenuWidget - ] - + SVerticalBox::Slot() - .HAlign(HAlign_Fill) - .VAlign(VAlign_Top) - .AutoHeight() - [ - SnapMenuWidget - ] - ] - + SVerticalBox::Slot() - .HAlign(HAlign_Fill) - .VAlign(VAlign_Bottom) - .AutoHeight() - [ - SNew(STextBlock) - .Justification(ETextJustify::Center) - .Text(LOCTEXT("Interface", "Interface")) - .TextStyle(FVREditorStyle::Get(), "VREditorStyle.Heading") - ] - + SVerticalBox::Slot() - .HAlign(HAlign_Fill) - .VAlign(VAlign_Top) - .AutoHeight() - .Padding(10.0f) - [ - InterfaceMenuWidget - ] - + SVerticalBox::Slot() - .HAlign(HAlign_Fill) - .VAlign(VAlign_Bottom) - .AutoHeight() - [ - SNew(STextBlock) - .Justification(ETextJustify::Center) - .Text(LOCTEXT("VRTools", "Tools")) - .TextStyle(FVREditorStyle::Get(), "VREditorStyle.Heading") - ] - + SVerticalBox::Slot() - .HAlign(HAlign_Fill) - .VAlign(VAlign_Top) - .AutoHeight() - .Padding(10.0f) - [ - ExtrasMenuWidget - ] - ] - ] - ; - - - return MenuWidget; -} - - - void UVREditorUISystem::BuildRadialMenuWidget() { @@ -2584,6 +2098,12 @@ UVREditorMotionControllerInteractor* UVREditorUISystem::GetUIInteractor() return UIInteractor; } +AVREditorFloatingUI* UVREditorUISystem::GetPanel(const VREditorPanelID& InPanelID) const +{ + AVREditorFloatingUI *const * FoundPanel = FloatingUIs.Find(InPanelID); + return FoundPanel != nullptr ? *FoundPanel : nullptr; +} + void UVREditorUISystem::SequencerRadialMenuGenerator(FMenuBuilder& MenuBuilder, TSharedPtr CommandList, UVREditorMode* InVRMode, float& RadiusOverride) { RadiusOverride = 1.0f; @@ -2658,20 +2178,18 @@ void UVREditorUISystem::SequencerRadialMenuGenerator(FMenuBuilder& MenuBuilder, void UVREditorUISystem::HandleEditorModeChanged(FEdMode* Mode, bool IsEnabled) { - if (IsEnabled == true) + if (IsEnabled == true && + (Mode->GetID() == FBuiltinEditorModes::EM_Foliage || + Mode->GetID() == FBuiltinEditorModes::EM_Landscape || + Mode->GetID() == FBuiltinEditorModes::EM_MeshPaint)) { - if (Mode->GetID() == FBuiltinEditorModes::EM_Foliage || - Mode->GetID() == FBuiltinEditorModes::EM_Landscape || - Mode->GetID() == FBuiltinEditorModes::EM_MeshPaint) + AVREditorFloatingUI* Panel = GetPanel(ModesPanelID); + if (Panel != nullptr && UIInteractor != nullptr && !Panel->IsUIVisible()) { - AVREditorFloatingUI* Panel = EditorUIPanels[(int32)EEditorUIPanel::Modes]; - if (Panel != nullptr && UIInteractor != nullptr && !IsShowingEditorUIPanel(EEditorUIPanel::Modes)) - { - const bool bShouldShow = true; - const bool bSpawnInFront = true; - const bool bDragFromOpen = ShouldPreviewPanel(); - ShowEditorUIPanel(Panel, UIInteractor, bShouldShow, bSpawnInFront, bDragFromOpen); - } + const bool bShouldShow = true; + const bool bSpawnInFront = true; + const bool bDragFromOpen = ShouldPreviewPanel(); + ShowEditorUIPanel(Panel, UIInteractor, bShouldShow, bSpawnInFront, bDragFromOpen); } } } @@ -2688,11 +2206,12 @@ void UVREditorUISystem::ResetAll() const bool bSpawnInFront = false; const bool bDragFromOpen = false; const bool bPlaySound = false; - for (AVREditorFloatingUI* FloatingUIPtr : FloatingUIs) + for (auto& CurrentUI : FloatingUIs) { - if (FloatingUIPtr != nullptr) + AVREditorFloatingUI* FloatingUI = CurrentUI.Value; + if (FloatingUI != nullptr) { - ShowEditorUIPanel(FloatingUIPtr, UIInteractor, bShouldShow, bSpawnInFront, bDragFromOpen, bPlaySound); + ShowEditorUIPanel(FloatingUI, UIInteractor, bShouldShow, bSpawnInFront, bDragFromOpen, bPlaySound); } } FVREditorActionCallbacks::ChangeEditorModes(FBuiltinEditorModes::EM_Placement); @@ -2772,24 +2291,22 @@ void UVREditorUISystem::SwapRadialMenu() void UVREditorUISystem::UpdateSequencerUI() { - if (EditorUIPanels[(int32)EEditorUIPanel::SequencerUI] != nullptr) + AVREditorFloatingUI* SequencerPanel = GetPanel(SequencerPanelID); + if (SequencerPanel != nullptr) { - AVREditorFloatingUI* SequencerPanel = EditorUIPanels[(int32)EEditorUIPanel::SequencerUI]; - - if(GetOwner().GetCurrentSequencer() != nullptr) + ISequencer* Sequencer = GetOwner().GetCurrentSequencer(); + if(Sequencer != nullptr) { - const TSharedRef SequencerWidget = GetOwner().GetCurrentSequencer()->GetSequencerWidget(); + const TSharedRef SequencerWidget = Sequencer->GetSequencerWidget(); - TSharedRef WidgetToDraw = - SNew(SDPIScaler) + TSharedRef WidgetToDraw = SNew(SDPIScaler) .DPIScale(1.0f) [ SequencerWidget - ] - ; + ]; const bool bWithSceneComponent = false; - SequencerPanel->SetSlateWidget(*this, WidgetToDraw, FIntPoint(VREd::SequencerUIResolutionX->GetFloat(), VREd::SequencerUIResolutionY->GetFloat()), VREd::EditorUISize->GetFloat(), AVREditorFloatingUI::EDockedTo::Nothing); + SequencerPanel->SetSlateWidget(*this, SequencerPanelID, WidgetToDraw, FIntPoint(VREd::SequencerUIResolutionX->GetFloat(), VREd::SequencerUIResolutionY->GetFloat()), VREd::EditorUISize->GetFloat(), AVREditorFloatingUI::EDockedTo::Nothing); if (bSequencerOpenedFromRadialMenu == true) { @@ -2802,7 +2319,7 @@ void UVREditorUISystem::UpdateSequencerUI() else { // Spawn the opened sequencer just in front of the content browser - AVREditorFloatingUI* ContentBrowser = EditorUIPanels[(int32)EEditorUIPanel::ContentBrowser]; + AVREditorFloatingUI* ContentBrowser = GetPanel(ContentBrowserPanelID); if (ContentBrowser && ContentBrowser->IsUIVisible()) { ShowEditorUIPanel(ContentBrowser, UIInteractor, false); @@ -2836,6 +2353,25 @@ void UVREditorUISystem::UpdateSequencerUI() } RadialMenuHandler->SetActionsMenuGenerator(SequencerRadialMenu, LOCTEXT("Sequencer", "Sequencer")); } + + + if (InfoDisplayPanel != nullptr) + { + const TSharedRef SequencerTimer = Sequencer->GetTopTimeSliderWidget().ToSharedRef(); + TSharedRef SequencerTimerToDraw = SNew(SDPIScaler) + .DPIScale(3.0f) + [ + SequencerTimer + ]; + CurrentWidgetOnInfoDisplay = SequencerTimerToDraw; + + InfoDisplayPanel->SetSlateWidget(SequencerTimerToDraw); + + const AVREditorFloatingUI::EDockedTo DockTo = LaserInteractor == nullptr ? AVREditorFloatingUI::EDockedTo::Nothing : + LaserInteractor->GetControllerSide() == EControllerHand::Left ? AVREditorFloatingUI::EDockedTo::LeftHand : AVREditorFloatingUI::EDockedTo::RightHand; + InfoDisplayPanel->SetDockedTo(DockTo); + InfoDisplayPanel->ShowUI(true); + } } else { @@ -2848,28 +2384,73 @@ void UVREditorUISystem::UpdateSequencerUI() RadialMenuHandler->SetActionsMenuGenerator(ExistingActionsMenu, ExistingActionsMenuLabel); } } + + // Hide the info display when finished with sequencer. + if (InfoDisplayPanel != nullptr) + { + const TSharedPtr Widget = InfoDisplayPanel->GetSlateWidget(); + if (Widget.Get() != nullptr && Widget != SNullWidget::NullWidget && Widget == CurrentWidgetOnInfoDisplay) + { + InfoDisplayPanel->ShowUI(false, true, 0.0f, true); + CurrentWidgetOnInfoDisplay.Reset(); + } + } } } } +void UVREditorUISystem::UpdateActorPreviewUI(TSharedRef InWidget) +{ + AVREditorFloatingUI* PreviewPanel = GetPanel(ActorPreviewUIID); + if (PreviewPanel != nullptr) + { + TSharedRef WidgetToDraw = + SNew(SDPIScaler) + .DPIScale(3.0f) + [ + InWidget + ] + ; + TSharedRef TestWidget = FindWidgetOfType(InWidget, FName(TEXT("SButton"))); + if (TestWidget != SNullWidget::NullWidget) + { + TSharedRef Button = StaticCastSharedRef(TestWidget); + Button->SetRenderTransformPivot(FVector2D(0.5f, 0.5f)); + Button->SetRenderTransform(FSlateRenderTransform::FTransform2D(2.0f)); + } + const bool bWithSceneComponent = false; + PreviewPanel->SetSlateWidget(WidgetToDraw); + + const bool bDragFromOpen = false; + const bool bShouldShow = InWidget != SNullWidget::NullWidget; + const bool bSpawnInFront = true; + ShowEditorUIPanel(PreviewPanel, UIInteractor, bShouldShow, bSpawnInFront, bDragFromOpen); + + } +} + void UVREditorUISystem::TransitionWorld(UWorld* NewWorld) { - for (AVREditorFloatingUI* FloatingUI : FloatingUIs) + for (auto& CurrentUI : FloatingUIs) { - UUserWidget* UserWidget = FloatingUI->GetUserWidget(); - if (UserWidget != nullptr) + AVREditorFloatingUI* FloatingUI = CurrentUI.Value; + if (FloatingUI != nullptr) { - // Only reparent the UserWidget if it was parented to a level to begin with. It may have been parented to an actor or - // some other object that doesn't require us to rename anything - ULevel* ExistingWidgetOuterLevel = Cast(UserWidget->GetOuter()); - if (ExistingWidgetOuterLevel != nullptr && ExistingWidgetOuterLevel != NewWorld->PersistentLevel) + UUserWidget* UserWidget = FloatingUI->GetUserWidget(); + if (UserWidget != nullptr) { - UserWidget->Rename(nullptr, NewWorld->PersistentLevel); + // Only reparent the UserWidget if it was parented to a level to begin with. It may have been parented to an actor or + // some other object that doesn't require us to rename anything + ULevel* ExistingWidgetOuterLevel = Cast(UserWidget->GetOuter()); + if (ExistingWidgetOuterLevel != nullptr && ExistingWidgetOuterLevel != NewWorld->PersistentLevel) + { + UserWidget->Rename(nullptr, NewWorld->PersistentLevel); + } } } } - AVREditorFloatingUI* TabManagerUI = EditorUIPanels[(int32)EEditorUIPanel::AssetEditor]; + AVREditorFloatingUI* TabManagerUI = GetPanel(AssetEditorPanelID); if (TabManagerUI != nullptr) { TabManagerUI->GetWidgetComponent()->UpdateWidget(); diff --git a/Engine/Source/Editor/VREditor/UI/VREditorUISystem.h b/Engine/Source/Editor/VREditor/UI/VREditorUISystem.h index fc8c29ae23e4..d0ede02046e9 100644 --- a/Engine/Source/Editor/VREditor/UI/VREditorUISystem.h +++ b/Engine/Source/Editor/VREditor/UI/VREditorUISystem.h @@ -25,7 +25,9 @@ class UVREditorInteractor; class FMenuBuilder; class FUICommandList; class UVREditorWidgetComponent; +class UWidgetComponent; +typedef FName VREditorPanelID; /** Stores the animation playback state of a VR UI element */ enum class EVREditorAnimationState : uint8 @@ -97,22 +99,6 @@ class UVREditorUISystem : public UObject public: - enum class EEditorUIPanel - { - ContentBrowser, - WorldOutliner, - ActorDetails, - Modes, - Tutorial, - AssetEditor, - WorldSettings, - ColorPicker, - SequencerUI, - // ... - - TotalCount, - }; - /** Default constructor */ UVREditorUISystem(); @@ -141,12 +127,12 @@ public: } /** Returns true if the specified editor UI panel is currently visible */ - bool IsShowingEditorUIPanel( const EEditorUIPanel EditorUIPanel ) const; + bool IsShowingEditorUIPanel(const VREditorPanelID& InPanelID) const; /** Sets whether the specified editor UI panel should be visible. Any other UI floating off this hand will be dismissed when showing it. */ - void ShowEditorUIPanel(const class UWidgetComponent* WidgetComponent, UVREditorInteractor* Interactor, const bool bShouldShow, const bool bSpawnInFront = false, const bool bDragFromOpen = false, const bool bPlaySound = true); - void ShowEditorUIPanel(const EEditorUIPanel EditorUIPanel, UVREditorInteractor* Interactor, const bool bShouldShow, const bool bSpawnInFront = false, const bool bDragFromOpen = false, const bool bPlaySound = true); - void ShowEditorUIPanel(class AVREditorFloatingUI* Panel, UVREditorInteractor* Interactor, const bool bShouldShow, const bool bSpawnInFront = false, const bool bDragFromOpen = false, const bool bPlaySound = true); + void ShowEditorUIPanel(const UWidgetComponent* WidgetComponent, UVREditorInteractor* Interactor, const bool bShouldShow, const bool bSpawnInFront = false, const bool bDragFromOpen = false, const bool bPlaySound = true); + void ShowEditorUIPanel(const VREditorPanelID& InPanelID, UVREditorInteractor* Interactor, const bool bShouldShow, const bool bSpawnInFront = false, const bool bDragFromOpen = false, const bool bPlaySound = true); + void ShowEditorUIPanel(AVREditorFloatingUI* Panel, UVREditorInteractor* Interactor, const bool bShouldShow, const bool bSpawnInFront = false, const bool bDragFromOpen = false, const bool bPlaySound = true); /** Returns true if the radial menu is visible on this hand */ bool IsShowingRadialMenu(const UVREditorInteractor* Interactor ) const; @@ -190,7 +176,7 @@ public: float GetMinDockWindowSize() const; /** Toggles the visibility of the panel, if the panel is in room space it will be hidden and docked to nothing */ - void TogglePanelVisibility( const EEditorUIPanel EditorUIPanel ); + void TogglePanelVisibility(const VREditorPanelID& InPanelID); /** Returns the radial widget so other classes, like the interactors, can access its functionality */ class AVREditorRadialFloatingUI* GetRadialMenuFloatingUI() const; @@ -212,6 +198,9 @@ public: /** Function to force an update of the Sequencer UI based on a change */ void UpdateSequencerUI(); + /** Function to force an update of the Actor Preview UI based on a change */ + void UpdateActorPreviewUI(TSharedRef InWidget); + /** Transition the user widgets to a new world */ void TransitionWorld(UWorld* NewWorld); @@ -234,6 +223,23 @@ public: /** Get the interactor that holds the radial menu */ class UVREditorMotionControllerInteractor* GetUIInteractor(); + static const VREditorPanelID ContentBrowserPanelID; + static const VREditorPanelID WorldOutlinerPanelID; + static const VREditorPanelID DetailsPanelID; + static const VREditorPanelID ModesPanelID; + static const VREditorPanelID TutorialPanelID; + static const VREditorPanelID AssetEditorPanelID; + static const VREditorPanelID WorldSettingsPanelID; + static const VREditorPanelID ColorPickerPanelID; + static const VREditorPanelID SequencerPanelID; + static const VREditorPanelID InfoDisplayPanelID; + static const VREditorPanelID RadialMenuPanelID; + static const VREditorPanelID TabManagerPanelID; + static const VREditorPanelID ActorPreviewUIID; + + /** Get UI panel Actor from the passed ID */ + AVREditorFloatingUI* GetPanel(const VREditorPanelID& InPanelID) const; + protected: /** Called to "preview" an input event to get a first chance at it. */ @@ -287,8 +293,6 @@ protected: /** Sets the text wrap size of the text block element nested in a BlockWidget */ TSharedRef SetButtonFormatting(TSharedRef& BlockWidget, float WrapSize); - /** Builds the quick menu Slate widget */ - TSharedRef BuildQuickMenuWidget(); /** Builds the radial menu Slate widget */ void BuildRadialMenuWidget(); /** Builds the numpad Slate widget */ @@ -323,15 +327,17 @@ protected: /** All of the floating UIs. These may or may not be visible (spawned) */ UPROPERTY() - TArray< class AVREditorFloatingUI* > FloatingUIs; + TMap FloatingUIs; /** Our Quick Menu UI */ UPROPERTY() - AVREditorFloatingUI* QuickMenuUI; + class AVREditorFloatingUI* InfoDisplayPanel; - /** Editor UI panels */ - UPROPERTY() - TArray EditorUIPanels; + /** + * The current widget used on the info display. Often we wrap a widget in a widget to configure the settings (e.g. DPI). + * To check the info display widget with other widgets we need that wrapper widget. + */ + TWeakPtr CurrentWidgetOnInfoDisplay; /** The Radial Menu UI */ UPROPERTY() diff --git a/Engine/Source/Editor/VREditor/UI/VRRadialMenuHandler.cpp b/Engine/Source/Editor/VREditor/UI/VRRadialMenuHandler.cpp index 76c7c0c46237..b350e1451dd4 100644 --- a/Engine/Source/Editor/VREditor/UI/VRRadialMenuHandler.cpp +++ b/Engine/Source/Editor/VREditor/UI/VRRadialMenuHandler.cpp @@ -91,10 +91,11 @@ FText UVRRadialMenuHandler::ActionMenuLabel = LOCTEXT("DefaultActions", "Actions"); -UVRRadialMenuHandler::UVRRadialMenuHandler(const FObjectInitializer& Initializer) : - Super(Initializer) +UVRRadialMenuHandler::UVRRadialMenuHandler() : + Super(), + UIOwner(nullptr) { - + } void UVRRadialMenuHandler::BackOutMenu() @@ -478,9 +479,9 @@ void UVRRadialMenuHandler::UIMenuGenerator(FMenuBuilder& MenuBuilder, TSharedPtr FSlateIcon(FVREditorStyle::GetStyleSetName(), "VREditorStyle.Details"), FUIAction ( - FExecuteAction::CreateStatic(&FVREditorActionCallbacks::OnUIToggleButtonClicked, VRMode, UVREditorUISystem::EEditorUIPanel::ActorDetails), + FExecuteAction::CreateStatic(&FVREditorActionCallbacks::OnUIToggleButtonClicked, VRMode, UVREditorUISystem::DetailsPanelID), FCanExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::DefaultCanExecuteAction), - FGetActionCheckState::CreateStatic(&FVREditorActionCallbacks::GetUIToggledState, VRMode, UVREditorUISystem::EEditorUIPanel::ActorDetails) + FGetActionCheckState::CreateStatic(&FVREditorActionCallbacks::GetUIToggledState, VRMode, UVREditorUISystem::DetailsPanelID) ), NAME_None, EUserInterfaceActionType::ToggleButton @@ -491,9 +492,9 @@ void UVRRadialMenuHandler::UIMenuGenerator(FMenuBuilder& MenuBuilder, TSharedPtr FSlateIcon(FVREditorStyle::GetStyleSetName(), "VREditorStyle.ContentBrowser"), FUIAction ( - FExecuteAction::CreateStatic(&FVREditorActionCallbacks::OnUIToggleButtonClicked, VRMode, UVREditorUISystem::EEditorUIPanel::ContentBrowser), + FExecuteAction::CreateStatic(&FVREditorActionCallbacks::OnUIToggleButtonClicked, VRMode, UVREditorUISystem::ContentBrowserPanelID), FCanExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::DefaultCanExecuteAction), - FGetActionCheckState::CreateStatic(&FVREditorActionCallbacks::GetUIToggledState, VRMode, UVREditorUISystem::EEditorUIPanel::ContentBrowser) + FGetActionCheckState::CreateStatic(&FVREditorActionCallbacks::GetUIToggledState, VRMode, UVREditorUISystem::ContentBrowserPanelID) ), NAME_None, EUserInterfaceActionType::ToggleButton @@ -504,9 +505,9 @@ void UVRRadialMenuHandler::UIMenuGenerator(FMenuBuilder& MenuBuilder, TSharedPtr FSlateIcon(FVREditorStyle::GetStyleSetName(), "VREditorStyle.ModesPanel"), FUIAction ( - FExecuteAction::CreateStatic(&FVREditorActionCallbacks::OnUIToggleButtonClicked, VRMode, UVREditorUISystem::EEditorUIPanel::Modes), + FExecuteAction::CreateStatic(&FVREditorActionCallbacks::OnUIToggleButtonClicked, VRMode, UVREditorUISystem::ModesPanelID), FCanExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::DefaultCanExecuteAction), - FGetActionCheckState::CreateStatic(&FVREditorActionCallbacks::GetUIToggledState, VRMode, UVREditorUISystem::EEditorUIPanel::Modes) + FGetActionCheckState::CreateStatic(&FVREditorActionCallbacks::GetUIToggledState, VRMode, UVREditorUISystem::ModesPanelID) ), NAME_None, EUserInterfaceActionType::ToggleButton @@ -517,9 +518,9 @@ void UVRRadialMenuHandler::UIMenuGenerator(FMenuBuilder& MenuBuilder, TSharedPtr FSlateIcon(FVREditorStyle::GetStyleSetName(), "VREditorStyle.WorldOutliner"), FUIAction ( - FExecuteAction::CreateStatic(&FVREditorActionCallbacks::OnUIToggleButtonClicked, VRMode, UVREditorUISystem::EEditorUIPanel::WorldOutliner), + FExecuteAction::CreateStatic(&FVREditorActionCallbacks::OnUIToggleButtonClicked, VRMode, UVREditorUISystem::WorldOutlinerPanelID), FCanExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::DefaultCanExecuteAction), - FGetActionCheckState::CreateStatic(&FVREditorActionCallbacks::GetUIToggledState, VRMode, UVREditorUISystem::EEditorUIPanel::WorldOutliner) + FGetActionCheckState::CreateStatic(&FVREditorActionCallbacks::GetUIToggledState, VRMode, UVREditorUISystem::WorldOutlinerPanelID) ), NAME_None, EUserInterfaceActionType::ToggleButton @@ -530,9 +531,9 @@ void UVRRadialMenuHandler::UIMenuGenerator(FMenuBuilder& MenuBuilder, TSharedPtr FSlateIcon(FVREditorStyle::GetStyleSetName(), "VREditorStyle.WorldSettings"), FUIAction ( - FExecuteAction::CreateStatic(&FVREditorActionCallbacks::OnUIToggleButtonClicked, VRMode, UVREditorUISystem::EEditorUIPanel::WorldSettings), + FExecuteAction::CreateStatic(&FVREditorActionCallbacks::OnUIToggleButtonClicked, VRMode, UVREditorUISystem::WorldSettingsPanelID), FCanExecuteAction::CreateStatic(&FLevelEditorActionCallbacks::DefaultCanExecuteAction), - FGetActionCheckState::CreateStatic(&FVREditorActionCallbacks::GetUIToggledState, VRMode, UVREditorUISystem::EEditorUIPanel::WorldSettings) + FGetActionCheckState::CreateStatic(&FVREditorActionCallbacks::GetUIToggledState, VRMode, UVREditorUISystem::WorldSettingsPanelID) ), NAME_None, EUserInterfaceActionType::ToggleButton diff --git a/Engine/Source/Editor/VREditor/UI/VRRadialMenuHandler.h b/Engine/Source/Editor/VREditor/UI/VRRadialMenuHandler.h index 1c1af690bd64..ddbbb5a0843a 100644 --- a/Engine/Source/Editor/VREditor/UI/VRRadialMenuHandler.h +++ b/Engine/Source/Editor/VREditor/UI/VRRadialMenuHandler.h @@ -20,9 +20,13 @@ DECLARE_DELEGATE_FourParams(FOnRadialMenuGenerated, FMenuBuilder&, TSharedPtr CommandList, UVREditorMode* VRMode, float& RadiusOverride); diff --git a/Engine/Source/Editor/VREditor/VREditor.Build.cs b/Engine/Source/Editor/VREditor/VREditor.Build.cs index 17332d060dbf..5c23851aadb7 100644 --- a/Engine/Source/Editor/VREditor/VREditor.Build.cs +++ b/Engine/Source/Editor/VREditor/VREditor.Build.cs @@ -22,7 +22,8 @@ namespace UnrealBuildTool.Rules "HeadMountedDisplay", "Analytics", "LevelSequence", - "Sequencer" + "Sequencer", + "Projects" } ); diff --git a/Engine/Source/Editor/VREditor/VREditorActions.cpp b/Engine/Source/Editor/VREditor/VREditorActions.cpp index 98014402f620..665d9f7162d4 100644 --- a/Engine/Source/Editor/VREditor/VREditorActions.cpp +++ b/Engine/Source/Editor/VREditor/VREditorActions.cpp @@ -7,7 +7,6 @@ #include "ViewportWorldInteraction.h" #include "VREditorInteractor.h" #include "VREditorFloatingUI.h" -#include "VREditorTransformGizmo.h" #include "SLevelViewport.h" #include "ImageUtils.h" #include "FileHelper.h" @@ -217,12 +216,12 @@ void FVREditorActionCallbacks::UpdateGizmoModeText(UVREditorMode* InVRMode) FVREditorActionCallbacks::GizmoModeText = GizmoTypeText; } -void FVREditorActionCallbacks::OnUIToggleButtonClicked(UVREditorMode* InVRMode, const UVREditorUISystem::EEditorUIPanel PanelToToggle) +void FVREditorActionCallbacks::OnUIToggleButtonClicked(UVREditorMode* InVRMode, VREditorPanelID PanelToToggle) { InVRMode->GetUISystem().TogglePanelVisibility(PanelToToggle); } -ECheckBoxState FVREditorActionCallbacks::GetUIToggledState(UVREditorMode* InVRMode, const UVREditorUISystem::EEditorUIPanel PanelToCheck) +ECheckBoxState FVREditorActionCallbacks::GetUIToggledState(UVREditorMode* InVRMode, VREditorPanelID PanelToCheck) { return InVRMode->GetUISystem().IsShowingEditorUIPanel(PanelToCheck) ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; } diff --git a/Engine/Source/Editor/VREditor/VREditorActions.h b/Engine/Source/Editor/VREditor/VREditorActions.h index ff22932f4651..caaad7a4ed69 100644 --- a/Engine/Source/Editor/VREditor/VREditorActions.h +++ b/Engine/Source/Editor/VREditor/VREditorActions.h @@ -88,14 +88,14 @@ public: * @param InVRMode Currently active VRMode * @param PanelToToggle UI panel to change the state of */ - static void OnUIToggleButtonClicked(UVREditorMode* InVRMode, const UVREditorUISystem::EEditorUIPanel PanelToToggle); + static void OnUIToggleButtonClicked(UVREditorMode* InVRMode, VREditorPanelID PanelToToggle); /** * Returns a VR UI panel's visibility - used for check boxes on the menu button * @param InVRMode Currently active VRMode * @param PanelToToggle UI panel to read the state of */ - static ECheckBoxState GetUIToggledState(UVREditorMode* InVRMode, const UVREditorUISystem::EEditorUIPanel PanelToCheck); + static ECheckBoxState GetUIToggledState(UVREditorMode* InVRMode, VREditorPanelID PanelToCheck); /** * Toggles a flashlight on and off on the interactor that clicked on the UI button diff --git a/Engine/Source/Editor/VREditor/VREditorAvatarActor.cpp b/Engine/Source/Editor/VREditor/VREditorAvatarActor.cpp index 7922235eccc7..091465950b20 100644 --- a/Engine/Source/Editor/VREditor/VREditorAvatarActor.cpp +++ b/Engine/Source/Editor/VREditor/VREditorAvatarActor.cpp @@ -40,10 +40,22 @@ namespace VREd static FAutoConsoleVariable ScaleProgressBarRadius( TEXT( "VREd.ScaleProgressBarRadius" ), 1.0f, TEXT( "Radius of the progressbar that appears when scaling" ) ); } -AVREditorAvatarActor::AVREditorAvatarActor( const FObjectInitializer& ObjectInitializer ) : - Super( ObjectInitializer ), +AVREditorAvatarActor::AVREditorAvatarActor() : + Super(), + HeadMeshComponent(nullptr), + WorldMovementGridMeshComponent(nullptr), + WorldMovementGridMID(nullptr), WorldMovementGridOpacity( 0.0f ), bIsDrawingWorldMovementPostProcess( false ), + WorldMovementPostProcessMaterial(nullptr), + ScaleProgressMeshComponent(nullptr), + CurrentScaleProgressMeshComponent(nullptr), + UserScaleIndicatorText(nullptr), + FixedUserScaleMID(nullptr), + TranslucentFixedUserScaleMID(nullptr), + CurrentUserScaleMID(nullptr), + TranslucentCurrentUserScaleMID(nullptr), + PostProcessComponent(nullptr), VRMode( nullptr ) { if (UNLIKELY(IsRunningDedicatedServer())) // @todo vreditor: Hack to avoid loading font assets in the cooker on Linux @@ -51,24 +63,30 @@ AVREditorAvatarActor::AVREditorAvatarActor( const FObjectInitializer& ObjectInit return; } + // Set root component { - USceneComponent* SceneRootComponent = CreateDefaultSubobject( TEXT( "RootComponent" ) ); - AddOwnedComponent( SceneRootComponent ); - SetRootComponent( SceneRootComponent ); + USceneComponent* SceneRootComponent = CreateDefaultSubobject(TEXT("Root")); + AddOwnedComponent(SceneRootComponent); + SetRootComponent(SceneRootComponent); } +} + +void AVREditorAvatarActor::Init( UVREditorMode* InVRMode ) +{ + VRMode = InVRMode; // Setup the asset container. - UVREditorAssetContainer* AssetContainer = LoadObject(nullptr, *UVREditorMode::AssetContainerPath); - check(AssetContainer != nullptr); + const UVREditorAssetContainer& AssetContainer = VRMode->GetAssetContainer(); // Give us a head mesh { - HeadMeshComponent = CreateDefaultSubobject( TEXT( "HeadMeshComponent" ) ); + HeadMeshComponent = NewObject(this); AddOwnedComponent( HeadMeshComponent ); HeadMeshComponent->SetupAttachment( RootComponent ); + HeadMeshComponent->RegisterComponent(); // @todo vreditor: This needs to adapt based on the device you're using - UStaticMesh* HeadMesh = AssetContainer->GenericHMDMesh; + UStaticMesh* HeadMesh = AssetContainer.GenericHMDMesh; check( HeadMesh != nullptr ); HeadMeshComponent->SetStaticMesh( HeadMesh ); @@ -79,18 +97,19 @@ AVREditorAvatarActor::AVREditorAvatarActor( const FObjectInitializer& ObjectInit // World movement grid mesh { - WorldMovementGridMeshComponent = CreateDefaultSubobject( TEXT( "WorldMovementGridMeshComponent" ) ); + WorldMovementGridMeshComponent = NewObject(this); AddOwnedComponent( WorldMovementGridMeshComponent ); WorldMovementGridMeshComponent->SetupAttachment( RootComponent ); - - UStaticMesh* GridMesh = AssetContainer->PlaneMesh; + WorldMovementGridMeshComponent->RegisterComponent(); + + UStaticMesh* GridMesh = AssetContainer.PlaneMesh; check( GridMesh != nullptr ); WorldMovementGridMeshComponent->SetStaticMesh( GridMesh ); WorldMovementGridMeshComponent->SetMobility( EComponentMobility::Movable ); WorldMovementGridMeshComponent->SetCollisionEnabled( ECollisionEnabled::NoCollision ); WorldMovementGridMeshComponent->bSelectable = false; - UMaterialInterface* GridMaterial = AssetContainer->GridMaterial; + UMaterialInterface* GridMaterial = AssetContainer.GridMaterial; check( GridMaterial != nullptr ); WorldMovementGridMID = UMaterialInstanceDynamic::Create( GridMaterial, GetTransientPackage( ) ); @@ -102,101 +121,102 @@ AVREditorAvatarActor::AVREditorAvatarActor( const FObjectInitializer& ObjectInit } { - { - UMaterialInterface* UserScaleIndicatorMaterial = AssetContainer->LaserPointerMaterial; - check( UserScaleIndicatorMaterial != nullptr ); + UMaterialInterface* UserScaleIndicatorMaterial = AssetContainer.LaserPointerMaterial; + check( UserScaleIndicatorMaterial != nullptr ); - UMaterialInterface* TranslucentUserScaleIndicatorMaterial = AssetContainer->LaserPointerTranslucentMaterial; - check( TranslucentUserScaleIndicatorMaterial != nullptr ); + UMaterialInterface* TranslucentUserScaleIndicatorMaterial = AssetContainer.LaserPointerTranslucentMaterial; + check( TranslucentUserScaleIndicatorMaterial != nullptr ); - FixedUserScaleMID = UMaterialInstanceDynamic::Create( UserScaleIndicatorMaterial, GetTransientPackage() ); - check( FixedUserScaleMID != nullptr ); + FixedUserScaleMID = UMaterialInstanceDynamic::Create( UserScaleIndicatorMaterial, GetTransientPackage() ); + check( FixedUserScaleMID != nullptr ); - TranslucentFixedUserScaleMID = UMaterialInstanceDynamic::Create( TranslucentUserScaleIndicatorMaterial, GetTransientPackage() ); - check( TranslucentFixedUserScaleMID != nullptr ); + TranslucentFixedUserScaleMID = UMaterialInstanceDynamic::Create( TranslucentUserScaleIndicatorMaterial, GetTransientPackage() ); + check( TranslucentFixedUserScaleMID != nullptr ); - CurrentUserScaleMID = UMaterialInstanceDynamic::Create( UserScaleIndicatorMaterial, GetTransientPackage() ); - check( CurrentUserScaleMID != nullptr ); + CurrentUserScaleMID = UMaterialInstanceDynamic::Create( UserScaleIndicatorMaterial, GetTransientPackage() ); + check( CurrentUserScaleMID != nullptr ); - TranslucentCurrentUserScaleMID = UMaterialInstanceDynamic::Create( TranslucentUserScaleIndicatorMaterial, GetTransientPackage() ); - check( TranslucentCurrentUserScaleMID != nullptr ); + TranslucentCurrentUserScaleMID = UMaterialInstanceDynamic::Create( TranslucentUserScaleIndicatorMaterial, GetTransientPackage() ); + check( TranslucentCurrentUserScaleMID != nullptr ); - UStaticMesh* ScaleLineMesh = AssetContainer->LaserPointerMesh; //@todo VREditor: The laser pointer mesh is not a closed cylinder anymore. - check( ScaleLineMesh != nullptr ); + UStaticMesh* ScaleLineMesh = AssetContainer.LaserPointerMesh; //@todo VREditor: The laser pointer mesh is not a closed cylinder anymore. + check( ScaleLineMesh != nullptr ); - // Creating the background bar progress of the scale - { - ScaleProgressMeshComponent = CreateDefaultSubobject( TEXT( "ScaleProgressMeshComponent" ) ); - this->AddOwnedComponent( ScaleProgressMeshComponent ); - ScaleProgressMeshComponent->SetupAttachment( RootComponent ); - - ScaleProgressMeshComponent->SetStaticMesh( ScaleLineMesh ); - ScaleProgressMeshComponent->SetMobility( EComponentMobility::Movable ); - ScaleProgressMeshComponent->SetCollisionEnabled( ECollisionEnabled::NoCollision ); - ScaleProgressMeshComponent->SetMaterial( 0, FixedUserScaleMID ); - ScaleProgressMeshComponent->SetMaterial( 1, TranslucentFixedUserScaleMID ); - ScaleProgressMeshComponent->bSelectable = false; - - // The user scale indicator starts invisible - ScaleProgressMeshComponent->SetVisibility( false ); - } - - // Creating the current progress of the scale - { - CurrentScaleProgressMeshComponent = CreateDefaultSubobject( TEXT( "CurrentScaleProgressMeshComponent" ) ); - AddOwnedComponent( CurrentScaleProgressMeshComponent ); - CurrentScaleProgressMeshComponent->SetupAttachment( RootComponent ); - - CurrentScaleProgressMeshComponent->SetStaticMesh( ScaleLineMesh ); - CurrentScaleProgressMeshComponent->SetMobility( EComponentMobility::Movable ); - CurrentScaleProgressMeshComponent->SetCollisionEnabled( ECollisionEnabled::NoCollision ); - CurrentScaleProgressMeshComponent->SetMaterial( 0, CurrentUserScaleMID ); - CurrentScaleProgressMeshComponent->SetMaterial( 1, TranslucentCurrentUserScaleMID ); - CurrentScaleProgressMeshComponent->bSelectable = false; - - // The user scale indicator starts invisible - CurrentScaleProgressMeshComponent->SetVisibility( false ); - } - } - - // Creating the text for scaling + // Creating the background bar progress of the scale { - UFont* TextFont = AssetContainer->TextFont; - check( TextFont != nullptr ); + ScaleProgressMeshComponent = NewObject(this); + AddOwnedComponent( ScaleProgressMeshComponent ); + ScaleProgressMeshComponent->SetupAttachment( RootComponent ); + ScaleProgressMeshComponent->RegisterComponent(); - UMaterialInterface* UserScaleIndicatorMaterial = AssetContainer->TextMaterial; - check( UserScaleIndicatorMaterial != nullptr ); + ScaleProgressMeshComponent->SetStaticMesh( ScaleLineMesh ); + ScaleProgressMeshComponent->SetMobility( EComponentMobility::Movable ); + ScaleProgressMeshComponent->SetCollisionEnabled( ECollisionEnabled::NoCollision ); + ScaleProgressMeshComponent->SetMaterial( 0, FixedUserScaleMID ); + ScaleProgressMeshComponent->SetMaterial( 1, TranslucentFixedUserScaleMID ); + ScaleProgressMeshComponent->bSelectable = false; - UserScaleIndicatorText = CreateDefaultSubobject( TEXT( "UserScaleIndicatorText" ) ); - AddOwnedComponent( UserScaleIndicatorText ); - UserScaleIndicatorText->SetupAttachment( RootComponent ); - - UserScaleIndicatorText->SetMobility( EComponentMobility::Movable ); - UserScaleIndicatorText->SetCollisionEnabled( ECollisionEnabled::NoCollision ); - UserScaleIndicatorText->SetCollisionProfileName( UCollisionProfile::NoCollision_ProfileName ); - UserScaleIndicatorText->bSelectable = false; - - UserScaleIndicatorText->bGenerateOverlapEvents = false; - UserScaleIndicatorText->SetCanEverAffectNavigation( false ); - UserScaleIndicatorText->bCastDynamicShadow = false; - UserScaleIndicatorText->bCastStaticShadow = false; - UserScaleIndicatorText->bAffectDistanceFieldLighting = false; - UserScaleIndicatorText->bAffectDynamicIndirectLighting = false; - - // Use a custom font. The text will be visible up close. - UserScaleIndicatorText->SetFont( TextFont ); - UserScaleIndicatorText->SetWorldSize( 8.0f ); - UserScaleIndicatorText->SetTextMaterial( UserScaleIndicatorMaterial ); - - // Center the text horizontally - UserScaleIndicatorText->SetHorizontalAlignment( EHTA_Center ); - UserScaleIndicatorText->SetVisibility( false ); + // The user scale indicator starts invisible + ScaleProgressMeshComponent->SetVisibility( false ); } + + // Creating the current progress of the scale + { + CurrentScaleProgressMeshComponent = NewObject(this); + AddOwnedComponent( CurrentScaleProgressMeshComponent ); + CurrentScaleProgressMeshComponent->SetupAttachment( RootComponent ); + CurrentScaleProgressMeshComponent->RegisterComponent(); + + CurrentScaleProgressMeshComponent->SetStaticMesh( ScaleLineMesh ); + CurrentScaleProgressMeshComponent->SetMobility( EComponentMobility::Movable ); + CurrentScaleProgressMeshComponent->SetCollisionEnabled( ECollisionEnabled::NoCollision ); + CurrentScaleProgressMeshComponent->SetMaterial( 0, CurrentUserScaleMID ); + CurrentScaleProgressMeshComponent->SetMaterial( 1, TranslucentCurrentUserScaleMID ); + CurrentScaleProgressMeshComponent->bSelectable = false; + + // The user scale indicator starts invisible + CurrentScaleProgressMeshComponent->SetVisibility( false ); + } + } + + // Creating the text for scaling + { + UFont* TextFont = AssetContainer.TextFont; + check( TextFont != nullptr ); + + UMaterialInterface* UserScaleIndicatorMaterial = AssetContainer.TextMaterial; + check( UserScaleIndicatorMaterial != nullptr ); + + UserScaleIndicatorText = NewObject(this); + AddOwnedComponent( UserScaleIndicatorText ); + UserScaleIndicatorText->SetupAttachment( RootComponent ); + UserScaleIndicatorText->RegisterComponent(); + + UserScaleIndicatorText->SetMobility( EComponentMobility::Movable ); + UserScaleIndicatorText->SetCollisionEnabled( ECollisionEnabled::NoCollision ); + UserScaleIndicatorText->SetCollisionProfileName( UCollisionProfile::NoCollision_ProfileName ); + UserScaleIndicatorText->bSelectable = false; + + UserScaleIndicatorText->bGenerateOverlapEvents = false; + UserScaleIndicatorText->SetCanEverAffectNavigation( false ); + UserScaleIndicatorText->bCastDynamicShadow = false; + UserScaleIndicatorText->bCastStaticShadow = false; + UserScaleIndicatorText->bAffectDistanceFieldLighting = false; + UserScaleIndicatorText->bAffectDynamicIndirectLighting = false; + + // Use a custom font. The text will be visible up close. + UserScaleIndicatorText->SetFont( TextFont ); + UserScaleIndicatorText->SetWorldSize( 8.0f ); + UserScaleIndicatorText->SetTextMaterial( UserScaleIndicatorMaterial ); + + // Center the text horizontally + UserScaleIndicatorText->SetHorizontalAlignment( EHTA_Center ); + UserScaleIndicatorText->SetVisibility( false ); } // Load our post process material for the world movement grid { - UMaterial* Material = AssetContainer->WorldMovementPostProcessMaterial; + UMaterial* Material = AssetContainer.WorldMovementPostProcessMaterial; check( Material != nullptr ); WorldMovementPostProcessMaterial = UMaterialInstanceDynamic::Create( Material, GetTransientPackage() ); check( WorldMovementPostProcessMaterial != nullptr ); @@ -204,33 +224,16 @@ AVREditorAvatarActor::AVREditorAvatarActor( const FObjectInitializer& ObjectInit // Post processing { - PostProcessComponent = CreateDefaultSubobject( TEXT( "PostProcessComponent" ) ); + PostProcessComponent = NewObject(this); AddOwnedComponent( PostProcessComponent ); PostProcessComponent->SetupAttachment( this->GetRootComponent( ) ); + PostProcessComponent->RegisterComponent(); // Unlimited size PostProcessComponent->bEnabled = GetDefault()->bShowWorldMovementPostProcess; PostProcessComponent->bUnbound = true; } -} - -AVREditorAvatarActor::~AVREditorAvatarActor() -{ - WorldMovementGridMID = nullptr; - WorldMovementPostProcessMaterial = nullptr; - HeadMeshComponent = nullptr; - WorldMovementGridMeshComponent = nullptr; - PostProcessComponent = nullptr; - ScaleProgressMeshComponent = nullptr; - CurrentScaleProgressMeshComponent = nullptr; - UserScaleIndicatorText = nullptr; -} - -void AVREditorAvatarActor::Init( UVREditorMode* InVRMode ) -{ - VRMode = InVRMode; - // Set the default color for the progress bar { static FName StaticLaserColorName( "LaserColor" ); diff --git a/Engine/Source/Editor/VREditor/VREditorAvatarActor.h b/Engine/Source/Editor/VREditor/VREditorAvatarActor.h index b0560f9244af..735e7efb6333 100644 --- a/Engine/Source/Editor/VREditor/VREditorAvatarActor.h +++ b/Engine/Source/Editor/VREditor/VREditorAvatarActor.h @@ -15,11 +15,12 @@ class UMaterialInstanceDynamic; UCLASS() class AVREditorAvatarActor : public AActor { - GENERATED_UCLASS_BODY() + GENERATED_BODY() public: - ~AVREditorAvatarActor(); + /** Default constructor */ + AVREditorAvatarActor(); /** Called by VREditorMode::Enter to initialize all post constructor components and to set the VRMode */ void Init( class UVREditorMode* InVRMode ); diff --git a/Engine/Source/Editor/VREditor/VREditorBaseActor.cpp b/Engine/Source/Editor/VREditor/VREditorBaseActor.cpp index 597b1354fc1f..2aee5640c5f8 100644 --- a/Engine/Source/Editor/VREditor/VREditorBaseActor.cpp +++ b/Engine/Source/Editor/VREditor/VREditorBaseActor.cpp @@ -14,6 +14,7 @@ namespace VREd AVREditorBaseActor::AVREditorBaseActor() : Super(), Scale( 1.0f ), + VRMode(nullptr), LocalRotation( FRotator( 90.0f, 180.0f, 0.0f ) ), RelativeOffset( FVector::ZeroVector ), DockedTo( EDockedTo::Nothing ), diff --git a/Engine/Source/Editor/VREditor/VREditorInteractor.cpp b/Engine/Source/Editor/VREditor/VREditorInteractor.cpp index b2c66990c7fb..3f92dec6dcd7 100644 --- a/Engine/Source/Editor/VREditor/VREditorInteractor.cpp +++ b/Engine/Source/Editor/VREditor/VREditorInteractor.cpp @@ -7,15 +7,14 @@ #include "Engine/Selection.h" #include "VREditorMode.h" #include "VREditorFloatingText.h" -#include "VREditorButton.h" #include "VREditorFloatingUI.h" #include "VREditorDockableWindow.h" #include "ActorTransformer.h" #define LOCTEXT_NAMESPACE "VREditor" -UVREditorInteractor::UVREditorInteractor( const FObjectInitializer& Initializer ) : - Super( Initializer ), +UVREditorInteractor::UVREditorInteractor() : + Super(), VRMode( nullptr ), bIsModifierPressed( false ), SelectAndMoveTriggerValue( 0.0f ), @@ -31,11 +30,6 @@ UVREditorInteractor::UVREditorInteractor( const FObjectInitializer& Initializer } -UVREditorInteractor::~UVREditorInteractor() -{ - Shutdown(); -} - void UVREditorInteractor::Init( UVREditorMode* InVRMode ) { VRMode = InVRMode; @@ -115,7 +109,6 @@ FHitResult UVREditorInteractor::GetHitResultFromLaserPointer( TArray* O ObjectsInFrontOfGizmo = &PriorityOverGizmoObjects; } - ObjectsInFrontOfGizmo->Add( AVREditorButton::StaticClass() ); ObjectsInFrontOfGizmo->Add( AVREditorDockableWindow::StaticClass() ); ObjectsInFrontOfGizmo->Add( AVREditorFloatingUI::StaticClass() ); diff --git a/Engine/Source/Editor/VREditor/VREditorMode.cpp b/Engine/Source/Editor/VREditor/VREditorMode.cpp index 6f7a29e0c287..fb285f5660e7 100644 --- a/Engine/Source/Editor/VREditor/VREditorMode.cpp +++ b/Engine/Source/Editor/VREditor/VREditorMode.cpp @@ -35,7 +35,6 @@ #include "IViewportInteractionModule.h" #include "VREditorMotionControllerInteractor.h" -#include "ViewportWorldInteractionManager.h" #include "EditorWorldExtension.h" #include "SequencerSettings.h" #include "Kismet/GameplayStatics.h" @@ -92,13 +91,6 @@ UVREditorMode::UVREditorMode() : { } - -UVREditorMode::~UVREditorMode() -{ - Shutdown(); -} - - void UVREditorMode::Init() { // @todo vreditor urgent: Turn on global editor hacks for VR Editor mode @@ -320,8 +312,11 @@ void UVREditorMode::Enter() void UVREditorMode::Exit(const bool bShouldDisableStereo) { { + GetLevelViewportPossessedForVR().RemoveAllPreviews(); + GEditor->SelectNone(true, true, false); + GEditor->NoteSelectionChange(); FVREditorActionCallbacks::ChangeEditorModes(FBuiltinEditorModes::EM_Placement); - + //Destroy the avatar { DestroyTransientActor(AvatarActor); @@ -399,11 +394,9 @@ void UVREditorMode::Exit(const bool bShouldDisableStereo) WorldInteraction->RemoveInteractor( LeftHandInteractor ); LeftHandInteractor->MarkPendingKill(); - LeftHandInteractor->Shutdown(); LeftHandInteractor = nullptr; WorldInteraction->RemoveInteractor( RightHandInteractor ); - RightHandInteractor->Shutdown(); RightHandInteractor->MarkPendingKill(); RightHandInteractor = nullptr; @@ -422,6 +415,8 @@ void UVREditorMode::Exit(const bool bShouldDisableStereo) FSlateNotificationManager::Get().SetAllowNotifications( true); } + AssetContainer = nullptr; + FEditorDelegates::PostPIEStarted.RemoveAll( this ); FEditorDelegates::PrePIEEnded.RemoveAll( this ); FEditorDelegates::EndPIE.RemoveAll( this ); @@ -692,12 +687,20 @@ void UVREditorMode::RefreshVREditorSequencer(class ISequencer* InCurrentSequence { CurrentSequencer = InCurrentSequencer; // Tell the VR Editor UI system to refresh the Sequencer UI - if (bActuallyUsingVR && InCurrentSequencer != nullptr) + if (bActuallyUsingVR && UISystem != nullptr) { GetUISystem().UpdateSequencerUI(); } } +void UVREditorMode::RefreshActorPreviewWidget(TSharedRef InWidget) +{ + if (bActuallyUsingVR && UISystem != nullptr) + { + GetUISystem().UpdateActorPreviewUI(InWidget); + } +} + class ISequencer* UVREditorMode::GetCurrentSequencer() { return CurrentSequencer; @@ -871,10 +874,14 @@ void UVREditorMode::TransitionWorld(UWorld* NewWorld) UISystem->TransitionWorld(NewWorld); } -void UVREditorMode::LeftSimulateInEditor() +void UVREditorMode::LeftSimulateInEditor(UWorld* SimulateWorld) { - GetWorld()->GetWorldSettings()->WorldToMeters = SavedWorldToMetersScaleForPIE; - WorldInteraction->SetWorldToMetersScale(SavedWorldToMetersScaleForPIE); + if (SimulateWorld != nullptr) + { + const float SimulateWorldToMeters = SimulateWorld->GetWorldSettings()->WorldToMeters; + GetWorld()->GetWorldSettings()->WorldToMeters = SimulateWorldToMeters; + WorldInteraction->SetWorldToMetersScale(SimulateWorldToMeters); + } } void UVREditorMode::StartViewport(TSharedPtr Viewport) diff --git a/Engine/Source/Editor/VREditor/VREditorModeManager.cpp b/Engine/Source/Editor/VREditor/VREditorModeManager.cpp index db1a2594fcd8..453cacdb71c5 100644 --- a/Engine/Source/Editor/VREditor/VREditorModeManager.cpp +++ b/Engine/Source/Editor/VREditor/VREditorModeManager.cpp @@ -16,12 +16,13 @@ #include "ViewportWorldInteraction.h" #include "VRModeSettings.h" #include "Dialogs.h" +#include "ProjectDescriptor.h" +#include "Interfaces/IProjectManager.h" #define LOCTEXT_NAMESPACE "VREditor" FVREditorModeManager::FVREditorModeManager() : CurrentVREditorMode( nullptr ), - PreviousVREditorMode( nullptr ), bEnableVRRequest( false ), HMDWornState( EHMDWornState::Unknown ), TimeSinceHMDChecked( 0.0f ) @@ -31,7 +32,6 @@ FVREditorModeManager::FVREditorModeManager() : FVREditorModeManager::~FVREditorModeManager() { CurrentVREditorMode = nullptr; - PreviousVREditorMode = nullptr; } void FVREditorModeManager::Tick( const float DeltaTime ) @@ -43,7 +43,6 @@ void FVREditorModeManager::Tick( const float DeltaTime ) bool bCanAutoEnterVR = GetDefault()->bEnableAutoVREditMode && (GEditor->PlayWorld == nullptr || (CurrentVREditorMode != nullptr && CurrentVREditorMode->GetStartedPlayFromVREditor())) && FPlatformProcess::IsThisApplicationForeground(); - if( GEngine != nullptr && GEngine->HMDDevice.IsValid() ) { // Only check whether you are wearing the HMD every second, if you are allowed to auto-enter VR, and if your HMD state has changed since the last check. @@ -59,7 +58,7 @@ void FVREditorModeManager::Tick( const float DeltaTime ) { if (GEditor->PlayWorld && !GEditor->bIsSimulatingInEditor) { - CurrentVREditorMode->TogglePIEAndVREditor(); + CurrentVREditorMode->TogglePIEAndVREditor(); //-V595 } EnableVREditor( false, false ); @@ -109,6 +108,12 @@ void FVREditorModeManager::Tick( const float DeltaTime ) } } +bool FVREditorModeManager::IsTickable() const +{ + const FProjectDescriptor* CurrentProject = IProjectManager::Get().GetCurrentProject(); + return CurrentProject != nullptr; +} + void FVREditorModeManager::EnableVREditor( const bool bEnable, const bool bForceWithoutHMD ) { // Don't do anything when the current VR Editor is already in the requested state @@ -169,14 +174,7 @@ void FVREditorModeManager::StartVREditorMode( const bool bForceWithoutHMD ) UEditorWorldExtensionCollection* ExtensionCollection = GEditor->GetEditorWorldExtensionsManager()->GetEditorWorldExtensions(World); check(ExtensionCollection != nullptr); - // Create viewport world interaction. - UViewportWorldInteraction* ViewportWorldInteraction = Cast( ExtensionCollection->FindExtension( UViewportWorldInteraction::StaticClass() ) ); - if( ViewportWorldInteraction == nullptr ) - { - ViewportWorldInteraction = NewObject(); - } - check( ViewportWorldInteraction != nullptr ); - ExtensionCollection->AddExtension( ViewportWorldInteraction ); + UViewportWorldInteraction* ViewportWorldInteraction = Cast(ExtensionCollection->AddExtension(UViewportWorldInteraction::StaticClass())); // Create vr editor mode. VRMode = NewObject(); @@ -206,13 +204,13 @@ void FVREditorModeManager::CloseVREditor( const bool bShouldDisableStereo ) if( CurrentVREditorMode != nullptr ) { + UViewportWorldInteraction* WorldInteraction = &CurrentVREditorMode->GetWorldInteraction(); CurrentVREditorMode->Exit( bShouldDisableStereo ); - PreviousVREditorMode = CurrentVREditorMode; UEditorWorldExtensionCollection* Collection = CurrentVREditorMode->GetOwningCollection(); check(Collection != nullptr); - Collection->RemoveExtension(Collection->FindExtension(UVREditorMode::StaticClass())); - Collection->RemoveExtension(Collection->FindExtension(UViewportWorldInteraction::StaticClass())); + Collection->RemoveExtension(CurrentVREditorMode); + Collection->RemoveExtension(WorldInteraction); CurrentVREditorMode = nullptr; } diff --git a/Engine/Source/Editor/VREditor/VREditorModeManager.h b/Engine/Source/Editor/VREditor/VREditorModeManager.h index 32ea3d3bea57..403674cb0b79 100644 --- a/Engine/Source/Editor/VREditor/VREditorModeManager.h +++ b/Engine/Source/Editor/VREditor/VREditorModeManager.h @@ -5,6 +5,7 @@ #include "CoreMinimal.h" #include "UObject/ObjectMacros.h" #include "UObject/GCObject.h" +#include "TickableEditorObject.h" #include "Kismet/HeadMountedDisplayFunctionLibrary.h" class UVREditorMode; @@ -13,7 +14,7 @@ enum class EMapChangeType : uint8; /** * Manages starting and closing the VREditor mode */ -class FVREditorModeManager : public FGCObject +class FVREditorModeManager : public FGCObject, public FTickableEditorObject { public: @@ -24,8 +25,13 @@ public: /** Default destructor */ ~FVREditorModeManager(); - /** Ticks to detect entering and closing the VR Editor */ - void Tick( const float DeltaTime ); + // FTickableEditorObject overrides + virtual void Tick(float DeltaTime) override; + virtual bool IsTickable() const override; + virtual TStatId GetStatId() const override + { + RETURN_QUICK_DECLARE_CYCLE_STAT(FVREditorModeManager, STATGROUP_Tickables); + } /** Start or stop the VR Editor */ void EnableVREditor( const bool bEnable, const bool bForceWithoutHMD ); @@ -61,10 +67,6 @@ private: UPROPERTY() UVREditorMode* CurrentVREditorMode; - /** The previous mode, nullptr if none */ - UPROPERTY() - UVREditorMode* PreviousVREditorMode; - /** If the VR Editor mode needs to be enabled next tick */ bool bEnableVRRequest; diff --git a/Engine/Source/Editor/VREditor/VREditorModule.cpp b/Engine/Source/Editor/VREditor/VREditorModule.cpp index c19bbd7a36ed..822f2e3cc839 100644 --- a/Engine/Source/Editor/VREditor/VREditorModule.cpp +++ b/Engine/Source/Editor/VREditor/VREditorModule.cpp @@ -5,7 +5,6 @@ #include "Stats/Stats.h" #include "HAL/IConsoleManager.h" #include "IVREditorModule.h" -#include "TickableEditorObject.h" #include "VREditorModeManager.h" #include "VREditorStyle.h" #include "VREditorMode.h" @@ -13,7 +12,7 @@ #include "MultiBoxExtender.h" #include "Kismet/HeadMountedDisplayFunctionLibrary.h" // For EHMDWornState::Type -class FVREditorModule : public IVREditorModule, public FTickableEditorObject +class FVREditorModule : public IVREditorModule { public: FVREditorModule() @@ -35,17 +34,8 @@ public: virtual void EnableVREditor( const bool bEnable, const bool bForceWithoutHMD ) override; virtual bool IsVREditorModeActive() override; virtual UVREditorMode* GetVRMode() override; + virtual void UpdateActorPreview(TSharedRef InWidget) override; - // FTickableEditorObject overrides - virtual void Tick( float DeltaTime ) override; - virtual bool IsTickable() const override - { - return true; - } - virtual TStatId GetStatId() const override - { - return TStatId(); - } virtual const TSharedRef& GetRadialMenuExtender() override { static TSharedRef RadialMenuExtender( new FExtender() ); @@ -114,6 +104,11 @@ UVREditorMode* FVREditorModule::GetVRMode() return ModeManager.GetCurrentVREditorMode(); } +void FVREditorModule::UpdateActorPreview(TSharedRef InWidget) +{ + GetVRMode()->RefreshActorPreviewWidget(InWidget); +} + void FVREditorModule::ToggleForceVRMode() { const bool bForceWithoutHMD = true; @@ -121,10 +116,4 @@ void FVREditorModule::ToggleForceVRMode() Self.EnableVREditor( !Self.IsVREditorEnabled(), bForceWithoutHMD ); } -void FVREditorModule::Tick( float DeltaTime ) -{ - ModeManager.Tick( DeltaTime ); -} - - IMPLEMENT_MODULE( FVREditorModule, VREditor ) diff --git a/Engine/Source/Editor/VREditor/VREditorMotionControllerInteractor.cpp b/Engine/Source/Editor/VREditor/VREditorMotionControllerInteractor.cpp index 6047c6d91d15..046a7388f014 100644 --- a/Engine/Source/Editor/VREditor/VREditorMotionControllerInteractor.cpp +++ b/Engine/Source/Editor/VREditor/VREditorMotionControllerInteractor.cpp @@ -58,6 +58,7 @@ namespace VREd static FAutoConsoleVariable TrackpadAbsoluteDragSpeed( TEXT( "VREd.TrackpadAbsoluteDragSpeed" ), 40.0f, TEXT( "How fast objects move toward or away when you drag on the touchpad while carrying them" ) ); static FAutoConsoleVariable TrackpadRelativeDragSpeed( TEXT( "VREd.TrackpadRelativeDragSpeed" ), 8.0f, TEXT( "How fast objects move toward or away when you hold a direction on an analog stick while carrying them" ) ); + static FAutoConsoleVariable TrackpadStopImpactAtLaserBuffer( TEXT( "VREd.TrackpadStopImpactAtLaserBuffer" ), 0.4f, TEXT( "Required amount to slide with input to stop transforming to end of laser" ) ); static FAutoConsoleVariable InvertTrackpadVertical( TEXT( "VREd.InvertTrackpadVertical" ), 1, TEXT( "Toggles inverting the touch pad vertical axis" ) ); static FAutoConsoleVariable MinVelocityForInertia( TEXT( "VREd.MinVelocityForMotionControllerInertia" ), 1.0f, TEXT( "Minimum velocity (in cm/frame in unscaled room space) before inertia will kick in when releasing objects (or the world)" ) ); static FAutoConsoleVariable MinTrackpadOffsetBeforeRadialMenu( TEXT( "VREd.MinTrackpadOffsetBeforeRadialMenu" ), 0.5f, TEXT( "How far you have to hold the trackpad upward before you can placing objects instantly by pulling the trigger" ) ); @@ -99,8 +100,8 @@ namespace SteamVRControllerKeyNames #define LOCTEXT_NAMESPACE "VREditor" -UVREditorMotionControllerInteractor::UVREditorMotionControllerInteractor( const FObjectInitializer& Initializer ) : - Super( Initializer ), +UVREditorMotionControllerInteractor::UVREditorMotionControllerInteractor() : + Super(), MotionControllerComponent( nullptr ), HandMeshComponent( nullptr ), LaserPointerMID( nullptr ), @@ -128,13 +129,6 @@ UVREditorMotionControllerInteractor::UVREditorMotionControllerInteractor( const { } - -UVREditorMotionControllerInteractor::~UVREditorMotionControllerInteractor() -{ - Shutdown(); -} - - void UVREditorMotionControllerInteractor::Init( class UVREditorMode* InVRMode ) { Super::Init( InVRMode ); @@ -386,11 +380,6 @@ void UVREditorMotionControllerInteractor::Tick( const float DeltaTime ) HandMeshComponent->SetVisibility( false ); } - // Offset the beginning of the laser pointer a bit, so that it doesn't overlap the hand mesh - const float LaserPointerStartOffset = - WorldScaleFactor * - ( GetVRMode().GetHMDDeviceType() == EHMDDeviceType::DT_OculusRift ? VREd::OculusLaserPointerStartOffset->GetFloat() : VREd::ViveLaserPointerStartOffset->GetFloat() ); - // The laser pointer needs to stay the same size relative to our tracking space, so we inverse compensate for world to meters scale here float LaserPointerRadius = VREd::LaserPointerRadius->GetFloat() * WorldScaleFactor; float HoverMeshRadius = VREd::LaserPointerHoverBallRadius->GetFloat() * WorldScaleFactor; @@ -464,13 +453,18 @@ void UVREditorMotionControllerInteractor::Tick( const float DeltaTime ) // Update the curved laser. No matter if we actually show the laser it needs to update, // so if in the next frame it needs to be visible it won't interpolate from a previous location. { + // Offset the beginning of the laser pointer a bit, so that it doesn't overlap the hand mesh + const float LaserPointerStartOffset = WorldScaleFactor * + (GetVRMode().GetHMDDeviceType() == EHMDDeviceType::DT_OculusRift ? VREd::OculusLaserPointerStartOffset->GetFloat() : VREd::ViveLaserPointerStartOffset->GetFloat()); + // Get the hand transform and forward vector. FTransform InteractorTransform; FVector InteractorForwardVector; GetTransformAndForwardVector( /* Out */ InteractorTransform, /* Out */ InteractorForwardVector); - + InteractorForwardVector.Normalize(); + // Offset the start point of the laser. - LaserPointerStart = InteractorTransform.GetLocation() + (InteractorForwardVector * FVector(LaserPointerStartOffset, 0.0f, 0.0f)); + LaserPointerStart = InteractorTransform.GetLocation() + (InteractorForwardVector * LaserPointerStartOffset); UpdateSplineLaser(LaserPointerStart, LaserPointerEnd, InteractorForwardVector); } @@ -569,6 +563,8 @@ void UVREditorMotionControllerInteractor::CalculateDragRay( float& InOutDragRayL if ( !FMath::IsNearlyZero( SlideDelta ) ) { + + InOutDragRayLength += SlideDelta; InOutDragRayVelocity = 0.0f; @@ -588,6 +584,12 @@ void UVREditorMotionControllerInteractor::CalculateDragRay( float& InOutDragRayL { InOutDragRayLength = 0.0f; InOutDragRayVelocity = 0.0f; + } + + // Stop transforming object to laser impact point when trying to slide with touchpad or analog stick. + if (InteractorData.DraggingMode == EViewportInteractionDraggingMode::TransformablesAtLaserImpact && !FMath::IsNearlyZero(SlideDelta, VREd::TrackpadStopImpactAtLaserBuffer->GetFloat())) + { + InteractorData.DraggingMode = EViewportInteractionDraggingMode::TransformablesFreely; } } } diff --git a/Engine/Source/Editor/VREditor/VREditorMotionControllerInteractor.h b/Engine/Source/Editor/VREditor/VREditorMotionControllerInteractor.h index b59b7a10eb63..9b4cfc7b20e0 100644 --- a/Engine/Source/Editor/VREditor/VREditorMotionControllerInteractor.h +++ b/Engine/Source/Editor/VREditor/VREditorMotionControllerInteractor.h @@ -19,11 +19,12 @@ class UStaticMeshSocket; UCLASS() class UVREditorMotionControllerInteractor : public UVREditorInteractor { - GENERATED_UCLASS_BODY() + GENERATED_BODY() public: - virtual ~UVREditorMotionControllerInteractor(); + /** Default constructor */ + UVREditorMotionControllerInteractor(); // UVREditorInteractor overrides virtual void Init( class UVREditorMode* InVRMode ) override; diff --git a/Engine/Source/Editor/VREditor/VREditorPlacement.cpp b/Engine/Source/Editor/VREditor/VREditorPlacement.cpp index c7a2eb8272bb..16b7c7cd6122 100644 --- a/Engine/Source/Editor/VREditor/VREditorPlacement.cpp +++ b/Engine/Source/Editor/VREditor/VREditorPlacement.cpp @@ -47,6 +47,7 @@ namespace VREd UVREditorPlacement::UVREditorPlacement() : Super(), VRMode( nullptr ), + ViewportWorldInteraction(nullptr), FloatingUIAssetDraggedFrom( nullptr ), PlacingMaterialOrTextureAsset( nullptr ) { @@ -145,7 +146,7 @@ void UVREditorPlacement::StartDraggingMaterialOrTexture( UViewportInteractor* In InteractorData.DraggingTransformGizmoComponent = nullptr; - InteractorData.TransformGizmoInteractionType = ETransformGizmoInteractionType::None; + InteractorData.DragOperationComponent.Reset(); InteractorData.GizmoStartTransform = FTransform::Identity; InteractorData.GizmoLastTransform = InteractorData.GizmoTargetTransform = InteractorData.GizmoUnsnappedTargetTransform = InteractorData.GizmoInterpolationSnapshotTransform = InteractorData.GizmoStartTransform; InteractorData.GizmoStartLocalBounds = FBox(EForceInit::ForceInit); @@ -170,7 +171,7 @@ void UVREditorPlacement::OnAssetDragStartedFromContentBrowser( const TArray& Interactors = ViewportWorldInteraction->GetInteractors(); + const TArray& Interactors = ViewportWorldInteraction->GetInteractors(); for( UViewportInteractor* Interactor : Interactors ) { UVREditorInteractor* VRInteractor = Cast( Interactor ); diff --git a/Engine/Source/Editor/VREditor/VREditorWidgetComponent.cpp b/Engine/Source/Editor/VREditor/VREditorWidgetComponent.cpp index 9a30d975ec35..04c8c18efae5 100644 --- a/Engine/Source/Editor/VREditor/VREditorWidgetComponent.cpp +++ b/Engine/Source/Editor/VREditor/VREditorWidgetComponent.cpp @@ -2,12 +2,12 @@ #include "VREditorWidgetComponent.h" -UVREditorWidgetComponent::UVREditorWidgetComponent(const FObjectInitializer& ObjectInitializer) - : Super( ObjectInitializer ) +UVREditorWidgetComponent::UVREditorWidgetComponent() + : Super(), + DrawingPolicy(EVREditorWidgetDrawingPolicy::Always), + bIsHovering(false), + bHasEverDrawn(false) { - bIsHovering = false; - DrawingPolicy = EVREditorWidgetDrawingPolicy::Always; - bHasEverDrawn = false; bSelectable = false; } diff --git a/Engine/Source/Editor/VREditor/VREditorWidgetComponent.h b/Engine/Source/Editor/VREditor/VREditorWidgetComponent.h index 63e8525944e5..bfe90546bcc8 100644 --- a/Engine/Source/Editor/VREditor/VREditorWidgetComponent.h +++ b/Engine/Source/Editor/VREditor/VREditorWidgetComponent.h @@ -24,7 +24,7 @@ class UVREditorWidgetComponent : public UWidgetComponent public: /** Default constructor that sets up CDO properties */ - UVREditorWidgetComponent(const FObjectInitializer& ObjectInitializer); + UVREditorWidgetComponent(); void SetDrawingPolicy(EVREditorWidgetDrawingPolicy Value) { DrawingPolicy = Value; } EVREditorWidgetDrawingPolicy GetDrawingPolicy() const { return DrawingPolicy; } diff --git a/Engine/Source/Editor/VREditor/VRModeSettings.cpp b/Engine/Source/Editor/VREditor/VRModeSettings.cpp index 683792c9c08e..f223b76e9084 100644 --- a/Engine/Source/Editor/VREditor/VRModeSettings.cpp +++ b/Engine/Source/Editor/VREditor/VRModeSettings.cpp @@ -6,8 +6,8 @@ #define LOCTEXT_NAMESPACE "VREditor" -UVRModeSettings::UVRModeSettings(const FObjectInitializer& ObjectInitializer) - : Super(ObjectInitializer) +UVRModeSettings::UVRModeSettings() + : Super() { bEnableAutoVREditMode = false; InteractorHand = EInteractorHand::Right; diff --git a/Engine/Source/Editor/ViewportInteraction/Gizmo/VIBaseTransformGizmo.cpp b/Engine/Source/Editor/ViewportInteraction/Gizmo/VIBaseTransformGizmo.cpp index e2748e85ee20..91c547ab60cf 100644 --- a/Engine/Source/Editor/ViewportInteraction/Gizmo/VIBaseTransformGizmo.cpp +++ b/Engine/Source/Editor/ViewportInteraction/Gizmo/VIBaseTransformGizmo.cpp @@ -6,6 +6,7 @@ #include "Components/StaticMeshComponent.h" #include "Materials/Material.h" #include "VIGizmoHandle.h" +#include "ViewportDragOperation.h" namespace VREd { @@ -24,25 +25,6 @@ ABaseTransformGizmo::ABaseTransformGizmo( ) : RootComponent = SceneComponent; } - - GizmoMaterial = nullptr; - { - static ConstructorHelpers::FObjectFinder ObjectFinder( TEXT( "/Engine/VREditor/TransformGizmo/TransformGizmoMaterial" ) ); - GizmoMaterial = ObjectFinder.Object; - check( GizmoMaterial != nullptr ); - } - - TranslucentGizmoMaterial = nullptr; - { - static ConstructorHelpers::FObjectFinder ObjectFinder( TEXT( "/Engine/VREditor/TransformGizmo/TranslucentTransformGizmoMaterial" ) ); - TranslucentGizmoMaterial = ObjectFinder.Object; - check( TranslucentGizmoMaterial != nullptr ); - } -} - -ABaseTransformGizmo::~ABaseTransformGizmo() -{ - WorldInteraction = nullptr; } void ABaseTransformGizmo::OnNewObjectsSelected() @@ -50,7 +32,7 @@ void ABaseTransformGizmo::OnNewObjectsSelected() SelectedAtTime = FTimespan::FromSeconds( FApp::GetCurrentTime() ); } -ETransformGizmoInteractionType ABaseTransformGizmo::GetInteractionType( UActorComponent* DraggedComponent, TOptional& OutHandlePlacement ) +UViewportDragOperationComponent* ABaseTransformGizmo::GetInteractionType( UActorComponent* DraggedComponent, TOptional& OutHandlePlacement ) { OutHandlePlacement.Reset(); if ( DraggedComponent != nullptr ) @@ -58,8 +40,6 @@ ETransformGizmoInteractionType ABaseTransformGizmo::GetInteractionType( UActorCo UStaticMeshComponent* DraggedMesh = Cast( DraggedComponent ); if ( DraggedMesh != nullptr ) { - ETransformGizmoInteractionType ResultInteractionType; - for ( UGizmoHandleGroup* HandleGroup : AllHandleGroups ) { if ( HandleGroup != nullptr ) @@ -67,8 +47,8 @@ ETransformGizmoInteractionType ABaseTransformGizmo::GetInteractionType( UActorCo int32 HandIndex = HandleGroup->GetDraggedHandleIndex( DraggedMesh ); if ( HandIndex != INDEX_NONE ) { - HandleGroup->GetHandleIndexInteractionType( HandIndex, ResultInteractionType, OutHandlePlacement ); - return ResultInteractionType; + OutHandlePlacement = HandleGroup->MakeHandlePlacementForIndex(HandIndex); + return HandleGroup->GetDragOperationComponent(); } } } @@ -76,7 +56,7 @@ ETransformGizmoInteractionType ABaseTransformGizmo::GetInteractionType( UActorCo } OutHandlePlacement.Reset(); - return ETransformGizmoInteractionType::Translate; + return nullptr; } float ABaseTransformGizmo::GetAnimationAlpha() diff --git a/Engine/Source/Editor/ViewportInteraction/Gizmo/VIGizmoHandle.cpp b/Engine/Source/Editor/ViewportInteraction/Gizmo/VIGizmoHandle.cpp index bea6c0d7afe5..b0774dcb716a 100644 --- a/Engine/Source/Editor/ViewportInteraction/Gizmo/VIGizmoHandle.cpp +++ b/Engine/Source/Editor/ViewportInteraction/Gizmo/VIGizmoHandle.cpp @@ -6,6 +6,7 @@ #include "GameFramework/WorldSettings.h" #include "VIBaseTransformGizmo.h" #include "ViewportWorldInteraction.h" +#include "ViewportDragOperation.h" UGizmoHandleGroup::UGizmoHandleGroup() : Super(), @@ -15,14 +16,7 @@ UGizmoHandleGroup::UGizmoHandleGroup() OwningTransformGizmoActor(nullptr), bShowOnUniversalGizmo(true) { - -} - -UGizmoHandleGroup::~UGizmoHandleGroup() -{ - OwningTransformGizmoActor = nullptr; - GizmoMaterial = nullptr; - TranslucentGizmoMaterial = nullptr; + DragOperationComponent = CreateDefaultSubobject( TEXT( "DragOperation" ) ); } FTransformGizmoHandlePlacement UGizmoHandleGroup::MakeHandlePlacementForIndex( const int32 HandleIndex ) const @@ -115,17 +109,6 @@ FVector UGizmoHandleGroup::GetAxisVector( const int32 AxisIndex, const ETransfor return AxisVector; } -void UGizmoHandleGroup::GetHandleIndexInteractionType( const int32 HandleIndex, ETransformGizmoInteractionType& OutInteractionType, TOptional& OutHandlePlacement ) -{ - OutHandlePlacement = MakeHandlePlacementForIndex( HandleIndex ); - OutInteractionType = GetInteractionType(); -} - -ETransformGizmoInteractionType UGizmoHandleGroup::GetInteractionType() const -{ - return ETransformGizmoInteractionType::Translate; -} - void UGizmoHandleGroup::UpdateGizmoHandleGroup(const FTransform& LocalToWorld, const FBox& LocalBounds, const FVector ViewLocation, const bool bAllHandlesVisible, class UActorComponent* DraggingHandle, const TArray< UActorComponent* >& HoveringOverHandles, float AnimationAlpha, float GizmoScale, const float GizmoHoverScale, const float GizmoHoverAnimationDuration, bool& bOutIsHoveringOrDraggingThisHandleGroup ) { @@ -259,6 +242,11 @@ void UGizmoHandleGroup::UpdateVisibilityAndCollision(const EGizmoHandleTypes Giz } } +UViewportDragOperationComponent* UGizmoHandleGroup::GetDragOperationComponent() +{ + return DragOperationComponent; +} + class UStaticMeshComponent* UGizmoHandleGroup::CreateMeshHandle( class UStaticMesh* HandleMesh, const FString& ComponentName ) { const bool bAllowGizmoLighting = false; // @todo vreditor: Not sure if we want this for gizmos or not yet. Needs feedback. Also they're translucent right now. diff --git a/Engine/Source/Editor/ViewportInteraction/Gizmo/VIPivotTransformGizmo.cpp b/Engine/Source/Editor/ViewportInteraction/Gizmo/VIPivotTransformGizmo.cpp index 7474e38458e9..c42b325fd24b 100644 --- a/Engine/Source/Editor/ViewportInteraction/Gizmo/VIPivotTransformGizmo.cpp +++ b/Engine/Source/Editor/ViewportInteraction/Gizmo/VIPivotTransformGizmo.cpp @@ -18,6 +18,7 @@ #include "Components/TextRenderComponent.h" #include "Components/StaticMeshComponent.h" #include "Math/UnitConversion.h" +#include "ViewportInteractionDragOperations.h" namespace VREd //@todo VREditor: Duplicates of TransformGizmo { @@ -38,6 +39,10 @@ APivotTransformGizmo::APivotTransformGizmo() : AimingAtGizmoScaleAlpha(0.0f), LastDraggingHandle(nullptr) { + const UViewportInteractionAssetContainer& AssetContainer = UViewportWorldInteraction::LoadAssetContainer(); + UMaterialInterface* GizmoMaterial = AssetContainer.TransformGizmoMaterial; + UMaterialInterface* TranslucentGizmoMaterial = AssetContainer.TranslucentTransformGizmoMaterial; + UniformScaleGizmoHandleGroup = CreateDefaultSubobject( TEXT( "UniformScaleHandles" ), true ); UniformScaleGizmoHandleGroup->SetOwningTransformGizmo(this); UniformScaleGizmoHandleGroup->SetTranslucentGizmoMaterial( TranslucentGizmoMaterial ); @@ -96,7 +101,7 @@ void APivotTransformGizmo::UpdateGizmo(const EGizmoHandleTypes InGizmoType, cons // Increase scale with distance, to make gizmo handles easier to click on const float WorldSpaceDistanceToToPivot = FMath::Max(VREd::PivotGizmoMinDistanceForScaling->GetFloat(), FMath::Sqrt(FVector::DistSquared( GetActorLocation(), InViewLocation ))); const float WorldScaleFactor = WorldInteraction->GetWorldScaleFactor(); - float GizmoScale = (InScaleMultiplier * ((WorldSpaceDistanceToToPivot / WorldScaleFactor) * VREd::PivotGizmoDistanceScaleFactor->GetFloat())) * WorldScaleFactor; + const float GizmoScale = (InScaleMultiplier * ((WorldSpaceDistanceToToPivot / WorldScaleFactor) * VREd::PivotGizmoDistanceScaleFactor->GetFloat())) * WorldScaleFactor; const bool bIsWorldSpaceGizmo = (WorldInteraction->GetTransformGizmoCoordinateSpace() == COORD_World); if (LastDraggingHandle != nullptr && DraggingHandle == nullptr) @@ -104,6 +109,7 @@ void APivotTransformGizmo::UpdateGizmo(const EGizmoHandleTypes InGizmoType, cons AimingAtGizmoScaleAlpha = 0.0f; } + float AnimatedGizmoScale = GizmoScale; // Only scale the gizmo down when not aiming at it for VR implementations if (WorldInteraction->IsInVR()) { @@ -141,7 +147,7 @@ void APivotTransformGizmo::UpdateGizmo(const EGizmoHandleTypes InGizmoType, cons } AimingAtGizmoScaleAlpha = FMath::Clamp(AimingAtGizmoScaleAlpha, VREd::PivotGizmoAimAtShrinkSize->GetFloat(), 1.0f); - GizmoScale *= AimingAtGizmoScaleAlpha; + AnimatedGizmoScale *= AimingAtGizmoScaleAlpha; } // Update animation @@ -152,10 +158,13 @@ void APivotTransformGizmo::UpdateGizmo(const EGizmoHandleTypes InGizmoType, cons { if (HandleGroup != nullptr) { - //const FTransform HandleGroupTransform = bIsWorldSpaceGizmo == true && HandleGroup != RotationGizmoHandleGroup == true ? TransformGizmoToWorld : InLocalToWorld; bool bIsHoveringOrDraggingThisHandleGroup = false; + + const float Scale = HandleGroup == StretchGizmoHandleGroup ? GizmoScale : AnimatedGizmoScale; + HandleGroup->UpdateGizmoHandleGroup(InLocalToWorld, InLocalBounds, InViewLocation, bInAllHandlesVisible, DraggingHandle, - InHoveringOverHandles, AnimationAlpha, GizmoScale, InGizmoHoverScale, InGizmoHoverAnimationDuration, /* Out */ bIsHoveringOrDraggingThisHandleGroup); + InHoveringOverHandles, AnimationAlpha, Scale, InGizmoHoverScale, InGizmoHoverAnimationDuration, /* Out */ bIsHoveringOrDraggingThisHandleGroup); + if (HandleGroup != RotationGizmoHandleGroup) { @@ -175,6 +184,8 @@ UPivotTranslationGizmoHandleGroup::UPivotTranslationGizmoHandleGroup() : { const UViewportInteractionAssetContainer& AssetContainer = UViewportWorldInteraction::LoadAssetContainer(); CreateHandles( AssetContainer.TranslationHandleMesh, FString( "PivotTranslationHandle" ) ); + + DragOperationComponent->SetDragOperationClass(UTranslationDragOperation::StaticClass()); } @@ -191,11 +202,6 @@ void UPivotTranslationGizmoHandleGroup::UpdateGizmoHandleGroup( const FTransform UpdateHandlesRelativeTransformOnAxis( FTransform( FVector( VREd::PivotGizmoTranslationPivotOffsetX->GetFloat(), 0, 0 ) ), AnimationAlpha, MultipliedGizmoScale, MultipliedGizmoHoverScale, ViewLocation, DraggingHandle, HoveringOverHandles ); } -ETransformGizmoInteractionType UPivotTranslationGizmoHandleGroup::GetInteractionType() const -{ - return ETransformGizmoInteractionType::Translate; -} - EGizmoHandleTypes UPivotTranslationGizmoHandleGroup::GetHandleType() const { return EGizmoHandleTypes::Translate; @@ -209,6 +215,8 @@ UPivotScaleGizmoHandleGroup::UPivotScaleGizmoHandleGroup() : { const UViewportInteractionAssetContainer& AssetContainer = UViewportWorldInteraction::LoadAssetContainer(); CreateHandles( AssetContainer.UniformScaleHandleMesh, FString( "PivotScaleHandle" ) ); + + DragOperationComponent->SetDragOperationClass(UScaleDragOperation::StaticClass()); } void UPivotScaleGizmoHandleGroup::UpdateGizmoHandleGroup( const FTransform& LocalToWorld, const FBox& LocalBounds, const FVector ViewLocation, const bool bAllHandlesVisible, class UActorComponent* DraggingHandle, @@ -221,11 +229,6 @@ void UPivotScaleGizmoHandleGroup::UpdateGizmoHandleGroup( const FTransform& Loca UpdateHandlesRelativeTransformOnAxis( FTransform( FVector( VREd::PivotGizmoScalePivotOffsetX->GetFloat(), 0, 0 ) ), AnimationAlpha, GizmoScale, GizmoHoverScale, ViewLocation, DraggingHandle, HoveringOverHandles ); } -ETransformGizmoInteractionType UPivotScaleGizmoHandleGroup::GetInteractionType() const -{ - return ETransformGizmoInteractionType::Scale; -} - EGizmoHandleTypes UPivotScaleGizmoHandleGroup::GetHandleType() const { return EGizmoHandleTypes::Scale; @@ -244,6 +247,8 @@ UPivotPlaneTranslationGizmoHandleGroup::UPivotPlaneTranslationGizmoHandleGroup() { const UViewportInteractionAssetContainer& AssetContainer = UViewportWorldInteraction::LoadAssetContainer(); CreateHandles( AssetContainer.PlaneTranslationHandleMesh, FString( "PlaneTranslationHandle" ) ); + + DragOperationComponent->SetDragOperationClass(UPlaneTranslationDragOperation::StaticClass()); } void UPivotPlaneTranslationGizmoHandleGroup::UpdateGizmoHandleGroup( const FTransform& LocalToWorld, const FBox& LocalBounds, const FVector ViewLocation, const bool bAllHandlesVisible, class UActorComponent* DraggingHandle, @@ -257,11 +262,6 @@ void UPivotPlaneTranslationGizmoHandleGroup::UpdateGizmoHandleGroup( const FTran AnimationAlpha, GizmoScale, GizmoHoverScale, ViewLocation, DraggingHandle, HoveringOverHandles ); } -ETransformGizmoInteractionType UPivotPlaneTranslationGizmoHandleGroup::GetInteractionType() const -{ - return ETransformGizmoInteractionType::TranslateOnPlane; -} - EGizmoHandleTypes UPivotPlaneTranslationGizmoHandleGroup::GetHandleType() const { return EGizmoHandleTypes::Translate; @@ -328,6 +328,8 @@ UPivotRotationGizmoHandleGroup::UPivotRotationGizmoHandleGroup() : FullRotationHandleMeshComponent->SetMaterial(1, TranslucentDynamicMaterialInst); } + + DragOperationComponent->SetDragOperationClass(URotateOnAngleDragOperation::StaticClass()); } void UPivotRotationGizmoHandleGroup::UpdateGizmoHandleGroup( const FTransform& LocalToWorld, const FBox& LocalBounds, const FVector ViewLocation, const bool bAllHandlesVisible, class UActorComponent* DraggingHandle, @@ -373,14 +375,13 @@ void UPivotRotationGizmoHandleGroup::UpdateGizmoHandleGroup( const FTransform& L } // Set the root of the full rotation handles to the rotation we had when starting the drag. - if (CoordSystem == ECoordSystem::COORD_Local) - { - RootFullRotationHandleComponent->SetWorldRotation(StartDragRotation.GetValue()); - } + RootFullRotationHandleComponent->SetWorldRotation(StartDragRotation.GetValue()); FullRotationHandleMeshComponent->SetRelativeTransform(FTransform(GizmoSpaceFacingAxisVector.ToOrientationQuat(), FVector::ZeroVector, FVector(GizmoScale))); - const FVector LocalIntersectPoint = OwningTransformGizmoActor->GetOwnerWorldInteraction()->GetLocalIntersectPointOnRotationGizmo(); + URotateOnAngleDragOperation* DragOperation = StaticCast(GetDragOperationComponent()->GetDragOperation()); + const FVector LocalIntersectPoint = DragOperation->GetLocalIntersectPointOnRotationGizmo(); + UpdateIndicator(RootDeltaRotationIndicatorComponent, LocalIntersectPoint, FacingAxisIndex); // Update the start indicator only if this was the first time dragging @@ -458,11 +459,6 @@ void UPivotRotationGizmoHandleGroup::UpdateGizmoHandleGroup( const FTransform& L ShowRotationVisuals(bShowFullRotationDragHandle); } -ETransformGizmoInteractionType UPivotRotationGizmoHandleGroup::GetInteractionType() const -{ - return ETransformGizmoInteractionType::RotateOnAngle; -} - EGizmoHandleTypes UPivotRotationGizmoHandleGroup::GetHandleType() const { return EGizmoHandleTypes::Rotate; diff --git a/Engine/Source/Editor/ViewportInteraction/Gizmo/VIPivotTransformGizmo.h b/Engine/Source/Editor/ViewportInteraction/Gizmo/VIPivotTransformGizmo.h index 74e1d26c8d3d..25a88163b21f 100644 --- a/Engine/Source/Editor/ViewportInteraction/Gizmo/VIPivotTransformGizmo.h +++ b/Engine/Source/Editor/ViewportInteraction/Gizmo/VIPivotTransformGizmo.h @@ -78,9 +78,6 @@ public: virtual void UpdateGizmoHandleGroup( const FTransform& LocalToWorld, const FBox& LocalBounds, const FVector ViewLocation, const bool bAllHandlesVisible, class UActorComponent* DraggingHandle, const TArray< UActorComponent* >& HoveringOverHandles, float AnimationAlpha, float GizmoScale, const float GizmoHoverScale, const float GizmoHoverAnimationDuration, bool& bOutIsHoveringOrDraggingThisHandleGroup ) override; - /** Gets the InteractionType for this Gizmo handle */ - virtual ETransformGizmoInteractionType GetInteractionType() const override; - /** Gets the GizmoType for this Gizmo handle */ virtual EGizmoHandleTypes GetHandleType() const override; }; @@ -102,9 +99,6 @@ public: virtual void UpdateGizmoHandleGroup( const FTransform& LocalToWorld, const FBox& LocalBounds, const FVector ViewLocation, const bool bAllHandlesVisible, class UActorComponent* DraggingHandle, const TArray< UActorComponent* >& HoveringOverHandles, float AnimationAlpha, float GizmoScale, const float GizmoHoverScale, const float GizmoHoverAnimationDuration, bool& bOutIsHoveringOrDraggingThisHandleGroup ) override; - /** Gets the InteractionType for this Gizmo handle */ - virtual ETransformGizmoInteractionType GetInteractionType() const override; - /** Gets the GizmoType for this Gizmo handle */ virtual EGizmoHandleTypes GetHandleType() const override; @@ -129,9 +123,6 @@ public: virtual void UpdateGizmoHandleGroup( const FTransform& LocalToWorld, const FBox& LocalBounds, const FVector ViewLocation, const bool bAllHandlesVisible, class UActorComponent* DraggingHandle, const TArray< UActorComponent* >& HoveringOverHandles, float AnimationAlpha, float GizmoScale, const float GizmoHoverScale, const float GizmoHoverAnimationDuration, bool& bOutIsHoveringOrDraggingThisHandleGroup ) override; - /** Gets the InteractionType for this Gizmo handle */ - virtual ETransformGizmoInteractionType GetInteractionType() const override; - /** Gets the GizmoType for this Gizmo handle */ virtual EGizmoHandleTypes GetHandleType() const override; }; @@ -154,9 +145,6 @@ public: virtual void UpdateGizmoHandleGroup(const FTransform& LocalToWorld, const FBox& LocalBounds, const FVector ViewLocation, const bool bAllHandlesVisible, class UActorComponent* DraggingHandle, const TArray< UActorComponent* >& HoveringOverHandles, float AnimationAlpha, float GizmoScale, const float GizmoHoverScale, const float GizmoHoverAnimationDuration, bool& bOutIsHoveringOrDraggingThisHandleGroup ) override; - /** Gets the InteractionType for this Gizmo handle */ - virtual ETransformGizmoInteractionType GetInteractionType() const override; - /** Gets the GizmoType for this Gizmo handle */ virtual EGizmoHandleTypes GetHandleType() const override; diff --git a/Engine/Source/Editor/ViewportInteraction/Gizmo/VIStretchGizmoHandle.cpp b/Engine/Source/Editor/ViewportInteraction/Gizmo/VIStretchGizmoHandle.cpp index ab399a0fe9ae..2631b18acb23 100644 --- a/Engine/Source/Editor/ViewportInteraction/Gizmo/VIStretchGizmoHandle.cpp +++ b/Engine/Source/Editor/ViewportInteraction/Gizmo/VIStretchGizmoHandle.cpp @@ -5,13 +5,14 @@ #include "Components/StaticMeshComponent.h" #include "Engine/StaticMesh.h" #include "VIBaseTransformGizmo.h" +#include "ViewportInteractionDragOperations.h" UStretchGizmoHandleGroup::UStretchGizmoHandleGroup() : Super() { UStaticMesh* StretchingHandleMesh = nullptr; { - static ConstructorHelpers::FObjectFinder ObjectFinder( TEXT( "/Engine/VREditor/TransformGizmo/StretchingHandle" ) ); + static ConstructorHelpers::FObjectFinder ObjectFinder( TEXT( "/Engine/VREditor/TransformGizmo/PlaneTranslationHandle" ) ); StretchingHandleMesh = ObjectFinder.Object; check( StretchingHandleMesh != nullptr ); } @@ -74,6 +75,8 @@ UStretchGizmoHandleGroup::UStretchGizmoHandleGroup() } } } + + DragOperationComponent->SetDragOperationClass(UStretchGizmoHandleDragOperation::StaticClass()); } void UStretchGizmoHandleGroup::UpdateGizmoHandleGroup( const FTransform& LocalToWorld, const FBox& LocalBounds, const FVector ViewLocation, const bool bAllHandlesVisible, class UActorComponent* DraggingHandle, const TArray< UActorComponent* >& HoveringOverHandles, @@ -235,11 +238,6 @@ void UStretchGizmoHandleGroup::UpdateGizmoHandleGroup( const FTransform& LocalTo } } -ETransformGizmoInteractionType UStretchGizmoHandleGroup::GetInteractionType() const -{ - return ETransformGizmoInteractionType::StretchAndReposition; -} - EGizmoHandleTypes UStretchGizmoHandleGroup::GetHandleType() const { return EGizmoHandleTypes::Scale; @@ -250,3 +248,68 @@ bool UStretchGizmoHandleGroup::SupportsWorldCoordinateSpace() const // Stretching only works with local space gizmos return false; } + +void UStretchGizmoHandleDragOperation::ExecuteDrag(FDraggingTransformableData& DraggingData) +{ + // We only support stretching by a handle currently + const FTransformGizmoHandlePlacement& HandlePlacement = DraggingData.OptionalHandlePlacement.GetValue(); + + const FVector PassGizmoSpaceDraggedTo = DraggingData.GizmoStartTransform.InverseTransformPositionNoScale(DraggingData.PassDraggedTo); + + FBox NewGizmoLocalBounds = DraggingData.GizmoStartLocalBounds; + FVector GizmoSpacePivotLocation = FVector::ZeroVector; + for (int32 AxisIndex = 0; AxisIndex < 3; ++AxisIndex) + { + // Figure out how much the gizmo bounds changes + if (HandlePlacement.Axes[AxisIndex] == ETransformGizmoHandleDirection::Negative) // Negative direction + { + GizmoSpacePivotLocation[AxisIndex] = DraggingData.GizmoStartLocalBounds.Max[AxisIndex]; + NewGizmoLocalBounds.Min[AxisIndex] = DraggingData.GizmoStartLocalBounds.Min[AxisIndex] + PassGizmoSpaceDraggedTo[AxisIndex]; + + } + else if (HandlePlacement.Axes[AxisIndex] == ETransformGizmoHandleDirection::Positive) // Positive direction + { + GizmoSpacePivotLocation[AxisIndex] = DraggingData.GizmoStartLocalBounds.Min[AxisIndex]; + NewGizmoLocalBounds.Max[AxisIndex] = DraggingData.GizmoStartLocalBounds.Max[AxisIndex] + PassGizmoSpaceDraggedTo[AxisIndex]; + } + else + { + // Must be ETransformGizmoHandleDirection::Center. + GizmoSpacePivotLocation[AxisIndex] = DraggingData.GizmoStartLocalBounds.GetCenter()[AxisIndex]; + } + } + + const FVector GizmoStartLocalSize = DraggingData.GizmoStartLocalBounds.GetSize(); + const FVector NewGizmoLocalSize = NewGizmoLocalBounds.GetSize(); + + FVector NewGizmoLocalScaleFromStart = FVector(1.0f); + for (int32 AxisIndex = 0; AxisIndex < 3; ++AxisIndex) + { + if (!FMath::IsNearlyZero(GizmoStartLocalSize[AxisIndex])) + { + NewGizmoLocalScaleFromStart[AxisIndex] = NewGizmoLocalSize[AxisIndex] / GizmoStartLocalSize[AxisIndex]; + } + else + { + // Zero scale. This is allowed in Unreal, for better or worse. + NewGizmoLocalScaleFromStart[AxisIndex] = 0.0f; + } + } + + // Stretch and reposition the gizmo! + { + FTransform& PassGizmoTargetTransform = DraggingData.bIsUpdatingUnsnappedTarget ? DraggingData.OutGizmoUnsnappedTargetTransform : DraggingData.OutGizmoTargetTransform; + + { + const FVector GizmoSpaceTransformableStartLocation = DraggingData.GizmoStartTransform.InverseTransformPositionNoScale(DraggingData.GizmoStartTransform.GetLocation()); + const FVector NewGizmoSpaceLocation = (GizmoSpaceTransformableStartLocation - GizmoSpacePivotLocation) * NewGizmoLocalScaleFromStart + GizmoSpacePivotLocation; + PassGizmoTargetTransform.SetLocation(DraggingData.GizmoStartTransform.TransformPosition(NewGizmoSpaceLocation)); + } + + // @todo vreditor: This scale is still in gizmo space, but we're setting it in world space + PassGizmoTargetTransform.SetScale3D(DraggingData.GizmoStartTransform.GetScale3D() * NewGizmoLocalScaleFromStart); + + DraggingData.bOutMovedTransformGizmo = true; + DraggingData.bOutShouldApplyVelocitiesFromDrag = false; + } +} diff --git a/Engine/Source/Editor/ViewportInteraction/Gizmo/VIUniformScaleGizmoHandle.cpp b/Engine/Source/Editor/ViewportInteraction/Gizmo/VIUniformScaleGizmoHandle.cpp index 314dfd94b319..ea4a80387438 100644 --- a/Engine/Source/Editor/ViewportInteraction/Gizmo/VIUniformScaleGizmoHandle.cpp +++ b/Engine/Source/Editor/ViewportInteraction/Gizmo/VIUniformScaleGizmoHandle.cpp @@ -7,6 +7,7 @@ #include "Materials/MaterialInstanceDynamic.h" #include "VIBaseTransformGizmo.h" #include "ViewportWorldInteraction.h" +#include "ViewportInteractionDragOperations.h" UUniformScaleGizmoHandleGroup::UUniformScaleGizmoHandleGroup() : Super(), @@ -25,6 +26,8 @@ UUniformScaleGizmoHandleGroup::UUniformScaleGizmoHandleGroup() FGizmoHandle& NewHandle = *new( Handles ) FGizmoHandle(); NewHandle.HandleMesh = UniformScaleHandle; + + DragOperationComponent->SetDragOperationClass(UUniformScaleDragOperation::StaticClass()); } void UUniformScaleGizmoHandleGroup::UpdateGizmoHandleGroup( const FTransform& LocalToWorld, const FBox& LocalBounds, const FVector ViewLocation, const bool bAllHandlesVisible, class UActorComponent* DraggingHandle, const TArray< UActorComponent* >& HoveringOverHandles, @@ -90,11 +93,6 @@ void UUniformScaleGizmoHandleGroup::UpdateGizmoHandleGroup( const FTransform& Lo } } -ETransformGizmoInteractionType UUniformScaleGizmoHandleGroup::GetInteractionType() const -{ - return ETransformGizmoInteractionType::UniformScale; -} - EGizmoHandleTypes UUniformScaleGizmoHandleGroup::GetHandleType() const { return EGizmoHandleTypes::Scale; diff --git a/Engine/Source/Editor/ViewportInteraction/MouseCursorInteractor.cpp b/Engine/Source/Editor/ViewportInteraction/MouseCursorInteractor.cpp index 6b19f163fadc..c3d9b3c422c8 100644 --- a/Engine/Source/Editor/ViewportInteraction/MouseCursorInteractor.cpp +++ b/Engine/Source/Editor/ViewportInteraction/MouseCursorInteractor.cpp @@ -7,8 +7,8 @@ #include "Editor.h" -UMouseCursorInteractor::UMouseCursorInteractor( const FObjectInitializer& Initializer ) - : UViewportInteractor( Initializer ) +UMouseCursorInteractor::UMouseCursorInteractor() + : UViewportInteractor() { // Grabber spheres don't really work well with mouse cursor interactors, because the origin of the // interactor is right on the near view plane. diff --git a/Engine/Source/Editor/ViewportInteraction/OneEuroFilter.tps b/Engine/Source/Editor/ViewportInteraction/OneEuroFilter.tps index cdd2cd1d2a06..217eaae2ba58 100644 --- a/Engine/Source/Editor/ViewportInteraction/OneEuroFilter.tps +++ b/Engine/Source/Editor/ViewportInteraction/OneEuroFilter.tps @@ -11,5 +11,5 @@ Git P4 - + None \ No newline at end of file diff --git a/Engine/Source/Editor/ViewportInteraction/Public/IViewportInteractionModule.h b/Engine/Source/Editor/ViewportInteraction/Public/IViewportInteractionModule.h index 986ae59125a3..4bdb1d94f409 100644 --- a/Engine/Source/Editor/ViewportInteraction/Public/IViewportInteractionModule.h +++ b/Engine/Source/Editor/ViewportInteraction/Public/IViewportInteractionModule.h @@ -34,10 +34,5 @@ public: { return FModuleManager::Get().IsModuleLoaded( "ViewportInteraction" ); } - - /** - * @return The ViewportWorldInteractionManager that owns entering and exiting the ViewportWorldInteraction - */ - virtual class FViewportWorldInteractionManager& GetWorldInteractionManager() = 0; }; diff --git a/Engine/Source/Editor/ViewportInteraction/Public/IViewportWorldInteractionManager.h b/Engine/Source/Editor/ViewportInteraction/Public/IViewportWorldInteractionManager.h deleted file mode 100644 index 43583e010625..000000000000 --- a/Engine/Source/Editor/ViewportInteraction/Public/IViewportWorldInteractionManager.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "CoreMinimal.h" - -class IViewportWorldInteractionManager -{ -public: - - /** - * Sets the current ViewportWorldInteraction - * - * @param UViewportWorldInteraction the next ViewportWorldInteraction used - */ - virtual void SetCurrentViewportWorldInteraction( class UViewportWorldInteraction* /*WorldInteraction*/ ) = 0; - -}; diff --git a/Engine/Source/Editor/ViewportInteraction/Public/MouseCursorInteractor.h b/Engine/Source/Editor/ViewportInteraction/Public/MouseCursorInteractor.h index bd6d67ac350c..ce15338071e6 100644 --- a/Engine/Source/Editor/ViewportInteraction/Public/MouseCursorInteractor.h +++ b/Engine/Source/Editor/ViewportInteraction/Public/MouseCursorInteractor.h @@ -13,10 +13,13 @@ UCLASS() class VIEWPORTINTERACTION_API UMouseCursorInteractor : public UViewportInteractor { - GENERATED_UCLASS_BODY() + GENERATED_BODY() public: + /** Default constructor. */ + UMouseCursorInteractor(); + /** Initialize default values */ void Init(); diff --git a/Engine/Source/Editor/ViewportInteraction/Public/VIBaseTransformGizmo.h b/Engine/Source/Editor/ViewportInteraction/Public/VIBaseTransformGizmo.h index 2ae1f272cd32..72eb0847e82c 100644 --- a/Engine/Source/Editor/ViewportInteraction/Public/VIBaseTransformGizmo.h +++ b/Engine/Source/Editor/ViewportInteraction/Public/VIBaseTransformGizmo.h @@ -28,8 +28,8 @@ struct FTransformGizmoMeasurement { GENERATED_BODY() - /** The text that displays the actual measurement and units */ - UPROPERTY() + /** The text that displays the actual measurement and units */ + UPROPERTY() class UTextRenderComponent* MeasurementText; }; @@ -47,9 +47,6 @@ public: /** Default constructor that sets up CDO properties */ ABaseTransformGizmo(); - /** Deconstructor */ - virtual ~ABaseTransformGizmo(); - //~ Begin AActor interface virtual bool IsEditorOnly() const final { @@ -63,7 +60,7 @@ public: /** Called by the world interaction system when one of our components is dragged by the user to find out what type of interaction to do. If null is passed in then we'll treat it as dragging the whole object (rather than a specific axis/handle) */ - ETransformGizmoInteractionType GetInteractionType( UActorComponent* DraggedComponent, TOptional& OutHandlePlacement ); + class UViewportDragOperationComponent* GetInteractionType( UActorComponent* DraggedComponent, TOptional& OutHandlePlacement ); /** Updates the animation with the current time and selected time */ float GetAnimationAlpha(); @@ -102,14 +99,6 @@ protected: UPROPERTY() USceneComponent* SceneComponent; - /** Gizmo material (opaque) */ - UPROPERTY() - UMaterialInterface* GizmoMaterial; - - /** Gizmo material (translucent) */ - UPROPERTY() - UMaterialInterface* TranslucentGizmoMaterial; - /** All gizmo components */ UPROPERTY() TArray< class UGizmoHandleGroup* > AllHandleGroups; diff --git a/Engine/Source/Editor/ViewportInteraction/Public/VIGizmoHandle.h b/Engine/Source/Editor/ViewportInteraction/Public/VIGizmoHandle.h index 630712caa9b0..b398a277ffa0 100644 --- a/Engine/Source/Editor/ViewportInteraction/Public/VIGizmoHandle.h +++ b/Engine/Source/Editor/ViewportInteraction/Public/VIGizmoHandle.h @@ -40,9 +40,6 @@ public: /** Default constructor that sets up CDO properties */ UGizmoHandleGroup(); - /** Deconstructor */ - virtual ~UGizmoHandleGroup(); - /** Given the unique index, makes a handle */ FTransformGizmoHandlePlacement MakeHandlePlacementForIndex( const int32 HandleIndex ) const; @@ -62,11 +59,7 @@ public: /** Default setting the visibility and collision for all the handles in this group */ void UpdateVisibilityAndCollision(const EGizmoHandleTypes GizmoType, const ECoordSystem GizmoCoordinateSpace, const bool bAllHandlesVisible, const bool bAllowRotationAndScaleHandles, UActorComponent* DraggingHandle); - /** Gets the InteractionType and the HandlePlacement for this Gizmo handle */ - virtual void GetHandleIndexInteractionType( const int32 HandleIndex, ETransformGizmoInteractionType& OutInteractionType, TOptional& OutHandlePlacement ); - - /** Gets the Gizmo InteractionType, needs to be implemented by derived classes */ - virtual ETransformGizmoInteractionType GetInteractionType() const; + class UViewportDragOperationComponent* GetDragOperationComponent(); /** Finds the index of DraggedMesh in HandleMeshes */ virtual int32 GetDraggedHandleIndex( class UStaticMeshComponent* DraggedMesh ); @@ -130,6 +123,9 @@ protected: UPROPERTY() class ABaseTransformGizmo* OwningTransformGizmoActor; + UPROPERTY() + class UViewportDragOperationComponent* DragOperationComponent; + private: /** Updates the hover animation for the HoveringOverHandles */ diff --git a/Engine/Source/Editor/ViewportInteraction/Public/VIStretchGizmoHandle.h b/Engine/Source/Editor/ViewportInteraction/Public/VIStretchGizmoHandle.h index ee36c255a67f..60641b0fb5ba 100644 --- a/Engine/Source/Editor/ViewportInteraction/Public/VIStretchGizmoHandle.h +++ b/Engine/Source/Editor/ViewportInteraction/Public/VIStretchGizmoHandle.h @@ -5,6 +5,7 @@ #include "CoreMinimal.h" #include "UObject/ObjectMacros.h" #include "VIGizmoHandle.h" +#include "ViewportDragOperation.h" #include "VIStretchGizmoHandle.generated.h" enum class EGizmoHandleTypes : uint8; @@ -26,12 +27,20 @@ public: virtual void UpdateGizmoHandleGroup( const FTransform& LocalToWorld, const FBox& LocalBounds, const FVector ViewLocation, const bool bAllHandlesVisible, class UActorComponent* DraggingHandle, const TArray< UActorComponent* >& HoveringOverHandles, float AnimationAlpha, float GizmoScale, const float GizmoHoverScale, const float GizmoHoverAnimationDuration, bool& bOutIsHoveringOrDraggingThisHandleGroup ) override; - /** Gets the InteractionType for this Gizmo handle */ - virtual ETransformGizmoInteractionType GetInteractionType() const override; - /** Gets the GizmoType for this Gizmo handle */ virtual EGizmoHandleTypes GetHandleType() const override; /** Returns true if this type of handle is allowed with world space gizmos */ virtual bool SupportsWorldCoordinateSpace() const override; }; + +UCLASS() +class UStretchGizmoHandleDragOperation : public UViewportDragOperation +{ + GENERATED_BODY() + +public: + + // IViewportDragOperation + virtual void ExecuteDrag(struct FDraggingTransformableData& DraggingData) override; +}; diff --git a/Engine/Source/Editor/ViewportInteraction/Public/VIUniformScaleGizmoHandle.h b/Engine/Source/Editor/ViewportInteraction/Public/VIUniformScaleGizmoHandle.h index 073115dd115c..16fa1f1bf99c 100644 --- a/Engine/Source/Editor/ViewportInteraction/Public/VIUniformScaleGizmoHandle.h +++ b/Engine/Source/Editor/ViewportInteraction/Public/VIUniformScaleGizmoHandle.h @@ -26,9 +26,6 @@ public: virtual void UpdateGizmoHandleGroup( const FTransform& LocalToWorld, const FBox& LocalBounds, const FVector ViewLocation, const bool bAllHandlesVisible, class UActorComponent* DraggingHandle, const TArray< UActorComponent* >& HoveringOverHandles, float AnimationAlpha, float GizmoScale, const float GizmoHoverScale, const float GizmoHoverAnimationDuration, bool& bOutIsHoveringOrDraggingThisHandleGroup ) override; - /** Gets the InteractionType for this Gizmo handle */ - virtual ETransformGizmoInteractionType GetInteractionType() const override; - /** Gets the GizmoType for this Gizmo handle */ virtual EGizmoHandleTypes GetHandleType() const override; diff --git a/Engine/Source/Editor/ViewportInteraction/Public/ViewportDragOperation.h b/Engine/Source/Editor/ViewportInteraction/Public/ViewportDragOperation.h index 3d4f3c71ca64..0f79692044c4 100644 --- a/Engine/Source/Editor/ViewportInteraction/Public/ViewportDragOperation.h +++ b/Engine/Source/Editor/ViewportInteraction/Public/ViewportDragOperation.h @@ -7,6 +7,8 @@ #include "UObject/Object.h" #include "Templates/SubclassOf.h" #include "Components/ActorComponent.h" +#include "ViewportInteractionTypes.h" +#include "UnrealWidget.h" #include "ViewportDragOperation.generated.h" /** @@ -25,20 +27,33 @@ public: * @param UViewportInteractor - The interactor causing the dragging * @param IViewportInteractableInterface - The interactable owning this drag operation */ - virtual void ExecuteDrag( class UViewportInteractor* Interactor, class IViewportInteractableInterface* Interactable ) PURE_VIRTUAL( UViewportDragOperation::ExecuteDrag, ); + virtual void ExecuteDrag(class UViewportInteractor* Interactor, class IViewportInteractableInterface* Interactable){}; + + /** + * Execute dragging + * + * @param UViewportInteractor - The interactor causing the dragging + * @param IViewportInteractableInterface - The interactable owning this drag operation + */ + virtual void ExecuteDrag(struct FDraggingTransformableData& DraggingData){}; + + /** @todo ViewportInteraction: Temporary way to check if a drag operation needs to constrain the drag delta on a plane of a gizmo axis. */ + bool bPlaneConstraint; }; + /** * Container component for UViewportDragOperation that can be used by objects in the world that are draggable and implement the ViewportInteractableInterface */ UCLASS() class VIEWPORTINTERACTION_API UViewportDragOperationComponent : public UActorComponent { - GENERATED_UCLASS_BODY() + GENERATED_BODY() public: - /** Destructor */ - ~UViewportDragOperationComponent(); + + /** Default constructor. */ + UViewportDragOperationComponent(); /** Get the actual dragging operation */ UViewportDragOperation* GetDragOperation(); @@ -65,3 +80,64 @@ private: UPROPERTY() TSubclassOf DragOperationSubclass; }; + +/** + * Data structure that holds all arguments that can be used while dragging a transformable. + */ +USTRUCT() +struct VIEWPORTINTERACTION_API FDraggingTransformableData +{ + GENERATED_BODY() + + FDraggingTransformableData() : + Interactor(nullptr), + WorldInteraction(nullptr), + bIsUpdatingUnsnappedTarget(false), + PassDraggedTo(FVector::ZeroVector), + OptionalHandlePlacement(), + DragDelta(FVector::ZeroVector), + ConstrainedDragDelta(FVector::ZeroVector), + OtherHandDragDelta(FVector::ZeroVector), + DraggedTo(FVector::ZeroVector), + OtherHandDraggedTo(FVector::ZeroVector), + DragDeltaFromStart(FVector::ZeroVector), + OtherHandDragDeltaFromStart(FVector::ZeroVector), + LaserPointerStart(FVector::ZeroVector), + LaserPointerDirection(FVector::ZeroVector), + GizmoStartTransform(FTransform::Identity), + GizmoLastTransform(FTransform::Identity), + OutGizmoTargetTransform(FTransform::Identity), + OutGizmoUnsnappedTargetTransform(FTransform::Identity), + GizmoStartLocalBounds(EForceInit::ForceInitToZero), + GizmoCoordinateSpace(ECoordSystem::COORD_World), + bOutMovedTransformGizmo(false), + bOutShouldApplyVelocitiesFromDrag(false), + OutUnsnappedDraggedTo(FVector::ZeroVector) + {} + + class UViewportInteractor* Interactor; + class UViewportWorldInteraction* WorldInteraction; + + bool bIsUpdatingUnsnappedTarget; + FVector PassDraggedTo; + TOptional OptionalHandlePlacement; + FVector DragDelta; + FVector ConstrainedDragDelta; + FVector OtherHandDragDelta; + FVector DraggedTo; + FVector OtherHandDraggedTo; + FVector DragDeltaFromStart; + FVector OtherHandDragDeltaFromStart; + FVector LaserPointerStart; + FVector LaserPointerDirection; + FTransform GizmoStartTransform; + FTransform GizmoLastTransform; + FTransform OutGizmoTargetTransform; + FTransform OutGizmoUnsnappedTargetTransform; + FBox GizmoStartLocalBounds; + ECoordSystem GizmoCoordinateSpace; + + bool bOutMovedTransformGizmo; + bool bOutShouldApplyVelocitiesFromDrag; + FVector OutUnsnappedDraggedTo; +}; diff --git a/Engine/Source/Editor/ViewportInteraction/Public/ViewportInteractionAssetContainer.h b/Engine/Source/Editor/ViewportInteraction/Public/ViewportInteractionAssetContainer.h index 99a9cbcd4e0e..a0df215634fa 100644 --- a/Engine/Source/Editor/ViewportInteraction/Public/ViewportInteractionAssetContainer.h +++ b/Engine/Source/Editor/ViewportInteraction/Public/ViewportInteractionAssetContainer.h @@ -6,7 +6,9 @@ #include "ViewportInteractionAssetContainer.generated.h" // Forward declarations +class UMaterialInterface; class USoundBase; +class UStaticMesh; /** * Asset container for viewport interaction. @@ -80,6 +82,8 @@ public: UPROPERTY(EditAnywhere, Category = Mesh) UStaticMesh* CurrentRotationIndicatorMesh; + UPROPERTY(EditAnywhere, Category = Mesh) + UStaticMesh* FreeRotationHandleMesh; // // Materials diff --git a/Engine/Source/Editor/ViewportInteraction/Public/ViewportInteractionDragOperations.h b/Engine/Source/Editor/ViewportInteraction/Public/ViewportInteractionDragOperations.h new file mode 100644 index 000000000000..c561dbd99d78 --- /dev/null +++ b/Engine/Source/Editor/ViewportInteraction/Public/ViewportInteractionDragOperations.h @@ -0,0 +1,86 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "UObject/Object.h" +#include "ViewportDragOperation.h" +#include "ViewportInteractionDragOperations.generated.h" + +/** + * Gizmo translation on one axis. + */ +UCLASS() +class VIEWPORTINTERACTION_API UTranslationDragOperation : public UViewportDragOperation +{ + GENERATED_BODY() + +public: + virtual void ExecuteDrag(struct FDraggingTransformableData& DraggingData) override; +}; + +/** + * Gizmo translation on two axes. + */ +UCLASS() +class VIEWPORTINTERACTION_API UPlaneTranslationDragOperation: public UViewportDragOperation +{ + GENERATED_BODY() + +public: + UPlaneTranslationDragOperation(); + virtual void ExecuteDrag(struct FDraggingTransformableData& DraggingData) override; +}; + +/** + * Rotation around one axis based on input angle. + */ +UCLASS() +class VIEWPORTINTERACTION_API URotateOnAngleDragOperation: public UViewportDragOperation +{ + GENERATED_BODY() + +public: + URotateOnAngleDragOperation(); + + virtual void ExecuteDrag(struct FDraggingTransformableData& DraggingData) override; + + /** When RotateOnAngle we intersect on a plane to rotate the transform gizmo. This is the local point from the transform gizmo location of that intersect */ + FVector GetLocalIntersectPointOnRotationGizmo() const; + +private: + + /** Starting angle when rotating an object with ETransformGizmoInteractionType::RotateOnAngle */ + TOptional StartDragAngleOnRotation; + + /** The direction of where the rotation handle is facing when starting rotation */ + TOptional DraggingRotationHandleDirection; + + /** Where the laser intersected on the gizmo rotation aligned plane. */ + FVector LocalIntersectPointOnRotationGizmo; +}; + +/** + * Scale on one axis. + */ +UCLASS() +class VIEWPORTINTERACTION_API UScaleDragOperation : public UViewportDragOperation +{ + GENERATED_BODY() + +public: + virtual void ExecuteDrag(struct FDraggingTransformableData& DraggingData) override; +}; + +/** + * Scale on all axes. + */ +UCLASS() +class VIEWPORTINTERACTION_API UUniformScaleDragOperation : public UViewportDragOperation +{ + GENERATED_BODY() + +public: + virtual void ExecuteDrag(struct FDraggingTransformableData& DraggingData) override; +}; diff --git a/Engine/Source/Editor/ViewportInteraction/Public/ViewportInteractionTypes.h b/Engine/Source/Editor/ViewportInteraction/Public/ViewportInteractionTypes.h index 616d935c5071..066f7e970665 100644 --- a/Engine/Source/Editor/ViewportInteraction/Public/ViewportInteractionTypes.h +++ b/Engine/Source/Editor/ViewportInteraction/Public/ViewportInteractionTypes.h @@ -66,38 +66,6 @@ enum class EViewportInteractionDraggingMode : uint8 Material }; -/** -* Things the transform gizmo can do to objects -*/ -UENUM() -enum class ETransformGizmoInteractionType : uint8 -{ - /** No interaction */ - None, - - /** Translate the object(s), either in any direction or confined to one axis. No rotation. */ - Translate, - - /** Translate the object, constrained to a plane. No rotation. */ - TranslateOnPlane, - - /** Stretch the object non-uniformly while simultaneously repositioning it so account for it's new size */ - StretchAndReposition, - - /** Scaling the object non-uniformly while */ - Scale, - - /** Rotate the object(s) around a specific axis relative to the gizmo's pivot, translating as needed */ - Rotate, - - /** Rotate the object(s) around the pivot based on start angle */ - RotateOnAngle, - - /** Uniform scale the object(s) */ - UniformScale, -}; - - /* Directions that a transform handle can face along any given axis */ enum class ETransformGizmoHandleDirection { @@ -123,4 +91,4 @@ struct VIEWPORTINTERACTION_API FTransformGizmoHandlePlacement The center axis index is valid for edges, and defines the axis perpendicular to that edge direction, or INDEX_NONE if it's not an edge */ void GetCenterHandleCountAndFacingAxisIndex( int32& OutCenterHandleCount, int32& OutFacingAxisIndex, int32& OutCenterAxisIndex ) const; -}; +}; \ No newline at end of file diff --git a/Engine/Source/Editor/ViewportInteraction/Public/ViewportInteractor.h b/Engine/Source/Editor/ViewportInteraction/Public/ViewportInteractor.h index 0593c007e523..45311a091876 100644 --- a/Engine/Source/Editor/ViewportInteraction/Public/ViewportInteractor.h +++ b/Engine/Source/Editor/ViewportInteraction/Public/ViewportInteractor.h @@ -20,10 +20,13 @@ class AActor; UCLASS( ABSTRACT ) class VIEWPORTINTERACTION_API UViewportInteractor : public UObject { - GENERATED_UCLASS_BODY() + GENERATED_BODY() public: + /** Default constructor */ + UViewportInteractor(); + /** Gets the private data for this interactor */ struct FViewportInteractorData& GetInteractorData(); diff --git a/Engine/Source/Editor/ViewportInteraction/Public/ViewportWorldInteraction.h b/Engine/Source/Editor/ViewportInteraction/Public/ViewportWorldInteraction.h index 6a268d4a96ac..19b725493deb 100644 --- a/Engine/Source/Editor/ViewportInteraction/Public/ViewportWorldInteraction.h +++ b/Engine/Source/Editor/ViewportInteraction/Public/ViewportWorldInteraction.h @@ -261,7 +261,7 @@ public: void SetLastDragGizmoStartTransform( const FTransform NewLastDragGizmoStartTransform ); /** Gets all the interactors */ - TArray& GetInteractors(); + const TArray& GetInteractors() const; /** Given a world space velocity vector, applies inertial damping to it to slow it down */ void ApplyVelocityDamping( FVector& Velocity, const bool bVelocitySensitive ); @@ -300,7 +300,7 @@ public: } /** The ability to move and scale the world */ - void AllowWorldMovement(bool bDisable); + void AllowWorldMovement(bool bAllow); /** For other systems to check if the Viewport World Interaction system is currently aligning transformables to actors*/ bool AreAligningToActors(); @@ -309,9 +309,6 @@ public: /** If there are no currently selected candidates, use the currently selected actors as candidates. Otherwise, reset the candidates */ void SetSelectionAsCandidates(); - /** When RotateOnAngle we intersect on a plane to rotate the transform gizmo. This is the local point from the transform gizmo location of that intersect */ - FVector GetLocalIntersectPointOnRotationGizmo() const; - /** Gets the current delta time, so functions that don't get the delta time passed can still get it */ float GetCurrentDeltaTime() const; @@ -337,11 +334,13 @@ public: /** Get if this world interaction is in VR. */ bool IsInVR() const; + FVector SnapLocation(const bool bLocalSpaceSnapping, const FVector& DesiredGizmoLocation, const FTransform &GizmoStartTransform, const FVector SnapGridBase, const bool bShouldConstrainMovement, const FVector AlignAxes); + protected: virtual void TransitionWorld(UWorld* NewWorld) override; virtual void EnteredSimulateInEditor() override; - virtual void LeftSimulateInEditor() override; + virtual void LeftSimulateInEditor(UWorld* SimulateWorld) override; private: @@ -356,24 +355,25 @@ private: /** Called by the world interaction system when one of our components is dragged by the user. If null is passed in then we'll treat it as dragging the whole object (rather than a specific axis/handle) */ - void UpdateDragging( + void UpdateDragging( const float DeltaTime, - bool& bIsFirstDragUpdate, - const EViewportInteractionDraggingMode DraggingMode, - const ETransformGizmoInteractionType InteractionType, - const bool bWithTwoHands, - const TOptional OptionalHandlePlacement, - const FVector& DragDelta, - const FVector& OtherHandDragDelta, - const FVector& DraggedTo, - const FVector& OtherHandDraggedTo, - const FVector& DragDeltaFromStart, - const FVector& OtherHandDragDeltaFromStart, - const FVector& LaserPointerStart, - const FVector& LaserPointerDirection, + bool& bIsFirstDragUpdate, + UViewportInteractor* Interactor, + const EViewportInteractionDraggingMode DraggingMode, + class UViewportDragOperation* DragOperation, + const bool bWithTwoHands, + const TOptional OptionalHandlePlacement, + const FVector& DragDelta, + const FVector& OtherHandDragDelta, + const FVector& DraggedTo, + const FVector& OtherHandDraggedTo, + const FVector& DragDeltaFromStart, + const FVector& OtherHandDragDeltaFromStart, + const FVector& LaserPointerStart, + const FVector& LaserPointerDirection, const float LaserPointerMaxLength, - const bool bIsLaserPointerValid, - const FTransform& GizmoStartTransform, + const bool bIsLaserPointerValid, + const FTransform& GizmoStartTransform, FTransform& GizmoLastTransform, FTransform& GizmoTargetTransform, FTransform& GizmoUnsnappedTargetTransform, @@ -385,21 +385,18 @@ private: bool& bIsDrivingVelocityOfSimulatedTransformables, FVector& OutUnsnappedDraggedTo); - FVector SnapLocation(const bool bLocalSpaceSnapping, const FVector& DesiredGizmoLocation, const FTransform &GizmoStartTransform, const FVector SnapGridBase, const bool bShouldConstrainMovement, const FVector AlignAxes); - - /** Given a drag delta from a starting point, contrains that delta based on a gizmo handle axis */ - FVector ComputeConstrainedDragDeltaFromStart( - const bool bIsFirstDragUpdate, - const ETransformGizmoInteractionType InteractionType, - const TOptional OptionalHandlePlacement, - const FVector& DragDeltaFromStart, - const FVector& LaserPointerStart, - const FVector& LaserPointerDirection, - const bool bIsLaserPointerValid, - const FTransform& GizmoStartTransform, - const float LaserPointerMaxLength, - FVector& GizmoSpaceFirstDragUpdateOffsetAlongAxis, + FVector ComputeConstrainedDragDeltaFromStart( + const bool bIsFirstDragUpdate, + const bool bOnPlane, + const TOptional OptionalHandlePlacement, + const FVector& DragDeltaFromStart, + const FVector& LaserPointerStart, + const FVector& LaserPointerDirection, + const bool bIsLaserPointerValid, + const FTransform& GizmoStartTransform, + const float LaserPointerMaxLength, + FVector& GizmoSpaceFirstDragUpdateOffsetAlongAxis, FVector& DragDeltaFromStartOffset, FVector& OutClosestPointOnLaser) const; @@ -584,14 +581,6 @@ private: /** Current gizmo bounds in local space. Updated every frame. This is not the same as the gizmo actor's bounds. */ FBox GizmoLocalBounds; - /** Starting angle when rotating an object with ETransformGizmoInteractionType::RotateOnAngle */ - TOptional StartDragAngleOnRotation; - - FVector LocalIntersectPointOnRotationGizmo; - - /** The direction of where the rotation handle is facing when starting rotation */ - TOptional DraggingRotationHandleDirection; - /** Whether the gizmo should be visible or not */ bool bShouldTransformGizmoBeVisible; @@ -715,4 +704,7 @@ private: /** If we want to skip playing the sound when refreshing the transform gizmo next time */ bool bPlayNextRefreshTransformGizmoSound; + + /** Slate Input Processor */ + TSharedPtr InputProcessor; }; diff --git a/Engine/Source/Editor/ViewportInteraction/ViewportDragOperation.cpp b/Engine/Source/Editor/ViewportInteraction/ViewportDragOperation.cpp index 33055111a46f..99222d5553d1 100644 --- a/Engine/Source/Editor/ViewportInteraction/ViewportDragOperation.cpp +++ b/Engine/Source/Editor/ViewportInteraction/ViewportDragOperation.cpp @@ -1,19 +1,15 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "ViewportDragOperation.h" +#include "ViewportInteractionTypes.h" -UViewportDragOperationComponent::UViewportDragOperationComponent( const class FObjectInitializer& Initializer ) : - Super( Initializer ), - DragOperation( nullptr ) +UViewportDragOperationComponent::UViewportDragOperationComponent() : + Super(), + DragOperation(nullptr) { } -UViewportDragOperationComponent::~UViewportDragOperationComponent() -{ - DragOperation = nullptr; -} - UViewportDragOperation* UViewportDragOperationComponent::GetDragOperation() { return DragOperation; @@ -37,7 +33,7 @@ void UViewportDragOperationComponent::StartDragOperation() void UViewportDragOperationComponent::ClearDragOperation() { - if ( DragOperation ) + if (DragOperation) { DragOperation->MarkPendingKill(); } @@ -48,4 +44,4 @@ void UViewportDragOperationComponent::ClearDragOperation() bool UViewportDragOperationComponent::IsDragging() const { return DragOperation != nullptr; -} +} \ No newline at end of file diff --git a/Engine/Source/Editor/ViewportInteraction/ViewportInteractionDragOperations.cpp b/Engine/Source/Editor/ViewportInteraction/ViewportInteractionDragOperations.cpp new file mode 100644 index 000000000000..fd6feae3096e --- /dev/null +++ b/Engine/Source/Editor/ViewportInteraction/ViewportInteractionDragOperations.cpp @@ -0,0 +1,218 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "ViewportInteractionDragOperations.h" +#include "ViewportInteractionTypes.h" +#include "VIGizmoHandle.h" +#include "ViewportInteractor.h" +#include "ViewportWorldInteraction.h" +#include "SnappingUtils.h" +#include "ViewportInteractor.h" +#include "UnrealWidget.h" + +namespace VI +{ + static FAutoConsoleVariable ScaleSensitivity(TEXT("VI.ScaleSensitivity"), 0.005f, TEXT("Sensitivity for scaling")); +} + +void UTranslationDragOperation::ExecuteDrag(FDraggingTransformableData& DraggingData) +{ + const EViewportInteractionDraggingMode DraggingMode = DraggingData.Interactor->GetDraggingMode(); + + FVector ResultLocation = DraggingData.PassDraggedTo; + + // Already snapped when transform to impact of laser, so we don't have to do it here. + if (!DraggingData.bIsUpdatingUnsnappedTarget && DraggingMode != EViewportInteractionDraggingMode::TransformablesAtLaserImpact) + { + const bool bLocalSpaceSnapping = DraggingData.GizmoCoordinateSpace == COORD_Local; + const FVector SnapGridBase = bLocalSpaceSnapping ? FVector::ZeroVector : DraggingData.GizmoStartTransform.GetLocation(); + const bool bShouldConstrainMovement = true; + ResultLocation = DraggingData.WorldInteraction->SnapLocation(bLocalSpaceSnapping, DraggingData.PassDraggedTo, DraggingData.GizmoStartTransform, SnapGridBase, bShouldConstrainMovement, DraggingData.ConstrainedDragDelta); + } + + // Translate the gizmo! + FTransform& PassGizmoTargetTransform = DraggingData.bIsUpdatingUnsnappedTarget ? DraggingData.OutGizmoUnsnappedTargetTransform : DraggingData.OutGizmoTargetTransform; + + PassGizmoTargetTransform.SetLocation(ResultLocation); + + DraggingData.bOutMovedTransformGizmo = true; + DraggingData.bOutShouldApplyVelocitiesFromDrag = true; +} + +UPlaneTranslationDragOperation::UPlaneTranslationDragOperation() +{ + bPlaneConstraint = true; +} + +void UPlaneTranslationDragOperation::ExecuteDrag(struct FDraggingTransformableData& DraggingData) +{ + // Translate the gizmo! + const EViewportInteractionDraggingMode DraggingMode = DraggingData.Interactor->GetDraggingMode(); + + FVector ResultLocation = DraggingData.PassDraggedTo; + + // Already snapped when transform to impact of laser, so we don't have to do it here. + if (!DraggingData.bIsUpdatingUnsnappedTarget && DraggingMode != EViewportInteractionDraggingMode::TransformablesAtLaserImpact) + { + const bool bLocalSpaceSnapping = DraggingData.GizmoCoordinateSpace == COORD_Local; + const FVector SnapGridBase = bLocalSpaceSnapping ? FVector::ZeroVector : DraggingData.GizmoStartTransform.GetLocation(); + const bool bShouldConstrainMovement = true; + ResultLocation = DraggingData.WorldInteraction->SnapLocation(bLocalSpaceSnapping, DraggingData.PassDraggedTo, DraggingData.GizmoStartTransform, SnapGridBase, bShouldConstrainMovement, DraggingData.ConstrainedDragDelta); + } + + // Translate the gizmo! + FTransform& PassGizmoTargetTransform = DraggingData.bIsUpdatingUnsnappedTarget ? DraggingData.OutGizmoUnsnappedTargetTransform : DraggingData.OutGizmoTargetTransform; + + PassGizmoTargetTransform.SetLocation(ResultLocation); + DraggingData.bOutMovedTransformGizmo = true; + DraggingData.bOutShouldApplyVelocitiesFromDrag = true; +} + +URotateOnAngleDragOperation::URotateOnAngleDragOperation(): + Super(), + StartDragAngleOnRotation(), + DraggingRotationHandleDirection() +{ + +} + +void URotateOnAngleDragOperation::ExecuteDrag(FDraggingTransformableData& DraggingData) +{ + const FTransformGizmoHandlePlacement& HandlePlacement = DraggingData.OptionalHandlePlacement.GetValue(); + const FTransform& GizmoStartTransform = DraggingData.GizmoStartTransform; + + int32 CenterHandleCount, FacingAxisIndex, CenterAxisIndex; + HandlePlacement.GetCenterHandleCountAndFacingAxisIndex( /* Out */ CenterHandleCount, /* Out */ FacingAxisIndex, /* Out */ CenterAxisIndex); + + FVector GizmoSpaceFacingAxisVector = UGizmoHandleGroup::GetAxisVector(FacingAxisIndex, HandlePlacement.Axes[FacingAxisIndex]); + + USceneComponent* DraggingTransformGizmoComponent = DraggingData.Interactor->GetInteractorData().DraggingTransformGizmoComponent.Get(); + if (DraggingTransformGizmoComponent) + { + const FTransform WorldToGizmo = GizmoStartTransform.Inverse(); + + FTransform NewGizmoToWorld; + { + if (!DraggingRotationHandleDirection.IsSet()) + { + DraggingRotationHandleDirection = DraggingTransformGizmoComponent->GetComponentTransform().GetRotation().Vector(); + DraggingRotationHandleDirection->Normalize(); + } + + //@todo ViewportInteraction: Use UViewportWorldInteraction::ComputeConstrainedDragDeltaFromStart instead of calculating where the laser hit on the plane with this intersect. + // Get the laser pointer intersection on the plane of the handle + const FPlane RotationPlane = FPlane(GizmoStartTransform.GetLocation(), DraggingRotationHandleDirection.GetValue()); + const ECoordSystem CoordSystem = DraggingData.WorldInteraction->GetTransformGizmoCoordinateSpace(); + const FVector LaserImpactOnRotationPlane = FMath::LinePlaneIntersection(DraggingData.LaserPointerStart, DraggingData.LaserPointerStart + DraggingData.LaserPointerDirection, RotationPlane); + + { + FTransform GizmoTransformNoRotation = FTransform(FRotator::ZeroRotator, GizmoStartTransform.GetLocation()); + if (CoordSystem == COORD_Local) + { + GizmoTransformNoRotation.SetRotation(GizmoStartTransform.GetRotation()); + } + + LocalIntersectPointOnRotationGizmo = GizmoTransformNoRotation.InverseTransformPositionNoScale(LaserImpactOnRotationPlane); + } + + // Set output for hover point + DraggingData.OutUnsnappedDraggedTo = LaserImpactOnRotationPlane; + + // Relative offset of the intersection on the plane + const FVector GizmoSpaceLaserImpactOnRotationPlane = WorldToGizmo.TransformPosition(LaserImpactOnRotationPlane); + FVector RotatedIntersectLocationOnPlane; + if (CoordSystem == COORD_Local) + { + RotatedIntersectLocationOnPlane = GizmoSpaceFacingAxisVector.Rotation().UnrotateVector(GizmoSpaceLaserImpactOnRotationPlane); + } + else + { + RotatedIntersectLocationOnPlane = GizmoStartTransform.TransformVector(GizmoSpaceFacingAxisVector).Rotation().UnrotateVector(GizmoSpaceLaserImpactOnRotationPlane); + } + + // Get the angle between the center and the intersected point + float AngleToIntersectedLocation = FMath::Atan2(RotatedIntersectLocationOnPlane.Y, RotatedIntersectLocationOnPlane.Z); + if (!StartDragAngleOnRotation.IsSet()) + { + StartDragAngleOnRotation = AngleToIntersectedLocation; + } + + // Delta rotation in gizmo space between the starting and the intersection rotation + const float AngleDeltaRotationFromStart = FMath::FindDeltaAngleRadians(AngleToIntersectedLocation, StartDragAngleOnRotation.GetValue()); + const FQuat GizmoSpaceDeltaRotation = FQuat(GizmoSpaceFacingAxisVector, AngleDeltaRotationFromStart); + + // Snap rotation in gizmo space + FTransform GizmoSpaceRotatedTransform(GizmoSpaceDeltaRotation); + if (!DraggingData.bIsUpdatingUnsnappedTarget) + { + FRotator SnappedRotation = GizmoSpaceRotatedTransform.GetRotation().Rotator(); + FSnappingUtils::SnapRotatorToGrid(SnappedRotation); + GizmoSpaceRotatedTransform.SetRotation(SnappedRotation.Quaternion()); + } + NewGizmoToWorld = GizmoSpaceRotatedTransform * GizmoStartTransform; + } + + // Rotate the gizmo! + FTransform& PassTargetTransform = DraggingData.bIsUpdatingUnsnappedTarget ? DraggingData.OutGizmoUnsnappedTargetTransform : DraggingData.OutGizmoTargetTransform; + PassTargetTransform = NewGizmoToWorld; + DraggingData.bOutMovedTransformGizmo = true; + DraggingData.bOutShouldApplyVelocitiesFromDrag = true; + } +} + +FVector URotateOnAngleDragOperation::GetLocalIntersectPointOnRotationGizmo() const +{ + return LocalIntersectPointOnRotationGizmo; +} + +void UScaleDragOperation::ExecuteDrag(struct FDraggingTransformableData& DraggingData) +{ + const FTransformGizmoHandlePlacement& HandlePlacement = DraggingData.OptionalHandlePlacement.GetValue(); + int32 CenterHandleCount, FacingAxisIndex, CenterAxisIndex; + HandlePlacement.GetCenterHandleCountAndFacingAxisIndex(/* Out */ CenterHandleCount, /* Out */ FacingAxisIndex, /* Out */ CenterAxisIndex); + + const FVector PassGizmoSpaceDraggedTo = DraggingData.GizmoStartTransform.InverseTransformPositionNoScale(DraggingData.PassDraggedTo); + float AddedScaleOnAxis = PassGizmoSpaceDraggedTo[FacingAxisIndex] * VI::ScaleSensitivity->GetFloat(); + + // Invert if we we are scaling on the negative side of the gizmo + USceneComponent* DraggingTransformGizmoComponent = DraggingData.Interactor->GetInteractorData().DraggingTransformGizmoComponent.Get(); + if (DraggingTransformGizmoComponent && DraggingTransformGizmoComponent->GetRelativeTransform().GetLocation()[FacingAxisIndex] < 0) + { + AddedScaleOnAxis *= -1; + } + + // Scale the gizmo! + FTransform& PassGizmoTargetTransform = DraggingData.bIsUpdatingUnsnappedTarget ? DraggingData.OutGizmoUnsnappedTargetTransform : DraggingData.OutGizmoTargetTransform; + FVector NewTotalScale = DraggingData.GizmoStartTransform.GetScale3D(); + NewTotalScale[FacingAxisIndex] += AddedScaleOnAxis; + + // Scale snap! + if (!DraggingData.bIsUpdatingUnsnappedTarget && FSnappingUtils::IsScaleSnapEnabled()) + { + FSnappingUtils::SnapScale(NewTotalScale, FVector::ZeroVector); + } + + PassGizmoTargetTransform.SetScale3D(NewTotalScale); + DraggingData.bOutMovedTransformGizmo = true; + DraggingData.bOutShouldApplyVelocitiesFromDrag = true; +} + +void UUniformScaleDragOperation::ExecuteDrag(struct FDraggingTransformableData& DraggingData) +{ + //Always use Z for uniform scale + const FVector RelativeDraggedTo = DraggingData.PassDraggedTo - DraggingData.GizmoStartTransform.GetLocation(); + float AddedScaleOnAxis = RelativeDraggedTo.Z * VI::ScaleSensitivity->GetFloat(); + + // Scale the gizmo! + FTransform& PassGizmoTargetTransform = DraggingData.bIsUpdatingUnsnappedTarget ? DraggingData.OutGizmoUnsnappedTargetTransform : DraggingData.OutGizmoTargetTransform; + FVector NewTotalScale = DraggingData.GizmoStartTransform.GetScale3D() + FVector(AddedScaleOnAxis); + + // Scale snap! + if (!DraggingData.bIsUpdatingUnsnappedTarget && FSnappingUtils::IsScaleSnapEnabled()) + { + FSnappingUtils::SnapScale(NewTotalScale, FVector::ZeroVector); + } + + PassGizmoTargetTransform.SetScale3D(NewTotalScale); + DraggingData.bOutMovedTransformGizmo = true; + DraggingData.bOutShouldApplyVelocitiesFromDrag = true; +} diff --git a/Engine/Source/Editor/ViewportInteraction/ViewportInteractionInputProcessor.cpp b/Engine/Source/Editor/ViewportInteraction/ViewportInteractionInputProcessor.cpp index c502262278e8..a58450befaf3 100644 --- a/Engine/Source/Editor/ViewportInteraction/ViewportInteractionInputProcessor.cpp +++ b/Engine/Source/Editor/ViewportInteraction/ViewportInteractionInputProcessor.cpp @@ -3,16 +3,16 @@ #include "ViewportInteractionInputProcessor.h" #include "Input/Events.h" #include "Misc/App.h" -#include "ViewportWorldInteractionManager.h" +#include "ViewportWorldInteraction.h" -FViewportInteractionInputProcessor::FViewportInteractionInputProcessor( FViewportWorldInteractionManager* InWorldInteractionManager ) - : WorldInteractionManager( InWorldInteractionManager ) +FViewportInteractionInputProcessor::FViewportInteractionInputProcessor(UViewportWorldInteraction* InWorldInteraction) + : WorldInteraction(InWorldInteraction) { } FViewportInteractionInputProcessor::~FViewportInteractionInputProcessor() { - WorldInteractionManager = nullptr; + WorldInteraction = nullptr; } void FViewportInteractionInputProcessor::Tick( const float DeltaTime, FSlateApplication& SlateApp, TSharedRef Cursor ) @@ -21,17 +21,17 @@ void FViewportInteractionInputProcessor::Tick( const float DeltaTime, FSlateAppl bool FViewportInteractionInputProcessor::HandleKeyDownEvent( FSlateApplication& SlateApp, const FKeyEvent& InKeyEvent ) { - return WorldInteractionManager->PreprocessedInputKey( InKeyEvent.GetKey(), InKeyEvent.IsRepeat() ? IE_Repeat : IE_Pressed ); + return WorldInteraction != nullptr ? WorldInteraction->PreprocessedInputKey( InKeyEvent.GetKey(), InKeyEvent.IsRepeat() ? IE_Repeat : IE_Pressed ) : false; } bool FViewportInteractionInputProcessor::HandleKeyUpEvent( FSlateApplication& SlateApp, const FKeyEvent& InKeyEvent ) { - return WorldInteractionManager->PreprocessedInputKey( InKeyEvent.GetKey(), IE_Released ); + return WorldInteraction != nullptr ? WorldInteraction->PreprocessedInputKey( InKeyEvent.GetKey(), IE_Released ) : false; } bool FViewportInteractionInputProcessor::HandleAnalogInputEvent( FSlateApplication& SlateApp, const FAnalogInputEvent& InAnalogInputEvent ) { - return WorldInteractionManager->PreprocessedInputAxis( InAnalogInputEvent.GetUserIndex(), InAnalogInputEvent.GetKey(), InAnalogInputEvent.GetAnalogValue(), FApp::GetDeltaTime() ); + return WorldInteraction != nullptr ? WorldInteraction->PreprocessedInputAxis( InAnalogInputEvent.GetUserIndex(), InAnalogInputEvent.GetKey(), InAnalogInputEvent.GetAnalogValue(), FApp::GetDeltaTime() ) : false; } bool FViewportInteractionInputProcessor::HandleMouseMoveEvent( FSlateApplication& SlateApp, const FPointerEvent& MouseEvent ) diff --git a/Engine/Source/Editor/ViewportInteraction/ViewportInteractionInputProcessor.h b/Engine/Source/Editor/ViewportInteraction/ViewportInteractionInputProcessor.h index c8c07bbe64fe..0822332925ad 100644 --- a/Engine/Source/Editor/ViewportInteraction/ViewportInteractionInputProcessor.h +++ b/Engine/Source/Editor/ViewportInteraction/ViewportInteractionInputProcessor.h @@ -15,7 +15,7 @@ struct FPointerEvent; class FViewportInteractionInputProcessor : public IInputProcessor { public: - FViewportInteractionInputProcessor ( FViewportWorldInteractionManager* InWorldInteractionManager ); + FViewportInteractionInputProcessor(class UViewportWorldInteraction* InWorldInteraction); virtual ~FViewportInteractionInputProcessor (); // IInputProcess overrides @@ -28,6 +28,5 @@ public: private: /** The WorldInteraction that will receive the input */ - FViewportWorldInteractionManager* WorldInteractionManager; - + class UViewportWorldInteraction* WorldInteraction; }; diff --git a/Engine/Source/Editor/ViewportInteraction/ViewportInteractionModule.cpp b/Engine/Source/Editor/ViewportInteraction/ViewportInteractionModule.cpp index 4fd07b140db6..15f9525f1cae 100644 --- a/Engine/Source/Editor/ViewportInteraction/ViewportInteractionModule.cpp +++ b/Engine/Source/Editor/ViewportInteraction/ViewportInteractionModule.cpp @@ -1,9 +1,21 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "ViewportInteractionModule.h" -#include "ViewportWorldInteractionManager.h" +#include "HAL/IConsoleManager.h" +#include "EditorWorldExtension.h" +#include "ViewportWorldInteraction.h" +#include "Editor.h" +#include "ILevelEditor.h" +#include "LevelEditor.h" +#include "SLevelViewport.h" -FViewportInteractionModule::FViewportInteractionModule() +namespace VI +{ + static FAutoConsoleCommand ForceMode(TEXT("VI.ForceMode"), TEXT("Toggles viewport interaction on desktop"), FConsoleCommandDelegate::CreateStatic(&FViewportInteractionModule::ToggleMode)); +} + +FViewportInteractionModule::FViewportInteractionModule() : + bEnabledViewportWorldInteractionFromCommand(false) { } @@ -25,7 +37,63 @@ void FViewportInteractionModule::PostLoadCallback() { } -FViewportWorldInteractionManager& FViewportInteractionModule::GetWorldInteractionManager() + +void FViewportInteractionModule::EnabledViewportWorldInteractionFromCommand(const bool bEnabled) { - return WorldInteractionManager; + bEnabledViewportWorldInteractionFromCommand = bEnabled; +} + +bool FViewportInteractionModule::EnabledViewportWorldInteractionFromCommand() +{ + return bEnabledViewportWorldInteractionFromCommand; +} + +void FViewportInteractionModule::ToggleMode() +{ + if (GEditor != nullptr) + { + //@todo ViewportInteraction: Get the world from the current viewport. + UWorld* World = GEditor->bIsSimulatingInEditor ? GEditor->PlayWorld : GWorld; + check (World != nullptr); + + UEditorWorldExtensionCollection* ExtensionCollection = GEditor->GetEditorWorldExtensionsManager()->GetEditorWorldExtensions(World); + check (ExtensionCollection != nullptr); + + UViewportWorldInteraction* ViewportWorldInteraction = Cast(ExtensionCollection->FindExtension(UViewportWorldInteraction::StaticClass())); + + FViewportInteractionModule& Self = FModuleManager::GetModuleChecked< FViewportInteractionModule >(TEXT("ViewportInteraction")); + + if (ViewportWorldInteraction == nullptr) + { + // There is no ViewportWorldInteraction, so we can create one and add it. + UViewportWorldInteraction* NewViewportWorldInteraction = NewObject(ExtensionCollection); + ExtensionCollection->AddExtension(NewViewportWorldInteraction); + NewViewportWorldInteraction->SetUseInputPreprocessor(true); + + // Set the current viewport. + { + const TSharedRef< ILevelEditor >& LevelEditor = FModuleManager::GetModuleChecked("LevelEditor").GetFirstLevelEditor().ToSharedRef(); + + // Do we have an active perspective viewport that is valid for VR? If so, go ahead and use that. + TSharedPtr ViewportClient; + { + TSharedPtr ActiveLevelViewport = LevelEditor->GetActiveViewportInterface(); + if (ActiveLevelViewport.IsValid()) + { + ViewportClient = StaticCastSharedRef(ActiveLevelViewport->AsWidget())->GetViewportClient(); + } + } + + NewViewportWorldInteraction->SetDefaultOptionalViewportClient(ViewportClient); + } + + Self.EnabledViewportWorldInteractionFromCommand(true); + } + else if (Self.EnabledViewportWorldInteractionFromCommand()) + { + // Close ViewportWorldInteraction, but only if we also started it with this command. + ExtensionCollection->RemoveExtension(ViewportWorldInteraction); + Self.EnabledViewportWorldInteractionFromCommand(false); + } + } } diff --git a/Engine/Source/Editor/ViewportInteraction/ViewportInteractionModule.h b/Engine/Source/Editor/ViewportInteraction/ViewportInteractionModule.h index bbbf2259754f..3fcdc60e6de3 100644 --- a/Engine/Source/Editor/ViewportInteraction/ViewportInteractionModule.h +++ b/Engine/Source/Editor/ViewportInteraction/ViewportInteractionModule.h @@ -4,7 +4,6 @@ #include "CoreMinimal.h" #include "IViewportInteractionModule.h" -#include "Editor/ViewportInteraction/ViewportWorldInteractionManager.h" class FViewportInteractionModule : public IViewportInteractionModule { @@ -21,11 +20,14 @@ public: { return true; } - virtual FViewportWorldInteractionManager& GetWorldInteractionManager() override; + + static void ToggleMode(); + + void EnabledViewportWorldInteractionFromCommand(const bool bEnabled); + bool EnabledViewportWorldInteractionFromCommand(); private: - /** Manager that owns the current ViewportWorldInteraction */ - FViewportWorldInteractionManager WorldInteractionManager; - + /** If we started the ViewportWorldInteraction from Toggle command. */ + bool bEnabledViewportWorldInteractionFromCommand; }; diff --git a/Engine/Source/Editor/ViewportInteraction/ViewportInteractor.cpp b/Engine/Source/Editor/ViewportInteraction/ViewportInteractor.cpp index 0fa71edb520b..cf0dc92b4c8a 100644 --- a/Engine/Source/Editor/ViewportInteraction/ViewportInteractor.cpp +++ b/Engine/Source/Editor/ViewportInteraction/ViewportInteractor.cpp @@ -28,8 +28,8 @@ namespace VI static FAutoConsoleVariable LaserSmoothMinimumCutoff(TEXT("VI.LaserSmoothMinimumCutoff"), 0.9f, TEXT("Laser smooth lag")); } -UViewportInteractor::UViewportInteractor( const FObjectInitializer& Initializer ) : - UObject( Initializer ), +UViewportInteractor::UViewportInteractor() : + Super(), InteractorData(), KeyToActionMap(), WorldInteraction( nullptr ), @@ -231,7 +231,7 @@ bool UViewportInteractor::HandleInputKey( FEditorViewportClient& ViewportClient, InteractorData.DragTranslationVelocity = FVector::ZeroVector; InteractorData.DragRayLengthVelocity = 0.0f; InteractorData.DraggingTransformGizmoComponent = nullptr; - InteractorData.TransformGizmoInteractionType = ETransformGizmoInteractionType::None; + InteractorData.DragOperationComponent.Reset(); InteractorData.bIsDrivingVelocityOfSimulatedTransformables = false; InteractorData.GizmoStartTransform = OtherInteractorData->GizmoStartTransform; @@ -420,7 +420,7 @@ bool UViewportInteractor::HandleInputKey( FEditorViewportClient& ViewportClient, // We won't use gizmo features for world movement InteractorData.DraggingTransformGizmoComponent = nullptr; - InteractorData.TransformGizmoInteractionType = ETransformGizmoInteractionType::None; + InteractorData.DragOperationComponent.Reset(); InteractorData.OptionalHandlePlacement.Reset(); InteractorData.GizmoStartTransform = FTransform::Identity; InteractorData.GizmoStartLocalBounds = FBox(ForceInit); @@ -647,7 +647,7 @@ FHitResult UViewportInteractor::GetHitResultFromLaserPointer( TArray* O const bool bOnlyEditorGizmos = ( PassIndex == 0 ); const bool bTraceComplex = true; - FCollisionQueryParams TraceParams( NAME_None, bTraceComplex, nullptr ); + FCollisionQueryParams TraceParams( NAME_None, FCollisionQueryParams::GetUnknownStatId(), bTraceComplex, nullptr ); if ( OptionalListOfIgnoredActors != nullptr ) { diff --git a/Engine/Source/Editor/ViewportInteraction/ViewportInteractorData.h b/Engine/Source/Editor/ViewportInteraction/ViewportInteractorData.h index 0987d85781f0..4b9ccc05c1c3 100644 --- a/Engine/Source/Editor/ViewportInteraction/ViewportInteractorData.h +++ b/Engine/Source/Editor/ViewportInteraction/ViewportInteractorData.h @@ -126,7 +126,10 @@ struct FViewportInteractorData FVector GizmoSpaceDragDeltaFromStartOffset; /** The gizmo interaction we're doing with this hand */ - ETransformGizmoInteractionType TransformGizmoInteractionType; + TWeakObjectPtr DragOperationComponent; + + /** The last drag operation. */ + class UViewportDragOperation* LastDragOperation; /** Which handle on the gizmo we're interacting with, if any */ TOptional OptionalHandlePlacement; @@ -176,7 +179,8 @@ struct FViewportInteractorData GizmoLastTransform = GizmoTargetTransform = GizmoUnsnappedTargetTransform = GizmoInterpolationSnapshotTransform = GizmoStartTransform; GizmoSpaceFirstDragUpdateOffsetAlongAxis = FVector::ZeroVector; GizmoSpaceDragDeltaFromStartOffset = FVector::ZeroVector; - TransformGizmoInteractionType = ETransformGizmoInteractionType::None; + DragOperationComponent.Reset(); + LastDragOperation = nullptr; OptionalHandlePlacement.Reset(); DraggingTransformGizmoComponent = nullptr; HoveringOverTransformGizmoComponent = nullptr; diff --git a/Engine/Source/Editor/ViewportInteraction/ViewportWorldInteraction.cpp b/Engine/Source/Editor/ViewportInteraction/ViewportWorldInteraction.cpp index 14eccd07e86b..2f51995bfaef 100644 --- a/Engine/Source/Editor/ViewportInteraction/ViewportWorldInteraction.cpp +++ b/Engine/Source/Editor/ViewportInteraction/ViewportWorldInteraction.cpp @@ -19,7 +19,6 @@ #include "ViewportDragOperation.h" #include "VIGizmoHandle.h" #include "Gizmo/VIPivotTransformGizmo.h" -#include "ViewportWorldInteractionManager.h" #include "IViewportInteractionModule.h" #include "ViewportTransformer.h" #include "ActorTransformer.h" @@ -38,12 +37,15 @@ #include "EngineUtils.h" #include "ActorViewportTransformable.h" +// Preprocessor input +#include "ViewportInteractionInputProcessor.h" +#include "Framework/Application/SlateApplication.h" + #define LOCTEXT_NAMESPACE "ViewportWorldInteraction" namespace VI { static FAutoConsoleVariable GizmoScaleInDesktop( TEXT( "VI.GizmoScaleInDesktop" ), 0.35f, TEXT( "How big the transform gizmo should be when used in desktop mode" ) ); - static FAutoConsoleVariable ScaleSensitivity( TEXT( "VI.ScaleSensitivity" ), 0.005f, TEXT( "Sensitivity for scaling" ) ); static FAutoConsoleVariable GizmoRotationSensitivity( TEXT( "VI.GizmoRotationSensitivity" ), 0.25f, TEXT( "How much to rotate as the user drags on a rotation gizmo handle" ) ); static FAutoConsoleVariable ScaleWorldFromFloor( TEXT( "VI.ScaleWorldFromFloor" ), 0, TEXT( "Whether the world should scale relative to your tracking space floor instead of the center of your hand locations" ) ); static FAutoConsoleVariable ScaleWorldWithDynamicPivot( TEXT( "VI.ScaleWorldWithDynamicPivot" ), 1, TEXT( "Whether to compute a new center point for scaling relative from by looking at how far either controller moved relative to the last frame" ) ); @@ -275,8 +277,6 @@ UViewportWorldInteraction::UViewportWorldInteraction(): TransformGizmoActor( nullptr ), TransformGizmoClass( APivotTransformGizmo::StaticClass() ), GizmoLocalBounds( FBox(ForceInit) ), - StartDragAngleOnRotation(), - DraggingRotationHandleDirection(), bShouldTransformGizmoBeVisible( true ), TransformGizmoScale( VI::GizmoScaleInDesktop->GetFloat() ), GizmoType(), @@ -293,7 +293,8 @@ UViewportWorldInteraction::UViewportWorldInteraction(): bShouldSuppressCursor(false), CurrentTickNumber(0), AssetContainer(nullptr), - bPlayNextRefreshTransformGizmoSound(true) + bPlayNextRefreshTransformGizmoSound(true), + InputProcessor() { } @@ -316,9 +317,6 @@ void UViewportWorldInteraction::Init() AssetContainer = LoadObject(nullptr, *UViewportWorldInteraction::AssetContainerPath); check(AssetContainer != nullptr); - IViewportWorldInteractionManager& WorldInteractionManager = IViewportInteractionModule::Get().GetWorldInteractionManager(); - WorldInteractionManager.SetCurrentViewportWorldInteraction( this ); - // Start with the default transformer SetTransformer( nullptr ); @@ -329,7 +327,6 @@ void UViewportWorldInteraction::Init() const bool bPropagateToChildren = true; TransformGizmoActor->GetRootComponent()->SetVisibility( bShouldBeVisible, bPropagateToChildren ); - /** This will make sure this is not ticking after the editor has been closed. */ GEditor->OnEditorClose().AddUObject( this, &UViewportWorldInteraction::Shutdown ); @@ -340,8 +337,13 @@ void UViewportWorldInteraction::Init() CandidateActors.Reset(); + // Create and add the input pre-processor to the slate application. + InputProcessor = MakeShareable(new FViewportInteractionInputProcessor(this)); + FSlateApplication::Get().RegisterInputPreProcessor(InputProcessor); + // Pretend that actor selection changed, so that our gizmo refreshes right away based on which objects are selected GEditor->NoteSelectionChange(); + GEditor->SelectNone(true, true, false); CurrentTickNumber = 0; } @@ -356,10 +358,11 @@ void UViewportWorldInteraction::Shutdown() } DestroyActors(); - DefaultOptionalViewportClient = nullptr; - - IViewportWorldInteractionManager& WorldInteractionManager = IViewportInteractionModule::Get().GetWorldInteractionManager(); - WorldInteractionManager.SetCurrentViewportWorldInteraction( nullptr ); + if (DefaultOptionalViewportClient != nullptr) + { + DefaultOptionalViewportClient->ShowWidget(true); + DefaultOptionalViewportClient = nullptr; + } AppTimeEntered = FTimespan::Zero(); @@ -395,6 +398,10 @@ void UViewportWorldInteraction::Shutdown() GizmoType.Reset(); + // Remove the input pre-processor + FSlateApplication::Get().UnregisterInputPreProcessor(InputProcessor); + InputProcessor.Reset(); + USelection::SelectionChangedEvent.RemoveAll( this ); GEditor->OnEditorClose().RemoveAll( this ); } @@ -415,7 +422,7 @@ void UViewportWorldInteraction::EnteredSimulateInEditor() GEditor->NoteSelectionChange(); } -void UViewportWorldInteraction::LeftSimulateInEditor() +void UViewportWorldInteraction::LeftSimulateInEditor(UWorld* SimulateWorld) { // Make sure transformables get updated GEditor->NoteSelectionChange(); @@ -478,6 +485,7 @@ void UViewportWorldInteraction::AddInteractor( UViewportInteractor* Interactor ) void UViewportWorldInteraction::RemoveInteractor( UViewportInteractor* Interactor ) { + Interactor->Shutdown(); Interactor->RemoveOtherInteractor(); Interactors.Remove( Interactor ); } @@ -533,6 +541,11 @@ void UViewportWorldInteraction::SetTransformables( TArray< TUniquePtr< class FVi void UViewportWorldInteraction::SetDefaultOptionalViewportClient(const TSharedPtr& InEditorViewportClient) { DefaultOptionalViewportClient = InEditorViewportClient.Get(); + + if (DefaultOptionalViewportClient != nullptr) + { + DefaultOptionalViewportClient->ShowWidget(false); + } } void UViewportWorldInteraction::PairInteractors( UViewportInteractor* FirstInteractor, UViewportInteractor* SecondInteractor ) @@ -868,12 +881,9 @@ void UViewportWorldInteraction::InteractionTick( const float DeltaTime ) check( DraggingWithInteractor == nullptr ); // Only support dragging one thing at a time right now! DraggingWithInteractor = Interactor; - if ( InteractorData.DraggingMode != EViewportInteractionDraggingMode::TransformablesAtLaserImpact ) + if (!InteractorData.bDraggingWithGrabberSphere) { - if( !InteractorData.bDraggingWithGrabberSphere ) - { - bCanSlideRayLength = true; - } + bCanSlideRayLength = true; } } @@ -1125,6 +1135,17 @@ void UViewportWorldInteraction::InteractionTick( const float DeltaTime ) } } + UViewportDragOperation* DragOperation = nullptr; + if (InteractorData.DragOperationComponent.IsValid()) + { + UViewportDragOperationComponent* DragOperationComponent = InteractorData.DragOperationComponent.Get(); + if (DragOperationComponent->GetDragOperation() == nullptr) + { + DragOperationComponent->StartDragOperation(); + } + DragOperation = DragOperationComponent->GetDragOperation(); + } + const FVector OldViewLocation = DefaultOptionalViewportClient != nullptr ? DefaultOptionalViewportClient->GetViewLocation() : FVector::ZeroVector; // Dragging transform gizmo handle @@ -1134,8 +1155,9 @@ void UViewportWorldInteraction::InteractionTick( const float DeltaTime ) UpdateDragging( DeltaTime, InteractorData.bIsFirstDragUpdate, + Interactor, InteractorData.DraggingMode, - InteractorData.TransformGizmoInteractionType, + DragOperation, bWithTwoHands, InteractorData.OptionalHandlePlacement, DragDelta, @@ -1267,8 +1289,9 @@ void UViewportWorldInteraction::InteractionTick( const float DeltaTime ) UpdateDragging( DeltaTime, InteractorData.bIsFirstDragUpdate, + Interactor, InteractorData.LastDraggingMode, - InteractorData.TransformGizmoInteractionType, + InteractorData.LastDragOperation, bWithTwoHands, InteractorData.OptionalHandlePlacement, DragDelta, @@ -1379,7 +1402,7 @@ void UViewportWorldInteraction::InteractionTick( const float DeltaTime ) { InterpolatedGizmoTransform.BlendWith( InteractorData.GizmoInterpolationSnapshotTransform, 1.0f - InterpProgress ); } - + for ( TUniquePtr& TransformablePtr : Transformables ) { FViewportTransformable& Transformable = *TransformablePtr; @@ -1460,7 +1483,7 @@ void UViewportWorldInteraction::SetLastDragGizmoStartTransform( const FTransform LastDragGizmoStartTransform = NewLastDragGizmoStartTransform; } -TArray& UViewportWorldInteraction::GetInteractors() +const TArray& UViewportWorldInteraction::GetInteractors() const { return Interactors; } @@ -1469,8 +1492,9 @@ BEGIN_FUNCTION_BUILD_OPTIMIZATION void UViewportWorldInteraction::UpdateDragging( const float DeltaTime, bool& bIsFirstDragUpdate, + UViewportInteractor* Interactor, const EViewportInteractionDraggingMode DraggingMode, - const ETransformGizmoInteractionType InteractionType, + UViewportDragOperation* DragOperation, const bool bWithTwoHands, const TOptional OptionalHandlePlacement, const FVector& DragDelta, @@ -1515,16 +1539,72 @@ void UViewportWorldInteraction::UpdateDragging( DraggingMode != EViewportInteractionDraggingMode::TransformablesAtLaserImpact; const FVector SnapGridBase = ( DraggingMode == EViewportInteractionDraggingMode::TransformablesAtLaserImpact || bLocalSpaceSnapping ) ? FVector::ZeroVector : GizmoStartTransform.GetLocation(); - // Okay, time to move stuff! We'll do this part differently depending on whether we're dragging actual actors around // or we're moving the camera (aka. dragging the world) - if( DraggingMode == EViewportInteractionDraggingMode::TransformablesWithGizmo || - DraggingMode == EViewportInteractionDraggingMode::TransformablesAtLaserImpact ) + if (DragOperation != nullptr && DraggingMode == EViewportInteractionDraggingMode::TransformablesWithGizmo) { FVector OutClosestPointOnLaser; FVector ConstrainedDragDeltaFromStart = ComputeConstrainedDragDeltaFromStart( bIsFirstDragUpdate, - InteractionType, + DragOperation->bPlaneConstraint, + OptionalHandlePlacement, + DragDeltaFromStart, + LaserPointerStart, + LaserPointerDirection, + bIsLaserPointerValid, + GizmoStartTransform, + LaserPointerMaxLength, + /* In/Out */ GizmoSpaceFirstDragUpdateOffsetAlongAxis, + /* In/Out */ DragDeltaFromStartOffset, + /* Out */ OutClosestPointOnLaser); + + // Set out put for hover point + OutUnsnappedDraggedTo = GizmoStartTransform.GetLocation() + OutClosestPointOnLaser; + + // Grid snap! + const FVector DesiredGizmoLocation = GizmoStartTransform.GetLocation() + ConstrainedDragDeltaFromStart; + + FDraggingTransformableData DragData; + DragData.Interactor = Interactor; + DragData.WorldInteraction = this; + DragData.OptionalHandlePlacement = OptionalHandlePlacement; + DragData.DragDelta = DragDelta; + DragData.ConstrainedDragDelta = ConstrainedDragDeltaFromStart; + DragData.OtherHandDragDelta = OtherHandDragDelta; + DragData.DraggedTo = DraggedTo; + DragData.OtherHandDraggedTo = OtherHandDraggedTo; + DragData.DragDeltaFromStart = DragDeltaFromStart; + DragData.OtherHandDragDeltaFromStart = OtherHandDragDeltaFromStart; + DragData.LaserPointerStart = LaserPointerStart; + DragData.LaserPointerDirection = LaserPointerDirection; + DragData.GizmoStartTransform = GizmoStartTransform; + DragData.GizmoLastTransform = GizmoLastTransform; + DragData.OutGizmoTargetTransform = GizmoTargetTransform; + DragData.OutGizmoUnsnappedTargetTransform = GizmoUnsnappedTargetTransform; + DragData.GizmoStartLocalBounds = GizmoStartLocalBounds; + DragData.OutUnsnappedDraggedTo = OutUnsnappedDraggedTo; + + // Two passes. First update the real transform. Then update the unsnapped transform. + for ( int32 PassIndex = 0; PassIndex < 2; ++PassIndex ) + { + const bool bIsUpdatingUnsnappedTarget = ( PassIndex == 1 ); + DragData.bIsUpdatingUnsnappedTarget = bIsUpdatingUnsnappedTarget; + DragData.PassDraggedTo = DesiredGizmoLocation; + + DragOperation->ExecuteDrag(DragData); + + GizmoTargetTransform = DragData.OutGizmoTargetTransform; + GizmoUnsnappedTargetTransform = DragData.OutGizmoUnsnappedTargetTransform; + bMovedTransformGizmo = DragData.bOutMovedTransformGizmo; + bShouldApplyVelocitiesFromDrag = DragData.bOutShouldApplyVelocitiesFromDrag; + } + } + else if (DraggingMode == EViewportInteractionDraggingMode::TransformablesAtLaserImpact) + { + FVector OutClosestPointOnLaser; + FVector ConstrainedDragDeltaFromStart = ComputeConstrainedDragDeltaFromStart( + bIsFirstDragUpdate, + false, OptionalHandlePlacement, DragDeltaFromStart, LaserPointerStart, @@ -1536,305 +1616,27 @@ void UViewportWorldInteraction::UpdateDragging( /* In/Out */ DragDeltaFromStartOffset, /* Out */ OutClosestPointOnLaser); - FVector OriginalConstrainedDragDelta = ConstrainedDragDeltaFromStart; - ConstrainedDragDeltaFromStart = GizmoStartTransform.GetLocation() + ConstrainedDragDeltaFromStart; + const FVector DesiredGizmoLocation = GizmoStartTransform.GetLocation() + ConstrainedDragDeltaFromStart; // Set out put for hover point OutUnsnappedDraggedTo = GizmoStartTransform.GetLocation() + OutClosestPointOnLaser; - // Grid snap! - FVector DesiredGizmoLocation = ConstrainedDragDeltaFromStart; - FVector SnappedDraggedTo = DesiredGizmoLocation; - if ((InteractionType == ETransformGizmoInteractionType::Translate || - InteractionType == ETransformGizmoInteractionType::TranslateOnPlane) || - DraggingMode == EViewportInteractionDraggingMode::TransformablesAtLaserImpact) - { - const bool bShouldConstrainMovement = true; - SnappedDraggedTo = SnapLocation(bLocalSpaceSnapping, DesiredGizmoLocation, GizmoStartTransform, SnapGridBase, bShouldConstrainMovement, OriginalConstrainedDragDelta); - } + const bool bShouldConstrainMovement = true; + FVector SnappedDraggedTo = SnapLocation(bLocalSpaceSnapping, DesiredGizmoLocation, GizmoStartTransform, SnapGridBase, bShouldConstrainMovement, ConstrainedDragDeltaFromStart); // Two passes. First update the real transform. Then update the unsnapped transform. - for ( int32 PassIndex = 0; PassIndex < 2; ++PassIndex ) + for (int32 PassIndex = 0; PassIndex < 2; ++PassIndex) { - const bool bIsUpdatingUnsnappedTarget = ( PassIndex == 1 ); - const FVector& PassDraggedTo = bIsUpdatingUnsnappedTarget ? ConstrainedDragDeltaFromStart : SnappedDraggedTo; + const bool bIsUpdatingUnsnappedTarget = (PassIndex == 1); + const FVector& PassDraggedTo = bIsUpdatingUnsnappedTarget ? DesiredGizmoLocation : SnappedDraggedTo; - if( InteractionType == ETransformGizmoInteractionType::Translate || - InteractionType == ETransformGizmoInteractionType::TranslateOnPlane ) - { - // Translate the gizmo! - FTransform& PassGizmoTargetTransform = bIsUpdatingUnsnappedTarget ? GizmoUnsnappedTargetTransform : GizmoTargetTransform; + // Translate the gizmo! + FTransform& PassGizmoTargetTransform = bIsUpdatingUnsnappedTarget ? GizmoUnsnappedTargetTransform : GizmoTargetTransform; + PassGizmoTargetTransform.SetLocation(PassDraggedTo); - PassGizmoTargetTransform.SetLocation( PassDraggedTo ); - - bMovedTransformGizmo = true; - bShouldApplyVelocitiesFromDrag = true; - } - else if ( InteractionType == ETransformGizmoInteractionType::StretchAndReposition ) - { - // We only support stretching by a handle currently - const FTransformGizmoHandlePlacement& HandlePlacement = OptionalHandlePlacement.GetValue(); - - const FVector PassGizmoSpaceDraggedTo = GizmoStartTransform.InverseTransformPositionNoScale( PassDraggedTo ); - - FBox NewGizmoLocalBounds = GizmoStartLocalBounds; - FVector GizmoSpacePivotLocation = FVector::ZeroVector; - for ( int32 AxisIndex = 0; AxisIndex < 3; ++AxisIndex ) - { - // Figure out how much the gizmo bounds changes - if ( HandlePlacement.Axes[ AxisIndex ] == ETransformGizmoHandleDirection::Negative ) // Negative direction - { - GizmoSpacePivotLocation[ AxisIndex ] = GizmoStartLocalBounds.Max[ AxisIndex ]; - NewGizmoLocalBounds.Min[ AxisIndex ] = GizmoStartLocalBounds.Min[ AxisIndex ] + PassGizmoSpaceDraggedTo[ AxisIndex ]; - - } - else if ( HandlePlacement.Axes[ AxisIndex ] == ETransformGizmoHandleDirection::Positive ) // Positive direction - { - GizmoSpacePivotLocation[ AxisIndex ] = GizmoStartLocalBounds.Min[ AxisIndex ]; - NewGizmoLocalBounds.Max[ AxisIndex ] = GizmoStartLocalBounds.Max[ AxisIndex ] + PassGizmoSpaceDraggedTo[ AxisIndex ]; - } - else - { - // Must be ETransformGizmoHandleDirection::Center. - GizmoSpacePivotLocation[ AxisIndex ] = GizmoStartLocalBounds.GetCenter()[ AxisIndex ]; - } - } - - const FVector GizmoStartLocalSize = GizmoStartLocalBounds.GetSize(); - const FVector NewGizmoLocalSize = NewGizmoLocalBounds.GetSize(); - - FVector NewGizmoLocalScaleFromStart = FVector( 1.0f ); - for( int32 AxisIndex = 0; AxisIndex < 3; ++AxisIndex ) - { - if( !FMath::IsNearlyZero( GizmoStartLocalSize[AxisIndex] ) ) - { - NewGizmoLocalScaleFromStart[AxisIndex] = NewGizmoLocalSize[AxisIndex] / GizmoStartLocalSize[AxisIndex]; - } - else - { - // Zero scale. This is allowed in Unreal, for better or worse. - NewGizmoLocalScaleFromStart[AxisIndex] = 0.0f; - } - } - - // Stretch and reposition the gizmo! - { - FTransform& PassGizmoTargetTransform = bIsUpdatingUnsnappedTarget ? GizmoUnsnappedTargetTransform : GizmoTargetTransform; - - { - const FVector GizmoSpaceTransformableStartLocation = GizmoStartTransform.InverseTransformPositionNoScale( GizmoStartTransform.GetLocation() ); - const FVector NewGizmoSpaceLocation = ( GizmoSpaceTransformableStartLocation - GizmoSpacePivotLocation ) * NewGizmoLocalScaleFromStart + GizmoSpacePivotLocation; - PassGizmoTargetTransform.SetLocation( GizmoStartTransform.TransformPosition( NewGizmoSpaceLocation ) ); - } - - // @todo vreditor: This scale is still in gizmo space, but we're setting it in world space - PassGizmoTargetTransform.SetScale3D( GizmoStartTransform.GetScale3D() * NewGizmoLocalScaleFromStart ); - - bMovedTransformGizmo = true; - bShouldApplyVelocitiesFromDrag = false; - } - } - else if ( InteractionType == ETransformGizmoInteractionType::Scale || InteractionType == ETransformGizmoInteractionType::UniformScale ) - { - const FTransformGizmoHandlePlacement& HandlePlacement = OptionalHandlePlacement.GetValue(); - - int32 CenterHandleCount, FacingAxisIndex, CenterAxisIndex; - HandlePlacement.GetCenterHandleCountAndFacingAxisIndex( /* Out */ CenterHandleCount, /* Out */ FacingAxisIndex, /* Out */ CenterAxisIndex ); - - const FVector PassGizmoSpaceDraggedTo = GizmoStartTransform.InverseTransformPositionNoScale( PassDraggedTo ); - - const float ScaleSensitivity = VI::ScaleSensitivity->GetFloat(); - float AddedScaleOnAxis = 0.0f; - if ( InteractionType == ETransformGizmoInteractionType::Scale ) - { - AddedScaleOnAxis = PassGizmoSpaceDraggedTo[ FacingAxisIndex ] * ScaleSensitivity; - - // Invert if we we are scaling on the negative side of the gizmo - if ( DraggingTransformGizmoComponent && DraggingTransformGizmoComponent->GetRelativeTransform().GetLocation()[ FacingAxisIndex ] < 0 ) - { - AddedScaleOnAxis *= -1; - } - } - else if ( InteractionType == ETransformGizmoInteractionType::UniformScale ) - { - // Always use Z for uniform scale - const FVector RelativeDraggedTo = PassDraggedTo - GizmoStartTransform.GetLocation(); - AddedScaleOnAxis = RelativeDraggedTo.Z * ScaleSensitivity; - } - - // Scale the gizmo! - { - FTransform& PassGizmoTargetTransform = bIsUpdatingUnsnappedTarget ? GizmoUnsnappedTargetTransform : GizmoTargetTransform; - FVector NewTotalScale = GizmoStartTransform.GetScale3D(); - - if ( InteractionType == ETransformGizmoInteractionType::Scale ) - { - NewTotalScale[ FacingAxisIndex ] += AddedScaleOnAxis; - } - else if ( InteractionType == ETransformGizmoInteractionType::UniformScale ) - { - NewTotalScale += FVector( AddedScaleOnAxis ); - } - - // Scale snap! - if ( !bIsUpdatingUnsnappedTarget && FSnappingUtils::IsScaleSnapEnabled() ) - { - FSnappingUtils::SnapScale( NewTotalScale, FVector::ZeroVector ); - } - - PassGizmoTargetTransform.SetScale3D( NewTotalScale ); - bMovedTransformGizmo = true; - bShouldApplyVelocitiesFromDrag = true; - } - } - else if ( InteractionType == ETransformGizmoInteractionType::Rotate ) - { - // We only support rotating by a handle currently - const FTransformGizmoHandlePlacement& HandlePlacement = OptionalHandlePlacement.GetValue(); - - int32 CenterHandleCount, FacingAxisIndex, CenterAxisIndex; - HandlePlacement.GetCenterHandleCountAndFacingAxisIndex( /* Out */ CenterHandleCount, /* Out */ FacingAxisIndex, /* Out */ CenterAxisIndex ); - check( CenterAxisIndex != INDEX_NONE ); - - // Get the local location of the rotation handle - FVector HandleRelativeLocation = FVector::ZeroVector; - for ( int32 AxisIndex = 0; AxisIndex < 3; ++AxisIndex ) - { - if ( HandlePlacement.Axes[ AxisIndex ] == ETransformGizmoHandleDirection::Negative ) // Negative direction - { - HandleRelativeLocation[ AxisIndex ] = GizmoStartLocalBounds.Min[ AxisIndex ]; - } - else if ( HandlePlacement.Axes[ AxisIndex ] == ETransformGizmoHandleDirection::Positive ) // Positive direction - { - HandleRelativeLocation[ AxisIndex ] = GizmoStartLocalBounds.Max[ AxisIndex ]; - } - else // ETransformGizmoHandleDirection::Center - { - HandleRelativeLocation[ AxisIndex ] = GizmoStartLocalBounds.GetCenter()[ AxisIndex ]; - } - } - - const FVector GizmoSpaceRotationAxis = ( CenterAxisIndex == 0 ) ? FVector::ForwardVector : ( CenterAxisIndex == 1 ? FVector::RightVector : FVector::UpVector ); - - // Make a vector that points along the tangent vector of the bounding box edge - const FVector GizmoSpaceTowardHandleVector = ( HandleRelativeLocation - GizmoStartLocalBounds.GetCenter() ).GetSafeNormal(); - const FVector GizmoSpaceDiagonalAxis = FQuat( GizmoSpaceRotationAxis, FMath::DegreesToRadians( 90.0f ) ).RotateVector( GizmoSpaceTowardHandleVector ); - - // Figure out how far we've dragged in the direction of the diagonal axis. - const float RotationProgress = FVector::DotProduct( DragDeltaFromStart, GizmoStartTransform.TransformVectorNoScale( GizmoSpaceDiagonalAxis ) ); - - const float RotationDegreesAroundAxis = RotationProgress * VI::GizmoRotationSensitivity->GetFloat(); - const FQuat RotationDeltaFromStart = FQuat( GizmoSpaceRotationAxis, FMath::DegreesToRadians( RotationDegreesAroundAxis ) ); - - const FTransform WorldToGizmo = GizmoStartTransform.Inverse(); - - // Rotate (and reposition) the gizmo! - { - // @todo mesheditor: This stuff doesn't make as much sense now that we're transforming the gizmo itself instead of individual objects. - // We can simplify this code along with similar code blocks in this function! - const FTransform GizmoSpaceStartTransform = GizmoStartTransform * WorldToGizmo; - FTransform GizmoSpaceRotatedTransform = GizmoSpaceStartTransform * RotationDeltaFromStart; - - // Snap rotation in gizmo space - if ( !bIsUpdatingUnsnappedTarget ) - { - FRotator SnappedRotation = GizmoSpaceRotatedTransform.GetRotation().Rotator(); - FSnappingUtils::SnapRotatorToGrid( SnappedRotation ); - GizmoSpaceRotatedTransform.SetRotation( SnappedRotation.Quaternion() ); - } - - const FTransform WorldSpaceRotatedTransform = GizmoSpaceRotatedTransform * GizmoStartTransform; - - FTransform& PassGizmoTargetTransform = bIsUpdatingUnsnappedTarget ? GizmoUnsnappedTargetTransform : GizmoTargetTransform; - PassGizmoTargetTransform = WorldSpaceRotatedTransform; - bMovedTransformGizmo = true; - bShouldApplyVelocitiesFromDrag = false; - } - } - else if ( InteractionType == ETransformGizmoInteractionType::RotateOnAngle ) - { - const FTransformGizmoHandlePlacement& HandlePlacement = OptionalHandlePlacement.GetValue(); - - int32 CenterHandleCount, FacingAxisIndex, CenterAxisIndex; - HandlePlacement.GetCenterHandleCountAndFacingAxisIndex( /* Out */ CenterHandleCount, /* Out */ FacingAxisIndex, /* Out */ CenterAxisIndex ); - - FVector GizmoSpaceFacingAxisVector = UGizmoHandleGroup::GetAxisVector( FacingAxisIndex, HandlePlacement.Axes[ FacingAxisIndex ] ); - - if ( DraggingTransformGizmoComponent ) - { - const FTransform WorldToGizmo = GizmoStartTransform.Inverse(); - - FTransform NewGizmoToWorld; - { - if ( !DraggingRotationHandleDirection.IsSet() ) - { - DraggingRotationHandleDirection = DraggingTransformGizmoComponent->GetComponentTransform().GetRotation().Vector(); - DraggingRotationHandleDirection->Normalize(); - } - - // Get the laser pointer intersection on the plane of the handle - const FPlane RotationPlane = FPlane( GizmoStartTransform.GetLocation(), DraggingRotationHandleDirection.GetValue() ); - - const FVector LaserImpactOnRotationPlane = FMath::LinePlaneIntersection( LaserPointerStart, LaserPointerStart + LaserPointerDirection, RotationPlane); - - { - FTransform GizmoTransformNoRotation = FTransform(FRotator::ZeroRotator, GizmoStartTransform.GetLocation()); - const ECoordSystem CoordSystem = GLevelEditorModeTools().GetCoordSystem(true); - if (CoordSystem == COORD_Local) - { - GizmoTransformNoRotation.SetRotation(GizmoStartTransform.GetRotation()); - } - - LocalIntersectPointOnRotationGizmo = GizmoTransformNoRotation.InverseTransformPositionNoScale(LaserImpactOnRotationPlane); - } - - // Set output for hover point - OutUnsnappedDraggedTo = LaserImpactOnRotationPlane; - - // Relative offset of the intersection on the plane - const FVector GizmoSpaceLaserImpactOnRotationPlane = WorldToGizmo.TransformPosition( LaserImpactOnRotationPlane ); - FVector RotatedIntersectLocationOnPlane; - if ( GLevelEditorModeTools().GetCoordSystem( true ) == COORD_Local ) - { - RotatedIntersectLocationOnPlane = GizmoSpaceFacingAxisVector.Rotation().UnrotateVector( GizmoSpaceLaserImpactOnRotationPlane ); - } - else - { - RotatedIntersectLocationOnPlane = GizmoStartTransform.TransformVector( GizmoSpaceFacingAxisVector ).Rotation().UnrotateVector( GizmoSpaceLaserImpactOnRotationPlane ); - } - - // Get the angle between the center and the intersected point - float AngleToIntersectedLocation = FMath::Atan2( RotatedIntersectLocationOnPlane.Y, RotatedIntersectLocationOnPlane.Z ); - if ( !StartDragAngleOnRotation.IsSet() ) - { - StartDragAngleOnRotation = AngleToIntersectedLocation; - } - - // Delta rotation in gizmo space between the starting and the intersection rotation - const float AngleDeltaRotationFromStart = FMath::FindDeltaAngleRadians( AngleToIntersectedLocation, StartDragAngleOnRotation.GetValue() ); - const FQuat GizmoSpaceDeltaRotation = FQuat( GizmoSpaceFacingAxisVector, AngleDeltaRotationFromStart ); - - // Snap rotation in gizmo space - FTransform GizmoSpaceRotatedTransform( GizmoSpaceDeltaRotation ); - if ( !bIsUpdatingUnsnappedTarget ) - { - FRotator SnappedRotation = GizmoSpaceRotatedTransform.GetRotation().Rotator(); - FSnappingUtils::SnapRotatorToGrid( SnappedRotation ); - GizmoSpaceRotatedTransform.SetRotation( SnappedRotation.Quaternion() ); - } - NewGizmoToWorld = GizmoSpaceRotatedTransform * GizmoStartTransform; - } - - // Rotate the gizmo! - { - FTransform& PassTargetTransform = bIsUpdatingUnsnappedTarget ? GizmoUnsnappedTargetTransform : GizmoTargetTransform; - PassTargetTransform = NewGizmoToWorld; - bMovedTransformGizmo = true; - bShouldApplyVelocitiesFromDrag = true; - } - } - } + bMovedTransformGizmo = true; + bShouldApplyVelocitiesFromDrag = true; } } else if ( DraggingMode == EViewportInteractionDraggingMode::TransformablesFreely || @@ -2051,12 +1853,11 @@ void UViewportWorldInteraction::UpdateDragging( bIsFirstDragUpdate = false; bSkipInteractiveWorldMovementThisFrame = false; } - END_FUNCTION_BUILD_OPTIMIZATION FVector UViewportWorldInteraction::ComputeConstrainedDragDeltaFromStart( const bool bIsFirstDragUpdate, - const ETransformGizmoInteractionType InteractionType, + const bool bOnPlane, const TOptional OptionalHandlePlacement, const FVector& DragDeltaFromStart, const FVector& LaserPointerStart, @@ -2093,7 +1894,6 @@ FVector UViewportWorldInteraction::ComputeConstrainedDragDeltaFromStart( GizmoSpaceConstraintAxis *= -1.0f; } - const bool bOnPlane = ( InteractionType == ETransformGizmoInteractionType::TranslateOnPlane ); if ( bOnPlane ) { const FPlane GizmoSpaceConstrainToPlane( FVector::ZeroVector, GizmoSpaceConstraintAxis ); @@ -2173,8 +1973,6 @@ FVector UViewportWorldInteraction::ComputeConstrainedDragDeltaFromStart( // more information. Inertial movement of constrained objects is actually very complicated! ConstrainedGizmoSpaceDeltaFromStart += GizmoSpaceDragDeltaFromStartOffset; - const bool bOnPlane = ( InteractionType == ETransformGizmoInteractionType::TranslateOnPlane ); - const FTransformGizmoHandlePlacement& HandlePlacement = OptionalHandlePlacement.GetValue(); for ( int32 AxisIndex = 0; AxisIndex < 3; ++AxisIndex ) { @@ -2292,13 +2090,13 @@ void UViewportWorldInteraction::StartDragging( UViewportInteractor* Interactor, if ( TransformGizmoActor != nullptr ) { - InteractorData.TransformGizmoInteractionType = TransformGizmoActor->GetInteractionType( InteractorData.DraggingTransformGizmoComponent.Get(), InteractorData.OptionalHandlePlacement ); + InteractorData.DragOperationComponent = TransformGizmoActor->GetInteractionType(InteractorData.DraggingTransformGizmoComponent.Get(), InteractorData.OptionalHandlePlacement); InteractorData.GizmoStartTransform = TransformGizmoActor->GetTransform(); InteractorData.GizmoStartLocalBounds = GizmoLocalBounds; } else { - InteractorData.TransformGizmoInteractionType = ETransformGizmoInteractionType::None; + InteractorData.DragOperationComponent.Reset(); InteractorData.GizmoStartTransform = FTransform::Identity; InteractorData.GizmoStartLocalBounds = FBox(ForceInit); } @@ -2394,14 +2192,14 @@ void UViewportWorldInteraction::StopDragging( UViewportInteractor* Interactor ) else if ( InteractorData.DraggingMode == EViewportInteractionDraggingMode::TransformablesWithGizmo || InteractorData.DraggingMode == EViewportInteractionDraggingMode::TransformablesFreely || InteractorData.DraggingMode == EViewportInteractionDraggingMode::TransformablesAtLaserImpact ) - { - // No hand is dragging the objects anymore. - if ( InteractorData.DraggingMode == EViewportInteractionDraggingMode::TransformablesWithGizmo && - InteractorData.TransformGizmoInteractionType == ETransformGizmoInteractionType::RotateOnAngle ) + { + // Destroy drag operation. + if (InteractorData.DragOperationComponent != nullptr) { - StartDragAngleOnRotation.Reset(); - DraggingRotationHandleDirection.Reset(); + InteractorData.LastDragOperation = InteractorData.DragOperationComponent->GetDragOperation(); + InteractorData.DragOperationComponent->ClearDragOperation(); } + InteractorData.DragOperationComponent.Reset(); // If we're not dragging anything around, check to see if transformables have come to a rest. const bool bTransformablesStillMoving = @@ -2425,8 +2223,7 @@ void UViewportWorldInteraction::StopDragging( UViewportInteractor* Interactor ) InteractorData.DraggingMode = EViewportInteractionDraggingMode::Nothing; } } - - + void UViewportWorldInteraction::FinishedMovingTransformables() { bAreTransformablesMoving = false; @@ -3045,11 +2842,6 @@ void UViewportWorldInteraction::SetSelectionAsCandidates() } } -FVector UViewportWorldInteraction::GetLocalIntersectPointOnRotationGizmo() const -{ - return LocalIntersectPointOnRotationGizmo; -} - float UViewportWorldInteraction::GetCurrentDeltaTime() const { return CurrentDeltaTime; @@ -3132,6 +2924,7 @@ void UViewportWorldInteraction::SetGizmoHandleType( const EGizmoHandleTypes InGi { case EGizmoHandleTypes::All: GizmoType = InGizmoHandleType; + GLevelEditorModeTools().SetWidgetMode( FWidget::WM_Translate ); break; case EGizmoHandleTypes::Translate: @@ -3254,7 +3047,6 @@ void UViewportWorldInteraction::ReleaseMouseCursorInteractor() DefaultMouseCursorInteractorRefCount = 0; // Remove mouse cursor - DefaultMouseCursorInteractor->Shutdown(); this->RemoveInteractor( DefaultMouseCursorInteractor ); DefaultMouseCursorInteractor = nullptr; } @@ -3342,7 +3134,8 @@ FVector UViewportWorldInteraction::FindTransformGizmoAlignPoint(const FTransform for (const AActor* SelectedCandidateActor : CandidateActors) { // Don't align to yourself, the entire world, or any actors hidden in the editor - if (!SelectedCandidateActor->IsSelected() + if (SelectedCandidateActor != nullptr + && !SelectedCandidateActor->IsSelected() && SelectedCandidateActor != GetWorld()->GetDefaultBrush() && SelectedCandidateActor->IsHiddenEd() == false && !SelectedCandidateActor->IsEditorOnly() @@ -3373,7 +3166,8 @@ FVector UViewportWorldInteraction::FindTransformGizmoAlignPoint(const FTransform const AActor* PossibleCandidateActor = OverlapResult.GetActor(); // Don't align to yourself, the entire world, or any actors hidden in the editor - if (!PossibleCandidateActor->IsSelected() + if (PossibleCandidateActor != nullptr + && !PossibleCandidateActor->IsSelected() && PossibleCandidateActor != GetWorld()->GetDefaultBrush() && PossibleCandidateActor->IsHiddenEd() == false && !PossibleCandidateActor->IsEditorOnly() @@ -3610,8 +3404,7 @@ FVector UViewportWorldInteraction::SnapLocation(const bool bLocalSpaceSnapping, FTransform DesiredGizmoTransform = GizmoStartTransform; DesiredGizmoTransform.SetLocation( DesiredGizmoLocation ); - FVector LocationOffset = FVector::ZeroVector; - LocationOffset = FindTransformGizmoAlignPoint(GizmoStartTransform, DesiredGizmoTransform, bShouldConstrainMovement, AlignAxes); + FVector LocationOffset = FindTransformGizmoAlignPoint(GizmoStartTransform, DesiredGizmoTransform, bShouldConstrainMovement, AlignAxes); if (!LocationOffset.IsZero()) { diff --git a/Engine/Source/Editor/ViewportInteraction/ViewportWorldInteractionManager.cpp b/Engine/Source/Editor/ViewportInteraction/ViewportWorldInteractionManager.cpp deleted file mode 100644 index d798e196dd35..000000000000 --- a/Engine/Source/Editor/ViewportInteraction/ViewportWorldInteractionManager.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#include "ViewportWorldInteractionManager.h" -#include "Framework/Application/SlateApplication.h" -#include "ViewportWorldInteraction.h" - -FViewportWorldInteractionManager::FViewportWorldInteractionManager() : - CurrentWorldInteraction( nullptr ) -{ - InputProcessor = MakeShareable( new FViewportInteractionInputProcessor( this ) ); - FSlateApplication::Get().SetInputPreProcessor( true, InputProcessor ); -} - -FViewportWorldInteractionManager::~FViewportWorldInteractionManager() -{ - CurrentWorldInteraction = nullptr; -} - -void FViewportWorldInteractionManager::AddReferencedObjects( FReferenceCollector& Collector ) -{ - Collector.AddReferencedObject( CurrentWorldInteraction ); -} - -bool FViewportWorldInteractionManager::PreprocessedInputKey( const FKey Key, const EInputEvent Event ) -{ - bool bResult = false; - if( CurrentWorldInteraction && CurrentWorldInteraction->IsActive() ) - { - bResult = CurrentWorldInteraction->PreprocessedInputKey( Key, Event ); - } - return bResult; -} - -bool FViewportWorldInteractionManager::PreprocessedInputAxis( const int32 ControllerId, const FKey Key, const float Delta, const float DeltaTime ) -{ - bool bResult = false; - if(CurrentWorldInteraction && CurrentWorldInteraction->IsActive() ) - { - bResult = CurrentWorldInteraction->PreprocessedInputAxis( ControllerId, Key, Delta, DeltaTime ); - } - return bResult; -} - -void FViewportWorldInteractionManager::SetCurrentViewportWorldInteraction( UViewportWorldInteraction* WorldInteraction ) -{ - CurrentWorldInteraction = WorldInteraction; -} diff --git a/Engine/Source/Editor/ViewportInteraction/ViewportWorldInteractionManager.h b/Engine/Source/Editor/ViewportInteraction/ViewportWorldInteractionManager.h deleted file mode 100644 index 3346b2d554c9..000000000000 --- a/Engine/Source/Editor/ViewportInteraction/ViewportWorldInteractionManager.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "CoreMinimal.h" -#include "InputCoreTypes.h" -#include "Engine/EngineBaseTypes.h" -#include "UObject/GCObject.h" -#include "Editor/ViewportInteraction/ViewportInteractionInputProcessor.h" -#include "IViewportWorldInteractionManager.h" - -class FViewportWorldInteractionManager: public FGCObject, public IViewportWorldInteractionManager -{ -public: - FViewportWorldInteractionManager(); - virtual ~FViewportWorldInteractionManager(); - - // FGCObject overrides - virtual void AddReferencedObjects( FReferenceCollector& Collector ) override; - - // IViewportWorldInteractionManager overrides - virtual void SetCurrentViewportWorldInteraction( class UViewportWorldInteraction* WorldInteraction ) override; - - // - // Input - // - - /** Passes the input key to the current world interaction */ - bool PreprocessedInputKey( const FKey Key, const EInputEvent Event ); - - /** Passes the input axis to the current world interaction */ - bool PreprocessedInputAxis( const int32 ControllerId, const FKey Key, const float Delta, const float DeltaTime ); - - -private: - - /** The current world interaction that is ticking */ - class UViewportWorldInteraction* CurrentWorldInteraction; - - // - // Input - // - - /** Slate Input Processor */ - TSharedPtr InputProcessor; -}; diff --git a/Engine/Source/Editor/WorldBrowser/Private/LevelCollectionModel.cpp b/Engine/Source/Editor/WorldBrowser/Private/LevelCollectionModel.cpp index 7c4115e06a5f..78aed5904132 100644 --- a/Engine/Source/Editor/WorldBrowser/Private/LevelCollectionModel.cpp +++ b/Engine/Source/Editor/WorldBrowser/Private/LevelCollectionModel.cpp @@ -29,6 +29,8 @@ #include "GameFramework/WorldSettings.h" #include "ShaderCompiler.h" +#include "FoliageEditModule.h" +#include "LevelUtils.h" #define LOCTEXT_NAMESPACE "WorldBrowser" @@ -622,6 +624,8 @@ void FLevelCollectionModel::UnloadLevels(const FLevelModelList& InLevelList) GLevelEditorModeTools().ActivateDefaultMode(); } + BroadcastPreLevelsUnloaded(); + // Take a copy of the list rather than using a reference to the selected levels list, as this will be modified in the loop below const FLevelModelList LevelListCopy = InLevelList; for (auto It = LevelListCopy.CreateConstIterator(); It; ++It) @@ -662,6 +666,8 @@ void FLevelCollectionModel::UnloadLevels(const FLevelModelList& InLevelList) } } + BroadcastPostLevelsUnloaded(); + GEditor->ResetTransaction( LOCTEXT("RemoveLevelTransReset", "Removing Levels from World") ); // Collect garbage to clear out the destroyed level @@ -719,9 +725,14 @@ void FLevelCollectionModel::AddExistingLevelsFromAssetData(const TArray FLevelCollectionModel::CreateDragDropOp() const +TSharedPtr FLevelCollectionModel::CreateDragDropOp() const { - return TSharedPtr(); + return MakeShareable( new WorldHierarchy::FWorldBrowserDragDropOp ); +} + +TSharedPtr FLevelCollectionModel::CreateDragDropOp(const FLevelModelList& InLevels) const +{ + return TSharedPtr(); } bool FLevelCollectionModel::PassesAllFilters(const FLevelModel& Item) const @@ -1032,6 +1043,16 @@ void FLevelCollectionModel::BroadcastHierarchyChanged() HierarchyChanged.Broadcast(); } +void FLevelCollectionModel::BroadcastPreLevelsUnloaded() +{ + PreLevelsUnloaded.Broadcast(); +} + +void FLevelCollectionModel::BroadcastPostLevelsUnloaded() +{ + PostLevelsUnloaded.Broadcast(); +} + float FLevelCollectionModel::EditableAxisLength() { return HALF_WORLD_MAX; @@ -1200,12 +1221,9 @@ void FLevelCollectionModel::SCCDiffAgainstDepot(const FLevelModelList& InList, U FString TempFileName; if (Revision->Get(TempFileName)) { - // Forcibly disable compile on load in case we are loading old blueprints that might try to update/compile - TGuardValue DisableCompileOnLoad(GForceDisableBlueprintCompileOnLoad, true); - // Try and load that package FText NotMapReason; - UPackage* OldPackage = LoadPackage(NULL, *TempFileName, LOAD_None); + UPackage* OldPackage = LoadPackage(NULL, *TempFileName, LOAD_DisableCompileOnLoad); if(OldPackage != NULL && InEditor->PackageIsAMapFile(*TempFileName, NotMapReason)) { /* Set the revision information*/ @@ -1632,7 +1650,7 @@ void FLevelCollectionModel::MoveActorsToSelected_Executed() MakeLevelCurrent_Executed(); const FScopedTransaction Transaction( LOCTEXT("MoveSelectedActorsToSelectedLevel", "Move Selected Actors to Level") ); - GEditor->MoveSelectedActorsToLevel(GetWorld()->GetCurrentLevel()); + UEditorLevelUtils::MoveSelectedActorsToLevel(GetWorld()->GetCurrentLevel()); RequestUpdateAllLevels(); } @@ -1642,7 +1660,13 @@ void FLevelCollectionModel::MoveFoliageToSelected_Executed() if (GetSelectedLevels().Num() == 1) { ULevel* TargetLevel = GetSelectedLevels()[0]->GetLevelObject(); - GEditor->MoveSelectedFoliageToLevel(TargetLevel); + + // Need to only permit this action when the foliage mode is open as the selection is being done there + if (GLevelEditorModeTools().IsModeActive(FBuiltinEditorModes::EM_Foliage)) + { + IFoliageEditModule& FoliageModule = FModuleManager::GetModuleChecked("FoliageEdit"); + FoliageModule.MoveSelectedFoliageToLevel(TargetLevel); + } } } diff --git a/Engine/Source/Editor/WorldBrowser/Private/LevelCollectionModel.h b/Engine/Source/Editor/WorldBrowser/Private/LevelCollectionModel.h index f298ed21ecff..1b422d606a74 100644 --- a/Engine/Source/Editor/WorldBrowser/Private/LevelCollectionModel.h +++ b/Engine/Source/Editor/WorldBrowser/Private/LevelCollectionModel.h @@ -6,7 +6,7 @@ #include "Framework/Commands/UICommandList.h" #include "Engine/World.h" #include "TickableEditorObject.h" -#include "DragAndDrop/LevelDragDropOp.h" +#include "WorldBrowserDragDrop.h" #include "Misc/IFilter.h" #include "LevelModel.h" @@ -133,7 +133,10 @@ public: virtual void AddExistingLevelsFromAssetData(const TArray& WorldList); /** Create drag drop operation for a selected level models */ - virtual TSharedPtr CreateDragDropOp() const; + virtual TSharedPtr CreateDragDropOp() const; + + /** Create a drag and drop operation for the specified level models */ + virtual TSharedPtr CreateDragDropOp(const FLevelModelList& InLevels) const; /** @return Whether specified level passes all filters */ virtual bool PassesAllFilters(const FLevelModel& InLevelModel) const; @@ -162,6 +165,9 @@ public: /** @return Whether this level collection model is a tile world */ virtual bool IsTileWorld() const { return false; }; + /** Returns true if this collection model will support folders */ + virtual bool HasFolderSupport() const { return false; } + /** Rebuilds levels collection */ void PopulateLevelsList(); @@ -265,6 +271,14 @@ public: /** Broadcasts whenever items hierarchy has changed */ FSimpleEvent HierarchyChanged; void BroadcastHierarchyChanged(); + + /** Broadcasts before levels are unloaded */ + FSimpleEvent PreLevelsUnloaded; + void BroadcastPreLevelsUnloaded(); + + /** Broadcasts after levels are unloaded */ + FSimpleEvent PostLevelsUnloaded; + void BroadcastPostLevelsUnloaded(); /** Editable world axis length */ static float EditableAxisLength(); diff --git a/Engine/Source/Editor/WorldBrowser/Private/LevelFolders.cpp b/Engine/Source/Editor/WorldBrowser/Private/LevelFolders.cpp new file mode 100644 index 000000000000..77e962852565 --- /dev/null +++ b/Engine/Source/Editor/WorldBrowser/Private/LevelFolders.cpp @@ -0,0 +1,391 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "LevelFolders.h" +#include "Misc/Crc.h" +#include "Misc/Paths.h" +#include "HAL/FileManager.h" +#include "Dom/JsonObject.h" +#include "Serialization/JsonReader.h" +#include "Serialization/JsonSerializer.h" +#include "ScopedTransaction.h" +#include "Engine/Level.h" +#include "Editor.h" + +#include "IWorldTreeItem.h" + +#define LOCTEXT_NAMESPACE "LevelFolders" + +/** Utility function to get a hashed filename for a level model */ +FString GetLevelModelFilename(TSharedPtr LevelModel) +{ + const FString LevelPackage = LevelModel->GetLongPackageName().ToString(); + const uint32 PackageNameCrc = FCrc::MemCrc32(*LevelPackage, sizeof(TCHAR)*LevelPackage.Len()); + return FPaths::Combine(*FPaths::GameSavedDir(), TEXT("Config"), TEXT("LevelState"), *FString::Printf(TEXT("%u.json"), PackageNameCrc)); +} + +FName OldPathToNewPath(const FString& InOldBranch, const FString& InNewBranch, const FString& PathToMove) +{ + return FName(*(InNewBranch + PathToMove.RightChop(InOldBranch.Len()))); +} + +FORCEINLINE FLevelModelKey GetLevelModelKey(TSharedRef LevelModel) +{ + ULevel* LevelObject = LevelModel->GetLevelObject(); + return LevelObject != nullptr ? *LevelObject->GetPathName() : FName(); +} + +void UEditorLevelFolders::Serialize(FArchive& Ar) +{ + Ar << Folders; +} + +FOnLevelFolderCreate FLevelFolders::OnFolderCreate; +FOnLevelFolderDelete FLevelFolders::OnFolderDelete; +FOnLevelFolderMove FLevelFolders::OnFolderMove; +FLevelFolders* FLevelFolders::Singleton = nullptr; + +FLevelFolders::FLevelFolders() +{ +} + +FLevelFolders::~FLevelFolders() +{ +} + +void FLevelFolders::AddReferencedObjects(FReferenceCollector& Collector) +{ + Collector.AddReferencedObjects(TemporaryLevelFolders); +} + +FLevelFolders& FLevelFolders::Get() +{ + check(Singleton != nullptr); + return *Singleton; +} + +void FLevelFolders::Init() +{ + Singleton = new FLevelFolders(); +} + +void FLevelFolders::Cleanup() +{ + delete Singleton; + Singleton = nullptr; +} + +void FLevelFolders::SaveLevel(TSharedRef LevelModel) +{ + Housekeeping(); + + // Attempt to save the folder state for the levels + const UEditorLevelFolders* const* Folders = TemporaryLevelFolders.Find(GetLevelModelKey(LevelModel)); + + if (Folders) + { + const FString Filename = GetLevelModelFilename(LevelModel); + TUniquePtr Ar(IFileManager::Get().CreateFileWriter(*Filename)); + + if (Ar) + { + TSharedRef RootObject = MakeShareable(new FJsonObject); + TSharedRef JsonFolders = MakeShareable(new FJsonObject); + + for (const auto& Pair : (*Folders)->Folders) + { + TSharedRef JsonFolder = MakeShareable(new FJsonObject); + JsonFolder->SetBoolField(TEXT("bExpanded"), Pair.Value.bExpanded); + + JsonFolders->SetObjectField(Pair.Key.ToString(), JsonFolder); + } + + RootObject->SetObjectField(TEXT("Folders"), JsonFolders); + { + auto Writer = TJsonWriterFactory::Create(Ar.Get()); + FJsonSerializer::Serialize(RootObject, Writer); + Ar->Close(); + } + } + } +} + +void FLevelFolders::Housekeeping() +{ + for (auto It = TemporaryModelObjects.CreateIterator(); It; ++It) + { + // If the level model or its associated level object are invalid, remove them from temporary folders + if (!It.Value().IsValid()) + { + TemporaryLevelFolders.Remove(It.Key()); + It.RemoveCurrent(); + } + } +} + +TMap& FLevelFolders::GetFolderProperties(TSharedRef LevelModel) +{ + return GetOrCreateFoldersForLevel(LevelModel).Folders; +} + +FLevelFolderProps* FLevelFolders::GetFolderProperties(TSharedRef LevelModel, FName InPath) +{ + return GetFolderProperties(LevelModel).Find(InPath); +} + +FName FLevelFolders::GetDefaultFolderName(TSharedRef LevelModel, FName ParentPath) +{ + // Gets the folder properties for the world to ensure a unique name + const TMap& Folders = GetFolderProperties(LevelModel); + + // Create a valid base name for the folder + uint32 NewFolderSuffix = 1; + FText NewFolderFormat = LOCTEXT("DefaultFolderNamePattern", "NewFolder{0}"); + + FString ParentFolderPath; + if (!ParentPath.IsNone()) + { + ParentFolderPath = ParentPath.ToString() + TEXT('/'); + } + + FName FolderName; + + do + { + FText LeafName = FText::Format(NewFolderFormat, FText::AsNumber(NewFolderSuffix++)); + FolderName = FName(*(ParentFolderPath + LeafName.ToString())); + + if (NewFolderSuffix == 0) + { + // If this happens, something's massively broken. + check(false); + } + } while (Folders.Contains(FolderName)); + + return FolderName; +} + +UEditorLevelFolders& FLevelFolders::GetOrCreateFoldersForLevel(TSharedRef LevelModel) +{ + if (UEditorLevelFolders** Folders = TemporaryLevelFolders.Find(GetLevelModelKey(LevelModel))) + { + return **Folders; + } + + return Initialize(LevelModel); +} + +void FLevelFolders::CreateFolder(TSharedRef LevelModel, FName InPath) +{ + FScopedTransaction Transaction(LOCTEXT("UndoAction_CreateFolder", "Create Folder")); + + if (AddFolder(LevelModel, InPath)) + { + OnFolderCreate.Broadcast(LevelModel, InPath); + } + else + { + Transaction.Cancel(); + } +} + +void FLevelFolders::RebuildFolderList(TSharedRef LevelModel) +{ + if (TemporaryLevelFolders.Contains(GetLevelModelKey(LevelModel))) + { + // Keep empty folders if we rebuild, since they have not been explicitly deleted + + for (TSharedPtr Child : LevelModel->GetChildren()) + { + AddFolder(LevelModel, Child->GetFolderPath()); + } + } + else + { + Initialize(LevelModel); + } +} + +void FLevelFolders::CreateFolderContainingSelectedLevels(TSharedRef WorldModel, TSharedRef LevelModel, FName InPath) +{ + const FScopedTransaction Transaction(LOCTEXT("UndoAction_CreateFolder", "Create Folder")); + CreateFolder(LevelModel, InPath); + SetSelectedLevelFolderPath(WorldModel, LevelModel, InPath); +} + +void FLevelFolders::SetSelectedLevelFolderPath(TSharedRef WorldModel, TSharedRef LevelModel, FName InPath) const +{ + FLevelModelList SelectedLevels = GetSelectedLevels(WorldModel, LevelModel); + + for (TSharedPtr Level : SelectedLevels) + { + Level->SetFolderPath(InPath); + } +} + +UEditorLevelFolders& FLevelFolders::Initialize(TSharedRef LevelModel) +{ + // Clean up stale levels + Housekeeping(); + + // Don't pass RF_Transactional to ConstructObject so that the creation of the object is not recorded by the undo buffer + UEditorLevelFolders* Folders = NewObject(GetTransientPackage(), NAME_None, RF_NoFlags); + Folders->SetFlags(RF_Transactional); // We still want to record changes made to the object, though + + FLevelModelKey LevelModelKey = GetLevelModelKey(LevelModel); + + // Only add the level model if it has a valid key + if (!LevelModelKey.IsNone()) + { + TemporaryLevelFolders.Add(LevelModelKey, Folders); + TemporaryModelObjects.Add(LevelModelKey, LevelModel); + + // Ensure the list is up to date + for (TSharedPtr ChildLevel : LevelModel->GetChildren()) + { + AddFolder(LevelModel, ChildLevel->GetFolderPath()); + } + + // Attempt to load the folder properties from config + const FString Filename = GetLevelModelFilename(LevelModel); + TUniquePtr Ar(IFileManager::Get().CreateFileReader(*Filename)); + if (Ar) + { + TSharedPtr RootObject = MakeShareable(new FJsonObject); + + auto Reader = TJsonReaderFactory::Create(Ar.Get()); + if (FJsonSerializer::Deserialize(Reader, RootObject)) + { + const TSharedPtr& JsonFolders = RootObject->GetObjectField("Folders"); + for (const auto& Pair : JsonFolders->Values) + { + // Only load properties for folders that still exist in the world + if (FLevelFolderProps* FolderInWorld = Folders->Folders.Find(FName(*Pair.Key))) + { + const TSharedPtr& FolderProps = Pair.Value->AsObject(); + FolderInWorld->bExpanded = FolderProps->GetBoolField(TEXT("bExpanded")); + } + } + } + } + } + + return *Folders; +} + +bool FLevelFolders::AddFolder(TSharedRef LevelModel, FName InPath) +{ + bool bFolderAdded = false; + + if (!InPath.IsNone()) + { + UEditorLevelFolders& LevelFolders = GetOrCreateFoldersForLevel(LevelModel); + + if (!LevelFolders.Folders.Contains(InPath)) + { + // Also add the parent path + AddFolder(LevelModel, WorldHierarchy::GetParentPath(InPath)); + + LevelFolders.Modify(); + LevelFolders.Folders.Add(InPath); + + bFolderAdded = true; + } + } + + return bFolderAdded; +} + +bool FLevelFolders::RenameFolder(TSharedRef LevelModel, FName OldPath, FName NewPath) +{ + const FString OldPathString = OldPath.ToString(); + const FString NewPathString = NewPath.ToString(); + + if (OldPath.IsNone() || NewPath.IsNone() || OldPath == NewPath || PathIsChildOf(NewPathString, OldPathString)) + { + return false; + } + + const FScopedTransaction Transaction(LOCTEXT("UndoAction_RenameFolder", "Rename Folder")); + + TSet RenamedFolders; + + // Move any folders we currently hold + UEditorLevelFolders& Folders = GetOrCreateFoldersForLevel(LevelModel); + Folders.Modify(); + + auto FoldersCopy = Folders.Folders; + for (const auto& Pair : FoldersCopy) + { + FName Path = Pair.Key; + + const FString FolderPath = Path.ToString(); + if (OldPath == Path || PathIsChildOf(FolderPath, OldPathString)) + { + const FName NewFolder = OldPathToNewPath(OldPathString, NewPathString, FolderPath); + if (!Folders.Folders.Contains(NewFolder)) + { + // Use the existing folder props if we have them + if (FLevelFolderProps* Props = Folders.Folders.Find(Path)) + { + Folders.Folders.Add(NewFolder, *Props); + } + else + { + Folders.Folders.Add(NewFolder); + } + OnFolderMove.Broadcast(LevelModel, Path, NewFolder); + OnFolderCreate.Broadcast(LevelModel, NewFolder); + } + RenamedFolders.Add(Path); + } + } + + // Delete old folders + for (const FName& Path : RenamedFolders) + { + Folders.Folders.Remove(Path); + OnFolderDelete.Broadcast(LevelModel, Path); + } + + return true; +} + +void FLevelFolders::DeleteFolder(TSharedRef LevelModel, FName FolderToDelete) +{ + const FScopedTransaction Transaction(LOCTEXT("UndoAction_DeleteFolder", "Delete Folder")); + + UEditorLevelFolders& Folders = GetOrCreateFoldersForLevel(LevelModel); + if (Folders.Folders.Contains(FolderToDelete)) + { + Folders.Modify(); + Folders.Folders.Remove(FolderToDelete); + OnFolderDelete.Broadcast(LevelModel, FolderToDelete); + } +} + +bool FLevelFolders::PathIsChildOf(const FString& InPotentialChild, const FString& InParent) +{ + const int32 ParentLen = InParent.Len(); + return InPotentialChild.Len() > ParentLen + && (InPotentialChild[ParentLen] == '/' || InPotentialChild[ParentLen] == '\\') + && InPotentialChild.Left(ParentLen) == InParent; +} + +FLevelModelList FLevelFolders::GetSelectedLevels(TSharedRef WorldModel, TSharedRef LevelModel) const +{ + FLevelModelList WorldModelSelectedLevels = WorldModel->GetSelectedLevels(); + FLevelModelList SelectedLevels; + + for (TSharedPtr Model : WorldModelSelectedLevels) + { + if (LevelModel->HasDescendant(Model)) + { + SelectedLevels.Add(Model); + } + } + + return SelectedLevels; +} + + +#undef LOCTEXT_NAMESPACE \ No newline at end of file diff --git a/Engine/Source/Editor/WorldBrowser/Private/LevelFolders.h b/Engine/Source/Editor/WorldBrowser/Private/LevelFolders.h new file mode 100644 index 000000000000..45771f595f2d --- /dev/null +++ b/Engine/Source/Editor/WorldBrowser/Private/LevelFolders.h @@ -0,0 +1,152 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "UObject/Object.h" +#include "UObject/WeakObjectPtr.h" +#include "UObject/GCObject.h" + +#include "LevelCollectionModel.h" + +#include "LevelFolders.generated.h" + +typedef FName FLevelModelKey; + +/** Broadcasted when an editor-only folder has been created for a level */ +DECLARE_MULTICAST_DELEGATE_TwoParams(FOnLevelFolderCreate, TSharedPtr, FName); + +/** Broadcasted when an editor-only folder for a level has been deleted */ +DECLARE_MULTICAST_DELEGATE_TwoParams(FOnLevelFolderDelete, TSharedPtr, FName); + +/** Broadcasted when an editor-only folder for a level has moved */ +DECLARE_MULTICAST_DELEGATE_ThreeParams(FOnLevelFolderMove, TSharedPtr, FName /* Source */, FName /* Destination */); + + +/** Properties for level folders */ +USTRUCT() +struct FLevelFolderProps +{ + GENERATED_USTRUCT_BODY() + + FLevelFolderProps() : bExpanded(true) {} + + /** Serializer */ + FORCEINLINE friend FArchive& operator<<(FArchive& Ar, FLevelFolderProps& Folder) + { + return Ar << Folder.bExpanded; + } + + bool bExpanded; +}; + + +/** Level folder UObject, for supporting undo/redo functionality */ +UCLASS() +class UEditorLevelFolders : public UObject +{ + GENERATED_BODY() + +public: + virtual void Serialize(FArchive& Ar) override; + + TMap Folders; +}; + + +/** The class for managing in-memory representations of level folders in the editor */ +struct FLevelFolders : public FGCObject +{ + FLevelFolders(); + ~FLevelFolders(); + +public: + + //~ FGCObject + virtual void AddReferencedObjects(FReferenceCollector& Collector) override; + +public: + + /** Checks if the singleton is valid */ + static bool IsAvailable() { return Singleton != nullptr; } + + /** Grants access to the singleton object if it's available */ + static FLevelFolders& Get(); + + /** Initialize the singleton */ + static void Init(); + + /** Clean up the singleton */ + static void Cleanup(); + + + /** Folder events */ + static FOnLevelFolderCreate OnFolderCreate; + static FOnLevelFolderDelete OnFolderDelete; + static FOnLevelFolderMove OnFolderMove; + + /** Gets all folder properties for a specified level */ + TMap& GetFolderProperties(TSharedRef LevelModel); + + /** Gets the folder properties for a specified path within the level */ + FLevelFolderProps* GetFolderProperties(TSharedRef LevelModel, FName InPath); + + /** Gets the default folder name for the given path. */ + FName GetDefaultFolderName(TSharedRef LevelModel, FName ParentPath); + + /** Creates a new folder with the given name for the current level selection */ + void CreateFolderContainingSelectedLevels(TSharedRef WorldModel, TSharedRef LevelModel, FName InPath); + + /** Creates a folder for the level model with the given path name */ + void CreateFolder(TSharedRef LevelModel, FName InPath); + + /** Renames a folder. The folder with the old name is removed from the folder props */ + bool RenameFolder(TSharedRef LevelModel, FName OldPath, FName NewPath); + + /** Deletes a folder and all saved properties */ + void DeleteFolder(TSharedRef LevelModel, FName FolderToDelete); + + /** Rebuilds the folder list for the level */ + void RebuildFolderList(TSharedRef LevelModel); + + /** Saves the level model when the world is saved */ + void SaveLevel(TSharedRef LevelModel); + +private: + + /** Sets the folder path for the current level selection */ + void SetSelectedLevelFolderPath(TSharedRef WorldModel, TSharedRef LevelModel, FName InPath) const; + + /** Remove references to folder arrays for unloaded levels */ + void Housekeeping(); + + /** Create a folder container for the specified level model */ + UEditorLevelFolders& InitializeForLevel(TSharedRef LevelModel); + + /** Checks if the supplied path is a descendant of the parent path */ + bool PathIsChildOf(const FString& InPotentialChild, const FString& InParent); + + /** Gets the folder information for the given level, or creates it if it's not in memory */ + UEditorLevelFolders& GetOrCreateFoldersForLevel(TSharedRef LevelModel); + + /** Creates new folder information for the level */ + UEditorLevelFolders& Initialize(TSharedRef LevelModel); + + /** Adds a folder for the level without triggering any events */ + bool AddFolder(TSharedRef LevelModel, FName InPath); + + /** Gets the selected levels in the world model */ + FLevelModelList GetSelectedLevels(TSharedRef WorldModel, TSharedRef LevelModel) const; + +private: + + /** Transient map of folders, keyed off level path name */ + TMap TemporaryLevelFolders; + + /** Maps level paths to level model objects, to clear out unloaded level model information when necessary */ + TMap> TemporaryModelObjects; + + /** Singleton object to be maintained by the world browser module */ + static FLevelFolders* Singleton; +}; \ No newline at end of file diff --git a/Engine/Source/Editor/WorldBrowser/Private/LevelModel.h b/Engine/Source/Editor/WorldBrowser/Private/LevelModel.h index f3c3e10ad17a..f1a9cb404560 100644 --- a/Engine/Source/Editor/WorldBrowser/Private/LevelModel.h +++ b/Engine/Source/Editor/WorldBrowser/Private/LevelModel.h @@ -20,6 +20,7 @@ class FLevelCollectionModel; */ struct FLevelModelVisitor { + virtual ~FLevelModelVisitor() { } virtual void Visit(FLevelModel& Item) = 0; }; @@ -203,6 +204,15 @@ public: /** @return Whether this model has in descendants specified level model */ bool HasDescendant(const TSharedPtr& InLevel) const; + /** Returns the folder path that the level should use when displayed in the world hierarchy */ + virtual FName GetFolderPath() const { return NAME_None; } + + /** Sets the folder path that the level should use when displayed in the world hierarchy */ + virtual void SetFolderPath(const FName& InFolderPath) {} + + /** Returns true if the level model can be added to hierarchy folders */ + virtual bool HasFolderSupport() const { return false; } + /** @return Handles drop operation */ virtual void OnDrop(const TSharedPtr& Op); diff --git a/Engine/Source/Editor/WorldBrowser/Private/SLevelsTreeWidget.cpp b/Engine/Source/Editor/WorldBrowser/Private/SLevelsTreeWidget.cpp new file mode 100644 index 000000000000..7cc89497d138 --- /dev/null +++ b/Engine/Source/Editor/WorldBrowser/Private/SLevelsTreeWidget.cpp @@ -0,0 +1,139 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "SLevelsTreeWidget.h" + +#include "EditorStyleSet.h" +#include "AssetDragDropOp.h" +#include "LevelCollectionModel.h" +#include "AssetSelection.h" +#include "LevelModel.h" +#include "LevelCollectionModel.h" +#include "WorldBrowserDragDrop.h" +#include "WorldTreeItemTypes.h" +#include "SWorldHierarchyImpl.h" + +#define LOCTEXT_NAMESPACE "WorldBrowser" + +void SLevelsTreeWidget::Construct(const FArguments& InArgs, const TSharedPtr& InWorldModel, const TSharedPtr& InHierarchy) +{ + STreeView>::Construct(InArgs); + + WorldModel = InWorldModel; + Hierarchy = InHierarchy; +} + +FReply SLevelsTreeWidget::OnDragOver(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) +{ + TSharedPtr HierarchyOp = DragDropEvent.GetOperationAs(); + + if (HierarchyOp.IsValid()) + { + // Assume that we're trying to attach the selection to the first persistent level + FLevelModelList Models = WorldModel->GetRootLevelList(); + check(Models.Num() > 0); + FText LevelName = FText::FromString(Models[0]->GetDisplayName()); + + FText ToolTipText = FText::Format(LOCTEXT("OnDragHierarchyItemsOver_Invalid", "Cannot attach selected items to {0}"), LevelName); + const FSlateBrush* ToolTipIcon = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); + + if (CanAttachAllItemsToRoot(HierarchyOp->GetDraggedItems())) + { + ToolTipText = FText::Format(LOCTEXT("OnDragHierarchyItemsOver_Success", "Attach selected items to {0}"), LevelName); + ToolTipIcon = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.OK")); + } + + HierarchyOp->SetToolTip(ToolTipText, ToolTipIcon); + + return FReply::Handled(); + } + else + { + TArray AssetList; + if (GetWorldAssetsFromDrag(DragDropEvent, AssetList) && DragDropEvent.GetOperation()->IsOfType()) + { + TSharedPtr< FAssetDragDropOp > AssetOp = DragDropEvent.GetOperationAs< FAssetDragDropOp >(); + AssetOp->SetToolTip(LOCTEXT("OnDragWorldAssetsOverFolder", "Add Level(s)"), FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.OK"))); + + return FReply::Handled(); + } + } + + return FReply::Unhandled(); +} + +void SLevelsTreeWidget::OnDragLeave(const FDragDropEvent& DragDropEvent) +{ + TSharedPtr HierarchyOp = DragDropEvent.GetOperationAs(); + TSharedPtr< FAssetDragDropOp > AssetOp = DragDropEvent.GetOperationAs< FAssetDragDropOp >(); + + if (AssetOp.IsValid()) + { + AssetOp->ResetToDefaultToolTip(); + } + else if (HierarchyOp.IsValid()) + { + HierarchyOp->ResetToDefaultToolTip(); + } +} + +FReply SLevelsTreeWidget::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) +{ + TSharedPtr HierarchyOp = DragDropEvent.GetOperationAs(); + + if (HierarchyOp.IsValid()) + { + TSharedPtr HierarchyPtr = Hierarchy.Pin(); + + if (HierarchyPtr.IsValid() && CanAttachAllItemsToRoot(HierarchyOp->GetDraggedItems())) + { + // Move any dropped items to the root + HierarchyPtr->MoveDroppedItems(HierarchyOp->GetDraggedItems(), NAME_None); + return FReply::Handled(); + } + } + else if (WorldModel.IsValid()) + { + // Handle adding dropped levels to world + TArray AssetList; + if (GetWorldAssetsFromDrag(DragDropEvent, AssetList)) + { + WorldModel->AddExistingLevelsFromAssetData(AssetList); + return FReply::Handled(); + } + } + + return FReply::Unhandled(); +} + +bool SLevelsTreeWidget::GetWorldAssetsFromDrag(const FDragDropEvent& DragDropEvent, TArray& OutWorldAssetList) +{ + TArray AssetList = AssetUtil::ExtractAssetDataFromDrag(DragDropEvent); + for (const auto& AssetData : AssetList) + { + if (AssetData.AssetClass == UWorld::StaticClass()->GetFName()) + { + OutWorldAssetList.Add(AssetData); + } + } + + return OutWorldAssetList.Num() > 0; +} + +bool SLevelsTreeWidget::CanAttachAllItemsToRoot(const TArray& Items) const +{ + bool bCanAttach = Items.Num() > 0; + + for (WorldHierarchy::FWorldTreeItemPtr Item : Items) + { + bCanAttach = Item->CanChangeParents(); + + if (!bCanAttach) + { + break; + } + } + + return bCanAttach; +} + +#undef LOCTEXT_NAMESPACE \ No newline at end of file diff --git a/Engine/Source/Editor/WorldBrowser/Private/SLevelsTreeWidget.h b/Engine/Source/Editor/WorldBrowser/Private/SLevelsTreeWidget.h new file mode 100644 index 000000000000..58b95e96a472 --- /dev/null +++ b/Engine/Source/Editor/WorldBrowser/Private/SLevelsTreeWidget.h @@ -0,0 +1,43 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "Layout/Visibility.h" +#include "Input/Reply.h" +#include "Widgets/SWidget.h" +#include "Widgets/DeclarativeSyntaxSupport.h" +#include "Widgets/SCompoundWidget.h" + +#include "Widgets/Views/STreeView.h" +#include "AssetData.h" + +#include "IWorldTreeItem.h" + +class FLevelModel; +class FLevelCollectionModel; +class SWorldHierarchyImpl; + +class SLevelsTreeWidget : public STreeView +{ +public: + void Construct(const FArguments& InArgs, const TSharedPtr& InWorldModel, const TSharedPtr& InHierachy); + + virtual FReply OnDragOver(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) override; + + virtual void OnDragLeave(const FDragDropEvent& DragDropEvent) override; + + virtual FReply OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) override; + +private: + /** Finds any world assets that are contained in the drag drop event and returns them in the supplied array. Returns true if a world asset was found */ + bool GetWorldAssetsFromDrag(const FDragDropEvent& DragDropEvent, TArray& OutWorldAssetList); + + /** Checks to see if all selected items can be moved. */ + bool CanAttachAllItemsToRoot(const TArray& Items) const; + +private: + TSharedPtr WorldModel; + + TWeakPtr Hierarchy; +}; \ No newline at end of file diff --git a/Engine/Source/Editor/WorldBrowser/Private/SWorldHierarchy.cpp b/Engine/Source/Editor/WorldBrowser/Private/SWorldHierarchy.cpp index 558fa4e47122..ee7ab173d8c2 100644 --- a/Engine/Source/Editor/WorldBrowser/Private/SWorldHierarchy.cpp +++ b/Engine/Source/Editor/WorldBrowser/Private/SWorldHierarchy.cpp @@ -1,621 +1,33 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #include "SWorldHierarchy.h" #include "Modules/ModuleManager.h" #include "Misc/PackageName.h" #include "Widgets/SBoxPanel.h" #include "Textures/SlateIcon.h" #include "Framework/Commands/UIAction.h" +#include "Framework/MultiBox/MultiBoxBuilder.h" #include "Widgets/Layout/SBorder.h" -#include "Widgets/Layout/SSeparator.h" #include "Widgets/Images/SImage.h" #include "Widgets/Text/STextBlock.h" -#include "Framework/MultiBox/MultiBoxBuilder.h" #include "Widgets/Input/SButton.h" #include "Widgets/Input/SComboButton.h" #include "Widgets/Views/SHeaderRow.h" #include "Widgets/Views/STableViewBase.h" #include "Widgets/Views/STableRow.h" -#include "Widgets/Views/STreeView.h" #include "EditorStyleSet.h" -#include "AssetData.h" #include "WorldBrowserModule.h" #include "LevelModel.h" #include "LevelCollectionModel.h" #include "LevelEditor.h" -#include "Misc/TextFilter.h" -#include "SWorldHierarchyItem.h" -#include "AssetSelection.h" #include "DragAndDrop/AssetDragDropOp.h" -#include "Widgets/Input/SSearchBox.h" + +#include "SWorldHierarchyImpl.h" #define LOCTEXT_NAMESPACE "WorldBrowser" -typedef TTextFilter LevelTextFilter; - -class SLevelsTreeWidget : public STreeView> -{ -public: - void Construct(const FArguments& InArgs, const TSharedPtr& InWorldModel) - { - STreeView>::Construct(InArgs); - - WorldModel = InWorldModel; - } - - void OnDragEnter(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) - { - TArray AssetList; - if ( GetWorldAssetsFromDrag(DragDropEvent, AssetList) ) - { - TSharedPtr< FAssetDragDropOp > DragDropOp = DragDropEvent.GetOperationAs< FAssetDragDropOp >(); - check(DragDropOp.IsValid()); - - DragDropOp->SetToolTip(LOCTEXT("OnDragWorldAssetsOverFolder", "Add Level(s)"), FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.OK"))); - } - } - - FReply OnDragOver(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) - { - TArray AssetList; - if (GetWorldAssetsFromDrag(DragDropEvent, AssetList)) - { - return FReply::Handled(); - } - - return FReply::Unhandled(); - } - - void OnDragLeave(const FDragDropEvent& DragDropEvent) - { - TSharedPtr< FAssetDragDropOp > DragDropOp = DragDropEvent.GetOperationAs< FAssetDragDropOp >(); - if (DragDropOp.IsValid()) - { - DragDropOp->ResetToDefaultToolTip(); - } - } - - FReply OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) - { - if ( WorldModel.IsValid() ) - { - // Handle adding dropped levels to world - TArray AssetList; - if ( GetWorldAssetsFromDrag(DragDropEvent, AssetList) ) - { - WorldModel->AddExistingLevelsFromAssetData(AssetList); - return FReply::Handled(); - } - } - - return FReply::Unhandled(); - } - -private: - bool GetWorldAssetsFromDrag(const FDragDropEvent& DragDropEvent, TArray& OutWorldAssetList) - { - TArray AssetList = AssetUtil::ExtractAssetDataFromDrag(DragDropEvent); - for (const auto& AssetData : AssetList) - { - if (AssetData.AssetClass == UWorld::StaticClass()->GetFName()) - { - OutWorldAssetList.Add(AssetData); - } - } - - return OutWorldAssetList.Num() > 0; - } - - TSharedPtr WorldModel; -}; - -//---------------------------------------------------------------- -// -// -//---------------------------------------------------------------- -class SWorldHierarchyImpl - : public SCompoundWidget -{ -public: - SLATE_BEGIN_ARGS(SWorldHierarchyImpl) {} - SLATE_ARGUMENT(TSharedPtr, InWorldModel) - SLATE_END_ARGS() - - SWorldHierarchyImpl() - : bUpdatingSelection(false) - { - } - - ~SWorldHierarchyImpl() - { - WorldModel->SelectionChanged.RemoveAll(this); - WorldModel->HierarchyChanged.RemoveAll(this); - WorldModel->CollectionChanged.RemoveAll(this); - } - - void Construct(const FArguments& InArgs) - { - WorldModel = InArgs._InWorldModel; - check(WorldModel.IsValid()); - - WorldModel->SelectionChanged.AddSP(this, &SWorldHierarchyImpl::OnUpdateSelection); - WorldModel->HierarchyChanged.AddSP(this, &SWorldHierarchyImpl::RefreshView); - WorldModel->CollectionChanged.AddSP(this, &SWorldHierarchyImpl::RefreshView); - - SearchBoxLevelFilter = MakeShareable(new LevelTextFilter( - LevelTextFilter::FItemToStringArray::CreateSP(this, &SWorldHierarchyImpl::TransformLevelToString) - )); - - HeaderRowWidget = - SNew( SHeaderRow ) - .Visibility(EVisibility::Collapsed) - - /** Level visibility column */ - + SHeaderRow::Column(HierarchyColumns::ColumnID_Visibility) - .FixedWidth(24.0f) - .HeaderContent() - [ - SNew(STextBlock) - .ToolTipText(NSLOCTEXT("WorldBrowser", "Visibility", "Visibility")) - ] - - /** LevelName label column */ - + SHeaderRow::Column( HierarchyColumns::ColumnID_LevelLabel ) - .FillWidth( 0.45f ) - .HeaderContent() - [ - SNew(STextBlock) - .ToolTipText(LOCTEXT("Column_LevelNameLabel", "Level")) - ] - - /** Lighting Scenario column */ - + SHeaderRow::Column( HierarchyColumns::ColumnID_LightingScenario ) - .FixedWidth( 18.0f ) - .HeaderContent() - [ - SNew(STextBlock) - .ToolTipText(NSLOCTEXT("WorldBrowser", "Lighting Scenario", "Lighting Scenario")) - ] - - - /** Level lock column */ - + SHeaderRow::Column( HierarchyColumns::ColumnID_Lock ) - .FixedWidth( 24.0f ) - .HeaderContent() - [ - SNew(STextBlock) - .ToolTipText(NSLOCTEXT("WorldBrowser", "Lock", "Lock")) - ] - - /** Level kismet column */ - + SHeaderRow::Column( HierarchyColumns::ColumnID_Kismet ) - .FixedWidth( 24.0f ) - .HeaderContent() - [ - SNew(STextBlock) - .ToolTipText(NSLOCTEXT("WorldBrowser", "Blueprint", "Open the level blueprint for this Level")) - ] - - /** Level SCC status column */ - + SHeaderRow::Column( HierarchyColumns::ColumnID_SCCStatus ) - .FixedWidth( 24.0f ) - .HeaderContent() - [ - SNew(STextBlock) - .ToolTipText(NSLOCTEXT("WorldBrowser", "SCCStatus", "Status in Source Control")) - ] - - /** Level save column */ - + SHeaderRow::Column( HierarchyColumns::ColumnID_Save ) - .FixedWidth( 24.0f ) - .HeaderContent() - [ - SNew(STextBlock) - .ToolTipText(NSLOCTEXT("WorldBrowser", "Save", "Save this Level")) - ] - - /** Level color column */ - + SHeaderRow::Column(HierarchyColumns::ColumnID_Color) - .FixedWidth(24.0f) - .HeaderContent() - [ - SNew(STextBlock) - .ToolTipText(NSLOCTEXT("WorldBrowser", "Color", "Color used for visualization of Level")) - ]; - - - ChildSlot - [ - SNew(SVerticalBox) - // Filter box - +SVerticalBox::Slot() - .AutoHeight() - [ - SNew( SSearchBox ) - .ToolTipText(LOCTEXT("FilterSearchToolTip", "Type here to search Levels")) - .HintText(LOCTEXT("FilterSearchHint", "Search Levels")) - .OnTextChanged(SearchBoxLevelFilter.Get(), &LevelTextFilter::SetRawFilterText) - ] - // Hierarchy - +SVerticalBox::Slot() - .FillHeight(1.f) - [ - SAssignNew(TreeWidget, SLevelsTreeWidget, WorldModel) - .TreeItemsSource(&WorldModel->GetRootLevelList()) - .SelectionMode(ESelectionMode::Multi) - .OnGenerateRow(this, &SWorldHierarchyImpl::GenerateTreeRow) - .OnGetChildren( this, &SWorldHierarchyImpl::GetChildrenForTree) - .OnSelectionChanged(this, &SWorldHierarchyImpl::OnSelectionChanged) - .OnExpansionChanged(this, &SWorldHierarchyImpl::OnExpansionChanged) - .OnMouseButtonDoubleClick(this, &SWorldHierarchyImpl::OnTreeViewMouseButtonDoubleClick) - .OnContextMenuOpening(this, &SWorldHierarchyImpl::ConstructLevelContextMenu) - .HeaderRow(HeaderRowWidget.ToSharedRef()) - ] - - // Separator - +SVerticalBox::Slot() - .AutoHeight() - .Padding(0, 0, 0, 1) - [ - SNew(SSeparator) - ] - - // View options - +SVerticalBox::Slot() - .AutoHeight() - [ - SNew(SHorizontalBox) - - // Asset count - +SHorizontalBox::Slot() - .FillWidth(1.f) - .VAlign(VAlign_Center) - .Padding(8, 0) - [ - SNew( STextBlock ) - .Text( this, &SWorldHierarchyImpl::GetFilterStatusText ) - .ColorAndOpacity( this, &SWorldHierarchyImpl::GetFilterStatusTextColor ) - ] - - // View mode combo button - +SHorizontalBox::Slot() - .AutoWidth() - [ - SAssignNew( ViewOptionsComboButton, SComboButton ) - .ContentPadding(0) - .ForegroundColor( this, &SWorldHierarchyImpl::GetViewButtonForegroundColor ) - .ButtonStyle( FEditorStyle::Get(), "ToggleButton" ) // Use the tool bar item style for this button - .OnGetMenuContent( this, &SWorldHierarchyImpl::GetViewButtonContent ) - .ButtonContent() - [ - SNew(SHorizontalBox) - - +SHorizontalBox::Slot() - .AutoWidth() - .VAlign(VAlign_Center) - [ - SNew(SImage).Image( FEditorStyle::GetBrush("GenericViewButton") ) - ] - - +SHorizontalBox::Slot() - .AutoWidth() - .Padding(2, 0, 0, 0) - .VAlign(VAlign_Center) - [ - SNew(STextBlock).Text( LOCTEXT("ViewButton", "View Options") ) - ] - ] - ] - ] - ]; - - WorldModel->AddFilter(SearchBoxLevelFilter.ToSharedRef()); - OnUpdateSelection(); - } - - /** Regenerates current items */ - void RefreshView() - { - TreeWidget->RequestTreeRefresh(); - - // Sync items expansion state - struct FExpander : public FLevelModelVisitor - { - TSharedPtr TreeWidget; - virtual void Visit(FLevelModel& Item) override - { - TreeWidget->SetItemExpansion(Item.AsShared(), Item.GetLevelExpansionFlag()); - }; - } Expander; - Expander.TreeWidget = TreeWidget; - - //Apply expansion - WorldModel->IterateHierarchy(Expander); - } - -private: - /** Creates an item for the tree view */ - TSharedRef GenerateTreeRow(TSharedPtr Item, const TSharedRef& OwnerTable) - { - check(Item.IsValid()); - - return SNew(SWorldHierarchyItem, OwnerTable) - .InWorldModel(WorldModel) - .InItemModel(Item) - .IsItemExpanded(this, &SWorldHierarchyImpl::IsTreeItemExpanded, Item) - .HighlightText(this, &SWorldHierarchyImpl::GetSearchBoxText); - - } - - /** Handler for returning a list of children associated with a particular tree node */ - void GetChildrenForTree(TSharedPtr Item, FLevelModelList& OutChildren) - { - OutChildren = Item->GetChildren(); - } - - /** @return the SWidget containing the context menu */ - TSharedPtr ConstructLevelContextMenu() const - { - if (!WorldModel->IsReadOnly()) - { - FMenuBuilder MenuBuilder(true, WorldModel->GetCommandList()); - WorldModel->BuildHierarchyMenu(MenuBuilder); - return MenuBuilder.MakeWidget(); - } - - return SNullWidget::NullWidget; - } - - /** Called by TreeView widget whenever tree item expanded or collapsed */ - void OnExpansionChanged(TSharedPtr Item, bool bIsItemExpanded) - { - Item->SetLevelExpansionFlag(bIsItemExpanded); - } - - /** Called by TreeView widget whenever selection is changed */ - void OnSelectionChanged(const TSharedPtr Item, ESelectInfo::Type SelectInfo) - { - if (bUpdatingSelection) - { - return; - } - - bUpdatingSelection = true; - WorldModel->SetSelectedLevels(TreeWidget->GetSelectedItems()); - bUpdatingSelection = false; - } - - /** Handles selection changes in data source */ - void OnUpdateSelection() - { - if (bUpdatingSelection) - { - return; - } - - bUpdatingSelection = true; - const auto& SelectedItems = WorldModel->GetSelectedLevels(); - TreeWidget->ClearSelection(); - for (auto It = SelectedItems.CreateConstIterator(); It; ++It) - { - TreeWidget->SetItemSelection(*It, true); - } - - if (SelectedItems.Num() == 1) - { - TreeWidget->RequestScrollIntoView(SelectedItems[0]); - } - - RefreshView(); - - bUpdatingSelection = false; - } - - /** - * Called by STreeView when the user double-clicks on an item - * - * @param Item The item that was double clicked - */ - void OnTreeViewMouseButtonDoubleClick(TSharedPtr Item) - { - Item->MakeLevelCurrent(); - } - - /** - * Checks to see if this widget supports keyboard focus. Override this in derived classes. - * - * @return True if this widget can take keyboard focus - */ - virtual bool SupportsKeyboardFocus() const override - { - return true; - } - - /** - * Called after a key is pressed when this widget has focus - * - * @param MyGeometry The Geometry of the widget receiving the event - * @param InKeyEvent Key event - * - * @return Returns whether the event was handled, along with other possible actions - */ - virtual FReply OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) override - { - if (WorldModel->GetCommandList()->ProcessCommandBindings(InKeyEvent)) - { - return FReply::Handled(); - } - - return SCompoundWidget::OnKeyDown(MyGeometry, InKeyEvent); - } - -private: - /** @returns Whether specified item should be expanded */ - bool IsTreeItemExpanded(TSharedPtr Item) const - { - return Item->GetLevelExpansionFlag(); - } - - /** Appends the Level's name to the OutSearchStrings array if the Level is valid */ - void TransformLevelToString(const FLevelModel* Level, TArray& OutSearchStrings) const - { - if (Level != nullptr && Level->HasValidPackage()) - { - OutSearchStrings.Add(FPackageName::GetShortName(Level->GetLongPackageName())); - } - } - - /** @return Text entered in search box */ - FText GetSearchBoxText() const - { - return SearchBoxLevelFilter->GetRawFilterText(); - } - - /** @return Returns the filter status text */ - FText GetFilterStatusText() const - { - const int32 SelectedLevelsCount = WorldModel->GetSelectedLevels().Num(); - const int32 TotalLevelsCount = WorldModel->GetAllLevels().Num(); - const int32 FilteredLevelsCount = WorldModel->GetFilteredLevels().Num(); - - if (!WorldModel->IsFilterActive()) - { - if (SelectedLevelsCount == 0) - { - return FText::Format( LOCTEXT("ShowingAllLevelsFmt", "{0} levels"), FText::AsNumber(TotalLevelsCount) ); - } - else - { - return FText::Format( LOCTEXT("ShowingAllLevelsSelectedFmt", "{0} levels ({1} selected)"), FText::AsNumber(TotalLevelsCount), FText::AsNumber(SelectedLevelsCount) ); - } - } - else if(WorldModel->IsFilterActive() && FilteredLevelsCount == 0) - { - return FText::Format( LOCTEXT("ShowingNoLevelsFmt", "No matching levels ({0} total)"), FText::AsNumber(TotalLevelsCount) ); - } - else if (SelectedLevelsCount != 0) - { - return FText::Format( LOCTEXT("ShowingOnlySomeLevelsSelectedFmt", "Showing {0} of {1} levels ({2} selected)"), FText::AsNumber(FilteredLevelsCount), FText::AsNumber(TotalLevelsCount), FText::AsNumber(SelectedLevelsCount) ); - } - else - { - return FText::Format( LOCTEXT("ShowingOnlySomeLevelsFmt", "Showing {0} of {1} levels"), FText::AsNumber(FilteredLevelsCount), FText::AsNumber(TotalLevelsCount) ); - } - } - - - /** @return Returns color for the filter status text message, based on success of search filter */ - FSlateColor GetFilterStatusTextColor() const - { - if (!WorldModel->IsFilterActive() ) - { - // White = no text filter - return FLinearColor( 1.0f, 1.0f, 1.0f ); - } - else if(WorldModel->GetFilteredLevels().Num() == 0) - { - // Red = no matching actors - return FLinearColor( 1.0f, 0.4f, 0.4f ); - } - else - { - // Green = found at least one match! - return FLinearColor( 0.4f, 1.0f, 0.4f ); - } - } - - /** @return the content for the view button */ - TSharedRef GetViewButtonContent() - { - FMenuBuilder MenuBuilder(true, NULL); - - MenuBuilder.BeginSection("SubLevelsViewMenu", LOCTEXT("ShowHeading", "Show")); - { - MenuBuilder.AddMenuEntry(LOCTEXT("ToggleDisplayPaths", "Display Paths"), - LOCTEXT("ToggleDisplayPaths_Tooltip", "If enabled, displays the path for each level"), - FSlateIcon(), - FUIAction( - FExecuteAction::CreateSP(this, &SWorldHierarchyImpl::ToggleDisplayPaths_Executed), - FCanExecuteAction(), - FIsActionChecked::CreateSP(this, &SWorldHierarchyImpl::GetDisplayPathsState)), - NAME_None, - EUserInterfaceActionType::ToggleButton - ); - - MenuBuilder.AddMenuEntry(LOCTEXT("ToggleDisplayActorsCount", "Display Actors Count"), - LOCTEXT("ToggleDisplayActorsCount_Tooltip", "If enabled, displays actors count for each level"), - FSlateIcon(), - FUIAction( - FExecuteAction::CreateSP(this, &SWorldHierarchyImpl::ToggleDisplayActorsCount_Executed), - FCanExecuteAction(), - FIsActionChecked::CreateSP(this, &SWorldHierarchyImpl::GetDisplayActorsCountState)), - NAME_None, - EUserInterfaceActionType::ToggleButton - ); - - } - MenuBuilder.EndSection(); - - return MenuBuilder.MakeWidget(); - } - - /** @return the foreground color for the view button */ - FSlateColor GetViewButtonForegroundColor() const - { - static const FName InvertedForegroundName("InvertedForeground"); - static const FName DefaultForegroundName("DefaultForeground"); - - return ViewOptionsComboButton->IsHovered() ? FEditorStyle::GetSlateColor(InvertedForegroundName) : FEditorStyle::GetSlateColor(DefaultForegroundName); - } - - /** Toggles state of 'display path' */ - void ToggleDisplayPaths_Executed() - { - WorldModel->SetDisplayPathsState(!WorldModel->GetDisplayPathsState()); - } - - /** Gets the state of the 'display paths' enabled/disabled */ - bool GetDisplayPathsState() const - { - return WorldModel->GetDisplayPathsState(); - } - - /** Toggles state of 'display actors count' */ - void ToggleDisplayActorsCount_Executed() - { - WorldModel->SetDisplayActorsCountState(!WorldModel->GetDisplayActorsCountState()); - } - - /** Gets the state of the 'display actors count' enabled/disabled */ - bool GetDisplayActorsCountState() const - { - return WorldModel->GetDisplayActorsCountState(); - } - -private: - /** Whether the view is currently updating the viewmodel selection */ - bool bUpdatingSelection; - /** Our list view widget */ - TSharedPtr TreeWidget; - - /** Items collection to display */ - TSharedPtr WorldModel; - - /** The Header Row for the hierarchy */ - TSharedPtr HeaderRowWidget; - - /** The LevelTextFilter that constrains which Levels appear in the hierarchy */ - TSharedPtr SearchBoxLevelFilter; - - /** Button representing view options on bottom */ - TSharedPtr ViewOptionsComboButton; -}; - -//---------------------------------------------------------------- -// -// -//---------------------------------------------------------------- SWorldHierarchy::SWorldHierarchy() { } @@ -752,7 +164,8 @@ void SWorldHierarchy::OnBrowseWorld(UWorld* InWorld) SNew(SBorder) .BorderImage(FEditorStyle::GetBrush(TEXT("ToolPanel.GroupBorder"))) [ - SNew(SWorldHierarchyImpl).InWorldModel(WorldModel) + SNew(SWorldHierarchyImpl) + .InWorldModel(WorldModel) ] ] ]; diff --git a/Engine/Source/Editor/WorldBrowser/Private/SWorldHierarchy.h b/Engine/Source/Editor/WorldBrowser/Private/SWorldHierarchy.h index 3fd62423853e..d86c0c50f6b0 100644 --- a/Engine/Source/Editor/WorldBrowser/Private/SWorldHierarchy.h +++ b/Engine/Source/Editor/WorldBrowser/Private/SWorldHierarchy.h @@ -11,10 +11,7 @@ class FLevelCollectionModel; struct FSlateBrush; -//---------------------------------------------------------------- -// -// -//---------------------------------------------------------------- + class SWorldHierarchy : public SCompoundWidget { diff --git a/Engine/Source/Editor/WorldBrowser/Private/SWorldHierarchyImpl.cpp b/Engine/Source/Editor/WorldBrowser/Private/SWorldHierarchyImpl.cpp new file mode 100644 index 000000000000..c223610482fb --- /dev/null +++ b/Engine/Source/Editor/WorldBrowser/Private/SWorldHierarchyImpl.cpp @@ -0,0 +1,1600 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "SWorldHierarchyImpl.h" +#include "SLevelsTreeWidget.h" +#include "SWorldHierarchyItem.h" +#include "SWorldHierarchy.h" + +#include "WorldBrowserModule.h" +#include "Modules/ModuleManager.h" + +#include "Framework/Application/SlateApplication.h" +#include "Framework/MultiBox/MultiBoxBuilder.h" +#include "Widgets/Layout/SSeparator.h" +#include "Widgets/Images/SImage.h" +#include "Widgets/Input/SComboButton.h" +#include "Widgets/Input/SSearchBox.h" +#include "Widgets/Input/SButton.h" + +#include "WorldTreeItemTypes.h" +#include "LevelFolders.h" +#include "ScopedTransaction.h" +#include "Editor.h" + +#define LOCTEXT_NAMESPACE "WorldBrowser" + +DEFINE_LOG_CATEGORY_STATIC(LogWorldHierarchy, Log, All); + +SWorldHierarchyImpl::SWorldHierarchyImpl() + : bUpdatingSelection(false) + , bIsReentrant(false) + , bFullRefresh(true) + , bNeedsRefresh(true) + , bRebuildFolders(false) + , bSortDirty(false) + , bFoldersOnlyMode(false) +{ +} + +SWorldHierarchyImpl::~SWorldHierarchyImpl() +{ + GEditor->UnregisterForUndo(this); + + WorldModel->SelectionChanged.RemoveAll(this); + WorldModel->HierarchyChanged.RemoveAll(this); + WorldModel->CollectionChanged.RemoveAll(this); + WorldModel->PreLevelsUnloaded.RemoveAll(this); + + if (FLevelFolders::IsAvailable()) + { + FLevelFolders& LevelFolders = FLevelFolders::Get(); + LevelFolders.OnFolderCreate.RemoveAll(this); + LevelFolders.OnFolderMove.RemoveAll(this); + LevelFolders.OnFolderDelete.RemoveAll(this); + } + + FEditorDelegates::PostSaveWorld.RemoveAll(this); +} + +void SWorldHierarchyImpl::Construct(const FArguments& InArgs) +{ + WorldModel = InArgs._InWorldModel; + check(WorldModel.IsValid()); + + WorldModel->SelectionChanged.AddSP(this, &SWorldHierarchyImpl::OnUpdateSelection); + WorldModel->HierarchyChanged.AddSP(this, &SWorldHierarchyImpl::RebuildFoldersAndFullRefresh); + WorldModel->CollectionChanged.AddSP(this, &SWorldHierarchyImpl::RebuildFoldersAndFullRefresh); + WorldModel->PreLevelsUnloaded.AddSP(this, &SWorldHierarchyImpl::OnBroadcastLevelsUnloaded); + + bFoldersOnlyMode = InArgs._ShowFoldersOnly; + ExcludedFolders = InArgs._InExcludedFolders; + OnItemPicked = InArgs._OnItemPickedDelegate; + + if (!bFoldersOnlyMode) + { + SearchBoxLevelFilter = MakeShareable(new LevelTextFilter( + LevelTextFilter::FItemToStringArray::CreateSP(this, &SWorldHierarchyImpl::TransformLevelToString) + )); + } + + SearchBoxHierarchyFilter = MakeShareable(new HierarchyFilter( + HierarchyFilter::FItemToStringArray::CreateSP(this, &SWorldHierarchyImpl::TransformItemToString) + )); + + // Might be overkill to have both filters call full refresh on change, but this should just request a full refresh + // twice instead of actually performing the refresh itself. + if (SearchBoxLevelFilter.IsValid()) + { + SearchBoxLevelFilter->OnChanged().AddSP(this, &SWorldHierarchyImpl::FullRefresh); + } + SearchBoxHierarchyFilter->OnChanged().AddSP(this, &SWorldHierarchyImpl::FullRefresh); + + HeaderRowWidget = + SNew( SHeaderRow ) + .Visibility(EVisibility::Collapsed) + + /** Level visibility column */ + + SHeaderRow::Column(HierarchyColumns::ColumnID_Visibility) + .Visibility(bFoldersOnlyMode ? EVisibility::Collapsed : EVisibility::Visible) + .FixedWidth(24.0f) + .HeaderContent() + [ + SNew(STextBlock) + .ToolTipText(NSLOCTEXT("WorldBrowser", "Visibility", "Visibility")) + ] + + /** LevelName label column */ + + SHeaderRow::Column( HierarchyColumns::ColumnID_LevelLabel ) + .FillWidth( 0.45f ) + .HeaderContent() + [ + SNew(STextBlock) + .ToolTipText(LOCTEXT("Column_LevelNameLabel", "Level")) + + ] + + /** Lighting Scenario column */ + + SHeaderRow::Column(HierarchyColumns::ColumnID_LightingScenario) + .Visibility(bFoldersOnlyMode ? EVisibility::Collapsed : EVisibility::Visible) + .FixedWidth( 18.0f ) + .HeaderContent() + [ + SNew(STextBlock) + .ToolTipText(NSLOCTEXT("WorldBrowser", "Lighting Scenario", "Lighting Scenario")) + ] + + + /** Level lock column */ + +SHeaderRow::Column(HierarchyColumns::ColumnID_Lock) + .Visibility(bFoldersOnlyMode ? EVisibility::Collapsed : EVisibility::Visible) + .FixedWidth( 24.0f ) + .HeaderContent() + [ + SNew(STextBlock) + .ToolTipText(NSLOCTEXT("WorldBrowser", "Lock", "Lock")) + ] + + /** Level kismet column */ + + SHeaderRow::Column(HierarchyColumns::ColumnID_Kismet) + .Visibility(bFoldersOnlyMode ? EVisibility::Collapsed : EVisibility::Visible) + .FixedWidth( 24.0f ) + .HeaderContent() + [ + SNew(STextBlock) + .ToolTipText(NSLOCTEXT("WorldBrowser", "Blueprint", "Open the level blueprint for this Level")) + ] + + /** Level SCC status column */ + + SHeaderRow::Column(HierarchyColumns::ColumnID_SCCStatus) + .Visibility(bFoldersOnlyMode ? EVisibility::Collapsed : EVisibility::Visible) + .FixedWidth( 24.0f ) + .HeaderContent() + [ + SNew(STextBlock) + .ToolTipText(NSLOCTEXT("WorldBrowser", "SCCStatus", "Status in Source Control")) + ] + + /** Level save column */ + + SHeaderRow::Column(HierarchyColumns::ColumnID_Save) + .Visibility(bFoldersOnlyMode ? EVisibility::Collapsed : EVisibility::Visible) + .FixedWidth( 24.0f ) + .HeaderContent() + [ + SNew(STextBlock) + .ToolTipText(NSLOCTEXT("WorldBrowser", "Save", "Save this Level")) + ] + + /** Level color column */ + + SHeaderRow::Column(HierarchyColumns::ColumnID_Color) + .Visibility(bFoldersOnlyMode ? EVisibility::Collapsed : EVisibility::Visible) + .FixedWidth(24.0f) + .HeaderContent() + [ + SNew(STextBlock) + .ToolTipText(NSLOCTEXT("WorldBrowser", "Color", "Color used for visualization of Level")) + ]; + + + FOnContextMenuOpening ContextMenuEvent; + if (!bFoldersOnlyMode) + { + ContextMenuEvent = FOnContextMenuOpening::CreateSP(this, &SWorldHierarchyImpl::ConstructLevelContextMenu); + } + + TSharedRef CreateNewFolderButton = SNullWidget::NullWidget; + if (!bFoldersOnlyMode) + { + CreateNewFolderButton = SNew(SButton) + .ButtonStyle(FEditorStyle::Get(), "HoverHintOnly") + .ToolTipText(LOCTEXT("CreateFolderTooltip", "Create a new folder containing the current selection")) + .OnClicked(this, &SWorldHierarchyImpl::OnCreateFolderClicked) + .Visibility(WorldModel->HasFolderSupport() ? EVisibility::Visible : EVisibility::Collapsed) + [ + SNew(SImage) + .Image(FEditorStyle::GetBrush("WorldBrowser.NewFolderIcon")) + ]; + } + + ChildSlot + [ + SNew(SVerticalBox) + // Hierarchy Toolbar + +SVerticalBox::Slot() + .AutoHeight() + [ + SNew(SHorizontalBox) + + // Filter box + + SHorizontalBox::Slot() + .FillWidth(1.0f) + [ + SNew(SSearchBox) + .ToolTipText(LOCTEXT("FilterSearchToolTip", "Type here to search Levels")) + .HintText(LOCTEXT("FilterSearchHint", "Search Levels")) + .OnTextChanged(this, &SWorldHierarchyImpl::SetFilterText) + ] + + // Create New Folder icon + + SHorizontalBox::Slot() + .AutoWidth() + .Padding(4.0f, 0.0f, 0.0f, 0.0f) + [ + CreateNewFolderButton + ] + ] + // Empty Label + +SVerticalBox::Slot() + .HAlign(HAlign_Center) + [ + SNew(STextBlock) + .Visibility(this, &SWorldHierarchyImpl::GetEmptyLabelVisibility) + .Text(LOCTEXT("EmptyLabel", "Empty")) + .ColorAndOpacity(FLinearColor(0.4f, 1.0f, 0.4f)) + ] + + // Hierarchy + +SVerticalBox::Slot() + .FillHeight(1.f) + [ + SAssignNew(TreeWidget, SLevelsTreeWidget, WorldModel, SharedThis(this)) + .TreeItemsSource(&RootTreeItems) + .SelectionMode(ESelectionMode::Multi) + .OnGenerateRow(this, &SWorldHierarchyImpl::GenerateTreeRow) + .OnGetChildren(this, &SWorldHierarchyImpl::GetChildrenForTree) + .OnSelectionChanged(this, &SWorldHierarchyImpl::OnSelectionChanged) + .OnExpansionChanged(this, &SWorldHierarchyImpl::OnExpansionChanged) + .OnMouseButtonDoubleClick(this, &SWorldHierarchyImpl::OnTreeViewMouseButtonDoubleClick) + .OnContextMenuOpening(ContextMenuEvent) + .OnItemScrolledIntoView(this, &SWorldHierarchyImpl::OnTreeItemScrolledIntoView) + .HeaderRow(HeaderRowWidget.ToSharedRef()) + ] + + // Separator + +SVerticalBox::Slot() + .AutoHeight() + .Padding(0, 0, 0, 1) + [ + SNew(SSeparator) + .Visibility(bFoldersOnlyMode ? EVisibility::Collapsed : EVisibility::Visible) + ] + + // View options + +SVerticalBox::Slot() + .AutoHeight() + [ + SNew(SHorizontalBox) + .Visibility(bFoldersOnlyMode ? EVisibility::Collapsed : EVisibility::Visible) + + // Asset count + +SHorizontalBox::Slot() + .FillWidth(1.f) + .VAlign(VAlign_Center) + .Padding(8, 0) + [ + SNew( STextBlock ) + .Text( this, &SWorldHierarchyImpl::GetFilterStatusText ) + .ColorAndOpacity( this, &SWorldHierarchyImpl::GetFilterStatusTextColor ) + ] + + // View mode combo button + +SHorizontalBox::Slot() + .AutoWidth() + [ + SAssignNew( ViewOptionsComboButton, SComboButton ) + .ContentPadding(0) + .ForegroundColor( this, &SWorldHierarchyImpl::GetViewButtonForegroundColor ) + .ButtonStyle( FEditorStyle::Get(), "ToggleButton" ) // Use the tool bar item style for this button + .OnGetMenuContent( this, &SWorldHierarchyImpl::GetViewButtonContent ) + .ButtonContent() + [ + SNew(SHorizontalBox) + + +SHorizontalBox::Slot() + .AutoWidth() + .VAlign(VAlign_Center) + [ + SNew(SImage).Image( FEditorStyle::GetBrush("GenericViewButton") ) + ] + + +SHorizontalBox::Slot() + .AutoWidth() + .Padding(2, 0, 0, 0) + .VAlign(VAlign_Center) + [ + SNew(STextBlock).Text( LOCTEXT("ViewButton", "View Options") ) + ] + ] + ] + ] + ]; + + if (FLevelFolders::IsAvailable()) + { + FLevelFolders& LevelFolders = FLevelFolders::Get(); + LevelFolders.OnFolderCreate.AddSP(this, &SWorldHierarchyImpl::OnBroadcastFolderCreate); + LevelFolders.OnFolderMove.AddSP(this, &SWorldHierarchyImpl::OnBroadcastFolderMove); + LevelFolders.OnFolderDelete.AddSP(this, &SWorldHierarchyImpl::OnBroadcastFolderDelete); + + if (!bFoldersOnlyMode) + { + FEditorDelegates::PostSaveWorld.AddSP(this, &SWorldHierarchyImpl::OnWorldSaved); + } + } + + if (SearchBoxLevelFilter.IsValid()) + { + WorldModel->AddFilter(SearchBoxLevelFilter.ToSharedRef()); + } + + OnUpdateSelection(); + + GEditor->RegisterForUndo(this); +} + +void SWorldHierarchyImpl::Tick( const FGeometry& AllotedGeometry, const double InCurrentTime, const float InDeltaTime ) +{ + SCompoundWidget::Tick(AllotedGeometry, InCurrentTime, InDeltaTime); + + if (bNeedsRefresh) + { + if (!bIsReentrant) + { + Populate(); + } + } + + if (bSortDirty) + { + SortItems(RootTreeItems); + for (const auto& Pair : TreeItemMap) + { + Pair.Value->Flags.bChildrenRequiresSort = true; + } + + bSortDirty = false; + } +} + +void SWorldHierarchyImpl::OnWorldSaved(uint32 SaveFlags, UWorld* World, bool bSuccess) +{ + if (FLevelFolders::IsAvailable()) + { + for (TSharedPtr RootLevel : WorldModel->GetRootLevelList()) + { + FLevelFolders::Get().SaveLevel(RootLevel.ToSharedRef()); + } + } +} + +void SWorldHierarchyImpl::RefreshView() +{ + bNeedsRefresh = true; +} + +TSharedRef SWorldHierarchyImpl::GenerateTreeRow(WorldHierarchy::FWorldTreeItemPtr Item, const TSharedRef& OwnerTable) +{ + check(Item.IsValid()); + + return SNew(SWorldHierarchyItem, OwnerTable) + .InWorldModel(WorldModel) + .InHierarchy(SharedThis(this)) + .InItemModel(Item) + .IsItemExpanded(Item->Flags.bExpanded) + .HighlightText(this, &SWorldHierarchyImpl::GetSearchBoxText) + .FoldersOnlyMode(bFoldersOnlyMode) + ; +} + +void SWorldHierarchyImpl::GetChildrenForTree(WorldHierarchy::FWorldTreeItemPtr Item, TArray& OutChildren) +{ + OutChildren = Item->GetChildren(); + + if (Item->Flags.bChildrenRequiresSort) + { + if (OutChildren.Num() > 0) + { + SortItems(OutChildren); + + // Empty out the children and repopulate them in the correct order + Item->RemoveAllChildren(); + + for (WorldHierarchy::FWorldTreeItemPtr Child : OutChildren) + { + Item->AddChild(Child.ToSharedRef()); + } + } + + Item->Flags.bChildrenRequiresSort = false; + } +} + +bool SWorldHierarchyImpl::PassesFilter(const WorldHierarchy::IWorldTreeItem& Item) +{ + bool bPassesFilter = true; + + WorldHierarchy::FFolderTreeItem* Folder = Item.GetAsFolderTreeItem(); + + if (bFoldersOnlyMode && Folder == nullptr) + { + // Level items should fail to pass the filter if we only want to display folders + bPassesFilter = false; + } + else + { + bPassesFilter = SearchBoxHierarchyFilter->PassesFilter(Item); + } + + if (bPassesFilter && ExcludedFolders.Num() > 0) + { + if (Folder != nullptr) + { + FName CheckPath = Folder->GetFullPath(); + + // Folders should not be shown if it or its parent have been excluded + while (!CheckPath.IsNone()) + { + if (ExcludedFolders.Contains(CheckPath)) + { + bPassesFilter = false; + break; + } + + CheckPath = WorldHierarchy::GetParentPath(CheckPath); + } + } + } + + return bPassesFilter; +} + +TSharedPtr SWorldHierarchyImpl::ConstructLevelContextMenu() const +{ + TSharedRef MenuWidget = SNullWidget::NullWidget; + + if (!WorldModel->IsReadOnly()) + { + FMenuBuilder MenuBuilder(true, WorldModel->GetCommandList()); + + TArray SelectedItems = GetSelectedTreeItems(); + + if (SelectedItems.Num() == 1) + { + // If exactly one item is selected, allow it to generate its own context menu + SelectedItems[0]->GenerateContextMenu(MenuBuilder, *this); + } + else if (SelectedItems.Num() == 0) + { + // If no items are selected, allow the first root level item to create a context menu + RootTreeItems[0]->GenerateContextMenu(MenuBuilder, *this); + } + + WorldModel->BuildHierarchyMenu(MenuBuilder); + + // Generate the "Move To" and "Select" submenus based on the current selection + if (WorldModel->HasFolderSupport()) + { + bool bOnlyFoldersSelected = SelectedItems.Num() > 0; + bool bAllSelectedItemsCanMove = SelectedItems.Num() > 0; + + for (WorldHierarchy::FWorldTreeItemPtr Item : SelectedItems) + { + bOnlyFoldersSelected &= Item->GetAsFolderTreeItem() != nullptr; + bAllSelectedItemsCanMove &= Item->CanChangeParents(); + + if (!bOnlyFoldersSelected && !bAllSelectedItemsCanMove) + { + // Neither submenu can be built, kill the check + break; + } + } + + if (bAllSelectedItemsCanMove && FLevelFolders::IsAvailable()) + { + MenuBuilder.AddSubMenu( + LOCTEXT("MoveSelectionTo", "Move To"), + LOCTEXT("MoveSelectionTo_Tooltip", "Move selection to another folder"), + FNewMenuDelegate::CreateSP(this, &SWorldHierarchyImpl::FillFoldersSubmenu) + ); + } + + if (bOnlyFoldersSelected) + { + MenuBuilder.AddSubMenu( + LOCTEXT("SelectSubmenu", "Select"), + LOCTEXT("SelectSubmenu_Tooltip", "Select child items of the current selection"), + FNewMenuDelegate::CreateSP(this, &SWorldHierarchyImpl::FillSelectionSubmenu) + ); + } + } + + MenuWidget = MenuBuilder.MakeWidget(); + } + + return MenuWidget; +} + +void SWorldHierarchyImpl::FillFoldersSubmenu(FMenuBuilder& MenuBuilder) +{ + TArray SelectedItems = GetSelectedTreeItems(); + check(SelectedItems.Num() > 0); + + // Assume that the root item of the first selected item is the root for all of them + TSharedPtr RootItem = SelectedItems[0]->GetRootItem(); + FName RootPath = NAME_None; + + MenuBuilder.AddMenuEntry( + LOCTEXT("CreateNewFolder", "Create New Folder"), + LOCTEXT("CreateNewFolder_Tooltip", "Move the selection to a new folder"), + FSlateIcon(FEditorStyle::GetStyleSetName(), "WorldBrowser.NewFolderIcon"), + FExecuteAction::CreateSP(this, &SWorldHierarchyImpl::CreateFolder, RootItem, RootPath) + ); + + AddMoveToFolderOutliner(MenuBuilder, SelectedItems, RootItem.ToSharedRef()); +} + +void SWorldHierarchyImpl::AddMoveToFolderOutliner(FMenuBuilder& MenuBuilder, const TArray& SelectedItems, TSharedRef RootItem) +{ + FLevelFolders& LevelFolders = FLevelFolders::Get(); + + if (LevelFolders.GetFolderProperties(RootItem).Num() > 0) + { + TSet ExcludedFolderPaths; + + // Exclude selected folders + for (WorldHierarchy::FWorldTreeItemPtr Item : SelectedItems) + { + if (WorldHierarchy::FFolderTreeItem* Folder = Item->GetAsFolderTreeItem()) + { + ExcludedFolderPaths.Add(Folder->GetFullPath()); + } + } + + // Copy the world model to ensure that any delegates fired for the mini hierarchy doesn't affect the main hierarchy + FWorldBrowserModule& WorldBrowserModule = FModuleManager::LoadModuleChecked("WorldBrowser"); + TSharedPtr WorldModelCopy = WorldBrowserModule.SharedWorldModel(WorldModel->GetWorld()); + + TSharedRef MiniHierarchy = + SNew(SVerticalBox) + + SVerticalBox::Slot() + .MaxHeight(400.0f) + [ + SNew(SWorldHierarchyImpl) + .InWorldModel(WorldModelCopy) + .ShowFoldersOnly(true) + .InExcludedFolders(ExcludedFolderPaths) + .OnItemPickedDelegate(FOnWorldHierarchyItemPicked::CreateSP(this, &SWorldHierarchyImpl::MoveSelectionTo)) + ]; + + MenuBuilder.BeginSection(FName(), LOCTEXT("ExistingFolders", "Existing:")); + MenuBuilder.AddWidget(MiniHierarchy, FText::GetEmpty(), false); + MenuBuilder.EndSection(); + } +} + +void SWorldHierarchyImpl::MoveSelectionTo(WorldHierarchy::FWorldTreeItemRef Item) +{ + FSlateApplication::Get().DismissAllMenus(); + + TSharedPtr RootLevel = Item->GetRootItem(); + FName Path = NAME_None; + + if (WorldHierarchy::FFolderTreeItem* Folder = Item->GetAsFolderTreeItem()) + { + Path = Folder->GetFullPath(); + } + + MoveItemsTo(RootLevel, Path); + + RefreshView(); +} + +void SWorldHierarchyImpl::FillSelectionSubmenu(FMenuBuilder& MenuBuilder) +{ + const bool bSelectAllDescendants = true; + + MenuBuilder.AddMenuEntry( + LOCTEXT("SelectImmediateChildren", "Immediate Children"), + LOCTEXT("SelectImmediateChildren_Tooltip", "Select all immediate children of the selected folders"), + FSlateIcon(), + FExecuteAction::CreateSP(this, &SWorldHierarchyImpl::SelectFolderDescendants, !bSelectAllDescendants) + ); + + MenuBuilder.AddMenuEntry( + LOCTEXT("SelectAllDescendants", "All Descendants"), + LOCTEXT("SelectAllDescendants_Tooltip", "Selects all descendants of the selected folders"), + FSlateIcon(), + FExecuteAction::CreateSP(this, &SWorldHierarchyImpl::SelectFolderDescendants, bSelectAllDescendants) + ); +} + +void SWorldHierarchyImpl::SelectFolderDescendants(bool bSelectAllDescendants) +{ + TArray OldSelection = GetSelectedTreeItems(); + FLevelModelList SelectedLevels; + + TreeWidget->ClearSelection(); + + for (WorldHierarchy::FWorldTreeItemPtr Item : OldSelection) + { + for (WorldHierarchy::FWorldTreeItemPtr Child : Item->GetChildren()) + { + if (bSelectAllDescendants) + { + SelectedLevels.Append(Child->GetLevelModels()); + } + else + { + SelectedLevels.Append(Child->GetModel()); + } + } + } + + if (SelectedLevels.Num() > 0) + { + WorldModel->SetSelectedLevels(SelectedLevels); + } +} + +void SWorldHierarchyImpl::MoveDroppedItems(const TArray& DraggedItems, FName FolderPath) +{ + if (DraggedItems.Num() > 0) + { + // Ensure that the dragged items are selected in the tree + TreeWidget->ClearSelection(); + + for (WorldHierarchy::FWorldTreeItemPtr Item : DraggedItems) + { + TreeWidget->SetItemSelection(Item, true); + } + + // Assume that the root of the first is the root of all the items + const FScopedTransaction Transaction(LOCTEXT("ItemsMoved", "Move World Hierarchy Items")); + MoveItemsTo(DraggedItems[0]->GetRootItem(), FolderPath); + + RefreshView(); + } +} + +void SWorldHierarchyImpl::AddDroppedLevelsToFolder(const TArray& WorldAssetList, FName FolderPath) +{ + if (WorldAssetList.Num() > 0) + { + // Populate the set of existing levels in the world + TSet ExistingLevels; + for (TSharedPtr Level : WorldModel->GetAllLevels()) + { + ExistingLevels.Add(Level->GetLongPackageName()); + } + + WorldModel->AddExistingLevelsFromAssetData(WorldAssetList); + + // Set the folder path of any newly added levels + for (TSharedPtr Level : WorldModel->GetAllLevels()) + { + if (!ExistingLevels.Contains(Level->GetLongPackageName())) + { + Level->SetFolderPath(FolderPath); + } + } + + RefreshView(); + } +} + +void SWorldHierarchyImpl::OnTreeItemScrolledIntoView( WorldHierarchy::FWorldTreeItemPtr Item, const TSharedPtr& Widget ) +{ + if (Item == ItemPendingRename) + { + ItemPendingRename = nullptr; + Item->RenameRequestEvent.ExecuteIfBound(); + } +} + +void SWorldHierarchyImpl::OnExpansionChanged(WorldHierarchy::FWorldTreeItemPtr Item, bool bIsItemExpanded) +{ + Item->SetExpansion(bIsItemExpanded); + + WorldHierarchy::FFolderTreeItem* Folder = Item->GetAsFolderTreeItem(); + if (FLevelFolders::IsAvailable() && Folder != nullptr) + { + if (FLevelFolderProps* Props = FLevelFolders::Get().GetFolderProperties(Item->GetRootItem().ToSharedRef(), Folder->GetFullPath())) + { + Props->bExpanded = Item->Flags.bExpanded; + } + } + + RefreshView(); +} + +void SWorldHierarchyImpl::OnSelectionChanged(const WorldHierarchy::FWorldTreeItemPtr Item, ESelectInfo::Type SelectInfo) +{ + if (bUpdatingSelection) + { + return; + } + + bUpdatingSelection = true; + + TArray SelectedItems = GetSelectedTreeItems(); + FLevelModelList SelectedLevels; + + for (const WorldHierarchy::FWorldTreeItemPtr& TreeItem : SelectedItems) + { + SelectedLevels.Append(TreeItem->GetModel()); + } + + if (!bFoldersOnlyMode) + { + WorldModel->SetSelectedLevels(SelectedLevels); + } + bUpdatingSelection = false; + + if (TreeWidget->GetNumItemsSelected() > 0) + { + OnItemPicked.ExecuteIfBound(GetSelectedTreeItems()[0].ToSharedRef()); + } +} + +void SWorldHierarchyImpl::OnUpdateSelection() +{ + if (bUpdatingSelection) + { + return; + } + + bUpdatingSelection = true; + + ItemsSelectedAfterRefresh.Empty(); + TArray SelectedItems = GetSelectedTreeItems(); + + for (WorldHierarchy::FWorldTreeItemPtr Item : SelectedItems) + { + ItemsSelectedAfterRefresh.Add(Item->GetID()); + } + + RefreshView(); + + bUpdatingSelection = false; +} + +void SWorldHierarchyImpl::OnTreeViewMouseButtonDoubleClick(WorldHierarchy::FWorldTreeItemPtr Item) +{ + if (Item->CanBeCurrent()) + { + Item->MakeCurrent(); + } + else + { + Item->SetExpansion(!Item->Flags.bExpanded); + TreeWidget->SetItemExpansion(Item, Item->Flags.bExpanded); + } +} + +FReply SWorldHierarchyImpl::OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) +{ + if (WorldModel->GetCommandList()->ProcessCommandBindings(InKeyEvent)) + { + return FReply::Handled(); + } + else if ( InKeyEvent.GetKey() == EKeys::F2 ) + { + // If a single folder is selected, F2 should attempt to rename it + if (TreeWidget->GetNumItemsSelected() == 1) + { + WorldHierarchy::FWorldTreeItemPtr ItemToRename = GetSelectedTreeItems()[0]; + + if (ItemToRename->GetAsFolderTreeItem() != nullptr) + { + ItemPendingRename = ItemToRename; + ScrollItemIntoView(ItemToRename); + + return FReply::Handled(); + } + } + } + else if ( InKeyEvent.GetKey() == EKeys::Platform_Delete ) + { + // Delete was pressed, but no levels were unloaded. Any selected folders should be removed transactionally + const bool bTransactional = true; + DeleteFolders(GetSelectedTreeItems(), bTransactional); + } + // F5 (Refresh) should be handled by the world model + + return SCompoundWidget::OnKeyDown(MyGeometry, InKeyEvent); +} + +void SWorldHierarchyImpl::OnBroadcastLevelsUnloaded() +{ + // We deleted levels from the hierarchy, so do not record the folder delete transaction either + const bool bTransactional = false; + DeleteFolders(GetSelectedTreeItems(), bTransactional); +} + +void SWorldHierarchyImpl::InitiateRename(WorldHierarchy::FWorldTreeItemRef InItem) +{ + // Only folders items are valid for rename in this view + if (InItem->GetAsFolderTreeItem() != nullptr) + { + ItemPendingRename = InItem; + ScrollItemIntoView(InItem); + } +} + +void SWorldHierarchyImpl::EmptyTreeItems() +{ + for (auto& Pair : TreeItemMap) + { + Pair.Value->RemoveAllChildren(); + } + + PendingOperations.Empty(); + TreeItemMap.Reset(); + PendingTreeItemMap.Reset(); + + RootTreeItems.Empty(); + NewItemActions.Empty(); + ItemPendingRename.Reset(); +} + +void SWorldHierarchyImpl::RepopulateEntireTree() +{ + EmptyTreeItems(); + + for (const TSharedPtr& Level : WorldModel->GetAllLevels()) + { + if (Level.IsValid()) + { + ConstructItemFor(Level.ToSharedRef()); + } + } + + if (FLevelFolders::IsAvailable() && WorldModel->HasFolderSupport()) + { + FLevelFolders& LevelFolders = FLevelFolders::Get(); + + // Add any folders which might match the search terms for each root level + for (TSharedPtr RootLevel : WorldModel->GetRootLevelList()) + { + for (const auto& Pair : LevelFolders.GetFolderProperties(RootLevel.ToSharedRef())) + { + if (!TreeItemMap.Contains(Pair.Key)) + { + ConstructItemFor(Pair.Key); + } + } + } + } +} + +TMap SWorldHierarchyImpl::GetParentsExpansionState() const +{ + TMap ExpansionStates; + + for (const auto& Pair : TreeItemMap) + { + if (Pair.Value->GetChildren().Num() > 0) + { + ExpansionStates.Add(Pair.Key, Pair.Value->Flags.bExpanded); + } + } + + return ExpansionStates; +} + +void SWorldHierarchyImpl::SetParentsExpansionState(const TMap& ExpansionInfo) +{ + for (const auto& Pair : TreeItemMap) + { + auto& Item = Pair.Value; + if (Item->GetChildren().Num() > 0) + { + const bool* bExpandedPtr = ExpansionInfo.Find(Pair.Key); + bool bExpanded = bExpandedPtr != nullptr ? *bExpandedPtr : Item->Flags.bExpanded; + + TreeWidget->SetItemExpansion(Item, bExpanded); + } + } +} + +void SWorldHierarchyImpl::OnBroadcastFolderCreate(TSharedPtr LevelModel, FName NewPath) +{ + if (!TreeItemMap.Contains(NewPath)) + { + ConstructItemFor(NewPath); + } +} + +void SWorldHierarchyImpl::OnBroadcastFolderDelete(TSharedPtr LevelModel, FName Path) +{ + WorldHierarchy::FWorldTreeItemPtr* Folder = TreeItemMap.Find(Path); + + if (Folder != nullptr) + { + PendingOperations.Emplace(WorldHierarchy::FPendingWorldTreeOperation::Removed, Folder->ToSharedRef()); + RefreshView(); + } +} + +void SWorldHierarchyImpl::OnBroadcastFolderMove(TSharedPtr LevelModel, FName OldPath, FName NewPath) +{ + WorldHierarchy::FWorldTreeItemPtr Folder = TreeItemMap.FindRef(OldPath); + + if (Folder.IsValid()) + { + // Remove the item with the old ID + TreeItemMap.Remove(Folder->GetID()); + + // Get all items that were moved + TArray AllSelectedItems = GetSelectedTreeItems(); + + // Change the path, and place it back in the tree with the new ID + { + WorldHierarchy::FFolderTreeItem* FolderItem = Folder->GetAsFolderTreeItem(); + FolderItem->SetNewPath(NewPath); + } + + for (WorldHierarchy::FWorldTreeItemPtr Child : Folder->GetChildren()) + { + // Any level model children that were not explicitly moved will need to be moved here to remain in + // sync with their parent folders + if (!AllSelectedItems.Contains(Child) && Child->GetAsLevelModelTreeItem() != nullptr) + { + Child->SetParentPath(NewPath); + } + } + + TreeItemMap.Add(Folder->GetID(), Folder); + + PendingOperations.Emplace(WorldHierarchy::FPendingWorldTreeOperation::Moved, Folder.ToSharedRef()); + RefreshView(); + } +} + +void SWorldHierarchyImpl::FullRefresh() +{ + bFullRefresh = true; + RefreshView(); +} + +void SWorldHierarchyImpl::RebuildFoldersAndFullRefresh() +{ + bRebuildFolders = true; + FullRefresh(); +} + +void SWorldHierarchyImpl::RequestSort() +{ + bSortDirty = true; +} + +void SWorldHierarchyImpl::Populate() +{ + TGuardValue ReentrantGuard(bIsReentrant, true); + + bool bMadeSignificantChanges = false; + + const TMap ExpansionStateInfo = GetParentsExpansionState(); + + if (bRebuildFolders) + { + if (FLevelFolders::IsAvailable()) + { + FLevelFolders& LevelFolders = FLevelFolders::Get(); + + for (TSharedPtr LevelModel : WorldModel->GetRootLevelList()) + { + LevelFolders.RebuildFolderList(LevelModel.ToSharedRef()); + } + } + + bRebuildFolders = false; + } + + if (bFullRefresh) + { + RepopulateEntireTree(); + + bFullRefresh = false; + bMadeSignificantChanges = true; + } + + if (PendingOperations.Num() > 0) + { + const int32 End = FMath::Min(PendingOperations.Num(), MaxPendingOperations); + for (int32 Index = 0; Index < End; ++Index) + { + const WorldHierarchy::FPendingWorldTreeOperation& PendingOp = PendingOperations[Index]; + switch (PendingOp.Operation) + { + case WorldHierarchy::FPendingWorldTreeOperation::Added: + bMadeSignificantChanges = AddItemToTree(PendingOp.Item); + break; + + case WorldHierarchy::FPendingWorldTreeOperation::Moved: + bMadeSignificantChanges = true; + OnItemMoved(PendingOp.Item); + break; + + case WorldHierarchy::FPendingWorldTreeOperation::Removed: + bMadeSignificantChanges = true; + RemoveItemFromTree(PendingOp.Item); + break; + + default: + check(false); + break; + } + } + + PendingOperations.RemoveAt(0, End); + } + + SetParentsExpansionState(ExpansionStateInfo); + + if (ItemsSelectedAfterRefresh.Num() > 0) + { + bool bScrolledIntoView = false; + for (const WorldHierarchy::FWorldTreeItemID& ID : ItemsSelectedAfterRefresh) + { + if (TreeItemMap.Contains(ID)) + { + WorldHierarchy::FWorldTreeItemPtr Item = TreeItemMap[ID]; + TreeWidget->SetItemSelection(Item, true); + + if (!bScrolledIntoView) + { + bScrolledIntoView = true; + TreeWidget->RequestScrollIntoView(Item); + } + } + } + + ItemsSelectedAfterRefresh.Empty(); + } + + if (bMadeSignificantChanges) + { + RequestSort(); + } + + TreeWidget->RequestTreeRefresh(); + + if (PendingOperations.Num() == 0) + { + NewItemActions.Empty(); + bNeedsRefresh = false; + } +} + +bool SWorldHierarchyImpl::AddItemToTree(WorldHierarchy::FWorldTreeItemRef InItem) +{ + const WorldHierarchy::FWorldTreeItemID ItemID = InItem->GetID(); + + bool bItemAdded = false; + + PendingTreeItemMap.Remove(ItemID); + if (!TreeItemMap.Find(ItemID)) + { + // Not currently in the tree, check if the item passes the current filter + + bool bFilteredOut = !PassesFilter(*InItem); + + InItem->Flags.bFilteredOut = bFilteredOut; + + if (!bFilteredOut) + { + AddUnfilteredItemToTree(InItem); + bItemAdded = true; + + if (WorldHierarchy::ENewItemAction* ActionPtr = NewItemActions.Find(ItemID)) + { + WorldHierarchy::ENewItemAction Actions = *ActionPtr; + + if ((Actions & WorldHierarchy::ENewItemAction::Select) != WorldHierarchy::ENewItemAction::None) + { + TreeWidget->ClearSelection(); + TreeWidget->SetItemSelection(InItem, true); + } + + if ((Actions & WorldHierarchy::ENewItemAction::Rename) != WorldHierarchy::ENewItemAction::None) + { + ItemPendingRename = InItem; + } + + WorldHierarchy::ENewItemAction ScrollIntoView = WorldHierarchy::ENewItemAction::ScrollIntoView | WorldHierarchy::ENewItemAction::Rename; + if ((Actions & ScrollIntoView) != WorldHierarchy::ENewItemAction::None) + { + ScrollItemIntoView(InItem); + } + } + } + } + + return bItemAdded; +} + +void SWorldHierarchyImpl::AddUnfilteredItemToTree(WorldHierarchy::FWorldTreeItemRef InItem) +{ + WorldHierarchy::FWorldTreeItemPtr Parent = EnsureParentForItem(InItem); + const WorldHierarchy::FWorldTreeItemID ItemID = InItem->GetID(); + + if (TreeItemMap.Contains(ItemID)) + { + UE_LOG(LogWorldHierarchy, Error, TEXT("(%d | %s) already exists in the World Hierarchy. Dumping map..."), GetTypeHash(ItemID), *InItem->GetDisplayString()); + + for (const auto& Entry : TreeItemMap) + { + UE_LOG(LogWorldHierarchy, Log, TEXT("(%d | %s)"), GetTypeHash(Entry.Key), *Entry.Value->GetDisplayString()); + } + + // Treat this as a fatal error + check(false); + } + + TreeItemMap.Add(ItemID, InItem); + + if (Parent.IsValid()) + { + Parent->AddChild(InItem); + } + else + { + RootTreeItems.Add(InItem); + } + + if (FLevelFolders::IsAvailable()) + { + WorldHierarchy::FFolderTreeItem* Folder = InItem->GetAsFolderTreeItem(); + + if (Folder != nullptr) + { + if (const FLevelFolderProps* Props = FLevelFolders::Get().GetFolderProperties(InItem->GetRootItem().ToSharedRef(), Folder->GetFullPath())) + { + InItem->SetExpansion(Props->bExpanded); + } + } + } +} + +void SWorldHierarchyImpl::RemoveItemFromTree(WorldHierarchy::FWorldTreeItemRef InItem) +{ + if (TreeItemMap.Contains(InItem->GetID())) + { + WorldHierarchy::FWorldTreeItemPtr Parent = InItem->GetParent(); + + if (Parent.IsValid()) + { + Parent->RemoveChild(InItem); + OnChildRemovedFromParent(Parent.ToSharedRef()); + } + else + { + RootTreeItems.Remove(InItem); + } + + TreeItemMap.Remove(InItem->GetID()); + } +} + +void SWorldHierarchyImpl::OnItemMoved(WorldHierarchy::FWorldTreeItemRef InItem) +{ + // If the item no longer matches the filter, remove it from the tree + if (!InItem->Flags.bFilteredOut && !PassesFilter(*InItem)) + { + RemoveItemFromTree(InItem); + } + else + { + WorldHierarchy::FWorldTreeItemPtr Parent = InItem->GetParent(); + + if (Parent.IsValid()) + { + Parent->RemoveChild(InItem); + OnChildRemovedFromParent(Parent.ToSharedRef()); + } + else + { + RootTreeItems.Remove(InItem); + } + + Parent = EnsureParentForItem(InItem); + if (Parent.IsValid()) + { + Parent->AddChild(InItem); + Parent->SetExpansion(true); + TreeWidget->SetItemExpansion(Parent, true); + } + else + { + RootTreeItems.Add(InItem); + } + } +} + +void SWorldHierarchyImpl::ScrollItemIntoView(WorldHierarchy::FWorldTreeItemPtr Item) +{ + WorldHierarchy::FWorldTreeItemPtr Parent = Item->GetParent(); + + while (Parent.IsValid()) + { + TreeWidget->SetItemExpansion(Parent, true); + Parent = Parent->GetParent(); + } + + TreeWidget->RequestScrollIntoView(Item); +} + +void SWorldHierarchyImpl::OnChildRemovedFromParent(WorldHierarchy::FWorldTreeItemRef InParent) +{ + if (InParent->Flags.bFilteredOut && InParent->GetChildren().Num() == 0) + { + // Parent does not match the search terms nor does it have any children that matches the search terms + RemoveItemFromTree(InParent); + } +} + +WorldHierarchy::FWorldTreeItemPtr SWorldHierarchyImpl::EnsureParentForItem(WorldHierarchy::FWorldTreeItemRef Item) +{ + WorldHierarchy::FWorldTreeItemID ParentID = Item->GetParentID(); + WorldHierarchy::FWorldTreeItemPtr ParentPtr; + + if (TreeItemMap.Contains(ParentID)) + { + ParentPtr = TreeItemMap[ParentID]; + } + else + { + ParentPtr = Item->CreateParent(); + if (ParentPtr.IsValid()) + { + AddUnfilteredItemToTree(ParentPtr.ToSharedRef()); + } + } + + + return ParentPtr; +} + +bool SWorldHierarchyImpl::IsTreeItemExpanded(WorldHierarchy::FWorldTreeItemPtr Item) const +{ + return Item->Flags.bExpanded; +} + +void SWorldHierarchyImpl::SortItems(TArray& Items) +{ + if (Items.Num() > 1) + { + Items.Sort([](WorldHierarchy::FWorldTreeItemPtr Item1, WorldHierarchy::FWorldTreeItemPtr Item2) { + const int32 Priority1 = Item1->GetSortPriority(); + const int32 Priority2 = Item2->GetSortPriority(); + + if (Priority1 == Priority2) + { + return Item1->GetDisplayString() < Item2->GetDisplayString(); + } + + return Priority1 > Priority2; + }); + } +} + +void SWorldHierarchyImpl::TransformLevelToString(const FLevelModel* Level, TArray& OutSearchStrings) const +{ + if (Level != nullptr && Level->HasValidPackage()) + { + OutSearchStrings.Add(FPackageName::GetShortName(Level->GetLongPackageName())); + } +} + +void SWorldHierarchyImpl::TransformItemToString(const WorldHierarchy::IWorldTreeItem& Item, TArray& OutSearchStrings) const +{ + OutSearchStrings.Add(Item.GetDisplayString()); +} + +void SWorldHierarchyImpl::SetFilterText(const FText& InFilterText) +{ + // Ensure that the level and hierarchy filters remain in sync + if (SearchBoxLevelFilter.IsValid()) + { + SearchBoxLevelFilter->SetRawFilterText(InFilterText); + } + SearchBoxHierarchyFilter->SetRawFilterText(InFilterText); +} + +FText SWorldHierarchyImpl::GetSearchBoxText() const +{ + return SearchBoxHierarchyFilter->GetRawFilterText(); +} + +FText SWorldHierarchyImpl::GetFilterStatusText() const +{ + const int32 SelectedLevelsCount = WorldModel->GetSelectedLevels().Num(); + const int32 TotalLevelsCount = WorldModel->GetAllLevels().Num(); + const int32 FilteredLevelsCount = WorldModel->GetFilteredLevels().Num(); + + if (!WorldModel->IsFilterActive()) + { + if (SelectedLevelsCount == 0) + { + return FText::Format(LOCTEXT("ShowingAllLevelsFmt", "{0} levels"), FText::AsNumber(TotalLevelsCount)); + } + else + { + return FText::Format(LOCTEXT("ShowingAllLevelsSelectedFmt", "{0} levels ({1} selected)"), FText::AsNumber(TotalLevelsCount), FText::AsNumber(SelectedLevelsCount)); + } + } + else if (WorldModel->IsFilterActive() && FilteredLevelsCount == 0) + { + return FText::Format(LOCTEXT("ShowingNoLevelsFmt", "No matching levels ({0} total)"), FText::AsNumber(TotalLevelsCount)); + } + else if (SelectedLevelsCount != 0) + { + return FText::Format(LOCTEXT("ShowingOnlySomeLevelsSelectedFmt", "Showing {0} of {1} levels ({2} selected)"), FText::AsNumber(FilteredLevelsCount), FText::AsNumber(TotalLevelsCount), FText::AsNumber(SelectedLevelsCount)); + } + else + { + return FText::Format(LOCTEXT("ShowingOnlySomeLevelsFmt", "Showing {0} of {1} levels"), FText::AsNumber(FilteredLevelsCount), FText::AsNumber(TotalLevelsCount)); + } +} + +FReply SWorldHierarchyImpl::OnCreateFolderClicked() +{ + // Assume that the folder will be created for the first persistent level + TSharedPtr PersistentLevel = WorldModel->GetRootLevelList()[0]; + + CreateFolder(PersistentLevel); + + return FReply::Handled(); +} + +EVisibility SWorldHierarchyImpl::GetEmptyLabelVisibility() const +{ + return ( !bFoldersOnlyMode || RootTreeItems.Num() > 0 ) ? EVisibility::Collapsed : EVisibility::Visible; +} + +void SWorldHierarchyImpl::CreateFolder(TSharedPtr InModel, FName ParentPath /* = NAME_None */) +{ + if (FLevelFolders::IsAvailable()) + { + TSharedPtr PersistentLevelModel = InModel; + if (!InModel.IsValid()) + { + // We're not making this for any specific level...assume it's the first persistent level in the world + PersistentLevelModel = WorldModel->GetRootLevelList()[0]; + } + + const FScopedTransaction Transaction(LOCTEXT("UndoAction_CreateFolder", "Create Folder")); + + FLevelFolders& LevelFolders = FLevelFolders::Get(); + FName NewFolderName = ParentPath; + + // Get the folder name for the selected level items + if (NewFolderName.IsNone()) + { + // Attempt to find the most relevant shared folder for all selected items + TArray SelectedItems = GetSelectedTreeItems(); + + TSet SharedAncestorPaths = SelectedItems.Num() > 0 ? SelectedItems[0]->GetAncestorPaths() : TSet(); + + for (int32 Index = 1; Index < SelectedItems.Num(); ++Index) + { + SharedAncestorPaths = SharedAncestorPaths.Intersect(SelectedItems[Index]->GetAncestorPaths()); + + if (SharedAncestorPaths.Num() == 0) + { + // No common ancestor path found, put them at the root + break; + } + } + + // Find the longest name in the shared ancestor paths, because that's the most local "root" folder + for (FName Ancestor : SharedAncestorPaths) + { + if (Ancestor.ToString().Len() > NewFolderName.ToString().Len()) + { + NewFolderName = Ancestor; + } + } + } + + NewFolderName = LevelFolders.GetDefaultFolderName(PersistentLevelModel.ToSharedRef(), NewFolderName); + + MoveItemsTo(PersistentLevelModel, NewFolderName); + } +} + +void SWorldHierarchyImpl::MoveItemsTo(TSharedPtr InModel, FName InPath) +{ + if (FLevelFolders::IsAvailable()) + { + FLevelFolders& LevelFolders = FLevelFolders::Get(); + + // Get the selected folders first before any items move + TArray PreviouslySelectedItems = GetSelectedTreeItems(); + TArray SelectedFolders; + + for (WorldHierarchy::FWorldTreeItemPtr Item : PreviouslySelectedItems) + { + if (WorldHierarchy::FFolderTreeItem* Folder = Item->GetAsFolderTreeItem()) + { + SelectedFolders.Add(Folder); + } + } + + // Move the levels first + LevelFolders.CreateFolderContainingSelectedLevels(WorldModel.ToSharedRef(), InModel.ToSharedRef(), InPath); + + // Ensure that any moved levels will have their hierarchy items updated + for (TSharedPtr SelectedLevel : WorldModel->GetSelectedLevels()) + { + WorldHierarchy::FWorldTreeItemID LevelID(SelectedLevel->GetLevelObject()); + + if (TreeItemMap.Contains(LevelID)) + { + PendingOperations.Emplace(WorldHierarchy::FPendingWorldTreeOperation::Moved, TreeItemMap[LevelID].ToSharedRef()); + } + } + + // Move any of the previously selected folders + for (WorldHierarchy::FFolderTreeItem* Folder : SelectedFolders) + { + FName OldPath = Folder->GetFullPath(); + FName NewPath = FName(*(InPath.ToString() / Folder->GetLeafName().ToString())); + + LevelFolders.RenameFolder(Folder->GetRootItem().ToSharedRef(), OldPath, NewPath); + } + + NewItemActions.Add(InPath, WorldHierarchy::ENewItemAction::Select | WorldHierarchy::ENewItemAction::Rename); + } +} + +void SWorldHierarchyImpl::DeleteFolders(TArray SelectedItems, bool bTransactional/* = true*/) +{ + TArray FolderItems; + TSet DeletedPaths; + + for (WorldHierarchy::FWorldTreeItemPtr Item : SelectedItems) + { + // Only take folder items + if (WorldHierarchy::FFolderTreeItem* Folder = Item->GetAsFolderTreeItem()) + { + FolderItems.Add(Item); + DeletedPaths.Add(Folder->GetFullPath()); + } + } + + FScopedTransaction Transaction(LOCTEXT("DeleteFolderTransaction", "Delete Folder")); + FLevelFolders& LevelFolders = FLevelFolders::Get(); + + // Folders are deleted one at a time + for (WorldHierarchy::FWorldTreeItemPtr Item : FolderItems) + { + TSharedRef LevelModel = Item->GetRootItem().ToSharedRef(); + + // First, move the folder's children up to the ancestor that will not be deleted + FName ItemPath = Item->GetAsFolderTreeItem()->GetFullPath(); + + FName ParentPath = ItemPath; + do + { + ParentPath = WorldHierarchy::GetParentPath(ParentPath); + } while (DeletedPaths.Contains(ParentPath) && !ParentPath.IsNone()); + + TArray Children = Item->GetChildren(); + for (WorldHierarchy::FWorldTreeItemPtr Child : Children) + { + if (!SelectedItems.Contains(Child)) + { + if (WorldHierarchy::FFolderTreeItem* ChildFolder = Child->GetAsFolderTreeItem()) + { + FName NewChildPath = ChildFolder->GetLeafName(); + if (!ParentPath.IsNone()) + { + NewChildPath = FName(*(ParentPath.ToString() / NewChildPath.ToString())); + } + + LevelFolders.RenameFolder(LevelModel, ChildFolder->GetFullPath(), NewChildPath); + } + else + { + Child->SetParentPath(ParentPath); + OnItemMoved(Child.ToSharedRef()); + } + } + } + + // Then delete the folder + LevelFolders.DeleteFolder(LevelModel, ItemPath); + } + + if (!bTransactional || FolderItems.Num() == 0) + { + Transaction.Cancel(); + } +} + +FSlateColor SWorldHierarchyImpl::GetFilterStatusTextColor() const +{ + if (!WorldModel->IsFilterActive()) + { + // White = no text filter + return FLinearColor(1.0f, 1.0f, 1.0f); + } + else if (WorldModel->GetFilteredLevels().Num() == 0) + { + // Red = no matching actors + return FLinearColor(1.0f, 0.4f, 0.4f); + } + else + { + // Green = found at least one match! + return FLinearColor(0.4f, 1.0f, 0.4f); + } +} + +TSharedRef SWorldHierarchyImpl::GetViewButtonContent() +{ + FMenuBuilder MenuBuilder(true, NULL); + + MenuBuilder.BeginSection("SubLevelsViewMenu", LOCTEXT("ShowHeading", "Show")); + { + MenuBuilder.AddMenuEntry(LOCTEXT("ToggleDisplayPaths", "Display Paths"), + LOCTEXT("ToggleDisplayPaths_Tooltip", "If enabled, displays the path for each level"), + FSlateIcon(), + FUIAction( + FExecuteAction::CreateSP(this, &SWorldHierarchyImpl::ToggleDisplayPaths_Executed), + FCanExecuteAction(), + FIsActionChecked::CreateSP(this, &SWorldHierarchyImpl::GetDisplayPathsState)), + NAME_None, + EUserInterfaceActionType::ToggleButton + ); + + MenuBuilder.AddMenuEntry(LOCTEXT("ToggleDisplayActorsCount", "Display Actors Count"), + LOCTEXT("ToggleDisplayActorsCount_Tooltip", "If enabled, displays actors count for each level"), + FSlateIcon(), + FUIAction( + FExecuteAction::CreateSP(this, &SWorldHierarchyImpl::ToggleDisplayActorsCount_Executed), + FCanExecuteAction(), + FIsActionChecked::CreateSP(this, &SWorldHierarchyImpl::GetDisplayActorsCountState)), + NAME_None, + EUserInterfaceActionType::ToggleButton + ); + + } + MenuBuilder.EndSection(); + + return MenuBuilder.MakeWidget(); +} + +FSlateColor SWorldHierarchyImpl::GetViewButtonForegroundColor() const +{ + static const FName InvertedForegroundName("InvertedForeground"); + static const FName DefaultForegroundName("DefaultForeground"); + + return ViewOptionsComboButton->IsHovered() ? FEditorStyle::GetSlateColor(InvertedForegroundName) : FEditorStyle::GetSlateColor(DefaultForegroundName); +} + +bool SWorldHierarchyImpl::GetDisplayPathsState() const +{ + return WorldModel->GetDisplayPathsState(); +} + +void SWorldHierarchyImpl::ToggleDisplayActorsCount_Executed() +{ + WorldModel->SetDisplayActorsCountState(!WorldModel->GetDisplayActorsCountState()); +} + +bool SWorldHierarchyImpl::GetDisplayActorsCountState() const +{ + return WorldModel->GetDisplayActorsCountState(); +} + +void SWorldHierarchyImpl::PostUndo(bool bSuccess) +{ + if (!bIsReentrant) + { + FullRefresh(); + } +} + +#undef LOCTEXT_NAMESPACE \ No newline at end of file diff --git a/Engine/Source/Editor/WorldBrowser/Private/SWorldHierarchyImpl.h b/Engine/Source/Editor/WorldBrowser/Private/SWorldHierarchyImpl.h new file mode 100644 index 000000000000..6b4b8e9e8658 --- /dev/null +++ b/Engine/Source/Editor/WorldBrowser/Private/SWorldHierarchyImpl.h @@ -0,0 +1,372 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. +#pragma once + +#include "CoreMinimal.h" +#include "Layout/Visibility.h" +#include "Input/Reply.h" +#include "Widgets/SWidget.h" +#include "Widgets/Input/SComboButton.h" +#include "Widgets/DeclarativeSyntaxSupport.h" +#include "Widgets/SCompoundWidget.h" +#include "EditorUndoClient.h" + +#include "LevelModel.h" +#include "LevelCollectionModel.h" +#include "Misc/TextFilter.h" +#include "SLevelsTreeWidget.h" + +#include "IWorldTreeItem.h" + +typedef TTextFilter HierarchyFilter; +typedef TTextFilter LevelTextFilter; + +namespace WorldHierarchy +{ + /** Structure that defines an operation that should be applied to the world hierarchy */ + struct FPendingWorldTreeOperation + { + enum EType { Added, Removed, Moved, }; + FPendingWorldTreeOperation(EType InOp, FWorldTreeItemRef InItem) : Operation(InOp), Item(InItem) {} + + /** The type of operation to perform */ + EType Operation; + + /** The item affected by this operation */ + FWorldTreeItemRef Item; + }; + + /** Defines operations for items to perform when they are added to the tree */ + enum class ENewItemAction : uint8 + { + None = 0, /** No Actions for the item */ + Select = 1 << 0, /** Item should be selected */ + ScrollIntoView = 1 << 1, /** Item should be selected */ + Rename = 1 << 2, /** Item should be renamed */ + }; + + ENUM_CLASS_FLAGS(ENewItemAction) +} // namespace WorldHierarchy + +DECLARE_DELEGATE_OneParam(FOnWorldHierarchyItemPicked, WorldHierarchy::FWorldTreeItemRef); + +class SWorldHierarchyImpl + : public SCompoundWidget + , public FEditorUndoClient +{ +public: + SLATE_BEGIN_ARGS(SWorldHierarchyImpl) + : _ShowFoldersOnly(false) + {} + /** The world represented by this hierarchy */ + SLATE_ARGUMENT(TSharedPtr, InWorldModel) + /** If true, the hierarchy will only show folders for the world model */ + SLATE_ARGUMENT(bool, ShowFoldersOnly) + /** If folders only mode is activated, this prevents certain folders from being displayed */ + SLATE_ARGUMENT(TSet, InExcludedFolders) + /** A delegate to fire when an item is picked */ + SLATE_ARGUMENT(FOnWorldHierarchyItemPicked, OnItemPickedDelegate) + SLATE_END_ARGS() + + SWorldHierarchyImpl(); + + ~SWorldHierarchyImpl(); + + void Construct(const FArguments& InArgs); + + /** Regenerates current items */ + void RefreshView(); + + virtual void Tick( const FGeometry& AllotedGeometry, const double InCurrentTime, const float InDeltaTime ) override; + + /** Creates a new folder for the hierarchy. If ParentPath is defined, the folder will be created relative to that path. */ + void CreateFolder(TSharedPtr InModel, FName ParentPath = NAME_None); + + /** Moves the current selection to the specified path */ + void MoveItemsTo(TSharedPtr InModel, FName Path); + + /** Initiates a rename of the selected item */ + void InitiateRename(WorldHierarchy::FWorldTreeItemRef InItem); + + /** Deletes the folders contained in the selection from the hierarchy tree. */ + void DeleteFolders(TArray SelectedItems, bool bTransactional = true); + + /** Moves selected items from a drag and drop operation */ + void MoveDroppedItems(const TArray& DraggedItems, FName FolderPath); + + /** Adds the specified levels to the hierarchy under the specified folder path */ + void AddDroppedLevelsToFolder(const TArray& WorldAssetList, FName FolderPath); + + /** Helper funciton to get the selected items from the tree widget */ + TArray GetSelectedTreeItems() const { return TreeWidget->GetSelectedItems(); } + +public: + //~ FEditorUndoClient + virtual void PostUndo(bool bSuccess) override; + virtual void PostRedo(bool bSuccess) override { PostUndo(bSuccess); } + +private: + // The maximum number of pending operations to process at one time + static const int32 MaxPendingOperations = 500; + + /** Creates an item for the tree view */ + TSharedRef GenerateTreeRow(WorldHierarchy::FWorldTreeItemPtr Item, const TSharedRef& OwnerTable); + + /** Handler for returning a list of children associated with a particular tree node */ + void GetChildrenForTree(WorldHierarchy::FWorldTreeItemPtr Item, TArray& OutChildren); + + /** @return the SWidget containing the context menu */ + TSharedPtr ConstructLevelContextMenu() const; + + /** Builds the submenu for moving items to other folders in the hierarchy */ + void FillFoldersSubmenu(FMenuBuilder& MenuBuilder); + + /** Builds the list of valid folders that an item can be moved to */ + void AddMoveToFolderOutliner(FMenuBuilder& MenuBuilder, const TArray& CachedSelectedItems, TSharedRef RootLevel); + + /** Builds the menu that allows for children of a folder to be selected from the context menu */ + void FillSelectionSubmenu(FMenuBuilder& MenuBuilder); + + /** Selects the level descendants of the currently selected folders. If bSelectAllDescendants is true, all descendants will be selected instead of immediate children */ + void SelectFolderDescendants(bool bSelectAllDescendants); + + /** Called after a tree item has been scrolled into view. This initiates a pending rename. */ + void OnTreeItemScrolledIntoView( WorldHierarchy::FWorldTreeItemPtr Item, const TSharedPtr& Widget ); + + /** Called by TreeView widget whenever tree item expanded or collapsed */ + void OnExpansionChanged(WorldHierarchy::FWorldTreeItemPtr Item, bool bIsItemExpanded); + + /** Called by TreeView widget whenever selection is changed */ + void OnSelectionChanged(const WorldHierarchy::FWorldTreeItemPtr Item, ESelectInfo::Type SelectInfo); + + /** Handles selection changes in data source */ + void OnUpdateSelection(); + + /** + * Called by STreeView when the user double-clicks on an item + * + * @param Item The item that was double clicked + */ + void OnTreeViewMouseButtonDoubleClick(WorldHierarchy::FWorldTreeItemPtr Item); + + /** + * Checks to see if this widget supports keyboard focus. Override this in derived classes. + * + * @return True if this widget can take keyboard focus + */ + virtual bool SupportsKeyboardFocus() const override + { + return true; + } + + /** + * Called after a key is pressed when this widget has focus + * + * @param MyGeometry The Geometry of the widget receiving the event + * @param InKeyEvent Key event + * + * @return Returns whether the event was handled, along with other possible actions + */ + virtual FReply OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) override; + + /** Adds a new item for the specified type and refreshes the tree, provided it matches the filter terms */ + template + void ConstructItemFor(const DataType& Data) + { + const TreeItemType Temporary(Data); + bool bPassesFilter = PassesFilter(Temporary); + + if (bPassesFilter) + { + WorldHierarchy::FWorldTreeItemRef NewItem = MakeShareable(new TreeItemType(Data)); + NewItem->WorldModel = WorldModel; + + PendingOperations.Emplace(WorldHierarchy::FPendingWorldTreeOperation::Added, NewItem); + PendingTreeItemMap.Add(NewItem->GetID(), NewItem); + RefreshView(); + } + } + + /** Applies incremental changes to the tree, or completely repopulates it */ + void Populate(); + + /** Empties all items within the tree */ + void EmptyTreeItems(); + + /** Fully rebuilds the tree, including folders */ + void RepopulateEntireTree(); + + /** Adds a new item to the tree if it passes the current filter */ + bool AddItemToTree(WorldHierarchy::FWorldTreeItemRef InItem); + + /** Removes a single item from the tree. This does not delete it */ + void RemoveItemFromTree(WorldHierarchy::FWorldTreeItemRef InItem); + + /** Handles moving an item to ensure that its parent now exists in the hierarchy regardless of filter, or potentially hides the previous parent */ + void OnItemMoved(WorldHierarchy::FWorldTreeItemRef InItem); + + /** Adds a new item to the tree, ignoring the current filter */ + void AddUnfilteredItemToTree(WorldHierarchy::FWorldTreeItemRef InItem); + + /** Called when a child is removed from the parent. This can potentially filter the parent out of the current view */ + void OnChildRemovedFromParent(WorldHierarchy::FWorldTreeItemRef InParent); + + /** Ensures that the item's parent exists and is placed in the hierarchy tree */ + WorldHierarchy::FWorldTreeItemPtr EnsureParentForItem(WorldHierarchy::FWorldTreeItemRef Item); + + /** Gets the expansion state of all parent items. Call this before repopulating the tree */ + TMap GetParentsExpansionState() const; + + /** Sets the expansion state of all parent items based on the cached expansion info */ + void SetParentsExpansionState(const TMap& ExpansionInfo); + + /** Causes the tree to be fully rebuilt */ + void FullRefresh(); + + /** Rebuilds the folder list for the hierarchy, and forces a full refresh */ + void RebuildFoldersAndFullRefresh(); + + /** Scrolls the specified item into view */ + void ScrollItemIntoView(WorldHierarchy::FWorldTreeItemPtr Item); + + /** Called when a folder is created */ + void OnBroadcastFolderCreate(TSharedPtr LevelModel, FName NewPath); + + /** Called when a folder is moved */ + void OnBroadcastFolderMove(TSharedPtr LevelModel, FName OldPath, FName NewPath); + + /** Called when a folder is deleted */ + void OnBroadcastFolderDelete(TSharedPtr LevelModel, FName Path); + + /** Called when levels have been unloaded */ + void OnBroadcastLevelsUnloaded(); + + /** Called when the Create Folder button has been clicked */ + FReply OnCreateFolderClicked(); + + /** Requests that items are sorted in the hierarchy view */ + void RequestSort(); + + /** Sorts the selected items */ + void SortItems(TArray& Items); + + /** Moves the selected items to the given item */ + void MoveSelectionTo(WorldHierarchy::FWorldTreeItemRef Item); + + /** Returns true if the item would pass the current filter */ + bool PassesFilter(const WorldHierarchy::IWorldTreeItem& Item); + + /** Gets the visibility of the empty label */ + EVisibility GetEmptyLabelVisibility() const; + +private: + /** @returns Whether specified item should be expanded */ + bool IsTreeItemExpanded(WorldHierarchy::FWorldTreeItemPtr Item) const; + + /** Appends the Level's name to the OutSearchStrings array if the Level is valid */ + void TransformLevelToString(const FLevelModel* Level, TArray& OutSearchStrings) const; + + /** Appends the levels contained in Item to the OutSearchStrings array */ + void TransformItemToString(const WorldHierarchy::IWorldTreeItem& Item, TArray& OutSearchStrings) const; + + /** @return Text entered in search box */ + FText GetSearchBoxText() const; + + /** @return Returns the filter status text */ + FText GetFilterStatusText() const; + + void SetFilterText(const FText& InFilterText); + + /** @return Returns color for the filter status text message, based on success of search filter */ + FSlateColor GetFilterStatusTextColor() const; + + /** @return the content for the view button */ + TSharedRef GetViewButtonContent(); + + /** @return the foreground color for the view button */ + FSlateColor GetViewButtonForegroundColor() const; + + /** Toggles state of 'display path' */ + void ToggleDisplayPaths_Executed() + { + WorldModel->SetDisplayPathsState(!WorldModel->GetDisplayPathsState()); + } + + /** Gets the state of the 'display paths' enabled/disabled */ + bool GetDisplayPathsState() const; + + /** Toggles state of 'display actors count' */ + void ToggleDisplayActorsCount_Executed(); + + /** Gets the state of the 'display actors count' enabled/disabled */ + bool GetDisplayActorsCountState() const; + + /** Callback for when the world is saved */ + void OnWorldSaved(uint32 SaveFlags, UWorld* World, bool bSuccess); + +private: + /** Whether the view is currently updating the viewmodel selection */ + bool bUpdatingSelection; + + /** Our list view widget */ + TSharedPtr TreeWidget; + + /** Items collection to display */ + TSharedPtr WorldModel; + + /** The Header Row for the hierarchy */ + TSharedPtr HeaderRowWidget; + + /** The LevelTextFilter that constrains which items appear in the world model list */ + TSharedPtr SearchBoxLevelFilter; + + /** The filter that constrains which items appear in the hierarchy */ + TSharedPtr SearchBoxHierarchyFilter; + + /** Button representing view options on bottom */ + TSharedPtr ViewOptionsComboButton; + + /** Root items for the tree widget */ + TArray RootTreeItems; + + /** Reentracy guard */ + bool bIsReentrant; + + /** True if the tree should perform a full refresh */ + bool bFullRefresh; + + /** True if the tree needs to be refreshed */ + bool bNeedsRefresh; + + /** True if the folder list needs to be rebuilt */ + bool bRebuildFolders; + + /** True if the items require sort */ + bool bSortDirty; + + /** Operations that are waiting to be resolved for items in the tree */ + TArray PendingOperations; + + /** Items that are waiting to be committed to the tree view */ + TMap PendingTreeItemMap; + + /** All items that are currently displayed in the tree widget */ + TMap TreeItemMap; + + /** Map of actions to apply to new tree items */ + TMap NewItemActions; + + /** The item that is currently pending a rename */ + TWeakPtr ItemPendingRename; + + /** Keeps track of which items should be selected after a refresh occurs */ + TArray ItemsSelectedAfterRefresh; + + /** If true, only show root items and the folders for each item */ + bool bFoldersOnlyMode; + + /** If folders-only mode is specified, prevents folders with the following names from being shown in the hierarchy */ + TSet ExcludedFolders; + + /** Delegate that fires when the selection changes */ + FOnWorldHierarchyItemPicked OnItemPicked; +}; \ No newline at end of file diff --git a/Engine/Source/Editor/WorldBrowser/Private/SWorldHierarchyItem.cpp b/Engine/Source/Editor/WorldBrowser/Private/SWorldHierarchyItem.cpp index 1e71d18b92f0..c3c83558c89b 100644 --- a/Engine/Source/Editor/WorldBrowser/Private/SWorldHierarchyItem.cpp +++ b/Engine/Source/Editor/WorldBrowser/Private/SWorldHierarchyItem.cpp @@ -1,24 +1,25 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "SWorldHierarchyItem.h" -#include "Misc/PackageName.h" #include "SlateOptMacros.h" #include "Widgets/Images/SImage.h" #include "Widgets/Text/STextBlock.h" +#include "Widgets/Text/SInlineEditableTextBlock.h" #include "Widgets/Input/SButton.h" #include "EditorStyleSet.h" #include "Engine/Engine.h" #include "ISourceControlProvider.h" #include "ISourceControlModule.h" #include "EngineGlobals.h" -#include "Engine/LevelStreamingAlwaysLoaded.h" -#include "Engine/LevelStreamingKismet.h" #include "Editor.h" -#include "DragAndDrop/LevelDragDropOp.h" #include "LevelCollectionModel.h" +#include "WorldBrowserDragDrop.h" +#include "SWorldHierarchyImpl.h" #include "Widgets/Views/SListView.h" #include "Widgets/Colors/SColorPicker.h" +#include "WorldTreeItemTypes.h" +#include "LevelFolders.h" #define LOCTEXT_NAMESPACE "WorldBrowser" @@ -30,19 +31,21 @@ void SWorldHierarchyItem::Construct(const FArguments& InArgs, TSharedRef OwnerTableView) { WorldModel = InArgs._InWorldModel; - LevelModel = InArgs._InItemModel; + WorldTreeItem = InArgs._InItemModel; + Hierarchy = InArgs._InHierarchy; IsItemExpanded = InArgs._IsItemExpanded; HighlightText = InArgs._HighlightText; + bFoldersOnlyMode = InArgs._FoldersOnlyMode; - StreamingLevelAlwaysLoadedBrush = FEditorStyle::GetBrush("WorldBrowser.LevelStreamingAlwaysLoaded"); - StreamingLevelKismetBrush = FEditorStyle::GetBrush("WorldBrowser.LevelStreamingBlueprint"); + FSuperRowType::FArguments Args = FSuperRowType::FArguments(); - SMultiColumnTableRow>::Construct( - FSuperRowType::FArguments() - .OnDragDetected(this, &SWorldHierarchyItem::OnItemDragDetected), - OwnerTableView - ); + if (!bFoldersOnlyMode) + { + // Drag should not be detected if the item is only displaying its name + Args.OnDragDetected(this, &SWorldHierarchyItem::OnItemDragDetected); + } + SMultiColumnTableRow::Construct(Args, OwnerTableView); } BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION @@ -52,6 +55,36 @@ TSharedRef< SWidget > SWorldHierarchyItem::GenerateWidgetForColumn( const FName& if (ColumnID == HierarchyColumns::ColumnID_LevelLabel) { + TSharedPtr TextWidget; + + if (!bFoldersOnlyMode && WorldTreeItem->GetAsFolderTreeItem() != nullptr) + { + // Folders should support renaming if we're also displaying levels + TSharedRef InlineText = SNew(SInlineEditableTextBlock) + .Font(this, &SWorldHierarchyItem::GetDisplayNameFont) + .Text(this, &SWorldHierarchyItem::GetDisplayNameText) + .ColorAndOpacity(this, &SWorldHierarchyItem::GetDisplayNameColorAndOpacity) + .HighlightText(HighlightText) + .ToolTipText(this, &SWorldHierarchyItem::GetDisplayNameTooltip) + .OnTextCommitted(this, &SWorldHierarchyItem::OnLabelCommitted) + .OnVerifyTextChanged(this, &SWorldHierarchyItem::OnVerifyItemLabelChanged) + ; + + TextWidget = StaticCastSharedRef(InlineText); + + WorldTreeItem->RenameRequestEvent.BindSP(InlineText, &SInlineEditableTextBlock::EnterEditingMode); + } + else + { + TextWidget = SNew(STextBlock) + .Font(this, &SWorldHierarchyItem::GetDisplayNameFont) + .Text(this, &SWorldHierarchyItem::GetDisplayNameText) + .ColorAndOpacity(this, &SWorldHierarchyItem::GetDisplayNameColorAndOpacity) + .HighlightText(HighlightText) + .ToolTipText(this, &SWorldHierarchyItem::GetDisplayNameTooltip) + ; + } + TableRowContent = SNew(SHorizontalBox) @@ -66,7 +99,7 @@ TSharedRef< SWidget > SWorldHierarchyItem::GenerateWidgetForColumn( const FName& .AutoWidth() [ SNew(SBox) - .WidthOverride(7) // in case brush for this item is empty + .WidthOverride(WorldTreeItem->GetHierarchyItemBrushWidth()) [ SNew(SImage) .Image(this, &SWorldHierarchyItem::GetLevelIconBrush) @@ -77,263 +110,325 @@ TSharedRef< SWidget > SWorldHierarchyItem::GenerateWidgetForColumn( const FName& .VAlign(VAlign_Center) .AutoWidth() [ - SNew(STextBlock) - .Font(this, &SWorldHierarchyItem::GetLevelDisplayNameFont) - .Text(this, &SWorldHierarchyItem::GetLevelDisplayNameText) - .ColorAndOpacity(this, &SWorldHierarchyItem::GetLevelDisplayNameColorAndOpacity) - .HighlightText(HighlightText) - .ToolTipText(this, &SWorldHierarchyItem::GetLevelDisplayNameTooltip) + TextWidget.ToSharedRef() ] ; } - else if (ColumnID == HierarchyColumns::ColumnID_LightingScenario) + else if (!bFoldersOnlyMode) { - TableRowContent = - SAssignNew(LightingScenarioButton, SButton) - .ContentPadding(0 ) - .ButtonStyle(FEditorStyle::Get(), "ToggleButton") - .IsEnabled(this, &SWorldHierarchyItem::IsLightingScenarioEnabled) - .OnClicked(this, &SWorldHierarchyItem::OnToggleLightingScenario) - .ToolTipText(this, &SWorldHierarchyItem::GetLightingScenarioToolTip) - .HAlign(HAlign_Center) - .VAlign(VAlign_Center) - .Content() - [ - SNew(SImage) - .Image(this, &SWorldHierarchyItem::GetLightingScenarioBrush) - ] - ; - } - else if (ColumnID == HierarchyColumns::ColumnID_Lock) - { - TableRowContent = - SAssignNew(LockButton, SButton) - .ContentPadding(0 ) - .ButtonStyle(FEditorStyle::Get(), "ToggleButton") - .IsEnabled(this, &SWorldHierarchyItem::IsLockEnabled) - .OnClicked(this, &SWorldHierarchyItem::OnToggleLock) - .ToolTipText(this, &SWorldHierarchyItem::GetLevelLockToolTip) - .HAlign(HAlign_Center) - .VAlign(VAlign_Center) - .Content() - [ - SNew(SImage) - .Image(this, &SWorldHierarchyItem::GetLevelLockBrush) - ] - ; - } - else if (ColumnID == HierarchyColumns::ColumnID_Visibility) - { - TableRowContent = - SAssignNew(VisibilityButton, SButton) - .ContentPadding(0) - .ButtonStyle(FEditorStyle::Get(), "ToggleButton") - .IsEnabled(this, &SWorldHierarchyItem::IsVisibilityEnabled) - .OnClicked(this, &SWorldHierarchyItem::OnToggleVisibility) - .ToolTipText(LOCTEXT("VisibilityButtonToolTip", "Toggle Level Visibility")) - .HAlign(HAlign_Center) - .VAlign(VAlign_Center) - .Content() - [ - SNew( SImage ) - .Image(this, &SWorldHierarchyItem::GetLevelVisibilityBrush) - ] - ; - } - else if (ColumnID == HierarchyColumns::ColumnID_Color) - { - TableRowContent = - SAssignNew(ColorButton, SButton) - .ContentPadding(0) - .ButtonStyle(FEditorStyle::Get(), "ToggleButton") - .IsEnabled(true) - .OnClicked(this, &SWorldHierarchyItem::OnChangeColor) - .ToolTipText(LOCTEXT("LevelColorButtonToolTip", "Change Level Color")) - .HAlign(HAlign_Center) - .VAlign(VAlign_Center) - .Visibility(this, &SWorldHierarchyItem::GetColorButtonVisibility) - .Content() - [ - SNew(SImage) - .ColorAndOpacity(this, &SWorldHierarchyItem::GetDrawColor) + // This is all information we do not want to display or modify if we only want to display item names + + if (ColumnID == HierarchyColumns::ColumnID_LightingScenario) + { + TableRowContent = + SAssignNew(LightingScenarioButton, SButton) + .ContentPadding(0) + .ButtonStyle(FEditorStyle::Get(), "ToggleButton") + .IsEnabled(this, &SWorldHierarchyItem::IsLightingScenarioEnabled) + .OnClicked(this, &SWorldHierarchyItem::OnToggleLightingScenario) + .ToolTipText(this, &SWorldHierarchyItem::GetLightingScenarioToolTip) + .Visibility(this, &SWorldHierarchyItem::GetLightingScenarioVisibility) + .HAlign(HAlign_Center) + .VAlign(VAlign_Center) + .Content() + [ + SNew(SImage) + .Image(this, &SWorldHierarchyItem::GetLightingScenarioBrush) + ] + ; + } + else if (ColumnID == HierarchyColumns::ColumnID_Lock) + { + TableRowContent = + SAssignNew(LockButton, SButton) + .ContentPadding(0) + .ButtonStyle(FEditorStyle::Get(), "ToggleButton") + .IsEnabled(this, &SWorldHierarchyItem::IsLockEnabled) + .OnClicked(this, &SWorldHierarchyItem::OnToggleLock) + .ToolTipText(this, &SWorldHierarchyItem::GetLevelLockToolTip) + .HAlign(HAlign_Center) + .VAlign(VAlign_Center) + .Content() + [ + SNew(SImage) + .Image(this, &SWorldHierarchyItem::GetLevelLockBrush) + ] + ; + } + else if (ColumnID == HierarchyColumns::ColumnID_Visibility) + { + TableRowContent = + SAssignNew(VisibilityButton, SButton) + .ContentPadding(0) + .ButtonStyle(FEditorStyle::Get(), "ToggleButton") + .IsEnabled(this, &SWorldHierarchyItem::IsVisibilityEnabled) + .OnClicked(this, &SWorldHierarchyItem::OnToggleVisibility) + .ToolTipText(this, &SWorldHierarchyItem::GetVisibilityToolTip) + .HAlign(HAlign_Center) + .VAlign(VAlign_Center) + .Content() + [ + SNew(SImage) + .Image(this, &SWorldHierarchyItem::GetLevelVisibilityBrush) + ] + ; + } + else if (ColumnID == HierarchyColumns::ColumnID_Color) + { + TableRowContent = + SAssignNew(ColorButton, SButton) + .ContentPadding(0) + .ButtonStyle(FEditorStyle::Get(), "ToggleButton") + .IsEnabled(true) + .OnClicked(this, &SWorldHierarchyItem::OnChangeColor) + .ToolTipText(LOCTEXT("LevelColorButtonToolTip", "Change Level Color")) + .HAlign(HAlign_Center) + .VAlign(VAlign_Center) + .Visibility(this, &SWorldHierarchyItem::GetColorButtonVisibility) + .Content() + [ + SNew(SImage) + .ColorAndOpacity(this, &SWorldHierarchyItem::GetDrawColor) .Image(this, &SWorldHierarchyItem::GetLevelColorBrush) - ] - ; - } - else if (ColumnID == HierarchyColumns::ColumnID_Kismet) - { - TableRowContent = - SAssignNew(KismetButton, SButton) - .ContentPadding(0) - .ButtonStyle(FEditorStyle::Get(), "ToggleButton") - .IsEnabled(this, &SWorldHierarchyItem::IsKismetEnabled) - .OnClicked(this, &SWorldHierarchyItem::OnOpenKismet) - .ToolTipText(LOCTEXT("KismetButtonToolTip", "Open Level Blueprint")) - .HAlign(HAlign_Center) - .VAlign(VAlign_Center) - .Content() - [ - SNew(SImage) - .Image(this, &SWorldHierarchyItem::GetLevelKismetBrush) - ] - ; - } - else if (ColumnID == HierarchyColumns::ColumnID_SCCStatus) - { - TableRowContent = - SNew(SVerticalBox) - +SVerticalBox::Slot() - .FillHeight(1.0f) - .HAlign(HAlign_Center) - .VAlign(VAlign_Center) - [ - SNew(SHorizontalBox) - +SHorizontalBox::Slot() - .FillWidth(1.0f) + ] + ; + } + else if (ColumnID == HierarchyColumns::ColumnID_Kismet) + { + TableRowContent = + SAssignNew(KismetButton, SButton) + .ContentPadding(0) + .ButtonStyle(FEditorStyle::Get(), "ToggleButton") + .IsEnabled(this, &SWorldHierarchyItem::IsKismetEnabled) + .OnClicked(this, &SWorldHierarchyItem::OnOpenKismet) + .ToolTipText(this, &SWorldHierarchyItem::GetKismetToolTip) + .HAlign(HAlign_Center) + .VAlign(VAlign_Center) + .Content() + [ + SNew(SImage) + .Image(this, &SWorldHierarchyItem::GetLevelKismetBrush) + ] + ; + } + else if (ColumnID == HierarchyColumns::ColumnID_SCCStatus) + { + TableRowContent = + SNew(SVerticalBox) + + SVerticalBox::Slot() + .FillHeight(1.0f) + .HAlign(HAlign_Center) .VAlign(VAlign_Center) [ - SNew( SImage ) + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .FillWidth(1.0f) + .VAlign(VAlign_Center) + [ + SNew(SImage) .Image(this, &SWorldHierarchyItem::GetSCCStateImage) .ToolTipText(this, &SWorldHierarchyItem::GetSCCStateTooltip) + ] ] - ] - ; - } - else if (ColumnID == HierarchyColumns::ColumnID_Save) - { - TableRowContent = - SAssignNew(SaveButton, SButton) - .ContentPadding(0) - .ButtonStyle(FEditorStyle::Get(), "ToggleButton") - .IsEnabled(this, &SWorldHierarchyItem::IsSaveEnabled) - .OnClicked(this, &SWorldHierarchyItem::OnSave) - .ToolTipText(LOCTEXT("SaveButtonToolTip", "Save Level")) - .HAlign( HAlign_Center ) - .VAlign( VAlign_Center ) - .Content() - [ - SNew(SImage) - .Image(this, &SWorldHierarchyItem::GetLevelSaveBrush) - ] - ; + ; + } + else if (ColumnID == HierarchyColumns::ColumnID_Save) + { + TableRowContent = + SAssignNew(SaveButton, SButton) + .ContentPadding(0) + .ButtonStyle(FEditorStyle::Get(), "ToggleButton") + .IsEnabled(this, &SWorldHierarchyItem::IsSaveEnabled) + .OnClicked(this, &SWorldHierarchyItem::OnSave) + .ToolTipText(this, &SWorldHierarchyItem::GetSaveToolTip) + .HAlign(HAlign_Center) + .VAlign(VAlign_Center) + .Content() + [ + SNew(SImage) + .Image(this, &SWorldHierarchyItem::GetLevelSaveBrush) + ] + ; + } } return TableRowContent.ToSharedRef(); } END_SLATE_FUNCTION_BUILD_OPTIMIZATION -FText SWorldHierarchyItem::GetLevelDisplayNameText() const +FText SWorldHierarchyItem::GetDisplayNameText() const { - return FText::FromString(LevelModel->GetDisplayName()); -} + FString DisplayString = WorldTreeItem->GetDisplayString(); + FText DisplayText; -FText SWorldHierarchyItem::GetLevelDisplayNameTooltip() const -{ - FString PackageName = LevelModel->GetLongPackageName().ToString(); - if (FPackageName::DoesPackageExist(PackageName)) + if (WorldTreeItem->IsReadOnly()) { - return FText::FromString(PackageName); + DisplayText = FText::Format(LOCTEXT("WorldItem_ReadOnly", "{0} (Read-Only)"), FText::FromString(DisplayString)); } else { - return LOCTEXT("UnsavedLevel", "Unsaved Level"); + DisplayText = FText::FromString(DisplayString); } + + return DisplayText; +} + +void SWorldHierarchyItem::OnLabelCommitted(const FText& InLabel, ETextCommit::Type InCommitInfo) +{ + WorldHierarchy::FFolderTreeItem* Folder = WorldTreeItem.IsValid() ? WorldTreeItem->GetAsFolderTreeItem() : nullptr; + + if (Folder != nullptr && !InLabel.ToString().Equals(Folder->GetLeafName().ToString(), ESearchCase::CaseSensitive)) + { + // Rename the item + FName OldPath = Folder->GetFullPath(); + FName NewPath = WorldHierarchy::GetParentPath(OldPath); + if (NewPath.IsNone()) + { + NewPath = FName(*InLabel.ToString()); + } + else + { + NewPath = FName(*(NewPath.ToString() / InLabel.ToString())); + } + + FLevelFolders::Get().RenameFolder(Folder->GetRootItem().ToSharedRef(), OldPath, NewPath); + + // TODO: Hand focus back to world hierarchy? + } +} + +bool SWorldHierarchyItem::OnVerifyItemLabelChanged(const FText& InLabel, FText& OutErrorMessage) +{ + WorldHierarchy::FFolderTreeItem* Folder = WorldTreeItem.IsValid() ? WorldTreeItem->GetAsFolderTreeItem() : nullptr; + + if (Folder == nullptr) + { + OutErrorMessage = LOCTEXT("RenameFailed_TreeItemDeleted", "Folder no longer exists"); + return false; + } + + FText TrimmedLabel = FText::TrimPrecedingAndTrailing(InLabel); + + if (TrimmedLabel.IsEmpty()) + { + OutErrorMessage = LOCTEXT("RenameFailed_LeftBlank", "Folder names cannot be left blank"); + return false; + } + + FString LabelString = TrimmedLabel.ToString(); + if (LabelString.Len() >= NAME_SIZE) + { + OutErrorMessage = FText::Format(LOCTEXT("RenameFailed_TooLong", "Names must be less than {0} characters long"), NAME_SIZE); + return false; + } + + if (Folder->GetLeafName().ToString() == LabelString) + { + return true; + } + + int32 Dummy = 0; + if (LabelString.FindChar('/', Dummy) || LabelString.FindChar('\\', Dummy)) + { + OutErrorMessage = LOCTEXT("RenameFailed_InvalidChar", "Folder names cannot contain / or \\"); + return false; + } + + // Validate that folder doesn't already exist + FName NewPath = WorldHierarchy::GetParentPath(Folder->GetFullPath()); + if (NewPath.IsNone()) + { + NewPath = FName(*LabelString); + } + else + { + NewPath = FName(*(NewPath.ToString() / LabelString)); + } + + if (FLevelFolders::Get().GetFolderProperties(Folder->GetRootItem().ToSharedRef(), NewPath)) + { + OutErrorMessage = LOCTEXT("RenameFailed_AlreadyExists", "A folder with this name already exists at this level"); + return false; + } + + return true; +} + +FText SWorldHierarchyItem::GetDisplayNameTooltip() const +{ + return WorldTreeItem->GetToolTipText(); } bool SWorldHierarchyItem::IsSaveEnabled() const { - return LevelModel->IsLoaded(); + return WorldTreeItem->CanSave(); } bool SWorldHierarchyItem::IsLightingScenarioEnabled() const { - return LevelModel->IsLoaded(); + return WorldTreeItem->HasLightingControls(); } bool SWorldHierarchyItem::IsLockEnabled() const { - return LevelModel->IsLoaded(); + return WorldTreeItem->HasLockControls(); } bool SWorldHierarchyItem::IsVisibilityEnabled() const { - return LevelModel->IsLoaded(); + return WorldTreeItem->HasVisibilityControls(); } bool SWorldHierarchyItem::IsKismetEnabled() const { - return LevelModel->HasKismet(); + return WorldTreeItem->HasKismet(); } FSlateColor SWorldHierarchyItem::GetDrawColor() const { - return FSlateColor(LevelModel->GetLevelColor()); + return WorldTreeItem->GetDrawColor(); } FReply SWorldHierarchyItem::OnToggleVisibility() { - FLevelModelList LevelList; - LevelList.Add(LevelModel); - - if (LevelModel->IsVisible()) - { - WorldModel->HideLevels(LevelList); - } - else - { - WorldModel->ShowLevels(LevelList); - } + WorldTreeItem->OnToggleVisibility(); return FReply::Handled(); } FReply SWorldHierarchyItem::OnToggleLightingScenario() { - LevelModel->SetIsLightingScenario(!LevelModel->IsLightingScenario()); + WorldTreeItem->OnToggleLightingScenario(); return FReply::Handled(); } FReply SWorldHierarchyItem::OnToggleLock() { - FLevelModelList LevelList; - LevelList.Add(LevelModel); - - if (LevelModel->IsLocked()) - { - WorldModel->UnlockLevels(LevelList); - } - else - { - WorldModel->LockLevels(LevelList); - } + WorldTreeItem->OnToggleLock(); return FReply::Handled(); } FReply SWorldHierarchyItem::OnSave() { - FLevelModelList LevelList; - LevelList.Add(LevelModel); - - - WorldModel->SaveLevels(LevelList); + WorldTreeItem->OnSave(); return FReply::Handled(); } FReply SWorldHierarchyItem::OnOpenKismet() { - LevelModel->OpenKismet(); + WorldTreeItem->OnOpenKismet(); return FReply::Handled(); } void SWorldHierarchyItem::OnSetColorFromColorPicker(FLinearColor NewColor) { - LevelModel->SetLevelColor(NewColor); + WorldTreeItem->SetDrawColor(NewColor); } void SWorldHierarchyItem::OnColorPickerCancelled(FLinearColor OriginalColor) { - LevelModel->SetLevelColor(OriginalColor); + WorldTreeItem->SetDrawColor(OriginalColor); } void SWorldHierarchyItem::OnColorPickerInteractiveBegin() @@ -348,11 +443,11 @@ void SWorldHierarchyItem::OnColorPickerInteractiveEnd() FReply SWorldHierarchyItem::OnChangeColor() { - if (LevelModel.IsValid()) + if (WorldTreeItem->HasColorButtonControls()) { FColorPickerArgs PickerArgs; PickerArgs.DisplayGamma = TAttribute::Create(TAttribute::FGetter::CreateUObject(GEngine, &UEngine::GetDisplayGamma)); - PickerArgs.InitialColorOverride = LevelModel->GetLevelColor(); + PickerArgs.InitialColorOverride = WorldTreeItem->GetDrawColor(); PickerArgs.bOnlyRefreshOnMouseUp = false; PickerArgs.bOnlyRefreshOnOk = false; PickerArgs.OnColorCommitted = FOnLinearColorValueChanged::CreateSP(this, &SWorldHierarchyItem::OnSetColorFromColorPicker); @@ -367,29 +462,77 @@ FReply SWorldHierarchyItem::OnChangeColor() return FReply::Handled(); } +EVisibility SWorldHierarchyItem::GetLightingScenarioVisibility() const +{ + EVisibility Result = EVisibility::Hidden; + if (WorldTreeItem->HasLightingControls() && WorldTreeItem->GetModel().Num() > 0) + { + Result = EVisibility::Visible; + } + return Result; +} + EVisibility SWorldHierarchyItem::GetColorButtonVisibility() const { EVisibility Result = EVisibility::Hidden; - if (LevelModel.IsValid()) + if (WorldTreeItem->HasColorButtonControls()) { - ULevel* LevelObject = LevelModel->GetLevelObject(); - if (LevelObject && !LevelObject->IsPersistentLevel()) - { - Result = EVisibility::Visible; - } + Result = EVisibility::Visible; } return Result; } +FText SWorldHierarchyItem::GetVisibilityToolTip() const +{ + return WorldTreeItem->GetVisibilityToolTipText(); +} + +FText SWorldHierarchyItem::GetSaveToolTip() const +{ + return WorldTreeItem->GetSaveToolTipText(); +} + +FText SWorldHierarchyItem::GetKismetToolTip() const +{ + FText KismetToolTip; + if (WorldTreeItem->HasKismet()) + { + KismetToolTip = LOCTEXT("KismetButtonToolTip", "Open Level Blueprint"); + } + return KismetToolTip; +} + +FReply SWorldHierarchyItem::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& Event) +{ + if (Event.GetEffectingButton() == EKeys::LeftMouseButton) + { + FReply Reply = SMultiColumnTableRow::OnMouseButtonDown(MyGeometry, Event); + + if (!bFoldersOnlyMode) + { + // Drags cannot start if we only want to display item names + return Reply.DetectDrag( SharedThis(this), EKeys::LeftMouseButton ); + } + + Reply.PreventThrottling(); + } + + return FReply::Handled(); +} + FReply SWorldHierarchyItem::OnItemDragDetected(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { if (MouseEvent.IsMouseButtonDown(EKeys::LeftMouseButton)) { - TSharedPtr Op = WorldModel->CreateDragDropOp(); - if (Op.IsValid()) + TSharedPtr HierarchyImpl = Hierarchy.Pin(); + + if (HierarchyImpl.IsValid()) { - // Start a drag-drop - return FReply::Handled().BeginDragDrop(Op.ToSharedRef()); + TSharedPtr DragDropOp = WorldHierarchy::CreateDragDropOperation(HierarchyImpl->GetSelectedTreeItems()); + if (DragDropOp.IsValid()) + { + return FReply::Handled().BeginDragDrop(DragDropOp.ToSharedRef()); + } } } @@ -398,47 +541,64 @@ FReply SWorldHierarchyItem::OnItemDragDetected(const FGeometry& MyGeometry, cons FReply SWorldHierarchyItem::OnDrop( const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent ) { - auto Op = DragDropEvent.GetOperationAs(); - if (Op.IsValid() && LevelModel->IsGoodToDrop(Op)) + WorldHierarchy::FValidationInfo ValidationInfo = WorldTreeItem->ValidateDrop(DragDropEvent); + + if (Hierarchy.Pin().IsValid()) { - LevelModel->OnDrop(Op); + if (ValidationInfo.bValid) + { + WorldTreeItem->OnDrop(DragDropEvent, Hierarchy.Pin().ToSharedRef()); + } return FReply::Handled(); } - + return FReply::Unhandled(); } void SWorldHierarchyItem::OnDragEnter( const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent ) { - SCompoundWidget::OnDragEnter(MyGeometry, DragDropEvent); - - auto Op = DragDropEvent.GetOperationAs(); - if (Op.IsValid()) + WorldHierarchy::FValidationInfo ValidationInfo = WorldTreeItem->ValidateDrop(DragDropEvent); + + FName IconName = ValidationInfo.bValid ? TEXT("Graph.ConnectorFeedback.OK") : TEXT("Graph.ConnectorFeedback.Error"); + const FSlateBrush* Icon = FEditorStyle::GetBrush(IconName); + + TSharedPtr Operation = DragDropEvent.GetOperation(); + if (Operation.IsValid()) { - // to show mouse hover effect - SWidget::OnMouseEnter(MyGeometry, DragDropEvent); - // D&D decorator icon - Op->bGoodToDrop = LevelModel->IsGoodToDrop(Op); + if (Operation->IsOfType()) + { + TSharedPtr HierarchyOp = DragDropEvent.GetOperationAs(); + HierarchyOp->SetToolTip(ValidationInfo.ValidationText, Icon); + } + else if (Operation->IsOfType() && !ValidationInfo.ValidationText.IsEmpty()) + { + TSharedPtr AssetOp = DragDropEvent.GetOperationAs(); + AssetOp->SetToolTip(ValidationInfo.ValidationText, Icon); + } } } void SWorldHierarchyItem::OnDragLeave( const FDragDropEvent& DragDropEvent ) { - SCompoundWidget::OnDragLeave(DragDropEvent); - - auto Op = DragDropEvent.GetOperationAs(); - if (Op.IsValid()) + TSharedPtr Operation = DragDropEvent.GetOperation(); + if (Operation.IsValid()) { - // to hide mouse hover effect - SWidget::OnMouseLeave(DragDropEvent); - // D&D decorator icon - Op->bGoodToDrop = false; + if (Operation->IsOfType()) + { + TSharedPtr HierarchyOp = DragDropEvent.GetOperationAs(); + HierarchyOp->ResetToDefaultToolTip(); + } + else if (Operation->IsOfType()) + { + TSharedPtr AssetOp = DragDropEvent.GetOperationAs(); + AssetOp->ResetToDefaultToolTip(); + } } } -FSlateFontInfo SWorldHierarchyItem::GetLevelDisplayNameFont() const +FSlateFontInfo SWorldHierarchyItem::GetDisplayNameFont() const { - if (LevelModel->IsCurrent()) + if (WorldTreeItem->IsCurrent()) { return FEditorStyle::GetFontStyle("WorldBrowser.LabelFontBold"); } @@ -448,29 +608,29 @@ FSlateFontInfo SWorldHierarchyItem::GetLevelDisplayNameFont() const } } -FSlateColor SWorldHierarchyItem::GetLevelDisplayNameColorAndOpacity() const +FSlateColor SWorldHierarchyItem::GetDisplayNameColorAndOpacity() const { // Force the text to display red if level is missing - if (!LevelModel->HasValidPackage()) + if (!WorldTreeItem->HasValidPackage()) { return FLinearColor(1.0f, 0.0f, 0.0f); } // Highlight text differently if it doesn't match the search filter (e.g., parent levels to child levels that // match search criteria.) - if (LevelModel->GetLevelFilteredOutFlag()) + if (WorldTreeItem->Flags.bFilteredOut) { return FLinearColor(0.30f, 0.30f, 0.30f); } - if (!LevelModel->IsLoaded()) + if (!WorldTreeItem->IsLoaded()) { return FSlateColor::UseSubduedForeground(); } - if (LevelModel->IsCurrent()) + if (WorldTreeItem->IsCurrent()) { - return LevelModel->GetLevelSelectionFlag() ? FSlateColor::UseForeground() : FLinearColor(0.12f, 0.56f, 1.0f); + return WorldTreeItem->GetLevelSelectionFlag() ? FSlateColor::UseForeground() : FLinearColor(0.12f, 0.56f, 1.0f); } return FSlateColor::UseForeground(); @@ -478,25 +638,14 @@ FSlateColor SWorldHierarchyItem::GetLevelDisplayNameColorAndOpacity() const const FSlateBrush* SWorldHierarchyItem::GetLevelIconBrush() const { - UClass* StreamingClass = LevelModel->GetStreamingClass(); - if (StreamingClass == ULevelStreamingKismet::StaticClass()) - { - return StreamingLevelKismetBrush; - } - - if (StreamingClass == ULevelStreamingAlwaysLoaded::StaticClass()) - { - return StreamingLevelAlwaysLoadedBrush; - } - - return nullptr; + return WorldTreeItem->GetHierarchyItemBrush(); } const FSlateBrush* SWorldHierarchyItem::GetLevelVisibilityBrush() const { - if (LevelModel->GetLevelObject()) + if (WorldTreeItem->HasVisibilityControls()) { - if (LevelModel->IsVisible()) + if (WorldTreeItem->IsVisible()) { return VisibilityButton->IsHovered() ? FEditorStyle::GetBrush( "Level.VisibleHighlightIcon16x" ) : FEditorStyle::GetBrush( "Level.VisibleIcon16x" ); @@ -515,7 +664,7 @@ const FSlateBrush* SWorldHierarchyItem::GetLevelVisibilityBrush() const const FSlateBrush* SWorldHierarchyItem::GetLightingScenarioBrush() const { - if (LevelModel->IsLightingScenario()) + if (WorldTreeItem->IsLightingScenario()) { return FEditorStyle::GetBrush( "Level.LightingScenarioIcon16x" ); } @@ -532,7 +681,7 @@ FText SWorldHierarchyItem::GetLightingScenarioToolTip() const const FSlateBrush* SWorldHierarchyItem::GetLevelLockBrush() const { - if (!LevelModel->IsLoaded() || LevelModel->IsPersistent()) + if (!WorldTreeItem->HasLockControls()) { //Locking the persistent level is not allowed; stub in a different brush return FEditorStyle::GetBrush( "Level.EmptyIcon16x" ); @@ -549,7 +698,7 @@ const FSlateBrush* SWorldHierarchyItem::GetLevelLockBrush() const // } //} - if (LevelModel->IsLocked()) + if (WorldTreeItem->IsLocked()) { return LockButton->IsHovered() ? FEditorStyle::GetBrush( "Level.LockedHighlightIcon16x" ) : FEditorStyle::GetBrush( "Level.LockedIcon16x" ); @@ -564,24 +713,19 @@ const FSlateBrush* SWorldHierarchyItem::GetLevelLockBrush() const FText SWorldHierarchyItem::GetLevelLockToolTip() const { - //Non-Persistent - if (GEngine && GEngine->bLockReadOnlyLevels) - { - if (LevelModel->IsFileReadOnly()) - { - return LOCTEXT("ReadOnly_LockButtonToolTip", "Read-Only levels are locked!"); - } - } - - return LOCTEXT("LockButtonToolTip", "Toggle Level Lock"); + return WorldTreeItem->GetLockToolTipText(); } FText SWorldHierarchyItem::GetSCCStateTooltip() const { - FSourceControlStatePtr SourceControlState = ISourceControlModule::Get().GetProvider().GetState(LevelModel->GetPackageFileName(), EStateCacheUsage::Use); - if(SourceControlState.IsValid()) + FString PackageName = WorldTreeItem->GetPackageFileName(); + if (!PackageName.IsEmpty()) { - return SourceControlState->GetDisplayTooltip(); + FSourceControlStatePtr SourceControlState = ISourceControlModule::Get().GetProvider().GetState(PackageName, EStateCacheUsage::Use); + if (SourceControlState.IsValid()) + { + return SourceControlState->GetDisplayTooltip(); + } } return FText::GetEmpty(); @@ -589,10 +733,10 @@ FText SWorldHierarchyItem::GetSCCStateTooltip() const const FSlateBrush* SWorldHierarchyItem::GetSCCStateImage() const { - FString PackageName = LevelModel->GetPackageFileName(); + FString PackageName = WorldTreeItem->GetPackageFileName(); if (!PackageName.IsEmpty()) { - FSourceControlStatePtr SourceControlState = ISourceControlModule::Get().GetProvider().GetState(LevelModel->GetPackageFileName(), EStateCacheUsage::Use); + FSourceControlStatePtr SourceControlState = ISourceControlModule::Get().GetProvider().GetState(PackageName, EStateCacheUsage::Use); if(SourceControlState.IsValid()) { return FEditorStyle::GetBrush(SourceControlState->GetSmallIconName()); @@ -604,15 +748,15 @@ const FSlateBrush* SWorldHierarchyItem::GetSCCStateImage() const const FSlateBrush* SWorldHierarchyItem::GetLevelSaveBrush() const { - if (LevelModel->IsLoaded()) + if (WorldTreeItem->IsLoaded()) { - if (LevelModel->IsLocked()) + if (WorldTreeItem->Flags.bLocked) { return FEditorStyle::GetBrush( "Level.SaveDisabledIcon16x" ); } else { - if (LevelModel->IsDirty()) + if (WorldTreeItem->IsDirty()) { return SaveButton->IsHovered() ? FEditorStyle::GetBrush( "Level.SaveModifiedHighlightIcon16x" ) : FEditorStyle::GetBrush( "Level.SaveModifiedIcon16x" ); @@ -632,9 +776,9 @@ const FSlateBrush* SWorldHierarchyItem::GetLevelSaveBrush() const const FSlateBrush* SWorldHierarchyItem::GetLevelKismetBrush() const { - if (LevelModel->IsLoaded()) + if (WorldTreeItem->IsLoaded()) { - if (LevelModel->HasKismet()) + if (WorldTreeItem->HasKismet()) { return KismetButton->IsHovered() ? FEditorStyle::GetBrush( "Level.ScriptHighlightIcon16x" ) : FEditorStyle::GetBrush( "Level.ScriptIcon16x" ); diff --git a/Engine/Source/Editor/WorldBrowser/Private/SWorldHierarchyItem.h b/Engine/Source/Editor/WorldBrowser/Private/SWorldHierarchyItem.h index 9a1b32edb8b6..5359fa9b16b0 100644 --- a/Engine/Source/Editor/WorldBrowser/Private/SWorldHierarchyItem.h +++ b/Engine/Source/Editor/WorldBrowser/Private/SWorldHierarchyItem.h @@ -12,9 +12,12 @@ #include "Widgets/Views/STableViewBase.h" #include "Widgets/Views/STableRow.h" +#include "IWorldTreeItem.h" + class FLevelCollectionModel; class FLevelModel; class SButton; +class SWorldHierarchyImpl; namespace HierarchyColumns { @@ -34,19 +37,23 @@ namespace HierarchyColumns /** A single item in the levels hierarchy tree. Represents a level model */ class SWorldHierarchyItem - : public SMultiColumnTableRow> + : public SMultiColumnTableRow { public: - DECLARE_DELEGATE_TwoParams( FOnNameChanged, const TSharedPtr& /*TreeItem*/, const FVector2D& /*MessageLocation*/); + DECLARE_DELEGATE_TwoParams( FOnNameChanged, const WorldHierarchy::FWorldTreeItemPtr& /*TreeItem*/, const FVector2D& /*MessageLocation*/); SLATE_BEGIN_ARGS( SWorldHierarchyItem ) : _IsItemExpanded( false ) + , _FoldersOnlyMode( false ) {} /** Data for the world */ SLATE_ARGUMENT(TSharedPtr, InWorldModel) /** Item model this widget represents */ - SLATE_ARGUMENT(TSharedPtr, InItemModel) + SLATE_ARGUMENT(WorldHierarchy::FWorldTreeItemPtr, InItemModel) + + /** The hierarchy that this item belongs to */ + SLATE_ARGUMENT(TSharedPtr, InHierarchy) /** True when this item has children and is expanded */ SLATE_ATTRIBUTE(bool, IsItemExpanded) @@ -54,6 +61,9 @@ public: /** The string in the title to highlight */ SLATE_ATTRIBUTE(FText, HighlightText) + /** If true, folders cannot be renamed and no other widget information is shown */ + SLATE_ARGUMENT(bool, FoldersOnlyMode) + SLATE_END_ARGS() /** Constructs this widget with InArgs */ @@ -62,9 +72,13 @@ public: TSharedRef GenerateWidgetForColumn( const FName& ColumnName ) override; FReply OnItemDragDetected(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent); - FReply OnDrop( const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent ) override; - void OnDragEnter( const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent ) override; - void OnDragLeave( const FDragDropEvent& DragDropEvent ) override; + virtual FReply OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) override; + virtual void OnDragEnter( const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent ) override; + virtual FReply OnDragOver( const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent ) override { return FReply::Handled(); } + virtual void OnDragLeave( const FDragDropEvent& DragDropEvent ) override; + +protected: + virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& Event) override; private: /** Operations buttons enabled/disabled state */ @@ -120,24 +134,36 @@ private: void OnColorPickerInteractiveBegin(); void OnColorPickerInteractiveEnd(); + /** Whether the lighting scenario button should be visible */ + EVisibility GetLightingScenarioVisibility() const; + /** Whether color button should be visible, depends on whether sub-level is loaded */ EVisibility GetColorButtonVisibility() const; + /** Gets the tooltip for the visibility toggle */ + FText GetVisibilityToolTip() const; + + /** Gets the tooltip for the save button */ + FText GetSaveToolTip() const; + + /** Gets the tooltip text for the Kismet button */ + FText GetKismetToolTip() const; + /** * @return The text of level name while it is not being edited */ - FText GetLevelDisplayNameText() const; + FText GetDisplayNameText() const; /** * @return The tooltip of level name (shows the full path of the asset package) */ - FText GetLevelDisplayNameTooltip() const; + FText GetDisplayNameTooltip() const; /** */ - FSlateFontInfo GetLevelDisplayNameFont() const; + FSlateFontInfo GetDisplayNameFont() const; /** */ - FSlateColor GetLevelDisplayNameColorAndOpacity() const; + FSlateColor GetDisplayNameColorAndOpacity() const; /** * @return The SlateBrush representing level icon @@ -198,12 +224,19 @@ private: /** */ const FSlateBrush* GetSCCStateImage() const; + bool OnVerifyItemLabelChanged(const FText& InLabel, FText& OutErrorMessage); + + void OnLabelCommitted(const FText& InLabel, ETextCommit::Type InCommitInfo); + private: /** The world data */ TSharedPtr WorldModel; /** The data for this item */ - TSharedPtr LevelModel; + WorldHierarchy::FWorldTreeItemPtr WorldTreeItem; + + /** The hierarchy for this item */ + TWeakPtr Hierarchy; /** The string to highlight in level display name */ TAttribute HighlightText; @@ -211,10 +244,6 @@ private: /** True when this item has children and is expanded */ TAttribute IsItemExpanded; - /** Brushes for the different streaming level types */ - const FSlateBrush* StreamingLevelAlwaysLoadedBrush; - const FSlateBrush* StreamingLevelKismetBrush; - /** The visibility button for the Level */ TSharedPtr VisibilityButton; @@ -232,4 +261,7 @@ private: /** The color button for the Level */ TSharedPtr ColorButton; + + /** If true, folders cannot be renamed and only folder names are ever shown */ + bool bFoldersOnlyMode; }; diff --git a/Engine/Source/Editor/WorldBrowser/Private/StreamingLevels/StreamingLevelCollectionModel.cpp b/Engine/Source/Editor/WorldBrowser/Private/StreamingLevels/StreamingLevelCollectionModel.cpp index 598b7d9ca9ff..4362566e6e04 100644 --- a/Engine/Source/Editor/WorldBrowser/Private/StreamingLevels/StreamingLevelCollectionModel.cpp +++ b/Engine/Source/Editor/WorldBrowser/Private/StreamingLevels/StreamingLevelCollectionModel.cpp @@ -230,23 +230,29 @@ void FStreamingLevelCollectionModel::BindCommands() } -TSharedPtr FStreamingLevelCollectionModel::CreateDragDropOp() const +TSharedPtr FStreamingLevelCollectionModel::CreateDragDropOp() const +{ + return CreateDragDropOp(SelectedLevelsList); +} + +TSharedPtr FStreamingLevelCollectionModel::CreateDragDropOp(const FLevelModelList& InLevels) const { TArray> LevelsToDrag; - for (auto It = SelectedLevelsList.CreateConstIterator(); It; ++It) + for (auto It = InLevels.CreateConstIterator(); It; ++It) { + check(AllLevelsList.Contains(*It)); TSharedPtr TargetModel = StaticCastSharedPtr(*It); - + if (TargetModel->GetLevelStreaming().IsValid()) { - LevelsToDrag.Add(TargetModel->GetLevelStreaming()); + LevelsToDrag.AddUnique(TargetModel->GetLevelStreaming()); } } if (LevelsToDrag.Num()) { - return FLevelDragDropOp::New(LevelsToDrag); + return WorldHierarchy::FWorldBrowserDragDropOp::New(LevelsToDrag); } else { @@ -410,7 +416,7 @@ const FLevelModelList& FStreamingLevelCollectionModel::GetInvalidSelectedLevels( //levels void FStreamingLevelCollectionModel::CreateEmptyLevel_Executed() { - EditorLevelUtils::CreateNewLevel( CurrentWorld.Get(), false, AddedLevelStreamingClass ); + EditorLevelUtils::CreateNewStreamingLevelForWorld( *CurrentWorld, AddedLevelStreamingClass, TEXT(""), false); // Force a cached level list rebuild PopulateLevelsList(); @@ -553,7 +559,7 @@ void FStreamingLevelCollectionModel::HandleAddExistingLevelCancelled() void FStreamingLevelCollectionModel::AddSelectedActorsToNewLevel_Executed() { - EditorLevelUtils::CreateNewLevel( CurrentWorld.Get(), true, AddedLevelStreamingClass ); + EditorLevelUtils::CreateNewStreamingLevelForWorld( *CurrentWorld, AddedLevelStreamingClass, TEXT(""), true); // Force a cached level list rebuild PopulateLevelsList(); @@ -601,11 +607,13 @@ void FStreamingLevelCollectionModel::MergeSelectedLevels_Executed() SelectActors_Executed(); //Create a new level with the selected actors - ULevel* NewLevel = EditorLevelUtils::CreateNewLevel(CurrentWorld.Get(), true, AddedLevelStreamingClass); + ULevelStreaming* NewStreamingLevel = EditorLevelUtils::CreateNewStreamingLevelForWorld(*CurrentWorld, AddedLevelStreamingClass, TEXT(""), true); //If the new level was successfully created (ie the user did not cancel) - if ((NewLevel != NULL) && (CurrentWorld.IsValid())) + if ((NewStreamingLevel != nullptr) && (CurrentWorld.IsValid())) { + ULevel* NewLevel = NewStreamingLevel->GetLoadedLevel(); + if (CurrentWorld->SetCurrentLevel(NewLevel)) { FEditorDelegates::NewCurrentLevel.Broadcast(); diff --git a/Engine/Source/Editor/WorldBrowser/Private/StreamingLevels/StreamingLevelCollectionModel.h b/Engine/Source/Editor/WorldBrowser/Private/StreamingLevels/StreamingLevelCollectionModel.h index 3ad6d88a35a5..2024efc035f6 100644 --- a/Engine/Source/Editor/WorldBrowser/Private/StreamingLevels/StreamingLevelCollectionModel.h +++ b/Engine/Source/Editor/WorldBrowser/Private/StreamingLevels/StreamingLevelCollectionModel.h @@ -36,11 +36,13 @@ public: /** FLevelCollection interface */ virtual void UnloadLevels(const FLevelModelList& InLevelList) override; virtual void AddExistingLevelsFromAssetData(const TArray& WorldList) override; - virtual TSharedPtr CreateDragDropOp() const override; + virtual TSharedPtr CreateDragDropOp() const override; + virtual TSharedPtr CreateDragDropOp(const FLevelModelList& InLevels) const override; virtual void BuildHierarchyMenu(FMenuBuilder& InMenuBuilder) const override; virtual void CustomizeFileMainMenu(FMenuBuilder& InMenuBuilder) const override; virtual void RegisterDetailsCustomization(class FPropertyEditorModule& PropertyModule, TSharedPtr InDetailsView) override; virtual void UnregisterDetailsCustomization(class FPropertyEditorModule& PropertyModule, TSharedPtr InDetailsView) override; + virtual bool HasFolderSupport() const override { return true; } private: virtual void Initialize(UWorld* InWorld) override; diff --git a/Engine/Source/Editor/WorldBrowser/Private/StreamingLevels/StreamingLevelModel.cpp b/Engine/Source/Editor/WorldBrowser/Private/StreamingLevels/StreamingLevelModel.cpp index e9af16ea208c..056e478325f1 100644 --- a/Engine/Source/Editor/WorldBrowser/Private/StreamingLevels/StreamingLevelModel.cpp +++ b/Engine/Source/Editor/WorldBrowser/Private/StreamingLevels/StreamingLevelModel.cpp @@ -96,6 +96,25 @@ void FStreamingLevelModel::SetLevelColor(FLinearColor InColor) } } +FName FStreamingLevelModel::GetFolderPath() const +{ + FName FolderPath = NAME_None; + if (LevelStreaming.IsValid()) + { + FolderPath = LevelStreaming->GetFolderPath(); + } + + return FolderPath; +} + +void FStreamingLevelModel::SetFolderPath(const FName& InFolderPath) +{ + if (LevelStreaming.IsValid()) + { + LevelStreaming->SetFolderPath(InFolderPath); + } +} + void FStreamingLevelModel::Update() { UpdatePackageFileAvailability(); diff --git a/Engine/Source/Editor/WorldBrowser/Private/StreamingLevels/StreamingLevelModel.h b/Engine/Source/Editor/WorldBrowser/Private/StreamingLevels/StreamingLevelModel.h index 03617ea98204..14315dd381db 100644 --- a/Engine/Source/Editor/WorldBrowser/Private/StreamingLevels/StreamingLevelModel.h +++ b/Engine/Source/Editor/WorldBrowser/Private/StreamingLevels/StreamingLevelModel.h @@ -47,6 +47,9 @@ public: virtual void OnDrop(const TSharedPtr& Op) override; virtual bool IsGoodToDrop(const TSharedPtr& Op) const override; virtual UClass* GetStreamingClass() const override; + FName GetFolderPath() const override; + virtual void SetFolderPath(const FName& InFolderPath) override; + virtual bool HasFolderSupport() const override { return true; } // FLevelModel interface end /** @return The ULevelStreaming this viewmodel contains*/ diff --git a/Engine/Source/Editor/WorldBrowser/Private/Tiles/WorldTileCollectionModel.cpp b/Engine/Source/Editor/WorldBrowser/Private/Tiles/WorldTileCollectionModel.cpp index cac26fef38a3..aa3cf6f4e3ee 100644 --- a/Engine/Source/Editor/WorldBrowser/Private/Tiles/WorldTileCollectionModel.cpp +++ b/Engine/Source/Editor/WorldBrowser/Private/Tiles/WorldTileCollectionModel.cpp @@ -236,36 +236,42 @@ void FWorldTileCollectionModel::TranslateLevels(const FLevelModelList& InLevels, RequestUpdateAllLevels(); } -TSharedPtr FWorldTileCollectionModel::CreateDragDropOp() const +TSharedPtr FWorldTileCollectionModel::CreateDragDropOp() const +{ + return CreateDragDropOp(SelectedLevelsList); +} + +TSharedPtr FWorldTileCollectionModel::CreateDragDropOp(const FLevelModelList& InLevels) const { TArray> LevelsToDrag; TArray> StreamingLevelsToDrag; if (!IsReadOnly()) { - for (TSharedPtr LevelModel : SelectedLevelsList) + for (TSharedPtr LevelModel : InLevels) { + check(AllLevelsList.Contains(LevelModel)); ULevel* Level = LevelModel->GetLevelObject(); if (Level) { - LevelsToDrag.Add(Level); + LevelsToDrag.AddUnique(Level); } TSharedPtr Tile = StaticCastSharedPtr(LevelModel); if (Tile->IsLoaded()) { - StreamingLevelsToDrag.Add(Tile->GetAssosiatedStreamingLevel()); + StreamingLevelsToDrag.AddUnique(Tile->GetAssosiatedStreamingLevel()); } else { // int32 TileStreamingIdx = GetWorld()->WorldComposition->TilesStreaming.IndexOfByPredicate( ULevelStreaming::FPackageNameMatcher(LevelModel->GetLongPackageName()) - ); + ); if (GetWorld()->WorldComposition->TilesStreaming.IsValidIndex(TileStreamingIdx)) { - StreamingLevelsToDrag.Add(GetWorld()->WorldComposition->TilesStreaming[TileStreamingIdx]); + StreamingLevelsToDrag.AddUnique(GetWorld()->WorldComposition->TilesStreaming[TileStreamingIdx]); } } } @@ -273,17 +279,17 @@ TSharedPtr FWorldTileCollectionModel::CreateDragDropOp() const if (LevelsToDrag.Num()) { - TSharedPtr Op = FLevelDragDropOp::New(LevelsToDrag); + TSharedPtr Op = WorldHierarchy::FWorldBrowserDragDropOp::New(LevelsToDrag); Op->StreamingLevelsToDrop = StreamingLevelsToDrag; return Op; } if (StreamingLevelsToDrag.Num()) { - TSharedPtr Op = FLevelDragDropOp::New(StreamingLevelsToDrag); + TSharedPtr Op = WorldHierarchy::FWorldBrowserDragDropOp::New(StreamingLevelsToDrag); return Op; } - + return FLevelCollectionModel::CreateDragDropOp(); } diff --git a/Engine/Source/Editor/WorldBrowser/Private/Tiles/WorldTileCollectionModel.h b/Engine/Source/Editor/WorldBrowser/Private/Tiles/WorldTileCollectionModel.h index 3ae04eed2bf2..e3b0f97c65c2 100644 --- a/Engine/Source/Editor/WorldBrowser/Private/Tiles/WorldTileCollectionModel.h +++ b/Engine/Source/Editor/WorldBrowser/Private/Tiles/WorldTileCollectionModel.h @@ -36,7 +36,8 @@ public: virtual void UnloadLevels(const FLevelModelList& InLevelList) override; virtual void TranslateLevels(const FLevelModelList& InList, FVector2D InAbsoluteDelta, bool bSnapDelta = true) override; virtual FVector2D SnapTranslationDelta(const FLevelModelList& InList, FVector2D InTranslationDelta, bool bBoundsSnapping, float InSnappingValue) override; - virtual TSharedPtr CreateDragDropOp() const override; + virtual TSharedPtr CreateDragDropOp() const override; + virtual TSharedPtr CreateDragDropOp(const FLevelModelList& InLevels) const override; virtual bool PassesAllFilters(const FLevelModel& InLevelModel) const override; virtual void BuildHierarchyMenu(FMenuBuilder& InMenuBuilder) const override; virtual void CustomizeFileMainMenu(FMenuBuilder& InMenuBuilder) const override; diff --git a/Engine/Source/Editor/WorldBrowser/Private/WorldBrowserDragDrop.cpp b/Engine/Source/Editor/WorldBrowser/Private/WorldBrowserDragDrop.cpp new file mode 100644 index 000000000000..7df29f4e196c --- /dev/null +++ b/Engine/Source/Editor/WorldBrowser/Private/WorldBrowserDragDrop.cpp @@ -0,0 +1,119 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "WorldBrowserDragDrop.h" +#include "EditorStyleSet.h" +#include "WorldTreeItemTypes.h" +#include "LevelCollectionModel.h" + +#define LOCTEXT_NAMESPACE "WorldBrowser" + +namespace WorldHierarchy +{ + TSharedPtr CreateDragDropOperation(const TArray& InTreeItems) + { + TSharedPtr Operation; + + if (InTreeItems.Num() > 0) + { + // Assume that the world model for the first selected item is the same world model for all items + TSharedPtr WorldModel = InTreeItems[0]->WorldModel.Pin(); + + if (WorldModel.IsValid()) + { + FDragDropPayload Payload; + Payload.DraggedTreeItems = InTreeItems; + + // Populate the list of models that are affected by this operation + FLevelModelList AffectedModels; + + for (FWorldTreeItemPtr Item : InTreeItems) + { + // Folder items should return all child models, but anything else should only return the model for that item + if (Item->GetAsFolderTreeItem() != nullptr) + { + AffectedModels.Append(Item->GetLevelModels()); + } + else + { + AffectedModels.Append(Item->GetModel()); + } + } + + TSharedPtr OutlinerOp = WorldModel->CreateDragDropOp(AffectedModels); + if (OutlinerOp.IsValid()) + { + OutlinerOp->Init(&Payload); + if (AffectedModels.Num() == 0) + { + OutlinerOp->Construct(); + } + Operation = OutlinerOp; + } + } + } + + return Operation; + } + + + FWorldBrowserDragDropOp::FWorldBrowserDragDropOp() + { + } + + void FWorldBrowserDragDropOp::Init(const FDragDropPayload* Payload) + { + FLevelDragDropOp::Init(); + + if (Payload != nullptr) + { + DraggedItems = Payload->DraggedTreeItems; + CurrentIconBrush = DraggedItems.Num() > 0 ? DraggedItems[0]->GetHierarchyItemBrush() : nullptr; + + if (DraggedItems.Num() == 1) + { + CurrentHoverText = FText::FromString(DraggedItems[0]->GetDisplayString()); + } + else + { + CurrentHoverText = FText::Format(LOCTEXT("WorldHierarchyDragDrop_Default", "{0} Items"), FText::AsNumber(DraggedItems.Num())); + } + + SetupDefaults(); + } + } + + TSharedPtr FWorldBrowserDragDropOp::GetDefaultDecorator() const + { + TSharedRef Decorator = SNew(SVerticalBox); + + Decorator->AddSlot() + [ + SNew(SBorder) + .BorderImage(FEditorStyle::GetBrush("Graph.ConnectorFeedback.Border")) + [ + SNew(SHorizontalBox) + + + SHorizontalBox::Slot() + .AutoWidth() + .Padding(0.0f, 0.0f, 3.0f, 0.0f) + [ + SNew(SImage) + .Image(this, &FDecoratedDragDropOp::GetIcon) + ] + + +SHorizontalBox::Slot() + .AutoWidth() + .VAlign(VAlign_Center) + [ + SNew(STextBlock) + .Text(this, &FDecoratedDragDropOp::GetHoverText) + ] + ] + ]; + + return Decorator; + } + +} // namespace WorldHierarchy + +#undef LOCTEXT_NAMESPACE \ No newline at end of file diff --git a/Engine/Source/Editor/WorldBrowser/Private/WorldBrowserDragDrop.h b/Engine/Source/Editor/WorldBrowser/Private/WorldBrowserDragDrop.h new file mode 100644 index 000000000000..6793ff42bc45 --- /dev/null +++ b/Engine/Source/Editor/WorldBrowser/Private/WorldBrowserDragDrop.h @@ -0,0 +1,80 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "Input/DragAndDrop.h" +#include "DragAndDrop/AssetDragDropOp.h" +#include "DragAndDrop/LevelDragDropOp.h" + +namespace WorldHierarchy +{ + struct IWorldTreeItem; + typedef TSharedPtr FWorldTreeItemPtr; + + struct FValidationInfo + { + FValidationInfo() + : bValid(true) + { + } + + FText ValidationText; + bool bValid; + }; + + + struct FDragDropPayload + { + /** World tree items */ + TArray DraggedTreeItems; + }; + + + /** Construct a new drag and drop operation for the world hierarchy */ + TSharedPtr CreateDragDropOperation(const TArray& InTreeItems); + + /** + * Used to drag folders and level items within the world hierarchy widget + */ + struct FWorldBrowserDragDropOp : public FLevelDragDropOp + { + DRAG_DROP_OPERATOR_TYPE(FWorldBrowserDragDropOp, FLevelDragDropOp); + + FWorldBrowserDragDropOp(); + + using FLevelDragDropOp::Construct; + + TArray GetDraggedItems() const { return DraggedItems; } + + /** Initializes the operation with the specified payload */ + void Init(const FDragDropPayload* Payload); + + virtual TSharedPtr GetDefaultDecorator() const override; + + /** Creates a drag and drop operation for the specified levels */ + static TSharedRef New(const TArray>& Levels) + { + TSharedRef Op = MakeShareable(new FWorldBrowserDragDropOp); + Op->LevelsToDrop.Append(Levels); + Op->Init(nullptr); + Op->Construct(); + return Op; + } + + /** Creates a drag and drop operation for the specified streaming levels */ + static TSharedRef New(const TArray>& StreamingLevels) + { + TSharedRef Op = MakeShareable(new FWorldBrowserDragDropOp); + Op->StreamingLevelsToDrop.Append(StreamingLevels); + Op->Init(nullptr); + Op->Construct(); + return Op; + } + + private: + + TArray DraggedItems; + }; + +} // namespace WorldHierarchy \ No newline at end of file diff --git a/Engine/Source/Editor/WorldBrowser/Private/WorldBrowserModule.cpp b/Engine/Source/Editor/WorldBrowser/Private/WorldBrowserModule.cpp index 80bd8b1407d5..89f71b071e22 100644 --- a/Engine/Source/Editor/WorldBrowser/Private/WorldBrowserModule.cpp +++ b/Engine/Source/Editor/WorldBrowser/Private/WorldBrowserModule.cpp @@ -6,6 +6,7 @@ #include "EditorModeRegistry.h" #include "EditorModes.h" #include "LevelCollectionCommands.h" +#include "LevelFolders.h" #include "Engine/WorldComposition.h" #include "StreamingLevels/StreamingLevelEdMode.h" @@ -36,10 +37,14 @@ void FWorldBrowserModule::StartupModule() } UWorldComposition::WorldCompositionChangedEvent.AddRaw(this, &FWorldBrowserModule::OnWorldCompositionChanged); + + FLevelFolders::Init(); } void FWorldBrowserModule::ShutdownModule() { + FLevelFolders::Cleanup(); + if (GEngine) { GEngine->OnWorldAdded().RemoveAll(this); diff --git a/Engine/Source/Editor/WorldBrowser/Private/WorldBrowserPrivateTypes.h b/Engine/Source/Editor/WorldBrowser/Private/WorldBrowserPrivateTypes.h new file mode 100644 index 000000000000..72818cc7b3d0 --- /dev/null +++ b/Engine/Source/Editor/WorldBrowser/Private/WorldBrowserPrivateTypes.h @@ -0,0 +1,187 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "Templates/MaxSizeof.h" +#include "UObject/ObjectKey.h" + +namespace WorldHierarchy +{ + /** Variable type for defining identifies for world tree items */ + struct FWorldTreeItemID + { + public: + + enum class EType : uint8 + { + Object, + Folder, + MissingObject, + Null, + }; + + FWorldTreeItemID() : Type(EType::Null), CachedHash(0) {} + + /** IDs for UObjects */ + FWorldTreeItemID(const UObject* InObject, FName ItemName) : Type(EType::Object) + { + if (InObject != nullptr) + { + new (Data) FObjectKey(InObject); + CachedHash = CalculateTypeHash(); + } + else + { + CreateAsMissing(ItemName); + } + } + FWorldTreeItemID(const FObjectKey& InKey) : Type(EType::Object) + { + new (Data) FObjectKey(InKey); + CachedHash = CalculateTypeHash(); + } + + /** IDs for folders */ + FWorldTreeItemID(const FName& InFolder) : Type(EType::Folder) + { + new (Data) FName(InFolder); + CachedHash = CalculateTypeHash(); + } + + /** Copy construction/assignment */ + FWorldTreeItemID(const FWorldTreeItemID& Other) + { + *this = Other; + } + FWorldTreeItemID& operator=(const FWorldTreeItemID& Other) + { + Type = Other.Type; + switch (Type) + { + case EType::Object: + new (Data) FObjectKey(Other.GetAsObjectKey()); + break; + case EType::Folder: + case EType::MissingObject: + new (Data) FName(Other.GetAsNameRef()); + break; + default: + break; + } + + CachedHash = CalculateTypeHash(); + return *this; + } + + /** Move construction/assignment */ + FWorldTreeItemID(FWorldTreeItemID&& Other) + { + *this = MoveTemp(Other); + } + FWorldTreeItemID& operator=(FWorldTreeItemID&& Other) + { + FMemory::Memswap(this, &Other, sizeof(FWorldTreeItemID)); + return *this; + } + + ~FWorldTreeItemID() + { + switch (Type) + { + case EType::Object: + GetAsObjectKey().~FObjectKey(); + break; + case EType::Folder: + case EType::MissingObject: + GetAsNameRef().~FName(); + break; + default: + break; + } + } + + friend bool operator==(const FWorldTreeItemID& One, const FWorldTreeItemID& Other) + { + return One.Compare(Other); + } + + friend bool operator!=(const FWorldTreeItemID& One, const FWorldTreeItemID& Other) + { + return !One.Compare(Other); + } + + uint32 CalculateTypeHash() const + { + uint32 Hash = 0; + switch (Type) + { + case EType::Object: + Hash = GetTypeHash(GetAsObjectKey()); + break; + case EType::Folder: + case EType::MissingObject: + Hash = GetTypeHash(GetAsNameRef()); + break; + default: + break; + } + + return HashCombine((uint8)Type, Hash); + } + + friend uint32 GetTypeHash(const FWorldTreeItemID& ItemID) + { + return ItemID.CachedHash; + } + + private: + + void CreateAsMissing(FName ObjectName) + { + Type = EType::MissingObject; + new (Data) FName(ObjectName); + CachedHash = CalculateTypeHash(); + } + + FObjectKey& GetAsObjectKey() const { return *reinterpret_cast(Data); } + FName& GetAsNameRef() const { return *reinterpret_cast(Data); } + + /** Compares the specified ID with this one, and returns true if they match. */ + bool Compare(const FWorldTreeItemID& Other) const + { + bool bSame = false; + + if (Type == Other.Type && CachedHash == Other.CachedHash) + { + switch (Type) + { + case EType::Object: + bSame = GetAsObjectKey() == Other.GetAsObjectKey(); + break; + case EType::Folder: + case EType::MissingObject: + bSame = GetAsNameRef() == Other.GetAsNameRef(); + break; + case EType::Null: + bSame = true; + break; + default: + check(false); + break; + } + } + + return bSame; + } + + private: + + static const uint32 MaxDataSize = TMaxSizeof::Value; + + EType Type; + uint32 CachedHash; + mutable uint8 Data[MaxDataSize]; + }; + +} // namespace WorldHierarchy \ No newline at end of file diff --git a/Engine/Source/Editor/WorldBrowser/Private/WorldTreeItemTypes.cpp b/Engine/Source/Editor/WorldBrowser/Private/WorldTreeItemTypes.cpp new file mode 100644 index 000000000000..7de5ea6f6d74 --- /dev/null +++ b/Engine/Source/Editor/WorldBrowser/Private/WorldTreeItemTypes.cpp @@ -0,0 +1,878 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "WorldTreeItemTypes.h" +#include "Templates/Casts.h" +#include "LevelModel.h" +#include "LevelCollectionModel.h" +#include "Misc/PackageName.h" +#include "Engine/Engine.h" +#include "SWorldHierarchyImpl.h" +#include "Framework/MultiBox/MultiBoxBuilder.h" +#include "EditorStyleSet.h" +#include "AssetSelection.h" +#include "SWorldHierarchyImpl.h" + +#include "Engine/LevelStreamingAlwaysLoaded.h" +#include "Engine/LevelStreamingKismet.h" + +#define LOCTEXT_NAMESPACE "WorldBrowser" + +namespace WorldHierarchy +{ + /** Utility function to get the leaf name of a specified path */ + FName GetPathLeafName(const FName& InPath) + { + FString PathString = InPath.ToString(); + FName LeafName = InPath; + int32 LeafIndex = 0; + if (PathString.FindLastChar(TCHAR('/'), LeafIndex)) + { + LeafName = FName(*PathString.RightChop(LeafIndex + 1)); + } + return LeafName; + } + + /** Utility function to get world assets from a drag operation */ + bool GetWorldAssetsFromDrag(TSharedPtr DragOp, TArray& OutWorlds) + { + TArray AssetList = AssetUtil::ExtractAssetDataFromDrag(DragOp); + + for (const FAssetData& Asset : AssetList) + { + if (Asset.AssetClass == UWorld::StaticClass()->GetFName()) + { + OutWorlds.Add(Asset); + } + } + + return OutWorlds.Num() > 0; + } + + //------------------------ + // FLevelModelTreeItem + //------------------------ + + FLevelModelTreeItem::FLevelModelTreeItem(TSharedRef InLevelModel) + : LevelModel(InLevelModel) + , bPersistentLevel(InLevelModel->IsPersistent()) + , ID(InLevelModel->GetLevelObject(), *InLevelModel->GetDisplayName()) + { + Flags.bExpanded = InLevelModel->GetLevelExpansionFlag(); + } + + FLevelModelList FLevelModelTreeItem::GetModel() const + { + FLevelModelList Models; + if (LevelModel.IsValid()) + { + Models.Add(LevelModel.Pin()); + } + + return Models; + } + + FWorldTreeItemID FLevelModelTreeItem::GetID() const + { + return ID; + } + + FWorldTreeItemPtr FLevelModelTreeItem::CreateParent() const + { + FWorldTreeItemPtr ParentPtr; + TSharedPtr Model = LevelModel.Pin(); + + if (Model->GetFolderPath() != NAME_None) + { + ParentPtr = MakeShareable(new FFolderTreeItem(Model->GetFolderPath())); + ParentPtr->WorldModel = WorldModel; + } + else if (Model->GetParent().IsValid()) + { + ParentPtr = MakeShareable(new FLevelModelTreeItem(Model->GetParent().ToSharedRef())); + ParentPtr->WorldModel = WorldModel; + } + + return ParentPtr; + } + + FString FLevelModelTreeItem::GetDisplayString() const + { + return LevelModel.IsValid() ? LevelModel.Pin()->GetDisplayName() : FString(); + } + + FText FLevelModelTreeItem::GetToolTipText() const + { + FString PackageName = LevelModel.IsValid() ? LevelModel.Pin()->GetLongPackageName().ToString() : FString(); + if (FPackageName::DoesPackageExist(PackageName)) + { + return FText::FromString(PackageName); + } + else + { + return LOCTEXT("UnsavedLevel", "Unsaved Level"); + } + } + + FText FLevelModelTreeItem::GetLockToolTipText() const + { + FText LockToolTip; + + if (!bPersistentLevel) + { + //Non-Persistent + if (GEngine && GEngine->bLockReadOnlyLevels) + { + if (LevelModel.IsValid() && LevelModel.Pin()->IsFileReadOnly()) + { + LockToolTip = LOCTEXT("ReadOnly_LockButtonToolTip", "Read-Only levels are locked!"); + } + } + + LockToolTip = LOCTEXT("LockButtonToolTip", "Toggle Level Lock"); + } + + return LockToolTip; + } + + FText FLevelModelTreeItem::GetVisibilityToolTipText() const + { + return LOCTEXT("VisibilityButtonToolTip", "Toggle Level Visibility"); + } + + FText FLevelModelTreeItem::GetSaveToolTipText() const + { + return LOCTEXT("SaveButtonToolTip", "Save Level"); + } + + FString FLevelModelTreeItem::GetPackageFileName() const + { + return IsLoaded() ? LevelModel.Pin()->GetPackageFileName() : FString(); + } + + FWorldTreeItemID FLevelModelTreeItem::GetParentID() const + { + FWorldTreeItemID ParentID; + TSharedPtr Model = LevelModel.Pin(); + + if (Parent.IsValid()) + { + ParentID = Parent->GetID(); + } + else if (!Model->GetFolderPath().IsNone()) + { + ParentID = Model->GetFolderPath(); + } + else if (Model->GetParent().IsValid()) + { + ParentID = FWorldTreeItemID(Model->GetParent()->GetLevelObject(), *Model->GetParent()->GetDisplayName()); + } + + return ParentID; + } + + bool FLevelModelTreeItem::CanHaveChildren() const + { + TSharedPtr Model = LevelModel.Pin(); + return Model.IsValid() && !Model->GetParent().IsValid(); + } + + void FLevelModelTreeItem::SetParentPath(const FName& InParentPath) + { + if (LevelModel.IsValid()) + { + LevelModel.Pin()->SetFolderPath(InParentPath); + } + } + + void FLevelModelTreeItem::SetExpansion(bool bExpanded) + { + IWorldTreeItem::SetExpansion(bExpanded); + LevelModel.Pin()->SetLevelExpansionFlag(bExpanded); + } + + bool FLevelModelTreeItem::HasModel(TSharedPtr InLevelModel) const + { + return InLevelModel.IsValid() && LevelModel.Pin().Get() == InLevelModel.Get(); + } + + TSet FLevelModelTreeItem::GetAncestorPaths() const + { + TSet Ancestors; + + if (LevelModel.IsValid()) + { + FName CurrentPath = LevelModel.Pin()->GetFolderPath(); + + while (!CurrentPath.IsNone()) + { + Ancestors.Add(CurrentPath); + CurrentPath = GetParentPath(CurrentPath); + } + } + + return Ancestors; + } + + bool FLevelModelTreeItem::CanSave() const + { + return IsLoaded(); + } + + bool FLevelModelTreeItem::HasLightingControls() const + { + return IsLoaded(); + } + + bool FLevelModelTreeItem::HasLockControls() const + { + // The root level cannot be locked + return IsLoaded() && Parent.IsValid(); + } + + bool FLevelModelTreeItem::HasVisibilityControls() const + { + return IsLoaded(); + } + + bool FLevelModelTreeItem::HasColorButtonControls() const + { + // The root level does not have a color button + return IsLoaded() && Parent.IsValid(); + } + + bool FLevelModelTreeItem::HasKismet() const + { + return LevelModel.IsValid() && LevelModel.Pin()->HasKismet(); + } + + bool FLevelModelTreeItem::IsCurrent() const + { + return LevelModel.IsValid() && LevelModel.Pin()->IsCurrent(); + } + + void FLevelModelTreeItem::MakeCurrent() + { + if (LevelModel.IsValid()) + { + LevelModel.Pin()->MakeLevelCurrent(); + } + } + + bool FLevelModelTreeItem::HasValidPackage() const + { + return LevelModel.IsValid() && LevelModel.Pin()->HasValidPackage(); + } + + bool FLevelModelTreeItem::IsDirty() const + { + return LevelModel.IsValid() && LevelModel.Pin()->IsDirty(); + } + + bool FLevelModelTreeItem::IsLoaded() const + { + return LevelModel.IsValid() && LevelModel.Pin()->IsLoaded(); + } + + FLinearColor FLevelModelTreeItem::GetDrawColor() const + { + return LevelModel.IsValid() ? LevelModel.Pin()->GetLevelColor() : FLinearColor::White; + } + + void FLevelModelTreeItem::SetDrawColor(const FLinearColor& Color) + { + if (LevelModel.IsValid()) + { + LevelModel.Pin()->SetLevelColor(Color); + } + } + + bool FLevelModelTreeItem::IsVisible() const + { + return LevelModel.IsValid() ? LevelModel.Pin()->IsVisible() : false; + } + + void FLevelModelTreeItem::OnToggleVisibility() + { + if (LevelModel.IsValid()) + { + SetVisible(!LevelModel.Pin()->IsVisible()); + } + } + + void FLevelModelTreeItem::SetVisible(bool bVisible) + { + FLevelModelList LevelModels; + + if (LevelModel.IsValid()) + { + LevelModels.Add(LevelModel.Pin()); + } + + if (bVisible) + { + WorldModel.Pin()->ShowLevels(LevelModels); + } + else + { + WorldModel.Pin()->HideLevels(LevelModels); + } + } + + void FLevelModelTreeItem::OnToggleLightingScenario() + { + TSharedPtr Model = LevelModel.Pin(); + if (Model.IsValid()) + { + Model->SetIsLightingScenario(!Model->IsLightingScenario()); + } + } + + void FLevelModelTreeItem::OnToggleLock() + { + if (LevelModel.IsValid()) + { + SetLocked(!LevelModel.Pin()->IsLocked()); + } + } + + bool FLevelModelTreeItem::IsLocked() const + { + return IsLoaded() && LevelModel.Pin()->IsLocked(); + } + + bool FLevelModelTreeItem::IsReadOnly() const + { + return IsLoaded() && LevelModel.Pin()->IsFileReadOnly(); + } + + void FLevelModelTreeItem::SetLocked(bool bLocked) + { + FLevelModelList LevelModels; + + if (LevelModel.IsValid()) + { + LevelModels.Add(LevelModel.Pin()); + } + + if (!LevelModel.Pin()->IsFileReadOnly()) + { + if (bLocked) + { + WorldModel.Pin()->LockLevels(LevelModels); + } + else + { + WorldModel.Pin()->UnlockLevels(LevelModels); + } + } + } + + void FLevelModelTreeItem::OnSave() + { + FLevelModelList LevelModels; + + if (LevelModel.IsValid()) + { + LevelModels.Add(LevelModel.Pin()); + } + + WorldModel.Pin()->SaveLevels(LevelModels); + } + + void FLevelModelTreeItem::OnOpenKismet() + { + if (LevelModel.IsValid()) + { + LevelModel.Pin()->OpenKismet(); + } + } + + bool FLevelModelTreeItem::GetLevelSelectionFlag() const + { + return LevelModel.IsValid() && LevelModel.Pin()->GetLevelSelectionFlag(); + } + + bool FLevelModelTreeItem::IsLightingScenario() const + { + return LevelModel.IsValid() && LevelModel.Pin()->IsLightingScenario(); + } + + const FSlateBrush* FLevelModelTreeItem::GetHierarchyItemBrush() const + { + UClass* StreamingClass = LevelModel.IsValid() ? LevelModel.Pin()->GetStreamingClass() : nullptr; + + if (StreamingClass == ULevelStreamingKismet::StaticClass()) + { + return FEditorStyle::GetBrush("WorldBrowser.LevelStreamingBlueprint"); + } + + if (StreamingClass == ULevelStreamingAlwaysLoaded::StaticClass()) + { + return FEditorStyle::GetBrush("WorldBrowser.LevelStreamingAlwaysLoaded"); + } + + return nullptr; + } + + bool FLevelModelTreeItem::CanChangeParents() const + { + return Parent.IsValid(); + } + + void FLevelModelTreeItem::GenerateContextMenu(FMenuBuilder& MenuBuilder, const SWorldHierarchyImpl& Hierarchy) + { + if (!Parent.IsValid() && WorldModel.Pin()->HasFolderSupport()) + { + // Persistent level items should be able to create new folders beneath them in the hierarchy + const FSlateIcon NewFolderIcon(FEditorStyle::GetStyleSetName(), "WorldBrowser.NewFolderIcon"); + + FName RootPath = LevelModel.Pin()->GetFolderPath(); + auto NewFolderAction = FExecuteAction::CreateSP(&Hierarchy, &SWorldHierarchyImpl::CreateFolder, LevelModel.Pin(), RootPath); + + MenuBuilder.AddMenuEntry(LOCTEXT("CreateFolder", "Create Folder"), FText(), NewFolderIcon, FUIAction(NewFolderAction)); + } + } + + FValidationInfo FLevelModelTreeItem::ValidateDrop(const FDragDropEvent& DragEvent) const + { + FValidationInfo ValidationInfo; + + TSharedPtr HierarchyOp = DragEvent.GetOperationAs(); + + if (HierarchyOp.IsValid()) + { + TArray SelectedItems = HierarchyOp->GetDraggedItems(); + + if (SelectedItems.Contains(AsShared())) + { + ValidationInfo.ValidationText = LOCTEXT("DropInvalid_CannotAttachToSelf", "Selection cannot be attached to itself"); + ValidationInfo.bValid = false; + } + else + { + TSet Ancestors = GetAncestorPaths(); + + for (FWorldTreeItemPtr Item : SelectedItems) + { + FWorldTreeItemPtr ItemParent = Item->GetParent(); + + if (!Item->CanChangeParents()) + { + ValidationInfo.ValidationText = LOCTEXT("DropInvalid_ItemCannotMove", "Cannot move selection"); + ValidationInfo.bValid = false; + } + else if (ItemParent.IsValid() && ItemParent.Get() == this) + { + ValidationInfo.ValidationText = LOCTEXT("DropInvalid_ItemAlreadyAttached", "Selection is already attached to this item"); + ValidationInfo.bValid = false; + } + else if (FFolderTreeItem* Folder = Item->GetAsFolderTreeItem()) + { + if (Ancestors.Contains(Folder->GetFullPath())) + { + ValidationInfo.ValidationText = LOCTEXT("DropInvalid_CannotBeChildOfSelf", "Selection cannot become a child of itself"); + ValidationInfo.bValid = false; + } + } + + if (!ValidationInfo.bValid) + { + break; + } + } + } + } + else + { + TArray WorldAssets; + ValidationInfo.bValid = GetWorldAssetsFromDrag(DragEvent.GetOperation(), WorldAssets); + } + + if (ValidationInfo.bValid && ValidationInfo.ValidationText.IsEmpty()) + { + FString ModelString = LevelModel.IsValid() ? LevelModel.Pin()->GetDisplayName() : TEXT("level"); + ValidationInfo.ValidationText = FText::Format(LOCTEXT("DropValid_MoveSelectionToLevel", "Drop selection on {0}"), FText::FromString(ModelString)); + } + + return ValidationInfo; + } + + void FLevelModelTreeItem::OnDrop(const FDragDropEvent& DragEvent, TSharedRef Hierarchy) + { + TSharedPtr HierarchyOp = DragEvent.GetOperationAs(); + + if (HierarchyOp.IsValid() && LevelModel.IsValid()) + { + Hierarchy->MoveDroppedItems(HierarchyOp->GetDraggedItems(), LevelModel.Pin()->GetFolderPath()); + LevelModel.Pin()->OnDrop(DragEvent.GetOperationAs()); + } + else + { + TArray Worlds; + if (GetWorldAssetsFromDrag(DragEvent.GetOperation(), Worlds)) + { + Hierarchy->AddDroppedLevelsToFolder(Worlds, NAME_None); + } + } + } + + + //------------------------ + // FFolderTreeItem + //------------------------ + + FFolderTreeItem::FFolderTreeItem(FName InPath) + : Path(InPath) + , LeafName(GetPathLeafName(InPath)) + { + } + + FWorldTreeItemID FFolderTreeItem::GetID() const + { + return FWorldTreeItemID(Path); + } + + FWorldTreeItemPtr FFolderTreeItem::CreateParent() const + { + FWorldTreeItemPtr ParentPtr; + + // Assume that the parent of this folder is another folder first + const FName ParentPath(GetParentPath(Path)); + if ( !ParentPath.IsNone() ) + { + ParentPtr = MakeShareable(new FFolderTreeItem(ParentPath)); + ParentPtr->WorldModel = WorldModel; + } + + // If there's no parent path, assume that it belongs to root level 0 + if ( !ParentPtr.IsValid() && WorldModel.IsValid() ) + { + FLevelModelList& RootLevels = WorldModel.Pin()->GetRootLevelList(); + + if (RootLevels.Num() > 0) + { + // TODO: Find a better solution than just root 0? + ParentPtr = MakeShareable((new FLevelModelTreeItem(RootLevels[0].ToSharedRef()))); + ParentPtr->WorldModel = WorldModel; + } + } + + return ParentPtr; + } + + FWorldTreeItemID FFolderTreeItem::GetParentID() const + { + FWorldTreeItemID ParentID; + + if (Parent.IsValid()) + { + ParentID = Parent->GetID(); + } + else if (!GetParentPath(Path).IsNone()) + { + ParentID = GetParentPath(Path); + } + else if (WorldModel.IsValid()) + { + FLevelModelList& RootLevels = WorldModel.Pin()->GetRootLevelList(); + + if (RootLevels.Num() > 0) + { + // TODO: Find a better solution than just root 0? + TSharedPtr Root = RootLevels[0]; + ParentID = FWorldTreeItemID(Root->GetLevelObject(), *Root->GetDisplayName()); + } + } + + return ParentID; + } + + TSet FFolderTreeItem::GetAncestorPaths() const + { + TSet Ancestors; + + FName CurrentPath = GetParentPath(GetFullPath()); + + while (!CurrentPath.IsNone()) + { + Ancestors.Add(CurrentPath); + CurrentPath = GetParentPath(CurrentPath); + } + + return Ancestors; + } + + FString FFolderTreeItem::GetDisplayString() const + { + return LeafName.ToString(); + } + + FText FFolderTreeItem::GetToolTipText() const + { + return FText::FromName(Path); + } + + FText FFolderTreeItem::GetLockToolTipText() const + { + FText LockToolTip; + + if (IsLocked()) + { + LockToolTip = LOCTEXT("FolderUnlockAllLevels_ToolTip", "Unlock All Levels"); + } + else + { + LockToolTip = LOCTEXT("FolderLockAllLevels_ToolTip", "Lock All Levels"); + } + + return LockToolTip; + } + + FText FFolderTreeItem::GetVisibilityToolTipText() const + { + return LOCTEXT("FolderVisibilityButtonToolTip", "Toggle Visibility for All Levels"); + } + + FText FFolderTreeItem::GetSaveToolTipText() const + { + return LOCTEXT("FolderSaveButtonToolTip", "Save All Levels"); + } + + void FFolderTreeItem::SetNewPath(FName NewPath) + { + Path = NewPath; + LeafName = GetPathLeafName(NewPath); + } + + void FFolderTreeItem::SetParentPath(const FName& InParentPath) + { + Path = FName(*(InParentPath.ToString() + LeafName.ToString())); + } + + bool FFolderTreeItem::CanSave() const + { + return IsAnyChildLoaded(); + } + + bool FFolderTreeItem::HasLockControls() const + { + // If the folder has no level models associated with it, always show the lock icon + return GetLevelModels().Num() == 0 || IsAnyChildLoaded(); + } + + bool FFolderTreeItem::HasVisibilityControls() const + { + // If the folder has no level models associated with it, always show the visibility icon + return GetLevelModels().Num() == 0 || IsAnyChildLoaded(); + } + + bool FFolderTreeItem::HasValidPackage() const + { + // Return true only if all children have valid packages + bool bAllValid = true; + for (const auto& Child : Children) + { + bAllValid = Child->HasValidPackage(); + + if (!bAllValid) + { + break; + } + } + + return bAllValid; + } + + bool FFolderTreeItem::IsDirty() const + { + FLevelModelList LevelModels = GetLevelModels(); + + return LevelModels.ContainsByPredicate([](const TSharedPtr& LevelModel) -> bool + { + return LevelModel.IsValid() && LevelModel->IsDirty(); + }); + } + + bool FFolderTreeItem::IsAnyChildLoaded() const + { + FLevelModelList LevelModels = GetLevelModels(); + + return LevelModels.ContainsByPredicate([](const TSharedPtr& LevelModel) -> bool + { + return LevelModel.IsValid() && LevelModel->IsLoaded(); + }); + } + + bool FFolderTreeItem::IsVisible() const + { + for (FWorldTreeItemPtr Child : Children) + { + if (Child->IsVisible()) + { + return true; + } + } + + return false; + } + + void FFolderTreeItem::OnToggleVisibility() + { + SetVisible(!IsVisible()); + } + + void FFolderTreeItem::SetVisible(bool bVisible) + { + for (auto& Child : Children) + { + Child->SetVisible(bVisible); + } + } + + bool FFolderTreeItem::IsLocked() const + { + for (FWorldTreeItemPtr Child : Children) + { + if (Child->IsLocked()) + { + return true; + } + } + + return false; + } + + void FFolderTreeItem::OnToggleLock() + { + SetLocked(!IsLocked()); + } + + void FFolderTreeItem::SetLocked(bool bLocked) + { + for (auto& Child : Children) + { + Child->SetLocked(bLocked); + } + } + + void FFolderTreeItem::OnSave() + { + WorldModel.Pin()->SaveLevels(GetLevelModels()); + } + + const FSlateBrush* FFolderTreeItem::GetHierarchyItemBrush() const + { + if (Children.Num() > 0 && Flags.bExpanded) + { + return FEditorStyle::Get().GetBrush("WorldBrowser.FolderOpen"); + } + + return FEditorStyle::Get().GetBrush("WorldBrowser.FolderClosed"); + } + + void FFolderTreeItem::GenerateContextMenu(FMenuBuilder& MenuBuilder, const SWorldHierarchyImpl& Hierarchy) + { + // Folder items should be able to create subfolders, rename themselves, or delete themselves from the tree + const FSlateIcon NewFolderIcon(FEditorStyle::GetStyleSetName(), "WorldBrowser.NewFolderIcon"); + + TSharedPtr RootLevel = GetRootItem(); + TArray Folders; + Folders.Add(AsShared()); + + auto NewFolderAction = FExecuteAction::CreateSP(&Hierarchy, &SWorldHierarchyImpl::CreateFolder, RootLevel, Path); + auto RenameFolderAction = FExecuteAction::CreateSP(&Hierarchy, &SWorldHierarchyImpl::InitiateRename, AsShared()); + auto DeleteFolderAction = FExecuteAction::CreateSP(&Hierarchy, &SWorldHierarchyImpl::DeleteFolders, Folders, /*bTransactional*/ true); + + MenuBuilder.AddMenuEntry(LOCTEXT("CreateSubFolder", "Create Subfolder"), FText(), NewFolderIcon, FUIAction(NewFolderAction)); + MenuBuilder.AddMenuEntry(LOCTEXT("RenameFolder", "Rename"), FText(), FSlateIcon(), FUIAction(RenameFolderAction)); + MenuBuilder.AddMenuEntry(LOCTEXT("DeleteFolder", "Delete"), FText(), FSlateIcon(), FUIAction(DeleteFolderAction)); + } + + FValidationInfo FFolderTreeItem::ValidateDrop(const FDragDropEvent& DragEvent) const + { + FValidationInfo ValidationInfo; + + TSharedPtr HierarchyOp = DragEvent.GetOperationAs(); + + if (HierarchyOp.IsValid()) + { + TSet Ancestors = GetAncestorPaths(); + + for (FWorldTreeItemPtr Item : HierarchyOp->GetDraggedItems()) + { + if (FFolderTreeItem* Folder = Item->GetAsFolderTreeItem()) + { + if (Path == Folder->GetFullPath()) + { + ValidationInfo.ValidationText = LOCTEXT("DropInvalid_CannotAttachToSelf", "Selection cannot be attached to itself"); + ValidationInfo.bValid = false; + } + else if (Children.Contains(Item)) + { + ValidationInfo.ValidationText = LOCTEXT("DropInvalid_AlreadyInFolder", "Selection is already in folder"); + ValidationInfo.bValid = false; + } + else if (Ancestors.Contains(Folder->GetFullPath())) + { + ValidationInfo.ValidationText = LOCTEXT("DropInvalid_CannotBeChildOfSelf", "Selection cannot become a child of itself"); + ValidationInfo.bValid = false; + } + } + else if (FLevelModelTreeItem* ModelItem = Item->GetAsLevelModelTreeItem()) + { + for (TSharedPtr Model : ModelItem->GetModel()) + { + if (Model->GetFolderPath() == Path) + { + ValidationInfo.ValidationText = LOCTEXT("DropInvalid_AlreadyInFolder", "Selection is already in folder"); + ValidationInfo.bValid = false; + } + else if (!Model->HasFolderSupport()) + { + ValidationInfo.ValidationText = LOCTEXT("DropInvalid_NoFolderSupport", "Selected levels cannot be added to folders"); + ValidationInfo.bValid = false; + } + } + } + + if (!ValidationInfo.bValid) + { + break; + } + } + } + else + { + TArray Worlds; + ValidationInfo.bValid = GetWorldAssetsFromDrag(DragEvent.GetOperation(), Worlds); + } + + if (ValidationInfo.bValid && ValidationInfo.ValidationText.IsEmpty()) + { + ValidationInfo.ValidationText = FText::Format(LOCTEXT("DropValid_MoveToFolder", "Move selection to {0}"), FText::FromName(LeafName)); + } + + return ValidationInfo; + } + + void FFolderTreeItem::OnDrop(const FDragDropEvent& DragEvent, TSharedRef Hierarchy) + { + TSharedPtr HierarchyOp = DragEvent.GetOperationAs(); + + if (HierarchyOp.IsValid()) + { + Hierarchy->MoveDroppedItems(HierarchyOp->GetDraggedItems(), Path); + } + else + { + TArray Worlds; + if (GetWorldAssetsFromDrag(DragEvent.GetOperation(), Worlds)) + { + Hierarchy->AddDroppedLevelsToFolder(Worlds, Path); + } + } + } + +} // namespace WorldHierarchy + +#undef LOCTEXT_NAMESPACE \ No newline at end of file diff --git a/Engine/Source/Editor/WorldBrowser/Private/WorldTreeItemTypes.h b/Engine/Source/Editor/WorldBrowser/Private/WorldTreeItemTypes.h new file mode 100644 index 000000000000..4aaee0c6f2cb --- /dev/null +++ b/Engine/Source/Editor/WorldBrowser/Private/WorldTreeItemTypes.h @@ -0,0 +1,185 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "IWorldTreeItem.h" + +namespace WorldHierarchy +{ + static const int32 FolderSortPriority = 10; + static const int32 LevelModelSortPriority = 0; + + /** The tree item for the level models */ + struct FLevelModelTreeItem : IWorldTreeItem + { + public: + + FLevelModelTreeItem(TSharedRef InLevelModel); + + virtual FWorldTreeItemID GetID() const override; + + virtual FWorldTreeItemPtr CreateParent() const override; + + virtual FLevelModelList GetModel() const override; + + virtual FString GetDisplayString() const override; + + virtual FText GetToolTipText() const override; + + virtual FText GetLockToolTipText() const override; + + virtual FText GetVisibilityToolTipText() const override; + + virtual FText GetSaveToolTipText() const override; + + virtual FString GetPackageFileName() const override; + + virtual FWorldTreeItemID GetParentID() const override; + + virtual bool CanHaveChildren() const override; + + virtual void SetExpansion(bool bExpanded) override; + + virtual bool HasModel(TSharedPtr InLevelModel) const override; + + virtual TSet GetAncestorPaths() const override; + + virtual void SetParentPath(const FName& InParentPath) override; + + virtual int32 GetSortPriority() const override { return LevelModelSortPriority; } + + virtual bool IsVisible() const override; + virtual bool IsLocked() const override; + virtual bool IsReadOnly() const override; + + public: + virtual bool CanSave() const override; + virtual bool HasLightingControls() const override; + virtual bool HasLockControls() const override; + virtual bool HasVisibilityControls() const override; + virtual bool HasColorButtonControls() const override; + virtual bool HasKismet() const override; + + virtual bool IsCurrent() const override; + virtual bool CanBeCurrent() const override { return true; } + virtual void MakeCurrent() override; + virtual bool HasValidPackage() const override; + virtual bool IsDirty() const override; + virtual bool IsLoaded() const override; + + virtual FLinearColor GetDrawColor() const override; + virtual void SetDrawColor(const FLinearColor& Color) override; + + virtual void OnToggleVisibility() override; + virtual void OnToggleLightingScenario() override; + virtual void OnToggleLock() override; + virtual void OnSave() override; + virtual void OnOpenKismet() override; + + virtual bool GetLevelSelectionFlag() const override; + virtual bool IsLightingScenario() const override; + virtual const FSlateBrush* GetHierarchyItemBrush() const override; + + virtual bool CanChangeParents() const override; + virtual void GenerateContextMenu(FMenuBuilder& MenuBuilder, const SWorldHierarchyImpl& Hierarchy) override; + + public: + virtual FLevelModelTreeItem* GetAsLevelModelTreeItem() const override { return const_cast(this); } + virtual FFolderTreeItem* GetAsFolderTreeItem() const override { return nullptr; } + + virtual void SetVisible(bool bVisible) override; + virtual void SetLocked(bool bLocked) override; + + public: + //~ IDropTarget + virtual FValidationInfo ValidateDrop(const FDragDropEvent& DragEvent) const override; + virtual void OnDrop(const FDragDropEvent& DragEvent, TSharedRef Hierarchy) override; + + protected: + TWeakPtr LevelModel; + bool bPersistentLevel : 1; + + private: + + FWorldTreeItemID ID; + }; + + + /** The tree item for the folders */ + struct FFolderTreeItem : IWorldTreeItem + { + public: + + FFolderTreeItem(FName InPath); + + public: + + virtual FWorldTreeItemID GetID() const override; + + virtual FWorldTreeItemPtr CreateParent() const override; + + virtual FString GetDisplayString() const override; + + virtual FText GetToolTipText() const override; + + virtual FText GetLockToolTipText() const override; + + virtual FText GetVisibilityToolTipText() const override; + + virtual FText GetSaveToolTipText() const override; + + virtual FWorldTreeItemID GetParentID() const override; + + virtual void SetParentPath(const FName& InParentPath) override; + + virtual TSet GetAncestorPaths() const override; + + virtual bool CanHaveChildren() const override { return true; } + + virtual int32 GetSortPriority() const override { return FolderSortPriority; } + + virtual bool IsVisible() const override; + virtual bool IsLocked() const override; + + virtual bool CanSave() const override; + virtual bool HasLockControls() const override; + virtual bool HasVisibilityControls() const override; + virtual bool HasValidPackage() const override; + virtual bool IsDirty() const override; + + virtual void OnToggleVisibility() override; + virtual void OnToggleLock() override; + virtual void OnSave() override; + virtual const FSlateBrush* GetHierarchyItemBrush() const override; + virtual float GetHierarchyItemBrushWidth() const { return 16.0f; } + + virtual bool CanChangeParents() const { return true; } + virtual void GenerateContextMenu(FMenuBuilder& MenuBuilder, const SWorldHierarchyImpl& Hierarchy) override; + + /** Sets the new path of the folder. This includes the leaf name. This will not rename any children in this folder */ + void SetNewPath(FName NewPath); + + public: + virtual FLevelModelTreeItem* GetAsLevelModelTreeItem() const override { return nullptr; } + virtual FFolderTreeItem* GetAsFolderTreeItem() const override { return const_cast(this); } + + FName GetFullPath() const { return Path; } + FName GetLeafName() const { return LeafName; } + + virtual void SetVisible(bool bVisible) override; + virtual void SetLocked(bool bLocked) override; + + public: + //~ IDropTarget + virtual FValidationInfo ValidateDrop(const FDragDropEvent& DragEvent) const override; + virtual void OnDrop(const FDragDropEvent& DragEvent, TSharedRef Hierarchy) override; + + private: + bool IsAnyChildLoaded() const; + + private: + FName Path; + FName LeafName; + }; + +} // namespace WorldHierarchy \ No newline at end of file diff --git a/Engine/Source/Editor/WorldBrowser/Public/IWorldTreeItem.h b/Engine/Source/Editor/WorldBrowser/Public/IWorldTreeItem.h new file mode 100644 index 000000000000..25027c8f5944 --- /dev/null +++ b/Engine/Source/Editor/WorldBrowser/Public/IWorldTreeItem.h @@ -0,0 +1,282 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "Misc/Paths.h" +#include "Misc/CoreDelegates.h" +#include "WorldBrowserPrivateTypes.h" +#include "LevelModel.h" +#include "Styling/SlateBrush.h" +#include "WorldBrowserDragDrop.h" + +class SWidget; +class SWorldHierarchy; +class FLevelCollectionModel; +class SWorldHierarchyImpl; +class FMenuBuilder; + +namespace WorldHierarchy +{ + struct IWorldTreeItem; + typedef TSharedPtr FWorldTreeItemPtr; + typedef TSharedRef FWorldTreeItemRef; + + /** Interface for validating drag/drop movement */ + struct IDropTarget + { + /** Called to test whether the specified payload can be dropped onto this tree item */ + virtual FValidationInfo ValidateDrop(const FDragDropEvent& DragEvent) const = 0; + + /** Called to drop the specified objects on this item. Only called if ValidateDrop() allows. */ + virtual void OnDrop(const FDragDropEvent& DragEvent, TSharedRef Hierarchy) = 0; + }; + + struct FLevelModelTreeItem; + struct FFolderTreeItem; + + /** Base tree item interface for the World Browser */ + struct IWorldTreeItem : IDropTarget, TSharedFromThis + { + friend SWorldHierarchy; + + struct FlagsType + { + bool bExpanded : 1; + + bool bFilteredOut : 1; + + bool bChildrenRequiresSort : 1; + + bool bVisible : 1; + + bool bLocked : 1; + + FlagsType() + : bExpanded(1) + , bFilteredOut(0) + , bChildrenRequiresSort(1) + {} + }; + + public: + + FlagsType Flags; + + DECLARE_DELEGATE( FOnRenameRequest ); + + FOnRenameRequest RenameRequestEvent; + + TWeakPtr WorldModel; + + protected: + + IWorldTreeItem() {} + virtual ~IWorldTreeItem() {} + + /** The parent of this tree item. Can be null. */ + mutable FWorldTreeItemPtr Parent; + + /** The children of this tree item, if any */ + mutable TArray Children; + + public: + FWorldTreeItemPtr GetParent() const + { + return Parent; + } + + TSharedPtr GetRootItem() const + { + const IWorldTreeItem* Ancestor = this; + + while (Ancestor->GetParent().IsValid()) + { + Ancestor = Ancestor->GetParent().Get(); + } + + // Assume that the root item will only ever have one level model item + return Ancestor->GetModel()[0]; + } + + void AddChild(FWorldTreeItemRef Child) + { + Child->Parent = AsShared(); + Children.Add(MoveTemp(Child)); + } + + void RemoveChild(const FWorldTreeItemRef& Child) + { + if (Children.Remove(Child)) + { + Child->Parent = nullptr; + } + } + + FORCEINLINE const TArray& GetChildren() const + { + return Children; + } + + FORCEINLINE void RemoveAllChildren() + { + Children.Reset(); + } + + /** Gets all level models for this tree item and its children */ + FLevelModelList GetLevelModels() const + { + FLevelModelList Models; + AppendLevelModels(Models); + + return Models; + } + + /** Appends all level models for this tree item to the supplied array */ + void AppendLevelModels(FLevelModelList& OutLevelModels) const + { + OutLevelModels.Append(GetModel()); + + for (const FWorldTreeItemPtr& Child : Children) + { + Child->AppendLevelModels(OutLevelModels); + } + } + + /** Gets the level model for this item, excluding its children */ + virtual FLevelModelList GetModel() const { return FLevelModelList(); } + + /** Gets the set of all ancestor paths for this item */ + virtual TSet GetAncestorPaths() const = 0; + + public: + + /** Gets the ID for this tree item */ + virtual FWorldTreeItemID GetID() const = 0; + + /** Create the parent item for this item, if it should have one */ + virtual FWorldTreeItemPtr CreateParent() const = 0; + + /** Gets the display string for this item */ + virtual FString GetDisplayString() const = 0; + + /** Gets the tooltip for this item */ + virtual FText GetToolTipText() const = 0; + + /** Gets the tooltip for this item's lock icon */ + virtual FText GetLockToolTipText() const = 0; + + /** Gets the tooltip for this item's visibility icon */ + virtual FText GetVisibilityToolTipText() const = 0; + + /** Gets the tooltip text for this item's save icon */ + virtual FText GetSaveToolTipText() const = 0; + + /** Gets the filename of the package for this item, if one exists */ + virtual FString GetPackageFileName() const { return FString(); } + + /** Gets the ID of the parent item, even if it is not yet constructed */ + virtual FWorldTreeItemID GetParentID() const = 0; + + /** Returns true if the item can have children */ + virtual bool CanHaveChildren() const = 0; + + /** Sets the item's expansion state */ + virtual void SetExpansion(bool bExpanded) + { + Flags.bExpanded = bExpanded; + } + + /** Returns true if this item has an associated level model with it */ + virtual bool HasModel(TSharedPtr InLevelModel) const { return false; } + + /** Changes the parent path of this item, without changing the name of this item */ + virtual void SetParentPath(const FName& InParentPath) = 0; + + /** Gets the sort priority of the item. A higher value means it will appear first in the list */ + virtual int32 GetSortPriority() const = 0; + + public: + + virtual FLevelModelTreeItem* GetAsLevelModelTreeItem() const = 0; + virtual FFolderTreeItem* GetAsFolderTreeItem() const = 0; + + public: + + virtual bool IsVisible() const = 0; + virtual bool IsLocked() const = 0; + + /** Can this item be saved? */ + virtual bool CanSave() const { return false; } + + /** Does this item have lighting controls? */ + virtual bool HasLightingControls() const { return false; } + + /** Can the lock state on this item be toggled? */ + virtual bool HasLockControls() const { return true; } + + /** Can visibility on this item be toggled? */ + virtual bool HasVisibilityControls() const { return true; } + + /** Does this item have color button controls? */ + virtual bool HasColorButtonControls() const { return false; } + + /** Does this item have Kismet controls? */ + virtual bool HasKismet() const { return false; } + + /** Is this the current item? */ + virtual bool IsCurrent() const { return false; } + + /** Can this ever become the current item? */ + virtual bool CanBeCurrent() const { return false; } + + /** Make this item the current item */ + virtual void MakeCurrent() {} + + /** Does the item have a valid package? */ + virtual bool HasValidPackage() const { return false; } + + /** Is the item dirty? */ + virtual bool IsDirty() const { return false; } + + /** Is the item loaded? */ + virtual bool IsLoaded() const { return true; } + + /** Is the item read-only? */ + virtual bool IsReadOnly() const { return false; } + + /** Gets the draw color for the item */ + virtual FLinearColor GetDrawColor() const { return FLinearColor::White; } + virtual void SetDrawColor(const FLinearColor& Color) {} + + virtual bool GetLevelSelectionFlag() const { return false; } + virtual bool IsLightingScenario() const { return false; } + virtual const FSlateBrush* GetHierarchyItemBrush() const { return nullptr; } + virtual float GetHierarchyItemBrushWidth() const { return 7.0f; } + + virtual void OnToggleVisibility() {} + virtual void OnToggleLightingScenario() {} + virtual void OnToggleLock() {} + virtual void OnSave() {} + virtual void OnOpenKismet() {} + + /** Returns true if this item can have its parent changed */ + virtual bool CanChangeParents() const = 0; + + /** Generates a context menu option for this item if and only if it's the only item selected in the hierarchy */ + virtual void GenerateContextMenu(FMenuBuilder& MenuBuilder, const SWorldHierarchyImpl& Hierarchy) {} + + /** Sets the item's visible status */ + virtual void SetVisible(bool bVisible) = 0; + + /** Sets the item's locked status */ + virtual void SetLocked(bool bLocked) = 0; + }; + + /** Utility function to get the parent path for a specific path */ + FORCEINLINE FName GetParentPath(const FName& InPath) + { + return FName(*FPaths::GetPath(InPath.ToString())); + } + +} // namespace WorldHierarchy \ No newline at end of file diff --git a/Engine/Source/Editor/WorldBrowser/WorldBrowser.Build.cs b/Engine/Source/Editor/WorldBrowser/WorldBrowser.Build.cs index 486e7c537dc7..a01e00f98f03 100644 --- a/Engine/Source/Editor/WorldBrowser/WorldBrowser.Build.cs +++ b/Engine/Source/Editor/WorldBrowser/WorldBrowser.Build.cs @@ -6,10 +6,12 @@ public class WorldBrowser : ModuleRules { public WorldBrowser(ReadOnlyTargetRules Target) : base(Target) { + PublicIncludePaths.Add("Editor/WorldBrowser/Public"); + PrivateIncludePaths.Add("Editor/WorldBrowser/Private"); // For PCH includes (because they don't work with relative paths, yet) PrivateIncludePathModuleNames.AddRange( - new string[] { + new string[] { "AssetRegistry", "AssetTools", "ContentBrowser", @@ -42,10 +44,12 @@ public class WorldBrowser : ModuleRules "SourceControlWindows", "RawMesh", "LandscapeEditor", + "FoliageEdit", "ImageWrapper", "Foliage", "MaterialUtilities", - "RHI" + "RHI", + "Json", } ); diff --git a/Engine/Source/Programs/AutomationTool/AllDesktop/AllDesktopPlatform.Automation.cs b/Engine/Source/Programs/AutomationTool/AllDesktop/AllDesktopPlatform.Automation.cs index afd42722756f..1b257e5c0304 100644 --- a/Engine/Source/Programs/AutomationTool/AllDesktop/AllDesktopPlatform.Automation.cs +++ b/Engine/Source/Programs/AutomationTool/AllDesktop/AllDesktopPlatform.Automation.cs @@ -114,11 +114,6 @@ public class AllDesktopPlatform : Platform return "AllDesktop"; } - public override bool DeployPakInternalLowerCaseFilenames() - { - return false; - } - public override bool DeployLowerCaseFilenames(bool bUFSFile) { return false; @@ -126,11 +121,6 @@ public class AllDesktopPlatform : Platform public override bool IsSupported { get { return true; } } - public override string Remap(string Dest) - { - return Dest; - } - public override PakType RequiresPak(ProjectParams Params) { return PakType.DontCare; diff --git a/Engine/Source/Programs/AutomationTool/Android/AndroidPlatform.Automation.cs b/Engine/Source/Programs/AutomationTool/Android/AndroidPlatform.Automation.cs index c1c430f86e85..ffcf5fa9ca63 100644 --- a/Engine/Source/Programs/AutomationTool/Android/AndroidPlatform.Automation.cs +++ b/Engine/Source/Programs/AutomationTool/Android/AndroidPlatform.Automation.cs @@ -203,7 +203,7 @@ public class AndroidPlatform : Platform // Create main OBB with entire contents of staging dir. This // includes any PAK files, movie files, etc. - string LocalObbName = SC.StageDirectory.TrimEnd(new char[] {'/', '\\'})+".obb"; + string LocalObbName = SC.StageDirectory.FullName+".obb"; // Always delete the target OBB file if it exists if (File.Exists(LocalObbName)) @@ -806,7 +806,7 @@ public class AndroidPlatform : Platform string SanitizedDeviceName = DeviceName.Replace(":", "_"); // Try retrieving the UFS files manifest files from the device - string UFSManifestFileName = CombinePaths(SC.StageDirectory, SC.UFSDeployedManifestFileName + "_" + SanitizedDeviceName); + string UFSManifestFileName = CombinePaths(SC.StageDirectory.FullName, SC.UFSDeployedManifestFileName + "_" + SanitizedDeviceName); IProcessResult UFSResult = RunAdbCommand(Params, DeviceName, " pull " + RemoteDir + "/" + SC.UFSDeployedManifestFileName + " \"" + UFSManifestFileName + "\"", null, ERunOptions.AppMustExist); if (!(UFSResult.Output.Contains("bytes") || UFSResult.Output.Contains("[100%]"))) { @@ -814,7 +814,7 @@ public class AndroidPlatform : Platform } // Try retrieving the non UFS files manifest files from the device - string NonUFSManifestFileName = CombinePaths(SC.StageDirectory, SC.NonUFSDeployedManifestFileName + "_" + SanitizedDeviceName); + string NonUFSManifestFileName = CombinePaths(SC.StageDirectory.FullName, SC.NonUFSDeployedManifestFileName + "_" + SanitizedDeviceName); IProcessResult NonUFSResult = RunAdbCommand(Params, DeviceName, " pull " + RemoteDir + "/" + SC.NonUFSDeployedManifestFileName + " \"" + NonUFSManifestFileName + "\"", null, ERunOptions.AppMustExist); if (!(NonUFSResult.Output.Contains("bytes") || NonUFSResult.Output.Contains("[100%]"))) { @@ -843,7 +843,9 @@ public class AndroidPlatform : Platform public override void Deploy(ProjectParams Params, DeploymentContext SC) { - foreach (var DeviceName in Params.DeviceNames) + var AppArchitectures = AndroidExports.CreateToolChain(Params.RawProjectPath).GetAllArchitectures(); + + foreach (var DeviceName in Params.DeviceNames) { string DeviceArchitecture = GetBestDeviceArchitecture(Params, DeviceName); string GPUArchitecture = GetBestGPUArchitecture(Params, DeviceName); @@ -856,9 +858,7 @@ public class AndroidPlatform : Platform { string CookFlavor = SC.FinalCookPlatform.IndexOf("_") > 0 ? SC.FinalCookPlatform.Substring(SC.FinalCookPlatform.IndexOf("_")) : ""; string SOName = GetSONameWithoutArchitecture(Params, SC.StageExecutables[0]); - List Architectures = new List(); - Architectures.Add(DeviceArchitecture); - Deploy.SetAndroidPluginData(Architectures, CollectPluginDataPaths(SC)); + Deploy.SetAndroidPluginData(AppArchitectures, CollectPluginDataPaths(SC)); Deploy.PrepForUATPackageOrDeploy(Params.RawProjectPath, Params.ShortProjectName, SC.ProjectRoot, SOName, SC.LocalRoot + "/Engine", Params.Distribution, CookFlavor, true); } @@ -951,7 +951,7 @@ public class AndroidPlatform : Platform // update the ue4commandline.txt // update and deploy ue4commandline.txt // always delete the existing commandline text file, so it doesn't reuse an old one - string IntermediateCmdLineFile = CombinePaths(SC.StageDirectory, "UE4CommandLine.txt"); + FileReference IntermediateCmdLineFile = FileReference.Combine(SC.StageDirectory, "UE4CommandLine.txt"); Project.WriteStageCommandline(IntermediateCmdLineFile, Params, SC); // copy files to device if we were staging @@ -965,7 +965,7 @@ public class AndroidPlatform : Platform if (Params.IterativeDeploy) { // always send UE4CommandLine.txt (it was written above after delta checks applied) - EntriesToDeploy.Add(IntermediateCmdLineFile); + EntriesToDeploy.Add(IntermediateCmdLineFile.FullName); // Add non UFS files if any to deploy String NonUFSManifestPath = SC.GetNonUFSDeploymentDeltaPath(DeviceName); @@ -976,7 +976,7 @@ public class AndroidPlatform : Platform { if (!string.IsNullOrEmpty(Filename) && !string.IsNullOrWhiteSpace(Filename)) { - EntriesToDeploy.Add(CombinePaths(SC.StageDirectory, Filename.Trim())); + EntriesToDeploy.Add(CombinePaths(SC.StageDirectory.FullName, Filename.Trim())); } } } @@ -990,7 +990,7 @@ public class AndroidPlatform : Platform { if (!string.IsNullOrEmpty(Filename) && !string.IsNullOrWhiteSpace(Filename)) { - EntriesToDeploy.Add(CombinePaths(SC.StageDirectory, Filename.Trim())); + EntriesToDeploy.Add(CombinePaths(SC.StageDirectory.FullName, Filename.Trim())); } } } @@ -1003,7 +1003,7 @@ public class AndroidPlatform : Platform EntriesToDeploy.Clear(); EntriesToDeploy.TrimExcess(); - EntriesToDeploy.Add(SC.StageDirectory); + EntriesToDeploy.Add(SC.StageDirectory.FullName); } } else @@ -1012,7 +1012,7 @@ public class AndroidPlatform : Platform RunAdbCommand(Params, DeviceName, "shell rm -r " + RemoteDir); // Copy UFS files.. - string[] Files = Directory.GetFiles(SC.StageDirectory, "*", SearchOption.AllDirectories); + string[] Files = Directory.GetFiles(SC.StageDirectory.FullName, "*", SearchOption.AllDirectories); System.Array.Sort(Files); // Find all the files we exclude from copying. And include @@ -1041,9 +1041,9 @@ public class AndroidPlatform : Platform IndividualCopyDirectories.Add(FileDirectory); } } - if (!IndividualCopyDirectories.Contains(SC.StageDirectory)) + if (!IndividualCopyDirectories.Contains(SC.StageDirectory.FullName)) { - IndividualCopyDirectories.Add(SC.StageDirectory); + IndividualCopyDirectories.Add(SC.StageDirectory.FullName); } } } @@ -1073,7 +1073,7 @@ public class AndroidPlatform : Platform if (EntriesToDeploy.Count == 0) { - EntriesToDeploy.Add(SC.StageDirectory); + EntriesToDeploy.Add(SC.StageDirectory.FullName); } } @@ -1085,7 +1085,7 @@ public class AndroidPlatform : Platform foreach (string Entry in EntriesToDeploy) { string FinalRemoteDir = RemoteDir; - string RemotePath = Entry.Replace(SC.StageDirectory, FinalRemoteDir).Replace("\\", "/"); + string RemotePath = Entry.Replace(SC.StageDirectory.FullName, FinalRemoteDir).Replace("\\", "/"); string Commandline = string.Format("{0} \"{1}\" \"{2}\"", BaseCommandline, Entry, RemotePath); // We run deploy commands in parallel to maximize the connection // throughput. @@ -1118,7 +1118,7 @@ public class AndroidPlatform : Platform else if (SC.Archive) { // deploy the obb if there is one - string ObbPath = Path.Combine(SC.StageDirectory, GetFinalObbName(ApkName)); + string ObbPath = Path.Combine(SC.StageDirectory.FullName, GetFinalObbName(ApkName)); if (File.Exists(ObbPath)) { // cache some strings @@ -1142,7 +1142,7 @@ public class AndroidPlatform : Platform } */ - string RemoteFilename = IntermediateCmdLineFile.Replace(SC.StageDirectory, FinalRemoteDir).Replace("\\", "/"); + string RemoteFilename = IntermediateCmdLineFile.FullName.Replace(SC.StageDirectory.FullName, FinalRemoteDir).Replace("\\", "/"); string Commandline = string.Format("{0} \"{1}\" \"{2}\"", BaseCommandline, IntermediateCmdLineFile, RemoteFilename); RunAdbCommand(Params, DeviceName, Commandline); } @@ -1423,6 +1423,18 @@ public class AndroidPlatform : Platform //same with the package names List PackageNames = new List(); + //strip off the device, GPU architecture and extension (.so) + int DashIndex = ClientApp.LastIndexOf("-"); + if (DashIndex >= 0) + { + ClientApp = ClientApp.Substring(0, DashIndex); + DashIndex = ClientApp.LastIndexOf("-"); + if (DashIndex >= 0) + { + ClientApp = ClientApp.Substring(0, DashIndex); + } + } + foreach (string DeviceName in Params.DeviceNames) { //save the device name @@ -1431,10 +1443,10 @@ public class AndroidPlatform : Platform //get the package name and save that string DeviceArchitecture = GetBestDeviceArchitecture(Params, DeviceName); string GPUArchitecture = GetBestGPUArchitecture(Params, DeviceName); - string ApkName = ClientApp + DeviceArchitecture + ".apk"; + string ApkName = GetFinalApkName(Params, Path.GetFileNameWithoutExtension(ClientApp), true, DeviceArchitecture, GPUArchitecture); if (!File.Exists(ApkName)) { - ApkName = GetFinalApkName(Params, Path.GetFileNameWithoutExtension(ClientApp), true, DeviceArchitecture, GPUArchitecture); + throw new AutomationException(ExitCode.Error_AppNotFound, "Failed to find application " + ApkName); } Console.WriteLine("Apk='{0}', ClientApp='{1}', ExeName='{2}'", ApkName, ClientApp, Params.ProjectGameExeFilename); @@ -1523,7 +1535,7 @@ public class AndroidPlatform : Platform public override void GetFilesToDeployOrStage(ProjectParams Params, DeploymentContext SC) { // Add any Android shader cache files - string ProjectShaderDir = Path.Combine(Path.GetDirectoryName(Path.GetFullPath(Params.RawProjectPath.ToString())), "Build/ShaderCaches/Android"); + DirectoryReference ProjectShaderDir = DirectoryReference.Combine(Params.RawProjectPath.Directory, "Build/ShaderCaches/Android"); SC.StageFiles(StagedFileType.UFS, ProjectShaderDir, "*.*", true, null, null, true); } @@ -1536,11 +1548,6 @@ public class AndroidPlatform : Platform return "Android"; } - public override bool DeployPakInternalLowerCaseFilenames() - { - return false; - } - public override bool DeployLowerCaseFilenames(bool bUFSFile) { return false; @@ -1553,11 +1560,6 @@ public class AndroidPlatform : Platform public override bool IsSupported { get { return true; } } - public override string Remap(string Dest) - { - return Dest; - } - public override PakType RequiresPak(ProjectParams Params) { // if packaging is enabled, always create a pak, otherwise use the Params.Pak value diff --git a/Engine/Source/Programs/AutomationTool/AutomationUtils/Automation.cs b/Engine/Source/Programs/AutomationTool/AutomationUtils/Automation.cs index a9364ba8ce27..39aacfca2354 100644 --- a/Engine/Source/Programs/AutomationTool/AutomationUtils/Automation.cs +++ b/Engine/Source/Programs/AutomationTool/AutomationUtils/Automation.cs @@ -7,7 +7,6 @@ using System.IO; using System.Reflection; using System.Diagnostics; using UnrealBuildTool; -using Tools.DotNETCommon.CaselessDictionary; namespace AutomationTool { @@ -94,7 +93,7 @@ namespace AutomationTool /// /// List of all registered command line parameters (global, not command-specific) /// - public static CaselessDictionary RegisteredArgs = new CaselessDictionary(); + public static Dictionary RegisteredArgs = new Dictionary(StringComparer.InvariantCultureIgnoreCase); public static CommandLineArg CompileOnly = new CommandLineArg("-CompileOnly"); public static CommandLineArg Verbose = new CommandLineArg("-Verbose"); @@ -443,9 +442,7 @@ AutomationTool.exe [-verbose] [-compileonly] [-p4] Command0 [-Arg0 -Arg1 -Arg2 // Get the path to the telemetry file, if present string TelemetryFile = CommandUtils.ParseParamValue(Arguments, "-Telemetry"); - - // Check for build machine override (force local) - IsBuildMachine = GlobalCommandLine.ForceLocal ? false : IsBuildMachine; + Log.TraceVerbose("IsBuildMachine={0}", IsBuildMachine); Environment.SetEnvironmentVariable("IsBuildMachine", IsBuildMachine ? "1" : "0"); @@ -547,7 +544,7 @@ AutomationTool.exe [-verbose] [-compileonly] [-p4] Command0 [-Arg0 -Arg1 -Arg2 /// /// /// - private static ExitCode Execute(List CommandsToExecute, CaselessDictionary Commands) + private static ExitCode Execute(List CommandsToExecute, Dictionary Commands) { for (int CommandIndex = 0; CommandIndex < CommandsToExecute.Count; ++CommandIndex) { @@ -595,7 +592,7 @@ AutomationTool.exe [-verbose] [-compileonly] [-p4] Command0 [-Arg0 -Arg1 -Arg2 /// /// List of commands specified in the command line. /// All discovered command objects. - private static void DisplayHelp(List CommandsToExecute, CaselessDictionary Commands) + private static void DisplayHelp(List CommandsToExecute, Dictionary Commands) { for (int CommandIndex = 0; CommandIndex < CommandsToExecute.Count; ++CommandIndex) { @@ -624,7 +621,7 @@ AutomationTool.exe [-verbose] [-compileonly] [-p4] Command0 [-Arg0 -Arg1 -Arg2 /// List all available commands. /// /// All vailable commands. - private static void ListAvailableCommands(CaselessDictionary Commands) + private static void ListAvailableCommands(Dictionary Commands) { string Message = Environment.NewLine; Message += "Available commands:" + Environment.NewLine; diff --git a/Engine/Source/Programs/AutomationTool/AutomationUtils/AutomationUtils.Automation.csproj b/Engine/Source/Programs/AutomationTool/AutomationUtils/AutomationUtils.Automation.csproj index 86e475206229..c14216244c10 100644 --- a/Engine/Source/Programs/AutomationTool/AutomationUtils/AutomationUtils.Automation.csproj +++ b/Engine/Source/Programs/AutomationTool/AutomationUtils/AutomationUtils.Automation.csproj @@ -80,6 +80,10 @@ + + + + diff --git a/Engine/Source/Programs/AutomationTool/AutomationUtils/CommandUtils.cs b/Engine/Source/Programs/AutomationTool/AutomationUtils/CommandUtils.cs index 61dcf7569c47..db54a6710e6f 100644 --- a/Engine/Source/Programs/AutomationTool/AutomationUtils/CommandUtils.cs +++ b/Engine/Source/Programs/AutomationTool/AutomationUtils/CommandUtils.cs @@ -9,14 +9,14 @@ using System.Runtime.Serialization; using System.Runtime.Serialization.Json; using System.Text; using System.Threading; -using Tools.DotNETCommon.XmlHandler; using UnrealBuildTool; using System.Runtime.CompilerServices; using System.Linq; using System.Reflection; using System.Threading.Tasks; using Tools.DotNETCommon; -using Tools.DotNETCommon.CaselessDictionary; +using System.Xml; +using System.Xml.Serialization; namespace AutomationTool { @@ -101,7 +101,7 @@ namespace AutomationTool /// Initialized and ready to use BuildEnvironment static internal void InitCommandEnvironment() { - CmdEnvironment = Automation.IsBuildMachine ? new CommandEnvironment() : new LocalCommandEnvironment(); ; + CmdEnvironment = (Automation.IsBuildMachine && !GlobalCommandLine.ForceLocal) ? new CommandEnvironment() : new LocalCommandEnvironment(); } #endregion @@ -341,6 +341,18 @@ namespace AutomationTool return FoundFiles.ToArray(); } + /// + /// Finds files in specified paths. + /// + /// Pattern + /// Recursive search + /// Paths to search + /// An array of files found in the specified paths + public static FileReference[] FindFiles(string SearchPattern, bool Recursive, DirectoryReference PathToSearch) + { + return FindFiles(SearchPattern, Recursive, PathToSearch.FullName).Select(x => new FileReference(x)).ToArray(); + } + /// /// Finds files in specified paths. /// @@ -1309,46 +1321,44 @@ namespace AutomationTool /// The full path to the destination file /// If true, will always skip a file if the destination exists, even if timestamp differs; defaults to false /// True if the operation was successful, false otherwise. - public static void CopyFileIncremental(string Source, string Dest, bool bAllowDifferingTimestamps = false, bool bFilterSpecialLinesFromIniFiles = false) + public static void CopyFileIncremental(FileReference Source, FileReference Dest, bool bAllowDifferingTimestamps = false, bool bFilterSpecialLinesFromIniFiles = false) { - Source = ConvertSeparators(PathSeparator.Default, Source); - Dest = ConvertSeparators(PathSeparator.Default, Dest); - if (InternalUtils.SafeFileExists(Dest, true)) + if (InternalUtils.SafeFileExists(Dest.FullName, true)) { if (bAllowDifferingTimestamps == true) { LogVerbose("CopyFileIncremental Skipping {0}, already exists", Dest); return; } - TimeSpan Diff = File.GetLastWriteTimeUtc(Dest) - File.GetLastWriteTimeUtc(Source); + TimeSpan Diff = File.GetLastWriteTimeUtc(Dest.FullName) - File.GetLastWriteTimeUtc(Source.FullName); if (Diff.TotalSeconds > -1 && Diff.TotalSeconds < 1) { LogVerbose("CopyFileIncremental Skipping {0}, up to date.", Dest); return; } - InternalUtils.SafeDeleteFile(Dest); + InternalUtils.SafeDeleteFile(Dest.FullName); } - else if (!InternalUtils.SafeDirectoryExists(Path.GetDirectoryName(Dest), true)) + else if (!InternalUtils.SafeDirectoryExists(Path.GetDirectoryName(Dest.FullName), true)) { - if (!InternalUtils.SafeCreateDirectory(Path.GetDirectoryName(Dest))) + if (!InternalUtils.SafeCreateDirectory(Path.GetDirectoryName(Dest.FullName))) { - throw new AutomationException("Failed to create directory {0} for copy", Path.GetDirectoryName(Dest)); + throw new AutomationException("Failed to create directory {0} for copy", Path.GetDirectoryName(Dest.FullName)); } } - if (InternalUtils.SafeFileExists(Dest, true)) + if (InternalUtils.SafeFileExists(Dest.FullName, true)) { throw new AutomationException("Failed to delete {0} for copy", Dest); } - if (!InternalUtils.SafeCopyFile(Source, Dest, bFilterSpecialLinesFromIniFiles:bFilterSpecialLinesFromIniFiles)) + if (!InternalUtils.SafeCopyFile(Source.FullName, Dest.FullName, bFilterSpecialLinesFromIniFiles:bFilterSpecialLinesFromIniFiles)) { throw new AutomationException("Failed to copy {0} to {1}", Source, Dest); } - FileAttributes Attributes = File.GetAttributes(Dest); + FileAttributes Attributes = File.GetAttributes(Dest.FullName); if ((Attributes & FileAttributes.ReadOnly) != 0) { - File.SetAttributes(Dest, Attributes & ~FileAttributes.ReadOnly); + File.SetAttributes(Dest.FullName, Attributes & ~FileAttributes.ReadOnly); } - File.SetLastWriteTimeUtc(Dest, File.GetLastWriteTimeUtc(Source)); + File.SetLastWriteTimeUtc(Dest.FullName, File.GetLastWriteTimeUtc(Source.FullName)); } /// @@ -1460,7 +1470,39 @@ namespace AutomationTool /// public static UnrealBuildTool.BuildManifest ReadManifest(string ManifestName) { - return XmlHandler.ReadXml(ManifestName); + // Create a new default instance of the type + UnrealBuildTool.BuildManifest Instance = new UnrealBuildTool.BuildManifest(); + XmlReader XmlStream = null; + try + { + // Use the default reader settings if none are passed in + XmlReaderSettings ReaderSettings = new XmlReaderSettings(); + ReaderSettings.CloseInput = true; + ReaderSettings.IgnoreComments = true; + + // Get the xml data stream to read from + XmlStream = XmlReader.Create( ManifestName, ReaderSettings ); + + // Creates an instance of the XmlSerializer class so we can read the settings object + XmlSerializer ObjectReader = new XmlSerializer( typeof( UnrealBuildTool.BuildManifest ) ); + + // Create an object from the xml data + Instance = ( UnrealBuildTool.BuildManifest )ObjectReader.Deserialize( XmlStream ); + } + catch( Exception Ex ) + { + Debug.WriteLine( Ex.Message ); + } + finally + { + if( XmlStream != null ) + { + // Done with the file so close it + XmlStream.Close(); + } + } + + return Instance; } private static void CloneDirectoryRecursiveWorker(string SourcePathBase, string TargetPathBase, List ClonedFiles, bool bIncremental = false) @@ -2219,7 +2261,12 @@ namespace AutomationTool /// public enum TelemetryUnits { + Count, + Milliseconds, + Seconds, Minutes, + Bytes, + Megabytes, } /// @@ -2710,11 +2757,11 @@ namespace AutomationTool /// Will automatically skip signing if -NoSign is specified in the command line. /// /// List of files to sign - public static void SignMultipleIfEXEOrDLL(BuildCommand Command, List Files) + public static void SignMultipleIfEXEOrDLL(BuildCommand Command, IEnumerable Files) { if (!Command.ParseParam("NoSign")) { - CommandUtils.Log("Signing up to {0} files...", Files.Count); + CommandUtils.Log("Signing up to {0} files...", Files.Count()); UnrealBuildTool.UnrealTargetPlatform TargetPlatform = UnrealBuildTool.BuildHostPlatform.Current.Platform; if (TargetPlatform == UnrealBuildTool.UnrealTargetPlatform.Mac) { @@ -2725,12 +2772,12 @@ namespace AutomationTool } else { - List FilesToSign = new List(); + List FilesToSign = new List(); foreach (string File in Files) { if (!(Path.GetDirectoryName(File).Replace("\\", "/")).Contains("Binaries/XboxOne")) { - FilesToSign.Add(File); + FilesToSign.Add(new FileReference(File)); } } SignMultipleFilesIfEXEOrDLL(FilesToSign); @@ -2738,7 +2785,7 @@ namespace AutomationTool } else { - CommandUtils.LogLog("Skipping signing {0} files due to -nosign.", Files.Count); + CommandUtils.LogLog("Skipping signing {0} files due to -nosign.", Files.Count()); } } @@ -2795,7 +2842,7 @@ namespace AutomationTool } } - public static void SignMultipleFilesIfEXEOrDLL(List Files, bool bIgnoreExtension = false) + public static void SignMultipleFilesIfEXEOrDLL(List Files, bool bIgnoreExtension = false) { if (UnrealBuildTool.Utils.IsRunningOnMono) { @@ -2803,7 +2850,7 @@ namespace AutomationTool return; } List FinalFiles = new List(); - foreach (string Filename in Files) + foreach (string Filename in Files.Select(x => x.FullName)) { // Make sure the file isn't read-only FileInfo TargetFileInfo = new FileInfo(Filename); diff --git a/Engine/Source/Programs/AutomationTool/AutomationUtils/CommandletUtils.cs b/Engine/Source/Programs/AutomationTool/AutomationUtils/CommandletUtils.cs index 604869754aa8..a689a7fc808b 100644 --- a/Engine/Source/Programs/AutomationTool/AutomationUtils/CommandletUtils.cs +++ b/Engine/Source/Programs/AutomationTool/AutomationUtils/CommandletUtils.cs @@ -146,7 +146,7 @@ namespace AutomationTool MapsToRebuildLighting = "-Map=" + CombineCommandletParams(Maps).Trim(); } - RunCommandlet(ProjectName, UE4Exe, "ResavePackages", String.Format("-buildlighting -MapsOnly -ProjectOnly -AllowCommandletRendering -SkipSkinVerify {0} {1}", MapsToRebuildLighting, Parameters)); + RunCommandlet(ProjectName, UE4Exe, "ResavePackages", String.Format("-buildtexturestreaming -buildlighting -MapsOnly -ProjectOnly -AllowCommandletRendering -SkipSkinVerify {0} {1}", MapsToRebuildLighting, Parameters)); } /// @@ -451,6 +451,44 @@ namespace AutomationTool } } + /// + /// Converts project name to FileReference used by other commandlet functions + /// + /// Project name. + /// FileReference to project location + public static FileReference GetCommandletProjectFile(string ProjectName) + { + FileReference ProjectFullPath = null; + var OriginalProjectName = ProjectName; + ProjectName = ProjectName.Trim(new char[] { '\"' }); + if (ProjectName.IndexOfAny(new char[] { '\\', '/' }) < 0) + { + ProjectName = CombinePaths(CmdEnv.LocalRoot, ProjectName, ProjectName + ".uproject"); + } + else if (!FileExists_NoExceptions(ProjectName)) + { + ProjectName = CombinePaths(CmdEnv.LocalRoot, ProjectName); + } + if (FileExists_NoExceptions(ProjectName)) + { + ProjectFullPath = new FileReference(ProjectName); + } + else + { + var Branch = new BranchInfo(new List { UnrealBuildTool.BuildHostPlatform.Current.Platform }); + var GameProj = Branch.FindGame(OriginalProjectName); + if (GameProj != null) + { + ProjectFullPath = GameProj.FilePath; + } + if (!FileExists_NoExceptions(ProjectFullPath.FullName)) + { + throw new AutomationException("Could not find a project file {0}.", ProjectName); + } + } + return ProjectFullPath; + } + #endregion } } diff --git a/Engine/Source/Programs/AutomationTool/AutomationUtils/DeploymentContext.cs b/Engine/Source/Programs/AutomationTool/AutomationUtils/DeploymentContext.cs index 31c34a9099b0..2efd3f2b0495 100644 --- a/Engine/Source/Programs/AutomationTool/AutomationUtils/DeploymentContext.cs +++ b/Engine/Source/Programs/AutomationTool/AutomationUtils/DeploymentContext.cs @@ -13,6 +13,57 @@ public struct StageTarget public bool RequireFilesExist; } +public class FilesToStage +{ + /// + /// After staging, this is a map from staged file to source file. These file are binaries, etc and can't go into a pak file. + /// + public Dictionary NonUFSStagingFiles = new Dictionary(); + + /// + /// After staging, this is a map from staged file to source file. These file are for debugging, and should not go into a pak file. + /// + public Dictionary NonUFSStagingFilesDebug = new Dictionary(); + + /// + /// After staging, this is a map from staged file to source file. These file are content, and can go into a pak file. + /// + public Dictionary UFSStagingFiles = new Dictionary(); + + /// + /// Adds a file to be staged as the given type + /// + /// The type of file to be staged + /// The staged file location + /// The input file + public void Add(StagedFileType FileType, StagedFileReference StagedFile, FileReference InputFile) + { + if (FileType == StagedFileType.UFS) + { + AddToDictionary(UFSStagingFiles, StagedFile, InputFile); + } + else if (FileType == StagedFileType.NonUFS) + { + AddToDictionary(NonUFSStagingFiles, StagedFile, InputFile); + } + else if (FileType == StagedFileType.DebugNonUFS) + { + AddToDictionary(NonUFSStagingFilesDebug, StagedFile, InputFile); + } + } + + /// + /// Adds a file to be staged to the given dictionary + /// + /// Dictionary of files to be staged + /// The staged file location + /// The input file + private void AddToDictionary(Dictionary FilesToStage, StagedFileReference StagedFile, FileReference InputFile) + { + FilesToStage[StagedFile] = InputFile; + } +} + public class DeploymentContext //: ProjectParams { /// @@ -56,14 +107,19 @@ public class DeploymentContext //: ProjectParams public List StageTargets; /// - /// this is the root directory that contains the engine: d:\a\UE4\ + /// This is the root directory that contains the engine: d:\a\UE4\ /// - public string LocalRoot; + public DirectoryReference LocalRoot; /// - /// this is the directory that contains the "game": d:\a\UE4\ShooterGame + /// This is the directory that contains the engine. /// - public string ProjectRoot; + public DirectoryReference EngineRoot; + + /// + /// The directory that contains the project: d:\a\UE4\ShooterGame + /// + public DirectoryReference ProjectRoot; /// /// raw name used for platform subdirectories Win32 @@ -71,125 +127,87 @@ public class DeploymentContext //: ProjectParams public string PlatformDir; /// - /// this is the directory that contains the "game", staged: d:\stagedir\WindowsNoEditor\ShooterGame + /// Directory to put all of the files in: d:\stagedir\WindowsNoEditor /// - public string StageProjectRoot; + public DirectoryReference StageDirectory; /// - /// Directory to put all of the files in: d:\stagedir\WindowsNoEditor + /// Directory name for staged projects /// - public string StageDirectory; + public StagedDirectoryReference RelativeProjectRootForStage; /// - /// The relative staged project root, what would be tacked on to StageDirectory - /// - public string RelativeProjectRootForStage; - - /// - /// The relative source project root, this will be the short project name for foreign projects, otherwise it is ProjectRoot minus the LocalRoot prefix - /// - public string SourceRelativeProjectRoot; - - /// - /// The relative staged project root, used inside the pak file list (different slash convention than above) - /// - public string RelativeProjectRootForUnrealPak; - - /// - /// This is what you use to test the engine which uproject you want. Many cases. + /// This is what you use to test the engine which uproject you want. Many cases. /// public string ProjectArgForCommandLines; - /// - /// This is the root that the cook source platform would run from - /// - public string CookSourceRuntimeRootDir; - /// - /// This is the root that we are going to run from. Many cases. + /// The directory containing the cooked data to be staged. This may be different to the target platform, eg. when creating cooked data for dedicated servers. /// - public string RuntimeRootDir; + public DirectoryReference CookSourceRuntimeRootDir; /// - /// This is the project root that we are going to run from. Many cases. + /// This is the root that we are going to run from. This will be the stage directory if we're staging, or the input directory if not. /// - public string RuntimeProjectRootDir; + public DirectoryReference RuntimeRootDir; /// - /// This is the executable we are going to run and stage. Filled in by the platform abstraction. + /// This is the project root that we are going to run from. Many cases. /// - public string RuntimeExecutable = ""; + public DirectoryReference RuntimeProjectRootDir; /// - /// List of executables we are going to stage + /// List of executables we are going to stage /// public List StageExecutables; /// - /// Probably going away, used to construct ProjectArgForCommandLines in the case that we are running staged + /// Probably going away, used to construct ProjectArgForCommandLines in the case that we are running staged /// - public string UProjectCommandLineArgInternalRoot = "../../../"; + public const string UProjectCommandLineArgInternalRoot = "../../../"; /// - /// Probably going away, used to construct the pak file list + /// Probably going away, used to construct the pak file list /// public string PakFileInternalRoot = "../../../"; /// - /// Probably going away, and currently unused, this would be used to build the list of files for the UFS server + /// List of files to be staged /// - public string UnrealFileServerInternalRoot = "../../../"; + public FilesToStage FilesToStage = new FilesToStage(); /// - /// After staging, this is a map from source file to relative file in the stage - /// These file are binaries, etc and can't go into a pak file - /// - public Dictionary> NonUFSStagingFiles = new Dictionary>(); - /// - /// After staging, this is a map from source file to relative file in the stage - /// These file are debug, and can't go into a pak file - /// - public Dictionary> NonUFSStagingFilesDebug = new Dictionary>(); - /// - /// After staging, this is a map from source file to relative file in the stage - /// These file are content, and can go into a pak file - /// - public Dictionary UFSStagingFiles = new Dictionary(); - /// - /// List of files to be archived + /// List of files to be archived /// public Dictionary ArchivedFiles = new Dictionary(); + /// /// Directory to archive all of the files in: d:\archivedir\WindowsNoEditor /// - public string ArchiveDirectory; + public DirectoryReference ArchiveDirectory; + /// /// Directory to project binaries /// - public string ProjectBinariesFolder; + public DirectoryReference ProjectBinariesFolder; /// /// Filename for the manifest of file changes for iterative deployment. /// - static public readonly string UFSDeployDeltaFileName = "Manifest_DeltaUFSFiles.txt"; - static public readonly string NonUFSDeployDeltaFileName = "Manifest_DeltaNonUFSFiles.txt"; + public const string UFSDeployDeltaFileName = "Manifest_DeltaUFSFiles.txt"; + public const string NonUFSDeployDeltaFileName = "Manifest_DeltaNonUFSFiles.txt"; /// /// Filename for the manifest of files to delete during deployment. /// - static public readonly string UFSDeployObsoleteFileName = "Manifest_ObsoleteUFSFiles.txt"; - static public readonly string NonUFSDeployObsoleteFileName = "Manifest_ObsoleteNonUFSFiles.txt"; + public const string UFSDeployObsoleteFileName = "Manifest_ObsoleteUFSFiles.txt"; + public const string NonUFSDeployObsoleteFileName = "Manifest_ObsoleteNonUFSFiles.txt"; /// /// The client connects to dedicated server to get data /// public bool DedicatedServer; - /// - /// The dedicated server and client use - /// - public bool bUseWebsocketNetDriver; - /// /// True if this build is staged /// @@ -222,9 +240,9 @@ public class DeploymentContext //: ProjectParams public DeploymentContext( FileReference RawProjectPathOrName, - string InLocalRoot, - string BaseStageDirectory, - string BaseArchiveDirectory, + DirectoryReference InLocalRoot, + DirectoryReference BaseStageDirectory, + DirectoryReference BaseArchiveDirectory, Platform InSourcePlatform, Platform InTargetPlatform, List InTargetConfigurations, @@ -238,14 +256,13 @@ public class DeploymentContext //: ProjectParams bool InArchive, bool InProgram, bool IsClientInsteadOfNoEditor, - bool InForceChunkManifests, - bool bInUseWebsocketNetDriver = false + bool InForceChunkManifests ) { bStageCrashReporter = InStageCrashReporter; RawProjectPath = RawProjectPathOrName; DedicatedServer = InServer; - LocalRoot = CommandUtils.CombinePaths(InLocalRoot); + LocalRoot = InLocalRoot; CookSourcePlatform = InSourcePlatform; StageTargetPlatform = InTargetPlatform; StageTargetConfigurations = new List(InTargetConfigurations); @@ -255,7 +272,6 @@ public class DeploymentContext //: ProjectParams ShortProjectName = ProjectUtils.GetShortProjectName(RawProjectPath); Stage = InStage; Archive = InArchive; - bUseWebsocketNetDriver = bInUseWebsocketNetDriver; if (CookSourcePlatform != null && InCooked) { @@ -285,60 +301,45 @@ public class DeploymentContext //: ProjectParams PlatformDir = StageTargetPlatform.PlatformType.ToString(); - StageDirectory = CommandUtils.CombinePaths(BaseStageDirectory, FinalCookPlatform); - ArchiveDirectory = CommandUtils.CombinePaths(BaseArchiveDirectory, FinalCookPlatform); + if (BaseStageDirectory != null) + { + StageDirectory = DirectoryReference.Combine(BaseStageDirectory, FinalCookPlatform); + } - if (!CommandUtils.FileExists(RawProjectPath.FullName)) + if(BaseArchiveDirectory != null) + { + ArchiveDirectory = DirectoryReference.Combine(BaseArchiveDirectory, FinalCookPlatform); + } + + if (!FileReference.Exists(RawProjectPath)) { throw new AutomationException("Can't find uproject file {0}.", RawProjectPathOrName); } - ProjectRoot = CommandUtils.CombinePaths(CommandUtils.GetDirectoryName(RawProjectPath.FullName)); + EngineRoot = DirectoryReference.Combine(LocalRoot, "Engine"); + ProjectRoot = RawProjectPath.Directory; - if (!CommandUtils.DirectoryExists(ProjectRoot)) - { - throw new AutomationException("Project Directory {0} doesn't exist.", ProjectRoot); - } - - RelativeProjectRootForStage = ShortProjectName; + RelativeProjectRootForStage = new StagedDirectoryReference(ShortProjectName); ProjectArgForCommandLines = CommandUtils.MakePathSafeToUseWithCommandLine(RawProjectPath.FullName); CookSourceRuntimeRootDir = RuntimeRootDir = LocalRoot; RuntimeProjectRootDir = ProjectRoot; - - RelativeProjectRootForUnrealPak = CommandUtils.CombinePaths(RelativeProjectRootForStage).Replace("\\", "/"); - if (RelativeProjectRootForUnrealPak.StartsWith("/")) - { - RelativeProjectRootForUnrealPak = RelativeProjectRootForUnrealPak.Substring(1); - RelativeProjectRootForStage = RelativeProjectRootForStage.Substring(1); - } - - SourceRelativeProjectRoot = RelativeProjectRootForStage; // for foreign projects this doesn't make much sense, but it turns into a noop on staging files - if (ProjectRoot.StartsWith(LocalRoot, StringComparison.InvariantCultureIgnoreCase)) - { - SourceRelativeProjectRoot = ProjectRoot.Substring(LocalRoot.Length); - } - if (SourceRelativeProjectRoot.StartsWith("/") || SourceRelativeProjectRoot.StartsWith("\\")) - { - SourceRelativeProjectRoot = SourceRelativeProjectRoot.Substring(1); - } - + if (Stage) { - CommandUtils.CreateDirectory(StageDirectory); - StageProjectRoot = CommandUtils.CombinePaths(StageDirectory, RelativeProjectRootForStage); + CommandUtils.CreateDirectory(StageDirectory.FullName); RuntimeRootDir = StageDirectory; - CookSourceRuntimeRootDir = CommandUtils.CombinePaths(BaseStageDirectory, CookPlatform); - RuntimeProjectRootDir = StageProjectRoot; - ProjectArgForCommandLines = CommandUtils.MakePathSafeToUseWithCommandLine(UProjectCommandLineArgInternalRoot + RelativeProjectRootForStage + "/" + ShortProjectName + ".uproject"); + CookSourceRuntimeRootDir = DirectoryReference.Combine(BaseStageDirectory, CookPlatform); + RuntimeProjectRootDir = DirectoryReference.Combine(StageDirectory, RelativeProjectRootForStage.Name); + ProjectArgForCommandLines = CommandUtils.MakePathSafeToUseWithCommandLine(UProjectCommandLineArgInternalRoot + RelativeProjectRootForStage.Name + "/" + ShortProjectName + ".uproject"); } if (Archive) { - CommandUtils.CreateDirectory(ArchiveDirectory); + CommandUtils.CreateDirectory(ArchiveDirectory.FullName); } ProjectArgForCommandLines = ProjectArgForCommandLines.Replace("\\", "/"); - ProjectBinariesFolder = CommandUtils.CombinePaths(ProjectUtils.GetClientProjectBinariesRootPath(RawProjectPath, TargetType.Game, IsCodeBasedProject), PlatformDir); + ProjectBinariesFolder = DirectoryReference.Combine(ProjectUtils.GetClientProjectBinariesRootPath(RawProjectPath, TargetType.Game, IsCodeBasedProject), PlatformDir); // If we were configured to use manifests across the whole project, then this platform should use manifests. // Otherwise, read whether we are generating chunks from the ProjectPackagingSettings ini. @@ -348,7 +349,7 @@ public class DeploymentContext //: ProjectParams } else { - ConfigHierarchy GameIni = ConfigCache.ReadHierarchy(ConfigHierarchyType.Game, RawProjectPath.Directory, InTargetPlatform.PlatformType); + ConfigHierarchy GameIni = ConfigCache.ReadHierarchy(ConfigHierarchyType.Game, ProjectRoot, InTargetPlatform.PlatformType); String IniPath = "/Script/UnrealEd.ProjectPackagingSettings"; bool bSetting = false; if (GameIni.GetBool(IniPath, "bGenerateChunks", out bSetting)) @@ -358,68 +359,43 @@ public class DeploymentContext //: ProjectParams } } - public void StageFile(StagedFileType FileType, string InputPath, string OutputPath = null, bool bRemap = true) + public void StageFile(StagedFileType FileType, FileReference InputFile, StagedFileReference OutputFile = null, bool bRemap = true) { - InputPath = InputPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); - - if(OutputPath == null) + if(OutputFile == null) { - if(InputPath.StartsWith(ProjectRoot, StringComparison.InvariantCultureIgnoreCase)) + if(InputFile.IsUnderDirectory(ProjectRoot)) { - OutputPath = CommandUtils.CombinePaths(RelativeProjectRootForStage, InputPath.Substring(ProjectRoot.Length).TrimStart('/', '\\')); + OutputFile = StagedFileReference.Combine(RelativeProjectRootForStage, InputFile.MakeRelativeTo(ProjectRoot)); } - else if (InputPath.EndsWith(".uplugin", StringComparison.InvariantCultureIgnoreCase)) + else if (InputFile.HasExtension(".uplugin")) { - if (InputPath.StartsWith(CommandUtils.CombinePaths(LocalRoot + "/Engine"), StringComparison.InvariantCultureIgnoreCase)) + if (InputFile.IsUnderDirectory(EngineRoot)) { - OutputPath = CommandUtils.CombinePaths(InputPath.Substring(LocalRoot.Length).TrimStart('/', '\\')); + OutputFile = new StagedFileReference(InputFile.MakeRelativeTo(LocalRoot)); } else { // This is a plugin that lives outside of the Engine/Plugins or Game/Plugins directory so needs to be remapped for staging/packaging // We need to remap C:\SomePath\PluginName\PluginName.uplugin to RemappedPlugins\PluginName\PluginName.uplugin - int Index = InputPath.LastIndexOf(Path.DirectorySeparatorChar); - if (Index != -1) - { - int PluginDirIndex = InputPath.LastIndexOf(Path.DirectorySeparatorChar, Index - 1); - if (PluginDirIndex != -1) - { - OutputPath = CommandUtils.CombinePaths("RemappedPlugins", InputPath.Substring(PluginDirIndex)); - } - } - if (OutputPath == null) - { - throw new AutomationException("Can't deploy {0} because the plugin path is non-standard, so could not be remapped", InputPath); - } + OutputFile = new StagedFileReference(String.Format("RemappedPlugins/{0}/{1}", InputFile.GetFileNameWithoutExtension(), InputFile.GetFileName())); } } - else if (InputPath.StartsWith(LocalRoot, StringComparison.InvariantCultureIgnoreCase)) + else if (InputFile.IsUnderDirectory(LocalRoot)) { - OutputPath = CommandUtils.CombinePaths(InputPath.Substring(LocalRoot.Length).TrimStart('/', '\\')); + OutputFile = new StagedFileReference(InputFile.MakeRelativeTo(LocalRoot)); } else { - throw new AutomationException("Can't deploy {0} because it doesn't start with {1} or {2}", InputPath, ProjectRoot, LocalRoot); + throw new AutomationException("Can't deploy {0} because it doesn't start with {1} or {2}", InputFile, ProjectRoot, LocalRoot); } } if(bRemap) { - OutputPath = StageTargetPlatform.Remap(OutputPath); + OutputFile = StageTargetPlatform.Remap(OutputFile); } - if (FileType == StagedFileType.UFS) - { - AddUniqueStagingFile(UFSStagingFiles, InputPath, OutputPath); - } - else if (FileType == StagedFileType.NonUFS) - { - AddStagingFile(NonUFSStagingFiles, InputPath, OutputPath); - } - else if (FileType == StagedFileType.DebugNonUFS) - { - AddStagingFile(NonUFSStagingFilesDebug, InputPath, OutputPath); - } + FilesToStage.Add(FileType, OutputFile, InputFile); } public void StageBuildProductsFromReceipt(TargetReceipt Receipt, bool RequireDependenciesToExist, bool TreatNonShippingBinariesAsDebugFiles) @@ -428,7 +404,7 @@ public class DeploymentContext //: ProjectParams foreach(BuildProduct BuildProduct in Receipt.BuildProducts) { // allow missing files if needed - if (RequireDependenciesToExist == false && File.Exists(BuildProduct.Path) == false) + if (RequireDependenciesToExist == false && FileReference.Exists(BuildProduct.Path) == false) { continue; } @@ -446,7 +422,7 @@ public class DeploymentContext //: ProjectParams else if(BuildProduct.Type == BuildProductType.SymbolFile || BuildProduct.Type == BuildProductType.MapFile) { // Symbol files aren't true dependencies so we can skip if they don't exist - if (File.Exists(BuildProduct.Path)) + if (FileReference.Exists(BuildProduct.Path)) { StageFile(StagedFileType.DebugNonUFS, BuildProduct.Path); } @@ -464,14 +440,11 @@ public class DeploymentContext //: ProjectParams // Also stage any additional runtime dependencies, like ThirdParty DLLs foreach(RuntimeDependency RuntimeDependency in Receipt.RuntimeDependencies) { - foreach(FileReference MatchingFile in CommandUtils.ResolveFilespec(CommandUtils.RootDirectory, RuntimeDependency.Path, ExcludePatterns)) + // allow missing files if needed + if ((RequireDependenciesToExist && RuntimeDependency.Type != StagedFileType.DebugNonUFS) || FileReference.Exists(RuntimeDependency.Path)) { - // allow missing files if needed - if ((RequireDependenciesToExist && RuntimeDependency.Type != StagedFileType.DebugNonUFS) || FileReference.Exists(MatchingFile)) - { - bool bRemap = RuntimeDependency.Type != StagedFileType.UFS || !bUsingPakFile; - StageFile(RuntimeDependency.Type, MatchingFile.FullName, bRemap: bRemap); - } + bool bRemap = RuntimeDependency.Type != StagedFileType.UFS || !bUsingPakFile; + StageFile(RuntimeDependency.Type, RuntimeDependency.Path, bRemap: bRemap); } } } @@ -546,149 +519,93 @@ public class DeploymentContext //: ProjectParams return true; } - public void StageFiles(StagedFileType FileType, string InPath, string Wildcard = "*", bool bRecursive = true, string[] ExcludeWildcard = null, string NewPath = null, bool bAllowNone = false, bool bRemap = true, string NewName = null, bool bAllowNotForLicenseesFiles = true, bool bStripFilesForOtherPlatforms = true, bool bConvertToLower = false) + bool IsFileForOtherPlatform(FileReference InputFile) { - int FilesAdded = 0; - // make sure any ..'s are removed - CollapseRelativeDirectories(ref InPath); - - if (CommandUtils.DirectoryExists(InPath)) - { - var All = CommandUtils.FindFiles(Wildcard, bRecursive, InPath); - - var Exclude = new HashSet(); - if (ExcludeWildcard != null) + foreach (UnrealTargetPlatform Plat in Enum.GetValues(typeof(UnrealTargetPlatform))) + { + bool bMatchesIniPlatform = (InputFile.HasExtension(".ini") && Plat == StageTargetPlatform.IniPlatformType); // filter ini files for the ini file platform + bool bMatchesTargetPlatform = (Plat == StageTargetPlatform.PlatformType || Plat == UnrealTargetPlatform.Unknown); // filter platform files for the target platform + if (!bMatchesIniPlatform && !bMatchesTargetPlatform) { - foreach (var Excl in ExcludeWildcard) + FileSystemName PlatformName = new FileSystemName(Plat.ToString()); + if (InputFile.IsUnderDirectory(ProjectRoot)) { - var Remove = CommandUtils.FindFiles(Excl, bRecursive, InPath); - foreach (var File in Remove) + if (InputFile.ContainsName(PlatformName, ProjectRoot)) { - Exclude.Add(CommandUtils.CombinePaths(File)); + return true; + } + } + else if (InputFile.IsUnderDirectory(LocalRoot)) + { + if (InputFile.ContainsName(PlatformName, LocalRoot)) + { + return true; } } } - foreach (var AllFile in All) + } + return false; + } + + public void StageFiles(StagedFileType FileType, DirectoryReference InputDir, string Wildcard = "*", bool bRecursive = true, string[] ExcludeWildcards = null, StagedDirectoryReference NewPath = null, bool bAllowNone = false, bool bRemap = true, string NewName = null, bool bAllowNotForLicenseesFiles = true, bool bStripFilesForOtherPlatforms = true, bool bConvertToLower = false) + { + int FilesAdded = 0; + + if (DirectoryReference.Exists(InputDir)) + { + FileReference[] InputFiles = CommandUtils.FindFiles(Wildcard, bRecursive, InputDir); + + HashSet ExcludeFiles = new HashSet(); + if (ExcludeWildcards != null) { - var FileToCopy = CommandUtils.CombinePaths(AllFile); - if (Exclude.Contains(FileToCopy)) + foreach (string ExcludeWildcard in ExcludeWildcards) + { + ExcludeFiles.UnionWith(CommandUtils.FindFiles(ExcludeWildcard, bRecursive, InputDir)); + } + } + + foreach (FileReference InputFile in InputFiles) + { + if (ExcludeFiles.Contains(InputFile)) { continue; } - if (!bAllowNotForLicenseesFiles && (FileToCopy.Contains("NotForLicensees") || FileToCopy.Contains("NoRedist"))) + if (bStripFilesForOtherPlatforms && !bIsCombiningMultiplePlatforms && IsFileForOtherPlatform(InputFile)) + { + continue; + } + + // Get the staged location for this file + StagedFileReference Dest; + if (NewPath != null) + { + // If the specified a new directory, first we deal with that, then apply the other things. This is used to collapse the sandbox, among other things. + Dest = StagedFileReference.Combine(NewPath, InputFile.MakeRelativeTo(InputDir)); + } + else if (InputFile.IsUnderDirectory(ProjectRoot)) + { + // Project relative file + Dest = StagedFileReference.Combine(RelativeProjectRootForStage, InputFile.MakeRelativeTo(ProjectRoot)); + } + else if (InputFile.IsUnderDirectory(LocalRoot)) + { + // Engine relative file + Dest = new StagedFileReference(InputFile.MakeRelativeTo(LocalRoot)); + } + else + { + throw new AutomationException("Can't deploy {0} because it doesn't start with {1} or {2}", InputFile, ProjectRoot, LocalRoot); + } + + if (!bAllowNotForLicenseesFiles && (Dest.ContainsName(new FileSystemName("NotForLicensees")) || Dest.ContainsName(new FileSystemName("NoRedist")))) { continue; } - if (bStripFilesForOtherPlatforms && !bIsCombiningMultiplePlatforms) - { - bool OtherPlatform = false; - foreach (UnrealTargetPlatform Plat in Enum.GetValues(typeof(UnrealTargetPlatform))) - { - bool bMatchesIniPlatform = (AllFile.EndsWith(".ini") && Plat == StageTargetPlatform.IniPlatformType); // filter ini files for the ini file platform - bool bMatchesTargetPlatform = (Plat == StageTargetPlatform.PlatformType || Plat == UnrealTargetPlatform.Unknown); // filter platform files for the target platform - if (!bMatchesIniPlatform && !bMatchesTargetPlatform) - { - var Search = FileToCopy; - if (Search.StartsWith(LocalRoot, StringComparison.InvariantCultureIgnoreCase)) - { - if (LocalRoot.EndsWith("\\") || LocalRoot.EndsWith("/")) - { - Search = Search.Substring(LocalRoot.Length - 1); - } - else - { - Search = Search.Substring(LocalRoot.Length); - } - } - if (Search.StartsWith(ProjectRoot, StringComparison.InvariantCultureIgnoreCase)) - { - if (ProjectRoot.EndsWith("\\") || ProjectRoot.EndsWith("/")) - { - Search = Search.Substring(ProjectRoot.Length - 1); - } - else - { - Search = Search.Substring(ProjectRoot.Length); - } - } - if (Search.IndexOf(CommandUtils.CombinePaths("/" + Plat.ToString() + "/"), 0, StringComparison.InvariantCultureIgnoreCase) >= 0) - { - OtherPlatform = true; - break; - } - } - } - if (OtherPlatform) - { - continue; - } - } - - string Dest; - if (!FileToCopy.StartsWith(InPath)) - { - throw new AutomationException("Can't deploy {0}; it was supposed to start with {1}", FileToCopy, InPath); - } - string FileToRemap = FileToCopy; - - // If the specified a new directory, first we deal with that, then apply the other things - // this is used to collapse the sandbox, among other things - if (NewPath != null) - { - Dest = FileToRemap.Substring(InPath.Length); - if (Dest.StartsWith("/") || Dest.StartsWith("\\")) - { - Dest = Dest.Substring(1); - } - Dest = CommandUtils.CombinePaths(NewPath, Dest); -#if false // if the cooker rebases, I don't think we need to ever rebase while staging to a new path - if (Dest.StartsWith("/") || Dest.StartsWith("\\")) - { - Dest = Dest.Substring(1); - } - // project relative stuff in a collapsed sandbox - if (Dest.StartsWith(SourceRelativeProjectRoot, StringComparison.InvariantCultureIgnoreCase)) - { - Dest = Dest.Substring(SourceRelativeProjectRoot.Length); - if (Dest.StartsWith("/") || Dest.StartsWith("\\")) - { - Dest = Dest.Substring(1); - } - Dest = CommandUtils.CombinePaths(RelativeProjectRootForStage, Dest); - } -#endif - } - - // project relative file - else if (FileToRemap.StartsWith(ProjectRoot, StringComparison.InvariantCultureIgnoreCase)) - { - Dest = FileToRemap.Substring(ProjectRoot.Length); - if (Dest.StartsWith("/") || Dest.StartsWith("\\")) - { - Dest = Dest.Substring(1); - } - Dest = CommandUtils.CombinePaths(RelativeProjectRootForStage, Dest); - } - // engine relative file - else if (FileToRemap.StartsWith(LocalRoot, StringComparison.InvariantCultureIgnoreCase)) - { - Dest = CommandUtils.CombinePaths(FileToRemap.Substring(LocalRoot.Length)); - } - else - { - throw new AutomationException("Can't deploy {0} because it doesn't start with {1} or {2}", FileToRemap, ProjectRoot, LocalRoot); - } - - if (Dest.StartsWith("/") || Dest.StartsWith("\\")) - { - Dest = Dest.Substring(1); - } - if (NewName != null) { - Dest = CommandUtils.CombinePaths(Path.GetDirectoryName(Dest), NewName); + Dest = StagedFileReference.Combine(Dest.Directory, NewName); } if (bRemap) @@ -696,68 +613,24 @@ public class DeploymentContext //: ProjectParams Dest = StageTargetPlatform.Remap(Dest); } - if (bConvertToLower) - { - Dest = Dest.ToLowerInvariant(); - } + if (bConvertToLower) + { + Dest = Dest.ToLowerInvariant(); + } + + FilesToStage.Add(FileType, Dest, InputFile); - if (FileType == StagedFileType.UFS) - { - AddUniqueStagingFile(UFSStagingFiles, FileToCopy, Dest); - } - else if (FileType == StagedFileType.NonUFS) - { - AddStagingFile(NonUFSStagingFiles, FileToCopy, Dest); - } - else if (FileType == StagedFileType.DebugNonUFS) - { - AddStagingFile(NonUFSStagingFilesDebug, FileToCopy, Dest); - } FilesAdded++; } } if (FilesAdded == 0 && !bAllowNone && !bIsCombiningMultiplePlatforms) { - throw new AutomationException(ExitCode.Error_StageMissingFile, "No files found to deploy for {0} with wildcard {1} and exclusions {2}", InPath, Wildcard, ExcludeWildcard); + throw new AutomationException(ExitCode.Error_StageMissingFile, "No files found to deploy for {0} with wildcard {1} and exclusions {2}", InputDir, Wildcard, String.Join(", ", ExcludeWildcards)); } } - private void AddUniqueStagingFile(Dictionary FilesToStage, string FileToCopy, string Dest) - { - string ExistingDest; - if (FilesToStage.TryGetValue(FileToCopy, out ExistingDest)) - { - // If the file already exists, it must have the same dest - if (String.Compare(ExistingDest, Dest, true) != 0) - { - throw new AutomationException("Attempting to add \"{0}\" to staging map but it already exists with a different destination (existing: \"{1}\", new: \"{2}\"", - FileToCopy, ExistingDest, Dest); - } - } - else - { - FilesToStage.Add(FileToCopy, Dest); - } - } - - private void AddStagingFile(Dictionary> FilesToStage, string FileToCopy, string Dest) - { - List ExistingDest; - if (FilesToStage.TryGetValue(FileToCopy, out ExistingDest)) - { - if (!FilesToStage[FileToCopy].Contains(Dest)) - { - FilesToStage[FileToCopy].Add(Dest); - } - } - else - { - FilesToStage.Add(FileToCopy, new List(){Dest}); - } - } - public int ArchiveFiles(string InPath, string Wildcard = "*", bool bRecursive = true, string[] ExcludeWildcard = null, string NewPath = null) { int FilesAdded = 0; @@ -788,33 +661,21 @@ public class DeploymentContext //: ProjectParams if (!bIsCombiningMultiplePlatforms) { + FileReference InputFile = new FileReference(FileToCopy); + bool OtherPlatform = false; foreach (UnrealTargetPlatform Plat in Enum.GetValues(typeof(UnrealTargetPlatform))) { if (Plat != StageTargetPlatform.PlatformType && Plat != UnrealTargetPlatform.Unknown) { var Search = FileToCopy; - if (Search.StartsWith(LocalRoot, StringComparison.InvariantCultureIgnoreCase)) + if (InputFile.IsUnderDirectory(LocalRoot)) { - if (LocalRoot.EndsWith("\\") || LocalRoot.EndsWith("/")) - { - Search = Search.Substring(LocalRoot.Length - 1); - } - else - { - Search = Search.Substring(LocalRoot.Length); - } + Search = InputFile.MakeRelativeTo(LocalRoot); } - if (Search.StartsWith(ProjectRoot, StringComparison.InvariantCultureIgnoreCase)) + else if (InputFile.IsUnderDirectory(ProjectRoot)) { - if (ProjectRoot.EndsWith("\\") || ProjectRoot.EndsWith("/")) - { - Search = Search.Substring(ProjectRoot.Length - 1); - } - else - { - Search = Search.Substring(ProjectRoot.Length); - } + Search = InputFile.MakeRelativeTo(ProjectRoot); } if (Search.IndexOf(CommandUtils.CombinePaths("/" + Plat.ToString() + "/"), 0, StringComparison.InvariantCultureIgnoreCase) >= 0) { @@ -880,7 +741,7 @@ public class DeploymentContext //: ProjectParams //replace the port name in the case of deploy while adb is using wifi string SanitizedDeviceName = DeviceName.Replace(":", "_"); - return Path.Combine(StageDirectory, UFSDeployDeltaFileName + SanitizedDeviceName); + return Path.Combine(StageDirectory.FullName, UFSDeployDeltaFileName + SanitizedDeviceName); } public String GetNonUFSDeploymentDeltaPath(string DeviceName) @@ -888,7 +749,7 @@ public class DeploymentContext //: ProjectParams //replace the port name in the case of deploy while adb is using wifi string SanitizedDeviceName = DeviceName.Replace(":", "_"); - return Path.Combine(StageDirectory, NonUFSDeployDeltaFileName + SanitizedDeviceName); + return Path.Combine(StageDirectory.FullName, NonUFSDeployDeltaFileName + SanitizedDeviceName); } public String GetUFSDeploymentObsoletePath(string DeviceName) @@ -896,7 +757,7 @@ public class DeploymentContext //: ProjectParams //replace the port name in the case of deploy while adb is using wifi string SanitizedDeviceName = DeviceName.Replace(":", "_"); - return Path.Combine(StageDirectory, UFSDeployObsoleteFileName + SanitizedDeviceName); + return Path.Combine(StageDirectory.FullName, UFSDeployObsoleteFileName + SanitizedDeviceName); } public String GetNonUFSDeploymentObsoletePath(string DeviceName) @@ -904,7 +765,7 @@ public class DeploymentContext //: ProjectParams //replace the port name in the case of deploy while adb is using wifi string SanitizedDeviceName = DeviceName.Replace(":", "_"); - return Path.Combine(StageDirectory, NonUFSDeployObsoleteFileName + SanitizedDeviceName); + return Path.Combine(StageDirectory.FullName, NonUFSDeployObsoleteFileName + SanitizedDeviceName); } public string UFSDeployedManifestFileName diff --git a/Engine/Source/Programs/AutomationTool/AutomationUtils/HelpUtils.cs b/Engine/Source/Programs/AutomationTool/AutomationUtils/HelpUtils.cs index 9dff5e57cefa..18f10ef1250d 100644 --- a/Engine/Source/Programs/AutomationTool/AutomationUtils/HelpUtils.cs +++ b/Engine/Source/Programs/AutomationTool/AutomationUtils/HelpUtils.cs @@ -10,7 +10,6 @@ using System.Runtime.Serialization; using System.Runtime.Serialization.Json; using System.Text; using System.Threading; -using Tools.DotNETCommon.XmlHandler; using System.ComponentModel; using System.Reflection; diff --git a/Engine/Source/Programs/AutomationTool/AutomationUtils/LinuxHostPlatform.cs b/Engine/Source/Programs/AutomationTool/AutomationUtils/LinuxHostPlatform.cs index f6f26c17698f..7015ec0c4678 100644 --- a/Engine/Source/Programs/AutomationTool/AutomationUtils/LinuxHostPlatform.cs +++ b/Engine/Source/Programs/AutomationTool/AutomationUtils/LinuxHostPlatform.cs @@ -107,6 +107,11 @@ namespace AutomationTool public override bool IsScriptModuleSupported(string ModuleName) { + // @todo: add more unsupported modules here + if (String.Equals(ModuleName, "Gauntlet", StringComparison.InvariantCultureIgnoreCase)) + { + return false; + } return true; } diff --git a/Engine/Source/Programs/AutomationTool/AutomationUtils/Log.cs b/Engine/Source/Programs/AutomationTool/AutomationUtils/Log.cs index ae3793f30d39..4e678ed766f0 100644 --- a/Engine/Source/Programs/AutomationTool/AutomationUtils/Log.cs +++ b/Engine/Source/Programs/AutomationTool/AutomationUtils/Log.cs @@ -173,7 +173,17 @@ namespace AutomationTool if (!File.Exists(LogFilename)) { - break; + try + { + Directory.CreateDirectory(Path.GetDirectoryName(LogFilename)); + using (FileStream Stream = File.Open(LogFilename, FileMode.CreateNew, FileAccess.Write, FileShare.None)) + { + } + break; + } + catch (IOException) + { + } } ++Attempt; diff --git a/Engine/Source/Programs/AutomationTool/AutomationUtils/MCPPublic.cs b/Engine/Source/Programs/AutomationTool/AutomationUtils/MCPPublic.cs index db594bb3b31d..286fb50b5349 100644 --- a/Engine/Source/Programs/AutomationTool/AutomationUtils/MCPPublic.cs +++ b/Engine/Source/Programs/AutomationTool/AutomationUtils/MCPPublic.cs @@ -103,7 +103,17 @@ namespace EpicGames.MCP.Automation /// /// Linux platform. /// - Linux + Linux, + + /// + /// Linux platform. + /// + IOS, + + /// + /// Linux platform. + /// + Android } /// @@ -1002,7 +1012,7 @@ namespace EpicGames.MCP.Automation /// Initializes the provider. /// Configuration data to initialize the provider. The exact format of the data is provider specific. It might, for example, contain an API key. /// - abstract public void Init(Dictionary Config); + abstract public void Init(Dictionary Config, bool bForce = false); /// /// Retrieves a file from the cloud storage provider diff --git a/Engine/Source/Programs/AutomationTool/AutomationUtils/MacHostPlatform.cs b/Engine/Source/Programs/AutomationTool/AutomationUtils/MacHostPlatform.cs index f73e79eeb4ad..f639a3db21d0 100644 --- a/Engine/Source/Programs/AutomationTool/AutomationUtils/MacHostPlatform.cs +++ b/Engine/Source/Programs/AutomationTool/AutomationUtils/MacHostPlatform.cs @@ -130,7 +130,7 @@ namespace AutomationTool public override bool IsScriptModuleSupported(string ModuleName) { // @todo: add more unsupported modules here - if (String.Equals(ModuleName, "OrionGame", StringComparison.InvariantCultureIgnoreCase)) + if (String.Equals(ModuleName, "Gauntlet", StringComparison.InvariantCultureIgnoreCase)) { return false; } diff --git a/Engine/Source/Programs/AutomationTool/AutomationUtils/P4Utils.cs b/Engine/Source/Programs/AutomationTool/AutomationUtils/P4Utils.cs index 77c1a14929b5..46fba1e36f44 100644 --- a/Engine/Source/Programs/AutomationTool/AutomationUtils/P4Utils.cs +++ b/Engine/Source/Programs/AutomationTool/AutomationUtils/P4Utils.cs @@ -7,7 +7,8 @@ using System.IO; using System.ComponentModel; using System.Diagnostics; using System.Text.RegularExpressions; -using Tools.DotNETCommon.CaselessDictionary; +using System.Reflection; +using System.Collections; namespace AutomationTool { @@ -30,7 +31,6 @@ namespace AutomationTool : base(Format, Args) { } } - [Flags] public enum P4LineEnd { Local = 0, @@ -43,9 +43,10 @@ namespace AutomationTool [Flags] public enum P4SubmitOption { - SubmitUnchanged = 0, - RevertUnchanged = 1, - LeaveUnchanged = 2, + SubmitUnchanged = 1, + RevertUnchanged = 2, + LeaveUnchanged = 4, + Reopen = 8 } [Flags] @@ -76,7 +77,7 @@ namespace AutomationTool public DateTime Access; public P4LineEnd LineEnd; public P4ClientOption Options; - public P4SubmitOption SubmitOptions; + public P4SubmitOption SubmitOptions = P4SubmitOption.SubmitUnchanged; public List> View = new List>(); public bool Matches(P4ClientInfo Other) @@ -325,6 +326,602 @@ namespace AutomationTool } } + /// + /// Describes the action performed by the user when resolving the integration + /// + public enum P4IntegrateAction + { + /// + /// file did not previously exist; it was created as a copy of partner-file + /// + [Description("branch from")] + BranchFrom, + + /// + /// partner-file did not previously exist; it was created as a copy of file. + /// + [Description("branch into")] + BranchInto, + + /// + /// file was integrated from partner-file, accepting merge. + /// + [Description("merge from")] + MergeFrom, + + /// + /// file was integrated into partner-file, accepting merge. + /// + [Description("merge into")] + MergeInto, + + /// + /// file was integrated from partner-file, accepting theirs and deleting the original. + /// + [Description("moved from")] + MovedFrom, + + /// + /// file was integrated into partner-file, accepting theirs and creating partner-file if it did not previously exist. + /// + [Description("moved into")] + MovedInto, + + /// + /// file was integrated from partner-file, accepting theirs. + /// + [Description("copy from")] + CopyFrom, + + /// + /// file was integrated into partner-file, accepting theirs. + /// + [Description("copy into")] + CopyInto, + + /// + /// file was integrated from partner-file, accepting yours. + /// + [Description("ignored")] + Ignored, + + /// + /// file was integrated into partner-file, accepting yours. + /// + [Description("ignored by")] + IgnoredBy, + + /// + /// file was integrated from partner-file, and partner-file had been previously deleted. + /// + [Description("delete from")] + DeleteFrom, + + /// + /// file was integrated into partner-file, and file had been previously deleted. + /// + [Description("delete into")] + DeleteInto, + + /// + /// file was integrated from partner-file, and file was edited within the p4 resolve process. + /// + [Description("edit from")] + EditFrom, + + /// + /// file was integrated into partner-file, and partner-file was reopened for edit before submission. + /// + [Description("edit into")] + EditInto, + + /// + /// file was integrated from a deleted partner-file, and partner-file was reopened for add (that is, someone restored a deleted file by syncing back to a pre-deleted revision and adding the file). + /// + [Description("add from")] + AddFrom, + + /// + /// file was integrated into previously nonexistent partner-file, and partner-file was reopened for add before submission. + /// + [Description("add into")] + AddInto, + } + + /// + /// Stores integration information for a file revision + /// + public class P4IntegrationRecord + { + /// + /// The integration action performed for this file + /// + public readonly P4IntegrateAction Action; + + /// + /// The partner file for this integration + /// + public readonly string OtherFile; + + /// + /// Min revision of the partner file for this integration + /// + public readonly int StartRevisionNumber; + + /// + /// Max revision of the partner file for this integration + /// + public readonly int EndRevisionNumber; + + /// + /// Constructor + /// + /// The integration action + /// The partner file involved in the integration + /// Starting revision of the partner file for the integration (exclusive) + /// Ending revision of the partner file for the integration (inclusive) + public P4IntegrationRecord(P4IntegrateAction Action, string OtherFile, int StartRevisionNumber, int EndRevisionNumber) + { + this.Action = Action; + this.OtherFile = OtherFile; + this.StartRevisionNumber = StartRevisionNumber; + this.EndRevisionNumber = EndRevisionNumber; + } + + /// + /// Summarize this record for display in the debugger + /// + /// Formatted integration record + public override string ToString() + { + if(StartRevisionNumber + 1 == EndRevisionNumber) + { + return String.Format("{0} {1}#{2}", Action, OtherFile, EndRevisionNumber); + } + else + { + return String.Format("{0} {1}#{2},#{3}", Action, OtherFile, StartRevisionNumber + 1, EndRevisionNumber); + } + } + } + + /// + /// Stores a revision record for a file + /// + public class P4RevisionRecord + { + /// + /// The revision number of this file + /// + public readonly int RevisionNumber; + + /// + /// The changelist responsible for this revision of the file + /// + public readonly int ChangeNumber; + + /// + /// Action performed to the file in this revision + /// + public readonly P4Action Action; + + /// + /// Type of the file + /// + public readonly string Type; + + /// + /// Timestamp of this modification + /// + public readonly DateTime DateTime; + + /// + /// Author of the changelist + /// + public readonly string UserName; + + /// + /// Client that submitted this changelist + /// + public readonly string ClientName; + + /// + /// Size of the file, or -1 if not specified + /// + public readonly int FileSize; + + /// + /// Digest of the file, or null if not specified + /// + public readonly string Digest; + + /// + /// Description of this changelist + /// + public readonly string Description; + + /// + /// Integration records for this revision + /// + public readonly P4IntegrationRecord[] Integrations; + + /// + /// Constructor + /// + /// Revision number of the file + /// Number of the changelist that submitted this revision + /// Action performed to the file in this changelist + /// Type of the file + /// Timestamp for the change + /// User that submitted the change + /// Client that submitted the change + /// Size of the file, or -1 if not specified + /// Digest of the file, or null if not specified + /// Description of the changelist + /// Integrations performed to the file + public P4RevisionRecord(int RevisionNumber, int ChangeNumber, P4Action Action, string Type, DateTime DateTime, string UserName, string ClientName, int FileSize, string Digest, string Description, P4IntegrationRecord[] Integrations) + { + this.RevisionNumber = RevisionNumber; + this.ChangeNumber = ChangeNumber; + this.Action = Action; + this.Type = Type; + this.DateTime = DateTime; + this.UserName = UserName; + this.ClientName = ClientName; + this.Description = Description; + this.FileSize = FileSize; + this.Digest = Digest; + this.Integrations = Integrations; + } + + /// + /// Format this record for display in the debugger + /// + /// Summary of this revision + public override string ToString() + { + return String.Format("#{0} change {1} {2} on {3} by {4}@{5}", RevisionNumber, ChangeNumber, Action, DateTime, UserName, ClientName); + } + } + + /// + /// Record output by the filelog command + /// + public class P4FileRecord + { + /// + /// Path to the file in the depot + /// + public string DepotPath; + + /// + /// Revisions of this file + /// + public P4RevisionRecord[] Revisions; + + /// + /// Constructor + /// + /// The depot path of the file + /// Revisions of the file + public P4FileRecord(string DepotPath, P4RevisionRecord[] Revisions) + { + this.DepotPath = DepotPath; + this.Revisions = Revisions; + } + + /// + /// Return the depot path of the file for display in the debugger + /// + /// Path to the file + public override string ToString() + { + return DepotPath; + } + } + + /// + /// Options for the filelog command + /// + [Flags] + public enum P4FileLogOptions + { + /// + /// No options + /// + None = 0, + + /// + /// Display file content history instead of file name history. + /// + ContentHistory = 1, + + /// + /// Follow file history across branches. + /// + FollowAcrossBranches = 2, + + /// + /// List long output, with the full text of each changelist description. + /// + FullDescriptions = 4, + + /// + /// List long output, with the full text of each changelist description truncated at 250 characters. + /// + LongDescriptions = 8, + + /// + /// When used with the ContentHistory option, do not follow content of promoted task streams. + /// + DoNotFollowPromotedTaskStreams = 16, + + /// + /// Display a shortened form of output by ignoring non-contributory integrations + /// + IgnoreNonContributoryIntegrations = 32, + } + + /// + /// Type of a Perforce stream + /// + public enum P4StreamType + { + /// + /// A mainline stream + /// + Mainline, + + /// + /// A development stream + /// + Development, + + /// + /// A release stream + /// + Release, + + /// + /// A virtual stream + /// + Virtual, + + /// + /// A task stream + /// + Task, + } + + /// + /// Options for a stream definition + /// + [Flags] + public enum P4StreamOptions + { + /// + /// The stream is locked + /// + Locked = 1, + + /// + /// Only the owner may submit to the stream + /// + OwnerSubmit = 4, + + /// + /// Integrations from this stream to its parent are expected + /// + ToParent = 4, + + /// + /// Integrations from this stream from its parent are expected + /// + FromParent = 8, + + /// + /// Undocumented? + /// + MergeDown = 16, + } + + /// + /// Contains information about a stream, as returned by the 'p4 streams' command + /// + [DebuggerDisplay("{Stream}")] + public class P4StreamRecord + { + /// + /// Path to the stream + /// + public string Stream; + + /// + /// Last time the stream definition was updated + /// + public DateTime Update; + + /// + /// Last time the stream definition was accessed + /// + public DateTime Access; + + /// + /// Owner of this stream + /// + public string Owner; + + /// + /// Name of the stream. This may be modified after the stream is initially created, but it's underlying depot path will not change. + /// + public string Name; + + /// + /// The parent stream + /// + public string Parent; + + /// + /// Type of the stream + /// + public P4StreamType Type; + + /// + /// User supplied description of the stream + /// + public string Description; + + /// + /// Options for the stream definition + /// + public P4StreamOptions Options; + + /// + /// Whether this stream is more stable than the parent stream + /// + public Nullable FirmerThanParent; + + /// + /// Whether changes from this stream flow to the parent stream + /// + public bool ChangeFlowsToParent; + + /// + /// Whether changes from this stream flow from the parent stream + /// + public bool ChangeFlowsFromParent; + + /// + /// The mainline branch associated with this stream + /// + public string BaseParent; + + /// + /// Constructor + /// + /// Path to the stream + /// Last time the stream definition was updated + /// Last time the stream definition was accessed + /// Owner of this stream + /// Name of the stream. This may be modified after the stream is initially created, but it's underlying depot path will not change. + /// The parent stream + /// Type of the stream + /// User supplied description of the stream + /// Options for the stream definition + /// Whether this stream is more stable than the parent stream + /// Whether changes from this stream flow to the parent stream + /// Whether changes from this stream flow from the parent stream + /// The mainline branch associated with this stream + public P4StreamRecord(string Stream, DateTime Update, DateTime Access, string Owner, string Name, string Parent, P4StreamType Type, string Description, P4StreamOptions Options, Nullable FirmerThanParent, bool ChangeFlowsToParent, bool ChangeFlowsFromParent, string BaseParent) + { + this.Stream = Stream; + this.Update = Update; + this.Owner = Owner; + this.Name = Name; + this.Parent = Parent; + this.Type = Type; + this.Description = Description; + this.Options = Options; + this.FirmerThanParent = FirmerThanParent; + this.ChangeFlowsToParent = ChangeFlowsToParent; + this.ChangeFlowsFromParent = ChangeFlowsFromParent; + this.BaseParent = BaseParent; + } + + /// + /// Return the path of this stream for display in the debugger + /// + /// Path to this stream + public override string ToString() + { + return Stream; + } + } + + /// + /// Error severity codes. Taken from the p4java documentation. + /// + public enum P4SeverityCode + { + Empty = 0, + Info = 1, + Warning = 2, + Failed = 3, + Fatal = 4, + } + + /// + /// Generic error codes that can be returned by the Perforce server. Taken from the p4java documentation. + /// + public enum P4GenericCode + { + None = 0, + Usage = 1, + Unknown = 2, + Context = 3, + Illegal = 4, + NotYet = 5, + Protect = 6, + Empty = 17, + Fault = 33, + Client = 34, + Admin = 35, + Config = 36, + Upgrade = 37, + Comm = 38, + TooBig = 39, + } + + /// + /// Represents a error return value from Perforce. + /// + public class P4ReturnCode + { + /// + /// The value of the "code" field returned by the server + /// + public string Code; + + /// + /// The severity of this error + /// + public P4SeverityCode Severity; + + /// + /// The generic error code associated with this message + /// + public P4GenericCode Generic; + + /// + /// The message text + /// + public string Message; + + /// + /// Constructor + /// + /// The value of the "code" field returned by the server + /// The severity of this error + /// The generic error code associated with this message + /// The message text + public P4ReturnCode(string Code, P4SeverityCode Severity, P4GenericCode Generic, string Message) + { + this.Code = Code; + this.Severity = Severity; + this.Generic = Generic; + this.Message = Message; + } + + /// + /// Formats this error for display in the debugger + /// + /// String representation of this object + public override string ToString() + { + return String.Format("{0}: {1} (Generic={2})", Code, Message, Generic); + } + } + public partial class CommandUtils { #region Environment Setup @@ -370,11 +967,9 @@ namespace AutomationTool /// static internal void InitP4Environment() { - CheckP4Enabled(); - // Temporary connection - will use only the currently set env vars to connect to P4 var DefaultConnection = new P4Connection(User: null, Client: null); - PerforceEnvironment = Automation.IsBuildMachine ? new P4Environment(DefaultConnection, CmdEnv) : new LocalP4Environment(DefaultConnection, CmdEnv); + PerforceEnvironment = (Automation.IsBuildMachine && !GlobalCommandLine.ForceLocal) ? new P4Environment(DefaultConnection, CmdEnv) : new LocalP4Environment(DefaultConnection, CmdEnv); } /// @@ -382,8 +977,6 @@ namespace AutomationTool /// static internal void InitDefaultP4Connection() { - CheckP4Enabled(); - PerforceConnection = new P4Connection(User: P4Env.User, Client: P4Env.Client, ServerAndPort: P4Env.P4Port); } @@ -429,17 +1022,6 @@ namespace AutomationTool } private static bool? bP4CLRequired; - /// - /// Throws an exception when P4 is disabled. This should be called in every P4 function. - /// - internal static void CheckP4Enabled() - { - if (P4Enabled == false) - { - throw new AutomationException("P4 is not enabled."); - } - } - /// /// Checks whether commands are allowed to submit files into P4. /// @@ -466,7 +1048,7 @@ namespace AutomationTool /// /// Commands to execute /// Commands - internal static void InitP4Support(List CommandsToExecute, CaselessDictionary Commands) + internal static void InitP4Support(List CommandsToExecute, Dictionary Commands) { // Init AllowSubmit // If we do not specify on the commandline if submitting is allowed or not, this is @@ -507,7 +1089,7 @@ namespace AutomationTool /// /// List of commands to be executed. /// Commands. - private static void CheckIfCommandsRequireP4(List CommandsToExecute, CaselessDictionary Commands, out bool bRequireP4, out bool bRequireCL) + private static void CheckIfCommandsRequireP4(List CommandsToExecute, Dictionary Commands, out bool bRequireP4, out bool bRequireCL) { bRequireP4 = false; bRequireCL = false; @@ -598,14 +1180,6 @@ namespace AutomationTool } } - /// - /// Throws an exception when P4 is disabled. This should be called in every P4 function. - /// - internal static void CheckP4Enabled() - { - CommandUtils.CheckP4Enabled(); - } - /// /// Shortcut to Run but with P4.exe as the program name. /// @@ -615,7 +1189,6 @@ namespace AutomationTool /// Exit code public IProcessResult P4(string CommandLine, string Input = null, bool AllowSpew = true, bool WithClient = true, bool SpewIsVerbose = false) { - CheckP4Enabled(); CommandUtils.ERunOptions RunOptions = AllowSpew ? CommandUtils.ERunOptions.AllowSpew : CommandUtils.ERunOptions.NoLoggingOfRunCommand; if( SpewIsVerbose ) { @@ -634,7 +1207,6 @@ namespace AutomationTool /// True if succeeded, otherwise false. public bool P4Output(out string Output, string CommandLine, string Input = null, bool AllowSpew = true, bool WithClient = true) { - CheckP4Enabled(); Output = ""; var Result = P4(CommandLine, Input, AllowSpew, WithClient); @@ -643,6 +1215,45 @@ namespace AutomationTool return Result.ExitCode == 0; } + /// + /// Calls p4 and returns the output. + /// + /// Output of the comman. + /// Commandline for p4. + /// Stdin input. + /// Whether the command should spew. + /// True if succeeded, otherwise false. + public bool P4Output(out string[] OutputLines, string CommandLine, string Input = null, bool AllowSpew = true, bool WithClient = true) + { + string Output; + bool bResult = P4Output(out Output, CommandLine, Input, AllowSpew, WithClient); + + List Lines = new List(); + for(int Idx = 0; Idx < Output.Length; ) + { + int EndIdx = Output.IndexOf('\n', Idx); + if(EndIdx == -1) + { + Lines.Add(Output.Substring(Idx)); + break; + } + + if(EndIdx > Idx && Output[EndIdx - 1] == '\r') + { + Lines.Add(Output.Substring(Idx, EndIdx - Idx - 1)); + } + else + { + Lines.Add(Output.Substring(Idx, EndIdx - Idx)); + } + + Idx = EndIdx + 1; + } + OutputLines = Lines.ToArray(); + + return bResult; + } + /// /// Calls p4 command and writes the output to a logfile. /// @@ -651,7 +1262,6 @@ namespace AutomationTool /// Whether the command is allowed to spew. public void LogP4(string CommandLine, string Input = null, bool AllowSpew = true, bool WithClient = true, bool SpewIsVerbose = false) { - CheckP4Enabled(); string Output; if (!LogP4Output(out Output, CommandLine, Input, AllowSpew, WithClient, SpewIsVerbose:SpewIsVerbose)) { @@ -669,7 +1279,6 @@ namespace AutomationTool /// True if succeeded, otherwise false. public bool LogP4Output(out string Output, string CommandLine, string Input = null, bool AllowSpew = true, bool WithClient = true, bool SpewIsVerbose = false) { - CheckP4Enabled(); Output = ""; if (String.IsNullOrEmpty(LogPath)) @@ -686,6 +1295,141 @@ namespace AutomationTool return Result.ExitCode == 0; } + /// + /// Execute a Perforce command and parse the output as marshalled Python objects. This is more robustly defined than the text-based tagged output + /// format, because it avoids ambiguity when returned fields can have newlines. + /// + /// Command line to execute Perforce with + /// List that receives the output records + /// Whether to include client information on the command line + public List> P4TaggedOutput(string CommandLine, bool WithClient = true) + { + // Execute Perforce, consuming the binary output into a memory stream + MemoryStream MemoryStream = new MemoryStream(); + using (Process Process = new Process()) + { + Process.StartInfo.FileName = HostPlatform.Current.P4Exe; + Process.StartInfo.Arguments = String.Format("-G {0} {1}", WithClient? GlobalOptions : GlobalOptionsWithoutClient, CommandLine); + + Process.StartInfo.RedirectStandardError = true; + Process.StartInfo.RedirectStandardOutput = true; + Process.StartInfo.RedirectStandardInput = false; + Process.StartInfo.UseShellExecute = false; + Process.StartInfo.CreateNoWindow = true; + + Process.Start(); + + Process.StandardOutput.BaseStream.CopyTo(MemoryStream); + Process.WaitForExit(); + } + + // Move back to the start of the memory stream + MemoryStream.Position = 0; + + // Parse the records + List> Records = new List>(); + using (BinaryReader Reader = new BinaryReader(MemoryStream, Encoding.UTF8)) + { + while(Reader.BaseStream.Position < Reader.BaseStream.Length) + { + // Check that a dictionary follows + byte Temp = Reader.ReadByte(); + if(Temp != '{') + { + throw new P4Exception("Unexpected data while parsing marshalled output - expected '{'"); + } + + // Read all the fields in the record + Dictionary Record = new Dictionary(); + for(;;) + { + // Read the next field type. Perforce only outputs string records. A '0' character indicates the end of the dictionary. + byte KeyFieldType = Reader.ReadByte(); + if(KeyFieldType == '0') + { + break; + } + else if(KeyFieldType != 's') + { + throw new P4Exception("Unexpected key field type while parsing marshalled output ({0}) - expected 's'", (int)KeyFieldType); + } + + // Read the key + int KeyLength = Reader.ReadInt32(); + string Key = Encoding.UTF8.GetString(Reader.ReadBytes(KeyLength)); + + // Read the value type. + byte ValueFieldType = Reader.ReadByte(); + if(ValueFieldType == 'i') + { + // An integer + string Value = Reader.ReadInt32().ToString(); + Record.Add(Key, Value); + } + else if(ValueFieldType == 's') + { + // A string + int ValueLength = Reader.ReadInt32(); + string Value = Encoding.UTF8.GetString(Reader.ReadBytes(ValueLength)); + Record.Add(Key, Value); + } + else + { + throw new P4Exception("Unexpected value field type while parsing marshalled output ({0}) - expected 's'", (int)ValueFieldType); + } + } + Records.Add(Record); + } + } + return Records; + } + + /// + /// Checks that the raw record data includes the given return code, or creates a ReturnCode value if it doesn't + /// + /// The raw record data + /// The expected code value + /// Output variable for receiving the return code if it doesn't match + public static bool VerifyReturnCode(Dictionary RawRecord, string ExpectedCode, out P4ReturnCode OtherReturnCode) + { + // Parse the code field + string Code; + if(!RawRecord.TryGetValue("code", out Code)) + { + Code = "unknown"; + } + + // Check whether it matches what we expect + if(Code == ExpectedCode) + { + OtherReturnCode = null; + return true; + } + else + { + string Severity; + if(!RawRecord.TryGetValue("severity", out Severity)) + { + Severity = ((int)P4SeverityCode.Empty).ToString(); + } + + string Generic; + if(!RawRecord.TryGetValue("generic", out Generic)) + { + Generic = ((int)P4GenericCode.None).ToString(); + } + + string Message; + if(!RawRecord.TryGetValue("data", out Message)) + { + Message = "No description available."; + } + + OtherReturnCode = new P4ReturnCode(Code, (P4SeverityCode)int.Parse(Severity), (P4GenericCode)int.Parse(Generic), Message.TrimEnd()); + return false; + } + } + /// /// Invokes p4 login command. /// @@ -727,7 +1471,12 @@ namespace AutomationTool { return (A.CL < B.CL) ? -1 : (A.CL > B.CL) ? 1 : 0; } - } + + public override string ToString() + { + return String.Format("CL {0}: {1}", CL, Summary); + } + } static Dictionary UserToEmailCache = new Dictionary(); public string UserToEmail(string User) { @@ -773,7 +1522,6 @@ namespace AutomationTool return true; } ChangeRecords = new List(); - CheckP4Enabled(); try { // Change 1999345 on 2014/02/16 by buildmachine@BuildFarm_BUILD-23_buildmachine_++depot+UE4 'GUBP Node Shadow_LabelPromotabl' @@ -914,6 +1662,11 @@ namespace AutomationTool public string File; public int Revision; public string ChangeType; + + public override string ToString() + { + return String.Format("{0}#{1} ({2})", File, Revision, ChangeType); + } } public List Files = new List(); @@ -921,7 +1674,12 @@ namespace AutomationTool { return (A.CL < B.CL) ? -1 : (A.CL > B.CL) ? 1 : 0; } - } + + public override string ToString() + { + return String.Format("CL {0}: {1}", CL, Summary); + } + } /// /// Wraps P4 describe @@ -960,7 +1718,6 @@ namespace AutomationTool public bool DescribeChangelists(List Changelists, out List DescribeRecords, bool AllowSpew = true) { DescribeRecords = new List(); - CheckP4Enabled(); try { // Change 234641 by This.User@WORKSPACE-C2Q-67_Dev on 2008/05/06 10:32:32 @@ -1147,7 +1904,6 @@ namespace AutomationTool /// CommandLine to pass on to the command. public void Sync(string CommandLine, bool AllowSpew = true, bool SpewIsVerbose = false) { - CheckP4Enabled(); LogP4("sync " + CommandLine, null, AllowSpew, SpewIsVerbose:SpewIsVerbose); } @@ -1159,7 +1915,6 @@ namespace AutomationTool /// Commandline for the command. public void Unshelve(int FromCL, int ToCL, string CommandLine = "", bool SpewIsVerbose = false) { - CheckP4Enabled(); LogP4("unshelve " + String.Format("-s {0} ", FromCL) + String.Format("-c {0} ", ToCL) + CommandLine, SpewIsVerbose: SpewIsVerbose); } @@ -1171,7 +1926,6 @@ namespace AutomationTool /// Commandline for the command. public void Shelve(int FromCL, string CommandLine = "", bool AllowSpew = true) { - CheckP4Enabled(); LogP4("shelve " + String.Format("-r -c {0} ", FromCL) + CommandLine, AllowSpew: AllowSpew); } @@ -1182,8 +1936,6 @@ namespace AutomationTool /// Commandline for the command. public void DeleteShelvedFiles(int FromCL, bool AllowSpew = true) { - CheckP4Enabled(); - string Output; if (!LogP4Output(out Output, String.Format("shelve -d -c {0}", FromCL), AllowSpew: AllowSpew) && !Output.StartsWith("No shelved files in changelist to delete.")) { @@ -1198,7 +1950,6 @@ namespace AutomationTool /// Commandline for the command. public void Edit(int CL, string CommandLine) { - CheckP4Enabled(); LogP4("edit " + String.Format("-c {0} ", CL) + CommandLine); } @@ -1211,7 +1962,6 @@ namespace AutomationTool { try { - CheckP4Enabled(); string Output; if (!LogP4Output(out Output, "edit " + String.Format("-c {0} ", CL) + CommandLine, null, true)) { @@ -1236,7 +1986,6 @@ namespace AutomationTool /// Commandline for the command. public void Add(int CL, string CommandLine) { - CheckP4Enabled(); LogP4("add " + String.Format("-c {0} ", CL) + CommandLine); } @@ -1247,7 +1996,6 @@ namespace AutomationTool /// Commandline for the command. public void Reconcile(int CL, string CommandLine, bool AllowSpew = true) { - CheckP4Enabled(); LogP4("reconcile " + String.Format("-c {0} -ead -f ", CL) + CommandLine, AllowSpew: AllowSpew); } @@ -1258,7 +2006,6 @@ namespace AutomationTool /// Commandline for the command. public void ReconcilePreview(string CommandLine) { - CheckP4Enabled(); LogP4("reconcile " + String.Format("-ead -n ") + CommandLine); } @@ -1270,7 +2017,6 @@ namespace AutomationTool /// Commandline for the command. public void ReconcileNoDeletes(int CL, string CommandLine, bool AllowSpew = true) { - CheckP4Enabled(); LogP4("reconcile " + String.Format("-c {0} -ea ", CL) + CommandLine, AllowSpew: AllowSpew); } @@ -1282,7 +2028,6 @@ namespace AutomationTool /// Commandline for the command. public void Resolve(int CL, string CommandLine) { - CheckP4Enabled(); LogP4("resolve -ay " + String.Format("-c {0} ", CL) + CommandLine); } @@ -1292,7 +2037,6 @@ namespace AutomationTool /// Commandline for the command. public void Revert(string CommandLine, bool AllowSpew = true) { - CheckP4Enabled(); LogP4("revert " + CommandLine, AllowSpew: AllowSpew); } @@ -1303,7 +2047,6 @@ namespace AutomationTool /// Commandline for the command. public void Revert(int CL, string CommandLine = "", bool AllowSpew = true) { - CheckP4Enabled(); LogP4("revert " + String.Format("-c {0} ", CL) + CommandLine, AllowSpew: AllowSpew); } @@ -1313,7 +2056,6 @@ namespace AutomationTool /// Changelist to revert the unmodified files from. public void RevertUnchanged(int CL) { - CheckP4Enabled(); // caution this is a really bad idea if you hope to force submit!!! LogP4("revert -a " + String.Format("-c {0} ", CL)); } @@ -1324,7 +2066,6 @@ namespace AutomationTool /// Changelist to revert. public void RevertAll(int CL, bool SpewIsVerbose = false) { - CheckP4Enabled(); LogP4("revert " + String.Format("-c {0} //...", CL), SpewIsVerbose: SpewIsVerbose); } @@ -1337,7 +2078,6 @@ namespace AutomationTool /// If true, if the submit fails, revert the CL. public void Submit(int CL, out int SubmittedCL, bool Force = false, bool RevertIfFail = false) { - CheckP4Enabled(); if (!CommandUtils.AllowSubmit) { throw new P4Exception("Submit is not allowed currently. Please use the -Submit switch to override that."); @@ -1505,11 +2245,18 @@ namespace AutomationTool /// Owner of the changelist. /// Description of the changelist. /// Id of the created changelist. - public int CreateChange(string Owner = null, string Description = null, bool AllowSpew = false) + public int CreateChange(string Owner = null, string Description = null, string User = null, string Type = null, bool AllowSpew = false) { - CheckP4Enabled(); var ChangeSpec = "Change: new" + "\n"; ChangeSpec += "Client: " + ((Owner != null) ? Owner : "") + "\n"; + if(User != null) + { + ChangeSpec += "User: " + User + "\n"; + } + if(Type != null) + { + ChangeSpec += "Type: " + Type + "\n"; + } ChangeSpec += "Description: " + ((Description != null) ? Description.Replace("\n", "\n\t") : "(none)") + "\n"; string CmdOutput; int CL = 0; @@ -1549,8 +2296,6 @@ namespace AutomationTool /// public void UpdateChange(int CL, string NewOwner, string NewDescription, bool SpewIsVerbose = false) { - CheckP4Enabled(); - string CmdOutput; if(!LogP4Output(out CmdOutput, String.Format("change -o {0}", CL), SpewIsVerbose: SpewIsVerbose)) { @@ -1584,7 +2329,6 @@ namespace AutomationTool /// Indicates whether files in that changelist should be reverted. public void DeleteChange(int CL, bool RevertFiles = true, bool SpewIsVerbose = false, bool AllowSpew = true) { - CheckP4Enabled(); if (RevertFiles) { RevertAll(CL, SpewIsVerbose: SpewIsVerbose); @@ -1612,8 +2356,6 @@ namespace AutomationTool /// True if the changelist was deleted, false otherwise. public bool TryDeleteEmptyChange(int CL) { - CheckP4Enabled(); - string CmdOutput; if (LogP4Output(out CmdOutput, String.Format("change -d {0}", CL))) { @@ -1637,7 +2379,6 @@ namespace AutomationTool /// Specification of the changelist. public string ChangeOutput(int CL, bool AllowSpew = true) { - CheckP4Enabled(); string CmdOutput; if (LogP4Output(out CmdOutput, String.Format("change -o {0}", CL), AllowSpew: AllowSpew)) { @@ -1654,7 +2395,6 @@ namespace AutomationTool /// Returns whether the changelist exists. public bool ChangeExists(int CL, out bool Pending, bool AllowSpew = true) { - CheckP4Enabled(); string CmdOutput = ChangeOutput(CL, AllowSpew); Pending = false; if (CmdOutput.Length > 0) @@ -1695,7 +2435,6 @@ namespace AutomationTool /// List of the files contained in the changelist. public List ChangeFiles(int CL, out bool Pending, bool AllowSpew = true) { - CheckP4Enabled(); var Result = new List(); if (ChangeExists(CL, out Pending, AllowSpew)) @@ -1750,7 +2489,6 @@ namespace AutomationTool /// Specification of the changelist. public string OpenedOutput() { - CheckP4Enabled(); string CmdOutput; if (LogP4Output(out CmdOutput, "opened")) { @@ -1764,7 +2502,6 @@ namespace AutomationTool /// Label to delete. public void DeleteLabel(string LabelName, bool AllowSpew = true) { - CheckP4Enabled(); var CommandLine = "label -d " + LabelName; // NOTE: We don't throw exceptions when trying to delete a label @@ -1787,7 +2524,6 @@ namespace AutomationTool /// Time of the label creation public void CreateLabel(string Name, string Options, string View, string Owner = null, string Description = null, string Date = null, string Time = null) { - CheckP4Enabled(); var LabelSpec = "Label: " + Name + "\n"; LabelSpec += "Owner: " + ((Owner != null) ? Owner : "") + "\n"; LabelSpec += "Description: " + ((Description != null) ? Description : "") + "\n"; @@ -1816,7 +2552,6 @@ namespace AutomationTool /// Whether the command is allowed to spew. public void Tag(string LabelName, string FilePath, bool AllowSpew = true) { - CheckP4Enabled(); LogP4("tag -l " + LabelName + " " + FilePath, null, AllowSpew); } @@ -1827,7 +2562,6 @@ namespace AutomationTool /// Whether the command is allowed to spew. public void LabelSync(string LabelName, bool AllowSpew = true, string FileToLabel = "") { - CheckP4Enabled(); string Quiet = ""; if (!AllowSpew) { @@ -1851,7 +2585,6 @@ namespace AutomationTool /// Whether the command is allowed to spew. public void LabelToLabelSync(string FromLabelName, string ToLabelName, bool AllowSpew = true) { - CheckP4Enabled(); string Quiet = ""; if (!AllowSpew) { @@ -1867,7 +2600,6 @@ namespace AutomationTool /// Whether there is an label with files. public bool LabelExistsAndHasFiles(string Name) { - CheckP4Enabled(); string Output; return LogP4Output(out Output, "files -m 1 //...@" + Name); } @@ -1881,7 +2613,6 @@ namespace AutomationTool /// Returns whether the label description could be retrieved. public bool LabelDescription(string Name, out string Description, bool AllowSpew = true) { - CheckP4Enabled(); string Output; Description = ""; if (LogP4Output(out Output, "label -o " + Name, AllowSpew: AllowSpew)) @@ -1976,8 +2707,6 @@ namespace AutomationTool /// The head CL number. public int GetLatestCLNumber() { - CheckP4Enabled(); - string Output; if (!LogP4Output(out Output, "changes -s submitted -m1") || string.IsNullOrWhiteSpace(Output)) { @@ -2053,20 +2782,105 @@ namespace AutomationTool /// The file's first reported path on disk or null if no mapping was found public string DepotToLocalPath(string DepotFile, bool AllowSpew = true) { - P4WhereRecord[] Records = Where(DepotFile, AllowSpew); - if (Records != null) + // P4 where outputs missing entries + string Command = String.Format("-z tag fstat \"{0}\"", DepotFile); + + // Run the command. + string[] Lines; + if (!P4Output(out Lines, Command, AllowSpew: AllowSpew)) { - foreach (P4WhereRecord Record in Records) + throw new P4Exception("p4.exe {0} failed.", Command); + } + + // Find the line containing the client file prefix + const string ClientFilePrefix = "... clientFile "; + foreach(string Line in Lines) + { + if(Line.StartsWith(ClientFilePrefix)) { - if (!Record.bUnmap) - { - return Record.Path; - } + return Line.Substring(ClientFilePrefix.Length); } } return null; } + /// + /// Given a set of file paths in the depot, returns the local disk mapping for the current view + /// + /// The full file paths in depot naming form + /// The file's first reported path on disk or null if no mapping was found + public string[] DepotToLocalPaths(string[] DepotFiles, bool AllowSpew = true) + { + const int BatchSize = 20; + + // Parse the output from P4 + List Lines = new List(); + for(int Idx = 0; Idx < DepotFiles.Length; Idx += BatchSize) + { + // Build the argument list + StringBuilder Command = new StringBuilder("-z tag fstat "); + for(int ArgIdx = Idx; ArgIdx < Idx + BatchSize && ArgIdx < DepotFiles.Length; ArgIdx++) + { + Command.AppendFormat(" {0}", CommandUtils.MakePathSafeToUseWithCommandLine(DepotFiles[ArgIdx])); + } + + // Run the command. + string[] Output; + if (!P4Output(out Output, Command.ToString(), AllowSpew: AllowSpew)) + { + throw new P4Exception("p4.exe {0} failed.", Command); + } + + // Append it to the combined output + Lines.AddRange(Output); + } + + // Parse all the error lines. These may occur out of sequence due to stdout/stderr buffering. + for(int LineIdx = 0; LineIdx < Lines.Count; LineIdx++) + { + if(Lines[LineIdx].Length > 0 && !Lines[LineIdx].StartsWith("... ")) + { + throw new AutomationException("Unexpected output from p4.exe fstat: {0}", Lines[LineIdx]); + } + } + + // Parse the output lines + string[] LocalFiles = new string[DepotFiles.Length]; + for(int FileIdx = 0, LineIdx = 0; FileIdx < DepotFiles.Length; FileIdx++) + { + string DepotFile = DepotFiles[FileIdx]; + if(LineIdx == Lines.Count) + { + throw new AutomationException("Unexpected end of output looking for file record for {0}", DepotFile); + } + else + { + // We've got a file record; try to parse the matching fields + for(; LineIdx < Lines.Count && Lines[LineIdx].Length > 0; LineIdx++) + { + const string DepotFilePrefix = "... depotFile "; + if(Lines[LineIdx].StartsWith(DepotFilePrefix) && Lines[LineIdx].Substring(DepotFilePrefix.Length) != DepotFile) + { + throw new AutomationException("Expected file record for '{0}'; received output '{1}'", DepotFile, Lines[LineIdx]); + } + + const string ClientFilePrefix = "... clientFile "; + if(Lines[LineIdx].StartsWith(ClientFilePrefix)) + { + LocalFiles[FileIdx] = Lines[LineIdx].Substring(ClientFilePrefix.Length); + } + } + + // Skip any blank lines + while(LineIdx < Lines.Count && Lines[LineIdx].Length == 0) + { + LineIdx++; + } + } + } + return LocalFiles; + } + /// /// Determines the mappings for a depot file in the workspace, without that file having to exist. /// NOTE: This function originally allowed multiple depot paths at once. The "file(s) not in client view" messages are written to stderr @@ -2077,8 +2891,6 @@ namespace AutomationTool /// List of records describing the file's mapping. Usually just one, but may be more. public P4WhereRecord[] Where(string DepotFile, bool AllowSpew = true) { - CheckP4Enabled(); - // P4 where outputs missing entries string Command = String.Format("-z tag where \"{0}\"", DepotFile); @@ -2166,7 +2978,6 @@ namespace AutomationTool /// File stats (invalid if the file does not exist in P4) public P4FileStat FStat(string Filename) { - CheckP4Enabled(); string Output; string Command = "fstat " + CommandUtils.MakePathSafeToUseWithCommandLine(Filename); if (!LogP4Output(out Output, Command)) @@ -2244,9 +3055,9 @@ namespace AutomationTool /// /// P4 command output (must be a form). /// Parsed output. - public CaselessDictionary ParseTaggedP4Output(string Output) + public Dictionary ParseTaggedP4Output(string Output) { - var Tags = new CaselessDictionary(); + var Tags = new Dictionary(StringComparer.InvariantCultureIgnoreCase); var Lines = Output.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); string DelayKey = ""; int DelayIndex = 0; @@ -2309,7 +3120,6 @@ namespace AutomationTool /// True if the client exists. public bool DoesClientExist(string ClientName, bool Quiet = false) { - CheckP4Enabled(); if(!Quiet) { CommandUtils.LogLog("Checking if client {0} exists", ClientName); @@ -2326,8 +3136,6 @@ namespace AutomationTool /// public P4ClientInfo GetClientInfo(string ClientName, bool Quiet = false) { - CheckP4Enabled(); - if(!Quiet) { CommandUtils.LogLog("Getting info for client {0}", ClientName); @@ -2347,8 +3155,8 @@ namespace AutomationTool /// private static object ParseEnumValues(string ValueText, Type EnumType) { - ValueText = ValueText.Replace(' ', ','); - return Enum.Parse(EnumType, ValueText, true); + ValueText = new Regex("[+ ]").Replace(ValueText, ","); + return Enum.Parse(EnumType, ValueText, true); } /// @@ -2431,8 +3239,6 @@ namespace AutomationTool /// List of clients owned by the user. public P4ClientInfo[] GetClientsForUser(string UserName, string PathUnderClientRoot = null) { - CheckP4Enabled(); - var ClientList = new List(); // Get all clients for this user @@ -2489,10 +3295,9 @@ namespace AutomationTool /// /// Client name. /// Forces the operation (-f) - public void DeleteClient(string Name, bool Force = false) + public void DeleteClient(string Name, bool Force = false, bool AllowSpew = true) { - CheckP4Enabled(); - LogP4(String.Format("client -d {0} {1}", (Force ? "-f" : ""), Name), WithClient: false); + LogP4(String.Format("client -d {0} {1}", (Force ? "-f" : ""), Name), WithClient: false, AllowSpew: AllowSpew); } /// @@ -2507,7 +3312,7 @@ namespace AutomationTool SpecInput += "Host: " + ClientSpec.Host + Environment.NewLine; SpecInput += "Root: " + ClientSpec.RootPath + Environment.NewLine; SpecInput += "Options: " + ClientSpec.Options.ToString().ToLowerInvariant().Replace(",", "") + Environment.NewLine; - SpecInput += "SubmitOptions: " + ClientSpec.SubmitOptions.ToString().ToLowerInvariant().Replace(",", "") + Environment.NewLine; + SpecInput += "SubmitOptions: " + ClientSpec.SubmitOptions.ToString().ToLowerInvariant().Replace(", ", "+") + Environment.NewLine; SpecInput += "LineEnd: " + ClientSpec.LineEnd.ToString().ToLowerInvariant() + Environment.NewLine; if(ClientSpec.Stream != null) { @@ -2534,7 +3339,6 @@ namespace AutomationTool /// List of sub-directories of the specified directories. public List Dirs(string CommandLine) { - CheckP4Enabled(); var DirsCmdLine = String.Format("dirs {0}", CommandLine); var P4Result = P4(DirsCmdLine, AllowSpew: false); if (P4Result.ExitCode != 0) @@ -2560,7 +3364,6 @@ namespace AutomationTool /// List of files in the specified directory. public List Files(string CommandLine) { - CheckP4Enabled(); string FilesCmdLine = String.Format("files {0}", CommandLine); IProcessResult P4Result = P4(FilesCmdLine, AllowSpew: false); if (P4Result.ExitCode != 0) @@ -2657,6 +3460,362 @@ namespace AutomationTool return Changelists; } + /// + /// Execute the 'filelog' command + /// + /// Options for the command + /// List of file specifications to query + /// List of file records + public P4FileRecord[] FileLog(P4FileLogOptions Options, params string[] FileSpecs) + { + return FileLog(-1, -1, Options, FileSpecs); + } + + /// + /// Execute the 'filelog' command + /// + /// Number of changelists to show. Ignored if zero or negative. + /// Options for the command + /// List of file specifications to query + /// List of file records + public P4FileRecord[] FileLog(int MaxChanges, P4FileLogOptions Options, params string[] FileSpecs) + { + return FileLog(-1, MaxChanges, Options, FileSpecs); + } + + /// + /// Execute the 'filelog' command + /// + /// Show only files modified by this changelist. Ignored if zero or negative. + /// Number of changelists to show. Ignored if zero or negative. + /// Options for the command + /// List of file specifications to query + /// List of file records + public P4FileRecord[] FileLog(int ChangeNumber, int MaxChanges, P4FileLogOptions Options, params string[] FileSpecs) + { + P4FileRecord[] Records; + P4ReturnCode ReturnCode = TryFileLog(ChangeNumber, MaxChanges, Options, FileSpecs, out Records); + if(ReturnCode != null) + { + if(ReturnCode.Generic == P4GenericCode.Empty) + { + return new P4FileRecord[0]; + } + else + { + throw new P4Exception(ReturnCode.ToString()); + } + } + return Records; + } + + /// + /// Execute the 'filelog' command + /// + /// Show only files modified by this changelist. Ignored if zero or negative. + /// Number of changelists to show. Ignored if zero or negative. + /// Options for the command + /// List of file specifications to query + /// List of file records + public P4ReturnCode TryFileLog(int ChangeNumber, int MaxChanges, P4FileLogOptions Options, string[] FileSpecs, out P4FileRecord[] OutRecords) + { + // Build the argument list + List Arguments = new List(); + if(ChangeNumber > 0) + { + Arguments.Add(String.Format("-c {0}", ChangeNumber)); + } + if((Options & P4FileLogOptions.ContentHistory) != 0) + { + Arguments.Add("-h"); + } + if((Options & P4FileLogOptions.FollowAcrossBranches) != 0) + { + Arguments.Add("-i"); + } + if((Options & P4FileLogOptions.FullDescriptions) != 0) + { + Arguments.Add("-l"); + } + if((Options & P4FileLogOptions.LongDescriptions) != 0) + { + Arguments.Add("-L"); + } + if(MaxChanges > 0) + { + Arguments.Add(String.Format("-m {0}", MaxChanges)); + } + if((Options & P4FileLogOptions.DoNotFollowPromotedTaskStreams) != 0) + { + Arguments.Add("-p"); + } + if((Options & P4FileLogOptions.IgnoreNonContributoryIntegrations) != 0) + { + Arguments.Add("-s"); + } + + // Always include times to simplify parsing + Arguments.Add("-t"); + + // Add the file arguments + foreach(string FileSpec in FileSpecs) + { + Arguments.Add(CommandUtils.MakePathSafeToUseWithCommandLine(FileSpec)); + } + + // Format the full command line + string CommandLine = String.Format("filelog {0}", String.Join(" ", Arguments)); + + // Get the output + List> RawRecords = P4TaggedOutput(CommandLine); + + // Parse all the output + List Records = new List(); + foreach(Dictionary RawRecord in RawRecords) + { + // Make sure the record has the correct return value + P4ReturnCode OtherReturnCode; + if(!VerifyReturnCode(RawRecord, "stat", out OtherReturnCode)) + { + OutRecords = null; + return OtherReturnCode; + } + + // Get the depot path for this revision + string DepotPath = RawRecord["depotFile"]; + + // Parse the revisions + List Revisions = new List(); + for(;;) + { + string RevisionSuffix = String.Format("{0}", Revisions.Count); + + string RevisionNumberText; + if(!RawRecord.TryGetValue("rev" + RevisionSuffix, out RevisionNumberText)) + { + break; + } + + int RevisionNumber = int.Parse(RevisionNumberText); + int RevisionChangeNumber = int.Parse(RawRecord["change" + RevisionSuffix]); + P4Action Action = ParseActionText(RawRecord["action" + RevisionSuffix]); + DateTime DateTime = UnixEpoch + TimeSpan.FromSeconds(long.Parse(RawRecord["time" + RevisionSuffix])); + string Type = RawRecord["type" + RevisionSuffix]; + string UserName = RawRecord["user" + RevisionSuffix]; + string ClientName = RawRecord["client" + RevisionSuffix]; + int FileSize = RawRecord.ContainsKey("fileSize" + RevisionSuffix)? int.Parse(RawRecord["fileSize" + RevisionSuffix]) : -1; + string Digest = RawRecord.ContainsKey("digest" + RevisionSuffix)? RawRecord["digest" + RevisionSuffix] : null; + string Description = RawRecord["desc" + RevisionSuffix]; + + // Parse all the following integration info + List Integrations = new List(); + for(;;) + { + string IntegrationSuffix = String.Format("{0},{1}", Revisions.Count, Integrations.Count); + + string HowText; + if(!RawRecord.TryGetValue("how" + IntegrationSuffix, out HowText)) + { + break; + } + + P4IntegrateAction IntegrateAction = ParseIntegrateActionText(HowText); + string OtherFile = RawRecord["file" + IntegrationSuffix]; + string StartRevisionText = RawRecord["srev" + IntegrationSuffix]; + string EndRevisionText = RawRecord["erev" + IntegrationSuffix]; + int StartRevisionNumber = (StartRevisionText == "#none")? 0 : int.Parse(StartRevisionText.Substring(1)); + int EndRevisionNumber = int.Parse(EndRevisionText.Substring(1)); + + Integrations.Add(new P4IntegrationRecord(IntegrateAction, OtherFile, StartRevisionNumber, EndRevisionNumber)); + } + + // Add the revision + Revisions.Add(new P4RevisionRecord(RevisionNumber, RevisionChangeNumber, Action, Type, DateTime, UserName, ClientName, FileSize, Digest, Description, Integrations.ToArray())); + } + + // Add the file record + Records.Add(new P4FileRecord(DepotPath, Revisions.ToArray())); + } + OutRecords = Records.ToArray(); + return null; + } + + static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + /// + /// Enumerates all streams in a depot + /// + /// The path for streams to enumerate (eg. "//UE4/...") + /// List of streams matching the given criteria + public List Streams(string StreamPath) + { + return Streams(StreamPath, -1, null, false); + } + + /// + /// Enumerates all streams in a depot + /// + /// The path for streams to enumerate (eg. "//UE4/...") + /// Maximum number of results to return + /// Additional filter to be applied to the results + /// Whether to enumerate unloaded workspaces + /// List of streams matching the given criteria + public List Streams(string StreamPath, int MaxResults, string Filter, bool bUnloaded) + { + // Build the command line + StringBuilder CommandLine = new StringBuilder("streams"); + if(bUnloaded) + { + CommandLine.Append(" -U"); + } + if(Filter != null) + { + CommandLine.AppendFormat("-F \"{0}\"", Filter); + } + if(MaxResults > 0) + { + CommandLine.AppendFormat("-m {0}", MaxResults); + } + CommandLine.AppendFormat(" \"{0}\"", StreamPath); + + // Execute the command + List> RawRecords = P4TaggedOutput(CommandLine.ToString(), false); + + // Parse the output + List Records = new List(); + foreach(Dictionary RawRecord in RawRecords) + { + // Make sure the record has the correct return value + P4ReturnCode OtherReturnCode; + if(!VerifyReturnCode(RawRecord, "stat", out OtherReturnCode)) + { + throw new P4Exception(OtherReturnCode.ToString()); + } + + // Parse the fields + string Stream = RawRecord["Stream"]; + DateTime Update = UnixEpoch + TimeSpan.FromSeconds(long.Parse(RawRecord["Update"])); + DateTime Access = UnixEpoch + TimeSpan.FromSeconds(long.Parse(RawRecord["Access"])); + string Owner = RawRecord["Owner"]; + string Name = RawRecord["Name"]; + string Parent = RawRecord["Parent"]; + P4StreamType Type = (P4StreamType)Enum.Parse(typeof(P4StreamType), RawRecord["Type"], true); + string Description = RawRecord["desc"]; + P4StreamOptions Options = ParseStreamOptions(RawRecord["Options"]); + Nullable FirmerThanParent = ParseNullableBool(RawRecord["firmerThanParent"]); + bool ChangeFlowsToParent = bool.Parse(RawRecord["changeFlowsToParent"]); + bool ChangeFlowsFromParent = bool.Parse(RawRecord["changeFlowsFromParent"]); + string BaseParent = RawRecord["baseParent"]; + + // Add the new stream record + Records.Add(new P4StreamRecord(Stream, Update, Access, Owner, Name, Parent, Type, Description, Options, FirmerThanParent, ChangeFlowsToParent, ChangeFlowsFromParent, BaseParent)); + } + return Records; + } + + /// + /// Parse a nullable boolean + /// + /// Text to parse. May be "true", "false", or "n/a". + /// The parsed boolean + static Nullable ParseNullableBool(string Text) + { + switch(Text) + { + case "true": + return true; + case "false": + return false; + case "n/a": + return null; + default: + throw new P4Exception("Invalid value for nullable bool: {0}", Text); + } + } + + /// + /// Parse a list of stream option flags + /// + /// Text to parse + /// Flags for the stream options + static P4StreamOptions ParseStreamOptions(string Text) + { + P4StreamOptions Options = 0; + foreach(string Option in Text.Split(' ')) + { + switch(Option) + { + case "locked": + Options |= P4StreamOptions.Locked; + break; + case "ownersubmit": + Options |= P4StreamOptions.OwnerSubmit; + break; + case "toparent": + Options |= P4StreamOptions.ToParent; + break; + case "fromparent": + Options |= P4StreamOptions.FromParent; + break; + case "mergedown": + Options |= P4StreamOptions.MergeDown; + break; + case "unlocked": + case "allsubmit": + case "notoparent": + case "nofromparent": + case "mergeany": + break; + default: + throw new P4Exception("Unknown stream option '{0}'", Option); + } + } + return Options; + } + + static Dictionary GetEnumLookup() + { + Dictionary Lookup = new Dictionary(); + foreach(T Value in Enum.GetValues(typeof(T))) + { + foreach(MemberInfo Member in typeof(T).GetMember(Value.ToString())) + { + string Description = Member.GetCustomAttribute().Description; + Lookup.Add(Description, Value); + } + } + return Lookup; + } + + static Lazy> DescriptionToAction = new Lazy>(() => GetEnumLookup()); + + static P4Action ParseActionText(string ActionText) + { + P4Action Action; + if(!DescriptionToAction.Value.TryGetValue(ActionText, out Action)) + { + throw new P4Exception("Invalid action '{0}'", Action); + } + return Action; + } + + static Lazy> DescriptionToIntegrationAction = new Lazy>(() => GetEnumLookup()); + + static P4IntegrateAction ParseIntegrateActionText(string ActionText) + { + P4IntegrateAction Action; + if(!DescriptionToIntegrationAction.Value.TryGetValue(ActionText, out Action)) + { + throw new P4Exception("Invalid integration action '{0}'", Action); + } + return Action; + } + + static DateTime ParseDateTime(string DateTimeText) + { + return DateTime.ParseExact(DateTimeText, "yyyy/MM/dd HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture); + } + /// /// For a given file (and revision, potentially), returns where it was integrated from. Useful in conjunction with files in a P4DescribeRecord, with action = "integrate". /// @@ -2755,7 +3914,7 @@ namespace AutomationTool } } - private static P4Action ParseAction(string Action) + static P4Action ParseAction(string Action) { P4Action Result = P4Action.Unknown; var AllActions = GetEnumValuesAndKeywords(typeof(P4Action)); diff --git a/Engine/Source/Programs/AutomationTool/AutomationUtils/Platform.cs b/Engine/Source/Programs/AutomationTool/AutomationUtils/Platform.cs index db36fef983f1..fb84ea8d7906 100644 --- a/Engine/Source/Programs/AutomationTool/AutomationUtils/Platform.cs +++ b/Engine/Source/Programs/AutomationTool/AutomationUtils/Platform.cs @@ -228,75 +228,26 @@ namespace AutomationTool return InExecutableName; } - public virtual List GetExecutableNames(DeploymentContext SC, bool bIsRun = false) + public virtual List GetExecutableNames(DeploymentContext SC) { - var ExecutableNames = new List(); - string Ext = AutomationTool.Platform.GetExeExtension(SC.StageTargetPlatform.TargetPlatformType); - if (!String.IsNullOrEmpty(SC.CookPlatform)) + List ExecutableNames = new List(); + foreach (StageTarget Target in SC.StageTargets) { - if (SC.StageTargets.Count() > 0) + foreach (BuildProduct Product in Target.Receipt.BuildProducts) { - DirectoryReference ProjectRoot = new DirectoryReference(SC.ProjectRoot); - foreach (StageTarget Target in SC.StageTargets) + if (Product.Type == BuildProductType.Executable) { - foreach (BuildProduct Product in Target.Receipt.BuildProducts) + FileReference BuildProductFile = Product.Path; + if (BuildProductFile.IsUnderDirectory(SC.ProjectRoot)) { - if (Product.Type == BuildProductType.Executable) - { - FileReference BuildProductFile = new FileReference(Product.Path); - if (BuildProductFile.IsUnderDirectory(ProjectRoot)) - { - ExecutableNames.Add(CombinePaths(SC.RuntimeProjectRootDir, BuildProductFile.MakeRelativeTo(ProjectRoot))); - } - else - { - ExecutableNames.Add(CombinePaths(SC.RuntimeRootDir, BuildProductFile.MakeRelativeTo(RootDirectory))); - } - } + ExecutableNames.Add(FileReference.Combine(SC.RuntimeProjectRootDir, BuildProductFile.MakeRelativeTo(SC.ProjectRoot))); + } + else + { + ExecutableNames.Add(FileReference.Combine(SC.RuntimeRootDir, BuildProductFile.MakeRelativeTo(RootDirectory))); } } } - //@todo, probably the rest of this can go away once everything passes it through - else if (SC.DedicatedServer) - { - if (!SC.IsCodeBasedProject) - { - string ExeName = SC.StageTargetPlatform.GetPlatformExecutableName("UE4Server"); - ExecutableNames.Add(CombinePaths(SC.RuntimeRootDir, "Engine/Binaries", SC.PlatformDir, ExeName + Ext)); - } - else - { - string ExeName = SC.StageTargetPlatform.GetPlatformExecutableName(SC.ShortProjectName + "Server"); - string ClientApp = CombinePaths(SC.RuntimeProjectRootDir, "Binaries", SC.PlatformDir, ExeName + Ext); - var TestApp = CombinePaths(SC.ProjectRoot, "Binaries", SC.PlatformDir, SC.ShortProjectName + "Server" + Ext); - string Game = "Game"; - //@todo, this is sketchy, someone might ask what the exe is before it is compiled - if (!FileExists_NoExceptions(ClientApp) && !FileExists_NoExceptions(TestApp) && SC.ShortProjectName.EndsWith(Game, StringComparison.InvariantCultureIgnoreCase)) - { - ExeName = SC.StageTargetPlatform.GetPlatformExecutableName(SC.ShortProjectName.Substring(0, SC.ShortProjectName.Length - Game.Length) + "Server"); - ClientApp = CombinePaths(SC.RuntimeProjectRootDir, "Binaries", SC.PlatformDir, ExeName + Ext); - } - ExecutableNames.Add(ClientApp); - } - } - else - { - if (!SC.IsCodeBasedProject) - { - string ExeName = SC.StageTargetPlatform.GetPlatformExecutableName("UE4Game"); - ExecutableNames.Add(CombinePaths(SC.RuntimeRootDir, "Engine/Binaries", SC.PlatformDir, ExeName + Ext)); - } - else - { - string ExeName = SC.StageTargetPlatform.GetPlatformExecutableName(SC.ShortProjectName); - ExecutableNames.Add(CombinePaths(SC.RuntimeProjectRootDir, "Binaries", SC.PlatformDir, ExeName + Ext)); - } - } - } - else - { - string ExeName = SC.StageTargetPlatform.GetPlatformExecutableName("UE4Editor"); - ExecutableNames.Add(CombinePaths(SC.RuntimeRootDir, "Engine/Binaries", SC.PlatformDir, ExeName + Ext)); } return ExecutableNames; } @@ -326,7 +277,7 @@ namespace AutomationTool /// Deployment Context public virtual void GetFilesToArchive(ProjectParams Params, DeploymentContext SC) { - SC.ArchiveFiles(SC.StageDirectory); + SC.ArchiveFiles(SC.StageDirectory.FullName); } /// @@ -387,15 +338,6 @@ namespace AutomationTool return GetCookPlatform(false, false); } - /// - /// return true if we need to change the case of filenames inside of pak files - /// - /// - public virtual bool DeployPakInternalLowerCaseFilenames() - { - return false; - } - /// /// return true if we need to change the case of filenames outside of pak files /// @@ -483,11 +425,11 @@ namespace AutomationTool /// /// Remaps the given content directory to its final location /// - public virtual string Remap(string Dest) + public virtual StagedFileReference Remap(StagedFileReference Dest) { return Dest; } - + /// /// Tri-state - The intent is to override command line parameters for pak if needed per platform. /// @@ -533,14 +475,14 @@ namespace AutomationTool get { return false; } } - public virtual List GetFilesForCRCCheck() + public virtual HashSet GetFilesForCRCCheck() { string CmdLine = "UE4CommandLine.txt"; if (DeployLowerCaseFilenames(true)) { CmdLine = CmdLine.ToLowerInvariant(); } - return new List() { CmdLine }; + return new HashSet() { new StagedFileReference(CmdLine) }; } public virtual void StripSymbols(FileReference SourceFile, FileReference TargetFile) diff --git a/Engine/Source/Programs/AutomationTool/AutomationUtils/ProcessUtils.cs b/Engine/Source/Programs/AutomationTool/AutomationUtils/ProcessUtils.cs index 7f5b60265dab..5e62bc13a2ac 100644 --- a/Engine/Source/Programs/AutomationTool/AutomationUtils/ProcessUtils.cs +++ b/Engine/Source/Programs/AutomationTool/AutomationUtils/ProcessUtils.cs @@ -818,7 +818,7 @@ namespace AutomationTool { Result.WaitForExit(); var BuildDuration = (DateTime.UtcNow - StartTime).TotalMilliseconds; - AddRunTime(App, (int)(BuildDuration)); + //AddRunTime(App, (int)(BuildDuration)); Result.ExitCode = Proc.ExitCode; if (!Options.HasFlag(ERunOptions.NoLoggingOfRunCommand) || Options.HasFlag(ERunOptions.LoggingOfRunDuration)) { @@ -959,7 +959,8 @@ namespace AutomationTool /// /// Environment to use. /// Commandline to pass on to the executable - public static string RunUAT(CommandEnvironment Env, string CommandLine) + /// Log prefix for output + public static string RunUAT(CommandEnvironment Env, string CommandLine, string Identifier = null) { // We want to redirect the output from recursive UAT calls into our normal log folder, but prefix everything with a unique identifier. To do so, we set the EnvVarNames.LogFolder environment // variable to a subfolder of it, then copy its contents into the main folder with a prefix after it's finished. Start by finding a base name we can use to identify the output of this run. @@ -1021,7 +1022,7 @@ namespace AutomationTool OSEnv.Add(AutomationTool.EnvVarNames.LocalRoot, ""); // if we don't clear this out, it will think it is a build machine; it will rederive everything } - IProcessResult Result = Run(App, CommandLine, null, ERunOptions.Default, OSEnv); + IProcessResult Result = Run(App, CommandLine, null, ERunOptions.Default, OSEnv, Identifier: Identifier); if (Result.Output.Length > 0) { WriteToFile(LogFile, Result.Output); diff --git a/Engine/Source/Programs/AutomationTool/AutomationUtils/ProjectParams.cs b/Engine/Source/Programs/AutomationTool/AutomationUtils/ProjectParams.cs index 1e1a03d89ef6..473b86185089 100644 --- a/Engine/Source/Programs/AutomationTool/AutomationUtils/ProjectParams.cs +++ b/Engine/Source/Programs/AutomationTool/AutomationUtils/ProjectParams.cs @@ -234,11 +234,14 @@ namespace AutomationTool this.ServerTargetPlatforms = InParams.ServerTargetPlatforms; this.ServerDependentPlatformMap = InParams.ServerDependentPlatformMap; this.Build = InParams.Build; + this.SkipBuildClient = InParams.SkipBuildClient; + this.SkipBuildEditor = InParams.SkipBuildEditor; this.Run = InParams.Run; this.Cook = InParams.Cook; this.IterativeCooking = InParams.IterativeCooking; this.IterateSharedCookedBuild = InParams.IterateSharedCookedBuild; - this.CookAll = InParams.CookAll; + this.IterateSharedBuildUsePrecompiledExe = InParams.IterateSharedBuildUsePrecompiledExe; + this.CookAll = InParams.CookAll; this.CookPartialGC = InParams.CookPartialGC; this.CookInEditor = InParams.CookInEditor; this.CookOutputDir = InParams.CookOutputDir; @@ -273,6 +276,7 @@ namespace AutomationTool this.CreateChunkInstall = InParams.CreateChunkInstall; this.UE4Exe = InParams.UE4Exe; this.NoDebugInfo = InParams.NoDebugInfo; + this.MapFile = InParams.MapFile; this.NoCleanStage = InParams.NoCleanStage; this.MapToRun = InParams.MapToRun; this.AdditionalServerMapParams = InParams.AdditionalServerMapParams; @@ -282,6 +286,7 @@ namespace AutomationTool this.BundleName = InParams.BundleName; this.RunCommandline = InParams.RunCommandline; this.ServerCommandline = InParams.ServerCommandline; + this.ClientCommandline = InParams.ClientCommandline; this.Package = InParams.Package; this.Deploy = InParams.Deploy; this.DeployFolder = InParams.DeployFolder; @@ -360,6 +365,8 @@ namespace AutomationTool List ServerTargetPlatforms = null, Dictionary ServerDependentPlatformMap = null, bool? Build = null, + bool? SkipBuildClient = null, + bool? SkipBuildEditor = null, bool? Cook = null, bool? Run = null, bool? SkipServer = null, @@ -368,6 +375,7 @@ namespace AutomationTool bool? UseDebugParamForEditorExe = null, bool? IterativeCooking = null, bool? IterateSharedCookedBuild = null, + bool? IterateSharedBuildUsePrecompiledExe = null, bool? CookAll = null, bool? CookPartialGC = null, bool? CookInEditor = null, @@ -402,6 +410,7 @@ namespace AutomationTool bool? NoCleanStage = null, bool? NoClient = null, bool? NoDebugInfo = null, + bool? MapFile = null, bool? NoXGE = null, bool? Package = null, bool? Pak = null, @@ -509,6 +518,8 @@ namespace AutomationTool this.ServerTargetPlatforms = SetupTargetPlatforms(ref this.ServerDependentPlatformMap, Command, ServerTargetPlatforms, this.ClientTargetPlatforms, false, "ServerTargetPlatform", "ServerPlatform"); this.Build = GetParamValueIfNotSpecified(Command, Build, this.Build, "build"); + this.SkipBuildClient = GetParamValueIfNotSpecified(Command, SkipBuildClient, this.SkipBuildEditor, "skipbuildclient"); + this.SkipBuildEditor = GetParamValueIfNotSpecified(Command, SkipBuildEditor, this.SkipBuildEditor, "skipbuildeditor"); this.Run = GetParamValueIfNotSpecified(Command, Run, this.Run, "run"); this.Cook = GetParamValueIfNotSpecified(Command, Cook, this.Cook, "cook"); this.CreateReleaseVersionBasePath = ParseParamValueIfNotSpecified(Command, CreateReleaseVersionBasePath, "createreleaseversionroot", String.Empty); @@ -566,7 +577,8 @@ namespace AutomationTool this.UseDebugParamForEditorExe = GetParamValueIfNotSpecified(Command, UseDebugParamForEditorExe, this.UseDebugParamForEditorExe, "UseDebugParamForEditorExe"); this.IterativeCooking = GetParamValueIfNotSpecified(Command, IterativeCooking, this.IterativeCooking, new string[] { "iterativecooking", "iterate" }); this.IterateSharedCookedBuild = GetParamValueIfNotSpecified(Command, IterateSharedCookedBuild, this.IterateSharedCookedBuild, new string[] { "IterateSharedCookedBuild"}); - + this.IterateSharedBuildUsePrecompiledExe = GetParamValueIfNotSpecified(Command, IterateSharedBuildUsePrecompiledExe, this.IterateSharedBuildUsePrecompiledExe, new string[] { "IterateSharedBuildUsePrecompiledExe" }); + this.SkipCookOnTheFly = GetParamValueIfNotSpecified(Command, SkipCookOnTheFly, this.SkipCookOnTheFly, "skipcookonthefly"); this.CookAll = GetParamValueIfNotSpecified(Command, CookAll, this.CookAll, "CookAll"); this.CookPartialGC = GetParamValueIfNotSpecified(Command, CookPartialGC, this.CookPartialGC, "CookPartialGC"); @@ -595,7 +607,12 @@ namespace AutomationTool this.CreateChunkInstall = GetParamValueIfNotSpecified(Command, CreateChunkInstall, this.CreateChunkInstall, "createchunkinstall"); this.ChunkInstallDirectory = ParseParamValueIfNotSpecified(Command, ChunkInstallDirectory, "chunkinstalldirectory", String.Empty, true); this.ChunkInstallVersionString = ParseParamValueIfNotSpecified(Command, ChunkInstallVersionString, "chunkinstallversion", String.Empty, true); - this.Archive = GetParamValueIfNotSpecified(Command, Archive, this.Archive, "archive"); + this.ChunkInstallReleaseString = ParseParamValueIfNotSpecified(Command, ChunkInstallReleaseString, "chunkinstallrelease", String.Empty, true); + if (string.IsNullOrEmpty(this.ChunkInstallReleaseString)) + { + this.ChunkInstallReleaseString = this.ChunkInstallVersionString; + } + this.Archive = GetParamValueIfNotSpecified(Command, Archive, this.Archive, "archive"); this.ArchiveDirectoryParam = ParseParamValueIfNotSpecified(Command, ArchiveDirectoryParam, "archivedirectory", String.Empty, true); this.ArchiveMetaData = GetParamValueIfNotSpecified(Command, ArchiveMetaData, this.ArchiveMetaData, "archivemetadata"); this.CreateAppBundle = GetParamValueIfNotSpecified(Command, CreateAppBundle, true, "createappbundle"); @@ -619,6 +636,7 @@ namespace AutomationTool //this.StageDirectoryParam = this.PrebuiltDir; } this.NoDebugInfo = GetParamValueIfNotSpecified(Command, NoDebugInfo, this.NoDebugInfo, "nodebuginfo"); + this.MapFile = GetParamValueIfNotSpecified(Command, MapFile, this.MapFile, "mapfile"); this.NoCleanStage = GetParamValueIfNotSpecified(Command, NoCleanStage, this.NoCleanStage, "nocleanstage"); this.MapToRun = ParseParamValueIfNotSpecified(Command, MapToRun, "map", String.Empty); this.AdditionalServerMapParams = ParseParamValueIfNotSpecified(Command, AdditionalServerMapParams, "AdditionalServerMapParams", String.Empty); @@ -630,6 +648,8 @@ namespace AutomationTool this.RunCommandline = this.RunCommandline.Replace('\'', '\"'); // replace any single quotes with double quotes this.ServerCommandline = ParseParamValueIfNotSpecified(Command, ServerCommandline, "servercmdline"); this.ServerCommandline = this.ServerCommandline.Replace('\'', '\"'); // replace any single quotes with double quotes + this.ClientCommandline = ParseParamValueIfNotSpecified(Command, ClientCommandline, "clientcmdline"); + this.ClientCommandline = this.ClientCommandline.Replace('\'', '\"'); // replace any single quotes with double quotes this.Package = GetParamValueIfNotSpecified(Command, Package, this.Package, "package"); this.Deploy = GetParamValueIfNotSpecified(Command, Deploy, this.Deploy, "deploy"); @@ -647,7 +667,6 @@ namespace AutomationTool this.Deploy = true; } - if (string.IsNullOrEmpty(this.DeployFolder)) this.IterativeDeploy = GetParamValueIfNotSpecified(Command, IterativeDeploy, this.IterativeDeploy, new string[] {"iterativedeploy", "iterate" } ); this.FastCook = GetParamValueIfNotSpecified(Command, FastCook, this.FastCook, "FastCook"); this.IgnoreCookErrors = GetParamValueIfNotSpecified(Command, IgnoreCookErrors, this.IgnoreCookErrors, "IgnoreCookErrors"); @@ -1052,10 +1071,15 @@ namespace AutomationTool /// public string ChunkInstallVersionString { set; get; } - /// - /// Shared: Directory to copy the client to, command line: -stagingdirectory= - /// - public string BaseStageDirectory + /// + /// Shared: Release string to use for built chunk install data, command line: -chunkinstallrelease= + /// + public string ChunkInstallReleaseString { set; get; } + + /// + /// Shared: Directory to copy the client to, command line: -stagingdirectory= + /// + public string BaseStageDirectory { get { @@ -1136,6 +1160,16 @@ namespace AutomationTool [Help("build", "True if build step should be executed")] public bool Build { private set; get; } + /// + /// SkipBuildClient if true then don't build the client exe + /// + public bool SkipBuildClient { private set; get; } + + /// + /// SkipBuildEditor if true then don't build the editor exe + /// + public bool SkipBuildEditor { private set; get; } + /// /// Build: True if XGE should NOT be used for building. /// @@ -1359,11 +1393,17 @@ namespace AutomationTool public bool IterativeCooking; /// - /// Cook: Iterate from a shared cooked build + /// Cook: Iterate from a build on the network /// [Help("Iteratively cook from a shared cooked build")] public bool IterateSharedCookedBuild; + /// + /// Build: Don't build the game instead use the prebuild exe (requires iterate shared cooked build + /// + [Help("Iteratively cook from a shared cooked build")] + public bool IterateSharedBuildUsePrecompiledExe; + /// /// Cook: Only cook maps (and referenced content) instead of cooking everything only affects -cookall flag /// @@ -1408,11 +1448,17 @@ namespace AutomationTool #region Stage /// - /// Stage: Commanndline: -nodebuginfo + /// Stage: Commandline: -nodebuginfo /// [Help("nodebuginfo", "do not copy debug files to the stage")] public bool NoDebugInfo { private set; get; } + /// + /// Stage: Commandline: -mapfile + /// + [Help("MapFile", "generates a *.map file")] + public bool MapFile { private set; get; } + /// /// true if the staging directory is to be cleaned: -cleanstage (also true if -clean is specified) /// @@ -1581,6 +1627,12 @@ namespace AutomationTool [Help("servercmdline", "Additional command line arguments for the program")] public string ServerCommandline; + /// + /// Run: Override command line arguments to pass to the client, if set it will not try to guess at IPs or settings + /// + [Help("clientcmdline", "Override command line arguments to pass to the client")] + public string ClientCommandline; + /// /// Run:adds -nullrhi to the client commandline /// @@ -1871,7 +1923,7 @@ namespace AutomationTool if ( ClientTargetPlatforms.Count > 0 ) { var ProjectClientBinariesPath = ProjectUtils.GetClientProjectBinariesRootPath(RawProjectPath, ProjectType, Properties.bIsCodeBasedProject); - ProjectBinariesPath = ProjectUtils.GetProjectClientBinariesFolder(ProjectClientBinariesPath, ClientTargetPlatforms[0].Type); + ProjectBinariesPath = ProjectUtils.GetProjectClientBinariesFolder(ProjectClientBinariesPath, ClientTargetPlatforms[0].Type).FullName; ProjectGameExePath = CommandUtils.CombinePaths(ProjectBinariesPath, GameTarget + Platform.GetExeExtension(ClientTargetPlatforms[0].Type)); } } @@ -2026,7 +2078,7 @@ namespace AutomationTool String Platform = SC.StageTargetPlatform.GetCookPlatform(SC.DedicatedServer, bIsClientOnly); if (String.IsNullOrEmpty(BasePath)) { - BasePath = CommandUtils.CombinePaths(SC.ProjectRoot, "Releases", BasedOnReleaseVersion, Platform); + BasePath = CommandUtils.CombinePaths(SC.ProjectRoot.FullName, "Releases", BasedOnReleaseVersion, Platform); } else { @@ -2052,7 +2104,7 @@ namespace AutomationTool String Platform = SC.StageTargetPlatform.GetCookPlatform(SC.DedicatedServer, bIsClientOnly); if (String.IsNullOrEmpty(BasePath)) { - BasePath = CommandUtils.CombinePaths(SC.ProjectRoot, "Releases", CreateReleaseVersion, Platform); + BasePath = CommandUtils.CombinePaths(SC.ProjectRoot.FullName, "Releases", CreateReleaseVersion, Platform); } else { @@ -2312,6 +2364,8 @@ namespace AutomationTool CommandUtils.LogLog("BaseArchiveDirectory={0}", BaseArchiveDirectory); CommandUtils.LogLog("BaseStageDirectory={0}", BaseStageDirectory); CommandUtils.LogLog("Build={0}", Build); + CommandUtils.LogLog("SkipBuildClient={0}", SkipBuildClient); + CommandUtils.LogLog("SkipBuildEditor={0}", SkipBuildEditor); CommandUtils.LogLog("Cook={0}", Cook); CommandUtils.LogLog("Clean={0}", Clean); CommandUtils.LogLog("Client={0}", Client); @@ -2344,6 +2398,7 @@ namespace AutomationTool CommandUtils.LogLog("IsProgramTarget={0}", IsProgramTarget.ToString()); CommandUtils.LogLog("IterativeCooking={0}", IterativeCooking); CommandUtils.LogLog("IterateSharedCookedBuild={0}", IterateSharedCookedBuild); + CommandUtils.LogLog("IterateSharedBuildUsePrecompiledExe={0}", IterateSharedBuildUsePrecompiledExe); CommandUtils.LogLog("CookAll={0}", CookAll); CommandUtils.LogLog("CookPartialGC={0}", CookPartialGC); CommandUtils.LogLog("CookInEditor={0}", CookInEditor); @@ -2357,6 +2412,7 @@ namespace AutomationTool CommandUtils.LogLog("NoClient={0}", NoClient); CommandUtils.LogLog("NumClients={0}", NumClients); CommandUtils.LogLog("NoDebugInfo={0}", NoDebugInfo); + CommandUtils.LogLog("MapFile={0}", MapFile); CommandUtils.LogLog("NoCleanStage={0}", NoCleanStage); CommandUtils.LogLog("NoXGE={0}", NoXGE); CommandUtils.LogLog("MapsToCook={0}", MapsToCook.ToString()); diff --git a/Engine/Source/Programs/AutomationTool/AutomationUtils/ProjectUtils.cs b/Engine/Source/Programs/AutomationTool/AutomationUtils/ProjectUtils.cs index a9f07b0dc46c..c9a1757acebe 100644 --- a/Engine/Source/Programs/AutomationTool/AutomationUtils/ProjectUtils.cs +++ b/Engine/Source/Programs/AutomationTool/AutomationUtils/ProjectUtils.cs @@ -7,7 +7,6 @@ using System.Text; using System.IO; using UnrealBuildTool; using System.Diagnostics; -using Tools.DotNETCommon.CaselessDictionary; using Tools.DotNETCommon; using System.Reflection; @@ -69,7 +68,7 @@ namespace AutomationTool /// public class ProjectUtils { - private static CaselessDictionary PropertiesCache = new CaselessDictionary(); + private static Dictionary PropertiesCache = new Dictionary(StringComparer.InvariantCultureIgnoreCase); /// /// Gets a short project name (QAGame, Elemental, etc) @@ -119,11 +118,11 @@ namespace AutomationTool /// Full project path. /// Platform type. /// Path to the binaries folder. - public static string GetProjectClientBinariesFolder(string ProjectClientBinariesPath, UnrealTargetPlatform Platform = UnrealTargetPlatform.Unknown) + public static DirectoryReference GetProjectClientBinariesFolder(DirectoryReference ProjectClientBinariesPath, UnrealTargetPlatform Platform = UnrealTargetPlatform.Unknown) { if (Platform != UnrealTargetPlatform.Unknown) { - ProjectClientBinariesPath = CommandUtils.CombinePaths(ProjectClientBinariesPath, Platform.ToString()); + ProjectClientBinariesPath = DirectoryReference.Combine(ProjectClientBinariesPath, Platform.ToString()); } return ProjectClientBinariesPath; } @@ -362,23 +361,23 @@ namespace AutomationTool /// Target type. /// True if uproject file. /// Binaries path. - public static string GetClientProjectBinariesRootPath(FileReference RawProjectPath, TargetType TargetType, bool bIsCodeBasedProject) + public static DirectoryReference GetClientProjectBinariesRootPath(FileReference RawProjectPath, TargetType TargetType, bool bIsCodeBasedProject) { - var BinPath = String.Empty; + DirectoryReference BinPath = null; switch (TargetType) { case TargetType.Program: - BinPath = CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Engine", "Binaries"); + BinPath = DirectoryReference.Combine(CommandUtils.RootDirectory, "Engine", "Binaries"); break; case TargetType.Client: case TargetType.Game: if (!bIsCodeBasedProject) { - BinPath = CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Engine", "Binaries"); + BinPath = DirectoryReference.Combine(CommandUtils.RootDirectory, "Engine", "Binaries"); } else { - BinPath = CommandUtils.CombinePaths(CommandUtils.GetDirectoryName(RawProjectPath.FullName), "Binaries"); + BinPath = DirectoryReference.Combine(RawProjectPath.Directory, "Binaries"); } break; } diff --git a/Engine/Source/Programs/AutomationTool/AutomationUtils/ScriptCompiler.cs b/Engine/Source/Programs/AutomationTool/AutomationUtils/ScriptCompiler.cs index 1c3a4c947443..a7909a3c2e90 100644 --- a/Engine/Source/Programs/AutomationTool/AutomationUtils/ScriptCompiler.cs +++ b/Engine/Source/Programs/AutomationTool/AutomationUtils/ScriptCompiler.cs @@ -10,7 +10,6 @@ using Microsoft.Win32; using System.Reflection; using System.Diagnostics; using UnrealBuildTool; -using Tools.DotNETCommon.CaselessDictionary; namespace AutomationTool { @@ -33,7 +32,7 @@ namespace AutomationTool { #region Fields - private CaselessDictionary ScriptCommands; + private Dictionary ScriptCommands; #if DEBUG const string BuildConfig = "Debug"; #else @@ -88,7 +87,7 @@ namespace AutomationTool // Instantiate all the automation classes for interrogation Log.TraceVerbose("Creating commands."); - ScriptCommands = new CaselessDictionary(); + ScriptCommands = new Dictionary(StringComparer.InvariantCultureIgnoreCase); foreach (var CompiledScripts in ScriptAssemblies) { try @@ -322,6 +321,17 @@ namespace AutomationTool { CommandUtils.LogVerbose("Cleaning up script DLL folder"); CommandUtils.DeleteDirectory(GetScriptAssemblyFolder()); + + // Bug in PortalPublishingTool caused these DLLs to be copied into Engine/Binaries/DotNET. Delete any files left over. + DirectoryReference BinariesDir = DirectoryReference.Combine(CommandUtils.RootDirectory, "Engine", "Binaries", "DotNET"); + foreach (FileReference FileToDelete in DirectoryReference.EnumerateFiles(BinariesDir, "*.automation.dll")) + { + CommandUtils.DeleteFile(FileToDelete.FullName); + } + foreach (FileReference FileToDelete in DirectoryReference.EnumerateFiles(BinariesDir, "*.automation.pdb")) + { + CommandUtils.DeleteFile(FileToDelete.FullName); + } } private static string GetScriptAssemblyFolder() @@ -333,7 +343,7 @@ namespace AutomationTool #region Properties - public CaselessDictionary Commands + public Dictionary Commands { get { return ScriptCommands; } } diff --git a/Engine/Source/Programs/AutomationTool/AutomationUtils/StagedDirectoryReference.cs b/Engine/Source/Programs/AutomationTool/AutomationUtils/StagedDirectoryReference.cs new file mode 100644 index 000000000000..2af3c93fcfa0 --- /dev/null +++ b/Engine/Source/Programs/AutomationTool/AutomationUtils/StagedDirectoryReference.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +public class StagedDirectoryReference : StagedFileSystemReference, IEquatable +{ + /// + /// Shared instance representing the root directory + /// + public static readonly StagedDirectoryReference Root = new StagedDirectoryReference(""); + + /// + /// Constructor + /// + /// The directory being referred to. Either type of directory separator is permitted and will be normalized. Empty path fragments and leading/trailing slashes are not permitted. + public StagedDirectoryReference(string Name) : base(Name) + { + } + + /// + /// Create a staged directory reference by concatenating multiple strings + /// + /// The base directory + /// The fragments to append + /// Directory reference formed by concatenating the arguments + public static StagedDirectoryReference Combine(string BaseDir, params string[] Fragments) + { + return new StagedDirectoryReference(CombineStrings(BaseDir, Fragments)); + } + + /// + /// Create a staged directory reference by concatenating multiple strings + /// + /// The base directory + /// The fragments to append + /// Directory reference formed by concatenating the arguments + public static StagedDirectoryReference Combine(StagedDirectoryReference BaseDir, params string[] Fragments) + { + return new StagedDirectoryReference(CombineStrings(BaseDir.Name, Fragments)); + } + + /// + /// Compares two directory references for equality + /// + /// First directory reference + /// Second directory reference + /// True if the two directories are identical. Case is ignored. + public static bool operator ==(StagedDirectoryReference A, StagedDirectoryReference B) + { + if ((object)A == null) + { + return (object)B == null; + } + else + { + return (object)B != null && A.CanonicalName == B.CanonicalName; + } + } + + /// + /// Compares two directory references for inequality + /// + /// First directory reference + /// Second directory reference + /// True if the two directories are not identical. Case is ignored. + public static bool operator !=(StagedDirectoryReference A, StagedDirectoryReference B) + { + return !(A == B); + } + + /// + /// Compares against another object for equality + /// + /// Object to compare against + /// True if the other object is a directory reference and is identical. Case is ignored. + public override bool Equals(object Obj) + { + StagedDirectoryReference Other = Obj as StagedDirectoryReference; + return Other != null && Other.CanonicalName == CanonicalName; + } + + /// + /// Compares against another object for equality + /// + /// Directory reference to compare against + /// True if the two directories are identical. Case is ignored. + public bool Equals(StagedDirectoryReference Other) + { + return CanonicalName == Other.CanonicalName; + } + + /// + /// Gets a hash code for this reference. + /// + /// Hash code for the current object. + public override int GetHashCode() + { + return CanonicalName.GetHashCode(); + } +} + diff --git a/Engine/Source/Programs/AutomationTool/AutomationUtils/StagedFileReference.cs b/Engine/Source/Programs/AutomationTool/AutomationUtils/StagedFileReference.cs new file mode 100644 index 000000000000..c60a743fbf74 --- /dev/null +++ b/Engine/Source/Programs/AutomationTool/AutomationUtils/StagedFileReference.cs @@ -0,0 +1,166 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnrealBuildTool; + +/// +/// Location of a staged file. Stored in a normalized format with forward slashes as directory separators. +/// +public class StagedFileReference : StagedFileSystemReference, IEquatable +{ + /// + /// Constructor + /// + /// The file being referred to. Either type of directory separator is permitted and will be normalized. Empty path fragments and leading/trailing slashes are not permitted. + public StagedFileReference(string Name) : base(Name) + { + } + + /// + /// Protected constructor. Initializes to the given parameters without validation. + /// + /// The name of this entity. + /// Canonical name of this entity. Should be equal to Name.ToLowerInvariant(). + private StagedFileReference(string Name, string CanonicalName) : base(Name, CanonicalName) + { + } + + /// + /// Accessor for the directory containing this file + /// + public StagedDirectoryReference Directory + { + get + { + int LastSlashIdx = Name.LastIndexOf('/'); + if(LastSlashIdx == -1) + { + return StagedDirectoryReference.Root; + } + else + { + return new StagedDirectoryReference(Name.Substring(0, LastSlashIdx)); + } + } + } + + /// + /// Determines if the name contains the given fragment + /// + /// + /// + public bool ContainsName(FileSystemName Name) + { + int StartIdx = 0; + for(;;) + { + int Idx = CanonicalName.IndexOf(Name.CanonicalName, StartIdx); + if(Idx == -1) + { + return false; + } + if (Idx == 0 || CanonicalName[Idx - 1] == '/') + { + int EndIdx = Idx + Name.CanonicalName.Length; + if(EndIdx < CanonicalName.Length && CanonicalName[EndIdx] == '/') + { + return true; + } + } + StartIdx = Idx + 1; + } + } + + /// + /// Create a staged file reference by concatenating multiple strings + /// + /// The base directory + /// The fragments to append + /// File reference formed by concatenating the arguments + public static StagedFileReference Combine(string BaseDir, params string[] Fragments) + { + return new StagedFileReference(CombineStrings(BaseDir, Fragments)); + } + + /// + /// Create a staged file reference by concatenating multiple strings + /// + /// The base directory + /// The fragments to append + /// File reference formed by concatenating the arguments + public static StagedFileReference Combine(StagedDirectoryReference BaseDir, params string[] Fragments) + { + return new StagedFileReference(CombineStrings(BaseDir.Name, Fragments)); + } + + /// + /// Converts this file reference to a lowercase invariant form. + /// + /// Lowercase version of this file reference. + public StagedFileReference ToLowerInvariant() + { + return new StagedFileReference(CanonicalName, CanonicalName); + } + + /// + /// Compares two file references for equality + /// + /// First file reference + /// Second file reference + /// True if the two files are identical. Case is ignored. + public static bool operator ==(StagedFileReference A, StagedFileReference B) + { + if ((object)A == null) + { + return (object)B == null; + } + else + { + return (object)B != null && A.CanonicalName == B.CanonicalName; + } + } + + /// + /// Compares two file references for inequality + /// + /// First file reference + /// Second file reference + /// True if the two files are not identical. Case is ignored. + public static bool operator !=(StagedFileReference A, StagedFileReference B) + { + return !(A == B); + } + + /// + /// Compares against another object for equality + /// + /// Object to compare against + /// True if the other object is a directory reference and is identical. Case is ignored. + public override bool Equals(object Obj) + { + StagedFileReference Other = Obj as StagedFileReference; + return Other != null && Other.CanonicalName == CanonicalName; + } + + /// + /// Compares against another object for equality + /// + /// Directory reference to compare against + /// True if the two directories are identical. Case is ignored. + public bool Equals(StagedFileReference Other) + { + return CanonicalName == Other.CanonicalName; + } + + /// + /// Gets a hash code for this reference. + /// + /// Hash code for the current object. + public override int GetHashCode() + { + return CanonicalName.GetHashCode(); + } +} + diff --git a/Engine/Source/Programs/AutomationTool/AutomationUtils/StagedFileSystemReference.cs b/Engine/Source/Programs/AutomationTool/AutomationUtils/StagedFileSystemReference.cs new file mode 100644 index 000000000000..ed264f44daaa --- /dev/null +++ b/Engine/Source/Programs/AutomationTool/AutomationUtils/StagedFileSystemReference.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnrealBuildTool; + +/// +/// Location of a staged file or directory. Stored in a normalized format with forward slashes as directory separators. +/// +public abstract class StagedFileSystemReference +{ + /// + /// The name of this file system entity + /// + public readonly string Name; + + /// + /// Name of this filesystem entity in a canonical format for easy comparison + /// + public readonly string CanonicalName; + + /// + /// Constructor + /// + /// The file system reference referred to. Either type of directory separator is permitted and will be normalized. Empty path fragments and leading/trailing slashes are not permitted. + public StagedFileSystemReference(string Name) + { + Name = Name.Replace('\\', '/'); + + this.Name = Name; + this.CanonicalName = Name.ToLowerInvariant(); + + if (Name.Length > 0) + { + int LastIdx = -1; + for (int Idx = 0; Idx <= Name.Length; Idx++) + { + if (Idx == Name.Length || Name[Idx] == '/') + { + if (Idx == LastIdx + 1) + { + throw new ArgumentException("Empty path fragment in staged filesystem reference"); + } + if (Idx == LastIdx + 2 && Name[Idx - 1] == '.') + { + throw new ArgumentException("Pseudo-directories are not permitted in filesystem references"); + } + if (Idx == LastIdx + 3 && Name[Idx - 1] == '.' && Name[Idx - 2] == '.') + { + throw new ArgumentException("Pseudo-directories are not permitted in filesystem references"); + } + LastIdx = Idx; + } + } + } + } + + /// + /// Protected constructor. Initializes to the given parameters without validation. + /// + /// The name of this entity. + /// Canonical name of this entity. Should be equal to Name.ToLowerInvariant(). + protected StagedFileSystemReference(string Name, string CanonicalName) + { + this.Name = Name; + this.CanonicalName = CanonicalName; + } + + /// + /// Create a full path by concatenating multiple strings + /// + /// + static protected string CombineStrings(string BaseDirectory, params string[] Fragments) + { + StringBuilder NewName = new StringBuilder(BaseDirectory); + foreach (string Fragment in Fragments) + { + if (NewName.Length > 0) + { + NewName.Append('/'); + } + NewName.Append(Fragment); + } + return NewName.ToString(); + } + + /// + /// Returns the name of this entity + /// + /// Path to the file or directory + public override string ToString() + { + return Name; + } +} diff --git a/Engine/Source/Programs/AutomationTool/AutomationUtils/ThreadPoolWorkQueue.cs b/Engine/Source/Programs/AutomationTool/AutomationUtils/ThreadPoolWorkQueue.cs new file mode 100644 index 000000000000..d733cb0de0df --- /dev/null +++ b/Engine/Source/Programs/AutomationTool/AutomationUtils/ThreadPoolWorkQueue.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace AutomationTool +{ + /// + /// Allows queuing a large number of tasks to a thread pool and waiting for them all to complete. + /// + public class ThreadPoolWorkQueue : IDisposable + { + /// + /// Number of jobs remaining in the queue. This is updated in an atomic way. + /// + int NumOutstandingJobs; + + /// + /// Event which indicates whether the queue is empty. + /// + ManualResetEvent EmptyEvent = new ManualResetEvent(true); + + /// + /// Default constructor + /// + public ThreadPoolWorkQueue() + { + } + + /// + /// Waits for the queue to drain, and disposes of it + /// + public void Dispose() + { + if(EmptyEvent != null) + { + Wait(); + + EmptyEvent.Dispose(); + EmptyEvent = null; + } + } + + /// + /// Returns the number of items remaining in the queue + /// + public int NumRemaining + { + get { return NumOutstandingJobs; } + } + + /// + /// Adds an item to the queue + /// + /// The action to add + public void Enqueue(Action ActionToExecute) + { + if(Interlocked.Increment(ref NumOutstandingJobs) == 1) + { + EmptyEvent.Reset(); + } + ThreadPool.QueueUserWorkItem(Execute, ActionToExecute); + } + + /// + /// Internal method to execute an action + /// + /// The action to execute + void Execute(object ActionToExecute) + { + ((Action)ActionToExecute)(); + if(Interlocked.Decrement(ref NumOutstandingJobs) == 0) + { + EmptyEvent.Set(); + } + } + + /// + /// Waits for all queued tasks to finish + /// + public void Wait() + { + EmptyEvent.WaitOne(); + } + + /// + /// Waits for all queued tasks to finish, or the timeout to elapse + /// + /// Maximum time to wait + /// True if the queue completed, false if the timeout elapsed + public bool Wait(int MillisecondsTimeout) + { + return EmptyEvent.WaitOne(MillisecondsTimeout); + } + } +} diff --git a/Engine/Source/Programs/AutomationTool/AutomationUtils/UE4Build.cs b/Engine/Source/Programs/AutomationTool/AutomationUtils/UE4Build.cs index 1d242ca4e814..7bb742cd5624 100644 --- a/Engine/Source/Programs/AutomationTool/AutomationUtils/UE4Build.cs +++ b/Engine/Source/Programs/AutomationTool/AutomationUtils/UE4Build.cs @@ -49,7 +49,7 @@ namespace AutomationTool public void AddBuildProduct(string InFile) { string File = CommandUtils.CombinePaths(InFile); - if (!CommandUtils.FileExists(File)) + if (!CommandUtils.FileExists(File) && !CommandUtils.DirectoryExists(File)) { throw new AutomationException("BUILD FAILED specified file to AddBuildProduct {0} does not exist.", File); } @@ -102,7 +102,9 @@ namespace AutomationTool static bool IsBuildReceipt(string FileName) { - return FileName.EndsWith(".target", StringComparison.InvariantCultureIgnoreCase) || FileName.EndsWith(".modules", StringComparison.InvariantCultureIgnoreCase); + return FileName.EndsWith(".target", StringComparison.InvariantCultureIgnoreCase) + || FileName.EndsWith(".modules", StringComparison.InvariantCultureIgnoreCase) + || FileName.EndsWith("buildid.txt", StringComparison.InvariantCultureIgnoreCase); } void AddBuildProductsFromManifest(string ManifestName) @@ -114,7 +116,7 @@ namespace AutomationTool UnrealBuildTool.BuildManifest Manifest = CommandUtils.ReadManifest(ManifestName); foreach (string Item in Manifest.BuildProducts) { - if (!CommandUtils.FileExists_NoExceptions(Item)) + if (!CommandUtils.FileExists_NoExceptions(Item) && !CommandUtils.DirectoryExists_NoExceptions(Item)) { throw new AutomationException("BUILD FAILED {0} was in manifest but was not produced.", Item); } @@ -466,10 +468,10 @@ namespace AutomationTool /// /// Updates the engine version files /// - public List UpdateVersionFiles(bool ActuallyUpdateVersionFiles = true, int? ChangelistNumberOverride = null, int? CompatibleChangelistNumberOverride = null, string Build = null) + public List UpdateVersionFiles(bool ActuallyUpdateVersionFiles = true, int? ChangelistNumberOverride = null, int? CompatibleChangelistNumberOverride = null, string Build = null, bool? IsPromotedOverride = null) { bool bIsLicenseeVersion = ParseParam("Licensee"); - bool bIsPromotedBuild = (ParseParamInt("Promoted", 1) != 0); + bool bIsPromotedBuild = IsPromotedOverride.HasValue? IsPromotedOverride.Value : (ParseParamInt("Promoted", 1) != 0); bool bDoUpdateVersionFiles = CommandUtils.P4Enabled && ActuallyUpdateVersionFiles; int ChangelistNumber = 0; if (bDoUpdateVersionFiles) @@ -482,7 +484,12 @@ namespace AutomationTool CompatibleChangelistNumber = CompatibleChangelistNumberOverride.Value; } - string Branch = CommandUtils.P4Enabled ? CommandUtils.P4Env.BuildRootEscaped : ""; + string Branch = OwnerCommand.ParseParamValue("Branch"); + if (String.IsNullOrEmpty(Branch)) + { + Branch = CommandUtils.P4Enabled ? CommandUtils.P4Env.BuildRootEscaped : ""; + } + return StaticUpdateVersionFiles(ChangelistNumber, CompatibleChangelistNumber, Branch, Build, bIsLicenseeVersion, bIsPromotedBuild, bDoUpdateVersionFiles); } @@ -1444,6 +1451,18 @@ namespace AutomationTool { Args += " /StopOnErrors"; } + + // A bug in the UCRT can cause XGE to hang on VS2015 builds. Figure out if this hang is likely to effect this build and workaround it if able. + string XGEVersion = Microsoft.Win32.Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Xoreax\IncrediBuild\Builder", "Version", null) as string; + if (XGEVersion != null) + { + // Per Xoreax support, subtract 1001000 from the registry value to get the build number of the installed XGE. + int XGEBuildNumber; + if (Int32.TryParse(XGEVersion, out XGEBuildNumber) && XGEBuildNumber - 1001000 >= 1659) + { + Args += " /no_watchdog_thread"; + } + } } if (!bCanUseParallelExecutor && String.IsNullOrEmpty(XGETool)) @@ -1509,7 +1528,7 @@ namespace AutomationTool { foreach (var Product in BuildProductFiles) { - if (!CommandUtils.FileExists(Product)) + if (!CommandUtils.FileExists(Product) && !CommandUtils.DirectoryExists(Product)) { throw new AutomationException("BUILD FAILED {0} was a build product but no longer exists", Product); } diff --git a/Engine/Source/Programs/AutomationTool/AutomationUtils/Utils.cs b/Engine/Source/Programs/AutomationTool/AutomationUtils/Utils.cs index f9bd1006f4f1..af41583402f2 100644 --- a/Engine/Source/Programs/AutomationTool/AutomationUtils/Utils.cs +++ b/Engine/Source/Programs/AutomationTool/AutomationUtils/Utils.cs @@ -284,6 +284,10 @@ namespace AutomationTool { "KeyStorePassword", "KeyPassword", + "rsa.privateexp", + "rsa.modulus", + "rsa.publicexp", + "aes.key", }; private static void FilterIniFile(string SourceName, string TargetName) diff --git a/Engine/Source/Programs/AutomationTool/BuildGraph/Script.cs b/Engine/Source/Programs/AutomationTool/BuildGraph/Script.cs index e3732044cfa0..5762a341e4fc 100644 --- a/Engine/Source/Programs/AutomationTool/BuildGraph/Script.cs +++ b/Engine/Source/Programs/AutomationTool/BuildGraph/Script.cs @@ -798,7 +798,6 @@ namespace AutomationTool foreach (Node ReferencedNode in ResolveReferences(Element, RequiredNames)) { NewBadge.Nodes.Add(ReferencedNode); - NewBadge.Nodes.UnionWith(ReferencedNode.OrderDependencies); } Graph.Badges.Add(NewBadge); } diff --git a/Engine/Source/Programs/AutomationTool/BuildGraph/Tasks/CommandTask.cs b/Engine/Source/Programs/AutomationTool/BuildGraph/Tasks/CommandTask.cs index 95f72b665cb7..a16c87ed3353 100644 --- a/Engine/Source/Programs/AutomationTool/BuildGraph/Tasks/CommandTask.cs +++ b/Engine/Source/Programs/AutomationTool/BuildGraph/Tasks/CommandTask.cs @@ -102,7 +102,7 @@ namespace BuildGraph.Tasks } try { - CommandUtils.RunUAT(CommandUtils.CmdEnv, CommandLine.ToString()); + CommandUtils.RunUAT(CommandUtils.CmdEnv, CommandLine.ToString(), Identifier: Parameters.Name); } catch (CommandUtils.CommandFailedException) { diff --git a/Engine/Source/Programs/AutomationTool/BuildGraph/Tasks/CompileTask.cs b/Engine/Source/Programs/AutomationTool/BuildGraph/Tasks/CompileTask.cs index b6717eb13731..047bafe01de5 100644 --- a/Engine/Source/Programs/AutomationTool/BuildGraph/Tasks/CompileTask.cs +++ b/Engine/Source/Programs/AutomationTool/BuildGraph/Tasks/CompileTask.cs @@ -40,6 +40,18 @@ namespace AutomationTool [TaskParameter(Optional = true)] public string Arguments; + /// + /// Whether to allow using XGE for compilation + /// + [TaskParameter(Optional = true)] + public bool AllowXGE = true; + + /// + /// Whether to allow using the parallel executor for this compile + /// + [TaskParameter(Optional = true)] + public bool AllowParallelExecutor = true; + /// /// Tag to be applied to build products of this task /// @@ -62,6 +74,16 @@ namespace AutomationTool /// Dictionary TargetToTagName = new Dictionary(); + /// + /// Whether to allow using XGE for this job + /// + bool bAllowXGE = true; + + /// + /// Whether to allow using the parallel executor for this job + /// + bool bAllowParallelExecutor = true; + /// /// Constructor /// @@ -84,7 +106,21 @@ namespace AutomationTool return false; } + if(Targets.Count > 0) + { + if (bAllowXGE != CompileTask.Parameters.AllowXGE) + { + return false; + } + if (!bAllowParallelExecutor || !CompileTask.Parameters.AllowParallelExecutor) + { + return false; + } + } + CompileTaskParameters Parameters = CompileTask.Parameters; + bAllowXGE &= Parameters.AllowXGE; + bAllowParallelExecutor &= Parameters.AllowParallelExecutor; UE4Build.BuildTarget Target = new UE4Build.BuildTarget { TargetName = Parameters.Target, Platform = Parameters.Platform, Config = Parameters.Configuration, UBTArgs = "-nobuilduht " + (Parameters.Arguments ?? "") }; if(!String.IsNullOrEmpty(Parameters.Tag)) @@ -114,8 +150,8 @@ namespace AutomationTool UE4Build Builder = new UE4Build(Job.OwnerCommand); try { - bool bCanUseParallelExecutor = (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Win64); // parallel executor is only available on Windows as of 2016-09-22 - Builder.Build(Agenda, InDeleteBuildProducts: null, InUpdateVersionFiles: false, InForceNoXGE: false, InUseParallelExecutor: bCanUseParallelExecutor, InTargetToManifest: TargetToManifest); + bool bCanUseParallelExecutor = (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Win64 && bAllowParallelExecutor); // parallel executor is only available on Windows as of 2016-09-22 + Builder.Build(Agenda, InDeleteBuildProducts: null, InUpdateVersionFiles: false, InForceNoXGE: !bAllowXGE, InUseParallelExecutor: bCanUseParallelExecutor, InTargetToManifest: TargetToManifest); } catch (CommandUtils.CommandFailedException) { diff --git a/Engine/Source/Programs/AutomationTool/BuildGraph/Tasks/StageTask.cs b/Engine/Source/Programs/AutomationTool/BuildGraph/Tasks/StageTask.cs index 01421c6d1705..4fb74e8e3387 100644 --- a/Engine/Source/Programs/AutomationTool/BuildGraph/Tasks/StageTask.cs +++ b/Engine/Source/Programs/AutomationTool/BuildGraph/Tasks/StageTask.cs @@ -116,28 +116,25 @@ namespace BuildGraph.Tasks DirectoryReference TargetProjectDir = DirectoryReference.Combine(TargetDir, ProjectFile.GetFileNameWithoutExtension()); // Get the path to the receipt - string ReceiptFileName = TargetReceipt.GetDefaultPath(SourceProjectDir.FullName, Parameters.Target, Parameters.Platform, Parameters.Configuration, Parameters.Architecture); + FileReference ReceiptFileName = TargetReceipt.GetDefaultPath(SourceProjectDir, Parameters.Target, Parameters.Platform, Parameters.Configuration, Parameters.Architecture); // Try to load it TargetReceipt Receipt; - if(!TargetReceipt.TryRead(ReceiptFileName, out Receipt)) + if(!TargetReceipt.TryRead(ReceiptFileName, SourceEngineDir, SourceProjectDir, out Receipt)) { CommandUtils.LogError("Couldn't read receipt '{0}'", ReceiptFileName); return false; } - // Expand all the paths from the receipt - Receipt.ExpandPathVariables(SourceEngineDir, SourceProjectDir); - // Stage all the build products needed at runtime HashSet SourceFiles = new HashSet(); foreach(BuildProduct BuildProduct in Receipt.BuildProducts.Where(x => x.Type != BuildProductType.StaticLibrary && x.Type != BuildProductType.ImportLibrary)) { - SourceFiles.Add(new FileReference(BuildProduct.Path)); + SourceFiles.Add(BuildProduct.Path); } foreach(RuntimeDependency RuntimeDependency in Receipt.RuntimeDependencies.Where(x => x.Type != StagedFileType.UFS)) { - SourceFiles.UnionWith(CommandUtils.ResolveFilespec(CommandUtils.RootDirectory, RuntimeDependency.Path, new string[]{ ".../*.umap", ".../*.uasset" })); + SourceFiles.Add(RuntimeDependency.Path); } // Get all the target files diff --git a/Engine/Source/Programs/AutomationTool/BuildGraph/Tasks/TagReceiptTask.cs b/Engine/Source/Programs/AutomationTool/BuildGraph/Tasks/TagReceiptTask.cs index c8277460ee90..641f06809844 100644 --- a/Engine/Source/Programs/AutomationTool/BuildGraph/Tasks/TagReceiptTask.cs +++ b/Engine/Source/Programs/AutomationTool/BuildGraph/Tasks/TagReceiptTask.cs @@ -136,7 +136,6 @@ namespace AutomationTool.Tasks // Resolve the input list IEnumerable TargetFiles = ResolveFilespec(CommandUtils.RootDirectory, Parameters.Files, TagNameToFileSet); HashSet Files = new HashSet(); - HashSet WildcardDependencies = new HashSet(); foreach (FileReference TargetFile in TargetFiles) { @@ -149,22 +148,19 @@ namespace AutomationTool.Tasks // Read the receipt TargetReceipt Receipt; - if (!TargetReceipt.TryRead(TargetFile.FullName, out Receipt)) + if (!TargetReceipt.TryRead(TargetFile, EngineDir, ProjectDir, out Receipt)) { CommandUtils.LogWarning("Unable to load file using TagReceipt task ({0})", TargetFile.FullName); continue; } - // Convert the paths to absolute - Receipt.ExpandPathVariables(EngineDir, ProjectDir); - if (Parameters.BuildProducts) { foreach (BuildProduct BuildProduct in Receipt.BuildProducts) { if (String.IsNullOrEmpty(Parameters.BuildProductType) || BuildProduct.Type == BuildProductType) { - Files.Add(new FileReference(BuildProduct.Path)); + Files.Add(BuildProduct.Path); } } } @@ -175,24 +171,15 @@ namespace AutomationTool.Tasks { if (String.IsNullOrEmpty(Parameters.StagedFileType) || RuntimeDependency.Type == StagedFileType) { - // If it doesn't contain any wildcards, just add the pattern directly - if (FileFilter.FindWildcardIndex(RuntimeDependency.Path) == -1) + // Only add files that exist as dependencies are assumed to always exist + FileReference DependencyPath = RuntimeDependency.Path; + if (FileReference.Exists(DependencyPath)) { - // Only add files that exist as dependencies are assumed to always exist - FileReference DependencyPath = new FileReference(RuntimeDependency.Path); - if (FileReference.Exists(DependencyPath)) - { - Files.Add(DependencyPath); - } - else - { - // Give a warning about files that don't exist so that we can clean up build.cs files - CommandUtils.LogWarning("File listed as RuntimeDependency in {0} does not exist ({1})", TargetFile.FullName, DependencyPath.FullName); - } + Files.Add(DependencyPath); } else { - WildcardDependencies.Add(RuntimeDependency.Path); + CommandUtils.LogWarning("File listed as RuntimeDependency in {0} does not exist ({1})", TargetFile.FullName, DependencyPath.FullName); } } } @@ -200,60 +187,39 @@ namespace AutomationTool.Tasks if (Parameters.PrecompiledBuildDependencies) { - foreach(string PrecompiledBuildDependency in Receipt.PrecompiledBuildDependencies) + foreach(FileReference PrecompiledBuildDependency in Receipt.PrecompiledBuildDependencies) { - // If it doesn't contain any wildcards, just add the pattern directly - if (FileFilter.FindWildcardIndex(PrecompiledBuildDependency) == -1) + // Only add files that exist as dependencies are assumed to always exist + FileReference DependencyPath = PrecompiledBuildDependency; + if (FileReference.Exists(DependencyPath)) { - // Only add files that exist as dependencies are assumed to always exist - FileReference DependencyPath = new FileReference(PrecompiledBuildDependency); - if (FileReference.Exists(DependencyPath)) - { - Files.Add(DependencyPath); - } - else - { - // Give a warning about files that don't exist so that we can clean up build.cs files - CommandUtils.LogWarning("File listed as PrecompiledBuildDependency in {0} does not exist ({1})", TargetFile.FullName, DependencyPath.FullName); - } + Files.Add(DependencyPath); } else { - WildcardDependencies.Add(PrecompiledBuildDependency); + CommandUtils.LogWarning("File listed as PrecompiledBuildDependency in {0} does not exist ({1})", TargetFile.FullName, DependencyPath.FullName); } } } if (Parameters.PrecompiledRuntimeDependencies) { - foreach (string PrecompiledRuntimeDependency in Receipt.PrecompiledRuntimeDependencies) + foreach (FileReference PrecompiledRuntimeDependency in Receipt.PrecompiledRuntimeDependencies) { - // If it doesn't contain any wildcards, just add the pattern directly - if (FileFilter.FindWildcardIndex(PrecompiledRuntimeDependency) == -1) + // Only add files that exist as dependencies are assumed to always exist + FileReference DependencyPath = PrecompiledRuntimeDependency; + if (FileReference.Exists(DependencyPath)) { - // Only add files that exist as dependencies are assumed to always exist - FileReference DependencyPath = new FileReference(PrecompiledRuntimeDependency); - if (FileReference.Exists(DependencyPath)) - { - Files.Add(DependencyPath); - } - else - { - // Give a warning about files that don't exist so that we can clean up build.cs files - CommandUtils.LogWarning("File listed as PrecompiledRuntimeDependency in {0} does not exist ({1})", TargetFile.FullName, DependencyPath.FullName); - } + Files.Add(DependencyPath); } else { - WildcardDependencies.Add(PrecompiledRuntimeDependency); + CommandUtils.LogWarning("File listed as PrecompiledRuntimeDependency in {0} does not exist ({1})", TargetFile.FullName, DependencyPath.FullName); } } } } - // Turn any wildcards into a file list - Files.UnionWith(ResolveFilespecWithExcludePatterns(CommandUtils.RootDirectory, WildcardDependencies.ToList(), new List(), TagNameToFileSet)); - // Apply the tag to all the matching files FindOrAddTagSet(TagNameToFileSet, Parameters.With).UnionWith(Files); diff --git a/Engine/Source/Programs/AutomationTool/HTML5/HTML5Platform.Automation.cs b/Engine/Source/Programs/AutomationTool/HTML5/HTML5Platform.Automation.cs index 7703db908f1c..352c1de491a8 100644 --- a/Engine/Source/Programs/AutomationTool/HTML5/HTML5Platform.Automation.cs +++ b/Engine/Source/Programs/AutomationTool/HTML5/HTML5Platform.Automation.cs @@ -15,7 +15,9 @@ public class HTML5Platform : Platform { // ini configurations static bool Compressed = false; - static bool targetingWasm = true; // THIS WILL BE default WHEN wasm BECOME STANDARD !!! + static bool targetingWasm = true; + static bool targetWebGL2 = true; + static bool enableIndexedDB = false; // experimental for now... public HTML5Platform() : base(UnrealTargetPlatform.HTML5) @@ -38,14 +40,32 @@ public class HTML5Platform : Platform // ini configurations var ConfigCache = UnrealBuildTool.ConfigCache.ReadHierarchy(ConfigHierarchyType.Engine, DirectoryReference.FromFile(Params.RawProjectPath), UnrealTargetPlatform.HTML5); - ConfigCache.GetBool("/Script/HTML5PlatformEditor.HTML5TargetSettings", "TargetWasm", out targetingWasm); + bool targetingAsmjs = false; // inverted checked - this will be going away soon... + bool targetWebGL1 = false; // inverted checked - this will be going away soon... + if ( ConfigCache.GetBool("/Script/HTML5PlatformEditor.HTML5TargetSettings", "TargetAsmjs", out targetingAsmjs) ) + { + targetingWasm = !targetingAsmjs; + } + if ( ConfigCache.GetBool("/Script/HTML5PlatformEditor.HTML5TargetSettings", "TargetWebGL1", out targetWebGL1) ) + { + targetWebGL2 = !targetWebGL1; + } - // Debug and Development builds are not uncompressed to speed up iteration times. - // Shipping builds "can be" compressed, + // Debug and Development builds are not uncompressed to: + // - speed up iteration times + // - ensure (IndexedDB) data are not cached/used + // Shipping builds "can be": + // - compressed + // - (IndexedDB) cached if (Params.ClientConfigsToBuild[0].ToString() == "Shipping") { ConfigCache.GetBool("/Script/HTML5PlatformEditor.HTML5TargetSettings", "Compressed", out Compressed); + ConfigCache.GetBool("/Script/HTML5PlatformEditor.HTML5TargetSettings", "EnableIndexedDB", out enableIndexedDB); } + Log("HTML5Platform.Automation: TargetWasm = " + targetingWasm ); + Log("HTML5Platform.Automation: TargetWebGL2 = " + targetWebGL2 ); + Log("HTML5Platform.Automation: Compressed = " + Compressed ); + Log("HTML5Platform.Automation: EnableIndexedDB = " + enableIndexedDB ); string FinalDataLocation = Path.Combine(PackagePath, Params.ShortProjectName) + ".data"; @@ -110,6 +130,8 @@ public class HTML5Platform : Platform string GameExe = GameBasename + ".js"; string FullGameExePath = Path.Combine(GameBasepath, GameExe); string FullPackageGameExePath = Path.Combine(PackagePath, GameExe); + // special case -- this will be removed when asm.js has been deprecated + string ASMJS_FullPackageGameExePath = Path.Combine(PackagePath, GameBasename + "_asm.js"); // ensure the ue4game binary exists, if applicable @@ -119,29 +141,33 @@ public class HTML5Platform : Platform throw new AutomationException(ExitCode.Error_MissingExecutable, "Stage Failed. Could not find application {0}. You may need to build the UE4 project with your target configuration and platform.", FullGameExePath); } - if (FullGameExePath != FullPackageGameExePath) + if (FullGameExePath != FullPackageGameExePath) // TODO: remove this check { - File.Copy(FullGameExePath, FullPackageGameExePath, true); File.Copy(FullGameExePath + ".symbols", FullPackageGameExePath + ".symbols", true); if (targetingWasm) { File.Copy(FullGameBasePath + ".wasm", FullPackageGameBasePath + ".wasm", true); + File.Copy(FullGameExePath, FullPackageGameExePath, true); } else { File.Copy(FullGameExePath + ".mem", FullPackageGameExePath + ".mem", true); + File.Copy(FullGameBasePath + ".asm.js", FullPackageGameBasePath + ".asm.js", true); } } - File.SetAttributes(FullPackageGameExePath, FileAttributes.Normal); File.SetAttributes(FullPackageGameExePath + ".symbols", FileAttributes.Normal); if (targetingWasm) { File.SetAttributes(FullPackageGameBasePath + ".wasm", FileAttributes.Normal); + File.SetAttributes(FullPackageGameExePath, FileAttributes.Normal); } else { File.SetAttributes(FullPackageGameExePath + ".mem", FileAttributes.Normal); + File.SetAttributes(FullPackageGameBasePath + ".asm.js", FileAttributes.Normal); + File.Copy(FullGameExePath, ASMJS_FullPackageGameExePath, true); // --separate-asm // UE-45058 + File.SetAttributes(ASMJS_FullPackageGameExePath, FileAttributes.Normal); } @@ -206,17 +232,21 @@ public class HTML5Platform : Platform // data file .js driver. CompressionTasks.Add(Task.Factory.StartNew(() => CompressFile(FinalDataLocation + ".js" , FinalDataLocation + ".jsgz"))); - // main js. - CompressionTasks.Add(Task.Factory.StartNew(() => CompressFile(FullPackageGameExePath, FullPackageGameExePath + "gz"))); if (targetingWasm) { // main game code CompressionTasks.Add(Task.Factory.StartNew(() => CompressFile(FullPackageGameBasePath + ".wasm", FullPackageGameBasePath + ".wasmgz"))); + // main js. + CompressionTasks.Add(Task.Factory.StartNew(() => CompressFile(FullPackageGameExePath, FullPackageGameExePath + "gz"))); } else { // mem init file. CompressionTasks.Add(Task.Factory.StartNew(() => CompressFile(FullPackageGameExePath + ".mem", FullPackageGameExePath + ".memgz"))); + // main js. + CompressionTasks.Add(Task.Factory.StartNew(() => CompressFile(FullPackageGameBasePath + ".asm.js", FullPackageGameBasePath + ".asm.jsgz"))); + // main game code + CompressionTasks.Add(Task.Factory.StartNew(() => CompressFile(ASMJS_FullPackageGameExePath, ASMJS_FullPackageGameExePath + "gz"))); } // symbols file. @@ -296,6 +326,12 @@ public class HTML5Platform : Platform while (reader.Peek() != -1) { LineStr = reader.ReadLine(); + if (LineStr.Contains("%TIMESTAMP%")) + { + string TimeStamp = DateTime.UtcNow.ToString("yyyyMMddHHmm"); + LineStr = LineStr.Replace("%TIMESTAMP%", TimeStamp); + } + if (LineStr.Contains("%GAME%")) { LineStr = LineStr.Replace("%GAME%", InGameName); @@ -306,6 +342,12 @@ public class HTML5Platform : Platform LineStr = LineStr.Replace("%SERVE_COMPRESSED%", Compressed ? "true" : "false"); } + if (LineStr.Contains("%DISABLE_INDEXEDDB%")) + { + LineStr = LineStr.Replace("%DISABLE_INDEXEDDB%", + enableIndexedDB ? "" : "enableReadFromIndexedDB = false;\nenableWriteToIndexedDB = false;"); + } + if (LineStr.Contains("%HEAPSIZE%")) { LineStr = LineStr.Replace("%HEAPSIZE%", HeapSize.ToString() + " * 1024 * 1024"); @@ -335,6 +377,16 @@ public class HTML5Platform : Platform LineStr = LineStr.Replace("%UE4CMDLINE%", ArgumentString); } + if (!targetingWasm && LineStr.Contains("const explicitlyLoadedAsmJs")) + { + LineStr = "const explicitlyLoadedAsmJs = true;"; + } + + if (!targetWebGL2 && LineStr.Contains("const explicitlyUseWebGL1")) + { + LineStr = "const explicitlyUseWebGL1 = true;"; + } + outputContents.AppendLine(LineStr); } } @@ -434,17 +486,21 @@ public class HTML5Platform : Platform SC.ArchiveFiles(PackagePath, ProjectDataName); // data file js driver SC.ArchiveFiles(PackagePath, ProjectDataName + ".js"); - // main js file - SC.ArchiveFiles(PackagePath, GameExe); if (targetingWasm) { // main game code SC.ArchiveFiles(PackagePath, GameBasename + ".wasm"); + // main js file + SC.ArchiveFiles(PackagePath, GameExe); } else { // memory init file SC.ArchiveFiles(PackagePath, GameExe + ".mem"); + // maingame code + SC.ArchiveFiles(PackagePath, GameBasename + ".asm.js"); + // main js file + SC.ArchiveFiles(PackagePath, GameBasename + "_asm.js"); } // symbols file SC.ArchiveFiles(PackagePath, GameExe + ".symbols"); @@ -471,6 +527,7 @@ public class HTML5Platform : Platform else { SC.ArchiveFiles(PackagePath, GameExe + ".memgz"); + SC.ArchiveFiles(PackagePath, GameExe + ".asm.jsgz"); } SC.ArchiveFiles(PackagePath, GameExe + ".symbolsgz"); SC.ArchiveFiles(PackagePath, "Utility.jsgz"); @@ -536,11 +593,25 @@ public class HTML5Platform : Platform if (LowerBrowserPath.Contains("chrome")) { - BrowserCommandline += " " + String.Format("--user-data-dir=\\\"{0}\\\" --enable-logging --no-first-run", Path.Combine(ProfileDirectory, "chrome")); + ProfileDirectory = Path.Combine(ProfileDirectory, "chrome"); + // removing [--enable-logging] otherwise, chrome breaks with a bunch of the following errors: + // > ERROR:process_info.cc(631)] range at 0x7848406c00000000, size 0x1a4 fully unreadable + // leaving this note here for future reference: UE-45078 + BrowserCommandline += " " + String.Format("--user-data-dir=\\\"{0}\\\" --no-first-run", ProfileDirectory); } else if (LowerBrowserPath.Contains("firefox")) { - BrowserCommandline += " " + String.Format("-no-remote -profile \\\"{0}\\\"", Path.Combine(ProfileDirectory, "firefox")); + ProfileDirectory = Path.Combine(ProfileDirectory, "firefox"); + BrowserCommandline += " " + String.Format("-no-remote -profile \\\"{0}\\\"", ProfileDirectory); + } + + if (UnrealBuildTool.BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Linux) + { + // TODO: test on other platforms to remove this if() check + if (!Directory.Exists(ProfileDirectory)) + { + Directory.CreateDirectory(ProfileDirectory); + } } string LauncherArguments = string.Format(" -Browser=\"{0}\" + -BrowserCommandLine=\"{1}\" -ServerPort=\"{2}\" -ServerRoot=\"{3}\" ", @@ -562,11 +633,6 @@ public class HTML5Platform : Platform return HTMLPakAutomation.CanCreateMapPaks(Params) ? " -GenerateDependenciesForMaps " : ""; } - public override bool DeployPakInternalLowerCaseFilenames() - { - return false; - } - public override PakType RequiresPak(ProjectParams Params) { return HTMLPakAutomation.CanCreateMapPaks(Params) ? PakType.Never : PakType.Always; @@ -599,10 +665,10 @@ public class HTML5Platform : Platform { } - public override List GetExecutableNames(DeploymentContext SC, bool bIsRun = false) + public override List GetExecutableNames(DeploymentContext SC) { - var ExecutableNames = new List(); - ExecutableNames.Add(Path.Combine(SC.ProjectRoot, "Binaries", "HTML5", SC.ShortProjectName)); + List ExecutableNames = new List(); + ExecutableNames.Add(FileReference.Combine(SC.ProjectRoot, "Binaries", "HTML5", SC.ShortProjectName)); return ExecutableNames; } #endregion diff --git a/Engine/Source/Programs/AutomationTool/HTML5/HTML5Platform.PakFiles.Automation.cs b/Engine/Source/Programs/AutomationTool/HTML5/HTML5Platform.PakFiles.Automation.cs index 573f6766cc42..dc63c9ecc258 100644 --- a/Engine/Source/Programs/AutomationTool/HTML5/HTML5Platform.PakFiles.Automation.cs +++ b/Engine/Source/Programs/AutomationTool/HTML5/HTML5Platform.PakFiles.Automation.cs @@ -37,7 +37,7 @@ public class HTMLPakAutomation Params = InParam; SC = InSC; - var PakOrderFileLocationBase = CommandUtils.CombinePaths(SC.ProjectRoot, "Build", SC.FinalCookPlatform, "FileOpenOrder"); + var PakOrderFileLocationBase = CommandUtils.CombinePaths(SC.ProjectRoot.FullName, "Build", SC.FinalCookPlatform, "FileOpenOrder"); PakOrderFileLocation = CommandUtils.CombinePaths(PakOrderFileLocationBase, "GameOpenOrder.log"); if (!CommandUtils.FileExists_NoExceptions(PakOrderFileLocation)) { @@ -52,7 +52,7 @@ public class HTMLPakAutomation } // read in the json file. - string JsonFile = CommandUtils.CombinePaths(new string[] { SC.ProjectRoot, "Saved", "Cooked", "HTML5", Params.ShortProjectName, "MapDependencyGraph.json" }); + string JsonFile = CommandUtils.CombinePaths(new string[] { SC.ProjectRoot.FullName, "Saved", "Cooked", "HTML5", Params.ShortProjectName, "MapDependencyGraph.json" }); string text = File.ReadAllText(JsonFile); DependencyJson = fastJSON.JSON.Instance.ToObject>(text); diff --git a/Engine/Source/Programs/AutomationTool/IOS/IOSPlatform.Automation.cs b/Engine/Source/Programs/AutomationTool/IOS/IOSPlatform.Automation.cs index 6cc1d4ce7d91..1cfa66e764f7 100644 --- a/Engine/Source/Programs/AutomationTool/IOS/IOSPlatform.Automation.cs +++ b/Engine/Source/Programs/AutomationTool/IOS/IOSPlatform.Automation.cs @@ -224,7 +224,7 @@ public class IOSPlatform : Platform return 4; } - public virtual bool PrepForUATPackageOrDeploy(UnrealTargetConfiguration Config, FileReference ProjectFile, string InProjectName, string InProjectDirectory, string InExecutablePath, string InEngineDir, bool bForDistribution, string CookFlavor, bool bIsDataDeploy, bool bCreateStubIPA) + public virtual bool PrepForUATPackageOrDeploy(UnrealTargetConfiguration Config, FileReference ProjectFile, string InProjectName, DirectoryReference InProjectDirectory, string InExecutablePath, DirectoryReference InEngineDir, bool bForDistribution, string CookFlavor, bool bIsDataDeploy, bool bCreateStubIPA) { return IOSExports.PrepForUATPackageOrDeploy(Config, ProjectFile, InProjectName, InProjectDirectory, InExecutablePath, InEngineDir, bForDistribution, CookFlavor, bIsDataDeploy, bCreateStubIPA); } @@ -234,9 +234,9 @@ public class IOSPlatform : Platform IOSExports.GetProvisioningData(InProject, bDistribution, out MobileProvision, out SigningCertificate, out TeamUUID, out bAutomaticSigning); } - public virtual bool DeployGeneratePList(FileReference ProjectFile, UnrealTargetConfiguration Config, string ProjectDirectory, bool bIsUE4Game, string GameName, string ProjectName, string InEngineDir, string AppDirectory) + public virtual bool DeployGeneratePList(FileReference ProjectFile, UnrealTargetConfiguration Config, DirectoryReference ProjectDirectory, bool bIsUE4Game, string GameName, string ProjectName, DirectoryReference InEngineDir, DirectoryReference AppDirectory, out bool bSupportsPortrait, out bool bSupportsLandscape) { - return IOSExports.GeneratePList(ProjectFile, Config, ProjectDirectory, bIsUE4Game, GameName, ProjectName, InEngineDir, AppDirectory); + return IOSExports.GeneratePList(ProjectFile, Config, ProjectDirectory, bIsUE4Game, GameName, ProjectName, InEngineDir, AppDirectory, out bSupportsPortrait, out bSupportsLandscape); } protected string MakeIPAFileName( UnrealTargetConfiguration TargetConfiguration, ProjectParams Params ) @@ -327,9 +327,9 @@ public class IOSPlatform : Platform // copy in all of the artwork and plist PrepForUATPackageOrDeploy(TargetConfiguration, Params.RawProjectPath, Params.ShortProjectName, - Path.GetDirectoryName(Params.RawProjectPath.FullName), + Params.RawProjectPath.Directory, CombinePaths(Path.GetDirectoryName(Params.ProjectGameExeFilename), SC.StageExecutables[0]), - CombinePaths(SC.LocalRoot, "Engine"), + DirectoryReference.Combine(SC.LocalRoot, "Engine"), Params.Distribution, "", false, @@ -347,10 +347,10 @@ public class IOSPlatform : Platform if (!Params.IterativeDeploy) { // copy the Staged files to the AppDirectory - string[] StagedFiles = Directory.GetFiles (SC.StageDirectory, "*", SearchOption.AllDirectories); + string[] StagedFiles = Directory.GetFiles (SC.StageDirectory.FullName, "*", SearchOption.AllDirectories); foreach (string Filename in StagedFiles) { - string DestFilename = Filename.Replace (SC.StageDirectory, AppDirectory); + string DestFilename = Filename.Replace (SC.StageDirectory.FullName, AppDirectory); Directory.CreateDirectory (Path.GetDirectoryName (DestFilename)); InternalUtils.SafeCopyFile (Filename, DestFilename, true); } @@ -358,10 +358,10 @@ public class IOSPlatform : Platform else { // copy just the root stage directory files - string[] StagedFiles = Directory.GetFiles (SC.StageDirectory, "*", SearchOption.TopDirectoryOnly); + string[] StagedFiles = Directory.GetFiles (SC.StageDirectory.FullName, "*", SearchOption.TopDirectoryOnly); foreach (string Filename in StagedFiles) { - string DestFilename = Filename.Replace (SC.StageDirectory, AppDirectory); + string DestFilename = Filename.Replace (SC.StageDirectory.FullName, AppDirectory); Directory.CreateDirectory (Path.GetDirectoryName (DestFilename)); InternalUtils.SafeCopyFile (Filename, DestFilename, true); } @@ -578,7 +578,7 @@ public class IOSPlatform : Platform bCreatedIPA = true; // code sign the app - CodeSign(Path.GetDirectoryName(Params.ProjectGameExeFilename), Params.IsCodeBasedProject ? Params.ShortProjectName : Path.GetFileNameWithoutExtension(Params.ProjectGameExeFilename), Params.RawProjectPath, SC.StageTargetConfigurations[0], SC.LocalRoot, Params.ShortProjectName, Path.GetDirectoryName(Params.RawProjectPath.FullName), SC.IsCodeBasedProject, Params.Distribution, Params.Provision, Params.Certificate, Params.Team, Params.AutomaticSigning, SchemeName, SchemeConfiguration); + CodeSign(Path.GetDirectoryName(Params.ProjectGameExeFilename), Params.IsCodeBasedProject ? Params.ShortProjectName : Path.GetFileNameWithoutExtension(Params.ProjectGameExeFilename), Params.RawProjectPath, SC.StageTargetConfigurations[0], SC.LocalRoot.FullName, Params.ShortProjectName, Path.GetDirectoryName(Params.RawProjectPath.FullName), SC.IsCodeBasedProject, Params.Distribution, Params.Provision, Params.Certificate, Params.Team, Params.AutomaticSigning, SchemeName, SchemeConfiguration); // now generate the ipa PackageIPA(Path.GetDirectoryName(Params.ProjectGameExeFilename), Params.IsCodeBasedProject ? Params.ShortProjectName : Path.GetFileNameWithoutExtension(Params.ProjectGameExeFilename), Params.ShortProjectName, Path.GetDirectoryName(Params.RawProjectPath.FullName), SC.StageTargetConfigurations[0], Params.Distribution); @@ -823,39 +823,29 @@ public class IOSPlatform : Platform { // if (UnrealBuildTool.BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac) { - // copy the icons/launch screens from the engine - { - string SourcePath = CombinePaths(SC.LocalRoot, "Engine", "Build", "IOS", "Resources", "Graphics"); - SC.StageFiles(StagedFileType.NonUFS, SourcePath, "*.png", false, null, "", true, false); - } // copy any additional framework assets that will be needed at runtime { - string SourcePath = CombinePaths( ( SC.IsCodeBasedProject ? SC.ProjectRoot : SC.LocalRoot + "\\Engine" ), "Intermediate", "IOS", "FrameworkAssets" ); - if ( Directory.Exists( SourcePath ) ) + DirectoryReference SourcePath = DirectoryReference.Combine((SC.IsCodeBasedProject ? SC.ProjectRoot : DirectoryReference.Combine(SC.LocalRoot, "Engine")), "Intermediate", "IOS", "FrameworkAssets"); + if ( Directory.Exists( SourcePath.FullName ) ) { - SC.StageFiles( StagedFileType.NonUFS, SourcePath, "*.*", true, null, "", true, false ); + SC.StageFiles( StagedFileType.NonUFS, SourcePath, "*.*", true, null, new StagedDirectoryReference(""), true, false ); } } - // copy the icons/launch screens from the game (may stomp the engine copies) - { - string SourcePath = CombinePaths(SC.ProjectRoot, "Build", "IOS", "Resources", "Graphics"); - SC.StageFiles(StagedFileType.NonUFS, SourcePath, "*.png", false, null, "", true, false); - } // copy the plist (only if code signing, as it's protected by the code sign blob in the executable and can't be modified independently) if (GetCodeSignDesirability(Params)) { - string SourcePath = CombinePaths((SC.IsCodeBasedProject ? SC.ProjectRoot : SC.LocalRoot + "/Engine"), "Intermediate", PlatformName); - string TargetPListFile = Path.Combine(SourcePath, (SC.IsCodeBasedProject ? SC.ShortProjectName : "UE4Game") + "-Info.plist"); + DirectoryReference SourcePath = DirectoryReference.Combine((SC.IsCodeBasedProject ? SC.ProjectRoot : DirectoryReference.Combine(SC.LocalRoot, "Engine")), "Intermediate", PlatformName); + string TargetPListFile = Path.Combine(SourcePath.FullName, (SC.IsCodeBasedProject ? SC.ShortProjectName : "UE4Game") + "-Info.plist"); // if (!File.Exists(TargetPListFile)) { // ensure the plist, entitlements, and provision files are properly copied Console.WriteLine("CookPlat {0}, this {1}", GetCookPlatform(false, false), ToString()); if (!SC.IsCodeBasedProject) { - UnrealBuildTool.PlatformExports.SetRemoteIniPath(SC.ProjectRoot); + UnrealBuildTool.PlatformExports.SetRemoteIniPath(SC.ProjectRoot.FullName); } if (SC.StageTargetConfigurations.Count != 1) @@ -864,23 +854,98 @@ public class IOSPlatform : Platform } var TargetConfiguration = SC.StageTargetConfigurations[0]; + bool bSupportsPortrait = false; + bool bSupportsLandscape = false; DeployGeneratePList( SC.RawProjectPath, TargetConfiguration, - (SC.IsCodeBasedProject ? SC.ProjectRoot : SC.LocalRoot + "/Engine"), + (SC.IsCodeBasedProject ? SC.ProjectRoot : DirectoryReference.Combine(SC.LocalRoot, "Engine")), !SC.IsCodeBasedProject, (SC.IsCodeBasedProject ? SC.ShortProjectName : "UE4Game"), - SC.ShortProjectName, SC.LocalRoot + "/Engine", - (SC.IsCodeBasedProject ? SC.ProjectRoot : SC.LocalRoot + "/Engine") + "/Binaries/" + PlatformName + "/Payload/" + (SC.IsCodeBasedProject ? SC.ShortProjectName : "UE4Game") + ".app"); + SC.ShortProjectName, DirectoryReference.Combine(SC.LocalRoot, "Engine"), + DirectoryReference.Combine((SC.IsCodeBasedProject ? SC.ProjectRoot : DirectoryReference.Combine(SC.LocalRoot, "Engine")), "Binaries", PlatformName, "Payload", (SC.IsCodeBasedProject ? SC.ShortProjectName : "UE4Game") + ".app"), + out bSupportsPortrait, + out bSupportsLandscape); + + // copy the plist to the stage dir + SC.StageFiles(StagedFileType.NonUFS, SourcePath, Path.GetFileName(TargetPListFile), false, null, new StagedDirectoryReference(""), false, false, "Info.plist"); + + // copy the icons/launch screens from the engine + { + DirectoryReference DataPath = DirectoryReference.Combine(SC.LocalRoot, "Engine", "Build", "IOS", "Resources", "Graphics"); + if (bSupportsPortrait) + { + SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default-IPhone6.jpg", false, null, new StagedDirectoryReference(""), true, false); + SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default-IPhone6Plus-Portrait.jpg", false, null, new StagedDirectoryReference(""), true, false); + // SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default-Portrait.jpg", false, null, new StagedDirectoryReference(""), true, false); + SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default-Portrait@2x.jpg", false, null, new StagedDirectoryReference(""), true, false); + // SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default-Portrait-1336.jpg", false, null, new StagedDirectoryReference(""), true, false); + SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default-Portrait-1336@2x.jpg", false, null, new StagedDirectoryReference(""), true, false); + } + if (bSupportsLandscape) + { + SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default-IPhone6-Landscape.jpg", false, null, new StagedDirectoryReference(""), true, false); + SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default-IPhone6Plus-Landscape.jpg", false, null, new StagedDirectoryReference(""), true, false); + // SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default-Landscape.jpg", false, null, new StagedDirectoryReference(""), true, false); + SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default-Landscape@2x.jpg", false, null, new StagedDirectoryReference(""), true, false); + // SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default-Landscape-1336.jpg", false, null, new StagedDirectoryReference(""), true, false); + SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default-Landscape-1336@2x.jpg", false, null, new StagedDirectoryReference(""), true, false); + } + // SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default.jpg", false, null, new StagedDirectoryReference(""), true, false); + SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default@2x.jpg", false, null, new StagedDirectoryReference(""), true, false); + SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default-568h@2x.png", false, null, new StagedDirectoryReference(""), true, false); + SC.StageFiles(StagedFileType.NonUFS, DataPath, "Icon*.png", false, null, new StagedDirectoryReference(""), true, false); + } + + // copy the icons/launch screens from the game (may stomp the engine copies) + { + DirectoryReference DataPath = DirectoryReference.Combine(SC.ProjectRoot, "Build", "IOS", "Resources", "Graphics"); + if (bSupportsPortrait) + { + SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default-IPhone6.jpg", false, null, new StagedDirectoryReference(""), true, false); + SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default-IPhone6Plus-Portrait.jpg", false, null, new StagedDirectoryReference(""), true, false); + // SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default-Portrait.jpg", false, null, new StagedDirectoryReference(""), true, false); + SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default-Portrait@2x.jpg", false, null, new StagedDirectoryReference(""), true, false); + // SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default-Portrait-1336.jpg", false, null, new StagedDirectoryReference(""), true, false); + SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default-Portrait-1336@2x.jpg", false, null, new StagedDirectoryReference(""), true, false); + } + if (bSupportsLandscape) + { + SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default-IPhone6-Landscape.jpg", false, null, new StagedDirectoryReference(""), true, false); + SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default-IPhone6Plus-Landscape.jpg", false, null, new StagedDirectoryReference(""), true, false); + // SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default-Landscape.jpg", false, null, new StagedDirectoryReference(""), true, false); + SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default-Landscape@2x.jpg", false, null, new StagedDirectoryReference(""), true, false); + // SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default-Landscape-1336.jpg", false, null, new StagedDirectoryReference(""), true, false); + SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default-Landscape-1336@2x.jpg", false, null, new StagedDirectoryReference(""), true, false); + } + // SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default.jpg", false, null, new StagedDirectoryReference(""), true, false); + SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default@2x.jpg", false, null, new StagedDirectoryReference(""), true, false); + SC.StageFiles(StagedFileType.NonUFS, DataPath, "Default-568h@2x.png", false, null, new StagedDirectoryReference(""), true, false); + SC.StageFiles(StagedFileType.NonUFS, DataPath, "Icon*.png", false, null, new StagedDirectoryReference(""), true, false); + } } - SC.StageFiles(StagedFileType.NonUFS, SourcePath, Path.GetFileName(TargetPListFile), false, null, "", false, false, "Info.plist"); + // copy the udebugsymbols if they exist + { + ConfigHierarchy PlatformGameConfig; + bool bIncludeSymbols = false; + if (Params.EngineConfigs.TryGetValue(SC.StageTargetPlatform.PlatformType, out PlatformGameConfig)) + { + PlatformGameConfig.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bGenerateCrashReportSymbols", out bIncludeSymbols); + } + if (bIncludeSymbols) + { + DirectoryReference DebugSymbolPath = DirectoryReference.Combine((SC.IsCodeBasedProject ? SC.ProjectRoot : DirectoryReference.Combine(SC.LocalRoot, "Engine")), "Binaries", "IOS"); + string SymbolFileName = SC.StageExecutables[0] + ".udebugsymbols"; + SC.StageFiles(StagedFileType.NonUFS, DebugSymbolPath, SymbolFileName, false, null, new StagedDirectoryReference(""), true, true, (Params.ShortProjectName + ".udebugsymbols").ToLowerInvariant()); + } + } } } { - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.LocalRoot, "Engine/Content/Movies"), "*", true, new string[] { "*.uasset", "*.umap" }, CombinePaths(SC.RelativeProjectRootForStage, "Engine/Content/Movies"), true, true, null, true, true, SC.StageTargetPlatform.DeployLowerCaseFilenames(true)); - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.ProjectRoot, "Content/Movies"), "*", true, new string[] { "*.uasset", "*.umap" }, CombinePaths(SC.RelativeProjectRootForStage, "Content/Movies"), true, true, null, true, true, SC.StageTargetPlatform.DeployLowerCaseFilenames(true)); + SC.StageFiles(StagedFileType.NonUFS, DirectoryReference.Combine(SC.LocalRoot, "Engine", "Content", "Movies"), "*", true, new string[] { "*.uasset", "*.umap" }, StagedDirectoryReference.Combine(SC.RelativeProjectRootForStage, "Engine", "Content", "Movies"), true, true, null, true, true, SC.StageTargetPlatform.DeployLowerCaseFilenames(true)); + SC.StageFiles(StagedFileType.NonUFS, DirectoryReference.Combine(SC.ProjectRoot, "Content", "Movies"), "*", true, new string[] { "*.uasset", "*.umap" }, StagedDirectoryReference.Combine(SC.RelativeProjectRootForStage, "Content", "Movies"), true, true, null, true, true, SC.StageTargetPlatform.DeployLowerCaseFilenames(true)); } } @@ -908,9 +973,13 @@ public class IOSPlatform : Platform if (bXCArchive && Utils.IsRunningOnMono) { - // Always put the archive in the current user's Library/Developer/Xcode/Archives path + // Always put the archive in the current user's Library/Developer/Xcode/Archives path if not on the build machine WindowsIdentity id = WindowsIdentity.GetCurrent(); string ArchivePath = "/Users/" + id.Name + "/Library/Developer/Xcode/Archives"; + if (IsBuildMachine) + { + ArchivePath = Params.ArchiveDirectoryParam; + } if (!DirectoryExists(ArchivePath)) { CreateDirectory(ArchivePath); @@ -942,13 +1011,23 @@ public class IOSPlatform : Platform // copy in the dSYM if found var ProjectExe = MakeExeFileName( TargetConfiguration, Params ); string dSYMName = (SC.IsCodeBasedProject ? Path.GetFileNameWithoutExtension(ProjectExe) : "UE4Game") + ".dSYM"; - string dSYMSrcPath = Path.Combine(SC.ProjectBinariesFolder, dSYMName); + string dSYMDestName = AppName + ".dSYM"; + string dSYMSrcPath = Path.Combine(SC.ProjectBinariesFolder.FullName, dSYMName); + string dSYMZipSrcPath = Path.Combine(SC.ProjectBinariesFolder.FullName, dSYMName + ".zip"); + if (File.Exists(dSYMZipSrcPath)) + { + // unzip the dsym + using (ZipFile Zip = new ZipFile(dSYMZipSrcPath)) + { + Zip.ExtractAll(SC.ProjectBinariesFolder.FullName, ExtractExistingFileAction.OverwriteSilently); + } + } if(DirectoryExists(dSYMSrcPath)) { // Create the dsyms archive folder CreateDirectory(Path.Combine(ArchiveName, "dSYMs")); - string dSYMDstPath = Path.Combine(ArchiveName, "dSYMs", dSYMName); + string dSYMDstPath = Path.Combine(ArchiveName, "dSYMs", dSYMDestName); // /Volumes/MacOSDrive1/pfEpicWorkspace/Dev-Platform/Samples/Sandbox/PlatformShowcase/Binaries/IOS/PlatformShowcase.dSYM/Contents/Resources/DWARF/PlatformShowcase CopyFile_NoExceptions(Path.Combine(dSYMSrcPath, "Contents", "Resources", "DWARF", SC.IsCodeBasedProject ? Path.GetFileNameWithoutExtension(ProjectExe) : "UE4Game"), dSYMDstPath); } @@ -956,12 +1035,12 @@ public class IOSPlatform : Platform { // Create the dsyms archive folder CreateDirectory(Path.Combine(ArchiveName, "dSYMs")); - string dSYMDstPath = Path.Combine(ArchiveName, "dSYMs", dSYMName); + string dSYMDstPath = Path.Combine(ArchiveName, "dSYMs", dSYMDestName); CopyFile_NoExceptions(dSYMSrcPath, dSYMDstPath); } // copy in the bitcode symbol maps if found - string[] bcmapfiles = Directory.GetFiles(SC.ProjectBinariesFolder, "*.bcsymbolmap"); + string[] bcmapfiles = Directory.GetFiles(SC.ProjectBinariesFolder.FullName, "*.bcsymbolmap"); if(bcmapfiles.Length > 0) { // Create the dsyms archive folder @@ -1037,8 +1116,8 @@ public class IOSPlatform : Platform Text.AppendLine(""); Text.AppendLine(""); File.WriteAllText(Path.Combine(ArchiveName, "Info.plist"), Text.ToString()); - } - else if (bXCArchive && !Utils.IsRunningOnMono) + } + else if (bXCArchive && !Utils.IsRunningOnMono) { LogWarning("Can not produce an XCArchive on windows"); } @@ -1170,11 +1249,6 @@ public class IOSPlatform : Platform return "IOS"; } - public override bool DeployPakInternalLowerCaseFilenames() - { - return false; - } - public override bool DeployLowerCaseFilenames(bool bUFSFile) { // we shouldn't modify the case on files like Info.plist or the icons @@ -1198,13 +1272,14 @@ public class IOSPlatform : Platform } } - public override string Remap(string Dest) + public override StagedFileReference Remap(StagedFileReference Dest) { - return "cookeddata/" + Dest; + return new StagedFileReference("cookeddata/" + Dest.Name); } + public override List GetDebugFileExtentions() { - return new List { ".dsym" }; + return new List { ".dsym", ".udebugsymbols" }; } // void MobileDeviceConnected(object sender, ConnectEventArgs args) @@ -1509,7 +1584,7 @@ public class IOSPlatform : Platform P4Change = CommandUtils.P4Env.ChangelistString; P4Branch = CommandUtils.P4Env.BuildRootEscaped; } - string ChunkInstallBasePath = CombinePaths(SC.ProjectRoot, "ChunkInstall", SC.FinalCookPlatform); + string ChunkInstallBasePath = CombinePaths(SC.ProjectRoot.FullName, "ChunkInstall", SC.FinalCookPlatform); string RawDataPath = CombinePaths(ChunkInstallBasePath, P4Branch + "-CL-" + P4Change, PakName); string RawDataPakPath = CombinePaths(RawDataPath, PakName + "-" + SC.FinalCookPlatform + ".pak"); string DestFile = CombinePaths (AssetDir, FileName); @@ -1517,10 +1592,10 @@ public class IOSPlatform : Platform } // generate the AssetPackManifest.plist - GenerateAssetPackManifestPlist (ChunkData, SC.StageDirectory); + GenerateAssetPackManifestPlist (ChunkData, SC.StageDirectory.FullName); // generate the OnDemandResources.plist - GenerateOnDemandResourcesPlist (ChunkData, SC.StageDirectory); + GenerateOnDemandResourcesPlist (ChunkData, SC.StageDirectory.FullName); } } @@ -1534,10 +1609,10 @@ public class IOSPlatform : Platform get { return true; } } - public override List GetFilesForCRCCheck() + public override HashSet GetFilesForCRCCheck() { - List FileList = base.GetFilesForCRCCheck(); - FileList.Add("Info.plist"); + HashSet FileList = base.GetFilesForCRCCheck(); + FileList.Add(new StagedFileReference("Info.plist")); return FileList; } public override bool SupportsMultiDeviceDeploy diff --git a/Engine/Source/Programs/AutomationTool/Linux/LinuxPlatform.Automation.cs b/Engine/Source/Programs/AutomationTool/Linux/LinuxPlatform.Automation.cs index 1cfdda60ea47..8ae555513e33 100644 --- a/Engine/Source/Programs/AutomationTool/Linux/LinuxPlatform.Automation.cs +++ b/Engine/Source/Programs/AutomationTool/Linux/LinuxPlatform.Automation.cs @@ -25,11 +25,12 @@ public abstract class BaseLinuxPlatform : Platform { if (SC.bStageCrashReporter) { - string ReceiptFileName = TargetReceipt.GetDefaultPath(CommandUtils.EngineDirectory.FullName, "CrashReportClient", SC.StageTargetPlatform.PlatformType, UnrealTargetConfiguration.Shipping, null); - if (File.Exists(ReceiptFileName)) + FileReference ReceiptFileName = TargetReceipt.GetDefaultPath(CommandUtils.EngineDirectory, "CrashReportClient", SC.StageTargetPlatform.PlatformType, UnrealTargetConfiguration.Shipping, null); + if (FileReference.Exists(ReceiptFileName)) { - TargetReceipt Receipt = TargetReceipt.Read(ReceiptFileName); - Receipt.ExpandPathVariables(CommandUtils.EngineDirectory, (Params.RawProjectPath == null) ? CommandUtils.EngineDirectory : Params.RawProjectPath.Directory); + DirectoryReference EngineDir = CommandUtils.EngineDirectory; + DirectoryReference ProjectDir = DirectoryReference.FromFile(Params.RawProjectPath); + TargetReceipt Receipt = TargetReceipt.Read(ReceiptFileName, EngineDir, ProjectDir); SC.StageBuildProductsFromReceipt(Receipt, true, false); } } @@ -44,7 +45,7 @@ public abstract class BaseLinuxPlatform : Platform ++BuildProductIdx; } - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.ProjectRoot, "Content/Splash"), "Splash.bmp", false, null, null, true); + SC.StageFiles(StagedFileType.NonUFS, DirectoryReference.Combine(SC.ProjectRoot, "Content/Splash"), "Splash.bmp", false, null, null, true); // Stage the bootstrap executable if (!Params.NoBootstrapExe) @@ -55,8 +56,8 @@ public abstract class BaseLinuxPlatform : Platform if (Executable != null) { // only create bootstraps for executables - string FullExecutablePath = Path.GetFullPath(Executable.Path); - if (Executable.Path.Replace("\\", "/").Contains("/" + TargetPlatformType.ToString() + "/")) + string FullExecutablePath = Path.GetFullPath(Executable.Path.FullName); + if (Executable.Path.FullName.Replace("\\", "/").Contains("/" + TargetPlatformType.ToString() + "/")) { string BootstrapArguments = ""; if (!ShouldStageCommandLine(Params, SC)) @@ -74,7 +75,7 @@ public abstract class BaseLinuxPlatform : Platform string BootstrapExeName; if (SC.StageTargetConfigurations.Count > 1) { - BootstrapExeName = Path.GetFileName(Executable.Path); + BootstrapExeName = Path.GetFileName(Executable.Path.FullName); } else if (Params.IsCodeBasedProject) { @@ -85,9 +86,10 @@ public abstract class BaseLinuxPlatform : Platform BootstrapExeName = SC.ShortProjectName; } - foreach (string StagePath in SC.NonUFSStagingFiles[FullExecutablePath]) + List StagePaths = SC.FilesToStage.NonUFSStagingFiles.Where(x => x.Value == Executable.Path).Select(x => x.Key).ToList(); + foreach (StagedFileReference StagePath in StagePaths) { - StageBootstrapExecutable(SC, BootstrapExeName + ".sh", FullExecutablePath, StagePath, BootstrapArguments); + StageBootstrapExecutable(SC, BootstrapExeName + ".sh", FullExecutablePath, StagePath.Name, BootstrapArguments); } } } @@ -103,9 +105,9 @@ public abstract class BaseLinuxPlatform : Platform void StageBootstrapExecutable(DeploymentContext SC, string ExeName, string TargetFile, string StagedRelativeTargetPath, string StagedArguments) { // create a temp script file location - string IntermediateDir = CombinePaths(SC.ProjectRoot, "Intermediate", "Staging"); - string IntermediateFile = CombinePaths(IntermediateDir, ExeName); - InternalUtils.SafeCreateDirectory(IntermediateDir); + DirectoryReference IntermediateDir = DirectoryReference.Combine(SC.ProjectRoot, "Intermediate", "Staging"); + string IntermediateFile = CombinePaths(IntermediateDir.FullName, ExeName); + InternalUtils.SafeCreateDirectory(IntermediateDir.FullName); // make sure slashes are good StagedRelativeTargetPath = StagedRelativeTargetPath.Replace("\\", "/"); @@ -132,7 +134,7 @@ public abstract class BaseLinuxPlatform : Platform } } - SC.StageFiles(StagedFileType.NonUFS, IntermediateDir, ExeName, false, null, ""); + SC.StageFiles(StagedFileType.NonUFS, IntermediateDir, ExeName, false, null, StagedDirectoryReference.Root); } public override string GetCookPlatform(bool bDedicatedServer, bool bIsClientOnly) @@ -188,7 +190,7 @@ public abstract class BaseLinuxPlatform : Platform } string DestPath = "./" + Params.ShortProjectName; - List Exes = GetExecutableNames(SC); + List Exes = GetExecutableNames(SC); string BinaryName = ""; if (Exes.Count > 0) { @@ -198,7 +200,7 @@ public abstract class BaseLinuxPlatform : Platform { Separator = "/"; } - BinaryName = Exes[0].Replace(Params.BaseStageDirectory, DestPath + Separator); + BinaryName = Exes[0].FullName.Replace(Params.BaseStageDirectory, DestPath + Separator); BinaryName = BinaryName.Replace("\\", "/"); } diff --git a/Engine/Source/Programs/AutomationTool/Localization/LocalizationProvider.cs b/Engine/Source/Programs/AutomationTool/Localization/LocalizationProvider.cs index 998a51ed52cb..f014e587141c 100644 --- a/Engine/Source/Programs/AutomationTool/Localization/LocalizationProvider.cs +++ b/Engine/Source/Programs/AutomationTool/Localization/LocalizationProvider.cs @@ -101,6 +101,11 @@ public abstract class LocalizationProvider public static LocalizationProvider GetLocalizationProvider(string InLocalizationProviderId, LocalizationProvider.LocalizationProviderArgs InLocalizationProviderArgs) { + if (String.IsNullOrEmpty(InLocalizationProviderId)) + { + return null; + } + if (CachedLocalizationProviderTypes == null) { // Find all types that derive from LocalizationProvider in any of our DLLs diff --git a/Engine/Source/Programs/AutomationTool/Mac/MacPlatform.Automation.cs b/Engine/Source/Programs/AutomationTool/Mac/MacPlatform.Automation.cs index c912f01c8e6a..477027f3363a 100644 --- a/Engine/Source/Programs/AutomationTool/Mac/MacPlatform.Automation.cs +++ b/Engine/Source/Programs/AutomationTool/Mac/MacPlatform.Automation.cs @@ -39,7 +39,7 @@ public class MacPlatform : Platform return "Mac"; } - private void StageAppBundle(DeploymentContext SC, StagedFileType InStageFileType, string InPath, string NewName) + private void StageAppBundle(DeploymentContext SC, StagedFileType InStageFileType, DirectoryReference InPath, StagedDirectoryReference NewName) { if (InStageFileType != StagedFileType.DebugNonUFS) { @@ -72,33 +72,33 @@ public class MacPlatform : Platform if (SC.bStageCrashReporter) { - string CrashReportClientPath = CombinePaths("Engine/Binaries", SC.PlatformDir, "CrashReportClient.app"); - StageAppBundle(SC, StagedFileType.NonUFS, CombinePaths(SC.LocalRoot, "Engine/Binaries", SC.PlatformDir, "CrashReportClient.app"), CrashReportClientPath); + StagedDirectoryReference CrashReportClientPath = StagedDirectoryReference.Combine("Engine/Binaries", SC.PlatformDir, "CrashReportClient.app"); + StageAppBundle(SC, StagedFileType.NonUFS, DirectoryReference.Combine(SC.LocalRoot, "Engine/Binaries", SC.PlatformDir, "CrashReportClient.app"), CrashReportClientPath); } // Find the app bundle path - List Exes = GetExecutableNames(SC); + List Exes = GetExecutableNames(SC); foreach (var Exe in Exes) { string AppBundlePath = ""; - if (Exe.StartsWith(CombinePaths(SC.RuntimeProjectRootDir, "Binaries", SC.PlatformDir))) + if (Exe.IsUnderDirectory(DirectoryReference.Combine(SC.RuntimeProjectRootDir, "Binaries", SC.PlatformDir))) { - AppBundlePath = CombinePaths(SC.ShortProjectName, "Binaries", SC.PlatformDir, Path.GetFileNameWithoutExtension(Exe) + ".app"); + AppBundlePath = CombinePaths(SC.ShortProjectName, "Binaries", SC.PlatformDir, Path.GetFileNameWithoutExtension(Exe.FullName) + ".app"); } - else if (Exe.StartsWith(CombinePaths(SC.RuntimeRootDir, "Engine/Binaries", SC.PlatformDir))) + else if (Exe.IsUnderDirectory(DirectoryReference.Combine(SC.RuntimeRootDir, "Engine/Binaries", SC.PlatformDir))) { - AppBundlePath = CombinePaths("Engine/Binaries", SC.PlatformDir, Path.GetFileNameWithoutExtension(Exe) + ".app"); + AppBundlePath = CombinePaths("Engine/Binaries", SC.PlatformDir, Path.GetFileNameWithoutExtension(Exe.FullName) + ".app"); } // Copy the custom icon and Steam dylib, if needed if (!string.IsNullOrEmpty(AppBundlePath)) { - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.ProjectRoot, "Build/Mac"), "Application.icns", false, null, CombinePaths(AppBundlePath, "Contents/Resources"), true); + SC.StageFiles(StagedFileType.NonUFS, DirectoryReference.Combine(SC.ProjectRoot, "Build/Mac"), "Application.icns", false, null, new StagedDirectoryReference(CombinePaths(AppBundlePath, "Contents/Resources")), true); } } // Copy the splash screen, Mac specific - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.ProjectRoot, "Content/Splash"), "Splash.bmp", false, null, null, true); + SC.StageFiles(StagedFileType.NonUFS, DirectoryReference.Combine(SC.ProjectRoot, "Content/Splash"), "Splash.bmp", false, null, null, true); // Stage the bootstrap executable if (!Params.NoBootstrapExe) @@ -109,7 +109,8 @@ public class MacPlatform : Platform if (Executable != null) { // only create bootstraps for executables - if (SC.NonUFSStagingFiles.ContainsKey(Executable.Path) && Executable.Path.Replace("\\", "/").Contains("/" + TargetPlatformType.ToString() + "/")) + List StagedFiles = SC.FilesToStage.NonUFSStagingFiles.Where(x => x.Value == Executable.Path).Select(x => x.Key).ToList(); + if (StagedFiles.Count > 0 && Executable.Path.FullName.Replace("\\", "/").Contains("/" + TargetPlatformType.ToString() + "/")) { string BootstrapArguments = ""; if (!ShouldStageCommandLine(Params, SC)) @@ -127,7 +128,7 @@ public class MacPlatform : Platform string BootstrapExeName; if (SC.StageTargetConfigurations.Count > 1) { - BootstrapExeName = Path.GetFileName(Executable.Path) + ".app"; + BootstrapExeName = Path.GetFileName(Executable.Path.FullName) + ".app"; } else if (Params.IsCodeBasedProject) { @@ -138,11 +139,10 @@ public class MacPlatform : Platform BootstrapExeName = SC.ShortProjectName + ".app"; } - string AppPath = Executable.Path.Substring(0, Executable.Path.LastIndexOf(".app/") + 4); - object Dest = SC.NonUFSStagingFiles[Executable.Path]; - foreach (var DestPath in SC.NonUFSStagingFiles[Executable.Path]) + string AppPath = Executable.Path.FullName.Substring(0, Executable.Path.FullName.LastIndexOf(".app/") + 4); + foreach (var DestPath in StagedFiles) { - string AppRelativePath = DestPath.Substring(0, DestPath.LastIndexOf(".app/") + 4); + string AppRelativePath = DestPath.Name.Substring(0, DestPath.Name.LastIndexOf(".app/") + 4); StageBootstrapExecutable(SC, BootstrapExeName, AppPath, AppRelativePath, BootstrapArguments); } } @@ -151,8 +151,8 @@ public class MacPlatform : Platform } // Copy the ShaderCache files, if they exist - SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.ProjectRoot, "Content"), "DrawCache.ushadercache", false, null, null, true); - SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.ProjectRoot, "Content"), "ByteCodeCache.ushadercode", false, null, null, true); + SC.StageFiles(StagedFileType.UFS, DirectoryReference.Combine(SC.ProjectRoot, "Content"), "DrawCache.ushadercache", false, null, null, true); + SC.StageFiles(StagedFileType.UFS, DirectoryReference.Combine(SC.ProjectRoot, "Content"), "ByteCodeCache.ushadercode", false, null, null, true); } string GetValueFromInfoPlist(string InfoPlist, string Key, string DefaultValue = "") @@ -174,23 +174,23 @@ public class MacPlatform : Platform void StageBootstrapExecutable(DeploymentContext SC, string ExeName, string TargetFile, string StagedRelativeTargetPath, string StagedArguments) { - string InputApp = CombinePaths(SC.LocalRoot, "Engine", "Binaries", SC.PlatformDir, "BootstrapPackagedGame.app"); - if (InternalUtils.SafeDirectoryExists(InputApp)) + DirectoryReference InputApp = DirectoryReference.Combine(SC.LocalRoot, "Engine", "Binaries", SC.PlatformDir, "BootstrapPackagedGame.app"); + if (InternalUtils.SafeDirectoryExists(InputApp.FullName)) { // Create the new bootstrap program - string IntermediateDir = CombinePaths(SC.ProjectRoot, "Intermediate", "Staging"); - InternalUtils.SafeCreateDirectory(IntermediateDir); + DirectoryReference IntermediateDir = DirectoryReference.Combine(SC.ProjectRoot, "Intermediate", "Staging"); + InternalUtils.SafeCreateDirectory(IntermediateDir.FullName); - string IntermediateApp = CombinePaths(IntermediateDir, ExeName); - if (Directory.Exists(IntermediateApp)) + DirectoryReference IntermediateApp = DirectoryReference.Combine(IntermediateDir, ExeName); + if (DirectoryReference.Exists(IntermediateApp)) { - Directory.Delete(IntermediateApp, true); + DirectoryReference.Delete(IntermediateApp, true); } - CloneDirectory(InputApp, IntermediateApp); + CloneDirectory(InputApp.FullName, IntermediateApp.FullName); // Rename the executable string GameName = Path.GetFileNameWithoutExtension(ExeName); - File.Move(CombinePaths(IntermediateApp, "Contents", "MacOS", "BootstrapPackagedGame"), CombinePaths(IntermediateApp, "Contents", "MacOS", GameName)); + FileReference.Move(FileReference.Combine(IntermediateApp, "Contents", "MacOS", "BootstrapPackagedGame"), FileReference.Combine(IntermediateApp, "Contents", "MacOS", GameName)); // Copy the icon string SrcInfoPlistPath = CombinePaths(TargetFile, "Contents", "Info.plist"); @@ -200,12 +200,12 @@ public class MacPlatform : Platform if (!string.IsNullOrEmpty(IconName)) { string IconPath = CombinePaths(TargetFile, "Contents", "Resources", IconName + ".icns"); - InternalUtils.SafeCreateDirectory(CombinePaths(IntermediateApp, "Contents", "Resources")); - File.Copy(IconPath, CombinePaths(IntermediateApp, "Contents", "Resources", IconName + ".icns")); + InternalUtils.SafeCreateDirectory(CombinePaths(IntermediateApp.FullName, "Contents", "Resources")); + File.Copy(IconPath, CombinePaths(IntermediateApp.FullName, "Contents", "Resources", IconName + ".icns")); } // Update Info.plist contents - string DestInfoPlistPath = CombinePaths(IntermediateApp, "Contents", "Info.plist"); + string DestInfoPlistPath = CombinePaths(IntermediateApp.FullName, "Contents", "Info.plist"); string DestInfoPlist = File.ReadAllText(DestInfoPlistPath); string AppIdentifier = GetValueFromInfoPlist(SrcInfoPlist, "CFBundleIdentifier"); @@ -229,7 +229,7 @@ public class MacPlatform : Platform File.WriteAllText(DestInfoPlistPath, DestInfoPlist); - StageAppBundle(SC, StagedFileType.NonUFS, IntermediateApp, ExeName); + StageAppBundle(SC, StagedFileType.NonUFS, IntermediateApp, new StagedDirectoryReference(ExeName)); } } @@ -244,12 +244,12 @@ public class MacPlatform : Platform if (Params.CreateAppBundle) { string ExeName = SC.StageExecutables[0]; - string BundlePath = CombinePaths(SC.ArchiveDirectory, SC.ShortProjectName + ".app"); + string BundlePath = CombinePaths(SC.ArchiveDirectory.FullName, SC.ShortProjectName + ".app"); if (SC.bIsCombiningMultiplePlatforms) { // when combining multiple platforms, don't merge the content into the .app, use the one in the Binaries directory - BundlePath = CombinePaths(SC.ArchiveDirectory, SC.ShortProjectName, "Binaries", "Mac", ExeName + ".app"); + BundlePath = CombinePaths(SC.ArchiveDirectory.FullName, SC.ShortProjectName, "Binaries", "Mac", ExeName + ".app"); if (!Directory.Exists(BundlePath)) { // if the .app wasn't there, just skip out (we don't require executables when combining) @@ -265,13 +265,13 @@ public class MacPlatform : Platform Directory.Delete(BundlePath, true); } - string SourceBundlePath = CombinePaths(SC.ArchiveDirectory, SC.ShortProjectName, "Binaries", "Mac", ExeName + ".app"); + string SourceBundlePath = CombinePaths(SC.ArchiveDirectory.FullName, SC.ShortProjectName, "Binaries", "Mac", ExeName + ".app"); if (!Directory.Exists(SourceBundlePath)) { - SourceBundlePath = CombinePaths(SC.ArchiveDirectory, "Engine", "Binaries", "Mac", ExeName + ".app"); + SourceBundlePath = CombinePaths(SC.ArchiveDirectory.FullName, "Engine", "Binaries", "Mac", ExeName + ".app"); if (!Directory.Exists(SourceBundlePath)) { - SourceBundlePath = CombinePaths(SC.ArchiveDirectory, "Engine", "Binaries", "Mac", "UE4.app"); + SourceBundlePath = CombinePaths(SC.ArchiveDirectory.FullName, "Engine", "Binaries", "Mac", "UE4.app"); } } Directory.Move(SourceBundlePath, BundlePath); @@ -282,7 +282,7 @@ public class MacPlatform : Platform } // First, move all files and folders inside he app bundle - string[] StagedFiles = Directory.GetFiles(SC.ArchiveDirectory, "*", SearchOption.TopDirectoryOnly); + string[] StagedFiles = Directory.GetFiles(SC.ArchiveDirectory.FullName, "*", SearchOption.TopDirectoryOnly); foreach (string FilePath in StagedFiles) { string TargetFilePath = CombinePaths(TargetPath, Path.GetFileName(FilePath)); @@ -290,7 +290,7 @@ public class MacPlatform : Platform File.Move(FilePath, TargetFilePath); } - string[] StagedDirectories = Directory.GetDirectories(SC.ArchiveDirectory, "*", SearchOption.TopDirectoryOnly); + string[] StagedDirectories = Directory.GetDirectories(SC.ArchiveDirectory.FullName, "*", SearchOption.TopDirectoryOnly); foreach (string DirPath in StagedDirectories) { string DirName = Path.GetFileName(DirPath); @@ -406,21 +406,21 @@ public class MacPlatform : Platform if (UnrealBuildTool.BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac) { // Sign everything we built - List FilesToSign = GetExecutableNames(SC); + List FilesToSign = GetExecutableNames(SC); Log("RuntimeProjectRootDir: " + SC.RuntimeProjectRootDir); foreach (var Exe in FilesToSign) { Log("Signing: " + Exe); string AppBundlePath = ""; - if (Exe.StartsWith(CombinePaths(SC.RuntimeProjectRootDir, "Binaries", SC.PlatformDir))) + if (Exe.IsUnderDirectory(DirectoryReference.Combine(SC.RuntimeProjectRootDir, "Binaries", SC.PlatformDir))) { Log("Starts with Binaries"); - AppBundlePath = CombinePaths(SC.RuntimeProjectRootDir, "Binaries", SC.PlatformDir, Path.GetFileNameWithoutExtension(Exe) + ".app"); + AppBundlePath = CombinePaths(SC.RuntimeProjectRootDir.FullName, "Binaries", SC.PlatformDir, Path.GetFileNameWithoutExtension(Exe.FullName) + ".app"); } - else if (Exe.StartsWith(CombinePaths(SC.RuntimeRootDir, "Engine/Binaries", SC.PlatformDir))) + else if (Exe.IsUnderDirectory(DirectoryReference.Combine(SC.RuntimeRootDir, "Engine/Binaries", SC.PlatformDir))) { Log("Starts with Engine/Binaries"); - AppBundlePath = CombinePaths("Engine/Binaries", SC.PlatformDir, Path.GetFileNameWithoutExtension(Exe) + ".app"); + AppBundlePath = CombinePaths("Engine/Binaries", SC.PlatformDir, Path.GetFileNameWithoutExtension(Exe.FullName) + ".app"); } Log("Signing: " + AppBundlePath); CodeSign.SignMacFileOrFolder(AppBundlePath); diff --git a/Engine/Source/Programs/AutomationTool/Scripts/ArchiveCommand.Automation.cs b/Engine/Source/Programs/AutomationTool/Scripts/ArchiveCommand.Automation.cs index 3efd4ba7b51e..92a3861152a3 100644 --- a/Engine/Source/Programs/AutomationTool/Scripts/ArchiveCommand.Automation.cs +++ b/Engine/Source/Programs/AutomationTool/Scripts/ArchiveCommand.Automation.cs @@ -27,7 +27,7 @@ public partial class Project : CommandUtils if (Params.ArchiveMetaData) { // archive the build.version file for extra info for testing, etc - string BuildVersionFile = CombinePaths(SC.LocalRoot, "Engine", "Build", "Build.version"); + string BuildVersionFile = CombinePaths(SC.LocalRoot.FullName, "Engine", "Build", "Build.version"); SC.ArchiveFiles(Path.GetDirectoryName(BuildVersionFile), Path.GetFileName(BuildVersionFile)); } } @@ -38,8 +38,8 @@ public partial class Project : CommandUtils { foreach (var Pair in SC.ArchivedFiles) { - string Src = Pair.Key; - string Dest = CombinePaths(SC.ArchiveDirectory, Pair.Value); + FileReference Src = new FileReference(Pair.Key); + FileReference Dest = FileReference.Combine(SC.ArchiveDirectory, Pair.Value); CopyFileIncremental(Src, Dest); } } diff --git a/Engine/Source/Programs/AutomationTool/Scripts/AutomationScripts.Automation.csproj b/Engine/Source/Programs/AutomationTool/Scripts/AutomationScripts.Automation.csproj index 3c2e5ca6cf61..90e013e62092 100644 --- a/Engine/Source/Programs/AutomationTool/Scripts/AutomationScripts.Automation.csproj +++ b/Engine/Source/Programs/AutomationTool/Scripts/AutomationScripts.Automation.csproj @@ -7,7 +7,7 @@ {8AA00D65-0954-4A27-AC0D-FB8B1106120F} Library Properties - AutomationScripts.Automation + AutomationTool AutomationScripts.Automation v4.5 512 @@ -72,14 +72,14 @@ - + - + @@ -100,9 +100,10 @@ - + + diff --git a/Engine/Source/Programs/AutomationTool/Scripts/BuildPhysX.Automation.cs b/Engine/Source/Programs/AutomationTool/Scripts/BuildPhysX.Automation.cs index 28927ed36a18..50fcbcc1c469 100644 --- a/Engine/Source/Programs/AutomationTool/Scripts/BuildPhysX.Automation.cs +++ b/Engine/Source/Programs/AutomationTool/Scripts/BuildPhysX.Automation.cs @@ -15,7 +15,7 @@ using UnrealBuildTool; [Help("TargetLibs", "Specify a list of target libraries to build, separated by '+' characters (eg. -TargetLibs=PhysX+APEX). Default is PhysX+APEX.")] [Help("TargetPlatforms", "Specify a list of target platforms to build, separated by '+' characters (eg. -TargetPlatforms=Win32+Win64). Architectures are specified with '-'. Default is Win32+Win64+PS4.")] [Help("TargetConfigs", "Specify a list of configurations to build, separated by '+' characters (eg. -TargetConfigs=profile+debug). Default is profile+release+checked.")] -[Help("TargetWindowsCompilers", "Specify a list of target compilers to use when building for Windows, separated by '+' characters (eg. -TargetCompilers=VisualStudio2012+VisualStudio2015). Default is VisualStudio2013+VisualStudio2015.")] +[Help("TargetWindowsCompilers", "Specify a list of target compilers to use when building for Windows, separated by '+' characters (eg. -TargetCompilers=VisualStudio2012+VisualStudio2015). Default is VisualStudio2015.")] [Help("SkipBuild", "Do not perform build step. If this argument is not supplied libraries will be built (in accordance with TargetLibs, TargetPlatforms and TargetWindowsCompilers).")] [Help("SkipDeployLibs", "Do not perform library deployment to the engine. If this argument is not supplied libraries will be copied into the engine.")] [Help("SkipDeploySource", "Do not perform source deployment to the engine. If this argument is not supplied source will be copied into the engine.")] @@ -182,7 +182,7 @@ class BuildPhysX : BuildCommand throw new AutomationException(String.Format("Non-CMake or unsupported platform '{0}' supplied to GetCMakeArguments", TargetData.ToString())); } - string OutputFlags = " -DPX_OUTPUT_LIB_DIR=" + GetPlatformLibDirectory(TargetData, TargetWindowsCompiler); + string OutputFlags = " -DPX_OUTPUT_LIB_DIR=\"" + GetPlatformLibDirectory(TargetData, TargetWindowsCompiler) + "\""; if(PlatformHasBinaries(TargetData)) { OutputFlags += " -DPX_OUTPUT_DLL_DIR=" + GetPlatformBinaryDirectory(TargetData, TargetWindowsCompiler) + " -DPX_OUTPUT_EXE_DIR=" + GetPlatformBinaryDirectory(TargetData, TargetWindowsCompiler); @@ -193,7 +193,8 @@ class BuildPhysX : BuildCommand switch (TargetData.Platform) { case UnrealTargetPlatform.PS4: - case UnrealTargetPlatform.Linux: + case UnrealTargetPlatform.Switch: + case UnrealTargetPlatform.Linux: OutputFlags += " -DUSE_RESPONSE_FILES=1"; break; } @@ -246,7 +247,7 @@ class BuildPhysX : BuildCommand return DirectoryReference.Combine(PhysXCMakeFiles, "Switch").ToString() + " -G \"Unix Makefiles\" -DTARGET_BUILD_PLATFORM=Switch -DCMAKE_BUILD_TYPE=" + BuildConfig + " -DCMAKE_TOOLCHAIN_FILE=\"" + PhysXSourceRootDirectory + "\\Externals\\CMakeModules\\Switch\\SwitchToolchain.cmake\"" + OutputFlags; case UnrealTargetPlatform.HTML5: string CmakeToolchainFile = FileReference.Combine(PhysXSourceRootDirectory, "Externals", "CMakeModules", "HTML5", "Emscripten." + BuildConfig + ".cmake").ToString(); - return DirectoryReference.Combine(PhysXCMakeFiles, "HTML5").ToString() + + return "\"" + DirectoryReference.Combine(PhysXCMakeFiles, "HTML5").ToString() + "\"" + " -G \"Unix Makefiles\" -DTARGET_BUILD_PLATFORM=HTML5" + " -DPXSHARED_ROOT_DIR=\"" + SharedSourceRootDirectory.ToString() + "\"" + " -DNVSIMD_INCLUDE_DIR=\"" + SharedSourceRootDirectory.ToString() + "/src/NvSimd\"" + @@ -288,6 +289,8 @@ class BuildPhysX : BuildCommand return DirectoryReference.Combine(NvClothCMakeFiles, "Windows").ToString() + " -G \"" + VisualStudioName + "\" -Ax64 -DTARGET_BUILD_PLATFORM=Windows" + OutputFlags; case UnrealTargetPlatform.PS4: return DirectoryReference.Combine(NvClothCMakeFiles, "PS4").ToString() + " -G \"Unix Makefiles\" -DTARGET_BUILD_PLATFORM=PS4 -DCMAKE_BUILD_TYPE=" + BuildConfig + " -DCMAKE_TOOLCHAIN_FILE=\"" + PhysXSourceRootDirectory + "\\Externals\\CMakeModules\\PS4\\PS4Toolchain.txt\"" + OutputFlags; + case UnrealTargetPlatform.Switch: + return DirectoryReference.Combine(NvClothCMakeFiles, "Switch").ToString() + " -G \"Unix Makefiles\" -DTARGET_BUILD_PLATFORM=Switch -DCMAKE_BUILD_TYPE=" + BuildConfig + " -DCMAKE_TOOLCHAIN_FILE=\"" + PhysXSourceRootDirectory + "\\Externals\\CMakeModules\\Switch\\SwitchToolchain.cmake\"" + OutputFlags; case UnrealTargetPlatform.XboxOne: return DirectoryReference.Combine(NvClothCMakeFiles, "XboxOne").ToString() + " -G \"Visual Studio 14 2015\" -DTARGET_BUILD_PLATFORM=XboxOne -DCMAKE_TOOLCHAIN_FILE=\"" + PhysXSourceRootDirectory + "\\Externals\\CMakeModules\\XboxOne\\XboxOneToolchain.txt\" -DCMAKE_GENERATOR_PLATFORM=DURANGO" + OutputFlags; case UnrealTargetPlatform.Linux: @@ -413,7 +416,7 @@ class BuildPhysX : BuildCommand List TargetPlatforms = new List(); // Remove any platforms that aren't enabled on the command line - string TargetPlatformFilter = ParseParamValue("TargetPlatforms", "Win32+Win64+PS4"); + string TargetPlatformFilter = ParseParamValue("TargetPlatforms", "Win32+Win64+PS4+Switch"); if (TargetPlatformFilter != null) { foreach (string TargetPlatformName in TargetPlatformFilter.Split(new char[] { '+' }, StringSplitOptions.RemoveEmptyEntries)) @@ -682,9 +685,9 @@ class BuildPhysX : BuildCommand // CMAKE ProcessStartInfo StartInfo = new ProcessStartInfo(); - StartInfo.FileName = "cmake"; + StartInfo.FileName = "python"; StartInfo.WorkingDirectory = CMakeTargetDirectory.ToString(); - StartInfo.Arguments = GetCMakeArguments(TargetLib, TargetData, BuildConfig); + StartInfo.Arguments = "\"" + HTML5SDKInfo.EMSCRIPTEN_ROOT + "\\emcmake\" cmake " + GetCMakeArguments(TargetLib, TargetData, BuildConfig); Log("Working in: {0}", StartInfo.WorkingDirectory); Log("{0} {1}", StartInfo.FileName, StartInfo.Arguments); @@ -926,7 +929,7 @@ class BuildPhysX : BuildCommand { // Use emscripten toolchain MakeCommand = "python"; - MakeOptions = HTML5SDKInfo.EMSCRIPTEN_ROOT + "\\emmake make"; + MakeOptions = "\"" + HTML5SDKInfo.EMSCRIPTEN_ROOT + "\\emmake\" make"; BuildMap = new Dictionary() { {"debug", "Build-O0"}, @@ -1364,6 +1367,7 @@ class BuildPhysX : BuildCommand case UnrealTargetPlatform.Win32: case UnrealTargetPlatform.Win64: case UnrealTargetPlatform.PS4: + case UnrealTargetPlatform.Switch: case UnrealTargetPlatform.XboxOne: case UnrealTargetPlatform.Mac: return true; diff --git a/Engine/Source/Programs/AutomationTool/Scripts/BuildPluginCommand.Automation.cs b/Engine/Source/Programs/AutomationTool/Scripts/BuildPluginCommand.Automation.cs index 04801116797c..9bd0f39233a8 100644 --- a/Engine/Source/Programs/AutomationTool/Scripts/BuildPluginCommand.Automation.cs +++ b/Engine/Source/Programs/AutomationTool/Scripts/BuildPluginCommand.Automation.cs @@ -119,7 +119,7 @@ class BuildPlugin : BuildCommand FileReference[] CompilePlugin(FileReference HostProjectFile, FileReference HostProjectPluginFile, PluginDescriptor Plugin, List HostPlatforms, List TargetPlatforms, string AdditionalArgs) { - List ReceiptFileNames = new List(); + List ReceiptFileNames = new List(); // Build the host platforms if(HostPlatforms.Count > 0) @@ -148,10 +148,10 @@ class BuildPlugin : BuildCommand // Package the plugin to the output folder List BuildProducts = GetBuildProductsFromReceipts(CommandUtils.EngineDirectory, HostProjectFile.Directory, ReceiptFileNames); - return BuildProducts.Select(x => new FileReference(x.Path)).ToArray(); + return BuildProducts.Select(x => x.Path).ToArray(); } - void CompilePluginWithUBT(FileReference HostProjectFile, FileReference HostProjectPluginFile, PluginDescriptor Plugin, string TargetName, TargetType TargetType, UnrealTargetPlatform Platform, UnrealTargetConfiguration Configuration, List ReceiptFileNames, string InAdditionalArgs) + void CompilePluginWithUBT(FileReference HostProjectFile, FileReference HostProjectPluginFile, PluginDescriptor Plugin, string TargetName, TargetType TargetType, UnrealTargetPlatform Platform, UnrealTargetConfiguration Configuration, List ReceiptFileNames, string InAdditionalArgs) { // Find a list of modules that need to be built for this plugin List ModuleNames = new List(); @@ -180,8 +180,8 @@ class BuildPlugin : BuildCommand string Architecture = PlatformExports.GetDefaultArchitecture(Platform, HostProjectFile); - string ReceiptFileName = TargetReceipt.GetDefaultPath(HostProjectPluginFile.Directory.FullName, TargetName, Platform, Configuration, Architecture); - Arguments += String.Format(" -receipt {0}", CommandUtils.MakePathSafeToUseWithCommandLine(ReceiptFileName)); + FileReference ReceiptFileName = TargetReceipt.GetDefaultPath(HostProjectPluginFile.Directory, TargetName, Platform, Configuration, Architecture); + Arguments += String.Format(" -receipt {0}", CommandUtils.MakePathSafeToUseWithCommandLine(ReceiptFileName.FullName)); ReceiptFileNames.Add(ReceiptFileName); if(!String.IsNullOrEmpty(InAdditionalArgs)) @@ -193,17 +193,16 @@ class BuildPlugin : BuildCommand } } - static List GetBuildProductsFromReceipts(DirectoryReference EngineDir, DirectoryReference ProjectDir, List ReceiptFileNames) + static List GetBuildProductsFromReceipts(DirectoryReference EngineDir, DirectoryReference ProjectDir, List ReceiptFileNames) { List BuildProducts = new List(); - foreach(string ReceiptFileName in ReceiptFileNames) + foreach(FileReference ReceiptFileName in ReceiptFileNames) { TargetReceipt Receipt; - if(!TargetReceipt.TryRead(ReceiptFileName, out Receipt)) + if(!TargetReceipt.TryRead(ReceiptFileName, EngineDir, ProjectDir, out Receipt)) { throw new AutomationException("Missing or invalid target receipt ({0})", ReceiptFileName); } - Receipt.ExpandPathVariables(EngineDir, ProjectDir); BuildProducts.AddRange(Receipt.BuildProducts); } return BuildProducts; diff --git a/Engine/Source/Programs/AutomationTool/Scripts/BuildProjectCommand.Automation.cs b/Engine/Source/Programs/AutomationTool/Scripts/BuildProjectCommand.Automation.cs index 13aa71c4c63f..116e82e15f7d 100644 --- a/Engine/Source/Programs/AutomationTool/Scripts/BuildProjectCommand.Automation.cs +++ b/Engine/Source/Programs/AutomationTool/Scripts/BuildProjectCommand.Automation.cs @@ -52,7 +52,14 @@ public partial class Project : CommandUtils FileReference CodePlugin = null; if(Params.BlueprintPluginPaths.TryGetValue(PluginKey, out CodePlugin)) { - ScriptPluginArgs += "-PLUGIN \"" + CodePlugin + "\" "; + if (FileReference.Exists(CodePlugin)) + { + ScriptPluginArgs += "-PLUGIN \"" + CodePlugin + "\" "; + } + else + { + LogWarning("Failed to find generated plugin for Blueprint nativization [" + CodePlugin.FullName + "]. Nativization has run, but maybe there are no Blueprints which were converted?"); + } } else { @@ -94,7 +101,7 @@ public partial class Project : CommandUtils var CrashReportPlatforms = new HashSet(); // Setup editor targets - if (Params.HasEditorTargets && !Automation.IsEngineInstalled() && (TargetMask & ProjectBuildTargets.Editor) == ProjectBuildTargets.Editor) + if (Params.HasEditorTargets && (!Params.SkipBuildEditor) && !Automation.IsEngineInstalled() && (TargetMask & ProjectBuildTargets.Editor) == ProjectBuildTargets.Editor) { // @todo Mac: proper platform detection UnrealTargetPlatform EditorPlatform = HostPlatform.Current.HostEditorPlatform; @@ -120,8 +127,15 @@ public partial class Project : CommandUtils } } + // Additional compile arguments + string AdditionalArgs = ""; + if (Params.MapFile) + { + AdditionalArgs += " -mapfile"; + } + // Setup cooked targets - if (Params.HasClientCookedTargets && (TargetMask & ProjectBuildTargets.ClientCooked) == ProjectBuildTargets.ClientCooked) + if (Params.HasClientCookedTargets && (!Params.SkipBuildClient) && (TargetMask & ProjectBuildTargets.ClientCooked) == ProjectBuildTargets.ClientCooked) { List UniquePlatformTypes = Params.ClientTargetPlatforms.ConvertAll(x => x.Type).Distinct().ToList(); @@ -131,7 +145,7 @@ public partial class Project : CommandUtils { string ScriptPluginArgs = GetBlueprintPluginPathArgument(Params, true, ClientPlatformType); CrashReportPlatforms.Add(ClientPlatformType); - Agenda.AddTargets(Params.ClientCookedTargets.ToArray(), ClientPlatformType, BuildConfig, Params.CodeBasedUprojectPath, InAddArgs: ScriptPluginArgs + " -remoteini=\"" + Params.RawProjectPath.Directory.FullName + "\""); + Agenda.AddTargets(Params.ClientCookedTargets.ToArray(), ClientPlatformType, BuildConfig, Params.CodeBasedUprojectPath, InAddArgs: ScriptPluginArgs + " -remoteini=\"" + Params.RawProjectPath.Directory.FullName + "\"" + AdditionalArgs); } } } @@ -145,7 +159,7 @@ public partial class Project : CommandUtils { string ScriptPluginArgs = GetBlueprintPluginPathArgument(Params, false, ServerPlatformType); CrashReportPlatforms.Add(ServerPlatformType); - Agenda.AddTargets(Params.ServerCookedTargets.ToArray(), ServerPlatformType, BuildConfig, Params.CodeBasedUprojectPath, InAddArgs: ScriptPluginArgs + " -remoteini=\"" + Params.RawProjectPath.Directory.FullName + "\""); + Agenda.AddTargets(Params.ServerCookedTargets.ToArray(), ServerPlatformType, BuildConfig, Params.CodeBasedUprojectPath, InAddArgs: ScriptPluginArgs + " -remoteini=\"" + Params.RawProjectPath.Directory.FullName + "\"" + AdditionalArgs); } } } diff --git a/Engine/Source/Programs/AutomationTool/Scripts/BuildTargetCommand.Automation.cs b/Engine/Source/Programs/AutomationTool/Scripts/BuildTargetCommand.Automation.cs deleted file mode 100644 index 0cc4c9e62581..000000000000 --- a/Engine/Source/Programs/AutomationTool/Scripts/BuildTargetCommand.Automation.cs +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading; -using System.Reflection; -using System.Linq; -using AutomationTool; -using UnrealBuildTool; - -[Help("Builds a target")] -[Help("Project", "Specify the project with the targets to build.")] -[Help("Target", "Specify a list of target descriptor files for the targets to build, separated by '+' characters (eg. -Target=Game+Client+Editor)")] -[Help("TargetPlatforms", "Specify a list of target platforms to build, separated by '+' characters (eg. -TargetPlatforms=Win32+Win64+IOS). Default is Win64.")] -[Help("Config", "Specify a list of target build configurations to build against, separated by '+' characters (eg. -Config=Debug+Test). Default is Development")] -class BuildTarget : BuildCommand -{ - private ParamList ParseParamList(string InArgument, string InDefault = null) - { - var ArgumentList = ParseParamValue(InArgument); - if (ArgumentList != null) - { - return new ParamList(ArgumentList.Split('+')); - } - else if (!String.IsNullOrEmpty(InDefault)) - { - return new ParamList(InDefault); - } - return null; - } - - public override void ExecuteBuild() - { - // get the project - var UProjectFileName = ParseParamValue("Project"); - if (UProjectFileName == null) - { - throw new AutomationException("Project was not specified via the -project argument."); - } - - // Get the list of targets - var TargetList = ParseParamList("Target"); - if (TargetList == null) - { - throw new AutomationException("Target was not specified via the -target argument."); - } - - // get the list of platforms - var PlatformList = ParseParamList("TargetPlatforms", "Win64"); - List TargetPlatforms = new List(); - foreach(string Platform in PlatformList) - { - TargetPlatforms.Add((UnrealTargetPlatform)Enum.Parse(typeof(UnrealTargetPlatform), Platform, true)); - } - - // get the list configurations - var ConfigList = ParseParamList("Config", "Development"); - List ConfigsToBuild = new List(); - foreach(string Config in ConfigList) - { - ConfigsToBuild.Add((UnrealTargetConfiguration)Enum.Parse(typeof(UnrealTargetConfiguration), Config, true)); - } - - // parse any extra parameters - bool bClean = ParseParam("Clean"); - int WorkingCL = ParseParamInt("P4Change"); - - FileReference UProjectFileReference = new FileReference( UProjectFileName); - - // add the targets to the agenda - // verify the targets and add them to the agenda - var Properties = ProjectUtils.GetProjectProperties(UProjectFileReference); - UE4Build.BuildAgenda Agenda = new UE4Build.BuildAgenda(); - foreach (string Target in TargetList) - { - SingleTargetProperties TargetData; - if (!Properties.Targets.TryGetValue((TargetType)Enum.Parse(typeof(TargetType), Target), out TargetData)) - { - throw new AutomationException("Project does not support specified target: {0}", Target); - } - - foreach (UnrealTargetPlatform TargetPlatform in TargetPlatforms) - { - foreach (UnrealTargetConfiguration TargetConfig in ConfigsToBuild) - { - Agenda.AddTarget(TargetData.TargetName, TargetPlatform, TargetConfig, UProjectFileReference); - } - } - } - - - // build it - UE4Build Build = new UE4Build(this); - Build.Build(Agenda, InDeleteBuildProducts: bClean, InUpdateVersionFiles: WorkingCL > 0); - - if (WorkingCL > 0) // only move UAT files if we intend to check in some build products - { - Build.AddUATFilesToBuildProducts(); - } - UE4Build.CheckBuildProducts(Build.BuildProductFiles); - - if (WorkingCL > 0) - { - // Sign everything we built - CodeSign.SignMultipleIfEXEOrDLL(this, Build.BuildProductFiles); - - // Open files for add or edit - UE4Build.AddBuildProductsToChangelist(WorkingCL, Build.BuildProductFiles); - } - - } - #region Build Command - -/* public static void Build(BuildCommand Command, ProjectParams Params, int WorkingCL = -1) - { - Log("********** BUILD COMMAND STARTED **********"); - - var UE4Build = new UE4Build(Command); - var Agenda = new UE4Build.BuildAgenda(); - var CrashReportPlatforms = new HashSet(); - - // Setup editor targets - if (Params.HasEditorTargets && !Params.Rocket) - { - // @todo Mac: proper platform detection - UnrealTargetPlatform EditorPlatform = HostPlatform.Current.HostEditorPlatform; - const UnrealTargetConfiguration EditorConfiguration = UnrealTargetConfiguration.Development; - - CrashReportPlatforms.Add(EditorPlatform); - Agenda.AddTargets(Params.EditorTargets.ToArray(), EditorPlatform, EditorConfiguration, Params.CodeBasedUprojectPath); - if (Params.EditorTargets.Contains("UnrealHeaderTool") == false) - { - Agenda.AddTargets(new string[] { "UnrealHeaderTool" }, EditorPlatform, EditorConfiguration); - } - if (Params.EditorTargets.Contains("ShaderCompileWorker") == false) - { - Agenda.AddTargets(new string[] { "ShaderCompileWorker" }, EditorPlatform, EditorConfiguration); - } - if (Params.Pak && Params.EditorTargets.Contains("UnrealPak") == false) - { - Agenda.AddTargets(new string[] { "UnrealPak" }, EditorPlatform, EditorConfiguration); - } - if (Params.FileServer && Params.EditorTargets.Contains("UnrealFileServer") == false) - { - Agenda.AddTargets(new string[] { "UnrealFileServer" }, EditorPlatform, EditorConfiguration); - } - } - - // Setup cooked targets - if (Params.HasClientCookedTargets) - { - foreach (var BuildConfig in Params.ClientConfigsToBuild) - { - foreach (var ClientPlatform in Params.ClientTargetPlatforms) - { - CrashReportPlatforms.Add(ClientPlatform); - Agenda.AddTargets(Params.ClientCookedTargets.ToArray(), ClientPlatform, BuildConfig, Params.CodeBasedUprojectPath); - } - } - } - if (Params.HasServerCookedTargets) - { - foreach (var BuildConfig in Params.ServerConfigsToBuild) - { - foreach (var ServerPlatform in Params.ServerTargetPlatforms) - { - CrashReportPlatforms.Add(ServerPlatform); - Agenda.AddTargets(Params.ServerCookedTargets.ToArray(), ServerPlatform, BuildConfig, Params.CodeBasedUprojectPath); - } - } - } - if (!Params.NoBootstrapExe && !Params.Rocket) - { - UnrealBuildTool.UnrealTargetPlatform[] BootstrapPackagedGamePlatforms = { UnrealBuildTool.UnrealTargetPlatform.Win32, UnrealBuildTool.UnrealTargetPlatform.Win64 }; - foreach(UnrealBuildTool.UnrealTargetPlatform BootstrapPackagedGamePlatform in BootstrapPackagedGamePlatforms) - { - if(Params.ClientTargetPlatforms.Contains(BootstrapPackagedGamePlatform)) - { - Agenda.AddTarget("BootstrapPackagedGame", BootstrapPackagedGamePlatform, UnrealBuildTool.UnrealTargetConfiguration.Shipping); - } - } - } - if (Params.CrashReporter && !Params.Rocket) - { - foreach (var CrashReportPlatform in CrashReportPlatforms) - { - if (UnrealBuildTool.UnrealBuildTool.PlatformSupportsCrashReporter(CrashReportPlatform)) - { - Agenda.AddTarget("CrashReportClient", CrashReportPlatform, UnrealTargetConfiguration.Shipping); - } - } - } - if (Params.HasProgramTargets && !Params.Rocket) - { - foreach (var BuildConfig in Params.ClientConfigsToBuild) - { - foreach (var ClientPlatform in Params.ClientTargetPlatforms) - { - Agenda.AddTargets(Params.ProgramTargets.ToArray(), ClientPlatform, BuildConfig, Params.CodeBasedUprojectPath); - } - } - } - UE4Build.Build(Agenda, InDeleteBuildProducts: Params.Clean, InUpdateVersionFiles: WorkingCL > 0); - - if (WorkingCL > 0) // only move UAT files if we intend to check in some build products - { - UE4Build.AddUATFilesToBuildProducts(); - } - UE4Build.CheckBuildProducts(UE4Build.BuildProductFiles); - - if (WorkingCL > 0) - { - // Sign everything we built - CodeSign.SignMultipleIfEXEOrDLL(Command, UE4Build.BuildProductFiles); - - // Open files for add or edit - UE4Build.AddBuildProductsToChangelist(WorkingCL, UE4Build.BuildProductFiles); - } - - Log("********** BUILD COMMAND COMPLETED **********"); - }*/ - - #endregion -} diff --git a/Engine/Source/Programs/AutomationTool/Scripts/CheckRestrictedFolders.cs b/Engine/Source/Programs/AutomationTool/Scripts/CheckRestrictedFolders.cs new file mode 100644 index 000000000000..1472a1d7d649 --- /dev/null +++ b/Engine/Source/Programs/AutomationTool/Scripts/CheckRestrictedFolders.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnrealBuildTool; + +namespace AutomationTool +{ + [Help("Checks a directory for folders which should not be distributed")] + [Help("BaseDir=", "Path to the base directory containing files to check")] + [Help("Allow=+...", "Specify names of folders which should be excluded from the list")] + class CheckRestrictedFolders : BuildCommand + { + public override ExitCode Execute() + { + // Get the base directory + DirectoryReference BaseDir = new DirectoryReference(ParseParamValue("BaseDir")); + if(!DirectoryReference.Exists(BaseDir)) + { + throw new AutomationException("Base directory '{0}' does not exist", BaseDir); + } + + // Find a list of restricted folders, and remove any names which are explicitly whitelisted + HashSet RestrictedNames = new HashSet(PlatformExports.RestrictedFolderNames, StringComparer.InvariantCultureIgnoreCase); + foreach (string AllowParam in ParseParamValues("Allow")) + { + RestrictedNames.ExceptWith(AllowParam.Split('+')); + } + + // Find all the folders which are problematic + CommandUtils.Log("Searching for folders under {0} named {1}...", BaseDir, String.Join(", ", RestrictedNames)); + List ProblemFolders = new List(); + FindRestrictedFolders(new DirectoryInfo(BaseDir.FullName), RestrictedNames, ProblemFolders); + + // Print out all the restricted folders + if(ProblemFolders.Count > 0) + { + CommandUtils.LogError("Found {0} {1} which should not be distributed:", ProblemFolders.Count, (ProblemFolders.Count == 1) ? "folder" : "folders"); + foreach(DirectoryInfo ProblemFolder in ProblemFolders) + { + CommandUtils.LogError(" {0}{1}...", new DirectoryReference(ProblemFolder).MakeRelativeTo(BaseDir), Path.DirectorySeparatorChar); + } + return ExitCode.Error_Unknown; + } + + // Otherwise return success + CommandUtils.Log("No restricted folders found under {0}", BaseDir); + return ExitCode.Success; + } + + void FindRestrictedFolders(DirectoryInfo CurrentDir, HashSet RestrictedNames, List ProblemFolders) + { + foreach (DirectoryInfo SubDir in CurrentDir.EnumerateDirectories("*", SearchOption.TopDirectoryOnly)) + { + if(RestrictedNames.Contains(SubDir.Name)) + { + ProblemFolders.Add(SubDir); + } + else + { + FindRestrictedFolders(SubDir, RestrictedNames, ProblemFolders); + } + } + } + } +} diff --git a/Engine/Source/Programs/AutomationTool/Scripts/CookCommand.Automation.cs b/Engine/Source/Programs/AutomationTool/Scripts/CookCommand.Automation.cs index 1f46ab7e14ce..127265896112 100644 --- a/Engine/Source/Programs/AutomationTool/Scripts/CookCommand.Automation.cs +++ b/Engine/Source/Programs/AutomationTool/Scripts/CookCommand.Automation.cs @@ -5,6 +5,7 @@ using System.IO; using System.Threading; using System.Reflection; using System.Linq; +using System.Threading.Tasks; using AutomationTool; using UnrealBuildTool; @@ -30,6 +31,8 @@ public partial class Project : CommandUtils string PlatformPlaceholderPattern = ""; string ProjectDir = Params.RawProjectPath.Directory.ToString(); + // NOTE: in UProjectPackagingSettings::PostEditChangeProperty() there is a hardcoded file path/name that is set to match this; + // if you alter this path then you need to update that and likely FBlueprintNativeCodeGenPaths::GetDefaultCodeGenPaths() as well PluginPath = CombinePaths(ProjectDir, "Intermediate", "Plugins", PlatformPlaceholderPattern, "NativizedAssets", "NativizedAssets.uplugin"); ProjectParams.BlueprintPluginKey PluginKey = new ProjectParams.BlueprintPluginKey(); @@ -41,132 +44,6 @@ public partial class Project : CommandUtils return PluginPath; } - static void CopySharedCookedBuildForTarget(ProjectParams Params,TargetPlatformDescriptor TargetPlatform, string CookPlatform) - { - - string ProjectPath = Params.RawProjectPath.FullName; - var LocalPath = CombinePaths(GetDirectoryName(ProjectPath), "Saved", "SharedIterativeBuild", CookPlatform); - - // get network location - ConfigHierarchy Hierarchy = ConfigCache.ReadHierarchy(ConfigHierarchyType.Engine, DirectoryReference.FromFile(Params.RawProjectPath), TargetPlatform.Type); - string CookedBuildPath; - if (Hierarchy.GetString("SharedCookedBuildSettings", "SharedCookedBuildPath", out CookedBuildPath) == false) - { - Log("Unable to copy shared cooked build: SharedCookedBuildPath not set in Engine.ini SharedCookedBuildSettings"); - return ; - } - - string BuildRoot = P4Enabled ? P4Env.BuildRootP4.Replace("/", "+") : ""; - int RecentCL = P4Enabled ? P4Env.Changelist : 0; - - BuildVersion Version; - if (BuildVersion.TryRead(out Version)) - { - RecentCL = Version.Changelist; - BuildRoot = Version.BranchName; - } - - // check to see if we have already synced this build ;) - var SyncedBuildFile = CombinePaths(LocalPath, "SyncedBuild.txt"); - string BuildCL = "Invalid"; - if ( File.Exists(SyncedBuildFile)) - { - BuildCL = File.ReadAllText(SyncedBuildFile); - } - - if (RecentCL == 0 && CookedBuildPath.Contains("[CL]") ) - { - Log("Unable to copy shared cooked build: Unable to determine CL number from P4 or UGS, and is required by SharedCookedBuildPath"); - return; - } - - if (RecentCL == 0 && CookedBuildPath.Contains("[BRANCHNAME]")) - { - Log("Unable to copy shared cooked build: Unable to determine BRANCHNAME number from P4 or UGS, and is required by SharedCookedBuildPath"); - return; - } - - - CookedBuildPath = CookedBuildPath.Replace("[CL]", RecentCL.ToString()); - CookedBuildPath = CookedBuildPath.Replace("[BRANCHNAME]", BuildRoot); - CookedBuildPath = CookedBuildPath.Replace("[PLATFORM]", CookPlatform); - - if ( Directory.Exists(CookedBuildPath) == false ) - { - Log("Unable to copy shared cooked build: Unable to find shared build at location {0} check SharedCookedBuildPath in Engine.ini SharedCookedBuildSettings is correct", CookedBuildPath); - return; - } - - Log("Attempting download of latest shared build CL {0} from location {1}", RecentCL, CookedBuildPath); - - if (BuildCL == RecentCL.ToString()) - { - Log("Already downloaded latest shared build at CL {0}", RecentCL); - return; - } - // delete all the stuff - Log("Deleting previous shared build because it was out of date"); - CommandUtils.DeleteDirectory(LocalPath); - Directory.CreateDirectory(LocalPath); - - - // find all the files in the staged directory - string CookedBuildStagedDirectory = Path.GetFullPath(Path.Combine( CookedBuildPath, "Staged" )); - string LocalBuildStagedDirectory = Path.GetFullPath(Path.Combine(LocalPath, "Staged")); - if (Directory.Exists(CookedBuildStagedDirectory)) - { - foreach (string FileName in Directory.EnumerateFiles(CookedBuildStagedDirectory, "*.*", SearchOption.AllDirectories)) - { - string SourceFileName = Path.GetFullPath(FileName); - string DestFileName = SourceFileName.Replace(CookedBuildStagedDirectory, LocalBuildStagedDirectory); - Directory.CreateDirectory(Path.GetDirectoryName(DestFileName)); - File.Copy(SourceFileName, DestFileName); - } - } - - - string CookedBuildCookedDirectory = Path.Combine(CookedBuildPath, "Cooked"); - CookedBuildCookedDirectory = Path.GetFullPath(CookedBuildCookedDirectory); - string LocalBuildCookedDirectory = Path.Combine(LocalPath, "Cooked"); - LocalBuildCookedDirectory = Path.GetFullPath(LocalBuildCookedDirectory); - if (Directory.Exists(CookedBuildCookedDirectory)) - { - foreach (string FileName in Directory.EnumerateFiles(CookedBuildCookedDirectory, "*.*", SearchOption.AllDirectories)) - { - string SourceFileName = Path.GetFullPath(FileName); - string DestFileName = SourceFileName.Replace(CookedBuildCookedDirectory, LocalBuildCookedDirectory); - Directory.CreateDirectory(Path.GetDirectoryName(DestFileName)); - File.Copy(SourceFileName, DestFileName); - } - } - File.WriteAllText(SyncedBuildFile, RecentCL.ToString()); - return; - } - - static void CopySharedCookedBuild(ProjectParams Params) - { - - if (!Params.NoClient) - { - foreach (var ClientPlatform in Params.ClientTargetPlatforms) - { - // Use the data platform, sometimes we will copy another platform's data - var DataPlatformDesc = Params.GetCookedDataPlatformForClientTarget(ClientPlatform); - string PlatformToCook = Platform.Platforms[DataPlatformDesc].GetCookPlatform(false, Params.Client); - CopySharedCookedBuildForTarget(Params, ClientPlatform, PlatformToCook); - } - } - if (Params.DedicatedServer) - { - foreach (var ServerPlatform in Params.ServerTargetPlatforms) - { - // Use the data platform, sometimes we will copy another platform's data - var DataPlatformDesc = Params.GetCookedDataPlatformForServerTarget(ServerPlatform); - string PlatformToCook = Platform.Platforms[DataPlatformDesc].GetCookPlatform(true, false); - CopySharedCookedBuildForTarget(Params, ServerPlatform, PlatformToCook); - } - } - } public static void Cook(ProjectParams Params) { @@ -318,7 +195,7 @@ public partial class Project : CommandUtils } if ( Params.IterateSharedCookedBuild) { - CopySharedCookedBuild(Params); + SharedCookedBuild.CopySharedCookedBuild(Params); CommandletParams += " -iteratesharedcookedbuild"; } @@ -406,6 +283,8 @@ public partial class Project : CommandUtils } CookCommandlet(Params.RawProjectPath, Params.UE4Exe, Maps, Dirs, InternationalizationPreset, CulturesToCook, CombineCommandletParams(PlatformsToCook.ToArray()), CommandletParams); + + SharedCookedBuild.WaitForCopy(); } catch (Exception Ex) { diff --git a/Engine/Source/Programs/AutomationTool/Scripts/CookTargetCommand.Automation.cs b/Engine/Source/Programs/AutomationTool/Scripts/CookTargetCommand.Automation.cs deleted file mode 100644 index b22a4e303724..000000000000 --- a/Engine/Source/Programs/AutomationTool/Scripts/CookTargetCommand.Automation.cs +++ /dev/null @@ -1,481 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading; -using System.Reflection; -using System.Linq; -using AutomationTool; -using UnrealBuildTool; - -[Help("Cooks a target")] -[Help("Project", "Specify the project with the targets to build.")] -[Help("Target", "Specify a list of target descriptor files for the targets to build, separated by '+' characters (eg. -Target=Game+Client+Server). Default is Game.")] -[Help("TargetPlatforms", "Specify a list of target platforms to build, separated by '+' characters (eg. -TargetPlatforms=Win32+Win64+IOS). Default is Win64.")] -class CookTarget : BuildCommand -{ - private ParamList ParseParamList(string InArgument, string InDefault = null) - { - var ArgumentList = ParseParamValue(InArgument); - if (ArgumentList != null) - { - return new ParamList(ArgumentList.Split('+')); - } - else if (!String.IsNullOrEmpty(InDefault)) - { - return new ParamList(InDefault); - } - return null; - } - - public override void ExecuteBuild() - { - // get the project - var UProjectFileName = ParseParamValue("Project"); - if (UProjectFileName == null) - { - throw new AutomationException("Project was not specified via the -project argument."); - } - - // get the list of platforms - var PlatformList = ParseParamList("TargetPlatforms", "WindowsNoEditor"); - - - /*foreach (string Platform in PlatformList) - { - TargetPlatforms.Add((UnrealTargetPlatform)Enum.Parse(typeof(UnrealTargetPlatform), Platform, true)); - }*/ - - // get the list of maps - - // parse any extra parameters - bool bCookOnTheFly = ParseParam("CookOnTheFly"); - string ExecutableName = ParseParamValue("ExeCmd", "UE4Editor.exe"); - - // add the target platforms to the cook agenda - string Targets = ""; - bool bFirstTarget = true; - foreach ( var PlatformTarget in PlatformList) - { - if ( bFirstTarget) - { - Targets += PlatformTarget; - bFirstTarget = false; - } - else - { - Targets += "+" + PlatformTarget; - } - } - - // set up the platform list - - // start the server - if (bCookOnTheFly) - { - RunCookOnTheFlyServer(UProjectFileName, ExecutableName, Targets); - } - else - { - RunCookCommandlet(UProjectFileName, ExecutableName, Targets); - } - } - - private void RunCookCommandlet(string InUProjectFile, string InExecutable, string InTargets, string InArgs = "") - { - string Params = String.Format("-targetplatform={0} {1}", InTargets, InArgs); - FileReference UProjectFile = new FileReference(InUProjectFile); - RunCommandlet(UProjectFile, InExecutable, "cook", Params); - } - - private void RunCookOnTheFlyServer(string InUProjectFile, string InExecutable, string InTargets, string InArgs = "") - { - var ServerApp = HostPlatform.Current.GetUE4ExePath(InExecutable); - string Params = String.Format("\"{0}\" -run=cook -cookonthefly -targetplatform={1} {2}", InUProjectFile, InTargets, InArgs); - Project.Run(ServerApp, Params, null, ERunOptions.AllowSpew | ERunOptions.NoWaitForExit | ERunOptions.AppMustExist | ERunOptions.NoStdOutRedirect); - } - -/*#region Cook Command - - public static void Cook(ProjectParams Params) - { - if ((!Params.Cook && !(Params.CookOnTheFly && !Params.SkipServer)) || Params.SkipCook) - { - return; - } - Params.ValidateAndLog(); - - Log("********** COOK COMMAND STARTED **********"); - - string UE4EditorExe = HostPlatform.Current.GetUE4ExePath(Params.UE4Exe); - if (!FileExists(UE4EditorExe)) - { - throw new AutomationException("Missing " + UE4EditorExe + " executable. Needs to be built first."); - } - - if (Params.CookOnTheFly && !Params.SkipServer) - { - if (Params.HasDLCName) - { - throw new AutomationException("Cook on the fly doesn't support cooking dlc"); - } - if (Params.ClientTargetPlatforms.Count > 0) - { - var LogFolderOutsideOfSandbox = GetLogFolderOutsideOfSandbox(); - if (!GlobalCommandLine.Installed) - { - // In the installed runs, this is the same folder as CmdEnv.LogFolder so delete only in not-installed - DeleteDirectory(LogFolderOutsideOfSandbox); - CreateDirectory(LogFolderOutsideOfSandbox); - } - - String COTFCommandLine = Params.RunCommandline; - if (Params.IterativeCooking) - { - COTFCommandLine += " -iterate"; - } - if (Params.UseDebugParamForEditorExe) - { - COTFCommandLine += " -debug"; - } - - var ServerLogFile = CombinePaths(LogFolderOutsideOfSandbox, "Server.log"); - Platform ClientPlatformInst = Params.ClientTargetPlatformInstances[0]; - string TargetCook = ClientPlatformInst.GetCookPlatform(false, Params.HasDedicatedServerAndClient, Params.CookFlavor); - ServerProcess = RunCookOnTheFlyServer(Params.RawProjectPath, Params.NoClient ? "" : ServerLogFile, TargetCook, COTFCommandLine); - - if (ServerProcess != null) - { - Log("Waiting a few seconds for the server to start..."); - Thread.Sleep(5000); - } - } - else - { - throw new AutomationException("Failed to run, client target platform not specified"); - } - } - else - { - var PlatformsToCook = new HashSet(); - - if (!Params.NoClient) - { - foreach (var ClientPlatform in Params.ClientTargetPlatforms) - { - // Use the data platform, sometimes we will copy another platform's data - var DataPlatform = Params.GetCookedDataPlatformForClientTarget(ClientPlatform); - PlatformsToCook.Add(Params.GetTargetPlatformInstance(DataPlatform).GetCookPlatform(false, Params.Client, Params.CookFlavor)); - } - } - if (Params.DedicatedServer) - { - foreach (var ServerPlatform in Params.ServerTargetPlatforms) - { - // Use the data platform, sometimes we will copy another platform's data - var DataPlatform = Params.GetCookedDataPlatformForServerTarget(ServerPlatform); - PlatformsToCook.Add(Params.GetTargetPlatformInstance(DataPlatform).GetCookPlatform(true, false, Params.CookFlavor)); - } - } - - if (Params.Clean.HasValue && Params.Clean.Value && !Params.IterativeCooking) - { - Log("Cleaning cooked data."); - CleanupCookedData(PlatformsToCook.ToList(), Params); - } - - // cook the set of maps, or the run map, or nothing - string[] Maps = null; - if (Params.HasMapsToCook) - { - Maps = Params.MapsToCook.ToArray(); - foreach (var M in Maps) - { - Log("HasMapsToCook " + M.ToString()); - } - foreach (var M in Params.MapsToCook) - { - Log("Params.HasMapsToCook " + M.ToString()); - } - } - - string[] Dirs = null; - if (Params.HasDirectoriesToCook) - { - Dirs = Params.DirectoriesToCook.ToArray(); - } - - string InternationalizationPreset = null; - if (Params.HasInternationalizationPreset) - { - InternationalizationPreset = Params.InternationalizationPreset; - } - - string[] Cultures = null; - if (Params.HasCulturesToCook) - { - Cultures = Params.CulturesToCook.ToArray(); - } - - try - { - var CommandletParams = IsBuildMachine ? "-buildmachine -fileopenlog" : "-fileopenlog"; - if (Params.UnversionedCookedContent) - { - CommandletParams += " -unversioned"; - } - if (Params.FastCook) - { - CommandletParams += " -FastCook"; - } - if (Params.UseDebugParamForEditorExe) - { - CommandletParams += " -debug"; - } - if (Params.Manifests) - { - CommandletParams += " -manifests"; - } - if (Params.IterativeCooking) - { - CommandletParams += " -iterate"; - } - if (Params.CookMapsOnly) - { - CommandletParams += " -mapsonly"; - } - if (Params.CookAll) - { - CommandletParams += " -cookall"; - } - if (Params.CookMapsOnly) - { - CommandletParams += " -mapsonly"; - } - if (Params.HasCreateReleaseVersion) - { - CommandletParams += " -createreleaseversion=" + Params.CreateReleaseVersion; - } - if ( Params.SkipCookingEditorContent) - { - CommandletParams += " -skipeditorcontent"; - } - if ( Params.NumCookersToSpawn != 0) - { - CommandletParams += " -numcookerstospawn=" + Params.NumCookersToSpawn; - - } - if (Params.HasDLCName) - { - CommandletParams += " -dlcname=" + Params.DLCName; - if ( !Params.DLCIncludeEngineContent ) - { - CommandletParams += " -errorOnEngineContentUse"; - } - } - // don't include the based on release version unless we are cooking dlc or creating a new release version - // in this case the based on release version is used in packaging - if (Params.HasBasedOnReleaseVersion && (Params.HasDLCName || Params.HasCreateReleaseVersion)) - { - CommandletParams += " -basedonreleaseversion=" + Params.BasedOnReleaseVersion; - } - // if we are not going to pak but we specified compressed then compress in the cooker ;) - // otherwise compress the pak files - if (!Params.Pak && !Params.SkipPak && Params.Compressed) - { - CommandletParams += " -compressed"; - } - if (Params.HasAdditionalCookerOptions) - { - string FormatedAdditionalCookerParams = Params.AdditionalCookerOptions.TrimStart(new char[] { '\"', ' ' }).TrimEnd(new char[] { '\"', ' ' }); - CommandletParams += " "; - CommandletParams += FormatedAdditionalCookerParams; - } - - if (!Params.NoClient) - { - var MapsList = Maps == null ? new List() : Maps.ToList(); - foreach (var ClientPlatform in Params.ClientTargetPlatforms) - { - var DataPlatform = Params.GetCookedDataPlatformForClientTarget(ClientPlatform); - CommandletParams += (Params.GetTargetPlatformInstance(DataPlatform).GetCookExtraCommandLine(Params)); - MapsList.AddRange((Params.GetTargetPlatformInstance(ClientPlatform).GetCookExtraMaps())); - } - Maps = MapsList.ToArray(); - } - - CookCommandlet(Params.RawProjectPath, Params.UE4Exe, Maps, Dirs, InternationalizationPreset, Cultures, CombineCommandletParams(PlatformsToCook.ToArray()), CommandletParams); - } - catch (Exception Ex) - { - if (Params.IgnoreCookErrors) - { - LogWarning("Ignoring cook failure."); - } - else - { - // Delete cooked data (if any) as it may be incomplete / corrupted. - Log("Cook failed. Deleting cooked data."); - CleanupCookedData(PlatformsToCook.ToList(), Params); - throw new AutomationException(ExitCode.Error_UnknownCookFailure, Ex, "Cook failed."); - } - } - - if (Params.HasDiffCookedContentPath) - { - try - { - DiffCookedContent(Params); - } - catch ( Exception Ex ) - { - // Delete cooked data (if any) as it may be incomplete / corrupted. - Log("Cook failed. Deleting cooked data."); - CleanupCookedData(PlatformsToCook.ToList(), Params); - throw new AutomationException(ExitCode.Error_UnknownCookFailure, Ex, "Cook failed."); - } - } - - } - - - Log("********** COOK COMMAND COMPLETED **********"); - } - - private static void DiffCookedContent( ProjectParams Params) - { - List PlatformsToCook = Params.ClientTargetPlatforms; - string ProjectPath = Path.GetFullPath(Params.RawProjectPath); - - var CookedSandboxesPath = CombinePaths(GetDirectoryName(ProjectPath), "Saved", "Cooked"); - - for (int CookPlatformIndex = 0; CookPlatformIndex < PlatformsToCook.Count; ++CookPlatformIndex) - { - // temporary directory to save the pak file to (pak file is usually not local and on network drive) - var TemporaryPakPath = CombinePaths(GetDirectoryName(ProjectPath), "Saved", "Temp", "LocalPKG"); - // extracted files from pak file - var TemporaryFilesPath = CombinePaths(GetDirectoryName(ProjectPath), "Saved", "Temp", "LocalFiles"); - - - - try - { - Directory.Delete(TemporaryPakPath, true); - Directory.Delete(TemporaryFilesPath, true); - } - catch(Exception ) - { - Log("Failed deleting temporary directories "+TemporaryPakPath+" "+TemporaryFilesPath+" continuing."); - } - - Directory.CreateDirectory(TemporaryPakPath); - Directory.CreateDirectory(TemporaryFilesPath); - - Platform CurrentPlatform = Params.GetTargetPlatformInstance(PlatformsToCook[CookPlatformIndex]); - - string SourceCookedContentPath = Params.DiffCookedContentPath; - - List PakFiles = new List(); - - if (Path.HasExtension(SourceCookedContentPath) && (!SourceCookedContentPath.EndsWith(".pak"))) - { - // must be a per platform pkg file try this - CurrentPlatform.ExtractPackage(Params, Params.DiffCookedContentPath, TemporaryPakPath); - - // find the pak file - PakFiles = Directory.EnumerateFiles(TemporaryPakPath, "*.pak").ToList(); - } - - string CookPlatformString = CurrentPlatform.GetCookPlatform(false, Params.HasDedicatedServerAndClient, Params.CookFlavor); - - if (!Path.HasExtension(SourceCookedContentPath)) - { - // try find the pak or pkg file - string SourceCookedContentPlatformPath = CombinePaths(SourceCookedContentPath, CookPlatformString); - - foreach (var PakName in Directory.EnumerateFiles(SourceCookedContentPlatformPath, "*.pak")) - { - string TemporaryPakFilename = CombinePaths(TemporaryPakPath, Path.GetFileName(PakName )); - File.Copy(PakName , TemporaryPakFilename); - PakFiles.Add(TemporaryPakFilename); - } - } - else if (SourceCookedContentPath.EndsWith(".pak")) - { - string TemporaryPakFilename = CombinePaths(TemporaryPakPath, Path.GetFileName(SourceCookedContentPath)); - File.Copy(SourceCookedContentPath, TemporaryPakFilename); - PakFiles.Add(TemporaryPakFilename); - } - - - string FullCookPath = CombinePaths(CookedSandboxesPath, CookPlatformString); - - var UnrealPakExe = CombinePaths(CmdEnv.LocalRoot, "Engine/Binaries/Win64/UnrealPak.exe"); - - - foreach (var Name in PakFiles) - { - string UnrealPakParams = Name + " -Extract " + " " + TemporaryFilesPath; - - RunAndLog(CmdEnv, UnrealPakExe, UnrealPakParams, Options: ERunOptions.Default | ERunOptions.UTF8Output); - } - - const string RootFailedContentDirectory = "\\\\epicgames.net\\root\\Developers\\Daniel.Lamb\\"; - - string FailedContentDirectory = CombinePaths( RootFailedContentDirectory, CommandUtils.P4Env.BuildRootP4 + CommandUtils.P4Env.ChangelistString, Params.ShortProjectName, CookPlatformString ); - - - // diff the content - List AllFiles = Directory.EnumerateFiles(FullCookPath, "*.uasset", System.IO.SearchOption.AllDirectories).ToList(); - AllFiles.AddRange(Directory.EnumerateFiles(FullCookPath, "*.map", System.IO.SearchOption.AllDirectories).ToList()); - foreach (string SourceFilename in AllFiles) - { - // Filename.StartsWith( CookedSandboxesPath ); - string RelativeFilename = SourceFilename.Remove(0, FullCookPath.Length); - - string DestFilename = TemporaryFilesPath + RelativeFilename; - - byte[] SourceFile = File.ReadAllBytes(SourceFilename); - - byte[] DestFile = File.ReadAllBytes(DestFilename); - - if ( SourceFile.LongLength == DestFile.LongLength ) - { - for ( long Index = 0; Index < SourceFile.LongLength; ++Index ) - { - if ( SourceFile[Index] != DestFile[Index] ) - { - Log("Diff cooked content failed on file " +SourceFilename + " when comparing against "+DestFilename + " at offset " + Index.ToString() ); - string SavedSourceFilename = CombinePaths( FailedContentDirectory, "Source" + Path.GetFileName(SourceFilename)); - string SavedDestFilename = CombinePaths( FailedContentDirectory, "Dest" + Path.GetFileName(DestFilename)); - File.Copy(SourceFilename, SavedSourceFilename); - File.Copy(DestFilename, SavedDestFilename); - Log("Content temporarily saved to " +SavedSourceFilename + " and "+SavedDestFilename + " at offset " + Index.ToString() ); - break; - } - } - } - else - { - Log("Diff cooked content failed on file " +SourceFilename + " when comparing against "+DestFilename + " files are different sizes " + SourceFile.LongLength.ToString() + " " + DestFile.LongLength.ToString() ); - } - } - } - } - - private static void CleanupCookedData(List PlatformsToCook, ProjectParams Params) - { - var ProjectPath = Path.GetFullPath(Params.RawProjectPath); - var CookedSandboxesPath = CombinePaths(GetDirectoryName(ProjectPath), "Saved", "Cooked"); - var CleanDirs = new string[PlatformsToCook.Count]; - for (int DirIndex = 0; DirIndex < CleanDirs.Length; ++DirIndex) - { - CleanDirs[DirIndex] = CombinePaths(CookedSandboxesPath, PlatformsToCook[DirIndex]); - } - - const bool bQuiet = true; - DeleteDirectory(bQuiet, CleanDirs); - } - - #endregion */ -} diff --git a/Engine/Source/Programs/AutomationTool/Scripts/CopyBuildToStagingDirectory.Automation.cs b/Engine/Source/Programs/AutomationTool/Scripts/CopyBuildToStagingDirectory.Automation.cs index f9f88bf2eb15..5da09e4caab2 100644 --- a/Engine/Source/Programs/AutomationTool/Scripts/CopyBuildToStagingDirectory.Automation.cs +++ b/Engine/Source/Programs/AutomationTool/Scripts/CopyBuildToStagingDirectory.Automation.cs @@ -98,19 +98,19 @@ public partial class Project : CommandUtils return Result; } - static public void RunUnrealPak(Dictionary UnrealPakResponseFile, string OutputLocation, string PakOrderFileLocation, string PlatformOptions, bool Compressed, bool EncryptIniFiles, bool EncryptEverything, bool EncryptPakIndex, String PatchSourceContentPath, String EngineDir, String ProjectDir, String Platform) + static public void RunUnrealPak(Dictionary UnrealPakResponseFile, FileReference OutputLocation, FileReference PakOrderFileLocation, string PlatformOptions, bool Compressed, bool EncryptIniFiles, bool EncryptEverything, bool EncryptPakIndex, String PatchSourceContentPath, String EngineDir, String ProjectDir, String Platform) { if (UnrealPakResponseFile.Count < 1) { return; } - string PakName = Path.GetFileNameWithoutExtension(OutputLocation); + string PakName = Path.GetFileNameWithoutExtension(OutputLocation.FullName); string UnrealPakResponseFileName = CombinePaths(CmdEnv.LogFolder, "PakList_" + PakName + ".txt"); WritePakResponseFile(UnrealPakResponseFileName, UnrealPakResponseFile, Compressed, EncryptIniFiles, EncryptEverything); var UnrealPakExe = CombinePaths(CmdEnv.LocalRoot, "Engine/Binaries/Win64/UnrealPak.exe"); Log("Running UnrealPak *******"); - string CmdLine = CommandUtils.MakePathSafeToUseWithCommandLine(OutputLocation) + " -create=" + CommandUtils.MakePathSafeToUseWithCommandLine(UnrealPakResponseFileName); + string CmdLine = CommandUtils.MakePathSafeToUseWithCommandLine(OutputLocation.FullName) + " -create=" + CommandUtils.MakePathSafeToUseWithCommandLine(UnrealPakResponseFileName); string LogFileName = CombinePaths(CmdEnv.LogFolder, "PakLog_" + PakName + ".log"); CmdLine += String.Format(" -encryptionini -enginedir=\"{0}\" -projectdir=\"{1}\" -platform={2} -abslog=\"{3}\"", EngineDir, ProjectDir, Platform, LogFileName); @@ -119,7 +119,7 @@ public partial class Project : CommandUtils { CmdLine += " -installed"; } - CmdLine += " -order=" + CommandUtils.MakePathSafeToUseWithCommandLine(PakOrderFileLocation); + CmdLine += " -order=" + CommandUtils.MakePathSafeToUseWithCommandLine(PakOrderFileLocation.FullName); if (GlobalCommandLine.UTF8Output) { CmdLine += " -UTF8Output"; @@ -134,59 +134,39 @@ public partial class Project : CommandUtils } CmdLine += " -multiprocess"; // Prevents warnings about being unable to write to config files CmdLine += PlatformOptions; - RunAndLog(CmdEnv, UnrealPakExe, CmdLine, Options: ERunOptions.Default | ERunOptions.UTF8Output); + string UnrealPakLogFileName = "UnrealPak_" + PakName; + RunAndLog(CmdEnv, UnrealPakExe, CmdLine, LogName: UnrealPakLogFileName, Options: ERunOptions.Default | ERunOptions.UTF8Output); Log("UnrealPak Done *******"); } static public void LogDeploymentContext(DeploymentContext SC) { LogLog("Deployment Context **************"); - LogLog("ArchiveDirectory = {0}", SC.ArchiveDirectory); - LogLog("RawProjectPath = {0}", SC.RawProjectPath); + LogLog("ProjectFile = {0}", SC.RawProjectPath); + LogLog("ArchiveDir = {0}", SC.ArchiveDirectory); LogLog("IsCodeBasedUprojectFile = {0}", SC.IsCodeBasedProject); LogLog("DedicatedServer = {0}", SC.DedicatedServer); LogLog("Stage = {0}", SC.Stage); LogLog("StageTargetPlatform = {0}", SC.StageTargetPlatform.PlatformType.ToString()); - LogLog("LocalRoot = {0}", SC.LocalRoot); - LogLog("ProjectRoot = {0}", SC.ProjectRoot); + LogLog("InputRootDir = {0}", SC.LocalRoot); + LogLog("InputProjectDir = {0}", SC.ProjectRoot); LogLog("PlatformDir = {0}", SC.PlatformDir); - LogLog("StageProjectRoot = {0}", SC.StageProjectRoot); + LogLog("StagedOutputDir = {0}", SC.StageDirectory); LogLog("ShortProjectName = {0}", SC.ShortProjectName); - LogLog("StageDirectory = {0}", SC.StageDirectory); - LogLog("SourceRelativeProjectRoot = {0}", SC.SourceRelativeProjectRoot); - LogLog("RelativeProjectRootForStage = {0}", SC.RelativeProjectRootForStage); - LogLog("RelativeProjectRootForUnrealPak = {0}", SC.RelativeProjectRootForUnrealPak); LogLog("ProjectArgForCommandLines = {0}", SC.ProjectArgForCommandLines); - LogLog("RuntimeRootDir = {0}", SC.RuntimeRootDir); - LogLog("RuntimeProjectRootDir = {0}", SC.RuntimeProjectRootDir); - LogLog("UProjectCommandLineArgInternalRoot = {0}", SC.UProjectCommandLineArgInternalRoot); + LogLog("RunRootDir = {0}", SC.RuntimeRootDir); + LogLog("RunProjectDir = {0}", SC.RuntimeProjectRootDir); LogLog("PakFileInternalRoot = {0}", SC.PakFileInternalRoot); - LogLog("UnrealFileServerInternalRoot = {0}", SC.UnrealFileServerInternalRoot); LogLog("PlatformUsesChunkManifests = {0}", SC.PlatformUsesChunkManifests); LogLog("End Deployment Context **************"); } - public static Dictionary ConvertToLower(Dictionary Mapping) + public static Dictionary ConvertToLower(Dictionary Mapping) { - var Result = new Dictionary(); - foreach (var Pair in Mapping) + Dictionary Result = new Dictionary(); + foreach (KeyValuePair Pair in Mapping) { - Result.Add(Pair.Key, Pair.Value.ToLowerInvariant()); - } - return Result; - } - - public static Dictionary> ConvertToLower(Dictionary> Mapping) - { - var Result = new Dictionary>(); - foreach (var Pair in Mapping) - { - List NewList = new List(); - foreach(string s in Pair.Value) - { - NewList.Add(s.ToLowerInvariant()); - } - Result.Add(Pair.Key, NewList); + Result.Add(Pair.Key.ToLowerInvariant(), Pair.Value); } return Result; } @@ -197,20 +177,16 @@ public partial class Project : CommandUtils if (BuildPlatform.DeployLowerCaseFilenames(false)) { - SC.NonUFSStagingFiles = ConvertToLower(SC.NonUFSStagingFiles); - SC.NonUFSStagingFilesDebug = ConvertToLower(SC.NonUFSStagingFilesDebug); - } - if (Params.UsePak(SC.StageTargetPlatform) && BuildPlatform.DeployPakInternalLowerCaseFilenames()) - { - SC.UFSStagingFiles = ConvertToLower(SC.UFSStagingFiles); + SC.FilesToStage.NonUFSStagingFiles = ConvertToLower(SC.FilesToStage.NonUFSStagingFiles); + SC.FilesToStage.NonUFSStagingFilesDebug = ConvertToLower(SC.FilesToStage.NonUFSStagingFilesDebug); } else if (!Params.UsePak(SC.StageTargetPlatform) && BuildPlatform.DeployLowerCaseFilenames(true)) { - SC.UFSStagingFiles = ConvertToLower(SC.UFSStagingFiles); + SC.FilesToStage.UFSStagingFiles = ConvertToLower(SC.FilesToStage.UFSStagingFiles); } } - private static void StageLocalizationDataForTarget(DeploymentContext SC, List CulturesToStage, string SourceDirectory, string DestinationDirectory = null, bool bRemap = true) + private static void StageLocalizationDataForTarget(DeploymentContext SC, List CulturesToStage, DirectoryReference SourceDirectory, StagedDirectoryReference DestinationDirectory = null, bool bRemap = true) { SC.StageFiles(StagedFileType.UFS, SourceDirectory, "*.locmeta", false, null, DestinationDirectory, true, bRemap); foreach (string Culture in CulturesToStage) @@ -219,7 +195,7 @@ public partial class Project : CommandUtils } } - private static void StageLocalizationDataForCulture(DeploymentContext SC, string CultureName, string SourceDirectory, string DestinationDirectory = null, bool bRemap = true) + private static void StageLocalizationDataForCulture(DeploymentContext SC, string CultureName, DirectoryReference SourceDirectory, StagedDirectoryReference DestinationDirectory = null, bool bRemap = true) { CultureName = CultureName.Replace('-', '_'); @@ -244,15 +220,14 @@ public partial class Project : CommandUtils PotentialParentCultures.Add(LocaleTags[0]); } - string[] FoundDirectories = CommandUtils.FindDirectories(true, "*", false, SourceDirectory); - foreach (string FoundDirectory in FoundDirectories) + foreach(DirectoryReference FoundDirectory in DirectoryReference.EnumerateDirectories(SourceDirectory, "*", SearchOption.TopDirectoryOnly)) { - string DirectoryName = CommandUtils.GetLastDirectoryName(FoundDirectory); + string DirectoryName = CommandUtils.GetLastDirectoryName(FoundDirectory.FullName); string CanonicalizedPotentialCulture = DirectoryName.Replace('-', '_'); if (PotentialParentCultures.Contains(CanonicalizedPotentialCulture)) { - SC.StageFiles(StagedFileType.UFS, CombinePaths(SourceDirectory, DirectoryName), "*.locres", true, null, DestinationDirectory != null ? CombinePaths(DestinationDirectory, DirectoryName) : null, true, bRemap); + SC.StageFiles(StagedFileType.UFS, FoundDirectory, "*.locres", true, null, (DestinationDirectory != null) ? StagedDirectoryReference.Combine(DestinationDirectory, DirectoryName) : null, true, bRemap); } } } @@ -273,43 +248,37 @@ public partial class Project : CommandUtils //check( Params.HasDLCName == false ); // stage all the previously staged files - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.ProjectRoot, "Saved", "SharedIterativeBuild", SC.CookPlatform, "Staged"), "*", true, null, "", true); // remap to the root directory + SC.StageFiles(StagedFileType.NonUFS, new DirectoryReference(CombinePaths(SC.ProjectRoot.FullName, "Saved", "SharedIterativeBuild", SC.CookPlatform, "Staged")), "*", true, null, new StagedDirectoryReference(""), true); // remap to the root directory } if (Params.HasDLCName) { string DLCName = Params.DLCName; // Making a plugin, grab the binaries too - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.ProjectRoot, "Plugins", DLCName), "*.uplugin", false, null, null, true); - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.ProjectRoot, "Plugins", DLCName, "Binaries"), "libUE4-*.so", true, null, null, true); - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.ProjectRoot, "Plugins", DLCName, "Binaries"), "UE4-*.dll", true, null, null, true); - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.ProjectRoot, "Plugins", DLCName, "Binaries"), "libUE4Server-*.so", true, null, null, true); - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.ProjectRoot, "Plugins", DLCName, "Binaries"), "UE4Server-*.dll", true, null, null, true); + SC.StageFiles(StagedFileType.NonUFS, DirectoryReference.Combine(SC.ProjectRoot, "Plugins", DLCName), "*.uplugin", false, null, null, true); + SC.StageFiles(StagedFileType.NonUFS, DirectoryReference.Combine(SC.ProjectRoot, "Plugins", DLCName, "Binaries"), "libUE4-*.so", true, null, null, true); + SC.StageFiles(StagedFileType.NonUFS, DirectoryReference.Combine(SC.ProjectRoot, "Plugins", DLCName, "Binaries"), "UE4-*.dll", true, null, null, true); + SC.StageFiles(StagedFileType.NonUFS, DirectoryReference.Combine(SC.ProjectRoot, "Plugins", DLCName, "Binaries"), "libUE4Server-*.so", true, null, null, true); + SC.StageFiles(StagedFileType.NonUFS, DirectoryReference.Combine(SC.ProjectRoot, "Plugins", DLCName, "Binaries"), "UE4Server-*.dll", true, null, null, true); // Put all of the cooked dir into the staged dir - string PlatformCookDir = String.IsNullOrEmpty(Params.CookOutputDir)? CombinePaths(SC.ProjectRoot, "Plugins", DLCName, "Saved", "Cooked", SC.CookPlatform) : CombinePaths(Params.CookOutputDir, SC.CookPlatform); + DirectoryReference PlatformCookDir = String.IsNullOrEmpty(Params.CookOutputDir)? DirectoryReference.Combine(SC.ProjectRoot, "Plugins", DLCName, "Saved", "Cooked", SC.CookPlatform) : DirectoryReference.Combine(new DirectoryReference(Params.CookOutputDir), SC.CookPlatform); string[] ExcludeWildCards = null; //{"AssetRegistry.bin"}; // Stage any loose files in the root folder // TODO: not sure if we should stage the loose files if we have pak files enabled... - SC.StageFiles(StagedFileType.UFS, PlatformCookDir, "*", false, ExcludeWildCards, SC.RelativeProjectRootForStage, true, !Params.UsePak(SC.StageTargetPlatform)); + SC.StageFiles(StagedFileType.UFS, PlatformCookDir, "*", false, ExcludeWildCards, NewPath: SC.RelativeProjectRootForStage, bAllowNone: true, bRemap: !Params.UsePak(SC.StageTargetPlatform)); // Stage each sub directory separately so that we can skip Engine if need be - string[] SubDirs = CommandUtils.FindDirectories(true, "*", false, PlatformCookDir); - - foreach (string SubDir in SubDirs) + foreach(DirectoryReference SubDir in DirectoryReference.EnumerateDirectories(PlatformCookDir)) { + StagedDirectoryReference MountPoint = new StagedDirectoryReference(SubDir.MakeRelativeTo(PlatformCookDir)); // Dedicated server cook doesn't save shaders so no Engine dir is created - if ((!SC.DedicatedServer) && (!Params.DLCIncludeEngineContent) && CommandUtils.GetLastDirectoryName(SubDir).Equals("Engine", StringComparison.InvariantCultureIgnoreCase)) + if ((!SC.DedicatedServer) && (!Params.DLCIncludeEngineContent) && MountPoint == new StagedDirectoryReference("Engine")) { continue; } // SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.ProjectRoot, "Plugins", DLCName, "Saved", "Cooked", SC.CookPlatform), "*", true, new[] { CommandUtils.CombinePaths("Engine", "*") }, "", true, !Params.UsePak(SC.StageTargetPlatform)); - string MountPoint = SubDir.Substring(PlatformCookDir.Length); - if ( MountPoint.StartsWith("\\") || MountPoint.StartsWith("/") ) - { - MountPoint = MountPoint.Substring(1); - } SC.StageFiles(StagedFileType.UFS, SubDir, "*", true, ExcludeWildCards, MountPoint, true, !Params.UsePak(SC.StageTargetPlatform)); //SC.StageFiles(StagedFileType.UFS, SubDir, "*", true, ExcludeWildCards, SC.RelativeProjectRootForStage, true, !Params.UsePak(SC.StageTargetPlatform)); } @@ -317,25 +286,21 @@ public partial class Project : CommandUtils return; } - - ThisPlatform.GetFilesToDeployOrStage(Params, SC); - - - // Stage any extra runtime dependencies from the receipts - foreach(StageTarget Target in SC.StageTargets) + if (!Params.IterateSharedBuildUsePrecompiledExe) { - SC.StageRuntimeDependenciesFromReceipt(Target.Receipt, Target.RequireFilesExist, Params.UsePak(SC.StageTargetPlatform)); - } + ThisPlatform.GetFilesToDeployOrStage(Params, SC); + // Stage any extra runtime dependencies from the receipts + foreach (StageTarget Target in SC.StageTargets) + { + SC.StageRuntimeDependenciesFromReceipt(Target.Receipt, Target.RequireFilesExist, Params.UsePak(SC.StageTargetPlatform)); + } + } // Get the build.properties file // this file needs to be treated as a UFS file for casing, but NonUFS for being put into the .pak file // @todo: Maybe there should be a new category - UFSNotForPak - string BuildPropertiesPath = CombinePaths(SC.LocalRoot, "Engine/Build"); - if (SC.StageTargetPlatform.DeployLowerCaseFilenames(true)) - { - BuildPropertiesPath = BuildPropertiesPath.ToLowerInvariant(); - } - SC.StageFiles(StagedFileType.NonUFS, BuildPropertiesPath, "Build.version", false, null, null, true); + DirectoryReference BuildPropertiesPath = DirectoryReference.Combine(SC.ProjectRoot, "Engine", "Build"); + SC.StageFiles(StagedFileType.NonUFS, BuildPropertiesPath, "Build.version", false, null, null, true, bConvertToLower: SC.StageTargetPlatform.DeployLowerCaseFilenames(true)); // move the UE4Commandline.txt file to the root of the stage // this file needs to be treated as a UFS file for casing, but NonUFS for being put into the .pak file @@ -345,11 +310,11 @@ public partial class Project : CommandUtils { CommandLineFile = CommandLineFile.ToLowerInvariant(); } - SC.StageFiles(StagedFileType.NonUFS, GetIntermediateCommandlineDir(SC), CommandLineFile, false, null, "", true, false); + SC.StageFiles(StagedFileType.NonUFS, GetIntermediateCommandlineDir(SC), CommandLineFile, false, null, new StagedDirectoryReference(""), true, false); ConfigHierarchy PlatformGameConfig = ConfigCache.ReadHierarchy(ConfigHierarchyType.Game, DirectoryReference.FromFile(Params.RawProjectPath), SC.StageTargetPlatform.IniPlatformType); - var ProjectContentRoot = CombinePaths(SC.ProjectRoot, "Content"); - var StageContentRoot = CombinePaths(SC.RelativeProjectRootForStage, "Content"); + DirectoryReference ProjectContentRoot = DirectoryReference.Combine(SC.ProjectRoot, "Content"); + StagedDirectoryReference StageContentRoot = StagedDirectoryReference.Combine(SC.RelativeProjectRootForStage, "Content"); if (!Params.CookOnTheFly && !Params.SkipCookOnTheFly) // only stage the UFS files if we are not using cook on the fly { @@ -398,46 +363,24 @@ public partial class Project : CommandUtils } // Stage ICU internationalization data from Engine. - SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.LocalRoot, "Engine", "Content", "Internationalization", InternationalizationPreset), "*", true, null, CombinePaths("Engine", "Content", "Internationalization"), true, !Params.UsePak(SC.StageTargetPlatform)); + SC.StageFiles(StagedFileType.UFS, DirectoryReference.Combine(SC.LocalRoot, "Engine", "Content", "Internationalization", InternationalizationPreset), "*", true, null, new StagedDirectoryReference("Engine/Content/Internationalization"), true, !Params.UsePak(SC.StageTargetPlatform)); // Engine ufs (content) - SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.LocalRoot, "Engine/Config"), "*", true, null, null, false, !Params.UsePak(SC.StageTargetPlatform)); // TODO: Exclude localization data generation config files. + SC.StageFiles(StagedFileType.UFS, DirectoryReference.Combine(SC.LocalRoot, "Engine", "Config"), "*", true, null, null, false, !Params.UsePak(SC.StageTargetPlatform)); // TODO: Exclude localization data generation config files. - StageLocalizationDataForTarget(SC, CulturesToStage, CombinePaths(SC.LocalRoot, "Engine/Content/Localization/Engine"), null, !Params.UsePak(SC.StageTargetPlatform)); + StageLocalizationDataForTarget(SC, CulturesToStage, DirectoryReference.Combine(SC.LocalRoot, "Engine", "Content", "Localization", "Engine"), null, !Params.UsePak(SC.StageTargetPlatform)); // Game ufs (content) - SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.ProjectRoot), "*.uproject", false, null, CombinePaths(SC.RelativeProjectRootForStage), true, !Params.UsePak(SC.StageTargetPlatform)); + SC.StageFiles(StagedFileType.UFS, SC.ProjectRoot, "*.uproject", false, null, SC.RelativeProjectRootForStage, true, !Params.UsePak(SC.StageTargetPlatform)); - if (SC.StageTargetPlatform.PlatformType != UnrealTargetPlatform.HTML5 && SC.bUseWebsocketNetDriver) - { - var EngineIniPath = Path.Combine(SC.ProjectRoot, "Config", "DefaultEngine.ini"); - var IntermediateEngineIniDir = Path.Combine(GetIntermediateCommandlineDir(SC), SC.RelativeProjectRootForStage, "Config"); - Directory.CreateDirectory(IntermediateEngineIniDir); - var IntermediateEngineIniPath = Path.Combine(IntermediateEngineIniDir, "DefaultEngine.ini"); - List IniLines = new List(); - if (File.Exists(EngineIniPath)) - { - IniLines = File.ReadAllLines(EngineIniPath).ToList(); - } - IniLines.Add("[/Script/Engine.GameEngine]"); - IniLines.Add("!NetDriverDefinitions=ClearArray"); - IniLines.Add("+NetDriverDefinitions=(DefName=\"GameNetDriver\", DriverClassName=\"/Script/HTML5Networking.WebSocketNetDriver\", DriverClassNameFallback=\"/Script/HTML5Networking.WebSocketNetDriver\")"); - File.WriteAllLines(IntermediateEngineIniPath, IniLines); - SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.ProjectRoot, "Config"), "*", true, new string[] {"DefaultEngine.ini"}, CombinePaths(SC.RelativeProjectRootForStage, "Config"), true, !Params.UsePak(SC.StageTargetPlatform)); // TODO: Exclude localization data generation config files. - SC.StageFiles(StagedFileType.UFS, IntermediateEngineIniDir, "*.ini", true, null, CombinePaths(SC.RelativeProjectRootForStage, "Config"), true, !Params.UsePak(SC.StageTargetPlatform)); // TODO: Exclude localization data generation config files. - } - else - { - SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.ProjectRoot, "Config"), "*", true, null, CombinePaths(SC.RelativeProjectRootForStage, "Config"), true, !Params.UsePak(SC.StageTargetPlatform)); // TODO: Exclude localization data generation config files. - } + SC.StageFiles(StagedFileType.UFS, DirectoryReference.Combine(SC.ProjectRoot, "Config"), "*", true, null, bAllowNone: true, bRemap: !Params.UsePak(SC.StageTargetPlatform)); // TODO: Exclude localization data generation config files. // Stage all project localization targets { - var ProjectLocRootDirectory = CombinePaths(SC.ProjectRoot, "Content/Localization"); - if (DirectoryExists(ProjectLocRootDirectory)) + DirectoryReference ProjectLocRootDirectory = DirectoryReference.Combine(SC.ProjectRoot, "Content", "Localization"); + if (DirectoryReference.Exists(ProjectLocRootDirectory)) { - string[] ProjectLocTargetDirectories = CommandUtils.FindDirectories(true, "*", false, ProjectLocRootDirectory); - foreach (string ProjectLocTargetDirectory in ProjectLocTargetDirectories) + foreach(DirectoryReference ProjectLocTargetDirectory in DirectoryReference.EnumerateDirectories(ProjectLocRootDirectory)) { StageLocalizationDataForTarget(SC, CulturesToStage, ProjectLocTargetDirectory, null, !Params.UsePak(SC.StageTargetPlatform)); } @@ -448,8 +391,8 @@ public partial class Project : CommandUtils { ProjectDescriptor Project = ProjectDescriptor.FromFile(SC.RawProjectPath.FullName); - List AvailablePlugins = Plugins.ReadAvailablePlugins(new DirectoryReference(CombinePaths(SC.LocalRoot, "Engine")), new FileReference(CombinePaths(SC.ProjectRoot, Params.ShortProjectName + ".uproject")), Project.AdditionalPluginDirectories); - foreach (var Plugin in AvailablePlugins) + List AvailablePlugins = Plugins.ReadAvailablePlugins(SC.EngineRoot, SC.RawProjectPath, Project.AdditionalPluginDirectories); + foreach (PluginInfo Plugin in AvailablePlugins) { if (!UProjectInfo.IsPluginEnabledForProject(Plugin, Project, SC.StageTargetPlatform.PlatformType, TargetType.Game) && UProjectInfo.IsPluginEnabledForProject(Plugin, Project, SC.StageTargetPlatform.PlatformType, TargetType.Client)) @@ -472,8 +415,8 @@ public partial class Project : CommandUtils continue; } - var PluginLocTargetDirectory = CombinePaths(Plugin.Directory.FullName, "Content", "Localization", LocalizationTarget.Name); - if (DirectoryExists(PluginLocTargetDirectory)) + DirectoryReference PluginLocTargetDirectory = DirectoryReference.Combine(Plugin.Directory, "Content", "Localization", LocalizationTarget.Name); + if (DirectoryReference.Exists(PluginLocTargetDirectory)) { StageLocalizationDataForTarget(SC, CulturesToStage, PluginLocTargetDirectory, null, !Params.UsePak(SC.StageTargetPlatform)); } @@ -494,12 +437,12 @@ public partial class Project : CommandUtils if (PathParts.Length == 3) { var RelativePath = PathParts[1]; - SC.StageFiles(StagedFileType.UFS, CombinePaths(ProjectContentRoot, RelativePath), "*", true, new string[] { "*.uasset", "*.umap" }, CombinePaths(StageContentRoot, RelativePath), true, !Params.UsePak(SC.StageTargetPlatform)); + SC.StageFiles(StagedFileType.UFS, DirectoryReference.Combine(ProjectContentRoot, RelativePath), "*", true, new string[] { "*.uasset", "*.umap" }, StagedDirectoryReference.Combine(StageContentRoot, RelativePath), true, !Params.UsePak(SC.StageTargetPlatform)); } else if (PathParts.Length == 1) { var RelativePath = PathParts[0]; - SC.StageFiles(StagedFileType.UFS, CombinePaths(ProjectContentRoot, RelativePath), "*", true, new string[] { "*.uasset", "*.umap" }, CombinePaths(StageContentRoot, RelativePath), true, !Params.UsePak(SC.StageTargetPlatform)); + SC.StageFiles(StagedFileType.UFS, DirectoryReference.Combine(ProjectContentRoot, RelativePath), "*", true, new string[] { "*.uasset", "*.umap" }, StagedDirectoryReference.Combine(StageContentRoot, RelativePath), true, !Params.UsePak(SC.StageTargetPlatform)); } } } @@ -515,12 +458,12 @@ public partial class Project : CommandUtils if (PathParts.Length == 3) { var RelativePath = PathParts[1]; - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(ProjectContentRoot, RelativePath), "*", true, null, CombinePaths(StageContentRoot, RelativePath), true, true); + SC.StageFiles(StagedFileType.NonUFS, DirectoryReference.Combine(ProjectContentRoot, RelativePath), "*", true, null, StagedDirectoryReference.Combine(StageContentRoot, RelativePath), true, true); } else if (PathParts.Length == 1) { var RelativePath = PathParts[0]; - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(ProjectContentRoot, RelativePath), "*", true, null, CombinePaths(StageContentRoot, RelativePath), true, true); + SC.StageFiles(StagedFileType.NonUFS, DirectoryReference.Combine(ProjectContentRoot, RelativePath), "*", true, null, StagedDirectoryReference.Combine(StageContentRoot, RelativePath), true, true); } } } @@ -536,29 +479,39 @@ public partial class Project : CommandUtils if (SC.StageTargetPlatform.StageMovies && !SC.DedicatedServer) { bool bRemap = (StagedFileTypeForMovies == StagedFileType.NonUFS); - SC.StageFiles(StagedFileTypeForMovies, CombinePaths(SC.LocalRoot, "Engine/Content/Movies"), "*", true, new string[] { "*.uasset", "*.umap" }, CombinePaths(SC.RelativeProjectRootForStage, "Engine/Content/Movies"), true, bRemap); - SC.StageFiles(StagedFileTypeForMovies, CombinePaths(SC.ProjectRoot, "Content/Movies"), "*", true, new string[] { "*.uasset", "*.umap" }, CombinePaths(SC.RelativeProjectRootForStage, "Content/Movies"), true, bRemap); + SC.StageFiles(StagedFileTypeForMovies, DirectoryReference.Combine(SC.EngineRoot, "Content", "Movies"), "*", true, new string[] { "*.uasset", "*.umap" }, bAllowNone: true, bRemap: bRemap); + SC.StageFiles(StagedFileTypeForMovies, DirectoryReference.Combine(SC.ProjectRoot, "Content", "Movies"), "*", true, new string[] { "*.uasset", "*.umap" }, bAllowNone: true, bRemap: bRemap); } + // shader cache + { + string ShaderCache = CombinePaths(SC.ProjectRoot.FullName, "Content/DrawCache.ushadercache"); + if (File.Exists(ShaderCache)) + { + SC.StageFile(StagedFileType.UFS, new FileReference(ShaderCache)); + } + } + + // eliminate the sand box // eliminate the sand box if (Params.CookInEditor) { - SC.StageFiles(StagedFileType.UFS, String.IsNullOrEmpty(Params.CookOutputDir)? CombinePaths(SC.ProjectRoot, "Saved", "EditorCooked", SC.CookPlatform) : CombinePaths(Params.CookOutputDir, SC.CookPlatform), "*", true, new string[] { "*.json" }, "", true, !Params.UsePak(SC.StageTargetPlatform)); + SC.StageFiles(StagedFileType.UFS, String.IsNullOrEmpty(Params.CookOutputDir)? DirectoryReference.Combine(SC.ProjectRoot, "Saved", "EditorCooked", SC.CookPlatform) : DirectoryReference.Combine(new DirectoryReference(Params.CookOutputDir), SC.CookPlatform), "*", true, new string[] { "*.json" }, StagedDirectoryReference.Root, true, !Params.UsePak(SC.StageTargetPlatform)); } else { - SC.StageFiles(StagedFileType.UFS, String.IsNullOrEmpty(Params.CookOutputDir)? CombinePaths(SC.ProjectRoot, "Saved", "Cooked", SC.CookPlatform) : CombinePaths(Params.CookOutputDir, SC.CookPlatform), "*", true, new string[] { "*.json" }, "", true, !Params.UsePak(SC.StageTargetPlatform)); + SC.StageFiles(StagedFileType.UFS, String.IsNullOrEmpty(Params.CookOutputDir)? DirectoryReference.Combine(SC.ProjectRoot, "Saved", "Cooked", SC.CookPlatform) : DirectoryReference.Combine(new DirectoryReference(Params.CookOutputDir), SC.CookPlatform), "*", true, new string[] { "*.json" }, StagedDirectoryReference.Root, true, !Params.UsePak(SC.StageTargetPlatform)); } // CrashReportClient is a standalone slate app that does not look in the generated pak file, so it needs the Content/Slate and Shaders/StandaloneRenderer folders Non-UFS // @todo Make CrashReportClient more portable so we don't have to do this - if (SC.bStageCrashReporter && PlatformSupportsCrashReporter(SC.StageTargetPlatform.PlatformType)) + if (SC.bStageCrashReporter && PlatformSupportsCrashReporter(SC.StageTargetPlatform.PlatformType) && (Params.IterateSharedBuildUsePrecompiledExe == false)) { //If the .dat file needs to be staged as NonUFS for non-Windows/Linux hosts we need to change the casing as we do with the build properties file above. - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.LocalRoot, "Engine/Content/Slate")); - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.LocalRoot, "Engine/Shaders/StandaloneRenderer")); + SC.StageFiles(StagedFileType.NonUFS, DirectoryReference.Combine(SC.EngineRoot, "Content", "Slate")); + SC.StageFiles(StagedFileType.NonUFS, DirectoryReference.Combine(SC.EngineRoot, "Shaders", "StandaloneRenderer")); - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.LocalRoot, "Engine", "Content", "Internationalization", InternationalizationPreset), "*", true, null, CombinePaths("Engine", "Content", "Internationalization"), false, true); + SC.StageFiles(StagedFileType.NonUFS, DirectoryReference.Combine(SC.EngineRoot, "Content", "Internationalization", InternationalizationPreset), "*", true, null, new StagedDirectoryReference("Engine/Content/Internationalization"), false, true); // Get the architecture in use string Architecture = Params.SpecifiedArchitecture; @@ -572,26 +525,24 @@ public partial class Project : CommandUtils } // Get the target receipt path for CrashReportClient - DirectoryReference EngineDir = new DirectoryReference(CombinePaths(SC.LocalRoot, "Engine")); - string ReceiptFileName = TargetReceipt.GetDefaultPath(EngineDir.FullName, "CrashReportClient", SC.StageTargetPlatform.PlatformType, UnrealTargetConfiguration.Shipping, Architecture); - if (!File.Exists(ReceiptFileName)) + FileReference ReceiptFileName = TargetReceipt.GetDefaultPath(SC.EngineRoot, "CrashReportClient", SC.StageTargetPlatform.PlatformType, UnrealTargetConfiguration.Shipping, Architecture); + if (!FileReference.Exists(ReceiptFileName)) { - throw new AutomationException(ExitCode.Error_MissingExecutable, "Stage Failed. Missing receipt '{0}'. Check that this target has been built.", Path.GetFileName(ReceiptFileName)); + throw new AutomationException(ExitCode.Error_MissingExecutable, "Stage Failed. Missing receipt '{0}'. Check that this target has been built.", Path.GetFileName(ReceiptFileName.FullName)); } // Read the receipt for this target TargetReceipt Receipt; - if (!TargetReceipt.TryRead(ReceiptFileName, out Receipt)) + if (!TargetReceipt.TryRead(ReceiptFileName, SC.EngineRoot, null, out Receipt)) { throw new AutomationException("Missing or invalid target receipt ({0})", ReceiptFileName); } // Stage any runtime dependencies for CrashReportClient - Receipt.ExpandPathVariables(EngineDir, EngineDir); SC.StageRuntimeDependenciesFromReceipt(Receipt, true, Params.UsePak(SC.StageTargetPlatform)); // Add config files. - SC.StageFiles( StagedFileType.NonUFS, CombinePaths( SC.LocalRoot, "Engine/Programs/CrashReportClient/Config" ), bAllowNotForLicenseesFiles:false ); + SC.StageFiles( StagedFileType.NonUFS, DirectoryReference.Combine(SC.EngineRoot, "Programs", "CrashReportClient", "Config" ), bAllowNotForLicenseesFiles:false ); } // check if the game will be verifying ssl connections - if not, we can skip staging files that won't be needed @@ -605,18 +556,18 @@ public partial class Project : CommandUtils if (bStageSSLCertificates) { // Game's SSL certs - int NumFilesBeforeGameCert = SC.UFSStagingFiles.Count; - SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.ProjectRoot, "Content/Certificates"), "cacert.pem", true, null, null, true, !Params.UsePak(SC.StageTargetPlatform)); + int NumFilesBeforeGameCert = SC.FilesToStage.UFSStagingFiles.Count; + SC.StageFiles(StagedFileType.UFS, DirectoryReference.Combine(SC.ProjectRoot, "Content", "Certificates"), "cacert.pem", true, null, null, true, !Params.UsePak(SC.StageTargetPlatform)); // if the game had any files to be staged, then we don't need to stage the engine one - it will just added hundreds of kb of data that is never used - if (SC.UFSStagingFiles.Count == NumFilesBeforeGameCert) + if (SC.FilesToStage.UFSStagingFiles.Count == NumFilesBeforeGameCert) { // Engine SSL certs - SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.LocalRoot, "Engine/Content/Certificates/ThirdParty"), "cacert.pem", true, null, null, true, !Params.UsePak(SC.StageTargetPlatform)); + SC.StageFiles(StagedFileType.UFS, DirectoryReference.Combine(SC.EngineRoot, "Content", "Certificates", "ThirdParty"), "cacert.pem", true, null, null, true, !Params.UsePak(SC.StageTargetPlatform)); } // now stage any other game certs besides cacert - SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.ProjectRoot, "Certificates"), "*.pem", true, null, null, true, !Params.UsePak(SC.StageTargetPlatform)); + SC.StageFiles(StagedFileType.UFS, DirectoryReference.Combine(SC.ProjectRoot, "Certificates"), "*.pem", true, null, null, true, !Params.UsePak(SC.StageTargetPlatform)); } } else @@ -633,12 +584,12 @@ public partial class Project : CommandUtils if (PathParts.Length == 3) { var RelativePath = PathParts[1]; - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(ProjectContentRoot, RelativePath)); + SC.StageFiles(StagedFileType.NonUFS, DirectoryReference.Combine(ProjectContentRoot, RelativePath)); } else if (PathParts.Length == 1) { var RelativePath = PathParts[0]; - SC.StageFiles(StagedFileType.UFS, CombinePaths(ProjectContentRoot, RelativePath), "*", true, null, CombinePaths(StageContentRoot, RelativePath), true, !Params.UsePak(SC.StageTargetPlatform)); + SC.StageFiles(StagedFileType.UFS, DirectoryReference.Combine(ProjectContentRoot, RelativePath), "*", true, null, StagedDirectoryReference.Combine(StageContentRoot, RelativePath), true, !Params.UsePak(SC.StageTargetPlatform)); } } } @@ -646,7 +597,7 @@ public partial class Project : CommandUtils } } - public static void DumpTargetManifest(Dictionary Mapping, string Filename, string StageDir, List CRCFiles) + public static void DumpTargetManifest(Dictionary Mapping, FileReference Filename, DirectoryReference StageDir, HashSet CRCFiles) { // const string Iso8601DateTimeFormat = "yyyy-MM-ddTHH:mm:ssZ"; // probably should work // const string Iso8601DateTimeFormat = "o"; // predefined universal Iso standard format (has too many millisecond spaces for our read code in FDateTime.ParseISO8601 @@ -658,140 +609,61 @@ public partial class Project : CommandUtils var Lines = new List(); foreach (var Pair in Mapping) { - string TimeStamp = File.GetLastWriteTimeUtc(Pair.Key).ToString(Iso8601DateTimeFormat); - if (CRCFiles.Contains(Pair.Value)) + string TimeStamp = FileReference.GetLastWriteTimeUtc(Pair.Value).ToString(Iso8601DateTimeFormat); + if (CRCFiles.Contains(Pair.Key)) { - byte[] FileData = File.ReadAllBytes(StageDir + "/" + Pair.Value); + byte[] FileData = File.ReadAllBytes(StageDir + "/" + Pair.Key); TimeStamp = BitConverter.ToString(System.Security.Cryptography.MD5.Create().ComputeHash(FileData)).Replace("-", string.Empty); } - string Dest = Pair.Value + "\t" + TimeStamp; + string Dest = Pair.Key.Name + "\t" + TimeStamp; Lines.Add(Dest); } - WriteAllLines(Filename, Lines.ToArray()); + + DirectoryReference.CreateDirectory(Filename.Directory); + WriteAllLines(Filename.FullName, Lines.ToArray()); } } - public static void DumpTargetManifest(Dictionary> Mapping, string Filename, string StageDir, List CRCFiles) - { - // const string Iso8601DateTimeFormat = "yyyy-MM-ddTHH:mm:ssZ"; // probably should work - // const string Iso8601DateTimeFormat = "o"; // predefined universal Iso standard format (has too many millisecond spaces for our read code in FDateTime.ParseISO8601 - const string Iso8601DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffZ"; - - if (Mapping.Count > 0) - { - var Lines = new List(); - foreach (var Pair in Mapping) - { - foreach (var DestFile in Pair.Value) - { - string TimeStamp = File.GetLastWriteTimeUtc(Pair.Key).ToString(Iso8601DateTimeFormat); - if (CRCFiles.Contains(DestFile)) - { - byte[] FileData = File.ReadAllBytes(StageDir + "/" + DestFile); - TimeStamp = BitConverter.ToString(System.Security.Cryptography.MD5.Create().ComputeHash(FileData)).Replace("-", string.Empty); - } - string DestData = DestFile + "\t" + TimeStamp; - Lines.Add(DestData); - } - } - WriteAllLines(Filename, Lines.ToArray()); - } - } - - public static void CopyManifestFilesToStageDir(Dictionary Mapping, string StageDir, string ManifestName, List CRCFiles, string PlatformName) + public static void CopyManifestFilesToStageDir(Dictionary Mapping, DirectoryReference StageDir, string ManifestName, HashSet CRCFiles, string PlatformName) { Log("Copying {0} to staging directory: {1}", ManifestName, StageDir); - string ManifestPath = ""; + FileReference ManifestPath = null; string ManifestFile = ""; if (!String.IsNullOrEmpty(ManifestName)) { ManifestFile = "Manifest_" + ManifestName + "_" + PlatformName + ".txt"; - ManifestPath = CombinePaths(StageDir, ManifestFile); - DeleteFile(ManifestPath); + ManifestPath = FileReference.Combine(StageDir, ManifestFile); + DeleteFile(ManifestPath.FullName); } - if (!String.IsNullOrEmpty(ManifestPath) && Mapping.Count > 0) + foreach (KeyValuePair Pair in Mapping) { - DumpTargetManifest(Mapping, ManifestPath, StageDir, CRCFiles); - if (!FileExists(ManifestPath)) - { - throw new AutomationException("Failed to write manifest {0}", ManifestPath); - } - CopyFile(ManifestPath, CombinePaths(CmdEnv.LogFolder, ManifestFile)); - } - foreach (var Pair in Mapping) - { - string Src = Pair.Key; - string Dest = CombinePaths(StageDir, Pair.Value); + FileReference Src = Pair.Value; + FileReference Dest = FileReference.Combine(StageDir, Pair.Key.Name); if (Src != Dest) // special case for things created in the staging directory, like the pak file { CopyFileIncremental(Src, Dest, bFilterSpecialLinesFromIniFiles:true); } } - } - - public static void CopyManifestFilesToStageDir(Dictionary> Mapping, string StageDir, string ManifestName, List CRCFiles, string PlatformName) - { - Log("Copying {0} to staging directory: {1}", ManifestName, StageDir); - string ManifestPath = ""; - string ManifestFile = ""; - if (!String.IsNullOrEmpty(ManifestName)) - { - ManifestFile = "Manifest_" + ManifestName + "_" + PlatformName + ".txt"; - ManifestPath = CombinePaths(StageDir, ManifestFile); - DeleteFile(ManifestPath); - } - foreach (var Pair in Mapping) - { - string Src = Pair.Key; - foreach (var DestPath in Pair.Value) - { - string DestFile = CombinePaths(StageDir, DestPath); - if (Src != DestFile) // special case for things created in the staging directory, like the pak file - { - CopyFileIncremental(Src, DestFile, bFilterSpecialLinesFromIniFiles: true); - } - } - } - if (!String.IsNullOrEmpty(ManifestPath) && Mapping.Count > 0) + if (ManifestPath != null && Mapping.Count > 0) { DumpTargetManifest(Mapping, ManifestPath, StageDir, CRCFiles); - if (!FileExists(ManifestPath)) + if (!FileReference.Exists(ManifestPath)) { throw new AutomationException("Failed to write manifest {0}", ManifestPath); } - CopyFile(ManifestPath, CombinePaths(CmdEnv.LogFolder, ManifestFile)); + CopyFile(ManifestPath.FullName, CombinePaths(CmdEnv.LogFolder, ManifestFile)); } } - public static void DumpManifest(Dictionary Mapping, string Filename) + public static void DumpManifest(Dictionary Mapping, string Filename) { if (Mapping.Count > 0) { - var Lines = new List(); - foreach (var Pair in Mapping) + List Lines = new List(); + foreach (KeyValuePair Pair in Mapping) { - string Src = Pair.Key; - string Dest = Pair.Value; - - Lines.Add("\"" + Src + "\" \"" + Dest + "\""); - } - WriteAllLines(Filename, Lines.ToArray()); - } - } - - public static void DumpManifest(Dictionary> Mapping, string Filename) - { - if (Mapping.Count > 0) - { - var Lines = new List(); - foreach (var Pair in Mapping) - { - string Src = Pair.Key; - foreach (var DestPath in Pair.Value) - { - Lines.Add("\"" + Src + "\" \"" + DestPath + "\""); - } + Lines.Add("\"" + Pair.Value + "\" \"" + Pair.Key + "\""); } WriteAllLines(Filename, Lines.ToArray()); } @@ -799,27 +671,27 @@ public partial class Project : CommandUtils public static void DumpManifest(DeploymentContext SC, string BaseFilename, bool DumpUFSFiles = true) { - DumpManifest(SC.NonUFSStagingFiles, BaseFilename + "_NonUFSFiles.txt"); + DumpManifest(SC.FilesToStage.NonUFSStagingFiles, BaseFilename + "_NonUFSFiles.txt"); if (DumpUFSFiles) { - DumpManifest(SC.NonUFSStagingFilesDebug, BaseFilename + "_NonUFSFilesDebug.txt"); + DumpManifest(SC.FilesToStage.NonUFSStagingFilesDebug, BaseFilename + "_NonUFSFilesDebug.txt"); } - DumpManifest(SC.UFSStagingFiles, BaseFilename + "_UFSFiles.txt"); + DumpManifest(SC.FilesToStage.UFSStagingFiles, BaseFilename + "_UFSFiles.txt"); } public static void CopyUsingStagingManifest(ProjectParams Params, DeploymentContext SC) { - CopyManifestFilesToStageDir(SC.NonUFSStagingFiles, SC.StageDirectory, "NonUFSFiles", SC.StageTargetPlatform.GetFilesForCRCCheck(), SC.StageTargetPlatform.PlatformType.ToString()); + CopyManifestFilesToStageDir(SC.FilesToStage.NonUFSStagingFiles, SC.StageDirectory, "NonUFSFiles", SC.StageTargetPlatform.GetFilesForCRCCheck(), SC.StageTargetPlatform.PlatformType.ToString()); if (!Params.NoDebugInfo) { - CopyManifestFilesToStageDir(SC.NonUFSStagingFilesDebug, SC.StageDirectory, "DebugFiles", SC.StageTargetPlatform.GetFilesForCRCCheck(), SC.StageTargetPlatform.PlatformType.ToString()); + CopyManifestFilesToStageDir(SC.FilesToStage.NonUFSStagingFilesDebug, SC.StageDirectory, "DebugFiles", SC.StageTargetPlatform.GetFilesForCRCCheck(), SC.StageTargetPlatform.PlatformType.ToString()); } bool bStageUnrealFileSystemFiles = !Params.CookOnTheFly && !Params.UsePak(SC.StageTargetPlatform) && !Params.FileServer; if (bStageUnrealFileSystemFiles) { - CopyManifestFilesToStageDir(SC.UFSStagingFiles, SC.StageDirectory, "UFSFiles", SC.StageTargetPlatform.GetFilesForCRCCheck(), SC.StageTargetPlatform.PlatformType.ToString()); + CopyManifestFilesToStageDir(SC.FilesToStage.UFSStagingFiles, SC.StageDirectory, "UFSFiles", SC.StageTargetPlatform.GetFilesForCRCCheck(), SC.StageTargetPlatform.PlatformType.ToString()); } } @@ -836,13 +708,6 @@ public partial class Project : CommandUtils var UnrealPakResponseFile = CreatePakResponseFileFromStagingManifest(SC); - if (Params.CreateChunkInstall) - { - string ChunkInstallBasePath = CombinePaths(Params.ChunkInstallDirectory, SC.FinalCookPlatform); - string CloudDir = MakePathSafeToUseWithCommandLine(CombinePaths(ChunkInstallBasePath, "CloudDir")); - InternalUtils.SafeDeleteDirectory(CloudDir, true); - } - CreatePak(Params, SC, UnrealPakResponseFile, SC.ShortProjectName); } @@ -857,11 +722,11 @@ public partial class Project : CommandUtils List Blacklist = null; if (SC.StageTargetConfigurations.Count == 1) { - var PakBlacklistFilename = CombinePaths(SC.ProjectRoot, "Build", SC.PlatformDir, string.Format("PakBlacklist-{0}.txt", SC.StageTargetConfigurations[0].ToString())); - if (File.Exists(PakBlacklistFilename)) + FileReference PakBlacklistFilename = FileReference.Combine(SC.ProjectRoot, "Build", SC.PlatformDir, string.Format("PakBlacklist-{0}.txt", SC.StageTargetConfigurations[0].ToString())); + if (FileReference.Exists(PakBlacklistFilename)) { Log("Applying PAK blacklist file {0}", PakBlacklistFilename); - string[] BlacklistContents = File.ReadAllLines(PakBlacklistFilename); + string[] BlacklistContents = FileReference.ReadAllLines(PakBlacklistFilename); foreach (string Candidate in BlacklistContents) { if (Candidate.Trim().Length > 0) @@ -877,10 +742,10 @@ public partial class Project : CommandUtils } var UnrealPakResponseFile = new Dictionary(StringComparer.InvariantCultureIgnoreCase); - foreach (var Pair in SC.UFSStagingFiles) + foreach (KeyValuePair Pair in SC.FilesToStage.UFSStagingFiles) { - string Src = Pair.Key; - string Dest = Pair.Value; + FileReference Src = Pair.Value; + string Dest = Pair.Key.Name; Dest = CombinePaths(PathSeparator.Slash, SC.PakFileInternalRoot, Dest); @@ -903,24 +768,20 @@ public partial class Project : CommandUtils } } - // special case DefaultEngine.ini to strip passwords - if (Path.GetFileName(Src).Equals("DefaultEngine.ini")) + // Do a filtered copy of all ini files to allow stripping of values that we don't want to distribute + if (Src.HasExtension(".ini")) { - string SrcDirectoryPath = Path.GetDirectoryName(Src); - string ConfigDirectory = "Config"; - int ConfigRootIdx = SrcDirectoryPath.LastIndexOf(ConfigDirectory); - string SubpathUnderConfig = (ConfigRootIdx != -1) ? SrcDirectoryPath.Substring(ConfigRootIdx + ConfigDirectory.Length) : "Unknown"; - - string NewIniFilename = CombinePaths(SC.ProjectRoot, "Saved", "Temp", SC.PlatformDir, SubpathUnderConfig, "DefaultEngine.ini"); - InternalUtils.SafeCreateDirectory(Path.GetDirectoryName(NewIniFilename), true); - InternalUtils.SafeCopyFile(Src, NewIniFilename, bFilterSpecialLinesFromIniFiles:true); + string SubFolder = Pair.Key.Name.Replace('/', Path.DirectorySeparatorChar); + FileReference NewIniFilename = FileReference.Combine(SC.ProjectRoot, "Saved", "Temp", SC.PlatformDir, SubFolder); + InternalUtils.SafeCreateDirectory(NewIniFilename.Directory.FullName, true); + InternalUtils.SafeCopyFile(Src.FullName, NewIniFilename.FullName, bFilterSpecialLinesFromIniFiles:true); Src = NewIniFilename; } // there can be files that only differ in case only, we don't support that in paks as paks are case-insensitive - if (UnrealPakResponseFile.ContainsKey(Src)) + if (UnrealPakResponseFile.ContainsKey(Src.FullName)) { - if (UnrealPakResponseFile[Src] != Dest) + if (UnrealPakResponseFile[Src.FullName] != Dest) { throw new AutomationException("Staging manifest already contains {0} (or a file that differs in case only)", Src); } @@ -928,7 +789,7 @@ public partial class Project : CommandUtils continue; } - UnrealPakResponseFile.Add(Src, Dest); + UnrealPakResponseFile.Add(Src.FullName, Dest); } return UnrealPakResponseFile; @@ -962,31 +823,34 @@ public partial class Project : CommandUtils // then be combined with the shared cooked build PostFix += "_S_P"; } - string OutputRelativeLocation; + + StagedFileReference OutputRelativeLocation; if(Params.HasDLCName) { - OutputRelativeLocation = CombinePaths(SC.RelativeProjectRootForStage, "Plugins/" + Params.DLCName + "/Content/Paks/" + SC.FinalCookPlatform, Params.DLCName + ".pak"); + OutputRelativeLocation = StagedFileReference.Combine(SC.RelativeProjectRootForStage, "Plugins", Params.DLCName, "Content", "Paks", SC.FinalCookPlatform, Params.DLCName + ".pak"); } else { - OutputRelativeLocation = CombinePaths(SC.RelativeProjectRootForStage, "Content/Paks/", PakName + "-" + SC.FinalCookPlatform + PostFix + ".pak"); + OutputRelativeLocation = StagedFileReference.Combine(SC.RelativeProjectRootForStage, "Content", "Paks", PakName + "-" + SC.FinalCookPlatform + PostFix + ".pak"); } if (SC.StageTargetPlatform.DeployLowerCaseFilenames(true)) { OutputRelativeLocation = OutputRelativeLocation.ToLowerInvariant(); } OutputRelativeLocation = SC.StageTargetPlatform.Remap(OutputRelativeLocation); - var OutputLocation = CombinePaths(SC.RuntimeRootDir, OutputRelativeLocation); + + FileReference OutputLocation = FileReference.Combine(SC.RuntimeRootDir, OutputRelativeLocation.Name); // Add input file to controll order of file within the pak - var PakOrderFileLocationBase = CombinePaths(SC.ProjectRoot, "Build", SC.FinalCookPlatform, "FileOpenOrder"); + DirectoryReference PakOrderFileLocationBase = DirectoryReference.Combine(SC.ProjectRoot, "Build", SC.FinalCookPlatform, "FileOpenOrder"); - var OrderFileLocations = new string[] { "GameOpenOrder.log", "CookerOpenOrder.log", "EditorOpenOrder.log" }; - string PakOrderFileLocation = null; - foreach (var Location in OrderFileLocations) + FileReference PakOrderFileLocation = null; + + string[] OrderFileNames = new string[] { "GameOpenOrder.log", "CookerOpenOrder.log", "EditorOpenOrder.log" }; + foreach (string OrderFileName in OrderFileNames) { - PakOrderFileLocation = CombinePaths(PakOrderFileLocationBase, Location); + PakOrderFileLocation = FileReference.Combine(PakOrderFileLocationBase, OrderFileName); - if (FileExists_NoExceptions(PakOrderFileLocation)) + if (FileExists_NoExceptions(PakOrderFileLocation.FullName)) { break; } @@ -998,32 +862,31 @@ public partial class Project : CommandUtils { // Check to see if we have an existing pak file we can use - var SourceOutputRelativeLocation = CombinePaths(SC.RelativeProjectRootForStage, "Content/Paks/", PakName + "-" + SC.CookPlatform + PostFix + ".pak"); + StagedFileReference SourceOutputRelativeLocation = StagedFileReference.Combine(SC.RelativeProjectRootForStage, "Content/Paks/", PakName + "-" + SC.CookPlatform + PostFix + ".pak"); if (SC.CookSourcePlatform.DeployLowerCaseFilenames(true)) { SourceOutputRelativeLocation = SourceOutputRelativeLocation.ToLowerInvariant(); } SourceOutputRelativeLocation = SC.CookSourcePlatform.Remap(SourceOutputRelativeLocation); - var SourceOutputLocation = CombinePaths(SC.CookSourceRuntimeRootDir, SourceOutputRelativeLocation); - if (FileExists_NoExceptions(SourceOutputLocation)) + FileReference SourceOutputLocation = FileReference.Combine(SC.CookSourceRuntimeRootDir, SourceOutputRelativeLocation.Name); + if (FileExists_NoExceptions(SourceOutputLocation.FullName)) { - InternalUtils.SafeCreateDirectory(Path.GetDirectoryName(OutputLocation), true); + InternalUtils.SafeCreateDirectory(Path.GetDirectoryName(OutputLocation.FullName), true); - if (InternalUtils.SafeCopyFile(SourceOutputLocation, OutputLocation)) + if (InternalUtils.SafeCopyFile(SourceOutputLocation.FullName, OutputLocation.FullName)) { Log("Copying source pak from {0} to {1} instead of creating new pak", SourceOutputLocation, OutputLocation); bCopiedExistingPak = true; - string InSigFile = Path.ChangeExtension(SourceOutputLocation, ".sig"); - - if (File.Exists(InSigFile)) + FileReference InSigFile = SourceOutputLocation.ChangeExtension(".sig"); + if (FileReference.Exists(InSigFile)) { - string OutSigFile = Path.ChangeExtension(OutputLocation, ".sig"); + FileReference OutSigFile = OutputLocation.ChangeExtension(".sig"); Log("Copying pak sig from {0} to {1}", InSigFile, OutSigFile); - if (!InternalUtils.SafeCopyFile(InSigFile, OutSigFile)) + if (!InternalUtils.SafeCopyFile(InSigFile.FullName, OutSigFile.FullName)) { Log("Failed to copy pak sig {0} to {1}, creating new pak", InSigFile, InSigFile); bCopiedExistingPak = false; @@ -1054,10 +917,10 @@ public partial class Project : CommandUtils if (!bCopiedExistingPak) { - if (File.Exists(OutputLocation)) + if (FileReference.Exists(OutputLocation)) { - string UnrealPakResponseFileName = CombinePaths(CmdEnv.LogFolder, "PakList_" + Path.GetFileNameWithoutExtension(OutputLocation) + ".txt"); - if (File.Exists(UnrealPakResponseFileName) && File.GetLastWriteTimeUtc(OutputLocation) > File.GetLastWriteTimeUtc(UnrealPakResponseFileName)) + string UnrealPakResponseFileName = CombinePaths(CmdEnv.LogFolder, "PakList_" + OutputLocation.GetFileNameWithoutExtension() + ".txt"); + if (File.Exists(UnrealPakResponseFileName) && FileReference.GetLastWriteTimeUtc(OutputLocation) > File.GetLastWriteTimeUtc(UnrealPakResponseFileName)) { bCopiedExistingPak = true; } @@ -1076,10 +939,10 @@ public partial class Project : CommandUtils { // copy the created pak to the release version directory we might need this later if we want to generate patches //string ReleaseVersionPath = CombinePaths( SC.ProjectRoot, "Releases", Params.CreateReleaseVersion, SC.StageTargetPlatform.GetCookPlatform(Params.DedicatedServer, false), Path.GetFileName(OutputLocation) ); - string ReleaseVersionPath = SC.StageTargetPlatform.GetReleasePakFilePath(SC, Params, Path.GetFileName(OutputLocation)); + string ReleaseVersionPath = SC.StageTargetPlatform.GetReleasePakFilePath(SC, Params, OutputLocation.GetFileName()); InternalUtils.SafeCreateDirectory(Path.GetDirectoryName(ReleaseVersionPath)); - InternalUtils.SafeCopyFile(OutputLocation, ReleaseVersionPath); + InternalUtils.SafeCopyFile(OutputLocation.FullName, ReleaseVersionPath); } if (Params.CreateChunkInstall) @@ -1117,8 +980,8 @@ public partial class Project : CommandUtils InternalUtils.SafeDeleteFile(RawDataPakPath, true); } InternalUtils.SafeCreateDirectory(RawDataPath, true); - InternalUtils.SafeCopyFile(OutputLocation, RawDataPakPath); - InternalUtils.SafeDeleteFile(OutputLocation, true); + InternalUtils.SafeCopyFile(OutputLocation.FullName, RawDataPakPath); + InternalUtils.SafeDeleteFile(OutputLocation.FullName, true); if (Params.IsGeneratingPatch) { @@ -1140,7 +1003,6 @@ public partial class Project : CommandUtils string AppLaunch = ""; // For a chunk install this value doesn't seem to matter string ManifestFilename = AppName + VersionString + ".manifest"; string SourceManifestPath = CombinePaths(CloudDir, ManifestFilename); - string BackupManifestPath = CombinePaths(RawDataPath, ManifestFilename); string DestManifestPath = CombinePaths(ManifestDir, ManifestFilename); InternalUtils.SafeCreateDirectory(ManifestDir, true); @@ -1154,19 +1016,18 @@ public partial class Project : CommandUtils string UnrealPakLogFileName = "UnrealPak_" + PakName; RunAndLog(CmdEnv, BPTExe, CmdLine, UnrealPakLogFileName, Options: ERunOptions.Default | ERunOptions.UTF8Output); - InternalUtils.SafeCopyFile(SourceManifestPath, BackupManifestPath); InternalUtils.SafeCopyFile(SourceManifestPath, DestManifestPath); } else { // add the first pak file as needing deployment and convert to lower case again if needed - SC.UFSStagingFiles.Add(OutputLocation, OutputRelativeLocation); + SC.FilesToStage.UFSStagingFiles.Add(OutputRelativeLocation, OutputLocation); } } else { // add the pak file as needing deployment and convert to lower case again if needed - SC.UFSStagingFiles.Add(OutputLocation, OutputRelativeLocation); + SC.FilesToStage.UFSStagingFiles.Add(OutputRelativeLocation, OutputLocation); } } @@ -1201,31 +1062,31 @@ public partial class Project : CommandUtils } foreach (var StagingFile in StagingManifestResponseFile) { - bool bAddedToChunk = false; - for (int ChunkIndex = 0; !bAddedToChunk && ChunkIndex < ChunkResponseFiles.Length; ++ChunkIndex) - { - string OriginalFilename = StagingFile.Key; - string NoExtension = CombinePaths(Path.GetDirectoryName(OriginalFilename), Path.GetFileNameWithoutExtension(OriginalFilename)); - string OriginalReplaceSlashes = OriginalFilename.Replace('/', '\\'); - string NoExtensionReplaceSlashes = NoExtension.Replace('/', '\\'); + bool bAddedToChunk = false; + for (int ChunkIndex = 0; !bAddedToChunk && ChunkIndex < ChunkResponseFiles.Length; ++ChunkIndex) + { + string OriginalFilename = StagingFile.Key; + string NoExtension = CombinePaths(Path.GetDirectoryName(OriginalFilename), Path.GetFileNameWithoutExtension(OriginalFilename)); + string OriginalReplaceSlashes = OriginalFilename.Replace('/', '\\'); + string NoExtensionReplaceSlashes = NoExtension.Replace('/', '\\'); - if (ChunkResponseFiles[ChunkIndex].Contains(OriginalFilename) || - ChunkResponseFiles[ChunkIndex].Contains(OriginalReplaceSlashes) || - ChunkResponseFiles[ChunkIndex].Contains(NoExtension) || - ChunkResponseFiles[ChunkIndex].Contains(NoExtensionReplaceSlashes)) - { - PakResponseFiles[ChunkIndex].Add(StagingFile.Key, StagingFile.Value); - bAddedToChunk = true; - } - } - if (!bAddedToChunk) - { - //Log("No chunk assigned found for {0}. Using default chunk.", StagingFile.Key); - PakResponseFiles[DefaultChunkIndex].Add(StagingFile.Key, StagingFile.Value); - } - } + if (ChunkResponseFiles[ChunkIndex].Contains(OriginalFilename) || + ChunkResponseFiles[ChunkIndex].Contains(OriginalReplaceSlashes) || + ChunkResponseFiles[ChunkIndex].Contains(NoExtension) || + ChunkResponseFiles[ChunkIndex].Contains(NoExtensionReplaceSlashes)) + { + PakResponseFiles[ChunkIndex].Add(StagingFile.Key, StagingFile.Value); + bAddedToChunk = true; + } + } + if (!bAddedToChunk) + { + //Log("No chunk assigned found for {0}. Using default chunk.", StagingFile.Key); + PakResponseFiles[DefaultChunkIndex].Add(StagingFile.Key, StagingFile.Value); + } + } - if (Params.CreateChunkInstall) + if (Params.CreateChunkInstall) { string ManifestDir = CombinePaths(Params.ChunkInstallDirectory, SC.FinalCookPlatform, "ManifestDir"); if (InternalUtils.SafeDirectoryExists(ManifestDir)) @@ -1244,24 +1105,22 @@ public partial class Project : CommandUtils IEnumerable, string>> PakPairs = PakResponseFiles.Zip(ChunkList, (a, b) => Tuple.Create(a, b)); - if (Params.CreateChunkInstall) - { - string ChunkInstallBasePath = CombinePaths(Params.ChunkInstallDirectory, SC.FinalCookPlatform); - string CloudDir = MakePathSafeToUseWithCommandLine(CombinePaths(ChunkInstallBasePath, "CloudDir")); - InternalUtils.SafeDeleteDirectory(CloudDir, true); - } - + System.Threading.Tasks.ParallelOptions Options = new System.Threading.Tasks.ParallelOptions(); + Options.MaxDegreeOfParallelism = 1; System.Threading.Tasks.Parallel.ForEach(PakPairs, (PakPair) => { var ChunkName = Path.GetFileNameWithoutExtension(PakPair.Item2); - CreatePak(Params, SC, PakPair.Item1, ChunkName); + if (PakPair.Item1.Count > 0) + { + CreatePak(Params, SC, PakPair.Item1, ChunkName); + } }); - String ChunkLayerFilename = CombinePaths(GetTmpPackagingPath(Params, SC), GetChunkPakLayerListName()); - String OutputChunkLayerFilename = Path.Combine(SC.ProjectRoot, "Build", SC.FinalCookPlatform, "ChunkLayerInfo", GetChunkPakLayerListName()); + String ChunkLayerFilename = CombinePaths(GetTmpPackagingPath(Params, SC), GetChunkPakLayerListName()); + String OutputChunkLayerFilename = Path.Combine(SC.ProjectRoot.FullName, "Build", SC.FinalCookPlatform, "ChunkLayerInfo", GetChunkPakLayerListName()); Directory.CreateDirectory(Path.GetDirectoryName(OutputChunkLayerFilename)); File.Copy(ChunkLayerFilename, OutputChunkLayerFilename, true); - } + } private static bool DoesChunkPakManifestExist(ProjectParams Params, DeploymentContext SC) { @@ -1336,17 +1195,17 @@ public partial class Project : CommandUtils public static void CleanStagingDirectory(ProjectParams Params, DeploymentContext SC) { MaybeConvertToLowerCase(Params, SC); - Log("Cleaning Stage Directory: {0}", SC.StageDirectory); + Log("Cleaning Stage Directory: {0}", SC.StageDirectory.FullName); if (SC.Stage && !Params.NoCleanStage && !Params.SkipStage && !Params.IterativeDeploy) { try { - DeleteDirectory(SC.StageDirectory); + DeleteDirectory(SC.StageDirectory.FullName); } catch (Exception Ex) { // Delete cooked data (if any) as it may be incomplete / corrupted. - throw new AutomationException(ExitCode.Error_FailedToDeleteStagingDirectory, Ex, "Stage Failed. Failed to delete staging directory " + SC.StageDirectory); + throw new AutomationException(ExitCode.Error_FailedToDeleteStagingDirectory, Ex, "Stage Failed. Failed to delete staging directory " + SC.StageDirectory.FullName); } } else @@ -1354,12 +1213,12 @@ public partial class Project : CommandUtils try { // delete old pak files - DeletePakFiles(SC.StageDirectory); + DeletePakFiles(SC.StageDirectory.FullName); } catch (Exception Ex) { // Delete cooked data (if any) as it may be incomplete / corrupted. - throw new AutomationException(ExitCode.Error_FailedToDeleteStagingDirectory, Ex, "Stage Failed. Failed to delete pak files in " + SC.StageDirectory); + throw new AutomationException(ExitCode.Error_FailedToDeleteStagingDirectory, Ex, "Stage Failed. Failed to delete pak files in " + SC.StageDirectory.FullName); } } } @@ -1388,22 +1247,22 @@ public partial class Project : CommandUtils ThisPlatform.PostStagingFileCopy(Params, SC); } - private static string GetIntermediateCommandlineDir(DeploymentContext SC) + private static DirectoryReference GetIntermediateCommandlineDir(DeploymentContext SC) { - return CombinePaths(SC.ProjectRoot, "Intermediate/UAT", SC.FinalCookPlatform); + return DirectoryReference.Combine(SC.LocalRoot, "Intermediate", "UAT", SC.FinalCookPlatform); } - public static void WriteStageCommandline(string IntermediateCmdLineFile, ProjectParams Params, DeploymentContext SC) + public static void WriteStageCommandline(FileReference IntermediateCmdLineFile, ProjectParams Params, DeploymentContext SC) { // this file needs to be treated as a UFS file for casing, but NonUFS for being put into the .pak file. // @todo: Maybe there should be a new category - UFSNotForPak if (SC.StageTargetPlatform.DeployLowerCaseFilenames(true)) { - IntermediateCmdLineFile = IntermediateCmdLineFile.ToLowerInvariant(); + IntermediateCmdLineFile = new FileReference(IntermediateCmdLineFile.CanonicalName); } - if (File.Exists(IntermediateCmdLineFile)) + if (FileReference.Exists(IntermediateCmdLineFile)) { - File.Delete(IntermediateCmdLineFile); + FileReference.Delete(IntermediateCmdLineFile); } if(!SC.StageTargetPlatform.ShouldStageCommandLine(Params, SC)) @@ -1565,13 +1424,13 @@ public partial class Project : CommandUtils { ProjectFile = ""; } - Directory.CreateDirectory(GetIntermediateCommandlineDir(SC)); + DirectoryReference.CreateDirectory(GetIntermediateCommandlineDir(SC)); string CommandLine = String.Format("{0} {1} {2} {3}\n", ProjectFile, Params.StageCommandline.Trim(new char[] { '\"' }), Params.RunCommandline.Trim(new char[] { '\"' }), FileHostParams).Trim(); if (Params.IterativeDeploy) { CommandLine += " -iterative"; } - File.WriteAllText(IntermediateCmdLineFile, CommandLine); + File.WriteAllText(IntermediateCmdLineFile.FullName, CommandLine); } else { @@ -1580,22 +1439,22 @@ public partial class Project : CommandUtils { ProjectFile = ""; } - Directory.CreateDirectory(GetIntermediateCommandlineDir(SC)); - File.WriteAllText(IntermediateCmdLineFile, ProjectFile); + DirectoryReference.CreateDirectory(GetIntermediateCommandlineDir(SC)); + File.WriteAllText(IntermediateCmdLineFile.FullName, ProjectFile); } } private static void WriteStageCommandline(ProjectParams Params, DeploymentContext SC) { // always delete the existing commandline text file, so it doesn't reuse an old one - string IntermediateCmdLineFile = CombinePaths(GetIntermediateCommandlineDir(SC), "UE4CommandLine.txt"); + FileReference IntermediateCmdLineFile = FileReference.Combine(GetIntermediateCommandlineDir(SC), "UE4CommandLine.txt"); WriteStageCommandline(IntermediateCmdLineFile, Params, SC); } - private static Dictionary ReadDeployedManifest(ProjectParams Params, DeploymentContext SC, List ManifestList) + private static Dictionary ReadDeployedManifest(ProjectParams Params, DeploymentContext SC, List ManifestList) { - Dictionary DeployedFiles = new Dictionary(); - List CRCFiles = SC.StageTargetPlatform.GetFilesForCRCCheck(); + Dictionary DeployedFiles = new Dictionary(); + HashSet CRCFiles = SC.StageTargetPlatform.GetFilesForCRCCheck(); // read the manifest bool bContinueSearch = true; @@ -1611,12 +1470,12 @@ public partial class Project : CommandUtils string[] Pair = Line.Split ('\t'); if (Pair.Length > 1) { - string Filename = Pair [0]; - string TimeStamp = Pair [1]; + StagedFileReference Filename = new StagedFileReference(Pair [0]); + string TimeStamp = Pair[1]; FilesAdded++; if (DeployedFiles.ContainsKey (Filename)) { - if ((CRCFiles.Contains (Filename) && DeployedFiles [Filename] != TimeStamp) || (!CRCFiles.Contains (Filename) && DateTime.Parse (DeployedFiles [Filename]) > DateTime.Parse (TimeStamp))) + if ((CRCFiles.Contains (Filename) && DeployedFiles [Filename] != TimeStamp) || (!CRCFiles.Contains (Filename) && DateTime.Parse(DeployedFiles[Filename]) > DateTime.Parse(TimeStamp))) { DeployedFiles [Filename] = TimeStamp; } @@ -1641,23 +1500,22 @@ public partial class Project : CommandUtils return DeployedFiles; } - protected static Dictionary ReadStagedManifest(ProjectParams Params, DeploymentContext SC, string Manifest) + protected static Dictionary ReadStagedManifest(ProjectParams Params, DeploymentContext SC, string Manifest) { - Dictionary StagedFiles = new Dictionary(); - List CRCFiles = SC.StageTargetPlatform.GetFilesForCRCCheck(); + Dictionary StagedFiles = new Dictionary(); + HashSet CRCFiles = SC.StageTargetPlatform.GetFilesForCRCCheck(); // get the staged manifest from staged directory - string ManifestFile = SC.StageDirectory + "/" + Manifest; - if (File.Exists(ManifestFile)) + FileReference ManifestFile = FileReference.Combine(SC.StageDirectory, Manifest); + if (FileReference.Exists(ManifestFile)) { - string Data = File.ReadAllText(ManifestFile); - string[] Lines = Data.Split('\n'); + string[] Lines = FileReference.ReadAllLines(ManifestFile); foreach (string Line in Lines) { string[] Pair = Line.Split('\t'); if (Pair.Length > 1) { - string Filename = Pair[0]; + StagedFileReference Filename = new StagedFileReference(Pair[0]); string TimeStamp = Pair[1]; if (!StagedFiles.ContainsKey(Filename)) { @@ -1673,12 +1531,12 @@ public partial class Project : CommandUtils return StagedFiles; } - protected static void WriteObsoleteManifest(ProjectParams Params, DeploymentContext SC, Dictionary DeployedFiles, Dictionary StagedFiles, string ObsoleteManifest) + protected static void WriteObsoleteManifest(ProjectParams Params, DeploymentContext SC, Dictionary DeployedFiles, Dictionary StagedFiles, string ObsoleteManifest) { - List ObsoleteFiles = new List(); + List ObsoleteFiles = new List(); // any file that has been deployed, but is no longer in the staged files is obsolete and should be deleted. - foreach (KeyValuePair File in DeployedFiles) + foreach (KeyValuePair File in DeployedFiles) { if (!StagedFiles.ContainsKey(File.Key)) { @@ -1687,20 +1545,20 @@ public partial class Project : CommandUtils } // write out to the deltamanifest.json - string ManifestFile = CombinePaths(SC.StageDirectory, ObsoleteManifest); - StreamWriter Writer = System.IO.File.CreateText(ManifestFile); - foreach (string Line in ObsoleteFiles) + FileReference ManifestFile = FileReference.Combine(SC.StageDirectory, ObsoleteManifest); + StreamWriter Writer = System.IO.File.CreateText(ManifestFile.FullName); + foreach (StagedFileReference ObsoleteFile in ObsoleteFiles) { - Writer.WriteLine(Line); + Writer.WriteLine(ObsoleteFile); } Writer.Close(); } - protected static void WriteDeltaManifest(ProjectParams Params, DeploymentContext SC, Dictionary DeployedFiles, Dictionary StagedFiles, string DeltaManifest) + protected static void WriteDeltaManifest(ProjectParams Params, DeploymentContext SC, Dictionary DeployedFiles, Dictionary StagedFiles, string DeltaManifest) { - List CRCFiles = SC.StageTargetPlatform.GetFilesForCRCCheck(); + HashSet CRCFiles = SC.StageTargetPlatform.GetFilesForCRCCheck(); List DeltaFiles = new List(); - foreach (KeyValuePair File in StagedFiles) + foreach (KeyValuePair File in StagedFiles) { bool bNeedsDeploy = true; if (DeployedFiles.ContainsKey(File.Key)) @@ -1719,7 +1577,7 @@ public partial class Project : CommandUtils if (bNeedsDeploy) { - DeltaFiles.Add(File.Key); + DeltaFiles.Add(File.Key.Name); } } @@ -1733,13 +1591,8 @@ public partial class Project : CommandUtils // TODO: determine files which need to be removed // write out to the deltamanifest.json - string ManifestFile = CombinePaths(SC.StageDirectory, DeltaManifest); - StreamWriter Writer = System.IO.File.CreateText(ManifestFile); - foreach (string Line in DeltaFiles) - { - Writer.WriteLine(Line); - } - Writer.Close(); + FileReference ManifestFile = FileReference.Combine(SC.StageDirectory, DeltaManifest); + FileReference.WriteAllLines(ManifestFile, DeltaFiles); } #endregion @@ -1751,7 +1604,6 @@ public partial class Project : CommandUtils { ParamList ListToProcess = InDedicatedServer && (Params.Cook || Params.CookOnTheFly) ? Params.ServerCookedTargets : Params.ClientCookedTargets; var ConfigsToProcess = InDedicatedServer && (Params.Cook || Params.CookOnTheFly) ? Params.ServerConfigsToBuild : Params.ClientConfigsToBuild; - var CreateWebSocketsServer = Params.ServerTargetPlatforms.Count() > 0 && Params.ClientTargetPlatforms.Contains(new TargetPlatformDescriptor(UnrealTargetPlatform.HTML5)); List PlatformsToStage = Params.ClientTargetPlatforms; if (InDedicatedServer && (Params.Cook || Params.CookOnTheFly)) @@ -1789,14 +1641,15 @@ public partial class Project : CommandUtils string StageDirectory = ((ShouldCreatePak(Params) || (Params.Stage)) || !String.IsNullOrEmpty(Params.StageDirectoryParam)) ? Params.BaseStageDirectory : ""; string ArchiveDirectory = (Params.Archive || !String.IsNullOrEmpty(Params.ArchiveDirectoryParam)) ? Params.BaseArchiveDirectory : ""; - string EngineDir = CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Engine"); + DirectoryReference EngineDir = DirectoryReference.Combine(CommandUtils.RootDirectory, "Engine"); + DirectoryReference ProjectDir = DirectoryReference.FromFile(Params.RawProjectPath); List TargetsToStage = new List(); foreach(string Target in ListToProcess) { foreach(UnrealTargetConfiguration Config in ConfigsToProcess) { - string ReceiptBaseDir = Params.IsCodeBasedProject? Path.GetDirectoryName(Params.RawProjectPath.FullName) : EngineDir; + DirectoryReference ReceiptBaseDir = Params.IsCodeBasedProject? ProjectDir : EngineDir; Platform PlatformInstance = Platform.Platforms[StagePlatform]; UnrealTargetPlatform[] SubPlatformsToStage = PlatformInstance.GetStagePlatforms(); @@ -1815,13 +1668,19 @@ public partial class Project : CommandUtils Architecture = PlatformExports.GetDefaultArchitecture(ReceiptPlatform, Params.RawProjectPath); } } - string ReceiptFileName = TargetReceipt.GetDefaultPath(ReceiptBaseDir, Target, ReceiptPlatform, Config, Architecture); - if(!File.Exists(ReceiptFileName)) + + if (Params.IterateSharedBuildUsePrecompiledExe) + { + continue; + } + + FileReference ReceiptFileName = TargetReceipt.GetDefaultPath(ReceiptBaseDir, Target, ReceiptPlatform, Config, Architecture); + if(!FileReference.Exists(ReceiptFileName)) { if (bRequireStagedFilesToExist) { // if we aren't collecting multiple platforms, then it is expected to exist - throw new AutomationException(ExitCode.Error_MissingExecutable, "Stage Failed. Missing receipt '{0}'. Check that this target has been built.", Path.GetFileName(ReceiptFileName)); + throw new AutomationException(ExitCode.Error_MissingExecutable, "Stage Failed. Missing receipt '{0}'. Check that this target has been built.", Path.GetFileName(ReceiptFileName.FullName)); } else { @@ -1833,22 +1692,21 @@ public partial class Project : CommandUtils // Read the receipt for this target TargetReceipt Receipt; - if(!TargetReceipt.TryRead(ReceiptFileName, out Receipt)) + if(!TargetReceipt.TryRead(ReceiptFileName, EngineDir, ProjectDir, out Receipt)) { throw new AutomationException("Missing or invalid target receipt ({0})", ReceiptFileName); } // Convert the paths to absolute - Receipt.ExpandPathVariables(new DirectoryReference(EngineDir), Params.RawProjectPath.Directory); TargetsToStage.Add(new StageTarget{ Receipt = Receipt, RequireFilesExist = bRequireStagedFilesToExist }); } } } //@todo should pull StageExecutables from somewhere else if not cooked - var SC = new DeploymentContext(Params.RawProjectPath, CmdEnv.LocalRoot, - StageDirectory, - ArchiveDirectory, + var SC = new DeploymentContext(Params.RawProjectPath, CommandUtils.RootDirectory, + String.IsNullOrEmpty(StageDirectory)? null : new DirectoryReference(StageDirectory), + String.IsNullOrEmpty(ArchiveDirectory)? null : new DirectoryReference(ArchiveDirectory), Platform.Platforms[CookedDataPlatform], Platform.Platforms[StagePlatform], ConfigsToProcess, @@ -1862,8 +1720,7 @@ public partial class Project : CommandUtils Params.Archive, Params.IsProgramTarget, Params.Client, - Params.Manifests, - bInUseWebsocketNetDriver: CreateWebSocketsServer + Params.Manifests ); LogDeploymentContext(SC); @@ -1912,8 +1769,8 @@ public partial class Project : CommandUtils List NonUFSManifests; // get the staged file data - Dictionary StagedUFSFiles = ReadStagedManifest(Params, SC, SC.UFSDeployedManifestFileName); - Dictionary StagedNonUFSFiles = ReadStagedManifest(Params, SC, SC.NonUFSDeployedManifestFileName); + Dictionary StagedUFSFiles = ReadStagedManifest(Params, SC, SC.UFSDeployedManifestFileName); + Dictionary StagedNonUFSFiles = ReadStagedManifest(Params, SC, SC.NonUFSDeployedManifestFileName); foreach (var DeviceName in Params.DeviceNames) { @@ -1925,8 +1782,8 @@ public partial class Project : CommandUtils } // get the deployed file data - Dictionary DeployedUFSFiles = new Dictionary(); - Dictionary DeployedNonUFSFiles = new Dictionary(); + Dictionary DeployedUFSFiles = new Dictionary(); + Dictionary DeployedNonUFSFiles = new Dictionary(); if (SC.StageTargetPlatform.RetrieveDeployedManifests(Params, SC, DeviceName, out UFSManifests, out NonUFSManifests)) { diff --git a/Engine/Source/Programs/AutomationTool/Scripts/CopySharedCookedBuild.Automation.cs b/Engine/Source/Programs/AutomationTool/Scripts/CopySharedCookedBuild.Automation.cs new file mode 100644 index 000000000000..0b908f89679e --- /dev/null +++ b/Engine/Source/Programs/AutomationTool/Scripts/CopySharedCookedBuild.Automation.cs @@ -0,0 +1,146 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; +using System.Linq; +using AutomationTool; +using UnrealBuildTool; + + +class CopySharedCookedBuild : BuildCommand +{ + [Help("Copies the current shared cooked build from the network to the local PC")] + [RequireP4] + [DoesNotNeedP4CL] + + FileReference ProjectFile + { + get + { + FileReference ProjectFullPath = null; + var OriginalProjectName = ParseParamValue("project", ""); + + if (string.IsNullOrEmpty(OriginalProjectName)) + { + throw new AutomationException("No project file specified. Use -project=."); + } + + var ProjectName = OriginalProjectName; + ProjectName = ProjectName.Trim(new char[] { '\"' }); + if (ProjectName.IndexOfAny(new char[] { '\\', '/' }) < 0) + { + ProjectName = CombinePaths(CmdEnv.LocalRoot, ProjectName, ProjectName + ".uproject"); + } + else if (!FileExists_NoExceptions(ProjectName)) + { + ProjectName = CombinePaths(CmdEnv.LocalRoot, ProjectName); + } + if (FileExists_NoExceptions(ProjectName)) + { + ProjectFullPath = new FileReference(ProjectName); + } + else + { + var Branch = new BranchInfo(new List { UnrealBuildTool.BuildHostPlatform.Current.Platform }); + var GameProj = Branch.FindGame(OriginalProjectName); + if (GameProj != null) + { + ProjectFullPath = GameProj.FilePath; + } + if (ProjectFullPath == null || !FileExists_NoExceptions(ProjectFullPath.FullName)) + { + throw new AutomationException("Could not find a project file {0}.", ProjectName); + } + } + return ProjectFullPath; + } + } + + public override void ExecuteBuild() + { + Log("************************* CopySharedCookedBuild"); + + // Parse the project filename (as a local path) + + + string CmdLinePlatform = ParseParamValue("Platform", null); + + bool bOnlyCopyAssetRegistry = ParseParam("onlycopyassetregistry"); + + List TargetPlatforms = new List(); + var PlatformNames = new List(CmdLinePlatform.Split('+')); + foreach (var PlatformName in PlatformNames) + { + // Look for dependent platforms, Source_1.Dependent_1+Source_2.Dependent_2+Standalone_3 + var SubPlatformNames = new List(PlatformName.Split('.')); + + foreach (var SubPlatformName in SubPlatformNames) + { + UnrealTargetPlatform NewPlatformType = (UnrealTargetPlatform)Enum.Parse(typeof(UnrealTargetPlatform), SubPlatformName, true); + + TargetPlatforms.Add(NewPlatformType); + } + } + + + + + foreach (var PlatformType in TargetPlatforms) + { + SharedCookedBuild.CopySharedCookedBuildForTarget(ProjectFile.FullName, PlatformType, PlatformType.ToString(), bOnlyCopyAssetRegistry); + SharedCookedBuild.WaitForCopy(); + } + + + /* + // Build the list of paths that need syncing + List SyncPaths = new List(); + if(bIsProjectFile) + { + SyncPaths.Add(CommandUtils.CombinePaths(PathSeparator.Slash, BranchRoot, "*")); + SyncPaths.Add(CommandUtils.CombinePaths(PathSeparator.Slash, BranchRoot, "Engine", "...")); + SyncPaths.Add(CommandUtils.CombinePaths(PathSeparator.Slash, CommandUtils.GetDirectoryName(ProjectFileRecord.DepotFile), "...")); + } + else + { + SyncPaths.Add(CommandUtils.CombinePaths(PathSeparator.Slash, CommandUtils.GetDirectoryName(ProjectFileRecord.DepotFile), "...")); + } + + // Sync them down + foreach(string SyncPath in SyncPaths) + { + Log("Syncing {0}@{1}", SyncPath, CL); + P4.Sync(String.Format("{0}@{1}", SyncPath, CL)); + } + + // Get the name of the editor target + string EditorTargetName = "UE4Editor"; + if(bIsProjectFile) + { + string SourceDirectoryName = Path.Combine(Path.GetDirectoryName(ProjectFileName), "Source"); + if(Directory.Exists(SourceDirectoryName)) + { + foreach(string EditorTargetFileName in Directory.EnumerateFiles(SourceDirectoryName, "*Editor.Target.cs")) + { + EditorTargetName = Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(EditorTargetFileName)); + break; + } + } + } + + // Build everything + UnrealTargetPlatform CurrentPlatform = HostPlatform.Current.HostEditorPlatform; + + UE4Build.BuildAgenda Agenda = new UE4Build.BuildAgenda(); + Agenda.AddTarget("UnrealHeaderTool", CurrentPlatform, UnrealTargetConfiguration.Development); + Agenda.AddTarget(EditorTargetName, CurrentPlatform, UnrealTargetConfiguration.Development, ProjectFileName.EndsWith(".uproject", StringComparison.InvariantCultureIgnoreCase)? new FileReference(ProjectFileName) : null); + Agenda.AddTarget("ShaderCompileWorker", CurrentPlatform, UnrealTargetConfiguration.Development); + Agenda.AddTarget("UnrealLightmass", CurrentPlatform, UnrealTargetConfiguration.Development); + Agenda.AddTarget("CrashReportClient", CurrentPlatform, UnrealTargetConfiguration.Shipping); + + UE4Build Build = new UE4Build(this); + Build.UpdateVersionFiles(ActuallyUpdateVersionFiles: true, ChangelistNumberOverride: CL); + Build.Build(Agenda, InUpdateVersionFiles: false);*/ + } +} \ No newline at end of file diff --git a/Engine/Source/Programs/AutomationTool/Scripts/FixupRedirects.Automation.cs b/Engine/Source/Programs/AutomationTool/Scripts/FixupRedirects.Automation.cs index d048c110b05e..b4b19b072086 100644 --- a/Engine/Source/Programs/AutomationTool/Scripts/FixupRedirects.Automation.cs +++ b/Engine/Source/Programs/AutomationTool/Scripts/FixupRedirects.Automation.cs @@ -10,13 +10,10 @@ class FixupRedirects : BuildCommand { public override void ExecuteBuild() { - var EditorExe = CombinePaths(CmdEnv.LocalRoot, @"Engine/Binaries/Win64/UE4Editor-Cmd.exe"); - Log("********** Running FixupRedirects: {0} -run=FixupRedirects -unattended -nopause -buildmachine", EditorExe); - var RunResult = Run(EditorExe, String.Format("-run=FixupRedirects -unattended -nopause -buildmachine -autosubmit")); - if (RunResult.ExitCode != 0) - { - throw new AutomationException("BUILD FAILED: FixupRedirects failed"); - } + var ProjectName = ParseParamValue("project", ""); + var EditorExe = CombinePaths(CmdEnv.LocalRoot, @"Engine/Binaries/Win64/UE4Editor-Cmd.exe"); + Log("********** Running FixupRedirects: {0} -run=ResavePackages -unattended -nopause -buildmachine -fixupredirects -autocheckout -autocheckin -projectonly", EditorExe); + RunCommandlet(GetCommandletProjectFile(ProjectName), EditorExe, "ResavePackages", "-unattended -nopause -buildmachine -fixupredirects -autocheckout -autocheckin -projectonly"); } } diff --git a/Engine/Source/Programs/AutomationTool/Scripts/InstalledBuild.cs b/Engine/Source/Programs/AutomationTool/Scripts/InstalledBuild.cs index 07d2bcfeb7c8..466ad59b81d3 100644 --- a/Engine/Source/Programs/AutomationTool/Scripts/InstalledBuild.cs +++ b/Engine/Source/Programs/AutomationTool/Scripts/InstalledBuild.cs @@ -109,12 +109,12 @@ namespace AutomationTool { // Need to check for development receipt as we use that for the Engine code in DebugGame UnrealTargetConfiguration EngineConfiguration = (CodeTargetConfiguration == UnrealTargetConfiguration.DebugGame) ? UnrealTargetConfiguration.Development : CodeTargetConfiguration; - string ReceiptFileName = TargetReceipt.GetDefaultPath(OutputEnginePath, "UE4Game", CodeTargetPlatform, EngineConfiguration, Architecture); + FileReference ReceiptFileName = TargetReceipt.GetDefaultPath(new DirectoryReference(OutputEnginePath), "UE4Game", CodeTargetPlatform, EngineConfiguration, Architecture); - if (File.Exists(ReceiptFileName)) + if (FileReference.Exists(ReceiptFileName)) { // Strip the output folder so that this can be used on any machine - ReceiptFileName = new FileReference(ReceiptFileName).MakeRelativeTo(new DirectoryReference(OutputDir)); + string RelativeReceiptFileName = ReceiptFileName.MakeRelativeTo(new DirectoryReference(OutputDir)); // If we have pre-compiled architectures for this platform then add an entry for each of these - // there isn't a receipt for each architecture like some other platforms @@ -122,12 +122,12 @@ namespace AutomationTool { foreach (string Arch in AllArchNames) { - InstalledConfigs.Add(new InstalledPlatformInfo.InstalledPlatformConfiguration(CodeTargetConfiguration, CodeTargetPlatform, TargetType.Game, Arch, ReceiptFileName, ProjectType, bCanBeDisplayed)); + InstalledConfigs.Add(new InstalledPlatformInfo.InstalledPlatformConfiguration(CodeTargetConfiguration, CodeTargetPlatform, TargetType.Game, Arch, RelativeReceiptFileName, ProjectType, bCanBeDisplayed)); } } else { - InstalledConfigs.Add(new InstalledPlatformInfo.InstalledPlatformConfiguration(CodeTargetConfiguration, CodeTargetPlatform, TargetType.Game, Architecture, ReceiptFileName, ProjectType, bCanBeDisplayed)); + InstalledConfigs.Add(new InstalledPlatformInfo.InstalledPlatformConfiguration(CodeTargetConfiguration, CodeTargetPlatform, TargetType.Game, Architecture, RelativeReceiptFileName, ProjectType, bCanBeDisplayed)); } } } diff --git a/Engine/Source/Programs/AutomationTool/Scripts/RunProjectCommand.Automation.cs b/Engine/Source/Programs/AutomationTool/Scripts/RunProjectCommand.Automation.cs index 0a1c4d0db33c..dbf871880cdd 100644 --- a/Engine/Source/Programs/AutomationTool/Scripts/RunProjectCommand.Automation.cs +++ b/Engine/Source/Programs/AutomationTool/Scripts/RunProjectCommand.Automation.cs @@ -130,15 +130,19 @@ public partial class Project : CommandUtils { TargetPlatformDescriptor ServerPlatformDesc = Params.ServerTargetPlatforms[0]; ServerProcess = RunDedicatedServer(Params, ServerLogFile, Params.RunCommandline); - // With dedicated server, the client connects to local host to load a map. - if (ServerPlatformDesc.Type == UnrealTargetPlatform.Linux) - { - Params.MapToRun = Params.ServerDeviceAddress; - } - else - { - Params.MapToRun = "127.0.0.1"; - } + + // With dedicated server, the client connects to local host to load a map, unless client parameters are already specified + if (String.IsNullOrEmpty(Params.ClientCommandline)) + { + if (!String.IsNullOrEmpty(Params.ServerDeviceAddress)) + { + Params.ClientCommandline = Params.ServerDeviceAddress; + } + else + { + Params.ClientCommandline = "127.0.0.1"; + } + } } else { @@ -620,17 +624,21 @@ public partial class Project : CommandUtils ClientRunFlags = ERunOptions.AllowSpew | ERunOptions.AppMustExist; ClientApp = ""; ClientCmdLine = ""; - string TempCmdLine = ""; + string TempCmdLine = SC.ProjectArgForCommandLines + " "; var PlatformName = Params.ClientTargetPlatforms[0].ToString(); if (Params.Cook || Params.CookOnTheFly) { - List Exes = SC.StageTargetPlatform.GetExecutableNames(SC, true); - ClientApp = Exes[0]; - if (SC.StageTargetPlatform.PlatformType != UnrealTargetPlatform.IOS) - { - TempCmdLine += SC.ProjectArgForCommandLines + " "; - } - TempCmdLine += Params.MapToRun + " "; + List Exes = SC.StageTargetPlatform.GetExecutableNames(SC); + ClientApp = Exes[0].FullName; + + if (!String.IsNullOrEmpty(Params.ClientCommandline)) + { + TempCmdLine += Params.ClientCommandline + " "; + } + else + { + TempCmdLine += Params.MapToRun + " "; + } if (Params.CookOnTheFly || Params.FileServer) { @@ -798,7 +806,7 @@ public partial class Project : CommandUtils } else if (!Params.Stage) { - var SandboxPath = CombinePaths(SC.RuntimeProjectRootDir, "Saved", "Cooked", SC.CookPlatform); + var SandboxPath = CombinePaths(SC.RuntimeProjectRootDir.FullName, "Saved", "Cooked", SC.CookPlatform); if (!SC.StageTargetPlatform.LaunchViaUFE) { TempCmdLine += "-sandbox=" + CommandUtils.MakePathSafeToUseWithCommandLine(SandboxPath) + " "; @@ -812,7 +820,6 @@ public partial class Project : CommandUtils else { ClientApp = CombinePaths(CmdEnv.LocalRoot, "Engine/Binaries", PlatformName, "UE4Editor.exe"); - TempCmdLine += SC.ProjectArgForCommandLines + " "; if (!Params.EditorTest) { TempCmdLine += "-game " + Params.MapToRun + " "; @@ -861,13 +868,12 @@ public partial class Project : CommandUtils { TempCmdLine += "-abslog=" + CommandUtils.MakePathSafeToUseWithCommandLine(ClientLogFile) + " "; } - if (SC.StageTargetPlatform.PlatformType != UnrealTargetPlatform.IOS && SC.StageTargetPlatform.PlatformType != UnrealTargetPlatform.Linux) + if (SC.StageTargetPlatform.PlatformType == UnrealTargetPlatform.Win32 || SC.StageTargetPlatform.PlatformType == UnrealTargetPlatform.Win64) { - TempCmdLine += "-Messaging -nomcp -Windowed "; + TempCmdLine += "-Messaging -Windowed "; } else { - // skip arguments which don't make sense for iOS TempCmdLine += "-Messaging "; } if (Params.NullRHI && SC.StageTargetPlatform.PlatformType != UnrealTargetPlatform.Mac) // all macs have GPUs, and currently the mac dies with nullrhi @@ -951,8 +957,8 @@ public partial class Project : CommandUtils var ServerApp = CombinePaths(CmdEnv.LocalRoot, "Engine/Binaries/Win64/UE4Editor.exe"); if (ServerParams.Cook) { - List Exes = SC.StageTargetPlatform.GetExecutableNames(SC); - ServerApp = Exes[0]; + List Exes = SC.StageTargetPlatform.GetExecutableNames(SC); + ServerApp = Exes[0].FullName; } var Args = ServerParams.Cook ? "" : (SC.ProjectArgForCommandLines + " "); Console.WriteLine(Params.ServerDeviceAddress); @@ -986,12 +992,7 @@ public partial class Project : CommandUtils { Args += " -unattended"; } - // Do not blindly add -nomcp, only do so if the client is using it - if (Params.RunCommandline.Contains("-nomcp")) - { - Args += " -nomcp"; - } - + if (Params.ServerCommandline.Length > 0) { Args += " " + Params.ServerCommandline; diff --git a/Engine/Source/Programs/AutomationTool/Scripts/SharedCookedBuild.cs b/Engine/Source/Programs/AutomationTool/Scripts/SharedCookedBuild.cs new file mode 100644 index 000000000000..84e997056360 --- /dev/null +++ b/Engine/Source/Programs/AutomationTool/Scripts/SharedCookedBuild.cs @@ -0,0 +1,195 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Reflection; +using System.Linq; +using System.Threading.Tasks; +using AutomationTool; +using UnrealBuildTool; + + +public class SharedCookedBuild +{ + private static Task CopySharedCookedBuildTask = null; + + private static bool CopySharedCookedBuildForTargetInternal(string CookedBuildPath, string CookPlatform, string LocalPath, bool bOnlyCopyAssetRegistry) + { + + string BuildRoot = CommandUtils.P4Enabled ? CommandUtils.P4Env.BuildRootP4.Replace("/", "+") : ""; + string RecentCL = CommandUtils.P4Enabled ? CommandUtils.P4Env.Changelist.ToString() : ""; + + BuildVersion Version; + if (BuildVersion.TryRead(out Version)) + { + RecentCL = Version.Changelist.ToString(); + BuildRoot = Version.BranchName; + } + System.GC.Collect(); + + // check to see if we have already synced this build ;) + var SyncedBuildFile = CommandUtils.CombinePaths(LocalPath, "SyncedBuild.txt"); + string BuildCL = "Invalid"; + if (File.Exists(SyncedBuildFile)) + { + BuildCL = File.ReadAllText(SyncedBuildFile); + } + + if (RecentCL == "" && CookedBuildPath.Contains("[CL]")) + { + CommandUtils.Log("Unable to copy shared cooked build: Unable to determine CL number from P4 or UGS, and is required by SharedCookedBuildPath"); + return false; + } + + if (RecentCL == "" && CookedBuildPath.Contains("[BRANCHNAME]")) + { + CommandUtils.Log("Unable to copy shared cooked build: Unable to determine BRANCHNAME number from P4 or UGS, and is required by SharedCookedBuildPath"); + return false; + } + + + CookedBuildPath = CookedBuildPath.Replace("[CL]", RecentCL.ToString()); + CookedBuildPath = CookedBuildPath.Replace("[BRANCHNAME]", BuildRoot); + CookedBuildPath = CookedBuildPath.Replace("[PLATFORM]", CookPlatform); + + if (Directory.Exists(CookedBuildPath) == false) + { + CommandUtils.Log("Unable to copy shared cooked build: Unable to find shared build at location {0} check SharedCookedBuildPath in Engine.ini SharedCookedBuildSettings is correct", CookedBuildPath); + return false; + } + + CommandUtils.Log("Attempting download of latest shared build CL {0} from location {1}", RecentCL, CookedBuildPath); + + if (BuildCL == RecentCL.ToString()) + { + CommandUtils.Log("Already downloaded latest shared build at CL {0}", RecentCL); + return false; + } + + if (bOnlyCopyAssetRegistry) + { + RecentCL += "RegistryOnly"; + } + + if ( BuildCL == RecentCL ) + { + CommandUtils.Log("Already downloaded latest shared build at CL {0}", RecentCL); + return false; + } + + // delete all the stuff + CommandUtils.Log("Deleting previous shared build because it was out of date"); + CommandUtils.DeleteDirectory(LocalPath); + Directory.CreateDirectory(LocalPath); + + + + string CookedBuildCookedDirectory = Path.Combine(CookedBuildPath, "Cooked"); + CookedBuildCookedDirectory = Path.GetFullPath(CookedBuildCookedDirectory); + string LocalBuildCookedDirectory = Path.Combine(LocalPath, "Cooked"); + LocalBuildCookedDirectory = Path.GetFullPath(LocalBuildCookedDirectory); + if (Directory.Exists(CookedBuildCookedDirectory)) + { + foreach (string FileName in Directory.EnumerateFiles(CookedBuildCookedDirectory, "*.*", SearchOption.AllDirectories)) + { + string SourceFileName = Path.GetFullPath(FileName); + string DestFileName = SourceFileName.Replace(CookedBuildCookedDirectory, LocalBuildCookedDirectory); + Directory.CreateDirectory(Path.GetDirectoryName(DestFileName)); + File.Copy(SourceFileName, DestFileName); + } + } + + if ( CopySharedCookedBuildTask != null ) + { + WaitForCopy(); + } + + if (bOnlyCopyAssetRegistry == false) + { + CopySharedCookedBuildTask = Task.Run(() => + { + // find all the files in the staged directory + string CookedBuildStagedDirectory = Path.GetFullPath(Path.Combine(CookedBuildPath, "Staged")); + string LocalBuildStagedDirectory = Path.GetFullPath(Path.Combine(LocalPath, "Staged")); + if (Directory.Exists(CookedBuildStagedDirectory)) + { + foreach (string FileName in Directory.EnumerateFiles(CookedBuildStagedDirectory, "*.*", SearchOption.AllDirectories)) + { + string SourceFileName = Path.GetFullPath(FileName); + string DestFileName = SourceFileName.Replace(CookedBuildStagedDirectory, LocalBuildStagedDirectory); + Directory.CreateDirectory(Path.GetDirectoryName(DestFileName)); + File.Copy(SourceFileName, DestFileName); + } + } + File.WriteAllText(SyncedBuildFile, RecentCL.ToString()); + } + ); + } + else + { + File.WriteAllText(SyncedBuildFile, RecentCL.ToString()); + } + + + return true; + } + + public static void CopySharedCookedBuildForTarget(string ProjectFullPath, UnrealTargetPlatform TargetPlatform, string CookPlatform, bool bOnlyCopyAssetRegistry = false) + { + var LocalPath = CommandUtils.CombinePaths(Path.GetDirectoryName(ProjectFullPath), "Saved", "SharedIterativeBuild", CookPlatform); + + FileReference ProjectFileRef = new FileReference(ProjectFullPath); + // get network location + ConfigHierarchy Hierarchy = ConfigCache.ReadHierarchy(ConfigHierarchyType.Engine, DirectoryReference.FromFile(ProjectFileRef), TargetPlatform); + List CookedBuildPaths; + if (Hierarchy.GetArray("SharedCookedBuildSettings", "SharedCookedBuildPath", out CookedBuildPaths) == false) + { + CommandUtils.Log("Unable to copy shared cooked build: SharedCookedBuildPath not set in Engine.ini SharedCookedBuildSettings"); + return; + } + foreach (var CookedBuildPath in CookedBuildPaths) + { + if (CopySharedCookedBuildForTargetInternal(CookedBuildPath, CookPlatform, LocalPath, bOnlyCopyAssetRegistry) == true) + { + return; + } + } + + return; + } + + public static void CopySharedCookedBuild(ProjectParams Params) + { + + if (!Params.NoClient) + { + foreach (var ClientPlatform in Params.ClientTargetPlatforms) + { + // Use the data platform, sometimes we will copy another platform's data + var DataPlatformDesc = Params.GetCookedDataPlatformForClientTarget(ClientPlatform); + string PlatformToCook = Platform.Platforms[DataPlatformDesc].GetCookPlatform(false, Params.Client); + CopySharedCookedBuildForTarget(Params.RawProjectPath.FullName, ClientPlatform.Type, PlatformToCook); + } + } + if (Params.DedicatedServer) + { + foreach (var ServerPlatform in Params.ServerTargetPlatforms) + { + // Use the data platform, sometimes we will copy another platform's data + var DataPlatformDesc = Params.GetCookedDataPlatformForServerTarget(ServerPlatform); + string PlatformToCook = Platform.Platforms[DataPlatformDesc].GetCookPlatform(true, false); + CopySharedCookedBuildForTarget(Params.RawProjectPath.FullName, ServerPlatform.Type, PlatformToCook); + } + } + } + + public static void WaitForCopy() + { + if (CopySharedCookedBuildTask != null) + { + CopySharedCookedBuildTask.Wait(); + } + } + +} \ No newline at end of file diff --git a/Engine/Source/Programs/AutomationTool/Scripts/StageTargetCommand.Automation.cs b/Engine/Source/Programs/AutomationTool/Scripts/StageTargetCommand.Automation.cs deleted file mode 100644 index 4cb58ad2fcd4..000000000000 --- a/Engine/Source/Programs/AutomationTool/Scripts/StageTargetCommand.Automation.cs +++ /dev/null @@ -1,1730 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -using AutomationTool; -using System; -using System.Collections.Generic; -using System.IO; -using System.Net.NetworkInformation; -using System.Reflection; -using System.Text.RegularExpressions; -using System.Threading; -using System.Linq; -using UnrealBuildTool; - -[Help("Stages a target")] -[Help("Project", "Specify the project with the targets to stage.")] -[Help("Target", "Specify a list of target descriptor files for the targets to stage, separated by '+' characters (eg. -Target=Game+Client+Server). Default is Game.")] -[Help("TargetPlatforms", "Specify a list of target platforms to stage, separated by '+' characters (eg. -TargetPlatforms=Win32+Win64+IOS). Default is Win64.")] -class StageTargetCommand : BuildCommand -{ - private class StageContext - { -/* public string UProjectPath; - public Platform StagePlatform; - public List StageConfigurations; - public List StageTargets;*/ - public Dictionary> NonUFSStagingFiles = new Dictionary>(); - public Dictionary> UFSStagingFiles = new Dictionary>(); - } - - private ParamList ParseParamList(string InArgument, string InDefault = null) - { - var ArgumentList = ParseParamValue(InArgument); - if (ArgumentList != null) - { - return new ParamList(ArgumentList.Split('+')); - } - else if (!String.IsNullOrEmpty(InDefault)) - { - return new ParamList(InDefault); - } - return null; - } - - public override void ExecuteBuild() - { - // get the project - var UProjectFileName = ParseParamValue("Project"); - if (UProjectFileName == null) - { - throw new AutomationException("Project was not specified via the -project argument."); - } - - // get the list of platforms - var PlatformList = ParseParamList("TargetPlatforms", "WindowsNoEditor"); - List TargetPlatforms = new List(); - foreach (string Platform in PlatformList) - { - TargetPlatforms.Add((UnrealTargetPlatform)Enum.Parse(typeof(UnrealTargetPlatform), Platform, true)); - } - - // create the staging context(s) - - } - - /* - #region Utilities - - private static readonly object SyncLock = new object(); - - /// The path for the BuildPatchTool executable depending on host platform. - private static string GetBuildPatchToolExecutable() - { - switch (UnrealBuildTool.BuildHostPlatform.Current.Platform) - { - case UnrealTargetPlatform.Win32: - return CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Engine/Binaries/Win32/BuildPatchTool.exe"); - case UnrealTargetPlatform.Win64: - return CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Engine/Binaries/Win64/BuildPatchTool.exe"); - case UnrealTargetPlatform.Mac: - return CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Engine/Binaries/Mac/BuildPatchTool"); - case UnrealTargetPlatform.Linux: - return CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Engine/Binaries/Linux/BuildPatchTool"); - } - throw new AutomationException(string.Format("Unknown host platform for BuildPatchTool - {0}", UnrealBuildTool.BuildHostPlatform.Current.Platform)); - } - - /// - /// Checks the existence of the BuildPatchTool executable exists and builds it if it is missing - /// - private static void EnsureBuildPatchToolExists() - { - string BuildPatchToolExe = GetBuildPatchToolExecutable(); - if (!CommandUtils.FileExists_NoExceptions(BuildPatchToolExe)) - { - lock (SyncLock) - { - if (!CommandUtils.FileExists_NoExceptions(BuildPatchToolExe)) - { - UE4BuildUtils.BuildBuildPatchTool(null, UnrealBuildTool.BuildHostPlatform.Current.Platform); - } - } - } - } - - /// - /// Writes a pak response file to disk - /// - /// - /// - private static void WritePakResponseFile(string Filename, Dictionary ResponseFile, bool Compressed) - { - using (var Writer = new StreamWriter(Filename, false, new System.Text.UTF8Encoding(true))) - { - foreach (var Entry in ResponseFile) - { - string Line = String.Format("\"{0}\" \"{1}\"", Entry.Key, Entry.Value); - if (Compressed) - { - Line += " -compress"; - } - Writer.WriteLine(Line); - } - } - } - - /// - /// Loads streaming install chunk manifest file from disk - /// - /// - /// - private static HashSet ReadPakChunkManifest(string Filename) - { - var ResponseFile = ReadAllLines(Filename); - var Result = new HashSet(ResponseFile, StringComparer.InvariantCultureIgnoreCase); - return Result; - } - - static public void RunUnrealPak(Dictionary UnrealPakResponseFile, string OutputLocation, string EncryptionKeys, string PakOrderFileLocation, string PlatformOptions, bool Compressed, String PatchSourceContentPath) - { - if (UnrealPakResponseFile.Count < 1) - { - return; - } - string PakName = Path.GetFileNameWithoutExtension(OutputLocation); - string UnrealPakResponseFileName = CombinePaths(CmdEnv.LogFolder, "PakList_" + PakName + ".txt"); - WritePakResponseFile(UnrealPakResponseFileName, UnrealPakResponseFile, Compressed); - - var UnrealPakExe = CombinePaths(CmdEnv.LocalRoot, "Engine/Binaries/Win64/UnrealPak.exe"); - - Log("Running UnrealPak *******"); - string CmdLine = CommandUtils.MakePathSafeToUseWithCommandLine(OutputLocation) + " -create=" + CommandUtils.MakePathSafeToUseWithCommandLine(UnrealPakResponseFileName); - if (!String.IsNullOrEmpty(EncryptionKeys)) - { - CmdLine += " -sign=" + CommandUtils.MakePathSafeToUseWithCommandLine(EncryptionKeys); - } - if (GlobalCommandLine.Installed) - { - CmdLine += " -installed"; - } - CmdLine += " -order=" + CommandUtils.MakePathSafeToUseWithCommandLine(PakOrderFileLocation); - if (GlobalCommandLine.UTF8Output) - { - CmdLine += " -UTF8Output"; - } - if (!String.IsNullOrEmpty(PatchSourceContentPath)) - { - CmdLine += " -generatepatch=" + CommandUtils.MakePathSafeToUseWithCommandLine(PatchSourceContentPath); - } - CmdLine += PlatformOptions; - RunAndLog(CmdEnv, UnrealPakExe, CmdLine, Options: ERunOptions.Default | ERunOptions.UTF8Output); - Log("UnrealPak Done *******"); - } - - static public void LogDeploymentContext(DeploymentContext SC) - { - LogLog("Deployment Context **************"); - LogLog("ArchiveDirectory = {0}", SC.ArchiveDirectory); - LogLog("RawProjectPath = {0}", SC.RawProjectPath); - LogLog("IsCodeBasedUprojectFile = {0}", SC.IsCodeBasedProject); - LogLog("DedicatedServer = {0}", SC.DedicatedServer); - LogLog("Stage = {0}", SC.Stage); - LogLog("StageTargetPlatform = {0}", SC.StageTargetPlatform.PlatformType.ToString()); - LogLog("LocalRoot = {0}", SC.LocalRoot); - LogLog("ProjectRoot = {0}", SC.ProjectRoot); - LogLog("PlatformDir = {0}", SC.PlatformDir); - LogLog("StageProjectRoot = {0}", SC.StageProjectRoot); - LogLog("ShortProjectName = {0}", SC.ShortProjectName); - LogLog("StageDirectory = {0}", SC.StageDirectory); - LogLog("SourceRelativeProjectRoot = {0}", SC.SourceRelativeProjectRoot); - LogLog("RelativeProjectRootForStage = {0}", SC.RelativeProjectRootForStage); - LogLog("RelativeProjectRootForUnrealPak = {0}", SC.RelativeProjectRootForUnrealPak); - LogLog("ProjectArgForCommandLines = {0}", SC.ProjectArgForCommandLines); - LogLog("RuntimeRootDir = {0}", SC.RuntimeRootDir); - LogLog("RuntimeProjectRootDir = {0}", SC.RuntimeProjectRootDir); - LogLog("UProjectCommandLineArgInternalRoot = {0}", SC.UProjectCommandLineArgInternalRoot); - LogLog("PakFileInternalRoot = {0}", SC.PakFileInternalRoot); - LogLog("UnrealFileServerInternalRoot = {0}", SC.UnrealFileServerInternalRoot); - LogLog("End Deployment Context **************"); - } - - public static Dictionary ConvertToLower(Dictionary Mapping) - { - var Result = new Dictionary(); - foreach (var Pair in Mapping) - { - Result.Add(Pair.Key, Pair.Value.ToLowerInvariant()); - } - return Result; - } - - public static void MaybeConvertToLowerCase(ProjectParams Params, DeploymentContext SC) - { - var BuildPlatform = SC.StageTargetPlatform; - - if (BuildPlatform.DeployLowerCaseFilenames(false)) - { - SC.NonUFSStagingFiles = ConvertToLower(SC.NonUFSStagingFiles); - SC.NonUFSStagingFilesDebug = ConvertToLower(SC.NonUFSStagingFilesDebug); - } - if (Params.UsePak(SC.StageTargetPlatform) && BuildPlatform.DeployPakInternalLowerCaseFilenames()) - { - SC.UFSStagingFiles = ConvertToLower(SC.UFSStagingFiles); - } - else if (!Params.UsePak(SC.StageTargetPlatform) && BuildPlatform.DeployLowerCaseFilenames(true)) - { - SC.UFSStagingFiles = ConvertToLower(SC.UFSStagingFiles); - } - } - - private static int StageLocalizationDataForCulture(DeploymentContext SC, string CultureName, string SourceDirectory, string DestinationDirectory = null, bool bRemap = true) - { - int FilesAdded = 0; - - CultureName = CultureName.Replace('-', '_'); - - string[] LocaleTags = CultureName.Replace('-', '_').Split('_'); - - List PotentialParentCultures = new List(); - - if (LocaleTags.Length > 0) - { - if (LocaleTags.Length > 1 && LocaleTags.Length > 2) - { - PotentialParentCultures.Add(string.Join("_", LocaleTags[0], LocaleTags[1], LocaleTags[2])); - } - if (LocaleTags.Length > 2) - { - PotentialParentCultures.Add(string.Join("_", LocaleTags[0], LocaleTags[2])); - } - if (LocaleTags.Length > 1) - { - PotentialParentCultures.Add(string.Join("_", LocaleTags[0], LocaleTags[1])); - } - PotentialParentCultures.Add(LocaleTags[0]); - } - - string[] FoundDirectories = CommandUtils.FindDirectories(true, "*", false, new string[] { SourceDirectory }); - foreach (string FoundDirectory in FoundDirectories) - { - string DirectoryName = CommandUtils.GetLastDirectoryName(FoundDirectory); - string CanonicalizedPotentialCulture = DirectoryName.Replace('-', '_'); - - if (PotentialParentCultures.Contains(CanonicalizedPotentialCulture)) - { - FilesAdded += SC.StageFiles(StagedFileType.UFS, CombinePaths(SourceDirectory, DirectoryName), "*.locres", true, null, DestinationDirectory != null ? CombinePaths(DestinationDirectory, DirectoryName) : null, true, bRemap); - } - } - - return FilesAdded; - } - - public static void CreateStagingManifest(ProjectParams Params, DeploymentContext SC) - { - if (!Params.Stage) - { - return; - } - var ThisPlatform = SC.StageTargetPlatform; - - Log("Creating Staging Manifest..."); - - if (Params.HasDLCName) - { - string DLCName = Params.DLCName; - - // Making a plugin, grab the binaries too - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.ProjectRoot, "Plugins", DLCName), "*.uplugin", true, null, null, true); - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.ProjectRoot, "Plugins", DLCName, "Binaries"), "libUE4-*.so", true, null, null, true); - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.ProjectRoot, "Plugins", DLCName, "Binaries"), "UE4-*.dll", true, null, null, true); - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.ProjectRoot, "Plugins", DLCName, "Binaries"), "libUE4Server-*.so", true, null, null, true); - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.ProjectRoot, "Plugins", DLCName, "Binaries"), "UE4Server-*.dll", true, null, null, true); - - // Put all of the cooked dir into the staged dir - // Dedicated server cook doesn't save shaders so no Engine dir is created - if ((!SC.DedicatedServer) && (!Params.DLCIncludeEngineContent)) - { - if (Directory.Exists(CombinePaths(SC.ProjectRoot, "Plugins", DLCName, "Saved", "Cooked", SC.CookPlatform, "Engine"))) - { - SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.ProjectRoot, "Plugins", DLCName, "Saved", "Cooked", SC.CookPlatform), "*", true, new[] { CommandUtils.CombinePaths("Engine", "*") }, "", true, !Params.UsePak(SC.StageTargetPlatform)); - } - } - - SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.ProjectRoot, "Plugins", DLCName, "Saved", "Cooked", SC.CookPlatform), "*", true, new[] { "AssetRegistry.bin" }, "", true, !Params.UsePak(SC.StageTargetPlatform)); - - return; - } - - - ThisPlatform.GetFilesToDeployOrStage(Params, SC); - - - // Stage any extra runtime dependencies from the receipts - foreach(StageTarget Target in SC.StageTargets) - { - SC.StageRuntimeDependenciesFromReceipt(Target.Receipt, Target.RequireFilesExist); - } - - // Get the build.properties file - // this file needs to be treated as a UFS file for casing, but NonUFS for being put into the .pak file - // @todo: Maybe there should be a new category - UFSNotForPak - string BuildPropertiesPath = CombinePaths(SC.LocalRoot, "Engine/Build"); - if (SC.StageTargetPlatform.DeployLowerCaseFilenames(true)) - { - BuildPropertiesPath = BuildPropertiesPath.ToLowerInvariant(); - } - SC.StageFiles(StagedFileType.NonUFS, BuildPropertiesPath, "Build.version", false, null, null, true); - - // move the UE4Commandline.txt file to the root of the stage - // this file needs to be treated as a UFS file for casing, but NonUFS for being put into the .pak file - // @todo: Maybe there should be a new category - UFSNotForPak - string CommandLineFile = "UE4CommandLine.txt"; - if (SC.StageTargetPlatform.DeployLowerCaseFilenames(true)) - { - CommandLineFile = CommandLineFile.ToLowerInvariant(); - } - SC.StageFiles(StagedFileType.NonUFS, GetIntermediateCommandlineDir(SC), CommandLineFile, false, null, "", true, false); - - ConfigCacheIni PlatformGameConfig = new ConfigCacheIni(SC.StageTargetPlatform.PlatformType, "Game", CommandUtils.GetDirectoryName(Params.RawProjectPath)); - var ProjectContentRoot = CombinePaths(SC.ProjectRoot, "Content"); - var StageContentRoot = CombinePaths(SC.RelativeProjectRootForStage, "Content"); - - if (!Params.CookOnTheFly && !Params.SkipCookOnTheFly) // only stage the UFS files if we are not using cook on the fly - { - - - // Initialize internationalization preset. - string InternationalizationPreset = null; - - // Use parameters if provided. - if (string.IsNullOrEmpty(InternationalizationPreset)) - { - InternationalizationPreset = Params.InternationalizationPreset; - } - - // Use configuration if otherwise lacking an internationalization preset. - if (string.IsNullOrEmpty(InternationalizationPreset)) - { - if (PlatformGameConfig != null) - { - PlatformGameConfig.GetString("/Script/UnrealEd.ProjectPackagingSettings", "InternationalizationPreset", out InternationalizationPreset); - } - } - - // Error if no preset has been provided. - if (string.IsNullOrEmpty(InternationalizationPreset)) - { - throw new AutomationException("No internationalization preset was specified for packaging. This will lead to fatal errors when launching. Specify preset via commandline (-I18NPreset=) or project packaging settings (InternationalizationPreset)."); - } - - // Initialize cultures to stage. - List CulturesToStage = null; - - // Use parameters if provided. - if (Params.CulturesToCook != null && Params.CulturesToCook.Count > 0) - { - CulturesToStage = Params.CulturesToCook; - } - - // Use configuration if otherwise lacking cultures to stage. - if (CulturesToStage == null || CulturesToStage.Count == 0) - { - if (PlatformGameConfig != null) - { - PlatformGameConfig.GetArray("/Script/UnrealEd.ProjectPackagingSettings", "CulturesToStage", out CulturesToStage); - } - } - - // Error if no cultures have been provided. - if (CulturesToStage == null || CulturesToStage.Count == 0) - { - throw new AutomationException("No cultures were specified for cooking and packaging. This will lead to fatal errors when launching. Specify culture codes via commandline (-CookCultures=) or using project packaging settings (+CulturesToStage)."); - } - - // Stage ICU internationalization data from Engine. - SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.LocalRoot, "Engine", "Content", "Internationalization", InternationalizationPreset), "*", true, null, CombinePaths("Engine", "Content", "Internationalization"), true, !Params.UsePak(SC.StageTargetPlatform)); - - // Engine ufs (content) - SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.LocalRoot, "Engine/Config"), "*", true, null, null, false, !Params.UsePak(SC.StageTargetPlatform)); // TODO: Exclude localization data generation config files. - - if (Params.bUsesSlate) - { - if (Params.bUsesSlateEditorStyle) - { - SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.LocalRoot, "Engine/Content/Editor/Slate"), "*", true, null, null, false, !Params.UsePak(SC.StageTargetPlatform)); - } - SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.LocalRoot, "Engine/Content/Slate"), "*", true, null, null, false, !Params.UsePak(SC.StageTargetPlatform)); - SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.ProjectRoot, "Content/Slate"), "*", true, new string[] { "*.uasset" }, CombinePaths(SC.RelativeProjectRootForStage, "Content/Slate"), true, !Params.UsePak(SC.StageTargetPlatform)); - } - foreach (string Culture in CulturesToStage) - { - StageLocalizationDataForCulture(SC, Culture, CombinePaths(SC.LocalRoot, "Engine/Content/Localization/Engine"), null, !Params.UsePak(SC.StageTargetPlatform)); - } - - // Engine & Game Plugins. Push the Engine/Source working directory so UBT code has a correct RelativeEnginePath in ReadAvailablePlugins - ProjectDescriptor Project = ProjectDescriptor.FromFile(SC.RawProjectPath); - LogLog("Searching for plugins with CurrentWorkingDir: " + Directory.GetCurrentDirectory()); - LogLog("Searching for plugins in: " + SC.RawProjectPath); - List AvailablePlugins = Plugins.ReadAvailablePlugins(CombinePaths(SC.LocalRoot, "Engine"), SC.RawProjectPath); - foreach (PluginInfo Plugin in AvailablePlugins) - { - LogLog("Considering Plugin for Stage: " + Plugin.FileName); - if (UProjectInfo.IsPluginEnabledForProject(Plugin, Project, SC.StageTargetPlatform.PlatformType)) - { - LogLog("EnabledPlugin: " + Plugin.FileName); - SC.StageFiles(StagedFileType.UFS, Plugin.Directory, "*.uplugin", false, null, null, true, !Params.UsePak(SC.StageTargetPlatform), null, true, false); - } - } - - // Game ufs (content) - - SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.ProjectRoot), "*.uproject", false, null, CombinePaths(SC.RelativeProjectRootForStage), true, !Params.UsePak(SC.StageTargetPlatform)); - if (SC.StageTargetPlatform.PlatformType != UnrealTargetPlatform.HTML5 && SC.bUseWebsocketNetDriver) - { - var EngineIniPath = Path.Combine(SC.ProjectRoot, "Config", "DefaultEngine.ini"); - var IntermediateEngineIniDir = Path.Combine(GetIntermediateCommandlineDir(SC), SC.RelativeProjectRootForStage, "Config"); - Directory.CreateDirectory(IntermediateEngineIniDir); - var IntermediateEngineIniPath = Path.Combine(IntermediateEngineIniDir, "DefaultEngine.ini"); - List IniLines = new List(); - if (File.Exists(EngineIniPath)) - { - IniLines = File.ReadAllLines(EngineIniPath).ToList(); - } - IniLines.Add("[/Script/Engine.GameEngine]"); - IniLines.Add("!NetDriverDefinitions=ClearArray"); - IniLines.Add("+NetDriverDefinitions=(DefName=\"GameNetDriver\", DriverClassName=\"/Script/HTML5Networking.WebSocketNetDriver\", DriverClassNameFallback=\"/Script/HTML5Networking.WebSocketNetDriver\")"); - File.WriteAllLines(IntermediateEngineIniPath, IniLines); - SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.ProjectRoot, "Config"), "*", true, new string[] {"DefaultEngine.ini"}, CombinePaths(SC.RelativeProjectRootForStage, "Config"), true, !Params.UsePak(SC.StageTargetPlatform)); // TODO: Exclude localization data generation config files. - SC.StageFiles(StagedFileType.UFS, IntermediateEngineIniDir, "*.ini", true, null, CombinePaths(SC.RelativeProjectRootForStage, "Config"), true, !Params.UsePak(SC.StageTargetPlatform)); // TODO: Exclude localization data generation config files. - } - else - { - SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.ProjectRoot, "Config"), "*", true, null, CombinePaths(SC.RelativeProjectRootForStage, "Config"), true, !Params.UsePak(SC.StageTargetPlatform)); // TODO: Exclude localization data generation config files. - } - foreach (string Culture in CulturesToStage) - { - StageLocalizationDataForCulture(SC, Culture, CombinePaths(SC.ProjectRoot, "Content/Localization/Game"), CombinePaths(SC.RelativeProjectRootForStage, "Content/Localization/Game"), !Params.UsePak(SC.StageTargetPlatform)); - } - - // Stage any additional UFS and NonUFS paths specified in the project ini files; these dirs are relative to the game content directory - if (PlatformGameConfig != null) - { - List ExtraUFSDirs; - if (PlatformGameConfig.GetArray("/Script/UnrealEd.ProjectPackagingSettings", "DirectoriesToAlwaysStageAsUFS", out ExtraUFSDirs)) - { - // Each string has the format '(Path="TheDirToStage")' - foreach (var PathStr in ExtraUFSDirs) - { - var PathParts = PathStr.Split('"'); - if (PathParts.Length == 3) - { - var RelativePath = PathParts[1]; - SC.StageFiles(StagedFileType.UFS, CombinePaths(ProjectContentRoot, RelativePath), "*", true, null, CombinePaths(StageContentRoot, RelativePath), true, !Params.UsePak(SC.StageTargetPlatform)); - } - else if (PathParts.Length == 1) - { - var RelativePath = PathParts[0]; - SC.StageFiles(StagedFileType.UFS, CombinePaths(ProjectContentRoot, RelativePath), "*", true, null, CombinePaths(StageContentRoot, RelativePath), true, !Params.UsePak(SC.StageTargetPlatform)); - } - } - } - - List ExtraNonUFSDirs; - if (PlatformGameConfig.GetArray("/Script/UnrealEd.ProjectPackagingSettings", "DirectoriesToAlwaysStageAsNonUFS", out ExtraNonUFSDirs)) - { - // Each string has the format '(Path="TheDirToStage")' - foreach (var PathStr in ExtraNonUFSDirs) - { - var PathParts = PathStr.Split('"'); - if (PathParts.Length == 3) - { - var RelativePath = PathParts[1]; - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(ProjectContentRoot, RelativePath)); - } - else if (PathParts.Length == 1) - { - var RelativePath = PathParts[0]; - SC.StageFiles(StagedFileType.UFS, CombinePaths(ProjectContentRoot, RelativePath), "*", true, null, CombinePaths(StageContentRoot, RelativePath), true, !Params.UsePak(SC.StageTargetPlatform)); - } - } - } - } - - StagedFileType StagedFileTypeForMovies = StagedFileType.NonUFS; - if (Params.FileServer) - { - // UFS is required when using a file server - StagedFileTypeForMovies = StagedFileType.UFS; - } - - if (SC.StageTargetPlatform.StageMovies) - { - SC.StageFiles(StagedFileTypeForMovies, CombinePaths(SC.LocalRoot, "Engine/Content/Movies"), "*", true, new string[] { "*.uasset", "*.umap" }, CombinePaths(SC.RelativeProjectRootForStage, "Engine/Content/Movies"), true, !Params.UsePak(SC.StageTargetPlatform)); - SC.StageFiles(StagedFileTypeForMovies, CombinePaths(SC.ProjectRoot, "Content/Movies"), "*", true, new string[] { "*.uasset", "*.umap" }, CombinePaths(SC.RelativeProjectRootForStage, "Content/Movies"), true, !Params.UsePak(SC.StageTargetPlatform)); - } - - // eliminate the sand box - SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.ProjectRoot, "Saved", "Cooked", SC.CookPlatform), "*", true, new string[] { "*.json" }, "", true, !Params.UsePak(SC.StageTargetPlatform)); - - // CrashReportClient is a standalone slate app that does not look in the generated pak file, so it needs the Content/Slate and Shaders/StandaloneRenderer folders Non-UFS - // @todo Make CrashReportClient more portable so we don't have to do this - if (SC.bStageCrashReporter && UnrealBuildTool.UnrealBuildTool.PlatformSupportsCrashReporter(SC.StageTargetPlatform.PlatformType)) - { - //If the .dat file needs to be staged as NonUFS for non-Windows/Linux hosts we need to change the casing as we do with the build properties file above. - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.LocalRoot, "Engine/Content/Slate")); - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.LocalRoot, "Engine/Shaders/StandaloneRenderer")); - - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.LocalRoot, "Engine", "Content", "Internationalization", InternationalizationPreset), "*", true, null, CombinePaths("Engine", "Content", "Internationalization"), false, true); - - // Linux platform stages ICU in GetFilesToDeployOrStage(), accounting for the actual architecture - if (SC.StageTargetPlatform.PlatformType == UnrealTargetPlatform.Win64 || - SC.StageTargetPlatform.PlatformType == UnrealTargetPlatform.Win32 || - SC.StageTargetPlatform.PlatformType == UnrealTargetPlatform.Mac) - { - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.LocalRoot, "Engine/Binaries/ThirdParty/ICU")); - } - - // SSL libraries are only available for Win64 builds. - // @see FPerforceSourceControlProvider::LoadSSLLibraries - if (SC.StageTargetPlatform.PlatformType == UnrealTargetPlatform.Win64) - { - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.LocalRoot, "Engine/Binaries/ThirdParty/OpenSSL")); - } - } - } - else - { - if (PlatformGameConfig != null) - { - List ExtraNonUFSDirs; - if (PlatformGameConfig.GetArray("/Script/UnrealEd.ProjectPackagingSettings", "DirectoriesToAlwaysStageAsNonUFS", out ExtraNonUFSDirs)) - { - // Each string has the format '(Path="TheDirToStage")' - foreach (var PathStr in ExtraNonUFSDirs) - { - var PathParts = PathStr.Split('"'); - if (PathParts.Length == 3) - { - var RelativePath = PathParts[1]; - SC.StageFiles(StagedFileType.NonUFS, CombinePaths(ProjectContentRoot, RelativePath)); - } - else if (PathParts.Length == 1) - { - var RelativePath = PathParts[0]; - SC.StageFiles(StagedFileType.UFS, CombinePaths(ProjectContentRoot, RelativePath), "*", true, null, CombinePaths(StageContentRoot, RelativePath), true, !Params.UsePak(SC.StageTargetPlatform)); - } - } - } - } - } - } - - public static void DumpTargetManifest(Dictionary Mapping, string Filename, string StageDir, List CRCFiles) - { - // const string Iso8601DateTimeFormat = "yyyy-MM-ddTHH:mm:ssZ"; // probably should work - // const string Iso8601DateTimeFormat = "o"; // predefined universal Iso standard format (has too many millisecond spaces for our read code in FDateTime.ParseISO8601 - const string Iso8601DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffZ"; - - - if (Mapping.Count > 0) - { - var Lines = new List(); - foreach (var Pair in Mapping) - { - string TimeStamp = File.GetLastWriteTimeUtc(Pair.Key).ToString(Iso8601DateTimeFormat); - if (CRCFiles.Contains(Pair.Value)) - { - byte[] FileData = File.ReadAllBytes(StageDir + "/" + Pair.Value); - TimeStamp = BitConverter.ToString(System.Security.Cryptography.MD5.Create().ComputeHash(FileData)).Replace("-", string.Empty); - } - string Dest = Pair.Value + "\t" + TimeStamp; - - Lines.Add(Dest); - } - WriteAllLines(Filename, Lines.ToArray()); - } - } - - public static void CopyManifestFilesToStageDir(Dictionary Mapping, string StageDir, string ManifestName, List CRCFiles) - { - Log("Copying {0} to staging directory: {1}", ManifestName, StageDir); - string ManifestPath = ""; - string ManifestFile = ""; - if (!String.IsNullOrEmpty(ManifestName)) - { - ManifestFile = "Manifest_" + ManifestName + ".txt"; - ManifestPath = CombinePaths(StageDir, ManifestFile); - DeleteFile(ManifestPath); - } - foreach (var Pair in Mapping) - { - string Src = Pair.Key; - string Dest = CombinePaths(StageDir, Pair.Value); - if (Src != Dest) // special case for things created in the staging directory, like the pak file - { - CopyFileIncremental(Src, Dest, bFilterSpecialLinesFromIniFiles:true); - } - } - if (!String.IsNullOrEmpty(ManifestPath) && Mapping.Count > 0) - { - DumpTargetManifest(Mapping, ManifestPath, StageDir, CRCFiles); - if (!FileExists(ManifestPath)) - { - throw new AutomationException("Failed to write manifest {0}", ManifestPath); - } - CopyFile(ManifestPath, CombinePaths(CmdEnv.LogFolder, ManifestFile)); - } - } - - public static void DumpManifest(Dictionary Mapping, string Filename) - { - if (Mapping.Count > 0) - { - var Lines = new List(); - foreach (var Pair in Mapping) - { - string Src = Pair.Key; - string Dest = Pair.Value; - - Lines.Add("\"" + Src + "\" \"" + Dest + "\""); - } - WriteAllLines(Filename, Lines.ToArray()); - } - } - - public static void DumpManifest(DeploymentContext SC, string BaseFilename, bool DumpUFSFiles = true) - { - DumpManifest(SC.NonUFSStagingFiles, BaseFilename + "_NonUFSFiles.txt"); - if (DumpUFSFiles) - { - DumpManifest(SC.NonUFSStagingFilesDebug, BaseFilename + "_NonUFSFilesDebug.txt"); - } - DumpManifest(SC.UFSStagingFiles, BaseFilename + "_UFSFiles.txt"); - } - - public static void CopyUsingStagingManifest(ProjectParams Params, DeploymentContext SC) - { - CopyManifestFilesToStageDir(SC.NonUFSStagingFiles, SC.StageDirectory, "NonUFSFiles", SC.StageTargetPlatform.GetFilesForCRCCheck()); - - if (!Params.NoDebugInfo) - { - CopyManifestFilesToStageDir(SC.NonUFSStagingFilesDebug, SC.StageDirectory, "DebugFiles", SC.StageTargetPlatform.GetFilesForCRCCheck()); - } - - bool bStageUnrealFileSystemFiles = !Params.CookOnTheFly && !Params.UsePak(SC.StageTargetPlatform) && !Params.FileServer; - if (bStageUnrealFileSystemFiles) - { - CopyManifestFilesToStageDir(SC.UFSStagingFiles, SC.StageDirectory, "UFSFiles", SC.StageTargetPlatform.GetFilesForCRCCheck()); - } - } - - /// - /// Creates a pak file using staging context (single manifest) - /// - /// - /// - private static void CreatePakUsingStagingManifest(ProjectParams Params, DeploymentContext SC) - { - Log("Creating pak using staging manifest."); - - DumpManifest(SC, CombinePaths(CmdEnv.LogFolder, "PrePak" + (SC.DedicatedServer ? "_Server" : ""))); - - var UnrealPakResponseFile = CreatePakResponseFileFromStagingManifest(SC); - - CreatePak(Params, SC, UnrealPakResponseFile, SC.ShortProjectName); - } - - /// - /// Creates a pak response file using stage context - /// - /// - /// - private static Dictionary CreatePakResponseFileFromStagingManifest(DeploymentContext SC) - { - // look for optional packaging blacklist if only one config active - List Blacklist = null; - if (SC.StageTargetConfigurations.Count == 1) - { - var PakBlacklistFilename = CombinePaths(SC.ProjectRoot, "Build", SC.PlatformDir, string.Format("PakBlacklist-{0}.txt", SC.StageTargetConfigurations[0].ToString())); - if (File.Exists(PakBlacklistFilename)) - { - Log("Applying PAK blacklist file {0}", PakBlacklistFilename); - string[] BlacklistContents = File.ReadAllLines(PakBlacklistFilename); - foreach (string Candidate in BlacklistContents) - { - if (Candidate.Trim().Length > 0) - { - if (Blacklist == null) - { - Blacklist = new List(); - } - Blacklist.Add(Candidate); - } - } - } - } - - var UnrealPakResponseFile = new Dictionary(StringComparer.InvariantCultureIgnoreCase); - foreach (var Pair in SC.UFSStagingFiles) - { - string Src = Pair.Key; - string Dest = Pair.Value; - - Dest = CombinePaths(PathSeparator.Slash, SC.PakFileInternalRoot, Dest); - - if (Blacklist != null) - { - bool bExcludeFile = false; - foreach (string ExcludePath in Blacklist) - { - if (Dest.StartsWith(ExcludePath)) - { - bExcludeFile = true; - break; - } - } - - if (bExcludeFile) - { - Log("Excluding {0}", Src); - continue; - } - } - - // there can be files that only differ in case only, we don't support that in paks as paks are case-insensitive - if (UnrealPakResponseFile.ContainsKey(Src)) - { - throw new AutomationException("Staging manifest already contains {0} (or a file that differs in case only)", Src); - } - UnrealPakResponseFile.Add(Src, Dest); - } - - return UnrealPakResponseFile; - } - - - private static string GetReleasePakFilePath(DeploymentContext SC, ProjectParams Params, string ReleaseVersion, string PakName) - { - string ReleaseVersionPath = CombinePaths(SC.ProjectRoot, "Releases", ReleaseVersion, SC.StageTargetPlatform.GetCookPlatform(SC.DedicatedServer, false, Params.CookFlavor), PakName); - return ReleaseVersionPath; - } - - - /// - /// Creates a pak file using response file. - /// - /// - /// - /// - /// - private static void CreatePak(ProjectParams Params, DeploymentContext SC, Dictionary UnrealPakResponseFile, string PakName) - { - string PostFix = ""; - if (Params.IsGeneratingPatch) - { - PostFix += "_P"; - } - var OutputRelativeLocation = CombinePaths(SC.RelativeProjectRootForStage, "Content/Paks/", PakName + "-" + SC.FinalCookPlatform + PostFix + ".pak"); - if (SC.StageTargetPlatform.DeployLowerCaseFilenames(true)) - { - OutputRelativeLocation = OutputRelativeLocation.ToLowerInvariant(); - } - OutputRelativeLocation = SC.StageTargetPlatform.Remap(OutputRelativeLocation); - var OutputLocation = CombinePaths(SC.RuntimeRootDir, OutputRelativeLocation); - // Add input file to controll order of file within the pak - var PakOrderFileLocationBase = CombinePaths(SC.ProjectRoot, "Build", SC.FinalCookPlatform, "FileOpenOrder"); - - var OrderFileLocations = new string[] { "GameOpenOrder.log", "CookerOpenOrder.log", "EditorOpenOrder.log" }; - string PakOrderFileLocation = null; - foreach (var Location in OrderFileLocations) - { - PakOrderFileLocation = CombinePaths(PakOrderFileLocationBase, Location); - - if (FileExists_NoExceptions(PakOrderFileLocation)) - { - break; - } - } - - bool bCopiedExistingPak = false; - - if (SC.StageTargetPlatform != SC.CookSourcePlatform) - { - // Check to see if we have an existing pak file we can use - - var SourceOutputRelativeLocation = CombinePaths(SC.RelativeProjectRootForStage, "Content/Paks/", PakName + "-" + SC.CookPlatform + PostFix + ".pak"); - if (SC.CookSourcePlatform.DeployLowerCaseFilenames(true)) - { - SourceOutputRelativeLocation = SourceOutputRelativeLocation.ToLowerInvariant(); - } - SourceOutputRelativeLocation = SC.CookSourcePlatform.Remap(SourceOutputRelativeLocation); - var SourceOutputLocation = CombinePaths(SC.CookSourceRuntimeRootDir, SourceOutputRelativeLocation); - - if (FileExists_NoExceptions(SourceOutputLocation)) - { - InternalUtils.SafeCreateDirectory(Path.GetDirectoryName(OutputLocation), true); - - if (InternalUtils.SafeCopyFile(SourceOutputLocation, OutputLocation)) - { - Log("Copying source pak from {0} to {1} instead of creating new pak", SourceOutputLocation, OutputLocation); - bCopiedExistingPak = true; - } - } - if (!bCopiedExistingPak) - { - Log("Failed to copy source pak from {0} to {1}, creating new pak", SourceOutputLocation, OutputLocation); - } - } - - string PatchSourceContentPath = null; - if (Params.HasBasedOnReleaseVersion && Params.IsGeneratingPatch) - { - // don't include the post fix in this filename because we are looking for the source pak path - string PakFilename = PakName + "-" + SC.FinalCookPlatform + ".pak"; - PatchSourceContentPath = GetReleasePakFilePath(SC, Params, Params.BasedOnReleaseVersion, PakFilename); - - - /*PatchSourceContentPath = Params.BasedOnReleaseVersion; - if (PatchSourceContentPath.EndsWith(PakName) == false) - { - string Temp = Path.GetDirectoryName(PatchSourceContentPath) + PakName; - if ( File.Exists(Temp)) - { - PatchSourceContentPath = Temp; - } - }* - } - - if (!bCopiedExistingPak) - { - RunUnrealPak(UnrealPakResponseFile, OutputLocation, Params.SignPak, PakOrderFileLocation, SC.StageTargetPlatform.GetPlatformPakCommandLine(), Params.Compressed, PatchSourceContentPath ); - } - - - if (Params.HasCreateReleaseVersion) - { - // copy the created pak to the release version directory we might need this later if we want to generate patches - //string ReleaseVersionPath = CombinePaths( SC.ProjectRoot, "Releases", Params.CreateReleaseVersion, SC.StageTargetPlatform.GetCookPlatform(Params.DedicatedServer, false, Params.CookFlavor), Path.GetFileName(OutputLocation) ); - string ReleaseVersionPath = GetReleasePakFilePath(SC, Params, Params.CreateReleaseVersion, Path.GetFileName(OutputLocation)); - - InternalUtils.SafeCreateDirectory(Path.GetDirectoryName(ReleaseVersionPath)); - InternalUtils.SafeCopyFile(OutputLocation, ReleaseVersionPath); - } - - if (Params.CreateChunkInstall) - { - var RegEx = new Regex("pakchunk(\\d+)", RegexOptions.IgnoreCase | RegexOptions.Compiled); - var Matches = RegEx.Matches(PakName); - - if (Matches.Count == 0 || Matches[0].Groups.Count < 2) - { - throw new AutomationException(String.Format("Failed Creating Chunk Install Data, Unable to parse chunk id from {0}", PakName)); - } - - int ChunkID = Convert.ToInt32(Matches[0].Groups[1].ToString()); - if (ChunkID != 0) - { - var BPTExe = GetBuildPatchToolExecutable(); - EnsureBuildPatchToolExists(); - - string VersionString = Params.ChunkInstallVersionString; - string ChunkInstallBasePath = CombinePaths(Params.ChunkInstallDirectory, SC.FinalCookPlatform); - string RawDataPath = CombinePaths(ChunkInstallBasePath, VersionString, PakName); - string RawDataPakPath = CombinePaths(RawDataPath, PakName + "-" + SC.FinalCookPlatform + PostFix + ".pak"); - //copy the pak chunk to the raw data folder - if (InternalUtils.SafeFileExists(RawDataPakPath, true)) - { - InternalUtils.SafeDeleteFile(RawDataPakPath, true); - } - InternalUtils.SafeCreateDirectory(RawDataPath, true); - InternalUtils.SafeCopyFile(OutputLocation, RawDataPakPath); - if (ChunkID != 0) - { - InternalUtils.SafeDeleteFile(OutputLocation, true); - } - if (Params.IsGeneratingPatch) - { - if (String.IsNullOrEmpty(PatchSourceContentPath)) - { - throw new AutomationException(String.Format("Failed Creating Chunk Install Data. No source pak for patch pak {0} given", OutputLocation)); - } - // If we are generating a patch, then we need to copy the original pak across - // for distribution. - string SourceRawDataPakPath = CombinePaths(RawDataPath, PakName + "-" + SC.FinalCookPlatform + ".pak"); - InternalUtils.SafeCopyFile(PatchSourceContentPath, SourceRawDataPakPath); - } - - string BuildRoot = MakePathSafeToUseWithCommandLine(RawDataPath); - string CloudDir = MakePathSafeToUseWithCommandLine(CombinePaths(ChunkInstallBasePath, "CloudDir")); - string ManifestDir = CombinePaths(ChunkInstallBasePath, "ManifestDir"); - var AppID = 1; // For a chunk install this value doesn't seem to matter - string AppName = String.Format("{0}_{1}", SC.ShortProjectName, PakName); - string AppLaunch = ""; // For a chunk install this value doesn't seem to matter - string ManifestFilename = AppName + VersionString + ".manifest"; - string SourceManifestPath = CombinePaths(CloudDir, ManifestFilename); - string BackupManifestPath = CombinePaths(RawDataPath, ManifestFilename); - string DestManifestPath = CombinePaths(ManifestDir, ManifestFilename); - InternalUtils.SafeCreateDirectory(ManifestDir, true); - - string CmdLine = String.Format("-BuildRoot=\"{0}\" -CloudDir=\"{1}\" -AppID={2} -AppName=\"{3}\" -BuildVersion=\"{4}\" -AppLaunch=\"{5}\" -DataAgeThreshold=12", BuildRoot, CloudDir, AppID, AppName, VersionString, AppLaunch); - CmdLine += " -AppArgs=\"\""; - CmdLine += " -custom=\"bIsPatch=false\""; - CmdLine += String.Format(" -customint=\"ChunkID={0}\"", ChunkID); - CmdLine += " -customint=\"PakReadOrdering=0\""; - CmdLine += " -stdout"; - - RunAndLog(CmdEnv, BPTExe, CmdLine, Options: ERunOptions.Default | ERunOptions.UTF8Output); - - InternalUtils.SafeCopyFile(SourceManifestPath, BackupManifestPath); - InternalUtils.SafeCopyFile(SourceManifestPath, DestManifestPath); - } - else - { - // add the first pak file as needing deployment and convert to lower case again if needed - SC.UFSStagingFiles.Add(OutputLocation, OutputRelativeLocation); - } - } - else - { - // add the pak file as needing deployment and convert to lower case again if needed - SC.UFSStagingFiles.Add(OutputLocation, OutputRelativeLocation); - } - } - - /// - /// Creates pak files using streaming install chunk manifests. - /// - /// - /// - private static void CreatePaksUsingChunkManifests(ProjectParams Params, DeploymentContext SC) - { - Log("Creating pak using streaming install manifests."); - DumpManifest(SC, CombinePaths(CmdEnv.LogFolder, "PrePak" + (SC.DedicatedServer ? "_Server" : ""))); - - var TmpPackagingPath = GetTmpPackagingPath(Params, SC); - var ChunkListFilename = GetChunkPakManifestListFilename(Params, SC); - var ChunkList = ReadAllLines(ChunkListFilename); - var ChunkResponseFiles = new HashSet[ChunkList.Length]; - for (int Index = 0; Index < ChunkList.Length; ++Index) - { - var ChunkManifestFilename = CombinePaths(TmpPackagingPath, ChunkList[Index]); - ChunkResponseFiles[Index] = ReadPakChunkManifest(ChunkManifestFilename); - } - // We still want to have a list of all files to stage. We will use the chunk manifests - // to put the files from staging manigest into the right chunk - var StagingManifestResponseFile = CreatePakResponseFileFromStagingManifest(SC); - // DefaultChunkIndex assumes 0 is the 'base' chunk - const int DefaultChunkIndex = 0; - var PakResponseFiles = new Dictionary[ChunkList.Length]; - for (int Index = 0; Index < PakResponseFiles.Length; ++Index) - { - PakResponseFiles[Index] = new Dictionary(StringComparer.InvariantCultureIgnoreCase); - } - foreach (var StagingFile in StagingManifestResponseFile) - { - bool bAddedToChunk = false; - for (int ChunkIndex = 0; !bAddedToChunk && ChunkIndex < ChunkResponseFiles.Length; ++ChunkIndex) - { - string OriginalFilename = StagingFile.Key; - string NoExtension = CombinePaths(Path.GetDirectoryName(OriginalFilename), Path.GetFileNameWithoutExtension(OriginalFilename)); - string OriginalReplaceSlashes = OriginalFilename.Replace('/', '\\'); - string NoExtensionReplaceSlashes = NoExtension.Replace('/', '\\'); - - if (ChunkResponseFiles[ChunkIndex].Contains(OriginalFilename) || - ChunkResponseFiles[ChunkIndex].Contains(OriginalReplaceSlashes) || - ChunkResponseFiles[ChunkIndex].Contains(NoExtension) || - ChunkResponseFiles[ChunkIndex].Contains(NoExtensionReplaceSlashes)) - { - PakResponseFiles[ChunkIndex].Add(StagingFile.Key, StagingFile.Value); - bAddedToChunk = true; - } - } - if (!bAddedToChunk) - { - PakResponseFiles[DefaultChunkIndex].Add(StagingFile.Key, StagingFile.Value); - } - } - - if (Params.CreateChunkInstall) - { - string ManifestDir = CombinePaths(Params.ChunkInstallDirectory, SC.FinalCookPlatform, "ManifestDir"); - if (InternalUtils.SafeDirectoryExists(ManifestDir)) - { - foreach (string ManifestFile in Directory.GetFiles(ManifestDir, "*.manifest")) - { - InternalUtils.SafeDeleteFile(ManifestFile, true); - } - } - string DestDir = CombinePaths(Params.ChunkInstallDirectory, SC.FinalCookPlatform, Params.ChunkInstallVersionString); - if (InternalUtils.SafeDirectoryExists(DestDir)) - { - InternalUtils.SafeDeleteDirectory(DestDir); - } - } - - for (int ChunkIndex = 0; ChunkIndex < PakResponseFiles.Length; ++ChunkIndex) - { - var ChunkName = Path.GetFileNameWithoutExtension(ChunkList[ChunkIndex]); - CreatePak(Params, SC, PakResponseFiles[ChunkIndex], ChunkName); - } - - String ChunkLayerFilename = CombinePaths(GetTmpPackagingPath(Params, SC), GetChunkPakLayerListName()); - String OutputChunkLayerFilename = Path.Combine(SC.ProjectRoot, "Build", SC.FinalCookPlatform, "ChunkLayerInfo", GetChunkPakLayerListName()); - Directory.CreateDirectory(Path.GetDirectoryName(OutputChunkLayerFilename)); - File.Copy(ChunkLayerFilename, OutputChunkLayerFilename, true); - } - - private static bool DoesChunkPakManifestExist(ProjectParams Params, DeploymentContext SC) - { - return FileExists_NoExceptions(GetChunkPakManifestListFilename(Params, SC)); - } - - private static string GetChunkPakManifestListFilename(ProjectParams Params, DeploymentContext SC) - { - return CombinePaths(GetTmpPackagingPath(Params, SC), "pakchunklist.txt"); - } - - private static string GetChunkPakLayerListName() - { - return "pakchunklayers.txt"; - } - - private static string GetTmpPackagingPath(ProjectParams Params, DeploymentContext SC) - { - return CombinePaths(Path.GetDirectoryName(Params.RawProjectPath), "Saved", "TmpPackaging", SC.StageTargetPlatform.GetCookPlatform(SC.DedicatedServer, false, Params.CookFlavor)); - } - - private static bool ShouldCreatePak(ProjectParams Params, DeploymentContext SC) - { - Platform.PakType Pak = SC.StageTargetPlatform.RequiresPak(Params); - - // we may care but we don't want. - if (Params.SkipPak) - return false; - - if (Pak == Platform.PakType.Always) - { - return true; - } - else if (Pak == Platform.PakType.Never) - { - return false; - } - else // DontCare - { - return (Params.Pak); - } - } - - private static bool ShouldCreatePak(ProjectParams Params) - { - Platform.PakType Pak = Params.ClientTargetPlatformInstances[0].RequiresPak(Params); - - // we may care but we don't want. - if (Params.SkipPak) - return false; - - if (Pak == Platform.PakType.Always) - { - return true; - } - else if (Pak == Platform.PakType.Never) - { - return false; - } - else // DontCare - { - return (Params.Pak); - } - } - - protected static void DeletePakFiles(string StagingDirectory) - { - var StagedFilesDir = new DirectoryInfo(StagingDirectory); - StagedFilesDir.GetFiles("*.pak", SearchOption.AllDirectories).ToList().ForEach(File => File.Delete()); - } - - public static void ApplyStagingManifest(ProjectParams Params, DeploymentContext SC) - { - MaybeConvertToLowerCase(Params, SC); - Log("Cleaning Stage Directory: {0}", SC.StageDirectory); - if (SC.Stage && !Params.NoCleanStage && !Params.SkipStage && !Params.IterativeDeploy) - { - try - { - DeleteDirectory(SC.StageDirectory); - } - catch (Exception Ex) - { - // Delete cooked data (if any) as it may be incomplete / corrupted. - throw new AutomationException(ExitCode.Error_FailedToDeleteStagingDirectory, Ex, "Stage Failed. Failed to delete staging directory " + SC.StageDirectory); - } - } - else - { - try - { - // delete old pak files - DeletePakFiles(SC.StageDirectory); - } - catch (Exception Ex) - { - // Delete cooked data (if any) as it may be incomplete / corrupted. - throw new AutomationException(ExitCode.Error_FailedToDeleteStagingDirectory, Ex, "Stage Failed. Failed to delete pak files in " + SC.StageDirectory); - } - } - if (ShouldCreatePak(Params, SC)) - { - if (Params.Manifests && DoesChunkPakManifestExist(Params, SC)) - { - CreatePaksUsingChunkManifests(Params, SC); - } - else - { - CreatePakUsingStagingManifest(Params, SC); - } - } - if (!SC.Stage || Params.SkipStage) - { - return; - } - DumpManifest(SC, CombinePaths(CmdEnv.LogFolder, "FinalCopy" + (SC.DedicatedServer ? "_Server" : "")), !Params.UsePak(SC.StageTargetPlatform)); - CopyUsingStagingManifest(Params, SC); - - var ThisPlatform = SC.StageTargetPlatform; - ThisPlatform.PostStagingFileCopy(Params, SC); - } - - private static string GetIntermediateCommandlineDir(DeploymentContext SC) - { - return CombinePaths(SC.ProjectRoot, "Intermediate/UAT", SC.FinalCookPlatform); - } - - public static void WriteStageCommandline(string IntermediateCmdLineFile, ProjectParams Params, DeploymentContext SC) - { - // this file needs to be treated as a UFS file for casing, but NonUFS for being put into the .pak file. - // @todo: Maybe there should be a new category - UFSNotForPak - if (SC.StageTargetPlatform.DeployLowerCaseFilenames(true)) - { - IntermediateCmdLineFile = IntermediateCmdLineFile.ToLowerInvariant(); - } - if (File.Exists(IntermediateCmdLineFile)) - { - File.Delete(IntermediateCmdLineFile); - } - - if(!SC.StageTargetPlatform.ShouldStageCommandLine(Params, SC)) - { - return; - } - - Log("Creating UE4CommandLine.txt"); - if (!string.IsNullOrEmpty(Params.StageCommandline) || !string.IsNullOrEmpty(Params.RunCommandline)) - { - string FileHostParams = " "; - if (Params.CookOnTheFly || Params.FileServer) - { - FileHostParams += "-filehostip="; - bool FirstParam = true; - if (UnrealBuildTool.BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac) - { - NetworkInterface[] Interfaces = NetworkInterface.GetAllNetworkInterfaces(); - foreach (NetworkInterface adapter in Interfaces) - { - if (adapter.NetworkInterfaceType != NetworkInterfaceType.Loopback) - { - IPInterfaceProperties IP = adapter.GetIPProperties(); - for (int Index = 0; Index < IP.UnicastAddresses.Count; ++Index) - { - if (IP.UnicastAddresses[Index].IsDnsEligible && IP.UnicastAddresses[Index].Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) - { - if (!IsNullOrEmpty(Params.Port)) - { - foreach (var Port in Params.Port) - { - if (!FirstParam) - { - FileHostParams += "+"; - } - FirstParam = false; - string[] PortProtocol = Port.Split(new char[] { ':' }); - if (PortProtocol.Length > 1) - { - FileHostParams += String.Format("{0}://{1}:{2}", PortProtocol[0], IP.UnicastAddresses[Index].Address.ToString(), PortProtocol[1]); - } - else - { - FileHostParams += IP.UnicastAddresses[Index].Address.ToString(); - FileHostParams += ":"; - FileHostParams += Params.Port; - } - - } - } - else - { - if (!FirstParam) - { - FileHostParams += "+"; - } - FirstParam = false; - - // use default port - FileHostParams += IP.UnicastAddresses[Index].Address.ToString(); - } - - } - } - } - } - } - else - { - NetworkInterface[] Interfaces = NetworkInterface.GetAllNetworkInterfaces(); - foreach (NetworkInterface adapter in Interfaces) - { - if (adapter.OperationalStatus == OperationalStatus.Up) - { - IPInterfaceProperties IP = adapter.GetIPProperties(); - for (int Index = 0; Index < IP.UnicastAddresses.Count; ++Index) - { - if (IP.UnicastAddresses[Index].IsDnsEligible) - { - if (!IsNullOrEmpty(Params.Port)) - { - foreach (var Port in Params.Port) - { - if (!FirstParam) - { - FileHostParams += "+"; - } - FirstParam = false; - string[] PortProtocol = Port.Split(new char[] { ':' }); - if (PortProtocol.Length > 1) - { - FileHostParams += String.Format("{0}://{1}:{2}", PortProtocol[0], IP.UnicastAddresses[Index].Address.ToString(), PortProtocol[1]); - } - else - { - FileHostParams += IP.UnicastAddresses[Index].Address.ToString(); - FileHostParams += ":"; - FileHostParams += Params.Port; - } - } - } - else - { - if (!FirstParam) - { - FileHostParams += "+"; - } - FirstParam = false; - - // use default port - FileHostParams += IP.UnicastAddresses[Index].Address.ToString(); - } - - } - } - } - } - } - const string LocalHost = "127.0.0.1"; - if (!IsNullOrEmpty(Params.Port)) - { - foreach (var Port in Params.Port) - { - if (!FirstParam) - { - FileHostParams += "+"; - } - FirstParam = false; - string[] PortProtocol = Port.Split(new char[] { ':' }); - if (PortProtocol.Length > 1) - { - FileHostParams += String.Format("{0}://{1}:{2}", PortProtocol[0], LocalHost, PortProtocol[1]); - } - else - { - FileHostParams += LocalHost; - FileHostParams += ":"; - FileHostParams += Params.Port; - } - - } - } - else - { - if (!FirstParam) - { - FileHostParams += "+"; - } - FirstParam = false; - - // use default port - FileHostParams += LocalHost; - } - FileHostParams += " "; - } - - String ProjectFile = String.Format("{0} ", SC.ProjectArgForCommandLines); - if (SC.StageTargetPlatform.PlatformType == UnrealTargetPlatform.Mac || SC.StageTargetPlatform.PlatformType == UnrealTargetPlatform.Win64 || SC.StageTargetPlatform.PlatformType == UnrealTargetPlatform.Win32 || SC.StageTargetPlatform.PlatformType == UnrealTargetPlatform.Linux) - { - ProjectFile = ""; - } - Directory.CreateDirectory(GetIntermediateCommandlineDir(SC)); - string CommandLine = String.Format("{0} {1} {2} {3}\n", ProjectFile, Params.StageCommandline.Trim(new char[] { '\"' }), Params.RunCommandline.Trim(new char[] { '\"' }), FileHostParams).Trim(); - if (Params.IterativeDeploy) - { - CommandLine += " -iterative"; - } - File.WriteAllText(IntermediateCmdLineFile, CommandLine); - } - else if (!Params.IsCodeBasedProject) - { - String ProjectFile = String.Format("{0} ", SC.ProjectArgForCommandLines); - if (SC.StageTargetPlatform.PlatformType == UnrealTargetPlatform.Mac || SC.StageTargetPlatform.PlatformType == UnrealTargetPlatform.Win64 || SC.StageTargetPlatform.PlatformType == UnrealTargetPlatform.Win32 || SC.StageTargetPlatform.PlatformType == UnrealTargetPlatform.Linux) - { - ProjectFile = ""; - } - Directory.CreateDirectory(GetIntermediateCommandlineDir(SC)); - File.WriteAllText(IntermediateCmdLineFile, ProjectFile); - } - } - - private static void WriteStageCommandline(ProjectParams Params, DeploymentContext SC) - { - // always delete the existing commandline text file, so it doesn't reuse an old one - string IntermediateCmdLineFile = CombinePaths(GetIntermediateCommandlineDir(SC), "UE4CommandLine.txt"); - WriteStageCommandline(IntermediateCmdLineFile, Params, SC); - } - - private static Dictionary ReadDeployedManifest(ProjectParams Params, DeploymentContext SC, List ManifestList) - { - Dictionary DeployedFiles = new Dictionary(); - List CRCFiles = SC.StageTargetPlatform.GetFilesForCRCCheck(); - - // read the manifest - bool bContinueSearch = true; - foreach (string Manifest in ManifestList) - { - int FilesAdded = 0; - if (bContinueSearch) - { - string Data = File.ReadAllText (Manifest); - string[] Lines = Data.Split ('\n'); - foreach (string Line in Lines) - { - string[] Pair = Line.Split ('\t'); - if (Pair.Length > 1) - { - string Filename = Pair [0]; - string TimeStamp = Pair [1]; - FilesAdded++; - if (DeployedFiles.ContainsKey (Filename)) - { - if ((CRCFiles.Contains (Filename) && DeployedFiles [Filename] != TimeStamp) || (!CRCFiles.Contains (Filename) && DateTime.Parse (DeployedFiles [Filename]) > DateTime.Parse (TimeStamp))) - { - DeployedFiles [Filename] = TimeStamp; - } - } - else - { - DeployedFiles.Add (Filename, TimeStamp); - } - } - } - } - File.Delete(Manifest); - - if (FilesAdded == 0 && bContinueSearch) - { - // no files have been deployed at all to this guy, so remove all previously added files and exit the loop as this means we need to deploy everything - DeployedFiles.Clear (); - bContinueSearch = false; - } - } - - return DeployedFiles; - } - - protected static Dictionary ReadStagedManifest(ProjectParams Params, DeploymentContext SC, string Manifest) - { - Dictionary StagedFiles = new Dictionary(); - List CRCFiles = SC.StageTargetPlatform.GetFilesForCRCCheck(); - - // get the staged manifest from staged directory - string ManifestFile = SC.StageDirectory + "/" + Manifest; - if (File.Exists(ManifestFile)) - { - string Data = File.ReadAllText(ManifestFile); - string[] Lines = Data.Split('\n'); - foreach (string Line in Lines) - { - string[] Pair = Line.Split('\t'); - if (Pair.Length > 1) - { - string Filename = Pair[0]; - string TimeStamp = Pair[1]; - if (!StagedFiles.ContainsKey(Filename)) - { - StagedFiles.Add(Filename, TimeStamp); - } - else if ((CRCFiles.Contains(Filename) && StagedFiles[Filename] != TimeStamp) || (!CRCFiles.Contains(Filename) && DateTime.Parse(StagedFiles[Filename]) > DateTime.Parse(TimeStamp))) - { - StagedFiles[Filename] = TimeStamp; - } - } - } - } - return StagedFiles; - } - - protected static void WriteObsoleteManifest(ProjectParams Params, DeploymentContext SC, Dictionary DeployedFiles, Dictionary StagedFiles, string ObsoleteManifest) - { - List ObsoleteFiles = new List(); - - // any file that has been deployed, but is no longer in the staged files is obsolete and should be deleted. - foreach (KeyValuePair File in DeployedFiles) - { - if (!StagedFiles.ContainsKey(File.Key)) - { - ObsoleteFiles.Add(File.Key); - } - } - - // write out to the deltamanifest.json - string ManifestFile = CombinePaths(SC.StageDirectory, ObsoleteManifest); - StreamWriter Writer = System.IO.File.CreateText(ManifestFile); - foreach (string Line in ObsoleteFiles) - { - Writer.WriteLine(Line); - } - Writer.Close(); - } - - protected static void WriteDeltaManifest(ProjectParams Params, DeploymentContext SC, Dictionary DeployedFiles, Dictionary StagedFiles, string DeltaManifest) - { - List CRCFiles = SC.StageTargetPlatform.GetFilesForCRCCheck(); - List DeltaFiles = new List(); - foreach (KeyValuePair File in StagedFiles) - { - bool bNeedsDeploy = true; - if (DeployedFiles.ContainsKey(File.Key)) - { - if (CRCFiles.Contains(File.Key)) - { - bNeedsDeploy = (File.Value != DeployedFiles[File.Key]); - } - else - { - DateTime Staged = DateTime.Parse(File.Value); - DateTime Deployed = DateTime.Parse(DeployedFiles[File.Key]); - bNeedsDeploy = (Staged > Deployed); - } - } - - if (bNeedsDeploy) - { - DeltaFiles.Add(File.Key); - } - } - - // add the manifest - if (!DeltaManifest.Contains("NonUFS")) - { - DeltaFiles.Add(DeploymentContext.NonUFSDeployedManifestFileName); - DeltaFiles.Add(DeploymentContext.UFSDeployedManifestFileName); - } - - // TODO: determine files which need to be removed - - // write out to the deltamanifest.json - string ManifestFile = CombinePaths(SC.StageDirectory, DeltaManifest); - StreamWriter Writer = System.IO.File.CreateText(ManifestFile); - foreach (string Line in DeltaFiles) - { - Writer.WriteLine(Line); - } - Writer.Close(); - } - - #endregion - - #region Stage Command - - //@todo move this - public static List CreateDeploymentContext(ProjectParams Params, bool InDedicatedServer, bool DoCleanStage = false) - { - ParamList ListToProcess = InDedicatedServer && (Params.Cook || Params.CookOnTheFly) ? Params.ServerCookedTargets : Params.ClientCookedTargets; - var ConfigsToProcess = InDedicatedServer && (Params.Cook || Params.CookOnTheFly) ? Params.ServerConfigsToBuild : Params.ClientConfigsToBuild; - var CreateWebSocketsServer = Params.ServerTargetPlatforms.Count() > 0 && Params.ClientTargetPlatforms.Contains(UnrealTargetPlatform.HTML5); - - List PlatformsToStage = Params.ClientTargetPlatforms; - if (InDedicatedServer && (Params.Cook || Params.CookOnTheFly)) - { - PlatformsToStage = Params.ServerTargetPlatforms; - } - - bool prefixArchiveDir = false; - if (PlatformsToStage.Contains(UnrealTargetPlatform.Win32) && PlatformsToStage.Contains(UnrealTargetPlatform.Win64)) - { - prefixArchiveDir = true; - } - - List DeploymentContexts = new List(); - foreach (var StagePlatform in PlatformsToStage) - { - // Get the platform to get cooked data from, may differ from the stage platform - UnrealTargetPlatform CookedDataPlatform = Params.GetCookedDataPlatformForClientTarget(StagePlatform); - - if (InDedicatedServer && (Params.Cook || Params.CookOnTheFly)) - { - CookedDataPlatform = Params.GetCookedDataPlatformForServerTarget(StagePlatform); - } - - List ExecutablesToStage = new List(); - - string PlatformName = StagePlatform.ToString(); - string StageArchitecture = !String.IsNullOrEmpty(Params.SpecifiedArchitecture) ? Params.SpecifiedArchitecture : ""; - foreach (var Target in ListToProcess) - { - foreach (var Config in ConfigsToProcess) - { - string Exe = Target; - if (Config != UnrealTargetConfiguration.Development) - { - Exe = Target + "-" + PlatformName + "-" + Config.ToString() + StageArchitecture; - } - ExecutablesToStage.Add(Exe); - } - } - - string StageDirectory = ((ShouldCreatePak(Params) || (Params.Stage)) || !String.IsNullOrEmpty(Params.StageDirectoryParam)) ? Params.BaseStageDirectory : ""; - string ArchiveDirectory = (Params.Archive || !String.IsNullOrEmpty(Params.ArchiveDirectoryParam)) ? Params.BaseArchiveDirectory : ""; - if (prefixArchiveDir && (StagePlatform == UnrealTargetPlatform.Win32 || StagePlatform == UnrealTargetPlatform.Win64)) - { - if (Params.Stage) - { - StageDirectory = CombinePaths(Params.BaseStageDirectory, StagePlatform.ToString()); - } - if (Params.Archive) - { - ArchiveDirectory = CombinePaths(Params.BaseArchiveDirectory, StagePlatform.ToString()); - } - } - - string EngineDir = CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Engine"); - - List TargetsToStage = new List(); - foreach(string Target in ListToProcess) - { - foreach(UnrealTargetConfiguration Config in ConfigsToProcess) - { - string ReceiptBaseDir = Params.IsCodeBasedProject? Path.GetDirectoryName(Params.RawProjectPath) : EngineDir; - - Platform PlatformInstance = Platform.Platforms[StagePlatform]; - UnrealTargetPlatform[] SubPlatformsToStage = PlatformInstance.GetStagePlatforms(); - - // if we are attempting to gathering multiple platforms, the files aren't required - bool bRequireStagedFilesToExist = SubPlatformsToStage.Length == 1 && PlatformsToStage.Count == 1; - - foreach (UnrealTargetPlatform ReceiptPlatform in SubPlatformsToStage) - { - string Architecture = Params.SpecifiedArchitecture; - if (Architecture == null) - { - Architecture = ""; - var BuildPlatform = UEBuildPlatform.GetBuildPlatform(ReceiptPlatform, true); - if (BuildPlatform != null) - { - Architecture = BuildPlatform.GetActiveArchitecture(); - } - } - string ReceiptFileName = TargetReceipt.GetDefaultPath(ReceiptBaseDir, Target, ReceiptPlatform, Config, Architecture); - if(!File.Exists(ReceiptFileName)) - { - if (bRequireStagedFilesToExist) - { - // if we aren't collecting multiple platforms, then it is expected to exist - throw new AutomationException(ExitCode.Error_MissingExecutable, "Stage Failed. Missing receipt '{0}'. Check that this target has been built.", Path.GetFileName(ReceiptFileName)); - } - else - { - // if it's multiple platforms, then allow missing receipts - continue; - } - - } - - // Read the receipt for this target - TargetReceipt Receipt; - if(!TargetReceipt.TryRead(ReceiptFileName, out Receipt)) - { - throw new AutomationException("Missing or invalid target receipt ({0})", ReceiptFileName); - } - - // Convert the paths to absolute - Receipt.ExpandPathVariables(EngineDir, Path.GetDirectoryName(Params.RawProjectPath)); - TargetsToStage.Add(new StageTarget{ Receipt = Receipt, RequireFilesExist = bRequireStagedFilesToExist }); - } - } - } - - //@todo should pull StageExecutables from somewhere else if not cooked - var SC = new DeploymentContext(Params.RawProjectPath, CmdEnv.LocalRoot, - StageDirectory, - ArchiveDirectory, - Params.CookFlavor, - Params.GetTargetPlatformInstance(CookedDataPlatform), - Params.GetTargetPlatformInstance(StagePlatform), - ConfigsToProcess, - TargetsToStage, - ExecutablesToStage, - InDedicatedServer, - Params.Cook || Params.CookOnTheFly, - Params.CrashReporter && !(StagePlatform == UnrealTargetPlatform.Linux && Params.Rocket), // can't include the crash reporter from binary Linux builds - Params.Stage, - Params.CookOnTheFly, - Params.Archive, - Params.IsProgramTarget, - Params.HasDedicatedServerAndClient, - bInUseWebsocketNetDriver: CreateWebSocketsServer - ); - LogDeploymentContext(SC); - - // If we're a derived platform make sure we're at the end, otherwise make sure we're at the front - - if (CookedDataPlatform != StagePlatform) - { - DeploymentContexts.Add(SC); - } - else - { - DeploymentContexts.Insert(0, SC); - } - } - - return DeploymentContexts; - } - - public static void CopyBuildToStagingDirectory(ProjectParams Params) - { - if (ShouldCreatePak(Params) || (Params.Stage && !Params.SkipStage)) - { - Params.ValidateAndLog(); - - Log("********** STAGE COMMAND STARTED **********"); - - if (!Params.NoClient) - { - var DeployContextList = CreateDeploymentContext(Params, false, true); - foreach (var SC in DeployContextList) - { - // write out the commandline file now so it can go into the manifest - WriteStageCommandline(Params, SC); - CreateStagingManifest(Params, SC); - ApplyStagingManifest(Params, SC); - - if (Params.Deploy) - { - // get the deployed file data - Dictionary DeployedUFSFiles = new Dictionary(); - Dictionary DeployedNonUFSFiles = new Dictionary(); - List UFSManifests; - List NonUFSManifests; - if (SC.StageTargetPlatform.RetrieveDeployedManifests(Params, SC, out UFSManifests, out NonUFSManifests)) - { - DeployedUFSFiles = ReadDeployedManifest(Params, SC, UFSManifests); - DeployedNonUFSFiles = ReadDeployedManifest(Params, SC, NonUFSManifests); - } - - // get the staged file data - Dictionary StagedUFSFiles = ReadStagedManifest(Params, SC, DeploymentContext.UFSDeployedManifestFileName); - Dictionary StagedNonUFSFiles = ReadStagedManifest(Params, SC, DeploymentContext.NonUFSDeployedManifestFileName); - - WriteObsoleteManifest(Params, SC, DeployedUFSFiles, StagedUFSFiles, DeploymentContext.UFSDeployObsoleteFileName); - WriteObsoleteManifest(Params, SC, DeployedNonUFSFiles, StagedNonUFSFiles, DeploymentContext.NonUFSDeployObsoleteFileName); - - if (Params.IterativeDeploy) - { - - // write out the delta file data - WriteDeltaManifest(Params, SC, DeployedUFSFiles, StagedUFSFiles, DeploymentContext.UFSDeployDeltaFileName); - WriteDeltaManifest(Params, SC, DeployedNonUFSFiles, StagedNonUFSFiles, DeploymentContext.NonUFSDeployDeltaFileName); - } - } - - if (Params.bCodeSign) - { - SC.StageTargetPlatform.SignExecutables(SC, Params); - } - } - } - - if (Params.DedicatedServer) - { - var DeployContextList = CreateDeploymentContext(Params, true, true); - foreach (var SC in DeployContextList) - { - CreateStagingManifest(Params, SC); - ApplyStagingManifest(Params, SC); - } - } - Log("********** STAGE COMMAND COMPLETED **********"); - } - } - - #endregion - */ -} diff --git a/Engine/Source/Programs/AutomationTool/Scripts/SyncDDC.cs b/Engine/Source/Programs/AutomationTool/Scripts/SyncDDC.cs new file mode 100644 index 000000000000..4997b6de6aca --- /dev/null +++ b/Engine/Source/Programs/AutomationTool/Scripts/SyncDDC.cs @@ -0,0 +1,524 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; + +namespace AutomationTool +{ + [Help("Merge one or more remote DDC shares into a local share, taking files with the newest timestamps and keeping the size below a certain limit")] + [Help("LocalDir=", "The local DDC directory to add/remove files from")] + [Help("RemoteDir=", "The remote DDC directory to pull from. May be specified multiple times.")] + [Help("MaxSize=", "Maximum size of the local DDC directory. TB/MB/GB/KB units are allowed.")] + [Help("MaxDays=", "Only copies files with modified timestamps in the past number of days.")] + [Help("TimeLimit= + \ No newline at end of file diff --git a/Engine/Source/Programs/DotNETCommon/DotNETUtilities/FileContentsCacheType.cs b/Engine/Source/Programs/DotNETCommon/DotNETUtilities/FileContentsCacheType.cs deleted file mode 100644 index 36bc47b7677b..000000000000 --- a/Engine/Source/Programs/DotNETCommon/DotNETUtilities/FileContentsCacheType.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -using System.Collections.Generic; -using System.IO; - -namespace Tools.DotNETCommon.FileContentsCacheType -{ - public class FileContentsCacheType - { - public string GetContents(string Filename) - { - string Contents; - if (FilenameContentsMap.TryGetValue(Filename, out Contents)) - { - return Contents; - } - - using (var Reader = new StreamReader(Filename, System.Text.Encoding.UTF8)) - { - Contents = Reader.ReadToEnd(); - FilenameContentsMap.Add(Filename, Contents); - } - - return Contents; - } - - private Dictionary FilenameContentsMap = new Dictionary(); - } -} diff --git a/Engine/Source/Programs/DotNETCommon/DotNETUtilities/FileSystem.cs b/Engine/Source/Programs/DotNETCommon/DotNETUtilities/FileSystem.cs deleted file mode 100644 index 604a0dd00096..000000000000 --- a/Engine/Source/Programs/DotNETCommon/DotNETUtilities/FileSystem.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -using System; -using System.Runtime.InteropServices; -using System.Text; - -namespace Tools.DotNETCommon.FileSystem -{ - public static class FileSystem - { - [DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Unicode)] - private static extern int GetShortPathName(string pathName, StringBuilder shortName, int cbShortName); - - public static string GetShortPathName(string Path) - { - int BufferSize = GetShortPathName(Path, null, 0); - if (BufferSize == 0) - { - throw new Exception(string.Format("Unable to convert path {0} to 8.3 format", Path)); - } - - var Builder = new StringBuilder(BufferSize); - int ConversionResult = GetShortPathName(Path, Builder, BufferSize); - if (ConversionResult == 0) - { - throw new Exception(string.Format("Unable to convert path {0} to 8.3 format", Path)); - } - - return Builder.ToString(); - } - } -} diff --git a/Engine/Source/Programs/DotNETCommon/DotNETUtilities/ThreadSafeQueue.cs b/Engine/Source/Programs/DotNETCommon/DotNETUtilities/ThreadSafeQueue.cs deleted file mode 100644 index c5cdb2099898..000000000000 --- a/Engine/Source/Programs/DotNETCommon/DotNETUtilities/ThreadSafeQueue.cs +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Threading; - -namespace Tools.DotNETCommon.ThreadSafeQueue -{ - /// - /// A thread-safe reader-writer-locked wrapper to the stock .NET Queue container. - /// - /// The type of the classes that will be queued in this container. - /// All operations are exception checked, so it will return default values rather than crash when used improperly. - public class ThreadSafeQueue - { - /// The key to protecting the contained queue properly - private ReaderWriterLock AccessLock = new ReaderWriterLock(); - - /// The protected queue - private Queue ProtectedQueue = new Queue(); - - /// - /// Default constructor. - /// - public ThreadSafeQueue() - { - } - - /// - /// Completely empties the queue. - /// - public void Clear() - { - // Modifies the collection, use a writer lock - AccessLock.AcquireWriterLock( Timeout.Infinite ); - try - { - ProtectedQueue.Clear(); - } - finally - { - AccessLock.ReleaseWriterLock(); - } - } - - /// - /// Queue up a new element. - /// - /// A new element to queue. - public void Enqueue( TValue V ) - { - // Modifies the collection, use a writer lock - AccessLock.AcquireWriterLock( Timeout.Infinite ); - try - { - ProtectedQueue.Enqueue( V ); - } - finally - { - AccessLock.ReleaseWriterLock(); - } - } - - /// - /// Dequeue an existing element. - /// - /// A previously queued element. - public TValue Dequeue() - { - // Modifies the collection, use a writer lock - AccessLock.AcquireWriterLock( Timeout.Infinite ); - TValue V = default( TValue ); - try - { - V = ProtectedQueue.Dequeue(); - } - finally - { - AccessLock.ReleaseWriterLock(); - } - - return V; - } - - /// - /// Return all elements of the queue as an array. - /// - /// An array of all elements in the queue. - public TValue[] ToArray() - { - // Does not modify the collection, use a reader lock - AccessLock.AcquireReaderLock( Timeout.Infinite ); - TValue[] ReturnValues; - try - { - ReturnValues = ProtectedQueue.ToArray(); - } - finally - { - AccessLock.ReleaseReaderLock(); - } - return ReturnValues; - } - - /// - /// Return the number of elements in the queue. - /// - /// A count of elements in the queue. - public int Count - { - get - { - // Does not modify the collection, use a reader lock - AccessLock.AcquireReaderLock( Timeout.Infinite ); - int ReturnValue = 0; - try - { - ReturnValue = ProtectedQueue.Count; - } - finally - { - AccessLock.ReleaseReaderLock(); - } - - return ReturnValue; - } - } - } -} \ No newline at end of file diff --git a/Engine/Source/Programs/GitDependencies/DependencyManifest.cs b/Engine/Source/Programs/GitDependencies/DependencyManifest.cs index e043149ce460..22263ad0aabc 100644 --- a/Engine/Source/Programs/GitDependencies/DependencyManifest.cs +++ b/Engine/Source/Programs/GitDependencies/DependencyManifest.cs @@ -12,67 +12,127 @@ using System.ComponentModel; namespace GitDependencies { + /// + /// Contains information about a binary dependency in the workspace + /// [DebuggerDisplay("{Name}")] public class DependencyFile { + /// + /// Name of the file, relative to the root. Directories are separated with forward slashes, without a leading slash. + /// [XmlAttribute] public string Name; + /// + /// Hash of this file. Used to determine which blob represents its contents. + /// [XmlAttribute] public string Hash; + /// + /// Whether this file should have the exectuable bit set, on platforms that support it. + /// [XmlAttribute] [DefaultValue(false)] public bool IsExecutable; } + /// + /// Represents a hashed binary blob of data. + /// [DebuggerDisplay("{Hash}")] public class DependencyBlob { + /// + /// Hash of the blob. + /// [XmlAttribute] public string Hash; + /// + /// Size of the blob. + /// [XmlAttribute] public long Size; + /// + /// Hash of the pack file containing this blob. + /// [XmlAttribute] public string PackHash; + /// + /// Offset of this blob's data within the pack file. + /// [XmlAttribute] public long PackOffset; } + /// + /// A downloadable data file which can contain several blobs. + /// [DebuggerDisplay("{Hash}")] public class DependencyPack { + /// + /// Hash of this pack file. + /// [XmlAttribute] public string Hash; + /// + /// Size of this pack file, when uncompressed. + /// [XmlAttribute] public long Size; + /// + /// Compressed size of this pack file. + /// [XmlAttribute] public long CompressedSize; + /// + /// Subdirectory for this pack file on the remote server. + /// [XmlAttribute] public string RemotePath; } + /// + /// A manifest for dependencies that should be unpacked into the workspace at a given revision. + /// public class DependencyManifest { + /// + /// Base URL for downloading pack files from. + /// [XmlAttribute] public string BaseUrl = "http://cdn.unrealengine.com/dependencies"; + /// + /// Whether to ignore proxy servers when downloading files from this remote. + /// [XmlAttribute] [DefaultValue(false)] public bool IgnoreProxy; + /// + /// Files which should be extracted into the workspace. + /// [XmlArrayItem("File")] public DependencyFile[] Files = new DependencyFile[0]; + /// + /// All the blobs required for entries in the Files array. + /// [XmlArrayItem("Blob")] public DependencyBlob[] Blobs = new DependencyBlob[0]; + /// + /// All the packs required for entries in the Blobs array + /// [XmlArrayItem("Pack")] public DependencyPack[] Packs = new DependencyPack[0]; } diff --git a/Engine/Source/Programs/IOS/iPhonePackager/MobileProvisionUtilities.cs b/Engine/Source/Programs/IOS/iPhonePackager/MobileProvisionUtilities.cs index 96e8222ff9c9..bcdda987fbd4 100644 --- a/Engine/Source/Programs/IOS/iPhonePackager/MobileProvisionUtilities.cs +++ b/Engine/Source/Programs/IOS/iPhonePackager/MobileProvisionUtilities.cs @@ -139,14 +139,14 @@ namespace iPhonePackager if (TestProvision.FileName.Contains(TestProvision.UUID)) continue; + Program.LogVerbose(" Phase {0} considering provision '{1}' named '{2}'", Phase, DebugName, TestProvision.ProvisionName); + // check to see if the platform is the same as what we are looking for if (!string.IsNullOrEmpty(TestProvision.Platform) && TestProvision.Platform != Config.OSString && !string.IsNullOrEmpty(Config.OSString)) continue; - Program.LogVerbose(" Phase {0} considering provision '{1}' named '{2}'", Phase, DebugName, TestProvision.ProvisionName); - - // Validate the name - bool bPassesNameCheck = false; + // Validate the name + bool bPassesNameCheck = false; if (Phase == 0) { bPassesNameCheck = TestProvision.ApplicationIdentifier.Substring(TestProvision.ApplicationIdentifierPrefix.Length+1) == CFBundleIdentifier; diff --git a/Engine/Source/Programs/IOS/iPhonePackager/iPhonePackager.csproj b/Engine/Source/Programs/IOS/iPhonePackager/iPhonePackager.csproj index 40688eae7c9f..fc7408bbf28c 100644 --- a/Engine/Source/Programs/IOS/iPhonePackager/iPhonePackager.csproj +++ b/Engine/Source/Programs/IOS/iPhonePackager/iPhonePackager.csproj @@ -53,7 +53,7 @@ DEBUG;TRACE prompt 4 - AnyCPU + x64 pdbonly diff --git a/Engine/Source/Programs/IncludeTool/IncludeTool/Rules.cs b/Engine/Source/Programs/IncludeTool/IncludeTool/Rules.cs index 524e8506a74a..5093d44bacc6 100644 --- a/Engine/Source/Programs/IncludeTool/IncludeTool/Rules.cs +++ b/Engine/Source/Programs/IncludeTool/IncludeTool/Rules.cs @@ -1,4 +1,4 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. using IncludeTool.Support; using System; @@ -263,6 +263,9 @@ namespace IncludeTool "/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Public/OnlineSubsystemSteamPackage.h", "/Engine/Plugins/Online/OnlineSubsystemAmazon/Source/Public/OnlineSubsystemAmazonPackage.h", "/Engine/Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Public/OnlineSubsystemUtilsPackage.h", + "/Engine/Plugins/Online/OnlineSubsystemTwitch/Source/Public/OnlineSubsystemTwitchPackage.h", + "/Engine/Plugins/Online/PS4/OnlineSubsystemPS4Server/Source/Public/OnlineSubsystemPS4ServerPackage.h", + "/Engine/Plugins/Online/XboxOne/OnlineSubsystemLiveServer/Source/Public/OnlineSubsystemLiveServerPackage.h", "/Engine/Source/Runtime/Online/OnlineSubsystemAmazon/Public/OnlineSubsystemAmazonPackage.h", "/Engine/Source/Runtime/Online/OnlineSubsystemFacebook/Public/OnlineSubsystemFacebookPackage.h", "/Engine/Source/Runtime/Online/OnlineSubsystemSteam/Public/OnlineSubsystemSteamPackage.h", @@ -592,7 +595,7 @@ namespace IncludeTool /// public static bool AllowSymbol(string Name) { - if(Name == "FNode" || Name == "FFunctionExpression" || Name == "ITextData") + if(Name == "FNode" || Name == "FFunctionExpression" || Name == "ITextData" || Name == "Rect") { return false; } diff --git a/Engine/Source/Programs/IncludeTool/IncludeTool/Support/FileSystemReference.cs b/Engine/Source/Programs/IncludeTool/IncludeTool/Support/FileSystemReference.cs index 7c12ee8cae8e..af7c9badbf0c 100644 --- a/Engine/Source/Programs/IncludeTool/IncludeTool/Support/FileSystemReference.cs +++ b/Engine/Source/Programs/IncludeTool/IncludeTool/Support/FileSystemReference.cs @@ -84,7 +84,7 @@ namespace IncludeTool.Support if (Length == 0) { // Multiple directory separators in a row; illegal. - throw new ArgumentException("Path fragment '{0}' contains invalid directory separators."); + throw new ArgumentException(String.Format("Path fragment '{0}' contains invalid directory separators.", Fragment)); } else if (Length == 2 && Fragment[StartIdx] == '.' && Fragment[StartIdx + 1] == '.') { diff --git a/Engine/Source/Programs/Mac/DsymExporter/Private/DsymExporterApp.cpp b/Engine/Source/Programs/Mac/DsymExporter/Private/DsymExporterApp.cpp index 1e2979cc181e..fcb6a7b8aa7c 100644 --- a/Engine/Source/Programs/Mac/DsymExporter/Private/DsymExporterApp.cpp +++ b/Engine/Source/Programs/Mac/DsymExporter/Private/DsymExporterApp.cpp @@ -15,7 +15,8 @@ int32 RunDsymExporter(int32 ArgC, TCHAR* Argv[]) if( ArgC < 2 ) { UE_LOG( LogInit, Error, TEXT( "DsymExporter - not enough parameters." ) ); - UE_LOG( LogInit, Error, TEXT( " ... usage: DsymExporter [Output Folder]" ) ); + UE_LOG( LogInit, Error, TEXT( " ... usage: DsymExporter [-UUID=ID] [Output Folder]" ) ); + UE_LOG( LogInit, Error, TEXT( "[-UUID=ID]: This is the UUID of the Mach-O Binary at the provided path. This for use by IOS because Core Symbolication is not properly finding it." ) ); UE_LOG( LogInit, Error, TEXT( ": This is an absolute path to a Mach-O binary containing symbols, which may be the payload binary within an application, framework or dSYM bundle, an executable or dylib." ) ); UE_LOG( LogInit, Error, TEXT( "[Output Folder]: The folder to write the new symbol database to, the database will take the filename of the input plus the .udebugsymbols extension." ) ); return 1; @@ -26,17 +27,30 @@ int32 RunDsymExporter(int32 ArgC, TCHAR* Argv[]) #endif FPlatformSymbolDatabase Symbols; - FString Signature; - bool bOK = FPlatformSymbolication::LoadSymbolDatabaseForBinary(TEXT(""), Argv[1], Signature, Symbols); + FString PathArg = Argv[1]; + FString SigArg; + bool bHaveSigArg = false; + if (PathArg[0] == L'-') + { + SigArg = Argv[1]; + PathArg = Argv[2]; + bHaveSigArg = true; + } + FString Signature = SigArg.RightChop(6); + bool bOK = FPlatformSymbolication::LoadSymbolDatabaseForBinary(TEXT(""), PathArg, Signature, Symbols); if(bOK) { FString OutputFolder = FPaths::GetPath(Argv[1]); - if(ArgC == 3) + if(ArgC == 3 && !bHaveSigArg) { OutputFolder = Argv[2]; } + else if (ArgC == 4) + { + OutputFolder = Argv[3]; + } - if(FPlatformSymbolication::SaveSymbolDatabaseForBinary(OutputFolder, FPaths::GetBaseFilename(Argv[1]), Symbols)) + if(FPlatformSymbolication::SaveSymbolDatabaseForBinary(OutputFolder, FPaths::GetBaseFilename(PathArg), Signature, Symbols)) { return 0; } diff --git a/Engine/Source/Programs/MayaLiveLinkPlugin/MayaLiveLinkPlugin.Target.cs b/Engine/Source/Programs/MayaLiveLinkPlugin/MayaLiveLinkPlugin.Target.cs index d5469459166d..70eb66019bc2 100644 --- a/Engine/Source/Programs/MayaLiveLinkPlugin/MayaLiveLinkPlugin.Target.cs +++ b/Engine/Source/Programs/MayaLiveLinkPlugin/MayaLiveLinkPlugin.Target.cs @@ -24,5 +24,7 @@ public class MayaLiveLinkPluginTarget : TargetRules bCompileAgainstCoreUObject = true; bCompileICU = false; bHasExports = true; + + bBuildInSolutionByDefault = false; } } diff --git a/Engine/Source/Programs/MayaLiveLinkPlugin/MayaLiveLinkPlugin.cpp b/Engine/Source/Programs/MayaLiveLinkPlugin/MayaLiveLinkPlugin.cpp index f7646cb1e52c..b342d6681104 100644 --- a/Engine/Source/Programs/MayaLiveLinkPlugin/MayaLiveLinkPlugin.cpp +++ b/Engine/Source/Programs/MayaLiveLinkPlugin/MayaLiveLinkPlugin.cpp @@ -9,6 +9,7 @@ #include "LiveLinkProvider.h" #include "LiveLinkRefSkeleton.h" +#include "LiveLinkTypes.h" #include "OutputDevice.h" DEFINE_LOG_CATEGORY_STATIC(LogBlankMayaPlugin, Log, All); @@ -143,30 +144,38 @@ TArray JointsToStream; double LastStreamSeconds = 0.f; +MTime CurrentTime; + +bool bNeedsHierarchy = true; + +void BuildStreamHierarchyData(); + void StreamJoints() { + if (bNeedsHierarchy) + { + BuildStreamHierarchyData(); + } + + CurrentTime = MAnimControl::currentTime(); + double NewSeconds = FPlatformTime::Seconds(); - if (NewSeconds - LastStreamSeconds < (1.f / 90.f)) + if (NewSeconds - LastStreamSeconds < (1.0 / 90.0)) { return; } LastStreamSeconds = NewSeconds; TArray JointTransforms; - JointTransforms.Reserve(JointTransforms.Num()); + JointTransforms.Reserve(JointsToStream.Num()); TArray InverseScales; - InverseScales.Reserve(JointTransforms.Num()); - - TArray JointNames; - JointNames.Reserve(JointTransforms.Num()); + InverseScales.Reserve(JointsToStream.Num()); for (int32 Idx = 0; Idx < JointsToStream.Num(); ++Idx) { FStreamHierarchy& H = JointsToStream[Idx]; - JointNames.Add(H.JointName); - MTransformationMatrix::RotationOrder RotOrder = H.JointObject.rotationOrder(); MMatrix JointScale = GetScale(H.JointObject); @@ -230,8 +239,38 @@ void StreamJoints() JointTransforms.Add(UETrans); } - const FString SubjectName(TEXT("Subject")); - LiveLinkProvider->SendSubject(SubjectName, JointNames, JointTransforms); + TArray Curves; + const FName SubjectName(TEXT("Maya")); + +#if 0 + double CurFrame = CurrentTime.value(); + double CurveValue = CurFrame / 200.0; + + Curves.AddDefaulted(); + Curves[0].CurveName = FName(TEXT("Test")); + Curves[0].CurveValue = static_cast(FMath::Clamp(CurveValue, 0.0, 1.0)); + + if (CurFrame > 100.0) + { + double Curve2Value = (CurFrame - 100.0) / 100.0; + Curves.AddDefaulted(); + Curves[1].CurveName = FName(TEXT("Test2")); + Curves[1].CurveValue = static_cast(FMath::Clamp(Curve2Value, 0.0, 1.0)); + } + //MGlobal::displayInfo(MString("CURVE TEST:") + CurFrame + " " + CurveValue); + + if (CurFrame > 201.0) + { + LiveLinkProvider->ClearSubject(SubjectName); + bNeedsHierarchy = true; + } + else + { + LiveLinkProvider->UpdateSubjectFrame(SubjectName, JointTransforms, Curves, FPlatformTime::Seconds(), CurrentTime.value()); + } +#else + LiveLinkProvider->UpdateSubjectFrame(SubjectName, JointTransforms, Curves, FPlatformTime::Seconds(), CurrentTime.value()); +#endif } void OnDagChangedAll(MObject& transformNode, MDagMessage::MatrixModifiedFlags& modified, void *clientData) @@ -246,6 +285,8 @@ MCallbackIdArray StreamHierarchyCallbackIds; void BuildStreamHierarchyData() { + bNeedsHierarchy = false; + if (StreamHierarchyCallbackIds.length() != 0) { // Make sure we remove all the callbacks we added @@ -262,6 +303,9 @@ void BuildStreamHierarchyData() MStatus status; MItDag dagIterator(traversalType, filter, &status); + TArray JointNames; + TArray JointParents; + for (; !dagIterator.isDone(); dagIterator.next()) { MDagPath dagPath; @@ -315,9 +359,14 @@ void BuildStreamHierarchyData() StreamHierarchyCallbackIds.append(NewCB); JointsToStream.Add(FStreamHierarchy(FName(SA[LastName].asChar()), JointPath, ParentIndex)); + JointNames.Add(FName(SA[LastName].asChar())); + JointParents.Add(ParentIndex); } } + const FName SubjectName(TEXT("Maya")); + LiveLinkProvider->UpdateSubject(SubjectName, JointNames, JointParents); + } void RecurseJoint(MFnDagNode& Joint, const MMatrix& ParentInverseScale, TArray& JointNames, TArray& JointTransform) { @@ -421,8 +470,6 @@ void RecurseJoint(MFnDagNode& Joint, const MMatrix& ParentInverseScale, TArraySendSubject(SubjectName, JointNames, JointTransforms); + //LiveLinkProvider->UpdateSubjectFrame(SubjectName, JointNames, JointTransforms); return; } diff --git a/Engine/Source/Programs/MemoryProfiler2/MainWindow.cs b/Engine/Source/Programs/MemoryProfiler2/MainWindow.cs index 6f1a6271be5d..9bd977dd3e4f 100644 --- a/Engine/Source/Programs/MemoryProfiler2/MainWindow.cs +++ b/Engine/Source/Programs/MemoryProfiler2/MainWindow.cs @@ -53,10 +53,15 @@ namespace MemoryProfiler2 /// Font used to draw numbers on an axis. public Font AxisFont = new Font( FontFamily.GenericSansSerif, 13, GraphicsUnit.Pixel ); - /// Initializes common controls and setups all needed properties. - private void CommonInit() + /// Copy of original window title so we rebuild it when the loaded file changes + public string OriginalWindowTitle; + + /// Initializes common controls and setups all needed properties. + private void CommonInit() { - Options = UnrealControls.XmlHandler.ReadXml( Path.Combine( Application.StartupPath, "MemoryProfiler2.ClassGroups.xml" ) ); + OriginalWindowTitle = Text; + + Options = UnrealControls.XmlHandler.ReadXml( Path.Combine( Application.StartupPath, "MemoryProfiler2.ClassGroups.xml" ) ); Options.ApplyDefaults(); AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler( CurrentDomain_AssemblyResolve ); @@ -499,6 +504,8 @@ namespace MemoryProfiler2 { CurrentFilename = InCurrentFilename; + Text = OriginalWindowTitle + " - " + CurrentFilename; + MemoryPoolFilterButton.Enabled = false; // Only parse if we have a valid file. diff --git a/Engine/Source/Programs/ShaderCompileWorker/Private/ShaderCompileWorker.cpp b/Engine/Source/Programs/ShaderCompileWorker/Private/ShaderCompileWorker.cpp index fdabf50bbe9b..de3e0cc309a7 100644 --- a/Engine/Source/Programs/ShaderCompileWorker/Private/ShaderCompileWorker.cpp +++ b/Engine/Source/Programs/ShaderCompileWorker/Private/ShaderCompileWorker.cpp @@ -567,7 +567,8 @@ static FName NAME_PCD3D_ES2(TEXT("PCD3D_ES2")); static FName NAME_GLSL_150(TEXT("GLSL_150")); static FName NAME_GLSL_150_MAC(TEXT("GLSL_150_MAC")); static FName NAME_SF_PS4(TEXT("SF_PS4")); -static FName NAME_SF_XBOXONE(TEXT("SF_XBOXONE")); +static FName NAME_SF_XBOXONE_D3D11(TEXT("SF_XBOXONE_D3D11")); +static FName NAME_SF_XBOXONE_D3D12(TEXT("SF_XBOXONE_D3D12")); static FName NAME_GLSL_430(TEXT("GLSL_430")); static FName NAME_GLSL_150_ES2(TEXT("GLSL_150_ES2")); static FName NAME_GLSL_150_ES2_NOUB(TEXT("GLSL_150_ES2_NOUB")); @@ -596,11 +597,12 @@ static EShaderPlatform FormatNameToEnum(FName ShaderFormat) if (ShaderFormat == NAME_PCD3D_ES2) return SP_PCD3D_ES2; if (ShaderFormat == NAME_GLSL_150) return SP_OPENGL_SM4; if (ShaderFormat == NAME_GLSL_150_MAC) return SP_OPENGL_SM4_MAC; - if (ShaderFormat == NAME_SF_PS4) return SP_PS4; - if (ShaderFormat == NAME_SF_XBOXONE) return SP_XBOXONE; + if (ShaderFormat == NAME_SF_PS4) return SP_PS4; + if (ShaderFormat == NAME_SF_XBOXONE_D3D11) return SP_XBOXONE_D3D11; + if (ShaderFormat == NAME_SF_XBOXONE_D3D12) return SP_XBOXONE_D3D12; if (ShaderFormat == NAME_GLSL_430) return SP_OPENGL_SM5; - if (ShaderFormat == NAME_GLSL_150_ES2) return SP_OPENGL_PCES2; - if (ShaderFormat == NAME_GLSL_150_ES2_NOUB) return SP_OPENGL_PCES2; + if (ShaderFormat == NAME_GLSL_150_ES2) return SP_OPENGL_PCES2; + if (ShaderFormat == NAME_GLSL_150_ES2_NOUB) return SP_OPENGL_PCES2; if (ShaderFormat == NAME_GLSL_150_ES31) return SP_OPENGL_PCES3_1; if (ShaderFormat == NAME_GLSL_ES2) return SP_OPENGL_ES2_ANDROID; if (ShaderFormat == NAME_GLSL_ES2_WEBGL) return SP_OPENGL_ES2_WEBGL; @@ -631,6 +633,7 @@ static void DirectCompile(const TArray& ShaderFormat FName FormatName; FString Entry = TEXT("Main"); bool bPipeline = false; + bool bUseMCPP = false; EShaderFrequency Frequency = SF_Pixel; TArray UsedOutputs; bool bIncludeUsedOutputs = false; @@ -679,6 +682,10 @@ static void DirectCompile(const TArray& ShaderFormat { bPipeline = true; } + else if (!FCString::Strcmp(*Token, TEXT("mcpp"))) + { + bUseMCPP = true; + } else if (Token.StartsWith(TEXT("usedoutputs="))) { FString Outputs = Token.RightChop(12); @@ -709,7 +716,7 @@ static void DirectCompile(const TArray& ShaderFormat Input.SourceFilename = InputFile; Input.Target.Platform = FormatNameToEnum(FormatName); Input.Target.Frequency = Frequency; - Input.bSkipPreprocessedCache = true; + Input.bSkipPreprocessedCache = !bUseMCPP; auto AddResourceTableEntry = [](TMap& Map, const FString& Name, const FString& UBName, int32 Type, int32 ResourceIndex) { diff --git a/Engine/Source/Programs/ShaderCompileWorker/ShaderCompileWorker.Target.cs b/Engine/Source/Programs/ShaderCompileWorker/ShaderCompileWorker.Target.cs index ca0635d374a2..1447693520a6 100644 --- a/Engine/Source/Programs/ShaderCompileWorker/ShaderCompileWorker.Target.cs +++ b/Engine/Source/Programs/ShaderCompileWorker/ShaderCompileWorker.Target.cs @@ -30,6 +30,9 @@ public class ShaderCompileWorkerTarget : TargetRules // Currently we force Lean and Mean mode UEBuildConfiguration.bCompileLeanAndMeanUE = true; + // ShaderCompileWorker isn't localized, so doesn't need ICU + UEBuildConfiguration.bCompileICU = false; + // Currently this app is not linking against the engine, so we'll compile out references from Core to the rest of the engine UEBuildConfiguration.bCompileAgainstEngine = false; UEBuildConfiguration.bCompileAgainstCoreUObject = false; diff --git a/Engine/Source/Programs/UnrealBuildTool/Android/AndroidAARHandler.cs b/Engine/Source/Programs/UnrealBuildTool/Android/AndroidAARHandler.cs index 91b22df1d546..3d369df863b4 100644 --- a/Engine/Source/Programs/UnrealBuildTool/Android/AndroidAARHandler.cs +++ b/Engine/Source/Programs/UnrealBuildTool/Android/AndroidAARHandler.cs @@ -137,7 +137,76 @@ namespace UnrealBuildTool return null; } - + + private bool HasAnyVersionCharacters(string InValue) + { + for (int Index = 0; Index < InValue.Length; Index++) + { + char c = InValue[Index]; + if (c == '.' || (c >= '0' && c <= '9')) + { + return true; + } + } + return false; + } + + private bool HasOnlyVersionCharacters(string InValue) + { + for (int Index = 0; Index < InValue.Length; Index++) + { + char c = InValue[Index]; + if (c != '.' && !(c >= '0' && c <= '9')) + { + return false; + } + } + return true; + } + + // clean up the version (Maven version info here: https://docs.oracle.com/middleware/1212/core/MAVEN/maven_version.htm) + // only going to handle a few cases, not proper ranges (keeps the rightmost valid version which should be highest) + // will still return something but will include an error in log, but don't want to throw an exception + private string CleanupVersion(string Filename, string InVersion) + { + string WorkVersion = InVersion; + + // if has commas, keep the rightmost part with actual numbers + if (WorkVersion.Contains(",")) + { + string[] CommaParts = WorkVersion.Split(','); + WorkVersion = ""; + for (int Index = CommaParts.Length - 1; Index >= 0; Index--) + { + if (HasAnyVersionCharacters(CommaParts[Index])) + { + WorkVersion = CommaParts[Index]; + break; + } + } + } + + // if not left with a possibly valid number, stop + if (!HasAnyVersionCharacters(WorkVersion)) + { + Log.TraceError("AAR Dependency file {0} version unknown! {1}", Filename, InVersion); + return InVersion; + } + + // just remove any parens or brackets left + WorkVersion = WorkVersion.Replace("(", "").Replace(")", "").Replace("[", "").Replace("]", ""); + + // just return it if now looks value + if (HasOnlyVersionCharacters(WorkVersion)) + { + return WorkVersion; + } + + // give an error, not likely going to work, though + Log.TraceError("AAR Dependency file {0} version unknown! {1}", Filename, InVersion); + return InVersion; + } + /// /// Adds a new required JAR file and resolves dependencies /// @@ -237,7 +306,7 @@ namespace UnrealBuildTool { string DepGroupId = GetElementValue(DependNode, GroupIdName, ""); string DepArtifactId = GetElementValue(DependNode, ArtifactIdName, ""); - string DepVersion = GetElementValue(DependNode, VersionName, ""); + string DepVersion = CleanupVersion(DependencyFilename + "." + DepGroupId + "." + DepArtifactId, GetElementValue(DependNode, VersionName, "")); string DepScope = GetElementValue(DependNode, ScopeName, "compile"); string DepType = GetElementValue(DependNode, TypeName, "jar"); @@ -360,7 +429,7 @@ namespace UnrealBuildTool { string DepGroupId = GetElementValue(DependNode, GroupIdName, ""); string DepArtifactId = GetElementValue(DependNode, ArtifactIdName, ""); - string DepVersion = GetElementValue(DependNode, VersionName, ""); + string DepVersion = CleanupVersion(DependencyFilename + "." + DepGroupId + "." + DepArtifactId, GetElementValue(DependNode, VersionName, "")); string DepScope = GetElementValue(DependNode, ScopeName, "compile"); string DepType = GetElementValue(DependNode, TypeName, "jar"); @@ -558,19 +627,19 @@ namespace UnrealBuildTool OutputFileName = NewOutputFileName; } - Directory.CreateDirectory(Path.GetDirectoryName(OutputFileName)); - if (!Entry.IsDirectory) - { - using (FileStream OutputStream = new FileStream(OutputFileName, FileMode.Create, FileAccess.Write)) - { - Entry.Extract(OutputStream); - } - OutputFileNames.Add(OutputFileName); - } - } - return OutputFileNames; - } - } + Directory.CreateDirectory(Path.GetDirectoryName(OutputFileName)); + if (!Entry.IsDirectory) + { + using (FileStream OutputStream = new FileStream(OutputFileName, FileMode.Create, FileAccess.Write)) + { + Entry.Extract(OutputStream); + } + OutputFileNames.Add(OutputFileName); + } + } + return OutputFileNames; + } + } - } + } } diff --git a/Engine/Source/Programs/UnrealBuildTool/Android/AndroidExports.cs b/Engine/Source/Programs/UnrealBuildTool/Android/AndroidExports.cs index fcceda6386fb..ca4413b87670 100644 --- a/Engine/Source/Programs/UnrealBuildTool/Android/AndroidExports.cs +++ b/Engine/Source/Programs/UnrealBuildTool/Android/AndroidExports.cs @@ -55,7 +55,7 @@ namespace UnrealBuildTool /// /// /// - bool PrepForUATPackageOrDeploy(FileReference ProjectFile, string ProjectName, string ProjectDirectory, string ExecutablePath, string EngineDirectory, bool bForDistribution, string CookFlavor, bool bIsDataDeploy); + bool PrepForUATPackageOrDeploy(FileReference ProjectFile, string ProjectName, DirectoryReference ProjectDirectory, string ExecutablePath, string EngineDirectory, bool bForDistribution, string CookFlavor, bool bIsDataDeploy); } /// diff --git a/Engine/Source/Programs/UnrealBuildTool/Android/AndroidToolChain.cs b/Engine/Source/Programs/UnrealBuildTool/Android/AndroidToolChain.cs index 59345bed7614..fc89209da83b 100644 --- a/Engine/Source/Programs/UnrealBuildTool/Android/AndroidToolChain.cs +++ b/Engine/Source/Programs/UnrealBuildTool/Android/AndroidToolChain.cs @@ -379,6 +379,7 @@ namespace UnrealBuildTool Result += " -c"; Result += " -fdiagnostics-format=msvc"; Result += " -Wall"; + Result += " -Wdelete-non-virtual-dtor"; Result += " -Wno-unused-variable"; // this will hide the warnings about static functions in headers that aren't used in every single .cpp file @@ -1120,7 +1121,7 @@ namespace UnrealBuildTool } // Create the response file - FileReference ResponseFileName = CompileAction.ProducedItems[0].Reference + "_" + AllArguments.GetHashCode().ToString("X") + ".response"; + FileReference ResponseFileName = CompileAction.ProducedItems[0].Reference + "_" + AllArguments.GetHashCode().ToString("X") + ".rsp"; string ResponseArgument = string.Format("@\"{0}\"", ResponseFile.Create(ResponseFileName, new List { AllArguments }).FullName); CompileAction.WorkingDirectory = UnrealBuildTool.EngineSourceDirectory.FullName; @@ -1376,7 +1377,7 @@ namespace UnrealBuildTool foreach (FileReference BinaryPath in Binary.Config.OutputFilePaths) { FileReference ApkFile = BinaryPath.ChangeExtension(".apk"); - BuildProducts.Add(ApkFile, BuildProductType.Executable); + BuildProducts.Add(ApkFile, BuildProductType.Package); } } } diff --git a/Engine/Source/Programs/UnrealBuildTool/Android/UEBuildAndroid.cs b/Engine/Source/Programs/UnrealBuildTool/Android/UEBuildAndroid.cs index 3935a083d550..8e762602f566 100644 --- a/Engine/Source/Programs/UnrealBuildTool/Android/UEBuildAndroid.cs +++ b/Engine/Source/Programs/UnrealBuildTool/Android/UEBuildAndroid.cs @@ -96,7 +96,6 @@ namespace UnrealBuildTool Target.bCompilePhysX = true; Target.bCompileAPEX = false; Target.bCompileNvCloth = false; - Target.bRuntimePhysicsCooking = false; Target.bBuildEditor = false; Target.bBuildDeveloperTools = false; diff --git a/Engine/Source/Programs/UnrealBuildTool/Android/UEDeployAndroid.cs b/Engine/Source/Programs/UnrealBuildTool/Android/UEDeployAndroid.cs index af04e6664159..64618e83b53a 100644 --- a/Engine/Source/Programs/UnrealBuildTool/Android/UEDeployAndroid.cs +++ b/Engine/Source/Programs/UnrealBuildTool/Android/UEDeployAndroid.cs @@ -14,6 +14,18 @@ namespace UnrealBuildTool { class UEDeployAndroid : UEBuildDeploy, IAndroidDeploy { + // Minimum Android SDK that must be used for Java compiling + readonly int MinimumSDKLevel = 23; + + // Reserved Java keywords not allowed in package names without modification + static private string[] JavaReservedKeywords = new string[] { + "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "default", "do", + "double", "else", "enum", "extends", "final", "finally", "float", "for", "goto", "if", "implements", "import", "instanceof", + "int", "interface", "long", "native", "new", "package", "private", "protected", "public", "return", "short", "static", + "strictfp", "super", "switch", "sychronized", "this", "throw", "throws", "transient", "try", "void", "volatile", "while", + "false", "null", "true" + }; + /// /// Internal usage for GetApiLevel /// @@ -27,6 +39,8 @@ namespace UnrealBuildTool } private UnrealPluginLanguage UPL = null; + private bool GoogleVRPluginEnabled = false; + private bool CrashlyticsPluginEnabled = false; public void SetAndroidPluginData(List Architectures, List inPluginExtraData) { @@ -35,6 +49,29 @@ namespace UnrealBuildTool { NDKArches.Add(GetNDKArch(Arch)); } + + // check if the GoogleVR plugin was enabled + GoogleVRPluginEnabled = false; + foreach (var Plugin in inPluginExtraData) + { + if (Plugin.Contains("GoogleVRHMD")) + { + GoogleVRPluginEnabled = true; + break; + } + } + + // check if the Crashlytics plugin was enabled + CrashlyticsPluginEnabled = false; + foreach (var Plugin in inPluginExtraData) + { + if (Plugin.Contains("Crashlytics")) + { + CrashlyticsPluginEnabled = true; + break; + } + } + UPL = new UnrealPluginLanguage(ProjectFile, inPluginExtraData, NDKArches, "http://schemas.android.com/apk/res/android", "xmlns:android=\"http://schemas.android.com/apk/res/android\"", UnrealTargetPlatform.Android); // APL.SetTrace(); } @@ -66,6 +103,45 @@ namespace UnrealBuildTool return ConfigCache.ReadHierarchy(Type, DirectoryReference.FromFile(ProjectFile), UnrealTargetPlatform.Android); } + private string GetLatestSDKApiLevel(AndroidToolChain ToolChain) + { + // we expect there to be one, so use the first one + string AndroidCommandPath = Environment.ExpandEnvironmentVariables("%ANDROID_HOME%/tools/android" + (Utils.IsRunningOnMono ? "" : ".bat")); + + // run a command and capture output + var ExeInfo = new ProcessStartInfo(AndroidCommandPath, "list targets"); + ExeInfo.UseShellExecute = false; + ExeInfo.RedirectStandardOutput = true; + using (var GameProcess = Process.Start(ExeInfo)) + { + PossibleApiLevels = new List(); + GameProcess.BeginOutputReadLine(); + GameProcess.OutputDataReceived += ParseApiLevel; + GameProcess.WaitForExit(); + } + + if (PossibleApiLevels != null && PossibleApiLevels.Count > 0) + { + return ToolChain.GetLargestApiLevel(PossibleApiLevels.ToArray()); + } + + throw new BuildException("Can't make an APK without an API installed (see \"android.bat list targets\")"); + } + + private int GetApiLevelInt(string ApiString) + { + int VersionInt = 0; + if (ApiString.Contains("-")) + { + int Version; + if (int.TryParse(ApiString.Substring(ApiString.LastIndexOf('-') + 1), out Version)) + { + VersionInt = Version; + } + } + return VersionInt; + } + private string CachedSDKLevel = null; private string GetSdkApiLevel(AndroidToolChain ToolChain) { @@ -85,27 +161,20 @@ namespace UnrealBuildTool // run a command and capture output if (SDKLevel == "latest") { - // we expect there to be one, so use the first one - string AndroidCommandPath = Environment.ExpandEnvironmentVariables("%ANDROID_HOME%/tools/android" + (Utils.IsRunningOnMono ? "" : ".bat")); + SDKLevel = GetLatestSDKApiLevel(ToolChain); + } - var ExeInfo = new ProcessStartInfo(AndroidCommandPath, "list targets"); - ExeInfo.UseShellExecute = false; - ExeInfo.RedirectStandardOutput = true; - using (var GameProcess = Process.Start(ExeInfo)) - { - PossibleApiLevels = new List(); - GameProcess.BeginOutputReadLine(); - GameProcess.OutputDataReceived += ParseApiLevel; - GameProcess.WaitForExit(); - } + // make sure it is at least android-23 + int SDKLevelInt = GetApiLevelInt(SDKLevel); + if (SDKLevelInt < MinimumSDKLevel) + { + Console.WriteLine("Requires at least SDK API level {0}, currently set to '{1}'", MinimumSDKLevel, SDKLevel); + SDKLevel = GetLatestSDKApiLevel(ToolChain); - if (PossibleApiLevels != null && PossibleApiLevels.Count > 0) + SDKLevelInt = GetApiLevelInt(SDKLevel); + if (SDKLevelInt < MinimumSDKLevel) { - SDKLevel = ToolChain.GetLargestApiLevel(PossibleApiLevels.ToArray()); - } - else - { - throw new BuildException("Can't make an APK without an API installed (see \"android.bat list targets\")"); + throw new BuildException("Can't make an APK without API 'android-" + MinimumSDKLevel.ToString() + "' minimum installed (see \"android.bat list targets\")"); } } @@ -198,6 +267,12 @@ namespace UnrealBuildTool public bool IsPackagingForDaydream(ConfigHierarchy Ini = null) { + // always false if the GoogleVR plugin wasn't enabled + if (!GoogleVRPluginEnabled) + { + return false; + } + // make a new one if one wasn't passed in if (Ini == null) { @@ -211,7 +286,9 @@ namespace UnrealBuildTool } else { - return false; + // the default value for the VRMode is DaydreamAndCardboard, so unless the developer + // changes the mode, there will be no setting string to look up here + return true; } } @@ -429,12 +506,36 @@ namespace UnrealBuildTool } } + private int CachedStoreVersion = -1; + public int GetStoreVersion() { - var Ini = GetConfigCacheIni(ConfigHierarchyType.Engine); - int StoreVersion; - Ini.GetInt32("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "StoreVersion", out StoreVersion); - return StoreVersion; + if (CachedStoreVersion < 1) + { + var Ini = GetConfigCacheIni(ConfigHierarchyType.Engine); + int StoreVersion = 1; + Ini.GetInt32("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "StoreVersion", out StoreVersion); + + bool bUseChangeListAsStoreVersion = false; + Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bUseChangeListAsStoreVersion", out bUseChangeListAsStoreVersion); + + // override store version with changelist if enabled and is build machine + if (bUseChangeListAsStoreVersion && Environment.GetEnvironmentVariable("IsBuildMachine") == "1") + { + int Changelist = 0; + if (int.TryParse(EngineChangelist, out Changelist)) + { + if (Changelist != 0) + { + StoreVersion = Changelist; + } + } + } + + CachedStoreVersion = StoreVersion; + } + + return CachedStoreVersion; } public void WriteJavaOBBDataFile(string FileName, string PackageName, List ObbSources) @@ -595,6 +696,49 @@ namespace UnrealBuildTool } } + public void WriteCrashlyticsResources(string UEBuildPath, string PackageName, string ApplicationDisplayName) + { + System.DateTime CurrentDateTime = System.DateTime.Now; + string BuildID = Guid.NewGuid().ToString(); + + ConfigHierarchy Ini = GetConfigCacheIni(ConfigHierarchyType.Engine); + string VersionDisplayName = ""; + Ini.GetString("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "VersionDisplayName", out VersionDisplayName); + + StringBuilder CrashPropertiesContent = new StringBuilder(""); + CrashPropertiesContent.Append("# This file is automatically generated by Crashlytics to uniquely\n"); + CrashPropertiesContent.Append("# identify individual builds of your Android application.\n"); + CrashPropertiesContent.Append("#\n"); + CrashPropertiesContent.Append("# Do NOT modify, delete, or commit to source control!\n"); + CrashPropertiesContent.Append("#\n"); + CrashPropertiesContent.Append("# " + CurrentDateTime.ToString("D") + "\n"); + CrashPropertiesContent.Append("version_name=" + VersionDisplayName + "\n"); + CrashPropertiesContent.Append("package_name=" + PackageName + "\n"); + CrashPropertiesContent.Append("build_id=" + BuildID + "\n"); + CrashPropertiesContent.Append("version_code=" + GetStoreVersion().ToString() + "\n"); + + string CrashPropertiesFileName = Path.Combine(UEBuildPath, "assets", "crashlytics-build.properties"); + MakeDirectoryIfRequired(CrashPropertiesFileName); + File.WriteAllText(CrashPropertiesFileName, CrashPropertiesContent.ToString()); + Log.TraceInformation("==== Write {0} ====", CrashPropertiesFileName); + + StringBuilder BuildIDContent = new StringBuilder(""); + BuildIDContent.Append("\n"); + BuildIDContent.Append("\n"); + BuildIDContent.Append("\n"); + BuildIDContent.Append("" + BuildID + "\n"); + BuildIDContent.Append("\n"); + + string BuildIDFileName = Path.Combine(UEBuildPath, "res", "values", "com_crashlytics_build_id.xml"); + MakeDirectoryIfRequired(BuildIDFileName); + File.WriteAllText(BuildIDFileName, BuildIDContent.ToString()); + Log.TraceInformation("==== Write {0} ====", BuildIDFileName); + } private static string GetNDKArch(string UE4Arch) { @@ -1307,15 +1451,106 @@ namespace UnrealBuildTool } } + private string CachedPackageName = null; + + private bool IsLetter(char Input) + { + return (Input >= 'A' && Input <= 'Z') || (Input >= 'a' && Input <= 'z'); + } + + private bool IsDigit(char Input) + { + return (Input >= '0' && Input <= '9'); + } + private string GetPackageName(string ProjectName) { - ConfigHierarchy Ini = GetConfigCacheIni(ConfigHierarchyType.Engine); - string PackageName; - Ini.GetString("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "PackageName", out PackageName); - // replace some variables - PackageName = PackageName.Replace("[PROJECT]", ProjectName); - PackageName = PackageName.Replace("-", "_"); - return PackageName; + if (CachedPackageName == null) + { + ConfigHierarchy Ini = GetConfigCacheIni(ConfigHierarchyType.Engine); + string PackageName; + Ini.GetString("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "PackageName", out PackageName); + + if (PackageName.Contains("[PROJECT]")) + { + // project name must start with a letter + if (!IsLetter(ProjectName[0])) + { + throw new BuildException("Package name segments must all start with a letter. Please replace [PROJECT] with a valid name"); + } + + // hyphens not allowed so change them to underscores in project name + if (ProjectName.Contains("-")) + { + Trace.TraceWarning("Project name contained hyphens, converted to underscore"); + ProjectName = ProjectName.Replace("-", "_"); + } + + // check for special characters + for (int Index = 0; Index < ProjectName.Length; Index++) + { + char c = ProjectName[Index]; + if (c != '.' && c != '_' && !IsDigit(c) && !IsLetter(c)) + { + throw new BuildException("Project name contains illegal characters (only letters, numbers, and underscore allowed); please replace [PROJECT] with a valid name"); + } + } + + PackageName = PackageName.Replace("[PROJECT]", ProjectName); + } + + // verify minimum number of segments + string[] PackageParts = PackageName.Split('.'); + int SectionCount = PackageParts.Length; + if (SectionCount < 2) + { + throw new BuildException("Package name must have at least 2 segments separated by periods (ex. com.projectname, not projectname); please change in Android Project Settings. Currently set to '" + PackageName + "'"); + } + + // hyphens not allowed + if (PackageName.Contains("-")) + { + throw new BuildException("Package names may not contain hyphens; please change in Android Project Settings. Currently set to '" + PackageName + "'"); + } + + // do not allow special characters + for (int Index = 0; Index < PackageName.Length; Index++) + { + char c = PackageName[Index]; + if (c != '.' && c != '_' && !IsDigit(c) && !IsLetter(c)) + { + throw new BuildException("Package name contains illegal characters (only letters, numbers, and underscore allowed); please change in Android Project Settings. Currently set to '" + PackageName + "'"); + } + } + + // validate each segment + for (int Index = 0; Index < SectionCount; Index++) + { + if (PackageParts[Index].Length < 1) + { + throw new BuildException("Package name segments must have at least one letter; please change in Android Project Settings. Currently set to '" + PackageName + "'"); + } + + if (!IsLetter(PackageParts[Index][0])) + { + throw new BuildException("Package name segments must start with a letter; please change in Android Project Settings. Currently set to '" + PackageName + "'"); + } + + // cannot use Java reserved keywords + foreach (string Keyword in JavaReservedKeywords) + { + if (PackageParts[Index] == Keyword) + { + throw new BuildException("Package name segments must not be a Java reserved keyword (" + Keyword + "); please change in Android Project Settings. Currently set to '" + PackageName + "'"); + } + } + } + + Console.WriteLine("Using package name: '{0}'", PackageName); + CachedPackageName = PackageName; + } + + return CachedPackageName; } private string GetPublicKey() @@ -1326,32 +1561,51 @@ namespace UnrealBuildTool return PlayLicenseKey; } + private bool bHaveReadEngineVersion = false; + private string EngineMajorVersion = "4"; + private string EngineMinorVersion = "0"; + private string EnginePatchVersion = "0"; + private string EngineChangelist = "0"; + + private string ReadEngineVersion(string EngineDirectory) + { + if (!bHaveReadEngineVersion) + { + string EngineVersionFile = Path.Combine(EngineDirectory, "Source", "Runtime", "Launch", "Resources", "Version.h"); + string[] EngineVersionLines = File.ReadAllLines(EngineVersionFile); + for (int i = 0; i < EngineVersionLines.Length; ++i) + { + if (EngineVersionLines[i].StartsWith("#define ENGINE_MAJOR_VERSION")) + { + EngineMajorVersion = EngineVersionLines[i].Split('\t')[1].Trim(' '); + } + else if (EngineVersionLines[i].StartsWith("#define ENGINE_MINOR_VERSION")) + { + EngineMinorVersion = EngineVersionLines[i].Split('\t')[1].Trim(' '); + } + else if (EngineVersionLines[i].StartsWith("#define ENGINE_PATCH_VERSION")) + { + EnginePatchVersion = EngineVersionLines[i].Split('\t')[1].Trim(' '); + } + else if (EngineVersionLines[i].StartsWith("#define BUILT_FROM_CHANGELIST")) + { + EngineChangelist = EngineVersionLines[i].Split(new char[] { ' ', '\t' })[2].Trim(' '); + } + } + + bHaveReadEngineVersion = true; + } + + return EngineMajorVersion + "." + EngineMinorVersion + "." + EnginePatchVersion; + } private string GenerateManifest(AndroidToolChain ToolChain, string ProjectName, string EngineDirectory, bool bIsForDistribution, bool bPackageDataInsideApk, string GameBuildFilesPath, bool bHasOBBFiles, bool bDisableVerifyOBBOnStartUp, string UE4Arch, string GPUArch, string CookFlavor, bool bUseExternalFilesDir, string Configuration) { // Read the engine version - string EngineMajorVersion = "4"; - string EngineMinorVersion = "0"; - string EnginePatchVersion = "0"; - string EngineVersionFile = Path.Combine(EngineDirectory, "Source", "Runtime", "Launch", "Resources", "Version.h"); - string[] EngineVersionLines = File.ReadAllLines(EngineVersionFile); - for (int i = 0; i < EngineVersionLines.Length; ++i) - { - if (EngineVersionLines[i].StartsWith("#define ENGINE_MAJOR_VERSION")) - { - EngineMajorVersion = EngineVersionLines[i].Split('\t')[1].Trim(' '); - } - else if (EngineVersionLines[i].StartsWith("#define ENGINE_MINOR_VERSION")) - { - EngineMinorVersion = EngineVersionLines[i].Split('\t')[1].Trim(' '); - } - else if (EngineVersionLines[i].StartsWith("#define ENGINE_PATCH_VERSION")) - { - EnginePatchVersion = EngineVersionLines[i].Split('\t')[1].Trim(' '); - } - } - string EngineVersion = EngineMajorVersion + "." + EngineMinorVersion + "." + EnginePatchVersion; + string EngineVersion = ReadEngineVersion(EngineDirectory); + + int StoreVersion = GetStoreVersion(); string Arch = GetNDKArch(UE4Arch); int NDKLevelInt = ToolChain.GetNdkApiLevelInt(); @@ -1378,8 +1632,6 @@ namespace UnrealBuildTool Ini.GetInt32("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "MinSDKVersion", out MinSDKVersion); int TargetSDKVersion = MinSDKVersion; Ini.GetInt32("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "TargetSDKVersion", out TargetSDKVersion); - int StoreVersion; - Ini.GetInt32("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "StoreVersion", out StoreVersion); string VersionDisplayName; Ini.GetString("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "VersionDisplayName", out VersionDisplayName); string Orientation; @@ -1409,7 +1661,7 @@ namespace UnrealBuildTool string InstallLocation; Ini.GetString("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "InstallLocation", out InstallLocation); - switch(InstallLocation.ToLower()) + switch (InstallLocation.ToLower()) { case "preferexternal": InstallLocation = "preferExternal"; @@ -1473,7 +1725,7 @@ namespace UnrealBuildTool } else { - switch(CookFlavor) + switch (CookFlavor) { case "_Multi": //need to check ini to determine which are supported @@ -1539,7 +1791,7 @@ namespace UnrealBuildTool Text.AppendLine("\t " + Line); } } - Text.AppendLine("\t android:hardwareAccelerated=\"true\">"); + Text.AppendLine("\t android:hardwareAccelerated=\"true\">"); Text.AppendLine("\t android:hasCode=\"true\">"); if (bShowLaunchImage) { @@ -1625,7 +1877,10 @@ namespace UnrealBuildTool Text.AppendLine(string.Format("\t\t", bHasOBBFiles ? "true" : "false")); Text.AppendLine(string.Format("\t\t", Configuration)); Text.AppendLine(string.Format("\t\t", bUseExternalFilesDir ? "true" : "false")); - Text.AppendLine(string.Format("\t\t", bPackageForDaydream ? "true" : "false")); + if (bPackageForDaydream) + { + Text.AppendLine(string.Format("\t\t")); + } Text.AppendLine("\t\t"); Text.AppendLine("\t\t= 'A'; DriveLetter--) + { + UnusedDriveLetter = Char.ToString(DriveLetter) + ":"; + bFound = false; + for (int DriveIndex = AllDrives.Length-1; DriveIndex >= 0; DriveIndex--) + { + if (AllDrives[DriveIndex].Name.ToUpper().StartsWith(UnusedDriveLetter)) + { + bFound = true; + break; + } + } + if (!bFound) + { + break; + } + } + + if (bFound) + { + Log.TraceInformation("\nUnable to apply fixed ant.bat (all drive letters in use!)"); + return; + } + + Log.TraceInformation("\nPatching ant.bat to work around commandline length limit (using unused drive letter {0})", UnusedDriveLetter); + + if (!File.Exists(AntOrigBatFilename)) + { + // copy the existing ant.bat to ant.orig.bat + File.Copy(AntBatFilename, AntOrigBatFilename, true); + } + + // make sure ant.bat isn't read-only + FileAttributes Attribs = File.GetAttributes(AntBatFilename); + if (Attribs.HasFlag(FileAttributes.ReadOnly)) + { + File.SetAttributes(AntBatFilename, Attribs & ~FileAttributes.ReadOnly); + } + + // generate new ant.bat with an unused drive letter for subst + string AntBatText = + "@echo off\n" + + "setlocal\n" + + "set ANTPATH=%~dp0\n" + + "set ANT_CMD_LINE_ARGS=\n" + + ":setupArgs\n" + + "if \"\"%1\"\"==\"\"\"\" goto doneStart\n" + + "set ANT_CMD_LINE_ARGS=%ANT_CMD_LINE_ARGS% %1\n" + + "shift\n" + + "goto setupArgs\n\n" + + ":doneStart\n" + + "subst " + UnusedDriveLetter + " \"%CD%\"\n" + + "pushd " + UnusedDriveLetter + "\n" + + "call \"%ANTPATH%\\ant.orig.bat\" %ANT_CMD_LINE_ARGS%\n" + + "popd\n" + + "subst " + UnusedDriveLetter + " /d\n"; + + File.WriteAllText(AntBatFilename, AntBatText); + } + private void MakeApk(AndroidToolChain ToolChain, string ProjectName, string ProjectDirectory, string OutputPath, string EngineDirectory, bool bForDistribution, string CookFlavor, bool bMakeSeparateApks, bool bIncrementalPackage, bool bDisallowPackagingDataInApk, bool bDisallowExternalFilesDir) { - Log.TraceInformation("\n===={0}====PREPARING TO MAKE APK=================================================================", DateTime.Now.ToString()); + Log.TraceInformation("\n===={0}====PREPARING TO MAKE APK=================================================================", DateTime.Now.ToString()); + + // do this here so we'll stop early if there is a problem with the SDK API level (cached so later calls will return the same) + string SDKAPILevel = GetSdkApiLevel(ToolChain); + + PatchAntBatIfNeeded(); + + // make sure it is cached + string EngineVersion = ReadEngineVersion(EngineDirectory); // cache some tools paths string NDKBuildPath = Environment.ExpandEnvironmentVariables("%NDKROOT%/ndk-build" + (Utils.IsRunningOnMono ? "" : ".cmd")); @@ -2010,6 +2349,7 @@ namespace UnrealBuildTool // Sometimes old files get left behind if things change, so we'll do a clean up pass { string CleanUpBaseDir = Path.Combine(ProjectDirectory, "Build", "Android", "src"); + string ImmediateBaseDir = Path.Combine(UE4BuildPath, "src"); var files = Directory.EnumerateFiles(CleanUpBaseDir, "*.java", SearchOption.AllDirectories); Log.TraceInformation("Cleaning up files based on template dir {0}", TemplateDestinationBase); @@ -2034,30 +2374,58 @@ namespace UnrealBuildTool if (!cleanFiles.Contains(Path.GetFileName(filename))) continue; - Log.TraceInformation("Cleaning up file {0} with path {1}", filename, filePath); + Log.TraceInformation("Cleaning up file {0}", filename); + FileAttributes Attribs = File.GetAttributes(filename); + File.SetAttributes(filename, Attribs & ~FileAttributes.ReadOnly); File.Delete(filename); // Check to see if this file also exists in our target destination, and if so nuke it too - string DestFilename = Path.Combine(UE4BuildPath, Utils.MakePathRelativeTo(filePath, UE4BuildFilesPath)); - if (File.Exists(filename)) + string DestFilename = Path.Combine(ImmediateBaseDir, Utils.MakePathRelativeTo(filename, CleanUpBaseDir)); + if (File.Exists(DestFilename)) { - File.Delete(filename); + Log.TraceInformation("Cleaning up file {0}", DestFilename); + Attribs = File.GetAttributes(DestFilename); + File.SetAttributes(DestFilename, Attribs & ~FileAttributes.ReadOnly); + File.Delete(DestFilename); } } } - // Directory clean up code - var directories = Directory.EnumerateDirectories(CleanUpBaseDir, "*", SearchOption.AllDirectories).OrderByDescending(x => x); - foreach (var directory in directories) + // Directory clean up code (Build/Android/src) + try { - if (Directory.Exists(directory) && Directory.GetFiles(directory, "*.*", SearchOption.AllDirectories).Count() == 0) + var BaseDirectories = Directory.EnumerateDirectories(CleanUpBaseDir, "*", SearchOption.AllDirectories).OrderByDescending(x => x); + foreach (var directory in BaseDirectories) { - Log.TraceInformation("Cleaning Directory {0} as empty.", directory); - Directory.Delete(directory, true); + if (Directory.Exists(directory) && Directory.GetFiles(directory, "*.*", SearchOption.AllDirectories).Count() == 0) + { + Log.TraceInformation("Cleaning Directory {0} as empty.", directory); + Directory.Delete(directory, true); + } } - }; - + } + catch (Exception) + { + // likely System.IO.DirectoryNotFoundException, ignore it + } + // Directory clean up code (Intermediate/APK/src) + try + { + var ImmediateDirectories = Directory.EnumerateDirectories(ImmediateBaseDir, "*", SearchOption.AllDirectories).OrderByDescending(x => x); + foreach (var directory in ImmediateDirectories) + { + if (Directory.Exists(directory) && Directory.GetFiles(directory, "*.*", SearchOption.AllDirectories).Count() == 0) + { + Log.TraceInformation("Cleaning Directory {0} as empty.", directory); + Directory.Delete(directory, true); + } + } + } + catch (Exception) + { + // likely System.IO.DirectoryNotFoundException, ignore it + } } @@ -2081,6 +2449,12 @@ namespace UnrealBuildTool Log.TraceInformation("Application display name is different than last build, forcing repackage."); } + // Write Crashlytics data if enabled + if (CrashlyticsPluginEnabled) + { + WriteCrashlyticsResources(Path.Combine(ProjectDirectory, "Build", "Android"), PackageName, ApplicationDisplayName); + } + // if the manifest matches, look at other settings stored in a file if (bBuildSettingsMatch) { @@ -2410,25 +2784,34 @@ namespace UnrealBuildTool string ShellExecutable = Utils.IsRunningOnMono ? "/bin/sh" : "cmd.exe"; string ShellParametersBegin = Utils.IsRunningOnMono ? "-c '" : "/c "; string ShellParametersEnd = Utils.IsRunningOnMono ? "'" : ""; + bool AntSuccess = false; switch (AntVerbosity.ToLower()) { default: case "quiet": - if (RunCommandLineProgramAndReturnResult(UE4BuildPath, ShellExecutable, ShellParametersBegin + "\"" + GetAntPath() + "\" -quiet " + AntOptions + ShellParametersEnd, "Making .apk with Ant... (note: it's safe to ignore javac obsolete warnings)") != 0) + AntSuccess = (RunCommandLineProgramAndReturnResult(UE4BuildPath, ShellExecutable, ShellParametersBegin + "\"" + GetAntPath() + "\" -quiet " + AntOptions + ShellParametersEnd, "Making .apk with Ant... (note: it's safe to ignore javac obsolete warnings)") == 0); + if (!AntSuccess) { - RunCommandLineProgramAndReturnResult(UE4BuildPath, ShellExecutable, ShellParametersBegin + "\"" + GetAntPath() + "\" " + AntOptions + ShellParametersEnd, "Making .apk with Ant again to show errors"); + AntSuccess = (RunCommandLineProgramAndReturnResult(UE4BuildPath, ShellExecutable, ShellParametersBegin + "\"" + GetAntPath() + "\" " + AntOptions + ShellParametersEnd, "Making .apk with Ant again to show errors") == 0); } break; case "normal": - RunCommandLineProgramAndReturnResult(UE4BuildPath, ShellExecutable, ShellParametersBegin + "\"" + GetAntPath() + "\" " + AntOptions + ShellParametersEnd, "Making .apk with Ant again to show errors"); + AntSuccess = (RunCommandLineProgramAndReturnResult(UE4BuildPath, ShellExecutable, ShellParametersBegin + "\"" + GetAntPath() + "\" " + AntOptions + ShellParametersEnd, "Making .apk with Ant again to show errors") == 0); break; case "verbose": - RunCommandLineProgramAndReturnResult(UE4BuildPath, ShellExecutable, ShellParametersBegin + "\"" + GetAntPath() + "\" -verbose " + AntOptions + ShellParametersEnd, "Making .apk with Ant again to show errors"); + AntSuccess = (RunCommandLineProgramAndReturnResult(UE4BuildPath, ShellExecutable, ShellParametersBegin + "\"" + GetAntPath() + "\" -verbose " + AntOptions + ShellParametersEnd, "Making .apk with Ant again to show errors") == 0); break; } + // upload Crashlytics symbols if plugin enabled and using build machine + if (CrashlyticsPluginEnabled && AntSuccess && Environment.GetEnvironmentVariable("IsBuildMachine") == "1") + { + AntOptions = "crashlytics-upload-symbols"; + RunCommandLineProgramAndReturnResult(UE4BuildPath, ShellExecutable, ShellParametersBegin + "\"" + GetAntPath() + "\" " + AntOptions + ShellParametersEnd, "Uploading Crashlytics symbols"); + } + // make sure destination exists Directory.CreateDirectory(Path.GetDirectoryName(DestApkName)); @@ -2463,7 +2846,7 @@ namespace UnrealBuildTool if (string.IsNullOrEmpty(KeyAlias) || string.IsNullOrEmpty(KeyStore) || string.IsNullOrEmpty(KeyStorePassword)) { - throw new BuildException("DistributionSigning settings are not all set. Check the DistributionSettings section in the Andriod tab of Project Settings"); + throw new BuildException("DistributionSigning settings are not all set. Check the DistributionSettings section in the Android tab of Project Settings"); } string[] AntPropertiesLines = new string[4]; @@ -2512,9 +2895,9 @@ namespace UnrealBuildTool UnrealTargetPlatform Platform = InTarget.Platform; UnrealTargetConfiguration Configuration = InTarget.Configuration; string ProjectBaseName = Path.GetFileName(BaseSoName).Replace("-" + Platform, "").Replace("-" + Configuration, "").Replace(".so", ""); - string ReceiptFilename = TargetReceipt.GetDefaultPath(InTarget.ProjectDirectory.FullName, ProjectBaseName, Platform, Configuration, ""); + FileReference ReceiptFilename = TargetReceipt.GetDefaultPath(InTarget.ProjectDirectory, ProjectBaseName, Platform, Configuration, ""); Log.TraceInformation("Receipt Filename: {0}", ReceiptFilename); - SetAndroidPluginData(ToolChain.GetAllArchitectures(), CollectPluginDataPaths(TargetReceipt.Read(ReceiptFilename))); + SetAndroidPluginData(ToolChain.GetAllArchitectures(), CollectPluginDataPaths(TargetReceipt.Read(ReceiptFilename, UnrealBuildTool.EngineDirectory, InTarget.ProjectDirectory))); // make an apk at the end of compiling, so that we can run without packaging (debugger, cook on the fly, etc) string RelativeEnginePath = UnrealBuildTool.EngineDirectory.MakeRelativeTo(DirectoryReference.GetCurrentDirectory()); @@ -2547,14 +2930,14 @@ namespace UnrealBuildTool // return bSeparateApks; } - public bool PrepForUATPackageOrDeploy(FileReference ProjectFile, string ProjectName, string ProjectDirectory, string ExecutablePath, string EngineDirectory, bool bForDistribution, string CookFlavor, bool bIsDataDeploy) + public bool PrepForUATPackageOrDeploy(FileReference ProjectFile, string ProjectName, DirectoryReference ProjectDirectory, string ExecutablePath, string EngineDirectory, bool bForDistribution, string CookFlavor, bool bIsDataDeploy) { //Log.TraceInformation("$$$$$$$$$$$$$$ PrepForUATPackageOrDeploy $$$$$$$$$$$$$$$$$"); // note that we cannot allow the data packaged into the APK if we are doing something like Launch On that will not make an obb // file and instead pushes files directly via deploy AndroidToolChain ToolChain = new AndroidToolChain(ProjectFile, false, null, null); - MakeApk(ToolChain, ProjectName, ProjectDirectory, ExecutablePath, EngineDirectory, bForDistribution: bForDistribution, CookFlavor: CookFlavor, + MakeApk(ToolChain, ProjectName, ProjectDirectory.FullName, ExecutablePath, EngineDirectory, bForDistribution: bForDistribution, CookFlavor: CookFlavor, bMakeSeparateApks: ShouldMakeSeparateApks(), bIncrementalPackage: false, bDisallowPackagingDataInApk: bIsDataDeploy, bDisallowExternalFilesDir: !bForDistribution || bIsDataDeploy ); return true; } diff --git a/Engine/Source/Programs/UnrealBuildTool/Configuration/ModuleRules.cs b/Engine/Source/Programs/UnrealBuildTool/Configuration/ModuleRules.cs index dd4bdbaad581..4d2bc6d9d8d9 100644 --- a/Engine/Source/Programs/UnrealBuildTool/Configuration/ModuleRules.cs +++ b/Engine/Source/Programs/UnrealBuildTool/Configuration/ModuleRules.cs @@ -116,6 +116,58 @@ namespace UnrealBuildTool Any, } + /// + /// Information about a file which is required by the target at runtime, and must be moved around with it. + /// + [Serializable] + public class RuntimeDependency + { + /// + /// The file that should be staged. Should use $(EngineDir) and $(ProjectDir) variables as a root, so that the target can be relocated to different machines. + /// + public string Path; + + /// + /// How to stage this file. + /// + public StagedFileType Type; + + /// + /// Constructor + /// + /// Path to the runtime dependency + /// How to stage the given path + public RuntimeDependency(string InPath, StagedFileType InType = StagedFileType.NonUFS) + { + Path = InPath; + Type = InType; + } + } + + /// + /// List of runtime dependencies, with convenience methods for adding new items + /// + [Serializable] + public class RuntimeDependencyList : List + { + /// + /// Default constructor + /// + public RuntimeDependencyList() + { + } + + /// + /// Add a runtime dependency to the list + /// + /// Path to the runtime dependency. May include wildcards. + /// How to stage this file + public void Add(string InPath, StagedFileType InType) + { + Add(new RuntimeDependency(InPath, InType)); + } + } + /// /// Rules for the target that this module belongs to /// @@ -147,6 +199,11 @@ namespace UnrealBuildTool /// This should only be set for header files that are included by a significant number of other C++ modules. /// public string SharedPCHHeaderFile; + + /// + /// Specifies an alternate name for intermediate directories and files for intermediates of this module. Useful when hitting path length limitations. + /// + public string ShortName = null; /// /// Precompiled header usage for this module @@ -227,6 +284,11 @@ namespace UnrealBuildTool /// public bool bEnforceIWYU = true; + /// + /// Whether to add all the default include paths to the module (eg. the Source/Classes folder, subfolders under Source/Public). + /// + public bool bAddDefaultIncludePaths = true; + /// /// List of modules names (no path needed) with header files that our module's public headers needs access to, but we don't need to "import" or link against. /// @@ -341,6 +403,11 @@ namespace UnrealBuildTool /// public PrecompileTargetsType PrecompileForTargets = PrecompileTargetsType.Default; + /// + /// External files which invalidate the makefile if modified. Relative paths are resolved relative to the .build.cs file. + /// + public List ExternalDependencies = new List(); + /// /// Property for the directory containing this module. Useful for adding paths to third party dependencies. /// @@ -453,7 +520,7 @@ namespace UnrealBuildTool Definitions.Add("WITH_APEX=1"); Definitions.Add("WITH_APEX_CLOTHING=1"); Definitions.Add("WITH_CLOTH_COLLISION_DETECTION=1"); - Definitions.Add("WITH_PHYSICS_COOKING=1"); // APEX currently relies on cooking even at runtime + Definitions.Add("WITH_PHYSX_COOKING=1"); // APEX currently relies on cooking even at runtime } else @@ -461,7 +528,7 @@ namespace UnrealBuildTool Definitions.Add("WITH_APEX=0"); Definitions.Add("WITH_APEX_CLOTHING=0"); Definitions.Add("WITH_CLOTH_COLLISION_DETECTION=0"); - Definitions.Add(string.Format("WITH_PHYSICS_COOKING={0}", UEBuildConfiguration.bBuildEditor ? 1 : 0)); // without APEX, we only need cooking in editor builds + Definitions.Add(string.Format("WITH_PHYSX_COOKING={0}", UEBuildConfiguration.bBuildEditor ? 1 : 0)); // without APEX, we only need cooking in editor builds } if (Target.bCompileNvCloth == true) @@ -479,15 +546,6 @@ namespace UnrealBuildTool { Definitions.Add("WITH_NVCLOTH=0"); } - - if (Target.bRuntimePhysicsCooking == true) - { - Definitions.Add("WITH_RUNTIME_PHYSICS_COOKING=1"); - } - else - { - Definitions.Add("WITH_RUNTIME_PHYSICS_COOKING=0"); - } } /// diff --git a/Engine/Source/Programs/UnrealBuildTool/Configuration/TargetRules.cs b/Engine/Source/Programs/UnrealBuildTool/Configuration/TargetRules.cs index 1872842dd5cf..baf556fbf539 100644 --- a/Engine/Source/Programs/UnrealBuildTool/Configuration/TargetRules.cs +++ b/Engine/Source/Programs/UnrealBuildTool/Configuration/TargetRules.cs @@ -313,6 +313,11 @@ namespace UnrealBuildTool /// public string SolutionDirectory = String.Empty; + /// + /// Whether the target should be included in the default solution build configuration + /// + public bool? bBuildInSolutionByDefault = null; + /// /// Output the executable to the engine binaries folder. /// @@ -348,12 +353,7 @@ namespace UnrealBuildTool /// Whether to include NvCloth. /// public bool bCompileNvCloth = false; - - /// - /// Whether to allow runtime cooking of physics. - /// - public bool bRuntimePhysicsCooking = true; - + /// /// Whether to include Box2D support. /// @@ -423,10 +423,16 @@ namespace UnrealBuildTool [ConfigFile(ConfigHierarchyType.Engine, "/Script/BuildSettings.BuildSettings", "bCompileLeanAndMeanUE")] public bool bCompileLeanAndMeanUE = false; - /// - /// Enabled for all builds that include the engine project. Disabled only when building standalone apps that only link with Core. + /// + /// Whether to utilize cache freed OS allocs with MallocBinned /// - public bool bCompileAgainstEngine = true; + [ConfigFile(ConfigHierarchyType.Engine, "/Script/BuildSettings.BuildSettings", "bUseCacheFreedOSAllocs")] + public bool bUseCacheFreedOSAllocs = true; + + /// + /// Enabled for all builds that include the engine project. Disabled only when building standalone apps that only link with Core. + /// + public bool bCompileAgainstEngine = true; /// /// Enabled for all builds that include the CoreUObject project. Disabled only when building standalone apps that only link with Core. @@ -593,7 +599,7 @@ namespace UnrealBuildTool /// Disable optimization for files that are in the adaptive non-unity working set. /// [XmlConfigFile(Category = "BuildConfiguration")] - public bool bAdaptiveUnityDisablesOptimizations = false; + public bool bAdaptiveUnityDisablesOptimizations = true; /// /// Disables force-included PCHs for files that are in the adaptive non-unity working set. @@ -795,15 +801,6 @@ namespace UnrealBuildTool [XmlConfigFile(Category = "BuildConfiguration")] public bool bCreateMapFile = false; - /// - /// Enables code analysis mode. Currently, this has specific requirements. It only works on Windows - /// platform with the MSVC compiler. Also, it requires a version of the compiler that supports the - /// /analyze option, such as Visual Studio 2013. - /// - [CommandLine("-EnableCodeAnalysis")] - [XmlConfigFile(Category = "BuildConfiguration")] - public bool bEnableCodeAnalysis = false; - /// /// Bundle version for Mac apps. /// @@ -1463,6 +1460,11 @@ namespace UnrealBuildTool get { return Inner.SolutionDirectory; } } + public bool? bBuildInSolutionByDefault + { + get { return Inner.bBuildInSolutionByDefault; } + } + public bool bOutputToEngineBinaries { get { return Inner.bOutputToEngineBinaries; } @@ -1493,11 +1495,6 @@ namespace UnrealBuildTool get { return Inner.bCompileNvCloth; } } - public bool bRuntimePhysicsCooking - { - get { return Inner.bRuntimePhysicsCooking; } - } - public bool bCompileBox2D { get { return Inner.bCompileBox2D; } @@ -1558,7 +1555,12 @@ namespace UnrealBuildTool get { return Inner.bCompileLeanAndMeanUE; } } - public bool bCompileAgainstEngine + public bool bUseCacheFreedOSAllocs + { + get { return Inner.bUseCacheFreedOSAllocs; } + } + + public bool bCompileAgainstEngine { get { return Inner.bCompileAgainstEngine; } } @@ -1853,11 +1855,6 @@ namespace UnrealBuildTool get { return Inner.bCreateMapFile; } } - public bool bEnableCodeAnalysis - { - get { return Inner.bEnableCodeAnalysis; } - } - public string BundleVersion { get { return Inner.BundleVersion; } diff --git a/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildBinary.cs b/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildBinary.cs index 155655883608..b2b0166a2958 100644 --- a/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildBinary.cs +++ b/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildBinary.cs @@ -8,7 +8,6 @@ using System.IO; using System.Linq; using System.Xml; using System.Globalization; -using Tools.DotNETCommon.CaselessDictionary; namespace UnrealBuildTool { diff --git a/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildBinaryCPP.cs b/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildBinaryCPP.cs index 1e2815f49b55..17f65ef6ef06 100644 --- a/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildBinaryCPP.cs +++ b/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildBinaryCPP.cs @@ -230,7 +230,7 @@ namespace UnrealBuildTool List GameModules = new List(); foreach (UEBuildModule Module in Modules) { - if (!Module.ModuleDirectory.IsUnderDirectory(UnrealBuildTool.EngineDirectory)) + if (!UnrealBuildTool.IsUnderAnEngineDirectory(Module.ModuleDirectory)) { GameModules.Add(Module); } diff --git a/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildDeployTarget.cs b/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildDeployTarget.cs index 320a0a35e72b..025854e80098 100644 --- a/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildDeployTarget.cs +++ b/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildDeployTarget.cs @@ -80,7 +80,7 @@ namespace UnrealBuildTool /// /// Path to the generated build receipt. /// - public readonly string BuildReceiptFileName; + public readonly FileReference BuildReceiptFileName; /// /// Whether to output build products to the Engine/Binaries folder. @@ -109,7 +109,7 @@ namespace UnrealBuildTool public UEBuildDeployTarget(UEBuildTarget Target) { this.ProjectFile = Target.ProjectFile; - this.TargetFile = Target.TargetCsFilename; + this.TargetFile = Target.TargetRulesFile; this.AppName = Target.AppName; this.TargetName = Target.TargetName; this.TargetType = Target.TargetType; @@ -118,7 +118,7 @@ namespace UnrealBuildTool this.OutputPaths = new List(Target.OutputPaths); this.EngineIntermediateDirectory = Target.EngineIntermediateDirectory; this.ProjectDirectory = Target.ProjectDirectory; - this.BuildReceiptFileName = Target.BuildReceiptFileName; + this.BuildReceiptFileName = Target.ReceiptFileName; this.bOutputToEngineBinaries = Target.Rules.bOutputToEngineBinaries; this.bCreateStubIPA = Target.Rules.bCreateStubIPA; this.AndroidArchitectures = Target.Rules.AndroidPlatform.Architectures.ToArray(); @@ -143,7 +143,7 @@ namespace UnrealBuildTool OutputPaths = Reader.ReadList(x => x.ReadFileReference()); EngineIntermediateDirectory = Reader.ReadDirectoryReference(); ProjectDirectory = Reader.ReadDirectoryReference(); - BuildReceiptFileName = Reader.ReadString(); + BuildReceiptFileName = Reader.ReadFileReference(); bOutputToEngineBinaries = Reader.ReadBoolean(); bCreateStubIPA = Reader.ReadBoolean(); AndroidArchitectures = Reader.ReadArray(x => x.ReadString()); diff --git a/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildModule.cs b/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildModule.cs index a2d6b6d1d7ba..a212341a36c9 100644 --- a/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildModule.cs +++ b/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildModule.cs @@ -8,7 +8,6 @@ using System.IO; using System.Linq; using System.Text.RegularExpressions; using System.Xml; -using Tools.DotNETCommon.CaselessDictionary; namespace UnrealBuildTool { @@ -155,7 +154,7 @@ namespace UnrealBuildTool /// /// Files which this module depends on at runtime. /// - public RuntimeDependencyList RuntimeDependencies; + public List RuntimeDependencies; /// /// Set of all whitelisted restricted folder references @@ -170,7 +169,8 @@ namespace UnrealBuildTool /// Base directory for the module /// Rules for this module /// Path to the rules file - public UEBuildModule(string InName, UHTModuleType InType, DirectoryReference InModuleDirectory, ModuleRules InRules, FileReference InRulesFile) + /// List of runtime dependencies + public UEBuildModule(string InName, UHTModuleType InType, DirectoryReference InModuleDirectory, ModuleRules InRules, FileReference InRulesFile, List InRuntimeDependencies) { Name = InName; Type = InType; @@ -193,7 +193,7 @@ namespace UnrealBuildTool PublicAdditionalBundleResources = InRules.AdditionalBundleResources == null ? new HashSet() : new HashSet(InRules.AdditionalBundleResources); PublicDelayLoadDLLs = HashSetFromOptionalEnumerableStringParameter(InRules.PublicDelayLoadDLLs); PrivateIncludePaths = HashSetFromOptionalEnumerableStringParameter(InRules.PrivateIncludePaths); - RuntimeDependencies = (InRules.RuntimeDependencies == null) ? new RuntimeDependencyList() : new RuntimeDependencyList(InRules.RuntimeDependencies); + RuntimeDependencies = InRuntimeDependencies; IsRedistributableOverride = InRules.IsRedistributableOverride; WhitelistRestrictedFolders = new HashSet(InRules.WhitelistRestrictedFolders.Select(x => DirectoryReference.Combine(ModuleDirectory, x))); @@ -797,10 +797,10 @@ namespace UnrealBuildTool Writer.WriteArrayEnd(); Writer.WriteArrayStart("RuntimeDependencies"); - foreach(RuntimeDependency RuntimeDependency in Rules.RuntimeDependencies) + foreach(RuntimeDependency RuntimeDependency in RuntimeDependencies) { Writer.WriteObjectStart(); - Writer.WriteValue("Path", RuntimeDependency.Path); + Writer.WriteValue("Path", RuntimeDependency.Path.FullName); Writer.WriteValue("Type", RuntimeDependency.Type.ToString()); Writer.WriteObjectEnd(); } diff --git a/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildModuleCPP.cs b/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildModuleCPP.cs index 4f8688639c99..5cd41d1cc31b 100644 --- a/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildModuleCPP.cs +++ b/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildModuleCPP.cs @@ -18,7 +18,7 @@ namespace UnrealBuildTool public class BuildInfoClass { /// - /// The wildcard of the *.generated.cpp file which was generated for the module + /// The wildcard of the *.gen.cpp file which was generated for the module /// public readonly string FileWildcard; @@ -31,7 +31,7 @@ namespace UnrealBuildTool } /// - /// Information about how to build the .generated.cpp files. If this is null, then we're not building .generated.cpp files for this module. + /// Information about how to build the .gen.cpp files. If this is null, then we're not building .gen.cpp files for this module. /// public BuildInfoClass BuildInfo; @@ -42,7 +42,7 @@ namespace UnrealBuildTool } /// - /// Information about the .generated.cpp file. If this is null then this module doesn't have any UHT-produced code. + /// Information about the .gen.cpp file. If this is null then this module doesn't have any UHT-produced code. /// public AutoGenerateCppInfoClass AutoGenerateCppInfo = null; @@ -160,11 +160,11 @@ namespace UnrealBuildTool /// public bool bSkipDefinitionsForCompileEnvironment = false; - public int FindNumberOfGeneratedCppFiles() + public IEnumerable FindGeneratedCppFiles() { - return ((null == GeneratedCodeDirectory) || !DirectoryReference.Exists(GeneratedCodeDirectory)) ? 0 - : (DirectoryReference.EnumerateFiles(GeneratedCodeDirectory, "*.generated.*.cpp", SearchOption.AllDirectories).Count() - + DirectoryReference.EnumerateFiles(GeneratedCodeDirectory, "*.generated.cpp", SearchOption.AllDirectories).Count()); + return ((null == GeneratedCodeDirectory) || !DirectoryReference.Exists(GeneratedCodeDirectory)) + ? Enumerable.Empty() + : DirectoryReference.EnumerateFiles(GeneratedCodeDirectory, "*.gen.cpp", SearchOption.TopDirectoryOnly).Select((Dir) => Dir.FullName); } protected override void GetReferencedDirectories(HashSet Directories) @@ -285,14 +285,16 @@ namespace UnrealBuildTool IEnumerable InSourceFiles, ModuleRules InRules, bool bInBuildSourceFiles, - FileReference InRulesFile + FileReference InRulesFile, + List InRuntimeDependencies ) : base( InName, InType, InModuleDirectory, InRules, - InRulesFile + InRulesFile, + InRuntimeDependencies ) { GeneratedCodeDirectory = InGeneratedCodeDirectory; @@ -376,7 +378,7 @@ namespace UnrealBuildTool // Check to see if this is an Engine module (including program or plugin modules). That is, the module is located under the "Engine" folder bool IsPluginModule = (Target.ProjectFile != null && ModuleDirectory.IsUnderDirectory(DirectoryReference.Combine(Target.ProjectFile.Directory, "Plugins"))); - bool IsGameModule = !IsPluginModule && !ModuleDirectory.IsUnderDirectory(UnrealBuildTool.EngineDirectory); + bool IsGameModule = !IsPluginModule && !UnrealBuildTool.IsUnderAnEngineDirectory(ModuleDirectory); // Should we force a precompiled header to be generated for this module? Usually, we only bother with a // precompiled header if there are at least several source files in the module (after combining them for unity @@ -471,7 +473,7 @@ namespace UnrealBuildTool PrecompiledHeaderTemplate Template = SharedPCHs.FirstOrDefault(x => ReferencedModules.Contains(x.Module)); if(Template != null && Template.IsValidFor(CompileEnvironment)) { - PrecompiledHeaderInstance Instance = FindOrCreateSharedPCH(ToolChain, Template, ModuleCompileEnvironment.bOptimizeCode, ActionGraph); + PrecompiledHeaderInstance Instance = FindOrCreateSharedPCH(ToolChain, Template, ModuleCompileEnvironment.bOptimizeCode, ModuleCompileEnvironment.bUseRTTI, ActionGraph); FileReference PrivateDefinitionsFile = FileReference.Combine(CompileEnvironment.OutputDirectory, String.Format("Definitions.{0}.h", Name)); using (StringWriter Writer = new StringWriter()) @@ -480,7 +482,7 @@ namespace UnrealBuildTool Writer.WriteLine("#undef {0}", ModuleApiDefine); // Games may choose to use shared PCHs from the engine, so allow them to change the value of these macros - if(Type.IsGameModule()) + if(!IsEngineModule()) { Writer.WriteLine("#undef UE_IS_ENGINE_MODULE"); Writer.WriteLine("#undef DEPRECATED_FORGAME"); @@ -521,8 +523,8 @@ namespace UnrealBuildTool List CPPFilesToCompile = SourceFilesToBuild.CPPFiles; if (bModuleUsesUnityBuild) { - CPPFilesToCompile = Unity.GenerateUnityCPPs(Target, CPPFilesToCompile, CompileEnvironment, Name); - LinkInputFiles.AddRange(CompileUnityFilesWithToolChain(Target, ToolChain, CompileEnvironment, ModuleCompileEnvironment, CPPFilesToCompile, Name, ActionGraph).ObjectFiles); + CPPFilesToCompile = Unity.GenerateUnityCPPs(Target, CPPFilesToCompile, CompileEnvironment, Rules.ShortName ?? Name); + LinkInputFiles.AddRange(CompileUnityFilesWithToolChain(Target, ToolChain, CompileEnvironment, ModuleCompileEnvironment, CPPFilesToCompile, ActionGraph).ObjectFiles); } else { @@ -544,6 +546,7 @@ namespace UnrealBuildTool } // Compile all the generated files + List GeneratedFileItems = new List(); foreach (string GeneratedFilename in GeneratedFiles) { FileItem GeneratedCppFileItem = FileItem.GetItemByPath(GeneratedFilename); @@ -551,13 +554,23 @@ namespace UnrealBuildTool CachePCHUsageForModuleSourceFile(CompileEnvironment, GeneratedCppFileItem); // @todo ubtmake: Check for ALL other places where we might be injecting .cpp or .rc files for compiling without caching CachedCPPIncludeInfo first (anything platform specific?) - LinkInputFiles.AddRange(ToolChain.CompileCPPFiles(GeneratedCPPCompileEnvironment, new List { GeneratedCppFileItem }, Name, ActionGraph).ObjectFiles); + GeneratedFileItems.Add(GeneratedCppFileItem); + } + + if (bModuleUsesUnityBuild) + { + GeneratedFileItems = Unity.GenerateUnityCPPs(Target, GeneratedFileItems, GeneratedCPPCompileEnvironment, (Rules.ShortName ?? Name) + ".gen"); + LinkInputFiles.AddRange(CompileUnityFilesWithToolChain(Target, ToolChain, GeneratedCPPCompileEnvironment, ModuleCompileEnvironment, GeneratedFileItems, ActionGraph).ObjectFiles); + } + else + { + LinkInputFiles.AddRange(ToolChain.CompileCPPFiles(GeneratedCPPCompileEnvironment, GeneratedFileItems, Name, ActionGraph).ObjectFiles); } } } - // Compile C files directly. - LinkInputFiles.AddRange(ToolChain.CompileCPPFiles(CompileEnvironment, SourceFilesToBuild.CFiles, Name, ActionGraph).ObjectFiles); + // Compile C files directly. Do not use a PCH here, because a C++ PCH is not compatible with C source files. + LinkInputFiles.AddRange(ToolChain.CompileCPPFiles(ModuleCompileEnvironment, SourceFilesToBuild.CFiles, Name, ActionGraph).ObjectFiles); // Compile CC files directly. LinkInputFiles.AddRange(ToolChain.CompileCPPFiles(CompileEnvironment, SourceFilesToBuild.CCFiles, Name, ActionGraph).ObjectFiles); @@ -616,7 +629,7 @@ namespace UnrealBuildTool // Create the action to compile the PCH file. CPPOutput Output = ToolChain.CompileCPPFiles(CompileEnvironment, new List() { WrapperFile }, Name, ActionGraph); - return new PrecompiledHeaderInstance(WrapperFile, CompileEnvironment.bOptimizeCode, Output); + return new PrecompiledHeaderInstance(WrapperFile, CompileEnvironment.bOptimizeCode, CompileEnvironment.bUseRTTI, Output); } /// @@ -625,11 +638,12 @@ namespace UnrealBuildTool /// The toolchain being used to build this module /// The PCH template /// Whether optimization should be enabled for this PCH + /// Whether to enable RTTI for this PCH /// Graph containing build actions /// Instance of a PCH - public PrecompiledHeaderInstance FindOrCreateSharedPCH(UEToolChain ToolChain, PrecompiledHeaderTemplate Template, bool bOptimizeCode, ActionGraph ActionGraph) + public PrecompiledHeaderInstance FindOrCreateSharedPCH(UEToolChain ToolChain, PrecompiledHeaderTemplate Template, bool bOptimizeCode, bool bUseRTTI, ActionGraph ActionGraph) { - PrecompiledHeaderInstance Instance = Template.Instances.Find(x => x.bOptimizeCode == bOptimizeCode); + PrecompiledHeaderInstance Instance = Template.Instances.Find(x => x.bOptimizeCode == bOptimizeCode && x.bUseRTTI == bUseRTTI); if(Instance == null) { // Create a suffix to distinguish this shared PCH variant from any others. Currently only optimized and non-optimized shared PCHs are supported. @@ -645,6 +659,17 @@ namespace UnrealBuildTool Variant += ".NonOptimized"; } } + if(bUseRTTI != Template.BaseCompileEnvironment.bUseRTTI) + { + if (bUseRTTI) + { + Variant += ".RTTI"; + } + else + { + Variant += ".NonRTTI"; + } + } // Create the wrapper file, which sets all the definitions needed to compile it FileReference WrapperLocation = FileReference.Combine(Template.OutputDir, String.Format("SharedPCH.{0}{1}.h", Template.Module.Name, Variant)); @@ -657,10 +682,11 @@ namespace UnrealBuildTool CompileEnvironment.PrecompiledHeaderIncludeFilename = WrapperFile.Reference; CompileEnvironment.OutputDirectory = Template.OutputDir; CompileEnvironment.bOptimizeCode = bOptimizeCode; + CompileEnvironment.bUseRTTI = bUseRTTI; // Create the PCH CPPOutput Output = ToolChain.CompileCPPFiles(CompileEnvironment, new List() { WrapperFile }, "Shared", ActionGraph); - Instance = new PrecompiledHeaderInstance(WrapperFile, bOptimizeCode, Output); + Instance = new PrecompiledHeaderInstance(WrapperFile, bOptimizeCode, bUseRTTI, Output); Template.Instances.Add(Instance); } return Instance; @@ -669,7 +695,7 @@ namespace UnrealBuildTool /// /// Compiles the provided CPP unity files. Will /// - private CPPOutput CompileUnityFilesWithToolChain(ReadOnlyTargetRules Target, UEToolChain ToolChain, CppCompileEnvironment CompileEnvironment, CppCompileEnvironment ModuleCompileEnvironment, List SourceFiles, string ModuleName, ActionGraph ActionGraph) + private CPPOutput CompileUnityFilesWithToolChain(ReadOnlyTargetRules Target, UEToolChain ToolChain, CppCompileEnvironment CompileEnvironment, CppCompileEnvironment ModuleCompileEnvironment, List SourceFiles, ActionGraph ActionGraph) { List NormalFiles = new List(); List AdaptiveFiles = new List(); @@ -712,7 +738,7 @@ namespace UnrealBuildTool AdaptiveUnityEnvironment.bOptimizeCode = false; } AdaptiveUnityEnvironment.PrecompiledHeaderAction = PrecompiledHeaderAction.None; - Console.WriteLine("Compiling {0} without PCH", String.Join(", ", AdaptiveFiles.Select(x => x.AbsolutePath))); + // Compile the files CPPOutput AdaptiveOutput = ToolChain.CompileCPPFiles(AdaptiveUnityEnvironment, AdaptiveFiles, Name, ActionGraph); @@ -943,7 +969,7 @@ namespace UnrealBuildTool // Bail out and let the user know which source files may need to be fixed up throw new BuildException( - "All source files in module \"{0}\" must include the same precompiled header first. Currently \"{1}\" is included by most of the source files. The following source files are not including \"{1}\" as their first include:\n\n{2}", + "All source files in module \"{0}\" must include the same precompiled header first. Currently \"{1}\" is included by most of the source files. The following source files are not including \"{1}\" as their first include:\n\n{2}\n\nTo compile this module without implicit precompiled headers, add \"PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;\" to {0}.build.cs.", Name, MostFilesAreIncludingPCH, FilesNotIncludingBestPCH); @@ -1009,6 +1035,16 @@ namespace UnrealBuildTool } } + /// + /// Determines whether the current module is an engine module, as opposed to a target-specific module + /// + /// True if it is an engine module, false otherwise + public bool IsEngineModule() + { + return UnrealBuildTool.IsUnderAnEngineDirectory(ModuleDirectory) && !ModuleDirectory.IsUnderDirectory(UnrealBuildTool.EngineSourceProgramsDirectory) && Name != "UE4Game" && + !ModuleDirectory.IsUnderDirectory(DirectoryReference.Combine(UnrealBuildTool.EnterpriseSourceDirectory, "Programs")); + } + /// /// Creates a compile environment from a base environment based on the module settings. /// @@ -1027,7 +1063,7 @@ namespace UnrealBuildTool } // Check if this is an engine module - bool bIsEngineModule = ModuleDirectory.IsUnderDirectory(UnrealBuildTool.EngineDirectory); + bool bIsEngineModule = IsEngineModule(); // Override compile environment Result.bFasterWithoutUnity = Rules.bFasterWithoutUnity; @@ -1042,7 +1078,7 @@ namespace UnrealBuildTool Result.bEnableShadowVariableWarnings = Rules.bEnableShadowVariableWarnings; Result.bEnableUndefinedIdentifierWarnings = Rules.bEnableUndefinedIdentifierWarnings; Result.bUseStaticCRT = Target.bUseStaticCRT; - Result.OutputDirectory = DirectoryReference.Combine(Binary.Config.IntermediateDirectory, Name); + Result.OutputDirectory = DirectoryReference.Combine(Binary.Config.IntermediateDirectory, Rules.ShortName ?? Name); Result.PCHOutputDirectory = (Result.PCHOutputDirectory == null)? null : DirectoryReference.Combine(Result.PCHOutputDirectory, Name); // Set the macro used to check whether monolithic headers can be used @@ -1074,6 +1110,16 @@ namespace UnrealBuildTool } } + // For game modules, set the define for the project name. This will be used by the IMPLEMENT_PRIMARY_GAME_MODULE macro. + if (!bIsEngineModule) + { + if (Target.ProjectFile != null) + { + string ProjectName = Target.ProjectFile.GetFileNameWithoutExtension(); + Result.Definitions.Add(String.Format("UE_PROJECT_NAME={0}", ProjectName)); + } + } + // Add the module's private definitions. Result.Definitions.AddRange(Definitions); @@ -1101,7 +1147,7 @@ namespace UnrealBuildTool CppCompileEnvironment CompileEnvironment = new CppCompileEnvironment(BaseCompileEnvironment); // Use the default optimization setting for - bool bIsEngineModule = ModuleDirectory.IsUnderDirectory(UnrealBuildTool.EngineDirectory); + bool bIsEngineModule = IsEngineModule(); CompileEnvironment.bOptimizeCode = ShouldEnableOptimization(ModuleRules.CodeOptimization.Default, Target.Configuration, bIsEngineModule); // Override compile environment @@ -1179,14 +1225,37 @@ namespace UnrealBuildTool { if (UHTModuleInfoCache == null) { - IEnumerable HeaderFilenames = Directory.GetFiles(ModuleDirectory.FullName, "*.h", SearchOption.AllDirectories); - UHTModuleInfo Info = ExternalExecution.CreateUHTModuleInfo(HeaderFilenames, Name, ModuleDirectory, Type, GeneratedCodeVersion); + List HeaderFiles = new List(); + FileSystemName[] ExcludedFolders = UEBuildPlatform.GetBuildPlatform(Rules.Target.Platform, true).GetExcludedFolderNames(); + FindHeaders(new DirectoryInfo(ModuleDirectory.FullName), ExcludedFolders, HeaderFiles); + UHTModuleInfo Info = ExternalExecution.CreateUHTModuleInfo(HeaderFiles, Name, ModuleDirectory, Type, GeneratedCodeVersion); UHTModuleInfoCache = new UHTModuleInfoCacheType(Info.PublicUObjectHeaders.Concat(Info.PublicUObjectClassesHeaders).Concat(Info.PrivateUObjectHeaders).Select(x => x.AbsolutePath).ToList(), Info); } return UHTModuleInfoCache; } + /// + /// Find all the headers under the given base directory, excluding any other platform folders. + /// + /// Base directory to search + /// Array of folders to exclude + /// Receives the list of headers that was found + static void FindHeaders(DirectoryInfo BaseDir, FileSystemName[] ExcludeFolders, List Headers) + { + if (!ExcludeFolders.Any(x => x.DisplayName.Equals(BaseDir.Name, StringComparison.InvariantCultureIgnoreCase))) + { + foreach (DirectoryInfo SubDir in BaseDir.EnumerateDirectories()) + { + FindHeaders(SubDir, ExcludeFolders, Headers); + } + foreach (FileInfo File in BaseDir.EnumerateFiles("*.h")) + { + Headers.Add(new FileReference(File)); + } + } + } + public override void GetAllDependencyModules(List ReferencedModules, HashSet IgnoreReferencedModules, bool bIncludeDynamicallyLoaded, bool bForceCircular, bool bOnlyDirectDependencies) { List AllDependencyModules = new List(); diff --git a/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildModuleExternal.cs b/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildModuleExternal.cs index d149d3d2dac4..bd87b40d2cbf 100644 --- a/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildModuleExternal.cs +++ b/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildModuleExternal.cs @@ -16,14 +16,16 @@ namespace UnrealBuildTool string InName, DirectoryReference InModuleDirectory, ModuleRules InRules, - FileReference InRulesFile + FileReference InRulesFile, + List InRuntimeDependencies ) : base( InType: InType, InName: InName, InModuleDirectory: InModuleDirectory, InRules: InRules, - InRulesFile: InRulesFile + InRulesFile: InRulesFile, + InRuntimeDependencies: InRuntimeDependencies ) { } diff --git a/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildPlugin.cs b/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildPlugin.cs new file mode 100644 index 000000000000..debec220b95c --- /dev/null +++ b/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildPlugin.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace UnrealBuildTool +{ + /// + /// Stores information about a plugin that is being built for a target + /// + class UEBuildPlugin + { + /// + /// Information about the plugin + /// + public PluginInfo Info; + + /// + /// Modules that this plugin belongs to + /// + public List Modules = new List(); + + /// + /// Recursive + /// + public HashSet Dependencies; + + /// + /// Whether the descriptor for this plugin is needed at runtime; because it has modules or content which is used, or because it references another module that does. + /// + public bool bDescriptorNeededAtRuntime; + + /// + /// Whether this descriptor is referenced non-optionally by something else; a project file or other plugin. This is recursively applied to the plugin's references. + /// + public bool bDescriptorReferencedExplicitly; + + /// + /// Constructor + /// + /// The static plugin information + public UEBuildPlugin(PluginInfo Info) + { + this.Info = Info; + } + + /// + /// Accessor for the name of this plugin + /// + public string Name + { + get { return Info.Name; } + } + + /// + /// Accessor for the file for this plugin + /// + public FileReference File + { + get { return Info.File; } + } + + /// + /// Accessor for this plugin's root directory + /// + public DirectoryReference Directory + { + get { return Info.Directory; } + } + + /// + /// Accessor for this plugin's descriptor + /// + public PluginDescriptor Descriptor + { + get { return Info.Descriptor; } + } + + /// + /// Returns the name of this plugin for debugging + /// + /// Name of the plugin + public override string ToString() + { + return Info.Name; + } + } +} diff --git a/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildTarget.cs b/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildTarget.cs index e7ba1654e971..3a419f447377 100644 --- a/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildTarget.cs +++ b/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildTarget.cs @@ -8,7 +8,6 @@ using System.Diagnostics; using System.IO; using System.Xml; using System.Runtime.Serialization; -using Tools.DotNETCommon.CaselessDictionary; using System.Text.RegularExpressions; namespace UnrealBuildTool @@ -283,6 +282,7 @@ namespace UnrealBuildTool { BuildCsFilename = Info.GetString("bf"); ModuleSourceFolder = (DirectoryReference)Info.GetValue("mf", typeof(DirectoryReference)); + ExternalDependencies = (List)Info.GetValue("ed", typeof(List)); UHTHeaderNames = (List)Info.GetValue("hn", typeof(List)); } @@ -290,16 +290,19 @@ namespace UnrealBuildTool { Info.AddValue("bf", BuildCsFilename); Info.AddValue("mf", ModuleSourceFolder); + Info.AddValue("ed", ExternalDependencies); Info.AddValue("hn", UHTHeaderNames); } - public FlatModuleCsDataType(string InBuildCsFilename) + public FlatModuleCsDataType(string InBuildCsFilename, IEnumerable InExternalDependencies) { BuildCsFilename = InBuildCsFilename; + ExternalDependencies = new List(InExternalDependencies); } public string BuildCsFilename; public DirectoryReference ModuleSourceFolder; + public List ExternalDependencies; public List UHTHeaderNames = new List(); } @@ -687,6 +690,17 @@ namespace UnrealBuildTool else { RulesAssembly = RulesCompiler.CreateEngineRulesAssembly(); + + if (RulesAssembly.GetTargetFileName(Desc.TargetName) == null) + { + // Target isn't part of the engine assembly, try the enterprise assembly + RulesAssembly EnterpriseRulesAssembly = RulesCompiler.CreateEnterpriseRulesAssembly(); + + if (EnterpriseRulesAssembly != null) + { + RulesAssembly = EnterpriseRulesAssembly; + } + } } if (Desc.ForeignPlugins != null) { @@ -780,12 +794,6 @@ namespace UnrealBuildTool } } - // If we're running static analysis, don't try to link anything. - if(RulesObject.bEnableCodeAnalysis) - { - RulesObject.bDisableLinking = true; - } - // If we're compiling just a single file, we need to prevent unity builds from running if(bCompilingSingleFile) { @@ -1090,29 +1098,23 @@ namespace UnrealBuildTool /// public bool bUsePrecompiled; - /// - /// All plugins which are valid for this target - /// - [NonSerialized] - public List ValidPlugins; - /// /// All plugins which are built for this target /// [NonSerialized] - public List BuildPlugins; + public List BuildPlugins; /// /// All plugin dependencies for this target. This differs from the list of plugins that is built for Launcher, where we build everything, but link in only the enabled plugins. /// [NonSerialized] - public List EnabledPlugins; + public List EnabledPlugins; /// - /// Additional plugin filenames which are foreign to this target + /// All plugins which should be precompiled for this target /// [NonSerialized] - public List UnrealHeaderToolPlugins; + public List PrecompilePlugins; /// /// Additional plugin filenames to include when building UnrealHeaderTool for the current target @@ -1156,24 +1158,30 @@ namespace UnrealBuildTool /// Used to keep track of all modules by name. /// [NonSerialized] - private Dictionary Modules = new CaselessDictionary(); + private Dictionary Modules = new Dictionary(StringComparer.InvariantCultureIgnoreCase); /// /// Used to map names of modules to their .Build.cs filename /// - public CaselessDictionary FlatModuleCsData = new CaselessDictionary(); + public Dictionary FlatModuleCsData = new Dictionary(StringComparer.InvariantCultureIgnoreCase); /// /// The receipt for this target, which contains a record of this build. /// - private TargetReceipt Receipt; - public TargetReceipt BuildReceipt { get { return Receipt; } } + public TargetReceipt Receipt + { + get; + private set; + } /// /// Filename for the receipt for this target. /// - private string ReceiptFileName; - public string BuildReceiptFileName { get { return ReceiptFileName; } } + public FileReference ReceiptFileName + { + get; + private set; + } /// /// Version manifests to be written to each output folder @@ -1189,8 +1197,7 @@ namespace UnrealBuildTool /// /// The name of the .Target.cs file, if the target was created with one /// - private readonly FileReference TargetCsFilenameField; - public FileReference TargetCsFilename { get { return TargetCsFilenameField; } } + public readonly FileReference TargetRulesFile; /// /// List of scripts to run before building @@ -1264,9 +1271,9 @@ namespace UnrealBuildTool FlatModuleCsData.Add(FlatModuleCsDataKeys[Index], FlatModuleCsDataValues[Index]); } Receipt = (TargetReceipt)Info.GetValue("re", typeof(TargetReceipt)); - ReceiptFileName = Info.GetString("rf"); + ReceiptFileName = (FileReference)Info.GetValue("rf", typeof(FileReference)); FileReferenceToVersionManifestPairs = (KeyValuePair[])Info.GetValue("vm", typeof(KeyValuePair[])); - TargetCsFilenameField = (FileReference)Info.GetValue("tc", typeof(FileReference)); + TargetRulesFile = (FileReference)Info.GetValue("tc", typeof(FileReference)); PreBuildStepScripts = (FileReference[])Info.GetValue("pr", typeof(FileReference[])); PostBuildStepScripts = (FileReference[])Info.GetValue("po", typeof(FileReference[])); DeployTargetFile = (FileReference)Info.GetValue("dt", typeof(FileReference)); @@ -1300,7 +1307,7 @@ namespace UnrealBuildTool Info.AddValue("re", Receipt); Info.AddValue("rf", ReceiptFileName); Info.AddValue("vm", FileReferenceToVersionManifestPairs); - Info.AddValue("tc", TargetCsFilenameField); + Info.AddValue("tc", TargetRulesFile); Info.AddValue("pr", PreBuildStepScripts); Info.AddValue("po", PostBuildStepScripts); Info.AddValue("dt", DeployTargetFile); @@ -1334,7 +1341,7 @@ namespace UnrealBuildTool PlatformIntermediateFolder = Path.Combine("Intermediate", "Build", Platform.ToString(), UEBuildPlatform.GetBuildPlatform(Platform).GetFolderNameForArchitecture(Architecture)); Debug.Assert(InTargetCsFilename == null || InTargetCsFilename.HasExtension(".Target.cs")); - TargetCsFilenameField = InTargetCsFilename; + TargetRulesFile = InTargetCsFilename; bCompileMonolithic = (Rules.LinkType == TargetLinkType.Monolithic); @@ -1375,7 +1382,14 @@ namespace UnrealBuildTool } else { - ProjectDirectory = UnrealBuildTool.EngineDirectory; + if (InTargetCsFilename.IsUnderDirectory(UnrealBuildTool.EnterpriseDirectory)) + { + ProjectDirectory = UnrealBuildTool.EnterpriseDirectory; + } + else + { + ProjectDirectory = UnrealBuildTool.EngineDirectory; + } } // Build the project intermediate directory @@ -1402,7 +1416,7 @@ namespace UnrealBuildTool } // Get the receipt path for this target - ReceiptFileName = TargetReceipt.GetDefaultPath(ProjectDirectory.FullName, TargetName, Platform, Configuration, Architecture); + ReceiptFileName = TargetReceipt.GetDefaultPath(ProjectDirectory, TargetName, Platform, Configuration, Architecture); // Read the project descriptor if (ProjectFile != null) @@ -1532,11 +1546,10 @@ namespace UnrealBuildTool // Expand all the paths in the receipt; they'll currently use variables for the engine and project directories TargetReceipt ReceiptWithFullPaths; - if (!TargetReceipt.TryRead(ReceiptFileName, out ReceiptWithFullPaths)) + if (!TargetReceipt.TryRead(ReceiptFileName, UnrealBuildTool.EngineDirectory, ProjectDirectory, out ReceiptWithFullPaths)) { - ReceiptWithFullPaths = new TargetReceipt(Receipt); + ReceiptWithFullPaths = (Receipt == null)? new TargetReceipt() : new TargetReceipt(Receipt); } - ReceiptWithFullPaths.ExpandPathVariables(UnrealBuildTool.EngineDirectory, ProjectDirectory); // Collect all files to delete. HashSet FilesToDelete = new HashSet(); @@ -1546,13 +1559,13 @@ namespace UnrealBuildTool // Don't delete executable binaries when we're hot-reloading. They may be in use. if(!bHotReloadFromIDE || (BuildProduct.Type != BuildProductType.Executable && BuildProduct.Type != BuildProductType.DynamicLibrary)) { - FilesToDelete.Add(new FileReference(BuildProduct.Path)); + FilesToDelete.Add(BuildProduct.Path); } } if (OnlyModules.Count == 0) { - FilesToDelete.Add(new FileReference(ReceiptFileName)); + FilesToDelete.Add(ReceiptFileName); } FilesToDelete.Add(FlatCPPIncludeDependencyCache.GetDependencyCachePathForTarget(this)); @@ -1612,17 +1625,10 @@ namespace UnrealBuildTool // Read the existing receipt from disk TargetReceipt OldReceipt; - if (TargetReceipt.TryRead(ReceiptFileName, out OldReceipt)) + if (TargetReceipt.TryRead(ReceiptFileName, UnrealBuildTool.EngineDirectory, ProjectDirectory, out OldReceipt)) { - OldReceipt.ExpandPathVariables(UnrealBuildTool.EngineDirectory, ProjectDirectory); - - // Expand all the paths in the new receipt - TargetReceipt NewReceipt= new TargetReceipt(Receipt); - NewReceipt.ExpandPathVariables(UnrealBuildTool.EngineDirectory, ProjectDirectory); - - // Intersect the two sets of paths - FilesToDelete.UnionWith(OldReceipt.BuildProducts.Select(x => new FileReference(x.Path))); - FilesToDelete.ExceptWith(NewReceipt.BuildProducts.Select(x => new FileReference(x.Path))); + FilesToDelete.UnionWith(OldReceipt.BuildProducts.Select(x => x.Path)); + FilesToDelete.ExceptWith(Receipt.BuildProducts.Select(x => x.Path)); } // The engine updates the PATH environment variable to supply all valid locations for DLLs, but the Windows loader reads imported DLLs from the first location it finds them. @@ -1856,29 +1862,26 @@ namespace UnrealBuildTool BuildManifest Manifest = new BuildManifest(); - if(!Rules.bEnableCodeAnalysis && !Rules.bDisableLinking) + if(!Rules.bDisableLinking) { // Expand all the paths in the receipt; they'll currently use variables for the engine and project directories - TargetReceipt ReceiptWithFullPaths = new TargetReceipt(Receipt); - ReceiptWithFullPaths.ExpandPathVariables(UnrealBuildTool.EngineDirectory, ProjectDirectory); - - foreach (BuildProduct BuildProduct in ReceiptWithFullPaths.BuildProducts) + foreach (BuildProduct BuildProduct in Receipt.BuildProducts) { // Don't add static libraries into the manifest unless we're explicitly building them; we don't submit them to Perforce. if (!bPrecompile && (BuildProduct.Type == BuildProductType.StaticLibrary || BuildProduct.Type == BuildProductType.ImportLibrary)) { - Manifest.LibraryBuildProducts.Add(BuildProduct.Path); + Manifest.LibraryBuildProducts.Add(BuildProduct.Path.FullName); } else { - Manifest.AddBuildProduct(BuildProduct.Path); + Manifest.AddBuildProduct(BuildProduct.Path.FullName); } } UEBuildPlatform BuildPlatform = UEBuildPlatform.GetBuildPlatform(Platform); if (OnlyModules.Count == 0) { - Manifest.AddBuildProduct(ReceiptFileName); + Manifest.AddBuildProduct(ReceiptFileName.FullName); } if(DeployTargetFile != null) @@ -1924,8 +1927,7 @@ namespace UnrealBuildTool // Add them to the receipt foreach (KeyValuePair BuildProductPair in BuildProducts) { - string NormalizedPath = TargetReceipt.InsertPathVariables(BuildProductPair.Key, UnrealBuildTool.EngineDirectory, ProjectDirectory); - BuildProduct BuildProduct = Receipt.AddBuildProduct(NormalizedPath, BuildProductPair.Value); + BuildProduct BuildProduct = Receipt.AddBuildProduct(BuildProductPair.Key, BuildProductPair.Value); BuildProduct.IsPrecompiled = !Binary.Config.bAllowCompilation; } } @@ -1933,31 +1935,32 @@ namespace UnrealBuildTool // Add the project file if(ProjectFile != null) { - string NormalizedPath = TargetReceipt.InsertPathVariables(ProjectFile, UnrealBuildTool.EngineDirectory, ProjectDirectory); - Receipt.RuntimeDependencies.Add(NormalizedPath, StagedFileType.UFS); + Receipt.RuntimeDependencies.Add(ProjectFile, StagedFileType.UFS); } // Add the descriptors for all enabled plugins - foreach(PluginInfo EnabledPlugin in EnabledPlugins) + foreach(UEBuildPlugin EnabledPlugin in EnabledPlugins) { - string SourcePath = TargetReceipt.InsertPathVariables(EnabledPlugin.File, UnrealBuildTool.EngineDirectory, ProjectDirectory); - Receipt.RuntimeDependencies.Add(SourcePath, StagedFileType.UFS); + if(EnabledPlugin.bDescriptorNeededAtRuntime || EnabledPlugin.bDescriptorReferencedExplicitly) + { + Receipt.RuntimeDependencies.Add(EnabledPlugin.File, StagedFileType.UFS); + } } // Add slate runtime dependencies if (Rules.bUsesSlate) { - Receipt.RuntimeDependencies.Add("$(EngineDir)/Content/Slate/...", StagedFileType.UFS); + AddRuntimeDependenciesFromDir(DirectoryReference.Combine(UnrealBuildTool.EngineDirectory, "Content", "Slate"), StagedFileType.UFS); if (Configuration != UnrealTargetConfiguration.Shipping) { - Receipt.RuntimeDependencies.Add("$(EngineDir)/Content/SlateDebug/...", StagedFileType.UFS); + AddRuntimeDependenciesFromDir(DirectoryReference.Combine(UnrealBuildTool.EngineDirectory, "Content", "SlateDebug"), StagedFileType.UFS); } if (ProjectFile != null) { - Receipt.RuntimeDependencies.Add("$(ProjectDir)/Content/Slate/...", StagedFileType.UFS); + AddRuntimeDependenciesFromDir(DirectoryReference.Combine(ProjectDirectory, "Content", "Slate"), StagedFileType.UFS); if (Configuration != UnrealTargetConfiguration.Shipping) { - Receipt.RuntimeDependencies.Add("$(EngineDir)/Content/SlateDebug/...", StagedFileType.UFS); + AddRuntimeDependenciesFromDir(DirectoryReference.Combine(ProjectDirectory, "Content", "SlateDebug"), StagedFileType.UFS); } } } @@ -1974,8 +1977,7 @@ namespace UnrealBuildTool { foreach (RuntimeDependency RuntimeDependency in Module.RuntimeDependencies) { - string SourcePath = TargetReceipt.InsertPathVariables(RuntimeDependency.Path, UnrealBuildTool.EngineDirectory, ProjectDirectory); - Receipt.RuntimeDependencies.Add(SourcePath, RuntimeDependency.Type); + Receipt.RuntimeDependencies.Add(RuntimeDependency.Path, RuntimeDependency.Type); } Receipt.AdditionalProperties.AddRange(Module.Rules.AdditionalPropertiesForReceipt); } @@ -1997,12 +1999,7 @@ namespace UnrealBuildTool { foreach (RuntimeDependency RuntimeDependency in Module.RuntimeDependencies) { - // Ignore project-relative dependencies when we're compiling targets without projects - we won't be able to resolve them. - if(ProjectFile != null || RuntimeDependency.Path.IndexOf("$(ProjectDir)", StringComparison.InvariantCultureIgnoreCase) == -1) - { - string SourcePath = TargetReceipt.InsertPathVariables(RuntimeDependency.Path, UnrealBuildTool.EngineDirectory, ProjectDirectory); - Receipt.PrecompiledRuntimeDependencies.Add(SourcePath); - } + Receipt.PrecompiledRuntimeDependencies.Add(RuntimeDependency.Path); } } } @@ -2018,16 +2015,14 @@ namespace UnrealBuildTool { if(ExternalFile.IsUnderDirectory(UnrealBuildTool.EngineDirectory) || ExternalFile.IsUnderDirectory(ProjectDirectory)) { - string VariablePath = TargetReceipt.InsertPathVariables(ExternalFile, UnrealBuildTool.EngineDirectory, ProjectDirectory); - Receipt.PrecompiledBuildDependencies.Add(VariablePath); + Receipt.PrecompiledBuildDependencies.Add(ExternalFile); } } // Also add the Shared Build Id File if it's been specified if (SharedBuildIdFile != null) { - string VariablePath = TargetReceipt.InsertPathVariables(SharedBuildIdFile, UnrealBuildTool.EngineDirectory, ProjectDirectory); - Receipt.BuildProducts.Add(new BuildProduct(VariablePath, BuildProductType.BuildResource)); + Receipt.BuildProducts.Add(new BuildProduct(SharedBuildIdFile, BuildProductType.BuildResource)); } } @@ -2079,8 +2074,23 @@ namespace UnrealBuildTool // Add all the version manifests to the receipt foreach(FileReference VersionManifestFile in FileNameToVersionManifest.Keys) { - string VariablePath = TargetReceipt.InsertPathVariables(VersionManifestFile.FullName, UnrealBuildTool.EngineDirectory, ProjectDirectory); - Receipt.AddBuildProduct(VariablePath, BuildProductType.RequiredResource); + Receipt.AddBuildProduct(VersionManifestFile, BuildProductType.RequiredResource); + } + } + + /// + /// Add the contents of a directory as runtime dependencies + /// + /// The base directory to enumerate files from + /// How the file should be staged + void AddRuntimeDependenciesFromDir(DirectoryReference BaseDir, StagedFileType Type) + { + if (DirectoryReference.Exists(BaseDir)) + { + foreach (FileReference File in DirectoryReference.EnumerateFiles(BaseDir, "*", SearchOption.AllDirectories)) + { + Receipt.RuntimeDependencies.Add(File, Type); + } } } @@ -2191,13 +2201,13 @@ namespace UnrealBuildTool UEBuildPlatform BuildPlatform = UEBuildPlatform.GetBuildPlatform(Platform); if (OnlyModules == null || OnlyModules.Count == 0) { - Directory.CreateDirectory(Path.GetDirectoryName(ReceiptFileName)); - Receipt.Write(ReceiptFileName); + DirectoryReference.CreateDirectory(ReceiptFileName.Directory); + Receipt.Write(ReceiptFileName, UnrealBuildTool.EngineDirectory, ProjectDirectory); } if (ForceReceiptFileName != null) { Directory.CreateDirectory(Path.GetDirectoryName(ForceReceiptFileName)); - Receipt.Write(ForceReceiptFileName); + Receipt.Write(new FileReference(ForceReceiptFileName), UnrealBuildTool.EngineDirectory, ProjectDirectory); } if(SharedBuildIdFile != null && (!FileReference.Exists(SharedBuildIdFile) || File.ReadAllText(SharedBuildIdFile.FullName) != Receipt.BuildId)) { @@ -2263,6 +2273,9 @@ namespace UnrealBuildTool PreBuildSetup(TargetToolChain, GlobalCompileEnvironment, GlobalLinkEnvironment); + // Save off the original list of binaries. We'll use this to figure out which PCHs to create later, to avoid switching PCHs when compiling single modules. + List OriginalBinaries = AppBinaries; + // If we're building a single module, then find the binary for that module and add it to our target if (OnlyModules.Count > 0) { @@ -2355,22 +2368,71 @@ namespace UnrealBuildTool // Check for linking against modules prohibited by the EULA CheckForEULAViolation(); + // Build a mapping from module to its plugin + Dictionary ModuleToPlugin = new Dictionary(); + foreach(UEBuildPlugin Plugin in BuildPlugins) + { + foreach(UEBuildModule Module in Plugin.Modules) + { + ModuleToPlugin.Add(Module, Plugin); + } + } + // Check there aren't any engine binaries with dependencies on game modules. This can happen when game-specific plugins override engine plugins. foreach(UEBuildModule Module in Modules.Values) { - if(Module.Binary != null && Module.RulesFile.IsUnderDirectory(UnrealBuildTool.EngineDirectory)) + if(Module.Binary != null && UnrealBuildTool.IsUnderAnEngineDirectory(Module.RulesFile.Directory)) { + DirectoryReference RootDirectory = UnrealBuildTool.EngineDirectory; + + if (Module.RulesFile.IsUnderDirectory(UnrealBuildTool.EnterpriseDirectory)) + { + RootDirectory = UnrealBuildTool.EnterpriseDirectory; + } + HashSet ReferencedModules = Module.GetDependencies(bWithIncludePathModules: true, bWithDynamicallyLoadedModules: true); + + // Make sure engine modules don't depend on enterprise or game modules and that enterprise modules don't depend on game modules foreach(UEBuildModule ReferencedModule in ReferencedModules) { - // Hard-code specific exceptions until these are properly fixed up - if(ReferencedModule.RulesFile != null && !ReferencedModule.RulesFile.IsUnderDirectory(UnrealBuildTool.EngineDirectory)) + if(ReferencedModule.RulesFile != null && !ReferencedModule.RulesFile.IsUnderDirectory(UnrealBuildTool.EngineDirectory) && !ReferencedModule.RulesFile.IsUnderDirectory(RootDirectory)) { string EngineModuleRelativePath = Module.RulesFile.MakeRelativeTo(UnrealBuildTool.EngineDirectory.ParentDirectory); - string ReferencedModuleRelativePath = ReferencedModule.RulesFile.IsUnderDirectory(ProjectFile.Directory)? ReferencedModule.RulesFile.MakeRelativeTo(ProjectFile.Directory.ParentDirectory) : ReferencedModule.RulesFile.FullName; + string ReferencedModuleRelativePath = (ProjectFile != null && ReferencedModule.RulesFile.IsUnderDirectory(ProjectFile.Directory)) ? ReferencedModule.RulesFile.MakeRelativeTo(ProjectFile.Directory.ParentDirectory) : ReferencedModule.RulesFile.FullName; throw new BuildException("Engine module '{0}' should not depend on game module '{1}'", EngineModuleRelativePath, ReferencedModuleRelativePath); } } + + // Make sure engine modules don't directly reference engine plugins + if(Module.RulesFile.IsUnderDirectory(UnrealBuildTool.EngineSourceDirectory) && !Module.RulesFile.IsUnderDirectory(TargetRulesFile.Directory)) + { + foreach(UEBuildModule ReferencedModule in ReferencedModules) + { + if(ReferencedModule.RulesFile != null && ModuleToPlugin.ContainsKey(ReferencedModule) && !IsWhitelistedEnginePluginReference(Module.Name, ReferencedModule.Name)) + { + string EngineModuleRelativePath = Module.RulesFile.MakeRelativeTo(UnrealBuildTool.EngineDirectory.ParentDirectory); + string ReferencedModuleRelativePath = ReferencedModule.RulesFile.MakeRelativeTo(UnrealBuildTool.EngineDirectory.ParentDirectory); + Log.TraceWarning("Warning: Engine module '{0}' should not depend on plugin module '{1}'", EngineModuleRelativePath, ReferencedModuleRelativePath); + } + } + } + } + } + + // Check that each plugin declares its dependencies explicitly + foreach(UEBuildPlugin Plugin in BuildPlugins) + { + foreach(UEBuildModule Module in Plugin.Modules) + { + HashSet DependencyModules = Module.GetDependencies(bWithIncludePathModules: true, bWithDynamicallyLoadedModules: true); + foreach(UEBuildModule DependencyModule in DependencyModules) + { + UEBuildPlugin DependencyPlugin; + if(ModuleToPlugin.TryGetValue(DependencyModule, out DependencyPlugin) && DependencyPlugin != Plugin && !Plugin.Dependencies.Contains(DependencyPlugin)) + { + Log.TraceWarning("Warning: Plugin '{0}' does not list plugin '{1}' as a dependency, but module '{2}' depends on '{3}'.", Plugin.Name, DependencyPlugin.Name, Module.Name, DependencyModule.Name); + } + } } } } @@ -2400,8 +2462,8 @@ namespace UnrealBuildTool } } - // Add global definitions for project-specific binaries - if(!bUseSharedBuildEnvironment) + // Add global definitions for project-specific binaries. HACK: Also defining for monolithic builds in binary releases. Might be better to set this via command line instead? + if(!bUseSharedBuildEnvironment || bCompileMonolithic) { UEBuildBinary ExecutableBinary = AppBinaries[0]; @@ -2431,13 +2493,6 @@ namespace UnrealBuildTool } GlobalCompileEnvironment.Definitions.Add("UE_ENGINE_DIRECTORY=" + EnginePath); } - - // Set the define for the project name. This allows the executable to locate the correct project file to use, which may not be the same as the game name or target. - if (ProjectFile != null) - { - string ProjectName = ProjectFile.GetFileNameWithoutExtension(); - GlobalCompileEnvironment.Definitions.Add(String.Format("UE_PROJECT_NAME={0}", ProjectName)); - } } // On Mac and Linux we have actions that should be executed after all the binaries are created @@ -2475,7 +2530,7 @@ namespace UnrealBuildTool if ((BuildConfiguration.bXGEExport && BuildConfiguration.bGenerateManifest) || (!BuildConfiguration.bGenerateManifest && !BuildConfiguration.bCleanProject && !ProjectFileGenerator.bGenerateProjectFiles)) { - HashSet ModulesToGenerateHeadersFor = GatherDependencyModules(AppBinaries); + HashSet ModulesToGenerateHeadersFor = GatherDependencyModules(OriginalBinaries); if (OnlyModules.Count > 0) { @@ -2516,7 +2571,7 @@ namespace UnrealBuildTool List SharedPCHs = new List(); if (!ProjectFileGenerator.bGenerateProjectFiles && Rules.bUseSharedPCHs) { - SharedPCHs = FindSharedPCHs(GlobalCompileEnvironment); + SharedPCHs = FindSharedPCHs(OriginalBinaries, GlobalCompileEnvironment); } // Compile the resource files common to all DLLs on Windows @@ -2552,6 +2607,9 @@ namespace UnrealBuildTool } } + // Allow the toolchain to modify the final output items + TargetToolChain.FinalizeOutput(Rules, OutputItems, ActionGraph); + // Make sure all the checked headers were valid List InvalidIncludeDirectiveMessages = Modules.Values.OfType().Where(x => x.InvalidIncludeDirectiveMessages != null).SelectMany(x => x.InvalidIncludeDirectiveMessages).ToList(); if (InvalidIncludeDirectiveMessages.Count > 0) @@ -2567,6 +2625,25 @@ namespace UnrealBuildTool return ECompilationResult.Succeeded; } + /// + /// Check whether a reference from an engine module to a plugin module is allowed. Temporary hack until these can be fixed up propertly. + /// + /// Name of the engine module. + /// Name of the plugin module. + /// True if the reference is whitelisted. + static bool IsWhitelistedEnginePluginReference(string EngineModuleName, string PluginModuleName) + { + if(EngineModuleName == "AndroidDeviceDetection" && PluginModuleName == "TcpMessaging") + { + return true; + } + if(EngineModuleName == "Voice" && PluginModuleName == "AndroidPermission") + { + return true; + } + return false; + } + /// /// Export the definition of this target to a JSON file /// @@ -2700,10 +2777,23 @@ namespace UnrealBuildTool } } - // Add the enabled plugins to the build - foreach (PluginInfo BuildPlugin in BuildPlugins) + // Add the plugin binaries to the build + UEBuildBinaryType BinaryType = ShouldCompileMonolithic() ? UEBuildBinaryType.StaticLibrary : UEBuildBinaryType.DynamicLinkLibrary; + foreach (UEBuildPlugin Plugin in BuildPlugins) { - AddPlugin(BuildPlugin); + foreach(UEBuildModule Module in Plugin.Modules) + { + // Add the corresponding binary for it + bool bAllowCompilation = RulesAssembly.DoesModuleHaveSource(Module.Name); + bool bPrecompileOnly = !EnabledPlugins.Contains(Plugin); + Module.Binary = CreateBinaryForModule(Module, BinaryType, bAllowCompilation: bAllowCompilation, bIsCrossTarget: false, bPrecompileOnly: bPrecompileOnly); + + // Add it to the binary if we're compiling monolithic (and it's enabled) + if (ShouldCompileMonolithic() && EnabledPlugins.Contains(Plugin)) + { + AppBinaries[0].AddModule(Module); + } + } } // Describe what's being built. @@ -2802,24 +2892,24 @@ namespace UnrealBuildTool } // Find all the pre-build steps - List> PreBuildSteps = new List>(); + List> PreBuildSteps = new List>(); if(ProjectDescriptor != null && ProjectDescriptor.PreBuildSteps != null) { - PreBuildSteps.Add(Tuple.Create(ProjectDescriptor.PreBuildSteps, (PluginInfo)null)); + PreBuildSteps.Add(Tuple.Create(ProjectDescriptor.PreBuildSteps, (UEBuildPlugin)null)); } - foreach(PluginInfo BuildPlugin in BuildPlugins.Where(x => x.Descriptor.PreBuildSteps != null)) + foreach(UEBuildPlugin BuildPlugin in BuildPlugins.Where(x => x.Descriptor.PreBuildSteps != null)) { PreBuildSteps.Add(Tuple.Create(BuildPlugin.Descriptor.PreBuildSteps, BuildPlugin)); } PreBuildStepScripts = WriteCustomBuildStepScripts(BuildHostPlatform.Current.Platform, ScriptDirectory, "PreBuild", PreBuildSteps); // Find all the post-build steps - List> PostBuildSteps = new List>(); + List> PostBuildSteps = new List>(); if(ProjectDescriptor != null && ProjectDescriptor.PostBuildSteps != null) { - PostBuildSteps.Add(Tuple.Create(ProjectDescriptor.PostBuildSteps, (PluginInfo)null)); + PostBuildSteps.Add(Tuple.Create(ProjectDescriptor.PostBuildSteps, (UEBuildPlugin)null)); } - foreach(PluginInfo BuildPlugin in BuildPlugins.Where(x => x.Descriptor.PostBuildSteps != null)) + foreach(UEBuildPlugin BuildPlugin in BuildPlugins.Where(x => x.Descriptor.PostBuildSteps != null)) { PostBuildSteps.Add(Tuple.Create(BuildPlugin.Descriptor.PostBuildSteps, BuildPlugin)); } @@ -2834,10 +2924,10 @@ namespace UnrealBuildTool /// Bare prefix for all the created script files /// List of custom build steps, and their matching PluginInfo (if appropriate) /// List of created script files - private FileReference[] WriteCustomBuildStepScripts(UnrealTargetPlatform HostPlatform, DirectoryReference Directory, string FilePrefix, List> BuildStepsAndPluginInfo) + private FileReference[] WriteCustomBuildStepScripts(UnrealTargetPlatform HostPlatform, DirectoryReference Directory, string FilePrefix, List> BuildStepsAndPluginInfo) { List ScriptFiles = new List(); - foreach(Tuple Pair in BuildStepsAndPluginInfo) + foreach(Tuple Pair in BuildStepsAndPluginInfo) { CustomBuildSteps BuildSteps = Pair.Item1; if(BuildSteps.HasHostPlatform(HostPlatform)) @@ -3146,23 +3236,28 @@ namespace UnrealBuildTool // Fill out the body of the function with the empty function calls. This is what causes the static libraries to be considered relevant List DependencyModules = ExecutableBinary.GetAllDependencyModules(bIncludeDynamicallyLoaded: false, bForceCircular: false); - HashSet AlreadyAddedEmptyLinkFunctions = new HashSet(); - foreach (UEBuildModuleCPP BuildModuleCPP in DependencyModules.OfType().Where(CPPModule => CPPModule.AutoGenerateCppInfo != null)) + HashSet AlreadyAddedEmptyLinkFunctions = new HashSet(); + foreach (UEBuildModuleCPP BuildModuleCPP in DependencyModules.OfType().Where(CPPModule => CPPModule.AutoGenerateCppInfo != null)) { - int NumGeneratedCppFilesWithTheFunction = BuildModuleCPP.FindNumberOfGeneratedCppFiles(); - if(NumGeneratedCppFilesWithTheFunction == 0) - { - Result.Add(" //" + BuildModuleCPP.Name + " has no generated files, path: " + BuildModuleCPP.GeneratedCodeDirectory.ToString()); - } - for (int FileIdx = 1; FileIdx <= NumGeneratedCppFilesWithTheFunction; ++FileIdx) - { - string FunctionName = "EmptyLinkFunctionForGeneratedCode" + FileIdx + BuildModuleCPP.Name; - if (AlreadyAddedEmptyLinkFunctions.Add(FunctionName)) - { - Result.Add(" extern void " + FunctionName + "();"); - Result.Add(" " + FunctionName + "();"); - } - } + IEnumerable GeneratedCppFilesWithTheFunction = BuildModuleCPP.FindGeneratedCppFiles(); + + bool bFound = false; + foreach (string CppFile in GeneratedCppFilesWithTheFunction) + { + bFound = true; + + string FunctionName = "EmptyLinkFunctionForGeneratedCode" + Path.GetFileName(CppFile).Replace(".gen.cpp", "").Replace(".", "_"); + if (AlreadyAddedEmptyLinkFunctions.Add(FunctionName)) + { + Result.Add(" extern void " + FunctionName + "();"); + Result.Add(" " + FunctionName + "();"); + } + } + + if (!bFound) + { + Result.Add(" //" + BuildModuleCPP.Name + " has no generated files, path: " + BuildModuleCPP.GeneratedCodeDirectory.ToString()); + } } foreach (string DependencyModuleName in PrivateDependencyModuleNames) { @@ -3215,18 +3310,19 @@ namespace UnrealBuildTool InSourceFiles: SourceFiles.ToList(), InRules: Rules, bInBuildSourceFiles: true, - InRulesFile: null); + InRulesFile: null, + InRuntimeDependencies: new List()); } /// /// Determines which modules can be used to create shared PCHs /// /// List of shared PCH modules, in order of preference - List FindSharedPCHs(CppCompileEnvironment GlobalCompileEnvironment) + List FindSharedPCHs(List OriginalBinaries, CppCompileEnvironment GlobalCompileEnvironment) { // Find how many other shared PCH modules each module depends on, and use that to sort the shared PCHs by reverse order of size. HashSet SharedPCHModules = new HashSet(); - foreach(UEBuildBinaryCPP Binary in AppBinaries.OfType()) + foreach(UEBuildBinaryCPP Binary in OriginalBinaries.OfType()) { foreach(UEBuildModuleCPP Module in Binary.Modules.OfType()) { @@ -3272,37 +3368,6 @@ namespace UnrealBuildTool return OrderedSharedPCHModules; } - /// - /// Include the given plugin in the target. It may be included as a separate binary, or compiled into a monolithic executable. - /// - public void AddPlugin(PluginInfo Plugin) - { - UEBuildBinaryType BinaryType = ShouldCompileMonolithic() ? UEBuildBinaryType.StaticLibrary : UEBuildBinaryType.DynamicLinkLibrary; - if (Plugin.Descriptor.Modules != null) - { - foreach (ModuleDescriptor Module in Plugin.Descriptor.Modules) - { - if (Module.IsCompiledInConfiguration(Platform, TargetType, Rules.bBuildDeveloperTools, Rules.bBuildEditor, Rules.bBuildRequiresCookedData)) - { - UEBuildModule ModuleInstance = FindOrCreateModuleByName(Module.Name); - if(ModuleInstance.Binary == null) - { - // Add the corresponding binary for it - bool bAllowCompilation = RulesAssembly.DoesModuleHaveSource(Module.Name); - bool bPrecompileOnly = !EnabledPlugins.Contains(Plugin); - ModuleInstance.Binary = CreateBinaryForModule(ModuleInstance, BinaryType, bAllowCompilation: bAllowCompilation, bIsCrossTarget: false, bPrecompileOnly: bPrecompileOnly); - - // Add it to the binary if we're compiling monolithic (and it's enabled) - if (ShouldCompileMonolithic() && EnabledPlugins.Contains(Plugin)) - { - AppBinaries[0].AddModule(ModuleInstance); - } - } - } - } - } - } - /// When building a target, this is called to add any additional modules that should be compiled along /// with the main target. If you override this in a derived class, remember to call the base implementation! protected virtual void AddExtraModules() @@ -3394,19 +3459,16 @@ namespace UnrealBuildTool } // Add all the plugins which aren't already being built - foreach (PluginInfo Plugin in ValidPlugins.Except(BuildPlugins)) + foreach(UEBuildPlugin PrecompilePlugin in PrecompilePlugins) { - if (Plugin.LoadedFrom == PluginLoadedFrom.Engine && Plugin.Descriptor.Modules != null) + foreach (ModuleDescriptor ModuleDescriptor in PrecompilePlugin.Descriptor.Modules) { - foreach (ModuleDescriptor ModuleDescriptor in Plugin.Descriptor.Modules) + if (ModuleDescriptor.IsCompiledInConfiguration(Platform, TargetType, bAllowDeveloperModules && Rules.bBuildDeveloperTools, Rules.bBuildEditor, Rules.bBuildRequiresCookedData)) { - if (ModuleDescriptor.IsCompiledInConfiguration(Platform, TargetType, bAllowDeveloperModules && Rules.bBuildDeveloperTools, Rules.bBuildEditor, Rules.bBuildRequiresCookedData)) + string RelativeFileName = RulesAssembly.GetModuleFileName(ModuleDescriptor.Name).MakeRelativeTo(UnrealBuildTool.EngineDirectory); + if (!ExcludeFolders.Any(x => RelativeFileName.Contains(x)) && !PrecompiledModules.Any(x => x.Name == ModuleDescriptor.Name)) { - string RelativeFileName = RulesAssembly.GetModuleFileName(ModuleDescriptor.Name).MakeRelativeTo(UnrealBuildTool.EngineDirectory); - if (!ExcludeFolders.Any(x => RelativeFileName.Contains(x)) && !PrecompiledModules.Any(x => x.Name == ModuleDescriptor.Name)) - { - FilteredModuleNames.Add(ModuleDescriptor.Name); - } + FilteredModuleNames.Add(ModuleDescriptor.Name); } } } @@ -3530,7 +3592,14 @@ namespace UnrealBuildTool } else { - BaseOutputDirectory = UnrealBuildTool.EngineDirectory; + if (Module.ModuleDirectory.IsUnderDirectory(UnrealBuildTool.EnterpriseDirectory)) + { + BaseOutputDirectory = UnrealBuildTool.EnterpriseDirectory; + } + else + { + BaseOutputDirectory = UnrealBuildTool.EngineDirectory; + } } // Get the configuration that this module will be built in. Engine modules compiled in DebugGame will use Development. @@ -3672,68 +3741,89 @@ namespace UnrealBuildTool /// protected virtual void SetupPlugins() { - // Filter the plugins list by the current project - ValidPlugins = new List(RulesAssembly.EnumeratePlugins()); + // Find all the valid plugins + Dictionary NameToInfo = RulesAssembly.EnumeratePlugins().ToDictionary(x => x.Name, x => x, StringComparer.InvariantCultureIgnoreCase); // Remove any plugins for platforms we don't have - List ExcludeFolders = new List(); + List MissingPlatforms = new List(); foreach (UnrealTargetPlatform TargetPlatform in Enum.GetValues(typeof(UnrealTargetPlatform))) { if (UEBuildPlatform.GetBuildPlatform(TargetPlatform, true) == null) { - string DirectoryFragment = Path.DirectorySeparatorChar + TargetPlatform.ToString() + Path.DirectorySeparatorChar; - ExcludeFolders.Add(DirectoryFragment); + MissingPlatforms.Add(TargetPlatform); } } - ValidPlugins.RemoveAll(x => x.Descriptor.bRequiresBuildPlatform && ShouldExcludePlugin(x, ExcludeFolders)); - // Build a list of enabled plugins - EnabledPlugins = new List(); - UnrealHeaderToolPlugins = new List(); + // Get an array of folders to filter out + FileSystemName[] ExcludeFolders = MissingPlatforms.Select(x => new FileSystemName(x.ToString())).ToArray(); - // If we're compiling against the engine, add the plugins enabled for this target + // Find a map of plugins which are explicitly referenced in the project file + Dictionary NameToReference = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + if(ProjectDescriptor != null && ProjectDescriptor.Plugins != null) + { + foreach(PluginReferenceDescriptor PluginReference in ProjectDescriptor.Plugins) + { + NameToReference[PluginReference.Name] = PluginReference; + } + } + + // Also synthesize references for plugins which are enabled by default if (Rules.bCompileAgainstEngine) { - ProjectDescriptor Project = (ProjectFile != null) ? ProjectDescriptor.FromFile(ProjectFile.FullName) : null; - foreach (PluginInfo ValidPlugin in ValidPlugins) + foreach(PluginInfo Plugin in NameToInfo.Values) { - if(UProjectInfo.IsPluginEnabledForProject(ValidPlugin, Project, Platform, TargetType)) + if(Plugin.Descriptor.bEnabledByDefault && !NameToReference.ContainsKey(Plugin.Name)) { - if (ValidPlugin.Descriptor.bCanBeUsedWithUnrealHeaderTool) + if (Plugin.Descriptor.bCanContainContent || Plugin.Descriptor.Modules.Any(x => x.IsCompiledInConfiguration(Platform, TargetType, Rules.bBuildDeveloperTools, Rules.bBuildEditor, Rules.bBuildRequiresCookedData))) { - UnrealHeaderToolPlugins.Add(ValidPlugin); + PluginReferenceDescriptor PluginReference = new PluginReferenceDescriptor(Plugin.Name, null, true); + PluginReference.bOptional = true; + NameToReference[Plugin.Name] = PluginReference; } - EnabledPlugins.Add(ValidPlugin); } } } - // Add the plugins explicitly required by the target rules - foreach (string AdditionalPlugin in Rules.AdditionalPlugins) + // If this is a program, synthesize references for plugins which are enabled via the config file + if(TargetType == TargetType.Program) { - PluginInfo Plugin = ValidPlugins.FirstOrDefault(ValidPlugin => ValidPlugin.Name == AdditionalPlugin); - if (Plugin == null) + ConfigHierarchy EngineConfig = ConfigCache.ReadHierarchy(ConfigHierarchyType.Engine, DirectoryReference.Combine(UnrealBuildTool.EngineDirectory, "Programs", TargetName), Platform); + + List PluginNames; + if(EngineConfig.GetArray("Plugins", "ProgramEnabledPlugins", out PluginNames)) { - throw new BuildException("Plugin '{0}' is in the list of additional plugins for {1}, but was not found.", AdditionalPlugin, TargetName); - } - if (!EnabledPlugins.Contains(Plugin)) - { - EnabledPlugins.Add(Plugin); + foreach(string PluginName in PluginNames) + { + if(!NameToReference.ContainsKey(PluginName)) + { + PluginReferenceDescriptor PluginReference = new PluginReferenceDescriptor(PluginName, null, true); + NameToReference[PluginName] = PluginReference; + } + } } } - // Remove any enabled plugins that are unused on the current platform. This prevents having to stage the .uplugin files, but requires that the project descriptor - // doesn't have a platform-neutral reference to it. - EnabledPlugins.RemoveAll(Plugin => !UProjectInfo.IsPluginDescriptorRequiredForProject(Plugin, ProjectDescriptor, Platform, TargetType, Rules.bBuildDeveloperTools, Rules.bBuildEditor, Rules.bBuildRequiresCookedData)); - - // Set the list of plugins that should be built - if (Rules.bBuildAllPlugins) + // Create all the plugin instances + Dictionary NameToInstance = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + foreach(PluginReferenceDescriptor PluginReference in NameToReference.Values) { - BuildPlugins = new List(ValidPlugins); + AddPlugin(PluginReference, ExcludeFolders, NameToInstance, NameToInfo); } - else + + // Create the list of enabled plugins + EnabledPlugins = new List(NameToInstance.Values); + + // Try to add any the other plugins that are valid + if(Rules.bBuildAllPlugins) { - BuildPlugins = new List(EnabledPlugins); + foreach(PluginInfo Plugin in NameToInfo.Values) + { + if(!NameToInstance.ContainsKey(Plugin.Name)) + { + PluginReferenceDescriptor Reference = new PluginReferenceDescriptor(Plugin.Name, null, true); + AddPlugin(Reference, ExcludeFolders, NameToInstance, NameToInfo); + } + } } // Add any foreign plugins to the list @@ -3741,29 +3831,162 @@ namespace UnrealBuildTool { foreach (FileReference ForeignPlugin in ForeignPlugins) { - PluginInfo ForeignPluginInfo = ValidPlugins.FirstOrDefault(x => x.File == ForeignPlugin); - if (!BuildPlugins.Contains(ForeignPluginInfo)) + PluginInfo ForeignPluginInfo = NameToInfo.Values.FirstOrDefault(x => x.File == ForeignPlugin); + if (!NameToInstance.ContainsKey(ForeignPluginInfo.Name)) { - BuildPlugins.Add(ForeignPluginInfo); + PluginReferenceDescriptor Reference = new PluginReferenceDescriptor(ForeignPluginInfo.Name, null, true); + AddPlugin(Reference, ExcludeFolders, NameToInstance, NameToInfo); } } } + + // Set the list of plugins that should be built + BuildPlugins = new List(NameToInstance.Values); + + // Create the list of plugins to precompile. This is separate to the list of binaries being built, because + // they and their dependencies won't be linked into the application binary by default on monolithic builds. + if (bPrecompile && ProjectFile == null && TargetType != TargetType.Program) + { + foreach(PluginInfo Plugin in NameToInfo.Values) + { + if (!NameToInstance.ContainsKey(Plugin.Name) && Plugin.Descriptor.Modules != null) + { + PluginReferenceDescriptor Reference = new PluginReferenceDescriptor(Plugin.Name, null, true); + AddPlugin(Reference, ExcludeFolders, NameToInstance, NameToInfo); + } + } + PrecompilePlugins = new List(NameToInstance.Values.Except(BuildPlugins)); + } + } + + /// + /// Creates a plugin instance from a reference to it + /// + /// Reference to the plugin + /// Array of folder names to be excluded + /// Map from plugin name to instance of it + /// Map from plugin name to information + /// Instance of the plugin, or null if it should not be used + private UEBuildPlugin AddPlugin(PluginReferenceDescriptor Reference, FileSystemName[] ExcludeFolders, Dictionary NameToInstance, Dictionary NameToInfo) + { + // Ignore disabled references + if(!Reference.bEnabled) + { + return null; + } + + // Try to get an existing reference to this plugin + UEBuildPlugin Instance; + if(NameToInstance.TryGetValue(Reference.Name, out Instance)) + { + // If this is a non-optional reference, make sure that and every referenced dependency is staged + if(!Reference.bOptional && !Instance.bDescriptorReferencedExplicitly) + { + Instance.bDescriptorReferencedExplicitly = true; + if(Instance.Descriptor.Plugins != null) + { + foreach(PluginReferenceDescriptor NextReference in Instance.Descriptor.Plugins) + { + AddPlugin(NextReference, ExcludeFolders, NameToInstance, NameToInfo); + } + } + } + } + else + { + // Check if the plugin is required for this platform + if(!Reference.IsEnabledForPlatform(Platform) || !Reference.IsEnabledForTarget(TargetType)) + { + Log.TraceVerbose("Ignoring plugin '{0}' for platform/configuration", Reference.Name); + return null; + } + + // Find the plugin being enabled + PluginInfo Info; + if(!NameToInfo.TryGetValue(Reference.Name, out Info)) + { + if (Reference.bOptional) + { + return null; + } + else + { + throw new BuildException("{0} requires the '{1}' plugin. Install it and try again, or remove it from the required plugin list.", TargetName, Reference.Name); + } + } + + // Disable any plugin that requires the build platform + if(Info.Descriptor.bRequiresBuildPlatform && ShouldExcludePlugin(Info, ExcludeFolders)) + { + Log.TraceVerbose("Excluding plugin '%s' due to missing build platform", Reference.Name); + return null; + } + + // Create the new instance and add it to the cache + Instance = new UEBuildPlugin(Info); + Instance.bDescriptorReferencedExplicitly = !Reference.bOptional; + NameToInstance.Add(Info.Name, Instance); + + // Create modules for this plugin + UEBuildBinaryType BinaryType = ShouldCompileMonolithic() ? UEBuildBinaryType.StaticLibrary : UEBuildBinaryType.DynamicLinkLibrary; + if (Info.Descriptor.Modules != null) + { + foreach (ModuleDescriptor ModuleInfo in Info.Descriptor.Modules) + { + if (ModuleInfo.IsCompiledInConfiguration(Platform, TargetType, Rules.bBuildDeveloperTools, Rules.bBuildEditor, Rules.bBuildRequiresCookedData)) + { + UEBuildModule Module = FindOrCreateModuleByName(ModuleInfo.Name); + if (!Module.RulesFile.IsUnderDirectory(Info.Directory)) + { + throw new BuildException("Plugin '{0}' does not contain the '{1}' module, but lists it in '{2}'.", Info.Name, ModuleInfo.Name, Info.File); + } + Instance.bDescriptorNeededAtRuntime = true; + Instance.Modules.Add(Module); + } + } + } + + // Create the dependencies set + HashSet Dependencies = new HashSet(); + if(Info.Descriptor.Plugins != null) + { + foreach(PluginReferenceDescriptor NextReference in Info.Descriptor.Plugins) + { + UEBuildPlugin NextInstance = AddPlugin(NextReference, ExcludeFolders, NameToInstance, NameToInfo); + if(NextInstance != null) + { + Dependencies.Add(NextInstance); + if(NextInstance.Dependencies == null) + { + throw new BuildException("Found circular dependency from plugin '{0}' onto itself.", NextReference.Name); + } + Dependencies.UnionWith(NextInstance.Dependencies); + } + } + } + Instance.Dependencies = Dependencies; + + // Stage the descriptor if the plugin contains content + if (Info.Descriptor.bCanContainContent || Dependencies.Any(x => x.bDescriptorNeededAtRuntime)) + { + Instance.bDescriptorNeededAtRuntime = true; + } + } + return Instance; } /// /// Checks whether a plugin path contains a platform directory fragment /// - private bool ShouldExcludePlugin(PluginInfo Plugin, List ExcludeFragments) + private bool ShouldExcludePlugin(PluginInfo Plugin, FileSystemName[] ExcludeFolders) { if (Plugin.LoadedFrom == PluginLoadedFrom.Engine) { - string RelativePathFromRoot = Plugin.File.MakeRelativeTo(UnrealBuildTool.EngineDirectory); - return ExcludeFragments.Any(x => RelativePathFromRoot.Contains(x)); + return Plugin.File.ContainsAnyNames(ExcludeFolders, UnrealBuildTool.EngineDirectory); } else if(ProjectFile != null) { - string RelativePathFromRoot = Plugin.File.MakeRelativeTo(ProjectFile.Directory); - return ExcludeFragments.Any(x => RelativePathFromRoot.Contains(x)); + return Plugin.File.ContainsAnyNames(ExcludeFolders, ProjectFile.Directory); } else { @@ -3858,7 +4081,7 @@ namespace UnrealBuildTool ToolChain.SetUpGlobalEnvironment(Rules); - // @Hack: This to prevent UHT from listing CoreUObject.generated.cpp as its dependency. + // @Hack: This to prevent UHT from listing CoreUObject.init.gen.cpp as its dependency. // We flag the compile environment when we build UHT so that we don't need to check // this for each file when generating their dependencies. GlobalCompileEnvironment.bHackHeaderGenerator = (GetAppName() == "UnrealHeaderTool"); @@ -3876,10 +4099,10 @@ namespace UnrealBuildTool GlobalCompileEnvironment.bSupportEditAndContinue = Rules.bSupportEditAndContinue; GlobalCompileEnvironment.bUseIncrementalLinking = Rules.bUseIncrementalLinking; GlobalCompileEnvironment.bAllowLTCG = Rules.bAllowLTCG; - GlobalCompileEnvironment.bEnableCodeAnalysis = Rules.bEnableCodeAnalysis; GlobalCompileEnvironment.bAllowRemotelyCompiledPCHs = Rules.bAllowRemotelyCompiledPCHs; GlobalCompileEnvironment.IncludePaths.bCheckSystemHeadersForModification = Rules.bCheckSystemHeadersForModification; GlobalCompileEnvironment.bPrintTimingInfo = Rules.bPrintToolChainTimingInfo; + GlobalCompileEnvironment.bUseRTTI = Rules.bForceEnableRTTI; GlobalLinkEnvironment.bIsBuildingConsoleApplication = Rules.bIsBuildingConsoleApplication; GlobalLinkEnvironment.bOptimizeForSize = Rules.bCompileForSize; @@ -4044,7 +4267,16 @@ namespace UnrealBuildTool GlobalCompileEnvironment.Definitions.Add("WITH_LOGGING_TO_MEMORY=0"); } - if (Rules.bUseChecksInShipping) + if (Rules.bUseCacheFreedOSAllocs) + { + GlobalCompileEnvironment.Definitions.Add("USE_CACHE_FREED_OS_ALLOCS=1"); + } + else + { + GlobalCompileEnvironment.Definitions.Add("USE_CACHE_FREED_OS_ALLOCS=0"); + } + + if (Rules.bUseChecksInShipping) { GlobalCompileEnvironment.Definitions.Add("USE_CHECKS_IN_SHIPPING=1"); } @@ -4249,8 +4481,6 @@ namespace UnrealBuildTool UEBuildModule Module; if (!Modules.TryGetValue(ModuleName, out Module)) { - // Create the module! (It will be added to our hash table in its constructor) - // @todo projectfiles: Cross-platform modules can appear here during project generation, but they may have already // been filtered out by the project generator. This causes the projects to not be added to directories properly. FileReference ModuleFileName; @@ -4275,7 +4505,7 @@ namespace UnrealBuildTool } } - if (ModuleFileName.IsUnderDirectory(UnrealBuildTool.EngineDirectory)) + if (UnrealBuildTool.IsUnderAnEngineDirectory(ModuleFileName.Directory)) { if (RulesObject.Type == ModuleRules.ModuleType.External) { @@ -4290,7 +4520,14 @@ namespace UnrealBuildTool if (!ModuleType.HasValue) { - ModuleType = ExternalExecution.GetEngineModuleTypeBasedOnLocation(ModuleFileName); + if (ModuleFileName.IsUnderDirectory(UnrealBuildTool.EngineDirectory)) + { + ModuleType = ExternalExecution.GetEngineModuleTypeBasedOnLocation(UnrealBuildTool.EngineSourceDirectory, ModuleFileName); + } + else if (ModuleFileName.IsUnderDirectory(UnrealBuildTool.EnterpriseSourceDirectory)) + { + ModuleType = ExternalExecution.GetEngineModuleTypeBasedOnLocation(UnrealBuildTool.EnterpriseSourceDirectory, ModuleFileName); + } } } } @@ -4365,10 +4602,10 @@ namespace UnrealBuildTool } // Don't generate include paths for third party modules; they don't follow our conventions. Core is a special-case... leave it alone - if (RulesObject.Type != ModuleRules.ModuleType.External && ModuleName != "Core") + if (RulesObject.Type != ModuleRules.ModuleType.External && RulesObject.bAddDefaultIncludePaths) { // Add the default include paths to the module rules, if they exist. Would be nice not to include game plugins here, but it would be a regression to change now. - bool bIsGameModuleOrProgram = ModuleFileName.IsUnderDirectory(TargetCsFilename.Directory) || (Plugin != null && Plugin.LoadedFrom == PluginLoadedFrom.GameProject); + bool bIsGameModuleOrProgram = ModuleFileName.IsUnderDirectory(TargetRulesFile.Directory) || (Plugin != null && Plugin.LoadedFrom == PluginLoadedFrom.GameProject); AddDefaultIncludePathsToModuleRules(ModuleFileName, bIsGameModuleOrProgram, Plugin, RulesObject); // Add the path to the generated headers @@ -4395,7 +4632,7 @@ namespace UnrealBuildTool } // So all we care about are the game module and/or plugins. - if (bDiscoverFiles && (!UnrealBuildTool.IsEngineInstalled() || !ModuleFileName.IsUnderDirectory(UnrealBuildTool.EngineDirectory))) + if (bDiscoverFiles && (!UnrealBuildTool.IsEngineInstalled() || !UnrealBuildTool.IsUnderAnEngineDirectory(ModuleFileName.Directory))) { List SourceFilePaths = new List(); @@ -4424,10 +4661,46 @@ namespace UnrealBuildTool // locations. UEBuildPlatform.PlatformModifyHostModuleRules(ModuleName, RulesObject, Rules); + // Expand the list of runtime dependencies, and update the run-time dependencies path to remove $(PluginDir) and replace with a full path. When the + // receipt is saved it'll be converted to a $(ProjectDir) or $(EngineDir) equivalent. + List RuntimeDependencies = new List(); + if(RulesObject.RuntimeDependencies.Count > 0) + { + // Get all the valid variables which can be expanded for this module + Dictionary Variables = new Dictionary(); + Variables["EngineDir"] = UnrealBuildTool.EngineDirectory.FullName; + if (ProjectFile != null) + { + Variables["ProjectDir"] = ProjectDirectory.FullName; + } + if (Plugin != null) + { + Variables["PluginDir"] = Plugin.Directory.FullName; + } + + // Convert them into concrete file lists. Ignore anything that still hasn't been resolved. + foreach (ModuleRules.RuntimeDependency Dependency in RulesObject.RuntimeDependencies) + { + string ExpandedPath = Utils.ExpandVariables(Dependency.Path, Variables); + if (!ExpandedPath.StartsWith("$(")) + { + int WildcardIdx = FileFilter.FindWildcardIndex(ExpandedPath); + if (WildcardIdx == -1) + { + RuntimeDependencies.Add(new RuntimeDependency(new FileReference(ExpandedPath), Dependency.Type)); + } + else + { + RuntimeDependencies.AddRange(FileFilter.ResolveWildcard(ExpandedPath).Select(x => new RuntimeDependency(x, Dependency.Type))); + } + } + } + } + // Now, go ahead and create the module builder instance - Module = InstantiateModule(RulesObject, ModuleName, ModuleType.Value, ModuleDirectory, GeneratedCodeDirectory, IntelliSenseGatherer, FoundSourceFiles, bBuildFiles, ModuleFileName); + Module = InstantiateModule(RulesObject, ModuleName, ModuleType.Value, ModuleDirectory, GeneratedCodeDirectory, IntelliSenseGatherer, FoundSourceFiles, bBuildFiles, ModuleFileName, RuntimeDependencies); Modules.Add(Module.Name, Module); - FlatModuleCsData.Add(Module.Name, new FlatModuleCsDataType((Module.RulesFile == null) ? null : Module.RulesFile.FullName)); + FlatModuleCsData.Add(Module.Name, new FlatModuleCsDataType((Module.RulesFile == null) ? null : Module.RulesFile.FullName, RulesObject.ExternalDependencies)); } return Module; } @@ -4441,7 +4714,8 @@ namespace UnrealBuildTool IntelliSenseGatherer IntelliSenseGatherer, List ModuleSourceFiles, bool bBuildSourceFiles, - FileReference InRulesFile) + FileReference InRulesFile, + List InRuntimeDependencies) { switch (RulesObject.Type) { @@ -4455,7 +4729,8 @@ namespace UnrealBuildTool InSourceFiles: ModuleSourceFiles, InRules: RulesObject, bInBuildSourceFiles: bBuildSourceFiles, - InRulesFile: InRulesFile + InRulesFile: InRulesFile, + InRuntimeDependencies: InRuntimeDependencies ); case ModuleRules.ModuleType.External: @@ -4464,7 +4739,8 @@ namespace UnrealBuildTool InType: ModuleType, InModuleDirectory: ModuleDirectory, InRules: RulesObject, - InRulesFile: InRulesFile + InRulesFile: InRulesFile, + InRuntimeDependencies: InRuntimeDependencies ); default: @@ -4482,7 +4758,7 @@ namespace UnrealBuildTool public void AddDefaultIncludePathsToModuleRules(FileReference ModuleFile, bool IsGameModule, PluginInfo Plugin, ModuleRules RulesObject) { // Get the base source directory for this module. This may be the project source directory, engine source directory, or plugin source directory. - if (!ModuleFile.IsUnderDirectory(UnrealBuildTool.EngineSourceDirectory)) + if (!ModuleFile.IsUnderDirectory(UnrealBuildTool.EngineSourceDirectory) && !ModuleFile.IsUnderDirectory(UnrealBuildTool.EnterpriseSourceDirectory)) { // Add the module source directory DirectoryReference BaseSourceDirectory; diff --git a/Engine/Source/Programs/UnrealBuildTool/HTML5/HTML5SDKInfo.cs b/Engine/Source/Programs/UnrealBuildTool/HTML5/HTML5SDKInfo.cs index 06eaab20dcab..2661512dabdc 100644 --- a/Engine/Source/Programs/UnrealBuildTool/HTML5/HTML5SDKInfo.cs +++ b/Engine/Source/Programs/UnrealBuildTool/HTML5/HTML5SDKInfo.cs @@ -181,9 +181,12 @@ namespace UnrealBuildTool } } } - // -------------------------------------------------- - // -------------------------------------------------- - static string HTML5Intermediatory + + /// + /// + /// + /// + public static string HTML5Intermediatory { get { @@ -252,7 +255,11 @@ namespace UnrealBuildTool return TempPath; } - static string PLATFORM_USER_HOME + /// + /// + /// + /// + public static string PLATFORM_USER_HOME { get { diff --git a/Engine/Source/Programs/UnrealBuildTool/HTML5/HTML5ToolChain.cs b/Engine/Source/Programs/UnrealBuildTool/HTML5/HTML5ToolChain.cs index 9e4ab31be2e7..c1257667a017 100644 --- a/Engine/Source/Programs/UnrealBuildTool/HTML5/HTML5ToolChain.cs +++ b/Engine/Source/Programs/UnrealBuildTool/HTML5/HTML5ToolChain.cs @@ -12,14 +12,14 @@ namespace UnrealBuildTool class HTML5ToolChain : VCToolChain { // ini configurations - static bool targetingWasm = true; + static bool targetingWasm = false; static bool targetWebGL2 = true; // Currently if this is set to true, UE4 can still fall back to WebGL 1 at runtime if browser does not support WebGL 2. static bool enableSIMD = false; static bool enableMultithreading = false; static bool bEnableTracing = false; // Debug option - public HTML5ToolChain() - : base(CppPlatform.HTML5, WindowsCompiler.VisualStudio2015) + public HTML5ToolChain(FileReference InProjectFile) + : base(CppPlatform.HTML5, WindowsCompiler.VisualStudio2015, false) { if (!HTML5SDKInfo.IsSDKInstalled()) { @@ -32,13 +32,29 @@ namespace UnrealBuildTool // - but, during packaging, if -remoteini is used -- need to use UnrealBuildTool.GetRemoteIniPath() // (note: ConfigCache can take null ProjectFile) string EngineIniPath = UnrealBuildTool.GetRemoteIniPath(); - DirectoryReference ProjectFile = !String.IsNullOrEmpty(EngineIniPath) ? new DirectoryReference(EngineIniPath) : null; - ConfigHierarchy Ini = ConfigCache.ReadHierarchy(ConfigHierarchyType.Engine, ProjectFile, UnrealTargetPlatform.HTML5); - Ini.GetBool("/Script/HTML5PlatformEditor.HTML5TargetSettings", "TargetWasm", out targetingWasm); - Ini.GetBool("/Script/HTML5PlatformEditor.HTML5TargetSettings", "TargetWebGL2", out targetWebGL2); + DirectoryReference ProjectDir = !String.IsNullOrEmpty(EngineIniPath) ? new DirectoryReference(EngineIniPath) + : DirectoryReference.FromFile(InProjectFile); + ConfigHierarchy Ini = ConfigCache.ReadHierarchy(ConfigHierarchyType.Engine, ProjectDir, UnrealTargetPlatform.HTML5); + + // these will be going away... + bool targetingAsmjs = true; // inverted check + bool targetWebGL1 = false; // inverted check + if ( Ini.GetBool("/Script/HTML5PlatformEditor.HTML5TargetSettings", "TargetAsmjs", out targetingAsmjs) ) + { + targetingWasm = !targetingAsmjs; + } + if ( Ini.GetBool("/Script/HTML5PlatformEditor.HTML5TargetSettings", "TargetWebGL1", out targetWebGL1) ) + { + targetWebGL2 = !targetWebGL1; + } Ini.GetBool("/Script/HTML5PlatformEditor.HTML5TargetSettings", "EnableSIMD", out enableSIMD); Ini.GetBool("/Script/HTML5PlatformEditor.HTML5TargetSettings", "EnableMultithreading", out enableMultithreading); Ini.GetBool("/Script/HTML5PlatformEditor.HTML5TargetSettings", "EnableTracing", out bEnableTracing); + Log.TraceInformation("HTML5ToolChain: TargetWasm = " + targetingWasm ); + Log.TraceInformation("HTML5ToolChain: TargetWebGL2 = " + targetWebGL2 ); + Log.TraceInformation("HTML5ToolChain: EnableSIMD = " + enableSIMD ); + Log.TraceInformation("HTML5ToolChain: EnableMultithreading " + enableMultithreading ); + Log.TraceInformation("HTML5ToolChain: EnableTracing = " + bEnableTracing ); // TODO: remove this "fix" when emscripten supports (SIMD & pthreads) + WASM if ( targetingWasm ) @@ -75,6 +91,7 @@ namespace UnrealBuildTool Result += " -fno-exceptions"; + Result += " -Wdelete-non-virtual-dtor"; Result += " -Wno-unused-value"; // appErrorf triggers this Result += " -Wno-switch"; // many unhandled cases Result += " -Wno-tautological-constant-out-of-range-compare"; // disables some warnings about comparisons from TCHAR being a char @@ -134,6 +151,24 @@ namespace UnrealBuildTool Result += " -s USE_PTHREADS=1"; } + // -------------------------------------------------------------------------------- + // normally, these option are for linking -- but it using here to force recompile when + if (targetingWasm) // flipping between asmjs and wasm + { + Result += " -s BINARYEN=1"; + } + else + { + Result += " -s BINARYEN=0"; + } + if (targetWebGL2) // flipping between webgl1 and webgl2 + { + Result += " -s USE_WEBGL2=1"; + } + else + { + Result += " -s USE_WEBGL2=0"; + } // -------------------------------------------------------------------------------- // Expect that Emscripten SDK has been properly set up ahead in time (with emsdk and prebundled toolchains this is always the case) @@ -145,6 +180,12 @@ namespace UnrealBuildTool // Environment.SetEnvironmentVariable("EMCC_CORES", "8"); // Environment.SetEnvironmentVariable("EMCC_OPTIMIZE_NORMALLY", "1"); + // Linux builds needs this - or else system clang will be attempted to be picked up instead of UE4's + // TODO: test on other platforms to remove this if() check + if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Linux) + { + Environment.SetEnvironmentVariable(HTML5SDKInfo.PLATFORM_USER_HOME, HTML5SDKInfo.HTML5Intermediatory); + } return Result; } @@ -254,6 +295,10 @@ namespace UnrealBuildTool // Memory init file is an asm.js only needed construct, in wasm the global data section is embedded in the wasm module, // so this flag is not needed there. Result += " --memory-init-file 1"; + + // Separate the asm.js code to its own file so that browsers can optimize memory usage for the script files for debugging. + Result += " -Wno-separate-asm"; + Result += " --separate-asm"; } // we have to specify the full amount of memory with Asm.JS. @@ -649,6 +694,8 @@ namespace UnrealBuildTool else { BuildProducts.Add(Binary.Config.OutputFilePath + ".mem", BuildProductType.RequiredResource); + BuildProducts.Add(Binary.Config.OutputFilePath.ChangeExtension("asm.js"), BuildProductType.RequiredResource); + // TODO: add "_asm.js" } BuildProducts.Add(Binary.Config.OutputFilePath + ".symbols", BuildProductType.RequiredResource); } diff --git a/Engine/Source/Programs/UnrealBuildTool/HTML5/UEBuildHTML5.cs b/Engine/Source/Programs/UnrealBuildTool/HTML5/UEBuildHTML5.cs index 4db68757868b..ef3b5a526e15 100644 --- a/Engine/Source/Programs/UnrealBuildTool/HTML5/UEBuildHTML5.cs +++ b/Engine/Source/Programs/UnrealBuildTool/HTML5/UEBuildHTML5.cs @@ -49,7 +49,6 @@ namespace UnrealBuildTool Target.bCompileAPEX = false; Target.bCompileNvCloth = false; Target.bCompilePhysX = true; - Target.bRuntimePhysicsCooking = false; Target.bCompileSimplygon = false; Target.bCompileSimplygonSSF = false; Target.bCompileForSize = true; @@ -288,7 +287,7 @@ namespace UnrealBuildTool /// New toolchain instance. public override UEToolChain CreateToolChain(CppPlatform CppPlatform, ReadOnlyTargetRules Target) { - return new HTML5ToolChain(); + return new HTML5ToolChain(Target.ProjectFile); } /// diff --git a/Engine/Source/Programs/UnrealBuildTool/IOS/IOSExports.cs b/Engine/Source/Programs/UnrealBuildTool/IOS/IOSExports.cs index a15dddc476b6..71f1bc8b074c 100644 --- a/Engine/Source/Programs/UnrealBuildTool/IOS/IOSExports.cs +++ b/Engine/Source/Programs/UnrealBuildTool/IOS/IOSExports.cs @@ -65,9 +65,9 @@ namespace UnrealBuildTool /// /// /// - public static bool PrepForUATPackageOrDeploy(UnrealTargetConfiguration Config, FileReference ProjectFile, string InProjectName, string InProjectDirectory, string InExecutablePath, string InEngineDir, bool bForDistribution, string CookFlavor, bool bIsDataDeploy, bool bCreateStubIPA) + public static bool PrepForUATPackageOrDeploy(UnrealTargetConfiguration Config, FileReference ProjectFile, string InProjectName, DirectoryReference InProjectDirectory, string InExecutablePath, DirectoryReference InEngineDir, bool bForDistribution, string CookFlavor, bool bIsDataDeploy, bool bCreateStubIPA) { - return new UEDeployIOS().PrepForUATPackageOrDeploy(Config, ProjectFile, InProjectName, InProjectDirectory, InExecutablePath, InEngineDir, bForDistribution, CookFlavor, bIsDataDeploy, bCreateStubIPA); + return new UEDeployIOS().PrepForUATPackageOrDeploy(Config, ProjectFile, InProjectName, InProjectDirectory.FullName, InExecutablePath, InEngineDir.FullName, bForDistribution, CookFlavor, bIsDataDeploy, bCreateStubIPA); } /// @@ -81,10 +81,12 @@ namespace UnrealBuildTool /// /// /// + /// + /// /// - public static bool GeneratePList(FileReference ProjectFile, UnrealTargetConfiguration Config, string ProjectDirectory, bool bIsUE4Game, string GameName, string ProjectName, string InEngineDir, string AppDirectory) + public static bool GeneratePList(FileReference ProjectFile, UnrealTargetConfiguration Config, DirectoryReference ProjectDirectory, bool bIsUE4Game, string GameName, string ProjectName, DirectoryReference InEngineDir, DirectoryReference AppDirectory, out bool bSupportsPortrait, out bool bSupportsLandscape) { - return new UEDeployIOS().GeneratePList(ProjectFile, Config, ProjectDirectory, bIsUE4Game, GameName, ProjectName, InEngineDir, AppDirectory); + return new UEDeployIOS().GeneratePList(ProjectFile, Config, ProjectDirectory.FullName, bIsUE4Game, GameName, ProjectName, InEngineDir.FullName, AppDirectory.FullName, out bSupportsPortrait, out bSupportsLandscape); } /// diff --git a/Engine/Source/Programs/UnrealBuildTool/IOS/IOSToolChain.cs b/Engine/Source/Programs/UnrealBuildTool/IOS/IOSToolChain.cs index 45153feeb950..ab31f5b71ffc 100644 --- a/Engine/Source/Programs/UnrealBuildTool/IOS/IOSToolChain.cs +++ b/Engine/Source/Programs/UnrealBuildTool/IOS/IOSToolChain.cs @@ -131,14 +131,19 @@ namespace UnrealBuildTool if (Target.bCreateStubIPA && Binary.Config.Type != UEBuildBinaryType.StaticLibrary) { FileReference StubFile = FileReference.Combine(Binary.Config.OutputFilePath.Directory, Binary.Config.OutputFilePath.GetFileNameWithoutExtension() + ".stub"); - BuildProducts.Add(StubFile, BuildProductType.Executable); + BuildProducts.Add(StubFile, BuildProductType.Package); if (CppPlatform == CppPlatform.TVOS) { FileReference AssetFile = FileReference.Combine(Binary.Config.OutputFilePath.Directory, "Assets.car"); - BuildProducts.Add(AssetFile, BuildProductType.Executable); + BuildProducts.Add(AssetFile, BuildProductType.RequiredResource); } } - } + if ((ProjectSettings.bGeneratedSYMFile == true || ProjectSettings.bGeneratedSYMBundle == true) && ProjectSettings.bGenerateCrashReportSymbols && Binary.Config.Type == UEBuildBinaryType.Executable) + { + FileReference DebugFile = FileReference.Combine(Binary.Config.OutputFilePath.Directory, Binary.Config.OutputFilePath.GetFileNameWithoutExtension() + ".udebugsymbols"); + BuildProducts.Add(DebugFile, BuildProductType.SymbolFile); + } + } /// /// Adds a build product and its associated debug file to a receipt. @@ -184,6 +189,7 @@ namespace UnrealBuildTool // } Result += " -Wall -Werror"; + Result += " -Wdelete-non-virtual-dtor"; if (CompileEnvironment.bEnableShadowVariableWarnings) { @@ -680,7 +686,7 @@ namespace UnrealBuildTool } string AllArgs = Arguments + FileArguments + CompileEnvironment.AdditionalArguments; - string SourceText = System.IO.File.ReadAllText(SourceFile.AbsolutePath); +/* string SourceText = System.IO.File.ReadAllText(SourceFile.AbsolutePath); if (CompileEnvironment.bOptimizeForSize && (SourceFile.AbsolutePath.Contains("ElementBatcher.cpp") || SourceText.Contains("ElementBatcher.cpp") || SourceFile.AbsolutePath.Contains("AnimationRuntime.cpp") || SourceText.Contains("AnimationRuntime.cpp") || SourceFile.AbsolutePath.Contains("AnimEncoding.cpp") || SourceText.Contains("AnimEncoding.cpp") || SourceFile.AbsolutePath.Contains("TextRenderComponent.cpp") || SourceText.Contains("TextRenderComponent.cpp") || SourceFile.AbsolutePath.Contains("SWidget.cpp") || SourceText.Contains("SWidget.cpp") || SourceFile.AbsolutePath.Contains("SCanvas.cpp") || SourceText.Contains("SCanvas.cpp") || SourceFile.AbsolutePath.Contains("ShaderCore.cpp") || SourceText.Contains("ShaderCore.cpp") @@ -689,7 +695,7 @@ namespace UnrealBuildTool Console.WriteLine("Forcing {0} to --O3!", SourceFile.AbsolutePath); AllArgs = AllArgs.Replace("-Oz", "-O3"); - } + }*/ // RPC utility parameters are in terms of the Mac side CompileAction.WorkingDirectory = GetMacDevSrcRoot(); @@ -945,7 +951,10 @@ namespace UnrealBuildTool FileItem OutputFile; OutputFile = FileItem.GetItemByPath(FullDestPathRoot); + FileItem ZipOutputFile; + ZipOutputFile = FileItem.GetItemByPath(FullDestPathRoot + ".zip"); FileItem DestFile = LocalToRemoteFileItem(OutputFile, false); + FileItem ZipDestFile = LocalToRemoteFileItem(ZipOutputFile, false); // Make the compile action Action GenDebugAction = ActionGraph.Add(ActionType.GenerateDebugInfo); @@ -962,22 +971,75 @@ namespace UnrealBuildTool Executable.AbsolutePath, DestFile.AbsolutePath, Path.GetFileName(FullDestPathRoot)); - } - else + GenDebugAction.ProducedItems.Add(ZipDestFile); + Log.TraceInformation("Zip file: " + ZipDestFile.AbsolutePath); + } + else { GenDebugAction.CommandArguments = string.Format("-c 'rm -rf \"{1}\"; /usr/bin/dsymutil \"{0}\" -f -o \"{1}\"'", Executable.AbsolutePath, DestFile.AbsolutePath); } GenDebugAction.PrerequisiteItems.Add(Executable); - GenDebugAction.ProducedItems.Add(DestFile); - GenDebugAction.StatusDescription = GenDebugAction.CommandArguments;// string.Format("Generating debug info for {0}", Path.GetFileName(Executable.AbsolutePath)); + GenDebugAction.ProducedItems.Add(DestFile); + GenDebugAction.StatusDescription = GenDebugAction.CommandArguments;// string.Format("Generating debug info for {0}", Path.GetFileName(Executable.AbsolutePath)); GenDebugAction.bCanExecuteRemotely = false; - return DestFile; + return (ProjectSettings.bGeneratedSYMBundle ? ZipDestFile : DestFile); } - private static void PackageStub(string BinaryPath, string GameName, string ExeName) + /// + /// Generates pseudo pdb info for a given executable + /// + /// FileItem describing the executable to generate debug info for + /// + public FileItem GeneratePseudoPDB(FileItem Executable, ActionGraph ActionGraph) + { + // Make a file item for the source and destination files + FileItem LocalExecutable = RemoteToLocalFileItem(Executable); + string FullDestPathRoot = Path.Combine(Path.GetDirectoryName(LocalExecutable.AbsolutePath), Path.GetFileName(LocalExecutable.AbsolutePath) + ".udebugsymbols"); + string FulldSYMPathRoot = Path.Combine(Path.GetDirectoryName(LocalExecutable.AbsolutePath), Path.GetFileName(LocalExecutable.AbsolutePath) + ".dSYM"); + string PathToDWARF = Path.Combine(FulldSYMPathRoot, "Contents", "Resources", "DWARF", Path.GetFileName(LocalExecutable.AbsolutePath)); + + FileItem dSYMFile; + dSYMFile = FileItem.GetItemByPath(FulldSYMPathRoot); + FileItem dSYMOutFile = LocalToRemoteFileItem(dSYMFile, false); + + FileItem DWARFFile; + DWARFFile = FileItem.GetItemByPath(PathToDWARF); + FileItem DWARFOutFile = LocalToRemoteFileItem(DWARFFile, false); + + FileItem OutputFile; + OutputFile = FileItem.GetItemByPath(FullDestPathRoot); + FileItem DestFile = LocalToRemoteFileItem(OutputFile, false); + + // Make the compile action + Action GenDebugAction = ActionGraph.Add(ActionType.GenerateDebugInfo); + GenDebugAction.WorkingDirectory = GetMacDevEngineRoot() + "/Binaries/Mac/"; + if (!Utils.IsRunningOnMono) + { + GenDebugAction.ActionHandler = new Action.BlockingActionHandler(RPCUtilHelper.RPCActionHandler); + FileItem DsymExporter = FileItem.GetItemByPath(Path.GetFullPath(Path.Combine(BranchDirectory, "Engine/")) + "/Binaries/Mac/" + "DsymExporter"); + QueueFileForBatchUpload(DsymExporter); + QueueDirectoryForBatchUpload(DirectoryReference.MakeFromNormalizedFullPath(Path.GetFullPath(Path.Combine(BranchDirectory, "Engine/")) + "Binaries/ThirdParty/ICU/icu4c-53_1/Mac/")); + QueueDirectoryForBatchUpload(DirectoryReference.MakeFromNormalizedFullPath(Path.GetFullPath(Path.Combine(BranchDirectory, "Engine/")) + "Content/Internationalization/")); + } + + GenDebugAction.CommandPath = "sh"; + GenDebugAction.CommandArguments = string.Format("-c 'rm -rf \"{1}\"; dwarfdump --uuid {3} | cut -d\" \" -f2; chmod 777 ./DsymExporter; ./DsymExporter -UUID=$(dwarfdump --uuid {3} | cut -d\" \" -f2) \"{0}\" \"{2}\"'", + DWARFOutFile.AbsolutePath, + DestFile.AbsolutePath, + Path.GetDirectoryName(DestFile.AbsolutePath), + dSYMOutFile.AbsolutePath); + GenDebugAction.PrerequisiteItems.Add(dSYMOutFile); + GenDebugAction.ProducedItems.Add(DestFile); + GenDebugAction.StatusDescription = GenDebugAction.CommandArguments;// string.Format("Generating debug info for {0}", Path.GetFileName(Executable.AbsolutePath)); + GenDebugAction.bCanExecuteRemotely = false; + + return DestFile; + } + + private static void PackageStub(string BinaryPath, string GameName, string ExeName) { // create the ipa string IPAName = BinaryPath + "/" + ExeName + ".stub"; @@ -1230,6 +1292,10 @@ namespace UnrealBuildTool if (ProjectSettings.bGeneratedSYMFile == true || ProjectSettings.bGeneratedSYMBundle == true || BinaryLinkEnvironment.bUsePDBFiles == true) { OutputFiles.Add(GenerateDebugInfo(Executable, ActionGraph)); + if (ProjectSettings.bGenerateCrashReportSymbols) + { + OutputFiles.Add(GeneratePseudoPDB(Executable, ActionGraph)); + } } // for tvOS generate the asset catalog @@ -1301,12 +1367,19 @@ namespace UnrealBuildTool string SchemeName = AppName; - // generate the dummy project so signing works - if (AppName == "UE4Game" || AppName == "UE4Client" || Utils.IsFileUnderDirectory(Target.ProjectDirectory + "/" + AppName + ".uproject", Path.GetFullPath("../.."))) + // ensure the plist, entitlements, and provision files are properly copied + var DeployHandler = (Target.Platform == UnrealTargetPlatform.IOS ? new UEDeployIOS() : new UEDeployTVOS()); + DeployHandler.PrepTargetForDeployment(new UEBuildDeployTarget(Target)); + + // generate the dummy project so signing works + if (AppName == "UE4Game" || AppName == "UE4Client" || Utils.IsFileUnderDirectory(Target.ProjectDirectory + "/" + AppName + ".uproject", Path.GetFullPath("../.."))) { UnrealBuildTool.GenerateProjectFiles(new XcodeProjectFileGenerator(Target.ProjectFile), new string[] { "-platforms=" + (Target.Platform == UnrealTargetPlatform.IOS ? "IOS" : "TVOS"), "-NoIntellIsense", (Target.Platform == UnrealTargetPlatform.IOS ? "-iosdeployonly" : "-tvosdeployonly"), "-ignorejunk" }); Project = Path.GetFullPath("../..") + "/UE4_" + (Target.Platform == UnrealTargetPlatform.IOS ? "IOS" : "TVOS") + ".xcworkspace"; - SchemeName = "UE4"; + if (AppName == "UE4Game" || AppName == "UE4Client") + { + SchemeName = "UE4"; + } } else { @@ -1317,7 +1390,7 @@ namespace UnrealBuildTool if (Directory.Exists(Project)) { // ensure the plist, entitlements, and provision files are properly copied - var DeployHandler = (Target.Platform == UnrealTargetPlatform.IOS ? new UEDeployIOS() : new UEDeployTVOS()); + DeployHandler = (Target.Platform == UnrealTargetPlatform.IOS ? new UEDeployIOS() : new UEDeployTVOS()); DeployHandler.PrepTargetForDeployment(new UEBuildDeployTarget(Target)); var ConfigName = Target.Configuration.ToString(); @@ -1454,8 +1527,13 @@ namespace UnrealBuildTool DSYMExt = ".dSYM"; } RPCUtilHelper.CopyFile(RemoteExecutablePath + DSYMExt, FilePath.FullName + DSYMExt, false); - } - } + if (ProjectSettings.bGenerateCrashReportSymbols) + { + RPCUtilHelper.CopyFile(RemoteExecutablePath + ".udebugsymbols", FilePath.FullName + ".udebugsymbols", false); + } + + } + } } // Generate the stub diff --git a/Engine/Source/Programs/UnrealBuildTool/IOS/UEBuildIOS.cs b/Engine/Source/Programs/UnrealBuildTool/IOS/UEBuildIOS.cs index b845ef6ab667..9b45a31774b2 100644 --- a/Engine/Source/Programs/UnrealBuildTool/IOS/UEBuildIOS.cs +++ b/Engine/Source/Programs/UnrealBuildTool/IOS/UEBuildIOS.cs @@ -32,10 +32,16 @@ namespace UnrealBuildTool [ConfigFile(ConfigHierarchyType.Engine, "/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bGeneratedSYMBundle")] public readonly bool bGeneratedSYMBundle = false; - /// - /// The minimum supported version - /// - [ConfigFile(ConfigHierarchyType.Engine, "/Script/IOSRuntimeSettings.IOSRuntimeSettings", "MinimumiOSVersion")] + /// + /// Whether to generate a dSYM file or not. + /// + [ConfigFile(ConfigHierarchyType.Engine, "/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bGenerateCrashReportSymbols")] + public readonly bool bGenerateCrashReportSymbols = false; + + /// + /// The minimum supported version + /// + [ConfigFile(ConfigHierarchyType.Engine, "/Script/IOSRuntimeSettings.IOSRuntimeSettings", "MinimumiOSVersion")] private readonly string MinimumIOSVersion = null; /// @@ -110,6 +116,7 @@ namespace UnrealBuildTool [ConfigFile(ConfigHierarchyType.Engine, "/Script/IOSRuntimeSettings.IOSRuntimeSettings", "SigningCertificate")] public readonly string SigningCertificate = ""; + /// /// true if bit code should be embedded /// @@ -461,7 +468,6 @@ namespace UnrealBuildTool Target.bBuildEditor = false; Target.bBuildDeveloperTools = false; Target.bCompileAPEX = false; - Target.bRuntimePhysicsCooking = false; Target.bCompileSimplygon = false; Target.bCompileSimplygonSSF = false; Target.bBuildDeveloperTools = false; @@ -552,17 +558,16 @@ namespace UnrealBuildTool { IOSProjectSettings ProjectSettings = ReadProjectSettings(InTarget.ProjectFile); - if(ProjectSettings.bGeneratedSYMFile) - { - return ".dSYM"; - } - if(ProjectSettings.bGeneratedSYMBundle) { return ".dSYM.zip"; } + else if (ProjectSettings.bGeneratedSYMFile) + { + return ".dSYM"; + } - return ""; + return ""; } public override bool CanUseXGE() @@ -599,8 +604,9 @@ namespace UnrealBuildTool string[] BoolKeys = new string[] { "bDevForArmV7", "bDevForArm64", "bDevForArmV7S", "bShipForArmV7", "bShipForArm64", "bShipForArmV7S", "bShipForBitcode", "bGeneratedSYMFile", - "bGeneratedSYMBundle", "bEnableRemoteNotificationsSupport", "bEnableCloudKitSupport" - }; + "bGeneratedSYMBundle", "bEnableRemoteNotificationsSupport", "bEnableCloudKitSupport", + "bGenerateCrashReportSymbols" + }; string[] StringKeys = new string[] { "MinimumiOSVersion", "AdditionalLinkerFlags", diff --git a/Engine/Source/Programs/UnrealBuildTool/IOS/UEDeployIOS.cs b/Engine/Source/Programs/UnrealBuildTool/IOS/UEDeployIOS.cs index ae0e11f2ed54..a0e78f3cbf08 100644 --- a/Engine/Source/Programs/UnrealBuildTool/IOS/UEDeployIOS.cs +++ b/Engine/Source/Programs/UnrealBuildTool/IOS/UEDeployIOS.cs @@ -20,12 +20,6 @@ namespace UnrealBuildTool protected UnrealPluginLanguage UPL = null; - public void SetIOSPluginData(FileReference ProjectFile, List Architectures, List inPluginExtraData) - { - UPL = new UnrealPluginLanguage(ProjectFile, inPluginExtraData, Architectures, "", "", UnrealTargetPlatform.IOS); - //UPL.SetTrace (); - } - protected class VersionUtilities { public static string BuildDirectory @@ -145,22 +139,40 @@ namespace UnrealBuildTool /// Updates the minor version in the CFBundleVersion key of the specified PList if this is a new package. /// Also updates the key EpicAppVersion with the bundle version and the current date/time (no year) /// - public static string UpdateBundleVersion(string OldPList) + public static string UpdateBundleVersion(string OldPList, string EngineDirectory) { - string CFBundleVersion; - int Index = OldPList.IndexOf("CFBundleVersion"); - if (Index != -1) - { - int Start = OldPList.IndexOf("", Index) + ("").Length; - CFBundleVersion = OldPList.Substring(Start, OldPList.IndexOf("", Index) - Start); - CFBundleVersion = CalculateUpdatedMinorVersionString(CFBundleVersion); - } - else - { - CFBundleVersion = "0.0"; - } + string CFBundleVersion = "-1"; + if (Environment.GetEnvironmentVariable("IsBuildMachine") != "1") + { + int Index = OldPList.IndexOf("CFBundleVersion"); + if (Index != -1) + { + int Start = OldPList.IndexOf("", Index) + ("").Length; + CFBundleVersion = OldPList.Substring(Start, OldPList.IndexOf("", Index) - Start); + CFBundleVersion = CalculateUpdatedMinorVersionString(CFBundleVersion); + } + else + { + CFBundleVersion = "0.0"; + } + } + else + { + // get the changelist from version.h + string EngineVersionFile = Path.Combine(EngineDirectory, "Source", "Runtime", "Launch", "Resources", "Version.h"); + string[] EngineVersionLines = File.ReadAllLines(EngineVersionFile); + for (int i = 0; i < EngineVersionLines.Length; ++i) + { + if (EngineVersionLines[i].StartsWith("#define BUILT_FROM_CHANGELIST")) + { + CFBundleVersion = EngineVersionLines[i].Split(new char[] { ' ', '\t' })[2].Trim(' '); + break; + } + } - return CFBundleVersion; + } + + return CFBundleVersion; } } @@ -181,7 +193,7 @@ namespace UnrealBuildTool return result; } - public static bool GenerateIOSPList(FileReference ProjectFile, UnrealTargetConfiguration Config, string ProjectDirectory, bool bIsUE4Game, string GameName, string ProjectName, string InEngineDir, string AppDirectory, UEDeployIOS InThis = null) + public static bool GenerateIOSPList(FileReference ProjectFile, UnrealTargetConfiguration Config, string ProjectDirectory, bool bIsUE4Game, string GameName, string ProjectName, string InEngineDir, string AppDirectory, out bool bSupportsPortrait, out bool bSupportsLandscape, UEDeployIOS InThis = null) { // generate the Info.plist for future use string BuildDirectory = ProjectDirectory + "/Build/IOS"; @@ -212,12 +224,16 @@ namespace UnrealBuildTool bool bSupported = true; Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsPortraitOrientation", out bSupported); SupportedOrientations += bSupported ? "\t\tUIInterfaceOrientationPortrait\n" : ""; + bSupportsPortrait = bSupported; Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsUpsideDownOrientation", out bSupported); SupportedOrientations += bSupported ? "\t\tUIInterfaceOrientationPortraitUpsideDown\n" : ""; + bSupportsPortrait |= bSupported; Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsLandscapeLeftOrientation", out bSupported); SupportedOrientations += bSupported ? "\t\tUIInterfaceOrientationLandscapeLeft\n" : ""; + bSupportsLandscape = bSupported; Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsLandscapeRightOrientation", out bSupported); SupportedOrientations += bSupported ? "\t\tUIInterfaceOrientationLandscapeRight\n" : ""; + bSupportsLandscape |= bSupported; // bundle display name string BundleDisplayName; @@ -301,6 +317,8 @@ namespace UnrealBuildTool string FacebookAppID = ""; Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "FacebookAppID", out FacebookAppID); bEnableFacebookSupport = bEnableFacebookSupport && !string.IsNullOrWhiteSpace(FacebookAppID); + string FacebookDisplayName = ""; + Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "BundleDisplayName", out FacebookDisplayName); // Add remote-notifications as background mode bool bRemoteNotificationsSupported = false; @@ -355,7 +373,7 @@ namespace UnrealBuildTool Text.AppendLine("\tCFBundleSignature"); Text.AppendLine("\t????"); Text.AppendLine("\tCFBundleVersion"); - Text.AppendLine(string.Format("\t{0}", VersionUtilities.UpdateBundleVersion(OldPListData))); + Text.AppendLine(string.Format("\t{0}", VersionUtilities.UpdateBundleVersion(OldPListData, InEngineDir))); Text.AppendLine("\tCFBundleShortVersionString"); Text.AppendLine(string.Format("\t{0}", BundleShortVersion)); Text.AppendLine("\tLSRequiresIPhoneOS"); @@ -440,31 +458,35 @@ namespace UnrealBuildTool // this is a temp way to inject the iphone 6 images without needing to upgrade everyone's plist // eventually we want to generate this based on what the user has set in the project settings string[] IPhoneConfigs = - { - "Default-IPhone6-Landscape", "Landscape", "{375, 667}", "8.0", - "Default-IPhone6", "Portrait", "{375, 667}", "8.0", - "Default-IPhone6Plus-Landscape", "Landscape", "{414, 736}", "8.0", - "Default-IPhone6Plus-Portrait", "Portrait", "{414, 736}", "8.0", - "Default", "Landscape", "{320, 480}", "7.0", - "Default", "Portrait", "{320, 480}", "7.0", - "Default-568h", "Landscape", "{320, 568}", "7.0", - "Default-568h", "Portrait", "{320, 568}", "7.0", + { + "Default-IPhone6-Landscape.jpg", "Landscape", "{375, 667}", "8.0", + "Default-IPhone6.jpg", "Portrait", "{375, 667}", "8.0", + "Default-IPhone6Plus-Landscape.jpg", "Landscape", "{414, 736}", "8.0", + "Default-IPhone6Plus-Portrait.jpg", "Portrait", "{414, 736}", "8.0", + "Default.jpg", "Landscape", "{320, 480}", "7.0", + "Default.jpg", "Portrait", "{320, 480}", "7.0", + "Default-568h.png", "Landscape", "{320, 568}", "7.0", + "Default-568h.png", "Portrait", "{320, 568}", "7.0", }; Text.AppendLine("\tUILaunchImages~iphone"); Text.AppendLine("\t"); for (int ConfigIndex = 0; ConfigIndex < IPhoneConfigs.Length; ConfigIndex += 4) { - Text.AppendLine("\t\t"); - Text.AppendLine("\t\t\tUILaunchImageMinimumOSVersion"); - Text.AppendLine(string.Format("\t\t\t{0}", IPhoneConfigs[ConfigIndex + 3])); - Text.AppendLine("\t\t\tUILaunchImageName"); - Text.AppendLine(string.Format("\t\t\t{0}", IPhoneConfigs[ConfigIndex + 0])); - Text.AppendLine("\t\t\tUILaunchImageOrientation"); - Text.AppendLine(string.Format("\t\t\t{0}", IPhoneConfigs[ConfigIndex + 1])); - Text.AppendLine("\t\t\tUILaunchImageSize"); - Text.AppendLine(string.Format("\t\t\t{0}", IPhoneConfigs[ConfigIndex + 2])); - Text.AppendLine("\t\t"); + if ((bSupportsPortrait && IPhoneConfigs[ConfigIndex + 1] == "Portrait") || + (bSupportsLandscape && IPhoneConfigs[ConfigIndex + 1] == "Landscape")) + { + Text.AppendLine("\t\t"); + Text.AppendLine("\t\t\tUILaunchImageMinimumOSVersion"); + Text.AppendLine(string.Format("\t\t\t{0}", IPhoneConfigs[ConfigIndex + 3])); + Text.AppendLine("\t\t\tUILaunchImageName"); + Text.AppendLine(string.Format("\t\t\t{0}", IPhoneConfigs[ConfigIndex + 0])); + Text.AppendLine("\t\t\tUILaunchImageOrientation"); + Text.AppendLine(string.Format("\t\t\t{0}", IPhoneConfigs[ConfigIndex + 1])); + Text.AppendLine("\t\t\tUILaunchImageSize"); + Text.AppendLine(string.Format("\t\t\t{0}", IPhoneConfigs[ConfigIndex + 2])); + Text.AppendLine("\t\t"); + } } // close it out @@ -473,27 +495,31 @@ namespace UnrealBuildTool // this is a temp way to inject the iPad Pro without needing to upgrade everyone's plist // eventually we want to generate this based on what the user has set in the project settings string[] IPadConfigs = - { - "Default-Landscape", "Landscape", "{768, 1024}", "7.0", - "Default-Portrait", "Portrait", "{768, 1024}", "7.0", - "Default-Landscape-1336", "Landscape", "{1024, 1366}", "9.0", - "Default-Portrait-1336", "Portrait", "{1024, 1366}", "9.0", + { + "Default-Landscape.jpg", "Landscape", "{768, 1024}", "7.0", + "Default-Portrait.jpg", "Portrait", "{768, 1024}", "7.0", + "Default-Landscape-1336.jpg", "Landscape", "{1024, 1366}", "9.0", + "Default-Portrait-1336.jpg", "Portrait", "{1024, 1366}", "9.0", }; Text.AppendLine("\tUILaunchImages~ipad"); Text.AppendLine("\t"); for (int ConfigIndex = 0; ConfigIndex < IPadConfigs.Length; ConfigIndex += 4) { - Text.AppendLine("\t\t"); - Text.AppendLine("\t\t\tUILaunchImageMinimumOSVersion"); - Text.AppendLine(string.Format("\t\t\t{0}", IPadConfigs[ConfigIndex + 3])); - Text.AppendLine("\t\t\tUILaunchImageName"); - Text.AppendLine(string.Format("\t\t\t{0}", IPadConfigs[ConfigIndex + 0])); - Text.AppendLine("\t\t\tUILaunchImageOrientation"); - Text.AppendLine(string.Format("\t\t\t{0}", IPadConfigs[ConfigIndex + 1])); - Text.AppendLine("\t\t\tUILaunchImageSize"); - Text.AppendLine(string.Format("\t\t\t{0}", IPadConfigs[ConfigIndex + 2])); - Text.AppendLine("\t\t"); + if ((bSupportsPortrait && IPhoneConfigs[ConfigIndex + 1] == "Portrait") || + (bSupportsLandscape && IPhoneConfigs[ConfigIndex + 1] == "Landscape")) + { + Text.AppendLine("\t\t"); + Text.AppendLine("\t\t\tUILaunchImageMinimumOSVersion"); + Text.AppendLine(string.Format("\t\t\t{0}", IPadConfigs[ConfigIndex + 3])); + Text.AppendLine("\t\t\tUILaunchImageName"); + Text.AppendLine(string.Format("\t\t\t{0}", IPadConfigs[ConfigIndex + 0])); + Text.AppendLine("\t\t\tUILaunchImageOrientation"); + Text.AppendLine(string.Format("\t\t\t{0}", IPadConfigs[ConfigIndex + 1])); + Text.AppendLine("\t\t\tUILaunchImageSize"); + Text.AppendLine(string.Format("\t\t\t{0}", IPadConfigs[ConfigIndex + 2])); + Text.AppendLine("\t\t"); + } } Text.AppendLine("\t"); } @@ -525,8 +551,18 @@ namespace UnrealBuildTool { Text.AppendLine("\tFacebookAppID"); Text.AppendLine(string.Format("\t{0}", FacebookAppID)); + Text.AppendLine("\tFacebookDisplayName"); + Text.AppendLine(string.Format("\t{0}", FacebookDisplayName)); + Text.AppendLine("\tLSApplicationQueriesSchemes"); + Text.AppendLine("\t"); + Text.AppendLine("\t\tfbapi"); + Text.AppendLine("\t\tfb-messenger-api"); + Text.AppendLine("\t\tfbauth2"); + Text.AppendLine("\t\tfbshareextension"); + Text.AppendLine("\t"); } + if (!string.IsNullOrEmpty(ExtraData)) { ExtraData = ExtraData.Replace("\\n", "\n"); @@ -574,11 +610,11 @@ namespace UnrealBuildTool InThis.UPL.ProcessPluginNode("None", "iosPListUpdates", "", ref XDoc); string result = XDoc.Declaration.ToString() + "\n" + XDoc.ToString().Replace("", ""); File.WriteAllText(PListFile, result); + + Text = new StringBuilder(result); } - else - { - File.WriteAllText(PListFile, Text.ToString()); - } + + File.WriteAllText(PListFile, Text.ToString()); if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac) { @@ -592,12 +628,37 @@ namespace UnrealBuildTool return bSkipDefaultPNGs; } - public virtual bool GeneratePList(FileReference ProjectFile, UnrealTargetConfiguration Config, string ProjectDirectory, bool bIsUE4Game, string GameName, string ProjectName, string InEngineDir, string AppDirectory) + public virtual bool GeneratePList(FileReference ProjectFile, UnrealTargetConfiguration Config, string ProjectDirectory, bool bIsUE4Game, string GameName, string ProjectName, string InEngineDir, string AppDirectory, out bool bSupportsPortrait, out bool bSupportsLandscape) { - return GenerateIOSPList(ProjectFile, Config, ProjectDirectory, bIsUE4Game, GameName, ProjectName, InEngineDir, AppDirectory, this); + List ProjectArches = new List(); + ProjectArches.Add("None"); + + FileReference ReceiptFilename; + string BundlePath; + + // get the receipt + if (bIsUE4Game) + { + ReceiptFilename = TargetReceipt.GetDefaultPath(UnrealBuildTool.EngineDirectory, "UE4Game", UnrealTargetPlatform.IOS, Config, ""); + BundlePath = Path.Combine(UnrealBuildTool.EngineDirectory.ToString(), "Intermediate", "IOS-Deploy", "UE4Game", Config.ToString(), "Payload", "UE4Game.app"); + } + else + { + ReceiptFilename = TargetReceipt.GetDefaultPath(new DirectoryReference(ProjectDirectory), ProjectName, UnrealTargetPlatform.IOS, Config, ""); + BundlePath = Path.Combine(ProjectDirectory, "Binaries", "IOS", "Payload", ProjectName + ".app"); + } + + string RelativeEnginePath = UnrealBuildTool.EngineDirectory.MakeRelativeTo(DirectoryReference.GetCurrentDirectory()); + + UPL = new UnrealPluginLanguage(ProjectFile, CollectPluginDataPaths(TargetReceipt.Read(ReceiptFilename, UnrealBuildTool.EngineDirectory, new DirectoryReference(ProjectDirectory))), ProjectArches, "", "", UnrealTargetPlatform.IOS); + + // Passing in true for distribution is not ideal here but given the way that ios packaging happens and this call chain it seems unavoidable for now, maybe there is a way to correctly pass it in that I can't find? + UPL.Init(ProjectArches, true, RelativeEnginePath, BundlePath, ProjectDirectory, Config.ToString()); + + return GenerateIOSPList(ProjectFile, Config, ProjectDirectory, bIsUE4Game, GameName, ProjectName, InEngineDir, AppDirectory, out bSupportsPortrait, out bSupportsLandscape, this); } - protected virtual void CopyGraphicsResources(bool bSkipDefaultPNGs, string InEngineDir, string AppDirectory, string BuildDirectory, string IntermediateDir) + protected virtual void CopyGraphicsResources(bool bSkipDefaultPNGs, string InEngineDir, string AppDirectory, string BuildDirectory, string IntermediateDir, bool bSupportsPortrait, bool bSupportsLandscape) { // copy engine assets in (IOS and TVOS shared in IOS) if (bSkipDefaultPNGs) @@ -607,13 +668,55 @@ namespace UnrealBuildTool } else { - CopyFiles(InEngineDir + "/Build/IOS/Resources/Graphics", AppDirectory, "*.png", true); + CopyFiles(InEngineDir + "/Build/IOS/Resources/Graphics", AppDirectory, "Icon*.png", true); + if (bSupportsPortrait) + { + CopyFiles(InEngineDir + "/Build/IOS/Resources/Graphics", AppDirectory, "Default-IPhone6.jpg", true); + CopyFiles(InEngineDir + "/Build/IOS/Resources/Graphics", AppDirectory, "Default-IPhone6Plus-Portrait.jpg", true); + // CopyFiles(InEngineDir + "/Build/IOS/Resources/Graphics", AppDirectory, "Default-Portrait.jpg", true); + CopyFiles(InEngineDir + "/Build/IOS/Resources/Graphics", AppDirectory, "Default-Portrait@2x.jpg", true); +// CopyFiles(InEngineDir + "/Build/IOS/Resources/Graphics", AppDirectory, "Default-Portrait-1336.jpg", true); + CopyFiles(InEngineDir + "/Build/IOS/Resources/Graphics", AppDirectory, "Default-Portrait-1336@2x.jpg", true); + } + if (bSupportsLandscape) + { + CopyFiles(InEngineDir + "/Build/IOS/Resources/Graphics", AppDirectory, "Default-IPhone6-Landscape.jpg", true); + CopyFiles(InEngineDir + "/Build/IOS/Resources/Graphics", AppDirectory, "Default-IPhone6Plus-Landscape.jpg", true); +// CopyFiles(InEngineDir + "/Build/IOS/Resources/Graphics", AppDirectory, "Default-Landscape.jpg", true); + CopyFiles(InEngineDir + "/Build/IOS/Resources/Graphics", AppDirectory, "Default-Landscape@2x.jpg", true); +// CopyFiles(InEngineDir + "/Build/IOS/Resources/Graphics", AppDirectory, "Default-Landscape-1336.jpg", true); + CopyFiles(InEngineDir + "/Build/IOS/Resources/Graphics", AppDirectory, "Default-Landscape-1336@2x.jpg", true); + } +// CopyFiles(InEngineDir + "/Build/IOS/Resources/Graphics", AppDirectory, "Default.jpg", true); + CopyFiles(InEngineDir + "/Build/IOS/Resources/Graphics", AppDirectory, "Default@2x.jpg", true); + CopyFiles(InEngineDir + "/Build/IOS/Resources/Graphics", AppDirectory, "Default-568h@2x.png", true); } // merge game assets on top // @todo tvos: Do we want to copy IOS and TVOS both in? (Engine/IOS -> Game/IOS -> Game/TVOS)? if (Directory.Exists(BuildDirectory + "/Resources/Graphics")) { - CopyFiles(BuildDirectory + "/Resources/Graphics", AppDirectory, "*.png", true); + CopyFiles(BuildDirectory + "/Resources/Graphics", AppDirectory, "Icon*.png", true); + if (bSupportsPortrait) + { + CopyFiles(BuildDirectory + "/Resources/Graphics", AppDirectory, "Default-IPhone6.jpg", true); + CopyFiles(BuildDirectory + "/Resources/Graphics", AppDirectory, "Default-IPhone6Plus-Portrait.jpg", true); +// CopyFiles(BuildDirectory + "/Resources/Graphics", AppDirectory, "Default-Portrait.jpg", true); + CopyFiles(BuildDirectory + "/Resources/Graphics", AppDirectory, "Default-Portrait@2x.jpg", true); +// CopyFiles(BuildDirectory + "/Resources/Graphics", AppDirectory, "Default-Portrait-1336.jpg", true); + CopyFiles(BuildDirectory + "/Resources/Graphics", AppDirectory, "Default-Portrait-1336@2x.jpg", true); + } + if (bSupportsLandscape) + { + CopyFiles(BuildDirectory + "/Resources/Graphics", AppDirectory, "Default-IPhone6-Landscape.jpg", true); + CopyFiles(BuildDirectory + "/Resources/Graphics", AppDirectory, "Default-IPhone6Plus-Landscape.jpg", true); +// CopyFiles(BuildDirectory + "/Resources/Graphics", AppDirectory, "Default-Landscape.jpg", true); + CopyFiles(BuildDirectory + "/Resources/Graphics", AppDirectory, "Default-Landscape@2x.jpg", true); +// CopyFiles(BuildDirectory + "/Resources/Graphics", AppDirectory, "Default-Landscape-1336.jpg", true); + CopyFiles(BuildDirectory + "/Resources/Graphics", AppDirectory, "Default-Landscape-1336@2x.jpg", true); + } +// CopyFiles(BuildDirectory + "/Resources/Graphics", AppDirectory, "Default.jpg", true); + CopyFiles(BuildDirectory + "/Resources/Graphics", AppDirectory, "Default@2x.jpg", true); + CopyFiles(BuildDirectory + "/Resources/Graphics", AppDirectory, "Default-568h@2x.png", true); } } @@ -769,15 +872,17 @@ namespace UnrealBuildTool DestFileInfo.Attributes = DestFileInfo.Attributes & ~FileAttributes.ReadOnly; } - // compile the launch .xib - // @todo tvos: Is this needed for IOS, but not TVOS? -// string LaunchXib = InEngineDir + "/Build/IOS/Resources/Interface/LaunchScreen.xib"; -// if (File.Exists(BuildDirectory + "/Resources/Interface/LaunchScreen.xib")) -// { -// LaunchXib = BuildDirectory + "/Resources/Interface/LaunchScreen.xib"; -// } + // compile the launch .xib + // @todo tvos: Is this needed for IOS, but not TVOS? + // string LaunchXib = InEngineDir + "/Build/IOS/Resources/Interface/LaunchScreen.xib"; + // if (File.Exists(BuildDirectory + "/Resources/Interface/LaunchScreen.xib")) + // { + // LaunchXib = BuildDirectory + "/Resources/Interface/LaunchScreen.xib"; + // } - bool bSkipDefaultPNGs = GeneratePList(ProjectFile, Config, InProjectDirectory, bIsUE4Game, GameName, InProjectName, InEngineDir, AppDirectory); + bool bSupportsPortrait = true; + bool bSupportsLandscape = false; + bool bSkipDefaultPNGs = GeneratePList(ProjectFile, Config, InProjectDirectory, bIsUE4Game, GameName, InProjectName, InEngineDir, AppDirectory, out bSupportsPortrait, out bSupportsLandscape); // ensure the destination is writable if (File.Exists(AppDirectory + "/" + GameName)) @@ -791,7 +896,7 @@ namespace UnrealBuildTool if (!bCreateStubIPA) { - CopyGraphicsResources(bSkipDefaultPNGs, InEngineDir, AppDirectory, BuildDirectory, IntermediateDirectory); + CopyGraphicsResources(bSkipDefaultPNGs, InEngineDir, AppDirectory, BuildDirectory, IntermediateDirectory, bSupportsPortrait, bSupportsLandscape); // copy additional engine framework assets in // @todo tvos: TVOS probably needs its own assets? @@ -833,43 +938,15 @@ namespace UnrealBuildTool DecoratedGameName = String.Format("{0}-{1}-{2}", GameName, InTarget.Platform.ToString(), InTarget.Configuration.ToString()); } - // Run through iOS APL file - string BaseSoName = InTarget.OutputPaths[0].FullName; - - IOSProjectSettings ProjectSettings = ((IOSPlatform)UEBuildPlatform.GetBuildPlatform(UnrealTargetPlatform.IOS)).ReadProjectSettings(InTarget.ProjectFile); - - List ProjectArches; - if(InTarget.Configuration == UnrealTargetConfiguration.Shipping) - { - ProjectArches = ProjectSettings.ShippingArchitectures.ToList(); - } - else - { - ProjectArches = ProjectSettings.NonShippingArchitectures.ToList(); - } - - // get the receipt - UnrealTargetPlatform Platform = InTarget.Platform; - UnrealTargetConfiguration Configuration = InTarget.Configuration; - string ProjectBaseName = Path.GetFileName(BaseSoName).Replace("-" + Platform, "").Replace("-" + Configuration, "").Replace(".so", ""); - string ReceiptFilename = TargetReceipt.GetDefaultPath(InTarget.ProjectDirectory.FullName, ProjectBaseName, Platform, Configuration, ""); - Log.TraceInformation("Receipt Filename: {0}", ReceiptFilename); - SetIOSPluginData(InTarget.ProjectFile, ProjectArches, CollectPluginDataPaths(TargetReceipt.Read(ReceiptFilename))); - - string BundlePath = Path.Combine (ProjectDirectory, "Binaries", "IOS", "Payload", ProjectBaseName + ".app"); - - // Passing in true for distribution is not ideal here but given the way that ios packaging happens and this call chain it seems unavoidable for now, maybe there is a way to correctly pass it in that I can't find? - string RelativeEnginePath = UnrealBuildTool.EngineDirectory.MakeRelativeTo(DirectoryReference.GetCurrentDirectory()); - UPL.Init (ProjectArches, true, RelativeEnginePath, BundlePath, ProjectDirectory, Configuration.ToString()); - if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac && Environment.GetEnvironmentVariable("UBT_NO_POST_DEPLOY") != "true") { return PrepForUATPackageOrDeploy(InTarget.Configuration, InTarget.ProjectFile, GameName, ProjectDirectory, BuildPath + "/" + DecoratedGameName, "../../Engine", false, "", false, InTarget.bCreateStubIPA); } else { - // @todo tvos merge: This used to copy the bundle back - where did that code go? It needs to be fixed up for TVOS directories - GeneratePList(InTarget.ProjectFile, InTarget.Configuration, ProjectDirectory, bIsUE4Game, GameName, (InTarget.ProjectFile == null) ? "" : Path.GetFileNameWithoutExtension(InTarget.ProjectFile.FullName), "../../Engine", ""); + // @todo tvos merge: This used to copy the bundle back - where did that code go? It needs to be fixed up for TVOS directories + bool bSupportPortrait, bSupportLandscape; + GeneratePList(InTarget.ProjectFile, InTarget.Configuration, ProjectDirectory, bIsUE4Game, GameName, (InTarget.ProjectFile == null) ? "" : Path.GetFileNameWithoutExtension(InTarget.ProjectFile.FullName), "../../Engine", "", out bSupportPortrait, out bSupportLandscape); } return true; } diff --git a/Engine/Source/Programs/UnrealBuildTool/Linux/LinuxToolChain.cs b/Engine/Source/Programs/UnrealBuildTool/Linux/LinuxToolChain.cs index 9481d949d5ee..b1bf7b3c841f 100644 --- a/Engine/Source/Programs/UnrealBuildTool/Linux/LinuxToolChain.cs +++ b/Engine/Source/Programs/UnrealBuildTool/Linux/LinuxToolChain.cs @@ -1,4 +1,4 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; @@ -14,7 +14,7 @@ namespace UnrealBuildTool { string Architecture; - public LinuxToolChain(string InArchitecture) + public LinuxToolChain(string InArchitecture) : base(CppPlatform.Linux) { Architecture = InArchitecture; @@ -41,6 +41,10 @@ namespace UnrealBuildTool { GCCPath = null; } + + // When compiling on Linux, use a faster way to relink circularly dependent libraries. + // Race condition between actions linking to the .so and action overwriting it is avoided thanks to inodes + bUseFixdeps = false; } else { @@ -77,6 +81,9 @@ namespace UnrealBuildTool ArPath = "ar.exe"; RanlibPath = "ranlib.exe"; StripPath = "strip.exe"; + + // When cross-compiling on Windows, use old FixDeps. It is slow, but it does not have timing issues + bUseFixdeps = (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Win64 || BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Win32); } if (!DetermineCompilerVersion()) @@ -335,8 +342,9 @@ namespace UnrealBuildTool // test without this next line? Result += " -funwind-tables"; // generate unwind tables as they seem to be needed for stack tracing (why??) Result += " -Wsequence-point"; // additional warning not normally included in Wall: warns if order of operations is ambigious - //Result += " -Wunreachable-code"; // additional warning not normally included in Wall: warns if there is code that will never be executed - not helpful due to bIsGCC and similar + //Result += " -Wunreachable-code"; // additional warning not normally included in Wall: warns if there is code that will never be executed - not helpful due to bIsGCC and similar //Result += " -Wshadow"; // additional warning not normally included in Wall: warns if there variable/typedef shadows some other variable - not helpful because we have gobs of code that shadows variables + Result += " -Wdelete-non-virtual-dtor"; Result += ArchitectureSpecificSwitches(CompileEnvironment.Architecture); @@ -349,8 +357,8 @@ namespace UnrealBuildTool // GCC only option Result += " -fno-strict-aliasing"; Result += " -Wno-sign-compare"; // needed to suppress: comparison between signed and unsigned integer expressions - Result += " -Wno-enum-compare"; // Stats2.h triggers this (ALIGNOF(int64) <= DATA_ALIGN) - Result += " -Wno-return-type"; // Variant.h triggers this + Result += " -Wno-enum-compare"; // Stats2.h triggers this (alignof(int64) <= DATA_ALIGN) + Result += " -Wno-return-type"; // Variant.h triggers this Result += " -Wno-unused-local-typedefs"; Result += " -Wno-multichar"; Result += " -Wno-unused-but-set-variable"; @@ -423,7 +431,7 @@ namespace UnrealBuildTool //Result += " -fsanitize=address"; // detect address based errors (support properly and link to libasan) } - // debug info + // debug info // bCreateDebugInfo is normally set for all configurations, including Shipping - this is needed to enable callstack in Shipping builds (proper resolution: UEPLAT-205, separate files with debug info) if (CompileEnvironment.bCreateDebugInfo) { @@ -529,9 +537,9 @@ namespace UnrealBuildTool return Result; } - // Conditionally enable (default disabled) generation of information about every class with virtual functions for use by the C++ runtime type identification features - // (`dynamic_cast' and `typeid'). If you don't use those parts of the language, you can save some space by using -fno-rtti. - // Note that exception handling uses the same information, but it will generate it as needed. + // Conditionally enable (default disabled) generation of information about every class with virtual functions for use by the C++ runtime type identification features + // (`dynamic_cast' and `typeid'). If you don't use those parts of the language, you can save some space by using -fno-rtti. + // Note that exception handling uses the same information, but it will generate it as needed. static string GetRTTIFlag(CppCompileEnvironment CompileEnvironment) { string Result = ""; @@ -602,7 +610,7 @@ namespace UnrealBuildTool } Result += " -Wl,-rpath=${ORIGIN}/../../../Engine/Binaries/ThirdParty/OpenAL/Linux/" + LinkEnvironment.Architecture; Result += " -Wl,-rpath=${ORIGIN}/../../../Engine/Binaries/ThirdParty/CEF3/Linux"; - Result += " -Wl,-rpath=${ORIGIN}/../../../Engine/Binaries/ThirdParty/OpenVR/OpenVRv1_0_2/Linux/" + LinkEnvironment.Architecture; + Result += " -Wl,-rpath=${ORIGIN}/../../../Engine/Binaries/ThirdParty/OpenVR/OpenVRv1_0_6/linux64"; // Some OS ship ld with new ELF dynamic tags, which use DT_RUNPATH vs DT_RPATH. Since DT_RUNPATH do not propagate to dlopen()ed DSOs, // this breaks the editor on such systems. See https://kenai.com/projects/maxine/lists/users/archive/2011-01/message/12 for details @@ -705,18 +713,27 @@ namespace UnrealBuildTool /// static int CompilerVersionPatch = -1; + /// + /// Whether to use old, slower way to relink circularly dependent libraries. + /// It makes sense to use it when cross-compiling on Windows due to race conditions between actions reading and modifying the libs. + /// + private bool bUseFixdeps = false; + /// /// Track which scripts need to be deleted before appending to /// private bool bHasWipedFixDepsScript = false; + /// + /// Holds all the binaries for a particular target (except maybe the executable itself). + /// + private static List AllBinaries = new List(); + /// /// Tracks that information about used C++ library is only printed once /// private bool bHasPrintedLibcxxInformation = false; - private static List BundleDependencies = new List(); - public override CPPOutput CompileCPPFiles(CppCompileEnvironment CompileEnvironment, List SourceFiles, string ModuleName, ActionGraph ActionGraph) { string Arguments = GetCLArguments_Global(CompileEnvironment); @@ -727,6 +744,17 @@ namespace UnrealBuildTool // inform the user which C++ library the engine is going to be compiled against - important for compatibility with third party code that uses STL bool bUseLibCxx = ShouldUseLibcxx(CompileEnvironment.Architecture); Console.WriteLine("Using {0} standard C++ library.", bUseLibCxx ? "bundled libc++" : "compiler default (most likely libstdc++)"); + + // Also print other once-per-build information + if (bUseFixdeps) + { + Console.WriteLine("Using old way to relink circularly dependent libraries (with a FixDeps step)."); + } + else + { + Console.WriteLine("Using fast way to relink circularly dependent libraries (no FixDeps)."); + } + bHasPrintedLibcxxInformation = true; } @@ -952,58 +980,65 @@ namespace UnrealBuildTool public FileItem FixDependencies(LinkEnvironment LinkEnvironment, FileItem Executable, ActionGraph ActionGraph) { - if (!LinkEnvironment.bIsCrossReferenced) + if (bUseFixdeps) + { + if (!LinkEnvironment.bIsCrossReferenced) + { + return null; + } + + Log.TraceVerbose("Adding postlink step"); + + bool bUseCmdExe = BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Win64 || BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Win32; + string ShellBinary = bUseCmdExe ? "cmd.exe" : "/bin/sh"; + string ExecuteSwitch = bUseCmdExe ? " /C" : ""; // avoid -c so scripts don't need +x + string ScriptName = bUseCmdExe ? "FixDependencies.bat" : "FixDependencies.sh"; + + FileItem FixDepsScript = FileItem.GetItemByFileReference(FileReference.Combine(LinkEnvironment.LocalShadowDirectory, ScriptName)); + + Action PostLinkAction = ActionGraph.Add(ActionType.Link); + PostLinkAction.WorkingDirectory = UnrealBuildTool.EngineSourceDirectory.FullName; + PostLinkAction.CommandPath = ShellBinary; + PostLinkAction.StatusDescription = string.Format("{0}", Path.GetFileName(Executable.AbsolutePath)); + PostLinkAction.CommandDescription = "FixDeps"; + PostLinkAction.bCanExecuteRemotely = false; + PostLinkAction.CommandArguments = ExecuteSwitch; + + PostLinkAction.CommandArguments += bUseCmdExe ? " \"" : " -c '"; + + FileItem OutputFile = FileItem.GetItemByFileReference(FileReference.Combine(LinkEnvironment.LocalShadowDirectory, Path.GetFileNameWithoutExtension(Executable.AbsolutePath) + ".link")); + + // Make sure we don't run this script until the all executables and shared libraries + // have been built. + PostLinkAction.PrerequisiteItems.Add(Executable); + foreach (FileItem Dependency in AllBinaries) + { + PostLinkAction.PrerequisiteItems.Add(Dependency); + } + + PostLinkAction.CommandArguments += ShellBinary + ExecuteSwitch + " \"" + FixDepsScript.AbsolutePath + "\" && "; + + // output file should not be empty or it will be rebuilt next time + string Touch = bUseCmdExe ? "echo \"Dummy\" >> \"{0}\" && copy /b \"{0}\" +,," : "echo \"Dummy\" >> \"{0}\""; + + PostLinkAction.CommandArguments += String.Format(Touch, OutputFile.AbsolutePath); + PostLinkAction.CommandArguments += bUseCmdExe ? "\"" : "'"; + + System.Console.WriteLine("{0} {1}", PostLinkAction.CommandPath, PostLinkAction.CommandArguments); + + // piping output through the handler during native builds is unnecessary and reportedly causes problems with tools like octobuild. + if (CrossCompiling()) + { + PostLinkAction.OutputEventHandler = new DataReceivedEventHandler(CrossCompileOutputReceivedDataEventHandler); + } + + PostLinkAction.ProducedItems.Add(OutputFile); + return OutputFile; + } + else { return null; } - - Log.TraceVerbose("Adding postlink step"); - - bool bUseCmdExe = BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Win64 || BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Win32; - string ShellBinary = bUseCmdExe ? "cmd.exe" : "/bin/sh"; - string ExecuteSwitch = bUseCmdExe ? " /C" : ""; // avoid -c so scripts don't need +x - string ScriptName = bUseCmdExe ? "FixDependencies.bat" : "FixDependencies.sh"; - - FileItem FixDepsScript = FileItem.GetItemByFileReference(FileReference.Combine(LinkEnvironment.LocalShadowDirectory, ScriptName)); - - Action PostLinkAction = ActionGraph.Add(ActionType.Link); - PostLinkAction.WorkingDirectory = UnrealBuildTool.EngineSourceDirectory.FullName; - PostLinkAction.CommandPath = ShellBinary; - PostLinkAction.StatusDescription = string.Format("{0}", Path.GetFileName(Executable.AbsolutePath)); - PostLinkAction.CommandDescription = "FixDeps"; - PostLinkAction.bCanExecuteRemotely = false; - PostLinkAction.CommandArguments = ExecuteSwitch; - - PostLinkAction.CommandArguments += bUseCmdExe ? " \"" : " -c '"; - - FileItem OutputFile = FileItem.GetItemByFileReference(FileReference.Combine(LinkEnvironment.LocalShadowDirectory, Path.GetFileNameWithoutExtension(Executable.AbsolutePath) + ".link")); - - // Make sure we don't run this script until the all executables and shared libraries - // have been built. - PostLinkAction.PrerequisiteItems.Add(Executable); - foreach (FileItem Dependency in BundleDependencies) - { - PostLinkAction.PrerequisiteItems.Add(Dependency); - } - - PostLinkAction.CommandArguments += ShellBinary + ExecuteSwitch + " \"" + FixDepsScript.AbsolutePath + "\" && "; - - // output file should not be empty or it will be rebuilt next time - string Touch = bUseCmdExe ? "echo \"Dummy\" >> \"{0}\" && copy /b \"{0}\" +,," : "echo \"Dummy\" >> \"{0}\""; - - PostLinkAction.CommandArguments += String.Format(Touch, OutputFile.AbsolutePath); - PostLinkAction.CommandArguments += bUseCmdExe ? "\"" : "'"; - - System.Console.WriteLine("{0} {1}", PostLinkAction.CommandPath, PostLinkAction.CommandArguments); - - // piping output through the handler during native builds is unnecessary and reportedly causes problems with tools like octobuild. - if (CrossCompiling()) - { - PostLinkAction.OutputEventHandler = new DataReceivedEventHandler(CrossCompileOutputReceivedDataEventHandler); - } - - PostLinkAction.ProducedItems.Add(OutputFile); - return OutputFile; } @@ -1098,7 +1133,8 @@ namespace UnrealBuildTool LinkAction.CommandArguments += string.Format(" -L\"{0}\"", Path.GetFullPath(LibraryPath)); } - List EngineAndGameLibraries = new List(); + List EngineAndGameLibrariesLinkFlags = new List(); + List EngineAndGameLibrariesFiles = new List(); // Pre-2.25 ld has symbol resolution problems when .so are mixed with .a in a single --start-group/--end-group // when linking with --as-needed. @@ -1156,10 +1192,12 @@ namespace UnrealBuildTool // We are building a cross referenced DLL so we can't actually include // dependencies at this point. Instead we add it to the list of // libraries to be used in the FixDependencies step. - EngineAndGameLibraries.Add(LibLinkFlag); - if (!LinkAction.CommandArguments.Contains("--allow-shlib-undefined")) + EngineAndGameLibrariesLinkFlags.Add(LibLinkFlag); + EngineAndGameLibrariesFiles.Add(LibraryDependency); + // it is important to add this exactly to the same place where the missing libraries would have been, it will be replaced later + if (!ExternalLibraries.Contains("--allow-shlib-undefined")) { - LinkAction.CommandArguments += string.Format(" -Wl,--allow-shlib-undefined"); + ExternalLibraries += string.Format(" -Wl,--allow-shlib-undefined"); } } else @@ -1240,63 +1278,164 @@ namespace UnrealBuildTool // are created. This script will be called by action created in FixDependencies() if (LinkEnvironment.bIsCrossReferenced && LinkEnvironment.bIsBuildingDLL) { - bool bUseCmdExe = BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Win64 || BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Win32; - string ScriptName = bUseCmdExe ? "FixDependencies.bat" : "FixDependencies.sh"; - - string FixDepsScriptPath = Path.Combine(LinkEnvironment.LocalShadowDirectory.FullName, ScriptName); - if (!bHasWipedFixDepsScript) + if (bUseFixdeps) { - bHasWipedFixDepsScript = true; - Log.TraceVerbose("Creating script: {0}", FixDepsScriptPath); - StreamWriter Writer = File.CreateText(FixDepsScriptPath); + bool bUseCmdExe = BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Win64 || BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Win32; + string ScriptName = bUseCmdExe ? "FixDependencies.bat" : "FixDependencies.sh"; + string FixDepsScriptPath = Path.Combine(LinkEnvironment.LocalShadowDirectory.FullName, ScriptName); + if (!bHasWipedFixDepsScript) + { + bHasWipedFixDepsScript = true; + Log.TraceVerbose("Creating script: {0}", FixDepsScriptPath); + StreamWriter Writer = File.CreateText(FixDepsScriptPath); + + if (bUseCmdExe) + { + Writer.Write("@echo off\n"); + Writer.Write("rem Automatically generated by UnrealBuildTool\n"); + Writer.Write("rem *DO NOT EDIT*\n\n"); + } + else + { + Writer.Write("#!/bin/sh\n"); + Writer.Write("# Automatically generated by UnrealBuildTool\n"); + Writer.Write("# *DO NOT EDIT*\n\n"); + Writer.Write("set -o errexit\n"); + } + Writer.Close(); + } + + StreamWriter FixDepsScript = File.AppendText(FixDepsScriptPath); + + string EngineAndGameLibrariesString = ""; + foreach (string Library in EngineAndGameLibrariesLinkFlags) + { + EngineAndGameLibrariesString += Library; + } + + FixDepsScript.Write(string.Format("echo Fixing {0}\n", Path.GetFileName(OutputFile.AbsolutePath))); + if (!bUseCmdExe) + { + FixDepsScript.Write(string.Format("TIMESTAMP=`stat --format %y \"{0}\"`\n", OutputFile.AbsolutePath)); + } + string FixDepsLine = LinkAction.CommandPath + " " + LinkAction.CommandArguments; + string Replace = "-Wl,--allow-shlib-undefined"; + + FixDepsLine = FixDepsLine.Replace(Replace, EngineAndGameLibrariesString); + string OutputFileForwardSlashes = OutputFile.AbsolutePath.Replace("\\", "/"); + FixDepsLine = FixDepsLine.Replace(OutputFileForwardSlashes, OutputFileForwardSlashes + ".fixed"); + FixDepsLine = FixDepsLine.Replace("$", "\\$"); + FixDepsScript.Write(FixDepsLine + "\n"); if (bUseCmdExe) { - Writer.Write("@echo off\n"); - Writer.Write("rem Automatically generated by UnrealBuildTool\n"); - Writer.Write("rem *DO NOT EDIT*\n\n"); + FixDepsScript.Write(string.Format("move /Y \"{0}.fixed\" \"{0}\"\n", OutputFile.AbsolutePath)); } else { - Writer.Write("#!/bin/sh\n"); - Writer.Write("# Automatically generated by UnrealBuildTool\n"); - Writer.Write("# *DO NOT EDIT*\n\n"); - Writer.Write("set -o errexit\n"); + FixDepsScript.Write(string.Format("mv \"{0}.fixed\" \"{0}\"\n", OutputFile.AbsolutePath)); + FixDepsScript.Write(string.Format("touch -d \"$TIMESTAMP\" \"{0}\"\n\n", OutputFile.AbsolutePath)); } - Writer.Close(); - } - - StreamWriter FixDepsScript = File.AppendText(FixDepsScriptPath); - - string EngineAndGameLibrariesString = ""; - foreach (string Library in EngineAndGameLibraries) - { - EngineAndGameLibrariesString += Library; - } - - FixDepsScript.Write(string.Format("echo Fixing {0}\n", Path.GetFileName(OutputFile.AbsolutePath))); - if (!bUseCmdExe) - { - FixDepsScript.Write(string.Format("TIMESTAMP=`stat --format %y \"{0}\"`\n", OutputFile.AbsolutePath)); - } - string FixDepsLine = LinkAction.CommandPath + " " + LinkAction.CommandArguments; - string Replace = "-Wl,--allow-shlib-undefined"; - - FixDepsLine = FixDepsLine.Replace(Replace, EngineAndGameLibrariesString); - string OutputFileForwardSlashes = OutputFile.AbsolutePath.Replace("\\", "/"); - FixDepsLine = FixDepsLine.Replace(OutputFileForwardSlashes, OutputFileForwardSlashes + ".fixed"); - FixDepsLine = FixDepsLine.Replace("$", "\\$"); - FixDepsScript.Write(FixDepsLine + "\n"); - if (bUseCmdExe) - { - FixDepsScript.Write(string.Format("move /Y \"{0}.fixed\" \"{0}\"\n", OutputFile.AbsolutePath)); + FixDepsScript.Close(); } else { - FixDepsScript.Write(string.Format("mv \"{0}.fixed\" \"{0}\"\n", OutputFile.AbsolutePath)); - FixDepsScript.Write(string.Format("touch -d \"$TIMESTAMP\" \"{0}\"\n\n", OutputFile.AbsolutePath)); + // Create the action to relink the library. This actions does not overwrite the source file so it can be executed in parallel + Action RelinkAction = ActionGraph.Add(ActionType.Link); + RelinkAction.WorkingDirectory = LinkAction.WorkingDirectory; + RelinkAction.StatusDescription = LinkAction.StatusDescription; + RelinkAction.CommandDescription = "Relink"; + RelinkAction.bCanExecuteRemotely = false; + RelinkAction.ProducedItems.Clear(); + RelinkAction.PrerequisiteItems = new List(LinkAction.PrerequisiteItems); + foreach (FileItem Dependency in EngineAndGameLibrariesFiles) + { + RelinkAction.PrerequisiteItems.Add(Dependency); + } + RelinkAction.PrerequisiteItems.Add(OutputFile); // also depend on the first link action's output + + string LinkOutputFileForwardSlashes = OutputFile.AbsolutePath.Replace("\\", "/"); + string RelinkedFileForwardSlashes = Path.Combine(LinkEnvironment.LocalShadowDirectory.FullName, OutputFile.Reference.GetFileName()) + ".relinked"; + + // cannot use the real product because we need to maintain the timestamp on it + FileReference RelinkActionDummyProductRef = FileReference.Combine(LinkEnvironment.LocalShadowDirectory, LinkEnvironment.OutputFilePath.GetFileNameWithoutExtension() + ".relinked_action_ran"); + RelinkAction.ProducedItems.Add(FileItem.GetItemByFileReference(RelinkActionDummyProductRef)); + + string EngineAndGameLibrariesString = ""; + foreach (string Library in EngineAndGameLibrariesLinkFlags) + { + EngineAndGameLibrariesString += Library; + } + + // create the action + bool bUseCmdExe = BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Win64 || BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Win32; + string ShellBinary = bUseCmdExe ? "cmd.exe" : "/bin/sh"; + string ExecuteSwitch = bUseCmdExe ? " /C" : ""; // avoid -c so scripts don't need +x + + // create the relinking step + string RelinkScriptName = string.Format((bUseCmdExe ? "Relink-{0}.bat" : "Relink-{0}.sh"), OutputFile); + string RelinkScriptFullPath = Path.Combine(LinkEnvironment.LocalShadowDirectory.FullName, RelinkScriptName); + + Log.TraceVerbose("Creating script: {0}", RelinkScriptFullPath); + StreamWriter RelinkWriter = File.CreateText(RelinkScriptFullPath); + + string RelinkInvocation = LinkAction.CommandPath + " " + LinkAction.CommandArguments; + string Replace = "-Wl,--allow-shlib-undefined"; + RelinkInvocation = RelinkInvocation.Replace(Replace, EngineAndGameLibrariesString); + + // should be the same as RelinkedFileRef + RelinkInvocation = RelinkInvocation.Replace(LinkOutputFileForwardSlashes, RelinkedFileForwardSlashes); + RelinkInvocation = RelinkInvocation.Replace("$", "\\$"); + + if (bUseCmdExe) + { + RelinkWriter.Write("@echo off\n"); + RelinkWriter.Write("rem Automatically generated by UnrealBuildTool\n"); + RelinkWriter.Write("rem *DO NOT EDIT*\n\n"); + RelinkWriter.Write("set Retries=0\n"); + RelinkWriter.Write(":relinkloop\n"); + RelinkWriter.Write("if %Retries% GEQ 10 goto failedtorelink\n"); + RelinkWriter.Write(RelinkInvocation + "\n"); + RelinkWriter.Write("if %errorlevel% neq 0 goto sleepandretry\n"); + RelinkWriter.Write("copy /B \"{0}\" \"{1}.temp\" >NUL 2>NUL\n", RelinkedFileForwardSlashes, OutputFile.AbsolutePath); + RelinkWriter.Write("if %errorlevel% neq 0 goto sleepandretry\n"); + RelinkWriter.Write("move /Y \"{0}.temp\" \"{1}\" >NUL 2>NUL\n", OutputFile.AbsolutePath, OutputFile.AbsolutePath); + RelinkWriter.Write("if %errorlevel% neq 0 goto sleepandretry\n"); + RelinkWriter.Write(string.Format("echo \"Dummy\" >> \"{0}\" && copy /b \"{0}\" +,,\n", RelinkActionDummyProductRef.FullName)); + RelinkWriter.Write("echo Relinked {0} successfully after %Retries% retries\n", OutputFile.AbsolutePath); + RelinkWriter.Write("exit 0\n"); + RelinkWriter.Write(":sleepandretry\n"); + RelinkWriter.Write("ping 127.0.0.1 -n 1 -w 5000 >NUL 2>NUL\n"); // timeout complains about lack of redirection + RelinkWriter.Write("set /a Retries+=1\n"); + RelinkWriter.Write("goto relinkloop\n"); + RelinkWriter.Write(":failedtorelink\n"); + RelinkWriter.Write("echo Failed to relink {0} after %Retries% retries\n", OutputFile.AbsolutePath); + RelinkWriter.Write("exit 1\n"); + } + else + { + RelinkWriter.Write("#!/bin/sh\n"); + RelinkWriter.Write("# Automatically generated by UnrealBuildTool\n"); + RelinkWriter.Write("# *DO NOT EDIT*\n\n"); + RelinkWriter.Write("set -o errexit\n"); + RelinkWriter.Write(RelinkInvocation + "\n"); + RelinkWriter.Write(string.Format("TIMESTAMP=`stat --format %y \"{0}\"`\n", OutputFile.AbsolutePath)); + RelinkWriter.Write("cp \"{0}\" \"{1}.temp\"\n", RelinkedFileForwardSlashes, OutputFile.AbsolutePath); + RelinkWriter.Write("mv \"{0}.temp\" \"{1}\"\n", OutputFile.AbsolutePath, OutputFile.AbsolutePath); + RelinkWriter.Write(string.Format("touch -d \"$TIMESTAMP\" \"{0}\"\n\n", OutputFile.AbsolutePath)); + RelinkWriter.Write(string.Format("echo \"Dummy\" >> \"{0}\"", RelinkActionDummyProductRef.FullName)); + } + RelinkWriter.Close(); + + RelinkAction.CommandPath = ShellBinary; + RelinkAction.CommandArguments = ExecuteSwitch + " \"" + RelinkScriptFullPath + "\""; + + // piping output through the handler during native builds is unnecessary and reportedly causes problems with tools like octobuild. + if (CrossCompiling()) + { + RelinkAction.OutputEventHandler = new DataReceivedEventHandler(CrossCompileOutputReceivedDataEventHandler); + } } - FixDepsScript.Close(); } if (CrossCompiling()) @@ -1313,9 +1452,12 @@ namespace UnrealBuildTool public override void SetupBundleDependencies(List Binaries, string GameName) { - foreach (UEBuildBinary Binary in Binaries) + if (bUseFixdeps) { - BundleDependencies.Add(FileItem.GetItemByFileReference(Binary.Config.OutputFilePath)); + foreach (UEBuildBinary Binary in Binaries) + { + AllBinaries.Add(FileItem.GetItemByFileReference(Binary.Config.OutputFilePath)); + } } } @@ -1338,17 +1480,28 @@ namespace UnrealBuildTool { var OutputFiles = base.PostBuild(Executable, BinaryLinkEnvironment, ActionGraph); - if (BinaryLinkEnvironment.bIsBuildingDLL || BinaryLinkEnvironment.bIsBuildingLibrary) + if (bUseFixdeps) { - return OutputFiles; - } + if (BinaryLinkEnvironment.bIsBuildingDLL || BinaryLinkEnvironment.bIsBuildingLibrary) + { + return OutputFiles; + } - FileItem FixDepsOutputFile = FixDependencies(BinaryLinkEnvironment, Executable, ActionGraph); - if (FixDepsOutputFile != null) + FileItem FixDepsOutputFile = FixDependencies(BinaryLinkEnvironment, Executable, ActionGraph); + if (FixDepsOutputFile != null) + { + OutputFiles.Add(FixDepsOutputFile); + } + } + else { - OutputFiles.Add(FixDepsOutputFile); + // make build product of cross-referenced DSOs to be *.relinked_action_ran, so the relinking steps are executed + if (BinaryLinkEnvironment.bIsBuildingDLL && BinaryLinkEnvironment.bIsCrossReferenced) + { + FileReference RelinkedMapRef = FileReference.Combine(BinaryLinkEnvironment.LocalShadowDirectory, BinaryLinkEnvironment.OutputFilePath.GetFileNameWithoutExtension() + ".relinked_action_ran"); + OutputFiles.Add(FileItem.GetItemByFileReference(RelinkedMapRef)); + } } - return OutputFiles; } diff --git a/Engine/Source/Programs/UnrealBuildTool/Mac/MacToolChain.cs b/Engine/Source/Programs/UnrealBuildTool/Mac/MacToolChain.cs index 40e32f7c3eaa..8302c5297253 100644 --- a/Engine/Source/Programs/UnrealBuildTool/Mac/MacToolChain.cs +++ b/Engine/Source/Programs/UnrealBuildTool/Mac/MacToolChain.cs @@ -134,6 +134,7 @@ namespace UnrealBuildTool } Result += " -Wall -Werror"; + Result += " -Wdelete-non-virtual-dtor"; //Result += " -Wsign-compare"; // fed up of not seeing the signed/unsigned warnings we get on Windows - lets enable them here too. Result += " -Wno-unused-variable"; @@ -845,7 +846,7 @@ namespace UnrealBuildTool else { string EnginePath = ConvertPath(Path.GetDirectoryName(Directory.GetCurrentDirectory())); - string InputFileRelativePath = InputFile.AbsolutePath.Replace(EnginePath, ".."); + string InputFileRelativePath = InputFile.AbsolutePath.Replace(EnginePath + "/", "../"); InputFileNames.Add(string.Format("\"{0}\"", InputFileRelativePath)); } LinkAction.PrerequisiteItems.Add(InputFile); @@ -945,11 +946,7 @@ namespace UnrealBuildTool } } - string ReadyFilePath = LinkEnvironment.IntermediateDirectory + "/" + LinkEnvironment.OutputFilePath.GetFileName() + ".ready"; - FileItem DylibReadyOutputFile = FileItem.GetItemByPath(ReadyFilePath); - FileItem RemoteDylibReadyOutputFile = LocalToRemoteFileItem(DylibReadyOutputFile, false); - - LinkAction.CommandArguments = "-c '" + LinkCommand + "; echo \"-\" >> \"" + RemoteDylibReadyOutputFile.AbsolutePath + "\"'"; + LinkAction.CommandArguments = "-c '" + LinkCommand + "'"; // Only execute linking on the local Mac. LinkAction.bCanExecuteRemotely = false; @@ -958,7 +955,6 @@ namespace UnrealBuildTool LinkAction.OutputEventHandler = new DataReceivedEventHandler(RemoteOutputReceivedEventHandler); LinkAction.ProducedItems.Add(RemoteOutputFile); - LinkAction.ProducedItems.Add(RemoteDylibReadyOutputFile); if (!DirectoryReference.Exists(LinkEnvironment.IntermediateDirectory)) { @@ -1253,9 +1249,6 @@ namespace UnrealBuildTool BinaryPath = Path.ChangeExtension(BinaryPath, ".dSYM"); } - string ReadyFilePath = LinkEnvironment.IntermediateDirectory + "/" + Path.GetFileName(MachOBinary.AbsolutePath) + ".ready"; - FileItem ReadyFile = FileItem.GetItemByPath(ReadyFilePath); - FileItem OutputFile = FileItem.GetItemByPath(BinaryPath); FileItem DestFile = LocalToRemoteFileItem(OutputFile, false); FileItem InputFile = LocalToRemoteFileItem(MachOBinary, false); @@ -1276,13 +1269,15 @@ namespace UnrealBuildTool GenDebugAction.WorkingDirectory = GetMacDevSrcRoot(); GenDebugAction.CommandPath = "sh"; - // Deletes ay existing file on the building machine, - // note that the source and dest are switched from a copy command - GenDebugAction.CommandArguments = string.Format("-c 'rm -rf \"{2}\"; \"{0}\"dsymutil -f \"{1}\" -o \"{2}\"'", + // Deletes ay existing file on the building machine. Also, waits 30 seconds, if needed, for the input file to be created in an attempt to work around + // a problem where dsymutil would exit with an error saying the input file did not exist. + // Note that the source and dest are switched from a copy command + GenDebugAction.CommandArguments = string.Format("-c 'rm -rf \"{2}\"; for i in {{1..30}}; do if [ -f \"{1}\" ] ; then break; else echo\"Waiting for {1} before generating dSYM file.\"; sleep 1; fi; done; \"{0}\"dsymutil -f \"{1}\" -o \"{2}\"'", Settings.ToolchainDir, InputFile.AbsolutePath, DestFile.AbsolutePath); - GenDebugAction.PrerequisiteItems.Add(LocalToRemoteFileItem(ReadyFile, false)); + GenDebugAction.PrerequisiteItems.Add(FixDylibOutputFile); + GenDebugAction.PrerequisiteItems.Add(LocalToRemoteFileItem(InputFile, false)); GenDebugAction.ProducedItems.Add(DestFile); GenDebugAction.CommandDescription = ""; GenDebugAction.StatusDescription = "Generating " + Path.GetFileName(BinaryPath); @@ -1572,7 +1567,6 @@ namespace UnrealBuildTool foreach (UEBuildBinary Binary in InTarget.AppBinaries) { BuiltBinaries.Add(Path.GetFullPath(Binary.ToString())); - BuiltBinaries.Add(Path.GetFullPath(Binary.ToString() + ".ready")); string DebugExtension = UEBuildPlatform.GetBuildPlatform(InTarget.Platform).GetDebugInfoExtension(InTarget.Rules, Binary.Config.Type); if (DebugExtension == ".dSYM") diff --git a/Engine/Source/Programs/UnrealBuildTool/System/ActionGraph.cs b/Engine/Source/Programs/UnrealBuildTool/System/ActionGraph.cs index e3892ec8e27b..df8cefe74cfc 100644 --- a/Engine/Source/Programs/UnrealBuildTool/System/ActionGraph.cs +++ b/Engine/Source/Programs/UnrealBuildTool/System/ActionGraph.cs @@ -471,6 +471,10 @@ namespace UnrealBuildTool { Executor = new RemoteExecutor(); } + else if(ActionsToExecute.Any(x => x.ActionHandler != null)) + { + Executor = new LocalExecutor(); + } else if ((XGE.IsAvailable() && BuildConfiguration.bAllowXGE) || BuildConfiguration.bXGEExport) { Executor = new XGE(); diff --git a/Engine/Source/Programs/UnrealBuildTool/System/CPPHeaders.cs b/Engine/Source/Programs/UnrealBuildTool/System/CPPHeaders.cs index a09ee888778c..2207ed263b6c 100644 --- a/Engine/Source/Programs/UnrealBuildTool/System/CPPHeaders.cs +++ b/Engine/Source/Programs/UnrealBuildTool/System/CPPHeaders.cs @@ -8,7 +8,6 @@ using System.Text.RegularExpressions; using System.IO; using System.Runtime.Serialization; using System.Linq; -using Tools.DotNETCommon.FileContentsCacheType; namespace UnrealBuildTool { @@ -527,12 +526,29 @@ namespace UnrealBuildTool static readonly Regex UObjectRegex = new Regex("^\\s*U(CLASS|STRUCT|ENUM|INTERFACE|DELEGATE)\\b", RegexOptions.Compiled | RegexOptions.Multiline); // Maintains a cache of file contents - private static FileContentsCacheType FileContentsCache = new FileContentsCacheType(); + private static Dictionary FileContentsCache = new Dictionary(); + + private static string GetFileContents(string Filename) + { + string Contents; + if (FileContentsCache.TryGetValue(Filename, out Contents)) + { + return Contents; + } + + using (var Reader = new StreamReader(Filename, System.Text.Encoding.UTF8)) + { + Contents = Reader.ReadToEnd(); + FileContentsCache.Add(Filename, Contents); + } + + return Contents; + } // Checks if a file contains UObjects public static bool DoesFileContainUObjects(string Filename) { - string Contents = FileContentsCache.GetContents(Filename); + string Contents = GetFileContents(Filename); return UObjectRegex.IsMatch(Contents); } @@ -575,7 +591,7 @@ namespace UnrealBuildTool string FileToRead = CPPFile.AbsolutePath; // Read lines from the C++ file. - string FileContents = FileContentsCache.GetContents(FileToRead); + string FileContents = GetFileContents(FileToRead); if (string.IsNullOrEmpty(FileContents)) { return Result; diff --git a/Engine/Source/Programs/UnrealBuildTool/System/CommandLine.cs b/Engine/Source/Programs/UnrealBuildTool/System/CommandLine.cs index 33526b97228f..8d2ae86e28dc 100644 --- a/Engine/Source/Programs/UnrealBuildTool/System/CommandLine.cs +++ b/Engine/Source/Programs/UnrealBuildTool/System/CommandLine.cs @@ -71,7 +71,7 @@ namespace UnrealBuildTool } else { - if(FieldInfo.FieldType != typeof(bool) && !Attribute.ValueAfterSpace && !Prefix.EndsWith("=")) + if(FieldInfo.FieldType != typeof(bool) && !Attribute.ValueAfterSpace && Attribute.Value == null && !Prefix.EndsWith("=")) { Prefix = Prefix + "="; } diff --git a/Engine/Source/Programs/UnrealBuildTool/System/ConfigFile.cs b/Engine/Source/Programs/UnrealBuildTool/System/ConfigFile.cs index acc56913fa0e..8d8dfb918018 100644 --- a/Engine/Source/Programs/UnrealBuildTool/System/ConfigFile.cs +++ b/Engine/Source/Programs/UnrealBuildTool/System/ConfigFile.cs @@ -177,7 +177,7 @@ namespace UnrealBuildTool { if(!TryAddConfigLine(CurrentSection, Line, StartIdx, EndIdx, DefaultAction)) { - Console.WriteLine("Couldn't parse '{0}'", Line); + Console.WriteLine("Couldn't parse '{0}' in {1} of {2}", Line, CurrentSection, Location.FullName); } break; } diff --git a/Engine/Source/Programs/UnrealBuildTool/System/CPPEnvironment.cs b/Engine/Source/Programs/UnrealBuildTool/System/CppCompileEnvironment.cs similarity index 98% rename from Engine/Source/Programs/UnrealBuildTool/System/CPPEnvironment.cs rename to Engine/Source/Programs/UnrealBuildTool/System/CppCompileEnvironment.cs index c1351f5c956c..c48407f8aadd 100644 --- a/Engine/Source/Programs/UnrealBuildTool/System/CPPEnvironment.cs +++ b/Engine/Source/Programs/UnrealBuildTool/System/CppCompileEnvironment.cs @@ -254,11 +254,6 @@ namespace UnrealBuildTool /// public bool bAllowLTCG; - /// - /// Enabled code analysis mode - /// - public bool bEnableCodeAnalysis; - /// /// Whether to log detailed timing info from the compiler /// @@ -358,7 +353,6 @@ namespace UnrealBuildTool bSupportEditAndContinue = Other.bSupportEditAndContinue; bUseIncrementalLinking = Other.bUseIncrementalLinking; bAllowLTCG = Other.bAllowLTCG; - bEnableCodeAnalysis = Other.bEnableCodeAnalysis; bPrintTimingInfo = Other.bPrintTimingInfo; bAllowRemotelyCompiledPCHs = Other.bAllowRemotelyCompiledPCHs; IncludePaths = new CppIncludePaths(Other.IncludePaths); diff --git a/Engine/Source/Programs/UnrealBuildTool/System/EddieGenerator.cs b/Engine/Source/Programs/UnrealBuildTool/System/EddieGenerator.cs index e1544a22844d..41f2fe430ee7 100644 --- a/Engine/Source/Programs/UnrealBuildTool/System/EddieGenerator.cs +++ b/Engine/Source/Programs/UnrealBuildTool/System/EddieGenerator.cs @@ -114,7 +114,7 @@ namespace UnrealBuildTool if (bGeneratingGameProjectFiles) { - IncludeEngineSource = true; + bIncludeEngineSource = true; } } } diff --git a/Engine/Source/Programs/UnrealBuildTool/System/ExternalExecution.cs b/Engine/Source/Programs/UnrealBuildTool/System/ExternalExecution.cs index c3b6e66c8930..450a36a083c3 100644 --- a/Engine/Source/Programs/UnrealBuildTool/System/ExternalExecution.cs +++ b/Engine/Source/Programs/UnrealBuildTool/System/ExternalExecution.cs @@ -181,7 +181,7 @@ namespace UnrealBuildTool public string PCH; /// - /// Base (i.e. extensionless) path+filename of the .generated files + /// Base (i.e. extensionless) path+filename of the .gen files /// public string GeneratedCPPFilenameBase; @@ -276,12 +276,13 @@ namespace UnrealBuildTool } } - public UHTManifest(UEBuildTarget Target, string InRootLocalPath, string InRootBuildPath, IEnumerable ModuleInfo, bool bUsePrecompiled) + public UHTManifest(UEBuildTarget Target, string InRootLocalPath, string InRootBuildPath, string InExternalDependenciesFile, IEnumerable ModuleInfo, bool bUsePrecompiled) { IsGameTarget = (Target.TargetType != TargetType.Program); RootLocalPath = InRootLocalPath; RootBuildPath = InRootBuildPath; TargetName = Target.GetTargetName(); + ExternalDependenciesFile = InExternalDependenciesFile; Modules = ModuleInfo.Select(Info => new Module { @@ -304,6 +305,7 @@ namespace UnrealBuildTool public string RootLocalPath; // The engine path on the local machine public string RootBuildPath; // The engine path on the build machine, if different (e.g. Mac/iOS builds) public string TargetName; // Name of the target currently being compiled + public string ExternalDependenciesFile; // File to contain additional dependencies that the generated code depends on public List Modules; } @@ -317,7 +319,7 @@ namespace UnrealBuildTool /// Generates a UHTModuleInfo for a particular named module under a directory. /// /// - public static UHTModuleInfo CreateUHTModuleInfo(IEnumerable HeaderFilenames, string ModuleName, DirectoryReference ModuleDirectory, UHTModuleType ModuleType, EGeneratedCodeVersion GeneratedCodeVersion) + public static UHTModuleInfo CreateUHTModuleInfo(IEnumerable HeaderFilenames, string ModuleName, DirectoryReference ModuleDirectory, UHTModuleType ModuleType, EGeneratedCodeVersion GeneratedCodeVersion) { DirectoryReference ClassesFolder = DirectoryReference.Combine(ModuleDirectory, "Classes"); DirectoryReference PublicFolder = DirectoryReference.Combine(ModuleDirectory, "Public"); @@ -326,19 +328,19 @@ namespace UnrealBuildTool List PublicUObjectHeaders = new List(); List PrivateUObjectHeaders = new List(); - foreach (string Header in HeaderFilenames) + foreach (FileReference Header in HeaderFilenames) { // Check to see if we know anything about this file. If we have up-to-date cached information about whether it has // UObjects or not, we can skip doing a test here. - FileItem UObjectHeaderFileItem = FileItem.GetExistingItemByPath(Header); + FileItem UObjectHeaderFileItem = FileItem.GetExistingItemByFileReference(Header); if (CPPHeaders.DoesFileContainUObjects(UObjectHeaderFileItem.AbsolutePath)) { - if (new FileReference(UObjectHeaderFileItem.AbsolutePath).IsUnderDirectory(ClassesFolder)) + if (UObjectHeaderFileItem.Reference.IsUnderDirectory(ClassesFolder)) { AllClassesHeaders.Add(UObjectHeaderFileItem); } - else if (new FileReference(UObjectHeaderFileItem.AbsolutePath).IsUnderDirectory(PublicFolder)) + else if (UObjectHeaderFileItem.Reference.IsUnderDirectory(PublicFolder)) { PublicUObjectHeaders.Add(UObjectHeaderFileItem); } @@ -387,29 +389,29 @@ namespace UnrealBuildTool return Type.GetValueOrDefault(); } - public static UHTModuleType? GetEngineModuleTypeBasedOnLocation(FileReference ModuleFileName) + public static UHTModuleType? GetEngineModuleTypeBasedOnLocation(DirectoryReference SourceDirectory, FileReference ModuleFileName) { - if (ModuleFileName.IsUnderDirectory(UnrealBuildTool.EngineSourceRuntimeDirectory)) + if (ModuleFileName.IsUnderDirectory(DirectoryReference.Combine(SourceDirectory, "Runtime"))) { return UHTModuleType.EngineRuntime; } - if (ModuleFileName.IsUnderDirectory(UnrealBuildTool.EngineSourceDeveloperDirectory)) + if (ModuleFileName.IsUnderDirectory(DirectoryReference.Combine(SourceDirectory, "Developer"))) { return UHTModuleType.EngineDeveloper; } - if (ModuleFileName.IsUnderDirectory(UnrealBuildTool.EngineSourceEditorDirectory)) + if (ModuleFileName.IsUnderDirectory(DirectoryReference.Combine(SourceDirectory, "Editor"))) { return UHTModuleType.EngineEditor; } - - if (ModuleFileName.IsUnderDirectory(UnrealBuildTool.EngineSourceProgramsDirectory)) + + if (ModuleFileName.IsUnderDirectory(DirectoryReference.Combine(SourceDirectory, "Programs"))) { return UHTModuleType.Program; } - if (ModuleFileName.IsUnderDirectory(UnrealBuildTool.EngineSourceThirdPartyDirectory)) + if (ModuleFileName.IsUnderDirectory(DirectoryReference.Combine(SourceDirectory, "ThirdParty"))) { return UHTModuleType.EngineThirdParty; } @@ -487,12 +489,12 @@ namespace UnrealBuildTool if (UHTModuleInfo.Info.PublicUObjectClassesHeaders.Count > 0 || UHTModuleInfo.Info.PrivateUObjectHeaders.Count > 0 || UHTModuleInfo.Info.PublicUObjectHeaders.Count > 0) { // If we've got this far and there are no source files then it's likely we're installed and ignoring - // engine files, so we don't need a .generated.cpp either + // engine files, so we don't need a .gen.cpp either UEBuildModuleCPP.AutoGenerateCppInfoClass.BuildInfoClass BuildInfo = null; - UHTModuleInfo.Info.GeneratedCPPFilenameBase = Path.Combine(Module.GeneratedCodeDirectory.FullName, UHTModuleInfo.Info.ModuleName) + ".generated"; + UHTModuleInfo.Info.GeneratedCPPFilenameBase = Path.Combine(Module.GeneratedCodeDirectory.FullName, UHTModuleInfo.Info.ModuleName) + ".gen"; if (Module.SourceFilesToBuild.Count != 0) { - BuildInfo = new UEBuildModuleCPP.AutoGenerateCppInfoClass.BuildInfoClass(UHTModuleInfo.Info.GeneratedCPPFilenameBase + "*.cpp"); + BuildInfo = new UEBuildModuleCPP.AutoGenerateCppInfoClass.BuildInfoClass(Path.Combine(Module.GeneratedCodeDirectory.FullName, "*.gen.cpp")); } Module.AutoGenerateCppInfo = new UEBuildModuleCPP.AutoGenerateCppInfoClass(BuildInfo); @@ -545,11 +547,10 @@ namespace UnrealBuildTool { UnrealTargetConfiguration Config = BuildConfiguration.bForceDebugUnrealHeaderTool ? UnrealTargetConfiguration.Debug : UnrealTargetConfiguration.Development; - string ReceiptFileName = TargetReceipt.GetDefaultPath(UnrealBuildTool.EngineDirectory.FullName, "UnrealHeaderTool", BuildHostPlatform.Current.Platform, Config, ""); - TargetReceipt Receipt = TargetReceipt.Read(ReceiptFileName); - Receipt.ExpandPathVariables(UnrealBuildTool.EngineDirectory, UnrealBuildTool.EngineDirectory); + FileReference ReceiptFileName = TargetReceipt.GetDefaultPath(UnrealBuildTool.EngineDirectory, "UnrealHeaderTool", BuildHostPlatform.Current.Platform, Config, ""); + TargetReceipt Receipt = TargetReceipt.Read(ReceiptFileName, UnrealBuildTool.EngineDirectory, null); - string HeaderToolPath = Receipt.BuildProducts[0].Path; + string HeaderToolPath = Receipt.BuildProducts[0].Path.FullName; return HeaderToolPath; } @@ -564,20 +565,19 @@ namespace UnrealBuildTool using (ScopedTimer TimestampTimer = new ScopedTimer("GetHeaderToolTimestamp")) { // Try to read the receipt for UHT. - string ReceiptPath = TargetReceipt.GetDefaultPath(UnrealBuildTool.EngineDirectory.FullName, "UnrealHeaderTool", BuildHostPlatform.Current.Platform, UnrealTargetConfiguration.Development, null); - if (!File.Exists(ReceiptPath)) + FileReference ReceiptPath = TargetReceipt.GetDefaultPath(UnrealBuildTool.EngineDirectory, "UnrealHeaderTool", BuildHostPlatform.Current.Platform, UnrealTargetConfiguration.Development, null); + if (!FileReference.Exists(ReceiptPath)) { Timestamp = DateTime.MaxValue; return false; } TargetReceipt Receipt; - if (!TargetReceipt.TryRead(ReceiptPath, out Receipt)) + if (!TargetReceipt.TryRead(ReceiptPath, UnrealBuildTool.EngineDirectory, null, out Receipt)) { Timestamp = DateTime.MaxValue; return false; } - Receipt.ExpandPathVariables(UnrealBuildTool.EngineDirectory, UnrealBuildTool.EngineDirectory); // Check all the binaries exist, and that all the DLLs are built against the right version if (!CheckBinariesExist(Receipt) || !CheckDynamicLibaryVersionsMatch(Receipt)) @@ -605,7 +605,7 @@ namespace UnrealBuildTool { if (BuildProduct.Type == BuildProductType.Executable || BuildProduct.Type == BuildProductType.DynamicLibrary) { - if (!File.Exists(BuildProduct.Path)) + if (!FileReference.Exists(BuildProduct.Path)) { Log.TraceWarning("Missing binary: {0}", BuildProduct.Path); bExist = false; @@ -623,13 +623,13 @@ namespace UnrealBuildTool /// static bool CheckDynamicLibaryVersionsMatch(TargetReceipt Receipt) { - List> BinaryVersions = new List>(); + List> BinaryVersions = new List>(); foreach (BuildProduct BuildProduct in Receipt.BuildProducts) { if (BuildProduct.Type == BuildProductType.DynamicLibrary) { - int Version = BuildHostPlatform.Current.GetDllApiVersion(BuildProduct.Path); - BinaryVersions.Add(new Tuple(BuildProduct.Path, Version)); + int Version = BuildHostPlatform.Current.GetDllApiVersion(BuildProduct.Path.FullName); + BinaryVersions.Add(new Tuple(BuildProduct.Path, Version)); } } @@ -637,10 +637,10 @@ namespace UnrealBuildTool if (BinaryVersions.Count > 0 && !BinaryVersions.All(x => x.Item2 == BinaryVersions[0].Item2)) { Log.TraceWarning("Detected mismatch in binary versions:"); - foreach (Tuple BinaryVersion in BinaryVersions) + foreach (Tuple BinaryVersion in BinaryVersions) { Log.TraceWarning(" {0} has API version {1}", BinaryVersion.Item1, BinaryVersion.Item2); - File.Delete(BinaryVersion.Item1); + FileReference.Delete(BinaryVersion.Item1); } bMatch = false; } @@ -660,7 +660,7 @@ namespace UnrealBuildTool { if (BuildProduct.Type == BuildProductType.Executable || BuildProduct.Type == BuildProductType.DynamicLibrary) { - DateTime WriteTime = File.GetLastWriteTime(BuildProduct.Path); + DateTime WriteTime = FileReference.GetLastWriteTime(BuildProduct.Path); if (WriteTime > LatestWriteTime) { LatestWriteTime = WriteTime; @@ -671,9 +671,9 @@ namespace UnrealBuildTool } /// - /// Gets the timestamp of CoreUObject.generated.cpp file. + /// Gets the timestamp of CoreUObject.gen.cpp file. /// - /// Last write time of CoreUObject.generated.cpp or DateTime.MaxValue if it doesn't exist. + /// Last write time of CoreUObject.gen.cpp or DateTime.MaxValue if it doesn't exist. private static DateTime GetCoreGeneratedTimestamp(string ModuleName, string ModuleGeneratedCodeDirectory) { // In Installed Builds, we don't check the timestamps on engine headers. Default to a very old date. @@ -682,15 +682,11 @@ namespace UnrealBuildTool return DateTime.MinValue; } - // Otherwise look for CoreUObject.generated.cpp or CoreUObject.generated.1.cpp - string[] Suffixes = { ".generated.cpp", ".generated.1.cpp" }; - foreach(string Suffix in Suffixes) + // Otherwise look for CoreUObject.init.gen.cpp + FileInfo CoreGeneratedFileInfo = new FileInfo(Path.Combine(ModuleGeneratedCodeDirectory, ModuleName + ".init.gen.cpp")); + if (CoreGeneratedFileInfo.Exists) { - FileInfo CoreGeneratedFileInfo = new FileInfo(Path.Combine(ModuleGeneratedCodeDirectory, ModuleName + Suffix)); - if (CoreGeneratedFileInfo.Exists) - { - return CoreGeneratedFileInfo.LastWriteTime; - } + return CoreGeneratedFileInfo.LastWriteTime; } // Doesn't exist, so use a 'newer that everything' date to force rebuild headers. @@ -706,7 +702,7 @@ namespace UnrealBuildTool /// True if the code files are out of date private static bool AreGeneratedCodeFilesOutOfDate(List UObjectModules, DateTime HeaderToolTimestamp, bool bUsePrecompiled) { - // Get CoreUObject.generated.cpp timestamp. If the source files are older than the CoreUObject generated code, we'll + // Get CoreUObject.init.gen.cpp timestamp. If the source files are older than the CoreUObject generated code, we'll // need to regenerate code for the module DateTime? CoreGeneratedTimestamp = null; { @@ -729,7 +725,7 @@ namespace UnrealBuildTool foreach (UHTModuleInfo Module in UObjectModules) { // If we're using a precompiled engine, skip skip checking timestamps for modules that are under the engine directory - if (bUsePrecompiled && Module.ModuleDirectory.IsUnderDirectory(UnrealBuildTool.EngineDirectory)) + if (bUsePrecompiled && UnrealBuildTool.IsUnderAnEngineDirectory(Module.ModuleDirectory)) { continue; } @@ -826,6 +822,36 @@ namespace UnrealBuildTool return false; } + /// + /// Determines if any external dependencies for generated code is out of date + /// + /// Path to the external dependencies file + /// True if any external dependencies are out of date + private static bool AreExternalDependenciesOutOfDate(FileReference ExternalDependenciesFile) + { + if (!FileReference.Exists(ExternalDependenciesFile)) + { + return true; + } + + DateTime LastWriteTime = File.GetLastWriteTimeUtc(ExternalDependenciesFile.FullName); + + string[] Lines = File.ReadAllLines(ExternalDependenciesFile.FullName); + foreach (string Line in Lines) + { + string ExternalDependencyFile = Line.Trim(); + if (ExternalDependencyFile.Length > 0) + { + if (!File.Exists(ExternalDependencyFile) || File.GetLastWriteTimeUtc(ExternalDependencyFile) > LastWriteTime) + { + return true; + } + } + } + + return false; + } + /// /// Updates the intermediate include directory timestamps of all the passed in UObject modules /// @@ -841,7 +867,7 @@ namespace UnrealBuildTool if (GeneratedCodeDirectoryInfo.Exists) { // Don't write anything to the engine directory if we're running an installed build - if (bUsePrecompiled && Module.ModuleDirectory.IsUnderDirectory(UnrealBuildTool.EngineDirectory)) + if (bUsePrecompiled && UnrealBuildTool.IsUnderAnEngineDirectory(Module.ModuleDirectory)) { continue; } @@ -955,8 +981,16 @@ namespace UnrealBuildTool } } + // Get the file containing dependencies for the generated code + FileReference ExternalDependenciesFile = ModuleInfoFileName.ChangeExtension(".deps"); + if (AreExternalDependenciesOutOfDate(ExternalDependenciesFile)) + { + bUHTNeedsToRun = true; + bHaveHeaderTool = false; // Force UHT to build until dependency checking is fast enough to run all the time + } + // @todo ubtmake: Optimization: Ideally we could avoid having to generate this data in the case where UHT doesn't even need to run! Can't we use the existing copy? (see below use of Manifest) - UHTManifest Manifest = new UHTManifest(Target, RootLocalPath, UEBuildPlatform.GetBuildPlatform(Target.Platform).ConvertPath(RootLocalPath + '\\'), UObjectModules, Target.bUsePrecompiled); + UHTManifest Manifest = new UHTManifest(Target, RootLocalPath, UEBuildPlatform.GetBuildPlatform(Target.Platform).ConvertPath(RootLocalPath + '\\'), ExternalDependenciesFile.FullName, UObjectModules, Target.bUsePrecompiled); if (!bIsBuildingUHT && bUHTNeedsToRun) { @@ -999,11 +1033,11 @@ namespace UnrealBuildTool UBTArguments.Append(" -ignorejunk"); // Add UHT plugins to UBT command line as external plugins - if (Target.UnrealHeaderToolPlugins != null && Target.UnrealHeaderToolPlugins.Count > 0) + foreach(UEBuildPlugin EnabledPlugin in Target.EnabledPlugins) { - foreach (PluginInfo Plugin in Target.UnrealHeaderToolPlugins) + if (EnabledPlugin.Descriptor.bCanBeUsedWithUnrealHeaderTool) { - UBTArguments.Append(" -PLUGIN \"" + Plugin.File + "\""); + UBTArguments.Append(" -PLUGIN \"" + EnabledPlugin.Info.File + "\""); } } diff --git a/Engine/Source/Programs/UnrealBuildTool/System/FileFilter.cs b/Engine/Source/Programs/UnrealBuildTool/System/FileFilter.cs index b2193a85c94a..2fad53131f66 100644 --- a/Engine/Source/Programs/UnrealBuildTool/System/FileFilter.cs +++ b/Engine/Source/Programs/UnrealBuildTool/System/FileFilter.cs @@ -411,7 +411,10 @@ namespace UnrealBuildTool public List ApplyToDirectory(DirectoryReference DirectoryName, bool bIgnoreSymlinks) { List MatchingFileNames = new List(); - FindMatchesFromDirectory(new DirectoryInfo(DirectoryName.FullName), "", bIgnoreSymlinks, MatchingFileNames); + if (DirectoryReference.Exists(DirectoryName)) + { + FindMatchesFromDirectory(new DirectoryInfo(DirectoryName.FullName), "", bIgnoreSymlinks, MatchingFileNames); + } return MatchingFileNames; } @@ -425,7 +428,10 @@ namespace UnrealBuildTool public List ApplyToDirectory(DirectoryReference DirectoryName, string PrefixPath, bool bIgnoreSymlinks) { List MatchingFileNames = new List(); - FindMatchesFromDirectory(new DirectoryInfo(DirectoryName.FullName), PrefixPath.Replace('\\', '/').TrimEnd('/') + "/", bIgnoreSymlinks, MatchingFileNames); + if (DirectoryReference.Exists(DirectoryName)) + { + FindMatchesFromDirectory(new DirectoryInfo(DirectoryName.FullName), PrefixPath.Replace('\\', '/').TrimEnd('/') + "/", bIgnoreSymlinks, MatchingFileNames); + } return MatchingFileNames; } @@ -448,6 +454,36 @@ namespace UnrealBuildTool return Result; } + /// + /// Resolve an individual wildcard to a set of files + /// + /// The pattern to resolve + /// List of files matching the wildcard + public static List ResolveWildcard(string Pattern) + { + for(int Idx = FindWildcardIndex(Pattern); Idx > 0; Idx--) + { + if(Pattern[Idx] == '/' || Pattern[Idx] == '\\') + { + return ResolveWildcard(new DirectoryReference(Pattern.Substring(0, Idx)), Pattern.Substring(Idx + 1)); + } + } + return ResolveWildcard(DirectoryReference.GetCurrentDirectory(), Pattern); + } + + /// + /// Resolve an individual wildcard to a set of files + /// + /// Base directory for wildcards + /// The pattern to resolve + /// List of files matching the wildcard + public static List ResolveWildcard(DirectoryReference BaseDir, string Pattern) + { + FileFilter Filter = new FileFilter(FileFilterType.Exclude); + Filter.AddRule(Pattern); + return Filter.ApplyToDirectory(BaseDir, true); + } + /// /// Finds a list of files within a given directory which match the filter. /// diff --git a/Engine/Source/Programs/UnrealBuildTool/System/FileReference.cs b/Engine/Source/Programs/UnrealBuildTool/System/FileReference.cs index 43b856c90347..1bee4adb1610 100644 --- a/Engine/Source/Programs/UnrealBuildTool/System/FileReference.cs +++ b/Engine/Source/Programs/UnrealBuildTool/System/FileReference.cs @@ -465,6 +465,27 @@ namespace UnrealBuildTool File.WriteAllLines(Location.FullName, Contents, Encoding); } + /// + /// Writes the contents of a file + /// + /// Location of the file + /// Contents of the file + public static void WriteAllText(FileReference Location, string Contents) + { + File.WriteAllText(Location.FullName, Contents); + } + + /// + /// Writes the contents of a file + /// + /// Location of the file + /// Contents of the file + /// The encoding to use when parsing the file + public static void WriteAllText(FileReference Location, string Contents, Encoding Encoding) + { + File.WriteAllText(Location.FullName, Contents, Encoding); + } + #endregion } diff --git a/Engine/Source/Programs/UnrealBuildTool/System/FileSystemReference.cs b/Engine/Source/Programs/UnrealBuildTool/System/FileSystemReference.cs index 2d6b80554d92..d86cedaa8f9d 100644 --- a/Engine/Source/Programs/UnrealBuildTool/System/FileSystemReference.cs +++ b/Engine/Source/Programs/UnrealBuildTool/System/FileSystemReference.cs @@ -84,7 +84,7 @@ namespace UnrealBuildTool if (Length == 0) { // Multiple directory separators in a row; illegal. - throw new ArgumentException("Path fragment '{0}' contains invalid directory separators."); + throw new ArgumentException(String.Format("Path fragment '{0}' contains invalid directory separators.", Fragment)); } else if (Length == 2 && Fragment[StartIdx] == '.' && Fragment[StartIdx + 1] == '.') { diff --git a/Engine/Source/Programs/UnrealBuildTool/System/LinkEnvironment.cs b/Engine/Source/Programs/UnrealBuildTool/System/LinkEnvironment.cs index 1baae7ebc085..05ff38908368 100644 --- a/Engine/Source/Programs/UnrealBuildTool/System/LinkEnvironment.cs +++ b/Engine/Source/Programs/UnrealBuildTool/System/LinkEnvironment.cs @@ -265,6 +265,12 @@ namespace UnrealBuildTool /// public List CommonResourceFiles = new List(); + /// + /// Provides a Module Definition File (.def) to the linker to describe various attributes of a DLL. + /// Necessary when exporting functions by ordinal values instead of by name. + /// + public string ModuleDefinitionFile; + /// /// Default constructor. /// @@ -322,6 +328,7 @@ namespace UnrealBuildTool InputLibraries.AddRange(Other.InputLibraries); DefaultResourceFiles.AddRange(Other.DefaultResourceFiles); CommonResourceFiles.AddRange(Other.CommonResourceFiles); - } + ModuleDefinitionFile = Other.ModuleDefinitionFile; + } } } diff --git a/Engine/Source/Programs/UnrealBuildTool/System/ModuleDescriptor.cs b/Engine/Source/Programs/UnrealBuildTool/System/ModuleDescriptor.cs index d1546ccb39c5..a18acadaf71e 100644 --- a/Engine/Source/Programs/UnrealBuildTool/System/ModuleDescriptor.cs +++ b/Engine/Source/Programs/UnrealBuildTool/System/ModuleDescriptor.cs @@ -141,6 +141,16 @@ namespace UnrealBuildTool /// public UnrealTargetPlatform[] BlacklistPlatforms; + /// + /// List of allowed targets + /// + public TargetType[] WhitelistTargets; + + /// + /// List of disallowed targets + /// + public TargetType[] BlacklistTargets; + /// /// List of additional dependencies for building this module. /// @@ -184,6 +194,18 @@ namespace UnrealBuildTool Module.BlacklistPlatforms = BlacklistPlatforms; } + TargetType[] WhitelistTargets; + if (InObject.TryGetEnumArrayField("WhitelistTargets", out WhitelistTargets)) + { + Module.WhitelistTargets = WhitelistTargets; + } + + TargetType[] BlacklistTargets; + if (InObject.TryGetEnumArrayField("BlacklistTargets", out BlacklistTargets)) + { + Module.BlacklistTargets = BlacklistTargets; + } + string[] AdditionalDependencies; if (InObject.TryGetStringArrayField("AdditionalDependencies", out AdditionalDependencies)) { @@ -221,6 +243,24 @@ namespace UnrealBuildTool } Writer.WriteArrayEnd(); } + if (WhitelistTargets != null && WhitelistTargets.Length > 0) + { + Writer.WriteArrayStart("WhitelistTargets"); + foreach (TargetType WhitelistTarget in WhitelistTargets) + { + Writer.WriteValue(WhitelistTarget.ToString()); + } + Writer.WriteArrayEnd(); + } + if (BlacklistTargets != null && BlacklistTargets.Length > 0) + { + Writer.WriteArrayStart("BlacklistTargets"); + foreach (TargetType BlacklistTarget in BlacklistTargets) + { + Writer.WriteValue(BlacklistTarget.ToString()); + } + Writer.WriteArrayEnd(); + } if (AdditionalDependencies != null && AdditionalDependencies.Length > 0) { Writer.WriteArrayStart("AdditionalDependencies"); @@ -274,6 +314,18 @@ namespace UnrealBuildTool return false; } + // Check the target is whitelisted + if (WhitelistTargets != null && WhitelistTargets.Length > 0 && !WhitelistTargets.Contains(TargetType)) + { + return false; + } + + // Check the target is not blacklisted + if (BlacklistTargets != null && BlacklistTargets.Contains(TargetType)) + { + return false; + } + // Check the module is compatible with this target. switch (Type) { @@ -292,9 +344,9 @@ namespace UnrealBuildTool case ModuleHostType.Program: return TargetType == TargetType.Program; case ModuleHostType.ServerOnly: - return TargetType != TargetType.Client; + return TargetType != TargetType.Program && TargetType != TargetType.Client; case ModuleHostType.ClientOnly: - return TargetType != TargetType.Server; + return TargetType != TargetType.Program && TargetType != TargetType.Server; } return false; diff --git a/Engine/Source/Programs/UnrealBuildTool/System/PluginDescriptor.cs b/Engine/Source/Programs/UnrealBuildTool/System/PluginDescriptor.cs index 8319e72c6e36..c983a5fbf435 100644 --- a/Engine/Source/Programs/UnrealBuildTool/System/PluginDescriptor.cs +++ b/Engine/Source/Programs/UnrealBuildTool/System/PluginDescriptor.cs @@ -113,11 +113,6 @@ namespace UnrealBuildTool /// public string EngineVersion; - /// - /// For packaged plugins, contains the changelist that this plugin is compatible with - /// - public int CompatibleChangelist; - /// /// List of all modules associated with this plugin /// @@ -173,6 +168,11 @@ namespace UnrealBuildTool /// public CustomBuildSteps PostBuildSteps; + /// + /// Additional plugins that this plugin depends on + /// + public PluginReferenceDescriptor[] Plugins; + /// /// Private constructor. This object should not be created directly; read it from disk using FromFile() instead. /// @@ -235,7 +235,6 @@ namespace UnrealBuildTool RawObject.TryGetStringField("MarketplaceURL", out Descriptor.MarketplaceURL); RawObject.TryGetStringField("SupportURL", out Descriptor.SupportURL); RawObject.TryGetStringField("EngineVersion", out Descriptor.EngineVersion); - RawObject.TryGetIntegerField("CompatibleChangelist", out Descriptor.CompatibleChangelist); JsonObject[] ModulesArray; if (RawObject.TryGetObjectArrayField("Modules", out ModulesArray)) @@ -264,6 +263,12 @@ namespace UnrealBuildTool CustomBuildSteps.TryRead(RawObject, "PreBuildSteps", out Descriptor.PreBuildSteps); CustomBuildSteps.TryRead(RawObject, "PostBuildSteps", out Descriptor.PostBuildSteps); + JsonObject[] PluginsArray; + if(RawObject.TryGetObjectArrayField("Plugins", out PluginsArray)) + { + Descriptor.Plugins = Array.ConvertAll(PluginsArray, x => PluginReferenceDescriptor.FromJsonObject(x)); + } + return Descriptor; } catch (JsonParseException ParseException) @@ -298,10 +303,6 @@ namespace UnrealBuildTool { Writer.WriteValue("EngineVersion", EngineVersion); } - if(CompatibleChangelist != 0) - { - Writer.WriteValue("CompatibleChangelist", CompatibleChangelist); - } if(bEnabledByDefault != bPluginTypeEnabledByDefault) { Writer.WriteValue("EnabledByDefault", bEnabledByDefault); @@ -327,6 +328,8 @@ namespace UnrealBuildTool PostBuildSteps.Write(Writer, "PostBuildSteps"); } + PluginReferenceDescriptor.WriteArray(Writer, "Plugins", Plugins); + Writer.WriteObjectEnd(); } } @@ -396,6 +399,65 @@ namespace UnrealBuildTool bEnabled = bInEnabled; } + /// + /// Construct a PluginReferenceDescriptor from a Json object + /// + /// The writer for output fields + public void Write(JsonWriter Writer) + { + Writer.WriteObjectStart(); + Writer.WriteValue("Name", Name); + Writer.WriteValue("Enabled", bEnabled); + if(bEnabled && bOptional) + { + Writer.WriteValue("Optional", bOptional); + } + if(!String.IsNullOrEmpty(Description)) + { + Writer.WriteValue("Description", Description); + } + if(!String.IsNullOrEmpty(MarketplaceURL)) + { + Writer.WriteValue("MarketplaceURL", MarketplaceURL); + } + if(WhitelistPlatforms != null && WhitelistPlatforms.Length > 0) + { + Writer.WriteEnumArrayField("WhitelistPlatforms", WhitelistPlatforms); + } + if(BlacklistPlatforms != null && BlacklistPlatforms.Length > 0) + { + Writer.WriteEnumArrayField("BlacklistPlatforms", BlacklistPlatforms); + } + if(WhitelistTargets != null && WhitelistTargets.Length > 0) + { + Writer.WriteEnumArrayField("WhitelistTargets", WhitelistTargets); + } + if(BlacklistTargets != null && BlacklistTargets.Length > 0) + { + Writer.WriteEnumArrayField("BlacklistTargets", BlacklistTargets); + } + Writer.WriteObjectEnd(); + } + + /// + /// Write an array of module descriptors + /// + /// The Json writer to output to + /// Name of the array + /// Array of plugins + public static void WriteArray(JsonWriter Writer, string Name, PluginReferenceDescriptor[] Plugins) + { + if (Plugins != null && Plugins.Length > 0) + { + Writer.WriteArrayStart(Name); + foreach (PluginReferenceDescriptor Plugin in Plugins) + { + Plugin.Write(Writer); + } + Writer.WriteArrayEnd(); + } + } + /// /// Construct a PluginReferenceDescriptor from a Json object /// diff --git a/Engine/Source/Programs/UnrealBuildTool/System/PrecompiledHeaderInstance.cs b/Engine/Source/Programs/UnrealBuildTool/System/PrecompiledHeaderInstance.cs index 6b573800cb74..4e96df0b9f1e 100644 --- a/Engine/Source/Programs/UnrealBuildTool/System/PrecompiledHeaderInstance.cs +++ b/Engine/Source/Programs/UnrealBuildTool/System/PrecompiledHeaderInstance.cs @@ -21,6 +21,11 @@ namespace UnrealBuildTool /// public bool bOptimizeCode; + /// + /// Whether to enable RTTI + /// + public bool bUseRTTI; + /// /// The output files for the shared PCH /// @@ -29,10 +34,11 @@ namespace UnrealBuildTool /// /// Constructor /// - public PrecompiledHeaderInstance(FileItem HeaderFile, bool bOptimizeCode, CPPOutput Output) + public PrecompiledHeaderInstance(FileItem HeaderFile, bool bOptimizeCode, bool bUseRTTI, CPPOutput Output) { this.HeaderFile = HeaderFile; this.bOptimizeCode = bOptimizeCode; + this.bUseRTTI = bUseRTTI; this.Output = Output; } @@ -42,7 +48,7 @@ namespace UnrealBuildTool /// String representation of the object public override string ToString() { - return String.Format("{0} (Optimized={1})", HeaderFile.Reference.GetFileName(), bOptimizeCode); + return String.Format("{0} (Optimized={1}, RTTI={2})", HeaderFile.Reference.GetFileName(), bOptimizeCode, bUseRTTI); } } } diff --git a/Engine/Source/Programs/UnrealBuildTool/System/ProjectDescriptor.cs b/Engine/Source/Programs/UnrealBuildTool/System/ProjectDescriptor.cs index 469aea74550a..6033bf9076de 100644 --- a/Engine/Source/Programs/UnrealBuildTool/System/ProjectDescriptor.cs +++ b/Engine/Source/Programs/UnrealBuildTool/System/ProjectDescriptor.cs @@ -104,12 +104,18 @@ namespace UnrealBuildTool /// public CustomBuildSteps PostBuildSteps; + /// + /// Indicates if this project is an Enterprise project + /// + public bool IsEnterpriseProject; + /// /// Constructor. /// public ProjectDescriptor() { FileVersion = (int)ProjectDescriptorVersion.Latest; + IsEnterpriseProject = false; } /// @@ -143,6 +149,7 @@ namespace UnrealBuildTool RawObject.TryGetStringField("EngineAssociation", out Descriptor.EngineAssociation); RawObject.TryGetStringField("Category", out Descriptor.Category); RawObject.TryGetStringField("Description", out Descriptor.Description); + RawObject.TryGetBoolField("Enterprise", out Descriptor.IsEnterpriseProject); // Read the modules JsonObject[] ModulesArray; diff --git a/Engine/Source/Programs/UnrealBuildTool/System/ProjectFileGenerator.cs b/Engine/Source/Programs/UnrealBuildTool/System/ProjectFileGenerator.cs index 33b88a7305bd..9f464db15914 100644 --- a/Engine/Source/Programs/UnrealBuildTool/System/ProjectFileGenerator.cs +++ b/Engine/Source/Programs/UnrealBuildTool/System/ProjectFileGenerator.cs @@ -45,30 +45,35 @@ namespace UnrealBuildTool /// The newly-added folder public MasterProjectFolder AddSubFolder( string SubFolderName ) { - MasterProjectFolder ResultFolder = null; + MasterProjectFolder ResultFolder = null; - foreach (string FolderName in SubFolderName.Split(new char[1] {'\\'}, StringSplitOptions.RemoveEmptyEntries)) - { - bool AlreadyExists = false; - foreach (MasterProjectFolder ExistingFolder in SubFolders) - { - if (ExistingFolder.FolderName.Equals(FolderName, StringComparison.InvariantCultureIgnoreCase)) - { - // Already exists! - ResultFolder = ExistingFolder; - AlreadyExists = true; - break; - } - } + List FolderNames = SubFolderName.Split(new char[2] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }, 2, StringSplitOptions.RemoveEmptyEntries).ToList(); + string FirstFolderName = FolderNames[0]; - if (!AlreadyExists) - { - ResultFolder = OwnerProjectFileGenerator.AllocateMasterProjectFolder(OwnerProjectFileGenerator, SubFolderName); - SubFolders.Add(ResultFolder); - } - } + bool AlreadyExists = false; + foreach (MasterProjectFolder ExistingFolder in SubFolders) + { + if (ExistingFolder.FolderName.Equals(FirstFolderName, StringComparison.InvariantCultureIgnoreCase)) + { + // Already exists! + ResultFolder = ExistingFolder; + AlreadyExists = true; + break; + } + } - return ResultFolder; + if (!AlreadyExists) + { + ResultFolder = OwnerProjectFileGenerator.AllocateMasterProjectFolder(OwnerProjectFileGenerator, FirstFolderName); + SubFolders.Add(ResultFolder); + } + + if (FolderNames.Count > 1) + { + ResultFolder = ResultFolder.AddSubFolder(FolderNames[1]); + } + + return ResultFolder; } @@ -162,7 +167,8 @@ namespace UnrealBuildTool bool bGenerateIntelliSenseData = true; /// True if we should include documentation in the generated projects - bool IncludeDocumentation = true; + [XmlConfigFile] + bool bIncludeDocumentation = true; /// True if all documentation languages should be included in generated projects, otherwise only "INT" will be included bool bAllDocumentationLanguages = false; @@ -171,35 +177,38 @@ namespace UnrealBuildTool public static bool bUsePrecompiled = false; /// True if we should include engine source in the generated solution - protected bool IncludeEngineSource = true; + protected bool bIncludeEngineSource = true; /// True if shader source files should be included in the generated projects - bool IncludeShaderSource = true; + bool bIncludeShaderSource = true; /// True if build system files should be included - bool IncludeBuildSystemFiles = true; + bool bIncludeBuildSystemFiles = true; /// True if we should include config files (.ini files) in the generated project - bool IncludeConfigFiles = true; + bool bIncludeConfigFiles = true; /// True if we should include localization files (.int/.kor/etc files) in the generated project - bool IncludeLocalizationFiles = false; + bool bIncludeLocalizationFiles = false; /// True if we should include template files (.template files) in the generated project - bool IncludeTemplateFiles = true; + bool bIncludeTemplateFiles = true; /// True if we should include program projects in the generated solution protected bool IncludeEnginePrograms = true; /// True if we should reflect "Source" sub-directories on disk in the master project as master project directories. /// This arguably adds some visual clutter to the master project, but is truer to the on-disk file organization. - bool KeepSourceSubDirectories = true; + bool bKeepSourceSubDirectories = true; /// Relative path to the directory where the master project file will be saved to public static DirectoryReference MasterProjectPath = UnrealBuildTool.RootDirectory; // We'll save the master project to our "root" folder - /// Name of the UE4 engine project name that contains all of the engine code, config files and other files - static readonly string EngineProjectFileNameBase = "UE4"; + /// Name of the UE4 engine project that contains all of the engine code, config files and other files + public static readonly string EngineProjectFileNameBase = "UE4"; + + /// Name of the UE4 enterprise project that contains all of the enterprise code, config files and other files + public static readonly string EnterpriseProjectFileNameBase = "Studio"; /// When ProjectsAreIntermediate is true, this is the directory to store generated project files // @todo projectfiles: Ideally, projects for game modules/targets would be created in the game's Intermediate folder! @@ -255,6 +264,7 @@ namespace UnrealBuildTool public ProjectFileGenerator(FileReference InOnlyGameProject) { OnlyGameProject = InOnlyGameProject; + XmlConfig.ApplyTo(this); } /// @@ -300,7 +310,7 @@ namespace UnrealBuildTool foreach (FileReference FoundProject in FoundProjects) { VCSharpProjectFile Project = new VCSharpProjectFile(FoundProject); - Project.ShouldBuildForAllSolutionTargets = false; + Project.ShouldBuildForAllSolutionTargets = true; Project.ShouldBuildByDefaultForSolutionTargets = true; AddExistingProjectFile(Project, bForceDevelopmentConfiguration: false); ProgramsFolder.ChildProjects.Add(Project); @@ -455,14 +465,15 @@ namespace UnrealBuildTool List AllModuleFiles = DiscoverModules(AllGameProjects); ProjectFile EngineProject = null; + ProjectFile EnterpriseProject = null; Dictionary GameProjects = null; Dictionary ModProjects = null; - Dictionary ProgramProjects = null; - HashSet TemplateGameProjects = null; - HashSet SampleGameProjects = null; + Dictionary ProgramProjects = null; + Dictionary TemplateGameProjects = null; + Dictionary SampleGameProjects = null; { // Setup buildable projects for all targets - AddProjectsForAllTargets( AllGameProjects, out EngineProject, out GameProjects, out ModProjects, out ProgramProjects, out TemplateGameProjects, out SampleGameProjects ); + AddProjectsForAllTargets( AllGameProjects, out EngineProject, out EnterpriseProject, out GameProjects, out ModProjects, out ProgramProjects, out TemplateGameProjects, out SampleGameProjects ); // Add all game projects and game config files AddAllGameProjects(GameProjects, SupportedPlatformNames, RootFolder); @@ -481,12 +492,12 @@ namespace UnrealBuildTool List> DebugProjectFiles = new List>(); // Place projects into root level solution folders - if ( IncludeEngineSource ) + if ( bIncludeEngineSource ) { // If we're still missing an engine project because we don't have any targets for it, make one up. if( EngineProject == null ) { - FileReference ProjectFilePath = FileReference.Combine(IntermediateProjectFilesPath, "UE4" + ProjectFileExtension); + FileReference ProjectFilePath = FileReference.Combine(IntermediateProjectFilesPath, EngineProjectFileNameBase + ProjectFileExtension); bool bAlreadyExisted; EngineProject = FindOrAddProject(ProjectFilePath, true, out bAlreadyExisted); @@ -501,7 +512,7 @@ namespace UnrealBuildTool RootFolder.AddSubFolder( "Engine" ).ChildProjects.Add( EngineProject ); // Engine config files - if( IncludeConfigFiles ) + if( bIncludeConfigFiles ) { AddEngineConfigFiles( EngineProject ); if( IncludeEnginePrograms ) @@ -515,18 +526,18 @@ namespace UnrealBuildTool AddEngineExtrasFiles(EngineProject); // Engine localization files - if( IncludeLocalizationFiles ) + if( bIncludeLocalizationFiles ) { AddEngineLocalizationFiles( EngineProject ); } // Engine template files - if (IncludeTemplateFiles) + if (bIncludeTemplateFiles) { AddEngineTemplateFiles( EngineProject ); } - if( IncludeShaderSource ) + if( bIncludeShaderSource ) { Log.TraceVerbose( "Adding shader source code..." ); @@ -534,14 +545,14 @@ namespace UnrealBuildTool AddEngineShaderSource( EngineProject ); } - if( IncludeBuildSystemFiles ) + if( bIncludeBuildSystemFiles ) { Log.TraceVerbose( "Adding build system files..." ); AddEngineBuildFiles( EngineProject ); } - if( IncludeDocumentation ) + if( bIncludeDocumentation ) { AddEngineDocumentation( EngineProject ); } @@ -554,6 +565,11 @@ namespace UnrealBuildTool } } + if (EnterpriseProject != null) + { + RootFolder.AddSubFolder(UnrealBuildTool.EnterpriseDirectory.GetDirectoryName()).ChildProjects.Add(EnterpriseProject); + } + foreach( ProjectFile CurModProject in ModProjects.Values ) { RootFolder.AddSubFolder("Mods").ChildProjects.Add(CurModProject); @@ -562,13 +578,30 @@ namespace UnrealBuildTool foreach( ProjectFile CurGameProject in GameProjects.Values ) { // Templates go under a different solution folder than games - if( TemplateGameProjects.Contains( CurGameProject ) ) + DirectoryReference TemplateGameDirectory = TemplateGameProjects.FirstOrDefault( FolderAndProject => FolderAndProject.Value == CurGameProject ).Key; + DirectoryReference SampleGameDirectory = SampleGameProjects.FirstOrDefault( FolderAndProject => FolderAndProject.Value == CurGameProject ).Key; + + if( TemplateGameDirectory != null ) { - RootFolder.AddSubFolder( "Templates" ).ChildProjects.Add( CurGameProject ); + if( TemplateGameDirectory.IsUnderDirectory((UnrealBuildTool.EnterpriseDirectory)) ) + { + RootFolder.AddSubFolder(UnrealBuildTool.EnterpriseDirectory.GetDirectoryName() + Path.DirectorySeparatorChar + "Templates").ChildProjects.Add(CurGameProject); + } + else + { + RootFolder.AddSubFolder("Templates").ChildProjects.Add(CurGameProject); + } } - else if (SampleGameProjects.Contains( CurGameProject ) ) + else if( SampleGameDirectory != null ) { - RootFolder.AddSubFolder("Samples").ChildProjects.Add(CurGameProject); + if( SampleGameDirectory.IsUnderDirectory((UnrealBuildTool.EnterpriseDirectory)) ) + { + RootFolder.AddSubFolder(UnrealBuildTool.EnterpriseDirectory.GetDirectoryName() + Path.DirectorySeparatorChar + "Samples").ChildProjects.Add(CurGameProject); + } + else + { + RootFolder.AddSubFolder("Samples").ChildProjects.Add(CurGameProject); + } } else { @@ -580,7 +613,7 @@ namespace UnrealBuildTool if (NewProjectFiles != null) { DebugProjectFiles.AddRange(NewProjectFiles); - } + } } @@ -594,17 +627,24 @@ namespace UnrealBuildTool } - foreach( ProjectFile CurProgramProject in ProgramProjects.Values ) + foreach( KeyValuePair CurProgramProject in ProgramProjects ) { - ProjectTarget Target = CurProgramProject.ProjectTargets.FirstOrDefault(t => !String.IsNullOrEmpty(t.TargetRules.SolutionDirectory)); + ProjectTarget Target = CurProgramProject.Value.ProjectTargets.FirstOrDefault(t => !String.IsNullOrEmpty(t.TargetRules.SolutionDirectory)); if (Target != null) { - RootFolder.AddSubFolder(Target.TargetRules.SolutionDirectory).ChildProjects.Add(CurProgramProject); + RootFolder.AddSubFolder(Target.TargetRules.SolutionDirectory).ChildProjects.Add(CurProgramProject.Value); } else { - RootFolder.AddSubFolder( "Programs" ).ChildProjects.Add( CurProgramProject ); + if (CurProgramProject.Key.IsUnderDirectory(UnrealBuildTool.EnterpriseDirectory)) + { + RootFolder.AddSubFolder(UnrealBuildTool.EnterpriseDirectory.GetDirectoryName() + Path.DirectorySeparatorChar + "Programs").ChildProjects.Add(CurProgramProject.Value); + } + else + { + RootFolder.AddSubFolder( "Programs" ).ChildProjects.Add( CurProgramProject.Value ); + } } } @@ -622,7 +662,7 @@ namespace UnrealBuildTool MasterProjectFolder ProgramsFolder = RootFolder.AddSubFolder( "Programs" ); // Add UnrealBuildTool to the master project - AddUnrealBuildToolProject( ProgramsFolder, new ProjectFile[]{ } ); + AddUnrealBuildToolProject( ProgramsFolder ); // Add AutomationTool to the master project ProgramsFolder.ChildProjects.Add(AddSimpleCSharpProject("AutomationTool", bShouldBuildForAllSolutionTargets: true, bForceDevelopmentConfiguration: true)); @@ -661,6 +701,23 @@ namespace UnrealBuildTool } } + // Enterprise targets + if (EnterpriseProject != null) + { + foreach (ProjectTarget ProjectTarget in EnterpriseProject.ProjectTargets) + { + if (ProjectTarget.TargetFilePath != null) + { + // Only bother with the editor target. We want to make sure that definitions are setup to be as inclusive as possible + // for good quality IntelliSense. For example, we want WITH_EDITORONLY_DATA=1, so using the editor targets works well. + if (ProjectTarget.TargetRules.Type == TargetType.Editor) + { + IntelliSenseTargetFiles.Add(Tuple.Create(EnterpriseProject, ProjectTarget.TargetFilePath)); + } + } + } + } + // Program targets foreach( ProjectFile ProgramProject in ProgramProjects.Values ) { @@ -863,12 +920,12 @@ namespace UnrealBuildTool bool bInstalledEngineWithSource = UnrealBuildTool.IsEngineInstalled() && DirectoryReference.Exists(UnrealBuildTool.EngineSourceDirectory); - IncludeEngineSource = bAlwaysIncludeEngineModules || bInstalledEngineWithSource; - IncludeDocumentation = false; - IncludeBuildSystemFiles = false; - IncludeShaderSource = true; - IncludeTemplateFiles = false; - IncludeConfigFiles = true; + bIncludeEngineSource = bAlwaysIncludeEngineModules || bInstalledEngineWithSource; + bIncludeDocumentation = false; + bIncludeBuildSystemFiles = false; + bIncludeShaderSource = true; + bIncludeTemplateFiles = false; + bIncludeConfigFiles = true; IncludeEnginePrograms = bAlwaysIncludeEngineModules; } else @@ -890,7 +947,7 @@ namespace UnrealBuildTool // @todo projectfiles: We have engine localization files, but should we also add GAME localization files? // Game config files - if( IncludeConfigFiles ) + if( bIncludeConfigFiles ) { DirectoryReference GameConfigDirectory = DirectoryReference.Combine(GameProjectDirectory, "Config"); if( DirectoryReference.Exists(GameConfigDirectory) ) @@ -901,7 +958,7 @@ namespace UnrealBuildTool } // Game build files - if( IncludeBuildSystemFiles ) + if( bIncludeBuildSystemFiles ) { var GameBuildDirectory = DirectoryReference.Combine(GameProjectDirectory, "Build"); if( DirectoryReference.Exists(GameBuildDirectory) ) @@ -964,6 +1021,26 @@ namespace UnrealBuildTool EngineProject.AddFilesToProject(SourceFileSearch.FindFiles(UHTConfigDirectory), UnrealBuildTool.EngineDirectory); } } + private List DiscoverExtraPlugins(List AllGameProjects) + { + List AddedPlugins = new List(); + foreach (UProjectInfo GameProject in AllGameProjects) + { + ProjectDescriptor ProjectDesc = ProjectDescriptor.FromFile(GameProject.FilePath.FullName); + foreach (DirectoryReference PluginDir in ProjectDesc.AdditionalPluginDirectories) + { + // @TODO: Right now, we're only including additional plugins that are still inside a game directory. + // This is so FindProjectForModule() succeeds in matching up a project with the plugin. If + // the plugin is outside of a game directory, then we'll need to add special handling to AddProjectsForAllModules() + // and generate a standalone project, since multiple games could share the same plugin + if (PluginDir.IsUnderDirectory(GameProject.Folder)) + { + AddedPlugins.AddRange(Plugins.EnumeratePlugins(PluginDir)); + } + } + } + return AddedPlugins; + } /// /// Finds all module files (filtering by platform) @@ -974,7 +1051,7 @@ namespace UnrealBuildTool List AllModuleFiles = new List(); // Locate all modules (*.Build.cs files) - List FoundModuleFiles = RulesCompiler.FindAllRulesSourceFiles( RulesCompiler.RulesFileType.Module, GameFolders: AllGameProjects.Select(x => x.Folder).ToList(), ForeignPlugins:null, AdditionalSearchPaths:null ); + List FoundModuleFiles = RulesCompiler.FindAllRulesSourceFiles( RulesCompiler.RulesFileType.Module, GameFolders: AllGameProjects.Select(x => x.Folder).ToList(), ForeignPlugins: DiscoverExtraPlugins(AllGameProjects), AdditionalSearchPaths:null ); foreach( FileReference BuildFileName in FoundModuleFiles ) { AllModuleFiles.Add( BuildFileName ); @@ -1018,7 +1095,7 @@ namespace UnrealBuildTool List UnsupportedPlatformNameStrings = Utils.MakeListOfUnsupportedPlatforms( SupportedPlatforms ); // Locate all targets (*.Target.cs files) - List FoundTargetFiles = RulesCompiler.FindAllRulesSourceFiles( RulesCompiler.RulesFileType.Target, AllGameProjects.Select(x => x.Folder).ToList(), ForeignPlugins:null, AdditionalSearchPaths:null ); + List FoundTargetFiles = RulesCompiler.FindAllRulesSourceFiles( RulesCompiler.RulesFileType.Target, AllGameProjects.Select(x => x.Folder).ToList(), ForeignPlugins: DiscoverExtraPlugins(AllGameProjects), AdditionalSearchPaths:null ); foreach( FileReference CurTargetFile in FoundTargetFiles ) { string CleanTargetFileName = Utils.CleanDirectorySeparators( CurTargetFile.FullName ); @@ -1124,7 +1201,7 @@ namespace UnrealBuildTool } } - if( !KeepSourceSubDirectories ) + if( !bKeepSourceSubDirectories ) { if( SubFolder.FolderName.Equals( "Source", StringComparison.InvariantCultureIgnoreCase ) ) { @@ -1227,17 +1304,12 @@ namespace UnrealBuildTool /// /// Adds UnrealBuildTool to the master project /// - private void AddUnrealBuildToolProject( MasterProjectFolder ProgramsFolder, IEnumerable Dependencies ) + private void AddUnrealBuildToolProject( MasterProjectFolder ProgramsFolder ) { FileReference ProjectFileName = FileReference.Combine(UnrealBuildTool.EngineSourceDirectory, "Programs", "UnrealBuildTool", "UnrealBuildTool.csproj" ); VCSharpProjectFile UnrealBuildToolProject = new VCSharpProjectFile( ProjectFileName ); UnrealBuildToolProject.ShouldBuildForAllSolutionTargets = true; - foreach (ProjectFile Dependent in Dependencies) - { - UnrealBuildToolProject.AddDependsOnProject( Dependent ); - } - // Store it off as we need it when generating target projects. UBTProject = UnrealBuildToolProject; @@ -1322,20 +1394,29 @@ namespace UnrealBuildTool /// /// Adds all of the config files for program targets to their project files /// - private void AddEngineProgramConfigFiles( Dictionary ProgramProjects ) + private void AddEngineProgramConfigFiles( Dictionary ProgramProjects ) { - if( IncludeConfigFiles ) + if( bIncludeConfigFiles ) { - foreach( KeyValuePair ProjectFolderAndFile in ProgramProjects ) + foreach( KeyValuePair FileAndProject in ProgramProjects ) { - string ProgramFolder = ProjectFolderAndFile.Key; - ProjectFile ProgramProjectFile = ProjectFolderAndFile.Value; - - string ProgramName = ProgramFolder; + string ProgramName = FileAndProject.Key.GetFileNameWithoutAnyExtensions(); + ProjectFile ProgramProjectFile = FileAndProject.Value; // @todo projectfiles: The config folder for programs is kind of weird -- you end up going UP a few directories to get to it. This stuff is not great. // @todo projectfiles: Fragile assumption here about Programs always being under /Engine/Programs - DirectoryReference ProgramDirectory = DirectoryReference.Combine( UnrealBuildTool.EngineDirectory, "Programs", ProgramName ); + + DirectoryReference ProgramDirectory; + + if ( FileAndProject.Key.IsUnderDirectory(UnrealBuildTool.EnterpriseDirectory) ) + { + ProgramDirectory = DirectoryReference.Combine( UnrealBuildTool.EnterpriseDirectory, "Programs", ProgramName ); + } + else + { + ProgramDirectory = DirectoryReference.Combine( UnrealBuildTool.EngineDirectory, "Programs", ProgramName ); + } + DirectoryReference ProgramConfigDirectory = DirectoryReference.Combine( ProgramDirectory, "Config" ); if( DirectoryReference.Exists(ProgramConfigDirectory) ) { @@ -1508,10 +1589,8 @@ namespace UnrealBuildTool /// All mod projects /// List of *.Build.cs files for all engine programs and games /// True to gather source code from third party projects too - protected void AddProjectsForAllModules( List AllGames, Dictionary ProgramProjects, Dictionary ModProjects, List AllModuleFiles, bool bGatherThirdPartySource ) + protected void AddProjectsForAllModules( List AllGames, Dictionary ProgramProjects, Dictionary ModProjects, List AllModuleFiles, bool bGatherThirdPartySource ) { - DirectoryReference EngineSourceThirdPartyDirectory = DirectoryReference.Combine(UnrealBuildTool.EngineSourceDirectory, "ThirdParty"); - HashSet ProjectsWithPlugins = new HashSet(); foreach( FileReference CurModuleFile in AllModuleFiles ) { @@ -1524,10 +1603,10 @@ namespace UnrealBuildTool bool WantProjectFileForModule = true; // We'll keep track of whether this is an "engine" or "external" module. This is determined below while loading module rules. - bool IsEngineModule = CurModuleFile.IsUnderDirectory(UnrealBuildTool.EngineDirectory); - bool IsThirdPartyModule = CurModuleFile.IsUnderDirectory(EngineSourceThirdPartyDirectory); + bool IsEngineModule = UnrealBuildTool.IsUnderAnEngineDirectory(CurModuleFile.Directory); + bool IsThirdPartyModule = CurModuleFile.IsUnderDirectory(UnrealBuildTool.EngineSourceThirdPartyDirectory); - if( IsEngineModule && !IncludeEngineSource ) + if( IsEngineModule && !bIncludeEngineSource ) { // We were asked to exclude engine modules from the generated projects WantProjectFileForModule = false; @@ -1583,7 +1662,7 @@ namespace UnrealBuildTool ProjectFile.AddFileToProject(PluginFileName, BaseFolder); // Add plugin config files if we have any - if( IncludeConfigFiles ) + if( bIncludeConfigFiles ) { DirectoryReference PluginConfigFolder = DirectoryReference.Combine(PluginFileName.Directory, "Config"); if(DirectoryReference.Exists(PluginConfigFolder)) @@ -1600,14 +1679,14 @@ namespace UnrealBuildTool } } - private ProjectFile FindProjectForModule(FileReference CurModuleFile, List AllGames, Dictionary ProgramProjects, Dictionary ModProjects, out DirectoryReference BaseFolder) + private ProjectFile FindProjectForModule(FileReference CurModuleFile, List AllGames, Dictionary ProgramProjects, Dictionary ModProjects, out DirectoryReference BaseFolder) { string ProjectFileNameBase = null; string PossibleProgramTargetName = CurModuleFile.GetFileNameWithoutAnyExtensions(); // @todo projectfiles: This works fine for now, but is pretty busted. It assumes only one module per program and that it matches the program target file name. (see TTP 307091) - if( ProgramProjects != null && ProgramProjects.ContainsKey( PossibleProgramTargetName ) ) // @todo projectfiles: When building (in mem projects), ProgramProjects will be null so we are using the UE4 project instead + if( ProgramProjects != null && ProgramProjects.Any( ProgramProject => PossibleProgramTargetName.Equals( ProgramProject.Key.GetFileNameWithoutAnyExtensions() ) ) ) // @todo projectfiles: When building (in mem projects), ProgramProjects will be null so we are using the UE4 project instead { ProjectFileNameBase = PossibleProgramTargetName; BaseFolder = CurModuleFile.Directory; @@ -1617,6 +1696,12 @@ namespace UnrealBuildTool ProjectFileNameBase = EngineProjectFileNameBase; BaseFolder = UnrealBuildTool.EngineDirectory; } + else if( CurModuleFile.IsUnderDirectory(UnrealBuildTool.EnterpriseSourceDirectory) || + CurModuleFile.IsUnderDirectory(DirectoryReference.Combine(UnrealBuildTool.EnterpriseDirectory, "Plugins")) ) + { + ProjectFileNameBase = EnterpriseProjectFileNameBase; + BaseFolder = UnrealBuildTool.EnterpriseDirectory; + } else { // Check if it's a mod @@ -1650,24 +1735,31 @@ namespace UnrealBuildTool /// /// All game folders /// The engine project we created + /// The enterprise project we created /// Map of game folder name to all of the game projects we created /// Map of mod folder name to all the mod projects we created /// Map of program names to all of the program projects we created /// Set of template game projects we found. These will also be in the GameProjects map /// Set of sample game projects that were found - private void AddProjectsForAllTargets( List AllGames, out ProjectFile EngineProject, out Dictionary GameProjects, out Dictionary ModProjects, out Dictionary ProgramProjects, out HashSet TemplateGameProjects, out HashSet SampleGameProjects ) + private void AddProjectsForAllTargets( List AllGames, out ProjectFile EngineProject, out ProjectFile EnterpriseProject, + out Dictionary GameProjects, out Dictionary ModProjects, + out Dictionary ProgramProjects, out Dictionary TemplateGameProjects, out Dictionary SampleGameProjects ) { // As we're creating project files, we'll also keep track of whether we created an "engine" project and return that if we have one EngineProject = null; - GameProjects = new Dictionary(); - ProgramProjects = new Dictionary( StringComparer.InvariantCultureIgnoreCase ); - TemplateGameProjects = new HashSet(); - SampleGameProjects = new HashSet(); + EnterpriseProject = null; + GameProjects = new Dictionary(); + ProgramProjects = new Dictionary(); + TemplateGameProjects = new Dictionary(); + SampleGameProjects = new Dictionary(); // Get some standard directories DirectoryReference EngineSourceProgramsDirectory = DirectoryReference.Combine(UnrealBuildTool.EngineSourceDirectory, "Programs"); DirectoryReference TemplatesDirectory = DirectoryReference.Combine(UnrealBuildTool.EngineDirectory, "..", "Templates"); DirectoryReference SamplesDirectory = DirectoryReference.Combine(UnrealBuildTool.EngineDirectory, "..", "Samples"); + DirectoryReference EnterpriseSourceProgramsDirectory = DirectoryReference.Combine(UnrealBuildTool.EnterpriseSourceDirectory, "Programs"); + DirectoryReference EnterpriseTemplatesDirectory = DirectoryReference.Combine(UnrealBuildTool.EnterpriseDirectory, "Templates"); + DirectoryReference EnterpriseSamplesDirectory = DirectoryReference.Combine(UnrealBuildTool.EnterpriseDirectory, "Samples"); // Find all of the target files. This will filter out any modules or targets that don't // belong to platforms we're generating project files for. @@ -1678,6 +1770,7 @@ namespace UnrealBuildTool // Check to see if this is an Engine target. That is, the target is located under the "Engine" folder bool IsEngineTarget = false; + bool IsEnterpriseTarget = false; bool WantProjectFileForTarget = true; if(TargetFilePath.IsUnderDirectory(UnrealBuildTool.EngineDirectory)) { @@ -1690,7 +1783,21 @@ namespace UnrealBuildTool } else if(TargetFilePath.IsUnderDirectory(UnrealBuildTool.EngineSourceDirectory)) { - WantProjectFileForTarget = IncludeEngineSource; + WantProjectFileForTarget = bIncludeEngineSource; + } + } + else if (TargetFilePath.IsUnderDirectory(UnrealBuildTool.EnterpriseSourceDirectory)) + { + // This is an enterprise target + IsEnterpriseTarget = true; + + if(TargetFilePath.IsUnderDirectory(EnterpriseSourceProgramsDirectory)) + { + WantProjectFileForTarget = IncludeEnginePrograms; + } + else if(TargetFilePath.IsUnderDirectory(UnrealBuildTool.EnterpriseSourceDirectory)) + { + WantProjectFileForTarget = bIncludeEngineSource; } } @@ -1701,7 +1808,14 @@ namespace UnrealBuildTool FileReference CheckProjectFile; if(!UProjectInfo.TryGetProjectForTarget(TargetName, out CheckProjectFile)) { - RulesAssembly = RulesCompiler.CreateEngineRulesAssembly(); + if(TargetFilePath.IsUnderDirectory(UnrealBuildTool.EnterpriseDirectory)) + { + RulesAssembly = RulesCompiler.CreateEnterpriseRulesAssembly(); + } + else + { + RulesAssembly = RulesCompiler.CreateEngineRulesAssembly(); + } } else { @@ -1725,6 +1839,10 @@ namespace UnrealBuildTool { ProjectFileNameBase = EngineProjectFileNameBase; } + else if (IsEnterpriseTarget) + { + ProjectFileNameBase = EnterpriseProjectFileNameBase; + } else { // Figure out which game project this target belongs to @@ -1758,15 +1876,19 @@ namespace UnrealBuildTool ProjectFile.IsForeignProject = bGeneratingGameProjectFiles && OnlyGameProject != null && TargetFilePath.IsUnderDirectory(OnlyGameProject.Directory); ProjectFile.IsGeneratedProject = true; ProjectFile.IsStubProject = UnrealBuildTool.IsProjectInstalled(); + if (TargetRulesObject.bBuildInSolutionByDefault.HasValue) + { + ProjectFile.ShouldBuildByDefaultForSolutionTargets = TargetRulesObject.bBuildInSolutionByDefault.Value; + } // Check to see if this is a template target. That is, the target is located under the "Templates" folder - bool IsTemplateTarget = TargetFilePath.IsUnderDirectory(TemplatesDirectory); - bool IsSampleTarget = TargetFilePath.IsUnderDirectory(SamplesDirectory); + bool IsTemplateTarget = TargetFilePath.IsUnderDirectory(TemplatesDirectory) || TargetFilePath.IsUnderDirectory(EnterpriseTemplatesDirectory); + bool IsSampleTarget = TargetFilePath.IsUnderDirectory(SamplesDirectory) || TargetFilePath.IsUnderDirectory(EnterpriseSamplesDirectory); DirectoryReference BaseFolder = null; if (IsProgramTarget) { - ProgramProjects[TargetName] = ProjectFile; + ProgramProjects[TargetFilePath] = ProjectFile; BaseFolder = TargetFilePath.Directory; } else if (IsEngineTarget) @@ -1781,16 +1903,28 @@ namespace UnrealBuildTool EngineProject.IsStubProject = true; } } + else if (IsEnterpriseTarget) + { + EnterpriseProject = ProjectFile; + BaseFolder = UnrealBuildTool.EnterpriseDirectory; + if (UnrealBuildTool.IsEngineInstalled()) + { + // Allow enterprise projects to be created but not built for Installed Engine builds + EnterpriseProject.IsForeignProject = false; + EnterpriseProject.IsGeneratedProject = true; + EnterpriseProject.IsStubProject = true; + } + } else { GameProjects[GameFolder] = ProjectFile; if (IsTemplateTarget) { - TemplateGameProjects.Add(ProjectFile); + TemplateGameProjects[GameFolder] = ProjectFile; } else if (IsSampleTarget) { - SampleGameProjects.Add(ProjectFile); + SampleGameProjects[GameFolder] = ProjectFile; } BaseFolder = GameFolder; diff --git a/Engine/Source/Programs/UnrealBuildTool/System/ResponseFile.cs b/Engine/Source/Programs/UnrealBuildTool/System/ResponseFile.cs index d8998091d7bd..fc289ede9930 100644 --- a/Engine/Source/Programs/UnrealBuildTool/System/ResponseFile.cs +++ b/Engine/Source/Programs/UnrealBuildTool/System/ResponseFile.cs @@ -31,7 +31,15 @@ namespace UnrealBuildTool /// public static FileReference Create(FileReference TempFileName, IEnumerable Lines, CreateOptions Options = CreateOptions.None) { - FileInfo TempFileInfo = new FileInfo(TempFileName.FullName); + FileInfo TempFileInfo; + try + { + TempFileInfo = new FileInfo(TempFileName.FullName); + } + catch(PathTooLongException) + { + throw new BuildException("Path for response file is too long ('{0}')", TempFileName); + } if (TempFileInfo.Exists) { if ((Options & CreateOptions.WriteEvenIfUnchanged) != CreateOptions.WriteEvenIfUnchanged) diff --git a/Engine/Source/Programs/UnrealBuildTool/System/RulesAssembly.cs b/Engine/Source/Programs/UnrealBuildTool/System/RulesAssembly.cs index 297b75f7ecfe..c64f5837756f 100644 --- a/Engine/Source/Programs/UnrealBuildTool/System/RulesAssembly.cs +++ b/Engine/Source/Programs/UnrealBuildTool/System/RulesAssembly.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -72,7 +72,21 @@ namespace UnrealBuildTool // Compile the assembly if (AssemblySourceFiles.Count > 0) { - CompiledAssembly = DynamicCompilation.CompileAndLoadAssembly(AssemblyFileName, AssemblySourceFiles); + List PreprocessorDefines = new List(); + PreprocessorDefines.Add("WITH_FORWARDED_MODULE_RULES_CTOR"); + PreprocessorDefines.Add("WITH_FORWARDED_TARGET_RULES_CTOR"); + + // Define macros for the UE4 version, starting with 4.17 + BuildVersion Version; + if (BuildVersion.TryRead(out Version)) + { + for(int MinorVersion = 17; MinorVersion <= Version.MinorVersion; MinorVersion++) + { + PreprocessorDefines.Add(String.Format("UE_4_{0}_OR_LATER", MinorVersion)); + } + } + + CompiledAssembly = DynamicCompilation.CompileAndLoadAssembly(AssemblyFileName, AssemblySourceFiles, PreprocessorDefines: PreprocessorDefines); } // Setup the module map @@ -299,20 +313,6 @@ namespace UnrealBuildTool throw new BuildException(Ex, "Unable to instantiate instance of '{0}' object type from compiled assembly '{1}'. Unreal Build Tool creates an instance of your module's 'Rules' object in order to find out about your module's requirements. The CLR exception details may provide more information: {2}", ModuleTypeName, CompiledAssembly.FullName, Ex.ToString()); } - // Update the run-time dependencies path to remove $(PluginDir) and replace with a full path. When the receipt is saved it'll be converted to a $(ProjectDir) or $(EngineDir) equivalent. - foreach (RuntimeDependency Dependency in RulesObject.RuntimeDependencies) - { - const string PluginDirVariable = "$(PluginDir)"; - if (Dependency.Path.StartsWith(PluginDirVariable, StringComparison.InvariantCultureIgnoreCase)) - { - PluginInfo Plugin; - if (ModuleFileToPluginInfo.TryGetValue(ModuleFileName, out Plugin)) - { - Dependency.Path = Plugin.Directory + Dependency.Path.Substring(PluginDirVariable.Length); - } - } - } - return RulesObject; } @@ -322,7 +322,7 @@ namespace UnrealBuildTool public bool IsGameModule(string InModuleName) { FileReference ModuleFileName = GetModuleFileName(InModuleName); - return (ModuleFileName != null && !ModuleFileName.IsUnderDirectory(UnrealBuildTool.EngineDirectory)); + return (ModuleFileName != null && !UnrealBuildTool.IsUnderAnEngineDirectory(ModuleFileName.Directory)); } /// diff --git a/Engine/Source/Programs/UnrealBuildTool/System/RulesCompiler.cs b/Engine/Source/Programs/UnrealBuildTool/System/RulesCompiler.cs index 6ab391527bf7..ab3eb6662d6d 100644 --- a/Engine/Source/Programs/UnrealBuildTool/System/RulesCompiler.cs +++ b/Engine/Source/Programs/UnrealBuildTool/System/RulesCompiler.cs @@ -67,6 +67,7 @@ namespace UnrealBuildTool if (bIncludeEngine) { Folders.Add(UnrealBuildTool.EngineSourceDirectory); + Folders.Add(UnrealBuildTool.EnterpriseSourceDirectory); } // @todo plugin: Disallow modules from including plugin modules as dependency modules? (except when the module is part of that plugin) @@ -76,6 +77,7 @@ namespace UnrealBuildTool if (bIncludeEngine) { RootFolders.Add(UnrealBuildTool.EngineDirectory); + RootFolders.Add(UnrealBuildTool.EnterpriseDirectory); } if (GameFolders != null) { @@ -227,6 +229,11 @@ namespace UnrealBuildTool /// private static RulesAssembly EngineRulesAssembly; + /// + /// The cached rules assembly for enterprise modules and targets. + /// + private static RulesAssembly EnterpriseRulesAssembly; + /// Map of assembly names we've already compiled and loaded to their Assembly and list of game folders. This is used to prevent /// trying to recompile the same assembly when ping-ponging between different types of targets private static Dictionary LoadedAssemblyMap = new Dictionary(); @@ -239,22 +246,49 @@ namespace UnrealBuildTool { if (EngineRulesAssembly == null) { - // Find all the rules files - List ModuleFiles = new List(FindAllRulesFiles(UnrealBuildTool.EngineSourceDirectory, RulesFileType.Module)); - List TargetFiles = new List(FindAllRulesFiles(UnrealBuildTool.EngineSourceDirectory, RulesFileType.Target)); - - // Add all the plugin modules too - IReadOnlyList EnginePlugins = Plugins.ReadEnginePlugins(UnrealBuildTool.EngineDirectory); - Dictionary ModuleFileToPluginInfo = new Dictionary(); - FindModuleRulesForPlugins(EnginePlugins, ModuleFiles, ModuleFileToPluginInfo); - - // Create a path to the assembly that we'll either load or compile - FileReference AssemblyFileName = FileReference.Combine(UnrealBuildTool.EngineDirectory, "Intermediate", "Build", "BuildRules", "UE4Rules.dll"); - EngineRulesAssembly = new RulesAssembly(EnginePlugins, ModuleFiles, TargetFiles, ModuleFileToPluginInfo, AssemblyFileName, null); + EngineRulesAssembly = CreateRulesAssembly(UnrealBuildTool.EngineDirectory, ProjectFileGenerator.EngineProjectFileNameBase, null); } return EngineRulesAssembly; } + /// + /// Creates the enterprise rules assembly + /// + /// New rules assembly. Returns null if the enterprise directory is unavailable. + public static RulesAssembly CreateEnterpriseRulesAssembly() + { + if (EnterpriseRulesAssembly == null && DirectoryReference.Exists(UnrealBuildTool.EnterpriseDirectory)) + { + EnterpriseRulesAssembly = CreateRulesAssembly(UnrealBuildTool.EnterpriseDirectory, ProjectFileGenerator.EnterpriseProjectFileNameBase, CreateEngineRulesAssembly()); + } + return EnterpriseRulesAssembly; + } + + /// + /// Creates a rules assembly + /// + /// The root directory to create rules for + /// A prefix for the assembly file name + /// The parent rules assembly + /// New rules assembly + private static RulesAssembly CreateRulesAssembly(DirectoryReference RootDirectory, string AssemblyPrefix, RulesAssembly Parent) + { + DirectoryReference SourceDirectory = DirectoryReference.Combine(RootDirectory, "Source"); + + // Find all the rules files + List ModuleFiles = new List(FindAllRulesFiles(SourceDirectory, RulesFileType.Module)); + List TargetFiles = new List(FindAllRulesFiles(SourceDirectory, RulesFileType.Target)); + + // Add all the plugin modules too + IReadOnlyList PluginInfos = Plugins.ReadEnginePlugins(RootDirectory); + Dictionary ModuleFileToPluginInfo = new Dictionary(); + FindModuleRulesForPlugins(PluginInfos, ModuleFiles, ModuleFileToPluginInfo); + + // Create a path to the assembly that we'll either load or compile + FileReference AssemblyFileName = FileReference.Combine(RootDirectory, "Intermediate", "Build", "BuildRules", AssemblyPrefix + "Rules.dll"); + return new RulesAssembly(PluginInfos, ModuleFiles, TargetFiles, ModuleFileToPluginInfo, AssemblyFileName, Parent); + } + /// /// Creates a rules assembly with the given parameters. /// @@ -266,8 +300,18 @@ namespace UnrealBuildTool RulesAssembly ProjectRulesAssembly; if (!LoadedAssemblyMap.TryGetValue(ProjectFileName, out ProjectRulesAssembly)) { - // Create the engine rules assembly - RulesAssembly Parent = CreateEngineRulesAssembly(); + ProjectDescriptor Project = ProjectDescriptor.FromFile(ProjectFileName.FullName); + + // Create the parent assembly + RulesAssembly Parent; + if (Project.IsEnterpriseProject) + { + Parent = CreateEnterpriseRulesAssembly(); + } + else + { + Parent = CreateEngineRulesAssembly(); + } // Find all the rules under the project source directory DirectoryReference ProjectDirectory = ProjectFileName.Directory; @@ -277,7 +321,7 @@ namespace UnrealBuildTool // Find all the project plugins List ProjectPlugins = new List(Plugins.ReadProjectPlugins(ProjectFileName.Directory)); - ProjectDescriptor Project = ProjectDescriptor.FromFile(ProjectFileName.FullName); + // Add the project's additional plugin directories plugins too ProjectPlugins.AddRange(Plugins.ReadAdditionalPlugins(Project.AdditionalPluginDirectories)); Dictionary ModuleFileToPluginInfo = new Dictionary(); @@ -364,6 +408,11 @@ namespace UnrealBuildTool { return FileName.FullName; } + else if (EnterpriseRulesAssembly != null && EnterpriseRulesAssembly.TryGetFileNameFromType(ExistingType, out FileName)) + { + return FileName.FullName; + } + foreach (RulesAssembly RulesAssembly in LoadedAssemblyMap.Values) { if (RulesAssembly.TryGetFileNameFromType(ExistingType, out FileName)) diff --git a/Engine/Source/Programs/UnrealBuildTool/System/TargetReceipt.cs b/Engine/Source/Programs/UnrealBuildTool/System/TargetReceipt.cs index 169d4edd8325..8f195394d2f4 100644 --- a/Engine/Source/Programs/UnrealBuildTool/System/TargetReceipt.cs +++ b/Engine/Source/Programs/UnrealBuildTool/System/TargetReceipt.cs @@ -55,6 +55,11 @@ namespace UnrealBuildTool /// A build resource which was generated by the build, but is not required for the executable to run. /// BuildResource, + + /// + /// A package which can be deployed on device (eg. *.apk for Android, *.stub for iOS) + /// + Package } /// @@ -66,7 +71,7 @@ namespace UnrealBuildTool /// /// Path to the file. /// - public string Path; + public FileReference Path; /// /// Type of the build product. @@ -90,7 +95,7 @@ namespace UnrealBuildTool /// /// Path to the build product /// Type of the build product - public BuildProduct(string InPath, BuildProductType InType) + public BuildProduct(FileReference InPath, BuildProductType InType) { Path = InPath; Type = InType; @@ -113,7 +118,7 @@ namespace UnrealBuildTool /// Path to this build product public override string ToString() { - return Path; + return Path.ToString(); } } @@ -147,7 +152,7 @@ namespace UnrealBuildTool /// /// The file that should be staged. Should use $(EngineDir) and $(ProjectDir) variables as a root, so that the target can be relocated to different machines. /// - public string Path; + public FileReference Path; /// /// How to stage this file. @@ -166,7 +171,7 @@ namespace UnrealBuildTool /// /// Path to the runtime dependency /// How to stage the given path - public RuntimeDependency(string InPath, StagedFileType InType = StagedFileType.NonUFS) + public RuntimeDependency(FileReference InPath, StagedFileType InType = StagedFileType.NonUFS) { Path = InPath; Type = InType; @@ -188,7 +193,7 @@ namespace UnrealBuildTool /// String representation of the object public override string ToString() { - return Path; + return Path.ToString(); } } @@ -218,7 +223,7 @@ namespace UnrealBuildTool /// /// Path to the runtime dependency. May include wildcards. /// How to stage this file - public void Add(string InPath, StagedFileType InType) + public void Add(FileReference InPath, StagedFileType InType) { Add(new RuntimeDependency(InPath, InType)); } @@ -298,12 +303,12 @@ namespace UnrealBuildTool /// /// All the files which are required to use precompiled binaries with this target /// - public HashSet PrecompiledBuildDependencies = new HashSet(StringComparer.InvariantCultureIgnoreCase); + public HashSet PrecompiledBuildDependencies = new HashSet(); /// /// All the files which are required runtime dependencies for precompiled binaries that are part of this target /// - public HashSet PrecompiledRuntimeDependencies = new HashSet(StringComparer.InvariantCultureIgnoreCase); + public HashSet PrecompiledRuntimeDependencies = new HashSet(); /// /// Additional build properties passed through from the module rules @@ -359,7 +364,7 @@ namespace UnrealBuildTool /// Path to the build product. /// Type of build product. /// The BuildProduct object that was created - public BuildProduct AddBuildProduct(string Path, BuildProductType Type) + public BuildProduct AddBuildProduct(FileReference Path, BuildProductType Type) { BuildProduct NewBuildProduct = new BuildProduct(Path, Type); BuildProducts.Add(NewBuildProduct); @@ -387,61 +392,6 @@ namespace UnrealBuildTool PrecompiledRuntimeDependencies.UnionWith(Other.PrecompiledRuntimeDependencies); } - /// - /// Expand all the path variables in the manifest - /// - /// Value for the $(EngineDir) variable - /// Value for the $(ProjectDir) variable - public void ExpandPathVariables(DirectoryReference EngineDir, DirectoryReference ProjectDir) - { - ExpandPathVariables(EngineDir, ProjectDir, new Dictionary()); - } - - /// - /// Expand all the path variables in the manifest, including a list of supplied variable values. - /// - /// Value for the $(EngineDir) variable - /// Value for the $(ProjectDir) variable - /// Other variables to expand from the manifest - public void ExpandPathVariables(DirectoryReference EngineDir, DirectoryReference ProjectDir, IDictionary OtherVariables) - { - // Build a dictionary containing the standard variable expansions - Dictionary Variables = new Dictionary(OtherVariables); - Variables["EngineDir"] = EngineDir.FullName; - Variables["ProjectDir"] = ProjectDir.FullName; - - // Replace all the variables in the paths - foreach (BuildProduct BuildProduct in BuildProducts) - { - BuildProduct.Path = Utils.ExpandVariables(BuildProduct.Path, Variables); - } - foreach (RuntimeDependency RuntimeDependency in RuntimeDependencies) - { - RuntimeDependency.Path = Utils.ExpandVariables(RuntimeDependency.Path, Variables); - } - - // Replace the variables in the precompiled dependencies - PrecompiledBuildDependencies = new HashSet(PrecompiledBuildDependencies.Select(x => Utils.ExpandVariables(x, Variables)), StringComparer.InvariantCultureIgnoreCase); - PrecompiledRuntimeDependencies = new HashSet(PrecompiledRuntimeDependencies.Select(x => Utils.ExpandVariables(x, Variables)), StringComparer.InvariantCultureIgnoreCase); - } - - /// - /// Inserts $(EngineDir) and $(ProjectDir) variables into a path string, so it can be used on different machines. - /// - /// Input path - /// The engine directory. Relative paths are ok. - /// The project directory. Relative paths are ok. - /// New string with the base directory replaced, or the original string - public static string InsertPathVariables(string InputPath, DirectoryReference EngineDir, DirectoryReference ProjectDir) - { - string Result = InputPath; - if (InputPath != null && !InputPath.StartsWith("$(")) - { - Result = InsertPathVariables(new FileReference(InputPath), EngineDir, ProjectDir); - } - return Result; - } - /// /// Inserts variables to make a file relative to $(EngineDir) or $(ProjectDir) /// @@ -455,7 +405,7 @@ namespace UnrealBuildTool { return "$(EngineDir)/" + File.MakeRelativeTo(EngineDir).Replace(Path.DirectorySeparatorChar, '/'); } - else if (File.IsUnderDirectory(ProjectDir)) + else if (ProjectDir != null && File.IsUnderDirectory(ProjectDir)) { return "$(ProjectDir)/" + File.MakeRelativeTo(ProjectDir).Replace(Path.DirectorySeparatorChar, '/'); } @@ -465,6 +415,30 @@ namespace UnrealBuildTool } } + /// + /// Inserts variables to make a file relative to $(EngineDir) or $(ProjectDir) + /// + /// The path to insert variables into. + /// Value of the $(EngineDir) variable. + /// Value of the $(ProjectDir) variable. + /// Converted path for the file. + public static FileReference ExpandPathVariables(string Path, DirectoryReference EngineDir, DirectoryReference ProjectDir) + { + const string EnginePrefix = "$(EngineDir)"; + if(Path.StartsWith(EnginePrefix, StringComparison.InvariantCultureIgnoreCase)) + { + return new FileReference(EngineDir.FullName + Path.Substring(EnginePrefix.Length)); + } + + const string ProjectPrefix = "$(ProjectDir)"; + if(ProjectDir != null && Path.StartsWith(ProjectPrefix, StringComparison.InvariantCultureIgnoreCase)) + { + return new FileReference(ProjectDir.FullName + Path.Substring(ProjectPrefix.Length)); + } + + return new FileReference(Path); + } + /// /// Returns the standard path to the build receipt for a given target /// @@ -474,7 +448,7 @@ namespace UnrealBuildTool /// The target configuration /// The architecture being built /// Path to the receipt for this target - public static string GetDefaultPath(string BaseDir, string TargetName, UnrealTargetPlatform Platform, UnrealTargetConfiguration Configuration, string BuildArchitecture) + public static FileReference GetDefaultPath(DirectoryReference BaseDir, string TargetName, UnrealTargetPlatform Platform, UnrealTargetConfiguration Configuration, string BuildArchitecture) { // Get the architecture suffix. Platforms have the option of overriding whether to include this string in filenames. string ArchitectureSuffix = ""; @@ -486,21 +460,23 @@ namespace UnrealBuildTool // Build the output filename if (String.IsNullOrEmpty(ArchitectureSuffix) && Configuration == UnrealTargetConfiguration.Development) { - return Path.Combine(BaseDir, "Binaries", Platform.ToString(), String.Format("{0}.target", TargetName)); + return FileReference.Combine(BaseDir, "Binaries", Platform.ToString(), String.Format("{0}.target", TargetName)); } else { - return Path.Combine(BaseDir, "Binaries", Platform.ToString(), String.Format("{0}-{1}-{2}{3}.target", TargetName, Platform.ToString(), Configuration.ToString(), ArchitectureSuffix)); + return FileReference.Combine(BaseDir, "Binaries", Platform.ToString(), String.Format("{0}-{1}-{2}{3}.target", TargetName, Platform.ToString(), Configuration.ToString(), ArchitectureSuffix)); } } /// /// Read a receipt from disk. /// - /// Filename to read from - public static TargetReceipt Read(string FileName) + /// Filename to read from + /// Engine directory for expanded variables + /// Project directory for expanded variables + public static TargetReceipt Read(FileReference Location, DirectoryReference EngineDir, DirectoryReference ProjectDir) { - JsonObject RawObject = JsonObject.Read(FileName); + JsonObject RawObject = JsonObject.Read(Location.FullName); // Read the initial fields string TargetName = RawObject.GetStringField("TargetName"); @@ -528,10 +504,12 @@ namespace UnrealBuildTool BuildProductType Type; if (BuildProductObject.TryGetStringField("Path", out Path) && BuildProductObject.TryGetEnumField("Type", out Type)) { + FileReference File = ExpandPathVariables(Path, EngineDir, ProjectDir); + string Module; BuildProductObject.TryGetStringField("Module", out Module); - BuildProduct NewBuildProduct = Receipt.AddBuildProduct(Path, Type); + BuildProduct NewBuildProduct = Receipt.AddBuildProduct(File, Type); bool IsPrecompiled; if (BuildProductObject.TryGetBoolField("IsPrecompiled", out IsPrecompiled)) @@ -551,6 +529,8 @@ namespace UnrealBuildTool string Path; if (RuntimeDependencyObject.TryGetStringField("Path", out Path)) { + FileReference File = ExpandPathVariables(Path, EngineDir, ProjectDir); + StagedFileType Type; if(!RuntimeDependencyObject.TryGetEnumField("Type", out Type)) { @@ -562,7 +542,8 @@ namespace UnrealBuildTool } Type = bIgnoreIfMissing? StagedFileType.DebugNonUFS : StagedFileType.NonUFS; } - Receipt.RuntimeDependencies.Add(Path, Type); + + Receipt.RuntimeDependencies.Add(File, Type); } } } @@ -589,14 +570,22 @@ namespace UnrealBuildTool string[] PrecompiledBuildDependencies; if(RawObject.TryGetStringArrayField("PrecompiledBuildDependencies", out PrecompiledBuildDependencies)) { - Receipt.PrecompiledBuildDependencies.UnionWith(PrecompiledBuildDependencies); + foreach(string PrecompiledBuildDependency in PrecompiledBuildDependencies) + { + FileReference File = ExpandPathVariables(PrecompiledBuildDependency, EngineDir, ProjectDir); + Receipt.PrecompiledBuildDependencies.Add(File); + } } // Read the precompiled dependencies string[] PrecompiledRuntimeDependencies; if(RawObject.TryGetStringArrayField("PrecompiledRuntimeDependencies", out PrecompiledRuntimeDependencies)) { - Receipt.PrecompiledRuntimeDependencies.UnionWith(PrecompiledRuntimeDependencies); + foreach(string PrecompiledRuntimeDependency in PrecompiledRuntimeDependencies) + { + FileReference File = ExpandPathVariables(PrecompiledRuntimeDependency, EngineDir, ProjectDir); + Receipt.PrecompiledRuntimeDependencies.Add(File); + } } return Receipt; @@ -605,12 +594,14 @@ namespace UnrealBuildTool /// /// Try to read a receipt from disk, failing gracefully if it can't be read. /// - /// Filename to read from + /// Filename to read from + /// Engine directory for expanded paths + /// Project directory for expanded paths /// If successful, the receipt that was read /// True if successful - public static bool TryRead(string FileName, out TargetReceipt Receipt) + public static bool TryRead(FileReference Location, DirectoryReference EngineDir, DirectoryReference ProjectDir, out TargetReceipt Receipt) { - if (!File.Exists(FileName)) + if (!FileReference.Exists(Location)) { Receipt = null; return false; @@ -618,7 +609,7 @@ namespace UnrealBuildTool try { - Receipt = Read(FileName); + Receipt = Read(Location, EngineDir, ProjectDir); return true; } catch (Exception) @@ -631,10 +622,12 @@ namespace UnrealBuildTool /// /// Write the receipt to disk. /// - /// Output filename - public void Write(string FileName) + /// Output filename + /// Engine directory for expanded paths + /// Project directory for expanded paths + public void Write(FileReference Location, DirectoryReference EngineDir, DirectoryReference ProjectDir) { - using (JsonWriter Writer = new JsonWriter(FileName)) + using (JsonWriter Writer = new JsonWriter(Location.FullName)) { Writer.WriteObjectStart(); Writer.WriteValue("TargetName", TargetName); @@ -650,7 +643,7 @@ namespace UnrealBuildTool foreach (BuildProduct BuildProduct in BuildProducts) { Writer.WriteObjectStart(); - Writer.WriteValue("Path", BuildProduct.Path); + Writer.WriteValue("Path", InsertPathVariables(BuildProduct.Path, EngineDir, ProjectDir)); Writer.WriteValue("Type", BuildProduct.Type.ToString()); if (BuildProduct.IsPrecompiled) { @@ -664,7 +657,7 @@ namespace UnrealBuildTool foreach (RuntimeDependency RuntimeDependency in RuntimeDependencies) { Writer.WriteObjectStart(); - Writer.WriteValue("Path", RuntimeDependency.Path); + Writer.WriteValue("Path", InsertPathVariables(RuntimeDependency.Path, EngineDir, ProjectDir)); Writer.WriteValue("Type", RuntimeDependency.Type.ToString()); Writer.WriteObjectEnd(); } @@ -686,7 +679,7 @@ namespace UnrealBuildTool if(PrecompiledBuildDependencies.Count > 0) { Writer.WriteArrayStart("PrecompiledBuildDependencies"); - foreach(string PrecompiledBuildDependency in PrecompiledBuildDependencies.OrderBy(x => x)) + foreach(string PrecompiledBuildDependency in PrecompiledBuildDependencies.Select(x => InsertPathVariables(x, EngineDir, ProjectDir)).OrderBy(x => x)) { Writer.WriteValue(PrecompiledBuildDependency); } @@ -696,7 +689,7 @@ namespace UnrealBuildTool if(PrecompiledRuntimeDependencies.Count > 0) { Writer.WriteArrayStart("PrecompiledRuntimeDependencies"); - foreach(string PrecompiledRuntimeDependency in PrecompiledRuntimeDependencies.OrderBy(x => x)) + foreach(string PrecompiledRuntimeDependency in PrecompiledRuntimeDependencies.Select(x => InsertPathVariables(x, EngineDir, ProjectDir)).OrderBy(x => x)) { Writer.WriteValue(PrecompiledRuntimeDependency); } diff --git a/Engine/Source/Programs/UnrealBuildTool/System/Unity.cs b/Engine/Source/Programs/UnrealBuildTool/System/Unity.cs index f7f66a52fdb6..f8bebc16eff3 100644 --- a/Engine/Source/Programs/UnrealBuildTool/System/Unity.cs +++ b/Engine/Source/Programs/UnrealBuildTool/System/Unity.cs @@ -22,6 +22,11 @@ namespace UnrealBuildTool /// public static HashSet CandidateSourceFilesForWorkingSet = new HashSet(); + /// + /// Set of target names we've printed out adaptive non-unity messages for. + /// + public static HashSet PrintedSettingsForTargets = new HashSet(); + /// /// Prefix used for all dynamically created Unity modules /// @@ -207,20 +212,17 @@ namespace UnrealBuildTool int WorkingSetSourceFileCount = 0; foreach (FileItem CPPFile in SortedCPPFiles) { + ++CandidateWorkingSetSourceFileCount; + // Don't include writable source files into unity blobs - if (!CPPFile.Reference.HasExtension(".generated.cpp")) + if (UnrealBuildTool.ShouldSourceFileBePartOfWorkingSet(CPPFile.AbsolutePath)) { - ++CandidateWorkingSetSourceFileCount; + ++WorkingSetSourceFileCount; - if (UnrealBuildTool.ShouldSourceFileBePartOfWorkingSet(CPPFile.AbsolutePath)) - { - ++WorkingSetSourceFileCount; - - // Mark this file as part of the working set. This will be saved into the UBT Makefile so that - // the assembler can automatically invalidate the Makefile when the working set changes (allowing this - // code to run again, to build up new unity blobs.) - SourceFileWorkingSet.Add(CPPFile); - } + // Mark this file as part of the working set. This will be saved into the UBT Makefile so that + // the assembler can automatically invalidate the Makefile when the working set changes (allowing this + // code to run again, to build up new unity blobs.) + SourceFileWorkingSet.Add(CPPFile); } } @@ -285,6 +287,17 @@ namespace UnrealBuildTool if (AdaptiveUnityBuildInfoString.Length > 0) { + if (PrintedSettingsForTargets.Add(Target.Name)) + { + if (Target.bAdaptiveUnityDisablesPCH) + { + Log.TraceInformation("[Adaptive unity build] Disabling PCH for excluded files. Set bAdaptiveUnityDisablesPCH to false in BuildConfiguration.xml to change this behavior."); + } + if (Target.bAdaptiveUnityDisablesOptimizations) + { + Log.TraceInformation("[Adaptive unity build] Disabling optimizations for excluded files. Set bAdaptiveUnityDisablesOptimizations to false in BuildConfiguration.xml to change this behavior."); + } + } Log.TraceInformation(AdaptiveUnityBuildInfoString.ToString()); } diff --git a/Engine/Source/Programs/UnrealBuildTool/System/UnrealBuildTool.cs b/Engine/Source/Programs/UnrealBuildTool/System/UnrealBuildTool.cs index 54b8707789b3..ff15f35db729 100644 --- a/Engine/Source/Programs/UnrealBuildTool/System/UnrealBuildTool.cs +++ b/Engine/Source/Programs/UnrealBuildTool/System/UnrealBuildTool.cs @@ -76,6 +76,16 @@ namespace UnrealBuildTool /// public static readonly DirectoryReference EngineSourceThirdPartyDirectory = DirectoryReference.Combine(EngineSourceDirectory, "ThirdParty"); + /// + /// The full name of the Enterprise directory + /// + public static readonly DirectoryReference EnterpriseDirectory = DirectoryReference.Combine(RootDirectory, "Enterprise"); + + /// + /// The full name of the Enterprise/Source directory + /// + public static readonly DirectoryReference EnterpriseSourceDirectory = DirectoryReference.Combine(EnterpriseDirectory, "Source"); + /// /// The Remote Ini directory. This should always be valid when compiling using a remote server. /// @@ -240,6 +250,18 @@ namespace UnrealBuildTool return InstalledPlatformInfo.Current.IsValidPlatform(InPlatform, EProjectType.Code); } + /// + /// Determines whether a directory is part of the engine + /// + /// + /// true if the directory is under of the engine directories, false if not + static public bool IsUnderAnEngineDirectory(DirectoryReference InDirectory) + { + // Enterprise modules are considered as engine modules + return InDirectory.IsUnderDirectory( UnrealBuildTool.EngineDirectory ) || InDirectory.IsUnderDirectory( UnrealBuildTool.EnterpriseSourceDirectory ) || + InDirectory.IsUnderDirectory( DirectoryReference.Combine( UnrealBuildTool.EnterpriseDirectory, "Plugins" ) ); + } + public static void RegisterAllUBTClasses(SDKOutputLevel OutputLevel, bool bValidatingPlatforms) { // Find and register all tool chains and build platforms that are present @@ -465,7 +487,7 @@ namespace UnrealBuildTool if (!bIsEngineInstalled.HasValue) { bIsEngineInstalled = FileReference.Exists(FileReference.Combine(RootDirectory, "Engine", "Build", "InstalledBuild.txt")); - } + } DateTime StartTime = DateTime.UtcNow; @@ -478,10 +500,10 @@ namespace UnrealBuildTool bLogSourcesToConsole: false, bColorConsoleOutput: true, TraceListeners: new[] - { - new ConsoleTraceListener(), - !string.IsNullOrEmpty(BuildConfiguration.LogFilename) ? new TextWriterTraceListener(new StreamWriter(new FileStream(BuildConfiguration.LogFilename, FileMode.Create, FileAccess.ReadWrite, FileShare.Read)) { AutoFlush = true }) : null, - }); + { + new ConsoleTraceListener(), + !string.IsNullOrEmpty(BuildConfiguration.LogFilename) ? new TextWriterTraceListener(new StreamWriter(new FileStream(BuildConfiguration.LogFilename, FileMode.Create, FileAccess.ReadWrite, FileShare.Read)) { AutoFlush = true }) : null, + }); // Parse rocket-specific arguments. FileReference ProjectFile = null; @@ -492,7 +514,7 @@ namespace UnrealBuildTool { // This is to allow relative paths for the project file Log.TraceVerbose("UBT Running for Rocket: " + ProjectFile); - break; + break; } } @@ -1114,6 +1136,12 @@ namespace UnrealBuildTool bool bIsHotReload = !bNoHotReload && (BuildConfiguration.bHotReloadFromIDE || (TargetDescs.Count == 1 && TargetDescs[0].OnlyModules.Count > 0 && TargetDescs[0].ForeignPlugins.Count == 0)); TargetDescriptor HotReloadTargetDesc = bIsHotReload ? TargetDescs[0] : null; + // Do a gather on hotreload - we don't want old module names from the makefile to be used + if (bIsHotReload) + { + UnrealBuildTool.bIsGatheringBuild_Unsafe = true; + } + if (ProjectFileGenerator.bGenerateProjectFiles) { // Create empty timestamp file to record when was the last time we regenerated projects. @@ -1240,7 +1268,7 @@ namespace UnrealBuildTool { // Ini files are newer than UBTMakefile UBTMakefile = null; - ReasonNotLoaded = "ini files are newer that UBTMakefile"; + ReasonNotLoaded = "ini files are newer than UBTMakefile"; break; } } @@ -1438,7 +1466,7 @@ namespace UnrealBuildTool UBTMakefile.SourceFileWorkingSet = Unity.SourceFileWorkingSet; UBTMakefile.CandidateSourceFilesForWorkingSet = Unity.CandidateSourceFilesForWorkingSet; - if (BuildConfiguration.bUseUBTMakefiles) + if (BuildConfiguration.bUseUBTMakefiles && !UBTMakefile.PrerequisiteActions.Any(x => x.ActionHandler != null)) { // We've been told to prepare to build, so let's go ahead and save out our action graph so that we can use in a later invocation // to assemble the build. Even if we are configured to assemble the build in this same invocation, we want to save out the @@ -1577,11 +1605,11 @@ namespace UnrealBuildTool // if the build succeeded, write the receipts and do any needed syncing if (bSuccess) { - foreach (UEBuildTarget Target in Targets) - { - Target.WriteReceipts(); + foreach (UEBuildTarget Target in Targets) + { + Target.WriteReceipts(); UEBuildPlatform.GetBuildPlatform(Target.Platform).PostBuildSync(Target); - } + } if (ActionsToExecute.Count == 0 && BuildConfiguration.bSkipLinkingWhenNothingToCompile) { BuildResult = ECompilationResult.UpToDate; @@ -1647,19 +1675,19 @@ namespace UnrealBuildTool // Save the include dependency cache. foreach(CPPHeaders Headers in TargetToHeaders.Values) + { + // NOTE: It's very important that we save the include cache, even if a build exception was thrown (compile error, etc), because we need to make sure that + // any C++ include dependencies that we computed for out of date source files are saved. Remember, the build may fail *after* some build products + // are successfully built. If we didn't save our dependency cache after build failures, source files for those build products that were successsfully + // built before the failure would not be considered out of date on the next run, so this is our only chance to cache C++ includes for those files! + + if (Headers.IncludeDependencyCache != null) { - // NOTE: It's very important that we save the include cache, even if a build exception was thrown (compile error, etc), because we need to make sure that - // any C++ include dependencies that we computed for out of date source files are saved. Remember, the build may fail *after* some build products - // are successfully built. If we didn't save our dependency cache after build failures, source files for those build products that were successsfully - // built before the failure would not be considered out of date on the next run, so this is our only chance to cache C++ includes for those files! - - if(Headers.IncludeDependencyCache != null) - { Headers.IncludeDependencyCache.Save(); - } + } - if(Headers.FlatCPPIncludeDependencyCache != null) - { + if (Headers.FlatCPPIncludeDependencyCache != null) + { Headers.FlatCPPIncludeDependencyCache.Save(); } } @@ -1996,7 +2024,7 @@ namespace UnrealBuildTool // Check if any of the target's Build.cs files are newer than the makefile foreach (UEBuildTarget Target in LoadedUBTMakefile.Targets) { - string TargetCsFilename = Target.TargetCsFilename.FullName; + string TargetCsFilename = Target.TargetRulesFile.FullName; if (TargetCsFilename != null) { FileInfo TargetCsFile = new FileInfo(TargetCsFilename); @@ -2024,6 +2052,25 @@ namespace UnrealBuildTool } } } + + foreach (FlatModuleCsDataType FlatCsModuleData in Target.FlatModuleCsData.Values) + { + if (FlatCsModuleData.BuildCsFilename != null && FlatCsModuleData.ExternalDependencies.Count > 0) + { + string BaseDir = Path.GetDirectoryName(FlatCsModuleData.BuildCsFilename); + foreach (string ExternalDependency in FlatCsModuleData.ExternalDependencies) + { + FileInfo DependencyFile = new FileInfo(Path.Combine(BaseDir, ExternalDependency)); + bool bDependencyFileExists = DependencyFile.Exists; + if (!bDependencyFileExists || DependencyFile.LastWriteTime > UBTMakefileInfo.LastWriteTime) + { + Log.TraceVerbose("{0} has been {1} since makefile was built, ignoring it ({2})", DependencyFile.FullName, bDependencyFileExists ? "changed" : "deleted", UBTMakefileInfo.FullName); + ReasonNotLoaded = string.Format("changes to external dependency"); + return null; + } + } + } + } } // We do a check to see if any modules' headers have changed which have @@ -2442,6 +2489,12 @@ namespace UnrealBuildTool /// True if file is part of the working set public static bool ShouldSourceFileBePartOfWorkingSet(string SourceFileAbsolutePath) { + // Generated .cpp files should never be treated as part of the working set + if (SourceFileAbsolutePath.EndsWith(".gen.cpp")) + { + return false; + } + bool bShouldBePartOfWorkingSourceFileSet = false; try { diff --git a/Engine/Source/Programs/UnrealBuildTool/System/Utils.cs b/Engine/Source/Programs/UnrealBuildTool/System/Utils.cs index a002282f37c0..5a6e3bbaf3d5 100644 --- a/Engine/Source/Programs/UnrealBuildTool/System/Utils.cs +++ b/Engine/Source/Programs/UnrealBuildTool/System/Utils.cs @@ -12,7 +12,6 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Linq; using System.Management; -using Tools.DotNETCommon.CaselessDictionary; using System.Web.Script.Serialization; namespace UnrealBuildTool diff --git a/Engine/Source/Programs/UnrealBuildTool/System/VCProjectFileGenerator.cs b/Engine/Source/Programs/UnrealBuildTool/System/VCProjectFileGenerator.cs index ca27cf1a8020..7064f1a91f5d 100644 --- a/Engine/Source/Programs/UnrealBuildTool/System/VCProjectFileGenerator.cs +++ b/Engine/Source/Programs/UnrealBuildTool/System/VCProjectFileGenerator.cs @@ -220,7 +220,7 @@ namespace UnrealBuildTool public const string DefaultPlatformName = "Win32"; /// The platform name that must be used for .NET projects - public const string DotNetPlatformName = "AnyCPU"; + public const string DotNetPlatformName = "Any CPU"; /// diff --git a/Engine/Source/Programs/UnrealBuildTool/System/XcodeProject.cs b/Engine/Source/Programs/UnrealBuildTool/System/XcodeProject.cs index e761509fcf30..45ef061d8cb9 100644 --- a/Engine/Source/Programs/UnrealBuildTool/System/XcodeProject.cs +++ b/Engine/Source/Programs/UnrealBuildTool/System/XcodeProject.cs @@ -875,7 +875,8 @@ namespace UnrealBuildTool if (bCreateIOSInfoPlist) { Directory.CreateDirectory(Path.GetDirectoryName(IOSInfoPlistPath)); - UEDeployIOS.GenerateIOSPList(ProjectFile, Config.BuildConfig, ProjectPath.FullName, bIsUE4Game, GameName, Config.BuildTarget, EngineDir.FullName, ProjectPath + "/Binaries/IOS/Payload"); + bool bSupportPortrait, bSupportLandscape; + UEDeployIOS.GenerateIOSPList(ProjectFile, Config.BuildConfig, ProjectPath.FullName, bIsUE4Game, GameName, Config.BuildTarget, EngineDir.FullName, ProjectPath + "/Binaries/IOS/Payload", out bSupportPortrait, out bSupportLandscape); } if (bCreateTVOSInfoPlist) { diff --git a/Engine/Source/Programs/UnrealBuildTool/System/XcodeProjectFileGenerator.cs b/Engine/Source/Programs/UnrealBuildTool/System/XcodeProjectFileGenerator.cs index c66158dd60b2..29684478189b 100644 --- a/Engine/Source/Programs/UnrealBuildTool/System/XcodeProjectFileGenerator.cs +++ b/Engine/Source/Programs/UnrealBuildTool/System/XcodeProjectFileGenerator.cs @@ -229,7 +229,7 @@ namespace UnrealBuildTool if (bGeneratingGameProjectFiles) { - IncludeEngineSource = true; + bIncludeEngineSource = true; } } } diff --git a/Engine/Source/Programs/UnrealBuildTool/TVOS/TVOSExports.cs b/Engine/Source/Programs/UnrealBuildTool/TVOS/TVOSExports.cs index 21eace1515f6..01a1d6662f29 100644 --- a/Engine/Source/Programs/UnrealBuildTool/TVOS/TVOSExports.cs +++ b/Engine/Source/Programs/UnrealBuildTool/TVOS/TVOSExports.cs @@ -55,9 +55,9 @@ namespace UnrealBuildTool /// /// /// - public static bool PrepForUATPackageOrDeploy(UnrealTargetConfiguration Config, FileReference ProjectFile, string InProjectName, string InProjectDirectory, string InExecutablePath, string InEngineDir, bool bForDistribution, string CookFlavor, bool bIsDataDeploy, bool bCreateStubIPA) + public static bool PrepForUATPackageOrDeploy(UnrealTargetConfiguration Config, FileReference ProjectFile, string InProjectName, DirectoryReference InProjectDirectory, string InExecutablePath, DirectoryReference InEngineDir, bool bForDistribution, string CookFlavor, bool bIsDataDeploy, bool bCreateStubIPA) { - return new UEDeployTVOS().PrepForUATPackageOrDeploy(Config, ProjectFile, InProjectName, InProjectDirectory, InExecutablePath, InEngineDir, bForDistribution, CookFlavor, bIsDataDeploy, bCreateStubIPA); + return new UEDeployTVOS().PrepForUATPackageOrDeploy(Config, ProjectFile, InProjectName, InProjectDirectory.FullName, InExecutablePath, InEngineDir.FullName, bForDistribution, CookFlavor, bIsDataDeploy, bCreateStubIPA); } /// @@ -71,10 +71,12 @@ namespace UnrealBuildTool /// /// /// + /// + /// /// - public static bool GeneratePList(FileReference ProjectFile, UnrealTargetConfiguration Config, string ProjectDirectory, bool bIsUE4Game, string GameName, string ProjectName, string InEngineDir, string AppDirectory) + public static bool GeneratePList(FileReference ProjectFile, UnrealTargetConfiguration Config, DirectoryReference ProjectDirectory, bool bIsUE4Game, string GameName, string ProjectName, DirectoryReference InEngineDir, DirectoryReference AppDirectory, out bool bSupportsPortrait, out bool bSupportsLandscape) { - return new UEDeployTVOS().GeneratePList(ProjectFile, Config, ProjectDirectory, bIsUE4Game, GameName, ProjectName, InEngineDir, AppDirectory); + return new UEDeployTVOS().GeneratePList(ProjectFile, Config, ProjectDirectory.FullName, bIsUE4Game, GameName, ProjectName, InEngineDir.FullName, AppDirectory.FullName, out bSupportsPortrait, out bSupportsLandscape); } } } diff --git a/Engine/Source/Programs/UnrealBuildTool/TVOS/UEDeployTVOS.cs b/Engine/Source/Programs/UnrealBuildTool/TVOS/UEDeployTVOS.cs index 70233e7e5dfa..b3bdb69b8b91 100644 --- a/Engine/Source/Programs/UnrealBuildTool/TVOS/UEDeployTVOS.cs +++ b/Engine/Source/Programs/UnrealBuildTool/TVOS/UEDeployTVOS.cs @@ -123,7 +123,7 @@ namespace UnrealBuildTool Text.AppendLine("\tCFBundleSignature"); Text.AppendLine("\t????"); Text.AppendLine("\tCFBundleVersion"); - Text.AppendLine(string.Format("\t{0}", VersionUtilities.UpdateBundleVersion(OldPListData))); + Text.AppendLine(string.Format("\t{0}", VersionUtilities.UpdateBundleVersion(OldPListData, InEngineDir))); Text.AppendLine("\tCFBundleShortVersionString"); Text.AppendLine(string.Format("\t{0}", BundleShortVersion)); Text.AppendLine("\tLSRequiresIPhoneOS"); @@ -328,12 +328,13 @@ namespace UnrealBuildTool return bSkipDefaultPNGs; } - public override bool GeneratePList(FileReference ProjectFile, UnrealTargetConfiguration Config, string ProjectDirectory, bool bIsUE4Game, string GameName, string ProjectName, string InEngineDir, string AppDirectory) + public override bool GeneratePList(FileReference ProjectFile, UnrealTargetConfiguration Config, string ProjectDirectory, bool bIsUE4Game, string GameName, string ProjectName, string InEngineDir, string AppDirectory, out bool bSupportsPortrait, out bool bSupportsLandscape) { + bSupportsLandscape = bSupportsPortrait = true; return GenerateTVOSPList(ProjectDirectory, bIsUE4Game, GameName, ProjectName, InEngineDir, AppDirectory, this); } - protected override void CopyGraphicsResources(bool bSkipDefaultPNGs, string InEngineDir, string AppDirectory, string BuildDirectory, string IntermediateDir) + protected override void CopyGraphicsResources(bool bSkipDefaultPNGs, string InEngineDir, string AppDirectory, string BuildDirectory, string IntermediateDir, bool bSupportsPortrait, bool bSupportsLandscape) { // do nothing on TVOS } diff --git a/Engine/Source/Programs/UnrealBuildTool/ToolChain/RemoteToolChain.cs b/Engine/Source/Programs/UnrealBuildTool/ToolChain/RemoteToolChain.cs index 635bf79978c4..c782889bdd18 100644 --- a/Engine/Source/Programs/UnrealBuildTool/ToolChain/RemoteToolChain.cs +++ b/Engine/Source/Programs/UnrealBuildTool/ToolChain/RemoteToolChain.cs @@ -633,7 +633,20 @@ namespace UnrealBuildTool } } - private static List RsyncDirs = new List(); + protected string GetMacDevEngineRoot() + { + if (BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac) + { + // figure out the remote version of Engine/Source + return ConvertPath(Path.GetFullPath(Path.Combine(BranchDirectory, "Engine/"))); + } + else + { + return UnrealBuildTool.EngineDirectory.FullName; + } + } + + private static List RsyncDirs = new List(); private static List RsyncExtensions = new List(); public static void QueueFileForBatchUpload(FileItem LocalFileItem) @@ -657,6 +670,23 @@ namespace UnrealBuildTool } } + public static void QueueDirectoryForBatchUpload(DirectoryReference LocalDirectory, bool bRecursive = true) + { + string Entry = LocalDirectory.FullName; + if (!RsyncDirs.Contains(Entry)) + { + RsyncDirs.Add(Entry); + } + + if (bRecursive) + { + foreach(var dir in DirectoryReference.EnumerateDirectories(LocalDirectory)) + { + QueueDirectoryForBatchUpload(dir); + } + } + } + public FileItem LocalToRemoteFileItem(FileItem LocalFileItem, bool bShouldUpload) { FileItem RemoteFileItem = null; diff --git a/Engine/Source/Programs/UnrealBuildTool/ToolChain/UEToolChain.cs b/Engine/Source/Programs/UnrealBuildTool/ToolChain/UEToolChain.cs index 0e60b25eab21..737f372bba52 100644 --- a/Engine/Source/Programs/UnrealBuildTool/ToolChain/UEToolChain.cs +++ b/Engine/Source/Programs/UnrealBuildTool/ToolChain/UEToolChain.cs @@ -70,6 +70,10 @@ namespace UnrealBuildTool { } + public virtual void FinalizeOutput(ReadOnlyTargetRules Target, List OutputItems, ActionGraph ActionGraph) + { + } + /// /// Adds a build product and its associated debug file to a receipt. /// diff --git a/Engine/Source/Programs/UnrealBuildTool/UnrealBuildTool.csproj b/Engine/Source/Programs/UnrealBuildTool/UnrealBuildTool.csproj index 38c705b177bd..c455530c6cb2 100644 --- a/Engine/Source/Programs/UnrealBuildTool/UnrealBuildTool.csproj +++ b/Engine/Source/Programs/UnrealBuildTool/UnrealBuildTool.csproj @@ -136,7 +136,9 @@ + + @@ -209,6 +211,7 @@ + @@ -286,7 +289,6 @@ - diff --git a/Engine/Source/Programs/UnrealBuildTool/Utilities/JsonObject.cs b/Engine/Source/Programs/UnrealBuildTool/Utilities/JsonObject.cs index bbfe02e1e327..7aff71208d82 100644 --- a/Engine/Source/Programs/UnrealBuildTool/Utilities/JsonObject.cs +++ b/Engine/Source/Programs/UnrealBuildTool/Utilities/JsonObject.cs @@ -545,6 +545,31 @@ namespace UnrealBuildTool bRequiresComma = true; } + /// + /// Write an array of strings + /// + /// Name of the field + /// Values for the field + public void WriteStringArrayField(string Name, IEnumerable Values) + { + WriteArrayStart(Name); + foreach(string Value in Values) + { + WriteValue(Value); + } + WriteArrayEnd(); + } + + /// + /// Write an array of enum values + /// + /// Name of the field + /// Values for the field + public void WriteEnumArrayField(string Name, IEnumerable Values) where T : struct + { + WriteStringArrayField(Name, Values.Select(x => x.ToString())); + } + /// /// Write a value with no field name, for the contents of an array /// diff --git a/Engine/Source/Programs/UnrealBuildTool/Windows/PVSToolChain.cs b/Engine/Source/Programs/UnrealBuildTool/Windows/PVSToolChain.cs new file mode 100644 index 000000000000..f54e3ff4ed58 --- /dev/null +++ b/Engine/Source/Programs/UnrealBuildTool/Windows/PVSToolChain.cs @@ -0,0 +1,207 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace UnrealBuildTool +{ + class PVSToolChain : UEToolChain + { + WindowsCompiler Compiler; + + public PVSToolChain(CppPlatform InCppPlatform, WindowsCompiler InCompiler) : base(InCppPlatform) + { + this.Compiler = InCompiler; + } + + static string GetFullIncludePath(string IncludePath) + { + return Path.GetFullPath(ActionThread.ExpandEnvironmentVariables(IncludePath)); + } + + public override CPPOutput CompileCPPFiles(CppCompileEnvironment CompileEnvironment, List SourceFiles, string ModuleName, ActionGraph ActionGraph) + { + VCEnvironment EnvVars = VCEnvironment.SetEnvironment(CppPlatform, Compiler); + + // Get the MSVC arguments required to compile all files in this batch + List SharedArguments = new List(); + SharedArguments.Add("/nologo"); + SharedArguments.Add("/P"); // Preprocess + SharedArguments.Add("/C"); // Preserve comments when preprocessing + SharedArguments.Add("/D PVS_STUDIO"); + SharedArguments.Add("/wd4005"); + foreach (string IncludePath in CompileEnvironment.IncludePaths.UserIncludePaths) + { + SharedArguments.Add(String.Format("/I \"{0}\"", GetFullIncludePath(IncludePath))); + } + foreach (string IncludePath in CompileEnvironment.IncludePaths.SystemIncludePaths) + { + SharedArguments.Add(String.Format("/I \"{0}\"", GetFullIncludePath(IncludePath))); + } + foreach (string Definition in CompileEnvironment.Definitions) + { + SharedArguments.Add(String.Format("/D \"{0}\"", Definition)); + } + + // Get the path to PVS studio + FileReference AnalyzerFile = new FileReference(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "PVS-Studio", "x64", "PVS-Studio.exe")); + if(!FileReference.Exists(AnalyzerFile)) + { + throw new BuildException("Unable to find PVS-Studio at {0}", AnalyzerFile); + } + + CPPOutput Result = new CPPOutput(); + foreach (FileItem SourceFile in SourceFiles) + { + // Get the file names for everything we need + string BaseFileName = SourceFile.Reference.GetFileName(); + + // Write the response file + FileReference PreprocessedFileLocation = FileReference.Combine(CompileEnvironment.OutputDirectory, BaseFileName + ".i"); + + List Arguments = new List(SharedArguments); + Arguments.Add(String.Format("/Fi\"{0}\"", PreprocessedFileLocation)); // Preprocess to a file + Arguments.Add(String.Format("\"{0}\"", SourceFile.AbsolutePath)); + + FileReference ResponseFileLocation = FileReference.Combine(CompileEnvironment.OutputDirectory, BaseFileName + ".i.response"); + FileItem ResponseFileItem = FileItem.CreateIntermediateTextFile(ResponseFileLocation, String.Join("\n", Arguments)); + + // Preprocess the source file + FileItem PreprocessedFileItem = FileItem.GetItemByFileReference(PreprocessedFileLocation); + + Action PreprocessAction = ActionGraph.Add(ActionType.Compile); + PreprocessAction.CommandPath = EnvVars.CompilerPath.FullName; + PreprocessAction.WorkingDirectory = UnrealBuildTool.EngineSourceDirectory.FullName; + PreprocessAction.CommandArguments = " @\"" + ResponseFileItem.AbsolutePath + "\""; + PreprocessAction.PrerequisiteItems.Add(SourceFile); + PreprocessAction.PrerequisiteItems.Add(ResponseFileItem); + PreprocessAction.ProducedItems.Add(PreprocessedFileItem); + PreprocessAction.bShouldOutputStatusDescription = false; + + // Write the PVS studio config file + StringBuilder ConfigFileContents = new StringBuilder(); + ConfigFileContents.AppendFormat("exclude-path={0}\n", EnvVars.VCInstallDir.FullName); + if (CppPlatform == CppPlatform.Win64) + { + ConfigFileContents.Append("platform=x64\n"); + } + else if(CppPlatform == CppPlatform.Win32) + { + ConfigFileContents.Append("platform=Win32\n"); + } + else + { + throw new BuildException("PVS studio does not support this platform"); + } + ConfigFileContents.Append("preprocessor=visualcpp\n"); + ConfigFileContents.Append("language=C++\n"); + ConfigFileContents.Append("skip-cl-exe=yes\n"); + ConfigFileContents.AppendFormat("i-file={0}\n", PreprocessedFileItem.Reference.FullName); + + FileReference ConfigFileLocation = FileReference.Combine(CompileEnvironment.OutputDirectory, BaseFileName + ".cfg"); + FileItem ConfigFileItem = FileItem.CreateIntermediateTextFile(ConfigFileLocation, ConfigFileContents.ToString()); + + // Run the analzyer on the preprocessed source file + FileReference OutputFileLocation = FileReference.Combine(CompileEnvironment.OutputDirectory, BaseFileName + ".pvslog"); + FileItem OutputFileItem = FileItem.GetItemByFileReference(OutputFileLocation); + + Action AnalyzeAction = ActionGraph.Add(ActionType.Compile); + AnalyzeAction.CommandDescription = "Analyzing"; + AnalyzeAction.StatusDescription = BaseFileName; + AnalyzeAction.WorkingDirectory = UnrealBuildTool.EngineSourceDirectory.FullName; + AnalyzeAction.CommandPath = AnalyzerFile.FullName; + AnalyzeAction.CommandArguments = String.Format("--cl-params \"{0}\" --source-file \"{1}\" --output-file \"{2}\" --cfg \"{3}\" --analysis-mode 4", PreprocessAction.CommandArguments, SourceFile.AbsolutePath, OutputFileLocation, ConfigFileItem.AbsolutePath); + AnalyzeAction.PrerequisiteItems.Add(ConfigFileItem); + AnalyzeAction.PrerequisiteItems.Add(PreprocessedFileItem); + AnalyzeAction.ProducedItems.Add(OutputFileItem); + AnalyzeAction.bShouldDeleteProducedItems = true; // PVS Studio will append by default, so need to delete produced items + + Result.ObjectFiles.AddRange(AnalyzeAction.ProducedItems); + } + return Result; + } + + public override FileItem LinkFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly, ActionGraph ActionGraph) + { + throw new BuildException("Unable to link with PVS toolchain."); + } + + public override void FinalizeOutput(ReadOnlyTargetRules Target, List OutputItems, ActionGraph ActionGraph) + { + FileReference OutputFile; + if (Target.ProjectFile == null) + { + OutputFile = FileReference.Combine(UnrealBuildTool.EngineDirectory, "Saved", "PVS-Studio", String.Format("{0}.pvslog", Target.Name)); + } + else + { + OutputFile = FileReference.Combine(Target.ProjectFile.Directory, "Saved", "PVS-Studio", String.Format("{0}.pvslog", Target.Name)); + } + + List InputFiles = OutputItems.Select(x => x.Reference).ToList(); + + Action AnalyzeAction = ActionGraph.Add(ActionType.Compile); + AnalyzeAction.CommandPath = "Dummy.exe"; + AnalyzeAction.CommandArguments = ""; + AnalyzeAction.CommandDescription = "Combining output from PVS-Studio"; + AnalyzeAction.WorkingDirectory = UnrealBuildTool.EngineSourceDirectory.FullName; + AnalyzeAction.PrerequisiteItems.AddRange(OutputItems); + AnalyzeAction.ProducedItems.Add(FileItem.GetItemByFileReference(OutputFile)); + AnalyzeAction.ActionHandler = (Action Action, out int ExitCode, out string Output) => WriteResults(OutputFile, InputFiles, out ExitCode, out Output); + AnalyzeAction.bShouldDeleteProducedItems = true; + + OutputItems.AddRange(AnalyzeAction.ProducedItems); + } + + void WriteResults(FileReference OutputFile, List InputFiles, out int ExitCode, out string Output) + { + StringBuilder OutputBuilder = new StringBuilder(); + OutputBuilder.Append("Processing PVS Studio output...\n"); + + // Create the combined output file, and print the diagnostics to the log + HashSet UniqueItems = new HashSet(); + using (StreamWriter RawWriter = new StreamWriter(OutputFile.FullName)) + { + foreach (FileReference InputFile in InputFiles) + { + string[] Lines = File.ReadAllLines(InputFile.FullName); + foreach (string Line in Lines) + { + if (!String.IsNullOrWhiteSpace(Line) && UniqueItems.Add(Line)) + { + string[] Tokens = Line.Split(new string[] { "<#~>" }, StringSplitOptions.None); + + string Trial = Tokens[1]; + int LineNumber = int.Parse(Tokens[2]); + string FileName = Tokens[3]; + string WarningCode = Tokens[5]; + string WarningMessage = Tokens[6]; + bool bFalseAlarm = bool.Parse(Tokens[7]); + int Level = int.Parse(Tokens[8]); + + // Ignore anything in ThirdParty folders + if(FileName.Replace('/', '\\').IndexOf("\\ThirdParty\\", StringComparison.InvariantCultureIgnoreCase) == -1) + { + // Output the line to the raw output file + RawWriter.WriteLine(Line); + + // Output the line to the log + if (!bFalseAlarm && Level == 1) + { + OutputBuilder.AppendFormat("{0}({1}): warning {2}: {3}\n", FileName, LineNumber, WarningCode, WarningMessage); + } + } + } + } + } + } + OutputBuilder.AppendFormat("Written {0} {1} to {2}.", UniqueItems.Count, (UniqueItems.Count == 1)? "diagnostic" : "diagnostics", OutputFile.FullName); + + // Return the text to be output. We don't have a custom output handler, so we can just return an empty string. + Output = OutputBuilder.ToString(); + ExitCode = 0; + } + } +} diff --git a/Engine/Source/Programs/UnrealBuildTool/Windows/UEBuildWindows.cs b/Engine/Source/Programs/UnrealBuildTool/Windows/UEBuildWindows.cs index fbdd5d41cf44..d7a12ef5090a 100644 --- a/Engine/Source/Programs/UnrealBuildTool/Windows/UEBuildWindows.cs +++ b/Engine/Source/Programs/UnrealBuildTool/Windows/UEBuildWindows.cs @@ -37,11 +37,40 @@ namespace UnrealBuildTool VisualStudio2017, } + /// + /// Which static analyzer to use + /// + public enum WindowsStaticAnalyzer + { + /// + /// Do not perform static analysis + /// + None, + + /// + /// Use the built-in Visual C++ static analyzer + /// + VisualCpp, + + /// + /// Use PVS-Studio for static analysis + /// + PVSStudio, + } + /// /// Windows-specific target settings /// public class WindowsTargetRules { + /// + /// Constructor + /// + public WindowsTargetRules() + { + XmlConfig.ApplyTo(this); + } + /// /// Version of the compiler toolchain to use on Windows platform. A value of "default" will be changed to a specific version at UBT startup. /// @@ -75,6 +104,19 @@ namespace UnrealBuildTool [ConfigFile(ConfigHierarchyType.Game, "/Script/EngineSettings.GeneralProjectSettings", "ProjectName")] public string ProductName; + /// + /// The static analyzer to use + /// + [XmlConfigFile(Category = "WindowsPlatform")] + [CommandLine("-StaticAnalyzer")] + public WindowsStaticAnalyzer StaticAnalyzer = WindowsStaticAnalyzer.None; + + /// + /// Provides a Module Definition File (.def) to the linker to describe various attributes of a DLL. + /// Necessary when exporting functions by ordinal values instead of by name. + /// + public string ModuleDefinitionFile; + /// VS2015 updated some of the CRT definitions but not all of the Windows SDK has been updated to match. /// Microsoft provides legacy_stdio_definitions library to enable building with VS2015 until they fix everything up. public bool bNeedsLegacyStdioDefinitionsLib @@ -153,6 +195,16 @@ namespace UnrealBuildTool get { return Inner.ProductName; } } + public WindowsStaticAnalyzer StaticAnalyzer + { + get { return Inner.StaticAnalyzer; } + } + + public string ModuleDefinitionFile + { + get { return Inner.ModuleDefinitionFile; } + } + public bool bNeedsLegacyStdioDefinitionsLib { get { return Inner.bNeedsLegacyStdioDefinitionsLib; } @@ -248,6 +300,18 @@ namespace UnrealBuildTool Target.WindowsPlatform.Compiler = GetDefaultCompiler(); } + // Disable linking if we're using a static analyzer + if(Target.WindowsPlatform.StaticAnalyzer != WindowsStaticAnalyzer.None) + { + Target.bDisableLinking = true; + } + + // Disable PCHs for PVS studio + if(Target.WindowsPlatform.StaticAnalyzer == WindowsStaticAnalyzer.PVSStudio) + { + Target.bUsePCHFiles = false; + } + // Override PCH settings if (bCompileWithClang) { @@ -263,6 +327,8 @@ namespace UnrealBuildTool } if (bCompileWithICL) { + Target.NumIncludedBytesPerUnityCPP = Math.Min(Target.NumIncludedBytesPerUnityCPP, 256 * 1024); + Target.bUseSharedPCHs = false; if (WindowsPlatform.bUseVCCompilerArgs) @@ -644,10 +710,6 @@ namespace UnrealBuildTool // Define to indicate profiling enabled (64-bit only) Rules.Definitions.Add("D3D12_PROFILING_ENABLED=1"); Rules.Definitions.Add("PROFILE"); - Rules.PublicAdditionalLibraries.Add("WinPixEventRuntime.lib"); - - Rules.PublicDelayLoadDLLs.Add("WinPixEventRuntime.dll"); - Rules.RuntimeDependencies.Add(new RuntimeDependency("$(EngineDir)/Binaries/ThirdParty/Windows/DirectX/x64/WinPixEventRuntime.dll")); } else { @@ -838,6 +900,8 @@ namespace UnrealBuildTool { LinkEnvironment.DefaultStackSizeCommit = IniDefaultStackSizeCommit; } + + LinkEnvironment.ModuleDefinitionFile = Target.WindowsPlatform.ModuleDefinitionFile; } /// @@ -937,7 +1001,18 @@ namespace UnrealBuildTool /// New toolchain instance. public override UEToolChain CreateToolChain(CppPlatform CppPlatform, ReadOnlyTargetRules Target) { - return new VCToolChain(CppPlatform, Target.WindowsPlatform.Compiler); + if (Target.WindowsPlatform.StaticAnalyzer == WindowsStaticAnalyzer.PVSStudio) + { + return new PVSToolChain(CppPlatform, Target.WindowsPlatform.Compiler); + } + else if(Target.WindowsPlatform.StaticAnalyzer == WindowsStaticAnalyzer.VisualCpp) + { + return new VCToolChain(CppPlatform, Target.WindowsPlatform.Compiler, true); + } + else + { + return new VCToolChain(CppPlatform, Target.WindowsPlatform.Compiler, false); + } } /// diff --git a/Engine/Source/Programs/UnrealBuildTool/Windows/VCToolChain.cs b/Engine/Source/Programs/UnrealBuildTool/Windows/VCToolChain.cs index 1d2e5b9bf06b..98bafcfeb25b 100644 --- a/Engine/Source/Programs/UnrealBuildTool/Windows/VCToolChain.cs +++ b/Engine/Source/Programs/UnrealBuildTool/Windows/VCToolChain.cs @@ -14,11 +14,13 @@ namespace UnrealBuildTool class VCToolChain : UEToolChain { WindowsCompiler Compiler; + bool bWithStaticAnalyzer; - public VCToolChain(CppPlatform CppPlatform, WindowsCompiler Compiler) + public VCToolChain(CppPlatform CppPlatform, WindowsCompiler Compiler, bool bWithStaticAnalyzer) : base(CppPlatform) { this.Compiler = Compiler; + this.bWithStaticAnalyzer = bWithStaticAnalyzer; } static void AddDefinition(List Arguments, string Definition) @@ -169,7 +171,7 @@ namespace UnrealBuildTool // NOTE re: clang: the arguments for clang-cl can be found at http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/CLCompatOptions.td?view=markup // This will show the cl.exe options that map to clang.exe ones, which ones are ignored and which ones are unsupported. - if (CompileEnvironment.bEnableCodeAnalysis) + if (bWithStaticAnalyzer) { Arguments.Add("/analyze"); @@ -227,13 +229,27 @@ namespace UnrealBuildTool // Separate functions for linker. Arguments.Add("/Gy"); - // Allow 1000% of the default memory allocation limit. - Arguments.Add("/Zm850"); + // Allow 750% of the default memory allocation limit when using the static analyzer, and 850% at other times. + if (bWithStaticAnalyzer) + { + Arguments.Add("/Zm750"); + } + else + { + Arguments.Add("/Zm850"); + } // Disable "The file contains a character that cannot be represented in the current code page" warning for non-US windows. Arguments.Add("/wd4819"); } + // Disable Microsoft extensions on VS2017+ for improved standards compliance. + if (Compiler >= WindowsCompiler.VisualStudio2017) + { + Arguments.Add("/permissive-"); + Arguments.Add("/Zc:strictStrings-"); // Have to disable strict const char* semantics due to Windows headers not being compliant. + } + // @todo UWP: UE4 is non-compliant when it comes to use of %s and %S // Previously %s meant "the current character set" and %S meant "the other one". // Now %s means multibyte and %S means wide. %Ts means "natural width". @@ -1437,7 +1453,6 @@ namespace UnrealBuildTool } - // Add delay loaded DLLs. if (!bIsBuildingLibrary) { // Delay-load these DLLs. @@ -1445,6 +1460,12 @@ namespace UnrealBuildTool { Arguments.Add(String.Format("/DELAYLOAD:\"{0}\"", DelayLoadDLL)); } + + // Pass the module definition file to the linker if we have one + if (LinkEnvironment.ModuleDefinitionFile != null && LinkEnvironment.ModuleDefinitionFile.Length > 0) + { + Arguments.Add(String.Format("/DEF:\"{0}\"", LinkEnvironment.ModuleDefinitionFile)); + } } // Set up the library paths for linking this binary diff --git a/Engine/Source/Programs/UnrealBuildTool/Windows/WindowsDeploy.cs b/Engine/Source/Programs/UnrealBuildTool/Windows/WindowsDeploy.cs index 15ff19405a0e..95fd522946ce 100644 --- a/Engine/Source/Programs/UnrealBuildTool/Windows/WindowsDeploy.cs +++ b/Engine/Source/Programs/UnrealBuildTool/Windows/WindowsDeploy.cs @@ -14,8 +14,7 @@ namespace UnrealBuildTool class BaseWindowsDeploy : UEBuildDeploy { - // public virtual bool PrepForUATPackageOrDeploy(FileReference ProjectFile, string ProjectName, string ProjectDirectory, List TargetConfigurations, List ExecutablePaths, string EngineDirectory, bool bForDistribution, string CookFlavor, bool bIsDataDeploy) - public bool PrepForUATPackageOrDeploy(FileReference ProjectFile, string ProjectName, string ProjectDirectory, List TargetConfigurations, List ExecutablePaths, string EngineDirectory, bool bForDistribution, string CookFlavor, bool bIsDataDeploy) + public bool PrepForUATPackageOrDeploy(FileReference ProjectFile, string ProjectName, string ProjectDirectory, List TargetConfigurations, List ExecutablePaths, string EngineDirectory) { string ApplicationIconPath = Path.Combine(ProjectDirectory, "Build/Windows/Application.ico"); // Does a Project icon exist? @@ -65,7 +64,7 @@ namespace UnrealBuildTool List TargetConfigs = new List { InTarget.Configuration }; List ExePaths = new List { InTarget.OutputPath.FullName }; string RelativeEnginePath = UnrealBuildTool.EngineDirectory.MakeRelativeTo(DirectoryReference.GetCurrentDirectory()); - PrepForUATPackageOrDeploy(InTarget.ProjectFile, InAppName, InTarget.ProjectDirectory.FullName, TargetConfigs, ExePaths, RelativeEnginePath, false, "", false); + PrepForUATPackageOrDeploy(InTarget.ProjectFile, InAppName, InTarget.ProjectDirectory.FullName, TargetConfigs, ExePaths, RelativeEnginePath); } return true; } diff --git a/Engine/Source/Programs/UnrealBuildTool/Windows/WindowsExports.cs b/Engine/Source/Programs/UnrealBuildTool/Windows/WindowsExports.cs index bcfe0b98ce0e..82fa3c28669f 100644 --- a/Engine/Source/Programs/UnrealBuildTool/Windows/WindowsExports.cs +++ b/Engine/Source/Programs/UnrealBuildTool/Windows/WindowsExports.cs @@ -20,14 +20,11 @@ namespace UnrealBuildTool /// /// /// - /// - /// - /// /// - public static bool PrepForUATPackageOrDeploy(FileReference ProjectFile, string ProjectName, string ProjectDirectory, List InTargetConfigurations, List InExecutablePaths, string EngineDirectory, bool bForDistribution, string CookFlavor, bool bIsDataDeploy) + public static bool PrepForUATPackageOrDeploy(FileReference ProjectFile, string ProjectName, DirectoryReference ProjectDirectory, List InTargetConfigurations, List InExecutablePaths, DirectoryReference EngineDirectory) { BaseWindowsDeploy Deploy = new BaseWindowsDeploy(); - return Deploy.PrepForUATPackageOrDeploy(ProjectFile, ProjectName, ProjectDirectory, InTargetConfigurations, InExecutablePaths, EngineDirectory, bForDistribution, CookFlavor, bIsDataDeploy); + return Deploy.PrepForUATPackageOrDeploy(ProjectFile, ProjectName, ProjectDirectory.FullName, InTargetConfigurations, InExecutablePaths.Select(x => x.FullName).ToList(), EngineDirectory.FullName); } /// diff --git a/Engine/Source/Programs/UnrealFrontend/Private/Commands/UserInterfaceCommand.cpp b/Engine/Source/Programs/UnrealFrontend/Private/Commands/UserInterfaceCommand.cpp index afdfafddd085..7426e3a7c8af 100644 --- a/Engine/Source/Programs/UnrealFrontend/Private/Commands/UserInterfaceCommand.cpp +++ b/Engine/Source/Programs/UnrealFrontend/Private/Commands/UserInterfaceCommand.cpp @@ -32,6 +32,8 @@ void FUserInterfaceCommand::Run( ) { FString UnrealFrontendLayoutIni = FPaths::GetPath(GEngineIni) + "/Layout.ini"; + FCoreStyle::ResetToDefault(); + // load required modules FModuleManager::Get().LoadModuleChecked("EditorStyle"); FModuleManager::Get().LoadModuleChecked("Messaging"); diff --git a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Controls/LogSplitContainer.cs b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Controls/LogSplitContainer.cs index d8f1b0d55bfd..b215ae40b42c 100644 --- a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Controls/LogSplitContainer.cs +++ b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Controls/LogSplitContainer.cs @@ -32,6 +32,8 @@ namespace UnrealGameSync public LogSplitContainer() { + DoubleBuffered = true; + SplitterMoved += OnSplitterMoved; } @@ -203,6 +205,11 @@ namespace UnrealGameSync } } + protected override bool ShowFocusCues + { + get { return false; } + } + protected override void OnResize(EventArgs e) { base.OnResize(e); @@ -210,12 +217,12 @@ namespace UnrealGameSync Invalidate(false); } + protected override void OnPaintBackground(PaintEventArgs e) + { + } + protected override void OnPaint(PaintEventArgs e) { - base.OnPaint(e); - - e.Graphics.FillRectangle(SystemBrushes.ButtonFace, ClientRectangle); - int CaptionMinY = SplitterDistance + CaptionPadding; int CaptionMaxY = SplitterDistance + SplitterWidth; int ButtonSize = SplitterWidth - CaptionPadding - 2 - 4; @@ -225,6 +232,26 @@ namespace UnrealGameSync ButtonSize -= CaptionPadding; } + using(Pen BackgroundPen = new Pen(SystemColors.Window)) + { + for(int Idx = 0; Idx < CaptionMinY; Idx++) + { + e.Graphics.DrawLine(BackgroundPen, 0, Idx, ClientRectangle.Width, Idx); + } + for(int Idx = CaptionMaxY; Idx < Height; Idx++) + { + e.Graphics.DrawLine(BackgroundPen, 0, Idx, ClientRectangle.Width, Idx); + } + } + using(Pen CaptionBorderPen = new Pen(SystemColors.ControlDark, 1.0f)) + { + e.Graphics.DrawRectangle(CaptionBorderPen, 0, CaptionMinY, ClientRectangle.Width - 1, CaptionMaxY - CaptionMinY - 1); + } + using(Brush BackgroundBrush = new SolidBrush(SystemColors.Window)) + { + e.Graphics.FillRectangle(BackgroundBrush, 1, CaptionMinY + 1, ClientRectangle.Width - 2, CaptionMaxY - CaptionMinY - 2); + } + int CrossX = ClientRectangle.Right - (ButtonSize / 2) - 4; int CrossY = (CaptionMinY + CaptionMaxY) / 2; if(bHoverOverClose) @@ -252,11 +279,6 @@ namespace UnrealGameSync } TextRenderer.DrawText(e.Graphics, "Log", CaptionFont, new Rectangle(2, CaptionMinY, ClientRectangle.Width - 20, CaptionMaxY - CaptionMinY), SystemColors.ControlText, TextFormatFlags.Left | TextFormatFlags.VerticalCenter); - - using(Pen CaptionBorderPen = new Pen(SystemColors.ControlDark, 1.0f)) - { - e.Graphics.DrawRectangle(CaptionBorderPen, 0, CaptionMinY, ClientRectangle.Width - 1, CaptionMaxY - CaptionMinY - 1); - } } protected override void WndProc(ref Message Message) diff --git a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Controls/TabControl.cs b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Controls/TabControl.cs new file mode 100644 index 000000000000..d9c172306853 --- /dev/null +++ b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Controls/TabControl.cs @@ -0,0 +1,525 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using System.Drawing.Drawing2D; + +namespace UnrealGameSync +{ + class TabControl : Control + { + class TabData + { + public string Name; + public object Data; + public int MinX; + public int Width; + public Rectangle TextRect; + public Tuple Highlight; + } + + class TabDragData + { + public TabData Tab; + public int InitialIdx; + public int MouseX; + public int RelativeMouseX; + } + + List Tabs = new List(); + int SelectedTabIdx; + int HoverTabIdx; + int HighlightTabIdx; + TabDragData DragState; + + public delegate void OnTabChangedDelegate(object NewTabData); + public event OnTabChangedDelegate OnTabChanged; + + public delegate void OnNewTabClickDelegate(Point Location, MouseButtons Buttons); + public event OnNewTabClickDelegate OnNewTabClick; + + public delegate void OnTabClickedDelegate(object TabData, Point Location, MouseButtons Buttons); + public event OnTabClickedDelegate OnTabClicked; + + public delegate bool OnTabClosingDelegate(object TabData); + public event OnTabClosingDelegate OnTabClosing; + + public delegate void OnTabClosedDelegate(object TabData); + public event OnTabClosedDelegate OnTabClosed; + + public delegate void OnTabReorderDelegate(); + public event OnTabReorderDelegate OnTabReorder; + + public TabControl() + { + DoubleBuffered = true; + Tabs.Add(new TabData{ Name = "+" }); + SelectedTabIdx = -1; + HoverTabIdx = -1; + HighlightTabIdx = -1; + } + + public void LockHover() + { + HighlightTabIdx = HoverTabIdx; + } + + public void UnlockHover() + { + HighlightTabIdx = -1; + Invalidate(); + } + + public void SetHighlight(int TabIdx, Tuple Highlight) + { + Tuple CurrentHighlight = Tabs[TabIdx].Highlight; + if(Highlight == null || CurrentHighlight == null) + { + if(Highlight != CurrentHighlight) + { + Tabs[TabIdx].Highlight = Highlight; + Invalidate(); + } + } + else + { + if(Highlight.Item1 != CurrentHighlight.Item1 || Highlight.Item2 != CurrentHighlight.Item2) + { + Tabs[TabIdx].Highlight = Highlight; + Invalidate(); + } + } + } + + public int InsertTab(int InsertIdx, string Name, object Data) + { + int Idx = Tabs.Count - 1; + if(InsertIdx >= 0 && InsertIdx < Tabs.Count - 1) + { + Idx = InsertIdx; + } + if(SelectedTabIdx >= Idx) + { + SelectedTabIdx++; + } + + Tabs.Insert(Idx, new TabData{ Name = Name, Data = Data }); + LayoutTabs(); + Invalidate(); + return Idx; + } + + public int GetTabCount() + { + return Tabs.Count - 1; + } + + public void SetTabName(int TabIdx, string Name) + { + Tabs[TabIdx].Name = Name; + LayoutTabs(); + Invalidate(); + } + + public object GetTabData(int TabIdx) + { + return Tabs[TabIdx].Data; + } + + public object GetSelectedTabData() + { + return Tabs[SelectedTabIdx].Data; + } + + public void SelectTab(int TabIdx) + { + if(TabIdx != SelectedTabIdx) + { + ForceSelectTab(TabIdx); + } + } + + private void ForceSelectTab(int TabIdx) + { + SelectedTabIdx = TabIdx; + LayoutTabs(); + Invalidate(); + + if(OnTabChanged != null) + { + if(SelectedTabIdx == -1) + { + OnTabChanged(null); + } + else + { + OnTabChanged(Tabs[SelectedTabIdx].Data); + } + } + } + + public void RemoveTab(int TabIdx) + { + object TabData = Tabs[TabIdx].Data; + if(OnTabClosing == null || OnTabClosing(TabData)) + { + Tabs.RemoveAt(TabIdx); + + if(HoverTabIdx == TabIdx) + { + HoverTabIdx = -1; + } + + if(HighlightTabIdx == TabIdx) + { + HighlightTabIdx = -1; + } + + if(SelectedTabIdx == TabIdx) + { + if(SelectedTabIdx < Tabs.Count - 1) + { + ForceSelectTab(SelectedTabIdx); + } + else + { + ForceSelectTab(SelectedTabIdx - 1); + } + } + else + { + if(SelectedTabIdx > TabIdx) + { + SelectedTabIdx--; + } + } + + LayoutTabs(); + Invalidate(); + + if(OnTabClosed != null) + { + OnTabClosed(TabData); + } + } + } + + void LayoutTabs() + { + using(Graphics Graphics = CreateGraphics()) + { + const int Padding = 15;//18; + + int X = 0; + for(int Idx = 0; Idx < Tabs.Count; Idx++) + { + TabData Tab = Tabs[Idx]; + + Tab.MinX = X; + int TextMinX = X + Padding;//18; + Size TextSize = TextRenderer.MeasureText(Graphics, Tab.Name, Font, new Size(int.MaxValue, int.MaxValue), TextFormatFlags.NoPadding); + Tab.TextRect = new Rectangle(TextMinX, (ClientSize.Height - 4 - TextSize.Height) / 2, TextSize.Width, TextSize.Height); + + Tab.Width = Tab.TextRect.Right + Padding - Tab.MinX;//18; + if(Idx == SelectedTabIdx) + { + Tab.Width += 8 + 13; + } + X += Tab.Width; + } + + if(X > Width) + { + int UsedWidth = Tabs.Take(Tabs.Count - 1).Sum(x => x.Width); + int RemainingWidth = Width - Tabs[Tabs.Count - 1].Width; + if(SelectedTabIdx != -1) + { + UsedWidth -= Tabs[SelectedTabIdx].Width; + RemainingWidth -= Tabs[SelectedTabIdx].Width; + } + + int NewX = 0; + for(int Idx = 0; Idx < Tabs.Count; Idx++) + { + Tabs[Idx].MinX = NewX; + int PrevWidth = Tabs[Idx].Width; + if(Idx != SelectedTabIdx && Idx != Tabs.Count - 1) + { + Tabs[Idx].Width = Math.Max((Tabs[Idx].Width * RemainingWidth) / UsedWidth, Padding * 3); + } + Tabs[Idx].TextRect = new Rectangle(NewX + Padding, Tabs[Idx].TextRect.Y, Tabs[Idx].TextRect.Width - (PrevWidth - Tabs[Idx].Width), Tabs[Idx].TextRect.Height); + NewX += Tabs[Idx].Width; + } + } + + if(DragState != null) + { + int MinOffset = -DragState.Tab.MinX; + int MaxOffset = Tabs[Tabs.Count - 1].MinX - DragState.Tab.Width - DragState.Tab.MinX; + + int Offset = (DragState.MouseX - DragState.RelativeMouseX) - DragState.Tab.MinX; + Offset = Math.Max(Offset, MinOffset); + Offset = Math.Min(Offset, MaxOffset); + + DragState.Tab.MinX += Offset; + DragState.Tab.TextRect.Offset(Offset, 0); + } + } + } + + protected override void OnResize(EventArgs e) + { + base.OnResize(e); + + LayoutTabs(); + Invalidate(); + } + + protected override void OnMouseDown(MouseEventArgs e) + { + base.OnMouseDown(e); + + OnMouseMove(e); + + if(HoverTabIdx != -1) + { + if(e.Button == MouseButtons.Left) + { + if(HoverTabIdx == SelectedTabIdx) + { + if(e.Location.X > Tabs[HoverTabIdx].TextRect.Right) + { + RemoveTab(HoverTabIdx); + } + else + { + DragState = new TabDragData{ Tab = Tabs[SelectedTabIdx], InitialIdx = SelectedTabIdx, MouseX = e.Location.X, RelativeMouseX = e.Location.X - Tabs[SelectedTabIdx].MinX }; + } + } + else + { + if(HoverTabIdx == Tabs.Count - 1) + { + OnNewTabClick(e.Location, e.Button); + } + else + { + SelectTab(HoverTabIdx); + } + } + } + else if(e.Button == MouseButtons.Middle) + { + if(HoverTabIdx != Tabs.Count - 1) + { + RemoveTab(HoverTabIdx); + } + } + } + + if(OnTabClicked != null) + { + object TabData = (HoverTabIdx == -1)? null : Tabs[HoverTabIdx].Data; + OnTabClicked(TabData, e.Location, e.Button); + } + } + + protected override void OnMouseUp(MouseEventArgs e) + { + base.OnMouseUp(e); + + if(DragState != null) + { + if(OnTabReorder != null) + { + OnTabReorder(); + } + + DragState = null; + + LayoutTabs(); + Invalidate(); + } + } + + protected override void OnMouseMove(MouseEventArgs e) + { + base.OnMouseMove(e); + + if(DragState != null) + { + DragState.MouseX = e.Location.X; + + Tabs.Remove(DragState.Tab); + + int TotalWidth = 0; + for(int InsertIdx = 0;;InsertIdx++) + { + if(InsertIdx == Tabs.Count - 1 || DragState.MouseX - DragState.RelativeMouseX < TotalWidth + Tabs[InsertIdx].Width / 2) + { + HoverTabIdx = SelectedTabIdx = InsertIdx; + Tabs.Insert(InsertIdx, DragState.Tab); + break; + } + TotalWidth += Tabs[InsertIdx].Width; + } + + LayoutTabs(); + Invalidate(); + } + else + { + int NewHoverTabIdx = -1; + if(ClientRectangle.Contains(e.Location)) + { + for(int Idx = 0; Idx < Tabs.Count; Idx++) + { + if(e.Location.X > Tabs[Idx].MinX && e.Location.X < Tabs[Idx].MinX + Tabs[Idx].Width) + { + NewHoverTabIdx = Idx; + break; + } + } + } + + if(HoverTabIdx != NewHoverTabIdx) + { + HoverTabIdx = NewHoverTabIdx; + LayoutTabs(); + Invalidate(); + + if(HoverTabIdx != -1) + { + Capture = true; + } + else + { + Capture = false; + } + } + } + } + + protected override void OnMouseCaptureChanged(EventArgs e) + { + base.OnMouseCaptureChanged(e); + + if(HoverTabIdx != -1) + { + HoverTabIdx = -1; + Invalidate(); + } + } + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + + LayoutTabs(); + + using(SolidBrush SelectedBrush = new SolidBrush(Color.FromArgb(0, 136, 204))) + { + using(SolidBrush HoverBrush = new SolidBrush(Color.FromArgb(192, 192, 192))) + { + for(int Idx = 0; Idx < Tabs.Count; Idx++) + { + TabData Tab = Tabs[Idx]; + if(Idx == SelectedTabIdx) + { + DrawBackground(e.Graphics, Tab, SystemBrushes.Window, SelectedBrush, Tab.Highlight); + } + else if(Idx == HoverTabIdx || Idx == HighlightTabIdx) + { + DrawBackground(e.Graphics, Tab, SystemBrushes.Window, HoverBrush, Tab.Highlight); + } + else + { + DrawBackground(e.Graphics, Tab, SystemBrushes.Control, SystemBrushes.Control, Tab.Highlight); + } + } + } + } + + using(Pen SeparatorPen = new Pen(Color.FromArgb(192, SystemColors.ControlDark))) + { + for(int Idx = 0; Idx < Tabs.Count; Idx++) + { + TabData Tab = Tabs[Idx]; + if(Idx > 0 || Idx == SelectedTabIdx || Idx == HoverTabIdx || Idx == HighlightTabIdx || Tabs.Count == 1) + { + e.Graphics.DrawLine(SeparatorPen, Tab.MinX, 0, Tab.MinX, ClientSize.Height - 2); + } + if(Idx < Tabs.Count - 1 || Idx == HoverTabIdx || Idx == HighlightTabIdx || Tabs.Count == 1) + { + e.Graphics.DrawLine(SeparatorPen, Tab.MinX + Tab.Width, 0, Tab.MinX + Tab.Width, ClientSize.Height - 2); + } + if(Idx == HoverTabIdx || Idx == HighlightTabIdx) + { + e.Graphics.DrawLine(SeparatorPen, Tab.MinX, 0, Tab.MinX + Tab.Width, 0); + } + } + } + + for(int Idx = 0; Idx < Tabs.Count; Idx++) + { + if(Idx != SelectedTabIdx) + { + TabData Tab = Tabs[Idx]; + TextRenderer.DrawText(e.Graphics, Tab.Name, Font, Tab.TextRect, Color.Black, TextFormatFlags.NoPadding | TextFormatFlags.EndEllipsis); + } + } + + if(SelectedTabIdx != -1) + { + TabData SelectedTab = Tabs[SelectedTabIdx]; + + // Draw the close button + SmoothingMode PrevSmoothingMode = e.Graphics.SmoothingMode; + e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; + + int CloseMidX = (SelectedTab.MinX + SelectedTab.Width + SelectedTab.TextRect.Right) / 2; + int CloseMidY = (ClientSize.Height - 4) / 2; + + Rectangle CloseButton = new Rectangle(CloseMidX - (13 / 2), CloseMidY - (13 / 2), 13, 13); + e.Graphics.FillEllipse(SystemBrushes.ControlDark, CloseButton); + + using(Pen CrossPen = new Pen(SystemBrushes.Window, 2.0f)) + { + const float Indent = 3.5f; + e.Graphics.DrawLine(CrossPen, CloseButton.Left + Indent, CloseButton.Top + Indent, CloseButton.Right - Indent, CloseButton.Bottom - Indent); + e.Graphics.DrawLine(CrossPen, CloseButton.Left + Indent, CloseButton.Bottom - Indent, CloseButton.Right - Indent, CloseButton.Top + Indent); + } + e.Graphics.SmoothingMode = PrevSmoothingMode; + + // Draw the text + TextRenderer.DrawText(e.Graphics, SelectedTab.Name, Font, SelectedTab.TextRect, Color.Black, TextFormatFlags.NoPadding); + + // Border + e.Graphics.DrawLine(SystemPens.ControlDark, SelectedTab.MinX, 0, SelectedTab.MinX + SelectedTab.Width, 0); + e.Graphics.DrawLine(SystemPens.ControlDark, SelectedTab.MinX, 0, SelectedTab.MinX, ClientSize.Height - 2); + e.Graphics.DrawLine(SystemPens.ControlDark, SelectedTab.MinX + SelectedTab.Width, 0, SelectedTab.MinX + SelectedTab.Width, ClientSize.Height - 2); + } + + e.Graphics.DrawLine(SystemPens.ControlDark, 0, ClientSize.Height - 2, ClientSize.Width, ClientSize.Height - 2); + e.Graphics.DrawLine(SystemPens.ControlLightLight, 0, ClientSize.Height - 1, ClientSize.Width, ClientSize.Height - 1); + } + + void DrawBackground(Graphics Graphics, TabData Tab, Brush BackgroundBrush, Brush StripeBrush, Tuple Highlight) + { + Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None; + Graphics.FillRectangle(BackgroundBrush, Tab.MinX + 1, 1, Tab.Width - 1, ClientSize.Height - 3); + Graphics.FillRectangle(StripeBrush, Tab.MinX + 1, ClientSize.Height - 5, Tab.Width - 1, 3); + + if(Highlight != null && Highlight.Item2 > 0.0f) + { + using(SolidBrush Brush = new SolidBrush(Highlight.Item1)) + { + Graphics.FillRectangle(Brush, Tab.MinX + 1, ClientSize.Height - 5, (int)((Tab.Width - 2) * Highlight.Item2), 3); + } + } + } + } +} diff --git a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Controls/WorkspaceControl.Designer.cs b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Controls/WorkspaceControl.Designer.cs new file mode 100644 index 000000000000..0f2d35a99119 --- /dev/null +++ b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Controls/WorkspaceControl.Designer.cs @@ -0,0 +1,988 @@ +namespace UnrealGameSync +{ + partial class WorkspaceControl + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.OptionsContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); + this.OptionsContextMenu_ScheduledSync = new System.Windows.Forms.ToolStripMenuItem(); + this.OptionsContextMenu_SyncPrecompiledEditor = new System.Windows.Forms.ToolStripMenuItem(); + this.OptionsContextMenu_AutoResolveConflicts = new System.Windows.Forms.ToolStripMenuItem(); + this.OptionsContextMenu_SyncFilter = new System.Windows.Forms.ToolStripMenuItem(); + this.OptionsContextMenu_PerforceSettings = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator(); + this.OptionsContextMenu_EditorBuildConfiguration = new System.Windows.Forms.ToolStripMenuItem(); + this.OptionsContextMenu_BuildConfig_Debug = new System.Windows.Forms.ToolStripMenuItem(); + this.OptionsContextMenu_BuildConfig_DebugGame = new System.Windows.Forms.ToolStripMenuItem(); + this.OptionsContextMenu_BuildConfig_Development = new System.Windows.Forms.ToolStripMenuItem(); + this.OptionsContextMenu_UseIncrementalBuilds = new System.Windows.Forms.ToolStripMenuItem(); + this.OptionsContextMenu_CustomizeBuildSteps = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator5 = new System.Windows.Forms.ToolStripSeparator(); + this.OptionsContextMenu_EditorArguments = new System.Windows.Forms.ToolStripMenuItem(); + this.OptionsContextMenu_TimeZone = new System.Windows.Forms.ToolStripMenuItem(); + this.OptionsContextMenu_TimeZone_Local = new System.Windows.Forms.ToolStripMenuItem(); + this.OptionsContextMenu_TimeZone_PerforceServer = new System.Windows.Forms.ToolStripMenuItem(); + this.OptionsContextMenu_AutomaticallyRunAtStartup = new System.Windows.Forms.ToolStripMenuItem(); + this.OptionsContextMenu_KeepInTray = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator6 = new System.Windows.Forms.ToolStripSeparator(); + this.OptionsContextMenu_Diagnostics = new System.Windows.Forms.ToolStripMenuItem(); + this.tabLabelsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.OptionsContextMenu_TabNames_Stream = new System.Windows.Forms.ToolStripMenuItem(); + this.OptionsContextMenu_TabNames_WorkspaceName = new System.Windows.Forms.ToolStripMenuItem(); + this.OptionsContextMenu_TabNames_WorkspaceRoot = new System.Windows.Forms.ToolStripMenuItem(); + this.OptionsContextMenu_TabNames_ProjectFile = new System.Windows.Forms.ToolStripMenuItem(); + this.OnlyShowReviewedCheckBox = new System.Windows.Forms.CheckBox(); + this.RunAfterSyncCheckBox = new System.Windows.Forms.CheckBox(); + this.BuildAfterSyncCheckBox = new System.Windows.Forms.CheckBox(); + this.AfterSyncingLabel = new System.Windows.Forms.Label(); + this.BuildListContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); + this.BuildListContextMenu_LaunchEditor = new System.Windows.Forms.ToolStripMenuItem(); + this.BuildListContextMenu_Sync = new System.Windows.Forms.ToolStripMenuItem(); + this.BuildListContextMenu_SyncContentOnly = new System.Windows.Forms.ToolStripMenuItem(); + this.BuildListContextMenu_SyncOnlyThisChange = new System.Windows.Forms.ToolStripMenuItem(); + this.BuildListContextMenu_Build = new System.Windows.Forms.ToolStripMenuItem(); + this.BuildListContextMenu_Rebuild = new System.Windows.Forms.ToolStripMenuItem(); + this.BuildListContextMenu_GenerateProjectFiles = new System.Windows.Forms.ToolStripMenuItem(); + this.BuildListContextMenu_Cancel = new System.Windows.Forms.ToolStripMenuItem(); + this.BuildListContextMenu_OpenVisualStudio = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator(); + this.BuildListContextMenu_MarkGood = new System.Windows.Forms.ToolStripMenuItem(); + this.BuildListContextMenu_MarkBad = new System.Windows.Forms.ToolStripMenuItem(); + this.BuildListContextMenu_WithdrawReview = new System.Windows.Forms.ToolStripMenuItem(); + this.BuildListContextMenu_LeaveComment = new System.Windows.Forms.ToolStripMenuItem(); + this.BuildListContextMenu_EditComment = new System.Windows.Forms.ToolStripMenuItem(); + this.BuildListContextMenu_StartInvestigating = new System.Windows.Forms.ToolStripMenuItem(); + this.BuildListContextMenu_FinishInvestigating = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); + this.BuildListContextMenu_AddStar = new System.Windows.Forms.ToolStripMenuItem(); + this.BuildListContextMenu_RemoveStar = new System.Windows.Forms.ToolStripMenuItem(); + this.BuildListContextMenu_TimeZoneSeparator = new System.Windows.Forms.ToolStripSeparator(); + this.BuildListContextMenu_ShowServerTimes = new System.Windows.Forms.ToolStripMenuItem(); + this.BuildListContextMenu_ShowLocalTimes = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); + this.BuildListContextMenu_MoreInfo = new System.Windows.Forms.ToolStripMenuItem(); + this.NotifyIcon = new System.Windows.Forms.NotifyIcon(this.components); + this.toolStripSeparator7 = new System.Windows.Forms.ToolStripSeparator(); + this.BuildListToolTip = new System.Windows.Forms.ToolTip(this.components); + this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); + this.OpenSolutionAfterSyncCheckBox = new System.Windows.Forms.CheckBox(); + this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel(); + this.OptionsButton = new System.Windows.Forms.Button(); + this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); + this.Splitter = new UnrealGameSync.LogSplitContainer(); + this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel(); + this.StatusPanel = new UnrealGameSync.StatusPanel(); + this.BuildList = new UnrealGameSync.BuildListControl(); + this.IconColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.ChangeColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.TimeColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.AuthorColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.DescriptionColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.CISColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.StatusColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.panel1 = new System.Windows.Forms.Panel(); + this.SyncLog = new UnrealGameSync.LogControl(); + this.MoreToolsContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); + this.MoreActionsContextMenu_CustomToolSeparator = new System.Windows.Forms.ToolStripSeparator(); + this.MoreToolsContextMenu_CleanWorkspace = new System.Windows.Forms.ToolStripMenuItem(); + this.SyncContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); + this.SyncContextMenu_LatestChange = new System.Windows.Forms.ToolStripMenuItem(); + this.SyncContextMenu_LatestGoodChange = new System.Windows.Forms.ToolStripMenuItem(); + this.SyncContextMenu_LatestStarredChange = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator8 = new System.Windows.Forms.ToolStripSeparator(); + this.SyncContexMenu_EnterChangelist = new System.Windows.Forms.ToolStripMenuItem(); + this.StreamContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); + this.OptionsContextMenu.SuspendLayout(); + this.BuildListContextMenu.SuspendLayout(); + this.flowLayoutPanel1.SuspendLayout(); + this.tableLayoutPanel3.SuspendLayout(); + this.tableLayoutPanel2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.Splitter)).BeginInit(); + this.Splitter.Panel1.SuspendLayout(); + this.Splitter.Panel2.SuspendLayout(); + this.Splitter.SuspendLayout(); + this.tableLayoutPanel4.SuspendLayout(); + this.panel1.SuspendLayout(); + this.MoreToolsContextMenu.SuspendLayout(); + this.SyncContextMenu.SuspendLayout(); + this.SuspendLayout(); + // + // OptionsContextMenu + // + this.OptionsContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.OptionsContextMenu_ScheduledSync, + this.OptionsContextMenu_SyncPrecompiledEditor, + this.OptionsContextMenu_AutoResolveConflicts, + this.OptionsContextMenu_SyncFilter, + this.OptionsContextMenu_PerforceSettings, + this.toolStripSeparator3, + this.OptionsContextMenu_EditorBuildConfiguration, + this.OptionsContextMenu_UseIncrementalBuilds, + this.OptionsContextMenu_CustomizeBuildSteps, + this.toolStripSeparator5, + this.tabLabelsToolStripMenuItem, + this.OptionsContextMenu_EditorArguments, + this.OptionsContextMenu_TimeZone, + this.OptionsContextMenu_AutomaticallyRunAtStartup, + this.OptionsContextMenu_KeepInTray, + this.toolStripSeparator6, + this.OptionsContextMenu_Diagnostics}); + this.OptionsContextMenu.Name = "ToolsMenuStrip"; + this.OptionsContextMenu.Size = new System.Drawing.Size(268, 352); + // + // OptionsContextMenu_ScheduledSync + // + this.OptionsContextMenu_ScheduledSync.Name = "OptionsContextMenu_ScheduledSync"; + this.OptionsContextMenu_ScheduledSync.Size = new System.Drawing.Size(267, 22); + this.OptionsContextMenu_ScheduledSync.Text = "Scheduled Sync..."; + this.OptionsContextMenu_ScheduledSync.Click += new System.EventHandler(this.OptionsContextMenu_ScheduleSync_Click); + // + // OptionsContextMenu_SyncPrecompiledEditor + // + this.OptionsContextMenu_SyncPrecompiledEditor.Name = "OptionsContextMenu_SyncPrecompiledEditor"; + this.OptionsContextMenu_SyncPrecompiledEditor.Size = new System.Drawing.Size(267, 22); + this.OptionsContextMenu_SyncPrecompiledEditor.Text = "Sync Precompiled Editor"; + this.OptionsContextMenu_SyncPrecompiledEditor.Click += new System.EventHandler(this.OptionsContextMenu_SyncPrecompiledEditor_Click); + // + // OptionsContextMenu_AutoResolveConflicts + // + this.OptionsContextMenu_AutoResolveConflicts.Name = "OptionsContextMenu_AutoResolveConflicts"; + this.OptionsContextMenu_AutoResolveConflicts.Size = new System.Drawing.Size(267, 22); + this.OptionsContextMenu_AutoResolveConflicts.Text = "Auto-Resolve Conflicts"; + this.OptionsContextMenu_AutoResolveConflicts.Click += new System.EventHandler(this.OptionsContextMenu_AutoResolveConflicts_Click); + // + // OptionsContextMenu_SyncFilter + // + this.OptionsContextMenu_SyncFilter.Name = "OptionsContextMenu_SyncFilter"; + this.OptionsContextMenu_SyncFilter.Size = new System.Drawing.Size(267, 22); + this.OptionsContextMenu_SyncFilter.Text = "Sync Filter..."; + this.OptionsContextMenu_SyncFilter.Click += new System.EventHandler(this.OptionsContextMenu_SyncFilter_Click); + // + // OptionsContextMenu_PerforceSettings + // + this.OptionsContextMenu_PerforceSettings.Name = "OptionsContextMenu_PerforceSettings"; + this.OptionsContextMenu_PerforceSettings.Size = new System.Drawing.Size(267, 22); + this.OptionsContextMenu_PerforceSettings.Text = "Perforce Settings..."; + this.OptionsContextMenu_PerforceSettings.Click += new System.EventHandler(this.OptionsContextMenu_PerforceSettings_Click); + // + // toolStripSeparator3 + // + this.toolStripSeparator3.Name = "toolStripSeparator3"; + this.toolStripSeparator3.Size = new System.Drawing.Size(264, 6); + // + // OptionsContextMenu_EditorBuildConfiguration + // + this.OptionsContextMenu_EditorBuildConfiguration.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.OptionsContextMenu_BuildConfig_Debug, + this.OptionsContextMenu_BuildConfig_DebugGame, + this.OptionsContextMenu_BuildConfig_Development}); + this.OptionsContextMenu_EditorBuildConfiguration.Name = "OptionsContextMenu_EditorBuildConfiguration"; + this.OptionsContextMenu_EditorBuildConfiguration.Size = new System.Drawing.Size(267, 22); + this.OptionsContextMenu_EditorBuildConfiguration.Text = "Editor Build Configuration"; + // + // OptionsContextMenu_BuildConfig_Debug + // + this.OptionsContextMenu_BuildConfig_Debug.Name = "OptionsContextMenu_BuildConfig_Debug"; + this.OptionsContextMenu_BuildConfig_Debug.Size = new System.Drawing.Size(145, 22); + this.OptionsContextMenu_BuildConfig_Debug.Text = "Debug"; + this.OptionsContextMenu_BuildConfig_Debug.Click += new System.EventHandler(this.OptionsContextMenu_BuildConfig_Debug_Click); + // + // OptionsContextMenu_BuildConfig_DebugGame + // + this.OptionsContextMenu_BuildConfig_DebugGame.Name = "OptionsContextMenu_BuildConfig_DebugGame"; + this.OptionsContextMenu_BuildConfig_DebugGame.Size = new System.Drawing.Size(145, 22); + this.OptionsContextMenu_BuildConfig_DebugGame.Text = "DebugGame"; + this.OptionsContextMenu_BuildConfig_DebugGame.Click += new System.EventHandler(this.OptionsContextMenu_BuildConfig_DebugGame_Click); + // + // OptionsContextMenu_BuildConfig_Development + // + this.OptionsContextMenu_BuildConfig_Development.Checked = true; + this.OptionsContextMenu_BuildConfig_Development.CheckState = System.Windows.Forms.CheckState.Checked; + this.OptionsContextMenu_BuildConfig_Development.Name = "OptionsContextMenu_BuildConfig_Development"; + this.OptionsContextMenu_BuildConfig_Development.Size = new System.Drawing.Size(145, 22); + this.OptionsContextMenu_BuildConfig_Development.Text = "Development"; + this.OptionsContextMenu_BuildConfig_Development.Click += new System.EventHandler(this.OptionsContextMenu_BuildConfig_Development_Click); + // + // OptionsContextMenu_UseIncrementalBuilds + // + this.OptionsContextMenu_UseIncrementalBuilds.Name = "OptionsContextMenu_UseIncrementalBuilds"; + this.OptionsContextMenu_UseIncrementalBuilds.Size = new System.Drawing.Size(267, 22); + this.OptionsContextMenu_UseIncrementalBuilds.Text = "Use Incremental Builds"; + this.OptionsContextMenu_UseIncrementalBuilds.Click += new System.EventHandler(this.OptionsContextMenu_UseIncrementalBuilds_Click); + // + // OptionsContextMenu_CustomizeBuildSteps + // + this.OptionsContextMenu_CustomizeBuildSteps.Name = "OptionsContextMenu_CustomizeBuildSteps"; + this.OptionsContextMenu_CustomizeBuildSteps.Size = new System.Drawing.Size(267, 22); + this.OptionsContextMenu_CustomizeBuildSteps.Text = "Customize Build Steps..."; + this.OptionsContextMenu_CustomizeBuildSteps.Click += new System.EventHandler(this.OptionsContextMenu_EditBuildSteps_Click); + // + // toolStripSeparator5 + // + this.toolStripSeparator5.Name = "toolStripSeparator5"; + this.toolStripSeparator5.Size = new System.Drawing.Size(264, 6); + // + // OptionsContextMenu_EditorArguments + // + this.OptionsContextMenu_EditorArguments.Name = "OptionsContextMenu_EditorArguments"; + this.OptionsContextMenu_EditorArguments.Size = new System.Drawing.Size(267, 22); + this.OptionsContextMenu_EditorArguments.Text = "Editor Command Line Arguments..."; + this.OptionsContextMenu_EditorArguments.Click += new System.EventHandler(this.OptionsContextMenu_EditorArguments_Click); + // + // OptionsContextMenu_TimeZone + // + this.OptionsContextMenu_TimeZone.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.OptionsContextMenu_TimeZone_Local, + this.OptionsContextMenu_TimeZone_PerforceServer}); + this.OptionsContextMenu_TimeZone.Name = "OptionsContextMenu_TimeZone"; + this.OptionsContextMenu_TimeZone.Size = new System.Drawing.Size(267, 22); + this.OptionsContextMenu_TimeZone.Text = "Time Zone"; + // + // OptionsContextMenu_TimeZone_Local + // + this.OptionsContextMenu_TimeZone_Local.Name = "OptionsContextMenu_TimeZone_Local"; + this.OptionsContextMenu_TimeZone_Local.Size = new System.Drawing.Size(153, 22); + this.OptionsContextMenu_TimeZone_Local.Text = "Local"; + this.OptionsContextMenu_TimeZone_Local.Click += new System.EventHandler(this.BuildListContextMenu_ShowLocalTimes_Click); + // + // OptionsContextMenu_TimeZone_PerforceServer + // + this.OptionsContextMenu_TimeZone_PerforceServer.Name = "OptionsContextMenu_TimeZone_PerforceServer"; + this.OptionsContextMenu_TimeZone_PerforceServer.Size = new System.Drawing.Size(153, 22); + this.OptionsContextMenu_TimeZone_PerforceServer.Text = "Perforce Server"; + this.OptionsContextMenu_TimeZone_PerforceServer.Click += new System.EventHandler(this.BuildListContextMenu_ShowServerTimes_Click); + // + // OptionsContextMenu_AutomaticallyRunAtStartup + // + this.OptionsContextMenu_AutomaticallyRunAtStartup.Name = "OptionsContextMenu_AutomaticallyRunAtStartup"; + this.OptionsContextMenu_AutomaticallyRunAtStartup.Size = new System.Drawing.Size(267, 22); + this.OptionsContextMenu_AutomaticallyRunAtStartup.Text = "Automatically run at startup"; + this.OptionsContextMenu_AutomaticallyRunAtStartup.Click += new System.EventHandler(this.OptionsContextMenu_AutomaticallyRunAtStartup_Click); + // + // OptionsContextMenu_KeepInTray + // + this.OptionsContextMenu_KeepInTray.Name = "OptionsContextMenu_KeepInTray"; + this.OptionsContextMenu_KeepInTray.Size = new System.Drawing.Size(267, 22); + this.OptionsContextMenu_KeepInTray.Text = "Stay in notification area when closed"; + this.OptionsContextMenu_KeepInTray.Click += new System.EventHandler(this.OptionsContextMenu_KeepInTray_Click); + // + // toolStripSeparator6 + // + this.toolStripSeparator6.Name = "toolStripSeparator6"; + this.toolStripSeparator6.Size = new System.Drawing.Size(264, 6); + // + // OptionsContextMenu_Diagnostics + // + this.OptionsContextMenu_Diagnostics.Name = "OptionsContextMenu_Diagnostics"; + this.OptionsContextMenu_Diagnostics.Size = new System.Drawing.Size(267, 22); + this.OptionsContextMenu_Diagnostics.Text = "Diagnostics..."; + this.OptionsContextMenu_Diagnostics.Click += new System.EventHandler(this.OptionsContextMenu_Diagnostics_Click); + // + // tabLabelsToolStripMenuItem + // + this.tabLabelsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.OptionsContextMenu_TabNames_Stream, + this.OptionsContextMenu_TabNames_WorkspaceName, + this.OptionsContextMenu_TabNames_WorkspaceRoot, + this.OptionsContextMenu_TabNames_ProjectFile}); + this.tabLabelsToolStripMenuItem.Name = "tabLabelsToolStripMenuItem"; + this.tabLabelsToolStripMenuItem.Size = new System.Drawing.Size(267, 22); + this.tabLabelsToolStripMenuItem.Text = "Tab Names"; + // + // OptionsContextMenu_TabNames_Stream + // + this.OptionsContextMenu_TabNames_Stream.Name = "OptionsContextMenu_TabNames_Stream"; + this.OptionsContextMenu_TabNames_Stream.Size = new System.Drawing.Size(167, 22); + this.OptionsContextMenu_TabNames_Stream.Text = "Stream"; + this.OptionsContextMenu_TabNames_Stream.Click += new System.EventHandler(this.OptionsContextMenu_TabNames_Stream_Click); + // + // OptionsContextMenu_TabNames_WorkspaceName + // + this.OptionsContextMenu_TabNames_WorkspaceName.Name = "OptionsContextMenu_TabNames_WorkspaceName"; + this.OptionsContextMenu_TabNames_WorkspaceName.Size = new System.Drawing.Size(167, 22); + this.OptionsContextMenu_TabNames_WorkspaceName.Text = "Workspace Name"; + this.OptionsContextMenu_TabNames_WorkspaceName.Click += new System.EventHandler(this.OptionsContextMenu_TabNames_WorkspaceName_Click); + // + // OptionsContextMenu_TabNames_WorkspaceRoot + // + this.OptionsContextMenu_TabNames_WorkspaceRoot.Name = "OptionsContextMenu_TabNames_WorkspaceRoot"; + this.OptionsContextMenu_TabNames_WorkspaceRoot.Size = new System.Drawing.Size(167, 22); + this.OptionsContextMenu_TabNames_WorkspaceRoot.Text = "Workspace Root"; + this.OptionsContextMenu_TabNames_WorkspaceRoot.Click += new System.EventHandler(this.OptionsContextMenu_TabNames_WorkspaceRoot_Click); + // + // OptionsContextMenu_TabNames_ProjectFile + // + this.OptionsContextMenu_TabNames_ProjectFile.Name = "OptionsContextMenu_TabNames_ProjectFile"; + this.OptionsContextMenu_TabNames_ProjectFile.Size = new System.Drawing.Size(167, 22); + this.OptionsContextMenu_TabNames_ProjectFile.Text = "Project File"; + this.OptionsContextMenu_TabNames_ProjectFile.Click += new System.EventHandler(this.OptionsContextMenu_TabNames_ProjectFile_Click); + // + // OnlyShowReviewedCheckBox + // + this.OnlyShowReviewedCheckBox.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.OnlyShowReviewedCheckBox.AutoSize = true; + this.OnlyShowReviewedCheckBox.Location = new System.Drawing.Point(3, 11); + this.OnlyShowReviewedCheckBox.Name = "OnlyShowReviewedCheckBox"; + this.OnlyShowReviewedCheckBox.Size = new System.Drawing.Size(166, 17); + this.OnlyShowReviewedCheckBox.TabIndex = 3; + this.OnlyShowReviewedCheckBox.Text = "Only show reviewed changes"; + this.OnlyShowReviewedCheckBox.UseVisualStyleBackColor = true; + this.OnlyShowReviewedCheckBox.CheckedChanged += new System.EventHandler(this.OnlyShowReviewedCheckBox_CheckedChanged); + // + // RunAfterSyncCheckBox + // + this.RunAfterSyncCheckBox.AutoSize = true; + this.RunAfterSyncCheckBox.Location = new System.Drawing.Point(138, 3); + this.RunAfterSyncCheckBox.Name = "RunAfterSyncCheckBox"; + this.RunAfterSyncCheckBox.Size = new System.Drawing.Size(45, 17); + this.RunAfterSyncCheckBox.TabIndex = 6; + this.RunAfterSyncCheckBox.Text = "Run"; + this.RunAfterSyncCheckBox.UseVisualStyleBackColor = true; + this.RunAfterSyncCheckBox.CheckedChanged += new System.EventHandler(this.RunAfterSyncCheckBox_CheckedChanged); + // + // BuildAfterSyncCheckBox + // + this.BuildAfterSyncCheckBox.AutoSize = true; + this.BuildAfterSyncCheckBox.Location = new System.Drawing.Point(84, 3); + this.BuildAfterSyncCheckBox.Name = "BuildAfterSyncCheckBox"; + this.BuildAfterSyncCheckBox.Size = new System.Drawing.Size(48, 17); + this.BuildAfterSyncCheckBox.TabIndex = 5; + this.BuildAfterSyncCheckBox.Text = "Build"; + this.BuildAfterSyncCheckBox.UseVisualStyleBackColor = true; + this.BuildAfterSyncCheckBox.CheckedChanged += new System.EventHandler(this.BuildAfterSyncCheckBox_CheckedChanged); + // + // AfterSyncingLabel + // + this.AfterSyncingLabel.AutoSize = true; + this.AfterSyncingLabel.Location = new System.Drawing.Point(3, 0); + this.AfterSyncingLabel.Name = "AfterSyncingLabel"; + this.AfterSyncingLabel.Padding = new System.Windows.Forms.Padding(0, 4, 0, 0); + this.AfterSyncingLabel.Size = new System.Drawing.Size(75, 17); + this.AfterSyncingLabel.TabIndex = 4; + this.AfterSyncingLabel.Text = "After syncing:"; + // + // BuildListContextMenu + // + this.BuildListContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.BuildListContextMenu_LaunchEditor, + this.BuildListContextMenu_Sync, + this.BuildListContextMenu_SyncContentOnly, + this.BuildListContextMenu_SyncOnlyThisChange, + this.BuildListContextMenu_Build, + this.BuildListContextMenu_Rebuild, + this.BuildListContextMenu_GenerateProjectFiles, + this.BuildListContextMenu_Cancel, + this.BuildListContextMenu_OpenVisualStudio, + this.toolStripSeparator4, + this.BuildListContextMenu_MarkGood, + this.BuildListContextMenu_MarkBad, + this.BuildListContextMenu_WithdrawReview, + this.BuildListContextMenu_LeaveComment, + this.BuildListContextMenu_EditComment, + this.BuildListContextMenu_StartInvestigating, + this.BuildListContextMenu_FinishInvestigating, + this.toolStripSeparator1, + this.BuildListContextMenu_AddStar, + this.BuildListContextMenu_RemoveStar, + this.BuildListContextMenu_TimeZoneSeparator, + this.BuildListContextMenu_ShowServerTimes, + this.BuildListContextMenu_ShowLocalTimes, + this.toolStripSeparator2, + this.BuildListContextMenu_MoreInfo}); + this.BuildListContextMenu.Name = "BuildListContextMenu"; + this.BuildListContextMenu.Size = new System.Drawing.Size(200, 490); + // + // BuildListContextMenu_LaunchEditor + // + this.BuildListContextMenu_LaunchEditor.Name = "BuildListContextMenu_LaunchEditor"; + this.BuildListContextMenu_LaunchEditor.Size = new System.Drawing.Size(199, 22); + this.BuildListContextMenu_LaunchEditor.Text = "Launch editor"; + this.BuildListContextMenu_LaunchEditor.Click += new System.EventHandler(this.BuildListContextMenu_LaunchEditor_Click); + // + // BuildListContextMenu_Sync + // + this.BuildListContextMenu_Sync.Name = "BuildListContextMenu_Sync"; + this.BuildListContextMenu_Sync.Size = new System.Drawing.Size(199, 22); + this.BuildListContextMenu_Sync.Text = "Sync"; + this.BuildListContextMenu_Sync.Click += new System.EventHandler(this.BuildListContextMenu_Sync_Click); + // + // BuildListContextMenu_SyncContentOnly + // + this.BuildListContextMenu_SyncContentOnly.Name = "BuildListContextMenu_SyncContentOnly"; + this.BuildListContextMenu_SyncContentOnly.Size = new System.Drawing.Size(199, 22); + this.BuildListContextMenu_SyncContentOnly.Text = "Sync (Just Content)"; + this.BuildListContextMenu_SyncContentOnly.Click += new System.EventHandler(this.BuildListContextMenu_SyncContentOnly_Click); + // + // BuildListContextMenu_SyncOnlyThisChange + // + this.BuildListContextMenu_SyncOnlyThisChange.Name = "BuildListContextMenu_SyncOnlyThisChange"; + this.BuildListContextMenu_SyncOnlyThisChange.Size = new System.Drawing.Size(199, 22); + this.BuildListContextMenu_SyncOnlyThisChange.Text = "Sync (Just This Change)"; + this.BuildListContextMenu_SyncOnlyThisChange.Click += new System.EventHandler(this.BuildListContextMenu_SyncOnlyThisChange_Click); + // + // BuildListContextMenu_Build + // + this.BuildListContextMenu_Build.Name = "BuildListContextMenu_Build"; + this.BuildListContextMenu_Build.Size = new System.Drawing.Size(199, 22); + this.BuildListContextMenu_Build.Text = "Build"; + this.BuildListContextMenu_Build.Click += new System.EventHandler(this.BuildListContextMenu_Build_Click); + // + // BuildListContextMenu_Rebuild + // + this.BuildListContextMenu_Rebuild.Name = "BuildListContextMenu_Rebuild"; + this.BuildListContextMenu_Rebuild.Size = new System.Drawing.Size(199, 22); + this.BuildListContextMenu_Rebuild.Text = "Rebuild"; + this.BuildListContextMenu_Rebuild.Click += new System.EventHandler(this.BuildListContextMenu_Rebuild_Click); + // + // BuildListContextMenu_GenerateProjectFiles + // + this.BuildListContextMenu_GenerateProjectFiles.Name = "BuildListContextMenu_GenerateProjectFiles"; + this.BuildListContextMenu_GenerateProjectFiles.Size = new System.Drawing.Size(199, 22); + this.BuildListContextMenu_GenerateProjectFiles.Text = "Generate project files"; + this.BuildListContextMenu_GenerateProjectFiles.Click += new System.EventHandler(this.BuildListContextMenu_GenerateProjectFiles_Click); + // + // BuildListContextMenu_Cancel + // + this.BuildListContextMenu_Cancel.Name = "BuildListContextMenu_Cancel"; + this.BuildListContextMenu_Cancel.Size = new System.Drawing.Size(199, 22); + this.BuildListContextMenu_Cancel.Text = "Cancel"; + this.BuildListContextMenu_Cancel.Click += new System.EventHandler(this.BuildListContextMenu_CancelSync_Click); + // + // BuildListContextMenu_OpenVisualStudio + // + this.BuildListContextMenu_OpenVisualStudio.Name = "BuildListContextMenu_OpenVisualStudio"; + this.BuildListContextMenu_OpenVisualStudio.Size = new System.Drawing.Size(199, 22); + this.BuildListContextMenu_OpenVisualStudio.Text = "Open in Visual Studio..."; + this.BuildListContextMenu_OpenVisualStudio.Click += new System.EventHandler(this.BuildListContextMenu_OpenVisualStudio_Click); + // + // toolStripSeparator4 + // + this.toolStripSeparator4.Name = "toolStripSeparator4"; + this.toolStripSeparator4.Size = new System.Drawing.Size(196, 6); + // + // BuildListContextMenu_MarkGood + // + this.BuildListContextMenu_MarkGood.Name = "BuildListContextMenu_MarkGood"; + this.BuildListContextMenu_MarkGood.Size = new System.Drawing.Size(199, 22); + this.BuildListContextMenu_MarkGood.Text = "Mark as good"; + this.BuildListContextMenu_MarkGood.Click += new System.EventHandler(this.BuildListContextMenu_MarkGood_Click); + // + // BuildListContextMenu_MarkBad + // + this.BuildListContextMenu_MarkBad.Name = "BuildListContextMenu_MarkBad"; + this.BuildListContextMenu_MarkBad.Size = new System.Drawing.Size(199, 22); + this.BuildListContextMenu_MarkBad.Text = "Mark as bad"; + this.BuildListContextMenu_MarkBad.Click += new System.EventHandler(this.BuildListContextMenu_MarkBad_Click); + // + // BuildListContextMenu_WithdrawReview + // + this.BuildListContextMenu_WithdrawReview.Name = "BuildListContextMenu_WithdrawReview"; + this.BuildListContextMenu_WithdrawReview.Size = new System.Drawing.Size(199, 22); + this.BuildListContextMenu_WithdrawReview.Text = "Withdraw review"; + this.BuildListContextMenu_WithdrawReview.Click += new System.EventHandler(this.BuildListContextMenu_WithdrawReview_Click); + // + // BuildListContextMenu_LeaveComment + // + this.BuildListContextMenu_LeaveComment.Name = "BuildListContextMenu_LeaveComment"; + this.BuildListContextMenu_LeaveComment.Size = new System.Drawing.Size(199, 22); + this.BuildListContextMenu_LeaveComment.Text = "Leave comment..."; + this.BuildListContextMenu_LeaveComment.Click += new System.EventHandler(this.BuildListContextMenu_LeaveOrEditComment_Click); + // + // BuildListContextMenu_EditComment + // + this.BuildListContextMenu_EditComment.Name = "BuildListContextMenu_EditComment"; + this.BuildListContextMenu_EditComment.Size = new System.Drawing.Size(199, 22); + this.BuildListContextMenu_EditComment.Text = "Edit comment..."; + this.BuildListContextMenu_EditComment.Click += new System.EventHandler(this.BuildListContextMenu_LeaveOrEditComment_Click); + // + // BuildListContextMenu_StartInvestigating + // + this.BuildListContextMenu_StartInvestigating.Name = "BuildListContextMenu_StartInvestigating"; + this.BuildListContextMenu_StartInvestigating.Size = new System.Drawing.Size(199, 22); + this.BuildListContextMenu_StartInvestigating.Text = "Start investigating"; + this.BuildListContextMenu_StartInvestigating.Click += new System.EventHandler(this.BuildListContextMenu_StartInvestigating_Click); + // + // BuildListContextMenu_FinishInvestigating + // + this.BuildListContextMenu_FinishInvestigating.Name = "BuildListContextMenu_FinishInvestigating"; + this.BuildListContextMenu_FinishInvestigating.Size = new System.Drawing.Size(199, 22); + this.BuildListContextMenu_FinishInvestigating.Text = "Finish investigating"; + this.BuildListContextMenu_FinishInvestigating.Click += new System.EventHandler(this.BuildListContextMenu_FinishInvestigating_Click); + // + // toolStripSeparator1 + // + this.toolStripSeparator1.Name = "toolStripSeparator1"; + this.toolStripSeparator1.Size = new System.Drawing.Size(196, 6); + // + // BuildListContextMenu_AddStar + // + this.BuildListContextMenu_AddStar.Name = "BuildListContextMenu_AddStar"; + this.BuildListContextMenu_AddStar.Size = new System.Drawing.Size(199, 22); + this.BuildListContextMenu_AddStar.Text = "Add Star"; + this.BuildListContextMenu_AddStar.Click += new System.EventHandler(this.BuildListContextMenu_AddStar_Click); + // + // BuildListContextMenu_RemoveStar + // + this.BuildListContextMenu_RemoveStar.Name = "BuildListContextMenu_RemoveStar"; + this.BuildListContextMenu_RemoveStar.Size = new System.Drawing.Size(199, 22); + this.BuildListContextMenu_RemoveStar.Text = "Remove Star"; + this.BuildListContextMenu_RemoveStar.Click += new System.EventHandler(this.BuildListContextMenu_RemoveStar_Click); + // + // BuildListContextMenu_TimeZoneSeparator + // + this.BuildListContextMenu_TimeZoneSeparator.Name = "BuildListContextMenu_TimeZoneSeparator"; + this.BuildListContextMenu_TimeZoneSeparator.Size = new System.Drawing.Size(196, 6); + // + // BuildListContextMenu_ShowServerTimes + // + this.BuildListContextMenu_ShowServerTimes.Name = "BuildListContextMenu_ShowServerTimes"; + this.BuildListContextMenu_ShowServerTimes.Size = new System.Drawing.Size(199, 22); + this.BuildListContextMenu_ShowServerTimes.Text = "Show server times"; + this.BuildListContextMenu_ShowServerTimes.Click += new System.EventHandler(this.BuildListContextMenu_ShowServerTimes_Click); + // + // BuildListContextMenu_ShowLocalTimes + // + this.BuildListContextMenu_ShowLocalTimes.Name = "BuildListContextMenu_ShowLocalTimes"; + this.BuildListContextMenu_ShowLocalTimes.Size = new System.Drawing.Size(199, 22); + this.BuildListContextMenu_ShowLocalTimes.Text = "Show local times"; + this.BuildListContextMenu_ShowLocalTimes.Click += new System.EventHandler(this.BuildListContextMenu_ShowLocalTimes_Click); + // + // toolStripSeparator2 + // + this.toolStripSeparator2.Name = "toolStripSeparator2"; + this.toolStripSeparator2.Size = new System.Drawing.Size(196, 6); + // + // BuildListContextMenu_MoreInfo + // + this.BuildListContextMenu_MoreInfo.Name = "BuildListContextMenu_MoreInfo"; + this.BuildListContextMenu_MoreInfo.Size = new System.Drawing.Size(199, 22); + this.BuildListContextMenu_MoreInfo.Text = "More Info..."; + this.BuildListContextMenu_MoreInfo.Click += new System.EventHandler(this.BuildListContextMenu_MoreInfo_Click); + // + // toolStripSeparator7 + // + this.toolStripSeparator7.Name = "toolStripSeparator7"; + this.toolStripSeparator7.Size = new System.Drawing.Size(193, 6); + // + // flowLayoutPanel1 + // + this.flowLayoutPanel1.Anchor = System.Windows.Forms.AnchorStyles.None; + this.flowLayoutPanel1.AutoSize = true; + this.flowLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.flowLayoutPanel1.Controls.Add(this.AfterSyncingLabel); + this.flowLayoutPanel1.Controls.Add(this.BuildAfterSyncCheckBox); + this.flowLayoutPanel1.Controls.Add(this.RunAfterSyncCheckBox); + this.flowLayoutPanel1.Controls.Add(this.OpenSolutionAfterSyncCheckBox); + this.flowLayoutPanel1.Location = new System.Drawing.Point(458, 8); + this.flowLayoutPanel1.Name = "flowLayoutPanel1"; + this.flowLayoutPanel1.Size = new System.Drawing.Size(285, 23); + this.flowLayoutPanel1.TabIndex = 8; + this.flowLayoutPanel1.WrapContents = false; + // + // OpenSolutionAfterSyncCheckBox + // + this.OpenSolutionAfterSyncCheckBox.AutoSize = true; + this.OpenSolutionAfterSyncCheckBox.Location = new System.Drawing.Point(189, 3); + this.OpenSolutionAfterSyncCheckBox.Name = "OpenSolutionAfterSyncCheckBox"; + this.OpenSolutionAfterSyncCheckBox.Size = new System.Drawing.Size(93, 17); + this.OpenSolutionAfterSyncCheckBox.TabIndex = 7; + this.OpenSolutionAfterSyncCheckBox.Text = "Open Solution"; + this.OpenSolutionAfterSyncCheckBox.UseVisualStyleBackColor = true; + this.OpenSolutionAfterSyncCheckBox.CheckedChanged += new System.EventHandler(this.OpenSolutionAfterSyncCheckBox_CheckedChanged); + // + // tableLayoutPanel3 + // + this.tableLayoutPanel3.AutoSize = true; + this.tableLayoutPanel3.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.tableLayoutPanel3.ColumnCount = 3; + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel3.Controls.Add(this.OnlyShowReviewedCheckBox, 0, 0); + this.tableLayoutPanel3.Controls.Add(this.flowLayoutPanel1, 1, 0); + this.tableLayoutPanel3.Controls.Add(this.OptionsButton, 2, 0); + this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel3.Location = new System.Drawing.Point(0, 618); + this.tableLayoutPanel3.Margin = new System.Windows.Forms.Padding(0); + this.tableLayoutPanel3.Name = "tableLayoutPanel3"; + this.tableLayoutPanel3.Padding = new System.Windows.Forms.Padding(0, 5, 0, 0); + this.tableLayoutPanel3.RowCount = 1; + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 29F)); + this.tableLayoutPanel3.Size = new System.Drawing.Size(1168, 34); + this.tableLayoutPanel3.TabIndex = 11; + // + // OptionsButton + // + this.OptionsButton.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.OptionsButton.AutoSize = true; + this.OptionsButton.Image = global::UnrealGameSync.Properties.Resources.DropList; + this.OptionsButton.ImageAlign = System.Drawing.ContentAlignment.MiddleRight; + this.OptionsButton.Location = new System.Drawing.Point(1033, 8); + this.OptionsButton.Name = "OptionsButton"; + this.OptionsButton.Size = new System.Drawing.Size(132, 23); + this.OptionsButton.TabIndex = 7; + this.OptionsButton.Text = "Options"; + this.OptionsButton.UseVisualStyleBackColor = true; + this.OptionsButton.Click += new System.EventHandler(this.OptionsButton_Click); + // + // tableLayoutPanel2 + // + this.tableLayoutPanel2.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.tableLayoutPanel2.ColumnCount = 1; + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel2.Controls.Add(this.Splitter, 0, 1); + this.tableLayoutPanel2.Controls.Add(this.tableLayoutPanel3, 0, 2); + this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel2.GrowStyle = System.Windows.Forms.TableLayoutPanelGrowStyle.FixedSize; + this.tableLayoutPanel2.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel2.Name = "tableLayoutPanel2"; + this.tableLayoutPanel2.RowCount = 3; + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel2.Size = new System.Drawing.Size(1168, 652); + this.tableLayoutPanel2.TabIndex = 12; + // + // Splitter + // + this.Splitter.Dock = System.Windows.Forms.DockStyle.Fill; + this.Splitter.Location = new System.Drawing.Point(0, 0); + this.Splitter.Margin = new System.Windows.Forms.Padding(0); + this.Splitter.Name = "Splitter"; + this.Splitter.Orientation = System.Windows.Forms.Orientation.Horizontal; + // + // Splitter.Panel1 + // + this.Splitter.Panel1.Controls.Add(this.tableLayoutPanel4); + // + // Splitter.Panel2 + // + this.Splitter.Panel2.Controls.Add(this.panel1); + this.Splitter.Panel2MinSize = 50; + this.Splitter.Size = new System.Drawing.Size(1168, 618); + this.Splitter.SplitterDistance = 390; + this.Splitter.SplitterWidth = 28; + this.Splitter.TabIndex = 0; + // + // tableLayoutPanel4 + // + this.tableLayoutPanel4.ColumnCount = 1; + this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel4.Controls.Add(this.StatusPanel, 0, 0); + this.tableLayoutPanel4.Controls.Add(this.BuildList, 0, 1); + this.tableLayoutPanel4.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel4.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel4.Name = "tableLayoutPanel4"; + this.tableLayoutPanel4.RowCount = 2; + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 128F)); + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel4.Size = new System.Drawing.Size(1168, 390); + this.tableLayoutPanel4.TabIndex = 1; + // + // StatusPanel + // + this.StatusPanel.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(250)))), ((int)(((byte)(250)))), ((int)(((byte)(250))))); + this.StatusPanel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.StatusPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.StatusPanel.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.StatusPanel.Location = new System.Drawing.Point(0, 0); + this.StatusPanel.Margin = new System.Windows.Forms.Padding(0, 0, 0, 3); + this.StatusPanel.Name = "StatusPanel"; + this.StatusPanel.Size = new System.Drawing.Size(1168, 125); + this.StatusPanel.TabIndex = 1; + // + // BuildList + // + this.BuildList.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.IconColumn, + this.ChangeColumn, + this.TimeColumn, + this.AuthorColumn, + this.DescriptionColumn, + this.CISColumn, + this.StatusColumn}); + this.BuildList.Dock = System.Windows.Forms.DockStyle.Fill; + this.BuildList.FullRowSelect = true; + this.BuildList.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; + this.BuildList.Location = new System.Drawing.Point(0, 128); + this.BuildList.Margin = new System.Windows.Forms.Padding(0); + this.BuildList.MultiSelect = false; + this.BuildList.Name = "BuildList"; + this.BuildList.OwnerDraw = true; + this.BuildList.Size = new System.Drawing.Size(1168, 262); + this.BuildList.TabIndex = 0; + this.BuildList.UseCompatibleStateImageBehavior = false; + this.BuildList.View = System.Windows.Forms.View.Details; + this.BuildList.DrawColumnHeader += new System.Windows.Forms.DrawListViewColumnHeaderEventHandler(this.BuildList_DrawColumnHeader); + this.BuildList.DrawItem += new System.Windows.Forms.DrawListViewItemEventHandler(this.BuildList_DrawItem); + this.BuildList.DrawSubItem += new System.Windows.Forms.DrawListViewSubItemEventHandler(this.BuildList_DrawSubItem); + this.BuildList.ItemMouseHover += new System.Windows.Forms.ListViewItemMouseHoverEventHandler(this.BuildList_ItemMouseHover); + this.BuildList.SelectedIndexChanged += new System.EventHandler(this.BuildList_SelectedIndexChanged); + this.BuildList.FontChanged += new System.EventHandler(this.BuildList_FontChanged); + this.BuildList.KeyDown += new System.Windows.Forms.KeyEventHandler(this.BuildList_KeyDown); + this.BuildList.MouseClick += new System.Windows.Forms.MouseEventHandler(this.BuildList_MouseClick); + this.BuildList.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.BuildList_MouseDoubleClick); + this.BuildList.MouseLeave += new System.EventHandler(this.BuildList_MouseLeave); + this.BuildList.MouseMove += new System.Windows.Forms.MouseEventHandler(this.BuildList_MouseMove); + // + // IconColumn + // + this.IconColumn.Text = ""; + this.IconColumn.Width = 45; + // + // ChangeColumn + // + this.ChangeColumn.Text = "Change"; + this.ChangeColumn.Width = 74; + // + // TimeColumn + // + this.TimeColumn.Text = "Time"; + // + // AuthorColumn + // + this.AuthorColumn.Text = "Author"; + this.AuthorColumn.Width = 120; + // + // DescriptionColumn + // + this.DescriptionColumn.Text = "Description"; + this.DescriptionColumn.Width = 245; + // + // CISColumn + // + this.CISColumn.Text = "CIS"; + this.CISColumn.Width = 184; + // + // StatusColumn + // + this.StatusColumn.Text = "Status"; + this.StatusColumn.Width = 375; + // + // panel1 + // + this.panel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.panel1.Controls.Add(this.SyncLog); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(1168, 200); + this.panel1.TabIndex = 0; + // + // SyncLog + // + this.SyncLog.BackColor = System.Drawing.Color.White; + this.SyncLog.Cursor = System.Windows.Forms.Cursors.IBeam; + this.SyncLog.Dock = System.Windows.Forms.DockStyle.Fill; + this.SyncLog.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.SyncLog.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(32)))), ((int)(((byte)(32))))); + this.SyncLog.Location = new System.Drawing.Point(0, 0); + this.SyncLog.Name = "SyncLog"; + this.SyncLog.Size = new System.Drawing.Size(1166, 198); + this.SyncLog.TabIndex = 0; + // + // MoreToolsContextMenu + // + this.MoreToolsContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.MoreActionsContextMenu_CustomToolSeparator, + this.MoreToolsContextMenu_CleanWorkspace}); + this.MoreToolsContextMenu.Name = "MoreActionsContextMenu"; + this.MoreToolsContextMenu.Size = new System.Drawing.Size(175, 32); + // + // MoreActionsContextMenu_CustomToolSeparator + // + this.MoreActionsContextMenu_CustomToolSeparator.Name = "MoreActionsContextMenu_CustomToolSeparator"; + this.MoreActionsContextMenu_CustomToolSeparator.Size = new System.Drawing.Size(171, 6); + // + // MoreToolsContextMenu_CleanWorkspace + // + this.MoreToolsContextMenu_CleanWorkspace.Name = "MoreToolsContextMenu_CleanWorkspace"; + this.MoreToolsContextMenu_CleanWorkspace.Size = new System.Drawing.Size(174, 22); + this.MoreToolsContextMenu_CleanWorkspace.Text = "Clean Workspace..."; + this.MoreToolsContextMenu_CleanWorkspace.Click += new System.EventHandler(this.MoreToolsContextMenu_CleanWorkspace_Click); + // + // SyncContextMenu + // + this.SyncContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.SyncContextMenu_LatestChange, + this.SyncContextMenu_LatestGoodChange, + this.SyncContextMenu_LatestStarredChange, + this.toolStripSeparator8, + this.SyncContexMenu_EnterChangelist}); + this.SyncContextMenu.Name = "SyncContextMenu"; + this.SyncContextMenu.Size = new System.Drawing.Size(190, 98); + // + // SyncContextMenu_LatestChange + // + this.SyncContextMenu_LatestChange.Name = "SyncContextMenu_LatestChange"; + this.SyncContextMenu_LatestChange.Size = new System.Drawing.Size(189, 22); + this.SyncContextMenu_LatestChange.Text = "Latest Change"; + this.SyncContextMenu_LatestChange.Click += new System.EventHandler(this.SyncContextMenu_LatestChange_Click); + // + // SyncContextMenu_LatestGoodChange + // + this.SyncContextMenu_LatestGoodChange.Name = "SyncContextMenu_LatestGoodChange"; + this.SyncContextMenu_LatestGoodChange.Size = new System.Drawing.Size(189, 22); + this.SyncContextMenu_LatestGoodChange.Text = "Latest Good Change"; + this.SyncContextMenu_LatestGoodChange.Click += new System.EventHandler(this.SyncContextMenu_LatestGoodChange_Click); + // + // SyncContextMenu_LatestStarredChange + // + this.SyncContextMenu_LatestStarredChange.Name = "SyncContextMenu_LatestStarredChange"; + this.SyncContextMenu_LatestStarredChange.Size = new System.Drawing.Size(189, 22); + this.SyncContextMenu_LatestStarredChange.Text = "Latest Starred Change"; + // + // toolStripSeparator8 + // + this.toolStripSeparator8.Name = "toolStripSeparator8"; + this.toolStripSeparator8.Size = new System.Drawing.Size(186, 6); + // + // SyncContexMenu_EnterChangelist + // + this.SyncContexMenu_EnterChangelist.Name = "SyncContexMenu_EnterChangelist"; + this.SyncContexMenu_EnterChangelist.Size = new System.Drawing.Size(189, 22); + this.SyncContexMenu_EnterChangelist.Text = "Specific Changelist..."; + this.SyncContexMenu_EnterChangelist.Click += new System.EventHandler(this.SyncContextMenu_EnterChangelist_Click); + // + // StreamContextMenu + // + this.StreamContextMenu.Name = "StreamContextMenu"; + this.StreamContextMenu.Size = new System.Drawing.Size(61, 4); + // + // WorkspaceControl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.tableLayoutPanel2); + this.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.MinimumSize = new System.Drawing.Size(800, 350); + this.Name = "WorkspaceControl"; + this.Size = new System.Drawing.Size(1168, 652); + this.Load += new System.EventHandler(this.MainWindow_Load); + this.OptionsContextMenu.ResumeLayout(false); + this.BuildListContextMenu.ResumeLayout(false); + this.flowLayoutPanel1.ResumeLayout(false); + this.flowLayoutPanel1.PerformLayout(); + this.tableLayoutPanel3.ResumeLayout(false); + this.tableLayoutPanel3.PerformLayout(); + this.tableLayoutPanel2.ResumeLayout(false); + this.tableLayoutPanel2.PerformLayout(); + this.Splitter.Panel1.ResumeLayout(false); + this.Splitter.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.Splitter)).EndInit(); + this.Splitter.ResumeLayout(false); + this.tableLayoutPanel4.ResumeLayout(false); + this.panel1.ResumeLayout(false); + this.MoreToolsContextMenu.ResumeLayout(false); + this.SyncContextMenu.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private BuildListControl BuildList; + private LogControl SyncLog; + private System.Windows.Forms.ColumnHeader IconColumn; + private System.Windows.Forms.ColumnHeader TimeColumn; + private System.Windows.Forms.ColumnHeader DescriptionColumn; + private System.Windows.Forms.ColumnHeader StatusColumn; + private System.Windows.Forms.ColumnHeader ChangeColumn; + private System.Windows.Forms.ColumnHeader AuthorColumn; + private System.Windows.Forms.Button OptionsButton; + private System.Windows.Forms.ContextMenuStrip OptionsContextMenu; + private System.Windows.Forms.CheckBox OnlyShowReviewedCheckBox; + private System.Windows.Forms.CheckBox RunAfterSyncCheckBox; + private System.Windows.Forms.CheckBox BuildAfterSyncCheckBox; + private System.Windows.Forms.Label AfterSyncingLabel; + private System.Windows.Forms.ContextMenuStrip BuildListContextMenu; + private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_Cancel; + private LogSplitContainer Splitter; + private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_MoreInfo; + private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_AddStar; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator2; + private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_MarkGood; + private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_MarkBad; + private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_StartInvestigating; + private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_Sync; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator4; + private System.Windows.Forms.NotifyIcon NotifyIcon; + private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_RemoveStar; + private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_FinishInvestigating; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; + private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_LaunchEditor; + private System.Windows.Forms.ToolTip BuildListToolTip; + private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_AutoResolveConflicts; + private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_EditorArguments; + private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_OpenVisualStudio; + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_Build; + private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_GenerateProjectFiles; + private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_EditorBuildConfiguration; + private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_BuildConfig_Debug; + private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_BuildConfig_DebugGame; + private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_BuildConfig_Development; + private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_UseIncrementalBuilds; + private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_Rebuild; + private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_WithdrawReview; + private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_ScheduledSync; + private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_LeaveComment; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator7; + private System.Windows.Forms.ColumnHeader CISColumn; + private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_EditComment; + private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; + private System.Windows.Forms.ToolStripSeparator BuildListContextMenu_TimeZoneSeparator; + private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_ShowServerTimes; + private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_ShowLocalTimes; + private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_CustomizeBuildSteps; + private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_TimeZone; + private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_TimeZone_Local; + private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_TimeZone_PerforceServer; + private System.Windows.Forms.CheckBox OpenSolutionAfterSyncCheckBox; + private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_AutomaticallyRunAtStartup; + private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_SyncPrecompiledEditor; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel4; + private StatusPanel StatusPanel; + private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_SyncContentOnly; + private System.Windows.Forms.ContextMenuStrip MoreToolsContextMenu; + private System.Windows.Forms.ToolStripMenuItem MoreToolsContextMenu_CleanWorkspace; + private System.Windows.Forms.ToolStripSeparator MoreActionsContextMenu_CustomToolSeparator; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator3; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator5; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator6; + private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_Diagnostics; + private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_SyncFilter; + private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_SyncOnlyThisChange; + private System.Windows.Forms.ContextMenuStrip SyncContextMenu; + private System.Windows.Forms.ToolStripMenuItem SyncContextMenu_LatestChange; + private System.Windows.Forms.ToolStripMenuItem SyncContextMenu_LatestGoodChange; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator8; + private System.Windows.Forms.ToolStripMenuItem SyncContexMenu_EnterChangelist; + private System.Windows.Forms.ToolStripMenuItem SyncContextMenu_LatestStarredChange; + private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_KeepInTray; + private System.Windows.Forms.ContextMenuStrip StreamContextMenu; + private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_PerforceSettings; + private System.Windows.Forms.ToolStripMenuItem tabLabelsToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_TabNames_Stream; + private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_TabNames_WorkspaceName; + private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_TabNames_WorkspaceRoot; + private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_TabNames_ProjectFile; + } +} diff --git a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Controls/WorkspaceControl.cs b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Controls/WorkspaceControl.cs new file mode 100644 index 000000000000..433d2e761b78 --- /dev/null +++ b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Controls/WorkspaceControl.cs @@ -0,0 +1,2852 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Data.SqlClient; +using System.Deployment.Application; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Windows.Forms; +using System.Windows.Forms.VisualStyles; +using Microsoft.Win32; + +using EventWaitHandle = System.Threading.EventWaitHandle; + +namespace UnrealGameSync +{ + public enum LatestChangeType + { + Any, + Good, + Starred, + } + + interface IWorkspaceControlOwner + { + void ShowAndActivate(); + void StreamChanged(WorkspaceControl Workspace); + void SetTabNames(TabLabels TabNames); + void SetupScheduledSync(); + void UpdateProgress(); + } + + partial class WorkspaceControl : UserControl + { + static Rectangle GoodBuildIcon = new Rectangle(0, 0, 16, 16); + static Rectangle MixedBuildIcon = new Rectangle(16, 0, 16, 16); + static Rectangle BadBuildIcon = new Rectangle(32, 0, 16, 16); + static Rectangle DefaultBuildIcon = new Rectangle(48, 0, 16, 16); + static Rectangle PromotedBuildIcon = new Rectangle(64, 0, 16, 16); + static Rectangle DetailsIcon = new Rectangle(80, 0, 16, 16); + static Rectangle InfoIcon = new Rectangle(96, 0, 16, 16); + static Rectangle CancelIcon = new Rectangle(112, 0, 16, 16); + static Rectangle SyncIcon = new Rectangle(128, 0, 32, 16); + static Rectangle HappyIcon = new Rectangle(160, 0, 16, 16); + static Rectangle DisabledHappyIcon = new Rectangle(176, 0, 16, 16); + static Rectangle FrownIcon = new Rectangle(192, 0, 16, 16); + static Rectangle DisabledFrownIcon = new Rectangle(208, 0, 16, 16); + static Rectangle PreviousSyncIcon = new Rectangle(224, 0, 16, 16); + static Rectangle AdditionalSyncIcon = new Rectangle(240, 0, 16, 16); + + [DllImport("uxtheme.dll", CharSet = CharSet.Unicode)] + static extern int SetWindowTheme(IntPtr hWnd, string pszSubAppName, string pszSubIdList); + + const string EditorArchiveType = "Editor"; + + IWorkspaceControlOwner Owner; + string SqlConnectionString; + string DataFolder; + BoundedLogWriter Log; + + UserSettings Settings; + UserWorkspaceSettings WorkspaceSettings; + UserProjectSettings ProjectSettings; + + public string SelectedFileName + { + get; + private set; + } + + string SelectedProjectIdentifier; + + public string BranchDirectoryName + { + get; + private set; + } + + public string StreamName + { + get; + private set; + } + + public string ClientName + { + get; + private set; + } + + string EditorTargetName; + PerforceMonitor PerforceMonitor; + Workspace Workspace; + EventMonitor EventMonitor; + Timer UpdateTimer; + HashSet PromotedChangeNumbers = new HashSet(); + List ListIndexToChangeIndex = new List(); + List SortedChangeNumbers = new List(); + Dictionary ChangeNumberToArchivePath = new Dictionary(); + List CustomToolMenuItems = new List(); + int NumChanges; + int PendingSelectedChangeNumber = -1; + bool bHasBuildSteps = false; + + Dictionary NotifiedBuildTypeToChangeNumber = new Dictionary(); + + TimeSpan ServerTimeZone; + + int HoverItem = -1; + BuildData HoverBadge; + bool bHoverSync; + PerforceChangeSummary ContextMenuChange; + VisualStyleRenderer SelectedItemRenderer; + VisualStyleRenderer TrackedItemRenderer; + Font BuildFont; + Font SelectedBuildFont; + Font BadgeFont; + bool bUnstable; + + bool bRestoreStateOnLoad; + + string OriginalExecutableFileName; + + NotificationWindow NotificationWindow; + + public Tuple DesiredTaskbarState + { + get; + private set; + } + + public WorkspaceControl(IWorkspaceControlOwner InOwner, string InSqlConnectionString, string InDataFolder, bool bInRestoreStateOnLoad, string InOriginalExecutableFileName, string InProjectFileName, bool bInUnstable, DetectProjectSettingsTask DetectSettings, BoundedLogWriter InLog, UserSettings InSettings) + { + InitializeComponent(); + + if (Application.RenderWithVisualStyles) + { + SelectedItemRenderer = new VisualStyleRenderer("Explorer::ListView", 1, 3); + TrackedItemRenderer = new VisualStyleRenderer("Explorer::ListView", 1, 2); + } + + Owner = InOwner; + SqlConnectionString = InSqlConnectionString; + DataFolder = InDataFolder; + bRestoreStateOnLoad = bInRestoreStateOnLoad; + OriginalExecutableFileName = InOriginalExecutableFileName; + bUnstable = bInUnstable; + Log = InLog; + Settings = InSettings; + WorkspaceSettings = InSettings.FindOrAddWorkspace(DetectSettings.BranchClientPath); + ProjectSettings = InSettings.FindOrAddProject(DetectSettings.NewSelectedClientFileName); + + DesiredTaskbarState = Tuple.Create(TaskbarState.NoProgress, 0.0f); + + System.Reflection.PropertyInfo DoubleBufferedProperty = typeof(Control).GetProperty("DoubleBuffered", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + DoubleBufferedProperty.SetValue(BuildList, true, null); + + // force the height of the rows + BuildList.SmallImageList = new ImageList(){ ImageSize = new Size(1, 20) }; + BuildList_FontChanged(null, null); + BuildList.OnScroll += BuildList_OnScroll; + + Splitter.OnVisibilityChanged += Splitter_OnVisibilityChanged; + + UpdateTimer = new Timer(); + UpdateTimer.Interval = 30; + UpdateTimer.Tick += TimerCallback; + + UpdateCheckedBuildConfig(); + + UpdateSyncActionCheckboxes(); + + if(Settings.bHasWindowSettings) + { + for(int Idx = 0; Idx < BuildList.Columns.Count; Idx++) + { + string ColumnName = BuildList.Columns[Idx].Text; + if(String.IsNullOrEmpty(ColumnName)) + { + ColumnName = String.Format("Column{0}", Idx); + } + + int ColumnWidth; + if(Settings.ColumnWidths.TryGetValue(ColumnName, out ColumnWidth)) + { + BuildList.Columns[Idx].Width = ColumnWidth; + } + } + } + + // Set the project logo on the status panel and notification window + NotificationWindow = new NotificationWindow(Properties.Resources.DefaultNotificationLogo); + StatusPanel.SetProjectLogo(DetectSettings.ProjectLogo); + DetectSettings.ProjectLogo = null; + + // Commit all the new project info + PerforceConnection PerforceClient = DetectSettings.PerforceClient; + ClientName = PerforceClient.ClientName; + SelectedFileName = InProjectFileName; + SelectedProjectIdentifier = DetectSettings.NewSelectedProjectIdentifier; + EditorTargetName = DetectSettings.NewProjectEditorTarget; + StreamName = DetectSettings.StreamName; + ServerTimeZone = DetectSettings.ServerTimeZone; + + // Update the branch directory + BranchDirectoryName = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(DetectSettings.BaseEditorTargetPath), "..", "..")); + + // Check if we've the project we've got open in this workspace is the one we're actually synced to + int CurrentChangeNumber = -1; + if(String.Compare(WorkspaceSettings.CurrentProjectIdentifier, SelectedProjectIdentifier, true) == 0) + { + CurrentChangeNumber = WorkspaceSettings.CurrentChangeNumber; + } + + string ProjectLogBaseName = Path.Combine(DataFolder, String.Format("{0}@{1}", PerforceClient.ClientName, DetectSettings.BranchClientPath.Replace("//" + PerforceClient.ClientName + "/", "").Trim('/').Replace("/", "$"))); + + string TelemetryProjectIdentifier = PerforceUtils.GetClientOrDepotDirectoryName(DetectSettings.NewSelectedProjectIdentifier); + + Workspace = new Workspace(PerforceClient, BranchDirectoryName, SelectedFileName, DetectSettings.BranchClientPath, DetectSettings.NewSelectedClientFileName, CurrentChangeNumber, WorkspaceSettings.LastBuiltChangeNumber, TelemetryProjectIdentifier, new LogControlTextWriter(SyncLog)); + Workspace.OnUpdateComplete += UpdateCompleteCallback; + + PerforceMonitor = new PerforceMonitor(PerforceClient, DetectSettings.BranchClientPath, DetectSettings.NewSelectedClientFileName, SelectedProjectIdentifier, ProjectLogBaseName + ".p4.log"); + PerforceMonitor.OnUpdate += UpdateBuildListCallback; + PerforceMonitor.OnUpdateMetadata += UpdateBuildMetadataCallback; + PerforceMonitor.OnStreamChange += StreamChangedCallbackAsync; + + EventMonitor = new EventMonitor(SqlConnectionString, PerforceUtils.GetClientOrDepotDirectoryName(SelectedProjectIdentifier), DetectSettings.PerforceClient.UserName, ProjectLogBaseName + ".review.log"); + EventMonitor.OnUpdatesReady += UpdateReviewsCallback; + + string LogFileName = Path.Combine(DataFolder, ProjectLogBaseName + ".sync.log"); + SyncLog.OpenFile(LogFileName); + + Splitter.SetLogVisibility(Settings.bShowLogWindow); + + BuildList.Items.Clear(); + UpdateBuildList(); + UpdateBuildSteps(); + UpdateSyncActionCheckboxes(); + UpdateStatusPanel(); + + if(CurrentChangeNumber != -1) + { + SelectChange(CurrentChangeNumber); + } + } + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + CloseProject(); + + if(BuildFont != null) + { + BuildFont.Dispose(); + BuildFont = null; + } + if(SelectedBuildFont != null) + { + SelectedBuildFont.Dispose(); + SelectedBuildFont = null; + } + if(BadgeFont != null) + { + BadgeFont.Dispose(); + BadgeFont = null; + } + + base.Dispose(disposing); + } + + public bool IsBusy() + { + return Workspace.IsBusy(); + } + + public bool CanSyncNow() + { + return Workspace != null && !Workspace.IsBusy(); + } + + public bool CanLaunchEditor() + { + return Workspace != null && !Workspace.IsBusy() && Workspace.CurrentChangeNumber != -1; + } + + private void MainWindow_Load(object sender, EventArgs e) + { + UpdateStatusPanel(); + } + + private void MainWindow_FormClosed(object sender, FormClosedEventArgs e) + { + CloseProject(); + } + + private void ShowErrorDialog(string Format, params object[] Args) + { + string Message = String.Format(Format, Args); + Log.WriteLine(Message); + MessageBox.Show(Message); + } + + public bool CanClose() + { + CancelWorkspaceUpdate(); + return !Workspace.IsBusy(); + } + + private void StreamChangedCallback() + { + Owner.StreamChanged(this); +/* + StatusPanel.SuspendDisplay(); + + string PrevSelectedFileName = SelectedFileName; + if(TryCloseProject()) + { + OpenProject(PrevSelectedFileName); + } + + StatusPanel.ResumeDisplay();*/ + } + + private void StreamChangedCallbackAsync() + { + BeginInvoke(new MethodInvoker(StreamChangedCallback)); + } + + private void CloseProject() + { + UpdateTimer.Stop(); + + BuildList.Items.Clear(); + BuildList.Groups.Clear(); + + SelectedFileName = null; + SelectedProjectIdentifier = null; + BranchDirectoryName = null; + EditorTargetName = null; + + if(NotificationWindow != null) + { + NotificationWindow.Dispose(); + NotificationWindow = null; + } + if(PerforceMonitor != null) + { + PerforceMonitor.Dispose(); + PerforceMonitor = null; + } + if(Workspace != null) + { + Workspace.Dispose(); + Workspace = null; + } + if(EventMonitor != null) + { + EventMonitor.Dispose(); + EventMonitor = null; + } + + ListIndexToChangeIndex = new List(); + SortedChangeNumbers = new List(); + NumChanges = 0; + ContextMenuChange = null; + HoverItem = -1; + PendingSelectedChangeNumber = -1; + NotifiedBuildTypeToChangeNumber = new Dictionary(); + + SyncLog.CloseFile(); + SyncLog.Clear(); + + UpdateBuildSteps(); + + StatusPanel.SetProjectLogo(null); + + DesiredTaskbarState = Tuple.Create(TaskbarState.NoProgress, 0.0f); + } + + private void UpdateSyncConfig(int ChangeNumber) + { + WorkspaceSettings.CurrentProjectIdentifier = SelectedProjectIdentifier; + WorkspaceSettings.CurrentChangeNumber = ChangeNumber; + if(ChangeNumber == -1 || ChangeNumber != WorkspaceSettings.CurrentChangeNumber) + { + WorkspaceSettings.AdditionalChangeNumbers.Clear(); + } + Settings.Save(); + } + + private void BuildList_OnScroll() + { + PendingSelectedChangeNumber = -1; + UpdateNumRequestedBuilds(false); + } + + void UpdateNumRequestedBuilds(bool bAllowShrink) + { + if(PerforceMonitor != null) + { + if(OnlyShowReviewedCheckBox.Checked) + { + PerforceMonitor.PendingMaxChanges = 1000; + } + else + { + int NumItemsPerPage = Math.Max(BuildList.GetVisibleItemsPerPage(), 10); + + // Find the number of visible items using a (slightly wasteful) binary search + int VisibleItemCount = 1; + for(int StepSize = BuildList.Items.Count / 2; StepSize >= 1; ) + { + int TestIndex = VisibleItemCount + StepSize; + if(TestIndex < BuildList.Items.Count && BuildList.GetItemRect(TestIndex).Top < BuildList.Height) + { + VisibleItemCount += StepSize; + } + else + { + StepSize /= 2; + } + } + + // Increase or decrease the number of builds we want, with a bit of rubber-banding + const int IncreaseStep = 50; + if(VisibleItemCount > BuildList.Items.Count - 20) + { + PerforceMonitor.PendingMaxChanges = NumChanges + IncreaseStep; + } + else if(bAllowShrink) + { + int NewNumChanges = ListIndexToChangeIndex[VisibleItemCount - 1] + IncreaseStep; + if(NewNumChanges < NumChanges) + { + PerforceMonitor.PendingMaxChanges = NewNumChanges; + } + } + } + } + } + + void StartSync(int ChangeNumber) + { + WorkspaceUpdateOptions Options = WorkspaceUpdateOptions.Sync | WorkspaceUpdateOptions.SyncArchives | WorkspaceUpdateOptions.GenerateProjectFiles; + if(Settings.bAutoResolveConflicts) + { + Options |= WorkspaceUpdateOptions.AutoResolveChanges; + } + if(Settings.bUseIncrementalBuilds) + { + Options |= WorkspaceUpdateOptions.UseIncrementalBuilds; + } + if(Settings.bBuildAfterSync) + { + Options |= WorkspaceUpdateOptions.Build; + } + if(Settings.bBuildAfterSync && Settings.bRunAfterSync) + { + Options |= WorkspaceUpdateOptions.RunAfterSync; + } + if(Settings.bOpenSolutionAfterSync) + { + Options |= WorkspaceUpdateOptions.OpenSolutionAfterSync; + } + StartWorkspaceUpdate(ChangeNumber, Options); + } + + void StartWorkspaceUpdate(int ChangeNumber, WorkspaceUpdateOptions Options) + { + if((Options & (WorkspaceUpdateOptions.Sync | WorkspaceUpdateOptions.Build)) != 0 && IsEditorRunning(GetEditorBuildConfig())) + { + MessageBox.Show("Please close the editor before trying to sync/build.", "Editor Open"); + return; + } + + WorkspaceUpdateContext Context = new WorkspaceUpdateContext(ChangeNumber, Options, Settings.GetCombinedSyncFilter(WorkspaceSettings), GetDefaultBuildStepObjects(), ProjectSettings.BuildSteps, null, GetWorkspaceVariables()); + if(Options.HasFlag(WorkspaceUpdateOptions.SyncArchives)) + { + string EditorArchivePath = null; + if(ShouldSyncPrecompiledEditor) + { + EditorArchivePath = GetArchivePathForChangeNumber(ChangeNumber); + if(EditorArchivePath == null) + { + MessageBox.Show("There are no compiled editor binaries for this change. To sync it, you must disable syncing of precompiled editor binaries."); + return; + } + } + Context.ArchiveTypeToDepotPath.Add(EditorArchiveType, EditorArchivePath); + } + StartWorkspaceUpdate(Context); + } + + void StartWorkspaceUpdate(WorkspaceUpdateContext Context) + { + Context.StartTime = DateTime.UtcNow; + Context.PerforceSyncOptions = (PerforceSyncOptions)Settings.SyncOptions.Clone(); + + Log.WriteLine(); + Log.WriteLine("Updating workspace at {0}...", Context.StartTime.ToLocalTime().ToString()); + Log.WriteLine(" ChangeNumber={0}", Context.ChangeNumber); + Log.WriteLine(" Options={0}", Context.Options.ToString()); + Log.WriteLine(" Clobbering {0} files", Context.ClobberFiles.Count); + + if(Context.Options.HasFlag(WorkspaceUpdateOptions.Sync)) + { + UpdateSyncConfig(-1); + EventMonitor.PostEvent(Context.ChangeNumber, EventType.Syncing); + } + + if(Context.Options.HasFlag(WorkspaceUpdateOptions.Sync) || Context.Options.HasFlag(WorkspaceUpdateOptions.Build)) + { + if(!Context.Options.HasFlag(WorkspaceUpdateOptions.ContentOnly) && (Context.CustomBuildSteps == null || Context.CustomBuildSteps.Count == 0)) + { + foreach(BuildConfig Config in Enum.GetValues(typeof(BuildConfig))) + { + List EditorReceiptPaths = GetEditorReceiptPaths(Config); + foreach(string EditorReceiptPath in EditorReceiptPaths) + { + if(File.Exists(EditorReceiptPath)) + { + try { File.Delete(EditorReceiptPath); } catch(Exception){ } + } + } + } + } + } + + SyncLog.Clear(); + Workspace.Update(Context); + UpdateSyncActionCheckboxes(); + Refresh(); + UpdateTimer.Start(); + } + + void CancelWorkspaceUpdate() + { + if(Workspace.IsBusy() && MessageBox.Show("Are you sure you want to cancel the current operation?", "Cancel operation", MessageBoxButtons.YesNo) == DialogResult.Yes) + { + WorkspaceSettings.LastSyncChangeNumber = Workspace.PendingChangeNumber; + WorkspaceSettings.LastSyncResult = WorkspaceUpdateResult.Canceled; + WorkspaceSettings.LastSyncResultMessage = null; + WorkspaceSettings.LastSyncTime = null; + WorkspaceSettings.LastSyncDurationSeconds = 0; + Settings.Save(); + + Workspace.CancelUpdate(); + + UpdateTimer.Stop(); + + UpdateSyncActionCheckboxes(); + Refresh(); + UpdateSyncConfig(Workspace.CurrentChangeNumber); + UpdateStatusPanel(); + DesiredTaskbarState = Tuple.Create(TaskbarState.NoProgress, 0.0f); + Owner.UpdateProgress(); + } + } + + void UpdateCompleteCallback(WorkspaceUpdateContext Context, WorkspaceUpdateResult Result, string ResultMessage) + { + Invoke(new MethodInvoker(() => UpdateComplete(Context, Result, ResultMessage))); + } + + void UpdateComplete(WorkspaceUpdateContext Context, WorkspaceUpdateResult Result, string ResultMessage) + { + UpdateTimer.Stop(); + + UpdateSyncConfig(Workspace.CurrentChangeNumber); + + if(Result == WorkspaceUpdateResult.Success && Context.Options.HasFlag(WorkspaceUpdateOptions.SyncSingleChange)) + { + WorkspaceSettings.AdditionalChangeNumbers.Add(Context.ChangeNumber); + Settings.Save(); + } + + if(Result == WorkspaceUpdateResult.Success && WorkspaceSettings.ExpandedArchiveTypes != null) + { + WorkspaceSettings.ExpandedArchiveTypes = WorkspaceSettings.ExpandedArchiveTypes.Except(Context.ArchiveTypeToDepotPath.Where(x => x.Value == null).Select(x => x.Key)).ToArray(); + } + + WorkspaceSettings.LastSyncChangeNumber = Context.ChangeNumber; + WorkspaceSettings.LastSyncResult = Result; + WorkspaceSettings.LastSyncResultMessage = ResultMessage; + WorkspaceSettings.LastSyncTime = DateTime.UtcNow; + WorkspaceSettings.LastSyncDurationSeconds = (int)(WorkspaceSettings.LastSyncTime.Value - Context.StartTime).TotalSeconds; + WorkspaceSettings.LastBuiltChangeNumber = Workspace.LastBuiltChangeNumber; + Settings.Save(); + + if(Result == WorkspaceUpdateResult.FilesToResolve) + { + MessageBox.Show("You have files to resolve after syncing your workspace. Please check P4."); + } + else if(Result == WorkspaceUpdateResult.FilesToClobber) + { + DesiredTaskbarState = Tuple.Create(TaskbarState.Paused, 0.0f); + Owner.UpdateProgress(); + + ClobberWindow Window = new ClobberWindow(Context.ClobberFiles); + if(Window.ShowDialog(this) == DialogResult.OK) + { + StartWorkspaceUpdate(Context); + return; + } + } + else if(Result == WorkspaceUpdateResult.FailedToCompileWithCleanWorkspace) + { + EventMonitor.PostEvent(Context.ChangeNumber, EventType.DoesNotCompile); + } + else if(Result == WorkspaceUpdateResult.Success) + { + if(Context.Options.HasFlag(WorkspaceUpdateOptions.Build)) + { + EventMonitor.PostEvent(Context.ChangeNumber, EventType.Compiles); + } + if(Context.Options.HasFlag(WorkspaceUpdateOptions.RunAfterSync)) + { + LaunchEditor(); + } + if(Context.Options.HasFlag(WorkspaceUpdateOptions.OpenSolutionAfterSync)) + { + OpenSolution(); + } + } + + DesiredTaskbarState = Tuple.Create((Result == WorkspaceUpdateResult.Success)? TaskbarState.NoProgress : TaskbarState.Error, 0.0f); + Owner.UpdateProgress(); + + BuildList.Invalidate(); + Refresh(); + UpdateStatusPanel(); + UpdateSyncActionCheckboxes(); + } + + void UpdateBuildListCallback() + { + Invoke(new MethodInvoker(UpdateBuildList)); + } + + void UpdateBuildList() + { + if(SelectedFileName != null) + { + int SelectedChange = (BuildList.SelectedItems.Count > 0)? ((PerforceChangeSummary)BuildList.SelectedItems[0].Tag).Number : -1; + + ChangeNumberToArchivePath.Clear(); + + BuildList.BeginUpdate(); + + foreach(ListViewGroup Group in BuildList.Groups) + { + Group.Name = "xxx " + Group.Name; + } + + int RemoveItems = BuildList.Items.Count; + int RemoveGroups = BuildList.Groups.Count; + + List Changes = PerforceMonitor.GetChanges(); + EventMonitor.FilterChanges(Changes.Select(x => x.Number)); + + PromotedChangeNumbers = PerforceMonitor.GetPromotedChangeNumbers(); + + string[] ExcludeChanges = new string[0]; + if(Workspace != null) + { + ConfigFile ProjectConfigFile = Workspace.ProjectConfigFile; + if(ProjectConfigFile != null) + { + ExcludeChanges = Workspace.ProjectConfigFile.GetValues("Options.ExcludeChanges", ExcludeChanges); + } + } + + bool bFirstChange = true; + bool bOnlyShowReviewed = OnlyShowReviewedCheckBox.Checked; + + NumChanges = Changes.Count; + ListIndexToChangeIndex = new List(); + SortedChangeNumbers = new List(); + + for(int ChangeIdx = 0; ChangeIdx < Changes.Count; ChangeIdx++) + { + PerforceChangeSummary Change = Changes[ChangeIdx]; + if(ShouldShowChange(Change, ExcludeChanges) || PromotedChangeNumbers.Contains(Change.Number)) + { + SortedChangeNumbers.Add(Change.Number); + + if(!bOnlyShowReviewed || (!EventMonitor.IsUnderInvestigation(Change.Number) && (ShouldIncludeInReviewedList(Change.Number) || bFirstChange))) + { + bFirstChange = false; + + ListViewGroup Group; + + string GroupName = Change.Date.ToString("D");//"dddd\\,\\ h\\.mmtt"); + for(int Idx = 0;;Idx++) + { + if(Idx == BuildList.Groups.Count) + { + Group = new ListViewGroup(GroupName); + Group.Name = GroupName; + BuildList.Groups.Add(Group); + break; + } + else if(BuildList.Groups[Idx].Name == GroupName) + { + Group = BuildList.Groups[Idx]; + break; + } + } + + DateTime DisplayTime = Change.Date; + if(Settings.bShowLocalTimes) + { + DisplayTime = (DisplayTime - ServerTimeZone).ToLocalTime(); + } + + ListViewItem Item = new ListViewItem(Group); + Item.Tag = Change; + Item.Selected = (Change.Number == SelectedChange); + Item.SubItems.Add(new ListViewItem.ListViewSubItem(Item, String.Format("{0}", Change.Number))); + Item.SubItems.Add(new ListViewItem.ListViewSubItem(Item, DisplayTime.ToString("h\\.mmtt"))); + Item.SubItems.Add(new ListViewItem.ListViewSubItem(Item, FormatUserName(Change.User))); + Item.SubItems.Add(new ListViewItem.ListViewSubItem(Item, Change.Description.Replace('\n', ' '))); + Item.SubItems.Add(new ListViewItem.ListViewSubItem(Item, "")); + Item.SubItems.Add(new ListViewItem.ListViewSubItem(Item, "")); + + // Insert it at the right position within the group + int GroupInsertIdx = 0; + while(GroupInsertIdx < Group.Items.Count && Change.Number < ((PerforceChangeSummary)Group.Items[GroupInsertIdx].Tag).Number) + { + GroupInsertIdx++; + } + Group.Items.Insert(GroupInsertIdx, Item); + + // Insert it at the right place in the list + BuildList.Items.Add(Item); + + // Store off the list index for this change + ListIndexToChangeIndex.Add(ChangeIdx); + } + } + } + + SortedChangeNumbers.Sort(); + + for(int Idx = 0; Idx < RemoveItems; Idx++) + { + BuildList.Items.RemoveAt(0); + } + for(int Idx = 0; Idx < RemoveGroups; Idx++) + { + BuildList.Groups.RemoveAt(0); + } + + BuildList.EndUpdate(); + + if(PendingSelectedChangeNumber != -1) + { + SelectChange(PendingSelectedChangeNumber); + } + } + + if(HoverItem > BuildList.Items.Count) + { + HoverItem = -1; + } + + UpdateBuildFailureNotification(); + + UpdateBuildSteps(); + UpdateSyncActionCheckboxes(); + } + + bool ShouldShowChange(PerforceChangeSummary Change, string[] ExcludeChanges) + { + foreach(string ExcludeChange in ExcludeChanges) + { + if(Regex.IsMatch(Change.Description, ExcludeChange, RegexOptions.IgnoreCase)) + { + return false; + } + } + + if(String.Compare(Change.User, "buildmachine", true) == 0 && Change.Description.IndexOf("lightmaps", StringComparison.InvariantCultureIgnoreCase) == -1) + { + return false; + } + return true; + } + + void UpdateBuildMetadataCallback() + { + Invoke(new MethodInvoker(UpdateBuildMetadata)); + } + + void UpdateBuildMetadata() + { + ChangeNumberToArchivePath.Clear(); + BuildList.Invalidate(); + UpdateStatusPanel(); + UpdateBuildFailureNotification(); + } + + bool ShouldIncludeInReviewedList(int ChangeNumber) + { + if(PromotedChangeNumbers.Contains(ChangeNumber)) + { + return true; + } + + EventSummary Review = EventMonitor.GetSummaryForChange(ChangeNumber); + if(Review != null) + { + if(Review.LastStarReview != null && Review.LastStarReview.Type == EventType.Starred) + { + return true; + } + if(Review.Verdict == ReviewVerdict.Good || Review.Verdict == ReviewVerdict.Mixed) + { + return true; + } + } + return false; + } + + void UpdateReviewsCallback() + { + Invoke(new MethodInvoker(UpdateReviews)); + } + + void UpdateReviews() + { + ChangeNumberToArchivePath.Clear(); + EventMonitor.ApplyUpdates(); + Refresh(); + UpdateBuildFailureNotification(); + } + + void UpdateBuildFailureNotification() + { + int LastChangeByCurrentUser = PerforceMonitor.LastChangeByCurrentUser; + int LastCodeChangeByCurrentUser = PerforceMonitor.LastCodeChangeByCurrentUser; + + // Find all the badges which should notify users due to content changes + HashSet ContentBadges = new HashSet(); + if(Workspace != null && Workspace.ProjectConfigFile != null) + { + ContentBadges.UnionWith(Workspace.ProjectConfigFile.GetValues("Notifications.ContentBadges", new string[0])); + } + + // Find the most recent build of each type, and the last time it succeeded + Dictionary TypeToLastBuild = new Dictionary(); + Dictionary TypeToLastSucceededBuild = new Dictionary(); + for(int Idx = SortedChangeNumbers.Count - 1; Idx >= 0; Idx--) + { + EventSummary Summary = EventMonitor.GetSummaryForChange(SortedChangeNumbers[Idx]); + if(Summary != null) + { + foreach(BuildData Build in Summary.Builds) + { + if(!TypeToLastBuild.ContainsKey(Build.BuildType) && (Build.Result == BuildDataResult.Success || Build.Result == BuildDataResult.Warning || Build.Result == BuildDataResult.Failure)) + { + TypeToLastBuild.Add(Build.BuildType, Build); + } + if(!TypeToLastSucceededBuild.ContainsKey(Build.BuildType) && Build.Result == BuildDataResult.Success) + { + TypeToLastSucceededBuild.Add(Build.BuildType, Build); + } + } + } + } + + // Find all the build types that the user needs to be notified about. + int RequireNotificationForChange = -1; + List NotifyBuilds = new List(); + foreach(BuildData LastBuild in TypeToLastBuild.Values.OrderBy(x => x.BuildType)) + { + if(LastBuild.Result == BuildDataResult.Failure || LastBuild.Result == BuildDataResult.Warning) + { + // Get the last submitted changelist by this user of the correct type + int LastChangeByCurrentUserOfType; + if(ContentBadges.Contains(LastBuild.BuildType)) + { + LastChangeByCurrentUserOfType = LastChangeByCurrentUser; + } + else + { + LastChangeByCurrentUserOfType = LastCodeChangeByCurrentUser; + } + + // Check if the failed build was after we submitted + if(LastChangeByCurrentUserOfType > 0 && LastBuild.ChangeNumber >= LastChangeByCurrentUserOfType) + { + // And check that there wasn't a successful build after we submitted (if there was, we're in the clear) + BuildData LastSuccessfulBuild; + if(!TypeToLastSucceededBuild.TryGetValue(LastBuild.BuildType, out LastSuccessfulBuild) || LastSuccessfulBuild.ChangeNumber < LastChangeByCurrentUserOfType) + { + // Add it to the list of notifications + NotifyBuilds.Add(LastBuild); + + // Check if this is a new notification, rather than one we've already dismissed + int NotifiedChangeNumber; + if(!NotifiedBuildTypeToChangeNumber.TryGetValue(LastBuild.BuildType, out NotifiedChangeNumber) || NotifiedChangeNumber < LastChangeByCurrentUserOfType) + { + RequireNotificationForChange = Math.Max(RequireNotificationForChange, LastChangeByCurrentUserOfType); + } + } + } + } + } + + // If there's anything we haven't already notified the user about, do so now + if(RequireNotificationForChange != -1) + { + // Format the platform list + StringBuilder PlatformList = new StringBuilder(NotifyBuilds[0].BuildType); + for(int Idx = 1; Idx < NotifyBuilds.Count - 1; Idx++) + { + PlatformList.AppendFormat(", {0}", NotifyBuilds[Idx].BuildType); + } + if(NotifyBuilds.Count > 1) + { + PlatformList.AppendFormat(" and {0}", NotifyBuilds[NotifyBuilds.Count - 1].BuildType); + } + + // Show the balloon tooltip + if(NotifyBuilds.Any(x => x.Result == BuildDataResult.Failure)) + { + string Title = String.Format("{0} Errors", PlatformList.ToString()); + string Message = String.Format("CIS failed after your last submitted changelist ({0}).", RequireNotificationForChange); + NotificationWindow.Show(NotificationType.Error, Title, Message); + } + else + { + string Title = String.Format("{0} Warnings", PlatformList.ToString()); + string Message = String.Format("CIS completed with warnings after your last submitted changelist ({0}).", RequireNotificationForChange); + NotificationWindow.Show(NotificationType.Warning, Title, Message); + } + + // Set the link to open the right build pages + int HighlightChange = NotifyBuilds.Max(x => x.ChangeNumber); + NotificationWindow.OnMoreInformation = () => { Owner.ShowAndActivate(); SelectChange(HighlightChange); }; + + // Don't show messages for this change again + foreach(BuildData NotifyBuild in NotifyBuilds) + { + NotifiedBuildTypeToChangeNumber[NotifyBuild.BuildType] = RequireNotificationForChange; + } + } + } + + private void BuildList_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e) + { + e.DrawDefault = true; + } + + private void BuildList_DrawItem(object sender, DrawListViewItemEventArgs e) + { + if(Application.RenderWithVisualStyles) + { + if(e.State.HasFlag(ListViewItemStates.Selected)) + { + SelectedItemRenderer.DrawBackground(e.Graphics, e.Bounds); + } + else if(e.ItemIndex == HoverItem) + { + TrackedItemRenderer.DrawBackground(e.Graphics, e.Bounds); + } + else if(((PerforceChangeSummary)e.Item.Tag).Number == Workspace.PendingChangeNumber) + { + TrackedItemRenderer.DrawBackground(e.Graphics, e.Bounds); + } + } + else + { + if(e.State.HasFlag(ListViewItemStates.Selected)) + { + e.Graphics.FillRectangle(SystemBrushes.ButtonFace, e.Bounds); + } + else + { + e.Graphics.FillRectangle(SystemBrushes.Window, e.Bounds); + } + } + } + + private string GetArchivePathForChangeNumber(int ChangeNumber) + { + string ArchivePath; + if(!ChangeNumberToArchivePath.TryGetValue(ChangeNumber, out ArchivePath)) + { + PerforceChangeType Type; + if(PerforceMonitor.TryGetChangeType(ChangeNumber, out Type)) + { + // Try to get the archive for this CL + if(!PerforceMonitor.TryGetArchivePathForChangeNumber(ChangeNumber, out ArchivePath) && Type == PerforceChangeType.Content) + { + // Otherwise if it's a content change, find the previous build any use the archive path from that + int Index = SortedChangeNumbers.BinarySearch(ChangeNumber); + if(Index > 0) + { + ArchivePath = GetArchivePathForChangeNumber(SortedChangeNumbers[Index - 1]); + } + } + } + ChangeNumberToArchivePath.Add(ChangeNumber, ArchivePath); + } + return ArchivePath; + } + + private Color Blend(Color First, Color Second, float T) + { + return Color.FromArgb((int)(First.R + (Second.R - First.R) * T), (int)(First.G + (Second.G - First.G) * T), (int)(First.B + (Second.B - First.B) * T)); + } + + private bool CanSyncChange(int ChangeNumber) + { + return !ShouldSyncPrecompiledEditor || GetArchivePathForChangeNumber(ChangeNumber) != null; + } + + private void BuildList_DrawSubItem(object sender, DrawListViewSubItemEventArgs e) + { + PerforceChangeSummary Change = (PerforceChangeSummary)e.Item.Tag; + + int IconY = e.Bounds.Top + (e.Bounds.Height - 16) / 2; + + StringFormat Format = new StringFormat(); + Format.LineAlignment = StringAlignment.Center; + Format.FormatFlags = StringFormatFlags.NoWrap; + Format.Trimming = StringTrimming.EllipsisCharacter; + + Font CurrentFont = (Change.Number == Workspace.PendingChangeNumber || Change.Number == Workspace.CurrentChangeNumber)? SelectedBuildFont : BuildFont; + + bool bAllowSync = CanSyncChange(Change.Number); + Color TextColor = (bAllowSync || Change.Number == Workspace.PendingChangeNumber || Change.Number == Workspace.CurrentChangeNumber || (WorkspaceSettings != null && WorkspaceSettings.AdditionalChangeNumbers.Contains(Change.Number)))? SystemColors.WindowText : Blend(SystemColors.Window, SystemColors.WindowText, 0.25f); + + if(e.ColumnIndex == IconColumn.Index) + { + EventSummary Summary = EventMonitor.GetSummaryForChange(Change.Number); + + int MinX = 4; + if((Summary != null && EventMonitor.WasSyncedByCurrentUser(Summary.ChangeNumber)) || (Workspace != null && Workspace.CurrentChangeNumber == Change.Number)) + { + e.Graphics.DrawImage(Properties.Resources.Icons, MinX, IconY, PreviousSyncIcon, GraphicsUnit.Pixel); + } + else if(WorkspaceSettings != null && WorkspaceSettings.AdditionalChangeNumbers.Contains(Change.Number)) + { + e.Graphics.DrawImage(Properties.Resources.Icons, MinX, IconY, AdditionalSyncIcon, GraphicsUnit.Pixel); + } + else if(bAllowSync && ((Summary != null && Summary.LastStarReview != null && Summary.LastStarReview.Type == EventType.Starred) || PromotedChangeNumbers.Contains(Change.Number))) + { + e.Graphics.DrawImage(Properties.Resources.Icons, MinX, IconY, PromotedBuildIcon, GraphicsUnit.Pixel); + } + MinX += PromotedBuildIcon.Width; + + if(bAllowSync) + { + Rectangle QualityIcon = DefaultBuildIcon; + if(EventMonitor.IsUnderInvestigation(Change.Number)) + { + QualityIcon = BadBuildIcon; + } + else if(Summary != null) + { + if(Summary.Verdict == ReviewVerdict.Good) + { + QualityIcon = GoodBuildIcon; + } + else if(Summary.Verdict == ReviewVerdict.Bad) + { + QualityIcon = BadBuildIcon; + } + else if(Summary.Verdict == ReviewVerdict.Mixed) + { + QualityIcon = MixedBuildIcon; + } + } + + e.Graphics.DrawImage(Properties.Resources.Icons, MinX, IconY, QualityIcon, GraphicsUnit.Pixel); + MinX += QualityIcon.Width; + } + } + else if(e.ColumnIndex == ChangeColumn.Index || e.ColumnIndex == TimeColumn.Index || e.ColumnIndex == AuthorColumn.Index || e.ColumnIndex == DescriptionColumn.Index) + { + TextRenderer.DrawText(e.Graphics, e.SubItem.Text, CurrentFont, e.Bounds, TextColor, TextFormatFlags.EndEllipsis | TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter | TextFormatFlags.NoPrefix); + } + else if(e.ColumnIndex == CISColumn.Index) + { + e.Graphics.IntersectClip(e.Bounds); + e.Graphics.SmoothingMode = SmoothingMode.HighQuality; + + EventSummary Summary = EventMonitor.GetSummaryForChange(Change.Number); + if(Summary == null || Summary.Builds.Count == 0) + { + PerforceChangeType Type; + if(PerforceMonitor.TryGetChangeType(Change.Number, out Type)) + { + if(Type == PerforceChangeType.Code) + { + DrawSingleBadge(e.Graphics, e.Bounds, "Code", Color.FromArgb(192, 192, 192)); + } + else if(Type == PerforceChangeType.Content) + { + DrawSingleBadge(e.Graphics, e.Bounds, "Content", bAllowSync? Color.FromArgb(128, 128, 192) : Color.FromArgb(192, 192, 192)); + } + } + } + else + { + Tuple[] Badges = LayoutBadges(Summary.Builds, e.Bounds); + foreach(Tuple Badge in Badges) + { + Color BadgeColor = Color.FromArgb(128, 192, 64); + if(Badge.Item1.Result == BuildDataResult.Starting) + { + BadgeColor = Color.FromArgb(128, 192, 255); + } + else if(Badge.Item1.Result == BuildDataResult.Warning) + { + BadgeColor = Color.FromArgb(255, 192, 0); + } + else if(Badge.Item1.Result == BuildDataResult.Failure) + { + BadgeColor = Color.FromArgb(192, 64, 0); + } + + if(Badge.Item1 == HoverBadge) + { + BadgeColor = Color.FromArgb(Math.Min(BadgeColor.R + 32, 255), Math.Min(BadgeColor.G + 32, 255), Math.Min(BadgeColor.B + 32, 255)); + } + + Size BadgeSize = GetBadgeSize(Badge.Item1.BuildType); + DrawBadge(e.Graphics, Badge.Item2, Badge.Item1.BuildType, BadgeColor); + } + } + } + else if(e.ColumnIndex == StatusColumn.Index) + { + int MaxX = e.SubItem.Bounds.Right; + + if(Change.Number == Workspace.PendingChangeNumber && Workspace.IsBusy()) + { + Tuple Progress = Workspace.CurrentProgress; + + MaxX -= CancelIcon.Width; + e.Graphics.DrawImage(Properties.Resources.Icons, MaxX, IconY, CancelIcon, GraphicsUnit.Pixel); + + if(!Splitter.IsLogVisible()) + { + MaxX -= InfoIcon.Width; + e.Graphics.DrawImage(Properties.Resources.Icons, MaxX, IconY, InfoIcon, GraphicsUnit.Pixel); + } + + int MinX = e.Bounds.Left; + + TextRenderer.DrawText(e.Graphics, Progress.Item1, CurrentFont, new Rectangle(MinX, e.Bounds.Top, MaxX - MinX, e.Bounds.Height), TextColor, TextFormatFlags.Left | TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis | TextFormatFlags.NoPrefix); + } + else + { + e.Graphics.IntersectClip(e.Bounds); + e.Graphics.SmoothingMode = SmoothingMode.HighQuality; + + if(Change.Number == Workspace.CurrentChangeNumber) + { + EventData Review = EventMonitor.GetReviewByCurrentUser(Change.Number); + + MaxX -= FrownIcon.Width; + e.Graphics.DrawImage(Properties.Resources.Icons, MaxX, IconY, (Review == null || !EventMonitor.IsPositiveReview(Review.Type))? FrownIcon : DisabledFrownIcon, GraphicsUnit.Pixel); + + MaxX -= HappyIcon.Width; + e.Graphics.DrawImage(Properties.Resources.Icons, MaxX, IconY, (Review == null || !EventMonitor.IsNegativeReview(Review.Type))? HappyIcon : DisabledHappyIcon, GraphicsUnit.Pixel); + } + else if(e.ItemIndex == HoverItem && bAllowSync) + { + Rectangle SyncBadgeRectangle = GetSyncBadgeRectangle(e.SubItem.Bounds); + DrawBadge(e.Graphics, SyncBadgeRectangle, "Sync", bHoverSync? Color.FromArgb(140, 180, 230) : Color.FromArgb(112, 146, 190)); + MaxX = SyncBadgeRectangle.Left - 2; + } + + string SummaryText; + if(WorkspaceSettings.LastSyncChangeNumber == -1 || WorkspaceSettings.LastSyncChangeNumber != Change.Number || !GetLastUpdateMessage(WorkspaceSettings.LastSyncResult, WorkspaceSettings.LastSyncResultMessage, out SummaryText)) + { + StringBuilder SummaryTextBuilder = new StringBuilder(); + + EventSummary Summary = EventMonitor.GetSummaryForChange(Change.Number); + + AppendItemList(SummaryTextBuilder, " ", "Under investigation by {0}.", EventMonitor.GetInvestigatingUsers(Change.Number).Select(x => FormatUserName(x))); + + if(Summary != null) + { + string Comments = String.Join(", ", Summary.Comments.Where(x => !String.IsNullOrWhiteSpace(x.Text)).Select(x => String.Format("{0}: \"{1}\"", FormatUserName(x.UserName), x.Text))); + if(Comments.Length > 0) + { + SummaryTextBuilder.Append(((SummaryTextBuilder.Length == 0)? "" : " ") + Comments); + } + else + { + AppendItemList(SummaryTextBuilder, " ", "Used by {0}.", Summary.CurrentUsers.Select(x => FormatUserName(x))); + } + } + + SummaryText = (SummaryTextBuilder.Length == 0)? "No current users." : SummaryTextBuilder.ToString(); + } + + if(SummaryText != null && SummaryText.Contains('\n')) + { + SummaryText = SummaryText.Substring(0, SummaryText.IndexOf('\n')).TrimEnd() + "..."; + } + + TextRenderer.DrawText(e.Graphics, SummaryText, CurrentFont, new Rectangle(e.Bounds.Left, e.Bounds.Top, MaxX - e.Bounds.Left, e.Bounds.Height), TextColor, TextFormatFlags.Left | TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis | TextFormatFlags.NoPrefix); + } + } + else + { + throw new NotImplementedException(); + } + } + + private Tuple[] LayoutBadges(IEnumerable Builds, Rectangle DisplayRectangle) + { + int NextX = 0; + List> Badges = new List>(); + foreach(BuildData Build in Builds.OrderBy(x => x.BuildType)) + { + Size BadgeSize = GetBadgeSize(Build.BuildType); + Badges.Add(new Tuple(Build, new Rectangle(NextX, DisplayRectangle.Top + (DisplayRectangle.Height - BadgeSize.Height) / 2, BadgeSize.Width, BadgeSize.Height))); + NextX += BadgeSize.Width + 2; + } + + int Offset = (Badges.Count > 0)? DisplayRectangle.Left + Math.Max(DisplayRectangle.Width - Badges.Last().Item2.Right, 0) / 2 : 0; + return Badges.Select(x => new Tuple(x.Item1, new Rectangle(x.Item2.Left + Offset, x.Item2.Top, x.Item2.Width, x.Item2.Height))).ToArray(); + } + + private Rectangle GetSyncBadgeRectangle(Rectangle Bounds) + { + Size BadgeSize = GetBadgeSize("Sync"); + return new Rectangle(Bounds.Right - BadgeSize.Width - 2, Bounds.Top + (Bounds.Height - BadgeSize.Height) / 2, BadgeSize.Width, BadgeSize.Height); + } + + private void DrawSingleBadge(Graphics Graphics, Rectangle DisplayRectangle, string BadgeText, Color BadgeColor) + { + Size BadgeSize = GetBadgeSize(BadgeText); + + int X = DisplayRectangle.Left + (DisplayRectangle.Width - BadgeSize.Width) / 2; + int Y = DisplayRectangle.Top + (DisplayRectangle.Height - BadgeSize.Height) / 2; + + DrawBadge(Graphics, new Rectangle(X, Y, BadgeSize.Width, BadgeSize.Height), BadgeText, BadgeColor); + } + + private void DrawBadge(Graphics Graphics, Rectangle BadgeRect, string BadgeText, Color BadgeColor) + { + GraphicsPath Path = new GraphicsPath(); + Path.StartFigure(); + Path.AddArc((float)BadgeRect.Left, (float)BadgeRect.Top, BadgeRect.Height, BadgeRect.Height, 90, 180); + Path.AddArc((float)BadgeRect.Right - BadgeRect.Height - 1, (float)BadgeRect.Top, BadgeRect.Height, BadgeRect.Height, 270, 180); + Path.CloseFigure(); + + using(SolidBrush Brush = new SolidBrush(BadgeColor)) + { + Graphics.FillPath(Brush, Path); + } + + TextRenderer.DrawText(Graphics, BadgeText, BadgeFont, BadgeRect, Color.White, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.SingleLine | TextFormatFlags.NoPrefix); + } + + private Size GetBadgeSize(string BadgeText) + { + Size LabelSize = TextRenderer.MeasureText(BadgeText, BadgeFont); + int BadgeHeight = BadgeFont.Height - 1; + return new Size(LabelSize.Width + BadgeHeight - 4, BadgeHeight); + } + + private static bool GetLastUpdateMessage(WorkspaceUpdateResult Result, string ResultMessage, out string Message) + { + if(Result != WorkspaceUpdateResult.Success && ResultMessage != null) + { + Message = ResultMessage; + return true; + } + return GetGenericLastUpdateMessage(Result, out Message); + } + + private static bool GetGenericLastUpdateMessage(WorkspaceUpdateResult Result, out string Message) + { + switch(Result) + { + case WorkspaceUpdateResult.Canceled: + Message = "Sync canceled."; + return true; + case WorkspaceUpdateResult.FailedToSync: + Message = "Failed to sync files."; + return true; + case WorkspaceUpdateResult.FilesToResolve: + Message = "Sync finished with unresolved files."; + return true; + case WorkspaceUpdateResult.FilesToClobber: + Message = "Sync failed due to modified files in workspace."; + return true; + case WorkspaceUpdateResult.FailedToCompile: + case WorkspaceUpdateResult.FailedToCompileWithCleanWorkspace: + Message = "Compile failed."; + return true; + default: + Message = null; + return false; + } + } + + private static string FormatUserName(string UserName) + { + StringBuilder NormalUserName = new StringBuilder(); + for(int Idx = 0; Idx < UserName.Length; Idx++) + { + if(Idx == 0 || UserName[Idx - 1] == '.') + { + NormalUserName.Append(Char.ToUpper(UserName[Idx])); + } + else if(UserName[Idx] == '.') + { + NormalUserName.Append(' '); + } + else + { + NormalUserName.Append(UserName[Idx]); + } + } + return NormalUserName.ToString(); + } + + private static void AppendUserList(StringBuilder Builder, string Separator, string Format, IEnumerable Reviews) + { + AppendItemList(Builder, Separator, Format, Reviews.Select(x => FormatUserName(x.UserName))); + } + + private static void AppendItemList(StringBuilder Builder, string Separator, string Format, IEnumerable Items) + { + string ItemList = FormatItemList(Format, Items); + if(ItemList != null) + { + if(Builder.Length > 0) + { + Builder.Append(Separator); + } + Builder.Append(ItemList); + } + } + + private static string FormatItemList(string Format, IEnumerable Items) + { + string[] ItemsArray = Items.Distinct().ToArray(); + if(ItemsArray.Length == 0) + { + return null; + } + + StringBuilder Builder = new StringBuilder(ItemsArray[0]); + if(ItemsArray.Length > 1) + { + for(int Idx = 1; Idx < ItemsArray.Length - 1; Idx++) + { + Builder.Append(", "); + Builder.Append(ItemsArray[Idx]); + } + Builder.Append(" and "); + Builder.Append(ItemsArray.Last()); + } + return String.Format(Format, Builder.ToString()); + } + + private void BuildList_MouseDoubleClick(object Sender, MouseEventArgs Args) + { + if(Args.Button == MouseButtons.Left) + { + ListViewHitTestInfo HitTest = BuildList.HitTest(Args.Location); + if(HitTest.Item != null) + { + PerforceChangeSummary Change = (PerforceChangeSummary)HitTest.Item.Tag; + if(Change.Number == Workspace.CurrentChangeNumber) + { + LaunchEditor(); + } + else + { + StartSync(Change.Number); + } + } + } + } + + public void LaunchEditor() + { + if(!Workspace.IsBusy() && Workspace.CurrentChangeNumber != -1) + { + BuildConfig EditorBuildConfig = GetEditorBuildConfig(); + + List ReceiptPaths = GetEditorReceiptPaths(EditorBuildConfig); + + string EditorExe = GetEditorExePath(EditorBuildConfig); + if(ReceiptPaths.Any(x => File.Exists(x)) && File.Exists(EditorExe)) + { + StringBuilder LaunchArguments = new StringBuilder(); + if(SelectedFileName.EndsWith(".uproject", StringComparison.InvariantCultureIgnoreCase)) + { + LaunchArguments.AppendFormat("\"{0}\"", SelectedFileName); + } + foreach(Tuple EditorArgument in Settings.EditorArguments) + { + if(EditorArgument.Item2) + { + LaunchArguments.AppendFormat(" {0}", EditorArgument.Item1); + } + } + if(EditorBuildConfig == BuildConfig.Debug || EditorBuildConfig == BuildConfig.DebugGame) + { + LaunchArguments.Append(" -debug"); + } + + if(!Utility.SpawnProcess(EditorExe, LaunchArguments.ToString())) + { + ShowErrorDialog("Unable to spawn {0} {1}", EditorExe, LaunchArguments.ToString()); + } + } + else + { + if(MessageBox.Show("The editor needs to be built before you can run it. Build it now?", "Editor out of date", MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes) + { + Owner.ShowAndActivate(); + + WorkspaceUpdateOptions Options = WorkspaceUpdateOptions.Build | WorkspaceUpdateOptions.RunAfterSync; + if(Settings.bUseIncrementalBuilds) + { + Options |= WorkspaceUpdateOptions.UseIncrementalBuilds; + } + + WorkspaceUpdateContext Context = new WorkspaceUpdateContext(Workspace.CurrentChangeNumber, Options, null, GetDefaultBuildStepObjects(), ProjectSettings.BuildSteps, null, GetWorkspaceVariables()); + StartWorkspaceUpdate(Context); + } + } + } + } + + private string GetEditorExePath(BuildConfig Config) + { + string ExeFileName = "UE4Editor.exe"; + if(Config != BuildConfig.DebugGame && Config != BuildConfig.Development) + { + ExeFileName = String.Format("UE4Editor-Win64-{0}.exe", Config.ToString()); + } + return Path.Combine(BranchDirectoryName, "Engine", "Binaries", "Win64", ExeFileName); + } + + private bool IsEditorRunning(BuildConfig Config) + { + string EditorFileName = Path.GetFullPath(GetEditorExePath(GetEditorBuildConfig())); + try + { + foreach(Process ProcessInstance in Process.GetProcessesByName(Path.GetFileNameWithoutExtension(EditorFileName))) + { + try + { + string ProcessFileName = Path.GetFullPath(Path.GetFullPath(ProcessInstance.MainModule.FileName)); + if(String.Compare(EditorFileName, ProcessFileName, StringComparison.InvariantCultureIgnoreCase) == 0) + { + return true; + } + } + catch + { + } + } + } + catch + { + } + return false; + } + + private List GetEditorReceiptPaths(BuildConfig Config) + { + string ConfigSuffix = (Config == BuildConfig.Development)? "" : String.Format("-Win64-{0}", Config.ToString()); + + List PossiblePaths = new List(); + if(EditorTargetName == null) + { + PossiblePaths.Add(Path.Combine(BranchDirectoryName, "Engine", "Binaries", "Win64", String.Format("UE4Editor{0}.target", ConfigSuffix))); + PossiblePaths.Add(Path.Combine(BranchDirectoryName, "Engine", "Build", "Receipts", String.Format("UE4Editor-Win64-{0}.target.xml", Config.ToString()))); + } + else + { + PossiblePaths.Add(Path.Combine(Path.GetDirectoryName(SelectedFileName), "Binaries", "Win64", String.Format("{0}{1}.target", EditorTargetName, ConfigSuffix))); + PossiblePaths.Add(Path.Combine(Path.GetDirectoryName(SelectedFileName), "Build", "Receipts", String.Format("{0}-Win64-{1}.target.xml", EditorTargetName, Config.ToString()))); + } + return PossiblePaths; + } + + private void TimerCallback(object Sender, EventArgs Args) + { + Tuple Progress = Workspace.CurrentProgress; + if(Progress != null && Progress.Item2 > 0.0f) + { + DesiredTaskbarState = Tuple.Create(TaskbarState.Normal, Progress.Item2); + } + else + { + DesiredTaskbarState = Tuple.Create(TaskbarState.NoProgress, 0.0f); + } + + Owner.UpdateProgress(); + + UpdateStatusPanel(); + BuildList.Refresh(); + } + + private void OpenPerforce() + { + StringBuilder CommandLine = new StringBuilder(); + if(Workspace != null && Workspace.Perforce != null) + { + string ServerAndPort; + if(!Workspace.Perforce.GetSetting("P4PORT", out ServerAndPort, Log)) + { + ServerAndPort = "perforce:1666"; + } + CommandLine.AppendFormat("-p \"{0}\" -c \"{1}\" -u \"{2}\"", ServerAndPort, Workspace.Perforce.ClientName, Workspace.Perforce.UserName); + } + Process.Start("p4v.exe", CommandLine.ToString()); + } + + private void UpdateStatusPanel() + { + int NewContentWidth = Math.Max(TextRenderer.MeasureText(String.Format("Last synced to {0} at changelist 123456789. 12 users are on a newer build. | Sync Now | Sync To...", StreamName ?? ""), StatusPanel.Font).Width, 400); + StatusPanel.SetContentWidth(NewContentWidth); + + List Lines = new List(); + if(Workspace.IsBusy()) + { + // Sync in progress + Tuple Progress = Workspace.CurrentProgress; + + StatusLine SummaryLine = new StatusLine(); + SummaryLine.AddText("Updating to changelist "); + SummaryLine.AddLink(Workspace.PendingChangeNumber.ToString(), FontStyle.Regular, () => { SelectChange(Workspace.PendingChangeNumber); }); + SummaryLine.AddText("... | "); + SummaryLine.AddLink(Splitter.IsLogVisible()? "Hide Log" : "Show Log", FontStyle.Bold | FontStyle.Underline, () => { ToggleLogVisibility(); }); + SummaryLine.AddText(" | "); + SummaryLine.AddLink("Cancel", FontStyle.Bold | FontStyle.Underline, () => { CancelWorkspaceUpdate(); }); + Lines.Add(SummaryLine); + + StatusLine ProgressLine = new StatusLine(); + ProgressLine.AddText(String.Format("{0} ", Progress.Item1)); + if(Progress.Item2 > 0.0f) ProgressLine.AddProgressBar(Progress.Item2); + Lines.Add(ProgressLine); + } + else + { + // Sync status + StatusLine SummaryLine = new StatusLine(); + if(Workspace.CurrentChangeNumber != -1) + { + if(StreamName == null) + { + SummaryLine.AddText("Last synced to changelist "); + } + else + { + SummaryLine.AddText("Last synced to "); + SummaryLine.AddLink(StreamName + "\u25BE", FontStyle.Regular, (P, R) => { SelectOtherStream(R); }); + SummaryLine.AddText(" at changelist "); + } + SummaryLine.AddLink(String.Format("{0}.", Workspace.CurrentChangeNumber), FontStyle.Regular, () => { SelectChange(Workspace.CurrentChangeNumber); }); + int NumUsersOnNewerChange = SortedChangeNumbers.Where(x => (x > Workspace.CurrentChangeNumber)).OrderByDescending(x => x).Select(x => EventMonitor.GetSummaryForChange(x)).Where(x => x != null && (!ShouldSyncPrecompiledEditor || GetArchivePathForChangeNumber(x.ChangeNumber) != null)).Sum(x => x.CurrentUsers.Count); + if(NumUsersOnNewerChange > 0) + { + SummaryLine.AddText((NumUsersOnNewerChange == 1)? " 1 user is on a newer build." : String.Format(" {0} users are on a newer build.", NumUsersOnNewerChange)); + } + } + else + { + SummaryLine.AddText("You are not currently synced to "); + if(StreamName == null) + { + SummaryLine.AddText("this branch."); + } + else + { + SummaryLine.AddLink(StreamName + " \u25BE", FontStyle.Regular, (P, R) => { SelectOtherStream(R); }); + } + } + SummaryLine.AddText(" | "); + SummaryLine.AddLink("Sync Now", FontStyle.Bold | FontStyle.Underline, () => { SyncLatestChange(); }); + SummaryLine.AddText(" - "); + SummaryLine.AddLink(" To... \u25BE", 0, (P, R) => { ShowSyncMenu(R); }); + Lines.Add(SummaryLine); + + // Programs + StatusLine ProgramsLine = new StatusLine(); + if(Workspace.CurrentChangeNumber != -1) + { + ProgramsLine.AddLink("Unreal Editor", FontStyle.Regular, () => { LaunchEditor(); }); + ProgramsLine.AddText(" | "); + } + ProgramsLine.AddLink("Perforce", FontStyle.Regular, () => { OpenPerforce(); }); + ProgramsLine.AddText(" | "); + ProgramsLine.AddLink("Visual Studio", FontStyle.Regular, () => { OpenSolution(); }); + ProgramsLine.AddText(" | "); + ProgramsLine.AddLink("Windows Explorer", FontStyle.Regular, () => { Process.Start("explorer.exe", String.Format("\"{0}\"", Path.GetDirectoryName(SelectedFileName))); }); + ProgramsLine.AddText(" | "); + ProgramsLine.AddLink("More... \u25BE", FontStyle.Regular, (P, R) => { ShowActionsMenu(R); }); + Lines.Add(ProgramsLine); + + // Get the summary of the last sync + if(WorkspaceSettings.LastSyncChangeNumber > 0) + { + string SummaryText; + if(WorkspaceSettings.LastSyncChangeNumber == Workspace.CurrentChangeNumber && WorkspaceSettings.LastSyncResult == WorkspaceUpdateResult.Success && WorkspaceSettings.LastSyncTime.HasValue) + { + Lines.Add(new StatusLine()); + + StatusLine SuccessLine = new StatusLine(); + SuccessLine.AddIcon(Properties.Resources.StatusIcons, new Size(16, 16), 0); + SuccessLine.AddText(String.Format(" Sync took {0}{1}s, completed at {2}.", (WorkspaceSettings.LastSyncDurationSeconds >= 60)? String.Format("{0}m ", WorkspaceSettings.LastSyncDurationSeconds / 60) : "", WorkspaceSettings.LastSyncDurationSeconds % 60, WorkspaceSettings.LastSyncTime.Value.ToLocalTime().ToString("h\\:mmtt").ToLowerInvariant())); + Lines.Add(SuccessLine); + } + else if(GetLastUpdateMessage(WorkspaceSettings.LastSyncResult, WorkspaceSettings.LastSyncResultMessage, out SummaryText)) + { + Lines.Add(new StatusLine()); + + int SummaryTextLength = SummaryText.IndexOf('\n'); + if(SummaryTextLength == -1) + { + SummaryTextLength = SummaryText.Length; + } + SummaryTextLength = Math.Min(SummaryTextLength, 80); + + StatusLine FailLine = new StatusLine(); + FailLine.AddIcon(Properties.Resources.StatusIcons, new Size(16, 16), 1); + + if(SummaryTextLength == SummaryText.Length) + { + FailLine.AddText(String.Format(" {0} ", SummaryText)); + } + else + { + FailLine.AddText(String.Format(" {0}... ", SummaryText.Substring(0, SummaryTextLength).TrimEnd())); + FailLine.AddLink("More...", FontStyle.Bold | FontStyle.Underline, () => { ViewLastSyncStatus(); }); + FailLine.AddText(" | "); + } + FailLine.AddLink("Show Log", FontStyle.Bold | FontStyle.Underline, () => { ShowErrorInLog(); }); + Lines.Add(FailLine); + } + } + } + StatusPanel.Set(Lines); + } + + private void SelectOtherStream(Rectangle Bounds) + { + if(StreamName != null) + { + IReadOnlyList OtherStreamNames = PerforceMonitor.OtherStreamNames; + IReadOnlyList OtherStreamFilter = Workspace.ProjectStreamFilter; + + StreamContextMenu.Items.Clear(); + + if(OtherStreamFilter != null && !Settings.bShowAllStreams) + { + OtherStreamNames = OtherStreamNames.Where(x => OtherStreamFilter.Any(y => y.Equals(x, StringComparison.InvariantCultureIgnoreCase)) || x.Equals(StreamName, StringComparison.InvariantCultureIgnoreCase)).ToList().AsReadOnly(); + } + + foreach(string OtherStreamName in OtherStreamNames.OrderBy(x => x).Where(x => !x.EndsWith("/Dev-Binaries"))) + { + string ThisStreamName = OtherStreamName; // Local for lambda capture + + ToolStripMenuItem Item = new ToolStripMenuItem(ThisStreamName, null, new EventHandler((S, E) => SelectStream(ThisStreamName))); + if(String.Compare(StreamName, OtherStreamName, StringComparison.InvariantCultureIgnoreCase) == 0) + { + Item.Checked = true; + } + StreamContextMenu.Items.Add(Item); + } + + if(OtherStreamFilter != null) + { + StreamContextMenu.Items.Add(new ToolStripSeparator()); + if(Settings.bShowAllStreams) + { + StreamContextMenu.Items.Add(new ToolStripMenuItem("Show Filtered Stream List...", null, new EventHandler((S, E) => SetShowAllStreamsOption(false, Bounds)))); + } + else + { + StreamContextMenu.Items.Add(new ToolStripMenuItem("Show All Streams...", null, new EventHandler((S, E) => SetShowAllStreamsOption(true, Bounds)))); + } + } + + StreamContextMenu.Show(StatusPanel, new Point(Bounds.Left, Bounds.Bottom), ToolStripDropDownDirection.BelowRight); + } + } + + private void SetShowAllStreamsOption(bool bValue, Rectangle Bounds) + { + Settings.bShowAllStreams = bValue; + Settings.Save(); + + // Showing the new context menu before the current one has closed seems to fail to display it if the new context menu is shorter (ie. the current cursor position is out of bounds). + // BeginInvoke() it so it won't happen until the menu has closed. + BeginInvoke(new MethodInvoker(() => SelectOtherStream(Bounds))); + } + + private void SelectStream(string StreamName) + { + if(Workspace.IsBusy()) + { + MessageBox.Show("Please retry after the current sync has finished.", "Sync in Progress"); + } + else if(Workspace.Perforce != null) + { + if(!Workspace.Perforce.HasOpenFiles(Log) || MessageBox.Show("You have files open for edit in this workspace. If you continue, you will not be able to submit them until you switch back.\n\nContinue switching workspaces?", "Files checked out", MessageBoxButtons.YesNo) == DialogResult.Yes) + { + if(Workspace.Perforce.SwitchStream(StreamName, Log)) + { + StatusPanel.SuspendLayout(); + StreamChangedCallback(); + StatusPanel.ResumeLayout(); + } + } + } + } + + private void ViewLastSyncStatus() + { + string SummaryText; + if(GetLastUpdateMessage(WorkspaceSettings.LastSyncResult, WorkspaceSettings.LastSyncResultMessage, out SummaryText)) + { + string CaptionText; + if(!GetGenericLastUpdateMessage(WorkspaceSettings.LastSyncResult, out CaptionText)) + { + CaptionText = "Sync error"; + } + MessageBox.Show(SummaryText, CaptionText); + } + } + + private void ShowErrorInLog() + { + if(!Splitter.IsLogVisible()) + { + ToggleLogVisibility(); + } + SyncLog.ScrollToEnd(); + } + + private void ShowActionsMenu(Rectangle Bounds) + { + MoreToolsContextMenu.Show(StatusPanel, new Point(Bounds.Left, Bounds.Bottom), ToolStripDropDownDirection.BelowRight); + } + + private void SelectChange(int ChangeNumber) + { + PendingSelectedChangeNumber = -1; + + foreach(ListViewItem Item in BuildList.Items) + { + PerforceChangeSummary Summary = (PerforceChangeSummary)Item.Tag; + if(Summary != null && Summary.Number <= ChangeNumber) + { + Item.Selected = true; + Item.EnsureVisible(); + return; + } + } + + PendingSelectedChangeNumber = ChangeNumber; + + if(BuildList.Items.Count > 0) + { + BuildList.Items[BuildList.Items.Count - 1].EnsureVisible(); + } + + UpdateNumRequestedBuilds(false); + } + + private void BuildList_MouseClick(object Sender, MouseEventArgs Args) + { + if(Args.Button == MouseButtons.Left) + { + ListViewHitTestInfo HitTest = BuildList.HitTest(Args.Location); + if(HitTest.Item != null) + { + PerforceChangeSummary Change = (PerforceChangeSummary)HitTest.Item.Tag; + if(Workspace.PendingChangeNumber == Change.Number) + { + Rectangle SubItemRect = HitTest.Item.SubItems[StatusColumn.Index].Bounds; + + if(Workspace.IsBusy()) + { + Rectangle CancelRect = new Rectangle(SubItemRect.Right - 16, SubItemRect.Top, 16, SubItemRect.Height); + Rectangle InfoRect = new Rectangle(SubItemRect.Right - 32, SubItemRect.Top, 16, SubItemRect.Height); + if(CancelRect.Contains(Args.Location)) + { + CancelWorkspaceUpdate(); + } + else if(InfoRect.Contains(Args.Location) && !Splitter.IsLogVisible()) + { + ToggleLogVisibility(); + } + } + else + { + Rectangle HappyRect = new Rectangle(SubItemRect.Right - 32, SubItemRect.Top, 16, SubItemRect.Height); + Rectangle FrownRect = new Rectangle(SubItemRect.Right - 16, SubItemRect.Top, 16, SubItemRect.Height); + if(HappyRect.Contains(Args.Location)) + { + EventMonitor.PostEvent(Change.Number, EventType.Good); + BuildList.Invalidate(); + } + else if(FrownRect.Contains(Args.Location)) + { + EventMonitor.PostEvent(Change.Number, EventType.Bad); + BuildList.Invalidate(); + } + } + } + else + { + Rectangle SyncBadgeRectangle = GetSyncBadgeRectangle(HitTest.Item.SubItems[StatusColumn.Index].Bounds); + if(SyncBadgeRectangle.Contains(Args.Location) && CanSyncChange(Change.Number)) + { + StartSync(Change.Number); + } + } + + if(CISColumn.Index < HitTest.Item.SubItems.Count && HitTest.Item.SubItems[CISColumn.Index] == HitTest.SubItem) + { + EventSummary Summary = EventMonitor.GetSummaryForChange(Change.Number); + if(Summary != null) + { + Tuple[] Badges = LayoutBadges(Summary.Builds, HitTest.SubItem.Bounds); + for(int Idx = 0; Idx < Badges.Length; Idx++) + { + if(Badges[Idx].Item2.Contains(Args.Location)) + { + Process.Start(Badges[Idx].Item1.Url); + break; + } + } + } + } + } + } + else if(Args.Button == MouseButtons.Right) + { + ListViewHitTestInfo HitTest = BuildList.HitTest(Args.Location); + if(HitTest.Item != null && HitTest.Item.Tag != null) + { + ContextMenuChange = (PerforceChangeSummary)HitTest.Item.Tag; + + BuildListContextMenu_WithdrawReview.Visible = (EventMonitor.GetReviewByCurrentUser(ContextMenuChange.Number) != null); + BuildListContextMenu_StartInvestigating.Visible = !EventMonitor.IsUnderInvestigationByCurrentUser(ContextMenuChange.Number); + BuildListContextMenu_FinishInvestigating.Visible = EventMonitor.IsUnderInvestigation(ContextMenuChange.Number); + + string CommentText; + bool bHasExistingComment = EventMonitor.GetCommentByCurrentUser(ContextMenuChange.Number, out CommentText); + BuildListContextMenu_LeaveComment.Visible = !bHasExistingComment; + BuildListContextMenu_EditComment.Visible = bHasExistingComment; + + bool bIsBusy = Workspace.IsBusy(); + bool bIsCurrentChange = (ContextMenuChange.Number == Workspace.CurrentChangeNumber); + BuildListContextMenu_Sync.Visible = !bIsBusy; + BuildListContextMenu_Sync.Font = new Font(SystemFonts.MenuFont, bIsCurrentChange? FontStyle.Regular : FontStyle.Bold); + BuildListContextMenu_SyncContentOnly.Visible = !bIsBusy && ShouldSyncPrecompiledEditor; + BuildListContextMenu_SyncOnlyThisChange.Visible = !bIsBusy && !bIsCurrentChange && ContextMenuChange.Number > Workspace.CurrentChangeNumber && Workspace.CurrentChangeNumber != -1; + BuildListContextMenu_Build.Visible = !bIsBusy && bIsCurrentChange && !ShouldSyncPrecompiledEditor && Settings.bUseIncrementalBuilds; + BuildListContextMenu_Rebuild.Visible = !bIsBusy && bIsCurrentChange && !ShouldSyncPrecompiledEditor; + BuildListContextMenu_GenerateProjectFiles.Visible = !bIsBusy && bIsCurrentChange; + BuildListContextMenu_LaunchEditor.Visible = !bIsBusy && ContextMenuChange.Number == Workspace.CurrentChangeNumber; + BuildListContextMenu_LaunchEditor.Font = new Font(SystemFonts.MenuFont, FontStyle.Bold); + BuildListContextMenu_OpenVisualStudio.Visible = !bIsBusy && bIsCurrentChange; + BuildListContextMenu_Cancel.Visible = bIsBusy; + + EventSummary Summary = EventMonitor.GetSummaryForChange(ContextMenuChange.Number); + bool bStarred = (Summary != null && Summary.LastStarReview != null && Summary.LastStarReview.Type == EventType.Starred); + BuildListContextMenu_AddStar.Visible = !bStarred; + BuildListContextMenu_RemoveStar.Visible = bStarred; + + bool bIsTimeColumn = (HitTest.Item.SubItems.IndexOf(HitTest.SubItem) == TimeColumn.Index); + BuildListContextMenu_TimeZoneSeparator.Visible = bIsTimeColumn; + BuildListContextMenu_ShowLocalTimes.Visible = bIsTimeColumn; + BuildListContextMenu_ShowLocalTimes.Checked = Settings.bShowLocalTimes; + BuildListContextMenu_ShowServerTimes.Visible = bIsTimeColumn; + BuildListContextMenu_ShowServerTimes.Checked = !Settings.bShowLocalTimes; + + BuildListContextMenu.Show(BuildList, Args.Location); + } + } + } + + private void BuildList_MouseMove(object sender, MouseEventArgs e) + { + ListViewHitTestInfo HitTest = BuildList.HitTest(e.Location); + int HitTestIndex = (HitTest.Item == null)? -1 : HitTest.Item.Index; + if(HitTestIndex != HoverItem) + { + if(HoverItem != -1) + { + BuildList.RedrawItems(HoverItem, HoverItem, true); + } + HoverItem = HitTestIndex; + if(HoverItem != -1) + { + BuildList.RedrawItems(HoverItem, HoverItem, true); + } + } + + BuildData NewHoverBadge = null; + if(HitTest.Item != null && HitTest.Item.SubItems.IndexOf(HitTest.SubItem) == CISColumn.Index) + { + EventSummary Summary = EventMonitor.GetSummaryForChange(((PerforceChangeSummary)HitTest.Item.Tag).Number); + if(Summary != null) + { + foreach(Tuple Badge in LayoutBadges(Summary.Builds, HitTest.SubItem.Bounds)) + { + if(Badge.Item2.Contains(e.Location)) + { + NewHoverBadge = Badge.Item1; + break; + } + } + } + } + if(NewHoverBadge != HoverBadge) + { + HoverBadge = NewHoverBadge; + BuildList.Invalidate(); + } + + bool bNewHoverSync = false; + if(HitTest.Item != null) + { + bNewHoverSync = GetSyncBadgeRectangle(HitTest.Item.SubItems[StatusColumn.Index].Bounds).Contains(e.Location); + } + if(bNewHoverSync != bHoverSync) + { + bHoverSync = bNewHoverSync; + BuildList.Invalidate(); + } + } + + private void OptionsButton_Click(object sender, EventArgs e) + { + OptionsContextMenu_AutoResolveConflicts.Checked = Settings.bAutoResolveConflicts; + OptionsContextMenu_SyncPrecompiledEditor.Visible = PerforceMonitor != null && PerforceMonitor.HasZippedBinaries; + OptionsContextMenu_SyncPrecompiledEditor.Checked = Settings.bSyncPrecompiledEditor; + OptionsContextMenu_EditorBuildConfiguration.Enabled = !ShouldSyncPrecompiledEditor; + OptionsContextMenu_UseIncrementalBuilds.Enabled = !ShouldSyncPrecompiledEditor; + OptionsContextMenu_UseIncrementalBuilds.Checked = Settings.bUseIncrementalBuilds; + OptionsContextMenu_CustomizeBuildSteps.Enabled = (Workspace != null); + OptionsContextMenu_EditorArguments.Checked = Settings.EditorArguments.Any(x => x.Item2); + OptionsContextMenu_ScheduledSync.Checked = Settings.bScheduleEnabled; + OptionsContextMenu_TimeZone_Local.Checked = Settings.bShowLocalTimes; + OptionsContextMenu_TimeZone_PerforceServer.Checked = !Settings.bShowLocalTimes; + OptionsContextMenu_AutomaticallyRunAtStartup.Checked = IsAutomaticallyRunAtStartup(); + OptionsContextMenu_KeepInTray.Checked = Settings.bKeepInTray; + OptionsContextMenu_TabNames_Stream.Checked = Settings.TabLabels == TabLabels.Stream; + OptionsContextMenu_TabNames_WorkspaceName.Checked = Settings.TabLabels == TabLabels.WorkspaceName; + OptionsContextMenu_TabNames_WorkspaceRoot.Checked = Settings.TabLabels == TabLabels.WorkspaceRoot; + OptionsContextMenu_TabNames_ProjectFile.Checked = Settings.TabLabels == TabLabels.ProjectFile; + OptionsContextMenu.Show(OptionsButton, new Point(OptionsButton.Width - OptionsContextMenu.Size.Width, OptionsButton.Height)); + } + + private void BuildAfterSyncCheckBox_CheckedChanged(object sender, EventArgs e) + { + Settings.bBuildAfterSync = BuildAfterSyncCheckBox.Checked; + Settings.Save(); + + UpdateSyncActionCheckboxes(); + } + + private void RunAfterSyncCheckBox_CheckedChanged(object sender, EventArgs e) + { + Settings.bRunAfterSync = RunAfterSyncCheckBox.Checked; + Settings.Save(); + + UpdateSyncActionCheckboxes(); + } + + private void OpenSolutionAfterSyncCheckBox_CheckedChanged(object sender, EventArgs e) + { + Settings.bOpenSolutionAfterSync = OpenSolutionAfterSyncCheckBox.Checked; + Settings.Save(); + + UpdateSyncActionCheckboxes(); + } + + private void UpdateSyncActionCheckboxes() + { + BuildAfterSyncCheckBox.Checked = Settings.bBuildAfterSync; + RunAfterSyncCheckBox.Checked = Settings.bRunAfterSync; + OpenSolutionAfterSyncCheckBox.Checked = Settings.bOpenSolutionAfterSync; + + if(Workspace == null || Workspace.IsBusy()) + { + AfterSyncingLabel.Enabled = false; + BuildAfterSyncCheckBox.Enabled = false; + RunAfterSyncCheckBox.Enabled = false; + OpenSolutionAfterSyncCheckBox.Enabled = false; + } + else + { + AfterSyncingLabel.Enabled = true; + BuildAfterSyncCheckBox.Enabled = bHasBuildSteps; + RunAfterSyncCheckBox.Enabled = BuildAfterSyncCheckBox.Checked; + OpenSolutionAfterSyncCheckBox.Enabled = true; + } + } + + private void BuildList_FontChanged(object sender, EventArgs e) + { + if(BuildFont != null) + { + BuildFont.Dispose(); + } + BuildFont = BuildList.Font; + + if(SelectedBuildFont != null) + { + SelectedBuildFont.Dispose(); + } + SelectedBuildFont = new Font(BuildFont, FontStyle.Bold); + + if(BadgeFont != null) + { + BadgeFont.Dispose(); + } + BadgeFont = new Font(BuildFont.FontFamily, BuildFont.SizeInPoints - 2, FontStyle.Bold); + } + + public void SyncLatestChange() + { + if(Workspace != null) + { + int ChangeNumber; + if(!FindChangeToSync(Settings.SyncType, out ChangeNumber)) + { + ShowErrorDialog(String.Format("Couldn't find any {0}changelist. Double-click on the change you want to sync manually.", (Settings.SyncType == LatestChangeType.Starred)? "starred " : (Settings.SyncType == LatestChangeType.Good)? "good " : "")); + } + else if(ChangeNumber < Workspace.CurrentChangeNumber) + { + ShowErrorDialog("Workspace is already synced to a later change ({0} vs {1}).", Workspace.CurrentChangeNumber, ChangeNumber); + } + else if(ChangeNumber >= PerforceMonitor.LastChangeByCurrentUser || MessageBox.Show(String.Format("The changelist that would be synced is before the last change you submitted.\n\nIf you continue, your changes submitted after CL {0} will be locally removed from your workspace until you can sync past them again.\n\nAre you sure you want to continue?", ChangeNumber), "Local changes will be removed", MessageBoxButtons.YesNo) == DialogResult.Yes) + { + Owner.ShowAndActivate(); + SelectChange(ChangeNumber); + StartSync(ChangeNumber); + } + } + } + + private void BuildListContextMenu_MarkGood_Click(object sender, EventArgs e) + { + EventMonitor.PostEvent(ContextMenuChange.Number, EventType.Good); + } + + private void BuildListContextMenu_MarkBad_Click(object sender, EventArgs e) + { + EventMonitor.PostEvent(ContextMenuChange.Number, EventType.Bad); + } + + private void BuildListContextMenu_WithdrawReview_Click(object sender, EventArgs e) + { + EventMonitor.PostEvent(ContextMenuChange.Number, EventType.Unknown); + } + + private void BuildListContextMenu_Sync_Click(object sender, EventArgs e) + { + StartSync(ContextMenuChange.Number); + } + + private void BuildListContextMenu_SyncContentOnly_Click(object sender, EventArgs e) + { + StartWorkspaceUpdate(ContextMenuChange.Number, WorkspaceUpdateOptions.Sync | WorkspaceUpdateOptions.ContentOnly); + } + + private void BuildListContextMenu_SyncOnlyThisChange_Click(object sender, EventArgs e) + { + StartWorkspaceUpdate(ContextMenuChange.Number, WorkspaceUpdateOptions.SyncSingleChange); + } + + private void BuildListContextMenu_Build_Click(object sender, EventArgs e) + { + StartWorkspaceUpdate(Workspace.CurrentChangeNumber, WorkspaceUpdateOptions.SyncArchives | WorkspaceUpdateOptions.Build | WorkspaceUpdateOptions.UseIncrementalBuilds); + } + + private void BuildListContextMenu_Rebuild_Click(object sender, EventArgs e) + { + StartWorkspaceUpdate(Workspace.CurrentChangeNumber, WorkspaceUpdateOptions.SyncArchives | WorkspaceUpdateOptions.Build); + } + + private void BuildListContextMenu_GenerateProjectFiles_Click(object sender, EventArgs e) + { + StartWorkspaceUpdate(Workspace.CurrentChangeNumber, WorkspaceUpdateOptions.GenerateProjectFiles); + } + + private void BuildListContextMenu_CancelSync_Click(object sender, EventArgs e) + { + CancelWorkspaceUpdate(); + } + + private void BuildListContextMenu_MoreInfo_Click(object sender, EventArgs e) + { + if(!Utility.SpawnHiddenProcess("p4vc.exe", String.Format("-c{0} change {1}", Workspace.ClientName, ContextMenuChange.Number))) + { + MessageBox.Show("Unable to spawn p4vc. Check you have P4V installed."); + } + } + + private void BuildListContextMenu_AddStar_Click(object sender, EventArgs e) + { + if(MessageBox.Show("Starred builds are meant to convey a stable, verified build to the rest of the team. Do not star a build unless it has been fully tested.\n\nAre you sure you want to star this build?", "Confirm star", MessageBoxButtons.YesNo) == DialogResult.Yes) + { + EventMonitor.PostEvent(ContextMenuChange.Number, EventType.Starred); + } + } + + private void BuildListContextMenu_RemoveStar_Click(object sender, EventArgs e) + { + EventSummary Summary = EventMonitor.GetSummaryForChange(ContextMenuChange.Number); + if(Summary != null && Summary.LastStarReview != null && Summary.LastStarReview.Type == EventType.Starred) + { + string Message = String.Format("This change was starred by {0}. Are you sure you want to remove it?", FormatUserName(Summary.LastStarReview.UserName)); + if(MessageBox.Show(Message, "Confirm removing star", MessageBoxButtons.YesNo) == DialogResult.Yes) + { + EventMonitor.PostEvent(ContextMenuChange.Number, EventType.Unstarred); + } + } + } + + private void BuildListContextMenu_LaunchEditor_Click(object sender, EventArgs e) + { + LaunchEditor(); + } + + private void BuildListContextMenu_StartInvestigating_Click(object sender, EventArgs e) + { + string Message = String.Format("All changes from {0} onwards will be marked as bad while you are investigating an issue.\n\nAre you sure you want to continue?", ContextMenuChange.Number); + if(MessageBox.Show(Message, "Confirm investigating", MessageBoxButtons.YesNo) == DialogResult.Yes) + { + EventMonitor.StartInvestigating(ContextMenuChange.Number); + } + } + + private void BuildListContextMenu_FinishInvestigating_Click(object sender, EventArgs e) + { + int StartChangeNumber = EventMonitor.GetInvestigationStartChangeNumber(ContextMenuChange.Number); + if(StartChangeNumber != -1) + { + if(ContextMenuChange.Number > StartChangeNumber) + { + string Message = String.Format("Mark all changes between {0} and {1} as bad?", StartChangeNumber, ContextMenuChange.Number); + if(MessageBox.Show(Message, "Finish investigating", MessageBoxButtons.YesNo) == DialogResult.Yes) + { + foreach(PerforceChangeSummary Change in PerforceMonitor.GetChanges()) + { + if (Change.Number >= StartChangeNumber && Change.Number < ContextMenuChange.Number) + { + EventMonitor.PostEvent(Change.Number, EventType.Bad); + } + } + } + } + EventMonitor.FinishInvestigating(ContextMenuChange.Number); + } + } + + private void OnlyShowReviewedCheckBox_CheckedChanged(object sender, EventArgs e) + { + UpdateBuildList(); + UpdateNumRequestedBuilds(true); + } + + public void Activate() + { + UpdateSyncActionCheckboxes(); + + if(PerforceMonitor != null) + { + PerforceMonitor.Refresh(); + } + + if(DesiredTaskbarState.Item1 == TaskbarState.Error) + { + DesiredTaskbarState = Tuple.Create(TaskbarState.NoProgress, 0.0f); + Owner.UpdateProgress(); + } + } + + public void Deactivate() + { + UpdateNumRequestedBuilds(true); + } + + private void BuildList_ItemMouseHover(object sender, ListViewItemMouseHoverEventArgs Args) + { + Point ClientPoint = BuildList.PointToClient(Cursor.Position); + if(Args.Item.SubItems.Count >= 6) + { + if(Args.Item.Bounds.Contains(ClientPoint)) + { + PerforceChangeSummary Change = (PerforceChangeSummary)Args.Item.Tag; + + Rectangle DescriptionBounds = Args.Item.SubItems[DescriptionColumn.Index].Bounds; + if(DescriptionBounds.Contains(ClientPoint)) + { + BuildListToolTip.Show(Change.Description, BuildList, new Point(DescriptionBounds.Left, DescriptionBounds.Bottom)); + return; + } + + EventSummary Summary = EventMonitor.GetSummaryForChange(Change.Number); + if(Summary != null) + { + StringBuilder SummaryText = new StringBuilder(); + if(Summary.Comments.Count > 0) + { + foreach(CommentData Comment in Summary.Comments) + { + if(!String.IsNullOrWhiteSpace(Comment.Text)) + { + SummaryText.AppendFormat("{0}: \"{1}\"\n", FormatUserName(Comment.UserName), Comment.Text); + } + } + if(SummaryText.Length > 0) + { + SummaryText.Append("\n"); + } + } + AppendUserList(SummaryText, "\n", "Compiled by {0}.", Summary.Reviews.Where(x => x.Type == EventType.Compiles)); + AppendUserList(SummaryText, "\n", "Failed to compile for {0}.", Summary.Reviews.Where(x => x.Type == EventType.DoesNotCompile)); + AppendUserList(SummaryText, "\n", "Marked good by {0}.", Summary.Reviews.Where(x => x.Type == EventType.Good)); + AppendUserList(SummaryText, "\n", "Marked bad by {0}.", Summary.Reviews.Where(x => x.Type == EventType.Bad)); + if(Summary.LastStarReview != null) + { + AppendUserList(SummaryText, "\n", "Starred by {0}.", new EventData[]{ Summary.LastStarReview }); + } + if(SummaryText.Length > 0) + { + Rectangle SummaryBounds = Args.Item.SubItems[StatusColumn.Index].Bounds; + BuildListToolTip.Show(SummaryText.ToString(), BuildList, new Point(SummaryBounds.Left, SummaryBounds.Bottom)); + return; + } + } + } + } + + BuildListToolTip.Hide(BuildList); + } + + private void BuildList_MouseLeave(object sender, EventArgs e) + { + BuildListToolTip.Hide(BuildList); + + if(HoverItem != -1) + { + HoverItem = -1; + BuildList.Invalidate(); + } + + if(HoverBadge != null) + { + HoverBadge = null; + BuildList.Invalidate(); + } + } + + private void OptionsContextMenu_ShowLog_Click(object sender, EventArgs e) + { + ToggleLogVisibility(); + } + + private void ToggleLogVisibility() + { + Splitter.SetLogVisibility(!Splitter.IsLogVisible()); + } + + private void Splitter_OnVisibilityChanged(bool bVisible) + { + Settings.bShowLogWindow = bVisible; + Settings.Save(); + + UpdateStatusPanel(); + } + + private void OptionsContextMenu_AutoResolveConflicts_Click(object sender, EventArgs e) + { + OptionsContextMenu_AutoResolveConflicts.Checked ^= true; + Settings.bAutoResolveConflicts = OptionsContextMenu_AutoResolveConflicts.Checked; + Settings.Save(); + } + + private void OptionsContextMenu_EditorArguments_Click(object sender, EventArgs e) + { + ArgumentsWindow Arguments = new ArgumentsWindow(Settings.EditorArguments); + if(Arguments.ShowDialog(this) == DialogResult.OK) + { + Settings.EditorArguments = Arguments.GetItems(); + Settings.Save(); + } + } + + private void BuildListContextMenu_OpenVisualStudio_Click(object sender, EventArgs e) + { + OpenSolution(); + } + + private void OpenSolution() + { + string SolutionFileName = Path.Combine(BranchDirectoryName, "UE4.sln"); + if(!File.Exists(SolutionFileName)) + { + MessageBox.Show(String.Format("Couldn't find solution at {0}", SolutionFileName)); + } + else + { + ProcessStartInfo StartInfo = new ProcessStartInfo(SolutionFileName); + StartInfo.WorkingDirectory = BranchDirectoryName; + Process.Start(StartInfo); + } + } + + private void OptionsContextMenu_BuildConfig_Debug_Click(object sender, EventArgs e) + { + UpdateBuildConfig(BuildConfig.Debug); + } + + private void OptionsContextMenu_BuildConfig_DebugGame_Click(object sender, EventArgs e) + { + UpdateBuildConfig(BuildConfig.DebugGame); + } + + private void OptionsContextMenu_BuildConfig_Development_Click(object sender, EventArgs e) + { + UpdateBuildConfig(BuildConfig.Development); + } + + void UpdateBuildConfig(BuildConfig NewConfig) + { + Settings.CompiledEditorBuildConfig = NewConfig; + Settings.Save(); + UpdateCheckedBuildConfig(); + } + + void UpdateCheckedBuildConfig() + { + BuildConfig EditorBuildConfig = GetEditorBuildConfig(); + + OptionsContextMenu_BuildConfig_Debug.Checked = (EditorBuildConfig == BuildConfig.Debug); + OptionsContextMenu_BuildConfig_Debug.Enabled = (!ShouldSyncPrecompiledEditor || EditorBuildConfig == BuildConfig.Debug); + + OptionsContextMenu_BuildConfig_DebugGame.Checked = (EditorBuildConfig == BuildConfig.DebugGame); + OptionsContextMenu_BuildConfig_DebugGame.Enabled = (!ShouldSyncPrecompiledEditor || EditorBuildConfig == BuildConfig.DebugGame); + + OptionsContextMenu_BuildConfig_Development.Checked = (EditorBuildConfig == BuildConfig.Development); + OptionsContextMenu_BuildConfig_Development.Enabled = (!ShouldSyncPrecompiledEditor || EditorBuildConfig == BuildConfig.Development); + } + + private void OptionsContextMenu_UseIncrementalBuilds_Click(object sender, EventArgs e) + { + OptionsContextMenu_UseIncrementalBuilds.Checked ^= true; + Settings.bUseIncrementalBuilds = OptionsContextMenu_UseIncrementalBuilds.Checked; + Settings.Save(); + } + + private void OptionsContextMenu_ScheduleSync_Click(object sender, EventArgs e) + { + Owner.SetupScheduledSync(); + } + + public void ScheduleTimerElapsed() + { + if(Settings.bScheduleEnabled) + { + Log.WriteLine("Scheduled sync at {0} for {1}.", DateTime.Now, Settings.ScheduleChange); + + int ChangeNumber; + if(!FindChangeToSync(Settings.ScheduleChange, out ChangeNumber)) + { + Log.WriteLine("Couldn't find any matching change"); + } + else if(Workspace.CurrentChangeNumber >= ChangeNumber) + { + Log.WriteLine("Sync ignored; already at or ahead of CL ({0} >= {1})", Workspace.CurrentChangeNumber, ChangeNumber); + } + else + { + WorkspaceUpdateOptions Options = WorkspaceUpdateOptions.Sync | WorkspaceUpdateOptions.SyncArchives | WorkspaceUpdateOptions.GenerateProjectFiles | WorkspaceUpdateOptions.Build | WorkspaceUpdateOptions.ScheduledBuild; + if(Settings.bAutoResolveConflicts) + { + Options |= WorkspaceUpdateOptions.AutoResolveChanges; + } + if(Settings.bBuildAfterSync && Settings.bRunAfterSync) + { + Options |= WorkspaceUpdateOptions.RunAfterSync; + } + StartWorkspaceUpdate(ChangeNumber, Options); + } + } + } + + bool FindChangeToSync(LatestChangeType ChangeType, out int ChangeNumber) + { + for(int Idx = 0; Idx < BuildList.Items.Count; Idx++) + { + PerforceChangeSummary Change = (PerforceChangeSummary)BuildList.Items[Idx].Tag; + if(ChangeType == LatestChangeType.Any) + { + if(CanSyncChange(Change.Number)) + { + ChangeNumber = FindNewestGoodContentChange(Change.Number); + return true; + } + } + else if(ChangeType == LatestChangeType.Good) + { + EventSummary Summary = EventMonitor.GetSummaryForChange(Change.Number); + if(Summary != null && Summary.Verdict == ReviewVerdict.Good && CanSyncChange(Change.Number)) + { + ChangeNumber = FindNewestGoodContentChange(Change.Number); + return true; + } + } + else if(ChangeType == LatestChangeType.Starred) + { + EventSummary Summary = EventMonitor.GetSummaryForChange(Change.Number); + if(((Summary != null && Summary.LastStarReview != null) || PromotedChangeNumbers.Contains(Change.Number)) && CanSyncChange(Change.Number)) + { + ChangeNumber = FindNewestGoodContentChange(Change.Number); + return true; + } + } + } + + ChangeNumber = -1; + return false; + } + + int FindNewestGoodContentChange(int ChangeNumber) + { + int Index = SortedChangeNumbers.BinarySearch(ChangeNumber); + if(Index <= 0) + { + return ChangeNumber; + } + + for(int NextIndex = Index + 1; NextIndex < SortedChangeNumbers.Count; NextIndex++) + { + int NextChangeNumber = SortedChangeNumbers[NextIndex]; + + PerforceChangeType Type; + if(!PerforceMonitor.TryGetChangeType(NextChangeNumber, out Type) || Type != PerforceChangeType.Content) + { + break; + } + + EventSummary Summary = EventMonitor.GetSummaryForChange(NextChangeNumber); + if(Summary != null && Summary.Verdict == ReviewVerdict.Bad) + { + break; + } + + Index = NextIndex; + } + + return SortedChangeNumbers[Index]; + } + + private void BuildListContextMenu_LeaveOrEditComment_Click(object sender, EventArgs e) + { + if(ContextMenuChange != null) + { + LeaveCommentWindow LeaveComment = new LeaveCommentWindow(); + + string CommentText; + if(EventMonitor.GetCommentByCurrentUser(ContextMenuChange.Number, out CommentText)) + { + LeaveComment.CommentTextBox.Text = CommentText; + } + + if(LeaveComment.ShowDialog() == System.Windows.Forms.DialogResult.OK) + { + EventMonitor.PostComment(ContextMenuChange.Number, LeaveComment.CommentTextBox.Text); + } + } + } + + private void BuildListContextMenu_ShowServerTimes_Click(object sender, EventArgs e) + { + Settings.bShowLocalTimes = false; + Settings.Save(); + UpdateBuildList(); + } + + private void BuildListContextMenu_ShowLocalTimes_Click(object sender, EventArgs e) + { + Settings.bShowLocalTimes = true; + Settings.Save(); + UpdateBuildList(); + } + + private void MoreToolsContextMenu_CleanWorkspace_Click(object sender, EventArgs e) + { + CleanWorkspaceWindow.DoClean(ParentForm, Workspace.Perforce, BranchDirectoryName, Workspace.ClientRootPath, Workspace.SyncPaths, Log); + } + + private void UpdateBuildSteps() + { + bHasBuildSteps = false; + + foreach(ToolStripMenuItem CustomToolMenuItem in CustomToolMenuItems) + { + MoreToolsContextMenu.Items.Remove(CustomToolMenuItem); + } + + CustomToolMenuItems.Clear(); + + if(Workspace != null) + { + ConfigFile ProjectConfigFile = Workspace.ProjectConfigFile; + if(ProjectConfigFile != null) + { + Dictionary ProjectBuildStepObjects = GetProjectBuildStepObjects(ProjectConfigFile); + + int InsertIdx = 0; + + List UserSteps = GetUserBuildSteps(ProjectBuildStepObjects); + foreach(BuildStep Step in UserSteps) + { + if(Step.bShowAsTool) + { + ToolStripMenuItem NewMenuItem = new ToolStripMenuItem(Step.Description); + NewMenuItem.Click += new EventHandler((sender, e) => { RunCustomTool(Step.UniqueId); }); + CustomToolMenuItems.Add(NewMenuItem); + MoreToolsContextMenu.Items.Insert(InsertIdx++, NewMenuItem); + } + bHasBuildSteps |= Step.bNormalSync; + } + } + } + + MoreActionsContextMenu_CustomToolSeparator.Visible = (CustomToolMenuItems.Count > 0); + } + + private void RunCustomTool(Guid UniqueId) + { + if(Workspace != null) + { + if(Workspace.IsBusy()) + { + MessageBox.Show("Please retry after the current sync has finished.", "Sync in Progress"); + } + else + { + WorkspaceUpdateContext Context = new WorkspaceUpdateContext(Workspace.CurrentChangeNumber, WorkspaceUpdateOptions.Build, null, GetDefaultBuildStepObjects(), ProjectSettings.BuildSteps, new HashSet{ UniqueId }, GetWorkspaceVariables()); + StartWorkspaceUpdate(Context); + } + } + } + + private Dictionary GetWorkspaceVariables() + { + BuildConfig EditorBuildConfig = GetEditorBuildConfig(); + + Dictionary Variables = new Dictionary(); + Variables.Add("BranchDir", BranchDirectoryName); + Variables.Add("ProjectDir", Path.GetDirectoryName(SelectedFileName)); + Variables.Add("ProjectFile", SelectedFileName); + Variables.Add("UE4EditorExe", GetEditorExePath(EditorBuildConfig)); + Variables.Add("UE4EditorCmdExe", GetEditorExePath(EditorBuildConfig).Replace(".exe", "-Cmd.exe")); + Variables.Add("UE4EditorConfig", EditorBuildConfig.ToString()); + Variables.Add("UE4EditorDebugArg", (EditorBuildConfig == BuildConfig.Debug || EditorBuildConfig == BuildConfig.DebugGame)? " -debug" : ""); + return Variables; + } + + private void OptionsContextMenu_EditBuildSteps_Click(object sender, EventArgs e) + { + ConfigFile ProjectConfigFile = Workspace.ProjectConfigFile; + if(Workspace != null && ProjectConfigFile != null) + { + // Find all the target names for this project + List TargetNames = new List(); + if(!String.IsNullOrEmpty(SelectedFileName) && SelectedFileName.EndsWith(".uproject", StringComparison.InvariantCultureIgnoreCase)) + { + DirectoryInfo SourceDirectory = new DirectoryInfo(Path.Combine(Path.GetDirectoryName(SelectedFileName), "Source")); + if(SourceDirectory.Exists) + { + foreach(FileInfo TargetFile in SourceDirectory.EnumerateFiles("*.target.cs", SearchOption.TopDirectoryOnly)) + { + TargetNames.Add(TargetFile.Name.Substring(0, TargetFile.Name.IndexOf('.'))); + } + } + } + + // Get all the task objects + Dictionary ProjectBuildStepObjects = GetProjectBuildStepObjects(ProjectConfigFile); + List UserSteps = GetUserBuildSteps(ProjectBuildStepObjects); + + // Show the dialog + ModifyBuildStepsWindow EditStepsWindow = new ModifyBuildStepsWindow(TargetNames, UserSteps, new HashSet(ProjectBuildStepObjects.Keys), BranchDirectoryName, GetWorkspaceVariables()); + EditStepsWindow.ShowDialog(); + + // Update the user settings + List ModifiedBuildSteps = new List(); + foreach(BuildStep Step in UserSteps) + { + ConfigObject DefaultObject; + ProjectBuildStepObjects.TryGetValue(Step.UniqueId, out DefaultObject); + + ConfigObject UserConfigObject = Step.ToConfigObject(DefaultObject); + if(UserConfigObject != null) + { + ModifiedBuildSteps.Add(UserConfigObject); + } + } + + // Save the settings + ProjectSettings.BuildSteps = ModifiedBuildSteps; + Settings.Save(); + + // Update the custom tools menu, because we might have changed it + UpdateBuildSteps(); + UpdateSyncActionCheckboxes(); + } + } + + private void AddOrUpdateBuildStep(Dictionary Steps, ConfigObject Object) + { + Guid UniqueId; + if(Guid.TryParse(Object.GetValue(BuildStep.UniqueIdKey, ""), out UniqueId)) + { + ConfigObject DefaultObject; + if(Steps.TryGetValue(UniqueId, out DefaultObject)) + { + Object.SetDefaults(DefaultObject); + } + Steps[UniqueId] = Object; + } + } + + private bool ShouldSyncPrecompiledEditor + { + get { return Settings.bSyncPrecompiledEditor && PerforceMonitor != null && PerforceMonitor.HasZippedBinaries; } + } + + public BuildConfig GetEditorBuildConfig() + { + return ShouldSyncPrecompiledEditor? BuildConfig.Development : Settings.CompiledEditorBuildConfig; + } + + private Dictionary GetDefaultBuildStepObjects() + { + List DefaultBuildSteps = new List(); + DefaultBuildSteps.Add(new BuildStep(new Guid("{01F66060-73FA-4CC8-9CB3-E217FBBA954E}"), 0, "Compile UnrealHeaderTool", "Compiling UnrealHeaderTool...", 1, "UnrealHeaderTool", "Win64", "Development", "", !ShouldSyncPrecompiledEditor)); + string ActualEditorTargetName = EditorTargetName ?? "UE4Editor"; + DefaultBuildSteps.Add(new BuildStep(new Guid("{F097FF61-C916-4058-8391-35B46C3173D5}"), 1, String.Format("Compile {0}", ActualEditorTargetName), String.Format("Compiling {0}...", ActualEditorTargetName), 10, ActualEditorTargetName, "Win64", Settings.CompiledEditorBuildConfig.ToString(), "", !ShouldSyncPrecompiledEditor)); + DefaultBuildSteps.Add(new BuildStep(new Guid("{C6E633A1-956F-4AD3-BC95-6D06D131E7B4}"), 2, "Compile ShaderCompileWorker", "Compiling ShaderCompileWorker...", 1, "ShaderCompileWorker", "Win64", "Development", "", !ShouldSyncPrecompiledEditor)); + DefaultBuildSteps.Add(new BuildStep(new Guid("{24FFD88C-7901-4899-9696-AE1066B4B6E8}"), 3, "Compile UnrealLightmass", "Compiling UnrealLightmass...", 1, "UnrealLightmass", "Win64", "Development", "", !ShouldSyncPrecompiledEditor)); + DefaultBuildSteps.Add(new BuildStep(new Guid("{FFF20379-06BF-4205-8A3E-C53427736688}"), 4, "Compile CrashReportClient", "Compiling CrashReportClient...", 1, "CrashReportClient", "Win64", "Shipping", "", !ShouldSyncPrecompiledEditor)); + return DefaultBuildSteps.ToDictionary(x => x.UniqueId, x => x.ToConfigObject()); + } + + private Dictionary GetProjectBuildStepObjects(ConfigFile ProjectConfigFile) + { + Dictionary ProjectBuildSteps = GetDefaultBuildStepObjects(); + foreach(string Line in ProjectConfigFile.GetValues("Build.Step", new string[0])) + { + AddOrUpdateBuildStep(ProjectBuildSteps, new ConfigObject(Line)); + } + return ProjectBuildSteps; + } + + private List GetUserBuildSteps(Dictionary ProjectBuildStepObjects) + { + // Read all the user-defined build tasks and modifications to the default list + Dictionary UserBuildStepObjects = ProjectBuildStepObjects.ToDictionary(x => x.Key, y => new ConfigObject(y.Value)); + foreach(ConfigObject UserBuildStep in ProjectSettings.BuildSteps) + { + AddOrUpdateBuildStep(UserBuildStepObjects, UserBuildStep); + } + + // Create the expanded task objects + return UserBuildStepObjects.Values.Select(x => new BuildStep(x)).OrderBy(x => x.OrderIndex).ToList(); + } + + private void OptionsContextMenu_AutomaticallyRunAtStartup_Click(object sender, EventArgs e) + { + RegistryKey Key = Registry.CurrentUser.CreateSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"); + if(IsAutomaticallyRunAtStartup()) + { + Key.DeleteValue("UnrealGameSync", false); + } + else + { + Key.SetValue("UnrealGameSync", OriginalExecutableFileName); + } + } + + private bool IsAutomaticallyRunAtStartup() + { + RegistryKey Key = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"); + return (Key.GetValue("UnrealGameSync") != null); + } + + private void OptionsContextMenu_SyncPrecompiledEditor_Click(object sender, EventArgs e) + { + OptionsContextMenu_SyncPrecompiledEditor.Checked ^= true; + + Settings.bSyncPrecompiledEditor = OptionsContextMenu_SyncPrecompiledEditor.Checked; + Settings.Save(); + + UpdateBuildSteps(); + UpdateSyncActionCheckboxes(); + + BuildList.Invalidate(); + } + + private void BuildList_SelectedIndexChanged(object sender, EventArgs e) + { + PendingSelectedChangeNumber = -1; + } + + private void OptionsContextMenu_Diagnostics_Click(object sender, EventArgs e) + { + StringBuilder DiagnosticsText = new StringBuilder(); + DiagnosticsText.AppendFormat("Application version: {0}\n", Assembly.GetExecutingAssembly().GetName().Version); + DiagnosticsText.AppendFormat("Synced from: {0}\n", Program.SyncVersion ?? "(unknown)"); + DiagnosticsText.AppendFormat("Selected file: {0}\n", (SelectedFileName == null)? "(none)" : SelectedFileName); + if(Workspace != null) + { + DiagnosticsText.AppendFormat("P4 server: {0}\n", Workspace.Perforce.ServerAndPort ?? "(default)"); + DiagnosticsText.AppendFormat("P4 user: {0}\n", Workspace.Perforce.UserName); + DiagnosticsText.AppendFormat("P4 workspace: {0}\n", Workspace.Perforce.ClientName); + } + DiagnosticsText.AppendFormat("Perforce monitor: {0}\n", (PerforceMonitor == null)? "(inactive)" : PerforceMonitor.LastStatusMessage); + DiagnosticsText.AppendFormat("Event monitor: {0}\n", (EventMonitor == null)? "(inactive)" : EventMonitor.LastStatusMessage); + + DiagnosticsWindow Diagnostics = new DiagnosticsWindow(DataFolder, DiagnosticsText.ToString()); + Diagnostics.ShowDialog(this); + } + + private void OptionsContextMenu_SyncFilter_Click(object sender, EventArgs e) + { + SyncFilter Filter = new SyncFilter(Settings.SyncFilter, WorkspaceSettings.SyncFilter); + if(Filter.ShowDialog() == DialogResult.OK) + { + Settings.SyncFilter = Filter.GlobalFilter; + WorkspaceSettings.SyncFilter = Filter.WorkspaceFilter; + Settings.Save(); + } + } + + private void ShowSyncMenu(Rectangle Bounds) + { + SyncContextMenu_LatestChange.Checked = (Settings.SyncType == LatestChangeType.Any); + SyncContextMenu_LatestGoodChange.Checked = (Settings.SyncType == LatestChangeType.Good); + SyncContextMenu_LatestStarredChange.Checked = (Settings.SyncType == LatestChangeType.Starred); + SyncContextMenu.Show(StatusPanel, new Point(Bounds.Left, Bounds.Bottom), ToolStripDropDownDirection.BelowRight); + } + + private void SyncContextMenu_LatestChange_Click(object sender, EventArgs e) + { + Settings.SyncType = LatestChangeType.Any; + Settings.Save(); + } + + private void SyncContextMenu_LatestGoodChange_Click(object sender, EventArgs e) + { + Settings.SyncType = LatestChangeType.Good; + Settings.Save(); + } + + private void SyncContextMenu_LatestStarredChange_Click(object sender, EventArgs e) + { + Settings.SyncType = LatestChangeType.Starred; + Settings.Save(); + } + + private void SyncContextMenu_EnterChangelist_Click(object sender, EventArgs e) + { + ChangelistWindow ChildWindow = new ChangelistWindow((Workspace == null)? -1 : Workspace.CurrentChangeNumber); + if(ChildWindow.ShowDialog() == DialogResult.OK) + { + StartSync(ChildWindow.ChangeNumber); + } + } + + private void OptionsContextMenu_KeepInTray_Click(object sender, EventArgs e) + { + Settings.bKeepInTray ^= true; + Settings.Save(); + } + + private void BuildList_KeyDown(object Sender, KeyEventArgs Args) + { + if(Args.Control && Args.KeyCode == Keys.C && BuildList.SelectedItems.Count > 0) + { + int SelectedChange = ((PerforceChangeSummary)BuildList.SelectedItems[0].Tag).Number; + Clipboard.SetText(String.Format("{0}", SelectedChange)); + } + } + + private void OptionsContextMenu_PerforceSettings_Click(object sender, EventArgs e) + { + PerforceSettingsWindow Perforce = new PerforceSettingsWindow(Settings); + Perforce.ShowDialog(); + } + + private void OptionsContextMenu_TabNames_Stream_Click(object sender, EventArgs e) + { + Owner.SetTabNames(TabLabels.Stream); + } + + private void OptionsContextMenu_TabNames_WorkspaceName_Click(object sender, EventArgs e) + { + Owner.SetTabNames(TabLabels.WorkspaceName); + } + + private void OptionsContextMenu_TabNames_WorkspaceRoot_Click(object sender, EventArgs e) + { + Owner.SetTabNames(TabLabels.WorkspaceRoot); + } + + private void OptionsContextMenu_TabNames_ProjectFile_Click(object sender, EventArgs e) + { + Owner.SetTabNames(TabLabels.ProjectFile); + } + } +} diff --git a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Controls/WorkspaceControl.resx b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Controls/WorkspaceControl.resx new file mode 100644 index 000000000000..ea3aa48b331a --- /dev/null +++ b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Controls/WorkspaceControl.resx @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 186, 17 + + + 357, 17 + + + 465, 17 + + + 603, 17 + + + 787, 17 + + + 938, 17 + + \ No newline at end of file diff --git a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Forms/CleanWorkspaceWindow.cs b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Forms/CleanWorkspaceWindow.cs index c4732499dbee..5d31ddfd2ffa 100644 --- a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Forms/CleanWorkspaceWindow.cs +++ b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Forms/CleanWorkspaceWindow.cs @@ -97,14 +97,14 @@ namespace UnrealGameSync InitializeComponent(); } - public static void DoClean(PerforceConnection PerforceClient, string LocalRootPath, string ClientRootPath, IReadOnlyList SyncPaths, TextWriter Log) + public static void DoClean(IWin32Window Owner, PerforceConnection PerforceClient, string LocalRootPath, string ClientRootPath, IReadOnlyList SyncPaths, TextWriter Log) { // Figure out which folders to clean FolderToClean RootFolderToClean = new FolderToClean(new DirectoryInfo(LocalRootPath)); using(FindFoldersToCleanTask QueryWorkspace = new FindFoldersToCleanTask(PerforceClient, RootFolderToClean, ClientRootPath, SyncPaths, Log)) { string ErrorMessage; - if(!ModalTaskWindow.Execute(QueryWorkspace, "Clean Workspace", "Querying files in Perforce, please wait...", out ErrorMessage)) + if(!ModalTaskWindow.Execute(Owner, QueryWorkspace, "Clean Workspace", "Querying files in Perforce, please wait...", out ErrorMessage)) { if(!String.IsNullOrEmpty(ErrorMessage)) { @@ -334,7 +334,7 @@ namespace UnrealGameSync } string ErrorMessage; - if(!ModalTaskWindow.Execute(new DeleteFilesTask(Files, Directories), "Clean Workspace", "Deleting files, please wait...", out ErrorMessage) && !String.IsNullOrEmpty(ErrorMessage)) + if(!ModalTaskWindow.Execute(this, new DeleteFilesTask(Files, Directories), "Clean Workspace", "Deleting files, please wait...", out ErrorMessage) && !String.IsNullOrEmpty(ErrorMessage)) { FailedToDeleteWindow FailedToDelete = new FailedToDeleteWindow(); FailedToDelete.FileList.Text = ErrorMessage; diff --git a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Forms/MainWindow.Designer.cs b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Forms/MainWindow.Designer.cs index 463d9b0f78bd..2fc30906ed31 100644 --- a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Forms/MainWindow.Designer.cs +++ b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Forms/MainWindow.Designer.cs @@ -19,556 +19,33 @@ namespace UnrealGameSync { this.components = new System.ComponentModel.Container(); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainWindow)); - this.label1 = new System.Windows.Forms.Label(); - this.ProjectList = new System.Windows.Forms.ComboBox(); - this.BrowseProject = new System.Windows.Forms.Button(); - this.OptionsContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); - this.OptionsContextMenu_ScheduledSync = new System.Windows.Forms.ToolStripMenuItem(); - this.OptionsContextMenu_SyncPrecompiledEditor = new System.Windows.Forms.ToolStripMenuItem(); - this.OptionsContextMenu_AutoResolveConflicts = new System.Windows.Forms.ToolStripMenuItem(); - this.OptionsContextMenu_SyncFilter = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator(); - this.OptionsContextMenu_EditorBuildConfiguration = new System.Windows.Forms.ToolStripMenuItem(); - this.OptionsContextMenu_BuildConfig_Debug = new System.Windows.Forms.ToolStripMenuItem(); - this.OptionsContextMenu_BuildConfig_DebugGame = new System.Windows.Forms.ToolStripMenuItem(); - this.OptionsContextMenu_BuildConfig_Development = new System.Windows.Forms.ToolStripMenuItem(); - this.OptionsContextMenu_UseIncrementalBuilds = new System.Windows.Forms.ToolStripMenuItem(); - this.OptionsContextMenu_CustomizeBuildSteps = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripSeparator5 = new System.Windows.Forms.ToolStripSeparator(); - this.OptionsContextMenu_EditorArguments = new System.Windows.Forms.ToolStripMenuItem(); - this.OptionsContextMenu_TimeZone = new System.Windows.Forms.ToolStripMenuItem(); - this.OptionsContextMenu_TimeZone_Local = new System.Windows.Forms.ToolStripMenuItem(); - this.OptionsContextMenu_TimeZone_PerforceServer = new System.Windows.Forms.ToolStripMenuItem(); - this.OptionsContextMenu_AutomaticallyRunAtStartup = new System.Windows.Forms.ToolStripMenuItem(); - this.OptionsContextMenu_KeepInTray = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripSeparator6 = new System.Windows.Forms.ToolStripSeparator(); - this.OptionsContextMenu_Diagnostics = new System.Windows.Forms.ToolStripMenuItem(); - this.OnlyShowReviewedCheckBox = new System.Windows.Forms.CheckBox(); - this.RunAfterSyncCheckBox = new System.Windows.Forms.CheckBox(); - this.BuildAfterSyncCheckBox = new System.Windows.Forms.CheckBox(); - this.AfterSyncingLabel = new System.Windows.Forms.Label(); - this.BuildListContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); - this.BuildListContextMenu_LaunchEditor = new System.Windows.Forms.ToolStripMenuItem(); - this.BuildListContextMenu_Sync = new System.Windows.Forms.ToolStripMenuItem(); - this.BuildListContextMenu_SyncContentOnly = new System.Windows.Forms.ToolStripMenuItem(); - this.BuildListContextMenu_SyncOnlyThisChange = new System.Windows.Forms.ToolStripMenuItem(); - this.BuildListContextMenu_Build = new System.Windows.Forms.ToolStripMenuItem(); - this.BuildListContextMenu_Rebuild = new System.Windows.Forms.ToolStripMenuItem(); - this.BuildListContextMenu_GenerateProjectFiles = new System.Windows.Forms.ToolStripMenuItem(); - this.BuildListContextMenu_Cancel = new System.Windows.Forms.ToolStripMenuItem(); - this.BuildListContextMenu_OpenVisualStudio = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator(); - this.BuildListContextMenu_MarkGood = new System.Windows.Forms.ToolStripMenuItem(); - this.BuildListContextMenu_MarkBad = new System.Windows.Forms.ToolStripMenuItem(); - this.BuildListContextMenu_WithdrawReview = new System.Windows.Forms.ToolStripMenuItem(); - this.BuildListContextMenu_LeaveComment = new System.Windows.Forms.ToolStripMenuItem(); - this.BuildListContextMenu_EditComment = new System.Windows.Forms.ToolStripMenuItem(); - this.BuildListContextMenu_StartInvestigating = new System.Windows.Forms.ToolStripMenuItem(); - this.BuildListContextMenu_FinishInvestigating = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); - this.BuildListContextMenu_AddStar = new System.Windows.Forms.ToolStripMenuItem(); - this.BuildListContextMenu_RemoveStar = new System.Windows.Forms.ToolStripMenuItem(); - this.BuildListContextMenu_TimeZoneSeparator = new System.Windows.Forms.ToolStripSeparator(); - this.BuildListContextMenu_ShowServerTimes = new System.Windows.Forms.ToolStripMenuItem(); - this.BuildListContextMenu_ShowLocalTimes = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); - this.BuildListContextMenu_MoreInfo = new System.Windows.Forms.ToolStripMenuItem(); this.NotifyIcon = new System.Windows.Forms.NotifyIcon(this.components); this.NotifyMenu = new System.Windows.Forms.ContextMenuStrip(this.components); this.NotifyMenu_OpenUnrealGameSync = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripSeparator7 = new System.Windows.Forms.ToolStripSeparator(); + this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); this.NotifyMenu_SyncNow = new System.Windows.Forms.ToolStripMenuItem(); this.NotifyMenu_LaunchEditor = new System.Windows.Forms.ToolStripMenuItem(); this.NotifyMenu_ExitSeparator = new System.Windows.Forms.ToolStripSeparator(); this.NotifyMenu_Exit = new System.Windows.Forms.ToolStripMenuItem(); - this.BuildListToolTip = new System.Windows.Forms.ToolTip(this.components); - this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); - this.OpenSolutionAfterSyncCheckBox = new System.Windows.Forms.CheckBox(); - this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); - this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel(); - this.OptionsButton = new System.Windows.Forms.Button(); - this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); - this.Splitter = new UnrealGameSync.LogSplitContainer(); - this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel(); - this.StatusPanel = new UnrealGameSync.StatusPanel(); - this.BuildList = new UnrealGameSync.BuildListControl(); - this.IconColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.ChangeColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.TimeColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.AuthorColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.DescriptionColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.CISColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.StatusColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.panel1 = new System.Windows.Forms.Panel(); - this.SyncLog = new UnrealGameSync.LogControl(); - this.MoreToolsContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); - this.MoreActionsContextMenu_CustomToolSeparator = new System.Windows.Forms.ToolStripSeparator(); - this.MoreToolsContextMenu_CleanWorkspace = new System.Windows.Forms.ToolStripMenuItem(); - this.SyncContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); - this.SyncContextMenu_LatestChange = new System.Windows.Forms.ToolStripMenuItem(); - this.SyncContextMenu_LatestGoodChange = new System.Windows.Forms.ToolStripMenuItem(); - this.SyncContextMenu_LatestStarredChange = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripSeparator8 = new System.Windows.Forms.ToolStripSeparator(); - this.SyncContexMenu_EnterChangelist = new System.Windows.Forms.ToolStripMenuItem(); - this.StreamContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); - this.OptionsContextMenu_PerforceSettings = new System.Windows.Forms.ToolStripMenuItem(); - this.OptionsContextMenu.SuspendLayout(); - this.BuildListContextMenu.SuspendLayout(); + this.TabPanel = new System.Windows.Forms.Panel(); + this.DefaultControl = new UnrealGameSync.StatusPanel(); + this.TabMenu = new System.Windows.Forms.ContextMenuStrip(this.components); + this.TabMenu_OpenProject = new System.Windows.Forms.ToolStripMenuItem(); + this.TabMenu_RecentProjects = new System.Windows.Forms.ToolStripMenuItem(); + this.TabMenu_Recent_Separator = new System.Windows.Forms.ToolStripSeparator(); + this.TabMenu_RecentProjects_ClearList = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); + this.labelsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.TabMenu_TabNames_Stream = new System.Windows.Forms.ToolStripMenuItem(); + this.TabMenu_TabNames_WorkspaceName = new System.Windows.Forms.ToolStripMenuItem(); + this.TabMenu_TabNames_WorkspaceRoot = new System.Windows.Forms.ToolStripMenuItem(); + this.TabMenu_TabNames_ProjectFile = new System.Windows.Forms.ToolStripMenuItem(); + this.TabControl = new UnrealGameSync.TabControl(); this.NotifyMenu.SuspendLayout(); - this.flowLayoutPanel1.SuspendLayout(); - this.tableLayoutPanel1.SuspendLayout(); - this.tableLayoutPanel3.SuspendLayout(); - this.tableLayoutPanel2.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.Splitter)).BeginInit(); - this.Splitter.Panel1.SuspendLayout(); - this.Splitter.Panel2.SuspendLayout(); - this.Splitter.SuspendLayout(); - this.tableLayoutPanel4.SuspendLayout(); - this.panel1.SuspendLayout(); - this.MoreToolsContextMenu.SuspendLayout(); - this.SyncContextMenu.SuspendLayout(); + this.TabPanel.SuspendLayout(); + this.TabMenu.SuspendLayout(); this.SuspendLayout(); // - // label1 - // - this.label1.AutoSize = true; - this.label1.Dock = System.Windows.Forms.DockStyle.Fill; - this.label1.Location = new System.Drawing.Point(3, 0); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(45, 29); - this.label1.TabIndex = 2; - this.label1.Text = "Project:"; - this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; - // - // ProjectList - // - this.ProjectList.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.ProjectList.FormattingEnabled = true; - this.ProjectList.Location = new System.Drawing.Point(54, 4); - this.ProjectList.Name = "ProjectList"; - this.ProjectList.Size = new System.Drawing.Size(1059, 21); - this.ProjectList.TabIndex = 1; - this.ProjectList.SelectionChangeCommitted += new System.EventHandler(this.ProjectList_SelectionChangeCommitted); - this.ProjectList.KeyDown += new System.Windows.Forms.KeyEventHandler(this.ProjectList_KeyDown); - this.ProjectList.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.ProjectList_MouseWheel); - // - // BrowseProject - // - this.BrowseProject.AutoSize = true; - this.BrowseProject.Dock = System.Windows.Forms.DockStyle.Fill; - this.BrowseProject.Location = new System.Drawing.Point(1119, 3); - this.BrowseProject.Name = "BrowseProject"; - this.BrowseProject.Size = new System.Drawing.Size(34, 23); - this.BrowseProject.TabIndex = 2; - this.BrowseProject.Text = "..."; - this.BrowseProject.UseVisualStyleBackColor = true; - this.BrowseProject.Click += new System.EventHandler(this.BrowseProject_Click); - // - // OptionsContextMenu - // - this.OptionsContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.OptionsContextMenu_ScheduledSync, - this.OptionsContextMenu_SyncPrecompiledEditor, - this.OptionsContextMenu_AutoResolveConflicts, - this.OptionsContextMenu_SyncFilter, - this.OptionsContextMenu_PerforceSettings, - this.toolStripSeparator3, - this.OptionsContextMenu_EditorBuildConfiguration, - this.OptionsContextMenu_UseIncrementalBuilds, - this.OptionsContextMenu_CustomizeBuildSteps, - this.toolStripSeparator5, - this.OptionsContextMenu_EditorArguments, - this.OptionsContextMenu_TimeZone, - this.OptionsContextMenu_AutomaticallyRunAtStartup, - this.OptionsContextMenu_KeepInTray, - this.toolStripSeparator6, - this.OptionsContextMenu_Diagnostics}); - this.OptionsContextMenu.Name = "ToolsMenuStrip"; - this.OptionsContextMenu.Size = new System.Drawing.Size(268, 330); - // - // OptionsContextMenu_ScheduledSync - // - this.OptionsContextMenu_ScheduledSync.Name = "OptionsContextMenu_ScheduledSync"; - this.OptionsContextMenu_ScheduledSync.Size = new System.Drawing.Size(267, 22); - this.OptionsContextMenu_ScheduledSync.Text = "Scheduled Sync..."; - this.OptionsContextMenu_ScheduledSync.Click += new System.EventHandler(this.OptionsContextMenu_ScheduleSync_Click); - // - // OptionsContextMenu_SyncPrecompiledEditor - // - this.OptionsContextMenu_SyncPrecompiledEditor.Name = "OptionsContextMenu_SyncPrecompiledEditor"; - this.OptionsContextMenu_SyncPrecompiledEditor.Size = new System.Drawing.Size(267, 22); - this.OptionsContextMenu_SyncPrecompiledEditor.Text = "Sync Precompiled Editor"; - this.OptionsContextMenu_SyncPrecompiledEditor.Click += new System.EventHandler(this.OptionsContextMenu_SyncPrecompiledEditor_Click); - // - // OptionsContextMenu_AutoResolveConflicts - // - this.OptionsContextMenu_AutoResolveConflicts.Name = "OptionsContextMenu_AutoResolveConflicts"; - this.OptionsContextMenu_AutoResolveConflicts.Size = new System.Drawing.Size(267, 22); - this.OptionsContextMenu_AutoResolveConflicts.Text = "Auto-Resolve Conflicts"; - this.OptionsContextMenu_AutoResolveConflicts.Click += new System.EventHandler(this.OptionsContextMenu_AutoResolveConflicts_Click); - // - // OptionsContextMenu_SyncFilter - // - this.OptionsContextMenu_SyncFilter.Name = "OptionsContextMenu_SyncFilter"; - this.OptionsContextMenu_SyncFilter.Size = new System.Drawing.Size(267, 22); - this.OptionsContextMenu_SyncFilter.Text = "Sync Filter..."; - this.OptionsContextMenu_SyncFilter.Click += new System.EventHandler(this.OptionsContextMenu_SyncFilter_Click); - // - // toolStripSeparator3 - // - this.toolStripSeparator3.Name = "toolStripSeparator3"; - this.toolStripSeparator3.Size = new System.Drawing.Size(264, 6); - // - // OptionsContextMenu_EditorBuildConfiguration - // - this.OptionsContextMenu_EditorBuildConfiguration.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.OptionsContextMenu_BuildConfig_Debug, - this.OptionsContextMenu_BuildConfig_DebugGame, - this.OptionsContextMenu_BuildConfig_Development}); - this.OptionsContextMenu_EditorBuildConfiguration.Name = "OptionsContextMenu_EditorBuildConfiguration"; - this.OptionsContextMenu_EditorBuildConfiguration.Size = new System.Drawing.Size(267, 22); - this.OptionsContextMenu_EditorBuildConfiguration.Text = "Editor Build Configuration"; - // - // OptionsContextMenu_BuildConfig_Debug - // - this.OptionsContextMenu_BuildConfig_Debug.Name = "OptionsContextMenu_BuildConfig_Debug"; - this.OptionsContextMenu_BuildConfig_Debug.Size = new System.Drawing.Size(145, 22); - this.OptionsContextMenu_BuildConfig_Debug.Text = "Debug"; - this.OptionsContextMenu_BuildConfig_Debug.Click += new System.EventHandler(this.OptionsContextMenu_BuildConfig_Debug_Click); - // - // OptionsContextMenu_BuildConfig_DebugGame - // - this.OptionsContextMenu_BuildConfig_DebugGame.Name = "OptionsContextMenu_BuildConfig_DebugGame"; - this.OptionsContextMenu_BuildConfig_DebugGame.Size = new System.Drawing.Size(145, 22); - this.OptionsContextMenu_BuildConfig_DebugGame.Text = "DebugGame"; - this.OptionsContextMenu_BuildConfig_DebugGame.Click += new System.EventHandler(this.OptionsContextMenu_BuildConfig_DebugGame_Click); - // - // OptionsContextMenu_BuildConfig_Development - // - this.OptionsContextMenu_BuildConfig_Development.Checked = true; - this.OptionsContextMenu_BuildConfig_Development.CheckState = System.Windows.Forms.CheckState.Checked; - this.OptionsContextMenu_BuildConfig_Development.Name = "OptionsContextMenu_BuildConfig_Development"; - this.OptionsContextMenu_BuildConfig_Development.Size = new System.Drawing.Size(145, 22); - this.OptionsContextMenu_BuildConfig_Development.Text = "Development"; - this.OptionsContextMenu_BuildConfig_Development.Click += new System.EventHandler(this.OptionsContextMenu_BuildConfig_Development_Click); - // - // OptionsContextMenu_UseIncrementalBuilds - // - this.OptionsContextMenu_UseIncrementalBuilds.Name = "OptionsContextMenu_UseIncrementalBuilds"; - this.OptionsContextMenu_UseIncrementalBuilds.Size = new System.Drawing.Size(267, 22); - this.OptionsContextMenu_UseIncrementalBuilds.Text = "Use Incremental Builds"; - this.OptionsContextMenu_UseIncrementalBuilds.Click += new System.EventHandler(this.OptionsContextMenu_UseIncrementalBuilds_Click); - // - // OptionsContextMenu_CustomizeBuildSteps - // - this.OptionsContextMenu_CustomizeBuildSteps.Name = "OptionsContextMenu_CustomizeBuildSteps"; - this.OptionsContextMenu_CustomizeBuildSteps.Size = new System.Drawing.Size(267, 22); - this.OptionsContextMenu_CustomizeBuildSteps.Text = "Customize Build Steps..."; - this.OptionsContextMenu_CustomizeBuildSteps.Click += new System.EventHandler(this.OptionsContextMenu_EditBuildSteps_Click); - // - // toolStripSeparator5 - // - this.toolStripSeparator5.Name = "toolStripSeparator5"; - this.toolStripSeparator5.Size = new System.Drawing.Size(264, 6); - // - // OptionsContextMenu_EditorArguments - // - this.OptionsContextMenu_EditorArguments.Name = "OptionsContextMenu_EditorArguments"; - this.OptionsContextMenu_EditorArguments.Size = new System.Drawing.Size(267, 22); - this.OptionsContextMenu_EditorArguments.Text = "Editor Command Line Arguments..."; - this.OptionsContextMenu_EditorArguments.Click += new System.EventHandler(this.OptionsContextMenu_EditorArguments_Click); - // - // OptionsContextMenu_TimeZone - // - this.OptionsContextMenu_TimeZone.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.OptionsContextMenu_TimeZone_Local, - this.OptionsContextMenu_TimeZone_PerforceServer}); - this.OptionsContextMenu_TimeZone.Name = "OptionsContextMenu_TimeZone"; - this.OptionsContextMenu_TimeZone.Size = new System.Drawing.Size(267, 22); - this.OptionsContextMenu_TimeZone.Text = "Time Zone"; - // - // OptionsContextMenu_TimeZone_Local - // - this.OptionsContextMenu_TimeZone_Local.Name = "OptionsContextMenu_TimeZone_Local"; - this.OptionsContextMenu_TimeZone_Local.Size = new System.Drawing.Size(153, 22); - this.OptionsContextMenu_TimeZone_Local.Text = "Local"; - this.OptionsContextMenu_TimeZone_Local.Click += new System.EventHandler(this.BuildListContextMenu_ShowLocalTimes_Click); - // - // OptionsContextMenu_TimeZone_PerforceServer - // - this.OptionsContextMenu_TimeZone_PerforceServer.Name = "OptionsContextMenu_TimeZone_PerforceServer"; - this.OptionsContextMenu_TimeZone_PerforceServer.Size = new System.Drawing.Size(153, 22); - this.OptionsContextMenu_TimeZone_PerforceServer.Text = "Perforce Server"; - this.OptionsContextMenu_TimeZone_PerforceServer.Click += new System.EventHandler(this.BuildListContextMenu_ShowServerTimes_Click); - // - // OptionsContextMenu_AutomaticallyRunAtStartup - // - this.OptionsContextMenu_AutomaticallyRunAtStartup.Name = "OptionsContextMenu_AutomaticallyRunAtStartup"; - this.OptionsContextMenu_AutomaticallyRunAtStartup.Size = new System.Drawing.Size(267, 22); - this.OptionsContextMenu_AutomaticallyRunAtStartup.Text = "Automatically run at startup"; - this.OptionsContextMenu_AutomaticallyRunAtStartup.Click += new System.EventHandler(this.OptionsContextMenu_AutomaticallyRunAtStartup_Click); - // - // OptionsContextMenu_KeepInTray - // - this.OptionsContextMenu_KeepInTray.Name = "OptionsContextMenu_KeepInTray"; - this.OptionsContextMenu_KeepInTray.Size = new System.Drawing.Size(267, 22); - this.OptionsContextMenu_KeepInTray.Text = "Stay in notification area when closed"; - this.OptionsContextMenu_KeepInTray.Click += new System.EventHandler(this.OptionsContextMenu_KeepInTray_Click); - // - // toolStripSeparator6 - // - this.toolStripSeparator6.Name = "toolStripSeparator6"; - this.toolStripSeparator6.Size = new System.Drawing.Size(264, 6); - // - // OptionsContextMenu_Diagnostics - // - this.OptionsContextMenu_Diagnostics.Name = "OptionsContextMenu_Diagnostics"; - this.OptionsContextMenu_Diagnostics.Size = new System.Drawing.Size(267, 22); - this.OptionsContextMenu_Diagnostics.Text = "Diagnostics..."; - this.OptionsContextMenu_Diagnostics.Click += new System.EventHandler(this.OptionsContextMenu_Diagnostics_Click); - // - // OnlyShowReviewedCheckBox - // - this.OnlyShowReviewedCheckBox.Anchor = System.Windows.Forms.AnchorStyles.Left; - this.OnlyShowReviewedCheckBox.AutoSize = true; - this.OnlyShowReviewedCheckBox.Location = new System.Drawing.Point(3, 6); - this.OnlyShowReviewedCheckBox.Name = "OnlyShowReviewedCheckBox"; - this.OnlyShowReviewedCheckBox.Size = new System.Drawing.Size(166, 17); - this.OnlyShowReviewedCheckBox.TabIndex = 3; - this.OnlyShowReviewedCheckBox.Text = "Only show reviewed changes"; - this.OnlyShowReviewedCheckBox.UseVisualStyleBackColor = true; - this.OnlyShowReviewedCheckBox.CheckedChanged += new System.EventHandler(this.OnlyShowReviewedCheckBox_CheckedChanged); - // - // RunAfterSyncCheckBox - // - this.RunAfterSyncCheckBox.AutoSize = true; - this.RunAfterSyncCheckBox.Location = new System.Drawing.Point(138, 3); - this.RunAfterSyncCheckBox.Name = "RunAfterSyncCheckBox"; - this.RunAfterSyncCheckBox.Size = new System.Drawing.Size(45, 17); - this.RunAfterSyncCheckBox.TabIndex = 6; - this.RunAfterSyncCheckBox.Text = "Run"; - this.RunAfterSyncCheckBox.UseVisualStyleBackColor = true; - this.RunAfterSyncCheckBox.CheckedChanged += new System.EventHandler(this.RunAfterSyncCheckBox_CheckedChanged); - // - // BuildAfterSyncCheckBox - // - this.BuildAfterSyncCheckBox.AutoSize = true; - this.BuildAfterSyncCheckBox.Location = new System.Drawing.Point(84, 3); - this.BuildAfterSyncCheckBox.Name = "BuildAfterSyncCheckBox"; - this.BuildAfterSyncCheckBox.Size = new System.Drawing.Size(48, 17); - this.BuildAfterSyncCheckBox.TabIndex = 5; - this.BuildAfterSyncCheckBox.Text = "Build"; - this.BuildAfterSyncCheckBox.UseVisualStyleBackColor = true; - this.BuildAfterSyncCheckBox.CheckedChanged += new System.EventHandler(this.BuildAfterSyncCheckBox_CheckedChanged); - // - // AfterSyncingLabel - // - this.AfterSyncingLabel.AutoSize = true; - this.AfterSyncingLabel.Location = new System.Drawing.Point(3, 0); - this.AfterSyncingLabel.Name = "AfterSyncingLabel"; - this.AfterSyncingLabel.Padding = new System.Windows.Forms.Padding(0, 4, 0, 0); - this.AfterSyncingLabel.Size = new System.Drawing.Size(75, 17); - this.AfterSyncingLabel.TabIndex = 4; - this.AfterSyncingLabel.Text = "After syncing:"; - // - // BuildListContextMenu - // - this.BuildListContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.BuildListContextMenu_LaunchEditor, - this.BuildListContextMenu_Sync, - this.BuildListContextMenu_SyncContentOnly, - this.BuildListContextMenu_SyncOnlyThisChange, - this.BuildListContextMenu_Build, - this.BuildListContextMenu_Rebuild, - this.BuildListContextMenu_GenerateProjectFiles, - this.BuildListContextMenu_Cancel, - this.BuildListContextMenu_OpenVisualStudio, - this.toolStripSeparator4, - this.BuildListContextMenu_MarkGood, - this.BuildListContextMenu_MarkBad, - this.BuildListContextMenu_WithdrawReview, - this.BuildListContextMenu_LeaveComment, - this.BuildListContextMenu_EditComment, - this.BuildListContextMenu_StartInvestigating, - this.BuildListContextMenu_FinishInvestigating, - this.toolStripSeparator1, - this.BuildListContextMenu_AddStar, - this.BuildListContextMenu_RemoveStar, - this.BuildListContextMenu_TimeZoneSeparator, - this.BuildListContextMenu_ShowServerTimes, - this.BuildListContextMenu_ShowLocalTimes, - this.toolStripSeparator2, - this.BuildListContextMenu_MoreInfo}); - this.BuildListContextMenu.Name = "BuildListContextMenu"; - this.BuildListContextMenu.Size = new System.Drawing.Size(200, 490); - // - // BuildListContextMenu_LaunchEditor - // - this.BuildListContextMenu_LaunchEditor.Name = "BuildListContextMenu_LaunchEditor"; - this.BuildListContextMenu_LaunchEditor.Size = new System.Drawing.Size(199, 22); - this.BuildListContextMenu_LaunchEditor.Text = "Launch editor"; - this.BuildListContextMenu_LaunchEditor.Click += new System.EventHandler(this.BuildListContextMenu_LaunchEditor_Click); - // - // BuildListContextMenu_Sync - // - this.BuildListContextMenu_Sync.Name = "BuildListContextMenu_Sync"; - this.BuildListContextMenu_Sync.Size = new System.Drawing.Size(199, 22); - this.BuildListContextMenu_Sync.Text = "Sync"; - this.BuildListContextMenu_Sync.Click += new System.EventHandler(this.BuildListContextMenu_Sync_Click); - // - // BuildListContextMenu_SyncContentOnly - // - this.BuildListContextMenu_SyncContentOnly.Name = "BuildListContextMenu_SyncContentOnly"; - this.BuildListContextMenu_SyncContentOnly.Size = new System.Drawing.Size(199, 22); - this.BuildListContextMenu_SyncContentOnly.Text = "Sync (Just Content)"; - this.BuildListContextMenu_SyncContentOnly.Click += new System.EventHandler(this.BuildListContextMenu_SyncContentOnly_Click); - // - // BuildListContextMenu_SyncOnlyThisChange - // - this.BuildListContextMenu_SyncOnlyThisChange.Name = "BuildListContextMenu_SyncOnlyThisChange"; - this.BuildListContextMenu_SyncOnlyThisChange.Size = new System.Drawing.Size(199, 22); - this.BuildListContextMenu_SyncOnlyThisChange.Text = "Sync (Just This Change)"; - this.BuildListContextMenu_SyncOnlyThisChange.Click += new System.EventHandler(this.BuildListContextMenu_SyncOnlyThisChange_Click); - // - // BuildListContextMenu_Build - // - this.BuildListContextMenu_Build.Name = "BuildListContextMenu_Build"; - this.BuildListContextMenu_Build.Size = new System.Drawing.Size(199, 22); - this.BuildListContextMenu_Build.Text = "Build"; - this.BuildListContextMenu_Build.Click += new System.EventHandler(this.BuildListContextMenu_Build_Click); - // - // BuildListContextMenu_Rebuild - // - this.BuildListContextMenu_Rebuild.Name = "BuildListContextMenu_Rebuild"; - this.BuildListContextMenu_Rebuild.Size = new System.Drawing.Size(199, 22); - this.BuildListContextMenu_Rebuild.Text = "Rebuild"; - this.BuildListContextMenu_Rebuild.Click += new System.EventHandler(this.BuildListContextMenu_Rebuild_Click); - // - // BuildListContextMenu_GenerateProjectFiles - // - this.BuildListContextMenu_GenerateProjectFiles.Name = "BuildListContextMenu_GenerateProjectFiles"; - this.BuildListContextMenu_GenerateProjectFiles.Size = new System.Drawing.Size(199, 22); - this.BuildListContextMenu_GenerateProjectFiles.Text = "Generate project files"; - this.BuildListContextMenu_GenerateProjectFiles.Click += new System.EventHandler(this.BuildListContextMenu_GenerateProjectFiles_Click); - // - // BuildListContextMenu_Cancel - // - this.BuildListContextMenu_Cancel.Name = "BuildListContextMenu_Cancel"; - this.BuildListContextMenu_Cancel.Size = new System.Drawing.Size(199, 22); - this.BuildListContextMenu_Cancel.Text = "Cancel"; - this.BuildListContextMenu_Cancel.Click += new System.EventHandler(this.BuildListContextMenu_CancelSync_Click); - // - // BuildListContextMenu_OpenVisualStudio - // - this.BuildListContextMenu_OpenVisualStudio.Name = "BuildListContextMenu_OpenVisualStudio"; - this.BuildListContextMenu_OpenVisualStudio.Size = new System.Drawing.Size(199, 22); - this.BuildListContextMenu_OpenVisualStudio.Text = "Open in Visual Studio..."; - this.BuildListContextMenu_OpenVisualStudio.Click += new System.EventHandler(this.BuildListContextMenu_OpenVisualStudio_Click); - // - // toolStripSeparator4 - // - this.toolStripSeparator4.Name = "toolStripSeparator4"; - this.toolStripSeparator4.Size = new System.Drawing.Size(196, 6); - // - // BuildListContextMenu_MarkGood - // - this.BuildListContextMenu_MarkGood.Name = "BuildListContextMenu_MarkGood"; - this.BuildListContextMenu_MarkGood.Size = new System.Drawing.Size(199, 22); - this.BuildListContextMenu_MarkGood.Text = "Mark as good"; - this.BuildListContextMenu_MarkGood.Click += new System.EventHandler(this.BuildListContextMenu_MarkGood_Click); - // - // BuildListContextMenu_MarkBad - // - this.BuildListContextMenu_MarkBad.Name = "BuildListContextMenu_MarkBad"; - this.BuildListContextMenu_MarkBad.Size = new System.Drawing.Size(199, 22); - this.BuildListContextMenu_MarkBad.Text = "Mark as bad"; - this.BuildListContextMenu_MarkBad.Click += new System.EventHandler(this.BuildListContextMenu_MarkBad_Click); - // - // BuildListContextMenu_WithdrawReview - // - this.BuildListContextMenu_WithdrawReview.Name = "BuildListContextMenu_WithdrawReview"; - this.BuildListContextMenu_WithdrawReview.Size = new System.Drawing.Size(199, 22); - this.BuildListContextMenu_WithdrawReview.Text = "Withdraw review"; - this.BuildListContextMenu_WithdrawReview.Click += new System.EventHandler(this.BuildListContextMenu_WithdrawReview_Click); - // - // BuildListContextMenu_LeaveComment - // - this.BuildListContextMenu_LeaveComment.Name = "BuildListContextMenu_LeaveComment"; - this.BuildListContextMenu_LeaveComment.Size = new System.Drawing.Size(199, 22); - this.BuildListContextMenu_LeaveComment.Text = "Leave comment..."; - this.BuildListContextMenu_LeaveComment.Click += new System.EventHandler(this.BuildListContextMenu_LeaveOrEditComment_Click); - // - // BuildListContextMenu_EditComment - // - this.BuildListContextMenu_EditComment.Name = "BuildListContextMenu_EditComment"; - this.BuildListContextMenu_EditComment.Size = new System.Drawing.Size(199, 22); - this.BuildListContextMenu_EditComment.Text = "Edit comment..."; - this.BuildListContextMenu_EditComment.Click += new System.EventHandler(this.BuildListContextMenu_LeaveOrEditComment_Click); - // - // BuildListContextMenu_StartInvestigating - // - this.BuildListContextMenu_StartInvestigating.Name = "BuildListContextMenu_StartInvestigating"; - this.BuildListContextMenu_StartInvestigating.Size = new System.Drawing.Size(199, 22); - this.BuildListContextMenu_StartInvestigating.Text = "Start investigating"; - this.BuildListContextMenu_StartInvestigating.Click += new System.EventHandler(this.BuildListContextMenu_StartInvestigating_Click); - // - // BuildListContextMenu_FinishInvestigating - // - this.BuildListContextMenu_FinishInvestigating.Name = "BuildListContextMenu_FinishInvestigating"; - this.BuildListContextMenu_FinishInvestigating.Size = new System.Drawing.Size(199, 22); - this.BuildListContextMenu_FinishInvestigating.Text = "Finish investigating"; - this.BuildListContextMenu_FinishInvestigating.Click += new System.EventHandler(this.BuildListContextMenu_FinishInvestigating_Click); - // - // toolStripSeparator1 - // - this.toolStripSeparator1.Name = "toolStripSeparator1"; - this.toolStripSeparator1.Size = new System.Drawing.Size(196, 6); - // - // BuildListContextMenu_AddStar - // - this.BuildListContextMenu_AddStar.Name = "BuildListContextMenu_AddStar"; - this.BuildListContextMenu_AddStar.Size = new System.Drawing.Size(199, 22); - this.BuildListContextMenu_AddStar.Text = "Add Star"; - this.BuildListContextMenu_AddStar.Click += new System.EventHandler(this.BuildListContextMenu_AddStar_Click); - // - // BuildListContextMenu_RemoveStar - // - this.BuildListContextMenu_RemoveStar.Name = "BuildListContextMenu_RemoveStar"; - this.BuildListContextMenu_RemoveStar.Size = new System.Drawing.Size(199, 22); - this.BuildListContextMenu_RemoveStar.Text = "Remove Star"; - this.BuildListContextMenu_RemoveStar.Click += new System.EventHandler(this.BuildListContextMenu_RemoveStar_Click); - // - // BuildListContextMenu_TimeZoneSeparator - // - this.BuildListContextMenu_TimeZoneSeparator.Name = "BuildListContextMenu_TimeZoneSeparator"; - this.BuildListContextMenu_TimeZoneSeparator.Size = new System.Drawing.Size(196, 6); - // - // BuildListContextMenu_ShowServerTimes - // - this.BuildListContextMenu_ShowServerTimes.Name = "BuildListContextMenu_ShowServerTimes"; - this.BuildListContextMenu_ShowServerTimes.Size = new System.Drawing.Size(199, 22); - this.BuildListContextMenu_ShowServerTimes.Text = "Show server times"; - this.BuildListContextMenu_ShowServerTimes.Click += new System.EventHandler(this.BuildListContextMenu_ShowServerTimes_Click); - // - // BuildListContextMenu_ShowLocalTimes - // - this.BuildListContextMenu_ShowLocalTimes.Name = "BuildListContextMenu_ShowLocalTimes"; - this.BuildListContextMenu_ShowLocalTimes.Size = new System.Drawing.Size(199, 22); - this.BuildListContextMenu_ShowLocalTimes.Text = "Show local times"; - this.BuildListContextMenu_ShowLocalTimes.Click += new System.EventHandler(this.BuildListContextMenu_ShowLocalTimes_Click); - // - // toolStripSeparator2 - // - this.toolStripSeparator2.Name = "toolStripSeparator2"; - this.toolStripSeparator2.Size = new System.Drawing.Size(196, 6); - // - // BuildListContextMenu_MoreInfo - // - this.BuildListContextMenu_MoreInfo.Name = "BuildListContextMenu_MoreInfo"; - this.BuildListContextMenu_MoreInfo.Size = new System.Drawing.Size(199, 22); - this.BuildListContextMenu_MoreInfo.Text = "More Info..."; - this.BuildListContextMenu_MoreInfo.Click += new System.EventHandler(this.BuildListContextMenu_MoreInfo_Click); - // // NotifyIcon // this.NotifyIcon.ContextMenuStrip = this.NotifyMenu; @@ -582,7 +59,7 @@ namespace UnrealGameSync // this.NotifyMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.NotifyMenu_OpenUnrealGameSync, - this.toolStripSeparator7, + this.toolStripSeparator1, this.NotifyMenu_SyncNow, this.NotifyMenu_LaunchEditor, this.NotifyMenu_ExitSeparator, @@ -597,10 +74,10 @@ namespace UnrealGameSync this.NotifyMenu_OpenUnrealGameSync.Text = "Open UnrealGameSync"; this.NotifyMenu_OpenUnrealGameSync.Click += new System.EventHandler(this.NotifyMenu_OpenUnrealGameSync_Click); // - // toolStripSeparator7 + // toolStripSeparator1 // - this.toolStripSeparator7.Name = "toolStripSeparator7"; - this.toolStripSeparator7.Size = new System.Drawing.Size(193, 6); + this.toolStripSeparator1.Name = "toolStripSeparator1"; + this.toolStripSeparator1.Size = new System.Drawing.Size(193, 6); // // NotifyMenu_SyncNow // @@ -628,329 +105,132 @@ namespace UnrealGameSync this.NotifyMenu_Exit.Text = "Exit"; this.NotifyMenu_Exit.Click += new System.EventHandler(this.NotifyMenu_Exit_Click); // - // flowLayoutPanel1 + // TabPanel // - this.flowLayoutPanel1.Anchor = System.Windows.Forms.AnchorStyles.None; - this.flowLayoutPanel1.AutoSize = true; - this.flowLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; - this.flowLayoutPanel1.Controls.Add(this.AfterSyncingLabel); - this.flowLayoutPanel1.Controls.Add(this.BuildAfterSyncCheckBox); - this.flowLayoutPanel1.Controls.Add(this.RunAfterSyncCheckBox); - this.flowLayoutPanel1.Controls.Add(this.OpenSolutionAfterSyncCheckBox); - this.flowLayoutPanel1.Location = new System.Drawing.Point(452, 3); - this.flowLayoutPanel1.Name = "flowLayoutPanel1"; - this.flowLayoutPanel1.Size = new System.Drawing.Size(285, 23); - this.flowLayoutPanel1.TabIndex = 8; - this.flowLayoutPanel1.WrapContents = false; + this.TabPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.TabPanel.Controls.Add(this.DefaultControl); + this.TabPanel.Location = new System.Drawing.Point(16, 51); + this.TabPanel.Margin = new System.Windows.Forms.Padding(0); + this.TabPanel.Name = "TabPanel"; + this.TabPanel.Size = new System.Drawing.Size(1140, 589); + this.TabPanel.TabIndex = 3; // - // OpenSolutionAfterSyncCheckBox + // DefaultControl // - this.OpenSolutionAfterSyncCheckBox.AutoSize = true; - this.OpenSolutionAfterSyncCheckBox.Location = new System.Drawing.Point(189, 3); - this.OpenSolutionAfterSyncCheckBox.Name = "OpenSolutionAfterSyncCheckBox"; - this.OpenSolutionAfterSyncCheckBox.Size = new System.Drawing.Size(93, 17); - this.OpenSolutionAfterSyncCheckBox.TabIndex = 7; - this.OpenSolutionAfterSyncCheckBox.Text = "Open Solution"; - this.OpenSolutionAfterSyncCheckBox.UseVisualStyleBackColor = true; - this.OpenSolutionAfterSyncCheckBox.CheckedChanged += new System.EventHandler(this.OpenSolutionAfterSyncCheckBox_CheckedChanged); + this.DefaultControl.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.DefaultControl.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(250)))), ((int)(((byte)(250)))), ((int)(((byte)(250))))); + this.DefaultControl.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.DefaultControl.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.DefaultControl.Location = new System.Drawing.Point(0, 0); + this.DefaultControl.Margin = new System.Windows.Forms.Padding(0); + this.DefaultControl.Name = "DefaultControl"; + this.DefaultControl.Size = new System.Drawing.Size(1140, 589); + this.DefaultControl.TabIndex = 0; // - // tableLayoutPanel1 + // TabMenu // - this.tableLayoutPanel1.AutoSize = true; - this.tableLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; - this.tableLayoutPanel1.ColumnCount = 3; - this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel1.Controls.Add(this.ProjectList, 1, 0); - this.tableLayoutPanel1.Controls.Add(this.label1, 0, 0); - this.tableLayoutPanel1.Controls.Add(this.BrowseProject, 2, 0); - this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Top; - this.tableLayoutPanel1.Location = new System.Drawing.Point(6, 6); - this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(0); - this.tableLayoutPanel1.Name = "tableLayoutPanel1"; - this.tableLayoutPanel1.RowCount = 1; - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 29F)); - this.tableLayoutPanel1.Size = new System.Drawing.Size(1156, 29); - this.tableLayoutPanel1.TabIndex = 10; + this.TabMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.TabMenu_OpenProject, + this.TabMenu_RecentProjects, + this.toolStripSeparator2, + this.labelsToolStripMenuItem}); + this.TabMenu.Name = "TabMenu"; + this.TabMenu.Size = new System.Drawing.Size(156, 98); + this.TabMenu.Closed += new System.Windows.Forms.ToolStripDropDownClosedEventHandler(this.TabMenu_Closed); // - // tableLayoutPanel3 + // TabMenu_OpenProject // - this.tableLayoutPanel3.AutoSize = true; - this.tableLayoutPanel3.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; - this.tableLayoutPanel3.ColumnCount = 3; - this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel3.Controls.Add(this.OnlyShowReviewedCheckBox, 0, 0); - this.tableLayoutPanel3.Controls.Add(this.flowLayoutPanel1, 1, 0); - this.tableLayoutPanel3.Controls.Add(this.OptionsButton, 2, 0); - this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Fill; - this.tableLayoutPanel3.Location = new System.Drawing.Point(6, 617); - this.tableLayoutPanel3.Margin = new System.Windows.Forms.Padding(0); - this.tableLayoutPanel3.Name = "tableLayoutPanel3"; - this.tableLayoutPanel3.RowCount = 1; - this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 29F)); - this.tableLayoutPanel3.Size = new System.Drawing.Size(1156, 29); - this.tableLayoutPanel3.TabIndex = 11; + this.TabMenu_OpenProject.Name = "TabMenu_OpenProject"; + this.TabMenu_OpenProject.Size = new System.Drawing.Size(155, 22); + this.TabMenu_OpenProject.Text = "Open Project..."; + this.TabMenu_OpenProject.Click += new System.EventHandler(this.TabMenu_OpenProject_Click); // - // OptionsButton + // TabMenu_RecentProjects // - this.OptionsButton.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.OptionsButton.AutoSize = true; - this.OptionsButton.Image = global::UnrealGameSync.Properties.Resources.DropList; - this.OptionsButton.ImageAlign = System.Drawing.ContentAlignment.MiddleRight; - this.OptionsButton.Location = new System.Drawing.Point(1021, 3); - this.OptionsButton.Name = "OptionsButton"; - this.OptionsButton.Size = new System.Drawing.Size(132, 23); - this.OptionsButton.TabIndex = 7; - this.OptionsButton.Text = "Options"; - this.OptionsButton.UseVisualStyleBackColor = true; - this.OptionsButton.Click += new System.EventHandler(this.OptionsButton_Click); + this.TabMenu_RecentProjects.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.TabMenu_Recent_Separator, + this.TabMenu_RecentProjects_ClearList}); + this.TabMenu_RecentProjects.Name = "TabMenu_RecentProjects"; + this.TabMenu_RecentProjects.Size = new System.Drawing.Size(155, 22); + this.TabMenu_RecentProjects.Text = "Recent Projects"; // - // tableLayoutPanel2 + // TabMenu_Recent_Separator // - this.tableLayoutPanel2.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; - this.tableLayoutPanel2.ColumnCount = 1; - this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F)); - this.tableLayoutPanel2.Controls.Add(this.tableLayoutPanel1, 0, 0); - this.tableLayoutPanel2.Controls.Add(this.Splitter, 0, 1); - this.tableLayoutPanel2.Controls.Add(this.tableLayoutPanel3, 0, 2); - this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill; - this.tableLayoutPanel2.GrowStyle = System.Windows.Forms.TableLayoutPanelGrowStyle.FixedSize; - this.tableLayoutPanel2.Location = new System.Drawing.Point(0, 0); - this.tableLayoutPanel2.Name = "tableLayoutPanel2"; - this.tableLayoutPanel2.Padding = new System.Windows.Forms.Padding(6); - this.tableLayoutPanel2.RowCount = 3; - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); - this.tableLayoutPanel2.Size = new System.Drawing.Size(1168, 652); - this.tableLayoutPanel2.TabIndex = 12; + this.TabMenu_Recent_Separator.Name = "TabMenu_Recent_Separator"; + this.TabMenu_Recent_Separator.Size = new System.Drawing.Size(149, 6); // - // Splitter + // TabMenu_RecentProjects_ClearList // - this.Splitter.Dock = System.Windows.Forms.DockStyle.Fill; - this.Splitter.Location = new System.Drawing.Point(12, 41); - this.Splitter.Margin = new System.Windows.Forms.Padding(6); - this.Splitter.Name = "Splitter"; - this.Splitter.Orientation = System.Windows.Forms.Orientation.Horizontal; + this.TabMenu_RecentProjects_ClearList.Name = "TabMenu_RecentProjects_ClearList"; + this.TabMenu_RecentProjects_ClearList.Size = new System.Drawing.Size(152, 22); + this.TabMenu_RecentProjects_ClearList.Text = "Clear List"; + this.TabMenu_RecentProjects_ClearList.Click += new System.EventHandler(this.TabMenu_RecentProjects_ClearList_Click); // - // Splitter.Panel1 + // toolStripSeparator2 // - this.Splitter.Panel1.Controls.Add(this.tableLayoutPanel4); + this.toolStripSeparator2.Name = "toolStripSeparator2"; + this.toolStripSeparator2.Size = new System.Drawing.Size(152, 6); // - // Splitter.Panel2 + // labelsToolStripMenuItem // - this.Splitter.Panel2.Controls.Add(this.panel1); - this.Splitter.Panel2MinSize = 50; - this.Splitter.Size = new System.Drawing.Size(1144, 570); - this.Splitter.SplitterDistance = 361; - this.Splitter.SplitterWidth = 28; - this.Splitter.TabIndex = 0; + this.labelsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.TabMenu_TabNames_Stream, + this.TabMenu_TabNames_WorkspaceName, + this.TabMenu_TabNames_WorkspaceRoot, + this.TabMenu_TabNames_ProjectFile}); + this.labelsToolStripMenuItem.Name = "labelsToolStripMenuItem"; + this.labelsToolStripMenuItem.Size = new System.Drawing.Size(155, 22); + this.labelsToolStripMenuItem.Text = "Labels"; // - // tableLayoutPanel4 + // TabMenu_TabNames_Stream // - this.tableLayoutPanel4.ColumnCount = 1; - this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tableLayoutPanel4.Controls.Add(this.StatusPanel, 0, 0); - this.tableLayoutPanel4.Controls.Add(this.BuildList, 0, 1); - this.tableLayoutPanel4.Dock = System.Windows.Forms.DockStyle.Fill; - this.tableLayoutPanel4.Location = new System.Drawing.Point(0, 0); - this.tableLayoutPanel4.Name = "tableLayoutPanel4"; - this.tableLayoutPanel4.RowCount = 2; - this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 128F)); - this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tableLayoutPanel4.Size = new System.Drawing.Size(1144, 361); - this.tableLayoutPanel4.TabIndex = 1; + this.TabMenu_TabNames_Stream.Name = "TabMenu_TabNames_Stream"; + this.TabMenu_TabNames_Stream.Size = new System.Drawing.Size(167, 22); + this.TabMenu_TabNames_Stream.Text = "Stream"; + this.TabMenu_TabNames_Stream.Click += new System.EventHandler(this.TabMenu_TabNames_Stream_Click); // - // StatusPanel + // TabMenu_TabNames_WorkspaceName // - this.StatusPanel.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(250)))), ((int)(((byte)(250)))), ((int)(((byte)(250))))); - this.StatusPanel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.StatusPanel.Dock = System.Windows.Forms.DockStyle.Fill; - this.StatusPanel.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.StatusPanel.Location = new System.Drawing.Point(0, 0); - this.StatusPanel.Margin = new System.Windows.Forms.Padding(0, 0, 0, 3); - this.StatusPanel.Name = "StatusPanel"; - this.StatusPanel.Size = new System.Drawing.Size(1144, 125); - this.StatusPanel.TabIndex = 1; + this.TabMenu_TabNames_WorkspaceName.Name = "TabMenu_TabNames_WorkspaceName"; + this.TabMenu_TabNames_WorkspaceName.Size = new System.Drawing.Size(167, 22); + this.TabMenu_TabNames_WorkspaceName.Text = "Workspace Name"; + this.TabMenu_TabNames_WorkspaceName.Click += new System.EventHandler(this.TabMenu_TabNames_WorkspaceName_Click); // - // BuildList + // TabMenu_TabNames_WorkspaceRoot // - this.BuildList.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this.IconColumn, - this.ChangeColumn, - this.TimeColumn, - this.AuthorColumn, - this.DescriptionColumn, - this.CISColumn, - this.StatusColumn}); - this.BuildList.Dock = System.Windows.Forms.DockStyle.Fill; - this.BuildList.FullRowSelect = true; - this.BuildList.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; - this.BuildList.Location = new System.Drawing.Point(0, 128); - this.BuildList.Margin = new System.Windows.Forms.Padding(0); - this.BuildList.MultiSelect = false; - this.BuildList.Name = "BuildList"; - this.BuildList.OwnerDraw = true; - this.BuildList.Size = new System.Drawing.Size(1144, 233); - this.BuildList.TabIndex = 0; - this.BuildList.UseCompatibleStateImageBehavior = false; - this.BuildList.View = System.Windows.Forms.View.Details; - this.BuildList.DrawColumnHeader += new System.Windows.Forms.DrawListViewColumnHeaderEventHandler(this.BuildList_DrawColumnHeader); - this.BuildList.DrawItem += new System.Windows.Forms.DrawListViewItemEventHandler(this.BuildList_DrawItem); - this.BuildList.DrawSubItem += new System.Windows.Forms.DrawListViewSubItemEventHandler(this.BuildList_DrawSubItem); - this.BuildList.ItemMouseHover += new System.Windows.Forms.ListViewItemMouseHoverEventHandler(this.BuildList_ItemMouseHover); - this.BuildList.SelectedIndexChanged += new System.EventHandler(this.BuildList_SelectedIndexChanged); - this.BuildList.FontChanged += new System.EventHandler(this.BuildList_FontChanged); - this.BuildList.KeyDown += new System.Windows.Forms.KeyEventHandler(this.BuildList_KeyDown); - this.BuildList.MouseClick += new System.Windows.Forms.MouseEventHandler(this.BuildList_MouseClick); - this.BuildList.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.BuildList_MouseDoubleClick); - this.BuildList.MouseLeave += new System.EventHandler(this.BuildList_MouseLeave); - this.BuildList.MouseMove += new System.Windows.Forms.MouseEventHandler(this.BuildList_MouseMove); + this.TabMenu_TabNames_WorkspaceRoot.Name = "TabMenu_TabNames_WorkspaceRoot"; + this.TabMenu_TabNames_WorkspaceRoot.Size = new System.Drawing.Size(167, 22); + this.TabMenu_TabNames_WorkspaceRoot.Text = "Workspace Root"; + this.TabMenu_TabNames_WorkspaceRoot.Click += new System.EventHandler(this.TabMenu_TabNames_WorkspaceRoot_Click); // - // IconColumn + // TabMenu_TabNames_ProjectFile // - this.IconColumn.Text = ""; - this.IconColumn.Width = 45; + this.TabMenu_TabNames_ProjectFile.Name = "TabMenu_TabNames_ProjectFile"; + this.TabMenu_TabNames_ProjectFile.Size = new System.Drawing.Size(167, 22); + this.TabMenu_TabNames_ProjectFile.Text = "Project File"; + this.TabMenu_TabNames_ProjectFile.Click += new System.EventHandler(this.TabMenu_TabNames_ProjectFile_Click); // - // ChangeColumn + // TabControl // - this.ChangeColumn.Text = "Change"; - this.ChangeColumn.Width = 74; - // - // TimeColumn - // - this.TimeColumn.Text = "Time"; - // - // AuthorColumn - // - this.AuthorColumn.Text = "Author"; - this.AuthorColumn.Width = 120; - // - // DescriptionColumn - // - this.DescriptionColumn.Text = "Description"; - this.DescriptionColumn.Width = 245; - // - // CISColumn - // - this.CISColumn.Text = "CIS"; - this.CISColumn.Width = 184; - // - // StatusColumn - // - this.StatusColumn.Text = "Status"; - this.StatusColumn.Width = 375; - // - // panel1 - // - this.panel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.panel1.Controls.Add(this.SyncLog); - this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; - this.panel1.Location = new System.Drawing.Point(0, 0); - this.panel1.Name = "panel1"; - this.panel1.Size = new System.Drawing.Size(1144, 181); - this.panel1.TabIndex = 0; - // - // SyncLog - // - this.SyncLog.BackColor = System.Drawing.Color.White; - this.SyncLog.Cursor = System.Windows.Forms.Cursors.IBeam; - this.SyncLog.Dock = System.Windows.Forms.DockStyle.Fill; - this.SyncLog.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.SyncLog.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(32)))), ((int)(((byte)(32))))); - this.SyncLog.Location = new System.Drawing.Point(0, 0); - this.SyncLog.Name = "SyncLog"; - this.SyncLog.Size = new System.Drawing.Size(1142, 179); - this.SyncLog.TabIndex = 0; - // - // MoreToolsContextMenu - // - this.MoreToolsContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.MoreActionsContextMenu_CustomToolSeparator, - this.MoreToolsContextMenu_CleanWorkspace}); - this.MoreToolsContextMenu.Name = "MoreActionsContextMenu"; - this.MoreToolsContextMenu.Size = new System.Drawing.Size(175, 32); - // - // MoreActionsContextMenu_CustomToolSeparator - // - this.MoreActionsContextMenu_CustomToolSeparator.Name = "MoreActionsContextMenu_CustomToolSeparator"; - this.MoreActionsContextMenu_CustomToolSeparator.Size = new System.Drawing.Size(171, 6); - // - // MoreToolsContextMenu_CleanWorkspace - // - this.MoreToolsContextMenu_CleanWorkspace.Name = "MoreToolsContextMenu_CleanWorkspace"; - this.MoreToolsContextMenu_CleanWorkspace.Size = new System.Drawing.Size(174, 22); - this.MoreToolsContextMenu_CleanWorkspace.Text = "Clean Workspace..."; - this.MoreToolsContextMenu_CleanWorkspace.Click += new System.EventHandler(this.MoreToolsContextMenu_CleanWorkspace_Click); - // - // SyncContextMenu - // - this.SyncContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.SyncContextMenu_LatestChange, - this.SyncContextMenu_LatestGoodChange, - this.SyncContextMenu_LatestStarredChange, - this.toolStripSeparator8, - this.SyncContexMenu_EnterChangelist}); - this.SyncContextMenu.Name = "SyncContextMenu"; - this.SyncContextMenu.Size = new System.Drawing.Size(190, 98); - // - // SyncContextMenu_LatestChange - // - this.SyncContextMenu_LatestChange.Name = "SyncContextMenu_LatestChange"; - this.SyncContextMenu_LatestChange.Size = new System.Drawing.Size(189, 22); - this.SyncContextMenu_LatestChange.Text = "Latest Change"; - this.SyncContextMenu_LatestChange.Click += new System.EventHandler(this.SyncContextMenu_LatestChange_Click); - // - // SyncContextMenu_LatestGoodChange - // - this.SyncContextMenu_LatestGoodChange.Name = "SyncContextMenu_LatestGoodChange"; - this.SyncContextMenu_LatestGoodChange.Size = new System.Drawing.Size(189, 22); - this.SyncContextMenu_LatestGoodChange.Text = "Latest Good Change"; - this.SyncContextMenu_LatestGoodChange.Click += new System.EventHandler(this.SyncContextMenu_LatestGoodChange_Click); - // - // SyncContextMenu_LatestStarredChange - // - this.SyncContextMenu_LatestStarredChange.Name = "SyncContextMenu_LatestStarredChange"; - this.SyncContextMenu_LatestStarredChange.Size = new System.Drawing.Size(189, 22); - this.SyncContextMenu_LatestStarredChange.Text = "Latest Starred Change"; - // - // toolStripSeparator8 - // - this.toolStripSeparator8.Name = "toolStripSeparator8"; - this.toolStripSeparator8.Size = new System.Drawing.Size(186, 6); - // - // SyncContexMenu_EnterChangelist - // - this.SyncContexMenu_EnterChangelist.Name = "SyncContexMenu_EnterChangelist"; - this.SyncContexMenu_EnterChangelist.Size = new System.Drawing.Size(189, 22); - this.SyncContexMenu_EnterChangelist.Text = "Specific Changelist..."; - this.SyncContexMenu_EnterChangelist.Click += new System.EventHandler(this.SyncContextMenu_EnterChangelist_Click); - // - // StreamContextMenu - // - this.StreamContextMenu.Name = "StreamContextMenu"; - this.StreamContextMenu.Size = new System.Drawing.Size(61, 4); - // - // OptionsContextMenu_PerforceSettings - // - this.OptionsContextMenu_PerforceSettings.Name = "OptionsContextMenu_PerforceSettings"; - this.OptionsContextMenu_PerforceSettings.Size = new System.Drawing.Size(267, 22); - this.OptionsContextMenu_PerforceSettings.Text = "Perforce Settings..."; - this.OptionsContextMenu_PerforceSettings.Click += new System.EventHandler(this.OptionsContextMenu_PerforceSettings_Click); + this.TabControl.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.TabControl.Location = new System.Drawing.Point(16, 13); + this.TabControl.Name = "TabControl"; + this.TabControl.Size = new System.Drawing.Size(1140, 31); + this.TabControl.TabIndex = 2; + this.TabControl.Text = "TabControl"; // // MainWindow // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(1168, 652); - this.Controls.Add(this.tableLayoutPanel2); + this.Controls.Add(this.TabPanel); + this.Controls.Add(this.TabControl); this.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.MinimumSize = new System.Drawing.Size(800, 350); @@ -959,126 +239,38 @@ namespace UnrealGameSync this.Activated += new System.EventHandler(this.MainWindow_Activated); this.Deactivate += new System.EventHandler(this.MainWindow_Deactivate); this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainWindow_FormClosing); - this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.MainWindow_FormClosed); this.Load += new System.EventHandler(this.MainWindow_Load); - this.OptionsContextMenu.ResumeLayout(false); - this.BuildListContextMenu.ResumeLayout(false); this.NotifyMenu.ResumeLayout(false); - this.flowLayoutPanel1.ResumeLayout(false); - this.flowLayoutPanel1.PerformLayout(); - this.tableLayoutPanel1.ResumeLayout(false); - this.tableLayoutPanel1.PerformLayout(); - this.tableLayoutPanel3.ResumeLayout(false); - this.tableLayoutPanel3.PerformLayout(); - this.tableLayoutPanel2.ResumeLayout(false); - this.tableLayoutPanel2.PerformLayout(); - this.Splitter.Panel1.ResumeLayout(false); - this.Splitter.Panel2.ResumeLayout(false); - ((System.ComponentModel.ISupportInitialize)(this.Splitter)).EndInit(); - this.Splitter.ResumeLayout(false); - this.tableLayoutPanel4.ResumeLayout(false); - this.panel1.ResumeLayout(false); - this.MoreToolsContextMenu.ResumeLayout(false); - this.SyncContextMenu.ResumeLayout(false); + this.TabPanel.ResumeLayout(false); + this.TabMenu.ResumeLayout(false); this.ResumeLayout(false); } #endregion - private BuildListControl BuildList; - private LogControl SyncLog; - private System.Windows.Forms.ColumnHeader IconColumn; - private System.Windows.Forms.ColumnHeader TimeColumn; - private System.Windows.Forms.Label label1; - private System.Windows.Forms.ComboBox ProjectList; - private System.Windows.Forms.Button BrowseProject; - private System.Windows.Forms.ColumnHeader DescriptionColumn; - private System.Windows.Forms.ColumnHeader StatusColumn; - private System.Windows.Forms.ColumnHeader ChangeColumn; - private System.Windows.Forms.ColumnHeader AuthorColumn; - private System.Windows.Forms.Button OptionsButton; - private System.Windows.Forms.ContextMenuStrip OptionsContextMenu; - private System.Windows.Forms.CheckBox OnlyShowReviewedCheckBox; - private System.Windows.Forms.CheckBox RunAfterSyncCheckBox; - private System.Windows.Forms.CheckBox BuildAfterSyncCheckBox; - private System.Windows.Forms.Label AfterSyncingLabel; - private System.Windows.Forms.ContextMenuStrip BuildListContextMenu; - private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_Cancel; - private LogSplitContainer Splitter; - private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_MoreInfo; - private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_AddStar; - private System.Windows.Forms.ToolStripSeparator toolStripSeparator2; - private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_MarkGood; - private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_MarkBad; - private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_StartInvestigating; - private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_Sync; - private System.Windows.Forms.ToolStripSeparator toolStripSeparator4; private System.Windows.Forms.NotifyIcon NotifyIcon; private System.Windows.Forms.ContextMenuStrip NotifyMenu; private System.Windows.Forms.ToolStripMenuItem NotifyMenu_OpenUnrealGameSync; private System.Windows.Forms.ToolStripSeparator NotifyMenu_ExitSeparator; private System.Windows.Forms.ToolStripMenuItem NotifyMenu_Exit; - private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_RemoveStar; - private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_FinishInvestigating; - private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; - private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_LaunchEditor; - private System.Windows.Forms.ToolTip BuildListToolTip; - private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_AutoResolveConflicts; - private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_EditorArguments; - private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_OpenVisualStudio; - private System.Windows.Forms.Panel panel1; - private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_Build; - private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_GenerateProjectFiles; - private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_EditorBuildConfiguration; - private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_BuildConfig_Debug; - private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_BuildConfig_DebugGame; - private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_BuildConfig_Development; - private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_UseIncrementalBuilds; - private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_Rebuild; - private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_WithdrawReview; - private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_ScheduledSync; - private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_LeaveComment; - private System.Windows.Forms.ToolStripSeparator toolStripSeparator7; private System.Windows.Forms.ToolStripMenuItem NotifyMenu_SyncNow; private System.Windows.Forms.ToolStripMenuItem NotifyMenu_LaunchEditor; - private System.Windows.Forms.ColumnHeader CISColumn; - private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_EditComment; - private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; - private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; - private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3; - private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; - private System.Windows.Forms.ToolStripSeparator BuildListContextMenu_TimeZoneSeparator; - private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_ShowServerTimes; - private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_ShowLocalTimes; - private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_CustomizeBuildSteps; - private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_TimeZone; - private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_TimeZone_Local; - private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_TimeZone_PerforceServer; - private System.Windows.Forms.CheckBox OpenSolutionAfterSyncCheckBox; - private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_AutomaticallyRunAtStartup; - private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_SyncPrecompiledEditor; - private System.Windows.Forms.TableLayoutPanel tableLayoutPanel4; - private StatusPanel StatusPanel; - private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_SyncContentOnly; - private System.Windows.Forms.ContextMenuStrip MoreToolsContextMenu; - private System.Windows.Forms.ToolStripMenuItem MoreToolsContextMenu_CleanWorkspace; - private System.Windows.Forms.ToolStripSeparator MoreActionsContextMenu_CustomToolSeparator; - private System.Windows.Forms.ToolStripSeparator toolStripSeparator3; - private System.Windows.Forms.ToolStripSeparator toolStripSeparator5; - private System.Windows.Forms.ToolStripSeparator toolStripSeparator6; - private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_Diagnostics; - private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_SyncFilter; - private System.Windows.Forms.ToolStripMenuItem BuildListContextMenu_SyncOnlyThisChange; - private System.Windows.Forms.ContextMenuStrip SyncContextMenu; - private System.Windows.Forms.ToolStripMenuItem SyncContextMenu_LatestChange; - private System.Windows.Forms.ToolStripMenuItem SyncContextMenu_LatestGoodChange; - private System.Windows.Forms.ToolStripSeparator toolStripSeparator8; - private System.Windows.Forms.ToolStripMenuItem SyncContexMenu_EnterChangelist; - private System.Windows.Forms.ToolStripMenuItem SyncContextMenu_LatestStarredChange; - private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_KeepInTray; - private System.Windows.Forms.ContextMenuStrip StreamContextMenu; - private System.Windows.Forms.ToolStripMenuItem OptionsContextMenu_PerforceSettings; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; + private TabControl TabControl; + private System.Windows.Forms.Panel TabPanel; + private StatusPanel DefaultControl; + private System.Windows.Forms.ContextMenuStrip TabMenu; + private System.Windows.Forms.ToolStripMenuItem labelsToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem TabMenu_TabNames_Stream; + private System.Windows.Forms.ToolStripMenuItem TabMenu_TabNames_WorkspaceName; + private System.Windows.Forms.ToolStripMenuItem TabMenu_TabNames_WorkspaceRoot; + private System.Windows.Forms.ToolStripMenuItem TabMenu_TabNames_ProjectFile; + private System.Windows.Forms.ToolStripMenuItem TabMenu_OpenProject; + private System.Windows.Forms.ToolStripMenuItem TabMenu_RecentProjects; + private System.Windows.Forms.ToolStripSeparator TabMenu_Recent_Separator; + private System.Windows.Forms.ToolStripMenuItem TabMenu_RecentProjects_ClearList; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator2; } } diff --git a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Forms/MainWindow.cs b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Forms/MainWindow.cs index c6cff145ac58..ce40e3260f90 100644 --- a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Forms/MainWindow.cs +++ b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Forms/MainWindow.cs @@ -14,6 +14,7 @@ using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Text; +using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Windows.Forms; using System.Windows.Forms.VisualStyles; @@ -23,142 +24,154 @@ using EventWaitHandle = System.Threading.EventWaitHandle; namespace UnrealGameSync { - public enum LatestChangeType + partial class MainWindow : Form, IWorkspaceControlOwner { - Any, - Good, - Starred, - } - - partial class MainWindow : Form - { - static Rectangle GoodBuildIcon = new Rectangle(0, 0, 16, 16); - static Rectangle MixedBuildIcon = new Rectangle(16, 0, 16, 16); - static Rectangle BadBuildIcon = new Rectangle(32, 0, 16, 16); - static Rectangle DefaultBuildIcon = new Rectangle(48, 0, 16, 16); - static Rectangle PromotedBuildIcon = new Rectangle(64, 0, 16, 16); - static Rectangle DetailsIcon = new Rectangle(80, 0, 16, 16); - static Rectangle InfoIcon = new Rectangle(96, 0, 16, 16); - static Rectangle CancelIcon = new Rectangle(112, 0, 16, 16); - static Rectangle SyncIcon = new Rectangle(128, 0, 32, 16); - static Rectangle HappyIcon = new Rectangle(160, 0, 16, 16); - static Rectangle DisabledHappyIcon = new Rectangle(176, 0, 16, 16); - static Rectangle FrownIcon = new Rectangle(192, 0, 16, 16); - static Rectangle DisabledFrownIcon = new Rectangle(208, 0, 16, 16); - static Rectangle PreviousSyncIcon = new Rectangle(224, 0, 16, 16); - static Rectangle AdditionalSyncIcon = new Rectangle(240, 0, 16, 16); - [DllImport("uxtheme.dll", CharSet = CharSet.Unicode)] static extern int SetWindowTheme(IntPtr hWnd, string pszSubAppName, string pszSubIdList); - const string EditorArchiveType = "Editor"; + [DllImport("user32.dll")] + public static extern int SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, Int32 lParam); + + private const int WM_SETREDRAW = 11; UpdateMonitor UpdateMonitor; - ActivationListener ActivationListener; string SqlConnectionString; string DataFolder; + ActivationListener ActivationListener; BoundedLogWriter Log; - UserSettings Settings; + int TabMenu_TabIndex = -1; - string SelectedFileName; - string SelectedProjectIdentifier; - string BranchDirectoryName; - string StreamName; - string EditorTargetName; - PerforceMonitor PerforceMonitor; - Workspace Workspace; - EventMonitor EventMonitor; - Timer UpdateTimer; - HashSet PromotedChangeNumbers = new HashSet(); - List ListIndexToChangeIndex = new List(); - List SortedChangeNumbers = new List(); - Dictionary ChangeNumberToArchivePath = new Dictionary(); - List CustomToolMenuItems = new List(); - int NumChanges; - int PendingSelectedChangeNumber = -1; - bool bHasBuildSteps = false; - - Dictionary NotifiedBuildTypeToChangeNumber = new Dictionary(); - - TimeSpan ServerTimeZone; - - int HoverItem = -1; - BuildData HoverBadge; - bool bHoverSync; - PerforceChangeSummary ContextMenuChange; - VisualStyleRenderer SelectedItemRenderer; - VisualStyleRenderer TrackedItemRenderer; - Font BuildFont; - Font SelectedBuildFont; - Font BadgeFont; - bool bUnstable; bool bAllowClose = false; + bool bUnstable; bool bRestoreStateOnLoad; System.Threading.Timer ScheduleTimer; string OriginalExecutableFileName; - NotificationWindow NotificationWindow; + WorkspaceControl CurrentWorkspace; - public MainWindow(UpdateMonitor InUpdateMonitor, string InSqlConnectionString, string InDataFolder, EventWaitHandle ActivateEvent, bool bInRestoreStateOnLoad, string InOriginalExecutableFileName, string InProjectFileName, bool bInUnstable) + public MainWindow(UpdateMonitor InUpdateMonitor, string InSqlConnectionString, string InDataFolder, EventWaitHandle ActivateEvent, bool bInRestoreStateOnLoad, string InOriginalExecutableFileName, string InProjectFileName, bool bInUnstable, BoundedLogWriter InLog, UserSettings InSettings) { InitializeComponent(); NotifyMenu_OpenUnrealGameSync.Font = new Font(NotifyMenu_OpenUnrealGameSync.Font, FontStyle.Bold); - if (Application.RenderWithVisualStyles) - { - SelectedItemRenderer = new VisualStyleRenderer("Explorer::ListView", 1, 3); - TrackedItemRenderer = new VisualStyleRenderer("Explorer::ListView", 1, 2); - } - UpdateMonitor = InUpdateMonitor; - ActivationListener = new ActivationListener(ActivateEvent); SqlConnectionString = InSqlConnectionString; DataFolder = InDataFolder; + ActivationListener = new ActivationListener(ActivateEvent); bRestoreStateOnLoad = bInRestoreStateOnLoad; OriginalExecutableFileName = InOriginalExecutableFileName; bUnstable = bInUnstable; - - Log = new BoundedLogWriter(Path.Combine(DataFolder, "UnrealGameSync.log")); - Log.WriteLine("Application version: {0}", Assembly.GetExecutingAssembly().GetName().Version); - Log.WriteLine("Started at {0}", DateTime.Now.ToString()); + Log = InLog; + Settings = InSettings; - Settings = new UserSettings(Path.Combine(DataFolder, "UnrealGameSync.ini")); - if(!String.IsNullOrEmpty(InProjectFileName)) + TabControl.OnTabChanged += TabControl_OnTabChanged; + TabControl.OnNewTabClick += TabControl_OnNewTabClick; + TabControl.OnTabClicked += TabControl_OnTabClicked; + TabControl.OnTabClosing += TabControl_OnTabClosing; + TabControl.OnTabClosed += TabControl_OnTabClosed; + TabControl.OnTabReorder += TabControl_OnTabReorder; + + SetupDefaultControl(); + + int SelectTabIdx = -1; + foreach(string ProjectFileName in Settings.OpenProjectFileNames) { - Settings.LastProjectFileName = InProjectFileName; + if(!String.IsNullOrEmpty(ProjectFileName)) + { + int TabIdx = TryOpenProject(ProjectFileName); + if(TabIdx != -1 && Settings.LastProjectFileName != null && ProjectFileName.Equals(Settings.LastProjectFileName, StringComparison.InvariantCultureIgnoreCase)) + { + SelectTabIdx = TabIdx; + } + } } - System.Reflection.PropertyInfo DoubleBufferedProperty = typeof(Control).GetProperty("DoubleBuffered", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); - DoubleBufferedProperty.SetValue(BuildList, true, null); + if(SelectTabIdx != -1) + { + TabControl.SelectTab(SelectTabIdx); + } + else if(TabControl.GetTabCount() > 0) + { + TabControl.SelectTab(0); + } + } - // force the height of the rows - BuildList.SmallImageList = new ImageList(){ ImageSize = new Size(1, 20) }; - BuildList_FontChanged(null, null); - BuildList.OnScroll += BuildList_OnScroll; + void TabControl_OnTabClicked(object TabData, Point Location, MouseButtons Buttons) + { + if(Buttons == System.Windows.Forms.MouseButtons.Right) + { + Activate(); - Splitter.OnVisibilityChanged += Splitter_OnVisibilityChanged; - - UpdateTimer = new Timer(); - UpdateTimer.Interval = 30; - UpdateTimer.Tick += TimerCallback; + int InsertIdx = 0; - BuildAfterSyncCheckBox.Checked = Settings.bBuildAfterSync; - RunAfterSyncCheckBox.Checked = Settings.bRunAfterSync; - OpenSolutionAfterSyncCheckBox.Checked = Settings.bOpenSolutionAfterSync; - Splitter.SetLogVisibility(Settings.bShowLogWindow); - OptionsContextMenu_AutoResolveConflicts.Checked = Settings.bAutoResolveConflicts; - OptionsContextMenu_UseIncrementalBuilds.Checked = Settings.bUseIncrementalBuilds; - OptionsContextMenu_SyncPrecompiledEditor.Checked = Settings.bSyncPrecompiledEditor; - - UpdateCheckedBuildConfig(); + while(TabMenu_RecentProjects.DropDownItems[InsertIdx] != TabMenu_Recent_Separator) + { + TabMenu_RecentProjects.DropDownItems.RemoveAt(InsertIdx); + } - UpdateProjectList(); - UpdateSyncActionCheckboxes(); + TabMenu_TabIndex = -1; + for(int Idx = 0; Idx < TabControl.GetTabCount(); Idx++) + { + if(TabControl.GetTabData(Idx) == TabData) + { + TabMenu_TabIndex = Idx; + break; + } + } + + HashSet ProjectList = new HashSet(StringComparer.InvariantCultureIgnoreCase); + foreach(string ProjectFileName in Settings.OtherProjectFileNames) + { + if(!String.IsNullOrEmpty(ProjectFileName)) + { + string FullProjectFileName = Path.GetFullPath(ProjectFileName); + if(ProjectList.Add(FullProjectFileName)) + { + ToolStripMenuItem Item = new ToolStripMenuItem(FullProjectFileName, null, new EventHandler((o, e) => TryOpenProject(FullProjectFileName, TabMenu_TabIndex))); + TabMenu_RecentProjects.DropDownItems.Insert(InsertIdx, Item); + InsertIdx++; + } + } + } + + TabMenu_RecentProjects.Visible = (ProjectList.Count > 0); + + TabMenu_TabNames_Stream.Checked = Settings.TabLabels == TabLabels.Stream; + TabMenu_TabNames_WorkspaceName.Checked = Settings.TabLabels == TabLabels.WorkspaceName; + TabMenu_TabNames_WorkspaceRoot.Checked = Settings.TabLabels == TabLabels.WorkspaceRoot; + TabMenu_TabNames_ProjectFile.Checked = Settings.TabLabels == TabLabels.ProjectFile; + TabMenu.Show(TabControl, Location); + + TabControl.LockHover(); + } + } + + void TabControl_OnTabReorder() + { + SaveTabSettings(); + } + + void TabControl_OnTabClosed(object Data) + { + WorkspaceControl Workspace = (WorkspaceControl)Data; + if(CurrentWorkspace == Workspace) + { + CurrentWorkspace = null; + } + Workspace.Dispose(); + + SaveTabSettings(); + } + + bool TabControl_OnTabClosing(object TabData) + { + WorkspaceControl Workspace = (WorkspaceControl)TabData; + return Workspace.CanClose(); } /// @@ -172,31 +185,16 @@ namespace UnrealGameSync components.Dispose(); } + for(int Idx = 0; Idx < TabControl.GetTabCount(); Idx++) + { + ((WorkspaceControl)TabControl.GetTabData(Idx)).Dispose(); + } + if(ActivationListener != null) { ActivationListener.Dispose(); ActivationListener = null; } - if(Log != null) - { - Log.Dispose(); - Log = null; - } - if(BuildFont != null) - { - BuildFont.Dispose(); - BuildFont = null; - } - if(SelectedBuildFont != null) - { - SelectedBuildFont.Dispose(); - SelectedBuildFont = null; - } - if(BadgeFont != null) - { - BadgeFont.Dispose(); - BadgeFont = null; - } StopScheduleTimer(); @@ -212,21 +210,6 @@ namespace UnrealGameSync { Location = WindowRectangle.Location; Size = WindowRectangle.Size; - - for(int Idx = 0; Idx < BuildList.Columns.Count; Idx++) - { - string ColumnName = BuildList.Columns[Idx].Text; - if(String.IsNullOrEmpty(ColumnName)) - { - ColumnName = String.Format("Column{0}", Idx); - } - - int ColumnWidth; - if(Settings.ColumnWidths.TryGetValue(ColumnName, out ColumnWidth)) - { - BuildList.Columns[Idx].Width = ColumnWidth; - } - } } if(bRestoreStateOnLoad && !Settings.bWindowVisible) @@ -241,14 +224,7 @@ namespace UnrealGameSync ActivationListener.Start(); ActivationListener.OnActivate += OnActivationListenerAsyncCallback; - string LastProjectFileName = Settings.LastProjectFileName; - if (LastProjectFileName != null && File.Exists(LastProjectFileName)) - { - OpenProject(LastProjectFileName); - } - StartScheduleTimer(); - UpdateStatusPanel(); } private void MainWindow_FormClosing(object Sender, FormClosingEventArgs EventArgs) @@ -258,12 +234,18 @@ namespace UnrealGameSync Hide(); EventArgs.Cancel = true; } - else if(!TryCloseProject()) - { - EventArgs.Cancel = true; - } else { + for(int Idx = 0; Idx < TabControl.GetTabCount(); Idx++) + { + WorkspaceControl Workspace = (WorkspaceControl)TabControl.GetTabData(Idx); + if(!Workspace.CanClose()) + { + EventArgs.Cancel = true; + return; + } + } + ActivationListener.OnActivate -= OnActivationListenerAsyncCallback; ActivationListener.Stop(); @@ -276,22 +258,26 @@ namespace UnrealGameSync Settings.WindowRectangle = SaveBounds; Settings.bWindowVisible = Visible; - Settings.ColumnWidths.Clear(); - for(int Idx = 0; Idx < BuildList.Columns.Count; Idx++) - { - string ColumnName = BuildList.Columns[Idx].Text; - if(String.IsNullOrEmpty(ColumnName)) - { - ColumnName = String.Format("Column{0}", Idx); - } - Settings.ColumnWidths[ColumnName] = BuildList.Columns[Idx].Width; - } - Settings.Save(); } } - private void ShowAndActivate() + private void SetupDefaultControl() + { + List Lines = new List(); + + StatusLine SummaryLine = new StatusLine(); + SummaryLine.AddText("To get started, open an existing Unreal project file on your hard drive."); + Lines.Add(SummaryLine); + + StatusLine OpenLine = new StatusLine(); + OpenLine.AddLink("Open project...", FontStyle.Bold | FontStyle.Underline, () => { BrowseForProject(); }); + Lines.Add(OpenLine); + + DefaultControl.Set(Lines); + } + + public void ShowAndActivate() { Show(); Activate(); @@ -315,11 +301,6 @@ namespace UnrealGameSync BeginInvoke(new MethodInvoker(OnActivationListenerCallback)); } - private void MainWindow_FormClosed(object sender, FormClosedEventArgs e) - { - CloseProject(); - } - private void OnUpdateAvailableCallback() { BeginInvoke(new MethodInvoker(OnUpdateAvailable)); @@ -329,11 +310,17 @@ namespace UnrealGameSync { if(!ContainsFocus && Form.ActiveForm != this) { - if(Workspace == null || !Workspace.IsBusy()) + for(int TabIdx = 0; TabIdx < TabControl.GetTabCount(); TabIdx++) { - bAllowClose = true; - Close(); + WorkspaceControl Workspace = (WorkspaceControl)TabControl.GetTabData(TabIdx); + if(Workspace.IsBusy()) + { + return; + } } + + bAllowClose = true; + Close(); } } @@ -344,1911 +331,17 @@ namespace UnrealGameSync MessageBox.Show(Message); } - private bool OpenProject(string NewSelectedFileName) - { - if(String.IsNullOrWhiteSpace(NewSelectedFileName)) - { - Log.WriteLine("Trying to open empty project path - closing instead"); - return TryCloseProject(); - } - - Log.WriteLine("Trying to open project {0}", NewSelectedFileName); - if(!File.Exists(NewSelectedFileName)) - { - ShowErrorDialog("{0} does not exist.", NewSelectedFileName); - return false; - } - - // Make sure the path case is correct. This can cause UBT intermediates to be out of date if the case mismatches. - NewSelectedFileName = Utility.GetPathWithCorrectCase(new FileInfo(NewSelectedFileName)); - - // Detect the project settings in a background thread - using(DetectProjectSettingsTask DetectSettings = new DetectProjectSettingsTask(NewSelectedFileName, Log)) - { - string ErrorMessage; - if(!ModalTaskWindow.Execute(DetectSettings, "Opening Project", "Opening project, please wait...", out ErrorMessage)) - { - if(!String.IsNullOrEmpty(ErrorMessage)) - { - ShowErrorDialog("{0}", ErrorMessage); - } - return false; - } - - // Now that we've done everything that can fail, perform the final switch over - if(!TryCloseProject()) - { - return false; - } - - // Set the project logo on the status panel and notification window - NotificationWindow = new NotificationWindow(Properties.Resources.DefaultNotificationLogo); - StatusPanel.SetProjectLogo(DetectSettings.ProjectLogo); - DetectSettings.ProjectLogo = null; - - // Update the user settings for the new project - Settings.OpenProject(DetectSettings.BranchClientPath, DetectSettings.NewSelectedClientFileName); - - // Commit all the new project info - PerforceConnection PerforceClient = DetectSettings.PerforceClient; - SelectedFileName = NewSelectedFileName; - SelectedProjectIdentifier = DetectSettings.NewSelectedProjectIdentifier; - EditorTargetName = DetectSettings.NewProjectEditorTarget; - BranchDirectoryName = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(DetectSettings.BaseEditorTargetPath), "..", "..")); - StreamName = DetectSettings.StreamName; - ServerTimeZone = DetectSettings.ServerTimeZone; - - // Check if we've the project we've got open in this workspace is the one we're actually synced to - int CurrentChangeNumber = -1; - if(String.Compare(Settings.CurrentWorkspace.CurrentProjectIdentifier, SelectedProjectIdentifier, true) == 0) - { - CurrentChangeNumber = Settings.CurrentWorkspace.CurrentChangeNumber; - } - - string ProjectLogBaseName = Path.Combine(DataFolder, String.Format("{0}@{1}", PerforceClient.ClientName, DetectSettings.BranchClientPath.Replace("//" + PerforceClient.ClientName + "/", "").Trim('/').Replace("/", "$"))); - - string TelemetryProjectIdentifier = PerforceUtils.GetClientOrDepotDirectoryName(DetectSettings.NewSelectedProjectIdentifier); - - Workspace = new Workspace(PerforceClient, BranchDirectoryName, SelectedFileName, DetectSettings.BranchClientPath, DetectSettings.NewSelectedClientFileName, CurrentChangeNumber, Settings.CurrentWorkspace.LastBuiltChangeNumber, TelemetryProjectIdentifier, new LogControlTextWriter(SyncLog)); - Workspace.OnUpdateComplete += UpdateCompleteCallback; - - PerforceMonitor = new PerforceMonitor(PerforceClient, DetectSettings.BranchClientPath, DetectSettings.NewSelectedClientFileName, SelectedProjectIdentifier, ProjectLogBaseName + ".p4.log"); - PerforceMonitor.OnUpdate += UpdateBuildListCallback; - PerforceMonitor.OnUpdateMetadata += UpdateBuildMetadataCallback; - PerforceMonitor.OnStreamChange += StreamChangedCallbackAsync; - - EventMonitor = new EventMonitor(SqlConnectionString, PerforceUtils.GetClientOrDepotDirectoryName(SelectedProjectIdentifier), DetectSettings.PerforceClient.UserName, ProjectLogBaseName + ".review.log"); - EventMonitor.OnUpdatesReady += UpdateReviewsCallback; - - string LogFileName = Path.Combine(DataFolder, ProjectLogBaseName + ".sync.log"); - SyncLog.OpenFile(LogFileName); - - ProjectList.Text = NewSelectedFileName; - UpdateProjectList(); - - Settings.LastProjectFileName = SelectedFileName; - Settings.Save(); - - BuildList.Items.Clear(); - UpdateBuildList(); - UpdateBuildSteps(); - UpdateSyncActionCheckboxes(); - UpdateStatusPanel(); - - if(CurrentChangeNumber != -1) - { - SelectChange(CurrentChangeNumber); - } - } - return true; - } - - private bool TryCloseProject() - { - if(Workspace != null) - { - CancelWorkspaceUpdate(); - if(Workspace.IsBusy()) - { - return false; - } - } - CloseProject(); - return true; - } - - private void StreamChangedCallback() - { - StatusPanel.SuspendDisplay(); - - string PrevSelectedFileName = SelectedFileName; - if(TryCloseProject()) - { - OpenProject(PrevSelectedFileName); - } - - StatusPanel.ResumeDisplay(); - } - - private void StreamChangedCallbackAsync() - { - BeginInvoke(new MethodInvoker(StreamChangedCallback)); - } - - private void CloseProject() - { - UpdateTimer.Stop(); - - BuildList.Items.Clear(); - BuildList.Groups.Clear(); - - SelectedFileName = null; - SelectedProjectIdentifier = null; - BranchDirectoryName = null; - EditorTargetName = null; - - if(NotificationWindow != null) - { - NotificationWindow.Dispose(); - NotificationWindow = null; - } - if(PerforceMonitor != null) - { - PerforceMonitor.Dispose(); - PerforceMonitor = null; - } - if(Workspace != null) - { - Workspace.Dispose(); - Workspace = null; - } - if(EventMonitor != null) - { - EventMonitor.Dispose(); - EventMonitor = null; - } - - ListIndexToChangeIndex = new List(); - SortedChangeNumbers = new List(); - NumChanges = 0; - ContextMenuChange = null; - HoverItem = -1; - PendingSelectedChangeNumber = -1; - NotifiedBuildTypeToChangeNumber = new Dictionary(); - - SyncLog.CloseFile(); - SyncLog.Clear(); - - UpdateBuildSteps(); - - StatusPanel.SetProjectLogo(null); - UpdateStatusPanel(); - - Taskbar.SetState(Handle, TaskbarState.NoProgress); - } - - private void UpdateProjectList() - { - string PrevSelectedText = ProjectList.Text; - - List ProjectFileNames = new List(); - ProjectFileNames.Add(ProjectList.Text); - ProjectFileNames.AddRange(Settings.OtherProjectFileNames); - - HashSet UniqueProjectFileNames = new HashSet(StringComparer.InvariantCultureIgnoreCase); - foreach(string ProjectFileName in ProjectFileNames) - { - if(!String.IsNullOrEmpty(ProjectFileName) && File.Exists(ProjectFileName)) - { - UniqueProjectFileNames.Add(Path.GetFullPath(ProjectFileName)); - } - } - - string[] NewProjectFileNames = UniqueProjectFileNames.OrderBy(x => x).ToArray(); - ProjectList.Items.Clear(); - ProjectList.Items.AddRange(NewProjectFileNames); - if(NewProjectFileNames.Length > 0) - { - ProjectList.Items.Add("Clear List"); - } - Settings.OtherProjectFileNames = NewProjectFileNames; - - ProjectList.Text = PrevSelectedText; - } - - private void UpdateSyncConfig(int ChangeNumber) - { - Settings.CurrentWorkspace.CurrentProjectIdentifier = SelectedProjectIdentifier; - Settings.CurrentWorkspace.CurrentChangeNumber = ChangeNumber; - if(ChangeNumber == -1 || ChangeNumber != Settings.CurrentWorkspace.CurrentChangeNumber) - { - Settings.CurrentWorkspace.AdditionalChangeNumbers.Clear(); - } - Settings.Save(); - } - - private void BuildList_OnScroll() - { - PendingSelectedChangeNumber = -1; - UpdateNumRequestedBuilds(false); - } - - void UpdateNumRequestedBuilds(bool bAllowShrink) - { - if(PerforceMonitor != null) - { - if(OnlyShowReviewedCheckBox.Checked) - { - PerforceMonitor.PendingMaxChanges = 1000; - } - else - { - int NumItemsPerPage = Math.Max(BuildList.GetVisibleItemsPerPage(), 10); - - // Find the number of visible items using a (slightly wasteful) binary search - int VisibleItemCount = 1; - for(int StepSize = BuildList.Items.Count / 2; StepSize >= 1; ) - { - int TestIndex = VisibleItemCount + StepSize; - if(TestIndex < BuildList.Items.Count && BuildList.GetItemRect(TestIndex).Top < BuildList.Height) - { - VisibleItemCount += StepSize; - } - else - { - StepSize /= 2; - } - } - - // Increase or decrease the number of builds we want, with a bit of rubber-banding - const int IncreaseStep = 50; - if(VisibleItemCount > BuildList.Items.Count - 20) - { - PerforceMonitor.PendingMaxChanges = NumChanges + IncreaseStep; - } - else if(bAllowShrink) - { - int NewNumChanges = ListIndexToChangeIndex[VisibleItemCount - 1] + IncreaseStep; - if(NewNumChanges < NumChanges) - { - PerforceMonitor.PendingMaxChanges = NewNumChanges; - } - } - } - } - } - - void StartSync(int ChangeNumber) - { - WorkspaceUpdateOptions Options = WorkspaceUpdateOptions.Sync | WorkspaceUpdateOptions.SyncArchives | WorkspaceUpdateOptions.GenerateProjectFiles; - if(OptionsContextMenu_AutoResolveConflicts.Checked) - { - Options |= WorkspaceUpdateOptions.AutoResolveChanges; - } - if(OptionsContextMenu_UseIncrementalBuilds.Checked) - { - Options |= WorkspaceUpdateOptions.UseIncrementalBuilds; - } - if(BuildAfterSyncCheckBox.Checked) - { - Options |= WorkspaceUpdateOptions.Build; - } - if(BuildAfterSyncCheckBox.Checked && RunAfterSyncCheckBox.Checked) - { - Options |= WorkspaceUpdateOptions.RunAfterSync; - } - if(OpenSolutionAfterSyncCheckBox.Checked) - { - Options |= WorkspaceUpdateOptions.OpenSolutionAfterSync; - } - StartWorkspaceUpdate(ChangeNumber, Options); - } - - void StartWorkspaceUpdate(int ChangeNumber, WorkspaceUpdateOptions Options) - { - if((Options & (WorkspaceUpdateOptions.Sync | WorkspaceUpdateOptions.Build)) != 0 && IsEditorRunning(GetEditorBuildConfig())) - { - MessageBox.Show("Please close the editor before trying to sync/build.", "Editor Open"); - return; - } - - WorkspaceUpdateContext Context = new WorkspaceUpdateContext(ChangeNumber, Options, Settings.GetCombinedSyncFilter(), GetDefaultBuildStepObjects(), Settings.CurrentProject.BuildSteps, null, GetWorkspaceVariables()); - if(Options.HasFlag(WorkspaceUpdateOptions.SyncArchives)) - { - string EditorArchivePath = null; - if(ShouldSyncPrecompiledEditor) - { - EditorArchivePath = GetArchivePathForChangeNumber(ChangeNumber); - if(EditorArchivePath == null) - { - MessageBox.Show("There are no compiled editor binaries for this change. To sync it, you must disable syncing of precompiled editor binaries."); - return; - } - } - Context.ArchiveTypeToDepotPath.Add(EditorArchiveType, EditorArchivePath); - } - StartWorkspaceUpdate(Context); - } - - void StartWorkspaceUpdate(WorkspaceUpdateContext Context) - { - Context.StartTime = DateTime.UtcNow; - Context.PerforceSyncOptions = (PerforceSyncOptions)Settings.SyncOptions.Clone(); - - Log.WriteLine(); - Log.WriteLine("Updating workspace at {0}...", Context.StartTime.ToLocalTime().ToString()); - Log.WriteLine(" ChangeNumber={0}", Context.ChangeNumber); - Log.WriteLine(" Options={0}", Context.Options.ToString()); - Log.WriteLine(" Clobbering {0} files", Context.ClobberFiles.Count); - - if(Context.Options.HasFlag(WorkspaceUpdateOptions.Sync)) - { - UpdateSyncConfig(-1); - EventMonitor.PostEvent(Context.ChangeNumber, EventType.Syncing); - } - - if(Context.Options.HasFlag(WorkspaceUpdateOptions.Sync) || Context.Options.HasFlag(WorkspaceUpdateOptions.Build)) - { - if(!Context.Options.HasFlag(WorkspaceUpdateOptions.ContentOnly)) - { - foreach(BuildConfig Config in Enum.GetValues(typeof(BuildConfig))) - { - List EditorReceiptPaths = GetEditorReceiptPaths(Config); - foreach(string EditorReceiptPath in EditorReceiptPaths) - { - if(File.Exists(EditorReceiptPath)) - { - try { File.Delete(EditorReceiptPath); } catch(Exception){ } - } - } - } - } - } - - SyncLog.Clear(); - Workspace.Update(Context); - UpdateSyncActionCheckboxes(); - Refresh(); - UpdateTimer.Start(); - } - - void CancelWorkspaceUpdate() - { - if(Workspace.IsBusy() && MessageBox.Show("Are you sure you want to cancel the current operation?", "Cancel operation", MessageBoxButtons.YesNo) == DialogResult.Yes) - { - Settings.CurrentWorkspace.LastSyncChangeNumber = Workspace.PendingChangeNumber; - Settings.CurrentWorkspace.LastSyncResult = WorkspaceUpdateResult.Canceled; - Settings.CurrentWorkspace.LastSyncResultMessage = null; - Settings.CurrentWorkspace.LastSyncTime = null; - Settings.CurrentWorkspace.LastSyncDurationSeconds = 0; - Settings.Save(); - - Workspace.CancelUpdate(); - - UpdateTimer.Stop(); - - UpdateSyncActionCheckboxes(); - Refresh(); - UpdateSyncConfig(Workspace.CurrentChangeNumber); - UpdateStatusPanel(); - Taskbar.SetState(Handle, TaskbarState.NoProgress); - } - } - - void UpdateCompleteCallback(WorkspaceUpdateContext Context, WorkspaceUpdateResult Result, string ResultMessage) - { - Invoke(new MethodInvoker(() => UpdateComplete(Context, Result, ResultMessage))); - } - - void UpdateComplete(WorkspaceUpdateContext Context, WorkspaceUpdateResult Result, string ResultMessage) - { - UpdateTimer.Stop(); - - UpdateSyncConfig(Workspace.CurrentChangeNumber); - - if(Result == WorkspaceUpdateResult.Success && Context.Options.HasFlag(WorkspaceUpdateOptions.SyncSingleChange)) - { - Settings.CurrentWorkspace.AdditionalChangeNumbers.Add(Context.ChangeNumber); - Settings.Save(); - } - - if(Result == WorkspaceUpdateResult.Success && Settings.CurrentWorkspace.ExpandedArchiveTypes != null) - { - Settings.CurrentWorkspace.ExpandedArchiveTypes = Settings.CurrentWorkspace.ExpandedArchiveTypes.Except(Context.ArchiveTypeToDepotPath.Where(x => x.Value == null).Select(x => x.Key)).ToArray(); - } - - Settings.CurrentWorkspace.LastSyncChangeNumber = Context.ChangeNumber; - Settings.CurrentWorkspace.LastSyncResult = Result; - Settings.CurrentWorkspace.LastSyncResultMessage = ResultMessage; - Settings.CurrentWorkspace.LastSyncTime = DateTime.UtcNow; - Settings.CurrentWorkspace.LastSyncDurationSeconds = (int)(Settings.CurrentWorkspace.LastSyncTime.Value - Context.StartTime).TotalSeconds; - Settings.CurrentWorkspace.LastBuiltChangeNumber = Workspace.LastBuiltChangeNumber; - Settings.Save(); - - if(Result == WorkspaceUpdateResult.FilesToResolve) - { - MessageBox.Show("You have files to resolve after syncing your workspace. Please check P4."); - } - else if(Result == WorkspaceUpdateResult.FilesToClobber) - { - Taskbar.SetState(Handle, TaskbarState.Paused); - - ClobberWindow Window = new ClobberWindow(Context.ClobberFiles); - if(Window.ShowDialog(this) == DialogResult.OK) - { - StartWorkspaceUpdate(Context); - return; - } - } - else if(Result == WorkspaceUpdateResult.FailedToCompileWithCleanWorkspace) - { - EventMonitor.PostEvent(Context.ChangeNumber, EventType.DoesNotCompile); - } - else if(Result == WorkspaceUpdateResult.Success) - { - if(Context.Options.HasFlag(WorkspaceUpdateOptions.Build)) - { - EventMonitor.PostEvent(Context.ChangeNumber, EventType.Compiles); - } - if(Context.Options.HasFlag(WorkspaceUpdateOptions.RunAfterSync)) - { - LaunchEditor(); - } - if(Context.Options.HasFlag(WorkspaceUpdateOptions.OpenSolutionAfterSync)) - { - OpenSolution(); - } - } - - Taskbar.SetState(Handle, (Result == WorkspaceUpdateResult.Success)? TaskbarState.NoProgress : TaskbarState.Error); - - BuildList.Invalidate(); - Refresh(); - UpdateStatusPanel(); - UpdateSyncActionCheckboxes(); - } - - void UpdateBuildListCallback() - { - Invoke(new MethodInvoker(UpdateBuildList)); - } - - void UpdateBuildList() - { - if(SelectedFileName != null) - { - int SelectedChange = (BuildList.SelectedItems.Count > 0)? ((PerforceChangeSummary)BuildList.SelectedItems[0].Tag).Number : -1; - - ChangeNumberToArchivePath.Clear(); - - BuildList.BeginUpdate(); - - foreach(ListViewGroup Group in BuildList.Groups) - { - Group.Name = "xxx " + Group.Name; - } - - int RemoveItems = BuildList.Items.Count; - int RemoveGroups = BuildList.Groups.Count; - - List Changes = PerforceMonitor.GetChanges(); - EventMonitor.FilterChanges(Changes.Select(x => x.Number)); - - PromotedChangeNumbers = PerforceMonitor.GetPromotedChangeNumbers(); - - bool bFirstChange = true; - bool bOnlyShowReviewed = OnlyShowReviewedCheckBox.Checked; - - NumChanges = Changes.Count; - ListIndexToChangeIndex = new List(); - SortedChangeNumbers = new List(); - - for(int ChangeIdx = 0; ChangeIdx < Changes.Count; ChangeIdx++) - { - PerforceChangeSummary Change = Changes[ChangeIdx]; - if(ShouldShowChange(Change) || PromotedChangeNumbers.Contains(Change.Number)) - { - SortedChangeNumbers.Add(Change.Number); - - if(!bOnlyShowReviewed || (!EventMonitor.IsUnderInvestigation(Change.Number) && (ShouldIncludeInReviewedList(Change.Number) || bFirstChange))) - { - bFirstChange = false; - - ListViewGroup Group; - - string GroupName = Change.Date.ToString("D");//"dddd\\,\\ h\\.mmtt"); - for(int Idx = 0;;Idx++) - { - if(Idx == BuildList.Groups.Count) - { - Group = new ListViewGroup(GroupName); - Group.Name = GroupName; - BuildList.Groups.Add(Group); - break; - } - else if(BuildList.Groups[Idx].Name == GroupName) - { - Group = BuildList.Groups[Idx]; - break; - } - } - - DateTime DisplayTime = Change.Date; - if(Settings.bShowLocalTimes) - { - DisplayTime = (DisplayTime - ServerTimeZone).ToLocalTime(); - } - - ListViewItem Item = new ListViewItem(Group); - Item.Tag = Change; - Item.Selected = (Change.Number == SelectedChange); - Item.SubItems.Add(new ListViewItem.ListViewSubItem(Item, String.Format("{0}", Change.Number))); - Item.SubItems.Add(new ListViewItem.ListViewSubItem(Item, DisplayTime.ToString("h\\.mmtt"))); - Item.SubItems.Add(new ListViewItem.ListViewSubItem(Item, FormatUserName(Change.User))); - Item.SubItems.Add(new ListViewItem.ListViewSubItem(Item, Change.Description.Replace('\n', ' '))); - Item.SubItems.Add(new ListViewItem.ListViewSubItem(Item, "")); - Item.SubItems.Add(new ListViewItem.ListViewSubItem(Item, "")); - - // Insert it at the right position within the group - int GroupInsertIdx = 0; - while(GroupInsertIdx < Group.Items.Count && Change.Number < ((PerforceChangeSummary)Group.Items[GroupInsertIdx].Tag).Number) - { - GroupInsertIdx++; - } - Group.Items.Insert(GroupInsertIdx, Item); - - // Insert it at the right place in the list - BuildList.Items.Add(Item); - - // Store off the list index for this change - ListIndexToChangeIndex.Add(ChangeIdx); - } - } - } - - SortedChangeNumbers.Sort(); - - for(int Idx = 0; Idx < RemoveItems; Idx++) - { - BuildList.Items.RemoveAt(0); - } - for(int Idx = 0; Idx < RemoveGroups; Idx++) - { - BuildList.Groups.RemoveAt(0); - } - - BuildList.EndUpdate(); - - if(PendingSelectedChangeNumber != -1) - { - SelectChange(PendingSelectedChangeNumber); - } - } - - if(HoverItem > BuildList.Items.Count) - { - HoverItem = -1; - } - - UpdateBuildFailureNotification(); - - UpdateBuildSteps(); - UpdateSyncActionCheckboxes(); - } - - bool ShouldShowChange(PerforceChangeSummary Change) - { - if(String.Compare(Change.User, "buildmachine", true) == 0 && Change.Description.IndexOf("lightmaps", StringComparison.InvariantCultureIgnoreCase) == -1) - { - return false; - } - return true; - } - - void UpdateBuildMetadataCallback() - { - Invoke(new MethodInvoker(UpdateBuildMetadata)); - } - - void UpdateBuildMetadata() - { - ChangeNumberToArchivePath.Clear(); - BuildList.Invalidate(); - UpdateStatusPanel(); - UpdateBuildFailureNotification(); - } - - bool ShouldIncludeInReviewedList(int ChangeNumber) - { - if(PromotedChangeNumbers.Contains(ChangeNumber)) - { - return true; - } - - EventSummary Review = EventMonitor.GetSummaryForChange(ChangeNumber); - if(Review != null) - { - if(Review.LastStarReview != null && Review.LastStarReview.Type == EventType.Starred) - { - return true; - } - if(Review.Verdict == ReviewVerdict.Good || Review.Verdict == ReviewVerdict.Mixed) - { - return true; - } - } - return false; - } - - void UpdateReviewsCallback() - { - Invoke(new MethodInvoker(UpdateReviews)); - } - - void UpdateReviews() - { - ChangeNumberToArchivePath.Clear(); - EventMonitor.ApplyUpdates(); - Refresh(); - UpdateBuildFailureNotification(); - } - - void UpdateBuildFailureNotification() - { - int LastChangeByCurrentUser = PerforceMonitor.LastChangeByCurrentUser; - int LastCodeChangeByCurrentUser = PerforceMonitor.LastCodeChangeByCurrentUser; - - // Find all the badges which should notify users due to content changes - HashSet ContentBadges = new HashSet(); - if(Workspace != null && Workspace.ProjectConfigFile != null) - { - ContentBadges.UnionWith(Workspace.ProjectConfigFile.GetValues("Notifications.ContentBadges", new string[0])); - } - - // Find the most recent build of each type, and the last time it succeeded - Dictionary TypeToLastBuild = new Dictionary(); - Dictionary TypeToLastSucceededBuild = new Dictionary(); - for(int Idx = SortedChangeNumbers.Count - 1; Idx >= 0; Idx--) - { - EventSummary Summary = EventMonitor.GetSummaryForChange(SortedChangeNumbers[Idx]); - if(Summary != null) - { - foreach(BuildData Build in Summary.Builds) - { - if(!TypeToLastBuild.ContainsKey(Build.BuildType) && (Build.Result == BuildDataResult.Success || Build.Result == BuildDataResult.Warning || Build.Result == BuildDataResult.Failure)) - { - TypeToLastBuild.Add(Build.BuildType, Build); - } - if(!TypeToLastSucceededBuild.ContainsKey(Build.BuildType) && Build.Result == BuildDataResult.Success) - { - TypeToLastSucceededBuild.Add(Build.BuildType, Build); - } - } - } - } - - // Find all the build types that the user needs to be notified about. - int RequireNotificationForChange = -1; - List NotifyBuilds = new List(); - foreach(BuildData LastBuild in TypeToLastBuild.Values.OrderBy(x => x.BuildType)) - { - if(LastBuild.Result == BuildDataResult.Failure || LastBuild.Result == BuildDataResult.Warning) - { - // Get the last submitted changelist by this user of the correct type - int LastChangeByCurrentUserOfType; - if(ContentBadges.Contains(LastBuild.BuildType)) - { - LastChangeByCurrentUserOfType = LastChangeByCurrentUser; - } - else - { - LastChangeByCurrentUserOfType = LastCodeChangeByCurrentUser; - } - - // Check if the failed build was after we submitted - if(LastChangeByCurrentUserOfType > 0 && LastBuild.ChangeNumber >= LastChangeByCurrentUserOfType) - { - // And check that there wasn't a successful build after we submitted (if there was, we're in the clear) - BuildData LastSuccessfulBuild; - if(!TypeToLastSucceededBuild.TryGetValue(LastBuild.BuildType, out LastSuccessfulBuild) || LastSuccessfulBuild.ChangeNumber < LastChangeByCurrentUserOfType) - { - // Add it to the list of notifications - NotifyBuilds.Add(LastBuild); - - // Check if this is a new notification, rather than one we've already dismissed - int NotifiedChangeNumber; - if(!NotifiedBuildTypeToChangeNumber.TryGetValue(LastBuild.BuildType, out NotifiedChangeNumber) || NotifiedChangeNumber < LastChangeByCurrentUserOfType) - { - RequireNotificationForChange = Math.Max(RequireNotificationForChange, LastChangeByCurrentUserOfType); - } - } - } - } - } - - // If there's anything we haven't already notified the user about, do so now - if(RequireNotificationForChange != -1) - { - // Format the platform list - StringBuilder PlatformList = new StringBuilder(NotifyBuilds[0].BuildType); - for(int Idx = 1; Idx < NotifyBuilds.Count - 1; Idx++) - { - PlatformList.AppendFormat(", {0}", NotifyBuilds[Idx].BuildType); - } - if(NotifyBuilds.Count > 1) - { - PlatformList.AppendFormat(" and {0}", NotifyBuilds[NotifyBuilds.Count - 1].BuildType); - } - - // Show the balloon tooltip - if(NotifyBuilds.Any(x => x.Result == BuildDataResult.Failure)) - { - string Title = String.Format("{0} Errors", PlatformList.ToString()); - string Message = String.Format("CIS failed after your last submitted changelist ({0}).", RequireNotificationForChange); - NotificationWindow.Show(NotificationType.Error, Title, Message); - } - else - { - string Title = String.Format("{0} Warnings", PlatformList.ToString()); - string Message = String.Format("CIS completed with warnings after your last submitted changelist ({0}).", RequireNotificationForChange); - NotificationWindow.Show(NotificationType.Warning, Title, Message); - } - - // Set the link to open the right build pages - int HighlightChange = NotifyBuilds.Max(x => x.ChangeNumber); - NotificationWindow.OnMoreInformation = () => { ShowAndActivate(); SelectChange(HighlightChange); }; - - // Don't show messages for this change again - foreach(BuildData NotifyBuild in NotifyBuilds) - { - NotifiedBuildTypeToChangeNumber[NotifyBuild.BuildType] = RequireNotificationForChange; - } - } - } - - private void BuildList_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e) - { - e.DrawDefault = true; - } - - private void BuildList_DrawItem(object sender, DrawListViewItemEventArgs e) - { - if(Application.RenderWithVisualStyles) - { - if(e.State.HasFlag(ListViewItemStates.Selected)) - { - SelectedItemRenderer.DrawBackground(e.Graphics, e.Bounds); - } - else if(e.ItemIndex == HoverItem) - { - TrackedItemRenderer.DrawBackground(e.Graphics, e.Bounds); - } - else if(((PerforceChangeSummary)e.Item.Tag).Number == Workspace.PendingChangeNumber) - { - TrackedItemRenderer.DrawBackground(e.Graphics, e.Bounds); - } - } - else - { - if(e.State.HasFlag(ListViewItemStates.Selected)) - { - e.Graphics.FillRectangle(SystemBrushes.ButtonFace, e.Bounds); - } - else - { - e.Graphics.FillRectangle(SystemBrushes.Window, e.Bounds); - } - } - } - - private string GetArchivePathForChangeNumber(int ChangeNumber) - { - string ArchivePath; - if(!ChangeNumberToArchivePath.TryGetValue(ChangeNumber, out ArchivePath)) - { - PerforceChangeType Type; - if(PerforceMonitor.TryGetChangeType(ChangeNumber, out Type)) - { - // Try to get the archive for this CL - if(!PerforceMonitor.TryGetArchivePathForChangeNumber(ChangeNumber, out ArchivePath) && Type == PerforceChangeType.Content) - { - // Otherwise if it's a content change, find the previous build any use the archive path from that - int Index = SortedChangeNumbers.BinarySearch(ChangeNumber); - if(Index > 0) - { - ArchivePath = GetArchivePathForChangeNumber(SortedChangeNumbers[Index - 1]); - } - } - } - ChangeNumberToArchivePath.Add(ChangeNumber, ArchivePath); - } - return ArchivePath; - } - - private Color Blend(Color First, Color Second, float T) - { - return Color.FromArgb((int)(First.R + (Second.R - First.R) * T), (int)(First.G + (Second.G - First.G) * T), (int)(First.B + (Second.B - First.B) * T)); - } - - private bool CanSyncChange(int ChangeNumber) - { - return !ShouldSyncPrecompiledEditor || GetArchivePathForChangeNumber(ChangeNumber) != null; - } - - private void BuildList_DrawSubItem(object sender, DrawListViewSubItemEventArgs e) - { - PerforceChangeSummary Change = (PerforceChangeSummary)e.Item.Tag; - - int IconY = e.Bounds.Top + (e.Bounds.Height - 16) / 2; - - StringFormat Format = new StringFormat(); - Format.LineAlignment = StringAlignment.Center; - Format.FormatFlags = StringFormatFlags.NoWrap; - Format.Trimming = StringTrimming.EllipsisCharacter; - - Font CurrentFont = (Change.Number == Workspace.PendingChangeNumber || Change.Number == Workspace.CurrentChangeNumber)? SelectedBuildFont : BuildFont; - - bool bAllowSync = CanSyncChange(Change.Number); - Color TextColor = (bAllowSync || Change.Number == Workspace.PendingChangeNumber || Change.Number == Workspace.CurrentChangeNumber || (Settings.CurrentWorkspace != null && Settings.CurrentWorkspace.AdditionalChangeNumbers.Contains(Change.Number)))? SystemColors.WindowText : Blend(SystemColors.Window, SystemColors.WindowText, 0.25f); - - if(e.ColumnIndex == IconColumn.Index) - { - EventSummary Summary = EventMonitor.GetSummaryForChange(Change.Number); - - int MinX = 4; - if((Summary != null && EventMonitor.WasSyncedByCurrentUser(Summary.ChangeNumber)) || (Workspace != null && Workspace.CurrentChangeNumber == Change.Number)) - { - e.Graphics.DrawImage(Properties.Resources.Icons, MinX, IconY, PreviousSyncIcon, GraphicsUnit.Pixel); - } - else if(Settings.CurrentWorkspace != null && Settings.CurrentWorkspace.AdditionalChangeNumbers.Contains(Change.Number)) - { - e.Graphics.DrawImage(Properties.Resources.Icons, MinX, IconY, AdditionalSyncIcon, GraphicsUnit.Pixel); - } - else if(bAllowSync && ((Summary != null && Summary.LastStarReview != null && Summary.LastStarReview.Type == EventType.Starred) || PromotedChangeNumbers.Contains(Change.Number))) - { - e.Graphics.DrawImage(Properties.Resources.Icons, MinX, IconY, PromotedBuildIcon, GraphicsUnit.Pixel); - } - MinX += PromotedBuildIcon.Width; - - if(bAllowSync) - { - Rectangle QualityIcon = DefaultBuildIcon; - if(EventMonitor.IsUnderInvestigation(Change.Number)) - { - QualityIcon = BadBuildIcon; - } - else if(Summary != null) - { - if(Summary.Verdict == ReviewVerdict.Good) - { - QualityIcon = GoodBuildIcon; - } - else if(Summary.Verdict == ReviewVerdict.Bad) - { - QualityIcon = BadBuildIcon; - } - else if(Summary.Verdict == ReviewVerdict.Mixed) - { - QualityIcon = MixedBuildIcon; - } - } - - e.Graphics.DrawImage(Properties.Resources.Icons, MinX, IconY, QualityIcon, GraphicsUnit.Pixel); - MinX += QualityIcon.Width; - } - } - else if(e.ColumnIndex == ChangeColumn.Index || e.ColumnIndex == TimeColumn.Index || e.ColumnIndex == AuthorColumn.Index || e.ColumnIndex == DescriptionColumn.Index) - { - TextRenderer.DrawText(e.Graphics, e.SubItem.Text, CurrentFont, e.Bounds, TextColor, TextFormatFlags.EndEllipsis | TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter | TextFormatFlags.NoPrefix); - } - else if(e.ColumnIndex == CISColumn.Index) - { - e.Graphics.IntersectClip(e.Bounds); - e.Graphics.SmoothingMode = SmoothingMode.HighQuality; - - EventSummary Summary = EventMonitor.GetSummaryForChange(Change.Number); - if(Summary == null || Summary.Builds.Count == 0) - { - PerforceChangeType Type; - if(PerforceMonitor.TryGetChangeType(Change.Number, out Type)) - { - if(Type == PerforceChangeType.Code) - { - DrawSingleBadge(e.Graphics, e.Bounds, "Code", Color.FromArgb(192, 192, 192)); - } - else if(Type == PerforceChangeType.Content) - { - DrawSingleBadge(e.Graphics, e.Bounds, "Content", bAllowSync? Color.FromArgb(128, 128, 192) : Color.FromArgb(192, 192, 192)); - } - } - } - else - { - Tuple[] Badges = LayoutBadges(Summary.Builds, e.Bounds); - foreach(Tuple Badge in Badges) - { - Color BadgeColor = Color.FromArgb(128, 192, 64); - if(Badge.Item1.Result == BuildDataResult.Starting) - { - BadgeColor = Color.FromArgb(128, 192, 255); - } - else if(Badge.Item1.Result == BuildDataResult.Warning) - { - BadgeColor = Color.FromArgb(255, 192, 0); - } - else if(Badge.Item1.Result == BuildDataResult.Failure) - { - BadgeColor = Color.FromArgb(192, 64, 0); - } - - if(Badge.Item1 == HoverBadge) - { - BadgeColor = Color.FromArgb(Math.Min(BadgeColor.R + 32, 255), Math.Min(BadgeColor.G + 32, 255), Math.Min(BadgeColor.B + 32, 255)); - } - - Size BadgeSize = GetBadgeSize(Badge.Item1.BuildType); - DrawBadge(e.Graphics, Badge.Item2, Badge.Item1.BuildType, BadgeColor); - } - } - } - else if(e.ColumnIndex == StatusColumn.Index) - { - int MaxX = e.SubItem.Bounds.Right; - - if(Change.Number == Workspace.PendingChangeNumber && Workspace.IsBusy()) - { - Tuple Progress = Workspace.CurrentProgress; - - MaxX -= CancelIcon.Width; - e.Graphics.DrawImage(Properties.Resources.Icons, MaxX, IconY, CancelIcon, GraphicsUnit.Pixel); - - if(!Splitter.IsLogVisible()) - { - MaxX -= InfoIcon.Width; - e.Graphics.DrawImage(Properties.Resources.Icons, MaxX, IconY, InfoIcon, GraphicsUnit.Pixel); - } - - int MinX = e.Bounds.Left; - - TextRenderer.DrawText(e.Graphics, Progress.Item1, CurrentFont, new Rectangle(MinX, e.Bounds.Top, MaxX - MinX, e.Bounds.Height), TextColor, TextFormatFlags.Left | TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis | TextFormatFlags.NoPrefix); - } - else - { - e.Graphics.IntersectClip(e.Bounds); - e.Graphics.SmoothingMode = SmoothingMode.HighQuality; - - if(Change.Number == Workspace.CurrentChangeNumber) - { - EventData Review = EventMonitor.GetReviewByCurrentUser(Change.Number); - - MaxX -= FrownIcon.Width; - e.Graphics.DrawImage(Properties.Resources.Icons, MaxX, IconY, (Review == null || !EventMonitor.IsPositiveReview(Review.Type))? FrownIcon : DisabledFrownIcon, GraphicsUnit.Pixel); - - MaxX -= HappyIcon.Width; - e.Graphics.DrawImage(Properties.Resources.Icons, MaxX, IconY, (Review == null || !EventMonitor.IsNegativeReview(Review.Type))? HappyIcon : DisabledHappyIcon, GraphicsUnit.Pixel); - } - else if(e.ItemIndex == HoverItem && bAllowSync) - { - Rectangle SyncBadgeRectangle = GetSyncBadgeRectangle(e.SubItem.Bounds); - DrawBadge(e.Graphics, SyncBadgeRectangle, "Sync", bHoverSync? Color.FromArgb(140, 180, 230) : Color.FromArgb(112, 146, 190)); - MaxX = SyncBadgeRectangle.Left - 2; - } - - string SummaryText; - if(Settings.CurrentWorkspace.LastSyncChangeNumber == -1 || Settings.CurrentWorkspace.LastSyncChangeNumber != Change.Number || !GetLastUpdateMessage(Settings.CurrentWorkspace.LastSyncResult, Settings.CurrentWorkspace.LastSyncResultMessage, out SummaryText)) - { - StringBuilder SummaryTextBuilder = new StringBuilder(); - - EventSummary Summary = EventMonitor.GetSummaryForChange(Change.Number); - - AppendItemList(SummaryTextBuilder, " ", "Under investigation by {0}.", EventMonitor.GetInvestigatingUsers(Change.Number).Select(x => FormatUserName(x))); - - if(Summary != null) - { - string Comments = String.Join(", ", Summary.Comments.Where(x => !String.IsNullOrWhiteSpace(x.Text)).Select(x => String.Format("{0}: \"{1}\"", FormatUserName(x.UserName), x.Text))); - if(Comments.Length > 0) - { - SummaryTextBuilder.Append(((SummaryTextBuilder.Length == 0)? "" : " ") + Comments); - } - else - { - AppendItemList(SummaryTextBuilder, " ", "Used by {0}.", Summary.CurrentUsers.Select(x => FormatUserName(x))); - } - } - - SummaryText = (SummaryTextBuilder.Length == 0)? "No current users." : SummaryTextBuilder.ToString(); - } - - if(SummaryText != null && SummaryText.Contains('\n')) - { - SummaryText = SummaryText.Substring(0, SummaryText.IndexOf('\n')).TrimEnd() + "..."; - } - - TextRenderer.DrawText(e.Graphics, SummaryText, CurrentFont, new Rectangle(e.Bounds.Left, e.Bounds.Top, MaxX - e.Bounds.Left, e.Bounds.Height), TextColor, TextFormatFlags.Left | TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis | TextFormatFlags.NoPrefix); - } - } - else - { - throw new NotImplementedException(); - } - } - - private Tuple[] LayoutBadges(IEnumerable Builds, Rectangle DisplayRectangle) - { - int NextX = 0; - List> Badges = new List>(); - foreach(BuildData Build in Builds.OrderBy(x => x.BuildType)) - { - Size BadgeSize = GetBadgeSize(Build.BuildType); - Badges.Add(new Tuple(Build, new Rectangle(NextX, DisplayRectangle.Top + (DisplayRectangle.Height - BadgeSize.Height) / 2, BadgeSize.Width, BadgeSize.Height))); - NextX += BadgeSize.Width + 2; - } - - int Offset = (Badges.Count > 0)? DisplayRectangle.Left + Math.Max(DisplayRectangle.Width - Badges.Last().Item2.Right, 0) / 2 : 0; - return Badges.Select(x => new Tuple(x.Item1, new Rectangle(x.Item2.Left + Offset, x.Item2.Top, x.Item2.Width, x.Item2.Height))).ToArray(); - } - - private Rectangle GetSyncBadgeRectangle(Rectangle Bounds) - { - Size BadgeSize = GetBadgeSize("Sync"); - return new Rectangle(Bounds.Right - BadgeSize.Width - 2, Bounds.Top + (Bounds.Height - BadgeSize.Height) / 2, BadgeSize.Width, BadgeSize.Height); - } - - private void DrawSingleBadge(Graphics Graphics, Rectangle DisplayRectangle, string BadgeText, Color BadgeColor) - { - Size BadgeSize = GetBadgeSize(BadgeText); - - int X = DisplayRectangle.Left + (DisplayRectangle.Width - BadgeSize.Width) / 2; - int Y = DisplayRectangle.Top + (DisplayRectangle.Height - BadgeSize.Height) / 2; - - DrawBadge(Graphics, new Rectangle(X, Y, BadgeSize.Width, BadgeSize.Height), BadgeText, BadgeColor); - } - - private void DrawBadge(Graphics Graphics, Rectangle BadgeRect, string BadgeText, Color BadgeColor) - { - GraphicsPath Path = new GraphicsPath(); - Path.StartFigure(); - Path.AddArc((float)BadgeRect.Left, (float)BadgeRect.Top, BadgeRect.Height, BadgeRect.Height, 90, 180); - Path.AddArc((float)BadgeRect.Right - BadgeRect.Height - 1, (float)BadgeRect.Top, BadgeRect.Height, BadgeRect.Height, 270, 180); - Path.CloseFigure(); - - using(SolidBrush Brush = new SolidBrush(BadgeColor)) - { - Graphics.FillPath(Brush, Path); - } - - TextRenderer.DrawText(Graphics, BadgeText, BadgeFont, BadgeRect, Color.White, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.SingleLine | TextFormatFlags.NoPrefix); - } - - private Size GetBadgeSize(string BadgeText) - { - Size LabelSize = TextRenderer.MeasureText(BadgeText, BadgeFont); - int BadgeHeight = BadgeFont.Height - 1; - return new Size(LabelSize.Width + BadgeHeight - 4, BadgeHeight); - } - - private static bool GetLastUpdateMessage(WorkspaceUpdateResult Result, string ResultMessage, out string Message) - { - if(Result != WorkspaceUpdateResult.Success && ResultMessage != null) - { - Message = ResultMessage; - return true; - } - return GetGenericLastUpdateMessage(Result, out Message); - } - - private static bool GetGenericLastUpdateMessage(WorkspaceUpdateResult Result, out string Message) - { - switch(Result) - { - case WorkspaceUpdateResult.Canceled: - Message = "Sync canceled."; - return true; - case WorkspaceUpdateResult.FailedToSync: - Message = "Failed to sync files."; - return true; - case WorkspaceUpdateResult.FilesToResolve: - Message = "Sync finished with unresolved files."; - return true; - case WorkspaceUpdateResult.FilesToClobber: - Message = "Sync failed due to modified files in workspace."; - return true; - case WorkspaceUpdateResult.FailedToCompile: - case WorkspaceUpdateResult.FailedToCompileWithCleanWorkspace: - Message = "Compile failed."; - return true; - default: - Message = null; - return false; - } - } - - private static string FormatUserName(string UserName) - { - StringBuilder NormalUserName = new StringBuilder(); - for(int Idx = 0; Idx < UserName.Length; Idx++) - { - if(Idx == 0 || UserName[Idx - 1] == '.') - { - NormalUserName.Append(Char.ToUpper(UserName[Idx])); - } - else if(UserName[Idx] == '.') - { - NormalUserName.Append(' '); - } - else - { - NormalUserName.Append(UserName[Idx]); - } - } - return NormalUserName.ToString(); - } - - private static void AppendUserList(StringBuilder Builder, string Separator, string Format, IEnumerable Reviews) - { - AppendItemList(Builder, Separator, Format, Reviews.Select(x => FormatUserName(x.UserName))); - } - - private static void AppendItemList(StringBuilder Builder, string Separator, string Format, IEnumerable Items) - { - string ItemList = FormatItemList(Format, Items); - if(ItemList != null) - { - if(Builder.Length > 0) - { - Builder.Append(Separator); - } - Builder.Append(ItemList); - } - } - - private static string FormatItemList(string Format, IEnumerable Items) - { - string[] ItemsArray = Items.Distinct().ToArray(); - if(ItemsArray.Length == 0) - { - return null; - } - - StringBuilder Builder = new StringBuilder(ItemsArray[0]); - if(ItemsArray.Length > 1) - { - for(int Idx = 1; Idx < ItemsArray.Length - 1; Idx++) - { - Builder.Append(", "); - Builder.Append(ItemsArray[Idx]); - } - Builder.Append(" and "); - Builder.Append(ItemsArray.Last()); - } - return String.Format(Format, Builder.ToString()); - } - - private void BuildList_MouseDoubleClick(object Sender, MouseEventArgs Args) - { - if(Args.Button == MouseButtons.Left) - { - ListViewHitTestInfo HitTest = BuildList.HitTest(Args.Location); - if(HitTest.Item != null) - { - PerforceChangeSummary Change = (PerforceChangeSummary)HitTest.Item.Tag; - if(Change.Number == Workspace.CurrentChangeNumber) - { - LaunchEditor(); - } - else - { - StartSync(Change.Number); - } - } - } - } - - private void LaunchEditor() - { - if(!Workspace.IsBusy() && Workspace.CurrentChangeNumber != -1) - { - BuildConfig EditorBuildConfig = GetEditorBuildConfig(); - - List ReceiptPaths = GetEditorReceiptPaths(EditorBuildConfig); - - string EditorExe = GetEditorExePath(EditorBuildConfig); - if(ReceiptPaths.Any(x => File.Exists(x)) && File.Exists(EditorExe)) - { - StringBuilder LaunchArguments = new StringBuilder(); - if(SelectedFileName.EndsWith(".uproject", StringComparison.InvariantCultureIgnoreCase)) - { - LaunchArguments.AppendFormat("\"{0}\"", SelectedFileName); - } - foreach(Tuple EditorArgument in Settings.EditorArguments) - { - if(EditorArgument.Item2) - { - LaunchArguments.AppendFormat(" {0}", EditorArgument.Item1); - } - } - if(EditorBuildConfig == BuildConfig.Debug || EditorBuildConfig == BuildConfig.DebugGame) - { - LaunchArguments.Append(" -debug"); - } - - if(!Utility.SpawnProcess(EditorExe, LaunchArguments.ToString())) - { - ShowErrorDialog("Unable to spawn {0} {1}", EditorExe, LaunchArguments.ToString()); - } - } - else - { - if(MessageBox.Show("The editor needs to be built before you can run it. Build it now?", "Editor out of date", MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes) - { - ShowAndActivate(); - - WorkspaceUpdateOptions Options = WorkspaceUpdateOptions.Build | WorkspaceUpdateOptions.RunAfterSync; - if(OptionsContextMenu_UseIncrementalBuilds.Checked) - { - Options |= WorkspaceUpdateOptions.UseIncrementalBuilds; - } - - WorkspaceUpdateContext Context = new WorkspaceUpdateContext(Workspace.CurrentChangeNumber, Options, null, GetDefaultBuildStepObjects(), Settings.CurrentProject.BuildSteps, null, GetWorkspaceVariables()); - StartWorkspaceUpdate(Context); - } - } - } - } - - private string GetEditorExePath(BuildConfig Config) - { - string ExeFileName = "UE4Editor.exe"; - if(Config != BuildConfig.DebugGame && Config != BuildConfig.Development) - { - ExeFileName = String.Format("UE4Editor-Win64-{0}.exe", Config.ToString()); - } - return Path.Combine(BranchDirectoryName, "Engine", "Binaries", "Win64", ExeFileName); - } - - private bool IsEditorRunning(BuildConfig Config) - { - string EditorFileName = Path.GetFullPath(GetEditorExePath(GetEditorBuildConfig())); - try - { - foreach(Process ProcessInstance in Process.GetProcessesByName(Path.GetFileNameWithoutExtension(EditorFileName))) - { - try - { - string ProcessFileName = Path.GetFullPath(Path.GetFullPath(ProcessInstance.MainModule.FileName)); - if(String.Compare(EditorFileName, ProcessFileName, StringComparison.InvariantCultureIgnoreCase) == 0) - { - return true; - } - } - catch - { - } - } - } - catch - { - } - return false; - } - - private List GetEditorReceiptPaths(BuildConfig Config) - { - string ConfigSuffix = (Config == BuildConfig.Development)? "" : String.Format("-Win64-{0}", Config.ToString()); - - List PossiblePaths = new List(); - if(EditorTargetName == null) - { - PossiblePaths.Add(Path.Combine(BranchDirectoryName, "Engine", "Binaries", "Win64", String.Format("UE4Editor{0}.target", ConfigSuffix))); - PossiblePaths.Add(Path.Combine(BranchDirectoryName, "Engine", "Build", "Receipts", String.Format("UE4Editor-Win64-{0}.target.xml", Config.ToString()))); - } - else - { - PossiblePaths.Add(Path.Combine(Path.GetDirectoryName(SelectedFileName), "Binaries", "Win64", String.Format("{0}{1}.target", EditorTargetName, ConfigSuffix))); - PossiblePaths.Add(Path.Combine(Path.GetDirectoryName(SelectedFileName), "Build", "Receipts", String.Format("{0}-Win64-{1}.target.xml", EditorTargetName, Config.ToString()))); - } - return PossiblePaths; - } - - private void TimerCallback(object Sender, EventArgs Args) - { - Tuple Progress = Workspace.CurrentProgress; - if(Progress != null && Progress.Item2 > 0.0f) - { - Taskbar.SetState(Handle, TaskbarState.Normal); - Taskbar.SetProgress(Handle, (ulong)(Progress.Item2 * 1000.0f), 1000); - } - else - { - Taskbar.SetState(Handle, TaskbarState.NoProgress); - } - - UpdateStatusPanel(); - BuildList.Refresh(); - } - - private void OpenPerforce() - { - StringBuilder CommandLine = new StringBuilder(); - if(Workspace != null && Workspace.Perforce != null) - { - string ServerAndPort; - if(!Workspace.Perforce.GetSetting("P4PORT", out ServerAndPort, Log)) - { - ServerAndPort = "perforce:1666"; - } - CommandLine.AppendFormat("-p \"{0}\" -c \"{1}\" -u \"{2}\"", ServerAndPort, Workspace.Perforce.ClientName, Workspace.Perforce.UserName); - } - Process.Start("p4v.exe", CommandLine.ToString()); - } - - private void UpdateStatusPanel() - { - int NewContentWidth = Math.Max(TextRenderer.MeasureText(String.Format("Last synced to {0} at changelist 123456789. 12 users are on a newer build. | Sync Now | Sync To...", StreamName ?? ""), StatusPanel.Font).Width, 400); - StatusPanel.SetContentWidth(NewContentWidth); - - List Lines = new List(); - if(Workspace == null) - { - StatusLine SummaryLine = new StatusLine(); - SummaryLine.AddText("To get started, open an existing Unreal project file on your hard drive."); - Lines.Add(SummaryLine); - - StatusLine OpenLine = new StatusLine(); - OpenLine.AddLink("Open project...", FontStyle.Bold | FontStyle.Underline, () => { BrowseForProject(); }); - Lines.Add(OpenLine); - } - else if(Workspace.IsBusy()) - { - // Sync in progress - Tuple Progress = Workspace.CurrentProgress; - - StatusLine SummaryLine = new StatusLine(); - SummaryLine.AddText("Updating to changelist "); - SummaryLine.AddLink(Workspace.PendingChangeNumber.ToString(), FontStyle.Regular, () => { SelectChange(Workspace.PendingChangeNumber); }); - SummaryLine.AddText("... | "); - SummaryLine.AddLink(Splitter.IsLogVisible()? "Hide Log" : "Show Log", FontStyle.Bold | FontStyle.Underline, () => { ToggleLogVisibility(); }); - SummaryLine.AddText(" | "); - SummaryLine.AddLink("Cancel", FontStyle.Bold | FontStyle.Underline, () => { CancelWorkspaceUpdate(); }); - Lines.Add(SummaryLine); - - StatusLine ProgressLine = new StatusLine(); - ProgressLine.AddText(String.Format("{0} ", Progress.Item1)); - if(Progress.Item2 > 0.0f) ProgressLine.AddProgressBar(Progress.Item2); - Lines.Add(ProgressLine); - } - else - { - // Sync status - StatusLine SummaryLine = new StatusLine(); - if(Workspace.CurrentChangeNumber != -1) - { - if(StreamName == null) - { - SummaryLine.AddText("Last synced to changelist "); - } - else - { - SummaryLine.AddText("Last synced to "); - SummaryLine.AddLink(StreamName + "\u25BE", FontStyle.Regular, (P, R) => { SelectOtherStream(R); }); - SummaryLine.AddText(" at changelist "); - } - SummaryLine.AddLink(String.Format("{0}.", Workspace.CurrentChangeNumber), FontStyle.Regular, () => { SelectChange(Workspace.CurrentChangeNumber); }); - int NumUsersOnNewerChange = SortedChangeNumbers.Where(x => (x > Workspace.CurrentChangeNumber)).OrderByDescending(x => x).Select(x => EventMonitor.GetSummaryForChange(x)).Where(x => x != null && (!ShouldSyncPrecompiledEditor || GetArchivePathForChangeNumber(x.ChangeNumber) != null)).Sum(x => x.CurrentUsers.Count); - if(NumUsersOnNewerChange > 0) - { - SummaryLine.AddText((NumUsersOnNewerChange == 1)? " 1 user is on a newer build." : String.Format(" {0} users are on a newer build.", NumUsersOnNewerChange)); - } - } - else - { - SummaryLine.AddText("You are not currently synced to "); - if(StreamName == null) - { - SummaryLine.AddText("this branch."); - } - else - { - SummaryLine.AddLink(StreamName + " \u25BE", FontStyle.Regular, (P, R) => { SelectOtherStream(R); }); - } - } - SummaryLine.AddText(" | "); - SummaryLine.AddLink("Sync Now", FontStyle.Bold | FontStyle.Underline, () => { SyncLatestChange(); }); - SummaryLine.AddText(" - "); - SummaryLine.AddLink(" To... \u25BE", 0, (P, R) => { ShowSyncMenu(R); }); - Lines.Add(SummaryLine); - - // Programs - StatusLine ProgramsLine = new StatusLine(); - if(Workspace.CurrentChangeNumber != -1) - { - ProgramsLine.AddLink("Unreal Editor", FontStyle.Regular, () => { LaunchEditor(); }); - ProgramsLine.AddText(" | "); - } - ProgramsLine.AddLink("Perforce", FontStyle.Regular, () => { OpenPerforce(); }); - ProgramsLine.AddText(" | "); - ProgramsLine.AddLink("Visual Studio", FontStyle.Regular, () => { OpenSolution(); }); - ProgramsLine.AddText(" | "); - ProgramsLine.AddLink("Windows Explorer", FontStyle.Regular, () => { Process.Start("explorer.exe", String.Format("\"{0}\"", Path.GetDirectoryName(SelectedFileName))); }); - ProgramsLine.AddText(" | "); - ProgramsLine.AddLink("More... \u25BE", FontStyle.Regular, (P, R) => { ShowActionsMenu(R); }); - Lines.Add(ProgramsLine); - - // Get the summary of the last sync - if(Settings.CurrentWorkspace.LastSyncChangeNumber > 0) - { - string SummaryText; - if(Settings.CurrentWorkspace.LastSyncChangeNumber == Workspace.CurrentChangeNumber && Settings.CurrentWorkspace.LastSyncResult == WorkspaceUpdateResult.Success && Settings.CurrentWorkspace.LastSyncTime.HasValue) - { - Lines.Add(new StatusLine()); - - StatusLine SuccessLine = new StatusLine(); - SuccessLine.AddIcon(Properties.Resources.StatusIcons, new Size(16, 16), 0); - SuccessLine.AddText(String.Format(" Sync took {0}{1}s, completed at {2}.", (Settings.CurrentWorkspace.LastSyncDurationSeconds >= 60)? String.Format("{0}m ", Settings.CurrentWorkspace.LastSyncDurationSeconds / 60) : "", Settings.CurrentWorkspace.LastSyncDurationSeconds % 60, Settings.CurrentWorkspace.LastSyncTime.Value.ToLocalTime().ToString("h\\:mmtt").ToLowerInvariant())); - Lines.Add(SuccessLine); - } - else if(GetLastUpdateMessage(Settings.CurrentWorkspace.LastSyncResult, Settings.CurrentWorkspace.LastSyncResultMessage, out SummaryText)) - { - Lines.Add(new StatusLine()); - - int SummaryTextLength = SummaryText.IndexOf('\n'); - if(SummaryTextLength == -1) - { - SummaryTextLength = SummaryText.Length; - } - SummaryTextLength = Math.Min(SummaryTextLength, 80); - - StatusLine FailLine = new StatusLine(); - FailLine.AddIcon(Properties.Resources.StatusIcons, new Size(16, 16), 1); - - if(SummaryTextLength == SummaryText.Length) - { - FailLine.AddText(String.Format(" {0} ", SummaryText)); - } - else - { - FailLine.AddText(String.Format(" {0}... ", SummaryText.Substring(0, SummaryTextLength).TrimEnd())); - FailLine.AddLink("More...", FontStyle.Bold | FontStyle.Underline, () => { ViewLastSyncStatus(); }); - FailLine.AddText(" | "); - } - FailLine.AddLink("Show Log", FontStyle.Bold | FontStyle.Underline, () => { ShowErrorInLog(); }); - Lines.Add(FailLine); - } - } - } - StatusPanel.Set(Lines); - } - - private void SelectOtherStream(Rectangle Bounds) - { - if(StreamName != null) - { - IReadOnlyList OtherStreamNames = PerforceMonitor.OtherStreamNames; - IReadOnlyList OtherStreamFilter = Workspace.ProjectStreamFilter; - - StreamContextMenu.Items.Clear(); - - if(OtherStreamFilter != null && !Settings.bShowAllStreams) - { - OtherStreamNames = OtherStreamNames.Where(x => OtherStreamFilter.Any(y => y.Equals(x, StringComparison.InvariantCultureIgnoreCase)) || x.Equals(StreamName, StringComparison.InvariantCultureIgnoreCase)).ToList().AsReadOnly(); - } - - foreach(string OtherStreamName in OtherStreamNames.OrderBy(x => x).Where(x => !x.EndsWith("/Dev-Binaries"))) - { - string ThisStreamName = OtherStreamName; // Local for lambda capture - - ToolStripMenuItem Item = new ToolStripMenuItem(ThisStreamName, null, new EventHandler((S, E) => SelectStream(ThisStreamName))); - if(String.Compare(StreamName, OtherStreamName, StringComparison.InvariantCultureIgnoreCase) == 0) - { - Item.Checked = true; - } - StreamContextMenu.Items.Add(Item); - } - - if(OtherStreamFilter != null) - { - StreamContextMenu.Items.Add(new ToolStripSeparator()); - if(Settings.bShowAllStreams) - { - StreamContextMenu.Items.Add(new ToolStripMenuItem("Show Filtered Stream List...", null, new EventHandler((S, E) => SetShowAllStreamsOption(false, Bounds)))); - } - else - { - StreamContextMenu.Items.Add(new ToolStripMenuItem("Show All Streams...", null, new EventHandler((S, E) => SetShowAllStreamsOption(true, Bounds)))); - } - } - - StreamContextMenu.Show(StatusPanel, new Point(Bounds.Left, Bounds.Bottom), ToolStripDropDownDirection.BelowRight); - } - } - - private void SetShowAllStreamsOption(bool bValue, Rectangle Bounds) - { - Settings.bShowAllStreams = bValue; - Settings.Save(); - - // Showing the new context menu before the current one has closed seems to fail to display it if the new context menu is shorter (ie. the current cursor position is out of bounds). - // BeginInvoke() it so it won't happen until the menu has closed. - BeginInvoke(new MethodInvoker(() => SelectOtherStream(Bounds))); - } - - private void SelectStream(string StreamName) - { - if(Workspace.IsBusy()) - { - MessageBox.Show("Please retry after the current sync has finished.", "Sync in Progress"); - } - else if(Workspace.Perforce != null) - { - if(!Workspace.Perforce.HasOpenFiles(Log) || MessageBox.Show("You have files open for edit in this workspace. If you continue, you will not be able to submit them until you switch back.\n\nContinue switching workspaces?", "Files checked out", MessageBoxButtons.YesNo) == DialogResult.Yes) - { - if(Workspace.Perforce.SwitchStream(StreamName, Log)) - { - StatusPanel.SuspendLayout(); - StreamChangedCallback(); - StatusPanel.ResumeLayout(); - } - } - } - } - - private void ViewLastSyncStatus() - { - string SummaryText; - if(GetLastUpdateMessage(Settings.CurrentWorkspace.LastSyncResult, Settings.CurrentWorkspace.LastSyncResultMessage, out SummaryText)) - { - string CaptionText; - if(!GetGenericLastUpdateMessage(Settings.CurrentWorkspace.LastSyncResult, out CaptionText)) - { - CaptionText = "Sync error"; - } - MessageBox.Show(SummaryText, CaptionText); - } - } - - private void ShowErrorInLog() - { - if(!Splitter.IsLogVisible()) - { - ToggleLogVisibility(); - } - SyncLog.ScrollToEnd(); - } - - private void ShowActionsMenu(Rectangle Bounds) - { - MoreToolsContextMenu.Show(StatusPanel, new Point(Bounds.Left, Bounds.Bottom), ToolStripDropDownDirection.BelowRight); - } - - private void SelectChange(int ChangeNumber) - { - PendingSelectedChangeNumber = -1; - - foreach(ListViewItem Item in BuildList.Items) - { - PerforceChangeSummary Summary = (PerforceChangeSummary)Item.Tag; - if(Summary != null && Summary.Number <= ChangeNumber) - { - Item.Selected = true; - Item.EnsureVisible(); - return; - } - } - - PendingSelectedChangeNumber = ChangeNumber; - - if(BuildList.Items.Count > 0) - { - BuildList.Items[BuildList.Items.Count - 1].EnsureVisible(); - } - - UpdateNumRequestedBuilds(false); - } - - private void BuildList_MouseClick(object Sender, MouseEventArgs Args) - { - if(Args.Button == MouseButtons.Left) - { - ListViewHitTestInfo HitTest = BuildList.HitTest(Args.Location); - if(HitTest.Item != null) - { - PerforceChangeSummary Change = (PerforceChangeSummary)HitTest.Item.Tag; - if(Workspace.PendingChangeNumber == Change.Number) - { - Rectangle SubItemRect = HitTest.Item.SubItems[StatusColumn.Index].Bounds; - - if(Workspace.IsBusy()) - { - Rectangle CancelRect = new Rectangle(SubItemRect.Right - 16, SubItemRect.Top, 16, SubItemRect.Height); - Rectangle InfoRect = new Rectangle(SubItemRect.Right - 32, SubItemRect.Top, 16, SubItemRect.Height); - if(CancelRect.Contains(Args.Location)) - { - CancelWorkspaceUpdate(); - } - else if(InfoRect.Contains(Args.Location) && !Splitter.IsLogVisible()) - { - ToggleLogVisibility(); - } - } - else - { - Rectangle HappyRect = new Rectangle(SubItemRect.Right - 32, SubItemRect.Top, 16, SubItemRect.Height); - Rectangle FrownRect = new Rectangle(SubItemRect.Right - 16, SubItemRect.Top, 16, SubItemRect.Height); - if(HappyRect.Contains(Args.Location)) - { - EventMonitor.PostEvent(Change.Number, EventType.Good); - BuildList.Invalidate(); - } - else if(FrownRect.Contains(Args.Location)) - { - EventMonitor.PostEvent(Change.Number, EventType.Bad); - BuildList.Invalidate(); - } - } - } - else - { - Rectangle SyncBadgeRectangle = GetSyncBadgeRectangle(HitTest.Item.SubItems[StatusColumn.Index].Bounds); - if(SyncBadgeRectangle.Contains(Args.Location) && CanSyncChange(Change.Number)) - { - StartSync(Change.Number); - } - } - - if(CISColumn.Index < HitTest.Item.SubItems.Count && HitTest.Item.SubItems[CISColumn.Index] == HitTest.SubItem) - { - EventSummary Summary = EventMonitor.GetSummaryForChange(Change.Number); - if(Summary != null) - { - Tuple[] Badges = LayoutBadges(Summary.Builds, HitTest.SubItem.Bounds); - for(int Idx = 0; Idx < Badges.Length; Idx++) - { - if(Badges[Idx].Item2.Contains(Args.Location)) - { - Process.Start(Badges[Idx].Item1.Url); - break; - } - } - } - } - } - } - else if(Args.Button == MouseButtons.Right) - { - ListViewHitTestInfo HitTest = BuildList.HitTest(Args.Location); - if(HitTest.Item != null && HitTest.Item.Tag != null) - { - ContextMenuChange = (PerforceChangeSummary)HitTest.Item.Tag; - - BuildListContextMenu_WithdrawReview.Visible = (EventMonitor.GetReviewByCurrentUser(ContextMenuChange.Number) != null); - BuildListContextMenu_StartInvestigating.Visible = !EventMonitor.IsUnderInvestigationByCurrentUser(ContextMenuChange.Number); - BuildListContextMenu_FinishInvestigating.Visible = EventMonitor.IsUnderInvestigation(ContextMenuChange.Number); - - string CommentText; - bool bHasExistingComment = EventMonitor.GetCommentByCurrentUser(ContextMenuChange.Number, out CommentText); - BuildListContextMenu_LeaveComment.Visible = !bHasExistingComment; - BuildListContextMenu_EditComment.Visible = bHasExistingComment; - - bool bIsBusy = Workspace.IsBusy(); - bool bIsCurrentChange = (ContextMenuChange.Number == Workspace.CurrentChangeNumber); - BuildListContextMenu_Sync.Visible = !bIsBusy; - BuildListContextMenu_Sync.Font = new Font(SystemFonts.MenuFont, bIsCurrentChange? FontStyle.Regular : FontStyle.Bold); - BuildListContextMenu_SyncContentOnly.Visible = !bIsBusy && ShouldSyncPrecompiledEditor; - BuildListContextMenu_SyncOnlyThisChange.Visible = !bIsBusy && !bIsCurrentChange && ContextMenuChange.Number > Workspace.CurrentChangeNumber && Workspace.CurrentChangeNumber != -1; - BuildListContextMenu_Build.Visible = !bIsBusy && bIsCurrentChange && !ShouldSyncPrecompiledEditor && OptionsContextMenu_UseIncrementalBuilds.Checked; - BuildListContextMenu_Rebuild.Visible = !bIsBusy && bIsCurrentChange && !ShouldSyncPrecompiledEditor; - BuildListContextMenu_GenerateProjectFiles.Visible = !bIsBusy && bIsCurrentChange; - BuildListContextMenu_LaunchEditor.Visible = !bIsBusy && ContextMenuChange.Number == Workspace.CurrentChangeNumber; - BuildListContextMenu_LaunchEditor.Font = new Font(SystemFonts.MenuFont, FontStyle.Bold); - BuildListContextMenu_OpenVisualStudio.Visible = !bIsBusy && bIsCurrentChange; - BuildListContextMenu_Cancel.Visible = bIsBusy; - - EventSummary Summary = EventMonitor.GetSummaryForChange(ContextMenuChange.Number); - bool bStarred = (Summary != null && Summary.LastStarReview != null && Summary.LastStarReview.Type == EventType.Starred); - BuildListContextMenu_AddStar.Visible = !bStarred; - BuildListContextMenu_RemoveStar.Visible = bStarred; - - bool bIsTimeColumn = (HitTest.Item.SubItems.IndexOf(HitTest.SubItem) == TimeColumn.Index); - BuildListContextMenu_TimeZoneSeparator.Visible = bIsTimeColumn; - BuildListContextMenu_ShowLocalTimes.Visible = bIsTimeColumn; - BuildListContextMenu_ShowLocalTimes.Checked = Settings.bShowLocalTimes; - BuildListContextMenu_ShowServerTimes.Visible = bIsTimeColumn; - BuildListContextMenu_ShowServerTimes.Checked = !Settings.bShowLocalTimes; - - BuildListContextMenu.Show(BuildList, Args.Location); - } - } - } - - private void BuildList_MouseMove(object sender, MouseEventArgs e) - { - ListViewHitTestInfo HitTest = BuildList.HitTest(e.Location); - int HitTestIndex = (HitTest.Item == null)? -1 : HitTest.Item.Index; - if(HitTestIndex != HoverItem) - { - if(HoverItem != -1) - { - BuildList.RedrawItems(HoverItem, HoverItem, true); - } - HoverItem = HitTestIndex; - if(HoverItem != -1) - { - BuildList.RedrawItems(HoverItem, HoverItem, true); - } - } - - BuildData NewHoverBadge = null; - if(HitTest.Item != null && HitTest.Item.SubItems.IndexOf(HitTest.SubItem) == CISColumn.Index) - { - EventSummary Summary = EventMonitor.GetSummaryForChange(((PerforceChangeSummary)HitTest.Item.Tag).Number); - if(Summary != null) - { - foreach(Tuple Badge in LayoutBadges(Summary.Builds, HitTest.SubItem.Bounds)) - { - if(Badge.Item2.Contains(e.Location)) - { - NewHoverBadge = Badge.Item1; - break; - } - } - } - } - if(NewHoverBadge != HoverBadge) - { - HoverBadge = NewHoverBadge; - BuildList.Invalidate(); - } - - bool bNewHoverSync = false; - if(HitTest.Item != null) - { - bNewHoverSync = GetSyncBadgeRectangle(HitTest.Item.SubItems[StatusColumn.Index].Bounds).Contains(e.Location); - } - if(bNewHoverSync != bHoverSync) - { - bHoverSync = bNewHoverSync; - BuildList.Invalidate(); - } - } - - private void BrowseProject_Click(object sender, EventArgs e) - { - BrowseForProject(); - } - - private void BrowseForProject() - { - OpenFileDialog Dialog = new OpenFileDialog(); - Dialog.Filter = "Project files (*.uproject)|*.uproject|Project directory lists (*.uprojectdirs)|*.uprojectdirs|All files (*.*)|*.*" ; - if(Dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) - { - OpenProject(Dialog.FileName); - } - } - - private void ProjectList_MouseWheel(object sender, MouseEventArgs e) - { - ((HandledMouseEventArgs)e).Handled = true; - } - - private void ProjectList_SelectionChangeCommitted(object sender, EventArgs e) - { - if(ProjectList.SelectedIndex >= 0 && ProjectList.SelectedIndex == ProjectList.Items.Count - 1) - { - if(MessageBox.Show("Clear the recently used projects list?", "Clear Projects", MessageBoxButtons.YesNo) == DialogResult.Yes) - { - Settings.OtherProjectFileNames = (SelectedFileName == null)? new string[0] : new string[]{ SelectedFileName }; - UpdateProjectList(); - } - ProjectList.Text = SelectedFileName; - } - else - { - string NewProjectFileName = (string)ProjectList.SelectedItem; - if(String.Compare(NewProjectFileName, SelectedFileName, true) != 0) - { - OpenProject(NewProjectFileName); - } - } - } - - private void ProjectList_KeyDown(object sender, KeyEventArgs e) - { - if(e.KeyCode == Keys.Enter) - { - if(String.Compare(ProjectList.Text, SelectedFileName, true) != 0) - { - OpenProject(ProjectList.Text); - } - e.Handled = true; - e.SuppressKeyPress = true; - } - } - - private void OptionsButton_Click(object sender, EventArgs e) - { - OptionsContextMenu_SyncPrecompiledEditor.Visible = PerforceMonitor != null && PerforceMonitor.HasZippedBinaries; - OptionsContextMenu_EditorBuildConfiguration.Enabled = !ShouldSyncPrecompiledEditor; - OptionsContextMenu_UseIncrementalBuilds.Enabled = !ShouldSyncPrecompiledEditor; - OptionsContextMenu_CustomizeBuildSteps.Enabled = (Workspace != null); - OptionsContextMenu_EditorArguments.Checked = Settings.EditorArguments.Any(x => x.Item2); - OptionsContextMenu_ScheduledSync.Checked = Settings.bScheduleEnabled; - OptionsContextMenu_TimeZone_Local.Checked = Settings.bShowLocalTimes; - OptionsContextMenu_TimeZone_PerforceServer.Checked = !Settings.bShowLocalTimes; - OptionsContextMenu_AutomaticallyRunAtStartup.Checked = IsAutomaticallyRunAtStartup(); - OptionsContextMenu_KeepInTray.Checked = Settings.bKeepInTray; - OptionsContextMenu.Show(OptionsButton, new Point(OptionsButton.Width - OptionsContextMenu.Size.Width, OptionsButton.Height)); - } - - private void BuildAfterSyncCheckBox_CheckedChanged(object sender, EventArgs e) - { - UpdateSyncActionCheckboxes(); - - Settings.bBuildAfterSync = BuildAfterSyncCheckBox.Checked; - Settings.Save(); - } - - private void RunAfterSyncCheckBox_CheckedChanged(object sender, EventArgs e) - { - UpdateSyncActionCheckboxes(); - - Settings.bRunAfterSync = RunAfterSyncCheckBox.Checked; - Settings.Save(); - } - - private void OpenSolutionAfterSyncCheckBox_CheckedChanged(object sender, EventArgs e) - { - UpdateSyncActionCheckboxes(); - - Settings.bOpenSolutionAfterSync = OpenSolutionAfterSyncCheckBox.Checked; - Settings.Save(); - } - - private void UpdateSyncActionCheckboxes() - { - if(Workspace == null || Workspace.IsBusy()) - { - AfterSyncingLabel.Enabled = false; - BuildAfterSyncCheckBox.Enabled = false; - RunAfterSyncCheckBox.Enabled = false; - OpenSolutionAfterSyncCheckBox.Enabled = false; - } - else - { - AfterSyncingLabel.Enabled = true; - BuildAfterSyncCheckBox.Enabled = bHasBuildSteps; - RunAfterSyncCheckBox.Enabled = BuildAfterSyncCheckBox.Checked; - OpenSolutionAfterSyncCheckBox.Enabled = true; - } - } - - private void BuildList_FontChanged(object sender, EventArgs e) - { - if(BuildFont != null) - { - BuildFont.Dispose(); - } - BuildFont = BuildList.Font; - - if(SelectedBuildFont != null) - { - SelectedBuildFont.Dispose(); - } - SelectedBuildFont = new Font(BuildFont, FontStyle.Bold); - - if(BadgeFont != null) - { - BadgeFont.Dispose(); - } - BadgeFont = new Font(BuildFont.FontFamily, BuildFont.SizeInPoints - 2, FontStyle.Bold); - } - private void NotifyIcon_MouseDown(object sender, MouseEventArgs e) { // Have to set up this stuff here, because the menu is laid out before Opening() is called on it after mouse-up. - NotifyMenu_SyncNow.Visible = (Workspace != null && !Workspace.IsBusy()); - NotifyMenu_LaunchEditor.Visible = (Workspace != null && !Workspace.IsBusy() && Workspace.CurrentChangeNumber != -1); - NotifyMenu_ExitSeparator.Visible = (Workspace != null && !Workspace.IsBusy()); + if(CurrentWorkspace != null) + { + bool bCanSyncNow = CurrentWorkspace.CanSyncNow(); + bool bCanLaunchEditor = CurrentWorkspace.CanLaunchEditor(); + NotifyMenu_SyncNow.Visible = CurrentWorkspace.CanSyncNow(); + NotifyMenu_LaunchEditor.Visible = CurrentWorkspace.CanLaunchEditor(); + NotifyMenu_ExitSeparator.Visible = bCanSyncNow || bCanLaunchEditor; + } } private void NotifyIcon_DoubleClick(object sender, EventArgs e) @@ -2263,34 +356,12 @@ namespace UnrealGameSync private void NotifyMenu_SyncNow_Click(object sender, EventArgs e) { - SyncLatestChange(); - } - - private void SyncLatestChange() - { - if(Workspace != null) - { - int ChangeNumber; - if(!FindChangeToSync(Settings.SyncType, out ChangeNumber)) - { - ShowErrorDialog(String.Format("Couldn't find any {0}changelist. Double-click on the change you want to sync manually.", (Settings.SyncType == LatestChangeType.Starred)? "starred " : (Settings.SyncType == LatestChangeType.Good)? "good " : "")); - } - else if(ChangeNumber < Workspace.CurrentChangeNumber) - { - ShowErrorDialog("Workspace is already synced to a later change ({0} vs {1}).", Workspace.CurrentChangeNumber, ChangeNumber); - } - else if(ChangeNumber >= PerforceMonitor.LastChangeByCurrentUser || MessageBox.Show(String.Format("The changelist that would be synced is before the last change you submitted.\n\nIf you continue, your changes submitted after CL {0} will be locally removed from your workspace until you can sync past them again.\n\nAre you sure you want to continue?", ChangeNumber), "Local changes will be removed", MessageBoxButtons.YesNo) == DialogResult.Yes) - { - ShowAndActivate(); - SelectChange(ChangeNumber); - StartSync(ChangeNumber); - } - } + CurrentWorkspace.SyncLatestChange(); } private void NotifyMenu_LaunchEditor_Click(object sender, EventArgs e) { - LaunchEditor(); + CurrentWorkspace.LaunchEditor(); } private void NotifyMenu_Exit_Click(object sender, EventArgs e) @@ -2299,310 +370,23 @@ namespace UnrealGameSync Close(); } - private void BuildListContextMenu_MarkGood_Click(object sender, EventArgs e) - { - EventMonitor.PostEvent(ContextMenuChange.Number, EventType.Good); - } - - private void BuildListContextMenu_MarkBad_Click(object sender, EventArgs e) - { - EventMonitor.PostEvent(ContextMenuChange.Number, EventType.Bad); - } - - private void BuildListContextMenu_WithdrawReview_Click(object sender, EventArgs e) - { - EventMonitor.PostEvent(ContextMenuChange.Number, EventType.Unknown); - } - - private void BuildListContextMenu_Sync_Click(object sender, EventArgs e) - { - StartSync(ContextMenuChange.Number); - } - - private void BuildListContextMenu_SyncContentOnly_Click(object sender, EventArgs e) - { - StartWorkspaceUpdate(ContextMenuChange.Number, WorkspaceUpdateOptions.Sync | WorkspaceUpdateOptions.ContentOnly); - } - - private void BuildListContextMenu_SyncOnlyThisChange_Click(object sender, EventArgs e) - { - StartWorkspaceUpdate(ContextMenuChange.Number, WorkspaceUpdateOptions.SyncSingleChange); - } - - private void BuildListContextMenu_Build_Click(object sender, EventArgs e) - { - StartWorkspaceUpdate(Workspace.CurrentChangeNumber, WorkspaceUpdateOptions.SyncArchives | WorkspaceUpdateOptions.Build | WorkspaceUpdateOptions.UseIncrementalBuilds); - } - - private void BuildListContextMenu_Rebuild_Click(object sender, EventArgs e) - { - StartWorkspaceUpdate(Workspace.CurrentChangeNumber, WorkspaceUpdateOptions.SyncArchives | WorkspaceUpdateOptions.Build); - } - - private void BuildListContextMenu_GenerateProjectFiles_Click(object sender, EventArgs e) - { - StartWorkspaceUpdate(Workspace.CurrentChangeNumber, WorkspaceUpdateOptions.GenerateProjectFiles); - } - - private void BuildListContextMenu_CancelSync_Click(object sender, EventArgs e) - { - CancelWorkspaceUpdate(); - } - - private void BuildListContextMenu_MoreInfo_Click(object sender, EventArgs e) - { - if(!Utility.SpawnHiddenProcess("p4vc.exe", String.Format("-c{0} change {1}", Workspace.ClientName, ContextMenuChange.Number))) - { - MessageBox.Show("Unable to spawn p4vc. Check you have P4V installed."); - } - } - - private void BuildListContextMenu_AddStar_Click(object sender, EventArgs e) - { - if(MessageBox.Show("Starred builds are meant to convey a stable, verified build to the rest of the team. Do not star a build unless it has been fully tested.\n\nAre you sure you want to star this build?", "Confirm star", MessageBoxButtons.YesNo) == DialogResult.Yes) - { - EventMonitor.PostEvent(ContextMenuChange.Number, EventType.Starred); - } - } - - private void BuildListContextMenu_RemoveStar_Click(object sender, EventArgs e) - { - EventSummary Summary = EventMonitor.GetSummaryForChange(ContextMenuChange.Number); - if(Summary != null && Summary.LastStarReview != null && Summary.LastStarReview.Type == EventType.Starred) - { - string Message = String.Format("This change was starred by {0}. Are you sure you want to remove it?", FormatUserName(Summary.LastStarReview.UserName)); - if(MessageBox.Show(Message, "Confirm removing star", MessageBoxButtons.YesNo) == DialogResult.Yes) - { - EventMonitor.PostEvent(ContextMenuChange.Number, EventType.Unstarred); - } - } - } - - private void BuildListContextMenu_LaunchEditor_Click(object sender, EventArgs e) - { - LaunchEditor(); - } - - private void BuildListContextMenu_StartInvestigating_Click(object sender, EventArgs e) - { - string Message = String.Format("All changes from {0} onwards will be marked as bad while you are investigating an issue.\n\nAre you sure you want to continue?", ContextMenuChange.Number); - if(MessageBox.Show(Message, "Confirm investigating", MessageBoxButtons.YesNo) == DialogResult.Yes) - { - EventMonitor.StartInvestigating(ContextMenuChange.Number); - } - } - - private void BuildListContextMenu_FinishInvestigating_Click(object sender, EventArgs e) - { - int StartChangeNumber = EventMonitor.GetInvestigationStartChangeNumber(ContextMenuChange.Number); - if(StartChangeNumber != -1) - { - if(ContextMenuChange.Number > StartChangeNumber) - { - string Message = String.Format("Mark all changes between {0} and {1} as bad?", StartChangeNumber, ContextMenuChange.Number); - if(MessageBox.Show(Message, "Finish investigating", MessageBoxButtons.YesNo) == DialogResult.Yes) - { - foreach(PerforceChangeSummary Change in PerforceMonitor.GetChanges()) - { - if (Change.Number >= StartChangeNumber && Change.Number < ContextMenuChange.Number) - { - EventMonitor.PostEvent(Change.Number, EventType.Bad); - } - } - } - } - EventMonitor.FinishInvestigating(ContextMenuChange.Number); - } - } - - private void OnlyShowReviewedCheckBox_CheckedChanged(object sender, EventArgs e) - { - UpdateBuildList(); - UpdateNumRequestedBuilds(true); - } - private void MainWindow_Activated(object sender, EventArgs e) { - if(PerforceMonitor != null) + if(CurrentWorkspace != null) { - PerforceMonitor.Refresh(); + CurrentWorkspace.Activate(); } } private void MainWindow_Deactivate(object sender, EventArgs e) { - UpdateNumRequestedBuilds(true); - } - - private void BuildList_ItemMouseHover(object sender, ListViewItemMouseHoverEventArgs Args) - { - Point ClientPoint = BuildList.PointToClient(Cursor.Position); - if(Args.Item.SubItems.Count >= 6) + if(CurrentWorkspace != null) { - if(Args.Item.Bounds.Contains(ClientPoint)) - { - PerforceChangeSummary Change = (PerforceChangeSummary)Args.Item.Tag; - - Rectangle DescriptionBounds = Args.Item.SubItems[DescriptionColumn.Index].Bounds; - if(DescriptionBounds.Contains(ClientPoint)) - { - BuildListToolTip.Show(Change.Description, BuildList, new Point(DescriptionBounds.Left, DescriptionBounds.Bottom)); - return; - } - - EventSummary Summary = EventMonitor.GetSummaryForChange(Change.Number); - if(Summary != null) - { - StringBuilder SummaryText = new StringBuilder(); - if(Summary.Comments.Count > 0) - { - foreach(CommentData Comment in Summary.Comments) - { - if(!String.IsNullOrWhiteSpace(Comment.Text)) - { - SummaryText.AppendFormat("{0}: \"{1}\"\n", FormatUserName(Comment.UserName), Comment.Text); - } - } - if(SummaryText.Length > 0) - { - SummaryText.Append("\n"); - } - } - AppendUserList(SummaryText, "\n", "Compiled by {0}.", Summary.Reviews.Where(x => x.Type == EventType.Compiles)); - AppendUserList(SummaryText, "\n", "Failed to compile for {0}.", Summary.Reviews.Where(x => x.Type == EventType.DoesNotCompile)); - AppendUserList(SummaryText, "\n", "Marked good by {0}.", Summary.Reviews.Where(x => x.Type == EventType.Good)); - AppendUserList(SummaryText, "\n", "Marked bad by {0}.", Summary.Reviews.Where(x => x.Type == EventType.Bad)); - if(Summary.LastStarReview != null) - { - AppendUserList(SummaryText, "\n", "Starred by {0}.", new EventData[]{ Summary.LastStarReview }); - } - if(SummaryText.Length > 0) - { - Rectangle SummaryBounds = Args.Item.SubItems[StatusColumn.Index].Bounds; - BuildListToolTip.Show(SummaryText.ToString(), BuildList, new Point(SummaryBounds.Left, SummaryBounds.Bottom)); - return; - } - } - } - } - - BuildListToolTip.Hide(BuildList); - } - - private void BuildList_MouseLeave(object sender, EventArgs e) - { - BuildListToolTip.Hide(BuildList); - - if(HoverItem != -1) - { - HoverItem = -1; - BuildList.Invalidate(); - } - - if(HoverBadge != null) - { - HoverBadge = null; - BuildList.Invalidate(); + CurrentWorkspace.Deactivate(); } } - private void OptionsContextMenu_ShowLog_Click(object sender, EventArgs e) - { - ToggleLogVisibility(); - } - - private void ToggleLogVisibility() - { - Splitter.SetLogVisibility(!Splitter.IsLogVisible()); - } - - private void Splitter_OnVisibilityChanged(bool bVisible) - { - Settings.bShowLogWindow = bVisible; - Settings.Save(); - - UpdateStatusPanel(); - } - - private void OptionsContextMenu_AutoResolveConflicts_Click(object sender, EventArgs e) - { - OptionsContextMenu_AutoResolveConflicts.Checked ^= true; - Settings.bAutoResolveConflicts = OptionsContextMenu_AutoResolveConflicts.Checked; - Settings.Save(); - } - - private void OptionsContextMenu_EditorArguments_Click(object sender, EventArgs e) - { - ArgumentsWindow Arguments = new ArgumentsWindow(Settings.EditorArguments); - if(Arguments.ShowDialog(this) == DialogResult.OK) - { - Settings.EditorArguments = Arguments.GetItems(); - Settings.Save(); - } - } - - private void BuildListContextMenu_OpenVisualStudio_Click(object sender, EventArgs e) - { - OpenSolution(); - } - - private void OpenSolution() - { - string SolutionFileName = Path.Combine(BranchDirectoryName, "UE4.sln"); - if(!File.Exists(SolutionFileName)) - { - MessageBox.Show(String.Format("Couldn't find solution at {0}", SolutionFileName)); - } - else - { - Process.Start(SolutionFileName); - } - } - - private void OptionsContextMenu_BuildConfig_Debug_Click(object sender, EventArgs e) - { - UpdateBuildConfig(BuildConfig.Debug); - } - - private void OptionsContextMenu_BuildConfig_DebugGame_Click(object sender, EventArgs e) - { - UpdateBuildConfig(BuildConfig.DebugGame); - } - - private void OptionsContextMenu_BuildConfig_Development_Click(object sender, EventArgs e) - { - UpdateBuildConfig(BuildConfig.Development); - } - - void UpdateBuildConfig(BuildConfig NewConfig) - { - Settings.CompiledEditorBuildConfig = NewConfig; - Settings.Save(); - UpdateCheckedBuildConfig(); - } - - void UpdateCheckedBuildConfig() - { - BuildConfig EditorBuildConfig = GetEditorBuildConfig(); - - OptionsContextMenu_BuildConfig_Debug.Checked = (EditorBuildConfig == BuildConfig.Debug); - OptionsContextMenu_BuildConfig_Debug.Enabled = (!ShouldSyncPrecompiledEditor || EditorBuildConfig == BuildConfig.Debug); - - OptionsContextMenu_BuildConfig_DebugGame.Checked = (EditorBuildConfig == BuildConfig.DebugGame); - OptionsContextMenu_BuildConfig_DebugGame.Enabled = (!ShouldSyncPrecompiledEditor || EditorBuildConfig == BuildConfig.DebugGame); - - OptionsContextMenu_BuildConfig_Development.Checked = (EditorBuildConfig == BuildConfig.Development); - OptionsContextMenu_BuildConfig_Development.Enabled = (!ShouldSyncPrecompiledEditor || EditorBuildConfig == BuildConfig.Development); - } - - private void OptionsContextMenu_UseIncrementalBuilds_Click(object sender, EventArgs e) - { - OptionsContextMenu_UseIncrementalBuilds.Checked ^= true; - Settings.bUseIncrementalBuilds = OptionsContextMenu_UseIncrementalBuilds.Checked; - Settings.Save(); - } - - private void OptionsContextMenu_ScheduleSync_Click(object sender, EventArgs e) + public void SetupScheduledSync() { StopScheduleTimer(); @@ -2646,440 +430,299 @@ namespace UnrealGameSync private void ScheduleTimerElapsed() { - if(Settings.bScheduleEnabled) + for(int Idx = 0; Idx < TabControl.GetTabCount(); Idx++) { - Log.WriteLine("Scheduled sync at {0} for {1}.", DateTime.Now, Settings.ScheduleChange); - - int ChangeNumber; - if(!FindChangeToSync(Settings.ScheduleChange, out ChangeNumber)) - { - Log.WriteLine("Couldn't find any matching change"); - } - else if(Workspace.CurrentChangeNumber >= ChangeNumber) - { - Log.WriteLine("Sync ignored; already at or ahead of CL ({0} >= {1})", Workspace.CurrentChangeNumber, ChangeNumber); - } - else - { - WorkspaceUpdateOptions Options = WorkspaceUpdateOptions.Sync | WorkspaceUpdateOptions.SyncArchives | WorkspaceUpdateOptions.GenerateProjectFiles | WorkspaceUpdateOptions.Build | WorkspaceUpdateOptions.ScheduledBuild; - if(OptionsContextMenu_AutoResolveConflicts.Checked) - { - Options |= WorkspaceUpdateOptions.AutoResolveChanges; - } - if(BuildAfterSyncCheckBox.Checked && RunAfterSyncCheckBox.Checked) - { - Options |= WorkspaceUpdateOptions.RunAfterSync; - } - StartWorkspaceUpdate(ChangeNumber, Options); - } + ((WorkspaceControl)TabControl.GetTabData(Idx)).ScheduleTimerElapsed(); } } - bool FindChangeToSync(LatestChangeType ChangeType, out int ChangeNumber) + void TabControl_OnTabChanged(object NewTabData) { - for(int Idx = 0; Idx < BuildList.Items.Count; Idx++) + SendMessage(Handle, WM_SETREDRAW, 0, 0); + SuspendLayout(); + + if(CurrentWorkspace != null) { - PerforceChangeSummary Change = (PerforceChangeSummary)BuildList.Items[Idx].Tag; - if(ChangeType == LatestChangeType.Any) - { - if(CanSyncChange(Change.Number)) - { - ChangeNumber = FindNewestGoodContentChange(Change.Number); - return true; - } - } - else if(ChangeType == LatestChangeType.Good) - { - EventSummary Summary = EventMonitor.GetSummaryForChange(Change.Number); - if(Summary != null && Summary.Verdict == ReviewVerdict.Good && CanSyncChange(Change.Number)) - { - ChangeNumber = FindNewestGoodContentChange(Change.Number); - return true; - } - } - else if(ChangeType == LatestChangeType.Starred) - { - EventSummary Summary = EventMonitor.GetSummaryForChange(Change.Number); - if(((Summary != null && Summary.LastStarReview != null) || PromotedChangeNumbers.Contains(Change.Number)) && CanSyncChange(Change.Number)) - { - ChangeNumber = FindNewestGoodContentChange(Change.Number); - return true; - } - } + CurrentWorkspace.Deactivate(); + CurrentWorkspace.Hide(); } - ChangeNumber = -1; - return false; - } - - int FindNewestGoodContentChange(int ChangeNumber) - { - int Index = SortedChangeNumbers.BinarySearch(ChangeNumber); - if(Index <= 0) + if(NewTabData == null) { - return ChangeNumber; - } - - for(int NextIndex = Index + 1; NextIndex < SortedChangeNumbers.Count; NextIndex++) - { - int NextChangeNumber = SortedChangeNumbers[NextIndex]; - - PerforceChangeType Type; - if(!PerforceMonitor.TryGetChangeType(NextChangeNumber, out Type) || Type != PerforceChangeType.Content) - { - break; - } - - EventSummary Summary = EventMonitor.GetSummaryForChange(NextChangeNumber); - if(Summary != null && Summary.Verdict == ReviewVerdict.Bad) - { - break; - } - - Index = NextIndex; - } - - return SortedChangeNumbers[Index]; - } - - private void BuildListContextMenu_LeaveOrEditComment_Click(object sender, EventArgs e) - { - if(ContextMenuChange != null) - { - LeaveCommentWindow LeaveComment = new LeaveCommentWindow(); - - string CommentText; - if(EventMonitor.GetCommentByCurrentUser(ContextMenuChange.Number, out CommentText)) - { - LeaveComment.CommentTextBox.Text = CommentText; - } - - if(LeaveComment.ShowDialog() == System.Windows.Forms.DialogResult.OK) - { - EventMonitor.PostComment(ContextMenuChange.Number, LeaveComment.CommentTextBox.Text); - } - } - } - - private void BuildListContextMenu_ShowServerTimes_Click(object sender, EventArgs e) - { - Settings.bShowLocalTimes = false; - Settings.Save(); - UpdateBuildList(); - } - - private void BuildListContextMenu_ShowLocalTimes_Click(object sender, EventArgs e) - { - Settings.bShowLocalTimes = true; - Settings.Save(); - UpdateBuildList(); - } - - private void MoreToolsContextMenu_CleanWorkspace_Click(object sender, EventArgs e) - { - CleanWorkspaceWindow.DoClean(Workspace.Perforce, BranchDirectoryName, Workspace.ClientRootPath, Workspace.SyncPaths, Log); - } - - private void UpdateBuildSteps() - { - bHasBuildSteps = false; - - foreach(ToolStripMenuItem CustomToolMenuItem in CustomToolMenuItems) - { - MoreToolsContextMenu.Items.Remove(CustomToolMenuItem); - } - - CustomToolMenuItems.Clear(); - - if(Workspace != null) - { - ConfigFile ProjectConfigFile = Workspace.ProjectConfigFile; - if(ProjectConfigFile != null) - { - Dictionary ProjectBuildStepObjects = GetProjectBuildStepObjects(ProjectConfigFile); - - int InsertIdx = 0; - - List UserSteps = GetUserBuildSteps(ProjectBuildStepObjects); - foreach(BuildStep Step in UserSteps) - { - if(Step.bShowAsTool) - { - ToolStripMenuItem NewMenuItem = new ToolStripMenuItem(Step.Description); - NewMenuItem.Click += new EventHandler((sender, e) => { RunCustomTool(Step.UniqueId); }); - CustomToolMenuItems.Add(NewMenuItem); - MoreToolsContextMenu.Items.Insert(InsertIdx++, NewMenuItem); - } - bHasBuildSteps |= Step.bNormalSync; - } - } - } - - MoreActionsContextMenu_CustomToolSeparator.Visible = (CustomToolMenuItems.Count > 0); - } - - private void RunCustomTool(Guid UniqueId) - { - if(Workspace != null) - { - if(Workspace.IsBusy()) - { - MessageBox.Show("Please retry after the current sync has finished.", "Sync in Progress"); - } - else - { - WorkspaceUpdateContext Context = new WorkspaceUpdateContext(Workspace.CurrentChangeNumber, WorkspaceUpdateOptions.Build, null, GetDefaultBuildStepObjects(), Settings.CurrentProject.BuildSteps, new HashSet{ UniqueId }, GetWorkspaceVariables()); - StartWorkspaceUpdate(Context); - } - } - } - - private Dictionary GetWorkspaceVariables() - { - BuildConfig EditorBuildConfig = GetEditorBuildConfig(); - - Dictionary Variables = new Dictionary(); - Variables.Add("BranchDir", BranchDirectoryName); - Variables.Add("ProjectDir", Path.GetDirectoryName(SelectedFileName)); - Variables.Add("ProjectFile", SelectedFileName); - Variables.Add("UE4EditorExe", GetEditorExePath(EditorBuildConfig)); - Variables.Add("UE4EditorCmdExe", GetEditorExePath(EditorBuildConfig).Replace(".exe", "-Cmd.exe")); - Variables.Add("UE4EditorConfig", EditorBuildConfig.ToString()); - Variables.Add("UE4EditorDebugArg", (EditorBuildConfig == BuildConfig.Debug || EditorBuildConfig == BuildConfig.DebugGame)? " -debug" : ""); - return Variables; - } - - private void OptionsContextMenu_EditBuildSteps_Click(object sender, EventArgs e) - { - ConfigFile ProjectConfigFile = Workspace.ProjectConfigFile; - if(Workspace != null && ProjectConfigFile != null) - { - // Find all the target names for this project - List TargetNames = new List(); - if(!String.IsNullOrEmpty(SelectedFileName) && SelectedFileName.EndsWith(".uproject", StringComparison.InvariantCultureIgnoreCase)) - { - DirectoryInfo SourceDirectory = new DirectoryInfo(Path.Combine(Path.GetDirectoryName(SelectedFileName), "Source")); - if(SourceDirectory.Exists) - { - foreach(FileInfo TargetFile in SourceDirectory.EnumerateFiles("*.target.cs", SearchOption.TopDirectoryOnly)) - { - TargetNames.Add(TargetFile.Name.Substring(0, TargetFile.Name.IndexOf('.'))); - } - } - } - - // Get all the task objects - Dictionary ProjectBuildStepObjects = GetProjectBuildStepObjects(ProjectConfigFile); - List UserSteps = GetUserBuildSteps(ProjectBuildStepObjects); - - // Show the dialog - ModifyBuildStepsWindow EditStepsWindow = new ModifyBuildStepsWindow(TargetNames, UserSteps, new HashSet(ProjectBuildStepObjects.Keys), BranchDirectoryName, GetWorkspaceVariables()); - EditStepsWindow.ShowDialog(); - - // Update the user settings - List ModifiedBuildSteps = new List(); - foreach(BuildStep Step in UserSteps) - { - ConfigObject DefaultObject; - ProjectBuildStepObjects.TryGetValue(Step.UniqueId, out DefaultObject); - - ConfigObject UserConfigObject = Step.ToConfigObject(DefaultObject); - if(UserConfigObject != null) - { - ModifiedBuildSteps.Add(UserConfigObject); - } - } - - // Save the settings - Settings.CurrentProject.BuildSteps = ModifiedBuildSteps; - Settings.Save(); - - // Update the custom tools menu, because we might have changed it - UpdateBuildSteps(); - UpdateSyncActionCheckboxes(); - } - } - - private void AddOrUpdateBuildStep(Dictionary Steps, ConfigObject Object) - { - Guid UniqueId; - if(Guid.TryParse(Object.GetValue(BuildStep.UniqueIdKey, ""), out UniqueId)) - { - ConfigObject DefaultObject; - if(Steps.TryGetValue(UniqueId, out DefaultObject)) - { - Object.SetDefaults(DefaultObject); - } - Steps[UniqueId] = Object; - } - } - - private bool ShouldSyncPrecompiledEditor - { - get { return Settings.bSyncPrecompiledEditor && PerforceMonitor != null && PerforceMonitor.HasZippedBinaries; } - } - - public BuildConfig GetEditorBuildConfig() - { - return ShouldSyncPrecompiledEditor? BuildConfig.Development : Settings.CompiledEditorBuildConfig; - } - - private Dictionary GetDefaultBuildStepObjects() - { - List DefaultBuildSteps = new List(); - DefaultBuildSteps.Add(new BuildStep(new Guid("{01F66060-73FA-4CC8-9CB3-E217FBBA954E}"), 0, "Compile UnrealHeaderTool", "Compiling UnrealHeaderTool...", 1, "UnrealHeaderTool", "Win64", "Development", "", !ShouldSyncPrecompiledEditor)); - string ActualEditorTargetName = EditorTargetName ?? "UE4Editor"; - DefaultBuildSteps.Add(new BuildStep(new Guid("{F097FF61-C916-4058-8391-35B46C3173D5}"), 1, String.Format("Compile {0}", ActualEditorTargetName), String.Format("Compiling {0}...", ActualEditorTargetName), 10, ActualEditorTargetName, "Win64", Settings.CompiledEditorBuildConfig.ToString(), "", !ShouldSyncPrecompiledEditor)); - DefaultBuildSteps.Add(new BuildStep(new Guid("{C6E633A1-956F-4AD3-BC95-6D06D131E7B4}"), 2, "Compile ShaderCompileWorker", "Compiling ShaderCompileWorker...", 1, "ShaderCompileWorker", "Win64", "Development", "", !ShouldSyncPrecompiledEditor)); - DefaultBuildSteps.Add(new BuildStep(new Guid("{24FFD88C-7901-4899-9696-AE1066B4B6E8}"), 3, "Compile UnrealLightmass", "Compiling UnrealLightmass...", 1, "UnrealLightmass", "Win64", "Development", "", !ShouldSyncPrecompiledEditor)); - DefaultBuildSteps.Add(new BuildStep(new Guid("{FFF20379-06BF-4205-8A3E-C53427736688}"), 4, "Compile CrashReportClient", "Compiling CrashReportClient...", 1, "CrashReportClient", "Win64", "Shipping", "", !ShouldSyncPrecompiledEditor)); - return DefaultBuildSteps.ToDictionary(x => x.UniqueId, x => x.ToConfigObject()); - } - - private Dictionary GetProjectBuildStepObjects(ConfigFile ProjectConfigFile) - { - Dictionary ProjectBuildSteps = GetDefaultBuildStepObjects(); - foreach(string Line in ProjectConfigFile.GetValues("Build.Step", new string[0])) - { - AddOrUpdateBuildStep(ProjectBuildSteps, new ConfigObject(Line)); - } - return ProjectBuildSteps; - } - - private List GetUserBuildSteps(Dictionary ProjectBuildStepObjects) - { - // Read all the user-defined build tasks and modifications to the default list - Dictionary UserBuildStepObjects = ProjectBuildStepObjects.ToDictionary(x => x.Key, y => new ConfigObject(y.Value)); - foreach(ConfigObject UserBuildStep in Settings.CurrentProject.BuildSteps) - { - AddOrUpdateBuildStep(UserBuildStepObjects, UserBuildStep); - } - - // Create the expanded task objects - return UserBuildStepObjects.Values.Select(x => new BuildStep(x)).OrderBy(x => x.OrderIndex).ToList(); - } - - private void OptionsContextMenu_AutomaticallyRunAtStartup_Click(object sender, EventArgs e) - { - RegistryKey Key = Registry.CurrentUser.CreateSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"); - if(OptionsContextMenu_AutomaticallyRunAtStartup.Checked) - { - Key.DeleteValue("UnrealGameSync", false); + CurrentWorkspace = null; + Settings.LastProjectFileName = null; + DefaultControl.Show(); } else { - Key.SetValue("UnrealGameSync", OriginalExecutableFileName); + CurrentWorkspace = (WorkspaceControl)NewTabData; + Settings.LastProjectFileName = CurrentWorkspace.SelectedFileName; + DefaultControl.Hide(); } - } - private bool IsAutomaticallyRunAtStartup() - { - RegistryKey Key = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"); - return (Key.GetValue("UnrealGameSync") != null); - } - - private void OptionsContextMenu_SyncPrecompiledEditor_Click(object sender, EventArgs e) - { - OptionsContextMenu_SyncPrecompiledEditor.Checked ^= true; - - Settings.bSyncPrecompiledEditor = OptionsContextMenu_SyncPrecompiledEditor.Checked; Settings.Save(); - UpdateBuildSteps(); - UpdateSyncActionCheckboxes(); - - BuildList.Invalidate(); - } - - private void BuildList_SelectedIndexChanged(object sender, EventArgs e) - { - PendingSelectedChangeNumber = -1; - } - - private void OptionsContextMenu_Diagnostics_Click(object sender, EventArgs e) - { - StringBuilder DiagnosticsText = new StringBuilder(); - DiagnosticsText.AppendFormat("Application version: {0}\n", Assembly.GetExecutingAssembly().GetName().Version); - DiagnosticsText.AppendFormat("Synced from: {0}\n", Program.SyncVersion ?? "(unknown)"); - DiagnosticsText.AppendFormat("Selected file: {0}\n", (SelectedFileName == null)? "(none)" : SelectedFileName); - if(Workspace != null) + if(CurrentWorkspace != null) { - DiagnosticsText.AppendFormat("P4 server: {0}\n", Workspace.Perforce.ServerAndPort ?? "(default)"); - DiagnosticsText.AppendFormat("P4 user: {0}\n", Workspace.Perforce.UserName); - DiagnosticsText.AppendFormat("P4 workspace: {0}\n", Workspace.Perforce.ClientName); + CurrentWorkspace.Activate(); + CurrentWorkspace.Show(); } - DiagnosticsText.AppendFormat("Perforce monitor: {0}\n", (PerforceMonitor == null)? "(inactive)" : PerforceMonitor.LastStatusMessage); - DiagnosticsText.AppendFormat("Event monitor: {0}\n", (EventMonitor == null)? "(inactive)" : EventMonitor.LastStatusMessage); - DiagnosticsWindow Diagnostics = new DiagnosticsWindow(DataFolder, DiagnosticsText.ToString()); - Diagnostics.ShowDialog(this); + ResumeLayout(); + + SendMessage(Handle, WM_SETREDRAW, 1, 0); + Refresh(); } - private void OptionsContextMenu_SyncFilter_Click(object sender, EventArgs e) + public void BrowseForProject(int ReplaceTabIdx = -1) { - SyncFilter Filter = new SyncFilter(Settings.SyncFilter, Settings.CurrentWorkspace.SyncFilter); - if(Filter.ShowDialog() == DialogResult.OK) + OpenFileDialog Dialog = new OpenFileDialog(); + Dialog.Filter = "Project files (*.uproject)|*.uproject|Project directory lists (*.uprojectdirs)|*.uprojectdirs|All files (*.*)|*.*" ; + if(Dialog.ShowDialog(this) == System.Windows.Forms.DialogResult.OK) { - Settings.SyncFilter = Filter.GlobalFilter; - Settings.CurrentWorkspace.SyncFilter = Filter.WorkspaceFilter; - Settings.Save(); + Settings.OtherProjectFileNames = Enumerable.Concat(new string[]{ Path.GetFullPath(Dialog.FileName) }, Settings.OtherProjectFileNames).Where(x => !String.IsNullOrEmpty(x)).Distinct(StringComparer.InvariantCultureIgnoreCase).ToArray(); + Settings.Save(); + + int TabIdx = TryOpenProject(Dialog.FileName, ReplaceTabIdx); + if(TabIdx != -1) + { + TabControl.SelectTab(TabIdx); + SaveTabSettings(); + } } } - private void ShowSyncMenu(Rectangle Bounds) + int TryOpenProject(string ProjectFileName, int ReplaceTabIdx = -1) { - SyncContextMenu_LatestChange.Checked = (Settings.SyncType == LatestChangeType.Any); - SyncContextMenu_LatestGoodChange.Checked = (Settings.SyncType == LatestChangeType.Good); - SyncContextMenu_LatestStarredChange.Checked = (Settings.SyncType == LatestChangeType.Starred); - SyncContextMenu.Show(StatusPanel, new Point(Bounds.Left, Bounds.Bottom), ToolStripDropDownDirection.BelowRight); - } + Log.WriteLine("Trying to open project {0}", ProjectFileName); - private void SyncContextMenu_LatestChange_Click(object sender, EventArgs e) - { - Settings.SyncType = LatestChangeType.Any; - Settings.Save(); - } + // Normalize the filename + ProjectFileName = Path.GetFullPath(ProjectFileName).Replace('/', Path.DirectorySeparatorChar); - private void SyncContextMenu_LatestGoodChange_Click(object sender, EventArgs e) - { - Settings.SyncType = LatestChangeType.Good; - Settings.Save(); - } - - private void SyncContextMenu_LatestStarredChange_Click(object sender, EventArgs e) - { - Settings.SyncType = LatestChangeType.Starred; - Settings.Save(); - } - - private void SyncContextMenu_EnterChangelist_Click(object sender, EventArgs e) - { - ChangelistWindow ChildWindow = new ChangelistWindow((Workspace == null)? -1 : Workspace.CurrentChangeNumber); - if(ChildWindow.ShowDialog() == DialogResult.OK) + // Make sure the project exists + if(!File.Exists(ProjectFileName)) { - StartSync(ChildWindow.ChangeNumber); + ShowErrorDialog("{0} does not exist.", ProjectFileName); + return -1; + } + + // Check that none of the other tabs already have it open + for(int TabIdx = 0; TabIdx < TabControl.GetTabCount(); TabIdx++) + { + if(ReplaceTabIdx != TabIdx) + { + WorkspaceControl Workspace = (WorkspaceControl)TabControl.GetTabData(TabIdx); + if(Workspace.SelectedFileName.Equals(ProjectFileName, StringComparison.InvariantCultureIgnoreCase)) + { + TabControl.SelectTab(TabIdx); + return TabIdx; + } + else if(ProjectFileName.StartsWith(Workspace.BranchDirectoryName + Path.DirectorySeparatorChar, StringComparison.InvariantCultureIgnoreCase)) + { + if(MessageBox.Show(String.Format("{0} is already open under {1}.\n\nWould you like to close it?", Path.GetFileNameWithoutExtension(Workspace.SelectedFileName), Workspace.BranchDirectoryName, Path.GetFileNameWithoutExtension(ProjectFileName)), "Branch already open", MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes) + { + TabControl.RemoveTab(TabIdx); + } + else + { + return -1; + } + } + } + } + + // Make sure the path case is correct. This can cause UBT intermediates to be out of date if the case mismatches. + ProjectFileName = Utility.GetPathWithCorrectCase(new FileInfo(ProjectFileName)); + + // Detect the project settings in a background thread + using(DetectProjectSettingsTask DetectSettings = new DetectProjectSettingsTask(ProjectFileName, Log)) + { + string ErrorMessage; + if(!ModalTaskWindow.Execute(this, DetectSettings, "Opening Project", "Opening project, please wait...", out ErrorMessage)) + { + if(!String.IsNullOrEmpty(ErrorMessage)) + { + ShowErrorDialog("{0}", ErrorMessage); + } + return -1; + } + + // Hide the default control if it's visible + DefaultControl.Hide(); + + // Now that we have the project settings, we can construct the tab + WorkspaceControl Workspace = new WorkspaceControl(this, SqlConnectionString, DataFolder, bRestoreStateOnLoad, OriginalExecutableFileName, ProjectFileName, bUnstable, DetectSettings, Log, Settings); + Workspace.Parent = TabPanel; + Workspace.Location = new Point(0, 0); + Workspace.Size = new Size(TabPanel.Width, TabPanel.Height); + Workspace.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom; + Workspace.Hide(); + + // Add the tab + string NewTabName = GetTabName(Workspace); + if(ReplaceTabIdx == -1) + { + int NewTabIdx = TabControl.InsertTab(-1, NewTabName, Workspace); + return NewTabIdx; + } + else + { + TabControl.InsertTab(ReplaceTabIdx + 1, NewTabName, Workspace); + TabControl.RemoveTab(ReplaceTabIdx); + return ReplaceTabIdx; + } } } - private void OptionsContextMenu_KeepInTray_Click(object sender, EventArgs e) + public void StreamChanged(WorkspaceControl Workspace) { - Settings.bKeepInTray ^= true; + BeginInvoke(new MethodInvoker(() => StreamChangedCallback(Workspace))); + } + + public void StreamChangedCallback(WorkspaceControl Workspace) + { + for(int Idx = 0; Idx < TabControl.GetTabCount(); Idx++) + { + if(TabControl.GetTabData(Idx) == Workspace) + { + string ProjectFileName = Workspace.SelectedFileName; + if(TryOpenProject(ProjectFileName, Idx) == -1) + { + TabControl.RemoveTab(Idx); + } + break; + } + } + } + + void SaveTabSettings() + { + List OpenProjectFileNames = new List(); + for(int TabIdx = 0; TabIdx < TabControl.GetTabCount(); TabIdx++) + { + WorkspaceControl Workspace = (WorkspaceControl)TabControl.GetTabData(TabIdx); + OpenProjectFileNames.Add(Workspace.SelectedFileName); + } + Settings.OpenProjectFileNames = OpenProjectFileNames.ToArray(); Settings.Save(); } - private void BuildList_KeyDown(object Sender, KeyEventArgs Args) + void TabControl_OnNewTabClick(Point Location, MouseButtons Buttons) { - if(Args.Control && Args.KeyCode == Keys.C && BuildList.SelectedItems.Count > 0) + if(Buttons == MouseButtons.Left) { - int SelectedChange = ((PerforceChangeSummary)BuildList.SelectedItems[0].Tag).Number; - Clipboard.SetText(String.Format("{0}", SelectedChange)); + BrowseForProject(); } } - private void OptionsContextMenu_PerforceSettings_Click(object sender, EventArgs e) + string GetTabName(WorkspaceControl Workspace) { - PerforceSettingsWindow Perforce = new PerforceSettingsWindow(Settings); - Perforce.ShowDialog(); + switch(Settings.TabLabels) + { + case TabLabels.Stream: + return Workspace.StreamName; + case TabLabels.ProjectFile: + return Workspace.SelectedFileName; + case TabLabels.WorkspaceName: + return Workspace.ClientName; + case TabLabels.WorkspaceRoot: + default: + return Workspace.BranchDirectoryName; + } + } + + public void SetTabNames(TabLabels NewTabNames) + { + if(Settings.TabLabels != NewTabNames) + { + Settings.TabLabels = NewTabNames; + Settings.Save(); + + for(int Idx = 0; Idx < TabControl.GetTabCount(); Idx++) + { + WorkspaceControl Workspace = (WorkspaceControl)TabControl.GetTabData(Idx); + TabControl.SetTabName(Idx, GetTabName(Workspace)); + } + } + } + + private void TabMenu_OpenProject_Click(object sender, EventArgs e) + { + BrowseForProject(TabMenu_TabIndex); + } + + private void TabMenu_TabNames_Stream_Click(object sender, EventArgs e) + { + SetTabNames(TabLabels.Stream); + } + + private void TabMenu_TabNames_WorkspaceName_Click(object sender, EventArgs e) + { + SetTabNames(TabLabels.WorkspaceName); + } + + private void TabMenu_TabNames_WorkspaceRoot_Click(object sender, EventArgs e) + { + SetTabNames(TabLabels.WorkspaceRoot); + } + + private void TabMenu_TabNames_ProjectFile_Click(object sender, EventArgs e) + { + SetTabNames(TabLabels.ProjectFile); + } + + private void TabMenu_RecentProjects_ClearList_Click(object sender, EventArgs e) + { + Settings.OtherProjectFileNames = new string[0]; + Settings.Save(); + } + + private void TabMenu_Closed(object sender, ToolStripDropDownClosedEventArgs e) + { + TabControl.UnlockHover(); + } + + public void UpdateProgress() + { + TaskbarState State = TaskbarState.NoProgress; + float Progress = -1.0f; + + for(int Idx = 0; Idx < TabControl.GetTabCount(); Idx++) + { + WorkspaceControl Workspace = (WorkspaceControl)TabControl.GetTabData(Idx); + + Tuple DesiredTaskbarState = Workspace.DesiredTaskbarState; + if(DesiredTaskbarState.Item1 == TaskbarState.Error) + { + State = TaskbarState.Error; + TabControl.SetHighlight(Idx, Tuple.Create(Color.FromArgb(204, 64, 64), 1.0f)); + } + else if(DesiredTaskbarState.Item1 == TaskbarState.Paused && State != TaskbarState.Error) + { + State = TaskbarState.Paused; + TabControl.SetHighlight(Idx, Tuple.Create(Color.FromArgb(255, 242, 0), 1.0f)); + } + else if(DesiredTaskbarState.Item1 == TaskbarState.Normal && State != TaskbarState.Error && State != TaskbarState.Paused) + { + State = TaskbarState.Normal; + Progress = Math.Max(Progress, DesiredTaskbarState.Item2); + TabControl.SetHighlight(Idx, Tuple.Create(Color.FromArgb(28, 180, 64), DesiredTaskbarState.Item2)); + } + else + { + TabControl.SetHighlight(Idx, null); + } + } + + if(State == TaskbarState.Normal) + { + Taskbar.SetState(Handle, TaskbarState.Normal); + Taskbar.SetProgress(Handle, (ulong)(Progress * 1000.0f), 1000); + } + else + { + Taskbar.SetState(Handle, State); + } } } } diff --git a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Forms/MainWindow.resx b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Forms/MainWindow.resx index ed0fdece4b9f..52054e7a4eb0 100644 --- a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Forms/MainWindow.resx +++ b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Forms/MainWindow.resx @@ -117,12 +117,6 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - 201, 17 - - - 370, 17 - 541, 17 @@ -1080,18 +1074,9 @@ 4A1veCPpRjsAaXV1HoiqN7zRBkfa/wMss7RLd+ic+QAAAABJRU5ErkJggg== - + 766, 17 - - 17, 17 - - - 904, 17 - - - 1055, 17 - AAABAAoAEBAQAAEABAAoAQAApgAAABAQAAABAAgAaAUAAM4BAAAQEAAAAQAgAGgEAAA2BwAAICAQAAEA diff --git a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Forms/ModalTaskWindow.cs b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Forms/ModalTaskWindow.cs index a0dc3cf9ebf4..f835e6c36bb3 100644 --- a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Forms/ModalTaskWindow.cs +++ b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Forms/ModalTaskWindow.cs @@ -36,10 +36,10 @@ namespace UnrealGameSync InitializeComponent(); } - public static bool Execute(IModalTask Task, string InTitle, string InMessage, out string ErrorMessage) + public static bool Execute(IWin32Window Owner, IModalTask Task, string InTitle, string InMessage, out string ErrorMessage) { ModalTaskWindow Window = new ModalTaskWindow(Task, InTitle, InMessage); - Window.ShowDialog(); + Window.ShowDialog(Owner); ErrorMessage = Window.ErrorMessage; return Window.bSucceeded; } diff --git a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Perforce.cs b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Perforce.cs index 95bf1b0afcdc..6cb3998d2231 100644 --- a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Perforce.cs +++ b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Perforce.cs @@ -50,6 +50,83 @@ namespace UnrealGameSync } } + [DebuggerDisplay("{DepotFile}")] + class PerforceDescribeFileRecord + { + public string DepotFile; + public string Action; + public string Type; + public int Revision; + public int FileSize; + public string Digest; + } + + [DebuggerDisplay("{ChangeNumber}: {Description}")] + class PerforceDescribeRecord + { + public int ChangeNumber; + public string User; + public string Client; + public long Time; + public string Description; + public string Status; + public string ChangeType; + public string Path; + public List Files = new List(); + + public PerforceDescribeRecord(Dictionary Tags) + { + string ChangeString; + if(!Tags.TryGetValue("change", out ChangeString) || !int.TryParse(ChangeString, out ChangeNumber)) + { + ChangeNumber = -1; + } + + Tags.TryGetValue("user", out User); + Tags.TryGetValue("client", out Client); + + string TimeString; + if(!Tags.TryGetValue("time", out TimeString) || !long.TryParse(TimeString, out Time)) + { + Time = -1; + } + + Tags.TryGetValue("desc", out Description); + Tags.TryGetValue("status", out Status); + Tags.TryGetValue("changeType", out ChangeType); + Tags.TryGetValue("path", out Path); + + for(int Idx = 0;;Idx++) + { + string Suffix = String.Format("{0}", Idx); + + PerforceDescribeFileRecord File = new PerforceDescribeFileRecord(); + if(!Tags.TryGetValue("depotFile" + Suffix, out File.DepotFile)) + { + break; + } + + Tags.TryGetValue("action" + Suffix, out File.Action); + Tags.TryGetValue("type" + Suffix, out File.Type); + + string RevisionString; + if(!Tags.TryGetValue("rev" + Suffix, out RevisionString) || !int.TryParse(RevisionString, out File.Revision)) + { + File.Revision = -1; + } + + string FileSizeString; + if(!Tags.TryGetValue("fileSize" + Suffix, out FileSizeString) || !int.TryParse(FileSizeString, out File.FileSize)) + { + File.FileSize = -1; + } + + Tags.TryGetValue("digest" + Suffix, out File.Digest); + Files.Add(File); + } + } + } + [DebuggerDisplay("{ServerAddress}")] class PerforceInfoRecord { @@ -757,6 +834,35 @@ namespace UnrealGameSync return RunCommand(String.Format("client -f -s -S \"{0}\" \"{1}\"", NewStream, ClientName), CommandOptions.None, Log); } + public bool Describe(int ChangeNumber, out PerforceDescribeRecord Record, TextWriter Log) + { + string CommandLine = String.Format("describe -s {0}", ChangeNumber); + + List> Records = new List>(); + if(!RunCommandWithBinaryOutput(CommandLine, Records, CommandOptions.None, Log)) + { + Record = null; + return false; + } + if(Records.Count != 1) + { + Log.WriteLine("Expected 1 record from p4 {0}, got {1}", CommandLine, Records.Count); + Record = null; + return false; + } + + string Code; + if(!Records[0].TryGetValue("code", out Code) || Code != "stat") + { + Log.WriteLine("Unexpected response from p4 {0}: {1}", CommandLine, String.Join(", ", Records[0].Select(x => String.Format("{ \"{0}\", \"{1}\" }", x.Key, x.Value)))); + Record = null; + return false; + } + + Record = new PerforceDescribeRecord(Records[0]); + return true; + } + public bool Where(string Filter, out PerforceWhereRecord WhereRecord, TextWriter Log) { List FileRecords; @@ -1113,6 +1219,113 @@ namespace UnrealGameSync } return false; } + + /// + /// Execute a Perforce command and parse the output as marshalled Python objects. This is more robustly defined than the text-based tagged output + /// format, because it avoids ambiguity when returned fields can have newlines. + /// + /// Command line to execute Perforce with + /// List that receives the output records + /// Whether to include client information on the command line + private bool RunCommandWithBinaryOutput(string CommandLine, List> Records, CommandOptions Options, TextWriter Log) + { + return RunCommandWithBinaryOutput(CommandLine, Record => { Records.Add(Record); return true; }, Options, Log); + } + + /// + /// Execute a Perforce command and parse the output as marshalled Python objects. This is more robustly defined than the text-based tagged output + /// format, because it avoids ambiguity when returned fields can have newlines. + /// + /// Command line to execute Perforce with + /// List that receives the output records + /// Whether to include client information on the command line + private bool RunCommandWithBinaryOutput(string CommandLine, HandleRecordDelegate HandleOutput, CommandOptions Options, TextWriter Log) + { + // Execute Perforce, consuming the binary output into a memory stream + MemoryStream MemoryStream = new MemoryStream(); + using (Process Process = new Process()) + { + Process.StartInfo.FileName = "p4.exe"; + Process.StartInfo.Arguments = GetFullCommandLine("-G " + CommandLine, Options | CommandOptions.NoChannels); + + Process.StartInfo.RedirectStandardError = true; + Process.StartInfo.RedirectStandardOutput = true; + Process.StartInfo.RedirectStandardInput = false; + Process.StartInfo.UseShellExecute = false; + Process.StartInfo.CreateNoWindow = true; + + Process.Start(); + + Process.StandardOutput.BaseStream.CopyTo(MemoryStream); + Process.WaitForExit(); + } + + // Move back to the start of the memory stream + MemoryStream.Position = 0; + + // Parse the records + List> Records = new List>(); + using (BinaryReader Reader = new BinaryReader(MemoryStream, Encoding.UTF8)) + { + while(Reader.BaseStream.Position < Reader.BaseStream.Length) + { + // Check that a dictionary follows + byte Temp = Reader.ReadByte(); + if(Temp != '{') + { + Log.WriteLine("Unexpected data while parsing marshalled output - expected '{'"); + return false; + } + + // Read all the fields in the record + Dictionary Record = new Dictionary(); + for(;;) + { + // Read the next field type. Perforce only outputs string records. A '0' character indicates the end of the dictionary. + byte KeyFieldType = Reader.ReadByte(); + if(KeyFieldType == '0') + { + break; + } + else if(KeyFieldType != 's') + { + Log.WriteLine("Unexpected key field type while parsing marshalled output ({0}) - expected 's'", (int)KeyFieldType); + return false; + } + + // Read the key + int KeyLength = Reader.ReadInt32(); + string Key = Encoding.UTF8.GetString(Reader.ReadBytes(KeyLength)); + + // Read the value type. + byte ValueFieldType = Reader.ReadByte(); + if(ValueFieldType == 'i') + { + // An integer + string Value = Reader.ReadInt32().ToString(); + Record.Add(Key, Value); + } + else if(ValueFieldType == 's') + { + // A string + int ValueLength = Reader.ReadInt32(); + string Value = Encoding.UTF8.GetString(Reader.ReadBytes(ValueLength)); + Record.Add(Key, Value); + } + else + { + Log.WriteLine("Unexpected value field type while parsing marshalled output ({0}) - expected 's'", (int)ValueFieldType); + return false; + } + } + if(!HandleOutput(Record)) + { + return false; + } + } + } + return true; + } } static class PerforceUtils diff --git a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/PerforceMonitor.cs b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/PerforceMonitor.cs index 6036d67faff6..cfa64ff0926d 100644 --- a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/PerforceMonitor.cs +++ b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/PerforceMonitor.cs @@ -160,7 +160,7 @@ namespace UnrealGameSync } // Wait for another request, or scan for new builds after a timeout - RefreshEvent.WaitOne(30 * 1000); + RefreshEvent.WaitOne(60 * 1000); } } @@ -286,35 +286,45 @@ namespace UnrealGameSync public bool UpdateChangeTypes() { - // Get the minimum change we need to query - bool bRequiresUpdate; + // Find the changes we need to query + List QueryChangeNumbers = new List(); lock(this) { - bRequiresUpdate = Changes.Any(x => !ChangeTypes.ContainsKey(x.Number)); + foreach(PerforceChangeSummary Change in Changes) + { + if(!ChangeTypes.ContainsKey(Change.Number)) + { + QueryChangeNumbers.Add(Change.Number); + } + } } - // If there's something to check for, find all the content changes after this changelist - if(bRequiresUpdate) + // Update them in batches + foreach(int QueryChangeNumber in QueryChangeNumbers) { string[] CodeExtensions = { ".cs", ".h", ".cpp", ".usf" }; - // Find all the content changes in this range. Include a few extra changes in case there have been more changes submitted since the last query (it seems -m is much faster than specifying a changelist range) - List CodeChanges; - if(!Perforce.FindChanges(CodeExtensions.Select(Extension => String.Format("{0}/...{1}", BranchClientPath, Extension)), CurrentMaxChanges + 10, out CodeChanges, LogWriter)) + // If there's something to check for, find all the content changes after this changelist + PerforceDescribeRecord DescribeRecord; + if(Perforce.Describe(QueryChangeNumber, out DescribeRecord, LogWriter)) { - return false; - } - - // Update the change types - HashSet CodeChangeNumbers = new HashSet(CodeChanges.Select(x => x.Number)); - lock(this) - { - foreach(PerforceChangeSummary Change in Changes) + // Check whether the files are code or content + PerforceChangeType Type; + if(CodeExtensions.Any(Extension => DescribeRecord.Files.Any(File => File.DepotFile.EndsWith(Extension, StringComparison.InvariantCultureIgnoreCase)))) { - if(!ChangeTypes.ContainsKey(Change.Number)) + Type = PerforceChangeType.Code; + } + else + { + Type = PerforceChangeType.Content; + } + + // Update the type of this change + lock(this) + { + if(!ChangeTypes.ContainsKey(QueryChangeNumber)) { - PerforceChangeType Type = CodeChangeNumbers.Contains(Change.Number)? PerforceChangeType.Code : PerforceChangeType.Content; - ChangeTypes.Add(Change.Number, Type); + ChangeTypes.Add(QueryChangeNumber, Type); } } } diff --git a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Program.cs b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Program.cs index 88c74428071c..b586258dac64 100644 --- a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Program.cs +++ b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Program.cs @@ -92,12 +92,28 @@ namespace UnrealGameSync { using(UpdateMonitor UpdateMonitor = new UpdateMonitor(new PerforceConnection(null, null, null), UpdatePath)) { - MainWindow Window = new MainWindow(UpdateMonitor, SqlConnectionString, DataFolder, ActivateEvent, bRestoreState, UpdateSpawn ?? Assembly.GetExecutingAssembly().Location, ProjectFileName, bUnstable); - if(bUnstable) + using(BoundedLogWriter Log = new BoundedLogWriter(Path.Combine(DataFolder, "UnrealGameSync.log"))) { - Window.Text += String.Format(" (UNSTABLE BUILD {0})", Assembly.GetExecutingAssembly().GetName().Version); + Log.WriteLine("Application version: {0}", Assembly.GetExecutingAssembly().GetName().Version); + Log.WriteLine("Started at {0}", DateTime.Now.ToString()); + + UserSettings Settings = new UserSettings(Path.Combine(DataFolder, "UnrealGameSync.ini")); + if(!String.IsNullOrEmpty(ProjectFileName)) + { + string FullProjectFileName = Path.GetFullPath(ProjectFileName); + if(!Settings.OpenProjectFileNames.Any(x => x.Equals(FullProjectFileName, StringComparison.InvariantCultureIgnoreCase))) + { + Settings.OpenProjectFileNames = Settings.OpenProjectFileNames.Concat(new string[]{ FullProjectFileName }).ToArray(); + } + } + + MainWindow Window = new MainWindow(UpdateMonitor, SqlConnectionString, DataFolder, ActivateEvent, bRestoreState, UpdateSpawn ?? Assembly.GetExecutingAssembly().Location, ProjectFileName, bUnstable, Log, Settings); + if(bUnstable) + { + Window.Text += String.Format(" (UNSTABLE BUILD {0})", Assembly.GetExecutingAssembly().GetName().Version); + } + Application.Run(Window); } - Application.Run(Window); if(UpdateMonitor.IsUpdateAvailable && UpdateSpawn != null) { diff --git a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Properties/AssemblyInfo.cs b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Properties/AssemblyInfo.cs index 1939855c9ac0..9ef9d03aa5d7 100644 --- a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Properties/AssemblyInfo.cs +++ b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Properties/AssemblyInfo.cs @@ -34,5 +34,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.95.*")] -[assembly: AssemblyFileVersion("1.95.0.0")] +[assembly: AssemblyVersion("1.102.*")] +[assembly: AssemblyFileVersion("1.102.0.0")] diff --git a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/UnrealGameSync.csproj b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/UnrealGameSync.csproj index 3325687041b3..1c59a23a428e 100644 --- a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/UnrealGameSync.csproj +++ b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/UnrealGameSync.csproj @@ -112,6 +112,12 @@ + + UserControl + + + WorkspaceControl.cs + Component @@ -124,6 +130,9 @@ Component + + Component + @@ -242,6 +251,9 @@ + + WorkspaceControl.cs + ArgumentsWindow.cs diff --git a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/UpdateMonitor.cs b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/UpdateMonitor.cs index 25146fd06d6d..3388f5f3f207 100644 --- a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/UpdateMonitor.cs +++ b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/UpdateMonitor.cs @@ -61,7 +61,7 @@ namespace UnrealGameSync void PollForUpdates() { - while(!QuitEvent.WaitOne(20 * 1000)) + while(!QuitEvent.WaitOne(5 * 60 * 1000)) { StringWriter Log = new StringWriter(); diff --git a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/UserSettings.cs b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/UserSettings.cs index c3b7b4e894ef..0a518e624bdb 100644 --- a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/UserSettings.cs +++ b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/UserSettings.cs @@ -17,6 +17,14 @@ namespace UnrealGameSync Development, } + enum TabLabels + { + Stream, + WorkspaceName, + WorkspaceRoot, + ProjectFile, + } + class UserWorkspaceSettings { // Settings for the currently synced project in this workspace. CurrentChangeNumber is only valid for this workspace if CurrentProjectPath is the current project. @@ -63,10 +71,12 @@ namespace UnrealGameSync public bool bShowAllStreams; public bool bKeepInTray; public string LastProjectFileName; + public string[] OpenProjectFileNames; public string[] OtherProjectFileNames; public string[] SyncFilter; public LatestChangeType SyncType; public BuildConfig CompiledEditorBuildConfig; // NB: This assumes not using precompiled editor. See CurrentBuildConfig. + public TabLabels TabLabels; // Window settings public bool bHasWindowSettings; @@ -83,10 +93,8 @@ namespace UnrealGameSync public List> EditorArguments = new List>(); // Project settings - public string CurrentWorkspaceKey; - public UserWorkspaceSettings CurrentWorkspace; - public string CurrentProjectKey; - public UserProjectSettings CurrentProject; + Dictionary WorkspaceKeyToSettings = new Dictionary(); + Dictionary ProjectKeyToSettings = new Dictionary(); // Perforce settings public PerforceSyncOptions SyncOptions = new PerforceSyncOptions(); @@ -111,6 +119,13 @@ namespace UnrealGameSync bShowAllStreams = ConfigFile.GetValue("General.ShowAllStreams", false); bKeepInTray = ConfigFile.GetValue("General.KeepInTray", true); LastProjectFileName = ConfigFile.GetValue("General.LastProjectFileName", null); + + OpenProjectFileNames = ConfigFile.GetValues("General.OpenProjectFileNames", new string[0]); + if(LastProjectFileName != null && !OpenProjectFileNames.Any(x => x.Equals(LastProjectFileName, StringComparison.InvariantCultureIgnoreCase))) + { + OpenProjectFileNames = OpenProjectFileNames.Concat(new string[]{ LastProjectFileName }).ToArray(); + } + OtherProjectFileNames = ConfigFile.GetValues("General.OtherProjectFileNames", new string[0]); SyncFilter = ConfigFile.GetValues("General.SyncFilter", new string[0]); if(!Enum.TryParse(ConfigFile.GetValue("General.SyncType", ""), out SyncType)) @@ -125,6 +140,13 @@ namespace UnrealGameSync CompiledEditorBuildConfig = BuildConfig.DebugGame; } + // Tab names + string TabLabelsValue = ConfigFile.GetValue("General.TabLabels", ""); + if(!Enum.TryParse(TabLabelsValue, true, out TabLabels)) + { + TabLabels = TabLabels.ProjectFile; + } + // Editor arguments string[] Arguments = ConfigFile.GetValues("General.EditorArguments", new string[]{ "0:-log", "0:-fastload" }); foreach(string Argument in Arguments) @@ -194,110 +216,111 @@ namespace UnrealGameSync } } - public void OpenProject(string ClientBranchPath, string ClientProjectFileName) + public UserWorkspaceSettings FindOrAddWorkspace(string ClientBranchPath) { - CloseProject(); - // Update the current workspace - CurrentWorkspaceKey = ClientBranchPath.Trim('/'); - CurrentWorkspace = new UserWorkspaceSettings(); + string CurrentWorkspaceKey = ClientBranchPath.Trim('/'); - // Read the workspace settings - ConfigSection WorkspaceSection = ConfigFile.FindSection(CurrentWorkspaceKey); - if(WorkspaceSection == null) + UserWorkspaceSettings CurrentWorkspace; + if(!WorkspaceKeyToSettings.TryGetValue(CurrentWorkspaceKey, out CurrentWorkspace)) { - string LegacyBranchAndClientKey = ClientBranchPath.Trim('/'); + // Create a new workspace settings object + CurrentWorkspace = new UserWorkspaceSettings(); + WorkspaceKeyToSettings.Add(CurrentWorkspaceKey, CurrentWorkspace); - int SlashIdx = LegacyBranchAndClientKey.IndexOf('/'); - if(SlashIdx != -1) + // Read the workspace settings + ConfigSection WorkspaceSection = ConfigFile.FindSection(CurrentWorkspaceKey); + if(WorkspaceSection == null) { - LegacyBranchAndClientKey = LegacyBranchAndClientKey.Substring(0, SlashIdx) + "$" + LegacyBranchAndClientKey.Substring(SlashIdx + 1); - } + string LegacyBranchAndClientKey = ClientBranchPath.Trim('/'); - string CurrentSync = ConfigFile.GetValue("Clients." + LegacyBranchAndClientKey, null); - if(CurrentSync != null) - { - int AtIdx = CurrentSync.LastIndexOf('@'); - if(AtIdx != -1) + int SlashIdx = LegacyBranchAndClientKey.IndexOf('/'); + if(SlashIdx != -1) { - int ChangeNumber; - if(int.TryParse(CurrentSync.Substring(AtIdx + 1), out ChangeNumber)) - { - CurrentWorkspace.CurrentProjectIdentifier = CurrentSync.Substring(0, AtIdx); - CurrentWorkspace.CurrentChangeNumber = ChangeNumber; - } + LegacyBranchAndClientKey = LegacyBranchAndClientKey.Substring(0, SlashIdx) + "$" + LegacyBranchAndClientKey.Substring(SlashIdx + 1); } - } - string LastUpdateResultText = ConfigFile.GetValue("Clients." + LegacyBranchAndClientKey + "$LastUpdate", null); - if(LastUpdateResultText != null) - { - int ColonIdx = LastUpdateResultText.LastIndexOf(':'); - if(ColonIdx != -1) + string CurrentSync = ConfigFile.GetValue("Clients." + LegacyBranchAndClientKey, null); + if(CurrentSync != null) { - int ChangeNumber; - if(int.TryParse(LastUpdateResultText.Substring(0, ColonIdx), out ChangeNumber)) + int AtIdx = CurrentSync.LastIndexOf('@'); + if(AtIdx != -1) { - WorkspaceUpdateResult Result; - if(Enum.TryParse(LastUpdateResultText.Substring(ColonIdx + 1), out Result)) + int ChangeNumber; + if(int.TryParse(CurrentSync.Substring(AtIdx + 1), out ChangeNumber)) { - CurrentWorkspace.LastSyncChangeNumber = ChangeNumber; - CurrentWorkspace.LastSyncResult = Result; + CurrentWorkspace.CurrentProjectIdentifier = CurrentSync.Substring(0, AtIdx); + CurrentWorkspace.CurrentChangeNumber = ChangeNumber; } } } - } - CurrentWorkspace.SyncFilter = new string[0]; - } - else - { - CurrentWorkspace.CurrentProjectIdentifier = WorkspaceSection.GetValue("CurrentProjectPath"); - CurrentWorkspace.CurrentChangeNumber = WorkspaceSection.GetValue("CurrentChangeNumber", -1); - foreach(string AdditionalChangeNumberString in WorkspaceSection.GetValues("AdditionalChangeNumbers", new string[0])) - { - int AdditionalChangeNumber; - if(int.TryParse(AdditionalChangeNumberString, out AdditionalChangeNumber)) + string LastUpdateResultText = ConfigFile.GetValue("Clients." + LegacyBranchAndClientKey + "$LastUpdate", null); + if(LastUpdateResultText != null) { - CurrentWorkspace.AdditionalChangeNumbers.Add(AdditionalChangeNumber); + int ColonIdx = LastUpdateResultText.LastIndexOf(':'); + if(ColonIdx != -1) + { + int ChangeNumber; + if(int.TryParse(LastUpdateResultText.Substring(0, ColonIdx), out ChangeNumber)) + { + WorkspaceUpdateResult Result; + if(Enum.TryParse(LastUpdateResultText.Substring(ColonIdx + 1), out Result)) + { + CurrentWorkspace.LastSyncChangeNumber = ChangeNumber; + CurrentWorkspace.LastSyncResult = Result; + } + } + } } - } - Enum.TryParse(WorkspaceSection.GetValue("LastSyncResult", ""), out CurrentWorkspace.LastSyncResult); - CurrentWorkspace.LastSyncResultMessage = UnescapeText(WorkspaceSection.GetValue("LastSyncResultMessage")); - CurrentWorkspace.LastSyncChangeNumber = WorkspaceSection.GetValue("LastSyncChangeNumber", -1); - DateTime LastSyncTime; - if(DateTime.TryParse(WorkspaceSection.GetValue("LastSyncTime", ""), out LastSyncTime)) + CurrentWorkspace.SyncFilter = new string[0]; + } + else { - CurrentWorkspace.LastSyncTime = LastSyncTime; + CurrentWorkspace.CurrentProjectIdentifier = WorkspaceSection.GetValue("CurrentProjectPath"); + CurrentWorkspace.CurrentChangeNumber = WorkspaceSection.GetValue("CurrentChangeNumber", -1); + foreach(string AdditionalChangeNumberString in WorkspaceSection.GetValues("AdditionalChangeNumbers", new string[0])) + { + int AdditionalChangeNumber; + if(int.TryParse(AdditionalChangeNumberString, out AdditionalChangeNumber)) + { + CurrentWorkspace.AdditionalChangeNumbers.Add(AdditionalChangeNumber); + } + } + Enum.TryParse(WorkspaceSection.GetValue("LastSyncResult", ""), out CurrentWorkspace.LastSyncResult); + CurrentWorkspace.LastSyncResultMessage = UnescapeText(WorkspaceSection.GetValue("LastSyncResultMessage")); + CurrentWorkspace.LastSyncChangeNumber = WorkspaceSection.GetValue("LastSyncChangeNumber", -1); + + DateTime LastSyncTime; + if(DateTime.TryParse(WorkspaceSection.GetValue("LastSyncTime", ""), out LastSyncTime)) + { + CurrentWorkspace.LastSyncTime = LastSyncTime; + } + + CurrentWorkspace.LastSyncDurationSeconds = WorkspaceSection.GetValue("LastSyncDuration", 0); + CurrentWorkspace.LastBuiltChangeNumber = WorkspaceSection.GetValue("LastBuiltChangeNumber", 0); + CurrentWorkspace.ExpandedArchiveTypes = WorkspaceSection.GetValues("ExpandedArchiveName", new string[0]); + + CurrentWorkspace.SyncFilter = WorkspaceSection.GetValues("SyncFilter", new string[0]); } - - CurrentWorkspace.LastSyncDurationSeconds = WorkspaceSection.GetValue("LastSyncDuration", 0); - CurrentWorkspace.LastBuiltChangeNumber = WorkspaceSection.GetValue("LastBuiltChangeNumber", 0); - CurrentWorkspace.ExpandedArchiveTypes = WorkspaceSection.GetValues("ExpandedArchiveName", new string[0]); - - CurrentWorkspace.SyncFilter = WorkspaceSection.GetValues("SyncFilter", new string[0]); } - - // Read the project settings - CurrentProjectKey = ClientProjectFileName; - CurrentProject = new UserProjectSettings(); - ConfigSection ProjectSection = ConfigFile.FindOrAddSection(CurrentProjectKey); - CurrentProject.BuildSteps.AddRange(ProjectSection.GetValues("BuildStep", new string[0]).Select(x => new ConfigObject(x))); + return CurrentWorkspace; } - public void CloseProject() + public UserProjectSettings FindOrAddProject(string ClientProjectFileName) { - if(CurrentWorkspace != null || CurrentProject != null) + // Read the project settings + UserProjectSettings CurrentProject; + if(!ProjectKeyToSettings.TryGetValue(ClientProjectFileName, out CurrentProject)) { - Save(); - - CurrentWorkspace = null; - CurrentWorkspaceKey = null; - - CurrentProject = null; - CurrentProjectKey = null; + CurrentProject = new UserProjectSettings(); + ProjectKeyToSettings.Add(ClientProjectFileName, CurrentProject); + + ConfigSection ProjectSection = ConfigFile.FindOrAddSection(ClientProjectFileName); + CurrentProject.BuildSteps.AddRange(ProjectSection.GetValues("BuildStep", new string[0]).Select(x => new ConfigObject(x))); } + return CurrentProject; } public void Save() @@ -315,6 +338,7 @@ namespace UnrealGameSync GeneralSection.SetValue("ShowLocalTimes", bShowLocalTimes); GeneralSection.SetValue("ShowAllStreams", bShowAllStreams); GeneralSection.SetValue("LastProjectFileName", LastProjectFileName); + GeneralSection.SetValues("OpenProjectFileNames", OpenProjectFileNames); GeneralSection.SetValue("KeepInTray", bKeepInTray); GeneralSection.SetValues("OtherProjectFileNames", OtherProjectFileNames); GeneralSection.SetValues("SyncFilter", SyncFilter); @@ -323,6 +347,9 @@ namespace UnrealGameSync // Build configuration GeneralSection.SetValue("BuildConfig", CompiledEditorBuildConfig.ToString()); + // Tab names + GeneralSection.SetValue("TabNames", TabLabels.ToString()); + // Editor arguments List EditorArgumentList = new List(); foreach(Tuple EditorArgument in EditorArguments) @@ -359,8 +386,11 @@ namespace UnrealGameSync } // Current workspace settings - if(CurrentWorkspace != null) + foreach(KeyValuePair Pair in WorkspaceKeyToSettings) { + string CurrentWorkspaceKey = Pair.Key; + UserWorkspaceSettings CurrentWorkspace = Pair.Value; + ConfigSection WorkspaceSection = ConfigFile.FindOrAddSection(CurrentWorkspaceKey); WorkspaceSection.Clear(); WorkspaceSection.SetValue("CurrentProjectPath", CurrentWorkspace.CurrentProjectIdentifier); @@ -383,8 +413,11 @@ namespace UnrealGameSync } // Current project settings - if(CurrentProject != null) + foreach(KeyValuePair Pair in ProjectKeyToSettings) { + string CurrentProjectKey = Pair.Key; + UserProjectSettings CurrentProject = Pair.Value; + ConfigSection ProjectSection = ConfigFile.FindOrAddSection(CurrentProjectKey); ProjectSection.Clear(); ProjectSection.SetValues("BuildStep", CurrentProject.BuildSteps.Select(x => x.ToString()).ToArray()); @@ -410,7 +443,7 @@ namespace UnrealGameSync ConfigFile.Save(FileName); } - public string[] GetCombinedSyncFilter() + public string[] GetCombinedSyncFilter(UserWorkspaceSettings CurrentWorkspace) { string[] CombinedSyncFilter = new string[SyncFilter.Length + CurrentWorkspace.SyncFilter.Length]; SyncFilter.CopyTo(CombinedSyncFilter, 0); diff --git a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Workspace.cs b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Workspace.cs index 410bc041485e..e079d9801c2f 100644 --- a/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Workspace.cs +++ b/Engine/Source/Programs/UnrealGameSync/UnrealGameSync/Workspace.cs @@ -93,6 +93,8 @@ namespace UnrealGameSync bool bSyncing; ProgressValue Progress = new ProgressValue(); + static Workspace ActiveWorkspace; + public event Action OnUpdateComplete; public Workspace(PerforceConnection InPerforce, string InLocalRootPath, string InSelectedLocalFileName, string InClientRootPath, string InSelectedClientFileName, int InInitialChangeNumber, int InLastBuiltChangeNumber, string InTelemetryProjectPath, TextWriter InLog) @@ -175,6 +177,7 @@ namespace UnrealGameSync } PendingChangeNumber = CurrentChangeNumber; bSyncing = false; + Interlocked.CompareExchange(ref ActiveWorkspace, null, this); } } @@ -204,6 +207,7 @@ namespace UnrealGameSync bSyncing = false; PendingChangeNumber = CurrentChangeNumber; + Interlocked.CompareExchange(ref ActiveWorkspace, null, this); if(OnUpdateComplete != null) { @@ -213,6 +217,15 @@ namespace UnrealGameSync WorkspaceUpdateResult UpdateWorkspaceInternal(WorkspaceUpdateContext Context, out string StatusMessage) { + if(Interlocked.CompareExchange(ref ActiveWorkspace, this, null) != null) + { + Log.WriteLine("Waiting for other workspaces to finish..."); + while(Interlocked.CompareExchange(ref ActiveWorkspace, this, null) != null) + { + Thread.Sleep(100); + } + } + string CmdExe = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "cmd.exe"); if(!File.Exists(CmdExe)) { diff --git a/Engine/Source/Programs/UnrealHeaderTool/Private/BaseParser.cpp b/Engine/Source/Programs/UnrealHeaderTool/Private/BaseParser.cpp index 3ca2f5319041..ea9f38602f57 100644 --- a/Engine/Source/Programs/UnrealHeaderTool/Private/BaseParser.cpp +++ b/Engine/Source/Programs/UnrealHeaderTool/Private/BaseParser.cpp @@ -90,6 +90,10 @@ namespace FMetadataKeyword& FriendlyName = Dictionary.Add(TEXT("FriendlyName"), EMetadataValueArgument::Required); FriendlyName.InsertAddAction(TEXT("FriendlyName"), TEXT("")); + FMetadataKeyword& BlueprintInternalUseOnly = Dictionary.Add(TEXT("BlueprintInternalUseOnly"), EMetadataValueArgument::None); + BlueprintInternalUseOnly.InsertAddAction(TEXT("BlueprintInternalUseOnly"), TEXT("true")); + BlueprintInternalUseOnly.InsertAddAction(TEXT("BlueprintType"), TEXT("true")); + FMetadataKeyword& BlueprintType = Dictionary.Add(TEXT("BlueprintType"), EMetadataValueArgument::None); BlueprintType.InsertAddAction(TEXT("BlueprintType"), TEXT("true")); diff --git a/Engine/Source/Programs/UnrealHeaderTool/Private/ClassDeclarationMetaData.cpp b/Engine/Source/Programs/UnrealHeaderTool/Private/ClassDeclarationMetaData.cpp index 67449036b7d3..2756dfbded20 100644 --- a/Engine/Source/Programs/UnrealHeaderTool/Private/ClassDeclarationMetaData.cpp +++ b/Engine/Source/Programs/UnrealHeaderTool/Private/ClassDeclarationMetaData.cpp @@ -28,14 +28,14 @@ namespace } FClassDeclarationMetaData::FClassDeclarationMetaData() - : ClassFlags(0) + : ClassFlags(CLASS_None) , WantsToBePlaceable(false) { } void FClassDeclarationMetaData::ParseClassProperties(const TArray& InClassSpecifiers, const FString& InRequiredAPIMacroIfPresent) { - ClassFlags = 0; + ClassFlags = CLASS_None; // Record that this class is RequiredAPI if the CORE_API style macro was present if (!InRequiredAPIMacroIfPresent.IsEmpty()) { diff --git a/Engine/Source/Programs/UnrealHeaderTool/Private/ClassDeclarationMetaData.h b/Engine/Source/Programs/UnrealHeaderTool/Private/ClassDeclarationMetaData.h index ee99e47f6546..a2eacbb55db6 100644 --- a/Engine/Source/Programs/UnrealHeaderTool/Private/ClassDeclarationMetaData.h +++ b/Engine/Source/Programs/UnrealHeaderTool/Private/ClassDeclarationMetaData.h @@ -5,6 +5,7 @@ #include "CoreMinimal.h" #include "UObject/NameTypes.h" #include "Containers/Map.h" +#include "Class.h" class FClass; class FClasses; @@ -16,7 +17,7 @@ class FClassDeclarationMetaData public: FClassDeclarationMetaData(); - uint64 ClassFlags; + EClassFlags ClassFlags; TMap MetaData; FString ClassWithin; FString ConfigName; diff --git a/Engine/Source/Programs/UnrealHeaderTool/Private/CodeGenerator.cpp b/Engine/Source/Programs/UnrealHeaderTool/Private/CodeGenerator.cpp index 519c88c4229c..d4f16a9f0284 100644 --- a/Engine/Source/Programs/UnrealHeaderTool/Private/CodeGenerator.cpp +++ b/Engine/Source/Programs/UnrealHeaderTool/Private/CodeGenerator.cpp @@ -51,6 +51,7 @@ #include "UHTMakefile/UHTMakefile.h" #include "Algo/Sort.h" #include "Algo/Reverse.h" +#include "Misc/ScopeExit.h" #include "FileLineException.h" @@ -88,8 +89,17 @@ namespace LINE_TERMINATOR; const TCHAR RequiredCPPIncludes[] = TEXT("#include \"GeneratedCppIncludes.h\"") LINE_TERMINATOR; + + /** Guard that should be put at the start editor only generated code */ + const TCHAR BeginEditorOnlyGuard[] = TEXT("#if WITH_EDITOR") LINE_TERMINATOR; + + /** Guard that should be put at the end of editor only generated code */ + const TCHAR EndEditorOnlyGuard[] = TEXT("#endif //WITH_EDITOR") LINE_TERMINATOR; } +#define BEGIN_WRAP_EDITOR_ONLY(DoWrap) DoWrap ? BeginEditorOnlyGuard : TEXT("") +#define END_WRAP_EDITOR_ONLY(DoWrap) DoWrap ? EndEditorOnlyGuard : TEXT("") + /** * Finds exact match of Identifier in string. Returns nullptr if none is found. * @@ -672,7 +682,7 @@ private: } return FString::Printf( - TEXT("\t%s_API class %s* %s;\r\n"), + TEXT("\t%s_API %s* %s;\r\n"), *FPackageName::GetShortName(InType->GetOutermost()).ToUpper(), TypeStr, *InName @@ -767,12 +777,7 @@ private: FString Suffix; if (UClass* ItemClass = Cast(Item)) { - if (ItemClass->HasAllClassFlags(CLASS_Intrinsic)) - { - return FString::Printf(TEXT("%s::StaticClass()"), NameLookupCPP.GetNameCPP(ItemClass)); - } - - if (!bRequiresValidObject) + if (!bRequiresValidObject && !ItemClass->HasAllClassFlags(CLASS_Intrinsic)) { Suffix = TEXT("_NoRegister"); } @@ -816,21 +821,16 @@ private: FString FNativeClassHeaderGenerator::GetSingletonName(UField* Item, bool bRequiresValidObject) { - FString Result = FTypeSingletonCache::Get(Item, bRequiresValidObject).GetName(); + const FTypeSingleton& Cache = FTypeSingletonCache::Get(Item, bRequiresValidObject); - UClass* ItemClass = Cast(Item); - if (ItemClass != nullptr && ItemClass->HasAllClassFlags(CLASS_Intrinsic)) + FString Result = Cache.GetName(); + + if (UniqueCrossModuleReferences) { - return Result; + const FString& Extern = Cache.GetExternDecl(); + UniqueCrossModuleReferences->Add(*Extern); } - if (CastChecked(Item->GetOutermost()) != Package) - { - // this is a cross module reference, we need to include the right extern decl - FString Extern = FTypeSingletonCache::Get(Item, bRequiresValidObject).GetExternDecl(); - - UniqueCrossModuleReferences.Add(*Extern); - } return Result; } @@ -1072,16 +1072,19 @@ void FNativeClassHeaderGenerator::OutputProperty(FString& Meta, FOutputDevice& O { PropNameDep += TEXT("_DEPRECATED"); } - UBoolProperty* BoolProperty = Cast(Prop); - if (BoolProperty) + if (UBoolProperty* BoolProperty = Cast(Prop)) { - OutputDevice.Logf(TEXT("%sCPP_BOOL_PROPERTY_BITMASK_STRUCT(%s, %s, %s);\r\n"), - Spaces, - *PropNameDep, - *SourceStruct, - *BoolProperty->GetCPPType(NULL, 0)); - PropMacroOuterClass = FString::Printf(TEXT("FObjectInitializer(), EC_CppProperty, CPP_BOOL_PROPERTY_OFFSET(%s, %s)"), - *PropNameDep, *SourceStruct); + OutputDevice.Logf( + TEXT("%sCPP_BOOL_PROPERTY_BITMASK_STRUCT(%s, %s);\r\n"), + Spaces, + *PropNameDep, + *SourceStruct + ); + PropMacroOuterClass = FString::Printf( + TEXT("FObjectInitializer(), EC_CppProperty, CPP_BOOL_PROPERTY_OFFSET(%s, %s)"), + *PropNameDep, + *SourceStruct + ); } else { @@ -1237,18 +1240,49 @@ static TArray FindNoExportStructs(UStruct* Start) return Result; } -FString GetPackageSingletonName(const UPackage* Package) +FString FNativeClassHeaderGenerator::GetPackageSingletonName(const UPackage* InPackage) { static FString ClassString = NameLookupCPP.GetNameCPP(UPackage::StaticClass()); - return FString(TEXT("Z_Construct_")) + ClassString + TEXT("_") + Package->GetName().Replace(TEXT("/"), TEXT("_")) + TEXT("()"); + + FString Result = TEXT("Z_Construct_") + ClassString + TEXT("_") + InPackage->GetName().Replace(TEXT("/"), TEXT("_")) + TEXT("()"); + + if (UniqueCrossModuleReferences) + { + UniqueCrossModuleReferences->Add(FString::Printf(TEXT("\tUPackage* %s;\r\n"), *Result)); + } + + return Result; } -void FNativeClassHeaderGenerator::ExportGeneratedPackageInitCode(FOutputDevice& Out, FUHTStringBuilder& OutDeclarations, const UPackage* InPackage, uint32 CRC) +void FNativeClassHeaderGenerator::ExportGeneratedPackageInitCode(FOutputDevice& Out, const TCHAR* InDeclarations, const UPackage* InPackage, uint32 CRC) { FString ApiString = GetAPIString(); FString SingletonName = GetPackageSingletonName(InPackage); - OutDeclarations.Logf(TEXT("\t%sclass UPackage* %s;\r\n"), *ApiString, *SingletonName); + TArray SingletonsToOutput; + for (UField* ScriptType : TObjectRange()) + { + if (ScriptType->GetOutermost() != InPackage) + { + continue; + } + + if (ScriptType->IsA() || (ScriptType->IsA() && (((UScriptStruct*)ScriptType)->StructFlags & STRUCT_NoExport))) + { + UField* FieldOuter = Cast(ScriptType->GetOuter()); + if (!FieldOuter || !FClass::IsDynamic(FieldOuter)) + { + SingletonsToOutput.Add(ScriptType); + } + } + } + + for (UField* ScriptType : SingletonsToOutput) + { + const FString& Extern = FTypeSingletonCache::Get(ScriptType, true).GetExternDecl(); + + Out.Logf(TEXT("%s"), *Extern); + } Out.Logf(TEXT("\tUPackage* %s\r\n"), *SingletonName); Out.Logf(TEXT("\t{\r\n")); @@ -1271,7 +1305,7 @@ void FNativeClassHeaderGenerator::ExportGeneratedPackageInitCode(FOutputDevice& FGuid Guid; Guid.A = CRC; - Guid.B = GenerateTextCRC(*OutDeclarations); + Guid.B = GenerateTextCRC(InDeclarations); Out.Logf(TEXT("\t\t\tFGuid Guid;\r\n")); Out.Logf(TEXT("\t\t\tGuid.A = 0x%08X;\r\n"), Guid.A); Out.Logf(TEXT("\t\t\tGuid.B = 0x%08X;\r\n"), Guid.B); @@ -1280,24 +1314,11 @@ void FNativeClassHeaderGenerator::ExportGeneratedPackageInitCode(FOutputDevice& Out.Logf(TEXT("\t\t\tReturnPackage->SetGuid(Guid);\r\n"), Guid.D); Out.Log(TEXT("\r\n")); - for (UField* ScriptType : TObjectRange()) + for (UField* ScriptType : SingletonsToOutput) { - if (ScriptType->GetOutermost() != InPackage) - { - continue; - } + const FString& Name = FTypeSingletonCache::Get(ScriptType, true).GetName(); - if ( - (ScriptType->IsA() && (((UScriptStruct*)ScriptType)->StructFlags & STRUCT_NoExport) != 0) || - ScriptType->IsA() - ) - { - UField* FieldOuter = Cast(ScriptType->GetOuter()); - if (!FieldOuter || !FClass::IsDynamic(FieldOuter)) - { - Out.Logf(TEXT("\t\t\t%s;\r\n"), *GetSingletonName(ScriptType)); - } - } + Out.Logf(TEXT("\t\t\t%s;\r\n"), *Name); } Out.Logf(TEXT("\t\t}\r\n")); @@ -1343,13 +1364,26 @@ void FNativeClassHeaderGenerator::ExportNativeGeneratedInitCode(FOutputDevice& O // Export the init code for each function for (UFunction* Function : FunctionsToExport) { + const bool bIsEditorOnlyFunction = Function->HasAnyFunctionFlags(FUNC_EditorOnly); + if (!Function->IsA()) { - OutDeclarations.Log(FTypeSingletonCache::Get(Function).GetExternDecl()); + + OutDeclarations.Logf(TEXT("%s%s%s"), + BEGIN_WRAP_EDITOR_ONLY(bIsEditorOnlyFunction), + *FTypeSingletonCache::Get(Function).GetExternDecl(), + END_WRAP_EDITOR_ONLY(bIsEditorOnlyFunction) + ); + ExportFunction(Out, SourceFile, Function, bIsNoExport); } - CallSingletons.Logf(TEXT("\t\t\t\tOuterClass->LinkChild(%s);\r\n"), *GetSingletonName(Function)); + CallSingletons.Logf(TEXT("%s\t\t\t\tOuterClass->LinkChild(%s);\r\n%s"), + BEGIN_WRAP_EDITOR_ONLY(bIsEditorOnlyFunction), + *GetSingletonName(Function), + END_WRAP_EDITOR_ONLY(bIsEditorOnlyFunction) + ); + } FUHTStringBuilder GeneratedClassRegisterFunctionText; @@ -1358,7 +1392,7 @@ void FNativeClassHeaderGenerator::ExportNativeGeneratedInitCode(FOutputDevice& O { // simple ::StaticClass wrapper to avoid header, link and DLL hell { - FString SingletonNameNoRegister(GetSingletonName(Class, false)); + FString SingletonNameNoRegister = GetSingletonName(Class, false); OutDeclarations.Log(FTypeSingletonCache::Get(Class, false).GetExternDecl()); @@ -1388,20 +1422,25 @@ void FNativeClassHeaderGenerator::ExportNativeGeneratedInitCode(FOutputDevice& O } GeneratedClassRegisterFunctionText.Logf(TEXT("\t\t{\r\n")); - if (Class->GetSuperClass() && Class->GetSuperClass() != Class) + UClass* SuperClass = Class->GetSuperClass(); + if (SuperClass && SuperClass != Class) { - GeneratedClassRegisterFunctionText.Logf(TEXT("\t\t\t%s;\r\n"), *GetSingletonName(Class->GetSuperClass())); + OutDeclarations.Log(FTypeSingletonCache::Get(SuperClass).GetExternDecl()); + GeneratedClassRegisterFunctionText.Logf(TEXT("\t\t\t%s;\r\n"), *GetSingletonName(SuperClass)); } if (!bIsDynamic) { - GeneratedClassRegisterFunctionText.Logf(TEXT("\t\t\t%s;\r\n"), *GetPackageSingletonName(CastChecked(Class->GetOutermost()))); + FString PackageSingletonName = GetPackageSingletonName(CastChecked(Class->GetOutermost())); + + OutDeclarations.Logf(TEXT("\t%s_API UPackage* %s;\r\n"), *ApiString, *PackageSingletonName); + GeneratedClassRegisterFunctionText.Logf(TEXT("\t\t\t%s;\r\n"), *PackageSingletonName); } GeneratedClassRegisterFunctionText.Logf(TEXT("\t\t\tOuterClass = %s::StaticClass();\r\n"), ClassNameCPP); GeneratedClassRegisterFunctionText.Logf(TEXT("\t\t\tif (!(OuterClass->ClassFlags & CLASS_Constructed))\r\n"), ClassNameCPP); GeneratedClassRegisterFunctionText.Logf(TEXT("\t\t\t{\r\n"), ClassNameCPP); GeneratedClassRegisterFunctionText.Logf(TEXT("\t\t\t\tUObjectForceRegistration(OuterClass);\r\n")); uint32 Flags = (Class->ClassFlags & CLASS_SaveInCompiledInClasses) | CLASS_Constructed; - GeneratedClassRegisterFunctionText.Logf(TEXT("\t\t\t\tOuterClass->ClassFlags |= 0x%08X;\r\n"), Flags); + GeneratedClassRegisterFunctionText.Logf(TEXT("\t\t\t\tOuterClass->ClassFlags |= (EClassFlags)0x%08Xu;\r\n"), Flags); TheFlagAudit.Add(Class, TEXT("ClassFlags"), Flags); GeneratedClassRegisterFunctionText.Logf(TEXT("\r\n")); GeneratedClassRegisterFunctionText.Log(CallSingletons); @@ -1427,12 +1466,7 @@ void FNativeClassHeaderGenerator::ExportNativeGeneratedInitCode(FOutputDevice& O Props.Add(*ItInner); } - if (Props.Num() > 0) - { - GeneratedClassRegisterFunctionText.Logf(TEXT("PRAGMA_DISABLE_DEPRECATION_WARNINGS\r\n")); - OutputProperties(Meta, GeneratedClassRegisterFunctionText, OuterString, Props, TEXT("\t\t\t\t")); - GeneratedClassRegisterFunctionText.Logf(TEXT("PRAGMA_ENABLE_DEPRECATION_WARNINGS\r\n")); - } + OutputProperties(Meta, GeneratedClassRegisterFunctionText, OuterString, Props, TEXT("\t\t\t\t")); } // function table { @@ -1448,7 +1482,13 @@ void FNativeClassHeaderGenerator::ExportNativeGeneratedInitCode(FOutputDevice& O // Emit code to construct each UFunction and rebuild the function map at runtime for (UFunction* Function : FunctionsInMap) { - GeneratedClassRegisterFunctionText.Logf(TEXT("\t\t\t\tOuterClass->AddFunctionToFunctionMapWithOverriddenName(%s, %s);%s\r\n"), *GetSingletonName(Function), *FNativeClassHeaderGenerator::GetOverriddenNameForLiteral(Function), *GetGeneratedCodeCRCTag(Function)); + const bool bIsEditorOnlyFunction = Function->HasAnyFunctionFlags(FUNC_EditorOnly); + GeneratedClassRegisterFunctionText.Logf(TEXT("%s\t\t\t\tOuterClass->AddFunctionToFunctionMapWithOverriddenName(%s, %s);%s\r\n%s"), + BEGIN_WRAP_EDITOR_ONLY(bIsEditorOnlyFunction), + *GetSingletonName(Function), + *FNativeClassHeaderGenerator::GetOverriddenNameForLiteral(Function), + *GetGeneratedCodeCRCTag(Function), + END_WRAP_EDITOR_ONLY(bIsEditorOnlyFunction)); } } @@ -1567,12 +1607,20 @@ void FNativeClassHeaderGenerator::ExportFunction(FOutputDevice& Out, const FUnre { UFunction* SuperFunction = Function->GetSuperFunction(); + const bool bIsEditorOnlyFunction = Function->HasAnyFunctionFlags(FUNC_EditorOnly); + bool bIsDelegate = Function->HasAnyFunctionFlags(FUNC_Delegate); const FString SingletonName = GetSingletonName(Function); FUHTStringBuilder CurrentFunctionText; + // Begin wrapping editor only functions. Note: This should always be the first step! + if (bIsEditorOnlyFunction) + { + CurrentFunctionText.Logf(BeginEditorOnlyGuard); + } + CurrentFunctionText.Logf(TEXT("\tUFunction* %s\r\n"), *SingletonName); CurrentFunctionText.Logf(TEXT("\t{\r\n")); @@ -1589,11 +1637,11 @@ void FNativeClassHeaderGenerator::ExportFunction(FOutputDevice& Out, const FUnre if (UObject* Outer = Function->GetOuter()) { - CurrentFunctionText.Logf(TEXT("\t\tUObject* Outer=%s;\r\n"), Outer->IsA() ? *GetPackageSingletonName((UPackage*)Outer) : *GetSingletonName(Function->GetOwnerClass())); + CurrentFunctionText.Logf(TEXT("\t\tUObject* Outer = %s;\r\n"), Outer->IsA() ? *GetPackageSingletonName((UPackage*)Outer) : *GetSingletonName(Function->GetOwnerClass())); } else { - CurrentFunctionText.Logf(TEXT("\t\tUObject* Outer=nullptr;\r\n")); + CurrentFunctionText.Logf(TEXT("\t\tUObject* Outer = nullptr;\r\n")); } UField* FieldOuter = Cast(Function->GetOuter()); @@ -1601,7 +1649,7 @@ void FNativeClassHeaderGenerator::ExportFunction(FOutputDevice& Out, const FUnre if (!bIsDynamic) { - CurrentFunctionText.Logf(TEXT("\t\tstatic UFunction* ReturnFunction = NULL;\r\n")); + CurrentFunctionText.Logf(TEXT("\t\tstatic UFunction* ReturnFunction = nullptr;\r\n")); } else { @@ -1611,7 +1659,7 @@ void FNativeClassHeaderGenerator::ExportFunction(FOutputDevice& Out, const FUnre CurrentFunctionText.Logf(TEXT("\t\tif (!ReturnFunction)\r\n")); CurrentFunctionText.Logf(TEXT("\t\t{\r\n")); - FString SuperFunctionString(TEXT("NULL")); + FString SuperFunctionString(TEXT("nullptr")); if (SuperFunction) { SuperFunctionString = GetSingletonName(SuperFunction); @@ -1640,15 +1688,15 @@ void FNativeClassHeaderGenerator::ExportFunction(FOutputDevice& Out, const FUnre const TCHAR* UFunctionType = bIsDelegate ? TEXT("UDelegateFunction") : TEXT("UFunction"); const TCHAR* UFunctionObjectFlags = FClass::IsOwnedByDynamicType(Function) ? TEXT("RF_Public|RF_Transient") : TEXT("RF_Public|RF_Transient|RF_MarkAsNative"); - CurrentFunctionText.Logf(TEXT("\t\t\tReturnFunction = new(EC_InternalUseOnlyConstructor, Outer, TEXT(\"%s\"), %s) %s(FObjectInitializer(), %s, 0x%08X, %d%s);\r\n"), + CurrentFunctionText.Logf(TEXT("\t\t\tReturnFunction = new(EC_InternalUseOnlyConstructor, Outer, TEXT(\"%s\"), %s) %s(FObjectInitializer(), %s, (EFunctionFlags)0x%08X, %d%s);\r\n"), *FNativeClassHeaderGenerator::GetOverriddenName(Function), UFunctionObjectFlags, UFunctionType, *SuperFunctionString, - Function->FunctionFlags, + (uint32)Function->FunctionFlags, (uint32)Function->RepOffset, *StructureSize - ); + ); TheFlagAudit.Add(Function, TEXT("FunctionFlags"), Function->FunctionFlags); @@ -1683,6 +1731,12 @@ void FNativeClassHeaderGenerator::ExportFunction(FOutputDevice& Out, const FUnre CurrentFunctionText.Logf(TEXT("\t\treturn ReturnFunction;\r\n")); CurrentFunctionText.Logf(TEXT("\t}\r\n")); + // End wrapping editor only functions. Note: This should always be the last step! + if (bIsEditorOnlyFunction) + { + CurrentFunctionText.Logf(EndEditorOnlyGuard); + } + uint32 FunctionCrc = GenerateTextCRC(*CurrentFunctionText); GGeneratedCodeCRCs.Add(Function, FunctionCrc); UHTMakefile.AddGeneratedCodeCRC(&SourceFile, Function, FunctionCrc); @@ -1730,16 +1784,22 @@ void FNativeClassHeaderGenerator::ExportNatives(FOutputDevice& Out, FClass* Clas for (const TTuple& Func : AnsiNamedFunctionsToExport) { + UFunction* Function = Func.Get<0>(); + const bool bEditorOnlyFunction = Function->HasAnyFunctionFlags(FUNC_EditorOnly); + Out.Logf( - TEXT("\t\t\t{ %s, (Native)&%s::exec%s },\r\n"), + TEXT("%s\t\t\t{ %s, (Native)&%s::exec%s },\r\n%s"), + BEGIN_WRAP_EDITOR_ONLY(bEditorOnlyFunction), *Func.Get<1>(), *TypeName, - *Func.Get<0>()->GetName() + *Function->GetName(), + END_WRAP_EDITOR_ONLY(bEditorOnlyFunction) ); + } Out.Log(TEXT("\t\t};\r\n")); - Out.Logf(TEXT("\t\tFNativeFunctionRegistrar::RegisterFunctions(Class, AnsiFuncs, %d);\r\n"), AnsiNamedFunctionsToExport.Num()); + Out.Logf(TEXT("\t\tFNativeFunctionRegistrar::RegisterFunctions(Class, AnsiFuncs, ARRAY_COUNT(AnsiFuncs));\r\n")); } if (TCharNamedFunctionsToExport.Num()) @@ -1748,16 +1808,20 @@ void FNativeClassHeaderGenerator::ExportNatives(FOutputDevice& Out, FClass* Clas for (const TTuple& Func : TCharNamedFunctionsToExport) { + UFunction* Function = Func.Get<0>(); + const bool bEditorOnlyFunction = Function->HasAnyFunctionFlags(FUNC_EditorOnly); Out.Logf( - TEXT("\t\t\t{ %s, (Native)&%s::exec%s },\r\n"), + TEXT("%s\t\t\t{ %s, (Native)&%s::exec%s },\r\n%s"), + BEGIN_WRAP_EDITOR_ONLY(bEditorOnlyFunction), *Func.Get<1>(), *TypeName, - *Func.Get<0>()->GetName() + *Function->GetName(), + END_WRAP_EDITOR_ONLY(bEditorOnlyFunction) ); } Out.Log(TEXT("\t\t};\r\n")); - Out.Logf(TEXT("\t\tFNativeFunctionRegistrar::RegisterFunctions(Class, TCharFuncs, %d);\r\n"), TCharNamedFunctionsToExport.Num()); + Out.Logf(TEXT("\t\tFNativeFunctionRegistrar::RegisterFunctions(Class, TCharFuncs, ARRAY_COUNT(TCharFuncs));\r\n")); } } @@ -2047,7 +2111,6 @@ void FNativeClassHeaderGenerator::ExportClassFromSourceFileInner( CallbackFunctions, *CallbackWrappersMacroName, (Class->ClassFlags & CLASS_Interface) ? EExportCallbackType::Interface : EExportCallbackType::Class, - *API, *GetAPIString() ); @@ -2194,7 +2257,9 @@ void FNativeClassHeaderGenerator::ExportClassFromSourceFileInner( // to script VM functions if (SuperClass->IsChildOf(UInterface::StaticClass())) { - InterfaceBoilerplate.Logf(TEXT("\tvirtual UObject* _getUObject() const = 0;\r\n")); + // Note: This used to be declared as a pure virtual function, but it was changed here in order to allow the Blueprint nativization process + // to detect C++ interface classes that explicitly declare pure virtual functions via type traits. This code will no longer trigger that check. + InterfaceBoilerplate.Logf(TEXT("\tvirtual UObject* _getUObject() const { check(0 && \"Missing required implementation.\"); return nullptr; }\r\n")); } if (bNeedsRep && !bHasGetLifetimeReplicatedProps) @@ -2550,10 +2615,11 @@ void FNativeClassHeaderGenerator::ExportEnum(FOutputDevice& Out, UEnum* Enum) } // Exports the header text for the list of structs specified (GENERATED_BODY impls) -void FNativeClassHeaderGenerator::ExportGeneratedStructBodyMacros(FOutputDevice& OutGeneratedHeaderText, FOutputDevice& Out, FOutputDevice& OutDeclarations, const FUnrealSourceFile& SourceFile, UScriptStruct* Struct) +void FNativeClassHeaderGenerator::ExportGeneratedStructBodyMacros(FOutputDevice& OutGeneratedHeaderText, FOutputDevice& Out, const FUnrealSourceFile& SourceFile, UScriptStruct* Struct) { const bool bIsDynamic = FClass::IsDynamic(Struct); const FString ActualStructName = FNativeClassHeaderGenerator::GetOverriddenName(Struct); + const FString FriendApiString = GetAPIString(); UStruct* BaseStruct = Struct->GetSuperStruct(); @@ -2562,7 +2628,6 @@ void FNativeClassHeaderGenerator::ExportGeneratedStructBodyMacros(FOutputDevice& { check(Struct->StructMacroDeclaredLineNumber != INDEX_NONE); - const FString FriendApiString = GetAPIString(); const FString StaticConstructionString = GetSingletonName(Struct); FString RequiredAPI; @@ -2592,34 +2657,21 @@ void FNativeClassHeaderGenerator::ExportGeneratedStructBodyMacros(FOutputDevice& // UStructs can have UClass or UPackage outer (if declared in non-UClass headers). FString OuterName; - if (Struct->GetOuter()->IsA(UStruct::StaticClass())) - { - OuterName = NameLookupCPP.GetNameCPP(CastChecked(Struct->GetOuter())); - OuterName += TEXT("::StaticClass()"); - } - else if (!bIsDynamic) + if (!bIsDynamic) { OuterName = GetPackageSingletonName(CastChecked(Struct->GetOuter())); - Out.Logf(TEXT("\textern %sclass UPackage* %s;\r\n"), *FriendApiString, *OuterName); + Out.Logf(TEXT("\tstatic class UScriptStruct* Singleton = NULL;\r\n")); } else { OuterName = TEXT("StructPackage"); Out.Logf(TEXT("\tclass UPackage* %s = FindOrConstructDynamicTypePackage(TEXT(\"%s\"));\r\n"), *OuterName, *FClass::GetTypePackageName(Struct)); - } - - if (!bIsDynamic) - { - Out.Logf(TEXT("\tstatic class UScriptStruct* Singleton = NULL;\r\n")); - } - else - { Out.Logf(TEXT("\tclass UScriptStruct* Singleton = Cast(StaticFindObjectFast(UScriptStruct::StaticClass(), %s, TEXT(\"%s\")));\r\n"), *OuterName, *ActualStructName); } + Out.Logf(TEXT("\tif (!Singleton)\r\n")); Out.Logf(TEXT("\t{\r\n")); - Out.Logf(TEXT("\t\textern %sclass UScriptStruct* %s;\r\n"), *FriendApiString, *StaticConstructionString); Out.Logf(TEXT("\t\textern %suint32 %s();\r\n"), *FriendApiString, *GetCRCName); Out.Logf(TEXT("\t\tSingleton = GetStaticStruct(%s, %s, TEXT(\"%s\"), sizeof(%s), %s());\r\n"), @@ -2652,7 +2704,6 @@ void FNativeClassHeaderGenerator::ExportGeneratedStructBodyMacros(FOutputDevice& } const FString SingletonName = GetSingletonName(Struct); - OutDeclarations.Log(FTypeSingletonCache::Get(Struct).GetExternDecl()); FUHTStringBuilder GeneratedStructRegisterFunctionText; @@ -2669,11 +2720,7 @@ void FNativeClassHeaderGenerator::ExportGeneratedStructBodyMacros(FOutputDevice& FString CRCFuncName = FString::Printf(TEXT("Get_%s_CRC"), *SingletonName.Replace(TEXT("()"), TEXT(""), ESearchCase::CaseSensitive)); // Structs can either have a UClass or UPackage as outer (if declared in non-UClass header). - if (Struct->GetOuter()->IsA(UStruct::StaticClass())) - { - GeneratedStructRegisterFunctionText.Logf(TEXT("\t\tUStruct* Outer = %s;\r\n"), *GetSingletonName(CastChecked(Struct->GetOuter()))); - } - else if (!bIsDynamic) + if (!bIsDynamic) { GeneratedStructRegisterFunctionText.Logf(TEXT("\t\tUPackage* Outer = %s;\r\n"), *GetPackageSingletonName(CastChecked(Struct->GetOuter()))); } @@ -2681,7 +2728,6 @@ void FNativeClassHeaderGenerator::ExportGeneratedStructBodyMacros(FOutputDevice& { GeneratedStructRegisterFunctionText.Logf(TEXT("\t\tUPackage* Outer = FindOrConstructDynamicTypePackage(TEXT(\"%s\"));\r\n"), *FClass::GetTypePackageName(Struct)); } - GeneratedStructRegisterFunctionText.Logf(TEXT("\t\textern uint32 %s();\r\n"), *CRCFuncName); if (!bIsDynamic) { @@ -2709,7 +2755,7 @@ void FNativeClassHeaderGenerator::ExportGeneratedStructBodyMacros(FOutputDevice& } else { - ExplicitSizeString = FString::Printf(TEXT(", sizeof(%s), ALIGNOF(%s)"), NameLookupCPP.GetNameCPP(Struct), NameLookupCPP.GetNameCPP(Struct)); + ExplicitSizeString = FString::Printf(TEXT(", sizeof(%s), alignof(%s)"), NameLookupCPP.GetNameCPP(Struct), NameLookupCPP.GetNameCPP(Struct)); } const TCHAR* UStructObjectFlags = bIsDynamic ? TEXT("RF_Public|RF_Transient") : TEXT("RF_Public|RF_Transient|RF_MarkAsNative"); @@ -2755,14 +2801,14 @@ void FNativeClassHeaderGenerator::ExportGeneratedStructBodyMacros(FOutputDevice& //CallSingletons.Logf(TEXT("\t\t\t\tOuterClass->LinkChild(%s); // %u\r\n"), *SingletonName, StructCrc); } -void FNativeClassHeaderGenerator::ExportGeneratedEnumInitCode(FOutputDevice& Out, FOutputDevice& OutDeclarations, const FUnrealSourceFile& SourceFile, UEnum* Enum) +void FNativeClassHeaderGenerator::ExportGeneratedEnumInitCode(FOutputDevice& Out, const FUnrealSourceFile& SourceFile, UEnum* Enum) { const bool bIsDynamic = FClass::IsDynamic(Enum); const FString FriendApiString = GetAPIString(); const FString StaticConstructionString = GetSingletonName(Enum); FString SingletonName = StaticConstructionString.Replace(TEXT("()"), TEXT(""), ESearchCase::CaseSensitive); // function address - FString PackageSingletonName = GetPackageSingletonName(CastChecked(Enum->GetOuter())); + FString PackageSingletonName; if (!bIsDynamic) { PackageSingletonName = GetPackageSingletonName(CastChecked(Enum->GetOuter())); @@ -2777,7 +2823,6 @@ void FNativeClassHeaderGenerator::ExportGeneratedEnumInitCode(FOutputDevice& Out if (!bIsDynamic) { - Out.Logf(TEXT("\textern %sclass UPackage* %s;\r\n"), *FriendApiString, *PackageSingletonName); Out.Logf(TEXT("\tstatic UEnum* Singleton = nullptr;\r\n")); } else @@ -2787,7 +2832,6 @@ void FNativeClassHeaderGenerator::ExportGeneratedEnumInitCode(FOutputDevice& Out } Out.Logf(TEXT("\tif (!Singleton)\r\n")); Out.Logf(TEXT("\t{\r\n")); - Out.Logf(TEXT("\t\textern %sclass UEnum* %s;\r\n"), *FriendApiString, *StaticConstructionString); if (!bIsDynamic) { Out.Logf(TEXT("\t\tSingleton = GetStaticEnum(%s, %s, TEXT(\"%s\"));\r\n"), *SingletonName, *PackageSingletonName, *Enum->GetName()); @@ -2809,7 +2853,6 @@ void FNativeClassHeaderGenerator::ExportGeneratedEnumInitCode(FOutputDevice& Out bIsDynamic ? *AsTEXT(FNativeClassHeaderGenerator::GetOverriddenPathName(Enum)) : TEXT("nullptr")); const FString EnumSingletonName = GetSingletonName(Enum); - OutDeclarations.Log(FTypeSingletonCache::Get(Enum).GetExternDecl()); FUHTStringBuilder GeneratedEnumRegisterFunctionText; @@ -2817,14 +2860,11 @@ void FNativeClassHeaderGenerator::ExportGeneratedEnumInitCode(FOutputDevice& Out GeneratedEnumRegisterFunctionText.Logf(TEXT("\tUEnum* %s\r\n"), *EnumSingletonName); GeneratedEnumRegisterFunctionText.Logf(TEXT("\t{\r\n")); + // Enums can either have a UClass or UPackage as outer (if declared in non-UClass header). - if (Enum->GetOuter()->IsA(UStruct::StaticClass())) + if (!bIsDynamic) { - GeneratedEnumRegisterFunctionText.Logf(TEXT("\t\tUClass* Outer=%s;\r\n"), *GetSingletonName(CastChecked(Enum->GetOuter()))); - } - else if (!bIsDynamic) - { - GeneratedEnumRegisterFunctionText.Logf(TEXT("\t\tUPackage* Outer=%s;\r\n"), *GetPackageSingletonName(CastChecked(Enum->GetOuter()))); + GeneratedEnumRegisterFunctionText.Logf(TEXT("\t\tUPackage* Outer = %s;\r\n"), *PackageSingletonName); } else { @@ -2950,7 +2990,7 @@ void WriteEventFunctionPrologue(FOutputDevice& Output, int32 Indent, const FParm } } -void WriteEventFunctionEpilogue(FOutputDevice& Output, int32 Indent, const FParmsAndReturnProperties& Parameters, const TCHAR* FunctionName) +void WriteEventFunctionEpilogue(FOutputDevice& Output, int32 Indent, const FParmsAndReturnProperties& Parameters) { // Out parm copying. for (auto It = Parameters.Parms.CreateConstIterator(); It; ++It) @@ -2981,7 +3021,7 @@ void WriteEventFunctionEpilogue(FOutputDevice& Output, int32 Indent, const FParm Output.Logf(TEXT("%s}\r\n"), FCString::Tab(Indent)); } -void FNativeClassHeaderGenerator::ExportDelegateDeclaration(FOutputDevice& Out, FOutputDevice& OutDeclarations, const FUnrealSourceFile& SourceFile, UFunction* Function) +void FNativeClassHeaderGenerator::ExportDelegateDeclaration(FOutputDevice& Out, const FUnrealSourceFile& SourceFile, UFunction* Function) { static const TCHAR DelegateStr[] = TEXT("delegate"); @@ -3017,7 +3057,6 @@ void FNativeClassHeaderGenerator::ExportDelegateDeclaration(FOutputDevice& Out, // Only exporting function prototype DelegateOutput.Logf(TEXT(";\r\n")); - OutDeclarations.Log(FTypeSingletonCache::Get(Function).GetExternDecl()); ExportFunction(Out, SourceFile, Function, false); } @@ -3068,7 +3107,7 @@ void FNativeClassHeaderGenerator::ExportDelegateDefinition(FOutputDevice& Out, c const TCHAR* DelegateArg = Parameters.HasParms() ? TEXT("&Parms") : TEXT("NULL"); DelegateOutput.Logf(TEXT("\t%s.%s(%s);\r\n"), *DelegateName, DelegateType, DelegateArg); } - WriteEventFunctionEpilogue(DelegateOutput, 0, Parameters, *DelegateName); + WriteEventFunctionEpilogue(DelegateOutput, 0, Parameters); FString MacroName = SourceFile.GetGeneratedMacroName(FunctionData.MacroLine, TEXT("_DELEGATE")); WriteMacro(Out, MacroName, DelegateOutput); @@ -3161,7 +3200,7 @@ void FNativeClassHeaderGenerator::ExportEventParm(FUHTStringBuilder& Out, TSetArrayDim == 1); // can't return arrays Out.Logf(TEXT("\r\n%s/** Constructor, initializes return property only **/\r\n"), FCString::Tab(Indent + 1)); Out.Logf(TEXT("%s%s()\r\n"), FCString::Tab(Indent + 1), *EventParmStructName); - Out.Logf(TEXT("%s%s %s(%s)\r\n"), FCString::Tab(Indent + 2), TEXT(":"), *Prop->GetName(), *GetNullParameterValue(Prop, false, true)); + Out.Logf(TEXT("%s%s %s(%s)\r\n"), FCString::Tab(Indent + 2), TEXT(":"), *Prop->GetName(), *GetNullParameterValue(Prop, true)); Out.Logf(TEXT("%s{\r\n"), FCString::Tab(Indent + 1)); Out.Logf(TEXT("%s}\r\n"), FCString::Tab(Indent + 1)); } @@ -3177,7 +3216,7 @@ void FNativeClassHeaderGenerator::ExportEventParm(FUHTStringBuilder& Out, TSetGetClass(); UObjectPropertyBase* ObjectProperty = Cast(Prop); @@ -3573,7 +3612,7 @@ void FNativeClassHeaderGenerator::ExportNativeFunctionHeader( * @param Return return parameter for the function * @param DeprecationWarningOutputDevice Device to output deprecation warnings for _Validate and _Implementation functions. */ -void FNativeClassHeaderGenerator::ExportFunctionThunk(FUHTStringBuilder& RPCWrappers, UFunction* Function, const FFuncInfo& FunctionData, const TArray& Parameters, UProperty* Return, FUHTStringBuilder& DeprecationWarningOutputDevice) +void FNativeClassHeaderGenerator::ExportFunctionThunk(FUHTStringBuilder& RPCWrappers, UFunction* Function, const FFuncInfo& FunctionData, const TArray& Parameters, UProperty* Return) { // export the GET macro for this parameter FString ParameterList; @@ -3819,11 +3858,17 @@ FString FNativeClassHeaderGenerator::GetFunctionParameterString(UFunction* Funct return ParameterList; } -void FNativeClassHeaderGenerator::ExportNativeFunctions(FOutputDevice& OutGeneratedHeaderText, FOutputDevice& OutMacroCalls, FOutputDevice& OutNoPureDeclsMacroCalls, const FUnrealSourceFile& SourceFile, UClass* Class, FClassMetaData* ClassData) +struct FNativeFunctionStringBuilder { FUHTStringBuilder RPCWrappers; FUHTStringBuilder AutogeneratedBlueprintFunctionDeclarations; FUHTStringBuilder AutogeneratedBlueprintFunctionDeclarationsOnlyNotDeclared; +}; + +void FNativeClassHeaderGenerator::ExportNativeFunctions(FOutputDevice& OutGeneratedHeaderText, FOutputDevice& OutMacroCalls, FOutputDevice& OutNoPureDeclsMacroCalls, const FUnrealSourceFile& SourceFile, UClass* Class, FClassMetaData* ClassData) +{ + FNativeFunctionStringBuilder RuntimeStringBuilders; + FNativeFunctionStringBuilder EditorStringBuilders; FString ClassName = Class->GetName(); @@ -3843,6 +3888,9 @@ void FNativeClassHeaderGenerator::ExportNativeFunctions(FOutputDevice& OutGenera continue; } + const bool bEditorOnlyFunc = Function->HasAnyFunctionFlags(FUNC_EditorOnly); + FNativeFunctionStringBuilder& FuncStringBuilders = bEditorOnlyFunc ? EditorStringBuilders : RuntimeStringBuilders; + FFunctionData* CompilerInfo = FFunctionData::FindForFunction(Function); const FFuncInfo& FunctionData = CompilerInfo->GetFunctionData(); @@ -3892,17 +3940,17 @@ void FNativeClassHeaderGenerator::ExportNativeFunctions(FOutputDevice& OutGenera const TCHAR* Virtual = (!FunctionData.FunctionReference->HasAnyFunctionFlags(FUNC_Static) && !(FunctionData.FunctionExportFlags & FUNCEXPORT_Final)) ? TEXT("virtual") : TEXT(""); FStringOutputDevice ValidDecl; ValidDecl.Logf(TEXT("\t%s bool %s(%s);\r\n"), Virtual, *FunctionData.CppValidationImplName, *ParameterList); - AutogeneratedBlueprintFunctionDeclarations.Log(*ValidDecl); + FuncStringBuilders.AutogeneratedBlueprintFunctionDeclarations.Log(*ValidDecl); if (!bHasValidate) { - AutogeneratedBlueprintFunctionDeclarationsOnlyNotDeclared.Logf(TEXT("%s"), *ValidDecl); + FuncStringBuilders.AutogeneratedBlueprintFunctionDeclarationsOnlyNotDeclared.Logf(TEXT("%s"), *ValidDecl); } } - AutogeneratedBlueprintFunctionDeclarations.Log(*FunctionDeclaration); + FuncStringBuilders.AutogeneratedBlueprintFunctionDeclarations.Log(*FunctionDeclaration); if (!bHasImplementation && FunctionData.CppImplName != FunctionName) { - AutogeneratedBlueprintFunctionDeclarationsOnlyNotDeclared.Log(*FunctionDeclaration); + FuncStringBuilders.AutogeneratedBlueprintFunctionDeclarationsOnlyNotDeclared.Log(*FunctionDeclaration); } // Versions that skip function autodeclaration throw an error when a function is missing. @@ -3913,7 +3961,7 @@ void FNativeClassHeaderGenerator::ExportNativeFunctions(FOutputDevice& OutGenera } } - RPCWrappers.Log(TEXT("\r\n")); + FuncStringBuilders.RPCWrappers.Log(TEXT("\r\n")); // if this function was originally declared in a base class, and it isn't a static function, // only the C++ function header will be exported @@ -3923,30 +3971,70 @@ void FNativeClassHeaderGenerator::ExportNativeFunctions(FOutputDevice& OutGenera } // export the script wrappers - RPCWrappers.Logf(TEXT("\tDECLARE_FUNCTION(%s)"), *FunctionData.UnMarshallAndCallName); - RPCWrappers += LINE_TERMINATOR TEXT("\t{") LINE_TERMINATOR; + FuncStringBuilders.RPCWrappers.Logf(TEXT("\tDECLARE_FUNCTION(%s)"), *FunctionData.UnMarshallAndCallName); + FuncStringBuilders.RPCWrappers += LINE_TERMINATOR TEXT("\t{") LINE_TERMINATOR; FParmsAndReturnProperties Parameters = GetFunctionParmsAndReturn(FunctionData.FunctionReference); - ExportFunctionThunk(RPCWrappers, Function, FunctionData, Parameters.Parms, Parameters.Return, AutogeneratedBlueprintFunctionDeclarationsOnlyNotDeclared); + ExportFunctionThunk(FuncStringBuilders.RPCWrappers, Function, FunctionData, Parameters.Parms, Parameters.Return); - RPCWrappers += TEXT("\t}") LINE_TERMINATOR; + FuncStringBuilders.RPCWrappers += TEXT("\t}") LINE_TERMINATOR; } - FString MacroName = SourceFile.GetGeneratedMacroName(ClassData, TEXT("_RPC_WRAPPERS")); - WriteMacro(OutGeneratedHeaderText, MacroName, AutogeneratedBlueprintFunctionDeclarations + RPCWrappers); - OutMacroCalls.Logf(TEXT("\t%s\r\n"), *MacroName); - - // Put static checks before RPCWrappers to get proper messages from static asserts before compiler errors. - FString NoPureDeclsMacroName = SourceFile.GetGeneratedMacroName(ClassData, TEXT("_RPC_WRAPPERS_NO_PURE_DECLS")); - if (SourceFile.GetGeneratedCodeVersionForStruct(Class) > EGeneratedCodeVersion::V1) + // Write runtime wrappers { - WriteMacro(OutGeneratedHeaderText, NoPureDeclsMacroName, RPCWrappers); + FString MacroName = SourceFile.GetGeneratedMacroName(ClassData, TEXT("_RPC_WRAPPERS")); + + WriteMacro(OutGeneratedHeaderText, MacroName, RuntimeStringBuilders.AutogeneratedBlueprintFunctionDeclarations + RuntimeStringBuilders.RPCWrappers); + OutMacroCalls.Logf(TEXT("\t%s\r\n"), *MacroName); + + // Put static checks before RPCWrappers to get proper messages from static asserts before compiler errors. + FString NoPureDeclsMacroName = SourceFile.GetGeneratedMacroName(ClassData, TEXT("_RPC_WRAPPERS_NO_PURE_DECLS")); + if (SourceFile.GetGeneratedCodeVersionForStruct(Class) > EGeneratedCodeVersion::V1) + { + WriteMacro(OutGeneratedHeaderText, NoPureDeclsMacroName, RuntimeStringBuilders.RPCWrappers); + } + else + { + WriteMacro(OutGeneratedHeaderText, NoPureDeclsMacroName, RuntimeStringBuilders.AutogeneratedBlueprintFunctionDeclarationsOnlyNotDeclared + RuntimeStringBuilders.RPCWrappers); + } + + OutNoPureDeclsMacroCalls.Logf(TEXT("\t%s\r\n"), *NoPureDeclsMacroName); } - else + + // Write editor only RPC wrappers if they exist + if (EditorStringBuilders.RPCWrappers.Len() > 0) { - WriteMacro(OutGeneratedHeaderText, NoPureDeclsMacroName, AutogeneratedBlueprintFunctionDeclarationsOnlyNotDeclared + RPCWrappers); + OutGeneratedHeaderText.Log( BeginEditorOnlyGuard ); + + FString MacroName = SourceFile.GetGeneratedMacroName(ClassData, TEXT("_EDITOR_ONLY_RPC_WRAPPERS")); + + + WriteMacro(OutGeneratedHeaderText, MacroName, EditorStringBuilders.AutogeneratedBlueprintFunctionDeclarations + EditorStringBuilders.RPCWrappers); + OutMacroCalls.Logf(TEXT("\t%s\r\n"), *MacroName); + + // Put static checks before RPCWrappers to get proper messages from static asserts before compiler errors. + FString NoPureDeclsMacroName = SourceFile.GetGeneratedMacroName(ClassData, TEXT("_EDITOR_ONLY_RPC_WRAPPERS_NO_PURE_DECLS")); + if (SourceFile.GetGeneratedCodeVersionForStruct(Class) > EGeneratedCodeVersion::V1) + { + WriteMacro(OutGeneratedHeaderText, NoPureDeclsMacroName, EditorStringBuilders.RPCWrappers); + } + else + { + WriteMacro(OutGeneratedHeaderText, NoPureDeclsMacroName, EditorStringBuilders.AutogeneratedBlueprintFunctionDeclarationsOnlyNotDeclared + EditorStringBuilders.RPCWrappers); + } + + // write out an else preprocessor block for when not compiling for the editor. The generated macros should be empty then since the functions are compiled out + { + OutGeneratedHeaderText.Log(TEXT("#else\r\n")); + + WriteMacro(OutGeneratedHeaderText, MacroName, TEXT("")); + WriteMacro(OutGeneratedHeaderText, NoPureDeclsMacroName, TEXT("")); + + OutGeneratedHeaderText.Log(EndEditorOnlyGuard); + } + + OutNoPureDeclsMacroCalls.Logf(TEXT("\t%s\r\n"), *NoPureDeclsMacroName); } - OutNoPureDeclsMacroCalls.Logf(TEXT("\t%s\r\n"), *NoPureDeclsMacroName); } /** @@ -3961,7 +4049,6 @@ void FNativeClassHeaderGenerator::ExportCallbackFunctions( const TArray& CallbackFunctions, const TCHAR* CallbackWrappersMacroName, EExportCallbackType ExportCallbackType, - const TCHAR* API, const TCHAR* APIString ) { @@ -4019,7 +4106,7 @@ void FNativeClassHeaderGenerator::ExportCallbackFunctions( Parameters.HasParms() ? TEXT("&Parms") : TEXT("NULL") ); } - WriteEventFunctionEpilogue(OutCpp, /*Indent=*/ 1, Parameters, *FunctionName); + WriteEventFunctionEpilogue(OutCpp, /*Indent=*/ 1, Parameters); } else { @@ -4141,6 +4228,8 @@ TArray GetSourceFilesInDependencyOrder(const UPackage* Packa return Result; } +TMap GClassToSourceFileMap; + // Constructor. FNativeClassHeaderGenerator::FNativeClassHeaderGenerator( const UPackage* InPackage, @@ -4151,12 +4240,20 @@ FNativeClassHeaderGenerator::FNativeClassHeaderGenerator( ) : API (FPackageName::GetShortName(InPackage).ToUpper()) , Package (InPackage) + , UniqueCrossModuleReferences(nullptr) , bAllowSaveExportedHeaders (InAllowSaveExportedHeaders) , bFailIfGeneratedCodeChanges(FParse::Param(FCommandLine::Get(), TEXT("FailIfGeneratedCodeChanges"))) , UHTMakefile (InUHTMakefile) { const FString PackageName = FPackageName::GetShortName(Package); + FString PkgDir; + FString GeneratedIncludeDirectory; + if (!FindPackageLocation(*PackageName, PkgDir, GeneratedIncludeDirectory)) + { + UE_LOG(LogCompile, Error, TEXT("Failed to find path for package %s"), *PackageName); + } + bool bWriteClassesH = false; const bool bPackageHasAnyExportClasses = AllClasses.GetClassesInPackage(Package).ContainsByPredicate([](FClass* Class) { @@ -4227,9 +4324,39 @@ FNativeClassHeaderGenerator::FNativeClassHeaderGenerator( return GeneratedFunctionBodyTextSplit.Last().Get(); }; + struct FGeneratedCPP + { + explicit FGeneratedCPP(FString InGeneratedCppFullFilename) + : GeneratedCppFullFilename(MoveTemp(InGeneratedCppFullFilename)) + { + } + + FString GeneratedCppFullFilename; + TArray RelativeIncludes; + FUHTStringBuilderLineCounter GeneratedText; + TSet CrossModuleReferences; + }; + + TMap GeneratedCPPs; for (FUnrealSourceFile* SourceFile : Exported) { + FString ModuleRelativeFilename = SourceFile->GetFilename(); + ConvertToBuildIncludePath(Package, ModuleRelativeFilename); + + FString StrippedName = FPaths::GetBaseFilename(ModuleRelativeFilename); + FString BaseSourceFilename = GeneratedIncludeDirectory / StrippedName; + FUHTStringBuilder GeneratedHeaderText; + FGeneratedCPP& GeneratedCPP = GeneratedCPPs.Emplace(SourceFile, BaseSourceFilename + TEXT(".gen.cpp")); + GeneratedCPP.RelativeIncludes.Add(MoveTemp(ModuleRelativeFilename)); + + UniqueCrossModuleReferences = &GeneratedCPP.CrossModuleReferences; + ON_SCOPE_EXIT + { + UniqueCrossModuleReferences = nullptr; + }; + + FUHTStringBuilderLineCounter& OutText = GeneratedCPP.GeneratedText; NameLookupCPP.SetCurrentSourceFile(SourceFile); UHTMakefile.AddToHeaderOrder(SourceFile); @@ -4257,7 +4384,8 @@ FNativeClassHeaderGenerator::FNativeClassHeaderGenerator( // export delegate definitions for (UDelegateFunction* Func : DelegateFunctions) { - ExportDelegateDeclaration(GetGeneratedFunctionTextDevice(), GeneratedFunctionDeclarations, *SourceFile, Func); + GeneratedFunctionDeclarations.Log(FTypeSingletonCache::Get(Func).GetExternDecl()); + ExportDelegateDeclaration(OutText, *SourceFile, Func); } // Export enums declared in non-UClass headers. @@ -4266,7 +4394,8 @@ FNativeClassHeaderGenerator::FNativeClassHeaderGenerator( // Is this ever not the case? if (Enum->GetOuter()->IsA(UPackage::StaticClass())) { - ExportGeneratedEnumInitCode(GetGeneratedFunctionTextDevice(), GeneratedFunctionDeclarations, *SourceFile, Enum); + GeneratedFunctionDeclarations.Log(FTypeSingletonCache::Get(Enum).GetExternDecl()); + ExportGeneratedEnumInitCode(OutText, *SourceFile, Enum); } } @@ -4274,7 +4403,8 @@ FNativeClassHeaderGenerator::FNativeClassHeaderGenerator( // reverse the order. for (UScriptStruct* Struct : Structs) { - ExportGeneratedStructBodyMacros(GeneratedHeaderText, GetGeneratedFunctionTextDevice(), GeneratedFunctionDeclarations, *SourceFile, Struct); + GeneratedFunctionDeclarations.Log(FTypeSingletonCache::Get(Struct).GetExternDecl()); + ExportGeneratedStructBodyMacros(GeneratedHeaderText, OutText, *SourceFile, Struct); } // export delegate wrapper function implementations @@ -4288,8 +4418,10 @@ FNativeClassHeaderGenerator::FNativeClassHeaderGenerator( { if (!(Class->ClassFlags & CLASS_Intrinsic)) { - ExportClassFromSourceFileInner(GeneratedHeaderText, GetGeneratedFunctionTextDevice(), GeneratedFunctionDeclarations, (FClass*)Class, *SourceFile); + ExportClassFromSourceFileInner(GeneratedHeaderText, OutText, GeneratedFunctionDeclarations, (FClass*)Class, *SourceFile); } + + GClassToSourceFileMap.Add(Class, SourceFile); } GeneratedHeaderText.Log(TEXT("#undef CURRENT_FILE_ID\r\n")); @@ -4300,20 +4432,10 @@ FNativeClassHeaderGenerator::FNativeClassHeaderGenerator( ExportEnum(GeneratedHeaderText, Enum); } - const FString PkgName = FPackageName::GetShortName(Package); + FString HeaderPath = BaseSourceFilename + TEXT(".generated.h"); + bool bHasChanged = WriteHeader(*HeaderPath, GeneratedHeaderText, ForwardDeclarations); - FString PkgDir; - FString GeneratedIncludeDirectory; - if (!FindPackageLocation(*PkgName, PkgDir, GeneratedIncludeDirectory)) - { - UE_LOG(LogCompile, Error, TEXT("Failed to find path for package %s"), *PkgName); - } - - const FString ClassHeaderPath = GeneratedIncludeDirectory / FPaths::GetBaseFilename(SourceFile->GetFilename()) + TEXT(".generated.h"); - - bool bHasChanged = WriteHeader(*ClassHeaderPath, GeneratedHeaderText, ForwardDeclarations); - - SourceFile->SetGeneratedFilename(ClassHeaderPath); + SourceFile->SetGeneratedFilename(HeaderPath); SourceFile->SetHasChanged(bHasChanged); ForwardDeclarations.Reset(); @@ -4324,17 +4446,28 @@ FNativeClassHeaderGenerator::FNativeClassHeaderGenerator( } } + // Add includes for 'Within' classes + for (FUnrealSourceFile* SourceFile : Exported) + { + TArray DefinedClasses = SourceFile->GetDefinedClasses(); + for (UClass* Class : DefinedClasses) + { + if (Class->ClassWithin && Class->ClassWithin != UObject::StaticClass()) + { + if (FUnrealSourceFile** WithinSourceFile = GClassToSourceFileMap.Find(Class->ClassWithin)) + { + FString Header = GetBuildPath(**WithinSourceFile); + TArray& RelativeIncludes = GeneratedCPPs[SourceFile].RelativeIncludes; + RelativeIncludes.AddUnique(MoveTemp(Header)); + } + } + } + } + if (bWriteClassesH) { // Write the classes and enums header prefixes. - FString PkgDir; - FString GeneratedIncludeDirectory; - if (!FindPackageLocation(*PackageName, PkgDir, GeneratedIncludeDirectory)) - { - UE_LOG(LogCompile, Error, TEXT("Failed to find path for package %s"), *PackageName); - } - FUHTStringBuilder ClassesHText; ClassesHText.Log(HeaderCopyright); ClassesHText.Log(TEXT("#pragma once\r\n")); @@ -4365,15 +4498,15 @@ FNativeClassHeaderGenerator::FNativeClassHeaderGenerator( // now export the names for the functions in this package // notice we always export this file (as opposed to only exporting if we have any marked names) // because there would be no way to know when the file was created otherwise - // Export .generated.cpp - UE_LOG(LogCompile, Log, TEXT("Autogenerating boilerplate cpp: %s.generated.cpp"), *PackageName); + // Export .gen.cpp + UE_LOG(LogCompile, Log, TEXT("Autogenerating boilerplate cpp: %s.gen.cpp"), *PackageName); - if (GeneratedFunctionDeclarations.Len() || UniqueCrossModuleReferences.Num() > 0) + if (GeneratedFunctionDeclarations.Len()) { uint32 CombinedCRC = 0; - for (TUniqueObj& Split : GeneratedFunctionBodyTextSplit) + for (const TPair& GeneratedCPP : GeneratedCPPs) { - uint32 SplitCRC = GenerateTextCRC(**Split); + uint32 SplitCRC = GenerateTextCRC(*GeneratedCPP.Value.GeneratedText); if (CombinedCRC == 0) { // Don't combine in the first case because it keeps GUID backwards compatibility @@ -4385,31 +4518,12 @@ FNativeClassHeaderGenerator::FNativeClassHeaderGenerator( } } - ExportGeneratedPackageInitCode(GetGeneratedFunctionTextDevice(), GeneratedFunctionDeclarations, Package, CombinedCRC); - } - - // Write out large include-everything header - FUHTStringBuilder Includes; - for (const FUnrealSourceFile* SourceFile : Exported) - { - FString NewFileName = SourceFile->GetFilename(); - ConvertToBuildIncludePath(Package, NewFileName); - - FString IncludeStr = FString::Printf( - TEXT("#ifndef %s") LINE_TERMINATOR - TEXT("\t#include \"%s\"") LINE_TERMINATOR - TEXT("#endif") LINE_TERMINATOR, - *SourceFile->GetFileDefineName(), *NewFileName); - - Includes.Log(*IncludeStr); + FGeneratedCPP& GeneratedCPP = GeneratedCPPs.Emplace(nullptr, GeneratedIncludeDirectory / FString::Printf(TEXT("%s.init.gen.cpp"), *PackageName)); + ExportGeneratedPackageInitCode(GeneratedCPP.GeneratedText, *GeneratedFunctionDeclarations, Package, CombinedCRC); } const FManifestModule* ModuleInfo = GPackageToManifestModuleMap.FindChecked(Package); - // Write out the ordered class dependencies into a single header that we can easily include - FString DepHeaderPathname = ModuleInfo->GeneratedCPPFilenameBase + TEXT(".dep.h"); - SaveHeaderIfChanged(*DepHeaderPathname, *FString::Printf(TEXT("%s%s%s"), HeaderCopyright, RequiredCPPIncludes, *Includes)); - // Find other includes to put at the top of the .cpp FUHTStringBuilder OtherIncludes; if (ModuleInfo->PCH.Len()) @@ -4418,45 +4532,51 @@ FNativeClassHeaderGenerator::FNativeClassHeaderGenerator( ConvertToBuildIncludePath(Package, PCH); OtherIncludes.Logf(TEXT("#include \"%s\"") LINE_TERMINATOR, *PCH); } - OtherIncludes.Logf(TEXT("#include \"%s\"") LINE_TERMINATOR, *FPaths::GetCleanFilename(DepHeaderPathname)); + // Generate CPP files + TArray GeneratedCPPNames; + for (const TPair& GeneratedCPP : GeneratedCPPs) { - // Generate CPP files - TArray NumberedHeaderNames; - for (int32 FileIdx = 0; FileIdx < GeneratedFunctionBodyTextSplit.Num(); ++FileIdx) + FUHTStringBuilder FileText; + + FString GeneratedIncludes = OtherIncludes; + for (const FString& RelativeInclude : GeneratedCPP.Value.RelativeIncludes) { - FUHTStringBuilder FileText; - ExportGeneratedCPP( - FileText, - *FString::Printf(TEXT("%d%s"), FileIdx + 1, *ModuleInfo->Name), - *GeneratedFunctionDeclarations, - *GeneratedFunctionBodyTextSplit[FileIdx].Get(), - *OtherIncludes - ); - - FString CppPath = ModuleInfo->GeneratedCPPFilenameBase + (GeneratedFunctionBodyTextSplit.Num() > 1 ? *FString::Printf(TEXT(".%d.cpp"), FileIdx + 1) : TEXT(".cpp")); - SaveHeaderIfChanged(*CppPath, *FileText); - - if (GeneratedFunctionBodyTextSplit.Num() > 1) - { - NumberedHeaderNames.Add(FPaths::GetCleanFilename(CppPath)); - } + GeneratedIncludes += FString::Printf(TEXT("#include \"%s\"\r\n"), *RelativeInclude); } + ExportGeneratedCPP( + FileText, + GeneratedCPP.Value.CrossModuleReferences, + *FPaths::GetCleanFilename(GeneratedCPP.Value.GeneratedCppFullFilename).Replace(TEXT(".gen.cpp"), TEXT("")).Replace(TEXT("."), TEXT("_")), + *GeneratedCPP.Value.GeneratedText, + *GeneratedIncludes + ); + + SaveHeaderIfChanged(*GeneratedCPP.Value.GeneratedCppFullFilename, *FileText); + + GeneratedCPPNames.Add(FPaths::GetCleanFilename(*GeneratedCPP.Value.GeneratedCppFullFilename)); + } + + if (bAllowSaveExportedHeaders) + { // Delete old generated .cpp files which we don't need because we generated less code than last time. TArray FoundFiles; - IFileManager::Get().FindFiles(FoundFiles, *(ModuleInfo->GeneratedCPPFilenameBase + TEXT(".*.cpp")), true, false); FString BaseDir = FPaths::GetPath(ModuleInfo->GeneratedCPPFilenameBase); + IFileManager::Get().FindFiles(FoundFiles, *FPaths::Combine(BaseDir, TEXT("*.generated.cpp")), true, false); + IFileManager::Get().FindFiles(FoundFiles, *FPaths::Combine(BaseDir, TEXT("*.generated.*.cpp")), true, false); + IFileManager::Get().FindFiles(FoundFiles, *FPaths::Combine(BaseDir, TEXT("*.gen.cpp")), true, false); + IFileManager::Get().FindFiles(FoundFiles, *FPaths::Combine(BaseDir, TEXT("*.gen.*.cpp")), true, false); for (FString& File : FoundFiles) { - if (!NumberedHeaderNames.Contains(File)) + if (!GeneratedCPPNames.Contains(File)) { IFileManager::Get().Delete(*FPaths::Combine(*BaseDir, *File)); } } - // delete the old .cpp file that will cause link errors if it's left around (Engine.generated.cpp and Engine.generated.1.cpp will - // conflict now that we no longer use Engine.generated.cpp to #include Engine.generated.1.cpp, and UBT would compile all 3) + // delete the old .cpp file that will cause link errors if it's left around (Engine.gen.cpp and Engine.gen.1.cpp will + // conflict now that we no longer use Engine.gen.cpp to #include Engine.gen.1.cpp, and UBT would compile all 3) // @todo: This is a temp measure so we don't force everyone to require a Clean if (GeneratedFunctionBodyTextSplit.Num() > 1) { @@ -4678,9 +4798,8 @@ void FNativeClassHeaderGenerator::ExportUpdatedHeaders(FString PackageName) /** * Exports C++ definitions for boilerplate that was generated for a package. - * They are exported to a file using the name .generated.cpp */ -void FNativeClassHeaderGenerator::ExportGeneratedCPP(FOutputDevice& Out, const TCHAR* EmptyLinkFunctionPostfix, const TCHAR* Declarations, const TCHAR* Body, const TCHAR* OtherIncludes) +void FNativeClassHeaderGenerator::ExportGeneratedCPP(FOutputDevice& Out, const TSet& InCrossModuleReferences, const TCHAR* EmptyLinkFunctionPostfix, const TCHAR* Body, const TCHAR* OtherIncludes) { static const TCHAR EnableOptimization [] = TEXT("PRAGMA_ENABLE_OPTIMIZATION") LINE_TERMINATOR; static const TCHAR DisableOptimization [] = TEXT("PRAGMA_DISABLE_OPTIMIZATION") LINE_TERMINATOR; @@ -4698,23 +4817,16 @@ void FNativeClassHeaderGenerator::ExportGeneratedCPP(FOutputDevice& Out, const T Out.Logf(TEXT("void EmptyLinkFunctionForGeneratedCode%s() {}") LINE_TERMINATOR, EmptyLinkFunctionPostfix); - if (*Declarations || UniqueCrossModuleReferences.Num() > 0) + if (InCrossModuleReferences.Num() > 0) { - Out.Logf(TEXT("#if USE_COMPILED_IN_NATIVES\r\n")); - if (UniqueCrossModuleReferences.Num() > 0) + Out.Logf(TEXT("// Cross Module References\r\n")); + for (const FString& Ref : InCrossModuleReferences) { - Out.Logf(TEXT("// Cross Module References\r\n")); - for (const FString& Ref : UniqueCrossModuleReferences) - { - Out.Log(*Ref); - } - Out.Logf(TEXT("\r\n")); + Out.Log(*Ref); } - Out.Log(Declarations); - Out.Log(Body); - Out.Logf(TEXT("#endif\r\n")); + Out.Logf(TEXT("// End Cross Module References\r\n")); } - + Out.Log(Body); Out.Log(EnableDeprecationWarnings); Out.Log(EnableWarning4883); Out.Log(EnableOptimization); @@ -4778,7 +4890,7 @@ void ResolveSuperClasses(UPackage* Package) TArray Objects; GetObjectsWithOuter(Package, Objects); - for (auto* Object : Objects) + for (UObject* Object : Objects) { if (!Object->IsA()) { @@ -5186,6 +5298,20 @@ ECompilationResult::Type UnrealHeaderTool_Main(const FString& ModuleInfoFilename ScriptGenerator->FinishExport(); } } + + // Get a list of external dependencies from each enabled plugin + FString ExternalDependencies; + for (IScriptGeneratorPluginInterface* ScriptPlugin : ScriptPlugins) + { + TArray PluginExternalDependencies; + ScriptPlugin->GetExternalDependencies(PluginExternalDependencies); + + for (const FString& PluginExternalDependency : PluginExternalDependencies) + { + ExternalDependencies += PluginExternalDependency + LINE_TERMINATOR; + } + } + FFileHelper::SaveStringToFile(ExternalDependencies, *GManifest.ExternalDependenciesFile); } } @@ -5238,7 +5364,7 @@ ECompilationResult::Type UnrealHeaderTool_Main(const FString& ModuleInfoFilename return Result; } -UClass* ProcessParsedClass(bool bClassIsAnInterface, TArray &DependentOn, const FString& ClassName, const FString& BaseClassName, UObject* InParent, EObjectFlags Flags) +UClass* ProcessParsedClass(bool bClassIsAnInterface, TArray& DependentOn, const FString& ClassName, const FString& BaseClassName, UObject* InParent, EObjectFlags Flags) { FString ClassNameStripped = GetClassNameWithPrefixRemoved(*ClassName); diff --git a/Engine/Source/Programs/UnrealHeaderTool/Private/HeaderParser.cpp b/Engine/Source/Programs/UnrealHeaderTool/Private/HeaderParser.cpp index a8d197ac181b..6114987df098 100644 --- a/Engine/Source/Programs/UnrealHeaderTool/Private/HeaderParser.cpp +++ b/Engine/Source/Programs/UnrealHeaderTool/Private/HeaderParser.cpp @@ -256,9 +256,10 @@ namespace * @param FuncInfo - The FFuncInfo object to populate. * @param Specifiers - The specifiers to process. */ - void ProcessFunctionSpecifiers(FFuncInfo& FuncInfo, const TArray& Specifiers) + void ProcessFunctionSpecifiers(FFuncInfo& FuncInfo, const TArray& Specifiers, TMap& MetaData) { bool bSpecifiedUnreliable = false; + bool bSawPropertyAccessor = false; for (const FPropertySpecifier& Specifier : Specifiers) { @@ -274,16 +275,20 @@ namespace { if (FuncInfo.FunctionFlags & FUNC_Net) { - FError::Throwf(TEXT("BlueprintNativeEvent functions cannot be replicated!") ); + UE_LOG_ERROR_UHT(TEXT("BlueprintNativeEvent functions cannot be replicated!") ); } else if ( (FuncInfo.FunctionFlags & FUNC_BlueprintEvent) && !(FuncInfo.FunctionFlags & FUNC_Native) ) { // already a BlueprintImplementableEvent - FError::Throwf(TEXT("A function cannot be both BlueprintNativeEvent and BlueprintImplementableEvent!") ); + UE_LOG_ERROR_UHT(TEXT("A function cannot be both BlueprintNativeEvent and BlueprintImplementableEvent!") ); + } + else if (bSawPropertyAccessor) + { + UE_LOG_ERROR_UHT(TEXT("A function cannot be both BlueprintNativeEvent and a Blueprint Property accessor!")); } else if ( (FuncInfo.FunctionFlags & FUNC_Private) ) { - FError::Throwf(TEXT("A Private function cannot be a BlueprintNativeEvent!") ); + UE_LOG_ERROR_UHT(TEXT("A Private function cannot be a BlueprintNativeEvent!") ); } FuncInfo.FunctionFlags |= FUNC_Event; @@ -295,16 +300,20 @@ namespace { if (FuncInfo.FunctionFlags & FUNC_Net) { - FError::Throwf(TEXT("BlueprintImplementableEvent functions cannot be replicated!") ); + UE_LOG_ERROR_UHT(TEXT("BlueprintImplementableEvent functions cannot be replicated!") ); } else if ( (FuncInfo.FunctionFlags & FUNC_BlueprintEvent) && (FuncInfo.FunctionFlags & FUNC_Native) ) { // already a BlueprintNativeEvent - FError::Throwf(TEXT("A function cannot be both BlueprintNativeEvent and BlueprintImplementableEvent!") ); + UE_LOG_ERROR_UHT(TEXT("A function cannot be both BlueprintNativeEvent and BlueprintImplementableEvent!") ); + } + else if (bSawPropertyAccessor) + { + UE_LOG_ERROR_UHT(TEXT("A function cannot be both BlueprintImplementableEvent and a Blueprint Property accessor!")); } else if ( (FuncInfo.FunctionFlags & FUNC_Private) ) { - FError::Throwf(TEXT("A Private function cannot be a BlueprintImplementableEvent!") ); + UE_LOG_ERROR_UHT(TEXT("A Private function cannot be a BlueprintImplementableEvent!") ); } FuncInfo.FunctionFlags |= FUNC_Event; @@ -318,7 +327,7 @@ namespace FuncInfo.FunctionFlags |= FUNC_Exec; if( FuncInfo.FunctionFlags & FUNC_Net ) { - FError::Throwf(TEXT("Exec functions cannot be replicated!") ); + UE_LOG_ERROR_UHT(TEXT("Exec functions cannot be replicated!") ); } } break; @@ -346,7 +355,7 @@ namespace if( FuncInfo.FunctionFlags & FUNC_Exec ) { - FError::Throwf(TEXT("Exec functions cannot be replicated!") ); + UE_LOG_ERROR_UHT(TEXT("Exec functions cannot be replicated!") ); } } break; @@ -445,6 +454,33 @@ namespace } break; + case EFunctionSpecifier::BlueprintGetter: + { + if (FuncInfo.FunctionFlags & FUNC_Event) + { + UE_LOG_ERROR_UHT(TEXT("Function cannot be a blueprint event and a blueprint getter.")); + } + + bSawPropertyAccessor = true; + FuncInfo.FunctionFlags |= FUNC_BlueprintCallable; + FuncInfo.FunctionFlags |= FUNC_BlueprintPure; + MetaData.Add(TEXT("BlueprintGetter")); + } + break; + + case EFunctionSpecifier::BlueprintSetter: + { + if (FuncInfo.FunctionFlags & FUNC_Event) + { + UE_LOG_ERROR_UHT(TEXT("Function cannot be a blueprint event and a blueprint setter.")); + } + + bSawPropertyAccessor = true; + FuncInfo.FunctionFlags |= FUNC_BlueprintCallable; + MetaData.Add(TEXT("BlueprintSetter")); + } + break; + case EFunctionSpecifier::BlueprintPure: { bool bIsPure = true; @@ -503,37 +539,43 @@ namespace bool bIsNetService = !!(FuncInfo.FunctionFlags & (FUNC_NetRequest | FUNC_NetResponse)); bool bIsNetReliable = !!(FuncInfo.FunctionFlags & FUNC_NetReliable); - if ( FuncInfo.FunctionFlags & FUNC_Static ) - FError::Throwf(TEXT("Static functions can't be replicated") ); + if (FuncInfo.FunctionFlags & FUNC_Static) + { + UE_LOG_ERROR_UHT(TEXT("Static functions can't be replicated")); + } if (!bIsNetReliable && !bSpecifiedUnreliable && !bIsNetService) - FError::Throwf(TEXT("Replicated function: 'reliable' or 'unreliable' is required")); + { + UE_LOG_ERROR_UHT(TEXT("Replicated function: 'reliable' or 'unreliable' is required")); + } if (bIsNetReliable && bSpecifiedUnreliable && !bIsNetService) - FError::Throwf(TEXT("'reliable' and 'unreliable' are mutually exclusive")); + { + UE_LOG_ERROR_UHT(TEXT("'reliable' and 'unreliable' are mutually exclusive")); + } } else if (FuncInfo.FunctionFlags & FUNC_NetReliable) { - FError::Throwf(TEXT("'reliable' specified without 'client' or 'server'")); + UE_LOG_ERROR_UHT(TEXT("'reliable' specified without 'client' or 'server'")); } else if (bSpecifiedUnreliable) { - FError::Throwf(TEXT("'unreliable' specified without 'client' or 'server'")); + UE_LOG_ERROR_UHT(TEXT("'unreliable' specified without 'client' or 'server'")); } if (FuncInfo.bSealedEvent && !(FuncInfo.FunctionFlags & FUNC_Event)) { - FError::Throwf(TEXT("SealedEvent may only be used on events")); + UE_LOG_ERROR_UHT(TEXT("SealedEvent may only be used on events")); } if (FuncInfo.bSealedEvent && FuncInfo.FunctionFlags & FUNC_BlueprintEvent) { - FError::Throwf(TEXT("SealedEvent cannot be used on Blueprint events")); + UE_LOG_ERROR_UHT(TEXT("SealedEvent cannot be used on Blueprint events")); } if (FuncInfo.bForceBlueprintImpure && (FuncInfo.FunctionFlags & FUNC_BlueprintPure) != 0) { - FError::Throwf(TEXT("BlueprintPure (or BlueprintPure=true) and BlueprintPure=false should not both appear on the same function, they are mutually exclusive")); + UE_LOG_ERROR_UHT(TEXT("BlueprintPure (or BlueprintPure=true) and BlueprintPure=false should not both appear on the same function, they are mutually exclusive")); } } @@ -881,7 +923,7 @@ namespace } // Unreachable - check(false); + check(false); //-V779 return nullptr; } @@ -1017,12 +1059,15 @@ namespace return IsPropertySupportedByBlueprint(MapProperty->KeyProp, false) && IsPropertySupportedByBlueprint(MapProperty->ValueProp, false); } + else if (const UStructProperty* StructProperty = Cast(Property)) + { + return (StructProperty->Struct->GetBoolMetaDataHierarchical(TEXT("BlueprintType"))); + } const bool bSupportedType = Property->IsA() || Property->IsA() || Property->IsA() || Property->IsA() - || Property->IsA() || Property->IsA() || Property->IsA() || Property->IsA() @@ -1992,7 +2037,7 @@ UScriptStruct* FHeaderParser::CompileStructDeclaration(FClasses& AllClasses) if (!FPaths::IsSamePath(Filename, GTypeDefinitionInfoMap[UObject::StaticClass()]->GetUnrealSourceFile().GetFilename())) { - FError::Throwf(TEXT("Immutable is being phased out in favor of SerializeNative, and is only legal on the mirror structs declared in UObject")); + UE_LOG_ERROR_UHT(TEXT("Immutable is being phased out in favor of SerializeNative, and is only legal on the mirror structs declared in UObject")); } } break; @@ -2675,7 +2720,7 @@ void FHeaderParser::FixupDelegateProperties( FClasses& AllClasses, UStruct* Stru const bool bAllowedArrayRefFromBP = bClassGeneratedFromBP && FuncParam->IsA(); if (!bAllowedArrayRefFromBP) { - FError::Throwf(TEXT("BlueprintAssignable delegates do not support non-const references at the moment. Function: %s Parameter: '%s'"), *SourceDelegateFunction->GetName(), *FuncParam->GetName()); + UE_LOG_ERROR_UHT(TEXT("BlueprintAssignable delegates do not support non-const references at the moment. Function: %s Parameter: '%s'"), *SourceDelegateFunction->GetName(), *FuncParam->GetName()); } } } @@ -2701,92 +2746,189 @@ void FHeaderParser::FixupDelegateProperties( FClasses& AllClasses, UStruct* Stru } } -/** - * Verifies that all specified class's UProperties with CFG_RepNotify have valid callback targets with no parameters nor return values - * - * @param TargetClass class to verify rep notify properties for - */ -void FHeaderParser::VerifyRepNotifyCallbacks( UClass* TargetClass ) +void FHeaderParser::VerifyBlueprintPropertyGetter(UProperty* Prop, UFunction* TargetFunc) +{ + check(TargetFunc); + + UProperty* ReturnProp = TargetFunc->GetReturnProperty(); + if (TargetFunc->NumParms > 1 || (TargetFunc->NumParms == 1 && ReturnProp == nullptr)) + { + UE_LOG_ERROR_UHT(TEXT("Blueprint Property getter function %s must not have parameters."), *TargetFunc->GetName()); + } + + if (ReturnProp == nullptr || !Prop->SameType(ReturnProp)) + { + FString ExtendedCPPType; + FString CPPType = Prop->GetCPPType(&ExtendedCPPType); + UE_LOG_ERROR_UHT(TEXT("Blueprint Property getter function %s must have return value of type %s%s."), *TargetFunc->GetName(), *CPPType, *ExtendedCPPType); + } + + if (TargetFunc->HasAnyFunctionFlags(FUNC_Event)) + { + UE_LOG_ERROR_UHT(TEXT("Blueprint Property setter function cannot be a blueprint event.")); + } + else if (!TargetFunc->HasAnyFunctionFlags(FUNC_BlueprintPure)) + { + UE_LOG_ERROR_UHT(TEXT("Blueprint Property getter function must be pure.")); + } +} + +void FHeaderParser::VerifyBlueprintPropertySetter(UProperty* Prop, UFunction* TargetFunc) +{ + check(TargetFunc); + UProperty* ReturnProp = TargetFunc->GetReturnProperty(); + + if (ReturnProp) + { + UE_LOG_ERROR_UHT(TEXT("Blueprint Property setter function %s must not have a return value."), *TargetFunc->GetName()); + } + else + { + TFieldIterator Parm(TargetFunc); + if (TargetFunc->NumParms != 1 || !Prop->SameType(*Parm)) + { + FString ExtendedCPPType; + FString CPPType = Prop->GetCPPType(&ExtendedCPPType); + UE_LOG_ERROR_UHT(TEXT("Blueprint Property setter function %s must have exactly one parameter of type %s%s."), *TargetFunc->GetName(), *CPPType, *ExtendedCPPType); + } + } + + if (TargetFunc->HasAnyFunctionFlags(FUNC_Event)) + { + UE_LOG_ERROR_UHT(TEXT("Blueprint Property setter function cannot be a blueprint event.")); + } + else if (!TargetFunc->HasAnyFunctionFlags(FUNC_BlueprintCallable)) + { + UE_LOG_ERROR_UHT(TEXT("Blueprint Property setter function must be blueprint callable.")); + } + else if (TargetFunc->HasAnyFunctionFlags(FUNC_BlueprintPure)) + { + UE_LOG_ERROR_UHT(TEXT("Blueprint Property setter function must not be pure.")); + } +} + +void FHeaderParser::VerifyRepNotifyCallback(UProperty* Prop, UFunction* TargetFunc) +{ + if( TargetFunc ) + { + if (TargetFunc->GetReturnProperty()) + { + UE_LOG_ERROR_UHT(TEXT("Replication notification function %s must not have return value."), *TargetFunc->GetName()); + } + + const bool bIsArrayProperty = ( Prop->ArrayDim > 1 || Cast(Prop) ); + const int32 MaxParms = bIsArrayProperty ? 2 : 1; + + if ( TargetFunc->NumParms > MaxParms) + { + UE_LOG_ERROR_UHT(TEXT("Replication notification function %s has too many parameters."), *TargetFunc->GetName()); + } + + TFieldIterator Parm(TargetFunc); + if ( TargetFunc->NumParms >= 1 && Parm) + { + // First parameter is always the old value: + if ( !Prop->SameType(*Parm) ) + { + FString ExtendedCPPType; + FString CPPType = Prop->GetCPPType(&ExtendedCPPType); + UE_LOG_ERROR_UHT(TEXT("Replication notification function %s has invalid parameter for property %s. First (optional) parameter must be of type %s%s."), *TargetFunc->GetName(), *Prop->GetName(), *CPPType, *ExtendedCPPType); + } + + ++Parm; + } + + if ( TargetFunc->NumParms >= 2 && Parm) + { + // A 2nd parameter for arrays can be specified as a const TArray&. This is a list of element indices that have changed + UArrayProperty *ArrayProp = Cast(*Parm); + if (!(ArrayProp && Cast(ArrayProp->Inner)) || !(Parm->GetPropertyFlags() & CPF_ConstParm) || !(Parm->GetPropertyFlags() & CPF_ReferenceParm)) + { + UE_LOG_ERROR_UHT(TEXT("Replication notification function %s (optional) second parameter must be of type 'const TArray&'"), *TargetFunc->GetName()); + } + } + } + else + { + // Couldn't find a valid function... + UE_LOG_ERROR_UHT(TEXT("Replication notification function %s not found"), *Prop->RepNotifyFunc.ToString() ); + } +} +void FHeaderParser::VerifyPropertyMarkups( UClass* TargetClass ) { // Iterate over all properties, looking for those flagged as CPF_RepNotify for ( UField* Field = TargetClass->Children; Field; Field = Field->Next ) { - UProperty* Prop = Cast(Field); - if( Prop && (Prop->GetPropertyFlags() & CPF_RepNotify) ) + if (UProperty* Prop = Cast(Field)) { + auto FindTargetFunction = [&](const FName FuncName) + { + // Search through this class and its superclasses looking for the specified callback + UFunction* TargetFunc = nullptr; + UClass* SearchClass = TargetClass; + while( SearchClass && !TargetFunc ) + { + // Since the function map is not valid yet, we have to iterate over the fields to look for the function + for( UField* TestField = SearchClass->Children; TestField; TestField = TestField->Next ) + { + UFunction* TestFunc = Cast(TestField); + if (TestFunc && FNativeClassHeaderGenerator::GetOverriddenFName(TestFunc) == FuncName) + { + TargetFunc = TestFunc; + break; + } + } + SearchClass = SearchClass->GetSuperClass(); + } + + return TargetFunc; + }; + FClassMetaData* TargetClassData = GScriptHelper.FindClassData(TargetClass); check(TargetClassData); FTokenData* PropertyToken = TargetClassData->FindTokenData(Prop); check(PropertyToken); - // Search through this class and its superclasses looking for the specified callback - UFunction* TargetFunc = NULL; - UClass* SearchClass = TargetClass; - while( SearchClass && !TargetFunc ) + TGuardValue GuardedInputPos(InputPos, PropertyToken->Token.StartPos); + TGuardValue GuardedInputLine(InputLine, PropertyToken->Token.StartLine); + + if (Prop->HasAnyPropertyFlags(CPF_RepNotify)) { - // Since the function map is not valid yet, we have to iterate over the fields to look for the function - for( UField* TestField = SearchClass->Children; TestField; TestField = TestField->Next ) - { - UFunction* TestFunc = Cast(TestField); - if (TestFunc && FNativeClassHeaderGenerator::GetOverriddenFName(TestFunc) == Prop->RepNotifyFunc) - { - TargetFunc = TestFunc; - break; - } - } - SearchClass = SearchClass->GetSuperClass(); + VerifyRepNotifyCallback(Prop, FindTargetFunction(Prop->RepNotifyFunc)); } - if( TargetFunc ) + if (Prop->HasAnyPropertyFlags(CPF_BlueprintVisible)) { - if (TargetFunc->GetReturnProperty()) + const FString GetterFuncName = Prop->GetMetaData(TEXT("BlueprintGetter")); + if (!GetterFuncName.IsEmpty()) { - UngetToken(PropertyToken->Token); - FError::Throwf(TEXT("Replication notification function %s must not have return values"), *Prop->RepNotifyFunc.ToString()); - break; - } - - bool IsArrayProperty = ( Prop->ArrayDim > 1 || Cast(Prop) ); - int32 MaxParms = IsArrayProperty ? 2 : 1; - - if ( TargetFunc->NumParms > MaxParms) - { - UngetToken(PropertyToken->Token); - FError::Throwf(TEXT("Replication notification function %s has too many parameters"), *Prop->RepNotifyFunc.ToString()); - break; - } - - TFieldIterator Parm(TargetFunc); - if ( TargetFunc->NumParms >= 1 && Parm) - { - // First parameter is always the old value: - if ( Parm->GetClass() != Prop->GetClass() ) + if (UFunction* TargetFunc = FindTargetFunction(*GetterFuncName)) { - UngetToken(PropertyToken->Token); - FError::Throwf(TEXT("Replication notification function %s has invalid parameter for property $%s. First (optional) parameter must be a const reference of the same property type."), *Prop->RepNotifyFunc.ToString(), *Prop->GetName()); - break; + VerifyBlueprintPropertyGetter(Prop, TargetFunc); } - - ++Parm; - } - - if ( TargetFunc->NumParms >= 2 && Parm) - { - // A 2nd parameter for arrays can be specified as a const TArray&. This is a list of element indices that have changed - UArrayProperty *ArrayProp = Cast(*Parm); - if (!(ArrayProp && Cast(ArrayProp->Inner)) || !(Parm->GetPropertyFlags() & CPF_ConstParm) || !(Parm->GetPropertyFlags() & CPF_ReferenceParm)) + else { - UngetToken(PropertyToken->Token); - FError::Throwf(TEXT("Replication notification function %s (optional) parameter must be of type 'const TArray&'"), *Prop->RepNotifyFunc.ToString()); - break; + // Couldn't find a valid function... + UE_LOG_ERROR_UHT(TEXT("Blueprint Property getter function %s not found"), *GetterFuncName); + } + } + + if (!Prop->HasAnyPropertyFlags(CPF_BlueprintReadOnly)) + { + const FString SetterFuncName = Prop->GetMetaData(TEXT("BlueprintSetter")); + if (!SetterFuncName.IsEmpty()) + { + if (UFunction* TargetFunc = FindTargetFunction(*SetterFuncName)) + { + VerifyBlueprintPropertySetter(Prop, TargetFunc); + } + else + { + // Couldn't find a valid function... + UE_LOG_ERROR_UHT(TEXT("Blueprint Property setter function %s not found"), *SetterFuncName); + } } } - } - else - { - // Couldn't find a valid function... - UngetToken(PropertyToken->Token); - FError::Throwf(TEXT("Replication notification function %s not found"), *Prop->RepNotifyFunc.ToString() ); } } } @@ -3014,7 +3156,9 @@ void FHeaderParser::GetVarType( // Process the list of specifiers bool bSeenEditSpecifier = false; - bool bSeenBlueprintEditSpecifier = false; + bool bSeenBlueprintWriteSpecifier = false; + bool bSeenBlueprintReadOnlySpecifier = false; + bool bSeenBlueprintGetterSpecifier = false; for (const FPropertySpecifier& Specifier : SpecifiersFound) { EVariableSpecifier SpecID = (EVariableSpecifier)Algo::FindSortedStringCaseInsensitive(*Specifier.Key, GVariableSpecifierStrings); @@ -3026,7 +3170,7 @@ void FHeaderParser::GetVarType( { if (bSeenEditSpecifier) { - FError::Throwf(TEXT("Found more than one edit/visibility specifier (%s), only one is allowed"), *Specifier.Key); + UE_LOG_ERROR_UHT(TEXT("Found more than one edit/visibility specifier (%s), only one is allowed"), *Specifier.Key); } Flags |= CPF_Edit; bSeenEditSpecifier = true; @@ -3037,7 +3181,7 @@ void FHeaderParser::GetVarType( { if (bSeenEditSpecifier) { - FError::Throwf(TEXT("Found more than one edit/visibility specifier (%s), only one is allowed"), *Specifier.Key); + UE_LOG_ERROR_UHT(TEXT("Found more than one edit/visibility specifier (%s), only one is allowed"), *Specifier.Key); } Flags |= CPF_Edit | CPF_DisableEditOnTemplate; bSeenEditSpecifier = true; @@ -3048,7 +3192,7 @@ void FHeaderParser::GetVarType( { if (bSeenEditSpecifier) { - FError::Throwf(TEXT("Found more than one edit/visibility specifier (%s), only one is allowed"), *Specifier.Key); + UE_LOG_ERROR_UHT(TEXT("Found more than one edit/visibility specifier (%s), only one is allowed"), *Specifier.Key); } Flags |= CPF_Edit | CPF_DisableEditOnInstance; bSeenEditSpecifier = true; @@ -3059,7 +3203,7 @@ void FHeaderParser::GetVarType( { if (bSeenEditSpecifier) { - FError::Throwf(TEXT("Found more than one edit/visibility specifier (%s), only one is allowed"), *Specifier.Key); + UE_LOG_ERROR_UHT(TEXT("Found more than one edit/visibility specifier (%s), only one is allowed"), *Specifier.Key); } Flags |= CPF_Edit | CPF_EditConst; bSeenEditSpecifier = true; @@ -3070,7 +3214,7 @@ void FHeaderParser::GetVarType( { if (bSeenEditSpecifier) { - FError::Throwf(TEXT("Found more than one edit/visibility specifier (%s), only one is allowed"), *Specifier.Key); + UE_LOG_ERROR_UHT(TEXT("Found more than one edit/visibility specifier (%s), only one is allowed"), *Specifier.Key); } Flags |= CPF_Edit | CPF_EditConst | CPF_DisableEditOnTemplate; bSeenEditSpecifier = true; @@ -3081,7 +3225,7 @@ void FHeaderParser::GetVarType( { if (bSeenEditSpecifier) { - FError::Throwf(TEXT("Found more than one edit/visibility specifier (%s), only one is allowed"), *Specifier.Key); + UE_LOG_ERROR_UHT(TEXT("Found more than one edit/visibility specifier (%s), only one is allowed"), *Specifier.Key); } Flags |= CPF_Edit | CPF_EditConst | CPF_DisableEditOnInstance; bSeenEditSpecifier = true; @@ -3090,50 +3234,84 @@ void FHeaderParser::GetVarType( case EVariableSpecifier::BlueprintReadWrite: { - if (bSeenBlueprintEditSpecifier) + if (bSeenBlueprintReadOnlySpecifier) { - FError::Throwf(TEXT("Found more than one Blueprint read/write specifier (%s), only one is allowed"), *Specifier.Key); + UE_LOG_ERROR_UHT(TEXT("Cannot specify a property as being both BlueprintReadOnly and BlueprintReadWrite.")); } const FString* PrivateAccessMD = MetaDataFromNewStyle.Find(TEXT("AllowPrivateAccess")); // FBlueprintMetadata::MD_AllowPrivateAccess const bool bAllowPrivateAccess = PrivateAccessMD ? (*PrivateAccessMD == TEXT("true")) : false; if (CurrentAccessSpecifier == ACCESS_Private && !bAllowPrivateAccess) { - FError::Throwf(TEXT("BlueprintReadWrite should not be used on private members")); + UE_LOG_ERROR_UHT(TEXT("BlueprintReadWrite should not be used on private members")); } if ((Flags & CPF_EditorOnly) != 0 && OwnerStruct->IsA()) { - FError::Throwf(TEXT("Blueprint exposed struct members cannot be editor only")); + UE_LOG_ERROR_UHT(TEXT("Blueprint exposed struct members cannot be editor only")); } Flags |= CPF_BlueprintVisible; - bSeenBlueprintEditSpecifier = true; + bSeenBlueprintWriteSpecifier = true; } + break; + + case EVariableSpecifier::BlueprintSetter: + { + if (bSeenBlueprintReadOnlySpecifier) + { + UE_LOG_ERROR_UHT(TEXT("Cannot specify a property as being both BlueprintReadOnly and having a BlueprintSetter.")); + } + + if (OwnerStruct->IsA()) + { + UE_LOG_ERROR_UHT(TEXT("Cannot specify BlueprintSetter for a struct member.")) + } + + const FString BlueprintSetterFunction = RequireExactlyOneSpecifierValue(Specifier); + MetaDataFromNewStyle.Add(TEXT("BlueprintSetter"), BlueprintSetterFunction); + + Flags |= CPF_BlueprintVisible; + bSeenBlueprintWriteSpecifier = true; } break; case EVariableSpecifier::BlueprintReadOnly: { - if (bSeenBlueprintEditSpecifier) + if (bSeenBlueprintWriteSpecifier) { - FError::Throwf(TEXT("Found more than one Blueprint read/write specifier (%s), only one is allowed"), *Specifier.Key); + UE_LOG_ERROR_UHT(TEXT("Cannot specify both BlueprintReadOnly and BlueprintReadWrite or BlueprintSetter."), *Specifier.Key); } const FString* PrivateAccessMD = MetaDataFromNewStyle.Find(TEXT("AllowPrivateAccess")); // FBlueprintMetadata::MD_AllowPrivateAccess const bool bAllowPrivateAccess = PrivateAccessMD ? (*PrivateAccessMD == TEXT("true")) : false; if (CurrentAccessSpecifier == ACCESS_Private && !bAllowPrivateAccess) { - FError::Throwf(TEXT("BlueprintReadOnly should not be used on private members")); + UE_LOG_ERROR_UHT(TEXT("BlueprintReadOnly should not be used on private members")); } if ((Flags & CPF_EditorOnly) != 0 && OwnerStruct->IsA()) { - FError::Throwf(TEXT("Blueprint exposed struct members cannot be editor only")); + UE_LOG_ERROR_UHT(TEXT("Blueprint exposed struct members cannot be editor only")); } Flags |= CPF_BlueprintVisible | CPF_BlueprintReadOnly; ImpliedFlags &= ~CPF_BlueprintReadOnly; - bSeenBlueprintEditSpecifier = true; + bSeenBlueprintReadOnlySpecifier = true; + } + break; + + case EVariableSpecifier::BlueprintGetter: + { + if (OwnerStruct->IsA()) + { + UE_LOG_ERROR_UHT(TEXT("Cannot specify BlueprintGetter for a struct member.")) + } + + const FString BlueprintGetterFunction = RequireExactlyOneSpecifierValue(Specifier); + MetaDataFromNewStyle.Add(TEXT("BlueprintGetter"), BlueprintGetterFunction); + + Flags |= CPF_BlueprintVisible; + bSeenBlueprintGetterSpecifier = true; } break; @@ -3151,7 +3329,7 @@ void FHeaderParser::GetVarType( case EVariableSpecifier::Localized: { - FError::Throwf(TEXT("The Localized specifier is deprecated")); + UE_LOG_ERROR_UHT(TEXT("The Localized specifier is deprecated")); } break; @@ -3194,7 +3372,7 @@ void FHeaderParser::GetVarType( case EVariableSpecifier::EditInline: { - FError::Throwf(TEXT("EditInline is deprecated. Remove it, or use Instanced instead.")); + UE_LOG_ERROR_UHT(TEXT("EditInline is deprecated. Remove it, or use Instanced instead.")); } break; @@ -3215,7 +3393,7 @@ void FHeaderParser::GetVarType( { if (OwnerStruct->IsA()) { - FError::Throwf(TEXT("Struct members cannot be replicated")); + UE_LOG_ERROR_UHT(TEXT("Struct members cannot be replicated")); } Flags |= CPF_Net; @@ -3233,7 +3411,7 @@ void FHeaderParser::GetVarType( { if (!OwnerStruct->IsA()) { - FError::Throwf(TEXT("Only Struct members can be marked NotReplicated")); + UE_LOG_ERROR_UHT(TEXT("Only Struct members can be marked NotReplicated")); } Flags |= CPF_RepSkip; @@ -3242,7 +3420,7 @@ void FHeaderParser::GetVarType( case EVariableSpecifier::RepRetry: { - FError::Throwf(TEXT("'RepRetry' is deprecated.")); + UE_LOG_ERROR_UHT(TEXT("'RepRetry' is deprecated.")); } break; @@ -3317,7 +3495,7 @@ void FHeaderParser::GetVarType( default: { - FError::Throwf(TEXT("Unknown variable specifier '%s'"), *Specifier.Key); + UE_LOG_ERROR_UHT(TEXT("Unknown variable specifier '%s'"), *Specifier.Key); } break; } @@ -3347,20 +3525,28 @@ void FHeaderParser::GetVarType( } else { - FError::Throwf(TEXT("Only parameters in service request functions can be marked NotReplicated")); + UE_LOG_ERROR_UHT(TEXT("Only parameters in service request functions can be marked NotReplicated")); } } break; default: { - FError::Throwf(TEXT("Unknown variable specifier '%s'"), *Specifier.Key); + UE_LOG_ERROR_UHT(TEXT("Unknown variable specifier '%s'"), *Specifier.Key); } break; } } } + // If we saw a BlueprintGetter but did not see BlueprintSetter or + // or BlueprintReadWrite then treat as BlueprintReadOnly + if (bSeenBlueprintGetterSpecifier && !bSeenBlueprintWriteSpecifier) + { + Flags |= CPF_BlueprintReadOnly; + ImpliedFlags &= ~CPF_BlueprintReadOnly; + } + { const FString* ExposeOnSpawnStr = MetaDataFromNewStyle.Find(TEXT("ExposeOnSpawn")); const bool bExposeOnSpawn = (NULL != ExposeOnSpawnStr); @@ -3519,7 +3705,7 @@ void FHeaderParser::GetVarType( { if (IsBitfieldProperty()) { - FError::Throwf(TEXT("bool bitfields are not supported.")); + UE_LOG_ERROR_UHT(TEXT("bool bitfields are not supported.")); } // C++ bool type VarProperty = FPropertyBase(CPT_Bool); @@ -4011,7 +4197,7 @@ void FHeaderParser::GetVarType( bHandledType = true; bool bAllowWeak = !(Disallow & CPF_AutoWeak); // if it is not allowing anything, force it strong. this is probably a function arg - VarProperty = FPropertyBase( TempClass, NULL, bAllowWeak, bIsWeak, bWeakIsAuto, bIsLazy, bIsAsset ); + VarProperty = FPropertyBase( TempClass, bAllowWeak && bIsWeak, bWeakIsAuto, bIsLazy, bIsAsset ); if (TempClass->IsChildOf(UClass::StaticClass())) { if ( MatchSymbol(TEXT("<")) ) @@ -4067,6 +4253,12 @@ void FHeaderParser::GetVarType( RequireSymbol(TEXT("*"), TEXT("Expected a pointer type")); + // Swallow trailing 'const' after pointer properties + if (VariableCategory == EVariableCategory::Member) + { + MatchIdentifier(TEXT("const")); + } + VarProperty.PointerType = EPointerType::Native; } @@ -4226,7 +4418,7 @@ void FHeaderParser::GetVarType( } } - if ( VarProperty.IsObject() && VarProperty.MetaClass == NULL && (VarProperty.PropertyFlags&CPF_Config) != 0 ) + if ( VarProperty.IsObject() && VarProperty.Type != CPT_AssetObjectReference && VarProperty.MetaClass == nullptr && (VarProperty.PropertyFlags&CPF_Config) != 0 ) { FError::Throwf(TEXT("Not allowed to use 'config' with object variables")); } @@ -4650,6 +4842,8 @@ UProperty* FHeaderParser::GetVarNameAndDim } VarProperty.TokenProperty = NewProperty; + VarProperty.StartLine = InputLine; + VarProperty.StartPos = InputPos; FClassMetaData* ScopeData = GScriptHelper.FindClassData(Scope); check(ScopeData); ScopeData->AddProperty(VarProperty, UHTMakefile, CurrentSrcFile); @@ -5575,8 +5769,10 @@ bool FHeaderParser::IsValidDelegateDeclaration(const FToken& Token) const void FHeaderParser::ParseParameterList(FClasses& AllClasses, UFunction* Function, bool bExpectCommaBeforeName, TMap* MetaData) { // Get parameter list. - if ( MatchSymbol(TEXT(")")) ) + if (MatchSymbol(TEXT(")"))) + { return; + } FAdvancedDisplayParameterHandler AdvancedDisplay(MetaData); do @@ -5607,27 +5803,41 @@ void FHeaderParser::ParseParameterList(FClasses& AllClasses, UFunction* Function if (!(Function->FunctionFlags & FUNC_NetRequest)) { if (Property.PropertyFlags & CPF_OutParm) - FError::Throwf(TEXT("Replicated functions cannot contain out parameters")); + { + UE_LOG_ERROR_UHT(TEXT("Replicated functions cannot contain out parameters")); + } if (Property.PropertyFlags & CPF_RepSkip) - FError::Throwf(TEXT("Only service request functions cannot contain NoReplication parameters")); + { + UE_LOG_ERROR_UHT(TEXT("Only service request functions cannot contain NoReplication parameters")); + } if ((Prop->GetClass()->ClassCastFlags & CASTCLASS_UDelegateProperty) != 0) - FError::Throwf(TEXT("Replicated functions cannot contain delegate parameters (this would be insecure)")); + { + UE_LOG_ERROR_UHT(TEXT("Replicated functions cannot contain delegate parameters (this would be insecure)")); + } if (Property.Type == CPT_String && Property.RefQualifier != ERefQualifier::ConstRef && Prop->ArrayDim == 1) - FError::Throwf(TEXT("Replicated FString parameters must be passed by const reference")); + { + UE_LOG_ERROR_UHT(TEXT("Replicated FString parameters must be passed by const reference")); + } if (Property.ArrayType == EArrayType::Dynamic && Property.RefQualifier != ERefQualifier::ConstRef && Prop->ArrayDim == 1) - FError::Throwf(TEXT("Replicated TArray parameters must be passed by const reference")); + { + UE_LOG_ERROR_UHT(TEXT("Replicated TArray parameters must be passed by const reference")); + } } else { if (!(Property.PropertyFlags & CPF_RepSkip) && (Property.PropertyFlags & CPF_OutParm)) - FError::Throwf(TEXT("Service request functions cannot contain out parameters, unless marked NotReplicated")); + { + UE_LOG_ERROR_UHT(TEXT("Service request functions cannot contain out parameters, unless marked NotReplicated")); + } if (!(Property.PropertyFlags & CPF_RepSkip) && (Prop->GetClass()->ClassCastFlags & CASTCLASS_UDelegateProperty) != 0) - FError::Throwf(TEXT("Service request functions cannot contain delegate parameters, unless marked NotReplicated")); + { + UE_LOG_ERROR_UHT(TEXT("Service request functions cannot contain delegate parameters, unless marked NotReplicated")); + } } } if ((Function->FunctionFlags & (FUNC_BlueprintEvent|FUNC_BlueprintCallable)) != 0) @@ -5729,13 +5939,15 @@ UDelegateFunction* FHeaderParser::CompileDelegateDeclaration(FClasses& AllClasse TArray SpecifiersFound; ReadSpecifierSetInsideMacro(SpecifiersFound, TEXT("Delegate"), MetaData); - ProcessFunctionSpecifiers(FuncInfo, SpecifiersFound); + ProcessFunctionSpecifiers(FuncInfo, SpecifiersFound, MetaData); // Get the next token and ensure it looks like a delegate FToken Token; GetToken(Token); if (!IsValidDelegateDeclaration(Token)) + { FError::Throwf(TEXT("Unexpected token following UDELEGATE(): %s"), Token.Identifier); + } DelegateMacro = Token.Identifier; @@ -5773,7 +5985,7 @@ UDelegateFunction* FHeaderParser::CompileDelegateDeclaration(FClasses& AllClasse // Multi-cast delegate function signatures are not allowed to have a return value if (bHasReturnValue && bIsMulticast) { - FError::Throwf(TEXT("Multi-cast delegates function signatures must not return a value")); + UE_LOG_ERROR_UHT(TEXT("Multi-cast delegates function signatures must not return a value")); } // Delegate signature @@ -5913,6 +6125,80 @@ UDelegateFunction* FHeaderParser::CompileDelegateDeclaration(FClasses& AllClasse return DelegateSignatureFunction; } +// Compares the properties of two functions to see if they have the same signature. +bool AreFunctionSignaturesEqual(const UFunction* Lhs, const UFunction* Rhs) +{ + auto LhsPropIter = TFieldIterator(Lhs); + auto RhsPropIter = TFieldIterator(Rhs); + + for (;;) + { + bool bEndOfLhsFunction = !LhsPropIter; + bool bEndOfRhsFunction = !RhsPropIter; + + if (bEndOfLhsFunction != bEndOfRhsFunction) + { + // The functions have different numbers of parameters + return false; + } + + if (bEndOfLhsFunction) + { + // We've compared all the parameters + return true; + } + + const UProperty* LhsProp = *LhsPropIter; + const UProperty* RhsProp = *RhsPropIter; + + const UClass* LhsClass = LhsProp->GetClass(); + const UClass* RhsClass = RhsProp->GetClass(); + + if (LhsClass != RhsClass) + { + // The properties have different types + return false; + } + + if (LhsClass == UArrayProperty::StaticClass()) + { + const UArrayProperty* LhsArrayProp = (const UArrayProperty*)LhsProp; + const UArrayProperty* RhsArrayProp = (const UArrayProperty*)RhsProp; + + if (LhsArrayProp->Inner->GetClass() != RhsArrayProp->Inner->GetClass()) + { + // The properties are arrays of different types + return false; + } + } + else if (LhsClass == UMapProperty::StaticClass()) + { + const UMapProperty* LhsMapProp = (const UMapProperty*)LhsProp; + const UMapProperty* RhsMapProp = (const UMapProperty*)RhsProp; + + if (LhsMapProp->KeyProp->GetClass() != RhsMapProp->KeyProp->GetClass() || LhsMapProp->ValueProp->GetClass() != RhsMapProp->ValueProp->GetClass()) + { + // The properties are maps of different types + return false; + } + } + else if (LhsClass == USetProperty::StaticClass()) + { + const USetProperty* LhsSetProp = (const USetProperty*)LhsProp; + const USetProperty* RhsSetProp = (const USetProperty*)RhsProp; + + if (LhsSetProp->ElementProp->GetClass() != RhsSetProp->ElementProp->GetClass()) + { + // The properties are sets of different types + return false; + } + } + + ++LhsPropIter; + ++RhsPropIter; + } +} + /** * Parses and compiles a function declaration */ @@ -5984,7 +6270,12 @@ void FHeaderParser::CompileFunctionDeclaration(FClasses& AllClasses) FuncInfo.FunctionFlags |= FUNC_Event; } - ProcessFunctionSpecifiers(FuncInfo, SpecifiersFound); + if (CompilerDirectiveStack.Num() > 0 && (CompilerDirectiveStack.Last()&ECompilerDirective::WithEditor) != 0) + { + FuncInfo.FunctionFlags |= FUNC_EditorOnly; + } + + ProcessFunctionSpecifiers(FuncInfo, SpecifiersFound, MetaData); const bool bClassGeneratedFromBP = FClass::IsDynamic(GetCurrentClass()); if ((FuncInfo.FunctionFlags & FUNC_NetServer) && !(FuncInfo.FunctionFlags & FUNC_NetValidate) && !bClassGeneratedFromBP) @@ -6000,7 +6291,7 @@ void FHeaderParser::CompileFunctionDeclaration(FClasses& AllClasses) if ((FuncInfo.FunctionFlags & FUNC_BlueprintPure) && GetCurrentClass()->HasAnyClassFlags(CLASS_Interface)) { // Until pure interface casts are supported, we don't allow pures in interfaces - FError::Throwf(TEXT("BlueprintPure specifier is not allowed for interface functions")); + UE_LOG_ERROR_UHT(TEXT("BlueprintPure specifier is not allowed for interface functions")); } if (FuncInfo.FunctionFlags & FUNC_Net) @@ -6024,14 +6315,16 @@ void FHeaderParser::CompileFunctionDeclaration(FClasses& AllClasses) } FString* InternalPtr = MetaData.Find("BlueprintInternalUseOnly"); // FBlueprintMetadata::MD_BlueprintInternalUseOnly - const bool bDeprecated = MetaData.Contains("DeprecatedFunction"); // FBlueprintMetadata::MD_DeprecatedFunction - const bool bHasMenuCategory = MetaData.Contains("Category"); // FBlueprintMetadata::MD_FunctionCategory const bool bInternalOnly = InternalPtr && *InternalPtr == TEXT("true"); // If this function is blueprint callable or blueprint pure, require a category if ((FuncInfo.FunctionFlags & (FUNC_BlueprintCallable | FUNC_BlueprintPure)) != 0) { - if (!bHasMenuCategory && !bInternalOnly && !bDeprecated) + const bool bDeprecated = MetaData.Contains("DeprecatedFunction"); // FBlueprintMetadata::MD_DeprecatedFunction + const bool bBlueprintAccessor = MetaData.Contains("BlueprintSetter") || MetaData.Contains("BlueprintGetter"); // FBlueprintMetadata::MD_BlueprintSetter, // FBlueprintMetadata::MD_BlueprintGetter + const bool bHasMenuCategory = MetaData.Contains("Category"); // FBlueprintMetadata::MD_FunctionCategory + + if (!bHasMenuCategory && !bInternalOnly && !bDeprecated && !bBlueprintAccessor) { const bool bModuleIsGame = CurrentlyParsedModule && ( CurrentlyParsedModule->ModuleType == EBuildModuleType::GameDeveloper || @@ -6042,7 +6335,7 @@ void FHeaderParser::CompileFunctionDeclaration(FClasses& AllClasses) // To allow for quick iteration, don't enforce the requirement that game functions have to be categorized if (!bModuleIsGame) { - FError::Throwf(TEXT("Blueprint accessible functions must have a category specified")); + UE_LOG_ERROR_UHT(TEXT("Blueprint accessible functions must have a category specified")); } } } @@ -6056,7 +6349,7 @@ void FHeaderParser::CompileFunctionDeclaration(FClasses& AllClasses) // Ensure that blueprint events are only allowed in implementable interfaces. Internal only functions allowed if (!bCanImplementInBlueprints && !bInternalOnly) { - FError::Throwf(TEXT("Interfaces that are not implementable in blueprints cannot have BlueprintImplementableEvent members.")); + UE_LOG_ERROR_UHT(TEXT("Interfaces that are not implementable in blueprints cannot have BlueprintImplementableEvent members.")); } } @@ -6065,7 +6358,7 @@ void FHeaderParser::CompileFunctionDeclaration(FClasses& AllClasses) // Ensure that if this interface contains blueprint callable functions that are not blueprint defined, that it must be implemented natively if (bCanImplementInBlueprints) { - FError::Throwf(TEXT("Blueprint implementable interfaces cannot contain BlueprintCallable functions that are not BlueprintImplementableEvents. Use CannotImplementInterfaceInBlueprint on the interface if you wish to keep this function.")); + UE_LOG_ERROR_UHT(TEXT("Blueprint implementable interfaces cannot contain BlueprintCallable functions that are not BlueprintImplementableEvents. Use CannotImplementInterfaceInBlueprint on the interface if you wish to keep this function.")); } } } @@ -6123,7 +6416,7 @@ void FHeaderParser::CompileFunctionDeclaration(FClasses& AllClasses) // if this is a BlueprintNativeEvent, make sure it's not "virtual" else if (FuncInfo.FunctionFlags & FUNC_Native) { - FError::Throwf(TEXT("BlueprintNativeEvent functions must be non-virtual.")); + UE_LOG_ERROR_UHT(TEXT("BlueprintNativeEvent functions must be non-virtual.")); } else @@ -6150,7 +6443,7 @@ void FHeaderParser::CompileFunctionDeclaration(FClasses& AllClasses) if (GetCurrentClass()->HasAnyClassFlags(CLASS_Interface)) { - FError::Throwf(TEXT("Interface functions cannot be declared 'final'")); + UE_LOG_ERROR_UHT(TEXT("Interface functions cannot be declared 'final'")); } } @@ -6184,12 +6477,16 @@ void FHeaderParser::CompileFunctionDeclaration(FClasses& AllClasses) { bool bIsNetService = !!(FuncInfo.FunctionFlags & (FUNC_NetRequest | FUNC_NetResponse)); if (bHasReturnValue && !bIsNetService) + { FError::Throwf(TEXT("Replicated functions can't have return values")); + } if (FuncInfo.RPCId > 0) { if (FString* ExistingFunc = UsedRPCIds.Find(FuncInfo.RPCId)) + { FError::Throwf(TEXT("Function %s already uses identifier %d"), **ExistingFunc, FuncInfo.RPCId); + } UsedRPCIds.Add(FuncInfo.RPCId, FuncInfo.Function.Identifier); if (FuncInfo.FunctionFlags & FUNC_NetResponse) @@ -6248,7 +6545,7 @@ void FHeaderParser::CompileFunctionDeclaration(FClasses& AllClasses) // determine if there are any outputs for this function bool bHasAnyOutputs = bHasReturnValue; - if (bHasAnyOutputs == false) + if (!bHasAnyOutputs) { for (TFieldIterator It(TopFunction); It; ++It) { @@ -6260,13 +6557,31 @@ void FHeaderParser::CompileFunctionDeclaration(FClasses& AllClasses) } } } - if ( (bHasAnyOutputs == false) && (FuncInfo.FunctionFlags & (FUNC_BlueprintPure)) ) + + // Check to see if there is a function in the super class with the same name but a different signature + UStruct* SuperStruct = GetCurrentClass(); + if (SuperStruct) + { + SuperStruct = SuperStruct->GetSuperStruct(); + } + if (SuperStruct) + { + if (UFunction* OverriddenFunction = ::FindField(SuperStruct, FuncInfo.Function.Identifier)) + { + if (!AreFunctionSignaturesEqual(TopFunction, OverriddenFunction)) + { + FError::Throwf(TEXT("Function '%s' has a different signature from the one defined in base class '%s'"), FuncInfo.Function.Identifier, *OverriddenFunction->GetOuter()->GetName()); + } + } + } + + if (!bHasAnyOutputs && (FuncInfo.FunctionFlags & (FUNC_BlueprintPure))) { // This bad behavior would be treated as a warning in the Blueprint editor, so when converted assets generates these bad functions // we don't want to prevent compilation: if (!bClassGeneratedFromBP) { - FError::Throwf(TEXT("BlueprintPure specifier is not allowed for functions with no return value and no output parameters.")); + UE_LOG_ERROR_UHT(TEXT("BlueprintPure specifier is not allowed for functions with no return value and no output parameters.")); } } @@ -6482,7 +6797,9 @@ void FHeaderParser::CompileFunctionDeclaration(FClasses& AllClasses) if (!IsPropertySupportedByBlueprint(Param, false)) { - FError::Throwf(TEXT("Type '%s' is not supported by blueprint. Function: %s Parameter %s\n"), *Param->GetCPPType(), *TopFunction->GetName(), *Param->GetName()); + FString ExtendedCPPType; + FString CPPType = Param->GetCPPType(&ExtendedCPPType); + UE_LOG_ERROR_UHT(TEXT("Type '%s%s' is not supported by blueprint. %s.%s"), *CPPType, *ExtendedCPPType, *TopFunction->GetName(), *Param->GetName()); } } } @@ -6619,7 +6936,7 @@ void FHeaderParser::ValidatePropertyIsDeprecatedIfNecessary(FPropertyBase& VarPr if ( VarProperty.MetaClass != NULL && VarProperty.MetaClass->HasAnyClassFlags(CLASS_Deprecated) && !(VarProperty.PropertyFlags & CPF_Deprecated) && (OuterPropertyType == NULL || !(OuterPropertyType->PropertyFlags & CPF_Deprecated)) ) { - FError::Throwf(TEXT("Property is using a deprecated class: %s. Property should be marked deprecated as well."), *VarProperty.MetaClass->GetPathName()); + UE_LOG_ERROR_UHT(TEXT("Property is using a deprecated class: %s. Property should be marked deprecated as well."), *VarProperty.MetaClass->GetPathName()); } // check to see if we have a UObjectProperty using a deprecated class. @@ -6629,7 +6946,7 @@ void FHeaderParser::ValidatePropertyIsDeprecatedIfNecessary(FPropertyBase& VarPr && (VarProperty.PropertyFlags&CPF_Deprecated) == 0 // and this property isn't marked deprecated as well && (OuterPropertyType == NULL || !(OuterPropertyType->PropertyFlags & CPF_Deprecated)) ) // and this property isn't in an array that was marked deprecated either { - FError::Throwf(TEXT("Property is using a deprecated class: %s. Property should be marked deprecated as well."), *VarProperty.PropertyClass->GetPathName()); + UE_LOG_ERROR_UHT(TEXT("Property is using a deprecated class: %s. Property should be marked deprecated as well."), *VarProperty.PropertyClass->GetPathName()); } } @@ -6649,8 +6966,6 @@ struct FExposeOnSpawnValidator case CPT_String: case CPT_Text: case CPT_Name: - case CPT_Vector: - case CPT_Rotation: case CPT_Interface: ProperNativeType = true; } @@ -6691,7 +7006,7 @@ void FHeaderParser::CompileVariableDeclaration(FClasses& AllClasses, UStruct* St } else { - FError::Throwf(TEXT("Property is exposed to the editor or blueprints but has no Category specified.")); + UE_LOG_ERROR_UHT(TEXT("Property is exposed to the editor or blueprints but has no Category specified.")); } } @@ -6706,7 +7021,7 @@ void FHeaderParser::CompileVariableDeclaration(FClasses& AllClasses, UStruct* St // If the category was specified explicitly, it wins if (Category && !(OriginalProperty.PropertyFlags & (CPF_Edit|CPF_BlueprintVisible|CPF_BlueprintAssignable|CPF_BlueprintCallable))) { - FError::Throwf(TEXT("Property has a Category set but is not exposed to the editor or Blueprints with EditAnywhere, BlueprintReadWrite, VisibleAnywhere, BlueprintReadOnly, BlueprintAssignable, BlueprintCallable keywords.\r\n")); + UE_LOG_WARNING_UHT(TEXT("Property has a Category set but is not exposed to the editor or Blueprints with EditAnywhere, BlueprintReadWrite, VisibleAnywhere, BlueprintReadOnly, BlueprintAssignable, BlueprintCallable keywords.\r\n")); } // Make sure that editblueprint variables are editable @@ -6714,12 +7029,12 @@ void FHeaderParser::CompileVariableDeclaration(FClasses& AllClasses, UStruct* St { if (OriginalProperty.PropertyFlags & CPF_DisableEditOnInstance) { - FError::Throwf(TEXT("Property cannot have 'DisableEditOnInstance' without being editable")); + UE_LOG_ERROR_UHT(TEXT("Property cannot have 'DisableEditOnInstance' without being editable")); } if (OriginalProperty.PropertyFlags & CPF_DisableEditOnTemplate) { - FError::Throwf(TEXT("Property cannot have 'DisableEditOnTemplate' without being editable")); + UE_LOG_ERROR_UHT(TEXT("Property cannot have 'DisableEditOnTemplate' without being editable")); } } @@ -6733,7 +7048,7 @@ void FHeaderParser::CompileVariableDeclaration(FClasses& AllClasses, UStruct* St { if ((*ExposeOnSpawnValue == TEXT("true")) && !FExposeOnSpawnValidator::IsSupported(OriginalProperty)) { - FError::Throwf(TEXT("ExposeOnSpawn - Property cannot be exposed")); + UE_LOG_ERROR_UHT(TEXT("ExposeOnSpawn - Property cannot be exposed")); } } @@ -6782,14 +7097,24 @@ void FHeaderParser::CompileVariableDeclaration(FClasses& AllClasses, UStruct* St } } - if (NewProperty->HasAnyPropertyFlags(CPF_BlueprintVisible) && (NewProperty->ArrayDim > 1)) + if (NewProperty->HasAnyPropertyFlags(CPF_BlueprintVisible)) { - FError::Throwf(TEXT("Static array cannot be exposed to blueprint %s.%s"), *Struct->GetName(), *NewProperty->GetName()); - } + if (Struct->IsA() && !Struct->GetBoolMetaDataHierarchical(TEXT("BlueprintType"))) + { + UE_LOG_ERROR_UHT(TEXT("Cannot expose property to blueprints in a struct that is not a BlueprintType. %s.%s"), *Struct->GetName(), *NewProperty->GetName()); + } - if (NewProperty->HasAnyPropertyFlags(CPF_BlueprintVisible) && !IsPropertySupportedByBlueprint(NewProperty, true)) - { - FError::Throwf(TEXT("Type '%s' is not supported by blueprint. %s.%s"), *NewProperty->GetCPPType(), *Struct->GetName(), *NewProperty->GetName()); + if (NewProperty->ArrayDim > 1) + { + UE_LOG_ERROR_UHT(TEXT("Static array cannot be exposed to blueprint %s.%s"), *Struct->GetName(), *NewProperty->GetName()); + } + + if (!IsPropertySupportedByBlueprint(NewProperty, true)) + { + FString ExtendedCPPType; + FString CPPType = NewProperty->GetCPPType(&ExtendedCPPType); + UE_LOG_ERROR_UHT(TEXT("Type '%s%s' is not supported by blueprint. %s.%s"), *CPPType, *ExtendedCPPType, *Struct->GetName(), *NewProperty->GetName()); + } } } while( MatchSymbol(TEXT(",")) ); @@ -6812,6 +7137,26 @@ void FHeaderParser::CompileVariableDeclaration(FClasses& AllClasses, UStruct* St // Expect a semicolon. RequireSymbol( TEXT(";"), TEXT("'variable declaration'") ); + + // Skip redundant semi-colons + for (;;) + { + int32 CurrInputPos = InputPos; + int32 CurrInputLine = InputLine; + + FToken Token; + if (!GetToken(Token, /*bNoConsts=*/ true)) + { + break; + } + + if (Token.TokenType != TOKEN_Symbol || FCString::Stricmp(Token.Identifier, TEXT(";"))) + { + InputPos = CurrInputPos; + InputLine = CurrInputLine; + break; + } + } } // @@ -7895,7 +8240,7 @@ void FHeaderParser::SimplifiedClassParse(const TCHAR* Filename, const TCHAR* InB { if (bFoundGeneratedInclude) { - FError::Throwf(TEXT("#include found after .generated.h file - the .generated.h file should always be the last #include in a header")); + UE_LOG_ERROR_UHT(TEXT("#include found after .generated.h file - the .generated.h file should always be the last #include in a header")); } // Handle #include directives as if they were 'dependson' keywords. @@ -8025,30 +8370,46 @@ void FHeaderParser::SimplifiedClassParse(const TCHAR* Filename, const TCHAR* InB Str = *StrLine; // Get class or interface name - if (const TCHAR* UInterfaceMacroDecl = FCString::Strfind(Str, TEXT("UINTERFACE("))) + if (const TCHAR* UInterfaceMacroDecl = FCString::Strfind(Str, TEXT("UINTERFACE"))) { - FName StrippedInterfaceName; - Parser.ParseClassDeclaration(Filename, StartOfLine + (UInterfaceMacroDecl - Str), CurrentLine, TEXT("UINTERFACE"), /*out*/ StrippedInterfaceName, /*out*/ ClassName, /*out*/ BaseClassName, /*out*/ DependentOn, OutParsedClassArray); - OutParsedClassArray.Add(FSimplifiedParsingClassInfo(MoveTemp(ClassName), MoveTemp(BaseClassName), CurrentLine, true)); - if (!bFoundExportedClasses) + if (UInterfaceMacroDecl == FCString::Strspn(Str, TEXT("\t ")) + Str) { - if (const TSharedRef* Found = GClassDeclarations.Find(StrippedInterfaceName)) + if (UInterfaceMacroDecl[10] != TEXT('(')) { - bFoundExportedClasses = !((*Found)->ClassFlags & CLASS_NoExport); + FFileLineException::Throwf(Filename, CurrentLine, TEXT("Missing open parenthesis after UINTERFACE")); + } + + FName StrippedInterfaceName; + Parser.ParseClassDeclaration(Filename, StartOfLine + (UInterfaceMacroDecl - Str), CurrentLine, TEXT("UINTERFACE"), /*out*/ StrippedInterfaceName, /*out*/ ClassName, /*out*/ BaseClassName, /*out*/ DependentOn, OutParsedClassArray); + OutParsedClassArray.Add(FSimplifiedParsingClassInfo(MoveTemp(ClassName), MoveTemp(BaseClassName), CurrentLine, true)); + if (!bFoundExportedClasses) + { + if (const TSharedRef* Found = GClassDeclarations.Find(StrippedInterfaceName)) + { + bFoundExportedClasses = !((*Found)->ClassFlags & CLASS_NoExport); + } } } } - if (const TCHAR* UClassMacroDecl = FCString::Strfind(Str, TEXT("UCLASS("))) + if (const TCHAR* UClassMacroDecl = FCString::Strfind(Str, TEXT("UCLASS"))) { - FName StrippedClassName; - Parser.ParseClassDeclaration(Filename, StartOfLine + (UClassMacroDecl - Str), CurrentLine, TEXT("UCLASS"), /*out*/ StrippedClassName, /*out*/ ClassName, /*out*/ BaseClassName, /*out*/ DependentOn, OutParsedClassArray); - OutParsedClassArray.Add(FSimplifiedParsingClassInfo(MoveTemp(ClassName), MoveTemp(BaseClassName), CurrentLine, false)); - if (!bFoundExportedClasses) + if (UClassMacroDecl == FCString::Strspn(Str, TEXT("\t ")) + Str) { - if (const TSharedRef* Found = GClassDeclarations.Find(StrippedClassName)) + if (UClassMacroDecl[6] != TEXT('(')) { - bFoundExportedClasses = !((*Found)->ClassFlags & CLASS_NoExport); + FFileLineException::Throwf(Filename, CurrentLine, TEXT("Missing open parenthesis after UCLASS")); + } + + FName StrippedClassName; + Parser.ParseClassDeclaration(Filename, StartOfLine + (UClassMacroDecl - Str), CurrentLine, TEXT("UCLASS"), /*out*/ StrippedClassName, /*out*/ ClassName, /*out*/ BaseClassName, /*out*/ DependentOn, OutParsedClassArray); + OutParsedClassArray.Add(FSimplifiedParsingClassInfo(MoveTemp(ClassName), MoveTemp(BaseClassName), CurrentLine, false)); + if (!bFoundExportedClasses) + { + if (const TSharedRef* Found = GClassDeclarations.Find(StrippedClassName)) + { + bFoundExportedClasses = !((*Found)->ClassFlags & CLASS_NoExport); + } } } } @@ -8059,7 +8420,7 @@ void FHeaderParser::SimplifiedClassParse(const TCHAR* Filename, const TCHAR* InB if (bFoundExportedClasses && !bFoundGeneratedInclude) { - FError::Throwf(TEXT("No #include found for the .generated.h file - the .generated.h file should always be the last #include in a header")); + UE_LOG_ERROR_UHT(TEXT("No #include found for the .generated.h file - the .generated.h file should always be the last #include in a header")); } } @@ -8652,7 +9013,7 @@ void FHeaderParser::ResetClassData() CurrentClass->ClassFlags |= (SuperClass->ClassFlags) & CLASS_ScriptInherit; CurrentClass->ClassConfigName = SuperClass->ClassConfigName; check(SuperClass->ClassWithin); - if (CurrentClass->ClassWithin == NULL) + if (CurrentClass->ClassWithin == nullptr) { CurrentClass->ClassWithin = SuperClass->ClassWithin; } @@ -8686,7 +9047,7 @@ void FHeaderParser::ResetClassData() void FHeaderParser::PostPopNestClass(UClass* CurrentClass) { // Validate all the rep notify events here, to make sure they're implemented - VerifyRepNotifyCallbacks(CurrentClass); + VerifyPropertyMarkups(CurrentClass); // Iterate over all the interfaces we claim to implement for (FImplementedInterface& Impl : CurrentClass->Interfaces) @@ -8696,7 +9057,9 @@ void FHeaderParser::PostPopNestClass(UClass* CurrentClass) { // If this interface is a common ancestor, skip it if (CurrentClass->IsChildOf(Interface)) + { continue; + } // So iterate over all functions this interface declares for (UFunction* InterfaceFunction : TFieldRange(Interface, EFieldIteratorFlags::ExcludeSuper)) @@ -8707,19 +9070,27 @@ void FHeaderParser::PostPopNestClass(UClass* CurrentClass) for (UFunction* ClassFunction : TFieldRange(CurrentClass)) { if (ClassFunction->GetFName() != InterfaceFunction->GetFName()) + { continue; + } if ((InterfaceFunction->FunctionFlags & FUNC_Event) && !(ClassFunction->FunctionFlags & FUNC_Event)) - FError::Throwf(TEXT("Implementation of function '%s' must be declared as 'event' to match declaration in interface '%s'"), *ClassFunction->GetName(), *Interface->GetName()); + { + FError::Throwf(TEXT("Implementation of function '%s::%s' must be declared as 'event' to match declaration in interface '%s'"), *ClassFunction->GetOuter()->GetName(), *ClassFunction->GetName(), *Interface->GetName()); + } if ((InterfaceFunction->FunctionFlags & FUNC_Delegate) && !(ClassFunction->FunctionFlags & FUNC_Delegate)) - FError::Throwf(TEXT("Implementation of function '%s' must be declared as 'delegate' to match declaration in interface '%s'"), *ClassFunction->GetName(), *Interface->GetName()); + { + FError::Throwf(TEXT("Implementation of function '%s::%s' must be declared as 'delegate' to match declaration in interface '%s'"), *ClassFunction->GetOuter()->GetName(), *ClassFunction->GetName(), *Interface->GetName()); + } // Making sure all the parameters match up correctly Implemented = true; if (ClassFunction->NumParms != InterfaceFunction->NumParms) + { FError::Throwf(TEXT("Implementation of function '%s' conflicts with interface '%s' - different number of parameters (%i/%i)"), *InterfaceFunction->GetName(), *Interface->GetName(), ClassFunction->NumParms, InterfaceFunction->NumParms); + } int32 Count = 0; for (TFieldIterator It1(InterfaceFunction), It2(ClassFunction); Count < ClassFunction->NumParms; ++It1, ++It2, Count++) diff --git a/Engine/Source/Programs/UnrealHeaderTool/Private/HeaderParser.h b/Engine/Source/Programs/UnrealHeaderTool/Private/HeaderParser.h index 9e80b8d7f378..1e1ab00bf9b9 100644 --- a/Engine/Source/Programs/UnrealHeaderTool/Private/HeaderParser.h +++ b/Engine/Source/Programs/UnrealHeaderTool/Private/HeaderParser.h @@ -412,7 +412,7 @@ protected: // Constructor. FHeaderParser(FFeedbackContext* InWarn, FUHTMakefile& InUHTMakefile); - ~FHeaderParser() + virtual ~FHeaderParser() { if ( FScriptLocation::Compiler == this ) { @@ -690,13 +690,6 @@ protected: */ void FixupDelegateProperties(FClasses& AllClasses, UStruct* ValidationScope, FScope& Scope, TMap& DelegateCache); - /** - * Verifies that all specified class's UProperties with CFG_RepNotify have valid callback targets with no parameters nor return values - * - * @param TargetClass class to verify rep notify properties for - */ - void VerifyRepNotifyCallbacks( UClass* TargetClass ); - // Retry functions. void InitScriptLocation( FScriptLocation& Retry ); void ReturnToLocation( const FScriptLocation& Retry, bool Binary=1, bool Text=1 ); @@ -735,6 +728,18 @@ private: // Parses possible version declaration in generated code, e.g. GENERATED_BODY(). void CompileVersionDeclaration(UStruct* Struct); + + // Verifies that all specified class's UProperties with function associations have valid targets + void VerifyPropertyMarkups( UClass* TargetClass ); + + // Verifies the target function meets the criteria for a blueprint property getter + void VerifyBlueprintPropertyGetter(UProperty* Property, UFunction* TargetFunction); + + // Verifies the target function meets the criteria for a blueprint property setter + void VerifyBlueprintPropertySetter(UProperty* Property, UFunction* TargetFunction); + + // Verifies the target function meets the criteria for a replication notify callback + void VerifyRepNotifyCallback(UProperty* Property, UFunction* TargetFunction); }; ///////////////////////////////////////////////////// diff --git a/Engine/Source/Programs/UnrealHeaderTool/Private/Manifest.cpp b/Engine/Source/Programs/UnrealHeaderTool/Private/Manifest.cpp index 68da6798c61a..86f811eb080c 100644 --- a/Engine/Source/Programs/UnrealHeaderTool/Private/Manifest.cpp +++ b/Engine/Source/Programs/UnrealHeaderTool/Private/Manifest.cpp @@ -82,11 +82,12 @@ FManifest FManifest::LoadFromFile(const FString& Filename) TArray> ModulesArray; - GetJsonFieldValue(Result.IsGameTarget, RootObject, TEXT("IsGameTarget"), TEXT("{manifest root}")); - GetJsonFieldValue(Result.RootLocalPath, RootObject, TEXT("RootLocalPath"), TEXT("{manifest root}")); - GetJsonFieldValue(Result.RootBuildPath, RootObject, TEXT("RootBuildPath"), TEXT("{manifest root}")); - GetJsonFieldValue(Result.TargetName, RootObject, TEXT("TargetName"), TEXT("{manifest root}")); - GetJsonFieldValue(ModulesArray, RootObject, TEXT("Modules"), TEXT("{manifest root}")); + GetJsonFieldValue(Result.IsGameTarget, RootObject, TEXT("IsGameTarget"), TEXT("{manifest root}")); + GetJsonFieldValue(Result.RootLocalPath, RootObject, TEXT("RootLocalPath"), TEXT("{manifest root}")); + GetJsonFieldValue(Result.RootBuildPath, RootObject, TEXT("RootBuildPath"), TEXT("{manifest root}")); + GetJsonFieldValue(Result.TargetName, RootObject, TEXT("TargetName"), TEXT("{manifest root}")); + GetJsonFieldValue(Result.ExternalDependenciesFile, RootObject, TEXT("ExternalDependenciesFile"), TEXT("{manifest root}")); + GetJsonFieldValue(ModulesArray, RootObject, TEXT("Modules"), TEXT("{manifest root}")); UE_LOG(LogCompile, Log, TEXT("Loaded manifest: %s"), *Filename); UE_LOG(LogCompile, Log, TEXT("Manifest.IsGameTarget=%s"), Result.IsGameTarget ? TEXT("True") : TEXT("False")); @@ -242,7 +243,6 @@ bool FManifestModule::IsCompatibleWith(const FManifestModule& ManifestModule) && BaseDirectory == ManifestModule.BaseDirectory && IncludeBase == ManifestModule.IncludeBase && GeneratedIncludeDirectory == ManifestModule.GeneratedIncludeDirectory - && BaseDirectory == ManifestModule.BaseDirectory && PublicUObjectClassesHeaders == ManifestModule.PublicUObjectClassesHeaders && PublicUObjectHeaders == ManifestModule.PublicUObjectHeaders && PrivateUObjectHeaders == ManifestModule.PrivateUObjectHeaders diff --git a/Engine/Source/Programs/UnrealHeaderTool/Private/Manifest.h b/Engine/Source/Programs/UnrealHeaderTool/Private/Manifest.h index 84cf12cf8d1f..949d1c451c54 100644 --- a/Engine/Source/Programs/UnrealHeaderTool/Private/Manifest.h +++ b/Engine/Source/Programs/UnrealHeaderTool/Private/Manifest.h @@ -95,6 +95,7 @@ struct FManifest FString RootLocalPath; FString RootBuildPath; FString TargetName; + FString ExternalDependenciesFile; /** Ordered list of modules that define UObjects or UStructs, which we may need to generate code for. The list is in module dependency order, such that most dependent modules appear first. */ diff --git a/Engine/Source/Programs/UnrealHeaderTool/Private/NativeClassExporter.h b/Engine/Source/Programs/UnrealHeaderTool/Private/NativeClassExporter.h index 6eb783e2791a..4a9ad4932982 100644 --- a/Engine/Source/Programs/UnrealHeaderTool/Private/NativeClassExporter.h +++ b/Engine/Source/Programs/UnrealHeaderTool/Private/NativeClassExporter.h @@ -80,7 +80,7 @@ private: const UPackage* Package; /** Set of already exported cross-module references, to prevent duplicates */ - TSet UniqueCrossModuleReferences; + TSet* UniqueCrossModuleReferences; /** the existing disk version of the header for this package's names */ FString OriginalNamesHeader; @@ -113,9 +113,12 @@ private: */ static void ExportProperties(FOutputDevice& Out, UStruct* Struct, int32 TextIndent); + /** Return the name of the singleton function that returns the UObject for Item */ + FString GetPackageSingletonName(const UPackage* Item); + /** Return the name of the singleton function that returns the UObject for Item */ FString GetSingletonName(UField* Item, bool bRequiresValidObject=true); - + /** * Returns the name (overridden if marked up) with TEXT("") or "" wrappers for use in a string literal. */ @@ -177,7 +180,7 @@ private: * @param OutputGetter The function to call to get the output. * @param Enum the enum to export */ - void ExportGeneratedEnumInitCode(FOutputDevice& Out, FOutputDevice& OutDeclarations, const FUnrealSourceFile& SourceFile, UEnum* Enum); + void ExportGeneratedEnumInitCode(FOutputDevice& Out, const FUnrealSourceFile& SourceFile, UEnum* Enum); /** * Exports the macro declarations for GENERATED_BODY() for each Foo in the struct specified @@ -185,7 +188,7 @@ private: * @param Out output device * @param Struct The struct to export */ - void ExportGeneratedStructBodyMacros(FOutputDevice& OutGeneratedHeaderText, FOutputDevice& Out, FOutputDevice& OutDeclarations, const FUnrealSourceFile& SourceFile, UScriptStruct* Struct); + void ExportGeneratedStructBodyMacros(FOutputDevice& OutGeneratedHeaderText, FOutputDevice& Out, const FUnrealSourceFile& SourceFile, UScriptStruct* Struct); /** * Exports a local mirror of the specified struct; used to get offsets @@ -211,7 +214,7 @@ private: * @param SourceFile Source file of the delegate. * @param DelegateFunctions the functions that have parameters which need to be exported */ - void ExportDelegateDeclaration(FOutputDevice& Out, FOutputDevice& OutDeclarations, const FUnrealSourceFile& SourceFile, UFunction* Function); + void ExportDelegateDeclaration(FOutputDevice& Out, const FUnrealSourceFile& SourceFile, UFunction* Function); /** * Exports C++ type definitions for delegates @@ -242,7 +245,7 @@ private: /** * Exports the generated cpp file for all functions/events/delegates in package. */ - void ExportGeneratedCPP(FOutputDevice& Out, const TCHAR* EmptyLinkFunctionPostfix, const TCHAR* Declarations, const TCHAR* Body, const TCHAR* OtherIncludes); + static void ExportGeneratedCPP(FOutputDevice& Out, const TSet& InCrossModuleReferences, const TCHAR* EmptyLinkFunctionPostfix, const TCHAR* Body, const TCHAR* OtherIncludes); /** * Get the intrinsic null value for this property @@ -253,7 +256,7 @@ private: * * @return the intrinsic null value for the property (0 for ints, TEXT("") for strings, etc.) */ - static FString GetNullParameterValue( UProperty* Prop, bool bMacroContext, bool bInitializer = false ); + static FString GetNullParameterValue( UProperty* Prop, bool bInitializer = false ); /** * Exports a native function prototype @@ -302,9 +305,8 @@ private: * @param FunctionData function data for the current function * @param Parameters list of parameters in the function * @param Return return parameter for the function - * @param DeprecationWarningOutputDevice Device to output deprecation warnings for _Validate and _Implementation functions. */ - void ExportFunctionThunk(FUHTStringBuilder& RPCWrappers, UFunction* Function, const FFuncInfo& FunctionData, const TArray& Parameters, UProperty* Return, FUHTStringBuilder& DeprecationWarningOutputDevice); + void ExportFunctionThunk(FUHTStringBuilder& RPCWrappers, UFunction* Function, const FFuncInfo& FunctionData, const TArray& Parameters, UProperty* Return); /** Exports the native function registration code for the given class. */ static void ExportNatives(FOutputDevice& Out, FClass* Class); @@ -334,7 +336,7 @@ private: * @param Out The destination to write to. * @param Package Package to export code for. **/ - void ExportGeneratedPackageInitCode(FOutputDevice& Out, FUHTStringBuilder& OutDeclarations, const UPackage* Package, uint32 CRC); + void ExportGeneratedPackageInitCode(FOutputDevice& Out, const TCHAR* InDeclarations, const UPackage* Package, uint32 CRC); /** * Function to output the C++ code necessary to set up the given array of properties @@ -381,7 +383,6 @@ private: const TArray& CallbackFunctions, const TCHAR* CallbackWrappersMacroName, EExportCallbackType ExportCallbackType, - const TCHAR* API, const TCHAR* APIString ); diff --git a/Engine/Source/Programs/UnrealHeaderTool/Private/ParserHelper.cpp b/Engine/Source/Programs/UnrealHeaderTool/Private/ParserHelper.cpp index d720306fac07..b0cb589dd92f 100644 --- a/Engine/Source/Programs/UnrealHeaderTool/Private/ParserHelper.cpp +++ b/Engine/Source/Programs/UnrealHeaderTool/Private/ParserHelper.cpp @@ -34,7 +34,7 @@ FTokenData* FClassMetaData::FindTokenData( UProperty* Prop ) { OuterClass = Cast(Outer); - if (Result == nullptr && OuterClass != nullptr && OuterClass->GetSuperClass() != OuterClass) + if (OuterClass != nullptr && OuterClass->GetSuperClass() != OuterClass) { OuterClass = OuterClass->GetSuperClass(); } @@ -121,10 +121,7 @@ const TCHAR* FPropertyBase::GetPropertyTypeText( EPropertyType Type ) CASE_TEXT(CPT_Interface); CASE_TEXT(CPT_Name); CASE_TEXT(CPT_Delegate); - CASE_TEXT(CPT_Range); CASE_TEXT(CPT_Struct); - CASE_TEXT(CPT_Vector); - CASE_TEXT(CPT_Rotation); CASE_TEXT(CPT_String); CASE_TEXT(CPT_Text); CASE_TEXT(CPT_MulticastDelegate); diff --git a/Engine/Source/Programs/UnrealHeaderTool/Private/ParserHelper.h b/Engine/Source/Programs/UnrealHeaderTool/Private/ParserHelper.h index fa81ccd37363..910e4b2745c1 100644 --- a/Engine/Source/Programs/UnrealHeaderTool/Private/ParserHelper.h +++ b/Engine/Source/Programs/UnrealHeaderTool/Private/ParserHelper.h @@ -189,7 +189,7 @@ public: { } - explicit FPropertyBase(UClass* InClass, UClass* InMetaClass=NULL, bool bAllowWeak = false, bool bIsWeak = false, bool bWeakIsAuto = false, bool bIsLazy = false, bool bIsAsset = false) + explicit FPropertyBase(UClass* InClass, bool bIsWeak = false, bool bWeakIsAuto = false, bool bIsLazy = false, bool bIsAsset = false) : Type (CPT_ObjectReference) , ArrayType (EArrayType::None) , PropertyFlags (0) @@ -197,7 +197,7 @@ public: , RefQualifier (ERefQualifier::None) , PropertyExportFlags (PROPEXPORT_Public) , PropertyClass (InClass) - , MetaClass (InMetaClass) + , MetaClass (nullptr) , DelegateName (NAME_None) , DelegateSignatureOwnerClass(nullptr) , RepNotifyName (NAME_None) @@ -209,28 +209,6 @@ public: { Type = CPT_Interface; } - if (bAllowWeak) - { - UClass* TestClass = InClass; - while (TestClass) // inherited class flags might not yet be propagated, so lets search - { - if ( TestClass->HasAnyClassFlags(CLASS_PointersDefaultToAutoWeak) ) - { - bIsWeak = true; - bWeakIsAuto = true; - break; - } - if ( TestClass->HasAnyClassFlags(CLASS_PointersDefaultToWeak) ) - { - bIsWeak = true; - } - TestClass = TestClass->GetSuperClass(); - } - } - else - { - bIsWeak = false; - } if (bIsLazy) { Type = CPT_LazyObjectReference; @@ -786,26 +764,6 @@ public: return String; // unsupported (parsing never produces a constant token of these types) - case CPT_Vector: - case CPT_Rotation: - case CPT_Int8: - case CPT_Int16: - case CPT_UInt16: - case CPT_UInt32: - case CPT_UInt64: - case CPT_Bool8: - case CPT_Bool16: - case CPT_Bool32: - case CPT_Bool64: - case CPT_Range: - case CPT_Struct: - case CPT_ObjectReference: - case CPT_WeakObjectReference: - case CPT_LazyObjectReference: - case CPT_AssetObjectReference: - case CPT_Interface: - case CPT_Delegate: - case CPT_MulticastDelegate: default: return TEXT("InvalidTypeForAToken"); } @@ -1028,7 +986,7 @@ struct FFuncInfo /** Name of the function or operator. */ FToken Function; /** Function flags. */ - uint32 FunctionFlags; + EFunctionFlags FunctionFlags; /** Function flags which are only required for exporting */ uint32 FunctionExportFlags; /** Number of parameters expected for operator. */ @@ -1063,7 +1021,7 @@ struct FFuncInfo /** Constructor. */ FFuncInfo() : Function() - , FunctionFlags(0) + , FunctionFlags(FUNC_None) , FunctionExportFlags(0) , ExpectParms(0) , FunctionReference(NULL) diff --git a/Engine/Source/Programs/UnrealHeaderTool/Private/Specifiers/FunctionSpecifiers.def b/Engine/Source/Programs/UnrealHeaderTool/Private/Specifiers/FunctionSpecifiers.def index db003c32fe50..fbdbef88ba31 100644 --- a/Engine/Source/Programs/UnrealHeaderTool/Private/Specifiers/FunctionSpecifiers.def +++ b/Engine/Source/Programs/UnrealHeaderTool/Private/Specifiers/FunctionSpecifiers.def @@ -5,9 +5,11 @@ FUNCTION_SPECIFIER(BlueprintAuthorityOnly) FUNCTION_SPECIFIER(BlueprintCallable) FUNCTION_SPECIFIER(BlueprintCosmetic) +FUNCTION_SPECIFIER(BlueprintGetter) FUNCTION_SPECIFIER(BlueprintImplementableEvent) FUNCTION_SPECIFIER(BlueprintNativeEvent) FUNCTION_SPECIFIER(BlueprintPure) +FUNCTION_SPECIFIER(BlueprintSetter) FUNCTION_SPECIFIER(Client) FUNCTION_SPECIFIER(CustomThunk) FUNCTION_SPECIFIER(Exec) diff --git a/Engine/Source/Programs/UnrealHeaderTool/Private/Specifiers/VariableSpecifiers.def b/Engine/Source/Programs/UnrealHeaderTool/Private/Specifiers/VariableSpecifiers.def index 449ed16589fb..f9cb89211ed5 100644 --- a/Engine/Source/Programs/UnrealHeaderTool/Private/Specifiers/VariableSpecifiers.def +++ b/Engine/Source/Programs/UnrealHeaderTool/Private/Specifiers/VariableSpecifiers.def @@ -7,8 +7,10 @@ VARIABLE_SPECIFIER(AssetRegistrySearchable) VARIABLE_SPECIFIER(BlueprintAssignable) VARIABLE_SPECIFIER(BlueprintAuthorityOnly) VARIABLE_SPECIFIER(BlueprintCallable) +VARIABLE_SPECIFIER(BlueprintGetter) VARIABLE_SPECIFIER(BlueprintReadOnly) VARIABLE_SPECIFIER(BlueprintReadWrite) +VARIABLE_SPECIFIER(BlueprintSetter) VARIABLE_SPECIFIER(Config) VARIABLE_SPECIFIER(Const) VARIABLE_SPECIFIER(DuplicateTransient) diff --git a/Engine/Source/Programs/UnrealHeaderTool/Private/UHTMakefile/ClassArchiveProxy.cpp b/Engine/Source/Programs/UnrealHeaderTool/Private/UHTMakefile/ClassArchiveProxy.cpp index 1ca9a8fd507b..8028fe1b530e 100644 --- a/Engine/Source/Programs/UnrealHeaderTool/Private/UHTMakefile/ClassArchiveProxy.cpp +++ b/Engine/Source/Programs/UnrealHeaderTool/Private/UHTMakefile/ClassArchiveProxy.cpp @@ -8,7 +8,7 @@ FClassArchiveProxy::FClassArchiveProxy(FUHTMakefile& UHTMakefile, const UClass* : FStructArchiveProxy(UHTMakefile, Class) { ClassUnique = Class->ClassUnique; - ClassFlags = Class->ClassFlags; + ClassFlags = Class->GetClassFlags(); ClassCastFlags = Class->ClassCastFlags; ClassWithinIndex = UHTMakefile.GetClassIndex(Class->ClassWithin); ClassGeneratedByIndex = UHTMakefile.GetObjectIndex(Class->ClassGeneratedBy); @@ -82,7 +82,7 @@ FArchive& operator<<(FArchive& Ar, FClassArchiveProxy& ClassArchiveProxy) { Ar << static_cast(ClassArchiveProxy); Ar << ClassArchiveProxy.ClassUnique; - Ar << ClassArchiveProxy.ClassFlags; + Ar << (uint32&)ClassArchiveProxy.ClassFlags; Ar << ClassArchiveProxy.ClassCastFlags; Ar << ClassArchiveProxy.ClassWithinIndex; Ar << ClassArchiveProxy.ClassGeneratedByIndex; diff --git a/Engine/Source/Programs/UnrealHeaderTool/Private/UHTMakefile/ClassArchiveProxy.h b/Engine/Source/Programs/UnrealHeaderTool/Private/UHTMakefile/ClassArchiveProxy.h index f46dda003d49..f8500f8a8572 100644 --- a/Engine/Source/Programs/UnrealHeaderTool/Private/UHTMakefile/ClassArchiveProxy.h +++ b/Engine/Source/Programs/UnrealHeaderTool/Private/UHTMakefile/ClassArchiveProxy.h @@ -26,7 +26,7 @@ struct FClassArchiveProxy : public FStructArchiveProxy static void AddReferencedNames(const UClass* Class, FUHTMakefile& UHTMakefile); int32 ClassUnique; - uint32 ClassFlags; + EClassFlags ClassFlags; EClassCastFlags ClassCastFlags; FSerializeIndex ClassWithinIndex; FSerializeIndex ClassGeneratedByIndex; diff --git a/Engine/Source/Programs/UnrealHeaderTool/Private/UHTMakefile/FunctionArchiveProxy.h b/Engine/Source/Programs/UnrealHeaderTool/Private/UHTMakefile/FunctionArchiveProxy.h index 63f4118764e1..2905df6a185b 100644 --- a/Engine/Source/Programs/UnrealHeaderTool/Private/UHTMakefile/FunctionArchiveProxy.h +++ b/Engine/Source/Programs/UnrealHeaderTool/Private/UHTMakefile/FunctionArchiveProxy.h @@ -28,7 +28,7 @@ struct FFunctionArchiveProxy : public FStructArchiveProxy FStructArchiveProxy::AddReferencedNames(Function, UHTMakefile); } - uint32 FunctionFlags; + EFunctionFlags FunctionFlags; uint16 RepOffset; uint8 NumParms; uint16 ParmsSize; diff --git a/Engine/Source/Programs/UnrealHeaderTool/Private/UnrealHeaderToolGlobals.h b/Engine/Source/Programs/UnrealHeaderTool/Private/UnrealHeaderToolGlobals.h index a6601c0663ec..d71b73be7a71 100644 --- a/Engine/Source/Programs/UnrealHeaderTool/Private/UnrealHeaderToolGlobals.h +++ b/Engine/Source/Programs/UnrealHeaderTool/Private/UnrealHeaderToolGlobals.h @@ -9,5 +9,7 @@ DECLARE_LOG_CATEGORY_EXTERN(LogCompile, Log, All); extern bool GUHTWarningLogged; +extern bool GUHTErrorLogged; #define UE_LOG_WARNING_UHT(Format, ...) { GUHTWarningLogged = true; UE_LOG(LogCompile, Warning, Format, ##__VA_ARGS__); } +#define UE_LOG_ERROR_UHT(Format, ...) { GUHTErrorLogged = true; UE_LOG(LogCompile, Error, Format, ##__VA_ARGS__); } diff --git a/Engine/Source/Programs/UnrealHeaderTool/Private/UnrealHeaderToolMain.cpp b/Engine/Source/Programs/UnrealHeaderTool/Private/UnrealHeaderToolMain.cpp index f430b8bb4219..1fe904b3aeca 100644 --- a/Engine/Source/Programs/UnrealHeaderTool/Private/UnrealHeaderToolMain.cpp +++ b/Engine/Source/Programs/UnrealHeaderTool/Private/UnrealHeaderToolMain.cpp @@ -15,26 +15,12 @@ #include "RequiredProgramMainCPPInclude.h" - -//#define COMPILER_WARNING(x) GCC warning x -//#define COMPILER_ERROR(x) GCC error x - -//#define DO_WARNING(x) _Pragma(#x) -//#define DO_WARNING_2(x) DO_WARNING(GCC warning x) - -//DO_WARNING_2("hello") - -//#pragma GCC warning "this is a warning" -//#pragma GCC error "this is an error" - -//COMPILER_WARNING("this is a warning") -//COMPILER_ERROR("this is an error") - IMPLEMENT_APPLICATION(UnrealHeaderTool, "UnrealHeaderTool"); DEFINE_LOG_CATEGORY(LogCompile); bool GUHTWarningLogged = false; +bool GUHTErrorLogged = false; /** * Application entry point @@ -125,7 +111,7 @@ INT32_MAIN_INT32_ARGC_TCHAR_ARGV() extern ECompilationResult::Type UnrealHeaderTool_Main(const FString& ModuleInfoFilename); ECompilationResult::Type Result = UnrealHeaderTool_Main(ModuleInfoFilename); - if (Result == ECompilationResult::Succeeded && GUHTWarningLogged && GWarn->TreatWarningsAsErrors) + if (Result == ECompilationResult::Succeeded && (GUHTErrorLogged || (GUHTWarningLogged && GWarn->TreatWarningsAsErrors))) { Result = ECompilationResult::OtherCompilationError; } diff --git a/Engine/Source/Programs/UnrealHeaderTool/Public/IScriptGeneratorPluginInterface.h b/Engine/Source/Programs/UnrealHeaderTool/Public/IScriptGeneratorPluginInterface.h index ad70a6cf1e72..d3ce34f20e2f 100644 --- a/Engine/Source/Programs/UnrealHeaderTool/Public/IScriptGeneratorPluginInterface.h +++ b/Engine/Source/Programs/UnrealHeaderTool/Public/IScriptGeneratorPluginInterface.h @@ -74,5 +74,7 @@ public: virtual void FinishExport() = 0; /** Name of the generator plugin, mostly for debuggind purposes */ virtual FString GetGeneratorName() const = 0; + /** Finds a list of external dependencies which require UHT to be re-run */ + virtual void GetExternalDependencies(TArray& Dependencies) const { } }; diff --git a/Engine/Source/Programs/UnrealHeaderTool/Resources/UHTDebugging.manifest b/Engine/Source/Programs/UnrealHeaderTool/Resources/UHTDebugging.manifest index c38301267f3d..f9bf4d2bbddc 100644 --- a/Engine/Source/Programs/UnrealHeaderTool/Resources/UHTDebugging.manifest +++ b/Engine/Source/Programs/UnrealHeaderTool/Resources/UHTDebugging.manifest @@ -3,6 +3,7 @@ "RootLocalPath": "..\\..\\..\\..", "RootBuildPath": "..\\..\\..\\..", "TargetName": "UHTDebugging", + "ExternalDependenciesFile": "", "Modules":[{ "Name": "CoreUObject", "ModuleType": "EngineRuntime", diff --git a/Engine/Source/Programs/UnrealHeaderTool/Resources/UHTDebugging/TestObject.h b/Engine/Source/Programs/UnrealHeaderTool/Resources/UHTDebugging/TestObject.h index f16c0e225cd7..d72d84e1266d 100644 --- a/Engine/Source/Programs/UnrealHeaderTool/Resources/UHTDebugging/TestObject.h +++ b/Engine/Source/Programs/UnrealHeaderTool/Resources/UHTDebugging/TestObject.h @@ -49,6 +49,9 @@ public: UPROPERTY() TSet TestSet; + UPROPERTY() + UObject* const ConstPointerProperty; + UFUNCTION() void CodeGenTestForEnumClasses(ECppEnum Val); @@ -87,6 +90,11 @@ public: } #endif +#if WITH_EDITOR + UFUNCTION(BlueprintCallable, Category = "MyEditorOnlyFunction") + void MyEditorOnlyFunction(); +#endif + UFUNCTION(BlueprintNativeEvent, Category="Game") UClass* BrokenReturnTypeForFunction(); }; diff --git a/Engine/Source/Programs/UnrealLightmass/Private/ImportExport/LightmassScene.h b/Engine/Source/Programs/UnrealLightmass/Private/ImportExport/LightmassScene.h index 0dcf3a43a8b4..c25f41354543 100644 --- a/Engine/Source/Programs/UnrealLightmass/Private/ImportExport/LightmassScene.h +++ b/Engine/Source/Programs/UnrealLightmass/Private/ImportExport/LightmassScene.h @@ -85,6 +85,7 @@ protected: class FLight : public FLightData { public: + virtual ~FLight() { } virtual void Import( class FLightmassImporter& Importer ); diff --git a/Engine/Source/Programs/UnrealLightmass/Private/ImportExport/Material.h b/Engine/Source/Programs/UnrealLightmass/Private/ImportExport/Material.h index 36b4b7b4d18d..b5de9346a1a5 100644 --- a/Engine/Source/Programs/UnrealLightmass/Private/ImportExport/Material.h +++ b/Engine/Source/Programs/UnrealLightmass/Private/ImportExport/Material.h @@ -17,6 +17,7 @@ namespace Lightmass class FBaseMaterial : public FBaseMaterialData { public: + virtual ~FBaseMaterial() { } virtual void Import( class FLightmassImporter& Importer ); }; diff --git a/Engine/Source/Programs/UnrealLightmass/Private/ImportExport/Mesh.h b/Engine/Source/Programs/UnrealLightmass/Private/ImportExport/Mesh.h index 7178fa9c5ea0..d0883813e216 100644 --- a/Engine/Source/Programs/UnrealLightmass/Private/ImportExport/Mesh.h +++ b/Engine/Source/Programs/UnrealLightmass/Private/ImportExport/Mesh.h @@ -22,6 +22,7 @@ class FStaticMeshElement; class FBaseMesh : public FBaseMeshData { public: + virtual ~FBaseMesh() { } virtual void Import( class FLightmassImporter& Importer ); }; @@ -56,6 +57,7 @@ protected: class FStaticMeshLOD : public FStaticMeshLODData { public: + virtual ~FStaticMeshLOD() { } virtual void Import( class FLightmassImporter& Importer ); /** diff --git a/Engine/Source/Programs/UnrealLightmass/Private/Launch/UnitTest.cpp b/Engine/Source/Programs/UnrealLightmass/Private/Launch/UnitTest.cpp index 69b5c45fc1b0..3cca4a7c51ab 100644 --- a/Engine/Source/Programs/UnrealLightmass/Private/Launch/UnitTest.cpp +++ b/Engine/Source/Programs/UnrealLightmass/Private/Launch/UnitTest.cpp @@ -160,7 +160,7 @@ void TestLightmass() FString TestString = FString::Printf(TEXT("Copy has %d, Vector is [%.2f, %.2f, %.2f, %.2f]\n"), ArrayCopy[0], TestVector.X, TestVector.Y, TestVector.Z, TestVector.W); - wprintf(*TestString); + wprintf(TEXT("%s"), *TestString); FMemory::Free(Buf); diff --git a/Engine/Source/Programs/UnrealLightmass/Private/Lighting/LightingSystem.cpp b/Engine/Source/Programs/UnrealLightmass/Private/Lighting/LightingSystem.cpp index edd0c4dcec1f..2b2d040619fa 100644 --- a/Engine/Source/Programs/UnrealLightmass/Private/Lighting/LightingSystem.cpp +++ b/Engine/Source/Programs/UnrealLightmass/Private/Lighting/LightingSystem.cpp @@ -1843,6 +1843,7 @@ void FStaticLightingSystem::CalculateStaticShadowDepthMap(FGuid LightGuid) const FSpotLight* SpotLight = Light->GetSpotLight(); const FPointLight* PointLight = Light->GetPointLight(); check(DirectionalLight || SpotLight || PointLight); + const float ClampedResolutionScale = FMath::Clamp(Light->ShadowResolutionScale, .125f, 8.0f); const double StartTime = FPlatformTime::Seconds(); @@ -1859,9 +1860,9 @@ void FStaticLightingSystem::CalculateStaticShadowDepthMap(FGuid LightGuid) FBoxSphereBounds ImportanceVolume = GetImportanceBounds().SphereRadius > 0.0f ? GetImportanceBounds() : FBoxSphereBounds(AggregateMesh->GetBounds()); const FBox LightSpaceImportanceBounds = ImportanceVolume.GetBox().TransformBy(ShadowDepthMap->WorldToLight); - ShadowDepthMap->ShadowMapSizeX = FMath::TruncToInt(FMath::Max(LightSpaceImportanceBounds.GetExtent().X * 2.0f / ShadowSettings.StaticShadowDepthMapTransitionSampleDistanceX, 4.0f)); + ShadowDepthMap->ShadowMapSizeX = FMath::TruncToInt(FMath::Max(LightSpaceImportanceBounds.GetExtent().X * 2.0f * ClampedResolutionScale / ShadowSettings.StaticShadowDepthMapTransitionSampleDistanceX, 4.0f)); ShadowDepthMap->ShadowMapSizeX = ShadowDepthMap->ShadowMapSizeX == appTruncErrorCode ? INT_MAX : ShadowDepthMap->ShadowMapSizeX; - ShadowDepthMap->ShadowMapSizeY = FMath::TruncToInt(FMath::Max(LightSpaceImportanceBounds.GetExtent().Y * 2.0f / ShadowSettings.StaticShadowDepthMapTransitionSampleDistanceY, 4.0f)); + ShadowDepthMap->ShadowMapSizeY = FMath::TruncToInt(FMath::Max(LightSpaceImportanceBounds.GetExtent().Y * 2.0f * ClampedResolutionScale / ShadowSettings.StaticShadowDepthMapTransitionSampleDistanceY, 4.0f)); ShadowDepthMap->ShadowMapSizeY = ShadowDepthMap->ShadowMapSizeY == appTruncErrorCode ? INT_MAX : ShadowDepthMap->ShadowMapSizeY; // Clamp the number of dominant shadow samples generated if necessary while maintaining aspect ratio @@ -1952,7 +1953,7 @@ void FStaticLightingSystem::CalculateStaticShadowDepthMap(FGuid LightGuid) const FVector4 LightSpaceImportanceBoundMin = FVector4(-HalfCrossSectionLength, -HalfCrossSectionLength, 0); const FVector4 LightSpaceImportanceBoundMax = FVector4(HalfCrossSectionLength, HalfCrossSectionLength, SpotLight->Radius); - ShadowDepthMap->ShadowMapSizeX = FMath::TruncToInt(FMath::Max(HalfCrossSectionLength / ShadowSettings.StaticShadowDepthMapTransitionSampleDistanceX, 4.0f)); + ShadowDepthMap->ShadowMapSizeX = FMath::TruncToInt(FMath::Max(HalfCrossSectionLength * ClampedResolutionScale / ShadowSettings.StaticShadowDepthMapTransitionSampleDistanceX, 4.0f)); ShadowDepthMap->ShadowMapSizeX = ShadowDepthMap->ShadowMapSizeX == appTruncErrorCode ? INT_MAX : ShadowDepthMap->ShadowMapSizeX; ShadowDepthMap->ShadowMapSizeY = ShadowDepthMap->ShadowMapSizeX; @@ -2039,7 +2040,7 @@ void FStaticLightingSystem::CalculateStaticShadowDepthMap(FGuid LightGuid) } else if (PointLight) { - ShadowDepthMap->ShadowMapSizeX = FMath::TruncToInt(FMath::Max(PointLight->Radius / ShadowSettings.StaticShadowDepthMapTransitionSampleDistanceX, 4.0f)); + ShadowDepthMap->ShadowMapSizeX = FMath::TruncToInt(FMath::Max(PointLight->Radius * 4 * ClampedResolutionScale / ShadowSettings.StaticShadowDepthMapTransitionSampleDistanceX, 4.0f)); ShadowDepthMap->ShadowMapSizeX = ShadowDepthMap->ShadowMapSizeX == appTruncErrorCode ? INT_MAX : ShadowDepthMap->ShadowMapSizeX; ShadowDepthMap->ShadowMapSizeY = ShadowDepthMap->ShadowMapSizeX; diff --git a/Engine/Source/Programs/UnrealLightmass/Private/Lighting/Mappings.h b/Engine/Source/Programs/UnrealLightmass/Private/Lighting/Mappings.h index 91a4f1585df6..397b3f5b389f 100644 --- a/Engine/Source/Programs/UnrealLightmass/Private/Lighting/Mappings.h +++ b/Engine/Source/Programs/UnrealLightmass/Private/Lighting/Mappings.h @@ -10,6 +10,9 @@ namespace Lightmass { + class FCacheIndirectTaskDescription; + class FInterpolateIndirectTaskDescription; + /** A mapping between world-space surfaces and a static lighting cache. */ class FStaticLightingMapping : public virtual FRefCountedObject, public FStaticLightingMappingData { @@ -135,13 +138,13 @@ public: volatile int32 NumOutstandingCacheTasks; /** List of completed cache tasks for this mapping. */ - FLockFreeVoidPointerListBase CompletedCacheIndirectLightingTasks; + TLockFreePointerListLIFO CompletedCacheIndirectLightingTasks; /** Counts how many interpolation tasks this mapping needs completed. */ volatile int32 NumOutstandingInterpolationTasks; /** List of completed interpolation tasks for this mapping. */ - FLockFreeVoidPointerListBase CompletedInterpolationTasks; + TLockFreePointerListLIFO CompletedInterpolationTasks; }; } //namespace Lightmass diff --git a/Engine/Source/Programs/UnrealLightmass/Private/Lighting/TextureMapping.cpp b/Engine/Source/Programs/UnrealLightmass/Private/Lighting/TextureMapping.cpp index 8f2e26ff319f..58d6ef104fc6 100644 --- a/Engine/Source/Programs/UnrealLightmass/Private/Lighting/TextureMapping.cpp +++ b/Engine/Source/Programs/UnrealLightmass/Private/Lighting/TextureMapping.cpp @@ -3166,7 +3166,7 @@ void FStaticLightingSystem::CalculateIndirectLightingTextureMapping( while (TextureMapping->NumOutstandingCacheTasks > 0); TArray CompletedCILTasks; - TextureMapping->CompletedCacheIndirectLightingTasks.PopAll, FCacheIndirectTaskDescription*>(CompletedCILTasks); + TextureMapping->CompletedCacheIndirectLightingTasks.PopAll(CompletedCILTasks); check(CompletedCILTasks.Num() == NumTasksSubmitted); int32 NextRecordId = 0; @@ -3259,7 +3259,7 @@ void FStaticLightingSystem::CalculateIndirectLightingTextureMapping( } TArray CompletedTasks; - TextureMapping->CompletedInterpolationTasks.PopAll, FInterpolateIndirectTaskDescription*>(CompletedTasks); + TextureMapping->CompletedInterpolationTasks.PopAll(CompletedTasks); check(CompletedTasks.Num() == NumIILTasksSubmitted); for (int32 TaskIndex = 0; TaskIndex < CompletedTasks.Num(); TaskIndex++) diff --git a/Engine/Source/Programs/UnrealLightmass/Public/SceneExport.h b/Engine/Source/Programs/UnrealLightmass/Public/SceneExport.h index 3fe316b0a25f..1b333a3598db 100644 --- a/Engine/Source/Programs/UnrealLightmass/Public/SceneExport.h +++ b/Engine/Source/Programs/UnrealLightmass/Public/SceneExport.h @@ -818,6 +818,8 @@ struct FLightData float IndirectLightingSaturation; /** Controls the falloff of shadow penumbras */ float ShadowExponent; + /** Scales resolution of the static shadowmap for this light. */ + float ShadowResolutionScale; // only used if an LightProfile, 1d texture data 0:occluded, 255:not occluded uint8 LightProfileTextureData[256]; diff --git a/Engine/Source/Programs/UnrealPak/Private/UnrealPak.cpp b/Engine/Source/Programs/UnrealPak/Private/UnrealPak.cpp index 7f28903e2d47..0bc6c6f5e318 100644 --- a/Engine/Source/Programs/UnrealPak/Private/UnrealPak.cpp +++ b/Engine/Source/Programs/UnrealPak/Private/UnrealPak.cpp @@ -10,6 +10,9 @@ #include "AES.h" #include "UniquePtr.h" #include "Serialization/BufferWriter.h" +#include "AssetRegistryModule.h" +#include "DiagnosticTable.h" +#include "JsonSerializer.h" IMPLEMENT_APPLICATION(UnrealPak, "UnrealPak"); @@ -1321,6 +1324,8 @@ bool ListFilesInPak(const TCHAR * InPakFilename, int64 SizeFilter = 0) if (PakFile.IsValid()) { + UE_LOG(LogPakFile, Display, TEXT("Mount point %s"), *PakFile.GetMountPoint()); + TArray Records; for (FPakFile::FFileIterator It(PakFile); It; ++It) @@ -1362,6 +1367,11 @@ bool ListFilesInPak(const TCHAR * InPakFilename, int64 SizeFilter = 0) bool ExtractFilesFromPak(const TCHAR* InPakFilename, const TCHAR* InDestPath, bool bUseMountPoint = false) { + if ( !IFileManager::Get().FileExists(InPakFilename) ) + { + return false; + } + FPakFile PakFile(InPakFilename, FParse::Param(FCommandLine::Get(), TEXT("signed"))); if (PakFile.IsValid()) { @@ -1623,6 +1633,11 @@ bool GenerateHashForFile( FString Filename, FFileInfo& FileHash) bool GenerateHashesFromPak(const TCHAR* InPakFilename, TMap& FileHashes, bool bUseMountPoint = false) { + if ( !IFileManager::Get().FileExists(InPakFilename) ) + { + // it's ok if we can't get the hashes from the pak file + return false; + } FPakFile PakFile(InPakFilename, FParse::Param(FCommandLine::Get(), TEXT("signed"))); if (PakFile.IsValid()) { @@ -1795,6 +1810,272 @@ FString GetPakPath(const TCHAR* SpecifiedPath, bool bIsForCreation) return PakFilename; } +struct FPackage +{ +public: + TSet DirectlyReferencing; + TSet DirectlyReferencedBy; + TSet AllReferences; + + FName Name; + int64 InclusiveSize; + int64 ExclusiveSize; + int Id; + +private: + bool bUpdateHelper; + static TMap NameToPackageMap; + +public: + FPackage(const FName& InName,int InId) + : Name(InName) + , InclusiveSize(0) + , ExclusiveSize(0) + , Id(InId) + , bUpdateHelper(false) + {} + + static FPackage* FindOrCreatePackage( FName PackageName ) + { + static int Id = 1; + FPackage* Package = NameToPackageMap.FindRef(PackageName); + if(!Package) + { + Package = new FPackage(PackageName,Id++); + NameToPackageMap.Add(PackageName,Package); + } + return Package; + } + + void ResetUpdateHelper() + { + bUpdateHelper = false; + } + + void RecurseUpdateReferences() + { + if( !bUpdateHelper ) + { + bUpdateHelper = true; + for( auto& DirectReference : DirectlyReferencing ) + { + AllReferences.Add(DirectReference); + DirectReference->RecurseUpdateReferences(); + AllReferences.Append(DirectReference->AllReferences); + } + } + } + + void UpdateInclusiveSize() + { + InclusiveSize = ExclusiveSize; + for(auto& Reference : AllReferences) + { + InclusiveSize += Reference->ExclusiveSize; + } + } + + static void GetAllPackages( TArray& OutPackages ) + { + OutPackages.Reset(NameToPackageMap.Num()); + for( const auto& Entry : NameToPackageMap ) + { + OutPackages.Add(Entry.Value); + } + } + + TArray< TSharedPtr > ToJsonHelper( const TSet& Packages ) + { + TArray< TSharedPtr > JsonPackageNames; + for( const auto Package : Packages ) + { + JsonPackageNames.Add(MakeShareable(new FJsonValueString(Package->Name.ToString()))); + } + return JsonPackageNames; + } + + TSharedPtr ToJsonObject() + { + TSharedPtr JsonPackageObject = MakeShareable(new FJsonObject); + + JsonPackageObject->SetStringField(TEXT("Name"),*Name.ToString()); + JsonPackageObject->SetNumberField(TEXT("InclusiveSize"),InclusiveSize); + JsonPackageObject->SetNumberField(TEXT("ExclusiveSize"),ExclusiveSize); + + JsonPackageObject->SetArrayField(TEXT("DirectlyReferencing"),ToJsonHelper(DirectlyReferencing)); + JsonPackageObject->SetArrayField(TEXT("DirectlyReferencedBy"),ToJsonHelper(DirectlyReferencedBy)); + JsonPackageObject->SetArrayField(TEXT("AllReferences"),ToJsonHelper(AllReferences)); + + return JsonPackageObject; + } +}; +TMap FPackage::NameToPackageMap; + +bool ExportDependencies(const TCHAR * PakFilename, const TCHAR* GameName, const TCHAR* GameFolderName, const TCHAR* OutputFilenameBase ) +{ + // Example command line used for this tool + // C:\Development\BB\WEX\Saved\StagedBuilds\WindowsNoEditor\WorldExplorers\Content\Paks\WorldExplorers-WindowsNoEditor.pak WorldExplorers WEX -exportdependencies=c:\dvtemp\output -debug -NoAssetRegistryCache -ForceDependsGathering + + FPakFile PakFile(PakFilename,FParse::Param(FCommandLine::Get(),TEXT("signed"))); + + if(PakFile.IsValid()) + { + // Get size information from PAK file. + { + TArray Records; + FString PakGameContentFolder = FString(GameName) + TEXT("/Content"); + for(FPakFile::FFileIterator It(PakFile); It; ++It) + { + FString PackageName; + It.Filename().Split(TEXT("."),&PackageName,NULL); + int64 Size = It.Info().Size; + + if( PackageName.StartsWith(TEXT("Engine/Content")) ) + { + PackageName = PackageName.Replace(TEXT("Engine/Content"),TEXT("/Engine")); + } + else if( PackageName.StartsWith(*PakGameContentFolder)) + { + PackageName = PackageName.Replace(*PakGameContentFolder,TEXT("/Game")); + } + + FPackage* Package = FPackage::FindOrCreatePackage(FName(*PackageName)); + Package->ExclusiveSize += Size; + } + } + + TMap PackageToClassMap; + + // Combine with dependency information from asset registry. + { + FString GameDir = FString(TEXT("../../../")) + GameFolderName + TEXT("/"); + FPlatformMisc::SetOverrideGameDir(*GameDir); + FAssetRegistryModule& AssetRegistryModule = FModuleManager::Get().LoadModuleChecked(TEXT("AssetRegistry")); + + AssetRegistryModule.Get().SearchAllAssets(true); + TArray AssetData; + AssetRegistryModule.Get().GetAllAssets(AssetData,true); + + TSet PackageNames; + for( int i=0; i DependencyArray; + AssetRegistryModule.Get().GetDependencies(PackageName,DependencyArray); + + FPackage* Package = FPackage::FindOrCreatePackage(PackageName); + for( const auto& DependencyName : DependencyArray ) + { + // exclude '/Script/' as it clutters up things significantly. + if( !DependencyName.ToString().StartsWith(TEXT("/Script/")) ) + { + FPackage* Dependency = FPackage::FindOrCreatePackage(DependencyName); + Package->DirectlyReferencing.Add(Dependency); + Dependency->DirectlyReferencedBy.Add(Package); + } + } + } + + // 2 passes are required to deal with cycles. + for(const auto& PackageName : PackageNames) + { + FPackage* Package = FPackage::FindOrCreatePackage(PackageName); + Package->RecurseUpdateReferences(); + } + for(const auto& PackageName : PackageNames) + { + FPackage* Package = FPackage::FindOrCreatePackage(PackageName); + Package->ResetUpdateHelper(); + } + for(const auto& PackageName : PackageNames) + { + FPackage* Package = FPackage::FindOrCreatePackage(PackageName); + Package->RecurseUpdateReferences(); + } + } + + // Update inclusive size, asset class, and export to CSV, JSON, and GDF + { + TSharedPtr JsonRootObject = MakeShareable(new FJsonObject); + TArray< TSharedPtr > JsonPackages; + + TArray AllPackages; + FPackage::GetAllPackages(AllPackages); + + for(auto Package : AllPackages) + { + Package->UpdateInclusiveSize(); + JsonPackages.Add( MakeShareable(new FJsonValueObject(Package->ToJsonObject())) ); + } + JsonRootObject->SetArrayField(TEXT("Packages"),JsonPackages); + + FString JsonOutputString; + TSharedRef>> JsonWriter = TJsonWriterFactory>::Create(&JsonOutputString); + FJsonSerializer::Serialize(JsonRootObject.ToSharedRef(),JsonWriter); + + FArchive* JsonFileWriter = IFileManager::Get().CreateFileWriter(*(FString(OutputFilenameBase)+TEXT(".json"))); + if(JsonFileWriter) + { + JsonFileWriter->Logf(TEXT("%s"),*JsonOutputString); + JsonFileWriter->Close(); + delete JsonFileWriter; + } + + FArchive* CSVFileWriter = IFileManager::Get().CreateFileWriter(*(FString(OutputFilenameBase)+TEXT(".csv"))); + if(CSVFileWriter) + { + CSVFileWriter->Logf(TEXT("class,name,inclusive,exclusive")); + for(auto Package : AllPackages) + { + FName ClassName = PackageToClassMap.FindRef(Package->Name); + CSVFileWriter->Logf(TEXT("%s,%s,%i,%i"),*ClassName.ToString(),*Package->Name.ToString(),Package->InclusiveSize,Package->ExclusiveSize); + } + CSVFileWriter->Close(); + delete CSVFileWriter; + CSVFileWriter = NULL; + } + + FArchive* GDFFileWriter = IFileManager::Get().CreateFileWriter(*(FString(OutputFilenameBase)+TEXT(".gdf"))); + if(GDFFileWriter) + { + GDFFileWriter->Logf(TEXT("nodedef> name VARCHAR,label VARCHAR,inclusive DOUBLE,exclusive DOUBLE")); + GDFFileWriter->Logf(TEXT("0,root,0,0")); + for(auto Package : AllPackages) + { + GDFFileWriter->Logf(TEXT("%i,%s,%i,%i"),Package->Id,*Package->Name.ToString(),Package->InclusiveSize,Package->ExclusiveSize); + } + GDFFileWriter->Logf(TEXT("edgedef> node1 VARCHAR,node2 VARCHAR")); + // fake root to ensure spanning tree + for(auto Package : AllPackages) + { + GDFFileWriter->Logf(TEXT("0,%i"),Package->Id); + } + for(auto Package : AllPackages) + { + for( auto ReferencedPackage : Package->DirectlyReferencing ) + { + GDFFileWriter->Logf(TEXT("%i,%i"),Package->Id,ReferencedPackage->Id); + } + } + GDFFileWriter->Close(); + delete GDFFileWriter; + GDFFileWriter = NULL; + } + } + return true; + } + else + { + return false; + } +} + + /** * Application entry point * Params: @@ -1823,6 +2104,7 @@ INT32_MAIN_INT32_ARGC_TCHAR_ARGV() UE_LOG(LogPakFile, Error, TEXT("No pak file name specified. Usage:")); UE_LOG(LogPakFile, Error, TEXT(" UnrealPak -Test")); UE_LOG(LogPakFile, Error, TEXT(" UnrealPak -List")); + UE_LOG(LogPakFile, Error, TEXT(" UnrealPak -ExportDependencies= -NoAssetRegistryCache -ForceDependsGathering")); UE_LOG(LogPakFile, Error, TEXT(" UnrealPak -Extract ")); UE_LOG(LogPakFile, Error, TEXT(" UnrealPak -Create= [Options]")); UE_LOG(LogPakFile, Error, TEXT(" UnrealPak -Dest=")); @@ -1867,6 +2149,7 @@ INT32_MAIN_INT32_ARGC_TCHAR_ARGV() } else { + FString ExportDependencyFilename; if (FParse::Param(FCommandLine::Get(), TEXT("Test"))) { FString PakFilename = GetPakPath(ArgV[1], false); @@ -1880,6 +2163,18 @@ INT32_MAIN_INT32_ARGC_TCHAR_ARGV() FString PakFilename = GetPakPath(ArgV[1], false); Result = ListFilesInPak(*PakFilename, SizeFilter) ? 0 : 1; } + else if(FParse::Value(FCommandLine::Get(),TEXT("ExportDependencies="),ExportDependencyFilename,false)) + { + if(ArgC < 4) + { + UE_LOG(LogPakFile,Error,TEXT("Insufficient arguments.")); + } + else + { + FString PakFilename = GetPakPath(ArgV[1],false); + Result = ExportDependencies(*PakFilename,ArgV[2],ArgV[3],*ExportDependencyFilename); + } + } else if (FParse::Param(FCommandLine::Get(), TEXT("Diff"))) { FString PakFilename1 = GetPakPath(ArgV[1], false); @@ -1936,9 +2231,12 @@ INT32_MAIN_INT32_ARGC_TCHAR_ARGV() { if ( ExtractFilesFromPak( *CmdLineParameters.SourcePatchPakFilename, *OutputPath ) == false ) { - UE_LOG(LogPakFile, Error, TEXT("Unable to extract files from source pak file for patch") ); + UE_LOG(LogPakFile, Warning, TEXT("Unable to extract files from source pak file for patch") ); + } + else + { + CmdLineParameters.SourcePatchDiffDirectory = OutputPath; } - CmdLineParameters.SourcePatchDiffDirectory = OutputPath; } } @@ -1970,5 +2268,8 @@ INT32_MAIN_INT32_ARGC_TCHAR_ARGV() GLog->Flush(); + FEngineLoop::AppPreExit(); + FEngineLoop::AppExit(); + return Result; } diff --git a/Engine/Source/Programs/UnrealPak/UnrealPak.Build.cs b/Engine/Source/Programs/UnrealPak/UnrealPak.Build.cs index 8de9a72cc8ea..60574dbfd1d7 100644 --- a/Engine/Source/Programs/UnrealPak/UnrealPak.Build.cs +++ b/Engine/Source/Programs/UnrealPak/UnrealPak.Build.cs @@ -8,8 +8,19 @@ public class UnrealPak : ModuleRules { PublicIncludePaths.Add("Runtime/Launch/Public"); - PrivateDependencyModuleNames.AddRange(new string[] { "Core", "PakFile", "Projects" }); + PrivateDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "PakFile", "Json", "Projects" }); - PrivateIncludePaths.Add("Runtime/Launch/Private"); // For LaunchEngineLoop.cpp include - } + PrivateIncludePaths.Add("Runtime/Launch/Private"); // For LaunchEngineLoop.cpp include + + PrivateIncludePathModuleNames.AddRange( + new string[] { + "AssetRegistry", + "Json" + }); + + DynamicallyLoadedModuleNames.AddRange( + new string[] { + "AssetRegistry" + }); + } } diff --git a/Engine/Source/Programs/UnrealVS/CommandLineEditor.cs b/Engine/Source/Programs/UnrealVS/CommandLineEditor.cs index be0f7907dce8..23ddf8118258 100644 --- a/Engine/Source/Programs/UnrealVS/CommandLineEditor.cs +++ b/Engine/Source/Programs/UnrealVS/CommandLineEditor.cs @@ -23,7 +23,6 @@ namespace UnrealVS private const int ComboID = 0x1030; private const int ComboListID = 0x1040; - private const string InvalidProjectString = ""; private const int ComboListCountMax = 32; /** methods */ @@ -161,7 +160,7 @@ namespace UnrealVS { if (PropertyStorage.GetPropertyValue("StartArguments", ConfigurationName, (uint)_PersistStorageType.PST_USER_FILE, out Text) != VSConstants.S_OK) { - Text = InvalidProjectString; + Text = ""; } } @@ -275,18 +274,36 @@ namespace UnrealVS } } + // Get the project platform name. + string ProjectPlatformName = SelectedConfiguration.PlatformName; + if(ProjectPlatformName == "Any CPU") + { + ProjectPlatformName = "AnyCPU"; + } + // Get the project kind. C++ projects store the debugger arguments differently to other project types. string ProjectKind = SelectedStartupProject.Kind; // Update the property - string ProjectConfigurationName = String.Format("{0}|{1}", SelectedConfiguration.ConfigurationName, SelectedConfiguration.PlatformName); + string ProjectConfigurationName = String.Format("{0}|{1}", SelectedConfiguration.ConfigurationName, ProjectPlatformName); if (String.Equals(ProjectKind, "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}", StringComparison.InvariantCultureIgnoreCase)) { PropertyStorage.SetPropertyValue("LocalDebuggerCommandArguments", ProjectConfigurationName, (uint)_PersistStorageType.PST_USER_FILE, FullCommandLine); } else { - PropertyStorage.SetPropertyValue("StartArguments", ProjectConfigurationName, (uint)_PersistStorageType.PST_USER_FILE, FullCommandLine); + // For some reason, have to update C# projects this way, otherwise the properties page doesn't update. Conversely, SelectedConfiguration.Properties is always null for C++ projects in VS2017. + if (SelectedConfiguration.Properties != null) + { + foreach (Property Property in SelectedConfiguration.Properties) + { + if (Property.Name.Equals("StartArguments", StringComparison.InvariantCultureIgnoreCase)) + { + Property.Value = FullCommandLine; + break; + } + } + } } } } diff --git a/Engine/Source/Programs/UnrealVS/Properties/AssemblyInfo.cs b/Engine/Source/Programs/UnrealVS/Properties/AssemblyInfo.cs index 222cc1e2f942..294cb0d6a97c 100644 --- a/Engine/Source/Programs/UnrealVS/Properties/AssemblyInfo.cs +++ b/Engine/Source/Programs/UnrealVS/Properties/AssemblyInfo.cs @@ -31,8 +31,8 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.46.0.0")] -[assembly: AssemblyFileVersion("1.46.0.0")] +[assembly: AssemblyVersion("1.48.0.0")] +[assembly: AssemblyFileVersion("1.48.0.0")] diff --git a/Engine/Source/Programs/UnrealVS/UnrealVS.csproj b/Engine/Source/Programs/UnrealVS/UnrealVS.csproj index e623b9fba30f..66f55c73c054 100644 --- a/Engine/Source/Programs/UnrealVS/UnrealVS.csproj +++ b/Engine/Source/Programs/UnrealVS/UnrealVS.csproj @@ -314,6 +314,7 @@ AnyCPU prompt MinimumRecommendedRules.ruleset + False ..\..\..\Extras\UnrealVS\VS2015\ diff --git a/Engine/Source/Programs/UnrealVS/UnrealVSPackage.cs b/Engine/Source/Programs/UnrealVS/UnrealVSPackage.cs index aeb1366dfd54..85bab060c3aa 100644 --- a/Engine/Source/Programs/UnrealVS/UnrealVSPackage.cs +++ b/Engine/Source/Programs/UnrealVS/UnrealVSPackage.cs @@ -59,7 +59,7 @@ namespace UnrealVS { /** Constants */ - private const string VersionString = "v1.46"; + private const string VersionString = "v1.48"; private const string UnrealSolutionFileNamePrefix = "UE4"; private const string ExtensionName = "UnrealVS"; private const string CommandLineOptionKey = ExtensionName + "CommandLineMRU"; diff --git a/Engine/Source/Programs/UnrealVS/UnrealVS_2017.csproj b/Engine/Source/Programs/UnrealVS/UnrealVS_2017.csproj index d4972eb80271..736510f4bf83 100644 --- a/Engine/Source/Programs/UnrealVS/UnrealVS_2017.csproj +++ b/Engine/Source/Programs/UnrealVS/UnrealVS_2017.csproj @@ -322,8 +322,8 @@ AnyCPU prompt MinimumRecommendedRules.ruleset - False - True + True + False C:\Users\Ben.Marsh\AppData\Local\Microsoft\VisualStudio\15.0_12f23ee0Exp\Extensions\Epic Games, Inc\UnrealVS\1.45 diff --git a/Engine/Source/Programs/UnrealVS/Utils.cs b/Engine/Source/Programs/UnrealVS/Utils.cs index 9ebc8ee7ba12..1ed1db755f72 100644 --- a/Engine/Source/Programs/UnrealVS/Utils.cs +++ b/Engine/Source/Programs/UnrealVS/Utils.cs @@ -405,6 +405,62 @@ namespace UnrealVS return '\"' + UProjectPath + '\"'; } + public static void AddProjects(DirectoryInfo ProjectDir, List Files) + { + Files.AddRange(ProjectDir.EnumerateFiles("*.uproject")); + } + + /// + /// Enumerate projects under the given directory + /// + /// Base directory to enumerate + /// List of project files + static List EnumerateProjects(DirectoryInfo SolutionDir) + { + // Enumerate all the projects in the same directory as the solution. If there's one here, we don't need to consider any other. + List ProjectFiles = new List(SolutionDir.EnumerateFiles("*.uproject")); + if (ProjectFiles.Count == 0) + { + // Build a list of all the parent directories for projects. This includes the UE4 root, plus any directories referenced via .uprojectdirs files. + List ParentProjectDirs = new List(); + ParentProjectDirs.Add(SolutionDir); + + // Read all the .uprojectdirs files + foreach (FileInfo ProjectDirsFile in SolutionDir.EnumerateFiles("*.uprojectdirs")) + { + foreach (string Line in File.ReadAllLines(ProjectDirsFile.FullName)) + { + string TrimLine = Line.Trim().Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar).Trim(Path.DirectorySeparatorChar); + if (TrimLine.Length > 0 && !TrimLine.StartsWith(";")) + { + try + { + ParentProjectDirs.Add(new DirectoryInfo(Path.Combine(SolutionDir.FullName, TrimLine))); + } + catch (Exception Ex) + { + Logging.WriteLine(String.Format("EnumerateProjects: Exception trying to resolve project directory '{0}': {1}", TrimLine, Ex.Message)); + } + } + } + } + + // Add projects in any subfolders of the parent directories + HashSet CheckedParentDirs = new HashSet(StringComparer.InvariantCultureIgnoreCase); + foreach (DirectoryInfo ParentProjectDir in ParentProjectDirs) + { + if(CheckedParentDirs.Add(ParentProjectDir.FullName) && ParentProjectDir.Exists) + { + foreach (DirectoryInfo ProjectDir in ParentProjectDir.EnumerateDirectories()) + { + ProjectFiles.AddRange(ProjectDir.EnumerateFiles("*.uproject")); + } + } + } + } + return ProjectFiles; + } + /// /// Returns all the .uprojects found under the solution root folder. /// @@ -422,11 +478,17 @@ namespace UnrealVS DateTime Start = DateTime.Now; CachedUProjectRootFolder = Folder; - CachedUProjectPaths = Directory.GetFiles(Folder, "*." + UProjectExtension, SearchOption.AllDirectories); + CachedUProjectPaths = EnumerateProjects(new DirectoryInfo(Folder)).Select(x => x.FullName); CachedUProjects = null; TimeSpan TimeTaken = DateTime.Now - Start; - Logging.WriteLine(string.Format("Directory.GetFiles took {0} sec", TimeTaken.TotalSeconds)); + Logging.WriteLine(string.Format("GetUProjects: EnumerateProjects took {0} sec", TimeTaken.TotalSeconds)); + + foreach (string CachedUProjectPath in CachedUProjectPaths) + { + Logging.WriteLine(String.Format("GetUProjects: found {0}", CachedUProjectPath)); + } + Logging.WriteLine(" DONE"); } diff --git a/Engine/Source/Programs/Windows/BootstrapPackagedGame/Private/BootstrapPackagedGame.cpp b/Engine/Source/Programs/Windows/BootstrapPackagedGame/Private/BootstrapPackagedGame.cpp index e10e17b157ea..e0a2cf097ad5 100644 --- a/Engine/Source/Programs/Windows/BootstrapPackagedGame/Private/BootstrapPackagedGame.cpp +++ b/Engine/Source/Programs/Windows/BootstrapPackagedGame/Private/BootstrapPackagedGame.cpp @@ -27,15 +27,35 @@ WCHAR* ReadResourceString(HMODULE ModuleHandle, LPCWSTR Name) return Result; } -int InstallMissingPrerequisites(const WCHAR* BaseDirectory) +bool TryLoadDll(const WCHAR* ExecDirectory, const WCHAR* Name) +{ + // Try to load it from the system path + if (LoadLibrary(Name) != nullptr) + { + return true; + } + + // Try to load it from the application directory + WCHAR AppLocalPath[MAX_PATH]; + PathCombine(AppLocalPath, ExecDirectory, Name); + if (LoadLibrary(AppLocalPath) != nullptr) + { + return true; + } + + // Otherwise fail + return false; +} + +int InstallMissingPrerequisites(const WCHAR* BaseDirectory, const WCHAR* ExecDirectory) { // Look for missing prerequisites WCHAR MissingPrerequisites[1024] = { 0, }; - if(LoadLibrary(L"MSVCP140.DLL") == NULL || LoadLibrary(L"ucrtbase.dll") == NULL) + if(!TryLoadDll(ExecDirectory, L"MSVCP140.DLL") || !TryLoadDll(ExecDirectory, L"ucrtbase.dll")) { wcscat_s(MissingPrerequisites, TEXT("Microsoft Visual C++ 2015 Runtime\n")); } - if(LoadLibrary(L"XINPUT1_3.DLL") == NULL) + if(!TryLoadDll(ExecDirectory, L"XINPUT1_3.DLL")) { wcscat_s(MissingPrerequisites, TEXT("DirectX Runtime\n")); } @@ -107,7 +127,7 @@ int SpawnTarget(WCHAR* CmdLine) WCHAR* Buffer = new WCHAR[wcslen(CmdLine) + 50]; wsprintf(Buffer, L"Couldn't start:\n%s\nCreateProcess() returned %x.", CmdLine, ErrorCode); MessageBoxW(NULL, Buffer, NULL, MB_OK); - delete Buffer; + delete[] Buffer; return 9005; } @@ -143,18 +163,26 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, TCHAR* CmdLine return 9000; } + // Get the directory containing the target to be executed + WCHAR* TempExecDirectory = new WCHAR[wcslen(BaseDirectory) + wcslen(ExecFile) + 20]; + wsprintf(TempExecDirectory, L"%s\\%s", BaseDirectory, ExecFile); + WCHAR ExecDirectory[MAX_PATH]; + PathCanonicalize(ExecDirectory, TempExecDirectory); + delete[] TempExecDirectory; + PathRemoveFileSpec(ExecDirectory); + // Create a full command line for the program to run WCHAR* BaseArgs = ReadResourceString(hInstance, MAKEINTRESOURCE(IDI_EXEC_ARGS)); WCHAR* ChildCmdLine = new WCHAR[wcslen(BaseDirectory) + wcslen(ExecFile) + wcslen(BaseArgs) + wcslen(CmdLine) + 20]; wsprintf(ChildCmdLine, L"\"%s\\%s\" %s %s", BaseDirectory, ExecFile, BaseArgs, CmdLine); - delete BaseArgs; - delete ExecFile; + delete[] BaseArgs; + delete[] ExecFile; // Install the prerequisites - int ExitCode = InstallMissingPrerequisites(BaseDirectory); + int ExitCode = InstallMissingPrerequisites(BaseDirectory, ExecDirectory); if(ExitCode != 0) { - delete ChildCmdLine; + delete[] ChildCmdLine; return ExitCode; } @@ -162,10 +190,10 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, TCHAR* CmdLine ExitCode = SpawnTarget(ChildCmdLine); if(ExitCode != 0) { - delete ChildCmdLine; + delete[] ChildCmdLine; return ExitCode; } - delete ChildCmdLine; + delete[] ChildCmdLine; return ExitCode; } diff --git a/Engine/Source/Runtime/AIModule/Classes/AIController.h b/Engine/Source/Runtime/AIModule/Classes/AIController.h index 720194fc2fc3..82b76262c003 100644 --- a/Engine/Source/Runtime/AIModule/Classes/AIController.h +++ b/Engine/Source/Runtime/AIModule/Classes/AIController.h @@ -116,10 +116,9 @@ public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AI) uint32 bSetControlRotationFromPawnOrientation:1; -private_subobject: +private: /** Component used for moving along a path. */ - DEPRECATED_FORGAME(4.6, "PathFollowingComponent should not be accessed directly, please use GetPathFollowingComponent() function instead. PathFollowingComponent will soon be private and your code will not compile.") UPROPERTY(VisibleDefaultsOnly, Category = AI) UPathFollowingComponent* PathFollowingComponent; @@ -129,12 +128,10 @@ public: UPROPERTY(BlueprintReadWrite, Category = AI) UBrainComponent* BrainComponent; - DEPRECATED_FORGAME(4.8, "PerceptionComponent should not be accessed directly, please use GetAIPerceptionComponent() function instead. PerceptionComponent will soon be private and your code will not compile.") UPROPERTY(VisibleDefaultsOnly, Category = AI) UAIPerceptionComponent* PerceptionComponent; -private_subobject: - DEPRECATED_FORGAME(4.6, "ActionsComp should not be accessed directly, please use GetActionsComp() function instead. ActionsComp will soon be private and your code will not compile.") +private: UPROPERTY(BlueprintReadOnly, Category = AI, meta = (AllowPrivateAccess = "true")) UPawnActionsComponent* ActionsComp; @@ -435,13 +432,13 @@ public: public: /** Returns PathFollowingComponent subobject **/ UFUNCTION(BlueprintCallable, Category="AI|Navigation") - UPathFollowingComponent* GetPathFollowingComponent() const; + UPathFollowingComponent* GetPathFollowingComponent() const { return PathFollowingComponent; } /** Returns ActionsComp subobject **/ - UPawnActionsComponent* GetActionsComp() const; + UPawnActionsComponent* GetActionsComp() const { return ActionsComp; } UFUNCTION(BlueprintPure, Category = "AI|Perception") - UAIPerceptionComponent* GetAIPerceptionComponent(); + UAIPerceptionComponent* GetAIPerceptionComponent() { return PerceptionComponent; } - const UAIPerceptionComponent* GetAIPerceptionComponent() const; + const UAIPerceptionComponent* GetAIPerceptionComponent() const { return PerceptionComponent; } UBrainComponent* GetBrainComponent() const { return BrainComponent; } const UBlackboardComponent* GetBlackboardComponent() const { return Blackboard; } diff --git a/Engine/Source/Runtime/AIModule/Classes/AITypes.h b/Engine/Source/Runtime/AIModule/Classes/AITypes.h index ce9b76510cff..7bd713a03091 100644 --- a/Engine/Source/Runtime/AIModule/Classes/AITypes.h +++ b/Engine/Source/Runtime/AIModule/Classes/AITypes.h @@ -584,3 +584,17 @@ protected: /** custom user data: flags */ int32 UserFlags; }; + +UENUM() +enum class EGenericAICheck : uint8 +{ + Less, + LessOrEqual, + Equal, + NotEqual, + GreaterOrEqual, + Greater, + IsTrue, + + MAX UMETA(Hidden) +}; \ No newline at end of file diff --git a/Engine/Source/Runtime/AIModule/Classes/BehaviorTree/BTCompositeNode.h b/Engine/Source/Runtime/AIModule/Classes/BehaviorTree/BTCompositeNode.h index 1a091d7da09f..314bd82efcd8 100644 --- a/Engine/Source/Runtime/AIModule/Classes/BehaviorTree/BTCompositeNode.h +++ b/Engine/Source/Runtime/AIModule/Classes/BehaviorTree/BTCompositeNode.h @@ -184,6 +184,15 @@ protected: /** if set, NotifyNodeDeactivation will be called */ uint8 bUseNodeDeactivationNotify : 1; + /** if set, CanNotifyDecoratorsOnActivation will be called */ + uint8 bUseDecoratorsActivationCheck : 1; + + /** if set, CanNotifyDecoratorsOnDeactivation will be called */ + uint8 bUseDecoratorsDeactivationCheck : 1; + + /** if set, CanNotifyDecoratorsOnFailedActivation will be called */ + uint8 bUseDecoratorsFailedActivationCheck : 1; + /** called just after child execution, allows to modify result */ virtual void NotifyChildExecution(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, int32 ChildIdx, EBTNodeResult::Type& NodeResult) const; @@ -193,6 +202,15 @@ protected: /** called when start leaves this node */ virtual void NotifyNodeDeactivation(FBehaviorTreeSearchData& SearchData, EBTNodeResult::Type& NodeResult) const; + /** check if NotifyDecoratorsOnActivation is allowed, requires bUseDecoratorsActivationCheck flag */ + virtual bool CanNotifyDecoratorsOnActivation(FBehaviorTreeSearchData& SearchData, int32 ChildIdx) const; + + /** check if NotifyDecoratorsOnDeactivation is allowed, requires bUseDecoratorsDeactivationCheck flag */ + virtual bool CanNotifyDecoratorsOnDeactivation(FBehaviorTreeSearchData& SearchData, int32 ChildIdx, EBTNodeResult::Type& NodeResult) const; + + /** check if NotifyDecoratorsOnFailedActivation is allowed, requires bUseDecoratorsActivationCheck flag */ + virtual bool CanNotifyDecoratorsOnFailedActivation(FBehaviorTreeSearchData& SearchData, int32 ChildIdx, EBTNodeResult::Type& NodeResult) const; + /** runs through decorators on given child node and notify them about activation */ void NotifyDecoratorsOnActivation(FBehaviorTreeSearchData& SearchData, int32 ChildIdx) const; diff --git a/Engine/Source/Runtime/AIModule/Classes/BehaviorTree/BehaviorTreeTypes.h b/Engine/Source/Runtime/AIModule/Classes/BehaviorTree/BehaviorTreeTypes.h index 44910e6c9476..7a1b1881a1c2 100644 --- a/Engine/Source/Runtime/AIModule/Classes/BehaviorTree/BehaviorTreeTypes.h +++ b/Engine/Source/Runtime/AIModule/Classes/BehaviorTree/BehaviorTreeTypes.h @@ -420,6 +420,9 @@ struct FBehaviorTreeSearchData /** assign unique Id number */ void AssignSearchId(); + /** clear state of search */ + void Reset(); + FBehaviorTreeSearchData(UBehaviorTreeComponent& InOwnerComp) : OwnerComp(InOwnerComp), bPostponeSearch(false), bSearchInProgress(false) {} diff --git a/Engine/Source/Runtime/AIModule/Classes/BehaviorTree/BlackboardComponent.h b/Engine/Source/Runtime/AIModule/Classes/BehaviorTree/BlackboardComponent.h index d8d093b65046..c8889279b5da 100644 --- a/Engine/Source/Runtime/AIModule/Classes/BehaviorTree/BlackboardComponent.h +++ b/Engine/Source/Runtime/AIModule/Classes/BehaviorTree/BlackboardComponent.h @@ -307,11 +307,11 @@ bool UBlackboardComponent::SetValue(FBlackboard::FKey KeyID, typename TDataClass return false; } - const uint16 DataOffset = EntryInfo->KeyType->IsInstanced() ? sizeof(FBlackboardInstancedKeyMemory) : 0; + const uint16 DataOffset = EntryInfo->KeyType->HasInstance() ? sizeof(FBlackboardInstancedKeyMemory) : 0; uint8* RawData = GetKeyRawData(KeyID) + DataOffset; if (RawData) { - UBlackboardKeyType* KeyOb = EntryInfo->KeyType->IsInstanced() ? KeyInstances[KeyID] : EntryInfo->KeyType; + UBlackboardKeyType* KeyOb = EntryInfo->KeyType->HasInstance() ? KeyInstances[KeyID] : EntryInfo->KeyType; const bool bChanged = TDataClass::SetValue((TDataClass*)KeyOb, RawData, Value); if (bChanged) { @@ -328,7 +328,7 @@ bool UBlackboardComponent::SetValue(FBlackboard::FKey KeyID, typename TDataClass const int32 OtherKeyID = OtherBlackboardAsset ? OtherBlackboardAsset->GetKeyID(EntryInfo->EntryName) : FBlackboard::InvalidKey; if (OtherKeyID != FBlackboard::InvalidKey) { - UBlackboardKeyType* OtherKeyOb = EntryInfo->KeyType->IsInstanced() ? OtherBlackboard->KeyInstances[OtherKeyID] : EntryInfo->KeyType; + UBlackboardKeyType* OtherKeyOb = EntryInfo->KeyType->HasInstance() ? OtherBlackboard->KeyInstances[OtherKeyID] : EntryInfo->KeyType; uint8* OtherRawData = OtherBlackboard->GetKeyRawData(OtherKeyID) + DataOffset; TDataClass::SetValue((TDataClass*)OtherKeyOb, OtherRawData, Value); @@ -361,8 +361,8 @@ typename TDataClass::FDataType UBlackboardComponent::GetValue(FBlackboard::FKey return TDataClass::InvalidValue; } - UBlackboardKeyType* KeyOb = EntryInfo->KeyType->IsInstanced() ? KeyInstances[KeyID] : EntryInfo->KeyType; - const uint16 DataOffset = EntryInfo->KeyType->IsInstanced() ? sizeof(FBlackboardInstancedKeyMemory) : 0; + UBlackboardKeyType* KeyOb = EntryInfo->KeyType->HasInstance() ? KeyInstances[KeyID] : EntryInfo->KeyType; + const uint16 DataOffset = EntryInfo->KeyType->HasInstance() ? sizeof(FBlackboardInstancedKeyMemory) : 0; const uint8* RawData = GetKeyRawData(KeyID) + DataOffset; return RawData ? TDataClass::GetValue((TDataClass*)KeyOb, RawData) : TDataClass::InvalidValue; diff --git a/Engine/Source/Runtime/AIModule/Classes/BehaviorTree/Composites/BTComposite_SimpleParallel.h b/Engine/Source/Runtime/AIModule/Classes/BehaviorTree/Composites/BTComposite_SimpleParallel.h index adaf37ac8ad1..2da61e3e7872 100644 --- a/Engine/Source/Runtime/AIModule/Classes/BehaviorTree/Composites/BTComposite_SimpleParallel.h +++ b/Engine/Source/Runtime/AIModule/Classes/BehaviorTree/Composites/BTComposite_SimpleParallel.h @@ -64,6 +64,7 @@ class AIMODULE_API UBTComposite_SimpleParallel : public UBTCompositeNode virtual void NotifyChildExecution(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, int32 ChildIdx, EBTNodeResult::Type& NodeResult) const override; virtual void NotifyNodeDeactivation(FBehaviorTreeSearchData& SearchData, EBTNodeResult::Type& NodeResult) const override; + virtual bool CanNotifyDecoratorsOnDeactivation(FBehaviorTreeSearchData& SearchData, int32 ChildIdx, EBTNodeResult::Type& NodeResult) const override; virtual bool CanPushSubtree(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, int32 ChildIdx) const override; virtual void SetChildOverride(FBehaviorTreeSearchData& SearchData, int8 Index) const override; virtual uint16 GetInstanceMemorySize() const override; diff --git a/Engine/Source/Runtime/AIModule/Classes/BehaviorTree/Decorators/BTDecorator_TimeLimit.h b/Engine/Source/Runtime/AIModule/Classes/BehaviorTree/Decorators/BTDecorator_TimeLimit.h index 69bc20b5945c..4e41c66c2492 100644 --- a/Engine/Source/Runtime/AIModule/Classes/BehaviorTree/Decorators/BTDecorator_TimeLimit.h +++ b/Engine/Source/Runtime/AIModule/Classes/BehaviorTree/Decorators/BTDecorator_TimeLimit.h @@ -27,7 +27,6 @@ class AIMODULE_API UBTDecorator_TimeLimit : public UBTDecorator #endif // WITH_EDITOR protected: - - virtual void OnBecomeRelevant(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override; + virtual void OnNodeActivation(FBehaviorTreeSearchData& SearchData) override; virtual void TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds) override; }; diff --git a/Engine/Source/Runtime/AIModule/Classes/EnvironmentQuery/EQSTestingPawn.h b/Engine/Source/Runtime/AIModule/Classes/EnvironmentQuery/EQSTestingPawn.h index 889a45c9f122..00c181c49431 100644 --- a/Engine/Source/Runtime/AIModule/Classes/EnvironmentQuery/EQSTestingPawn.h +++ b/Engine/Source/Runtime/AIModule/Classes/EnvironmentQuery/EQSTestingPawn.h @@ -67,9 +67,8 @@ class AIMODULE_API AEQSTestingPawn : public ACharacter, public IEQSQueryResultSo #if WITH_EDITORONLY_DATA -private_subobject: +private: /** Editor Preview */ - DEPRECATED_FORGAME(4.6, "EdRenderComp should not be accessed directly, please use GetEdRenderComp() function instead. EdRenderComp will soon be private and your code will not compile.") UPROPERTY(Transient) UEQSRenderingComponent* EdRenderComp; #endif // WITH_EDITORONLY_DATA @@ -111,6 +110,6 @@ protected: public: #if WITH_EDITORONLY_DATA /** Returns EdRenderComp subobject **/ - UEQSRenderingComponent* GetEdRenderComp(); + UEQSRenderingComponent* GetEdRenderComp() { return EdRenderComp; } #endif }; diff --git a/Engine/Source/Runtime/AIModule/Classes/EnvironmentQuery/EnvQueryManager.h b/Engine/Source/Runtime/AIModule/Classes/EnvironmentQuery/EnvQueryManager.h index 311001b0c1a0..51f7ef417ba4 100644 --- a/Engine/Source/Runtime/AIModule/Classes/EnvironmentQuery/EnvQueryManager.h +++ b/Engine/Source/Runtime/AIModule/Classes/EnvironmentQuery/EnvQueryManager.h @@ -226,8 +226,8 @@ class AIMODULE_API UEnvQueryManager : public UObject, public FTickableGameObject static UEnvQueryManager* GetCurrent(UWorld* World); static UEnvQueryManager* GetCurrent(const UObject* WorldContextObject); - UFUNCTION(BlueprintCallable, Category = "AI|EQS", meta = (WorldContext = "WorldContext", AdvancedDisplay = "WrapperClass")) - static UEnvQueryInstanceBlueprintWrapper* RunEQSQuery(UObject* WorldContext, UEnvQuery* QueryTemplate, UObject* Querier, TEnumAsByte RunMode, TSubclassOf WrapperClass); + UFUNCTION(BlueprintCallable, Category = "AI|EQS", meta = (WorldContext = "WorldContextObject", AdvancedDisplay = "WrapperClass")) + static UEnvQueryInstanceBlueprintWrapper* RunEQSQuery(UObject* WorldContextObject, UEnvQuery* QueryTemplate, UObject* Querier, TEnumAsByte RunMode, TSubclassOf WrapperClass); void RegisterActiveWrapper(UEnvQueryInstanceBlueprintWrapper& Wrapper); void UnregisterActiveWrapper(UEnvQueryInstanceBlueprintWrapper& Wrapper); diff --git a/Engine/Source/Runtime/AIModule/Classes/EnvironmentQuery/EnvQueryTypes.h b/Engine/Source/Runtime/AIModule/Classes/EnvironmentQuery/EnvQueryTypes.h index 3028a9a65bc8..f03a55d6f8df 100644 --- a/Engine/Source/Runtime/AIModule/Classes/EnvironmentQuery/EnvQueryTypes.h +++ b/Engine/Source/Runtime/AIModule/Classes/EnvironmentQuery/EnvQueryTypes.h @@ -44,6 +44,9 @@ DECLARE_CYCLE_STAT_EXTERN(TEXT("Load Time"),STAT_AI_EQS_LoadTime,STATGROUP_AI_EQ DECLARE_CYCLE_STAT_EXTERN(TEXT("Execute One Step Time"),STAT_AI_EQS_ExecuteOneStep,STATGROUP_AI_EQS, ); DECLARE_CYCLE_STAT_EXTERN(TEXT("Generator Time"),STAT_AI_EQS_GeneratorTime,STATGROUP_AI_EQS, ); DECLARE_CYCLE_STAT_EXTERN(TEXT("Test Time"),STAT_AI_EQS_TestTime,STATGROUP_AI_EQS, ); +DECLARE_CYCLE_STAT_EXTERN(TEXT("EQS Debug StoreQuery"), STAT_AI_EQS_Debug_StoreQuery, STATGROUP_AI_EQS, ); +DECLARE_CYCLE_STAT_EXTERN(TEXT("EQS Debug StoreTickTime"), STAT_AI_EQS_Debug_StoreTickTime, STATGROUP_AI_EQS, ); +DECLARE_CYCLE_STAT_EXTERN(TEXT("EQS Debug StoreStats"), STAT_AI_EQS_Debug_StoreStats, STATGROUP_AI_EQS, ); DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("Num Instances"),STAT_AI_EQS_NumInstances,STATGROUP_AI_EQS, ); DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("Num Items"),STAT_AI_EQS_NumItems,STATGROUP_AI_EQS, ); DECLARE_MEMORY_STAT_EXTERN(TEXT("Instance memory"),STAT_AI_EQS_InstanceMemory,STATGROUP_AI_EQS, AIMODULE_API); @@ -485,7 +488,7 @@ struct AIMODULE_API FEnvQueryItem template <> struct TIsZeroConstructType { enum { Value = true }; }; -USTRUCT() +USTRUCT(BlueprintType) struct AIMODULE_API FEnvQueryResult { GENERATED_USTRUCT_BODY() @@ -702,7 +705,7 @@ class AIMODULE_API UEnvQueryTypes : public UObject public: /** special test value assigned to items skipped by condition check */ - static float SkippedItemValue; + static const float SkippedItemValue; /** special value used for executing query steps to prevent them from being time sliced */ static float UnlimitedStepTime; diff --git a/Engine/Source/Runtime/AIModule/Classes/GenericTeamAgentInterface.h b/Engine/Source/Runtime/AIModule/Classes/GenericTeamAgentInterface.h index b11c88b5c5d3..bc995fc6d607 100644 --- a/Engine/Source/Runtime/AIModule/Classes/GenericTeamAgentInterface.h +++ b/Engine/Source/Runtime/AIModule/Classes/GenericTeamAgentInterface.h @@ -19,7 +19,7 @@ namespace ETeamAttitude }; } -USTRUCT() +USTRUCT(BlueprintType) struct AIMODULE_API FGenericTeamId { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/AIModule/Classes/Navigation/NavLocalGridManager.h b/Engine/Source/Runtime/AIModule/Classes/Navigation/NavLocalGridManager.h index 2c9ac36507fd..54e78ed34411 100644 --- a/Engine/Source/Runtime/AIModule/Classes/Navigation/NavLocalGridManager.h +++ b/Engine/Source/Runtime/AIModule/Classes/Navigation/NavLocalGridManager.h @@ -80,28 +80,28 @@ public: /** get version of grid data, incremented with each rebuild */ int32 GetVersion() const { return VersionNum; } - UFUNCTION(BlueprintCallable, Category = "AI|Navigation", meta = (WorldContext = "WorldContext")) - static bool SetLocalNavigationGridDensity(UObject* WorldContext, float CellSize); + UFUNCTION(BlueprintCallable, Category = "AI|Navigation", meta = (WorldContext = "WorldContextObject")) + static bool SetLocalNavigationGridDensity(UObject* WorldContextObject, float CellSize); /** creates new grid data for single point */ - UFUNCTION(BlueprintCallable, Category = "AI|Navigation", meta = (WorldContext = "WorldContext")) - static int32 AddLocalNavigationGridForPoint(UObject* WorldContext, const FVector& Location, const int32 Radius2D = 5, const float Height = 100.0f, bool bRebuildGrids = true); + UFUNCTION(BlueprintCallable, Category = "AI|Navigation", meta = (WorldContext = "WorldContextObject")) + static int32 AddLocalNavigationGridForPoint(UObject* WorldContextObject, const FVector& Location, const int32 Radius2D = 5, const float Height = 100.0f, bool bRebuildGrids = true); /** creates single grid data for set of points */ - UFUNCTION(BlueprintCallable, Category = "AI|Navigation", meta = (WorldContext = "WorldContext")) - static int32 AddLocalNavigationGridForPoints(UObject* WorldContext, const TArray& Locations, const int32 Radius2D = 5, const float Height = 100.0f, bool bRebuildGrids = true); + UFUNCTION(BlueprintCallable, Category = "AI|Navigation", meta = (WorldContext = "WorldContextObject")) + static int32 AddLocalNavigationGridForPoints(UObject* WorldContextObject, const TArray& Locations, const int32 Radius2D = 5, const float Height = 100.0f, bool bRebuildGrids = true); - UFUNCTION(BlueprintCallable, Category = "AI|Navigation", meta = (WorldContext = "WorldContext")) - static int32 AddLocalNavigationGridForBox(UObject* WorldContext, const FVector& Location, FVector Extent = FVector(1,1,1), FRotator Rotation = FRotator::ZeroRotator, const int32 Radius2D = 5, const float Height = 100.0f, bool bRebuildGrids = true); + UFUNCTION(BlueprintCallable, Category = "AI|Navigation", meta = (WorldContext = "WorldContextObject")) + static int32 AddLocalNavigationGridForBox(UObject* WorldContextObject, const FVector& Location, FVector Extent = FVector(1,1,1), FRotator Rotation = FRotator::ZeroRotator, const int32 Radius2D = 5, const float Height = 100.0f, bool bRebuildGrids = true); - UFUNCTION(BlueprintCallable, Category = "AI|Navigation", meta = (WorldContext = "WorldContext")) - static int32 AddLocalNavigationGridForCapsule(UObject* WorldContext, const FVector& Location, float CapsuleRadius, float CapsuleHalfHeight, const int32 Radius2D = 5, const float Height = 100.0f, bool bRebuildGrids = true); + UFUNCTION(BlueprintCallable, Category = "AI|Navigation", meta = (WorldContext = "WorldContextObject")) + static int32 AddLocalNavigationGridForCapsule(UObject* WorldContextObject, const FVector& Location, float CapsuleRadius, float CapsuleHalfHeight, const int32 Radius2D = 5, const float Height = 100.0f, bool bRebuildGrids = true); - UFUNCTION(BlueprintCallable, Category = "AI|Navigation", meta = (WorldContext = "WorldContext")) - static void RemoveLocalNavigationGrid(UObject* WorldContext, int32 GridId, bool bRebuildGrids = true); + UFUNCTION(BlueprintCallable, Category = "AI|Navigation", meta = (WorldContext = "WorldContextObject")) + static void RemoveLocalNavigationGrid(UObject* WorldContextObject, int32 GridId, bool bRebuildGrids = true); - UFUNCTION(BlueprintCallable, Category = "AI|Navigation", meta = (WorldContext = "WorldContext")) - static bool FindLocalNavigationGridPath(UObject* WorldContext, const FVector& Start, const FVector& End, TArray& PathPoints); + UFUNCTION(BlueprintCallable, Category = "AI|Navigation", meta = (WorldContext = "WorldContextObject")) + static bool FindLocalNavigationGridPath(UObject* WorldContextObject, const FVector& Start, const FVector& End, TArray& PathPoints); static UNavLocalGridManager* GetCurrent(UWorld* World); static UNavLocalGridManager* GetCurrent(const UObject* WorldContextObject); diff --git a/Engine/Source/Runtime/AIModule/Classes/Perception/AIPerceptionComponent.h b/Engine/Source/Runtime/AIModule/Classes/Perception/AIPerceptionComponent.h index 9318d2cc51f1..cfde7d6a4ea6 100644 --- a/Engine/Source/Runtime/AIModule/Classes/Perception/AIPerceptionComponent.h +++ b/Engine/Source/Runtime/AIModule/Classes/Perception/AIPerceptionComponent.h @@ -313,6 +313,7 @@ protected: void UpdatePerceptionFilter(FAISenseID Channel, bool bNewValue); FActorPerceptionContainer& GetPerceptualData() { return PerceptualData; } + const FActorPerceptionContainer& GetPerceptualData() const { return PerceptualData; } /** called to clean up on owner's end play or destruction */ virtual void CleanUp(); diff --git a/Engine/Source/Runtime/AIModule/Classes/Perception/AIPerceptionSystem.h b/Engine/Source/Runtime/AIModule/Classes/Perception/AIPerceptionSystem.h index 63358af0bdba..da5b62a47d4a 100644 --- a/Engine/Source/Runtime/AIModule/Classes/Perception/AIPerceptionSystem.h +++ b/Engine/Source/Runtime/AIModule/Classes/Perception/AIPerceptionSystem.h @@ -132,8 +132,8 @@ public: UFUNCTION(BlueprintCallable, Category = "AI|Perception") void ReportEvent(UAISenseEvent* PerceptionEvent); - UFUNCTION(BlueprintCallable, Category = "AI|Perception", meta = (WorldContext="WorldContext")) - static void ReportPerceptionEvent(UObject* WorldContext, UAISenseEvent* PerceptionEvent); + UFUNCTION(BlueprintCallable, Category = "AI|Perception", meta = (WorldContext="WorldContextObject")) + static void ReportPerceptionEvent(UObject* WorldContextObject, UAISenseEvent* PerceptionEvent); template void RegisterSource(AActor& SourceActor); @@ -155,13 +155,13 @@ public: static void MakeNoiseImpl(AActor* NoiseMaker, float Loudness, APawn* NoiseInstigator, const FVector& NoiseLocation, float MaxRange, FName Tag); - UFUNCTION(BlueprintCallable, Category = "AI|Perception", meta = (WorldContext="WorldContext")) - static bool RegisterPerceptionStimuliSource(UObject* WorldContext, TSubclassOf Sense, AActor* Target); + UFUNCTION(BlueprintCallable, Category = "AI|Perception", meta = (WorldContext="WorldContextObject")) + static bool RegisterPerceptionStimuliSource(UObject* WorldContextObject, TSubclassOf Sense, AActor* Target); FAISenseID RegisterSenseClass(TSubclassOf SenseClass); - UFUNCTION(BlueprintCallable, Category = "AI|Perception", meta = (WorldContext="WorldContext")) - static TSubclassOf GetSenseClassForStimulus(UObject* WorldContext, const FAIStimulus& Stimulus); + UFUNCTION(BlueprintCallable, Category = "AI|Perception", meta = (WorldContext="WorldContextObject")) + static TSubclassOf GetSenseClassForStimulus(UObject* WorldContextObject, const FAIStimulus& Stimulus); protected: diff --git a/Engine/Source/Runtime/AIModule/Classes/Perception/AIPerceptionTypes.h b/Engine/Source/Runtime/AIModule/Classes/Perception/AIPerceptionTypes.h index 22663bc9a5da..3f8f7d92bd58 100644 --- a/Engine/Source/Runtime/AIModule/Classes/Perception/AIPerceptionTypes.h +++ b/Engine/Source/Runtime/AIModule/Classes/Perception/AIPerceptionTypes.h @@ -201,7 +201,7 @@ public: #endif // !(UE_BUILD_SHIPPING || UE_BUILD_TEST) }; -USTRUCT() +USTRUCT(BlueprintType) struct AIMODULE_API FAISenseAffiliationFilter { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/AIModule/Classes/Perception/AISense_Damage.h b/Engine/Source/Runtime/AIModule/Classes/Perception/AISense_Damage.h index 1d1c7550776f..916b4ed45191 100644 --- a/Engine/Source/Runtime/AIModule/Classes/Perception/AISense_Damage.h +++ b/Engine/Source/Runtime/AIModule/Classes/Perception/AISense_Damage.h @@ -10,7 +10,7 @@ class IAIPerceptionListenerInterface; class UAISenseEvent; -USTRUCT() +USTRUCT(BlueprintType) struct AIMODULE_API FAIDamageEvent { GENERATED_USTRUCT_BODY() @@ -65,8 +65,8 @@ public: virtual void RegisterWrappedEvent(UAISenseEvent& PerceptionEvent) override; /** EventLocation will be reported as Instigator's location at the moment of event happening*/ - UFUNCTION(BlueprintCallable, Category = "AI|Perception", meta = (WorldContext="WorldContext", AdvancedDisplay="HitLocation")) - static void ReportDamageEvent(UObject* WorldContext, AActor* DamagedActor, AActor* Instigator, float DamageAmount, FVector EventLocation, FVector HitLocation); + UFUNCTION(BlueprintCallable, Category = "AI|Perception", meta = (WorldContext="WorldContextObject", AdvancedDisplay="HitLocation")) + static void ReportDamageEvent(UObject* WorldContextObject, AActor* DamagedActor, AActor* Instigator, float DamageAmount, FVector EventLocation, FVector HitLocation); protected: virtual float Update() override; diff --git a/Engine/Source/Runtime/AIModule/Classes/Perception/AISense_Hearing.h b/Engine/Source/Runtime/AIModule/Classes/Perception/AISense_Hearing.h index 667543ebf177..b50a28e999ff 100644 --- a/Engine/Source/Runtime/AIModule/Classes/Perception/AISense_Hearing.h +++ b/Engine/Source/Runtime/AIModule/Classes/Perception/AISense_Hearing.h @@ -11,7 +11,7 @@ class UAISenseConfig_Hearing; class UAISenseEvent; -USTRUCT() +USTRUCT(BlueprintType) struct AIMODULE_API FAINoiseEvent { GENERATED_USTRUCT_BODY() @@ -100,8 +100,8 @@ public: * @param MaxRange Max range at which the sound can be heard, multiplied by Loudness. Values <= 0 mean no limit (still limited by listener's range however). * @param Tag Identifier for the event. */ - UFUNCTION(BlueprintCallable, Category = "AI|Perception", meta = (WorldContext="WorldContext")) - static void ReportNoiseEvent(UObject* WorldContext, FVector NoiseLocation, float Loudness = 1.f, AActor* Instigator = nullptr, float MaxRange = 0.f, FName Tag = NAME_None); + UFUNCTION(BlueprintCallable, Category = "AI|Perception", meta = (WorldContext="WorldContextObject")) + static void ReportNoiseEvent(UObject* WorldContextObject, FVector NoiseLocation, float Loudness = 1.f, AActor* Instigator = nullptr, float MaxRange = 0.f, FName Tag = NAME_None); protected: virtual float Update() override; diff --git a/Engine/Source/Runtime/AIModule/Classes/Tasks/AITask_MoveTo.h b/Engine/Source/Runtime/AIModule/Classes/Tasks/AITask_MoveTo.h index e03edcfe7e7d..2ff996958eb5 100644 --- a/Engine/Source/Runtime/AIModule/Classes/Tasks/AITask_MoveTo.h +++ b/Engine/Source/Runtime/AIModule/Classes/Tasks/AITask_MoveTo.h @@ -36,6 +36,10 @@ public: DEPRECATED(4.12, "This function is now depreacted, please use version with FAIMoveRequest parameter") void SetUp(AAIController* Controller, FVector GoalLocation, AActor* GoalActor = nullptr, float AcceptanceRadius = -1.f, bool bUsePathfinding = true, EAIOptionFlag::Type StopOnOverlap = EAIOptionFlag::Default, EAIOptionFlag::Type AcceptPartialPath = EAIOptionFlag::Default); + /** Allows custom move request tweaking. Note that all MoveRequest need to + * be performed before PerformMove is called. */ + FAIMoveRequest& GetMoveRequestRef() { return MoveRequest; } + protected: UPROPERTY(BlueprintAssignable) FGenericGameplayTaskDelegate OnRequestFailed; diff --git a/Engine/Source/Runtime/AIModule/Private/AIController.cpp b/Engine/Source/Runtime/AIModule/Private/AIController.cpp index 24be6fb0e9ab..a527ce07e0f8 100644 --- a/Engine/Source/Runtime/AIModule/Private/AIController.cpp +++ b/Engine/Source/Runtime/AIModule/Private/AIController.cpp @@ -324,10 +324,9 @@ bool AAIController::LineOfSightTo(const AActor* Other, FVector ViewPoint, bool b } } - static FName NAME_LineOfSight = FName(TEXT("LineOfSight")); FVector TargetLocation = Other->GetTargetLocation(GetPawn()); - FCollisionQueryParams CollisionParams(NAME_LineOfSight, true, this->GetPawn()); + FCollisionQueryParams CollisionParams(SCENE_QUERY_STAT(LineOfSight), true, this->GetPawn()); CollisionParams.AddIgnoredActor(Other); bool bHit = GetWorld()->LineTraceTestByChannel(ViewPoint, TargetLocation, ECC_Visibility, CollisionParams); @@ -1063,22 +1062,6 @@ FString AAIController::GetDebugIcon() const return TEXT("/Engine/EngineResources/AICON-Green.AICON-Green"); } - -/** Returns PathFollowingComponent subobject **/ -UPathFollowingComponent* AAIController::GetPathFollowingComponent() const { return PathFollowingComponent; } -/** Returns ActionsComp subobject **/ -UPawnActionsComponent* AAIController::GetActionsComp() const { return ActionsComp; } - -UAIPerceptionComponent* AAIController::GetAIPerceptionComponent() -{ - return PerceptionComponent; -} - -const UAIPerceptionComponent* AAIController::GetAIPerceptionComponent() const -{ - return PerceptionComponent; -} - void AAIController::OnGameplayTaskResourcesClaimed(FGameplayResourceSet NewlyClaimed, FGameplayResourceSet FreshlyReleased) { if (BrainComponent) diff --git a/Engine/Source/Runtime/AIModule/Private/BehaviorTree/BTCompositeNode.cpp b/Engine/Source/Runtime/AIModule/Private/BehaviorTree/BTCompositeNode.cpp index 5f14cb50ae5e..a45083b741b7 100644 --- a/Engine/Source/Runtime/AIModule/Private/BehaviorTree/BTCompositeNode.cpp +++ b/Engine/Source/Runtime/AIModule/Private/BehaviorTree/BTCompositeNode.cpp @@ -13,6 +13,9 @@ UBTCompositeNode::UBTCompositeNode(const FObjectInitializer& ObjectInitializer) bUseChildExecutionNotify = false; bUseNodeActivationNotify = false; bUseNodeDeactivationNotify = false; + bUseDecoratorsActivationCheck = false; + bUseDecoratorsDeactivationCheck = false; + bUseDecoratorsFailedActivationCheck = false; } void UBTCompositeNode::InitializeComposite(uint16 InLastExecutionIndex) @@ -40,7 +43,12 @@ int32 UBTCompositeNode::FindChildToExecute(FBehaviorTreeSearchData& SearchData, else { LastResult = EBTNodeResult::Failed; - NotifyDecoratorsOnFailedActivation(SearchData, ChildIdx, LastResult); + + const bool bCanNotify = !bUseDecoratorsFailedActivationCheck || CanNotifyDecoratorsOnFailedActivation(SearchData, ChildIdx, LastResult); + if (bCanNotify) + { + NotifyDecoratorsOnFailedActivation(SearchData, ChildIdx, LastResult); + } } ChildIdx = GetNextChild(SearchData, ChildIdx, LastResult); @@ -87,7 +95,11 @@ void UBTCompositeNode::OnChildActivation(FBehaviorTreeSearchData& SearchData, in // pass to decorators before changing current child in node memory // so they can access previously executed one if needed - NotifyDecoratorsOnActivation(SearchData, ChildIndex); + const bool bCanNotify = !bUseDecoratorsActivationCheck || CanNotifyDecoratorsOnActivation(SearchData, ChildIndex); + if (bCanNotify) + { + NotifyDecoratorsOnActivation(SearchData, ChildIndex); + } // don't activate task services here, it's applied BEFORE aborting (e.g. abort lower pri decorator) // use UBehaviorTreeComponent::ExecuteTask instead @@ -127,7 +139,11 @@ void UBTCompositeNode::OnChildDeactivation(FBehaviorTreeSearchData& SearchData, // pass to decorators after composite is updated (so far only simple parallel uses it) // to have them working on correct result + they must be able to modify it if requested (e.g. force success) - NotifyDecoratorsOnDeactivation(SearchData, ChildIndex, NodeResult); + const bool bCanNotify = !bUseDecoratorsDeactivationCheck || CanNotifyDecoratorsOnDeactivation(SearchData, ChildIndex, NodeResult); + if (bCanNotify) + { + NotifyDecoratorsOnDeactivation(SearchData, ChildIndex, NodeResult); + } } void UBTCompositeNode::OnNodeActivation(FBehaviorTreeSearchData& SearchData) const @@ -580,6 +596,21 @@ bool UBTCompositeNode::CanPushSubtree(UBehaviorTreeComponent& OwnerComp, uint8* return true; } +bool UBTCompositeNode::CanNotifyDecoratorsOnActivation(FBehaviorTreeSearchData& SearchData, int32 ChildIdx) const +{ + return true; +} + +bool UBTCompositeNode::CanNotifyDecoratorsOnDeactivation(FBehaviorTreeSearchData& SearchData, int32 ChildIdx, EBTNodeResult::Type& NodeResult) const +{ + return true; +} + +bool UBTCompositeNode::CanNotifyDecoratorsOnFailedActivation(FBehaviorTreeSearchData& SearchData, int32 ChildIdx, EBTNodeResult::Type& NodeResult) const +{ + return true; +} + void UBTCompositeNode::DescribeRuntimeValues(const UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, EBTDescriptionVerbosity::Type Verbosity, TArray& Values) const { Super::DescribeRuntimeValues(OwnerComp, NodeMemory, Verbosity, Values); diff --git a/Engine/Source/Runtime/AIModule/Private/BehaviorTree/BTFunctionLibrary.cpp b/Engine/Source/Runtime/AIModule/Private/BehaviorTree/BTFunctionLibrary.cpp index 81252ef3e3b0..1be0fa871895 100644 --- a/Engine/Source/Runtime/AIModule/Private/BehaviorTree/BTFunctionLibrary.cpp +++ b/Engine/Source/Runtime/AIModule/Private/BehaviorTree/BTFunctionLibrary.cpp @@ -44,7 +44,7 @@ namespace FORCEINLINE UBlackboardComponent* GetBlackboard(UBTNode& BTNode) { check(BTNode.GetOuter()); - check(BTNode.GetClass()->HasAnyClassFlags(CLASS_CompiledFromBlueprint) || Cast(BTNode.GetClass()) && "This function call is valid only for BP-implemented BT nodes"); + checkf(BTNode.GetClass()->HasAnyClassFlags(CLASS_CompiledFromBlueprint) || Cast(BTNode.GetClass()), TEXT("This function call is valid only for BP-implemented BT nodes")); check(Cast(BTNode.GetOuter())); return ((UBehaviorTreeComponent*)BTNode.GetOuter())->GetBlackboardComponent(); @@ -54,7 +54,7 @@ namespace UBehaviorTreeComponent* UBTFunctionLibrary::GetOwnerComponent(UBTNode* NodeOwner) { check(NodeOwner); - check(NodeOwner->GetClass()->HasAnyClassFlags(CLASS_CompiledFromBlueprint) && "This function call is valid only for BP-implemented BT nodes"); + checkf(NodeOwner->GetClass()->HasAnyClassFlags(CLASS_CompiledFromBlueprint), TEXT("This function call is valid only for BP-implemented BT nodes")); check(NodeOwner->GetOuter()); UBehaviorTreeComponent* OwnerComp = Cast(NodeOwner->GetOuter()); diff --git a/Engine/Source/Runtime/AIModule/Private/BehaviorTree/BehaviorTreeComponent.cpp b/Engine/Source/Runtime/AIModule/Private/BehaviorTree/BehaviorTreeComponent.cpp index 6cafd1189dc3..d23667e180d3 100644 --- a/Engine/Source/Runtime/AIModule/Private/BehaviorTree/BehaviorTreeComponent.cpp +++ b/Engine/Source/Runtime/AIModule/Private/BehaviorTree/BehaviorTreeComponent.cpp @@ -288,6 +288,13 @@ void UBehaviorTreeComponent::StopTree(EBTStopMode::Type StopMode) UE_VLOG(GetOwner(), LogBehaviorTree, Warning, TEXT("StopTree was forced while waiting for tasks to finish aborting!")); } + // make sure that all nodes are getting deactivation notifies + if (InstanceStack.Num()) + { + EBTNodeResult::Type AbortedResult = EBTNodeResult::Aborted; + DeactivateUpTo(InstanceStack[0].RootNode, 0, AbortedResult); + } + // clear current state, don't touch debugger data for (int32 InstanceIndex = 0; InstanceIndex < InstanceStack.Num(); InstanceIndex++) { @@ -297,6 +304,7 @@ void UBehaviorTreeComponent::StopTree(EBTStopMode::Type StopMode) InstanceStack.Reset(); TaskMessageObservers.Reset(); + SearchData.Reset(); ExecutionRequest = FBTNodeExecutionInfo(); PendingExecution = FBTPendingExecutionInfo(); ActiveInstanceIdx = 0; diff --git a/Engine/Source/Runtime/AIModule/Private/BehaviorTree/BehaviorTreeTypes.cpp b/Engine/Source/Runtime/AIModule/Private/BehaviorTree/BehaviorTreeTypes.cpp index 57685f2540bc..049b4b4e4e29 100644 --- a/Engine/Source/Runtime/AIModule/Private/BehaviorTree/BehaviorTreeTypes.cpp +++ b/Engine/Source/Runtime/AIModule/Private/BehaviorTree/BehaviorTreeTypes.cpp @@ -277,6 +277,15 @@ void FBehaviorTreeSearchData::AssignSearchId() NextSearchId++; } +void FBehaviorTreeSearchData::Reset() +{ + PendingUpdates.Reset(); + SearchStart = FBTNodeIndex(); + SearchEnd = FBTNodeIndex(); + bSearchInProgress = false; + bPostponeSearch = false; +} + //----------------------------------------------------------------------// // FBlackboardKeySelector //----------------------------------------------------------------------// @@ -337,7 +346,7 @@ void FBlackboardKeySelector::AddObjectFilter(UObject* Owner, FName PropertyName, void FBlackboardKeySelector::AddClassFilter(UObject* Owner, FName PropertyName, TSubclassOf AllowedClass) { - const FName FilterName = MakeUniqueObjectName(Owner, UBlackboardKeyType_Class::StaticClass(), *FString::Printf(TEXT("%_Class"), *PropertyName.ToString())); + const FName FilterName = MakeUniqueObjectName(Owner, UBlackboardKeyType_Class::StaticClass(), *FString::Printf(TEXT("%s_Class"), *PropertyName.ToString())); UBlackboardKeyType_Class* FilterOb = NewObject(Owner, FilterName); FilterOb->BaseClass = AllowedClass; AllowedTypes.Add(FilterOb); @@ -345,7 +354,7 @@ void FBlackboardKeySelector::AddClassFilter(UObject* Owner, FName PropertyName, void FBlackboardKeySelector::AddEnumFilter(UObject* Owner, FName PropertyName, UEnum* AllowedEnum) { - const FName FilterName = MakeUniqueObjectName(Owner, UBlackboardKeyType_Enum::StaticClass(), *FString::Printf(TEXT("%_Enum"), *PropertyName.ToString())); + const FName FilterName = MakeUniqueObjectName(Owner, UBlackboardKeyType_Enum::StaticClass(), *FString::Printf(TEXT("%s_Enum"), *PropertyName.ToString())); UBlackboardKeyType_Enum* FilterOb = NewObject(Owner, FilterName); FilterOb->EnumType = AllowedEnum; AllowedTypes.Add(FilterOb); @@ -353,7 +362,7 @@ void FBlackboardKeySelector::AddEnumFilter(UObject* Owner, FName PropertyName, U void FBlackboardKeySelector::AddNativeEnumFilter(UObject* Owner, FName PropertyName, const FString& AllowedEnumName) { - const FName FilterName = MakeUniqueObjectName(Owner, UBlackboardKeyType_NativeEnum::StaticClass(), *FString::Printf(TEXT("%_NativeEnum"), *PropertyName.ToString())); + const FName FilterName = MakeUniqueObjectName(Owner, UBlackboardKeyType_NativeEnum::StaticClass(), *FString::Printf(TEXT("%s_NativeEnum"), *PropertyName.ToString())); UBlackboardKeyType_NativeEnum* FilterOb = NewObject(Owner, FilterName); FilterOb->EnumName = AllowedEnumName; AllowedTypes.Add(FilterOb); diff --git a/Engine/Source/Runtime/AIModule/Private/BehaviorTree/Blackboard/BlackboardKeyType.cpp b/Engine/Source/Runtime/AIModule/Private/BehaviorTree/Blackboard/BlackboardKeyType.cpp index 2188d7e0f336..4d71aa3a3e4a 100644 --- a/Engine/Source/Runtime/AIModule/Private/BehaviorTree/Blackboard/BlackboardKeyType.cpp +++ b/Engine/Source/Runtime/AIModule/Private/BehaviorTree/Blackboard/BlackboardKeyType.cpp @@ -23,7 +23,7 @@ void UBlackboardKeyType::InitializeKey(UBlackboardComponent& OwnerComp, FBlackbo if (bCreateKeyInstance) { FBlackboardInstancedKeyMemory* MyMemory = (FBlackboardInstancedKeyMemory*)RawData; - UBlackboardKeyType* KeyInstance = NewObject(&OwnerComp, GetClass(), GetFName(), RF_NoFlags, (UObject*)(this)); + UBlackboardKeyType* KeyInstance = NewObject(&OwnerComp, GetClass()); MyMemory->KeyIdx = KeyID; OwnerComp.KeyInstances[KeyID] = KeyInstance; diff --git a/Engine/Source/Runtime/AIModule/Private/BehaviorTree/Composites/BTComposite_SimpleParallel.cpp b/Engine/Source/Runtime/AIModule/Private/BehaviorTree/Composites/BTComposite_SimpleParallel.cpp index 584f922d441a..22e8d7dc0bef 100644 --- a/Engine/Source/Runtime/AIModule/Private/BehaviorTree/Composites/BTComposite_SimpleParallel.cpp +++ b/Engine/Source/Runtime/AIModule/Private/BehaviorTree/Composites/BTComposite_SimpleParallel.cpp @@ -11,6 +11,7 @@ UBTComposite_SimpleParallel::UBTComposite_SimpleParallel(const FObjectInitialize NodeName = "Simple Parallel"; bUseChildExecutionNotify = true; bUseNodeDeactivationNotify = true; + bUseDecoratorsDeactivationCheck = true; OnNextChild.BindUObject(this, &UBTComposite_SimpleParallel::GetNextChildHandler); } @@ -73,6 +74,10 @@ void UBTComposite_SimpleParallel::NotifyChildExecution(UBehaviorTreeComponent& O else if (MyMemory->bMainTaskIsActive) { MyMemory->bMainTaskIsActive = false; + + // notify decorators on main task, ignore observers updates in FakeSearchData - they are not allowed by parallel composite + FBehaviorTreeSearchData FakeSearchData(OwnerComp); + NotifyDecoratorsOnDeactivation(FakeSearchData, ChildIdx, NodeResult); const int32 MyInstanceIdx = OwnerComp.FindInstanceContainingNode(this); @@ -142,6 +147,22 @@ void UBTComposite_SimpleParallel::NotifyNodeDeactivation(FBehaviorTreeSearchData } } +bool UBTComposite_SimpleParallel::CanNotifyDecoratorsOnDeactivation(FBehaviorTreeSearchData& SearchData, int32 ChildIdx, EBTNodeResult::Type& NodeResult) const +{ + // don't pass deactivation to decorators when parallel is just switching to background tree + // decorators on running main task will be notified when their task finishes execution + if (ChildIdx == EBTParallelChild::MainTask) + { + FBTParallelMemory* MyMemory = GetNodeMemory(SearchData); + if (MyMemory->bMainTaskIsActive) + { + return false; + } + } + + return true; +} + uint16 UBTComposite_SimpleParallel::GetInstanceMemorySize() const { return sizeof(FBTParallelMemory); diff --git a/Engine/Source/Runtime/AIModule/Private/BehaviorTree/Decorators/BTDecorator_TimeLimit.cpp b/Engine/Source/Runtime/AIModule/Private/BehaviorTree/Decorators/BTDecorator_TimeLimit.cpp index b73a533f5c77..04609adde48c 100644 --- a/Engine/Source/Runtime/AIModule/Private/BehaviorTree/Decorators/BTDecorator_TimeLimit.cpp +++ b/Engine/Source/Runtime/AIModule/Private/BehaviorTree/Decorators/BTDecorator_TimeLimit.cpp @@ -6,7 +6,7 @@ UBTDecorator_TimeLimit::UBTDecorator_TimeLimit(const FObjectInitializer& ObjectI { NodeName = "TimeLimit"; TimeLimit = 5.0f; - bNotifyBecomeRelevant = true; + bNotifyActivation = true; bNotifyTick = true; bTickIntervals = true; @@ -16,11 +16,15 @@ UBTDecorator_TimeLimit::UBTDecorator_TimeLimit(const FObjectInitializer& ObjectI FlowAbortMode = EBTFlowAbortMode::Self; } -void UBTDecorator_TimeLimit::OnBecomeRelevant(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) +void UBTDecorator_TimeLimit::OnNodeActivation(FBehaviorTreeSearchData& SearchData) { - FBTAuxiliaryMemory* DecoratorMemory = GetSpecialNodeMemory(NodeMemory); - DecoratorMemory->NextTickRemainingTime = TimeLimit; - DecoratorMemory->AccumulatedDeltaTime = 0.0f; + uint8* RawMemory = SearchData.OwnerComp.GetNodeMemory(this, SearchData.OwnerComp.FindInstanceContainingNode(this)); + if (RawMemory) + { + FBTAuxiliaryMemory* DecoratorMemory = GetSpecialNodeMemory(RawMemory); + DecoratorMemory->NextTickRemainingTime = TimeLimit; + DecoratorMemory->AccumulatedDeltaTime = 0.0f; + } } void UBTDecorator_TimeLimit::TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds) diff --git a/Engine/Source/Runtime/AIModule/Private/BehaviorTree/Tasks/BTTask_MoveTo.cpp b/Engine/Source/Runtime/AIModule/Private/BehaviorTree/Tasks/BTTask_MoveTo.cpp index 27071cf8876a..db248b60c201 100644 --- a/Engine/Source/Runtime/AIModule/Private/BehaviorTree/Tasks/BTTask_MoveTo.cpp +++ b/Engine/Source/Runtime/AIModule/Private/BehaviorTree/Tasks/BTTask_MoveTo.cpp @@ -203,7 +203,7 @@ EBlackboardNotificationResult UBTTask_MoveTo::OnBlackboardValueChange(const UBla // resetting BBObserverDelegateHandle without unregistering observer since // returning EBlackboardNotificationResult::RemoveObserver here will take care of that for us - MyMemory->BBObserverDelegateHandle.Reset(); + MyMemory->BBObserverDelegateHandle.Reset(); //-V595 return EBlackboardNotificationResult::RemoveObserver; } diff --git a/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/EQSTestingPawn.cpp b/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/EQSTestingPawn.cpp index 810b43f9fa4a..29293beac998 100644 --- a/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/EQSTestingPawn.cpp +++ b/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/EQSTestingPawn.cpp @@ -350,8 +350,3 @@ void AEQSTestingPawn::PostEditMove(bool bFinished) } #endif // WITH_EDITOR - -#if WITH_EDITORONLY_DATA -/** Returns EdRenderComp subobject **/ -UEQSRenderingComponent* AEQSTestingPawn::GetEdRenderComp() { return EdRenderComp; } -#endif diff --git a/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/EnvQueryInstance.cpp b/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/EnvQueryInstance.cpp index 133ad2696fb9..61f3048b1d82 100644 --- a/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/EnvQueryInstance.cpp +++ b/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/EnvQueryInstance.cpp @@ -15,6 +15,12 @@ #include "EnvironmentQuery/Generators/EnvQueryGenerator_Composite.h" #include "AISystem.h" +#if UE_BUILD_SHIPPING +#define eqs_ensure ensure +#else +#define eqs_ensure ensureAlways +#endif + //----------------------------------------------------------------------// // FEnvQueryDebugData //----------------------------------------------------------------------// @@ -543,7 +549,7 @@ void FEnvQueryInstance::FItemIterator::HandleFailedTestResult() void FEnvQueryInstance::FItemIterator::StoreTestResult() { CheckItemPassed(); - ensureAlways(FMath::IsNaN(ItemScore) == false); + eqs_ensure(FMath::IsNaN(ItemScore) == false); #if USE_EQS_DEBUGGER Instance.NumProcessedItems++; @@ -577,7 +583,7 @@ void FEnvQueryInstance::FItemIterator::StoreTestResult() } else if (CachedScoreOp == EEnvTestScoreOperator::AverageScore && !bForced) { - ensureAlways(NumPassedForItem != 0); + eqs_ensure(NumPassedForItem != 0); ItemScore /= NumPassedForItem; } @@ -893,3 +899,5 @@ FBox FEnvQueryInstance::GetBoundingBox() const return BBox; } + +#undef eqs_ensure \ No newline at end of file diff --git a/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/EnvQueryManager.cpp b/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/EnvQueryManager.cpp index 6b39011c8d62..0bdf6500097e 100644 --- a/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/EnvQueryManager.cpp +++ b/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/EnvQueryManager.cpp @@ -25,6 +25,7 @@ extern UNREALED_API UEditorEngine* GEditor; #endif // WITH_EDITOR +#include "TimeGuard.h" DEFINE_LOG_CATEGORY(LogEQS); @@ -40,6 +41,9 @@ DEFINE_STAT(STAT_AI_EQS_NumInstances); DEFINE_STAT(STAT_AI_EQS_NumItems); DEFINE_STAT(STAT_AI_EQS_InstanceMemory); DEFINE_STAT(STAT_AI_EQS_AvgInstanceResponseTime); +DEFINE_STAT(STAT_AI_EQS_Debug_StoreQuery); +DEFINE_STAT(STAT_AI_EQS_Debug_StoreTickTime); +DEFINE_STAT(STAT_AI_EQS_Debug_StoreStats); #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) bool UEnvQueryManager::bAllowEQSTimeSlicing = true; @@ -313,6 +317,7 @@ bool UEnvQueryManager::AbortQuery(int32 RequestID) void UEnvQueryManager::Tick(float DeltaTime) { + SCOPE_TIME_GUARD_MS(TEXT("UEnvQueryManager::Tick"), 10); SCOPE_CYCLE_COUNTER(STAT_AI_EQS_Tick); SET_DWORD_STAT(STAT_AI_EQS_NumInstances, RunningQueries.Num()); @@ -330,10 +335,18 @@ void UEnvQueryManager::Tick(float DeltaTime) const int32 NumRunningQueries = RunningQueries.Num(); int32 Index = 0; - while ((TimeLeft > 0.0) && (Index < NumRunningQueries) && (QueriesFinishedDuringUpdate < NumRunningQueries)) + + while ((TimeLeft > 0.0) + && (Index < NumRunningQueries) + // make sure we account for queries that have finished (been aborted) + // before UEnvQueryManager::Tick has been called + && (QueriesFinishedDuringUpdate + NumRunningQueriesAbortedSinceLastUpdate < NumRunningQueries)) { const double StepStartTime = FPlatformTime::Seconds(); float ResultHandlingDuration = 0.0f; +#if USE_EQS_DEBUGGER + bool bWorkHasBeenDone = false; +#endif // USE_EQS_DEBUGGER TSharedPtr QueryInstance = RunningQueries[Index]; FEnvQueryInstance* QueryInstancePtr = QueryInstance.Get(); @@ -344,13 +357,10 @@ void UEnvQueryManager::Tick(float DeltaTime) } else { -#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) - const float StepTimeLimit = bAllowEQSTimeSlicing ? TimeLeft : UEnvQueryTypes::UnlimitedStepTime; -#else - const float StepTimeLimit = TimeLeft; -#endif QueryInstancePtr->ExecuteOneStep(TimeLeft); - +#if USE_EQS_DEBUGGER + bWorkHasBeenDone = true; +#endif // USE_EQS_DEBUGGER if (QueryInstancePtr->IsFinished()) { // Always log that we executed total execution time at the end of the query. @@ -409,7 +419,8 @@ void UEnvQueryManager::Tick(float DeltaTime) TimeLeft -= StepProcessingTime; #if USE_EQS_DEBUGGER - if (QueryInstancePtr) + // we want to do any kind of logging only if any work has been done + if (QueryInstancePtr && bWorkHasBeenDone) { EQSDebugger.StoreTickTime(*QueryInstancePtr, StepProcessingTime, MaxAllowedTestingTime); } @@ -859,14 +870,14 @@ float UEnvQueryManager::FindNamedParam(int32 QueryId, FName ParamName) const //----------------------------------------------------------------------// // BP functions and related functionality //----------------------------------------------------------------------// -UEnvQueryInstanceBlueprintWrapper* UEnvQueryManager::RunEQSQuery(UObject* WorldContext, UEnvQuery* QueryTemplate, UObject* Querier, TEnumAsByte RunMode, TSubclassOf WrapperClass) +UEnvQueryInstanceBlueprintWrapper* UEnvQueryManager::RunEQSQuery(UObject* WorldContextObject, UEnvQuery* QueryTemplate, UObject* Querier, TEnumAsByte RunMode, TSubclassOf WrapperClass) { if (QueryTemplate == nullptr || Querier == nullptr) { return nullptr; } - UEnvQueryManager* EQSManager = GetCurrent(WorldContext); + UEnvQueryManager* EQSManager = GetCurrent(WorldContextObject); UEnvQueryInstanceBlueprintWrapper* QueryInstanceWrapper = nullptr; if (EQSManager) @@ -968,6 +979,8 @@ bool UEnvQueryManager::Exec(UWorld* Inworld, const TCHAR* Cmd, FOutputDevice& Ar void FEQSDebugger::StoreStats(const FEnvQueryInstance& QueryInstance) { + SCOPE_CYCLE_COUNTER(STAT_AI_EQS_Debug_StoreStats); + FStatsInfo& UpdateInfo = UEnvQueryManager::DebuggerStats.FindOrAdd(FName(*QueryInstance.QueryName)); const FEnvQueryDebugProfileData& QueryStats = QueryInstance.DebugData; @@ -996,6 +1009,8 @@ void FEQSDebugger::StoreStats(const FEnvQueryInstance& QueryInstance) void FEQSDebugger::StoreQuery(const TSharedPtr& QueryInstance) { + SCOPE_CYCLE_COUNTER(STAT_AI_EQS_Debug_StoreQuery); + StoredQueries.Remove(nullptr); if (!QueryInstance.IsValid() || QueryInstance->World == nullptr) { @@ -1028,6 +1043,8 @@ void FEQSDebugger::StoreQuery(const TSharedPtr& QueryInstance void FEQSDebugger::StoreTickTime(const FEnvQueryInstance& QueryInstance, float TickTime, float MaxTickTime) { #if USE_EQS_TICKLOADDATA + SCOPE_CYCLE_COUNTER(STAT_AI_EQS_Debug_StoreTickTime); + const int32 NumRecordedTicks = 0x4000; FStatsInfo& UpdateInfo = UEnvQueryManager::DebuggerStats.FindOrAdd(FName(*QueryInstance.QueryName)); diff --git a/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/EnvQueryTraceHelpers.cpp b/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/EnvQueryTraceHelpers.cpp index 7d5fb77c50e3..8769bd26e918 100644 --- a/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/EnvQueryTraceHelpers.cpp +++ b/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/EnvQueryTraceHelpers.cpp @@ -288,7 +288,7 @@ void FEQSHelpers::RunRaycastsOnNavHitOnlyWalls(const ANavigationData& NavData, c ECollisionChannel TraceCollisionChannel = UEngineTypes::ConvertToCollisionChannel(TraceData.TraceChannel); FVector TraceExtent(TraceData.ExtentX, TraceData.ExtentY, TraceData.ExtentZ); - FCollisionQueryParams TraceParams(TEXT("EnvQueryTrace"), TraceData.bTraceComplex); + FCollisionQueryParams TraceParams(SCENE_QUERY_STAT(EnvQueryTrace), TraceData.bTraceComplex); TraceParams.bTraceAsyncScene = true; TraceParams.AddIgnoredActors(IgnoredActors); @@ -394,7 +394,7 @@ void FEQSHelpers::RunPhysRaycasts(UWorld* World, const FEnvTraceData& TraceData, ECollisionChannel TraceCollisionChannel = UEngineTypes::ConvertToCollisionChannel(TraceData.TraceChannel); FVector TraceExtent(TraceData.ExtentX, TraceData.ExtentY, TraceData.ExtentZ); - FCollisionQueryParams TraceParams(TEXT("EnvQueryTrace"), TraceData.bTraceComplex); + FCollisionQueryParams TraceParams(SCENE_QUERY_STAT(EnvQueryTrace), TraceData.bTraceComplex); TraceParams.bTraceAsyncScene = true; TraceParams.AddIgnoredActors(IgnoredActors); @@ -428,7 +428,7 @@ void FEQSHelpers::RunPhysProjection(UWorld* World, const FEnvTraceData& TraceDat ECollisionChannel TraceCollisionChannel = UEngineTypes::ConvertToCollisionChannel(TraceData.TraceChannel); FVector TraceExtent(TraceData.ExtentX, TraceData.ExtentY, TraceData.ExtentZ); - FCollisionQueryParams TraceParams(TEXT("EnvQueryTrace"), TraceData.bTraceComplex); + FCollisionQueryParams TraceParams(SCENE_QUERY_STAT(EnvQueryTrace), TraceData.bTraceComplex); TraceParams.bTraceAsyncScene = true; FBatchTrace BatchOb(World, TraceCollisionChannel, TraceParams, TraceExtent, TraceMode); @@ -461,7 +461,7 @@ void FEQSHelpers::RunPhysProjection(UWorld* World, const FEnvTraceData& TraceDat ECollisionChannel TraceCollisionChannel = UEngineTypes::ConvertToCollisionChannel(TraceData.TraceChannel); FVector TraceExtent(TraceData.ExtentX, TraceData.ExtentY, TraceData.ExtentZ); - FCollisionQueryParams TraceParams(TEXT("EnvQueryTrace"), TraceData.bTraceComplex); + FCollisionQueryParams TraceParams(SCENE_QUERY_STAT(EnvQueryTrace), TraceData.bTraceComplex); TraceParams.bTraceAsyncScene = true; FBatchTrace BatchOb(World, TraceCollisionChannel, TraceParams, TraceExtent, ETraceMode::Keep); diff --git a/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/EnvQueryTypes.cpp b/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/EnvQueryTypes.cpp index 6cf2e5795f1e..3e8641266dd5 100644 --- a/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/EnvQueryTypes.cpp +++ b/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/EnvQueryTypes.cpp @@ -20,7 +20,7 @@ #define LOCTEXT_NAMESPACE "EnvQueryGenerator" -float UEnvQueryTypes::SkippedItemValue = -FLT_MAX; +const float UEnvQueryTypes::SkippedItemValue = -MAX_flt; float UEnvQueryTypes::UnlimitedStepTime = -1.f; //----------------------------------------------------------------------// diff --git a/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/Tests/EnvQueryTest_Overlap.cpp b/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/Tests/EnvQueryTest_Overlap.cpp index def0164ca039..62eec9d3286e 100644 --- a/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/Tests/EnvQueryTest_Overlap.cpp +++ b/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/Tests/EnvQueryTest_Overlap.cpp @@ -23,7 +23,7 @@ void UEnvQueryTest_Overlap::RunTest(FEnvQueryInstance& QueryInstance) const bool bWantsHit = BoolValue.GetValue(); - FCollisionQueryParams OverlapParams(TEXT("EnvQueryOverlap"), OverlapData.bOverlapComplex); + FCollisionQueryParams OverlapParams(SCENE_QUERY_STAT(EnvQueryOverlap), OverlapData.bOverlapComplex); OverlapParams.bTraceAsyncScene = true; const ECollisionChannel OverlapCollisionChannel = OverlapData.OverlapChannel; diff --git a/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/Tests/EnvQueryTest_Trace.cpp b/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/Tests/EnvQueryTest_Trace.cpp index 5f4d98136b63..5414a92f81ab 100644 --- a/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/Tests/EnvQueryTest_Trace.cpp +++ b/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/Tests/EnvQueryTest_Trace.cpp @@ -39,7 +39,7 @@ void UEnvQueryTest_Trace::RunTest(FEnvQueryInstance& QueryInstance) const return; } - FCollisionQueryParams TraceParams(TEXT("EnvQueryTrace"), TraceData.bTraceComplex); + FCollisionQueryParams TraceParams(SCENE_QUERY_STAT(EnvQueryTrace), TraceData.bTraceComplex); TraceParams.bTraceAsyncScene = true; TArray IgnoredActors; diff --git a/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_AI.cpp b/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_AI.cpp index e91d33059144..863c443f5688 100644 --- a/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_AI.cpp +++ b/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_AI.cpp @@ -1,6 +1,9 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "GameplayDebugger/GameplayDebuggerCategory_AI.h" + +#if WITH_GAMEPLAY_DEBUGGER + #include "GameFramework/Pawn.h" #include "ShowFlags.h" #include "PrimitiveViewRelevance.h" @@ -13,9 +16,6 @@ #include "Engine/Canvas.h" #include "AIController.h" #include "BehaviorTree/BehaviorTreeComponent.h" - -#if WITH_GAMEPLAY_DEBUGGER - #include "Engine/Texture2D.h" #include "DynamicMeshBuilder.h" #include "DebugRenderSceneProxy.h" @@ -289,7 +289,7 @@ void FGameplayDebuggerCategory_AI::DrawData(APlayerController* OwnerPC, FGamepla const bool bReducedMode = IsSimulateInEditor(); bShowCategoryName = !bReducedMode || DataPack.bHasController; - DrawPawnIcons(MyWorld, SelectedActor, OwnerPC ? OwnerPC->GetPawn() : nullptr, CanvasContext); + DrawPawnIcons(MyWorld, SelectedActor, OwnerPC->GetPawn(), CanvasContext); if (SelectedActor) { DrawOverheadInfo(*SelectedActor, CanvasContext); diff --git a/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_AI.h b/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_AI.h index 4978217bed86..4d05024e99be 100644 --- a/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_AI.h +++ b/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_AI.h @@ -2,10 +2,10 @@ #pragma once -#include "CoreMinimal.h" #if WITH_GAMEPLAY_DEBUGGER + +#include "CoreMinimal.h" #include "GameplayDebuggerCategory.h" -#endif class AActor; class AAIController; @@ -17,8 +17,6 @@ class UPrimitiveComponent; struct FDebugDrawDelegateHelper; struct FNavigationPath; -#if WITH_GAMEPLAY_DEBUGGER - class FGameplayDebuggerCategory_AI : public FGameplayDebuggerCategory { public: diff --git a/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_BehaviorTree.cpp b/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_BehaviorTree.cpp index 62118ef4fdf4..651707e1b083 100644 --- a/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_BehaviorTree.cpp +++ b/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_BehaviorTree.cpp @@ -1,13 +1,14 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "GameplayDebugger/GameplayDebuggerCategory_BehaviorTree.h" + +#if WITH_GAMEPLAY_DEBUGGER + #include "GameFramework/Pawn.h" #include "BrainComponent.h" #include "AIController.h" #include "BehaviorTree/BlackboardComponent.h" -#if WITH_GAMEPLAY_DEBUGGER - FGameplayDebuggerCategory_BehaviorTree::FGameplayDebuggerCategory_BehaviorTree() { SetDataPackReplication(&DataPack); diff --git a/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_BehaviorTree.h b/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_BehaviorTree.h index 43a44578aded..438676dd2db9 100644 --- a/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_BehaviorTree.h +++ b/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_BehaviorTree.h @@ -2,16 +2,14 @@ #pragma once -#include "CoreMinimal.h" #if WITH_GAMEPLAY_DEBUGGER + +#include "CoreMinimal.h" #include "GameplayDebuggerCategory.h" -#endif class AActor; class APlayerController; -#if WITH_GAMEPLAY_DEBUGGER - class FGameplayDebuggerCategory_BehaviorTree : public FGameplayDebuggerCategory { public: diff --git a/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_EQS.cpp b/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_EQS.cpp index 87686efe4861..3044fceb4bf0 100644 --- a/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_EQS.cpp +++ b/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_EQS.cpp @@ -1,16 +1,16 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "GameplayDebugger/GameplayDebuggerCategory_EQS.h" + +#if WITH_GAMEPLAY_DEBUGGER + #include "GameFramework/PlayerController.h" #include "CanvasItem.h" #include "Engine/Canvas.h" - #include "EnvironmentQuery/EnvQueryManager.h" #include "EnvironmentQuery/EQSRenderingComponent.h" #include "DrawDebugHelpers.h" -#if WITH_GAMEPLAY_DEBUGGER - FGameplayDebuggerCategory_EQS::FGameplayDebuggerCategory_EQS() { MaxQueries = 5; diff --git a/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_EQS.h b/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_EQS.h index 02856830ed4c..6dc827b3f454 100644 --- a/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_EQS.h +++ b/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_EQS.h @@ -2,18 +2,16 @@ #pragma once -#include "CoreMinimal.h" #if WITH_GAMEPLAY_DEBUGGER + +#include "CoreMinimal.h" #include "GameplayDebuggerCategory.h" -#endif #include "EnvironmentQuery/EnvQueryTypes.h" #include "EnvironmentQuery/EnvQueryDebugHelpers.h" class APlayerController; class UPrimitiveComponent; -#if WITH_GAMEPLAY_DEBUGGER - class FGameplayDebuggerCategory_EQS : public FGameplayDebuggerCategory { public: diff --git a/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_NavLocalGrid.cpp b/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_NavLocalGrid.cpp index 3f868dfd00cb..1cc3ca2371c7 100644 --- a/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_NavLocalGrid.cpp +++ b/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_NavLocalGrid.cpp @@ -1,11 +1,12 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "GameplayDebuggerCategory_NavLocalGrid.h" + +#if WITH_GAMEPLAY_DEBUGGER + #include "GameFramework/PlayerController.h" #include "AIController.h" #include "Engine/Engine.h" - -#if WITH_GAMEPLAY_DEBUGGER #include "Navigation/NavLocalGridManager.h" #include "Navigation/GridPathFollowingComponent.h" #include "DebugRenderSceneProxy.h" diff --git a/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_NavLocalGrid.h b/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_NavLocalGrid.h index b40739633a31..27539f092aca 100644 --- a/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_NavLocalGrid.h +++ b/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_NavLocalGrid.h @@ -2,15 +2,13 @@ #pragma once -#include "CoreMinimal.h" #if WITH_GAMEPLAY_DEBUGGER + +#include "CoreMinimal.h" #include "GameplayDebuggerCategory.h" -#endif class APlayerController; -#if WITH_GAMEPLAY_DEBUGGER - class FGameplayDebuggerCategory_NavLocalGrid : public FGameplayDebuggerCategory { public: diff --git a/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_Navmesh.cpp b/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_Navmesh.cpp index dcf4693117b9..beb9fd74e904 100644 --- a/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_Navmesh.cpp +++ b/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_Navmesh.cpp @@ -1,12 +1,13 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "GameplayDebugger/GameplayDebuggerCategory_Navmesh.h" + +#if WITH_GAMEPLAY_DEBUGGER + #include "AI/Navigation/NavigationSystem.h" #include "GameFramework/PlayerController.h" #include "AI/Navigation/RecastNavMesh.h" -#if WITH_GAMEPLAY_DEBUGGER - FGameplayDebuggerCategory_Navmesh::FGameplayDebuggerCategory_Navmesh() { bShowOnlyWithDebugActor = false; diff --git a/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_Navmesh.h b/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_Navmesh.h index 770771eb3730..80507ed5a58c 100644 --- a/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_Navmesh.h +++ b/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_Navmesh.h @@ -2,16 +2,14 @@ #pragma once -#include "CoreMinimal.h" #if WITH_GAMEPLAY_DEBUGGER + +#include "CoreMinimal.h" #include "GameplayDebuggerCategory.h" -#endif #include "AI/Navigation/NavMeshRenderingComponent.h" class APlayerController; -#if WITH_GAMEPLAY_DEBUGGER - class FGameplayDebuggerCategory_Navmesh : public FGameplayDebuggerCategory { public: diff --git a/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_Perception.cpp b/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_Perception.cpp index 014d10697c91..547a1b951662 100644 --- a/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_Perception.cpp +++ b/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_Perception.cpp @@ -1,12 +1,13 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "GameplayDebugger/GameplayDebuggerCategory_Perception.h" + +#if WITH_GAMEPLAY_DEBUGGER + #include "GameFramework/Pawn.h" #include "AIController.h" #include "Perception/AIPerceptionComponent.h" -#if WITH_GAMEPLAY_DEBUGGER - FGameplayDebuggerCategory_Perception::FGameplayDebuggerCategory_Perception() { } diff --git a/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_Perception.h b/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_Perception.h index d6a1b0a64bf2..a72982c9dad0 100644 --- a/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_Perception.h +++ b/Engine/Source/Runtime/AIModule/Private/GameplayDebugger/GameplayDebuggerCategory_Perception.h @@ -2,17 +2,14 @@ #pragma once -#include "CoreMinimal.h" #if WITH_GAMEPLAY_DEBUGGER + +#include "CoreMinimal.h" #include "GameplayDebuggerCategory.h" -#endif class AActor; class APlayerController; -#if WITH_GAMEPLAY_DEBUGGER - - class FGameplayDebuggerCategory_Perception : public FGameplayDebuggerCategory { public: diff --git a/Engine/Source/Runtime/AIModule/Private/Navigation/NavLocalGridManager.cpp b/Engine/Source/Runtime/AIModule/Private/Navigation/NavLocalGridManager.cpp index 1ed34001285e..d6a0f2183d37 100644 --- a/Engine/Source/Runtime/AIModule/Private/Navigation/NavLocalGridManager.cpp +++ b/Engine/Source/Runtime/AIModule/Private/Navigation/NavLocalGridManager.cpp @@ -316,11 +316,11 @@ bool UNavLocalGridManager::FindPath(const FVector& Start, const FVector& End, TA return false; } -int32 UNavLocalGridManager::AddLocalNavigationGridForPoint(UObject* WorldContext, const FVector& Location, const int32 Radius2D, const float Height, bool bRebuildGrids) +int32 UNavLocalGridManager::AddLocalNavigationGridForPoint(UObject* WorldContextObject, const FVector& Location, const int32 Radius2D, const float Height, bool bRebuildGrids) { int32 GridId = 0; - UNavLocalGridManager* GridManager = UNavLocalGridManager::GetCurrent(WorldContext); + UNavLocalGridManager* GridManager = UNavLocalGridManager::GetCurrent(WorldContextObject); if (GridManager) { FNavLocalGridData GridData(Location, UNavLocalGridManager::GridCellSize * Radius2D); @@ -333,11 +333,11 @@ int32 UNavLocalGridManager::AddLocalNavigationGridForPoint(UObject* WorldContext return GridId; } -int32 UNavLocalGridManager::AddLocalNavigationGridForPoints(UObject* WorldContext, const TArray& Locations, const int32 Radius2D, const float Height, bool bRebuildGrids) +int32 UNavLocalGridManager::AddLocalNavigationGridForPoints(UObject* WorldContextObject, const TArray& Locations, const int32 Radius2D, const float Height, bool bRebuildGrids) { int32 GridId = 0; - UNavLocalGridManager* GridManager = UNavLocalGridManager::GetCurrent(WorldContext); + UNavLocalGridManager* GridManager = UNavLocalGridManager::GetCurrent(WorldContextObject); if (GridManager) { const FBox Bounds(Locations); @@ -357,11 +357,11 @@ int32 UNavLocalGridManager::AddLocalNavigationGridForPoints(UObject* WorldContex return GridId; } -int32 UNavLocalGridManager::AddLocalNavigationGridForBox(UObject* WorldContext, const FVector& Location, FVector Extent, FRotator Rotation, const int32 Radius2D, const float Height, bool bRebuildGrids) +int32 UNavLocalGridManager::AddLocalNavigationGridForBox(UObject* WorldContextObject, const FVector& Location, FVector Extent, FRotator Rotation, const int32 Radius2D, const float Height, bool bRebuildGrids) { int32 GridId = 0; - UNavLocalGridManager* GridManager = UNavLocalGridManager::GetCurrent(WorldContext); + UNavLocalGridManager* GridManager = UNavLocalGridManager::GetCurrent(WorldContextObject); if (GridManager) { FNavLocalGridData GridData(Location, FVector2D(Extent.X + UNavLocalGridManager::GridCellSize * Radius2D, Extent.Y + UNavLocalGridManager::GridCellSize * Radius2D)); @@ -374,11 +374,11 @@ int32 UNavLocalGridManager::AddLocalNavigationGridForBox(UObject* WorldContext, return GridId; } -int32 UNavLocalGridManager::AddLocalNavigationGridForCapsule(UObject* WorldContext, const FVector& Location, float CapsuleRadius, float CapsuleHalfHeight, const int32 Radius2D, const float Height, bool bRebuildGrids) +int32 UNavLocalGridManager::AddLocalNavigationGridForCapsule(UObject* WorldContextObject, const FVector& Location, float CapsuleRadius, float CapsuleHalfHeight, const int32 Radius2D, const float Height, bool bRebuildGrids) { int32 GridId = 0; - UNavLocalGridManager* GridManager = UNavLocalGridManager::GetCurrent(WorldContext); + UNavLocalGridManager* GridManager = UNavLocalGridManager::GetCurrent(WorldContextObject); if (GridManager) { FNavLocalGridData GridData(Location, FVector2D(CapsuleRadius + UNavLocalGridManager::GridCellSize * Radius2D, CapsuleRadius + UNavLocalGridManager::GridCellSize * Radius2D)); @@ -391,18 +391,18 @@ int32 UNavLocalGridManager::AddLocalNavigationGridForCapsule(UObject* WorldConte return GridId; } -void UNavLocalGridManager::RemoveLocalNavigationGrid(UObject* WorldContext, int32 GridId, bool bRebuildGrids) +void UNavLocalGridManager::RemoveLocalNavigationGrid(UObject* WorldContextObject, int32 GridId, bool bRebuildGrids) { - UNavLocalGridManager* GridManager = UNavLocalGridManager::GetCurrent(WorldContext); + UNavLocalGridManager* GridManager = UNavLocalGridManager::GetCurrent(WorldContextObject); if (GridManager) { GridManager->RemoveGridData(GridId, bRebuildGrids); } } -bool UNavLocalGridManager::FindLocalNavigationGridPath(UObject* WorldContext, const FVector& Start, const FVector& End, TArray& PathPoints) +bool UNavLocalGridManager::FindLocalNavigationGridPath(UObject* WorldContextObject, const FVector& Start, const FVector& End, TArray& PathPoints) { - UNavLocalGridManager* GridManager = UNavLocalGridManager::GetCurrent(WorldContext); + UNavLocalGridManager* GridManager = UNavLocalGridManager::GetCurrent(WorldContextObject); if (GridManager) { return GridManager->FindPath(Start, End, PathPoints); @@ -411,9 +411,9 @@ bool UNavLocalGridManager::FindLocalNavigationGridPath(UObject* WorldContext, co return false; } -bool UNavLocalGridManager::SetLocalNavigationGridDensity(UObject* WorldContext, float CellSize) +bool UNavLocalGridManager::SetLocalNavigationGridDensity(UObject* WorldContextObject, float CellSize) { - UNavLocalGridManager* GridManager = UNavLocalGridManager::GetCurrent(WorldContext); + UNavLocalGridManager* GridManager = UNavLocalGridManager::GetCurrent(WorldContextObject); if (GridManager) { return GridManager->SetCellSize(CellSize); diff --git a/Engine/Source/Runtime/AIModule/Private/Navigation/PathFollowingComponent.cpp b/Engine/Source/Runtime/AIModule/Private/Navigation/PathFollowingComponent.cpp index 1fc5651904a0..61021cdc364c 100644 --- a/Engine/Source/Runtime/AIModule/Private/Navigation/PathFollowingComponent.cpp +++ b/Engine/Source/Runtime/AIModule/Private/Navigation/PathFollowingComponent.cpp @@ -886,6 +886,11 @@ void UPathFollowingComponent::UpdatePathSegment() FMetaNavMeshPath* MetaNavPath = bIsUsingMetaPath ? Path->CastPath() : nullptr; + /** it's possible that finishing this move request will result in another request + * which won't be easily detectable from this function. This simple local + * variable gives us this knowledge. */ + const FAIRequestID MoveRequestId = GetCurrentRequestId(); + // if agent has control over its movement, check finish conditions const FVector CurrentLocation = MovementComp->GetActorFeetLocation(); const bool bCanUpdateState = HasMovementAuthority(); @@ -933,10 +938,13 @@ void UPathFollowingComponent::UpdatePathSegment() } } - if (bCanUpdateState && Status == EPathFollowingStatus::Moving) + if (bCanUpdateState + && Status == EPathFollowingStatus::Moving + // still the same move request + && MoveRequestId == GetCurrentRequestId()) { // check waypoint switch condition in meta paths - if (MetaNavPath && Status == EPathFollowingStatus::Moving) + if (MetaNavPath) { MetaNavPath->ConditionalMoveToNextSection(CurrentLocation, EMetaPathUpdateReason::MoveTick); } diff --git a/Engine/Source/Runtime/AIModule/Private/Perception/AIPerceptionSystem.cpp b/Engine/Source/Runtime/AIModule/Private/Perception/AIPerceptionSystem.cpp index c6d3474d404f..5713ea549bd8 100644 --- a/Engine/Source/Runtime/AIModule/Private/Perception/AIPerceptionSystem.cpp +++ b/Engine/Source/Runtime/AIModule/Private/Perception/AIPerceptionSystem.cpp @@ -574,12 +574,12 @@ void UAIPerceptionSystem::RegisterAllPawnsAsSourcesForSense(FAISenseID SenseID) } } -bool UAIPerceptionSystem::RegisterPerceptionStimuliSource(UObject* WorldContext, TSubclassOf Sense, AActor* Target) +bool UAIPerceptionSystem::RegisterPerceptionStimuliSource(UObject* WorldContextObject, TSubclassOf Sense, AActor* Target) { bool bResult = false; if (Sense && Target) { - UWorld* World = GEngine->GetWorldFromContextObject(WorldContext); + UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject); if (World && World->GetAISystem()) { UAISystem* AISys = Cast(World->GetAISystem()); @@ -617,10 +617,10 @@ void UAIPerceptionSystem::OnPerceptionStimuliSourceEndPlay(AActor* Actor, EEndPl bStimuliSourcesRefreshRequired = true; } -TSubclassOf UAIPerceptionSystem::GetSenseClassForStimulus(UObject* WorldContext, const FAIStimulus& Stimulus) +TSubclassOf UAIPerceptionSystem::GetSenseClassForStimulus(UObject* WorldContextObject, const FAIStimulus& Stimulus) { TSubclassOf Result = nullptr; - UAIPerceptionSystem* PercSys = GetCurrent(WorldContext); + UAIPerceptionSystem* PercSys = GetCurrent(WorldContextObject); if (PercSys && PercSys->Senses.IsValidIndex(Stimulus.Type) && PercSys->Senses[Stimulus.Type] != nullptr) { Result = PercSys->Senses[Stimulus.Type]->GetClass(); @@ -650,9 +650,9 @@ void UAIPerceptionSystem::ReportEvent(UAISenseEvent* PerceptionEvent) } } -void UAIPerceptionSystem::ReportPerceptionEvent(UObject* WorldContext, UAISenseEvent* PerceptionEvent) +void UAIPerceptionSystem::ReportPerceptionEvent(UObject* WorldContextObject, UAISenseEvent* PerceptionEvent) { - UAIPerceptionSystem* PerceptionSys = GetCurrent(WorldContext); + UAIPerceptionSystem* PerceptionSys = GetCurrent(WorldContextObject); if (PerceptionSys != nullptr) { PerceptionSys->ReportEvent(PerceptionEvent); diff --git a/Engine/Source/Runtime/AIModule/Private/Perception/AISense_Damage.cpp b/Engine/Source/Runtime/AIModule/Private/Perception/AISense_Damage.cpp index c82927dc8cea..9205d3ee0e67 100644 --- a/Engine/Source/Runtime/AIModule/Private/Perception/AISense_Damage.cpp +++ b/Engine/Source/Runtime/AIModule/Private/Perception/AISense_Damage.cpp @@ -127,9 +127,9 @@ void UAISense_Damage::RegisterWrappedEvent(UAISenseEvent& PerceptionEvent) } } -void UAISense_Damage::ReportDamageEvent(UObject* WorldContext, AActor* DamagedActor, AActor* Instigator, float DamageAmount, FVector EventLocation, FVector HitLocation) +void UAISense_Damage::ReportDamageEvent(UObject* WorldContextObject, AActor* DamagedActor, AActor* Instigator, float DamageAmount, FVector EventLocation, FVector HitLocation) { - UAIPerceptionSystem* PerceptionSystem = UAIPerceptionSystem::GetCurrent(WorldContext); + UAIPerceptionSystem* PerceptionSystem = UAIPerceptionSystem::GetCurrent(WorldContextObject); if (PerceptionSystem) { FAIDamageEvent Event(DamagedActor, Instigator, DamageAmount, EventLocation, HitLocation); diff --git a/Engine/Source/Runtime/AIModule/Private/Perception/AISense_Hearing.cpp b/Engine/Source/Runtime/AIModule/Private/Perception/AISense_Hearing.cpp index 3af8aed7fb50..295c3909d148 100644 --- a/Engine/Source/Runtime/AIModule/Private/Perception/AISense_Hearing.cpp +++ b/Engine/Source/Runtime/AIModule/Private/Perception/AISense_Hearing.cpp @@ -69,9 +69,9 @@ UAISense_Hearing::UAISense_Hearing(const FObjectInitializer& ObjectInitializer) } } -void UAISense_Hearing::ReportNoiseEvent(UObject* WorldContext, FVector NoiseLocation, float Loudness, AActor* Instigator, float MaxRange, FName Tag) +void UAISense_Hearing::ReportNoiseEvent(UObject* WorldContextObject, FVector NoiseLocation, float Loudness, AActor* Instigator, float MaxRange, FName Tag) { - UAIPerceptionSystem* PerceptionSystem = UAIPerceptionSystem::GetCurrent(WorldContext); + UAIPerceptionSystem* PerceptionSystem = UAIPerceptionSystem::GetCurrent(WorldContextObject); if (PerceptionSystem) { FAINoiseEvent Event(Instigator, NoiseLocation, Loudness, MaxRange, Tag); diff --git a/Engine/Source/Runtime/AIModule/Private/Perception/AISense_Sight.cpp b/Engine/Source/Runtime/AIModule/Private/Perception/AISense_Sight.cpp index 5419449a9832..950beb6e0692 100644 --- a/Engine/Source/Runtime/AIModule/Private/Perception/AISense_Sight.cpp +++ b/Engine/Source/Runtime/AIModule/Private/Perception/AISense_Sight.cpp @@ -139,8 +139,6 @@ bool UAISense_Sight::ShouldAutomaticallySeeTarget(const FDigestedSightProperties float UAISense_Sight::Update() { - static const FName NAME_AILineOfSight = FName(TEXT("AILineOfSight")); - SCOPE_CYCLE_COUNTER(STAT_AI_Sense_Sight); const UWorld* World = GEngine->GetWorldFromContextObject(GetPerceptionSystem()->GetOuter()); @@ -246,7 +244,7 @@ float UAISense_Sight::Update() FHitResult HitResult; const bool bHit = World->LineTraceSingleByChannel(HitResult, Listener.CachedLocation, TargetLocation , DefaultSightCollisionChannel - , FCollisionQueryParams(NAME_AILineOfSight, true, Listener.Listener->GetBodyActor())); + , FCollisionQueryParams(SCENE_QUERY_STAT(AILineOfSight), true, Listener.Listener->GetBodyActor())); ++TracesCount; diff --git a/Engine/Source/Runtime/AIModule/Private/Perception/PawnSensingComponent.cpp b/Engine/Source/Runtime/AIModule/Private/Perception/PawnSensingComponent.cpp index 1ce4c6693c24..3d1a4922940d 100644 --- a/Engine/Source/Runtime/AIModule/Private/Perception/PawnSensingComponent.cpp +++ b/Engine/Source/Runtime/AIModule/Private/Perception/PawnSensingComponent.cpp @@ -431,8 +431,7 @@ bool UPawnSensingComponent::CanHear(const FVector& NoiseLoc, float Loudness, boo } // check if sound is occluded - static FName NAME_CanHear = FName(TEXT("CanHear")); - return !Owner->GetWorld()->LineTraceTestByChannel(HearingLocation, NoiseLoc, ECC_Visibility, FCollisionQueryParams(NAME_CanHear, true, Owner)); + return !Owner->GetWorld()->LineTraceTestByChannel(HearingLocation, NoiseLoc, ECC_Visibility, FCollisionQueryParams(SCENE_QUERY_STAT(CanHear), true, Owner)); } diff --git a/Engine/Source/Runtime/ALAudio/Private/ALAudioSource.cpp b/Engine/Source/Runtime/ALAudio/Private/ALAudioSource.cpp index 9b8105ba6314..39d040715a25 100644 --- a/Engine/Source/Runtime/ALAudio/Private/ALAudioSource.cpp +++ b/Engine/Source/Runtime/ALAudio/Private/ALAudioSource.cpp @@ -120,20 +120,14 @@ void FALSoundSource::Update( void ) SetFilterFrequency(); FVector Location; - FVector Velocity; // See file header for coordinate system explanation. Location.X = WaveInstance->Location.X; Location.Y = WaveInstance->Location.Z; // Z/Y swapped on purpose, see file header Location.Z = WaveInstance->Location.Y; // Z/Y swapped on purpose, see file header - Velocity.X = WaveInstance->Velocity.X; - Velocity.Y = WaveInstance->Velocity.Z; // Z/Y swapped on purpose, see file header - Velocity.Z = WaveInstance->Velocity.Y; // Z/Y swapped on purpose, see file header - // Convert to meters. Location *= AUDIO_DISTANCE_FACTOR; - Velocity *= AUDIO_DISTANCE_FACTOR; // We're using a relative coordinate system for un- spatialized sounds. FVector RelativeDirection = FVector::ZeroVector; @@ -156,7 +150,6 @@ void FALSoundSource::Update( void ) alSourcef(SourceId, AL_PITCH, Pitch); alSourcefv(SourceId, AL_POSITION, (ALfloat*)&EmitterPosition); - alSourcefv(SourceId, AL_VELOCITY, (ALfloat*)&Velocity); } /** diff --git a/Engine/Source/Runtime/AVIWriter/Private/AVIWriter.cpp b/Engine/Source/Runtime/AVIWriter/Private/AVIWriter.cpp index 7925111019b3..899d7591040e 100644 --- a/Engine/Source/Runtime/AVIWriter/Private/AVIWriter.cpp +++ b/Engine/Source/Runtime/AVIWriter/Private/AVIWriter.cpp @@ -26,16 +26,17 @@ typedef TCHAR* PTCHAR; #pragma warning(push) #pragma warning(disable : 4263) // 'function' : member function does not override any base class virtual member function #pragma warning(disable : 4264) // 'virtual_function' : no override available for virtual member function from base 'cla +#pragma warning(disable : 4265) // 'class' : class has virtual functions, but destructor is not virtual #if USING_CODE_ANALYSIS #pragma warning(disable:6509) // Invalid annotation: 'return' cannot be referenced in some contexts #pragma warning(disable:6101) // Returning uninitialized memory '*lpdwExitCode'. A successful path through the function does not set the named _Out_ parameter. #pragma warning(disable:28204) // 'Func' has an override at 'file' and only the override is annotated for _Param_(N): when an override is annotated, the base (this function) should be similarly annotated. #endif #include -#pragma warning(pop) - #include #include +#pragma warning(pop) + #include "HideWindowsPlatformTypes.h" #include "CapturePin.h" @@ -60,7 +61,7 @@ const AMOVIESETUP_MEDIATYPE sudOpPinTypes = const AMOVIESETUP_PIN sudOutputPinDesktop = { - L"Output", // Obsolete, not used. + (LPWSTR)L"Output", // Obsolete, not used. false, // Is this pin rendered? true, // Is it an output pin? false, // Can the filter create zero instances? diff --git a/Engine/Source/Runtime/AVIWriter/Private/CapturePin.h b/Engine/Source/Runtime/AVIWriter/Private/CapturePin.h index 3aa5fe09062f..67c34913b378 100644 --- a/Engine/Source/Runtime/AVIWriter/Private/CapturePin.h +++ b/Engine/Source/Runtime/AVIWriter/Private/CapturePin.h @@ -23,6 +23,7 @@ typedef TCHAR* PTCHAR; #pragma warning(push) #pragma warning(disable : 4263) // 'function' : member function does not override any base class virtual member function #pragma warning(disable : 4264) // 'virtual_function' : no override available for virtual member function from base + #pragma warning(disable : 4265) // 'class' : class has virtual functions, but destructor is not virtual #if USING_CODE_ANALYSIS #pragma warning(disable:6509) // Invalid annotation: 'return' cannot be referenced in some contexts #pragma warning(disable:6101) // Returning uninitialized memory '*lpdwExitCode'. A successful path through the function does not set the named _Out_ parameter. diff --git a/Engine/Source/Runtime/AVIWriter/Private/CaptureSource.h b/Engine/Source/Runtime/AVIWriter/Private/CaptureSource.h index 813f685b2d91..b1dbb98f6c3b 100644 --- a/Engine/Source/Runtime/AVIWriter/Private/CaptureSource.h +++ b/Engine/Source/Runtime/AVIWriter/Private/CaptureSource.h @@ -25,7 +25,9 @@ typedef TCHAR* PTCHAR; #endif #include "WindowsHWrapper.h" #include "AllowWindowsPlatformTypes.h" +THIRD_PARTY_INCLUDES_START #include +THIRD_PARTY_INCLUDES_END #include "HideWindowsPlatformTypes.h" #pragma warning(pop) class FCapturePin; diff --git a/Engine/Source/Runtime/Analytics/Analytics/Private/Analytics.cpp b/Engine/Source/Runtime/Analytics/Analytics/Private/Analytics.cpp index 485401cbd960..225ecc2f0ddf 100644 --- a/Engine/Source/Runtime/Analytics/Analytics/Private/Analytics.cpp +++ b/Engine/Source/Runtime/Analytics/Analytics/Private/Analytics.cpp @@ -4,7 +4,7 @@ #include "Misc/CommandLine.h" #include "Interfaces/IAnalyticsProviderModule.h" -DEFINE_LOG_CATEGORY_STATIC(LogAnalytics, Display, All); +DEFINE_LOG_CATEGORY(LogAnalytics); IMPLEMENT_MODULE( FAnalytics, Analytics ); diff --git a/Engine/Source/Runtime/Analytics/Analytics/Public/Analytics.h b/Engine/Source/Runtime/Analytics/Analytics/Public/Analytics.h index 6ee426f4f83e..211414eec5a6 100644 --- a/Engine/Source/Runtime/Analytics/Analytics/Public/Analytics.h +++ b/Engine/Source/Runtime/Analytics/Analytics/Public/Analytics.h @@ -9,6 +9,8 @@ #include "AnalyticsProviderConfigurationDelegate.h" #include "AnalyticsBuildType.h" +ANALYTICS_API DECLARE_LOG_CATEGORY_EXTERN(LogAnalytics, Display, All); + class IAnalyticsProvider; /** diff --git a/Engine/Source/Runtime/Analytics/Analytics/Public/AnalyticsConversion.h b/Engine/Source/Runtime/Analytics/Analytics/Public/AnalyticsConversion.h index 8d1b69ec29f7..4c79c0388412 100644 --- a/Engine/Source/Runtime/Analytics/Analytics/Public/AnalyticsConversion.h +++ b/Engine/Source/Runtime/Analytics/Analytics/Public/AnalyticsConversion.h @@ -8,52 +8,17 @@ /** Helpers for converting various common types to strings that analytics providers can consume. */ namespace AnalyticsConversion { - /** Identity conversion for strings. Complete passthrough. */ - inline const FString& ToString(const FString& Str) - { - return Str; - } - - /** Identity conversion for strings. Move support. */ - inline FString&& ToString(FString&& Str) - { - return MoveTemp(Str); - } - - /** Identity conversion for strings. char-array support. */ - inline FString ToString(const ANSICHAR* Str) - { - return Str; - } - - /** Identity conversion for strings. char-array support. */ - inline FString ToString(const WIDECHAR* Str) - { - return Str; - } - - /** Bool conversion. */ - inline FString ToString(bool Value) - { - return Value ? TEXT("true") : TEXT("false"); - } - - /** Guid conversion. */ - inline FString ToString(FGuid Value) - { - return Value.ToString(); - } - - /** Double conversion. Lex is broken to doubles (won't use SanitizeFloat), so overload this directly. */ - inline FString ToString(double Value) - { - return FString::SanitizeFloat(Value); - } - - - /** Lexical conversion. Allow any type that we have a Lex for. */ + /** Lexical conversion. Allow any type that we have a Lex for. Can't use universal references here because it then eats all non-perfect matches for the array and TMap conversions below, which we want to use a custom, analytics specific implementation for. */ template - inline typename TEnableIf::Value, FString>::Type ToString(T Value) + inline auto ToString(const T& Value) -> decltype(Lex::ToString(Value)) + { + return Lex::ToString(Value); + } + inline FString ToString(float Value) + { + return Lex::ToSanitizedString(Value); + } + inline FString ToString(double Value) { return Lex::ToSanitizedString(Value); } diff --git a/Engine/Source/Runtime/Analytics/Analytics/Public/AnalyticsEventAttribute.h b/Engine/Source/Runtime/Analytics/Analytics/Public/AnalyticsEventAttribute.h index 8a5af158a2d4..14f3bb29385a 100644 --- a/Engine/Source/Runtime/Analytics/Analytics/Public/AnalyticsEventAttribute.h +++ b/Engine/Source/Runtime/Analytics/Analytics/Public/AnalyticsEventAttribute.h @@ -18,46 +18,15 @@ struct FAnalyticsEventAttribute FAnalyticsEventAttribute() {} - #if !PLATFORM_COMPILER_HAS_DEFAULTED_FUNCTIONS - /** copy ctor for platforms that don't implement defaulted functions properly. */ - FAnalyticsEventAttribute(const FAnalyticsEventAttribute& RHS) - : AttrName(RHS.AttrName) - , AttrValue(RHS.AttrValue) - {} - /** move ctor for platforms that don't implement defaulted functions properly. */ - FAnalyticsEventAttribute(FAnalyticsEventAttribute&& RHS) - : AttrName(MoveTemp(RHS.AttrName)) - , AttrValue(MoveTemp(RHS.AttrValue)) - {} - /** copy assignment ctor for platforms that don't implement defaulted functions properly. */ - FAnalyticsEventAttribute& operator=(const FAnalyticsEventAttribute& RHS) - { - AttrName = RHS.AttrName; - AttrValue = RHS.AttrValue; - return *this; - } - /** move assignment ctor for platforms that don't implement defaulted functions properly. */ - FAnalyticsEventAttribute& operator=(FAnalyticsEventAttribute&& RHS) - { - AttrName = MoveTemp(RHS.AttrName); - AttrValue = MoveTemp(RHS.AttrValue); - return *this; - } -#endif - /** - * Helper constructor to make an attribute from a name/value pair. + * Helper constructor to make an attribute from a name/value pair by forwarding through Lex::ToString and AnalyticsConversion::ToString. * - * NameType - * ValueType will be converted to a string via forwarding to ToStringForAnalytics. - * - * @param InName Name of the attribute. Will be forwarded to an FString constructor. - * @param InValue Value of the attribute. Will be forwarded to ToStringForAnalytics to convert to a string. - * @return + * @param InName Name of the attribute. Will be converted to a string via forwarding to Lex::ToString + * @param InValue Value of the attribute. Will be converted to a string via forwarding to AnalyticsConversion::ToString (same as Lex but with basic support for arrays and maps) */ template FAnalyticsEventAttribute(NameType&& InName, ValueType&& InValue) - : AttrName(Forward(InName)) + : AttrName(Lex::ToString(Forward(InName))) , AttrValue(AnalyticsConversion::ToString(Forward(InValue))) {} }; @@ -88,14 +57,23 @@ namespace ImplMakeAnalyticsEventAttributeArray } } -/** Helper to create an array of attributes using a single expression. There must be an even number of arguments, one for each key/value pair. */ +/** Helper to create an array of attributes using a single expression. Reserves the necessary space in advance. There must be an even number of arguments, one for each key/value pair. */ template inline TArray MakeAnalyticsEventAttributeArray(ArgTypes&&...Args) { - static_assert(sizeof...(Args) % 2 == 0, "Must pass an even number of arguments to MakeAnalyticsEventAttributeArray."); + static_assert(sizeof...(Args) % 2 == 0, "Must pass an even number of arguments."); TArray Attrs; Attrs.Empty(sizeof...(Args) / 2); ImplMakeAnalyticsEventAttributeArray::MakeArray(Attrs, Forward(Args)...); return Attrs; } +/** Helper to append to an array of attributes using a single expression. Reserves the necessary space in advance. There must be an even number of arguments, one for each key/value pair. */ +template +inline TArray& AppendAnalyticsEventAttributeArray(TArray& Attrs, ArgTypes&&...Args) +{ + static_assert(sizeof...(Args) % 2 == 0, "Must pass an even number of arguments."); + Attrs.Reserve(Attrs.Num() + (sizeof...(Args) / 2)); + ImplMakeAnalyticsEventAttributeArray::MakeArray(Attrs, Forward(Args)...); + return Attrs; +} diff --git a/Engine/Source/Runtime/Analytics/AnalyticsET/Private/AnalyticsET.cpp b/Engine/Source/Runtime/Analytics/AnalyticsET/Private/AnalyticsET.cpp index 5cb56eef6803..7e94c1b108d0 100644 --- a/Engine/Source/Runtime/Analytics/AnalyticsET/Private/AnalyticsET.cpp +++ b/Engine/Source/Runtime/Analytics/AnalyticsET/Private/AnalyticsET.cpp @@ -4,9 +4,9 @@ #include "IAnalyticsProviderET.h" #include "HttpModule.h" +#include "Analytics.h" IMPLEMENT_MODULE( FAnalyticsET, AnalyticsET ); -DEFINE_LOG_CATEGORY(LogAnalytics); void FAnalyticsET::StartupModule() { diff --git a/Engine/Source/Runtime/Analytics/AnalyticsET/Private/HttpServiceTracker.cpp b/Engine/Source/Runtime/Analytics/AnalyticsET/Private/HttpServiceTracker.cpp index a799cf6aeed9..fa996183d755 100644 --- a/Engine/Source/Runtime/Analytics/AnalyticsET/Private/HttpServiceTracker.cpp +++ b/Engine/Source/Runtime/Analytics/AnalyticsET/Private/HttpServiceTracker.cpp @@ -6,6 +6,7 @@ #include "IAnalyticsProviderET.h" #include "AnalyticsET.h" #include "Interfaces/IHttpResponse.h" +#include "Analytics.h" bool FHttpServiceTracker::Tick(float DeltaTime) { diff --git a/Engine/Source/Runtime/Analytics/AnalyticsET/Private/IAnalyticsProviderET.cpp b/Engine/Source/Runtime/Analytics/AnalyticsET/Private/IAnalyticsProviderET.cpp index fb64b9b59205..2b11dfcc032a 100644 --- a/Engine/Source/Runtime/Analytics/AnalyticsET/Private/IAnalyticsProviderET.cpp +++ b/Engine/Source/Runtime/Analytics/AnalyticsET/Private/IAnalyticsProviderET.cpp @@ -14,6 +14,7 @@ #include "Serialization/JsonWriter.h" #include "Modules/ModuleManager.h" #include "AnalyticsET.h" +#include "Analytics.h" #include "Interfaces/IHttpResponse.h" #include "Interfaces/IHttpRequest.h" #include "HttpModule.h" @@ -192,6 +193,7 @@ public: virtual void RecordEvent(FString EventName, TArray&& Attributes) override; virtual void RecordEventJson(FString EventName, TArray&& AttributesJson) override; virtual void SetDefaultEventAttributes(TArray&& Attributes) override; + virtual const TArray& GetDefaultEventAttributes() const override; virtual ~FAnalyticsProviderET(); @@ -225,6 +227,10 @@ private: const int32 MaxCachedNumEvents; /** Max time that can elapse before pushing cached events to server */ const float MaxCachedElapsedTime; + /** Min retry delay (in seconds) after a failure to submit. */ + const float RetryDelaySecs; + /** Timecode of the last time a flush request failed to submit (for throttling). */ + FDateTime LastFailedFlush; /** Allows events to not be cached when -AnalyticsDisableCaching is used. This should only be used for debugging as caching significantly reduces bandwidth overhead per event. */ bool bShouldCacheEvents; /** Current countdown timer to keep track of MaxCachedElapsedTime push */ @@ -272,8 +278,8 @@ private: */ TArray CachedEvents; - /** Critical section for updating the CachedEvents */ - FCriticalSection CachedEventsCS; + /** Critical section for updating the CachedEvents. Mutable to allow const methods to access the list. */ + mutable FCriticalSection CachedEventsCS; /** * Delegate called when an event Http request completes @@ -342,6 +348,8 @@ FAnalyticsProviderET::FAnalyticsProviderET(const FAnalyticsET::Config& ConfigVal , APIServer(ConfigValues.APIServerET) , MaxCachedNumEvents(20) , MaxCachedElapsedTime(60.0f) + , RetryDelaySecs(120.0f) + , LastFailedFlush(FDateTime::MinValue()) , bShouldCacheEvents(true) , FlushEventsCountdown(MaxCachedElapsedTime) , bInDestructor(false) @@ -415,7 +423,11 @@ bool FAnalyticsProviderET::Tick(float DeltaSeconds) if (FlushEventsCountdown <= 0 || CachedEvents.Num() >= MaxCachedNumEvents) { - FlushEvents(); + FTimespan TimeSinceLastFailure = FDateTime::UtcNow() - LastFailedFlush; + if (TimeSinceLastFailure.GetTotalSeconds() >= RetryDelaySecs) + { + FlushEvents(); + } } } return true; @@ -454,6 +466,8 @@ bool FAnalyticsProviderET::StartSession(TArray&& Attri // always ensure we send a few specific attributes on session start. TArray AppendedAttributes(MoveTemp(Attributes)); + // this allows mapping to ad networks attribution data + AppendedAttributes.Emplace(TEXT("AttributionId"), FPlatformMisc::GetUniqueAdvertisingId()); // we should always know what platform is hosting this session. AppendedAttributes.Emplace(TEXT("Platform"), FString(FPlatformProperties::IniPlatformName())); @@ -792,6 +806,15 @@ void FAnalyticsProviderET::SetDefaultEventAttributes(TArray& FAnalyticsProviderET::GetDefaultEventAttributes() const +{ + FScopeLock ScopedLock(&CachedEventsCS); + + int DefaultIndex = CachedEvents.FindLastByPredicate([](const FAnalyticsEventEntry& Entry) { return Entry.bIsDefaultAttributes == 1; }); + checkf(DefaultIndex != INDEX_NONE, TEXT("failed to find default attributes entry in analytics cached events list")); + return CachedEvents[DefaultIndex].Attributes; +} + void FAnalyticsProviderET::EventRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool, TSharedPtr< TArray > FlushedEvents) { // process responses @@ -809,31 +832,37 @@ void FAnalyticsProviderET::EventRequestComplete(FHttpRequestPtr HttpRequest, FHt UE_LOG(LogAnalytics, VeryVerbose, TEXT("[%s] ET response for [%s]. No response"), *APIKey, *HttpRequest->GetURL()); } - // if the events were not delivered and FlushedEvents is passed, requeue them at the beginning - if (FlushedEvents.IsValid() && !bEventsDelivered) + // if the events were not delivered + if (!bEventsDelivered) { - // add a dropped submission event so we can see how often this is happening - if (bShouldCacheEvents && CachedEvents.Num() < 1024) - { - TArray Attributes; - Attributes.Emplace(FAnalyticsEventAttribute(FString(TEXT("HTTP_STATUS")), FString::Printf(TEXT("%d"), HttpResponse.IsValid() ? HttpResponse->GetResponseCode() : 0))); - Attributes.Emplace(FAnalyticsEventAttribute(FString(TEXT("URL")), HttpRequest->GetURL())); - Attributes.Emplace(FAnalyticsEventAttribute(FString(TEXT("EVENTS_IN_BATCH")), FString::Printf(TEXT("%d"), FlushedEvents->Num()))); - Attributes.Emplace(FAnalyticsEventAttribute(FString(TEXT("EVENTS_QUEUED")), FString::Printf(TEXT("%d"), CachedEvents.Num()))); - CachedEvents.Emplace(FAnalyticsEventEntry(FString(TEXT("ET.DroppedSubmission")), MoveTemp(Attributes), false, false)); - } + // record the time (for throttling) so we don't retry again immediately + LastFailedFlush = FDateTime::UtcNow(); - // if we're being super spammy or have been offline forever, just leave it at the ET.DroppedSubmission event - if (bShouldCacheEvents && CachedEvents.Num() < 256) + // if FlushedEvents is passed, re-queue the events for next time + if (FlushedEvents.IsValid()) { - UE_LOG(LogAnalytics, Log, TEXT("[%s] ET Requeuing %d analytics events due to failure to send"), *APIKey, FlushedEvents->Num()); + // add a dropped submission event so we can see how often this is happening + if (bShouldCacheEvents && CachedEvents.Num() < 1024) + { + TArray Attributes; + Attributes.Emplace(FAnalyticsEventAttribute(FString(TEXT("HTTP_STATUS")), FString::Printf(TEXT("%d"), HttpResponse.IsValid() ? HttpResponse->GetResponseCode() : 0))); + Attributes.Emplace(FAnalyticsEventAttribute(FString(TEXT("EVENTS_IN_BATCH")), FString::Printf(TEXT("%d"), FlushedEvents->Num()))); + Attributes.Emplace(FAnalyticsEventAttribute(FString(TEXT("EVENTS_QUEUED")), FString::Printf(TEXT("%d"), CachedEvents.Num()))); + CachedEvents.Emplace(FAnalyticsEventEntry(FString(TEXT("ET.DroppedSubmission")), MoveTemp(Attributes), false, false)); + } - // put them at the beginning since it should include a default attributes entry and we don't want to change the current default attributes - CachedEvents.Insert(*FlushedEvents, 0); - } - else - { - UE_LOG(LogAnalytics, Error, TEXT("[%s] ET dropping %d analytics events due to too many in queue (%d)"), *APIKey, FlushedEvents->Num(), CachedEvents.Num()); + // if we're being super spammy or have been offline forever, just leave it at the ET.DroppedSubmission event + if (bShouldCacheEvents && CachedEvents.Num() < 256) + { + UE_LOG(LogAnalytics, Log, TEXT("[%s] ET Requeuing %d analytics events due to failure to send"), *APIKey, FlushedEvents->Num()); + + // put them at the beginning since it should include a default attributes entry and we don't want to change the current default attributes + CachedEvents.Insert(*FlushedEvents, 0); + } + else + { + UE_LOG(LogAnalytics, Error, TEXT("[%s] ET dropping %d analytics events due to too many in queue (%d)"), *APIKey, FlushedEvents->Num(), CachedEvents.Num()); + } } } } diff --git a/Engine/Source/Runtime/Analytics/AnalyticsET/Public/AnalyticsET.h b/Engine/Source/Runtime/Analytics/AnalyticsET/Public/AnalyticsET.h index c3e0211bf208..db129f8a5f34 100644 --- a/Engine/Source/Runtime/Analytics/AnalyticsET/Public/AnalyticsET.h +++ b/Engine/Source/Runtime/Analytics/AnalyticsET/Public/AnalyticsET.h @@ -9,7 +9,6 @@ class IAnalyticsProvider; class IAnalyticsProviderET; -DECLARE_LOG_CATEGORY_EXTERN(LogAnalytics, Display, All); class IAnalyticsProviderET; diff --git a/Engine/Source/Runtime/Analytics/AnalyticsET/Public/IAnalyticsProviderET.h b/Engine/Source/Runtime/Analytics/AnalyticsET/Public/IAnalyticsProviderET.h index c64f859c65ba..e6b4dc5ad9b0 100644 --- a/Engine/Source/Runtime/Analytics/AnalyticsET/Public/IAnalyticsProviderET.h +++ b/Engine/Source/Runtime/Analytics/AnalyticsET/Public/IAnalyticsProviderET.h @@ -80,4 +80,11 @@ public: * @param Attributes array of attributes that should be appended to every event. */ virtual void SetDefaultEventAttributes(TArray&& Attributes) = 0; + + /** + * returns the current set of default event attributes set on the provider. + * + * @param Attributes array of attributes that should be appended to every event. + */ + virtual const TArray& GetDefaultEventAttributes() const = 0; }; diff --git a/Engine/Source/Runtime/Analytics/AnalyticsSwrve/Private/AnalyticsSwrve.cpp b/Engine/Source/Runtime/Analytics/AnalyticsSwrve/Private/AnalyticsSwrve.cpp index 893ea292a1e3..506b2ae8dd7b 100644 --- a/Engine/Source/Runtime/Analytics/AnalyticsSwrve/Private/AnalyticsSwrve.cpp +++ b/Engine/Source/Runtime/Analytics/AnalyticsSwrve/Private/AnalyticsSwrve.cpp @@ -13,11 +13,10 @@ #include "HttpModule.h" #include "Misc/EngineVersion.h" #include "Interfaces/IAnalyticsProvider.h" +#include "Analytics.h" #if PLATFORM_DESKTOP -DEFINE_LOG_CATEGORY_STATIC(LogAnalytics, Display, All); - IMPLEMENT_MODULE( FAnalyticsSwrve, AnalyticsSwrve ); class FAnalyticsProviderSwrve : public IAnalyticsProvider diff --git a/Engine/Source/Runtime/Android/AndroidAudio/Private/AndroidAudioSource.cpp b/Engine/Source/Runtime/Android/AndroidAudio/Private/AndroidAudioSource.cpp index 79a5fbe6c61f..70f1fe4178af 100644 --- a/Engine/Source/Runtime/Android/AndroidAudio/Private/AndroidAudioSource.cpp +++ b/Engine/Source/Runtime/Android/AndroidAudio/Private/AndroidAudioSource.cpp @@ -439,27 +439,6 @@ void FSLESSoundSource::Update( void ) SetFilterFrequency(); - FVector Location; - FVector Velocity; - - // See file header for coordinate system explanation. - Location.X = WaveInstance->Location.X; - Location.Y = WaveInstance->Location.Z; // Z/Y swapped to match UE coordinate system - Location.Z = WaveInstance->Location.Y; // Z/Y swapped to match UE coordinate system - - Velocity.X = WaveInstance->Velocity.X; - Velocity.Y = WaveInstance->Velocity.Z; // Z/Y swapped to match UE coordinate system - Velocity.Z = WaveInstance->Velocity.Y; // Z/Y swapped to match UE coordinate system - - // We're using a relative coordinate system for un- spatialized sounds. - if( !WaveInstance->bUseSpatialization ) - { - Location = FVector( 0.f, 0.f, 0.f ); - } - - // Set volume (Pitch changes are not supported on current Android platforms!) - // also Location & Velocity - // Avoid doing the log calculation each update by only doing it if the volume changed if (Volume != VolumePreviousUpdate) { diff --git a/Engine/Source/Runtime/Android/AndroidLocalNotification/Private/AndroidLocalNotification.cpp b/Engine/Source/Runtime/Android/AndroidLocalNotification/Private/AndroidLocalNotification.cpp index 274568723036..c57c8b79c7f8 100644 --- a/Engine/Source/Runtime/Android/AndroidLocalNotification/Private/AndroidLocalNotification.cpp +++ b/Engine/Source/Runtime/Android/AndroidLocalNotification/Private/AndroidLocalNotification.cpp @@ -95,6 +95,11 @@ void FAndroidLocalNotificationService::ScheduleLocalNotificationAtTime(const FDa #endif } +void FAndroidLocalNotificationService::ScheduleLocalNotificationBadgeAtTime(const FDateTime& FireDateTime, bool LocalTime, const FString& ActivationEvent) +{ + // Do nothing... +} + void FAndroidLocalNotificationService::GetLaunchNotification(bool& NotificationLaunchedApp, FString& ActivationEvent, int32& FireDate) { #if PLATFORM_ANDROID diff --git a/Engine/Source/Runtime/Android/AndroidLocalNotification/Public/AndroidLocalNotification.h b/Engine/Source/Runtime/Android/AndroidLocalNotification/Public/AndroidLocalNotification.h index 2e8ca687206a..2caeec59fa03 100644 --- a/Engine/Source/Runtime/Android/AndroidLocalNotification/Public/AndroidLocalNotification.h +++ b/Engine/Source/Runtime/Android/AndroidLocalNotification/Public/AndroidLocalNotification.h @@ -37,6 +37,13 @@ public: * @param ActivationEvent A string that is passed in the delegate callback when the app is brought into the foreground from the user activating the notification */ virtual void ScheduleLocalNotificationAtTime(const FDateTime& FireDateTime, bool LocalTime, const FText& Title, const FText& Body, const FText& Action, const FString& ActivationEvent); + + /** Schedule a local notification badge at a specific time, inLocalTime specifies the current local time or if UTC time should be used + * @param FireDateTime The time at which to fire the local notification + * @param LocalTime If true the provided time is in the local timezone, if false it is in UTC + * @param ActivationEvent A string that is passed in the delegate callback when the app is brought into the foreground from the user activating the notification + */ + virtual void ScheduleLocalNotificationBadgeAtTime(const FDateTime& FireDateTime, bool LocalTime, const FString& ActivationEvent); /** Get the local notification that was used to launch the app * @param NotificationLaunchedApp Return true if a notification was used to launch the app diff --git a/Engine/Source/Runtime/Android/AndroidRuntimeSettings/Classes/AndroidRuntimeSettings.h b/Engine/Source/Runtime/Android/AndroidRuntimeSettings/Classes/AndroidRuntimeSettings.h index b79be50c8d8b..fe608d243677 100644 --- a/Engine/Source/Runtime/Android/AndroidRuntimeSettings/Classes/AndroidRuntimeSettings.h +++ b/Engine/Source/Runtime/Android/AndroidRuntimeSettings/Classes/AndroidRuntimeSettings.h @@ -372,10 +372,30 @@ public: UPROPERTY(GlobalConfig, EditAnywhere, Category = LaunchImages, meta = (DisplayName = "Show launch image")) bool bShowLaunchImage; - /** Android Audio encoding options */ - UPROPERTY(GlobalConfig, EditAnywhere, Category = DataCooker, meta = (DisplayName = "Audio encoding")) + /** Android encoding options. */ + UPROPERTY(GlobalConfig, EditAnywhere, Category = Audio, meta = (DisplayName = "Encoding Format")) TEnumAsByte AndroidAudio; + /** Sample rate to run the audio mixer with. */ + UPROPERTY(config, EditAnywhere, Category = "Audio", Meta = (DisplayName = "Audio Mixer Sample Rate")) + int32 AudioSampleRate; + + /** The amount of audio to compute each callback block. Lower values decrease latency but may increase CPU cost. */ + UPROPERTY(config, EditAnywhere, Category = "Audio", meta = (ClampMin = "512", ClampMax = "4096", DisplayName = "Callback Buffer Size")) + int32 AudioCallbackBufferFrameSize; + + /** The number of buffers to keep enqueued. More buffers increases latency, but can compensate for variable compute availability in audio callbacks on some platforms. */ + UPROPERTY(config, EditAnywhere, Category = "Audio", meta = (ClampMin = "2", UIMin = "2", DisplayName = "Number of Buffers To Enqueue")) + int32 AudioNumBuffersToEnqueue; + + /** The max number of channels (voices) to limit for this platform. The max channels used will be the minimum of this value and the global audio quality settings. A value of 0 will not apply a platform channel count max. */ + UPROPERTY(config, EditAnywhere, Category = "Audio", meta = (ClampMin = "0", UIMin = "0", DisplayName = "Max Channels")) + int32 AudioMaxChannels; + + /** The number of workers to use to compute source audio. Will only use up to the max number of sources. Will evenly divide sources to each source worker. */ + UPROPERTY(config, EditAnywhere, Category = "Audio", meta = (ClampMin = "0", UIMin = "0", DisplayName = "Number of Source Workers")) + int32 AudioNumSourceWorkers; + // Several Android graphics debuggers require configuration changes to be made to your application in order to operate. Choosing an option from this menu will configure your project to work with that graphics debugger. UPROPERTY(GlobalConfig, EditAnywhere, Category = GraphicsDebugger) TEnumAsByte AndroidGraphicsDebugger; diff --git a/Engine/Source/Runtime/Android/AndroidRuntimeSettings/Private/AndroidRuntimeSettings.cpp b/Engine/Source/Runtime/Android/AndroidRuntimeSettings/Private/AndroidRuntimeSettings.cpp index af44df53f7fb..1ca3f392db80 100644 --- a/Engine/Source/Runtime/Android/AndroidRuntimeSettings/Private/AndroidRuntimeSettings.cpp +++ b/Engine/Source/Runtime/Android/AndroidRuntimeSettings/Private/AndroidRuntimeSettings.cpp @@ -16,6 +16,9 @@ UAndroidRuntimeSettings::UAndroidRuntimeSettings(const FObjectInitializer& Objec , GoogleVRMode(EGoogleVRMode::DaydreamAndCardboard) , bEnableGooglePlaySupport(false) , bUseGetAccounts(false) + , AudioSampleRate(44100) + , AudioCallbackBufferFrameSize(1024) + , AudioNumBuffersToEnqueue(4) , bMultiTargetFormat_ETC1(true) , bMultiTargetFormat_ETC2(true) , bMultiTargetFormat_DXT(true) diff --git a/Engine/Source/Runtime/Android/AudioMixerAndroid/AudioMixerAndroid.Build.cs b/Engine/Source/Runtime/Android/AudioMixerAndroid/AudioMixerAndroid.Build.cs new file mode 100644 index 000000000000..1d0ebeb16d52 --- /dev/null +++ b/Engine/Source/Runtime/Android/AudioMixerAndroid/AudioMixerAndroid.Build.cs @@ -0,0 +1,29 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +using UnrealBuildTool; + +public class AudioMixerAndroid : ModuleRules +{ + public AudioMixerAndroid(ReadOnlyTargetRules Target) : base(Target) + { + PrivateIncludePathModuleNames.Add("TargetPlatform"); + PublicIncludePaths.Add("Runtime/AudioMixer/Public"); + PrivateIncludePaths.Add("Runtime/AudioMixer/Private"); + + PrivateDependencyModuleNames.AddRange( + new string[] { + "Core", + "CoreUObject", + "Engine", + } + ); + + PrivateDependencyModuleNames.Add("AudioMixer"); + + AddEngineThirdPartyPrivateStaticDependencies(Target, + "UEOgg", + "Vorbis", + "VorbisFile" + ); + } +} diff --git a/Engine/Source/Runtime/Android/AudioMixerAndroid/Private/AudioMixerAndroid.cpp b/Engine/Source/Runtime/Android/AudioMixerAndroid/Private/AudioMixerAndroid.cpp new file mode 100644 index 000000000000..ec3b812b0d89 --- /dev/null +++ b/Engine/Source/Runtime/Android/AudioMixerAndroid/Private/AudioMixerAndroid.cpp @@ -0,0 +1,17 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "AudioMixer.h" +#include "AudioMixerDevice.h" +#include "AudioMixerPlatformAndroid.h" + + +class FAudioMixerModuleAndroid : public IAudioDeviceModule +{ +public: + virtual FAudioDevice* CreateAudioDevice() override + { + return new Audio::FMixerDevice(new Audio::FMixerPlatformAndroid()); + } +}; + +IMPLEMENT_MODULE(FAudioMixerModuleAndroid, AudioMixerAndroid); diff --git a/Engine/Source/Runtime/Android/AudioMixerAndroid/Private/AudioMixerPlatformAndroid.cpp b/Engine/Source/Runtime/Android/AudioMixerAndroid/Private/AudioMixerPlatformAndroid.cpp new file mode 100644 index 000000000000..6ff9228041f3 --- /dev/null +++ b/Engine/Source/Runtime/Android/AudioMixerAndroid/Private/AudioMixerPlatformAndroid.cpp @@ -0,0 +1,387 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "AudioMixerPlatformAndroid.h" +#include "ModuleManager.h" +#include "AudioMixer.h" +#include "AudioMixerDevice.h" +#include "CoreGlobals.h" +#include "Misc/ConfigCacheIni.h" +#include "VorbisAudioInfo.h" +#include "ADPCMAudioInfo.h" + +#include +#include "SLES/OpenSLES_Android.h" + +DECLARE_LOG_CATEGORY_EXTERN(LogAudioMixerAndroid, Log, All); +DEFINE_LOG_CATEGORY(LogAudioMixerAndroid); + +#define UNREAL_AUDIO_TEST_WHITE_NOISE 0 + +// Macro to check result for XAudio2 failure, get string version, log, and return false +#define OPENSLES_RETURN_ON_FAIL(Result) \ + if (Result != SL_RESULT_SUCCESS) \ + { \ + const TCHAR* ErrorString = GetErrorString(Result); \ + AUDIO_PLATFORM_ERROR(ErrorString); \ + return false; \ + } + +#define OPENSLES_CHECK_ON_FAIL(Result) \ + if (Result != SL_RESULT_SUCCESS) \ + { \ + const TCHAR* ErrorString = GetErrorString(Result); \ + AUDIO_PLATFORM_ERROR(ErrorString); \ + check(false); \ + } + +#define OPENSLES_LOG_ON_FAIL(Result) \ + if (Result != SL_RESULT_SUCCESS) \ + { \ + const TCHAR* ErrorString = GetErrorString(Result); \ + AUDIO_PLATFORM_ERROR(ErrorString); \ + } + +namespace Audio +{ + FMixerPlatformAndroid::FMixerPlatformAndroid() + : bSuspended(false) + , bInitialized(false) + , bInCallback(false) + { + } + + FMixerPlatformAndroid::~FMixerPlatformAndroid() + { + if (bInitialized) + { + TeardownHardware(); + } + } + + const TCHAR* FMixerPlatformAndroid::GetErrorString(SLresult Result) + { + switch (Result) + { + case SL_RESULT_PRECONDITIONS_VIOLATED: return TEXT("SL_RESULT_PRECONDITIONS_VIOLATED"); + case SL_RESULT_PARAMETER_INVALID: return TEXT("SL_RESULT_PARAMETER_INVALID"); + case SL_RESULT_MEMORY_FAILURE: return TEXT("SL_RESULT_MEMORY_FAILURE"); + case SL_RESULT_RESOURCE_ERROR: return TEXT("SL_RESULT_RESOURCE_ERROR"); + case SL_RESULT_RESOURCE_LOST: return TEXT("SL_RESULT_RESOURCE_LOST"); + case SL_RESULT_IO_ERROR: return TEXT("SL_RESULT_IO_ERROR"); + case SL_RESULT_BUFFER_INSUFFICIENT: return TEXT("SL_RESULT_BUFFER_INSUFFICIENT"); + case SL_RESULT_CONTENT_CORRUPTED: return TEXT("SL_RESULT_CONTENT_CORRUPTED"); + case SL_RESULT_CONTENT_UNSUPPORTED: return TEXT("SL_RESULT_CONTENT_UNSUPPORTED"); + case SL_RESULT_CONTENT_NOT_FOUND: return TEXT("SL_RESULT_CONTENT_NOT_FOUND"); + case SL_RESULT_PERMISSION_DENIED: return TEXT("SL_RESULT_PERMISSION_DENIED"); + case SL_RESULT_FEATURE_UNSUPPORTED: return TEXT("SL_RESULT_FEATURE_UNSUPPORTED"); + case SL_RESULT_INTERNAL_ERROR: return TEXT("SL_RESULT_INTERNAL_ERROR"); + case SL_RESULT_OPERATION_ABORTED: return TEXT("SL_RESULT_OPERATION_ABORTED"); + case SL_RESULT_CONTROL_LOST: return TEXT("SL_RESULT_CONTROL_LOST"); + + default: + case SL_RESULT_UNKNOWN_ERROR: return TEXT("SL_RESULT_UNKNOWN_ERROR"); + } + } + + bool FMixerPlatformAndroid::InitializeHardware() + { + if (bInitialized) + { + return false; + } + + SLresult Result; + SLEngineOption EngineOption[] = { {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE} }; + + // Create engine + Result = slCreateEngine( &SL_EngineObject, 1, EngineOption, 0, NULL, NULL); + OPENSLES_CHECK_ON_FAIL(Result); + + // Realize the engine + Result = (*SL_EngineObject)->Realize(SL_EngineObject, SL_BOOLEAN_FALSE); + OPENSLES_CHECK_ON_FAIL(Result); + + // get the engine interface, which is needed in order to create other objects + Result = (*SL_EngineObject)->GetInterface(SL_EngineObject, SL_IID_ENGINE, &SL_EngineEngine); + OPENSLES_CHECK_ON_FAIL(Result); + + // create output mix + Result = (*SL_EngineEngine)->CreateOutputMix(SL_EngineEngine, &SL_OutputMixObject, 0, NULL, NULL ); + OPENSLES_CHECK_ON_FAIL(Result); + + // realize the output mix + Result = (*SL_OutputMixObject)->Realize(SL_OutputMixObject, SL_BOOLEAN_FALSE); + OPENSLES_CHECK_ON_FAIL(Result); + + bInitialized = true; + + return true; + } + + bool FMixerPlatformAndroid::TeardownHardware() + { + if(!bInitialized) + { + return true; + } + + // Teardown OpenSLES.. + // Destroy the SLES objects in reverse order of creation: + if (SL_OutputMixObject) + { + (*SL_OutputMixObject)->Destroy(SL_OutputMixObject); + SL_OutputMixObject = nullptr; + } + + if (SL_EngineObject) + { + (*SL_EngineObject)->Destroy(SL_EngineObject); + + SL_EngineObject = nullptr; + SL_EngineEngine = nullptr; + } + + bInitialized = false; + + return true; + } + + bool FMixerPlatformAndroid::IsInitialized() const + { + return bInitialized; + } + + bool FMixerPlatformAndroid::GetNumOutputDevices(uint32& OutNumOutputDevices) + { + OutNumOutputDevices = 1; + return true; + } + + bool FMixerPlatformAndroid::GetOutputDeviceInfo(const uint32 InDeviceIndex, FAudioPlatformDeviceInfo& OutInfo) + { + OutInfo.Name = TEXT("Android Audio Device"); + OutInfo.DeviceId = 0; + OutInfo.bIsSystemDefault = true; + OutInfo.SampleRate = 44100; // We don't really know of a way to get sample rate from an android device + OutInfo.NumChannels = 2; // Android doesn't support surround sound + OutInfo.Format = EAudioMixerStreamDataFormat::Int16; + OutInfo.OutputChannelArray.SetNum(2); + OutInfo.OutputChannelArray[0] = EAudioMixerChannel::FrontLeft; + OutInfo.OutputChannelArray[1] = EAudioMixerChannel::FrontRight; + return true; + } + + bool FMixerPlatformAndroid::GetDefaultOutputDeviceIndex(uint32& OutDefaultDeviceIndex) const + { + OutDefaultDeviceIndex = 0; + return true; + } + + bool FMixerPlatformAndroid::OpenAudioStream(const FAudioMixerOpenStreamParams& Params) + { + if (!bInitialized || AudioStreamInfo.StreamState != EAudioOutputStreamState::Closed) + { + return false; + } + + OpenStreamParams = Params; + + AudioStreamInfo.Reset(); + + AudioStreamInfo.OutputDeviceIndex = 0; + AudioStreamInfo.NumOutputFrames = OpenStreamParams.NumFrames; + AudioStreamInfo.NumBuffers = OpenStreamParams.NumBuffers; + AudioStreamInfo.AudioMixer = OpenStreamParams.AudioMixer; + + if (!GetOutputDeviceInfo(AudioStreamInfo.OutputDeviceIndex, AudioStreamInfo.DeviceInfo)) + { + return false; + } + + SLresult Result; + + // data info + SLDataLocator_AndroidSimpleBufferQueue LocationBuffer = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 1}; + + // PCM Info + SLDataFormat_PCM PCM_Format = { + SL_DATAFORMAT_PCM, + (SLuint32)AudioStreamInfo.DeviceInfo.NumChannels, + (SLuint32)(Params.SampleRate * 1000), // NOTE: OpenSLES has sample rates specified in millihertz. + SL_PCMSAMPLEFORMAT_FIXED_16, + SL_PCMSAMPLEFORMAT_FIXED_16, + SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT, + SL_BYTEORDER_LITTLEENDIAN + }; + + SLDataSource SoundDataSource = { &LocationBuffer, &PCM_Format }; + + // configure audio sink + SLDataLocator_OutputMix OutputMix = { SL_DATALOCATOR_OUTPUTMIX, SL_OutputMixObject }; + SLDataSink AudioSink = { &OutputMix, nullptr }; + + // create audio player + const SLInterfaceID InterfaceIds[] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME}; + const SLboolean Req[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; + + Result = (*SL_EngineEngine)->CreateAudioPlayer(SL_EngineEngine, &SL_PlayerObject, &SoundDataSource, &AudioSink, sizeof(InterfaceIds) / sizeof(SLInterfaceID), InterfaceIds, Req); + OPENSLES_RETURN_ON_FAIL(Result); + + // realize the player + Result = (*SL_PlayerObject)->Realize(SL_PlayerObject, SL_BOOLEAN_FALSE); + OPENSLES_RETURN_ON_FAIL(Result); + + // get the play interface + Result = (*SL_PlayerObject)->GetInterface(SL_PlayerObject, SL_IID_PLAY, &SL_PlayerPlayInterface); + OPENSLES_RETURN_ON_FAIL(Result); + + // buffer system + Result = (*SL_PlayerObject)->GetInterface(SL_PlayerObject, SL_IID_BUFFERQUEUE, &SL_PlayerBufferQueue); + OPENSLES_RETURN_ON_FAIL(Result); + + Result = (*SL_PlayerBufferQueue)->RegisterCallback(SL_PlayerBufferQueue, OpenSLBufferQueueCallback, (void*)this); + OPENSLES_RETURN_ON_FAIL(Result); + + AudioStreamInfo.StreamState = EAudioOutputStreamState::Open; + + return true; + } + + bool FMixerPlatformAndroid::CloseAudioStream() + { + if (!bInitialized || (AudioStreamInfo.StreamState != EAudioOutputStreamState::Open && AudioStreamInfo.StreamState != EAudioOutputStreamState::Stopped)) + { + return false; + } + + SLresult Result =(*SL_PlayerBufferQueue)->RegisterCallback(SL_PlayerBufferQueue, nullptr, nullptr); + + (*SL_PlayerObject)->Destroy(SL_PlayerObject); + + SL_PlayerObject = nullptr; + SL_PlayerPlayInterface = nullptr; + SL_PlayerBufferQueue = nullptr; + + AudioStreamInfo.StreamState = EAudioOutputStreamState::Closed; + + return true; + } + + bool FMixerPlatformAndroid::StartAudioStream() + { + BeginGeneratingAudio(); + + // set the player's state to playing + SLresult Result = (*SL_PlayerPlayInterface)->SetPlayState(SL_PlayerPlayInterface, SL_PLAYSTATE_PLAYING); + OPENSLES_CHECK_ON_FAIL(Result); + + return true; + } + + bool FMixerPlatformAndroid::StopAudioStream() + { + if(!bInitialized || AudioStreamInfo.StreamState != EAudioOutputStreamState::Running) + { + return false; + } + + if (AudioStreamInfo.StreamState != EAudioOutputStreamState::Stopped) + { + // set the player's state to stopped + SLresult Result = (*SL_PlayerPlayInterface)->SetPlayState(SL_PlayerPlayInterface, SL_PLAYSTATE_STOPPED); + OPENSLES_CHECK_ON_FAIL(Result); + + if (AudioStreamInfo.StreamState == EAudioOutputStreamState::Running) + { + StopGeneratingAudio(); + } + + check(AudioStreamInfo.StreamState == EAudioOutputStreamState::Stopped); + } + + return true; + } + + FAudioPlatformDeviceInfo FMixerPlatformAndroid::GetPlatformDeviceInfo() const + { + return AudioStreamInfo.DeviceInfo; + } + + FAudioPlatformSettings FMixerPlatformAndroid::GetPlatformSettings() const + { + return FAudioPlatformSettings::GetPlatformSettings(TEXT("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings")); + } + + void FMixerPlatformAndroid::SubmitBuffer(const uint8* Buffer) + { + SLresult Result = (*SL_PlayerBufferQueue)->Enqueue(SL_PlayerBufferQueue, Buffer, AudioStreamInfo.NumOutputFrames * AudioStreamInfo.DeviceInfo.NumChannels * sizeof(int16)); + OPENSLES_LOG_ON_FAIL(Result); + } + + FName FMixerPlatformAndroid::GetRuntimeFormat(USoundWave* InSoundWave) + { +#if WITH_OGGVORBIS + static FName NAME_OGG(TEXT("OGG")); + if (InSoundWave->HasCompressedData(NAME_OGG)) + { + return NAME_OGG; + } +#endif + + static FName NAME_ADPCM(TEXT("ADPCM")); + + return NAME_ADPCM; + } + + bool FMixerPlatformAndroid::HasCompressedAudioInfoClass(USoundWave* InSoundWave) + { + return true; + } + + ICompressedAudioInfo* FMixerPlatformAndroid::CreateCompressedAudioInfo(USoundWave* InSoundWave) + { +#if WITH_OGGVORBIS + static FName NAME_OGG(TEXT("OGG")); + if (InSoundWave->HasCompressedData(NAME_OGG)) + { + return new FVorbisAudioInfo(); + } +#endif + + static FName NAME_ADPCM(TEXT("ADPCM")); + + return new FADPCMAudioInfo(); + } + + FString FMixerPlatformAndroid::GetDefaultDeviceName() + { + return FString(); + } + + void FMixerPlatformAndroid::ResumeContext() + { + if (bSuspended) + { + UE_LOG(LogAudioMixerAndroid, Display, TEXT("Resuming Audio")); + bSuspended = false; + } + } + + void FMixerPlatformAndroid::SuspendContext() + { + if (!bSuspended) + { + UE_LOG(LogAudioMixerAndroid, Display, TEXT("Suspending Audio")); + bSuspended = true; + } + } + + void FMixerPlatformAndroid::OpenSLBufferQueueCallback(SLAndroidSimpleBufferQueueItf InQueueInterface, void* pContext) + { + FMixerPlatformAndroid* MixerPlatformAndroid = (FMixerPlatformAndroid*)pContext; + if (MixerPlatformAndroid != nullptr) + { + MixerPlatformAndroid->ReadNextBuffer(); + } + } +} diff --git a/Engine/Source/Runtime/Android/AudioMixerAndroid/Private/AudioMixerPlatformAndroid.h b/Engine/Source/Runtime/Android/AudioMixerAndroid/Private/AudioMixerPlatformAndroid.h new file mode 100644 index 000000000000..e6ebde56a153 --- /dev/null +++ b/Engine/Source/Runtime/Android/AudioMixerAndroid/Private/AudioMixerPlatformAndroid.h @@ -0,0 +1,64 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "AudioMixer.h" +#include +#include "SLES/OpenSLES_Android.h" + +// Any platform defines +namespace Audio +{ + + class FMixerPlatformAndroid : public IAudioMixerPlatformInterface + { + + public: + + FMixerPlatformAndroid(); + ~FMixerPlatformAndroid(); + + //~ Begin IAudioMixerPlatformInterface + virtual EAudioMixerPlatformApi::Type GetPlatformApi() const override { return EAudioMixerPlatformApi::OpenSLES; } + virtual bool InitializeHardware() override; + virtual bool TeardownHardware() override; + virtual bool IsInitialized() const override; + virtual bool GetNumOutputDevices(uint32& OutNumOutputDevices) override; + virtual bool GetOutputDeviceInfo(const uint32 InDeviceIndex, FAudioPlatformDeviceInfo& OutInfo) override; + virtual bool GetDefaultOutputDeviceIndex(uint32& OutDefaultDeviceIndex) const override; + virtual bool OpenAudioStream(const FAudioMixerOpenStreamParams& Params) override; + virtual bool CloseAudioStream() override; + virtual bool StartAudioStream() override; + virtual bool StopAudioStream() override; + virtual FAudioPlatformDeviceInfo GetPlatformDeviceInfo() const override; + virtual void SubmitBuffer(const uint8* Buffer) override; + virtual FName GetRuntimeFormat(USoundWave* InSoundWave) override; + virtual bool HasCompressedAudioInfoClass(USoundWave* InSoundWave) override; + virtual ICompressedAudioInfo* CreateCompressedAudioInfo(USoundWave* InSoundWave) override; + virtual FString GetDefaultDeviceName() override; + virtual FAudioPlatformSettings GetPlatformSettings() const override; + //~ End IAudioMixerPlatformInterface + + // These are not being used yet but they should be in the near future + void ResumeContext(); + void SuspendContext(); + + private: + const TCHAR* GetErrorString(SLresult Result); + + SLObjectItf SL_EngineObject; + SLEngineItf SL_EngineEngine; + SLObjectItf SL_OutputMixObject; + SLObjectItf SL_PlayerObject; + SLPlayItf SL_PlayerPlayInterface; + SLAndroidSimpleBufferQueueItf SL_PlayerBufferQueue; + + bool bSuspended; + bool bInitialized; + bool bInCallback; + + static void OpenSLBufferQueueCallback( SLAndroidSimpleBufferQueueItf InQueueInterface, void* pContext ); + }; + +} + diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimCustomInstance.cpp b/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimCustomInstance.cpp new file mode 100644 index 000000000000..3b054620f249 --- /dev/null +++ b/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimCustomInstance.cpp @@ -0,0 +1,57 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +/*============================================================================= + UAnimCustomInstance.cpp: Single Node Tree Instance + Only plays one animation at a time. +=============================================================================*/ + +#include "AnimCustomInstance.h" + +///////////////////////////////////////////////////// +// UAnimCustomInstance +///////////////////////////////////////////////////// + +UAnimCustomInstance::UAnimCustomInstance(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ +} + +void UAnimCustomInstance::UnbindFromSkeletalMeshComponent(USkeletalMeshComponent* InSkeletalMeshComponent) +{ +#if WITH_EDITOR + InSkeletalMeshComponent->SetUpdateAnimationInEditor(false); +#endif + + if (InSkeletalMeshComponent->GetAnimationMode() == EAnimationMode::Type::AnimationCustomMode) + { + UAnimCustomInstance* SequencerInstance = Cast(InSkeletalMeshComponent->GetAnimInstance()); + if (SequencerInstance) + { + InSkeletalMeshComponent->AnimScriptInstance = nullptr; + } + } + else if (InSkeletalMeshComponent->GetAnimationMode() == EAnimationMode::Type::AnimationBlueprint) + { + UAnimInstance* AnimInstance = InSkeletalMeshComponent->GetAnimInstance(); + if (AnimInstance) + { + AnimInstance->Montage_Stop(0.0f); + AnimInstance->UpdateAnimation(0.0f, false); + } + + // Update space bases to reset it back to ref pose + InSkeletalMeshComponent->RefreshBoneTransforms(); + InSkeletalMeshComponent->RefreshSlaveComponents(); + InSkeletalMeshComponent->UpdateComponentToWorld(); + } +} + +bool UAnimCustomInstance::ShouldUseSequenceInstancePlayer(const USkeletalMeshComponent* SkeletalMeshComponent) +{ + const USkeletalMesh* SkeletalMesh = SkeletalMeshComponent->SkeletalMesh; + // create proper anim instance to animate + UAnimInstance* AnimInstance = SkeletalMeshComponent->GetAnimInstance(); + + return (AnimInstance == nullptr || SkeletalMeshComponent->GetAnimationMode() != EAnimationMode::AnimationBlueprint || + AnimInstance->GetClass() != SkeletalMeshComponent->AnimClass || !SkeletalMesh->Skeleton->IsCompatible(AnimInstance->CurrentSkeleton)); +} \ No newline at end of file diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimNodes/AnimNode_BlendBoneByChannel.cpp b/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimNodes/AnimNode_BlendBoneByChannel.cpp new file mode 100644 index 000000000000..7cc9b95c527d --- /dev/null +++ b/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimNodes/AnimNode_BlendBoneByChannel.cpp @@ -0,0 +1,180 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "AnimNodes/AnimNode_BlendBoneByChannel.h" +#include "AnimationRuntime.h" +#include "Animation/AnimInstanceProxy.h" + +///////////////////////////////////////////////////// +// FAnimNode_BlendBoneByChannel + +void FAnimNode_BlendBoneByChannel::Initialize(const FAnimationInitializeContext& Context) +{ + FAnimNode_Base::Initialize(Context); + + A.Initialize(Context); + B.Initialize(Context); +} + +void FAnimNode_BlendBoneByChannel::CacheBones(const FAnimationCacheBonesContext& Context) +{ + A.CacheBones(Context); + B.CacheBones(Context); + + // Pre-validate bone entries, so we don't waste cycles every frame figuring it out. + ValidBoneEntries.Reset(); + const FBoneContainer& BoneContainer = Context.AnimInstanceProxy->GetRequiredBones(); + for (FBlendBoneByChannelEntry& Entry : BoneDefinitions) + { + Entry.SourceBone.Initialize(BoneContainer); + Entry.TargetBone.Initialize(BoneContainer); + + if (Entry.SourceBone.IsValid(BoneContainer) && Entry.TargetBone.IsValid(BoneContainer) + && (Entry.bBlendTranslation || Entry.bBlendRotation || Entry.bBlendScale)) + { + ValidBoneEntries.Add(Entry); + } + } +} + +void FAnimNode_BlendBoneByChannel::Update(const FAnimationUpdateContext& Context) +{ + QUICK_SCOPE_CYCLE_COUNTER(STAT_FAnimNode_BlendBoneByChannel_Update); + EvaluateGraphExposedInputs.Execute(Context); + + InternalBlendAlpha = AlphaScaleBias.ApplyTo(Alpha); + bBIsRelevant = FAnimWeight::IsRelevant(InternalBlendAlpha) && (ValidBoneEntries.Num() > 0); + + A.Update(Context); + if (bBIsRelevant) + { + B.Update(Context.FractionalWeight(InternalBlendAlpha)); + } +} + +void FAnimNode_BlendBoneByChannel::Evaluate(FPoseContext& Output) +{ + A.Evaluate(Output); + + if (bBIsRelevant) + { + const FBoneContainer& BoneContainer = Output.AnimInstanceProxy->GetRequiredBones(); + + FPoseContext PoseB(Output); + B.Evaluate(PoseB); + + // Faster code path in local space + if (TransformsSpace == EBoneControlSpace::BCS_BoneSpace) + { + const FCompactPose& SourcePose = PoseB.Pose; + FCompactPose& TargetPose = Output.Pose; + + for (const FBlendBoneByChannelEntry& Entry : ValidBoneEntries) + { + const FCompactPoseBoneIndex SourceBoneIndex = Entry.SourceBone.GetCompactPoseIndex(BoneContainer); + const FCompactPoseBoneIndex TargetBoneIndex = Entry.TargetBone.GetCompactPoseIndex(BoneContainer); + + const FTransform SourceTransform = SourcePose[SourceBoneIndex]; + FTransform& TargetTransform = TargetPose[TargetBoneIndex]; + + // Blend Transforms. + FTransform BlendedTransform; + BlendedTransform.Blend(TargetTransform, SourceTransform, InternalBlendAlpha); + + // Filter through channels + { + if (Entry.bBlendTranslation) + { + TargetTransform.SetTranslation(BlendedTransform.GetTranslation()); + } + + if (Entry.bBlendRotation) + { + TargetTransform.SetRotation(BlendedTransform.GetRotation()); + } + + if (Entry.bBlendScale) + { + TargetTransform.SetScale3D(BlendedTransform.GetScale3D()); + } + } + } + } + // Slower code path where local transforms have to be converted to a different space. + else + { + FCSPose TargetPoseCmpntSpace; + TargetPoseCmpntSpace.InitPose(Output.Pose); + + FCSPose SourcePoseCmpntSpace; + SourcePoseCmpntSpace.InitPose(PoseB.Pose); + + TArray QueuedModifiedBoneTransforms; + + const FTransform ComponentTransform = Output.AnimInstanceProxy->GetComponentTransform(); + + for (const FBlendBoneByChannelEntry& Entry : ValidBoneEntries) + { + const FCompactPoseBoneIndex SourceBoneIndex = Entry.SourceBone.GetCompactPoseIndex(BoneContainer); + const FCompactPoseBoneIndex TargetBoneIndex = Entry.TargetBone.GetCompactPoseIndex(BoneContainer); + + FTransform SourceTransform = SourcePoseCmpntSpace.GetComponentSpaceTransform(SourceBoneIndex); + FTransform TargetTransform = TargetPoseCmpntSpace.GetComponentSpaceTransform(TargetBoneIndex); + + // Convert Transforms to correct space. + FAnimationRuntime::ConvertCSTransformToBoneSpace(ComponentTransform, SourcePoseCmpntSpace, SourceTransform, SourceBoneIndex, TransformsSpace); + FAnimationRuntime::ConvertCSTransformToBoneSpace(ComponentTransform, TargetPoseCmpntSpace, TargetTransform, TargetBoneIndex, TransformsSpace); + + // Blend Transforms. + FTransform BlendedTransform; + BlendedTransform.Blend(TargetTransform, SourceTransform, InternalBlendAlpha); + + // Filter through channels + { + if (Entry.bBlendTranslation) + { + TargetTransform.SetTranslation(BlendedTransform.GetTranslation()); + } + + if (Entry.bBlendRotation) + { + TargetTransform.SetRotation(BlendedTransform.GetRotation()); + } + + if (Entry.bBlendScale) + { + TargetTransform.SetScale3D(BlendedTransform.GetScale3D()); + } + } + + // Convert blended and filtered result back in component space. + FAnimationRuntime::ConvertBoneSpaceTransformToCS(ComponentTransform, TargetPoseCmpntSpace, TargetTransform, TargetBoneIndex, TransformsSpace); + + // Queue transform to be applied after all transforms have been created. + // So we don't have parent bones affecting children bones. + QueuedModifiedBoneTransforms.Add(FBoneTransform(TargetBoneIndex, TargetTransform)); + } + + if (QueuedModifiedBoneTransforms.Num() > 0) + { + // Sort OutBoneTransforms so indices are in increasing order. + QueuedModifiedBoneTransforms.Sort(FCompareBoneTransformIndex()); + + // Apply transforms + TargetPoseCmpntSpace.SafeSetCSBoneTransforms(QueuedModifiedBoneTransforms); + + // Turn Component Space poses back into local space. + TargetPoseCmpntSpace.ConvertToLocalPoses(Output.Pose); + } + } + } +} + +void FAnimNode_BlendBoneByChannel::GatherDebugData(FNodeDebugData& DebugData) +{ + FString DebugLine = DebugData.GetNodeName(this); + DebugLine += FString::Printf(TEXT("(Alpha: %.1f%%)"), InternalBlendAlpha * 100); + DebugData.AddDebugItem(DebugLine); + + A.GatherDebugData(DebugData.BranchFlow(1.f)); + B.GatherDebugData(DebugData.BranchFlow(InternalBlendAlpha)); +} diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimNodes/AnimNode_CopyPoseFromMesh.cpp b/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimNodes/AnimNode_CopyPoseFromMesh.cpp index f6a9555148b4..d478ef78f74b 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimNodes/AnimNode_CopyPoseFromMesh.cpp +++ b/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimNodes/AnimNode_CopyPoseFromMesh.cpp @@ -7,31 +7,70 @@ // FAnimNode_CopyPoseFromMesh FAnimNode_CopyPoseFromMesh::FAnimNode_CopyPoseFromMesh() + : SourceMeshComponent(nullptr) + , bUseAttachedParent (false) { } void FAnimNode_CopyPoseFromMesh::Initialize(const FAnimationInitializeContext& Context) { FAnimNode_Base::Initialize(Context); - ReinitializeMeshComponent(Context.AnimInstanceProxy); + RefreshMeshComponent(Context.AnimInstanceProxy); } void FAnimNode_CopyPoseFromMesh::CacheBones(const FAnimationCacheBonesContext& Context) { } +void FAnimNode_CopyPoseFromMesh::RefreshMeshComponent(FAnimInstanceProxy* AnimInstanceProxy) +{ + auto ResetMeshComponent = [this](USkeletalMeshComponent* InMeshComponent, FAnimInstanceProxy* InAnimInstanceProxy) + { + if (CurrentlyUsedSourceMeshComponent.IsValid() && CurrentlyUsedSourceMeshComponent.Get() != InMeshComponent) + { + ReinitializeMeshComponent(InMeshComponent, InAnimInstanceProxy); + } + else if (!CurrentlyUsedSourceMeshComponent.IsValid() && InMeshComponent) + { + ReinitializeMeshComponent(InMeshComponent, InAnimInstanceProxy); + } + }; + + if (SourceMeshComponent.IsValid()) + { + ResetMeshComponent(SourceMeshComponent.Get(), AnimInstanceProxy); + } + else if (bUseAttachedParent) + { + USkeletalMeshComponent* Component = AnimInstanceProxy->GetSkelMeshComponent(); + if (Component) + { + USkeletalMeshComponent* ParentComponent = Cast(Component->GetAttachParent()); + if (ParentComponent) + { + ResetMeshComponent(ParentComponent, AnimInstanceProxy); + } + else + { + CurrentlyUsedSourceMeshComponent.Reset(); + } + } + else + { + CurrentlyUsedSourceMeshComponent.Reset(); + } + } + else + { + CurrentlyUsedSourceMeshComponent.Reset(); + } +} + void FAnimNode_CopyPoseFromMesh::Update(const FAnimationUpdateContext& Context) { EvaluateGraphExposedInputs.Execute(Context); - if (CurrentlyUsedSourceMeshComponent.IsValid() && CurrentlyUsedSourceMeshComponent.Get() != SourceMeshComponent) - { - ReinitializeMeshComponent(Context.AnimInstanceProxy); - } - else if (!CurrentlyUsedSourceMeshComponent.IsValid() && SourceMeshComponent) - { - ReinitializeMeshComponent(Context.AnimInstanceProxy); - } + RefreshMeshComponent(Context.AnimInstanceProxy); } void FAnimNode_CopyPoseFromMesh::Evaluate(FPoseContext& Output) @@ -74,16 +113,16 @@ void FAnimNode_CopyPoseFromMesh::GatherDebugData(FNodeDebugData& DebugData) { } -void FAnimNode_CopyPoseFromMesh::ReinitializeMeshComponent(FAnimInstanceProxy* AnimInstanceProxy) +void FAnimNode_CopyPoseFromMesh::ReinitializeMeshComponent(USkeletalMeshComponent* NewSourceMeshComponent, FAnimInstanceProxy* AnimInstanceProxy) { - CurrentlyUsedSourceMeshComponent = SourceMeshComponent; + CurrentlyUsedSourceMeshComponent = NewSourceMeshComponent; BoneMapToSource.Reset(); - if (SourceMeshComponent && SourceMeshComponent->SkeletalMesh && !SourceMeshComponent->IsPendingKill()) + if (NewSourceMeshComponent && NewSourceMeshComponent->SkeletalMesh && !NewSourceMeshComponent->IsPendingKill()) { USkeletalMeshComponent* TargetMeshComponent = AnimInstanceProxy->GetSkelMeshComponent(); if (TargetMeshComponent) { - USkeletalMesh* SourceSkelMesh = SourceMeshComponent->SkeletalMesh; + USkeletalMesh* SourceSkelMesh = NewSourceMeshComponent->SkeletalMesh; USkeletalMesh* TargetSkelMesh = TargetMeshComponent->SkeletalMesh; if (SourceSkelMesh == TargetSkelMesh) diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimNodes/AnimNode_CurveSource.cpp b/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimNodes/AnimNode_CurveSource.cpp index 160efb27af3c..6c373983b495 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimNodes/AnimNode_CurveSource.cpp +++ b/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimNodes/AnimNode_CurveSource.cpp @@ -20,28 +20,44 @@ void FAnimNode_CurveSource::PreUpdate(const UAnimInstance* AnimInstance) { ICurveSourceInterface* PotentialCurveSource = nullptr; + auto IsSpecifiedCurveSource = [&PotentialCurveSource](UObject* InObject, const FName& InSourceBinding, TScriptInterface& InOutCurveSource) + { + PotentialCurveSource = Cast(InObject); + if (PotentialCurveSource && PotentialCurveSource->Execute_GetBindingName(InObject) == InSourceBinding) + { + InOutCurveSource.SetObject(InObject); + InOutCurveSource.SetInterface(PotentialCurveSource); + return true; + } + + return false; + }; + AActor* Actor = AnimInstance->GetOwningActor(); if (Actor) { // check if our actor implements our interface - PotentialCurveSource = Cast(Actor); - if (PotentialCurveSource && PotentialCurveSource->Execute_GetBindingName(Actor) == SourceBinding) + if (IsSpecifiedCurveSource(Actor, SourceBinding, CurveSource)) { - CurveSource.SetObject(Actor); - CurveSource.SetInterface(PotentialCurveSource); + return; } - else + + for (TFieldIterator PropertyIt(Actor->GetClass(), EFieldIteratorFlags::IncludeSuper); PropertyIt; ++PropertyIt) { - for (TFieldIterator PropertyIt(Actor->GetClass(), EFieldIteratorFlags::IncludeSuper); PropertyIt; ++PropertyIt) + UObjectProperty* ObjProp = *PropertyIt; + UActorComponent* ActorComponent = Cast(ObjProp->GetObjectPropertyValue(ObjProp->ContainerPtrToValuePtr(Actor))); + if (IsSpecifiedCurveSource(ActorComponent, SourceBinding, CurveSource)) { - UObjectProperty* ObjProp = *PropertyIt; - UActorComponent* ActorComponent = Cast(ObjProp->GetObjectPropertyValue(ObjProp->ContainerPtrToValuePtr(Actor))); - PotentialCurveSource = Cast(ActorComponent); - if (PotentialCurveSource && PotentialCurveSource->Execute_GetBindingName(ActorComponent) == SourceBinding) - { - CurveSource.SetObject(ActorComponent); - CurveSource.SetInterface(PotentialCurveSource); - } + return; + } + } + + const TSet& ActorOwnedComponents = Actor->GetComponents(); + for (UActorComponent* OwnedComponent : ActorOwnedComponents) + { + if (IsSpecifiedCurveSource(OwnedComponent, SourceBinding, CurveSource)) + { + return; } } } diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimNodes/AnimNode_LayeredBoneBlend.cpp b/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimNodes/AnimNode_LayeredBoneBlend.cpp index 378b52ad1859..c76b09e022ff 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimNodes/AnimNode_LayeredBoneBlend.cpp +++ b/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimNodes/AnimNode_LayeredBoneBlend.cpp @@ -18,7 +18,7 @@ void FAnimNode_LayeredBoneBlend::Initialize(const FAnimationInitializeContext& C // initialize children BasePose.Initialize(Context); - if ( NumPoses > 0 ) + if (NumPoses > 0) { for (int32 ChildIndex = 0; ChildIndex < NumPoses; ++ChildIndex) { @@ -41,7 +41,7 @@ void FAnimNode_LayeredBoneBlend::PostCompile(const class USkeleton* InSkeleton) void FAnimNode_LayeredBoneBlend::RebuildCacheData(const USkeleton* InSkeleton) { - // make sure it's inished post load yet, this might cause more things to cache in initialize instead of during cooking + // make sure it's Finished post load yet, this might cause more things to cache in initialize instead of during cooking if (InSkeleton && !(InSkeleton->GetFlags() & RF_NeedPostLoad)) { FAnimationRuntime::CreateMaskWeights(PerBoneBlendWeights, LayerSetup, InSkeleton); @@ -64,11 +64,12 @@ void FAnimNode_LayeredBoneBlend::ReinitializeBoneBlendWeights(const FBoneContain // build desired bone weights const TArray& RequiredBoneIndices = RequiredBones.GetBoneIndicesArray(); - DesiredBoneBlendWeights.SetNumZeroed(RequiredBoneIndices.Num()); - for (int32 RequiredBoneIndex = 0; RequiredBoneIndex < RequiredBoneIndices.Num(); ++RequiredBoneIndex) + const int32 NumRequiredBones = RequiredBoneIndices.Num(); + DesiredBoneBlendWeights.SetNumZeroed(NumRequiredBones); + for (int32 RequiredBoneIndex=0; RequiredBoneIndexGetSkeleton())) + { + ReinitializeBoneBlendWeights(Context.AnimInstanceProxy->GetRequiredBones(), Context.AnimInstanceProxy->GetSkeleton()); + + // If Cache is still invalid, we don't have correct DesiredBoneBlendWeights, so abort. + // bHasRelevantPoses == false, will passthrough in evaluate. + if (!ensure(IsCacheInvalid(Context.AnimInstanceProxy->GetSkeleton()))) + { + break; + } + } + else + { + FAnimationRuntime::UpdateDesiredBoneWeight(DesiredBoneBlendWeights, CurrentBoneBlendWeights, BlendWeights); + } + bHasRelevantPoses = true; if(bBlendRootMotionBasedOnRootBone) @@ -192,7 +209,7 @@ void FAnimNode_LayeredBoneBlend::Evaluate(FPoseContext& Output) for (int32 ChildIndex = 0; ChildIndex < NumPoses; ++ChildIndex) { - if (BlendWeights[ChildIndex] > ZERO_ANIMWEIGHT_THRESH) + if (FAnimWeight::IsRelevant(BlendWeights[ChildIndex])) { FPoseContext CurrentPoseContext(Output); BlendPoses[ChildIndex].Evaluate(CurrentPoseContext); diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimNodes/AnimNode_RotationOffsetBlendSpace.cpp b/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimNodes/AnimNode_RotationOffsetBlendSpace.cpp index 5a99226a8bd3..6cc77df807ad 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimNodes/AnimNode_RotationOffsetBlendSpace.cpp +++ b/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimNodes/AnimNode_RotationOffsetBlendSpace.cpp @@ -6,6 +6,12 @@ ///////////////////////////////////////////////////// // FAnimNode_RotationOffsetBlendSpace +FAnimNode_RotationOffsetBlendSpace::FAnimNode_RotationOffsetBlendSpace() + : LODThreshold(INDEX_NONE) + , Alpha(1.f) +{ +} + void FAnimNode_RotationOffsetBlendSpace::Initialize(const FAnimationInitializeContext& Context) { FAnimNode_BlendSpacePlayer::Initialize(Context); @@ -20,10 +26,13 @@ void FAnimNode_RotationOffsetBlendSpace::CacheBones(const FAnimationCacheBonesCo void FAnimNode_RotationOffsetBlendSpace::UpdateAssetPlayer(const FAnimationUpdateContext& Context) { + EvaluateGraphExposedInputs.Execute(Context); + + ActualAlpha = AlphaScaleBias.ApplyTo(Alpha); bIsLODEnabled = IsLODEnabled(Context.AnimInstanceProxy, LODThreshold); - if (bIsLODEnabled) + if (bIsLODEnabled && FAnimWeight::IsRelevant(ActualAlpha)) { - FAnimNode_BlendSpacePlayer::UpdateAssetPlayer(Context); + UpdateInternal(Context); } BasePose.Update(Context); @@ -34,14 +43,14 @@ void FAnimNode_RotationOffsetBlendSpace::Evaluate(FPoseContext& Context) // Evaluate base pose BasePose.Evaluate(Context); - if (bIsLODEnabled) + if (bIsLODEnabled && FAnimWeight::IsRelevant(ActualAlpha)) { // Evaluate MeshSpaceRotation additive blendspace FPoseContext MeshSpaceRotationAdditivePoseContext(Context); FAnimNode_BlendSpacePlayer::Evaluate(MeshSpaceRotationAdditivePoseContext); // Accumulate poses together - FAnimationRuntime::AccumulateMeshSpaceRotationAdditiveToLocalPose(Context.Pose, MeshSpaceRotationAdditivePoseContext.Pose, Context.Curve, MeshSpaceRotationAdditivePoseContext.Curve, 1.f); + FAnimationRuntime::AccumulateMeshSpaceRotationAdditiveToLocalPose(Context.Pose, MeshSpaceRotationAdditivePoseContext.Pose, Context.Curve, MeshSpaceRotationAdditivePoseContext.Curve, ActualAlpha); // Resulting rotations are not normalized, so normalize here. Context.Pose.NormalizeRotations(); @@ -52,13 +61,10 @@ void FAnimNode_RotationOffsetBlendSpace::GatherDebugData(FNodeDebugData& DebugDa { FString DebugLine = DebugData.GetNodeName(this); - DebugLine += FString::Printf(TEXT("(Play Time: %.3f)"), InternalTimeAccumulator); + DebugLine += FString::Printf(TEXT("Alpha (%.1f%%) PlayTime (%.3f)"), ActualAlpha * 100.f, InternalTimeAccumulator); DebugData.AddDebugItem(DebugLine); BasePose.GatherDebugData(DebugData); } -FAnimNode_RotationOffsetBlendSpace::FAnimNode_RotationOffsetBlendSpace() - : LODThreshold(INDEX_NONE) -{ -} + diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimSequencerInstance.cpp b/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimSequencerInstance.cpp index 39cbe7ca6254..ba20c19eb14c 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimSequencerInstance.cpp +++ b/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimSequencerInstance.cpp @@ -7,7 +7,6 @@ #include "AnimSequencerInstance.h" #include "AnimSequencerInstanceProxy.h" -#include "Components/SkeletalMeshComponent.h" ///////////////////////////////////////////////////// // UAnimSequencerInstance @@ -24,46 +23,6 @@ FAnimInstanceProxy* UAnimSequencerInstance::CreateAnimInstanceProxy() return new FAnimSequencerInstanceProxy(this); } -bool UAnimSequencerInstance::ShouldUseSequenceInstancePlayer(const USkeletalMeshComponent* SkeletalMeshComponent) -{ - const USkeletalMesh* SkeletalMesh = SkeletalMeshComponent->SkeletalMesh; - // create proper anim instance to animate - UAnimInstance* AnimInstance = SkeletalMeshComponent->GetAnimInstance(); - - return (AnimInstance == nullptr || SkeletalMeshComponent->GetAnimationMode() != EAnimationMode::AnimationBlueprint || - AnimInstance->GetClass() != SkeletalMeshComponent->AnimClass || !SkeletalMesh->Skeleton->IsCompatible(AnimInstance->CurrentSkeleton)); -} - -void UAnimSequencerInstance::UnbindFromSkeletalMeshComponent(USkeletalMeshComponent* InSkeletalMeshComponent) -{ -#if WITH_EDITOR - InSkeletalMeshComponent->SetUpdateAnimationInEditor(false); -#endif - - if (InSkeletalMeshComponent->GetAnimationMode() == EAnimationMode::Type::AnimationCustomMode) - { - UAnimSequencerInstance* SequencerInstance = Cast(InSkeletalMeshComponent->GetAnimInstance()); - if (SequencerInstance) - { - InSkeletalMeshComponent->AnimScriptInstance = nullptr; - } - } - else if (InSkeletalMeshComponent->GetAnimationMode() == EAnimationMode::Type::AnimationBlueprint) - { - UAnimInstance* AnimInstance = InSkeletalMeshComponent->GetAnimInstance(); - if (AnimInstance) - { - AnimInstance->Montage_Stop(0.0f); - AnimInstance->UpdateAnimation(0.0f, false); - } - - // Update space bases to reset it back to ref pose - InSkeletalMeshComponent->RefreshBoneTransforms(); - InSkeletalMeshComponent->RefreshSlaveComponents(); - InSkeletalMeshComponent->UpdateComponentToWorld(); - } -} - void UAnimSequencerInstance::UpdateAnimTrack(UAnimSequenceBase* InAnimSequence, int32 SequenceId, float InPosition, float Weight, bool bFireNotifies) { GetProxyOnGameThread().UpdateAnimTrack(InAnimSequence, SequenceId, InPosition, Weight, bFireNotifies); diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Private/BoneControllers/AnimNode_AnimDynamics.cpp b/Engine/Source/Runtime/AnimGraphRuntime/Private/BoneControllers/AnimNode_AnimDynamics.cpp index 6a88e6b98b2a..8159344507ca 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Private/BoneControllers/AnimNode_AnimDynamics.cpp +++ b/Engine/Source/Runtime/AnimGraphRuntime/Private/BoneControllers/AnimNode_AnimDynamics.cpp @@ -698,7 +698,6 @@ void FAnimNode_AnimDynamics::PreUpdate(const UAnimInstance* InAnimInstance) const UWorld* World = SkelComp->GetWorld(); check(World->GetWorldSettings()); - check(World->Scene); CurrentTimeDilation = World->GetWorldSettings()->GetEffectiveTimeDilation(); if(CVarEnableWind.GetValueOnAnyThread() == 1 && bEnableWind) @@ -709,7 +708,7 @@ void FAnimNode_AnimDynamics::PreUpdate(const UAnimInstance* InAnimInstance) { Body->bWindEnabled = bEnableWind; - if(Body->bWindEnabled) + if(Body->bWindEnabled && World->Scene) { FSceneInterface* Scene = World->Scene; @@ -719,9 +718,9 @@ void FAnimNode_AnimDynamics::PreUpdate(const UAnimInstance* InAnimInstance) // Setup wind data Body->bWindEnabled = true; - Scene->GetWindParameters_GameThread(SkelComp->ComponentToWorld.TransformPosition(Body->Pose.Position), Body->WindData.WindDirection, Body->WindData.WindSpeed, WindMinGust, WindMaxGust); + Scene->GetWindParameters_GameThread(SkelComp->GetComponentTransform().TransformPosition(Body->Pose.Position), Body->WindData.WindDirection, Body->WindData.WindSpeed, WindMinGust, WindMaxGust); - Body->WindData.WindDirection = SkelComp->ComponentToWorld.Inverse().TransformVector(Body->WindData.WindDirection); + Body->WindData.WindDirection = SkelComp->GetComponentTransform().Inverse().TransformVector(Body->WindData.WindDirection); Body->WindData.WindAdaption = FMath::FRandRange(0.0f, 2.0f); Body->WindData.BodyWindScale = WindScale; } diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Private/BoneControllers/AnimNode_ScaleChainLength.cpp b/Engine/Source/Runtime/AnimGraphRuntime/Private/BoneControllers/AnimNode_ScaleChainLength.cpp index 217574abe3f1..39cf2a6861e4 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Private/BoneControllers/AnimNode_ScaleChainLength.cpp +++ b/Engine/Source/Runtime/AnimGraphRuntime/Private/BoneControllers/AnimNode_ScaleChainLength.cpp @@ -9,7 +9,9 @@ // FAnimNode_ScaleChainLength FAnimNode_ScaleChainLength::FAnimNode_ScaleChainLength() + : Alpha(1.f) { + ChainInitialLength = EScaleChainInitialLength::FixedDefaultLengthValue; } void FAnimNode_ScaleChainLength::Initialize(const FAnimationInitializeContext& Context) @@ -22,6 +24,8 @@ void FAnimNode_ScaleChainLength::Update(const FAnimationUpdateContext& Context) { EvaluateGraphExposedInputs.Execute(Context); InputPose.Update(Context); + + ActualAlpha = AlphaScaleBias.ApplyTo(Alpha); } void FAnimNode_ScaleChainLength::CacheBones(const FAnimationCacheBonesContext& Context) @@ -37,8 +41,7 @@ void FAnimNode_ScaleChainLength::Evaluate(FPoseContext& Output) // Evaluate incoming pose into our output buffer. InputPose.Evaluate(Output); - const float FinalAlpha = AlphaScaleBias.ApplyTo(Alpha); - if (!FAnimWeight::IsRelevant(FinalAlpha)) + if (!FAnimWeight::IsRelevant(ActualAlpha)) { return; } @@ -60,7 +63,7 @@ void FAnimNode_ScaleChainLength::Evaluate(FPoseContext& Output) if (bBoneSetupIsValid) { - FCompactPoseBoneIndex StartBoneIndex = ChainStartBone.GetCompactPoseIndex(BoneContainer); + const FCompactPoseBoneIndex StartBoneIndex = ChainStartBone.GetCompactPoseIndex(BoneContainer); FCompactPoseBoneIndex BoneIndex = ChainEndBone.GetCompactPoseIndex(BoneContainer); ChainBoneIndices.Add(BoneIndex); if (BoneIndex != INDEX_NONE) @@ -92,8 +95,9 @@ void FAnimNode_ScaleChainLength::Evaluate(FPoseContext& Output) const FTransform StartTransformCompSpace = CSPose.GetComponentSpaceTransform(ChainBoneIndices[0]); const float DesiredChainLength = (TargetLocationCompSpace - StartTransformCompSpace.GetLocation()).Size(); - const float ChainLengthScale = !FMath::IsNearlyZero(DefaultChainLength) ? (DesiredChainLength / DefaultChainLength) : 1.f; - const float ChainLengthScaleWithAlpha = FMath::LerpStable(1.f, ChainLengthScale, FinalAlpha); + const float InitialChainLength = GetInitialChainLength(Output.Pose, CSPose); + const float ChainLengthScale = !FMath::IsNearlyZero(InitialChainLength) ? (DesiredChainLength / InitialChainLength) : 1.f; + const float ChainLengthScaleWithAlpha = FMath::LerpStable(1.f, ChainLengthScale, ActualAlpha); // If we're not going to scale anything, early out. if (FMath::IsNearlyEqual(ChainLengthScaleWithAlpha, 1.f)) @@ -101,19 +105,46 @@ void FAnimNode_ScaleChainLength::Evaluate(FPoseContext& Output) return; } - // Scale translation of all bones. - FCompactPose& BSPose = Output.Pose; + // Scale translation of all bones in local space. + FCompactPose& LSPose = Output.Pose; for (const FCompactPoseBoneIndex& BoneIndex : ChainBoneIndices) { // Get bone space transform, scale transition. - BSPose[BoneIndex].ScaleTranslation(ChainLengthScaleWithAlpha); + LSPose[BoneIndex].ScaleTranslation(ChainLengthScaleWithAlpha); } } +float FAnimNode_ScaleChainLength::GetInitialChainLength(FCompactPose& InLSPose, FCSPose& InCSPose) const +{ + switch (ChainInitialLength) + { + case EScaleChainInitialLength::Distance : + { + const FVector ChainStartLocation = InCSPose.GetComponentSpaceTransform(ChainBoneIndices[0]).GetLocation(); + const FVector ChainEndLocation = InCSPose.GetComponentSpaceTransform(ChainBoneIndices.Last()).GetLocation(); + return (ChainEndLocation - ChainStartLocation).Size(); + } + + case EScaleChainInitialLength::ChainLength : + { + float ChainLength = 0.f; + for (const FCompactPoseBoneIndex& BoneIndex : ChainBoneIndices) + { + ChainLength += InLSPose[BoneIndex].GetTranslation().Size(); + } + return ChainLength; + } + }; + + // Fallback is using fixed value DefaultChainLength. + return DefaultChainLength; +} + void FAnimNode_ScaleChainLength::GatherDebugData(FNodeDebugData& DebugData) { FString DebugLine = DebugData.GetNodeName(this); - + DebugLine += FString::Printf(TEXT("Alpha (%.1f%%)"), ActualAlpha * 100.f); DebugData.AddDebugItem(DebugLine); + InputPose.GatherDebugData(DebugData); } diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimCustomInstance.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimCustomInstance.h new file mode 100644 index 000000000000..849562fb5aaf --- /dev/null +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimCustomInstance.h @@ -0,0 +1,70 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +/** + * + * This Instance only contains one AnimationAsset, and produce poses + * Used by Preview in AnimGraph, Playing single animation in Kismet2 and etc + */ + +#pragma once +#include "Animation/AnimInstance.h" +#include "Components/SkeletalMeshComponent.h" +#include "AnimCustomInstance.generated.h" + +UCLASS(transient, NotBlueprintable) +class ANIMGRAPHRUNTIME_API UAnimCustomInstance : public UAnimInstance +{ + GENERATED_UCLASS_BODY() + + /** + * Called to bind a typed UAnimCustomInstance to an existing skeletal mesh component + * @return the current (or newly created) UAnimCustomInstance + */ + template + static InstanceClassType* BindToSkeletalMeshComponent(USkeletalMeshComponent* InSkeletalMeshComponent) + { + // make sure to tick and refresh all the time when ticks + // @TODO: this needs restoring post-binding + InSkeletalMeshComponent->MeshComponentUpdateFlag = EMeshComponentUpdateFlag::AlwaysTickPoseAndRefreshBones; +#if WITH_EDITOR + InSkeletalMeshComponent->SetUpdateAnimationInEditor(true); +#endif + + // we use sequence instance if it's using anim blueprint that matches. Otherwise, we create sequence player + // this might need more check - i.e. making sure if it's same skeleton and so on, + // Ideally we could just call NeedToSpawnAnimScriptInstance call, which is protected now + const bool bShouldUseSequenceInstance = ShouldUseSequenceInstancePlayer(InSkeletalMeshComponent); + + // if it should use sequence instance + if (bShouldUseSequenceInstance) + { + // this has to wrap around with this because we don't want to reinitialize everytime they come here + // SetAnimationMode will reinitiaize it even if it's same, so make sure we just call SetAnimationMode if not AnimationCustomMode + if (InSkeletalMeshComponent->GetAnimationMode() != EAnimationMode::AnimationCustomMode) + { + InSkeletalMeshComponent->SetAnimationMode(EAnimationMode::AnimationCustomMode); + } + + if (Cast(InSkeletalMeshComponent->AnimScriptInstance) == nullptr || !InSkeletalMeshComponent->AnimScriptInstance->GetClass()->IsChildOf(InstanceClassType::StaticClass())) + { + InstanceClassType* SequencerInstance = NewObject(InSkeletalMeshComponent, InstanceClassType::StaticClass()); + InSkeletalMeshComponent->AnimScriptInstance = SequencerInstance; + InSkeletalMeshComponent->AnimScriptInstance->InitializeAnimation(); + return SequencerInstance; + } + else + { + return Cast(InSkeletalMeshComponent->AnimScriptInstance); + } + } + + return nullptr; + } + + /** Called to unbind a UAnimCustomInstance to an existing skeletal mesh component */ + static void UnbindFromSkeletalMeshComponent(USkeletalMeshComponent* InSkeletalMeshComponent); + +private: + /** Helper function for BindToSkeletalMeshComponent */ + static bool ShouldUseSequenceInstancePlayer(const USkeletalMeshComponent* SkeletalMeshComponent); +}; diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_AimOffsetLookAt.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_AimOffsetLookAt.h index acd86062d411..fbbdad98ec51 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_AimOffsetLookAt.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_AimOffsetLookAt.h @@ -9,7 +9,7 @@ #include "AnimNode_AimOffsetLookAt.generated.h" //@TODO: Comment -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_AimOffsetLookAt : public FAnimNode_BlendSpacePlayer { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_ApplyAdditive.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_ApplyAdditive.h index 9acab2064e4b..46efdafd8e7a 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_ApplyAdditive.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_ApplyAdditive.h @@ -8,7 +8,7 @@ #include "Animation/InputScaleBias.h" #include "AnimNode_ApplyAdditive.generated.h" -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_ApplyAdditive : public FAnimNode_Base { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_BlendBoneByChannel.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_BlendBoneByChannel.h new file mode 100644 index 000000000000..3add28cd2589 --- /dev/null +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_BlendBoneByChannel.h @@ -0,0 +1,99 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "Animation/AnimNodeBase.h" +#include "Animation/InputScaleBias.h" +#include "BoneContainer.h" +#include "AnimNode_BlendBoneByChannel.generated.h" + +USTRUCT(BlueprintInternalUseOnly) +struct FBlendBoneByChannelEntry +{ + GENERATED_USTRUCT_BODY() + + /** Bone to take Transform from */ + UPROPERTY(EditAnywhere, Category = Blend) + FBoneReference SourceBone; + + /** Bone to apply Transform to */ + UPROPERTY(EditAnywhere, Category = Blend) + FBoneReference TargetBone; + + /** Copy Translation from Source to Target */ + UPROPERTY(EditAnywhere, Category = Blend) + bool bBlendTranslation; + + /** Copy Rotation from Source to Target */ + UPROPERTY(EditAnywhere, Category = Blend) + bool bBlendRotation; + + /** Copy Scale from Source to Target */ + UPROPERTY(EditAnywhere, Category = Blend) + bool bBlendScale; + + FBlendBoneByChannelEntry() + : bBlendTranslation(true) + , bBlendRotation(true) + , bBlendScale(true) + { + } +}; + +USTRUCT(BlueprintInternalUseOnly) +struct ANIMGRAPHRUNTIME_API FAnimNode_BlendBoneByChannel : public FAnimNode_Base +{ + GENERATED_USTRUCT_BODY() + +public: + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Links) + FPoseLink A; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Links) + FPoseLink B; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Settings, meta = (PinShownByDefault)) + mutable float Alpha; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Settings) + FInputScaleBias AlphaScaleBias; + + UPROPERTY(EditAnywhere, Category = Blend) + TArray BoneDefinitions; + + /** Space to convert transforms into prior to copying channels */ + UPROPERTY(EditAnywhere, Category = Blend) + TEnumAsByte TransformsSpace; + +protected: + UPROPERTY(Transient) + mutable float InternalBlendAlpha; + + UPROPERTY(Transient) + mutable bool bBIsRelevant; + +private: + // Array of bone entries, that has been validated to be correct at runtime. + // So we don't have to perform validation checks per frame. + UPROPERTY(Transient) + TArray ValidBoneEntries; + +public: + FAnimNode_BlendBoneByChannel() + : Alpha(0.0f) + , TransformsSpace(EBoneControlSpace::BCS_BoneSpace) + { + } + + // FAnimNode_Base interface + virtual void Initialize(const FAnimationInitializeContext& Context) override; + virtual void CacheBones(const FAnimationCacheBonesContext& Context) override; + virtual void Update(const FAnimationUpdateContext& Context) override; + virtual void Evaluate(FPoseContext& Output) override; + virtual void GatherDebugData(FNodeDebugData& DebugData) override; + // End of FAnimNode_Base interface +}; + diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_BlendListBase.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_BlendListBase.h index 45fb60f225ec..16a7e51686e0 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_BlendListBase.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_BlendListBase.h @@ -13,7 +13,7 @@ class UBlendProfile; class UCurveFloat; // Blend list node; has many children -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_BlendListBase : public FAnimNode_Base { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_BlendListByBool.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_BlendListByBool.h index 877416fee016..70973782b885 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_BlendListByBool.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_BlendListByBool.h @@ -8,7 +8,7 @@ #include "AnimNode_BlendListByBool.generated.h" // This node is effectively a 'branch', picking one of two input poses based on an input Boolean value -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_BlendListByBool : public FAnimNode_BlendListBase { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_BlendListByEnum.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_BlendListByEnum.h index 66ec00e35cfc..0e6c0ff1be52 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_BlendListByEnum.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_BlendListByEnum.h @@ -8,7 +8,7 @@ #include "AnimNode_BlendListByEnum.generated.h" // Blend List by Enum, it changes based on enum input that enters -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_BlendListByEnum : public FAnimNode_BlendListBase { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_BlendListByInt.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_BlendListByInt.h index cb19f1aa02a8..350e6ba81fb3 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_BlendListByInt.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_BlendListByInt.h @@ -8,7 +8,7 @@ #include "AnimNode_BlendListByInt.generated.h" // Blend list node; has many children -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_BlendListByInt : public FAnimNode_BlendListBase { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_BlendSpaceEvaluator.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_BlendSpaceEvaluator.h index 0a03ccc1b700..e67fcf1254fb 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_BlendSpaceEvaluator.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_BlendSpaceEvaluator.h @@ -10,7 +10,7 @@ // Evaluates a point in a blendspace, using a specific time input rather than advancing time internally. // Typically the playback position of the animation for this node will represent something other than time, like jump height. // This node will not trigger any notifies present in the associated sequence. -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_BlendSpaceEvaluator : public FAnimNode_BlendSpacePlayer { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_BlendSpacePlayer.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_BlendSpacePlayer.h index 292091028853..6598fd5be226 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_BlendSpacePlayer.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_BlendSpacePlayer.h @@ -11,7 +11,7 @@ class UBlendSpaceBase; //@TODO: Comment -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_BlendSpacePlayer : public FAnimNode_AssetPlayerBase { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_CopyPoseFromMesh.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_CopyPoseFromMesh.h index 986eae554176..ce6151dc8c3e 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_CopyPoseFromMesh.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_CopyPoseFromMesh.h @@ -14,13 +14,18 @@ struct FAnimInstanceProxy; * Simple controller to copy a bone's transform to another one. */ -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_CopyPoseFromMesh : public FAnimNode_Base { GENERATED_USTRUCT_BODY() + /* This is used by default if it's valid */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Copy, meta=(PinShownByDefault)) - USkeletalMeshComponent* SourceMeshComponent; + TWeakObjectPtr SourceMeshComponent; + + /* If SourceMeshComponent is not valid, and if this is true, it will look for attahced parent as a source */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Copy, meta = (NeverAsPin)) + bool bUseAttachedParent; FAnimNode_CopyPoseFromMesh(); @@ -38,5 +43,6 @@ private: TMap BoneMapToSource; // reinitialize mesh component - void ReinitializeMeshComponent(FAnimInstanceProxy* AnimInstanceProxy); + void ReinitializeMeshComponent(USkeletalMeshComponent* NewSkeletalMeshComponent, FAnimInstanceProxy* AnimInstanceProxy); + void RefreshMeshComponent(FAnimInstanceProxy* AnimInstanceProxy); }; diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_CurveSource.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_CurveSource.h index d64fa1cffea6..3cfd8217aad8 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_CurveSource.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_CurveSource.h @@ -13,7 +13,7 @@ class UAnimInstance; /** Supply curves from some external source (e.g. audio) */ -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_CurveSource : public FAnimNode_Base { GENERATED_BODY() diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_LayeredBoneBlend.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_LayeredBoneBlend.h index 46ee71348e4e..73449eac2e69 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_LayeredBoneBlend.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_LayeredBoneBlend.h @@ -10,7 +10,7 @@ #include "AnimNode_LayeredBoneBlend.generated.h" // Layered blend (per bone); has dynamic number of blendposes that can blend per different bone sets -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_LayeredBoneBlend : public FAnimNode_Base { GENERATED_USTRUCT_BODY() @@ -23,7 +23,7 @@ public: UPROPERTY(EditAnywhere, BlueprintReadWrite, editfixedsize, Category=Links) TArray BlendPoses; - UPROPERTY(EditAnywhere, BlueprintReadWrite, editfixedsize, Category=Config) + UPROPERTY(EditAnywhere, editfixedsize, Category=Config) TArray LayerSetup; UPROPERTY(EditAnywhere, BlueprintReadWrite, editfixedsize, Category=Runtime, meta=(PinShownByDefault)) diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_ModifyCurve.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_ModifyCurve.h index 0c22a204a12f..4fe86b1786b5 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_ModifyCurve.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_ModifyCurve.h @@ -21,7 +21,7 @@ enum class EModifyCurveApplyMode : uint8 }; /** Easy way to modify curve values on a pose */ -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_ModifyCurve : public FAnimNode_Base { GENERATED_BODY() diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_MultiWayBlend.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_MultiWayBlend.h index 903214ac76ac..eed585b2f70d 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_MultiWayBlend.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_MultiWayBlend.h @@ -7,7 +7,7 @@ #include "AnimNode_MultiWayBlend.generated.h" // This represents a baked transition -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_MultiWayBlend : public FAnimNode_Base { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_PoseBlendNode.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_PoseBlendNode.h index 62853b9a6277..31b03f68e773 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_PoseBlendNode.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_PoseBlendNode.h @@ -11,7 +11,7 @@ // Evaluates a point in an anim sequence, using a specific time input rather than advancing time internally. // Typically the playback position of the animation for this node will represent something other than time, like jump height. // This node will not trigger any notifies present in the associated sequence. -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_PoseBlendNode : public FAnimNode_PoseHandler { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_PoseByName.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_PoseByName.h index dc078cd54080..e84df93af40a 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_PoseByName.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_PoseByName.h @@ -10,7 +10,7 @@ // Evaluates a point in an anim sequence, using a specific time input rather than advancing time internally. // Typically the playback position of the animation for this node will represent something other than time, like jump height. // This node will not trigger any notifies present in the associated sequence. -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_PoseByName : public FAnimNode_PoseHandler { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_PoseDriver.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_PoseDriver.h index 76fdbe71898f..22be0ff68e02 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_PoseDriver.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_PoseDriver.h @@ -107,7 +107,7 @@ struct ANIMGRAPHRUNTIME_API FPoseDriverTarget }; /** RBF based orientation driver */ -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_PoseDriver : public FAnimNode_PoseHandler { GENERATED_BODY() diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_PoseHandler.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_PoseHandler.h index 36def42dd84e..5767ae007137 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_PoseHandler.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_PoseHandler.h @@ -12,7 +12,7 @@ // Evaluates a point in an anim sequence, using a specific time input rather than advancing time internally. // Typically the playback position of the animation for this node will represent something other than time, like jump height. // This node will not trigger any notifies present in the associated sequence. -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_PoseHandler : public FAnimNode_AssetPlayerBase { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_PoseSnapshot.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_PoseSnapshot.h index e3e8eefe088e..c316a99bcdb0 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_PoseSnapshot.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_PoseSnapshot.h @@ -28,7 +28,7 @@ enum class ESnapshotSourceMode : uint8 }; /** Provide a snapshot pose, either from the internal named pose cache or via a supplied snapshot */ -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_PoseSnapshot : public FAnimNode_Base { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_RandomPlayer.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_RandomPlayer.h index f02b2f258a81..b24b1d39f7ff 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_RandomPlayer.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_RandomPlayer.h @@ -50,7 +50,7 @@ struct FRandomAnimPlayData /** The random player node holds a list of sequences and parameter ranges which will be played continuously * In a random order. If shuffle mode is enabled then each entry will be played once before repeating any */ -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct FRandomPlayerSequenceEntry { GENERATED_BODY() @@ -91,11 +91,11 @@ struct FRandomPlayerSequenceEntry float MaxPlayRate; /** Blending properties used when this entry is blending in ontop of another entry */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Settings") + UPROPERTY(EditAnywhere, Category = "Settings") FAlphaBlend BlendIn; }; -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_RandomPlayer : public FAnimNode_Base { GENERATED_BODY() diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_Root.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_Root.h index 9d628b79abfc..a4adfeaa288e 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_Root.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_Root.h @@ -8,7 +8,7 @@ #include "AnimNode_Root.generated.h" // Root node of an animation tree (sink) -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_Root : public FAnimNode_Base { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_RotateRootBone.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_RotateRootBone.h index c1aad9322b74..ceb3a5372f4f 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_RotateRootBone.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_RotateRootBone.h @@ -8,7 +8,7 @@ #include "AnimNode_RotateRootBone.generated.h" //@TODO: Comment -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_RotateRootBone : public FAnimNode_Base { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_RotationOffsetBlendSpace.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_RotationOffsetBlendSpace.h index 88a5fe4bc9b8..d6e934af99ea 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_RotationOffsetBlendSpace.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_RotationOffsetBlendSpace.h @@ -6,10 +6,11 @@ #include "UObject/ObjectMacros.h" #include "Animation/AnimNodeBase.h" #include "AnimNodes/AnimNode_BlendSpacePlayer.h" +#include "Animation/InputScaleBias.h" #include "AnimNode_RotationOffsetBlendSpace.generated.h" //@TODO: Comment -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_RotationOffsetBlendSpace : public FAnimNode_BlendSpacePlayer { GENERATED_USTRUCT_BODY() @@ -29,6 +30,16 @@ struct ANIMGRAPHRUNTIME_API FAnimNode_RotationOffsetBlendSpace : public FAnimNod UPROPERTY(Transient) bool bIsLODEnabled; + // Current strength of the AimOffset + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Settings, meta = (PinShownByDefault)) + mutable float Alpha; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Settings) + FInputScaleBias AlphaScaleBias; + + UPROPERTY(Transient) + float ActualAlpha; + public: FAnimNode_RotationOffsetBlendSpace(); diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_SequenceEvaluator.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_SequenceEvaluator.h index a9955b0fe3c3..cc51e8901bdd 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_SequenceEvaluator.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_SequenceEvaluator.h @@ -24,7 +24,7 @@ namespace ESequenceEvalReinit // Evaluates a point in an anim sequence, using a specific time input rather than advancing time internally. // Typically the playback position of the animation for this node will represent something other than time, like jump height. // This node will not trigger any notifies present in the associated sequence. -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_SequenceEvaluator : public FAnimNode_AssetPlayerBase { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_Slot.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_Slot.h index 8c7e00873af8..4641230ee5fc 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_Slot.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_Slot.h @@ -11,7 +11,7 @@ // An animation slot node normally acts as a passthru, but a montage or PlaySlotAnimation call from // game code can cause an animation to blend in and be played on the slot temporarily, overriding the // Source input. -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_Slot : public FAnimNode_Base { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_TwoWayBlend.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_TwoWayBlend.h index 695bf519209d..1f84a924332c 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_TwoWayBlend.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimNodes/AnimNode_TwoWayBlend.h @@ -9,7 +9,7 @@ #include "AnimNode_TwoWayBlend.generated.h" // This represents a baked transition -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_TwoWayBlend : public FAnimNode_Base { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimSequencerInstance.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimSequencerInstance.h index 473516c76d01..68991e746a27 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimSequencerInstance.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/AnimSequencerInstance.h @@ -8,62 +8,13 @@ #pragma once #include "Animation/AnimInstance.h" -#include "Components/SkeletalMeshComponent.h" +#include "AnimCustomInstance.h" #include "AnimSequencerInstance.generated.h" UCLASS(transient, NotBlueprintable) -class ANIMGRAPHRUNTIME_API UAnimSequencerInstance : public UAnimInstance +class ANIMGRAPHRUNTIME_API UAnimSequencerInstance : public UAnimCustomInstance { GENERATED_UCLASS_BODY() - - /** - * Called to bind a typed UAnimSequencerInstance to an existing skeletal mesh component - * @return the current (or newly created) UAnimSequencerInstance - */ - template - static InstanceClassType* BindToSkeletalMeshComponent(USkeletalMeshComponent* InSkeletalMeshComponent) - { - // make sure to tick and refresh all the time when ticks - // @TODO: this needs restoring post-binding - InSkeletalMeshComponent->MeshComponentUpdateFlag = EMeshComponentUpdateFlag::AlwaysTickPoseAndRefreshBones; -#if WITH_EDITOR - InSkeletalMeshComponent->SetUpdateAnimationInEditor(true); -#endif - - // we use sequence instance if it's using anim blueprint that matches. Otherwise, we create sequence player - // this might need more check - i.e. making sure if it's same skeleton and so on, - // Ideally we could just call NeedToSpawnAnimScriptInstance call, which is protected now - const bool bShouldUseSequenceInstance = ShouldUseSequenceInstancePlayer(InSkeletalMeshComponent); - - // if it should use sequence instance - if (bShouldUseSequenceInstance) - { - // this has to wrap around with this because we don't want to reinitialize everytime they come here - // SetAnimationMode will reinitiaize it even if it's same, so make sure we just call SetAnimationMode if not AnimationCustomMode - if (InSkeletalMeshComponent->GetAnimationMode() != EAnimationMode::AnimationCustomMode) - { - InSkeletalMeshComponent->SetAnimationMode(EAnimationMode::AnimationCustomMode); - } - - if (Cast(InSkeletalMeshComponent->AnimScriptInstance) == nullptr || !InSkeletalMeshComponent->AnimScriptInstance->GetClass()->IsChildOf(InstanceClassType::StaticClass())) - { - InstanceClassType* SequencerInstance = NewObject(InSkeletalMeshComponent, InstanceClassType::StaticClass()); - InSkeletalMeshComponent->AnimScriptInstance = SequencerInstance; - InSkeletalMeshComponent->AnimScriptInstance->InitializeAnimation(); - return SequencerInstance; - } - else - { - return Cast(InSkeletalMeshComponent->AnimScriptInstance); - } - } - - return nullptr; - } - - /** Called to unbind a UAnimSequencerInstance to an existing skeletal mesh component */ - static void UnbindFromSkeletalMeshComponent(USkeletalMeshComponent* InSkeletalMeshComponent); - public: /** Update an animation sequence player in this instance */ void UpdateAnimTrack(UAnimSequenceBase* InAnimSequence, int32 SequenceId, float InPosition, float Weight, bool bFireNotifies); @@ -74,7 +25,4 @@ public: protected: // UAnimInstance interface virtual FAnimInstanceProxy* CreateAnimInstanceProxy() override; - - /** Helper function for BindToSkeletalMeshComponent */ - static bool ShouldUseSequenceInstancePlayer(const USkeletalMeshComponent* SkeletalMeshComponent); }; diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_AnimDynamics.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_AnimDynamics.h index f60d5ab729a2..35d0578b7781 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_AnimDynamics.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_AnimDynamics.h @@ -204,7 +204,7 @@ struct FAnimPhysSphericalLimit ESphericalLimitType LimitType; }; -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_AnimDynamics : public FAnimNode_SkeletalControlBase { GENERATED_BODY(); @@ -216,27 +216,27 @@ struct ANIMGRAPHRUNTIME_API FAnimNode_AnimDynamics : public FAnimNode_SkeletalCo AnimPhysSimSpaceType SimulationSpace; /** When in BoneRelative sim space, the simulation will use this bone as the origin */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setup) + UPROPERTY(EditAnywhere, Category = Setup) FBoneReference RelativeSpaceBone; /** Set to true to use the solver to simulate a connected chain */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setup) + UPROPERTY(EditAnywhere, Category = Setup) bool bChain; /** The bone to attach the physics body to, if bChain is true this is the top of the chain */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setup) + UPROPERTY(EditAnywhere, Category = Setup) FBoneReference BoundBone; /** If bChain is true this is the bottom of the chain, otherwise ignored */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setup, meta=(EditCondition = bChain)) + UPROPERTY(EditAnywhere, Category = Setup, meta=(EditCondition = bChain)) FBoneReference ChainEnd; /** Extents of the box to use for simulation */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setup) + UPROPERTY(EditAnywhere, Category = Setup) FVector BoxExtents; /** Vector relative to the body being simulated to attach the constraint to */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setup) + UPROPERTY(EditAnywhere, Category = Setup) FVector LocalJointOffset; /** Scale for gravity, higher values increase forces due to gravity */ @@ -244,11 +244,11 @@ struct ANIMGRAPHRUNTIME_API FAnimNode_AnimDynamics : public FAnimNode_SkeletalCo float GravityScale; /** If true the body will attempt to spring back to its initial position */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setup) + UPROPERTY(EditAnywhere, Category = Setup) bool bLinearSpring; /** If true the body will attempt to align itself with the specified angular target */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Setup) + UPROPERTY(EditAnywhere, Category = Setup) bool bAngularSpring; /** Spring constant to use when calculating linear springs, higher values mean a stronger spring.*/ @@ -260,18 +260,18 @@ struct ANIMGRAPHRUNTIME_API FAnimNode_AnimDynamics : public FAnimNode_SkeletalCo float AngularSpringConstant; /** Whether or not wind is enabled for the bodies in this simulation */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Wind) + UPROPERTY(EditAnywhere, Category = Wind) bool bEnableWind; UPROPERTY(Transient) bool bWindWasEnabled; /** Scale to apply to calculated wind velocities in the solver */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Wind) + UPROPERTY(EditAnywhere, Category = Wind) float WindScale; /** If true, the override value will be used for linear damping */ - UPROPERTY(EditAnywhere, AdvancedDisplay, BlueprintReadWrite, Category = Setup) + UPROPERTY(EditAnywhere, AdvancedDisplay, Category = Setup) bool bOverrideLinearDamping; /** Overridden linear damping value */ @@ -279,7 +279,7 @@ struct ANIMGRAPHRUNTIME_API FAnimNode_AnimDynamics : public FAnimNode_SkeletalCo float LinearDampingOverride; /** If true, the override value will be used for angular damping */ - UPROPERTY(EditAnywhere, AdvancedDisplay, BlueprintReadWrite, Category = Setup) + UPROPERTY(EditAnywhere, AdvancedDisplay, Category = Setup) bool bOverrideAngularDamping; /** Overridden angular damping value */ @@ -291,7 +291,7 @@ struct ANIMGRAPHRUNTIME_API FAnimNode_AnimDynamics : public FAnimNode_SkeletalCo * in check. When using single-body systems sometimes angular forces will look like they are "catching-up" with * the mesh, if that's the case override this and push it towards 1.0f until it settles correctly */ - UPROPERTY(EditAnywhere, AdvancedDisplay, BlueprintReadWrite, Category = Setup) + UPROPERTY(EditAnywhere, AdvancedDisplay, Category = Setup) bool bOverrideAngularBias; /** Overridden angular bias value @@ -303,11 +303,11 @@ struct ANIMGRAPHRUNTIME_API FAnimNode_AnimDynamics : public FAnimNode_SkeletalCo float AngularBiasOverride; /** If true we will perform physics update, otherwise skip - allows visualisation of the initial state of the bodies */ - UPROPERTY(EditAnywhere, AdvancedDisplay, BlueprintReadWrite, Category = Setup) + UPROPERTY(EditAnywhere, AdvancedDisplay, Category = Setup) bool bDoUpdate; /** If true we will perform bone transform evaluation, otherwise skip - allows visualisation of the initial anim state compared to the physics sim */ - UPROPERTY(EditAnywhere, AdvancedDisplay, BlueprintReadWrite, Category = Setup) + UPROPERTY(EditAnywhere, AdvancedDisplay, Category = Setup) bool bDoEval; /** Number of update passes on the linear and angular limits before we solve the position of the bodies recommended to be four times the value of NumSolverIterationsPostUpdate */ @@ -319,23 +319,23 @@ struct ANIMGRAPHRUNTIME_API FAnimNode_AnimDynamics : public FAnimNode_SkeletalCo int32 NumSolverIterationsPostUpdate; /** Data describing the constraints we will apply to the body */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Constraint) + UPROPERTY(EditAnywhere, Category = Constraint) FAnimPhysConstraintSetup ConstraintSetup; /** Whether to evaluate planar limits */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=PlanarLimit) + UPROPERTY(EditAnywhere, Category=PlanarLimit) bool bUsePlanarLimit; /** List of available planar limits for this node */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=PlanarLimit) + UPROPERTY(EditAnywhere, Category=PlanarLimit) TArray PlanarLimits; /** Whether to evaluate spherical limits */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = SphericalLimit) + UPROPERTY(EditAnywhere, Category = SphericalLimit) bool bUseSphericalLimits; /** List of available spherical limits for this node */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = SphericalLimit) + UPROPERTY(EditAnywhere, Category = SphericalLimit) TArray SphericalLimits; /** Resolution method for planar limits */ diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_CopyBone.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_CopyBone.h index 9969a7fe9365..04ca6bbc1dc4 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_CopyBone.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_CopyBone.h @@ -15,17 +15,17 @@ class USkeletalMeshComponent; * Simple controller to copy a bone's transform to another one. */ -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_CopyBone : public FAnimNode_SkeletalControlBase { GENERATED_USTRUCT_BODY() /** Source Bone Name to get transform from */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Copy) + UPROPERTY(EditAnywhere, Category = Copy) FBoneReference SourceBone; /** Name of bone to control. This is the main bone chain to modify from. **/ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Copy) + UPROPERTY(EditAnywhere, Category=Copy) FBoneReference TargetBone; /** If Translation should be copied */ @@ -41,7 +41,7 @@ struct ANIMGRAPHRUNTIME_API FAnimNode_CopyBone : public FAnimNode_SkeletalContro bool bCopyScale; /** Space to convert transforms into prior to copying components */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Copy) + UPROPERTY(EditAnywhere, Category = Copy) TEnumAsByte ControlSpace; FAnimNode_CopyBone(); diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_CopyBoneDelta.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_CopyBoneDelta.h index bb5b98c799ce..1c23653cd7b1 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_CopyBoneDelta.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_CopyBoneDelta.h @@ -23,15 +23,15 @@ enum class CopyBoneDeltaMode : uint8 * instead of the copy bone node which copies the absolute transform */ -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_CopyBoneDelta : public FAnimNode_SkeletalControlBase { GENERATED_USTRUCT_BODY() - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Settings) + UPROPERTY(EditAnywhere, Category = Settings) FBoneReference SourceBone; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Settings) + UPROPERTY(EditAnywhere, Category = Settings) FBoneReference TargetBone; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Settings, meta = (PinShownByDefault)) @@ -43,7 +43,7 @@ struct ANIMGRAPHRUNTIME_API FAnimNode_CopyBoneDelta : public FAnimNode_SkeletalC UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Settings, meta = (PinShownByDefault)) bool bCopyScale; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Settings) + UPROPERTY(EditAnywhere, Category = Settings) CopyBoneDeltaMode CopyMode; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Settings, meta = (PinHiddenByDefault)) diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_Fabrik.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_Fabrik.h index 749a5141fc42..d29a0e9bdc1e 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_Fabrik.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_Fabrik.h @@ -54,7 +54,7 @@ public: } }; -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_Fabrik : public FAnimNode_SkeletalControlBase { GENERATED_USTRUCT_BODY() @@ -64,34 +64,34 @@ struct ANIMGRAPHRUNTIME_API FAnimNode_Fabrik : public FAnimNode_SkeletalControlB FTransform EffectorTransform; /** Reference frame of Effector Transform. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = EndEffector) + UPROPERTY(EditAnywhere, Category = EndEffector) TEnumAsByte EffectorTransformSpace; /** If EffectorTransformSpace is a bone, this is the bone to use. **/ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = EndEffector) + UPROPERTY(EditAnywhere, Category = EndEffector) FBoneReference EffectorTransformBone; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = EndEffector) + UPROPERTY(EditAnywhere, Category = EndEffector) TEnumAsByte EffectorRotationSource; /** Name of tip bone */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Solver) + UPROPERTY(EditAnywhere, Category = Solver) FBoneReference TipBone; /** Name of the root bone*/ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Solver) + UPROPERTY(EditAnywhere, Category = Solver) FBoneReference RootBone; /** Tolerance for final tip location delta from EffectorLocation*/ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Solver) + UPROPERTY(EditAnywhere, Category = Solver) float Precision; /** Maximum number of iterations allowed, to control performance. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Solver) + UPROPERTY(EditAnywhere, Category = Solver) int32 MaxIterations; /** Toggle drawing of axes to debug joint rotation*/ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Solver) + UPROPERTY(EditAnywhere, Category = Solver) bool bEnableDebugDraw; public: diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_HandIKRetargeting.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_HandIKRetargeting.h index 309f29479071..7926e7189a1d 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_HandIKRetargeting.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_HandIKRetargeting.h @@ -18,29 +18,29 @@ class USkeletalMeshComponent; * This is used so characters of different proportions can handle the same props. */ -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_HandIKRetargeting : public FAnimNode_SkeletalControlBase { GENERATED_USTRUCT_BODY() /** Bone for Right Hand FK */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HandIKRetargeting") + UPROPERTY(EditAnywhere, Category = "HandIKRetargeting") FBoneReference RightHandFK; /** Bone for Left Hand FK */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HandIKRetargeting") + UPROPERTY(EditAnywhere, Category = "HandIKRetargeting") FBoneReference LeftHandFK; /** Bone for Right Hand IK */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HandIKRetargeting") + UPROPERTY(EditAnywhere, Category = "HandIKRetargeting") FBoneReference RightHandIK; /** Bone for Left Hand IK */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HandIKRetargeting") + UPROPERTY(EditAnywhere, Category = "HandIKRetargeting") FBoneReference LeftHandIK; /** IK Bones to move. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HandIKRetargeting") + UPROPERTY(EditAnywhere, Category = "HandIKRetargeting") TArray IKBonesToMove; /** Which hand to favor. 0.5 is equal weight for both, 1 = right hand, 0 = left hand. */ diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_LookAt.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_LookAt.h index 98480b66dbf7..89d12052be2a 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_LookAt.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_LookAt.h @@ -33,21 +33,21 @@ namespace EInterpolationBlend /** * Simple controller that make a bone to look at the point or another bone */ -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_LookAt : public FAnimNode_SkeletalControlBase { GENERATED_USTRUCT_BODY() /** Name of bone to control. This is the main bone chain to modify from. **/ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=SkeletalControl) + UPROPERTY(EditAnywhere, Category=SkeletalControl) FBoneReference BoneToModify; /** Target Bone to look at - You can use LookAtLocation if you need offset from this point. That location will be used in their local space. **/ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Target) + UPROPERTY(EditAnywhere, Category=Target) FBoneReference LookAtBone; /** Target socket to look at. Used if LookAtBone is empty. - You can use LookAtLocation if you need offset from this point. That location will be used in their local space. **/ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Target) + UPROPERTY(EditAnywhere, Category = Target) FName LookAtSocket; /** Target Offset. It's in world space if LookAtBone is empty or it is based on LookAtBone or LookAtSocket in their local space*/ @@ -62,11 +62,11 @@ struct ANIMGRAPHRUNTIME_API FAnimNode_LookAt : public FAnimNode_SkeletalControlB UPROPERTY() FVector CustomLookAtAxis_DEPRECATED; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = SkeletalControl) + UPROPERTY(EditAnywhere, Category = SkeletalControl) FAxis LookAt_Axis; /** Whether or not to use Look up axis */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=SkeletalControl) + UPROPERTY(EditAnywhere, Category=SkeletalControl) bool bUseLookUpAxis; /** Look up axis in local space */ @@ -77,7 +77,7 @@ struct ANIMGRAPHRUNTIME_API FAnimNode_LookAt : public FAnimNode_SkeletalControlB UPROPERTY() FVector CustomLookUpAxis_DEPRECATED; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = SkeletalControl) + UPROPERTY(EditAnywhere, Category = SkeletalControl) FAxis LookUp_Axis; /** Look at Clamp value in degree - if you're look at axis is Z, only X, Y degree of clamp will be used*/ diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_ModifyBone.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_ModifyBone.h index c69ed971a309..8b5e73eebc00 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_ModifyBone.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_ModifyBone.h @@ -27,13 +27,13 @@ enum EBoneModificationMode /** * Simple controller that replaces or adds to the translation/rotation of a single bone. */ -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_ModifyBone : public FAnimNode_SkeletalControlBase { GENERATED_USTRUCT_BODY() /** Name of bone to control. This is the main bone chain to modify from. **/ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=SkeletalControl) + UPROPERTY(EditAnywhere, Category=SkeletalControl) FBoneReference BoneToModify; /** New translation of bone to apply. */ @@ -49,27 +49,27 @@ struct ANIMGRAPHRUNTIME_API FAnimNode_ModifyBone : public FAnimNode_SkeletalCont FVector Scale; /** Whether and how to modify the translation of this bone. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Translation) + UPROPERTY(EditAnywhere, Category=Translation) TEnumAsByte TranslationMode; /** Whether and how to modify the translation of this bone. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Rotation) + UPROPERTY(EditAnywhere, Category=Rotation) TEnumAsByte RotationMode; /** Whether and how to modify the translation of this bone. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Scale) + UPROPERTY(EditAnywhere, Category=Scale) TEnumAsByte ScaleMode; /** Reference frame to apply Translation in. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Translation) + UPROPERTY(EditAnywhere, Category=Translation) TEnumAsByte TranslationSpace; /** Reference frame to apply Rotation in. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Rotation) + UPROPERTY(EditAnywhere, Category=Rotation) TEnumAsByte RotationSpace; /** Reference frame to apply Scale in. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Scale) + UPROPERTY(EditAnywhere, Category=Scale) TEnumAsByte ScaleSpace; FAnimNode_ModifyBone(); diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_RotationMultiplier.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_RotationMultiplier.h index 2b01f5d528c7..d64c75822cf1 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_RotationMultiplier.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_RotationMultiplier.h @@ -15,17 +15,17 @@ class USkeletalMeshComponent; * Simple controller that multiplies scalar value to the translation/rotation/scale of a single bone. */ -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_RotationMultiplier : public FAnimNode_SkeletalControlBase { GENERATED_USTRUCT_BODY() /** Name of bone to control. This is the main bone chain to modify from. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Multiplier) + UPROPERTY(EditAnywhere, Category=Multiplier) FBoneReference TargetBone; /** Source to get transform from */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Multiplier) + UPROPERTY(EditAnywhere, Category=Multiplier) FBoneReference SourceBone; // To make these to be easily pin-hookable, I'm not making it struct, but each variable @@ -33,10 +33,10 @@ struct ANIMGRAPHRUNTIME_API FAnimNode_RotationMultiplier : public FAnimNode_Skel UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Multiplier, meta=(PinShownByDefault)) float Multiplier; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Multiplier) + UPROPERTY(EditAnywhere, Category=Multiplier) TEnumAsByte RotationAxisToRefer; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Multiplier) + UPROPERTY(EditAnywhere, Category = Multiplier) bool bIsAdditive; FAnimNode_RotationMultiplier(); diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_ScaleChainLength.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_ScaleChainLength.h index f51520eadf42..91ce5434f4df 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_ScaleChainLength.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_ScaleChainLength.h @@ -12,34 +12,51 @@ class USkeletalMeshComponent; +UENUM(BlueprintType) +enum class EScaleChainInitialLength : uint8 +{ + /** Use the 'DefaultChainLength' input value. */ + FixedDefaultLengthValue, + /** Use distance between 'ChainStartBone' and 'ChainEndBone' (in Component Space) */ + Distance, + /* Use animated chain length (length in local space of every bone from 'ChainStartBone' to 'ChainEndBone' */ + ChainLength, +}; + /** - * + * Scale the length of a chain of bones. */ -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_ScaleChainLength : public FAnimNode_Base { GENERATED_USTRUCT_BODY() - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Links) + UPROPERTY(EditAnywhere, Category = Links) FPoseLink InputPose; /** Default chain length, as animated. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = ScaleChainLength, meta = (PinHiddenByDefault)) float DefaultChainLength; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = ScaleChainLength) + UPROPERTY(EditAnywhere, Category = ScaleChainLength) FBoneReference ChainStartBone; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = ScaleChainLength) + UPROPERTY(EditAnywhere, Category = ScaleChainLength) FBoneReference ChainEndBone; + UPROPERTY(EditAnywhere, Category = ScaleChainLength) + EScaleChainInitialLength ChainInitialLength; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = ScaleChainLength, meta = (PinShownByDefault)) FVector TargetLocation; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Settings, meta = (PinShownByDefault)) mutable float Alpha; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Settings) + UPROPERTY(Transient) + float ActualAlpha; + + UPROPERTY(EditAnywhere, Category = Settings) FInputScaleBias AlphaScaleBias; UPROPERTY(Transient) @@ -57,4 +74,7 @@ public: virtual void Evaluate(FPoseContext& Output) override; virtual void GatherDebugData(FNodeDebugData& DebugData) override; // End of FAnimNode_Base interface + +protected: + float GetInitialChainLength(FCompactPose& InLSPose, FCSPose& InCSPose) const; }; diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_SkeletalControlBase.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_SkeletalControlBase.h index d67c4963c1e2..52357bcda285 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_SkeletalControlBase.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_SkeletalControlBase.h @@ -16,7 +16,7 @@ class USkeletalMeshComponent; -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_SkeletalControlBase : public FAnimNode_Base { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_SplineIK.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_SplineIK.h index f964809598c4..5ae1c67c7eb8 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_SplineIK.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_SplineIK.h @@ -44,29 +44,29 @@ struct FSplineIKCachedBoneData int32 RefSkeletonIndex; }; -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_SplineIK : public FAnimNode_SkeletalControlBase { GENERATED_BODY() /** Name of root bone from which the spline extends **/ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Parameters") + UPROPERTY(EditAnywhere, Category = "Parameters") FBoneReference StartBone; /** Name of bone at the end of the spline chain. Bones after this will not be altered by the controller. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Parameters") + UPROPERTY(EditAnywhere, Category = "Parameters") FBoneReference EndBone; /** Axis of the controlled bone (ie the direction of the spline) to use as the direction for the curve. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Parameters") + UPROPERTY(EditAnywhere, Category = "Parameters") ESplineBoneAxis BoneAxis; /** The number of points in the spline if we are specifying it directly */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Parameters") + UPROPERTY(EditAnywhere, Category = "Parameters") bool bAutoCalculateSpline; /** The number of points in the spline if we are not auto-calculating */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Parameters", meta = (ClampMin = 2, UIMin = 2, EditCondition = "!bAutoCalculateSpline")) + UPROPERTY(EditAnywhere, Category = "Parameters", meta = (ClampMin = 2, UIMin = 2, EditCondition = "!bAutoCalculateSpline")) int32 PointCount; /** Transforms applied to spline points **/ @@ -86,7 +86,7 @@ struct ANIMGRAPHRUNTIME_API FAnimNode_SplineIK : public FAnimNode_SkeletalContro float TwistEnd; /** How to interpolate twist along the length of the spline */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Parameters") + UPROPERTY(EditAnywhere, Category = "Parameters") FAlphaBlend TwistBlend; /** diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_SpringBone.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_SpringBone.h index 6c2a68a9368f..6cce9ccb0cd1 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_SpringBone.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_SpringBone.h @@ -16,17 +16,17 @@ class USkeletalMeshComponent; * Simple controller that replaces or adds to the translation/rotation of a single bone. */ -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_SpringBone : public FAnimNode_SkeletalControlBase { GENERATED_USTRUCT_BODY() /** Name of bone to control. This is the main bone chain to modify from. **/ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Spring) + UPROPERTY(EditAnywhere, Category=Spring) FBoneReference SpringBone; /** Limit the amount that a bone can stretch from its ref-pose length. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Spring) + UPROPERTY(EditAnywhere, Category=Spring) bool bLimitDisplacement; /** If bLimitDisplacement is true, this indicates how long a bone can stretch beyond its length in the ref-pose. */ @@ -34,15 +34,15 @@ struct ANIMGRAPHRUNTIME_API FAnimNode_SpringBone : public FAnimNode_SkeletalCont float MaxDisplacement; /** Stiffness of spring */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Spring) + UPROPERTY(EditAnywhere, Category=Spring) float SpringStiffness; /** Damping of spring */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Spring) + UPROPERTY(EditAnywhere, Category=Spring) float SpringDamping; /** If spring stretches more than this, reset it. Useful for catching teleports etc */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Spring) + UPROPERTY(EditAnywhere, Category=Spring) float ErrorResetThresh; /** If true, Z position is always correct, no spring applied */ @@ -50,27 +50,27 @@ struct ANIMGRAPHRUNTIME_API FAnimNode_SpringBone : public FAnimNode_SkeletalCont bool bNoZSpring_DEPRECATED; /** If true take the spring calculation for translation in X */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=FilterChannels) + UPROPERTY(EditAnywhere, Category=FilterChannels) bool bTranslateX; /** If true take the spring calculation for translation in Y */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=FilterChannels) + UPROPERTY(EditAnywhere, Category=FilterChannels) bool bTranslateY; /** If true take the spring calculation for translation in Z */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=FilterChannels) + UPROPERTY(EditAnywhere, Category=FilterChannels) bool bTranslateZ; /** If true take the spring calculation for rotation in X */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=FilterChannels) + UPROPERTY(EditAnywhere, Category=FilterChannels) bool bRotateX; /** If true take the spring calculation for rotation in Y */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=FilterChannels) + UPROPERTY(EditAnywhere, Category=FilterChannels) bool bRotateY; /** If true take the spring calculation for rotation in Z */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=FilterChannels) + UPROPERTY(EditAnywhere, Category=FilterChannels) bool bRotateZ; /** Internal use - Amount of time we need to simulate. */ diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_Trail.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_Trail.h index b67aee882617..ba0658154645 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_Trail.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_Trail.h @@ -24,25 +24,25 @@ struct FPerJointTrailSetup * Trail Controller */ -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_Trail : public FAnimNode_SkeletalControlBase { GENERATED_USTRUCT_BODY() /** Reference to the active bone in the hierarchy to modify. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Trail) + UPROPERTY(EditAnywhere, Category=Trail) FBoneReference TrailBone; /** Number of bones above the active one in the hierarchy to modify. ChainLength should be at least 2. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Trail, meta = (ClampMin = "2", UIMin = "2")) + UPROPERTY(EditAnywhere, Category = Trail, meta = (ClampMin = "2", UIMin = "2")) int32 ChainLength; /** Axis of the bones to point along trail. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Trail) + UPROPERTY(EditAnywhere, Category=Trail) TEnumAsByte ChainBoneAxis; /** Invert the direction specified in ChainBoneAxis. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Trail) + UPROPERTY(EditAnywhere, Category=Trail) bool bInvertChainBoneAxis; /** How quickly we 'relax' the bones to their animated positions. Deprecated. Replaced to TrailRelaxationCurve */ @@ -50,27 +50,27 @@ struct ANIMGRAPHRUNTIME_API FAnimNode_Trail : public FAnimNode_SkeletalControlBa float TrailRelaxation_DEPRECATED; /** How quickly we 'relax' the bones to their animated positions. Time 0 will map to top root joint, time 1 will map to the bottom joint. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Trail, meta=(CustomizeProperty)) + UPROPERTY(EditAnywhere, Category=Trail, meta=(CustomizeProperty)) FRuntimeFloatCurve TrailRelaxationSpeed; /** Limit the amount that a bone can stretch from its ref-pose length. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Limit) + UPROPERTY(EditAnywhere, Category=Limit) bool bLimitStretch; /** If bLimitStretch is true, this indicates how long a bone can stretch beyond its length in the ref-pose. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Limit) + UPROPERTY(EditAnywhere, Category=Limit) float StretchLimit; /** 'Fake' velocity applied to bones. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Velocity) + UPROPERTY(EditAnywhere, Category=Velocity) FVector FakeVelocity; /** Whether 'fake' velocity should be applied in actor or world space. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Velocity) + UPROPERTY(EditAnywhere, Category=Velocity) bool bActorSpaceFakeVel; /** Base Joint to calculate velocity from. If none, it will use Component's World Transform. . */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Velocity) + UPROPERTY(EditAnywhere, Category=Velocity) FBoneReference BaseJoint; /** Internal use - we need the timestep to do the relaxation in CalculateNewBoneTransforms. */ diff --git a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_TwoBoneIK.h b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_TwoBoneIK.h index e08a9bc14d33..51c0ff2b5e52 100644 --- a/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_TwoBoneIK.h +++ b/Engine/Source/Runtime/AnimGraphRuntime/Public/BoneControllers/AnimNode_TwoBoneIK.h @@ -15,13 +15,13 @@ class USkeletalMeshComponent; * Simple 2 Bone IK Controller. */ -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ANIMGRAPHRUNTIME_API FAnimNode_TwoBoneIK : public FAnimNode_SkeletalControlBase { GENERATED_USTRUCT_BODY() /** Name of bone to control. This is the main bone chain to modify from. **/ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=IK) + UPROPERTY(EditAnywhere, Category=IK) FBoneReference IKBone; /** Effector Location. Target Location to reach. */ @@ -33,19 +33,19 @@ struct ANIMGRAPHRUNTIME_API FAnimNode_TwoBoneIK : public FAnimNode_SkeletalContr FVector JointTargetLocation; /** If EffectorLocationSpace is a bone, this is the bone to use. **/ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=EndEffector) + UPROPERTY(EditAnywhere, Category=EndEffector) FName EffectorSpaceBoneName; /** Set end bone to use End Effector rotation */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=EndEffector) + UPROPERTY(EditAnywhere, Category=EndEffector) uint32 bTakeRotationFromEffectorSpace:1; /** Keep local rotation of end bone */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=EndEffector) + UPROPERTY(EditAnywhere, Category=EndEffector) uint32 bMaintainEffectorRelRot:1; /** Should stretching be allowed, to be prevent over extension */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=IK) + UPROPERTY(EditAnywhere, Category=IK) uint32 bAllowStretching:1; /** Limits to use if stretching is allowed - old property DEPRECATED */ @@ -53,23 +53,23 @@ struct ANIMGRAPHRUNTIME_API FAnimNode_TwoBoneIK : public FAnimNode_SkeletalContr FVector2D StretchLimits_DEPRECATED; /** Limits to use if stretching is allowed. This value determines when to start stretch. For example, 0.9 means once it reaches 90% of the whole length of the limb, it will start apply. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=IK, meta = (editcondition = "bAllowStretching", ClampMin = "0.0", UIMin = "0.0")) + UPROPERTY(EditAnywhere, Category=IK, meta = (editcondition = "bAllowStretching", ClampMin = "0.0", UIMin = "0.0")) float StartStretchRatio; /** Limits to use if stretching is allowed. This value determins what is the max stretch scale. For example, 1.5 means it will stretch until 150 % of the whole length of the limb.*/ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = IK, meta = (editcondition = "bAllowStretching", ClampMin = "0.0", UIMin = "0.0")) + UPROPERTY(EditAnywhere, Category = IK, meta = (editcondition = "bAllowStretching", ClampMin = "0.0", UIMin = "0.0")) float MaxStretchScale; /** Reference frame of Effector Location. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = IK) + UPROPERTY(EditAnywhere, Category = IK) TEnumAsByte EffectorLocationSpace; /** Reference frame of Joint Target Location. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=JointTarget) + UPROPERTY(EditAnywhere, Category=JointTarget) TEnumAsByte JointTargetLocationSpace; /** If JointTargetSpaceBoneName is a bone, this is the bone to use. **/ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=JointTarget) + UPROPERTY(EditAnywhere, Category=JointTarget) FName JointTargetSpaceBoneName; FAnimNode_TwoBoneIK(); diff --git a/Engine/Source/Runtime/AnimationCore/Private/SplineIK.cpp b/Engine/Source/Runtime/AnimationCore/Private/SplineIK.cpp index 289cd8bcd54e..763e21794917 100644 --- a/Engine/Source/Runtime/AnimationCore/Private/SplineIK.cpp +++ b/Engine/Source/Runtime/AnimationCore/Private/SplineIK.cpp @@ -1,73 +1,90 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "SplineIK.h" +#include "ThreadSingleton.h" namespace AnimationCore { - -void SolveSplineIK(const TArray& BoneTransforms, const FInterpCurveVector& PositionSpline, const FInterpCurveQuat& RotationSpline, const FInterpCurveVector& ScaleSpline, const float TotalSplineAlpha, const float TotalSplineLength, const FFloatMapping& Twist, const float Roll, const float Stretch, const float Offset, const EAxis::Type BoneAxis, const FFindParamAtFirstSphereIntersection& FindParamAtFirstSphereIntersection, const TArray& BoneOffsetRotations, const TArray& BoneLengths, const float OriginalSplineLength, TArray& OutBoneTransforms) -{ - check(BoneTransforms.Num() == BoneLengths.Num()); - check(BoneTransforms.Num() == BoneOffsetRotations.Num()); - check(Twist.IsBound()); - check(FindParamAtFirstSphereIntersection.IsBound()); - - OutBoneTransforms.Reset(); - - const float TotalStretchRatio = FMath::Lerp(OriginalSplineLength, TotalSplineLength, Stretch) / OriginalSplineLength; - - FVector PreviousPoint; - int32 StartingLinearIndex = 0; - float InitialAlpha = 0.0f; - if (Offset == 0.0f) + struct FSplineIKSolverScratchArea : public TThreadSingleton { - PreviousPoint = PositionSpline.Points[0].OutVal; - } - else + TArray SplineAlphas; + }; + + void SolveSplineIK(const TArray& BoneTransforms, const FInterpCurveVector& PositionSpline, const FInterpCurveQuat& RotationSpline, const FInterpCurveVector& ScaleSpline, const float TotalSplineAlpha, const float TotalSplineLength, const FFloatMapping& Twist, const float Roll, const float Stretch, const float Offset, const EAxis::Type BoneAxis, const FFindParamAtFirstSphereIntersection& FindParamAtFirstSphereIntersection, const TArray& BoneOffsetRotations, const TArray& BoneLengths, const float OriginalSplineLength, TArray& OutBoneTransforms) { - InitialAlpha = FindParamAtFirstSphereIntersection.Execute(PositionSpline.Points[0].OutVal, Offset, StartingLinearIndex); - PreviousPoint = PositionSpline.Eval(InitialAlpha); - } -// const float TotalSplineAlpha = ReparamTable.Points.Last().OutVal; - const int32 BoneCount = BoneTransforms.Num(); - for (int32 BoneIndex = 0; BoneIndex < BoneCount; BoneIndex++) - { - const float SplineAlpha = BoneIndex > 0 ? FindParamAtFirstSphereIntersection.Execute(PreviousPoint, BoneLengths[BoneIndex] * TotalStretchRatio, StartingLinearIndex) : InitialAlpha; + check(BoneTransforms.Num() == BoneLengths.Num()); + check(BoneTransforms.Num() == BoneOffsetRotations.Num()); + check(Twist.IsBound()); + check(FindParamAtFirstSphereIntersection.IsBound()); - FTransform BoneTransform; - BoneTransform.SetLocation(PositionSpline.Eval(SplineAlpha)); - BoneTransform.SetScale3D(ScaleSpline.Eval(SplineAlpha)); + OutBoneTransforms.Reset(); - // Get the rotation that the spline provides - FQuat SplineRotation = RotationSpline.Eval(SplineAlpha); + const float TotalStretchRatio = FMath::Lerp(OriginalSplineLength, TotalSplineLength, Stretch) / OriginalSplineLength; - // Build roll/twist rotation - const float TotalRoll = Roll + Twist.Execute(SplineAlpha / TotalSplineAlpha); - FQuat RollRotation = FRotator(BoneAxis == EAxis::Y ? TotalRoll : 0.0f, BoneAxis == EAxis::X ? TotalRoll : 0.0f, BoneAxis == EAxis::Z ? TotalRoll : 0.0f).Quaternion(); - - // Calculate rotation to correct our orientation onto the spline's - FQuat DirectionCorrectingRotation(FQuat::Identity); - if (BoneIndex > 0) + FVector PreviousPoint; + int32 StartingLinearIndex = 0; + float InitialAlpha = 0.0f; + if (Offset == 0.0f) { - FVector NewBoneDir = BoneTransform.GetLocation() - OutBoneTransforms[BoneIndex - 1].GetLocation(); - - // Only try and correct direction if we get a non-zero tangent. - if (NewBoneDir.Normalize()) - { - // Calculate the direction that bone is currently pointing. - const FVector CurrentBoneDir = BoneTransforms[BoneIndex].GetUnitAxis(BoneAxis).GetSafeNormal(); - - // Calculate a quaternion that gets us from our current rotation to the desired one. - DirectionCorrectingRotation = FQuat::FindBetweenNormals(CurrentBoneDir, NewBoneDir); - } + PreviousPoint = PositionSpline.Points[0].OutVal; + } + else + { + InitialAlpha = FindParamAtFirstSphereIntersection.Execute(PositionSpline.Points[0].OutVal, Offset, StartingLinearIndex); + PreviousPoint = PositionSpline.Eval(InitialAlpha); } - BoneTransform.SetRotation(RollRotation * DirectionCorrectingRotation * BoneOffsetRotations[BoneIndex] * SplineRotation); + const int32 BoneCount = BoneTransforms.Num(); - OutBoneTransforms.Add(BoneTransform); + TArray& SplineAlphas = FSplineIKSolverScratchArea::Get().SplineAlphas; + SplineAlphas.SetNum(BoneCount); + OutBoneTransforms.SetNum(BoneCount); - PreviousPoint = BoneTransform.GetLocation(); + // First calculate positions & scales + for (int32 BoneIndex = 0; BoneIndex < BoneCount; BoneIndex++) + { + SplineAlphas[BoneIndex] = BoneIndex > 0 ? FindParamAtFirstSphereIntersection.Execute(PreviousPoint, BoneLengths[BoneIndex] * TotalStretchRatio, StartingLinearIndex) : InitialAlpha; + + FTransform& BoneTransform = OutBoneTransforms[BoneIndex]; + BoneTransform.SetLocation(PositionSpline.Eval(SplineAlphas[BoneIndex])); + BoneTransform.SetScale3D(ScaleSpline.Eval(SplineAlphas[BoneIndex])); + + PreviousPoint = BoneTransform.GetLocation(); + } + + // Now calculate rotations + for (int32 BoneIndex = 0; BoneIndex < BoneCount; BoneIndex++) + { + FTransform& BoneTransform = OutBoneTransforms[BoneIndex]; + + // Get the rotation that the spline provides + FQuat SplineRotation = RotationSpline.Eval(SplineAlphas[BoneIndex]); + + // Build roll/twist rotation + const float TotalRoll = Roll + Twist.Execute(SplineAlphas[BoneIndex] / TotalSplineAlpha); + FQuat RollRotation = FRotator(BoneAxis == EAxis::Y ? TotalRoll : 0.0f, BoneAxis == EAxis::X ? TotalRoll : 0.0f, BoneAxis == EAxis::Z ? TotalRoll : 0.0f).Quaternion(); + + // Correct rotation of bone to align our orientation onto the spline + FQuat DirectionCorrectingRotation(FQuat::Identity); + FQuat BoneOffsetRotation(FQuat::Identity); + if (BoneIndex < BoneCount - 1) + { + FVector NewBoneDir = OutBoneTransforms[BoneIndex + 1].GetLocation() - BoneTransform.GetLocation(); + + // Only try and correct direction if we get a non-zero tangent. + if (NewBoneDir.Normalize()) + { + // Calculate the direction that bone is currently pointing. + const FVector CurrentBoneDir = BoneTransforms[BoneIndex + 1].GetUnitAxis(BoneAxis).GetSafeNormal(); + + // Calculate a quaternion that gets us from our current rotation to the desired one. + DirectionCorrectingRotation = FQuat::FindBetweenNormals(CurrentBoneDir, NewBoneDir); + } + + BoneOffsetRotation = BoneOffsetRotations[BoneIndex + 1]; + } + + BoneTransform.SetRotation(RollRotation * DirectionCorrectingRotation * BoneOffsetRotation * SplineRotation); + } } -} - } \ No newline at end of file diff --git a/Engine/Source/Runtime/AppFramework/Private/Widgets/Colors/SColorGradingPicker.cpp b/Engine/Source/Runtime/AppFramework/Private/Widgets/Colors/SColorGradingPicker.cpp index d91605ae7cf7..46237f93a9f3 100644 --- a/Engine/Source/Runtime/AppFramework/Private/Widgets/Colors/SColorGradingPicker.cpp +++ b/Engine/Source/Runtime/AppFramework/Private/Widgets/Colors/SColorGradingPicker.cpp @@ -74,7 +74,7 @@ void SColorGradingPicker::Construct( const FArguments& InArgs ) .EditableTextBoxStyle(&FCoreStyle::Get().GetWidgetStyle("DarkEditableTextBox")) .Value(this, &SColorGradingPicker::OnGetMainValue) .OnValueChanged(this, &SColorGradingPicker::OnMainValueChanged, false) - .AllowSpin(true) + .AllowSpin(InArgs._AllowSpin.Get()) .SupportDynamicSliderMaxValue(InArgs._SupportDynamicSliderMaxValue) .SupportDynamicSliderMinValue(InArgs._SupportDynamicSliderMinValue) .OnDynamicSliderMaxValueChanged(this, &SColorGradingPicker::OnDynamicSliderMaxValueChanged) @@ -87,25 +87,38 @@ void SColorGradingPicker::Construct( const FArguments& InArgs ) .ShiftMouseMovePixelPerDelta(MainShiftMouseMovePixelPerDelta) .OnBeginSliderMovement(this, &SColorGradingPicker::OnBeginSliderMovement) .OnEndSliderMovement(this, &SColorGradingPicker::OnEndSliderMovement) + .UndeterminedString(NSLOCTEXT("PropertyEditor", "MultipleValues", "Multiple Values")) + .IsEnabled(this, &SColorGradingPicker::IsEntryBoxEnabled) ] ]; } +bool SColorGradingPicker::IsEntryBoxEnabled() const +{ + return OnGetMainValue() != TOptional(); +} + void SColorGradingPicker::OnBeginSliderMovement() { bIsMouseDragging = true; //Keep the current value so we can always keep the ratio during the whole drag. - OnQueryCurrentColor.ExecuteIfBound(StartDragRatio); - TransformColorGradingRangeToLinearColorRange(StartDragRatio); - float MaxCurrentValue = FMath::Max3(StartDragRatio.X, StartDragRatio.Y, StartDragRatio.Z); - FVector4 RatioValue(1.0f, 1.0f, 1.0f, 1.0f); - if (MaxCurrentValue > SMALL_NUMBER) + + if (OnQueryCurrentColor.IsBound()) { - RatioValue.X = StartDragRatio.X / MaxCurrentValue; - RatioValue.Y = StartDragRatio.Y / MaxCurrentValue; - RatioValue.Z = StartDragRatio.Z / MaxCurrentValue; + if (OnQueryCurrentColor.Execute(StartDragRatio)) + { + TransformColorGradingRangeToLinearColorRange(StartDragRatio); + float MaxCurrentValue = FMath::Max3(StartDragRatio.X, StartDragRatio.Y, StartDragRatio.Z); + FVector4 RatioValue(1.0f, 1.0f, 1.0f, 1.0f); + if (MaxCurrentValue > SMALL_NUMBER) + { + RatioValue.X = StartDragRatio.X / MaxCurrentValue; + RatioValue.Y = StartDragRatio.Y / MaxCurrentValue; + RatioValue.Z = StartDragRatio.Z / MaxCurrentValue; + } + StartDragRatio = RatioValue; + } } - StartDragRatio = RatioValue; } void SColorGradingPicker::OnEndSliderMovement(float NewValue) @@ -143,34 +156,47 @@ void SColorGradingPicker::OnMainValueChanged(float InValue, bool ShouldCommitVal TransformColorGradingRangeToLinearColorRange(InValue); FVector4 CurrentValue(0.0f, 0.0f, 0.0f, 0.0f); - OnQueryCurrentColor.ExecuteIfBound(CurrentValue); - TransformColorGradingRangeToLinearColorRange(CurrentValue); - - - //The MainValue is the maximum of any channel value - float MaxCurrentValue = FMath::Max3(CurrentValue.X, CurrentValue.Y, CurrentValue.Z); - if (MaxCurrentValue <= SMALL_NUMBER) + + if (OnQueryCurrentColor.IsBound()) { - //We need the neutral value for the type of color grading, currently only offset is an addition(0.0) all other are multiplier(1.0) - CurrentValue = FVector4(InValue, InValue, InValue, CurrentValue.W); + if (OnQueryCurrentColor.Execute(CurrentValue)) + { + TransformColorGradingRangeToLinearColorRange(CurrentValue); + + //The MainValue is the maximum of any channel value + float MaxCurrentValue = FMath::Max3(CurrentValue.X, CurrentValue.Y, CurrentValue.Z); + if (MaxCurrentValue <= SMALL_NUMBER) + { + //We need the neutral value for the type of color grading, currently only offset is an addition(0.0) all other are multiplier(1.0) + CurrentValue = FVector4(InValue, InValue, InValue, CurrentValue.W); + } + else + { + float Ratio = InValue / MaxCurrentValue; + CurrentValue *= FVector4(Ratio, Ratio, Ratio, 1.0f); + AdjustRatioValue(CurrentValue); + } + TransformLinearColorRangeToColorGradingRange(CurrentValue); + OnColorCommitted.ExecuteIfBound(CurrentValue, ShouldCommitValueChanges); + } } - else - { - float Ratio = InValue / MaxCurrentValue; - CurrentValue *= FVector4(Ratio, Ratio, Ratio, 1.0f); - AdjustRatioValue(CurrentValue); - } - TransformLinearColorRangeToColorGradingRange(CurrentValue); - OnColorCommitted.ExecuteIfBound(CurrentValue, ShouldCommitValueChanges); } TOptional SColorGradingPicker::OnGetMainValue() const { FVector4 CurrentValue(0.0f, 0.0f, 0.0f, 0.0f); - OnQueryCurrentColor.ExecuteIfBound(CurrentValue); - //The MainValue is the maximum of any channel value - TOptional CurrentValueOption = FMath::Max3(CurrentValue.X, CurrentValue.Y, CurrentValue.Z); - return CurrentValueOption; + + if (OnQueryCurrentColor.IsBound()) + { + if (OnQueryCurrentColor.Execute(CurrentValue)) + { + //The MainValue is the maximum of any channel value + TOptional CurrentValueOption = FMath::Max3(CurrentValue.X, CurrentValue.Y, CurrentValue.Z); + return CurrentValueOption; + } + } + + return TOptional(); } void SColorGradingPicker::TransformLinearColorRangeToColorGradingRange(FVector4 &VectorValue) const @@ -198,11 +224,16 @@ FLinearColor SColorGradingPicker::GetCurrentLinearColor() { FLinearColor CurrentColor; FVector4 CurrentValue; - if (OnQueryCurrentColor.ExecuteIfBound(CurrentValue)) + + if (OnQueryCurrentColor.IsBound()) { - TransformColorGradingRangeToLinearColorRange(CurrentValue); - CurrentColor = FLinearColor(CurrentValue.X, CurrentValue.Y, CurrentValue.Z); + if (OnQueryCurrentColor.Execute(CurrentValue)) + { + TransformColorGradingRangeToLinearColorRange(CurrentValue); + CurrentColor = FLinearColor(CurrentValue.X, CurrentValue.Y, CurrentValue.Z); + } } + return CurrentColor.LinearRGBToHSV(); } @@ -210,14 +241,18 @@ void SColorGradingPicker::HandleCurrentColorValueChanged( const FLinearColor& Ne { //Query the current vector4 so we can pass back the w value FVector4 CurrentValue(0.0f, 0.0f, 0.0f, 0.0f); - OnQueryCurrentColor.ExecuteIfBound(CurrentValue); - - FLinearColor NewValueRGB = NewValue.HSVToLinearRGB(); - FVector4 NewValueVector(NewValueRGB.R, NewValueRGB.G, NewValueRGB.B); - TransformLinearColorRangeToColorGradingRange(NewValueVector); - //Set the W with the original value - NewValueVector.W = CurrentValue.W; - OnColorCommitted.ExecuteIfBound(NewValueVector, ShouldCommitValueChanges); + if (OnQueryCurrentColor.IsBound()) + { + if (OnQueryCurrentColor.Execute(CurrentValue)) + { + FLinearColor NewValueRGB = NewValue.HSVToLinearRGB(); + FVector4 NewValueVector(NewValueRGB.R, NewValueRGB.G, NewValueRGB.B); + TransformLinearColorRangeToColorGradingRange(NewValueVector); + //Set the W with the original value + NewValueVector.W = CurrentValue.W; + OnColorCommitted.ExecuteIfBound(NewValueVector, ShouldCommitValueChanges); + } + } } void SColorGradingPicker::OnDynamicSliderMaxValueChanged(float NewMaxSliderValue, TWeakPtr InValueChangedSourceWidget, bool IsOriginator, bool UpdateOnlyIfHigher) diff --git a/Engine/Source/Runtime/AppFramework/Private/Widgets/Colors/SColorPicker.cpp b/Engine/Source/Runtime/AppFramework/Private/Widgets/Colors/SColorPicker.cpp index ab1a47fd08ea..504624038df6 100644 --- a/Engine/Source/Runtime/AppFramework/Private/Widgets/Colors/SColorPicker.cpp +++ b/Engine/Source/Runtime/AppFramework/Private/Widgets/Colors/SColorPicker.cpp @@ -1664,7 +1664,7 @@ bool OpenColorPicker(const FColorPickerArgs& Args) const FVector2D CursorPos = FSlateApplication::Get().GetCursorPos(); FSlateRect Anchor(CursorPos.X, CursorPos.Y, CursorPos.X, CursorPos.Y); - FVector2D AdjustedSummonLocation = FSlateApplication::Get().CalculatePopupWindowPosition( Anchor, SColorPicker::DEFAULT_WINDOW_SIZE, Orient_Horizontal ); + FVector2D AdjustedSummonLocation = FSlateApplication::Get().CalculatePopupWindowPosition( Anchor, SColorPicker::DEFAULT_WINDOW_SIZE, FVector2D::ZeroVector, Orient_Horizontal ); // Only override the color picker window creation behavior if we are not creating a modal color picker const bool bOverrideNonModalCreation = (SColorPicker::OnColorPickerNonModalCreateOverride.IsBound() && !Args.bIsModal); diff --git a/Engine/Source/Runtime/AppFramework/Private/Widgets/Testing/STestSuite.cpp b/Engine/Source/Runtime/AppFramework/Private/Widgets/Testing/STestSuite.cpp index 52a5d142655a..b077ece4d001 100644 --- a/Engine/Source/Runtime/AppFramework/Private/Widgets/Testing/STestSuite.cpp +++ b/Engine/Source/Runtime/AppFramework/Private/Widgets/Testing/STestSuite.cpp @@ -5837,7 +5837,7 @@ TSharedRef SpawnTestSuite2( const FSpawnTabArgs& Args ) .SetGroup(TestSuiteMenu::SuiteTabs); TestSuite2TabManager->RegisterTabSpawner("InvalidationTest", FOnSpawnTab::CreateStatic(&SpawnTab, FName("InvalidationTest"))) - .SetDisplayName(NSLOCTEXT("TestSuite1", "InvalidationTest", "Invalidtion")) + .SetDisplayName(NSLOCTEXT("TestSuite1", "InvalidationTest", "Invalidation")) .SetGroup(TestSuiteMenu::SuiteTabs); TestSuite2TabManager->RegisterTabSpawner("GammaTest", FOnSpawnTab::CreateStatic(&SpawnTab, FName("GammaTest"))) diff --git a/Engine/Source/Runtime/AppFramework/Public/Widgets/Colors/SColorGradingPicker.h b/Engine/Source/Runtime/AppFramework/Public/Widgets/Colors/SColorGradingPicker.h index fd8342d742cf..5c6e7520aa74 100644 --- a/Engine/Source/Runtime/AppFramework/Public/Widgets/Colors/SColorGradingPicker.h +++ b/Engine/Source/Runtime/AppFramework/Public/Widgets/Colors/SColorGradingPicker.h @@ -12,7 +12,7 @@ #include "SNumericEntryBox.h" /** Callback to get the current FVector4 value */ -DECLARE_DELEGATE_OneParam(FOnGetCurrentVector4Value, FVector4&) +DECLARE_DELEGATE_RetVal_OneParam(bool, FOnGetCurrentVector4Value, FVector4&) /** * Enumerates color picker modes. @@ -45,7 +45,8 @@ public: SLATE_BEGIN_ARGS(SColorGradingPicker) - : _SupportDynamicSliderMaxValue(false) + : _AllowSpin(true) + , _SupportDynamicSliderMaxValue(false) , _SupportDynamicSliderMinValue(false) , _MainDelta(0.01f) , _MainShiftMouseMovePixelPerDelta(10) @@ -58,6 +59,7 @@ public: SLATE_ARGUMENT(TOptional, ValueMax ) SLATE_ARGUMENT(TOptional, SliderValueMin) SLATE_ARGUMENT(TOptional, SliderValueMax) + SLATE_ATTRIBUTE(bool, AllowSpin) /** Tell us if we want to support dynamically changing of the max value using ctrl */ SLATE_ATTRIBUTE(bool, SupportDynamicSliderMaxValue) @@ -107,6 +109,8 @@ protected: void OnMainValueChanged(float InValue, bool ShouldCommitValueChanges); FLinearColor GetCurrentLinearColor(); + bool IsEntryBoxEnabled() const; + // Callback for value changes in the color spectrum picker. void HandleCurrentColorValueChanged(const FLinearColor& NewValue, bool ShouldCommitValueChanges); void HandleColorWheelMouseCaptureEnd(); diff --git a/Engine/Source/Runtime/Apple/AudioMixerAudioUnit/AudioMixerAudioUnit.Build.cs b/Engine/Source/Runtime/Apple/AudioMixerAudioUnit/AudioMixerAudioUnit.Build.cs new file mode 100644 index 000000000000..2e44a5a89e40 --- /dev/null +++ b/Engine/Source/Runtime/Apple/AudioMixerAudioUnit/AudioMixerAudioUnit.Build.cs @@ -0,0 +1,40 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +using UnrealBuildTool; + +public class AudioMixerAudioUnit : ModuleRules +{ + public AudioMixerAudioUnit(ReadOnlyTargetRules Target) : base(Target) + { + PrivateIncludePathModuleNames.Add("TargetPlatform"); + PublicIncludePaths.Add("Runtime/AudioMixer/Public"); + PrivateIncludePaths.Add("Runtime/AudioMixer/Private"); + + PrivateDependencyModuleNames.AddRange( + new string[] { + "Core", + "CoreUObject", + "Engine", + } + ); + + PrecompileForTargets = PrecompileTargetsType.None; + + PrivateDependencyModuleNames.Add("AudioMixer"); + + AddEngineThirdPartyPrivateStaticDependencies(Target, + "UEOgg", + "Vorbis", + "VorbisFile" + ); + + PublicFrameworks.AddRange(new string[] + { + "AudioToolbox", + "CoreAudio", + "AVFoundation" + }); + + Definitions.Add("WITH_OGGVORBIS=1"); + } +} diff --git a/Engine/Source/Runtime/Apple/AudioMixerAudioUnit/Private/AudioMixerAudioUnit.cpp b/Engine/Source/Runtime/Apple/AudioMixerAudioUnit/Private/AudioMixerAudioUnit.cpp new file mode 100644 index 000000000000..e4671c319a97 --- /dev/null +++ b/Engine/Source/Runtime/Apple/AudioMixerAudioUnit/Private/AudioMixerAudioUnit.cpp @@ -0,0 +1,24 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +/** + Concrete implementation of FAudioDevice for Apple's CoreAudio + +*/ + +#include "AudioMixer.h" +#include "AudioMixerDevice.h" +#include "AudioMixerPlatformAudioUnit.h" + + +class FAudioMixerModuleAudioUnit : public IAudioDeviceModule +{ +public: + virtual bool IsAudioMixerModule() const override { return true; } + + virtual FAudioDevice* CreateAudioDevice() override + { + return new Audio::FMixerDevice(new Audio::FMixerPlatformAudioUnit()); + } +}; + +IMPLEMENT_MODULE(FAudioMixerModuleAudioUnit, AudioMixerAudioUnit); diff --git a/Engine/Source/Runtime/Apple/AudioMixerAudioUnit/Private/AudioMixerPlatformAudioUnit.cpp b/Engine/Source/Runtime/Apple/AudioMixerAudioUnit/Private/AudioMixerPlatformAudioUnit.cpp new file mode 100644 index 000000000000..c714e2464633 --- /dev/null +++ b/Engine/Source/Runtime/Apple/AudioMixerAudioUnit/Private/AudioMixerPlatformAudioUnit.cpp @@ -0,0 +1,450 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "AudioMixerPlatformAudioUnit.h" +#include "ModuleManager.h" +#include "AudioMixer.h" +#include "AudioMixerDevice.h" +#include "CoreGlobals.h" +#include "Misc/ConfigCacheIni.h" +#include "VorbisAudioInfo.h" +#include "ADPCMAudioInfo.h" + +/* + This implementation only depends on the audio units API which allows it to run on iOS. + Unfortunately, it is not clear yet if we can get the detailed channel configuration information + that is needed on desktop from this API. + + For now just assume an iOS configuration (only 2 left and right channels on a single device) +*/ + +/** +* CoreAudio System Headers +*/ +#include +#include +#include + +DECLARE_LOG_CATEGORY_EXTERN(LogAudioMixerAudioUnit, Log, All); +DEFINE_LOG_CATEGORY(LogAudioMixerAudioUnit); + +#define UNREAL_AUDIO_TEST_WHITE_NOISE 0 + +const uint32 cSampleBufferBits = 12; +const uint32 cNumChannels = 2; +const uint32 cAudioMixerBufferSize = 1 << cSampleBufferBits; +const uint32 cSampleBufferSize = cAudioMixerBufferSize * 2 * cNumChannels; +const uint32 cSampleBufferSizeMask = cSampleBufferSize - 1; + +namespace Audio +{ + FMixerPlatformAudioUnit::FMixerPlatformAudioUnit() + : bInitialized(false), + bInCallback(false), + sampleBufferHead(0), + sampleBufferTail(0) + { + sampleBuffer = (SInt16*)FMemory::Malloc(cSampleBufferSize); + } + + FMixerPlatformAudioUnit::~FMixerPlatformAudioUnit() + { + if(sampleBuffer != NULL) + { + FMemory::Free(sampleBuffer); + sampleBuffer = NULL; + } + + if (bInitialized) + { + TeardownHardware(); + } + } + + bool FMixerPlatformAudioUnit::InitializeHardware() + { + if (bInitialized) + { + return false; + } + + size_t SampleSize = sizeof(SInt16); + double GraphSampleRate = 44100.0; + + AVAudioSession* AudioSession = [AVAudioSession sharedInstance]; + [AudioSession setPreferredSampleRate:GraphSampleRate error:nil]; + [AudioSession setActive:true error:nil]; + + // Retrieve the actual hardware sample rate + GraphSampleRate = [AudioSession preferredSampleRate]; + + DeviceInfo.NumChannels = 2; + DeviceInfo.SampleRate = (int32)GraphSampleRate; + DeviceInfo.Format = EAudioMixerStreamDataFormat::Int16; + DeviceInfo.OutputChannelArray.SetNum(2); + DeviceInfo.OutputChannelArray[0] = EAudioMixerChannel::FrontLeft; + DeviceInfo.OutputChannelArray[1] = EAudioMixerChannel::FrontRight; + DeviceInfo.bIsSystemDefault = true; + AudioStreamInfo.DeviceInfo = DeviceInfo; + + // Linear PCM stream format + OutputFormat.mFormatID = kAudioFormatLinearPCM; + OutputFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; + OutputFormat.mChannelsPerFrame = 2; + OutputFormat.mBytesPerFrame = sizeof(SInt16) * OutputFormat.mChannelsPerFrame; + OutputFormat.mFramesPerPacket = 1; + OutputFormat.mBytesPerPacket = OutputFormat.mBytesPerFrame * OutputFormat.mFramesPerPacket; + OutputFormat.mBitsPerChannel = 8 * sizeof(SInt16); + OutputFormat.mSampleRate = GraphSampleRate; + + OSStatus Status = NewAUGraph(&AudioUnitGraph); + if (Status != noErr) + { + HandleError(TEXT("Failed to create audio unit graph!")); + return false; + } + + AudioComponentDescription UnitDescription; + + // Setup audio output unit + UnitDescription.componentType = kAudioUnitType_Output; + UnitDescription.componentSubType = kAudioUnitSubType_RemoteIO; + UnitDescription.componentManufacturer = kAudioUnitManufacturer_Apple; + UnitDescription.componentFlags = 0; + UnitDescription.componentFlagsMask = 0; + Status = AUGraphAddNode(AudioUnitGraph, &UnitDescription, &OutputNode); + if (Status != noErr) + { + HandleError(TEXT("Failed to initialize audio output node!"), true); + return false; + } + + Status = AUGraphOpen(AudioUnitGraph); + if (Status != noErr) + { + HandleError(TEXT("Failed to open audio unit graph"), true); + return false; + } + + Status = AUGraphNodeInfo(AudioUnitGraph, OutputNode, NULL, &OutputUnit); + if (Status != noErr) + { + HandleError(TEXT("Failed to retrieve output unit reference!"), true); + return false; + } + + Status = AudioUnitSetProperty(OutputUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + 0, + &OutputFormat, + sizeof(AudioStreamBasicDescription)); + if (Status != noErr) + { + HandleError(TEXT("Failed to set output format!"), true); + return false; + } + + // Set the approimate callback rate for iOS, this can't be banked on so we must buffer to handle varibale sized requests from the os + Float32 bufferSizeInSec = (float)cAudioMixerBufferSize / GraphSampleRate; + NSError* error; + [AudioSession setPreferredIOBufferDuration:bufferSizeInSec error:&error]; + + AURenderCallbackStruct InputCallback; + InputCallback.inputProc = &IOSAudioRenderCallback; + InputCallback.inputProcRefCon = this; + Status = AUGraphSetNodeInputCallback(AudioUnitGraph, + OutputNode, + 0, + &InputCallback); + UE_CLOG(Status != noErr, LogAudioMixerAudioUnit, Error, TEXT("Failed to set input callback for audio output node")); + + + AudioStreamInfo.StreamState = EAudioOutputStreamState::Closed; + + bInitialized = true; + + return true; + } + + bool FMixerPlatformAudioUnit::CheckAudioDeviceChange() + { + // only ever one device currently + return false; + } + + bool FMixerPlatformAudioUnit::TeardownHardware() + { + if(!bInitialized) + { + return true; + } + + StopAudioStream(); + CloseAudioStream(); + + DisposeAUGraph(AudioUnitGraph); + + AudioUnitGraph = NULL; + OutputNode = -1; + OutputUnit = NULL; + + bInitialized = false; + + return true; + } + + bool FMixerPlatformAudioUnit::IsInitialized() const + { + return bInitialized; + } + + bool FMixerPlatformAudioUnit::GetNumOutputDevices(uint32& OutNumOutputDevices) + { + OutNumOutputDevices = 1; + + return true; + } + + bool FMixerPlatformAudioUnit::GetOutputDeviceInfo(const uint32 InDeviceIndex, FAudioPlatformDeviceInfo& OutInfo) + { + OutInfo = DeviceInfo; + return true; + } + + bool FMixerPlatformAudioUnit::GetDefaultOutputDeviceIndex(uint32& OutDefaultDeviceIndex) const + { + OutDefaultDeviceIndex = 0; + + return true; + } + + bool FMixerPlatformAudioUnit::OpenAudioStream(const FAudioMixerOpenStreamParams& Params) + { + if (!bInitialized || AudioStreamInfo.StreamState != EAudioOutputStreamState::Closed) + { + return false; + } + + AudioStreamInfo.DeviceInfo = DeviceInfo; + AudioStreamInfo.OutputDeviceIndex = Params.OutputDeviceIndex; + AudioStreamInfo.AudioMixer = Params.AudioMixer; + + // Initialize the audio unit graph + OSStatus Status = AUGraphInitialize(AudioUnitGraph); + if (Status != noErr) + { + HandleError(TEXT("Failed to initialize audio graph!"), true); + return false; + } + + AudioStreamInfo.StreamState = EAudioOutputStreamState::Open; + + return true; + } + + bool FMixerPlatformAudioUnit::CloseAudioStream() + { + if (!bInitialized || (AudioStreamInfo.StreamState != EAudioOutputStreamState::Open && AudioStreamInfo.StreamState != EAudioOutputStreamState::Stopped)) + { + return false; + } + + AudioStreamInfo.StreamState = EAudioOutputStreamState::Closed; + + return true; + } + + bool FMixerPlatformAudioUnit::StartAudioStream() + { + if (!bInitialized || (AudioStreamInfo.StreamState != EAudioOutputStreamState::Open && AudioStreamInfo.StreamState != EAudioOutputStreamState::Stopped)) + { + return false; + } + + sampleBufferHead = sampleBufferTail = 0; + BeginGeneratingAudio(); + ReadNextBuffer(); + + // This will start the render audio callback + OSStatus Status = AUGraphStart(AudioUnitGraph); + if (Status != noErr) + { + HandleError(TEXT("Failed to start audio graph!"), true); + return false; + } + + return true; + } + + bool FMixerPlatformAudioUnit::StopAudioStream() + { + if(!bInitialized || AudioStreamInfo.StreamState != EAudioOutputStreamState::Running) + { + return false; + } + + AudioStreamInfo.StreamState = EAudioOutputStreamState::Stopping; + + AUGraphStop(AudioUnitGraph); + + AudioStreamInfo.StreamState = EAudioOutputStreamState::Stopped; + + return true; + } + + bool FMixerPlatformAudioUnit::MoveAudioStreamToNewAudioDevice(const FString& InNewDeviceId) + { + return false; + } + + FAudioPlatformDeviceInfo FMixerPlatformAudioUnit::GetPlatformDeviceInfo() const + { + return AudioStreamInfo.DeviceInfo; + } + + void FMixerPlatformAudioUnit::SubmitBuffer(const uint8* Buffer) + { + int32 sampleCount = AudioStreamInfo.NumOutputFrames * AudioStreamInfo.DeviceInfo.NumChannels; + float const* curSample = (const float*)Buffer; + float const* lastSample = curSample + sampleCount; + + while(curSample < lastSample) + { + if(sampleBufferHead - sampleBufferTail < cSampleBufferSize) + { + sampleBuffer[sampleBufferHead++ & cSampleBufferSizeMask] = (SInt16)(*curSample++ * 32767.0f); + } + else + { + // Overrun + check(false); + } + } + } + + FName FMixerPlatformAudioUnit::GetRuntimeFormat(USoundWave* InSoundWave) + { + static FName NAME_ADPCM(TEXT("ADPCM")); + return NAME_ADPCM; + } + + bool FMixerPlatformAudioUnit::HasCompressedAudioInfoClass(USoundWave* InSoundWave) + { + return true; + } + + ICompressedAudioInfo* FMixerPlatformAudioUnit::CreateCompressedAudioInfo(USoundWave* InSoundWave) + { + return new FADPCMAudioInfo(); + } + + FString FMixerPlatformAudioUnit::GetDefaultDeviceName() + { + return FString(); + } + + FAudioPlatformSettings FMixerPlatformAudioUnit::GetPlatformSettings() const + { + return FAudioPlatformSettings(); + } + + void FMixerPlatformAudioUnit::ResumeContext() + { + if (bSuspended) + { + AUGraphStart(AudioUnitGraph); + UE_LOG(LogAudioMixerAudioUnit, Display, TEXT("Resuming Audio")); + bSuspended = false; + } + } + + void FMixerPlatformAudioUnit::SuspendContext() + { + if (!bSuspended) + { + AUGraphStop(AudioUnitGraph); + UE_LOG(LogAudioMixerAudioUnit, Display, TEXT("Suspending Audio")); + bSuspended = true; + } + } + + void FMixerPlatformAudioUnit::HandleError(const TCHAR* InLogOutput, bool bTeardown) + { + UE_LOG(LogAudioMixerAudioUnit, Log, TEXT("%s"), InLogOutput); + if (bTeardown) + { + TeardownHardware(); + } + } + + bool FMixerPlatformAudioUnit::PerformCallback(UInt32 NumFrames, const AudioBufferList* OutputBufferData) + { + bInCallback = true; + + if (AudioStreamInfo.StreamState == EAudioOutputStreamState::Running) + { + + #if UNREAL_AUDIO_TEST_WHITE_NOISE + + for (uint32 bufferItr = 0; bufferItr < OutputBufferData->mNumberBuffers; ++bufferItr) + { + SInt16* floatSampleData = (SInt16*)OutputBufferData->mBuffers[bufferItr].mData; + for (uint32 Sample = 0; Sample < OutputBufferData->mBuffers[bufferItr].mDataByteSize / sizeof(SInt16); ++Sample) + { + floatSampleData[Sample] = (SInt16)FMath::FRandRange(-10000.0f, 10000.0f); + } + } + + #else // UNREAL_AUDIO_TEST_WHITE_NOISE + + // We can not count on getting predicable buffer sizes on iOS so we have to do some buffering + int outputBufferSize = OutputBufferData->mBuffers[0].mDataByteSize / sizeof(SInt16); + SInt16* curOutputSample = (SInt16*)OutputBufferData->mBuffers[0].mData; + SInt16* lastOutputSample = curOutputSample + outputBufferSize; + + while(curOutputSample < lastOutputSample) + { + if(sampleBufferHead - sampleBufferTail <= cSampleBufferSize / 2) + { + ReadNextBuffer(); // This will trigger a call to SubmitBuffer() which will copy the audio generated by the mixer into audioMixerSampleBuffer + } + + if(sampleBufferHead > sampleBufferTail) + { + *curOutputSample++ = sampleBuffer[sampleBufferTail++ & cSampleBufferSizeMask]; + } + else + { + // Underrun + *curOutputSample++ = 0; + check(false); + } + } + + #endif // UNREAL_AUDIO_TEST_WHITE_NOISE + } + else + { + for (uint32 bufferItr = 0; bufferItr < OutputBufferData->mNumberBuffers; ++bufferItr) + { + memset(OutputBufferData->mBuffers[bufferItr].mData, 0, OutputBufferData->mBuffers[bufferItr].mDataByteSize); + } + } + + bInCallback = false; + + return true; + } + + OSStatus FMixerPlatformAudioUnit::IOSAudioRenderCallback(void* RefCon, AudioUnitRenderActionFlags* ActionFlags, + const AudioTimeStamp* TimeStamp, UInt32 BusNumber, + UInt32 NumFrames, AudioBufferList* IOData) + { + // Get the user data and cast to our FMixerPlatformCoreAudio object + FMixerPlatformAudioUnit* me = (FMixerPlatformAudioUnit*) RefCon; + + me->PerformCallback(NumFrames, IOData); + + return noErr; + } +} diff --git a/Engine/Source/Runtime/Apple/AudioMixerAudioUnit/Private/AudioMixerPlatformAudioUnit.h b/Engine/Source/Runtime/Apple/AudioMixerAudioUnit/Private/AudioMixerPlatformAudioUnit.h new file mode 100644 index 000000000000..6c34076f0ff7 --- /dev/null +++ b/Engine/Source/Runtime/Apple/AudioMixerAudioUnit/Private/AudioMixerPlatformAudioUnit.h @@ -0,0 +1,78 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "AudioMixer.h" + +#include +#include + +// Any platform defines +namespace Audio +{ + + class FMixerPlatformAudioUnit : public IAudioMixerPlatformInterface + { + + public: + + FMixerPlatformAudioUnit(); + ~FMixerPlatformAudioUnit(); + + //~ Begin IAudioMixerPlatformInterface + virtual EAudioMixerPlatformApi::Type GetPlatformApi() const override { return EAudioMixerPlatformApi::CoreAudio; } + virtual bool InitializeHardware() override; + virtual bool CheckAudioDeviceChange() override; + virtual bool TeardownHardware() override; + virtual bool IsInitialized() const override; + virtual bool GetNumOutputDevices(uint32& OutNumOutputDevices) override; + virtual bool GetOutputDeviceInfo(const uint32 InDeviceIndex, FAudioPlatformDeviceInfo& OutInfo) override; + virtual bool GetDefaultOutputDeviceIndex(uint32& OutDefaultDeviceIndex) const override; + virtual bool OpenAudioStream(const FAudioMixerOpenStreamParams& Params) override; + virtual bool CloseAudioStream() override; + virtual bool StartAudioStream() override; + virtual bool StopAudioStream() override; + virtual bool MoveAudioStreamToNewAudioDevice(const FString& InNewDeviceId) override; + virtual FAudioPlatformDeviceInfo GetPlatformDeviceInfo() const override; + virtual void SubmitBuffer(const uint8* Buffer) override; + virtual FName GetRuntimeFormat(USoundWave* InSoundWave) override; + virtual bool HasCompressedAudioInfoClass(USoundWave* InSoundWave) override; + virtual ICompressedAudioInfo* CreateCompressedAudioInfo(USoundWave* InSoundWave) override; + virtual FString GetDefaultDeviceName() override; + virtual FAudioPlatformSettings GetPlatformSettings() const override; + //~ End IAudioMixerPlatformInterface + + // These are not being used yet but they should be in the near future + void ResumeContext(); + void SuspendContext(); + + private: + FAudioPlatformDeviceInfo DeviceInfo; + AudioStreamBasicDescription OutputFormat; + + bool bSuspended; + + /** True if the connection to the device has been initialized */ + bool bInitialized; + + /** True if execution is in the callback */ + bool bInCallback; + + SInt16* sampleBuffer; + uint32 sampleBufferHead; + uint32 sampleBufferTail; + + AUGraph AudioUnitGraph; + AUNode OutputNode; + AudioUnit OutputUnit; + + bool PerformCallback(UInt32 NumFrames, const AudioBufferList* OutputBufferData); + void HandleError(const TCHAR* InLogOutput, bool bTeardown = true); + static OSStatus IOSAudioRenderCallback(void* RefCon, AudioUnitRenderActionFlags* ActionFlags, + const AudioTimeStamp* TimeStamp, UInt32 BusNumber, + UInt32 NumFrames, AudioBufferList* IOData); + + }; + +} + diff --git a/Engine/Source/Runtime/Apple/AudioMixerCoreAudio/Private/AudioMixerCoreAudio.cpp b/Engine/Source/Runtime/Apple/AudioMixerCoreAudio/Private/AudioMixerCoreAudio.cpp index 64e6ddfdac0a..cc92b54d4f42 100644 --- a/Engine/Source/Runtime/Apple/AudioMixerCoreAudio/Private/AudioMixerCoreAudio.cpp +++ b/Engine/Source/Runtime/Apple/AudioMixerCoreAudio/Private/AudioMixerCoreAudio.cpp @@ -13,6 +13,9 @@ class FAudioMixerModuleCoreAudio : public IAudioDeviceModule { public: + + virtual bool IsAudioMixerModule() const override { return true; } + virtual FAudioDevice* CreateAudioDevice() override { return new Audio::FMixerDevice(new Audio::FMixerPlatformCoreAudio()); diff --git a/Engine/Source/Runtime/Apple/AudioMixerCoreAudio/Private/AudioMixerPlatformCoreAudio.cpp b/Engine/Source/Runtime/Apple/AudioMixerCoreAudio/Private/AudioMixerPlatformCoreAudio.cpp index 3090cd500bf9..0c3c13512fb5 100644 --- a/Engine/Source/Runtime/Apple/AudioMixerCoreAudio/Private/AudioMixerPlatformCoreAudio.cpp +++ b/Engine/Source/Runtime/Apple/AudioMixerCoreAudio/Private/AudioMixerPlatformCoreAudio.cpp @@ -92,19 +92,17 @@ namespace Audio TArray FMixerPlatformCoreAudio::DeviceArray; FMixerPlatformCoreAudio::FMixerPlatformCoreAudio() - : - OutputDeviceId(INDEX_NONE), - OutputDeviceIndex(INDEX_NONE), - DefaultDeviceId(INDEX_NONE), - DefaultDeviceIndex(INDEX_NONE), - DeviceIOProcId(nullptr), - NumDeviceStreams(0), - bInitialized(false), - bInCallback(false), - coreAudioBuffer(NULL), - coreAudioBufferByteSize(0) + : OutputDeviceId(INDEX_NONE) + , OutputDeviceIndex(INDEX_NONE) + , DefaultDeviceId(INDEX_NONE) + , DefaultDeviceIndex(INDEX_NONE) + , DeviceIOProcId(nullptr) + , NumDeviceStreams(0) + , bInitialized(false) + , bInCallback(false) + , coreAudioBuffer(nullptr) + , coreAudioBufferByteSize(0) { - } FMixerPlatformCoreAudio::~FMixerPlatformCoreAudio() @@ -115,7 +113,6 @@ namespace Audio } } - //~ Begin IAudioMixerPlatformInterface bool FMixerPlatformCoreAudio::InitializeHardware() { if (bInitialized) @@ -205,8 +202,6 @@ namespace Audio { AudioStreamInfo.StreamState = EAudioOutputStreamState::Open; - AudioStreamInfo.DeviceInfo.NumFrames = AudioStreamInfo.NumOutputFrames; - AudioStreamInfo.DeviceInfo.NumSamples = AudioStreamInfo.NumOutputFrames * AudioStreamInfo.DeviceInfo.NumChannels; AudioStreamInfo.OutputDeviceIndex = Params.OutputDeviceIndex; AudioStreamInfo.AudioMixer = Params.AudioMixer; } @@ -230,7 +225,7 @@ namespace Audio AudioStreamInfo.StreamState = EAudioOutputStreamState::Closed; - return false; + return true; } bool FMixerPlatformCoreAudio::StartAudioStream() @@ -285,12 +280,12 @@ namespace Audio return AudioStreamInfo.DeviceInfo; } - void FMixerPlatformCoreAudio::SubmitBuffer(const TArray& Buffer) + void FMixerPlatformCoreAudio::SubmitBuffer(const uint8* Buffer) { + // TODO: this shouldn't have to be a copy... could probably just point coreAudioBuffer to Buffer since Buffer is guaranteed to be valid for lifetime of the render! if(coreAudioBuffer != NULL && coreAudioBufferByteSize > 0) { - check(Buffer.Num() * sizeof(float) == coreAudioBufferByteSize); - memcpy(coreAudioBuffer, Buffer.GetData(), Buffer.Num() * sizeof(float)); + memcpy(coreAudioBuffer, Buffer, coreAudioBufferByteSize); } } @@ -302,66 +297,32 @@ namespace Audio bool FMixerPlatformCoreAudio::HasCompressedAudioInfoClass(USoundWave* InSoundWave) { - #if WITH_OGGVORBIS - return true; - #else - return false; - #endif +#if WITH_OGGVORBIS + return true; +#else + return false; +#endif } ICompressedAudioInfo* FMixerPlatformCoreAudio::CreateCompressedAudioInfo(USoundWave* InSoundWave) { - #if WITH_OGGVORBIS - return new FVorbisAudioInfo(); - #else - return NULL; - #endif +#if WITH_OGGVORBIS + return new FVorbisAudioInfo(); +#else + return NULL; +#endif } FString FMixerPlatformCoreAudio::GetDefaultDeviceName() { return FString(); } - //~ End IAudioMixerPlatformInterface - //~ Begin IAudioMixerDeviceChangedLister - void FMixerPlatformCoreAudio::RegisterDeviceChangedListener() + FAudioPlatformSettings FMixerPlatformCoreAudio::GetPlatformSettings() const { - + return FAudioPlatformSettings(); } - void FMixerPlatformCoreAudio::UnRegisterDeviceChangedListener() - { - - } - - void FMixerPlatformCoreAudio::OnDefaultCaptureDeviceChanged(const EAudioDeviceRole InAudioDeviceRole, const FString& DeviceId) - { - - } - - void FMixerPlatformCoreAudio::OnDefaultRenderDeviceChanged(const EAudioDeviceRole InAudioDeviceRole, const FString& DeviceId) - { - - } - - void FMixerPlatformCoreAudio::OnDeviceAdded(const FString& DeviceId) - { - - } - - void FMixerPlatformCoreAudio::OnDeviceRemoved(const FString& DeviceId) - { - - } - - void FMixerPlatformCoreAudio::OnDeviceStateChanged(const FString& DeviceId, const EAudioDeviceState InState) - { - - } - //~ End IAudioMixerDeviceChangedLister - - bool FMixerPlatformCoreAudio::InitRunLoop() { CFRunLoopRef RunLoop = nullptr; @@ -444,7 +405,6 @@ namespace Audio DeviceInfo.DeviceId = FString::Printf(TEXT("%x"), DeviceID); bool bSuccess = GetDeviceName(DeviceID, DeviceInfo.Name); - bSuccess &= GetDeviceLatency(DeviceID, DeviceInfo.Latency); bSuccess &= GetDeviceSampleRate(DeviceID, DeviceInfo.SampleRate); bSuccess &= GetDeviceChannels(DeviceID, DeviceInfo.OutputChannelArray); @@ -455,10 +415,7 @@ namespace Audio AudioObjectPropertyAddress Property = NEW_OUTPUT_PROPERTY(kAudioDevicePropertyBufferFrameSizeRange); OSStatus Status = AudioObjectGetPropertyData(DeviceID, &Property, 0, nullptr, &DataSize, &BufferSizeRange); CORE_AUDIO_ERR(Status, "Failed to get callback buffer size range"); - - DeviceInfo.NumFrames = (uint32)BufferSizeRange.mMaximum; - DeviceInfo.NumSamples = DeviceInfo.NumFrames * DeviceInfo.NumChannels; - + return bSuccess; } @@ -1187,7 +1144,7 @@ namespace Audio const AudioTimeStamp* OutputTime, void* UserData) { - // Get the user data and cast to our FUnrealAudioCoreAudio object + // Get the user data and cast to our FMixerPlatformCoreAudio object FMixerPlatformCoreAudio* me = (FMixerPlatformCoreAudio*) UserData; // Call our callback function diff --git a/Engine/Source/Runtime/Apple/AudioMixerCoreAudio/Private/AudioMixerPlatformCoreAudio.h b/Engine/Source/Runtime/Apple/AudioMixerCoreAudio/Private/AudioMixerPlatformCoreAudio.h index 84d1f71b6b8c..4ac2b63a6996 100644 --- a/Engine/Source/Runtime/Apple/AudioMixerCoreAudio/Private/AudioMixerPlatformCoreAudio.h +++ b/Engine/Source/Runtime/Apple/AudioMixerCoreAudio/Private/AudioMixerPlatformCoreAudio.h @@ -21,37 +21,28 @@ namespace Audio ~FMixerPlatformCoreAudio(); //~ Begin IAudioMixerPlatformInterface - EAudioMixerPlatformApi::Type GetPlatformApi() const override { return EAudioMixerPlatformApi::CoreAudio; } - bool InitializeHardware() override; - bool CheckAudioDeviceChange() override; - bool TeardownHardware() override; - bool IsInitialized() const override; - bool GetNumOutputDevices(uint32& OutNumOutputDevices) override; - bool GetOutputDeviceInfo(const uint32 InDeviceIndex, FAudioPlatformDeviceInfo& OutInfo) override; - bool GetDefaultOutputDeviceIndex(uint32& OutDefaultDeviceIndex) const override; - bool OpenAudioStream(const FAudioMixerOpenStreamParams& Params) override; - bool CloseAudioStream() override; - bool StartAudioStream() override; - bool StopAudioStream() override; - bool MoveAudioStreamToNewAudioDevice(const FString& InNewDeviceId) override; - FAudioPlatformDeviceInfo GetPlatformDeviceInfo() const override; - void SubmitBuffer(const TArray& Buffer) override; - FName GetRuntimeFormat(USoundWave* InSoundWave) override; - bool HasCompressedAudioInfoClass(USoundWave* InSoundWave) override; - ICompressedAudioInfo* CreateCompressedAudioInfo(USoundWave* InSoundWave) override; - FString GetDefaultDeviceName() override; + virtual EAudioMixerPlatformApi::Type GetPlatformApi() const override { return EAudioMixerPlatformApi::CoreAudio; } + virtual bool InitializeHardware() override; + virtual bool CheckAudioDeviceChange() override; + virtual bool TeardownHardware() override; + virtual bool IsInitialized() const override; + virtual bool GetNumOutputDevices(uint32& OutNumOutputDevices) override; + virtual bool GetOutputDeviceInfo(const uint32 InDeviceIndex, FAudioPlatformDeviceInfo& OutInfo) override; + virtual bool GetDefaultOutputDeviceIndex(uint32& OutDefaultDeviceIndex) const override; + virtual bool OpenAudioStream(const FAudioMixerOpenStreamParams& Params) override; + virtual bool CloseAudioStream() override; + virtual bool StartAudioStream() override; + virtual bool StopAudioStream() override; + virtual bool MoveAudioStreamToNewAudioDevice(const FString& InNewDeviceId) override; + virtual FAudioPlatformDeviceInfo GetPlatformDeviceInfo() const override; + virtual void SubmitBuffer(const uint8* Buffer) override; + virtual FName GetRuntimeFormat(USoundWave* InSoundWave) override; + virtual bool HasCompressedAudioInfoClass(USoundWave* InSoundWave) override; + virtual ICompressedAudioInfo* CreateCompressedAudioInfo(USoundWave* InSoundWave) override; + virtual FString GetDefaultDeviceName() override; + virtual FAudioPlatformSettings GetPlatformSettings() const override; //~ End IAudioMixerPlatformInterface - //~ Begin IAudioMixerDeviceChangedLister - void RegisterDeviceChangedListener() override; - void UnRegisterDeviceChangedListener() override; - void OnDefaultCaptureDeviceChanged(const EAudioDeviceRole InAudioDeviceRole, const FString& DeviceId) override; - void OnDefaultRenderDeviceChanged(const EAudioDeviceRole InAudioDeviceRole, const FString& DeviceId) override; - void OnDeviceAdded(const FString& DeviceId) override; - void OnDeviceRemoved(const FString& DeviceId) override; - void OnDeviceStateChanged(const FString& DeviceId, const EAudioDeviceState InState) override; - //~ End IAudioMixerDeviceChangedLister - private: struct FDevice diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalBlitCommandEncoder.cpp b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalBlitCommandEncoder.cpp index 4e3bf464500e..94d4aa035c18 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalBlitCommandEncoder.cpp +++ b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalBlitCommandEncoder.cpp @@ -14,6 +14,8 @@ extern int32 GMetalRuntimeDebugLevel; @implementation FMetalDebugBlitCommandEncoder +APPLE_PLATFORM_OBJECT_ALLOC_OVERRIDES(FMetalDebugBlitCommandEncoder) + @synthesize Inner; @synthesize Buffer; diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalCommandEncoder.cpp b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalCommandEncoder.cpp index 37d17745bcce..d9a95a0f75c7 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalCommandEncoder.cpp +++ b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalCommandEncoder.cpp @@ -38,7 +38,7 @@ FMetalCommandEncoder::FMetalCommandEncoder(FMetalCommandList& CmdList) RingBuffer = MakeShareable(new FRingBuffer(CommandList.GetCommandQueue().GetDevice(), ResOptions, EncoderRingBufferSize, BufferOffsetAlignment)); - for (uint32 i = 0; i < MaxMetalRenderTargets; i++) + for (uint32 i = 0; i < MaxSimultaneousRenderTargets; i++) { ColorStoreActions[i] = MTLStoreActionUnknown; } @@ -84,7 +84,7 @@ void FMetalCommandEncoder::Reset(void) static bool bDeferredStoreActions = CommandList.GetCommandQueue().SupportsFeature(EMetalFeaturesDeferredStoreActions); if (bDeferredStoreActions) { - for (uint32 i = 0; i < MaxMetalRenderTargets; i++) + for (uint32 i = 0; i < MaxSimultaneousRenderTargets; i++) { ColorStoreActions[i] = MTLStoreActionUnknown; } @@ -350,7 +350,7 @@ id FMetalCommandEncoder::EndEncoding(void) { check(RenderPassDesc); - for (uint32 i = 0; i < MaxMetalRenderTargets; i++) + for (uint32 i = 0; i < MaxSimultaneousRenderTargets; i++) { if (ColorStoreActions[i] != MTLStoreActionUnknown && RenderPassDesc.colorAttachments[i].storeAction == MTLStoreActionUnknown) { @@ -562,7 +562,7 @@ void FMetalCommandEncoder::SetRenderPassDescriptor(MTLRenderPassDescriptor* cons static bool bDeferredStoreActions = CommandList.GetCommandQueue().SupportsFeature(EMetalFeaturesDeferredStoreActions); if (bDeferredStoreActions) { - for (uint32 i = 0; i < MaxMetalRenderTargets; i++) + for (uint32 i = 0; i < MaxSimultaneousRenderTargets; i++) { ColorStoreActions[i] = MTLStoreActionUnknown; } @@ -581,7 +581,7 @@ void FMetalCommandEncoder::SetRenderPassStoreActions(MTLStoreAction const* const static bool bDeferredStoreActions = CommandList.GetCommandQueue().SupportsFeature(EMetalFeaturesDeferredStoreActions); if (bDeferredStoreActions) { - for (uint32 i = 0; i < MaxMetalRenderTargets; i++) + for (uint32 i = 0; i < MaxSimultaneousRenderTargets; i++) { ColorStoreActions[i] = ColorStore[i]; } diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalCommandEncoder.h b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalCommandEncoder.h index efbd41a0d67f..43e4edebdcbb 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalCommandEncoder.h +++ b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalCommandEncoder.h @@ -341,7 +341,7 @@ private: FMetalBufferBindings ShaderBuffers[MTLFunctionTypeKernel+1]; - MTLStoreAction ColorStoreActions[MaxMetalRenderTargets]; + MTLStoreAction ColorStoreActions[MaxSimultaneousRenderTargets]; MTLStoreAction DepthStoreAction; MTLStoreAction StencilStoreAction; diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalCommandList.cpp b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalCommandList.cpp index fbf7a3f3228c..a9824949fc39 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalCommandList.cpp +++ b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalCommandList.cpp @@ -27,7 +27,7 @@ FMetalCommandList::~FMetalCommandList(void) #pragma mark - Public Command List Mutators - -static void ReportMetalCommandBufferFailure(id CompletedBuffer, TCHAR const* ErrorType) +static void ReportMetalCommandBufferFailure(id CompletedBuffer, TCHAR const* ErrorType, bool bDoCheck=true) { NSString* Label = CompletedBuffer.label; int32 Code = CompletedBuffer.error.code; @@ -44,7 +44,11 @@ static void ReportMetalCommandBufferFailure(id CompletedBuffe NSString* Desc = CompletedBuffer.debugDescription; UE_LOG(LogMetal, Warning, TEXT("%s"), *FString(Desc)); - UE_LOG(LogMetal, Fatal, TEXT("Command Buffer %s Failed with %s Error! Error Domain: %s Code: %d Description %s %s %s"), *LabelString, ErrorType, *DomainString, Code, *ErrorString, *FailureString, *RecoveryString); + + if (bDoCheck) + { + UE_LOG(LogMetal, Fatal, TEXT("Command Buffer %s Failed with %s Error! Error Domain: %s Code: %d Description %s %s %s"), *LabelString, ErrorType, *DomainString, Code, *ErrorString, *FailureString, *RecoveryString); + } } static __attribute__ ((optnone)) void MetalCommandBufferFailureInternal(id CompletedBuffer) @@ -54,7 +58,7 @@ static __attribute__ ((optnone)) void MetalCommandBufferFailureInternal(id CompletedBuffer) { - ReportMetalCommandBufferFailure(CompletedBuffer, TEXT("Timeout")); + ReportMetalCommandBufferFailure(CompletedBuffer, TEXT("Timeout"), PLATFORM_IOS); } static __attribute__ ((optnone)) void MetalCommandBufferFailurePageFault(id CompletedBuffer) diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalComputeCommandEncoder.cpp b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalComputeCommandEncoder.cpp index dcc48b8b859f..30aaf03c6931 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalComputeCommandEncoder.cpp +++ b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalComputeCommandEncoder.cpp @@ -15,6 +15,8 @@ NS_ASSUME_NONNULL_BEGIN @implementation FMetalDebugComputeCommandEncoder +APPLE_PLATFORM_OBJECT_ALLOC_OVERRIDES(FMetalDebugComputeCommandEncoder) + @synthesize Inner; @synthesize Buffer; @synthesize Pipeline; diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalContext.cpp b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalContext.cpp index 4e3446a73f26..24bc83897c62 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalContext.cpp +++ b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalContext.cpp @@ -225,7 +225,6 @@ static id GetMTLDevice(uint32& DeviceIndex) UE_LOG(LogMetal, Warning, TEXT("Couldn't find Metal device %s in GPU descriptors from IORegistry - capability reporting may be wrong."), *FString(SelectedDevice.name)); } } - check(SelectedDevice); return SelectedDevice; } @@ -293,8 +292,13 @@ FMetalDeviceContext* FMetalDeviceContext::CreateDeviceContext() uint32 DeviceIndex = 0; #if PLATFORM_IOS id Device = [IOSAppDelegate GetDelegate].IOSView->MetalDevice; -#else // @todo zebra +#else id Device = GetMTLDevice(DeviceIndex); + if (!Device) + { + FPlatformMisc::MessageBoxExt(EAppMsgType::Ok, TEXT("The graphics card in this Mac appears to erroneously report support for Metal graphics technology, which is required to run this application, but failed to create a Metal device. The application will now exit."), TEXT("Failed to initialize Metal")); + exit(0); + } #endif FMetalCommandQueue* Queue = new FMetalCommandQueue(Device, GMetalCommandQueueSize); check(Queue); @@ -858,7 +862,7 @@ FMetalRHICommandContext* FMetalDeviceContext::AcquireContext(int32 NewIndex, int if (NewIndex == 0) { - if (FRHICommandListExecutor::GetImmediateCommandList().Bypass() || !GRHIThread) + if (FRHICommandListExecutor::GetImmediateCommandList().Bypass() || !IsRunningRHIInSeparateThread()) { FMetalRHICommandUpdateFence UpdateCommand(this, StartFence, FMetalRHICommandUpdateFence::End); UpdateCommand.Execute(FRHICommandListExecutor::GetImmediateCommandList()); @@ -869,7 +873,7 @@ FMetalRHICommandContext* FMetalDeviceContext::AcquireContext(int32 NewIndex, int } } - if (FRHICommandListExecutor::GetImmediateCommandList().Bypass() || !GRHIThread) + if (FRHICommandListExecutor::GetImmediateCommandList().Bypass() || !IsRunningRHIInSeparateThread()) { FMetalRHICommandUpdateFence UpdateCommand(this, EndFence, FMetalRHICommandUpdateFence::Start); UpdateCommand.Execute(FRHICommandListExecutor::GetImmediateCommandList()); @@ -1233,7 +1237,7 @@ void FMetalContext::SetRenderTargetsInfo(const FRHISetRenderTargetsInfo& RenderT { bool bClearInParallelBuffer = false; - for (uint32 RenderTargetIndex = 0; RenderTargetIndex < MaxMetalRenderTargets; RenderTargetIndex++) + for (uint32 RenderTargetIndex = 0; RenderTargetIndex < MaxSimultaneousRenderTargets; RenderTargetIndex++) { if (RenderTargetIndex < RenderTargetsInfo.NumColorRenderTargets && RenderTargetsInfo.ColorRenderTarget[RenderTargetIndex].Texture != nullptr) { diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalHeap.cpp b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalHeap.cpp index 814d5159ad03..8f66e337804f 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalHeap.cpp +++ b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalHeap.cpp @@ -1093,9 +1093,9 @@ id FMetalHeap::CreateTexture(MTLTextureDescriptor* Desc, FMetalSurfa check((uint32)Descriptor.StorageMode < (uint32)EMetalHeapTypeNum); check((uint32)Descriptor.CPUCacheMode < (uint32)EMetalHeapCacheNum); - if ((TotalTextureMemory + Descriptor.Size) > GTexturePoolSize) + if (GTexturePoolSize > 0 && (TotalTextureMemory + Descriptor.Size) > GTexturePoolSize) { - UE_LOG(LogMetal, Warning, TEXT("Texture heap allocations (%.2f) will exceed texture pool size (%.2f) - performance may suffer and the application may be subject to OS low-memory handling!"), (float)(TotalTextureMemory + Descriptor.Size) / 1024.f / 1024.f, ((float)GTexturePoolSize / 1024.f / 1024.f)); + UE_LOG(LogMetal, Verbose, TEXT("Texture heap allocations (%.2f) will exceed texture pool size (%.2f) - performance may suffer and the application may be subject to OS low-memory handling!"), (float)(TotalTextureMemory + Descriptor.Size) / 1024.f / 1024.f, ((float)GTexturePoolSize / 1024.f / 1024.f)); } Heap = CreateHeap(Descriptor); diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalProfiler.cpp b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalProfiler.cpp index 2be3bee7d66a..8c04b9e8d0a3 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalProfiler.cpp +++ b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalProfiler.cpp @@ -254,6 +254,11 @@ void FMetalEventNode::StopDraw(void) } } #endif + +bool MetalGPUProfilerIsInSafeThread() +{ + return IsInRHIThread() || IsInActualRenderingThread(); +} /** Start this frame of per tracking */ void FMetalEventNodeFrame::StartFrame() @@ -295,12 +300,18 @@ void FMetalGPUProfiler::Cleanup() void FMetalGPUProfiler::PushEvent(const TCHAR* Name, FColor Color) { - FGPUProfiler::PushEvent(Name, Color); + if(MetalGPUProfilerIsInSafeThread()) + { + FGPUProfiler::PushEvent(Name, Color); + } } void FMetalGPUProfiler::PopEvent() { - FGPUProfiler::PopEvent(); + if(MetalGPUProfilerIsInSafeThread()) + { + FGPUProfiler::PopEvent(); + } } //TGlobalResource GMetalVector4VertexDeclaration; @@ -314,6 +325,11 @@ void FMetalGPUProfiler::BeginFrame() CurrentEventNodeFrame = new FMetalEventNodeFrame(Context, GTriggerGPUProfile); CurrentEventNodeFrame->StartFrame(); + if(GNumActiveGPUsForRendering > 1) + { + GTriggerGPUProfile = false; + } + if(GTriggerGPUProfile) { bTrackingEvents = true; @@ -373,7 +389,10 @@ void FMetalGPUProfiler::BeginFrame() }*/ } - PushEvent(TEXT("FRAME"), FColor(0, 255, 0, 255)); + if(GEmitDrawEvents) + { + PushEvent(TEXT("FRAME"), FColor(0, 255, 0, 255)); + } } NumNestedFrames++; } @@ -382,7 +401,10 @@ void FMetalGPUProfiler::EndFrame() { if(--NumNestedFrames == 0) { - PopEvent(); + if(GEmitDrawEvents) + { + PopEvent(); + } #if PLATFORM_MAC FPlatformMisc::UpdateDriverMonitorStatistics(GetMetalDeviceContext().GetDeviceIndex()); @@ -444,7 +466,7 @@ void FMetalGPUProfiler::EndFrame() void FMetalGPUProfiler::StartGPUWork(uint32 StartPoint, uint32 EndPoint, uint32 NumPrimitives, uint32 NumVertices) { - if(CurrentEventNode) + if(CurrentEventNode && MetalGPUProfilerIsInSafeThread()) { RegisterGPUWork(NumPrimitives, NumVertices); #if METAL_STATISTICS @@ -457,7 +479,7 @@ void FMetalGPUProfiler::StartGPUWork(uint32 StartPoint, uint32 EndPoint, uint32 void FMetalGPUProfiler::FinishGPUWork(void) { #if METAL_STATISTICS - if(CurrentEventNode) + if(CurrentEventNode && MetalGPUProfilerIsInSafeThread()) { FMetalEventNode* EventNode = (FMetalEventNode*)CurrentEventNode; EventNode->StopDraw(); diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalRHI.cpp b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalRHI.cpp index 1a56c502f554..d76999c94267 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalRHI.cpp +++ b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalRHI.cpp @@ -89,13 +89,6 @@ FMetalDynamicRHI::FMetalDynamicRHI(ERHIFeatureLevel::Type RequestedFeatureLevel) GRHIAdapterName = TEXT("Metal"); GRHIVendorId = 1; // non-zero to avoid asserts - // Disable RHI CommandList State Caching: MetalRHI needs to do this itself internally to function. - static auto CVarRHICmdStateCacheEnable = IConsoleManager::Get().FindConsoleVariable(TEXT("r.RHICmdStateCacheEnable")); - if(CVarRHICmdStateCacheEnable && CVarRHICmdStateCacheEnable->GetInt() != 0) - { - CVarRHICmdStateCacheEnable->Set(0); - } - bool const bRequestedFeatureLevel = (RequestedFeatureLevel != ERHIFeatureLevel::Num); bool bSupportsPointLights = false; bool bSupportsRHIThread = false; diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalRHIPrivate.h b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalRHIPrivate.h index 4048d360e141..46069c4cbf0a 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalRHIPrivate.h +++ b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalRHIPrivate.h @@ -10,9 +10,6 @@ #include "Misc/ScopeLock.h" #include "Misc/CommandLine.h" -// UE4 has a Max of 8 RTs, but we can spend less time looping with 6 -const uint32 MaxMetalRenderTargets = 6; - // Requirement for vertex buffer offset field const uint32 BufferOffsetAlignment = 256; @@ -32,7 +29,7 @@ const uint32 MaxMetalStreams = 31; #define BUFFER_MANAGED_MEM 0 #define BUFFER_STORAGE_MODE MTLStorageModeShared #define BUFFER_RESOURCE_STORAGE_MANAGED MTLResourceStorageModeShared -#define BUFFER_DYNAMIC_REALLOC BUF_Volatile +#define BUFFER_DYNAMIC_REALLOC BUF_AnyDynamic // How many possible vertex streams are allowed const uint32 MaxMetalStreams = 30; #endif diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalRenderCommandEncoder.cpp b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalRenderCommandEncoder.cpp index 4626a01b2a6b..4767b048e28a 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalRenderCommandEncoder.cpp +++ b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalRenderCommandEncoder.cpp @@ -15,6 +15,8 @@ NS_ASSUME_NONNULL_BEGIN @implementation FMetalDebugRenderCommandEncoder +APPLE_PLATFORM_OBJECT_ALLOC_OVERRIDES(FMetalDebugRenderCommandEncoder) + @synthesize Inner; @synthesize Buffer; @synthesize Pipeline; diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalRenderPass.cpp b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalRenderPass.cpp index 45777dd9c7ad..e326f6be9e70 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalRenderPass.cpp +++ b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalRenderPass.cpp @@ -489,15 +489,15 @@ void FMetalRenderPass::DrawPatches(uint32 PrimitiveType,id IndexBuffe if(hullShaderOutputBufferSize) { - deviceContext.ReleasePooledBuffer(hullShaderOutputBuffer); + deviceContext.ReleaseResource(hullShaderOutputBuffer); } if(hullConstShaderOutputBufferSize) { - deviceContext.ReleasePooledBuffer(hullConstShaderOutputBuffer); + deviceContext.ReleaseResource(hullConstShaderOutputBuffer); } if(tessellationFactorBufferSize) { - deviceContext.ReleasePooledBuffer(tessellationFactorBuffer); + deviceContext.ReleaseResource(tessellationFactorBuffer); } auto computeEncoder = PrologueEncoder.GetComputeCommandEncoder(); diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalRenderPipelineDesc.cpp b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalRenderPipelineDesc.cpp index 09eaaa3450f9..6e6f2d8dc07b 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalRenderPipelineDesc.cpp +++ b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalRenderPipelineDesc.cpp @@ -143,7 +143,7 @@ FMetalRenderPipelineDesc::FMetalRenderPipelineDesc() { Hash.RasterBits = 0; Hash.TargetBits = 0; - for (int Index = 0; Index < MaxMetalRenderTargets; Index++) + for (int Index = 0; Index < MaxSimultaneousRenderTargets; Index++) { [PipelineDescriptor.colorAttachments setObject:[[MTLRenderPipelineColorAttachmentDescriptor new] autorelease] atIndexedSubscript:Index]; } @@ -168,7 +168,7 @@ FMetalShaderPipeline* FMetalRenderPipelineDesc::CreatePipelineStateForBoundShade // Disable blending and writing on unbound targets or Metal will assert/crash/abort depending on build. // At least with this API all the state must match all of the time for it to work. - for (int Index = 0; Index < MaxMetalRenderTargets; Index++) + for (int Index = 0; Index < MaxSimultaneousRenderTargets; Index++) { MTLRenderPipelineColorAttachmentDescriptor* Desc = [PipelineDescriptor.colorAttachments objectAtIndexedSubscript:Index]; if(Desc.pixelFormat == MTLPixelFormatInvalid) @@ -206,7 +206,7 @@ FMetalShaderPipeline* FMetalRenderPipelineDesc::CreatePipelineStateForBoundShade NSError* Error = nil; - if(GUseRHIThread) + if (IsRunningRHIInSeparateThread()) { SCOPE_CYCLE_COUNTER(STAT_MetalPipelineLockTime); int Err = pthread_rwlock_rdlock(&MetalPipelineMutex.Mutex); @@ -224,7 +224,7 @@ FMetalShaderPipeline* FMetalRenderPipelineDesc::CreatePipelineStateForBoundShade FMetalShaderPipeline* statePack = MetalPipelineCache.FindRef(ComparableDesc); if(statePack == nil) { - if(GUseRHIThread) + if(IsRunningRHIInSeparateThread()) { SCOPE_CYCLE_COUNTER(STAT_MetalPipelineLockTime); int Err = pthread_rwlock_unlock(&MetalPipelineMutex.Mutex); @@ -251,15 +251,17 @@ FMetalShaderPipeline* FMetalRenderPipelineDesc::CreatePipelineStateForBoundShade tessellationDesc.TessellationControlPointIndexBufferIndex = UINT_MAX; tessellationDesc.DomainVertexDescriptor = PipelineDescriptor.vertexDescriptor; + // Disambiguated function name. + NSString* Name = [NSString stringWithFormat:@"Main_%0.8x_%0.8x", BSS->VertexShader->SourceLen, BSS->VertexShader->SourceCRC]; if (FunctionConstants.Num()) { MTLFunctionConstantValues* constantValues = [[MTLFunctionConstantValues new] autorelease]; [constantValues setConstantValues:FunctionConstants.GetData() type:MTLDataTypeUInt withRange:NSMakeRange(0, FunctionConstants.Num())]; - computeFunction = [[BSS->VertexShader->Library newFunctionWithName:@"Main" constantValues:constantValues error:&Error] autorelease]; + computeFunction = [[BSS->VertexShader->Library newFunctionWithName:Name constantValues:constantValues error:&Error] autorelease]; } else { - computeFunction = [[BSS->VertexShader->Library newFunctionWithName:@"Main"] autorelease]; + computeFunction = [[BSS->VertexShader->Library newFunctionWithName:Name] autorelease]; } if (computeFunction == nil) @@ -538,7 +540,7 @@ FMetalShaderPipeline* FMetalRenderPipelineDesc::CreatePipelineStateForBoundShade statePack.FragmentSource = BSS->PixelShader ? BSS->PixelShader->GlslCodeNSString : nil; #endif - if(GUseRHIThread) + if(IsRunningRHIInSeparateThread()) { SCOPE_CYCLE_COUNTER(STAT_MetalPipelineLockTime); int Err = pthread_rwlock_wrlock(&MetalPipelineMutex.Mutex); @@ -556,7 +558,7 @@ FMetalShaderPipeline* FMetalRenderPipelineDesc::CreatePipelineStateForBoundShade statePack = ExistingPipeline; } - if(GUseRHIThread) + if(IsRunningRHIInSeparateThread()) { SCOPE_CYCLE_COUNTER(STAT_MetalPipelineLockTime); int Err = pthread_rwlock_unlock(&MetalPipelineMutex.Mutex); @@ -583,7 +585,7 @@ FMetalShaderPipeline* FMetalRenderPipelineDesc::CreatePipelineStateForBoundShade return nil; } } - else if(GUseRHIThread) + else if(IsRunningRHIInSeparateThread()) { SCOPE_CYCLE_COUNTER(STAT_MetalPipelineLockTime); int Err = pthread_rwlock_unlock(&MetalPipelineMutex.Mutex); diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalShaders.cpp b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalShaders.cpp index f086cf8a0ac1..04d384aef99d 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalShaders.cpp +++ b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalShaders.cpp @@ -14,6 +14,7 @@ #include "MetalCommandBuffer.h" #include "Serialization/MemoryReader.h" #include "Misc/FileHelper.h" +#include "ScopeRWLock.h" #define SHADERCOMPILERCOMMON_API # include "Developer/ShaderCompilerCommon/Public/ShaderCompilerCommon.h" @@ -56,14 +57,10 @@ struct FMetalCompiledShaderCache public: FMetalCompiledShaderCache() { - int Err = pthread_rwlock_init(&Lock, nullptr); - checkf(Err == 0, TEXT("pthread_rwlock_init failed with error: %d"), Err); } ~FMetalCompiledShaderCache() { - int Err = pthread_rwlock_destroy(&Lock); - checkf(Err == 0, TEXT("pthread_rwlock_destroy failed with error: %d"), Err); for (TPair> Pair : Cache) { [Pair.Value release]; @@ -72,25 +69,19 @@ public: id FindRef(FMetalCompiledShaderKey Key) { - int Err = pthread_rwlock_rdlock(&Lock); - checkf(Err == 0, TEXT("pthread_rwlock_rdlock failed with error: %d"), Err); + FRWScopeLock(Lock, SLT_ReadOnly); id Func = Cache.FindRef(Key); - Err = pthread_rwlock_unlock(&Lock); - checkf(Err == 0, TEXT("pthread_rwlock_unlock failed with error: %d"), Err); return Func; } void Add(FMetalCompiledShaderKey Key, id Function) { - int Err = pthread_rwlock_wrlock(&Lock); - checkf(Err == 0, TEXT("pthread_rwlock_wrlock failed with error: %d"), Err); + FRWScopeLock(Lock, SLT_Write); Cache.Add(Key, Function); - Err = pthread_rwlock_unlock(&Lock); - checkf(Err == 0, TEXT("pthread_rwlock_unlock failed with error: %d"), Err); } private: - pthread_rwlock_t Lock; + FRWLock Lock; TMap> Cache; }; @@ -119,6 +110,9 @@ void TMetalBaseShader::Init(const TArray& I Header = { 0 }; Ar << Header; + SourceLen = Header.SourceLen; + SourceCRC = Header.SourceCRC; + // remember where the header ended and code (precompiled or source) begins int32 CodeOffset = Ar.Tell(); uint32 BufferSize = ShaderCode.GetActualShaderCodeSize() - CodeOffset; @@ -307,7 +301,10 @@ void TMetalBaseShader::Init(const TArray& I // get the header Header = { 0 }; Ar << Header; - + + SourceLen = Header.SourceLen; + SourceCRC = Header.SourceCRC; + // Only archived shaders should be in here. UE_CLOG(!(Header.CompileFlags & (1 << CFLAG_Archive)), LogMetal, Warning, TEXT("Loaded a shader from a library that wasn't marked for archiving.")); { @@ -1047,7 +1044,7 @@ FMetalShaderPipeline* FMetalBoundShaderState::PrepareToDraw(FMetalHashedVertexDe // generate a key for the current statez FMetalRenderPipelineHash PipelineHash = RenderPipelineDesc.GetHash(); - if(GUseRHIThread) + if(IsRunningRHIInSeparateThread()) { SCOPE_CYCLE_COUNTER(STAT_MetalBoundShaderLockTime); int Err = pthread_rwlock_rdlock(&PipelineMutex); @@ -1062,7 +1059,7 @@ FMetalShaderPipeline* FMetalBoundShaderState::PrepareToDraw(FMetalHashedVertexDe PipelineStatePack = Dict->FindRef(VertexDesc); } - if(GUseRHIThread) + if(IsRunningRHIInSeparateThread()) { SCOPE_CYCLE_COUNTER(STAT_MetalBoundShaderLockTime); int Err = pthread_rwlock_unlock(&PipelineMutex); @@ -1075,7 +1072,7 @@ FMetalShaderPipeline* FMetalBoundShaderState::PrepareToDraw(FMetalHashedVertexDe PipelineStatePack = RenderPipelineDesc.CreatePipelineStateForBoundShaderState(this, VertexDesc); check(PipelineStatePack); - if(GUseRHIThread) + if(IsRunningRHIInSeparateThread()) { SCOPE_CYCLE_COUNTER(STAT_MetalBoundShaderLockTime); int Err = pthread_rwlock_wrlock(&PipelineMutex); @@ -1101,7 +1098,7 @@ FMetalShaderPipeline* FMetalBoundShaderState::PrepareToDraw(FMetalHashedVertexDe PipelineStatePack = ExistingPipeline; } - if(GUseRHIThread) + if(IsRunningRHIInSeparateThread()) { SCOPE_CYCLE_COUNTER(STAT_MetalBoundShaderLockTime); int Err = pthread_rwlock_unlock(&PipelineMutex); diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalState.cpp b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalState.cpp index 1013ea124aea..f76b5612dc75 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalState.cpp +++ b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalState.cpp @@ -273,7 +273,7 @@ FCriticalSection FMetalBlendState::Mutex; FMetalBlendState::FMetalBlendState(const FBlendStateInitializerRHI& Initializer) { - for(uint32 RenderTargetIndex = 0;RenderTargetIndex < MaxMetalRenderTargets; ++RenderTargetIndex) + for(uint32 RenderTargetIndex = 0;RenderTargetIndex < MaxSimultaneousRenderTargets; ++RenderTargetIndex) { // which initializer to use const FBlendStateInitializerRHI::FRenderTarget& Init = @@ -306,7 +306,7 @@ FMetalBlendState::FMetalBlendState(const FBlendStateInitializerRHI& Initializer) (BlendState.writeMask << 22); - if(GUseRHIThread) + if(IsRunningRHIInSeparateThread()) { Mutex.Lock(); } @@ -320,7 +320,7 @@ FMetalBlendState::FMetalBlendState(const FBlendStateInitializerRHI& Initializer) } // set the key RenderTargetStates[RenderTargetIndex].BlendStateKey = *Key; - if(GUseRHIThread) + if(IsRunningRHIInSeparateThread()) { Mutex.Unlock(); } @@ -329,7 +329,7 @@ FMetalBlendState::FMetalBlendState(const FBlendStateInitializerRHI& Initializer) FMetalBlendState::~FMetalBlendState() { - for(uint32 RenderTargetIndex = 0;RenderTargetIndex < MaxMetalRenderTargets; ++RenderTargetIndex) + for(uint32 RenderTargetIndex = 0;RenderTargetIndex < MaxSimultaneousRenderTargets; ++RenderTargetIndex) { UNTRACK_OBJECT(STAT_MetalRenderPipelineColorAttachmentDescriptor, RenderTargetStates[RenderTargetIndex].BlendState); [RenderTargetStates[RenderTargetIndex].BlendState release]; diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalStateCache.cpp b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalStateCache.cpp index 5a7ed95b40bb..1c61bcf78387 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalStateCache.cpp +++ b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalStateCache.cpp @@ -107,7 +107,7 @@ FMetalStateCache::FMetalStateCache(bool const bInImmediate) Viewport.originX = Viewport.originY = Viewport.width = Viewport.height = Viewport.znear = Viewport.zfar = 0.0; Scissor.x = Scissor.y = Scissor.width = Scissor.height; - for (uint32 i = 0; i < MaxMetalRenderTargets; i++) + for (uint32 i = 0; i < MaxSimultaneousRenderTargets; i++) { ColorStore[i] = MTLStoreActionUnknown; } @@ -217,7 +217,7 @@ void FMetalStateCache::Reset(void) [RenderPassDesc release]; RenderPassDesc = nil; - for (uint32 i = 0; i < MaxMetalRenderTargets; i++) + for (uint32 i = 0; i < MaxSimultaneousRenderTargets; i++) { ColorStore[i] = MTLStoreActionUnknown; } @@ -290,7 +290,7 @@ void FMetalStateCache::SetBlendState(FMetalBlendState* InBlendState) BlendState = InBlendState; if(InBlendState) { - for(uint32 RenderTargetIndex = 0;RenderTargetIndex < MaxMetalRenderTargets; ++RenderTargetIndex) + for(uint32 RenderTargetIndex = 0;RenderTargetIndex < MaxSimultaneousRenderTargets; ++RenderTargetIndex) { MTLRenderPipelineColorAttachmentDescriptor* Blend = BlendState->RenderTargetStates[RenderTargetIndex].BlendState; MTLRenderPipelineColorAttachmentDescriptor* Dest = [PipelineDesc.PipelineDescriptor.colorAttachments objectAtIndexedSubscript:RenderTargetIndex]; @@ -410,17 +410,18 @@ bool FMetalStateCache::SetRenderTargetsInfo(FRHISetRenderTargetsInfo const& InRe // Deferred store actions make life a bit easier... static bool bSupportsDeferredStore = GetMetalDeviceContext().GetCommandQueue().SupportsFeature(EMetalFeaturesDeferredStoreActions); - - if (bSupportsDeferredStore) + + //Create local store action states if we support deferred store + MTLStoreAction NewColorStore[MaxSimultaneousRenderTargets]; + for (uint32 i = 0; i < MaxSimultaneousRenderTargets; ++i) { - for (uint32 i = 0; i < MaxMetalRenderTargets; i++) - { - ColorStore[i] = MTLStoreActionUnknown; - } - DepthStore = MTLStoreActionUnknown; - StencilStore = MTLStoreActionUnknown; + NewColorStore[i] = MTLStoreActionUnknown; } + MTLStoreAction NewDepthStore = MTLStoreActionUnknown; + MTLStoreAction NewStencilStore = MTLStoreActionUnknown; + + // back this up for next frame RenderTargetsInfo = InRenderTargets; @@ -457,7 +458,7 @@ bool FMetalStateCache::SetRenderTargetsInfo(FRHISetRenderTargetsInfo const& InRe bCanRestartRenderPass = true; - for (uint32 RenderTargetIndex = 0; RenderTargetIndex < MaxMetalRenderTargets; RenderTargetIndex++) + for (uint32 RenderTargetIndex = 0; RenderTargetIndex < MaxSimultaneousRenderTargets; RenderTargetIndex++) { // default to invalid uint8 FormatKey = 0; @@ -533,8 +534,8 @@ bool FMetalStateCache::SetRenderTargetsInfo(FRHISetRenderTargetsInfo const& InRe { // set up an MSAA attachment ColorAttachment.texture = Surface.MSAATexture; - ColorStore[RenderTargetIndex] = MTLStoreActionMultisampleResolve; - ColorAttachment.storeAction = bSupportsDeferredStore ? MTLStoreActionUnknown : ColorStore[RenderTargetIndex]; + NewColorStore[RenderTargetIndex] = MTLStoreActionMultisampleResolve; + ColorAttachment.storeAction = bSupportsDeferredStore ? MTLStoreActionUnknown : NewColorStore[RenderTargetIndex]; ColorAttachment.resolveTexture = Surface.Texture; PipelineDesc.SampleCount = Surface.MSAATexture.sampleCount; @@ -545,8 +546,8 @@ bool FMetalStateCache::SetRenderTargetsInfo(FRHISetRenderTargetsInfo const& InRe { // set up non-MSAA attachment ColorAttachment.texture = Surface.Texture; - ColorStore[RenderTargetIndex] = GetMetalRTStoreAction(RenderTargetView.StoreAction); - ColorAttachment.storeAction = bSupportsDeferredStore ? MTLStoreActionUnknown : ColorStore[RenderTargetIndex]; + NewColorStore[RenderTargetIndex] = GetMetalRTStoreAction(RenderTargetView.StoreAction); + ColorAttachment.storeAction = bSupportsDeferredStore ? MTLStoreActionUnknown : NewColorStore[RenderTargetIndex]; PipelineDesc.SampleCount = 1; } @@ -744,8 +745,8 @@ bool FMetalStateCache::SetRenderTargetsInfo(FRHISetRenderTargetsInfo const& InRe bNeedsClear |= (DepthAttachment.loadAction == MTLLoadActionClear); - DepthStore = GetMetalRTStoreAction(RenderTargetsInfo.DepthStencilRenderTarget.DepthStoreAction); - DepthAttachment.storeAction = bSupportsDeferredStore ? MTLStoreActionUnknown : DepthStore; + NewDepthStore = GetMetalRTStoreAction(RenderTargetsInfo.DepthStencilRenderTarget.DepthStoreAction); + DepthAttachment.storeAction = bSupportsDeferredStore ? MTLStoreActionUnknown : NewDepthStore; DepthAttachment.clearDepth = DepthClearValue; PipelineDesc.PipelineDescriptor.depthAttachmentPixelFormat = DepthAttachment.texture.pixelFormat; @@ -756,7 +757,7 @@ bool FMetalStateCache::SetRenderTargetsInfo(FRHISetRenderTargetsInfo const& InRe bHasValidRenderTarget = true; - bCanRestartRenderPass &= (PipelineDesc.SampleCount <= 1) && ((RenderTargetsInfo.DepthStencilRenderTarget.Texture == FallbackDepthStencilSurface) || ((DepthAttachment.loadAction == MTLLoadActionLoad) && (!RenderTargetsInfo.DepthStencilRenderTarget.GetDepthStencilAccess().IsDepthWrite() || (RenderTargetsInfo.DepthStencilRenderTarget.DepthStoreAction == ERenderTargetStoreAction::EStore)))); + bCanRestartRenderPass &= (PipelineDesc.SampleCount <= 1) && ((RenderTargetsInfo.DepthStencilRenderTarget.Texture == FallbackDepthStencilSurface) || ((DepthAttachment.loadAction == MTLLoadActionLoad) && (!RenderTargetsInfo.DepthStencilRenderTarget.GetDepthStencilAccess().IsDepthWrite() || (RenderTargetsInfo.DepthStencilRenderTarget.DepthStoreAction == ERenderTargetStoreAction::ENoAction) || (RenderTargetsInfo.DepthStencilRenderTarget.DepthStoreAction == ERenderTargetStoreAction::EStore)))); // and assign it RenderPass.depthAttachment = DepthAttachment; @@ -778,8 +779,8 @@ bool FMetalStateCache::SetRenderTargetsInfo(FRHISetRenderTargetsInfo const& InRe bNeedsClear |= (StencilAttachment.loadAction == MTLLoadActionClear); - StencilStore = GetMetalRTStoreAction(RenderTargetsInfo.DepthStencilRenderTarget.GetStencilStoreAction()); - StencilAttachment.storeAction = bSupportsDeferredStore ? MTLStoreActionUnknown : StencilStore; + NewStencilStore = GetMetalRTStoreAction(RenderTargetsInfo.DepthStencilRenderTarget.GetStencilStoreAction()); + StencilAttachment.storeAction = bSupportsDeferredStore ? MTLStoreActionUnknown : NewStencilStore; StencilAttachment.clearStencil = StencilClearValue; PipelineDesc.PipelineDescriptor.stencilAttachmentPixelFormat = StencilAttachment.texture.pixelFormat; @@ -802,6 +803,17 @@ bool FMetalStateCache::SetRenderTargetsInfo(FRHISetRenderTargetsInfo const& InRe } } + //Update deferred store states if required otherwise they're already set directly on the Metal Attachement Descriptors + if (bSupportsDeferredStore) + { + for (uint32 i = 0; i < MaxSimultaneousRenderTargets; ++i) + { + ColorStore[i] = NewColorStore[i]; + } + DepthStore = NewDepthStore; + StencilStore = NewStencilStore; + } + bHasValidRenderTarget |= (InRenderTargets.NumUAVs > 0); if (PipelineDesc.SampleCount == 0) { @@ -1556,16 +1568,6 @@ void FMetalStateCache::SetRenderStoreActions(FMetalCommandEncoder& CommandEncode void FMetalStateCache::SetRenderState(FMetalCommandEncoder& CommandEncoder, FMetalCommandEncoder* PrologueEncoder) { - if (RasterBits & EMetalRenderFlagPipelineState) - { - check(PipelineState); - CommandEncoder.SetRenderPipelineState(PipelineState); - if (PipelineState.ComputePipelineState) - { - check(PrologueEncoder); - PrologueEncoder->SetComputePipelineState(PipelineState); - } - } if (RasterBits & EMetalRenderFlagViewport) { CommandEncoder.SetViewport(Viewport); @@ -1610,6 +1612,17 @@ void FMetalStateCache::SetRenderState(FMetalCommandEncoder& CommandEncoder, FMet { CommandEncoder.SetVisibilityResultMode(VisibilityMode, VisibilityOffset); } + // Some Intel drivers need RenderPipeline state to be set after DepthStencil state to work properly + if (RasterBits & EMetalRenderFlagPipelineState) + { + check(PipelineState); + CommandEncoder.SetRenderPipelineState(PipelineState); + if (PipelineState.ComputePipelineState) + { + check(PrologueEncoder); + PrologueEncoder->SetComputePipelineState(PipelineState); + } + } RasterBits = 0; } diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalStateCache.h b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalStateCache.h index f91e70762e12..e9ba44fafa24 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalStateCache.h +++ b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalStateCache.h @@ -220,7 +220,7 @@ private: FMetalTextureBindings ShaderTextures[SF_NumFrequencies]; FMetalSamplerBindings ShaderSamplers[SF_NumFrequencies]; - MTLStoreAction ColorStore[MaxMetalRenderTargets]; + MTLStoreAction ColorStore[MaxSimultaneousRenderTargets]; MTLStoreAction DepthStore; MTLStoreAction StencilStore; diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalTexture.cpp b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalTexture.cpp index 8bbe79204660..602ad3a4cc49 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalTexture.cpp +++ b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalTexture.cpp @@ -889,13 +889,14 @@ FMetalSurface::FMetalSurface(ERHIResourceType ResourceType, EPixelFormat Format, #else Desc.cpuCacheMode = MTLCPUCacheModeDefaultCache; // No private storage for PVRTC as it messes up the blit-encoder usage. - if (MTLFormat >= MTLPixelFormatPVRTC_RGB_2BPP && MTLFormat <= MTLPixelFormatPVRTC_RGBA_4BPP_sRGB) + // note: this is set to always be on for 4.16 and will be re-addressed in 4.17 + if (PLATFORM_IOS) { - Desc.storageMode = MTLStorageModeShared; - Desc.resourceOptions = MTLResourceCPUCacheModeDefaultCache|MTLResourceStorageModeShared; - } + Desc.storageMode = MTLStorageModeShared; + Desc.resourceOptions = MTLResourceCPUCacheModeDefaultCache|MTLResourceStorageModeShared; + } else - { + { Desc.storageMode = MTLStorageModePrivate; Desc.resourceOptions = MTLResourceCPUCacheModeDefaultCache|MTLResourceStorageModePrivate; } @@ -1481,7 +1482,7 @@ void FMetalSurface::AsyncUnlock(class FRHICommandListImmediate& RHICmdList, uint bool bDoDirectUnlock = Params.bDirectLock; const bool bUnlockForCreate = Params.bCreateLock; - if (RHICmdList.Bypass() || !GRHIThread || bDoDirectUnlock) + if (RHICmdList.Bypass() || !IsRunningRHIInSeparateThread() || bDoDirectUnlock) { if (bDoDirectUnlock) { @@ -1755,53 +1756,54 @@ struct FMetalRHICommandAsyncReallocateTexture2D : public FRHICommandGetNumMips(), NewTexture->GetNumMips()); - const uint32 SourceMipOffset = OldTexture->GetNumMips() - NumSharedMips; - const uint32 DestMipOffset = NewTexture->GetNumMips() - NumSharedMips; - - const uint32 BlockSizeX = GPixelFormats[OldTexture->GetFormat()].BlockSizeX; - const uint32 BlockSizeY = GPixelFormats[OldTexture->GetFormat()].BlockSizeY; - - // only handling straight 2D textures here - uint32 SliceIndex = 0; - MTLOrigin Origin = MTLOriginMake(0,0,0); - - id Tex = OldTexture->Surface.Texture; - [Tex retain]; - - // DXT/BC formats on Mac actually do have mip-tails that are smaller than the block size, they end up being uncompressed. - bool const bPixelFormatASTC = IsPixelFormatASTCCompressed(OldTexture->GetFormat()); - - for (uint32 MipIndex = 0; MipIndex < NumSharedMips; ++MipIndex) { + // figure out what mips to schedule + const uint32 NumSharedMips = FMath::Min(OldTexture->GetNumMips(), NewTexture->GetNumMips()); + const uint32 SourceMipOffset = OldTexture->GetNumMips() - NumSharedMips; + const uint32 DestMipOffset = NewTexture->GetNumMips() - NumSharedMips; + + const uint32 BlockSizeX = GPixelFormats[OldTexture->GetFormat()].BlockSizeX; + const uint32 BlockSizeY = GPixelFormats[OldTexture->GetFormat()].BlockSizeY; + + // only handling straight 2D textures here + uint32 SliceIndex = 0; + MTLOrigin Origin = MTLOriginMake(0,0,0); + + id Tex = OldTexture->Surface.Texture; + [Tex retain]; + + // DXT/BC formats on Mac actually do have mip-tails that are smaller than the block size, they end up being uncompressed. + bool const bPixelFormatASTC = IsPixelFormatASTCCompressed(OldTexture->GetFormat()); + + for (uint32 MipIndex = 0; MipIndex < NumSharedMips; ++MipIndex) + { const uint32 UnalignedMipSizeX = FMath::Max(1, NewSizeX >> (MipIndex + DestMipOffset)); const uint32 UnalignedMipSizeY = FMath::Max(1, NewSizeY >> (MipIndex + DestMipOffset)); const uint32 MipSizeX = (bPixelFormatASTC) ? AlignArbitrary(UnalignedMipSizeX, BlockSizeX) : UnalignedMipSizeX; const uint32 MipSizeY = (bPixelFormatASTC) ? AlignArbitrary(UnalignedMipSizeY, BlockSizeY) : UnalignedMipSizeY; Context.AsyncCopyFromTextureToTexture(OldTexture->Surface.Texture, SliceIndex, MipIndex + SourceMipOffset, Origin, MTLSizeMake(MipSizeX, MipSizeY, 1), NewTexture->Surface.Texture, SliceIndex, MipIndex + DestMipOffset, Origin); - } + } - // when done, decrement the counter to indicate it's safe + // when done, decrement the counter to indicate it's safe MTLCommandBufferHandler CompletionHandler = ^(id Buffer) - { - [Tex release]; - RequestStatus->Decrement(); + { + [Tex release]; }; - // kick it off! + // kick it off! Context.SubmitAsyncCommands(nil, CompletionHandler, false); + + RequestStatus->Decrement(); } }; @@ -1810,7 +1812,7 @@ FTexture2DRHIRef FMetalDynamicRHI::AsyncReallocateTexture2D_RenderThread(class F @autoreleasepool { FTexture2DRHIRef Result; - if (RHICmdList.Bypass() || !GRHIThread) + if (RHICmdList.Bypass() || !IsRunningRHIInSeparateThread()) { Result = GDynamicRHI->RHIAsyncReallocateTexture2D(Texture2D, NewMipCount, NewSizeX, NewSizeY, RequestStatus); } @@ -1978,7 +1980,7 @@ struct FMetalRHICommandUpdateTexture2D : public FRHICommandRHIUpdateTexture2D(Texture, MipIndex, UpdateRegion, SourcePitch, SourceData); } @@ -2363,7 +2365,7 @@ void FMetalDynamicRHI::RHISetResourceAliasability_RenderThread(class FRHICommand } case EResourceAliasability::EUnaliasable: { - if (RHICmdList.Bypass() || !GRHIThread) + if (RHICmdList.Bypass() || !IsRunningRHIInSeparateThread()) { for (int32 i = 0; i < NumTextures; ++i) { diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalUniformBuffer.cpp b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalUniformBuffer.cpp index a6b9d79fef02..7f850d939356 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalUniformBuffer.cpp +++ b/Engine/Source/Runtime/Apple/MetalRHI/Private/MetalUniformBuffer.cpp @@ -100,7 +100,7 @@ void InitFrame_UniformBufferPoolCleanup() SCOPE_CYCLE_COUNTER(STAT_MetalUniformBufferCleanupTime); - if(GUseRHIThread) + if(IsRunningRHIInSeparateThread()) { GMutex.Lock(); } @@ -125,7 +125,7 @@ void InitFrame_UniformBufferPoolCleanup() SafeUniformBufferPools[SafeFrameIndex][BucketIndex].Reset(); } - if(GUseRHIThread) + if(IsRunningRHIInSeparateThread()) { GMutex.Unlock(); } @@ -135,7 +135,7 @@ void AddNewlyFreedBufferToUniformBufferPool(id Buffer, uint32 Offset, { check(Buffer); - if(GUseRHIThread) + if(IsRunningRHIInSeparateThread()) { GMutex.Lock(); } @@ -154,7 +154,7 @@ void AddNewlyFreedBufferToUniformBufferPool(id Buffer, uint32 Offset, INC_DWORD_STAT(STAT_MetalNumFreeUniformBuffers); INC_MEMORY_STAT_BY(STAT_MetalFreeUniformBufferMemory, Buffer.length); - if(GUseRHIThread) + if(IsRunningRHIInSeparateThread()) { GMutex.Unlock(); } @@ -196,7 +196,7 @@ FMetalUniformBuffer::FMetalUniformBuffer(const void* Contents, const FRHIUniform else { // for single use buffers, allocate from the ring buffer to avoid thrashing memory - if (Usage == UniformBuffer_SingleDraw && !GUseRHIThread) // @todo Make this properly RHIThread safe. + if (Usage == UniformBuffer_SingleDraw && !IsRunningRHIInSeparateThread()) // @todo Make this properly RHIThread safe. { // use a bit of the ring buffer Offset = GetMetalDeviceContext().AllocateFromRingBuffer(Layout.ConstantBufferSize); @@ -205,7 +205,7 @@ FMetalUniformBuffer::FMetalUniformBuffer(const void* Contents, const FRHIUniform else { // Find the appropriate bucket based on size - if(GUseRHIThread) + if(IsRunningRHIInSeparateThread()) { GMutex.Lock(); } @@ -237,7 +237,7 @@ FMetalUniformBuffer::FMetalUniformBuffer(const void* Contents, const FRHIUniform } #endif - if(GUseRHIThread) + if(IsRunningRHIInSeparateThread()) { GMutex.Unlock(); } @@ -279,7 +279,7 @@ FMetalUniformBuffer::~FMetalUniformBuffer() INC_DWORD_STAT_BY(STAT_MetalUniformMemFreed, Size); // don't need to free the ring buffer! - if (GIsRHIInitialized && Buffer != nil && !(Usage == UniformBuffer_SingleDraw && !GUseRHIThread)) + if (GIsRHIInitialized && Buffer != nil && !(Usage == UniformBuffer_SingleDraw && !IsRunningRHIInSeparateThread())) { check(Size <= 65536); AddNewlyFreedBufferToUniformBufferPool(Buffer, Offset, Size); diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Public/MetalResources.h b/Engine/Source/Runtime/Apple/MetalRHI/Public/MetalResources.h index 4949fc11a664..676472de0fb5 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Public/MetalResources.h +++ b/Engine/Source/Runtime/Apple/MetalRHI/Public/MetalResources.h @@ -73,6 +73,8 @@ public: , Library(nil) , SideTableBinding(-1) , GlslCodeNSString(nil) + , SourceLen(0) + , SourceCRC(0) { } @@ -112,6 +114,10 @@ public: /** The debuggable text source */ NSString* GlslCodeNSString; + + /** CRC & Len for name disambiguation */ + uint32 SourceLen; + uint32 SourceCRC; }; class FMetalVertexShader : public TMetalBaseShader diff --git a/Engine/Source/Runtime/Apple/MetalRHI/Public/MetalState.h b/Engine/Source/Runtime/Apple/MetalRHI/Public/MetalState.h index 2111bdf5d85f..21b031237013 100644 --- a/Engine/Source/Runtime/Apple/MetalRHI/Public/MetalState.h +++ b/Engine/Source/Runtime/Apple/MetalRHI/Public/MetalState.h @@ -67,7 +67,7 @@ public: MTLRenderPipelineColorAttachmentDescriptor* BlendState; uint8 BlendStateKey; }; - FBlendPerMRT RenderTargetStates[MaxMetalRenderTargets]; + FBlendPerMRT RenderTargetStates[MaxSimultaneousRenderTargets]; private: // this tracks blend settings (in a bit flag) into a unique key that uses few bits, for PipelineState MRT setup diff --git a/Engine/Source/Runtime/AssetRegistry/Private/AssetBundleData.cpp b/Engine/Source/Runtime/AssetRegistry/Private/AssetBundleData.cpp index da430b1d58f6..04d932da9aeb 100644 --- a/Engine/Source/Runtime/AssetRegistry/Private/AssetBundleData.cpp +++ b/Engine/Source/Runtime/AssetRegistry/Private/AssetBundleData.cpp @@ -8,6 +8,9 @@ bool FAssetBundleData::SetFromAssetData(const FAssetData& AssetData) { FString TagValue; + // Register that we're reading string assets for a specific package + FStringAssetReferenceSerializationScope SerializationScope(AssetData.PackageName, FAssetBundleData::StaticStruct()->GetFName(), EStringAssetReferenceCollectType::AlwaysCollect); + if (AssetData.GetTagValue(FAssetBundleData::StaticStruct()->GetFName(), TagValue)) { if (FAssetBundleData::StaticStruct()->ImportText(*TagValue, this, nullptr, PPF_None, (FOutputDevice*)GWarn, AssetData.AssetName.ToString())) @@ -77,7 +80,41 @@ void FAssetBundleData::AddBundleAssets(FName BundleName, const TArray&& AssetPaths) +{ + FAssetBundleEntry* FoundEntry = FindEntry(FPrimaryAssetId(), BundleName); + + if (!FoundEntry) + { + FoundEntry = new(Bundles) FAssetBundleEntry(FPrimaryAssetId(), BundleName); + } + + FoundEntry->BundleAssets = AssetPaths; +} + void FAssetBundleData::Reset() { Bundles.Reset(); +} + +bool FAssetBundleData::ExportTextItem(FString& ValueStr, FAssetBundleData const& DefaultValue, UObject* Parent, int32 PortFlags, UObject* ExportRootScope) const +{ + if (Bundles.Num() == 0) + { + // Empty, don't write anything to avoid it cluttering the asset registry tags + return true; + } + // Not empty, do normal export + return false; +} + +bool FAssetBundleData::ImportTextItem(const TCHAR*& Buffer, int32 PortFlags, UObject* Parent, FOutputDevice* ErrorText) +{ + if (*Buffer != TEXT('(')) + { + // Empty, don't read/write anything + return true; + } + // Full structure, do normal parse + return false; } \ No newline at end of file diff --git a/Engine/Source/Runtime/AssetRegistry/Private/AssetData.cpp b/Engine/Source/Runtime/AssetRegistry/Private/AssetData.cpp index 91ee8f803995..fdff22ab3fd5 100644 --- a/Engine/Source/Runtime/AssetRegistry/Private/AssetData.cpp +++ b/Engine/Source/Runtime/AssetRegistry/Private/AssetData.cpp @@ -1,5 +1,42 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "AssetData.h" +#include "Serialization/CustomVersion.h" DEFINE_LOG_CATEGORY(LogAssetData); + +// Register Asset Registry version +const FGuid FAssetRegistryVersion::GUID(0x717F9EE7, 0xE9B0493A, 0x88B39132, 0x1B388107); +FCustomVersionRegistration GRegisterAssetRegistryVersion(FAssetRegistryVersion::GUID, FAssetRegistryVersion::LatestVersion, TEXT("AssetRegistry")); + +bool FAssetRegistryVersion::SerializeVersion(FArchive& Ar, FAssetRegistryVersion::Type& Version) +{ + FGuid Guid = FAssetRegistryVersion::GUID; + + if (Ar.IsLoading()) + { + Version = FAssetRegistryVersion::PreVersioning; + } + + Ar << Guid; + + if (Ar.IsError()) + { + return false; + } + + if (Guid == FAssetRegistryVersion::GUID) + { + int32 VersionInt = Version; + Ar << VersionInt; + Version = (FAssetRegistryVersion::Type)VersionInt; + + Ar.SetCustomVersion(Guid, VersionInt, TEXT("AssetRegistry")); + } + else + { + return false; + } + + return !Ar.IsError(); +} \ No newline at end of file diff --git a/Engine/Source/Runtime/AssetRegistry/Private/AssetDataGatherer.cpp b/Engine/Source/Runtime/AssetRegistry/Private/AssetDataGatherer.cpp index 3bbd6a061a5e..350729f19211 100644 --- a/Engine/Source/Runtime/AssetRegistry/Private/AssetDataGatherer.cpp +++ b/Engine/Source/Runtime/AssetRegistry/Private/AssetDataGatherer.cpp @@ -13,13 +13,12 @@ namespace AssetDataGathererConstants { - static const int32 CacheSerializationVersion = 9; + static const int32 CacheSerializationVersion = 10; static const int32 MaxFilesToDiscoverBeforeFlush = 2500; static const int32 MaxFilesToGatherBeforeFlush = 250; static const int32 MaxFilesToProcessBeforeCacheWrite = 50000; } - namespace { class FLambdaDirectoryStatVisitor : public IPlatformFile::FDirectoryStatVisitor @@ -387,7 +386,7 @@ FAssetDataGatherer::FAssetDataGatherer(const TArray& InPaths, const TAr , bFinishedInitialDiscovery( false ) , Thread(nullptr) { - bGatherDependsData = GIsEditor && !FParse::Param( FCommandLine::Get(), TEXT("NoDependsGathering") ); + bGatherDependsData = (GIsEditor && !FParse::Param( FCommandLine::Get(), TEXT("NoDependsGathering") )) || FParse::Param(FCommandLine::Get(),TEXT("ForceDependsGathering")) ; if (FParse::Param(FCommandLine::Get(), TEXT("NoAssetRegistryCache")) || FParse::Param(FCommandLine::Get(), TEXT("multiprocess"))) { @@ -453,21 +452,20 @@ uint32 FAssetDataGatherer::Run() { int32 CacheSerializationVersion = AssetDataGathererConstants::CacheSerializationVersion; - static const bool bUsingWorldAssets = FAssetRegistry::IsUsingWorldAssets(); - if ( bUsingWorldAssets ) - { - // Bump the serialization version to refresh the cache when switching between -WorldAssets and without. - // This is a temporary hack just while WorldAssets are under development - CacheSerializationVersion++; - } - if ( bLoadAndSaveCache ) { // load the cached data FNameTableArchiveReader CachedAssetDataReader(CacheSerializationVersion, CacheFilename); if (!CachedAssetDataReader.IsError()) { - SerializeCache(CachedAssetDataReader); + FAssetRegistryVersion::Type Version = FAssetRegistryVersion::LatestVersion; + if (FAssetRegistryVersion::SerializeVersion(CachedAssetDataReader, Version)) + { + SerializeCache(CachedAssetDataReader); + + DependencyResults.Reserve(DiskCachedAssetDataMap.Num()); + AssetResults.Reserve(DiskCachedAssetDataMap.Num()); + } } } @@ -484,6 +482,10 @@ uint32 FAssetDataGatherer::Run() auto WriteAssetCacheFile = [&]() { FNameTableArchiveWriter CachedAssetDataWriter(CacheSerializationVersion, CacheFilename); + + FAssetRegistryVersion::Type Version = FAssetRegistryVersion::LatestVersion; + FAssetRegistryVersion::SerializeVersion(CachedAssetDataWriter, Version); + SerializeCache(CachedAssetDataWriter); NumFilesProcessedSinceLastCacheSave = 0; @@ -727,7 +729,7 @@ void FAssetDataGatherer::EnsureCompletion() } } -bool FAssetDataGatherer::GetAndTrimSearchResults(TArray& OutAssetResults, TArray& OutPathResults, TArray& OutDependencyResults, TArray& OutCookedPackageNamesWithoutAssetDataResults, TArray& OutSearchTimes, int32& OutNumFilesToSearch, int32& OutNumPathsToSearch, bool& OutIsDiscoveringFiles) +bool FAssetDataGatherer::GetAndTrimSearchResults(TBackgroundGatherResults& OutAssetResults, TBackgroundGatherResults& OutPathResults, TBackgroundGatherResults& OutDependencyResults, TBackgroundGatherResults& OutCookedPackageNamesWithoutAssetDataResults, TArray& OutSearchTimes, int32& OutNumFilesToSearch, int32& OutNumPathsToSearch, bool& OutIsDiscoveringFiles) { FScopeLock CritSectionLock(&WorkerThreadCriticalSection); @@ -880,11 +882,10 @@ void FAssetDataGatherer::SerializeCache(FArchive& Ar) if (Ar.IsSaving()) { // save out by walking the TMap - for (auto CacheIt = NewCachedAssetDataMap.CreateConstIterator(); CacheIt; ++CacheIt) + for (TPair& Pair : NewCachedAssetDataMap) { - FName PackageName = CacheIt.Key(); - Ar << PackageName; - Ar << *CacheIt.Value(); + Ar << Pair.Key; + Pair.Value->SerializeForCache(Ar); } } else @@ -907,7 +908,7 @@ void FAssetDataGatherer::SerializeCache(FArchive& Ar) FDiskCachedAssetData& CachedAssetData = DiskCachedAssetDataMap.Add(PackageName); // Now load the data - Ar << CachedAssetData; + CachedAssetData.SerializeForCache(Ar); if (Ar.IsError()) { diff --git a/Engine/Source/Runtime/AssetRegistry/Private/AssetDataGatherer.h b/Engine/Source/Runtime/AssetRegistry/Private/AssetDataGatherer.h index e74a97bae772..c4d04fb0f6cb 100644 --- a/Engine/Source/Runtime/AssetRegistry/Private/AssetDataGatherer.h +++ b/Engine/Source/Runtime/AssetRegistry/Private/AssetDataGatherer.h @@ -7,7 +7,8 @@ #include "PackageDependencyData.h" #include "HAL/FileManager.h" #include "HAL/Runnable.h" -#include "Runtime/AssetRegistry/Private/DiskCachedAssetData.h" +#include "DiskCachedAssetData.h" +#include "BackgroundGatherResults.h" /** * Minimal amount of information needed about a discovered asset file @@ -168,7 +169,7 @@ public: void EnsureCompletion(); /** Gets search results from the data gatherer */ - bool GetAndTrimSearchResults(TArray& OutAssetResults, TArray& OutPathResults, TArray& OutDependencyResults, TArray& OutCookedPackageNamesWithoutAssetDataResults, TArray& OutSearchTimes, int32& OutNumFilesToSearch, int32& OutNumPathsToSearch, bool& OutIsDiscoveringFiles); + bool GetAndTrimSearchResults(TBackgroundGatherResults& OutAssetResults, TBackgroundGatherResults& OutPathResults, TBackgroundGatherResults& OutDependencyResults, TBackgroundGatherResults& OutCookedPackageNamesWithoutAssetDataResults, TArray& OutSearchTimes, int32& OutNumFilesToSearch, int32& OutNumPathsToSearch, bool& OutIsDiscoveringFiles); /** Adds a root path to the search queue. Only works when searching asynchronously */ void AddPathToSearch(const FString& Path); diff --git a/Engine/Source/Runtime/AssetRegistry/Private/AssetRegistry.cpp b/Engine/Source/Runtime/AssetRegistry/Private/AssetRegistry.cpp index cb864d0b09d6..33290ae3f8c3 100644 --- a/Engine/Source/Runtime/AssetRegistry/Private/AssetRegistry.cpp +++ b/Engine/Source/Runtime/AssetRegistry/Private/AssetRegistry.cpp @@ -1,6 +1,5 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - #include "AssetRegistry.h" #include "Misc/CommandLine.h" #include "Misc/FileHelper.h" @@ -16,6 +15,9 @@ #include "PackageReader.h" #include "GenericPlatform/GenericPlatformChunkInstall.h" #include "IPluginManager.h" +#include "Misc/CoreDelegates.h" +#include "UObject/ConstructorHelpers.h" +#include "Misc/RedirectCollector.h" #if WITH_EDITOR #include "IDirectoryWatcher.h" @@ -110,8 +112,8 @@ FAssetRegistry::FAssetRegistry() UE_LOG(LogAssetRegistry, Log, TEXT( "FAssetRegistry took %0.4f seconds to start up" ), FPlatformTime::Seconds() - StartupStartTime ); #if WITH_EDITOR - // Commandlets and in-game don't listen for directory changes - if ( !IsRunningCommandlet() && GIsEditor) + // In-game doesn't listen for directory changes + if (GIsEditor) { FDirectoryWatcherModule& DirectoryWatcherModule = FModuleManager::LoadModuleChecked(TEXT("DirectoryWatcher")); IDirectoryWatcher* DirectoryWatcher = DirectoryWatcherModule.Get(); @@ -150,8 +152,11 @@ FAssetRegistry::FAssetRegistry() // Listen for new content paths being added or removed at runtime. These are usually plugin-specific asset paths that // will be loaded a bit later on. - FPackageName::OnContentPathMounted().AddRaw( this, &FAssetRegistry::OnContentPathMounted ); - FPackageName::OnContentPathDismounted().AddRaw( this, &FAssetRegistry::OnContentPathDismounted ); + FPackageName::OnContentPathMounted().AddRaw(this, &FAssetRegistry::OnContentPathMounted); + FPackageName::OnContentPathDismounted().AddRaw(this, &FAssetRegistry::OnContentPathDismounted); + + // If we were called before engine has fully initialized, refresh classes on initialize. If not this won't do anything as it already happened + FCoreDelegates::OnPostEngineInit.AddRaw(this, &FAssetRegistry::RefreshNativeClasses); } void FAssetRegistry::InitializeSerializationOptions(FAssetRegistrySerializationOptions& Options, const FString& PlatformIniName) const @@ -168,6 +173,7 @@ void FAssetRegistry::InitializeSerializationOptions(FAssetRegistrySerializationO PlatformEngineIni.GetBool(TEXT("AssetRegistry"), TEXT("bSerializeManageDependencies"), Options.bSerializeManageDependencies); PlatformEngineIni.GetBool(TEXT("AssetRegistry"), TEXT("bSerializePackageData"), Options.bSerializePackageData); PlatformEngineIni.GetBool(TEXT("AssetRegistry"), TEXT("bUseAssetRegistryTagsWhitelistInsteadOfBlacklist"), Options.bUseAssetRegistryTagsWhitelistInsteadOfBlacklist); + PlatformEngineIni.GetBool(TEXT("AssetRegistry"), TEXT("bFilterAssetDataWithNoTags"), Options.bFilterAssetDataWithNoTags); TArray FilterlistItems; if (Options.bUseAssetRegistryTagsWhitelistInsteadOfBlacklist) @@ -265,6 +271,15 @@ void FAssetRegistry::CollectCodeGeneratorClasses() } } +void FAssetRegistry::RefreshNativeClasses() +{ + // Native classes have changed so reinitialize code generator and serialization options + CollectCodeGeneratorClasses(); + + // Read default serialization options + InitializeSerializationOptions(SerializationOptions); +} + FAssetRegistry::~FAssetRegistry() { // Make sure the asset search thread is closed @@ -275,12 +290,12 @@ FAssetRegistry::~FAssetRegistry() } // Stop listening for content mount point events - FPackageName::OnContentPathMounted().RemoveAll( this ); - FPackageName::OnContentPathDismounted().RemoveAll( this ); + FPackageName::OnContentPathMounted().RemoveAll(this); + FPackageName::OnContentPathDismounted().RemoveAll(this); + FCoreDelegates::OnPostEngineInit.RemoveAll(this); - // Commandlets dont listen for directory changes #if WITH_EDITOR - if ( !IsRunningCommandlet() && GIsEditor ) + if (GIsEditor) { // If the directory module is still loaded, unregister any delegates if ( FModuleManager::Get().IsModuleLoaded("DirectoryWatcher") ) @@ -335,6 +350,14 @@ void FAssetRegistry::SearchAllAssets(bool bSynchronousSearch) { const bool bForceRescan = false; ScanPathsAndFilesSynchronous(PathsToSearch, TArray(), bForceRescan, EAssetDataCacheMode::UseMonolithicCache); + +#if WITH_EDITOR + if (IsRunningCommandlet()) + { + // Update redirectors + UpdateRedirectCollector(); + } +#endif } else if ( !BackgroundAssetSearch.IsValid() ) { @@ -343,6 +366,27 @@ void FAssetRegistry::SearchAllAssets(bool bSynchronousSearch) } } +bool FAssetRegistry::HasAssets(const FName PackagePath, const bool bRecursive) const +{ + bool bHasAssets = State.HasAssets(PackagePath); + + if (!bHasAssets && bRecursive) + { + TSet SubPaths; + CachedPathTree.GetSubPaths(PackagePath, SubPaths); + + for (const FName& SubPath : SubPaths) + { + bHasAssets = State.HasAssets(SubPath); + if (bHasAssets) + { + break; + } + } + } + + return bHasAssets; +} bool FAssetRegistry::GetAssetsByPackageName(FName PackageName, TArray& OutAssetData, bool bIncludeOnlyOnDiskAssets ) const { @@ -484,19 +528,18 @@ bool FAssetRegistry::GetAssets(const FARFilter& InFilter, TArray& Ou } } - // Find the group names - FString GroupNamesStr; - FString AssetNameStr; - Obj->GetPathName(InMemoryPackage).Split(TEXT("."), &GroupNamesStr, &AssetNameStr, ESearchCase::CaseSensitive, ESearchDir::FromEnd); - - TMap TagMap; + FAssetDataTagMap TagMap; for (UObject::FAssetRegistryTag& AssetRegistryTag : ObjectTags) { - TagMap.Add(AssetRegistryTag.Name, AssetRegistryTag.Value); + if (AssetRegistryTag.Name != NAME_None && !AssetRegistryTag.Value.IsEmpty()) + { + // Don't add empty tags + TagMap.Add(AssetRegistryTag.Name, AssetRegistryTag.Value); + } } // This asset is in memory and passes all filters - FAssetData* AssetData = new (OutAssetData)FAssetData(PackageName, PackagePath, FName(*GroupNamesStr), Obj->GetFName(), Obj->GetClass()->GetFName(), TagMap, InMemoryPackage->GetChunkIDs(), InMemoryPackage->GetPackageFlags()); + FAssetData* AssetData = new (OutAssetData)FAssetData(PackageName, PackagePath, Obj->GetFName(), Obj->GetClass()->GetFName(), TagMap, InMemoryPackage->GetChunkIDs(), InMemoryPackage->GetPackageFlags()); } }; @@ -633,6 +676,40 @@ const FAssetPackageData* FAssetRegistry::GetAssetPackageData(FName PackageName) return State.GetAssetPackageData(PackageName); } +FName FAssetRegistry::GetRedirectedObjectPath(const FName ObjectPath) const +{ + FString RedirectedPath = ObjectPath.ToString(); + FAssetData DestinationData = GetAssetByObjectPath(ObjectPath); + TSet SeenPaths; + SeenPaths.Add(RedirectedPath); + + // Need to follow chain of redirectors + while (DestinationData.IsRedirector()) + { + if (DestinationData.GetTagValue("DestinationObject", RedirectedPath)) + { + ConstructorHelpers::StripObjectClass(RedirectedPath); + if (SeenPaths.Contains(RedirectedPath)) + { + // Recursive, bail + DestinationData = FAssetData(); + } + else + { + SeenPaths.Add(RedirectedPath); + DestinationData = GetAssetByObjectPath(FName(*RedirectedPath), true); + } + } + else + { + // Can't extract + DestinationData = FAssetData(); + } + } + + return FName(*RedirectedPath); +} + bool FAssetRegistry::GetAncestorClassNames(FName ClassName, TArray& OutAncestorClassNames) const { // Start with the cached inheritance map @@ -1045,19 +1122,14 @@ void FAssetRegistry::PrioritizeSearchPath(const FString& PathToPrioritize) } // Also prioritize the queue of background search results + BackgroundAssetResults.Prioritize([&PathToPrioritize](const FAssetData* BackgroundAssetResult) { - // Swap all priority files to the top of the list - int32 LowestNonPriorityFileIdx = 0; - for (int32 ResultIdx = 0; ResultIdx < BackgroundAssetResults.Num(); ++ResultIdx) - { - FAssetData* BackgroundAssetResult = BackgroundAssetResults[ResultIdx]; - if (BackgroundAssetResult && BackgroundAssetResult->PackagePath.ToString().StartsWith(PathToPrioritize)) - { - BackgroundAssetResults.Swap(ResultIdx, LowestNonPriorityFileIdx); - LowestNonPriorityFileIdx++; - } - } - } + return BackgroundAssetResult && BackgroundAssetResult->PackagePath.ToString().StartsWith(PathToPrioritize); + }); + BackgroundPathResults.Prioritize([&PathToPrioritize](const FString& BackgroundPathResult) + { + return BackgroundPathResult.StartsWith(PathToPrioritize); + }); } void FAssetRegistry::AssetCreated(UObject* NewAsset) @@ -1114,8 +1186,18 @@ void FAssetRegistry::AssetDeleted(UObject* DeletedAsset) } } + FAssetData AssetDataDeleted = FAssetData(DeletedAsset); + +#if WITH_EDITOR + if (bInitialSearchCompleted && AssetDataDeleted.IsRedirector()) + { + // Need to remove from GRedirectCollector + GRedirectCollector.RemoveAssetPathRedirection(AssetDataDeleted.ObjectPath.ToString()); + } +#endif + // Let subscribers know that the asset was removed from the registry - AssetRemovedEvent.Broadcast(FAssetData(DeletedAsset)); + AssetRemovedEvent.Broadcast(AssetDataDeleted); // Notify listeners that an in-memory asset was just deleted InMemoryAssetDeletedEvent.Broadcast(DeletedAsset); @@ -1199,6 +1281,12 @@ void FAssetRegistry::Tick(float DeltaTime) { double TickStartTime = FPlatformTime::Seconds(); + if (DeltaTime < 0) + { + // Force a full flush + TickStartTime = -1; + } + // Gather results from the background search bool bIsSearching = false; TArray SearchTimes; @@ -1270,6 +1358,10 @@ void FAssetRegistry::Tick(float DeltaTime) { if ( !bInitialSearchCompleted ) { +#if WITH_EDITOR + // update redirectors + UpdateRedirectCollector(); +#endif UE_LOG(LogAssetRegistry, Verbose, TEXT("### Time spent amortizing search results: %0.4f seconds"), TotalAmortizeTime); UE_LOG(LogAssetRegistry, Log, TEXT("Asset discovery search completed in %0.4f seconds"), FPlatformTime::Seconds() - FullSearchStartTime); @@ -1286,7 +1378,6 @@ void FAssetRegistry::Tick(float DeltaTime) } } - bool FAssetRegistry::IsUsingWorldAssets() { return !FParse::Param(FCommandLine::Get(), TEXT("DisableWorldAssets")); @@ -1311,6 +1402,22 @@ void FAssetRegistry::Serialize(FArchive& Ar) } } +uint32 FAssetRegistry::GetAllocatedSize(bool bLogDetailed) const +{ + uint32 StateSize = State.GetAllocatedSize(bLogDetailed); + + uint32 StaticSize = sizeof(FAssetRegistry) + CachedEmptyPackages.GetAllocatedSize() + CachedInheritanceMap.GetAllocatedSize() + EditSearchableNameDelegates.GetAllocatedSize() + ClassGeneratorNames.GetAllocatedSize() + SerializationOptions.CookFilterlistTagsByClass.GetAllocatedSize(); + uint32 SearchSize = BackgroundAssetResults.GetAllocatedSize() + BackgroundPathResults.GetAllocatedSize() + BackgroundDependencyResults.GetAllocatedSize() + BackgroundCookedPackageNamesWithoutAssetDataResults.GetAllocatedSize() + SynchronouslyScannedPathsAndFiles.GetAllocatedSize() + CachedPathTree.GetAllocatedSize(); + + if (bLogDetailed) + { + UE_LOG(LogAssetRegistry, Log, TEXT("AssetRegistry Static Size: %dk"), StaticSize / 1024); + UE_LOG(LogAssetRegistry, Log, TEXT("AssetRegistry Search Size: %dk"), SearchSize / 1024); + } + + return StaticSize + StaticSize + SearchSize; +} + void FAssetRegistry::LoadPackageRegistryData(FArchive& Ar, TArray &AssetDataList ) const { @@ -1330,7 +1437,7 @@ void FAssetRegistry::LoadPackageRegistryData(FArchive& Ar, TArray & void FAssetRegistry::SaveRegistryData(FArchive& Ar, TMap& Data, TArray* InMaps /* = nullptr */) { FAssetRegistryState TempState; - InitializeTemporaryAssetRegistryState(TempState, SerializationOptions, Data); + InitializeTemporaryAssetRegistryState(TempState, SerializationOptions, false, Data); TempState.Serialize(Ar, SerializationOptions); } @@ -1357,11 +1464,11 @@ void FAssetRegistry::LoadRegistryData(FArchive& Ar, TMap& Da } } -void FAssetRegistry::InitializeTemporaryAssetRegistryState(FAssetRegistryState& OutState, const FAssetRegistrySerializationOptions& Options, const TMap& OverrideData) const +void FAssetRegistry::InitializeTemporaryAssetRegistryState(FAssetRegistryState& OutState, const FAssetRegistrySerializationOptions& Options, bool bRefreshExisting, const TMap& OverrideData) const { const TMap& DataToUse = OverrideData.Num() > 0 ? OverrideData : State.CachedAssetsByObjectPath; - OutState.InitializeFromExisting(DataToUse, State.CachedDependsNodes, State.CachedPackageData, Options); + OutState.InitializeFromExisting(DataToUse, State.CachedDependsNodes, State.CachedPackageData, Options, bRefreshExisting); } void FAssetRegistry::ScanPathsAndFilesSynchronous(const TArray& InPaths, const TArray& InSpecificFiles, bool bForceRescan, EAssetDataCacheMode AssetDataCacheMode) @@ -1376,12 +1483,36 @@ void FAssetRegistry::ScanPathsAndFilesSynchronous(const TArray& InPaths // Only scan paths that were not previously synchronously scanned, unless we were asked to force rescan. TArray PathsToScan; TArray FilesToScan; + bool bPathsRemoved = false; + for (const FString& Path : InPaths) { - if (bForceRescan || !SynchronouslyScannedPathsAndFiles.Contains(Path)) + bool bAlreadyScanned = false; + FString PathWithSlash = Path; + if (!PathWithSlash.EndsWith(TEXT("/"), ESearchCase::CaseSensitive)) + { + // Add / if it's missing so the substring check is safe + PathWithSlash += TEXT("/"); + } + + // Check that it starts with / + for (const FString& ScannedPath : SynchronouslyScannedPathsAndFiles) + { + if (PathWithSlash.StartsWith(ScannedPath)) + { + bAlreadyScanned = true; + break; + } + } + + if (bForceRescan || !bAlreadyScanned) { PathsToScan.Add(Path); - SynchronouslyScannedPathsAndFiles.Add(Path); + SynchronouslyScannedPathsAndFiles.Add(PathWithSlash); + } + else + { + bPathsRemoved = true; } } @@ -1392,6 +1523,16 @@ void FAssetRegistry::ScanPathsAndFilesSynchronous(const TArray& InPaths FilesToScan.Add(SpecificFile); SynchronouslyScannedPathsAndFiles.Add(SpecificFile); } + else + { + bPathsRemoved = true; + } + } + + // If we removed paths, we can't use the monolithic cache as this will replace it with invalid data + if (AssetDataCacheMode == EAssetDataCacheMode::UseMonolithicCache && bPathsRemoved) + { + AssetDataCacheMode = EAssetDataCacheMode::UseModularCache; } if ( PathsToScan.Num() > 0 || FilesToScan.Num() > 0 ) @@ -1400,10 +1541,10 @@ void FAssetRegistry::ScanPathsAndFilesSynchronous(const TArray& InPaths FAssetDataGatherer AssetSearch(PathsToScan, FilesToScan, /*bSynchronous=*/true, AssetDataCacheMode); // Get the search results - TArray AssetResults; - TArray PathResults; - TArray DependencyResults; - TArray CookedPackageNamesWithoutAssetDataResults; + TBackgroundGatherResults AssetResults; + TBackgroundGatherResults PathResults; + TBackgroundGatherResults DependencyResults; + TBackgroundGatherResults CookedPackageNamesWithoutAssetDataResults; TArray SearchTimes; int32 NumFilesToSearch = 0; int32 NumPathsToSearch = 0; @@ -1461,36 +1602,33 @@ void FAssetRegistry::ScanPathsAndFilesSynchronous(const TArray& InPaths } } -void FAssetRegistry::AssetSearchDataGathered(const double TickStartTime, TArray& AssetResults) +void FAssetRegistry::AssetSearchDataGathered(const double TickStartTime, TBackgroundGatherResults& AssetResults) { const bool bFlushFullBuffer = TickStartTime < 0; - TSet ModifiedPaths; // Add the found assets - int32 AssetIndex = 0; - for (AssetIndex = 0; AssetIndex < AssetResults.Num(); ++AssetIndex) + while (AssetResults.Num() > 0) { - FAssetData*& BackgroundResult = AssetResults[AssetIndex]; + FAssetData*& BackgroundResult = AssetResults.Pop(); CA_ASSUME(BackgroundResult); // Try to update any asset data that may already exist - FAssetData* AssetData = nullptr; - FAssetData** AssetDataPtr = State.CachedAssetsByObjectPath.Find(BackgroundResult->ObjectPath); - if (AssetDataPtr != nullptr) - { - AssetData = *AssetDataPtr; - } + FAssetData* AssetData = State.CachedAssetsByObjectPath.FindRef(BackgroundResult->ObjectPath); const FName PackagePath = BackgroundResult->PackagePath; - if ( AssetData != nullptr ) + if (AssetData) { - // The asset exists in the cache, update it - UpdateAssetData(AssetData, *BackgroundResult); + // If this ensure fires then we've somehow processed the same result more than once, and that should never happen + if (ensure(AssetData != BackgroundResult)) + { + // The asset exists in the cache, update it + UpdateAssetData(AssetData, *BackgroundResult); - // Delete the result that was originally created by an FPackageReader - delete BackgroundResult; - BackgroundResult = nullptr; + // Delete the result that was originally created by an FPackageReader + delete BackgroundResult; + BackgroundResult = nullptr; + } } else { @@ -1502,51 +1640,43 @@ void FAssetRegistry::AssetSearchDataGathered(const double TickStartTime, TArray< AddAssetPath(PackagePath); // Check to see if we have run out of time in this tick - if ( !bFlushFullBuffer && (FPlatformTime::Seconds() - TickStartTime) > MaxSecondsPerFrame) + if (!bFlushFullBuffer && (FPlatformTime::Seconds() - TickStartTime) > MaxSecondsPerFrame) { - // Increment the index to properly trim the buffer below - ++AssetIndex; break; } } // Trim the results array - if (AssetIndex > 0) - { - AssetResults.RemoveAt(0, AssetIndex); - } + AssetResults.Trim(); } -void FAssetRegistry::PathDataGathered(const double TickStartTime, TArray& PathResults) +void FAssetRegistry::PathDataGathered(const double TickStartTime, TBackgroundGatherResults& PathResults) { const bool bFlushFullBuffer = TickStartTime < 0; - int32 ResultIdx = 0; - for (ResultIdx = 0; ResultIdx < PathResults.Num(); ++ResultIdx) + + while (PathResults.Num() > 0) { - const FString& Path = PathResults[ResultIdx]; + const FString& Path = PathResults.Pop(); AddAssetPath(FName(*Path)); - + // Check to see if we have run out of time in this tick - if ( !bFlushFullBuffer && (FPlatformTime::Seconds() - TickStartTime) > MaxSecondsPerFrame) + if (!bFlushFullBuffer && (FPlatformTime::Seconds() - TickStartTime) > MaxSecondsPerFrame) { - // Increment the index to properly trim the buffer below - ++ResultIdx; break; } } // Trim the results array - PathResults.RemoveAt(0, ResultIdx); + PathResults.Trim(); } -void FAssetRegistry::DependencyDataGathered(const double TickStartTime, TArray& DependsResults) +void FAssetRegistry::DependencyDataGathered(const double TickStartTime, TBackgroundGatherResults& DependsResults) { const bool bFlushFullBuffer = TickStartTime < 0; - int32 ResultIdx = 0; - for (ResultIdx = 0; ResultIdx < DependsResults.Num(); ++ResultIdx) + while (DependsResults.Num() > 0) { - FPackageDependencyData& Result = DependsResults[ResultIdx]; + FPackageDependencyData& Result = DependsResults.Pop(); // Update package data FAssetPackageData* PackageData = State.CreateOrGetAssetPackageData(Result.PackageName); @@ -1666,42 +1796,34 @@ void FAssetRegistry::DependencyDataGathered(const double TickStartTime, TArray MaxSecondsPerFrame) { - // Increment the index to properly trim the buffer below - ++ResultIdx; break; } } // Trim the results array - DependsResults.RemoveAt(0, ResultIdx); + DependsResults.Trim(); } -void FAssetRegistry::CookedPackageNamesWithoutAssetDataGathered(const double TickStartTime, TArray& CookedPackageNamesWithoutAssetDataResults) +void FAssetRegistry::CookedPackageNamesWithoutAssetDataGathered(const double TickStartTime, TBackgroundGatherResults& CookedPackageNamesWithoutAssetDataResults) { const bool bFlushFullBuffer = TickStartTime < 0; // Add the found assets - int32 PackageNameIndex = 0; - for (PackageNameIndex = 0; PackageNameIndex < CookedPackageNamesWithoutAssetDataResults.Num(); ++PackageNameIndex) + while (CookedPackageNamesWithoutAssetDataResults.Num() > 0) { // If this data is cooked and it we couldn't find any asset in its export table then try load the entire package - const FString& BackgroundResult = CookedPackageNamesWithoutAssetDataResults[PackageNameIndex]; + const FString& BackgroundResult = CookedPackageNamesWithoutAssetDataResults.Pop(); LoadPackage(nullptr, *BackgroundResult, 0); // Check to see if we have run out of time in this tick if (!bFlushFullBuffer && (FPlatformTime::Seconds() - TickStartTime) > MaxSecondsPerFrame) { - // Increment the index to properly trim the buffer below - ++PackageNameIndex; break; } } // Trim the results array - if (PackageNameIndex > 0) - { - CookedPackageNamesWithoutAssetDataResults.RemoveAt(0, PackageNameIndex); - } + CookedPackageNamesWithoutAssetDataResults.Trim(); } void FAssetRegistry::AddEmptyPackage(FName PackageName) @@ -2031,7 +2153,7 @@ void FAssetRegistry::ProcessLoadedAssetsToUpdateCache(const double TickStartTime FAssetData NewAssetData = FAssetData(LoadedAsset); - if (!NewAssetData.TagsAndValues.GetMap().OrderIndependentCompareEqual((*CachedData)->TagsAndValues.GetMap())) + if (NewAssetData.TagsAndValues.GetMap() != (*CachedData)->TagsAndValues.GetMap()) { // We need to actually update disk cache UpdateAssetData(*CachedData, NewAssetData); @@ -2053,6 +2175,22 @@ void FAssetRegistry::ProcessLoadedAssetsToUpdateCache(const double TickStartTime } } +void FAssetRegistry::UpdateRedirectCollector() +{ + // Look for all redirectors in list + const TArray& RedirectorAssets = State.GetAssetsByClassName(UObjectRedirector::StaticClass()->GetFName()); + + for (const FAssetData* AssetData : RedirectorAssets) + { + FName Destination = GetRedirectedObjectPath(AssetData->ObjectPath); + + if (Destination != AssetData->ObjectPath) + { + GRedirectCollector.AddAssetPathRedirection(AssetData->ObjectPath.ToString(), Destination.ToString()); + } + } +} + #endif // WITH_EDITOR @@ -2071,8 +2209,8 @@ void FAssetRegistry::OnContentPathMounted( const FString& InAssetPath, const FSt // Listen for directory changes in this content path #if WITH_EDITOR - // Commandlets and in-game don't listen for directory changes - if ( !IsRunningCommandlet() && GIsEditor) + // In-game doesn't listen for directory changes + if (GIsEditor) { FDirectoryWatcherModule& DirectoryWatcherModule = FModuleManager::LoadModuleChecked(TEXT("DirectoryWatcher")); IDirectoryWatcher* DirectoryWatcher = DirectoryWatcherModule.Get(); @@ -2127,8 +2265,8 @@ void FAssetRegistry::OnContentPathDismounted(const FString& InAssetPath, const F // Stop listening for directory changes in this content path #if WITH_EDITOR - // Commandlets and in-game don't listen for directory changes - if (!IsRunningCommandlet() && GIsEditor) + // In-game doesn't listen for directory changes + if (GIsEditor) { FDirectoryWatcherModule& DirectoryWatcherModule = FModuleManager::LoadModuleChecked(TEXT("DirectoryWatcher")); IDirectoryWatcher* DirectoryWatcher = DirectoryWatcherModule.Get(); @@ -2354,11 +2492,11 @@ bool FAssetRegistry::SetPrimaryAssetIdForObjectPath(const FName ObjectPath, FPri FAssetData* AssetData = *FoundAssetData; - TMap TagsAndValues = AssetData->TagsAndValues.GetMap(); + FAssetDataTagMap TagsAndValues = AssetData->TagsAndValues.GetMap(); TagsAndValues.Add(FPrimaryAssetId::PrimaryAssetTypeTag, PrimaryAssetId.PrimaryAssetType.ToString()); TagsAndValues.Add(FPrimaryAssetId::PrimaryAssetNameTag, PrimaryAssetId.PrimaryAssetName.ToString()); - FAssetData NewAssetData = FAssetData(AssetData->PackageName, AssetData->PackagePath, AssetData->GroupNames, AssetData->AssetName, AssetData->AssetClass, TagsAndValues, AssetData->ChunkIDs, AssetData->PackageFlags); + FAssetData NewAssetData = FAssetData(AssetData->PackageName, AssetData->PackagePath, AssetData->AssetName, AssetData->AssetClass, TagsAndValues, AssetData->ChunkIDs, AssetData->PackageFlags); UpdateAssetData(AssetData, NewAssetData); diff --git a/Engine/Source/Runtime/AssetRegistry/Private/AssetRegistry.h b/Engine/Source/Runtime/AssetRegistry/Private/AssetRegistry.h index c195e07429d1..2072d7a1d8dd 100644 --- a/Engine/Source/Runtime/AssetRegistry/Private/AssetRegistry.h +++ b/Engine/Source/Runtime/AssetRegistry/Private/AssetRegistry.h @@ -1,15 +1,15 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - #pragma once #include "CoreMinimal.h" #include "AssetData.h" #include "IAssetRegistry.h" #include "AssetRegistryState.h" -#include "Runtime/AssetRegistry/Private/PathTree.h" -#include "Runtime/AssetRegistry/Private/PackageDependencyData.h" -#include "Runtime/AssetRegistry/Private/AssetDataGatherer.h" +#include "PathTree.h" +#include "PackageDependencyData.h" +#include "AssetDataGatherer.h" +#include "BackgroundGatherResults.h" class FDependsNode; struct FARFilter; @@ -26,6 +26,7 @@ public: virtual ~FAssetRegistry(); // IAssetRegistry implementation + virtual bool HasAssets(const FName PackagePath, const bool bRecursive = false) const override; virtual bool GetAssetsByPackageName(FName PackageName, TArray& OutAssetData, bool bIncludeOnlyOnDiskAssets = false) const override; virtual bool GetAssetsByPath(FName PackagePath, TArray& OutAssetData, bool bRecursive = false, bool bIncludeOnlyOnDiskAssets = false) const override; virtual bool GetAssetsByClass(FName ClassName, TArray& OutAssetData, bool bSearchSubClasses = false) const override; @@ -38,6 +39,7 @@ public: virtual bool GetReferencers(const FAssetIdentifier& AssetIdentifier, TArray& OutReferencers, EAssetRegistryDependencyType::Type InReferenceType = EAssetRegistryDependencyType::All) const override; virtual bool GetReferencers(FName PackageName, TArray& OutReferencers, EAssetRegistryDependencyType::Type InReferenceType = EAssetRegistryDependencyType::Packages) const override; virtual const FAssetPackageData* GetAssetPackageData(FName PackageName) const override; + virtual FName GetRedirectedObjectPath(const FName ObjectPath) const override; virtual bool GetAncestorClassNames(FName ClassName, TArray& OutAncestorClassNames) const override; virtual void GetDerivedClassNames(const TArray& ClassNames, const TSet& ExcludedClassNames, TSet& OutDerivedClassNames) const override; virtual void GetAllCachedPaths(TArray& OutPathList) const override; @@ -55,8 +57,9 @@ public: virtual void ScanFilesSynchronous(const TArray& InFilePaths, bool bForceRescan = false) override; virtual void PrioritizeSearchPath(const FString& PathToPrioritize) override; virtual void Serialize(FArchive& Ar) override; + virtual uint32 GetAllocatedSize(bool bLogDetailed = false) const override; virtual void LoadPackageRegistryData(FArchive& Ar, TArray& Data) const override; - virtual void InitializeTemporaryAssetRegistryState(FAssetRegistryState& OutState, const FAssetRegistrySerializationOptions& Options, const TMap& OverrideData = TMap()) const override; + virtual void InitializeTemporaryAssetRegistryState(FAssetRegistryState& OutState, const FAssetRegistrySerializationOptions& Options, bool bRefreshExisting = false, const TMap& OverrideData = TMap()) const override; virtual void InitializeSerializationOptions(FAssetRegistrySerializationOptions& Options, const FString& PlatformIniName = FString()) const override; virtual void SaveRegistryData(FArchive& Ar, TMap& Data, TArray* InMaps = nullptr) override; @@ -117,16 +120,16 @@ private: void ScanPathsAndFilesSynchronous(const TArray& InPaths, const TArray& InSpecificFiles, bool bForceRescan, EAssetDataCacheMode AssetDataCacheMode, TArray* OutFoundAssets, TArray* OutFoundPaths); /** Called every tick to when data is retrieved by the background asset search. If TickStartTime is < 0, the entire list of gathered assets will be cached. Also used in sychronous searches */ - void AssetSearchDataGathered(const double TickStartTime, TArray& AssetResults); + void AssetSearchDataGathered(const double TickStartTime, TBackgroundGatherResults& AssetResults); /** Called every tick when data is retrieved by the background path search. If TickStartTime is < 0, the entire list of gathered assets will be cached. Also used in sychronous searches */ - void PathDataGathered(const double TickStartTime, TArray& PathResults); + void PathDataGathered(const double TickStartTime, TBackgroundGatherResults& PathResults); /** Called every tick when data is retrieved by the background dependency search */ - void DependencyDataGathered(const double TickStartTime, TArray& DependsResults); + void DependencyDataGathered(const double TickStartTime, TBackgroundGatherResults& DependsResults); /** Called every tick when data is retrieved by the background search for cooked packages that do not contain asset data */ - void CookedPackageNamesWithoutAssetDataGathered(const double TickStartTime, TArray& CookedPackageNamesWithoutAssetDataResults); + void CookedPackageNamesWithoutAssetDataGathered(const double TickStartTime, TBackgroundGatherResults& CookedPackageNamesWithoutAssetDataResults); /** Adds an asset to the empty package list which contains packages that have no assets left in them */ void AddEmptyPackage(FName PackageName); @@ -174,6 +177,9 @@ private: /** Process Loaded Assets to update cache */ void ProcessLoadedAssetsToUpdateCache(const double TickStartTime); + + /** Update Redirect collector with redirects loaded from asset registry */ + void UpdateRedirectCollector(); #endif // WITH_EDITOR /** @@ -194,6 +200,9 @@ private: */ void OnContentPathDismounted( const FString& AssetPath, const FString& FileSystemPath ); + /** Called to refresh the native classes list, called at end of engine initialization */ + void RefreshNativeClasses(); + /** Returns the names of all subclasses of the class whose name is ClassName */ void GetSubClasses(const TArray& InClassNames, const TSet& ExcludedClassNames, TSet& SubClassNames) const; void GetSubClasses_Recursive(FName InClassName, TSet& SubClassNames, const TMap>& ReverseInheritanceMap, const TSet& ExcludedClassNames) const; @@ -225,10 +234,10 @@ private: TSharedPtr< class FAssetDataGatherer > BackgroundAssetSearch; /** A list of results that were gathered from the background thread that are waiting to get processed by the main thread */ - TArray BackgroundAssetResults; - TArray BackgroundPathResults; - TArray BackgroundDependencyResults; - TArray BackgroundCookedPackageNamesWithoutAssetDataResults; + TBackgroundGatherResults BackgroundAssetResults; + TBackgroundGatherResults BackgroundPathResults; + TBackgroundGatherResults BackgroundDependencyResults; + TBackgroundGatherResults BackgroundCookedPackageNamesWithoutAssetDataResults; /** The max number of results to process per tick */ float MaxSecondsPerFrame; diff --git a/Engine/Source/Runtime/AssetRegistry/Private/AssetRegistryState.cpp b/Engine/Source/Runtime/AssetRegistry/Private/AssetRegistryState.cpp index 9d5771a8d7f2..5b7e31a5d1d2 100644 --- a/Engine/Source/Runtime/AssetRegistry/Private/AssetRegistryState.cpp +++ b/Engine/Source/Runtime/AssetRegistry/Private/AssetRegistryState.cpp @@ -17,48 +17,6 @@ #include "NameTableArchive.h" #include "GenericPlatform/GenericPlatformChunkInstall.h" -/** - * Enum for tracking versions of the runtime asset registry that gets used for cooked asset registries - * This enum is NOT used for the editor caching, that uses AssetDataGathererConstants::CacheSerializationVersion - */ -enum class ERuntimeRegistryVersion -{ - PreVersioning, // From before file versioning was implemented - HardSoftDependencies, // The first version of the runtime asset registry to include file versioning. - AddAssetRegistryState, // Added FAssetRegistryState and support for piecemeal serialization - - LatestPlusOne, - Latest = (LatestPlusOne - 1), -}; - -/** Guid for the runtime asset registry file format, used for identification purposes */ -static const FGuid GRuntimeRegistryGuid(0x717F9EE7, 0xE9B0493A, 0x88B39132, 0x1B388107); - -/** Helper function for reading the header of the runtime asset registry. It deals with the header not - existing for old formats of the file */ -inline ERuntimeRegistryVersion ReadRuntimeRegistryVersion(FArchive& Ar) -{ - int64 InitialLocation = Ar.Tell(); - FGuid Guid; - Ar << Guid; - - ERuntimeRegistryVersion Version = ERuntimeRegistryVersion::PreVersioning; - - if (Guid == GRuntimeRegistryGuid) - { - int32 VersionInt; - Ar << VersionInt; - Version = (ERuntimeRegistryVersion)VersionInt; - } - else - { - // This is an old format file, so skip back to where we started - Ar.Seek(InitialLocation); - } - - return Version; -} - FAssetRegistryState::FAssetRegistryState() { NumAssets = 0; @@ -160,12 +118,26 @@ void FAssetRegistryState::Reset() CachedPackageData.Empty(); } -void FAssetRegistryState::InitializeFromExisting(const TMap& AssetDataMap, const TMap& DependsNodeMap, const TMap& AssetPackageDataMap, const FAssetRegistrySerializationOptions& Options) +void FAssetRegistryState::InitializeFromExisting(const TMap& AssetDataMap, const TMap& DependsNodeMap, const TMap& AssetPackageDataMap, const FAssetRegistrySerializationOptions& Options, bool bRefreshExisting) { - Reset(); + if (!bRefreshExisting) + { + Reset(); + } for (const TPair& Pair : AssetDataMap) { + FAssetData* ExistingData = nullptr; + + if (bRefreshExisting) + { + ExistingData = CachedAssetsByObjectPath.FindRef(Pair.Key); + if (!ExistingData) + { + continue; + } + } + if (Pair.Value) { // Filter asset registry tags now @@ -176,19 +148,18 @@ void FAssetRegistryState::InitializeFromExisting(const TMap& const TSet* ClassSpecificFilterlist = Options.CookFilterlistTagsByClass.Find(AssetData.AssetClass); // Exclude blacklisted tags or include only whitelisted tags, based on how we were configured in ini - TMap LocalTagsAndValues; - for (auto TagIt = AssetData.TagsAndValues.GetMap().CreateConstIterator(); TagIt; ++TagIt) + FAssetDataTagMap LocalTagsAndValues; + for (const TPair& TagPair : AssetData.TagsAndValues) { - FName TagName = TagIt.Key(); - const bool bInAllClasseslist = AllClassesFilterlist && (AllClassesFilterlist->Contains(TagName) || AllClassesFilterlist->Contains(WildcardName)); - const bool bInClassSpecificlist = ClassSpecificFilterlist && (ClassSpecificFilterlist->Contains(TagName) || ClassSpecificFilterlist->Contains(WildcardName)); + const bool bInAllClasseslist = AllClassesFilterlist && (AllClassesFilterlist->Contains(TagPair.Key) || AllClassesFilterlist->Contains(WildcardName)); + const bool bInClassSpecificlist = ClassSpecificFilterlist && (ClassSpecificFilterlist->Contains(TagPair.Key) || ClassSpecificFilterlist->Contains(WildcardName)); if (Options.bUseAssetRegistryTagsWhitelistInsteadOfBlacklist) { // It's a whitelist, only include it if it is in the all classes list or in the class specific list if (bInAllClasseslist || bInClassSpecificlist) { // It is in the whitelist. Keep it. - LocalTagsAndValues.Add(TagIt.Key(), TagIt.Value()); + LocalTagsAndValues.Add(TagPair.Key, TagPair.Value); } } else @@ -197,47 +168,61 @@ void FAssetRegistryState::InitializeFromExisting(const TMap& if (!bInAllClasseslist && !bInClassSpecificlist) { // It isn't in the blacklist. Keep it. - LocalTagsAndValues.Add(TagIt.Key(), TagIt.Value()); + LocalTagsAndValues.Add(TagPair.Key, TagPair.Value); } } } - FAssetData* NewData = new FAssetData(AssetData.PackageName, AssetData.PackagePath, AssetData.GroupNames, AssetData.AssetName, - AssetData.AssetClass, LocalTagsAndValues, AssetData.ChunkIDs, AssetData.PackageFlags); - - AddAssetData(NewData); + if (bRefreshExisting) + { + // Only modify tags + if (LocalTagsAndValues != ExistingData->TagsAndValues.GetMap()) + { + FAssetData TempData = *ExistingData; + TempData.TagsAndValues = FAssetDataTagMapSharedView(MoveTemp(LocalTagsAndValues)); + UpdateAssetData(ExistingData, TempData); + } + } + else + { + FAssetData* NewData = new FAssetData(AssetData.PackageName, AssetData.PackagePath, AssetData.AssetName, + AssetData.AssetClass, LocalTagsAndValues, AssetData.ChunkIDs, AssetData.PackageFlags); + AddAssetData(NewData); + } } } - for (const TPair& Pair : DependsNodeMap) + if (!bRefreshExisting) { - FDependsNode* OldNode = Pair.Value; - FDependsNode* NewNode = CreateOrFindDependsNode(Pair.Key); + for (const TPair& Pair : AssetPackageDataMap) + { + // Only add if also in asset data map + if (Pair.Value && CachedAssetsByPackageName.Find(Pair.Key)) + { + FAssetPackageData* NewData = CreateOrGetAssetPackageData(Pair.Key); + *NewData = *Pair.Value; + } + } - Pair.Value->IterateOverDependencies( - [this, &DependsNodeMap, OldNode, NewNode](FDependsNode* InDependency, EAssetRegistryDependencyType::Type InDependencyType) { + for (const TPair& Pair : DependsNodeMap) + { + FDependsNode* OldNode = Pair.Value; + FDependsNode* NewNode = CreateOrFindDependsNode(Pair.Key); + + Pair.Value->IterateOverDependencies([this, &DependsNodeMap, OldNode, NewNode](FDependsNode* InDependency, EAssetRegistryDependencyType::Type InDependencyType) { if (DependsNodeMap.Find(InDependency->GetIdentifier())) { // Only add if this node is in the incoming map FDependsNode* NewDependency = CreateOrFindDependsNode(InDependency->GetIdentifier()); - NewNode->AddDependency(NewDependency, InDependencyType); + NewNode->AddDependency(NewDependency, InDependencyType, true); NewDependency->AddReferencer(NewNode); } }); - } - - for (const TPair& Pair : AssetPackageDataMap) - { - // Only add if also in asset data map - if (Pair.Value && CachedAssetsByPackageName.Find(Pair.Key)) - { - FAssetPackageData* NewData = CreateOrGetAssetPackageData(Pair.Key); - *NewData = *Pair.Value; } } } -void FAssetRegistryState::PruneAssetData(const TSet& RequiredPackages, const TSet& RemovePackages) +void FAssetRegistryState::PruneAssetData(const TSet& RequiredPackages, const TSet& RemovePackages, bool bFilterAssetDataWithNoTags) { // Generate list up front as the maps will get cleaned up TArray AllAssetData; @@ -253,6 +238,10 @@ void FAssetRegistryState::PruneAssetData(const TSet& RequiredPackages, co { RemoveAssetData(AssetData); } + else if (bFilterAssetDataWithNoTags && AssetData->TagsAndValues.Num() == 0) + { + RemoveAssetData(AssetData); + } } // Remove any orphaned depends nodes. This will leave cycles in but those might represent useful data @@ -268,6 +257,12 @@ void FAssetRegistryState::PruneAssetData(const TSet& RequiredPackages, co } } +bool FAssetRegistryState::HasAssets(const FName PackagePath) const +{ + const TArray* FoundAssetArray = CachedAssetsByPath.Find(PackagePath); + return FoundAssetArray && FoundAssetArray->Num() > 0; +} + bool FAssetRegistryState::GetAssets(const FARFilter& Filter, const TSet& PackageNamesToSkip, TArray& OutAssetData) const { // Verify filter input. If all assets are needed, use GetAllAssets() instead. @@ -288,7 +283,7 @@ bool FAssetRegistryState::GetAssets(const FARFilter& Filter, const TSet& // On disk package names if (FilterPackageNames.Num()) { - TArray* PackageNameFilter = new (DiskFilterSets) TArray(); + TArray& PackageNameFilter = DiskFilterSets[DiskFilterSets.AddDefaulted()]; for (FName PackageName : FilterPackageNames) { @@ -296,7 +291,7 @@ bool FAssetRegistryState::GetAssets(const FARFilter& Filter, const TSet& if (PackageAssets != nullptr) { - PackageNameFilter->Append(*PackageAssets); + PackageNameFilter.Append(*PackageAssets); } } } @@ -304,7 +299,7 @@ bool FAssetRegistryState::GetAssets(const FARFilter& Filter, const TSet& // On disk package paths if (FilterPackagePaths.Num()) { - TArray* PathFilter = new (DiskFilterSets) TArray(); + TArray& PathFilter = DiskFilterSets[DiskFilterSets.AddDefaulted()]; for (FName PackagePath : FilterPackagePaths) { @@ -312,7 +307,7 @@ bool FAssetRegistryState::GetAssets(const FARFilter& Filter, const TSet& if (PathAssets != nullptr) { - PathFilter->Append(*PathAssets); + PathFilter.Append(*PathAssets); } } } @@ -320,7 +315,7 @@ bool FAssetRegistryState::GetAssets(const FARFilter& Filter, const TSet& // On disk classes if (FilterClassNames.Num()) { - TArray* ClassFilter = new (DiskFilterSets) TArray(); + TArray& ClassFilter = DiskFilterSets[DiskFilterSets.AddDefaulted()]; for (FName ClassName : FilterClassNames) { @@ -328,7 +323,7 @@ bool FAssetRegistryState::GetAssets(const FARFilter& Filter, const TSet& if (ClassAssets != nullptr) { - ClassFilter->Append(*ClassAssets); + ClassFilter.Append(*ClassAssets); } } } @@ -336,15 +331,15 @@ bool FAssetRegistryState::GetAssets(const FARFilter& Filter, const TSet& // On disk object paths if (FilterObjectPaths.Num()) { - TArray* ObjectPathsFilter = new (DiskFilterSets) TArray(); + TArray& ObjectPathsFilter = DiskFilterSets[DiskFilterSets.AddDefaulted()]; for (FName ObjectPath : FilterObjectPaths) { - const FAssetData* const* AssetDataPtr = CachedAssetsByObjectPath.Find(ObjectPath); + FAssetData* AssetDataPtr = CachedAssetsByObjectPath.FindRef(ObjectPath); if (AssetDataPtr != nullptr) { - ObjectPathsFilter->Add(*AssetDataPtr); + ObjectPathsFilter.Add(AssetDataPtr); } } } @@ -352,7 +347,7 @@ bool FAssetRegistryState::GetAssets(const FARFilter& Filter, const TSet& // On disk tags and values if (Filter.TagsAndValues.Num()) { - TArray* TagAndValuesFilter = new (DiskFilterSets) TArray(); + TArray& TagAndValuesFilter = DiskFilterSets[DiskFilterSets.AddDefaulted()]; for (auto FilterTagIt = Filter.TagsAndValues.CreateConstIterator(); FilterTagIt; ++FilterTagIt) { @@ -370,7 +365,7 @@ bool FAssetRegistryState::GetAssets(const FARFilter& Filter, const TSet& const FString* TagValue = AssetData->TagsAndValues.Find(Tag); if (TagValue != nullptr && *TagValue == Value) { - TagAndValuesFilter->Add(AssetData); + TagAndValuesFilter.Add(AssetData); } } } @@ -547,11 +542,8 @@ bool FAssetRegistryState::Serialize(FArchive& OriginalAr, FAssetRegistrySerializ { check(CachedAssetsByObjectPath.Num() == NumAssets); - // Write asset registry header - FGuid LocalGuid = GRuntimeRegistryGuid; - LocalGuid.Serialize(OriginalAr); - int32 VersionInt = (int32)ERuntimeRegistryVersion::Latest; - OriginalAr << VersionInt; + FAssetRegistryVersion::Type Version = FAssetRegistryVersion::LatestVersion; + FAssetRegistryVersion::SerializeVersion(OriginalAr, Version); // Set up name table archive FNameTableArchiveWriter Ar(OriginalAr); @@ -568,7 +560,7 @@ bool FAssetRegistryState::Serialize(FArchive& OriginalAr, FAssetRegistrySerializ for (TPair& Pair : CachedAssetsByObjectPath) { FAssetData& AssetData(*Pair.Value); - Ar << AssetData; + AssetData.SerializeForCache(Ar); } if (Options.bSerializeDependencies) @@ -648,12 +640,7 @@ bool FAssetRegistryState::Serialize(FArchive& OriginalAr, FAssetRegistrySerializ for (FDependsNode* Dependency : ProcessedDependencies) { - FDependsNode* RedirectedDependency = ResolveRedirector(Dependency, CachedAssetsByObjectPath, RedirectCache); - if (RedirectedDependency == nullptr) - { - RedirectedDependency = Dependency; - } - int32 Index = DependsIndexMap[RedirectedDependency->GetIdentifier()]; + int32 Index = DependsIndexMap[Dependency->GetIdentifier()]; Ar << Index; } } @@ -667,7 +654,7 @@ bool FAssetRegistryState::Serialize(FArchive& OriginalAr, FAssetRegistrySerializ for (TPair& Pair : CachedPackageData) { Ar << Pair.Key; - Ar << *Pair.Value; + Pair.Value->SerializeForCache(Ar); } } else @@ -678,11 +665,13 @@ bool FAssetRegistryState::Serialize(FArchive& OriginalAr, FAssetRegistrySerializ // load in by building the TMap else { - ERuntimeRegistryVersion Version = ReadRuntimeRegistryVersion(OriginalAr); + FAssetRegistryVersion::Type Version = FAssetRegistryVersion::LatestVersion; + FAssetRegistryVersion::SerializeVersion(OriginalAr, Version); - if (Version < ERuntimeRegistryVersion::AddAssetRegistryState) + if (Version < FAssetRegistryVersion::ChangedAssetData) { - return ReadDeprecated(OriginalAr, Version); + // Cannot read states before this version + return false; } // Set up name table archive @@ -702,7 +691,7 @@ bool FAssetRegistryState::Serialize(FArchive& OriginalAr, FAssetRegistrySerializ FAssetData* NewAssetData = &PreallocatedAssetDataBuffer[AssetIndex]; // load it - Ar << *NewAssetData; + NewAssetData->SerializeForCache(Ar); AddAssetData(NewAssetData); } @@ -759,11 +748,11 @@ bool FAssetRegistryState::Serialize(FArchive& OriginalAr, FAssetRegistrySerializ { if (InDependencyType == EAssetRegistryDependencyType::None) { - NewDependsNodeData->AddReferencer(&PreallocatedDependsNodeDataBuffer[Index]); + NewDependsNodeData->AddReferencer(&PreallocatedDependsNodeDataBuffer[Index], true); } else { - NewDependsNodeData->AddDependency(&PreallocatedDependsNodeDataBuffer[Index], InDependencyType); + NewDependsNodeData->AddDependency(&PreallocatedDependsNodeDataBuffer[Index], InDependencyType, true); } } } @@ -795,13 +784,13 @@ bool FAssetRegistryState::Serialize(FArchive& OriginalAr, FAssetRegistrySerializ if (Options.bSerializePackageData) { FAssetPackageData& NewPackageData = PreallocatedPackageDataBuffer[PackageDataIndex]; - Ar << NewPackageData; + NewPackageData.SerializeForCache(Ar); CachedPackageData.Add(PackageName, &NewPackageData); } else { FAssetPackageData FakeData; - Ar << FakeData; + FakeData.SerializeForCache(Ar); } } } @@ -809,141 +798,124 @@ bool FAssetRegistryState::Serialize(FArchive& OriginalAr, FAssetRegistrySerializ return !OriginalAr.IsError(); } -bool FAssetRegistryState::ReadDeprecated(FArchive& Ar, ERuntimeRegistryVersion Version) +uint32 FAssetRegistryState::GetAllocatedSize(bool bLogDetailed) const { - // serialize number of objects - int32 LocalNumAssets = 0; - Ar << LocalNumAssets; + uint32 TotalBytes = 0; - // allocate one single block for all asset data structs (to reduce tens of thousands of heap allocations) - FAssetData* PreallocatedAssetDataBuffer = new FAssetData[LocalNumAssets]; - PreallocatedAssetDataBuffers.Add(PreallocatedAssetDataBuffer); + uint32 MapMemory = CachedAssetsByObjectPath.GetAllocatedSize(); + MapMemory += CachedAssetsByPackageName.GetAllocatedSize(); + MapMemory += CachedAssetsByPath.GetAllocatedSize(); + MapMemory += CachedAssetsByClass.GetAllocatedSize(); + MapMemory += CachedAssetsByTag.GetAllocatedSize(); + MapMemory += CachedDependsNodes.GetAllocatedSize(); + MapMemory += CachedPackageData.GetAllocatedSize(); - double LastPumpTime = FPlatformTime::Seconds(); - for (int32 AssetIndex = 0; AssetIndex < LocalNumAssets; AssetIndex++) + if (bLogDetailed) { - // make a new asset data object - FAssetData* NewAssetData = &PreallocatedAssetDataBuffer[AssetIndex]; - - // load it - Ar << *NewAssetData; - - AddAssetData(NewAssetData); + UE_LOG(LogAssetRegistry, Log, TEXT("Index Size: %dk"), MapMemory / 1024); } - int32 LocalNumDependsNodes = LocalNumAssets; - if (Version == ERuntimeRegistryVersion::PreVersioning) + uint32 AssetDataSize = 0, TagOverHead = 0, TotalTagSize = 0; + TMap TagSizes; + + for (const TPair& AssetDataPair : CachedAssetsByObjectPath) { - Ar << LocalNumDependsNodes; - } - - FDependsNode* PreallocatedDependsNodeDataBuffer = new FDependsNode[LocalNumDependsNodes]; - PreallocatedDependsNodeDataBuffers.Add(PreallocatedDependsNodeDataBuffer); - CachedDependsNodes.Reserve(LocalNumDependsNodes); - - for (int32 DependsNodeIndex = 0; DependsNodeIndex < LocalNumDependsNodes; DependsNodeIndex++) - { - FDependsNode* NewDependsNodeData = &PreallocatedDependsNodeDataBuffer[DependsNodeIndex]; - - if (DependsNodeIndex < LocalNumAssets) - { - // One of the packages - int32 AssetIndex = DependsNodeIndex; - - if (Version == ERuntimeRegistryVersion::PreVersioning) - { - Ar << AssetIndex; - } - - NewDependsNodeData->SetPackageName(PreallocatedAssetDataBuffer[AssetIndex].PackageName); - } + const FAssetData& AssetData = *AssetDataPair.Value; - CachedDependsNodes.Add(NewDependsNodeData->GetIdentifier(), NewDependsNodeData); + AssetDataSize += sizeof(AssetData); + AssetDataSize += AssetData.ChunkIDs.GetAllocatedSize(); + + TagOverHead += AssetData.TagsAndValues.GetAllocatedSize(); + + for (const TPair& TagPair : AssetData.TagsAndValues) + { + uint32 StringSize = TagPair.Value.GetAllocatedSize(); + + TotalTagSize += StringSize; + TagSizes.FindOrAdd(TagPair.Key) += StringSize; + } } - for (int32 DependsNodeIndex = 0; DependsNodeIndex < LocalNumDependsNodes; DependsNodeIndex++) + if (bLogDetailed) { - int32 LocalNumHardDependencies = 0; - int32 LocalNumSoftDependencies = 0; - int32 LocalNumReferencers = 0; - Ar << LocalNumHardDependencies; - if (Version >= ERuntimeRegistryVersion::HardSoftDependencies) + UE_LOG(LogAssetRegistry, Log, TEXT("AssetData Count: %d"), CachedAssetsByObjectPath.Num()); + UE_LOG(LogAssetRegistry, Log, TEXT("AssetData Static Size: %dk"), AssetDataSize / 1024); + UE_LOG(LogAssetRegistry, Log, TEXT("AssetData Tag Overhead: %dk"), TagOverHead / 1024); + + for (const TPair& SizePair : TagSizes) { - Ar << LocalNumSoftDependencies; - } - - Ar << LocalNumReferencers; - - FDependsNode* NewDependsNodeData = &PreallocatedDependsNodeDataBuffer[DependsNodeIndex]; - NewDependsNodeData->Reserve(LocalNumHardDependencies, LocalNumSoftDependencies, 0, 0, LocalNumReferencers); - - for (int32 DependencyIndex = 0; DependencyIndex < LocalNumHardDependencies; ++DependencyIndex) - { - int32 Index = 0; - Ar << Index; - - NewDependsNodeData->AddDependency(&PreallocatedDependsNodeDataBuffer[Index], EAssetRegistryDependencyType::Hard); - } - - for (int32 DependencyIndex = 0; DependencyIndex < LocalNumSoftDependencies; ++DependencyIndex) - { - int32 Index = 0; - Ar << Index; - - NewDependsNodeData->AddDependency(&PreallocatedDependsNodeDataBuffer[Index], EAssetRegistryDependencyType::Soft); - } - - for (int32 ReferencerIndex = 0; ReferencerIndex < LocalNumReferencers; ++ReferencerIndex) - { - int32 Index = 0; - Ar << Index; - - NewDependsNodeData->AddReferencer(&PreallocatedDependsNodeDataBuffer[Index]); + UE_LOG(LogAssetRegistry, Log, TEXT("Tag %s Size: %dk"), *SizePair.Key.ToString(), SizePair.Value / 1024); } } - return !Ar.IsError(); + uint32 DependNodesSize = 0, DependenciesSize = 0; + + for (const TPair& DependsNodePair : CachedDependsNodes) + { + const FDependsNode& DependsNode = *DependsNodePair.Value; + DependNodesSize += sizeof(DependsNode); + + DependenciesSize += DependsNode.GetAllocatedSize(); + } + + if (bLogDetailed) + { + UE_LOG(LogAssetRegistry, Log, TEXT("Dependency Node Count: %d"), CachedDependsNodes.Num()); + UE_LOG(LogAssetRegistry, Log, TEXT("Dependency Node Static Size: %dk"), DependNodesSize / 1024); + UE_LOG(LogAssetRegistry, Log, TEXT("Dependency Arrays Size: %dk"), DependenciesSize / 1024); + } + + uint32 PackageDataSize = CachedPackageData.Num() * sizeof(FAssetPackageData); + + TotalBytes = MapMemory + AssetDataSize + TagOverHead + TotalTagSize + DependNodesSize + DependenciesSize + PackageDataSize; + + if (bLogDetailed) + { + UE_LOG(LogAssetRegistry, Log, TEXT("PackageData Count: %d"), CachedPackageData.Num()); + UE_LOG(LogAssetRegistry, Log, TEXT("PackageData Static Size: %dk"), PackageDataSize / 1024); + UE_LOG(LogAssetRegistry, Log, TEXT("Total State Size: %dk"), TotalBytes / 1024); + } + return TotalBytes; } FDependsNode* FAssetRegistryState::ResolveRedirector(FDependsNode* InDependency, TMap& InAllowedAssets, TMap& InCache) { - static const FName ObjectRedirectorClassName(TEXT("ObjectRedirector")); - - FDependsNode* Original = InDependency; - FDependsNode* Result = nullptr; - if (InCache.Contains(InDependency)) { return InCache[InDependency]; } + FDependsNode* CurrentDependency = InDependency; + FDependsNode* Result = nullptr; + static TSet EncounteredDependencies; EncounteredDependencies.Empty(); while (Result == nullptr) { - checkSlow(InDependency); + checkSlow(CurrentDependency); - if (EncounteredDependencies.Contains(InDependency->GetPackageName())) + if (EncounteredDependencies.Contains(CurrentDependency->GetPackageName())) { break; } - EncounteredDependencies.Add(InDependency->GetPackageName()); + EncounteredDependencies.Add(CurrentDependency->GetPackageName()); - if (CachedAssetsByPackageName.Contains(InDependency->GetPackageName())) + if (CachedAssetsByPackageName.Contains(CurrentDependency->GetPackageName())) { // Get the list of assets contained in this package - TArray& Assets = CachedAssetsByPackageName[InDependency->GetPackageName()]; + TArray& Assets = CachedAssetsByPackageName[CurrentDependency->GetPackageName()]; for (FAssetData* Asset : Assets) { - if (Asset->AssetClass == ObjectRedirectorClassName) + if (Asset->IsRedirector()) { + FDependsNode* ChainedRedirector = nullptr; // This asset is a redirector, so we want to look at its dependencies and find the asset that it is redirecting to - InDependency->IterateOverDependencies([&](FDependsNode* InDepends, EAssetRegistryDependencyType::Type) { + CurrentDependency->IterateOverDependencies([&](FDependsNode* InDepends, EAssetRegistryDependencyType::Type) { if (InAllowedAssets.Contains(InDepends->GetPackageName())) { // This asset is in the allowed asset list, so take this as the redirect target @@ -954,13 +926,20 @@ FDependsNode* FAssetRegistryState::ResolveRedirector(FDependsNode* InDependency, // This dependency isn't in the allowed list, but it is a valid asset in the registry. // Because this is a redirector, this should mean that the redirector is pointing at ANOTHER // redirector (or itself in some horrible situations) so we'll move to that node and try again - InDependency = InDepends; + ChainedRedirector = InDepends; } }); + + if (ChainedRedirector) + { + // Found a redirector, break for loop + CurrentDependency = ChainedRedirector; + break; + } } else { - Result = InDependency; + Result = CurrentDependency; } if (Result) @@ -972,11 +951,11 @@ FDependsNode* FAssetRegistryState::ResolveRedirector(FDependsNode* InDependency, } else { - Result = InDependency; + Result = CurrentDependency; } } - InCache.Add(Original, Result); + InCache.Add(InDependency, Result); return Result; } @@ -1092,14 +1071,14 @@ bool FAssetRegistryState::RemoveAssetData(FAssetData* AssetData) TArray* OldClassAssets = CachedAssetsByClass.Find(AssetData->AssetClass); CachedAssetsByObjectPath.Remove(AssetData->ObjectPath); - OldPackageAssets->Remove(AssetData); - OldPathAssets->Remove(AssetData); - OldClassAssets->Remove(AssetData); + OldPackageAssets->RemoveSingleSwap(AssetData); + OldPathAssets->RemoveSingleSwap(AssetData); + OldClassAssets->RemoveSingleSwap(AssetData); for (auto TagIt = AssetData->TagsAndValues.CreateConstIterator(); TagIt; ++TagIt) { TArray* OldTagAssets = CachedAssetsByTag.Find(TagIt.Key()); - OldTagAssets->Remove(AssetData); + OldTagAssets->RemoveSingleSwap(AssetData); } // We need to update the cached dependencies references cache so that they know we no diff --git a/Engine/Source/Runtime/AssetRegistry/Private/BackgroundGatherResults.h b/Engine/Source/Runtime/AssetRegistry/Private/BackgroundGatherResults.h new file mode 100644 index 000000000000..893ce76ec761 --- /dev/null +++ b/Engine/Source/Runtime/AssetRegistry/Private/BackgroundGatherResults.h @@ -0,0 +1,131 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" + +/** + * This is a specialized container for storing the results of the asset gather process. + * Internally it is an array, but it acts like a FIFO queue. Items are pushed and appended, and then popped off for processing. + * The difference between it and a standard queue are that the popped items aren't removed until the container is trimmed, + * which allows multiple results to be processed per-trim with a minimal amount of array reshuffling (since we're removing from the front). + */ +template +class TBackgroundGatherResults +{ +public: + /** Constructor. */ + TBackgroundGatherResults() + : PoppedCount(0) + { + } + + /** Push the given item onto the end of the queue. */ + FORCEINLINE void Push(const T& Item) + { + InternalQueue.Add(Item); + } + + /** Push the given item onto the end of the queue. */ + FORCEINLINE void Push(T&& Item) + { + InternalQueue.Add(MoveTemp(Item)); + } + + /** Append the given items onto the end of the queue. */ + FORCEINLINE void Append(const TArray& Items) + { + InternalQueue.Append(Items); + } + + /** Append the given items onto the end of the queue. */ + FORCEINLINE void Append(TArray&& Items) + { + InternalQueue.Append(MoveTemp(Items)); + } + + /** Pop an item from the front of the queue. The returned data is valid until the queue is trimmed. */ + FORCEINLINE T& Pop() + { + return InternalQueue[PoppedCount++]; + } + + /** Trim any popped items from this queue. */ + FORCEINLINE void Trim() + { + if (PoppedCount > 0) + { + InternalQueue.RemoveAt(0, PoppedCount); + PoppedCount = 0; + } + } + + /** Get the number of items left to process in this queue. */ + FORCEINLINE int32 Num() const + { + return InternalQueue.Num() - PoppedCount; + } + + /** Empty the queue, keeping the current allocation. */ + FORCEINLINE void Reset() + { + PoppedCount = 0; + InternalQueue.Reset(); + } + + /** Empty the queue, discarding the current allocation. */ + FORCEINLINE void Empty() + { + PoppedCount = 0; + InternalQueue.Empty(); + } + + /** Gets the size of the current allocation */ + FORCEINLINE uint32 GetAllocatedSize() const + { + return InternalQueue.GetAllocatedSize(); + } + + /** Prioritize any items that pass the given predicate to be at the front of the queue. */ + void Prioritize(TFunctionRef Pred) + { + int32 LowestNonPriorityIdx = PoppedCount; + for (int32 Idx = PoppedCount; Idx < InternalQueue.Num(); ++Idx) + { + if (Pred(InternalQueue[Idx])) + { + InternalQueue.Swap(Idx, LowestNonPriorityIdx++); + } + } + } + + + +private: + typedef TArray InternalQueueType; + typedef typename InternalQueueType::RangedForIteratorType RangedForIteratorType; + typedef typename InternalQueueType::RangedForConstIteratorType RangedForConstIteratorType; + + /** + * DO NOT USE DIRECTLY + * STL-like iterators to enable range-based for loop support. + */ + #if TARRAY_RANGED_FOR_CHECKS + FORCEINLINE friend RangedForIteratorType begin( TBackgroundGatherResults& Results) { return RangedForIteratorType (Results.InternalQueue.Num(), Results.InternalQueue.GetData() + Results.PoppedCount); } + FORCEINLINE friend RangedForConstIteratorType begin(const TBackgroundGatherResults& Results) { return RangedForConstIteratorType(Results.InternalQueue.Num(), Results.InternalQueue.GetData() + Results.PoppedCount); } + FORCEINLINE friend RangedForIteratorType end ( TBackgroundGatherResults& Results) { return RangedForIteratorType (Results.InternalQueue.Num(), Results.InternalQueue.GetData() + Results.InternalQueue.Num()); } + FORCEINLINE friend RangedForConstIteratorType end (const TBackgroundGatherResults& Results) { return RangedForConstIteratorType(Results.InternalQueue.Num(), Results.InternalQueue.GetData() + Results.InternalQueue.Num()); } + #else + FORCEINLINE friend RangedForIteratorType begin( TBackgroundGatherResults& Results) { return Results.InternalQueue.GetData() + Results.PoppedCount; } + FORCEINLINE friend RangedForConstIteratorType begin(const TBackgroundGatherResults& Results) { return Results.InternalQueue.GetData() + Results.PoppedCount; } + FORCEINLINE friend RangedForIteratorType end ( TBackgroundGatherResults& Results) { return Results.InternalQueue.GetData() + Results.InternalQueue.Num(); } + FORCEINLINE friend RangedForConstIteratorType end (const TBackgroundGatherResults& Results) { return Results.InternalQueue.GetData() + Results.InternalQueue.Num(); } + #endif + +private: + /** Number of items that have been popped off the queue without it being trimmed. Items before this count should not be mutated, and we should trim to this number. */ + int32 PoppedCount; + + /** Internal FIFO queue of data. */ + InternalQueueType InternalQueue; +}; diff --git a/Engine/Source/Runtime/AssetRegistry/Private/DependsNode.cpp b/Engine/Source/Runtime/AssetRegistry/Private/DependsNode.cpp index b0d75c030fb7..1435c714f42e 100644 --- a/Engine/Source/Runtime/AssetRegistry/Private/DependsNode.cpp +++ b/Engine/Source/Runtime/AssetRegistry/Private/DependsNode.cpp @@ -72,11 +72,18 @@ void FDependsNode::GetReferencers(TArray& OutReferencers, EAssetR } } -void FDependsNode::AddDependency(FDependsNode* InDependency, EAssetRegistryDependencyType::Type InDependencyType) +void FDependsNode::AddDependency(FDependsNode* InDependency, EAssetRegistryDependencyType::Type InDependencyType, bool bGuaranteedUnique) { - IterateOverDependencyArrays([InDependency](TArray& InArray, EAssetRegistryDependencyType::Type) + IterateOverDependencyArrays([InDependency,&bGuaranteedUnique](TArray& InArray, EAssetRegistryDependencyType::Type) { - InArray.AddUnique(InDependency); + if (bGuaranteedUnique) + { + InArray.Add(InDependency); + } + else + { + InArray.AddUnique(InDependency); + } }, InDependencyType); } diff --git a/Engine/Source/Runtime/AssetRegistry/Private/DependsNode.h b/Engine/Source/Runtime/AssetRegistry/Private/DependsNode.h index 26e2eb91f845..ab45bc01499d 100644 --- a/Engine/Source/Runtime/AssetRegistry/Private/DependsNode.h +++ b/Engine/Source/Runtime/AssetRegistry/Private/DependsNode.h @@ -34,9 +34,9 @@ public: /** Sets the entire identifier */ void SetIdentifier(const FAssetIdentifier& InIdentifier) { Identifier = InIdentifier; } /** Add a dependency to this node */ - void AddDependency(FDependsNode* InDependency, EAssetRegistryDependencyType::Type InDependencyType = EAssetRegistryDependencyType::Hard); + void AddDependency(FDependsNode* InDependency, EAssetRegistryDependencyType::Type InDependencyType = EAssetRegistryDependencyType::Hard, bool bGuaranteedUnique = false); /** Add a referencer to this node */ - void AddReferencer(FDependsNode* InReferencer) { Referencers.AddUnique(InReferencer); } + void AddReferencer(FDependsNode* InReferencer, bool bGuaranteedUnique = false) { bGuaranteedUnique ? Referencers.Add(InReferencer) : Referencers.AddUnique(InReferencer); } /** Remove a dependency from this node */ void RemoveDependency(FDependsNode* InDependency); /** Remove a referencer from this node */ @@ -47,6 +47,11 @@ public: void RemoveManageReferencesToNode(); /** Returns number of connections this node has, both references and dependencies */ int32 GetConnectionCount() const; + /** Returns amount of memory used by the arrays */ + uint32 GetAllocatedSize(void) const + { + return HardDependencies.GetAllocatedSize() + SoftDependencies.GetAllocatedSize() + NameDependencies.GetAllocatedSize() + ManageDependencies.GetAllocatedSize() + Referencers.GetAllocatedSize(); + } /** Iterate over all the dependencies of this node, filtered by the supplied type parameter, and call the supplied lambda parameter on the record */ template diff --git a/Engine/Source/Runtime/AssetRegistry/Private/DiskCachedAssetData.h b/Engine/Source/Runtime/AssetRegistry/Private/DiskCachedAssetData.h index d37c96124f13..03b533c7d841 100644 --- a/Engine/Source/Runtime/AssetRegistry/Private/DiskCachedAssetData.h +++ b/Engine/Source/Runtime/AssetRegistry/Private/DiskCachedAssetData.h @@ -20,23 +20,27 @@ public: : Timestamp(InTimestamp) {} - /** Operator for serialization */ - friend FArchive& operator<<(FArchive& Ar, FDiskCachedAssetData& DiskCachedAssetData) + /** + * Serialize as part of the registry cache. This is not meant to be serialized as part of a package so it does not handle versions normally + * To version this data change FAssetRegistryVersion or CacheSerializationVersion + */ + void SerializeForCache(FArchive& Ar) { - Ar << DiskCachedAssetData.Timestamp; - if (Ar.IsError()) + Ar << Timestamp; + + int32 AssetDataCount = AssetDataList.Num(); + Ar << AssetDataCount; + + if (Ar.IsLoading()) { - return Ar; + AssetDataList.SetNum(AssetDataCount); } - Ar << DiskCachedAssetData.AssetDataList; - if (Ar.IsError()) + for (int32 i = 0; i < AssetDataCount; i++) { - return Ar; + AssetDataList[i].SerializeForCache(Ar); } - Ar << DiskCachedAssetData.DependencyData; - - return Ar; + DependencyData.SerializeForCache(Ar); } }; diff --git a/Engine/Source/Runtime/AssetRegistry/Private/NameTableArchive.cpp b/Engine/Source/Runtime/AssetRegistry/Private/NameTableArchive.cpp index fe293f044b25..740a1f2c7a41 100644 --- a/Engine/Source/Runtime/AssetRegistry/Private/NameTableArchive.cpp +++ b/Engine/Source/Runtime/AssetRegistry/Private/NameTableArchive.cpp @@ -156,6 +156,31 @@ int64 FNameTableArchiveReader::TotalSize() return 0; } +const FCustomVersionContainer& FNameTableArchiveReader::GetCustomVersions() const +{ + if (ProxyAr) + { + return ProxyAr->GetCustomVersions(); + } + return FArchive::GetCustomVersions(); +} + +void FNameTableArchiveReader::SetCustomVersions(const FCustomVersionContainer& NewVersions) +{ + if (ProxyAr) + { + ProxyAr->SetCustomVersions(NewVersions); + } +} + +void FNameTableArchiveReader::ResetCustomVersions() +{ + if (ProxyAr) + { + ProxyAr->ResetCustomVersions(); + } +} + FArchive& FNameTableArchiveReader::operator<<( FName& Name ) { int32 NameIndex; @@ -323,6 +348,31 @@ int64 FNameTableArchiveWriter::TotalSize() return 0.f; } +const FCustomVersionContainer& FNameTableArchiveWriter::GetCustomVersions() const +{ + if (ProxyAr) + { + return ProxyAr->GetCustomVersions(); + } + return FArchive::GetCustomVersions(); +} + +void FNameTableArchiveWriter::SetCustomVersions(const FCustomVersionContainer& NewVersions) +{ + if (ProxyAr) + { + ProxyAr->SetCustomVersions(NewVersions); + } +} + +void FNameTableArchiveWriter::ResetCustomVersions() +{ + if (ProxyAr) + { + ProxyAr->ResetCustomVersions(); + } +} + FArchive& FNameTableArchiveWriter::operator<<( FName& Name ) { int32* NameIndexPtr = NameMap.Find(Name); diff --git a/Engine/Source/Runtime/AssetRegistry/Private/NameTableArchive.h b/Engine/Source/Runtime/AssetRegistry/Private/NameTableArchive.h index 9211f864b145..1ed81db18d7f 100644 --- a/Engine/Source/Runtime/AssetRegistry/Private/NameTableArchive.h +++ b/Engine/Source/Runtime/AssetRegistry/Private/NameTableArchive.h @@ -35,11 +35,14 @@ public: ~FNameTableArchiveReader(); // Farchive implementation to redirect requests to the wrapped archive - virtual void Serialize(void* V, int64 Length); - virtual bool Precache(int64 PrecacheOffset, int64 PrecacheSize); - virtual void Seek(int64 InPos); - virtual int64 Tell(); - virtual int64 TotalSize(); + virtual void Serialize(void* V, int64 Length) override; + virtual bool Precache(int64 PrecacheOffset, int64 PrecacheSize) override; + virtual void Seek(int64 InPos) override; + virtual int64 Tell() override; + virtual int64 TotalSize() override; + virtual const FCustomVersionContainer& GetCustomVersions() const override; + virtual void SetCustomVersions(const FCustomVersionContainer& NewVersions) override; + virtual void ResetCustomVersions() override; virtual FArchive& operator<<(FName& Name); private: @@ -63,11 +66,14 @@ public: ~FNameTableArchiveWriter(); // Farchive implementation to redirect requests to the wrapped archive - virtual void Serialize(void* V, int64 Length); - virtual bool Precache(int64 PrecacheOffset, int64 PrecacheSize); - virtual void Seek(int64 InPos); - virtual int64 Tell(); - virtual int64 TotalSize(); + virtual void Serialize(void* V, int64 Length) override; + virtual bool Precache(int64 PrecacheOffset, int64 PrecacheSize) override; + virtual void Seek(int64 InPos) override; + virtual int64 Tell() override; + virtual int64 TotalSize() override; + virtual const FCustomVersionContainer& GetCustomVersions() const override; + virtual void SetCustomVersions(const FCustomVersionContainer& NewVersions) override; + virtual void ResetCustomVersions() override; virtual FArchive& operator<<(FName& Name); private: diff --git a/Engine/Source/Runtime/AssetRegistry/Private/PackageDependencyData.h b/Engine/Source/Runtime/AssetRegistry/Private/PackageDependencyData.h index 45a7930afcd6..3ffd0d3e5750 100644 --- a/Engine/Source/Runtime/AssetRegistry/Private/PackageDependencyData.h +++ b/Engine/Source/Runtime/AssetRegistry/Private/PackageDependencyData.h @@ -24,16 +24,17 @@ public: */ FName GetImportPackageName(int32 ImportIndex); - /** Operator for serialization */ - friend FArchive& operator<<(FArchive& Ar, FPackageDependencyData& DependencyData) + /** + * Serialize as part of the registry cache. This is not meant to be serialized as part of a package so it does not handle versions normally + * To version this data change FAssetRegistryVersion or CacheSerializationVersion + */ + void SerializeForCache(FArchive& Ar) { - // serialize out the asset info, this is tied to CacheSerializationVersion - Ar << DependencyData.PackageName; - Ar << DependencyData.PackageData; - Ar << DependencyData.ImportMap; - Ar << DependencyData.StringAssetReferencesMap; - Ar << DependencyData.SearchableNamesMap; + Ar << PackageName; + Ar << ImportMap; + Ar << StringAssetReferencesMap; + Ar << SearchableNamesMap; - return Ar; + PackageData.SerializeForCache(Ar); } }; diff --git a/Engine/Source/Runtime/AssetRegistry/Private/PackageReader.cpp b/Engine/Source/Runtime/AssetRegistry/Private/PackageReader.cpp index b15d68ae629f..c9b15fae5005 100644 --- a/Engine/Source/Runtime/AssetRegistry/Private/PackageReader.cpp +++ b/Engine/Source/Runtime/AssetRegistry/Private/PackageReader.cpp @@ -159,11 +159,11 @@ bool FPackageReader::ReadAssetRegistryData (TArray& AssetDataList) if (bLegacyPackage || bNoMapAsset) { FString AssetName = FPackageName::GetLongPackageAssetName(PackageName); - AssetDataList.Add(new FAssetData(FName(*PackageName), FName(*PackagePath), FName(), MoveTemp(FName(*AssetName)), FName(TEXT("World")), TMap(), PackageFileSummary.ChunkIDs, PackageFileSummary.PackageFlags)); + AssetDataList.Add(new FAssetData(FName(*PackageName), FName(*PackagePath), MoveTemp(FName(*AssetName)), FName(TEXT("World")), FAssetDataTagMap(), PackageFileSummary.ChunkIDs, PackageFileSummary.PackageFlags)); } } - // UAsset files only have one object, but legacy or map packages may have more. + // UAsset files usually only have one asset, maps and redirectors have multiple for(int32 ObjectIdx = 0; ObjectIdx < ObjectCount; ++ObjectIdx) { FString ObjectPath; @@ -173,7 +173,7 @@ bool FPackageReader::ReadAssetRegistryData (TArray& AssetDataList) *this << ObjectClassName; *this << TagCount; - TMap TagsAndValues; + FAssetDataTagMap TagsAndValues; TagsAndValues.Reserve(TagCount); for(int32 TagIdx = 0; TagIdx < TagCount; ++TagIdx) @@ -183,21 +183,26 @@ bool FPackageReader::ReadAssetRegistryData (TArray& AssetDataList) *this << Key; *this << Value; - TagsAndValues.Add(FName(*Key), Value); + if (!Key.IsEmpty() && !Value.IsEmpty()) + { + TagsAndValues.Add(FName(*Key), Value); + } } - FString GroupNames; - FString AssetName; + if (ObjectPath.StartsWith(TEXT("/"), ESearchCase::CaseSensitive)) + { + // This should never happen, it means that package A has an export with an outer of package B + UE_LOG(LogAssetRegistry, Warning, TEXT("Package %s has invalid export %s, resave source package!"), *PackageName, *ObjectPath); + continue; + } - if ( ObjectPath.Contains(TEXT("."), ESearchCase::CaseSensitive)) + if (!ensureMsgf(!ObjectPath.Contains(TEXT("."), ESearchCase::CaseSensitive), TEXT("Cannot make FAssetData for sub object %s!"), *ObjectPath)) { - ObjectPath.Split(TEXT("."), &GroupNames, &AssetName, ESearchCase::CaseSensitive, ESearchDir::FromEnd); - } - else - { - AssetName = ObjectPath; + continue; } + FString AssetName = ObjectPath; + // Before world were RF_Public, other non-public assets were added to the asset data table in map packages. // Here we simply skip over them if ( bIsMapPackage && PackageFileSummary.GetFileVersionUE4() < VER_UE4_PUBLIC_WORLDS ) @@ -209,7 +214,7 @@ bool FPackageReader::ReadAssetRegistryData (TArray& AssetDataList) } // Create a new FAssetData for this asset and update it with the gathered data - AssetDataList.Add(new FAssetData(FName(*PackageName), FName(*PackagePath), MoveTemp(FName(*GroupNames)), MoveTemp(FName(*AssetName)), MoveTemp(FName(*ObjectClassName)), MoveTemp(TagsAndValues), PackageFileSummary.ChunkIDs, PackageFileSummary.PackageFlags)); + AssetDataList.Add(new FAssetData(FName(*PackageName), FName(*PackagePath), MoveTemp(FName(*AssetName)), MoveTemp(FName(*ObjectClassName)), MoveTemp(TagsAndValues), PackageFileSummary.ChunkIDs, PackageFileSummary.PackageFlags)); } return true; @@ -254,17 +259,13 @@ bool FPackageReader::ReadAssetDataFromThumbnailCache(TArray& AssetD FString GroupNames; FString AssetName; - if ( ObjectPathWithoutPackageName.Contains(TEXT("."), ESearchCase::CaseSensitive) ) + if (!ensureMsgf(!ObjectPathWithoutPackageName.Contains(TEXT("."), ESearchCase::CaseSensitive), TEXT("Cannot make FAssetData for sub object %s!"), *ObjectPathWithoutPackageName)) { - ObjectPathWithoutPackageName.Split(TEXT("."), &GroupNames, &AssetName, ESearchCase::CaseSensitive, ESearchDir::FromEnd); - } - else - { - AssetName = ObjectPathWithoutPackageName; + continue; } // Create a new FAssetData for this asset and update it with the gathered data - AssetDataList.Add(new FAssetData(FName(*PackageName), FName(*PackagePath), MoveTemp(FName(*GroupNames)), MoveTemp(FName(*AssetName)), MoveTemp(FName(*AssetClassName)), TMap(), PackageFileSummary.ChunkIDs, PackageFileSummary.PackageFlags)); + AssetDataList.Add(new FAssetData(FName(*PackageName), FName(*PackagePath), MoveTemp(FName(*ObjectPathWithoutPackageName)), MoveTemp(FName(*AssetClassName)), FAssetDataTagMap(), PackageFileSummary.ChunkIDs, PackageFileSummary.PackageFlags)); } return true; @@ -295,10 +296,6 @@ bool FPackageReader::ReadAssetRegistryDataIfCookedPackage(TArray& A { if (Export.bIsAsset) { - FString GroupNames; // Not used for anything - TMap Tags; // Not used for anything - TArray ChunkIDs; // Not used for anything - // We need to get the class name from the import/export maps FName ObjectClassName; if (Export.ClassIndex.IsNull()) @@ -316,7 +313,7 @@ bool FPackageReader::ReadAssetRegistryDataIfCookedPackage(TArray& A ObjectClassName = ClassImport.ObjectName; } - AssetDataList.Add(new FAssetData(FName(*PackageName), FName(*PackagePath), FName(*GroupNames), Export.ObjectName, ObjectClassName, Tags, ChunkIDs, GetPackageFlags())); + AssetDataList.Add(new FAssetData(FName(*PackageName), FName(*PackagePath), Export.ObjectName, ObjectClassName, FAssetDataTagMap(), TArray(), GetPackageFlags())); bFoundAtLeastOneAsset = true; } } diff --git a/Engine/Source/Runtime/AssetRegistry/Private/PathTree.h b/Engine/Source/Runtime/AssetRegistry/Private/PathTree.h index 2faccfe77c48..a4dee28e2162 100644 --- a/Engine/Source/Runtime/AssetRegistry/Private/PathTree.h +++ b/Engine/Source/Runtime/AssetRegistry/Private/PathTree.h @@ -19,6 +19,11 @@ public: /** Recursively gathers all child paths from the specified base path relative to this node */ bool GetSubPaths(FName BasePath, TSet& OutPaths, bool bRecurse = true) const; + uint32 GetAllocatedSize(void) const + { + return ParentPathToChildPaths.GetAllocatedSize() + ChildPathToParentPath.GetAllocatedSize(); + } + private: /** A one-to-many mapping between a parent path and its child paths. */ TMap> ParentPathToChildPaths; diff --git a/Engine/Source/Runtime/AssetRegistry/Public/AssetBundleData.h b/Engine/Source/Runtime/AssetRegistry/Public/AssetBundleData.h index 607bd66585f0..4ebacf0d3fb2 100644 --- a/Engine/Source/Runtime/AssetRegistry/Public/AssetBundleData.h +++ b/Engine/Source/Runtime/AssetRegistry/Public/AssetBundleData.h @@ -11,7 +11,11 @@ USTRUCT() struct ASSETREGISTRY_API FAssetBundleEntry { - GENERATED_USTRUCT_BODY() + GENERATED_BODY() + + /** Declare constructors inline so this can be a header only class */ + FORCEINLINE FAssetBundleEntry() {} + FORCEINLINE ~FAssetBundleEntry() {} /** Asset this bundle is saved within. This is empty for global bundles, or in the saved bundle info */ UPROPERTY() @@ -25,9 +29,6 @@ struct ASSETREGISTRY_API FAssetBundleEntry UPROPERTY() TArray BundleAssets; - FAssetBundleEntry() - {} - FAssetBundleEntry(const FAssetBundleEntry& OldEntry) : BundleScope(OldEntry.BundleScope), BundleName(OldEntry.BundleName), BundleAssets(OldEntry.BundleAssets) { @@ -51,7 +52,11 @@ struct ASSETREGISTRY_API FAssetBundleEntry USTRUCT() struct ASSETREGISTRY_API FAssetBundleData { - GENERATED_USTRUCT_BODY() + GENERATED_BODY() + + /** Declare constructors inline so this can be a header only class */ + FORCEINLINE FAssetBundleData() {} + FORCEINLINE ~FAssetBundleData() {} /** List of bundles defined */ UPROPERTY() @@ -75,7 +80,24 @@ struct ASSETREGISTRY_API FAssetBundleData /** Adds multiple assets at once */ void AddBundleAssets(FName BundleName, const TArray& AssetPaths); + /** A fast set of asset bundle assets, will destroy copied in path list */ + void SetBundleAssets(FName BundleName, TArray&& AssetPaths); + /** Resets the data to defaults */ void Reset(); + /** Override Import/Export to not write out empty structs */ + bool ExportTextItem(FString& ValueStr, FAssetBundleData const& DefaultValue, UObject* Parent, int32 PortFlags, UObject* ExportRootScope) const; + bool ImportTextItem(const TCHAR*& Buffer, int32 PortFlags, UObject* Parent, FOutputDevice* ErrorText); + +}; + +template<> +struct TStructOpsTypeTraits : public TStructOpsTypeTraitsBase2 +{ + enum + { + WithExportTextItem = true, + WithImportTextItem = true, + }; }; diff --git a/Engine/Source/Runtime/AssetRegistry/Public/AssetData.h b/Engine/Source/Runtime/AssetRegistry/Public/AssetData.h index 33f886ab6551..dfcb176966a0 100644 --- a/Engine/Source/Runtime/AssetRegistry/Public/AssetData.h +++ b/Engine/Source/Runtime/AssetRegistry/Public/AssetData.h @@ -12,30 +12,53 @@ #include "Misc/PackageName.h" #include "Misc/SecureHash.h" #include "UObject/LinkerLoad.h" -#include "SharedMapView.h" +#include "AssetDataTagMap.h" #include "PrimaryAssetId.h" ASSETREGISTRY_API DECLARE_LOG_CATEGORY_EXTERN(LogAssetData, Log, All); +/** Version used for serializing asset registry caches, both runtime and editor */ +struct ASSETREGISTRY_API FAssetRegistryVersion +{ + enum Type + { + PreVersioning = 0, // From before file versioning was implemented + HardSoftDependencies, // The first version of the runtime asset registry to include file versioning. + AddAssetRegistryState, // Added FAssetRegistryState and support for piecemeal serialization + ChangedAssetData, // AssetData serialization format changed, versions before this are not readable + + // ------------------------------------------------------ + VersionPlusOne, + LatestVersion = VersionPlusOne - 1 + }; + + /** The GUID for this custom version number */ + const static FGuid GUID; + + /** Read/write the custom version to the archive, should call at the very beginning */ + static bool SerializeVersion(FArchive& Ar, FAssetRegistryVersion::Type& Version); + +private: + FAssetRegistryVersion() {} +}; + /** A class to hold important information about an assets found by the Asset Registry */ class FAssetData { public: - /** The object path for the asset in the form 'Package.GroupNames.AssetName' */ + /** The object path for the asset in the form PackageName.AssetName. Only top level objects in a package can have AssetData */ FName ObjectPath; - /** The name of the package in which the asset is found */ + /** The name of the package in which the asset is found, this is the full long package name such as /Game/Path/Package */ FName PackageName; - /** The path to the package in which the asset is found */ + /** The path to the package in which the asset is found, this is /Game/Path with the Package stripped off */ FName PackagePath; - /** The '.' delimited list of group names in which the asset is found. NAME_None if there were no groups */ - FName GroupNames; - /** The name of the asset without the package or groups */ + /** The name of the asset without the package */ FName AssetName; /** The name of the asset's class */ FName AssetClass; - /** The map of values for properties that were marked AssetRegistrySearchable */ - TSharedMapView TagsAndValues; + /** The map of values for properties that were marked AssetRegistrySearchable or added by GetAssetRegistryTags */ + FAssetDataTagMapSharedView TagsAndValues; /** The IDs of the chunks this asset is located in for streaming install. Empty if not assigned to a chunk */ TArray ChunkIDs; /** Asset package flags */ @@ -47,65 +70,56 @@ public: {} /** Constructor */ - FAssetData(FName InPackageName, FName InPackagePath, FName InGroupNames, FName InAssetName, FName InAssetClass, TMap InTags, TArray InChunkIDs, uint32 InPackageFlags) + FAssetData(FName InPackageName, FName InPackagePath, FName InAssetName, FName InAssetClass, FAssetDataTagMap InTags = FAssetDataTagMap(), TArray InChunkIDs = TArray(), uint32 InPackageFlags = 0) : PackageName(InPackageName) , PackagePath(InPackagePath) - , GroupNames(InGroupNames) , AssetName(InAssetName) , AssetClass(InAssetClass) - , TagsAndValues(MakeSharedMapView(MoveTemp(InTags))) + , TagsAndValues(MoveTemp(InTags)) , ChunkIDs(MoveTemp(InChunkIDs)) , PackageFlags(InPackageFlags) { FString ObjectPathStr = PackageName.ToString() + TEXT("."); - if ( GroupNames != NAME_None ) - { - ObjectPathStr += GroupNames.ToString() + TEXT("."); - } - ObjectPathStr += AssetName.ToString(); ObjectPath = FName(*ObjectPathStr); } - /** Constructor taking a UObject */ - FAssetData(const UObject* InAsset) + /** Constructor taking a UObject. By default trying to create one for a blueprint class will create one for the UBlueprint instead, but this can be overridden */ + FAssetData(const UObject* InAsset, bool bAllowBlueprintClass = false) { - if ( InAsset != NULL ) + if ( InAsset != nullptr ) { const UClass* InClass = Cast(InAsset); - if (InClass && InClass->ClassGeneratedBy) + if (InClass && InClass->ClassGeneratedBy && !bAllowBlueprintClass) { - // this UObject was generated by another class, use the generator to identify - // the source asset: + // For Blueprints, the AssetData refers to the UBlueprint and not the UBlueprintGeneratedClass InAsset = InClass->ClassGeneratedBy; } const UPackage* Outermost = InAsset->GetOutermost(); - // Find the group names - FString GroupNamesStr; - FString AssetNameStr; - InAsset->GetPathName(Outermost).Split(TEXT("."), &GroupNamesStr, &AssetNameStr, ESearchCase::CaseSensitive); - PackageName = Outermost->GetFName(); PackagePath = FName(*FPackageName::GetLongPackagePath(Outermost->GetName())); - GroupNames = FName(*GroupNamesStr); AssetName = InAsset->GetFName(); AssetClass = InAsset->GetClass()->GetFName(); ObjectPath = FName(*InAsset->GetPathName()); - TArray TagList; - InAsset->GetAssetRegistryTags(TagList); + TArray ObjectTags; + InAsset->GetAssetRegistryTags(ObjectTags); - TMap TagsAndValuesMap; - for ( auto TagIt = TagList.CreateConstIterator(); TagIt; ++TagIt ) + FAssetDataTagMap NewTagsAndValues; + for (UObject::FAssetRegistryTag& AssetRegistryTag : ObjectTags) { - TagsAndValuesMap.Add(TagIt->Name, TagIt->Value); + if (AssetRegistryTag.Name != NAME_None && !AssetRegistryTag.Value.IsEmpty()) + { + // Don't add empty tags + NewTagsAndValues.Add(AssetRegistryTag.Name, AssetRegistryTag.Value); + } } - TagsAndValues = MakeSharedMapView(MoveTemp(TagsAndValuesMap)); + TagsAndValues = FAssetDataTagMapSharedView(MoveTemp(NewTagsAndValues)); ChunkIDs = Outermost->GetChunkIDs(); PackageFlags = Outermost->GetPackageFlags(); } @@ -294,7 +308,6 @@ public: UE_LOG(LogAssetData, Log, TEXT(" =============================")); UE_LOG(LogAssetData, Log, TEXT(" PackageName: %s"), *PackageName.ToString()); UE_LOG(LogAssetData, Log, TEXT(" PackagePath: %s"), *PackagePath.ToString()); - UE_LOG(LogAssetData, Log, TEXT(" GroupNames: %s"), *GroupNames.ToString()); UE_LOG(LogAssetData, Log, TEXT(" AssetName: %s"), *AssetName.ToString()); UE_LOG(LogAssetData, Log, TEXT(" AssetClass: %s"), *AssetClass.ToString()); UE_LOG(LogAssetData, Log, TEXT(" TagsAndValues: %d"), TagsAndValues.Num()); @@ -339,38 +352,24 @@ public: return (T*)Asset; } - /** Operator for serialization */ - friend FArchive& operator<<(FArchive& Ar, FAssetData& AssetData) + /** + * Serialize as part of the registry cache. This is not meant to be serialized as part of a package so it does not handle versions normally + * To version this data change FAssetRegistryVersion + */ + void SerializeForCache(FArchive& Ar) { - // serialize out the asset info - Ar << AssetData.ObjectPath; - Ar << AssetData.PackagePath; - Ar << AssetData.AssetClass; - Ar << AssetData.GroupNames; + // Serialize out the asset info + Ar << ObjectPath; + Ar << PackagePath; + Ar << AssetClass; - // these are derived from ObjectPath, probably can skip serializing at the expense of runtime string manipulation - Ar << AssetData.PackageName; - Ar << AssetData.AssetName; + // These are derived from ObjectPath, we manually serialize them because they get pooled + Ar << PackageName; + Ar << AssetName; - Ar << const_cast&>(AssetData.TagsAndValues.GetMap()); - - if (Ar.UE4Ver() >= VER_UE4_CHANGED_CHUNKID_TO_BE_AN_ARRAY_OF_CHUNKIDS) - { - Ar << AssetData.ChunkIDs; - } - else if (Ar.UE4Ver() >= VER_UE4_ADDED_CHUNKID_TO_ASSETDATA_AND_UPACKAGE) - { - // loading old assetdata. we weren't using this value yet, so throw it away - int ChunkID = -1; - Ar << ChunkID; - } - - if (Ar.UE4Ver() >= VER_UE4_COOKED_ASSETS_IN_EDITOR_SUPPORT) - { - Ar << AssetData.PackageFlags; - } - - return Ar; + Ar << TagsAndValues; + Ar << ChunkIDs; + Ar << PackageFlags; } private: @@ -509,13 +508,15 @@ public: { } - friend FArchive& operator<<(FArchive& Ar, FAssetPackageData& PackageData) + /** + * Serialize as part of the registry cache. This is not meant to be serialized as part of a package so it does not handle versions normally + * To version this data change FAssetRegistryVersion + */ + void SerializeForCache(FArchive& Ar) { - Ar << PackageData.DiskSize; - Ar << PackageData.PackageGuid; - Ar << PackageData.PackageSourceHash; - - return Ar; + Ar << DiskSize; + Ar << PackageGuid; + Ar << PackageSourceHash; } }; @@ -665,6 +666,7 @@ struct FAssetIdentifier return Hash; } + /** Identifiers may be serialized as part of the registry cache, or in other contexts. If you make changes here you must also change FAssetRegistryVersion */ friend FArchive& operator<<(FArchive& Ar, FAssetIdentifier& AssetIdentifier) { // Serialize bitfield of which elements to serialize, in general many are empty diff --git a/Engine/Source/Runtime/AssetRegistry/Public/AssetDataTagMap.h b/Engine/Source/Runtime/AssetRegistry/Public/AssetDataTagMap.h new file mode 100644 index 000000000000..ad9b0dfbbff9 --- /dev/null +++ b/Engine/Source/Runtime/AssetRegistry/Public/AssetDataTagMap.h @@ -0,0 +1,166 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "SortedMap.h" + +/** Type of tag map that can be used during construction */ +typedef TSortedMap FAssetDataTagMap; + +/** Wrapper of shared pointer to a map */ +class FAssetDataTagMapSharedView +{ + +public: + /** Default constructor - empty map */ + FAssetDataTagMapSharedView() + { + } + + /** Constructor from an existing map pointer */ + FAssetDataTagMapSharedView(TSharedPtr InMap) + : Map(InMap) + { + } + + /** Constructor from an existing map pointer */ + FAssetDataTagMapSharedView(FAssetDataTagMap&& InMap) + { + if (InMap.Num()) + { + Map = MakeShareable(new FAssetDataTagMap(MoveTemp(InMap))); + } + } + + /** Find a value by key (nullptr if not found) */ + const FString* Find(FAssetDataTagMap::KeyConstPointerType Key) const + { + return GetMap().Find(Key); + } + + /** Find a value by key (abort if not found) */ + const FString& FindChecked(FAssetDataTagMap::KeyConstPointerType Key) const + { + return GetMap().FindChecked(Key); + } + + /** Find a value by key (default value if not found) */ + FString FindRef(FAssetDataTagMap::KeyConstPointerType Key) const + { + return GetMap().FindRef(Key); + } + + /** Determine whether a key is present in the map */ + bool Contains(FAssetDataTagMap::KeyConstPointerType Key) const + { + return GetMap().Contains(Key); + } + + /** Retrieve size of map */ + int32 Num() const + { + return GetMap().Num(); + } + + /** Populate an array with all the map's keys */ + template + int32 GetKeys(TArray& OutKeys) const + { + return GetMap().GetKeys(OutKeys); + } + + /** Populate an array with all the map's keys */ + template + void GenerateKeyArray(TArray& OutKeys) const + { + GetMap().GenerateKeyArray(OutKeys); + } + + /** Populate an array with all the map's values */ + template + void GenerateValueArray(TArray& OutValues) const + { + GetMap().GenerateValueArray(OutValues); + } + + /** Iterate all key-value pairs */ + FAssetDataTagMap::TConstIterator CreateConstIterator() const + { + return GetMap().CreateConstIterator(); + } + + /** Const access to the underlying map, mainly for taking a copy */ + const FAssetDataTagMap& GetMap() const + { + static FAssetDataTagMap EmptyMap; + + if (Map.IsValid()) + { + return *Map; + } + + return EmptyMap; + } + + /** Returns amount of extra memory used by this structure, including shared ptr overhead */ + uint32 GetAllocatedSize() const + { + uint32 AllocatedSize = 0; + if (Map.IsValid()) + { + AllocatedSize += sizeof(FAssetDataTagMap); // Map itself + AllocatedSize += (sizeof(int32) * 2); // SharedPtr overhead + AllocatedSize += Map->GetAllocatedSize(); + } + + return AllocatedSize; + } +private: + friend class FAssetData; + + FORCEINLINE friend FArchive& operator<<(FArchive& Ar, FAssetDataTagMapSharedView& SharedView) + { + if (Ar.IsSaving()) + { + if (SharedView.Map.IsValid()) + { + Ar << *SharedView.Map; + } + else + { + FAssetDataTagMap TempMap; + Ar << TempMap; + } + } + else + { + // Serialize into temporary map, if it isn't empty move memory into new map + FAssetDataTagMap TempMap; + Ar << TempMap; + + if (TempMap.Num()) + { + SharedView.Map = MakeShareable(new FAssetDataTagMap(MoveTemp(TempMap))); + } + } + + return Ar; + } + + /** Range for iterator access - DO NOT USE DIRECTLY */ + friend FAssetDataTagMap::RangedForConstIteratorType begin(const FAssetDataTagMapSharedView& View) + { + return begin(View.GetMap()); + } + + /** Range for iterator access - DO NOT USE DIRECTLY */ + friend FAssetDataTagMap::RangedForConstIteratorType end(const FAssetDataTagMapSharedView& View) + { + return end(View.GetMap()); + } + + /** Pointer to map being wrapped, it is created on demand */ + TSharedPtr Map; +}; + diff --git a/Engine/Source/Runtime/AssetRegistry/Public/AssetRegistryModule.h b/Engine/Source/Runtime/AssetRegistry/Public/AssetRegistryModule.h index 0649bfefe3eb..62a28fab67b9 100644 --- a/Engine/Source/Runtime/AssetRegistry/Public/AssetRegistryModule.h +++ b/Engine/Source/Runtime/AssetRegistry/Public/AssetRegistryModule.h @@ -67,6 +67,16 @@ public: } } + /** Notifies the asset registry that an in-memory package was deleted */ + static void PackageDeleted(UPackage* DeletedPackage) + { + if (GIsEditor) + { + FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(AssetRegistryConstants::ModuleName); + AssetRegistryModule.Get().PackageDeleted(DeletedPackage); + } + } + /** Access the dependent package names for a given source package */ void GetDependencies(FName InPackageName, TArray& OutDependencies, EAssetRegistryDependencyType::Type InDependencyType) override { diff --git a/Engine/Source/Runtime/AssetRegistry/Public/AssetRegistryState.h b/Engine/Source/Runtime/AssetRegistry/Public/AssetRegistryState.h index ae037a575a25..8e3d49a85c8a 100644 --- a/Engine/Source/Runtime/AssetRegistry/Public/AssetRegistryState.h +++ b/Engine/Source/Runtime/AssetRegistry/Public/AssetRegistryState.h @@ -8,7 +8,6 @@ class FDependsNode; struct FARFilter; -enum class ERuntimeRegistryVersion; /** Load/Save options used to modify how the cache is serialized. These are read out of the AssetRegistry section of Engine.ini and can be changed per platform. */ struct FAssetRegistrySerializationOptions @@ -31,6 +30,9 @@ struct FAssetRegistrySerializationOptions /** True if CookFilterlistTagsByClass is a whitelist. False if it is a blacklist. */ bool bUseAssetRegistryTagsWhitelistInsteadOfBlacklist; + /** True if we want to only write out asset data if it has valid tags. This saves memory by not saving data for things like textures */ + bool bFilterAssetDataWithNoTags; + /** The map of classname to tag set of tags that are allowed in cooked builds. This is either a whitelist or blacklist depending on bUseAssetRegistryTagsWhitelistInsteadOfBlacklist */ TMap> CookFilterlistTagsByClass; @@ -41,12 +43,14 @@ struct FAssetRegistrySerializationOptions , bSerializeManageDependencies(false) , bSerializePackageData(false) , bUseAssetRegistryTagsWhitelistInsteadOfBlacklist(false) + , bFilterAssetDataWithNoTags(false) {} /** Options used to read/write the DevelopmentAssetRegistry, which includes all data */ void ModifyForDevelopment() { bSerializeAssetRegistry = bSerializeDependencies = bSerializeSearchableNameDependencies = bSerializeManageDependencies = bSerializePackageData = true; + bFilterAssetDataWithNoTags = false; } }; @@ -57,6 +61,12 @@ public: FAssetRegistryState(); ~FAssetRegistryState(); + /** + * Does the given path contain assets? + * @note This function doesn't recurse into sub-paths. + */ + bool HasAssets(const FName PackagePath) const; + /** * Gets asset data for all assets that match the filter. * Assets returned must satisfy every filter component if there is at least one element in the component's array. @@ -112,10 +122,10 @@ public: } /** - * Gets the asset data for the specified object path + * Gets the asset data for the specified package name * - * @param ObjectPath the path of the object to be looked up - * @return the assets data, null if not found + * @param PackageName the path of the package to be looked up + * @return an array of AssetData*, empty if nothing found */ const TArray& GetAssetsByPackageName(const FName PackageName) const { @@ -129,6 +139,42 @@ public: return InvalidArray; } + /** + * Gets the asset data for the specified asset class + * + * @param ClassName the class name of the assets to look for + * @return An array of AssetData*, empty if nothing found + */ + const TArray& GetAssetsByClassName(const FName ClassName) const + { + static TArray InvalidArray; + const TArray* FoundAssetArray = CachedAssetsByClass.Find(ClassName); + if (FoundAssetArray) + { + return reinterpret_cast&>(*FoundAssetArray); + } + + return InvalidArray; + } + + /** + * Gets the asset data for the specified asset tag + * + * @param TagName the tag name to search for + * @return An array of AssetData*, empty if nothing found + */ + const TArray& GetAssetsByTagName(const FName TagName) const + { + static TArray InvalidArray; + const TArray* FoundAssetArray = CachedAssetsByTag.Find(TagName); + if (FoundAssetArray) + { + return reinterpret_cast&>(*FoundAssetArray); + } + + return InvalidArray; + } + /** Returns const version of internal ObjectPath->AssetData map for fast iteration */ const TMap& GetObjectPathToAssetDataMap() const { @@ -163,18 +209,26 @@ public: void Reset(); /** Initializes cache from existing set of asset data and depends nodes */ - void InitializeFromExisting(const TMap& AssetDataMap, const TMap& DependsNodeMap, const TMap& AssetPackageDataMap, const FAssetRegistrySerializationOptions& Options); - void InitializeFromExisting(const FAssetRegistryState& Existing, const FAssetRegistrySerializationOptions& Options) + void InitializeFromExisting(const TMap& AssetDataMap, const TMap& DependsNodeMap, const TMap& AssetPackageDataMap, const FAssetRegistrySerializationOptions& Options, bool bRefreshExisting = false); + void InitializeFromExisting(const FAssetRegistryState& Existing, const FAssetRegistrySerializationOptions& Options, bool bRefreshExisting = false) { - InitializeFromExisting(Existing.CachedAssetsByObjectPath, Existing.CachedDependsNodes, Existing.CachedPackageData, Options); + InitializeFromExisting(Existing.CachedAssetsByObjectPath, Existing.CachedDependsNodes, Existing.CachedPackageData, Options, bRefreshExisting); } - /** Prunes an asset cache, this removes asset data, nodes, and package data that isn't needed. If Required is empty it will only apply ignored */ - void PruneAssetData(const TSet& RequiredPackages, const TSet& RemovePackages); + /** + * Prunes an asset cache, this removes asset data, nodes, and package data that isn't needed. + * @param RequiredPackages If set, only these packages will be maintained. If empty it will keep all unless filtered by other parameters + * @param RemovePackages These packages will be removed from the current set + * @param bFilterAssetDataWithNoTags If true, any AssetData with no Tags will be removed + */ + void PruneAssetData(const TSet& RequiredPackages, const TSet& RemovePackages, bool bFilterAssetDataWithNoTags = false); /** Serialize the registry to/from a file, skipping editor only data */ bool Serialize(FArchive& Ar, FAssetRegistrySerializationOptions& Options); + /** Returns memory size of entire registry, optionally logging sizes */ + uint32 GetAllocatedSize(bool bLogDetailed = false) const; + /** Checks a filter to make sure there are no illegal entries */ static bool IsFilterValid(const FARFilter& Filter, bool bAllowRecursion); @@ -191,9 +245,6 @@ private: /** Removes the depends node and updates the dependencies to no longer contain it as as a referencer. */ bool RemoveDependsNode(const FAssetIdentifier& Identifier); - /** Reads old format asset registry state */ - bool ReadDeprecated(FArchive& Ar, ERuntimeRegistryVersion Version); - /** The map of ObjectPath names to asset data for assets saved to disk */ TMap CachedAssetsByObjectPath; diff --git a/Engine/Source/Runtime/AssetRegistry/Public/IAssetRegistry.h b/Engine/Source/Runtime/AssetRegistry/Public/IAssetRegistry.h index 793a94a950c5..9a855ca2746a 100644 --- a/Engine/Source/Runtime/AssetRegistry/Public/IAssetRegistry.h +++ b/Engine/Source/Runtime/AssetRegistry/Public/IAssetRegistry.h @@ -57,6 +57,14 @@ public: /** Virtual destructor*/ virtual ~IAssetRegistry() {} + /** + * Does the given path contain assets, optionally also testing sub-paths? + * + * @param PackagePath the path to query asset data in + * @param bRecursive if true, the supplied path will be tested recursively + */ + virtual bool HasAssets(const FName PackagePath, const bool bRecursive = false) const = 0; + /** * Gets asset data for the assets in the package with the specified package name * @@ -157,6 +165,9 @@ public: /** Finds Package data for a package name. This data is only updated on save and can only be accessed for valid packages */ virtual const FAssetPackageData* GetAssetPackageData(FName PackageName) const = 0; + /** Uses the asset registry to look for ObjectRedirectors. This will follow the chain of redirectors. It will return the original path if no redirectors are found */ + virtual FName GetRedirectedObjectPath(const FName ObjectPath) const = 0; + /** Returns true if the specified ClassName's ancestors could be found. If so, OutAncestorClassNames is a list of all its ancestors */ virtual bool GetAncestorClassNames(FName ClassName, TArray& OutAncestorClassNames) const = 0; @@ -302,14 +313,18 @@ public: /** Serialize the registry to/from a file, skipping editor only data */ virtual void Serialize(FArchive& Ar) = 0; + /** Returns memory size of entire registry, optionally logging sizes */ + virtual uint32 GetAllocatedSize(bool bLogDetailed = false) const = 0; + /** * Fills in a AssetRegistryState with a copy of the data in the internal cache, overriding some * - * @param OutState This will be filled in with a copy of the asset data, platform data, and dependency data - * @param Options Serialization options that will be used to write this later - * @param OverrideData Map of ObjectPath to AssetData. If non empty, it will use this map of AssetData, and will filter Platform/Dependency data to only include this set + * @param OutState This will be filled in with a copy of the asset data, platform data, and dependency data + * @param Options Serialization options that will be used to write this later + * @param bRefreshExisting If true, will not delete or add packages in OutState and will just update things that already exist + * @param OverrideData Map of ObjectPath to AssetData. If non empty, it will use this map of AssetData, and will filter Platform/Dependency data to only include this set */ - virtual void InitializeTemporaryAssetRegistryState(FAssetRegistryState& OutState, const FAssetRegistrySerializationOptions& Options, const TMap& OverrideData = TMap()) const = 0; + virtual void InitializeTemporaryAssetRegistryState(FAssetRegistryState& OutState, const FAssetRegistrySerializationOptions& Options, bool bRefreshExisting = false, const TMap& OverrideData = TMap()) const = 0; /** Fills in FAssetRegistrySerializationOptions from ini, optionally using a target platform ini name */ virtual void InitializeSerializationOptions(FAssetRegistrySerializationOptions& Options, const FString& PlatformIniName = FString()) const = 0; diff --git a/Engine/Source/Runtime/AssetRegistry/Public/SharedMapView.h b/Engine/Source/Runtime/AssetRegistry/Public/SharedMapView.h deleted file mode 100644 index 5ba50390642d..000000000000 --- a/Engine/Source/Runtime/AssetRegistry/Public/SharedMapView.h +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "CoreMinimal.h" - -struct FKey; - -/** Immutable wrapper of shared pointer to a map */ -template -class TSharedMapView -{ - typedef TMap FMap; -public: - /** Default constructor - empty map */ - TSharedMapView() : Map(new FMap()) - { - } - - /** Constructor from an existing map pointer */ - explicit TSharedMapView(TSharedRef InMap) - : Map(InMap) - { - } - - /** Find a value by key (nullptr if not found) */ - const FValue* Find(typename FMap::KeyConstPointerType Key) const - { - return Map->Find(Key); - } - - /** Find a value by key (abort if not found) */ - const FValue& FindChecked(typename FMap::KeyConstPointerType Key) const - { - return Map->FindChecked(Key); - } - - /** Find a value by key (default value if not found) */ - FValue FindRef(typename FMap::KeyConstPointerType Key) const - { - return Map->FindRef(Key); - } - - /** Determine whether a key is present in the map */ - bool Contains(typename FMap::KeyConstPointerType Key) const - { - return Map->Contains(Key); - } - - /** Retrieve size of map */ - int32 Num() const - { - return Map->Num(); - } - - /** Populate an array with all the map's keys */ - template - int32 GetKeys(TArray& OutKeys) const - { - return Map->GetKeys(OutKeys); - } - - /** Populate an array with all the map's keys */ - template - int32 GenerateKeyArray(TArray& OutKeys) const - { - return Map->GenerateKeyArray(OutKeys); - } - - /** Populate an array with all the map's values */ - template - int32 GenerateValueArray(TArray& OutValues) const - { - return Map->GenerateValueArray(OutValues); - } - - /** Iterate all key-value pairs */ - typename FMap::TConstIterator CreateConstIterator() const - { - return Map->CreateConstIterator(); - } - - /** Const access to the underlying map, mainly for taking a copy */ - const FMap& GetMap() const - { - return *Map; - } - - /** Range for iterator access - DO NOT USE DIRECTLY */ - friend typename FMap::TConstIterator begin(const TSharedMapView& View) - { - return begin(*View.Map); - } - - /** Range for iterator access - DO NOT USE DIRECTLY */ - friend typename FMap::TConstIterator end(const TSharedMapView& View) - { - return end(*View.Map); - } - -private: - /** Pointer to map being wrapped */ - TSharedRef Map; -}; - -/** Helper function to wrap a TMap in a TSharedMapView */ -template -TSharedMapView MakeSharedMapView(TMap Map) -{ - return TSharedMapView(MakeShareable(new TMap(MoveTemp(Map)))); -} diff --git a/Engine/Source/Runtime/AudioMixer/AudioMixer.Build.cs b/Engine/Source/Runtime/AudioMixer/AudioMixer.Build.cs index 69932593be03..c307563d5ef1 100644 --- a/Engine/Source/Runtime/AudioMixer/AudioMixer.Build.cs +++ b/Engine/Source/Runtime/AudioMixer/AudioMixer.Build.cs @@ -82,6 +82,12 @@ namespace UnrealBuildTool.Rules ); } - } + if (Target.Platform == UnrealTargetPlatform.XboxOne) + { + AddEngineThirdPartyPrivateStaticDependencies(Target, + "libOpus" + ); + } + } } } diff --git a/Engine/Source/Runtime/AudioMixer/Classes/SubmixEffects/AudioMixerSubmixEffectReverb.h b/Engine/Source/Runtime/AudioMixer/Classes/SubmixEffects/AudioMixerSubmixEffectReverb.h index 5a1191ff0aac..93c8f2793f00 100644 --- a/Engine/Source/Runtime/AudioMixer/Classes/SubmixEffects/AudioMixerSubmixEffectReverb.h +++ b/Engine/Source/Runtime/AudioMixer/Classes/SubmixEffects/AudioMixerSubmixEffectReverb.h @@ -7,7 +7,7 @@ #include "AudioEffect.h" #include "AudioMixerSubmixEffectReverb.generated.h" -USTRUCT() +USTRUCT(BlueprintType) struct AUDIOMIXER_API FSubmixEffectReverbSettings { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/AudioMixer/Private/AudioMixer.cpp b/Engine/Source/Runtime/AudioMixer/Private/AudioMixer.cpp index e61b7a4d86ba..3584d7326e41 100644 --- a/Engine/Source/Runtime/AudioMixer/Private/AudioMixer.cpp +++ b/Engine/Source/Runtime/AudioMixer/Private/AudioMixer.cpp @@ -19,15 +19,108 @@ DEFINE_STAT(STAT_AudioMixerMasterEQ); namespace Audio { + void FOutputBuffer::Init(IAudioMixer* InAudioMixer, const int32 InNumSamples, const EAudioMixerStreamDataFormat::Type InDataFormat) + { + Buffer.SetNumZeroed(InNumSamples); + DataFormat = InDataFormat; + AudioMixer = InAudioMixer; + + switch (DataFormat) + { + case EAudioMixerStreamDataFormat::Float: + // nothing to do... + break; + + case EAudioMixerStreamDataFormat::Int16: + FormattedBuffer.SetNumZeroed(InNumSamples * sizeof(int16)); + break; + + default: + // Not implemented/supported + check(false); + break; + } + } + + void FOutputBuffer::MixNextBuffer() + { + SCOPE_CYCLE_COUNTER(STAT_AudioMixerRenderAudio); + + // Zero the buffer + FPlatformMemory::Memzero(Buffer.GetData(), Buffer.Num() * sizeof(float)); + AudioMixer->OnProcessAudioStream(Buffer); + + switch (DataFormat) + { + // Doesn't do anything... + case EAudioMixerStreamDataFormat::Float: + break; + + case EAudioMixerStreamDataFormat::Int16: + { + int16* BufferInt16 = (int16*)FormattedBuffer.GetData(); + const int32 NumSamples = Buffer.Num(); + for (int32 i = 0; i < NumSamples; ++i) + { + BufferInt16[i] = (int16)(Buffer[i] * 32767.0f); + } + } + break; + + default: + // Not implemented/supported + check(false); + break; + } + + // Mark that we're ready + bIsReady = true; + } + + const uint8* FOutputBuffer::GetBufferData() + { + if (DataFormat == EAudioMixerStreamDataFormat::Float) + { + return (const uint8*)Buffer.GetData(); + } + else + { + return (const uint8*)FormattedBuffer.GetData(); + } + } + + void FOutputBuffer::Reset(const int32 InNewNumSamples) + { + Buffer.Reset(); + Buffer.AddZeroed(InNewNumSamples); + + switch (DataFormat) + { + // Doesn't do anything... + case EAudioMixerStreamDataFormat::Float: + break; + + case EAudioMixerStreamDataFormat::Int16: + { + FormattedBuffer.Reset(); + FormattedBuffer.AddZeroed(InNewNumSamples * sizeof(int16)); + } + break; + } + } + /** * IAudioMixerPlatformInterface */ IAudioMixerPlatformInterface::IAudioMixerPlatformInterface() - : AudioRenderThread(nullptr) + : bWarnedBufferUnderrun(false) + , AudioRenderThread(nullptr) , AudioRenderEvent(nullptr) , AudioFadeEvent(nullptr) - , CurrentBufferIndex(0) + , CurrentBufferReadIndex(INDEX_NONE) + , CurrentBufferWriteIndex(INDEX_NONE) + , NumOutputBuffers(0) , LastError(TEXT("None")) , bAudioDeviceChanging(false) , bFadingIn(true) @@ -65,7 +158,9 @@ namespace Audio } else { - TArray& Buffer = OutputBuffers[CurrentBufferIndex]; + FOutputBuffer& CurrentReadBuffer = OutputBuffers[CurrentBufferReadIndex]; + + TArray& Buffer = CurrentReadBuffer.GetBuffer(); const float Slope = 1.0f / Buffer.Num(); for (int32 i = 0; i < Buffer.Num(); ++i) { @@ -88,7 +183,9 @@ namespace Audio } else { - TArray& Buffer = OutputBuffers[CurrentBufferIndex]; + FOutputBuffer& CurrentReadBuffer = OutputBuffers[CurrentBufferReadIndex]; + + TArray& Buffer = CurrentReadBuffer.GetBuffer(); const float Slope = 1.0f / Buffer.Num(); for (int32 i = 0; i < Buffer.Num(); ++i) { @@ -101,7 +198,8 @@ namespace Audio if (bFadedOut) { // If we're faded out, then just zero the data. - TArray& Buffer = OutputBuffers[CurrentBufferIndex]; + FOutputBuffer& CurrentReadBuffer = OutputBuffers[CurrentBufferReadIndex]; + TArray& Buffer = CurrentReadBuffer.GetBuffer(); FPlatformMemory::Memzero(Buffer.GetData(), sizeof(float)*Buffer.Num()); } } @@ -114,47 +212,78 @@ namespace Audio return; } - PerformFades(); + check(CurrentBufferReadIndex != INDEX_NONE); + check(CurrentBufferWriteIndex != INDEX_NONE); - // We know that the last buffer has been consumed at this point so lets kick off the rendering of the next buffer now to overlap it with the submission of this buffer + // Reset the ready state of the buffer which was just finished playing + FOutputBuffer& CurrentReadBuffer = OutputBuffers[CurrentBufferReadIndex]; + CurrentReadBuffer.ResetReadyState(); - // Remember the buffer we will be submitting before we switch it - uint32 myBufferIndex = CurrentBufferIndex; + // Get the next index that we want to read + int32 NextReadIndex = (CurrentBufferReadIndex + 1) % NumOutputBuffers; - // Switch to the next buffer - CurrentBufferIndex = !CurrentBufferIndex; - - // Kick off rendering of the next buffer - AudioRenderEvent->Trigger(); - - // Ensure we have a buffer ready to be consumed, if we don't that means the audio processing thread can not keep up - if(OutputBufferReady[myBufferIndex] == false) + // If it's not ready, warn, and then wait here. This will cause underruns but is preferable than getting out-of-order buffer state. + static int32 UnderrunCount = 0; + static int32 CurrentUnderrunCount = 0; + + if (!OutputBuffers[NextReadIndex].IsReady()) { - if(!WarnedBufferUnderrun) - { - UE_LOG(LogAudioMixer, Warning, TEXT("Audio thread is not keeping up with the device, audio may stutter, try increasing buffer size or boosting the audio thread priority")); - WarnedBufferUnderrun = true; + + UnderrunCount++; + CurrentUnderrunCount++; + + if (!bWarnedBufferUnderrun) + { + UE_LOG(LogAudioMixer, Error, TEXT("Audio Buffer Underrun detected.")); + bWarnedBufferUnderrun = true; } + + SubmitBuffer(UnderrunBuffer.GetBufferData()); + } + else + { + PerformFades(); + + // As soon as a valid buffer goes through, allow more warning + if (bWarnedBufferUnderrun) + { + UE_LOG(LogAudioMixer, Error, TEXT("Audio had %d underruns [Total: %d]."), CurrentUnderrunCount, UnderrunCount); + } + CurrentUnderrunCount = 0; + bWarnedBufferUnderrun = false; + + // Submit the buffer at the next read index, but don't set the read index value yet + SubmitBuffer(OutputBuffers[NextReadIndex].GetBufferData()); + + // Update the current read index to the next read index + CurrentBufferReadIndex = NextReadIndex; } - // Submit the buffer to the platform specific device - SubmitBuffer(OutputBuffers[myBufferIndex]); - - // Mark this buffer as used and hence ready to be filled - OutputBufferReady[myBufferIndex] = false; + // Kick off rendering of the next set of buffers + AudioRenderEvent->Trigger(); } void IAudioMixerPlatformInterface::BeginGeneratingAudio() { - FAudioPlatformDeviceInfo & DeviceInfo = AudioStreamInfo.DeviceInfo; - // Setup the output buffers - for (int32 Index = 0; Index < NumMixerBuffers; ++Index) + const int32 NumOutputFrames = OpenStreamParams.NumFrames; + const int32 NumOutputChannels = AudioStreamInfo.DeviceInfo.NumChannels; + const int32 NumOutputSamples = NumOutputFrames * NumOutputChannels; + + // Set the number of buffers to be one more than the number to queue. + NumOutputBuffers = FMath::Max(OpenStreamParams.NumBuffers, 2); + + CurrentBufferReadIndex = 0; + CurrentBufferWriteIndex = 1; + + OutputBuffers.AddDefaulted(NumOutputBuffers); + for (int32 Index = 0; Index < NumOutputBuffers; ++Index) { - OutputBuffers[Index].SetNumZeroed(DeviceInfo.NumSamples); + OutputBuffers[Index].Init(AudioStreamInfo.AudioMixer, NumOutputSamples, AudioStreamInfo.DeviceInfo.Format); } - WarnedBufferUnderrun = false; + // Create an underrun buffer + UnderrunBuffer.Init(AudioStreamInfo.AudioMixer, NumOutputSamples, AudioStreamInfo.DeviceInfo.Format); AudioStreamInfo.StreamState = EAudioOutputStreamState::Running; @@ -180,13 +309,13 @@ namespace Audio AudioStreamInfo.StreamState = EAudioOutputStreamState::Stopping; } - if(AudioRenderEvent != nullptr) + if (AudioRenderEvent != nullptr) { // Make sure the thread wakes up AudioRenderEvent->Trigger(); } - if(AudioRenderThread != nullptr) + if (AudioRenderThread != nullptr) { AudioRenderThread->WaitForCompletion(); check(AudioStreamInfo.StreamState == EAudioOutputStreamState::Stopped); @@ -201,70 +330,57 @@ namespace Audio AudioRenderEvent = nullptr; } - FPlatformProcess::ReturnSynchEventToPool(AudioFadeEvent); - AudioFadeEvent = nullptr; + if (AudioFadeEvent != nullptr) + { + FPlatformProcess::ReturnSynchEventToPool(AudioFadeEvent); + AudioFadeEvent = nullptr; + } } - uint32 IAudioMixerPlatformInterface::Run() + uint32 IAudioMixerPlatformInterface::MainAudioDeviceRun() { - // Lets prime the first buffer - FPlatformMemory::Memzero(OutputBuffers[0].GetData(), OutputBuffers[0].Num() * sizeof(float)); - AudioStreamInfo.AudioMixer->OnProcessAudioStream(OutputBuffers[0]); + return RunInternal(); + } - // Give the platform audio device this first buffer - SubmitBuffer(OutputBuffers[0]); + uint32 IAudioMixerPlatformInterface::RunInternal() + { + // Lets prime and submit the first buffer (which is going to be the buffer underrun buffer) + SubmitBuffer(UnderrunBuffer.GetBufferData()); - // Initialize the ready flags - OutputBufferReady[0] = false; - OutputBufferReady[1] = false; + OutputBuffers[0].MixNextBuffer(); - CurrentBufferIndex = 1; + check(CurrentBufferReadIndex == 0); + check(CurrentBufferWriteIndex == 1); // Start immediately processing the next buffer while (AudioStreamInfo.StreamState != EAudioOutputStreamState::Stopping) { + // Render mixed buffers till our queued buffers are filled up + while (CurrentBufferReadIndex != CurrentBufferWriteIndex) { - SCOPE_CYCLE_COUNTER(STAT_AudioMixerRenderAudio); + OutputBuffers[CurrentBufferWriteIndex].MixNextBuffer(); - // Zero the current output buffer - FPlatformMemory::Memzero(OutputBuffers[CurrentBufferIndex].GetData(), OutputBuffers[CurrentBufferIndex].Num() * sizeof(float)); - - // Render - AudioStreamInfo.AudioMixer->OnProcessAudioStream(OutputBuffers[CurrentBufferIndex]); - - // Mark this buffer as ready to be consumed - OutputBufferReady[CurrentBufferIndex] = true; + CurrentBufferWriteIndex = (CurrentBufferWriteIndex + 1) % NumOutputBuffers; } - // Now wait for a buffer to be consumed + // Now wait for a buffer to be consumed, which will bump up the read index. AudioRenderEvent->Wait(); - - // At this point the output buffer will have been switched } - // Do one more process - FPlatformMemory::Memzero(OutputBuffers[CurrentBufferIndex].GetData(), OutputBuffers[CurrentBufferIndex].Num() * sizeof(float)); - AudioStreamInfo.AudioMixer->OnProcessAudioStream(OutputBuffers[CurrentBufferIndex]); - AudioStreamInfo.StreamState = EAudioOutputStreamState::Stopped; return 0; } - uint32 IAudioMixerPlatformInterface::GetNumBytesForFormat(const EAudioMixerStreamDataFormat::Type DataFormat) - { - switch (DataFormat) + uint32 IAudioMixerPlatformInterface::Run() + { + // Call different functions depending on if it's the "main" audio mixer instance. Helps debugging callstacks. + if (AudioStreamInfo.AudioMixer->IsMainAudioMixer()) { - case EAudioMixerStreamDataFormat::Float: return 4; - case EAudioMixerStreamDataFormat::Double: return 8; - case EAudioMixerStreamDataFormat::Int16: return 2; - case EAudioMixerStreamDataFormat::Int24: return 3; - case EAudioMixerStreamDataFormat::Int32: return 4; - - default: - checkf(false, TEXT("Unknown or unsupported data format.")) - return 0; + return MainAudioDeviceRun(); } + + return RunInternal(); } /** The default channel orderings to use when using pro audio interfaces while still supporting surround sound. */ diff --git a/Engine/Source/Runtime/AudioMixer/Private/AudioMixerDevice.cpp b/Engine/Source/Runtime/AudioMixer/Private/AudioMixerDevice.cpp index 522b72458cf6..9db20d871533 100644 --- a/Engine/Source/Runtime/AudioMixer/Private/AudioMixerDevice.cpp +++ b/Engine/Source/Runtime/AudioMixer/Private/AudioMixerDevice.cpp @@ -103,17 +103,23 @@ namespace Audio bool FMixerDevice::InitializeHardware() { AUDIO_MIXER_CHECK_GAME_THREAD(this); + + // Log that we're inside the audio mixer + UE_LOG(LogAudioMixer, Display, TEXT("Initializing audio mixer.")); if (AudioMixerPlatform && AudioMixerPlatform->InitializeHardware()) { + // Set whether we're the main audio mixer + bIsMainAudioMixer = IsMainAudioDevice(); + AUDIO_MIXER_CHECK(SampleRate != 0.0f); - AUDIO_MIXER_CHECK(DeviceOutputBufferLength != 0); AudioMixerPlatform->RegisterDeviceChangedListener(); - OpenStreamParams.NumFrames = DeviceOutputBufferLength; + OpenStreamParams.NumBuffers = PlatformSettings.NumBuffers; + OpenStreamParams.NumFrames = PlatformSettings.CallbackBufferFrameSize; OpenStreamParams.OutputDeviceIndex = 0; // Default device - OpenStreamParams.SampleRate = AUDIO_SAMPLE_RATE; + OpenStreamParams.SampleRate = SampleRate; OpenStreamParams.AudioMixer = this; FString DefaultDeviceName = AudioMixerPlatform->GetDefaultDeviceName(); @@ -167,17 +173,17 @@ namespace Audio // Initialize any plugins if they exist if (SpatializationPluginInterface.IsValid()) { - SpatializationPluginInterface->Initialize(AUDIO_SAMPLE_RATE, MaxChannels, OpenStreamParams.NumFrames); + SpatializationPluginInterface->Initialize(SampleRate, MaxChannels, OpenStreamParams.NumFrames); } if (OcclusionInterface.IsValid()) { - OcclusionInterface->Initialize(AUDIO_SAMPLE_RATE, MaxChannels); + OcclusionInterface->Initialize(SampleRate, MaxChannels); } if (ReverbPluginInterface.IsValid()) { - ReverbPluginInterface->Initialize(AUDIO_SAMPLE_RATE, MaxChannels, OpenStreamParams.NumFrames); + ReverbPluginInterface->Initialize(SampleRate, MaxChannels, OpenStreamParams.NumFrames); } // Need to set these up before we start the audio stream. @@ -217,12 +223,13 @@ namespace Audio // Get the platform device info we're using PlatformInfo = AudioMixerPlatform->GetPlatformDeviceInfo(); - SampleRate = AUDIO_SAMPLE_RATE; - // Initialize some data that depends on speaker configuration, etc. InitializeChannelAzimuthMap(PlatformInfo.NumChannels); SourceManager.UpdateDeviceChannelCount(PlatformInfo.NumChannels); + + // Audio rendering was suspended in CheckAudioDeviceChange if it changed. + AudioMixerPlatform->ResumePlaybackOnNewDevice(); } } @@ -487,9 +494,22 @@ namespace Audio // Perform any other initialization on the submix instance SubmixInstance->Init(SoundSubmix); } - } + FAudioPlatformSettings FMixerDevice::GetPlatformSettings() const + { + FAudioPlatformSettings Settings = AudioMixerPlatform->GetPlatformSettings(); + + UE_LOG(LogAudioMixer, Display, TEXT("Audio Mixer Platform Settings:")); + UE_LOG(LogAudioMixer, Display, TEXT(" Sample Rate: %d"), Settings.SampleRate); + UE_LOG(LogAudioMixer, Display, TEXT(" Callback Buffer Frame Size: %d"), Settings.CallbackBufferFrameSize); + UE_LOG(LogAudioMixer, Display, TEXT(" Number of buffers to queue: %d"), Settings.NumBuffers); + UE_LOG(LogAudioMixer, Display, TEXT(" Max Channels (voices): %d"), Settings.MaxChannels); + UE_LOG(LogAudioMixer, Display, TEXT(" Number of Async Source Workers: %d"), Settings.NumSourceWorkers); + + return Settings; + } + FMixerSubmixPtr FMixerDevice::GetMasterSubmix() { return MasterSubmixInstances[EMasterSubmixType::Master]; @@ -886,8 +906,8 @@ namespace Audio void FMixerDevice::WhiteNoiseTest(TArray& Output) { - int32 NumFrames = PlatformInfo.NumFrames; - int32 NumChannels = PlatformInfo.NumChannels; + const int32 NumFrames = OpenStreamParams.NumFrames; + const int32 NumChannels = PlatformInfo.NumChannels; static FWhiteNoise WhiteNoise(0.2f); @@ -903,8 +923,8 @@ namespace Audio void FMixerDevice::SineOscTest(TArray& Output) { - int32 NumFrames = PlatformInfo.NumFrames; - int32 NumChannels = PlatformInfo.NumChannels; + const int32 NumFrames = OpenStreamParams.NumFrames; + const int32 NumChannels = PlatformInfo.NumChannels; check(NumChannels > 0); diff --git a/Engine/Source/Runtime/AudioMixer/Private/AudioMixerSource.cpp b/Engine/Source/Runtime/AudioMixer/Private/AudioMixerSource.cpp index e4226263295d..aa9a8c5c35ec 100644 --- a/Engine/Source/Runtime/AudioMixer/Private/AudioMixerSource.cpp +++ b/Engine/Source/Runtime/AudioMixer/Private/AudioMixerSource.cpp @@ -154,7 +154,7 @@ namespace Audio InitParams.DebugName = InWaveInstance->GetName(); bool bIsDebug = false; - FString WaveInstanceName = WaveInstance->GetName(); + FString WaveInstanceName = WaveInstance->GetName(); //-V595 FString TestName = GEngine->GetAudioDeviceManager()->GetAudioMixerDebugSoundName(); if (WaveInstanceName.Contains(TestName)) { @@ -305,7 +305,8 @@ namespace Audio else { // Now check to see if we need to kick off a decode the first chunk of audio - if (MixerBuffer->GetType() == EBufferType::PCMRealTime && WaveInstance->WaveData) + const EBufferType::Type BufferType = MixerBuffer->GetType(); + if ((BufferType == EBufferType::PCMRealTime || BufferType == EBufferType::Streaming) && WaveInstance->WaveData) { // If any of these conditions meet, we need to do an initial async decode before we're ready to start playing the sound if (WaveInstance->StartTime > 0.0f || WaveInstance->WaveData->bProcedural || !WaveInstance->WaveData->CachedRealtimeFirstBuffer) @@ -643,7 +644,7 @@ namespace Audio } else { - DataReadMode = (MixerBuffer->GetType() == EBufferType::Streaming ? EBufferReadMode::Synchronous : EBufferReadMode::Asynchronous); + DataReadMode = EBufferReadMode::Asynchronous; } const bool bLooped = ReadMorePCMRTData(CurrentBuffer, DataReadMode); diff --git a/Engine/Source/Runtime/AudioMixer/Private/AudioMixerSource.h b/Engine/Source/Runtime/AudioMixer/Private/AudioMixerSource.h index 54034adb24c5..a6aa48a0c417 100644 --- a/Engine/Source/Runtime/AudioMixer/Private/AudioMixerSource.h +++ b/Engine/Source/Runtime/AudioMixer/Private/AudioMixerSource.h @@ -39,7 +39,7 @@ namespace Audio FMixerSourceVoiceBuffer() { - FMemory::Memzero(this, sizeof(this)); + FMemory::Memzero(this, sizeof(*this)); } }; diff --git a/Engine/Source/Runtime/AudioMixer/Private/AudioMixerSourceManager.cpp b/Engine/Source/Runtime/AudioMixer/Private/AudioMixerSourceManager.cpp index 4a693578c43f..572082bcf53e 100644 --- a/Engine/Source/Runtime/AudioMixer/Private/AudioMixerSourceManager.cpp +++ b/Engine/Source/Runtime/AudioMixer/Private/AudioMixerSourceManager.cpp @@ -9,7 +9,7 @@ DEFINE_STAT(STAT_AudioMixerHRTF); -static int32 DisableParallelSourceProcessingCvar = 0; +static int32 DisableParallelSourceProcessingCvar = 1; FAutoConsoleVariableRef CVarDisableParallelSourceProcessing( TEXT("au.DisableParallelSourceProcessing"), DisableParallelSourceProcessingCvar, @@ -52,14 +52,7 @@ namespace Audio StartValue = InValue; EndValue = InValue; Frame = NumInterpFrames; - if (NumInterpFrames == 0.0f) - { - bIsDone = true; - } - else - { - bIsDone = false; - } + bIsDone = true; } else { @@ -121,6 +114,8 @@ namespace Audio : MixerDevice(InMixerDevice) , NumActiveSources(0) , NumTotalSources(0) + , NumOutputFrames(0) + , NumOutputSamples(0) , NumSourceWorkers(4) , bInitialized(false) { @@ -153,6 +148,9 @@ namespace Audio NumTotalSources = InitParams.NumSources; + NumOutputFrames = MixerDevice->PlatformSettings.CallbackBufferFrameSize; + NumOutputSamples = NumOutputFrames * MixerDevice->GetNumDeviceChannels(); + MixerSources.Init(nullptr, NumTotalSources); SourceInfos.AddDefaulted(NumTotalSources); @@ -186,7 +184,7 @@ namespace Audio //SourceInfo.SourceEffects //SourceInfo.SourceEffectPresets - SourceInfo.SourceEnvelopeFollower = Audio::FEnvelopeFollower(AUDIO_SAMPLE_RATE, 10, 100, Audio::EPeakMode::Peak); + SourceInfo.SourceEnvelopeFollower = Audio::FEnvelopeFollower(MixerDevice->SampleRate, 10, 100, Audio::EPeakMode::Peak); SourceInfo.SourceEnvelopeValue = 0.0f; SourceInfo.bEffectTailsDone = false; //SourceInfo.SourceEffectInputData @@ -226,13 +224,12 @@ namespace Audio } // Initialize the source buffer memory usage to max source scratch buffers (num frames times max source channels) - const int32 NumFrames = MixerDevice->GetNumOutputFrames(); for (int32 SourceId = 0; SourceId < NumTotalSources; ++SourceId) { FSourceInfo& SourceInfo = SourceInfos[SourceId]; - SourceInfo.SourceBuffer.Reset(NumFrames * 8); - SourceInfo.AudioPluginOutputData.AudioBuffer.Reset(NumFrames * 2); + SourceInfo.SourceBuffer.Reset(NumOutputFrames * 8); + SourceInfo.AudioPluginOutputData.AudioBuffer.Reset(NumOutputFrames * 2); } // Setup the source workers @@ -249,7 +246,7 @@ namespace Audio StartId = EndId; } } - AUDIO_MIXER_CHECK(SourceWorkers.Num() == NumSourceWorkers); + NumSourceWorkers = SourceWorkers.Num(); bInitialized = true; bPumpQueue = false; @@ -309,6 +306,22 @@ namespace Audio SubmixSendItem.Value.Submix->RemoveSourceVoice(MixerSources[SourceId]); } + // Notify plugin effects + if (SourceInfo.bUseHRTFSpatializer) + { + MixerDevice->SpatializationPluginInterface->OnReleaseSource(SourceId); + } + + if (SourceInfo.bUseOcclusionPlugin) + { + MixerDevice->OcclusionInterface->OnReleaseSource(SourceId); + } + + if (SourceInfo.bUseReverbPlugin) + { + MixerDevice->ReverbPluginInterface->OnReleaseSource(SourceId); + } + // Delete the source effects SourceInfo.SourceEffectChainId = INDEX_NONE; ResetSourceEffectChain(SourceId); @@ -468,25 +481,24 @@ namespace Audio // Initialize the number of per-source LPF filters based on input channels SourceInfo.LowPassFilters.AddDefaulted(InitParams.NumInputChannels); - // Setup the spatialization settings preset - if (InitParams.SpatializationPluginSettings != nullptr) + // Create the spatialization plugin source effect + if (InitParams.bUseHRTFSpatialization) { - MixerDevice->SpatializationPluginInterface->SetSpatializationSettings(SourceId, InitParams.SpatializationPluginSettings); + MixerDevice->SpatializationPluginInterface->OnInitSource(SourceId, InitParams.AudioComponentUserID, + InitParams.SpatializationPluginSettings); } - // Setup the occlusion settings preset + // Create the occlusion plugin source effect if (InitParams.OcclusionPluginSettings != nullptr) { - MixerDevice->OcclusionInterface->SetOcclusionSettings(SourceId, InitParams.OcclusionPluginSettings); - + MixerDevice->OcclusionInterface->OnInitSource(SourceId, InitParams.AudioComponentUserID, InitParams.OcclusionPluginSettings); SourceInfo.bUseOcclusionPlugin = true; } - // Setup the reverb settings preset + // Create the reverb plugin source effect if (InitParams.ReverbPluginSettings != nullptr) { - MixerDevice->ReverbPluginInterface->SetReverbSettings(SourceId, InitParams.AudioComponentUserID, InitParams.ReverbPluginSettings); - + MixerDevice->ReverbPluginInterface->OnInitSource(SourceId, InitParams.AudioComponentUserID, InitParams.ReverbPluginSettings); SourceInfo.bUseReverbPlugin = true; } @@ -501,13 +513,13 @@ namespace Audio SourceInfo.bEffectTailsDone = !InitParams.bPlayEffectChainTails; FSoundEffectSourceInitData InitData; - InitData.SampleRate = AUDIO_SAMPLE_RATE; + InitData.SampleRate = MixerDevice->SampleRate; InitData.NumSourceChannels = InitParams.NumInputChannels; InitData.AudioClock = MixerDevice->GetAudioTime(); if (InitParams.NumInputFrames != INDEX_NONE) { - InitData.SourceDuration = (float)InitParams.NumInputFrames / AUDIO_SAMPLE_RATE; + InitData.SourceDuration = (float)InitParams.NumInputFrames / MixerDevice->SampleRate; } else { @@ -907,8 +919,6 @@ namespace Audio { SCOPE_CYCLE_COUNTER(STAT_AudioMixerSourceBuffers); - const int32 NumFrames = MixerDevice->GetNumOutputFrames(); - // Local variable used for sample values float SampleValue = 0.0f; @@ -925,10 +935,10 @@ namespace Audio // Fill array with elements all at once to avoid sequential Add() operation overhead. const int32 NumSourceChannels = SourceInfo.NumInputChannels; - SourceInfo.SourceBuffer.AddUninitialized(NumFrames * NumSourceChannels); + SourceInfo.SourceBuffer.AddUninitialized(NumOutputFrames * NumSourceChannels); int32 SampleIndex = 0; - for (int32 Frame = 0; Frame < NumFrames; ++Frame) + for (int32 Frame = 0; Frame < NumOutputFrames; ++Frame) { // If the source is done, then we'll just write out 0s if (!SourceInfo.bIsDone) @@ -995,7 +1005,6 @@ namespace Audio void FMixerSourceManager::ComputePostSourceEffectBufferForIdRange(const int32 SourceIdStart, const int32 SourceIdEnd) { SCOPE_CYCLE_COUNTER(STAT_AudioMixerSourceEffectBuffers); - const int32 NumFrames = MixerDevice->GetNumOutputFrames(); const bool bIsDebugModeEnabled = DebugSoloSources.Num() > 0; @@ -1018,7 +1027,7 @@ namespace Audio // Process the per-source LPF if the source hasn't actually been finished if (!SourceInfo.bIsDone) { - for (int32 Frame = 0; Frame < NumFrames; ++Frame) + for (int32 Frame = 0; Frame < NumOutputFrames; ++Frame) { FSourceParam& LPFFrequencyParam = SourceInfo.LPFCutoffFrequencyParam; @@ -1199,7 +1208,7 @@ namespace Audio AudioPluginInputData.SpatializationParams = &SourceInfo.SpatParams; SourceInfo.AudioPluginOutputData.AudioBuffer.Reset(); - SourceInfo.AudioPluginOutputData.AudioBuffer.AddZeroed(2 * NumFrames); + SourceInfo.AudioPluginOutputData.AudioBuffer.AddZeroed(2 * NumOutputFrames); SpatializationPlugin->ProcessAudio(AudioPluginInputData, SourceInfo.AudioPluginOutputData); @@ -1223,11 +1232,9 @@ namespace Audio { SCOPE_CYCLE_COUNTER(STAT_AudioMixerSourceOutputBuffers); - const int32 NumFrames = MixerDevice->GetNumOutputFrames(); const int32 NumOutputChannels = MixerDevice->GetNumDeviceChannels(); // Reset the dry/wet buffers for all the sources - const int32 NumOutputSamples = NumFrames * NumOutputChannels; for (int32 SourceId = SourceIdStart; SourceId < SourceIdEnd; ++SourceId) { @@ -1249,7 +1256,7 @@ namespace Audio continue; } - for (int32 Frame = 0; Frame < NumFrames; ++Frame) + for (int32 Frame = 0; Frame < NumOutputFrames; ++Frame) { const int32 PostEffectChannels = SourceInfo.NumPostEffectChannels; AUDIO_MIXER_CHECK(SourceInfo.ChannelMapParam.ChannelValues.Num() == PostEffectChannels * NumOutputChannels); @@ -1311,6 +1318,8 @@ namespace Audio void FMixerSourceManager::UpdateDeviceChannelCount(const int32 InNumOutputChannels) { + NumOutputSamples = NumOutputFrames * MixerDevice->GetNumDeviceChannels(); + // Update all source's to appropriate channel maps for (int32 SourceId = 0; SourceId < NumTotalSources; ++SourceId) { @@ -1348,7 +1357,8 @@ namespace Audio { FSoundEffectSourceInitData InitData; InitData.AudioClock = MixerDevice->GetAudioClock(); - InitData.SampleRate = AUDIO_SAMPLE_RATE; + InitData.SampleRate = MixerDevice->SampleRate; + for (int32 SourceId = 0; SourceId < NumTotalSources; ++SourceId) { FSourceInfo& SourceInfo = SourceInfos[SourceId]; @@ -1389,7 +1399,7 @@ namespace Audio if (SourceInfo.NumInputFrames != INDEX_NONE) { - InitData.SourceDuration = (float)SourceInfo.NumInputFrames / AUDIO_SAMPLE_RATE; + InitData.SourceDuration = (float)SourceInfo.NumInputFrames / InitData.SampleRate; } else { diff --git a/Engine/Source/Runtime/AudioMixer/Private/AudioMixerSourceManager.h b/Engine/Source/Runtime/AudioMixer/Private/AudioMixerSourceManager.h index 0ed2927fd63b..60351bd15e30 100644 --- a/Engine/Source/Runtime/AudioMixer/Private/AudioMixerSourceManager.h +++ b/Engine/Source/Runtime/AudioMixer/Private/AudioMixerSourceManager.h @@ -79,7 +79,7 @@ namespace Audio USpatializationPluginSourceSettingsBase* SpatializationPluginSettings; UOcclusionPluginSourceSettingsBase* OcclusionPluginSettings; UReverbPluginSourceSettingsBase* ReverbPluginSettings; - uint32 AudioComponentUserID; + FName AudioComponentUserID; bool bPlayEffectChainTails; bool bUseHRTFSpatialization; bool bIsDebugMode; @@ -93,7 +93,6 @@ namespace Audio , SpatializationPluginSettings(nullptr) , OcclusionPluginSettings(nullptr) , ReverbPluginSettings(nullptr) - , AudioComponentUserID(INDEX_NONE) , bPlayEffectChainTails(true) , bUseHRTFSpatialization(false) , bIsDebugMode(false) @@ -397,6 +396,8 @@ namespace Audio int32 NumActiveSources; int32 NumTotalSources; + int32 NumOutputFrames; + int32 NumOutputSamples; int32 NumSourceWorkers; uint8 bInitialized : 1; diff --git a/Engine/Source/Runtime/AudioMixer/Private/AudioMixerSourceVoice.cpp b/Engine/Source/Runtime/AudioMixer/Private/AudioMixerSourceVoice.cpp index c364a8870fce..7aa675af89d0 100644 --- a/Engine/Source/Runtime/AudioMixer/Private/AudioMixerSourceVoice.cpp +++ b/Engine/Source/Runtime/AudioMixer/Private/AudioMixerSourceVoice.cpp @@ -19,6 +19,7 @@ namespace Audio , Pitch(-1.0f) , Volume(-1.0f) , Distance(-1.0f) + , LPFFrequency(-1.0f) , SourceId(INDEX_NONE) , bIsPlaying(false) , bIsPaused(false) diff --git a/Engine/Source/Runtime/AudioMixer/Private/Components/SynthComponent.cpp b/Engine/Source/Runtime/AudioMixer/Private/Components/SynthComponent.cpp index 32c85c51f79d..3d8a81e34310 100644 --- a/Engine/Source/Runtime/AudioMixer/Private/Components/SynthComponent.cpp +++ b/Engine/Source/Runtime/AudioMixer/Private/Components/SynthComponent.cpp @@ -19,7 +19,7 @@ void USynthSound::Init(USynthComponent* InSynthComponent, int32 InNumChannels) bCanProcessAsync = true; Duration = INDEFINITELY_LOOPING_DURATION; bLooping = true; - SampleRate = AUDIO_SAMPLE_RATE; + SampleRate = InSynthComponent->GetAudioDevice()->SampleRate; } bool USynthSound::OnGeneratePCMAudio(TArray& OutAudio, int32 NumSamples) @@ -44,7 +44,6 @@ USynthComponent::USynthComponent(const FObjectInitializer& ObjectInitializer) AudioComponent->bStopWhenOwnerDestroyed = true; AudioComponent->bShouldRemainActiveIfDropped = true; AudioComponent->Mobility = EComponentMobility::Movable; - AudioComponent->SetupAttachment(this); bAutoActivate = true; bStopWhenOwnerDestroyed = true; @@ -91,19 +90,26 @@ void USynthComponent::Deactivate() void USynthComponent::OnRegister() { + if (AudioComponent->GetAttachParent() == nullptr && !AudioComponent->IsAttachedTo(this)) + { + AudioComponent->SetupAttachment(this); + } + Super::OnRegister(); if (!bIsInitialized) { bIsInitialized = true; + const int32 SampleRate = GetAudioDevice()->SampleRate; + #if SYNTH_GENERATOR_TEST_TONE NumChannels = 2; - TestSineLeft.Init(AUDIO_SAMPLE_RATE, 440.0f, 0.5f); - TestSineRight.Init(AUDIO_SAMPLE_RATE, 220.0f, 0.5f); + TestSineLeft.Init(SampleRate, 440.0f, 0.5f); + TestSineRight.Init(SampleRate, 220.0f, 0.5f); #else // Initialize the synth component - this->Init(AUDIO_SAMPLE_RATE); + this->Init(SampleRate); if (NumChannels < 0 || NumChannels > 2) { diff --git a/Engine/Source/Runtime/AudioMixer/Private/DSP/AllPassFilter.cpp b/Engine/Source/Runtime/AudioMixer/Private/DSP/AllPassFilter.cpp index 796bde06ba02..d2b835a69e3b 100644 --- a/Engine/Source/Runtime/AudioMixer/Private/DSP/AllPassFilter.cpp +++ b/Engine/Source/Runtime/AudioMixer/Private/DSP/AllPassFilter.cpp @@ -32,7 +32,7 @@ namespace Audio // form y(n) = -gw(n) + w(n-D) float Yn = -G*Wn + WnD; - UnderflowClamp(Yn); + Yn = UnderflowClamp(Yn); this->WriteDelayAndInc(Wn); *OutputSample = Yn; } diff --git a/Engine/Source/Runtime/AudioMixer/Private/DSP/BitCrusher.cpp b/Engine/Source/Runtime/AudioMixer/Private/DSP/BitCrusher.cpp index c6564a5aad66..8de223c979c6 100644 --- a/Engine/Source/Runtime/AudioMixer/Private/DSP/BitCrusher.cpp +++ b/Engine/Source/Runtime/AudioMixer/Private/DSP/BitCrusher.cpp @@ -6,7 +6,7 @@ namespace Audio { FBitCrusher::FBitCrusher() - : SampleRate(AUDIO_SAMPLE_RATE) + : SampleRate(0) , BitDepth(16.0f) , BitDelta(0.0f) , Phase(1.0f) diff --git a/Engine/Source/Runtime/AudioMixer/Private/DSP/DelayStereo.cpp b/Engine/Source/Runtime/AudioMixer/Private/DSP/DelayStereo.cpp index 61a9c9d49136..d65ba9435897 100644 --- a/Engine/Source/Runtime/AudioMixer/Private/DSP/DelayStereo.cpp +++ b/Engine/Source/Runtime/AudioMixer/Private/DSP/DelayStereo.cpp @@ -75,8 +75,8 @@ namespace Audio float LeftDelayOut = LeftDelay.Read(); float RightDelayOut = RightDelay.Read(); - float LeftDelayIn; - float RightDelayIn; + float LeftDelayIn = 0.0f; + float RightDelayIn = 0.0f; if (DelayMode == EStereoDelayMode::Normal) { diff --git a/Engine/Source/Runtime/AudioMixer/Private/DSP/Granulator.cpp b/Engine/Source/Runtime/AudioMixer/Private/DSP/Granulator.cpp index ac1efc2dac0b..0db09fccb9e3 100644 --- a/Engine/Source/Runtime/AudioMixer/Private/DSP/Granulator.cpp +++ b/Engine/Source/Runtime/AudioMixer/Private/DSP/Granulator.cpp @@ -253,7 +253,7 @@ namespace Audio SpeakerMap[1] = FMath::Cos(0.5f * CurrentPan * PI); // Get information about the buffer if there is one - if (Parent->SampleBuffer.IsLoaded()) + if (Parent->SampleBuffer.GetData() != nullptr) { const int16* Buffer = Parent->SampleBuffer.GetData(); const int32 NumBufferSamples = Parent->SampleBuffer.GetNumSamples(); @@ -376,8 +376,7 @@ namespace Audio } FGranularSynth::FGranularSynth() - : AudioDevice(nullptr) - , SampleRate(0) + : SampleRate(0) , NumChannels(0) , Mode(EGranularSynthMode::Synthesis) , GrainOscType(EOsc::NumOscTypes) @@ -388,7 +387,6 @@ namespace Audio , NextSpawnFrame(0) , NoteDurationFrameCount(0) , NoteDurationFrameEnd(0) - , SampleDuration(0.0f) , CurrentPlayHeadFrame(0.0f) , PlaybackSpeed(1.0f) , NumActiveGrains(0) @@ -401,20 +399,13 @@ namespace Audio } - void FGranularSynth::Init(FAudioDevice* InAudioDevice, const int32 InNumInitialGrains) + void FGranularSynth::Init(const int32 InSampleRate, const int32 InNumInitialGrains) { // make sure we're not double-initializing check(SampleRate == 0); - AudioDevice = InAudioDevice; - - // Initialize the sample buffer with the audio device - SampleBuffer.Init(AudioDevice); - // Init the sample rate and channels. This is set when grains need to play. - SampleRate = InAudioDevice->GetSampleRate(); - - SampleDuration = 0.0f; + SampleRate = InSampleRate; // Set the granular synth to be stereo NumChannels = 2; @@ -468,21 +459,9 @@ namespace Audio } } - void FGranularSynth::LoadSoundWave(USoundWave* InSoundWave, const bool bLoadAsync) + void FGranularSynth::LoadSampleBuffer(const FSampleBuffer& InSampleBuffer) { - SampleDuration = 0.0f; - SampleBuffer.Init(AudioDevice); - SampleBuffer.LoadSoundWave(InSoundWave, bLoadAsync); - } - - void FGranularSynth::UpdateSoundWaveLoading() - { - SampleBuffer.UpdateLoading(); - } - - bool FGranularSynth::IsSoundWaveLoaded() const - { - return SampleBuffer.IsLoaded(); + SampleBuffer = InSampleBuffer; } void FGranularSynth::NoteOn(const uint32 InMidiNote, const float InVelocity, const float InDurationSec) @@ -545,7 +524,7 @@ namespace Audio void FGranularSynth::SeekTime(const float InTimeSec, const float LerpTimeSec, const ESeekType::Type InSeekType) { - if (IsSoundWaveLoaded()) + if (SampleBuffer.GetData() != nullptr) { float TargetPlayheadFrame = 0.0f; @@ -795,7 +774,7 @@ namespace Audio float FGranularSynth::GetSampleDuration() const { - return SampleDuration; + return SampleBuffer.SampleDuration; } void FGranularSynth::Generate(TArray& OutAudiobuffer, const int32 NumFrames) @@ -803,32 +782,9 @@ namespace Audio OutAudiobuffer.Reset(); OutAudiobuffer.AddZeroed(2 * NumFrames); - // If we're granulating, that means we're generating grains from a loaded buffer - if (Mode == EGranularSynthMode::Granulation) + if (SampleBuffer.GetData() == nullptr) { - if (SampleBuffer.IsLoaded()) - { - if (SampleBuffer.GetSampleRate() > 0) - { - SampleDuration = (float)SampleBuffer.GetNumFrames() / SampleBuffer.GetSampleRate(); - } - else - { - static bool bLoggedError = false; - if (!bLoggedError) - { - bLoggedError = true; - UE_LOG(LogAudioMixer, Error, TEXT("Loaded sample buffer in FGranularSynth is reporting 0 sample rate.")) - } - return; - } - } - else - { - // Update loading - SampleBuffer.UpdateLoading(); - return; - } + return; } // If the gain envelope is done, nothing to generate diff --git a/Engine/Source/Runtime/AudioMixer/Private/DSP/Reverb.cpp b/Engine/Source/Runtime/AudioMixer/Private/DSP/Reverb.cpp index ceb35c35700a..4cb235cb0a88 100644 --- a/Engine/Source/Runtime/AudioMixer/Private/DSP/Reverb.cpp +++ b/Engine/Source/Runtime/AudioMixer/Private/DSP/Reverb.cpp @@ -158,8 +158,7 @@ namespace Audio } FPlateReverb::FPlateReverb() - : LFO(nullptr) - , bEnableLateReflections(true) + : bEnableLateReflections(true) , bEnableEarlyReflections(true) { FMemory::Memzero(LeftTaps, sizeof(float)*NumTaps); @@ -168,11 +167,6 @@ namespace Audio FPlateReverb::~FPlateReverb() { - if (LFO) - { - delete LFO; - LFO = nullptr; - } } void FPlateReverb::Init(const int32 InSampleRate) @@ -198,7 +192,7 @@ namespace Audio APF4.Init(SampleRate, DefaultDelayLength); APF4.SetDelayMsec(GetDelayMsec(277)); - if (!LFO) + if (!LFO.IsValid()) { LFO = FWaveTableOsc::CreateWaveTable(EWaveTable::SineWaveTable); } diff --git a/Engine/Source/Runtime/AudioMixer/Private/DSP/SampleBuffer.cpp b/Engine/Source/Runtime/AudioMixer/Private/DSP/SampleBuffer.cpp index b92c81a6bdc5..92a7e6d92fd4 100644 --- a/Engine/Source/Runtime/AudioMixer/Private/DSP/SampleBuffer.cpp +++ b/Engine/Source/Runtime/AudioMixer/Private/DSP/SampleBuffer.cpp @@ -6,9 +6,12 @@ namespace Audio { FSampleBuffer::FSampleBuffer() - : AudioDevice(nullptr) - , SoundWave(nullptr) - , bIsLoading(false) + : RawPCMData(nullptr) + , NumSamples(0) + , NumFrames(0) + , NumChannels(0) + , SampleRate(0) + , SampleDuration(0.0f) { } @@ -16,117 +19,126 @@ namespace Audio { } - void FSampleBuffer::Init(FAudioDevice* InAudioDevice) - { - AudioDevice = InAudioDevice; - } - - void FSampleBuffer::LoadSoundWave(USoundWave* InSoundWave, const bool bLoadAsync) - { - check(InSoundWave); - - if (AudioDevice) - { - // finish loading any other sound waves before flushing this - if (bIsLoading) - { - check(SoundWave); - if (SoundWave->AudioDecompressor) - { - SoundWave->AudioDecompressor->EnsureCompletion(); - delete SoundWave->AudioDecompressor; - SoundWave->AudioDecompressor = nullptr; - } - } - - SoundWave = InSoundWave; - - bIsLoaded = false; - bIsLoading = true; - - // Precache the sound wave and force it to be fully decompressed - AudioDevice->Precache(SoundWave, !bLoadAsync, true, true); - - // If we synchronously loaded then we're good - if (!bLoadAsync) - { - check(SoundWave->RawPCMData); - bIsLoading = false; - bIsLoaded = true; - } - } - } - - void FSampleBuffer::UpdateLoading() - { - if (bIsLoading) - { - check(SoundWave); - - if (SoundWave->AudioDecompressor && SoundWave->AudioDecompressor->IsDone()) - { - bIsLoading = false; - bIsLoaded = true; - - delete SoundWave->AudioDecompressor; - SoundWave->AudioDecompressor = nullptr; - } - } - } - - bool FSampleBuffer::IsLoaded() const - { - return bIsLoaded; - } - - bool FSampleBuffer::IsLoading() const - { - return bIsLoading; - } - const int16* FSampleBuffer::GetData() const { - if (bIsLoaded) - { - return (int16*)SoundWave->RawPCMData; - } - return nullptr; + return RawPCMData; } int32 FSampleBuffer::GetNumSamples() const { - if (bIsLoaded) - { - return SoundWave->RawPCMDataSize / sizeof(int16); - } - return 0; + return NumSamples; } int32 FSampleBuffer::GetNumFrames() const { - if (bIsLoaded) - { - return GetNumSamples() / GetNumChannels(); - } - return 0; + return NumFrames; } int32 FSampleBuffer::GetNumChannels() const { - if (bIsLoaded) - { - return SoundWave->NumChannels; - } - return 0; + return NumChannels; } int32 FSampleBuffer::GetSampleRate() const { - if (bIsLoaded) + return SampleRate; + } + + FSoundWavePCMLoader::FSoundWavePCMLoader() + : AudioDevice(nullptr) + , SoundWave(nullptr) + , bIsLoading(false) + , bIsLoaded(false) + { + } + + void FSoundWavePCMLoader::Init(FAudioDevice* InAudioDevice) + { + AudioDevice = InAudioDevice; + } + + void FSoundWavePCMLoader::LoadSoundWave(USoundWave* InSoundWave) + { + if (!AudioDevice || !InSoundWave) { - return SoundWave->SampleRate; + return; } - return 0; + + // If we're already loading a sound wave, finish it before trying to load a new one + if (bIsLoading) + { + check(SoundWave); + if (SoundWave->AudioDecompressor) + { + SoundWave->AudioDecompressor->EnsureCompletion(); + delete SoundWave->AudioDecompressor; + SoundWave->AudioDecompressor = nullptr; + } + } + + // Queue existing sound wave reference so it can be + // cleared when the audio thread gets newly loaded audio data. + // Don't want to kill the sound wave PCM data while it's playing on audio thread. + if (SoundWave) + { + PendingStoppingSoundWaves.Enqueue(SoundWave); + } + + SoundWave = InSoundWave; + if (!SoundWave->RawPCMData) + { + bIsLoaded = false; + bIsLoading = true; + + // Kick off a decompression/precache of the sound wave + AudioDevice->Precache(SoundWave, false, true, true); + } + else + { + bIsLoading = true; + bIsLoaded = true; + } + } + + bool FSoundWavePCMLoader::Update() + { + if (bIsLoading) + { + check(SoundWave); + + if (bIsLoaded || (SoundWave->AudioDecompressor && SoundWave->AudioDecompressor->IsDone())) + { + bIsLoading = false; + bIsLoaded = true; + + if (SoundWave->AudioDecompressor) + { + delete SoundWave->AudioDecompressor; + SoundWave->AudioDecompressor = nullptr; + } + + SampleBuffer.RawPCMData = (int16*)SoundWave->RawPCMData; + SampleBuffer.NumSamples = SoundWave->RawPCMDataSize / sizeof(int16); + SampleBuffer.NumChannels = SoundWave->NumChannels; + SampleBuffer.NumFrames = SampleBuffer.NumSamples / SoundWave->NumChannels; + SampleBuffer.SampleRate = SoundWave->SampleRate; + SampleBuffer.SampleDuration = (float)SampleBuffer.NumFrames / SampleBuffer.SampleRate; + + return true; + } + } + + return false; + } + + void FSoundWavePCMLoader::GetSampleBuffer(FSampleBuffer& OutSampleBuffer) + { + OutSampleBuffer = SampleBuffer; + } + + void FSoundWavePCMLoader::Reset() + { + PendingStoppingSoundWaves.Empty(); } } diff --git a/Engine/Source/Runtime/AudioMixer/Private/DSP/WaveTableOsc.cpp b/Engine/Source/Runtime/AudioMixer/Private/DSP/WaveTableOsc.cpp index aa8df0b2a579..3dd3131d2fce 100644 --- a/Engine/Source/Runtime/AudioMixer/Private/DSP/WaveTableOsc.cpp +++ b/Engine/Source/Runtime/AudioMixer/Private/DSP/WaveTableOsc.cpp @@ -5,12 +5,8 @@ namespace Audio { - ICustomWaveTableOscFactory* FWaveTableOsc::CustomWaveTableOscFactory = nullptr; - FWaveTableOsc::FWaveTableOsc() - : WaveTableBuffer(nullptr) - , WaveTableBufferSize(0) - , FrequencyHz(440.0f) + : FrequencyHz(440.0f) , SampleRate(44100) , NormalPhaseReadIndex(0.0f) , QuadPhaseReadIndex(0.0f) @@ -24,11 +20,6 @@ namespace Audio FWaveTableOsc::~FWaveTableOsc() { - if (WaveTableBuffer) - { - delete[] WaveTableBuffer; - WaveTableBuffer = nullptr; - } } void FWaveTableOsc::Init(const float InSampleRate, const float InFrequencyHz) @@ -58,7 +49,7 @@ namespace Audio NormalPhaseReadIndex = 0.0f; // Quad phase starts at 25% of the wave table buffer size - QuadPhaseReadIndex = 0.25f * WaveTableBufferSize; + QuadPhaseReadIndex = 0.25f * WaveTableBuffer.Num(); } // Sets the frequency of the wave table oscillator. @@ -70,7 +61,17 @@ namespace Audio void FWaveTableOsc::UpdateFrequency() { - PhaseIncrement = (float)WaveTableBufferSize * FrequencyHz / (float)SampleRate; + PhaseIncrement = (float)WaveTableBuffer.Num() * FrequencyHz / (float)SampleRate; + } + + TArray& FWaveTableOsc::GetTable() + { + return WaveTableBuffer; + } + + const TArray& FWaveTableOsc::GetTable() const + { + return WaveTableBuffer; } void FWaveTableOsc::Generate(float* OutputNormalPhase, float* OutputQuadPhase) @@ -80,7 +81,7 @@ namespace Audio if (OutputNormalPhase) { - const int32 NormPhaseReadIndexNext = (NormPhaseReadIndexPrev + 1) % WaveTableBufferSize; + const int32 NormPhaseReadIndexNext = (NormPhaseReadIndexPrev + 1) % WaveTableBuffer.Num(); const float NormalPhaseOutput = FMath::Lerp(WaveTableBuffer[NormPhaseReadIndexPrev], WaveTableBuffer[NormPhaseReadIndexNext], Alpha); *OutputNormalPhase = NormalPhaseOutput * OutputScale + OutputAdd; } @@ -88,7 +89,7 @@ namespace Audio if (OutputQuadPhase) { const int32 QuadPhaseReadIndexPrev = (int32)QuadPhaseReadIndex; - const int32 QuadPhaseReadIndexNext = (QuadPhaseReadIndexPrev + 1) % WaveTableBufferSize; + const int32 QuadPhaseReadIndexNext = (QuadPhaseReadIndexPrev + 1) % WaveTableBuffer.Num(); float QuadPhaseOutput = FMath::Lerp(WaveTableBuffer[QuadPhaseReadIndexPrev], WaveTableBuffer[QuadPhaseReadIndexNext], Alpha); *OutputQuadPhase = QuadPhaseOutput * OutputScale + OutputAdd; @@ -97,203 +98,187 @@ namespace Audio NormalPhaseReadIndex += PhaseIncrement; QuadPhaseReadIndex += PhaseIncrement; - while (NormalPhaseReadIndex >= WaveTableBufferSize) + while (NormalPhaseReadIndex >= WaveTableBuffer.Num()) { - NormalPhaseReadIndex -= WaveTableBufferSize; + NormalPhaseReadIndex -= WaveTableBuffer.Num(); } - while (QuadPhaseReadIndex >= WaveTableBufferSize) + while (QuadPhaseReadIndex >= WaveTableBuffer.Num()) { - QuadPhaseReadIndex -= WaveTableBufferSize; + QuadPhaseReadIndex -= WaveTableBuffer.Num(); } } - void FWaveTableOsc::SetCustomWaveTableOscFactory(ICustomWaveTableOscFactory* InCustomWaveTableOscFactory) + TSharedPtr FWaveTableOsc::CreateWaveTable(const EWaveTable::Type WaveTableType, const int32 WaveTableSize) { - FWaveTableOsc::CustomWaveTableOscFactory = InCustomWaveTableOscFactory; - } - - FWaveTableOsc* FWaveTableOsc::CreateWaveTable(const EWaveTable::Type WaveTableType, const int32 WaveTableSize) - { - if (WaveTableType == EWaveTable::Custom) - { - if (FWaveTableOsc::CustomWaveTableOscFactory != nullptr) - { - // Use the user-set custom wave table factory to create a new wave table oscillator - return FWaveTableOsc::CustomWaveTableOscFactory->CreateCustomWaveTable(WaveTableSize); - } - else - { - // No custom wave table factory set, return nullptr - return nullptr; - } - } - if (WaveTableType == EWaveTable::None || WaveTableSize <= 0) { return nullptr; } // Make a new wave table oscillator - FWaveTableOsc* NewWaveTableOsc = new FWaveTableOsc(); + TSharedPtr NewWaveTableOsc = TSharedPtr(new FWaveTableOsc()); - NewWaveTableOsc->WaveTableBuffer = new float[WaveTableSize]; - NewWaveTableOsc->WaveTableBufferSize = WaveTableSize; + NewWaveTableOsc->WaveTableBuffer.AddDefaulted(WaveTableSize); NewWaveTableOsc->WaveTableType = WaveTableType; NewWaveTableOsc->Reset(); switch (WaveTableType) { - case EWaveTable::SineWaveTable: - { - for (int32 i = 0; i < WaveTableSize; ++i) + case EWaveTable::SineWaveTable: { - NewWaveTableOsc->WaveTableBuffer[i] = FMath::Sin(2.0f * PI * (float)i / WaveTableSize); + for (int32 i = 0; i < WaveTableSize; ++i) + { + NewWaveTableOsc->WaveTableBuffer[i] = FMath::Sin(2.0f * PI * (float)i / WaveTableSize); + } } + break; + + case EWaveTable::SawWaveTable: + { + const int32 HalfTableSize = WaveTableSize / 2; + const float Slope = 1.0f / HalfTableSize; + + // Rise to half-point, the offset by 1.0, continue to rise + for (int32 i = 0; i < WaveTableSize; ++i) + { + if (i < HalfTableSize) + { + NewWaveTableOsc->WaveTableBuffer[i] = Slope * i; + } + else + { + NewWaveTableOsc->WaveTableBuffer[i] = Slope * (i - HalfTableSize - 1) - 1.0f; + } + } + } + break; + + case EWaveTable::TriangleWaveTable: + { + const int32 QuarterTableSize = WaveTableSize / 4; + const int32 HalfTableSize = WaveTableSize / 2; + const int32 ThreeQuarterTableSize = 3 * WaveTableSize / 4; + const float SlopeUp = 1.0f / QuarterTableSize; + const float SlopeDown = -2.0f / HalfTableSize; + + for (int32 i = 0; i < WaveTableSize; ++i) + { + if (i < QuarterTableSize) + { + NewWaveTableOsc->WaveTableBuffer[i] = SlopeUp * i - 1.0f; + } + else if (i < ThreeQuarterTableSize) + { + NewWaveTableOsc->WaveTableBuffer[i] = SlopeDown * (i - QuarterTableSize) + 1.0f; + } + else + { + NewWaveTableOsc->WaveTableBuffer[i] = SlopeUp * (i - ThreeQuarterTableSize) - 1.0f; + } + } + } + break; + + case EWaveTable::SquareWaveTable: + { + const int32 HalfTableSize = WaveTableSize / 2; + + for (int32 i = 0; i < WaveTableSize; ++i) + { + if (i < HalfTableSize) + { + NewWaveTableOsc->WaveTableBuffer[i] = 1.0f; + } + else + { + NewWaveTableOsc->WaveTableBuffer[i] = -1.0f; + } + } + } + break; + + case EWaveTable::BandLimitedSawWaveTable: + { + float MaxSample = 0.0f; + + for (int32 i = 0; i < WaveTableSize; ++i) + { + NewWaveTableOsc->WaveTableBuffer[i] = 0.0f; + for (int32 g = 1; g <= 6; ++g) + { + NewWaveTableOsc->WaveTableBuffer[i] += FMath::Pow(-1.0f, (float)(g + 1)) * (1.0f / g) * FMath::Sin(2.0f * PI * i * (float)g / WaveTableSize); + } + + if (NewWaveTableOsc->WaveTableBuffer[i] > MaxSample) + { + MaxSample = NewWaveTableOsc->WaveTableBuffer[i]; + } + } + + for (int32 i = 0; i < WaveTableSize; ++i) + { + NewWaveTableOsc->WaveTableBuffer[i] /= MaxSample; + } + } + break; + + case EWaveTable::BandLimitedTriangleWaveTable: + { + float MaxSample = 0.0f; + + for (int32 i = 0; i < WaveTableSize; ++i) + { + NewWaveTableOsc->WaveTableBuffer[i] = 0.0f; + for (int g = 1; g <= 6; ++g) + { + NewWaveTableOsc->WaveTableBuffer[i] += FMath::Pow(-1.0f, (float)g) * (1.0f / FMath::Pow(2.0f * (float)g + 1.0f, 2.0f)) * FMath::Sin(2.0f * PI * (2.0f * (float)g + 1.0f) * i / WaveTableSize); + } + + if (NewWaveTableOsc->WaveTableBuffer[i] > MaxSample) + { + MaxSample = NewWaveTableOsc->WaveTableBuffer[i]; + } + } + + for (int32 i = 0; i < WaveTableSize; ++i) + { + NewWaveTableOsc->WaveTableBuffer[i] /= MaxSample; + } + } + break; + + case EWaveTable::BandLimitedSquareWaveTable: + { + float MaxSample = 0.0f; + + for (int32 i = 0; i < WaveTableSize; ++i) + { + NewWaveTableOsc->WaveTableBuffer[i] = 0.0f; + for (int g = 1; g <= 6; ++g) + { + NewWaveTableOsc->WaveTableBuffer[i] += (1.0f / g) * (float)FMath::Sin(2.0f * PI * i * (float)g / WaveTableSize); + } + + if (NewWaveTableOsc->WaveTableBuffer[i] > MaxSample) + { + MaxSample = NewWaveTableOsc->WaveTableBuffer[i]; + } + } + + for (int32 i = 0; i < WaveTableSize; ++i) + { + NewWaveTableOsc->WaveTableBuffer[i] /= MaxSample; + } + } + break; + + case EWaveTable::Custom: + { + // don't do anything, the caller will fill in the table themselves + } + break; } - break; - - case EWaveTable::SawWaveTable: - { - const int32 HalfTableSize = WaveTableSize / 2; - const float Slope = 1.0f / HalfTableSize; - - // Rise to half-point, the offset by 1.0, continue to rise - for (int32 i = 0; i < WaveTableSize; ++i) - { - if (i < HalfTableSize) - { - NewWaveTableOsc->WaveTableBuffer[i] = Slope * i; - } - else - { - NewWaveTableOsc->WaveTableBuffer[i] = Slope * (i - HalfTableSize - 1) - 1.0f; - } - } - } - break; - - case EWaveTable::TriangleWaveTable: - { - const int32 QuarterTableSize = WaveTableSize / 4; - const int32 HalfTableSize = WaveTableSize / 2; - const int32 ThreeQuarterTableSize = 3 * WaveTableSize / 4; - const float SlopeUp = 1.0f / QuarterTableSize; - const float SlopeDown = -2.0f / HalfTableSize; - - for (int32 i = 0; i < WaveTableSize; ++i) - { - if (i < QuarterTableSize) - { - NewWaveTableOsc->WaveTableBuffer[i] = SlopeUp * i - 1.0f; - } - else if (i < ThreeQuarterTableSize) - { - NewWaveTableOsc->WaveTableBuffer[i] = SlopeDown * (i - QuarterTableSize) + 1.0f; - } - else - { - NewWaveTableOsc->WaveTableBuffer[i] = SlopeUp * (i - ThreeQuarterTableSize) - 1.0f; - } - } - } - break; - - case EWaveTable::SquareWaveTable: - { - const int32 HalfTableSize = WaveTableSize / 2; - - for (int32 i = 0; i < WaveTableSize; ++i) - { - if (i < HalfTableSize) - { - NewWaveTableOsc->WaveTableBuffer[i] = 1.0f; - } - else - { - NewWaveTableOsc->WaveTableBuffer[i] = -1.0f; - } - } - } - break; - - case EWaveTable::BandLimitedSawWaveTable: - { - float MaxSample = 0.0f; - - for (int32 i = 0; i < WaveTableSize; ++i) - { - NewWaveTableOsc->WaveTableBuffer[i] = 0.0f; - for (int32 g = 1; g <= 6; ++g) - { - NewWaveTableOsc->WaveTableBuffer[i] += FMath::Pow(-1.0f, (float)(g + 1)) * (1.0f / g) * FMath::Sin(2.0f * PI * i * (float)g / WaveTableSize); - } - - if (NewWaveTableOsc->WaveTableBuffer[i] > MaxSample) - { - MaxSample = NewWaveTableOsc->WaveTableBuffer[i]; - } - } - - for (int32 i = 0; i < WaveTableSize; ++i) - { - NewWaveTableOsc->WaveTableBuffer[i] /= MaxSample; - } - } - break; - - case EWaveTable::BandLimitedTriangleWaveTable: - { - float MaxSample = 0.0f; - - for (int32 i = 0; i < WaveTableSize; ++i) - { - NewWaveTableOsc->WaveTableBuffer[i] = 0.0f; - for (int g = 1; g <= 6; ++g) - { - NewWaveTableOsc->WaveTableBuffer[i] += FMath::Pow(-1.0f, (float)g) * (1.0f / FMath::Pow(2.0f * (float)g + 1.0f, 2.0f)) * FMath::Sin(2.0f * PI * (2.0f * (float)g + 1.0f) * i / WaveTableSize); - } - - if (NewWaveTableOsc->WaveTableBuffer[i] > MaxSample) - { - MaxSample = NewWaveTableOsc->WaveTableBuffer[i]; - } - } - - for (int32 i = 0; i < WaveTableSize; ++i) - { - NewWaveTableOsc->WaveTableBuffer[i] /= MaxSample; - } - } - break; - - case EWaveTable::BandLimitedSquareWaveTable: - { - float MaxSample = 0.0f; - - for (int32 i = 0; i < WaveTableSize; ++i) - { - NewWaveTableOsc->WaveTableBuffer[i] = 0.0f; - for (int g = 1; g <= 6; ++g) - { - NewWaveTableOsc->WaveTableBuffer[i] += (1.0f / g) * (float)sin(2.0f * PI * i * (float)g / WaveTableSize); - } - - if (NewWaveTableOsc->WaveTableBuffer[i] > MaxSample) - { - MaxSample = NewWaveTableOsc->WaveTableBuffer[i]; - } - } - - for (int32 i = 0; i < WaveTableSize; ++i) - { - NewWaveTableOsc->WaveTableBuffer[i] /= MaxSample; - } - } - break; - } - return NewWaveTableOsc; } - } diff --git a/Engine/Source/Runtime/AudioMixer/Private/Effects/AudioMixerSubmixEffectEQ.cpp b/Engine/Source/Runtime/AudioMixer/Private/Effects/AudioMixerSubmixEffectEQ.cpp index f889a6c228b7..4188be6ebb09 100644 --- a/Engine/Source/Runtime/AudioMixer/Private/Effects/AudioMixerSubmixEffectEQ.cpp +++ b/Engine/Source/Runtime/AudioMixer/Private/Effects/AudioMixerSubmixEffectEQ.cpp @@ -55,7 +55,7 @@ static bool IsEqual(const FSubmixEffectSubmixEQSettings& Left, const FSubmixEffe FSubmixEffectSubmixEQ::FSubmixEffectSubmixEQ() - : SampleRate(AUDIO_SAMPLE_RATE) + : SampleRate(0) , NumOutputChannels(2) { FMemory::Memzero((void*)ScratchInBuffer, sizeof(float) * 2); diff --git a/Engine/Source/Runtime/AudioMixer/Private/Effects/AudioMixerSubmixEffectReverb.cpp b/Engine/Source/Runtime/AudioMixer/Private/Effects/AudioMixerSubmixEffectReverb.cpp index fdd73decd0fc..301592283241 100644 --- a/Engine/Source/Runtime/AudioMixer/Private/Effects/AudioMixerSubmixEffectReverb.cpp +++ b/Engine/Source/Runtime/AudioMixer/Private/Effects/AudioMixerSubmixEffectReverb.cpp @@ -8,7 +8,7 @@ class UReverbEffect; -static int32 DisableSubmixReverbCVar = 0; +static int32 DisableSubmixReverbCVar = 1; FAutoConsoleVariableRef CVarDisableSubmixReverb( TEXT("au.DisableReverbSubmix"), DisableSubmixReverbCVar, diff --git a/Engine/Source/Runtime/AudioMixer/Public/AudioMixer.h b/Engine/Source/Runtime/AudioMixer/Public/AudioMixer.h index 29da3fb7e896..35841a25a20a 100644 --- a/Engine/Source/Runtime/AudioMixer/Public/AudioMixer.h +++ b/Engine/Source/Runtime/AudioMixer/Public/AudioMixer.h @@ -9,6 +9,7 @@ #include "AudioMixerTypes.h" #include "HAL/Runnable.h" #include "Stats/Stats.h" +#include "Classes/Sound/AudioSettings.h" // defines used for AudioMixer.h #define AUDIO_PLATFORM_ERROR(INFO) (OnAudioMixerPlatformError(INFO, FString(__FILE__), __LINE__)) @@ -96,24 +97,12 @@ namespace Audio /** The sample rate of the audio device */ int32 SampleRate; - /** The default sample of the audio device */ - int32 DefaultSampleRate; - - /** The number of frames processed by audio device */ - int32 NumFrames; - - /** The number of samples processed by the audio device (NumChannels * NumFrames) */ - int32 NumSamples; - /** The data format of the audio stream */ EAudioMixerStreamDataFormat::Type Format; /** The output channel array of the audio device */ TArray OutputChannelArray; - /** The estimated latency of the audio device */ - uint32 Latency; - /** Whether or not this device is the system default */ uint8 bIsSystemDefault : 1; @@ -128,12 +117,8 @@ namespace Audio DeviceId = TEXT("Unknown"); NumChannels = 0; SampleRate = 0; - DefaultSampleRate = 0; - NumFrames = 0; - NumSamples = 0; Format = EAudioMixerStreamDataFormat::Unknown; OutputChannelArray.Reset(); - Latency = 0; bIsSystemDefault = false; } @@ -152,6 +137,16 @@ namespace Audio virtual void OnDefaultDeviceOutputChanged(const FString& DeviceId) {} virtual void OnDefaultInputOutputChanged(const FString& DeviceId) {} + + bool IsMainAudioMixer() const { return bIsMainAudioMixer; } + + protected: + + IAudioMixer() + : bIsMainAudioMixer(false) + {} + + bool bIsMainAudioMixer; }; @@ -164,6 +159,9 @@ namespace Audio /** The number of desired audio frames in audio callback. */ uint32 NumFrames; + /** The number of queued buffers to use for the strea. */ + int32 NumBuffers; + /** Owning platform independent audio mixer ptr.*/ IAudioMixer* AudioMixer; @@ -176,6 +174,7 @@ namespace Audio FAudioMixerOpenStreamParams() : OutputDeviceIndex(INDEX_NONE) , NumFrames(1024) + , NumBuffers(1) , AudioMixer(nullptr) , SampleRate(44100) , bRestoreIfRemoved(false) @@ -195,14 +194,11 @@ namespace Audio /** The callback to use for platform-independent layer. */ IAudioMixer* AudioMixer; - /** The number of frames used in each audio callback. */ - uint32 NumOutputFrames; + /** The number of queued buffers to use. */ + uint32 NumBuffers; - /** Whether or not we need to perform a format conversion of the audio for this output device. */ - uint8 bPerformFormatConversion : 1; - - /** Whether or not we need to perform a byte swap for this output device. */ - uint8 bPerformByteSwap : 1; + /** Number of output frames */ + int32 NumOutputFrames; FAudioOutputStreamInfo() { @@ -220,9 +216,8 @@ namespace Audio DeviceInfo.Reset(); StreamState = EAudioOutputStreamState::Closed; AudioMixer = nullptr; + NumBuffers = 2; NumOutputFrames = 0; - bPerformFormatConversion = false; - bPerformByteSwap = false; } }; @@ -241,6 +236,44 @@ namespace Audio Unplugged, }; + /** Class which wraps an output float buffer and handles conversion to device stream formats. */ + class AUDIOMIXER_API FOutputBuffer + { + public: + FOutputBuffer() + : AudioMixer(nullptr) + , DataFormat(EAudioMixerStreamDataFormat::Unknown) + {} + + /** Initialize the buffer with the given samples and output format. */ + void Init(IAudioMixer* InAudioMixer, const int32 InNumSamples, const EAudioMixerStreamDataFormat::Type InDataFormat); + + /** Gets the next mixed buffer from the audio mixer. */ + void MixNextBuffer(); + + /** Returns the float buffer. */ + TArray& GetBuffer() { return Buffer; } + + /** Submits the buffer to the audio mixer. */ + const uint8* GetBufferData(); + + /** Returns if ready. */ + bool IsReady() const { return bIsReady; } + + /** Resets the buffer ready state. */ + void ResetReadyState() { bIsReady = false; } + + /** Resets the internal buffers to the new sample count. Used when device is changed. */ + void Reset(const int32 InNewNumSamples); + + private: + IAudioMixer* AudioMixer; + TArray Buffer; + TArray FormattedBuffer; + EAudioMixerStreamDataFormat::Type DataFormat; + FThreadSafeBool bIsReady; + }; + /** Abstract interface for receiving audio device changed notifications */ class AUDIOMIXER_API IAudioMixerDeviceChangedLister { @@ -262,7 +295,7 @@ namespace Audio { public: // Virtual functions - + /** Virtual destructor. */ virtual ~IAudioMixerPlatformInterface(); @@ -275,6 +308,9 @@ namespace Audio /** Check if audio device changed if applicable. Return true if audio device changed. */ virtual bool CheckAudioDeviceChange() { return false; }; + /** Resumes playback on new audio device after device change. */ + virtual void ResumePlaybackOnNewDevice() {} + /** Teardown the hardware. */ virtual bool TeardownHardware() = 0; @@ -287,6 +323,9 @@ namespace Audio /** Gets the device information of the given device index. */ virtual bool GetOutputDeviceInfo(const uint32 InDeviceIndex, FAudioPlatformDeviceInfo& OutInfo) = 0; + /** Gets the platform specific audio settings. */ + virtual FAudioPlatformSettings GetPlatformSettings() const = 0; + /** Returns the default device index. */ virtual bool GetDefaultOutputDeviceIndex(uint32& OutDefaultDeviceIndex) const = 0; @@ -309,7 +348,7 @@ namespace Audio virtual FAudioPlatformDeviceInfo GetPlatformDeviceInfo() const = 0; /** Submit the given buffer to the platform's output audio device. */ - virtual void SubmitBuffer(const TArray& Buffer) = 0; + virtual void SubmitBuffer(const uint8* Buffer) {}; /** Returns the name of the format of the input sound wave. */ virtual FName GetRuntimeFormat(USoundWave* InSoundWave) = 0; @@ -344,6 +383,12 @@ namespace Audio FString GetLastError() const { return LastError; } protected: + + // Run the "main" audio device + uint32 MainAudioDeviceRun(); + + // Wrapper around the thread Run + uint32 RunInternal(); /** Is called when an error is generated. */ inline void OnAudioMixerPlatformError(const FString& ErrorDetails, const FString& FileName, int32 LineNumber) @@ -352,9 +397,6 @@ namespace Audio UE_LOG(LogAudioMixer, Error, TEXT("%s"), *LastError); } - /** Returns the number of bytes for the given audio stream format. */ - uint32 GetNumBytesForFormat(const EAudioMixerStreamDataFormat::Type DataFormat); - /** Start generating audio from our mixer. */ void BeginGeneratingAudio(); @@ -367,25 +409,37 @@ namespace Audio /** The audio device stream info. */ FAudioOutputStreamInfo AudioStreamInfo; - - /** The number of mixer buffers. */ - static const int32 NumMixerBuffers = 2; + FAudioMixerOpenStreamParams OpenStreamParams; /** List of generated output buffers. */ - TArray OutputBuffers[NumMixerBuffers]; - bool OutputBufferReady[NumMixerBuffers]; - bool WarnedBufferUnderrun; + TArray OutputBuffers; + + /** Special empty buffer for buffer underruns. */ + FOutputBuffer UnderrunBuffer; + + /** Whether or not we warned of buffer underrun. */ + bool bWarnedBufferUnderrun; /** The audio render thread. */ FRunnableThread* AudioRenderThread; + /** The render thread sync event. */ FEvent* AudioRenderEvent; + /** Event for a single buffer render. */ + FEvent* AudioBufferEvent; + /** Event allows you to block until fadeout is complete. */ FEvent* AudioFadeEvent; - /** The current buffer index. */ - int32 CurrentBufferIndex; + /** The buffer which is currently submitted to the output device (and is being read from). */ + int32 CurrentBufferReadIndex; + + /** The buffer which is currently being rendered to (or about to be rendered to). */ + int32 CurrentBufferWriteIndex; + + /** The number of mixer buffers to queue on the output source voice. */ + int32 NumOutputBuffers; /** String containing the last generated error. */ FString LastError; @@ -397,6 +451,7 @@ namespace Audio FThreadSafeBool bFadingOut; FThreadSafeBool bFadedOut; float FadeEnvelopeValue; + }; diff --git a/Engine/Source/Runtime/AudioMixer/Public/AudioMixerDevice.h b/Engine/Source/Runtime/AudioMixer/Public/AudioMixerDevice.h index 78862bd5ca5b..847b9accde0b 100644 --- a/Engine/Source/Runtime/AudioMixer/Public/AudioMixerDevice.h +++ b/Engine/Source/Runtime/AudioMixer/Public/AudioMixerDevice.h @@ -69,6 +69,7 @@ namespace Audio virtual void SuspendContext() override; virtual void EnableDebugAudioOutput() override; virtual void InitSoundSubmixes() override; + virtual FAudioPlatformSettings GetPlatformSettings() const override; virtual void RegisterSoundSubmix(USoundSubmix* SoundSubmix, bool bInit = true) override; virtual void UnregisterSoundSubmix(USoundSubmix* SoundSubmix) override; @@ -101,7 +102,7 @@ namespace Audio int32 GetNumSpatialChannels() const { return NumSpatialChannels; } - int32 GetNumOutputFrames() const { return PlatformInfo.NumFrames; } + int32 GetNumOutputFrames() const { return PlatformSettings.CallbackBufferFrameSize; } const TArray& GetCurrentChannelPositions() const { return CurrentChannelAzimuthPositions; } diff --git a/Engine/Source/Runtime/AudioMixer/Public/Components/SynthComponent.h b/Engine/Source/Runtime/AudioMixer/Public/Components/SynthComponent.h index 818ee25f552e..a12cc504c3cc 100644 --- a/Engine/Source/Runtime/AudioMixer/Public/Components/SynthComponent.h +++ b/Engine/Source/Runtime/AudioMixer/Public/Components/SynthComponent.h @@ -148,10 +148,10 @@ protected: private: - UPROPERTY() + UPROPERTY(Transient) USynthSound* Synth; - UPROPERTY() + UPROPERTY(Transient) UAudioComponent* AudioComponent; void PumpPendingMessages(); diff --git a/Engine/Source/Runtime/AudioMixer/Public/DSP/BiQuadFilter.h b/Engine/Source/Runtime/AudioMixer/Public/DSP/BiQuadFilter.h index 3722304e3ac4..4d7e5e0d8812 100644 --- a/Engine/Source/Runtime/AudioMixer/Public/DSP/BiQuadFilter.h +++ b/Engine/Source/Runtime/AudioMixer/Public/DSP/BiQuadFilter.h @@ -34,7 +34,7 @@ namespace Audio float Output = A0 * InSample + A1 * X_Z1 + A2 * X_Z2 - B1 * Y_Z1 - B2 * Y_Z2; // Clamp the output to 0.0 if in sub-normal float region - UnderflowClamp(Output); + Output = UnderflowClamp(Output); // Apply the z-transforms Y_Z2 = Y_Z1; diff --git a/Engine/Source/Runtime/AudioMixer/Public/DSP/Envelope.h b/Engine/Source/Runtime/AudioMixer/Public/DSP/Envelope.h index b3bfa41b9e85..4275d600fdf8 100644 --- a/Engine/Source/Runtime/AudioMixer/Public/DSP/Envelope.h +++ b/Engine/Source/Runtime/AudioMixer/Public/DSP/Envelope.h @@ -13,7 +13,7 @@ namespace Audio { public: FEnvelope(); - ~FEnvelope(); + virtual ~FEnvelope(); // Initialize the envelope with the given sample rate void Init(const float InSampleRate, const int32 InVoiceId = 0, FModulationMatrix* InModMatrix = nullptr, const bool bInSimulateAnalog = true); diff --git a/Engine/Source/Runtime/AudioMixer/Public/DSP/Granulator.h b/Engine/Source/Runtime/AudioMixer/Public/DSP/Granulator.h index 730ba0ddba49..0a76f300f574 100644 --- a/Engine/Source/Runtime/AudioMixer/Public/DSP/Granulator.h +++ b/Engine/Source/Runtime/AudioMixer/Public/DSP/Granulator.h @@ -173,17 +173,11 @@ namespace Audio FGranularSynth(); ~FGranularSynth(); - void Init(FAudioDevice* InAudioDevice, const int32 NumInitialFreeGrains); + void Init(const int32 InSampleRate, const int32 InNumInitialGrains); // Loads a sound wave to use for granular synth mode - void LoadSoundWave(USoundWave* InSoundWave, const bool bLoadAsync = true); + void LoadSampleBuffer(const FSampleBuffer& InSampleBuffer); - // Updates the loading state - void UpdateSoundWaveLoading(); - - // Queries if the sound wave has finished loading - bool IsSoundWaveLoaded() const; - // Plays a granular synthesis "Note" void NoteOn(const uint32 InMidiNote, const float InVelocity, const float InDurationSec = INDEX_NONE); @@ -296,8 +290,6 @@ namespace Audio {} }; - FAudioDevice* AudioDevice; - int32 SampleRate; int32 NumChannels; @@ -348,7 +340,6 @@ namespace Audio // The buffer which holds the sample to be granulated FSampleBuffer SampleBuffer; - float SampleDuration; // The current playhead frame float CurrentPlayHeadFrame; diff --git a/Engine/Source/Runtime/AudioMixer/Public/DSP/OnePole.h b/Engine/Source/Runtime/AudioMixer/Public/DSP/OnePole.h index ec3f487543b2..78d0ca8264e0 100644 --- a/Engine/Source/Runtime/AudioMixer/Public/DSP/OnePole.h +++ b/Engine/Source/Runtime/AudioMixer/Public/DSP/OnePole.h @@ -38,24 +38,15 @@ namespace Audio /** Sets the filter frequency using normalized frequency (between 0.0 and 1.0f or 0.0 hz and Nyquist Frequency in Hz) */ FORCEINLINE void SetFrequency(const float InFrequency) { - if (CutoffFrequency != InFrequency) - { - CutoffFrequency = InFrequency; - B1 = FMath::Exp(-PI * CutoffFrequency); - A0 = 1.0f - B1; - } + CutoffFrequency = InFrequency; + B1 = FMath::Exp(-PI * CutoffFrequency); + A0 = 1.0f - B1; } float ProcessAudio(const float InputSample) { - // read the delay line to get w(n-D); call base class - // read float Yn = InputSample*A0 + B1*Z1; - - // Underflow check Yn = UnderflowClamp(Yn); - - // Write to z1 delayed sample Z1 = Yn; return Yn; } diff --git a/Engine/Source/Runtime/AudioMixer/Public/DSP/ParamInterpolator.h b/Engine/Source/Runtime/AudioMixer/Public/DSP/ParamInterpolator.h index 356b32e6df15..6e58e72050a6 100644 --- a/Engine/Source/Runtime/AudioMixer/Public/DSP/ParamInterpolator.h +++ b/Engine/Source/Runtime/AudioMixer/Public/DSP/ParamInterpolator.h @@ -17,7 +17,7 @@ namespace Audio public: FParamInterpolator(); - ~FParamInterpolator(); + virtual ~FParamInterpolator(); /** Initialize the value. */ void InitValue(const float InValue); diff --git a/Engine/Source/Runtime/AudioMixer/Public/DSP/Reverb.h b/Engine/Source/Runtime/AudioMixer/Public/DSP/Reverb.h index ba493f62327b..bcfd07cb8bcd 100644 --- a/Engine/Source/Runtime/AudioMixer/Public/DSP/Reverb.h +++ b/Engine/Source/Runtime/AudioMixer/Public/DSP/Reverb.h @@ -164,7 +164,7 @@ namespace Audio FDelayAPF APF4; // Wave table oscillator, modulates input APF in plates - FWaveTableOsc* LFO; + TSharedPtr LFO; // Plate data struction to organize each plate's delay lines and filters struct FPlate diff --git a/Engine/Source/Runtime/AudioMixer/Public/DSP/SampleBuffer.h b/Engine/Source/Runtime/AudioMixer/Public/DSP/SampleBuffer.h index d17c223c48b4..86edacb2c22f 100644 --- a/Engine/Source/Runtime/AudioMixer/Public/DSP/SampleBuffer.h +++ b/Engine/Source/Runtime/AudioMixer/Public/DSP/SampleBuffer.h @@ -16,21 +16,6 @@ namespace Audio FSampleBuffer(); ~FSampleBuffer(); - // Initialize the sample buffer - void Init(FAudioDevice* InAudioDevice); - - // Load a USoundWave and get the decoded PCM data and store internally - void LoadSoundWave(USoundWave* InSoundWave, const bool bLoadAsync = true); - - // Updates the loading state - void UpdateLoading(); - - // Queries if the sound file is loaded - bool IsLoaded() const; - - // Queries if the sound file is loading - bool IsLoading() const; - // Gets the raw PCM data of the sound wave const int16* GetData() const; @@ -46,17 +31,59 @@ namespace Audio // Gets the sample rate of the sound wave int32 GetSampleRate() const; - protected: - - // What audio device this sample buffer is playing in. - FAudioDevice* AudioDevice; - - // Sound wave object - USoundWave* SoundWave; - - bool bIsLoaded; - bool bIsLoading; + // Ptr to raw PCM data buffer + int16* RawPCMData; + // The number of samples in the buffer + int32 NumSamples; + // The number of frames in the buffer + int32 NumFrames; + // The number of channels in the buffer + int32 NumChannels; + // The sample rate of the buffer + int32 SampleRate; + // The duration of the buffer in seconds + float SampleDuration; }; + // Class which handles loading and decoding a USoundWave asset into a PCM buffer + class AUDIOMIXER_API FSoundWavePCMLoader + { + public: + FSoundWavePCMLoader(); + + // Intialize loader with audio device + void Init(FAudioDevice* InAudioDevice); + + // Loads a USoundWave, call on game thread. + void LoadSoundWave(USoundWave* InSoundWave); + + // Update the loading state. Returns true once the sound wave is loaded/decoded. + // Call on game thread. + bool Update(); + + // Returns the sample buffer data once the sound wave is loaded/decoded. Call on game thread thread. + void GetSampleBuffer(FSampleBuffer& OutSampleBuffer); + + // Empties pending sound wave load references. Call on audio rendering thread. + void Reset(); + + // Queries whether the current sound wave has finished loading/decoding + bool IsSoundWaveLoaded() const { return bIsLoaded; } + + private: + + // Ptr to the audio device to use to do the decoding + FAudioDevice* AudioDevice; + // Reference to current loading sound wave + USoundWave* SoundWave; + // Struct to meta-data of decoded PCM buffer and ptr to PCM data + FSampleBuffer SampleBuffer; + // Queue of sound wave ptrs to hold references to them until fully released in audio render thread + TQueue PendingStoppingSoundWaves; + // Whether the sound wave load/decode is in-flight + bool bIsLoading; + // Whether or not the sound wave has already been loaded + bool bIsLoaded; + }; } diff --git a/Engine/Source/Runtime/AudioMixer/Public/DSP/WaveTableOsc.h b/Engine/Source/Runtime/AudioMixer/Public/DSP/WaveTableOsc.h index afaff3359ac0..d7cc1fc59fa9 100644 --- a/Engine/Source/Runtime/AudioMixer/Public/DSP/WaveTableOsc.h +++ b/Engine/Source/Runtime/AudioMixer/Public/DSP/WaveTableOsc.h @@ -3,7 +3,6 @@ #pragma once #include "CoreMinimal.h" -#include "DSP/Osc.h" namespace Audio { @@ -26,13 +25,6 @@ namespace Audio class FWaveTableOsc; - // A factory interface for creating custom wave tables - class ICustomWaveTableOscFactory - { - public: - // Creates custom wave table with the given requested size. Custom table doesn't necessarily have to honor the requested size. - virtual FWaveTableOsc* CreateCustomWaveTable(const int32 RequestedWaveTableSize) = 0; - }; // A wave table oscillator class class AUDIOMIXER_API FWaveTableOsc @@ -65,26 +57,21 @@ namespace Audio // Returns the frequency of the wave table oscillator. float GetFrequencyHz() const { return FrequencyHz; } + // Returns the internal table used in the wave table. + TArray& GetTable(); + const TArray& GetTable() const; + // Processes the wave table, outputs the normal and quad phase (optional) values void Generate(float* OutputNormalPhase, float* OutputQuadPhase = nullptr); - // Sets the factory interface to use to create a custom wave table - static void SetCustomWaveTableOscFactory(ICustomWaveTableOscFactory* InCustomWaveTableOscFactory); - // Creates a wave table using internal factories for standard wave tables or uses custom wave table factor if it exists. - static FWaveTableOsc* CreateWaveTable(const EWaveTable::Type WaveTableType, const int32 WaveTableSize = 1024); + static TSharedPtr CreateWaveTable(const EWaveTable::Type WaveTableType, const int32 WaveTableSize = 1024); protected: void UpdateFrequency(); - // Custom wave table factory - static ICustomWaveTableOscFactory* CustomWaveTableOscFactory; - // The wave table buffer - float* WaveTableBuffer; - - // The wave table buffer size - int32 WaveTableBufferSize; + TArray WaveTableBuffer; // The frequency of the output (given the sample rate) float FrequencyHz; diff --git a/Engine/Source/Runtime/AutomationMessages/Classes/AutomationWorkerMessages.h b/Engine/Source/Runtime/AutomationMessages/Classes/AutomationWorkerMessages.h index 00426770b705..d646ca48c344 100644 --- a/Engine/Source/Runtime/AutomationMessages/Classes/AutomationWorkerMessages.h +++ b/Engine/Source/Runtime/AutomationMessages/Classes/AutomationWorkerMessages.h @@ -643,3 +643,92 @@ public: UPROPERTY(EditAnywhere, Category="Message") FString ErrorMessage; }; + + +/** + * Implements a message that handles both storing and requesting ground truth data. + * for the first time this test is run, it might need to store things, or get things. + */ +USTRUCT() +struct FAutomationWorkerTestDataRequest +{ + GENERATED_USTRUCT_BODY() + + /** The category of the data, this is purely to bucket and separate the ground truth data we store into different directories. */ + UPROPERTY(EditAnywhere, Category="Message") + FString DataType; + + /** */ + UPROPERTY(EditAnywhere, Category="Message") + FString DataPlatform; + + /** */ + UPROPERTY(EditAnywhere, Category="Message") + FString DataTestName; + + /** */ + UPROPERTY(EditAnywhere, Category="Message") + FString DataName; + + /** */ + UPROPERTY(EditAnywhere, Category="Message") + FString JsonData; +}; + +/** + * Implements a message that responds to TestDataRequests. + */ +USTRUCT() +struct FAutomationWorkerTestDataResponse +{ + GENERATED_USTRUCT_BODY() + + /** */ + UPROPERTY(EditAnywhere, Category="Message") + FString JsonData; + + UPROPERTY(EditAnywhere, Category="Message") + bool bIsNew; +}; + +/** + * Implements a message to request the performance data for this hardware. + */ +USTRUCT() +struct FAutomationWorkerPerformanceDataRequest +{ + GENERATED_USTRUCT_BODY() + + /** */ + UPROPERTY(EditAnywhere, Category="Message") + FString Platform; + + /** */ + UPROPERTY(EditAnywhere, Category="Message") + FString Hardware; + + /** */ + UPROPERTY(EditAnywhere, Category="Message") + FString TestName; + + /** */ + UPROPERTY(EditAnywhere, Category="Message") + TArray DataPoints; +}; + +/** + * Implements a message that responds to PerformanceDataRequest. + */ +USTRUCT() +struct FAutomationWorkerPerformanceDataResponse +{ + GENERATED_USTRUCT_BODY() + + /** */ + UPROPERTY(EditAnywhere, Category="Message") + bool bSuccess; + + /** */ + UPROPERTY(EditAnywhere, Category="Message") + FString ErrorMessage; +}; diff --git a/Engine/Source/Runtime/AutomationWorker/Private/AutomationWorkerModule.cpp b/Engine/Source/Runtime/AutomationWorker/Private/AutomationWorkerModule.cpp index f833462f678b..cff7e9be02c2 100644 --- a/Engine/Source/Runtime/AutomationWorker/Private/AutomationWorkerModule.cpp +++ b/Engine/Source/Runtime/AutomationWorker/Private/AutomationWorkerModule.cpp @@ -136,6 +136,7 @@ void FAutomationWorkerModule::Initialize() .Handling(this, &FAutomationWorkerModule::HandleRequestTestsMessage) .Handling(this, &FAutomationWorkerModule::HandleRunTestsMessage) .Handling(this, &FAutomationWorkerModule::HandleScreenShotCompared) + .Handling(this, &FAutomationWorkerModule::HandleTestDataRetrieved) .WithInbox(); if (MessageEndpoint.IsValid()) @@ -392,6 +393,16 @@ void FAutomationWorkerModule::HandleScreenShotCompared(const FAutomationWorkerIm FAutomationTestFramework::Get().NotifyScreenshotComparisonComplete(Message.bNew, Message.bSimilar, Message.MaxLocalDifference, Message.GlobalDifference, Message.ErrorMessage); } +void FAutomationWorkerModule::HandleTestDataRetrieved(const FAutomationWorkerTestDataResponse& Message, const IMessageContextRef& Context) +{ + FAutomationTestFramework::Get().NotifyTestDataRetrieved(Message.bIsNew, Message.JsonData); +} + +void FAutomationWorkerModule::HandlePerformanceDataRetrieved(const FAutomationWorkerPerformanceDataResponse& Message, const IMessageContextRef& Context) +{ + FAutomationTestFramework::Get().NotifyPerformanceDataRetrieved(Message.bSuccess, Message.ErrorMessage); +} + #if WITH_ENGINE void FAutomationWorkerModule::HandleScreenShotCaptured(int32 Width, int32 Height, const TArray& Bitmap) { diff --git a/Engine/Source/Runtime/AutomationWorker/Private/AutomationWorkerModule.h b/Engine/Source/Runtime/AutomationWorker/Private/AutomationWorkerModule.h index 69831fa9bb60..48af8157e8a4 100644 --- a/Engine/Source/Runtime/AutomationWorker/Private/AutomationWorkerModule.h +++ b/Engine/Source/Runtime/AutomationWorker/Private/AutomationWorkerModule.h @@ -10,6 +10,8 @@ struct FAutomationWorkerFindWorkers; struct FAutomationWorkerImageComparisonResults; +struct FAutomationWorkerTestDataResponse; +struct FAutomationWorkerPerformanceDataResponse; struct FAutomationWorkerNextNetworkCommandReply; struct FAutomationWorkerPing; struct FAutomationWorkerRequestTests; @@ -104,6 +106,12 @@ private: // Handles FAutomationWorkerImageComparisonResults messages. void HandleScreenShotCompared(const FAutomationWorkerImageComparisonResults& Message, const IMessageContextRef& Context); + // Handles FAutomationWorkerTestDataResponse messages. + void HandleTestDataRetrieved(const FAutomationWorkerTestDataResponse& Message, const IMessageContextRef& Context); + + // Handles FAutomationWorkerPerformanceDataResponse messages. + void HandlePerformanceDataRetrieved(const FAutomationWorkerPerformanceDataResponse& Message, const IMessageContextRef& Context); + // Handles FAutomationTestFramework PreTestingEvents. void HandlePreTestingEvent(); diff --git a/Engine/Source/Runtime/CinematicCamera/Private/CameraRig_Crane.cpp b/Engine/Source/Runtime/CinematicCamera/Private/CameraRig_Crane.cpp index 9fe156042dfa..ceb58a79ebb5 100644 --- a/Engine/Source/Runtime/CinematicCamera/Private/CameraRig_Crane.cpp +++ b/Engine/Source/Runtime/CinematicCamera/Private/CameraRig_Crane.cpp @@ -38,8 +38,8 @@ ACameraRig_Crane::ACameraRig_Crane(const FObjectInitializer& ObjectInitializer) CraneCameraMount->SetupAttachment(CranePitchControl); CraneCameraMount->RelativeLocation = FVector(CraneArmLength, 0.f, -15.f); // negative z == underslung mount - // create preview meshes #if WITH_EDITORONLY_DATA + // create preview meshes if (!IsRunningDedicatedServer()) { static ConstructorHelpers::FObjectFinder CraneBaseMesh(TEXT("/Engine/EditorMeshes/Camera/SM_CraneRig_Base.SM_CraneRig_Base")); diff --git a/Engine/Source/Runtime/CinematicCamera/Private/CineCameraActor.cpp b/Engine/Source/Runtime/CinematicCamera/Private/CineCameraActor.cpp index 63ac9095eea9..365288e943a4 100644 --- a/Engine/Source/Runtime/CinematicCamera/Private/CineCameraActor.cpp +++ b/Engine/Source/Runtime/CinematicCamera/Private/CineCameraActor.cpp @@ -36,7 +36,7 @@ FVector ACineCameraActor::GetLookatLocation() const FVector FinalLookat; if (LookatTrackingSettings.ActorToTrack) { - FTransform const BaseTransform = LookatTrackingSettings.ActorToTrack ? LookatTrackingSettings.ActorToTrack->GetActorTransform() : FTransform::Identity; + FTransform const BaseTransform = LookatTrackingSettings.ActorToTrack->GetActorTransform(); FinalLookat = BaseTransform.TransformPosition(LookatTrackingSettings.RelativeOffset); } else @@ -57,7 +57,7 @@ void ACineCameraActor::Tick(float DeltaTime) { Super::Tick(DeltaTime); - if (CameraComponent && ShouldTickForTracking()) + if (GetCameraComponent() && ShouldTickForTracking()) { if (LookatTrackingSettings.bEnableLookAtTracking) { diff --git a/Engine/Source/Runtime/CinematicCamera/Private/CineCameraComponent.cpp b/Engine/Source/Runtime/CinematicCamera/Private/CineCameraComponent.cpp index 72a574046601..b4edcf51495c 100644 --- a/Engine/Source/Runtime/CinematicCamera/Private/CineCameraComponent.cpp +++ b/Engine/Source/Runtime/CinematicCamera/Private/CineCameraComponent.cpp @@ -17,6 +17,8 @@ ////////////////////////////////////////////////////////////////////////// // UCameraComponent +/// @cond DOXYGEN_WARNINGS + UCineCameraComponent::UCineCameraComponent() { // Super 35mm 4 Perf @@ -57,7 +59,6 @@ UCineCameraComponent::UCineCameraComponent() #endif } - void UCineCameraComponent::PostInitProperties() { Super::PostInitProperties(); @@ -109,6 +110,7 @@ void UCineCameraComponent::TickComponent(float DeltaTime, ELevelTick TickType, F } #if WITH_EDITORONLY_DATA + void UCineCameraComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) { RecalcDerivedData(); @@ -146,8 +148,8 @@ void UCineCameraComponent::ResetProxyMeshTransform() ProxyMeshComponent->SetRelativeLocation(FVector(-46.f, 0, -24.f)); } } -#endif // WITH_EDITORONLY_DATA +#endif // WITH_EDITORONLY_DATA float UCineCameraComponent::GetHorizontalFieldOfView() const { @@ -200,6 +202,8 @@ void UCineCameraComponent::RecalcDerivedData() #endif } +/// @endcond + float UCineCameraComponent::GetDesiredFocusDistance(const FVector& InLocation) const { float DesiredFocusDistance = 0.f; @@ -251,9 +255,9 @@ void UCineCameraComponent::UpdateDebugFocusPlane() #if WITH_EDITORONLY_DATA if (FocusSettings.bDrawDebugFocusPlane && DebugFocusPlaneMesh && DebugFocusPlaneComponent) { - FVector const CamLocation = ComponentToWorld.GetLocation(); - FVector const CamDir = ComponentToWorld.GetRotation().Vector(); - FVector const FocusPoint = ComponentToWorld.GetLocation() + CamDir * GetDesiredFocusDistance(CamLocation); + FVector const CamLocation = GetComponentTransform().GetLocation(); + FVector const CamDir = GetComponentTransform().GetRotation().Vector(); + FVector const FocusPoint = GetComponentTransform().GetLocation() + CamDir * GetDesiredFocusDistance(CamLocation); DebugFocusPlaneComponent->SetWorldLocation(FocusPoint); } #endif diff --git a/Engine/Source/Runtime/CinematicCamera/Public/CineCameraActor.h b/Engine/Source/Runtime/CinematicCamera/Public/CineCameraActor.h index 0d2c986f9b5f..4f4c729a6489 100644 --- a/Engine/Source/Runtime/CinematicCamera/Public/CineCameraActor.h +++ b/Engine/Source/Runtime/CinematicCamera/Public/CineCameraActor.h @@ -11,7 +11,7 @@ class UCineCameraComponent; /** Settings to control the camera's lookat feature */ -USTRUCT() +USTRUCT(BlueprintType) struct FCameraLookatTrackingSettings { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/CinematicCamera/Public/CineCameraComponent.h b/Engine/Source/Runtime/CinematicCamera/Public/CineCameraComponent.h index 209327ff8c5d..9f51612a7b35 100644 --- a/Engine/Source/Runtime/CinematicCamera/Public/CineCameraComponent.h +++ b/Engine/Source/Runtime/CinematicCamera/Public/CineCameraComponent.h @@ -14,7 +14,7 @@ class UStaticMesh; class UStaticMeshComponent; /** #note, this struct has a details customization in CameraFilmbackSettingsCustomization.cpp/h */ -USTRUCT() +USTRUCT(BlueprintType) struct FCameraFilmbackSettings { GENERATED_USTRUCT_BODY() @@ -49,7 +49,7 @@ struct FNamedFilmbackPreset /** * #note, this struct has a details customization in CameraLensSettingsCustomization.cpp/h */ -USTRUCT() +USTRUCT(BlueprintType) struct FCameraLensSettings { GENERATED_USTRUCT_BODY() @@ -102,13 +102,18 @@ struct FNamedLensPreset UENUM() enum class ECameraFocusMethod : uint8 { - None, /** Disables DoF entirely. */ - Manual, /** Allows for specifying or animating exact focus distances. */ - Tracking, /** Locks focus to specific object. */ + /** Disables DoF entirely. */ + None, + + /** Allows for specifying or animating exact focus distances. */ + Manual, + + /** Locks focus to specific object. */ + Tracking, }; /** Settings to control tracking-focus mode. */ -USTRUCT() +USTRUCT(BlueprintType) struct FCameraTrackingFocusSettings { GENERATED_USTRUCT_BODY() @@ -132,7 +137,7 @@ struct FCameraTrackingFocusSettings }; /** Settings to control camera focus */ -USTRUCT() +USTRUCT(BlueprintType) struct FCameraFocusSettings { GENERATED_USTRUCT_BODY() @@ -149,8 +154,8 @@ struct FCameraFocusSettings UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Tracking Focus Settings") FCameraTrackingFocusSettings TrackingFocusSettings; -// TODO: Make this editor only again once UE-43122 has been completed. -//#if WITH_EDITORONLY_DATA +//~ TODO: Make this editor only again once UE-43122 has been completed. +//~ #if WITH_EDITORONLY_DATA /** True to draw a translucent plane at the current focus depth, for easy tweaking. */ UPROPERTY(Transient, EditAnywhere, Category = "Focus Settings") uint8 bDrawDebugFocusPlane : 1; @@ -158,7 +163,7 @@ struct FCameraFocusSettings /** For customizing the focus plane color, in case the default doesn't show up well in your scene. */ UPROPERTY(EditAnywhere, Category = "Focus Settings", meta = (EditCondition = "bDrawDebugFocusPlane")) FColor DebugFocusPlaneColor; -//#endif +//~ #endif /** True to use interpolation to smooth out changes in focus distance, false for focus distance changes to be instantaneous. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Focus Settings") @@ -188,14 +193,7 @@ struct FCameraFocusSettings /** * A specialized version of a camera component, geared toward cinematic usage. */ -UCLASS( - HideCategories = (CameraSettings), - HideFunctions = (SetFieldOfView, SetAspectRatio, SetConstraintAspectRatio), - Blueprintable, - ClassGroup = Camera, - meta = (BlueprintSpawnableComponent), - Config = Engine - ) +UCLASS(HideCategories = (CameraSettings), HideFunctions = (SetFieldOfView, SetAspectRatio, SetConstraintAspectRatio), Blueprintable, ClassGroup = Camera, meta = (BlueprintSpawnableComponent), Config = Engine) class CINEMATICCAMERA_API UCineCameraComponent : public UCameraComponent { GENERATED_BODY() @@ -261,7 +259,12 @@ protected: /** Set to true to skip any interpolations on the next update. Resets to false automatically. */ uint8 bResetInterpolation : 1; + /// @cond DOXYGEN_WARNINGS + virtual void PostLoad() override; + + /// @endcond + virtual void PostInitProperties() override; virtual void OnRegister() override; virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; diff --git a/Engine/Source/Runtime/ClothingSystemRuntime/Private/Assets/ClothingAsset.cpp b/Engine/Source/Runtime/ClothingSystemRuntime/Private/Assets/ClothingAsset.cpp index 8082e6911364..81f6c0bc9a09 100644 --- a/Engine/Source/Runtime/ClothingSystemRuntime/Private/Assets/ClothingAsset.cpp +++ b/Engine/Source/Runtime/ClothingSystemRuntime/Private/Assets/ClothingAsset.cpp @@ -16,6 +16,7 @@ #include "SNotificationList.h" #include "NotificationManager.h" #include "ComponentReregisterContext.h" +#include "AnimPhysObjectVersion.h" DEFINE_LOG_CATEGORY(LogClothingAsset) @@ -29,6 +30,27 @@ UClothingAsset::UClothingAsset(const FObjectInitializer& ObjectInitializer) } +void UClothingAsset::RefreshBoneMapping(USkeletalMesh* InSkelMesh) +{ + // No mesh, can't remap + if(!InSkelMesh) + { + return; + } + + if(UsedBoneNames.Num() != UsedBoneIndices.Num()) + { + UsedBoneIndices.Reset(); + UsedBoneIndices.AddDefaulted(UsedBoneNames.Num()); + } + + // Repopulate the used indices. + for(int32 BoneNameIndex = 0; BoneNameIndex < UsedBoneNames.Num(); ++BoneNameIndex) + { + UsedBoneIndices[BoneNameIndex] = InSkelMesh->RefSkeleton.FindBoneIndex(UsedBoneNames[BoneNameIndex]); + } +} + #if WITH_EDITOR void LogAndToastClothingInfo(const FText& Error) @@ -475,27 +497,6 @@ void UClothingAsset::UnbindFromSkeletalMesh(USkeletalMesh* InSkelMesh, int32 InM } } -void UClothingAsset::RefreshBoneMapping(USkeletalMesh* InSkelMesh) -{ - // No mesh, can't remap - if(!InSkelMesh) - { - return; - } - - if(UsedBoneNames.Num() != UsedBoneIndices.Num()) - { - UsedBoneIndices.Reset(); - UsedBoneIndices.AddDefaulted(UsedBoneNames.Num()); - } - - // Repopulate the used indices. - for(int32 BoneNameIndex = 0; BoneNameIndex < UsedBoneNames.Num(); ++BoneNameIndex) - { - UsedBoneIndices[BoneNameIndex] = InSkelMesh->RefSkeleton.FindBoneIndex(UsedBoneNames[BoneNameIndex]); - } -} - void UClothingAsset::InvalidateCachedData() { for(FClothLODData& CurrentLodData : LodData) @@ -596,6 +597,48 @@ void UClothingAsset::BuildLodTransitionData() } } +void UClothingAsset::ApplyParameterMasks() +{ + for(FClothLODData& Lod : LodData) + { + // First zero out the parameters, otherwise disabled masks might hang around + Lod.PhysicalMeshData.ClearParticleParameters(); + + for(FClothParameterMask_PhysMesh& Mask : Lod.ParameterMasks) + { + // Only apply enabled masks + if(!Mask.bEnabled) + { + continue; + } + + TArray* TargetArray = nullptr; + + switch(Mask.CurrentTarget) + { + case MaskTarget_PhysMesh::BackstopDistance: + TargetArray = &Lod.PhysicalMeshData.BackstopDistances; + break; + case MaskTarget_PhysMesh::BackstopRadius: + TargetArray = &Lod.PhysicalMeshData.BackstopRadiuses; + break; + case MaskTarget_PhysMesh::MaxDistance: + TargetArray = &Lod.PhysicalMeshData.MaxDistances; + break; + default: + break; + } + + if(TargetArray) + { + *TargetArray = Mask.GetValueArray(); + } + } + } + + InvalidateCachedData(); +} + bool UClothingAsset::IsValidLod(int32 InLodIndex) { return LodData.IsValidIndex(InLodIndex); @@ -616,9 +659,8 @@ void UClothingAsset::BuildSelfCollisionData() return; } - // We can inflate here by close to half, because we're only trying to make it so the spheres // can't pass through the network of other spheres. - const float SCRadius = ClothConfig.SelfCollisionRadius * 1.4f; + const float SCRadius = ClothConfig.SelfCollisionRadius * ClothConfig.SelfCollisionCullScale; const float SCRadiusSq = SCRadius * SCRadius; for(FClothLODData& Lod : LodData) @@ -693,6 +735,50 @@ void UClothingAsset::PostLoad() #if WITH_EDITORONLY_DATA CalculateReferenceBoneIndex(); #endif + + int32 CustomVersion = GetLinkerCustomVersion(FAnimPhysObjectVersion::GUID); + + if(CustomVersion < FAnimPhysObjectVersion::AddedClothingMaskWorkflow) + { +#if WITH_EDITORONLY_DATA + // Convert current parameters to masks + for(FClothLODData& Lod : LodData) + { + FClothPhysicalMeshData& PhysMesh = Lod.PhysicalMeshData; + + // Didn't do anything previously - clear out incase there's something in there + // so we can use it correctly now. + Lod.ParameterMasks.Reset(3); + + // Max distances (Always present) + Lod.ParameterMasks.AddDefaulted(); + FClothParameterMask_PhysMesh& MaxDistanceMask = Lod.ParameterMasks.Last(); + MaxDistanceMask.CopyFromPhysMesh(PhysMesh, MaskTarget_PhysMesh::MaxDistance); + MaxDistanceMask.bEnabled = true; + + // Following params are only added if necessary, if we don't have any backstop + // radii then there's no backstops. + if(PhysMesh.BackstopRadiuses.FindByPredicate([](const float& A) {return A != 0.0f; })) + { + // Backstop radii + Lod.ParameterMasks.AddDefaulted(); + FClothParameterMask_PhysMesh& BackstopRadiusMask = Lod.ParameterMasks.Last(); + BackstopRadiusMask.CopyFromPhysMesh(PhysMesh, MaskTarget_PhysMesh::BackstopRadius); + BackstopRadiusMask.bEnabled = true; + + // Backstop distances + Lod.ParameterMasks.AddDefaulted(); + FClothParameterMask_PhysMesh& BackstopDistanceMask = Lod.ParameterMasks.Last(); + BackstopDistanceMask.CopyFromPhysMesh(PhysMesh, MaskTarget_PhysMesh::BackstopDistance); + BackstopDistanceMask.bEnabled = true; + } + + } +#endif + + // Make sure we're transactional + SetFlags(RF_Transactional); + } } void UClothingAsset::CalculateReferenceBoneIndex() @@ -804,6 +890,12 @@ void UClothingAsset::CalculateReferenceBoneIndex() } +void UClothingAsset::Serialize(FArchive& Ar) +{ + Super::Serialize(Ar); + Ar.UsingCustomVersion(FAnimPhysObjectVersion::GUID); +} + void ClothingAssetUtils::GetMeshClothingAssetBindings(USkeletalMesh* InSkelMesh, TArray& OutBindings) { OutBindings.Empty(); @@ -1044,6 +1136,14 @@ void FClothPhysicalMeshData::Reset(const int32 InNumVerts) NumFixedVerts = 0; } +void FClothPhysicalMeshData::ClearParticleParameters() +{ + // All float parameter arrays can just be memzeroed + FMemory::Memzero(MaxDistances.GetData(), MaxDistances.GetAllocatedSize()); + FMemory::Memzero(BackstopDistances.GetData(), BackstopDistances.GetAllocatedSize()); + FMemory::Memzero(BackstopRadiuses.GetData(), BackstopRadiuses.GetAllocatedSize()); +} + void FClothParameterMask_PhysMesh::Initialize(const FClothPhysicalMeshData& InMeshData) { const int32 NumVerts = InMeshData.Vertices.Num(); @@ -1051,6 +1151,35 @@ void FClothParameterMask_PhysMesh::Initialize(const FClothPhysicalMeshData& InMe // Set up value array Values.Reset(NumVerts); Values.AddZeroed(NumVerts); + + bEnabled = false; +} + +void FClothParameterMask_PhysMesh::CopyFromPhysMesh(const FClothPhysicalMeshData& InMeshData, MaskTarget_PhysMesh InTarget) +{ + // Presize value arrays + Initialize(InMeshData); + + // Set our target + CurrentTarget = InTarget; + + // Copy the actual parameter data + switch(InTarget) + { + case MaskTarget_PhysMesh::BackstopDistance: + Values = InMeshData.BackstopDistances; + break; + case MaskTarget_PhysMesh::BackstopRadius: + Values = InMeshData.BackstopRadiuses; + break; + case MaskTarget_PhysMesh::MaxDistance: + Values = InMeshData.MaxDistances; + break; + default: + break; + } + + CalcRanges(); } void FClothParameterMask_PhysMesh::SetValue(int32 InVertexIndex, float InValue) @@ -1059,13 +1188,7 @@ void FClothParameterMask_PhysMesh::SetValue(int32 InVertexIndex, float InValue) { Values[InVertexIndex] = InValue; - float TempMax = 0.0f; - for(const float& Value : Values) - { - TempMax = FMath::Max(TempMax, Value); - } - - MaxValue = TempMax; + CalcRanges(); } } @@ -1074,7 +1197,10 @@ float FClothParameterMask_PhysMesh::GetValue(int32 InVertexIndex) const return InVertexIndex < Values.Num() ? Values[InVertexIndex] : 0.0f; } -#if WITH_EDITOR +const TArray& FClothParameterMask_PhysMesh::GetValueArray() const +{ + return Values; +} void FClothParameterMask_PhysMesh::CalcRanges() { @@ -1084,14 +1210,12 @@ void FClothParameterMask_PhysMesh::CalcRanges() for(const float& Value : Values) { MaxValue = FMath::Max(Value, MaxValue); - - if(Value > 0.0f) - { - MinValue = FMath::Min(Value, MinValue); - } + MinValue = FMath::Min(Value, MinValue); } } +#if WITH_EDITOR + FColor FClothParameterMask_PhysMesh::GetValueAsColor(int32 InVertexIndex) const { if(InVertexIndex < Values.Num()) @@ -1158,4 +1282,19 @@ void FClothParameterMask_PhysMesh::Apply(FClothPhysicalMeshData& InTargetMesh) } } +#if WITH_EDITORONLY_DATA + +void FClothLODData::GetParameterMasksForTarget(const MaskTarget_PhysMesh& InTarget, TArray& OutMasks) +{ + for(FClothParameterMask_PhysMesh& Mask : ParameterMasks) + { + if(Mask.CurrentTarget == InTarget) + { + OutMasks.Add(&Mask); + } + } +} + +#endif + #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Runtime/ClothingSystemRuntime/Private/ClothingSimulation.cpp b/Engine/Source/Runtime/ClothingSystemRuntime/Private/ClothingSimulation.cpp index 3a4a5f2801a1..666c751b6045 100644 --- a/Engine/Source/Runtime/ClothingSystemRuntime/Private/ClothingSimulation.cpp +++ b/Engine/Source/Runtime/ClothingSystemRuntime/Private/ClothingSimulation.cpp @@ -2,18 +2,28 @@ #include "ClothingSimulation.h" +#include "PhysicsEngine/PhysicsSettings.h" +#include "Components/SkeletalMeshComponent.h" #include "ClothingSimulationInterface.h" #include "ClothingSystemRuntimeModule.h" -#include "Components/SkeletalMeshComponent.h" - #include "ClothingAsset.h" + DECLARE_CYCLE_STAT(TEXT("Skin Physics Mesh"), STAT_ClothSkinPhysMesh, STATGROUP_Physics); +FClothingSimulationBase::FClothingSimulationBase() +{ + MaxPhysicsDelta = UPhysicsSettings::Get()->MaxPhysicsDeltaTime; +} + void FClothingSimulationBase::SkinPhysicsMesh(UClothingAsset* InAsset, const FClothPhysicalMeshData& InMesh, const FTransform& RootBoneTransform, const FMatrix* InBoneMatrices, const int32 InNumBoneMatrices, TArray& OutPositions, TArray& OutNormals) { SCOPE_CYCLE_COUNTER(STAT_ClothSkinPhysMesh); + // Ignore any user scale. It's already accounted for in our skinning matrices + FTransform RootBoneTransformInternal = RootBoneTransform; + RootBoneTransformInternal.SetScale3D(FVector(1.0f)); + const uint32 NumVerts = InMesh.Vertices.Num(); OutPositions.Empty(NumVerts); @@ -121,8 +131,8 @@ void FClothingSimulationBase::SkinPhysicsMesh(UClothingAsset* InAsset, const FCl } } - OutPosition = RootBoneTransform.InverseTransformPosition(OutPosition); - OutNormal = RootBoneTransform.InverseTransformVector(OutNormal); + OutPosition = RootBoneTransformInternal.InverseTransformPosition(OutPosition); + OutNormal = RootBoneTransformInternal.InverseTransformVector(OutNormal); OutNormal = OutNormal.GetUnsafeNormal(); } } @@ -130,27 +140,47 @@ void FClothingSimulationBase::SkinPhysicsMesh(UClothingAsset* InAsset, const FCl void FClothingSimulationBase::FillContext(USkeletalMeshComponent* InComponent, IClothingSimulationContext* InOutContext) { FClothingSimulationContextBase* BaseContext = static_cast(InOutContext); - BaseContext->ComponentToWorld = InComponent->ComponentToWorld; + BaseContext->ComponentToWorld = InComponent->GetComponentTransform(); BaseContext->PredictedLod = InComponent->PredictedLODLevel; InComponent->GetWindForCloth_GameThread(BaseContext->WindVelocity, BaseContext->WindAdaption); - + USkeletalMesh* SkelMesh = InComponent->SkeletalMesh; + if(USkinnedMeshComponent* MasterComponent = InComponent->MasterPoseComponent.Get()) { const int32 NumBones = InComponent->MasterBoneMap.Num(); - + BaseContext->BoneTransforms.Empty(NumBones); BaseContext->BoneTransforms.AddDefaulted(NumBones); for(int32 BoneIndex = 0; BoneIndex < NumBones; ++BoneIndex) { + bool bFoundMaster = false; if(InComponent->MasterBoneMap.IsValidIndex(BoneIndex)) { - const int32 ParentIndex = InComponent->MasterBoneMap[BoneIndex]; - BaseContext->BoneTransforms[BoneIndex] = MasterComponent->GetComponentSpaceTransforms()[ParentIndex]; + const int32 MasterIndex = InComponent->MasterBoneMap[BoneIndex]; + + if(MasterIndex != INDEX_NONE) + { + BaseContext->BoneTransforms[BoneIndex] = MasterComponent->GetComponentSpaceTransforms()[MasterIndex]; + bFoundMaster = true; + } } - else + + if(!bFoundMaster) { - BaseContext->BoneTransforms[BoneIndex] = FTransform::Identity; + if(SkelMesh) + { + const int32 ParentIndex = SkelMesh->RefSkeleton.GetParentIndex(BoneIndex); + + if(ParentIndex != INDEX_NONE) + { + BaseContext->BoneTransforms[BoneIndex] = BaseContext->BoneTransforms[ParentIndex] * SkelMesh->RefSkeleton.GetRefBonePose()[BoneIndex]; + } + else + { + BaseContext->BoneTransforms[BoneIndex] = SkelMesh->RefSkeleton.GetRefBonePose()[BoneIndex]; + } + } } } } @@ -162,7 +192,7 @@ void FClothingSimulationBase::FillContext(USkeletalMeshComponent* InComponent, I UWorld* ComponentWorld = InComponent->GetWorld(); check(ComponentWorld); - BaseContext->DeltaSeconds = ComponentWorld->GetDeltaSeconds(); + BaseContext->DeltaSeconds = FMath::Min(ComponentWorld->GetDeltaSeconds(), MaxPhysicsDelta); BaseContext->TeleportMode = InComponent->ClothTeleportMode; diff --git a/Engine/Source/Runtime/ClothingSystemRuntime/Private/ClothingSimulationNv.cpp b/Engine/Source/Runtime/ClothingSystemRuntime/Private/ClothingSimulationNv.cpp index 907f027494f5..2d5cc2da4ebd 100644 --- a/Engine/Source/Runtime/ClothingSystemRuntime/Private/ClothingSimulationNv.cpp +++ b/Engine/Source/Runtime/ClothingSystemRuntime/Private/ClothingSimulationNv.cpp @@ -24,6 +24,8 @@ #include "DynamicMeshBuilder.h" #endif +#include "PhysicsEngine/PhysicsAsset.h" + DECLARE_CYCLE_STAT(TEXT("Compute Clothing Normals"), STAT_NvClothComputeNormals, STATGROUP_Physics); DECLARE_CYCLE_STAT(TEXT("Internal Solve"), STAT_NvClothInternalSolve, STATGROUP_Physics); DECLARE_CYCLE_STAT(TEXT("Update Collisions"), STAT_NvClothUpdateCollisions, STATGROUP_Physics); @@ -180,22 +182,105 @@ void FClothingSimulationNv::CreateActor(USkeletalMeshComponent* InOwnerComponent // Keep track of our asset NewActor.AssetCreatedFrom = Asset; - // Initialise storage arrays for data that will be generated during the sim step - NewActor.CurrentNormals.AddDefaulted(NumVerts); - NewActor.SkinnedPhysicsMeshPositions.AddZeroed(NumVerts); - NewActor.SkinnedPhysicsMeshNormals.AddZeroed(NumVerts); + // LOD0 is responsible on the first frame, so store off current data for frame-0 for LOD0 + if(LodIndex == 0) + { + // Initialise storage arrays for data that will be generated during the sim step + NewActor.CurrentNormals.AddDefaulted(NumVerts); + NewActor.SkinnedPhysicsMeshPositions.AddZeroed(NumVerts); + NewActor.SkinnedPhysicsMeshNormals.AddZeroed(NumVerts); - NewActor.SkinnedPhysicsMeshPositions = SkinnedVerts; + NewActor.SkinnedPhysicsMeshPositions = SkinnedVerts; + NewActor.SkinnedPhysicsMeshNormals = SkinnedNormals; + } } ApplyClothConfig(Asset->ClothConfig, NewActor, InOwnerComponent); + // Pull collisions from the specified physics asset inside the clothing asset + ExtractActorCollisions(InOwnerComponent, Asset, NewActor); + // Always start at zero, we'll pick up the right one before we simulate on the first tick CurrentMeshLodIndex = 0; NewActor.CurrentLodIndex = 0; check(NewActor.LodData.IsValidIndex(0)); + Solver->addCloth(NewActor.LodData[0].Cloth); + + // Force update LODs so we're in the correct state now + UpdateLod(InOwnerComponent->PredictedLODLevel, InOwnerComponent->ComponentToWorld, InOwnerComponent->GetComponentSpaceTransforms(), true); + + // Compute normals for all active actors for first frame + for(FClothingActorNv& Actor : Actors) + { + if(Actor.CurrentLodIndex != INDEX_NONE) + { + ComputePhysicalMeshNormals(Actor); + } + } +} + +void FClothingSimulationNv::ExtractActorCollisions(USkeletalMeshComponent* InOwnerComponent, UClothingAsset* Asset, FClothingActorNv &InActor) +{ + // Build collision data for this Actor + USkeletalMesh* TargetMesh = InOwnerComponent->SkeletalMesh; + if(UPhysicsAsset* PhysAsset = Asset->PhysicsAsset) + { + bool bAddedBodies = false; + for(const USkeletalBodySetup* BodySetup : PhysAsset->SkeletalBodySetups) + { + int32 MeshBoneIndex = TargetMesh->RefSkeleton.FindBoneIndex(BodySetup->BoneName); + int32 MappedBoneIndex = INDEX_NONE; + + if(MeshBoneIndex != INDEX_NONE) + { + MappedBoneIndex = Asset->UsedBoneNames.AddUnique(BodySetup->BoneName); + } + + for(const FKSphereElem& Sphere : BodySetup->AggGeom.SphereElems) + { + FClothCollisionPrim_Sphere NewSphere; + NewSphere.LocalPosition = Sphere.Center; + NewSphere.Radius = Sphere.Radius; + NewSphere.BoneIndex = MappedBoneIndex; + + InActor.ExtractedCollisions.Spheres.Add(NewSphere); + bAddedBodies = true; + } + + for(const FKSphylElem& Sphyl : BodySetup->AggGeom.SphylElems) + { + FClothCollisionPrim_Sphere Sphere0; + FClothCollisionPrim_Sphere Sphere1; + FVector OrientedDirection = Sphyl.Rotation.RotateVector(FVector(0.0f, 0.0f, 1.0f)); + FVector HalfDim = OrientedDirection * (Sphyl.Length / 2.0f); + Sphere0.LocalPosition = Sphyl.Center - HalfDim; + Sphere1.LocalPosition = Sphyl.Center + HalfDim; + Sphere0.Radius = Sphyl.Radius; + Sphere1.Radius = Sphyl.Radius; + Sphere0.BoneIndex = MappedBoneIndex; + Sphere1.BoneIndex = MappedBoneIndex; + + InActor.ExtractedCollisions.Spheres.Add(Sphere0); + InActor.ExtractedCollisions.Spheres.Add(Sphere1); + + FClothCollisionPrim_SphereConnection Connection; + Connection.SphereIndices[0] = InActor.ExtractedCollisions.Spheres.Num() - 2; + Connection.SphereIndices[1] = InActor.ExtractedCollisions.Spheres.Num() - 1; + + InActor.ExtractedCollisions.SphereConnections.Add(Connection); + bAddedBodies = true; + } + } + + // Dirty the actor collisions if we've changed the bodies + InActor.bCollisionsDirty |= bAddedBodies; + + // If we've used a bone that isn't in our skinned set we will have added entries + // to UsedBoneNames, so rebuild the bone mapping so our collisions work at runtime + Asset->RefreshBoneMapping(TargetMesh); + } } void FClothingSimulationNv::ApplyClothConfig(FClothConfig &Config, FClothingActorNv &InActor, USkeletalMeshComponent* InOwnerComponent) @@ -223,9 +308,9 @@ void FClothingSimulationNv::ApplyClothConfig(FClothConfig &Config, FClothingActo 1.0f - FMath::Exp(ExpDragLinY * PrecalcLog2), 1.0f - FMath::Exp(ExpDragLinZ * PrecalcLog2)); - const FVector AdjustedDragAng(1.0f - FMath::Exp(ExpDragLinX * PrecalcLog2), - 1.0f - FMath::Exp(ExpDragLinY * PrecalcLog2), - 1.0f - FMath::Exp(ExpDragLinZ * PrecalcLog2)); + const FVector AdjustedDragAng(1.0f - FMath::Exp(ExpDragAngX * PrecalcLog2), + 1.0f - FMath::Exp(ExpDragAngY * PrecalcLog2), + 1.0f - FMath::Exp(ExpDragAngZ * PrecalcLog2)); for(FClothingActorNv::FActorLodData& LodData : InActor.LodData) { @@ -356,7 +441,7 @@ void FClothingSimulationNv::Simulate(IClothingSimulationContext* InContext) { FClothingSimulationContextNv* NvContext = (FClothingSimulationContextNv*)InContext; - UpdateLod(NvContext); + UpdateLod(NvContext->PredictedLod, NvContext->ComponentToWorld, NvContext->BoneTransforms); // Pre-sim work for(FClothingActorNv& Actor : Actors) @@ -379,39 +464,39 @@ void FClothingSimulationNv::Simulate(IClothingSimulationContext* InContext) const FClothPhysicalMeshData& PhysMesh = Actor.AssetCreatedFrom->LodData[Actor.CurrentLodIndex].PhysicalMeshData; FClothingSimulationBase::SkinPhysicsMesh(Actor.AssetCreatedFrom, PhysMesh, RootBoneTransform, NvContext->RefToLocals.GetData(), NvContext->RefToLocals.Num(), Actor.SkinnedPhysicsMeshPositions, Actor.SkinnedPhysicsMeshNormals); - Actor.UpdateMotionConstraints(NvContext); - nv::cloth::Cloth* CurrentCloth = Actor.LodData[Actor.CurrentLodIndex].Cloth; + bool bTeleport = NvContext->TeleportMode > EClothingTeleportMode::None; + bool bReset = NvContext->TeleportMode == EClothingTeleportMode::TeleportAndReset; + + if(bReset) + { + nv::cloth::Range CurrParticles = CurrentCloth->getCurrentParticles(); + nv::cloth::Range PrevParticles = CurrentCloth->getPreviousParticles(); + const int32 NumParticles = CurrentCloth->getNumParticles(); + check(NumParticles == Actor.SkinnedPhysicsMeshPositions.Num()); + + for(int32 ParticleIndex = 0; ParticleIndex < NumParticles; ++ParticleIndex) + { + CurrParticles[ParticleIndex] = physx::PxVec4(U2PVector(Actor.SkinnedPhysicsMeshPositions[ParticleIndex]), CurrParticles[ParticleIndex].w); + PrevParticles[ParticleIndex] = CurrParticles[ParticleIndex]; + } + + CurrentCloth->clearParticleAccelerations(); + } + // Push the component position into the actor, this will set up the forces in local space to simulate the movement FTransform RootBoneWorldTransform = RootBoneTransform * NvContext->ComponentToWorld; CurrentCloth->setTranslation(U2PVector(RootBoneWorldTransform.GetTranslation())); CurrentCloth->setRotation(U2PQuat(RootBoneWorldTransform.GetRotation())); - bool bTeleport = NvContext->TeleportMode > EClothingTeleportMode::None; - bool bReset = NvContext->TeleportMode == EClothingTeleportMode::TeleportAndReset; - if(bTeleport) { CurrentCloth->clearInertia(); - - if(bReset) - { - nv::cloth::Range CurrParticles = CurrentCloth->getCurrentParticles(); - nv::cloth::Range PrevParticles = CurrentCloth->getPreviousParticles(); - const int32 NumParticles = CurrentCloth->getNumParticles(); - check(NumParticles == Actor.SkinnedPhysicsMeshPositions.Num()); - - for(int32 ParticleIndex = 0; ParticleIndex < NumParticles; ++ParticleIndex) - { - CurrParticles[ParticleIndex] = physx::PxVec4(U2PVector(Actor.SkinnedPhysicsMeshPositions[ParticleIndex]), CurrParticles[ParticleIndex].w); - PrevParticles[ParticleIndex] = CurrParticles[ParticleIndex]; - } - - CurrentCloth->clearParticleAccelerations(); - } } + Actor.UpdateMotionConstraints(NvContext); + { SCOPE_CYCLE_COUNTER(STAT_NvClothUpdateCollisions); // Set collision spheres for this frame @@ -469,10 +554,13 @@ void FClothingSimulationNv::Simulate(IClothingSimulationContext* InContext) { CollisionPlanes.AddDefaulted(); physx::PxVec4& NewPlane = CollisionPlanes.Last(); - NewPlane.x = ConvexPlane.X; - NewPlane.y = ConvexPlane.Y; - NewPlane.z = ConvexPlane.Z; - NewPlane.w = -ConvexPlane.W; + + FPlane TempPlane = ConvexPlane.TransformBy(RootBoneTransform.ToMatrixWithScale().Inverse()); + + NewPlane.x = TempPlane.X; + NewPlane.y = TempPlane.Y; + NewPlane.z = TempPlane.Z; + NewPlane.w = -TempPlane.W; ConvexMask |= (1 << (CollisionPlanes.Num() - 1)); @@ -608,7 +696,7 @@ void FClothingSimulationNv::GetSimulationData(TMap& OutD bool bFoundSimData = false; - const FTransform& OwnerTransform = InOwnerComponent->ComponentToWorld; + const FTransform& OwnerTransform = InOwnerComponent->GetComponentTransform(); for(int32 ActorIdx = 0; ActorIdx < NumActors; ++ActorIdx) { @@ -627,6 +715,7 @@ void FClothingSimulationNv::GetSimulationData(TMap& OutD NvClothSupport::ClothParticleScopeLock ParticleLock(Actor.LodData[CurrentClothingLod].Cloth); FTransform RootBoneTransform = InOverrideComponent ? InOverrideComponent->GetComponentSpaceTransforms()[Asset->ReferenceBoneIndex] : InOwnerComponent->GetComponentSpaceTransforms()[Asset->ReferenceBoneIndex]; + RootBoneTransform.SetScale3D(FVector(1.0f)); RootBoneTransform *= OwnerTransform; const uint32 NumParticles = Actor.LodData[CurrentClothingLod].Cloth->getNumParticles(); @@ -743,14 +832,14 @@ FBoxSphereBounds FClothingSimulationNv::GetBounds(const USkeletalMeshComponent* return CurrentBounds; } -void FClothingSimulationNv::UpdateLod(FClothingSimulationContextNv* InContext) +void FClothingSimulationNv::UpdateLod(int32 InPredictedLod, const FTransform& ComponentToWorld, const TArray& CSTransforms, bool bForceNoRemap) { - if(InContext->PredictedLod != CurrentMeshLodIndex) + if(InPredictedLod != CurrentMeshLodIndex) { for(FClothingActorNv& Actor : Actors) { const TArray LodMap = Actor.AssetCreatedFrom->LodMap; - if(!LodMap.IsValidIndex(InContext->PredictedLod)) + if(!LodMap.IsValidIndex(InPredictedLod)) { // New LOD unmapped, remove old LOD and move on if(Actor.CurrentLodIndex != INDEX_NONE) @@ -766,10 +855,10 @@ void FClothingSimulationNv::UpdateLod(FClothingSimulationContextNv* InContext) continue; } - bool bOldLodMapped = LodMap.IsValidIndex(CurrentMeshLodIndex); + bool bOldLodMapped = LodMap.IsValidIndex(CurrentMeshLodIndex) && LodMap[CurrentMeshLodIndex] != INDEX_NONE; // Get the clothing LOD mapped from the mesh predicted LOD - const int32 PredictedClothingLod = LodMap[InContext->PredictedLod]; + const int32 PredictedClothingLod = LodMap[InPredictedLod]; const int32 OldClothingLod = bOldLodMapped ? LodMap[CurrentMeshLodIndex] : INDEX_NONE; if(!Actor.LodData.IsValidIndex(PredictedClothingLod)) @@ -796,7 +885,7 @@ void FClothingSimulationNv::UpdateLod(FClothingSimulationContextNv* InContext) nv::cloth::Range NewLodPrevParticles = NewLodData.Cloth->getPreviousParticles(); nv::cloth::Range NewAccelerations = NewLodData.Cloth->getParticleAccelerations(); - if(bOldLodMapped) + if(bOldLodMapped && !bForceNoRemap) { FClothingActorNv::FActorLodData& CurrLodData = Actor.LodData[OldClothingLod]; @@ -862,10 +951,10 @@ void FClothingSimulationNv::UpdateLod(FClothingSimulationContextNv* InContext) } } - NewLodData.Cloth->clearInterpolation(); + FTransform SimRootTransform = CSTransforms[Actor.AssetCreatedFrom->ReferenceBoneIndex] * ComponentToWorld; + NewLodData.Cloth->setTranslation(U2PVector(SimRootTransform.GetTranslation())); + NewLodData.Cloth->setRotation(U2PQuat(SimRootTransform.GetRotation())); NewLodData.Cloth->clearInertia(); - NewLodData.Cloth->clearMotionConstraints(); - NewLodData.Cloth->clearSeparationConstraints(); Actor.CurrentLodIndex = PredictedClothingLod; } @@ -883,10 +972,10 @@ void FClothingSimulationNv::UpdateLod(FClothingSimulationContextNv* InContext) NewAccelerations[ParticleIndex] = physx::PxVec4(0.0f); } - NewLodData.Cloth->clearInterpolation(); + FTransform SimRootTransform = CSTransforms[Actor.AssetCreatedFrom->ReferenceBoneIndex] * ComponentToWorld; + NewLodData.Cloth->setTranslation(U2PVector(SimRootTransform.GetTranslation())); + NewLodData.Cloth->setRotation(U2PQuat(SimRootTransform.GetRotation())); NewLodData.Cloth->clearInertia(); - NewLodData.Cloth->clearMotionConstraints(); - NewLodData.Cloth->clearSeparationConstraints(); Actor.CurrentLodIndex = PredictedClothingLod; } @@ -897,7 +986,7 @@ void FClothingSimulationNv::UpdateLod(FClothingSimulationContextNv* InContext) } } - CurrentMeshLodIndex = InContext->PredictedLod; + CurrentMeshLodIndex = InPredictedLod; } } @@ -919,7 +1008,9 @@ void FClothingSimulationNv::DebugDraw_PhysMesh(USkeletalMeshComponent* OwnerComp check(CurrentCloth); + FTransform RootBoneTransform = OwnerComponent->GetComponentSpaceTransforms()[Actor.AssetCreatedFrom->ReferenceBoneIndex]; + RootBoneTransform.SetScale3D(FVector(1.0f)); NvClothSupport::ClothParticleScopeLock ParticleLoc(CurrentCloth); @@ -992,7 +1083,12 @@ void FClothingSimulationNv::DebugDraw_Collision(USkeletalMeshComponent* OwnerCom { for(const FClothingActorNv& Actor : Actors) { - const FClothCollisionData& CollisionData = Actor.AssetCreatedFrom->LodData[Actor.CurrentLodIndex].CollisionData; + if(Actor.CurrentLodIndex == INDEX_NONE) + { + continue; + } + + const FClothCollisionData& CollisionData = Actor.AggregatedCollisions; for(const FClothCollisionPrim_SphereConnection& Connection : CollisionData.SphereConnections) { @@ -1166,6 +1262,8 @@ void FClothingSimulationNv::DebugDraw_SelfCollision(USkeletalMeshComponent* Owne continue; } + FTransform RootBoneTransform = OwnerComponent->GetComponentSpaceTransforms()[Actor.AssetCreatedFrom->ReferenceBoneIndex]; + const float SelfCollisionThickness = Config.SelfCollisionRadius; @@ -1183,7 +1281,7 @@ void FClothingSimulationNv::DebugDraw_SelfCollision(USkeletalMeshComponent* Owne for(int32 SelfColIdx = 0; SelfColIdx < PhysMesh.SelfCollisionIndices.Num(); ++SelfColIdx) { - FVector ParticlePosition = P2UVector(Particles[PhysMesh.SelfCollisionIndices[SelfColIdx]]); + FVector ParticlePosition = RootBoneTransform.TransformPosition(P2UVector(Particles[PhysMesh.SelfCollisionIndices[SelfColIdx]])); DrawWireSphere(PDI, ParticlePosition, FColor::White, SelfCollisionThickness, 8, SDPG_World, 0.2f); } } @@ -1302,8 +1400,15 @@ void FClothingActorNv::ConditionalRebuildCollisions() } AggregatedCollisions.Reset(); + + // Asset-embedded collisions (created during import) AggregatedCollisions.Append(AssetCreatedFrom->LodData[CurrentLodIndex].CollisionData); + // Extracted collisions from the physics asset selected by the user + AggregatedCollisions.Append(ExtractedCollisions); + // External collisions added from the world AggregatedCollisions.Append(ExternalCollisions); + + bCollisionsDirty = false; } void FClothingActorNv::CalculateParticleVelocities(TArray& OutVelocities) diff --git a/Engine/Source/Runtime/ClothingSystemRuntime/Public/Assets/ClothingAsset.h b/Engine/Source/Runtime/ClothingSystemRuntime/Public/Assets/ClothingAsset.h index 9de32b5a8680..c43b8a1c9765 100644 --- a/Engine/Source/Runtime/ClothingSystemRuntime/Public/Assets/ClothingAsset.h +++ b/Engine/Source/Runtime/ClothingSystemRuntime/Public/Assets/ClothingAsset.h @@ -11,6 +11,7 @@ #include "ClothingAsset.generated.h" class UClothingAsset; +class UPhysicsAsset; struct FClothPhysicalMeshData; namespace nvidia @@ -43,12 +44,27 @@ struct CLOTHINGSYSTEMRUNTIME_API FClothParameterMask_PhysMesh { GENERATED_BODY(); + FClothParameterMask_PhysMesh() + : MaskName(NAME_None) + , CurrentTarget(MaskTarget_PhysMesh::None) + , MaxValue(-MAX_flt) + , MinValue(MAX_flt) + , bEnabled(false) + {} + /** * Initialize the mask based on the specified mesh data * @param InMeshData the mesh to initialize against */ void Initialize(const FClothPhysicalMeshData& InMeshData); + /** + * Copies the specified parameter from a physical mesh + * @param InMeshData The mesh to copy from + * @param InTarget The target parameter to copy + */ + void CopyFromPhysMesh(const FClothPhysicalMeshData& InMeshData, MaskTarget_PhysMesh InTarget); + /** * Set a value in the mask * @param InVertexIndex the value/vertex index to set @@ -62,11 +78,15 @@ struct CLOTHINGSYSTEMRUNTIME_API FClothParameterMask_PhysMesh */ float GetValue(int32 InVertexIndex) const; -#if WITH_EDITOR + /** + * Read only version of the array holding the mask values + */ + const TArray& GetValueArray() const; - /** Calculates Min/Max values based on values. Call before querying colors */ + /** Calculates Min/Max values based on values. */ void CalcRanges(); +#if WITH_EDITOR /** * Get a value represented as a preview color for painting * @param InVertexIndex the value/vertex index to retrieve @@ -99,6 +119,10 @@ struct CLOTHINGSYSTEMRUNTIME_API FClothParameterMask_PhysMesh /** The actual values stored in the mask */ UPROPERTY() TArray Values; + + /** Whether this mask is enabled and able to effect final mesh values */ + UPROPERTY() + bool bEnabled; }; // Bone data for a vertex @@ -132,6 +156,9 @@ struct CLOTHINGSYSTEMRUNTIME_API FClothPhysicalMeshData void Reset(const int32 InNumVerts); + // Clear out any target properties in this physical mesh + void ClearParticleParameters(); + // Positions of each simulation vertex UPROPERTY(EditAnywhere, Category = SimMesh) TArray Vertices; @@ -178,7 +205,7 @@ struct CLOTHINGSYSTEMRUNTIME_API FClothPhysicalMeshData }; USTRUCT() -struct FClothLODData +struct CLOTHINGSYSTEMRUNTIME_API FClothLODData { GENERATED_BODY() @@ -194,6 +221,10 @@ struct FClothLODData // Parameter masks defining the physics mesh masked data UPROPERTY(EditAnywhere, Category = Masks) TArray ParameterMasks; + + // Get all available parameter masks for the specified target + void GetParameterMasksForTarget(const MaskTarget_PhysMesh& InTarget, TArray& OutMasks); + #endif // Skinning data for transitioning from a higher detail LOD to this one @@ -282,6 +313,7 @@ struct FClothConfig : WindMethod(EClothingWindMethod::Legacy) , SelfCollisionRadius(0.0f) , SelfCollisionStiffness(0.0f) + , SelfCollisionCullScale(1.0f) , Damping(0.4f) , Friction(0.1f) , WindDragCoefficient(0.02f/100.0f) @@ -329,6 +361,16 @@ struct FClothConfig UPROPERTY(EditAnywhere, Category = ClothConfig) float SelfCollisionStiffness; + /** + * Scale to use for the radius of the culling checks for self collisions. + * Any other self collision body within the radius of this check will be culled. + * This helps performance with higher resolution meshes by reducing the number + * of colliding bodies within the cloth. Reducing this will have a negative + * effect on performance! + */ + UPROPERTY(EditAnywhere, Category = ClothConfig, meta = (UIMin="0", ClampMin="0")) + float SelfCollisionCullScale; + // Damping of particle motion per-axis UPROPERTY(EditAnywhere, Category = ClothConfig) FVector Damping; @@ -477,12 +519,12 @@ public: UClothingAsset(const FObjectInitializer& ObjectInitializer); -#if WITH_EDITOR // UClothingAssetBase Interface //////////////////////////////////////////// + virtual void RefreshBoneMapping(USkeletalMesh* InSkelMesh) override; +#if WITH_EDITOR virtual bool BindToSkeletalMesh(USkeletalMesh* InSkelMesh, int32 InMeshLodIndex, int32 InSectionIndex, int32 InAssetLodIndex) override; virtual void UnbindFromSkeletalMesh(USkeletalMesh* InSkelMesh) override; virtual void UnbindFromSkeletalMesh(USkeletalMesh* InSkelMesh, int32 InMeshLodIndex) override; - virtual void RefreshBoneMapping(USkeletalMesh* InSkelMesh) override; virtual void InvalidateCachedData() override; virtual bool IsValidLod(int32 InLodIndex) override; virtual int32 GetNumLods() override; @@ -494,9 +536,17 @@ public: * in exactly the same way the render mesh is skinned to create a smooth swap */ void BuildLodTransitionData(); + + /** + * Applies the painted parameter masks to the final parameters in the physical mesh + */ + void ApplyParameterMasks(); #endif + // UObject Interface ////////////////////////////////////////////////////// virtual void PostLoad() override; + virtual void Serialize(FArchive& Ar) override; + // End UObject Interface ////////////////////////////////////////////////// /** * Builds self collision data @@ -508,6 +558,10 @@ public: // Calculates the prefered root bone for the simulation void CalculateReferenceBoneIndex(); + // The physics asset to extract collisions from when building a simulation + UPROPERTY(EditAnywhere, Category = Config) + UPhysicsAsset* PhysicsAsset; + // Configuration of the cloth, contains all the parameters for how the clothing behaves UPROPERTY(EditAnywhere, Category = Config) FClothConfig ClothConfig; diff --git a/Engine/Source/Runtime/ClothingSystemRuntime/Public/ClothingSimulation.h b/Engine/Source/Runtime/ClothingSystemRuntime/Public/ClothingSimulation.h index bf291dfd4684..9fa06ad55055 100644 --- a/Engine/Source/Runtime/ClothingSystemRuntime/Public/ClothingSimulation.h +++ b/Engine/Source/Runtime/ClothingSystemRuntime/Public/ClothingSimulation.h @@ -66,8 +66,7 @@ class FClothingSimulationBase : public IClothingSimulation { public: - FClothingSimulationBase() - {} + FClothingSimulationBase(); virtual ~FClothingSimulationBase() {} @@ -77,6 +76,10 @@ public: protected: + /** Fills in the base data for a clothing simulation */ virtual void FillContext(USkeletalMeshComponent* InComponent, IClothingSimulationContext* InOutContext) override; + /** Maximum physics time, incoming deltas will be clamped down to this value on long frames */ + float MaxPhysicsDelta; + }; diff --git a/Engine/Source/Runtime/ClothingSystemRuntime/Public/ClothingSimulationNv.h b/Engine/Source/Runtime/ClothingSystemRuntime/Public/ClothingSimulationNv.h index 02c95c6cddf0..6d6ac94c8175 100644 --- a/Engine/Source/Runtime/ClothingSystemRuntime/Public/ClothingSimulationNv.h +++ b/Engine/Source/Runtime/ClothingSystemRuntime/Public/ClothingSimulationNv.h @@ -86,6 +86,9 @@ private: // List of collisions that were injected from an external source FClothCollisionData ExternalCollisions; + // Collisions extracted from our physics asset + FClothCollisionData ExtractedCollisions; + // Whether or not we need to rebuild our collisions on the next simulation setp bool bCollisionsDirty; @@ -158,7 +161,7 @@ private: // Update the LOD for the current actors, this is more complex than just updating a LOD value, // we need to skin the incoming simulation mesh to the outgoing mesh (the weighting data should have been // built in the asset already) to make sure it matches up without popping - void UpdateLod(FClothingSimulationContextNv* InContext); + void UpdateLod(int32 InPredictedLod, const FTransform& ComponentToWorld, const TArray& CSTransforms, bool bForceNoRemap = false); // The core simulation is only solving unoriented particles, so we need to compute normals after the // simulation runs @@ -168,6 +171,10 @@ private: // this is only used from CreateActor, but could be exposed for runtime changes void ApplyClothConfig(FClothConfig &Config, FClothingActorNv &InActor, USkeletalMeshComponent* InOwnerComponent); + // Extract collisions from the physics asset inside Asset and apply them to InActor + // Not safe to call from workers (i.e. inside the simulation). + void ExtractActorCollisions(USkeletalMeshComponent* InOwnerComponent, UClothingAsset* Asset, FClothingActorNv &InActor); + // The current LOD index for the owning skeletal mesh component int32 CurrentMeshLodIndex; diff --git a/Engine/Source/Runtime/ClothingSystemRuntimeInterface/Public/ClothingSimulationInterface.h b/Engine/Source/Runtime/ClothingSystemRuntimeInterface/Public/ClothingSimulationInterface.h index 297dc6b22cbe..e1f9f2ef306c 100644 --- a/Engine/Source/Runtime/ClothingSystemRuntimeInterface/Public/ClothingSimulationInterface.h +++ b/Engine/Source/Runtime/ClothingSystemRuntimeInterface/Public/ClothingSimulationInterface.h @@ -8,9 +8,10 @@ class UClothingAssetBase; class USkeletalMeshComponent; // Empty interface, derived simulation modules define the contents of the context -class IClothingSimulationContext +class CLOTHINGSYSTEMRUNTIMEINTERFACE_API IClothingSimulationContext { - +public: + virtual ~IClothingSimulationContext() {}; }; class CLOTHINGSYSTEMRUNTIMEINTERFACE_API IClothingSimulation diff --git a/Engine/Source/Runtime/CookedIterativeFile/CookedIterativeFile.Build.cs b/Engine/Source/Runtime/CookedIterativeFile/CookedIterativeFile.Build.cs new file mode 100644 index 000000000000..18ddec3f699d --- /dev/null +++ b/Engine/Source/Runtime/CookedIterativeFile/CookedIterativeFile.Build.cs @@ -0,0 +1,17 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +using UnrealBuildTool; + +public class CookedIterativeFile : ModuleRules +{ + public CookedIterativeFile(ReadOnlyTargetRules Target) : base(Target) + { + PublicDependencyModuleNames.AddRange( + new string[] { + "Core", + "NetworkFile", + "Sockets", + } + ); + } +} diff --git a/Engine/Source/Runtime/CookedIterativeFile/Private/CookedIterativeNetworkFile.cpp b/Engine/Source/Runtime/CookedIterativeFile/Private/CookedIterativeNetworkFile.cpp new file mode 100644 index 000000000000..5d4ee1a92ca5 --- /dev/null +++ b/Engine/Source/Runtime/CookedIterativeFile/Private/CookedIterativeNetworkFile.cpp @@ -0,0 +1,730 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "CookedIterativeNetworkFile.h" +#include "Templates/ScopedPointer.h" +#include "Misc/CommandLine.h" +#include "Misc/ScopeLock.h" +#include "Modules/ModuleManager.h" +#include "HAL/IPlatformFileModule.h" +#include "UniquePtr.h" +#include "Misc/EngineVersion.h" + +DEFINE_LOG_CATEGORY(LogCookedIterativeNetworkFile); + +bool FCookedIterativeNetworkFile::InitializeInternal(IPlatformFile* Inner, const TCHAR* HostIP) +{ + if ( Inner->GetLowerLevel() == nullptr ) + { + UE_LOG(LogCookedIterativeNetworkFile, Fatal, TEXT("Platform file is missing it's inner. Is pak file deployed?") ); + } + + + PakPlatformFile = Inner; + + return FNetworkPlatformFile::InitializeInternal(Inner->GetLowerLevel(), HostIP ); +} + + +void FCookedIterativeNetworkFile::ProcessServerCachedFilesResponse(FArrayReader& Response, const int32 ServerPackageVersion, const int32 ServerPackageLicenseeVersion) +{ + FNetworkPlatformFile::ProcessServerCachedFilesResponse(Response, ServerPackageVersion, ServerPackageLicenseeVersion); + + + // some of our stuff is on here too! + + // receive a list of the cache files and their timestamps + TMap ServerValidPakFileFiles; + Response << ServerValidPakFileFiles; + + + for ( const auto& ServerPakFileFile : ServerValidPakFileFiles ) + { + // the server should contain all these files + FString Path = FPaths::GetPath( ServerPakFileFile.Key); + FString Filename = FPaths::GetCleanFilename(ServerPakFileFile.Key); + + FServerTOC::FDirectory* ServerDirectory = ServerFiles.FindDirectory(Path); + if ( !ServerDirectory) + { + UE_LOG(LogCookedIterativeNetworkFile, Warning, TEXT("Unable to find directory %s while trying to resolve pak file %s"), *Path, *ServerPakFileFile.Key ); + } + else + { + FDateTime* ServerDate = ServerDirectory->Find(Filename); + if ( !ServerDate ) + { + UE_LOG(LogCookedIterativeNetworkFile, Warning, TEXT("Unable to find filename %s while trying to resolve pak file %s"), *Filename, *ServerPakFileFile.Key); + } + } + + // check the file is accessable + if (!PakPlatformFile->FileExists(*ServerPakFileFile.Key)) + { + UE_LOG(LogCookedIterativeNetworkFile, Warning, TEXT("Unable to find file %s in pak file. Server says it should be!"), *ServerPakFileFile.Key) + } + + ValidPakFileFiles.AddFileOrDirectory(ServerPakFileFile.Key, ServerPakFileFile.Value); + + UE_LOG(LogCookedIterativeNetworkFile, Display, TEXT("Using pak file %s"), *ServerPakFileFile.Key); + } +} + +FString FCookedIterativeNetworkFile::GetVersionInfo() const +{ + FString VersionInfo = FString::Printf(TEXT("%s %d"), *FEngineVersion::CompatibleWith().GetBranch(), FEngineVersion::CompatibleWith().GetChangelist() ); + + return VersionInfo; +} + +bool FCookedIterativeNetworkFile::ShouldPassToPak(const TCHAR* Filename) const +{ + if ( FCString::Stricmp( *FPaths::GetExtension(Filename), TEXT("ufont") ) == 0 ) + { + FString Path = FPaths::GetPath( Filename ); + + const FServerTOC::FDirectory* Directory = ValidPakFileFiles.FindDirectory(Path); + if ( Directory ) + { + FString StringFilename = Filename; + for ( const auto& File : *Directory ) + { + if ( File.Key.StartsWith( StringFilename ) ) + { + return true; + } + } + return false; + } + else + { + return false; + } + } + + if ( ValidPakFileFiles.FindFile(Filename) != nullptr ) + { + return true; + } + // if we are searching for the .uexp or .ubulk or any of those content extra files.... + // then change it to the original, if we are using the pak version of the original file then we want the bulk / uexp file to be the same + // potential async issue here if the file is invalidated after we start loading the original but before we load the uexp + // not much we can do about that though... + FString OriginalName = FPaths::ChangeExtension(Filename, TEXT("uasset")); + if ( ValidPakFileFiles.FindFile(OriginalName) ) + { + return true; + } + OriginalName = FPaths::ChangeExtension(Filename, TEXT("umap")); + if ( ValidPakFileFiles.FindFile(OriginalName)) + { + return true; + } + + return false; +} + + +bool FCookedIterativeNetworkFile::FileExists(const TCHAR* Filename) +{ + if ( ShouldPassToPak(Filename) ) + { + PakPlatformFile->FileExists(Filename); + return true; + } + return FNetworkPlatformFile::FileExists(Filename); +} + +int64 FCookedIterativeNetworkFile::FileSize(const TCHAR* Filename) +{ + if ( ShouldPassToPak(Filename) ) + { + return PakPlatformFile->FileSize(Filename); + } + else + { + return FNetworkPlatformFile::FileSize(Filename); + } +} +bool FCookedIterativeNetworkFile::DeleteFile(const TCHAR* Filename) +{ + // delete both of these entries + ValidPakFileFiles.RemoveFileOrDirectory(Filename); + return FNetworkPlatformFile::DeleteFile(Filename); +} + +bool FCookedIterativeNetworkFile::IsReadOnly(const TCHAR* Filename) +{ + if ( ShouldPassToPak(Filename) ) + { + return PakPlatformFile->IsReadOnly(Filename); + } + + return FNetworkPlatformFile::IsReadOnly(Filename); +} + +bool FCookedIterativeNetworkFile::SetReadOnly(const TCHAR* Filename, bool bNewReadOnlyValue) +{ + if (ShouldPassToPak(Filename)) + { + return PakPlatformFile->SetReadOnly(Filename, bNewReadOnlyValue); + } + return FNetworkPlatformFile::SetReadOnly(Filename, bNewReadOnlyValue); +} +FDateTime FCookedIterativeNetworkFile::GetTimeStamp(const TCHAR* Filename) +{ + if ( ShouldPassToPak(Filename) ) + { + return PakPlatformFile->GetTimeStamp(Filename); + } + return FNetworkPlatformFile::GetTimeStamp(Filename); +} + + +void FCookedIterativeNetworkFile::OnFileUpdated(const FString& LocalFilename) +{ + FNetworkPlatformFile::OnFileUpdated(LocalFilename); + ValidPakFileFiles.RemoveFileOrDirectory(LocalFilename); +} + + +IFileHandle* FCookedIterativeNetworkFile::OpenRead(const TCHAR* Filename, bool bAllowWrite) +{ + if ( ShouldPassToPak(Filename) ) + { + return PakPlatformFile->OpenRead(Filename, bAllowWrite); + } + return FNetworkPlatformFile::OpenRead(Filename, bAllowWrite); +} +IFileHandle* FCookedIterativeNetworkFile::OpenWrite(const TCHAR* Filename, bool bAppend, bool bAllowRead) +{ + if (ShouldPassToPak(Filename)) + { + return PakPlatformFile->OpenWrite(Filename, bAppend, bAllowRead); + } + // FNetworkPlatformFile::CreateDirectoryTree(Directory); + return FNetworkPlatformFile::OpenWrite(Filename, bAppend, bAllowRead); +} + +bool FCookedIterativeNetworkFile::CopyFile(const TCHAR* To, const TCHAR* From, EPlatformFileRead ReadFlags, EPlatformFileWrite WriteFlags) +{ + return PakPlatformFile->CopyFile(To, From, ReadFlags, WriteFlags); +} + +bool FCookedIterativeNetworkFile::MoveFile(const TCHAR* To, const TCHAR* From) +{ + if (ShouldPassToPak(From)) + { + return PakPlatformFile->MoveFile(To, From); + } + return FNetworkPlatformFile::MoveFile(To, From); +} + +bool FCookedIterativeNetworkFile::DirectoryExists(const TCHAR* Directory) +{ + if ( ValidPakFileFiles.FindDirectory(Directory) ) + { + return true; + } + return FNetworkPlatformFile::DirectoryExists(Directory); +} + +bool FCookedIterativeNetworkFile::CreateDirectoryTree(const TCHAR* Directory) +{ + return FNetworkPlatformFile::CreateDirectoryTree(Directory); +} + +bool FCookedIterativeNetworkFile::CreateDirectory(const TCHAR* Directory) +{ + return FNetworkPlatformFile::CreateDirectory(Directory); +} + +bool FCookedIterativeNetworkFile::DeleteDirectory(const TCHAR* Directory) +{ + bool bSucceeded = false; + if( ValidPakFileFiles.FindDirectory(Directory) ) + { + bSucceeded |= ValidPakFileFiles.RemoveFileOrDirectory(Directory) > 0 ? true : false; + } + bSucceeded |= FNetworkPlatformFile::DeleteDirectory(Directory); + return bSucceeded; +} + +bool FCookedIterativeNetworkFile::DeleteDirectoryRecursively(const TCHAR* Directory) +{ + bool bSucceeded = false; + if (ValidPakFileFiles.FindDirectory(Directory)) + { + bSucceeded |= ValidPakFileFiles.RemoveFileOrDirectory(Directory) > 0 ? true : false; + } + bSucceeded |= FNetworkPlatformFile::DeleteDirectoryRecursively(Directory); + return bSucceeded; +} + + +bool FCookedIterativeNetworkFile::IterateDirectory(const TCHAR* Directory, IPlatformFile::FDirectoryVisitor& Visitor) +{ + //return PakPlatformFile->IterateDirectory(Directory, Visitor); + return FNetworkPlatformFile::IterateDirectory(Directory, Visitor); +} + +bool FCookedIterativeNetworkFile::IterateDirectoryRecursively(const TCHAR* Directory, IPlatformFile::FDirectoryVisitor& Visitor) +{ + return FNetworkPlatformFile::IterateDirectoryRecursively(Directory, Visitor); +} + + +FFileStatData FCookedIterativeNetworkFile::GetStatData(const TCHAR* FilenameOrDirectory) +{ + if (ShouldPassToPak(FilenameOrDirectory)) + { + return PakPlatformFile->GetStatData(FilenameOrDirectory); + } + return FNetworkPlatformFile::GetStatData(FilenameOrDirectory); +} + + +bool FCookedIterativeNetworkFile::IterateDirectoryStat(const TCHAR* Directory, IPlatformFile::FDirectoryStatVisitor& Visitor) +{ + return FNetworkPlatformFile::IterateDirectoryStat(Directory, Visitor); +} + +bool FCookedIterativeNetworkFile::IterateDirectoryStatRecursively(const TCHAR* Directory, IPlatformFile::FDirectoryStatVisitor& Visitor) +{ + return FNetworkPlatformFile::IterateDirectoryStatRecursively(Directory, Visitor); +} + + + + + + + +/** + * A helper class for wrapping some of the network file payload specifics + */ +/* +class FStreamingNetworkFileArchive + : public FBufferArchive +{ +public: + + FStreamingNetworkFileArchive(uint32 Command) + { + // make sure the command is at the start + *this << Command; + } + + // helper to serialize TCHAR* (there are a lot) + FORCEINLINE friend FStreamingNetworkFileArchive& operator<<(FStreamingNetworkFileArchive& Ar, const TCHAR*& Str) + { + FString Temp(Str); + Ar << Temp; + return Ar; + } +}; +*/ + + +/* +class FStreamingNetworkFileHandle + : public IFileHandle +{ + FStreamingNetworkPlatformFile& Network; + FString Filename; + uint64 HandleId; + int64 FilePos; + int64 FileSize; + bool bWritable; + bool bReadable; + uint8 BufferCache[2][GBufferCacheSize]; + int64 CacheStart[2]; + int64 CacheEnd[2]; + bool LazySeek; + int32 CurrentCache; + +public: + + FStreamingNetworkFileHandle(FStreamingNetworkPlatformFile& InNetwork, const TCHAR* InFilename, uint64 InHandleId, int64 InFileSize, bool bWriting) + : Network(InNetwork) + , Filename(InFilename) + , HandleId(InHandleId) + , FilePos(0) + , FileSize(InFileSize) + , bWritable(bWriting) + , bReadable(!bWriting) + , LazySeek(false) + ,CurrentCache(0) + { + CacheStart[0] = CacheStart[1] = -1; + CacheEnd[0] = CacheEnd[1] = -1; + } + + ~FStreamingNetworkFileHandle() + { + Network.SendCloseMessage(HandleId); + } + + virtual int64 Size() override + { + return FileSize; + } + + virtual int64 Tell() override + { + return FilePos; + } + + virtual bool Seek(int64 NewPosition) override + { + if( bWritable ) + { + if( NewPosition == FilePos ) + { + return true; + } + + if (NewPosition >= 0 && NewPosition <= FileSize) + { + if (Network.SendSeekMessage(HandleId, NewPosition)) + { + FilePos = NewPosition; + + return true; + } + } + } + else if( bReadable ) + { + if (NewPosition >= 0 && NewPosition <= FileSize) + { + if (NewPosition < CacheStart[0] || NewPosition >= CacheEnd[0] || CacheStart[0] == -1) + { + if (NewPosition < CacheStart[1] || NewPosition >= CacheEnd[1] || CacheStart[1] == -1) + { + LazySeek = true; + FilePos = NewPosition; + if (CacheStart[CurrentCache] != -1) + { + CurrentCache++; + CurrentCache %= 2; + CacheStart[CurrentCache] = -1; // Invalidate the cache + } + + return true; + } + else + { + LazySeek = false; + FilePos = NewPosition; + CurrentCache = 1; + + return true; + } + } + else + { + LazySeek = false; + FilePos = NewPosition; + CurrentCache = 0; + + return true; + } + } + } + + return false; + } + + virtual bool SeekFromEnd(int64 NewPositionRelativeToEnd = 0) override + { + return Seek(FileSize + NewPositionRelativeToEnd); + } + + virtual bool Read(uint8* Destination, int64 BytesToRead) override + { + bool Result = false; + if (bReadable && BytesToRead >= 0 && BytesToRead + FilePos <= FileSize) + { + if (BytesToRead == 0) + { + Result = true; + } + else + { + if (BytesToRead > GBufferCacheSize) // reading more than we cache + { + // if the file position is within the cache, copy out the remainder of the cache + if (CacheStart[CurrentCache] != -1 && FilePos >= CacheStart[CurrentCache] && FilePos < CacheEnd[CurrentCache]) + { + int64 CopyBytes = CacheEnd[CurrentCache]-FilePos; + FMemory::Memcpy(Destination, BufferCache[CurrentCache]+(FilePos-CacheStart[CurrentCache]), CopyBytes); + FilePos += CopyBytes; + BytesToRead -= CopyBytes; + Destination += CopyBytes; + } + + if (Network.SendSeekMessage(HandleId, FilePos)) + { + Result = Network.SendReadMessage(HandleId, Destination, BytesToRead); + } + if (Result) + { + FilePos += BytesToRead; + CurrentCache++; + CurrentCache %= 2; + CacheStart[CurrentCache] = -1; // Invalidate the cache + } + } + else + { + Result = true; + + // need to update the cache + if (CacheStart[CurrentCache] == -1 && FileSize < GBufferCacheSize) + { + Result = Network.SendReadMessage(HandleId, BufferCache[CurrentCache], FileSize); + if (Result) + { + CacheStart[CurrentCache] = 0; + CacheEnd[CurrentCache] = FileSize; + } + } + else if (FilePos + BytesToRead > CacheEnd[CurrentCache] || CacheStart[CurrentCache] == -1 || FilePos < CacheStart[CurrentCache]) + { + // copy the data from FilePos to the end of the Cache to the destination as long as it is in the cache + if (CacheStart[CurrentCache] != -1 && FilePos >= CacheStart[CurrentCache] && FilePos < CacheEnd[CurrentCache]) + { + int64 CopyBytes = CacheEnd[CurrentCache]-FilePos; + FMemory::Memcpy(Destination, BufferCache[CurrentCache]+(FilePos-CacheStart[CurrentCache]), CopyBytes); + FilePos += CopyBytes; + BytesToRead -= CopyBytes; + Destination += CopyBytes; + } + + // switch to the other cache + if (CacheStart[CurrentCache] != -1) + { + CurrentCache++; + CurrentCache %= 2; + } + + int64 SizeToRead = GBufferCacheSize; + + if (FilePos + SizeToRead > FileSize) + { + SizeToRead = FileSize-FilePos; + } + + if (Network.SendSeekMessage(HandleId, FilePos)) + { + Result = Network.SendReadMessage(HandleId, BufferCache[CurrentCache], SizeToRead); + } + + if (Result) + { + CacheStart[CurrentCache] = FilePos; + CacheEnd[CurrentCache] = FilePos + SizeToRead; + } + } + + // copy from the cache to the destination + if (Result) + { + FMemory::Memcpy(Destination, BufferCache[CurrentCache]+(FilePos-CacheStart[CurrentCache]), BytesToRead); + FilePos += BytesToRead; + } + } + } + } + + return Result; + } + + virtual bool Write(const uint8* Source, int64 BytesToWrite) override + { + bool Result = false; + + if (bWritable && BytesToWrite >= 0) + { + if (BytesToWrite == 0) + { + Result = true; + } + else + { + Result = Network.SendWriteMessage(HandleId, Source, BytesToWrite); + + if (Result) + { + FilePos += BytesToWrite; + FileSize = FMath::Max(FilePos, FileSize); + } + } + } + + return Result; + } +}; +*/ + + +bool FCookedIterativeNetworkFile::ShouldBeUsed(IPlatformFile* Inner, const TCHAR* CmdLine) const +{ + bool bResult = FNetworkPlatformFile::ShouldBeUsed(Inner, CmdLine); + + if (bResult) + { + bResult = FParse::Param(CmdLine, TEXT("precookednetwork")); + } + + return bResult; +} + +/* +bool FCookedIterativeNetworkFile::InitializeInternal(IPlatformFile* Inner, const TCHAR* HostIP) +{ + // look for the commandline that will read files from over the network + if (HostIP == nullptr) + { + UE_LOG(LogStreamingPlatformFile, Error, TEXT("No Host IP specified in the commandline.")); + bIsUsable = false; + + return false; + } + + // optionally get the port from the command line + int32 OverridePort; + if (FParse::Value(FCommandLine::Get(), TEXT("fileserverport="), OverridePort)) + { + UE_LOG(LogStreamingPlatformFile, Display, TEXT("Overriding file server port: %d"), OverridePort); + FileServerPort = OverridePort; + } + + // Send the filenames and timestamps to the server. + FNetworkFileArchive Payload(NFS_Messages::GetFileList); + FillGetFileList(Payload, true); + + // Send the directories over, and wait for a response. + FArrayReader Response; + + if(SendPayloadAndReceiveResponse(Payload,Response)) + { + // Receive the cooked version information. + int32 ServerPackageVersion = 0; + int32 ServerPackageLicenseeVersion = 0; + ProcessServerInitialResponse(Response, ServerPackageVersion, ServerPackageLicenseeVersion); + + // Make sure we can sync a file. + FString TestSyncFile = FPaths::Combine(*(FPaths::EngineDir()), TEXT("Config/BaseEngine.ini")); + IFileHandle* TestFileHandle = OpenRead(*TestSyncFile); + if (TestFileHandle != nullptr) + { + uint8* FileContents = (uint8*)FMemory::Malloc(TestFileHandle->Size()); + if (!TestFileHandle->Read(FileContents, TestFileHandle->Size())) + { + UE_LOG(LogStreamingPlatformFile, Fatal, TEXT("Could not read test file %s."), *TestSyncFile); + } + FMemory::Free(FileContents); + delete TestFileHandle; + } + else + { + UE_LOG(LogStreamingPlatformFile, Fatal, TEXT("Could not open test file %s."), *TestSyncFile); + } + + FCommandLine::AddToSubprocessCommandline( *FString::Printf( TEXT("-StreamingHostIP=%s"), HostIP ) ); + + return true; + } + + return false; +}*/ + + +FCookedIterativeNetworkFile::~FCookedIterativeNetworkFile() +{ +} + +/* +bool FStreamingNetworkPlatformFile::IterateDirectory(const TCHAR* InDirectory, IPlatformFile::FDirectoryVisitor& Visitor) +{ + FString RelativeDirectory = InDirectory; + MakeStandardNetworkFilename(RelativeDirectory); + // for .dll, etc searches that don't specify a path, we need to strip off the path + // before we send it to the visitor + bool bHadNoPath = InDirectory[0] == 0; + + // we loop until this is false + bool RetVal = true; + + // Find the directory in TOC + FServerTOC::FDirectory* ServerDirectory = ServerFiles.FindDirectory(RelativeDirectory); + if (ServerDirectory != nullptr) + { + // loop over the server files and look if they are in this exact directory + for (FServerTOC::FDirectory::TIterator It(*ServerDirectory); It && RetVal == true; ++It) + { + if (FPaths::GetPath(It.Key()) == RelativeDirectory) + { + // timestamps of 0 mean directories + bool bIsDirectory = It.Value() == 0; + + // visit (stripping off the path if needed) + RetVal = Visitor.Visit(bHadNoPath ? *FPaths::GetCleanFilename(It.Key()) : *It.Key(), bIsDirectory); + } + } + } + + return RetVal; +} + + +bool FStreamingNetworkPlatformFile::IterateDirectoryRecursively(const TCHAR* InDirectory, IPlatformFile::FDirectoryVisitor& Visitor) +{ + FString RelativeDirectory = InDirectory; + MakeStandardNetworkFilename(RelativeDirectory); + // we loop until this is false + bool RetVal = true; + + // loop over the server TOC + for (TMap::TIterator DirIt(ServerFiles.Directories); DirIt && RetVal == true; ++DirIt) + { + if (DirIt.Key().StartsWith(RelativeDirectory)) + { + FServerTOC::FDirectory& ServerDirectory = *DirIt.Value(); + + // loop over the server files and look if they are in this exact directory + for (FServerTOC::FDirectory::TIterator It(ServerDirectory); It && RetVal == true; ++It) + { + // timestamps of 0 mean directories + bool bIsDirectory = It.Value() == 0; + + // visit! + RetVal = Visitor.Visit(*It.Key(), bIsDirectory); + } + } + } + + return RetVal; +} + +*/ + + +/** + * Module for the streaming file + */ +class FCookedIterativeFileModule + : public IPlatformFileModule +{ +public: + + virtual IPlatformFile* GetPlatformFile() override + { + static TUniquePtr AutoDestroySingleton = MakeUnique(); + return AutoDestroySingleton.Get(); + } +}; + + +IMPLEMENT_MODULE(FCookedIterativeFileModule, CookedIterativeFile); diff --git a/Engine/Source/Runtime/CookedIterativeFile/Public/CookedIterativeNetworkFile.h b/Engine/Source/Runtime/CookedIterativeFile/Public/CookedIterativeNetworkFile.h new file mode 100644 index 000000000000..581738ca2124 --- /dev/null +++ b/Engine/Source/Runtime/CookedIterativeFile/Public/CookedIterativeNetworkFile.h @@ -0,0 +1,196 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "GenericPlatform/GenericPlatformFile.h" +#include "Misc/Paths.h" +#include "NetworkMessage.h" +#include "NetworkPlatformFile.h" + +DECLARE_LOG_CATEGORY_EXTERN(LogCookedIterativeNetworkFile, Display, All); + + +#if 0 +/** + * Visitor to gather local files with their timestamps + */ +class STREAMINGFILE_API FStreamingLocalTimestampVisitor : public IPlatformFile::FDirectoryVisitor +{ +private: + + /** The file interface to use for any file operations */ + IPlatformFile& FileInterface; + + /** true if we want directories in this list */ + bool bCacheDirectories; + + /** A list of directories that we should not traverse into */ + TArray DirectoriesToIgnore; + + /** A list of directories that we should only go one level into */ + TArray DirectoriesToNotRecurse; + +public: + + /** Relative paths to local files and their timestamps */ + TMap FileTimes; + + FStreamingLocalTimestampVisitor(IPlatformFile& InFileInterface, const TArray& InDirectoriesToIgnore, const TArray& InDirectoriesToNotRecurse, bool bInCacheDirectories=false) + : FileInterface(InFileInterface) + , bCacheDirectories(bInCacheDirectories) + { + // make sure the paths are standardized, since the Visitor will assume they are standard + for (int32 DirIndex = 0; DirIndex < InDirectoriesToIgnore.Num(); DirIndex++) + { + FString DirToIgnore = InDirectoriesToIgnore[DirIndex]; + FPaths::MakeStandardFilename(DirToIgnore); + DirectoriesToIgnore.Add(DirToIgnore); + } + + for (int32 DirIndex = 0; DirIndex < InDirectoriesToNotRecurse.Num(); DirIndex++) + { + FString DirToNotRecurse = InDirectoriesToNotRecurse[DirIndex]; + FPaths::MakeStandardFilename(DirToNotRecurse); + DirectoriesToNotRecurse.Add(DirToNotRecurse); + } + } + + virtual bool Visit(const TCHAR* FilenameOrDirectory, bool bIsDirectory) + { + // make sure all paths are "standardized" so the other end can match up with it's own standardized paths + FString RelativeFilename = FilenameOrDirectory; + FPaths::MakeStandardFilename(RelativeFilename); + + // cache files and optionally directories + if (!bIsDirectory) + { + FileTimes.Add(RelativeFilename, FileInterface.GetTimeStamp(FilenameOrDirectory)); + } + else if (bCacheDirectories) + { + // we use a timestamp of 0 to indicate a directory + FileTimes.Add(RelativeFilename, 0); + } + + // iterate over directories we care about + if (bIsDirectory) + { + bool bShouldRecurse = true; + // look in all the ignore directories looking for a match + for (int32 DirIndex = 0; DirIndex < DirectoriesToIgnore.Num() && bShouldRecurse; DirIndex++) + { + if (RelativeFilename.StartsWith(DirectoriesToIgnore[DirIndex])) + { + bShouldRecurse = false; + } + } + + if (bShouldRecurse == true) + { + // If it is a directory that we should not recurse (ie we don't want to process subdirectories of it) + // handle that case as well... + for (int32 DirIndex = 0; DirIndex < DirectoriesToNotRecurse.Num() && bShouldRecurse; DirIndex++) + { + if (RelativeFilename.StartsWith(DirectoriesToNotRecurse[DirIndex])) + { + // Are we more than level deep in that directory? + FString CheckFilename = RelativeFilename.Right(RelativeFilename.Len() - DirectoriesToNotRecurse[DirIndex].Len()); + if (CheckFilename.Len() > 1) + { + bShouldRecurse = false; + } + } + } + } + + // recurse if we should + if (bShouldRecurse) + { + FileInterface.IterateDirectory(FilenameOrDirectory, *this); + } + } + + return true; + } +}; +#endif + + +/** + * Wrapper to redirect the low level file system to a server + */ +class COOKEDITERATIVEFILE_API FCookedIterativeNetworkFile + : public FNetworkPlatformFile +{ + friend class FAsyncFileSync; + +public: + + /** Default Constructor */ + FCookedIterativeNetworkFile() + { + ConnectionFlags = EConnectionFlags::PreCookedIterative; + HeartbeatFrequency = 1; // increase the heartbeat frequency + } + + /** Virtual destructor */ + virtual ~FCookedIterativeNetworkFile(); + +public: + + static const TCHAR* GetTypeName() + { + return TEXT("CookedIterativeNetworkFile"); + } + +protected: + + virtual bool InitializeInternal(IPlatformFile* Inner, const TCHAR* HostIP) override; + + // need to override what FNetworkPlatformFile does here + virtual void ProcessServerCachedFilesResponse(FArrayReader& InReponse, const int32 ServerPackageVersion, const int32 ServerPackageLicenseeVersion) override; + + // IPlatformFile interface + + virtual bool ShouldBeUsed(IPlatformFile* Inner, const TCHAR* CmdLine) const override; + + virtual bool FileExists(const TCHAR* Filename) override; + virtual int64 FileSize(const TCHAR* Filename) override; + virtual bool DeleteFile(const TCHAR* Filename) override; + virtual bool IsReadOnly(const TCHAR* Filename) override; + virtual bool MoveFile(const TCHAR* To, const TCHAR* From) override; + virtual bool SetReadOnly(const TCHAR* Filename, bool bNewReadOnlyValue) override; + virtual FDateTime GetTimeStamp(const TCHAR* Filename) override; + + virtual IFileHandle* OpenRead(const TCHAR* Filename, bool bAllowWrite = false) override; + virtual IFileHandle* OpenWrite(const TCHAR* Filename, bool bAppend = false, bool bAllowRead = false) override; + virtual bool DirectoryExists(const TCHAR* Directory) override; + virtual bool CreateDirectoryTree(const TCHAR* Directory) override; + virtual bool CreateDirectory(const TCHAR* Directory) override; + virtual bool DeleteDirectory(const TCHAR* Directory) override; + + virtual FFileStatData GetStatData(const TCHAR* FilenameOrDirectory) override; + + virtual bool IterateDirectory(const TCHAR* Directory, IPlatformFile::FDirectoryVisitor& Visitor) override; + virtual bool IterateDirectoryRecursively(const TCHAR* Directory, IPlatformFile::FDirectoryVisitor& Visitor) override; + + virtual bool IterateDirectoryStat(const TCHAR* Directory, IPlatformFile::FDirectoryStatVisitor& Visitor) override; + virtual bool IterateDirectoryStatRecursively(const TCHAR* Directory, IPlatformFile::FDirectoryStatVisitor& Visitor) override; + + virtual bool DeleteDirectoryRecursively(const TCHAR* Directory) override; + virtual bool CopyFile(const TCHAR* To, const TCHAR* From, EPlatformFileRead ReadFlags = EPlatformFileRead::None, EPlatformFileWrite WriteFlags = EPlatformFileWrite::None) override; + + + virtual void OnFileUpdated(const FString& LocalFilename) override; + + virtual FString GetVersionInfo() const override; +private: + bool ShouldPassToPak(const TCHAR* Filename) const; + +private: + FServerTOC ValidPakFileFiles; + + IPlatformFile* PakPlatformFile; + +}; diff --git a/Engine/Source/Runtime/Core/Core.Build.cs b/Engine/Source/Runtime/Core/Core.Build.cs index 9b78bfa2b824..7945cb2bcf5e 100644 --- a/Engine/Source/Runtime/Core/Core.Build.cs +++ b/Engine/Source/Runtime/Core/Core.Build.cs @@ -12,6 +12,8 @@ public class Core : ModuleRules SharedPCHHeaderFile = "Public/CoreSharedPCH.h"; + bAddDefaultIncludePaths = false; + PublicIncludePaths.AddRange( new string[] { "Runtime/Core/Public", @@ -105,7 +107,10 @@ public class Core : ModuleRules PublicFrameworks.AddRange(new string[] { "UIKit", "Foundation", "AudioToolbox", "AVFoundation", "GameKit", "StoreKit", "CoreVideo", "CoreMedia", "CoreGraphics", "GameController", "SystemConfiguration" }); if (Target.Platform == UnrealTargetPlatform.IOS) { - PublicFrameworks.AddRange(new string[] { "CoreMotion" }); + PublicFrameworks.AddRange(new string[] { "CoreMotion", "AdSupport" }); + AddEngineThirdPartyPrivateStaticDependencies(Target, + "PLCrashReporter" + ); } bool bSupportAdvertising = Target.Platform == UnrealTargetPlatform.IOS; diff --git a/Engine/Source/Runtime/Core/Private/Android/AndroidFile.cpp b/Engine/Source/Runtime/Core/Private/Android/AndroidFile.cpp index e436bf753373..a61eaed1b45f 100644 --- a/Engine/Source/Runtime/Core/Private/Android/AndroidFile.cpp +++ b/Engine/Source/Runtime/Core/Private/Android/AndroidFile.cpp @@ -60,8 +60,8 @@ namespace // AndroidProcess uses this for executable name FString GAndroidProjectName; FString GPackageName; -static int32 GPackageVersion = 0; -static int32 GPackagePatchVersion = 0; +int32 GAndroidPackageVersion = 0; +int32 GAndroidPackagePatchVersion = 0; // External File Path base - setup during load FString GFilePathBase; @@ -88,8 +88,8 @@ JNI_METHOD void Java_com_epicgames_ue4_GameActivity_nativeSetObbInfo(JNIEnv* jen GAndroidProjectName = UTF8_TO_TCHAR(JavaProjectChars); const char* JavaPackageChars = jenv->GetStringUTFChars(PackageName, 0); GPackageName = UTF8_TO_TCHAR(JavaPackageChars); - GPackageVersion = Version; - GPackagePatchVersion = PatchVersion; + GAndroidPackageVersion = Version; + GAndroidPackagePatchVersion = PatchVersion; //Release the strings jenv->ReleaseStringUTFChars(ProjectName, JavaProjectChars); @@ -336,6 +336,18 @@ public: return bSuccess; } + virtual void Flush() override + { + CheckValid(); + if (nullptr != File->Asset) + { + // Can't write to assets. + return; + } + + fsync(File->Handle); + } + virtual int64 Size() override { return Length; @@ -934,8 +946,8 @@ public: // See FString OBBDir1 = GOBBFilePathBase + FString(TEXT("/Android/obb/") + GPackageName); FString OBBDir2 = GOBBFilePathBase + FString(TEXT("/obb/") + GPackageName); - FString MainOBBName = FString::Printf(TEXT("main.%d.%s.obb"), GPackageVersion, *GPackageName); - FString PatchOBBName = FString::Printf(TEXT("patch.%d.%s.obb"), GPackageVersion, *GPackageName); + FString MainOBBName = FString::Printf(TEXT("main.%d.%s.obb"), GAndroidPackageVersion, *GPackageName); + FString PatchOBBName = FString::Printf(TEXT("patch.%d.%s.obb"), GAndroidPackageVersion, *GPackageName); if (FileExists(*(OBBDir1 / MainOBBName), true)) { MountOBB(*(OBBDir1 / MainOBBName)); diff --git a/Engine/Source/Runtime/Core/Private/Android/AndroidInputInterface.cpp b/Engine/Source/Runtime/Core/Private/Android/AndroidInputInterface.cpp index 2a1577530506..80faa99422e0 100644 --- a/Engine/Source/Runtime/Core/Private/Android/AndroidInputInterface.cpp +++ b/Engine/Source/Runtime/Core/Private/Android/AndroidInputInterface.cpp @@ -8,6 +8,7 @@ #include #include "Misc/CallbackDevice.h" #include "HAL/PlatformTime.h" +#include "IConsoleManager.h" TArray FAndroidInputInterface::TouchInputStack = TArray(); @@ -32,6 +33,12 @@ int32 FAndroidInputInterface::DeferredMessageQueueDroppedCount = 0; TArray FAndroidInputInterface::MotionDataStack = TArray(); +int32 GAndroidOldXBoxWirelessFirmware = 0; +static FAutoConsoleVariableRef CVarAndroidOldXBoxWirelessFirmware( + TEXT("Android.OldXBoxWirelessFirmware"), + GAndroidOldXBoxWirelessFirmware, + TEXT("Determines how XBox Wireless controller mapping is handled. 0 assumes new firmware, 1 will use old firmware mapping (Default: 0)"), + ECVF_Default); TSharedRef< FAndroidInputInterface > FAndroidInputInterface::Create( const TSharedRef< FGenericApplicationMessageHandler >& InMessageHandler ) { @@ -783,12 +790,17 @@ void FAndroidInputInterface::SendControllerEvents() } else if (CurrentDevice.DeviceInfo.Name.StartsWith(TEXT("Xbox Wireless Controller"))) { - CurrentDevice.ButtonRemapping = ButtonRemapType::XBoxWireless; CurrentDevice.bSupportsHat = true; - CurrentDevice.bMapL1R1ToTriggers = false; - CurrentDevice.bMapZRZToTriggers = true; - CurrentDevice.bRightStickZRZ = false; - CurrentDevice.bRightStickRXRY = true; + + if (GAndroidOldXBoxWirelessFirmware == 1) + { + // Apply mappings for older firmware before 3.1.1221.0 + CurrentDevice.ButtonRemapping = ButtonRemapType::XBoxWireless; + CurrentDevice.bMapL1R1ToTriggers = false; + CurrentDevice.bMapZRZToTriggers = true; + CurrentDevice.bRightStickZRZ = false; + CurrentDevice.bRightStickRXRY = true; + } } else if (CurrentDevice.DeviceInfo.Name.StartsWith(TEXT("SteelSeries Stratus XL"))) { @@ -848,17 +860,17 @@ void FAndroidInputInterface::SendControllerEvents() ControllerId = (ControllerId == -1) ? 0 : ControllerId; // send input to handler - if (Touch.Type == TouchBegan) - { - MessageHandler->OnTouchStarted(NULL, Touch.Position, Touch.Handle, ControllerId); - } - else if (Touch.Type == TouchEnded) + switch ( Touch.Type ) { + case TouchBegan: + MessageHandler->OnTouchStarted(nullptr, Touch.Position, Touch.Handle, ControllerId); + break; + case TouchEnded: MessageHandler->OnTouchEnded(Touch.Position, Touch.Handle, ControllerId); - } - else - { + break; + case TouchMoved: MessageHandler->OnTouchMoved(Touch.Position, Touch.Handle, ControllerId); + break; } } diff --git a/Engine/Source/Runtime/Core/Private/Android/AndroidMisc.cpp b/Engine/Source/Runtime/Core/Private/Android/AndroidMisc.cpp index e3be25c212e6..1abcfc2add8f 100644 --- a/Engine/Source/Runtime/Core/Private/Android/AndroidMisc.cpp +++ b/Engine/Source/Runtime/Core/Private/Android/AndroidMisc.cpp @@ -22,6 +22,9 @@ #include "AndroidJavaMessageBox.h" #include "GenericPlatformChunkInstall.h" +#include "Misc/Parse.h" +#include "Internationalization/Regex.h" + #include #include "Function.h" @@ -117,6 +120,7 @@ void FAndroidMisc::LoadPreInitModules() { FModuleManager::Get().LoadModule(TEXT("OpenGLDrv")); FModuleManager::Get().LoadModule(TEXT("AndroidAudio")); + FModuleManager::Get().LoadModule(TEXT("AudioMixerAndroid")); } // Test for device vulkan support. @@ -160,7 +164,7 @@ extern "C" JNIEXPORT void Java_com_epicgames_ue4_BatteryReceiver_dispatchEvent(JNIEnv * jni, jclass clazz, jint status, jint level, jint temperature) { - FPlatformMisc::LowLevelOutputDebugStringf(TEXT("nativeBatteryEvent(stat = %i, lvl = %i, t = %3.2f)"), status, level, float(temperature)/10.f); + FPlatformMisc::LowLevelOutputDebugStringf(TEXT("nativeBatteryEvent(stat = %i, lvl = %i %, temp = %3.2f \u00B0C)"), status, level, float(temperature)/10.f); ReceiversLock.Lock(); FAndroidMisc::FBatteryState state; @@ -228,7 +232,11 @@ void FAndroidMisc::PlatformInit() extern void AndroidThunkCpp_DismissSplashScreen(); -void FAndroidMisc::PlatformPostInit(bool ShowSplashScreen) +void FAndroidMisc::PlatformPostInit() +{ +} + +void FAndroidMisc::PlatformHandleSplashScreen(bool ShowSplashScreen) { if (!ShowSplashScreen) { @@ -300,6 +308,8 @@ EAppReturnType::Type FAndroidMisc::MessageBoxExt( EAppMsgType::Type MsgType, con static EAppReturnType::Type ResultsYesNoYesAllNoAllCancel[] = { EAppReturnType::Yes, EAppReturnType::No, EAppReturnType::YesAll, EAppReturnType::NoAll, EAppReturnType::Cancel }; + static EAppReturnType::Type ResultsYesNoYesAll[] = { + EAppReturnType::Yes, EAppReturnType::No, EAppReturnType::YesAll }; // TODO: Should we localize button text? @@ -346,6 +356,12 @@ EAppReturnType::Type FAndroidMisc::MessageBoxExt( EAppMsgType::Type MsgType, con MessageBox.AddButton(TEXT("Cancel")); ResultValues = ResultsYesNoYesAllNoAllCancel; break; + case EAppMsgType::YesNoYesAll: + MessageBox.AddButton(TEXT("Yes")); + MessageBox.AddButton(TEXT("No")); + MessageBox.AddButton(TEXT("Yes To All")); + ResultValues = ResultsYesNoYesAll; + break; default: check(0); } @@ -388,6 +404,112 @@ bool FAndroidMisc::HasPlatformFeature(const TCHAR* FeatureName) return FGenericPlatformMisc::HasPlatformFeature(FeatureName); } +struct FScreenDensity +{ + FString Model; + bool IsRegex; + int32 Density; + + FScreenDensity() + : Model() + , IsRegex(false) + , Density(0) + { + } + + bool InitFromString(const FString& InSourceString) + { + Model = TEXT(""); + Density = 0; + IsRegex = false; + + // The initialization is only successful if the Model and Density values can all be parsed from the string + const bool bSuccessful = FParse::Value(*InSourceString, TEXT("Model="), Model) && FParse::Value(*InSourceString, TEXT("Density="), Density); + + // Regex= is optional, it lets us know if this model requires regular expression matching, which is much more expensive. + FParse::Bool(*InSourceString, TEXT("IsRegex="), IsRegex); + + return bSuccessful; + } + + bool IsMatch(const FString& InDeviceModel) const + { + if ( IsRegex ) + { + const FRegexPattern RegexPattern(Model); + FRegexMatcher RegexMatcher(RegexPattern, InDeviceModel); + + return RegexMatcher.FindNext(); + } + else + { + return Model == InDeviceModel; + } + } +}; + +float FAndroidMisc::GetWindowUpscaleFactor() +{ + // Determine the difference between the native resolution of the device, and the size of our window, + // and return that scalar. + + int32_t SurfaceWidth, SurfaceHeight; + FAndroidWindow::CalculateSurfaceSize(FPlatformMisc::GetHardwareWindow(), SurfaceWidth, SurfaceHeight); + + FPlatformRect ScreenRect = FAndroidWindow::GetScreenRect(); + + const float CalculatedScaleFactor = FVector2D(ScreenRect.Right - ScreenRect.Left, ScreenRect.Bottom - ScreenRect.Top).Size() / FVector2D(SurfaceWidth, SurfaceHeight).Size(); + + return CalculatedScaleFactor; +} + +extern FString AndroidThunkCpp_GetMetaDataString(const FString& Key); + +EScreenPhysicalAccuracy FAndroidMisc::ComputePhysicalScreenDensity(int32& OutScreenDensity) +{ + FString MyDeviceModel = GetDeviceModel(); + + TArray DeviceStrings; + GConfig->GetArray(TEXT("DeviceScreenDensity"), TEXT("Devices"), DeviceStrings, GEngineIni); + + TArray Devices; + for ( const FString& DeviceString : DeviceStrings ) + { + FScreenDensity DensityEntry; + if ( DensityEntry.InitFromString(DeviceString) ) + { + Devices.Add(DensityEntry); + } + } + + for ( const FScreenDensity& Device : Devices ) + { + if ( Device.IsMatch(MyDeviceModel) ) + { + OutScreenDensity = Device.Density * GetWindowUpscaleFactor(); + return EScreenPhysicalAccuracy::Truth; + } + } + + FString DPIStrings = AndroidThunkCpp_GetMetaDataString(TEXT("ue4.displaymetrics.dpi")); + TArray DPIValues; + DPIStrings.ParseIntoArray(DPIValues, TEXT(",")); + + float xdpi, ydpi; + LexicalConversion::FromString(xdpi, *DPIValues[0]); + LexicalConversion::FromString(ydpi, *DPIValues[1]); + + OutScreenDensity = ( xdpi + ydpi ) / 2.0f; + + if ( OutScreenDensity <= 0 || OutScreenDensity > 2000 ) + { + return EScreenPhysicalAccuracy::Unknown; + } + + OutScreenDensity *= GetWindowUpscaleFactor(); + return EScreenPhysicalAccuracy::Approximation; +} + bool FAndroidMisc::AllowRenderThread() { // Check for DisableThreadedRendering CVar from DeviceProfiles config @@ -704,6 +826,19 @@ bool FAndroidMisc::GetUseVirtualJoysticks() return true; } +extern void AndroidThunkCpp_RegisterForRemoteNotifications(); +extern void AndroidThunkCpp_UnregisterForRemoteNotifications(); + +void FAndroidMisc::RegisterForRemoteNotifications() +{ + AndroidThunkCpp_RegisterForRemoteNotifications(); +} + +void FAndroidMisc::UnregisterForRemoteNotifications() +{ + AndroidThunkCpp_UnregisterForRemoteNotifications(); +} + TArray FAndroidMisc::GetSystemFontBytes() { TArray FontBytes; @@ -715,15 +850,28 @@ TArray FAndroidMisc::GetSystemFontBytes() class IPlatformChunkInstall* FAndroidMisc::GetPlatformChunkInstall() { static IPlatformChunkInstall* ChunkInstall = nullptr; - IPlatformChunkInstallModule* PlatformChunkInstallModule = FModuleManager::LoadModulePtr("HTTPChunkInstaller"); - if (!ChunkInstall) + static bool bIniChecked = false; + if (!ChunkInstall || !bIniChecked) { - if (PlatformChunkInstallModule != NULL) + FString ProviderName; + IPlatformChunkInstallModule* PlatformChunkInstallModule = nullptr; + if (!GEngineIni.IsEmpty()) { - // Attempt to grab the platform installer - ChunkInstall = PlatformChunkInstallModule->GetPlatformChunkInstall(); + FString InstallModule; + GConfig->GetString(TEXT("StreamingInstall"), TEXT("DefaultProviderName"), InstallModule, GEngineIni); + FModuleStatus Status; + if (FModuleManager::Get().QueryModule(*InstallModule, Status)) + { + PlatformChunkInstallModule = FModuleManager::LoadModulePtr(*InstallModule); + if (PlatformChunkInstallModule != nullptr) + { + // Attempt to grab the platform installer + ChunkInstall = PlatformChunkInstallModule->GetPlatformChunkInstall(); + } + } + bIniChecked = true; } - else + if (!ChunkInstall) { // Placeholder instance ChunkInstall = FGenericPlatformMisc::GetPlatformChunkInstall(); @@ -1572,6 +1720,56 @@ const TCHAR* FAndroidMisc::GamePersistentDownloadDir() return *GExternalFilePath; } +FString FAndroidMisc::GetLoginId() +{ + static FString LoginId = TEXT(""); + + // Return already loaded or generated Id + if (!LoginId.IsEmpty()) + { + return LoginId; + } + + // Check for existing identifier file + extern FString GExternalFilePath; + FString LoginIdFilename = GExternalFilePath / TEXT("login-identifier.txt"); + if (FPaths::FileExists(LoginIdFilename)) + { + if (FFileHelper::LoadFileToString(LoginId, *LoginIdFilename)) + { + return LoginId; + } + } + + // Generate a new one and write to file + FGuid DeviceGuid; + FPlatformMisc::CreateGuid(DeviceGuid); + LoginId = DeviceGuid.ToString(); + FFileHelper::SaveStringToFile(LoginId, *LoginIdFilename); + + return LoginId; +} + +extern FString AndroidThunkCpp_GetAndroidId(); + +FString FAndroidMisc::GetDeviceId() +{ + static FString DeviceId = AndroidThunkCpp_GetAndroidId(); + + // note: this can be empty or NOT unique depending on the OEM implementation! + return DeviceId; +} + +extern FString AndroidThunkCpp_GetAdvertisingId(); + +FString FAndroidMisc::GetUniqueAdvertisingId() +{ + static FString AdvertisingId = AndroidThunkCpp_GetAdvertisingId(); + + // note: this can be empty if Google Play not installed, or user is blocking it! + return AdvertisingId; +} + FAndroidMisc::FBatteryState FAndroidMisc::GetBatteryState() { FBatteryState CurState; @@ -1581,6 +1779,18 @@ FAndroidMisc::FBatteryState FAndroidMisc::GetBatteryState() return CurState; } +int FAndroidMisc::GetBatteryLevel() +{ + FBatteryState BatteryState = GetBatteryState(); + return BatteryState.Level; +} + +bool FAndroidMisc::IsRunningOnBattery() +{ + FBatteryState BatteryState = GetBatteryState(); + return BatteryState.State == BATTERY_STATE_DISCHARGING; +} + bool FAndroidMisc::AreHeadPhonesPluggedIn() { return HeadPhonesArePluggedIn; @@ -1602,4 +1812,25 @@ FAndroidMisc::ReInitWindowCallbackType FAndroidMisc::GetOnReInitWindowCallback() void FAndroidMisc::SetOnReInitWindowCallback(FAndroidMisc::ReInitWindowCallbackType InOnReInitWindowCallback) { OnReInitWindowCallback = InOnReInitWindowCallback; -} \ No newline at end of file +} + +FString FAndroidMisc::GetCPUVendor() +{ + return DeviceMake; +} + +FString FAndroidMisc::GetCPUBrand() +{ + return DeviceModel; +} + +void FAndroidMisc::GetOSVersions(FString& out_OSVersionLabel, FString& out_OSSubVersionLabel) +{ + out_OSVersionLabel = TEXT("Android"); + out_OSSubVersionLabel = AndroidVersion; +} + +FString FAndroidMisc::GetOSVersion() +{ + return GetAndroidVersion(); +} diff --git a/Engine/Source/Runtime/Core/Private/Android/AndroidProcess.cpp b/Engine/Source/Runtime/Core/Private/Android/AndroidProcess.cpp index fe0f11c0ccc1..2019e9742b22 100644 --- a/Engine/Source/Runtime/Core/Private/Android/AndroidProcess.cpp +++ b/Engine/Source/Runtime/Core/Private/Android/AndroidProcess.cpp @@ -107,8 +107,7 @@ FString FAndroidPlatformProcess::GetGameBundleId() TAutoConsoleVariable CVarAndroidDefaultThreadAffinity( TEXT("android.DefaultThreadAffinity"), TEXT(""), - TEXT("Sets the thread affinity for Android platform. Pairs of args [GT|RT] [Hex affinity], ex: android.DefaultThreadAffinity GT 0x01 RT 0x02"), - ECVF_ReadOnly); + TEXT("Sets the thread affinity for Android platform. Pairs of args [GT|RT] [Hex affinity], ex: android.DefaultThreadAffinity GT 0x01 RT 0x02")); static void AndroidSetAffinityOnThread() { @@ -122,10 +121,10 @@ static void AndroidSetAffinityOnThread() } } -void AndroidSetupDefaultThreadAffinity() +static void ApplyDefaultThreadAffinity(IConsoleVariable* Var) { FString AffinityCmd = CVarAndroidDefaultThreadAffinity.GetValueOnAnyThread(); - + TArray Args; if (AffinityCmd.ParseIntoArrayWS(Args) > 0) { @@ -137,7 +136,7 @@ void AndroidSetupDefaultThreadAffinity() UE_LOG(LogAndroid, Display, TEXT("Parsed 0 for affinity, using 0xFFFFFFFFFFFFFFFF instead")); Aff = 0xFFFFFFFFFFFFFFFF; } - + if (Args[Index] == TEXT("GT")) { FAndroidAffinity::GameThreadMask = Aff; @@ -153,7 +152,7 @@ void AndroidSetupDefaultThreadAffinity() FSimpleDelegateGraphTask::CreateAndDispatchWhenReady( FSimpleDelegateGraphTask::FDelegate::CreateStatic(&AndroidSetAffinityOnThread), TStatId(), NULL, ENamedThreads::RenderThread); - + FSimpleDelegateGraphTask::CreateAndDispatchWhenReady( FSimpleDelegateGraphTask::FDelegate::CreateStatic(&AndroidSetAffinityOnThread), TStatId(), NULL, ENamedThreads::GameThread); @@ -164,3 +163,11 @@ void AndroidSetupDefaultThreadAffinity() } } } + +void AndroidSetupDefaultThreadAffinity() +{ + ApplyDefaultThreadAffinity(nullptr); + + // Watch for CVar update + CVarAndroidDefaultThreadAffinity->SetOnChangedCallback(FConsoleVariableDelegate::CreateStatic(&ApplyDefaultThreadAffinity)); +} diff --git a/Engine/Source/Runtime/Core/Private/Android/AndroidWindow.cpp b/Engine/Source/Runtime/Core/Private/Android/AndroidWindow.cpp index 02ca4193f9ec..e909d905d5be 100644 --- a/Engine/Source/Runtime/Core/Private/Android/AndroidWindow.cpp +++ b/Engine/Source/Runtime/Core/Private/Android/AndroidWindow.cpp @@ -15,6 +15,8 @@ static int32 GSurfaceViewHeight = -1; static bool WindowInit = false; static float ContentScaleFactor = -1.0f; static ANativeWindow* LastWindow = NULL; +static bool bLastMosaicState = false; + FAndroidWindow::~FAndroidWindow() { @@ -125,23 +127,47 @@ FPlatformRect FAndroidWindow::GetScreenRect() } check(Window != NULL); + // determine mosaic requirements: + static auto* MobileHDRCvar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.MobileHDR")); + const bool bMobileHDR = (MobileHDRCvar && MobileHDRCvar->GetValueOnAnyThread() == 1); + + static auto* MobileHDR32bppModeCvar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.MobileHDR32bppMode")); + const int32 MobileHDR32Mode = MobileHDR32bppModeCvar->GetValueOnAnyThread(); + + const bool bDeviceRequiresHDR32bpp = !FAndroidMisc::SupportsFloatingPointRenderTargets(); + const bool bDeviceRequiresMosaic = bDeviceRequiresHDR32bpp && !FAndroidMisc::SupportsShaderFramebufferFetch(); + + const bool bHDR32ModeOverridden = MobileHDR32Mode != 0; + const bool bMosaicEnabled = bDeviceRequiresMosaic && (!bHDR32ModeOverridden || MobileHDR32Mode == 1); + + bool bUseResCache = WindowInit; + + if (bLastMosaicState != bMosaicEnabled) + { + FPlatformMisc::LowLevelOutputDebugStringf(TEXT("***** Mosaic State change (to %s), not using res cache"), bMosaicEnabled ? TEXT("enabled") : TEXT("disabled")); + bUseResCache = false; + } + if (RequestedContentScaleFactor != ContentScaleFactor) { FPlatformMisc::LowLevelOutputDebugStringf(TEXT("***** RequestedContentScaleFactor different %f != %f, not using res cache"), RequestedContentScaleFactor, ContentScaleFactor); + bUseResCache = false; } if (Window != LastWindow) { FPlatformMisc::LowLevelOutputDebugString(TEXT("***** Window different, not using res cache")); + bUseResCache = false; } if (WindowWidth <= 8) { FPlatformMisc::LowLevelOutputDebugStringf(TEXT("***** WindowWidth is %d, not using res cache"), WindowWidth); + bUseResCache = false; } // since orientation won't change on Android, use cached results if still valid - if (WindowInit && RequestedContentScaleFactor == ContentScaleFactor && Window == LastWindow && WindowWidth > 8) + if (bUseResCache) { FPlatformRect ScreenRect; ScreenRect.Left = 0; @@ -162,21 +188,22 @@ FPlatformRect FAndroidWindow::GetScreenRect() int32 MaxWidth = ScreenWidth; int32 MaxHeight = ScreenHeight; - static auto* MobileHDRCvar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.MobileHDR")); - static auto* MobileHDR32bppModeCvar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.MobileHDR32bppMode")); - - const bool bMobileHDR = (MobileHDRCvar && MobileHDRCvar->GetValueOnAnyThread() == 1); - + UE_LOG(LogAndroid, Log, TEXT("Mobile HDR: %s"), bMobileHDR ? TEXT("YES") : TEXT("no")); if (bMobileHDR && !bIsGearVRApp) { - const bool bMobileHDR32bpp = (!FAndroidMisc::SupportsFloatingPointRenderTargets() || (MobileHDR32bppModeCvar && MobileHDR32bppModeCvar->GetValueOnAnyThread() != 0)); - const bool bRequiresMosaic = bMobileHDR32bpp && (!FAndroidMisc::SupportsShaderFramebufferFetch() || (MobileHDR32bppModeCvar && MobileHDR32bppModeCvar->GetValueOnAnyThread() == 1)); + UE_LOG(LogAndroid, Log, TEXT("Device requires 32BPP mode : %s"), bDeviceRequiresHDR32bpp ? TEXT("YES") : TEXT("no")); + UE_LOG(LogAndroid, Log, TEXT("Device requires mosaic: %s"), bDeviceRequiresMosaic ? TEXT("YES") : TEXT("no")); - UE_LOG(LogAndroid, Log, TEXT("Requires 32BPP Encoding: %s"), bMobileHDR32bpp ? TEXT("YES") : TEXT("no")); - UE_LOG(LogAndroid, Log, TEXT("Requires Mosaic: %s"), bRequiresMosaic ? TEXT("YES") : TEXT("no")); + if(bHDR32ModeOverridden) + { + UE_LOG(LogAndroid, Log, TEXT("--- Enabling 32 BPP override with 'r.MobileHDR32bppMode' = %d"), MobileHDR32Mode); + UE_LOG(LogAndroid, Log, TEXT(" 32BPP mode : YES")); + UE_LOG(LogAndroid, Log, TEXT(" 32BPP mode requires mosaic: %s"), bMosaicEnabled ? TEXT("YES") : TEXT("no")); + UE_LOG(LogAndroid, Log, TEXT(" 32BPP mode requires RGBE: %s"), MobileHDR32Mode == 2 ? TEXT("YES") : TEXT("no")); + } - if (bRequiresMosaic) + if(bMosaicEnabled) { UE_LOG(LogAndroid, Log, TEXT("Using mosaic rendering due to lack of Framebuffer Fetch support.")); if (!FAndroidMisc::SupportsES30()) @@ -241,6 +268,7 @@ FPlatformRect FAndroidWindow::GetScreenRect() WindowInit = true; ContentScaleFactor = RequestedContentScaleFactor; LastWindow = Window; + bLastMosaicState = bMosaicEnabled; return ScreenRect; } diff --git a/Engine/Source/Runtime/Core/Private/Apple/ApplePlatformDebugEvents.cpp b/Engine/Source/Runtime/Core/Private/Apple/ApplePlatformDebugEvents.cpp index 828e8ed8c7ae..49707e82ca0c 100644 --- a/Engine/Source/Runtime/Core/Private/Apple/ApplePlatformDebugEvents.cpp +++ b/Engine/Source/Runtime/Core/Private/Apple/ApplePlatformDebugEvents.cpp @@ -9,6 +9,7 @@ #include "UnrealString.h" #include "IConsoleManager.h" #include "Color.h" +#include "ScopeRWLock.h" #include #include @@ -170,23 +171,6 @@ TArray* FApplePlatformDebugEvents::GetEventSt return Current; } -struct FAppleRWMutex -{ - FAppleRWMutex() - { - int Err = pthread_rwlock_init(&Mutex, nullptr); - checkf(Err == 0, TEXT("pthread_rwlock_init failed with error: %d"), errno); - } - - ~FAppleRWMutex() - { - int Err = pthread_rwlock_destroy(&Mutex); - checkf(Err == 0, TEXT("pthread_rwlock_destroy failed with error: %d"), errno); - } - - pthread_rwlock_t Mutex; -}; - uint16 FApplePlatformDebugEvents::GetEventCode(FString String) { // Never emit 0 as we use that for the frame marker... @@ -207,20 +191,19 @@ uint16 FApplePlatformDebugEvents::GetEventCode(FString String) uint32 Hash = GetTypeHash(String); - static FAppleRWMutex RWMutex; + static FRWLock RWMutex; static TMap Names; { - pthread_rwlock_rdlock(&RWMutex.Mutex); + FRWScopeLock Lock(RWMutex, SLT_ReadOnly); uint16* CodePtr = Names.Find(Hash); if(CodePtr) { Code = *CodePtr; } - pthread_rwlock_unlock(&RWMutex.Mutex); if(!CodePtr) { - pthread_rwlock_wrlock(&RWMutex.Mutex); + Lock.RaiseLockToWrite(); CodePtr = Names.Find(Hash); if(CodePtr) { @@ -233,7 +216,6 @@ uint16 FApplePlatformDebugEvents::GetEventCode(FString String) Names.Add(Hash, Code); UE_LOG(LogInstruments, Display, TEXT("New Event Code: %u : %s"), (uint32)Code, *String); } - pthread_rwlock_unlock(&RWMutex.Mutex); } } diff --git a/Engine/Source/Runtime/Core/Private/Apple/ApplePlatformSymbolication.cpp b/Engine/Source/Runtime/Core/Private/Apple/ApplePlatformSymbolication.cpp index d39aebae0ae8..5e4e19d16e3b 100644 --- a/Engine/Source/Runtime/Core/Private/Apple/ApplePlatformSymbolication.cpp +++ b/Engine/Source/Runtime/Core/Private/Apple/ApplePlatformSymbolication.cpp @@ -91,6 +91,7 @@ static CSSourceInfoGetSymbolPtr CSSourceInfoGetSymbol = nullptr; FApplePlatformSymbolDatabase::FApplePlatformSymbolDatabase() { + GenericDB = MakeShareable( new FGenericPlatformSymbolDatabase() ); AppleDB.Buffer0 = nullptr; AppleDB.Buffer1 = nullptr; } @@ -108,6 +109,7 @@ FApplePlatformSymbolDatabase::~FApplePlatformSymbolDatabase() } AppleDB.Buffer0 = nullptr; AppleDB.Buffer1 = nullptr; + GenericDB = nullptr; } FApplePlatformSymbolDatabase& FApplePlatformSymbolDatabase::operator=(FApplePlatformSymbolDatabase const& Other) @@ -116,7 +118,10 @@ FApplePlatformSymbolDatabase& FApplePlatformSymbolDatabase::operator=(FApplePlat { GenericDB = Other.GenericDB; AppleDB = Other.AppleDB; - CSRetain(AppleDB); + if (AppleDB.Buffer0 != nullptr && AppleDB.Buffer1 != nullptr) + { + CSRetain(AppleDB); + } } return *this; } @@ -234,7 +239,7 @@ void FApplePlatformSymbolication::EnableCoreSymbolication(bool const bEnable) bool FApplePlatformSymbolication::LoadSymbolDatabaseForBinary(FString SourceFolder, FString BinaryPath, FString BinarySignature, FApplePlatformSymbolDatabase& OutDatabase) { - bool bOK = FGenericPlatformSymbolication::LoadSymbolDatabaseForBinary(SourceFolder, BinaryPath, BinarySignature, OutDatabase.GenericDB); + bool bOK = FGenericPlatformSymbolication::LoadSymbolDatabaseForBinary(SourceFolder, BinaryPath, BinarySignature, *OutDatabase.GenericDB); if(!bOK && GAllowApplePlatformSymbolication && (IFileManager::Get().FileSize(*BinaryPath) > 0)) { CSSymbolicatorRef Symbolicator = OutDatabase.AppleDB; @@ -242,6 +247,10 @@ bool FApplePlatformSymbolication::LoadSymbolDatabaseForBinary(FString SourceFold { Symbolicator = CSSymbolicatorCreateWithPathAndArchitecture(TCHAR_TO_UTF8(*BinaryPath), CPU_TYPE_X86_64); } + if (CSIsNull(Symbolicator)) + { + Symbolicator = CSSymbolicatorCreateWithPathAndArchitecture(TCHAR_TO_UTF8(*BinaryPath), CPU_TYPE_ARM64); + } if( !CSIsNull(Symbolicator) ) { if(BinarySignature.Len()) @@ -251,7 +260,7 @@ bool FApplePlatformSymbolication::LoadSymbolDatabaseForBinary(FString SourceFold CSSymbolOwnerRef SymbolOwner = CSSymbolicatorGetSymbolOwnerWithUUIDAtTime(Symbolicator, UUID, kCSNow); bOK = (!CSIsNull(SymbolOwner)); - OutDatabase.GenericDB.Signature = BinarySignature; + OutDatabase.GenericDB->Signature = BinarySignature; } else { @@ -261,7 +270,7 @@ bool FApplePlatformSymbolication::LoadSymbolDatabaseForBinary(FString SourceFold CFUUIDRef OwnerUUID = CSSymbolOwnerGetUUID(SymbolOwner); CFStringRef String = CFUUIDCreateString(kCFAllocatorDefault, OwnerUUID); check(String); - OutDatabase.GenericDB.Signature = FString((NSString*)String); + OutDatabase.GenericDB->Signature = FString((NSString*)String); CFRelease(String); bOK = true; } @@ -276,7 +285,7 @@ bool FApplePlatformSymbolication::LoadSymbolDatabaseForBinary(FString SourceFold return bOK; } -bool FApplePlatformSymbolication::SaveSymbolDatabaseForBinary(FString TargetFolder, FString InName, FApplePlatformSymbolDatabase& Database) +bool FApplePlatformSymbolication::SaveSymbolDatabaseForBinary(FString TargetFolder, FString InName, FString BinarySignature, FApplePlatformSymbolDatabase& Database) { __block bool bOK = true; if(GAllowApplePlatformSymbolication) @@ -291,14 +300,23 @@ bool FApplePlatformSymbolication::SaveSymbolDatabaseForBinary(FString TargetFold const char* OwnerName = CSSymbolOwnerGetName(SymbolOwner); vm_address_t BaseAddress = CSSymbolOwnerGetBaseAddress(SymbolOwner); - Database.GenericDB.Name = OwnerName; - Database.GenericDB.StringTable.Reset(); - Database.GenericDB.Symbols.Reset(); + Database.GenericDB->Name = OwnerName; + Database.GenericDB->StringTable.Reset(); + Database.GenericDB->Symbols.Reset(); - CFStringRef String = CFUUIDCreateString(kCFAllocatorDefault, OwnerUUID); - check(String); - Database.GenericDB.Signature = FString((NSString*)String); - CFRelease(String); + if(BinarySignature.Len()) + { + CFUUIDRef UUID = CFUUIDCreateFromString(kCFAllocatorDefault, (CFStringRef)BinarySignature.GetNSString()); + check(UUID); + Database.GenericDB->Signature = BinarySignature; + } + else + { + CFStringRef String = CFUUIDCreateString(kCFAllocatorDefault, OwnerUUID); + check(String); + Database.GenericDB->Signature = FString((NSString*)String); + CFRelease(String); + } CSSymbolicatorForeachSymbolAtTime(Symbolicator, kCSNow, ^(CSSymbolRef Symbol){ CSSymbolOwnerRef Owner = CSSymbolGetSymbolOwner(Symbol); @@ -316,9 +334,9 @@ bool FApplePlatformSymbolication::SaveSymbolDatabaseForBinary(FString TargetFold } else { - SymbolData.NameIdx = Database.GenericDB.StringTable.Num(); + SymbolData.NameIdx = Database.GenericDB->StringTable.Num(); StringLookup.Add(Name, SymbolData.NameIdx); - Database.GenericDB.StringTable.Push(Name); + Database.GenericDB->StringTable.Push(Name); } CSSymbolForeachSourceInfo(Symbol, ^(CSSourceInfoRef SourceInfo){ @@ -338,9 +356,9 @@ bool FApplePlatformSymbolication::SaveSymbolDatabaseForBinary(FString TargetFold } else { - Info.PathIdx = Database.GenericDB.StringTable.Num(); + Info.PathIdx = Database.GenericDB->StringTable.Num(); StringLookup.Add(Path, Info.PathIdx); - Database.GenericDB.StringTable.Push(Path); + Database.GenericDB->StringTable.Push(Path); } SymbolData.SymbolInfo.Add(Info); @@ -348,7 +366,7 @@ bool FApplePlatformSymbolication::SaveSymbolDatabaseForBinary(FString TargetFold return 0; }); - Database.GenericDB.Symbols.Add(SymbolData); + Database.GenericDB->Symbols.Add(SymbolData); } else { @@ -358,13 +376,13 @@ bool FApplePlatformSymbolication::SaveSymbolDatabaseForBinary(FString TargetFold } return 0; }); - bOK &= (Database.GenericDB.Symbols.Num() >= 1); + bOK &= (Database.GenericDB->Symbols.Num() >= 1); } } if(bOK) { - bOK = FGenericPlatformSymbolication::SaveSymbolDatabaseForBinary(TargetFolder, InName, Database.GenericDB); + bOK = FGenericPlatformSymbolication::SaveSymbolDatabaseForBinary(TargetFolder, InName, *Database.GenericDB); } return bOK; @@ -372,7 +390,7 @@ bool FApplePlatformSymbolication::SaveSymbolDatabaseForBinary(FString TargetFold bool FApplePlatformSymbolication::SymbolInfoForStrippedSymbol(FApplePlatformSymbolDatabase const& Database, uint64 ProgramCounter, uint64 ModuleOffset, FString ModuleSignature, FProgramCounterSymbolInfo& Info) { - bool bOK = FGenericPlatformSymbolication::SymbolInfoForStrippedSymbol(Database.GenericDB, ProgramCounter, ModuleOffset, ModuleSignature, Info); + bool bOK = FGenericPlatformSymbolication::SymbolInfoForStrippedSymbol(*Database.GenericDB, ProgramCounter, ModuleOffset, ModuleSignature, Info); if(!bOK && GAllowApplePlatformSymbolication && !CSIsNull(Database.AppleDB) && (ModuleSignature.Len())) { CSSymbolicatorRef Symbolicator = Database.AppleDB; diff --git a/Engine/Source/Runtime/Core/Private/Async/TaskGraph.cpp b/Engine/Source/Runtime/Core/Private/Async/TaskGraph.cpp index 0e3d5b713459..4509f505a0d5 100644 --- a/Engine/Source/Runtime/Core/Private/Async/TaskGraph.cpp +++ b/Engine/Source/Runtime/Core/Private/Async/TaskGraph.cpp @@ -25,6 +25,7 @@ #include "Misc/App.h" #include "Containers/LockFreeFixedSizeAllocator.h" #include "Async/TaskGraphInterfaces.h" +#include "HAL/ThreadHeartBeat.h" DEFINE_LOG_CATEGORY_STATIC(LogTaskGraph, Log, All); @@ -33,12 +34,14 @@ DEFINE_STAT(STAT_FTriggerEventGraphTask); DEFINE_STAT(STAT_ParallelFor); DEFINE_STAT(STAT_ParallelForTask); -#if PLATFORM_XBOXONE || PLATFORM_PS4 -#define CREATE_HIPRI_TASK_THREADS (1) -#define CREATE_BACKGROUND_TASK_THREADS (1) +static int32 GNumWorkerThreadsToIgnore = 0; + +#if (PLATFORM_XBOXONE || PLATFORM_PS4 || PLATFORM_WINDOWS || PLATFORM_MAC || PLATFORM_LINUX) && !IS_PROGRAM && WITH_ENGINE && !UE_SERVER + #define CREATE_HIPRI_TASK_THREADS (1) + #define CREATE_BACKGROUND_TASK_THREADS (1) #else -#define CREATE_HIPRI_TASK_THREADS (0) -#define CREATE_BACKGROUND_TASK_THREADS (0) + #define CREATE_HIPRI_TASK_THREADS (0) + #define CREATE_BACKGROUND_TASK_THREADS (0) #endif namespace ENamedThreads @@ -49,39 +52,7 @@ namespace ENamedThreads CORE_API int32 bHasHighPriorityThreads = CREATE_HIPRI_TASK_THREADS; } -static int32 GNumWorkerThreadsToIgnore = 0; -static FAutoConsoleVariableRef CVarNumWorkerThreadsToIgnore( - TEXT("TaskGraph.NumWorkerThreadsToIgnore"), - GNumWorkerThreadsToIgnore, - TEXT("Used to tune the number of task threads. Generally once you have found the right value, PlatformMisc::NumberOfWorkerThreadsToSpawn() should be hardcoded."), - ECVF_Cheat - ); - -static int32 GFastScheduler = 0; -#if USE_NEW_LOCK_FREE_LISTS -static int32 GFastSchedulerLatched = 1; -#else -static int32 GFastSchedulerLatched = 0; -#endif -static FAutoConsoleVariableRef CVarFastScheduler( - TEXT("TaskGraph.FastScheduler"), - GFastScheduler, - TEXT("If > 0, then use the new experimental anythread task scheduler."), - ECVF_Cheat - ); - -// move to platform abstraction -#if PLATFORM_XBOXONE || PLATFORM_PS4 -#define PLATFORM_OK_TO_BURN_CPU (1) -#else -#define PLATFORM_OK_TO_BURN_CPU (0) -#endif - -#define USE_INTRUSIVE_TASKQUEUES (USE_NEW_LOCK_FREE_LISTS) - - #if CREATE_HIPRI_TASK_THREADS || CREATE_BACKGROUND_TASK_THREADS - static int32 GConsoleSpinMode = 0; // when we have multiple task thread banks, we don't want to do spin mode as a high priority thread spinning would interfere with lower priority work static void ThreadSwitchForABTest(const TArray& Args) { if (Args.Num() == 2) @@ -106,16 +77,8 @@ static FAutoConsoleVariableRef CVarFastScheduler( FConsoleCommandWithArgsDelegate::CreateStatic(&ThreadSwitchForABTest) ); -#else - static int32 GConsoleSpinMode = PLATFORM_OK_TO_BURN_CPU * 2; - static FAutoConsoleVariableRef CVarConsoleSpinMode( - TEXT("TaskGraph.ConsoleSpinMode"), - GConsoleSpinMode, - TEXT("If > 0, then we never allow all task threads to idle; one will always be spinning looking for work (if mode == 2, then we sleep0 when spinning); this relieve the calling thread from the buden of starting threads. Only active with TaskGraph.FastScheduler 1."), - ECVF_Cheat - ); #endif -static int32 GConsoleSpinModeLatched = 0; + #if CREATE_BACKGROUND_TASK_THREADS static FAutoConsoleVariableRef CVarUseBackgroundThreads( @@ -135,21 +98,6 @@ static FAutoConsoleVariableRef CVarUseHiPriThreads( ); #endif - - -#if USE_NEW_LOCK_FREE_LISTS -static int32 GMaxTasksToStartOnDequeue = 1; -#else -static int32 GMaxTasksToStartOnDequeue = 2; -#endif - -static FAutoConsoleVariableRef CVarMaxTasksToStartOnDequeue( - TEXT("TaskGraph.MaxTasksToStartOnDequeue"), - GMaxTasksToStartOnDequeue, - TEXT("Performance tweak, controls how many additional task threads a task thread starts when it grabs a list of new tasks. This only applies in TaskGraph.ConsoleSpinMode"), - ECVF_Cheat - ); - #define PROFILE_TASKGRAPH (0) #if PROFILE_TASKGRAPH struct FProfileRec @@ -415,96 +363,6 @@ void FAutoConsoleTaskPriority::CommandExecute(const TArray& Args) } -/** - * FTaskQueue - * High performance, SINGLE threaded, FIFO task queue for the private queue on named threads. -**/ -class FTaskQueue -{ -public: - /** Constructor, sets the queue to the empty state. **/ - FTaskQueue() - : StartIndex(0) - , EndIndex(0) - { - } - /** Returns the number of non-NULL items in the queue. **/ - FORCEINLINE int32 Num() const - { - CheckInvariants(); - return EndIndex - StartIndex; - } - /** - * Adds a task to the queue. - * @param Task; the task to add to the queue - **/ - FORCEINLINE void Enqueue(FBaseGraphTask* Task) - { - CheckInvariants(); - if (EndIndex >= Tasks.Num()) - { - if (StartIndex >= ARRAY_EXPAND) - { - checkThreadGraph(Tasks[StartIndex - 1]==NULL); - checkThreadGraph(Tasks[0]==NULL); - FMemory::Memmove(Tasks.GetData(), &Tasks[StartIndex], (EndIndex - StartIndex) * sizeof(FBaseGraphTask*)); - EndIndex -= StartIndex; - FMemory::Memzero(&Tasks[EndIndex],StartIndex * sizeof(FBaseGraphTask*)); // not needed in final - StartIndex = 0; - } - else - { - Tasks.AddZeroed(ARRAY_EXPAND); - } - } - checkThreadGraph(EndIndex < Tasks.Num() && Tasks[EndIndex]==NULL); - Tasks[EndIndex++] = Task; - } - /** - * Pops a task off the queue. - * @return The oldest task in the queue or NULL if the queue is empty - **/ - FORCEINLINE FBaseGraphTask* Dequeue() - { - if (!Num()) - { - return NULL; - } - FBaseGraphTask* ReturnValue = Tasks[StartIndex]; - Tasks[StartIndex++] = NULL; - if (StartIndex == EndIndex) - { - // Queue is empty, reset to start - StartIndex = 0; - EndIndex = 0; - } - return ReturnValue; - } -private: - enum - { - /** Number of tasks by which to expand and compact the queue on **/ - ARRAY_EXPAND=1024 - }; - - /** Internal function to verify the state of the object is legal. **/ - void CheckInvariants() const - { - checkThreadGraph(StartIndex <= EndIndex); - checkThreadGraph(EndIndex <= Tasks.Num()); - checkThreadGraph(StartIndex >= 0 && EndIndex >= 0); - } - - /** Array to hold the tasks, only the [StartIndex,EndIndex) range contains non-NULL tasks. **/ - TArray Tasks; - - /** Index of first non-NULL task in the queue unless StartIndex == EndIndex (which means empty) **/ - int32 StartIndex; - - /** Index of first NULL task in the queue after the non-NULL tasks, unless StartIndex == EndIndex (which means empty) **/ - int32 EndIndex; - -}; /** * FTaskThreadBase @@ -691,69 +549,28 @@ public: virtual void ProcessTasksUntilQuit(int32 QueueIndex) override { - Queue(QueueIndex).QuitWhenIdle.Reset(); + check(Queue(QueueIndex).StallRestartEvent); // make sure we are started up + + Queue(QueueIndex).QuitForReturn = false; verify(++Queue(QueueIndex).RecursionGuard == 1); - //checkThreadGraph(!Queue(QueueIndex).IncomingQueue.IsClosed()); // make sure we are started up - while (Queue(QueueIndex).QuitWhenIdle.GetValue() == 0) + do { - ProcessTasksNamedThread(QueueIndex, true); - // @Hack - quit now when running with only one thread. - if (!FPlatformProcess::SupportsMultithreading()) - { - break; - } - } - //checkThreadGraph(!Queue(QueueIndex).IncomingQueue.IsClosed()); // make sure we are started up + ProcessTasksNamedThread(QueueIndex, FPlatformProcess::SupportsMultithreading()); + } while (!Queue(QueueIndex).QuitForReturn && !Queue(QueueIndex).QuitForShutdown && FPlatformProcess::SupportsMultithreading()); // @Hack - quit now when running with only one thread. verify(!--Queue(QueueIndex).RecursionGuard); } virtual void ProcessTasksUntilIdle(int32 QueueIndex) override { + check(Queue(QueueIndex).StallRestartEvent); // make sure we are started up + + Queue(QueueIndex).QuitForReturn = false; verify(++Queue(QueueIndex).RecursionGuard == 1); - //checkThreadGraph(!Queue(QueueIndex).IncomingQueue.IsClosed()); // make sure we are started up ProcessTasksNamedThread(QueueIndex, false); - //checkThreadGraph(!Queue(QueueIndex).IncomingQueue.IsClosed()); // make sure we are started up verify(!--Queue(QueueIndex).RecursionGuard); } -#if USE_NEW_LOCK_FREE_LISTS - FORCEINLINE FBaseGraphTask* GetNextTask(int32 QueueIndex) - { - FBaseGraphTask* Task = NULL; - Task = Queue(QueueIndex).PrivateQueueHiPri.Dequeue(); - if (!Task) - { - if (Queue(QueueIndex).OutstandingHiPriTasks.GetValue()) - { - while (true) - { - FBaseGraphTask* NewTask = Queue(QueueIndex).IncomingQueue.Pop(); - if (!NewTask) - { - break; - } - if (ENamedThreads::GetTaskPriority(NewTask->ThreadToExecuteOn)) - { - Queue(QueueIndex).OutstandingHiPriTasks.Decrement(); - Task = NewTask; - break; - } - else - { - Queue(QueueIndex).PrivateQueue.Enqueue(NewTask); - } - } - } - if (!Task) - { - Task = Queue(QueueIndex).PrivateQueue.Dequeue(); - } - } - if (!Task) - { - Task = Queue(QueueIndex).IncomingQueue.Pop(); - } - return Task; - } + + void ProcessTasksNamedThread(int32 QueueIndex, bool bAllowStall) { TStatId StallStatId; @@ -789,13 +606,14 @@ public: ProcessingTasks.Start(StatName); } #endif - while (1) + while (!Queue(QueueIndex).QuitForReturn) { - FBaseGraphTask* Task = GetNextTask(QueueIndex); + FBaseGraphTask* Task = Queue(QueueIndex).StallQueue.Pop(0, bAllowStall); + TestRandomizedThreads(); if (!Task) { #if STATS - if(bTasksOpen) + if (bTasksOpen) { ProcessingTasks.Stop(); bTasksOpen = false; @@ -803,10 +621,14 @@ public: #endif if (bAllowStall) { - bool bNewTaskReady = Stall(QueueIndex, StallStatId, bCountAsStall); - if (!bNewTaskReady) { - break; // we didn't really stall, rather we were asked to quit + FScopeCycleCounter Scope(StallStatId); + Queue(QueueIndex).StallRestartEvent->Wait(MAX_uint32, bCountAsStall); + if (Queue(QueueIndex).QuitForShutdown) + { + return; + } + TestRandomizedThreads(); } #if STATS if (!bTasksOpen && FThreadStats::IsCollectingData(StatName)) @@ -824,160 +646,24 @@ public: } else { - TestRandomizedThreads(); Task->Execute(NewTasks, ENamedThreads::Type(ThreadId | (QueueIndex << ENamedThreads::QueueIndexShift))); TestRandomizedThreads(); } } - } -#else - void ProcessTasksNamedThread(int32 QueueIndex, bool bAllowStall) - { - //checkThreadGraph(!Queue(QueueIndex).IncomingQueue.IsClosed()); // make sure we are started up - TStatId StallStatId; - bool bCountAsStall = false; #if STATS - TStatId StatName; - FCycleCounter ProcessingTasks; - if (ThreadId == ENamedThreads::GameThread) - { - StatName = GET_STATID(STAT_TaskGraph_GameTasks); - StallStatId = GET_STATID(STAT_TaskGraph_GameStalls); - bCountAsStall = true; - } - else if (ThreadId == ENamedThreads::RenderThread) - { - if (QueueIndex > 0) - { - StallStatId = GET_STATID(STAT_TaskGraph_RenderStalls); - bCountAsStall = true; - } - // else StatName = none, we need to let the scope empty so that the render thread submits tasks in a timely manner. - } - else if (ThreadId != ENamedThreads::StatsThread) - { - StatName = GET_STATID(STAT_TaskGraph_OtherTasks); - StallStatId = GET_STATID(STAT_TaskGraph_OtherStalls); - bCountAsStall = true; - } - bool bTasksOpen = false; -#endif - while (1) - { - FBaseGraphTask* Task = NULL; - Task = Queue(QueueIndex).PrivateQueueHiPri.Dequeue(); - if (!Task) - { - if (Queue(QueueIndex).OutstandingHiPriTasks.GetValue()) - { - Queue(QueueIndex).IncomingQueue.PopAll(NewTasks); - if (NewTasks.Num()) - { - for (int32 Index = NewTasks.Num() - 1; Index >= 0 ; Index--) // reverse the order since PopAll is implicitly backwards - { - FBaseGraphTask* NewTask = NewTasks[Index]; - if (ENamedThreads::GetTaskPriority(NewTask->ThreadToExecuteOn)) - { - Queue(QueueIndex).PrivateQueueHiPri.Enqueue(NewTask); - Queue(QueueIndex).OutstandingHiPriTasks.Decrement(); - } - else - { - Queue(QueueIndex).PrivateQueue.Enqueue(NewTask); - } - } - NewTasks.Reset(); - Task = Queue(QueueIndex).PrivateQueueHiPri.Dequeue(); - } - } - if (!Task) - { - Task = Queue(QueueIndex).PrivateQueue.Dequeue(); - } - } - if (!Task) - { - Queue(QueueIndex).IncomingQueue.PopAll(NewTasks); - if (!NewTasks.Num()) - { - if (bAllowStall) - { -#if STATS - if(bTasksOpen) - { - ProcessingTasks.Stop(); - bTasksOpen = false; - } -#endif - if (Stall(QueueIndex, StallStatId, bCountAsStall)) - { - Queue(QueueIndex).IncomingQueue.PopAll(NewTasks); - } - } - } - if (NewTasks.Num()) - { - for (int32 Index = NewTasks.Num() - 1; Index >= 0 ; Index--) // reverse the order since PopAll is implicitly backwards - { - FBaseGraphTask* NewTask = NewTasks[Index]; - checkThreadGraph(NewTask); - if (ENamedThreads::GetTaskPriority(NewTask->ThreadToExecuteOn)) - { - Queue(QueueIndex).PrivateQueueHiPri.Enqueue(NewTask); - Queue(QueueIndex).OutstandingHiPriTasks.Decrement(); - } - else - { - Queue(QueueIndex).PrivateQueue.Enqueue(NewTask); - } - } - NewTasks.Reset(); - Task = Queue(QueueIndex).PrivateQueueHiPri.Dequeue(); - if (!Task) - { - Task = Queue(QueueIndex).PrivateQueue.Dequeue(); - } - } - } - if (Task) - { - TestRandomizedThreads(); -#if STATS - if (!bTasksOpen && FThreadStats::IsCollectingData(StatName)) - { - bTasksOpen = true; - ProcessingTasks.Start(StatName); - } -#endif - Task->Execute(NewTasks, ENamedThreads::Type(ThreadId | (QueueIndex << ENamedThreads::QueueIndexShift))); - - TestRandomizedThreads(); - } - else - { - break; - } - } -#if STATS - if(bTasksOpen) + if (bTasksOpen) { ProcessingTasks.Stop(); bTasksOpen = false; } #endif } -#endif virtual void EnqueueFromThisThread(int32 QueueIndex, FBaseGraphTask* Task) override { checkThreadGraph(Task && Queue(QueueIndex).StallRestartEvent); // make sure we are started up - if (ENamedThreads::GetTaskPriority(Task->ThreadToExecuteOn)) - { - Queue(QueueIndex).PrivateQueueHiPri.Enqueue(Task); - } - else - { - Queue(QueueIndex).PrivateQueue.Enqueue(Task); - } + uint32 PriIndex = ENamedThreads::GetTaskPriority(Task->ThreadToExecuteOn) ? 0 : 1; + int32 ThreadToStart = Queue(QueueIndex).StallQueue.Push(Task, PriIndex); + check(ThreadToStart < 0); // if I am stalled, then how can I be queueing a task? } virtual void RequestQuit(int32 QueueIndex) override @@ -987,31 +673,21 @@ public: { return; } -#if USE_NEW_LOCK_FREE_LISTS if (QueueIndex == -1) { // we are shutting down checkThreadGraph(Queue(0).StallRestartEvent); // make sure we are started up checkThreadGraph(Queue(1).StallRestartEvent); // make sure we are started up - Queue(0).QuitWhenIdle.Increment(); - Queue(1).QuitWhenIdle.Increment(); - Queue(0).StallRestartEvent->Trigger(); - Queue(1).StallRestartEvent->Trigger(); + Queue(0).QuitForShutdown = true; + Queue(1).QuitForShutdown = true; + Queue(0).StallRestartEvent->Trigger(); + Queue(1).StallRestartEvent->Trigger(); } else { checkThreadGraph(Queue(QueueIndex).StallRestartEvent); // make sure we are started up - Queue(QueueIndex).QuitWhenIdle.Increment(); + Queue(QueueIndex).QuitForReturn = true; } -#else - if (QueueIndex == -1) - { - QueueIndex = 0; - } - checkThreadGraph(Queue(QueueIndex).StallRestartEvent); // make sure we are started up - Queue(QueueIndex).QuitWhenIdle.Increment(); - Queue(QueueIndex).StallRestartEvent->Trigger(); -#endif } virtual bool EnqueueFromOtherThread(int32 QueueIndex, FBaseGraphTask* Task) override @@ -1019,22 +695,17 @@ public: TestRandomizedThreads(); checkThreadGraph(Task && Queue(QueueIndex).StallRestartEvent); // make sure we are started up - bool bWasReopenedByMe; - bool bHiPri = !!ENamedThreads::GetTaskPriority(Task->ThreadToExecuteOn); - { - TASKGRAPH_SCOPE_CYCLE_COUNTER(0, STAT_TaskGraph_EnqueueFromOtherThread_ReopenIfClosedAndPush); - bWasReopenedByMe = Queue(QueueIndex).IncomingQueue.ReopenIfClosedAndPush(Task); - } - if (bHiPri) - { - Queue(QueueIndex).OutstandingHiPriTasks.Increment(); - } - if (bWasReopenedByMe) + uint32 PriIndex = ENamedThreads::GetTaskPriority(Task->ThreadToExecuteOn) ? 0 : 1; + int32 ThreadToStart = Queue(QueueIndex).StallQueue.Push(Task, PriIndex); + + if (ThreadToStart >= 0) { + checkThreadGraph(ThreadToStart == 0); TASKGRAPH_SCOPE_CYCLE_COUNTER(1, STAT_TaskGraph_EnqueueFromOtherThread_Trigger); Queue(QueueIndex).StallRestartEvent->Trigger(); + return true; } - return bWasReopenedByMe; + return false; } virtual bool IsProcessingTasks(int32 QueueIndex) override @@ -1047,88 +718,35 @@ private: /** Grouping of the data for an individual queue. **/ struct FThreadTaskQueue { - /** A non-threas safe queue for the thread locked tasks of a named thread **/ - FTaskQueue PrivateQueue; - /** A non-threas safe queue for the thread locked tasks of a named thread. These are high priority.**/ - FTaskQueue PrivateQueueHiPri; + FStallingTaskQueue StallQueue; - uint8 PadToAvoidContention1[PLATFORM_CACHE_LINE_SIZE]; - /** Used to signal pending hi pri tasks. **/ - FThreadSafeCounter OutstandingHiPriTasks; - uint8 PadToAvoidContention2[PLATFORM_CACHE_LINE_SIZE]; - - - /** - * For named threads, this is a queue of thread locked tasks coming from other threads. They are not stealable. - * For unnamed thread this is the public queue, subject to stealing. - * In either case this queue is closely related to the stall event. Other threads that reopen the incoming queue must trigger the stall event to allow the thread to run. - **/ -#if USE_NEW_LOCK_FREE_LISTS && USE_INTRUSIVE_TASKQUEUES - FCloseableLockFreePointerQueueBaseSingleBaseConsumerIntrusive IncomingQueue; -#elif USE_NEW_LOCK_FREE_LISTS - TReopenableLockFreePointerListFIFOSingleConsumer IncomingQueue; -#else - TReopenableLockFreePointerListLIFO IncomingQueue; -#endif - uint8 PadToAvoidContention3[PLATFORM_CACHE_LINE_SIZE]; - /** Used to signal the thread to quit when idle. **/ - FThreadSafeCounter QuitWhenIdle; /** We need to disallow reentry of the processing loop **/ - uint32 RecursionGuard; + uint32 RecursionGuard; + + /** Indicates we executed a return task, so break out of the processing loop. **/ + bool QuitForReturn; + + /** Indicates we executed a return task, so break out of the processing loop. **/ + bool QuitForShutdown; + /** Event that this thread blocks on when it runs out of work. **/ - FEvent* StallRestartEvent; + FEvent* StallRestartEvent; FThreadTaskQueue() : RecursionGuard(0) - , StallRestartEvent(FPlatformProcess::GetSynchEventFromPool(true)) + , QuitForReturn(false) + , QuitForShutdown(false) + , StallRestartEvent(FPlatformProcess::GetSynchEventFromPool(false)) { } ~FThreadTaskQueue() { - FPlatformProcess::ReturnSynchEventToPool( StallRestartEvent ); + FPlatformProcess::ReturnSynchEventToPool(StallRestartEvent); StallRestartEvent = nullptr; } }; - /** - * Internal function to block on the stall wait event. - * @param QueueIndex - Queue to stall - * @param StallStatId - Stall stat id - * @param bCountAsStall - true if StallStatId is a valid stat id - * @return true if the thread actually stalled; false in the case of a stop request or a task arrived while we were trying to stall. - */ - bool Stall(int32 QueueIndex, TStatId StallStatId, bool bCountAsStall) - { - TestRandomizedThreads(); - - checkThreadGraph(Queue(QueueIndex).StallRestartEvent); // make sure we are started up - if (Queue(QueueIndex).QuitWhenIdle.GetValue() == 0) - { - // @Hack - Only stall when multithreading is enabled. - if (FPlatformProcess::SupportsMultithreading()) - { - FPlatformMisc::MemoryBarrier(); - Queue(QueueIndex).StallRestartEvent->Reset(); - TestRandomizedThreads(); - if (Queue(QueueIndex).IncomingQueue.CloseIfEmpty()) - { - FScopeCycleCounter Scope( StallStatId ); - - TestRandomizedThreads(); - Queue(QueueIndex).StallRestartEvent->Wait(MAX_uint32, bCountAsStall); - //checkThreadGraph(!Queue(QueueIndex).IncomingQueue.IsClosed()); // make sure we are started up - return true; - } - } - else - { - return true; - } - } - return false; - } - FORCEINLINE FThreadTaskQueue& Queue(int32 QueueIndex) { checkThreadGraph(QueueIndex >= 0 && QueueIndex < ENamedThreads::NumQueues); @@ -1140,13 +758,12 @@ private: return Queues[QueueIndex]; } - /** Array of queues, only the first one is used for unnamed threads. **/ FThreadTaskQueue Queues[ENamedThreads::NumQueues]; }; -/** - * FTaskThreadAnyThread - * A class for managing a worker threads. +/** +* FTaskThreadAnyThread +* A class for managing a worker threads. **/ class FTaskThreadAnyThread : public FTaskThreadBase { @@ -1155,7 +772,6 @@ public: : PriorityIndex(InPriorityIndex) { } - /** Used for named threads to start processing tasks until the thread is idle and RequestQuit has been called. **/ virtual void ProcessTasksUntilQuit(int32 QueueIndex) override { if (PriorityIndex != (ENamedThreads::BackgroundThreadPriority >> ENamedThreads::ThreadPriorityShift)) @@ -1163,38 +779,31 @@ public: FMemory::SetupTLSCachesOnCurrentThread(); } check(!QueueIndex); - Queue.QuitWhenIdle.Reset(); - while (Queue.QuitWhenIdle.GetValue() == 0) + do { - ProcessTasks(); - // @Hack - quit now when running with only one thread. - if (!FPlatformProcess::SupportsMultithreading()) - { - break; - } - } + ProcessTasks(); + } while (!Queue.QuitForShutdown && FPlatformProcess::SupportsMultithreading()); // @Hack - quit now when running with only one thread. } virtual void ProcessTasksUntilIdle(int32 QueueIndex) override { - if (!FPlatformProcess::SupportsMultithreading()) + if (!FPlatformProcess::SupportsMultithreading()) { - Queue.QuitWhenIdle.Set(1); ProcessTasks(); - Queue.QuitWhenIdle.Reset(); } else { - FTaskThreadBase::ProcessTasksUntilIdle(QueueIndex); + check(0); } } + // Calls meant to be called from any thread. - /** - * Will cause the thread to return to the caller when it becomes idle. Used to return from ProcessTasksUntilQuit for named threads or to shut down unnamed threads. - * CAUTION: This will not work under arbitrary circumstances. For example you should not attempt to stop unnamed threads unless they are known to be idle. - * Return requests for named threads should be submitted from that named thread as FReturnGraphTask does. - * @param QueueIndex, Queue to request quit from + /** + * Will cause the thread to return to the caller when it becomes idle. Used to return from ProcessTasksUntilQuit for named threads or to shut down unnamed threads. + * CAUTION: This will not work under arbitrary circumstances. For example you should not attempt to stop unnamed threads unless they are known to be idle. + * Return requests for named threads should be submitted from that named thread as FReturnGraphTask does. + * @param QueueIndex, Queue to request quit from **/ virtual void RequestQuit(int32 QueueIndex) override { @@ -1202,8 +811,8 @@ public: // this will not work under arbitrary circumstances. For example you should not attempt to stop threads unless they are known to be idle. checkThreadGraph(Queue.StallRestartEvent); // make sure we are started up - Queue.QuitWhenIdle.Increment(); - Queue.StallRestartEvent->Trigger(); + Queue.QuitForShutdown = true; + Queue.StallRestartEvent->Trigger(); } virtual void WakeUp() final override @@ -1212,10 +821,23 @@ public: Queue.StallRestartEvent->Trigger(); } - /** - *Return true if this thread is processing tasks. This is only a "guess" if you ask for a thread other than yourself because that can change before the function returns. - *@param QueueIndex, Queue to request quit from - **/ + void StallForTuning(bool Stall) + { + if (Stall) + { + Queue.StallForTuning.Lock(); + Queue.bStallForTuning = true; + } + else + { + Queue.bStallForTuning = false; + Queue.StallForTuning.Unlock(); + } + } + /** + *Return true if this thread is processing tasks. This is only a "guess" if you ask for a thread other than yourself because that can change before the function returns. + *@param QueueIndex, Queue to request quit from + **/ virtual bool IsProcessingTasks(int32 QueueIndex) override { check(!QueueIndex); @@ -1224,11 +846,11 @@ public: private: - /** - * Process tasks until idle. May block if bAllowStall is true - * @param QueueIndex, Queue to process tasks from - * @param bAllowStall, if true, the thread will block on the stall event when it runs out of tasks. - **/ + /** + * Process tasks until idle. May block if bAllowStall is true + * @param QueueIndex, Queue to process tasks from + * @param bAllowStall, if true, the thread will block on the stall event when it runs out of tasks. + **/ void ProcessTasks() { TStatId StallStatId; @@ -1252,17 +874,26 @@ private: if (!Task) { #if STATS - if(bTasksOpen) + if (bTasksOpen) { ProcessingTasks.Stop(); bTasksOpen = false; } #endif - Stall(StallStatId, bCountAsStall); - if (Queue.QuitWhenIdle.GetValue()) + + TestRandomizedThreads(); + if (FPlatformProcess::SupportsMultithreading()) + { + FScopeCycleCounter Scope(StallStatId); + Queue.StallRestartEvent->Wait(MAX_uint32, bCountAsStall); + } + if (Queue.QuitForShutdown || !FPlatformProcess::SupportsMultithreading()) { break; } + + TestRandomizedThreads(); + #if STATS if (FThreadStats::IsCollectingData(StatName)) { @@ -1275,6 +906,26 @@ private: TestRandomizedThreads(); Task->Execute(NewTasks, ENamedThreads::Type(ThreadId)); TestRandomizedThreads(); + if (Queue.bStallForTuning) + { +#if STATS + if (bTasksOpen) + { + ProcessingTasks.Stop(); + bTasksOpen = false; + } +#endif + { + FScopeLock Lock(&Queue.StallForTuning); + } +#if STATS + if (FThreadStats::IsCollectingData(StatName)) + { + bTasksOpen = true; + ProcessingTasks.Start(StatName); + } +#endif + } } verify(!--Queue.RecursionGuard); } @@ -1282,78 +933,43 @@ private: /** Grouping of the data for an individual queue. **/ struct FThreadTaskQueue { - /** Used to signal the thread to quit when idle. **/ - FThreadSafeCounter QuitWhenIdle; - /** We need to disallow reentry of the processing loop **/ - uint32 RecursionGuard; /** Event that this thread blocks on when it runs out of work. **/ - FEvent* StallRestartEvent; + FEvent* StallRestartEvent; + /** We need to disallow reentry of the processing loop **/ + uint32 RecursionGuard; + /** Indicates we executed a return task, so break out of the processing loop. **/ + bool QuitForShutdown; + /** Should we stall for tuning? **/ + bool bStallForTuning; + FCriticalSection StallForTuning; FThreadTaskQueue() - : RecursionGuard(0) - , StallRestartEvent(FPlatformProcess::GetSynchEventFromPool(true)) + : StallRestartEvent(FPlatformProcess::GetSynchEventFromPool(false)) + , RecursionGuard(0) + , QuitForShutdown(false) + , bStallForTuning(false) { } ~FThreadTaskQueue() { - FPlatformProcess::ReturnSynchEventToPool( StallRestartEvent ); + FPlatformProcess::ReturnSynchEventToPool(StallRestartEvent); StallRestartEvent = nullptr; } }; /** - * Internal function to block on the stall wait event. - * @param QueueIndex - Queue to stall - * @param StallStatId - Stall stat id - * @param bCountAsStall - true if StallStatId is a valid stat id - */ - void Stall(TStatId StallStatId, bool bCountAsStall) - { - TestRandomizedThreads(); - - checkThreadGraph(Queue.StallRestartEvent); // make sure we are started up - if (Queue.QuitWhenIdle.GetValue() == 0) - { - // @Hack - Only stall when multithreading is enabled. - if (FPlatformProcess::SupportsMultithreading()) - { - FPlatformMisc::MemoryBarrier(); - - FScopeCycleCounter Scope( StallStatId ); - - NotifyStalling(); - TestRandomizedThreads(); - Queue.StallRestartEvent->Wait(MAX_uint32, bCountAsStall); - TestRandomizedThreads(); - Queue.StallRestartEvent->Reset(); - } - } - } - - /** - * Internal function to call the system looking for work. Called from this thread. - * @return New task to process. - */ + * Internal function to call the system looking for work. Called from this thread. + * @return New task to process. + */ FBaseGraphTask* FindWork(); - /** - * Internal function to notify the that system that I am stalling. This is a hint to give me a job asap. - */ - void NotifyStalling(); - /** Array of queues, only the first one is used for unnamed threads. **/ FThreadTaskQueue Queue; int32 PriorityIndex; }; -/** - * FTaskGraphImplementation - * Implementation of the centralized part of the task graph system. - * These parts of the system have no knowledge of the dependency graph, they exclusively work on tasks. -**/ -#define FAtomicStateBitfield_MAX_THREADS (13) /** * FWorkerThread @@ -1377,7 +993,13 @@ struct FWorkerThread } }; -class FTaskGraphImplementation : public FTaskGraphInterface +/** +* FTaskGraphImplementation +* Implementation of the centralized part of the task graph system. +* These parts of the system have no knowledge of the dependency graph, they exclusively work on tasks. +**/ + +class FTaskGraphImplementation : public FTaskGraphInterface { public: @@ -1527,11 +1149,6 @@ public: } TaskGraphImplementationSingleton = NULL; NumTaskThreadsPerSet = 0; - TArray NotProperlyUnstalled; - for (int32 PriorityIndex = 0; PriorityIndex < NumTaskThreadSets; PriorityIndex++) - { - StalledUnnamedThreads[PriorityIndex].PopAll(NotProperlyUnstalled); - } FPlatformTLS::FreeTlsSlot(PerThreadIDTLSSlot); } @@ -1547,61 +1164,12 @@ public: { TASKGRAPH_SCOPE_CYCLE_COUNTER(2, STAT_TaskGraph_QueueTask); - TestRandomizedThreads(); - checkThreadGraph(NumTaskThreadsPerSet); - if (GFastSchedulerLatched != GFastScheduler && IsInGameThread()) - { -#if USE_NEW_LOCK_FREE_LISTS - GFastScheduler = !!FApp::ShouldUseThreadingForPerformance(); -#endif - if (GFastSchedulerLatched != GFastScheduler) - { - if (GFastScheduler) - { - for (int32 PriorityIndex = 0; PriorityIndex < NumTaskThreadSets; PriorityIndex++) - { - AtomicForConsoleApproach[PriorityIndex] = FAtomicStateBitfield(); - AtomicForConsoleApproach[PriorityIndex].Stalled = (1 << GetNumWorkerThreads()) - 1; // everyone is stalled - } - } - // this is all kinda of sketchy, but runtime switching just has to barely work. - FPlatformProcess::Sleep(.1f); // hopefully all task threads are idle - GFastSchedulerLatched = GFastScheduler; - - // wake up all threads to prevent deadlock on the transition - if (GFastSchedulerLatched) - { - GConsoleSpinModeLatched = 0; // nobody is started now, this will re latch and start someone if we have that mode on - } - else - { - StartAllTaskThreads(true); - } - } - } - if (GFastSchedulerLatched && GConsoleSpinModeLatched != GConsoleSpinMode && IsInGameThread()) - { - bool bStartTask = GConsoleSpinMode && ((!!GConsoleSpinModeLatched) != !!GConsoleSpinMode); - GConsoleSpinModeLatched = GConsoleSpinMode; - if (bStartTask) - { - for (int32 Priority = 0; Priority < ENamedThreads::NumThreadPriorities; Priority++) - { - if (Priority == (ENamedThreads::NormalThreadPriority >> ENamedThreads::ThreadPriorityShift) || - (Priority == (ENamedThreads::HighThreadPriority >> ENamedThreads::ThreadPriorityShift) && bCreatedHiPriorityThreads)) - { - StartTaskThreadFastMode(Priority, -1); - } - } - } - } - if (ENamedThreads::GetThreadIndex(ThreadToExecuteOn) == ENamedThreads::AnyThread) { TASKGRAPH_SCOPE_CYCLE_COUNTER(3, STAT_TaskGraph_QueueTask_AnyThread); if (FPlatformProcess::SupportsMultithreading()) { - int32 TaskPriority = ENamedThreads::GetTaskPriority(Task->ThreadToExecuteOn); + uint32 TaskPriority = ENamedThreads::GetTaskPriority(Task->ThreadToExecuteOn); int32 Priority = ENamedThreads::GetThreadPriorityIndex(Task->ThreadToExecuteOn); if (Priority == (ENamedThreads::BackgroundThreadPriority >> ENamedThreads::ThreadPriorityShift) && (!bCreatedBackgroundPriorityThreads || !ENamedThreads::bHasBackgroundThreads)) { @@ -1614,61 +1182,12 @@ public: TaskPriority = ENamedThreads::HighTaskPriority >> ENamedThreads::TaskPriorityShift; // promote to hi task pri } check(Priority >= 0 && Priority < MAX_THREAD_PRIORITIES); - { TASKGRAPH_SCOPE_CYCLE_COUNTER(4, STAT_TaskGraph_QueueTask_IncomingAnyThreadTasks_Push); - if (TaskPriority) + int32 IndexToStart = IncomingAnyThreadTasks[Priority].Push(Task, TaskPriority); + if (IndexToStart >= 0) { - IncomingAnyThreadTasksHiPri[Priority].Push(Task); - } - else - { - IncomingAnyThreadTasks[Priority].Push(Task); - } - } - if (GFastSchedulerLatched) - { - if (!GConsoleSpinModeLatched || - Priority == (ENamedThreads::BackgroundThreadPriority >> ENamedThreads::ThreadPriorityShift)) // background never spins - { - StartTaskThreadFastMode(Priority, -1); - } - } - else - { - ENamedThreads::Type CurrentThreadIfKnown = ENamedThreads::AnyThread; - if (ENamedThreads::GetThreadIndex(InCurrentThreadIfKnown) == ENamedThreads::AnyThread) - { - CurrentThreadIfKnown = GetCurrentThread(); - } - else - { - CurrentThreadIfKnown = ENamedThreads::GetThreadIndex(InCurrentThreadIfKnown); - checkThreadGraph(CurrentThreadIfKnown == GetCurrentThread()); - } - FTaskThreadBase* TempTarget; - { - TASKGRAPH_SCOPE_CYCLE_COUNTER(5, STAT_TaskGraph_QueueTask_StalledUnnamedThreads_Pop); - TempTarget = StalledUnnamedThreads[Priority].Pop(); //@todo it is possible that a thread is in the process of stalling and we just missed it, non-fatal, but we could lose a whole task of potential parallelism. - if (TempTarget && GNumWorkerThreadsToIgnore && (TempTarget->GetThreadId() - NumNamedThreads) % NumTaskThreadsPerSet >= GetNumWorkerThreads()) - { - TempTarget = nullptr; - } - } - if (TempTarget) - { - ThreadToExecuteOn = TempTarget->GetThreadId(); - } - else - { - check(NumTaskThreadsPerSet - GNumWorkerThreadsToIgnore > 0); // can't tune it to zero task threads - ThreadToExecuteOn = ENamedThreads::Type( - (uint32(NextUnnamedThreadForTaskFromUnknownThread[Priority].Increment()) % uint32(NumTaskThreadsPerSet - GNumWorkerThreadsToIgnore)) + Priority * NumTaskThreadsPerSet + NumNamedThreads); - } - FTaskThreadBase* Target = &Thread(ThreadToExecuteOn); - if (ENamedThreads::GetThreadIndex(ThreadToExecuteOn) != ENamedThreads::GetThreadIndex(CurrentThreadIfKnown)) - { - Target->WakeUp(); + StartTaskThread(Priority, IndexToStart); } } return; @@ -1850,7 +1369,7 @@ public: void StartTaskThread(int32 Priority, int32 IndexToStart) { ENamedThreads::Type ThreadToWake = ENamedThreads::Type(IndexToStart + Priority * NumTaskThreadsPerSet + NumNamedThreads); - ((FTaskThreadAnyThread&)Thread(ThreadToWake)).FTaskThreadAnyThread::WakeUp(); + ((FTaskThreadAnyThread&)Thread(ThreadToWake)).WakeUp(); } void StartAllTaskThreads(bool bDoBackgroundThreads) { @@ -1869,334 +1388,26 @@ public: } } - void StartTaskThreadFastMode(int32 Priority, int32 MyIndex) - { - check(Priority >= 0 && Priority < MAX_THREAD_PRIORITIES); - int32 LocalNumWorkingThread = GetNumWorkerThreads(); - while (true) - { - FAtomicStateBitfield LocalAtomicForConsoleApproachInner = AtomicForConsoleApproach[Priority]; - TestRandomizedThreads(); - check(MyIndex < 0 || !(LocalAtomicForConsoleApproachInner.Stalled & (1 << MyIndex))); // if I was stalled, I would not be here - int32 NumStalled = LocalAtomicForConsoleApproachInner.NumberOfStalledThreads(); - int32 NumSpinning = LocalNumWorkingThread - NumStalled - LocalAtomicForConsoleApproachInner.NumberOfWorkingThreads(); - - if (NumStalled) - { - uint32 IndexToStart = 31 - FMath::CountLeadingZeros((uint32)LocalAtomicForConsoleApproachInner.Stalled); - check(IndexToStart != MyIndex); - check(((uint32)LocalAtomicForConsoleApproachInner.Stalled) & (1 << IndexToStart)); - - FAtomicStateBitfield NewAtomicForConsoleApproachInner = LocalAtomicForConsoleApproachInner; - NewAtomicForConsoleApproachInner.Stalled = LocalAtomicForConsoleApproachInner.Stalled & ~(1 << IndexToStart); - check(!(((uint32)NewAtomicForConsoleApproachInner.Stalled) & (1 << IndexToStart))); - check(LocalAtomicForConsoleApproachInner != NewAtomicForConsoleApproachInner); - if (FAtomicStateBitfield::InterlockedCompareExchange(&AtomicForConsoleApproach[Priority], NewAtomicForConsoleApproachInner, LocalAtomicForConsoleApproachInner) == LocalAtomicForConsoleApproachInner) - { - TestRandomizedThreads(); - StartTaskThread(Priority, IndexToStart); - return; - } - } - else if (NumSpinning) - { - uint32 IndexToPreventStall = 31 - FMath::CountLeadingZeros(uint32((1 << FAtomicStateBitfield_MAX_THREADS) - 1) ^ uint32(LocalAtomicForConsoleApproachInner.Working | LocalAtomicForConsoleApproachInner.Stalled)); - check(IndexToPreventStall != MyIndex); - check(!(((uint32)LocalAtomicForConsoleApproachInner.Working) & (1 << IndexToPreventStall))); - check(!(((uint32)LocalAtomicForConsoleApproachInner.Stalled) & (1 << IndexToPreventStall))); - - FAtomicStateBitfield NewAtomicForConsoleApproachInner = LocalAtomicForConsoleApproachInner; - NewAtomicForConsoleApproachInner.Working = LocalAtomicForConsoleApproachInner.Working | (1 << IndexToPreventStall); - check((((uint32)NewAtomicForConsoleApproachInner.Working) & (1 << IndexToPreventStall))); - check(LocalAtomicForConsoleApproachInner != NewAtomicForConsoleApproachInner); - if (FAtomicStateBitfield::InterlockedCompareExchange(&AtomicForConsoleApproach[Priority], NewAtomicForConsoleApproachInner, LocalAtomicForConsoleApproachInner) == LocalAtomicForConsoleApproachInner) - { - // by changing it to working, it will be unable to stall without rechecking the queues - return; - } - } - else - { - return; - } - } - return; - } - - FORCEINLINE void SetWorking(int32 Priority, uint32 MyIndex, int32 LocalNumWorkingThread) - { - if (!GConsoleSpinModeLatched) - { - // we don't need to track the number of threads working or start threads when we take a job unless we are in spin mode - return; - } - while (true) - { - FAtomicStateBitfield LocalAtomicForConsoleApproachInner = AtomicForConsoleApproach[Priority]; - TestRandomizedThreads(); - check(!(LocalAtomicForConsoleApproachInner.Stalled & (1 << MyIndex))); // if I was stalled, I would not be here - check(!((LocalAtomicForConsoleApproachInner.Working) & (1 << MyIndex))); // I am already marked working - - FAtomicStateBitfield NewAtomicForConsoleApproachInner = LocalAtomicForConsoleApproachInner; - NewAtomicForConsoleApproachInner.Working = LocalAtomicForConsoleApproachInner.Working | (1 << MyIndex); - int32 NumStalled = LocalAtomicForConsoleApproachInner.NumberOfStalledThreads(); - int32 NumSpinning = LocalNumWorkingThread - NumStalled - NewAtomicForConsoleApproachInner.NumberOfWorkingThreads(); - - // we are going to do work, so if everyone else is either working or stalled, we need to start a thread - if (NumStalled && !NumSpinning) - { - // start one while we flip ourselves to working. - check(LocalAtomicForConsoleApproachInner.Stalled); - - uint32 IndexToStart = 31 - FMath::CountLeadingZeros((uint32)LocalAtomicForConsoleApproachInner.Stalled); - check(IndexToStart != MyIndex); - check(((uint32)LocalAtomicForConsoleApproachInner.Stalled) & (1 << IndexToStart)); - - NewAtomicForConsoleApproachInner.Stalled = LocalAtomicForConsoleApproachInner.Stalled & ~(1 << IndexToStart); - - check(LocalAtomicForConsoleApproachInner != NewAtomicForConsoleApproachInner); - if (FAtomicStateBitfield::InterlockedCompareExchange(&AtomicForConsoleApproach[Priority], NewAtomicForConsoleApproachInner, LocalAtomicForConsoleApproachInner) == LocalAtomicForConsoleApproachInner) - { - TestRandomizedThreads(); - StartTaskThread(Priority, IndexToStart); - // if we have another stalled thread and it looks like there are more tasks, then start an extra thread to get fan-out on the thread starts -#if USE_NEW_LOCK_FREE_LISTS - if (GMaxTasksToStartOnDequeue > 1 && NumStalled > 1 && (!IncomingAnyThreadTasks[Priority].IsEmptyFast() || !IncomingAnyThreadTasksHiPri[Priority].IsEmptyFast())) - { - StartTaskThreadFastMode(Priority, MyIndex); - } -#endif - return; - } - } - else - { - // we don't need to wake anyone either because there are other unstalled idle threads or everyone is busy - check(LocalAtomicForConsoleApproachInner != NewAtomicForConsoleApproachInner); - if (FAtomicStateBitfield::InterlockedCompareExchange(&AtomicForConsoleApproach[Priority], NewAtomicForConsoleApproachInner, LocalAtomicForConsoleApproachInner) == LocalAtomicForConsoleApproachInner) - { - TestRandomizedThreads(); - return; - } - } - } - } -#if USE_NEW_LOCK_FREE_LISTS FBaseGraphTask* FindWork(ENamedThreads::Type ThreadInNeed) { - int32 LocalNumWorkingThread = GetNumWorkerThreads(); - uint32 MyIndex = (uint32(ThreadInNeed) - NumNamedThreads) % NumTaskThreadsPerSet; - int32 Priority = (uint32(ThreadInNeed) - NumNamedThreads) / NumTaskThreadsPerSet; - check(MyIndex >= 0 && (int32)MyIndex < LocalNumWorkingThread && - LocalNumWorkingThread <= FAtomicStateBitfield_MAX_THREADS); // this is an atomic on 32 bits currently; we use two fields - check(Priority >= 0 && Priority < ENamedThreads::NumThreadPriorities); - bool bDoSpinMode = !!GConsoleSpinModeLatched && Priority != (ENamedThreads::BackgroundThreadPriority >> ENamedThreads::ThreadPriorityShift); - while (true) - { - if (!GFastSchedulerLatched) - { - return nullptr; - } - FAtomicStateBitfield LocalAtomicForConsoleApproachInner = AtomicForConsoleApproach[Priority]; - TestRandomizedThreads(); - check(!(LocalAtomicForConsoleApproachInner.Stalled & (1 << MyIndex))); // if I was stalled, I would not be here - bool CurrentlyWorking = !!((LocalAtomicForConsoleApproachInner.Working) & (1 << MyIndex)); + int32 LocalNumWorkingThread = GetNumWorkerThreads() + GNumWorkerThreadsToIgnore; + int32 MyIndex = int32((uint32(ThreadInNeed) - NumNamedThreads) % NumTaskThreadsPerSet); + int32 Priority = int32((uint32(ThreadInNeed) - NumNamedThreads) / NumTaskThreadsPerSet); + check(MyIndex >= 0 && MyIndex < LocalNumWorkingThread && + MyIndex < (PLATFORM_64BITS ? 63 : 32) && + Priority >= 0 && Priority < ENamedThreads::NumThreadPriorities); - { - FBaseGraphTask* Task = IncomingAnyThreadTasksHiPri[Priority].Pop(CurrentlyWorking); // if we are marked working, this is still preliminary so we do a faster pop - if (!Task) - { - Task = IncomingAnyThreadTasks[Priority].Pop(CurrentlyWorking); // if we are marked working, this is still preliminary so we do a faster pop - } - if (Task) - { - if (!CurrentlyWorking) - { - SetWorking(Priority, MyIndex, LocalNumWorkingThread); - } - return Task; - } - } - - TestRandomizedThreads(); - - if (CurrentlyWorking) - { - FAtomicStateBitfield NewAtomicForConsoleApproachInner = LocalAtomicForConsoleApproachInner; - NewAtomicForConsoleApproachInner.Working = NewAtomicForConsoleApproachInner.Working & ~(1 << MyIndex); - - check(LocalAtomicForConsoleApproachInner != NewAtomicForConsoleApproachInner); - FAtomicStateBitfield::InterlockedCompareExchange(&AtomicForConsoleApproach[Priority], NewAtomicForConsoleApproachInner, LocalAtomicForConsoleApproachInner); - } - else - { - int32 NumSpinning = LocalNumWorkingThread - LocalAtomicForConsoleApproachInner.NumberOfStalledThreads() - LocalAtomicForConsoleApproachInner.NumberOfWorkingThreads(); - bool bAttemptStall = (!bDoSpinMode || NumSpinning > 1); - if (bAttemptStall) - { - FBaseGraphTask* Task = IncomingAnyThreadTasksHiPri[Priority].Pop(); - if (!Task) - { - Task = IncomingAnyThreadTasks[Priority].Pop(); - } - if (Task) - { - SetWorking(Priority, MyIndex, LocalNumWorkingThread); - return Task; - } - FAtomicStateBitfield NewAtomicForConsoleApproachInner = LocalAtomicForConsoleApproachInner; - NewAtomicForConsoleApproachInner.Stalled = LocalAtomicForConsoleApproachInner.Stalled | (1 << MyIndex); - check((((uint32)NewAtomicForConsoleApproachInner.Stalled) & (1 << MyIndex))); - - check(LocalAtomicForConsoleApproachInner != NewAtomicForConsoleApproachInner); - if (FAtomicStateBitfield::InterlockedCompareExchange(&AtomicForConsoleApproach[Priority], NewAtomicForConsoleApproachInner, LocalAtomicForConsoleApproachInner) == LocalAtomicForConsoleApproachInner) - { - TestRandomizedThreads(); - return nullptr; // we did stall - } - - } - else if (GConsoleSpinModeLatched == 2) - { - FPlatformProcess::SleepNoStats(0.0f); - } - } - } + return IncomingAnyThreadTasks[Priority].Pop(MyIndex, true); } -#else - // API used by FWorkerThread's - /** - * @param ThreadInNeed; Id of the thread requesting work. - * @return Task that was stolen if any was found. - **/ - FBaseGraphTask* FindWork(ENamedThreads::Type ThreadInNeed) + void StallForTuning(int32 Index, bool Stall) { - int32 LocalNumWorkingThread = GetNumWorkerThreads(); - uint32 MyIndex = (uint32(ThreadInNeed) - NumNamedThreads) % NumTaskThreadsPerSet; - int32 Priority = (uint32(ThreadInNeed) - NumNamedThreads) / NumTaskThreadsPerSet; - check(MyIndex >= 0 && (int32)MyIndex < LocalNumWorkingThread); - check(Priority >= 0 && Priority < ENamedThreads::NumThreadPriorities && - (ENamedThreads::bHasHighPriorityThreads || (Priority << ENamedThreads::ThreadPriorityShift) != ENamedThreads::HighThreadPriority) && - (ENamedThreads::bHasBackgroundThreads || (Priority << ENamedThreads::ThreadPriorityShift) != ENamedThreads::BackgroundThreadPriority) - ); - TestRandomizedThreads(); - check(!GFastSchedulerLatched); // the fast scheduler is no longer supported without the new lock free lists. + for (int32 Priority = 0; Priority < ENamedThreads::NumThreadPriorities; Priority++) { - FBaseGraphTask* Task = SortedAnyThreadTasksHiPri[Priority].Pop(); - if (Task) - { - return Task; - } - } - if (!IncomingAnyThreadTasksHiPri[Priority].IsEmpty()) - { - do - { - FScopeLock ScopeLock(&CriticalSectionForSortingIncomingAnyThreadTasksHiPri[Priority]); - if (GFastSchedulerLatched) - { - return nullptr; - } - if (!IncomingAnyThreadTasksHiPri[Priority].IsEmpty() && SortedAnyThreadTasksHiPri[Priority].IsEmpty()) - { - static TArray NewTasks; - NewTasks.Reset(); - IncomingAnyThreadTasksHiPri[Priority].PopAll(NewTasks); - check(NewTasks.Num()); - - if (NewTasks.Num() > 1) - { - TLockFreePointerListLIFO TempSortedAnyThreadTasks; - for (int32 Index = 0 ; Index < NewTasks.Num() - 1; Index++) // we are going to take the last one for ourselves - { - TempSortedAnyThreadTasks.Push(NewTasks[Index]); - } - verify(SortedAnyThreadTasksHiPri[Priority].ReplaceListIfEmpty(TempSortedAnyThreadTasks)); - } - return NewTasks[NewTasks.Num() - 1]; - } - { - FBaseGraphTask* Task = SortedAnyThreadTasksHiPri[Priority].Pop(); - if (Task) - { - return Task; - } - } - } while (!IncomingAnyThreadTasksHiPri[Priority].IsEmpty() || !SortedAnyThreadTasksHiPri[Priority].IsEmpty()); - } - { - FBaseGraphTask* Task = SortedAnyThreadTasks[Priority].Pop(); - if (Task) - { - return Task; - } - } - do - { - FScopeLock ScopeLock(&CriticalSectionForSortingIncomingAnyThreadTasks[Priority]); - if (GFastSchedulerLatched) - { - return nullptr; - } - if (!IncomingAnyThreadTasks[Priority].IsEmpty() && SortedAnyThreadTasks[Priority].IsEmpty()) - { - struct FPadArray - { - uint8 Pad1[PLATFORM_CACHE_LINE_SIZE / 2]; - TArray NewTaskArray; - uint8 Pad2[PLATFORM_CACHE_LINE_SIZE / 2]; - }; - static FPadArray PrioTasks[MAX_THREAD_PRIORITIES]; - TArray& NewTasks = PrioTasks[Priority].NewTaskArray; - NewTasks.Reset(); - IncomingAnyThreadTasks[Priority].PopAll(NewTasks); - check(NewTasks.Num()); - - if (NewTasks.Num() > 1) - { - TLockFreePointerListLIFO TempSortedAnyThreadTasks; - for (int32 Index = 0; Index < NewTasks.Num() - 1; Index++) // we are going to take the last one for ourselves - { - TempSortedAnyThreadTasks.Push(NewTasks[Index]); - } - verify(SortedAnyThreadTasks[Priority].ReplaceListIfEmpty(TempSortedAnyThreadTasks)); - } - return NewTasks[NewTasks.Num() - 1]; - } - { - FBaseGraphTask* Task = SortedAnyThreadTasks[Priority].Pop(); - if (Task) - { - return Task; - } - } - } while (!IncomingAnyThreadTasks[Priority].IsEmpty() || !SortedAnyThreadTasks[Priority].IsEmpty()); - return nullptr; - } - -#endif - - /** - * Hint from a worker thread that it is stalling. - * @param StallingThread; Id of the thread that is stalling. - **/ - void NotifyStalling(ENamedThreads::Type StallingThread) - { - if (StallingThread >= NumNamedThreads && !GFastSchedulerLatched) - { - int32 LocalNumWorkingThread = GetNumWorkerThreads(); - uint32 MyIndex = (uint32(StallingThread) - NumNamedThreads) % NumTaskThreadsPerSet; - int32 Priority = (uint32(StallingThread) - NumNamedThreads) / NumTaskThreadsPerSet; - check(MyIndex >= 0 && (int32)MyIndex < LocalNumWorkingThread); - check(Priority >= 0 && Priority < ENamedThreads::NumThreadPriorities && - (ENamedThreads::bHasHighPriorityThreads || (Priority << ENamedThreads::ThreadPriorityShift) != ENamedThreads::HighThreadPriority) && - (ENamedThreads::bHasBackgroundThreads || (Priority << ENamedThreads::ThreadPriorityShift) != ENamedThreads::BackgroundThreadPriority) - ); - StalledUnnamedThreads[Priority].Push(&Thread(StallingThread)); + ENamedThreads::Type ThreadToWake = ENamedThreads::Type(Index + Priority * NumTaskThreadsPerSet + NumNamedThreads); + ((FTaskThreadAnyThread&)Thread(ThreadToWake)).StallForTuning(Stall); } } - void SetTaskThreadPriorities(EThreadPriority Pri) { check(NumTaskThreadSets == 1); // otherwise tuning this doesn't make a lot of sense @@ -2263,8 +1474,8 @@ private: enum { - /** Compile time maximum number of threads. @todo Didn't really need to be a compile time constant. **/ - MAX_THREADS=24, + /** Compile time maximum number of threads. Didn't really need to be a compile time constant, but task thread are limited by MAX_LOCK_FREE_LINKS_AS_BITS **/ + MAX_THREADS = 22 * (CREATE_HIPRI_TASK_THREADS + CREATE_BACKGROUND_TASK_THREADS + 1) + ENamedThreads::ActualRenderingThread + 1, MAX_THREAD_PRIORITIES = 3 }; @@ -2286,136 +1497,14 @@ private: * All unnamed threads must be internal **/ ENamedThreads::Type LastExternalThread; - /** Counter used to distribute new jobs to "any thread". **/ - FThreadSafeCounter NextUnnamedThreadForTaskFromUnknownThread[MAX_THREAD_PRIORITIES]; FThreadSafeCounter ReentrancyCheck; /** Index of TLS slot for FWorkerThread* pointer. **/ uint32 PerThreadIDTLSSlot; - /** Thread safe list of stalled thread "Hints". **/ - TLockFreePointerListUnordered StalledUnnamedThreads[MAX_THREAD_PRIORITIES]; /** Array of callbacks to call before shutdown. **/ TArray > ShutdownCallbacks; -#if USE_NEW_LOCK_FREE_LISTS -#if USE_INTRUSIVE_TASKQUEUES - FLockFreePointerListFIFOIntrusive IncomingAnyThreadTasks[MAX_THREAD_PRIORITIES]; - FLockFreePointerListFIFOIntrusive IncomingAnyThreadTasksHiPri[MAX_THREAD_PRIORITIES]; - #else - TLockFreePointerListFIFO IncomingAnyThreadTasks[MAX_THREAD_PRIORITIES]; - TLockFreePointerListFIFO IncomingAnyThreadTasksHiPri[MAX_THREAD_PRIORITIES]; - #endif -#else - TLockFreePointerListLIFO IncomingAnyThreadTasks[MAX_THREAD_PRIORITIES]; - TLockFreePointerListLIFO IncomingAnyThreadTasksHiPri[MAX_THREAD_PRIORITIES]; - TLockFreePointerListLIFO SortedAnyThreadTasks[MAX_THREAD_PRIORITIES]; - TLockFreePointerListLIFO SortedAnyThreadTasksHiPri[MAX_THREAD_PRIORITIES]; -#endif - FCriticalSection CriticalSectionForSortingIncomingAnyThreadTasks[MAX_THREAD_PRIORITIES]; - FCriticalSection CriticalSectionForSortingIncomingAnyThreadTasksHiPri[MAX_THREAD_PRIORITIES]; - - // we use a single atomic to control the state of the anythread queues. This limits the maximum number of threads. - struct FAtomicStateBitfield - { -#if !USE_NEW_LOCK_FREE_LISTS - uint32 QueueOwned: 1; - uint32 QueueOwnerIndex: 4; -#endif - uint32 Stalled : FAtomicStateBitfield_MAX_THREADS; - uint32 Working: FAtomicStateBitfield_MAX_THREADS; - - uint32 Unused; - uint8 PadToAvoidContention[PLATFORM_CACHE_LINE_SIZE - 2 * sizeof(uint32)]; - - FAtomicStateBitfield() - : -#if !USE_NEW_LOCK_FREE_LISTS - QueueOwned(false) - , QueueOwnerIndex(0) , -#endif - Stalled(0) - , Working(0) - { - static_assert(offsetof(FAtomicStateBitfield, Unused) == sizeof(uint32), "The bitfields in FAtomicStateBitfield must fit into a single uint32 and be the first member"); - } - - static FORCEINLINE FAtomicStateBitfield InterlockedCompareExchange(FAtomicStateBitfield* Dest, FAtomicStateBitfield Exchange, FAtomicStateBitfield Comparand) - { - FAtomicStateBitfield Result; - *(int32*)&Result = FPlatformAtomics::InterlockedCompareExchange((volatile int32*)Dest, *(int32*)&Exchange, *(int32*)&Comparand); - return Result; - } - - static int32 CountBits(uint32 Bits) - { - MS_ALIGN(64) static uint8 Table[64] GCC_ALIGN(64) = {0}; - if (!Table[63]) - { - for (uint32 Index = 0; Index < 63; Index++) - { - uint32 LocalIndex = Index; - uint8 Result = 0; - while (LocalIndex) - { - if (LocalIndex & 1) - { - Result++; - } - LocalIndex >>= 1; - } - Table[Index] = Result; - } - FPlatformMisc::MemoryBarrier(); - Table[63] = 6; - } - int32 Count = 0; - while (true) - { - Count += Table[Bits & 63]; - if (!(Bits & ~63)) - { - break; - } - Bits >>= 6; - } - return Count; - } - - FORCEINLINE int32 NumberOfStalledThreads() - { - return CountBits(Stalled); - } - - FORCEINLINE int32 NumberOfWorkingThreads() - { - return CountBits(Working); - } - - bool operator==(FAtomicStateBitfield Other) const - { - return -#if !USE_NEW_LOCK_FREE_LISTS - QueueOwned == Other.QueueOwned && - QueueOwnerIndex == Other.QueueOwnerIndex && -#endif - Stalled == Other.Stalled && - Working == Other.Working; - } - - bool operator!=(FAtomicStateBitfield Other) const - { - return -#if !USE_NEW_LOCK_FREE_LISTS - QueueOwned != Other.QueueOwned || - QueueOwnerIndex != Other.QueueOwnerIndex || -#endif - Stalled != Other.Stalled || - Working != Other.Working; - } - }; - - uint8 PadToAvoidContention6[PLATFORM_CACHE_LINE_SIZE]; - FAtomicStateBitfield AtomicForConsoleApproach[MAX_THREAD_PRIORITIES]; + FStallingTaskQueue IncomingAnyThreadTasks[MAX_THREAD_PRIORITIES]; }; @@ -2426,12 +1515,6 @@ FBaseGraphTask* FTaskThreadAnyThread::FindWork() return FTaskGraphImplementation::Get().FindWork(ThreadId); } -void FTaskThreadAnyThread::NotifyStalling() -{ - return FTaskGraphImplementation::Get().NotifyStalling(ThreadId); -} - - // Statics in FTaskGraphInterface @@ -2474,148 +1557,6 @@ void FBaseGraphTask::LogPossiblyInvalidSubsequentsTask(const TCHAR* TaskName) } #endif -#if USE_NEW_LOCK_FREE_LISTS - -#define USE_TLS_FOR_EVENTS (1) - -#define MONITOR_TASK_ALLOCATION (0) - -#if MONITOR_TASK_ALLOCATION==1 - typedef FThreadSafeCounter FTaskLockFreeListCounter; -#else - typedef FNoopCounter FTaskLockFreeListCounter; -#endif - -static FTaskLockFreeListCounter GraphEventsInUse; -static FTaskLockFreeListCounter GraphEventsWithInlineStorageInUse; - -#if USE_TLS_FOR_EVENTS - -static TPointerSet_TLSCacheBase, FTaskLockFreeListCounter> TheGraphEventAllocator; -static TPointerSet_TLSCacheBase, FTaskLockFreeListCounter> TheGraphEventWithInlineStorageAllocator; - -static FThreadSafeCounter GraphEventsAllocated; -static FThreadSafeCounter GraphEventsWithInlineStorageAllocated; - -FGraphEvent* FGraphEvent::GetBundle(int32 NumBundle) -{ - GraphEventsAllocated.Add(NumBundle); - FGraphEvent* Root = nullptr; - uint8* Block = (uint8*)FMemory::Malloc(NumBundle * sizeof(FGraphEvent)); - for (int32 Index = 0; Index < NumBundle; Index++) - { - FGraphEvent* Event = new ((void*)Block) FGraphEvent(false); - Event->LockFreePointerQueueNext = Root; - Root = Event; - Block += sizeof(FGraphEvent); - } - return Root; -} - -FGraphEventAndSmallTaskStorage* FGraphEventAndSmallTaskStorage::GetBundle(int32 NumBundle) -{ - GraphEventsWithInlineStorageAllocated.Add(NumBundle); - FGraphEventAndSmallTaskStorage* Root = nullptr; - uint8* Block = (uint8*)FMemory::Malloc(NumBundle * sizeof(FGraphEventAndSmallTaskStorage)); - for (int32 Index = 0; Index < NumBundle; Index++) - { - FGraphEventAndSmallTaskStorage* Event = new ((void*)Block) FGraphEventAndSmallTaskStorage(); - Event->LockFreePointerQueueNext = Root; - Root = Event; - Block += sizeof(FGraphEventAndSmallTaskStorage); - } - return Root; -} - -#else -static FLockFreePointerListFIFOIntrusive TheGraphEventAllocator; -static FLockFreePointerListFIFOIntrusive TheGraphEventWithInlineStorageAllocator; - -#endif - -#define USE_NIEVE_GRAPH_EVENT_ALLOCTOR (0) // this is useful for tracking leaked handles - -FGraphEventRef FGraphEvent::CreateGraphEvent() -{ - GraphEventsInUse.Increment(); -#if !USE_NIEVE_GRAPH_EVENT_ALLOCTOR - FGraphEvent* Used = TheGraphEventAllocator.Pop(); - if (Used) - { - FPlatformMisc::MemoryBarrier(); - checkThreadGraph(!Used->SubsequentList.IsClosed()); - checkThreadGraph(Used->ReferenceCount.GetValue() == 0); - checkThreadGraph(!Used->EventsToWaitFor.Num()); - checkThreadGraph(!Used->bComplete); - checkThreadGraph(!Used->bInline); -// Used->ReferenceCount.Reset(); // temp -// Used->LockFreePointerQueueNext = nullptr; // temp - return FGraphEventRef(Used); - } -#endif - return FGraphEventRef(new FGraphEvent(false)); -} - -FGraphEvent* FGraphEvent::CreateGraphEventWithInlineStorage() -{ - GraphEventsWithInlineStorageInUse.Increment(); - FGraphEventAndSmallTaskStorage* Used; -#if !USE_NIEVE_GRAPH_EVENT_ALLOCTOR - Used = TheGraphEventWithInlineStorageAllocator.Pop(); - if (Used) - { - FPlatformMisc::MemoryBarrier(); - checkThreadGraph(!Used->SubsequentList.IsClosed()); - checkThreadGraph(Used->ReferenceCount.GetValue() == 0); - checkThreadGraph(!Used->EventsToWaitFor.Num()); - checkThreadGraph(!Used->bComplete); - checkThreadGraph(Used->bInline); - } - else -#endif - { - Used = new FGraphEventAndSmallTaskStorage(); - } - checkThreadGraph(Used->bInline); - return Used; -} - - -void FGraphEvent::Recycle(FGraphEvent* ToRecycle) -{ - ToRecycle->Reset(); - if (ToRecycle->bInline) - { - GraphEventsWithInlineStorageInUse.Decrement(); -#if USE_NIEVE_GRAPH_EVENT_ALLOCTOR - delete ToRecycle; -#else - TheGraphEventWithInlineStorageAllocator.Push((FGraphEventAndSmallTaskStorage*)ToRecycle); -#endif - } - else - { - GraphEventsInUse.Decrement(); -#if USE_NIEVE_GRAPH_EVENT_ALLOCTOR - delete ToRecycle; -#else - TheGraphEventAllocator.Push(ToRecycle); -#endif - } -} - - -void FGraphEvent::Reset() -{ -// ReferenceCount.Set(-5); // temp - SubsequentList.Reset(); - checkThreadGraph(!SubsequentList.Pop()); - EventsToWaitFor.Empty(); // we will let the memory block free here if there is one; these are not common - // checkThreadGraph(!LockFreePointerQueueNext); // temp - bComplete= false; -} - -#else static TLockFreeClassAllocator_TLSCache TheGraphEventAllocator; FGraphEventRef FGraphEvent::CreateGraphEvent() @@ -2627,7 +1568,6 @@ void FGraphEvent::Recycle(FGraphEvent* ToRecycle) { TheGraphEventAllocator.Free(ToRecycle); } -#endif void FGraphEvent::DispatchSubsequents(TArray& NewTasks, ENamedThreads::Type CurrentThreadIfKnown) { @@ -2645,24 +1585,6 @@ void FGraphEvent::DispatchSubsequents(TArray& NewTasks, ENamedT return; } -#if USE_NEW_LOCK_FREE_LISTS - bComplete = true; - int32 SpinCount = 0; - while (true) - { - FBaseGraphTask* NewTask = SubsequentList.Pop(); - if (!NewTask) - { - if (SubsequentList.CloseIfEmpty()) - { - break; - } - LockFreeCriticalSpin(SpinCount); - continue; - } - NewTask->ConditionalQueueTask(CurrentThreadIfKnown); - } -#else SubsequentList.PopAllAndClose(NewTasks); for (int32 Index = NewTasks.Num() - 1; Index >= 0 ; Index--) // reverse the order since PopAll is implicitly backwards { @@ -2671,7 +1593,6 @@ void FGraphEvent::DispatchSubsequents(TArray& NewTasks, ENamedT NewTask->ConditionalQueueTask(CurrentThreadIfKnown); } NewTasks.Reset(); -#endif } FGraphEvent::~FGraphEvent() @@ -2679,14 +1600,7 @@ FGraphEvent::~FGraphEvent() #if DO_CHECK if (!IsComplete()) { -#if USE_NEW_LOCK_FREE_LISTS - checkThreadGraph(!SubsequentList.Pop()); -#else - // Verifies that the event is completed. We do not allow events to die before completion. - TArray NewTasks; - SubsequentList.PopAllAndClose(NewTasks); - checkThreadGraph(!NewTasks.Num()); -#endif + check(SubsequentList.IsClosed()); } #endif CheckDontCompleteUntilIsEmpty(); // We should not have any wait untils outstanding @@ -2755,13 +1669,12 @@ void FTaskGraphInterface::BroadcastSlow_OnlyUseForSpecialPurposes(bool bDoTaskTh FEvent* MyEvent = nullptr; FGraphEventArray TaskThreadTasks; + FThreadSafeCounter StallForTaskThread; if (bDoTaskThreads) { MyEvent = FPlatformProcess::GetSynchEventFromPool(false); - FThreadSafeCounter StallForTaskThread; int32 Workers = FTaskGraphInterface::Get().GetNumWorkerThreads(); - StallForTaskThread.Reset(); StallForTaskThread.Add(Workers * (1 + (bDoBackgroundThreads && ENamedThreads::bHasBackgroundThreads) + !!(ENamedThreads::bHasHighPriorityThreads))); TaskEvents.Reserve(StallForTaskThread.GetValue()); @@ -2794,13 +1707,12 @@ void FTaskGraphInterface::BroadcastSlow_OnlyUseForSpecialPurposes(bool bDoTaskTh } } check(TaskGraphImplementationSingleton); - check(USE_NEW_LOCK_FREE_LISTS); } FGraphEventArray Tasks; STAT(Tasks.Add(TGraphTask::CreateTask().ConstructAndDispatchWhenReady(Callback, ENamedThreads::SetTaskPriority(ENamedThreads::StatsThread, ENamedThreads::HighTaskPriority), nullptr, nullptr, nullptr));); - if (GRHIThread) + if (GRHIThread_InternalUseOnly) { Tasks.Add(TGraphTask::CreateTask().ConstructAndDispatchWhenReady(Callback, ENamedThreads::SetTaskPriority(ENamedThreads::RHIThread, ENamedThreads::HighTaskPriority), nullptr, nullptr, nullptr)); } @@ -2811,25 +1723,61 @@ void FTaskGraphInterface::BroadcastSlow_OnlyUseForSpecialPurposes(bool bDoTaskTh Tasks.Add(TGraphTask::CreateTask().ConstructAndDispatchWhenReady(Callback, ENamedThreads::GameThread_Local, nullptr, nullptr, nullptr)); if (bDoTaskThreads) { - if (!MyEvent->Wait(3000)) + check(MyEvent); + if (MyEvent && !MyEvent->Wait(3000)) { - UE_LOG(LogTaskGraph, Error, TEXT("FTaskGraphInterface::BroadcastSlow_OnlyUseForSpecialPurposes Broadcast failed after three seconds")); + UE_LOG(LogTaskGraph, Log, TEXT("FTaskGraphInterface::BroadcastSlow_OnlyUseForSpecialPurposes Broadcast failed after three seconds. Ok during automated tests.")); } for (FEvent* TaskEvent : TaskEvents) { TaskEvent->Trigger(); } FTaskGraphInterface::Get().WaitUntilTasksComplete(TaskThreadTasks, ENamedThreads::GameThread_Local); - for (FEvent* TaskEvent : TaskEvents) - { - FPlatformProcess::ReturnSynchEventToPool(TaskEvent); - } - FTaskGraphInterface::Get().WaitUntilTasksComplete(Tasks, ENamedThreads::GameThread_Local); + } + FTaskGraphInterface::Get().WaitUntilTasksComplete(Tasks, ENamedThreads::GameThread_Local); + for (FEvent* TaskEvent : TaskEvents) + { + FPlatformProcess::ReturnSynchEventToPool(TaskEvent); + } + if (MyEvent) + { FPlatformProcess::ReturnSynchEventToPool(MyEvent); } } +static void HandleNumWorkerThreadsToIgnore(const TArray& Args) +{ + if (Args.Num() > 0) + { + int32 Arg = FCString::Atoi(*Args[0]); + int32 MaxNumPerBank = FTaskGraphInterface::Get().GetNumWorkerThreads() + GNumWorkerThreadsToIgnore; + if (Arg < MaxNumPerBank && Arg >= 0 && Arg != GNumWorkerThreadsToIgnore) + { + if (Arg > GNumWorkerThreadsToIgnore) + { + for (int32 Index = MaxNumPerBank - GNumWorkerThreadsToIgnore - 1; Index >= MaxNumPerBank - Arg; Index--) + { + FTaskGraphImplementation::Get().StallForTuning(Index, true); + } + } + else + { + for (int32 Index = MaxNumPerBank - Arg - 1; Index >= MaxNumPerBank - GNumWorkerThreadsToIgnore; Index--) + { + FTaskGraphImplementation::Get().StallForTuning(Index, false); + } + } + GNumWorkerThreadsToIgnore = Arg; + } + } + UE_LOG(LogConsoleResponse, Display, TEXT("Currently ignoring %d threads per priority bank"), GNumWorkerThreadsToIgnore); +} +static FAutoConsoleCommand CVarNumWorkerThreadsToIgnore( + TEXT("TaskGraph.NumWorkerThreadsToIgnore"), + TEXT("Used to tune the number of task threads. Generally once you have found the right value, PlatformMisc::NumberOfWorkerThreadsToSpawn() should be hardcoded."), + FConsoleCommandWithArgsDelegate::CreateStatic(&HandleNumWorkerThreadsToIgnore) + ); // Benchmark @@ -2880,6 +1828,32 @@ private: int32 Work; }; +class FIncGraphTaskSub : public FCustomStatIDGraphTaskBase +{ +public: + FORCEINLINE FIncGraphTaskSub(FThreadSafeCounter& InCounter, FThreadSafeCounter& InCycles, int32 InWork) + : FCustomStatIDGraphTaskBase(TStatId()) + , Counter(InCounter) + , Cycles(InCycles) + , Work(InWork) + { + } + static FORCEINLINE ENamedThreads::Type GetDesiredThread() + { + return ENamedThreads::AnyThread; + } + + static FORCEINLINE ESubsequentsMode::Type GetSubsequentsMode() { return ESubsequentsMode::TrackSubsequents; } + void FORCEINLINE DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent) + { + DoWork(this, Counter, Cycles, Work); + } +private: + FThreadSafeCounter& Counter; + FThreadSafeCounter& Cycles; + int32 Work; +}; + class FIncGraphTaskGT : public FIncGraphTask { public: @@ -2933,6 +1907,7 @@ void PrintResult(double& StartTime, double& QueueTime, double& EndTime, double& static void TaskGraphBenchmark(const TArray& Args) { + FSlowHeartBeatScope SuspendHeartBeat; double StartTime, QueueTime, EndTime, JoinTime; FThreadSafeCounter Counter; FThreadSafeCounter Cycles; @@ -2972,6 +1947,21 @@ static void TaskGraphBenchmark(const TArray& Args) EndTime = FPlatformTime::Seconds(); } PrintResult(StartTime, QueueTime, EndTime, JoinTime, Counter, Cycles, TEXT("1000 tasks, ordinary GT start")); + { + StartTime = FPlatformTime::Seconds(); + FGraphEventArray Tasks; + Tasks.Reserve(1000); + for (int32 Index = 0; Index < 1000; Index++) + { + Tasks.Emplace(TGraphTask::CreateTask(nullptr, ENamedThreads::GameThread).ConstructAndDispatchWhenReady(Counter, Cycles, 1000)); + } + QueueTime = FPlatformTime::Seconds(); + FGraphEventRef Join = TGraphTask::CreateTask(&Tasks, ENamedThreads::GameThread).ConstructAndDispatchWhenReady(TStatId(), ENamedThreads::AnyThread); + JoinTime = FPlatformTime::Seconds(); + FTaskGraphInterface::Get().WaitUntilTaskCompletes(Join, ENamedThreads::GameThread_Local); + EndTime = FPlatformTime::Seconds(); + } + PrintResult(StartTime, QueueTime, EndTime, JoinTime, Counter, Cycles, TEXT("1000 tasks, ordinary GT start, with work")); { StartTime = FPlatformTime::Seconds(); FGraphEventArray Tasks; @@ -3120,7 +2110,6 @@ static void TaskGraphBenchmark(const TArray& Args) EndTime = FPlatformTime::Seconds(); } PrintResult(StartTime, QueueTime, EndTime, JoinTime, Counter, Cycles, TEXT("1000 tasks, GT submit, counter tracking, with work")); - { StartTime = FPlatformTime::Seconds(); @@ -3187,6 +2176,311 @@ static FAutoConsoleCommand TaskGraphBenchmarkCmd( FConsoleCommandWithArgsDelegate::CreateStatic(&TaskGraphBenchmark) ); + +struct FTestStruct +{ + int32 Index; + int32 Constant; + FTestStruct(int32 InIndex) + : Index(InIndex) + , Constant(0xfe05abcd) + { + } +}; + +struct FTestRigFIFO +{ + FLockFreePointerFIFOBase Test1; + FLockFreePointerFIFOBase Test2; + FLockFreePointerFIFOBase Test3; +}; + +struct FTestRigLIFO +{ + FLockFreePointerListLIFOBase Test1; + FLockFreePointerListLIFOBase Test2; + FLockFreePointerListLIFOBase Test3; +}; + +static void TestLockFree(int32 OuterIters = 3) +{ + FSlowHeartBeatScope SuspendHeartBeat; + + for (int32 Iter = 0; Iter < OuterIters; Iter++) + { + { + UE_LOG(LogTemp, Display, TEXT("******************************* Iter FIFO %d"), Iter); + FTestRigFIFO Rig; + for (int32 Index = 0; Index < 1000; Index++) + { + Rig.Test1.Push(new FTestStruct(Index)); + } + TFunction Broadcast = + [&Rig](ENamedThreads::Type MyThread) + { + FRandomStream Stream(((int32)MyThread) * 7 + 13); + for (int32 Index = 0; Index < 1000000; Index++) + { + if (Index % 200000 == 1) + { + //UE_LOG(LogTemp, Log, TEXT("%8d iters thread=%d"), Index, int32(MyThread)); + } + if (Stream.FRand() < .03f) + { + TArray Items; + { + float r = Stream.FRand(); + if (r < .33f) + { + Rig.Test1.PopAll(Items); + } + else if (r < .66f) + { + Rig.Test2.PopAll(Items); + } + else + { + Rig.Test3.PopAll(Items); + } + } + for (FTestStruct* Item : Items) + { + float r = Stream.FRand(); + if (r < .33f) + { + Rig.Test1.Push(Item); + } + else if (r < .66f) + { + Rig.Test2.Push(Item); + } + else + { + Rig.Test3.Push(Item); + } + } + } + else + { + FTestStruct* Item; + { + float r = Stream.FRand(); + if (r < .33f) + { + Item = Rig.Test1.Pop(); + } + else if (r < .66f) + { + Item = Rig.Test2.Pop(); + } + else + { + Item = Rig.Test3.Pop(); + } + } + if (Item) + { + float r = Stream.FRand(); + if (r < .33f) + { + Rig.Test1.Push(Item); + } + else if (r < .66f) + { + Rig.Test2.Push(Item); + } + else + { + Rig.Test3.Push(Item); + } + } + } + } + }; + FTaskGraphInterface::BroadcastSlow_OnlyUseForSpecialPurposes(true, false, Broadcast); + + TArray Items; + Rig.Test1.PopAll(Items); + Rig.Test2.PopAll(Items); + Rig.Test3.PopAll(Items); + + checkf(Items.Num() == 1000, TEXT("Items %d"), Items.Num()); + + for (int32 LookFor = 0; LookFor < 1000; LookFor++) + { + bool bFound = false; + for (int32 Index = 0; Index < 1000; Index++) + { + if (Items[Index]->Index == LookFor && Items[Index]->Constant == 0xfe05abcd) + { + check(!bFound); + bFound = true; + } + } + check(bFound); + } + for (FTestStruct* Item : Items) + { + delete Item; + } + + UE_LOG(LogTemp, Display, TEXT("******************************* Pass FTestRigFIFO")); + + } + { + UE_LOG(LogTemp, Display, TEXT("******************************* Iter LIFO %d"), Iter); + FTestRigLIFO Rig; + for (int32 Index = 0; Index < 1000; Index++) + { + Rig.Test1.Push(new FTestStruct(Index)); + } + TFunction Broadcast = + [&Rig](ENamedThreads::Type MyThread) + { + FRandomStream Stream(((int32)MyThread) * 7 + 13); + for (int32 Index = 0; Index < 1000000; Index++) + { + if (Index % 200000 == 1) + { + //UE_LOG(LogTemp, Log, TEXT("%8d iters thread=%d"), Index, int32(MyThread)); + } + if (Stream.FRand() < .03f) + { + TArray Items; + { + float r = Stream.FRand(); + if (r < .33f) + { + Rig.Test1.PopAll(Items); + } + else if (r < .66f) + { + Rig.Test2.PopAll(Items); + } + else + { + Rig.Test3.PopAll(Items); + } + } + for (FTestStruct* Item : Items) + { + float r = Stream.FRand(); + if (r < .33f) + { + Rig.Test1.Push(Item); + } + else if (r < .66f) + { + Rig.Test2.Push(Item); + } + else + { + Rig.Test3.Push(Item); + } + } + } + else + { + FTestStruct* Item; + { + float r = Stream.FRand(); + if (r < .33f) + { + Item = Rig.Test1.Pop(); + } + else if (r < .66f) + { + Item = Rig.Test2.Pop(); + } + else + { + Item = Rig.Test3.Pop(); + } + } + if (Item) + { + float r = Stream.FRand(); + if (r < .33f) + { + Rig.Test1.Push(Item); + } + else if (r < .66f) + { + Rig.Test2.Push(Item); + } + else + { + Rig.Test3.Push(Item); + } + } + } + } + }; + FTaskGraphInterface::BroadcastSlow_OnlyUseForSpecialPurposes(true, false, Broadcast); + + TArray Items; + Rig.Test1.PopAll(Items); + Rig.Test2.PopAll(Items); + Rig.Test3.PopAll(Items); + + checkf(Items.Num() == 1000, TEXT("Items %d"), Items.Num()); + + for (int32 LookFor = 0; LookFor < 1000; LookFor++) + { + bool bFound = false; + for (int32 Index = 0; Index < 1000; Index++) + { + if (Items[Index]->Index == LookFor && Items[Index]->Constant == 0xfe05abcd) + { + check(!bFound); + bFound = true; + } + } + check(bFound); + } + for (FTestStruct* Item : Items) + { + delete Item; + } + + UE_LOG(LogTemp, Display, TEXT("******************************* Pass FTestRigLIFO")); + + } + } +} + +static void TestLockFree(const TArray& Args) +{ + TestLockFree(10); +} + +static FAutoConsoleCommand TestLockFreeCmd( + TEXT("TaskGraph.TestLockFree"), + TEXT("Test lock free lists"), + FConsoleCommandWithArgsDelegate::CreateStatic(&TestLockFree) + ); + +#if WITH_DEV_AUTOMATION_TESTS + +#include "Misc/AutomationTest.h" + +IMPLEMENT_SIMPLE_AUTOMATION_TEST(FMyTaskGraphTest, "System.Core.Misc.TaskGraph", EAutomationTestFlags::EditorContext | EAutomationTestFlags::ClientContext | EAutomationTestFlags::ServerContext | EAutomationTestFlags::EngineFilter) +bool FMyTaskGraphTest::RunTest(const FString& Parameters) +{ + TArray Args; + TaskGraphBenchmark(Args); + return true; +} + +IMPLEMENT_SIMPLE_AUTOMATION_TEST(FLockFreeTest, "System.Core.Misc.LockFree", EAutomationTestFlags::ApplicationContextMask | EAutomationTestFlags::EngineFilter) +bool FLockFreeTest::RunTest(const FString& Parameters) +{ + TestLockFree(3); + return true; +} + +#endif + static void SetTaskThreadPriority(const TArray& Args) { EThreadPriority Pri = TPri_Normal; diff --git a/Engine/Source/Runtime/Core/Private/Containers/Algo/AlgosTest.cpp b/Engine/Source/Runtime/Core/Private/Containers/Algo/AlgosTest.cpp index f739e88f0b2f..3451bca4078b 100644 --- a/Engine/Source/Runtime/Core/Private/Containers/Algo/AlgosTest.cpp +++ b/Engine/Source/Runtime/Core/Private/Containers/Algo/AlgosTest.cpp @@ -7,6 +7,10 @@ #include "Containers/UnrealString.h" #include "Misc/AutomationTest.h" #include "Containers/Algo/Copy.h" +#include "Containers/Algo/Heapify.h" +#include "Containers/Algo/HeapSort.h" +#include "Containers/Algo/IsHeap.h" +#include "Containers/Algo/IsSorted.h" #include "Containers/Algo/Transform.h" IMPLEMENT_SIMPLE_AUTOMATION_TEST(FAlgosTest, "System.Core.Misc.Algos", EAutomationTestFlags::ApplicationContextMask | EAutomationTestFlags::SmokeFilter) @@ -249,5 +253,53 @@ bool FAlgosTest::RunTest(const FString& Parameters) } } + // binary search + { + // Verify static array case + int StaticArray[] = { 2,4,6,6,6,8 }; + + check(Algo::BinarySearch(StaticArray, 6) == 2); + check(Algo::BinarySearch(StaticArray, 5) == INDEX_NONE); + + check(Algo::LowerBound(StaticArray, 6) == 2); + check(Algo::LowerBound(StaticArray, 5) == 2); + check(Algo::UpperBound(StaticArray, 6) == 5); + check(Algo::LowerBound(StaticArray, 7) == 5); + check(Algo::LowerBound(StaticArray, 9) == 6); + + // Dynamic array case + TArray IntArray = { 2,2,4,4,6,6,6,8,8 }; + + check(Algo::BinarySearch(IntArray, 6) == 4); + check(Algo::BinarySearch(IntArray, 5) == INDEX_NONE); + + check(Algo::LowerBound(IntArray, 2) == 0); + check(Algo::UpperBound(IntArray, 2) == 2); + check(Algo::LowerBound(IntArray, 6) == 4); + check(Algo::UpperBound(IntArray, 6) == 7); + check(Algo::LowerBound(IntArray, 5) == 4); + check(Algo::UpperBound(IntArray, 5) == 4); + check(Algo::LowerBound(IntArray, 7) == 7); + check(Algo::LowerBound(IntArray, 9) == 9); + } + + // heapify + { + TArray TestArray = TestData2; + Algo::Heapify(TestArray); + + check(Algo::IsHeap(TestArray)); + } + + // heap sort + { + TArray TestArray = TestData2; + Algo::HeapSort(TestArray); + + check(Algo::IsHeap(TestArray)); + + check(Algo::IsSorted(TestArray)); + } + return true; } diff --git a/Engine/Source/Runtime/Core/Private/Containers/ContainersTest.cpp b/Engine/Source/Runtime/Core/Private/Containers/ContainersTest.cpp index 65e5ae4b1ad5..43f149fe1f24 100644 --- a/Engine/Source/Runtime/Core/Private/Containers/ContainersTest.cpp +++ b/Engine/Source/Runtime/Core/Private/Containers/ContainersTest.cpp @@ -4,14 +4,15 @@ #include "Misc/AssertionMacros.h" #include "Containers/Array.h" #include "Containers/Map.h" +#include "Containers/SortedMap.h" +#include "Containers/ArrayView.h" #include "Misc/AutomationTest.h" - - -IMPLEMENT_SIMPLE_AUTOMATION_TEST(FContainersTest, "System.Core.Misc.Containers", EAutomationTestFlags::ApplicationContextMask | EAutomationTestFlags::SmokeFilter) +#include "Stats/StatsMisc.h" +#include "Math/RandomStream.h" #define MAX_TEST_OBJECTS 65 #define MAX_TEST_OBJECTS_STEP 1 - +#define RANDOM_SEED 12345 namespace { @@ -270,60 +271,268 @@ namespace ++CIter; } - check(end( Cont) == Iter); - check(end((const Container&)Cont) == CIter); + check(!Iter); + check(!CIter); } + + template + KeyType GenerateTestKey(int32 Input) + { + return (KeyType)Input; + } + + template <> + FName GenerateTestKey(int32 Input) + { + // Don't use _foo as we want to test the slower compare path + return FName(*FString::Printf(TEXT("TestName%d"), Input)); + } + + template <> + FString GenerateTestKey(int32 Input) + { + return FString::Printf(TEXT("TestString%d"), Input); + } + + template + void RunContainerTests() + { + ContainerType Cont; + + ContainerTestStats.Reset(); + // Subtract one to account for temporaries that will be created during an Add + for (int32 Count = 0; Count < MAX_TEST_OBJECTS - 1; Count += MAX_TEST_OBJECTS_STEP) + { + for (int32 N = 0; N != Count; ++N) + { + Cont.Add(GenerateTestKey(N), FContainerTestValueType(TEXT("New Value"))); + CheckContainerNum(Cont); + CheckContainerEnds(Cont); + CheckContainerElements(Cont); + } + + for (int32 N = 0; N != Count; ++N) + { + Cont.Remove(GenerateTestKey(N)); + CheckContainerNum(Cont); + CheckContainerEnds(Cont); + CheckContainerElements(Cont); + } + + for (int32 N = 0; N != Count; ++N) + { + Cont.Add(GenerateTestKey((Count - 1) - N), FContainerTestValueType(TEXT("New Value"))); + CheckContainerNum(Cont); + CheckContainerEnds(Cont); + CheckContainerElements(Cont); + } + + for (int32 N = 0; N != Count; ++N) + { + Cont.Remove(GenerateTestKey(N)); + CheckContainerNum(Cont); + CheckContainerEnds(Cont); + CheckContainerElements(Cont); + } + } + } + + template + void RunPerformanceTest(const FString& Description, int32 NumObjects, int32 NumOperations) + { + ContainerTestStats.Reset(); + + ContainerType Cont; + FRandomStream RandomStream(RANDOM_SEED); + + // Prep keys, not part of performance test + TArray KeyArray; + KeyArray.Reserve(NumObjects); + + for (int32 i = 0; i < NumObjects; i++) + { + KeyArray.Add(GenerateTestKey(i)); + } + + for (int32 i = 0; i < NumObjects; i++) + { + int32 SwapIndex = RandomStream.RandRange(0, NumObjects - 1); + if (i != SwapIndex) + { + KeyArray.Swap(i, SwapIndex); + } + } + + FScopeLogTime LogTimePtr(*FString::Printf(TEXT("%s objects=%d count=%d"), *Description, NumObjects, NumOperations), nullptr, FScopeLogTime::ScopeLog_Milliseconds); + + // Add elements in stably randomized order + for (int32 i = 0; i < NumObjects; i++) + { + Cont.Add(KeyArray[i], FString(TEXT("New Value"))); + } + + // Now do searches + for (int32 i = 0; i < NumOperations; i++) + { + KeyType& Key = KeyArray[RandomStream.RandRange(0, NumObjects - 1)]; + + FString* FoundValue = Cont.Find(Key); + check(FoundValue); + } + } + + template + void RunSetPerformanceTest(const FString& Description, int32 NumObjects, int32 NumOperations) + { + ContainerTestStats.Reset(); + + ContainerType Cont; + FRandomStream RandomStream(RANDOM_SEED); + + // Prep keys, not part of performance test + TArray KeyArray; + KeyArray.Reserve(NumObjects); + + for (int32 i = 0; i < NumObjects; i++) + { + KeyArray.Add(GenerateTestKey(i)); + } + + for (int32 i = 0; i < NumObjects; i++) + { + int32 SwapIndex = RandomStream.RandRange(0, NumObjects - 1); + if (i != SwapIndex) + { + KeyArray.Swap(i, SwapIndex); + } + } + + FScopeLogTime LogTimePtr(*FString::Printf(TEXT("%s objects=%d count=%d"), *Description, NumObjects, NumOperations), nullptr, FScopeLogTime::ScopeLog_Milliseconds); + + // Add elements in stably randomized order + for (int32 i = 0; i < NumObjects; i++) + { + Cont.Add(KeyArray[i]); + } + + // Now do searches + for (int32 i = 0; i < NumOperations; i++) + { + KeyType& Key = KeyArray[RandomStream.RandRange(0, NumObjects - 1)]; + + bool FoundValue = Cont.Contains(Key); + check(FoundValue); + } + } + + template + struct FCaseSensitiveLookupKeyFuncs : BaseKeyFuncs + { + static FORCEINLINE const FString& GetSetKey(const TPair& Element) + { + return Element.Key; + } + static FORCEINLINE bool Matches(const FString& A, const FString& B) + { + return A.Equals(B, ESearchCase::CaseSensitive); + } + static FORCEINLINE uint32 GetKeyHash(const FString& Key) + { + return FCrc::StrCrc32(*Key); + } + }; } -bool FContainersTest::RunTest( const FString& Parameters ) +IMPLEMENT_SIMPLE_AUTOMATION_TEST(FContainersSmokeTest, "System.Core.Containers.Smoke", EAutomationTestFlags::ApplicationContextMask | EAutomationTestFlags::SmokeFilter) +bool FContainersSmokeTest::RunTest( const FString& Parameters ) { - typedef TMap TestMapType; - - ContainerTestStats.Reset(); - - TestMapType TestMap; - - // Subtract one to account for temporaries that will be created during an Add - for (int32 Count = 0; Count < MAX_TEST_OBJECTS - 1; Count += MAX_TEST_OBJECTS_STEP) - { - for (int32 N = 0; N != Count; ++N) - { - TestMap.Add(N, FContainerTestValueType(TEXT("New Value"))); - CheckContainerNum (TestMap); - CheckContainerEnds (TestMap); - CheckContainerElements(TestMap); - } - - for (int32 N = 0; N != Count; ++N) - { - TestMap.Remove(N); - CheckContainerNum (TestMap); - CheckContainerEnds (TestMap); - CheckContainerElements(TestMap); - } - - for (int32 N = 0; N != Count; ++N) - { - TestMap.Add((Count - 1) - N, FContainerTestValueType(TEXT("New Value"))); - CheckContainerNum (TestMap); - CheckContainerEnds (TestMap); - CheckContainerElements(TestMap); - } - - for (int32 N = 0; N != Count; ++N) - { - TestMap.Remove(N); - CheckContainerNum (TestMap); - CheckContainerEnds (TestMap); - CheckContainerElements(TestMap); - } - } + RunContainerTests, int32>(); return true; } -//Array view tests -#include "Containers/ArrayView.h" +IMPLEMENT_SIMPLE_AUTOMATION_TEST(FContainersFullTest, "System.Core.Containers.Full", EAutomationTestFlags::ApplicationContextMask | EAutomationTestFlags::EngineFilter) +bool FContainersFullTest::RunTest(const FString& Parameters) +{ + RunContainerTests, int32>(); + RunContainerTests, FName>(); + RunContainerTests, FString>(); + RunContainerTests>, int32>(); + RunContainerTests>, FString>(); + + RunContainerTests, int32>(); + RunContainerTests, FName>(); + RunContainerTests, FString>(); + RunContainerTests>, FString>(); + + // Verify use of FName index sorter with SortedMap + + TSortedMap NameMap; + NameMap.Add(NAME_NameProperty); + NameMap.Add(NAME_FloatProperty); + NameMap.Add(NAME_None); + NameMap.Add(NAME_IntProperty); + + auto It = NameMap.CreateConstIterator(); + + check(It->Key == NAME_None); ++It; + check(It->Key == NAME_IntProperty); ++It; + check(It->Key == NAME_FloatProperty); ++It; + check(It->Key == NAME_NameProperty); ++It; + check(!It); + + return true; +} + +IMPLEMENT_SIMPLE_AUTOMATION_TEST(FContainerPerformanceTest, "System.Core.Containers.Performance", EAutomationTestFlags::ApplicationContextMask | EAutomationTestFlags::EngineFilter) +bool FContainerPerformanceTest::RunTest(const FString& Parameters) +{ + RunPerformanceTest, int32>(TEXT("TMap int32"), 1, 1000000); + RunPerformanceTest, int32>(TEXT("TMap int32"), 10, 1000000); + RunPerformanceTest, int32>(TEXT("TMap int32"), 100, 1000000); + RunPerformanceTest, int32>(TEXT("TMap int32"), 1000, 1000000); + RunPerformanceTest, int32>(TEXT("TMap int32"), 10000, 1000000); + + RunPerformanceTest, FName>(TEXT("TMap FName"), 1, 1000000); + RunPerformanceTest, FName>(TEXT("TMap FName"), 10, 1000000); + RunPerformanceTest, FName>(TEXT("TMap FName"), 100, 1000000); + RunPerformanceTest, FName>(TEXT("TMap FName"), 1000, 1000000); + RunPerformanceTest, FName>(TEXT("TMap FName"), 10000, 1000000); + + RunPerformanceTest, FString>(TEXT("TMap FString"), 1, 1000000); + RunPerformanceTest, FString>(TEXT("TMap FString"), 10, 1000000); + RunPerformanceTest, FString>(TEXT("TMap FString"), 100, 1000000); + RunPerformanceTest, FString>(TEXT("TMap FString"), 1000, 1000000); + RunPerformanceTest, FString>(TEXT("TMap FString"), 10000, 1000000); + + RunPerformanceTest, int32>(TEXT("TSortedMap int32"), 1, 1000000); + RunPerformanceTest, int32>(TEXT("TSortedMap int32"), 10, 1000000); + RunPerformanceTest, int32>(TEXT("TSortedMap int32"), 100, 1000000); + RunPerformanceTest, int32>(TEXT("TSortedMap int32"), 1000, 1000000); + RunPerformanceTest, int32>(TEXT("TSortedMap int32"), 10000, 1000000); + + RunPerformanceTest, FName>(TEXT("TSortedMap FName"), 1, 1000000); + RunPerformanceTest, FName>(TEXT("TSortedMap FName"), 10, 1000000); + RunPerformanceTest, FName>(TEXT("TSortedMap FName"), 100, 1000000); + RunPerformanceTest, FName>(TEXT("TSortedMap FName"), 1000, 1000000); + RunPerformanceTest, FName>(TEXT("TSortedMap FName"), 10000, 1000000); + + RunPerformanceTest, FString>(TEXT("TSortedMap FString"), 1, 1000000); + RunPerformanceTest, FString>(TEXT("TSortedMap FString"), 10, 1000000); + RunPerformanceTest, FString>(TEXT("TSortedMap FString"), 100, 1000000); + RunPerformanceTest, FString>(TEXT("TSortedMap FString"), 1000, 1000000); + RunPerformanceTest, FString>(TEXT("TSortedMap FString"), 10000, 1000000); + + RunSetPerformanceTest, FName>(TEXT("TSet FName"), 1, 1000000); + RunSetPerformanceTest, FName>(TEXT("TSet FName"), 10, 1000000); + RunSetPerformanceTest, FName>(TEXT("TSet FName"), 100, 1000000); + + RunSetPerformanceTest, FName>(TEXT("TArray FName"), 1, 1000000); + RunSetPerformanceTest, FName>(TEXT("TArray FName"), 10, 1000000); + RunSetPerformanceTest, FName>(TEXT("TArray FName"), 100, 1000000); + + return true; +} namespace ArrayViewTests { diff --git a/Engine/Source/Developer/MeshSimplifier/Private/HashTable.cpp b/Engine/Source/Runtime/Core/Private/Containers/HashTable.cpp similarity index 83% rename from Engine/Source/Developer/MeshSimplifier/Private/HashTable.cpp rename to Engine/Source/Runtime/Core/Private/Containers/HashTable.cpp index 3f3c8108930a..5f9fe3e971fa 100644 --- a/Engine/Source/Developer/MeshSimplifier/Private/HashTable.cpp +++ b/Engine/Source/Runtime/Core/Private/Containers/HashTable.cpp @@ -2,9 +2,9 @@ #include "HashTable.h" -uint32 FHashTable::EmptyHash[1] = { ~0u }; +CORE_API uint32 FHashTable::EmptyHash[1] = { ~0u }; -void FHashTable::Resize( uint32 NewIndexSize ) +CORE_API void FHashTable::Resize( uint32 NewIndexSize ) { if( NewIndexSize == IndexSize ) { diff --git a/Engine/Source/Runtime/Core/Private/Containers/LockFreeList.cpp b/Engine/Source/Runtime/Core/Private/Containers/LockFreeList.cpp index 0911658c31ce..9a25ac1ab1cf 100644 --- a/Engine/Source/Runtime/Core/Private/Containers/LockFreeList.cpp +++ b/Engine/Source/Runtime/Core/Private/Containers/LockFreeList.cpp @@ -3,129 +3,27 @@ #include "Containers/LockFreeList.h" #include "HAL/PlatformProcess.h" #include "HAL/IConsoleManager.h" +#include "Stats.h" + DEFINE_LOG_CATEGORY(LogLockFreeList); +DECLARE_MEMORY_STAT(TEXT("Lock Free List Links"), STAT_LockFreeListLinks, STATGROUP_Memory); -#if USE_LOCKFREELIST_128 - -/*----------------------------------------------------------------------------- - FLockFreeVoidPointerListBase128 ------------------------------------------------------------------------------*/ - -FLockFreeVoidPointerListBase128::FLinkAllocator& FLockFreeVoidPointerListBase128::FLinkAllocator::Get() -{ - static FLinkAllocator TheAllocator; - return TheAllocator; -} - -FLockFreeVoidPointerListBase128::FLinkAllocator::FLinkAllocator() - : SpecialClosedLink( FLargePointer( new FLink(), FLockFreeListConstants::SpecialClosedLink ) ) -{ - if( !FPlatformAtomics::CanUseCompareExchange128() ) - { - // This is a fatal error. - FPlatformMisc::MessageBoxExt( EAppMsgType::Ok, TEXT( "CPU does not support Compare and Exchange 128-bit operation. Unreal Engine 4 will exit now." ), TEXT( "Unsupported processor" ) ); - FPlatformMisc::RequestExit( true ); - UE_LOG( LogHAL, Fatal, TEXT( "CPU does not support Compare and Exchange 128-bit operation" ) ); - } -} - - -FLockFreeVoidPointerListBase128::FLinkAllocator::~FLinkAllocator() -{ - // - Deliberately leak to allow LockFree to be used during shutdown -#if 0 - check(SpecialClosedLink.Pointer); // double free? - check(!NumUsedLinks.GetValue()); - while( FLink* ToDelete = FLink::Unlink(FreeLinks) ) - { - delete ToDelete; - NumFreeLinks.Decrement(); - } - check(!NumFreeLinks.GetValue()); - delete SpecialClosedLink.Pointer; - SpecialClosedLink.Pointer = 0; -#endif // 0 -} - -#else - -/*----------------------------------------------------------------------------- - FLockFreeVoidPointerListBase ------------------------------------------------------------------------------*/ - -FLockFreeVoidPointerListBase::FLinkAllocator& FLockFreeVoidPointerListBase::FLinkAllocator::Get() -{ - static FLinkAllocator TheAllocator; - return TheAllocator; -} - -FLockFreeVoidPointerListBase::FLinkAllocator::FLinkAllocator() - : FreeLinks(NULL) - , SpecialClosedLink(new FLink()) -{ - ClosedLink()->LockCount.Increment(); -} - -FLockFreeVoidPointerListBase::FLinkAllocator::~FLinkAllocator() -{ - // - Deliberately leak to allow LockFree to be used during shutdown -#if 0 - check(SpecialClosedLink); // double free? - check(!NumUsedLinks.GetValue()); - while (FLink* ToDelete = FLink::Unlink(&FreeLinks)) - { - delete ToDelete; - NumFreeLinks.Decrement(); - } - check(!NumFreeLinks.GetValue()); - delete SpecialClosedLink; - SpecialClosedLink = 0; -#endif // 0 -} - -FLockFreePointerQueueBaseLinkAllocator& FLockFreePointerQueueBaseLinkAllocator::Get() -{ - static FLockFreePointerQueueBaseLinkAllocator Singleton; - return Singleton; -} - -//static FThreadSafeCounter Sleeps; -//static FThreadSafeCounter BigSleeps; - -void LockFreeCriticalSpin(int32& SpinCount) -{ - SpinCount++; - if (SpinCount > 256) - { - FPlatformProcess::Sleep(0.00001f); - //BigSleeps.Increment(); - } - else if (SpinCount > 32) - { - FPlatformProcess::Sleep(0.0f); - //if (Sleeps.Increment() % 10000 == 9999) - //{ - // UE_LOG(LogTemp, Warning, TEXT("sleep0 %d sleep 10us %d"), Sleeps.GetValue() + 1, BigSleeps.GetValue()); - //} - } - else if (SpinCount > 8) - { - FPlatformMisc::MemoryBarrier(); - } -} #if !UE_BUILD_SHIPPING && !UE_BUILD_TEST -static FThreadSafeCounter TestStall; - void DoTestCriticalStall() { - if (TestStall.Increment() % 9713 == 9712) + float Test = FMath::FRand(); + if (Test < .001) { - FPlatformProcess::Sleep(0.000001f); + FPlatformProcess::SleepNoStats(0.001f); + } + else if (Test < .01f) + { + FPlatformProcess::SleepNoStats(0.0f); } } @@ -139,5 +37,185 @@ static FAutoConsoleVariableRef CVarTestCriticalLockFree( #endif -#endif //USE_LOCKFREELIST_128 +void LockFreeTagCounterHasOverflowed() +{ + UE_LOG(LogTemp, Log, TEXT("LockFree Tag has overflowed...(not a problem).")); + FPlatformProcess::Sleep(.001f); +} +void LockFreeLinksExhausted(uint32 TotalNum) +{ + UE_LOG(LogTemp, Fatal, TEXT("Consumed %d lock free links; there are no more."), TotalNum); +} + +static void ChangeMem(int32 Delta) +{ + static FThreadSafeCounter LockFreeListMem; + LockFreeListMem.Add(Delta); + if (GIsRunning) + { + SET_MEMORY_STAT(STAT_LockFreeListLinks, LockFreeListMem.GetValue()); + } +} + +void* LockFreeAllocLinks(SIZE_T AllocSize) +{ + ChangeMem(AllocSize); + return FMemory::Malloc(AllocSize); +} +void LockFreeFreeLinks(SIZE_T AllocSize, void* Ptr) +{ + ChangeMem(-int32(AllocSize)); + FMemory::Free(Ptr); +} + +class LockFreeLinkAllocator_TLSCache : public FNoncopyable +{ + enum + { + NUM_PER_BUNDLE = 64, + }; + + typedef FLockFreeLinkPolicy::TLink TLink; + typedef FLockFreeLinkPolicy::TLinkPtr TLinkPtr; + +public: + + LockFreeLinkAllocator_TLSCache() + { + check(IsInGameThread()); + TlsSlot = FPlatformTLS::AllocTlsSlot(); + check(FPlatformTLS::IsValidTlsSlot(TlsSlot)); + } + /** Destructor, leaks all of the memory **/ + ~LockFreeLinkAllocator_TLSCache() + { + FPlatformTLS::FreeTlsSlot(TlsSlot); + TlsSlot = 0; + } + + /** + * Allocates a memory block of size SIZE. + * + * @return Pointer to the allocated memory. + * @see Free + */ + TLinkPtr Pop() + { + FThreadLocalCache& TLS = GetTLS(); + + if (!TLS.PartialBundle) + { + if (TLS.FullBundle) + { + TLS.PartialBundle = TLS.FullBundle; + TLS.FullBundle = 0; + } + else + { + TLS.PartialBundle = GlobalFreeListBundles.Pop(); + if (!TLS.PartialBundle) + { + int32 FirstIndex = FLockFreeLinkPolicy::LinkAllocator.Alloc(NUM_PER_BUNDLE); + for (int32 Index = 0; Index < NUM_PER_BUNDLE; Index++) + { + TLink* Event = FLockFreeLinkPolicy::IndexToLink(FirstIndex + Index); + Event->DoubleNext.Init(); + Event->SingleNext = 0; + Event->Payload = (void*)UPTRINT(TLS.PartialBundle); + TLS.PartialBundle = FLockFreeLinkPolicy::IndexToPtr(FirstIndex + Index); + } + } + } + TLS.NumPartial = NUM_PER_BUNDLE; + } + TLinkPtr Result = TLS.PartialBundle; + TLink* ResultP = FLockFreeLinkPolicy::DerefLink(TLS.PartialBundle); + TLS.PartialBundle = TLinkPtr(UPTRINT(ResultP->Payload)); + TLS.NumPartial--; + checkLockFreePointerList(TLS.NumPartial >= 0 && ((!!TLS.NumPartial) == (!!TLS.PartialBundle))); + ResultP->Payload = nullptr; + checkLockFreePointerList(!ResultP->DoubleNext.GetPtr() && !ResultP->SingleNext); + return Result; + } + + /** + * Puts a memory block previously obtained from Allocate() back on the free list for future use. + * + * @param Item The item to free. + * @see Allocate + */ + void Push(TLinkPtr Item) + { + FThreadLocalCache& TLS = GetTLS(); + if (TLS.NumPartial >= NUM_PER_BUNDLE) + { + if (TLS.FullBundle) + { + GlobalFreeListBundles.Push(TLS.FullBundle); + //TLS.FullBundle = nullptr; + } + TLS.FullBundle = TLS.PartialBundle; + TLS.PartialBundle = 0; + TLS.NumPartial = 0; + } + TLink* ItemP = FLockFreeLinkPolicy::DerefLink(Item); + ItemP->DoubleNext.SetPtr(0); + ItemP->SingleNext = 0; + ItemP->Payload = (void*)UPTRINT(TLS.PartialBundle); + TLS.PartialBundle = Item; + TLS.NumPartial++; + } + +private: + + /** struct for the TLS cache. */ + struct FThreadLocalCache + { + TLinkPtr FullBundle; + TLinkPtr PartialBundle; + int32 NumPartial; + + FThreadLocalCache() + : FullBundle(0) + , PartialBundle(0) + , NumPartial(0) + { + } + }; + + FThreadLocalCache& GetTLS() + { + checkSlow(FPlatformTLS::IsValidTlsSlot(TlsSlot)); + FThreadLocalCache* TLS = (FThreadLocalCache*)FPlatformTLS::GetTlsValue(TlsSlot); + if (!TLS) + { + TLS = new FThreadLocalCache(); + FPlatformTLS::SetTlsValue(TlsSlot, TLS); + } + return *TLS; + } + + /** Slot for TLS struct. */ + uint32 TlsSlot; + + /** Lock free list of free memory blocks, these are all linked into a bundle of NUM_PER_BUNDLE. */ + FLockFreePointerListLIFORoot GlobalFreeListBundles; +}; + +static LockFreeLinkAllocator_TLSCache GLockFreeLinkAllocator; + +void FLockFreeLinkPolicy::FreeLockFreeLink(FLockFreeLinkPolicy::TLinkPtr Item) +{ + GLockFreeLinkAllocator.Push(Item); +} + +FLockFreeLinkPolicy::TLinkPtr FLockFreeLinkPolicy::AllocLockFreeLink() +{ + FLockFreeLinkPolicy::TLinkPtr Result = GLockFreeLinkAllocator.Pop(); + // this can only really be a mem stomp + checkLockFreePointerList(Result && !FLockFreeLinkPolicy::DerefLink(Result)->DoubleNext.GetPtr() && !FLockFreeLinkPolicy::DerefLink(Result)->Payload && !FLockFreeLinkPolicy::DerefLink(Result)->SingleNext); + return Result; +} + +FLockFreeLinkPolicy::TAllocator FLockFreeLinkPolicy::LinkAllocator; diff --git a/Engine/Source/Runtime/Core/Private/Containers/String.cpp b/Engine/Source/Runtime/Core/Private/Containers/String.cpp index 0e46ff950767..22f591287fa5 100644 --- a/Engine/Source/Runtime/Core/Private/Containers/String.cpp +++ b/Engine/Source/Runtime/Core/Private/Containers/String.cpp @@ -1356,3 +1356,20 @@ int32 FindMatchingClosingParenthesis(const FString& TargetString, const int32 St return INDEX_NONE; } + +FString SlugStringForValidName(const FString& DisplayString) +{ + FString GeneratedName = DisplayString; + + // Convert the display label, which may consist of just about any possible character, into a + // suitable name for a UObject (remove whitespace, certain symbols, etc.) + { + for ( int32 BadCharacterIndex = 0; BadCharacterIndex < ARRAY_COUNT(INVALID_OBJECTNAME_CHARACTERS) - 1; ++BadCharacterIndex ) + { + const TCHAR TestChar[2] = { INVALID_OBJECTNAME_CHARACTERS[BadCharacterIndex], 0 }; + const int32 NumReplacedChars = GeneratedName.ReplaceInline(TestChar, TEXT("")); + } + } + + return GeneratedName; +} \ No newline at end of file diff --git a/Engine/Source/Runtime/Core/Private/CorePrivatePCH.h b/Engine/Source/Runtime/Core/Private/CorePrivatePCH.h index bfd52b2da1e8..6f5a9081a70f 100644 --- a/Engine/Source/Runtime/Core/Private/CorePrivatePCH.h +++ b/Engine/Source/Runtime/Core/Private/CorePrivatePCH.h @@ -30,7 +30,6 @@ #include "Templates/IsArithmetic.h" #include "Templates/UnrealTypeTraits.h" #include "Templates/RemoveCV.h" -#include "Templates/AlignOf.h" #include "Templates/ChooseClass.h" #include "Templates/IntegralConstant.h" #include "Templates/IsClass.h" diff --git a/Engine/Source/Runtime/Core/Private/GenericPlatform/GenericPlatformAtomics.cpp b/Engine/Source/Runtime/Core/Private/GenericPlatform/GenericPlatformAtomics.cpp index 3f509b3d38fd..eba4109e6830 100644 --- a/Engine/Source/Runtime/Core/Private/GenericPlatform/GenericPlatformAtomics.cpp +++ b/Engine/Source/Runtime/Core/Private/GenericPlatform/GenericPlatformAtomics.cpp @@ -1,8 +1,7 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "GenericPlatform/GenericPlatformAtomics.h" -#include "Templates/AlignOf.h" static_assert(sizeof(FInt128) == 16, "FInt128 size must be 16 bytes."); -static_assert(ALIGNOF(FInt128) == 16, "FInt128 alignment must equals 16."); +static_assert(alignof(FInt128) == 16, "FInt128 alignment must equals 16."); diff --git a/Engine/Source/Runtime/Core/Private/GenericPlatform/GenericPlatformFile.cpp b/Engine/Source/Runtime/Core/Private/GenericPlatform/GenericPlatformFile.cpp index ab574177250b..363775e4160b 100644 --- a/Engine/Source/Runtime/Core/Private/GenericPlatform/GenericPlatformFile.cpp +++ b/Engine/Source/Runtime/Core/Private/GenericPlatform/GenericPlatformFile.cpp @@ -9,7 +9,6 @@ #include "Async/AsyncWork.h" #include "UniquePtr.h" #include "ScopeLock.h" - #include "AsyncFileHandle.h" class FGenericBaseRequest; @@ -273,9 +272,9 @@ public: if (bDisableHandleCaching) { #if DISABLE_BUFFERING_ON_GENERIC_ASYNC_FILE_HANDLE - return LowerLevel->OpenRead(*Filename); -#else return LowerLevel->OpenReadNoBuffering(*Filename); +#else + return LowerLevel->OpenRead(*Filename); #endif } IFileHandle* Result = nullptr; @@ -286,9 +285,9 @@ public: if (!HandleCache[0] && !bOpenFailed) { #if DISABLE_BUFFERING_ON_GENERIC_ASYNC_FILE_HANDLE - HandleCache[0] = LowerLevel->OpenRead(*Filename); -#else HandleCache[0] = LowerLevel->OpenReadNoBuffering(*Filename); +#else + HandleCache[0] = LowerLevel->OpenRead(*Filename); #endif bOpenFailed = (HandleCache[0] == nullptr); } @@ -313,9 +312,9 @@ public: if (!Result && !bOpenFailed) { #if DISABLE_BUFFERING_ON_GENERIC_ASYNC_FILE_HANDLE - Result = LowerLevel->OpenRead(*Filename); -#else Result = LowerLevel->OpenReadNoBuffering(*Filename); +#else + Result = LowerLevel->OpenRead(*Filename); #endif bOpenFailed = (Result == nullptr); } diff --git a/Engine/Source/Runtime/Core/Private/GenericPlatform/GenericPlatformMemory.cpp b/Engine/Source/Runtime/Core/Private/GenericPlatform/GenericPlatformMemory.cpp index a6f621fe505e..f7073b991bda 100644 --- a/Engine/Source/Runtime/Core/Private/GenericPlatform/GenericPlatformMemory.cpp +++ b/Engine/Source/Runtime/Core/Private/GenericPlatform/GenericPlatformMemory.cpp @@ -165,7 +165,7 @@ void FGenericPlatformMemory::OnOutOfMemory(uint64 Size, uint32 Alignment) } // let any registered handlers go - FCoreDelegates::OnOutOfMemory.Broadcast(); + FCoreDelegates::GetMemoryTrimDelegate().Broadcast(); UE_LOG(LogMemory, Fatal, TEXT("Ran out of memory allocating %llu bytes with alignment %u"), Size, Alignment); } diff --git a/Engine/Source/Runtime/Core/Private/GenericPlatform/GenericPlatformMisc.cpp b/Engine/Source/Runtime/Core/Private/GenericPlatform/GenericPlatformMisc.cpp index bcb232e2b0f6..baa606a52d00 100644 --- a/Engine/Source/Runtime/Core/Private/GenericPlatform/GenericPlatformMisc.cpp +++ b/Engine/Source/Runtime/Core/Private/GenericPlatform/GenericPlatformMisc.cpp @@ -178,12 +178,15 @@ FString FSHA256Signature::ToString() const /* FGenericPlatformMisc interface *****************************************************************************/ +bool FGenericPlatformMisc::CachedPhysicalScreenData = false; +EScreenPhysicalAccuracy FGenericPlatformMisc::CachedPhysicalScreenAccuracy = EScreenPhysicalAccuracy::Unknown; +int32 FGenericPlatformMisc::CachedPhysicalScreenDensity = 0; + #if !UE_BUILD_SHIPPING bool FGenericPlatformMisc::bShouldPromptForRemoteDebugging = false; bool FGenericPlatformMisc::bPromptForRemoteDebugOnEnsure = false; #endif //#if !UE_BUILD_SHIPPING - GenericApplication* FGenericPlatformMisc::CreateApplication() { return new GenericApplication( nullptr ); @@ -239,6 +242,12 @@ FString FGenericPlatformMisc::GetDeviceId() PRAGMA_ENABLE_DEPRECATION_WARNINGS } +FString FGenericPlatformMisc::GetUniqueAdvertisingId() +{ + // this has no meaning generically, primarily used for attribution on mobile platforms + return FString(); +} + void FGenericPlatformMisc::SubmitErrorReport( const TCHAR* InErrorHist, EErrorReportMode::Type InMode ) { if ((!FPlatformMisc::IsDebuggerPresent() || GAlwaysReportCrash) && !FParse::Param(FCommandLine::Get(), TEXT("CrashForUAT"))) @@ -284,6 +293,13 @@ FString FGenericPlatformMisc::GetPrimaryGPUBrand() return FString( TEXT( "GenericGPUBrand" ) ); } +FString FGenericPlatformMisc::GetDeviceMakeAndModel() +{ + const FString CPUVendor = FPlatformMisc::GetCPUVendor().Trim().TrimTrailing(); + const FString CPUBrand = FPlatformMisc::GetCPUBrand().Trim().TrimTrailing(); + return FString::Printf(TEXT("%s|%s"), *CPUVendor, *CPUBrand); +} + FGPUDriverInfo FGenericPlatformMisc::GetGPUDriverInfo(const FString& DeviceDescription) { return FGPUDriverInfo(); @@ -297,6 +313,11 @@ void FGenericPlatformMisc::GetOSVersions( FString& out_OSVersionLabel, FString& } +FString FGenericPlatformMisc::GetOSVersion() +{ + return FString(); +} + bool FGenericPlatformMisc::GetDiskTotalAndFreeSpace( const FString& InPath, uint64& TotalNumberOfBytes, uint64& NumberOfFreeBytes ) { // Not implemented cross-platform. Each platform may or may not choose to implement this. @@ -1101,6 +1122,63 @@ void FGenericPlatformMisc::RegisterForRemoteNotifications() // not implemented by default } +void FGenericPlatformMisc::UnregisterForRemoteNotifications() +{ + // not implemented by default +} + +EScreenPhysicalAccuracy FGenericPlatformMisc::GetPhysicalScreenDensity(int32& ScreenDensity) +{ + if ( !CachedPhysicalScreenData ) + { + CachedPhysicalScreenData = true; + CachedPhysicalScreenAccuracy = FPlatformMisc::ComputePhysicalScreenDensity(CachedPhysicalScreenDensity); + } + + ScreenDensity = CachedPhysicalScreenDensity; + return CachedPhysicalScreenAccuracy; +} + +EScreenPhysicalAccuracy FGenericPlatformMisc::ConvertInchesToPixels(float Inches, float& OutPixels) +{ + int32 ScreenDensity; + EScreenPhysicalAccuracy Accuracy = GetPhysicalScreenDensity(ScreenDensity); + + if ( Accuracy != EScreenPhysicalAccuracy::Unknown ) + { + OutPixels = Inches * ScreenDensity; + } + else + { + OutPixels = 0; + } + + return Accuracy; +} + +EScreenPhysicalAccuracy FGenericPlatformMisc::ConvertPixelsToInches(float Pixels, float& OutInches) +{ + int32 ScreenDensity; + EScreenPhysicalAccuracy Accuracy = GetPhysicalScreenDensity(ScreenDensity); + + if ( Accuracy != EScreenPhysicalAccuracy::Unknown ) + { + OutInches = Pixels / (float)ScreenDensity; + } + else + { + OutInches = 0; + } + + return Accuracy; +} + +EScreenPhysicalAccuracy FGenericPlatformMisc::ComputePhysicalScreenDensity(int32& ScreenDensity) +{ + ScreenDensity = 0; + return EScreenPhysicalAccuracy::Unknown; +} + const TArray& FGenericPlatformMisc::GetConfidentialPlatforms() { static bool bHasSearchedForPlatforms = false; diff --git a/Engine/Source/Runtime/Core/Private/GenericPlatform/GenericPlatformOutputDevices.cpp b/Engine/Source/Runtime/Core/Private/GenericPlatform/GenericPlatformOutputDevices.cpp index 54c3156758e4..cf5f6c118e24 100644 --- a/Engine/Source/Runtime/Core/Private/GenericPlatform/GenericPlatformOutputDevices.cpp +++ b/Engine/Source/Runtime/Core/Private/GenericPlatform/GenericPlatformOutputDevices.cpp @@ -22,22 +22,20 @@ void FGenericPlatformOutputDevices::SetupOutputDevices() GLog->AddOutputDevice(FPlatformOutputDevices::GetLog()); - bool bHasConsole = !FParse::Param(FCommandLine::Get(), TEXT("NOCONSOLE")); - if (bHasConsole) + // if console is enabled add an output device, unless the commandline says otherwise... + if (ALLOW_CONSOLE && !FParse::Param(FCommandLine::Get(), TEXT("NOCONSOLE"))) { GLog->AddOutputDevice(GLogConsole); } - - // Only create debug output device if a debugger is attached or we're running on a console or build machine - // A shipping build with logging explicitly enabled will fail the IsDebuggerPresent() check, but we still need to add the debug output device for logging purposes - if (!FPlatformProperties::SupportsWindowedMode() || FPlatformMisc::IsDebuggerPresent() || (UE_BUILD_SHIPPING && !NO_LOGGING) || GIsBuildMachine) + + // If the platform has a separate debug output channel (e.g. OutputDebugString) then add an output device + // unless logging is turned off +#if !NO_LOGGING + if (FPlatformMisc::HasSeparateChannelForDebugOutput()) { - // Only need to do this if it's actually going to go to a different place than GLogConsole - if(!bHasConsole || FPlatformMisc::HasSeparateChannelForDebugOutput()) - { - GLog->AddOutputDevice(new FOutputDeviceDebug()); - } + GLog->AddOutputDevice(new FOutputDeviceDebug()); } +#endif GLog->AddOutputDevice(FPlatformOutputDevices::GetEventLog()); }; diff --git a/Engine/Source/Runtime/Core/Private/GenericPlatform/GenericPlatformProcess.cpp b/Engine/Source/Runtime/Core/Private/GenericPlatform/GenericPlatformProcess.cpp index 54c311931220..f38aeae69d32 100644 --- a/Engine/Source/Runtime/Core/Private/GenericPlatform/GenericPlatformProcess.cpp +++ b/Engine/Source/Runtime/Core/Private/GenericPlatform/GenericPlatformProcess.cpp @@ -25,6 +25,7 @@ DEFINE_STAT(STAT_Sleep); DEFINE_STAT(STAT_EventWait); +TArray FGenericPlatformProcess::ShaderDirs; void* FGenericPlatformProcess::GetDllHandle( const TCHAR* Filename ) { @@ -60,6 +61,12 @@ void FGenericPlatformProcess::SetThreadAffinityMask( uint64 AffinityMask ) // Not implemented cross-platform. Each platform may or may not choose to implement this. } +bool FGenericPlatformProcess::ShouldSaveToUserDir() +{ + // default to use the engine/game directories + return false; +} + const TCHAR* FGenericPlatformProcess::UserDir() { // default to the root directory @@ -129,6 +136,25 @@ void FGenericPlatformProcess::SetShaderDir(const TCHAR*Where) } } + +const TArray& FGenericPlatformProcess::AllShaderDirs() +{ + return ShaderDirs; +} + +void FGenericPlatformProcess::AddShaderDir(const FString& InShaderDir) +{ + check(IsInGameThread()); + + FString ShaderDir = InShaderDir; + // make sure we store only relative paths + if (!FPaths::IsRelative(ShaderDir)) + { + FPaths::MakePathRelativeTo(ShaderDir, FPlatformProcess::BaseDir()); + } + ShaderDirs.Add(ShaderDir); +} + /** * Get the shader working directory */ diff --git a/Engine/Source/Runtime/Core/Private/GenericPlatform/GenericPlatformSurvey.cpp b/Engine/Source/Runtime/Core/Private/GenericPlatform/GenericPlatformSurvey.cpp index 07dab4326cf6..9bca67c46a2e 100644 --- a/Engine/Source/Runtime/Core/Private/GenericPlatform/GenericPlatformSurvey.cpp +++ b/Engine/Source/Runtime/Core/Private/GenericPlatform/GenericPlatformSurvey.cpp @@ -3,6 +3,8 @@ #include "GenericPlatform/GenericPlatformSurvey.h" #include "Containers/Array.h" +DEFINE_LOG_CATEGORY(LogSynthBenchmark); + // 100: avg good CPU, <100:slower, >100:faster float FSynthBenchmarkResults::ComputeCPUPerfIndex(TArray* OutIndividualResults) const { diff --git a/Engine/Source/Runtime/Core/Private/HAL/ConsoleManager.cpp b/Engine/Source/Runtime/Core/Private/HAL/ConsoleManager.cpp index 8f69a15553fe..ce768ea884da 100644 --- a/Engine/Source/Runtime/Core/Private/HAL/ConsoleManager.cpp +++ b/Engine/Source/Runtime/Core/Private/HAL/ConsoleManager.cpp @@ -4,7 +4,7 @@ ConsoleManager.cpp: console command handling =============================================================================*/ -#include "HAL/ConsoleManager.h" +#include "ConsoleManager.h" #include "Misc/ScopeLock.h" #include "Misc/Paths.h" #include "Stats/Stats.h" @@ -1857,9 +1857,10 @@ static TAutoConsoleVariable CVarMobileAllowMovableDirectionalLights( static TAutoConsoleVariable CVarMobileHDR32bppMode( TEXT("r.MobileHDR32bppMode"), 0, - TEXT("0: If 32bpp is required mobile HDR will use best suited 32 bpp mode. (default)") - TEXT("1: Force Mobile 32bpp HDR to use mosaic encoding.\n") - TEXT("2: Force Mobile 32bpp HDR to use RGBA encoding mode."), + TEXT("0: If 32bpp is required mobile HDR will use best suited 32 bpp mode. (default)\n") + TEXT("1: Force Mobile 32bpp HDR with mosaic encoding.\n") + TEXT("2: Force Mobile 32bpp HDR with RGBE encoding mode. (device must support framebuffer fetch)\n") + TEXT("3: Force Mobile 32bpp HDR with direct RGBA8 rendering."), ECVF_RenderThreadSafe); static TAutoConsoleVariable CVarMobileReduceLoadedMips( @@ -1966,6 +1967,16 @@ static TAutoConsoleVariable CVarSceneColorFormat( TEXT(" 5: PF_A32B32G32R32F 128Bit (unreasonable but good for testing)"), ECVF_Scalability | ECVF_RenderThreadSafe); +static TAutoConsoleVariable CVarMobileSceneColorFormat( + TEXT("r.Mobile.SceneColorFormat"), + 0, + TEXT("Overrides the memory layout (RGBA) used for the scene color of the mobile renderer.\nUnsupported overridden formats silently use default") + TEXT(" 0: (default) Automatically select the appropriate format depending on project settings and device support.\n") + TEXT(" 1: PF_FloatRGBA 64Bit \n") + TEXT(" 2: PF_FloatR11G11B10 32Bit\n") + TEXT(" 3: PF_B8G8R8A8 32Bit"), + ECVF_Scalability | ECVF_RenderThreadSafe); + static TAutoConsoleVariable CVarPostProcessingColorFormat( TEXT("r.PostProcessingColorFormat"), 0, @@ -2391,3 +2402,4 @@ static TAutoConsoleVariable GLSLCvar( 0, TEXT("2 to use ES GLSL\n1 to use GLSL\n0 to use SPIRV") ); + diff --git a/Engine/Source/Runtime/Core/Private/HAL/FileManagerGeneric.cpp b/Engine/Source/Runtime/Core/Private/HAL/FileManagerGeneric.cpp index 485427421ccd..cd867feb26e5 100644 --- a/Engine/Source/Runtime/Core/Private/HAL/FileManagerGeneric.cpp +++ b/Engine/Source/Runtime/Core/Private/HAL/FileManagerGeneric.cpp @@ -857,6 +857,10 @@ void FArchiveFileWriterGeneric::Flush() } BufferCount = 0; } + if (Handle.IsValid()) + { + Handle->Flush(); + } } void FArchiveFileWriterGeneric::LogWriteError(const TCHAR* Message) diff --git a/Engine/Source/Runtime/Core/Private/HAL/MallocBinned.cpp b/Engine/Source/Runtime/Core/Private/HAL/MallocBinned.cpp index 6cd7d3604b1d..4bf5718c6e20 100644 --- a/Engine/Source/Runtime/Core/Private/HAL/MallocBinned.cpp +++ b/Engine/Source/Runtime/Core/Private/HAL/MallocBinned.cpp @@ -1214,7 +1214,7 @@ void FMallocBinned::DumpAllocatorStats( class FOutputDevice& Ar ) Table = MemSizeToPoolTable[i]; #ifdef USE_FINE_GRAIN_LOCKS - FScopeLock TableLock(&Table->CriticalSection); + Table->CriticalSection.Lock(); #endif uint32 TableAllocSize = (Table->BlockSize > BinnedSizeLimit ? (((3 * (i - BinnedSizeLimit)) + 3)*Private::BINNED_ALLOC_POOL_SIZE) : Private::BINNED_ALLOC_POOL_SIZE); @@ -1228,15 +1228,27 @@ void FMallocBinned::DumpAllocatorStats( class FOutputDevice& Ar ) uint32 MemWaste = (uint32)(((double)Table->TotalWaste / (double)Table->TotalRequests) * (double)Table->ActiveRequests) / 1024 + PoolMemWaste; // Memory that is reserved in active pools and ready for future use uint32 MemSlack = MemAllocated - MemUsed - PoolMemWaste; + // Copy the other stats before releasing the lock and calling CategorizedLogf + uint32 TableBlockSize = Table->BlockSize; + uint32 TableNumActivePools = Table->NumActivePools; + uint32 TableMaxActivePools = Table->MaxActivePools; + uint32 TableActiveRequests = Table->ActiveRequests; + uint32 TableTotalRequests = (uint32)Table->TotalRequests; + uint32 TableMinRequest = Table->MinRequest; + uint32 TableMaxRequest = Table->MaxRequest; + +#ifdef USE_FINE_GRAIN_LOCKS + Table->CriticalSection.Unlock(); +#endif BufferedOutput.CategorizedLogf( LogMemory.GetCategoryName(), ELogVerbosity::Log, TEXT( "% 10i % 9i % 9i % 10i % 12i % 7i % 7i % 7iK % 8iK % 8iK % 9.2f%%" ), - Table->BlockSize, - Table->NumActivePools, - Table->MaxActivePools, - Table->ActiveRequests, - (uint32)Table->TotalRequests, - Table->MinRequest, - Table->MaxRequest, + TableBlockSize, + TableNumActivePools, + TableMaxActivePools, + TableActiveRequests, + TableTotalRequests, + TableMinRequest, + TableMaxRequest, MemUsed, MemSlack, MemWaste, @@ -1245,9 +1257,9 @@ void FMallocBinned::DumpAllocatorStats( class FOutputDevice& Ar ) TotalMemory += MemAllocated; TotalWaste += MemWaste; TotalSlack += MemSlack; - TotalActiveRequests += Table->ActiveRequests; - TotalTotalRequests += Table->TotalRequests; - TotalPools += Table->NumActivePools; + TotalActiveRequests += TableActiveRequests; + TotalTotalRequests += TableTotalRequests; + TotalPools += TableNumActivePools; } BufferedOutput.CategorizedLogf( LogMemory.GetCategoryName(), ELogVerbosity::Log, TEXT( "" ) ); diff --git a/Engine/Source/Runtime/Core/Private/HAL/MallocBinned2.cpp b/Engine/Source/Runtime/Core/Private/HAL/MallocBinned2.cpp index d79561a7077c..c4251e4164f2 100644 --- a/Engine/Source/Runtime/Core/Private/HAL/MallocBinned2.cpp +++ b/Engine/Source/Runtime/Core/Private/HAL/MallocBinned2.cpp @@ -11,6 +11,7 @@ #include "GenericPlatform/GenericPlatformProcess.h" #include "Stats/Stats.h" #include "HAL/IConsoleManager.h" +#include "HAL/MemoryMisc.h" #if BINNED2_ALLOW_RUNTIME_TWEAKING @@ -52,6 +53,14 @@ static FAutoConsoleVariableRef GMallocBinned2AllocExtraCVar( #endif +#if BINNED2_ALLOCATOR_STATS +int64 AllocatedSmallPoolMemory = 0; // memory that's requested to be allocated by the game +int64 AllocatedOSSmallPoolMemory = 0; + +int64 AllocatedLargePoolMemory = 0; // memory requests to the OS which don't fit in the small pool +int64 AllocatedLargePoolMemoryWAlignment = 0; // when we allocate at OS level we need to align to a size +#endif + // Block sizes are based around getting the maximum amount of allocations per pool, with as little alignment waste as possible. // Block sizes should be close to even divisors of the system page size, and well distributed. // They must be 16-byte aligned as well. @@ -480,6 +489,9 @@ struct FMallocBinned2::Private // Free the OS memory. NodePool->Unlink(); Allocator.CachedOSPageAllocator.Free(BasePtrOfNode, Allocator.PageSize); +#if BINNED2_ALLOCATOR_STATS + AllocatedOSSmallPoolMemory -= ((int64)Allocator.PageSize); +#endif } Node = NextNode; @@ -525,6 +537,9 @@ FMallocBinned2::FPoolInfo& FMallocBinned2::FPoolList::PushNewPoolToFront(FMalloc { Private::OutOfMemory(LocalPageSize); } +#if BINNED2_ALLOCATOR_STATS + AllocatedOSSmallPoolMemory += (int64)LocalPageSize; +#endif check(IsAligned(Free, LocalPageSize)); // Create pool FPoolInfo* Result = Private::GetOrCreatePoolInfo(Allocator, Free, FPoolInfo::ECanary::FirstFreeBlockIsPtr, false); @@ -623,6 +638,10 @@ void* FMallocBinned2::MallocExternal(SIZE_T Size, uint32 Alignment) { uint32 PoolIndex = BoundSizeToPoolIndex(Size); +#if BINNED2_ALLOCATOR_STATS + FPlatformAtomics::InterlockedAdd(&AllocatedSmallPoolMemory, (int64)PoolIndexToBlockSize(PoolIndex)); +#endif + FPerThreadFreeBlockLists* Lists = GMallocBinned2PerThreadCaches ? FPerThreadFreeBlockLists::Get() : nullptr; if (Lists) { @@ -683,12 +702,20 @@ void* FMallocBinned2::MallocExternal(SIZE_T Size, uint32 Alignment) // Use OS for non-pooled allocations. UPTRINT AlignedSize = Align(Size, OsAllocationGranularity); void* Result = CachedOSPageAllocator.Allocate(AlignedSize); + + UE_CLOG(!IsAligned(Result, Alignment) ,LogMemory, Fatal, TEXT("FMallocBinned2 alignment was too large for OS. Alignment=%d Ptr=%p"), Alignment, Result); + if (!Result) { Private::OutOfMemory(AlignedSize); } check(IsAligned(Result, PageSize) && IsOSAllocation(Result)); +#if BINNED2_ALLOCATOR_STATS + AllocatedLargePoolMemory += (int64)Size; + AllocatedLargePoolMemoryWAlignment += AlignedSize; +#endif + // Create pool. FPoolInfo* Pool = Private::GetOrCreatePoolInfo(*this, Result, FPoolInfo::ECanary::FirstFreeBlockIsOSAllocSize, false); check(Size > 0 && Size <= AlignedSize && AlignedSize >= OsAllocationGranularity); @@ -758,6 +785,11 @@ void* FMallocBinned2::ReallocExternal(void* Ptr, SIZE_T NewSize, uint32 Alignmen return Result; } +#if BINNED2_ALLOCATOR_STATS + AllocatedLargePoolMemory += ((int64)NewSize) - ((int64)Pool->GetOSRequestedBytes()); + // don't need to change the AllocatedLargePoolMemoryWAlignment because we didn't reallocate so it's the same size +#endif + Pool->SetOSAllocationSizes(NewSize, PoolOsBytes); return Ptr; @@ -772,6 +804,10 @@ void FMallocBinned2::FreeExternal(void* Ptr) BasePtr->CanaryTest(); uint32 BlockSize = BasePtr->BlockSize; uint32 PoolIndex = BasePtr->PoolIndex; + +#if BINNED2_ALLOCATOR_STATS + FPlatformAtomics::InterlockedAdd(&AllocatedSmallPoolMemory, -((int64)(BlockSize))); +#endif FBundleNode* BundlesToRecycle = nullptr; FPerThreadFreeBlockLists* Lists = GMallocBinned2PerThreadCaches ? FPerThreadFreeBlockLists::Get() : nullptr; if (Lists) @@ -802,6 +838,12 @@ void FMallocBinned2::FreeExternal(void* Ptr) } UPTRINT PoolOsBytes = Pool->GetOsAllocatedBytes(); uint32 PoolOSRequestedBytes = Pool->GetOSRequestedBytes(); + +#if BINNED2_ALLOCATOR_STATS + AllocatedLargePoolMemory -= ((int64)PoolOSRequestedBytes); + AllocatedLargePoolMemoryWAlignment -= ((int64)PoolOsBytes); +#endif + checkf(PoolOSRequestedBytes <= PoolOsBytes, TEXT("FMallocBinned2::FreeExternal %d %d"), int32(PoolOSRequestedBytes), int32(PoolOsBytes)); Pool->SetCanary(FPoolInfo::ECanary::Unassigned, true, false); // Free an OS allocation. @@ -833,7 +875,7 @@ bool FMallocBinned2::GetAllocationSizeExternal(void* Ptr, SIZE_T& SizeOut) UPTRINT PoolOsBytes = Pool->GetOsAllocatedBytes(); uint32 PoolOSRequestedBytes = Pool->GetOSRequestedBytes(); checkf(PoolOSRequestedBytes <= PoolOsBytes, TEXT("FMallocBinned2::GetAllocationSizeExternal %d %d"), int32(PoolOSRequestedBytes), int32(PoolOsBytes)); - SizeOut = PoolOSRequestedBytes; + SizeOut = PoolOsBytes; return true; } @@ -1027,6 +1069,39 @@ void FMallocBinned2::FFreeBlock::CanaryFail() const UE_LOG(LogMemory, Fatal, TEXT("FMallocBinned2 Attempt to realloc an unrecognized block %p canary == 0x%x != 0x%x"), (void*)this, (int32)Canary, (int32)FMallocBinned2::FFreeBlock::CANARY_VALUE); } +void FMallocBinned2::GetAllocatorStats( FGenericMemoryStats& OutStats ) +{ + OutStats.Add(TEXT("AllocatedSmallPoolMemory"), AllocatedSmallPoolMemory ); + OutStats.Add(TEXT("AllocatedOSSmallPoolMemory"), AllocatedOSSmallPoolMemory); + OutStats.Add(TEXT("AllocatedLargePoolMemory"), AllocatedLargePoolMemory); + OutStats.Add(TEXT("AllocatedLargePoolMemoryWAlignment"), AllocatedLargePoolMemoryWAlignment); + OutStats.Add(TEXT("PageAllocatorFreeCacheSize"), CachedOSPageAllocator.GetCachedFreeTotal()); + + uint64 TotalAllocated = AllocatedSmallPoolMemory + AllocatedLargePoolMemory; + uint64 TotalOSAllocated = AllocatedOSSmallPoolMemory + AllocatedLargePoolMemoryWAlignment + CachedOSPageAllocator.GetCachedFreeTotal(); + + OutStats.Add(TEXT("TotalAllocated"), TotalAllocated); + OutStats.Add(TEXT("TotalOSAllocated"), TotalOSAllocated); +} + +void FMallocBinned2::DumpAllocatorStats(class FOutputDevice& Ar) +{ +#if BINNED2_ALLOCATOR_STATS + Ar.Logf(TEXT("FMallocBinned2 Mem report")); + Ar.Logf(TEXT("Small Pool")); + Ar.Logf(TEXT("Requested Allocations: %fmb (including block size padding)"), ((double)AllocatedSmallPoolMemory) / (1024.0f * 1024.0f) ); + Ar.Logf(TEXT("OS Allocated: %fmb"), ((double)AllocatedOSSmallPoolMemory) / (1024.0f * 1024.0f)); + Ar.Logf(TEXT("Large Pool")); + Ar.Logf(TEXT("Requested Allocations: %fmb"), ((double)AllocatedLargePoolMemory) / (1024.0f * 1024.0f)); + Ar.Logf(TEXT("OS Allocated: %fmb"), ((double)AllocatedLargePoolMemoryWAlignment) / (1024.0f * 1024.0f)); + + uint32 OSPageAllocatorCachedFreeSize = CachedOSPageAllocator.GetCachedFreeTotal(); + Ar.Logf(TEXT("OS Page Allocator")); + Ar.Logf(TEXT("Cached free pages: %fmb"), ((double)OSPageAllocatorCachedFreeSize) / (1024.0f * 1024.0f)); +#else + Ar.Logf(TEXT("Allocator Stats for binned2 are not in this build set BINNED2_ALLOCATOR_STATS 1 in MallocBinned2.cpp")); +#endif +} #if !BINNED2_INLINE #if PLATFORM_USES_FIXED_GMalloc_CLASS && !FORCE_ANSI_ALLOCATOR && USE_MALLOC_BINNED2 //#define FMEMORY_INLINE_FUNCTION_DECORATOR FORCEINLINE diff --git a/Engine/Source/Runtime/Core/Private/HAL/MallocLeakDetection.cpp b/Engine/Source/Runtime/Core/Private/HAL/MallocLeakDetection.cpp index d149ce5a1a39..972a123e895b 100644 --- a/Engine/Source/Runtime/Core/Private/HAL/MallocLeakDetection.cpp +++ b/Engine/Source/Runtime/Core/Private/HAL/MallocLeakDetection.cpp @@ -14,16 +14,40 @@ #include "Misc/Paths.h" #include "Logging/LogMacros.h" #include "Misc/OutputDeviceArchiveWrapper.h" +#include "Misc/OutputDeviceRedirector.h" #include "Misc/DateTime.h" #include "ProfilingDebugging/ProfilingHelpers.h" #if MALLOC_LEAKDETECTION +/** + * Need forced-initialization of this data as it can be used during global +* ctors. + */ +struct FMallocLeakDetectionStatics +{ + uint32 ContextsTLSID = 0; + uint32 WhitelistTLSID = 0; + + FMallocLeakDetectionStatics() + { + WhitelistTLSID = FPlatformTLS::AllocTlsSlot(); + ContextsTLSID = FPlatformTLS::AllocTlsSlot(); + } + + static FMallocLeakDetectionStatics& Get() + { + static FMallocLeakDetectionStatics Singleton; + return Singleton; + } +}; + FMallocLeakDetection::FMallocLeakDetection() : bRecursive(false) , bCaptureAllocs(false) , MinAllocationSize(0) , TotalTracked(0) + , AllocsWithoutCompact(0) { Contexts.Empty(16); } @@ -38,7 +62,20 @@ FMallocLeakDetection::~FMallocLeakDetection() { } -static uint32 ContextsTLSID = FPlatformTLS::AllocTlsSlot(); + +void FMallocLeakDetection::SetDisabledForThisThread(const bool Disabled) +{ + int Count = (int)(size_t)FPlatformTLS::GetTlsValue(FMallocLeakDetectionStatics::Get().WhitelistTLSID); + Count += Disabled ? 1 : -1; + check(Count >= 0); + + FPlatformTLS::SetTlsValue(FMallocLeakDetectionStatics::Get().WhitelistTLSID, (void*)(size_t)Count); +} + +bool FMallocLeakDetection::IsDisabledForThisThread() const +{ + return !!FPlatformTLS::GetTlsValue(FMallocLeakDetectionStatics::Get().WhitelistTLSID); +} void FMallocLeakDetection::PushContext(const FString& Context) { @@ -46,11 +83,11 @@ void FMallocLeakDetection::PushContext(const FString& Context) FScopeLock Lock(&AllocatedPointersCritical); - TArray* TLContexts = (TArray*)FPlatformTLS::GetTlsValue(ContextsTLSID); + TArray* TLContexts = (TArray*)FPlatformTLS::GetTlsValue(FMallocLeakDetectionStatics::Get().ContextsTLSID); if (!TLContexts) { TLContexts = new TArray(); - FPlatformTLS::SetTlsValue(ContextsTLSID, TLContexts); + FPlatformTLS::SetTlsValue(FMallocLeakDetectionStatics::Get().ContextsTLSID, TLContexts); } bRecursive = true; @@ -65,99 +102,11 @@ void FMallocLeakDetection::PushContext(const FString& Context) void FMallocLeakDetection::PopContext() { - TArray* TLContexts = (TArray*)FPlatformTLS::GetTlsValue(ContextsTLSID); + TArray* TLContexts = (TArray*)FPlatformTLS::GetTlsValue(FMallocLeakDetectionStatics::Get().ContextsTLSID); check(TLContexts); TLContexts->Pop(false); } -bool FMallocLeakDetection::Exec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) -{ - if (FParse::Command(&Cmd, TEXT("mallocleak"))) - { - if (FParse::Command(&Cmd, TEXT("start"))) - { - uint32 FilterSize = 64; - FParse::Value(Cmd, TEXT("filtersize="), FilterSize); - - UE_LOG(LogConsoleResponse, Display, TEXT("Starting tracking of allocations >= %d KB"), FilterSize); - SetAllocationCollection(true, FilterSize * 1024); - } - else if (FParse::Command(&Cmd, TEXT("stop"))) - { - uint32 FilterSize = 64; - FParse::Value(Cmd, TEXT("filtersize="), FilterSize); - - FilterSize *= 1024; - - UE_LOG(LogConsoleResponse, Display, TEXT("Stopping allocation tracking and clearing data.")); - SetAllocationCollection(false); - - UE_LOG(LogConsoleResponse, Display, TEXT("Dumping unique calltacks with %i bytes or more oustanding."), FilterSize); - - FMallocLeakReportOptions Options; - Options.FilterSize = FilterSize; - DumpOpenCallstacks(Options); - - ClearData(); - } - else if (FParse::Command(&Cmd, TEXT("Clear"))) - { - UE_LOG(LogConsoleResponse, Display, TEXT("Clearing tracking data.")); - ClearData(); - } - else if (FParse::Command(&Cmd, TEXT("Dump"))) - { - uint32 FilterSize = 128; - FParse::Value(Cmd, TEXT("filtersize="), FilterSize); - FilterSize *= 1024; - - FString FileName; - FParse::Value(Cmd, TEXT("name="), FileName); - - UE_LOG(LogConsoleResponse, Display, TEXT("Dumping unique calltacks with %i KB or more oustanding."), FilterSize/1024); - - FMallocLeakReportOptions Options; - Options.FilterSize = FilterSize; - Options.OutputFile = *FileName; - - DumpOpenCallstacks(Options); - } - else if (FParse::Command(&Cmd, TEXT("dumpleaks"))) - { - uint32 FilterSize = 0; - FParse::Value(Cmd, TEXT("filtersize="), FilterSize); - FilterSize *= 1024; - - FString FileName; - FParse::Value(Cmd, TEXT("name="), FileName); - - FMallocLeakReportOptions Options; - Options.FilterSize = FilterSize; - Options.OutputFile = *FileName; - - UE_LOG(LogConsoleResponse, Display, TEXT("Dumping potential leakers with %i KB or more oustanding."), FilterSize / 1024); - DumpPotentialLeakers(Options); - } - else if (FParse::Command(&Cmd, TEXT("Checkpoint"))) - { - CheckpointLinearFit(); - } - else - { - UE_LOG(LogConsoleResponse, Display, TEXT("'MallocLeak Start [filtersize=Size]' Begins accumulating unique callstacks of allocations > Size KBytes\n") - TEXT("'MallocLeak stop filtersize=[Size]' Dumps outstanding unique callstacks and stops accumulation (with an optional filter size in KBytes, if not specified 128 KB is assumed). Also clears data.\n") - TEXT("'MallocLeak clear' Clears all accumulated data. Does not change start/stop state.\n") - TEXT("'MallocLeak dump filtersize=[Size] name=[file]' Dumps oustanding unique callstacks with optional size filter in KBytes (if size is not specified it is assumed to be 128 KB).\n") - TEXT("'MallocLeak dumpleaks filtersize=[Size] name=[file]' Dumps oustanding unique callstacks with optional size filter in KBytes (if size is not specified it is assumed to be 0).\n") - ); - } - - return true; - } - return false; -} - - void FMallocLeakDetection::AddCallstack(FCallstackTrack& Callstack) { FScopeLock Lock(&AllocatedPointersCritical); @@ -186,17 +135,19 @@ void FMallocLeakDetection::AddCallstack(FCallstackTrack& Callstack) void FMallocLeakDetection::RemoveCallstack(FCallstackTrack& Callstack) { FScopeLock Lock(&AllocatedPointersCritical); - uint32 CallstackHash = FCrc::MemCrc32(Callstack.CallStack, sizeof(Callstack.CallStack), 0); + uint32 CallstackHash = Callstack.GetHash(); FCallstackTrack* UniqueCallstack = UniqueCallstacks.Find(CallstackHash); if (UniqueCallstack) { UniqueCallstack->Count--; UniqueCallstack->Size -= Callstack.Size; + if (UniqueCallstack->Count == 0) { UniqueCallstack = nullptr; UniqueCallstacks.Remove(CallstackHash); } + TotalTracked -= Callstack.Size; } } @@ -212,42 +163,81 @@ void FMallocLeakDetection::SetAllocationCollection(bool bEnabled, int32 Size) } } -void FMallocLeakDetection::GetOpenCallstacks(TArray& OutCallstacks, const FMallocLeakReportOptions& Options /*= FMallocLeakReportOptions()*/) +void FMallocLeakDetection::GetOpenCallstacks(TArray& OutCallstacks, SIZE_T& OutTotalSize, const FMallocLeakReportOptions& Options /*= FMallocLeakReportOptions()*/) { // Make sure we preallocate memory to avoid OutCallstacks.Empty(UniqueCallstacks.Num() + 32); + OutTotalSize = 0; + + TMap HashesToAllocRate; + HashesToAllocRate.Empty(UniqueCallstacks.Num() + 32); + { FScopeLock Lock(&AllocatedPointersCritical); + const int kRequiredRateCheckpoints = 3; + for (const auto& Pair : UniqueCallstacks) { + const FCallstackTrack& Callstack = Pair.Value; - // Filter on type? - if (Options.OnlyNonDeleters && KnownDeleters.Contains(Pair.Value.GetHash())) + // filter based on rate (discard if we have less, or not enough data) + if (Options.RateFilter > 0.0f && (Callstack.NumCheckPoints < kRequiredRateCheckpoints || Callstack.BytesPerFrame < Options.RateFilter)) + { + continue; + } + + // Filter out allocations that free/resize down? + if (Options.OnlyNonDeleters + && (KnownDeleters.Contains(Callstack.CachedHash) || KnownTrimmers.Contains(Callstack.CachedHash))) { continue; } // frame number? - if (Options.FrameStart > Pair.Value.LastFrame) + if (Options.FrameStart > Callstack.LastFrame) { continue; } - if (Options.FrameEnd && Options.FrameEnd < Pair.Value.LastFrame) + if (Options.FrameEnd && Options.FrameEnd < Callstack.LastFrame) { continue; } // Filter on size? - if (Pair.Value.Size < Options.FilterSize) + if (Callstack.Size < Options.SizeFilter) { continue; - } + } + + HashesToAllocRate.Add(Callstack.CachedHash, Callstack.BytesPerFrame); OutCallstacks.Add(Pair.Key); + + OutTotalSize += Callstack.Size; } + + // now sort + OutCallstacks.Sort([this, &Options, &HashesToAllocRate](uint32 lhs, uint32 rhs) { + + if (Options.SortBy == FMallocLeakReportOptions::ESortOption::SortRate) + { + return HashesToAllocRate[lhs] >= HashesToAllocRate[rhs]; + } + + FCallstackTrack& Left = UniqueCallstacks[lhs]; + FCallstackTrack& Right = UniqueCallstacks[rhs]; + + if (Options.SortBy == FMallocLeakReportOptions::ESortOption::SortHash) + { + return Left.CachedHash < Right.CachedHash; + } + + // else sort by Ascending size + return Left.Size >= Right.Size; + }); } } @@ -293,274 +283,58 @@ void FMallocLeakDetection::FCallstackTrack::GetLinearFit() BytesPerFrame = AtAInv[1][0] * SumOfMemory + AtAInv[1][1] * SumOfMemoryTimesFrameNumber; } -#define LOG_OUTPUT(Format, ...) \ - do {\ - if (ReportAr){\ - ReportAr->Logf(Format, ##__VA_ARGS__);\ - }\ - else {\ - FPlatformMisc::LowLevelOutputDebugStringf(Format, ##__VA_ARGS__);\ - FPlatformMisc::LowLevelOutputDebugStringf(TEXT("\n"));\ - }\ - } while(0);\ - -int32 FMallocLeakDetection::DumpPotentialLeakers(const FMallocLeakReportOptions& Options /*= FMallocLeakReportOptions()*/) +int32 FMallocLeakDetection::DumpOpenCallstacks(const TCHAR* FileName, const FMallocLeakReportOptions& Options /*= FMallocLeakReportOptions()*/) { - const int32 MaxCallstackLineChars = 2048; - char CallstackString[MaxCallstackLineChars]; - TCHAR CallstackStringWide[MaxCallstackLineChars]; - FMemory::Memzero(CallstackString); - - TArray CallstackHashes; - - GetOpenCallstacks(CallstackHashes, Options); - - CheckpointLinearFit(); - - const int kMaxDump = 30; - - TMap HashesToLeakRate; - float TotalLeakRate = 0.0f; - SIZE_T TotalSize = 0; - - - for (uint32 Hash : CallstackHashes) - { - FCallstackTrack Callstack; - - { - FScopeLock Lock(&AllocatedPointersCritical); - if (UniqueCallstacks.Contains(Hash) == false) - continue; - - Callstack = UniqueCallstacks[Hash]; - } - - if (Callstack.NumCheckPoints > 5 && Callstack.BytesPerFrame > .01f && Callstack.Count > 5) - { - HashesToLeakRate.Add(Hash) = Callstack.BytesPerFrame; - - TotalLeakRate += Callstack.BytesPerFrame; - TotalSize += Callstack.Size; - - if (HashesToLeakRate.Num() > kMaxDump) - { - float SmallestValue = MAX_FLT; - uint32 SmallestKey = 0; - for (const auto& KV : HashesToLeakRate) - { - if (KV.Value < SmallestValue) - { - SmallestValue = Callstack.BytesPerFrame; - SmallestKey = KV.Key; - } - } - - check(SmallestKey); - HashesToLeakRate.Remove(SmallestKey); - TotalLeakRate -= SmallestValue; - TotalSize -= UniqueCallstacks[SmallestKey].Size; - } - } - } - - if (HashesToLeakRate.Num() > 0) - { - FOutputDevice* ReportAr = nullptr; - FArchive* FileAr = nullptr; - FOutputDeviceArchiveWrapper* FileArWrapper = nullptr; - - if (Options.OutputFile && FCString::Strlen(Options.OutputFile)) - { - const FString PathName = *(FPaths::ProfilingDir() + TEXT("memreports/")); - IFileManager::Get().MakeDirectory(*PathName); - - FString FilePath = PathName + CreateProfileFilename(Options.OutputFile, TEXT(".leaks"), true); - - FileAr = IFileManager::Get().CreateDebugFileWriter(*FilePath); - FileArWrapper = new FOutputDeviceArchiveWrapper(FileAr); - ReportAr = FileArWrapper; - - //UE_LOG(LogConsoleResponse, Log, TEXT("MemReportDeferred: saving to %s"), *FilePath); - } - - const float InvToMb = 1.0 / (1024 * 1024); - FPlatformMemoryStats MemoryStats = FPlatformMemory::GetStats(); - - LOG_OUTPUT(TEXT("Current Time: %s, Current Frame %d"), *FDateTime::Now().ToString(TEXT("%m.%d-%H.%M.%S")), GFrameCounter); - - LOG_OUTPUT(TEXT("Current Memory: %.02fMB (Peak: %.02fMB)."), - MemoryStats.UsedPhysical * InvToMb, - MemoryStats.PeakUsedPhysical * InvToMb); - - LOG_OUTPUT(TEXT("Tracking %d callstacks that hold %.02fMB"), UniqueCallstacks.Num(), TotalTracked * InvToMb); - - LOG_OUTPUT(TEXT("Leak detection allocation filter: %dKB"), MinAllocationSize / 1024); - LOG_OUTPUT(TEXT("Leak detection report filter: %dKB"), Options.FilterSize / 1024); - LOG_OUTPUT(TEXT("Dumping %d callstacks that hold %.02fMB and may be leaking memory."), HashesToLeakRate.Num(), TotalSize * InvToMb); - LOG_OUTPUT(TEXT("Current estimated leak rate: %.02fB/frame\n.") , TotalLeakRate); - - TArray SortedKeys; - HashesToLeakRate.GetKeys(SortedKeys); - - SortedKeys.Sort([&](uint32 lhs, uint32 rhs) { - //return HashesToLeakRate[rhs] < HashesToLeakRate[lhs]; - return lhs < rhs; - }); - - for (uint32 Key : SortedKeys) - { - FCallstackTrack Callstack; - - { - FScopeLock Lock(&AllocatedPointersCritical); - if (UniqueCallstacks.Contains(Key) == false) - continue; - - Callstack = UniqueCallstacks[Key]; - } - - bool KnownDeleter = KnownDeleters.Contains(Callstack.GetHash()); - - LOG_OUTPUT(TEXT("AllocSize: %i KB, Num: %i, FirstFrame %i, LastFrame %i, KnownDeleter: %d, Baseline memory %.3fMB Leak Rate %.2fB/frame"), - Callstack.Size / 1024 - , Callstack.Count - , Callstack.FirstFrame - , Callstack.LastFrame - , KnownDeleter - , Callstack.Baseline / 1024.0f / 1024.0f - , Callstack.BytesPerFrame); - - for (int32 i = 0; i < FCallstackTrack::Depth; ++i) - { - FPlatformStackWalk::ProgramCounterToHumanReadableString(i, Callstack.CallStack[i], CallstackString, MaxCallstackLineChars); - - if (Callstack.CallStack[i] && FCStringAnsi::Strlen(CallstackString) > 0) - { - //convert ansi -> tchar without mallocs in case we are in OOM handler. - for (int32 CurrChar = 0; CurrChar < MaxCallstackLineChars; ++CurrChar) - { - CallstackStringWide[CurrChar] = CallstackString[CurrChar]; - } - - LOG_OUTPUT(TEXT("%s"), CallstackStringWide); - } - FMemory::Memzero(CallstackString); - } - - { - FScopeLock Lock(&AllocatedPointersCritical); - - TArray SortedContexts; - - for (const auto& Pair : OpenPointers) - { - if (Pair.Value.GetHash() == Key) - { - if (PointerContexts.Contains(Pair.Key)) - { - SortedContexts.Add(*PointerContexts.Find(Pair.Key)); - } - } - } - - if (SortedContexts.Num()) - { - LOG_OUTPUT(TEXT("%d contexts:"), SortedContexts.Num(), CallstackStringWide); - - SortedContexts.Sort(); - - for (const auto& Str : SortedContexts) - { - LOG_OUTPUT(TEXT("\t%s"), *Str); - } - } - } - - LOG_OUTPUT(TEXT("\n")); - } - - if (FileArWrapper != nullptr) - { - FileArWrapper->TearDown(); - delete FileArWrapper; - delete FileAr; - } - } - - return HashesToLeakRate.Num(); -} - -int32 FMallocLeakDetection::DumpOpenCallstacks(const FMallocLeakReportOptions& Options /*= FMallocLeakReportOptions()*/) -{ - const int32 MaxCallstackLineChars = 2048; - char CallstackString[MaxCallstackLineChars]; - TCHAR CallstackStringWide[MaxCallstackLineChars]; - FMemory::Memzero(CallstackString); + check(FCString::Strlen(FileName)); SIZE_T ReportedSize = 0; SIZE_T TotalSize = 0; - TArray SortedKeys; - GetOpenCallstacks(SortedKeys, Options); + GetOpenCallstacks(SortedKeys, ReportedSize, Options); + // Nothing to do + if (SortedKeys.Num() == 0) { - FScopeLock Lock(&AllocatedPointersCritical); - - SortedKeys.Sort([this](uint32 lhs, uint32 rhs) { - - FCallstackTrack& Left = UniqueCallstacks[lhs]; - FCallstackTrack& Right = UniqueCallstacks[rhs]; - - //return Right.Size < Left.Size; - return Left.GetHash() < Right.GetHash(); - }); - - for (uint32 ID : SortedKeys) - { - ReportedSize += UniqueCallstacks[ID].Size; - } + return 0; } FOutputDevice* ReportAr = nullptr; FArchive* FileAr = nullptr; FOutputDeviceArchiveWrapper* FileArWrapper = nullptr; - if (Options.OutputFile && FCString::Strlen(Options.OutputFile)) - { - const FString PathName = *(FPaths::ProfilingDir() + TEXT("memreports/")); - IFileManager::Get().MakeDirectory(*PathName); - - FString FilePath = PathName + CreateProfileFilename(Options.OutputFile, TEXT(".allocs"), true); + const FString PathName = *(FPaths::ProfilingDir() + TEXT("memreports/")); + IFileManager::Get().MakeDirectory(*PathName); - FileAr = IFileManager::Get().CreateDebugFileWriter(*FilePath); - FileArWrapper = new FOutputDeviceArchiveWrapper(FileAr); - ReportAr = FileArWrapper; + FString FilePath = PathName + CreateProfileFilename(FileName, TEXT(""), true); - //UE_LOG(LogConsoleResponse, Log, TEXT("MemReportDeferred: saving to %s"), *FilePath); - } + FileAr = IFileManager::Get().CreateDebugFileWriter(*FilePath); + FileArWrapper = new FOutputDeviceArchiveWrapper(FileAr); + ReportAr = FileArWrapper; const float InvToMb = 1.0 / (1024 * 1024); FPlatformMemoryStats MemoryStats = FPlatformMemory::GetStats(); - LOG_OUTPUT(TEXT("Current Time: %s, Current Frame %d"), *FDateTime::Now().ToString(TEXT("%m.%d-%H.%M.%S")), GFrameCounter); + ReportAr->Logf(TEXT("Current Time: %s, Current Frame %d"), *FDateTime::Now().ToString(TEXT("%m.%d-%H.%M.%S")), GFrameCounter); - LOG_OUTPUT(TEXT("Current Memory: %.02fMB (Peak: %.02fMB)."), + ReportAr->Logf(TEXT("Current Memory: %.02fMB (Peak: %.02fMB)."), MemoryStats.UsedPhysical * InvToMb, MemoryStats.PeakUsedPhysical * InvToMb); - LOG_OUTPUT(TEXT("Tracking %d callstacks that hold %.02fMB"), UniqueCallstacks.Num(), TotalTracked * InvToMb); + ReportAr->Logf(TEXT("Tracking %d callstacks that hold %.02fMB"), UniqueCallstacks.Num(), TotalTracked * InvToMb); - LOG_OUTPUT(TEXT("Leak detection allocation filter: %dKB"), MinAllocationSize / 1024); - LOG_OUTPUT(TEXT("Leak detection report filter: %dKB"), Options.FilterSize / 1024); + ReportAr->Logf(TEXT("Allocation filter: %dKB"), MinAllocationSize / 1024); + ReportAr->Logf(TEXT("Report filter: %dKB"), Options.SizeFilter / 1024); + ReportAr->Logf(TEXT("Have %i open callstacks at frame: %i"), UniqueCallstacks.Num(),(int32)GFrameCounter); - LOG_OUTPUT(TEXT("Have %i open callstacks at frame: %i"), UniqueCallstacks.Num(),(int32)GFrameCounter); - - //for (const auto& Key : SortedKeys) - LOG_OUTPUT(TEXT("Dumping %d callstacks that hold more than %uKBs and total %uKBs"), - SortedKeys.Num(), Options.FilterSize / 1024, ReportedSize / 1024); + ReportAr->Logf(TEXT("Dumping %d callstacks that hold more than %uKBs and total %uKBs"), + SortedKeys.Num(), Options.SizeFilter / 1024, ReportedSize / 1024); + + const int32 MaxCallstackLineChars = 2048; + char CallstackString[MaxCallstackLineChars]; + TCHAR CallstackStringWide[MaxCallstackLineChars]; + FMemory::Memzero(CallstackString); for (const auto& Key : SortedKeys) { @@ -575,13 +349,16 @@ int32 FMallocLeakDetection::DumpOpenCallstacks(const FMallocLeakReportOptions& O } bool KnownDeleter = KnownDeleters.Contains(Callstack.GetHash()); + bool KnownTrimmer = KnownTrimmers.Contains(Callstack.CachedHash); - LOG_OUTPUT(TEXT("\nAllocSize: %i KB, Num: %i, FirstFrame %i, LastFrame %i, KnownDeleter: %d") + ReportAr->Logf(TEXT("\nAllocSize: %i KB, Num: %i, FirstFrame %i, LastFrame %i, KnownDeleter: %d, KnownTrimmer: %d, Alloc Rate %.2fB/frame") , Callstack.Size / 1024 , Callstack.Count , Callstack.FirstFrame , Callstack.LastFrame - , KnownDeleter); + , KnownDeleter + , KnownTrimmer + , Callstack.BytesPerFrame); for (int32 i = 0; i < FCallstackTrack::Depth; ++i) { @@ -595,7 +372,7 @@ int32 FMallocLeakDetection::DumpOpenCallstacks(const FMallocLeakReportOptions& O CallstackStringWide[CurrChar] = CallstackString[CurrChar]; } - LOG_OUTPUT(TEXT("%s"), CallstackStringWide); + ReportAr->Logf(TEXT("%s"), CallstackStringWide); } FMemory::Memzero(CallstackString); } @@ -604,7 +381,7 @@ int32 FMallocLeakDetection::DumpOpenCallstacks(const FMallocLeakReportOptions& O for (const auto& Pair : OpenPointers) { - if (Pair.Value.GetHash() == Key) + if (Pair.Value.CachedHash == Key) { if (PointerContexts.Contains(Pair.Key)) { @@ -615,17 +392,17 @@ int32 FMallocLeakDetection::DumpOpenCallstacks(const FMallocLeakReportOptions& O if (SortedContexts.Num()) { - LOG_OUTPUT(TEXT("%d contexts:"), SortedContexts.Num(), CallstackStringWide); + ReportAr->Logf(TEXT("%d contexts:"), SortedContexts.Num(), CallstackStringWide); SortedContexts.Sort(); for (const auto& Str : SortedContexts) { - LOG_OUTPUT(TEXT("\t%s"), *Str); + ReportAr->Logf(TEXT("\t%s"), *Str); } } - LOG_OUTPUT(TEXT("\n")); + ReportAr->Logf(TEXT("\n")); } if (FileArWrapper != nullptr) @@ -638,8 +415,6 @@ int32 FMallocLeakDetection::DumpOpenCallstacks(const FMallocLeakReportOptions& O return SortedKeys.Num(); } -#undef LOG_OUTPUT - void FMallocLeakDetection::ClearData() { bool OldCapture = bCaptureAllocs; @@ -662,7 +437,9 @@ void FMallocLeakDetection::Malloc(void* Ptr, SIZE_T Size) { if (Ptr) { - if (bCaptureAllocs && (MinAllocationSize == 0 || Size >= MinAllocationSize)) + bool Enabled = bCaptureAllocs && IsDisabledForThisThread() == false; + + if (Enabled && (MinAllocationSize == 0 || Size >= MinAllocationSize)) { FScopeLock Lock(&AllocatedPointersCritical); @@ -676,21 +453,43 @@ void FMallocLeakDetection::Malloc(void* Ptr, SIZE_T Size) Callstack.Size = Size; AddCallstack(Callstack); OpenPointers.Add(Ptr, Callstack); + AllocsWithoutCompact++; - TArray* TLContexts = (TArray*)FPlatformTLS::GetTlsValue(ContextsTLSID); + TArray* TLContexts = (TArray*)FPlatformTLS::GetTlsValue(FMallocLeakDetectionStatics::Get().ContextsTLSID); if (TLContexts && TLContexts->Num()) { - PointerContexts.Add(Ptr, TLContexts->Top().Buffer); + FString Context; + + for (int i = TLContexts->Num() - 1; i >= 0; i--) + { + if (Context.Len()) + { + Context += TEXT("."); + } + + Context += (*TLContexts)[i].Buffer; + } + + PointerContexts.Add(Ptr, Context); + } + + if (AllocsWithoutCompact >= 100000) + { + OpenPointers.Compact(); + OpenPointers.Shrink(); + AllocsWithoutCompact = 0; } bRecursive = false; } } } + + } -void FMallocLeakDetection::Realloc(void* OldPtr, void* NewPtr, SIZE_T Size) +void FMallocLeakDetection::Realloc(void* OldPtr, SIZE_T OldSize, void* NewPtr, SIZE_T NewSize) { if (bRecursive == false && (bCaptureAllocs || OpenPointers.Num())) { @@ -703,15 +502,17 @@ void FMallocLeakDetection::Realloc(void* OldPtr, void* NewPtr, SIZE_T Size) FCallstackTrack* Callstack = OpenPointers.Find(OldPtr); uint32 OldHash = 0; bool WasKnownDeleter = false; + if (Callstack) { + OldSize = Callstack->Size; OldHash = Callstack->GetHash(); WasKnownDeleter = KnownDeleters.Contains(OldHash); } // Note - malloc and then free so linearfit checkpoints in the callstack are // preserved - Malloc(NewPtr, Size); + Malloc(NewPtr, NewSize); // See if we should/need to copy the context across if (OldPtr && NewPtr) @@ -728,18 +529,50 @@ void FMallocLeakDetection::Realloc(void* OldPtr, void* NewPtr, SIZE_T Size) Free(OldPtr); - // if we had a tracked callstack, and it was not a deleter, remark it as such because this 'free' - // was not actually deallocating memory. - if (Size > 0 && OldHash > 0 && WasKnownDeleter == false) + // if we had an old pointer need to do some book keeping... + if (OldPtr != nullptr) { - KnownDeleters.Remove(OldHash); + // If size is decreasing credit the locations involved with "Trimmer" status. + if (NewSize < OldSize) + { + // some of the below may cause allocations + bRecursive = true; + + // We may not have a hash if we're reallocing() something that was allocated before + // we started tracking + if (OldHash) + { + KnownTrimmers.Add(OldHash); + } + + FCallstackTrack* NewCallstack = OpenPointers.Find(NewPtr); + + // Give the new location immediate credit for being a trimmer. This is for the case where a buffer prior to tracking is + // sized down. If that happens we don't want the reallocer to look like just an allocation. + if (NewCallstack) + { + if (NewSize > 0) + { + KnownTrimmers.Add(NewCallstack->CachedHash); + } + } + + bRecursive = false; + } + + // if we had a tracked callstack and a NewSize > 0 then undo the deleter credit that was applied by the Free() above + // since it was not actually deallocating memory. + if (OldHash && NewSize > 0 && WasKnownDeleter == false) + { + KnownDeleters.Remove(OldHash); + } } } else { // realloc returned the same pointer, if there was a context when the call happened then // update it. - TArray* TLContexts = (TArray*)FPlatformTLS::GetTlsValue(ContextsTLSID); + TArray* TLContexts = (TArray*)FPlatformTLS::GetTlsValue(FMallocLeakDetectionStatics::Get().ContextsTLSID); if (TLContexts && TLContexts->Num()) { diff --git a/Engine/Source/Runtime/Core/Private/HAL/MallocLeakDetection.h b/Engine/Source/Runtime/Core/Private/HAL/MallocLeakDetection.h index bf6f62716062..ef95afe784c6 100644 --- a/Engine/Source/Runtime/Core/Private/HAL/MallocLeakDetection.h +++ b/Engine/Source/Runtime/Core/Private/HAL/MallocLeakDetection.h @@ -15,28 +15,50 @@ #include "Containers/Set.h" #include "Containers/Map.h" #include "Misc/ScopeLock.h" +#include "ThreadSafeBool.h" #ifndef MALLOC_LEAKDETECTION #define MALLOC_LEAKDETECTION 0 #endif -#if MALLOC_LEAKDETECTION - - +/** + * Options that can be supplied when calling FMallocLeakDetection::DumpOpenCallstacks + */ struct FMallocLeakReportOptions { + enum class ESortOption + { + SortSize, + SortRate, + SortHash + }; + FMallocLeakReportOptions() { FMemory::Memzero(this, sizeof(FMallocLeakReportOptions)); } - uint32 FilterSize; - float LeakRate; + + /** If >0 only report allocations greater than this size */ + uint32 SizeFilter; + + /** If >0 only report allocations at a greater bytes/frame than this */ + float RateFilter; + + /** Restrict report to allocations that have no history of being deleted */ bool OnlyNonDeleters; + + /** Only show allocations after this frame */ uint32 FrameStart; + + /** Only show allocations from before this frame */ uint32 FrameEnd; - const TCHAR* OutputFile; + + /** Sort allocations by this (default - size) */ + ESortOption SortBy; }; +#if MALLOC_LEAKDETECTION + /** * Maintains a list of all pointers to currently allocated memory. */ @@ -55,6 +77,7 @@ class FMallocLeakDetection uint32 LastFrame; uint64 Size; uint32 Count; + uint32 CachedHash; // least square line fit stuff uint32 NumCheckPoints; @@ -67,7 +90,6 @@ class FMallocLeakDetection float Baseline; float BytesPerFrame; - bool operator==(const FCallstackTrack& Other) const { bool bEqual = true; @@ -89,9 +111,10 @@ class FMallocLeakDetection void GetLinearFit(); - uint32 GetHash() const + uint32 GetHash() { - return FCrc::MemCrc32(CallStack, sizeof(CallStack), 0); + CachedHash = FCrc::MemCrc32(CallStack, sizeof(CallStack), 0); + return CachedHash; } }; @@ -112,21 +135,24 @@ private: /** List of all unique callstacks with allocated memory */ TMap UniqueCallstacks; - /** Set of callstacks that are known to delete memory (never cleared) */ + /** Set of callstacks that are known to delete memory (not reset on ClearData()) */ TSet KnownDeleters; + /** Set of callstacks that are known to resize memory (not reset on ClearData()) */ + TSet KnownTrimmers; + /** Contexts that are associated with allocations */ TMap PointerContexts; /** Stack of contexts */ - struct ContextString { TCHAR Buffer[128]; }; + struct ContextString { TCHAR Buffer[64]; }; TArray Contexts; /** Critical section for mutating internal data */ FCriticalSection AllocatedPointersCritical; - /** Set during mutating operationms to prevent internal allocations from recursing */ - bool bRecursive; + /** Set during mutating operations to prevent internal allocations from recursing */ + FThreadSafeBool bRecursive; /** Is allocation capture enabled? */ bool bCaptureAllocs; @@ -134,8 +160,12 @@ private: /** Minimal size to capture? */ int32 MinAllocationSize; + /** Size of all tracked callstacks */ SIZE_T TotalTracked; + /** How long since we compacted things? */ + int32 AllocsWithoutCompact; + public: static FMallocLeakDetection& Get(); @@ -150,35 +180,36 @@ public: /** Clear currently accumulated data */ void ClearData(); - /** Dumps callstacks that appear to be leaks based on allocation trends */ - int32 DumpPotentialLeakers(const FMallocLeakReportOptions& Options = FMallocLeakReportOptions()); - /** Dumps currently open callstacks */ - int32 DumpOpenCallstacks(const FMallocLeakReportOptions& Options = FMallocLeakReportOptions()); + int32 DumpOpenCallstacks(const TCHAR* FileName, const FMallocLeakReportOptions& Options = FMallocLeakReportOptions()); /** Perform a linear fit checkpoint of all open callstacks */ void CheckpointLinearFit(); - - /** Cmd handler */ - bool Exec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar); - /** Handles new allocated pointer */ void Malloc(void* Ptr, SIZE_T Size); /** Handles reallocation */ - void Realloc(void* OldPtr, void* NewPtr, SIZE_T Size); + void Realloc(void* OldPtr, SIZE_T OldSize, void* NewPtr, SIZE_T NewSize); /** Removes allocated pointer from list */ void Free(void* Ptr); - /** Push/Pop a context that will be associated with allocations. All open contexts will be displayed alongside + /** Disabled allocation tracking for this thread. Used by MALLOCLEAK_WHITELIST_SCOPE macros */ + void SetDisabledForThisThread(const bool Disabled); + + /** Returns true of allocation tracking for this thread is */ + bool IsDisabledForThisThread() const; + + /** Pushes context that will be associated with allocations. All open contexts will be displayed alongside callstacks in a report. */ void PushContext(const FString& Context); + + /** Pops a context from the above */ void PopContext(); /** Returns */ - void GetOpenCallstacks(TArray& OutCallstacks, const FMallocLeakReportOptions& Options = FMallocLeakReportOptions()); + void GetOpenCallstacks(TArray& OutCallstacks, SIZE_T& OutTotalSize, const FMallocLeakReportOptions& Options = FMallocLeakReportOptions()); }; /** @@ -209,12 +240,14 @@ public: return Result; } - virtual void* Realloc(void* Ptr, SIZE_T NewSize, uint32 Alignment) override + virtual void* Realloc(void* OldPtr, SIZE_T NewSize, uint32 Alignment) override { FScopeLock SafeLock(&AllocatedPointersCritical); - void* Result = UsedMalloc->Realloc(Ptr, NewSize, Alignment); - Verify.Realloc(Ptr, Result, NewSize); - return Result; + SIZE_T OldSize(0); + GetAllocationSize(OldPtr, OldSize); + void* NewPtr = UsedMalloc->Realloc(OldPtr, NewSize, Alignment); + Verify.Realloc(OldPtr, OldSize, NewPtr, NewSize); + return NewPtr; } virtual void Free(void* Ptr) override @@ -251,11 +284,6 @@ public: virtual bool Exec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) override { - FScopeLock Lock(&AllocatedPointersCritical); - if (Verify.Exec(InWorld, Cmd, Ar)) - { - return true; - } return UsedMalloc->Exec(InWorld, Cmd, Ar); } @@ -298,4 +326,32 @@ public: } }; -#endif // MALLOC_LEAKDETECTION +/** + * Helper class that can be used to whitelist allocations from a specific scope. Use this + * carefully and only if you know that a portion of code is throwing up either false + * positives or can be ignored. (e.g. one example is the FName table which never shrinks + * and eventually reaches a max that is relatively inconsequential). + */ +class FMallocLeakScopeWhitelist +{ +public: + + FMallocLeakScopeWhitelist() + { + FMallocLeakDetection::Get().SetDisabledForThisThread(true); + } + + ~FMallocLeakScopeWhitelist() + { + FMallocLeakDetection::Get().SetDisabledForThisThread(false); + } +}; + +#define MALLOCLEAK_WHITELIST_SCOPE() \ + FMallocLeakScopeWhitelist ANONYMOUS_VARIABLE(ScopeWhitelist) + +#else // MALLOC_LEAKDETECTION 0 + +#define MALLOCLEAK_WHITELIST_SCOPE() + +#endif // MALLOC_LEAKDETECTIONMALLOC_LEAKDETECTION diff --git a/Engine/Source/Runtime/Core/Private/HAL/MallocTBB.cpp b/Engine/Source/Runtime/Core/Private/HAL/MallocTBB.cpp index 0e5d1159a89c..84e472d5f120 100644 --- a/Engine/Source/Runtime/Core/Private/HAL/MallocTBB.cpp +++ b/Engine/Source/Runtime/Core/Private/HAL/MallocTBB.cpp @@ -7,6 +7,9 @@ #include "HAL/MallocTBB.h" #include "Math/UnrealMathUtility.h" #include "HAL/UnrealMemory.h" +#if PLATFORM_MAC +#include "Templates/AlignmentTemplates.h" +#endif // Only use for supported platforms #if PLATFORM_SUPPORTS_TBB && TBB_ALLOCATOR_ALLOWED @@ -37,6 +40,11 @@ void* FMallocTBB::Malloc( SIZE_T Size, uint32 Alignment ) MEM_TIME(MemTime -= FPlatformTime::Seconds()); void* NewPtr = NULL; +#if PLATFORM_MAC + // macOS expects all allocations to be aligned to 16 bytes, but TBBs default alignment is 8, so on Mac we always have to use scalable_aligned_malloc + Alignment = AlignArbitrary(FMath::Max((uint32)16, Alignment), (uint32)16); + NewPtr = scalable_aligned_malloc(Size, Alignment); +#else if( Alignment != DEFAULT_ALIGNMENT ) { Alignment = FMath::Max(Size >= 16 ? (uint32)16 : (uint32)8, Alignment); @@ -46,6 +54,7 @@ void* FMallocTBB::Malloc( SIZE_T Size, uint32 Alignment ) { NewPtr = scalable_malloc( Size ); } +#endif if( !NewPtr && Size ) { @@ -78,6 +87,11 @@ void* FMallocTBB::Realloc( void* Ptr, SIZE_T NewSize, uint32 Alignment ) } #endif void* NewPtr = NULL; +#if PLATFORM_MAC + // macOS expects all allocations to be aligned to 16 bytes, but TBBs default alignment is 8, so on Mac we always have to use scalable_aligned_realloc + Alignment = AlignArbitrary(FMath::Max((uint32)16, Alignment), (uint32)16); + NewPtr = scalable_aligned_realloc(Ptr, NewSize, Alignment); +#else if (Alignment != DEFAULT_ALIGNMENT) { Alignment = FMath::Max(NewSize >= 16 ? (uint32)16 : (uint32)8, Alignment); @@ -87,6 +101,7 @@ void* FMallocTBB::Realloc( void* Ptr, SIZE_T NewSize, uint32 Alignment ) { NewPtr = scalable_realloc(Ptr, NewSize); } +#endif #if UE_BUILD_DEBUG || UE_BUILD_DEVELOPMENT if (NewPtr && NewSize > OldSize ) { diff --git a/Engine/Source/Runtime/Core/Private/HAL/PlatformFileManager.cpp b/Engine/Source/Runtime/Core/Private/HAL/PlatformFileManager.cpp index 382c0a9043d0..54452f5c226a 100644 --- a/Engine/Source/Runtime/Core/Private/HAL/PlatformFileManager.cpp +++ b/Engine/Source/Runtime/Core/Private/HAL/PlatformFileManager.cpp @@ -48,6 +48,14 @@ IPlatformFile* FPlatformFileManager::FindPlatformFile(const TCHAR* Name) return NULL; } +void FPlatformFileManager::TickActivePlatformFile() +{ + for ( IPlatformFile* ChainElement = TopmostPlatformFile; ChainElement; ChainElement = ChainElement->GetLowerLevel() ) + { + ChainElement->Tick(); + } +} + IPlatformFile* FPlatformFileManager::GetPlatformFile(const TCHAR* Name) { IPlatformFile* PlatformFile = NULL; diff --git a/Engine/Source/Runtime/Core/Private/HAL/ThreadingBase.cpp b/Engine/Source/Runtime/Core/Private/HAL/ThreadingBase.cpp index 3281fc96332a..8c3ca9627518 100644 --- a/Engine/Source/Runtime/Core/Private/HAL/ThreadingBase.cpp +++ b/Engine/Source/Runtime/Core/Private/HAL/ThreadingBase.cpp @@ -32,7 +32,7 @@ CORE_API FRunnableThread* GAudioThread = nullptr; CORE_API bool IsInAudioThread() { // True if this is the audio thread or if there is no audio thread, then if it is the game thread - return (GAudioThreadId != 0 && FPlatformTLS::GetCurrentThreadId() == GAudioThreadId) || (GAudioThreadId == 0 && FPlatformTLS::GetCurrentThreadId() == GGameThreadId); + return FPlatformTLS::GetCurrentThreadId() == (GAudioThreadId ? GAudioThreadId : GGameThreadId); } CORE_API int32 GIsRenderingThreadSuspended = 0; @@ -54,11 +54,14 @@ CORE_API bool IsInParallelRenderingThread() return !GRenderingThread || GIsRenderingThreadSuspended || (FPlatformTLS::GetCurrentThreadId() != GGameThreadId); } +CORE_API uint32 GRHIThreadId = 0; +CORE_API FRunnableThread* GRHIThread_InternalUseOnly = nullptr; + CORE_API bool IsInRHIThread() { - return GRHIThread && FPlatformTLS::GetCurrentThreadId() == GRHIThread->GetThreadID(); + return GRHIThreadId && FPlatformTLS::GetCurrentThreadId() == GRHIThreadId; } -CORE_API FRunnableThread* GRHIThread = nullptr; + // Fake threads // Core version of IsInAsyncLoadingThread @@ -261,11 +264,29 @@ FScopedEvent::FScopedEvent() : Event(FEventPool::Get().GetEventFromPool()) { } +bool FScopedEvent::IsReady() +{ + if ( Event ) + { + if ( Event->Wait(1) ) + { + FEventPool::Get().ReturnToPool(Event); + Event = nullptr; + return true; + } + return false; + } + return true; +} + FScopedEvent::~FScopedEvent() { - Event->Wait(); - FEventPool::Get().ReturnToPool(Event); - Event = nullptr; + if ( Event ) + { + Event->Wait(); + FEventPool::Get().ReturnToPool(Event); + Event = nullptr; + } } /*----------------------------------------------------------------------------- diff --git a/Engine/Source/Runtime/Core/Private/HTML5/HTML5PlatformMisc.cpp b/Engine/Source/Runtime/Core/Private/HTML5/HTML5PlatformMisc.cpp index 6acb6aa30793..630e138b6b9f 100644 --- a/Engine/Source/Runtime/Core/Private/HTML5/HTML5PlatformMisc.cpp +++ b/Engine/Source/Runtime/Core/Private/HTML5/HTML5PlatformMisc.cpp @@ -179,7 +179,7 @@ const void FHTML5Misc::PreLoadMap(FString& Map, FString& LastMap, void* DynData) Downloader->Cache(Map, LastMap, DynData); } -void FHTML5Misc::PlatformPostInit(bool ShowSplashScreen /*= false*/) +void FHTML5Misc::PlatformPostInit() { FModuleManager::Get().LoadModule("MapPakDownloader"); } diff --git a/Engine/Source/Runtime/Core/Private/IOS/IOSAppDelegate.cpp b/Engine/Source/Runtime/Core/Private/IOS/IOSAppDelegate.cpp index 771446471a3b..a7e07edacee9 100644 --- a/Engine/Source/Runtime/Core/Private/IOS/IOSAppDelegate.cpp +++ b/Engine/Source/Runtime/Core/Private/IOS/IOSAppDelegate.cpp @@ -15,6 +15,11 @@ #include "Misc/CommandLine.h" #include "IOS/IOSPlatformFramePacer.h" #include "IOS/IOSAsyncTask.h" +#include "Misc/ConfigCacheIni.h" +#include "IOSPlatformCrashContext.h" +#include "Misc/OutputDeviceError.h" +#include "Misc/OutputDeviceRedirector.h" +#include "Misc/FeedbackContext.h" #include #include @@ -77,10 +82,34 @@ void InstallSignalHandlers() sigaction(SIGSYS, &Action, NULL); } +void EngineCrashHandler(const FGenericCrashContext& GenericContext) +{ + const FIOSCrashContext& Context = static_cast(GenericContext); + + Context.ReportCrash(); + if (GLog) + { + GLog->SetCurrentThreadAsMasterThread(); + GLog->Flush(); + } + if (GWarn) + { + GWarn->Flush(); + } + if (GError) + { + GError->Flush(); + GError->HandleError(); + } + return Context.GenerateCrashInfo(); +} + @implementation IOSAppDelegate #if !UE_BUILD_SHIPPING && !PLATFORM_TVOS +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0 @synthesize ConsoleAlert; +#endif #ifdef __IPHONE_8_0 @synthesize ConsoleAlertController; #endif @@ -98,6 +127,8 @@ void InstallSignalHandlers() @synthesize IOSController; @synthesize SlateController; @synthesize timer; +@synthesize IdleTimerEnableTimer; +@synthesize IdleTimerEnablePeriod; -(void) ParseCommandLineOverrides { @@ -144,13 +175,17 @@ void InstallSignalHandlers() } + // Look for overrides specified on the command-line [self ParseCommandLineOverrides]; FAppEntry::Init(); + + [self InitIdleTimerSettings]; bEngineInit = true; - GShowSplashScreen = false; + // @PJS - need a better way to allow the game to turn off the splash screen +// GShowSplashScreen = false; while( !GIsRequestingExit ) { @@ -196,10 +231,51 @@ void InstallSignalHandlers() } } --(void)EnableIdleTimer:(bool)bEnabled +-(void)RecordPeakMemory +{ + FIOSPlatformMemory::GetStats(); +} + +-(void)InitIdleTimerSettings +{ + float TimerDuration = 0.0F; + GConfig->GetFloat(TEXT("/Script/IOSRuntimeSettings.IOSRuntimeSettings"), TEXT("IdleTimerEnablePeriod"), TimerDuration, GEngineIni); + IdleTimerEnablePeriod = TimerDuration; + + self.IdleTimerEnableTimer = nil; +} + +-(void)DeferredEnableIdleTimer { [UIApplication sharedApplication].idleTimerDisabled = NO; - [UIApplication sharedApplication].idleTimerDisabled = (bEnabled ? NO : YES); + self.IdleTimerEnableTimer = nil; +} + +-(void)EnableIdleTimer:(bool)bEnabled +{ + dispatch_async(dispatch_get_main_queue(),^ + { + if (bEnabled) + { + // Nothing needs to be done, if the enable timer is already running. + if (self.IdleTimerEnableTimer == nil) + { + self.IdleTimerEnableTimer = [NSTimer scheduledTimerWithTimeInterval:IdleTimerEnablePeriod target:self selector:@selector(DeferredEnableIdleTimer) userInfo:nil repeats:NO]; + } + } + else + { + // Ensure pending attempts to enable the idle timer are cancelled. + if (self.IdleTimerEnableTimer != nil) + { + [self.IdleTimerEnableTimer invalidate]; + self.IdleTimerEnableTimer = nil; + } + + [UIApplication sharedApplication].idleTimerDisabled = NO; + [UIApplication sharedApplication].idleTimerDisabled = YES; + } + }); } -(void)NoUrlCommandLine @@ -382,16 +458,34 @@ void InstallSignalHandlers() - (int)GetBatteryLevel { - UIDevice *myDevice = [UIDevice currentDevice]; - #if PLATFORM_TVOS // TVOS does not have a battery, return fully charged return 100; #else - //must enable battery monitoring in order to get a valid value here - [myDevice setBatteryMonitoringEnabled : YES]; - //battery level is from 0.0 to 1.0, get it in terms of 0-100 - return ((int)([myDevice batteryLevel] * 100)); + UIDevice* Device = [UIDevice currentDevice]; + Device.batteryMonitoringEnabled = YES; + + // Battery level is from 0.0 to 1.0, get it in terms of 0-100 + int Level = ((int)([Device batteryLevel] * 100)); + + Device.batteryMonitoringEnabled = NO; + return Level; +#endif +} + +- (bool)IsRunningOnBattery +{ +#if PLATFORM_TVOS + // TVOS does not have a battery, return plugged in + return false; +#else + UIDevice* Device = [UIDevice currentDevice]; + Device.batteryMonitoringEnabled = YES; + + UIDeviceBatteryState State = Device.batteryState; + + Device.batteryMonitoringEnabled = NO; + return State == UIDeviceBatteryStateUnplugged || State == UIDeviceBatteryStateUnknown; #endif } @@ -455,7 +549,7 @@ void InstallSignalHandlers() OSVersion = [[[UIDevice currentDevice] systemVersion] floatValue]; if (!FPlatformMisc::IsDebuggerPresent() || GAlwaysReportCrash) { - InstallSignalHandlers(); + FPlatformMisc::SetCrashHandler(EngineCrashHandler); } // create the main landscape window object @@ -476,6 +570,7 @@ void InstallSignalHandlers() [path setString: [[NSBundle mainBundle] resourcePath]]; UIImageOrientation orient = UIImageOrientationUp; NSMutableString* ImageString = [[NSMutableString alloc]init]; + NSMutableString* PngString = [[NSMutableString alloc] init]; [ImageString appendString:@"Default"]; FPlatformMisc::EIOSDevice Device = FPlatformMisc::GetIOSDeviceType(); @@ -520,11 +615,7 @@ void InstallSignalHandlers() if (NativeScale > 1.0f) { - [ImageString appendString:@"@2x.png"]; - } - else - { - [ImageString appendString:@".png"]; + [ImageString appendString:@"@2x"]; } } else @@ -538,7 +629,7 @@ void InstallSignalHandlers() { orient = UIImageOrientationRight; } - else if (MainFrame.size.height == 568) + else if (MainFrame.size.height == 568 || Device == FPlatformMisc::IOS_IPodTouch6) { [ImageString appendString:@"-568h"]; } @@ -558,17 +649,23 @@ void InstallSignalHandlers() if (NativeScale > 1.0f) { - [ImageString appendString:@"@2x.png"]; - } - else - { - [ImageString appendString:@".png"]; + [ImageString appendString:@"@2x"]; } } + [PngString appendString : ImageString]; + [PngString appendString : @".png"]; + [ImageString appendString : @".jpg"]; [path setString: [path stringByAppendingPathComponent:ImageString]]; UIImage* image = [[UIImage alloc] initWithContentsOfFile: path]; - [path release]; + if (image == nil) + { + [path setString: [[NSBundle mainBundle] resourcePath]]; + [path setString : [path stringByAppendingPathComponent : PngString]]; + image = [[UIImage alloc] initWithContentsOfFile:path]; + } + [path release]; + UIImage* imageToDisplay = [UIImage imageWithCGImage: [image CGImage] scale: 1.0 orientation: orient]; UIImageView* imageView = [[UIImageView alloc] initWithImage: imageToDisplay]; imageView.frame = MainFrame; @@ -598,6 +695,8 @@ void InstallSignalHandlers() timer = [NSTimer scheduledTimerWithTimeInterval: 0.05f target:self selector:@selector(timerForSplashScreen) userInfo:nil repeats:YES]; + self.PeakMemoryTimer = [NSTimer scheduledTimerWithTimeInterval:0.1f target:self selector:@selector(RecordPeakMemory) userInfo:nil repeats:YES]; + // create a new thread (the pointer will be retained forever) NSThread* GameThread = [[NSThread alloc] initWithTarget:self selector:@selector(MainAppThread:) object:launchOptions]; [GameThread setStackSize:GAME_THREAD_STACK_SIZE]; @@ -794,6 +893,15 @@ void InstallSignalHandlers() Token.AddUninitialized([deviceToken length]); memcpy(Token.GetData(), [deviceToken bytes], [deviceToken length]); + const char *data = (const char*)([deviceToken bytes]); + NSMutableString *token = [NSMutableString string]; + + for (NSUInteger i = 0; i < [deviceToken length]; i++) { + [token appendFormat : @"%02.2hhX", data[i]]; + } + + UE_LOG(LogTemp, Display, TEXT("Device Token: %s"), *FString(token)); + FFunctionGraphTask::CreateAndDispatchWhenReady([Token]() { FCoreDelegates::ApplicationRegisteredForRemoteNotificationsDelegate.Broadcast(Token); @@ -824,18 +932,35 @@ void InstallSignalHandlers() } FString jsonFString(JsonString); - - FFunctionGraphTask::CreateAndDispatchWhenReady([jsonFString]() + int AppState; + if (application.applicationState == UIApplicationStateInactive) + { + AppState = 1; // EApplicationState::Inactive; + } + else if (application.applicationState == UIApplicationStateBackground) + { + AppState = 2; // EApplicationState::Background; + } + else + { + AppState = 3; // EApplicationState::Active; + } + + FFunctionGraphTask::CreateAndDispatchWhenReady([jsonFString, AppState]() { - FCoreDelegates::ApplicationReceivedRemoteNotificationDelegate.Broadcast(jsonFString); + FCoreDelegates::ApplicationReceivedRemoteNotificationDelegate.Broadcast(jsonFString, AppState); }, TStatId(), NULL, ENamedThreads::GameThread); } -- (NSUInteger)application:(UIApplication*)application supportedInterfaceOrientationsForWindow:(UIWindow*)window +#endif + +#if !PLATFORM_TVOS +// the below code breaks all of the plist specifying what to support +/*- (NSUInteger)application:(UIApplication*)application supportedInterfaceOrientationsForWindow:(UIWindow*)window { // UIImagePickerController or GameCenter might have portrait-only variant and will throw exception if portrait is not supported here return UIInterfaceOrientationMaskAll; -} +}*/ - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification { @@ -846,9 +971,23 @@ void InstallSignalHandlers() FString activationEventFString(activationEvent); int32 fireDate = [notification.fireDate timeIntervalSince1970]; - FFunctionGraphTask::CreateAndDispatchWhenReady([activationEventFString, fireDate]() + int AppState; + if (application.applicationState == UIApplicationStateInactive) { - FCoreDelegates::ApplicationReceivedLocalNotificationDelegate.Broadcast(activationEventFString, fireDate); + AppState = 1;// EApplicationState::Inactive; + } + else if (application.applicationState == UIApplicationStateBackground) + { + AppState = 2; // EApplicationState::Background; + } + else + { + AppState = 3; // EApplicationState::Active; + } + + FFunctionGraphTask::CreateAndDispatchWhenReady([activationEventFString, fireDate, AppState]() + { + FCoreDelegates::ApplicationReceivedLocalNotificationDelegate.Broadcast(activationEventFString, fireDate, AppState); }, TStatId(), NULL, ENamedThreads::GameThread); } else diff --git a/Engine/Source/Runtime/Core/Private/IOS/IOSInputInterface.cpp b/Engine/Source/Runtime/Core/Private/IOS/IOSInputInterface.cpp index 112259a40e3f..0fefd1dc976c 100644 --- a/Engine/Source/Runtime/Core/Private/IOS/IOSInputInterface.cpp +++ b/Engine/Source/Runtime/Core/Private/IOS/IOSInputInterface.cpp @@ -239,7 +239,7 @@ void FIOSInputInterface::ProcessTouchesAndKeys(uint32 ControllerId) int32 KeyCode = KeyInputStack[KeyIndex]; int32 CharCode = KeyInputStack[KeyIndex + 1]; MessageHandler->OnKeyDown(KeyCode, CharCode, false); - MessageHandler->OnKeyChar(KeyCode, false); + MessageHandler->OnKeyChar(CharCode, false); MessageHandler->OnKeyUp (KeyCode, CharCode, false); } KeyInputStack.Empty(0); diff --git a/Engine/Source/Runtime/Core/Private/IOS/IOSPlatformFile.cpp b/Engine/Source/Runtime/Core/Private/IOS/IOSPlatformFile.cpp index 7d49f9c22883..3aa5afe61060 100644 --- a/Engine/Source/Runtime/Core/Private/IOS/IOSPlatformFile.cpp +++ b/Engine/Source/Runtime/Core/Private/IOS/IOSPlatformFile.cpp @@ -390,6 +390,27 @@ FString FIOSPlatformFile::NormalizeDirectory(const TCHAR* Directory) return Result; } + +FString FIOSPlatformFile::ConvertToAbsolutePathForExternalAppForRead( const TCHAR* Filename ) +{ + struct stat FileInfo; + FString NormalizedFilename = NormalizeFilename(Filename); + if (stat(TCHAR_TO_UTF8(*ConvertToIOSPath(NormalizedFilename, false)), &FileInfo) == -1) + { + return ConvertToAbsolutePathForExternalAppForWrite(Filename); + } + else + { + return ConvertToIOSPath(NormalizedFilename, false); + } +} + +FString FIOSPlatformFile::ConvertToAbsolutePathForExternalAppForWrite( const TCHAR* Filename ) +{ + FString NormalizedFilename = NormalizeFilename(Filename); + return ConvertToIOSPath(NormalizedFilename, true); +} + bool FIOSPlatformFile::FileExists(const TCHAR* Filename) { struct stat FileInfo; @@ -602,7 +623,7 @@ IFileHandle* FIOSPlatformFile::OpenWrite(const TCHAR* Filename, bool bAppend, bo Flags |= O_WRONLY; } FString IOSFilename = ConvertToIOSPath(NormalizeFilename(Filename), true); - int32 Handle = open(TCHAR_TO_UTF8(*IOSFilename), Flags, S_IRUSR | S_IWUSR); + int32 Handle = open(TCHAR_TO_UTF8(*IOSFilename), Flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); if (Handle != -1) { FIOSFileHandle* FileHandleIOS = new FIOSFileHandle(Handle, IOSFilename, false); @@ -761,8 +782,9 @@ FString FIOSPlatformFile::ConvertToIOSPath(const FString& Filename, bool bForWri } else { - static FString ReadPathBase = FString([[NSBundle mainBundle] bundlePath]) + TEXT("/cookeddata/"); - return ReadPathBase + Result.ToLower(); + FString ReadPathBase = FString([[NSBundle mainBundle] bundlePath]) + TEXT("/cookeddata/"); + FString OutString = ReadPathBase + Result.ToLower(); + return OutString; } } diff --git a/Engine/Source/Runtime/Core/Private/IOS/IOSPlatformFile.h b/Engine/Source/Runtime/Core/Private/IOS/IOSPlatformFile.h index 0b9623da5758..00b7e95ca83f 100644 --- a/Engine/Source/Runtime/Core/Private/IOS/IOSPlatformFile.h +++ b/Engine/Source/Runtime/Core/Private/IOS/IOSPlatformFile.h @@ -32,6 +32,9 @@ public: virtual void SetTimeStamp(const TCHAR* Filename, const FDateTime DateTime) override; virtual FDateTime GetAccessTimeStamp(const TCHAR* Filename) override; virtual FString GetFilenameOnDisk(const TCHAR* Filename) override; + + virtual FString ConvertToAbsolutePathForExternalAppForRead( const TCHAR* Filename ) override; + virtual FString ConvertToAbsolutePathForExternalAppForWrite( const TCHAR* Filename ) override; virtual FFileStatData GetStatData(const TCHAR* FilenameOrDirectory) override; @@ -52,4 +55,4 @@ private: FString ReadDirectory; FString WriteDirectory; -}; \ No newline at end of file +}; diff --git a/Engine/Source/Runtime/Core/Private/IOS/IOSPlatformMemory.cpp b/Engine/Source/Runtime/Core/Private/IOS/IOSPlatformMemory.cpp index f04aaad50035..607871f402ad 100644 --- a/Engine/Source/Runtime/Core/Private/IOS/IOSPlatformMemory.cpp +++ b/Engine/Source/Runtime/Core/Private/IOS/IOSPlatformMemory.cpp @@ -27,6 +27,9 @@ FPlatformMemoryStats FIOSPlatformMemory::GetStats() { const FPlatformMemoryConstants& MemoryConstants = FPlatformMemory::GetConstants(); + static SIZE_T PeakUsedPhysical = 0; + static SIZE_T PeakUsedVirtual = 0; + FPlatformMemoryStats MemoryStats; // Gather system-wide memory stats. @@ -41,11 +44,22 @@ FPlatformMemoryStats FIOSPlatformMemory::GetStats() mach_msg_type_number_t InfoSize = sizeof(Info); task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&Info, &InfoSize); + if (Info.resident_size > PeakUsedPhysical) + { + PeakUsedPhysical = Info.resident_size; + } + if (Info.virtual_size > PeakUsedVirtual) + { + PeakUsedVirtual = Info.virtual_size; + } + MemoryStats.AvailablePhysical = FreeMem; MemoryStats.AvailableVirtual = 0; MemoryStats.UsedPhysical = Info.resident_size; MemoryStats.UsedVirtual = Info.virtual_size; - + MemoryStats.PeakUsedPhysical = PeakUsedPhysical; + MemoryStats.PeakUsedVirtual = PeakUsedVirtual; + return MemoryStats; } diff --git a/Engine/Source/Runtime/Core/Private/IOS/IOSPlatformMisc.cpp b/Engine/Source/Runtime/Core/Private/IOS/IOSPlatformMisc.cpp index b3f9db4ec989..f03a2b7a3159 100644 --- a/Engine/Source/Runtime/Core/Private/IOS/IOSPlatformMisc.cpp +++ b/Engine/Source/Runtime/Core/Private/IOS/IOSPlatformMisc.cpp @@ -5,8 +5,11 @@ =============================================================================*/ #include "IOSPlatformMisc.h" +#include "Misc/App.h" #include "ExceptionHandling.h" #include "SecureHash.h" +#include "EngineVersion.h" +#include "IOSMallocZone.h" #include "IOSApplication.h" #include "IOSAppDelegate.h" #include "IOSView.h" @@ -15,12 +18,34 @@ #include "Misc/CommandLine.h" #include "Misc/ConfigCacheIni.h" #include "Apple/ApplePlatformDebugEvents.h" +#include "HAL/FileManager.h" +#include "Misc/FileHelper.h" #include "Apple/ApplePlatformCrashContext.h" +#include "IOSPlatformCrashContext.h" +#if !PLATFORM_TVOS +#include "PLCrashReporter.h" +#include "PLCrashReport.h" +#include "PLCrashReportTextFormatter.h" +#endif +#include "HAL/PlatformOutputDevices.h" +#include "Misc/OutputDeviceError.h" +#include "Misc/OutputDeviceRedirector.h" +#include "Misc/FeedbackContext.h" + +#include "Internationalization/Internationalization.h" +#include "Internationalization/Culture.h" + +#if !PLATFORM_TVOS +#include +#endif #include #include +//#include +#include + /** Amount of free memory in MB reported by the system at startup */ CORE_API int32 GStartupFreeMemoryMB; @@ -70,9 +95,9 @@ void FIOSPlatformMisc::PlatformInit() UE_LOG(LogInit, Log, TEXT("Free Memory at startup: %d MB"), GStartupFreeMemoryMB); } -void FIOSPlatformMisc::PlatformPostInit(bool ShowSplashScreen) +void FIOSPlatformMisc::PlatformHandleSplashScreen(bool ShowSplashScreen) { - GShowSplashScreen = ShowSplashScreen; +// GShowSplashScreen = ShowSplashScreen; } GenericApplication* FIOSPlatformMisc::CreateApplication() @@ -252,6 +277,11 @@ EAppReturnType::Type FIOSPlatformMisc::MessageBoxExt( EAppMsgType::Type MsgType, [StringArray addObject:@"No To All"]; [StringArray addObject:@"Cancel"]; break; + case EAppMsgType::YesNoYesAll: + [StringArray addObject : @"Yes"]; + [StringArray addObject : @"No"]; + [StringArray addObject : @"Yes To All"]; + break; default: [StringArray addObject:@"Ok"]; break; @@ -317,6 +347,9 @@ EAppReturnType::Type FIOSPlatformMisc::MessageBoxExt( EAppMsgType::Type MsgType, case EAppMsgType::YesNoYesAllNoAllCancel: // return 0 for No, 1 for Yes, 2 for YesToAll, 3 for NoToAll, 4 for Cancel break; + case EAppMsgType::YesNoYesAll: + // return 0 for No, 1 for Yes, 2 for YesToAll + break; default: Result = EAppReturnType::Ok; break; @@ -372,6 +405,11 @@ int FIOSPlatformMisc::GetBatteryLevel() return [[IOSAppDelegate GetDelegate] GetBatteryLevel]; } +bool FIOSPlatformMisc::IsRunningOnBattery() +{ + return [[IOSAppDelegate GetDelegate] IsRunningOnBattery]; +} + int32 FIOSPlatformMisc::NumberOfCores() { // cache the number of cores @@ -393,6 +431,7 @@ void FIOSPlatformMisc::LoadPreInitModules() { FModuleManager::Get().LoadModule(TEXT("OpenGLDrv")); FModuleManager::Get().LoadModule(TEXT("IOSAudio")); + FModuleManager::Get().LoadModule(TEXT("AudioMixerAudioUnit")); } void* FIOSPlatformMisc::CreateAutoreleasePool() @@ -421,6 +460,29 @@ bool FIOSPlatformMisc::HasPlatformFeature(const TCHAR* FeatureName) return FGenericPlatformMisc::HasPlatformFeature(FeatureName); } +FString GetIOSDeviceIDString() +{ + static FString CachedResult; + static bool bCached = false; + if (!bCached) + { + // get the device hardware type string length + size_t DeviceIDLen; + sysctlbyname("hw.machine", NULL, &DeviceIDLen, NULL, 0); + + // get the device hardware type + char* DeviceID = (char*)malloc(DeviceIDLen); + sysctlbyname("hw.machine", DeviceID, &DeviceIDLen, NULL, 0); + + CachedResult = ANSI_TO_TCHAR(DeviceID); + bCached = true; + + free(DeviceID); + } + + return CachedResult; +} + FIOSPlatformMisc::EIOSDevice FIOSPlatformMisc::GetIOSDeviceType() { // default to unknown @@ -432,24 +494,13 @@ FIOSPlatformMisc::EIOSDevice FIOSPlatformMisc::GetIOSDeviceType() return DeviceType; } - // get the device hardware type string length - size_t DeviceIDLen; - sysctlbyname("hw.machine", NULL, &DeviceIDLen, NULL, 0); - - // get the device hardware type - char* DeviceID = (char*)malloc(DeviceIDLen); - sysctlbyname("hw.machine", DeviceID, &DeviceIDLen, NULL, 0); - - // convert to NSStringt - NSString *DeviceIDString= [NSString stringWithCString:DeviceID encoding:NSUTF8StringEncoding]; - FString DeviceIDFstring = FString(DeviceIDString); - free(DeviceID); + const FString DeviceIDString = GetIOSDeviceIDString(); // iPods - if ([DeviceIDString hasPrefix:@"iPod"]) + if (DeviceIDString.StartsWith(TEXT("iPod"))) { // get major revision number - int Major = FCString::Atoi(&DeviceIDFstring[4]); + int Major = FCString::Atoi(&DeviceIDString[4]); if (Major == 5) { @@ -461,11 +512,12 @@ FIOSPlatformMisc::EIOSDevice FIOSPlatformMisc::GetIOSDeviceType() } } // iPads - else if ([DeviceIDString hasPrefix:@"iPad"]) + else if (DeviceIDString.StartsWith(TEXT("iPad"))) { // get major revision number - int Major = FCString::Atoi(&DeviceIDFstring[4]); - int Minor = FCString::Atoi(&DeviceIDFstring[([DeviceIDString rangeOfString:@","].location + 1)]); + const int Major = FCString::Atoi(&DeviceIDString[4]); + const int CommaIndex = DeviceIDString.Find(TEXT(","), ESearchCase::CaseSensitive, ESearchDir::FromStart, 4); + const int Minor = FCString::Atoi(&DeviceIDString[CommaIndex + 1]); // iPad2,[1|2|3] is iPad 2 (1 - wifi, 2 - gsm, 3 - cdma) if (Major == 2) @@ -535,10 +587,11 @@ FIOSPlatformMisc::EIOSDevice FIOSPlatformMisc::GetIOSDeviceType() } } // iPhones - else if ([DeviceIDString hasPrefix:@"iPhone"]) + else if (DeviceIDString.StartsWith(TEXT("iPhone"))) { - int Major = FCString::Atoi(&DeviceIDFstring[6]); - int Minor = FCString::Atoi(&DeviceIDFstring[([DeviceIDString rangeOfString:@","].location + 1)]); + const int Major = FCString::Atoi(&DeviceIDString[6]); + const int CommaIndex = DeviceIDString.Find(TEXT(","), ESearchCase::CaseSensitive, ESearchDir::FromStart, 6); + const int Minor = FCString::Atoi(&DeviceIDString[CommaIndex + 1]); if (Major == 3) { @@ -609,12 +662,12 @@ FIOSPlatformMisc::EIOSDevice FIOSPlatformMisc::GetIOSDeviceType() } } // tvOS - else if ([DeviceIDString hasPrefix:@"AppleTV"]) + else if (DeviceIDString.StartsWith(TEXT("AppleTV"))) { DeviceType = IOS_AppleTV; } // simulator - else if ([DeviceIDString hasPrefix:@"x86"]) + else if (DeviceIDString.StartsWith(TEXT("x86"))) { // iphone if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) @@ -642,7 +695,6 @@ FIOSPlatformMisc::EIOSDevice FIOSPlatformMisc::GetIOSDeviceType() } } - // if this is unknown at this point, we have a problem if (DeviceType == IOS_Unknown) { @@ -707,6 +759,7 @@ FString FIOSPlatformMisc::GetUniqueDeviceId() FString FIOSPlatformMisc::GetDeviceId() { // Check to see if this OS has this function + if ([[UIDevice currentDevice] respondsToSelector:@selector(identifierForVendor)]) { NSUUID* Id = [[UIDevice currentDevice] identifierForVendor]; @@ -720,26 +773,59 @@ FString FIOSPlatformMisc::GetDeviceId() return FString(); } +FString FIOSPlatformMisc::GetOSVersion() +{ + return FString([[UIDevice currentDevice] systemVersion]); +} + + +/** +* Returns a unique string for advertising identification +* +* @return the unique string generated by this platform for this device +*/ +FString FIOSPlatformMisc::GetUniqueAdvertisingId() +{ +#if !PLATFORM_TVOS + // Check to see if this OS has this function + if ([[ASIdentifierManager sharedManager] respondsToSelector:@selector(advertisingIdentifier)]) + { + NSString* IdfaString = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString]; + FString IDFA(IdfaString); + return IDFA; + } +#endif + return FString(); +} + class IPlatformChunkInstall* FIOSPlatformMisc::GetPlatformChunkInstall() { static IPlatformChunkInstall* ChunkInstall = nullptr; - if (!ChunkInstall) + static bool bIniChecked = false; + if (!ChunkInstall || !bIniChecked) { FString ProviderName; - GConfig->GetString(TEXT("StreamingInstall"), TEXT("DefaultProviderName"), ProviderName, GEngineIni); - if (ProviderName == TEXT("HTTPChunkInstaller")) + IPlatformChunkInstallModule* PlatformChunkInstallModule = nullptr; + if (!GEngineIni.IsEmpty()) { - IPlatformChunkInstallModule* PlatformChunkInstallModule = FModuleManager::LoadModulePtr("HTTPChunkInstaller"); - if (PlatformChunkInstallModule != NULL) + FString InstallModule; + GConfig->GetString(TEXT("StreamingInstall"), TEXT("DefaultProviderName"), InstallModule, GEngineIni); + FModuleStatus Status; + if (FModuleManager::Get().QueryModule(*InstallModule, Status)) { - // Attempt to grab the platform installer - ChunkInstall = PlatformChunkInstallModule->GetPlatformChunkInstall(); + PlatformChunkInstallModule = FModuleManager::LoadModulePtr(*InstallModule); + if (PlatformChunkInstallModule != nullptr) + { + // Attempt to grab the platform installer + ChunkInstall = PlatformChunkInstallModule->GetPlatformChunkInstall(); + } } - } - else if (ProviderName == TEXT("IOSChunkInstaller")) - { - static FIOSChunkInstall Singleton; - ChunkInstall = &Singleton; + else if (ProviderName == TEXT("IOSChunkInstaller")) + { + static FIOSChunkInstall Singleton; + ChunkInstall = &Singleton; + } + bIniChecked = true; } if (!ChunkInstall) { @@ -1022,3 +1108,913 @@ void FIOSPlatformMisc::EndNamedEvent() FApplePlatformDebugEvents::EndNamedEvent(); } #endif + +FString FIOSPlatformMisc::GetCPUVendor() +{ + return TEXT("Apple"); +} + +FString FIOSPlatformMisc::GetCPUBrand() +{ + return GetIOSDeviceIDString(); +} + +void FIOSPlatformMisc::GetOSVersions(FString& out_OSVersionLabel, FString& out_OSSubVersionLabel) +{ +#if PLATFORM_TVOS + out_OSVersionLabel = TEXT("TVOS"); +#else + out_OSVersionLabel = TEXT("IOS"); +#endif + NSOperatingSystemVersion IOSVersion; + IOSVersion = [[NSProcessInfo processInfo] operatingSystemVersion]; + out_OSSubVersionLabel = FString::Printf(TEXT("%ld.%ld.%ld"), IOSVersion.majorVersion, IOSVersion.minorVersion, IOSVersion.patchVersion); +} + +int32 FIOSPlatformMisc::IOSVersionCompare(uint8 Major, uint8 Minor, uint8 Revision) +{ + NSOperatingSystemVersion IOSVersion; + IOSVersion = [[NSProcessInfo processInfo] operatingSystemVersion]; + uint8 TargetValues[3] = { Major, Minor, Revision }; + NSInteger ComponentValues[3] = { IOSVersion.majorVersion, IOSVersion.minorVersion, IOSVersion.patchVersion }; + + for (uint32 i = 0; i < 3; i++) + { + if (ComponentValues[i] < TargetValues[i]) + { + return -1; + } + else if (ComponentValues[i] > TargetValues[i]) + { + return 1; + } + } + + return 0; +} + +EScreenPhysicalAccuracy FIOSPlatformMisc::ComputePhysicalScreenDensity(int32& ScreenDensity) +{ + EIOSDevice Device = GetIOSDeviceType(); + static_assert( EIOSDevice::IOS_Unknown == 25, "Every device needs to be handled here." ); + + ScreenDensity = 0; + EScreenPhysicalAccuracy Accuracy = EScreenPhysicalAccuracy::Unknown; + + // look up what the device can support + const float NativeScale =[[UIScreen mainScreen] scale]; + + switch ( Device ) + { + case IOS_IPhoneSE: + case IOS_IPhone4: + case IOS_IPhone4S: + case IOS_IPhone5: + case IOS_IPhone5S: + case IOS_IPodTouch5: + case IOS_IPodTouch6: + case IOS_IPhone6: + case IOS_IPhone6S: + case IOS_IPhone7: + ScreenDensity = 326; + Accuracy = EScreenPhysicalAccuracy::Truth; + break; + case IOS_IPhone6Plus: + case IOS_IPhone6SPlus: + case IOS_IPhone7Plus: + ScreenDensity = 401; + Accuracy = EScreenPhysicalAccuracy::Truth; + break; + case IOS_IPadMini: + case IOS_IPadMini2: // also the iPadMini3 + case IOS_IPadMini4: + ScreenDensity = 401; + Accuracy = EScreenPhysicalAccuracy::Truth; + break; + case IOS_IPad2: + case IOS_IPad3: + case IOS_IPad4: + case IOS_IPadAir: + case IOS_IPadAir2: + case IOS_IPadPro_97: + ScreenDensity = 264; + Accuracy = EScreenPhysicalAccuracy::Truth; + break; + case IOS_IPadPro: + case IOS_IPadPro_129: + ScreenDensity = 264; + Accuracy = EScreenPhysicalAccuracy::Truth; + break; + case IOS_AppleTV: + Accuracy = EScreenPhysicalAccuracy::Unknown; + break; + default: + // If we don't know, assume that the density is a multiple of the + // native Content Scaling Factor. Won't be exact, but should be close enough. + ScreenDensity = 163 * NativeScale; + Accuracy = EScreenPhysicalAccuracy::Approximation; + break; + } + + // look up the current scale factor + UIView* View = [IOSAppDelegate GetDelegate].IOSView; + const float ContentScaleFactor = View.contentScaleFactor; + + if ( ContentScaleFactor != 0 ) + { + ScreenDensity = ScreenDensity * ( ContentScaleFactor / NativeScale ); + } + + return Accuracy; +} + +/*------------------------------------------------------------------------------ + FIOSApplicationInfo - class to contain all state for crash reporting that is unsafe to acquire in a signal. + ------------------------------------------------------------------------------*/ + +/** + * Information that cannot be obtained during a signal-handler is initialised here. + * This ensures that we only call safe functions within the crash reporting handler. + */ +struct FIOSApplicationInfo +{ + void Init() + { + SCOPED_AUTORELEASE_POOL; + + AppName = FApp::GetGameName(); + FCStringAnsi::Strcpy(AppNameUTF8, PATH_MAX+1, TCHAR_TO_UTF8(*AppName)); + + ExecutableName = FPlatformProcess::ExecutableName(); + + AppPath = FString([[NSBundle mainBundle] executablePath]); + + AppBundleID = FString([[NSBundle mainBundle] bundleIdentifier]); + + NumCores = FPlatformMisc::NumberOfCores(); + + LCID = FString::Printf(TEXT("%d"), FInternationalization::Get().GetCurrentCulture()->GetLCID()); + + PrimaryGPU = FPlatformMisc::GetPrimaryGPUBrand(); + + RunUUID = RunGUID(); + + OSXVersion = [[NSProcessInfo processInfo] operatingSystemVersion]; + OSVersion = FString::Printf(TEXT("%ld.%ld.%ld"), OSXVersion.majorVersion, OSXVersion.minorVersion, OSXVersion.patchVersion); + FCStringAnsi::Strcpy(OSVersionUTF8, PATH_MAX+1, TCHAR_TO_UTF8(*OSVersion)); + + // macOS build number is only accessible on non-sandboxed applications as it resides outside the accessible sandbox + if(!bIsSandboxed) + { + NSDictionary* SystemVersion = [NSDictionary dictionaryWithContentsOfFile: @"/System/Library/CoreServices/SystemVersion.plist"]; + OSBuild = FString((NSString*)[SystemVersion objectForKey: @"ProductBuildVersion"]); + } + + char TempSysCtlBuffer[PATH_MAX] = {}; + size_t TempSysCtlBufferSize = PATH_MAX; + + sysctlbyname("kern.osrelease", TempSysCtlBuffer, &TempSysCtlBufferSize, NULL, 0); + BiosRelease = TempSysCtlBuffer; + uint32 KernelRevision = 0; + TempSysCtlBufferSize = 4; + sysctlbyname("kern.osrevision", &KernelRevision, &TempSysCtlBufferSize, NULL, 0); + BiosRevision = FString::Printf(TEXT("%d"), KernelRevision); + TempSysCtlBufferSize = PATH_MAX; + sysctlbyname("kern.uuid", TempSysCtlBuffer, &TempSysCtlBufferSize, NULL, 0); + BiosUUID = TempSysCtlBuffer; + TempSysCtlBufferSize = PATH_MAX; + sysctlbyname("hw.model", TempSysCtlBuffer, &TempSysCtlBufferSize, NULL, 0); + MachineModel = TempSysCtlBuffer; + TempSysCtlBufferSize = PATH_MAX+1; + sysctlbyname("machdep.cpu.brand_string", MachineCPUString, &TempSysCtlBufferSize, NULL, 0); + + gethostname(MachineName, ARRAY_COUNT(MachineName)); + + BranchBaseDir = FString::Printf( TEXT( "%s!%s!%s!%d" ), *FApp::GetBranchName(), FPlatformProcess::BaseDir(), FPlatformMisc::GetEngineMode(), FEngineVersion::Current().GetChangelist() ); + + // Get the paths that the files will actually have been saved to + FString LogDirectory = FPaths::GameLogDir(); + TCHAR CommandlineLogFile[MAX_SPRINTF]=TEXT(""); + + // Use the log file specified on the commandline if there is one + CommandLine = FCommandLine::Get(); + FString LogPath = FGenericPlatformOutputDevices::GetAbsoluteLogFilename(); + LogPath = IFileManager::Get().ConvertToAbsolutePathForExternalAppForWrite(*LogPath); + FCStringAnsi::Strcpy(AppLogPath, PATH_MAX + 1, TCHAR_TO_UTF8(*LogPath)); + + // Cache & create the crash report folder. + FString ReportPath = FPaths::ConvertRelativePathToFull(FString::Printf(TEXT("%s"), *(FPaths::GameAgnosticSavedDir() / TEXT("Crashes")))); + IFileManager::Get().MakeDirectory(*ReportPath, true); + ReportPath = IFileManager::Get().ConvertToAbsolutePathForExternalAppForWrite(*ReportPath); + FCStringAnsi::Strcpy(CrashReportPath, PATH_MAX+1, TCHAR_TO_UTF8(*ReportPath)); + + NSString* PLCrashReportFile = [TemporaryCrashReportFolder().GetNSString() stringByAppendingPathComponent:TemporaryCrashReportName().GetNSString()]; + [PLCrashReportFile getCString:PLCrashReportPath maxLength:PATH_MAX encoding:NSUTF8StringEncoding]; + } + + ~FIOSApplicationInfo() + { +#if !PLATFORM_TVOS + if (CrashReporter) + { + [CrashReporter release]; + CrashReporter = nil; + } +#endif + } + + static FGuid RunGUID() + { + static FGuid Guid; + if (!Guid.IsValid()) + { + FPlatformMisc::CreateGuid(Guid); + } + return Guid; + } + + static FString TemporaryCrashReportFolder() + { + static FString PLCrashReportFolder; + if (PLCrashReportFolder.IsEmpty()) + { + SCOPED_AUTORELEASE_POOL; + + NSArray* Paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); + NSString* CacheDir = [Paths objectAtIndex: 0]; + + NSString* BundleID = [[NSBundle mainBundle] bundleIdentifier]; + if (!BundleID) + { + BundleID = [[NSProcessInfo processInfo] processName]; + } + check(BundleID); + + NSString* PLCrashReportFolderPath = [CacheDir stringByAppendingPathComponent: BundleID]; + PLCrashReportFolder = FString(PLCrashReportFolderPath); + } + return PLCrashReportFolder; + } + + static FString TemporaryCrashReportName() + { + static FString PLCrashReportFileName(RunGUID().ToString() + TEXT(".plcrash")); + return PLCrashReportFileName; + } + + bool bIsSandboxed; + int32 NumCores; + char AppNameUTF8[PATH_MAX+1]; + char AppLogPath[PATH_MAX+1]; + char CrashReportPath[PATH_MAX+1]; + char PLCrashReportPath[PATH_MAX+1]; + char OSVersionUTF8[PATH_MAX+1]; + char MachineName[PATH_MAX+1]; + char MachineCPUString[PATH_MAX+1]; + FString AppPath; + FString AppName; + FString AppBundleID; + FString OSVersion; + FString OSBuild; + FString MachineUUID; + FString MachineModel; + FString BiosRelease; + FString BiosRevision; + FString BiosUUID; + FString ParentProcess; + FString LCID; + FString CommandLine; + FString BranchBaseDir; + FString PrimaryGPU; + FString ExecutableName; + NSOperatingSystemVersion OSXVersion; + FGuid RunUUID; + FString XcodePath; +#if !PLATFORM_TVOS + static PLCrashReporter* CrashReporter; +#endif + static FIOSMallocCrashHandler* CrashMalloc; +}; + +static FIOSApplicationInfo GIOSAppInfo; +#if !PLATFORM_TVOS +PLCrashReporter* FIOSApplicationInfo::CrashReporter = nullptr; +#endif +FIOSMallocCrashHandler* FIOSApplicationInfo::CrashMalloc = nullptr; + +void (*GCrashHandlerPointer)(const FGenericCrashContext& Context) = NULL; + +// good enough default crash reporter +static void DefaultCrashHandler(FIOSCrashContext const& Context) +{ + Context.ReportCrash(); + if (GLog) + { + GLog->SetCurrentThreadAsMasterThread(); + GLog->Flush(); + } + if (GWarn) + { + GWarn->Flush(); + } + if (GError) + { + GError->Flush(); + GError->HandleError(); + } + return Context.GenerateCrashInfo(); +} + +// number of stack entries to ignore in backtrace +static uint32 GIOSStackIgnoreDepth = 6; + +// true system specific crash handler that gets called first +static void PlatformCrashHandler(int32 Signal, siginfo_t* Info, void* Context) +{ + FIOSCrashContext CrashContext; + CrashContext.IgnoreDepth = GIOSStackIgnoreDepth; + CrashContext.InitFromSignal(Signal, Info, Context); + + // switch to crash handler malloc to avoid malloc reentrancy + check(FIOSApplicationInfo::CrashMalloc); + FIOSApplicationInfo::CrashMalloc->Enable(&CrashContext, FPlatformTLS::GetCurrentThreadId()); + + if (GCrashHandlerPointer) + { + GCrashHandlerPointer(CrashContext); + } + else + { + // call default one + DefaultCrashHandler(CrashContext); + } +} + +static void PLCrashReporterHandler(siginfo_t* Info, ucontext_t* Uap, void* Context) +{ + PlatformCrashHandler((int32)Info->si_signo, Info, Uap); +} + +// handles graceful termination. +static void GracefulTerminationHandler(int32 Signal, siginfo_t* Info, void* Context) +{ + // make sure we write out as much as possible + if (GLog) + { + GLog->Flush(); + } + if (GWarn) + { + GWarn->Flush(); + } + if (GError) + { + GError->Flush(); + } + + if (!GIsRequestingExit) + { + GIsRequestingExit = 1; + } + else + { + _Exit(0); + } +} + +void FIOSPlatformMisc::PlatformPreInit() +{ + FGenericPlatformMisc::PlatformPreInit(); + + GIOSAppInfo.Init(); + + // turn off SIGPIPE crashes + signal(SIGPIPE, SIG_IGN); +} + +void FIOSPlatformMisc::SetGracefulTerminationHandler() +{ + struct sigaction Action; + FMemory::Memzero(&Action, sizeof(struct sigaction)); + Action.sa_sigaction = GracefulTerminationHandler; + sigemptyset(&Action.sa_mask); + Action.sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK; + sigaction(SIGINT, &Action, NULL); + sigaction(SIGTERM, &Action, NULL); + sigaction(SIGHUP, &Action, NULL); +} + +void FIOSPlatformMisc::SetCrashHandler(void (* CrashHandler)(const FGenericCrashContext& Context)) +{ + SCOPED_AUTORELEASE_POOL; + + GCrashHandlerPointer = CrashHandler; + +#if !PLATFORM_TVOS + if (!FIOSApplicationInfo::CrashReporter && !FIOSApplicationInfo::CrashMalloc) + { + // configure the crash handler malloc zone to reserve a little memory for itself + FIOSApplicationInfo::CrashMalloc = new FIOSMallocCrashHandler(128*1024); + + PLCrashReporterConfig* Config = [[[PLCrashReporterConfig alloc] initWithSignalHandlerType: PLCrashReporterSignalHandlerTypeBSD symbolicationStrategy: PLCrashReporterSymbolicationStrategyNone crashReportFolder: FIOSApplicationInfo::TemporaryCrashReportFolder().GetNSString() crashReportName: FIOSApplicationInfo::TemporaryCrashReportName().GetNSString()] autorelease]; + FIOSApplicationInfo::CrashReporter = [[PLCrashReporter alloc] initWithConfiguration: Config]; + + PLCrashReporterCallbacks CrashReportCallback = { + .version = 0, + .context = nullptr, + .handleSignal = PLCrashReporterHandler + }; + + [FIOSApplicationInfo::CrashReporter setCrashCallbacks: &CrashReportCallback]; + + NSError* Error = nil; + if ([FIOSApplicationInfo::CrashReporter enableCrashReporterAndReturnError: &Error]) + { + GIOSStackIgnoreDepth = 0; + } + else + { + UE_LOG(LogIOS, Log, TEXT("Failed to enable PLCrashReporter: %s"), *FString([Error localizedDescription])); + UE_LOG(LogIOS, Log, TEXT("Falling back to native signal handlers")); + + struct sigaction Action; + FMemory::Memzero(&Action, sizeof(struct sigaction)); + Action.sa_sigaction = PlatformCrashHandler; + sigemptyset(&Action.sa_mask); + Action.sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK; + sigaction(SIGQUIT, &Action, NULL); + sigaction(SIGILL, &Action, NULL); + sigaction(SIGEMT, &Action, NULL); + sigaction(SIGFPE, &Action, NULL); + sigaction(SIGBUS, &Action, NULL); + sigaction(SIGSEGV, &Action, NULL); + sigaction(SIGSYS, &Action, NULL); + sigaction(SIGABRT, &Action, NULL); + } + } +#endif +} + +void FIOSCrashContext::GenerateWindowsErrorReport(char const* WERPath, bool bIsEnsure) const +{ + int ReportFile = open(WERPath, O_CREAT|O_WRONLY, 0766); + if (ReportFile != -1) + { + TCHAR Line[PATH_MAX] = {}; + + // write BOM + static uint16 ByteOrderMarker = 0xFEFF; + write(ReportFile, &ByteOrderMarker, sizeof(ByteOrderMarker)); + + WriteLine(ReportFile, TEXT("")); + WriteLine(ReportFile, TEXT("")); + + WriteLine(ReportFile, TEXT("\t")); + WriteUTF16String(ReportFile, TEXT("\t\t")); + WriteUTF16String(ReportFile, *GIOSAppInfo.OSVersion); + WriteLine(ReportFile, TEXT("")); + + WriteUTF16String(ReportFile, TEXT("\t\t")); + WriteUTF16String(ReportFile, *GIOSAppInfo.OSVersion); + WriteUTF16String(ReportFile, TEXT(" (")); + WriteUTF16String(ReportFile, *GIOSAppInfo.OSBuild); + WriteLine(ReportFile, TEXT(")")); + + WriteUTF16String(ReportFile, TEXT("\t\t(0x30): IOS ")); + WriteUTF16String(ReportFile, *GIOSAppInfo.OSVersion); + WriteLine(ReportFile, TEXT("")); + + WriteLine(ReportFile, TEXT("\t\tIOS")); + + WriteUTF16String(ReportFile, TEXT("\t\tIOS ")); + WriteUTF16String(ReportFile, *GIOSAppInfo.OSVersion); + WriteUTF16String(ReportFile, TEXT(" (")); + WriteUTF16String(ReportFile, *GIOSAppInfo.OSBuild); + WriteLine(ReportFile, TEXT(")")); + + WriteUTF16String(ReportFile, TEXT("\t\t")); + WriteUTF16String(ReportFile, *GIOSAppInfo.OSBuild); + WriteLine(ReportFile, TEXT("")); + + WriteLine(ReportFile, TEXT("\t\tMultiprocessor Free")); + WriteLine(ReportFile, TEXT("\t\tX64")); + WriteUTF16String(ReportFile, TEXT("\t\t")); + WriteUTF16String(ReportFile, *GIOSAppInfo.LCID); + WriteLine(ReportFile, TEXT("")); + WriteLine(ReportFile, TEXT("\t")); + + WriteLine(ReportFile, TEXT("\t")); + + WriteUTF16String(ReportFile, TEXT("\t\t")); + WriteUTF16String(ReportFile, ItoTCHAR(getppid(), 10)); + WriteLine(ReportFile, TEXT("")); + + WriteUTF16String(ReportFile, TEXT("\t\t")); + WriteUTF16String(ReportFile, *GIOSAppInfo.ParentProcess); + WriteLine(ReportFile, TEXT("")); + + WriteLine(ReportFile, TEXT("\t\t")); // FIXME: supply valid? + WriteLine(ReportFile, TEXT("\t")); + + WriteLine(ReportFile, TEXT("\t")); + WriteLine(ReportFile, TEXT("\t\tAPPCRASH")); + + WriteUTF16String(ReportFile, TEXT("\t\tUE4-")); + WriteUTF16String(ReportFile, *GIOSAppInfo.AppName); + WriteLine(ReportFile, TEXT("")); + + WriteUTF16String(ReportFile, TEXT("\t\t")); + WriteUTF16String(ReportFile, ItoTCHAR(FEngineVersion::Current().GetMajor(), 10)); + WriteUTF16String(ReportFile, TEXT(".")); + WriteUTF16String(ReportFile, ItoTCHAR(FEngineVersion::Current().GetMinor(), 10)); + WriteUTF16String(ReportFile, TEXT(".")); + WriteUTF16String(ReportFile, ItoTCHAR(FEngineVersion::Current().GetPatch(), 10)); + WriteLine(ReportFile, TEXT("")); + + // App time stamp + WriteLine(ReportFile, TEXT("\t\t528f2d37")); // FIXME: supply valid? + + Dl_info DLInfo; + if(Info && Info->si_addr != 0 && dladdr(Info->si_addr, &DLInfo) != 0) + { + // Crash Module name + WriteUTF16String(ReportFile, TEXT("\t\t")); + if (DLInfo.dli_fname && FCStringAnsi::Strlen(DLInfo.dli_fname)) + { + FMemory::Memzero(Line, PATH_MAX * sizeof(TCHAR)); + FUTF8ToTCHAR_Convert::Convert(Line, PATH_MAX, DLInfo.dli_fname, FCStringAnsi::Strlen(DLInfo.dli_fname)); + WriteUTF16String(ReportFile, Line); + } + else + { + WriteUTF16String(ReportFile, TEXT("Unknown")); + } + WriteLine(ReportFile, TEXT("")); + + // Check header + uint32 Version = 0; + uint32 TimeStamp = 0; + struct mach_header_64* Header = (struct mach_header_64*)DLInfo.dli_fbase; + struct load_command *CurrentCommand = (struct load_command *)( (char *)Header + sizeof(struct mach_header_64) ); + if( Header->magic == MH_MAGIC_64 ) + { + for( int32 i = 0; i < Header->ncmds; i++ ) + { + if( CurrentCommand->cmd == LC_LOAD_DYLIB ) + { + struct dylib_command *DylibCommand = (struct dylib_command *) CurrentCommand; + Version = DylibCommand->dylib.current_version; + TimeStamp = DylibCommand->dylib.timestamp; + Version = ((Version & 0xff) + ((Version >> 8) & 0xff) * 100 + ((Version >> 16) & 0xffff) * 10000); + break; + } + + CurrentCommand = (struct load_command *)( (char *)CurrentCommand + CurrentCommand->cmdsize ); + } + } + + // Module version + WriteUTF16String(ReportFile, TEXT("\t\t")); + WriteUTF16String(ReportFile, ItoTCHAR(Version, 10)); + WriteLine(ReportFile, TEXT("")); + + // Module time stamp + WriteUTF16String(ReportFile, TEXT("\t\t")); + WriteUTF16String(ReportFile, ItoTCHAR(TimeStamp, 16)); + WriteLine(ReportFile, TEXT("")); + + // MethodDef token -> no equivalent + WriteLine(ReportFile, TEXT("\t\t00000001")); + + // IL Offset -> Function pointer + WriteUTF16String(ReportFile, TEXT("\t\t")); + WriteUTF16String(ReportFile, ItoTCHAR((uint64)Info->si_addr, 16)); + WriteLine(ReportFile, TEXT("")); + } + + // Command line, must match the Windows version. + WriteUTF16String(ReportFile, TEXT("\t\t!")); + WriteUTF16String(ReportFile, FCommandLine::GetOriginal()); + WriteLine(ReportFile, TEXT("!")); + + WriteUTF16String(ReportFile, TEXT("\t\t")); + WriteUTF16String(ReportFile, *GIOSAppInfo.BranchBaseDir); + WriteLine(ReportFile, TEXT("")); + + WriteLine(ReportFile, TEXT("\t")); + + WriteLine(ReportFile, TEXT("\t")); + + WriteUTF16String(ReportFile, TEXT("\t\t")); + WriteUTF16String(ReportFile, *GIOSAppInfo.BiosUUID); + WriteLine(ReportFile, TEXT("")); + + WriteUTF16String(ReportFile, TEXT("\t\t")); + WriteUTF16String(ReportFile, *GIOSAppInfo.LCID); + WriteLine(ReportFile, TEXT("")); + WriteLine(ReportFile, *FString::Printf(TEXT("\t\t%s"), FApp::GetDeploymentName())); + WriteLine(ReportFile, *FString::Printf(TEXT("\t\t%s"), bIsEnsure ? TEXT("1") : TEXT("0"))); + WriteLine(ReportFile, *FString::Printf(TEXT("\t\t%s"), FDebug::bHasAsserted ? TEXT("1") : TEXT("0"))); + WriteLine(ReportFile, *FString::Printf(TEXT("\t\t%s"), FGenericCrashContext::GetCrashTypeString(bIsEnsure, FDebug::bHasAsserted))); + WriteLine(ReportFile, *FString::Printf(TEXT("\t\t%s"), FApp::GetBuildVersion())); + WriteLine(ReportFile, *FString::Printf(TEXT("\t\t%s"), FGenericCrashContext::EngineModeExString())); + + WriteLine(ReportFile, TEXT("\t")); + + WriteLine(ReportFile, TEXT("\t")); + + WriteUTF16String(ReportFile, TEXT("\t\t")); + WriteUTF16String(ReportFile, *GIOSAppInfo.MachineUUID); + WriteLine(ReportFile, TEXT("")); + + WriteLine(ReportFile, TEXT("\t\tApple Inc.")); + + WriteUTF16String(ReportFile, TEXT("\t\t")); + WriteUTF16String(ReportFile, *GIOSAppInfo.MachineModel); + WriteLine(ReportFile, TEXT("")); + + WriteUTF16String(ReportFile, TEXT("\t\t")); + WriteUTF16String(ReportFile, *GIOSAppInfo.BiosRelease); + WriteUTF16String(ReportFile, TEXT("-")); + WriteUTF16String(ReportFile, *GIOSAppInfo.BiosRevision); + WriteLine(ReportFile, TEXT("")); + + WriteUTF16String(ReportFile, TEXT("\t\t")); + WriteUTF16String(ReportFile, *GIOSAppInfo.PrimaryGPU); + WriteLine(ReportFile, TEXT("")); + + WriteLine(ReportFile, TEXT("\t")); + + WriteLine(ReportFile, TEXT("")); + + close(ReportFile); + } +} + +void FIOSCrashContext::CopyMinidump(char const* OutputPath, char const* InputPath) const +{ +#if !PLATFORM_TVOS + NSError* Error = nil; + NSString* Path = FString(ANSI_TO_TCHAR(InputPath)).GetNSString(); + NSData* CrashData = [NSData dataWithContentsOfFile: Path options: NSMappedRead error: &Error]; + if (CrashData && !Error) + { + PLCrashReport* CrashLog = [[PLCrashReport alloc] initWithData: CrashData error: &Error]; + if (CrashLog && !Error) + { + NSString* Report = [PLCrashReportTextFormatter stringValueForCrashReport: CrashLog withTextFormat: PLCrashReportTextFormatiOS]; + FString CrashDump = FString(Report); + [Report writeToFile: Path atomically: YES encoding: NSUTF8StringEncoding error: &Error]; + } + else + { + NSLog(@"****UE4 %@", [Error localizedDescription]); + } + } + else + { + NSLog(@"****UE4 %@", [Error localizedDescription]); + } + int ReportFile = open(OutputPath, O_CREAT|O_WRONLY, 0766); + int DumpFile = open(InputPath, O_RDONLY, 0766); + if (ReportFile != -1 && DumpFile != -1) + { + char Data[PATH_MAX]; + + int Bytes = 0; + while((Bytes = read(DumpFile, Data, PATH_MAX)) > 0) + { + write(ReportFile, Data, Bytes); + } + + close(DumpFile); + close(ReportFile); + + unlink(InputPath); + } +#endif +} + +void FIOSCrashContext::GenerateInfoInFolder(char const* const InfoFolder, bool bIsEnsure) const +{ + // create a crash-specific directory + char CrashInfoFolder[PATH_MAX] = {}; + FCStringAnsi::Strncpy(CrashInfoFolder, InfoFolder, PATH_MAX); + + if(!mkdir(CrashInfoFolder, 0766)) + { + char FilePath[PATH_MAX] = {}; + FCStringAnsi::Strncpy(FilePath, CrashInfoFolder, PATH_MAX); + FCStringAnsi::Strcat(FilePath, PATH_MAX, "/report.wer"); + int ReportFile = open(FilePath, O_CREAT|O_WRONLY, 0766); + if (ReportFile != -1) + { + // write BOM + static uint16 ByteOrderMarker = 0xFEFF; + write(ReportFile, &ByteOrderMarker, sizeof(ByteOrderMarker)); + + WriteUTF16String(ReportFile, TEXT("\r\nAppPath=")); + WriteUTF16String(ReportFile, *GIOSAppInfo.AppPath); + WriteLine(ReportFile, TEXT("\r\n")); + + close(ReportFile); + } + + // generate "WER" + FCStringAnsi::Strncpy(FilePath, CrashInfoFolder, PATH_MAX); + FCStringAnsi::Strcat(FilePath, PATH_MAX, "/wermeta.xml"); + GenerateWindowsErrorReport(FilePath, bIsEnsure); + + // generate "minidump" (Apple crash log format) + FCStringAnsi::Strncpy(FilePath, CrashInfoFolder, PATH_MAX); + FCStringAnsi::Strcat(FilePath, PATH_MAX, "/minidump.dmp"); + CopyMinidump(FilePath, GIOSAppInfo.PLCrashReportPath); + + // generate "info.txt" custom data for our server + FCStringAnsi::Strncpy(FilePath, CrashInfoFolder, PATH_MAX); + FCStringAnsi::Strcat(FilePath, PATH_MAX, "/info.txt"); + ReportFile = open(FilePath, O_CREAT|O_WRONLY, 0766); + if (ReportFile != -1) + { + WriteUTF16String(ReportFile, TEXT("GameName UE4-")); + WriteLine(ReportFile, *GIOSAppInfo.AppName); + + WriteUTF16String(ReportFile, TEXT("BuildVersion 1.0.")); + WriteUTF16String(ReportFile, ItoTCHAR(FEngineVersion::Current().GetChangelist() >> 16, 10)); + WriteUTF16String(ReportFile, TEXT(".")); + WriteLine(ReportFile, ItoTCHAR(FEngineVersion::Current().GetChangelist() & 0xffff, 10)); + + WriteUTF16String(ReportFile, TEXT("CommandLine ")); + WriteLine(ReportFile, *GIOSAppInfo.CommandLine); + + WriteUTF16String(ReportFile, TEXT("BaseDir ")); + WriteLine(ReportFile, *GIOSAppInfo.BranchBaseDir); + + WriteUTF16String(ReportFile, TEXT("MachineGuid ")); + WriteLine(ReportFile, *GIOSAppInfo.MachineUUID); + + close(ReportFile); + } + + // Introduces a new runtime crash context. Will replace all Windows related crash reporting. + FCStringAnsi::Strncpy(FilePath, CrashInfoFolder, PATH_MAX); + FCStringAnsi::Strcat(FilePath, PATH_MAX, "/" ); + FCStringAnsi::Strcat(FilePath, PATH_MAX, FGenericCrashContext::CrashContextRuntimeXMLNameA ); + //SerializeAsXML( FilePath ); @todo uncomment after verification - need to do a bit more work on this for macOS + + // copy log + FCStringAnsi::Strncpy(FilePath, CrashInfoFolder, PATH_MAX); + FCStringAnsi::Strcat(FilePath, PATH_MAX, "/"); + FCStringAnsi::Strcat(FilePath, PATH_MAX, (!GIOSAppInfo.AppName.IsEmpty() ? GIOSAppInfo.AppNameUTF8 : "UE4")); + FCStringAnsi::Strcat(FilePath, PATH_MAX, ".log"); + + int LogSrc = open(GIOSAppInfo.AppLogPath, O_RDONLY); + int LogDst = open(FilePath, O_CREAT|O_WRONLY, 0766); + + char Data[PATH_MAX] = {}; + int Bytes = 0; + while((Bytes = read(LogSrc, Data, PATH_MAX)) > 0) + { + write(LogDst, Data, Bytes); + } + + // If present, include the crash report config file to pass config values to the CRC + FCStringAnsi::Strncpy(FilePath, CrashInfoFolder, PATH_MAX); + FCStringAnsi::Strcat(FilePath, PATH_MAX, "/"); + FCStringAnsi::Strcat(FilePath, PATH_MAX, FGenericCrashContext::CrashConfigFileNameA); + int ConfigSrc = open(TCHAR_TO_ANSI(GetCrashConfigFilePath()), O_RDONLY); + int ConfigDst = open(FilePath, O_CREAT | O_WRONLY, 0766); + + while ((Bytes = read(ConfigSrc, Data, PATH_MAX)) > 0) + { + write(ConfigDst, Data, Bytes); + } + + close(ConfigDst); + close(ConfigSrc); + + close(LogDst); + close(LogSrc); + // best effort, so don't care about result: couldn't copy -> tough, no log + } + else + { + NSLog(@"******* UE4 - Failed to make folder: %s", CrashInfoFolder); + } +} + +void FIOSCrashContext::GenerateCrashInfo() const +{ + // create a crash-specific directory + char CrashInfoFolder[PATH_MAX] = {}; + FCStringAnsi::Strncpy(CrashInfoFolder, GIOSAppInfo.CrashReportPath, PATH_MAX); + FCStringAnsi::Strcat(CrashInfoFolder, PATH_MAX, "/CrashReport-UE4-"); + FCStringAnsi::Strcat(CrashInfoFolder, PATH_MAX, GIOSAppInfo.AppNameUTF8); + FCStringAnsi::Strcat(CrashInfoFolder, PATH_MAX, "-pid-"); + FCStringAnsi::Strcat(CrashInfoFolder, PATH_MAX, ItoANSI(getpid(), 10)); + FCStringAnsi::Strcat(CrashInfoFolder, PATH_MAX, "-"); + FCStringAnsi::Strcat(CrashInfoFolder, PATH_MAX, ItoANSI(GIOSAppInfo.RunUUID.A, 16)); + FCStringAnsi::Strcat(CrashInfoFolder, PATH_MAX, ItoANSI(GIOSAppInfo.RunUUID.B, 16)); + FCStringAnsi::Strcat(CrashInfoFolder, PATH_MAX, ItoANSI(GIOSAppInfo.RunUUID.C, 16)); + FCStringAnsi::Strcat(CrashInfoFolder, PATH_MAX, ItoANSI(GIOSAppInfo.RunUUID.D, 16)); + + const bool bIsEnsure = false; + GenerateInfoInFolder(CrashInfoFolder, bIsEnsure); + + // for IOS we will need to send the report on the next run + + // Sandboxed applications re-raise the signal to trampoline into the system crash reporter as suppressing it may fall foul of Apple's Mac App Store rules. + // @todo Submit an application to the MAS & see whether Apple's reviewers highlight our crash reporting or trampolining to the system reporter. + if(GIOSAppInfo.bIsSandboxed) + { + struct sigaction Action; + FMemory::Memzero(&Action, sizeof(struct sigaction)); + Action.sa_handler = SIG_DFL; + sigemptyset(&Action.sa_mask); + sigaction(SIGQUIT, &Action, NULL); + sigaction(SIGILL, &Action, NULL); + sigaction(SIGEMT, &Action, NULL); + sigaction(SIGFPE, &Action, NULL); + sigaction(SIGBUS, &Action, NULL); + sigaction(SIGSEGV, &Action, NULL); + sigaction(SIGSYS, &Action, NULL); + sigaction(SIGABRT, &Action, NULL); + sigaction(SIGTRAP, &Action, NULL); + + raise(Signal); + } + + _Exit(0); +} + +void FIOSCrashContext::GenerateEnsureInfo() const +{ + // Prevent CrashReportClient from spawning another CrashReportClient. + const bool bCanRunCrashReportClient = FCString::Stristr( *(GIOSAppInfo.ExecutableName), TEXT( "CrashReportClient" ) ) == nullptr; + +#if !PLATFORM_TVOS + if(bCanRunCrashReportClient) + { + SCOPED_AUTORELEASE_POOL; + + // Write the PLCrashReporter report to the expected location + NSData* CrashReport = [FIOSApplicationInfo::CrashReporter generateLiveReport]; + [CrashReport writeToFile:[NSString stringWithUTF8String:GIOSAppInfo.PLCrashReportPath] atomically:YES]; + + // Use a slightly different output folder name to not conflict with a subequent crash + const FGuid Guid = FGuid::NewGuid(); + FString GameName = FApp::GetGameName(); + FString EnsureLogFolder = FString(GIOSAppInfo.CrashReportPath) / FString::Printf(TEXT("EnsureReport-%s-%s"), *GameName, *Guid.ToString(EGuidFormats::Digits)); + + const bool bIsEnsure = true; + GenerateInfoInFolder(TCHAR_TO_UTF8(*EnsureLogFolder), bIsEnsure); + + FString Arguments; + if (IsInteractiveEnsureMode()) + { + Arguments = FString::Printf(TEXT("\"%s/\""), *EnsureLogFolder); + } + else + { + Arguments = FString::Printf(TEXT("\"%s/\" -Unattended"), *EnsureLogFolder); + } + + FString ReportClient = FPaths::ConvertRelativePathToFull(FPlatformProcess::GenerateApplicationPath(TEXT("CrashReportClient"), EBuildConfigurations::Development)); + FPlatformProcess::ExecProcess(*ReportClient, *Arguments, nullptr, nullptr, nullptr); + } +#endif +} + +static FCriticalSection EnsureLock; +static bool bReentranceGuard = false; + +void NewReportEnsure( const TCHAR* ErrorMessage ) +{ + // Simple re-entrance guard. + EnsureLock.Lock(); + + if( bReentranceGuard ) + { + EnsureLock.Unlock(); + return; + } + + bReentranceGuard = true; + +#if !PLATFORM_TVOS + if(FIOSApplicationInfo::CrashReporter != nil) + { + siginfo_t Signal; + Signal.si_signo = SIGTRAP; + Signal.si_code = TRAP_TRACE; + Signal.si_addr = __builtin_return_address(0); + + FIOSCrashContext EnsureContext; + EnsureContext.InitFromSignal(SIGTRAP, &Signal, nullptr); + EnsureContext.GenerateEnsureInfo(); + } +#endif + + bReentranceGuard = false; + EnsureLock.Unlock(); +} diff --git a/Engine/Source/Runtime/Core/Private/IOS/IOSPlatformProcess.cpp b/Engine/Source/Runtime/Core/Private/IOS/IOSPlatformProcess.cpp index 239cdf752c19..acee328a2c06 100644 --- a/Engine/Source/Runtime/Core/Private/IOS/IOSPlatformProcess.cpp +++ b/Engine/Source/Runtime/Core/Private/IOS/IOSPlatformProcess.cpp @@ -135,6 +135,32 @@ const TCHAR* FIOSPlatformProcess::ExecutableName(bool bRemoveExtension) return Result; } +FString FIOSPlatformProcess::GenerateApplicationPath( const FString& AppName, EBuildConfigurations::Type BuildConfiguration) +{ + SCOPED_AUTORELEASE_POOL; + + FString PlatformName = TEXT("IOS"); + FString ExecutableName = AppName; + if (BuildConfiguration != EBuildConfigurations::Development && BuildConfiguration != EBuildConfigurations::DebugGame) + { + ExecutableName += FString::Printf(TEXT("-%s-%s"), *PlatformName, EBuildConfigurations::ToString(BuildConfiguration)); + } + + NSURL* CurrentBundleURL = [[NSBundle mainBundle] bundleURL]; + NSString* CurrentBundleName = [[CurrentBundleURL lastPathComponent] stringByDeletingPathExtension]; + if(FString(CurrentBundleName) == ExecutableName) + { + CFStringRef FilePath = CFURLCopyFileSystemPath((CFURLRef)CurrentBundleURL, kCFURLPOSIXPathStyle); + FString ExecutablePath = FString::Printf(TEXT("%s/%s"), *FString((NSString*)FilePath), *ExecutableName); + CFRelease(FilePath); + return ExecutablePath; + } + else + { + return FString(); + } +} + const uint64 FIOSPlatformAffinity::GetMainGameMask() { return MAKEAFFINITYMASK1(0); diff --git a/Engine/Source/Runtime/Core/Private/IOS/IOSView.cpp b/Engine/Source/Runtime/Core/Private/IOS/IOSView.cpp index 57f5c55209c0..a24d9817ef15 100644 --- a/Engine/Source/Runtime/Core/Private/IOS/IOSView.cpp +++ b/Engine/Source/Runtime/Core/Private/IOS/IOSView.cpp @@ -8,6 +8,7 @@ #include "Misc/ConfigCacheIni.h" #include "HAL/IConsoleManager.h" #include "Misc/CommandLine.h" +#include "IOSPlatformProcess.h" #include #import "IOSAsyncTask.h" @@ -76,6 +77,10 @@ id GMetalDevice = nil; @implementation FIOSView +@synthesize keyboardType = KeyboardType; +@synthesize autocorrectionType = AutocorrectionType; +@synthesize autocapitalizationType = AutocapitalizationType; +@synthesize secureTextEntry = bSecureTextEntry; @synthesize SwapCount, OnScreenColorRenderBuffer, OnScreenColorRenderBufferMSAA, markedTextStyle; /** @@ -492,6 +497,16 @@ id GMetalDevice = nil; TouchMessage.LastPosition = FVector2D(FMath::Min(self.frame.size.width - 1, PrevLoc.x), FMath::Min(self.frame.size.height - 1, PrevLoc.y)) * Scale; TouchesArray.Add(TouchMessage); + if (Type == TouchBegan) + { + TouchInput EmulatedMessage; + EmulatedMessage.Handle = TouchMessage.Handle; + EmulatedMessage.Type = TouchMoved; + EmulatedMessage.Position = TouchMessage.Position; + EmulatedMessage.LastPosition = TouchMessage.Position; + TouchesArray.Add(EmulatedMessage); + } + // clear out the touch when it ends if (Type == TouchEnded) { @@ -527,7 +542,8 @@ id GMetalDevice = nil; if (bShowConsole) { - if (bIsUsingIntegratedKeyboard) + // disable the integrated keyboard when launching the console +/* if (bIsUsingIntegratedKeyboard) { // press the console key twice to get the big one up // @todo keyboard: Find a direct way to bering this up (it can get into a bad state where two presses won't do it correctly) @@ -537,7 +553,7 @@ id GMetalDevice = nil; [self ActivateKeyboard:true]; } - else + else*/ { // Route the command to the main iOS thread (all UI must go to the main thread) [[IOSAppDelegate GetDelegate] performSelectorOnMainThread:@selector(ShowConsole) withObject:nil waitUntilDone:NO]; @@ -617,17 +633,67 @@ id GMetalDevice = nil; FIOSInputInterface::QueueKeyInput(KEYCODE_BACKSPACE, '\b'); } - -(void)ActivateKeyboard:(bool)bInSendEscapeOnClose { - // remember the setting - bSendEscapeOnClose = bInSendEscapeOnClose; - [self becomeFirstResponder]; + FKeyboardConfig DefaultConfig; + [self ActivateKeyboard:bInSendEscapeOnClose keyboardConfig:DefaultConfig]; +} + +-(void)ActivateKeyboard:(bool)bInSendEscapeOnClose keyboardConfig:(FKeyboardConfig)KeyboardConfig +{ + FPlatformAtomics::InterlockedIncrement(&KeyboardShowCount); + + dispatch_async(dispatch_get_main_queue(),^ { + volatile int32 ShowCount = KeyboardShowCount; + if (ShowCount == 1) + { + self.keyboardType = KeyboardConfig.KeyboardType; + self.autocorrectionType = KeyboardConfig.AutocorrectionType; + self.autocapitalizationType = KeyboardConfig.AutocapitalizationType; + self.secureTextEntry = KeyboardConfig.bSecureTextEntry; + + // Remember the setting + bSendEscapeOnClose = bInSendEscapeOnClose; + + // Dismiss the existing keyboard, if one exists, so the style can be overridden. + [self endEditing:YES]; + [self becomeFirstResponder]; + } + + FPlatformAtomics::InterlockedDecrement(&KeyboardShowCount); + }); +} + +-(void)DeactivateKeyboard +{ + dispatch_async(dispatch_get_main_queue(),^ { + volatile int32 ShowCount = KeyboardShowCount; + if (ShowCount == 0) + { + // Wait briefly, in case a keyboard activation is triggered. + FPlatformProcess::Sleep(0.1F); + + ShowCount = KeyboardShowCount; + if (ShowCount == 0) + { + // Dismiss the existing keyboard, if one exists. + [self endEditing:YES]; + } + } + }); } -(BOOL)becomeFirstResponder { - return [super becomeFirstResponder]; + volatile int32 ShowCount = KeyboardShowCount; + if (ShowCount >= 1) + { + return [super becomeFirstResponder]; + } + else + { + return NO; + } } -(BOOL)resignFirstResponder @@ -888,8 +954,13 @@ id GMetalDevice = nil; - (void)InitKeyboard { #if !PLATFORM_TVOS + KeyboardShowCount = 0; + + bool bUseIntegratedKeyboard = false; + GConfig->GetBool(TEXT("/Script/IOSRuntimeSettings.IOSRuntimeSettings"), TEXT("bUseIntegratedKeyboard"), bUseIntegratedKeyboard, GEngineIni); + // get notifications when the keyboard is in view - bIsUsingIntegratedKeyboard = FParse::Param(FCommandLine::Get(), TEXT("NewKeyboard")); + bIsUsingIntegratedKeyboard = FParse::Param(FCommandLine::Get(), TEXT("NewKeyboard")) || bUseIntegratedKeyboard; if (bIsUsingIntegratedKeyboard) { [[NSNotificationCenter defaultCenter] addObserver:self diff --git a/Engine/Source/Runtime/Core/Private/IOS/IOSWindow.cpp b/Engine/Source/Runtime/Core/Private/IOS/IOSWindow.cpp index f5dd37aec4f5..a81e6ab93db0 100644 --- a/Engine/Source/Runtime/Core/Private/IOS/IOSWindow.cpp +++ b/Engine/Source/Runtime/Core/Private/IOS/IOSWindow.cpp @@ -51,6 +51,7 @@ void FIOSWindow::Initialize( class FIOSApplication* const Application, const TSh else #endif { +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0 UIAlertView* AlertView = [[UIAlertView alloc] initWithTitle:@"" message:@"Error: Only one UIWindow may be created on iOS." delegate:nil @@ -59,6 +60,7 @@ void FIOSWindow::Initialize( class FIOSApplication* const Application, const TSh [AlertView show]; [AlertView release]; +#endif } } ); } diff --git a/Engine/Source/Runtime/Core/Private/Internationalization/FastDecimalFormat.cpp b/Engine/Source/Runtime/Core/Private/Internationalization/FastDecimalFormat.cpp index c750d59ff1e7..2a6fa983730e 100644 --- a/Engine/Source/Runtime/Core/Private/Internationalization/FastDecimalFormat.cpp +++ b/Engine/Source/Runtime/Core/Private/Internationalization/FastDecimalFormat.cpp @@ -38,6 +38,10 @@ static_assert(ARRAY_COUNT(Pow10Table) - 1 >= MaxFractionalPrintPrecision, "Pow10 void SanitizeNumberFormattingOptions(FNumberFormattingOptions& InOutFormattingOptions) { + // Ensure that the minimum limits are >= 0 + InOutFormattingOptions.MinimumIntegralDigits = FMath::Max(0, InOutFormattingOptions.MinimumIntegralDigits); + InOutFormattingOptions.MinimumFractionalDigits = FMath::Max(0, InOutFormattingOptions.MinimumFractionalDigits); + // Ensure that the maximum limits are >= the minimum limits InOutFormattingOptions.MaximumIntegralDigits = FMath::Max(InOutFormattingOptions.MinimumIntegralDigits, InOutFormattingOptions.MaximumIntegralDigits); InOutFormattingOptions.MaximumFractionalDigits = FMath::Max(InOutFormattingOptions.MinimumFractionalDigits, InOutFormattingOptions.MaximumFractionalDigits); @@ -62,7 +66,7 @@ int32 IntegralToString_UInt64ToString( { // Perform the initial number -> string conversion uint64 TmpNum = InVal; - while (StringLen < InMaxDigitsToPrint && TmpNum != 0) + while (DigitsPrinted < InMaxDigitsToPrint && TmpNum != 0) { if (InUseGrouping && NumUntilNextGroup-- == 0) { diff --git a/Engine/Source/Runtime/Core/Private/Internationalization/ICUCulture.cpp b/Engine/Source/Runtime/Core/Private/Internationalization/ICUCulture.cpp index 7abd5ad1f1f4..e2d862d632e8 100644 --- a/Engine/Source/Runtime/Core/Private/Internationalization/ICUCulture.cpp +++ b/Engine/Source/Runtime/Core/Private/Internationalization/ICUCulture.cpp @@ -178,14 +178,16 @@ int FCulture::FICUCultureImplementation::GetLCID() const FString FCulture::FICUCultureImplementation::GetCanonicalName(const FString& Name) { - static const int32 MaximumNameLength = 64; - const int32 NameLength = Name.Len(); - check(NameLength < MaximumNameLength); - char CanonicalName[MaximumNameLength]; + const FString SanitizedName = ICUUtilities::SanitizeCultureCode(Name); + + static const int32 CanonicalNameBufferSize = 64; + char CanonicalNameBuffer[CanonicalNameBufferSize]; UErrorCode ICUStatus = U_ZERO_ERROR; - uloc_canonicalize(TCHAR_TO_ANSI( *Name ), CanonicalName, MaximumNameLength, &ICUStatus); - FString CanonicalNameString = CanonicalName; + uloc_canonicalize(TCHAR_TO_ANSI(*SanitizedName), CanonicalNameBuffer, CanonicalNameBufferSize-1, &ICUStatus); + CanonicalNameBuffer[CanonicalNameBufferSize-1] = 0; + + FString CanonicalNameString = CanonicalNameBuffer; CanonicalNameString.ReplaceInline(TEXT("_"), TEXT("-")); return CanonicalNameString; } @@ -417,7 +419,8 @@ TSharedRef FCulture::FICUCultureImplementation::GetCur ICUCurrencyFormat = CreateCurrencyFormat( ICULocale ); } - const bool bIsDefault = Options == NULL && CurrencyCode.IsEmpty(); + const FString SanitizedCurrencyCode = ICUUtilities::SanitizeCurrencyCode(CurrencyCode); + const bool bIsDefault = Options == NULL && SanitizedCurrencyCode.IsEmpty(); const TSharedRef DefaultFormatter( ICUCurrencyFormat.ToSharedRef() ); if(bIsDefault) @@ -431,7 +434,7 @@ TSharedRef FCulture::FICUCultureImplementation::GetCur if (!CurrencyCode.IsEmpty()) { icu::UnicodeString ICUCurrencyCode; - ICUUtilities::ConvertString(CurrencyCode, ICUCurrencyCode); + ICUUtilities::ConvertString(SanitizedCurrencyCode, ICUCurrencyCode); Formatter->setCurrency(ICUCurrencyCode.getBuffer()); } @@ -485,12 +488,14 @@ TSharedRef FCulture::FICUCultureImplementation::GetDateFo ICUDateFormat = CreateDateFormat( ICULocale ); } + const FString SanitizedTimezoneCode = ICUUtilities::SanitizeTimezoneCode(TimeZone); + icu::UnicodeString InputTimeZoneID; - ICUUtilities::ConvertString(TimeZone, InputTimeZoneID, false); + ICUUtilities::ConvertString(SanitizedTimezoneCode, InputTimeZoneID, false); const TSharedRef DefaultFormatter( ICUDateFormat.ToSharedRef() ); - bool bIsDefaultTimeZone = TimeZone.IsEmpty(); + bool bIsDefaultTimeZone = SanitizedTimezoneCode.IsEmpty(); if( !bIsDefaultTimeZone ) { UErrorCode ICUStatus = U_ZERO_ERROR; @@ -518,7 +523,7 @@ TSharedRef FCulture::FICUCultureImplementation::GetDateFo else { const TSharedRef Formatter( icu::DateFormat::createDateInstance( UEToICU(DateStyle), ICULocale ) ); - Formatter->adoptTimeZone( bIsDefaultTimeZone ? icu::TimeZone::createDefault() :icu::TimeZone::createTimeZone(InputTimeZoneID) ); + Formatter->adoptTimeZone( bIsDefaultTimeZone ? icu::TimeZone::createDefault() : icu::TimeZone::createTimeZone(InputTimeZoneID) ); return Formatter; } } @@ -530,12 +535,14 @@ TSharedRef FCulture::FICUCultureImplementation::GetTimeFo ICUTimeFormat = CreateTimeFormat( ICULocale ); } + const FString SanitizedTimezoneCode = ICUUtilities::SanitizeTimezoneCode(TimeZone); + icu::UnicodeString InputTimeZoneID; - ICUUtilities::ConvertString(TimeZone, InputTimeZoneID, false); + ICUUtilities::ConvertString(SanitizedTimezoneCode, InputTimeZoneID, false); const TSharedRef DefaultFormatter( ICUTimeFormat.ToSharedRef() ); - bool bIsDefaultTimeZone = TimeZone.IsEmpty(); + bool bIsDefaultTimeZone = SanitizedTimezoneCode.IsEmpty(); if( !bIsDefaultTimeZone ) { UErrorCode ICUStatus = U_ZERO_ERROR; @@ -563,7 +570,7 @@ TSharedRef FCulture::FICUCultureImplementation::GetTimeFo else { const TSharedRef Formatter( icu::DateFormat::createTimeInstance( UEToICU(TimeStyle), ICULocale ) ); - Formatter->adoptTimeZone( bIsDefaultTimeZone ? icu::TimeZone::createDefault() :icu::TimeZone::createTimeZone(InputTimeZoneID) ); + Formatter->adoptTimeZone( bIsDefaultTimeZone ? icu::TimeZone::createDefault() : icu::TimeZone::createTimeZone(InputTimeZoneID) ); return Formatter; } } @@ -575,12 +582,14 @@ TSharedRef FCulture::FICUCultureImplementation::GetDateTi ICUDateTimeFormat = CreateDateTimeFormat( ICULocale ); } + const FString SanitizedTimezoneCode = ICUUtilities::SanitizeTimezoneCode(TimeZone); + icu::UnicodeString InputTimeZoneID; - ICUUtilities::ConvertString(TimeZone, InputTimeZoneID, false); + ICUUtilities::ConvertString(SanitizedTimezoneCode, InputTimeZoneID, false); const TSharedRef DefaultFormatter( ICUDateTimeFormat.ToSharedRef() ); - bool bIsDefaultTimeZone = TimeZone.IsEmpty(); + bool bIsDefaultTimeZone = SanitizedTimezoneCode.IsEmpty(); if( !bIsDefaultTimeZone ) { UErrorCode ICUStatus = U_ZERO_ERROR; @@ -609,7 +618,7 @@ TSharedRef FCulture::FICUCultureImplementation::GetDateTi else { const TSharedRef Formatter( icu::DateFormat::createDateTimeInstance( UEToICU(DateStyle), UEToICU(TimeStyle), ICULocale ) ); - Formatter->adoptTimeZone( bIsDefaultTimeZone ? icu::TimeZone::createDefault() :icu::TimeZone::createTimeZone(InputTimeZoneID) ); + Formatter->adoptTimeZone( bIsDefaultTimeZone ? icu::TimeZone::createDefault() : icu::TimeZone::createTimeZone(InputTimeZoneID) ); return Formatter; } } @@ -739,7 +748,8 @@ const FDecimalNumberFormattingRules& FCulture::FICUCultureImplementation::GetPer const FDecimalNumberFormattingRules& FCulture::FICUCultureImplementation::GetCurrencyFormattingRules(const FString& InCurrencyCode) { - const bool bUseDefaultFormattingRules = InCurrencyCode.IsEmpty(); + const FString SanitizedCurrencyCode = ICUUtilities::SanitizeCurrencyCode(InCurrencyCode); + const bool bUseDefaultFormattingRules = SanitizedCurrencyCode.IsEmpty(); if (bUseDefaultFormattingRules) { @@ -752,7 +762,7 @@ const FDecimalNumberFormattingRules& FCulture::FICUCultureImplementation::GetCur { FScopeLock MapLock(&UEAlternateCurrencyFormattingRulesCS); - auto FoundUEAlternateCurrencyFormattingRules = UEAlternateCurrencyFormattingRules.FindRef(InCurrencyCode); + auto FoundUEAlternateCurrencyFormattingRules = UEAlternateCurrencyFormattingRules.FindRef(SanitizedCurrencyCode); if (FoundUEAlternateCurrencyFormattingRules.IsValid()) { return *FoundUEAlternateCurrencyFormattingRules; @@ -770,7 +780,7 @@ const FDecimalNumberFormattingRules& FCulture::FICUCultureImplementation::GetCur if (!bUseDefaultFormattingRules) { // Set the custom currency before we extract the data from the formatter - icu::UnicodeString ICUCurrencyCode = ICUUtilities::ConvertString(InCurrencyCode); + icu::UnicodeString ICUCurrencyCode = ICUUtilities::ConvertString(SanitizedCurrencyCode); CurrencyFormatterForCulture->setCurrency(ICUCurrencyCode.getBuffer()); } @@ -795,14 +805,14 @@ const FDecimalNumberFormattingRules& FCulture::FICUCultureImplementation::GetCur FScopeLock MapLock(&UEAlternateCurrencyFormattingRulesCS); // Find again in case another thread beat us to it - auto FoundUEAlternateCurrencyFormattingRules = UEAlternateCurrencyFormattingRules.FindRef(InCurrencyCode); + auto FoundUEAlternateCurrencyFormattingRules = UEAlternateCurrencyFormattingRules.FindRef(SanitizedCurrencyCode); if (FoundUEAlternateCurrencyFormattingRules.IsValid()) { return *FoundUEAlternateCurrencyFormattingRules; } FoundUEAlternateCurrencyFormattingRules = MakeShareable(new FDecimalNumberFormattingRules(NewUECurrencyFormattingRules)); - UEAlternateCurrencyFormattingRules.Add(InCurrencyCode, FoundUEAlternateCurrencyFormattingRules); + UEAlternateCurrencyFormattingRules.Add(SanitizedCurrencyCode, FoundUEAlternateCurrencyFormattingRules); return *FoundUEAlternateCurrencyFormattingRules; } } diff --git a/Engine/Source/Runtime/Core/Private/Internationalization/ICURegex.cpp b/Engine/Source/Runtime/Core/Private/Internationalization/ICURegex.cpp index 36c047bc2bbb..c8b5ba851a10 100644 --- a/Engine/Source/Runtime/Core/Private/Internationalization/ICURegex.cpp +++ b/Engine/Source/Runtime/Core/Private/Internationalization/ICURegex.cpp @@ -13,7 +13,7 @@ THIRD_PARTY_INCLUDES_END namespace { - TSharedRef CreateRegexPattern(const FString& SourceString) + TSharedPtr CreateRegexPattern(const FString& SourceString) { icu::UnicodeString ICUSourceString; ICUUtilities::ConvertString(SourceString, ICUSourceString); @@ -26,91 +26,110 @@ namespace class FRegexPatternImplementation { public: - FRegexPatternImplementation(const FString& SourceString) : ICURegexPattern( CreateRegexPattern(SourceString) ) + FRegexPatternImplementation(const FString& SourceString) + : ICURegexPattern( CreateRegexPattern(SourceString) ) { } public: - TSharedRef ICURegexPattern; + TSharedPtr ICURegexPattern; }; -FRegexPattern::FRegexPattern(const FString& SourceString) : Implementation(new FRegexPatternImplementation(SourceString)) +FRegexPattern::FRegexPattern(const FString& SourceString) + : Implementation(new FRegexPatternImplementation(SourceString)) { } namespace { - TSharedRef CreateRegexMatcher(const FRegexPatternImplementation& Pattern, const icu::UnicodeString& InputString) + TSharedPtr CreateRegexMatcher(const FRegexPatternImplementation& Pattern, const icu::UnicodeString& InputString) { - UErrorCode ICUStatus = U_ZERO_ERROR; - return MakeShareable( Pattern.ICURegexPattern->matcher(InputString, ICUStatus) ); + if (Pattern.ICURegexPattern.IsValid()) + { + UErrorCode ICUStatus = U_ZERO_ERROR; + return MakeShareable( Pattern.ICURegexPattern->matcher(InputString, ICUStatus) ); + } + return nullptr; } } class FRegexMatcherImplementation { public: - FRegexMatcherImplementation(const FRegexPatternImplementation& Pattern, const FString& InputString) : ICUInputString(ICUUtilities::ConvertString(InputString)), ICURegexMatcher(CreateRegexMatcher(Pattern, ICUInputString)), OriginalString(InputString) + FRegexMatcherImplementation(const FRegexPatternImplementation& Pattern, const FString& InputString) + : ICUInputString(ICUUtilities::ConvertString(InputString)) + , ICURegexMatcher(CreateRegexMatcher(Pattern, ICUInputString)) + , OriginalString(InputString) { } public: const icu::UnicodeString ICUInputString; - TSharedRef ICURegexMatcher; + TSharedPtr ICURegexMatcher; FString OriginalString; }; -FRegexMatcher::FRegexMatcher(const FRegexPattern& Pattern, const FString& InputString) : Implementation(new FRegexMatcherImplementation(Pattern.Implementation.Get(), InputString)) +FRegexMatcher::FRegexMatcher(const FRegexPattern& Pattern, const FString& InputString) + : Implementation(new FRegexMatcherImplementation(Pattern.Implementation.Get(), InputString)) { } bool FRegexMatcher::FindNext() { - return Implementation->ICURegexMatcher->find() != 0; + return Implementation->ICURegexMatcher.IsValid() && Implementation->ICURegexMatcher->find() != 0; } int32 FRegexMatcher::GetMatchBeginning() { UErrorCode ICUStatus = U_ZERO_ERROR; - return Implementation->ICURegexMatcher->start(ICUStatus); + return Implementation->ICURegexMatcher.IsValid() ? Implementation->ICURegexMatcher->start(ICUStatus) : INDEX_NONE; } int32 FRegexMatcher::GetMatchEnding() { UErrorCode ICUStatus = U_ZERO_ERROR; - return Implementation->ICURegexMatcher->end(ICUStatus); + return Implementation->ICURegexMatcher.IsValid() ? Implementation->ICURegexMatcher->end(ICUStatus) : INDEX_NONE; } int32 FRegexMatcher::GetCaptureGroupBeginning(const int32 Index) { UErrorCode ICUStatus = U_ZERO_ERROR; - return Implementation->ICURegexMatcher->start(Index, ICUStatus); + return Implementation->ICURegexMatcher.IsValid() ? Implementation->ICURegexMatcher->start(Index, ICUStatus) : INDEX_NONE; } int32 FRegexMatcher::GetCaptureGroupEnding(const int32 Index) { UErrorCode ICUStatus = U_ZERO_ERROR; - return Implementation->ICURegexMatcher->end(Index, ICUStatus); + return Implementation->ICURegexMatcher.IsValid() ? Implementation->ICURegexMatcher->end(Index, ICUStatus) : INDEX_NONE; } FString FRegexMatcher::GetCaptureGroup(const int32 Index) { - return Implementation->OriginalString.Mid(GetCaptureGroupBeginning(Index), GetCaptureGroupEnding(Index) - GetCaptureGroupBeginning(Index)); + int32 CaptureGroupBeginning = GetCaptureGroupBeginning(Index); + CaptureGroupBeginning = FMath::Max(0, CaptureGroupBeginning); + + int32 CaptureGroupEnding = GetCaptureGroupEnding(Index); + CaptureGroupEnding = FMath::Max(CaptureGroupBeginning, CaptureGroupEnding); + + return Implementation->OriginalString.Mid(CaptureGroupBeginning, CaptureGroupEnding - CaptureGroupBeginning); } int32 FRegexMatcher::GetBeginLimit() { - return Implementation->ICURegexMatcher->regionStart(); + return Implementation->ICURegexMatcher.IsValid() ? Implementation->ICURegexMatcher->regionStart() : INDEX_NONE; } int32 FRegexMatcher::GetEndLimit() { - return Implementation->ICURegexMatcher->regionEnd(); + return Implementation->ICURegexMatcher.IsValid() ? Implementation->ICURegexMatcher->regionEnd() : INDEX_NONE; } void FRegexMatcher::SetLimits(const int32 BeginIndex, const int32 EndIndex) { - UErrorCode ICUStatus = U_ZERO_ERROR; - Implementation->ICURegexMatcher->region(BeginIndex, EndIndex, ICUStatus); + if (Implementation->ICURegexMatcher.IsValid()) + { + UErrorCode ICUStatus = U_ZERO_ERROR; + Implementation->ICURegexMatcher->region(BeginIndex, EndIndex, ICUStatus); + } } #endif diff --git a/Engine/Source/Runtime/Core/Private/Internationalization/ICUUtilities.cpp b/Engine/Source/Runtime/Core/Private/Internationalization/ICUUtilities.cpp index cbab721a4a6c..62faf18e8ae5 100644 --- a/Engine/Source/Runtime/Core/Private/Internationalization/ICUUtilities.cpp +++ b/Engine/Source/Runtime/Core/Private/Internationalization/ICUUtilities.cpp @@ -276,5 +276,84 @@ namespace ICUUtilities { return GetUnicodeStringLengthImpl(Source, InSourceStartIndex, InSourceLength); } + + FString SanitizeCultureCode(const FString& InCultureCode) + { + if (InCultureCode.IsEmpty()) + { + return InCultureCode; + } + + // ICU culture codes (IETF language tags) may only contain A-Z, a-z, -, or _ + FString SanitizedCultureCode = InCultureCode; + { + SanitizedCultureCode.GetCharArray().RemoveAll([](const TCHAR InChar) + { + if (InChar != 0) + { + const bool bIsValid = (InChar >= TEXT('A') && InChar <= TEXT('Z')) || (InChar >= TEXT('a') && InChar <= TEXT('z')) || (InChar == TEXT('-')) || (InChar == TEXT('_')); + return !bIsValid; + } + return false; + }); + } + return SanitizedCultureCode; + } + + FString SanitizeTimezoneCode(const FString& InTimezoneCode) + { + if (InTimezoneCode.IsEmpty()) + { + return InTimezoneCode; + } + + // ICU timezone codes (Olson or custom offset codes) may only contain A-Z, a-z, 0-9, :, /, +, -, or _, and each / delimited name can be 14-characters max + FString SanitizedTimezoneCode = InTimezoneCode; + { + int32 NumValidChars = 0; + SanitizedTimezoneCode.GetCharArray().RemoveAll([&NumValidChars](const TCHAR InChar) + { + if (InChar != 0) + { + if (InChar == TEXT('/')) + { + NumValidChars = 0; + return false; + } + else + { + const bool bIsValid = (InChar >= TEXT('A') && InChar <= TEXT('Z')) || (InChar >= TEXT('a') && InChar <= TEXT('z')) || (InChar >= TEXT('0') && InChar <= TEXT('9')) || (InChar == TEXT(':')) || (InChar == TEXT('+')) || (InChar == TEXT('-')) || (InChar == TEXT('_')); + return !bIsValid || ++NumValidChars > 14; + } + } + return false; + }); + } + return SanitizedTimezoneCode; + } + + FString SanitizeCurrencyCode(const FString& InCurrencyCode) + { + if (InCurrencyCode.IsEmpty()) + { + return InCurrencyCode; + } + + // ICU currency codes (ISO 4217) may only contain A-Z or a-z, and should be 3-characters + FString SanitizedCurrencyCode = InCurrencyCode; + { + int32 NumValidChars = 0; + SanitizedCurrencyCode.GetCharArray().RemoveAll([&NumValidChars](const TCHAR InChar) + { + if (InChar != 0) + { + const bool bIsValid = (InChar >= TEXT('A') && InChar <= TEXT('Z')) || (InChar >= TEXT('a') && InChar <= TEXT('z')); + return !bIsValid || ++NumValidChars > 3; + } + return false; + }); + } + return SanitizedCurrencyCode; + } } #endif diff --git a/Engine/Source/Runtime/Core/Private/Internationalization/ICUUtilities.h b/Engine/Source/Runtime/Core/Private/Internationalization/ICUUtilities.h index 7602eefd9e3a..bb3817f751e3 100644 --- a/Engine/Source/Runtime/Core/Private/Internationalization/ICUUtilities.h +++ b/Engine/Source/Runtime/Core/Private/Internationalization/ICUUtilities.h @@ -62,5 +62,14 @@ namespace ICUUtilities /** Given an FString, count how many characters it would be if converted to an icu::UnicodeString (as FString may not always be UTF-16) */ int32 GetUnicodeStringLength(const FString& Source); int32 GetUnicodeStringLength(const TCHAR* Source, const int32 InSourceStartIndex, const int32 InSourceLength); + + /** Sanitize the given culture code so that it is safe to use with ICU */ + FString SanitizeCultureCode(const FString& InCultureCode); + + /** Sanitize the given timezone code so that it is safe to use with ICU */ + FString SanitizeTimezoneCode(const FString& InTimezoneCode); + + /** Sanitize the given currency code so that it is safe to use with ICU */ + FString SanitizeCurrencyCode(const FString& InCurrencyCode); } #endif diff --git a/Engine/Source/Runtime/Core/Private/Internationalization/Text.cpp b/Engine/Source/Runtime/Core/Private/Internationalization/Text.cpp index 10ef41dd7e0f..83ff4759af28 100644 --- a/Engine/Source/Runtime/Core/Private/Internationalization/Text.cpp +++ b/Engine/Source/Runtime/Core/Private/Internationalization/Text.cpp @@ -1605,11 +1605,6 @@ bool FTextStringHelper::ReadFromString(const TCHAR* Buffer, FText& OutValue, con { const TCHAR* const Start = Buffer; - while (FChar::IsWhitespace(*Buffer)) - { - ++Buffer; - } - // First, try and parse the text as a complex text export { int32 SubNumCharsRead = 0; diff --git a/Engine/Source/Runtime/Core/Private/Internationalization/TextHistory.cpp b/Engine/Source/Runtime/Core/Private/Internationalization/TextHistory.cpp index 907e3965ba1b..25190a86406f 100644 --- a/Engine/Source/Runtime/Core/Private/Internationalization/TextHistory.cpp +++ b/Engine/Source/Runtime/Core/Private/Internationalization/TextHistory.cpp @@ -162,7 +162,7 @@ void FTextHistory_Base::SerializeForDisplayString(FArchive& Ar, FTextDisplayStri #if USE_STABLE_LOCALIZATION_KEYS // Make sure the package namespace for this text property is up-to-date // We do this on load (as well as save) to handle cases where data is being duplicated, as it will be written by one package and loaded into another - if (GIsEditor && !Ar.HasAnyPortFlags(PPF_DuplicateForPIE)) + if (GIsEditor && !Ar.HasAnyPortFlags(PPF_DuplicateVerbatim | PPF_DuplicateForPIE)) { const FString PackageNamespace = TextNamespaceUtil::GetPackageNamespace(Ar); if (!PackageNamespace.IsEmpty()) @@ -192,7 +192,7 @@ void FTextHistory_Base::SerializeForDisplayString(FArchive& Ar, FTextDisplayStri #if USE_STABLE_LOCALIZATION_KEYS // Make sure the package namespace for this text property is up-to-date - if (GIsEditor && !Ar.HasAnyPortFlags(PPF_DuplicateForPIE)) + if (GIsEditor && !Ar.HasAnyPortFlags(PPF_DuplicateVerbatim | PPF_DuplicateForPIE)) { const FString PackageNamespace = TextNamespaceUtil::GetPackageNamespace(Ar); if (!PackageNamespace.IsEmpty()) @@ -598,7 +598,7 @@ FString FTextHistory_FormatNumber::BuildNumericDisplayString(const FDecimalNumbe case EFormatArgumentType::Double: return FastDecimalFormat::NumberToString(SourceValue.GetDoubleValue() * static_cast(InValueMultiplier), InFormattingRules, FormattingOptions); default: - check(0); // Should never reach this point + break; } return FString(); } @@ -1090,7 +1090,7 @@ FString FTextHistory_Transform::BuildLocalizedDisplayString() const case ETransformType::ToUpper: return FTextTransformer::ToUpper(SourceText.ToString()); default: - check(0); // Should never reach this point + break; } return FString(); } @@ -1106,7 +1106,7 @@ FString FTextHistory_Transform::BuildInvariantDisplayString() const case ETransformType::ToUpper: return FTextTransformer::ToUpper(SourceText.BuildSourceString()); default: - check(0); // Should never reach this point + break; } return FString(); } diff --git a/Engine/Source/Runtime/Core/Private/Internationalization/TextLocalizationManager.cpp b/Engine/Source/Runtime/Core/Private/Internationalization/TextLocalizationManager.cpp index 31db407471b9..99e8c0b3c308 100644 --- a/Engine/Source/Runtime/Core/Private/Internationalization/TextLocalizationManager.cpp +++ b/Engine/Source/Runtime/Core/Private/Internationalization/TextLocalizationManager.cpp @@ -163,14 +163,17 @@ void EndInitTextLocalization() ReadSettingsFromCommandLine(); #if WITH_EDITOR // Read setting specified in editor configuration. - if(GIsEditor) + if (GIsEditor) { ReadSettingsFromConfig(TEXT("editor"), GEditorSettingsIni); } #endif // WITH_EDITOR // Read setting specified in game configurations. - ReadSettingsFromConfig(TEXT("game user settings"), GGameUserSettingsIni); - ReadSettingsFromConfig(TEXT("game"), GGameIni); + if (!GIsEditor) + { + ReadSettingsFromConfig(TEXT("game user settings"), GGameUserSettingsIni); + ReadSettingsFromConfig(TEXT("game"), GGameIni); + } // Read setting specified in engine configuration. ReadSettingsFromConfig(TEXT("engine"), GEngineIni); // Read defaults diff --git a/Engine/Source/Runtime/Core/Private/Linux/LinuxApplication.cpp b/Engine/Source/Runtime/Core/Private/Linux/LinuxApplication.cpp index 7fd816aa7890..e8d51df6f784 100644 --- a/Engine/Source/Runtime/Core/Private/Linux/LinuxApplication.cpp +++ b/Engine/Source/Runtime/Core/Private/Linux/LinuxApplication.cpp @@ -1512,12 +1512,6 @@ void FLinuxApplication::OnMouseCursorLock( bool bLockEnabled ) } } - -bool FLinuxApplication::TryCalculatePopupWindowPosition( const FPlatformRect& InAnchor, const FVector2D& InSize, const EPopUpOrientation::Type Orientation, /*OUT*/ FVector2D* const CalculatedPopUpPosition ) const -{ - return false; -} - void FDisplayMetrics::GetDisplayMetrics(FDisplayMetrics& OutDisplayMetrics) { int NumDisplays = 0; diff --git a/Engine/Source/Runtime/Core/Private/Linux/LinuxPlatformMisc.cpp b/Engine/Source/Runtime/Core/Private/Linux/LinuxPlatformMisc.cpp index 848fa240412a..d2a5cf8de943 100644 --- a/Engine/Source/Runtime/Core/Private/Linux/LinuxPlatformMisc.cpp +++ b/Engine/Source/Runtime/Core/Private/Linux/LinuxPlatformMisc.cpp @@ -445,6 +445,13 @@ bool FLinuxPlatformMisc::HasOverriddenReturnCode(uint8 * OverriddenReturnCodeToU return GHasOverriddenReturnCode; } +FString FLinuxPlatformMisc::GetOSVersion() +{ + // TODO [RCL] 2015-07-15: check if /etc/os-release or /etc/redhat-release exist and parse it + // See void FLinuxPlatformSurvey::GetOSName(FHardwareSurveyResults& OutResults) + return FString(); +} + const TCHAR* FLinuxPlatformMisc::GetSystemErrorMessage(TCHAR* OutBuffer, int32 BufferCount, int32 Error) { check(OutBuffer && BufferCount); diff --git a/Engine/Source/Runtime/Core/Private/Linux/LinuxPlatformProcess.cpp b/Engine/Source/Runtime/Core/Private/Linux/LinuxPlatformProcess.cpp index 07e6dd0acfe4..9d9ba6f222f7 100644 --- a/Engine/Source/Runtime/Core/Private/Linux/LinuxPlatformProcess.cpp +++ b/Engine/Source/Runtime/Core/Private/Linux/LinuxPlatformProcess.cpp @@ -151,14 +151,17 @@ void FLinuxPlatformProcess::CleanFileCache() if (bShouldCleanShaderWorkingDirectory && !FParse::Param( FCommandLine::Get(), TEXT("Multiprocess"))) { // get shader path, and convert it to the userdirectory - FString ShaderDir = FString(FPlatformProcess::BaseDir()) / FPlatformProcess::ShaderDir(); - FString UserShaderDir = IFileManager::Get().ConvertToAbsolutePathForExternalAppForWrite(*ShaderDir); - FPaths::CollapseRelativeDirectories(ShaderDir); - - // make sure we don't delete from the source directory - if (ShaderDir != UserShaderDir) + for (FString Dir : FPlatformProcess::AllShaderDirs()) { - IFileManager::Get().DeleteDirectory(*UserShaderDir, false, true); + FString ShaderDir = FString(FPlatformProcess::BaseDir()) / Dir; + FString UserShaderDir = IFileManager::Get().ConvertToAbsolutePathForExternalAppForWrite(*ShaderDir); + FPaths::CollapseRelativeDirectories(ShaderDir); + + // make sure we don't delete from the source directory + if (ShaderDir != UserShaderDir) + { + IFileManager::Get().DeleteDirectory(*UserShaderDir, false, true); + } } FPlatformProcess::CleanShaderWorkingDir(); diff --git a/Engine/Source/Runtime/Core/Private/Linux/LinuxPlatformSplash.cpp b/Engine/Source/Runtime/Core/Private/Linux/LinuxPlatformSplash.cpp index ca3a4b821f93..9cd81a20a380 100644 --- a/Engine/Source/Runtime/Core/Private/Linux/LinuxPlatformSplash.cpp +++ b/Engine/Source/Runtime/Core/Private/Linux/LinuxPlatformSplash.cpp @@ -25,6 +25,7 @@ #include "Misc/EngineVersion.h" #include "Misc/EngineBuildSettings.h" #include "Modules/ModuleManager.h" +#include "ScopeLock.h" #if WITH_EDITOR @@ -83,7 +84,7 @@ static FString GSplashPath; static FString GIconPath; static IImageWrapperPtr GSplashImageWrapper; static IImageWrapperPtr GIconImageWrapper; - +static FCriticalSection GSplashScreenTextCriticalSection; static int32 SplashWidth = 0, SplashHeight = 0; static unsigned char *ScratchSpace = nullptr; @@ -367,7 +368,7 @@ static void DrawCharacter(int32 penx, int32 peny, FT_GlyphSlot Glyph, int32 CurT for (int x=0; xmetrics.horiBearingX >> 6); int ypos = peny + y - (Glyph->metrics.horiBearingY >> 6); // make sure pixel is in drawing rectangle @@ -444,61 +445,64 @@ static int RenderString (GLuint tex_idx) peny += Font->Face->descender >> 6; // convert strings to glyphs and place them in bitmap. - FString Text = GSplashScreenText[CurTypeIndex].ToString(); - - for (int i=0; iFace, charcode); - FT_Load_Glyph(Font->Face, glyph_idx, FT_LOAD_DEFAULT); + FScopeLock ScopeLock(&GSplashScreenTextCriticalSection); - - if (Font->Face->glyph->format != FT_GLYPH_FORMAT_BITMAP) - { - FT_Render_Glyph(Font->Face->glyph, FT_RENDER_MODE_NORMAL); - } + FString Text = GSplashScreenText[CurTypeIndex].ToString(); - - // pen advance and kerning - if (bRightJustify) + for (int i=0; iFace, glyph_idx, last_glyph, FT_KERNING_DEFAULT, &kern); - } + FT_ULong charcode; - penx -= (Font->Face->glyph->metrics.horiAdvance - kern.x) >> 6; - } - else - { - if (last_glyph != 0) + // fetch next glyph + if (bRightJustify) { - FT_Get_Kerning(Font->Face, last_glyph, glyph_idx, FT_KERNING_DEFAULT, &kern); - } - } + charcode = (Uint32)(Text[Text.Len() - i - 1]); + } + else + { + charcode = (Uint32)(Text[i]); + } + + FT_UInt glyph_idx = FT_Get_Char_Index(Font->Face, charcode); + FT_Load_Glyph(Font->Face, glyph_idx, FT_LOAD_DEFAULT); - last_glyph = glyph_idx; + + if (Font->Face->glyph->format != FT_GLYPH_FORMAT_BITMAP) + { + FT_Render_Glyph(Font->Face->glyph, FT_RENDER_MODE_NORMAL); + } - // draw character - DrawCharacter(penx, peny, Font->Face->glyph,CurTypeIndex, red, green, blue); - - if (!bRightJustify) - { - penx += (Font->Face->glyph->metrics.horiAdvance - kern.x) >> 6; + + // pen advance and kerning + if (bRightJustify) + { + if (last_glyph != 0) + { + FT_Get_Kerning(Font->Face, glyph_idx, last_glyph, FT_KERNING_DEFAULT, &kern); + } + + penx -= (Font->Face->glyph->metrics.horiAdvance - kern.x) >> 6; + } + else + { + if (last_glyph != 0) + { + FT_Get_Kerning(Font->Face, last_glyph, glyph_idx, FT_KERNING_DEFAULT, &kern); + } + } + + last_glyph = glyph_idx; + + // draw character + DrawCharacter(penx, peny, Font->Face->glyph,CurTypeIndex, red, green, blue); + + if (!bRightJustify) + { + penx += (Font->Face->glyph->metrics.horiAdvance - kern.x) >> 6; + } } } - // store rendered text as texture glBindTexture(GL_TEXTURE_2D, tex_idx); @@ -830,7 +834,7 @@ static int StartSplashScreenThread(void *ptr) if (ThreadState > 0) { RenderString(texture); - ThreadState--; + FPlatformAtomics::InterlockedDecrement(&ThreadState); } // Set stream positions and draw. @@ -883,7 +887,7 @@ static int StartSplashScreenThread(void *ptr) FMemory::Free(ScratchSpace); // set the thread state to -1 to let the caller know we're done (FIXME: can be done without busy-loops) - ThreadState = -1; + FPlatformAtomics::InterlockedExchange(&ThreadState, -1); return 0; } @@ -899,6 +903,8 @@ static int StartSplashScreenThread(void *ptr) static void StartSetSplashText( const SplashTextType::Type InType, const FText& InText ) { #if WITH_EDITOR + FScopeLock ScopeLock(&GSplashScreenTextCriticalSection); + // Update splash text GSplashScreenText[ InType ] = InText; #endif @@ -1028,7 +1034,7 @@ void FLinuxPlatformSplash::Show( ) else { SDL_DetachThread(GSplashThread); - ThreadState = 1; + FPlatformAtomics::InterlockedExchange(&ThreadState, 1); } #endif //WITH_EDITOR } @@ -1043,7 +1049,8 @@ void FLinuxPlatformSplash::Hide() // signal thread it's time to quit if (ThreadState >= 0) // if there's a thread at all... { - ThreadState = -99; + FPlatformAtomics::InterlockedExchange(&ThreadState, -99); + // wait for the thread to be done before tearing it tearing it down (it will set the ThreadState to 0) while (ThreadState != -1) { @@ -1076,6 +1083,8 @@ void FLinuxPlatformSplash::SetSplashText( const SplashTextType::Type InType, con { bool bWasUpdated = false; { + FScopeLock ScopeLock(&GSplashScreenTextCriticalSection); + // Update splash text if (FCString::Strcmp( InText, *GSplashScreenText[ InType ].ToString() ) != 0) { @@ -1086,7 +1095,7 @@ void FLinuxPlatformSplash::SetSplashText( const SplashTextType::Type InType, con if (bWasUpdated && GSplashThread && ThreadState >= 0) { - ThreadState++; + FPlatformAtomics::InterlockedIncrement(&ThreadState); } } #endif //WITH_EDITOR diff --git a/Engine/Source/Runtime/Core/Private/Linux/LinuxWindow.cpp b/Engine/Source/Runtime/Core/Private/Linux/LinuxWindow.cpp index b02f49761dc9..a2cef23327d3 100644 --- a/Engine/Source/Runtime/Core/Private/Linux/LinuxWindow.cpp +++ b/Engine/Source/Runtime/Core/Private/Linux/LinuxWindow.cpp @@ -8,6 +8,9 @@ #include "GenericPlatform/GenericWindowDefinition.h" #include "Misc/App.h" #include "Linux/LinuxApplication.h" +#include "Internationalization.h" // LOCTEXT + +#define LOCTEXT_NAMESPACE "LinuxWindow" DEFINE_LOG_CATEGORY( LogLinuxWindow ); DEFINE_LOG_CATEGORY( LogLinuxWindowType ); @@ -219,6 +222,34 @@ void FLinuxWindow::Initialize( FLinuxApplication* const Application, const TShar // The SDL window doesn't need to be reshaped. // the size of the window you input is the sizeof the client. HWnd = SDL_CreateWindow( TCHAR_TO_ANSI( *Definition->Title ), X, Y, ClientWidth, ClientHeight, WindowStyle ); + // produce a helpful message for common driver errors + if (HWnd == nullptr) + { + FString ErrorMessage; + + if ((WindowStyle & SDL_WINDOW_VULKAN) != 0) + { + ErrorMessage = LOCTEXT("VulkanWindowCreationFailedLinux", "Unable to create a Vulkan window - make sure an up-to-date libvulkan.so.1 is installed.").ToString(); + FPlatformMisc::MessageBoxExt(EAppMsgType::Ok, *ErrorMessage, + *LOCTEXT("VulkanWindowCreationFailedLinuxTitle", "Unable to create a Vulkan window.").ToString()); + } + else if ((WindowStyle & SDL_WINDOW_OPENGL) != 0) + { + ErrorMessage = LOCTEXT("OpenGLWindowCreationFailedLinux", "Unable to create an OpenGL window - make sure your drivers support at least OpenGL 4.3.").ToString(); + FPlatformMisc::MessageBoxExt(EAppMsgType::Ok, *ErrorMessage, + *LOCTEXT("OpenGLWindowCreationFailedLinuxTitle", "Unable to create an OpenGL window.").ToString()); + } + else + { + ErrorMessage = FString::Printf(*LOCTEXT("SDLWindowCreationFailedLinux", "Window creation failed (SDL error: '%s'')").ToString(), UTF8_TO_TCHAR(SDL_GetError())); + FPlatformMisc::MessageBoxExt(EAppMsgType::Ok, *ErrorMessage, + *LOCTEXT("SDLWindowCreationFailedLinuxTitle", "Unable to create an SDL window.").ToString()); + } + + checkf(false, TEXT("%s"), *ErrorMessage); + // unreachable + return; + } if (Definition->AppearsInTaskbar) { @@ -299,13 +330,6 @@ void FLinuxWindow::Initialize( FLinuxApplication* const Application, const TShar // desired client area space. ReshapeWindow( X, Y, ClientWidth, ClientHeight ); - if (HWnd == nullptr) - { - // @todo Error message should be localized! - checkf(false, TEXT("Window creation failed (%s)"), UTF8_TO_TCHAR(SDL_GetError())); - return; - } - if ( Definition->TransparencySupport == EWindowTransparency::PerWindow ) { SetOpacity( Definition->Opacity ); @@ -790,3 +814,5 @@ void FLinuxWindow::CacheNativeProperties() bValidNativePropertiesCache = true; } + +#undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Runtime/Core/Private/Logging/LogSuppressionInterface.cpp b/Engine/Source/Runtime/Core/Private/Logging/LogSuppressionInterface.cpp index 0b1d7b56dbbf..99e8d4bb3eb0 100644 --- a/Engine/Source/Runtime/Core/Private/Logging/LogSuppressionInterface.cpp +++ b/Engine/Source/Runtime/Core/Private/Logging/LogSuppressionInterface.cpp @@ -541,8 +541,10 @@ public: { Ar.Logf(TEXT("%-40s %-12s %s"), *It->Name, FOutputDeviceHelper::VerbosityToString(It->Verbosity), It->Postfix ? TEXT(" - DebugBreak") : TEXT("")); } + + return true; } - else + else if (Cmd[0] != '.') { FString Rest(Cmd); Rest = Rest.Trim(); @@ -600,8 +602,8 @@ public: Ar.Logf( TEXT("[cat]=[level]") ); Ar.Logf( TEXT("foo=verbose break") ); } + return true; } - return true; } return false; } diff --git a/Engine/Source/Runtime/Core/Private/Logging/TokenizedMessage.cpp b/Engine/Source/Runtime/Core/Private/Logging/TokenizedMessage.cpp index fd5d0e24888a..67c11557d946 100644 --- a/Engine/Source/Runtime/Core/Private/Logging/TokenizedMessage.cpp +++ b/Engine/Source/Runtime/Core/Private/Logging/TokenizedMessage.cpp @@ -21,23 +21,27 @@ TSharedRef FTokenizedMessage::Create(EMessageSeverity::Type I FText FTokenizedMessage::ToText() const { FText OutMessage; + int32 TokenIndex = 0; - // Dont duplicate starting severity when displaying as string - but display it if it differs (for whatever reason) + // Don't duplicate starting severity when displaying as string - but display it if it differs (for whatever reason) if(MessageTokens.Num() > 0 && MessageTokens[0]->GetType() == EMessageToken::Severity) { TSharedRef SeverityToken = StaticCastSharedRef(MessageTokens[0]); if(SeverityToken->GetSeverity() != Severity) { - OutMessage = FTokenizedMessage::GetSeverityText( Severity ); + OutMessage = FText::Format(LOCTEXT("SeverityMessageTokenFormatter", "{0}:"), FTokenizedMessage::GetSeverityText(Severity)); } + + // Skip the first token message as the Severity gets added again in FMsg::Logf + TokenIndex = 1; } else { OutMessage = FTokenizedMessage::GetSeverityText( Severity ); } - + //@todo This is bad and not safe for localization, this needs to be refactored once rich text is implemented [9/24/2013 justin.sargent] - for(int TokenIndex = 0; TokenIndex < MessageTokens.Num(); TokenIndex++) + for(; TokenIndex < MessageTokens.Num(); TokenIndex++) { if ( !OutMessage.IsEmpty() ) { @@ -46,7 +50,7 @@ FText FTokenizedMessage::ToText() const else { OutMessage = MessageTokens[TokenIndex]->ToText(); - } + } } return OutMessage; diff --git a/Engine/Source/Runtime/Core/Private/Mac/MacApplication.cpp b/Engine/Source/Runtime/Core/Private/Mac/MacApplication.cpp index 0d24668d1674..5e2bf61500f1 100644 --- a/Engine/Source/Runtime/Core/Private/Mac/MacApplication.cpp +++ b/Engine/Source/Runtime/Core/Private/Mac/MacApplication.cpp @@ -324,7 +324,7 @@ FPlatformRect FMacApplication::GetWorkArea(const FPlatformRect& CurrentWindow) c #if WITH_EDITOR void FMacApplication::SendAnalytics(IAnalyticsProvider* Provider) { - static_assert(EGestureEvent::Count == 5, "If the number of gestures changes you need to add more entries below!"); + static_assert(EGestureEvent::Count == 6, "If the number of gestures changes you need to add more entries below!"); TArray GestureAttributes; GestureAttributes.Add(FAnalyticsEventAttribute(FString("Scroll"), GestureUsage[EGestureEvent::Scroll])); @@ -1237,17 +1237,19 @@ void FMacApplication::OnActiveSpaceDidChange() void FMacApplication::OnCursorLock() { - MainThreadCall(^{ + if (Cursor.IsValid()) + { SCOPED_AUTORELEASE_POOL; NSWindow* NativeWindow = [NSApp keyWindow]; - // This block can be called after MacApplication is destroyed - if (MacApplication && NativeWindow && Cursor.IsValid()) + if (NativeWindow) { - const bool bIsCursorLocked = ((FMacCursor*)Cursor.Get())->IsLocked(); - if (bIsCursorLocked) + if (((FMacCursor*)Cursor.Get())->IsLocked()) { - [NativeWindow setMinSize:NSMakeSize(NativeWindow.frame.size.width, NativeWindow.frame.size.height)]; - [NativeWindow setMaxSize:NSMakeSize(NativeWindow.frame.size.width, NativeWindow.frame.size.height)]; + MainThreadCall(^{ + SCOPED_AUTORELEASE_POOL; + [NativeWindow setMinSize:NSMakeSize(NativeWindow.frame.size.width, NativeWindow.frame.size.height)]; + [NativeWindow setMaxSize:NSMakeSize(NativeWindow.frame.size.width, NativeWindow.frame.size.height)]; + }, NSDefaultRunLoopMode, false); } else { @@ -1255,12 +1257,17 @@ void FMacApplication::OnCursorLock() if (Window.IsValid()) { const FGenericWindowDefinition& Definition = Window->GetDefinition(); - [NativeWindow setMinSize:NSMakeSize(Definition.SizeLimits.GetMinWidth().Get(10.0f), Definition.SizeLimits.GetMinHeight().Get(10.0f))]; - [NativeWindow setMaxSize:NSMakeSize(Definition.SizeLimits.GetMaxWidth().Get(10000.0f), Definition.SizeLimits.GetMaxHeight().Get(10000.0f))]; + const NSSize MinSize = NSMakeSize(Definition.SizeLimits.GetMinWidth().Get(10.0f), Definition.SizeLimits.GetMinHeight().Get(10.0f)); + const NSSize MaxSize = NSMakeSize(Definition.SizeLimits.GetMaxWidth().Get(10000.0f), Definition.SizeLimits.GetMaxHeight().Get(10000.0f)); + MainThreadCall(^{ + SCOPED_AUTORELEASE_POOL; + [NativeWindow setMinSize:MinSize]; + [NativeWindow setMaxSize:MaxSize]; + }, NSDefaultRunLoopMode, false); } } } - }, NSDefaultRunLoopMode, false); + } } void FMacApplication::ConditionallyUpdateModifierKeys(const FDeferredMacEvent& Event) diff --git a/Engine/Source/Runtime/Core/Private/Mac/MacPlatformMisc.cpp b/Engine/Source/Runtime/Core/Private/Mac/MacPlatformMisc.cpp index d6cfb0c9b36d..8a47294e8e1c 100644 --- a/Engine/Source/Runtime/Core/Private/Mac/MacPlatformMisc.cpp +++ b/Engine/Source/Runtime/Core/Private/Mac/MacPlatformMisc.cpp @@ -424,7 +424,7 @@ void FMacPlatformMisc::PlatformInit() UE_LOG(LogInit, Log, TEXT("Power Source: %s"), GMacAppInfo.RunningOnBattery ? TEXT(kIOPSBatteryPowerValue) : TEXT(kIOPSACPowerValue) ); } -void FMacPlatformMisc::PlatformPostInit(bool ShowSplashScreen) +void FMacPlatformMisc::PlatformPostInit() { // Setup the app menu in menu bar const bool bIsBundledApp = [[[NSBundle mainBundle] bundlePath] hasSuffix:@".app"]; @@ -1631,6 +1631,11 @@ void FMacPlatformMisc::GetOSVersions( FString& out_OSVersionLabel, FString& out_ out_OSSubVersionLabel = GMacAppInfo.OSBuild; } +FString FMacPlatformMisc::GetOSVersion() +{ + return GMacAppInfo.OSVersion; +} + bool FMacPlatformMisc::GetDiskTotalAndFreeSpace(const FString& InPath, uint64& TotalNumberOfBytes, uint64& NumberOfFreeBytes) { struct statfs FSStat = { 0 }; diff --git a/Engine/Source/Runtime/Core/Private/Mac/MacPlatformProcess.cpp b/Engine/Source/Runtime/Core/Private/Mac/MacPlatformProcess.cpp index fe537995030f..c222d41a899c 100644 --- a/Engine/Source/Runtime/Core/Private/Mac/MacPlatformProcess.cpp +++ b/Engine/Source/Runtime/Core/Private/Mac/MacPlatformProcess.cpp @@ -9,6 +9,7 @@ #include "Misc/App.h" #include "Misc/Paths.h" #include "MacApplication.h" +#include "HAL/FileManager.h" #include #include @@ -755,10 +756,24 @@ void FMacPlatformProcess::CleanFileCache() bShouldCleanShaderWorkingDirectory = GIsFirstInstance; #endif - if (bShouldCleanShaderWorkingDirectory && !FParse::Param( FCommandLine::Get(), TEXT("Multiprocess"))) - { - FPlatformProcess::CleanShaderWorkingDir(); - } + if (bShouldCleanShaderWorkingDirectory && !FParse::Param( FCommandLine::Get(), TEXT("Multiprocess"))) + { + // get shader path, and convert it to the userdirectory + for (FString Dir : FPlatformProcess::AllShaderDirs()) + { + FString ShaderDir = FString(FPlatformProcess::BaseDir()) / Dir; + FString UserShaderDir = IFileManager::Get().ConvertToAbsolutePathForExternalAppForWrite(*ShaderDir); + FPaths::CollapseRelativeDirectories(ShaderDir); + + // make sure we don't delete from the source directory + if (ShaderDir != UserShaderDir) + { + IFileManager::Get().DeleteDirectory(*UserShaderDir, false, true); + } + } + + FPlatformProcess::CleanShaderWorkingDir(); + } } const TCHAR* FMacPlatformProcess::BaseDir() diff --git a/Engine/Source/Runtime/Core/Private/Math/Sobol.cpp b/Engine/Source/Runtime/Core/Private/Math/Sobol.cpp new file mode 100644 index 000000000000..c7a6882cdfad --- /dev/null +++ b/Engine/Source/Runtime/Core/Private/Math/Sobol.cpp @@ -0,0 +1,231 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + + +#include "Math/Sobol.h" + +float FSobol::Evaluate(int32 Index, int32 Dim, int32 Seed) +{ + check(Dim >= 0 && Dim <= MaxDimension); + int32 Result = Seed & 0xffffff; + for (int i = 0; i < 32; ++i, Index >>= 1) { + Result ^= (Index & 1) * DirectionNumbers[Dim][i]; + } + return float(Result) * 5.96046448e-08f; // 2^-24 +} + +float FSobol::Next(int32 Index, int32 Dim, float Value) +{ + if (Index == 0) + { + return Value; + } + + check(Dim >= 0 && Dim <= MaxDimension); + int32 Result = FMath::FloorToInt(Value * 0x1000000) & 0xffffff; + int32 ChangedBit = FMath::CountTrailingZeros(Index) & 31; + Result ^= GrayNumbers[Dim][ChangedBit]; + return float(Result) * 5.96046448e-08f; // 2^-24 +} + +FVector2D FSobol::Evaluate(int32 Index, int32 CellBits, FIntPoint Cell, FIntPoint Seed) +{ + check(CellBits >= 0 && CellBits <= MaxCell2DBits); + int32 CellMask = (1 << CellBits) - 1; + Cell = FIntPoint(Cell.X & CellMask, Cell.Y & CellMask); + FIntPoint Result = FIntPoint((Seed.X & 0xffffff) >> CellBits, (Seed.Y & 0xffffff) >> CellBits); + + for (int i = 0; (i < CellBits) && (Cell.X != 0); ++i, Cell.X >>= 1) + { + Result.X ^= (Cell.X & 1) * Cell2DDirectionNumbers[CellBits][i][0]; + Result.Y ^= (Cell.X & 1) * Cell2DDirectionNumbers[CellBits][i][1]; + } + for (int i = CellBits; (i < 2*CellBits) && (Cell.Y != 0); ++i, Cell.Y >>= 1) + { + Result.X ^= (Cell.Y & 1) * Cell2DDirectionNumbers[CellBits][i][0]; + Result.Y ^= (Cell.Y & 1) * Cell2DDirectionNumbers[CellBits][i][1]; + } + for (int i = 2*CellBits; (i < 32) && (Index != 0); ++i, Index >>= 1) + { + Result.X ^= (Index & 1) * Cell2DDirectionNumbers[CellBits][i][0]; + Result.Y ^= (Index & 1) * Cell2DDirectionNumbers[CellBits][i][1]; + } + + return FVector2D(Result) / float(1 << (24 - CellBits)); +} + +FVector2D FSobol::Next(int32 Index, int32 CellBits, FVector2D Value) +{ + if (Index == 0) + { + return Value; + } + + check(CellBits >= 0 && CellBits <= MaxCell2DBits); + int32 ChangedBit = FMath::CountTrailingZeros(Index) & 31; + float CellScale = float(1 << (24 - CellBits)); + + FIntPoint Result = FIntPoint(int32(Value.X * CellScale) & 0xffffff, int32(Value.Y * CellScale) & 0xffffff); + Result.X ^= Cell2DGrayNumbers[CellBits][ChangedBit][0]; + Result.Y ^= Cell2DGrayNumbers[CellBits][ChangedBit][1]; + return FVector2D(Result) / CellScale; +} + + +FVector FSobol::Evaluate(int32 Index, int32 CellBits, FIntVector Cell, FIntVector Seed) +{ + check(CellBits >= 0 && CellBits <= MaxCell2DBits); + int32 CellMask = (1 << CellBits) - 1; + Cell = FIntVector(Cell.X & CellMask, Cell.Y & CellMask, Cell.Z & CellMask); + FIntVector Result = FIntVector((Seed.X & 0xffffff) >> CellBits, (Seed.Y & 0xffffff) >> CellBits, (Seed.Z & 0xffffff) >> CellBits); + + for (int i = 0; (i < CellBits) && (Cell.X != 0); ++i, Cell.X >>= 1) + { + Result.X ^= (Cell.X & 1) * Cell3DDirectionNumbers[CellBits][i][0]; + Result.Y ^= (Cell.X & 1) * Cell3DDirectionNumbers[CellBits][i][1]; + Result.Z ^= (Cell.X & 1) * Cell3DDirectionNumbers[CellBits][i][2]; + } + for (int i = CellBits; (i < 2*CellBits) && (Cell.Y != 0); ++i, Cell.Y >>= 1) + { + Result.X ^= (Cell.Y & 1) * Cell3DDirectionNumbers[CellBits][i][0]; + Result.Y ^= (Cell.Y & 1) * Cell3DDirectionNumbers[CellBits][i][1]; + Result.Z ^= (Cell.Y & 1) * Cell3DDirectionNumbers[CellBits][i][2]; + } + for (int i = 2*CellBits; (i < 3*CellBits) && (Cell.Z != 0); ++i, Cell.Z >>= 1) + { + Result.X ^= (Cell.Z & 1) * Cell3DDirectionNumbers[CellBits][i][0]; + Result.Y ^= (Cell.Z & 1) * Cell3DDirectionNumbers[CellBits][i][1]; + Result.Z ^= (Cell.Z & 1) * Cell3DDirectionNumbers[CellBits][i][2]; + } + for (int i = 3*CellBits; (i < 32) && (Index != 0); ++i, Index >>= 1) + { + Result.X ^= (Index & 1) * Cell3DDirectionNumbers[CellBits][i][0]; + Result.Y ^= (Index & 1) * Cell3DDirectionNumbers[CellBits][i][1]; + Result.Z ^= (Index & 1) * Cell3DDirectionNumbers[CellBits][i][2]; + } + + return FVector(Result) / float(1 << (24 - CellBits)); +} + +FVector FSobol::Next(int32 Index, int32 CellBits, FVector Value) +{ + if (Index == 0) + { + return Value; + } + + check(CellBits >= 0 && CellBits <= MaxCell2DBits); + int32 ChangedBit = FMath::CountTrailingZeros(Index) & 31; + float CellScale = float(1 << (24 - CellBits)); + + FIntVector Result = FIntVector(int32(Value.X * CellScale) & 0xffffff, int32(Value.Y * CellScale) & 0xffffff, int32(Value.Z * CellScale) & 0xffffff); + Result.X ^= Cell3DGrayNumbers[CellBits][ChangedBit][0]; + Result.Y ^= Cell3DGrayNumbers[CellBits][ChangedBit][1]; + Result.Z ^= Cell3DGrayNumbers[CellBits][ChangedBit][2]; + return FVector(Result) / CellScale; +} + +// Sobol direction number table +const int32 FSobol::DirectionNumbers[FSobol::MaxDimension + 1][32] = { + { 0x000001, 0x000002, 0x000004, 0x000008, 0x000010, 0x000020, 0x000040, 0x000080, 0x000100, 0x000200, 0x000400, 0x000800, 0x001000, 0x002000, 0x004000, 0x008000, 0x010000, 0x020000, 0x040000, 0x080000, 0x100000, 0x200000, 0x400000, 0x800000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000 }, + { 0x800000, 0x400000, 0x200000, 0x100000, 0x080000, 0x040000, 0x020000, 0x010000, 0x008000, 0x004000, 0x002000, 0x001000, 0x000800, 0x000400, 0x000200, 0x000100, 0x000080, 0x000040, 0x000020, 0x000010, 0x000008, 0x000004, 0x000002, 0x000001, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000 }, + { 0x800000, 0xc00000, 0xa00000, 0xf00000, 0x880000, 0xcc0000, 0xaa0000, 0xff0000, 0x808000, 0xc0c000, 0xa0a000, 0xf0f000, 0x888800, 0xcccc00, 0xaaaa00, 0xffff00, 0x800080, 0xc000c0, 0xa000a0, 0xf000f0, 0x880088, 0xcc00cc, 0xaa00aa, 0xff00ff, 0x808080, 0xc0c0c0, 0xa0a0a0, 0xf0f0f0, 0x888888, 0xcccccc, 0xaaaaaa, 0xffffff }, + { 0x800000, 0xc00000, 0x600000, 0x900000, 0xe80000, 0x5c0000, 0x8e0000, 0xc50000, 0x688000, 0x9cc000, 0xee6000, 0x559000, 0x806800, 0xc09c00, 0x60ee00, 0x905500, 0xe88080, 0x5cc0c0, 0x8e6060, 0xc59090, 0x6868e8, 0x9c9c5c, 0xeeee8e, 0x5555c5, 0x8000e8, 0xc0005c, 0x60008e, 0x9000c5, 0xe80068, 0x5c009c, 0x8e00ee, 0xc50055 }, + { 0x800000, 0xc00000, 0x200000, 0x500000, 0xf80000, 0x740000, 0xa20000, 0x930000, 0xd88000, 0x254000, 0x59e000, 0xe6d000, 0x780800, 0xb40c00, 0x820200, 0xc30500, 0x208f80, 0x514740, 0xfbea20, 0x75d930, 0xa08588, 0x914e54, 0xdbe79e, 0x25db6d, 0x588000, 0xe54000, 0x79e000, 0xb6d000, 0x800800, 0xc00c00, 0x200200, 0x500500 }, + { 0x800000, 0x400000, 0x200000, 0xb00000, 0xf80000, 0xdc0000, 0x7a0000, 0x9d0000, 0x5a8000, 0x2fc000, 0xa16000, 0xf0b000, 0xda8800, 0x6fc400, 0x816200, 0x40bb00, 0x228780, 0xb3c9c0, 0xfb65a0, 0xddb2d0, 0x780228, 0x9c0b3c, 0x5a0fb6, 0x2d0ddb, 0xa28780, 0xf3c9c0, 0xdb65a0, 0x6db2d0, 0x800228, 0x400b3c, 0x200fb6, 0xb00ddb }, + { 0x800000, 0x400000, 0x600000, 0x300000, 0xc80000, 0x240000, 0x560000, 0xfb0000, 0xe08000, 0x704000, 0xa86000, 0x143000, 0x9ec800, 0xdf2400, 0xb6d600, 0x8bbb00, 0x480080, 0x640040, 0x360060, 0xcb0030, 0x2880c8, 0x544024, 0xfe6056, 0xef30fb, 0x7e48e0, 0xaf6470, 0x1eb6a8, 0x9f8b14, 0xd6c81e, 0xbb249f, 0x80d6d6, 0x40bbbb }, + { 0x800000, 0xc00000, 0xa00000, 0xd00000, 0x580000, 0x940000, 0x3e0000, 0xe30000, 0xbe8000, 0x23c000, 0x1e2000, 0xf31000, 0x467800, 0x678400, 0x784600, 0x846700, 0xc67880, 0xa784c0, 0xd846a0, 0x5467d0, 0x9e78d8, 0x338454, 0xe6469e, 0xb76733, 0x20f866, 0x104477, 0xf86680, 0x4477c0, 0x668020, 0x77c010, 0x8020f8, 0xc01044 }, + { 0x800000, 0x400000, 0xa00000, 0x500000, 0x880000, 0x240000, 0x120000, 0x2d0000, 0x768000, 0x9e4000, 0x082000, 0x641000, 0xb22800, 0x7d1400, 0xfea200, 0xba4900, 0x1a2480, 0x491b40, 0xc4b5a0, 0xe37390, 0xf68008, 0xde4004, 0xa8200a, 0x341005, 0x3a2808, 0x591402, 0xeca201, 0x974902, 0x6ca487, 0xd75b49, 0xcc95a0, 0x876396 }, + { 0x800000, 0x400000, 0xa00000, 0x500000, 0x280000, 0xd40000, 0x6a0000, 0x710000, 0x388000, 0x584000, 0xea2000, 0x311000, 0x98a800, 0x085400, 0xc22a00, 0xe52500, 0xf2b280, 0x794840, 0xfaa420, 0xbd7310, 0x18a808, 0x485404, 0x622a0a, 0xb52505, 0xdab282, 0xad484d, 0x90a426, 0xcc7317, 0x20280b, 0x101401, 0x880a04, 0x843506 }, + { 0x800000, 0x400000, 0xe00000, 0xb00000, 0x980000, 0x940000, 0x8a0000, 0x5b0000, 0x338000, 0xd9c000, 0x722000, 0x3f1000, 0xc1b800, 0xa6ec00, 0x538600, 0x29f500, 0x0a3a80, 0x1b2ac0, 0xd392e0, 0x69ff70, 0xea3808, 0xab2c04, 0x4ba60e, 0xfde50b, 0x600289, 0xf006c9, 0x7834e8, 0x241a75, 0x123a8b, 0xcf2ac9, 0xb992e9, 0x82ff78 }, + { 0x800000, 0x400000, 0xa00000, 0x100000, 0x080000, 0x6c0000, 0x9e0000, 0x230000, 0x578000, 0xadc000, 0x7fa000, 0x91d000, 0x498800, 0xced400, 0x880a00, 0x2c0f00, 0x3e0d80, 0x3317c0, 0x5fb060, 0xc1f8b0, 0xe18d88, 0xb2d7c4, 0x1e106a, 0x6328b1, 0xf78588, 0xbdc3c2, 0x77ba63, 0xfdf7b3, 0xd7800d, 0xedc008, 0xdfa004, 0x81d00a }, + { 0x800000, 0x400000, 0x200000, 0x300000, 0x580000, 0xac0000, 0x960000, 0x2b0000, 0xd48000, 0x094000, 0xe2a000, 0x525000, 0x4e2800, 0xc71c00, 0x629e00, 0x126700, 0x6e1380, 0xf731c0, 0x3a98a0, 0xbe4490, 0xf83b88, 0xdc2dc4, 0xee06a2, 0xb72393, 0x1aa80d, 0x8e5c0e, 0xa03e0b, 0x703701, 0x783b88, 0x9c2dca, 0xce06a7, 0x872397 }, + { 0x800000, 0xc00000, 0xa00000, 0x500000, 0xf80000, 0x8c0000, 0xe20000, 0x330000, 0x0f8000, 0x214000, 0x95a000, 0x5e7000, 0xd80800, 0x1c2400, 0xba1600, 0xef3700, 0x158680, 0x9e6fc0, 0x781b60, 0x4c3490, 0x420e88, 0x630bcc, 0xf7ad6a, 0xad7395, 0x778007, 0x6d4004, 0xd7a004, 0x3d7006, 0x2f880f, 0xb1640a, 0xcdb607, 0x824706 }, + { 0x800000, 0xc00000, 0x600000, 0x900000, 0x380000, 0xc40000, 0x420000, 0xa30000, 0xf18000, 0xaa4000, 0xfce000, 0x851000, 0xe00800, 0x500c00, 0x580600, 0x540900, 0x7a0380, 0x670c40, 0xb38420, 0x094a30, 0x0d6f18, 0x2f5aa4, 0x1ce7ce, 0xd51451, 0xb80000, 0x040000, 0x220000, 0x330000, 0xc98000, 0x6e4000, 0xbee000, 0x261000 }, + { 0x800000, 0x400000, 0x200000, 0xf00000, 0xa80000, 0x540000, 0x9a0000, 0x9d0000, 0x1e8000, 0x5cc000, 0x7d2000, 0x8d1000, 0x248800, 0x71c400, 0xeba200, 0x75df00, 0x6ba280, 0x35d140, 0x4ba3a0, 0xc5d2d0, 0xe3a168, 0x91db8c, 0x79aef2, 0x0cdf41, 0x672a80, 0x501540, 0x1a01a0, 0xdd0dd0, 0x3e83e8, 0xaccacc, 0xd52d52, 0xd91d91 } +}; + +const int32 FSobol::GrayNumbers[FSobol::MaxDimension + 1][32] = { + { 0x000001, 0x000003, 0x000007, 0x00000f, 0x00001f, 0x00003f, 0x00007f, 0x0000ff, 0x0001ff, 0x0003ff, 0x0007ff, 0x000fff, 0x001fff, 0x003fff, 0x007fff, 0x00ffff, 0x01ffff, 0x03ffff, 0x07ffff, 0x0fffff, 0x1fffff, 0x3fffff, 0x7fffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff }, + { 0x800000, 0xc00000, 0xe00000, 0xf00000, 0xf80000, 0xfc0000, 0xfe0000, 0xff0000, 0xff8000, 0xffc000, 0xffe000, 0xfff000, 0xfff800, 0xfffc00, 0xfffe00, 0xffff00, 0xffff80, 0xffffc0, 0xffffe0, 0xfffff0, 0xfffff8, 0xfffffc, 0xfffffe, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff }, + { 0x800000, 0x400000, 0xe00000, 0x100000, 0x980000, 0x540000, 0xfe0000, 0x010000, 0x818000, 0x414000, 0xe1e000, 0x111000, 0x999800, 0x555400, 0xfffe00, 0x000100, 0x800180, 0x400140, 0xe001e0, 0x100110, 0x980198, 0x540154, 0xfe01fe, 0x010101, 0x818181, 0x414141, 0xe1e1e1, 0x111111, 0x999999, 0x555555, 0xffffff, 0x000000 }, + { 0x800000, 0x400000, 0x200000, 0xb00000, 0x580000, 0x040000, 0x8a0000, 0x4f0000, 0x278000, 0xbb4000, 0x552000, 0x00b000, 0x80d800, 0x404400, 0x20aa00, 0xb0ff00, 0x587f80, 0x04bf40, 0x8adf20, 0x4f4fb0, 0x272758, 0xbbbb04, 0x55558a, 0x00004f, 0x8000a7, 0x4000fb, 0x200075, 0xb000b0, 0x5800d8, 0x040044, 0x8a00aa, 0x4f00ff }, + { 0x800000, 0x400000, 0x600000, 0x300000, 0xc80000, 0xbc0000, 0x1e0000, 0x8d0000, 0x558000, 0x70c000, 0x292000, 0xcff000, 0xb7f800, 0x03f400, 0x81f600, 0x42f300, 0x627c80, 0x333bc0, 0xc8d1e0, 0xbd08d0, 0x1d8d58, 0x8cc30c, 0x572492, 0x72ffff, 0x2a7fff, 0xcf3fff, 0xb6dfff, 0x000fff, 0x8007ff, 0x400bff, 0x6009ff, 0x300cff }, + { 0x800000, 0xc00000, 0xe00000, 0x500000, 0xa80000, 0x740000, 0x0e0000, 0x930000, 0xc98000, 0xe64000, 0x472000, 0xb79000, 0x6d1800, 0x02dc00, 0x83be00, 0xc30500, 0xe18280, 0x524b40, 0xa92ee0, 0x749c30, 0x0c9e18, 0x909524, 0xca9a92, 0xe79749, 0x4510c9, 0xb6d909, 0x6dbca9, 0x000e79, 0x800c51, 0xc0076d, 0xe008db, 0x500500 }, + { 0x800000, 0xc00000, 0xa00000, 0x900000, 0x580000, 0x7c0000, 0x2a0000, 0xd10000, 0x318000, 0x41c000, 0xe9a000, 0xfd9000, 0x635800, 0xbc7c00, 0x0aaa00, 0x811100, 0xc91180, 0xad11c0, 0x9b11a0, 0x501190, 0x789158, 0x2cd17c, 0xd2b12a, 0x3d81d1, 0x43c931, 0xecad41, 0xf21be9, 0x6d90fd, 0xbb58e3, 0x007c7c, 0x80aaaa, 0xc01111 }, + { 0x800000, 0x400000, 0xe00000, 0x300000, 0x680000, 0xfc0000, 0xc20000, 0x210000, 0x9f8000, 0xbc4000, 0xa26000, 0x517000, 0x170800, 0x708c00, 0x08ca00, 0x8cad00, 0x4ad580, 0xed5140, 0x3517e0, 0x617030, 0xff08e8, 0xcc8cbc, 0x2aca22, 0x9dad11, 0xbd5577, 0xad1100, 0x557780, 0x110040, 0x778060, 0x004070, 0x806088, 0x4070cc }, + { 0x800000, 0xc00000, 0x600000, 0x300000, 0xb80000, 0x9c0000, 0x8e0000, 0xa30000, 0xd58000, 0x4bc000, 0x43e000, 0x27f000, 0x95d800, 0xe8cc00, 0x166e00, 0xac2700, 0xb60380, 0xff18c0, 0x3bad60, 0xd8def0, 0x2e5ef8, 0xf01efc, 0x583ef6, 0x6c2ef3, 0x5606fb, 0x0f12f9, 0xe3b0f8, 0x74f9fa, 0x185d7d, 0xcf0634, 0x039394, 0x84f002 }, + { 0x800000, 0xc00000, 0x600000, 0x300000, 0x180000, 0xcc0000, 0xa60000, 0xd70000, 0xef8000, 0xb7c000, 0x5de000, 0x6cf000, 0xf45800, 0xfc0c00, 0x3e2600, 0xdb0300, 0x29b180, 0x50f9c0, 0xaa5de0, 0x172ef0, 0x0f86f8, 0x47d2fc, 0x25f8f6, 0x90ddf3, 0x4a6f71, 0xe7273c, 0x77831a, 0xbbf00d, 0x9bd806, 0x8bcc07, 0x03c603, 0x87f305 }, + { 0x800000, 0xc00000, 0x200000, 0x900000, 0x080000, 0x9c0000, 0x160000, 0x4d0000, 0x7e8000, 0xa74000, 0xd56000, 0xea7000, 0x2bc800, 0x8d2400, 0xdea200, 0xf75700, 0xfd6d80, 0xe64740, 0x35d5a0, 0x5c2ad0, 0xb612d8, 0x1d3edc, 0x5698d2, 0xab7dd9, 0xcb7f50, 0x3b7999, 0x434d71, 0x675704, 0x756d8f, 0xba4746, 0x03d5af, 0x812ad7 }, + { 0x800000, 0xc00000, 0x600000, 0x700000, 0x780000, 0x140000, 0x8a0000, 0xa90000, 0xfe8000, 0x534000, 0x2ce000, 0xbd3000, 0xf4b800, 0x3a6c00, 0xb26600, 0x9e6900, 0xa06480, 0x937340, 0xccc320, 0x0d3b90, 0xecb618, 0x5e61dc, 0x4071b6, 0x235907, 0xd4dc8f, 0x691f4d, 0x1ea52e, 0xe3529d, 0x34d290, 0xd91298, 0x06b29c, 0x876296 }, + { 0x800000, 0xc00000, 0xe00000, 0xd00000, 0x880000, 0x240000, 0xb20000, 0x990000, 0x4d8000, 0x44c000, 0xa66000, 0xf43000, 0xba1800, 0x7d0400, 0x1f9a00, 0x0dfd00, 0x63ee80, 0x94df40, 0xae47e0, 0x100370, 0xe838f8, 0x34153c, 0xda139e, 0x6d300d, 0x779800, 0xf9c40e, 0x59fa05, 0x29cd04, 0x51f68c, 0xcddb46, 0x03dde1, 0x84fe76 }, + { 0x800000, 0x400000, 0xe00000, 0xb00000, 0x480000, 0xc40000, 0x260000, 0x150000, 0x1a8000, 0x3bc000, 0xae6000, 0xf01000, 0x281800, 0x343c00, 0x8e2a00, 0x611d00, 0x749b80, 0xeaf440, 0x92ef20, 0xdedbb0, 0x9cd538, 0xffdef4, 0x08739e, 0xa5000b, 0xd2800c, 0xbfc008, 0x68600c, 0x55100a, 0x7a9805, 0xcbfc0f, 0x064a08, 0x840d0e }, + { 0x800000, 0x400000, 0x200000, 0xb00000, 0x880000, 0x4c0000, 0x0e0000, 0xad0000, 0x5c8000, 0xf6c000, 0x0a2000, 0x8f3000, 0x6f3800, 0x3f3400, 0x673200, 0x333b00, 0x493880, 0x2e34c0, 0x9db0e0, 0x94fad0, 0x9995c8, 0xb6cf6c, 0xaa28a2, 0x7f3cf3, 0xc73cf3, 0xc33cf3, 0xe13cf3, 0xd23cf3, 0x1bbcf3, 0x75fcf3, 0xcb1cf3, 0xed0cf3 }, + { 0x800000, 0xc00000, 0xe00000, 0x100000, 0xb80000, 0xec0000, 0x760000, 0xeb0000, 0xf58000, 0xa94000, 0xd46000, 0x597000, 0x7df800, 0x0c3c00, 0xe79e00, 0x924100, 0xf9e380, 0xcc32c0, 0x879160, 0x4243b0, 0xa1e2d8, 0x303954, 0x4997a6, 0x4548e7, 0x226267, 0x727727, 0x687687, 0xb57b57, 0x8bf8bf, 0x273273, 0xf21f21, 0x2b02b0 } +}; + +const int32 FSobol::Cell2DDirectionNumbers[FSobol::MaxCell2DBits + 1][32][2] = { + { {0x800000, 0x800000}, {0x900000, 0x500000}, {0xc00000, 0xc00000}, {0x600000, 0x200000}, {0xe80000, 0xf80000}, {0x5c0000, 0x740000}, {0x8e0000, 0xa20000}, {0x688000, 0xd88000}, {0xc50000, 0x930000}, {0x559000, 0xe6d000}, {0x9cc000, 0x254000}, {0xee6000, 0x59e000}, {0x806800, 0x780800}, {0xc09c00, 0xb40c00}, {0x60ee00, 0x820200}, {0xe88080, 0x208f80}, {0x905500, 0xc30500}, {0x5cc0c0, 0x514740}, {0x8e6060, 0xfbea20}, {0xc59090, 0x75d930}, {0x6868e8, 0xa08588}, {0xeeee8e, 0xdbe79e}, {0x9c9c5c, 0x914e54}, {0x5555c5, 0x25db6d}, {0x8000e8, 0x588000}, {0x60008e, 0x79e000}, {0xc0005c, 0xe54000}, {0x9000c5, 0xb6d000}, {0xe80068, 0x800800}, {0x8e00ee, 0x200200}, {0x5c009c, 0xc00c00}, {0x688080, 0xf80f80} }, + { {0x900000, 0x500000}, {0x100000, 0xd00000}, {0x400000, 0x400000}, {0x600000, 0x200000}, {0x680000, 0x780000}, {0x5c0000, 0x740000}, {0x0e0000, 0x220000}, {0x788000, 0x088000}, {0x450000, 0x130000}, {0x459000, 0x36d000}, {0x0cc000, 0x754000}, {0x7e6000, 0x09e000}, {0x106800, 0x280800}, {0x409c00, 0x340c00}, {0x70ee00, 0x520200}, {0x788080, 0x708f80}, {0x105500, 0x430500}, {0x5cc0c0, 0x514740}, {0x0e6060, 0x7bea20}, {0x559090, 0x25d930}, {0x7868e8, 0x708588}, {0x6eee8e, 0x5be79e}, {0x1c9c5c, 0x114e54}, {0x5555c5, 0x25db6d}, {0x1000e8, 0x088000}, {0x60008e, 0x79e000}, {0x40005c, 0x654000}, {0x1000c5, 0x36d000}, {0x680068, 0x000800}, {0x1e00ee, 0x700200}, {0x4c009c, 0x100c00}, {0x788080, 0x280f80} }, + { {0x600000, 0x200000}, {0xb00000, 0x300000}, {0x200000, 0x600000}, {0x300000, 0xb00000}, {0x280000, 0x380000}, {0x1c0000, 0x340000}, {0x0e0000, 0x220000}, {0x188000, 0x288000}, {0x250000, 0x330000}, {0x259000, 0x16d000}, {0x2cc000, 0x154000}, {0x1e6000, 0x29e000}, {0x106800, 0x280800}, {0x209c00, 0x140c00}, {0x30ee00, 0x120200}, {0x388080, 0x308f80}, {0x305500, 0x230500}, {0x1cc0c0, 0x114740}, {0x2e6060, 0x1bea20}, {0x359090, 0x05d930}, {0x3868e8, 0x308588}, {0x2eee8e, 0x1be79e}, {0x1c9c5c, 0x114e54}, {0x3555c5, 0x05db6d}, {0x1000e8, 0x088000}, {0x20008e, 0x39e000}, {0x00005c, 0x254000}, {0x1000c5, 0x36d000}, {0x080068, 0x200800}, {0x3e00ee, 0x100200}, {0x2c009c, 0x300c00}, {0x188080, 0x080f80} }, + { {0x340000, 0x0c0000}, {0x480000, 0x180000}, {0x980000, 0x080000}, {0x1c0000, 0x340000}, {0x080000, 0x580000}, {0x180000, 0x880000}, {0x120000, 0x160000}, {0x048000, 0x1c8000}, {0x0d0000, 0x0b0000}, {0x119000, 0x1ad000}, {0x18c000, 0x194000}, {0x026000, 0x1de000}, {0x0c6800, 0x1c0800}, {0x149c00, 0x180c00}, {0x04ee00, 0x1e0200}, {0x108080, 0x088f80}, {0x185500, 0x1b0500}, {0x1cc0c0, 0x114740}, {0x1a6060, 0x17ea20}, {0x019090, 0x09d930}, {0x1068e8, 0x088588}, {0x1aee8e, 0x17e79e}, {0x1c9c5c, 0x114e54}, {0x0155c5, 0x09db6d}, {0x1000e8, 0x088000}, {0x08008e, 0x01e000}, {0x1c005c, 0x114000}, {0x0c00c5, 0x02d000}, {0x140068, 0x140800}, {0x0a00ee, 0x1c0200}, {0x04009c, 0x080c00}, {0x188080, 0x080f80} }, + { {0x168000, 0x0a8000}, {0x228000, 0x068000}, {0x4c8000, 0x048000}, {0x8e8000, 0x028000}, {0x048000, 0x1c8000}, {0x0e0000, 0x220000}, {0x0c8000, 0x448000}, {0x0e8000, 0x828000}, {0x0d0000, 0x0b0000}, {0x039000, 0x0cd000}, {0x0ac000, 0x0f4000}, {0x06e000, 0x016000}, {0x08e800, 0x008800}, {0x069c00, 0x0e0c00}, {0x006e00, 0x028200}, {0x060080, 0x020f80}, {0x0a5500, 0x0d0500}, {0x0ec0c0, 0x074740}, {0x086060, 0x01ea20}, {0x019090, 0x09d930}, {0x06e8e8, 0x020588}, {0x08ee8e, 0x01e79e}, {0x0e9c5c, 0x074e54}, {0x0155c5, 0x09db6d}, {0x0680e8, 0x020000}, {0x08008e, 0x01e000}, {0x0e005c, 0x074000}, {0x0c00c5, 0x02d000}, {0x060068, 0x020800}, {0x0e80ee, 0x008200}, {0x04009c, 0x080c00}, {0x0e0080, 0x028f80} }, + { {0x0e9000, 0x07d000}, {0x151000, 0x065000}, {0x228000, 0x068000}, {0x421000, 0x035000}, {0x801000, 0x055000}, {0x039000, 0x0cd000}, {0x071000, 0x105000}, {0x009000, 0x25d000}, {0x021000, 0x435000}, {0x001000, 0x855000}, {0x07c000, 0x044000}, {0x06e000, 0x016000}, {0x067800, 0x075800}, {0x050c00, 0x02dc00}, {0x006e00, 0x028200}, {0x060080, 0x020f80}, {0x075500, 0x060500}, {0x0050c0, 0x009740}, {0x06f060, 0x063a20}, {0x020090, 0x050930}, {0x06e8e8, 0x020588}, {0x067e8e, 0x06379e}, {0x000c5c, 0x009e54}, {0x02c5c5, 0x050b6d}, {0x0680e8, 0x020000}, {0x06908e, 0x063000}, {0x00905c, 0x009000}, {0x0290c5, 0x050000}, {0x060068, 0x020800}, {0x0010ee, 0x075200}, {0x07909c, 0x04dc00}, {0x009080, 0x055f80} }, + { {0x06e000, 0x016000}, {0x095000, 0x039000}, {0x12d000, 0x021000}, {0x23a000, 0x03a000}, {0x421000, 0x035000}, {0x813000, 0x007000}, {0x012000, 0x052000}, {0x02b000, 0x09f000}, {0x01f000, 0x113000}, {0x01b000, 0x20f000}, {0x021000, 0x435000}, {0x013000, 0x807000}, {0x01b800, 0x031800}, {0x03ec00, 0x03bc00}, {0x006e00, 0x028200}, {0x00e080, 0x036f80}, {0x009500, 0x024500}, {0x0050c0, 0x009740}, {0x013060, 0x027a20}, {0x032090, 0x002930}, {0x0008e8, 0x036588}, {0x01be8e, 0x02779e}, {0x000c5c, 0x009e54}, {0x03e5c5, 0x002b6d}, {0x0060e8, 0x036000}, {0x01508e, 0x027000}, {0x00905c, 0x009000}, {0x03b0c5, 0x002000}, {0x00e068, 0x036800}, {0x0130ee, 0x027200}, {0x00509c, 0x009c00}, {0x01b080, 0x007f80} }, + { {0x025400, 0x00a400}, {0x04b400, 0x01c400}, {0x08e800, 0x008800}, {0x113c00, 0x01ac00}, {0x204c00, 0x001c00}, {0x41fc00, 0x00ec00}, {0x813000, 0x007000}, {0x01b800, 0x031800}, {0x012000, 0x052000}, {0x00e400, 0x095400}, {0x01f000, 0x113000}, {0x01b000, 0x20f000}, {0x01fc00, 0x40ec00}, {0x013000, 0x807000}, {0x01d600, 0x019a00}, {0x015880, 0x007780}, {0x012d00, 0x015d00}, {0x0050c0, 0x009740}, {0x008860, 0x016220}, {0x017490, 0x008d30}, {0x01b0e8, 0x007d88}, {0x00068e, 0x016f9e}, {0x000c5c, 0x009e54}, {0x01b1c5, 0x008f6d}, {0x01d8e8, 0x007800}, {0x00e88e, 0x016800}, {0x00905c, 0x009000}, {0x01e4c5, 0x008400}, {0x015868, 0x007000}, {0x0088ee, 0x016a00}, {0x00509c, 0x009c00}, {0x01b080, 0x007f80} }, + { {0x015880, 0x007780}, {0x025400, 0x00a400}, {0x043a80, 0x002980}, {0x08e800, 0x008800}, {0x10ea00, 0x003600}, {0x204c00, 0x001c00}, {0x40a480, 0x009b80}, {0x806880, 0x000780}, {0x008e80, 0x01ed80}, {0x006e00, 0x028200}, {0x00f600, 0x04ba00}, {0x006a80, 0x08b980}, {0x002600, 0x10aa00}, {0x00e880, 0x208780}, {0x00a480, 0x409b80}, {0x006880, 0x800780}, {0x00fb00, 0x00c700}, {0x0050c0, 0x009740}, {0x0006e0, 0x008fa0}, {0x002c10, 0x00fab0}, {0x00e868, 0x000a08}, {0x00880e, 0x00821e}, {0x000c5c, 0x009e54}, {0x00e945, 0x00f8ed}, {0x008068, 0x000f80}, {0x00660e, 0x008580}, {0x00905c, 0x009000}, {0x00bc45, 0x00f380}, {0x0000e8, 0x000780}, {0x00066e, 0x008780}, {0x00509c, 0x009c00}, {0x00e800, 0x000800} }, + { {0x00abc0, 0x005040}, {0x015880, 0x007780}, {0x0204c0, 0x003340}, {0x043a80, 0x002980}, {0x081300, 0x004f00}, {0x1041c0, 0x006640}, {0x204c00, 0x001c00}, {0x405f80, 0x005c80}, {0x806880, 0x000780}, {0x0050c0, 0x009740}, {0x007580, 0x012a80}, {0x003ec0, 0x021540}, {0x000d00, 0x047d00}, {0x003a40, 0x082ec0}, {0x0076c0, 0x103d40}, {0x001380, 0x204080}, {0x005f80, 0x405c80}, {0x006880, 0x800780}, {0x005620, 0x0018e0}, {0x007cd0, 0x006df0}, {0x0043a8, 0x005a48}, {0x00730e, 0x00451e}, {0x005c9c, 0x000914}, {0x001245, 0x003fed}, {0x002ba8, 0x005fc0}, {0x0036ce, 0x0012c0}, {0x006b5c, 0x005700}, {0x004745, 0x003480}, {0x0000e8, 0x000780}, {0x0056ae, 0x0010c0}, {0x00005c, 0x000b40}, {0x0043c0, 0x005840} }, + { {0x005620, 0x0018e0}, {0x008130, 0x002550}, {0x012450, 0x001a70}, {0x0204c0, 0x003340}, {0x043a80, 0x002980}, {0x0839f0, 0x003a10}, {0x103d10, 0x000bb0}, {0x201a20, 0x0004e0}, {0x402350, 0x003170}, {0x803ea0, 0x001f60}, {0x002af0, 0x007510}, {0x0006e0, 0x008fa0}, {0x0023a0, 0x013260}, {0x003ec0, 0x021540}, {0x0027f0, 0x040810}, {0x003a40, 0x082ec0}, {0x0020e0, 0x1025a0}, {0x003970, 0x203590}, {0x002350, 0x403170}, {0x003ea0, 0x801f60}, {0x003f78, 0x0037b8}, {0x000fde, 0x0028ee}, {0x000abc, 0x0011f4}, {0x001245, 0x003fed}, {0x000158, 0x002ad0}, {0x0036ce, 0x0012c0}, {0x00178c, 0x003af0}, {0x001165, 0x002c60}, {0x0000e8, 0x000780}, {0x00008e, 0x000820}, {0x00005c, 0x000b40}, {0x003f10, 0x0035b0} }, + { {0x0030a6, 0x001f56}, {0x005620, 0x0018e0}, {0x008eee, 0x000dbe}, {0x0114f6, 0x000526}, {0x020b1e, 0x001bae}, {0x0405f8, 0x001e38}, {0x080688, 0x000da8}, {0x100db6, 0x0014e6}, {0x201a20, 0x0004e0}, {0x401c28, 0x0006c8}, {0x800e06, 0x000036}, {0x000fde, 0x0028ee}, {0x001588, 0x0042a8}, {0x0006e0, 0x008fa0}, {0x001cd8, 0x0105d8}, {0x000e66, 0x020a16}, {0x001756, 0x041746}, {0x000538, 0x081978}, {0x001f98, 0x101218}, {0x000608, 0x200228}, {0x001c28, 0x4006c8}, {0x000e06, 0x800036}, {0x000abc, 0x0011f4}, {0x001d9b, 0x001703}, {0x000e86, 0x00023e}, {0x000668, 0x000d96}, {0x001852, 0x00121e}, {0x001ebb, 0x00048e}, {0x0000e8, 0x000780}, {0x00008e, 0x000820}, {0x00005c, 0x000b40}, {0x000068, 0x000208} }, + { {0x001727, 0x0006f7}, {0x002d3d, 0x000855}, {0x004bbb, 0x000fe3}, {0x008eee, 0x000dbe}, {0x0103d1, 0x0003d1}, {0x0201a2, 0x000a5a}, {0x040f44, 0x000fcc}, {0x080688, 0x000da8}, {0x10070a, 0x000512}, {0x200d07, 0x000217}, {0x400b0f, 0x00003f}, {0x800e06, 0x000036}, {0x000abc, 0x0011f4}, {0x000fde, 0x0028ee}, {0x0002af, 0x00445f}, {0x0006e0, 0x008fa0}, {0x000bff, 0x01032f}, {0x000e66, 0x020a16}, {0x000acd, 0x040045}, {0x000f84, 0x08088c}, {0x000203, 0x10051b}, {0x000608, 0x200228}, {0x000b0f, 0x40003f}, {0x000e06, 0x800036}, {0x000e86, 0x00023e}, {0x000668, 0x000d96}, {0x0005c9, 0x00051d}, {0x00099c, 0x000279}, {0x0000e8, 0x000780}, {0x00008e, 0x000820}, {0x00005c, 0x000b40}, {0x000068, 0x000208} }, + { {0x000e86, 0x00023e}, {0x001727, 0x0006f7}, {0x0025d3, 0x0007fd}, {0x004355, 0x00004b}, {0x008600, 0x000216}, {0x0103d1, 0x0003d1}, {0x0207ca, 0x0007cc}, {0x0407aa, 0x000064}, {0x0800e0, 0x00003e}, {0x10070a, 0x000512}, {0x200381, 0x000029}, {0x400589, 0x000201}, {0x800080, 0x000208}, {0x000668, 0x000d96}, {0x00043a, 0x0013ca}, {0x000730, 0x002746}, {0x0002af, 0x00445f}, {0x000088, 0x008236}, {0x000579, 0x010111}, {0x000688, 0x0205be}, {0x00044b, 0x04027b}, {0x00076a, 0x080724}, {0x000203, 0x10051b}, {0x000608, 0x200228}, {0x000589, 0x400201}, {0x000080, 0x800208}, {0x0005c9, 0x00051d}, {0x00071a, 0x000047}, {0x0000e8, 0x000780}, {0x0006e6, 0x0005b6}, {0x000634, 0x0006d6}, {0x000068, 0x000208} }, + { {0x00071a, 0x000047}, {0x00099c, 0x000279}, {0x0012ee, 0x0003ea}, {0x00201a, 0x0002e0}, {0x004355, 0x00004b}, {0x00811a, 0x000251}, {0x0103d1, 0x0003d1}, {0x020203, 0x0002d1}, {0x0400b0, 0x000023}, {0x0800e0, 0x00003e}, {0x1002c3, 0x00000f}, {0x200381, 0x000029}, {0x400293, 0x000246}, {0x800080, 0x000208}, {0x0002d3, 0x00055a}, {0x0003a1, 0x00088b}, {0x000320, 0x00138d}, {0x0002f9, 0x00225b}, {0x00007c, 0x004105}, {0x000088, 0x008236}, {0x000263, 0x010156}, {0x000341, 0x0200a3}, {0x000351, 0x04023c}, {0x0002a3, 0x080239}, {0x0000d0, 0x100041}, {0x000112, 0x20026f}, {0x000293, 0x400246}, {0x000080, 0x800208}, {0x00023b, 0x0002da}, {0x00032f, 0x0000ab}, {0x0003fd, 0x0003cb}, {0x000068, 0x000208} }, + { {0x00032f, 0x0000ab}, {0x000435, 0x0000ec}, {0x000888, 0x000008}, {0x0010d5, 0x000130}, {0x00210e, 0x000091}, {0x00407a, 0x0000e0}, {0x00800e, 0x000020}, {0x0101ea, 0x00010b}, {0x020038, 0x00000b}, {0x0400b0, 0x000023}, {0x0800e0, 0x00003e}, {0x1001ec, 0x0000a4}, {0x2000ae, 0x000082}, {0x4000a8, 0x00009c}, {0x800194, 0x000079}, {0x000114, 0x000271}, {0x0001fc, 0x0005f1}, {0x00008e, 0x000820}, {0x00011b, 0x001157}, {0x0000c2, 0x002081}, {0x00007c, 0x004105}, {0x00019c, 0x008047}, {0x00014c, 0x0101fd}, {0x00006e, 0x020008}, {0x00016a, 0x0400e6}, {0x000098, 0x0800e3}, {0x0000d0, 0x100041}, {0x000006, 0x20001e}, {0x0000a8, 0x40009c}, {0x000194, 0x800079}, {0x0001c6, 0x000111}, {0x00017c, 0x000079} } +}; + +const int32 FSobol::Cell2DGrayNumbers[FSobol::MaxCell2DBits + 1][32][2] = { + { {0x800000, 0x800000}, {0x100000, 0xd00000}, {0x500000, 0x900000}, {0xa00000, 0xe00000}, {0x880000, 0xd80000}, {0xb40000, 0x8c0000}, {0xd20000, 0xd60000}, {0xe68000, 0x7a8000}, {0xad8000, 0x4b8000}, {0x909000, 0x75d000}, {0xc95000, 0xc39000}, {0x72a000, 0x7ca000}, {0x6e0800, 0x21e800}, {0x40f400, 0xcc0400}, {0xa07200, 0x360e00}, {0x886e80, 0xa28d80}, {0x78d580, 0xe38a80}, {0xcc95c0, 0x924240}, {0xd2a0a0, 0xaaad60}, {0x4bf0f0, 0x8e3310}, {0xadf878, 0xd55cb8}, {0x868666, 0x7b6216}, {0x7272d2, 0x4aa9ca}, {0xc9c999, 0xb49539}, {0xd5552d, 0x7d5b6d}, {0xe00066, 0x216000}, {0xa000d2, 0x9ca000}, {0x500099, 0x539000}, {0x7800ad, 0x36d800}, {0x660086, 0xa00a00}, {0xd20072, 0xe00e00}, {0x34801c, 0x380380} }, + { {0x400000, 0x400000}, {0x200000, 0x600000}, {0x080000, 0x580000}, {0x340000, 0x0c0000}, {0x520000, 0x560000}, {0x768000, 0x2a8000}, {0x3d8000, 0x1b8000}, {0x009000, 0x25d000}, {0x495000, 0x439000}, {0x72a000, 0x7ca000}, {0x6e0800, 0x21e800}, {0x50f400, 0x1c0400}, {0x307200, 0x660e00}, {0x086e80, 0x228d80}, {0x68d580, 0x338a80}, {0x4c95c0, 0x124240}, {0x52a0a0, 0x2aad60}, {0x5bf0f0, 0x5e3310}, {0x2df878, 0x555cb8}, {0x168666, 0x2b6216}, {0x7272d2, 0x4aa9ca}, {0x49c999, 0x349539}, {0x45552d, 0x2d5b6d}, {0x700066, 0x716000}, {0x2000d2, 0x1ca000}, {0x500099, 0x539000}, {0x7800ad, 0x36d800}, {0x760086, 0x700a00}, {0x520072, 0x600e00}, {0x34801c, 0x380380}, {0x2d80d5, 0x280a80}, {0x3b6035, 0x220f20} }, + { {0x280000, 0x380000}, {0x340000, 0x0c0000}, {0x120000, 0x160000}, {0x168000, 0x0a8000}, {0x3d8000, 0x1b8000}, {0x009000, 0x25d000}, {0x095000, 0x039000}, {0x32a000, 0x3ca000}, {0x0e0800, 0x01e800}, {0x30f400, 0x3c0400}, {0x107200, 0x060e00}, {0x086e80, 0x228d80}, {0x08d580, 0x138a80}, {0x2c95c0, 0x324240}, {0x32a0a0, 0x0aad60}, {0x1bf0f0, 0x1e3310}, {0x0df878, 0x355cb8}, {0x168666, 0x2b6216}, {0x3272d2, 0x0aa9ca}, {0x29c999, 0x149539}, {0x25552d, 0x0d5b6d}, {0x300066, 0x316000}, {0x2000d2, 0x1ca000}, {0x100099, 0x139000}, {0x1800ad, 0x16d800}, {0x360086, 0x300a00}, {0x120072, 0x200e00}, {0x34801c, 0x380380}, {0x2d80d5, 0x280a80}, {0x3b6035, 0x220f20}, {0x02a0a0, 0x260d60}, {0x095050, 0x270e70} }, + { {0x120000, 0x160000}, {0x168000, 0x0a8000}, {0x098000, 0x178000}, {0x1c9000, 0x11d000}, {0x095000, 0x039000}, {0x1aa000, 0x04a000}, {0x0e0800, 0x01e800}, {0x18f400, 0x040400}, {0x107200, 0x060e00}, {0x146e80, 0x168d80}, {0x08d580, 0x138a80}, {0x0495c0, 0x0a4240}, {0x06a0a0, 0x06ad60}, {0x1bf0f0, 0x1e3310}, {0x11f878, 0x015cb8}, {0x0a8666, 0x1f6216}, {0x0672d2, 0x06a9ca}, {0x1dc999, 0x189539}, {0x11552d, 0x015b6d}, {0x180066, 0x096000}, {0x1400d2, 0x10a000}, {0x100099, 0x139000}, {0x1800ad, 0x16d800}, {0x1e0086, 0x080a00}, {0x0e0072, 0x140e00}, {0x1c801c, 0x000380}, {0x0580d5, 0x100a80}, {0x136035, 0x1a0f20}, {0x1ea0a0, 0x120d60}, {0x155050, 0x130e70}, {0x0df878, 0x0384b8}, {0x04f4b4, 0x01cfdc} }, + { {0x0d0000, 0x0b0000}, {0x0e9000, 0x07d000}, {0x095000, 0x039000}, {0x0c2000, 0x0e2000}, {0x0e0800, 0x01e800}, {0x0e7400, 0x0e8400}, {0x06f200, 0x0c8e00}, {0x066e80, 0x008d80}, {0x0c5580, 0x0f0a80}, {0x0495c0, 0x0a4240}, {0x06a0a0, 0x06ad60}, {0x09f0f0, 0x083310}, {0x077878, 0x0bdcb8}, {0x0e0666, 0x03e216}, {0x0672d2, 0x06a9ca}, {0x0fc999, 0x0e9539}, {0x07d52d, 0x0bdb6d}, {0x0e8066, 0x03e000}, {0x0600d2, 0x06a000}, {0x020099, 0x059000}, {0x0a00ad, 0x00d800}, {0x088086, 0x028a00}, {0x0a8072, 0x088e00}, {0x0a001c, 0x0a8380}, {0x0100d5, 0x0c8a80}, {0x016035, 0x0c0f20}, {0x0ca0a0, 0x040d60}, {0x075050, 0x050e70}, {0x0df878, 0x0384b8}, {0x04f4b4, 0x01cfdc}, {0x0a72d2, 0x02a7ca}, {0x08ee66, 0x016a1e} }, + { {0x07c000, 0x044000}, {0x012000, 0x052000}, {0x009800, 0x063800}, {0x037400, 0x058400}, {0x056200, 0x005e00}, {0x066e80, 0x008d80}, {0x015580, 0x040a80}, {0x0705c0, 0x069240}, {0x06a0a0, 0x06ad60}, {0x04f0f0, 0x033310}, {0x04e878, 0x070cb8}, {0x009666, 0x043216}, {0x0672d2, 0x06a9ca}, {0x02c999, 0x059539}, {0x04452d, 0x070b6d}, {0x001066, 0x043000}, {0x0600d2, 0x06a000}, {0x020099, 0x059000}, {0x0490ad, 0x070800}, {0x061086, 0x055a00}, {0x078072, 0x038e00}, {0x07001c, 0x018380}, {0x0290d5, 0x005a80}, {0x02f035, 0x00df20}, {0x0230a0, 0x03dd60}, {0x075050, 0x050e70}, {0x036878, 0x0454b8}, {0x04f4b4, 0x01cfdc}, {0x04e2d2, 0x0577ca}, {0x067e66, 0x06ba1e}, {0x07552d, 0x0351ed}, {0x050599, 0x00092d} }, + { {0x01b800, 0x031800}, {0x025400, 0x00a400}, {0x038200, 0x013e00}, {0x008e80, 0x01ed80}, {0x007580, 0x012a80}, {0x00c5c0, 0x02d240}, {0x0160a0, 0x02ed60}, {0x0210f0, 0x025310}, {0x032878, 0x034cb8}, {0x01b666, 0x011216}, {0x01b2d2, 0x02e9ca}, {0x03e999, 0x00b539}, {0x03852d, 0x034b6d}, {0x013066, 0x011000}, {0x01c0d2, 0x02e000}, {0x032099, 0x00b000}, {0x0350ad, 0x034800}, {0x01d086, 0x011a00}, {0x016072, 0x02ee00}, {0x01e01c, 0x00e380}, {0x0290d5, 0x005a80}, {0x02f035, 0x00df20}, {0x0230a0, 0x03dd60}, {0x009050, 0x014e70}, {0x024878, 0x0174b8}, {0x0214b4, 0x00afdc}, {0x0322d2, 0x0137ca}, {0x01be66, 0x02fa1e}, {0x01b52d, 0x0231ed}, {0x03e599, 0x01692d}, {0x0230d2, 0x03dd60}, {0x02a04b, 0x029310} }, + { {0x01d600, 0x019a00}, {0x008e80, 0x01ed80}, {0x007580, 0x012a80}, {0x017dc0, 0x01ca40}, {0x00d8a0, 0x01f560}, {0x01fcf0, 0x01ef10}, {0x00c478, 0x00f0b8}, {0x01b666, 0x011216}, {0x000ad2, 0x01f1ca}, {0x01bd99, 0x001139}, {0x00692d, 0x00f76d}, {0x013066, 0x011000}, {0x0078d2, 0x01f800}, {0x017499, 0x001400}, {0x00bcad, 0x00f400}, {0x01d086, 0x011a00}, {0x00d872, 0x01f600}, {0x01e01c, 0x00e380}, {0x00c4d5, 0x00fe80}, {0x00a435, 0x007b20}, {0x01dca0, 0x006160}, {0x009050, 0x014e70}, {0x001c78, 0x01d0b8}, {0x0040b4, 0x000bdc}, {0x0176d2, 0x0193ca}, {0x000666, 0x01e21e}, {0x000d2d, 0x0129ed}, {0x01b199, 0x01cd2d}, {0x01dcd2, 0x006160}, {0x014c4b, 0x012f10}, {0x001cad, 0x01d0b8}, {0x0040f4, 0x000bdc} }, + { {0x00fb00, 0x00c700}, {0x00abc0, 0x005040}, {0x005620, 0x0018e0}, {0x002af0, 0x007510}, {0x00c478, 0x00f0b8}, {0x006066, 0x008816}, {0x008452, 0x001c4a}, {0x00e519, 0x0066b9}, {0x00692d, 0x00f76d}, {0x00e666, 0x008a00}, {0x00f652, 0x001580}, {0x002c19, 0x006380}, {0x00bcad, 0x00f400}, {0x000686, 0x008000}, {0x0056f2, 0x001b80}, {0x00b89c, 0x009400}, {0x00c4d5, 0x00fe80}, {0x00a435, 0x007b20}, {0x008420, 0x0016e0}, {0x001ed0, 0x00a3f0}, {0x0092f8, 0x003d38}, {0x0040b4, 0x000bdc}, {0x00a0d2, 0x0009ca}, {0x0088e6, 0x000f9e}, {0x0083ad, 0x00c46d}, {0x006799, 0x00572d}, {0x008452, 0x0016e0}, {0x009a4b, 0x00b510}, {0x00922d, 0x003d38}, {0x0040f4, 0x000bdc}, {0x00a072, 0x0009ca}, {0x000bbb, 0x00cbf3} }, + { {0x005620, 0x0018e0}, {0x002af0, 0x007510}, {0x003f78, 0x0037b8}, {0x0030a6, 0x001f56}, {0x002f92, 0x004c0a}, {0x004ed9, 0x0036f9}, {0x0039ed, 0x00602d}, {0x001d66, 0x004d00}, {0x005d92, 0x0045c0}, {0x002c19, 0x006380}, {0x0047ad, 0x003300}, {0x005646, 0x001740}, {0x0056f2, 0x001b80}, {0x00439c, 0x005300}, {0x003fd5, 0x003980}, {0x000ff5, 0x002b60}, {0x002fe0, 0x0046a0}, {0x004e10, 0x0034b0}, {0x003938, 0x006d78}, {0x0040b4, 0x000bdc}, {0x000b12, 0x00598a}, {0x002326, 0x005fde}, {0x0078ad, 0x00036d}, {0x006799, 0x00572d}, {0x002f92, 0x0046a0}, {0x00614b, 0x007210}, {0x0039ed, 0x006d78}, {0x0040f4, 0x000bdc}, {0x000bb2, 0x00598a}, {0x005b7b, 0x005cb3}, {0x0078d5, 0x00036d}, {0x001f80, 0x005440} }, + { {0x003f78, 0x0037b8}, {0x0030a6, 0x001f56}, {0x000562, 0x00391a}, {0x0018f9, 0x002e19}, {0x00131d, 0x00153d}, {0x003796, 0x003810}, {0x002142, 0x002830}, {0x0006e9, 0x001690}, {0x00118d, 0x002be0}, {0x000066, 0x000fa0}, {0x0000d2, 0x000360}, {0x003f4c, 0x003ef0}, {0x003fd5, 0x003980}, {0x000ff5, 0x002b60}, {0x000510, 0x0033b0}, {0x001830, 0x002c50}, {0x0013c8, 0x001868}, {0x001694, 0x00133c}, {0x0021e2, 0x002c9a}, {0x0009d6, 0x002ace}, {0x002e8d, 0x001b8d}, {0x001b49, 0x003add}, {0x000562, 0x0033b0}, {0x001d9b, 0x001fe0}, {0x00131d, 0x001868}, {0x0016d4, 0x00133c}, {0x002142, 0x002c9a}, {0x0027ab, 0x003143}, {0x002ef5, 0x001b8d}, {0x003570, 0x002150}, {0x001860, 0x002c50}, {0x0013b0, 0x001868} }, + { {0x000abc, 0x0011f4}, {0x001727, 0x0006f7}, {0x00131d, 0x00153d}, {0x0008ee, 0x000fa8}, {0x001e3a, 0x001f88}, {0x0006e9, 0x001690}, {0x001e53, 0x00030e}, {0x000066, 0x000fa0}, {0x0000d2, 0x000360}, {0x000034, 0x000948}, {0x0000ad, 0x000e38}, {0x00002b, 0x00038e}, {0x000ace, 0x001b5e}, {0x0017ee, 0x0004be}, {0x0013c8, 0x001868}, {0x001694, 0x00133c}, {0x001e9a, 0x001b22}, {0x000608, 0x000220}, {0x001e2b, 0x0004db}, {0x001497, 0x001233}, {0x000abc, 0x001b5e}, {0x001d9b, 0x001fe0}, {0x00131d, 0x001868}, {0x0016d4, 0x00133c}, {0x001e3a, 0x001b22}, {0x0018d3, 0x0006fb}, {0x001e53, 0x0004db}, {0x000a08, 0x0016e8}, {0x0017be, 0x0004be}, {0x0013b0, 0x001868}, {0x000e60, 0x000788}, {0x001840, 0x0014b4} }, + { {0x000e86, 0x00023e}, {0x0008ee, 0x000fa8}, {0x0003a1, 0x00088b}, {0x000c55, 0x000764}, {0x000974, 0x0005f9}, {0x000066, 0x000fa0}, {0x0000d2, 0x000360}, {0x000034, 0x000948}, {0x0000ad, 0x000e38}, {0x00002b, 0x00038e}, {0x000072, 0x000aaa}, {0x0000c9, 0x000249}, {0x000e53, 0x000f6b}, {0x000b0f, 0x00043f}, {0x000301, 0x000c21}, {0x000608, 0x000220}, {0x00090c, 0x00022c}, {0x00090c, 0x000530}, {0x000000, 0x000aaa}, {0x000000, 0x0008e3}, {0x000e86, 0x000f6b}, {0x000b4f, 0x00043f}, {0x0003a1, 0x000c21}, {0x000ff4, 0x00000c}, {0x000974, 0x00022c}, {0x0000b4, 0x00071c}, {0x000099, 0x000249}, {0x000e2b, 0x000f6b}, {0x000e60, 0x000788}, {0x0005db, 0x0003b7}, {0x0003d3, 0x000c21}, {0x000f4f, 0x00000c} }, + { {0x0005c9, 0x00051d}, {0x0002d3, 0x00055a}, {0x0007f2, 0x0007c7}, {0x00060e, 0x000236}, {0x0000d2, 0x000360}, {0x00065c, 0x0004de}, {0x0006c5, 0x0003ae}, {0x00002b, 0x00038e}, {0x00061a, 0x00073c}, {0x0000c9, 0x000249}, {0x0006bd, 0x0000c3}, {0x000589, 0x000601}, {0x000569, 0x0001b7}, {0x000608, 0x000220}, {0x00078a, 0x000012}, {0x00078a, 0x00070e}, {0x000668, 0x00073c}, {0x000668, 0x000575}, {0x000668, 0x0000c3}, {0x0005c9, 0x000601}, {0x0005c9, 0x0001b7}, {0x000172, 0x000232}, {0x0007f2, 0x000012}, {0x0000b4, 0x00071c}, {0x000099, 0x000249}, {0x0006c5, 0x0000c3}, {0x0000e6, 0x0005b6}, {0x0005db, 0x0003b7}, {0x0005bb, 0x0001b7}, {0x0001c9, 0x000232}, {0x000727, 0x000012}, {0x0006ee, 0x000020} }, + { {0x00023b, 0x0002da}, {0x000114, 0x000271}, {0x0000d2, 0x000360}, {0x000395, 0x0001c3}, {0x0001df, 0x0003e9}, {0x00002b, 0x00038e}, {0x0003d3, 0x000221}, {0x0000c9, 0x000249}, {0x0001a7, 0x000084}, {0x000040, 0x00031c}, {0x000273, 0x0001f0}, {0x000112, 0x000267}, {0x000090, 0x000055}, {0x000243, 0x000213}, {0x0003a1, 0x000221}, {0x0003a1, 0x000068}, {0x000172, 0x000084}, {0x000000, 0x00031c}, {0x0002d3, 0x0001f0}, {0x000172, 0x000232}, {0x0000e8, 0x000055}, {0x000267, 0x000246}, {0x000099, 0x000249}, {0x0001df, 0x000084}, {0x000235, 0x0000ec}, {0x0002c1, 0x0003f0}, {0x0002a1, 0x0001f0}, {0x0001c9, 0x000232}, {0x00003d, 0x000055}, {0x0001f4, 0x000067}, {0x0003d3, 0x000221}, {0x0000c9, 0x000249} }, + { {0x0001c6, 0x000111}, {0x0000ba, 0x000168}, {0x0000cb, 0x000198}, {0x00013f, 0x0001ff}, {0x0001e8, 0x0000fb}, {0x0001dd, 0x000038}, {0x0001a7, 0x000084}, {0x000154, 0x00016d}, {0x00015c, 0x00015b}, {0x000006, 0x000016}, {0x000090, 0x000055}, {0x000078, 0x0000c9}, {0x00019a, 0x0000fb}, {0x00008e, 0x0000c3}, {0x000172, 0x000084}, {0x000114, 0x00016d}, {0x0001fc, 0x00015b}, {0x000066, 0x000043}, {0x0000e8, 0x000055}, {0x00005c, 0x00009c}, {0x00018d, 0x000038}, {0x0001df, 0x000084}, {0x00011a, 0x000047}, {0x0000fa, 0x00012a}, {0x00018e, 0x00015b}, {0x0000dd, 0x000043}, {0x00003d, 0x000055}, {0x0001f4, 0x000067}, {0x0001e8, 0x0000fb}, {0x0001dd, 0x000038}, {0x0001a7, 0x000084}, {0x000154, 0x00016d} } +}; + +const int32 FSobol::Cell3DDirectionNumbers[FSobol::MaxCell3DBits + 1][32][3] = { + { {0x800000, 0x800000, 0x800000}, {0xc00000, 0xc00000, 0x400000}, {0x900000, 0x500000, 0xb00000}, {0x600000, 0x200000, 0x200000}, {0xe80000, 0xf80000, 0xf80000}, {0x8e0000, 0xa20000, 0x7a0000}, {0x5c0000, 0x740000, 0xdc0000}, {0xc50000, 0x930000, 0x9d0000}, {0x688000, 0xd88000, 0x5a8000}, {0x9cc000, 0x254000, 0x2fc000}, {0xee6000, 0x59e000, 0xa16000}, {0x559000, 0xe6d000, 0xf0b000}, {0xc09c00, 0xb40c00, 0x6fc400}, {0x60ee00, 0x820200, 0x816200}, {0xe88080, 0x208f80, 0x228780}, {0x806800, 0x780800, 0xda8800}, {0x905500, 0xc30500, 0x40bb00}, {0x5cc0c0, 0x514740, 0xb3c9c0}, {0x8e6060, 0xfbea20, 0xfb65a0}, {0x6868e8, 0xa08588, 0x780228}, {0x9c9c5c, 0x914e54, 0x9c0b3c}, {0xc59090, 0x75d930, 0xddb2d0}, {0x5555c5, 0x25db6d, 0x2d0ddb}, {0x8000e8, 0x588000, 0xa28780}, {0xeeee8e, 0xdbe79e, 0x5a0fb6}, {0xc0005c, 0xe54000, 0xf3c9c0}, {0x60008e, 0x79e000, 0xdb65a0}, {0x9000c5, 0xb6d000, 0x6db2d0}, {0xe80068, 0x800800, 0x800228}, {0x8e00ee, 0x200200, 0x200fb6}, {0x5c009c, 0xc00c00, 0x400b3c}, {0xc50055, 0x500500, 0xb00ddb} }, + { {0xd00000, 0x100000, 0x700000}, {0x100000, 0xd00000, 0x300000}, {0x400000, 0x400000, 0xc00000}, {0x600000, 0x200000, 0x200000}, {0x680000, 0x780000, 0x780000}, {0x4e0000, 0x620000, 0x3a0000}, {0x1c0000, 0x340000, 0x1c0000}, {0x450000, 0x130000, 0x1d0000}, {0x788000, 0x088000, 0x6a8000}, {0x4cc000, 0x354000, 0x5fc000}, {0x7e6000, 0x09e000, 0x116000}, {0x059000, 0x76d000, 0x00b000}, {0x009c00, 0x740c00, 0x2fc400}, {0x30ee00, 0x120200, 0x716200}, {0x388080, 0x308f80, 0x528780}, {0x106800, 0x280800, 0x6a8800}, {0x505500, 0x030500, 0x00bb00}, {0x1cc0c0, 0x114740, 0x73c9c0}, {0x0e6060, 0x7bea20, 0x7b65a0}, {0x7868e8, 0x708588, 0x480228}, {0x1c9c5c, 0x114e54, 0x1c0b3c}, {0x559090, 0x25d930, 0x6db2d0}, {0x5555c5, 0x25db6d, 0x2d0ddb}, {0x1000e8, 0x088000, 0x128780}, {0x2eee8e, 0x1be79e, 0x1a0fb6}, {0x40005c, 0x654000, 0x73c9c0}, {0x20008e, 0x39e000, 0x1b65a0}, {0x5000c5, 0x76d000, 0x2db2d0}, {0x680068, 0x000800, 0x000228}, {0x5e00ee, 0x300200, 0x500fb6}, {0x4c009c, 0x100c00, 0x700b3c}, {0x550055, 0x000500, 0x000ddb} }, + { {0x600000, 0x200000, 0x200000}, {0x960000, 0x2a0000, 0x120000}, {0x2e0000, 0x420000, 0x1a0000}, {0x3e0000, 0x920000, 0x2a0000}, {0x260000, 0x1a0000, 0x420000}, {0x280000, 0x380000, 0xb80000}, {0x1c0000, 0x340000, 0x1c0000}, {0x250000, 0x330000, 0x3d0000}, {0x3e8000, 0x328000, 0x088000}, {0x0ac000, 0x0f4000, 0x3dc000}, {0x1e6000, 0x29e000, 0x316000}, {0x2b9000, 0x34d000, 0x1ab000}, {0x2e9c00, 0x360c00, 0x35c400}, {0x16ee00, 0x080200, 0x336200}, {0x1e8080, 0x2a8f80, 0x108780}, {0x366800, 0x320800, 0x288800}, {0x305500, 0x230500, 0x20bb00}, {0x3ac0c0, 0x0b4740, 0x31c9c0}, {0x066060, 0x23ea20, 0x2365a0}, {0x1068e8, 0x088588, 0x300228}, {0x1c9c5c, 0x114e54, 0x1c0b3c}, {0x139090, 0x1fd930, 0x0fb2d0}, {0x3555c5, 0x05db6d, 0x0d0ddb}, {0x1000e8, 0x088000, 0x128780}, {0x2eee8e, 0x1be79e, 0x1a0fb6}, {0x28005c, 0x1d4000, 0x0bc9c0}, {0x20008e, 0x39e000, 0x1b65a0}, {0x1e00c5, 0x14d000, 0x17b2d0}, {0x080068, 0x200800, 0x200228}, {0x1800ee, 0x0a0200, 0x320fb6}, {0x0a009c, 0x2a0c00, 0x120b3c}, {0x350055, 0x200500, 0x200ddb} }, + { {0x228000, 0x068000, 0x148000}, {0x450000, 0x130000, 0x1d0000}, {0x8a0000, 0x1e0000, 0x0e0000}, {0x1c0000, 0x340000, 0x1c0000}, {0x0c8000, 0x448000, 0x0e8000}, {0x070000, 0x950000, 0x0b0000}, {0x1b8000, 0x018000, 0x358000}, {0x048000, 0x1c8000, 0x568000}, {0x0d0000, 0x0b0000, 0x850000}, {0x114000, 0x0ec000, 0x084000}, {0x19e000, 0x1c6000, 0x18e000}, {0x151000, 0x065000, 0x123000}, {0x0b9c00, 0x050c00, 0x08c400}, {0x0d6e00, 0x098200, 0x06e200}, {0x028080, 0x1e8f80, 0x0c8780}, {0x136800, 0x010800, 0x158800}, {0x155500, 0x100500, 0x1dbb00}, {0x03c0c0, 0x0c4740, 0x10c9c0}, {0x01e060, 0x166a20, 0x0ae5a0}, {0x0be8e8, 0x090588, 0x058228}, {0x1c9c5c, 0x114e54, 0x1c0b3c}, {0x139090, 0x1fd930, 0x0fb2d0}, {0x17d5c5, 0x035b6d, 0x198ddb}, {0x1000e8, 0x088000, 0x128780}, {0x0c6e8e, 0x1d679e, 0x0e8fb6}, {0x0a805c, 0x1bc000, 0x1f49c0}, {0x1e808e, 0x0b6000, 0x13e5a0}, {0x1e00c5, 0x14d000, 0x17b2d0}, {0x0f8068, 0x158800, 0x098228}, {0x0380ee, 0x0b8200, 0x078fb6}, {0x16009c, 0x1e0c00, 0x0e0b3c}, {0x100055, 0x130500, 0x1d0ddb} }, + { {0x114000, 0x0ec000, 0x084000}, {0x26d000, 0x0e1000, 0x0ef000}, {0x4da000, 0x01a000, 0x0da000}, {0x86f000, 0x043000, 0x04d000}, {0x0cf000, 0x1a3000, 0x0ad000}, {0x05e000, 0x286000, 0x04e000}, {0x0c8000, 0x448000, 0x0e8000}, {0x0bf000, 0x8f3000, 0x01d000}, {0x045000, 0x089000, 0x1a7000}, {0x0e9000, 0x07d000, 0x27b000}, {0x0c2000, 0x0e2000, 0x462000}, {0x0d0000, 0x0b0000, 0x850000}, {0x0b9c00, 0x050c00, 0x08c400}, {0x0d6e00, 0x098200, 0x06e200}, {0x0e7080, 0x04bf80, 0x065780}, {0x067800, 0x075800, 0x07b800}, {0x0cb500, 0x0c6500, 0x055b00}, {0x0790c0, 0x04d740, 0x0ab9c0}, {0x0d1060, 0x0c5a20, 0x0035a0}, {0x0be8e8, 0x090588, 0x058228}, {0x057c5c, 0x0d2e54, 0x04eb3c}, {0x0e2090, 0x0b2930, 0x0d22d0}, {0x02c5c5, 0x050b6d, 0x0bbddb}, {0x0510e8, 0x0ed000, 0x00b780}, {0x009e8e, 0x07579e, 0x045fb6}, {0x02205c, 0x096000, 0x0fe9c0}, {0x0b908e, 0x0d3000, 0x01d5a0}, {0x07e0c5, 0x08b000, 0x0f52d0}, {0x037068, 0x0fb800, 0x035228}, {0x0380ee, 0x0b8200, 0x078fb6}, {0x0bb09c, 0x0afc00, 0x0c9b3c}, {0x09e055, 0x0f6500, 0x05eddb} }, + { {0x0e7080, 0x04bf80, 0x065780}, {0x17b200, 0x024e00, 0x066600}, {0x202200, 0x029e00, 0x00d600}, {0x463c00, 0x04ac00, 0x056400}, {0x86f000, 0x043000, 0x04d000}, {0x031e80, 0x0d3d80, 0x00b580}, {0x047280, 0x120180, 0x02a180}, {0x06fe80, 0x255d80, 0x045580}, {0x071c00, 0x418c00, 0x064400}, {0x069e00, 0x86b200, 0x073200}, {0x05ec80, 0x01b380, 0x0e9380}, {0x02a200, 0x041e00, 0x145600}, {0x00e080, 0x036f80, 0x21e780}, {0x014e00, 0x07a200, 0x40c200}, {0x006e00, 0x028200, 0x83e200}, {0x067800, 0x075800, 0x07b800}, {0x01db00, 0x05e700, 0x03b900}, {0x027c40, 0x0564c0, 0x042a40}, {0x007e60, 0x05d820, 0x06d7a0}, {0x0686e8, 0x008788, 0x036028}, {0x0662dc, 0x0013d4, 0x045ebc}, {0x06a210, 0x0318b0, 0x055350}, {0x072945, 0x04b8ed, 0x052e5b}, {0x060e68, 0x03ed80, 0x000200}, {0x009e8e, 0x07579e, 0x045fb6}, {0x04d25c, 0x05ee00, 0x01cfc0}, {0x06fe8e, 0x04b200, 0x0737a0}, {0x0112c5, 0x043e00, 0x0174d0}, {0x006ee8, 0x028580, 0x03e7a8}, {0x009e6e, 0x06bf80, 0x073a36}, {0x03321c, 0x02cd80, 0x04eabc}, {0x048e55, 0x06e700, 0x030fdb} }, + { {0x040440, 0x023cc0, 0x039240}, {0x080880, 0x03e780, 0x01ef80}, {0x101100, 0x00f100, 0x026700}, {0x202200, 0x029e00, 0x00d600}, {0x404400, 0x03f400, 0x02dc00}, {0x808800, 0x036800, 0x036800}, {0x01db00, 0x05e700, 0x03b900}, {0x02c580, 0x08da80, 0x030c80}, {0x0076c0, 0x103d40, 0x0133c0}, {0x008680, 0x220580, 0x03ed80}, {0x00bf00, 0x433300, 0x024500}, {0x00e600, 0x81ea00, 0x008a00}, {0x03a740, 0x0083c0, 0x079340}, {0x024f80, 0x030c80, 0x0a9280}, {0x00de40, 0x017ac0, 0x107c40}, {0x00e080, 0x036f80, 0x21e780}, {0x009500, 0x024500, 0x437b00}, {0x006e00, 0x028200, 0x83e200}, {0x020220, 0x00bce0, 0x02fde0}, {0x0282a8, 0x02bb48, 0x00f268}, {0x01c1dc, 0x02acd4, 0x005fbc}, {0x010110, 0x01a7b0, 0x015250}, {0x015145, 0x03e0ed, 0x02965b}, {0x020a28, 0x01d140, 0x039040}, {0x02e2ce, 0x02335e, 0x0075f6}, {0x010d1c, 0x0235c0, 0x01e480}, {0x00868e, 0x03ea00, 0x008fa0}, {0x00c9c5, 0x01d900, 0x02cdd0}, {0x006ee8, 0x028580, 0x03e7a8}, {0x02e22e, 0x03db40, 0x031076}, {0x00955c, 0x024e40, 0x0379fc}, {0x015115, 0x013cc0, 0x03249b} }, + { {0x034374, 0x00179c, 0x00add4}, {0x0484c8, 0x003b68, 0x019dc8}, {0x09c95c, 0x014b54, 0x01b03c}, {0x115054, 0x005a7c, 0x003734}, {0x21e3dc, 0x0032d4, 0x0089bc}, {0x40c488, 0x01f3a8, 0x00d388}, {0x800888, 0x016fa8, 0x016788}, {0x01c1dc, 0x02acd4, 0x005fbc}, {0x009a54, 0x054c7c, 0x01e934}, {0x00c7a0, 0x086660, 0x01f160}, {0x0076c0, 0x103d40, 0x0133c0}, {0x000608, 0x200228, 0x01e208}, {0x003f88, 0x4134a8, 0x004a88}, {0x00e600, 0x81ea00, 0x008a00}, {0x014154, 0x00ab7c, 0x025034}, {0x01a560, 0x003f20, 0x056ea0}, {0x018c7c, 0x011cb4, 0x0830dc}, {0x00de40, 0x017ac0, 0x107c40}, {0x01215c, 0x01c354, 0x21b83c}, {0x001588, 0x0042a8, 0x417488}, {0x00ee88, 0x0085a8, 0x81ed88}, {0x010110, 0x01a7b0, 0x015250}, {0x01d1cd, 0x01e745, 0x0099d3}, {0x000808, 0x016da0, 0x016da0}, {0x006066, 0x008816, 0x00879e}, {0x00ccc0, 0x009914, 0x01bb3c}, {0x014752, 0x0146d4, 0x00d01c}, {0x018891, 0x01727c, 0x009de4}, {0x00ee60, 0x008228, 0x01e820}, {0x0121d2, 0x01cb74, 0x01b22a}, {0x0015d4, 0x0049e8, 0x017674}, {0x001041, 0x0197bc, 0x0174af} }, + { {0x010918, 0x00ca10, 0x003ff0}, {0x024a6c, 0x00dd8c, 0x009224}, {0x045415, 0x007b9d, 0x00564b}, {0x08c84c, 0x00ece4, 0x00e26c}, {0x10594c, 0x00906c, 0x0008c4}, {0x20eac4, 0x00f8c4, 0x00b64c}, {0x401c5d, 0x00defd, 0x0075ab}, {0x800080, 0x000208, 0x000a28}, {0x00d8d5, 0x012d55, 0x00a623}, {0x00c8c4, 0x0266c4, 0x00604c}, {0x00925c, 0x0421dc, 0x008494}, {0x00177d, 0x082695, 0x003ae3}, {0x00a61d, 0x107db5, 0x00f843}, {0x00d6d5, 0x2042dd, 0x00298b}, {0x00e75d, 0x4019fd, 0x00ecab}, {0x003ed5, 0x80c755, 0x002c23}, {0x00d0dd, 0x0040f5, 0x01cb83}, {0x00484c, 0x00616c, 0x026fc4}, {0x007ca5, 0x00b5c5, 0x049ad3}, {0x005db1, 0x00fbf1, 0x08a90f}, {0x000695, 0x005795, 0x10da63}, {0x00204c, 0x0064e4, 0x20ea6c}, {0x00c555, 0x00025d, 0x40bf0b}, {0x003e55, 0x00c55d, 0x80260b}, {0x006066, 0x008816, 0x00879e}, {0x001c1d, 0x00d9e1, 0x0070bf}, {0x00969f, 0x00a191, 0x0049cf}, {0x00595c, 0x009539, 0x000437}, {0x003ebd, 0x00c2dd, 0x0023a3}, {0x0020c2, 0x006cc4, 0x00e07a}, {0x00c509, 0x00091d, 0x00bdf7}, {0x001849, 0x00fa1c, 0x00190f} }, + { {0x008a82, 0x007870, 0x003970}, {0x011505, 0x0013f1, 0x004f4f}, {0x022a0a, 0x00559a, 0x0015ba}, {0x045415, 0x007b9d, 0x00564b}, {0x0822a8, 0x001c82, 0x005c82}, {0x104551, 0x00498d, 0x00787b}, {0x200020, 0x0008a2, 0x0008a2}, {0x400040, 0x00071c, 0x000514}, {0x800080, 0x000208, 0x000a28}, {0x001c1d, 0x00d9e1, 0x0070bf}, {0x002e2c, 0x0104d2, 0x006872}, {0x004246, 0x021eb4, 0x00593c}, {0x0064a5, 0x04085b, 0x004ac5}, {0x00177d, 0x082695, 0x003ae3}, {0x0050e4, 0x105432, 0x003612}, {0x005c57, 0x203aad, 0x0010fb}, {0x0011a4, 0x40307a, 0x0022fa}, {0x0022c8, 0x801eb4, 0x005c9c}, {0x007c7b, 0x0051f7, 0x00f721}, {0x002624, 0x006972, 0x0105d2}, {0x00484c, 0x00616c, 0x026fc4}, {0x001cc3, 0x003dd3, 0x041d4d}, {0x003dd7, 0x0073e7, 0x082e91}, {0x007aee, 0x000662, 0x102d42}, {0x005c37, 0x003513, 0x201d4d}, {0x0033ac, 0x002bda, 0x40715a}, {0x002248, 0x001cbc, 0x8056b4}, {0x004541, 0x004cd8, 0x007488}, {0x0022a0, 0x001b3c, 0x00531c}, {0x005cb9, 0x003d33, 0x00175b}, {0x0033f0, 0x00209a, 0x0073a6}, {0x000454, 0x0023fd, 0x0069b0} }, + { {0x005cb9, 0x003d33, 0x00175b}, {0x00b1da, 0x0012a7, 0x0009bf}, {0x0137a5, 0x0008cd, 0x001c53}, {0x021152, 0x003f4d, 0x002575}, {0x041154, 0x003745, 0x0022c3}, {0x080008, 0x0007be, 0x000f9e}, {0x100010, 0x000555, 0x000cf3}, {0x200020, 0x0008a2, 0x0008a2}, {0x400040, 0x00071c, 0x000514}, {0x800080, 0x000208, 0x000a28}, {0x003b58, 0x006ad7, 0x0030cf}, {0x0005e5, 0x00a80a, 0x00136c}, {0x000c8c, 0x011fee, 0x003b6e}, {0x003c5f, 0x0238bb, 0x001d7b}, {0x001abc, 0x042e54, 0x000e82}, {0x00177d, 0x082695, 0x003ae3}, {0x003705, 0x1003d6, 0x001186}, {0x0000ee, 0x20079e, 0x0007a0}, {0x0011a4, 0x40307a, 0x0022fa}, {0x000068, 0x800588, 0x000f80}, {0x0022a0, 0x001b3c, 0x00531c}, {0x00393a, 0x001d2f, 0x0083a9}, {0x001d7c, 0x0003a5, 0x01351d}, {0x000d0d, 0x002db4, 0x021b4c}, {0x001cc3, 0x003dd3, 0x041d4d}, {0x00068f, 0x001930, 0x081e5e}, {0x002657, 0x003b51, 0x103a19}, {0x00008e, 0x000820, 0x200a16}, {0x00110c, 0x0030e6, 0x402246}, {0x0000e8, 0x000780, 0x8005a8}, {0x001150, 0x003ba6, 0x0020ba}, {0x0026f4, 0x0038c1, 0x003aac} } +}; + +const int32 FSobol::Cell3DGrayNumbers[FSobol::MaxCell3DBits + 1][32][3] = { + { {0x800000, 0x800000, 0x800000}, {0x400000, 0x400000, 0xc00000}, {0x500000, 0x900000, 0xf00000}, {0xf00000, 0x700000, 0x900000}, {0x880000, 0xd80000, 0xd80000}, {0x660000, 0x5a0000, 0x820000}, {0xd20000, 0xd60000, 0xa60000}, {0x990000, 0xe70000, 0x410000}, {0xad8000, 0x4b8000, 0xc78000}, {0xf44000, 0xfdc000, 0x754000}, {0x72a000, 0x7ca000, 0x8ea000}, {0xbbf000, 0xbf3000, 0x51d000}, {0x950c00, 0x52dc00, 0x9f7400}, {0xa07200, 0x360e00, 0xeea600}, {0x886e80, 0xa28d80, 0xa3e580}, {0x68e880, 0x588780, 0xf80f80}, {0x103d00, 0xbb0d00, 0x9a3300}, {0xcc95c0, 0x924240, 0xf372c0}, {0xd2a0a0, 0xaaad60, 0x48ac60}, {0xe60888, 0x5b6fa8, 0x836788}, {0xf4f4b4, 0x31cbdc, 0xe40914}, {0x590ccc, 0xe49764, 0x41b9ec}, {0x90c555, 0x50025d, 0xf0bf0b}, {0xd5552d, 0x7d5b6d, 0x8f8a5b}, {0x6eee66, 0x83679e, 0xf88836}, {0x2eeed2, 0x3ea79e, 0xa9c676}, {0xa000d2, 0x9ca000, 0x28ac60}, {0xf0004b, 0xcf3000, 0xb6d770}, {0x7800ad, 0x36d800, 0xedb0f8}, {0x660086, 0xa00a00, 0xa00d9e}, {0xd20072, 0xe00e00, 0x60048a}, {0x9900c9, 0x900900, 0xf006e7} }, + { {0x400000, 0x400000, 0xc00000}, {0x200000, 0x600000, 0xe00000}, {0x080000, 0x580000, 0x580000}, {0x260000, 0x1a0000, 0x420000}, {0x520000, 0x560000, 0x260000}, {0x590000, 0x270000, 0x010000}, {0x3d8000, 0x1b8000, 0x778000}, {0x344000, 0x3dc000, 0x354000}, {0x32a000, 0x3ca000, 0x4ea000}, {0x7bf000, 0x7f3000, 0x11d000}, {0x050c00, 0x02dc00, 0x2f7400}, {0x307200, 0x660e00, 0x5ea600}, {0x086e80, 0x228d80, 0x23e580}, {0x28e880, 0x188780, 0x380f80}, {0x403d00, 0x2b0d00, 0x6a3300}, {0x4c95c0, 0x124240, 0x7372c0}, {0x12a0a0, 0x6aad60, 0x08ac60}, {0x760888, 0x0b6fa8, 0x336788}, {0x64f4b4, 0x61cbdc, 0x540914}, {0x490ccc, 0x349764, 0x71b9ec}, {0x00c555, 0x00025d, 0x40bf0b}, {0x45552d, 0x2d5b6d, 0x3f8a5b}, {0x3eee66, 0x13679e, 0x088836}, {0x6eeed2, 0x7ea79e, 0x69c676}, {0x6000d2, 0x5ca000, 0x68ac60}, {0x70004b, 0x4f3000, 0x36d770}, {0x3800ad, 0x76d800, 0x2db0f8}, {0x360086, 0x300a00, 0x500d9e}, {0x120072, 0x200e00, 0x20048a}, {0x1900c9, 0x100900, 0x7006e7}, {0x59c095, 0x240240, 0x6c041b}, {0x344040, 0x4c08c0, 0x640e40} }, + { {0x260000, 0x1a0000, 0x420000}, {0x0e0000, 0x220000, 0xfa0000}, {0x340000, 0x0c0000, 0xa40000}, {0x390000, 0x070000, 0x210000}, {0x1b8000, 0x018000, 0x358000}, {0x344000, 0x3dc000, 0x354000}, {0x14a000, 0x26a000, 0x0ca000}, {0x35f000, 0x1d3000, 0x2bd000}, {0x050c00, 0x02dc00, 0x2f7400}, {0x387200, 0x3e0e00, 0x06a600}, {0x086e80, 0x228d80, 0x23e580}, {0x28e880, 0x188780, 0x380f80}, {0x063d00, 0x110d00, 0x083300}, {0x0a95c0, 0x284240, 0x1172c0}, {0x3ca0a0, 0x28ad60, 0x12ac60}, {0x160888, 0x2b6fa8, 0x136788}, {0x0cf4b4, 0x19cbdc, 0x2c0914}, {0x0f0ccc, 0x0e9764, 0x13b9ec}, {0x26c555, 0x1a025d, 0x02bf0b}, {0x25552d, 0x0d5b6d, 0x1f8a5b}, {0x3eee66, 0x13679e, 0x088836}, {0x06eed2, 0x06a79e, 0x11c676}, {0x0800d2, 0x24a000, 0x10ac60}, {0x3e004b, 0x2d3000, 0x0cd770}, {0x1600ad, 0x34d800, 0x37b0f8}, {0x100086, 0x2a0a00, 0x120d9e}, {0x120072, 0x200e00, 0x20048a}, {0x3f00c9, 0x0a0900, 0x3206e7}, {0x1fc095, 0x1e0240, 0x0e041b}, {0x3c4040, 0x1408c0, 0x3c0e40}, {0x16e0e0, 0x0a05a0, 0x320220}, {0x23f0f0, 0x390310, 0x0f0770} }, + { {0x1b8000, 0x018000, 0x358000}, {0x1f0000, 0x1d0000, 0x630000}, {0x098000, 0x178000, 0xd38000}, {0x1c4000, 0x05c000, 0x8d4000}, {0x08a000, 0x12a000, 0x10a000}, {0x0cf000, 0x1a3000, 0x0ad000}, {0x1e8c00, 0x035c00, 0x1af400}, {0x06f200, 0x0c8e00, 0x0e2600}, {0x0fee80, 0x170d80, 0x0a6580}, {0x11e880, 0x1f8780, 0x190f80}, {0x063d00, 0x110d00, 0x083300}, {0x1695c0, 0x1c4240, 0x0d72c0}, {0x0220a0, 0x1a2d60, 0x1a2c60}, {0x0a0888, 0x1f6fa8, 0x0f6788}, {0x1774b4, 0x184bdc, 0x198914}, {0x0f0ccc, 0x0e9764, 0x13b9ec}, {0x044555, 0x1c825d, 0x163f0b}, {0x07d52d, 0x0bdb6d, 0x0b0a5b}, {0x1c6e66, 0x15e79e, 0x1c0836}, {0x06eed2, 0x06a79e, 0x11c676}, {0x1400d2, 0x10a000, 0x0cac60}, {0x00804b, 0x1fb000, 0x045770}, {0x1180ad, 0x015800, 0x1e30f8}, {0x0c0086, 0x1e0a00, 0x0e0d9e}, {0x158072, 0x158e00, 0x09848a}, {0x0600c9, 0x0d0900, 0x1306e7}, {0x1fc095, 0x1e0240, 0x0e041b}, {0x054040, 0x1308c0, 0x1d0e40}, {0x0d60e0, 0x0b85a0, 0x078220}, {0x1d70f0, 0x0b8310, 0x078770}, {0x1ff878, 0x1584b8, 0x0988f8}, {0x0d74b4, 0x164fdc, 0x12c514} }, + { {0x045000, 0x089000, 0x1a7000}, {0x0ac000, 0x0f4000, 0x3dc000}, {0x02b000, 0x09f000, 0x619000}, {0x012000, 0x052000, 0xc32000}, {0x069c00, 0x0e0c00, 0x8dc400}, {0x06f200, 0x0c8e00, 0x0e2600}, {0x031e80, 0x0d3d80, 0x00b580}, {0x080880, 0x03e780, 0x01ef80}, {0x0acd00, 0x0b3d00, 0x02e300}, {0x0b25c0, 0x08b240, 0x0fe2c0}, {0x0a80a0, 0x088d60, 0x0a8c60}, {0x06f888, 0x055fa8, 0x05b788}, {0x0e94b4, 0x042bdc, 0x016914}, {0x0b5ccc, 0x060764, 0x09c9ec}, {0x0ce555, 0x0e225d, 0x069f0b}, {0x07d52d, 0x0bdb6d, 0x0b0a5b}, {0x058e66, 0x09879e, 0x04e836}, {0x02bed2, 0x0e379e, 0x0bb676}, {0x09b0d2, 0x045000, 0x0e3c60}, {0x0c704b, 0x058000, 0x0e8770}, {0x0490ad, 0x070800, 0x0c00f8}, {0x00f086, 0x043a00, 0x04dd9e}, {0x083072, 0x017e00, 0x0b148a}, {0x0250c9, 0x059900, 0x0976e7}, {0x027095, 0x0af240, 0x0c941b}, {0x0de040, 0x01a8c0, 0x0dae40}, {0x0d60e0, 0x0b85a0, 0x078220}, {0x0c30f0, 0x054310, 0x0fc770}, {0x024878, 0x0174b8, 0x0b18f8}, {0x05d4b4, 0x04efdc, 0x026514}, {0x08c2d2, 0x0b57ca, 0x01328a}, {0x06eb4b, 0x01abf3, 0x0dab6d} }, + { {0x05ec80, 0x01b380, 0x0e9380}, {0x074e80, 0x05ad80, 0x1ac580}, {0x024280, 0x077180, 0x35b180}, {0x01ae80, 0x04cd80, 0x612580}, {0x012000, 0x052000, 0xc32000}, {0x061600, 0x05da00, 0x845a00}, {0x07a300, 0x02bf00, 0x040100}, {0x03a740, 0x0083c0, 0x079340}, {0x020220, 0x00bce0, 0x02fde0}, {0x06f888, 0x055fa8, 0x05b788}, {0x00e434, 0x00945c, 0x073e94}, {0x00c0cc, 0x030b64, 0x010dec}, {0x018b55, 0x07a05d, 0x007d0b}, {0x01272d, 0x07556d, 0x052c5b}, {0x0690e6, 0x04ba1e, 0x045db6}, {0x044cd2, 0x02b99e, 0x059076}, {0x022cd2, 0x015c00, 0x06f860}, {0x07ec4b, 0x008c00, 0x064370}, {0x017c2d, 0x06bb80, 0x029378}, {0x00f086, 0x043a00, 0x04dd9e}, {0x03ac72, 0x047200, 0x03d08a}, {0x07bc49, 0x042a80, 0x07e567}, {0x048295, 0x067c40, 0x02b21b}, {0x067c40, 0x04a4c0, 0x056a40}, {0x000ee0, 0x0207a0, 0x016020}, {0x07acf0, 0x004f10, 0x070370}, {0x07a4f8, 0x00c738, 0x058b78}, {0x05d4b4, 0x04efdc, 0x026514}, {0x05acd2, 0x02d5ca, 0x07d08a}, {0x0307cb, 0x001873, 0x0338ed}, {0x03f7ad, 0x05406d, 0x05e75b}, {0x036ead, 0x06db30, 0x04e580} }, + { {0x03a740, 0x0083c0, 0x079340}, {0x01e8c0, 0x038f40, 0x0d01c0}, {0x0291c0, 0x027640, 0x1aeec0}, {0x003ec0, 0x021540, 0x319bc0}, {0x007580, 0x012a80, 0x629c80}, {0x00fb00, 0x00c700, 0xc09900}, {0x026c20, 0x023ee0, 0x811fe0}, {0x008088, 0x0207a8, 0x020f88}, {0x034374, 0x00179c, 0x00add4}, {0x00c0cc, 0x030b64, 0x010dec}, {0x005055, 0x02475d, 0x03c40b}, {0x035b6d, 0x0231ad, 0x01061b}, {0x00e8e6, 0x03e21e, 0x03e5b6}, {0x03efd2, 0x00069e, 0x019176}, {0x018b92, 0x01dfc0, 0x016b20}, {0x004f4b, 0x023300, 0x024270}, {0x00a72d, 0x035c80, 0x012a78}, {0x028cc6, 0x015ec0, 0x00f7de}, {0x027772, 0x019500, 0x00698a}, {0x01c449, 0x037280, 0x005d67}, {0x015dd5, 0x01a780, 0x02995b}, {0x000440, 0x03fcc0, 0x02d240}, {0x000ee0, 0x0207a0, 0x016020}, {0x000ff0, 0x02f010, 0x030270}, {0x0007f8, 0x027838, 0x018a78}, {0x000bf4, 0x03341c, 0x024e54}, {0x020fd2, 0x006aca, 0x03d18a}, {0x0307cb, 0x001873, 0x0338ed}, {0x018bed, 0x0024ad, 0x01cd1b}, {0x0112ed, 0x03bff0, 0x00cfc0}, {0x015d19, 0x037cf0, 0x005480}, {0x02a5d2, 0x019860, 0x006b00} }, + { {0x014154, 0x00ab7c, 0x025034}, {0x00e434, 0x00945c, 0x073e94}, {0x00291c, 0x012394, 0x0d5e7c}, {0x01523c, 0x006674, 0x184c9c}, {0x01ff1c, 0x00b994, 0x31c47c}, {0x0134d4, 0x0181fc, 0x60ccb4}, {0x00fb00, 0x00c700, 0xc09900}, {0x01ef98, 0x012218, 0x80bfd8}, {0x00d0dd, 0x0040f5, 0x01cb83}, {0x01d9c5, 0x008ae5, 0x01f473}, {0x00686e, 0x01e5b6, 0x01ea3e}, {0x00aca6, 0x001102, 0x013ca2}, {0x018b92, 0x01dfc0, 0x016b20}, {0x00cfc3, 0x0034a8, 0x004df8}, {0x0166f1, 0x01f054, 0x0175c4}, {0x01cfb2, 0x01495c, 0x005a0a}, {0x013406, 0x01829c, 0x00c45e}, {0x000595, 0x01de54, 0x0002db}, {0x001c81, 0x010cfc, 0x00c96f}, {0x0084c8, 0x01fb68, 0x00ddc8}, {0x01cf3c, 0x00ab74, 0x013f9c}, {0x008f78, 0x00f7b8, 0x010df8}, {0x01c624, 0x00d4ec, 0x01d5c4}, {0x008b7c, 0x0133b4, 0x0041dc}, {0x000df2, 0x00d62a, 0x012c6a}, {0x0105eb, 0x00a493, 0x01c50d}, {0x018bed, 0x0024ad, 0x01cd1b}, {0x00d331, 0x011324, 0x00907c}, {0x009cc5, 0x01d024, 0x000b3c}, {0x01e6a6, 0x018ffc, 0x00c6d4}, {0x014fd2, 0x00acf4, 0x00d794}, {0x00703c, 0x01f4b4, 0x00d1c8} }, + { {0x00d0dd, 0x0040f5, 0x01cb83}, {0x009891, 0x002199, 0x03a447}, {0x0034e9, 0x00d4a9, 0x06f517}, {0x002114, 0x004e34, 0x0c33dc}, {0x005b24, 0x00ac64, 0x18736c}, {0x0026d9, 0x003371, 0x30300f}, {0x00e519, 0x0066b9, 0x605567}, {0x00fb00, 0x00c700, 0xc09900}, {0x005e33, 0x004d4b, 0x80a195}, {0x007c7b, 0x0051f7, 0x00f721}, {0x008a82, 0x007870, 0x003970}, {0x00cfc3, 0x0034a8, 0x004df8}, {0x0067e1, 0x0057e4, 0x002794}, {0x001e7f, 0x00ae19, 0x00c3d9}, {0x00e5cb, 0x0065d9, 0x005d8d}, {0x00dd40, 0x00f301, 0x00a4f8}, {0x00c454, 0x0021a9, 0x006f4c}, {0x005c1d, 0x00d63d, 0x007beb}, {0x0016f9, 0x002191, 0x00cbef}, {0x005fa5, 0x00b74d, 0x00c67b}, {0x001fe1, 0x005e09, 0x0021b7}, {0x0053a9, 0x001ee1, 0x00e7ff}, {0x00dd2f, 0x0096df, 0x00e7e9}, {0x00dc2e, 0x002e76, 0x00317e}, {0x005228, 0x00ae48, 0x003968}, {0x000be4, 0x003e71, 0x00365f}, {0x004410, 0x00fd71, 0x00ad1f}, {0x00376b, 0x0068b9, 0x005f07}, {0x0046ca, 0x0066e4, 0x00e864}, {0x00a8e9, 0x00d9e1, 0x0077eb}, {0x003896, 0x00f066, 0x00b604}, {0x00e41e, 0x00bcbe, 0x00cf7b} }, + { {0x007c7b, 0x0051f7, 0x00f721}, {0x005a5f, 0x003885, 0x01f2f3}, {0x006e68, 0x00081e, 0x036a16}, {0x00548f, 0x005cbf, 0x067289}, {0x002114, 0x004e34, 0x0c33dc}, {0x004739, 0x007585, 0x1803d3}, {0x0026d9, 0x003371, 0x30300f}, {0x006f9b, 0x001ec9, 0x606c17}, {0x0011e4, 0x003766, 0xc027ee}, {0x006709, 0x005064, 0x80223c}, {0x0067e1, 0x0057e4, 0x002794}, {0x007e19, 0x00260f, 0x004447}, {0x006f49, 0x001da9, 0x0064fd}, {0x0037a4, 0x000367, 0x001a16}, {0x004ed6, 0x0059d9, 0x00563c}, {0x004000, 0x000fdc, 0x000b54}, {0x006a82, 0x007066, 0x003cce}, {0x003fc3, 0x003f5b, 0x0041e5}, {0x001fe1, 0x005e09, 0x0021b7}, {0x002fd2, 0x004f16, 0x0010de}, {0x0037cb, 0x0066b9, 0x005907}, {0x0056ac, 0x005606, 0x00080e}, {0x004e35, 0x0077a9, 0x0049d7}, {0x000be4, 0x003e71, 0x00365f}, {0x002476, 0x007567, 0x002a81}, {0x00376b, 0x0068b9, 0x005f07}, {0x003ab1, 0x003713, 0x001f45}, {0x003e76, 0x007870, 0x003e24}, {0x0058f0, 0x007870, 0x00319a}, {0x000efa, 0x004cd8, 0x007195}, {0x004036, 0x002f94, 0x001c47}, {0x006fd2, 0x0043d6, 0x00129e} }, + { {0x0022a0, 0x001b3c, 0x00531c}, {0x001b9a, 0x000613, 0x00d0b5}, {0x002446, 0x001e8a, 0x01b6b4}, {0x001071, 0x002e11, 0x032e51}, {0x0011ce, 0x001067, 0x060601}, {0x001a4c, 0x0024e3, 0x0c0313}, {0x0020d8, 0x002261, 0x182447}, {0x0026d9, 0x003371, 0x30300f}, {0x001182, 0x0038c6, 0x602850}, {0x0011e4, 0x003766, 0xc027ee}, {0x0011b8, 0x003c26, 0x802512}, {0x0037a4, 0x000367, 0x001a16}, {0x000b97, 0x001501, 0x0022b4}, {0x001cb9, 0x0032ef, 0x001c0f}, {0x000d63, 0x002782, 0x001b5a}, {0x001d63, 0x002467, 0x0012f9}, {0x0024b9, 0x0034de, 0x001178}, {0x00148a, 0x0025c1, 0x002011}, {0x002e33, 0x001752, 0x003ad4}, {0x00314d, 0x0001e2, 0x002f9a}, {0x000b74, 0x003b71, 0x003d5f}, {0x000be4, 0x003e71, 0x00365f}, {0x001f2e, 0x001fb0, 0x001a4e}, {0x002e93, 0x001952, 0x003cd4}, {0x003ab1, 0x003713, 0x001f45}, {0x00052e, 0x0012a7, 0x000eeb}, {0x003f11, 0x002f94, 0x00160e}, {0x001702, 0x003d33, 0x001246}, {0x001c8f, 0x0012a7, 0x000b1c}, {0x000833, 0x001432, 0x00350a}, {0x003fe9, 0x000695, 0x00390b}, {0x002c2e, 0x002a66, 0x003f0e} } +}; + diff --git a/Engine/Source/Runtime/Core/Private/Math/UnitConversion.cpp b/Engine/Source/Runtime/Core/Private/Math/UnitConversion.cpp index cd8529fac0ea..3e5609de9438 100644 --- a/Engine/Source/Runtime/Core/Private/Math/UnitConversion.cpp +++ b/Engine/Source/Runtime/Core/Private/Math/UnitConversion.cpp @@ -74,6 +74,8 @@ FParseCandidate ParseCandidates[] = { { TEXT("Months"), EUnit::Months }, { TEXT("mth"), EUnit::Months }, { TEXT("Years"), EUnit::Years }, { TEXT("yr"), EUnit::Years }, + { TEXT("ppi"), EUnit::PixelsPerInch }, { TEXT("dpi"), EUnit::PixelsPerInch }, + { TEXT("times"), EUnit::Multiplier }, { TEXT("x"), EUnit::Multiplier }, { TEXT("multiplier"), EUnit::Multiplier }, }; @@ -102,6 +104,8 @@ const TCHAR* const DisplayStrings[] = { TEXT("ms"), TEXT("s"), TEXT("min"), TEXT("hr"), TEXT("dy"), TEXT("mth"), TEXT("yr"), + TEXT("ppi"), + TEXT("x"), }; @@ -129,6 +133,8 @@ const EUnitType UnitTypes[] = { EUnitType::Time, EUnitType::Time, EUnitType::Time, EUnitType::Time, EUnitType::Time, EUnitType::Time, EUnitType::Time, + EUnitType::PixelDensity, + EUnitType::Arbitrary, }; diff --git a/Engine/Source/Runtime/Core/Private/Misc/AssertionMacros.cpp b/Engine/Source/Runtime/Core/Private/Misc/AssertionMacros.cpp index 1eb6d51b1df8..2202e7daaa11 100644 --- a/Engine/Source/Runtime/Core/Private/Misc/AssertionMacros.cpp +++ b/Engine/Source/Runtime/Core/Private/Misc/AssertionMacros.cpp @@ -371,3 +371,27 @@ void VARARGS LowLevelFatalErrorHandler(const ANSICHAR* File, int32 Line, const T StaticFailDebug(TEXT("LowLevelFatalError"), File, Line, DescriptionString, false); } + +void FDebug::DumpStackTraceToLog() +{ +#if !NO_LOGGING + // Walk the stack and dump it to the allocated memory. + const SIZE_T StackTraceSize = 65535; + ANSICHAR* StackTrace = (ANSICHAR*)FMemory::SystemMalloc(StackTraceSize); + + { +#if STATS + FString StackWalkPerfMessage = FString::Printf(TEXT("FPlatformStackWalk::StackWalkAndDump")); + SCOPE_LOG_TIME_IN_SECONDS(*StackWalkPerfMessage, nullptr) +#endif + StackTrace[0] = 0; + FPlatformStackWalk::StackWalkAndDumpEx(StackTrace, StackTraceSize, CALLSTACK_IGNOREDEPTH, FGenericPlatformStackWalk::EStackWalkFlags::FlagsUsedWhenHandlingEnsure); + } + + // Dump the error and flush the log. + // ELogVerbosity::Error to make sure it gets printed in log for conveniency. + OutputMultiLineCallstack(__FILE__, __LINE__, LogOutputDevice.GetCategoryName(), TEXT("=== FDebug::DumpStackTrace(): ==="), ANSI_TO_TCHAR(StackTrace), ELogVerbosity::Error); + GLog->Flush(); + FMemory::SystemFree(StackTrace); +#endif +} diff --git a/Engine/Source/Runtime/Core/Private/Misc/AutomationTest.cpp b/Engine/Source/Runtime/Core/Private/Misc/AutomationTest.cpp index 39dee6e307fe..ccee1652fe06 100644 --- a/Engine/Source/Runtime/Core/Private/Misc/AutomationTest.cpp +++ b/Engine/Source/Runtime/Core/Private/Misc/AutomationTest.cpp @@ -11,6 +11,7 @@ #include "Misc/App.h" #include "Modules/ModuleManager.h" #include "Misc/OutputDeviceRedirector.h" +#include "Internationalization/Regex.h" DEFINE_LOG_CATEGORY_STATIC(LogAutomationTest, Warning, All); @@ -606,10 +607,11 @@ bool FAutomationTestFramework::InternalStopTest(FAutomationTestExecutionInfo& Ou // Disassociate the test from the feedback context AutomationTestFeedbackContext.SetCurrentAutomationTest( NULL ); - // Determine if the test was successful based on two criteria: + // Determine if the test was successful based on three criteria: // 1) Did the test itself report success? // 2) Did any errors occur and were logged by the feedback context during execution?++---- - bTestSuccessful = bTestSuccessful && !CurrentTest->HasAnyErrors(); + // 3) Did we meet any errors that were expected with this test + bTestSuccessful = bTestSuccessful && !CurrentTest->HasAnyErrors() && CurrentTest->HasMetExpectedErrors(); // Set the success state of the test based on the above criteria CurrentTest->SetSuccessState( bTestSuccessful ); @@ -617,10 +619,17 @@ bool FAutomationTestFramework::InternalStopTest(FAutomationTestExecutionInfo& Ou // Fill out the provided execution info with the info from the test CurrentTest->GetExecutionInfo( OutExecutionInfo ); - //save off timing for the test + // Save off timing for the test OutExecutionInfo.Duration = TimeForTest; - //release pointers to now-invalid data + // Re-enable log parsing if it was disabled and empty the expected errors list + if (CurrentTest->ExpectedErrors.Num()) + { + GLog->Logf(ELogVerbosity::Display, TEXT("<-- Resume Log Parsing -->")); + } + CurrentTest->ExpectedErrors.Empty(); + + // Release pointers to now-invalid data CurrentTest = NULL; return bTestSuccessful; @@ -653,6 +662,16 @@ void FAutomationTestFramework::NotifyScreenshotComparisonComplete(bool bWasNew, OnScreenshotCompared.Broadcast(bWasNew, bWasSimilar, MaxLocalDifference, GlobalDifference, ErrorMessage); } +void FAutomationTestFramework::NotifyTestDataRetrieved(bool bWasNew, const FString& JsonData) +{ + OnTestDataRetrieved.Broadcast(bWasNew, JsonData); +} + +void FAutomationTestFramework::NotifyPerformanceDataRetrieved(bool bSuccess, const FString& ErrorMessage) +{ + OnPerformanceDataRetrieved.Broadcast(bSuccess, ErrorMessage); +} + void FAutomationTestFramework::NotifyScreenshotTakenAndCompared() { OnScreenshotTakenAndCompared.Broadcast(); @@ -782,7 +801,7 @@ void FAutomationTestBase::ClearExecutionInfo() void FAutomationTestBase::AddError(const FString& InError, int32 StackOffset) { - if( !bSuppressLogs ) + if( !bSuppressLogs && !IsExpectedError(InError)) { if ( FAutomationTestFramework::Get().GetCaptureStack() ) { @@ -798,7 +817,7 @@ void FAutomationTestBase::AddError(const FString& InError, int32 StackOffset) void FAutomationTestBase::AddError(const FString& InError, const FString& InFilename, int32 InLineNumber) { - if ( !bSuppressLogs ) + if ( !bSuppressLogs && !IsExpectedError(InError)) { ExecutionInfo.AddEvent(FAutomationEvent(EAutomationEventType::Error, InError, ExecutionInfo.GetContext(), InFilename, InLineNumber)); } @@ -806,7 +825,7 @@ void FAutomationTestBase::AddError(const FString& InError, const FString& InFile void FAutomationTestBase::AddWarning(const FString& InWarning, const FString& InFilename, int32 InLineNumber) { - if ( !bSuppressLogs ) + if ( !bSuppressLogs && !IsExpectedError(InWarning)) { ExecutionInfo.AddEvent(FAutomationEvent(EAutomationEventType::Warning, InWarning, ExecutionInfo.GetContext(), InFilename, InLineNumber)); } @@ -814,7 +833,7 @@ void FAutomationTestBase::AddWarning(const FString& InWarning, const FString& In void FAutomationTestBase::AddWarning( const FString& InWarning, int32 StackOffset ) { - if ( !bSuppressLogs ) + if ( !bSuppressLogs && !IsExpectedError(InWarning)) { if ( FAutomationTestFramework::Get().GetCaptureStack() ) { @@ -854,6 +873,50 @@ bool FAutomationTestBase::HasAnyErrors() const return ExecutionInfo.GetErrorTotal() > 0; } +bool FAutomationTestBase::HasMetExpectedErrors() +{ + bool HasMetAllExpectedErrors = true; + + for (auto& EError : ExpectedErrors) + { + if ((EError.ExpectedNumberOfOccurrences > 0) && (EError.ExpectedNumberOfOccurrences != EError.ActualNumberOfOccurrences)) + { + HasMetAllExpectedErrors = false; + + ExecutionInfo.AddEvent(FAutomationEvent(EAutomationEventType::Error, + FString::Printf(TEXT("Expected Error or Warning matching '%s' to occur %d times with %s match type, but it was found %d time(s).") + , *EError.ErrorPatternString + , EError.ExpectedNumberOfOccurrences + , EAutomationExpectedErrorFlags::ToString(EError.CompareType) + , EError.ActualNumberOfOccurrences) + , ExecutionInfo.GetContext())); + } + else if (EError.ExpectedNumberOfOccurrences == 0) + { + if (EError.ActualNumberOfOccurrences == 0) + { + HasMetAllExpectedErrors = false; + + ExecutionInfo.AddEvent(FAutomationEvent(EAutomationEventType::Error, + FString::Printf(TEXT("Expected suppressed Error or Warning matching '%s' did not occur."), *EError.ErrorPatternString), + ExecutionInfo.GetContext())); + } + else + { + ExecutionInfo.AddEvent(FAutomationEvent(EAutomationEventType::Info, + FString::Printf(TEXT("Suppressed expected Error or Warning matching '%s' %d times.") + , *EError.ErrorPatternString + , EError.ActualNumberOfOccurrences) + , ExecutionInfo.GetContext())); + } + } + } + + return HasMetAllExpectedErrors; +} + + + void FAutomationTestBase::SetSuccessState( bool bSuccessful ) { ExecutionInfo.bSuccessful = bSuccessful; @@ -864,6 +927,45 @@ void FAutomationTestBase::GetExecutionInfo( FAutomationTestExecutionInfo& OutInf OutInfo = ExecutionInfo; } +void FAutomationTestBase::AddExpectedError(FString ExpectedErrorPattern, EAutomationExpectedErrorFlags::MatchType InCompareType, int32 Occurrences) +{ + if (Occurrences >= 0) + { + // If we already have an error matching string in our list, let's not add it again. + FAutomationExpectedError* FoundEntry = ExpectedErrors.FindByPredicate( + [ExpectedErrorPattern](const FAutomationExpectedError& InItem) + { + return InItem.ErrorPatternString == ExpectedErrorPattern; + } + ); + + if (FoundEntry) + { + UE_LOG(LogAutomationTest, Warning, TEXT("Adding expected error matching '%s' failed: cannot add duplicate entries"), *ExpectedErrorPattern) + } + else + { + // Disable log pre-processor the first time we successfully add an expected error + // so that successful tests don't trigger CIS failures + if (!ExpectedErrors.Num()) + { + GLog->Logf(ELogVerbosity::Display, TEXT("<-- Suspend Log Parsing -->")); + } + // ToDo: After UE-44340 is resolved, create FAutomationExpectedError and check that its ErrorPattern is valid before adding + ExpectedErrors.Add(FAutomationExpectedError(ExpectedErrorPattern, InCompareType, Occurrences)); + } + } + else + { + UE_LOG(LogAutomationTest, Error, TEXT("Adding expected error matching '%s' failed: number of expected occurrences must be >= 0"), *ExpectedErrorPattern); + } +} + +void FAutomationTestBase::GetExpectedErrors(TArray& OutInfo) const +{ + OutInfo = ExpectedErrors; +} + void FAutomationTestBase::GenerateTestNames(TArray& TestInfo) const { TArray BeautifiedNames; @@ -986,3 +1088,19 @@ void FAutomationTestBase::TestNull(const FString& What, void* Pointer) AddInfo(FString::Printf(TEXT("Expected '%s' to be null."), *What), 1); } } + +bool FAutomationTestBase::IsExpectedError(const FString& Error) +{ + for (auto& EError : ExpectedErrors) + { + FRegexMatcher ErrorMatcher(EError.ErrorPattern, Error); + + if (ErrorMatcher.FindNext()) + { + EError.ActualNumberOfOccurrences++; + return true; + } + } + + return false; +} \ No newline at end of file diff --git a/Engine/Source/Runtime/Core/Private/Misc/ConfigCacheIni.cpp b/Engine/Source/Runtime/Core/Private/Misc/ConfigCacheIni.cpp index 1b323cd8fb14..9819e0b332ce 100644 --- a/Engine/Source/Runtime/Core/Private/Misc/ConfigCacheIni.cpp +++ b/Engine/Source/Runtime/Core/Private/Misc/ConfigCacheIni.cpp @@ -1147,20 +1147,24 @@ bool FConfigFile::Write( const FString& Filename, bool bDoRemoteWrite/* = true*/ { // Check for an array of differing size. This will trigger a full writeout. // This also catches the case where the property doesn't exist in the source in non-array cases - bool bDifferentNumberOfElements = false; + const bool bDifferentNumberOfElements = false; + /* // This code is a no-op { - const FConfigSection* SourceSection = nullptr; - if( SourceSection ) + if (SourceConfigFile) { - TArray SourceMatchingProperties; - SourceSection->MultiFind( PropertyName, SourceMatchingProperties ); + if (const FConfigSection* SourceSection = SourceConfigFile->Find(SectionName)) + { + TArray SourceMatchingProperties; + SourceSection->MultiFind(PropertyName, SourceMatchingProperties); - TArray DestMatchingProperties; - Section.MultiFind( PropertyName, DestMatchingProperties ); + TArray DestMatchingProperties; + Section.MultiFind(PropertyName, DestMatchingProperties); - bDifferentNumberOfElements = SourceMatchingProperties.Num() != DestMatchingProperties.Num(); + bDifferentNumberOfElements = SourceMatchingProperties.Num() != DestMatchingProperties.Num(); + } } } + */ // check whether the option we are attempting to write out, came from the commandline as a temporary override. const bool bOptionIsFromCommandline = PropertySetFromCommandlineOption(this, SectionName, PropertyName, PropertyValue); @@ -3570,38 +3574,14 @@ bool FConfigFile::UpdateSinglePropertyInSection(const TCHAR* DiskFilename, const // Result of whether the file has been updated on disk. bool bSuccessfullyUpdatedFile = false; - + FString PropertyValue; if (const FConfigSection* LocalSection = this->Find(SectionName)) { - TArray ConfigValues; - LocalSection->MultiFind(PropertyName, ConfigValues); - - if (ConfigValues.Num()) + if (const FConfigValue* ConfigValue = LocalSection->Find(PropertyName)) { - FString PropertyValue; - if (ConfigValues.Num() > 1) - { - for (const FConfigValue& ConfigValue : ConfigValues) - { - if (!PropertyValue.IsEmpty()) - { - PropertyValue += "\n"; - PropertyValue += PropertyName; - PropertyValue += "="; - } - - PropertyValue += ConfigValue.GetSavedValue(); - } - - PropertyValue += ")"; - } - else - { - PropertyValue = ConfigValues.Top().GetSavedValue(); - } - + PropertyValue = ConfigValue->GetSavedValue(); FSinglePropertyConfigHelper SinglePropertyConfigHelper(DiskFilename, SectionName, PropertyName, PropertyValue); - bSuccessfullyUpdatedFile |= SinglePropertyConfigHelper.UpdateConfigFile(); + bSuccessfullyUpdatedFile = SinglePropertyConfigHelper.UpdateConfigFile(); } } diff --git a/Engine/Source/Runtime/Core/Private/Misc/CoreDelegates.cpp b/Engine/Source/Runtime/Core/Private/Misc/CoreDelegates.cpp index 5aca6f9e5d5f..9fd2ef77f4c0 100644 --- a/Engine/Source/Runtime/Core/Private/Misc/CoreDelegates.cpp +++ b/Engine/Source/Runtime/Core/Private/Misc/CoreDelegates.cpp @@ -53,9 +53,13 @@ FCoreDelegates::FPakSigningKeysDelegate& FCoreDelegates::GetPakSigningKeysDelega #endif //WITH_EDITOR FSimpleMulticastDelegate FCoreDelegates::OnShutdownAfterError; FSimpleMulticastDelegate FCoreDelegates::OnInit; +FSimpleMulticastDelegate FCoreDelegates::OnPostEngineInit; +FSimpleMulticastDelegate FCoreDelegates::OnFEngineLoopInitComplete; FSimpleMulticastDelegate FCoreDelegates::OnExit; FSimpleMulticastDelegate FCoreDelegates::OnPreExit; FSimpleMulticastDelegate FCoreDelegates::ColorPickerChanged; +FSimpleMulticastDelegate FCoreDelegates::OnBeginFrame; +FSimpleMulticastDelegate FCoreDelegates::OnEndFrame; FCoreDelegates::FOnModalMessageBox FCoreDelegates::ModalErrorMessage; FCoreDelegates::FOnInviteAccepted FCoreDelegates::OnInviteAccepted; FCoreDelegates::FWorldOriginOffset FCoreDelegates::PreWorldOriginOffset; @@ -109,14 +113,26 @@ FCoreDelegates::FOnAsyncLoadingFlush FCoreDelegates::OnAsyncLoadingFlush; FCoreDelegates::FOnAsyncLoadPackage FCoreDelegates::OnAsyncLoadPackage; FCoreDelegates::FRenderingThreadChanged FCoreDelegates::PostRenderingThreadCreated; FCoreDelegates::FRenderingThreadChanged FCoreDelegates::PreRenderingThreadDestroyed; -FSimpleMulticastDelegate FCoreDelegates::OnFEngineLoopInitComplete; FCoreDelegates::FImageIntegrityChanged FCoreDelegates::OnImageIntegrityChanged; FCoreDelegates::FApplicationReceivedOnScreenOrientationChangedNotificationDelegate FCoreDelegates::ApplicationReceivedScreenOrientationChangedNotificationDelegate; FCoreDelegates::FConfigReadyForUse FCoreDelegates::ConfigReadyForUse; -FSimpleMulticastDelegate FCoreDelegates::OnOutOfMemory; +/** Implemented as a function to address global ctor issues */ +FSimpleMulticastDelegate& FCoreDelegates::GetMemoryTrimDelegate() +{ + static FSimpleMulticastDelegate OnMemoryTrim;; + return OnMemoryTrim; +} + +/** Implemented as a function to address global ctor issues */ +FSimpleMulticastDelegate& FCoreDelegates::GetOutOfMemoryDelegate() +{ + static FSimpleMulticastDelegate OnOOM; + return OnOOM; +} + FCoreDelegates::FGetOnScreenMessagesDelegate FCoreDelegates::OnGetOnScreenMessages; void RegisterEncryptionKey(const char* InEncryptionKey) diff --git a/Engine/Source/Runtime/Core/Private/Misc/CoreGlobals.cpp b/Engine/Source/Runtime/Core/Private/Misc/CoreGlobals.cpp index 4dfbad490b35..31cbd32828ae 100644 --- a/Engine/Source/Runtime/Core/Private/Misc/CoreGlobals.cpp +++ b/Engine/Source/Runtime/Core/Private/Misc/CoreGlobals.cpp @@ -96,9 +96,6 @@ bool GCompilingBlueprint = false; /** True if we're reconstructing blueprint instances. Should never be true on cooked builds */ bool GIsReconstructingBlueprintInstances = false; -/** Force blueprints to not compile on load */ -bool GForceDisableBlueprintCompileOnLoad = false; - /** True if actors and objects are being re-instanced. */ bool GIsReinstancing = false; @@ -280,16 +277,6 @@ bool GPumpingMessagesOutsideOfMainLoop = false; /** Enables various editor and HMD hacks that allow the experimental VR editor feature to work, perhaps at the expense of other systems */ bool GEnableVREditorHacks = false; -// Constrain bandwidth if wanted. Value is in MByte/ sec. -float GAsyncIOBandwidthLimit = 0.0f; -static FAutoConsoleVariableRef CVarAsyncIOBandwidthLimit( - TEXT("s.AsyncIOBandwidthLimit"), - GAsyncIOBandwidthLimit, - TEXT("Constrain bandwidth if wanted. Value is in MByte/ sec."), - ECVF_Default - ); - - DEFINE_STAT(STAT_AudioMemory); DEFINE_STAT(STAT_TextureMemory); DEFINE_STAT(STAT_MemoryPhysXTotalAllocationSize); diff --git a/Engine/Source/Runtime/Core/Private/Misc/EngineVersion.cpp b/Engine/Source/Runtime/Core/Private/Misc/EngineVersion.cpp index 3b76f87b1190..8dae368b3c78 100644 --- a/Engine/Source/Runtime/Core/Private/Misc/EngineVersion.cpp +++ b/Engine/Source/Runtime/Core/Private/Misc/EngineVersion.cpp @@ -206,6 +206,11 @@ const FEngineVersion& FEngineVersion::CompatibleWith() return CompatibleWithVersion; } +const FString& FEngineVersion::GetBranchDescriptor() const +{ + return Branch; +} + bool FEngineVersion::OverrideCurrentVersionChangelist(int32 NewChangelist, int32 NewCompatibleChangelist) { if(CurrentVersion.GetChangelist() != 0 || CompatibleWithVersion.GetChangelist() != 0) diff --git a/Engine/Source/Runtime/Core/Private/Misc/ObjectThumbnail.cpp b/Engine/Source/Runtime/Core/Private/Misc/ObjectThumbnail.cpp index 4bef9876ea16..07fa3ebe745e 100644 --- a/Engine/Source/Runtime/Core/Private/Misc/ObjectThumbnail.cpp +++ b/Engine/Source/Runtime/Core/Private/Misc/ObjectThumbnail.cpp @@ -85,7 +85,7 @@ void FObjectThumbnail::DecompressImageData() void FObjectThumbnail::CountBytes( FArchive& Ar ) const { SIZE_T StaticSize = sizeof(FObjectThumbnail); - Ar.CountBytes(StaticSize, Align(StaticSize, ALIGNOF(FObjectThumbnail))); + Ar.CountBytes(StaticSize, Align(StaticSize, alignof(FObjectThumbnail))); FObjectThumbnail* UnconstThis = const_cast(this); UnconstThis->CompressedImageData.CountBytes(Ar); @@ -108,7 +108,7 @@ void FObjectThumbnail::CountImageBytes_Uncompressed( FArchive& Ar ) const void FObjectFullNameAndThumbnail::CountBytes( FArchive& Ar ) const { SIZE_T StaticSize = sizeof(FObjectFullNameAndThumbnail); - Ar.CountBytes(StaticSize, Align(StaticSize, ALIGNOF(FObjectFullNameAndThumbnail))); + Ar.CountBytes(StaticSize, Align(StaticSize, alignof(FObjectFullNameAndThumbnail))); if ( ObjectThumbnail != NULL ) { diff --git a/Engine/Source/Runtime/Core/Private/Misc/OutputDeviceHelper.cpp b/Engine/Source/Runtime/Core/Private/Misc/OutputDeviceHelper.cpp index ac12b1a6541b..28b777753e5e 100644 --- a/Engine/Source/Runtime/Core/Private/Misc/OutputDeviceHelper.cpp +++ b/Engine/Source/Runtime/Core/Private/Misc/OutputDeviceHelper.cpp @@ -40,12 +40,12 @@ FString FOutputDeviceHelper::FormatLogLine( ELogVerbosity::Type Verbosity, const case ELogTimes::SinceGStartTime: { const double RealTime = Time == -1.0f ? FPlatformTime::Seconds() - GStartTime : Time; - Format = FString::Printf( TEXT( "[%07.2f][%3d]" ), RealTime, GFrameCounter % 1000 ); + Format = FString::Printf( TEXT( "[%07.2f][%3llu]" ), RealTime, GFrameCounter % 1000); break; } case ELogTimes::UTC: - Format = FString::Printf(TEXT("[%s][%3d]"), *FDateTime::UtcNow().ToString(TEXT("%Y.%m.%d-%H.%M.%S:%s")), GFrameCounter % 1000); + Format = FString::Printf(TEXT("[%s][%3llu]"), *FDateTime::UtcNow().ToString(TEXT("%Y.%m.%d-%H.%M.%S:%s")), GFrameCounter % 1000); break; default: @@ -54,18 +54,14 @@ FString FOutputDeviceHelper::FormatLogLine( ELogVerbosity::Type Verbosity, const if (bShowCategory) { + Format += Category.ToString(); + Format += TEXT(": "); + if (Verbosity != ELogVerbosity::Log) { - Format += Category.ToString(); - Format += TEXT(":"); Format += VerbosityToString(Verbosity); Format += TEXT(": "); } - else - { - Format += Category.ToString(); - Format += TEXT(": "); - } } else { diff --git a/Engine/Source/Runtime/Core/Private/Misc/Parse.cpp b/Engine/Source/Runtime/Core/Private/Misc/Parse.cpp index 136b1b818649..d4fd87d65481 100644 --- a/Engine/Source/Runtime/Core/Private/Misc/Parse.cpp +++ b/Engine/Source/Runtime/Core/Private/Misc/Parse.cpp @@ -195,8 +195,8 @@ void ConsoleCommandLibrary_DumpLibraryHTML(UWorld* InWorld, FExec& SubSystem, co LazyPrintf.PushParam(*AllData); - auto AnsiHelp = StringCast(*LazyPrintf.GetResultString()); - File->Serialize((ANSICHAR*)AnsiHelp.Get(), AnsiHelp.Length()); + FTCHARToUTF8 UTF8Help(*LazyPrintf.GetResultString()); + File->Serialize((ANSICHAR*)UTF8Help.Get(), UTF8Help.Length()); delete File; File = 0; @@ -296,7 +296,8 @@ bool FParse::Param( const TCHAR* Stream, const TCHAR* Param ) { while( (Start=FCString::Strifind(Start+1,Param)) != NULL ) { - if( Start>Stream && (Start[-1]=='-' || Start[-1]=='/') ) + if( Start>Stream && (Start[-1]=='-' || Start[-1]=='/') && + (Stream > (Start - 2) || FChar::IsWhitespace(Start[-2]))) // Reject if the character before '-' or '/' is not a whitespace { const TCHAR* End = Start + FCString::Strlen(Param); if ( End == NULL || *End == 0 || FChar::IsWhitespace(*End) ) diff --git a/Engine/Source/Runtime/Core/Private/Misc/Paths.cpp b/Engine/Source/Runtime/Core/Private/Misc/Paths.cpp index 4780d5086d06..c1caf1d7588c 100644 --- a/Engine/Source/Runtime/Core/Private/Misc/Paths.cpp +++ b/Engine/Source/Runtime/Core/Private/Misc/Paths.cpp @@ -17,6 +17,7 @@ DEFINE_LOG_CATEGORY_STATIC(LogPaths, Log, All); +FString FPaths::GameProjectFilePath; /*----------------------------------------------------------------------------- Path helpers for retrieving game dir, engine dir, etc. @@ -86,7 +87,7 @@ namespace UE4Paths_Private bool FPaths::ShouldSaveToUserDir() { - static bool bShouldSaveToUserDir = FApp::IsInstalled() || FParse::Param(FCommandLine::Get(), TEXT("SaveToUserDir")); + static bool bShouldSaveToUserDir = FApp::IsInstalled() || FParse::Param(FCommandLine::Get(), TEXT("SaveToUserDir")) || FPlatformProcess::ShouldSaveToUserDir(); return bShouldSaveToUserDir; } @@ -149,6 +150,16 @@ FString FPaths::EnginePluginsDir() return FPaths::EngineDir() + TEXT("Plugins/"); } +FString FPaths::EnterpriseDir() +{ + return FPaths::RootDir() + TEXT("Enterprise/"); +} + +FString FPaths::EnterprisePluginsDir() +{ + return EnterpriseDir() + TEXT("Plugins/"); +} + FString FPaths::RootDir() { return FString(FPlatformMisc::RootDir()); @@ -563,6 +574,16 @@ FString FPaths::ChangeExtension(const FString& InPath, const FString& InNewExten { int32 Pos = INDEX_NONE; if (InPath.FindLastChar('.', Pos)) + { + const int32 PathEndPos = InPath.FindLastCharByPredicate(UE4Paths_Private::IsSlashOrBackslash); + if (PathEndPos != INDEX_NONE && PathEndPos > Pos) + { + // The dot found was part of the path rather than the name + Pos = INDEX_NONE; + } + } + + if (Pos != INDEX_NONE) { FString Result = InPath.Left(Pos); @@ -582,7 +603,15 @@ FString FPaths::ChangeExtension(const FString& InPath, const FString& InNewExten FString FPaths::SetExtension(const FString& InPath, const FString& InNewExtension) { int32 Pos = INDEX_NONE; - InPath.FindLastChar('.', Pos); + if (InPath.FindLastChar('.', Pos)) + { + const int32 PathEndPos = InPath.FindLastCharByPredicate(UE4Paths_Private::IsSlashOrBackslash); + if (PathEndPos != INDEX_NONE && PathEndPos > Pos) + { + // The dot found was part of the path rather than the name + Pos = INDEX_NONE; + } + } FString Result = Pos == INDEX_NONE ? InPath : InPath.Left(Pos); @@ -805,6 +834,9 @@ void FPaths::MakeStandardFilename(FString& InPath) { #if !PLATFORM_HTML5 InPath = FPlatformProcess::BaseDir(); + // if the base directory is nothing then this function will recurse infinitely instead of returning nothing. + if (InPath.Len() == 0) + return; FPaths::MakeStandardFilename(InPath); #else // @todo: revisit this as needed @@ -1120,7 +1152,7 @@ bool FPaths::IsSamePath(const FString& PathA, const FString& PathB) MakeStandardFilename(TmpA); MakeStandardFilename(TmpB); -#if defined(PLATFORM_WINDOWS) || defined(PLATFORM_XBOXONE) +#if PLATFORM_WINDOWS || PLATFORM_XBOXONE return FCString::Stricmp(*TmpA, *TmpB) == 0; #else return FCString::Strcmp(*TmpA, *TmpB) == 0; diff --git a/Engine/Source/Runtime/Core/Private/Misc/SecureHash.cpp b/Engine/Source/Runtime/Core/Private/Misc/SecureHash.cpp index 9e4952ed371f..54e11588699f 100644 --- a/Engine/Source/Runtime/Core/Private/Misc/SecureHash.cpp +++ b/Engine/Source/Runtime/Core/Private/Misc/SecureHash.cpp @@ -266,6 +266,7 @@ void FMD5::Decode( uint32* output, const uint8* input, int32 len ) } } +/// @cond DOXYGEN_WARNINGS // // MD5 initialization. Begins an MD5 operation, writing a new context. // @@ -457,6 +458,7 @@ void FMD5::Decode( uint32* output, const uint8* input, int32 len ) // output[i] = ((uint32)input[j]) | (((uint32)input[j+1]) << 8) | // (((uint32)input[j+2]) << 16) | (((uint32)input[j+3]) << 24); // } +/// @endcond namespace Lex { diff --git a/Engine/Source/Runtime/Core/Private/Misc/TimeGuard.cpp b/Engine/Source/Runtime/Core/Private/Misc/TimeGuard.cpp index 7a720c9ae703..7e1fead3584a 100644 --- a/Engine/Source/Runtime/Core/Private/Misc/TimeGuard.cpp +++ b/Engine/Source/Runtime/Core/Private/Misc/TimeGuard.cpp @@ -9,7 +9,6 @@ DEFINE_LOG_CATEGORY_STATIC(LogTimeGuard, Log, All); TMap FLightweightTimeGuard::HitchData; bool FLightweightTimeGuard::bEnabled; -double FLightweightTimeGuard::LastHitchTime; float FLightweightTimeGuard::FrameTimeThresholdMS = 1000.0 / 30.0; FCriticalSection FLightweightTimeGuard::ReportMutex; @@ -27,8 +26,6 @@ void FLightweightTimeGuard::ClearData() { FScopeLock Lock(&ReportMutex); HitchData.Empty(); - // don't capture any hitches immediately - LastHitchTime = FPlatformTime::Seconds(); } void FLightweightTimeGuard::GetData(TMap& Dest) @@ -39,16 +36,6 @@ void FLightweightTimeGuard::GetData(TMap& Dest) void FLightweightTimeGuard::ReportHitch(const TCHAR* InName, const float TimeMS) { - const double kHitchDebounceTime = 2.0; - - // Don't report hitches that occur in the same 5sec window. This will also stop - // the outer scope of nested checks reporting - const double TimeNow = FPlatformTime::Seconds(); - if (TimeNow < LastHitchTime + kHitchDebounceTime) - { - return; - } - FScopeLock lock(&ReportMutex); FGuardInfo& Data = HitchData.FindOrAdd(InName); @@ -64,8 +51,6 @@ void FLightweightTimeGuard::ReportHitch(const TCHAR* InName, const float TimeMS) Data.Max = FMath::Max(Data.Max, TimeMS); Data.LastTime = FDateTime::UtcNow(); - LastHitchTime = TimeNow; - UE_LOG(LogTimeGuard, Warning, TEXT("Detected Hitch of %0.2fms in %s"), TimeMS, InName); } diff --git a/Engine/Source/Runtime/Core/Private/ProfilingDebugging/Histogram.cpp b/Engine/Source/Runtime/Core/Private/ProfilingDebugging/Histogram.cpp index e48894cf4ef0..a917feb87893 100644 --- a/Engine/Source/Runtime/Core/Private/ProfilingDebugging/Histogram.cpp +++ b/Engine/Source/Runtime/Core/Private/ProfilingDebugging/Histogram.cpp @@ -12,6 +12,8 @@ void FHistogram::InitLinear(double MinTime, double MaxTime, double BinSize) SumOfAllMeasures = 0.0; CountOfAllMeasures = 0; + Bins.Empty(); + double CurrentBinMin = MinTime; while (CurrentBinMin < MaxTime) { @@ -46,6 +48,26 @@ void FHistogram::InitHitchTracking() Bins.Add(FBin(5000.0)); } +void FHistogram::InitFromArray(TArrayView Thresholds) +{ + SumOfAllMeasures = 0.0; + CountOfAllMeasures = 0; + Bins.Empty(); + + for (int32 Index = 0; Index < Thresholds.Num(); ++Index) + { + const int32 NextIndex = Index + 1; + if (NextIndex == Thresholds.Num()) + { + Bins.Emplace(Thresholds[Index]); + } + else + { + Bins.Emplace(Thresholds[Index], Thresholds[NextIndex]); + } + } +} + void FHistogram::Reset() { for (FBin& Bin : Bins) diff --git a/Engine/Source/Runtime/Core/Private/ProfilingDebugging/InstanceCounter.cpp b/Engine/Source/Runtime/Core/Private/ProfilingDebugging/InstanceCounter.cpp new file mode 100644 index 000000000000..a42def17f06f --- /dev/null +++ b/Engine/Source/Runtime/Core/Private/ProfilingDebugging/InstanceCounter.cpp @@ -0,0 +1,113 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "ProfilingDebugging/InstanceCounter.h" +#include "Misc/ScopeLock.h" +#include "Logging/LogMacros.h" +#include "IConsoleManager.h" + +DEFINE_LOG_CATEGORY_STATIC(LogInstanceCount, Log, All); + +FInstanceCountingObject::FGlobalVars* FInstanceCountingObject::Globals = nullptr; + +/** + * used to dump instance counts at the console or with associated commands (e.g. memreport) + */ +static FAutoConsoleCommandWithOutputDevice FInstanceCountingDumpCommand( + TEXT("LogCountedInstances"), + TEXT("Dumps count of all tracked FInstanceCountingObject's"), + FConsoleCommandWithOutputDeviceDelegate::CreateStatic(&FInstanceCountingObject::LogCounts) +); + +FInstanceCountingObject::FGlobalVars& FInstanceCountingObject::GetGlobals() +{ + if (Globals == nullptr) + { + Globals = new FGlobalVars(); + } + return *Globals; +} + +FInstanceCountingObject::FInstanceCountingObject(const TCHAR* InName, bool InLogConstruction) + : Name(InName) + , DoLog(InLogConstruction) +{ + IncrementStats(); +} + +FInstanceCountingObject::FInstanceCountingObject(const FInstanceCountingObject& RHS) + : Name(RHS.Name) + , DoLog(RHS.DoLog) +{ + IncrementStats(); +} + +FInstanceCountingObject::~FInstanceCountingObject() +{ + DecrementStats(); +} + +void FInstanceCountingObject::IncrementStats() +{ + int32 Count = 0; + + { + FScopeLock Lock(&GetGlobals().Mutex); + + int32& RefCount = GetGlobals().InstanceCounts.FindOrAdd(Name); + + RefCount++; + Count = RefCount; + } + + if (DoLog) + { + UE_LOG(LogInstanceCount, Log, TEXT("Constructed %s at 0x%08X, count=%d"), *Name.ToString(), this, Count); + } +} + +void FInstanceCountingObject::DecrementStats() +{ + int32 Count = 0; + + { + check(Globals); + FScopeLock Lock(&Globals->Mutex); + + int32& RefCount = Globals->InstanceCounts[Name]; + + RefCount--; + Count = RefCount; + } + + if (DoLog) + { + UE_LOG(LogInstanceCount, Log, TEXT("Destructed %s at 0x%08X, count=%d"), *Name.ToString(), this, Count); + } +} + + int32 FInstanceCountingObject::GetInstanceCount(const TCHAR* Name) +{ + check(Globals); + FScopeLock Lock(&Globals->Mutex); + return Globals->InstanceCounts.FindOrAdd(FName(Name)); +} + +void FInstanceCountingObject::LogCounts(FOutputDevice& OutputDevice) +{ + if (Globals) + { + FScopeLock Lock(&Globals->Mutex); + + if (Globals->InstanceCounts.Num()) + { + OutputDevice.Logf(TEXT("Manually tracked object counts:")); + + for (const auto& KP : Globals->InstanceCounts) + { + OutputDevice.Logf(TEXT("\t%s: %d instances"), *KP.Key.ToString(), KP.Value); + } + + OutputDevice.Logf(TEXT("")); + } + } +} \ No newline at end of file diff --git a/Engine/Source/Runtime/Core/Private/ProfilingDebugging/MallocProfiler.cpp b/Engine/Source/Runtime/Core/Private/ProfilingDebugging/MallocProfiler.cpp index 10c5f1b3796f..8c64dcb1368c 100644 --- a/Engine/Source/Runtime/Core/Private/ProfilingDebugging/MallocProfiler.cpp +++ b/Engine/Source/Runtime/Core/Private/ProfilingDebugging/MallocProfiler.cpp @@ -452,7 +452,7 @@ FMallocProfiler::FMallocProfiler(FMalloc* InMalloc) StartTime = FPlatformTime::Seconds(); // attempt to panic dump the mprof file if the system runs out of memory - FCoreDelegates::OnOutOfMemory.AddLambda([this]() + FCoreDelegates::GetOutOfMemoryDelegate().AddLambda([this]() { PanicDump(TYPE_Malloc, nullptr, nullptr); }); diff --git a/Engine/Source/Runtime/Core/Private/Serialization/Csv/CsvParser.cpp b/Engine/Source/Runtime/Core/Private/Serialization/Csv/CsvParser.cpp index ff6d34cec450..d4733bc6c9b1 100644 --- a/Engine/Source/Runtime/Core/Private/Serialization/Csv/CsvParser.cpp +++ b/Engine/Source/Runtime/Core/Private/Serialization/Csv/CsvParser.cpp @@ -81,10 +81,11 @@ FCsvParser::EParseResult FCsvParser::ParseCell() ReadAt += NumQuotes; // Unescape the double quotes - // We leave the write pos pointing at the trailing closing quote if present so - // it gets overwritten by any subsequent text in the cell + // We null terminate and leave the write pos pointing at the trailing closing quote + // if present so it gets overwritten by any subsequent text in the cell NumQuotes /= 2; while(NumQuotes-- > 0) *(WriteAt++) = '"'; + *WriteAt = '\0'; continue; } diff --git a/Engine/Source/Runtime/Core/Private/Serialization/Csv/CsvParserTests.cpp b/Engine/Source/Runtime/Core/Private/Serialization/Csv/CsvParserTests.cpp index 2c7ccbbdb8ff..7d25686ace9c 100644 --- a/Engine/Source/Runtime/Core/Private/Serialization/Csv/CsvParserTests.cpp +++ b/Engine/Source/Runtime/Core/Private/Serialization/Csv/CsvParserTests.cpp @@ -146,6 +146,16 @@ bool FEndOfStringTest::RunTest(const FString& Parameters) bSuccess &= CsvParser_Tests::CheckRows(Parser.GetRows(), Expected, this); } + { + const FCsvParser Parser(TEXT("\"\",\"\",\"\",\"\"")); + + const FString Expected[][4] = { + { "", "", "", "" }, + }; + + bSuccess &= CsvParser_Tests::CheckRows(Parser.GetRows(), Expected, this); + } + { const FCsvParser Parser(TEXT(",,,\n")); @@ -156,5 +166,15 @@ bool FEndOfStringTest::RunTest(const FString& Parameters) bSuccess &= CsvParser_Tests::CheckRows(Parser.GetRows(), Expected, this); } + { + const FCsvParser Parser(TEXT("\"\",\"\",\"\",\"\"\n")); + + const FString Expected[][4] = { + { "", "", "", "" }, + }; + + bSuccess &= CsvParser_Tests::CheckRows(Parser.GetRows(), Expected, this); + } + return bSuccess; } diff --git a/Engine/Source/Runtime/Core/Private/Stats/Stats2.cpp b/Engine/Source/Runtime/Core/Private/Stats/Stats2.cpp index 8352db92545e..9c18a028b299 100644 --- a/Engine/Source/Runtime/Core/Private/Stats/Stats2.cpp +++ b/Engine/Source/Runtime/Core/Private/Stats/Stats2.cpp @@ -112,7 +112,7 @@ void DebugLeakTest() { DECLARE_SCOPE_CYCLE_COUNTER( TEXT( "LeakTest::NewInt8" ), Stat_LeakTest_NewInt8, STATGROUP_Quick ); int8* Leak = new int8[1000 * 1000]; - } + } //-V773 if (GFrameCounter < 250) @@ -127,7 +127,7 @@ void DebugLeakTest() int8* IntAlloc = new int8[112233]; int8* LeakTask = new int8[100000]; delete[] IntAlloc; - } + } //-V773 }; for (int32 Index = 0; Index < 40; ++Index) @@ -145,7 +145,7 @@ void DebugLeakTest() int8* IntAlloc = new int8[223311]; int8* LeakTask = new int8[100000]; delete[] IntAlloc; - } + } //-V773 TStatId GetStatId() const { @@ -166,7 +166,7 @@ void DebugLeakTest() int8* IntAlloc = new int8[331122]; int8* LeakTask = new int8[100000]; delete[] IntAlloc; - } + } //-V773 if (GIsRequestingExit) { @@ -825,6 +825,7 @@ FName FStatNameAndInfo::GetGroupCategoryFrom(FName InLongName) static TAutoConsoleVariable CVarDumpStatPackets( TEXT("DumpStatPackets"),0, TEXT("If true, dump stat packets.")); + /** The rendering thread runnable object. */ class FStatsThread : public FRunnable, FSingleThreadRunnable { @@ -857,6 +858,7 @@ public: /** Attaches to the task graph stats thread, all processing will be handled by the task graph. */ virtual uint32 Run() override { + FThreadStats::GetThreadStats()->bIsStatsThread = true; FMemory::SetupTLSCachesOnCurrentThread(); FTaskGraphInterface::Get().AttachToThread(ENamedThreads::StatsThread); FTaskGraphInterface::Get().ProcessThreadUntilRequestReturn(ENamedThreads::StatsThread); @@ -878,9 +880,9 @@ public: const int32 MaxIncomingMessages = 24*1024*1024/sizeof(FStatMessage); int32 IncomingDataMessages = 0; - for( int32 Index = 0; Index < IncomingData.Packets.Num(); ++Index ) + for( FStatPacket* Packet : IncomingData.Packets ) { - IncomingDataMessages += IncomingData.Packets[Index]->StatMessages.Num(); + IncomingDataMessages += Packet->StatMessages.Num(); } bShouldProcess = IncomingDataMessages > MaxIncomingMessages || IncomingData.Packets.Num() > MaxIncomingPackets; @@ -960,6 +962,17 @@ public: Tick(); } + void SelfStatMessage(FStatPacket* Packet) + { + if (CVarDumpStatPackets.GetValueOnAnyThread()) + { + UE_LOG(LogStats, Log, TEXT("Self Packet from %x with %d messages"), Packet->ThreadId, Packet->StatMessages.Num()); + } + + IncomingData.Packets.Add(Packet); + State.NumStatMessages.Add(Packet->StatMessages.Num()); + } + /** Start a stats runnable thread. */ void Start() { @@ -1043,11 +1056,12 @@ FThreadStats::FThreadStats(): bWaitForExplicitFlush(0), MemoryMessageScope(0), bReentranceGuard(false), - bSawExplicitFlush(false) + bSawExplicitFlush(false), + bIsStatsThread(false) { Packet.SetThreadProperties(); - check(FPlatformTLS::IsValidTlsSlot(TlsSlot)); + check(TlsSlot && FPlatformTLS::IsValidTlsSlot(TlsSlot)); FPlatformTLS::SetTlsValue(TlsSlot, this); } @@ -1057,7 +1071,8 @@ FThreadStats::FThreadStats( EConstructor ): bWaitForExplicitFlush(0), MemoryMessageScope(0), bReentranceGuard(false), - bSawExplicitFlush(false) + bSawExplicitFlush(false), + bIsStatsThread(false) {} void FThreadStats::CheckEnable() @@ -1147,8 +1162,14 @@ void FThreadStats::FlushRegularStats( bool bHasBrokenCallstacks, bool bForceFlus } Packet.StatMessages.Empty(MaxPresize); } - - TGraphTask::CreateTask().ConstructAndDispatchWhenReady(ToSend); + if (bIsStatsThread) + { + FStatsThread::Get().SelfStatMessage(ToSend); + } + else + { + TGraphTask::CreateTask().ConstructAndDispatchWhenReady(ToSend); + } UpdateExplicitFlush(); } } @@ -1184,7 +1205,14 @@ void FThreadStats::FlushRawStats( bool bHasBrokenCallstacks /*= false*/, bool bF check(!Packet.StatMessages.Num()); - TGraphTask::CreateTask().ConstructAndDispatchWhenReady(ToSend); + if (bIsStatsThread) + { + FStatsThread::Get().SelfStatMessage(ToSend); + } + else + { + TGraphTask::CreateTask().ConstructAndDispatchWhenReady(ToSend); + } UpdateExplicitFlush(); const float NumMessagesAsMB = NumMessages*sizeof(FStatMessage) / 1024.0f / 1024.0f; @@ -1283,18 +1311,18 @@ void FThreadStats::StartThread() FThreadStats::FrameDataIsIncomplete(); // make this non-zero check(IsInGameThread()); check(!IsThreadingReady()); - FStatsThreadState::GetLocalState(); // start up the state - FStatsThread::Get(); - FStatsThread::Get().Start(); - // Preallocate a bunch of FThreadStats to avoid dynamic memory allocation. // (Must do this before we expose ourselves to other threads via tls). FThreadStatsPool::Get(); - + FStatsThreadState::GetLocalState(); // start up the state if (!TlsSlot) { TlsSlot = FPlatformTLS::AllocTlsSlot(); + check(TlsSlot); } + FStatsThread::Get(); + FStatsThread::Get().Start(); + check(IsThreadingReady()); CheckEnable(); diff --git a/Engine/Source/Runtime/Core/Private/Stats/StatsCommand.cpp b/Engine/Source/Runtime/Core/Private/Stats/StatsCommand.cpp index a7ee10cdfcd0..02c4e950b828 100644 --- a/Engine/Source/Runtime/Core/Private/Stats/StatsCommand.cpp +++ b/Engine/Source/Runtime/Core/Private/Stats/StatsCommand.cpp @@ -39,6 +39,9 @@ DECLARE_CYCLE_STAT(TEXT("GetFlatAggregates"),STAT_GetFlatAggregates,STATGROUP_St static float DumpCull = 1.0f; +//Whether or not we render stats in certain modes +bool GRenderStats = true; + void FromString( EStatCompareBy::Type& OutValue, const TCHAR* Buffer ) { @@ -54,8 +57,53 @@ void FromString( EStatCompareBy::Type& OutValue, const TCHAR* Buffer ) } } +/** + * Predicate to sort stats into reverse order of definition, which historically is how people specified a preferred order. + */ +struct FGroupSort +{ + FORCEINLINE bool operator()( FStatMessage const& A, FStatMessage const& B ) const + { + FName GroupA = A.NameAndInfo.GetGroupName(); + FName GroupB = B.NameAndInfo.GetGroupName(); + // first sort by group + if (GroupA == GroupB) + { + // cycle stats come first + if (A.NameAndInfo.GetFlag(EStatMetaFlags::IsCycle) && !B.NameAndInfo.GetFlag(EStatMetaFlags::IsCycle)) + { + return true; + } + if (!A.NameAndInfo.GetFlag(EStatMetaFlags::IsCycle) && B.NameAndInfo.GetFlag(EStatMetaFlags::IsCycle)) + { + return false; + } + // then memory + if (A.NameAndInfo.GetFlag(EStatMetaFlags::IsMemory) && !B.NameAndInfo.GetFlag(EStatMetaFlags::IsMemory)) + { + return true; + } + if (!A.NameAndInfo.GetFlag(EStatMetaFlags::IsMemory) && B.NameAndInfo.GetFlag(EStatMetaFlags::IsMemory)) + { + return false; + } + // otherwise, reverse order of definition + return A.NameAndInfo.GetRawName().GetComparisonIndex() > B.NameAndInfo.GetRawName().GetComparisonIndex(); + } + if (GroupA == NAME_None) + { + return false; + } + if (GroupB == NAME_None) + { + return true; + } + return GroupA.GetComparisonIndex() > GroupB.GetComparisonIndex(); + } +}; + struct FHUDGroupManager; -struct FGroupFilter : public IItemFiler +struct FGroupFilter : public IItemFilter { TSet const& EnabledItems; FString RootFilter; @@ -715,15 +763,15 @@ static bool HandleToggleCommandBroadcast(const FName& InStatName, bool& bOutCurr #if STATS -void FHUDGroupGameThreadRenderer::NewData(FGameThreadHudData* Data) +void FLatestGameThreadStatsData::NewData(FGameThreadStatsData* Data) { delete Latest; Latest = Data; } -FHUDGroupGameThreadRenderer& FHUDGroupGameThreadRenderer::Get() +FLatestGameThreadStatsData& FLatestGameThreadStatsData::Get() { - static FHUDGroupGameThreadRenderer Singleton; + static FLatestGameThreadStatsData Singleton; return Singleton; } @@ -998,7 +1046,7 @@ struct FHUDGroupManager FSimpleDelegateGraphTask::CreateAndDispatchWhenReady ( - FSimpleDelegateGraphTask::FDelegate::CreateRaw(&FHUDGroupGameThreadRenderer::Get(), &FHUDGroupGameThreadRenderer::NewData, (FGameThreadHudData*)nullptr), + FSimpleDelegateGraphTask::FDelegate::CreateRaw(&FLatestGameThreadStatsData::Get(), &FLatestGameThreadStatsData::NewData, (FGameThreadStatsData*)nullptr), GET_STATID(STAT_FSimpleDelegateGraphTask_StatsToGame), nullptr, ENamedThreads::GameThread ); } @@ -1233,7 +1281,7 @@ struct FHUDGroupManager check(NumFrames <= Params.MaxHistoryFrames.Get()); if( NumFrames > 0 ) { - FGameThreadHudData* ToGame = new FGameThreadHudData(false); + FGameThreadStatsData* ToGame = new FGameThreadStatsData(false, GRenderStats); ToGame->RootFilter = RootString; // Copy the total stats stack to the history stats stack and clear all nodes' data and set data type to none. @@ -1315,8 +1363,8 @@ struct FHUDGroupManager FInternalGroup& InternalGroup = GroupIt.Value(); // Create a new hud group. - new(ToGame->HudGroups) FHudGroup(); - FHudGroup& HudGroup = ToGame->HudGroups.Last(); + new(ToGame->ActiveStatGroups) FActiveStatGroupInfo(); + FActiveStatGroupInfo& HudGroup = ToGame->ActiveStatGroups.Last(); ToGame->GroupNames.Add( GroupName ); ToGame->GroupDescriptions.Add( InternalGroup.GroupDescription ); @@ -1419,13 +1467,25 @@ struct FHUDGroupManager } } + { + const TIndirectArray& ActiveGroups = ToGame->ActiveStatGroups; + for(const FActiveStatGroupInfo& GroupInfo : ActiveGroups) + { + for(const FComplexStatMessage& StatMessage : GroupInfo.FlatAggregate) + { + const FName StatName = StatMessage.GetShortName(); + ToGame->NameToStatMap.Add(StatName, &StatMessage); + } + } + } + DECLARE_CYCLE_STAT(TEXT("FSimpleDelegateGraphTask.StatsHierToGame"), STAT_FSimpleDelegateGraphTask_StatsHierToGame, STATGROUP_TaskGraphTasks); FSimpleDelegateGraphTask::CreateAndDispatchWhenReady ( - FSimpleDelegateGraphTask::FDelegate::CreateRaw(&FHUDGroupGameThreadRenderer::Get(), &FHUDGroupGameThreadRenderer::NewData, ToGame), + FSimpleDelegateGraphTask::FDelegate::CreateRaw(&FLatestGameThreadStatsData::Get(), &FLatestGameThreadStatsData::NewData, ToGame), GET_STATID(STAT_FSimpleDelegateGraphTask_StatsHierToGame), nullptr, ENamedThreads::GameThread ); } @@ -1661,11 +1721,9 @@ struct FDumpSpam void NewFrame(const FStatPacket* Packet) { NumPackets++; - int32 NumMessages = Packet->StatMessages.Num(); - TotalCount += NumMessages; - for( int32 MessageIndex = 0; MessageIndex < NumMessages; ++MessageIndex ) + TotalCount += Packet->StatMessages.Num(); + for( const FStatMessage& Message : Packet->StatMessages ) { - const FStatMessage& Message = Packet->StatMessages[MessageIndex]; FName Name = Message.NameAndInfo.GetRawName(); int32* Existing = Counts.Find(Name); if (Existing) @@ -1898,7 +1956,7 @@ static void StatCmd(FString InCmd, bool bStatCommand, FOutputDevice* Ar /*= null // Disable displaying the raw stats memory overhead. FSimpleDelegateGraphTask::CreateAndDispatchWhenReady ( - FSimpleDelegateGraphTask::FDelegate::CreateRaw(&FHUDGroupGameThreadRenderer::Get(), &FHUDGroupGameThreadRenderer::NewData, (FGameThreadHudData*)nullptr), + FSimpleDelegateGraphTask::FDelegate::CreateRaw(&FLatestGameThreadStatsData::Get(), &FLatestGameThreadStatsData::NewData, (FGameThreadStatsData*)nullptr), TStatId(), nullptr, ENamedThreads::GameThread ); } @@ -1981,6 +2039,8 @@ static void StatCmd(FString InCmd, bool bStatCommand, FOutputDevice* Ar /*= null FStatParams Params(Cmd); Params.Group.Set(MaybeGroupFName); FHUDGroupManager::Get(Stats).HandleCommand(Params, bHierarchy); + + GRenderStats = !FParse::Command(&Cmd, TEXT("-nodisplay")); //allow us to hide the rendering of stats #else // If stats aren't enabled, broadcast so engine stats can still be triggered bool bCurrentEnabled, bOthersEnabled; @@ -2196,7 +2256,7 @@ bool DirectStatsCommand(const TCHAR* Cmd, bool bBlockForCompletion /*= false*/, } // make sure these are initialized on the game thread - FHUDGroupGameThreadRenderer::Get(); + FLatestGameThreadStatsData::Get(); FStatGroupGameThreadNotifier::Get(); DECLARE_CYCLE_STAT(TEXT("FSimpleDelegateGraphTask.StatCmd"), diff --git a/Engine/Source/Runtime/Core/Private/Stats/StatsData.cpp b/Engine/Source/Runtime/Core/Private/Stats/StatsData.cpp index 82dfe9e96d4f..a000a1f7341a 100644 --- a/Engine/Source/Runtime/Core/Private/Stats/StatsData.cpp +++ b/Engine/Source/Runtime/Core/Private/Stats/StatsData.cpp @@ -37,6 +37,8 @@ const FName FStatConstants::RAW_NamedMarker = FStatNameAndInfo( GET_STATFNAME( S const FStatNameAndInfo FStatConstants::AdvanceFrame = FStatNameAndInfo( NAME_AdvanceFrame, "", "", TEXT( "" ), EStatDataType::ST_int64, true, false ); +extern bool GRenderStats; + /*----------------------------------------------------------------------------- FRawStatStackNode -----------------------------------------------------------------------------*/ @@ -677,18 +679,17 @@ void FStatsThreadState::ScanForAdvance(const FStatMessagesArray& Data) static const int32 FramesPerSpew = 300; static TMap Profile; static uint64 LastFrame = GFrameCounter; - for (int32 Index = 0; Index < Data.Num(); Index++) + for (const FStatMessage& Item : Data) { - FStatMessage const& Item = Data[Index]; FName ItemName = Item.NameAndInfo.GetRawName(); Profile.FindOrAdd(ItemName)++; } if (GFrameCounter > LastFrame + FramesPerSpew) { LastFrame = GFrameCounter; - Profile.ValueSort(TGreater()); + Profile.ValueSort(TGreater<>()); UE_LOG(LogStats, Log, TEXT("---- stats spam profile -------------")); - for (auto Pair : Profile) + for (TPair Pair : Profile) { float PerFrame = float(Pair.Value) / float(FramesPerSpew); @@ -701,9 +702,8 @@ void FStatsThreadState::ScanForAdvance(const FStatMessagesArray& Data) Profile.Reset(); } } - for (int32 Index = 0; Index < Data.Num(); Index++) + for (const FStatMessage& Item : Data) { - FStatMessage const& Item = Data[Index]; EStatOperation::Type Op = Item.NameAndInfo.GetField(); if (Op == EStatOperation::AdvanceFrameEventGameThread) { @@ -765,28 +765,27 @@ void FStatsThreadState::ScanForAdvance(FStatPacketArray& NewData) } uint32 Count = 0; - for (int32 Index = 0; Index < NewData.Packets.Num(); Index++) + for (FStatPacket* Packet : NewData.Packets) { - const EThreadType::Type ThreadType = NewData.Packets[Index]->ThreadType; - FStatPacket* Packet = NewData.Packets[Index]; - if ( ThreadType == EThreadType::Renderer) + switch (Packet->ThreadType) { - Packet->AssignFrame( CurrentRenderFrame ); + case EThreadType::Renderer: + Packet->AssignFrame( CurrentRenderFrame ); + break; + + case EThreadType::Game: + Packet->AssignFrame( CurrentGameFrame ); + break; + + case EThreadType::Other: + // @see FThreadStats::DetectAndUpdateCurrentGameFrame + break; + + default: + checkf( 0, TEXT( "Unknown thread type" ) ); } - else if (ThreadType == EThreadType::Game) - { - Packet->AssignFrame( CurrentGameFrame ); - } - else if (ThreadType == EThreadType::Other) - { - // @see FThreadStats::DetectAndUpdateCurrentGameFrame - } - else - { - checkf( 0, TEXT( "Unknown thread type" ) ); - } - - const FStatMessagesArray& Data = NewData.Packets[Index]->StatMessages; + + const FStatMessagesArray& Data = Packet->StatMessages; ScanForAdvance(Data); Count += Data.Num(); } @@ -814,9 +813,8 @@ void FStatsThreadState::ToggleFindMemoryExtensiveStats() void FStatsThreadState::ProcessNonFrameStats(FStatMessagesArray& Data, TSet* NonFrameStatsFound) { - for (int32 Index = 0; Index < Data.Num() ; Index++) + for (FStatMessage& Item : Data) { - FStatMessage& Item = Data[Index]; check(Item.NameAndInfo.GetFlag(EStatMetaFlags::DummyAlwaysOne)); // we should never be sending short names to the stats any more EStatOperation::Type Op = Item.NameAndInfo.GetField(); check(Op != EStatOperation::SetLongName); @@ -854,7 +852,7 @@ void FStatsThreadState::ProcessNonFrameStats(FStatMessagesArray& Data, TSet() == EStatOperation::Set); } - } + } } } } @@ -876,9 +874,8 @@ void FStatsThreadState::AddToHistoryAndEmpty(FStatPacketArray& NewData) return; } - for (int32 Index = 0; Index < NewData.Packets.Num(); Index++) + for (FStatPacket* Packet : NewData.Packets) { - FStatPacket* Packet = NewData.Packets[Index]; int64 FrameNum = Packet->Frame; FStatPacketArray& Frame = History.FindOrAdd(FrameNum); Frame.Packets.Add(Packet); @@ -900,9 +897,8 @@ void FStatsThreadState::AddToHistoryAndEmpty(FStatPacketArray& NewData) int64 LatestFinishedFrame = FMath::Min(CurrentGameFrame, CurrentRenderFrame) - 1; - for (int32 Index = 0; Index < Frames.Num(); Index++) + for (int64 FrameNum : Frames) { - int64 FrameNum = Frames[Index]; if (LastFullFrameMetaAndNonFrame < 0) { LastFullFrameMetaAndNonFrame = FrameNum - 1; @@ -919,40 +915,39 @@ void FStatsThreadState::AddToHistoryAndEmpty(FStatPacketArray& NewData) } TSet NonFrameStatsFound; - for (int32 PacketIndex = 0; PacketIndex < Frame.Packets.Num(); PacketIndex++) + for (FStatPacket* Packet : Frame.Packets) { - ProcessNonFrameStats(Frame.Packets[PacketIndex]->StatMessages, &NonFrameStatsFound); - if (!PacketToCopyForNonFrame && Frame.Packets[PacketIndex]->ThreadType == EThreadType::Game) + ProcessNonFrameStats(Packet->StatMessages, &NonFrameStatsFound); + if (!PacketToCopyForNonFrame && Packet->ThreadType == EThreadType::Game) { - PacketToCopyForNonFrame = Frame.Packets[PacketIndex]; + PacketToCopyForNonFrame = Packet; } } // was this a good frame - if (!BadFrames.Contains(FrameNum) && PacketToCopyForNonFrame) + if (PacketToCopyForNonFrame && !BadFrames.Contains(FrameNum)) { // add the non frame stats as a new last packet - check(PacketToCopyForNonFrame); FThreadStats* ThreadStats = FThreadStats::GetThreadStats(); - FStatMessagesArray* NonFrameMessages = nullptr; + FStatPacket* NonFramePacket = nullptr; - for (TMap::TConstIterator It(NotClearedEveryFrame); It; ++It) + for (const TPair& It : NotClearedEveryFrame) { - if (!NonFrameStatsFound.Contains(It.Key())) // don't add stats that are updated during this frame, they would be redundant + if (!NonFrameStatsFound.Contains(It.Key)) // don't add stats that are updated during this frame, they would be redundant { - if (!NonFrameMessages) + if (!NonFramePacket) { - const int32 NonFrameIndex = Frame.Packets.Add(new FStatPacket(*PacketToCopyForNonFrame)); - NonFrameMessages = &Frame.Packets[NonFrameIndex]->StatMessages; + NonFramePacket = new FStatPacket(*PacketToCopyForNonFrame); + Frame.Packets.Add(NonFramePacket); } - new (*NonFrameMessages) FStatMessage(It.Value()); + NonFramePacket->StatMessages.AddElement(It.Value); } } - if(NonFrameMessages) + if(NonFramePacket) { - NumStatMessages.Add(NonFrameMessages->Num()); + NumStatMessages.Add(NonFramePacket->StatMessages.Num()); } GoodFrames.Add(FrameNum); @@ -1101,7 +1096,7 @@ void FStatsThreadState::UpdateStatMessagesMemoryUsage() if( FThreadStats::bIsRawStatsActive ) { - FGameThreadHudData* ToGame = new FGameThreadHudData(true); + FGameThreadStatsData* ToGame = new FGameThreadStatsData(true, GRenderStats); const double InvMB = 1.0f / 1024.0f / 1024.0f; @@ -1119,7 +1114,7 @@ void FStatsThreadState::UpdateStatMessagesMemoryUsage() FSimpleDelegateGraphTask::CreateAndDispatchWhenReady ( - FSimpleDelegateGraphTask::FDelegate::CreateRaw(&FHUDGroupGameThreadRenderer::Get(), &FHUDGroupGameThreadRenderer::NewData, ToGame), + FSimpleDelegateGraphTask::FDelegate::CreateRaw(&FLatestGameThreadStatsData::Get(), &FLatestGameThreadStatsData::NewData, ToGame), TStatId(), nullptr, ENamedThreads::GameThread ); } @@ -1128,7 +1123,7 @@ void FStatsThreadState::UpdateStatMessagesMemoryUsage() void FStatsThreadState::GetInclusiveAggregateStackStats( int64 TargetFrame, TArray& OutStats, - IItemFiler* Filter /*= nullptr*/, + IItemFilter* Filter /*= nullptr*/, bool bAddNonStackStats /*= true*/, TMap>* OptionalOutThreadBreakdownMap /*= nullptr */) const { @@ -1139,7 +1134,7 @@ void FStatsThreadState::GetInclusiveAggregateStackStats( void FStatsThreadState::GetInclusiveAggregateStackStats( const TArray& CondensedMessages, TArray& OutStats, - IItemFiler* Filter /*= nullptr*/, + IItemFilter* Filter /*= nullptr*/, bool bAddNonStackStats /*= true*/, TMap>* OptionalOutThreadBreakdownMap /*= nullptr */ ) const { @@ -1282,7 +1277,7 @@ void FStatsThreadState::GetInclusiveAggregateStackStats( void FStatsThreadState::GetExclusiveAggregateStackStats( int64 TargetFrame, TArray& OutStats, - IItemFiler* Filter /*= nullptr*/, + IItemFilter* Filter /*= nullptr*/, bool bAddNonStackStats /*= true*/ ) const { const TArray& CondensedMessages = GetCondensedHistory( TargetFrame ); @@ -1292,7 +1287,7 @@ void FStatsThreadState::GetExclusiveAggregateStackStats( void FStatsThreadState::GetExclusiveAggregateStackStats( const TArray& CondensedMessages, TArray& OutStats, - IItemFiler* Filter /*= nullptr*/, + IItemFilter* Filter /*= nullptr*/, bool bAddNonStackStats /*= true */ ) const { TMap ThisFrameMetaData; @@ -1390,10 +1385,8 @@ void FStatsThreadState::GetRawStackStats(int64 TargetFrame, FRawStatStackNode& R Stack.Add(ThreadRoot); FRawStatStackNode* Current = Stack.Last(); - const FStatMessagesArray& Data = Packet.StatMessages; - for (int32 Index = 0; Index < Data.Num(); Index++) + for (FStatMessage const& Item : Packet.StatMessages) { - FStatMessage const& Item = Data[Index]; check(Item.NameAndInfo.GetFlag(EStatMetaFlags::DummyAlwaysOne)); // we should never be sending short names to the stats anymore EStatOperation::Type Op = Item.NameAndInfo.GetField(); @@ -1525,7 +1518,7 @@ void FStatsThreadState::GetRawStackStats(int64 TargetFrame, FRawStatStackNode& R void FStatsThreadState::UncondenseStackStats( int64 TargetFrame, FRawStatStackNode& Root, - IItemFiler* Filter /*= nullptr*/, + IItemFilter* Filter /*= nullptr*/, TArray* OutNonStackStats /*= nullptr */) const { const TArray& CondensedMessages = GetCondensedHistory( TargetFrame ); @@ -1535,7 +1528,7 @@ void FStatsThreadState::UncondenseStackStats( void FStatsThreadState::UncondenseStackStats( const TArray& CondensedMessages, FRawStatStackNode& Root, - IItemFiler* Filter /*= nullptr*/, + IItemFilter* Filter /*= nullptr*/, TArray* OutNonStackStats /*= nullptr */ ) const { TMap ThisFrameNonStackStats; @@ -1610,9 +1603,8 @@ int64 FStatsThreadState::GetFastThreadFrameTimeInternal( int64 TargetFrame, int3 if( Packet.ThreadId == ThreadID || Packet.ThreadType == Thread ) { const FStatMessagesArray& Data = Packet.StatMessages; - for (int32 Index = 0; Index < Data.Num(); Index++) + for (FStatMessage const& Item : Data) { - FStatMessage const& Item = Data[Index]; EStatOperation::Type Op = Item.NameAndInfo.GetField(); FName LongName = Item.NameAndInfo.GetRawName(); if (Op == EStatOperation::CycleScopeStart) @@ -1776,7 +1768,7 @@ void FStatsThreadState::AddMissingStats(TArray& Dest, TSet } } -void FStatsThreadState::FindAndDumpMemoryExtensiveStats( FStatPacketArray &Frame ) +void FStatsThreadState::FindAndDumpMemoryExtensiveStats( const FStatPacketArray& Frame ) { int32 TotalMessages = 0; TMap NameToCount; @@ -1784,9 +1776,9 @@ void FStatsThreadState::FindAndDumpMemoryExtensiveStats( FStatPacketArray &Frame // Generate some data statistics. for( const FStatPacket* StatPacket : Frame.Packets ) { - for( int32 MessageIndex = 0; MessageIndex < StatPacket->StatMessages.Num(); MessageIndex++) + for( const FStatMessage& Message : StatPacket->StatMessages ) { - const FName ShortName = StatPacket->StatMessages[MessageIndex].NameAndInfo.GetShortName(); + const FName ShortName = Message.NameAndInfo.GetShortName(); NameToCount.FindOrAdd(ShortName) += 1; TotalMessages++; } diff --git a/Engine/Source/Runtime/Core/Private/Stats/StatsFile.cpp b/Engine/Source/Runtime/Core/Private/Stats/StatsFile.cpp index 637f230871fe..4668ad1199d1 100644 --- a/Engine/Source/Runtime/Core/Private/Stats/StatsFile.cpp +++ b/Engine/Source/Runtime/Core/Private/Stats/StatsFile.cpp @@ -467,9 +467,9 @@ void FRawStatsWriteFile::WriteStatPacket( FArchive& Ar, FStatPacket& StatPacket // We must handle stat messages in a different way. int32 NumMessages = StatPacket.StatMessages.Num(); Ar << NumMessages; - for (int32 MessageIndex = 0; MessageIndex < NumMessages; ++MessageIndex) + for (const FStatMessage& Message : StatPacket.StatMessages) { - WriteMessage( Ar, StatPacket.StatMessages[MessageIndex] ); + WriteMessage( Ar, Message ); } } diff --git a/Engine/Source/Runtime/Core/Private/Tests/HAL/PlatformTest.cpp b/Engine/Source/Runtime/Core/Private/Tests/HAL/PlatformTest.cpp index 15b68f9c45dd..237d2f9c4aaa 100644 --- a/Engine/Source/Runtime/Core/Private/Tests/HAL/PlatformTest.cpp +++ b/Engine/Source/Runtime/Core/Private/Tests/HAL/PlatformTest.cpp @@ -4,7 +4,6 @@ #include "Misc/AssertionMacros.h" #include "GenericPlatform/GenericPlatformMath.h" #include "Math/UnrealMathUtility.h" -#include "Templates/AlignOf.h" #include "Templates/UnrealTemplate.h" #include "Containers/UnrealString.h" #include "UObject/NameTypes.h" @@ -95,14 +94,14 @@ bool FPlatformVerificationTest::RunTest (const FString& Parameters) check(FString(FPlatformProperties::PlatformName()).Len() > 0); - static_assert(ALIGNOF(int32) == 4, "Align of int32 is not 4."); //Hmmm, this would be very strange, ok maybe, but strange + static_assert(alignof(int32) == 4, "Align of int32 is not 4."); //Hmmm, this would be very strange, ok maybe, but strange MS_ALIGN(16) struct FTestAlign { uint8 Test; } GCC_ALIGN(16); - static_assert(ALIGNOF(FTestAlign) == 16, "Align of FTestAlign is not 16."); + static_assert(alignof(FTestAlign) == 16, "Align of FTestAlign is not 16."); FName::AutoTest(); diff --git a/Engine/Source/Runtime/Core/Private/Tests/Internationalization/ManifestTest.cpp b/Engine/Source/Runtime/Core/Private/Tests/Internationalization/ManifestTest.cpp index 3a3ef6411276..6eb495a5b56c 100644 --- a/Engine/Source/Runtime/Core/Private/Tests/Internationalization/ManifestTest.cpp +++ b/Engine/Source/Runtime/Core/Private/Tests/Internationalization/ManifestTest.cpp @@ -69,7 +69,7 @@ bool FLocContextTest::RunTest( const FString& Parameters ) // Test copy ctor - { + { //-V760 FManifestContext ContextAClone = ContextA; if( ContextAClone.InfoMetadataObj == ContextA.InfoMetadataObj ) diff --git a/Engine/Source/Runtime/Core/Private/Tests/Internationalization/NumberFormatingRulesTest.cpp b/Engine/Source/Runtime/Core/Private/Tests/Internationalization/NumberFormatingRulesTest.cpp index 9774f32530db..8223cb8a9483 100644 --- a/Engine/Source/Runtime/Core/Private/Tests/Internationalization/NumberFormatingRulesTest.cpp +++ b/Engine/Source/Runtime/Core/Private/Tests/Internationalization/NumberFormatingRulesTest.cpp @@ -127,6 +127,24 @@ bool FNumberFormattingRulesTest::RunTest (const FString& Parameters) Test(this, TEXT("Convert a Negative int64 to a number formatted correct for en-US"), FText::AsNumber(Int64NegativeValue, &(NumberFormattingOptions)), FText::FromString(TEXT("-00000000000000012345.000"))); } + { + FNumberFormattingOptions NumberFormattingOptions; + NumberFormattingOptions.MinimumIntegralDigits = 5; + NumberFormattingOptions.MaximumIntegralDigits = 5; + NumberFormattingOptions.UseGrouping = true; + + Test(this, TEXT("Convert a 5 digit int to 5 grouped integral digits formatted correct for en-US"), FText::AsNumber(12345, &NumberFormattingOptions), FText::FromString(TEXT("12,345"))); + } + + { + FNumberFormattingOptions NumberFormattingOptions; + NumberFormattingOptions.MinimumIntegralDigits = 6; + NumberFormattingOptions.MaximumIntegralDigits = 6; + NumberFormattingOptions.UseGrouping = true; + + Test(this, TEXT("Convert a 5 digit int to 6 grouped integral digits formatted correct for en-US"), FText::AsNumber(12345, &NumberFormattingOptions), FText::FromString(TEXT("012,345"))); + } + { FNumberFormattingOptions NumberFormattingOptions; NumberFormattingOptions.MinimumIntegralDigits = 1; diff --git a/Engine/Source/Runtime/Core/Private/Tests/Internationalization/TextTest.cpp b/Engine/Source/Runtime/Core/Private/Tests/Internationalization/TextTest.cpp index b19e813e0fb8..bfbabe90fde9 100644 --- a/Engine/Source/Runtime/Core/Private/Tests/Internationalization/TextTest.cpp +++ b/Engine/Source/Runtime/Core/Private/Tests/Internationalization/TextTest.cpp @@ -979,6 +979,72 @@ bool FTextFormatArgModifierTest::RunTest(const FString& Parameters) #if UE_ENABLE_ICU +IMPLEMENT_SIMPLE_AUTOMATION_TEST(FICUSanitizationTest, "System.Core.Misc.ICUSanitization", EAutomationTestFlags::EditorContext | EAutomationTestFlags::ClientContext | EAutomationTestFlags::EngineFilter) + +bool FICUSanitizationTest::RunTest(const FString& Parameters) +{ + // Validate culture code sanitization + { + auto TestCultureCodeSanitization = [this](const FString& InCode, const FString& InExpectedCode) + { + const FString SanitizedCode = ICUUtilities::SanitizeCultureCode(InCode); + if (SanitizedCode != InExpectedCode) + { + AddError(FString::Printf(TEXT("SanitizeCultureCode did not produce the expected result (got '%s', expected '%s')"), *SanitizedCode, *InExpectedCode)); + } + }; + + TestCultureCodeSanitization(TEXT("en-US"), TEXT("en-US")); + TestCultureCodeSanitization(TEXT("en_US_POSIX"), TEXT("en_US_POSIX")); + TestCultureCodeSanitization(TEXT("en-US{}%"), TEXT("en-US")); + TestCultureCodeSanitization(TEXT("en{}%-US"), TEXT("en-US")); + } + + // Validate timezone code sanitization + { + auto TestTimezoneCodeSanitization = [this](const FString& InCode, const FString& InExpectedCode) + { + const FString SanitizedCode = ICUUtilities::SanitizeTimezoneCode(InCode); + if (SanitizedCode != InExpectedCode) + { + AddError(FString::Printf(TEXT("SanitizeTimezoneCode did not produce the expected result (got '%s', expected '%s')"), *SanitizedCode, *InExpectedCode)); + } + }; + + TestTimezoneCodeSanitization(TEXT("Etc/Unknown"), TEXT("Etc/Unknown")); + TestTimezoneCodeSanitization(TEXT("America/Sao_Paulo"), TEXT("America/Sao_Paulo")); + TestTimezoneCodeSanitization(TEXT("America/Sao_Paulo{}%"), TEXT("America/Sao_Paulo")); + TestTimezoneCodeSanitization(TEXT("America/Sao{}%_Paulo"), TEXT("America/Sao_Paulo")); + TestTimezoneCodeSanitization(TEXT("Antarctica/DumontDUrville"), TEXT("Antarctica/DumontDUrville")); + TestTimezoneCodeSanitization(TEXT("Antarctica/DumontDUrville{}%"), TEXT("Antarctica/DumontDUrville")); + TestTimezoneCodeSanitization(TEXT("Antarctica/Dumont{}%DUrville"), TEXT("Antarctica/DumontDUrville")); + TestTimezoneCodeSanitization(TEXT("Antarctica/DumontD'Urville"), TEXT("Antarctica/DumontDUrville")); + TestTimezoneCodeSanitization(TEXT("Antarctica/DumontDUrville_Dumont"), TEXT("Antarctica/DumontDUrville")); + TestTimezoneCodeSanitization(TEXT("GMT-8:00"), TEXT("GMT-8:00")); + TestTimezoneCodeSanitization(TEXT("GMT-8:00{}%"), TEXT("GMT-8:00")); + TestTimezoneCodeSanitization(TEXT("GMT-{}%8:00"), TEXT("GMT-8:00")); + } + + // Validate currency code sanitization + { + auto TestCurrencyCodeSanitization = [this](const FString& InCode, const FString& InExpectedCode) + { + const FString SanitizedCode = ICUUtilities::SanitizeCurrencyCode(InCode); + if (SanitizedCode != InExpectedCode) + { + AddError(FString::Printf(TEXT("SanitizeCurrencyCode did not produce the expected result (got '%s', expected '%s')"), *SanitizedCode, *InExpectedCode)); + } + }; + + TestCurrencyCodeSanitization(TEXT("USD"), TEXT("USD")); + TestCurrencyCodeSanitization(TEXT("USD{}%"), TEXT("USD")); + TestCurrencyCodeSanitization(TEXT("U{}%SD"), TEXT("USD")); + TestCurrencyCodeSanitization(TEXT("USDUSD"), TEXT("USD")); + } + + return true; +} + IMPLEMENT_SIMPLE_AUTOMATION_TEST(FICUTextTest, "System.Core.Misc.ICUText", EAutomationTestFlags::EditorContext | EAutomationTestFlags::ClientContext | EAutomationTestFlags::EngineFilter) bool FICUTextTest::RunTest (const FString& Parameters) diff --git a/Engine/Source/Runtime/Core/Private/Tests/Misc/FileTest.cpp b/Engine/Source/Runtime/Core/Private/Tests/Misc/FileTest.cpp index 1c540da7fe71..17f089e1ba19 100644 --- a/Engine/Source/Runtime/Core/Private/Tests/Misc/FileTest.cpp +++ b/Engine/Source/Runtime/Core/Private/Tests/Misc/FileTest.cpp @@ -21,70 +21,72 @@ bool FFileTests::RunTest( const FString& Parameters ) // Disabled for now, pending changes to make all platforms consistent. return true; - const FString TempFilename = FPaths::EngineSavedDir() / FGuid::NewGuid().ToString(); - TArray TestData; - TArray ReadData; - uint8 One = 1; - FArchive* TestFile = nullptr; + /* + const FString TempFilename = FPaths::EngineSavedDir() / FGuid::NewGuid().ToString(); + TArray TestData; + TArray ReadData; + uint8 One = 1; + FArchive* TestFile = nullptr; - // We will test the platform abstraction class, IFileManager - IFileManager& FileManager = IFileManager::Get(); + // We will test the platform abstraction class, IFileManager + IFileManager& FileManager = IFileManager::Get(); - // Ensure always starting off without test file existing - FileManager.Delete(*TempFilename); - check(FileManager.FileExists(*TempFilename) == false); + // Ensure always starting off without test file existing + FileManager.Delete(*TempFilename); + check(FileManager.FileExists(*TempFilename) == false); - // Check a new file can be created - TestData.AddZeroed(64); - TestFile = FileManager.CreateFileWriter(*TempFilename, 0); - check(TestFile != nullptr); - TestFile->Serialize(TestData.GetData(), TestData.Num()); - delete TestFile; + // Check a new file can be created + TestData.AddZeroed(64); + TestFile = FileManager.CreateFileWriter(*TempFilename, 0); + check(TestFile != nullptr); + TestFile->Serialize(TestData.GetData(), TestData.Num()); + delete TestFile; - // Confirm same data - check(FFileHelper::LoadFileToArray(ReadData, *TempFilename)); - if(ReadData != TestData) - { - return false; - } + // Confirm same data + check(FFileHelper::LoadFileToArray(ReadData, *TempFilename)); + if(ReadData != TestData) + { + return false; + } - // Using append flag should open the file, and writing data immediatly should append to the end. - // We should also be capable of seeking writing. - TestData.Add(One); - TestData[10] = One; - TestFile = FileManager.CreateFileWriter(*TempFilename, EFileWrite::FILEWRITE_Append); - check(TestFile != nullptr); - TestFile->Serialize(&One, 1); - TestFile->Seek(10); - TestFile->Serialize(&One, 1); - delete TestFile; + // Using append flag should open the file, and writing data immediatly should append to the end. + // We should also be capable of seeking writing. + TestData.Add(One); + TestData[10] = One; + TestFile = FileManager.CreateFileWriter(*TempFilename, EFileWrite::FILEWRITE_Append); + check(TestFile != nullptr); + TestFile->Serialize(&One, 1); + TestFile->Seek(10); + TestFile->Serialize(&One, 1); + delete TestFile; - // Confirm same data - check(FFileHelper::LoadFileToArray(ReadData, *TempFilename)); - if(ReadData != TestData) - { - return false; - } + // Confirm same data + check(FFileHelper::LoadFileToArray(ReadData, *TempFilename)); + if(ReadData != TestData) + { + return false; + } - // No flags should clobber existing file - TestData.Empty(); - TestData.Add(One); - TestFile = FileManager.CreateFileWriter(*TempFilename, 0); - check(TestFile != nullptr); - TestFile->Serialize(&One, 1); - delete TestFile; + // No flags should clobber existing file + TestData.Empty(); + TestData.Add(One); + TestFile = FileManager.CreateFileWriter(*TempFilename, 0); + check(TestFile != nullptr); + TestFile->Serialize(&One, 1); + delete TestFile; - // Confirm same data - check(FFileHelper::LoadFileToArray(ReadData, *TempFilename)); - if(ReadData != TestData) - { - return false; - } + // Confirm same data + check(FFileHelper::LoadFileToArray(ReadData, *TempFilename)); + if(ReadData != TestData) + { + return false; + } - // Delete temp file - FileManager.Delete(*TempFilename); + // Delete temp file + FileManager.Delete(*TempFilename); - return true; + return true; + */ } #endif //WITH_DEV_AUTOMATION_TESTS diff --git a/Engine/Source/Runtime/Core/Private/Tests/Misc/PathsTest.cpp b/Engine/Source/Runtime/Core/Private/Tests/Misc/PathsTest.cpp index a68579776372..d0eed92368e6 100644 --- a/Engine/Source/Runtime/Core/Private/Tests/Misc/PathsTest.cpp +++ b/Engine/Source/Runtime/Core/Private/Tests/Misc/PathsTest.cpp @@ -6,89 +6,155 @@ #include "Misc/Paths.h" #include "Misc/AutomationTest.h" -FString FPaths::GameProjectFilePath; - #if WITH_DEV_AUTOMATION_TESTS IMPLEMENT_SIMPLE_AUTOMATION_TEST(FPathTests, "System.Core.Misc.Paths", EAutomationTestFlags::ApplicationContextMask | EAutomationTestFlags::SmokeFilter) bool FPathTests::RunTest( const FString& Parameters ) { - struct FCollapseRelativeDirectoriesTest + // Directory collapsing { - static void Run(FString Path, const TCHAR* Result) + auto RunCollapseRelativeDirectoriesTest = [this](const FString& InPath, const TCHAR* InResult) { // Run test - bool bValid = FPaths::CollapseRelativeDirectories(Path); + FString CollapsedPath = InPath; + const bool bValid = FPaths::CollapseRelativeDirectories(CollapsedPath); - if (Result) + if (InResult) { // If we're looking for a result, make sure it was returned correctly - check(bValid); - check(Path == Result); + if (!bValid || CollapsedPath != InResult) + { + AddError(FString::Printf(TEXT("Path '%s' failed to collapse correctly (got '%s', expected '%s')."), *InPath, *CollapsedPath, InResult)); + } } else { // Otherwise, make sure it failed - check(!bValid); + if (bValid) + { + AddError(FString::Printf(TEXT("Path '%s' collapsed unexpectedly."), *InPath)); + } } - } - }; + }; - FCollapseRelativeDirectoriesTest::Run(TEXT(".."), NULL); - FCollapseRelativeDirectoriesTest::Run(TEXT("/.."), NULL); - FCollapseRelativeDirectoriesTest::Run(TEXT("./"), TEXT("")); - FCollapseRelativeDirectoriesTest::Run(TEXT("./file.txt"), TEXT("file.txt")); - FCollapseRelativeDirectoriesTest::Run(TEXT("/."), TEXT("/.")); - FCollapseRelativeDirectoriesTest::Run(TEXT("Folder"), TEXT("Folder")); - FCollapseRelativeDirectoriesTest::Run(TEXT("/Folder"), TEXT("/Folder")); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/Folder"), TEXT("C:/Folder")); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/Folder/.."), TEXT("C:")); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/Folder/../"), TEXT("C:/")); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/Folder/../file.txt"), TEXT("C:/file.txt")); - FCollapseRelativeDirectoriesTest::Run(TEXT("Folder/.."), TEXT("")); - FCollapseRelativeDirectoriesTest::Run(TEXT("Folder/../"), TEXT("/")); - FCollapseRelativeDirectoriesTest::Run(TEXT("Folder/../file.txt"), TEXT("/file.txt")); - FCollapseRelativeDirectoriesTest::Run(TEXT("/Folder/.."), TEXT("")); - FCollapseRelativeDirectoriesTest::Run(TEXT("/Folder/../"), TEXT("/")); - FCollapseRelativeDirectoriesTest::Run(TEXT("/Folder/../file.txt"), TEXT("/file.txt")); - FCollapseRelativeDirectoriesTest::Run(TEXT("Folder/../.."), NULL); - FCollapseRelativeDirectoriesTest::Run(TEXT("Folder/../../"), NULL); - FCollapseRelativeDirectoriesTest::Run(TEXT("Folder/../../file.txt"), NULL); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/.."), NULL); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/."), TEXT("C:/.")); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/./"), TEXT("C:/")); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/./file.txt"), TEXT("C:/file.txt")); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/Folder1/../Folder2"), TEXT("C:/Folder2")); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/Folder1/../Folder2/"), TEXT("C:/Folder2/")); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/Folder1/../Folder2/file.txt"), TEXT("C:/Folder2/file.txt")); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/Folder1/../Folder2/../.."), NULL); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/Folder1/../Folder2/../Folder3"), TEXT("C:/Folder3")); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/Folder1/../Folder2/../Folder3/"), TEXT("C:/Folder3/")); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/Folder1/../Folder2/../Folder3/file.txt"), TEXT("C:/Folder3/file.txt")); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/Folder1/Folder2/../../Folder3"), TEXT("C:/Folder3")); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/Folder1/Folder2/../../Folder3/"), TEXT("C:/Folder3/")); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/Folder1/Folder2/../../Folder3/file.txt"), TEXT("C:/Folder3/file.txt")); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/Folder1/Folder2/../../Folder3/../Folder4"), TEXT("C:/Folder4")); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/Folder1/Folder2/../../Folder3/../Folder4/"), TEXT("C:/Folder4/")); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/Folder1/Folder2/../../Folder3/../Folder4/file.txt"), TEXT("C:/Folder4/file.txt")); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/Folder1/Folder2/../Folder3/../../Folder4"), TEXT("C:/Folder4")); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/Folder1/Folder2/../Folder3/../../Folder4/"), TEXT("C:/Folder4/")); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/Folder1/Folder2/../Folder3/../../Folder4/file.txt"), TEXT("C:/Folder4/file.txt")); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/Folder1/Folder2/.././../Folder4"), TEXT("C:/Folder4")); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/Folder1/Folder2/.././../Folder4/"), TEXT("C:/Folder4/")); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/Folder1/Folder2/.././../Folder4/file.txt"), TEXT("C:/Folder4/file.txt")); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/A/B/.././../C"), TEXT("C:/C")); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/A/B/.././../C/"), TEXT("C:/C/")); - FCollapseRelativeDirectoriesTest::Run(TEXT("C:/A/B/.././../C/file.txt"), TEXT("C:/C/file.txt")); - FCollapseRelativeDirectoriesTest::Run(TEXT(".svn"), TEXT(".svn")); - FCollapseRelativeDirectoriesTest::Run(TEXT("/.svn"), TEXT("/.svn")); - FCollapseRelativeDirectoriesTest::Run(TEXT("./Folder/.svn"), TEXT("Folder/.svn")); - FCollapseRelativeDirectoriesTest::Run(TEXT("./.svn/../.svn"), TEXT(".svn")); - FCollapseRelativeDirectoriesTest::Run(TEXT(".svn/./.svn/.././../.svn"), TEXT("/.svn")); + RunCollapseRelativeDirectoriesTest(TEXT(".."), NULL); + RunCollapseRelativeDirectoriesTest(TEXT("/.."), NULL); + RunCollapseRelativeDirectoriesTest(TEXT("./"), TEXT("")); + RunCollapseRelativeDirectoriesTest(TEXT("./file.txt"), TEXT("file.txt")); + RunCollapseRelativeDirectoriesTest(TEXT("/."), TEXT("/.")); + RunCollapseRelativeDirectoriesTest(TEXT("Folder"), TEXT("Folder")); + RunCollapseRelativeDirectoriesTest(TEXT("/Folder"), TEXT("/Folder")); + RunCollapseRelativeDirectoriesTest(TEXT("C:/Folder"), TEXT("C:/Folder")); + RunCollapseRelativeDirectoriesTest(TEXT("C:/Folder/.."), TEXT("C:")); + RunCollapseRelativeDirectoriesTest(TEXT("C:/Folder/../"), TEXT("C:/")); + RunCollapseRelativeDirectoriesTest(TEXT("C:/Folder/../file.txt"), TEXT("C:/file.txt")); + RunCollapseRelativeDirectoriesTest(TEXT("Folder/.."), TEXT("")); + RunCollapseRelativeDirectoriesTest(TEXT("Folder/../"), TEXT("/")); + RunCollapseRelativeDirectoriesTest(TEXT("Folder/../file.txt"), TEXT("/file.txt")); + RunCollapseRelativeDirectoriesTest(TEXT("/Folder/.."), TEXT("")); + RunCollapseRelativeDirectoriesTest(TEXT("/Folder/../"), TEXT("/")); + RunCollapseRelativeDirectoriesTest(TEXT("/Folder/../file.txt"), TEXT("/file.txt")); + RunCollapseRelativeDirectoriesTest(TEXT("Folder/../.."), NULL); + RunCollapseRelativeDirectoriesTest(TEXT("Folder/../../"), NULL); + RunCollapseRelativeDirectoriesTest(TEXT("Folder/../../file.txt"), NULL); + RunCollapseRelativeDirectoriesTest(TEXT("C:/.."), NULL); + RunCollapseRelativeDirectoriesTest(TEXT("C:/."), TEXT("C:/.")); + RunCollapseRelativeDirectoriesTest(TEXT("C:/./"), TEXT("C:/")); + RunCollapseRelativeDirectoriesTest(TEXT("C:/./file.txt"), TEXT("C:/file.txt")); + RunCollapseRelativeDirectoriesTest(TEXT("C:/Folder1/../Folder2"), TEXT("C:/Folder2")); + RunCollapseRelativeDirectoriesTest(TEXT("C:/Folder1/../Folder2/"), TEXT("C:/Folder2/")); + RunCollapseRelativeDirectoriesTest(TEXT("C:/Folder1/../Folder2/file.txt"), TEXT("C:/Folder2/file.txt")); + RunCollapseRelativeDirectoriesTest(TEXT("C:/Folder1/../Folder2/../.."), NULL); + RunCollapseRelativeDirectoriesTest(TEXT("C:/Folder1/../Folder2/../Folder3"), TEXT("C:/Folder3")); + RunCollapseRelativeDirectoriesTest(TEXT("C:/Folder1/../Folder2/../Folder3/"), TEXT("C:/Folder3/")); + RunCollapseRelativeDirectoriesTest(TEXT("C:/Folder1/../Folder2/../Folder3/file.txt"), TEXT("C:/Folder3/file.txt")); + RunCollapseRelativeDirectoriesTest(TEXT("C:/Folder1/Folder2/../../Folder3"), TEXT("C:/Folder3")); + RunCollapseRelativeDirectoriesTest(TEXT("C:/Folder1/Folder2/../../Folder3/"), TEXT("C:/Folder3/")); + RunCollapseRelativeDirectoriesTest(TEXT("C:/Folder1/Folder2/../../Folder3/file.txt"), TEXT("C:/Folder3/file.txt")); + RunCollapseRelativeDirectoriesTest(TEXT("C:/Folder1/Folder2/../../Folder3/../Folder4"), TEXT("C:/Folder4")); + RunCollapseRelativeDirectoriesTest(TEXT("C:/Folder1/Folder2/../../Folder3/../Folder4/"), TEXT("C:/Folder4/")); + RunCollapseRelativeDirectoriesTest(TEXT("C:/Folder1/Folder2/../../Folder3/../Folder4/file.txt"), TEXT("C:/Folder4/file.txt")); + RunCollapseRelativeDirectoriesTest(TEXT("C:/Folder1/Folder2/../Folder3/../../Folder4"), TEXT("C:/Folder4")); + RunCollapseRelativeDirectoriesTest(TEXT("C:/Folder1/Folder2/../Folder3/../../Folder4/"), TEXT("C:/Folder4/")); + RunCollapseRelativeDirectoriesTest(TEXT("C:/Folder1/Folder2/../Folder3/../../Folder4/file.txt"), TEXT("C:/Folder4/file.txt")); + RunCollapseRelativeDirectoriesTest(TEXT("C:/Folder1/Folder2/.././../Folder4"), TEXT("C:/Folder4")); + RunCollapseRelativeDirectoriesTest(TEXT("C:/Folder1/Folder2/.././../Folder4/"), TEXT("C:/Folder4/")); + RunCollapseRelativeDirectoriesTest(TEXT("C:/Folder1/Folder2/.././../Folder4/file.txt"), TEXT("C:/Folder4/file.txt")); + RunCollapseRelativeDirectoriesTest(TEXT("C:/A/B/.././../C"), TEXT("C:/C")); + RunCollapseRelativeDirectoriesTest(TEXT("C:/A/B/.././../C/"), TEXT("C:/C/")); + RunCollapseRelativeDirectoriesTest(TEXT("C:/A/B/.././../C/file.txt"), TEXT("C:/C/file.txt")); + RunCollapseRelativeDirectoriesTest(TEXT(".svn"), TEXT(".svn")); + RunCollapseRelativeDirectoriesTest(TEXT("/.svn"), TEXT("/.svn")); + RunCollapseRelativeDirectoriesTest(TEXT("./Folder/.svn"), TEXT("Folder/.svn")); + RunCollapseRelativeDirectoriesTest(TEXT("./.svn/../.svn"), TEXT(".svn")); + RunCollapseRelativeDirectoriesTest(TEXT(".svn/./.svn/.././../.svn"), TEXT("/.svn")); + } + + // Extension texts + { + auto RunGetExtensionTest = [this](const FString& InPath, const FString& InExpectedExt) + { + // Run test + const FString Ext = FPaths::GetExtension(InPath); + if (Ext != InExpectedExt) + { + AddError(FString::Printf(TEXT("Path '%s' failed to get the extension (got '%s', expected '%s')."), *InPath, *Ext, *InExpectedExt)); + } + }; + + RunGetExtensionTest(TEXT("file"), TEXT("")); + RunGetExtensionTest(TEXT("file.txt"), TEXT("txt")); + RunGetExtensionTest(TEXT("file.tar.gz"), TEXT("gz")); + RunGetExtensionTest(TEXT("C:/Folder/file"), TEXT("")); + RunGetExtensionTest(TEXT("C:/Folder/file.txt"), TEXT("txt")); + RunGetExtensionTest(TEXT("C:/Folder/file.tar.gz"), TEXT("gz")); + RunGetExtensionTest(TEXT("C:/Folder/First.Last/file"), TEXT("")); + RunGetExtensionTest(TEXT("C:/Folder/First.Last/file.txt"), TEXT("txt")); + RunGetExtensionTest(TEXT("C:/Folder/First.Last/file.tar.gz"), TEXT("gz")); + + auto RunSetExtensionTest = [this](const FString& InPath, const FString& InNewExt, const FString& InExpectedPath) + { + // Run test + const FString NewPath = FPaths::SetExtension(InPath, InNewExt); + if (NewPath != InExpectedPath) + { + AddError(FString::Printf(TEXT("Path '%s' failed to set the extension (got '%s', expected '%s')."), *InPath, *NewPath, *InExpectedPath)); + } + }; + + RunSetExtensionTest(TEXT("file"), TEXT("log"), TEXT("file.log")); + RunSetExtensionTest(TEXT("file.txt"), TEXT("log"), TEXT("file.log")); + RunSetExtensionTest(TEXT("file.tar.gz"), TEXT("gz2"), TEXT("file.tar.gz2")); + RunSetExtensionTest(TEXT("C:/Folder/file"), TEXT("log"), TEXT("C:/Folder/file.log")); + RunSetExtensionTest(TEXT("C:/Folder/file.txt"), TEXT("log"), TEXT("C:/Folder/file.log")); + RunSetExtensionTest(TEXT("C:/Folder/file.tar.gz"), TEXT("gz2"), TEXT("C:/Folder/file.tar.gz2")); + RunSetExtensionTest(TEXT("C:/Folder/First.Last/file"), TEXT("log"), TEXT("C:/Folder/First.Last/file.log")); + RunSetExtensionTest(TEXT("C:/Folder/First.Last/file.txt"), TEXT("log"), TEXT("C:/Folder/First.Last/file.log")); + RunSetExtensionTest(TEXT("C:/Folder/First.Last/file.tar.gz"), TEXT("gz2"), TEXT("C:/Folder/First.Last/file.tar.gz2")); + + auto RunChangeExtensionTest = [this](const FString& InPath, const FString& InNewExt, const FString& InExpectedPath) + { + // Run test + const FString NewPath = FPaths::ChangeExtension(InPath, InNewExt); + if (NewPath != InExpectedPath) + { + AddError(FString::Printf(TEXT("Path '%s' failed to change the extension (got '%s', expected '%s')."), *InPath, *NewPath, *InExpectedPath)); + } + }; + + RunChangeExtensionTest(TEXT("file"), TEXT("log"), TEXT("file")); + RunChangeExtensionTest(TEXT("file.txt"), TEXT("log"), TEXT("file.log")); + RunChangeExtensionTest(TEXT("file.tar.gz"), TEXT("gz2"), TEXT("file.tar.gz2")); + RunChangeExtensionTest(TEXT("C:/Folder/file"), TEXT("log"), TEXT("C:/Folder/file")); + RunChangeExtensionTest(TEXT("C:/Folder/file.txt"), TEXT("log"), TEXT("C:/Folder/file.log")); + RunChangeExtensionTest(TEXT("C:/Folder/file.tar.gz"), TEXT("gz2"), TEXT("C:/Folder/file.tar.gz2")); + RunChangeExtensionTest(TEXT("C:/Folder/First.Last/file"), TEXT("log"), TEXT("C:/Folder/First.Last/file")); + RunChangeExtensionTest(TEXT("C:/Folder/First.Last/file.txt"), TEXT("log"), TEXT("C:/Folder/First.Last/file.log")); + RunChangeExtensionTest(TEXT("C:/Folder/First.Last/file.tar.gz"), TEXT("gz2"), TEXT("C:/Folder/First.Last/file.tar.gz2")); + } return true; } - #endif //WITH_DEV_AUTOMATION_TESTS diff --git a/Engine/Source/Runtime/Core/Private/UObject/UnrealNames.cpp b/Engine/Source/Runtime/Core/Private/UObject/UnrealNames.cpp index baf90b41a0c7..980979c41d6c 100644 --- a/Engine/Source/Runtime/Core/Private/UObject/UnrealNames.cpp +++ b/Engine/Source/Runtime/Core/Private/UObject/UnrealNames.cpp @@ -6,7 +6,6 @@ #include "Math/NumericLimits.h" #include "Math/UnrealMathUtility.h" #include "HAL/UnrealMemory.h" -#include "Templates/AlignOf.h" #include "Templates/UnrealTemplate.h" #include "Misc/CString.h" #include "Misc/Crc.h" @@ -1277,7 +1276,7 @@ public: check(ThreadGuard.Increment() == 1); // Some platforms need all of the name entries to be aligned to 4 bytes, so by // aligning the size here the next allocation will be aligned to 4 - Size = Align( Size, ALIGNOF(FNameEntry) ); + Size = Align( Size, alignof(FNameEntry) ); // Allocate a new pool if current one is exhausted. We don't worry about a little bit // of waste at the end given the relative size of pool to average and max allocation. diff --git a/Engine/Source/Runtime/Core/Private/Windows/WindowsApplication.cpp b/Engine/Source/Runtime/Core/Private/Windows/WindowsApplication.cpp index c903d6669723..1350037e42b6 100644 --- a/Engine/Source/Runtime/Core/Private/Windows/WindowsApplication.cpp +++ b/Engine/Source/Runtime/Core/Private/Windows/WindowsApplication.cpp @@ -410,11 +410,6 @@ void FWindowsApplication::SetHighPrecisionMouseMode( const bool Enable, const TS ::RegisterRawInputDevices( &RawInputDevice, 1, sizeof( RAWINPUTDEVICE ) ); } -bool FWindowsApplication::TryCalculatePopupWindowPosition( const FPlatformRect& InAnchor, const FVector2D& InSize, const EPopUpOrientation::Type Orientation, /*OUT*/ FVector2D* const CalculatedPopUpPosition ) const -{ - return false; -} - FPlatformRect FWindowsApplication::GetWorkArea( const FPlatformRect& CurrentWindow ) const { RECT WindowsWindowDim; @@ -2394,6 +2389,7 @@ void FWindowsApplication::QueryConnectedMice() TUniquePtr Name; if (Device.dwType != RIM_TYPEMOUSE) continue; + //Force the use of ANSI versions of these calls if (GetRawInputDeviceInfoA(Device.hDevice, RIDI_DEVICENAME, nullptr, &NameLen) == static_cast(-1)) continue; @@ -2405,6 +2401,7 @@ void FWindowsApplication::QueryConnectedMice() Name[NameLen] = 0; FString WName = ANSI_TO_TCHAR(Name.Get()); WName.ReplaceInline(TEXT("#"), TEXT("\\"), ESearchCase::CaseSensitive); + /* * Name XP starts with \??\, vista+ starts \\?\ * In the device list exists a fake Mouse device with the device name of RDP_MOU @@ -2418,6 +2415,17 @@ void FWindowsApplication::QueryConnectedMice() ++MouseCount; } + // If the session is a remote desktop session - assume that a mouse is present, it seems that you can end up + // in a situation where RDP mice don't have a valid name, so the code above fails to locate a valid mouse, + // even though one is present. + if ( MouseCount == 0 ) + { + if ( GetSystemMetrics(SM_REMOTESESSION) ) + { + MouseCount++; + } + } + bIsMouseAttached = MouseCount > 0; } diff --git a/Engine/Source/Runtime/Core/Private/Windows/WindowsAsyncIO.h b/Engine/Source/Runtime/Core/Private/Windows/WindowsAsyncIO.h new file mode 100644 index 000000000000..f6ece8493516 --- /dev/null +++ b/Engine/Source/Runtime/Core/Private/Windows/WindowsAsyncIO.h @@ -0,0 +1,392 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +class FWindowsReadRequest; +class FWindowsAsyncReadFileHandle; + +class FWindowsReadRequestWorker : public FNonAbandonableTask +{ + FWindowsReadRequest& ReadRequest; +public: + FWindowsReadRequestWorker(FWindowsReadRequest* InReadRequest) + : ReadRequest(*InReadRequest) + { + } + void DoWork(); + FORCEINLINE TStatId GetStatId() const + { + RETURN_QUICK_DECLARE_CYCLE_STAT(FWindowsReadRequestWorker, STATGROUP_ThreadPoolAsyncTasks); + } +}; + +extern CORE_API TLockFreePointerListUnordered WindowsAsyncIOEventPool; + +HANDLE GetIOPooledEvent() +{ + void *Popped = WindowsAsyncIOEventPool.Pop(); + HANDLE Result = Popped ? (HANDLE)UPTRINT(Popped) : INVALID_HANDLE_VALUE; + if (Result == INVALID_HANDLE_VALUE) + { + Result = CreateEvent(nullptr, true, 0, nullptr); + check((void*)(UPTRINT)Result); //awkwardly using void* to store handles, hope we don't ever have a zero handle :) + } + return Result; +} + +void FreeIOPooledEvent(HANDLE ToFree) +{ + check(ToFree != INVALID_HANDLE_VALUE && (void*)(UPTRINT)ToFree); //awkwardly using void* to store handles, hope we don't ever have a zero handle :) + ResetEvent(ToFree); + WindowsAsyncIOEventPool.Push((void*)(UPTRINT)ToFree); +} + + +class FWindowsReadRequest : public IAsyncReadRequest +{ + FAsyncTask* Task; + FWindowsAsyncReadFileHandle* Owner; + int64 Offset; + int64 BytesToRead; + int64 FileSize; + HANDLE FileHandle; + EAsyncIOPriority Priority; + uint8* TempMemory; + int64 AlignedOffset; + int64 AlignedBytesToRead; + OVERLAPPED OverlappedIO; +public: + FWindowsReadRequest(FWindowsAsyncReadFileHandle* InOwner, FAsyncFileCallBack* CompleteCallback, uint8* InUserSuppliedMemory, int64 InOffset, int64 InBytesToRead, int64 InFileSize, HANDLE InHandle, EAsyncIOPriority InPriority) + : IAsyncReadRequest(CompleteCallback, false, InUserSuppliedMemory) + , Task(nullptr) + , Owner(InOwner) + , Offset(InOffset) + , BytesToRead(InBytesToRead) + , FileSize(InFileSize) + , FileHandle(InHandle) + , Priority(InPriority) + , TempMemory(nullptr) + { + FMemory::Memzero(OverlappedIO); + OverlappedIO.hEvent = INVALID_HANDLE_VALUE; + check(Offset >= 0 && BytesToRead > 0); + if (BytesToRead == MAX_int64) + { + BytesToRead = FileSize - Offset; + check(BytesToRead > 0); + } + AlignedOffset = Offset; + AlignedBytesToRead = BytesToRead; + if (CheckForPrecache()) + { + SetComplete(); + } + else + { + AlignedOffset = AlignDown(Offset, 4096); + AlignedBytesToRead = Align(Offset + BytesToRead, 4096) - AlignedOffset; + check(AlignedOffset >= 0 && AlignedBytesToRead > 0); + + bool bMemoryHasBeenAcquired = bUserSuppliedMemory; + if (bUserSuppliedMemory && (AlignedOffset != Offset || AlignedBytesToRead != BytesToRead)) + { + static int32 NumMessages = 0; + if (NumMessages < 10) + { + NumMessages++; + UE_LOG(LogTemp, Log, TEXT("FWindowsReadRequest request was not aligned. This is expected with loose files, but not a pak file.")); + } + else if (NumMessages == 10) + { + NumMessages++; + UE_LOG(LogTemp, Log, TEXT("LAST NOTIFICATION THIS RUN: FWindowsReadRequest request was not aligned.")); + } + TempMemory = (uint8*)FMemory::Malloc(AlignedBytesToRead); + INC_MEMORY_STAT_BY(STAT_AsyncFileMemory, AlignedBytesToRead); + } + else if (!bMemoryHasBeenAcquired) + { + check(!Memory); + Memory = (uint8*)FMemory::Malloc(AlignedBytesToRead); + INC_MEMORY_STAT_BY(STAT_AsyncFileMemory, AlignedBytesToRead); + } + check(Memory); + uint32 NumRead = 0; + + { + ULARGE_INTEGER LI; + LI.QuadPart = AlignedOffset; + OverlappedIO.Offset = LI.LowPart; + OverlappedIO.OffsetHigh = LI.HighPart; + } + OverlappedIO.hEvent = GetIOPooledEvent(); + if (!ReadFile(FileHandle, TempMemory ? TempMemory : Memory, AlignedBytesToRead, (LPDWORD)&NumRead, &OverlappedIO)) + { + uint32 ErrorCode = GetLastError(); + if (ErrorCode != ERROR_IO_PENDING) + { + UE_LOG(LogTemp, Fatal, TEXT("FWindowsReadRequest ReadFile Failed! Error code = %x"), ErrorCode); + } + } + Task = new FAsyncTask(this); + Start(); + } + } + virtual ~FWindowsReadRequest(); + + bool CheckForPrecache(); + + void PerformRequest() + { + +#if 0 + if (!HasOverlappedIoCompleted(&OverlappedIO)) + { + WaitForSingleObject(OverlappedIO.hEvent, 0); + } +#endif + check(AlignedOffset <= Offset); + uint32 BytesRead = 0; + if (!GetOverlappedResult(FileHandle, &OverlappedIO, (LPDWORD)&BytesRead, TRUE)) + { + uint32 ErrorCode = GetLastError(); + UE_LOG(LogTemp, Fatal, TEXT("FWindowsReadRequest GetOverlappedResult failed code = %x!"), ErrorCode); + } + if (int64(BytesRead) < BytesToRead + (Offset - AlignedOffset)) + { + uint32 ErrorCode = GetLastError(); + UE_LOG(LogTemp, Fatal, TEXT("FWindowsReadRequest Short Read code = %x!"), ErrorCode); + } + + check(Memory); + if (TempMemory) + { + FMemory::Memcpy(Memory, TempMemory + (Offset - AlignedOffset), BytesToRead); + FMemory::Free(TempMemory); + TempMemory = nullptr; + DEC_MEMORY_STAT_BY(STAT_AsyncFileMemory, AlignedBytesToRead); + } + else if (AlignedOffset != Offset) + { + FMemory::Memmove(Memory, Memory + (Offset - AlignedOffset), BytesToRead); + } + SetComplete(); + } + + uint8* GetContainedSubblock(uint8* UserSuppliedMemory, int64 InOffset, int64 InBytesToRead) + { + if (InOffset >= Offset && InOffset + InBytesToRead <= Offset + BytesToRead && + this->PollCompletion()) + { + check(Memory); + if (!UserSuppliedMemory) + { + UserSuppliedMemory = (uint8*)FMemory::Malloc(InBytesToRead); + INC_MEMORY_STAT_BY(STAT_AsyncFileMemory, InBytesToRead); + } + FMemory::Memcpy(UserSuppliedMemory, Memory + InOffset - Offset, InBytesToRead); + return UserSuppliedMemory; + } + return nullptr; + } + + void Start() + { + if (FPlatformProcess::SupportsMultithreading()) + { + Task->StartBackgroundTask(GIOThreadPool); + } + else + { + Task->StartSynchronousTask(); + WaitCompletionImpl(0.0f); // might as well finish it now + } + } + + virtual void WaitCompletionImpl(float TimeLimitSeconds) override + { + if (Task) + { + bool bResult; + if (TimeLimitSeconds <= 0.0f) + { + Task->EnsureCompletion(); + bResult = true; + } + else + { + bResult = Task->WaitCompletionWithTimeout(TimeLimitSeconds); + } + if (bResult) + { + check(bCompleteAndCallbackCalled); + delete Task; + Task = nullptr; + } + } + } + virtual void CancelImpl() override + { + // no cancel support + } + +}; + +void FWindowsReadRequestWorker::DoWork() +{ + ReadRequest.PerformRequest(); +} + +class FWindowsSizeRequest : public IAsyncReadRequest +{ +public: + FWindowsSizeRequest(FAsyncFileCallBack* CompleteCallback, int64 InFileSize) + : IAsyncReadRequest(CompleteCallback, true, nullptr) + { + Size = InFileSize; + SetComplete(); + } + virtual void WaitCompletionImpl(float TimeLimitSeconds) override + { + } + virtual void CancelImpl() + { + } +}; + +class FWindowsFailedRequest : public IAsyncReadRequest +{ +public: + FWindowsFailedRequest(FAsyncFileCallBack* CompleteCallback) + : IAsyncReadRequest(CompleteCallback, false, nullptr) + { + SetComplete(); + } + virtual void WaitCompletionImpl(float TimeLimitSeconds) override + { + } + virtual void CancelImpl() + { + } +}; + + +class FWindowsAsyncReadFileHandle final : public IAsyncReadFileHandle +{ +public: + HANDLE FileHandle; + int64 FileSize; +private: + TArray LiveRequests; // linear searches could be improved + + FCriticalSection LiveRequestsCritical; + FCriticalSection HandleCacheCritical; +public: + + FWindowsAsyncReadFileHandle(HANDLE InFileHandle) + : FileHandle(InFileHandle) + , FileSize(-1) + { + if (FileHandle != INVALID_HANDLE_VALUE) + { + LARGE_INTEGER LI; + GetFileSizeEx(FileHandle, &LI); + FileSize = LI.QuadPart; + } + } + ~FWindowsAsyncReadFileHandle() + { +#if DO_CHECK + FScopeLock Lock(&LiveRequestsCritical); + check(!LiveRequests.Num()); // must delete all requests before you delete the handle +#endif + } + void RemoveRequest(FWindowsReadRequest* Req) + { + FScopeLock Lock(&LiveRequestsCritical); + verify(LiveRequests.Remove(Req) == 1); + } + uint8* GetPrecachedBlock(uint8* UserSuppliedMemory, int64 InOffset, int64 InBytesToRead) + { + FScopeLock Lock(&LiveRequestsCritical); + uint8* Result = nullptr; + for (FWindowsReadRequest* Req : LiveRequests) + { + Result = Req->GetContainedSubblock(UserSuppliedMemory, InOffset, InBytesToRead); + if (Result) + { + break; + } + } + return Result; + } + virtual IAsyncReadRequest* SizeRequest(FAsyncFileCallBack* CompleteCallback = nullptr) override + { + return new FWindowsSizeRequest(CompleteCallback, FileSize); + } + virtual IAsyncReadRequest* ReadRequest(int64 Offset, int64 BytesToRead, EAsyncIOPriority Priority = AIOP_Normal, FAsyncFileCallBack* CompleteCallback = nullptr, uint8* UserSuppliedMemory = nullptr) override + { + if (FileHandle != INVALID_HANDLE_VALUE) + { + FWindowsReadRequest* Result = new FWindowsReadRequest(this, CompleteCallback, UserSuppliedMemory, Offset, BytesToRead, FileSize, FileHandle, Priority); + if (Priority == AIOP_Precache) // only precache requests are tracked for possible reuse + { + FScopeLock Lock(&LiveRequestsCritical); + LiveRequests.Add(Result); + } + return Result; + } + return new FWindowsFailedRequest(CompleteCallback); + } +}; + +FWindowsReadRequest::~FWindowsReadRequest() +{ + if (Task) + { + Task->EnsureCompletion(); // if the user polls, then we might never actual sync completion of the task until now, this will almost always be done, however we need to be sure the task is clear + delete Task; + } + if (OverlappedIO.hEvent != INVALID_HANDLE_VALUE) + { + FreeIOPooledEvent(OverlappedIO.hEvent); + OverlappedIO.hEvent = INVALID_HANDLE_VALUE; + } + if (Memory) + { + // this can happen with a race on cancel, it is ok, they didn't take the memory, free it now + if (!bUserSuppliedMemory) + { + DEC_MEMORY_STAT_BY(STAT_AsyncFileMemory, BytesToRead); + FMemory::Free(Memory); + } + Memory = nullptr; + } + if (TempMemory) + { + DEC_MEMORY_STAT_BY(STAT_AsyncFileMemory, AlignedBytesToRead); + FMemory::Free(TempMemory); + TempMemory = nullptr; + } + if (Priority == AIOP_Precache) // only precache requests are tracked for possible reuse + { + Owner->RemoveRequest(this); + } + Owner = nullptr; +} + +bool FWindowsReadRequest::CheckForPrecache() +{ + if (Priority > AIOP_Precache) // only requests at higher than precache priority check for existing blocks to copy from + { + check(!Memory || bUserSuppliedMemory); + uint8* Result = Owner->GetPrecachedBlock(Memory, Offset, BytesToRead); + if (Result) + { + check(!bUserSuppliedMemory || Memory == Result); + Memory = Result; + return true; + } + } + return false; +} diff --git a/Engine/Source/Runtime/Core/Private/Windows/WindowsPlatformFile.cpp b/Engine/Source/Runtime/Core/Private/Windows/WindowsPlatformFile.cpp index 83e6d64d6a9a..30621f55136a 100644 --- a/Engine/Source/Runtime/Core/Private/Windows/WindowsPlatformFile.cpp +++ b/Engine/Source/Runtime/Core/Private/Windows/WindowsPlatformFile.cpp @@ -14,8 +14,19 @@ #include "CoreGlobals.h" #include "Windows/WindowsHWrapper.h" #include +#include "LockFreeList.h" +#include "AsyncFileHandle.h" +#include "Async/AsyncWork.h" +#include "ScopeLock.h" #include "Windows/AllowWindowsPlatformTypes.h" + +#include "Private/Windows/WindowsAsyncIO.h" + +TLockFreePointerListUnordered WindowsAsyncIOEventPool; + + + namespace FileConstants { uint32 WIN_INVALID_SET_FILE_POINTER = INVALID_SET_FILE_POINTER; @@ -422,88 +433,134 @@ public: /** * Windows file handle implementation **/ + class CORE_API FFileHandleWindows : public IFileHandle { - enum {READWRITE_SIZE = 1024 * 1024}; + enum { READWRITE_SIZE = 1024 * 1024 }; HANDLE FileHandle; + /** The overlapped IO struct to use for determining async state */ + OVERLAPPED OverlappedIO; + /** Manages the location of our file position for setting on the overlapped struct for reads/writes */ + int64 FilePos; + /** Need the file size for seek from end */ + int64 FileSize; - FORCEINLINE int64 FileSeek(int64 Distance, uint32 MoveMethod) - { - LARGE_INTEGER li; - li.QuadPart = Distance; - li.LowPart = SetFilePointer(FileHandle, li.LowPart, &li.HighPart, MoveMethod); - if (li.LowPart == FileConstants::WIN_INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) - { - li.QuadPart = -1; - } - return li.QuadPart; - } FORCEINLINE bool IsValid() { return FileHandle != NULL && FileHandle != INVALID_HANDLE_VALUE; } + FORCEINLINE void UpdateOverlappedPos() + { + ULARGE_INTEGER LI; + LI.QuadPart = FilePos; + OverlappedIO.Offset = LI.LowPart; + OverlappedIO.OffsetHigh = LI.HighPart; + } + + FORCEINLINE void UpdateFileSize() + { + LARGE_INTEGER LI; + GetFileSizeEx(FileHandle, &LI); + FileSize = LI.QuadPart; + } + public: FFileHandleWindows(HANDLE InFileHandle = NULL) : FileHandle(InFileHandle) + , FilePos(0) + , FileSize(0) { + if (IsValid()) + { + UpdateFileSize(); + } + FMemory::Memzero(&OverlappedIO, sizeof(OVERLAPPED)); } virtual ~FFileHandleWindows() { CloseHandle(FileHandle); FileHandle = NULL; } - virtual int64 Tell() override + virtual int64 Tell(void) override { check(IsValid()); - return FileSeek(0, FILE_CURRENT); + return FilePos; + } + virtual int64 Size() override + { + check(IsValid()); + return FileSize; } virtual bool Seek(int64 NewPosition) override { check(IsValid()); check(NewPosition >= 0); - return FileSeek(NewPosition, FILE_BEGIN) != -1; + check(NewPosition <= FileSize); + + FilePos = NewPosition; + UpdateOverlappedPos(); + return true; } virtual bool SeekFromEnd(int64 NewPositionRelativeToEnd = 0) override { check(IsValid()); check(NewPositionRelativeToEnd <= 0); - return FileSeek(NewPositionRelativeToEnd, FILE_END) != -1; + + // Position is negative so this is actually subtracting + return Seek(FileSize + NewPositionRelativeToEnd); } virtual bool Read(uint8* Destination, int64 BytesToRead) override { check(IsValid()); - while (BytesToRead) + uint32 NumRead = 0; + // Now kick off an async read + if (!ReadFile(FileHandle, Destination, BytesToRead, (::DWORD*)&NumRead, &OverlappedIO)) { - check(BytesToRead >= 0); - int64 ThisSize = FMath::Min(READWRITE_SIZE, BytesToRead); - check(Destination); - uint32 Result=0; - if (!ReadFile(FileHandle, Destination, uint32(ThisSize), (::DWORD *)&Result, NULL) || Result != uint32(ThisSize)) + uint32 ErrorCode = GetLastError(); + if (ErrorCode != ERROR_IO_PENDING) { + // Read failed + return false; + } + // Wait for the read to complete + NumRead = 0; + if (!GetOverlappedResult(FileHandle, &OverlappedIO, (::DWORD*)&NumRead, true)) + { + // Read failed return false; } - Destination += ThisSize; - BytesToRead -= ThisSize; } + // Update where we are in the file + FilePos += NumRead; + UpdateOverlappedPos(); return true; } virtual bool Write(const uint8* Source, int64 BytesToWrite) override { check(IsValid()); - while (BytesToWrite) + uint32 NumWritten = 0; + // Now kick off an async write + if (!WriteFile(FileHandle, Source, BytesToWrite, (::DWORD*)&NumWritten, &OverlappedIO)) { - check(BytesToWrite >= 0); - int64 ThisSize = FMath::Min(READWRITE_SIZE, BytesToWrite); - check(Source); - uint32 Result=0; - if (!WriteFile(FileHandle, Source, uint32(ThisSize), (::DWORD *)&Result, NULL) || Result != uint32(ThisSize)) + uint32 ErrorCode = GetLastError(); + if (ErrorCode != ERROR_IO_PENDING) { + // Write failed + return false; + } + // Wait for the write to complete + NumWritten = 0; + if (!GetOverlappedResult(FileHandle, &OverlappedIO, (::DWORD*)&NumWritten, true)) + { + // Write failed return false; } - Source += ThisSize; - BytesToWrite -= ThisSize; } + // Update where we are in the file + FilePos += NumWritten; + UpdateOverlappedPos(); + UpdateFileSize(); return true; } }; @@ -655,6 +712,22 @@ public: } return Result; } + +#define USE_WINDOWS_ASYNC_IMPL (!IS_PROGRAM && !WITH_EDITOR) +#if USE_WINDOWS_ASYNC_IMPL + virtual IAsyncReadFileHandle* OpenAsyncRead(const TCHAR* Filename) override + { + uint32 Access = GENERIC_READ; + uint32 WinFlags = FILE_SHARE_READ; + uint32 Create = OPEN_EXISTING; + + HANDLE Handle = CreateFileW(*NormalizeFilename(Filename), Access, WinFlags, NULL, Create, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL); + // we can't really fail here because this is intended to be an async open + return new FWindowsAsyncReadFileHandle(Handle); + + } +#endif + virtual IFileHandle* OpenRead(const TCHAR* Filename, bool bAllowWrite = false) override { uint32 Access = GENERIC_READ; @@ -683,7 +756,7 @@ public: uint32 Access = GENERIC_READ; uint32 WinFlags = FILE_SHARE_READ | (bAllowWrite ? FILE_SHARE_WRITE : 0); uint32 Create = OPEN_EXISTING; - HANDLE Handle = CreateFileW(*NormalizeFilename(Filename), Access, WinFlags, NULL, Create, FILE_ATTRIBUTE_NORMAL, NULL); + HANDLE Handle = CreateFileW(*NormalizeFilename(Filename), Access, WinFlags, NULL, Create, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); if (Handle != INVALID_HANDLE_VALUE) { return new FFileHandleWindows(Handle); diff --git a/Engine/Source/Runtime/Core/Private/Windows/WindowsPlatformMemory.cpp b/Engine/Source/Runtime/Core/Private/Windows/WindowsPlatformMemory.cpp index 27b69d78820a..f2051aa9e8f8 100644 --- a/Engine/Source/Runtime/Core/Private/Windows/WindowsPlatformMemory.cpp +++ b/Engine/Source/Runtime/Core/Private/Windows/WindowsPlatformMemory.cpp @@ -81,7 +81,7 @@ FMalloc* FWindowsPlatformMemory::BaseAllocator() _CrtSetAllocHook(WindowsAllocHook); #endif // ENABLE_WIN_ALLOC_TRACKING - if (FORCE_ANSI_ALLOCATOR) + if (FORCE_ANSI_ALLOCATOR) //-V517 { AllocatorToUse = EMemoryAllocatorToUse::Ansi; } diff --git a/Engine/Source/Runtime/Core/Private/Windows/WindowsPlatformMisc.cpp b/Engine/Source/Runtime/Core/Private/Windows/WindowsPlatformMisc.cpp index c9ee8195ad41..dc18b976c5b9 100644 --- a/Engine/Source/Runtime/Core/Private/Windows/WindowsPlatformMisc.cpp +++ b/Engine/Source/Runtime/Core/Private/Windows/WindowsPlatformMisc.cpp @@ -411,6 +411,35 @@ int32 FWindowsOSVersionHelper::GetOSVersions( FString& out_OSVersionLabel, FStri return ErrorCode; } + +FString FWindowsOSVersionHelper::GetOSVersion() +{ + int32 ErrorCode = (int32)SUCCEEDED; + + // Get system info + SYSTEM_INFO SystemInfo; + if (FPlatformMisc::Is64bitOperatingSystem()) + { + GetNativeSystemInfo(&SystemInfo); + } + else + { + GetSystemInfo(&SystemInfo); + } + + OSVERSIONINFOEX OsVersionInfo = { 0 }; + OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); +#pragma warning(push) +#pragma warning(disable : 4996) // 'function' was declared deprecated + CA_SUPPRESS(28159) + if (GetVersionEx((LPOSVERSIONINFO)&OsVersionInfo)) +#pragma warning(pop) + { + return FString::Printf(TEXT("%d.%d.%d.%d.%d"), OsVersionInfo.dwMajorVersion, OsVersionInfo.dwMinorVersion, OsVersionInfo.dwBuildNumber, OsVersionInfo.wProductType, OsVersionInfo.wSuiteMask); + } + return FString(); +} + #include "Windows/HideWindowsPlatformTypes.h" /** @@ -1472,15 +1501,23 @@ int MessageBoxExtInternal( EAppMsgType::Type MsgType, HWND HandleWnd, const TCHA GMessageBoxText = (TCHAR *) Text; GMessageBoxCaption = (TCHAR *) Caption; - if( MsgType == EAppMsgType::YesNoYesAllNoAll ) + switch (MsgType) { - GCancelButtonEnabled = false; - return DialogBox( GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_YESNO2ALL), HandleWnd, MessageBoxDlgProc ); - } - else if( MsgType == EAppMsgType::YesNoYesAllNoAllCancel ) - { - GCancelButtonEnabled = true; - return DialogBox( GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_YESNO2ALLCANCEL), HandleWnd, MessageBoxDlgProc ); + case EAppMsgType::YesNoYesAllNoAll: + { + GCancelButtonEnabled = false; + return DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_YESNO2ALL), HandleWnd, MessageBoxDlgProc); + } + case EAppMsgType::YesNoYesAllNoAllCancel: + { + GCancelButtonEnabled = true; + return DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_YESNO2ALLCANCEL), HandleWnd, MessageBoxDlgProc); + } + case EAppMsgType::YesNoYesAll: + { + GCancelButtonEnabled = false; + return DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_YESNOYESTOALL), HandleWnd, MessageBoxDlgProc); + } } return -1; @@ -1496,6 +1533,11 @@ EAppReturnType::Type FWindowsPlatformMisc::MessageBoxExt( EAppMsgType::Type MsgT HWND ParentWindow = (HWND)NULL; switch( MsgType ) { + case EAppMsgType::Ok: + { + MessageBox(ParentWindow, Text, Caption, MB_OK|MB_SYSTEMMODAL); + return EAppReturnType::Ok; + } case EAppMsgType::YesNo: { int32 Return = MessageBox( ParentWindow, Text, Caption, MB_YESNO|MB_SYSTEMMODAL ); @@ -1527,8 +1569,14 @@ EAppReturnType::Type FWindowsPlatformMisc::MessageBoxExt( EAppMsgType::Type MsgT //These return codes just happen to match up with ours. // return 0 for No, 1 for Yes, 2 for YesToAll, 3 for NoToAll, 4 for Cancel break; + + case EAppMsgType::YesNoYesAll: + return (EAppReturnType::Type)MessageBoxExtInternal(EAppMsgType::YesNoYesAll, ParentWindow, Text, Caption); + //These return codes just happen to match up with ours. + // return 0 for No, 1 for Yes, 2 for YesToAll + break; + default: - MessageBox( ParentWindow, Text, Caption, MB_OK|MB_SYSTEMMODAL ); break; } return EAppReturnType::Cancel; @@ -2065,11 +2113,12 @@ bool FWindowsPlatformMisc::GetWindowTitleMatchingText(const TCHAR* TitleStartsWi HWND hWnd = FindWindowW(NULL,NULL); if (hWnd != NULL) { + size_t TitleStartsWithLen = _tcslen(TitleStartsWith); do { GetWindowText(hWnd,Buffer,8192); // If this matches, then grab the full text - if (_tcsnccmp(TitleStartsWith, Buffer, _tcslen(TitleStartsWith)) == 0) + if (_tcsnccmp(TitleStartsWith, Buffer, TitleStartsWithLen) == 0) { OutTitle = Buffer; hWnd = NULL; @@ -2835,6 +2884,12 @@ void FWindowsPlatformMisc::GetOSVersions( FString& out_OSVersionLabel, FString& } +FString FWindowsPlatformMisc::GetOSVersion() +{ + static FString CachedOSVersion = FWindowsOSVersionHelper::GetOSVersion(); + return CachedOSVersion; +} + bool FWindowsPlatformMisc::GetDiskTotalAndFreeSpace( const FString& InPath, uint64& TotalNumberOfBytes, uint64& NumberOfFreeBytes ) { bool bSuccess = false; @@ -2972,25 +3027,28 @@ EConvertibleLaptopMode FWindowsPlatformMisc::GetConvertibleLaptopMode() IPlatformChunkInstall* FWindowsPlatformMisc::GetPlatformChunkInstall() { static IPlatformChunkInstall* ChunkInstall = nullptr; - if (!ChunkInstall) + static bool bIniChecked = false; + if (!ChunkInstall || !bIniChecked) { -#if !(WITH_EDITORONLY_DATA || IS_PROGRAM) - IPlatformChunkInstallModule* PlatformChunkInstallModule = nullptr; - - FModuleStatus Status; - if (FModuleManager::Get().QueryModule("HTTPChunkInstaller", Status)) + if (!GEngineIni.IsEmpty()) { - PlatformChunkInstallModule = FModuleManager::LoadModulePtr("HTTPChunkInstaller"); - if (PlatformChunkInstallModule != nullptr) - { - // Attempt to grab the platform installer - ChunkInstall = PlatformChunkInstallModule->GetPlatformChunkInstall(); - } + FString InstallModule; + GConfig->GetString(TEXT("StreamingInstall"), TEXT("DefaultProviderName"), InstallModule, GEngineIni); + FModuleStatus Status; + if (FModuleManager::Get().QueryModule(*InstallModule, Status)) + { + PlatformChunkInstallModule = FModuleManager::LoadModulePtr(*InstallModule); + if (PlatformChunkInstallModule != nullptr) + { + // Attempt to grab the platform installer + ChunkInstall = PlatformChunkInstallModule->GetPlatformChunkInstall(); + } + } + bIniChecked = true; } if (PlatformChunkInstallModule == nullptr) -#endif { // Placeholder instance ChunkInstall = FGenericPlatformMisc::GetPlatformChunkInstall(); diff --git a/Engine/Source/Runtime/Core/Private/Windows/WindowsPlatformProcess.cpp b/Engine/Source/Runtime/Core/Private/Windows/WindowsPlatformProcess.cpp index 52a0113b0ede..e264347e7a88 100644 --- a/Engine/Source/Runtime/Core/Private/Windows/WindowsPlatformProcess.cpp +++ b/Engine/Source/Runtime/Core/Private/Windows/WindowsPlatformProcess.cpp @@ -53,7 +53,7 @@ TArray FWindowsPlatformProcess::DllDirectories; void FWindowsPlatformProcess::AddDllDirectory(const TCHAR* Directory) { - FString NormalizedDirectory = Directory; + FString NormalizedDirectory = FPaths::ConvertRelativePathToFull(Directory); FPaths::NormalizeDirectoryName(NormalizedDirectory); FPaths::MakePlatformFilename(NormalizedDirectory); DllDirectories.AddUnique(NormalizedDirectory); @@ -75,13 +75,33 @@ void* FWindowsPlatformProcess::GetDllHandle( const TCHAR* FileName ) SearchPaths.Add(DllDirectories[Idx]); } + static bool SuppressErrors = !FParse::Param(::GetCommandLineW(), TEXT("dllerrors")); + // Load the DLL, avoiding windows dialog boxes if missing - int32 PrevErrorMode = ::SetErrorMode(SEM_NOOPENFILEERRORBOX); + int32 PrevErrorMode = ::SetErrorMode(SuppressErrors ? SEM_NOOPENFILEERRORBOX : 0); void* Handle = LoadLibraryWithSearchPaths(FileName, SearchPaths); - ::SetErrorMode(PrevErrorMode); + if (!Handle) + { + DWORD LastError = ::GetLastError(); + UE_LOG(LogWindows, Log, TEXT("LoadLibraryWithSearchPaths failed for file %s. GetLastError=%d"), FileName, LastError); + + // if errors == 126 (module not found) then write out more info + if (LastError == ERROR_MOD_NOT_FOUND) + { + BOOL Missing = IFileManager::Get().FileExists(FileName); + UE_LOG(LogWindows, Log, TEXT("FileExists returned %d for Module %s"), Missing, FileName); + + for (const auto& Path : SearchPaths) + { + UE_LOG(LogWindows, Log, TEXT("\t%s"), *Path); + } + } + } + + ::SetErrorMode(PrevErrorMode); return Handle; } @@ -718,14 +738,17 @@ void FWindowsPlatformProcess::CleanFileCache() if (bShouldCleanShaderWorkingDirectory && !FParse::Param( FCommandLine::Get(), TEXT("Multiprocess"))) { // get shader path, and convert it to the userdirectory - FString ShaderDir = FString(FPlatformProcess::BaseDir()) / FPlatformProcess::ShaderDir(); - FString UserShaderDir = IFileManager::Get().ConvertToAbsolutePathForExternalAppForWrite(*ShaderDir); - FPaths::CollapseRelativeDirectories(ShaderDir); - - // make sure we don't delete from the source directory - if (ShaderDir != UserShaderDir) + for (FString Dir : FPlatformProcess::AllShaderDirs()) { - IFileManager::Get().DeleteDirectory(*UserShaderDir, false, true); + FString ShaderDir = FString(FPlatformProcess::BaseDir()) / Dir; + FString UserShaderDir = IFileManager::Get().ConvertToAbsolutePathForExternalAppForWrite(*ShaderDir); + FPaths::CollapseRelativeDirectories(ShaderDir); + + // make sure we don't delete from the source directory + if (ShaderDir != UserShaderDir) + { + IFileManager::Get().DeleteDirectory(*UserShaderDir, false, true); + } } FPlatformProcess::CleanShaderWorkingDir(); @@ -856,7 +879,7 @@ const TCHAR* FWindowsPlatformProcess::ApplicationSettingsDir() // make the base user dir path // @todo rocket this folder should be based on your company name, not just be hard coded to /Epic/ - WindowsApplicationSettingsDir = FString(ApplictionSettingsPath) + TEXT("/Epic/"); + WindowsApplicationSettingsDir = FString(ApplictionSettingsPath).Replace(TEXT("\\"), TEXT("/")) + TEXT("/Epic/"); } return *WindowsApplicationSettingsDir; } diff --git a/Engine/Source/Runtime/Core/Private/iOS/IOSMallocZone.cpp b/Engine/Source/Runtime/Core/Private/iOS/IOSMallocZone.cpp new file mode 100644 index 000000000000..88cdce336131 --- /dev/null +++ b/Engine/Source/Runtime/Core/Private/iOS/IOSMallocZone.cpp @@ -0,0 +1,192 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "IOSMallocZone.h" +#include "IOSPlatformMisc.h" +#include "IOSPlatformCrashContext.h" +#include "HAL/PlatformTLS.h" +#include "HAL/PlatformProcess.h" +#include + +FIOSMallocZone::FIOSMallocZone( uint64 const InitialSize ) +: MemoryZone( malloc_create_zone( InitialSize, 0 ) ) +{ +} + +FIOSMallocZone::~FIOSMallocZone() +{ + if ( MemoryZone ) + { + malloc_destroy_zone( MemoryZone ); + } +} + +void* FIOSMallocZone::Malloc( SIZE_T Size, uint32 Alignment ) +{ + check( MemoryZone ); + void* Result = malloc_zone_malloc( MemoryZone, Size ); + return Result; +} + +void* FIOSMallocZone::Realloc( void* Ptr, SIZE_T NewSize, uint32 Alignment ) +{ + check( MemoryZone ); + void* Result = malloc_zone_realloc( MemoryZone, Ptr, NewSize ); + return Result; +} + +void FIOSMallocZone::Free( void* Ptr ) +{ + check( MemoryZone ); + malloc_zone_free( MemoryZone, Ptr ); +} + +bool FIOSMallocZone::GetAllocationSize(void *Original, SIZE_T &SizeOut) +{ + SizeOut = malloc_size( Original ); + return SizeOut > 0; +} + +bool FIOSMallocZone::IsInternallyThreadSafe() const +{ + return true; +} + +bool FIOSMallocZone::ValidateHeap() +{ + check( MemoryZone ); + return malloc_zone_check( MemoryZone ) ; +} + +const TCHAR* FIOSMallocZone::GetDescriptiveName() +{ + return TEXT("MallocZone"); +} + +FIOSMallocCrashHandler::FIOSMallocCrashHandler( uint64 const InitialSize ) +: FIOSMallocZone( InitialSize ) +, OriginalHeap( GMalloc ) +, CrashContext( nullptr ) +, ThreadId( -1 ) +{ + check( GMalloc ); +} + +FIOSMallocCrashHandler::~FIOSMallocCrashHandler() +{ + // We crashed, so don't try and tidy the malloc zone + if ( ThreadId != -1 ) + { + MemoryZone = nullptr; + } +} + +void FIOSMallocCrashHandler::Enable( FIOSCrashContext* Context, uint32 CrashedThreadId ) +{ + check(Context); + CrashContext = Context; + ThreadId = CrashedThreadId; + OriginalHeap = GMalloc; + if (PLATFORM_USES_FIXED_GMalloc_CLASS && GFixedMallocLocationPtr) + { + *GFixedMallocLocationPtr = nullptr; // this disables any fast-path inline allocators + } + GMalloc = this; +} + +void* FIOSMallocCrashHandler::Malloc( SIZE_T Size, uint32 Alignment ) +{ + void* Result = nullptr; + if ( IsOnCrashedThread() ) + { + Result = FIOSMallocZone::Malloc( Size, Alignment ); + if( !Result ) + { + check(CrashContext); + CrashContext->GenerateCrashInfo(); + } + } + return Result; +} + +void* FIOSMallocCrashHandler::Realloc( void* Ptr, SIZE_T NewSize, uint32 Alignment ) +{ + void* Result = nullptr; + if ( IsOnCrashedThread() ) + { + if ( Ptr == nullptr || MemoryZone->size( MemoryZone, Ptr ) > 0 ) + { + Result = FIOSMallocZone::Realloc( Ptr, NewSize, Alignment ); + if( NewSize && !Result ) + { + check(CrashContext); + CrashContext->GenerateCrashInfo(); + } + } + else if ( NewSize ) + { + if ( FCStringWide::Strcmp( OriginalHeap->GetDescriptiveName(), TEXT("ANSI") ) != 0 ) + { + SIZE_T OldSize = 0; + if ( OriginalHeap->GetAllocationSize( Ptr, OldSize ) ) + { + Result = Malloc( NewSize, Alignment ); + if ( Result ) + { + FMemory::Memcpy( Result, Ptr, FMath::Min( NewSize, OldSize ) ); + } + else + { + check(CrashContext); + CrashContext->GenerateCrashInfo(); + } + } + } + else // Can't safely handle this, so just report & exit + { + check(CrashContext); + CrashContext->GenerateCrashInfo(); + } + } + } + return Result; +} + +void FIOSMallocCrashHandler::Free( void* Ptr ) +{ + if ( IsOnCrashedThread() && Ptr && MemoryZone->size( MemoryZone, Ptr ) > 0 ) + { + FIOSMallocZone::Free( Ptr ); + } +} + +bool FIOSMallocCrashHandler::GetAllocationSize( void *Original, SIZE_T &SizeOut ) +{ + SizeOut = 0; + if ( IsOnCrashedThread() && Original ) + { + SizeOut = MemoryZone->size( MemoryZone, Original ); + } + return SizeOut > 0; +} + +const TCHAR* FIOSMallocCrashHandler::GetDescriptiveName() +{ + return TEXT("MallocCrashHandler"); +} + +bool FIOSMallocCrashHandler::IsOnCrashedThread( void ) +{ + // Suspend threads other than the crashed one to prevent serious memory errors. + // Only the crashed thread can do anything meaningful from here anyway. + if ( ThreadId == FPlatformTLS::GetCurrentThreadId() ) + { + return true; + } + else + { + do { + FPlatformProcess::SleepInfinite(); + } while (true); + return false; + } +} diff --git a/Engine/Source/Runtime/Core/Public/Android/AndroidApplication.h b/Engine/Source/Runtime/Core/Public/Android/AndroidApplication.h index 55134b1710c4..6f2b2e98f535 100644 --- a/Engine/Source/Runtime/Core/Public/Android/AndroidApplication.h +++ b/Engine/Source/Runtime/Core/Public/Android/AndroidApplication.h @@ -47,6 +47,7 @@ public: static void DetachJavaEnv(); static bool CheckJavaException(); + static FAndroidApplication* Get() { return _application; } public: diff --git a/Engine/Source/Runtime/Core/Public/Android/AndroidAtomics.h b/Engine/Source/Runtime/Core/Public/Android/AndroidAtomics.h index 55de9fa588cd..e2ddaba0b19e 100644 --- a/Engine/Source/Runtime/Core/Public/Android/AndroidAtomics.h +++ b/Engine/Source/Runtime/Core/Public/Android/AndroidAtomics.h @@ -65,12 +65,15 @@ struct CORE_API FAndroidPlatformAtomics return __sync_val_compare_and_swap(Dest, Comperand, Exchange); } -#if PLATFORM_64BITS static FORCEINLINE int64 InterlockedCompareExchange( volatile int64* Dest, int64 Exchange, int64 Comperand ) { return __sync_val_compare_and_swap(Dest, Comperand, Exchange); } -#endif + + static FORCEINLINE int64 AtomicRead64(volatile const int64* Src) + { + return InterlockedCompareExchange((volatile int64*)Src, 0, 0); + } static FORCEINLINE void* InterlockedCompareExchangePointer( void** Dest, void* Exchange, void* Comperand ) { diff --git a/Engine/Source/Runtime/Core/Public/Android/AndroidCriticalSection.h b/Engine/Source/Runtime/Core/Public/Android/AndroidCriticalSection.h index 4029d1ab0bd3..c263da872f38 100644 --- a/Engine/Source/Runtime/Core/Public/Android/AndroidCriticalSection.h +++ b/Engine/Source/Runtime/Core/Public/Android/AndroidCriticalSection.h @@ -4,6 +4,8 @@ #include "PThreadCriticalSection.h" #include "GenericPlatform/GenericPlatformCriticalSection.h" +#include "PThreadRWLock.h" typedef FPThreadsCriticalSection FCriticalSection; typedef FSystemWideCriticalSectionNotImplemented FSystemWideCriticalSection; +typedef FPThreadsRWLock FRWLock; diff --git a/Engine/Source/Runtime/Core/Public/Android/AndroidMisc.h b/Engine/Source/Runtime/Core/Public/Android/AndroidMisc.h index 587743768403..8956c644c027 100644 --- a/Engine/Source/Runtime/Core/Public/Android/AndroidMisc.h +++ b/Engine/Source/Runtime/Core/Public/Android/AndroidMisc.h @@ -27,7 +27,8 @@ struct CORE_API FAndroidMisc : public FGenericPlatformMisc static void LocalPrint(const TCHAR *Message); static void PlatformPreInit(); static void PlatformInit(); - static void PlatformPostInit(bool ShowSplashScreen); + static void PlatformPostInit(); + static void PlatformHandleSplashScreen(bool ShowSplashScreen); static void GetEnvironmentVariable(const TCHAR* VariableName, TCHAR* Result, int32 ResultLength); static void* GetHardwareWindow(); static void SetHardwareWindow(void* InWindow); @@ -40,6 +41,9 @@ struct CORE_API FAndroidMisc : public FGenericPlatformMisc static bool HasPlatformFeature(const TCHAR* FeatureName); static bool ShouldDisablePluginAtRuntime(const FString& PluginName); static bool SupportsES30(); + static EScreenPhysicalAccuracy ComputePhysicalScreenDensity(int32& OutScreenDensity); + +public: static bool AllowThreadHeartBeat() { @@ -90,14 +94,20 @@ struct CORE_API FAndroidMisc : public FGenericPlatformMisc // Returns current volume, 0-15 static int GetVolumeState(double* OutTimeOfChangeInSec = nullptr); static const TCHAR* GamePersistentDownloadDir(); + static FString GetDeviceId(); + static FString GetLoginId(); + static FString GetUniqueAdvertisingId(); + static FString GetCPUVendor(); + static FString GetCPUBrand(); + static void GetOSVersions(FString& out_OSVersionLabel, FString& out_OSSubVersionLabel); enum EBatteryState { + BATTERY_STATE_UNKNOWN = 1, BATTERY_STATE_CHARGING, BATTERY_STATE_DISCHARGING, - BATTERY_STATE_FULL, BATTERY_STATE_NOT_CHARGING, - BATTERY_STATE_UNKNOWN + BATTERY_STATE_FULL }; struct FBatteryState { @@ -107,9 +117,14 @@ struct CORE_API FAndroidMisc : public FGenericPlatformMisc }; static FBatteryState GetBatteryState(); + static int GetBatteryLevel(); + static bool IsRunningOnBattery(); static bool AreHeadPhonesPluggedIn(); static bool HasActiveWiFiConnection(); + static void RegisterForRemoteNotifications(); + static void UnregisterForRemoteNotifications(); + /** @return Memory representing a true type or open type font provided by the platform as a default font for unreal to consume; empty array if the default font failed to load. */ static TArray GetSystemFontBytes(); @@ -134,6 +149,8 @@ struct CORE_API FAndroidMisc : public FGenericPlatformMisc typedef TFunction ReInitWindowCallbackType; static ReInitWindowCallbackType GetOnReInitWindowCallback(); static void SetOnReInitWindowCallback(ReInitWindowCallbackType InOnReInitWindowCallback); + static FString GetOSVersion(); + static float GetWindowUpscaleFactor(); #if !UE_BUILD_SHIPPING static bool IsDebuggerPresent(); diff --git a/Engine/Source/Runtime/Core/Public/Android/AndroidPlatform.h b/Engine/Source/Runtime/Core/Public/Android/AndroidPlatform.h index 9181207a4d43..f3363d8cfdde 100644 --- a/Engine/Source/Runtime/Core/Public/Android/AndroidPlatform.h +++ b/Engine/Source/Runtime/Core/Public/Android/AndroidPlatform.h @@ -46,6 +46,9 @@ typedef FAndroidTypes FPlatformTypes; #define PLATFORM_HAS_TOUCH_MAIN_SCREEN 1 #define PLATFORM_SUPPORTS_STACK_SYMBOLS 1 #define PLATFORM_NUM_AUDIODECOMPRESSION_PRECACHE_BUFFERS 1 +#define PLATFORM_UI_HAS_MOBILE_SCROLLBARS 1 +#define PLATFORM_UI_NEEDS_TOOLTIPS 0 +#define PLATFORM_UI_NEEDS_FOCUS_OUTLINES 0 // Function type macros. #define VARARGS /* Functions with variable arguments */ diff --git a/Engine/Source/Runtime/Core/Public/Android/AndroidPlatformCompilerPreSetup.h b/Engine/Source/Runtime/Core/Public/Android/AndroidPlatformCompilerPreSetup.h index d9134b79261d..75757ce371ee 100644 --- a/Engine/Source/Runtime/Core/Public/Android/AndroidPlatformCompilerPreSetup.h +++ b/Engine/Source/Runtime/Core/Public/Android/AndroidPlatformCompilerPreSetup.h @@ -63,6 +63,17 @@ _Pragma("clang diagnostic pop") #endif // PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS +#ifndef PRAGMA_DISABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS + #define PRAGMA_DISABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wdelete-non-virtual-dtor\"") +#endif // PRAGMA_DISABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS + +#ifndef PRAGMA_ENABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS + #define PRAGMA_ENABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS \ + _Pragma("clang diagnostic pop") +#endif // PRAGMA_ENABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS + #ifndef PRAGMA_POP #define PRAGMA_POP \ _Pragma("clang diagnostic pop") @@ -72,11 +83,13 @@ #ifndef THIRD_PARTY_INCLUDES_START #define THIRD_PARTY_INCLUDES_START \ PRAGMA_DISABLE_SHADOW_VARIABLE_WARNINGS \ - PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS + PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS \ + PRAGMA_DISABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS #endif #ifndef THIRD_PARTY_INCLUDES_END #define THIRD_PARTY_INCLUDES_END \ + PRAGMA_ENABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS \ PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS \ PRAGMA_ENABLE_SHADOW_VARIABLE_WARNINGS #endif diff --git a/Engine/Source/Runtime/Core/Public/Apple/ApplePlatformAtomics.h b/Engine/Source/Runtime/Core/Public/Apple/ApplePlatformAtomics.h index 4f46375f12b5..8b7d361ebddf 100644 --- a/Engine/Source/Runtime/Core/Public/Apple/ApplePlatformAtomics.h +++ b/Engine/Source/Runtime/Core/Public/Apple/ApplePlatformAtomics.h @@ -7,140 +7,15 @@ #pragma once #include "GenericPlatform/GenericPlatformAtomics.h" #include "CoreTypes.h" -#if PLATFORM_MAC -#include "Mac/MacSystemIncludes.h" -#elif PLATFORM_IOS -#include "IOS/IOSSystemIncludes.h" -#endif +#include "Clang/ClangPlatformAtomics.h" PRAGMA_DISABLE_DEPRECATION_WARNINGS /** * Apple implementation of the Atomics OS functions **/ -struct CORE_API FApplePlatformAtomics : public FGenericPlatformAtomics +struct CORE_API FApplePlatformAtomics : public FClangPlatformAtomics { - static FORCEINLINE int32 InterlockedIncrement( volatile int32* Value ) - { - return (int32)OSAtomicIncrement32Barrier((int32_t*)Value); - } - - static FORCEINLINE int64 InterlockedIncrement( volatile int64* Value ) - { - return (int64)OSAtomicIncrement64Barrier((int64_t*)Value); - } - - static FORCEINLINE int32 InterlockedDecrement( volatile int32* Value ) - { - return (int32)OSAtomicDecrement32Barrier((int32_t*)Value); - } - - static FORCEINLINE int64 InterlockedDecrement( volatile int64* Value ) - { - return (int64)OSAtomicDecrement64Barrier((int64_t*)Value); - } - - static FORCEINLINE int32 InterlockedAdd( volatile int32* Value, int32 Amount ) - { - return OSAtomicAdd32Barrier((int32_t)Amount, (int32_t*)Value) - Amount; - } - - static FORCEINLINE int64 InterlockedAdd( volatile int64* Value, int64 Amount ) - { - return OSAtomicAdd64Barrier((int64_t)Amount, (int64_t*)Value) - Amount; - } - - static FORCEINLINE int32 InterlockedExchange( volatile int32* Value, int32 Exchange ) - { - int32 RetVal; - - do - { - RetVal = *Value; - } - while (!OSAtomicCompareAndSwap32Barrier(RetVal, Exchange, (int32_t*) Value)); - - return RetVal; - } - - static FORCEINLINE int64 InterlockedExchange( volatile int64* Value, int64 Exchange ) - { - int64 RetVal; - - do - { - RetVal = *Value; - } - while (!OSAtomicCompareAndSwap64Barrier(RetVal, Exchange, (int64_t*) Value)); - - return RetVal; - } - - static FORCEINLINE void* InterlockedExchangePtr( void** Dest, void* Exchange ) - { - void* RetVal; - - do - { - RetVal = *Dest; - } - while (!OSAtomicCompareAndSwapPtrBarrier(RetVal, Exchange, Dest)); - - return RetVal; - } - - static FORCEINLINE int32 InterlockedCompareExchange(volatile int32* Dest, int32 Exchange, int32 Comparand) - { - int32 RetVal; - - do - { - if (OSAtomicCompareAndSwap32Barrier(Comparand, Exchange, (int32_t*) Dest)) - { - return Comparand; - } - RetVal = *Dest; - } - while (RetVal == Comparand); - - return RetVal; - } - -#if PLATFORM_64BITS - static FORCEINLINE int64 InterlockedCompareExchange( volatile int64* Dest, int64 Exchange, int64 Comparand ) - { - int64 RetVal; - - do - { - if (OSAtomicCompareAndSwap64Barrier(Comparand, Exchange, (int64_t*) Dest)) - { - return Comparand; - } - RetVal = *Dest; - } - while (RetVal == Comparand); - - return RetVal; - } -#endif - - static FORCEINLINE void* InterlockedCompareExchangePointer( void** Dest, void* Exchange, void* Comparand ) - { - void *RetVal; - - do - { - if (OSAtomicCompareAndSwapPtrBarrier(Comparand, Exchange, Dest)) - { - return Comparand; - } - RetVal = *Dest; - } - while (RetVal == Comparand); - - return RetVal; - } }; PRAGMA_ENABLE_DEPRECATION_WARNINGS diff --git a/Engine/Source/Runtime/Core/Public/Apple/ApplePlatformSymbolication.h b/Engine/Source/Runtime/Core/Public/Apple/ApplePlatformSymbolication.h index cbe45de0b978..8ee3dd5f9d8f 100644 --- a/Engine/Source/Runtime/Core/Public/Apple/ApplePlatformSymbolication.h +++ b/Engine/Source/Runtime/Core/Public/Apple/ApplePlatformSymbolication.h @@ -9,6 +9,7 @@ #include "GenericPlatformSymbolication.h" #include "ApplePlatformStackWalk.h" #include "Serialization/Archive.h" +#include "SharedPointer.h" /** * Opaque symbol cache for improved symbolisation performance. @@ -29,7 +30,7 @@ struct FApplePlatformSymbolDatabase ~FApplePlatformSymbolDatabase(); FApplePlatformSymbolDatabase& operator=(FApplePlatformSymbolDatabase const& Other); - FGenericPlatformSymbolDatabase GenericDB; + TSharedPtr GenericDB; FApplePlatformSymbolCache AppleDB; }; @@ -47,7 +48,7 @@ struct FApplePlatformSymbolDatabaseKeyFuncs */ static FORCEINLINE KeyInitType GetSetKey(ElementInitType Element) { - return Element.GenericDB.Signature; + return Element.GenericDB->Signature; } /** @@ -75,7 +76,7 @@ struct CORE_API FApplePlatformSymbolication static void EnableCoreSymbolication(bool const bEnable); static bool LoadSymbolDatabaseForBinary(FString SourceFolder, FString Binary, FString BinarySignature, FApplePlatformSymbolDatabase& OutDatabase); - static bool SaveSymbolDatabaseForBinary(FString TargetFolder, FString Name, FApplePlatformSymbolDatabase& Database); + static bool SaveSymbolDatabaseForBinary(FString TargetFolder, FString Name, FString BinarySignature, FApplePlatformSymbolDatabase& Database); static bool SymbolInfoForStrippedSymbol(FApplePlatformSymbolDatabase const& Database, uint64 ProgramCounter, uint64 ModuleOffset, FString ModuleSignature, FProgramCounterSymbolInfo& Info); diff --git a/Engine/Source/Runtime/Core/Public/Async/AsyncFileHandle.h b/Engine/Source/Runtime/Core/Public/Async/AsyncFileHandle.h index 70beea8fd4eb..edfc0d3f6ce9 100644 --- a/Engine/Source/Runtime/Core/Public/Async/AsyncFileHandle.h +++ b/Engine/Source/Runtime/Core/Public/Async/AsyncFileHandle.h @@ -188,4 +188,8 @@ public: * @return A request for the read. This is owned by the caller and must be deleted by the caller. **/ virtual IAsyncReadRequest* ReadRequest(int64 Offset, int64 BytesToRead, EAsyncIOPriority Priority = AIOP_Normal, FAsyncFileCallBack* CompleteCallback = nullptr, uint8* UserSuppliedMemory = nullptr) = 0; + + // Non-copyable + IAsyncReadFileHandle(const IAsyncReadFileHandle&) = delete; + IAsyncReadFileHandle& operator=(const IAsyncReadFileHandle&) = delete; }; diff --git a/Engine/Source/Runtime/Core/Public/Async/Future.h b/Engine/Source/Runtime/Core/Public/Async/Future.h index 548a94dba661..227d7835780a 100644 --- a/Engine/Source/Runtime/Core/Public/Async/Future.h +++ b/Engine/Source/Runtime/Core/Public/Async/Future.h @@ -894,7 +894,7 @@ public: BaseType::operator=(MoveTemp(Other)); FutureRetrieved = MoveTemp(Other.FutureRetrieved); - return this; + return *this; } public: diff --git a/Engine/Source/Runtime/Core/Public/Async/TaskGraphInterfaces.h b/Engine/Source/Runtime/Core/Public/Async/TaskGraphInterfaces.h index 1fcbbb606549..c1e32e2668b5 100644 --- a/Engine/Source/Runtime/Core/Public/Async/TaskGraphInterfaces.h +++ b/Engine/Source/Runtime/Core/Public/Async/TaskGraphInterfaces.h @@ -8,7 +8,6 @@ #include "CoreTypes.h" #include "Misc/AssertionMacros.h" -#include "Templates/AlignOf.h" #include "Containers/ContainerAllocationPolicies.h" #include "Containers/Array.h" #include "Containers/UnrealString.h" @@ -27,6 +26,10 @@ #error "STATS must be defined as either zero or one." #endif + + + + // what level of checking to perform...normally checkSlow but could be ensure or check #define checkThreadGraph checkSlow @@ -362,18 +365,11 @@ public: * Tasks go through a very specific life stage progression, and this is verified. **/ -#define USE_VIRTUAL_BYPASS USE_NEW_LOCK_FREE_LISTS class FBaseGraphTask { public: -#if USE_VIRTUAL_BYPASS - typedef void (*TExecuteTask)(FBaseGraphTask*, TArray& NewTasks, ENamedThreads::Type CurrentThread); -#endif -#if USE_NEW_LOCK_FREE_LISTS - FBaseGraphTask* LockFreePointerQueueNext; -#endif // Allocator for small tasks. enum { @@ -386,18 +382,10 @@ protected: * Constructor * @param InNumberOfPrerequistitesOutstanding; the number of prerequisites outstanding. We actually add one to this to prevent the task from firing while we are setting up the task **/ - FBaseGraphTask( -#if USE_VIRTUAL_BYPASS - TExecuteTask InExecuteTaskPtr, -#endif - int32 InNumberOfPrerequistitesOutstanding - ) + FBaseGraphTask(int32 InNumberOfPrerequistitesOutstanding) : ThreadToExecuteOn(ENamedThreads::AnyThread) , NumberOfPrerequistitesOutstanding(InNumberOfPrerequistitesOutstanding + 1) // + 1 is not a prerequisite, it is a lock to prevent it from executing while it is getting prerequisites, one it is safe to execute, call PrerequisitesComplete { -#if USE_VIRTUAL_BYPASS - ExecuteTaskPtr = InExecuteTaskPtr; -#endif checkThreadGraph(LifeStage.Increment() == int32(LS_Contructed)); } /** @@ -425,12 +413,7 @@ protected: } } /** destructor, just checks the life stage **/ -#if USE_VIRTUAL_BYPASS - FORCEINLINE -#else - virtual -#endif - ~FBaseGraphTask() + virtual ~FBaseGraphTask() { checkThreadGraph(LifeStage.Increment() == int32(LS_Deconstucted)); } @@ -468,9 +451,7 @@ private: * Virtual call to actually execute the task. This should also call the destructor and free any memory. * @param CurrentThread; provides the index of the thread we are running on. This is handy for submitting new taks. **/ -#if !USE_VIRTUAL_BYPASS virtual void ExecuteTask(TArray& NewTasks, ENamedThreads::Type CurrentThread)=0; -#endif // API called from other parts of the system @@ -482,11 +463,7 @@ private: FORCEINLINE void Execute(TArray& NewTasks, ENamedThreads::Type CurrentThread) { checkThreadGraph(LifeStage.Increment() == int32(LS_Executing)); -#if USE_VIRTUAL_BYPASS - ExecuteTaskPtr(this, NewTasks, CurrentThread); -#else ExecuteTask(NewTasks, CurrentThread); -#endif } // Internal Use @@ -501,9 +478,6 @@ private: FTaskGraphInterface::Get().QueueTask(this, ThreadToExecuteOn, CurrentThreadIfKnown); } -#if USE_VIRTUAL_BYPASS - TExecuteTask ExecuteTaskPtr; -#endif /** Thread to execute on, can be ENamedThreads::AnyThread to execute on any unnamed thread **/ ENamedThreads::Type ThreadToExecuteOn; /** Number of prerequisites outstanding. When this drops to zero, the thread is queued for execution. **/ @@ -551,12 +525,6 @@ public: **/ bool AddSubsequent(class FBaseGraphTask* Task) { -#if USE_NEW_LOCK_FREE_LISTS - if (bComplete) - { - return false; - } -#endif return SubsequentList.PushIfNotClosed(Task); } @@ -592,18 +560,9 @@ public: **/ bool IsComplete() const { -#if USE_NEW_LOCK_FREE_LISTS - FPlatformMisc::MemoryBarrier(); - return bComplete; -#else return SubsequentList.IsClosed(); -#endif } -#if USE_NEW_LOCK_FREE_LISTS - void* GetInlineStorage(); - static CORE_API FGraphEvent* GetBundle(int32 NumBundle); -#endif private: friend class TRefCountPtr; @@ -620,11 +579,6 @@ private: **/ friend struct FGraphEventAndSmallTaskStorage; FGraphEvent(bool bInInline = false) -#if USE_NEW_LOCK_FREE_LISTS - : bComplete(false) - , bInline(bInInline) - , LockFreePointerQueueNext(nullptr) -#endif { } @@ -670,43 +624,8 @@ private: FGraphEventArray EventsToWaitFor; /** Number of outstanding references to this graph event **/ FThreadSafeCounter ReferenceCount; -#if USE_NEW_LOCK_FREE_LISTS - void Reset(); - bool bComplete; - bool bInline; -public: - void *LockFreePointerQueueNext; -#endif }; -#if USE_NEW_LOCK_FREE_LISTS -struct FGraphEventAndSmallTaskStorage : public FGraphEvent -{ - enum - { - StorageAlignment = 16, - StorageSize = 256 - StorageAlignment * ((sizeof(FGraphEvent) + StorageAlignment - 1) / StorageAlignment) - }; - TAlignedBytes TaskStorage; - - FGraphEventAndSmallTaskStorage() - : FGraphEvent(true) - { - } - - static CORE_API FGraphEventAndSmallTaskStorage* GetBundle(int32 NumBundle); -}; - -FORCEINLINE void* FGraphEvent::GetInlineStorage() -{ - if (!bInline) - { - return nullptr; - } - return &(((FGraphEventAndSmallTaskStorage *)this)->TaskStorage); -} - -#endif /** @@ -814,16 +733,6 @@ public: static FConstructor CreateTask(const FGraphEventArray* Prerequisites = NULL, ENamedThreads::Type CurrentThreadIfKnown = ENamedThreads::AnyThread) { int32 NumPrereq = Prerequisites ? Prerequisites->Num() : 0; -#if USE_NEW_LOCK_FREE_LISTS - if (sizeof(TGraphTask) <= FGraphEventAndSmallTaskStorage::StorageSize && ALIGNOF(TGraphTask) <= FGraphEventAndSmallTaskStorage::StorageAlignment && TTask::GetSubsequentsMode() != ESubsequentsMode::FireAndForget) - { - FGraphEventRef Event(FGraphEvent::CreateGraphEventWithInlineStorage()); - void *Mem = Event->GetInlineStorage(); - checkThreadGraph(Mem); - return FConstructor(new (Mem) TGraphTask(Event, NumPrereq), Prerequisites, CurrentThreadIfKnown); - } - else -#endif if (sizeof(TGraphTask) <= FBaseGraphTask::SMALL_TASK_SIZE) { void *Mem = FBaseGraphTask::GetSmallTaskAllocator().Allocate(); @@ -856,15 +765,7 @@ private: * Dispatches the subsequents. * Destroys myself. **/ -#if USE_VIRTUAL_BYPASS - static void ExecuteTask(FBaseGraphTask *This, TArray& NewTasks, ENamedThreads::Type CurrentThread) - { - ((TGraphTask*)This)->ExecuteTaskInner(NewTasks, CurrentThread); - } - FORCEINLINE void ExecuteTaskInner(TArray& NewTasks, ENamedThreads::Type CurrentThread) -#else virtual void ExecuteTask(TArray& NewTasks, ENamedThreads::Type CurrentThread) final override -#endif { checkThreadGraph(TaskConstructed); @@ -893,15 +794,6 @@ private: Subsequents->DispatchSubsequents(NewTasks, CurrentThread); } -#if USE_NEW_LOCK_FREE_LISTS - FGraphEventRef LocalSubsequents; // need to make sure this dies just a wee bit later, after the task is all destroyed - if (Subsequents.GetReference() && Subsequents->GetInlineStorage() == this) - { - LocalSubsequents.Swap(Subsequents); - this->TGraphTask::~TGraphTask(); // this will free the ref, if that is the last one it will recycle - } - else -#endif if (sizeof(TGraphTask) <= FBaseGraphTask::SMALL_TASK_SIZE) { this->TGraphTask::~TGraphTask(); @@ -921,11 +813,7 @@ private: * @param NumberOfPrerequistitesOutstanding the number of prerequisites this task will have when it is built. **/ TGraphTask(FGraphEventRef InSubsequents, int32 NumberOfPrerequistitesOutstanding) - : FBaseGraphTask( -#if USE_VIRTUAL_BYPASS - &ExecuteTask, -#endif - NumberOfPrerequistitesOutstanding) + : FBaseGraphTask(NumberOfPrerequistitesOutstanding) , TaskConstructed(false) { Subsequents.Swap(InSubsequents); @@ -934,13 +822,7 @@ private: /** * Private destructor, just checks that the task appears to be completed **/ -#if !USE_VIRTUAL_BYPASS - virtual -#endif - ~TGraphTask() -#if !USE_VIRTUAL_BYPASS - final override -#endif + virtual ~TGraphTask() final override { checkThreadGraph(!TaskConstructed); } @@ -1030,7 +912,7 @@ private: } /** An aligned bit of storage to hold the embedded task **/ - TAlignedBytes TaskStorage; + TAlignedBytes TaskStorage; /** Used to sanity check the state of the object **/ bool TaskConstructed; /** A reference counted pointer to the completion event which lists the tasks that have me as a prerequisite. **/ diff --git a/Engine/Source/Runtime/Core/Public/Clang/ClangPlatformAtomics.h b/Engine/Source/Runtime/Core/Public/Clang/ClangPlatformAtomics.h new file mode 100644 index 000000000000..aa0c3da6d34f --- /dev/null +++ b/Engine/Source/Runtime/Core/Public/Clang/ClangPlatformAtomics.h @@ -0,0 +1,81 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +/*============================================================================================= + ClangPlatformAtomics.h: Apple platform Atomics functions +==============================================================================================*/ + +#pragma once + +#include "GenericPlatform/GenericPlatformAtomics.h" +#include "CoreTypes.h" + +/** + * GCC/Clang implementation of the Atomics OS functions + **/ +struct CORE_API FClangPlatformAtomics : public FGenericPlatformAtomics +{ + static FORCEINLINE int32 InterlockedIncrement(volatile int32* Value) + { + return __sync_fetch_and_add(Value, 1) + 1; + } + + static FORCEINLINE int64 InterlockedIncrement(volatile int64* Value) + { + return __sync_fetch_and_add(Value, 1) + 1; + } + + static FORCEINLINE int32 InterlockedDecrement(volatile int32* Value) + { + return __sync_fetch_and_sub(Value, 1) - 1; + } + + static FORCEINLINE int64 InterlockedDecrement(volatile int64* Value) + { + return __sync_fetch_and_sub(Value, 1) - 1; + } + + static FORCEINLINE int32 InterlockedAdd(volatile int32* Value, int32 Amount) + { + return __sync_fetch_and_add(Value, Amount); + } + + static FORCEINLINE int64 InterlockedAdd(volatile int64* Value, int64 Amount) + { + return __sync_fetch_and_add(Value, Amount); + } + + static FORCEINLINE int32 InterlockedExchange(volatile int32* Value, int32 Exchange) + { + return __sync_lock_test_and_set(Value, Exchange); + } + + static FORCEINLINE int64 InterlockedExchange(volatile int64* Value, int64 Exchange) + { + return __sync_lock_test_and_set(Value, Exchange); + } + + static FORCEINLINE void* InterlockedExchangePtr(void** Dest, void* Exchange) + { + return __sync_lock_test_and_set(Dest, Exchange); + } + + static FORCEINLINE int32 InterlockedCompareExchange(volatile int32* Dest, int32 Exchange, int32 Comperand) + { + return __sync_val_compare_and_swap(Dest, Comperand, Exchange); + } + + static FORCEINLINE int64 InterlockedCompareExchange(volatile int64* Dest, int64 Exchange, int64 Comperand) + { + return __sync_val_compare_and_swap(Dest, Comperand, Exchange); + } + static FORCEINLINE int64 AtomicRead64(volatile const int64* Src) + { + return InterlockedCompareExchange((volatile int64*)Src, 0, 0); + } + + static FORCEINLINE void* InterlockedCompareExchangePointer(void** Dest, void* Exchange, void* Comperand) + { + return __sync_val_compare_and_swap(Dest, Comperand, Exchange); + } +}; + diff --git a/Engine/Source/Runtime/Core/Public/Containers/Algo/BinarySearch.h b/Engine/Source/Runtime/Core/Public/Containers/Algo/BinarySearch.h new file mode 100644 index 000000000000..8579100498f0 --- /dev/null +++ b/Engine/Source/Runtime/Core/Public/Containers/Algo/BinarySearch.h @@ -0,0 +1,222 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "Templates/IdentityFunctor.h" +#include "Templates/Invoke.h" +#include "Templates/Less.h" + +namespace AlgoImpl +{ + /** + * Performs binary search, resulting in position of the first element >= Value + * + * @param First Pointer to array + * @param Num Number of elements in array + * @param Value Value to look for + * @param Projection Called on values in array to get type that can be compared to Value + * @param SortPredicate Predicate for sort comparison + * + * @returns Position of the first element >= Value, may be == Num + */ + template + FORCEINLINE SIZE_T LowerBoundInternal(RangeValueType* First, const SIZE_T Num, const PredicateValueType& Value, ProjectionType Projection, SortPredicateType SortPredicate) + { + // Current start of sequence to check + SIZE_T Start = 0; + // Size of sequence to check + SIZE_T Size = Num; + + // With this method, if Size is even it will do one more comparison than necessary, but because Size can be predicted by the CPU it is faster in practice + while (Size > 0) + { + const SIZE_T LeftoverSize = Size % 2; + Size = Size / 2; + + const SIZE_T CheckIndex = Start + Size; + const SIZE_T StartIfLess = CheckIndex + LeftoverSize; + + auto&& CheckValue = Invoke(Projection, First[CheckIndex]); + Start = SortPredicate(CheckValue, Value) ? StartIfLess : Start; + } + return Start; + } + + /** + * Performs binary search, resulting in position of the first element that is larger than the given value + * + * @param First Pointer to array + * @param Num Number of elements in array + * @param Value Value to look for + * @param SortPredicate Predicate for sort comparison + * + * @returns Position of the first element > Value, may be == Num + */ + template + FORCEINLINE SIZE_T UpperBoundInternal(RangeValueType* First, const SIZE_T Num, const PredicateValueType& Value, ProjectionType Projection, SortPredicateType SortPredicate) + { + // Current start of sequence to check + SIZE_T Start = 0; + // Size of sequence to check + SIZE_T Size = Num; + + // With this method, if Size is even it will do one more comparison than necessary, but because Size can be predicted by the CPU it is faster in practice + while (Size > 0) + { + const SIZE_T LeftoverSize = Size % 2; + Size = Size / 2; + + const SIZE_T CheckIndex = Start + Size; + const SIZE_T StartIfLess = CheckIndex + LeftoverSize; + + auto&& CheckValue = Invoke(Projection, First[CheckIndex]); + Start = !SortPredicate(Value, CheckValue) ? StartIfLess : Start; + } + + return Start; + } +} + +namespace Algo +{ + /** + * Performs binary search, resulting in position of the first element >= Value using predicate + * + * @param Range Range to search through, must be already sorted by SortPredicate + * @param Value Value to look for + * @param SortPredicate Predicate for sort comparison, defaults to < + * + * @returns Position of the first element >= Value, may be position after last element in range + */ + template + FORCEINLINE int32 LowerBound(RangeType& Range, const ValueType& Value, SortPredicateType SortPredicate) + { + return AlgoImpl::LowerBoundInternal(GetData(Range), GetNum(Range), Value, FIdentityFunctor(), SortPredicate); + } + template + FORCEINLINE int32 LowerBound(RangeType& Range, const ValueType& Value) + { + return AlgoImpl::LowerBoundInternal(GetData(Range), GetNum(Range), Value, FIdentityFunctor(), TLess<>()); + } + + /** + * Performs binary search, resulting in position of the first element with projected value >= Value using predicate + * + * @param Range Range to search through, must be already sorted by SortPredicate + * @param Value Value to look for + * @param Projection Functor or data member pointer, called via Invoke to compare to Value + * @param SortPredicate Predicate for sort comparison, defaults to < + * + * @returns Position of the first element >= Value, may be position after last element in range + */ + template + FORCEINLINE int32 LowerBoundBy(RangeType& Range, const ValueType& Value, ProjectionType Projection, SortPredicateType SortPredicate) + { + return AlgoImpl::LowerBoundInternal(GetData(Range), GetNum(Range), Value, Projection, SortPredicate); + } + template + FORCEINLINE int32 LowerBoundBy(RangeType& Range, const ValueType& Value, ProjectionType Projection) + { + return AlgoImpl::LowerBoundInternal(GetData(Range), GetNum(Range), Value, Projection, TLess<>()); + } + + /** + * Performs binary search, resulting in position of the first element > Value using predicate + * + * @param Range Range to search through, must be already sorted by SortPredicate + * @param Value Value to look for + * @param SortPredicate Predicate for sort comparison, defaults to < + * + * @returns Position of the first element > Value, may be past end of range + */ + template + FORCEINLINE int32 UpperBound(RangeType& Range, const ValueType& Value, SortPredicateType SortPredicate) + { + return AlgoImpl::UpperBoundInternal(GetData(Range), GetNum(Range), Value, FIdentityFunctor(), SortPredicate); + } + template + FORCEINLINE int32 UpperBound(RangeType& Range, const ValueType& Value) + { + return AlgoImpl::UpperBoundInternal(GetData(Range), GetNum(Range), Value, FIdentityFunctor(), TLess<>()); + } + + /** + * Performs binary search, resulting in position of the first element with projected value > Value using predicate + * + * @param Range Range to search through, must be already sorted by SortPredicate + * @param Value Value to look for + * @param Projection Functor or data member pointer, called via Invoke to compare to Value + * @param SortPredicate Predicate for sort comparison, defaults to < + * + * @returns Position of the first element > Value, may be past end of range + */ + template + FORCEINLINE int32 UpperBoundBy(RangeType& Range, const ValueType& Value, ProjectionType Projection, SortPredicateType SortPredicate) + { + return AlgoImpl::UpperBoundInternal(GetData(Range), GetNum(Range), Value, Projection, SortPredicate); + } + template + FORCEINLINE int32 UpperBoundBy(RangeType& Range, const ValueType& Value, ProjectionType Projection) + { + return AlgoImpl::UpperBoundInternal(GetData(Range), GetNum(Range), Value, Projection); + } + + /** + * Returns index to the first found element matching a value in a range, the range must be sorted by < + * + * @param Range The range to search, must be already sorted by SortPredicate + * @param Value The value to search for + * @param SortPredicate Predicate for sort comparison, defaults to < + * @return Index of found element, or INDEX_NONE + */ + template + FORCEINLINE int32 BinarySearch(RangeType& Range, const ValueType& Value, SortPredicateType SortPredicate) + { + SIZE_T CheckIndex = LowerBound(Range, Value, SortPredicate); + if (CheckIndex < GetNum(Range)) + { + auto&& CheckValue = GetData(Range)[CheckIndex]; + // Since we returned lower bound we already know Value <= CheckValue. So if Value is not < CheckValue, they must be equal + if (!SortPredicate(Value, CheckValue)) + { + return CheckIndex; + } + } + return INDEX_NONE; + } + template + FORCEINLINE int32 BinarySearch(RangeType& Range, const ValueType& Value) + { + return BinarySearch(Range, Value, TLess<>()); + } + + /** + * Returns index to the first found element with projected value matching Value in a range, the range must be sorted by predicate + * + * @param Range The range to search, must be already sorted by SortPredicate + * @param Value The value to search for + * @param Projection Functor or data member pointer, called via Invoke to compare to Value + * @param SortPredicate Predicate for sort comparison, defaults to < + * @return Index of found element, or INDEX_NONE + */ + template + FORCEINLINE int32 BinarySearchBy(RangeType& Range, const ValueType& Value, ProjectionType Projection, SortPredicateType SortPredicate) + { + SIZE_T CheckIndex = LowerBoundBy(Range, Value, Projection, SortPredicate); + if (CheckIndex < GetNum(Range)) + { + auto&& CheckValue = Invoke(Projection, GetData(Range)[CheckIndex]); + // Since we returned lower bound we already know Value <= CheckValue. So if Value is not < CheckValue, they must be equal + if (!SortPredicate(Value, CheckValue)) + { + return CheckIndex; + } + } + return INDEX_NONE; + } + template + FORCEINLINE int32 BinarySearchBy(RangeType& Range, const ValueType& Value, ProjectionType Projection) + { + return BinarySearchBy(Range, Value, Projection, TLess<>()); + } +} diff --git a/Engine/Source/Runtime/Core/Public/Containers/Algo/Find.h b/Engine/Source/Runtime/Core/Public/Containers/Algo/Find.h index 95590cd7ced3..da7461c594fc 100644 --- a/Engine/Source/Runtime/Core/Public/Containers/Algo/Find.h +++ b/Engine/Source/Runtime/Core/Public/Containers/Algo/Find.h @@ -3,16 +3,44 @@ #pragma once #include "CoreTypes.h" -#include "Traits/ElementType.h" +#include "Templates/IdentityFunctor.h" +#include "Templates/Invoke.h" +#include "Templates/UnrealTemplate.h" // For MoveTemp namespace AlgoImpl { - template - const typename TElementType::Type* FindByPredicate(const RangeType& Range, PredicateType Predicate) + template + struct TRangePointerType { - for (const auto& Elem : Range) + using Type = decltype(&*begin(DeclVal())); + }; + + template + struct TRangePointerType + { + using Type = T*; + }; + + template + typename TRangePointerType::Type FindBy(RangeType& Range, const ValueType& Value, ProjectionType Proj) + { + for (auto& Elem : Range) { - if (Predicate(Elem)) + if (Invoke(Proj, Elem) == Value) + { + return &Elem; + } + } + + return nullptr; + } + + template + typename TRangePointerType::Type FindByPredicate(RangeType& Range, PredicateType Pred) + { + for (auto& Elem : Range) + { + if (Invoke(Pred, Elem)) { return &Elem; } @@ -25,56 +53,48 @@ namespace AlgoImpl namespace Algo { /** - * Returns a pointer to the first element matching a value in a range. + * Returns a pointer to the first element in the range which is equal to the given value. * * @param Range The range to search. * @param Value The value to search for. + * * @return A pointer to the first element found, or nullptr if none was found. */ template - FORCEINLINE typename TElementType::Type* Find(RangeType& Range, const ValueType& Value) + FORCEINLINE auto Find(RangeType& Range, const ValueType& Value) + -> decltype(AlgoImpl::FindBy(Range, Value, FIdentityFunctor())) { - return const_cast::Type*>(Find(const_cast(Range), Value)); + return AlgoImpl::FindBy(Range, Value, FIdentityFunctor()); } /** - * Returns a pointer to the first element matching a value in a range. + * Returns a pointer to the first element in the range whose projection is equal to the given value. * * @param Range The range to search. * @param Value The value to search for. + * @param Proj The projection to apply to the element. + * * @return A pointer to the first element found, or nullptr if none was found. */ - template - FORCEINLINE const typename TElementType::Type* Find(const RangeType& Range, const ValueType& Value) + template + FORCEINLINE auto FindBy(RangeType& Range, const ValueType& Value, ProjectionType Proj) + -> decltype(AlgoImpl::FindBy(Range, Value, MoveTemp(Proj))) { - return AlgoImpl::FindByPredicate(Range, [&](const typename TElementType::Type& Elem){ - return Elem == Value; - }); + return AlgoImpl::FindBy(Range, Value, MoveTemp(Proj)); } /** - * Returns a pointer to the first element matching a predicate in a range. + * Returns a pointer to the first element in the range which matches the predicate. * * @param Range The range to search. * @param Pred The predicate to search for. - * @return A pointer to the first element found, or nullptr if none was found. - */ - template - FORCEINLINE typename TElementType::Type* FindByPredicate(RangeType& Range, PredicateType Pred) - { - return const_cast::Type*>(FindByPredicate(const_cast(Range), Pred)); - } - - /** - * Returns a pointer to the first element matching a predicate in a range. * - * @param Range The range to search. - * @param Pred The predicate to search for. * @return A pointer to the first element found, or nullptr if none was found. */ template - FORCEINLINE const typename TElementType::Type* FindByPredicate(const RangeType& Range, PredicateType Pred) + FORCEINLINE auto FindByPredicate(RangeType& Range, PredicateType Pred) + -> decltype(AlgoImpl::FindByPredicate(Range, MoveTemp(Pred))) { - return AlgoImpl::FindByPredicate(Range, Pred); + return AlgoImpl::FindByPredicate(Range, MoveTemp(Pred)); } } diff --git a/Engine/Source/Runtime/Core/Public/Containers/Algo/HeapSort.h b/Engine/Source/Runtime/Core/Public/Containers/Algo/HeapSort.h new file mode 100644 index 000000000000..10a5a78b1f96 --- /dev/null +++ b/Engine/Source/Runtime/Core/Public/Containers/Algo/HeapSort.h @@ -0,0 +1,59 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "Algo/Impl/BinaryHeap.h" +#include "Templates/IdentityFunctor.h" +#include "Templates/Less.h" +#include "Templates/UnrealTemplate.h" // For GetData, GetNum + +namespace Algo +{ + /** + * Performs heap sort on the elements. Assumes < operator is defined for the element type. + * + * @param Range The range to sort. + */ + template + FORCEINLINE void HeapSort(RangeType& Range) + { + AlgoImpl::HeapSortInternal(GetData(Range), GetNum(Range), FIdentityFunctor(), TLess<>()); + } + + /** + * Performs heap sort on the elements. + * + * @param Range The range to sort. + * @param Predicate A binary predicate object used to specify if one element should precede another. + */ + template + FORCEINLINE void HeapSort(RangeType& Range, PredicateType Predicate) + { + AlgoImpl::HeapSortInternal(GetData(Range), GetNum(Range), FIdentityFunctor(), MoveTemp(Predicate)); + } + + /** + * Performs heap sort on the elements. Assumes < operator is defined for the projected element type. + * + * @param Range The range to sort. + * @param Projection The projection to sort by when applied to the element. + */ + template + FORCEINLINE void HeapSortBy(RangeType& Range, ProjectionType Projection) + { + AlgoImpl::HeapSortInternal(GetData(Range), GetNum(Range), Projection, TLess<>()); + } + + /** + * Performs heap sort on the elements. + * + * @param Range The range to sort. + * @param Projection The projection to sort by when applied to the element. + * @param Predicate A binary predicate object, applied to the projection, used to specify if one element should precede another. + */ + template + FORCEINLINE void HeapSortBy(RangeType& Range, ProjectionType Projection, PredicateType Predicate) + { + AlgoImpl::HeapSortInternal(GetData(Range), GetNum(Range), MoveTemp(Projection), MoveTemp(Predicate)); + } +} \ No newline at end of file diff --git a/Engine/Source/Runtime/Core/Public/Containers/Algo/Heapify.h b/Engine/Source/Runtime/Core/Public/Containers/Algo/Heapify.h new file mode 100644 index 000000000000..1207ca0c693c --- /dev/null +++ b/Engine/Source/Runtime/Core/Public/Containers/Algo/Heapify.h @@ -0,0 +1,62 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "Algo/Impl/BinaryHeap.h" +#include "Templates/IdentityFunctor.h" +#include "Templates/Invoke.h" +#include "Templates/Less.h" +#include "Templates/UnrealTemplate.h" // For GetData, GetNum + +namespace Algo +{ + /** + * Builds an implicit min-heap from a range of elements. Assumes < operator is defined + * for the element type. + * + * @param Range The range to heapify. + */ + template + FORCEINLINE void Heapify(RangeType& Range) + { + AlgoImpl::HeapifyInternal(GetData(Range), GetNum(Range), FIdentityFunctor(), TLess<>()); + } + + /** + * Builds an implicit min-heap from a range of elements. + * + * @param Range The range to heapify. + * @param Predicate A binary predicate object used to specify if one element should precede another. + */ + template + FORCEINLINE void Heapify(RangeType& Range, PredicateType Predicate) + { + AlgoImpl::HeapifyInternal(GetData(Range), GetNum(Range), FIdentityFunctor(), Predicate); + } + + /** + * Builds an implicit min-heap from a range of elements. Assumes < operator is defined + * for the projected element type. + * + * @param Range The range to heapify. + * @param Projection The projection to apply to the elements. + */ + template + FORCEINLINE void HeapifyBy(RangeType& Range, ProjectionType Projection) + { + AlgoImpl::HeapifyInternal(GetData(Range), GetNum(Range), Projection, TLess<>()); + } + + /** + * Builds an implicit min-heap from a range of elements. + * + * @param Range The range to heapify. + * @param Projection The projection to apply to the elements. + * @param Predicate A binary predicate object used to specify if one element should precede another. + */ + template + FORCEINLINE void HeapifyBy(RangeType& Range, ProjectionType Projection, PredicateType Predicate) + { + AlgoImpl::HeapifyInternal(GetData(Range), GetNum(Range), Projection, Predicate); + } +} \ No newline at end of file diff --git a/Engine/Source/Runtime/Core/Public/Containers/Algo/Impl/BinaryHeap.h b/Engine/Source/Runtime/Core/Public/Containers/Algo/Impl/BinaryHeap.h new file mode 100644 index 000000000000..2464b93c8e73 --- /dev/null +++ b/Engine/Source/Runtime/Core/Public/Containers/Algo/Impl/BinaryHeap.h @@ -0,0 +1,145 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +//#include "Templates/Decay.h" +#include "Templates/Invoke.h" +#include "Templates/ReversePredicate.h" + +namespace AlgoImpl +{ + /** + * Gets the index of the left child of node at Index. + * + * @param Index Node for which the left child index is to be returned. + * @returns Index of the left child. + */ + FORCEINLINE int32 HeapGetLeftChildIndex(int32 Index) + { + return Index * 2 + 1; + } + + /** + * Checks if node located at Index is a leaf or not. + * + * @param Index Node index. + * @returns true if node is a leaf, false otherwise. + */ + FORCEINLINE bool HeapIsLeaf(int32 Index, int32 Count) + { + return HeapGetLeftChildIndex(Index) >= Count; + } + + /** + * Gets the parent index for node at Index. + * + * @param Index node index. + * @returns Parent index. + */ + FORCEINLINE int32 HeapGetParentIndex(int32 Index) + { + return (Index - 1) / 2; + } + + /** + * Fixes a possible violation of order property between node at Index and a child. + * + * @param Heap Pointer to the first element of a binary heap. + * @param Index Node index. + * @param Count Size of the heap. + * @param Projection The projection to apply to the elements. + * @param Predicate A binary predicate object used to specify if one element should precede another. + */ + template + FORCEINLINE void HeapSiftDown(RangeValueType* Heap, int32 Index, const int32 Count, const ProjectionType& Projection, const PredicateType& Predicate) + { + while (!HeapIsLeaf(Index, Count)) + { + const int32 LeftChildIndex = HeapGetLeftChildIndex(Index); + const int32 RightChildIndex = LeftChildIndex + 1; + + int32 MinChildIndex = LeftChildIndex; + if (RightChildIndex < Count) + { + MinChildIndex = Predicate( Invoke(Projection, Heap[LeftChildIndex]), Invoke(Projection, Heap[RightChildIndex]) ) ? LeftChildIndex : RightChildIndex; + } + + if (!Predicate( Invoke(Projection, Heap[MinChildIndex]), Invoke(Projection, Heap[Index]) )) + { + break; + } + + Swap(Heap[Index], Heap[MinChildIndex]); + Index = MinChildIndex; + } + } + + /** + * Fixes a possible violation of order property between node at NodeIndex and a parent. + * + * @param Heap Pointer to the first element of a binary heap. + * @param RootIndex How far to go up? + * @param NodeIndex Node index. + * @param Projection The projection to apply to the elements. + * @param Predicate A binary predicate object used to specify if one element should precede another. + * + * @return The new index of the node that was at NodeIndex + */ + template + FORCEINLINE int32 HeapSiftUp(RangeValueType* Heap, int32 RootIndex, int32 NodeIndex, const ProjectionType& Projection, const PredicateType& Predicate) + { + while (NodeIndex > RootIndex) + { + int32 ParentIndex = HeapGetParentIndex(NodeIndex); + if (!Predicate( Invoke(Projection, Heap[NodeIndex]), Invoke(Projection, Heap[ParentIndex]) )) + { + break; + } + + Swap(Heap[NodeIndex], Heap[ParentIndex]); + NodeIndex = ParentIndex; + } + + return NodeIndex; + } + + /** + * Builds an implicit min-heap from a range of elements. + * This is the internal function used by Heapify overrides. + * + * @param First pointer to the first element to heapify + * @param Num the number of items to heapify + * @param Projection The projection to apply to the elements. + * @param Predicate A binary predicate object used to specify if one element should precede another. + */ + template + FORCEINLINE void HeapifyInternal(RangeValueType* First, SIZE_T Num, ProjectionType Projection, PredicateType Predicate) + { + for (int32 Index = HeapGetParentIndex(Num - 1); Index >= 0; Index--) + { + HeapSiftDown(First, Index, Num, Projection, Predicate); + } + } + + /** + * Performs heap sort on the elements. + * This is the internal sorting function used by HeapSort overrides. + * + * @param First pointer to the first element to sort + * @param Num the number of elements to sort + * @param Predicate predicate class + */ + template + void HeapSortInternal(RangeValueType* First, SIZE_T Num, ProjectionType Projection, PredicateType Predicate) + { + TReversePredicate< PredicateType > ReversePredicateWrapper(Predicate); // Reverse the predicate to build a max-heap instead of a min-heap + HeapifyInternal(First, Num, Projection, ReversePredicateWrapper); + + for(int32 Index = Num - 1; Index > 0; Index--) + { + Swap(First[0], First[Index]); + + HeapSiftDown(First, 0, Index, Projection, ReversePredicateWrapper); + } + } +} diff --git a/Engine/Source/Runtime/Core/Public/Containers/Algo/IntroSort.h b/Engine/Source/Runtime/Core/Public/Containers/Algo/IntroSort.h new file mode 100644 index 000000000000..269bfde80e50 --- /dev/null +++ b/Engine/Source/Runtime/Core/Public/Containers/Algo/IntroSort.h @@ -0,0 +1,177 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "Algo/Impl/BinaryHeap.h" +#include "Templates/IdentityFunctor.h" +#include "Templates/Invoke.h" +#include "Templates/Less.h" +#include "Templates/UnrealTemplate.h" // For GetData, GetNum + + +namespace AlgoImpl +{ + /** + * Implementation of an introspective sort. Starts with quick sort and switches to heap sort when the iteration depth is too big. + * The sort is unstable, meaning that the ordering of equal items is not necessarily preserved. + * This is the internal sorting function used by IntroSort overrides. + * + * @param First pointer to the first element to sort + * @param Num the number of items to sort + * @param Projection The projection to sort by when applied to the element. + * @param Predicate predicate class + */ + template + void IntroSortInternal(T* First, SIZE_T Num, ProjectionType Projection, PredicateType Predicate) + { + struct FStack + { + T* Min; + T* Max; + uint32 MaxDepth; + }; + + if( Num < 2 ) + { + return; + } + + FStack RecursionStack[32]={{First, First+Num-1, (uint32)(FMath::Loge(Num) * 2.f)}}, Current, Inner; + for( FStack* StackTop=RecursionStack; StackTop>=RecursionStack; --StackTop ) //-V625 + { + Current = *StackTop; + + Loop: + PTRINT Count = Current.Max - Current.Min + 1; + + if ( Current.MaxDepth == 0 ) + { + // We're too deep into quick sort, switch to heap sort + HeapSortInternal( Current.Min, Count, Projection, Predicate ); + continue; + } + + if( Count <= 8 ) + { + // Use simple bubble-sort. + while( Current.Max > Current.Min ) + { + T *Max, *Item; + for( Max=Current.Min, Item=Current.Min+1; Item<=Current.Max; Item++ ) + { + if( Predicate( Invoke( Projection, *Max ), Invoke( Projection, *Item ) ) ) + { + Max = Item; + } + } + Swap( *Max, *Current.Max-- ); + } + } + else + { + // Grab middle element so sort doesn't exhibit worst-cast behavior with presorted lists. + Swap( Current.Min[Count/2], Current.Min[0] ); + + // Divide list into two halves, one with items <=Current.Min, the other with items >Current.Max. + Inner.Min = Current.Min; + Inner.Max = Current.Max+1; + for( ; ; ) + { + while( ++Inner.Min<=Current.Max && !Predicate( Invoke( Projection, *Current.Min ), Invoke( Projection, *Inner.Min ) ) ); + while( --Inner.Max> Current.Min && !Predicate( Invoke( Projection, *Inner.Max ), Invoke( Projection, *Current.Min ) ) ); + if( Inner.Min>Inner.Max ) + { + break; + } + Swap( *Inner.Min, *Inner.Max ); + } + Swap( *Current.Min, *Inner.Max ); + + --Current.MaxDepth; + + // Save big half and recurse with small half. + if( Inner.Max-1-Current.Min >= Current.Max-Inner.Min ) + { + if( Current.Min+1 < Inner.Max ) + { + StackTop->Min = Current.Min; + StackTop->Max = Inner.Max - 1; + StackTop->MaxDepth = Current.MaxDepth; + StackTop++; + } + if( Current.Max>Inner.Min ) + { + Current.Min = Inner.Min; + goto Loop; + } + } + else + { + if( Current.Max>Inner.Min ) + { + StackTop->Min = Inner .Min; + StackTop->Max = Current.Max; + StackTop->MaxDepth = Current.MaxDepth; + StackTop++; + } + if( Current.Min+1 + FORCEINLINE void IntroSort(RangeType& Range) + { + AlgoImpl::IntroSortInternal(GetData(Range), GetNum(Range), FIdentityFunctor(), TLess<>()); + } + + /** + * Sort a range of elements using a user-defined predicate class. The sort is unstable. + * + * @param Range The range to sort. + * @param Predicate A binary predicate object used to specify if one element should precede another. + */ + template + FORCEINLINE void IntroSort(RangeType& Range, PredicateType Predicate) + { + AlgoImpl::IntroSortInternal(GetData(Range), GetNum(Range), FIdentityFunctor(), MoveTemp(Predicate)); + } + + /** + * Sort a range of elements by a projection using the projection's operator<. The sort is unstable. + * + * @param Range The range to sort. + * @param Projection The projection to sort by when applied to the element. + */ + template + FORCEINLINE void IntroSortBy(RangeType& Range, ProjectionType Projection) + { + AlgoImpl::IntroSortInternal(GetData(Range), GetNum(Range), MoveTemp(Projection), TLess<>()); + } + + /** + * Sort a range of elements by a projection using a user-defined predicate class. The sort is unstable. + * + * @param Range The range to sort. + * @param Projection The projection to sort by when applied to the element. + * @param Predicate A binary predicate object, applied to the projection, used to specify if one element should precede another. + */ + template + FORCEINLINE void IntroSortBy(RangeType& Range, ProjectionType Projection, PredicateType Predicate) + { + AlgoImpl::IntroSortInternal(GetData(Range), GetNum(Range), MoveTemp(Projection), MoveTemp(Predicate)); + } +} diff --git a/Engine/Source/Runtime/Core/Public/Containers/Algo/IsHeap.h b/Engine/Source/Runtime/Core/Public/Containers/Algo/IsHeap.h new file mode 100644 index 000000000000..1353aff03b01 --- /dev/null +++ b/Engine/Source/Runtime/Core/Public/Containers/Algo/IsHeap.h @@ -0,0 +1,97 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "Algo/Impl/BinaryHeap.h" +#include "Templates/IdentityFunctor.h" +#include "Templates/Invoke.h" +#include "Templates/Less.h" +#include "Templates/UnrealTemplate.h" // For GetData, GetNum + +namespace AlgoImpl +{ + /** + * Verifies that the range is a min-heap (parent <= child) + * This is the internal function used by IsHeap overrides. + * + * @param Heap Pointer to the first element of a binary heap. + * @param Num the number of items in the heap. + * @param Projection The projection to apply to the elements. + * @param Predicate A binary predicate object used to specify if one element should precede another. + * + * @return returns true if the range is a min-heap + */ + template + bool IsHeapInternal(RangeValueType* Heap, SIZE_T Num, ProjectionType Projection, PredicateType Predicate) + { + for (SIZE_T Index = 1; Index < Num; Index++) + { + int32 ParentIndex = HeapGetParentIndex(Index); + if (Predicate( Invoke(Projection, Heap[Index]), Invoke(Projection, Heap[ParentIndex]) )) + { + return false; + } + } + + return true; + } +} + +namespace Algo +{ + /** + * Verifies that the range is a min-heap (parent <= child). Assumes < operator is defined for the element type. + * + * @param Range The range to verify. + * + * @return returns true if the range is a min-heap + */ + template + FORCEINLINE bool IsHeap(RangeType& Range) + { + return AlgoImpl::IsHeapInternal(GetData(Range), GetNum(Range), FIdentityFunctor(), TLess<>()); + } + + /** + * Verifies that the range is a min-heap (parent <= child) + * + * @param Range The range to verify. + * @param Predicate A binary predicate object used to specify if one element should precede another. + * + * @return returns true if the range is a min-heap + */ + template + FORCEINLINE bool IsHeap(RangeType& Range, PredicateType Predicate) + { + return AlgoImpl::IsHeapInternal(GetData(Range), GetNum(Range), FIdentityFunctor(), MoveTemp(Predicate)); + } + + /** + * Verifies that the range is a min-heap (parent <= child). Assumes < operator is defined for the projected element type. + * + * @param Range The range to verify. + * @param Projection The projection to apply to the elements. + * + * @return returns true if the range is a min-heap + */ + template + FORCEINLINE bool IsHeapBy(RangeType& Range, ProjectionType Projection) + { + return AlgoImpl::IsHeapInternal(GetData(Range), GetNum(Range), MoveTemp(Projection), TLess<>()); + } + + /** + * Verifies that the range is a min-heap (parent <= child) + * + * @param Range The range to verify. + * @param Projection The projection to apply to the elements. + * @param Predicate A binary predicate object used to specify if one element should precede another. + * + * @return returns true if the range is a min-heap + */ + template + FORCEINLINE bool IsHeapBy(RangeType& Range, ProjectionType Projection, PredicateType Predicate) + { + return AlgoImpl::IsHeapInternal(GetData(Range), GetNum(Range), MoveTemp(Projection), MoveTemp(Predicate)); + } +} \ No newline at end of file diff --git a/Engine/Source/Runtime/Core/Public/Containers/Algo/IsSorted.h b/Engine/Source/Runtime/Core/Public/Containers/Algo/IsSorted.h index 9a03dc8f59a3..1dda07c5c24e 100644 --- a/Engine/Source/Runtime/Core/Public/Containers/Algo/IsSorted.h +++ b/Engine/Source/Runtime/Core/Public/Containers/Algo/IsSorted.h @@ -3,12 +3,16 @@ #pragma once #include "CoreTypes.h" -#include "Traits/ElementType.h" +#include "Templates/IdentityFunctor.h" +#include "Templates/Invoke.h" +#include "Templates/Less.h" +#include "Templates/UnrealTemplate.h" // For GetData, GetNum, MoveTemp + namespace AlgoImpl { - template - bool IsSorted(const T* Range, int32 RangeSize, PredType Pred) + template + bool IsSortedBy(const T* Range, int32 RangeSize, ProjectionType Proj, PredType Pred) { if (RangeSize == 0) { @@ -26,7 +30,9 @@ namespace AlgoImpl return true; } - if (Pred(*Next, *Range)) + auto&& Ref1 = Invoke(Proj, *Next); + auto&& Ref2 = Invoke(Proj, *Range); + if (Invoke(Pred, Ref1, Ref2)) { return false; } @@ -50,34 +56,7 @@ namespace AlgoImpl namespace Algo { /** - * Tests is a range is sorted. - * - * @param Array The array to test for being sorted. - * - * @return true if the range is sorted, false otherwise. - */ - template - FORCEINLINE bool IsSorted(const T (&Array)[ArraySize]) - { - return AlgoImpl::IsSorted((const T*)Array, ArraySize, AlgoImpl::TLess()); - } - - /** - * Tests is a range is sorted. - * - * @param Array The array to test for being sorted. - * @param Pred A binary sorting predicate which describes the ordering of the elements in the array. - * - * @return true if the range is sorted, false otherwise. - */ - template - FORCEINLINE bool IsSorted(const T (&Array)[ArraySize], PredType Pred) - { - return AlgoImpl::IsSorted((const T*)Array, ArraySize, Pred); - } - - /** - * Tests is a range is sorted. + * Tests if a range is sorted by its element type's operator<. * * @param Array A pointer to the array to test for being sorted. * @param ArraySize The number of elements in the array. @@ -85,13 +64,14 @@ namespace Algo * @return true if the range is sorted, false otherwise. */ template + DEPRECATED(4.16, "IsSorted taking a pointer and size has been deprecated - please pass a TArrayView instead") FORCEINLINE bool IsSorted(const T* Array, int32 ArraySize) { - return AlgoImpl::IsSorted(Array, ArraySize, AlgoImpl::TLess()); + return AlgoImpl::IsSortedBy(Array, ArraySize, FIdentityFunctor(), TLess<>()); } /** - * Tests is a range is sorted. + * Tests if a range is sorted by a user-defined predicate. * * @param Array A pointer to the array to test for being sorted. * @param ArraySize The number of elements in the array. @@ -100,35 +80,63 @@ namespace Algo * @return true if the range is sorted, false otherwise. */ template + DEPRECATED(4.16, "IsSorted taking a pointer and size has been deprecated - please pass a TArrayView instead") FORCEINLINE bool IsSorted(const T* Array, int32 ArraySize, PredType Pred) { - return AlgoImpl::IsSorted(Array, ArraySize, Pred); + return AlgoImpl::IsSortedBy(Array, ArraySize, FIdentityFunctor(), MoveTemp(Pred)); } /** - * Tests is a range is sorted. + * Tests if a range is sorted by its element type's operator<. * - * @param Container The container to test for being sorted. + * @param Range The container to test for being sorted. * * @return true if the range is sorted, false otherwise. */ - template - FORCEINLINE bool IsSorted(const ContainerType& Container) + template + FORCEINLINE bool IsSorted(const RangeType& Range) { - return AlgoImpl::IsSorted(Container.GetData(), Container.Num(), AlgoImpl::TLess::Type>()); + return AlgoImpl::IsSortedBy(GetData(Range), GetNum(Range), FIdentityFunctor(), TLess<>()); } /** - * Tests is a range is sorted. + * Tests if a range is sorted by a user-defined predicate. * - * @param Container The container to test for being sorted. - * @param Pred A binary sorting predicate which describes the ordering of the elements in the array. + * @param Range The container to test for being sorted. + * @param Pred A binary sorting predicate which describes the ordering of the elements in the array. * * @return true if the range is sorted, false otherwise. */ - template - FORCEINLINE bool IsSorted(const ContainerType& Container, PredType Pred) + template + FORCEINLINE bool IsSorted(const RangeType& Range, PredType Pred) { - return AlgoImpl::IsSorted(Container.GetData(), Container.Num(), Pred); + return AlgoImpl::IsSortedBy(GetData(Range), GetNum(Range), FIdentityFunctor(), MoveTemp(Pred)); + } + + /** + * Tests if a range is sorted by a projection of the element type, using the projection's operator<. + * + * @param Range The container to test for being sorted. + * + * @return true if the range is sorted, false otherwise. + */ + template + FORCEINLINE bool IsSortedBy(const RangeType& Range, ProjectionType Projection) + { + return AlgoImpl::IsSortedBy(GetData(Range), GetNum(Range), MoveTemp(Projection), TLess<>()); + } + + /** + * Tests if a range is sorted by a projection of the element type, using a user-defined predicate on the projection. + * + * @param Range The container to test for being sorted. + * @param Pred A binary sorting predicate which describes the ordering of the elements in the array. + * + * @return true if the range is sorted, false otherwise. + */ + template + FORCEINLINE bool IsSortedBy(const RangeType& Range, ProjectionType Projection, PredType Pred) + { + return AlgoImpl::IsSortedBy(GetData(Range), GetNum(Range), MoveTemp(Projection), MoveTemp(Pred)); } } diff --git a/Engine/Source/Runtime/Core/Public/Containers/Algo/Sort.h b/Engine/Source/Runtime/Core/Public/Containers/Algo/Sort.h index c6987baed34e..7bfdc8edab48 100644 --- a/Engine/Source/Runtime/Core/Public/Containers/Algo/Sort.h +++ b/Engine/Source/Runtime/Core/Public/Containers/Algo/Sort.h @@ -5,6 +5,7 @@ #include "Templates/IdentityFunctor.h" #include "Templates/Invoke.h" #include "Templates/Less.h" +#include "Templates/UnrealTemplate.h" // For GetData, GetNum namespace AlgoImpl @@ -116,7 +117,7 @@ namespace Algo template FORCEINLINE void Sort(RangeType& Range) { - AlgoImpl::SortInternal(Range.GetData(), Range.Num(), FIdentityFunctor(), TLess<>()); + AlgoImpl::SortInternal(GetData(Range), GetNum(Range), FIdentityFunctor(), TLess<>()); } /** @@ -129,7 +130,7 @@ namespace Algo template FORCEINLINE void Sort(RangeType& Range, PredicateType Pred) { - AlgoImpl::SortInternal(Range.GetData(), Range.Num(), FIdentityFunctor(), MoveTemp(Pred)); + AlgoImpl::SortInternal(GetData(Range), GetNum(Range), FIdentityFunctor(), MoveTemp(Pred)); } /** @@ -141,7 +142,7 @@ namespace Algo template FORCEINLINE void SortBy(RangeType& Range, ProjectionType Proj) { - AlgoImpl::SortInternal(Range.GetData(), Range.Num(), MoveTemp(Proj), TLess<>()); + AlgoImpl::SortInternal(GetData(Range), GetNum(Range), MoveTemp(Proj), TLess<>()); } /** @@ -155,6 +156,6 @@ namespace Algo template FORCEINLINE void SortBy(RangeType& Range, ProjectionType Proj, PredicateType Pred) { - AlgoImpl::SortInternal(Range.GetData(), Range.Num(), MoveTemp(Proj), MoveTemp(Pred)); + AlgoImpl::SortInternal(GetData(Range), GetNum(Range), MoveTemp(Proj), MoveTemp(Pred)); } } diff --git a/Engine/Source/Runtime/Core/Public/Containers/Array.h b/Engine/Source/Runtime/Core/Public/Containers/Array.h index de3b768cb57e..f71fa2994793 100644 --- a/Engine/Source/Runtime/Core/Public/Containers/Array.h +++ b/Engine/Source/Runtime/Core/Public/Containers/Array.h @@ -11,10 +11,15 @@ #include "Containers/ContainerAllocationPolicies.h" #include "Serialization/Archive.h" +#include "Algo/Heapify.h" +#include "Algo/HeapSort.h" +#include "Algo/IsHeap.h" +#include "Algo/Impl/BinaryHeap.h" +#include "Templates/IdentityFunctor.h" #include "Templates/Less.h" +#include "Templates/ChooseClass.h" #include "Templates/Sorting.h" -#define DEBUG_HEAP 0 #if UE_BUILD_SHIPPING || UE_BUILD_TEST #define TARRAY_RANGED_FOR_CHECKS 0 @@ -22,14 +27,13 @@ #define TARRAY_RANGED_FOR_CHECKS 1 #endif -#define AGRESSIVE_ARRAY_FORCEINLINE - /** * Generic iterator which can operate on types that expose the following: * - A type called ElementType representing the contained type. * - A method IndexType Num() const that returns the number of items in the container. * - A method bool IsValidIndex(IndexType index) which returns whether a given index is valid in the container. * - A method T& operator\[\](IndexType index) which returns a reference to a contained object by index. + * - A method void RemoveAt(IndexType index) which removes the element at index */ template< typename ContainerType, typename ElementType, typename IndexType> class TIndexedContainerIterator @@ -91,29 +95,21 @@ public: return Tmp -= Offset; } - /** @name Element access */ - //@{ ElementType& operator* () const { return Container[ Index ]; } - ElementType* operator-> () const + ElementType* operator->() const { return &Container[ Index ]; } - //@} /** conversion to "bool" returning true if the iterator has not reached the last element. */ FORCEINLINE explicit operator bool() const { return Container.IsValidIndex(Index); } - /** inverse of the "bool" operator */ - FORCEINLINE bool operator !() const - { - return !(bool)*this; - } /** Returns an index to the current element. */ IndexType GetIndex() const @@ -127,6 +123,19 @@ public: Index = 0; } + /** Sets iterator to the last element. */ + void SetToEnd() + { + Index = Container.Num(); + } + + /** Removes current element in array. This invalidates the current iterator value and it must be incremented */ + void RemoveCurrent() + { + Container.RemoveAt(Index); + Index--; + } + FORCEINLINE friend bool operator==(const TIndexedContainerIterator& Lhs, const TIndexedContainerIterator& Rhs) { return &Lhs.Container == &Rhs.Container && Lhs.Index == Rhs.Index; } FORCEINLINE friend bool operator!=(const TIndexedContainerIterator& Lhs, const TIndexedContainerIterator& Rhs) { return &Lhs.Container != &Rhs.Container || Lhs.Index != Rhs.Index; } @@ -229,52 +238,6 @@ private: } }; - -/** - * TReversePredicateWrapper class used by implicit heaps. - * This is similar to TDereferenceWrapper from Sorting.h except it reverses the comparison at the same time - */ -template -class TReversePredicateWrapper -{ - const PREDICATE_CLASS& Predicate; -public: - TReversePredicateWrapper( const PREDICATE_CLASS& InPredicate ) - : Predicate( InPredicate ) - {} - - FORCEINLINE bool operator()( ElementType& A, ElementType& B ) const { return Predicate( B, A ); } - FORCEINLINE bool operator()( const ElementType& A, const ElementType& B ) const { return Predicate( B, A ); } -}; - - -/** - * Partially specialized version of the above. - */ -template -class TReversePredicateWrapper -{ - const PREDICATE_CLASS& Predicate; -public: - TReversePredicateWrapper( const PREDICATE_CLASS& InPredicate ) - : Predicate( InPredicate ) - {} - - FORCEINLINE bool operator()( ElementType* A, ElementType* B ) const - { - check( A != nullptr ); - check( B != nullptr ); - return Predicate( *B, *A ); - } - FORCEINLINE bool operator()( const ElementType* A, const ElementType* B ) const - { - check( A != nullptr ); - check( B != nullptr ); - return Predicate( *B, *A ); - } -}; - - namespace UE4Array_Private { template @@ -379,7 +342,7 @@ public: * * @param InitList The initializer_list to copy from. */ - AGRESSIVE_ARRAY_FORCEINLINE TArray& operator=(std::initializer_list InitList) + TArray& operator=(std::initializer_list InitList) { DestructItems(GetData(), ArrayNum); // This is not strictly legal, as std::initializer_list's iterators are not guaranteed to be pointers, but @@ -398,7 +361,7 @@ public: * @param Other The source array to assign from. */ template - AGRESSIVE_ARRAY_FORCEINLINE TArray& operator=(const TArray& Other) + TArray& operator=(const TArray& Other) { DestructItems(GetData(), ArrayNum); CopyToEmpty(Other.GetData(), Other.Num(), ArrayMax, 0); @@ -411,7 +374,7 @@ public: * * @param Other The source array to assign from. */ - AGRESSIVE_ARRAY_FORCEINLINE TArray& operator=(const TArray& Other) + TArray& operator=(const TArray& Other) { if (this != &Other) { @@ -522,7 +485,7 @@ public: * at the end of the array in the number of elements. */ template - AGRESSIVE_ARRAY_FORCEINLINE TArray(TArray&& Other, int32 ExtraSlack) + TArray(TArray&& Other, int32 ExtraSlack) { // We don't implement move semantics for general OtherAllocators, as there's no way // to tell if they're compatible with the current one. Probably going to be a pretty @@ -536,7 +499,7 @@ public: * * @param Other Array to assign and move from. */ - AGRESSIVE_ARRAY_FORCEINLINE TArray& operator=(TArray&& Other) + TArray& operator=(TArray&& Other) { if (this != &Other) { @@ -547,7 +510,7 @@ public: } /** Destructor. */ - AGRESSIVE_ARRAY_FORCEINLINE ~TArray() + ~TArray() { DestructItems(GetData(), ArrayNum); @@ -813,7 +776,7 @@ public: * @returns Index of the found element. INDEX_NONE otherwise. * @see FindLast, FindLastByPredicate */ - AGRESSIVE_ARRAY_FORCEINLINE int32 Find(const ElementType& Item) const + int32 Find(const ElementType& Item) const { const ElementType* RESTRICT Start = GetData(); for (const ElementType* RESTRICT Data = Start, *RESTRICT DataEnd = Data + ArrayNum; Data != DataEnd; ++Data) @@ -901,7 +864,7 @@ public: * @returns Index to the first matching element, or INDEX_NONE if none is found. */ template - AGRESSIVE_ARRAY_FORCEINLINE int32 IndexOfByKey(const KeyType& Key) const + int32 IndexOfByKey(const KeyType& Key) const { const ElementType* RESTRICT Start = GetData(); for (const ElementType* RESTRICT Data = Start, *RESTRICT DataEnd = Start + ArrayNum; Data != DataEnd; ++Data) @@ -921,7 +884,7 @@ public: * @returns Index to the first matching element, or INDEX_NONE if none is found. */ template - AGRESSIVE_ARRAY_FORCEINLINE int32 IndexOfByPredicate(Predicate Pred) const + int32 IndexOfByPredicate(Predicate Pred) const { const ElementType* RESTRICT Start = GetData(); for (const ElementType* RESTRICT Data = Start, *RESTRICT DataEnd = Start + ArrayNum; Data != DataEnd; ++Data) @@ -957,7 +920,7 @@ public: * @see Find */ template - AGRESSIVE_ARRAY_FORCEINLINE ElementType* FindByKey(const KeyType& Key) + ElementType* FindByKey(const KeyType& Key) { for (ElementType* RESTRICT Data = GetData(), *RESTRICT DataEnd = Data + ArrayNum; Data != DataEnd; ++Data) { @@ -990,7 +953,7 @@ public: * @see FilterByPredicate, ContainsByPredicate */ template - AGRESSIVE_ARRAY_FORCEINLINE ElementType* FindByPredicate(Predicate Pred) + ElementType* FindByPredicate(Predicate Pred) { for (ElementType* RESTRICT Data = GetData(), *RESTRICT DataEnd = Data + ArrayNum; Data != DataEnd; ++Data) { @@ -1032,7 +995,7 @@ public: * @see ContainsByPredicate, FilterByPredicate, FindByPredicate */ template - AGRESSIVE_ARRAY_FORCEINLINE bool Contains(const ComparisonType& Item) const + bool Contains(const ComparisonType& Item) const { for (const ElementType* RESTRICT Data = GetData(), *RESTRICT DataEnd = Data + ArrayNum; Data != DataEnd; ++Data) { @@ -1063,7 +1026,7 @@ public: * @param OtherArray Array to compare. * @returns True if this array is the same as OtherArray. False otherwise. */ - AGRESSIVE_ARRAY_FORCEINLINE bool operator==(const TArray& OtherArray) const + bool operator==(const TArray& OtherArray) const { int32 Count = Num(); @@ -1456,7 +1419,7 @@ public: } private: - AGRESSIVE_ARRAY_FORCEINLINE void RemoveAtSwapImpl(int32 Index, int32 Count = 1, bool bAllowShrinking = true) + void RemoveAtSwapImpl(int32 Index, int32 Count = 1, bool bAllowShrinking = true) { if (Count) { @@ -1529,7 +1492,7 @@ public: * * @param NewSize The expected usage size after calling this function. */ - AGRESSIVE_ARRAY_FORCEINLINE void Reset(int32 NewSize = 0) + void Reset(int32 NewSize = 0) { // If we have space to hold the excepted size, then don't reallocate if (NewSize <= ArrayMax) @@ -1548,7 +1511,7 @@ public: * * @param Slack (Optional) The expected usage size after empty operation. Default is 0. */ - AGRESSIVE_ARRAY_FORCEINLINE void Empty(int32 Slack = 0) + void Empty(int32 Slack = 0) { DestructItems(GetData(), ArrayNum); @@ -1603,7 +1566,7 @@ public: * * @param NewNum New size of the array. */ - AGRESSIVE_ARRAY_FORCEINLINE void SetNumUninitialized(int32 NewNum, bool bAllowShrinking = true) + void SetNumUninitialized(int32 NewNum, bool bAllowShrinking = true) { if (NewNum > Num()) { @@ -1634,7 +1597,7 @@ public: * @see Add, Insert */ template - AGRESSIVE_ARRAY_FORCEINLINE void Append(const TArray& Source) + void Append(const TArray& Source) { check((void*)this != (void*)&Source); @@ -1660,7 +1623,7 @@ public: * @see Add, Insert */ template - AGRESSIVE_ARRAY_FORCEINLINE void Append(TArray&& Source) + void Append(TArray&& Source) { check((void*)this != (void*)&Source); @@ -1687,7 +1650,7 @@ public: * @param Count The number of elements to insert from Ptr. * @see Add, Insert */ - AGRESSIVE_ARRAY_FORCEINLINE void Append(const ElementType* Ptr, int32 Count) + void Append(const ElementType* Ptr, int32 Count) { check(Ptr != nullptr); @@ -1717,7 +1680,7 @@ public: * * @param Other The array to append. */ - AGRESSIVE_ARRAY_FORCEINLINE TArray& operator+=(TArray&& Other) + TArray& operator+=(TArray&& Other) { Append(MoveTemp(Other)); return *this; @@ -1729,7 +1692,7 @@ public: * * @param Other The array to append. */ - AGRESSIVE_ARRAY_FORCEINLINE TArray& operator+=(const TArray& Other) + TArray& operator+=(const TArray& Other) { Append(Other); return *this; @@ -1740,7 +1703,7 @@ public: * * @param InitList The initializer list to append. */ - AGRESSIVE_ARRAY_FORCEINLINE TArray& operator+=(std::initializer_list InitList) + TArray& operator+=(std::initializer_list InitList) { Append(InitList); return *this; @@ -1805,7 +1768,7 @@ public: * @return Index to the first of the new items. * @see Add, AddDefaulted, AddUnique, Append, Insert */ - AGRESSIVE_ARRAY_FORCEINLINE int32 AddZeroed(int32 Count = 1) + int32 AddZeroed(int32 Count = 1) { const int32 Index = AddUninitialized(Count); FMemory::Memzero((uint8*)AllocatorInstance.GetAllocation() + Index*sizeof(ElementType), Count*sizeof(ElementType)); @@ -1820,7 +1783,7 @@ public: * @return Index to the first of the new items. * @see Add, AddZeroed, AddUnique, Append, Insert */ - AGRESSIVE_ARRAY_FORCEINLINE int32 AddDefaulted(int32 Count = 1) + int32 AddDefaulted(int32 Count = 1) { const int32 Index = AddUninitialized(Count); DefaultConstructItems((uint8*)AllocatorInstance.GetAllocation() + Index * sizeof(ElementType), Count); @@ -1836,7 +1799,7 @@ private: * @returns Index of the element in the array. */ template - AGRESSIVE_ARRAY_FORCEINLINE int32 AddUniqueImpl(ArgsType&& Args) + int32 AddUniqueImpl(ArgsType&& Args) { int32 Index; if (Find(Args, Index)) @@ -1889,7 +1852,7 @@ public: * @param Element The element to fill array with. * @param Number The number of elements that the array should be able to contain after allocation. */ - AGRESSIVE_ARRAY_FORCEINLINE void Init(const ElementType& Element, int32 Number) + void Init(const ElementType& Element, int32 Number) { Empty(Number); for (int32 Index = 0; Index < Number; ++Index) @@ -2313,7 +2276,7 @@ private: * default. */ template - AGRESSIVE_ARRAY_FORCEINLINE void CopyToEmpty(const OtherElementType* OtherData, int32 OtherNum, int32 PrevMax, int32 ExtraSlack) + void CopyToEmpty(const OtherElementType* OtherData, int32 OtherNum, int32 PrevMax, int32 ExtraSlack) { checkSlow(ExtraSlack >= 0); ArrayNum = OtherNum; @@ -2358,7 +2321,8 @@ public: template FORCEINLINE void Heapify(const PREDICATE_CLASS& Predicate) { - HeapifyInternal(TDereferenceWrapper(Predicate)); + TDereferenceWrapper PredicateWrapper(Predicate); + Algo::Heapify(*this, PredicateWrapper); } /** @@ -2391,11 +2355,7 @@ public: // Add at the end, then sift up Add(MoveTemp(InItem)); TDereferenceWrapper PredicateWrapper(Predicate); - int32 Result = SiftUp(0, Num() - 1, PredicateWrapper); - -#if DEBUG_HEAP - VerifyHeap(PredicateWrapper); -#endif + int32 Result = AlgoImpl::HeapSiftUp(GetData(), 0, Num() - 1, FIdentityFunctor(), PredicateWrapper); return Result; } @@ -2417,11 +2377,7 @@ public: // Add at the end, then sift up Add(InItem); TDereferenceWrapper PredicateWrapper(Predicate); - int32 Result = SiftUp(0, Num() - 1, PredicateWrapper); - -#if DEBUG_HEAP - VerifyHeap(PredicateWrapper); -#endif + int32 Result = AlgoImpl::HeapSiftUp(GetData(), 0, Num() - 1, FIdentityFunctor(), PredicateWrapper); return Result; } @@ -2475,11 +2431,7 @@ public: RemoveAtSwap(0, 1, bAllowShrinking); TDereferenceWrapper< ElementType, PREDICATE_CLASS> PredicateWrapper(Predicate); - SiftDown(0, Num(), PredicateWrapper); - -#if DEBUG_HEAP - VerifyHeap(PredicateWrapper); -#endif + AlgoImpl::HeapSiftDown(GetData(), 0, Num(), FIdentityFunctor(), PredicateWrapper); } /** @@ -2502,24 +2454,11 @@ public: * Verifies the heap. * * @param Predicate Predicate class instance. - * - * @note: If your array contains raw pointers, they will be automatically dereferenced during heap verification. - * Therefore, your predicate will be passed references rather than pointers. - * The auto-dereferencing behavior does not occur with smart pointers. */ template void VerifyHeap(const PREDICATE_CLASS& Predicate) { - // Verify Predicate - ElementType* Heap = GetData(); - for (int32 Index = 1; Index < Num(); Index++) - { - int32 ParentIndex = HeapGetParentIndex(Index); - if (Predicate(Heap[Index], Heap[ParentIndex])) - { - check(false); - } - } + check(Algo::IsHeap(*this, Predicate)); } /** @@ -2537,11 +2476,7 @@ public: { RemoveAtSwap(0, 1, bAllowShrinking); TDereferenceWrapper< ElementType, PREDICATE_CLASS> PredicateWrapper(Predicate); - SiftDown(0, Num(), PredicateWrapper); - -#if DEBUG_HEAP - VerifyHeap(PredicateWrapper); -#endif + AlgoImpl::HeapSiftDown(GetData(), 0, Num(), FIdentityFunctor(), PredicateWrapper); } /** @@ -2599,12 +2534,8 @@ public: RemoveAtSwap(Index, 1, bAllowShrinking); TDereferenceWrapper< ElementType, PREDICATE_CLASS> PredicateWrapper(Predicate); - SiftDown(Index, Num(), PredicateWrapper); - SiftUp(0, FPlatformMath::Min(Index, Num() - 1), PredicateWrapper); - -#if DEBUG_HEAP - VerifyHeap(PredicateWrapper); -#endif + AlgoImpl::HeapSiftDown(GetData(), Index, Num(), FIdentityFunctor(), PredicateWrapper); + AlgoImpl::HeapSiftUp(GetData(), 0, FPlatformMath::Min(Index, Num() - 1), FIdentityFunctor(), PredicateWrapper); } /** @@ -2635,31 +2566,8 @@ public: template void HeapSort(const PREDICATE_CLASS& Predicate) { - TReversePredicateWrapper ReversePredicateWrapper(Predicate); - HeapifyInternal(ReversePredicateWrapper); - - ElementType* Heap = GetData(); - for(int32 Index=Num()-1; Index>0; Index--) - { - Exchange(Heap[0], Heap[Index]); - SiftDown(0, Index, ReversePredicateWrapper); - } - -#if DEBUG_HEAP TDereferenceWrapper PredicateWrapper(Predicate); - - // Verify Heap Property - VerifyHeap(PredicateWrapper); - - // Also verify Array is properly sorted - for(int32 Index=1; Index()); } - -private: - - /** - * Gets the index of the left child of node at Index. - * - * @param Index Node for which the left child index is to be returned. - * @returns Index of the left child. - */ - FORCEINLINE int32 HeapGetLeftChildIndex(int32 Index) const - { - return Index * 2 + 1; - } - - /** - * Checks if node located at Index is a leaf or not. - * - * @param Index Node index. - * @returns true if node is a leaf, false otherwise. - */ - FORCEINLINE bool HeapIsLeaf(int32 Index, int32 Count) const - { - return HeapGetLeftChildIndex(Index) >= Count; - } - - /** - * Gets the parent index for node at Index. - * - * @param Index node index. - * @returns Parent index. - */ - FORCEINLINE int32 HeapGetParentIndex(int32 Index) const - { - return (Index - 1) / 2; - } - -private: - template - void HeapifyInternal(const PREDICATE_CLASS& Predicate) - { - for (int32 Index = HeapGetParentIndex(Num() - 1); Index >= 0; Index--) - { - SiftDown(Index, Num(), Predicate); - } - -#if DEBUG_HEAP - VerifyHeap(Predicate); -#endif - } - - /** - * Fixes a possible violation of order property between node at Index and a child. - * - * @param Index Node index. - * @param Count Size of the heap (to avoid using Num()). - * @param Predicate Predicate class instance. - */ - template - FORCEINLINE void SiftDown(int32 Index, const int32 Count, const PREDICATE_CLASS& Predicate) - { - ElementType* Heap = GetData(); - while (!HeapIsLeaf(Index, Count)) - { - const int32 LeftChildIndex = HeapGetLeftChildIndex(Index); - const int32 RightChildIndex = LeftChildIndex + 1; - - int32 MinChildIndex = LeftChildIndex; - if (RightChildIndex < Count) - { - MinChildIndex = Predicate(Heap[LeftChildIndex], Heap[RightChildIndex]) ? LeftChildIndex : RightChildIndex; - } - - if (!Predicate(Heap[MinChildIndex], Heap[Index])) - { - break; - } - - Exchange(Heap[Index], Heap[MinChildIndex]); - Index = MinChildIndex; - } - } - - /** - * Fixes a possible violation of order property between node at NodeIndex and a parent. - * - * @param RootIndex How far to go up? - * @param NodeIndex Node index. - * @param Predicate Predicate class instance. - * - * @return The new index of the node that was at NodeIndex - */ - template - FORCEINLINE int32 SiftUp(int32 RootIndex, int32 NodeIndex, const PREDICATE_CLASS& Predicate) - { - ElementType* Heap = GetData(); - while (NodeIndex > RootIndex) - { - int32 ParentIndex = HeapGetParentIndex(NodeIndex); - if (!Predicate(Heap[NodeIndex], Heap[ParentIndex])) - { - break; - } - - Exchange(Heap[NodeIndex], Heap[ParentIndex]); - NodeIndex = ParentIndex; - } - - return NodeIndex; - } }; diff --git a/Engine/Source/Runtime/Core/Public/Containers/BinaryHeap.h b/Engine/Source/Runtime/Core/Public/Containers/BinaryHeap.h new file mode 100644 index 000000000000..42b37829635e --- /dev/null +++ b/Engine/Source/Runtime/Core/Public/Containers/BinaryHeap.h @@ -0,0 +1,363 @@ +// Copyright (C) 2009 Nine Realms, Inc +// + +#pragma once + +#include "CoreMinimal.h" + +/*----------------------------------------------------------------------------- + Binary Heap, used to index another data structure. + + Also known as a priority queue. Smallest key at top. + KeyType must implement operator< +-----------------------------------------------------------------------------*/ +template< typename KeyType, typename IndexType = uint32 > +class FBinaryHeap +{ +public: + FBinaryHeap(); + FBinaryHeap( uint32 InHeapSize, uint32 InIndexSize ); + ~FBinaryHeap(); + + void Clear(); + void Free(); + void Resize( uint32 NewHeapSize, uint32 NewIndexSize ); + + uint32 Num() const { return HeapNum; } + uint32 GetHeapSize() const { return HeapSize; } + uint32 GetIndexSize() const { return IndexSize; } + + bool IsPresent( IndexType Index ) const; + KeyType GetKey( IndexType Index ) const; + + IndexType Top() const; + void Pop(); + + void Add( KeyType Key, IndexType Index ); + void Update( KeyType Key, IndexType Index ); + void Remove( IndexType Index ); + +protected: + void ResizeHeap( uint32 NewHeapSize ); + void ResizeIndexes( uint32 NewIndexSize ); + + void UpHeap( IndexType HeapIndex ); + void DownHeap( IndexType HeapIndex ); + + uint32 HeapNum; + uint32 HeapSize; + uint32 IndexSize; + + IndexType* Heap; + + KeyType* Keys; + IndexType* HeapIndexes; +}; + +template< typename KeyType, typename IndexType > +FORCEINLINE FBinaryHeap< KeyType, IndexType >::FBinaryHeap() + : HeapNum(0) + , HeapSize(0) + , IndexSize(0) + , Heap( nullptr ) + , Keys( nullptr ) + , HeapIndexes( nullptr ) +{} + +template< typename KeyType, typename IndexType > +FORCEINLINE FBinaryHeap< KeyType, IndexType >::FBinaryHeap( uint32 InHeapSize, uint32 InIndexSize ) + : HeapNum(0) + , HeapSize( InHeapSize ) + , IndexSize( InIndexSize ) +{ + Heap = new IndexType[ HeapSize ]; + Keys = new KeyType[ IndexSize ]; + HeapIndexes = new IndexType[ IndexSize ]; + + FMemory::Memset( HeapIndexes, 0xff, IndexSize * sizeof( IndexType ) ); +} + +template< typename KeyType, typename IndexType > +FORCEINLINE FBinaryHeap< KeyType, IndexType >::~FBinaryHeap() +{ + Free(); +} + +template< typename KeyType, typename IndexType > +FORCEINLINE void FBinaryHeap< KeyType, IndexType >::Clear() +{ + HeapNum = 0; + FMemory::Memset( HeapIndexes, 0xff, IndexSize * sizeof( IndexType ) ); +} + +template< typename KeyType, typename IndexType > +FORCEINLINE void FBinaryHeap< KeyType, IndexType >::Free() +{ + HeapNum = 0; + HeapSize = 0; + IndexSize = 0; + + delete[] Heap; + delete[] Keys; + delete[] HeapIndexes; + + Heap = nullptr; + Keys = nullptr; + HeapIndexes = nullptr; +} + +template< typename KeyType, typename IndexType > +void FBinaryHeap< KeyType, IndexType >::ResizeHeap( uint32 NewHeapSize ) +{ + checkSlow( NewHeapSize != HeapSize ); + + if( NewHeapSize == 0 ) + { + HeapNum = 0; + HeapSize = 0; + + delete[] Heap; + Heap = nullptr; + + return; + } + + IndexType* NewHeap = new IndexType[ NewHeapSize ]; + + if( HeapSize != 0 ) + { + FMemory::Memcpy( NewHeap, Heap, HeapSize * sizeof( IndexType ) ); + delete[] Heap; + } + + HeapNum = FMath::Min( HeapNum, NewHeapSize ); + HeapSize = NewHeapSize; + Heap = NewHeap; +} + +template< typename KeyType, typename IndexType > +void FBinaryHeap< KeyType, IndexType >::ResizeIndexes( uint32 NewIndexSize ) +{ + checkSlow( NewIndexSize != IndexSize ); + + if( NewIndexSize == 0 ) + { + IndexSize = 0; + + delete[] Keys; + delete[] HeapIndexes; + + Keys = nullptr; + HeapIndexes = nullptr; + + return; + } + + KeyType* NewKeys = new KeyType[ NewIndexSize ]; + IndexType* NewHeapIndexes = new IndexType[ NewIndexSize ]; + + if( IndexSize != 0 ) + { + check( NewIndexSize >= IndexSize ); + + for( uint32 i = 0; i < IndexSize; i++ ) + { + NewKeys[i] = Keys[i]; + NewHeapIndexes[i] = HeapIndexes[i]; + } + delete[] Keys; + delete[] HeapIndexes; + } + + for( uint32 i = IndexSize; i < NewIndexSize; i++ ) + { + NewHeapIndexes[i] = (IndexType)-1; + } + + IndexSize = NewIndexSize; + Keys = NewKeys; + HeapIndexes = NewHeapIndexes; +} + +template< typename KeyType, typename IndexType > +FORCEINLINE void FBinaryHeap< KeyType, IndexType >::Resize( uint32 NewHeapSize, uint32 NewIndexSize ) +{ + if( NewHeapSize != HeapSize ) + { + ResizeHeap( NewHeapSize ); + } + + if( NewIndexSize != IndexSize ) + { + ResizeIndexes( NewIndexSize ); + } +} + +template< typename KeyType, typename IndexType > +FORCEINLINE bool FBinaryHeap< KeyType, IndexType >::IsPresent( IndexType Index ) const +{ + checkSlow( Index < IndexSize ); + return HeapIndexes[ Index ] != (IndexType)-1; +} + +template< typename KeyType, typename IndexType > +FORCEINLINE KeyType FBinaryHeap< KeyType, IndexType >::GetKey( IndexType Index ) const +{ + checkSlow( IsPresent( Index ) ); + return Keys[ Index ]; +} + +template< typename KeyType, typename IndexType > +FORCEINLINE IndexType FBinaryHeap< KeyType, IndexType >::Top() const +{ + checkSlow( Heap ); + checkSlow( HeapNum > 0 ); + return Heap[0]; +} + +template< typename KeyType, typename IndexType > +FORCEINLINE void FBinaryHeap< KeyType, IndexType >::Pop() +{ + checkSlow( Heap ); + checkSlow( HeapNum > 0 ); + + IndexType Index = Heap[0]; + + Heap[0] = Heap[ --HeapNum ]; + HeapIndexes[ Heap[0] ] = 0; + HeapIndexes[ Index ] = (IndexType)-1; + + DownHeap(0); +} + +template< typename KeyType, typename IndexType > +FORCEINLINE void FBinaryHeap< KeyType, IndexType >::Add( KeyType Key, IndexType Index ) +{ + if( HeapNum == HeapSize ) + { + ResizeHeap( FMath::Max( 32u, HeapSize * 2 ) ); + } + + if( Index >= IndexSize ) + { + ResizeIndexes(FMath::Max(32u, FMath::RoundUpToPowerOfTwo(Index + 1))); + } + + checkSlow( !IsPresent( Index ) ); + + IndexType HeapIndex = HeapNum++; + Heap[ HeapIndex ] = Index; + + Keys[ Index ] = Key; + HeapIndexes[ Index ] = HeapIndex; + + UpHeap( HeapIndex ); +} + +template< typename KeyType, typename IndexType > +FORCEINLINE void FBinaryHeap< KeyType, IndexType >::Update( KeyType Key, IndexType Index ) +{ + checkSlow( Heap ); + checkSlow( IsPresent( Index ) ); + + Keys[ Index ] = Key; + + IndexType HeapIndex = HeapIndexes[ Index ]; + IndexType Parent = (HeapIndex - 1) >> 1; + if( HeapIndex > 0 && Key < Keys[ Heap[ Parent ] ] ) + { + UpHeap( HeapIndex ); + } + else + { + DownHeap( HeapIndex ); + } +} + +template< typename KeyType, typename IndexType > +FORCEINLINE void FBinaryHeap< KeyType, IndexType >::Remove( IndexType Index ) +{ + checkSlow( Heap ); + + if( !IsPresent( Index ) ) + { + return; + } + + KeyType Key = Keys[ Index ]; + IndexType HeapIndex = HeapIndexes[ Index ]; + + Heap[ HeapIndex ] = Heap[ --HeapNum ]; + HeapIndexes[ Heap[ HeapIndex ] ] = HeapIndex; + HeapIndexes[ Index ] = (IndexType)-1; + + if( Key < Keys[ Heap[ HeapIndex ] ] ) + { + DownHeap( HeapIndex ); + } + else + { + UpHeap( HeapIndex ); + } +} + +template< typename KeyType, typename IndexType > +void FBinaryHeap< KeyType, IndexType >::UpHeap( IndexType HeapIndex ) +{ + IndexType Moving = Heap[ HeapIndex ]; + IndexType i = HeapIndex; + IndexType Parent = (i - 1) >> 1; + + while( i > 0 && Keys[ Moving ] < Keys[ Heap[ Parent ] ] ) + { + Heap[i] = Heap[ Parent ]; + HeapIndexes[ Heap[i] ] = i; + + i = Parent; + Parent = (i - 1) >> 1; + } + + if( i != HeapIndex ) + { + Heap[i] = Moving; + HeapIndexes[ Heap[i] ] = i; + } +} + +template< typename KeyType, typename IndexType > +void FBinaryHeap< KeyType, IndexType >::DownHeap( IndexType HeapIndex ) +{ + IndexType Moving = Heap[ HeapIndex ]; + IndexType i = HeapIndex; + IndexType Left = (i << 1) + 1; + IndexType Right = Left + 1; + + while( Left < HeapNum ) + { + IndexType Smallest = Left; + if( Right < HeapNum ) + { + Smallest = ( Keys[ Heap[Left] ] < Keys[ Heap[Right] ] ) ? Left : Right; + } + + if( Keys[ Heap[Smallest] ] < Keys[ Moving ] ) + { + Heap[i] = Heap[ Smallest ]; + HeapIndexes[ Heap[i] ] = i; + + i = Smallest; + Left = (i << 1) + 1; + Right = Left + 1; + } + else + { + break; + } + } + + if( i != HeapIndex ) + { + Heap[i] = Moving; + HeapIndexes[ Heap[i] ] = i; + } +} diff --git a/Engine/Source/Runtime/Core/Public/Containers/BitArray.h b/Engine/Source/Runtime/Core/Public/Containers/BitArray.h index c8cbbabb001e..9f9618325077 100644 --- a/Engine/Source/Runtime/Core/Public/Containers/BitArray.h +++ b/Engine/Source/Runtime/Core/Public/Containers/BitArray.h @@ -6,7 +6,6 @@ #include "Misc/AssertionMacros.h" #include "HAL/UnrealMemory.h" #include "Templates/UnrealTypeTraits.h" -#include "Templates/AlignOf.h" #include "Templates/UnrealTemplate.h" #include "Containers/ContainerAllocationPolicies.h" #include "Serialization/Archive.h" @@ -422,20 +421,23 @@ public: */ void RemoveAt(int32 BaseIndex,int32 NumBitsToRemove = 1) { - check(BaseIndex >= 0 && BaseIndex + NumBitsToRemove <= NumBits); + check(BaseIndex >= 0 && NumBitsToRemove >= 0 && BaseIndex + NumBitsToRemove <= NumBits); - // Until otherwise necessary, this is an obviously correct implementation rather than an efficient implementation. - FIterator WriteIt(*this); - for(FConstIterator ReadIt(*this);ReadIt;++ReadIt) + if (BaseIndex + NumBitsToRemove != NumBits) { - // If this bit isn't being removed, write it back to the array at its potentially new index. - if(ReadIt.GetIndex() < BaseIndex || ReadIt.GetIndex() >= BaseIndex + NumBitsToRemove) + // Until otherwise necessary, this is an obviously correct implementation rather than an efficient implementation. + FIterator WriteIt(*this); + for(FConstIterator ReadIt(*this);ReadIt;++ReadIt) { - if(WriteIt.GetIndex() != ReadIt.GetIndex()) + // If this bit isn't being removed, write it back to the array at its potentially new index. + if(ReadIt.GetIndex() < BaseIndex || ReadIt.GetIndex() >= BaseIndex + NumBitsToRemove) { - WriteIt.GetValue() = (bool)ReadIt.GetValue(); + if(WriteIt.GetIndex() != ReadIt.GetIndex()) + { + WriteIt.GetValue() = (bool)ReadIt.GetValue(); + } + ++WriteIt; } - ++WriteIt; } } NumBits -= NumBitsToRemove; @@ -449,7 +451,7 @@ public: */ void RemoveAtSwap( int32 BaseIndex, int32 NumBitsToRemove=1 ) { - check(BaseIndex >= 0 && BaseIndex + NumBitsToRemove <= NumBits); + check(BaseIndex >= 0 && NumBitsToRemove >= 0 && BaseIndex + NumBitsToRemove <= NumBits); if( BaseIndex < NumBits - NumBitsToRemove ) { // Copy bits from the end to the region we are removing @@ -469,8 +471,9 @@ public: #endif } } + // Remove the bits from the end of the array. - RemoveAt(NumBits - NumBitsToRemove, NumBitsToRemove); + NumBits -= NumBitsToRemove; } @@ -779,7 +782,7 @@ public: TConstSetBitIterator(const TBitArray& InArray,int32 StartIndex = 0) : FRelativeBitReference(StartIndex) , Array (InArray) - , UnvisitedBitMask ((~0) << (StartIndex & (NumBitsPerDWORD - 1))) + , UnvisitedBitMask ((~0U) << (StartIndex & (NumBitsPerDWORD - 1))) , CurrentBitIndex (StartIndex) , BaseBitIndex (StartIndex & ~(NumBitsPerDWORD - 1)) { @@ -897,7 +900,7 @@ public: : FRelativeBitReference(StartIndex) , ArrayA(InArrayA) , ArrayB(InArrayB) - , UnvisitedBitMask((~0) << (StartIndex & (NumBitsPerDWORD - 1))) + , UnvisitedBitMask((~0U) << (StartIndex & (NumBitsPerDWORD - 1))) , CurrentBitIndex(StartIndex) , BaseBitIndex(StartIndex & ~(NumBitsPerDWORD - 1)) { @@ -1063,7 +1066,7 @@ private: // Check that the class footprint is the same static_assert(sizeof (ScriptType) == sizeof (RealType), "FScriptBitArray's size doesn't match TBitArray"); - static_assert(ALIGNOF(ScriptType) == ALIGNOF(RealType), "FScriptBitArray's alignment doesn't match TBitArray"); + static_assert(alignof(ScriptType) == alignof(RealType), "FScriptBitArray's alignment doesn't match TBitArray"); // Check member sizes static_assert(sizeof(DeclVal().AllocatorInstance) == sizeof(DeclVal().AllocatorInstance), "FScriptBitArray's AllocatorInstance member size does not match TBitArray's"); @@ -1093,11 +1096,11 @@ private: sizeof(uint32) ); MaxBits = MaxDWORDs * NumBitsPerDWORD; - const int32 PreviousNumDWORDs = FMath::DivideAndRoundUp(PreviousNumBits, NumBitsPerDWORD); + const uint32 PreviousNumDWORDs = FMath::DivideAndRoundUp(PreviousNumBits, NumBitsPerDWORD); AllocatorInstance.ResizeAllocation(PreviousNumDWORDs, MaxDWORDs, sizeof(uint32)); - if (MaxDWORDs && MaxDWORDs - PreviousNumDWORDs > 0) + if (MaxDWORDs && MaxDWORDs > PreviousNumDWORDs) { // Reset the newly allocated slack DWORDs. FMemory::Memzero((uint32*)AllocatorInstance.GetAllocation() + PreviousNumDWORDs, (MaxDWORDs - PreviousNumDWORDs) * sizeof(uint32)); @@ -1112,9 +1115,9 @@ private: sizeof(uint32) ); MaxBits = MaxDWORDs * NumBitsPerDWORD; - const int32 PreviousNumDWORDs = FMath::DivideAndRoundUp(PreviousNumBits, NumBitsPerDWORD); + const uint32 PreviousNumDWORDs = FMath::DivideAndRoundUp(PreviousNumBits, NumBitsPerDWORD); AllocatorInstance.ResizeAllocation(PreviousNumDWORDs, MaxDWORDs, sizeof(uint32)); - if (MaxDWORDs && MaxDWORDs - PreviousNumDWORDs > 0) + if (MaxDWORDs && MaxDWORDs > PreviousNumDWORDs) { // Reset the newly allocated slack DWORDs. FMemory::Memzero((uint32*)AllocatorInstance.GetAllocation() + PreviousNumDWORDs, (MaxDWORDs - PreviousNumDWORDs) * sizeof(uint32)); diff --git a/Engine/Source/Runtime/Core/Public/Containers/ChunkedArray.h b/Engine/Source/Runtime/Core/Public/Containers/ChunkedArray.h index b6d3b132302d..e12aa0bda3f5 100644 --- a/Engine/Source/Runtime/Core/Public/Containers/ChunkedArray.h +++ b/Engine/Source/Runtime/Core/Public/Containers/ChunkedArray.h @@ -8,6 +8,43 @@ #include "Containers/IndirectArray.h" +namespace UE4ChunkedArray_Private +{ + template + struct TChunkedArrayIterator + { + TChunkedArrayIterator(ChunkType** InChunk, ElementType* InElem) + : Elem (InElem) + , Chunk(InChunk) + { + + } + + ElementType* Elem; + ChunkType** Chunk; + + ElementType& operator*() const + { + return *Elem; + } + + void operator++() + { + ++Elem; + if (Elem == (*Chunk)->Elements + NumElementsPerChunk) + { + ++Chunk; + Elem = (*Chunk)->Elements; + } + } + + friend bool operator!=(const TChunkedArrayIterator& Lhs, const TChunkedArrayIterator& Rhs) + { + return Lhs.Elem != Rhs.Elem; + } + }; +} + /** An array that uses multiple allocations to avoid allocation failure due to fragmentation. */ template class TChunkedArray @@ -235,6 +272,36 @@ protected: /** The number of elements in the array. */ int32 NumElements; + +private: + typedef UE4ChunkedArray_Private::TChunkedArrayIterator< FChunk, ElementType, NumElementsPerChunk> FIterType; + typedef UE4ChunkedArray_Private::TChunkedArrayIterator FConstIterType; + + friend FIterType begin(TChunkedArray& Array) + { + FChunk** ChunkPtr = Array.Chunks.GetData(); + return FIterType(ChunkPtr, ChunkPtr ? (*ChunkPtr)->Elements : nullptr); + } + + friend FConstIterType begin(const TChunkedArray& Array) + { + const FChunk** ChunkPtr = Array.Chunks.GetData(); + return FConstIterType(ChunkPtr, ChunkPtr ? (*ChunkPtr)->Elements : nullptr); + } + + friend FIterType end(TChunkedArray& Array) + { + int32 Num = Array.NumElements; + FChunk** ChunkPtr = Array.Chunks.GetData() + (Num / NumElementsPerChunk); + return FIterType(ChunkPtr, ChunkPtr ? (*ChunkPtr)->Elements + (Num % NumElementsPerChunk) : nullptr); + } + + friend FConstIterType end(const TChunkedArray& Array) + { + int32 Num = Array.NumElements; + const FChunk** ChunkPtr = Array.Chunks.GetData() + (Num / NumElementsPerChunk); + return FConstIterType(ChunkPtr, ChunkPtr ? (*ChunkPtr)->Elements + (Num % NumElementsPerChunk) : nullptr); + } }; diff --git a/Engine/Source/Runtime/Core/Public/Containers/ContainersFwd.h b/Engine/Source/Runtime/Core/Public/Containers/ContainersFwd.h index f45055f214f6..4ee073ccb511 100644 --- a/Engine/Source/Runtime/Core/Public/Containers/ContainersFwd.h +++ b/Engine/Source/Runtime/Core/Public/Containers/ContainersFwd.h @@ -12,3 +12,5 @@ template class TTransArray; template struct TDefaultMapHashableKeyFuncs; template > class TMap; template > class TMultiMap; +template struct TLess; +template > class TSortedMap; diff --git a/Engine/Source/Runtime/Core/Public/Containers/DynamicRHIResourceArray.h b/Engine/Source/Runtime/Core/Public/Containers/DynamicRHIResourceArray.h index 693738939cdc..a184acc7738a 100644 --- a/Engine/Source/Runtime/Core/Public/Containers/DynamicRHIResourceArray.h +++ b/Engine/Source/Runtime/Core/Public/Containers/DynamicRHIResourceArray.h @@ -77,6 +77,9 @@ public: #endif + virtual ~TResourceArray() { } + + // FResourceArrayInterface /** diff --git a/Engine/Source/Runtime/Core/Public/Containers/HashTable.h b/Engine/Source/Runtime/Core/Public/Containers/HashTable.h new file mode 100644 index 000000000000..bbb581b04fab --- /dev/null +++ b/Engine/Source/Runtime/Core/Public/Containers/HashTable.h @@ -0,0 +1,265 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +/*----------------------------------------------------------------------------- + Statically sized hash table, used to index another data structure. + Vastly simpler and faster than TMap. + + Example find: + + uint16 Key = HashFunction( ID ); + for( uint16 i = HashTable.First( Key ); HashTable.IsValid( i ); i = HashTable.Next( i ) ) + { + if( Array[i].ID == ID ) + { + return Array[i]; + } + } +-----------------------------------------------------------------------------*/ +template< uint16 HashSize, uint16 IndexSize > +class TStaticHashTable +{ +public: + TStaticHashTable(); + + void Clear(); + + // Functions used to search + uint16 First( uint16 Key ) const; + uint16 Next( uint16 Index ) const; + bool IsValid( uint16 Index ) const; + + void Add( uint16 Key, uint16 Index ); + void Remove( uint16 Key, uint16 Index ); + +protected: + uint16 Hash[ HashSize ]; + uint16 NextIndex[ IndexSize ]; +}; + +template< uint16 HashSize, uint16 IndexSize > +FORCEINLINE TStaticHashTable< HashSize, IndexSize >::TStaticHashTable() +{ + static_assert( ( HashSize & (HashSize - 1) ) == 0, "Hash size must be power of 2" ); + static_assert( IndexSize - 1 < 0xffff, "Index 0xffff is reserved" ); + Clear(); +} + +template< uint16 HashSize, uint16 IndexSize > +FORCEINLINE void TStaticHashTable< HashSize, IndexSize >::Clear() +{ + FMemory::Memset( Hash, 0xff, HashSize * 2 ); +} + +// First in hash chain +template< uint16 HashSize, uint16 IndexSize > +FORCEINLINE uint16 TStaticHashTable< HashSize, IndexSize >::First( uint16 Key ) const +{ + Key &= HashSize - 1; + return Hash[ Key ]; +} + +// Next in hash chain +template< uint16 HashSize, uint16 IndexSize > +FORCEINLINE uint16 TStaticHashTable< HashSize, IndexSize >::Next( uint16 Index ) const +{ + checkSlow( Index < IndexSize ); + return NextIndex[ Index ]; +} + +template< uint16 HashSize, uint16 IndexSize > +FORCEINLINE bool TStaticHashTable< HashSize, IndexSize >::IsValid( uint16 Index ) const +{ + return Index != 0xffff; +} + +template< uint16 HashSize, uint16 IndexSize > +FORCEINLINE void TStaticHashTable< HashSize, IndexSize >::Add( uint16 Key, uint16 Index ) +{ + checkSlow( Index < IndexSize ); + + Key &= HashSize - 1; + NextIndex[ Index ] = Hash[ Key ]; + Hash[ Key ] = Index; +} + +template< uint16 HashSize, uint16 IndexSize > +inline void TStaticHashTable< HashSize, IndexSize >::Remove( uint16 Key, uint16 Index ) +{ + checkSlow( Index < IndexSize ); + + Key &= HashSize - 1; + + if( Hash[Key] == Index ) + { + // Head of chain + Hash[Key] = NextIndex[ Index ]; + } + else + { + for( uint16 i = Hash[Key]; IsValid(i); i = NextIndex[i] ) + { + if( NextIndex[i] == Index ) + { + // Next = Next->Next + NextIndex[i] = NextIndex[ Index ]; + break; + } + } + } +} + +/*----------------------------------------------------------------------------- + Dynamically sized hash table, used to index another data structure. + Vastly simpler and faster than TMap. + + Example find: + + uint32 Key = HashFunction( ID ); + for( uint32 i = HashTable.First( Key ); HashTable.IsValid( i ); i = HashTable.Next( i ) ) + { + if( Array[i].ID == ID ) + { + return Array[i]; + } + } +-----------------------------------------------------------------------------*/ +class FHashTable +{ +public: + FHashTable( uint16 InHashSize = 1024, uint32 InIndexSize = 0 ); + ~FHashTable(); + + void Clear(); + void Free(); + CORE_API void Resize( uint32 NewIndexSize ); + + // Functions used to search + uint32 First( uint16 Key ) const; + uint32 Next( uint32 Index ) const; + bool IsValid( uint32 Index ) const; + + void Add( uint16 Key, uint32 Index ); + void Remove( uint16 Key, uint32 Index ); + +protected: + // Avoids allocating hash until first add + CORE_API static uint32 EmptyHash[1]; + + uint16 HashSize; + uint16 HashMask; + uint32 IndexSize; + + uint32* Hash; + uint32* NextIndex; +}; + + +FORCEINLINE FHashTable::FHashTable( uint16 InHashSize, uint32 InIndexSize ) + : HashSize( InHashSize ) + , HashMask( 0 ) + , IndexSize( InIndexSize ) + , Hash( EmptyHash ) + , NextIndex( NULL ) +{ + check( FMath::IsPowerOfTwo( HashSize ) ); + + if( IndexSize ) + { + HashMask = HashSize - 1; + + Hash = new uint32[ HashSize ]; + NextIndex = new uint32[ IndexSize ]; + + FMemory::Memset( Hash, 0xff, HashSize * 4 ); + } +} + +FORCEINLINE FHashTable::~FHashTable() +{ + Free(); +} + +FORCEINLINE void FHashTable::Clear() +{ + if( IndexSize ) + { + FMemory::Memset( Hash, 0xff, HashSize * 4 ); + } +} + +FORCEINLINE void FHashTable::Free() +{ + if( IndexSize ) + { + HashMask = 0; + IndexSize = 0; + + delete[] Hash; + Hash = EmptyHash; + + delete[] NextIndex; + NextIndex = NULL; + } +} + +// First in hash chain +FORCEINLINE uint32 FHashTable::First( uint16 Key ) const +{ + Key &= HashMask; + return Hash[ Key ]; +} + +// Next in hash chain +FORCEINLINE uint32 FHashTable::Next( uint32 Index ) const +{ + checkSlow( Index < IndexSize ); + return NextIndex[ Index ]; +} + +FORCEINLINE bool FHashTable::IsValid( uint32 Index ) const +{ + return Index != ~0u; +} + +FORCEINLINE void FHashTable::Add( uint16 Key, uint32 Index ) +{ + if( Index >= IndexSize ) + { + Resize(FMath::Max(32u, FMath::RoundUpToPowerOfTwo(Index + 1))); + } + + Key &= HashMask; + NextIndex[ Index ] = Hash[ Key ]; + Hash[ Key ] = Index; +} + +inline void FHashTable::Remove( uint16 Key, uint32 Index ) +{ + if( Index >= IndexSize ) + { + return; + } + + Key &= HashMask; + + if( Hash[Key] == Index ) + { + // Head of chain + Hash[Key] = NextIndex[ Index ]; + } + else + { + for( uint32 i = Hash[Key]; IsValid(i); i = NextIndex[i] ) + { + if( NextIndex[i] == Index ) + { + // Next = Next->Next + NextIndex[i] = NextIndex[ Index ]; + break; + } + } + } +} diff --git a/Engine/Source/Runtime/Core/Public/Containers/LockFreeFixedSizeAllocator.h b/Engine/Source/Runtime/Core/Public/Containers/LockFreeFixedSizeAllocator.h index dfc9c57f8c77..842a3214ea4e 100644 --- a/Engine/Source/Runtime/Core/Public/Containers/LockFreeFixedSizeAllocator.h +++ b/Engine/Source/Runtime/Core/Public/Containers/LockFreeFixedSizeAllocator.h @@ -7,91 +7,133 @@ #include "Misc/NoopCounter.h" #include "Containers/LockFreeList.h" - - -#if USE_NEW_LOCK_FREE_LISTS /** - * Thread safe, lock free pooling allocator of fixed size blocks that - * never returns free space until program shutdown. - * alignment isn't handled, assumes FMemory::Malloc will work - */ -template -class TLockFreeFixedSizeAllocator -{ - /** - * Fake struct to use as a type for recycling memory blocks with intrusive lockfree lists - */ - struct FFakeType - { - FFakeType* LockFreePointerQueueNext; - }; +* Thread safe, lock free pooling allocator of fixed size blocks that +* never returns free space, even at shutdown +* alignment isn't handled, assumes FMemory::Malloc will work +*/ +#define USE_NIEVE_TLockFreeFixedSizeAllocator_TLSCacheBase (0) // this is useful for find who really leaked +template +class TLockFreeFixedSizeAllocator_TLSCacheBase : public FNoncopyable +{ + enum + { + NUM_PER_BUNDLE = 32, + }; public: - /** Destructor, returns all memory via FMemory::Free **/ - ~TLockFreeFixedSizeAllocator() + TLockFreeFixedSizeAllocator_TLSCacheBase() { - check(!NumUsed.GetValue()); - while (void* Mem = FreeList.Pop()) - { - FMemory::Free(Mem); - NumFree.Decrement(); - } - check(!NumFree.GetValue()); + static_assert(SIZE >= sizeof(void*) && SIZE % sizeof(void*) == 0, "Blocks in TLockFreeFixedSizeAllocator must be at least the size of a pointer."); + check(IsInGameThread()); + TlsSlot = FPlatformTLS::AllocTlsSlot(); + check(FPlatformTLS::IsValidTlsSlot(TlsSlot)); + } + /** Destructor, leaks all of the memory **/ + ~TLockFreeFixedSizeAllocator_TLSCacheBase() + { + FPlatformTLS::FreeTlsSlot(TlsSlot); + TlsSlot = 0; } /** - * Allocates a memory block of size SIZE. - * - * @return Pointer to the allocated memory. - * @see Free - */ - void* Allocate() + * Allocates a memory block of size SIZE. + * + * @return Pointer to the allocated memory. + * @see Free + */ + FORCEINLINE void* Allocate() { - static_assert(sizeof(FFakeType) <= SIZE, "can't make an efficient recycler for blocks smaller than a pointer"); +#if USE_NIEVE_TLockFreeFixedSizeAllocator_TLSCacheBase + return FMemory::Malloc(SIZE); +#else + FThreadLocalCache& TLS = GetTLS(); + + if (!TLS.PartialBundle) + { + if (TLS.FullBundle) + { + TLS.PartialBundle = TLS.FullBundle; + TLS.FullBundle = nullptr; + } + else + { + TLS.PartialBundle = GlobalFreeListBundles.Pop(); + if (!TLS.PartialBundle) + { + TLS.PartialBundle = (void**)FMemory::Malloc(SIZE * NUM_PER_BUNDLE); + void **Next = TLS.PartialBundle; + for (int32 Index = 0; Index < NUM_PER_BUNDLE - 1; Index++) + { + void* NextNext = (void*)(((uint8*)Next) + SIZE); + *Next = NextNext; + Next = (void**)NextNext; + } + *Next = nullptr; + NumFree.Add(NUM_PER_BUNDLE); + } + } + TLS.NumPartial = NUM_PER_BUNDLE; + } NumUsed.Increment(); - void *Memory = FreeList.Pop(); - if (Memory) - { - NumFree.Decrement(); - } - else - { - Memory = FMemory::Malloc(SIZE); - } - return Memory; + NumFree.Decrement(); + void* Result = (void*)TLS.PartialBundle; + TLS.PartialBundle = (void**)*TLS.PartialBundle; + TLS.NumPartial--; + check(TLS.NumPartial >= 0 && ((!!TLS.NumPartial) == (!!TLS.PartialBundle))); + return Result; +#endif } /** - * Puts a memory block previously obtained from Allocate() back on the free list for future use. - * - * @param Item The item to free. - * @see Allocate - */ - void Free(void *Item) + * Puts a memory block previously obtained from Allocate() back on the free list for future use. + * + * @param Item The item to free. + * @see Allocate + */ + FORCEINLINE void Free(void *Item) { +#if USE_NIEVE_TLockFreeFixedSizeAllocator_TLSCacheBase + return FMemory::Free(Item); +#else NumUsed.Decrement(); - FreeList.Push((FFakeType*)Item); NumFree.Increment(); + FThreadLocalCache& TLS = GetTLS(); + if (TLS.NumPartial >= NUM_PER_BUNDLE) + { + if (TLS.FullBundle) + { + GlobalFreeListBundles.Push(TLS.FullBundle); + //TLS.FullBundle = nullptr; + } + TLS.FullBundle = TLS.PartialBundle; + TLS.PartialBundle = nullptr; + TLS.NumPartial = 0; + } + *(void**)Item = (void*)TLS.PartialBundle; + TLS.PartialBundle = (void**)Item; + TLS.NumPartial++; +#endif } /** - * Gets the number of allocated memory blocks that are currently in use. - * - * @return Number of used memory blocks. - * @see GetNumFree - */ + * Gets the number of allocated memory blocks that are currently in use. + * + * @return Number of used memory blocks. + * @see GetNumFree + */ const TTrackingCounter& GetNumUsed() const { return NumUsed; } /** - * Gets the number of allocated memory blocks that are currently unused. - * - * @return Number of unused memory blocks. - * @see GetNumUsed - */ + * Gets the number of allocated memory blocks that are currently unused. + * + * @return Number of unused memory blocks. + * @see GetNumUsed + */ const TTrackingCounter& GetNumFree() const { return NumFree; @@ -99,17 +141,46 @@ public: private: - /** Lock free list of free memory blocks. */ - FLockFreePointerListFIFOIntrusive FreeList; + /** struct for the TLS cache. */ + struct FThreadLocalCache + { + void **FullBundle; + void **PartialBundle; + int32 NumPartial; + + FThreadLocalCache() + : FullBundle(nullptr) + , PartialBundle(nullptr) + , NumPartial(0) + { + } + }; + + FThreadLocalCache& GetTLS() + { + checkSlow(FPlatformTLS::IsValidTlsSlot(TlsSlot)); + FThreadLocalCache* TLS = (FThreadLocalCache*)FPlatformTLS::GetTlsValue(TlsSlot); + if (!TLS) + { + TLS = new FThreadLocalCache(); + FPlatformTLS::SetTlsValue(TlsSlot, TLS); + } + return *TLS; + } + + /** Slot for TLS struct. */ + uint32 TlsSlot; + + /** Lock free list of free memory blocks, these are all linked into a bundle of NUM_PER_BUNDLE. */ + TBundleRecycler GlobalFreeListBundles; /** Total number of blocks outstanding and not in the free list. */ - TTrackingCounter NumUsed; + TTrackingCounter NumUsed; /** Total number of blocks in the free list. */ TTrackingCounter NumFree; }; -#else /** * Thread safe, lock free pooling allocator of fixed size blocks that * never returns free space until program shutdown. @@ -199,7 +270,6 @@ private: /** Total number of blocks in the free list. */ TTrackingCounter NumFree; }; -#endif /** * Thread safe, lock free pooling allocator of fixed size blocks that diff --git a/Engine/Source/Runtime/Core/Public/Containers/LockFreeList.h b/Engine/Source/Runtime/Core/Public/Containers/LockFreeList.h index e55ec64cb1fe..d827581e284c 100644 --- a/Engine/Source/Runtime/Core/Public/Containers/LockFreeList.h +++ b/Engine/Source/Runtime/Core/Public/Containers/LockFreeList.h @@ -8,39 +8,936 @@ #include "CoreGlobals.h" #include "HAL/ThreadSafeCounter.h" #include "Misc/NoopCounter.h" +#include "Containers/ContainersFwd.h" CORE_API DECLARE_LOG_CATEGORY_EXTERN(LogLockFreeList, Log, All); // what level of checking to perform...normally checkLockFreePointerList but could be ensure or check #define checkLockFreePointerList checkSlow -//#define checkLockFreePointerList(x) ((x)||((*(char*)3) = 0)) +//#define checkLockFreePointerList(x) ((x)||((*(char*)3) = 0) -#define MONITOR_LINK_ALLOCATION (0) -#if MONITOR_LINK_ALLOCATION==1 - typedef FThreadSafeCounter FLockFreeListCounter; +#if !UE_BUILD_SHIPPING && !UE_BUILD_TEST + + CORE_API void DoTestCriticalStall(); + extern CORE_API int32 GTestCriticalStalls; + + FORCEINLINE void TestCriticalStall() + { + if (GTestCriticalStalls) + { + DoTestCriticalStall(); + } + } #else - typedef FNoopCounter FLockFreeListCounter; -#endif // MONITOR_LINK_ALLOCATION==1 + FORCEINLINE void TestCriticalStall() + { + } +#endif -/** Enumerates lock free list alignments. */ -namespace ELockFreeAligment +CORE_API void LockFreeTagCounterHasOverflowed(); +CORE_API void LockFreeLinksExhausted(uint32 TotalNum); +CORE_API void* LockFreeAllocLinks(SIZE_T AllocSize); +CORE_API void LockFreeFreeLinks(SIZE_T AllocSize, void* Ptr); + +#define MAX_LOCK_FREE_LINKS_AS_BITS (26) +#define MAX_LOCK_FREE_LINKS (1 << 26) + +template +struct FPaddingForCacheContention +{ + uint8 PadToAvoidContention[TPaddingForCacheContention]; +}; + +template<> +struct FPaddingForCacheContention<0> +{ +}; + +template +class TLockFreeAllocOnceIndexedAllocator { enum { - LF64bit = 8, - LF128bit = 16, + MaxBlocks = (MaxTotalItems + ItemsPerPage - 1) / ItemsPerPage }; -} +public: -/** Whether to use the lock free list based on 128-bit atomics. */ -#define USE_LOCKFREELIST_128 (0/*PLATFORM_HAS_128BIT_ATOMICS*/) + TLockFreeAllocOnceIndexedAllocator() + { + NextIndex.Increment(); // skip the null ptr + for (uint32 Index = 0; Index < MaxBlocks; Index++) + { + Pages[Index] = nullptr; + } + } -#if USE_LOCKFREELIST_128==1 -#include "LockFreeVoidPointerListBase128.h" -#else -#include "Containers/LockFreeVoidPointerListBase.h" -#endif + FORCEINLINE uint32 Alloc(uint32 Count = 1) + { + uint32 FirstItem = NextIndex.Add(Count); + if (FirstItem + Count > MaxTotalItems) + { + LockFreeLinksExhausted(MaxTotalItems); + } + for (uint32 CurrentItem = FirstItem; CurrentItem < FirstItem + Count; CurrentItem++) + { + new (GetRawItem(CurrentItem)) T(); + } + return FirstItem; + } + FORCEINLINE T* GetItem(uint32 Index) + { + if (!Index) + { + return nullptr; + } + uint32 BlockIndex = Index / ItemsPerPage; + uint32 SubIndex = Index % ItemsPerPage; + checkLockFreePointerList(Index < (uint32)NextIndex.GetValue() && Index < MaxTotalItems && BlockIndex < MaxBlocks && Pages[BlockIndex]); + return Pages[BlockIndex] + SubIndex; + } + +private: + void* GetRawItem(uint32 Index) + { + uint32 BlockIndex = Index / ItemsPerPage; + uint32 SubIndex = Index % ItemsPerPage; + checkLockFreePointerList(Index && Index < (uint32)NextIndex.GetValue() && Index < MaxTotalItems && BlockIndex < MaxBlocks); + if (!Pages[BlockIndex]) + { + T* NewBlock = (T*)LockFreeAllocLinks(ItemsPerPage * sizeof(T)); + checkLockFreePointerList(IsAligned(NewBlock, alignof(T))); + if (FPlatformAtomics::InterlockedCompareExchangePointer((void**)&Pages[BlockIndex], NewBlock, nullptr) != nullptr) + { + // we lost discard block + checkLockFreePointerList(Pages[BlockIndex] && Pages[BlockIndex] != NewBlock); + LockFreeFreeLinks(ItemsPerPage * sizeof(T), NewBlock); + } + else + { + checkLockFreePointerList(Pages[BlockIndex]); + } + } + return (void*)(Pages[BlockIndex] + SubIndex); + } + + uint8 PadToAvoidContention0[PLATFORM_CACHE_LINE_SIZE]; + FThreadSafeCounter NextIndex; + uint8 PadToAvoidContention1[PLATFORM_CACHE_LINE_SIZE]; + T* Pages[MaxBlocks]; + uint8 PadToAvoidContention2[PLATFORM_CACHE_LINE_SIZE]; +}; + + +#define MAX_TagBitsValue (uint64(1) << (64 - MAX_LOCK_FREE_LINKS_AS_BITS)) +struct FIndexedLockFreeLink; + + +MS_ALIGN(8) +struct FIndexedPointer +{ + // no constructor, intentionally. We need to keep the ABA double counter in tact + + // This should only be used for FIndexedPointer's with no outstanding concurrency. + // Not recycled links, for example. + void Init() + { + static_assert(((MAX_LOCK_FREE_LINKS - 1) & MAX_LOCK_FREE_LINKS) == 0, "MAX_LOCK_FREE_LINKS must be a power of two"); + Ptrs = 0; + } + FORCEINLINE void SetAll(uint32 Ptr, uint64 CounterAndState) + { + checkLockFreePointerList(Ptr < MAX_LOCK_FREE_LINKS && CounterAndState < (uint64(1) << (64 - MAX_LOCK_FREE_LINKS_AS_BITS))); + Ptrs = (uint64(Ptr) | (CounterAndState << MAX_LOCK_FREE_LINKS_AS_BITS)); + } + + FORCEINLINE uint32 GetPtr() const + { + return uint32(Ptrs & (MAX_LOCK_FREE_LINKS - 1)); + } + + FORCEINLINE void SetPtr(uint32 To) + { + SetAll(To, GetCounterAndState()); + } + + FORCEINLINE uint64 GetCounterAndState() const + { + return (Ptrs >> MAX_LOCK_FREE_LINKS_AS_BITS); + } + + FORCEINLINE void SetCounterAndState(uint64 To) + { + SetAll(GetPtr(), To); + } + + FORCEINLINE void AdvanceCounterAndState(const FIndexedPointer &From, uint64 TABAInc) + { + SetCounterAndState(From.GetCounterAndState() + TABAInc); + if (UNLIKELY(GetCounterAndState() < From.GetCounterAndState())) + { + // this is not expected to be a problem and it is not expected to happen very often. When it does happen, we will sleep as an extra precaution. + LockFreeTagCounterHasOverflowed(); + } + } + + template + FORCEINLINE uint64 GetState() const + { + return GetCounterAndState() & (TABAInc - 1); + } + + template + FORCEINLINE void SetState(uint64 Value) + { + checkLockFreePointerList(Value < TABAInc); + SetCounterAndState((GetCounterAndState() & ~(TABAInc - 1)) | Value); + } + + FORCEINLINE void AtomicRead(const FIndexedPointer& Other) + { + checkLockFreePointerList(IsAligned(&Ptrs, 8) && IsAligned(&Other.Ptrs, 8)); + Ptrs = uint64(FPlatformAtomics::AtomicRead64((volatile const int64*)&Other.Ptrs)); + TestCriticalStall(); + } + + FORCEINLINE bool InterlockedCompareExchange(const FIndexedPointer& Exchange, const FIndexedPointer& Comparand) + { + TestCriticalStall(); + return uint64(FPlatformAtomics::InterlockedCompareExchange((volatile int64*)&Ptrs, Exchange.Ptrs, Comparand.Ptrs)) == Comparand.Ptrs; + } + + FORCEINLINE bool operator==(const FIndexedPointer& Other) const + { + return Ptrs == Other.Ptrs; + } + FORCEINLINE bool operator!=(const FIndexedPointer& Other) const + { + return Ptrs != Other.Ptrs; + } + +private: + uint64 Ptrs; + +} GCC_ALIGN(8); + +struct FIndexedLockFreeLink +{ + FIndexedPointer DoubleNext; + void *Payload; + uint32 SingleNext; +}; + +// there is a version of this code that uses 128 bit atomics to avoid the indirection, that is why we have this policy class at all. +struct FLockFreeLinkPolicy +{ + enum + { + MAX_BITS_IN_TLinkPtr = MAX_LOCK_FREE_LINKS_AS_BITS + }; + typedef FIndexedPointer TDoublePtr; + typedef FIndexedLockFreeLink TLink; + typedef uint32 TLinkPtr; + typedef TLockFreeAllocOnceIndexedAllocator TAllocator; + + static FORCEINLINE FIndexedLockFreeLink* DerefLink(uint32 Ptr) + { + return LinkAllocator.GetItem(Ptr); + } + static FORCEINLINE FIndexedLockFreeLink* IndexToLink(uint32 Index) + { + return LinkAllocator.GetItem(Index); + } + static FORCEINLINE uint32 IndexToPtr(uint32 Index) + { + return Index; + } + + CORE_API static uint32 AllocLockFreeLink(); + CORE_API static void FreeLockFreeLink(uint32 Item); + CORE_API static TAllocator LinkAllocator; +}; + +template +class FLockFreePointerListLIFORoot : public FNoncopyable +{ + typedef FLockFreeLinkPolicy::TDoublePtr TDoublePtr; + typedef FLockFreeLinkPolicy::TLink TLink; + typedef FLockFreeLinkPolicy::TLinkPtr TLinkPtr; + +public: + FORCEINLINE FLockFreePointerListLIFORoot() + { + // We want to make sure we have quite a lot of extra counter values to avoid the ABA problem. This could probably be relaxed, but eventually it will be dangerous. + // The question is "how many queue operations can a thread starve for". + static_assert(MAX_TagBitsValue / TABAInc >= (1 << 23), "risk of ABA problem"); + static_assert((TABAInc & (TABAInc - 1)) == 0, "must be power of two"); + Reset(); + } + + void Reset() + { + Head.Init(); + } + + void Push(TLinkPtr Item) + { + while (true) + { + TDoublePtr LocalHead; + LocalHead.AtomicRead(Head); + TDoublePtr NewHead; + NewHead.AdvanceCounterAndState(LocalHead, TABAInc); + NewHead.SetPtr(Item); + FLockFreeLinkPolicy::DerefLink(Item)->SingleNext = LocalHead.GetPtr(); + if (Head.InterlockedCompareExchange(NewHead, LocalHead)) + { + break; + } + } + } + + bool PushIf(TFunctionRef AllocateIfOkToPush) + { + static_assert(TABAInc > 1, "method should not be used for lists without state"); + while (true) + { + TDoublePtr LocalHead; + LocalHead.AtomicRead(Head); + uint64 LocalState = LocalHead.GetState(); + TLinkPtr Item = AllocateIfOkToPush(LocalState); + if (!Item) + { + return false; + } + + TDoublePtr NewHead; + NewHead.AdvanceCounterAndState(LocalHead, TABAInc); + FLockFreeLinkPolicy::DerefLink(Item)->SingleNext = LocalHead.GetPtr(); + NewHead.SetPtr(Item); + if (Head.InterlockedCompareExchange(NewHead, LocalHead)) + { + break; + } + } + return true; + } + + + TLinkPtr Pop() + { + TLinkPtr Item = 0; + while (true) + { + TDoublePtr LocalHead; + LocalHead.AtomicRead(Head); + Item = LocalHead.GetPtr(); + if (!Item) + { + break; + } + TDoublePtr NewHead; + NewHead.AdvanceCounterAndState(LocalHead, TABAInc); + TLink* ItemP = FLockFreeLinkPolicy::DerefLink(Item); + NewHead.SetPtr(ItemP->SingleNext); + if (Head.InterlockedCompareExchange(NewHead, LocalHead)) + { + ItemP->SingleNext = 0; + break; + } + } + return Item; + } + + TLinkPtr PopAll() + { + TLinkPtr Item = 0; + while (true) + { + TDoublePtr LocalHead; + LocalHead.AtomicRead(Head); + Item = LocalHead.GetPtr(); + if (!Item) + { + break; + } + TDoublePtr NewHead; + NewHead.AdvanceCounterAndState(LocalHead, TABAInc); + NewHead.SetPtr(0); + if (Head.InterlockedCompareExchange(NewHead, LocalHead)) + { + break; + } + } + return Item; + } + + TLinkPtr PopAllAndChangeState(TFunctionRef StateChange) + { + static_assert(TABAInc > 1, "method should not be used for lists without state"); + TLinkPtr Item = 0; + while (true) + { + TDoublePtr LocalHead; + LocalHead.AtomicRead(Head); + Item = LocalHead.GetPtr(); + TDoublePtr NewHead; + NewHead.AdvanceCounterAndState(LocalHead, TABAInc); + NewHead.SetState(StateChange(LocalHead.GetState())); + NewHead.SetPtr(0); + if (Head.InterlockedCompareExchange(NewHead, LocalHead)) + { + break; + } + } + return Item; + } + + FORCEINLINE bool IsEmpty() const + { + return !Head.GetPtr(); + } + + FORCEINLINE uint64 GetState() const + { + TDoublePtr LocalHead; + LocalHead.AtomicRead(Head); + return LocalHead.GetState(); + } + +private: + + FPaddingForCacheContention PadToAvoidContention1; + TDoublePtr Head; + FPaddingForCacheContention PadToAvoidContention2; +}; + +template +class FLockFreePointerListLIFOBase : public FNoncopyable +{ + typedef FLockFreeLinkPolicy::TDoublePtr TDoublePtr; + typedef FLockFreeLinkPolicy::TLink TLink; + typedef FLockFreeLinkPolicy::TLinkPtr TLinkPtr; +public: + void Reset() + { + RootList.Reset(); + } + + void Push(T* InPayload) + { + TLinkPtr Item = FLockFreeLinkPolicy::AllocLockFreeLink(); + FLockFreeLinkPolicy::DerefLink(Item)->Payload = InPayload; + RootList.Push(Item); + } + + bool PushIf(T* InPayload, TFunctionRef OkToPush) + { + TLinkPtr Item = 0; + + auto AllocateIfOkToPush = [&OkToPush, InPayload, &Item](uint64 State)->TLinkPtr + { + if (OkToPush(State)) + { + if (!Item) + { + Item = FLockFreeLinkPolicy::AllocLockFreeLink(); + FLockFreeLinkPolicy::DerefLink(Item)->Payload = InPayload; + } + return Item; + } + return 0; + }; + if (!RootList.PushIf(AllocateIfOkToPush)) + { + if (Item) + { + // we allocated the link, but it turned out that the list was closed + FLockFreeLinkPolicy::FreeLockFreeLink(Item); + } + return false; + } + return true; + } + + + T* Pop() + { + TLinkPtr Item = RootList.Pop(); + T* Result = nullptr; + if (Item) + { + Result = (T*)FLockFreeLinkPolicy::DerefLink(Item)->Payload; + FLockFreeLinkPolicy::FreeLockFreeLink(Item); + } + return Result; + } + + void PopAll(TArray& OutArray) + { + TLinkPtr Links = RootList.PopAll(); + while (Links) + { + TLink* LinksP = FLockFreeLinkPolicy::DerefLink(Links); + OutArray.Add((T*)LinksP->Payload); + TLinkPtr Del = Links; + Links = LinksP->SingleNext; + FLockFreeLinkPolicy::FreeLockFreeLink(Del); + } + } + + void PopAllAndChangeState(TArray& OutArray, TFunctionRef StateChange) + { + TLinkPtr Links = RootList.PopAllAndChangeState(StateChange); + while (Links) + { + TLink* LinksP = FLockFreeLinkPolicy::DerefLink(Links); + OutArray.Add((T*)LinksP->Payload); + TLinkPtr Del = Links; + Links = LinksP->SingleNext; + FLockFreeLinkPolicy::FreeLockFreeLink(Del); + } + } + + FORCEINLINE bool IsEmpty() const + { + return RootList.IsEmpty(); + } + + FORCEINLINE uint64 GetState() const + { + return RootList.GetState(); + } + +private: + + FLockFreePointerListLIFORoot RootList; +}; + +template +class FLockFreePointerFIFOBase : public FNoncopyable +{ + typedef FLockFreeLinkPolicy::TDoublePtr TDoublePtr; + typedef FLockFreeLinkPolicy::TLink TLink; + typedef FLockFreeLinkPolicy::TLinkPtr TLinkPtr; +public: + + FORCEINLINE FLockFreePointerFIFOBase() + { + // We want to make sure we have quite a lot of extra counter values to avoid the ABA problem. This could probably be relaxed, but eventually it will be dangerous. + // The question is "how many queue operations can a thread starve for". + static_assert(TABAInc <= 65536, "risk of ABA problem"); + static_assert((TABAInc & (TABAInc - 1)) == 0, "must be power of two"); + + Head.Init(); + Tail.Init(); + TLinkPtr Stub = FLockFreeLinkPolicy::AllocLockFreeLink(); + Head.SetPtr(Stub); + Tail.SetPtr(Stub); + } + + void Push(T* InPayload) + { + TLinkPtr Item = FLockFreeLinkPolicy::AllocLockFreeLink(); + FLockFreeLinkPolicy::DerefLink(Item)->Payload = InPayload; + TDoublePtr LocalTail; + while (true) + { + LocalTail.AtomicRead(Tail); + TLink* LoadTailP = FLockFreeLinkPolicy::DerefLink(LocalTail.GetPtr()); + TDoublePtr LocalNext; + LocalNext.AtomicRead(LoadTailP->DoubleNext); + TDoublePtr TestLocalTail; + TestLocalTail.AtomicRead(Tail); + if (TestLocalTail == LocalTail) + { + if (LocalNext.GetPtr()) + { + TDoublePtr NewTail; + NewTail.AdvanceCounterAndState(LocalTail, TABAInc); + NewTail.SetPtr(LocalNext.GetPtr()); + Tail.InterlockedCompareExchange(NewTail, LocalTail); + } + else + { + TDoublePtr NewNext; + NewNext.AdvanceCounterAndState(LocalNext, 1); + NewNext.SetPtr(Item); + if (LoadTailP->DoubleNext.InterlockedCompareExchange(NewNext, LocalNext)) + { + break; + } + } + } + } + { + TestCriticalStall(); + TDoublePtr NewTail; + NewTail.AdvanceCounterAndState(LocalTail, TABAInc); + NewTail.SetPtr(Item); + Tail.InterlockedCompareExchange(NewTail, LocalTail); + } + } + + T* Pop() + { + T* Result = nullptr; + TDoublePtr LocalHead; + while (true) + { + LocalHead.AtomicRead(Head); + TDoublePtr LocalTail; + LocalTail.AtomicRead(Tail); + TDoublePtr LocalNext; + LocalNext.AtomicRead(FLockFreeLinkPolicy::DerefLink(LocalHead.GetPtr())->DoubleNext); + TDoublePtr LocalHeadTest; + LocalHeadTest.AtomicRead(Head); + if (LocalHead == LocalHeadTest) + { + if (LocalHead.GetPtr() == LocalTail.GetPtr()) + { + if (!LocalNext.GetPtr()) + { + return nullptr; + } + TestCriticalStall(); + TDoublePtr NewTail; + NewTail.AdvanceCounterAndState(LocalTail, TABAInc); + NewTail.SetPtr(LocalNext.GetPtr()); + Tail.InterlockedCompareExchange(NewTail, LocalTail); + } + else + { + Result = (T*)FLockFreeLinkPolicy::DerefLink(LocalNext.GetPtr())->Payload; + TDoublePtr NewHead; + NewHead.AdvanceCounterAndState(LocalHead, TABAInc); + NewHead.SetPtr(LocalNext.GetPtr()); + if (Head.InterlockedCompareExchange(NewHead, LocalHead)) + { + break; + } + } + } + } + FLockFreeLinkPolicy::FreeLockFreeLink(LocalHead.GetPtr()); + return Result; + } + + void PopAll(TArray& OutArray) + { + while (T* Item = Pop()) + { + OutArray.Add(Item); + } + } + + + FORCEINLINE bool IsEmpty() const + { + TDoublePtr LocalHead; + LocalHead.AtomicRead(Head); + TDoublePtr LocalNext; + LocalNext.AtomicRead(FLockFreeLinkPolicy::DerefLink(LocalHead.GetPtr())->DoubleNext); + return !LocalNext.GetPtr(); + } + +private: + + FPaddingForCacheContention PadToAvoidContention1; + TDoublePtr Head; + FPaddingForCacheContention PadToAvoidContention2; + TDoublePtr Tail; + FPaddingForCacheContention PadToAvoidContention3; +}; + + +template +class FStallingTaskQueue : public FNoncopyable +{ + typedef FLockFreeLinkPolicy::TDoublePtr TDoublePtr; + typedef FLockFreeLinkPolicy::TLink TLink; + typedef FLockFreeLinkPolicy::TLinkPtr TLinkPtr; +public: + FStallingTaskQueue() + { + MasterState.Init(); + } + int32 Push(T* InPayload, uint32 Priority) + { + checkLockFreePointerList(Priority < NumPriorities); + TDoublePtr LocalMasterState; + LocalMasterState.AtomicRead(MasterState); + PriorityQueues[Priority].Push(InPayload); + TDoublePtr NewMasterState; + NewMasterState.AdvanceCounterAndState(LocalMasterState, 1); + int32 ThreadToWake = FindThreadToWake(LocalMasterState.GetPtr()); + if (ThreadToWake >= 0) + { + NewMasterState.SetPtr(TurnOffBit(LocalMasterState.GetPtr(), ThreadToWake)); + } + else + { + NewMasterState.SetPtr(LocalMasterState.GetPtr()); + } + while (!MasterState.InterlockedCompareExchange(NewMasterState, LocalMasterState)) + { + LocalMasterState.AtomicRead(MasterState); + NewMasterState.AdvanceCounterAndState(LocalMasterState, 1); + ThreadToWake = FindThreadToWake(LocalMasterState.GetPtr()); + if (ThreadToWake >= 0) + { + bool bAny = false; + for (int32 Index = 0; !bAny && Index < NumPriorities; Index++) + { + bAny = PriorityQueues[Index].IsEmpty(); + } + if (!bAny) // if there is nothing in the queues, then don't wake anyone + { + ThreadToWake = -1; + } + } + if (ThreadToWake >= 0) + { + NewMasterState.SetPtr(TurnOffBit(LocalMasterState.GetPtr(), ThreadToWake)); + } + else + { + NewMasterState.SetPtr(LocalMasterState.GetPtr()); + } + } + return ThreadToWake; + } + + T* Pop(int32 MyThread, bool bAllowStall) + { + check(MyThread >= 0 && MyThread < FLockFreeLinkPolicy::MAX_BITS_IN_TLinkPtr); + + while (true) + { + TDoublePtr LocalMasterState; + LocalMasterState.AtomicRead(MasterState); + checkLockFreePointerList(!TestBit(LocalMasterState.GetPtr(), MyThread)); // you should not be stalled if you are asking for a task + for (int32 Index = 0; Index < NumPriorities; Index++) + { + T *Result = PriorityQueues[Index].Pop(); + if (Result) + { + return Result; + } + } + if (!bAllowStall) + { + break; // if we aren't stalling, we are done, the queues are empty + } + TDoublePtr NewMasterState; + NewMasterState.AdvanceCounterAndState(LocalMasterState, 1); + NewMasterState.SetPtr(TurnOnBit(LocalMasterState.GetPtr(), MyThread)); + if (MasterState.InterlockedCompareExchange(NewMasterState, LocalMasterState)) + { + break; + } + } + return nullptr; + } + +private: + + static int32 FindThreadToWake(TLinkPtr Ptr) + { + int32 Result = -1; + UPTRINT Test = UPTRINT(Ptr); + if (Test) + { + Result = 0; + while (!(Test & 1)) + { + Test >>= 1; + Result++; + } + } + return Result; + } + + static TLinkPtr TurnOffBit(TLinkPtr Ptr, int32 BitToTurnOff) + { + return (TLinkPtr)(UPTRINT(Ptr) & ~(UPTRINT(1) << BitToTurnOff)); + } + + static TLinkPtr TurnOnBit(TLinkPtr Ptr, int32 BitToTurnOn) + { + return (TLinkPtr)(UPTRINT(Ptr) | (UPTRINT(1) << BitToTurnOn)); + } + + static bool TestBit(TLinkPtr Ptr, int32 BitToTest) + { + return !!(UPTRINT(Ptr) & (UPTRINT(1) << BitToTest)); + } + + FLockFreePointerFIFOBase PriorityQueues[NumPriorities]; + // not a pointer to anything, rather tracks the stall state of all threads servicing this queue. + TDoublePtr MasterState; + FPaddingForCacheContention PadToAvoidContention1; +}; + + + + +template +class TLockFreePointerListLIFOPad : private FLockFreePointerListLIFOBase +{ +public: + + /** + * Push an item onto the head of the list. + * + * @param NewItem, the new item to push on the list, cannot be NULL. + */ + void Push(T *NewItem) + { + FLockFreePointerListLIFOBase::Push(NewItem); + } + + /** + * Pop an item from the list or return NULL if the list is empty. + * @return The popped item, if any. + */ + T* Pop() + { + return FLockFreePointerListLIFOBase::Pop(); + } + + /** + * Pop all items from the list. + * + * @param Output The array to hold the returned items. Must be empty. + */ + void PopAll(TArray& Output) + { + FLockFreePointerListLIFOBase::PopAll(Output); + } + + /** + * Check if the list is empty. + * + * @return true if the list is empty. + * CAUTION: This methods safety depends on external assumptions. For example, if another thread could add to the list at any time, the return value is no better than a best guess. + * As typically used, the list is not being access concurrently when this is called. + */ + FORCEINLINE bool IsEmpty() const + { + return FLockFreePointerListLIFOBase::IsEmpty(); + } +}; + +template +class TLockFreePointerListLIFO : public TLockFreePointerListLIFOPad +{ + +}; + +template +class TLockFreePointerListUnordered : public TLockFreePointerListLIFOPad +{ + +}; + +template +class TLockFreePointerListFIFO : private FLockFreePointerFIFOBase +{ +public: + + /** + * Push an item onto the head of the list. + * + * @param NewItem, the new item to push on the list, cannot be NULL. + */ + void Push(T *NewItem) + { + FLockFreePointerFIFOBase::Push(NewItem); + } + + /** + * Pop an item from the list or return NULL if the list is empty. + * @return The popped item, if any. + */ + T* Pop() + { + return FLockFreePointerFIFOBase::Pop(); + } + + /** + * Pop all items from the list. + * + * @param Output The array to hold the returned items. Must be empty. + */ + void PopAll(TArray& Output) + { + FLockFreePointerFIFOBase::PopAll(Output); + } + + /** + * Check if the list is empty. + * + * @return true if the list is empty. + * CAUTION: This methods safety depends on external assumptions. For example, if another thread could add to the list at any time, the return value is no better than a best guess. + * As typically used, the list is not being access concurrently when this is called. + */ + FORCEINLINE bool IsEmpty() const + { + return FLockFreePointerFIFOBase::IsEmpty(); + } +}; + + +template +class TClosableLockFreePointerListUnorderedSingleConsumer : private FLockFreePointerListLIFOBase +{ +public: + + /** + * Reset the list to the initial state. Not thread safe, but used for recycling when we know all users are gone. + */ + void Reset() + { + FLockFreePointerListLIFOBase::Reset(); + } + + /** + * Push an item onto the head of the list, unless the list is closed + * + * @param NewItem, the new item to push on the list, cannot be NULL + * @return true if the item was pushed on the list, false if the list was closed. + */ + bool PushIfNotClosed(T *NewItem) + { + return FLockFreePointerListLIFOBase::PushIf(NewItem, [](uint64 State)->bool {return !(State & 1); }); + } + + /** + * Pop all items from the list and atomically close it. + * + * @param Output The array to hold the returned items. Must be empty. + */ + void PopAllAndClose(TArray& Output) + { + auto CheckOpenAndClose = [](uint64 State) -> uint64 + { + checkLockFreePointerList(!(State & 1)); + return State | 1; + }; + FLockFreePointerListLIFOBase::PopAllAndChangeState(Output, CheckOpenAndClose); + } + + /** + * Check if the list is closed + * + * @return true if the list is closed. + */ + bool IsClosed() const + { + return !!(FLockFreePointerListLIFOBase::GetState() & 1); + } + +}; -#include "Containers/LockFreeListImpl.h" diff --git a/Engine/Source/Runtime/Core/Public/Containers/LockFreeListImpl.h b/Engine/Source/Runtime/Core/Public/Containers/LockFreeListImpl.h deleted file mode 100644 index d4530a26e972..000000000000 --- a/Engine/Source/Runtime/Core/Public/Containers/LockFreeListImpl.h +++ /dev/null @@ -1,274 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "Containers/ContainersFwd.h" - -/** - * Wrapper around FLockFreeVoidPointerListBase - * Simple lock free list (stack) that does not permit closure. - * T is the type of the pointer the list will contain. - */ -template -class TLockFreePointerListLIFOBase : private FLockFreeVoidPointerListGeneric -{ -public: - /** - * Push an item onto the head of the list. - * - * @param NewItem, the new item to push on the list, cannot be NULL. - */ - void Push(T *NewItem) - { - FLockFreeVoidPointerListGeneric::Push(NewItem); - } - - /** - * Pop an item from the list or return NULL if the list is empty. - * @return The popped item, if any. - */ - T* Pop() - { - return (T*)FLockFreeVoidPointerListGeneric::Pop(); - } - - /** - * Pop all items from the list. - * - * @param Output The array to hold the returned items. Must be empty. - */ - void PopAll(TArray& Output) - { - FLockFreeVoidPointerListGeneric::PopAll, T * >(Output); - } - - /** - * Check if the list is empty. - * - * @return true if the list is empty. - * CAUTION: This methods safety depends on external assumptions. For example, if another thread could add to the list at any time, the return value is no better than a best guess. - * As typically used, the list is not being access concurrently when this is called. - */ - FORCEINLINE bool IsEmpty() const - { - return FLockFreeVoidPointerListGeneric::IsEmpty(); - } -protected: - /** - * If the list is empty, replace it with the other list and null the other list. - * @return true if this call actively closed the list - */ - FORCEINLINE bool ReplaceListIfEmpty(TLockFreePointerListLIFOBase& NotThreadSafeTempListToReplaceWith) - { - return FLockFreeVoidPointerListGeneric::ReplaceListIfEmpty(NotThreadSafeTempListToReplaceWith); - } -}; - -template -class TLockFreePointerListLIFO : public TLockFreePointerListLIFOBase -{ -public: - FORCEINLINE bool ReplaceListIfEmpty(TLockFreePointerListLIFO& NotThreadSafeTempListToReplaceWith) - { - return TLockFreePointerListLIFOBase::ReplaceListIfEmpty(NotThreadSafeTempListToReplaceWith); - } - -}; - -template -class TClosableLockFreePointerListLIFO : private FLockFreeVoidPointerListGeneric -{ -public: - /** - * Push an item onto the head of the list, unless the list is closed - * - * @param NewItem, the new item to push on the list, cannot be NULL - * @return true if the item was pushed on the list, false if the list was closed. - */ - bool PushIfNotClosed(T *NewItem) - { - return FLockFreeVoidPointerListGeneric::PushIfNotClosed(NewItem); - } - - /** - * Pop all items from the list and atomically close it. - * - * @param Output The array to hold the returned items. Must be empty. - */ - void PopAllAndClose(TArray& Output) - { - FLockFreeVoidPointerListGeneric::PopAllAndClose, T * >(Output); - } - - /** - * Check if the list is closed - * - * @return true if the list is closed. - */ - bool IsClosed() const - { - return FLockFreeVoidPointerListGeneric::IsClosed(); - } -}; - -template -class TReopenableLockFreePointerListLIFO : private FLockFreeVoidPointerListGeneric -{ -public: - /** - * Push an item onto the head of the list, opening it first if necessary. - * - * @param NewItem, the new item to push on the list, cannot be NULL. - * @return true if the list needed to be opened first, false if the list was not closed before our push. - */ - bool ReopenIfClosedAndPush(T *NewItem) - { - bool bWasReopenedByMe = FLockFreeVoidPointerListGeneric::ReopenIfClosedAndPush(NewItem); - return bWasReopenedByMe; - } - - /** - * Pop an item from the list or return NULL if the list is empty or closed. - * @return The new item, if any - */ - T* PopIfNotClosed() - { - return (T*)FLockFreeVoidPointerListGeneric::PopIfNotClosed(); - } - - /** - * Pop all items from the list. - * - * @param Output The array to hold the returned items. Must be empty. - * CAUTION: This method should not be used unless the list is known to not be closed. - */ - void PopAll(TArray& Output) - { - FLockFreeVoidPointerListGeneric::PopAll, T * >(Output); - } - /** - * Close the list if it is empty. - * - * @return true if this call actively closed the list. - */ - bool CloseIfEmpty() - { - return FLockFreeVoidPointerListGeneric::CloseIfEmpty(); - } -}; - -#if !USE_NEW_LOCK_FREE_LISTS -// where you don't care what order they pop in. We choose the fastest implementation we have. -template -class TLockFreePointerListUnordered : public TLockFreePointerListLIFOBase -{ - -}; -template -class TClosableLockFreePointerListUnorderedSingleConsumer : public TClosableLockFreePointerListLIFO -{ - -}; - -#else - -template -class TClosableLockFreePointerListFIFOSingleConsumer -{ -public: - /** - * Push an item onto the head of the list, unless the list is closed - * - * @param NewItem, the new item to push on the list, cannot be NULL - * @return true if the item was pushed on the list, false if the list was closed. - */ - FORCEINLINE bool PushIfNotClosed(T *NewItem) - { - return Inner.PushIfNotClosed(NewItem); - } - - /** - * Pop an item from the list or return NULL if the list is empty - * @return The new item, if any - * CAUTION: This method should not be used unless the list is known to not be closed. - */ - FORCEINLINE T* Pop() - { - return (T*)Inner.Pop(); - } - - /** - * Close the list if it is empty. - * @return true if this call actively closed the list. - */ - FORCEINLINE bool CloseIfEmpty() - { - return Inner.CloseIfEmpty(); - } - - /** - * Check if the list is closed - * @return true if the list is closed. - */ - FORCEINLINE bool IsClosed() const - { - return Inner.IsClosed(); - } - /** - * Not thread safe, used to reset the list for recycling without freeing the stub - * @return true if the list is closed. - */ - FORCEINLINE void Reset() - { - return Inner.Reset(); - } -private: - FCloseableLockFreePointerListFIFOBaseSingleConsumer Inner; -}; - -template -class TReopenableLockFreePointerListFIFOSingleConsumer -{ -public: - /** - * Push an item onto the head of the list, opening it first if necessary. - * - * @param NewItem, the new item to push on the list, cannot be NULL. - * @return true if the list needed to be opened first, false if the list was not closed before our push. - */ - FORCEINLINE bool ReopenIfClosedAndPush(T *NewItem) - { - return Inner.ReopenIfClosedAndPush(NewItem); - } - - /** - * Pop an item from the list or return NULL if the list is empty - * @return The new item, if any - * CAUTION: This method should not be used unless the list is known to not be closed. - */ - FORCEINLINE T* Pop() - { - return (T*)Inner.Pop(); - } - - /** - * Close the list if it is empty. - * @return true if this call actively closed the list. - */ - FORCEINLINE bool CloseIfEmpty() - { - return Inner.CloseIfEmpty(); - } -private: - FCloseableLockFreePointerListFIFOBaseSingleConsumer Inner; -}; - -template -class TClosableLockFreePointerListUnorderedSingleConsumer : public TClosableLockFreePointerListFIFOSingleConsumer -{ - -}; - - -#endif - diff --git a/Engine/Source/Runtime/Core/Public/Containers/LockFreeVoidPointerListBase.h b/Engine/Source/Runtime/Core/Public/Containers/LockFreeVoidPointerListBase.h deleted file mode 100644 index 54fc3d033eeb..000000000000 --- a/Engine/Source/Runtime/Core/Public/Containers/LockFreeVoidPointerListBase.h +++ /dev/null @@ -1,3228 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "CoreTypes.h" -#include "CoreFwd.h" - -#define CHECK_NON_CONCURRENT_ASSUMPTIONS (0) - -#define USE_NEW_LOCK_FREE_LISTS (PLATFORM_PS4 || PLATFORM_XBOXONE || PLATFORM_SWITCH) - -class FNoncopyable; -class FNoopCounter; -struct FMemory; - -/** - * Base class for a lock free list of pointers - * This class has several different features. Not all methods are supported in all situations. - * The intention is that derived classes use private inheritance to build a data structure only supports a small meaningful set of operations. - * - * A key feature is that lists can be "closed". A closed list cannot be pushed to or popped from. Closure is atomic with push and pop. - * All operations are threadsafe, except that the constructor is not reentrant. - */ -class FLockFreeVoidPointerListBase : public FNoncopyable -{ -public: - /** Constructor - sets the list to empty and initializes the allocator if it hasn't already been initialized. */ - FLockFreeVoidPointerListBase() - : Head(nullptr) - { - FLinkAllocator::Get(); // construct allocator singleton if it isn't already - } - /** Destructor - checks that the list is either empty or closed. Lists should not be destroyed in any other state. */ - ~FLockFreeVoidPointerListBase() - { - // leak these at shutdown - //checkLockFreePointerList(Head == nullptr || Head == FLinkAllocator::Get().ClosedLink()); // we do not allow destruction except in the empty or closed state - } - - /** - * Push an item onto the head of the list - * @param NewItem, the new item to push on the list, cannot be nullptr - * CAUTION: This method should not be used unless the list is known to not be closed. - */ - void Push(void *NewItem) - { - FLink* NewLink = FLinkAllocator::Get().AllocateLink(NewItem); - NewLink->Link(&Head); - checkLockFreePointerList(NewLink->Next != FLinkAllocator::Get().ClosedLink()); // it is not permissible to call push on a Closed queue - } - - /** - * Push an item onto the head of the list, unless the list is closed - * @param NewItem, the new item to push on the list, cannot be nullptr - * @return true if the item was pushed on the list, false if the list was closed. - */ - bool PushIfNotClosed(void *NewItem) - { - FLink* NewLink = FLinkAllocator::Get().AllocateLink(NewItem); - bool bSuccess = NewLink->LinkIfHeadNotEqual(&Head, FLinkAllocator::Get().ClosedLink()); - if (!bSuccess) - { - NewLink->Dispose(); - } - return bSuccess; - } - - /** - * Push an item onto the head of the list, opening it first if necessary - * @param NewItem, the new item to push on the list, cannot be nullptr - * @return true if the list needed to be opened first, false if the list was not closed before our push - */ - bool ReopenIfClosedAndPush(void *NewItem) - { - FLink* NewLink = FLinkAllocator::Get().AllocateLink(NewItem); - while (1) - { - if (NewLink->LinkIfHeadNotEqual(&Head, FLinkAllocator::Get().ClosedLink())) - { - return false; - } - if (NewLink->ReplaceHeadIfHeadEqual(&Head, FLinkAllocator::Get().ClosedLink())) - { - return true; - } - } - } - - /** - * Pop an item from the list or return nullptr if the list is empty - * @return The popped item, if any - * CAUTION: This method should not be used unless the list is known to not be closed. - */ - void* Pop() - { - FLink* Link = FLink::Unlink(&Head); - if (!Link) - { - return nullptr; - } - checkLockFreePointerList(Link != FLinkAllocator::Get().ClosedLink()); // it is not permissible to call pop on a Closed queue - void* Return = Link->Item; - Link->Dispose(); - return Return; - } - - /** - * Pop an item from the list or return nullptr if the list is empty or closed - * @return The new item, if any - */ - void* PopIfNotClosed() - { - FLink* Link = FLink::Unlink(&Head, FLinkAllocator::Get().ClosedLink()); - if (!Link) - { - return nullptr; - } - checkLockFreePointerList(Link != FLinkAllocator::Get().ClosedLink()); // internal error, this should not be possible - void* Return = Link->Item; - Link->Dispose(); - return Return; - } - - /** - * Close the list if it is empty - * @return true if this call actively closed the list - */ - bool CloseIfEmpty() - { - if (FLinkAllocator::Get().ClosedLink()->ReplaceHeadIfHeadEqual(&Head,nullptr)) - { - return true; - } - return false; - } - - /** - * If the list is empty, replace it with the other list and null the other list. - * @return true if this call actively closed the list - */ - bool ReplaceListIfEmpty(FLockFreeVoidPointerListBase& NotThreadSafeTempListToReplaceWith) - { - if (NotThreadSafeTempListToReplaceWith.Head->ReplaceHeadIfHeadEqual(&Head,nullptr)) - { - NotThreadSafeTempListToReplaceWith.Head = nullptr; - return true; - } - return false; - } - - /** - * Pop all items from the list - * @param Output The array to hold the returned items. Must be empty. - * CAUTION: This method should not be used unless the list is known to not be closed. - */ - template - void PopAll(ARRAYTYPE& Output) - { - checkLockFreePointerList(!Output.Num()); - FLink* Link = FLink::ReplaceList(&Head); - while (Link) - { - checkLockFreePointerList(Link != FLinkAllocator::Get().ClosedLink()); // it is not permissible to call PopAll on a Closed queue - checkLockFreePointerList(Link->Item); // we don't allow nullptr items - Output.Add((ElementType)(Link->Item)); - FLink* NextLink = Link->Next; - Link->Dispose(); - Link = NextLink; - } - } - - /** - * Pop all items from the list and atomically close it. - * @param Output The array to hold the returned items. Must be empty. - */ - template - void PopAllAndClose(ARRAYTYPE& Output) - { - checkLockFreePointerList(!Output.Num()); - FLink* Link = FLink::ReplaceList(&Head, FLinkAllocator::Get().ClosedLink()); - while (Link) - { - checkLockFreePointerList(Link != FLinkAllocator::Get().ClosedLink()); // we should not pop off the closed link - checkLockFreePointerList(Link->Item); // we don't allow nullptr items - Output.Add((ElementType)(Link->Item)); - FLink* NextLink = Link->Next; - Link->Dispose(); - Link = NextLink; - } - } - - /** - * Check if the list is closed - * @return true if the list is closed. - * CAUTION: This methods safety depends on external assumptions. For example, if another thread could open or close the list at any time, the return value is no better than a best guess. - * As typically used, the list is only closed once it is lifetime, so a return of true here means it is closed forever. - */ - bool IsClosed() const // caution, if this returns false, that does not mean the list is open! - { - FPlatformMisc::MemoryBarrier(); - return Head == FLinkAllocator::Get().ClosedLink(); - } - - /** - * Check if the list is empty - * @return true if the list is empty. - * CAUTION: This methods safety depends on external assumptions. For example, if another thread could add to the list at any time, the return value is no better than a best guess. - * As typically used, the list is not being access concurrently when this is called. - */ - bool IsEmpty() const - { - FPlatformMisc::MemoryBarrier(); - return Head == nullptr; - } - - -private: - /** Internal single-linked list link structure. */ - struct FLink - { - /** Next item in the list or nullptr if we are at the end of the list */ - FLink* Next; - /** - * Pointer to the item this list holds. The is useful to the external users of the system. Must not be nullptr for ordinary links. - * Also part of the solution to the ABA problem. nullptr Items are always on the recycling list and NON-nullptr items are not. - */ - void* Item; - /** Part of the solution to the ABA problem. Links cannot be recycled until no threads hold pointers to them. When the lock count drops to zero, the link is recycled. */ - FThreadSafeCounter LockCount; - /** Part of the solution to the ABA problem. Links that are free still need locking, but we need to make sure that links are only added to the free list when they are transitioning to the free list. */ - FThreadSafeCounter MarkedForDeath; - - /** Constructor, everything is initialized to zero. */ - FLink() - : Next(nullptr) - , Item(nullptr) - { - } - - /** - * Link this node into the head of the given list. - * @param HeadPointer; the head of the list - * CAUTION: Not checked here, but linking into a closed list with the routine would accidently and incorrectly open the list - */ - void Link(FLink** HeadPointer) - { - CheckNotMarkedForDeath(); - while (1) - { - FLink* LocalHeadPointer = LockLink(HeadPointer); - CheckNotMarkedForDeath(); - SetNextPointer(LocalHeadPointer); - FLink* ValueWas = (FLink*)FPlatformAtomics::InterlockedCompareExchangePointer((void**)HeadPointer,this,LocalHeadPointer); - if (ValueWas == LocalHeadPointer) - { - if (LocalHeadPointer) - { - LocalHeadPointer->Unlock(); - } - break; - } - SetNextPointer(nullptr); - if (LocalHeadPointer) - { - LocalHeadPointer->Unlock(); - } - } - } - - /** - * Link this node into the head of the given list, unless the head is a special, given node - * @param HeadPointer; the head of the list - * @param SpecialClosedLink; special link that is never recycled that indicates a closed list. - * @return true if this node was linked to the head. - */ - bool LinkIfHeadNotEqual(FLink** HeadPointer, FLink* SpecialClosedLink) - { - - checkLockFreePointerList(!Next); // this should not be set yet - CheckNotMarkedForDeath(); - while (1) - { - if (*HeadPointer == SpecialClosedLink) - { - CheckNotMarkedForDeath(); - return false; - } - FLink* LocalHeadPointer = LockLink(HeadPointer, SpecialClosedLink); - CheckNotMarkedForDeath(); - // here if the list turns out to be locked now, the compare and swap will fail anyway - SetNextPointer(LocalHeadPointer); - FLink* ValueWas = (FLink*)FPlatformAtomics::InterlockedCompareExchangePointer((void**)HeadPointer,this,LocalHeadPointer); - if (ValueWas == LocalHeadPointer) - { - if (LocalHeadPointer) - { - LocalHeadPointer->Unlock(); - } - break; - } - SetNextPointer(nullptr); - if (LocalHeadPointer) - { - LocalHeadPointer->Unlock(); - } - } - return true; - } - /** - * If the head is a particular value, then replace it with this node. This is the primitive that is used to close and open lists - * @param HeadPointer; the head of the list - * @param SpecialTestLink; special link that is never recycled that indicates a closed list. Or nullptr in the case that we are using this to open the list - * @return true if this node was linked to the head. - * CAUTION: The test link must nullptr or a special link that is never recycled. The ABA problem is assumed to not occur here. - */ - bool ReplaceHeadIfHeadEqual(FLink** HeadPointer, FLink* SpecialTestLink) - { - CheckNotMarkedForDeath(); - while (1) - { - if (*HeadPointer != SpecialTestLink) - { - return false; - } - CheckNotMarkedForDeath(); - if (FPlatformAtomics::InterlockedCompareExchangePointer((void**)HeadPointer,this,SpecialTestLink) == SpecialTestLink) - { - break; - } - } - return true; - } - /** - * Pop an item off the list, unless the list is empty or the head is a special, given node - * @param HeadPointer; the head of the list - * @param SpecialClosedLink; special link that is never recycled that indicates a closed list. Can be nullptr for lists that are known to not be closed - * @return The link that was popped off, or nullptr if the list was empty or closed. - * CAUTION: Not checked here, but if the list is closed and SpecialClosedLink is nullptr, you will pop off the closed link, and that usually isn't what you want - */ - static FLink* Unlink(FLink** HeadPointer, FLink* SpecialClosedLink = nullptr) - { - while (1) - { - FLink* LocalHeadPointer = LockLink(HeadPointer, SpecialClosedLink); - if (!LocalHeadPointer) - { - break; - } - FLink* NextLink = LocalHeadPointer->Next; - FLink* ValueWas = (FLink*)FPlatformAtomics::InterlockedCompareExchangePointer((void**)HeadPointer,NextLink,LocalHeadPointer); - if (ValueWas == LocalHeadPointer) - { - checkLockFreePointerList(NextLink == LocalHeadPointer->Next); - LocalHeadPointer->SetNextPointer(nullptr); // this is redundant, but we are not given the caller ownership of the other items - LocalHeadPointer->Unlock(true); // this cannot possibly result in a destruction of the link because we have taken sole possession of it - LocalHeadPointer->CheckNotMarkedForDeath(); // we are the exclusive owners at this point - return LocalHeadPointer; - } - LocalHeadPointer->Unlock(); - } - return nullptr; - } - /** - * Replace the list with another list.h Use to either acquire all of the items or acquire all of the items and close the list. - * @param HeadPointer; the head of the list - * @param NewHeadLink; Head of the new list to replace this list with - * @return The original list before we replaced it. - * CAUTION: Not checked here, but if the list is closed this is probably not what you want. - */ - static FLink* ReplaceList(FLink** HeadPointer, FLink* NewHeadLink = nullptr) - { - while (1) - { - FLink* LocalHeadPointer = LockLink(HeadPointer); - if (!LocalHeadPointer && !NewHeadLink) - { - // we are asking to replace nullptr with nullptr, this does not require an atomic (or any) operation - break; - } - checkLockFreePointerList(LocalHeadPointer != NewHeadLink); // replacing nullptr with nullptr is ok, but otherwise we cannot be replacing something with itself or we lose determination of who did what. - FLink* ValueWas = (FLink*)FPlatformAtomics::InterlockedCompareExchangePointer((void**)HeadPointer,NewHeadLink,LocalHeadPointer); - if (ValueWas == LocalHeadPointer) - { - if (LocalHeadPointer) - { - LocalHeadPointer->Unlock(true); // this cannot possibly result in a destruction of the link because we have taken sole possession of it - LocalHeadPointer->CheckNotMarkedForDeath(); // we are the exclusive owners at this point - } - return LocalHeadPointer; - } - if (LocalHeadPointer) - { - LocalHeadPointer->Unlock(); - } - } - return nullptr; - } - - /** - * Internal function to safely grab the head pointer and increase the ref count of a link to avoid the ABA problem - * @param HeadPointer; the head of the list - * @param SpecialClosedLink; special link that is never recycled that indicates a closed list. Can be nullptr for lists that are known to not be closed, or if you want to operate on the closed link. - * @return Pointer to the head link, with the ref count increased. Or nullptr if the head is nullptr or SpecialClosedLink - * CAUTION: Not checked here, but if the list is closed this is probably not what you want. - */ - static FLink* LockLink(FLink** HeadPointer, FLink* SpecialClosedLink = nullptr) - { - while (1) - { - FLink* LocalHeadPointer = *HeadPointer; - if (!LocalHeadPointer || LocalHeadPointer == SpecialClosedLink) - { - return nullptr; - } - LocalHeadPointer->LockCount.Increment(); - FPlatformMisc::MemoryBarrier(); - if (*HeadPointer == LocalHeadPointer) - { - return LocalHeadPointer; - } - LocalHeadPointer->Unlock(); - } - } - - void SetNextPointer(FLink* NewNext) - { - FLink* LocalNextPointer = Next; - checkLockFreePointerList(LocalNextPointer != NewNext || !NewNext); // should not be the same, except both can be nullptr - checkLockFreePointerList(!LocalNextPointer || !NewNext); // one (or both) of them should be nullptr -#if CHECK_NON_CONCURRENT_ASSUMPTIONS - FLink* ValueWas = (FLink*)FPlatformAtomics::InterlockedCompareExchangePointer((void**)&Next, NewNext, LocalNextPointer); // not known to need to be interlocked - checkLockFreePointerList(ValueWas == LocalNextPointer); // this should always work because there should never be contention on setting next -#else - Next = NewNext; -#endif - FPlatformMisc::MemoryBarrier(); - if (NewNext) - { - CheckNotMarkedForDeath(); // it shouldn't be possible for the node to die while we are setting a non-nullptr next pointer - } - } - - // verify that we are not marked for destruction - void CheckNotMarkedForDeath() - { - checkLockFreePointerList(MarkedForDeath.GetValue() == 0); // we don't allow nullptr items - } - - /** - * Mark the node for disposal and unlock it - */ - void Dispose() - { - CheckNotMarkedForDeath(); - -#if CHECK_NON_CONCURRENT_ASSUMPTIONS - { - void *CurrentItem = Item; - checkLockFreePointerList(CurrentItem); // we don't allow nullptr items - void* ValueWas = FPlatformAtomics::InterlockedCompareExchangePointer(&Item,nullptr,CurrentItem); // do not need an interlocked operation here - checkLockFreePointerList(ValueWas == CurrentItem); // there should be no concurrency here - } - - { - FLink* LocalNextPointer = Next; - FLink* ValueWas = (FLink*)FPlatformAtomics::InterlockedCompareExchangePointer((void**)&Next, nullptr, LocalNextPointer); // not known to need to be interlocked - checkLockFreePointerList(ValueWas == LocalNextPointer); // this should always work because there should never be contention on setting next - } -#else - Item = nullptr; - Next = nullptr; -#endif - FPlatformMisc::MemoryBarrier(); // memory barrier in here to make sure item and next are cleared before the link is recycled - - int32 Death = MarkedForDeath.Increment(); - checkLockFreePointerList(Death == 1); // there should be no concurrency here - Unlock(); - } - - /** - * Internal function to unlock a link and recycle it if the ref count drops to zero and it hasn't already been recycled. - * This solves the ABA problem by delaying recycling until all pointers to this link are gone. - * @param bShouldNeverCauseAFree - if true, then this should never result in a free if it does, there is a run time error - */ - void Unlock(bool bShouldNeverCauseAFree = false); - }; - - /** - * Class to allocate and recycle links. - */ - class FLinkAllocator - { - public: - - /** - * Return a new link. - * @param NewItem "item" pointer of the new node. - * @return New node, ready for use - */ - FLink* AllocateLink(void *NewItem) - { - checkLockFreePointerList(NewItem); // we don't allow nullptr items - if (NumUsedLinks.Increment() % 8192 == 1) - { - UE_CLOG(0/*MONITOR_LINK_ALLOCATION*/,LogLockFreeList, Log, TEXT("Number of links %d"),NumUsedLinks.GetValue()); - } - - FLink* NewLink = FLink::Unlink(&FreeLinks); - if (NewLink) - { - NumFreeLinks.Decrement(); - } - else - { - if (NumAllocatedLinks.Increment() % 10 == 1) - { - UE_CLOG(0/*MONITOR_LINK_ALLOCATION*/,LogLockFreeList, Log, TEXT("Number of allocated links %d"),NumAllocatedLinks.GetValue()); - } - - NewLink = new FLink(); - NewLink->LockCount.Increment(); - } - checkLockFreePointerList(!NewLink->Item); - checkLockFreePointerList(!NewLink->Next); - checkLockFreePointerList(NewLink->LockCount.GetValue() >= 1); -#if CHECK_NON_CONCURRENT_ASSUMPTIONS - void* ValueWas = FPlatformAtomics::InterlockedCompareExchangePointer(&NewLink->Item, NewItem, nullptr); // in theory this doesn't need to be interlocked - checkLockFreePointerList(ValueWas == nullptr); -#else - NewLink->Item = NewItem; -#endif - FPlatformMisc::MemoryBarrier(); - return NewLink; - } - /** - * Make a link available for recycling. - * @param Link link to recycle - * CAUTION: Do not call this directly, it should only be called when the reference count drop to zero. - */ - void FreeLink(FLink* Link) - { - checkLockFreePointerList(Link != ClosedLink()); // very bad to recycle the special link - NumUsedLinks.Decrement(); - Link->LockCount.Increment(); - FPlatformMisc::MemoryBarrier(); - Link->Link(&FreeLinks); - NumFreeLinks.Increment(); - } - /** - * Return a pointer to the special closed link - * @return pointer to special closed link - */ - FLink* ClosedLink() - { - checkLockFreePointerList(nullptr != SpecialClosedLink); - return SpecialClosedLink; - } - /** - * Singleton access - * @return the singleton for the link allocator - */ - static CORE_API FLinkAllocator& Get(); - - private: - /** - * Constructor zeros the free link list and creates the special closed link - * @return the singleton for the link allocator - */ - FLinkAllocator(); - - /** - * Destructor, should only be called when there are no outstanding links. - * Frees the elements of the free list and frees the special link - * @return the singleton for the link allocator - */ - ~FLinkAllocator(); - - /** Head to a list of free links that can be used for new allocations. */ - FLink* FreeLinks; - - /** Pointer to the special closed link. It should never be recycled. */ - FLink* SpecialClosedLink; - - /** Total number of links outstanding and not in the free list */ - FLockFreeListCounter NumUsedLinks; - /** Total number of links in the free list */ - FLockFreeListCounter NumFreeLinks; - /** Total number of links allocated */ - FLockFreeListCounter NumAllocatedLinks; - }; - - /** Head of the list */ - MS_ALIGN(8) FLink* Head; -}; - -/** - * Internal function to unlock a link and recycle it if the ref count drops to zero and it hasn't already been recycled. - * This solves the ABA problem by delaying recycling until all pointers to this link are gone. - * @param bShouldNeverCauseAFree - if true, then this should never result in a free if it does, there is a run time error - */ -inline void FLockFreeVoidPointerListBase::FLink::Unlock(bool bShouldNeverCauseAFree) -{ - FPlatformMisc::MemoryBarrier(); - checkLockFreePointerList(LockCount.GetValue() > 0); - if (LockCount.Decrement() == 0) - { - checkLockFreePointerList(MarkedForDeath.GetValue() < 2); - if (MarkedForDeath.Reset()) - { - checkLockFreePointerList(!bShouldNeverCauseAFree); - FLockFreeVoidPointerListBase::FLinkAllocator::Get().FreeLink(this); - } - } -} - -typedef FLockFreeVoidPointerListBase FLockFreeVoidPointerListGeneric; - -// New lock free lists - -template -class TPointerSet_TLSCacheBase : public FNoncopyable -{ - enum - { - NUM_PER_BUNDLE=32, - }; -public: - - TPointerSet_TLSCacheBase() - { - check(IsInGameThread()); - TlsSlot = FPlatformTLS::AllocTlsSlot(); - check(FPlatformTLS::IsValidTlsSlot(TlsSlot)); - } - /** Destructor, leaks all of the memory **/ - ~TPointerSet_TLSCacheBase() - { - FPlatformTLS::FreeTlsSlot(TlsSlot); - TlsSlot = 0; - } - - /** - * Allocates a memory block of size SIZE. - * - * @return Pointer to the allocated memory. - * @see Free - */ - T* Pop() - { - FThreadLocalCache& TLS = GetTLS(); - - if (!TLS.PartialBundle) - { - if (TLS.FullBundle) - { - TLS.PartialBundle = TLS.FullBundle; - TLS.FullBundle = nullptr; - } - else - { - TLS.PartialBundle = GlobalFreeListBundles.Pop(); - if (!TLS.PartialBundle) - { - TLS.PartialBundle = T::GetBundle(NUM_PER_BUNDLE); - NumFree.Add(NUM_PER_BUNDLE); - } - } - TLS.NumPartial = NUM_PER_BUNDLE; - } - NumUsed.Increment(); - NumFree.Decrement(); - T* Result = TLS.PartialBundle; - TLS.PartialBundle = (T*)(TLS.PartialBundle->LockFreePointerQueueNext); - TLS.NumPartial--; - checkLockFreePointerList(TLS.NumPartial >= 0 && ((!!TLS.NumPartial) == (!!TLS.PartialBundle))); - return Result; - } - - /** - * Puts a memory block previously obtained from Allocate() back on the free list for future use. - * - * @param Item The item to free. - * @see Allocate - */ - void Push(T *Item) - { - NumUsed.Decrement(); - NumFree.Increment(); - FThreadLocalCache& TLS = GetTLS(); - if (TLS.NumPartial >= NUM_PER_BUNDLE) - { - if (TLS.FullBundle) - { - GlobalFreeListBundles.Push(TLS.FullBundle); - //TLS.FullBundle = nullptr; - } - TLS.FullBundle = TLS.PartialBundle; - TLS.PartialBundle = nullptr; - TLS.NumPartial = 0; - } - Item->LockFreePointerQueueNext = TLS.PartialBundle; - TLS.PartialBundle = Item; - TLS.NumPartial++; - } - - /** - * Gets the number of allocated memory blocks that are currently in use. - * - * @return Number of used memory blocks. - * @see GetNumFree - */ - const TTrackingCounter& GetNumUsed() const - { - return NumUsed; - } - - /** - * Gets the number of allocated memory blocks that are currently unused. - * - * @return Number of unused memory blocks. - * @see GetNumUsed - */ - const TTrackingCounter& GetNumFree() const - { - return NumFree; - } - -private: - - /** struct for the TLS cache. */ - struct FThreadLocalCache - { - T* FullBundle; - T* PartialBundle; - int32 NumPartial; - - FThreadLocalCache() - : FullBundle(nullptr) - , PartialBundle(nullptr) - , NumPartial(0) - { - } - }; - - FThreadLocalCache& GetTLS() - { - checkSlow(FPlatformTLS::IsValidTlsSlot(TlsSlot)); - FThreadLocalCache* TLS = (FThreadLocalCache*)FPlatformTLS::GetTlsValue(TlsSlot); - if (!TLS) - { - TLS = new FThreadLocalCache(); - FPlatformTLS::SetTlsValue(TlsSlot, TLS); - } - return *TLS; - } - - /** Slot for TLS struct. */ - uint32 TlsSlot; - - /** Lock free list of free memory blocks, these are all linked into a bundle of NUM_PER_BUNDLE. */ - TBundleRecycler GlobalFreeListBundles; - - /** Total number of blocks outstanding and not in the free list. */ - TTrackingCounter NumUsed; - - /** Total number of blocks in the free list. */ - TTrackingCounter NumFree; -}; - -/** - * Thread safe, lock free pooling allocator of fixed size blocks that - * never returns free space, even at shutdown - * alignment isn't handled, assumes FMemory::Malloc will work - */ - -#define USE_NIEVE_TLockFreeFixedSizeAllocator_TLSCacheBase (0) // this is useful for find who really leaked -template -class TLockFreeFixedSizeAllocator_TLSCacheBase : public FNoncopyable -{ - enum - { - NUM_PER_BUNDLE=32, - }; -public: - - TLockFreeFixedSizeAllocator_TLSCacheBase() - { - static_assert(SIZE >= sizeof(void*) && SIZE % sizeof(void*) == 0, "Blocks in TLockFreeFixedSizeAllocator must be at least the size of a pointer."); - check(IsInGameThread()); - TlsSlot = FPlatformTLS::AllocTlsSlot(); - check(FPlatformTLS::IsValidTlsSlot(TlsSlot)); - } - /** Destructor, leaks all of the memory **/ - ~TLockFreeFixedSizeAllocator_TLSCacheBase() - { - FPlatformTLS::FreeTlsSlot(TlsSlot); - TlsSlot = 0; - } - - /** - * Allocates a memory block of size SIZE. - * - * @return Pointer to the allocated memory. - * @see Free - */ - FORCEINLINE void* Allocate() - { -#if USE_NIEVE_TLockFreeFixedSizeAllocator_TLSCacheBase - return FMemory::Malloc(SIZE); -#else - FThreadLocalCache& TLS = GetTLS(); - - if (!TLS.PartialBundle) - { - if (TLS.FullBundle) - { - TLS.PartialBundle = TLS.FullBundle; - TLS.FullBundle = nullptr; - } - else - { - TLS.PartialBundle = GlobalFreeListBundles.Pop(); - if (!TLS.PartialBundle) - { - TLS.PartialBundle = (void**)FMemory::Malloc(SIZE * NUM_PER_BUNDLE); - void **Next = TLS.PartialBundle; - for (int32 Index = 0; Index < NUM_PER_BUNDLE - 1; Index++) - { - void* NextNext = (void*)(((uint8*)Next) + SIZE); - *Next = NextNext; - Next = (void**)NextNext; - } - *Next = nullptr; - NumFree.Add(NUM_PER_BUNDLE); - } - } - TLS.NumPartial = NUM_PER_BUNDLE; - } - NumUsed.Increment(); - NumFree.Decrement(); - void* Result = (void*)TLS.PartialBundle; - TLS.PartialBundle = (void**)*TLS.PartialBundle; - TLS.NumPartial--; - check(TLS.NumPartial >= 0 && ((!!TLS.NumPartial) == (!!TLS.PartialBundle))); - return Result; -#endif - } - - /** - * Puts a memory block previously obtained from Allocate() back on the free list for future use. - * - * @param Item The item to free. - * @see Allocate - */ - FORCEINLINE void Free(void *Item) - { -#if USE_NIEVE_TLockFreeFixedSizeAllocator_TLSCacheBase - return FMemory::Free(Item); -#else - NumUsed.Decrement(); - NumFree.Increment(); - FThreadLocalCache& TLS = GetTLS(); - if (TLS.NumPartial >= NUM_PER_BUNDLE) - { - if (TLS.FullBundle) - { - GlobalFreeListBundles.Push(TLS.FullBundle); - //TLS.FullBundle = nullptr; - } - TLS.FullBundle = TLS.PartialBundle; - TLS.PartialBundle = nullptr; - TLS.NumPartial = 0; - } - *(void**)Item = (void*)TLS.PartialBundle; - TLS.PartialBundle = (void**)Item; - TLS.NumPartial++; -#endif - } - - /** - * Gets the number of allocated memory blocks that are currently in use. - * - * @return Number of used memory blocks. - * @see GetNumFree - */ - const TTrackingCounter& GetNumUsed() const - { - return NumUsed; - } - - /** - * Gets the number of allocated memory blocks that are currently unused. - * - * @return Number of unused memory blocks. - * @see GetNumUsed - */ - const TTrackingCounter& GetNumFree() const - { - return NumFree; - } - -private: - - /** struct for the TLS cache. */ - struct FThreadLocalCache - { - void **FullBundle; - void **PartialBundle; - int32 NumPartial; - - FThreadLocalCache() - : FullBundle(nullptr) - , PartialBundle(nullptr) - , NumPartial(0) - { - } - }; - - FThreadLocalCache& GetTLS() - { - checkSlow(FPlatformTLS::IsValidTlsSlot(TlsSlot)); - FThreadLocalCache* TLS = (FThreadLocalCache*)FPlatformTLS::GetTlsValue(TlsSlot); - if (!TLS) - { - TLS = new FThreadLocalCache(); - FPlatformTLS::SetTlsValue(TlsSlot, TLS); - } - return *TLS; - } - - /** Slot for TLS struct. */ - uint32 TlsSlot; - - /** Lock free list of free memory blocks, these are all linked into a bundle of NUM_PER_BUNDLE. */ - TBundleRecycler GlobalFreeListBundles; - - /** Total number of blocks outstanding and not in the free list. */ - TTrackingCounter NumUsed; - - /** Total number of blocks in the free list. */ - TTrackingCounter NumFree; -}; - -// in these cases it is critical that no thread starves because they must advance and other threads are blocked. - -CORE_API void LockFreeCriticalSpin(int32& SpinCount); - -#if !UE_BUILD_SHIPPING && !UE_BUILD_TEST - -CORE_API void DoTestCriticalStall(); -extern CORE_API int32 GTestCriticalStalls; - -FORCEINLINE void TestCriticalStall() -{ - if (GTestCriticalStalls) - { - DoTestCriticalStall(); - } -} -#else -FORCEINLINE void TestCriticalStall() -{ -} -#endif - -template -class FLockFreePointerQueueBaseSingleConsumerIntrusive : public FNoncopyable -{ -public: - FLockFreePointerQueueBaseSingleConsumerIntrusive() - : Head(GetStub()) - , Tail(GetStub()) - { - GetStub()->LockFreePointerQueueNext = nullptr; - } - - void Push(T* Link) - { - Link->LockFreePointerQueueNext = nullptr; - T* Prev = (T*)FPlatformAtomics::InterlockedExchangePtr((void**)&Head, Link); - TestCriticalStall(); - Prev->LockFreePointerQueueNext = Link; - //FPlatformMisc::MemoryBarrier(); - } - - T* Pop() - { - int32 SpinCount = 0; - while (true) - { - T* LocalTail = Tail; - T* LocalTailNext = (T*)(LocalTail->LockFreePointerQueueNext); - if (LocalTail == GetStub()) - { - if (!LocalTailNext) - { - if (LocalTail != Head) - { - LockFreeCriticalSpin(SpinCount); - continue; - } - return nullptr; - } - Tail = LocalTailNext; - LocalTail = LocalTailNext; - LocalTailNext = (T*)(LocalTailNext->LockFreePointerQueueNext); - } - if (LocalTailNext) - { - Tail = LocalTailNext; - return LocalTail; - } - if (LocalTail != Head) - { - LockFreeCriticalSpin(SpinCount); - continue; - } - Push(GetStub()); - LocalTailNext = (T*)(LocalTail->LockFreePointerQueueNext); - if (LocalTailNext) - { - Tail = LocalTailNext; - return LocalTail; - } - LockFreeCriticalSpin(SpinCount); - } - return nullptr; - } - /** - * Check if the list is empty. - * - * @return true if the list is empty. - * CAUTION: This methods safety depends on external assumptions. For example, if another thread could add to the list at any time, the return value is no better than a best guess. - * As typically used, the list is not being access concurrently when this is called. - */ - bool IsEmpty() const - { - //FPlatformMisc::MemoryBarrier(); - T* LocalTail = Tail; - return Head == LocalTail && GetStub() == LocalTail; - } - -private: - uint8 PadToAvoidContention1[TPaddingForCacheContention]; - T* Head; - uint8 PadToAvoidContention2[TPaddingForCacheContention]; - T* Tail; - uint8 PadToAvoidContention3[TPaddingForCacheContention]; - - T* GetStub() const - { - return (T*)&StubStorage; // we aren't going to do anything with this other than mess with internal links - } - TAlignedBytes StubStorage; -}; - -template -class FLockFreePointerQueueBaseSingleConsumerIntrusive : public FNoncopyable -{ -public: - FLockFreePointerQueueBaseSingleConsumerIntrusive() - : Head(GetStub()) - , Tail(GetStub()) - { - GetStub()->LockFreePointerQueueNext = nullptr; - } - - void Push(T* Link) - { - Link->LockFreePointerQueueNext = nullptr; - T* Prev = (T*)FPlatformAtomics::InterlockedExchangePtr((void**)&Head, Link); - TestCriticalStall(); - Prev->LockFreePointerQueueNext = Link; - //FPlatformMisc::MemoryBarrier(); - } - - T* Pop() - { - int32 SpinCount = 0; - while (true) - { - T* LocalTail = Tail; - T* LocalTailNext = (T*)(LocalTail->LockFreePointerQueueNext); - if (LocalTail == GetStub()) - { - if (!LocalTailNext) - { - if (LocalTail != Head) - { - LockFreeCriticalSpin(SpinCount); - continue; - } - return nullptr; - } - Tail = LocalTailNext; - LocalTail = LocalTailNext; - LocalTailNext = (T*)(LocalTailNext->LockFreePointerQueueNext); - } - if (LocalTailNext) - { - Tail = LocalTailNext; - return LocalTail; - } - if (LocalTail != Head) - { - LockFreeCriticalSpin(SpinCount); - continue; - } - Push(GetStub()); - LocalTailNext = (T*)(LocalTail->LockFreePointerQueueNext); - if (LocalTailNext) - { - Tail = LocalTailNext; - return LocalTail; - } - LockFreeCriticalSpin(SpinCount); - } - return nullptr; - } - /** - * Check if the list is empty. - * - * @return true if the list is empty. - * CAUTION: This methods safety depends on external assumptions. For example, if another thread could add to the list at any time, the return value is no better than a best guess. - * As typically used, the list is not being access concurrently when this is called. - */ - bool IsEmpty() const - { - //FPlatformMisc::MemoryBarrier(); - T* LocalTail = Tail; - return Head == LocalTail && GetStub() == LocalTail; - } - -private: - T* Head; - T* Tail; - - T* GetStub() const - { - return (T*)&StubStorage; // we aren't going to do anything with this other than mess with internal links - } - TAlignedBytes StubStorage; -}; - -struct FLockFreeLink -{ - FLockFreeLink* Next; - void *Payload; -}; - -template -class FSpinLocked_LIFO -{ -public: - void** Pop() - { - int32 SpinCount = 0; - while (true) - { - if (!Lock && FPlatformAtomics::InterlockedCompareExchange((volatile int32*)&Lock, 1, 0) == 0) - { - TestCriticalStall(); - void** Result = nullptr; - if (Queue.Num()) - { - Result = Queue.Pop(false); - } - FPlatformMisc::MemoryBarrier(); - Lock = 0; - return Result; - } - LockFreeCriticalSpin(SpinCount); - } - } - void Push(void** Item) - { - int32 SpinCount = 0; - while (true) - { - if (!Lock && FPlatformAtomics::InterlockedCompareExchange((volatile int32*)&Lock, 1, 0) == 0) - { - TestCriticalStall(); - Queue.Add(Item); - FPlatformMisc::MemoryBarrier(); - Lock = 0; - return; - } - LockFreeCriticalSpin(SpinCount); - } - } -private: - TArray Queue; - uint8 PadToAvoidContention1[TPaddingForCacheContention]; - int32 Lock; - uint8 PadToAvoidContention2[TPaddingForCacheContention]; -}; - -template<> -class FSpinLocked_LIFO<0> -{ -public: - void** Pop() - { - int32 SpinCount = 0; - while (true) - { - if (!Lock && FPlatformAtomics::InterlockedCompareExchange((volatile int32*)&Lock, 1, 0) == 0) - { - TestCriticalStall(); - void** Result = nullptr; - if (Queue.Num()) - { - Result = Queue.Pop(false); - } - FPlatformMisc::MemoryBarrier(); - Lock = 0; - return Result; - } - LockFreeCriticalSpin(SpinCount); - } - } - void Push(void** Item) - { - int32 SpinCount = 0; - while (true) - { - if (!Lock && FPlatformAtomics::InterlockedCompareExchange((volatile int32*)&Lock, 1, 0) == 0) - { - TestCriticalStall(); - Queue.Add(Item); - FPlatformMisc::MemoryBarrier(); - Lock = 0; - return; - } - LockFreeCriticalSpin(SpinCount); - } - } -private: - TArray Queue; - int32 Lock; -}; - -class FLockFreePointerQueueBaseLinkAllocator : public FNoncopyable -{ -public: - static CORE_API FLockFreePointerQueueBaseLinkAllocator& Get(); - - FORCEINLINE void Free(FLockFreeLink* Link) - { - Link->~FLockFreeLink(); - InnerAllocator.Free(Link); - } - - FORCEINLINE FLockFreeLink* Alloc() - { - return new (InnerAllocator.Allocate()) FLockFreeLink(); - } - - /** - * Gets the number of allocated memory blocks that are currently in use. - * - * @return Number of used memory blocks. - */ - const int32 GetNumUsed() const - { - return InnerAllocator.GetNumUsed().GetValue(); - } - - /** - * Gets the number of allocated memory blocks that are currently unused. - * - * @return Number of allocated, but unused memory blocks. - */ - const int32 GetNumFree() const - { - return InnerAllocator.GetNumFree().GetValue(); - } - -private: - TLockFreeFixedSizeAllocator_TLSCacheBase, -#if 1 || UE_BUILD_SHIPPING || UE_BUILD_TEST - FNoopCounter -#else - FThreadSafeCounter -#endif - > InnerAllocator; -}; - -template -class FLockFreePointerQueueBaseSingleConsumer : public FNoncopyable -{ -public: - FLockFreePointerQueueBaseSingleConsumer() - : Head(FLockFreePointerQueueBaseLinkAllocator::Get().Alloc()) - , Tail(Head) - { - } - ~FLockFreePointerQueueBaseSingleConsumer() - { - check(IsEmpty()); - FLockFreePointerQueueBaseLinkAllocator::Get().Free(Head); - } - - void Push(FLockFreeLink* Link) - { - Link->Next = nullptr; - FLockFreeLink* Prev = (FLockFreeLink*)FPlatformAtomics::InterlockedExchangePtr((void**)&Head, Link); - TestCriticalStall(); - Prev->Next = Link; - //FPlatformMisc::MemoryBarrier(); - } - - FLockFreeLink* Pop() - { - int32 SpinCount = 0; - while (true) - { - FLockFreeLink* LocalTail = Tail; - FLockFreeLink* LocalTailNext = LocalTail->Next; - if (LocalTailNext) - { - Tail = LocalTailNext; - LocalTail->Payload = LocalTailNext->Payload; - return LocalTail; - } - else if (Head == LocalTail) - { - break; - } - LockFreeCriticalSpin(SpinCount); - } - return nullptr; - } - - /** - * Check if the list is empty. - * @return true if the list is empty. - * CAUTION: This methods safety depends on external assumptions. For example, if another thread could add to the list at any time, the return value is no better than a best guess. - * As typically used, the list is not being access concurrently when this is called. - */ - bool IsEmpty() const - { - //FPlatformMisc::MemoryBarrier(); - return Head == Tail; - } - -private: - - uint8 PadToAvoidContention1[TPaddingForCacheContention]; - FLockFreeLink* Head; - uint8 PadToAvoidContention2[TPaddingForCacheContention]; - FLockFreeLink* Tail; - uint8 PadToAvoidContention3[TPaddingForCacheContention]; -}; - -template<> -class FLockFreePointerQueueBaseSingleConsumer<0> : public FNoncopyable -{ -public: - FLockFreePointerQueueBaseSingleConsumer() - : Head(FLockFreePointerQueueBaseLinkAllocator::Get().Alloc()) - , Tail(Head) - { - } - - ~FLockFreePointerQueueBaseSingleConsumer() - { - check(IsEmpty()); - FLockFreePointerQueueBaseLinkAllocator::Get().Free(Head); - } - - void Push(FLockFreeLink* Link) - { - Link->Next = nullptr; - FLockFreeLink* Prev = (FLockFreeLink*)FPlatformAtomics::InterlockedExchangePtr((void**)&Head, Link); - TestCriticalStall(); - Prev->Next = Link; - //FPlatformMisc::MemoryBarrier(); - } - - FLockFreeLink* Pop() - { - int32 SpinCount = 0; - while (true) - { - FLockFreeLink* LocalTail = Tail; - FLockFreeLink* LocalTailNext = LocalTail->Next; - if (LocalTailNext) - { - Tail = LocalTailNext; - LocalTail->Payload = LocalTailNext->Payload; - return LocalTail; - } - else if (Head == LocalTail) - { - break; - } - LockFreeCriticalSpin(SpinCount); - } - return nullptr; - } - - /** - * Check if the list is empty. - * @return true if the list is empty. - * CAUTION: This methods safety depends on external assumptions. For example, if another thread could add to the list at any time, the return value is no better than a best guess. - * As typically used, the list is not being access concurrently when this is called. - */ - bool IsEmpty() const - { - //FPlatformMisc::MemoryBarrier(); - return Head == Tail; - } - -private: - - FLockFreeLink* Head; - FLockFreeLink* Tail; -}; - -template -class FCloseableLockFreePointerQueueBaseSingleConsumer : public FNoncopyable -{ -public: - FCloseableLockFreePointerQueueBaseSingleConsumer() - : Head(FLockFreePointerQueueBaseLinkAllocator::Get().Alloc()) - , Tail(Head) - { - - } - - ~FCloseableLockFreePointerQueueBaseSingleConsumer() - { - check(IsEmpty()); - FLockFreePointerQueueBaseLinkAllocator::Get().Free(Head); - } - - /** - * Push an item onto the head of the list, unless the list is closed - * @param NewItem, the new item to push on the list, cannot be nullptr - * @return true if the item was pushed on the list, false if the list was closed. - */ - bool PushIfNotClosed(FLockFreeLink* Link) - { - checkLockFreePointerList(Link); - Link->Next = nullptr; - while (true) - { - FLockFreeLink* LocalHead = Head; - if (!IsClosed(LocalHead)) - { - if (FPlatformAtomics::InterlockedCompareExchangePointer((void**)&Head, Link, LocalHead) == LocalHead) - { - TestCriticalStall(); - LocalHead->Next = Link; - return true; - } - } - else - { - break; - } - } - return false; - } - - /** - * Push an item onto the head of the list, opening it first if necessary - * @param NewItem, the new item to push on the list, cannot be nullptr - * @return true if the list needed to be opened first, false if the list was not closed before our push - */ - bool ReopenIfClosedAndPush(FLockFreeLink *Link) - { - bool bWasReopenedByMe = false; - Link->Next = nullptr; - while (true) - { - FLockFreeLink* LocalHead = Head; - if (FPlatformAtomics::InterlockedCompareExchangePointer((void**)&Head, Link, LocalHead) == LocalHead) - { - TestCriticalStall(); - FLockFreeLink* LocalHeadOpen = ClearClosed(LocalHead); - bWasReopenedByMe = IsClosed(LocalHead); - LocalHeadOpen->Next = Link; - break; - } - } - return bWasReopenedByMe; - } - - /** - * Close the list if it is empty - * @return true if this call actively closed the list - */ - bool CloseIfEmpty() - { - int32 SpinCount = 0; - while (true) - { - FPlatformMisc::MemoryBarrier(); - FLockFreeLink* LocalTail = Tail; - FLockFreeLink* LocalHead = Head; - checkLockFreePointerList(!IsClosed(LocalHead)); - if (LocalTail == LocalHead) - { - FLockFreeLink* LocalHeadClosed = SetClosed(LocalHead); - checkLockFreePointerList(LocalHeadClosed != LocalHead); - if (FPlatformAtomics::InterlockedCompareExchangePointer((void**)&Head, LocalHeadClosed, LocalHead) == LocalHead) - { - return true; - } - } - else - { - break; - } - LockFreeCriticalSpin(SpinCount); - } - return false; - } - /** - * Pop an item from the list or return nullptr if the list is empty - * @return The popped item, if any - * CAUTION: This method should not be used unless the list is known to not be closed. - */ - FLockFreeLink* Pop() - { - int32 SpinCount = 0; - while (true) - { - FLockFreeLink* LocalTail = Tail; - checkLockFreePointerList(!IsClosed(LocalTail)); - FLockFreeLink* LocalTailNext = LocalTail->Next; - checkLockFreePointerList(!IsClosed(LocalTailNext)); - if (LocalTailNext) - { - Tail = LocalTailNext; - LocalTail->Payload = LocalTailNext->Payload; - return LocalTail; - } - else if (Head == LocalTail) - { - break; - } - checkLockFreePointerList(!IsClosed(Head)); - LockFreeCriticalSpin(SpinCount); - } - return nullptr; - } - /** - * Check if the list is empty. - * - * @return true if the list is empty. - * CAUTION: This methods safety depends on external assumptions. For example, if another thread could add to the list at any time, the return value is no better than a best guess. - * As typically used, the list is not being access concurrently when this is called. - */ - bool IsEmpty() const - { - FPlatformMisc::MemoryBarrier(); - return ClearClosed(Head) == Tail; - } - - /** - * Check if the list is closed - * @return true if the list is closed. - * CAUTION: This methods safety depends on external assumptions. For example, if another thread could open or close the list at any time, the return value is no better than a best guess. - * As typically used, the list is only closed once it is lifetime, so a return of true here means it is closed forever. - */ - FORCEINLINE bool IsClosed() const // caution, if this returns false, that does not mean the list is open! - { - FPlatformMisc::MemoryBarrier(); - return IsClosed(Head); - } - /** - * Not thread safe, used to reset the list for recycling without freeing the stub - * @return true if the list is closed. - */ - void Reset() - { - Head = ClearClosed(Head); - FPlatformMisc::MemoryBarrier(); - checkLockFreePointerList(Head == Tail); // we don't clear the list here, we assume it is already clear and possibly closed - } - -private: - // we will use the lowest bit for the closed state - FORCEINLINE static bool IsClosed(FLockFreeLink* HeadToTest) - { - return !!(UPTRINT(HeadToTest) & 1); - } - FORCEINLINE static FLockFreeLink* SetClosed(FLockFreeLink* In) - { - return (FLockFreeLink*)(UPTRINT(In) | 1); - } - FORCEINLINE static FLockFreeLink* ClearClosed(FLockFreeLink* In) - { - return (FLockFreeLink*)(UPTRINT(In) & ~UPTRINT(1)); - } - - uint8 PadToAvoidContention1[TPaddingForCacheContention]; - FLockFreeLink* Head; - uint8 PadToAvoidContention2[TPaddingForCacheContention]; - FLockFreeLink* Tail; - uint8 PadToAvoidContention3[TPaddingForCacheContention]; -}; - -template<> -class FCloseableLockFreePointerQueueBaseSingleConsumer<0> : public FNoncopyable -{ -public: - FCloseableLockFreePointerQueueBaseSingleConsumer() - : Head(FLockFreePointerQueueBaseLinkAllocator::Get().Alloc()) - , Tail(Head) - { - } - ~FCloseableLockFreePointerQueueBaseSingleConsumer() - { - check(IsEmpty()); - FLockFreePointerQueueBaseLinkAllocator::Get().Free(Head); - } - - /** - * Push an item onto the head of the list, unless the list is closed - * @param NewItem, the new item to push on the list, cannot be nullptr - * @return true if the item was pushed on the list, false if the list was closed. - */ - bool PushIfNotClosed(FLockFreeLink* Link) - { - checkLockFreePointerList(Link); - Link->Next = nullptr; - while (true) - { - FLockFreeLink* LocalHead = Head; - if (!IsClosed(LocalHead)) - { - if (FPlatformAtomics::InterlockedCompareExchangePointer((void**)&Head, Link, LocalHead) == LocalHead) - { - TestCriticalStall(); - LocalHead->Next = Link; - return true; - } - } - else - { - break; - } - } - return false; - } - - /** - * Push an item onto the head of the list, opening it first if necessary - * @param NewItem, the new item to push on the list, cannot be nullptr - * @return true if the list needed to be opened first, false if the list was not closed before our push - */ - bool ReopenIfClosedAndPush(FLockFreeLink *Link) - { - bool bWasReopenedByMe = false; - Link->Next = nullptr; - while (true) - { - FLockFreeLink* LocalHead = Head; - if (FPlatformAtomics::InterlockedCompareExchangePointer((void**)&Head, Link, LocalHead) == LocalHead) - { - TestCriticalStall(); - FLockFreeLink* LocalHeadOpen = ClearClosed(LocalHead); - bWasReopenedByMe = IsClosed(LocalHead); - LocalHeadOpen->Next = Link; - break; - } - } - return bWasReopenedByMe; - } - - /** - * Close the list if it is empty - * @return true if this call actively closed the list - */ - bool CloseIfEmpty() - { - int32 SpinCount = 0; - while (true) - { - FPlatformMisc::MemoryBarrier(); - FLockFreeLink* LocalTail = Tail; - FLockFreeLink* LocalHead = Head; - checkLockFreePointerList(!IsClosed(LocalHead)); - if (LocalTail == LocalHead) - { - FLockFreeLink* LocalHeadClosed = SetClosed(LocalHead); - checkLockFreePointerList(LocalHeadClosed != LocalHead); - if (FPlatformAtomics::InterlockedCompareExchangePointer((void**)&Head, LocalHeadClosed, LocalHead) == LocalHead) - { - return true; - } - } - else - { - break; - } - LockFreeCriticalSpin(SpinCount); - } - return false; - } - /** - * Pop an item from the list or return nullptr if the list is empty - * @return The popped item, if any - * CAUTION: This method should not be used unless the list is known to not be closed. - */ - FLockFreeLink* Pop() - { - int32 SpinCount = 0; - while (true) - { - FLockFreeLink* LocalTail = Tail; - checkLockFreePointerList(!IsClosed(LocalTail)); - FLockFreeLink* LocalTailNext = LocalTail->Next; - checkLockFreePointerList(!IsClosed(LocalTailNext)); - if (LocalTailNext) - { - Tail = LocalTailNext; - LocalTail->Payload = LocalTailNext->Payload; - return LocalTail; - } - else if (Head == LocalTail) - { - break; - } - checkLockFreePointerList(!IsClosed(Head)); - LockFreeCriticalSpin(SpinCount); - } - return nullptr; - } - /** - * Check if the list is empty. - * - * @return true if the list is empty. - * CAUTION: This methods safety depends on external assumptions. For example, if another thread could add to the list at any time, the return value is no better than a best guess. - * As typically used, the list is not being access concurrently when this is called. - */ - bool IsEmpty() const - { - FPlatformMisc::MemoryBarrier(); - return ClearClosed(Head) == Tail; - } - - /** - * Check if the list is closed - * @return true if the list is closed. - * CAUTION: This methods safety depends on external assumptions. For example, if another thread could open or close the list at any time, the return value is no better than a best guess. - * As typically used, the list is only closed once it is lifetime, so a return of true here means it is closed forever. - */ - FORCEINLINE bool IsClosed() const // caution, if this returns false, that does not mean the list is open! - { - FPlatformMisc::MemoryBarrier(); - return IsClosed(Head); - } - /** - * Not thread safe, used to reset the list for recycling without freeing the stub - * @return true if the list is closed. - */ - void Reset() - { - Head = ClearClosed(Head); - FPlatformMisc::MemoryBarrier(); - checkLockFreePointerList(Head == Tail); // we don't clear the list here, we assume it is already clear and possibly closed - } - -private: - // we will use the lowest bit for the closed state - FORCEINLINE static bool IsClosed(FLockFreeLink* HeadToTest) - { - return !!(UPTRINT(HeadToTest) & 1); - } - FORCEINLINE static FLockFreeLink* SetClosed(FLockFreeLink* In) - { - return (FLockFreeLink*)(UPTRINT(In) | 1); - } - FORCEINLINE static FLockFreeLink* ClearClosed(FLockFreeLink* In) - { - return (FLockFreeLink*)(UPTRINT(In) & ~UPTRINT(1)); - } - - FLockFreeLink* Head; - FLockFreeLink* Tail; -}; - -template -class FCloseableLockFreePointerQueueBaseSingleBaseConsumerIntrusive : public FNoncopyable -{ -public: - FCloseableLockFreePointerQueueBaseSingleBaseConsumerIntrusive() - : Head(GetStub()) - , Tail(GetStub()) - { - GetStub()->LockFreePointerQueueNext = nullptr; - } -#if 0 - /** - * Push an item onto the head of the list, unless the list is closed - * @param NewItem, the new item to push on the list, cannot be nullptr - * @return true if the item was pushed on the list, false if the list was closed. - */ - bool PushIfNotClosed(T* Link) - { - checkLockFreePointerList(Link); - Link->LockFreePointerQueueNext = nullptr; - while (true) - { - T* LocalHead = Head; - if (!IsClosed(LocalHead)) - { - if (FPlatformAtomics::InterlockedCompareExchangePointer((void**)&Head, Link, LocalHead) == LocalHead) - { - TestCriticalStall(); - LocalHead->LockFreePointerQueueNext = Link; - return true; - } - } - else - { - break; - } - } - return false; - } -#endif - /** - * Push an item onto the head of the list, opening it first if necessary - * @param NewItem, the new item to push on the list, cannot be nullptr - * @return true if the list needed to be opened first, false if the list was not closed before our push - */ - bool ReopenIfClosedAndPush(T *Link) - { - bool bWasReopenedByMe = false; - checkLockFreePointerList(Link); - Link->LockFreePointerQueueNext = nullptr; - while (true) - { - T* LocalHead = Head; - if (FPlatformAtomics::InterlockedCompareExchangePointer((void**)&Head, Link, LocalHead) == LocalHead) - { - TestCriticalStall(); - T* LocalHeadOpen = ClearClosed(LocalHead); - bWasReopenedByMe = IsClosed(LocalHead); - LocalHeadOpen->LockFreePointerQueueNext = Link; - break; - } - } - return bWasReopenedByMe; - } - - /** - * Close the list if it is empty - * @return true if this call actively closed the list - */ - bool CloseIfEmpty() - { - int32 SpinCount = 0; - while (true) - { - T* LocalTail = Tail; - T* LocalHead = Head; - checkLockFreePointerList(!IsClosed(LocalHead)); - if (LocalTail == LocalHead) - { - T* LocalHeadClosed = SetClosed(LocalHead); - checkLockFreePointerList(LocalHeadClosed != LocalHead); - if (FPlatformAtomics::InterlockedCompareExchangePointer((void**)&Head, LocalHeadClosed, LocalHead) == LocalHead) - { - return true; - } - } - else - { - break; - } - LockFreeCriticalSpin(SpinCount); - } - return false; - } - - /** - * Pop an item from the list or return nullptr if the list is empty - * @return The popped item, if any - * CAUTION: This method should not be used unless the list is known to not be closed. - */ - FORCEINLINE T* Pop() - { - int32 SpinCount = 0; - while (true) - { - T* LocalTail = Tail; - checkLockFreePointerList(!IsClosed(LocalTail)); - T* LocalTailNext = (T*)(LocalTail->LockFreePointerQueueNext); - checkLockFreePointerList(!IsClosed(LocalTailNext)); - if (LocalTail == GetStub()) - { - if (!LocalTailNext) - { - if (LocalTail != Head) - { - LockFreeCriticalSpin(SpinCount); - continue; - } - return nullptr; - } - Tail = LocalTailNext; - LocalTail = LocalTailNext; - LocalTailNext = (T*)(LocalTailNext->LockFreePointerQueueNext); - } - if (LocalTailNext) - { - Tail = LocalTailNext; - return LocalTail; - } - if (LocalTail != Head) - { - LockFreeCriticalSpin(SpinCount); - continue; - } - Push(GetStub()); - LocalTailNext = (T*)(LocalTail->LockFreePointerQueueNext); - if (LocalTailNext) - { - Tail = LocalTailNext; - return LocalTail; - } - LockFreeCriticalSpin(SpinCount); - } - return nullptr; - } - /** - * Check if the list is closed - * @return true if the list is closed. - * CAUTION: This methods safety depends on external assumptions. For example, if another thread could open or close the list at any time, the return value is no better than a best guess. - * As typically used, the list is only closed once it is lifetime, so a return of true here means it is closed forever. - */ - FORCEINLINE bool IsClosed() const // caution, if this returns false, that does not mean the list is open! - { - FPlatformMisc::MemoryBarrier(); - return IsClosed(Head); - } -#if 0 - /** - * Check if the list is empty. - * - * @return true if the list is empty. - * CAUTION: This methods safety depends on external assumptions. For example, if another thread could add to the list at any time, the return value is no better than a best guess. - * As typically used, the list is not being access concurrently when this is called. - */ - bool IsEmpty() const - { - FPlatformMisc::MemoryBarrier(); - return ClearClosed(Head) == Tail; - } - - /** - * Not thread safe, used to reset the list for recycling without freeing the stub - * @return true if the list is closed. - */ - void Reset() - { - Head = ClearClosed(Head); - FPlatformMisc::MemoryBarrier(); - checkLockFreePointerList(Head == Tail); // we don't clear the list here, we assume it is already clear and possibly closed - } -#endif -private: - void Push(T* Link) - { - Link->LockFreePointerQueueNext = nullptr; - T* Prev = (T*)FPlatformAtomics::InterlockedExchangePtr((void**)&Head, Link); - TestCriticalStall(); - Prev->LockFreePointerQueueNext = Link; - //FPlatformMisc::MemoryBarrier(); - } - - // we will use the lowest bit for the closed state - FORCEINLINE static bool IsClosed(T* HeadToTest) - { - return !!(UPTRINT(HeadToTest) & 1); - } - FORCEINLINE static T* SetClosed(T* In) - { - return (T*)(UPTRINT(In) | 1); - } - FORCEINLINE static T* ClearClosed(T* In) - { - return (T*)(UPTRINT(In) & ~UPTRINT(1)); - } - - - uint8 PadToAvoidContention1[TPaddingForCacheContention]; - T* Head; - uint8 PadToAvoidContention2[TPaddingForCacheContention]; - T* Tail; - uint8 PadToAvoidContention3[TPaddingForCacheContention]; - - T* GetStub() const - { - return (T*)&StubStorage; // we aren't going to do anything with this other than mess with internal links - } - TAlignedBytes StubStorage; -}; - -template -class FCloseableLockFreePointerQueueBaseSingleBaseConsumerIntrusive : public FNoncopyable -{ -public: - FCloseableLockFreePointerQueueBaseSingleBaseConsumerIntrusive() - : Head(GetStub()) - , Tail(GetStub()) - { - GetStub()->LockFreePointerQueueNext = nullptr; - } -#if 0 - /** - * Push an item onto the head of the list, unless the list is closed - * @param NewItem, the new item to push on the list, cannot be nullptr - * @return true if the item was pushed on the list, false if the list was closed. - */ - bool PushIfNotClosed(T* Link) - { - checkLockFreePointerList(Link); - Link->LockFreePointerQueueNext = nullptr; - while (true) - { - T* LocalHead = Head; - if (!IsClosed(LocalHead)) - { - if (FPlatformAtomics::InterlockedCompareExchangePointer((void**)&Head, Link, LocalHead) == LocalHead) - { - TestCriticalStall(); - LocalHead->LockFreePointerQueueNext = Link; - return true; - } - } - else - { - break; - } - } - return false; - } -#endif - /** - * Push an item onto the head of the list, opening it first if necessary - * @param NewItem, the new item to push on the list, cannot be nullptr - * @return true if the list needed to be opened first, false if the list was not closed before our push - */ - bool ReopenIfClosedAndPush(T *Link) - { - bool bWasReopenedByMe = false; - checkLockFreePointerList(Link); - Link->LockFreePointerQueueNext = nullptr; - while (true) - { - T* LocalHead = Head; - if (FPlatformAtomics::InterlockedCompareExchangePointer((void**)&Head, Link, LocalHead) == LocalHead) - { - TestCriticalStall(); - T* LocalHeadOpen = ClearClosed(LocalHead); - bWasReopenedByMe = IsClosed(LocalHead); - LocalHeadOpen->LockFreePointerQueueNext = Link; - break; - } - } - return bWasReopenedByMe; - } - - /** - * Close the list if it is empty - * @return true if this call actively closed the list - */ - bool CloseIfEmpty() - { - int32 SpinCount = 0; - while (true) - { - T* LocalTail = Tail; - T* LocalHead = Head; - checkLockFreePointerList(!IsClosed(LocalHead)); - if (LocalTail == LocalHead) - { - T* LocalHeadClosed = SetClosed(LocalHead); - checkLockFreePointerList(LocalHeadClosed != LocalHead); - if (FPlatformAtomics::InterlockedCompareExchangePointer((void**)&Head, LocalHeadClosed, LocalHead) == LocalHead) - { - return true; - } - } - else - { - break; - } - LockFreeCriticalSpin(SpinCount); - } - return false; - } - - /** - * Pop an item from the list or return nullptr if the list is empty - * @return The popped item, if any - * CAUTION: This method should not be used unless the list is known to not be closed. - */ - FORCEINLINE T* Pop() - { - int32 SpinCount = 0; - while (true) - { - T* LocalTail = Tail; - checkLockFreePointerList(!IsClosed(LocalTail)); - T* LocalTailNext = (T*)(LocalTail->LockFreePointerQueueNext); - checkLockFreePointerList(!IsClosed(LocalTailNext)); - if (LocalTail == GetStub()) - { - if (!LocalTailNext) - { - if (LocalTail != Head) - { - LockFreeCriticalSpin(SpinCount); - continue; - } - return nullptr; - } - Tail = LocalTailNext; - LocalTail = LocalTailNext; - LocalTailNext = (T*)(LocalTailNext->LockFreePointerQueueNext); - } - if (LocalTailNext) - { - Tail = LocalTailNext; - return LocalTail; - } - if (LocalTail != Head) - { - LockFreeCriticalSpin(SpinCount); - continue; - } - Push(GetStub()); - LocalTailNext = (T*)(LocalTail->LockFreePointerQueueNext); - if (LocalTailNext) - { - Tail = LocalTailNext; - return LocalTail; - } - LockFreeCriticalSpin(SpinCount); - } - return nullptr; - } - /** - * Check if the list is closed - * @return true if the list is closed. - * CAUTION: This methods safety depends on external assumptions. For example, if another thread could open or close the list at any time, the return value is no better than a best guess. - * As typically used, the list is only closed once it is lifetime, so a return of true here means it is closed forever. - */ - FORCEINLINE bool IsClosed() const // caution, if this returns false, that does not mean the list is open! - { - FPlatformMisc::MemoryBarrier(); - return IsClosed(Head); - } -#if 0 - /** - * Check if the list is empty. - * - * @return true if the list is empty. - * CAUTION: This methods safety depends on external assumptions. For example, if another thread could add to the list at any time, the return value is no better than a best guess. - * As typically used, the list is not being access concurrently when this is called. - */ - bool IsEmpty() const - { - FPlatformMisc::MemoryBarrier(); - return ClearClosed(Head) == Tail; - } - - /** - * Not thread safe, used to reset the list for recycling without freeing the stub - * @return true if the list is closed. - */ - void Reset() - { - Head = ClearClosed(Head); - FPlatformMisc::MemoryBarrier(); - checkLockFreePointerList(Head == Tail); // we don't clear the list here, we assume it is already clear and possibly closed - } -#endif -private: - void Push(T* Link) - { - Link->LockFreePointerQueueNext = nullptr; - T* Prev = (T*)FPlatformAtomics::InterlockedExchangePtr((void**)&Head, Link); - TestCriticalStall(); - Prev->LockFreePointerQueueNext = Link; - //FPlatformMisc::MemoryBarrier(); - } - - // we will use the lowest bit for the closed state - FORCEINLINE static bool IsClosed(T* HeadToTest) - { - return !!(UPTRINT(HeadToTest) & 1); - } - FORCEINLINE static T* SetClosed(T* In) - { - return (T*)(UPTRINT(In) | 1); - } - FORCEINLINE static T* ClearClosed(T* In) - { - return (T*)(UPTRINT(In) & ~UPTRINT(1)); - } - - T* Head; - T* Tail; - - T* GetStub() const - { - return (T*)&StubStorage; // we aren't going to do anything with this other than mess with internal links - } - TAlignedBytes StubStorage; -}; - -class FDequeueCache : public FNoncopyable -{ - enum - { - DequeueCacheSize = 256, // probably needs to be a power of two so wraparound works right - }; - - typedef uint32 TCounter; // must be unsigned - typedef int32 TSignedCounter; // must be signed - -public: - FDequeueCache() - : NumPopped(0) - , NumPushed(0) - { - FMemory::Memzero(&Available[0], sizeof(void*) * DequeueCacheSize); - } - - FORCEINLINE void* Pop() - { - int32 SpinCount = 0; - while (true) - { - TCounter LocalNumPushed = NumPushed; - TCounter LocalNumPopped = NumPopped; - if (TSignedCounter(LocalNumPushed - LocalNumPopped) < 0) - { - LockFreeCriticalSpin(SpinCount); - continue; - } - if (LocalNumPushed == LocalNumPopped) - { - break; - } - uint32 Slot = LocalNumPopped % DequeueCacheSize; - FPlatformMisc::MemoryBarrier(); - void *ReturnPtr = Available[Slot]; - TCounter Result = (TCounter)FPlatformAtomics::InterlockedCompareExchange((volatile TSignedCounter*)&NumPopped, LocalNumPopped + 1, LocalNumPopped); - if (Result == LocalNumPopped) - { - check(ReturnPtr); - return ReturnPtr; - } - } - return nullptr; - } - - FORCEINLINE bool IsEmpty() const - { - return NumPushed == NumPopped; - } - - FORCEINLINE bool IsFull() const - { - return NumPushed - NumPopped >= TCounter(DequeueCacheSize); - } - - // must not be called concurrently! - FORCEINLINE bool Push(void* Item) - { - TCounter LocalNumPushed = NumPushed; - TCounter LocalNumPopped = NumPopped; - if (LocalNumPushed - LocalNumPopped >= TCounter(DequeueCacheSize)) - { - return false; - } - check(TSignedCounter(LocalNumPushed - LocalNumPopped) >= 0); // wraparound is ok, this would mean we have at least 16GB of queue for 32 bits...which is not possible - Available[LocalNumPushed % DequeueCacheSize] = Item; - FPlatformMisc::MemoryBarrier(); - verify(++NumPushed == LocalNumPushed + 1); - return true; - } - -private: - - TCounter NumPopped; - void *Available[DequeueCacheSize]; - TCounter NumPushed; -}; - - - -template -class FLockFreePointerListFIFOIntrusive : public FNoncopyable -{ -public: - - FLockFreePointerListFIFOIntrusive() - : DequeueLock(0) - { - } - - void Push(T *Link) - { - IncomingQueue.Push(Link); - } - - FORCEINLINE T* Pop(bool bOkToSpeculativelyReturnNull = false) - { - int32 SpinCount = 0; - while (true) - { - T* Result = (T*)DequeueCache.Pop(); - if (Result) - { - return Result; - } - if (bOkToSpeculativelyReturnNull && IncomingQueue.IsEmpty()) - { - return nullptr; - } - - if (!DequeueLock && FPlatformAtomics::InterlockedCompareExchange((volatile int32*)&DequeueLock, 1, 0) == 0) - { - TestCriticalStall(); - Result = (T*)DequeueCache.Pop(); - if (Result) - { - // someone beat us to it - FPlatformMisc::MemoryBarrier(); - DequeueLock = 0; - return Result; - } - T* Link = IncomingQueue.Pop(); - if (!Link) - { - FPlatformMisc::MemoryBarrier(); - DequeueLock = 0; - return nullptr; - } - check(!DequeueCache.IsFull()); // can't be full because it was empty and we have the lock - verify(DequeueCache.Push(Link)); - while (!DequeueCache.IsFull()) - { - T* Repush = IncomingQueue.Pop(); - if (!Repush) - { - break; - } - verify(DequeueCache.Push(Repush)); - } - FPlatformMisc::MemoryBarrier(); - DequeueLock = 0; - } - LockFreeCriticalSpin(SpinCount); - } - } - - /** - * Check if the list is empty. - * - * @return true if the list is empty. - * CAUTION: This methods safety depends on external assumptions. For example, if another thread could add to the list at any time, the return value is no better than a best guess. - * As typically used, the list is not being access concurrently when this is called. - */ - bool IsEmpty() - { - int32 SpinCount = 0; - bool bResult = true; - while (true) - { - if (!DequeueCache.IsEmpty()) - { - bResult = false; - break; - } - if (!DequeueLock && FPlatformAtomics::InterlockedCompareExchange((volatile int32*)&DequeueLock, 1, 0) == 0) - { - TestCriticalStall(); - bool bAny = false; - if (!DequeueCache.IsFull()) - { - T* Repush = IncomingQueue.Pop(); - if (!Repush) - { - FPlatformMisc::MemoryBarrier(); - DequeueLock = 0; - break; - } - bResult = false; - verify(DequeueCache.Push(Repush)); - } - else - { - bResult = false; // we didn't pop one because the dequeue cache is full...guess it isn't empty - } - FPlatformMisc::MemoryBarrier(); - DequeueLock = 0; - break; - } - LockFreeCriticalSpin(SpinCount); - } - return bResult; - } - /** - * Check if the list is empty. This is a faster, less rigorous test that can miss a queue full of stuff. Used to optimize thread restarts. - */ - bool IsEmptyFast() - { - return DequeueCache.IsEmpty() && IncomingQueue.IsEmpty(); - } - - /** - * Pop all items from the list. - * - * @param Output The array to hold the returned items. Must be empty. - */ - void PopAll(TArray& Output) - { - while (true) - { - T* Item = Pop(); - if (!Item) - { - break; - } - Output.Add(Item); - } - } - -private: - FLockFreePointerQueueBaseSingleConsumerIntrusive IncomingQueue; - FDequeueCache DequeueCache; - int32 DequeueLock; -}; - -template -class FLockFreePointerListFIFOIntrusive : public FNoncopyable -{ -public: - - FLockFreePointerListFIFOIntrusive() - : DequeueLock(0) - { - } - - void Push(T *Link) - { - IncomingQueue.Push(Link); - } - - FORCEINLINE T* Pop(bool bOkToSpeculativelyReturnNull = false) - { - int32 SpinCount = 0; - while (true) - { - T* Result = (T*)DequeueCache.Pop(); - if (Result) - { - return Result; - } - if (bOkToSpeculativelyReturnNull && IncomingQueue.IsEmpty()) - { - return nullptr; - } - - if (!DequeueLock && FPlatformAtomics::InterlockedCompareExchange((volatile int32*)&DequeueLock, 1, 0) == 0) - { - TestCriticalStall(); - Result = (T*)DequeueCache.Pop(); - if (Result) - { - // someone beat us to it - FPlatformMisc::MemoryBarrier(); - DequeueLock = 0; - return Result; - } - T* Link = IncomingQueue.Pop(); - if (!Link) - { - FPlatformMisc::MemoryBarrier(); - DequeueLock = 0; - return nullptr; - } - check(!DequeueCache.IsFull()); // can't be full because it was empty and we have the lock - verify(DequeueCache.Push(Link)); - while (!DequeueCache.IsFull()) - { - T* Repush = IncomingQueue.Pop(); - if (!Repush) - { - break; - } - verify(DequeueCache.Push(Repush)); - } - FPlatformMisc::MemoryBarrier(); - DequeueLock = 0; - } - LockFreeCriticalSpin(SpinCount); - } - } - - /** - * Check if the list is empty. - * - * @return true if the list is empty. - * CAUTION: This methods safety depends on external assumptions. For example, if another thread could add to the list at any time, the return value is no better than a best guess. - * As typically used, the list is not being access concurrently when this is called. - */ - bool IsEmpty() - { - int32 SpinCount = 0; - bool bResult = true; - while (true) - { - if (!DequeueCache.IsEmpty()) - { - bResult = false; - break; - } - if (!DequeueLock && FPlatformAtomics::InterlockedCompareExchange((volatile int32*)&DequeueLock, 1, 0) == 0) - { - TestCriticalStall(); - bool bAny = false; - if (!DequeueCache.IsFull()) - { - T* Repush = IncomingQueue.Pop(); - if (!Repush) - { - FPlatformMisc::MemoryBarrier(); - DequeueLock = 0; - break; - } - bResult = false; - verify(DequeueCache.Push(Repush)); - } - else - { - bResult = false; // we didn't pop one because the dequeue cache is full...guess it isn't empty - } - FPlatformMisc::MemoryBarrier(); - DequeueLock = 0; - break; - } - LockFreeCriticalSpin(SpinCount); - } - return bResult; - } - /** - * Check if the list is empty. This is a faster, less rigorous test that can miss a queue full of stuff. Used to optimize thread restarts. - */ - bool IsEmptyFast() - { - return DequeueCache.IsEmpty() && IncomingQueue.IsEmpty(); - } - - /** - * Pop all items from the list. - * - * @param Output The array to hold the returned items. Must be empty. - */ - void PopAll(TArray& Output) - { - while (true) - { - T* Item = Pop(); - if (!Item) - { - break; - } - Output.Add(Item); - } - } - -private: - FLockFreePointerQueueBaseSingleConsumerIntrusive IncomingQueue; - FDequeueCache DequeueCache; - int32 DequeueLock; -}; - -// FIFO of void *'s -template -class FLockFreePointerListFIFOBase : public FNoncopyable -{ -public: - - FLockFreePointerListFIFOBase() - : LinkAllocator(FLockFreePointerQueueBaseLinkAllocator::Get()) - , DequeueLock(0) - { - } - - void Push(void *Item) - { - FLockFreeLink* Link = LinkAllocator.Alloc(); - Link->Payload = Item; - IncomingQueue.Push(Link); - } - - void* Pop(bool bOkToSpeculativelyReturnNull = false) - { - int32 SpinCount = 0; - while (true) - { - void* Result = DequeueCache.Pop(); - if (Result) - { - return Result; - } - if (bOkToSpeculativelyReturnNull && IncomingQueue.IsEmpty()) - { - return nullptr; - } - if (!DequeueLock && FPlatformAtomics::InterlockedCompareExchange((volatile int32*)&DequeueLock, 1, 0) == 0) - { - TestCriticalStall(); - Result = DequeueCache.Pop(); - if (Result) - { - // someone beat us to it - FPlatformMisc::MemoryBarrier(); - DequeueLock = 0; - return Result; - } - FLockFreeLink* Link = IncomingQueue.Pop(); - if (!Link) - { - FPlatformMisc::MemoryBarrier(); - DequeueLock = 0; - return nullptr; - } - check(!DequeueCache.IsFull() && Link->Payload); // can't be full because it was empty and we have the lock - verify(DequeueCache.Push(Link->Payload)); - LinkAllocator.Free(Link); - while (!DequeueCache.IsFull()) - { - FLockFreeLink* Repush = IncomingQueue.Pop(); - if (!Repush) - { - break; - } - check(Repush->Payload); - verify(DequeueCache.Push(Repush->Payload)); - LinkAllocator.Free(Repush); - } - FPlatformMisc::MemoryBarrier(); - DequeueLock = 0; - } - LockFreeCriticalSpin(SpinCount); - } - } - - /** - * Check if the list is empty. - * - * @return true if the list is empty. - * CAUTION: This methods safety depends on external assumptions. For example, if another thread could add to the list at any time, the return value is no better than a best guess. - * As typically used, the list is not being access concurrently when this is called. - */ - bool IsEmpty() - { - bool bResult = true; - int32 SpinCount = 0; - while (true) - { - if (!DequeueCache.IsEmpty()) - { - bResult = false; - break; - } - if (!DequeueLock && FPlatformAtomics::InterlockedCompareExchange((volatile int32*)&DequeueLock, 1, 0) == 0) - { - TestCriticalStall(); - bool bAny = false; - if (!DequeueCache.IsFull()) - { - FLockFreeLink* Repush = IncomingQueue.Pop(); - if (!Repush) - { - FPlatformMisc::MemoryBarrier(); - DequeueLock = 0; - break; - } - bResult = false; - check(Repush->Payload); - verify(DequeueCache.Push(Repush->Payload)); - LinkAllocator.Free(Repush); - } - else - { - bResult = false; // we didn't pop one because the dequeue cache is full...guess it isn't empty - } - FPlatformMisc::MemoryBarrier(); - DequeueLock = 0; - break; - } - LockFreeCriticalSpin(SpinCount); - } - return bResult; - } - /** - * Check if the list is empty. This is a faster, less rigorous test that can miss a queue full of stuff. Used to optimize thread restarts. - */ - bool IsEmptyFast() - { - return DequeueCache.IsEmpty() && IncomingQueue.IsEmpty(); - } - -private: - FLockFreePointerQueueBaseLinkAllocator& LinkAllocator; - FLockFreePointerQueueBaseSingleConsumer IncomingQueue; - FDequeueCache DequeueCache; - int32 DequeueLock; -}; - -// FIFO of void *'s -template<> -class FLockFreePointerListFIFOBase<0> : public FNoncopyable -{ -public: - - FLockFreePointerListFIFOBase() - : LinkAllocator(FLockFreePointerQueueBaseLinkAllocator::Get()) - , DequeueLock(0) - { - } - - void Push(void *Item) - { - FLockFreeLink* Link = LinkAllocator.Alloc(); - Link->Payload = Item; - IncomingQueue.Push(Link); - } - - void* Pop(bool bOkToSpeculativelyReturnNull = false) - { - int32 SpinCount = 0; - while (true) - { - void* Result = DequeueCache.Pop(); - if (Result) - { - return Result; - } - if (bOkToSpeculativelyReturnNull && IncomingQueue.IsEmpty()) - { - return nullptr; - } - if (!DequeueLock && FPlatformAtomics::InterlockedCompareExchange((volatile int32*)&DequeueLock, 1, 0) == 0) - { - TestCriticalStall(); - Result = DequeueCache.Pop(); - if (Result) - { - // someone beat us to it - FPlatformMisc::MemoryBarrier(); - DequeueLock = 0; - return Result; - } - FLockFreeLink* Link = IncomingQueue.Pop(); - if (!Link) - { - FPlatformMisc::MemoryBarrier(); - DequeueLock = 0; - return nullptr; - } - check(!DequeueCache.IsFull() && Link->Payload); // can't be full because it was empty and we have the lock - verify(DequeueCache.Push(Link->Payload)); - LinkAllocator.Free(Link); - while (!DequeueCache.IsFull()) - { - FLockFreeLink* Repush = IncomingQueue.Pop(); - if (!Repush) - { - break; - } - check(Repush->Payload); - verify(DequeueCache.Push(Repush->Payload)); - LinkAllocator.Free(Repush); - } - FPlatformMisc::MemoryBarrier(); - DequeueLock = 0; - } - LockFreeCriticalSpin(SpinCount); - } - } - - /** - * Check if the list is empty. - * - * @return true if the list is empty. - * CAUTION: This methods safety depends on external assumptions. For example, if another thread could add to the list at any time, the return value is no better than a best guess. - * As typically used, the list is not being access concurrently when this is called. - */ - bool IsEmpty() - { - bool bResult = true; - int32 SpinCount = 0; - while (true) - { - if (!DequeueCache.IsEmpty()) - { - bResult = false; - break; - } - if (!DequeueLock && FPlatformAtomics::InterlockedCompareExchange((volatile int32*)&DequeueLock, 1, 0) == 0) - { - TestCriticalStall(); - bool bAny = false; - if (!DequeueCache.IsFull()) - { - FLockFreeLink* Repush = IncomingQueue.Pop(); - if (!Repush) - { - FPlatformMisc::MemoryBarrier(); - DequeueLock = 0; - break; - } - bResult = false; - check(Repush->Payload); - verify(DequeueCache.Push(Repush->Payload)); - LinkAllocator.Free(Repush); - } - else - { - bResult = false; // we didn't pop one because the dequeue cache is full...guess it isn't empty - } - FPlatformMisc::MemoryBarrier(); - DequeueLock = 0; - break; - } - LockFreeCriticalSpin(SpinCount); - } - return bResult; - } - /** - * Check if the list is empty. This is a faster, less rigorous test that can miss a queue full of stuff. Used to optimize thread restarts. - */ - bool IsEmptyFast() - { - return DequeueCache.IsEmpty() && IncomingQueue.IsEmpty(); - } - -private: - FLockFreePointerQueueBaseLinkAllocator& LinkAllocator; - FLockFreePointerQueueBaseSingleConsumer<0> IncomingQueue; - FDequeueCache DequeueCache; - int32 DequeueLock; -}; - -// closeable FIFO of void *'s -template -class FCloseableLockFreePointerListFIFOBaseSingleConsumer : public FNoncopyable -{ -public: - - FCloseableLockFreePointerListFIFOBaseSingleConsumer() - : LinkAllocator(FLockFreePointerQueueBaseLinkAllocator::Get()) - { - } - /** - * Push an item onto the head of the list, unless the list is closed - * - * @param NewItem, the new item to push on the list, cannot be NULL - * @return true if the item was pushed on the list, false if the list was closed. - */ - bool PushIfNotClosed(void *NewItem) - { - FLockFreeLink* Link = LinkAllocator.Alloc(); - Link->Payload = NewItem; - if (!IncomingQueue.PushIfNotClosed(Link)) - { - LinkAllocator.Free(Link); - return false; - } - return true; - } - - /** - * Pop all items from the list and atomically close it. - * - * @param Output The array to hold the returned items. Must be empty. - */ - template - void PopAllAndClose(TArray& Output) - { - while (true) - { - FLockFreeLink* Link = IncomingQueue.Pop(); - if (Link) - { - Output.Add((T*)Link->Payload); - LinkAllocator.Free(Link); - } - else if (IncomingQueue.CloseIfEmpty()) - { - break; - } - } - } - - /** - * Check if the list is closed - * - * @return true if the list is closed. - */ - FORCEINLINE bool IsClosed() const - { - return IncomingQueue.IsClosed(); - } - - /** - * Push an item onto the head of the list, opening it first if necessary. - * - * @param NewItem, the new item to push on the list, cannot be NULL. - * @return true if the list needed to be opened first, false if the list was not closed before our push. - */ - bool ReopenIfClosedAndPush(void *NewItem) - { - FLockFreeLink* Link = LinkAllocator.Alloc(); - Link->Payload = NewItem; - bool bWasReopenedByMe = IncomingQueue.ReopenIfClosedAndPush(Link); - return bWasReopenedByMe; - } - - /** - * Pop an item from the list or return NULL if the list is empty or closed. - * CAUTION: This method should not be used unless the list is known to not be closed. - * @return The new item, if any - */ - void* Pop() - { - FLockFreeLink* Link = IncomingQueue.Pop(); - if (Link) - { - void* Result = Link->Payload; - LinkAllocator.Free(Link); - return Result; - } - return nullptr; - } - - /** - * Close the list if it is empty. - * - * @return true if this call actively closed the list. - */ - bool CloseIfEmpty() - { - return IncomingQueue.CloseIfEmpty(); - } - - /** - * Not thread safe, used to reset the list for recycling without freeing the stub - * @return true if the list is closed. - */ - FORCEINLINE void Reset() - { - return IncomingQueue.Reset(); - } - -private: - FLockFreePointerQueueBaseLinkAllocator& LinkAllocator; - FCloseableLockFreePointerQueueBaseSingleConsumer IncomingQueue; -}; - -// closeable FIFO of void *'s -template<> -class FCloseableLockFreePointerListFIFOBaseSingleConsumer<0> : public FNoncopyable -{ -public: - - FCloseableLockFreePointerListFIFOBaseSingleConsumer() - : LinkAllocator(FLockFreePointerQueueBaseLinkAllocator::Get()) - { - } - /** - * Push an item onto the head of the list, unless the list is closed - * - * @param NewItem, the new item to push on the list, cannot be NULL - * @return true if the item was pushed on the list, false if the list was closed. - */ - bool PushIfNotClosed(void *NewItem) - { - FLockFreeLink* Link = LinkAllocator.Alloc(); - Link->Payload = NewItem; - if (!IncomingQueue.PushIfNotClosed(Link)) - { - LinkAllocator.Free(Link); - return false; - } - return true; - } - - /** - * Pop all items from the list and atomically close it. - * - * @param Output The array to hold the returned items. Must be empty. - */ - template - void PopAllAndClose(TArray& Output) - { - while (true) - { - FLockFreeLink* Link = IncomingQueue.Pop(); - if (Link) - { - Output.Add((T*)Link->Payload); - LinkAllocator.Free(Link); - } - else if (IncomingQueue.CloseIfEmpty()) - { - break; - } - } - } - - /** - * Check if the list is closed - * - * @return true if the list is closed. - */ - FORCEINLINE bool IsClosed() const - { - return IncomingQueue.IsClosed(); - } - - /** - * Push an item onto the head of the list, opening it first if necessary. - * - * @param NewItem, the new item to push on the list, cannot be NULL. - * @return true if the list needed to be opened first, false if the list was not closed before our push. - */ - bool ReopenIfClosedAndPush(void *NewItem) - { - FLockFreeLink* Link = LinkAllocator.Alloc(); - Link->Payload = NewItem; - bool bWasReopenedByMe = IncomingQueue.ReopenIfClosedAndPush(Link); - return bWasReopenedByMe; - } - - /** - * Pop an item from the list or return NULL if the list is empty or closed. - * CAUTION: This method should not be used unless the list is known to not be closed. - * @return The new item, if any - */ - void* Pop() - { - FLockFreeLink* Link = IncomingQueue.Pop(); - if (Link) - { - void* Result = Link->Payload; - LinkAllocator.Free(Link); - return Result; - } - return nullptr; - } - - /** - * Close the list if it is empty. - * - * @return true if this call actively closed the list. - */ - bool CloseIfEmpty() - { - return IncomingQueue.CloseIfEmpty(); - } - - /** - * Not thread safe, used to reset the list for recycling without freeing the stub - * @return true if the list is closed. - */ - FORCEINLINE void Reset() - { - return IncomingQueue.Reset(); - } - -private: - FLockFreePointerQueueBaseLinkAllocator& LinkAllocator; - FCloseableLockFreePointerQueueBaseSingleConsumer<0> IncomingQueue; -}; - - -template -class TLockFreePointerListFIFO : private FLockFreePointerListFIFOBase -{ -public: - /** - * Push an item onto the head of the list. - * - * @param NewItem, the new item to push on the list, cannot be NULL. - */ - FORCEINLINE void Push(T *NewItem) - { - FLockFreePointerListFIFOBase::Push(NewItem); - } - - /** - * Pop an item from the list or return NULL if the list is empty. - * @return The popped item, if any. - */ - FORCEINLINE T* Pop() - { - return (T*)FLockFreePointerListFIFOBase::Pop(); - } - - /** - * Pop all items from the list. - * - * @param Output The array to hold the returned items. Must be empty. - */ - void PopAll(TArray& Output) - { - while (true) - { - T* Item = Pop(); - if (!Item) - { - break; - } - Output.Add(Item); - } - } - - /** - * Check if the list is empty. - * - * @return true if the list is empty. - * CAUTION: This methods safety depends on external assumptions. For example, if another thread could add to the list at any time, the return value is no better than a best guess. - * As typically used, the list is not being access concurrently when this is called. - */ - FORCEINLINE bool IsEmpty() - { - return FLockFreePointerListFIFOBase::IsEmpty(); - } - /** - * Check if the list is empty. This is a faster, less rigorous test that can miss a queue full of stuff. Used to optimize thread restarts. - */ - FORCEINLINE bool IsEmptyFast() - { - return FLockFreePointerListFIFOBase::IsEmptyFast(); - } -}; - -template -class TLockFreePointerListFIFO : private FLockFreePointerListFIFOBase<0> -{ -public: - /** - * Push an item onto the head of the list. - * - * @param NewItem, the new item to push on the list, cannot be NULL. - */ - FORCEINLINE void Push(T *NewItem) - { - FLockFreePointerListFIFOBase<0>::Push(NewItem); - } - - /** - * Pop an item from the list or return NULL if the list is empty. - * @return The popped item, if any. - */ - FORCEINLINE T* Pop() - { - return (T*)FLockFreePointerListFIFOBase<0>::Pop(); - } - - /** - * Pop all items from the list. - * - * @param Output The array to hold the returned items. Must be empty. - */ - void PopAll(TArray& Output) - { - while (true) - { - T* Item = Pop(); - if (!Item) - { - break; - } - Output.Add(Item); - } - } - - /** - * Check if the list is empty. - * - * @return true if the list is empty. - * CAUTION: This methods safety depends on external assumptions. For example, if another thread could add to the list at any time, the return value is no better than a best guess. - * As typically used, the list is not being access concurrently when this is called. - */ - FORCEINLINE bool IsEmpty() - { - return FLockFreePointerListFIFOBase<0>::IsEmpty(); - } - /** - * Check if the list is empty. This is a faster, less rigorous test that can miss a queue full of stuff. Used to optimize thread restarts. - */ - FORCEINLINE bool IsEmptyFast() - { - return FLockFreePointerListFIFOBase<0>::IsEmptyFast(); - } -}; - -#if USE_NEW_LOCK_FREE_LISTS - -// a list where you don't care what order they pop in. We choose the fastest implementation we have. -template -class TLockFreePointerListUnordered : public TLockFreePointerListFIFO -{ - -}; - -#endif - - diff --git a/Engine/Source/Runtime/Core/Public/Containers/LockFreeVoidPointerListBase128.h b/Engine/Source/Runtime/Core/Public/Containers/LockFreeVoidPointerListBase128.h deleted file mode 100644 index 832f86a0e5a0..000000000000 --- a/Engine/Source/Runtime/Core/Public/Containers/LockFreeVoidPointerListBase128.h +++ /dev/null @@ -1,643 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - - -/** Defines initial values used by the lock free linked list. */ -struct FLockFreeListConstants -{ - /** - * Initial ABA counter, this value is greater than 'lower half' of virtual address space in 64-bit addressing. - * It means that you will never get this address in the pointer obtained by new function, mostly for debugging purpose. - * Set to 200000000000000 for easier reading and debugging. - */ - static const uint64 InitialABACounter = 0x0000B5E620F48000; // 200000000000000 > 48-bit - - /** - * ABA counter for the special closed link, this value is less than 'higher half' of virtual address space in 64-bit addressing. - * It means that you will never get this address in the pointer obtained by new function, mostly for debugging purpose. - */ - static const uint64 SpecialClosedLink = 0xFFFF700000000000; // 18446603336221196288 > 48-bit - - /** - * @return next ABA counter value. - */ - FORCEINLINE static const uint64 GetNextABACounter() - { - static uint64 ABACounter = FLockFreeListConstants::InitialABACounter; - return FPlatformAtomics::InterlockedIncrement( (volatile int64*)&ABACounter ); - } -}; - -/*----------------------------------------------------------------------------- - FLockFreeVoidPointerListBase128 ------------------------------------------------------------------------------*/ - -MS_ALIGN(16) -class FLockFreeVoidPointerListBase128 : public FNoncopyable -{ - struct FLargePointer; -public: - - /** Constructor - sets the list to empty and initializes the allocator if it hasn't already been initialized. */ - FLockFreeVoidPointerListBase128() - { - FLinkAllocator::Get(); // construct allocator singleton if it isn't already - } - - /** Destructor - checks that the list is either empty or closed. Lists should not be destroyed in any other state. */ - ~FLockFreeVoidPointerListBase128() - { - // leak these at shutdown - //checkLockFreePointerList(Head.Pointer == NULL || Head.Pointer == FLinkAllocator::Get().ClosedLink()); // we do not allow destruction except in the empty or closed state - } - - /** - * Push an item onto the head of the list - * @param NewItem, the new item to push on the list, cannot be NULL - * CAUTION: This method should not be used unless the list is known to not be closed. - */ - void Push(void *NewItem) - { - FLink* NewLink = FLinkAllocator::Get().AllocateLink(NewItem); - NewLink->Link( Head ); - NumElements.Increment(); - checkLockFreePointerList(NewLink->Next.Pointer != FLinkAllocator::Get().ClosedLink().Pointer); // it is not permissible to call push on a Closed queue - } - - /** - * Push an item onto the head of the list, unless the list is closed - * @param NewItem, the new item to push on the list, cannot be NULL - * @return true if the item was pushed on the list, false if the list was closed. - */ - bool PushIfNotClosed(void *NewItem) - { - FLink* NewLink = FLinkAllocator::Get().AllocateLink(NewItem); - bool bSuccess = NewLink->LinkIfHeadNotEqual( Head, FLinkAllocator::Get().ClosedLink() ); - if( !bSuccess ) - { - NewLink->Dispose(); - } - else - { - NumElements.Increment(); - } - return bSuccess; - } - - /** - * Push an item onto the head of the list, opening it first if necessary - * @param NewItem, the new item to push on the list, cannot be NULL - * @return true if the list needed to be opened first, false if the list was not closed before our push - */ - bool ReopenIfClosedAndPush(void *NewItem) - { - FLink* NewLink = FLinkAllocator::Get().AllocateLink(NewItem); - while (1) - { - if( NewLink->LinkIfHeadNotEqual( Head, FLinkAllocator::Get().ClosedLink() ) ) - { - NumElements.Increment(); - return false; - } - if( NewLink->ReplaceHeadWithThisIfHeadIsClosed( Head ) ) - { - NumElements.Increment(); - return true; - } - } - } - - /** - * Pop an item from the list or return NULL if the list is empty - * @return The popped item, if any - * CAUTION: This method should not be used unless the list is known to not be closed. - */ - void* Pop() - { - FLink* Link = FLink::Unlink( Head ); - if( !Link ) - { - return nullptr; - } - NumElements.Decrement(); - checkLockFreePointerList(Link != FLinkAllocator::Get().ClosedLink().Pointer); // it is not permissible to call pop on a Closed queue - void* Return = Link->Item; - Link->Dispose(); - return Return; - } - - /** - * Pop an item from the list or return NULL if the list is empty or closed - * @return The new item, if any - */ - void* PopIfNotClosed() - { - FLink* Link = FLink::Unlink( Head, FLinkAllocator::Get().ClosedLink() ); - if( !Link ) - { - return nullptr; - } - NumElements.Decrement(); - checkLockFreePointerList(Link != FLinkAllocator::Get().ClosedLink().Pointer); // internal error, this should not be possible - void* Return = Link->Item; - Link->Dispose(); - return Return; - } - - /** - * Close the list if it is empty - * @return true if this call actively closed the list - */ - bool CloseIfEmpty() - { - if( FLink::ReplaceHeadWithOtherIfHeadIsEmpty( Head, FLinkAllocator::Get().ClosedLink() ) ) - { - return true; - } - return false; - } - - /** - * If the list is empty, replace it with the other list and null the other list. - * @return true if this call actively closed the list - */ - bool ReplaceListIfEmpty( FLockFreeVoidPointerListBase128& NotThreadSafeTempListToReplaceWith ) - { - if( FLink::ReplaceHeadWithOtherIfHeadIsEmpty( Head, NotThreadSafeTempListToReplaceWith.Head ) ) - { - NotThreadSafeTempListToReplaceWith.Head = FLargePointer(); - return true; - } - return false; - } - - /** - * Pop all items from the list - * @param Output The array to hold the returned items. Must be empty. - * CAUTION: This method should not be used unless the list is known to not be closed. - */ - template - void PopAll(ARRAYTYPE& Output) - { - checkLockFreePointerList(!Output.Num()); - FLink* Link = FLink::ReplaceList( Head ); - NumElements.Set( 0 ); - while (Link) - { - checkLockFreePointerList(Link != FLinkAllocator::Get().ClosedLink().Pointer); // it is not permissible to call PopAll on a Closed queue - checkLockFreePointerList(Link->Item); // we don't allow null items - Output.Add((ElementType)(Link->Item)); - FLink* NextLink = Link->Next.Pointer; - Link->Dispose(); - Link = NextLink; - } - } - - /** - * Pop all items from the list and atomically close it. - * @param Output The array to hold the returned items. Must be empty. - */ - template - void PopAllAndClose(ARRAYTYPE& Output) - { - checkLockFreePointerList(!Output.Num()); - FLink* Link = FLink::ReplaceList( Head, FLinkAllocator::Get().ClosedLink() ); - NumElements.Set( 0 ); - while (Link) - { - checkLockFreePointerList(Link != FLinkAllocator::Get().ClosedLink().Pointer); // we should not pop off the closed link - checkLockFreePointerList(Link->Item); // we don't allow null items - Output.Add((ElementType)(Link->Item)); - FLink* NextLink = Link->Next.Pointer; - Link->Dispose(); - Link = NextLink; - } - } - - /** - * Check if the list is closed - * @return true if the list is closed. - * CAUTION: This methods safety depends on external assumptions. For example, if another thread could open or close the list at any time, the return value is no better than a best guess. - * As typically used, the list is only closed once it is lifetime, so a return of true here means it is closed forever. - */ - bool IsClosed() const // caution, if this returns false, that does not mean the list is open! - { - FPlatformMisc::MemoryBarrier(); - return Head.Pointer == FLinkAllocator::Get().ClosedLink().Pointer && Head.ABACounter == FLinkAllocator::Get().ClosedLink().ABACounter; - } - - /** - * Check if the list is empty - * @return true if the list is empty. - * CAUTION: This methods safety depends on external assumptions. For example, if another thread could add to the list at any time, the return value is no better than a best guess. - * As typically used, the list is not being access concurrently when this is called. - */ - bool IsEmpty() const - { - FPlatformMisc::MemoryBarrier(); - return Head.Pointer == nullptr && Head.ABACounter == 0; - } - -#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) - /** - * Checks if item pointers look 'ok'. Used for debugging. - */ - bool CheckPointers() const - { - const int32 AlignmentCheck = ELockFreeAligment::LF128bit - 1; - FPlatformMisc::MemoryBarrier(); - - for( FLink* Link = Head.Pointer; Link; Link = Link->Next.Pointer ) - { - void* ItemPtr = Link->Item; - if (!ItemPtr || (UPTRINT)ItemPtr < 0x100 || (UPTRINT)ItemPtr > FLockFreeListConstants::InitialABACounter ) - { - return false; - } - if ((UPTRINT)ItemPtr & AlignmentCheck) - { - return false; - } - - if ((UPTRINT)Link & AlignmentCheck) - { - return false; - } - - if( Link->Next.ABACounter != 0 && Link->Next.ABACounter < FLockFreeListConstants::InitialABACounter ) - { - return false; - } - } - - return true; - } - - /** - * @return number of elements via iterating through this list, used for debugging. - */ - int32 NumVerified() const - { - FPlatformMisc::MemoryBarrier(); - - int32 NumElements = 0; - for( FLink* Link = Head.Pointer; Link; Link = Link->Next.Pointer ) - { - NumElements++; - } - return NumElements; - } - -#endif //!(UE_BUILD_SHIPPING || UE_BUILD_TEST) - -private: - struct FLink; - - /** Fakes 128-bit pointers to solve the ABA problem. */ - MS_ALIGN(16) - struct FLargePointer - { - /** Default constructor, initializes to zero. */ - FLargePointer() - : Pointer( nullptr ) - , ABACounter( 0 ) - { - } - - /** - * Initialization constructor, only used to initialize the SpecialClosedLink - */ - FLargePointer( FLink* InPointer, uint64 InABACounter ) - : Pointer( InPointer ) - , ABACounter( InABACounter ) - { - } - - /** - * Initialization constructor, only used to get the current value of the head. - * Read atomically 8-bytes and sets ABACounter to 0, which is invalid. - */ - FLargePointer( FLink* InPointer ) - : Pointer( InPointer ) - , ABACounter( 0 ) - { - } - - /** Copy constructor, only valid if copied from constant. */ - FLargePointer( const FLargePointer& Other ) - { - Pointer = Other.Pointer; - ABACounter = Other.ABACounter; - } - - /** Holds pointer to the element. */ - FLink* Pointer; - /** Holds ABA counter. */ - uint64 ABACounter; - } - GCC_ALIGN(16); - - /** - * Internal single-linked list link structure. - * 32 bytes, 8 bytes wasted, not used - */ - MS_ALIGN(16) - struct FLink : public FNoncopyable - { - /** 16 bytes. 'Pointer' to the next element. */ - FLargePointer Next; - - /** 8 bytes. Pointer to the user data. */ - void* Item; - - FLink() - : Item( nullptr ) - {} - - FLargePointer GetSafeNewLinkPointer() - { - return FLargePointer( this, FLockFreeListConstants::GetNextABACounter() ); - } - - /** - * Link this node into the head of the given list. - * @param Head; the head of the list - * CAUTION: Not checked here, but linking into a closed list with the routine would accidentally and incorrectly open the list - */ - void Link(FLargePointer& HeadPointer) - { - const FLargePointer NewLinkPointer = GetSafeNewLinkPointer(); - FLargePointer LocalHeadPointer = FLargePointer(HeadPointer.Pointer); - - do - { - Next = LocalHeadPointer; - } - while( FPlatformAtomics::InterlockedCompareExchange128( (volatile FInt128*)&HeadPointer, (FInt128&)NewLinkPointer, (FInt128*)&LocalHeadPointer ) == false ); - } - - /** - * Link this node into the head of the given list, unless the head is a special, given node - * @param HeadPointer; the head of the list - * @param SpecialClosedLink; special link that is never recycled that indicates a closed list. - * @return true if this node was linked to the head. - */ - bool LinkIfHeadNotEqual( FLargePointer& HeadPointer, const FLargePointer& SpecialClosedLink ) - { - checkLockFreePointerList(!Next.Pointer); // this should not be set yet - - const FLargePointer NewLinkPointer = GetSafeNewLinkPointer(); - FLargePointer LocalHeadPointer = FLargePointer(HeadPointer.Pointer); - - do - { - if( LocalHeadPointer.Pointer==SpecialClosedLink.Pointer ) - { - Next = FLargePointer(); - return false; - } - - Next = LocalHeadPointer; - } - while( FPlatformAtomics::InterlockedCompareExchange128( (volatile FInt128*)&HeadPointer, (FInt128&)NewLinkPointer, (FInt128*)&LocalHeadPointer ) == false ); - - return true; - } - - /** - * If the head is a closed list, then replace it with this node. This is the primitive that is used to open lists - * @param HeadPointer; the head of the list - * @return true if head was replaced with this node - * CAUTION: The test link must a special link that is never recycled. The ABA problem is assumed to not occur here. - */ - bool ReplaceHeadWithThisIfHeadIsClosed( const FLargePointer& HeadPointer ) - { - const FLargePointer NewLinkPointer = GetSafeNewLinkPointer(); - const FLargePointer ClosedLinkPointer = FLinkAllocator::Get().ClosedLink(); - FLargePointer LocalHeadPointer = FLinkAllocator::Get().ClosedLink(); - - do - { - // This will be the same on the first iteration, then LocalHeadPointer will be updated with the latest HeadPointer. - if( LocalHeadPointer.Pointer != ClosedLinkPointer.Pointer ) - { - return false; - } - } - while( FPlatformAtomics::InterlockedCompareExchange128( (volatile FInt128*)&HeadPointer, (FInt128&)NewLinkPointer, (FInt128*)&LocalHeadPointer ) == false ); - - return true; - } - - /** - * If the head is empty, then replace it with a head from the second list. This is the primitive that is used to close lists - * @param HeadPointer; the head of the list - * @param HeadToReplace; the head of the list to be replaced - * @return true if head was replaced with a new head - */ - static bool ReplaceHeadWithOtherIfHeadIsEmpty( FLargePointer& HeadPointer, const FLargePointer& HeadToReplace ) - { - const FLargePointer LocalHeadToReplace = HeadToReplace; - const FLargePointer LocalEmptyLink = FLargePointer(); - FLargePointer LocalHeadPointer = FLargePointer(); - - do - { - // This will be the same on the first iteration, then LocalHeadPointer will be updated with the latest HeadPointer. - if( LocalHeadPointer.Pointer != LocalEmptyLink.Pointer ) - { - return false; - } - } - while( FPlatformAtomics::InterlockedCompareExchange128( (volatile FInt128*)&HeadPointer, (FInt128&)LocalHeadToReplace, (FInt128*)&LocalHeadPointer ) == false ); - - return true; - } - - /** - * Pop an item off the list, unless the list is empty or the head is a special, given node - * @param HeadPointer; the head of the list - * @param SpecialClosedLink; special link that is never recycled that indicates a closed list. Can be NULL for lists that are known to not be closed - * @return The link that was popped off, or NULL if the list was empty or closed. - * CAUTION: Not checked here, but if the list is closed and SpecialClosedLink is NULL, you will pop off the closed link, and that usually isn't what you want - */ - static FLink* Unlink( FLargePointer& HeadPointer, const FLargePointer& SpecialClosedLink = FLargePointer() ) - { - FLargePointer LocalHeadPointer = FLargePointer(HeadPointer.Pointer); - FLargePointer NextPointer; - - do - { - if( LocalHeadPointer.Pointer==nullptr ) - { - return nullptr; - } - if( LocalHeadPointer.Pointer==SpecialClosedLink.Pointer ) - { - return nullptr; - } - - //NextPointer = FLargePointer( LocalHeadPointer.Pointer->Next.Pointer, FLockFreeListConstants::GetNextABACounter() ); - NextPointer = LocalHeadPointer.Pointer->Next; - } - while( FPlatformAtomics::InterlockedCompareExchange128( (volatile FInt128*)&HeadPointer, (FInt128&)NextPointer, (FInt128*)&LocalHeadPointer ) == false ); - checkLockFreePointerList(NextPointer.Pointer == LocalHeadPointer.Pointer->Next.Pointer); - - return LocalHeadPointer.Pointer; - } - - /** - * Replace the list with another list. Use to either acquire all of the items or acquire all of the items and close the list. - * @param HeadPointer; the head of the list - * @param NewHeadLink; Head of the new list to replace this list with - * @return The original list before we replaced it. - * CAUTION: Not checked here, but if the list is closed this is probably not what you want. - */ - static FLink* ReplaceList( FLargePointer& HeadPointer, const FLargePointer& NewHeadLink = FLargePointer() ) - { - FLargePointer LocalHeadPointer = FLargePointer(HeadPointer.Pointer); - const FLargePointer NewHeadLinkPointer = NewHeadLink; - - do - { - if (LocalHeadPointer.Pointer==nullptr && NewHeadLink.Pointer==nullptr) - { - // we are asking to replace NULL with NULL, this does not require an atomic (or any) operation - return nullptr; - } - - checkLockFreePointerList(LocalHeadPointer.Pointer != NewHeadLink.Pointer); // replacing NULL with NULL is ok, but otherwise we cannot be replacing something with itself or we lose determination of who did what. - } - while( FPlatformAtomics::InterlockedCompareExchange128( (volatile FInt128*)&HeadPointer, (FInt128&)NewHeadLinkPointer, (FInt128*)&LocalHeadPointer ) == false ); - - return LocalHeadPointer.Pointer; - } - - /** - * Disposes this node. - */ - void Dispose(); - } - GCC_ALIGN(16); - - /** - * Class to allocate and recycle links. - */ - MS_ALIGN(16) - class FLinkAllocator - { - public: - /** - * Return a new link. - * @param NewItem "item" pointer of the new node. - * @return New node, ready for use - */ - FLink* AllocateLink( void *NewItem ) - { - checkLockFreePointerList(NewItem); // we don't allow null items - if (NumUsedLinks.Increment() % 8192 == 1) - { - UE_CLOG(0/*MONITOR_LINK_ALLOCATION*/,LogLockFreeList, Log, TEXT("Number of links %d"),NumUsedLinks.GetValue()); - } - - FLink* NewLink = FLink::Unlink( FreeLinks ); - if( NewLink ) - { - NewLink->Next = FLargePointer(); - NewLink->Item = nullptr; - NumFreeLinks.Decrement(); - } - else - { - if (NumAllocatedLinks.Increment() % 10 == 1) - { - UE_CLOG(0/*MONITOR_LINK_ALLOCATION*/,LogLockFreeList, Log, TEXT("Number of allocated links %d"),NumAllocatedLinks.GetValue()); - } - - NewLink = new FLink(); - } - - checkLockFreePointerList(!NewLink->Item); - checkLockFreePointerList(!NewLink->Next.Pointer); - NewLink->Item = NewItem; - FPlatformMisc::MemoryBarrier(); - return NewLink; - } - /** - * Make a link available for recycling. - * @param Link link to recycle - * CAUTION: Do not call this directly, it should only be called when the reference count drop to zero. - */ - void FreeLink( FLink* Link ) - { - checkLockFreePointerList(Link != ClosedLink().Pointer); // very bad to recycle the special link - NumUsedLinks.Decrement(); - FPlatformMisc::MemoryBarrier(); - Link->Link(FreeLinks); - NumFreeLinks.Increment(); - } - /** - * @return a pointer to special closed link - */ - const FLargePointer& ClosedLink() const - { - checkLockFreePointerList(NULL != SpecialClosedLink.Pointer); - return SpecialClosedLink; - } - /** - * Singleton access - * @return the singleton for the link allocator - */ - static CORE_API FLinkAllocator& Get(); - - private: - /** - * Constructor zeros the free link list and creates the special closed link - * @return the singleton for the link allocator - */ - FLinkAllocator(); - - /** - * Destructor, should only be called when there are no outstanding links. - * Frees the elements of the free list and frees the special link - * @return the singleton for the link allocator - */ - ~FLinkAllocator(); - - /** Head to a list of free links that can be used for new allocations. **/ - FLargePointer FreeLinks; - - /** Pointer to the special closed link. It should never be recycled. **/ - FLargePointer SpecialClosedLink; - - /** Total number of links outstanding and not in the free list **/ - FLockFreeListCounter NumUsedLinks; - /** Total number of links in the free list **/ - FLockFreeListCounter NumFreeLinks; - /** Total number of links allocated **/ - FLockFreeListCounter NumAllocatedLinks; - } - GCC_ALIGN(16); - - /** Head of the list. */ - FLargePointer Head; - - /** - * Current number of elements, due to the high contention this value may not be valid. - * Used for debugging. - */ - FLockFreeListCounter NumElements; -}; - -inline void FLockFreeVoidPointerListBase128::FLink::Dispose() -{ - Next = FLockFreeVoidPointerListBase128::FLargePointer(); - Item = nullptr; - - FPlatformMisc::MemoryBarrier(); // memory barrier in here to make sure item and next are cleared before the link is recycled - - FLockFreeVoidPointerListBase128::FLinkAllocator::Get().FreeLink( this ); -} - -typedef FLockFreeVoidPointerListBase128 FLockFreeVoidPointerListGeneric; diff --git a/Engine/Source/Runtime/Core/Public/Containers/Map.h b/Engine/Source/Runtime/Core/Public/Containers/Map.h index 0122dc1904d1..42ee92f2bca3 100644 --- a/Engine/Source/Runtime/Core/Public/Containers/Map.h +++ b/Engine/Source/Runtime/Core/Public/Containers/Map.h @@ -5,7 +5,6 @@ #include "CoreTypes.h" #include "Misc/AssertionMacros.h" #include "Templates/UnrealTypeTraits.h" -#include "Templates/AlignOf.h" #include "Templates/UnrealTemplate.h" #include "Templates/Sorting.h" #include "Misc/StructBuilder.h" @@ -1395,7 +1394,7 @@ private: // Check that the class footprint is the same static_assert(sizeof (ScriptType) == sizeof (RealType), "FScriptMap's size doesn't match TMap"); - static_assert(ALIGNOF(ScriptType) == ALIGNOF(RealType), "FScriptMap's alignment doesn't match TMap"); + static_assert(alignof(ScriptType) == alignof(RealType), "FScriptMap's alignment doesn't match TMap"); // Check member sizes static_assert(sizeof(DeclVal().Pairs) == sizeof(DeclVal().Pairs), "FScriptMap's Pairs member size does not match TMap's"); diff --git a/Engine/Source/Runtime/Core/Public/Containers/ScriptArray.h b/Engine/Source/Runtime/Core/Public/Containers/ScriptArray.h index 43258cc66397..e53de24484c0 100644 --- a/Engine/Source/Runtime/Core/Public/Containers/ScriptArray.h +++ b/Engine/Source/Runtime/Core/Public/Containers/ScriptArray.h @@ -62,7 +62,7 @@ public: (OldNum-Index)*NumBytesPerElement ); } - AGRESSIVE_ARRAY_FORCEINLINE int32 Add( int32 Count, int32 NumBytesPerElement ) + int32 Add( int32 Count, int32 NumBytesPerElement ) { check(Count>=0); checkSlow(ArrayNum>=0); diff --git a/Engine/Source/Runtime/Core/Public/Containers/Set.h b/Engine/Source/Runtime/Core/Public/Containers/Set.h index 089328b86f55..2a1eb6d6eb5f 100644 --- a/Engine/Source/Runtime/Core/Public/Containers/Set.h +++ b/Engine/Source/Runtime/Core/Public/Containers/Set.h @@ -5,7 +5,6 @@ #include "CoreTypes.h" #include "Misc/AssertionMacros.h" #include "Templates/UnrealTypeTraits.h" -#include "Templates/AlignOf.h" #include "Templates/UnrealTemplate.h" #include "Containers/ContainerAllocationPolicies.h" #include "Templates/Sorting.h" @@ -16,6 +15,8 @@ #include #include "Templates/TypeHash.h" #include "Containers/SparseArray.h" +#include "Templates/AreTypesEqual.h" +#include "Templates/Decay.h" /** * The base KeyFuncs type with some useful definitions for all KeyFuncs; meant to be derived from instead of used directly. @@ -159,8 +160,8 @@ public: {} /** Initialization constructor. */ - template FORCEINLINE TSetElement(const InitType& InValue) : Value( InValue ) {} - template FORCEINLINE TSetElement( InitType&& InValue) : Value(MoveTemp(InValue)) {} + template ::Type>::Value>::Type> explicit FORCEINLINE TSetElement(const InitType& InValue) : Value( InValue ) {} + template ::Type>::Value>::Type> explicit FORCEINLINE TSetElement( InitType&& InValue) : Value(MoveTemp(InValue)) {} /** Copy/move constructors */ FORCEINLINE TSetElement(const TSetElement& Rhs) : Value( Rhs.Value ), HashNextId( Rhs.HashNextId ), HashIndex(Rhs.HashIndex) {} @@ -1305,8 +1306,8 @@ public: // TSetElement> FStructBuilder SetElementStruct; Result.ElementOffset = SetElementStruct.AddMember(ElementSize, ElementAlignment); - Result.HashNextIdOffset = SetElementStruct.AddMember(sizeof(FSetElementId), ALIGNOF(FSetElementId)); - Result.HashIndexOffset = SetElementStruct.AddMember(sizeof(int32), ALIGNOF(int32)); + Result.HashNextIdOffset = SetElementStruct.AddMember(sizeof(FSetElementId), alignof(FSetElementId)); + Result.HashIndexOffset = SetElementStruct.AddMember(sizeof(int32), alignof(int32)); Result.Size = SetElementStruct.GetSize(); Result.SparseArrayLayout = FScriptSparseArray::GetScriptLayout(SetElementStruct.GetSize(), SetElementStruct.GetAlignment()); @@ -1530,7 +1531,7 @@ private: // Check that the class footprint is the same static_assert(sizeof (ScriptType) == sizeof (RealType), "FScriptSet's size doesn't match TSet"); - static_assert(ALIGNOF(ScriptType) == ALIGNOF(RealType), "FScriptSet's alignment doesn't match TSet"); + static_assert(alignof(ScriptType) == alignof(RealType), "FScriptSet's alignment doesn't match TSet"); // Check member sizes static_assert(sizeof(DeclVal().Elements) == sizeof(DeclVal().Elements), "FScriptSet's Elements member size does not match TSet's"); diff --git a/Engine/Source/Runtime/Core/Public/Containers/SortedMap.h b/Engine/Source/Runtime/Core/Public/Containers/SortedMap.h new file mode 100644 index 000000000000..a8a508fe822a --- /dev/null +++ b/Engine/Source/Runtime/Core/Public/Containers/SortedMap.h @@ -0,0 +1,669 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "Containers/Map.h" +#include "Containers/Algo/BinarySearch.h" +#include "Containers/Algo/Sort.h" +#include "UObject/NameTypes.h" + +/** + * A Map of keys to value, implemented as a sorted TArray of TPairs. It has a mostly identical interface to TMap and is designed as a drop in replacement + * Keys must be unique, there is no equivalent sorted version of TMultiMap + * It uses half as much memory as TMap, but adding/removing elements is O(n) and finding is O(Log n) + * In practice it is faster than TMap for low element counts, and slower as n increases + * This map is always kept sorted by the key type so cannot be sorted manually + */ +template */ > +class TSortedMap +{ + template + friend class TSortedMap; + friend struct TContainerTraits; + +public: + typedef typename TTypeTraits::ConstPointerType KeyConstPointerType; + typedef typename TTypeTraits::ConstInitType KeyInitType; + typedef typename TTypeTraits::ConstInitType ValueInitType; + typedef TPair ElementType; + + TSortedMap() = default; + TSortedMap(TSortedMap&&) = default; + TSortedMap(const TSortedMap&) = default; + TSortedMap& operator=(TSortedMap&&) = default; + TSortedMap& operator=(const TSortedMap&) = default; + + /** Constructor for moving elements from a TSortedMap with a different ArrayAllocator */ + template + TSortedMap(TSortedMap&& Other) + : Pairs(MoveTemp(Other.Pairs)) + { + } + + /** Constructor for copying elements from a TSortedMap with a different ArrayAllocator */ + template + TSortedMap(const TSortedMap& Other) + : Pairs(Other.Pairs) + { + } + + /** Assignment operator for moving elements from a TSortedMap with a different ArrayAllocator */ + template + TSortedMap& operator=(TSortedMap&& Other) + { + Pairs = MoveTemp(Other.Pairs); + return *this; + } + + /** Assignment operator for copying elements from a TSortedMap with a different ArrayAllocator */ + template + TSortedMap& operator=(const TSortedMap& Other) + { + Pairs = Other.Pairs; + return *this; + } + + /** Equality operator. This is efficient because pairs are always sorted */ + FORCEINLINE bool operator==(const TSortedMap& Other) const + { + return Pairs == Other.Pairs; + } + + /** Inequality operator. This is efficient because pairs are always sorted */ + FORCEINLINE bool operator!=(const TSortedMap& Other) const + { + return Pairs != Other.Pairs; + } + + /** + * Removes all elements from the map, potentially leaving space allocated for an expected number of elements about to be added. + * @param ExpectedNumElements - The number of elements about to be added to the set. + */ + FORCEINLINE void Empty(int32 ExpectedNumElements = 0) + { + Pairs.Empty(ExpectedNumElements); + } + + /** Efficiently empties out the map but preserves all allocations and capacities */ + FORCEINLINE void Reset() + { + Pairs.Reset(); + } + + /** Shrinks the pair set to avoid slack. */ + FORCEINLINE void Shrink() + { + Pairs.Shrink(); + } + + /** Preallocates enough memory to contain Number elements */ + FORCEINLINE void Reserve(int32 Number) + { + Pairs.Reserve(Number); + } + + /** @return The number of elements in the map. */ + FORCEINLINE int32 Num() const + { + return Pairs.Num(); + } + + /** + * Helper function to return the amount of memory allocated by this container + * @return number of bytes allocated by this container + */ + FORCEINLINE uint32 GetAllocatedSize() const + { + return Pairs.GetAllocatedSize(); + } + + /** Tracks the container's memory use through an archive. */ + FORCEINLINE void CountBytes(FArchive& Ar) + { + Pairs.CountBytes(Ar); + } + + /** + * Sets the value associated with a key. + * + * @param InKey - The key to associate the value with. + * @param InValue - The value to associate with the key. + * @return A reference to the value as stored in the map. The reference is only valid until the next change to any key in the map. + */ + FORCEINLINE ValueType& Add(const KeyType& InKey, const ValueType& InValue) { return Emplace( InKey , InValue ); } + FORCEINLINE ValueType& Add(const KeyType& InKey, ValueType&& InValue) { return Emplace( InKey , MoveTemp(InValue)); } + FORCEINLINE ValueType& Add( KeyType&& InKey, const ValueType& InValue) { return Emplace(MoveTemp(InKey), InValue ); } + FORCEINLINE ValueType& Add( KeyType&& InKey, ValueType&& InValue) { return Emplace(MoveTemp(InKey), MoveTemp(InValue)); } + + /** + * Sets a default value associated with a key. + * + * @param InKey - The key to associate the value with. + * @return A reference to the value as stored in the map. The reference is only valid until the next change to any key in the map. + */ + FORCEINLINE ValueType& Add(const KeyType& InKey) { return Emplace( InKey ); } + FORCEINLINE ValueType& Add( KeyType&& InKey) { return Emplace(MoveTemp(InKey)); } + + /** + * Sets the value associated with a key. + * + * @param InKey - The key to associate the value with. + * @param InValue - The value to associate with the key. + * @return A reference to the value as stored in the map. The reference is only valid until the next change to any key in the map. + */ + template + ValueType& Emplace(InitKeyType&& InKey, InitValueType&& InValue) + { + ElementType* DataPtr = AllocateMemoryForEmplace(InKey); + + new(DataPtr) ElementType(TPairInitializer(Forward(InKey), Forward(InValue))); + + return DataPtr->Value; + } + + /** + * Sets a default value associated with a key. + * + * @param InKey - The key to associate the value with. + * @return A reference to the value as stored in the map. The reference is only valid until the next change to any key in the map. + */ + template + ValueType& Emplace(InitKeyType&& InKey) + { + ElementType* DataPtr = AllocateMemoryForEmplace(InKey); + + new(DataPtr) ElementType(TKeyInitializer(Forward(InKey))); + + return DataPtr->Value; + } + + /** + * Removes all value associations for a key. + * @param InKey - The key to remove associated values for. + * @return The number of values that were associated with the key. + */ + FORCEINLINE int32 Remove(KeyConstPointerType InKey) + { + int32 RemoveIndex = FindIndex(InKey); + + if (RemoveIndex == INDEX_NONE) + { + return 0; + } + + Pairs.RemoveAt(RemoveIndex); + + return 1; + } + + /** + * Returns the key associated with the specified value. The time taken is O(N) in the number of pairs. + * @param Value - The value to search for + * @return A pointer to the key associated with the specified value, or nullptr if the value isn't contained in this map. The pointer + * is only valid until the next change to any key in the map. + */ + const KeyType* FindKey(ValueInitType Value) const + { + for(typename ElementArrayType::TConstIterator PairIt(Pairs);PairIt;++PairIt) + { + if(PairIt->Value == Value) + { + return &PairIt->Key; + } + } + return nullptr; + } + + /** + * Returns the value associated with a specified key. + * @param Key - The key to search for. + * @return A pointer to the value associated with the specified key, or nullptr if the key isn't contained in this map. The pointer + * is only valid until the next change to any key in the map. + */ + FORCEINLINE ValueType* Find(KeyConstPointerType Key) + { + int32 FoundIndex = FindIndex(Key); + + if (FoundIndex != INDEX_NONE) + { + return &Pairs[FoundIndex].Value; + } + + return nullptr; + } + + FORCEINLINE const ValueType* Find(KeyConstPointerType Key) const + { + return const_cast(this)->Find(Key); + } + + /** + * Returns the value associated with a specified key, or if none exists, + * adds a value using the default constructor. + * @param Key - The key to search for. + * @return A reference to the value associated with the specified key. + */ + FORCEINLINE ValueType& FindOrAdd(const KeyType& Key) { return FindOrAddImpl( Key ); } + FORCEINLINE ValueType& FindOrAdd( KeyType&& Key) { return FindOrAddImpl(MoveTemp(Key)); } + + /** + * Returns a reference to the value associated with a specified key. + * @param Key - The key to search for. + * @return The value associated with the specified key, or triggers an assertion if the key does not exist. + */ + FORCEINLINE ValueType& FindChecked(KeyConstPointerType Key) + { + ValueType* Value = Find(Key); + check(Value != nullptr); + return *Value; + } + + FORCEINLINE const ValueType& FindChecked(KeyConstPointerType Key) const + { + const ValueType* Value = Find(Key); + check(Value != nullptr); + return *Value; + } + + /** + * Returns the value associated with a specified key. + * @param Key - The key to search for. + * @return The value associated with the specified key, or the default value for the ValueType if the key isn't contained in this map. + */ + FORCEINLINE ValueType FindRef(KeyConstPointerType Key) const + { + if (const ValueType* Value = Find(Key)) + { + return *Value; + } + + return ValueType(); + } + + /** + * Checks if map contains the specified key. + * @param Key - The key to check for. + * @return true if the map contains the key. + */ + FORCEINLINE bool Contains(KeyConstPointerType Key) const + { + if (Find(Key)) + { + return true; + } + return false; + } + + /** + * Returns the unique keys contained within this map + * @param OutKeys - Upon return, contains the set of unique keys in this map. + * @return The number of unique keys in the map. + */ + template int32 GetKeys(TArray& OutKeys) const + { + for (typename ElementArrayType::TConstIterator PairIt(Pairs); PairIt; ++PairIt) + { + new(OutKeys) KeyType(PairIt->Key); + } + + return OutKeys.Num(); + } + + /** + * Generates an array from the keys in this map. + */ + template void GenerateKeyArray(TArray& OutArray) const + { + OutArray.Empty(Pairs.Num()); + for(typename ElementArrayType::TConstIterator PairIt(Pairs);PairIt;++PairIt) + { + new(OutArray) KeyType(PairIt->Key); + } + } + + /** + * Generates an array from the values in this map. + */ + template void GenerateValueArray(TArray& OutArray) const + { + OutArray.Empty(Pairs.Num()); + for(typename ElementArrayType::TConstIterator PairIt(Pairs);PairIt;++PairIt) + { + new(OutArray) ValueType(PairIt->Value); + } + } + + /** Serializer. */ + FORCEINLINE friend FArchive& operator<<(FArchive& Ar, TSortedMap& Map) + { + Ar << Map.Pairs; + + if (Ar.IsLoading()) + { + // We need to resort, in case the sorting is not consistent with what it was before + Algo::SortBy(Map.Pairs, FKeyForward(), SortPredicate()); + } + return Ar; + } + + /** + * Describes the map's contents through an output device. + * @param Ar - The output device to describe the map's contents through. + */ + void Dump(FOutputDevice& Ar) + { + Pairs.Dump(Ar); + } + + /** + * Removes the pair with the specified key and copies the value that was removed to the ref parameter + * @param Key - the key to search for + * @param OutRemovedValue - if found, the value that was removed (not modified if the key was not found) + * @return whether or not the key was found + */ + FORCEINLINE bool RemoveAndCopyValue(KeyInitType Key, ValueType& OutRemovedValue) + { + int32 FoundIndex = FindIndex(Key); + if (FoundIndex == INDEX_NONE) + { + return false; + } + + OutRemovedValue = MoveTemp(Pairs[FoundIndex].Value); + Pairs.RemoveAt(FoundIndex); + return true; + } + + /** + * Finds a pair with the specified key, removes it from the map, and returns the value part of the pair. + * If no pair was found, an exception is thrown. + * @param Key - the key to search for + * @return whether or not the key was found + */ + FORCEINLINE ValueType FindAndRemoveChecked(KeyConstPointerType Key) + { + int32 FoundIndex = FindIndex(Key); + check(FoundIndex != INDEX_NONE); + + ValueType OutRemovedValue = MoveTemp(Pairs[FoundIndex].Value); + Pairs.RemoveAt(FoundIndex); + return OutRemovedValue; + } + + /** + * Move all items from another map into our map (if any keys are in both, the value from the other map wins) and empty the other map. + * @param OtherMap - The other map of items to move the elements from. + */ + template + void Append(TSortedMap&& OtherMap) + { + this->Reserve(this->Num() + OtherMap.Num()); + for (auto& Pair : OtherMap) + { + this->Add(MoveTemp(Pair.Key), MoveTemp(Pair.Value)); + } + + OtherMap.Reset(); + } + + /** + * Add all items from another map to our map (if any keys are in both, the value from the other map wins) + * @param OtherMap - The other map of items to add. + */ + template + void Append(const TSortedMap& OtherMap) + { + this->Reserve(this->Num() + OtherMap.Num()); + for (auto& Pair : OtherMap) + { + this->Add(Pair.Key, Pair.Value); + } + } + + FORCEINLINE ValueType& operator[](KeyConstPointerType Key) { return this->FindChecked(Key); } + FORCEINLINE const ValueType& operator[](KeyConstPointerType Key) const { return this->FindChecked(Key); } + +private: + typedef TArray ElementArrayType; + + /** Implementation of find and add */ + template + FORCEINLINE ValueType& FindOrAddImpl(ArgType&& Key) + { + if (ValueType* Value = Find(Key)) + { + return *Value; + } + + return Add(Forward(Key)); + } + + /** Find index of key */ + FORCEINLINE int32 FindIndex(KeyConstPointerType Key) + { + return Algo::BinarySearchBy(Pairs, Key, FKeyForward(), SortPredicate()); + } + + /** Allocates raw memory for emplacing */ + template + FORCEINLINE ElementType* AllocateMemoryForEmplace(InitKeyType&& InKey) + { + int32 InsertIndex = Algo::LowerBoundBy(Pairs, InKey, FKeyForward(), SortPredicate()); + check(InsertIndex >= 0 && InsertIndex <= Pairs.Num()); + + ElementType* DataPtr = nullptr; + // Since we returned lower bound we already know InKey <= InsertIndex key. So if InKey is not < InsertIndex key, they must be equal + if (Pairs.IsValidIndex(InsertIndex) && !SortPredicate()(InKey, Pairs[InsertIndex].Key)) + { + // Replacing element, delete old one + DataPtr = Pairs.GetData() + InsertIndex; + DestructItems(DataPtr, 1); + } + else + { + // Adding new one, this may reallocate Pairs + Pairs.InsertUninitialized(InsertIndex, 1); + DataPtr = Pairs.GetData() + InsertIndex; + } + + return DataPtr; + } + + /** Forwards sorting into Key of pair */ + struct FKeyForward + { + FORCEINLINE const KeyType& operator()(const ElementType& Pair) const + { + return Pair.Key; + } + }; + + /** The base of TSortedMap iterators */ + template + class TBaseIterator + { + public: + typedef typename TChooseClass::Result PairItType; + private: + typedef typename TChooseClass::Result MapType; + typedef typename TChooseClass::Result ItKeyType; + typedef typename TChooseClass::Result ItValueType; + typedef typename TChooseClass::Result PairType; + + protected: + FORCEINLINE TBaseIterator(const PairItType& InElementIt) + : PairIt(InElementIt) + { + } + + public: + FORCEINLINE TBaseIterator& operator++() + { + ++PairIt; + return *this; + } + + /** conversion to "bool" returning true if the iterator is valid. */ + FORCEINLINE explicit operator bool() const + { + return !!PairIt; + } + + FORCEINLINE friend bool operator==(const TBaseIterator& Lhs, const TBaseIterator& Rhs) { return Lhs.PairIt == Rhs.PairIt; } + FORCEINLINE friend bool operator!=(const TBaseIterator& Lhs, const TBaseIterator& Rhs) { return Lhs.PairIt != Rhs.PairIt; } + + FORCEINLINE ItKeyType& Key() const { return PairIt->Key; } + FORCEINLINE ItValueType& Value() const { return PairIt->Value; } + + FORCEINLINE PairType& operator* () const { return *PairIt; } + FORCEINLINE PairType* operator->() const { return &*PairIt; } + + protected: + PairItType PairIt; + }; + + /** An array of the key-value pairs in the map */ + ElementArrayType Pairs; + +public: + + /** Map iterator */ + class TIterator : public TBaseIterator + { + public: + + FORCEINLINE TIterator(TSortedMap& InMap) + : TBaseIterator(InMap.Pairs.CreateIterator()) + { + } + + FORCEINLINE TIterator(const typename TBaseIterator::PairItType& InPairIt) + : TBaseIterator(InPairIt) + { + } + + /** Removes the current pair from the map */ + FORCEINLINE void RemoveCurrent() + { + TBaseIterator::PairIt.RemoveCurrent(); + } + }; + + /** Const map iterator */ + class TConstIterator : public TBaseIterator + { + public: + FORCEINLINE TConstIterator(const TSortedMap& InMap) + : TBaseIterator(InMap.Pairs.CreateConstIterator()) + { + } + + FORCEINLINE TConstIterator(const typename TBaseIterator::PairItType& InPairIt) + : TBaseIterator(InPairIt) + { + } + }; + + /** Iterates over values associated with a specified key in a const map. This will be at most one value because keys must be unique */ + class TConstKeyIterator : public TBaseIterator + { + public: + FORCEINLINE TConstKeyIterator(const TSortedMap& InMap, KeyInitType InKey) + : TBaseIterator(InMap.Pairs.CreateIterator()) + { + int32 NewIndex = FindIndex(InKey); + + if (NewIndex != INDEX_NONE) + { + TBaseIterator::PairIt += NewIndex; + } + else + { + TBaseIterator::PairIt.SetToEnd(); + } + } + + FORCEINLINE TConstKeyIterator& operator++() + { + TBaseIterator::PairIt.SetToEnd(); + return *this; + } + }; + + /** Iterates over values associated with a specified key in a map. This will be at most one value because keys must be unique */ + class TKeyIterator : public TBaseIterator + { + public: + FORCEINLINE TKeyIterator(TSortedMap& InMap, KeyInitType InKey) + : TBaseIterator(InMap.Pairs.CreateConstIterator()) + { + int32 NewIndex = FindIndex(InKey); + + if (NewIndex != INDEX_NONE) + { + TBaseIterator::PairIt += NewIndex; + } + else + { + TBaseIterator::PairIt.SetToEnd(); + } + } + + FORCEINLINE TKeyIterator& operator++() + { + TBaseIterator::PairIt.SetToEnd(); + return *this; + } + + /** Removes the current key-value pair from the map. */ + FORCEINLINE void RemoveCurrent() + { + TBaseIterator::PairIt.RemoveCurrent(); + TBaseIterator::PairIt.SetToEnd(); + } + }; + + /** Creates an iterator over all the pairs in this map */ + FORCEINLINE TIterator CreateIterator() + { + return TIterator(*this); + } + + /** Creates a const iterator over all the pairs in this map */ + FORCEINLINE TConstIterator CreateConstIterator() const + { + return TConstIterator(*this); + } + + /** Creates an iterator over the values associated with a specified key in a map. This will be at most one value because keys must be unique */ + FORCEINLINE TKeyIterator CreateKeyIterator(KeyInitType InKey) + { + return TKeyIterator(*this, InKey); + } + + /** Creates a const iterator over the values associated with a specified key in a map. This will be at most one value because keys must be unique */ + FORCEINLINE TConstKeyIterator CreateConstKeyIterator(KeyInitType InKey) const + { + return TConstKeyIterator(*this, InKey); + } + + /** Ranged For iterators. Unlike normal TMap these are not the same as the normal iterator for performance reasons */ + typedef typename ElementArrayType::RangedForIteratorType RangedForIteratorType; + typedef typename ElementArrayType::RangedForConstIteratorType RangedForConstIteratorType; + +private: + /** + * DO NOT USE DIRECTLY + * STL-like iterators to enable range-based for loop support. + */ + FORCEINLINE friend RangedForIteratorType begin(TSortedMap& MapBase) { return begin(MapBase.Pairs); } + FORCEINLINE friend RangedForConstIteratorType begin(const TSortedMap& MapBase){ return begin(MapBase.Pairs); } + FORCEINLINE friend RangedForIteratorType end(TSortedMap& MapBase) { return end(MapBase.Pairs); } + FORCEINLINE friend RangedForConstIteratorType end(const TSortedMap& MapBase) { return end(MapBase.Pairs); } +}; + +template +struct TContainerTraits> : public TContainerTraitsBase> +{ + enum { MoveWillEmptyContainer = TContainerTraits::ElementArrayType>::MoveWillEmptyContainer }; +}; diff --git a/Engine/Source/Runtime/Core/Public/Containers/SparseArray.h b/Engine/Source/Runtime/Core/Public/Containers/SparseArray.h index 32985ab64a74..67b8dcdb914b 100644 --- a/Engine/Source/Runtime/Core/Public/Containers/SparseArray.h +++ b/Engine/Source/Runtime/Core/Public/Containers/SparseArray.h @@ -7,7 +7,6 @@ #include "HAL/UnrealMemory.h" #include "Templates/IsTriviallyCopyConstructible.h" #include "Templates/UnrealTypeTraits.h" -#include "Templates/AlignOf.h" #include "Templates/UnrealTemplate.h" #include "Templates/IsTriviallyDestructible.h" #include "Containers/ContainerAllocationPolicies.h" @@ -557,11 +556,13 @@ public: /** Copy assignment operator. */ TSparseArray& operator=(const TSparseArray& InCopy) { - if(this != &InCopy) + if (this != &InCopy) { + int32 SrcMax = InCopy.GetMaxIndex(); + // Reallocate the array. - Empty(InCopy.GetMaxIndex()); - Data.AddUninitialized(InCopy.GetMaxIndex()); + Empty(SrcMax); + Data.AddUninitialized(SrcMax); // Copy the other array's element allocation state. FirstFreeIndex = InCopy.FirstFreeIndex; @@ -571,26 +572,29 @@ public: // Determine whether we need per element construction or bulk copy is fine if (!TIsTriviallyCopyConstructible::Value) { - FElementOrFreeListLink* SrcData = (FElementOrFreeListLink*)Data.GetData(); - const FElementOrFreeListLink* DestData = (FElementOrFreeListLink*)InCopy.Data.GetData(); + FElementOrFreeListLink* DestData = (FElementOrFreeListLink*)Data.GetData(); + const FElementOrFreeListLink* SrcData = (FElementOrFreeListLink*)InCopy.Data.GetData(); // Use the inplace new to copy the element to an array element - for(int32 Index = 0;Index < InCopy.GetMaxIndex();Index++) + for (int32 Index = 0; Index < SrcMax; ++Index) { - FElementOrFreeListLink& DestElement = SrcData [Index]; - const FElementOrFreeListLink& SourceElement = DestData[Index]; - if(InCopy.IsAllocated(Index)) + FElementOrFreeListLink& DestElement = DestData[Index]; + const FElementOrFreeListLink& SrcElement = SrcData [Index]; + if (InCopy.IsAllocated(Index)) { - ::new((uint8*)&DestElement.ElementData) ElementType(*(ElementType*)&SourceElement.ElementData); + ::new((uint8*)&DestElement.ElementData) ElementType(*(const ElementType*)&SrcElement.ElementData); + } + else + { + DestElement.PrevFreeIndex = SrcElement.PrevFreeIndex; + DestElement.NextFreeIndex = SrcElement.NextFreeIndex; } - DestElement.PrevFreeIndex = SourceElement.PrevFreeIndex; - DestElement.NextFreeIndex = SourceElement.NextFreeIndex; } } else { // Use the much faster path for types that allow it - FMemory::Memcpy(Data.GetData(),InCopy.Data.GetData(),sizeof(FElementOrFreeListLink) * InCopy.GetMaxIndex()); + FMemory::Memcpy(Data.GetData(), InCopy.Data.GetData(), sizeof(FElementOrFreeListLink) * SrcMax); } } return *this; @@ -831,7 +835,7 @@ private: * compatible types. */ typedef TSparseArrayElementOrFreeListLink< - TAlignedBytes + TAlignedBytes > FElementOrFreeListLink; /** Extracts the element value from the array's element structure and passes it to the user provided comparison class. */ @@ -916,7 +920,7 @@ public: { FScriptSparseArrayLayout Result; Result.ElementOffset = 0; - Result.Alignment = FMath::Max(ElementAlignment, (int32)ALIGNOF(FFreeListLink)); + Result.Alignment = FMath::Max(ElementAlignment, (int32)alignof(FFreeListLink)); Result.Size = FMath::Max(ElementSize, (int32)sizeof (FFreeListLink)); return Result; @@ -1031,7 +1035,7 @@ private: // Check that the class footprint is the same static_assert(sizeof (ScriptType) == sizeof (RealType), "FScriptSparseArray's size doesn't match TSparseArray"); - static_assert(ALIGNOF(ScriptType) == ALIGNOF(RealType), "FScriptSparseArray's alignment doesn't match TSparseArray"); + static_assert(alignof(ScriptType) == alignof(RealType), "FScriptSparseArray's alignment doesn't match TSparseArray"); // Check member sizes static_assert(sizeof(DeclVal().Data) == sizeof(DeclVal().Data), "FScriptSparseArray's Data member size does not match TSparseArray's"); diff --git a/Engine/Source/Runtime/Core/Public/Containers/StaticArray.h b/Engine/Source/Runtime/Core/Public/Containers/StaticArray.h index 66e541cb8899..d06aed77d933 100644 --- a/Engine/Source/Runtime/Core/Public/Containers/StaticArray.h +++ b/Engine/Source/Runtime/Core/Public/Containers/StaticArray.h @@ -5,12 +5,11 @@ #include "CoreTypes.h" #include "Misc/AssertionMacros.h" #include "Templates/UnrealTypeTraits.h" -#include "Templates/AlignOf.h" #include "Templates/TypeCompatibleBytes.h" #include "Templates/MemoryOps.h" /** An array with a static number of elements. */ -template +template class TStaticArray { public: diff --git a/Engine/Source/Runtime/Core/Public/Containers/StaticBitArray.h b/Engine/Source/Runtime/Core/Public/Containers/StaticBitArray.h index 1489fb2284c2..24655db18691 100644 --- a/Engine/Source/Runtime/Core/Public/Containers/StaticBitArray.h +++ b/Engine/Source/Runtime/Core/Public/Containers/StaticBitArray.h @@ -273,6 +273,73 @@ public: { return !(A == Value); } + + /** + * Finds the first clear bit in the array and returns the bit index. + * If there isn't one, INDEX_NONE is returned. + */ + int32 FindFirstClearBit() const + { + static const int32 NumBitsPerWordLog2 = FMath::FloorLog2(NumBitsPerWord); + + const int32 LocalNumBits = NumBits; + + int32 WordIndex = 0; + // Iterate over the array until we see a word with a unset bit. + while (WordIndex < NumWords && Words[WordIndex] == WordType(-1)) + { + ++WordIndex; + } + + if (WordIndex < NumWords) + { + // Flip the bits, then we only need to find the first one bit -- easy. + const WordType Bits = ~(Words[WordIndex]); + ASSUME(Bits != 0); + + const uint32 LowestBit = (Bits) & (-WordType(Bits)); + const int32 LowestBitIndex = FMath::CountTrailingZeros(Bits) + (WordIndex << NumBitsPerWordLog2); + if (LowestBitIndex < LocalNumBits) + { + return LowestBitIndex; + } + } + + return INDEX_NONE; + } + + /** + * Finds the first set bit in the array and returns it's index. + * If there isn't one, INDEX_NONE is returned. + */ + int32 FindFirstSetBit() const + { + static const int32 NumBitsPerWordLog2 = FMath::FloorLog2(NumBitsPerWord); + + const int32 LocalNumBits = NumBits; + + int32 WordIndex = 0; + // Iterate over the array until we see a word with a set bit. + while (WordIndex < NumWords && Words[WordIndex] == WordType(0)) + { + ++WordIndex; + } + + if (WordIndex < NumWords) + { + const WordType Bits = Words[WordIndex]; + ASSUME(Bits != 0); + + const uint32 LowestBit = (Bits) & (-WordType(Bits)); + const int32 LowestBitIndex = FMath::CountTrailingZeros(Bits) + (WordIndex << NumBitsPerWordLog2); + if (LowestBitIndex < LocalNumBits) + { + return LowestBitIndex; + } + } + + return INDEX_NONE; + } /** * Serializer. diff --git a/Engine/Source/Runtime/Core/Public/Containers/Ticker.h b/Engine/Source/Runtime/Core/Public/Containers/Ticker.h index 107a0037c9e6..36db27e34662 100644 --- a/Engine/Source/Runtime/Core/Public/Containers/Ticker.h +++ b/Engine/Source/Runtime/Core/Public/Containers/Ticker.h @@ -11,7 +11,8 @@ /** * Ticker delegates return true to automatically reschedule at the same delay or false for one-shot. * You will not get more than one fire per "frame", which is just a FTicker::Tick call. - * Argument is DeltaTime + * DeltaTime argument iz the time since the last game frame, *not* since the last tick the + * delegate received. */ DECLARE_DELEGATE_RetVal_OneParam(bool, FTickerDelegate, float); diff --git a/Engine/Source/Runtime/Core/Public/Containers/UnrealString.h b/Engine/Source/Runtime/Core/Public/Containers/UnrealString.h index 1d6b450326a6..bb9c9cb0ef16 100644 --- a/Engine/Source/Runtime/Core/Public/Containers/UnrealString.h +++ b/Engine/Source/Runtime/Core/Public/Containers/UnrealString.h @@ -1910,9 +1910,12 @@ namespace Lex { /** * Expected functions in this namespace are as follows: - * static bool TryParseString(T& OutValue, const TCHAR* Buffer); - * static void FromString(T& OutValue, const TCHAR* Buffer); - * static FString ToString(const T& OutValue); + * bool TryParseString(T& OutValue, const TCHAR* Buffer); + * void FromString(T& OutValue, const TCHAR* Buffer); + * ToString(T); + * ^-- Generally this means it can return either FString or const TCHAR* + * Generic code that uses ToString should assign to an FString or forward along to other functions + * that accept types that are also implicitly convertible to FString * * Implement custom functionality externally. */ @@ -1968,11 +1971,16 @@ namespace Lex return ToString(Value); } - /** Specialized for floats */ - template<> - inline FString ToSanitizedString(const float& Value) + /** Overloaded for floats */ + inline FString ToSanitizedString(float Value) { - return FString::SanitizeFloat( Value ); + return FString::SanitizeFloat(Value); + } + + /** Overloaded for doubles */ + inline FString ToSanitizedString(double Value) + { + return FString::SanitizeFloat(Value); } @@ -2197,4 +2205,14 @@ public: */ CORE_API int32 FindMatchingClosingParenthesis(const FString& TargetString, const int32 StartSearch = 0); +/** +* Given a display label string, generates an FString slug that only contains valid characters for an FName. +* For example, "[MyObject]: Object Label" becomes "MyObjectObjectLabel" FName slug. +* +* @param DisplayLabel The label string to convert to an FName +* +* @return The slugged string +*/ +CORE_API FString SlugStringForValidName(const FString& DisplayString); + #include "Misc/StringFormatArg.h" diff --git a/Engine/Source/Runtime/Core/Public/Core.h b/Engine/Source/Runtime/Core/Public/Core.h index 0659680d6d9e..939a9bb833dc 100644 --- a/Engine/Source/Runtime/Core/Public/Core.h +++ b/Engine/Source/Runtime/Core/Public/Core.h @@ -14,7 +14,6 @@ MONOLITHIC_HEADER_BOILERPLATE() #include "Misc/Timespan.h" #include "Misc/DateTime.h" #include "HAL/PlatformCrt.h" -#include "HAL/PlatformCodeAnalysis.h" #include "GenericPlatform/GenericPlatformMemory.h" #include "HAL/PlatformMemory.h" #include "Misc/Char.h" @@ -76,7 +75,6 @@ MONOLITHIC_HEADER_BOILERPLATE() #include "Templates/ChooseClass.h" #include "Templates/IntegralConstant.h" #include "Templates/IsClass.h" -#include "Templates/AlignOf.h" #include "Templates/TypeCompatibleBytes.h" #include "Traits/IsContiguousContainer.h" #include "Templates/IsTriviallyDestructible.h" diff --git a/Engine/Source/Runtime/Core/Public/CoreGlobals.h b/Engine/Source/Runtime/Core/Public/CoreGlobals.h index b4230f75ede4..07c8d000932d 100644 --- a/Engine/Source/Runtime/Core/Public/CoreGlobals.h +++ b/Engine/Source/Runtime/Core/Public/CoreGlobals.h @@ -89,9 +89,6 @@ extern CORE_API bool GCompilingBlueprint; /** True if we're reconstructing blueprint instances. Should never be true on cooked builds */ extern CORE_API bool GIsReconstructingBlueprintInstances; -/** Force blueprints to not compile on load */ -extern CORE_API bool GForceDisableBlueprintCompileOnLoad; - /** True if actors and objects are being re-instanced. */ extern CORE_API bool GIsReinstancing; @@ -371,9 +368,6 @@ extern CORE_API FName GLongCoreUObjectPackageName; /** Whether or not a unit test is currently being run. */ extern CORE_API bool GIsAutomationTesting; -/** Constrain bandwidth if wanted. Value is in MByte/ sec. */ -extern CORE_API float GAsyncIOBandwidthLimit; - /** Whether or not messages are being pumped outside of main loop */ extern CORE_API bool GPumpingMessagesOutsideOfMainLoop; @@ -433,7 +427,10 @@ extern CORE_API int32 GIsRenderingThreadSuspended; extern CORE_API bool IsInRHIThread(); /** Thread used for RHI */ -extern CORE_API FRunnableThread* GRHIThread; +extern CORE_API FRunnableThread* GRHIThread_InternalUseOnly; + +/** Thread ID of the the thread we are executing RHI commands on. This could either be a constant dedicated thread or changing every task if we run the rhi thread on tasks. */ +extern CORE_API uint32 GRHIThreadId; /** Array to help visualize weak pointers in the debugger */ class FFixedUObjectArray; diff --git a/Engine/Source/Runtime/Core/Public/CoreMinimal.h b/Engine/Source/Runtime/Core/Public/CoreMinimal.h index 5748362d9ab0..a4b2b9bf5fa5 100644 --- a/Engine/Source/Runtime/Core/Public/CoreMinimal.h +++ b/Engine/Source/Runtime/Core/Public/CoreMinimal.h @@ -44,7 +44,6 @@ #include "Templates/ChooseClass.h" #include "Templates/IntegralConstant.h" #include "Templates/IsClass.h" -#include "Templates/AlignOf.h" #include "Templates/TypeCompatibleBytes.h" #include "Traits/IsContiguousContainer.h" #include "Templates/UnrealTemplate.h" diff --git a/Engine/Source/Runtime/Core/Public/CoreSharedPCH.h b/Engine/Source/Runtime/Core/Public/CoreSharedPCH.h index 119cd1331c82..c030a89ed5be 100644 --- a/Engine/Source/Runtime/Core/Public/CoreSharedPCH.h +++ b/Engine/Source/Runtime/Core/Public/CoreSharedPCH.h @@ -34,7 +34,6 @@ #include "Templates/EnableIf.h" #include "Templates/RemoveReference.h" #include "Templates/TypeCompatibleBytes.h" -#include "Templates/AlignOf.h" #include "Templates/ChooseClass.h" #include "Templates/IntegralConstant.h" #include "Templates/IsClass.h" diff --git a/Engine/Source/Runtime/Core/Public/Delegates/DelegateBase.h b/Engine/Source/Runtime/Core/Public/Delegates/DelegateBase.h index b558b62897a3..901634ea9db2 100644 --- a/Engine/Source/Runtime/Core/Public/Delegates/DelegateBase.h +++ b/Engine/Source/Runtime/Core/Public/Delegates/DelegateBase.h @@ -47,6 +47,11 @@ public: { } + ~FDelegateBase() + { + Unbind(); + } + /** * Move constructor. */ diff --git a/Engine/Source/Runtime/Core/Public/Delegates/DelegateSignatureImpl.inl b/Engine/Source/Runtime/Core/Public/Delegates/DelegateSignatureImpl.inl index 33ddf6b0024a..13c0d8bbda94 100644 --- a/Engine/Source/Runtime/Core/Public/Delegates/DelegateSignatureImpl.inl +++ b/Engine/Source/Runtime/Core/Public/Delegates/DelegateSignatureImpl.inl @@ -883,7 +883,7 @@ protected: { if (&Other != this) { - Clear(); + Super::Clear(); for (const FDelegateBase& OtherDelegateRef : Other.GetInvocationList()) { @@ -891,7 +891,7 @@ protected: { FDelegate TempDelegate; ((TDelegateInstanceInterface*)OtherInstance)->CreateCopy(TempDelegate); - AddInternal(MoveTemp(TempDelegate)); + Super::AddInternal(MoveTemp(TempDelegate)); } } } @@ -910,7 +910,7 @@ protected: */ FDelegateHandle AddDelegateInstance(FDelegate&& InNewDelegate) { - return AddInternal(MoveTemp(InNewDelegate)); + return Super::AddInternal(MoveTemp(InNewDelegate)); } public: @@ -923,9 +923,9 @@ public: { bool NeedsCompaction = false; - LockInvocationList(); + Super::LockInvocationList(); { - const TInvocationList& LocalInvocationList = GetInvocationList(); + const TInvocationList& LocalInvocationList = Super::GetInvocationList(); // call bound functions in reverse order, so we ignore any instances that may be added by callees for (int32 InvocationListIndex = LocalInvocationList.Num() - 1; InvocationListIndex >= 0; --InvocationListIndex) @@ -940,7 +940,7 @@ public: } } } - UnlockInvocationList(); + Super::UnlockInvocationList(); if (NeedsCompaction) { @@ -959,7 +959,7 @@ protected: */ void RemoveDelegateInstance( FDelegateHandle Handle ) { - const TInvocationList& LocalInvocationList = GetInvocationList(); + const TInvocationList& LocalInvocationList = Super::GetInvocationList(); for (int32 InvocationListIndex = 0; InvocationListIndex < LocalInvocationList.Num(); ++InvocationListIndex) { @@ -976,7 +976,7 @@ protected: } } - CompactInvocationList(); + Super::CompactInvocationList(); } }; diff --git a/Engine/Source/Runtime/Core/Public/Delegates/MulticastDelegateBase.h b/Engine/Source/Runtime/Core/Public/Delegates/MulticastDelegateBase.h index 1fd4878f0292..4ff8e412479c 100644 --- a/Engine/Source/Runtime/Core/Public/Delegates/MulticastDelegateBase.h +++ b/Engine/Source/Runtime/Core/Public/Delegates/MulticastDelegateBase.h @@ -31,7 +31,7 @@ public: DelegateBaseRef.Unbind(); } - CompactInvocationList(); + CompactInvocationList(false); } /** @@ -78,18 +78,50 @@ public: */ void RemoveAll( const void* InUserObject ) { - for (int32 InvocationListIndex = InvocationList.Num() - 1; InvocationListIndex >= 0; --InvocationListIndex) + if (InvocationListLockCount > 0) { - FDelegateBase& DelegateBaseRef = InvocationList[InvocationListIndex]; - - IDelegateInstance* DelegateInstance = DelegateBaseRef.GetDelegateInstanceProtected(); - if ((DelegateInstance != nullptr) && DelegateInstance->HasSameObject(InUserObject)) + bool NeedsCompacted = false; + for (FDelegateBase& DelegateBaseRef : InvocationList) { - DelegateBaseRef.Unbind(); + IDelegateInstance* DelegateInstance = DelegateBaseRef.GetDelegateInstanceProtected(); + if ((DelegateInstance != nullptr) && DelegateInstance->HasSameObject(InUserObject)) + { + // Manually unbind the delegate here so the compaction will find and remove it. + DelegateBaseRef.Unbind(); + NeedsCompacted = true; + } + } + + // can't compact at the moment, but set out threshold to zero so the next add will do it + if (NeedsCompacted) + { + CompactionThreshold = 0; } } + else + { + // compact us while shuffling in later delegates to fill holes + for (int32 InvocationListIndex = 0; InvocationListIndex < InvocationList.Num();) + { + FDelegateBase& DelegateBaseRef = InvocationList[InvocationListIndex]; - CompactInvocationList(); + IDelegateInstance* DelegateInstance = DelegateBaseRef.GetDelegateInstanceProtected(); + if (DelegateInstance == nullptr + || DelegateInstance->HasSameObject(InUserObject) + || DelegateInstance->IsCompactable()) + { + InvocationList.RemoveAtSwap(InvocationListIndex, 1, false); + } + else + { + InvocationListIndex++; + } + } + + CompactionThreshold = FMath::Max(2, 2 * InvocationList.Num()); + + InvocationList.Shrink(); + } } protected: @@ -109,6 +141,8 @@ protected: */ inline FDelegateHandle AddInternal(FDelegateBase&& NewDelegateBaseRef) { + // compact but obey threshold of when this will trigger + CompactInvocationList(true); FDelegateHandle Result = NewDelegateBaseRef.GetHandle(); InvocationList.Add(MoveTemp(NewDelegateBaseRef)); return Result; @@ -119,26 +153,46 @@ protected: * * @see RequestCompaction */ - void CompactInvocationList( ) + void CompactInvocationList(bool CheckThreshold=false) { - if ((InvocationList.Num() < CompactionThreshold) || (InvocationListLockCount != 0)) + // if locked and no object, just return + if (InvocationListLockCount > 0) { return; } - for (int32 InvocationListIndex = InvocationList.Num() - 1; InvocationListIndex >= 0; --InvocationListIndex) + // if checking threshold, obey but decay. This is to ensure that even infrequently called delegates will + // eventually compact during an Add() + if (CheckThreshold && --CompactionThreshold > InvocationList.Num()) + { + return; + } + + int32 OldNumItems = InvocationList.Num(); + + // Find anything null or compactable and remove it + for (int32 InvocationListIndex = 0; InvocationListIndex < InvocationList.Num();) { FDelegateBase& DelegateBaseRef = InvocationList[InvocationListIndex]; IDelegateInstance* DelegateInstance = DelegateBaseRef.GetDelegateInstanceProtected(); - - if ((DelegateInstance == nullptr) || DelegateInstance->IsCompactable()) + if (DelegateInstance == nullptr || DelegateInstance->IsCompactable()) { InvocationList.RemoveAtSwap(InvocationListIndex); } + else + { + InvocationListIndex++; + } } CompactionThreshold = FMath::Max(2, 2 * InvocationList.Num()); + + if (OldNumItems > CompactionThreshold) + { + // would be nice to shrink down to threshold, but reserve only grows..? + InvocationList.Shrink(); + } } /** diff --git a/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericApplication.h b/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericApplication.h index 45b613e20d3f..d9830daae2df 100644 --- a/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericApplication.h +++ b/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericApplication.h @@ -465,7 +465,7 @@ public: return OutRect; } - virtual bool TryCalculatePopupWindowPosition( const FPlatformRect& InAnchor, const FVector2D& InSize, const EPopUpOrientation::Type Orientation, /*OUT*/ FVector2D* const CalculatedPopUpPosition ) const { return false; } + virtual bool TryCalculatePopupWindowPosition( const FPlatformRect& InAnchor, const FVector2D& InSize, const FVector2D& ProposedPlacement, const EPopUpOrientation::Type Orientation, /*OUT*/ FVector2D* const CalculatedPopUpPosition ) const { return false; } DECLARE_EVENT_OneParam(GenericApplication, FOnDisplayMetricsChanged, const FDisplayMetrics&); diff --git a/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericApplicationMessageHandler.h b/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericApplicationMessageHandler.h index 09d8177b4ca8..f7ddc403c755 100644 --- a/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericApplicationMessageHandler.h +++ b/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericApplicationMessageHandler.h @@ -202,6 +202,7 @@ namespace EGestureEvent Magnify, Swipe, Rotate, + LongPress, Count }; } @@ -355,6 +356,11 @@ public: return false; } + virtual void ShouldSimulateGesture(EGestureEvent::Type Gesture, bool bEnable) + { + + } + virtual bool OnMotionDetected( const FVector& Tilt, const FVector& RotationRate, const FVector& Gravity, const FVector& Acceleration, int32 ControllerId ) { return false; diff --git a/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformAtomics.h b/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformAtomics.h index 1d4789daeb14..8f66896948ac 100644 --- a/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformAtomics.h +++ b/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformAtomics.h @@ -159,16 +159,23 @@ struct FGenericPlatformAtomics #error must implement } -#if PLATFORM_64BITS // This function is not possible on 32-bit architectures /** * Atomically compares the value to comparand and replaces with the exchange * value if they are equal and returns the original value + * REQUIRED, even on 32 bit architectures. */ static FORCEINLINE int64 InterlockedCompareExchange (volatile int64* Dest, int64 Exchange, int64 Comparand) { #error must implement } -#endif + + /** + * Atomic read of 64 bit value with an implicit memory barrier. + */ + static FORCEINLINE int64 AtomicRead64(volatile const int64* Src) + { + return InterlockedCompareExchange((volatile int64*)Src, 0, 0); + } /** * Atomically compares the pointer to comparand and replaces with the exchange @@ -196,6 +203,18 @@ struct FGenericPlatformAtomics { #error Must implement } + + /** + * Atomic read of 128 bit value with a memory barrier + */ + static FORCEINLINE void AtomicRead128(const volatile FInt128* Src, FInt128* OutResult) + { + FInt128 Zero; + Zero.High = 0; + Zero.Low = 0; + *OutResult = Zero; + InterlockedCompareExchange128((volatile FInt128*)Src, Zero, OutResult); + } #endif // PLATFORM_HAS_128BIT_ATOMICS #endif // 0 @@ -223,3 +242,4 @@ protected: return !(PTRINT(Ptr) & (Alignment - 1)); } }; + diff --git a/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformCrashContext.h b/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformCrashContext.h index 168c3f1ee1c4..6f7e71d3f0df 100644 --- a/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformCrashContext.h +++ b/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformCrashContext.h @@ -118,6 +118,8 @@ public: /** Default constructor. */ FGenericCrashContext(); + virtual ~FGenericCrashContext() { } + /** Serializes all data to the buffer. */ void SerializeContentToBuffer(); diff --git a/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformCriticalSection.h b/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformCriticalSection.h index 188319e5fc75..df129981972c 100644 --- a/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformCriticalSection.h +++ b/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformCriticalSection.h @@ -29,3 +29,44 @@ private: FSystemWideCriticalSectionNotImplemented(const FSystemWideCriticalSectionNotImplemented&); FSystemWideCriticalSectionNotImplemented& operator=(const FSystemWideCriticalSectionNotImplemented&); }; + +/** + * TGenericPlatformRWLock - Read/Write Mutex + * - Provides non-recursive Read/Write (or shared-exclusive) access. + * - As a fallback default for non implemented platforms, using a single FCriticalSection to provide complete single mutual exclusion - no seperate Read/Write access. + */ +template +class TGenericPlatformRWLock +{ +public: + FORCEINLINE TGenericPlatformRWLock() + { + } + + FORCEINLINE ~TGenericPlatformRWLock() + { + } + + FORCEINLINE void ReadLock() + { + Mutex.Lock(); + } + + FORCEINLINE void WriteLock() + { + Mutex.Lock(); + } + + FORCEINLINE void ReadUnlock() + { + Mutex.Unlock(); + } + + FORCEINLINE void WriteUnlock() + { + Mutex.Unlock(); + } + +private: + CriticalSection Mutex; +}; diff --git a/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformFile.h b/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformFile.h index cd1f372be16a..3ed2ab3431e2 100644 --- a/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformFile.h +++ b/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformFile.h @@ -95,6 +95,11 @@ public: **/ virtual bool Write(const uint8* Source, int64 BytesToWrite) = 0; + /** + * Flushes file. + **/ + virtual void Flush() { }; + public: /////////// Utility Functions. These have a default implementation that uses the pure virtual operations. @@ -231,6 +236,8 @@ public: } } + /** Platform file can override this to get a regular tick from the engine */ + virtual void Tick() { } /** Gets the platform file wrapped by this file. */ virtual IPlatformFile* GetLowerLevel() = 0; /** Sets the platform file wrapped by this file. */ @@ -290,6 +297,8 @@ public: class FDirectoryVisitor { public: + virtual ~FDirectoryVisitor() { } + /** * Callback for a single file or a directory in a directory iteration. * @param FilenameOrDirectory If bIsDirectory is true, this is a directory (with no trailing path delimiter), otherwise it is a file name. @@ -303,6 +312,7 @@ public: class FDirectoryStatVisitor { public: + virtual ~FDirectoryStatVisitor() { } /** * Callback for a single file or a directory in a directory iteration. * @param FilenameOrDirectory If bIsDirectory is true, this is a directory (with no trailing path delimiter), otherwise it is a file name. @@ -415,6 +425,8 @@ public: class IFileServerMessageHandler { public: + virtual ~IFileServerMessageHandler() { } + /** Subclass fills out an archive to send to the server */ virtual void FillPayload(FArchive& Payload) = 0; diff --git a/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformMemory.h b/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformMemory.h index 3f430aa1dcd0..e4ff44b2f581 100644 --- a/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformMemory.h +++ b/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformMemory.h @@ -451,6 +451,17 @@ public: */ static bool UnmapNamedSharedMemoryRegion(FSharedMemoryRegion * MemoryRegion); + /** + * Gets whether this platform supports Fast VRAM memory + * Ie, whether TexCreate_FastVRAM flags actually mean something or not + * + * @return bool true if supported, false if not + */ + static FORCEINLINE bool SupportsFastVRAMMemory() + { + return false; + } + protected: friend struct FGenericStatsUpdater; diff --git a/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformMisc.h b/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformMisc.h index 677cdb920c74..b411ae37d49a 100644 --- a/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformMisc.h +++ b/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformMisc.h @@ -186,6 +186,16 @@ struct CORE_API FSHA256Signature FString ToString() const; }; +/** + * The accuracy when dealing with physical characteristics of the monitor/screen of the device we're running on. + */ +enum class EScreenPhysicalAccuracy +{ + Unknown, + Approximation, + Truth +}; + /** * Generic implementation for most platforms **/ @@ -196,7 +206,12 @@ struct CORE_API FGenericPlatformMisc */ static void PlatformPreInit(); static void PlatformInit() { } - static void PlatformPostInit(bool ShowSplashScreen = false) { } + static void PlatformPostInit() { } + + /** + * Called to dismiss splash screen + */ + static void PlatformHandleSplashScreen(bool ShowSplashScreen = false) { } /** * Called during AppExit(). Log, Config still exist at this point, but not much else does. @@ -290,6 +305,13 @@ struct CORE_API FGenericPlatformMisc */ static FString GetDeviceId(); + /** + * Returns a unique string for advertising identification + * + * @return the unique string generated by this platform for this device + */ + static FString GetUniqueAdvertisingId(); + // #CrashReport: 2015-02-24 Remove /** Submits a crash report to a central server (release builds only) */ static void SubmitErrorReport( const TCHAR* InErrorHist, EErrorReportMode::Type InMode ); @@ -348,6 +370,11 @@ struct CORE_API FGenericPlatformMisc */ static FString GetPrimaryGPUBrand(); + /** + * @return "DeviceMake|DeviceModel" if possible, and "CPUVendor|CPUBrand" otherwise + */ + static FString GetDeviceMakeAndModel(); + static struct FGPUDriverInfo GetGPUDriverInfo(const FString& DeviceDescription); /** @@ -355,6 +382,13 @@ struct CORE_API FGenericPlatformMisc */ static void GetOSVersions( FString& out_OSVersionLabel, FString& out_OSSubVersionLabel ); + /** + * Gets a string representing the numeric OS version (as opposed to a translated OS version that GetOSVersions returns). + * The returned string should try to be brief and avoid newlines and symbols, but there's technically no restriction on the string it can return. + * If the implementation does not support this, it should return an empty string. + */ + static FString GetOSVersion(); + /** Retrieves information about the total number of bytes and number of free bytes for the specified disk path. */ static bool GetDiskTotalAndFreeSpace( const FString& InPath, uint64& TotalNumberOfBytes, uint64& NumberOfFreeBytes ); @@ -898,6 +932,16 @@ public: * @return the default profile name. */ static const TCHAR* GetDefaultDeviceProfileName(); + + /** + * Gets the current battery level. + * + * @return the battery level between 0 and 100. + */ + FORCEINLINE static int GetBatteryLevel() + { + return -1; + } /** * Allows a game/program/etc to control the game directory in a special place (for instance, monolithic programs that don't have .uprojects) @@ -1068,7 +1112,34 @@ public: static void RegisterForRemoteNotifications(); /** - * Execute plaform dependent pre load map actions + * Requests unregistering from receiving remote notifications on the user's device. + */ + static void UnregisterForRemoteNotifications(); + + /** + * Gets the physical size of the screen if possible. Some platforms lie, some platforms don't know. + */ + static EScreenPhysicalAccuracy GetPhysicalScreenDensity(int32& OutScreenDensity); + + /** + * Gets the physical size of the screen if possible. Some platforms lie, some platforms don't know. + */ + static EScreenPhysicalAccuracy ComputePhysicalScreenDensity(int32& OutScreenDensity); + + /** + * If we know or can approximate the pixel density of the screen we will convert the incoming inches + * to pixels on the device. If the accuracy is unknown OutPixels will be set to 0. + */ + static EScreenPhysicalAccuracy ConvertInchesToPixels(float Inches, float& OutPixels); + + /** + * If we know or can approximate the pixel density of the screen we will convert the incoming pixels + * to inches on the device. If the accuracy is unknown OutInches will be set to 0. + */ + static EScreenPhysicalAccuracy ConvertPixelsToInches(float Pixels, float& OutInches); + + /** + * Execute platform dependent pre load map actions */ static const void PreLoadMap(FString&, FString&, void*) {} @@ -1107,6 +1178,11 @@ public: return true; } +protected: + static bool CachedPhysicalScreenData; + static EScreenPhysicalAccuracy CachedPhysicalScreenAccuracy; + static int32 CachedPhysicalScreenDensity; + #if !UE_BUILD_SHIPPING protected: /** Whether the user should be prompted to allow for a remote debugger to be attached */ diff --git a/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformProcess.h b/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformProcess.h index 33e3b47adfdd..9d9dea1e274a 100644 --- a/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformProcess.h +++ b/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformProcess.h @@ -210,6 +210,9 @@ struct CORE_API FGenericPlatformProcess /** Allow the platform to do anything it needs for audio thread */ static void SetupAudioThread() { } + /** Content saved to the game or engine directories should be rerouted to user directories instead **/ + static bool ShouldSaveToUserDir(); + /** Get startup directory. NOTE: Only one return value is valid at a time! **/ static const TCHAR* BaseDir(); @@ -574,6 +577,19 @@ struct CORE_API FGenericPlatformProcess * Checks if we're the first instance. An instance can become first if the previous first instance quits before it. */ static bool IsFirstInstance(); + + /** + * Returns the list of all shader dirs that were added with AddShaderDir + */ + static const TArray& AllShaderDirs(); + + /** + * Add a shader to the list of shader dirs + */ + static void AddShaderDir(const FString& InShaderDir); + + private: + static TArray ShaderDirs; }; diff --git a/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformProperties.h b/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformProperties.h index c14d9879b8f3..6885d7f13611 100644 --- a/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformProperties.h +++ b/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformProperties.h @@ -232,17 +232,6 @@ struct FGenericPlatformProperties return true; } - /** - * Gets whether this platform supports Fast VRAM memory - * Ie, whether TexCreate_FastVRAM flags actually mean something or not - * - * @return bool true if supported, false if not - */ - static FORCEINLINE bool SupportsFastVRAMMemory() - { - return false; - } - static FORCEINLINE bool SupportsMinimize() { return false; diff --git a/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformSurvey.h b/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformSurvey.h index 7ac971f9625a..a78174552cbc 100644 --- a/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformSurvey.h +++ b/Engine/Source/Runtime/Core/Public/GenericPlatform/GenericPlatformSurvey.h @@ -2,9 +2,11 @@ #pragma once -#include "CoreTypes.h" +#include "CoreMinimal.h" #include "Containers/ContainersFwd.h" +CORE_API DECLARE_LOG_CATEGORY_EXTERN(LogSynthBenchmark, Log, All); + // time and amount of work that was measured struct FTimeSample { diff --git a/Engine/Source/Runtime/Core/Public/HAL/Allocators/CachedOSPageAllocator.h b/Engine/Source/Runtime/Core/Public/HAL/Allocators/CachedOSPageAllocator.h index c50580c8c434..c4a8a578552d 100644 --- a/Engine/Source/Runtime/Core/Public/HAL/Allocators/CachedOSPageAllocator.h +++ b/Engine/Source/Runtime/Core/Public/HAL/Allocators/CachedOSPageAllocator.h @@ -47,6 +47,11 @@ struct TCachedOSPageAllocator : private FCachedOSPageAllocator return FreeAllImpl(FreedPageBlocks, FreedPageBlocksNum, CachedTotal); } + uint32 GetCachedFreeTotal() + { + return CachedTotal; + } + private: FFreePageBlock FreedPageBlocks[NumCacheBlocks]; uint32 FreedPageBlocksNum; diff --git a/Engine/Source/Runtime/Core/Public/HAL/IConsoleManager.h b/Engine/Source/Runtime/Core/Public/HAL/IConsoleManager.h index ef456ad93f72..6ea82928320d 100644 --- a/Engine/Source/Runtime/Core/Public/HAL/IConsoleManager.h +++ b/Engine/Source/Runtime/Core/Public/HAL/IConsoleManager.h @@ -197,16 +197,19 @@ public: virtual class TConsoleVariableData* AsVariableInt() { + ensureMsgf(false, TEXT("Attempted to access variable data of a console variable type that doesn't support it. For example FindTConsoleVariableData* on a FAutoConsoleVariableRef.")); return 0; } virtual class TConsoleVariableData* AsVariableFloat() { + ensureMsgf(false, TEXT("Attempted to access variable data of a console variable type that doesn't support it. For example FindTConsoleVariableData* on a FAutoConsoleVariableRef.")); return 0; } virtual class TConsoleVariableData* AsVariableString() { + ensureMsgf(false, TEXT("Attempted to access variable data of a console variable type that doesn't support it. For example FindTConsoleVariableData* on a FAutoConsoleVariableRef.")); return 0; } @@ -620,6 +623,9 @@ struct CORE_API IConsoleManager return *Singleton; } +protected: + virtual ~IConsoleManager() { } + private: /** Singleton for the console manager **/ static IConsoleManager* Singleton; diff --git a/Engine/Source/Runtime/Core/Public/HAL/IPlatformFileProfilerWrapper.h b/Engine/Source/Runtime/Core/Public/HAL/IPlatformFileProfilerWrapper.h index 0186d1a6881d..34b7239eb688 100644 --- a/Engine/Source/Runtime/Core/Public/HAL/IPlatformFileProfilerWrapper.h +++ b/Engine/Source/Runtime/Core/Public/HAL/IPlatformFileProfilerWrapper.h @@ -585,6 +585,7 @@ public: } virtual bool Initialize(IPlatformFile* Inner, const TCHAR* CommandLineParam) override; + using IPlatformFile::Tick; bool Tick(float Delta); virtual IPlatformFile* GetLowerLevel() override { diff --git a/Engine/Source/Runtime/Core/Public/HAL/MallocBinned.h b/Engine/Source/Runtime/Core/Public/HAL/MallocBinned.h index ab316450d5df..7ff57052531b 100644 --- a/Engine/Source/Runtime/Core/Public/HAL/MallocBinned.h +++ b/Engine/Source/Runtime/Core/Public/HAL/MallocBinned.h @@ -13,7 +13,9 @@ //#define USE_LOCKFREE_DELETE #define USE_INTERNAL_LOCKS +#if USE_CACHE_FREED_OS_ALLOCS #define CACHE_FREED_OS_ALLOCS +#endif #ifdef USE_INTERNAL_LOCKS //# define USE_COARSE_GRAIN_LOCKS diff --git a/Engine/Source/Runtime/Core/Public/HAL/MallocBinned2.h b/Engine/Source/Runtime/Core/Public/HAL/MallocBinned2.h index a882d65fba4e..1bdfa89a6c60 100644 --- a/Engine/Source/Runtime/Core/Public/HAL/MallocBinned2.h +++ b/Engine/Source/Runtime/Core/Public/HAL/MallocBinned2.h @@ -50,6 +50,21 @@ #endif +#define BINNED2_ALLOCATOR_STATS 1 + + +#if BINNED2_ALLOCATOR_STATS +extern int64 AllocatedSmallPoolMemory; // memory that's requested to be allocated by the game + + +////////////////////////////////////////////////////////////////////////// +// the following don't need a critical section because they are covered by the critical section called Mutex +extern int64 AllocatedOSSmallPoolMemory; +extern int64 AllocatedLargePoolMemory; // memory requests to the OS which don't fit in the small pool +extern int64 AllocatedLargePoolMemoryWAlignment; // when we allocate at OS level we need to align to a size +#endif + + // // Optimized virtual memory allocator. @@ -495,6 +510,10 @@ public: void FreeExternal(void *Ptr); bool GetAllocationSizeExternal(void* Ptr, SIZE_T& SizeOut); + virtual void GetAllocatorStats( FGenericMemoryStats& out_Stats ) override; + /** Dumps current allocator stats to the log. */ + virtual void DumpAllocatorStats(class FOutputDevice& Ar) override; + static uint16 SmallBlockSizesReversed[BINNED2_SMALL_POOL_COUNT]; // this is reversed to get the smallest elements on our main cache line static FMallocBinned2* MallocBinned2; static uint32 Binned2TlsSlot; diff --git a/Engine/Source/Runtime/Core/Public/HAL/PThreadCriticalSection.h b/Engine/Source/Runtime/Core/Public/HAL/PThreadCriticalSection.h index 02567c013fc8..3a79da911ac2 100644 --- a/Engine/Source/Runtime/Core/Public/HAL/PThreadCriticalSection.h +++ b/Engine/Source/Runtime/Core/Public/HAL/PThreadCriticalSection.h @@ -46,7 +46,17 @@ public: */ FORCEINLINE void Lock(void) { - pthread_mutex_lock(&Mutex); + pthread_mutex_lock(&Mutex); + } + + /** + * Attempt to take a lock and returns whether or not a lock was taken. + * + * @return true if a lock was taken, false otherwise. + */ + FORCEINLINE bool TryLock() + { + return 0 == pthread_mutex_trylock(&Mutex); } /** diff --git a/Engine/Source/Runtime/Core/Public/HAL/PThreadRWLock.h b/Engine/Source/Runtime/Core/Public/HAL/PThreadRWLock.h new file mode 100644 index 000000000000..19d89b7dc0ca --- /dev/null +++ b/Engine/Source/Runtime/Core/Public/HAL/PThreadRWLock.h @@ -0,0 +1,55 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreTypes.h" +#include "Misc/AssertionMacros.h" +#include +#include + +/** + * FPThreadsRWLock - Read/Write Mutex + * - Provides non-recursive Read/Write (or shared-exclusive) access. + */ +class FPThreadsRWLock +{ +public: + FPThreadsRWLock() + { + int Err = pthread_rwlock_init(&Mutex, nullptr); + checkf(Err == 0, TEXT("pthread_rwlock_init failed with error: %d"), Err); + } + + ~FPThreadsRWLock() + { + int Err = pthread_rwlock_destroy(&Mutex); + checkf(Err == 0, TEXT("pthread_rwlock_destroy failed with error: %d"), Err); + } + + void ReadLock() + { + int Err = pthread_rwlock_rdlock(&Mutex); + checkf(Err == 0, TEXT("pthread_rwlock_rdlock failed with error: %d"), Err); + } + + void WriteLock() + { + int Err = pthread_rwlock_wrlock(&Mutex); + checkf(Err == 0, TEXT("pthread_rwlock_wrlock failed with error: %d"), Err); + } + + void ReadUnlock() + { + int Err = pthread_rwlock_unlock(&Mutex); + checkf(Err == 0, TEXT("pthread_rwlock_unlock failed with error: %d"), Err); + } + + void WriteUnlock() + { + int Err = pthread_rwlock_unlock(&Mutex); + checkf(Err == 0, TEXT("pthread_rwlock_unlock failed with error: %d"), Err); + } + +private: + pthread_rwlock_t Mutex; +}; diff --git a/Engine/Source/Runtime/Core/Public/HAL/Platform.h b/Engine/Source/Runtime/Core/Public/HAL/Platform.h index 5ad53d62eca5..857df548e79d 100644 --- a/Engine/Source/Runtime/Core/Public/HAL/Platform.h +++ b/Engine/Source/Runtime/Core/Public/HAL/Platform.h @@ -75,7 +75,7 @@ #elif PLATFORM_MAC #include "Mac/MacPlatformCompilerPreSetup.h" #elif PLATFORM_IOS - #include "IOS/IOSPlatformCompilerPreSetup.h" + #include "iOS/IOSPlatformCompilerPreSetup.h" #elif PLATFORM_ANDROID #include "Android/AndroidPlatformCompilerPreSetup.h" #elif PLATFORM_HTML5 @@ -124,6 +124,14 @@ #error Unknown Compiler #endif +//------------------------------------------------------------------ +// Setup macros for static code analysis +//------------------------------------------------------------------ + +#if PLATFORM_WINDOWS + #include "Windows/WindowsPlatformCodeAnalysis.h" +#endif + //------------------------------------------------------------------ // Finalize define setup //------------------------------------------------------------------ @@ -341,7 +349,7 @@ #endif #ifndef PLATFORM_USES_ANSI_STRING_FOR_EXTERNAL_PROFILING - #define PLATFORM_USES_ANSI_STRING_FOR_EXTERNAL_PROFILING 1 + #define PLATFORM_USES_ANSI_STRING_FOR_EXTERNAL_PROFILING 1 #endif #ifndef PLATFORM_RHITHREAD_DEFAULT_BYPASS @@ -364,6 +372,26 @@ #define PLATFORM_SUPPORTS_EARLY_MOVIE_PLAYBACK 0 #endif +#ifndef PLATFORM_VECTOR_CUBIC_INTERP_SSE + #define PLATFORM_VECTOR_CUBIC_INTERP_SSE 0 +#endif + +#ifndef PLATFORM_UI_HAS_MOBILE_SCROLLBARS + #define PLATFORM_UI_HAS_MOBILE_SCROLLBARS 0 +#endif + +#ifndef PLATFORM_UI_NEEDS_TOOLTIPS + #define PLATFORM_UI_NEEDS_TOOLTIPS 1 +#endif + +#ifndef PLATFORM_UI_NEEDS_FOCUS_OUTLINES + #define PLATFORM_UI_NEEDS_FOCUS_OUTLINES 1 +#endif + +#ifndef PLATFORM_LIMIT_MOBILE_BONE_MATRICES + #define PLATFORM_LIMIT_MOBILE_BONE_MATRICES 0 +#endif + // deprecated, do not use #define PLATFORM_HAS_THREADSAFE_RHIGetRenderQueryResult # #define PLATFORM_SUPPORTS_RHI_THREAD # @@ -478,18 +506,6 @@ #define TYPENAME_OUTSIDE_TEMPLATE typename #endif -// Legacy method modifier macros. You shouldn't use these macros in modern code. Use the built-in keyword directly. -#ifndef OVERRIDE - #define OVERRIDE \ - EMIT_DEPRECATED_WARNING_MESSAGE("OVERRIDE macro is deprecated. Please use override keyword instead.") \ - override -#endif -#ifndef FINAL - #define FINAL \ - EMIT_DEPRECATED_WARNING_MESSAGE("FINAL macro is deprecated. Please use final keyword instead.") \ - final -#endif - // Method modifiers #ifndef ABSTRACT #define ABSTRACT @@ -589,7 +605,9 @@ // This is a temporary macro, will be removed when TSubobjectPtr can be safely removed #ifndef private_subobject -#define private_subobject public +#define private_subobject \ +DEPRECATED_MACRO(4.17, "private_subobject macro is deprecated. Please use the standard 'private' keyword instead.") \ +private #endif // Console ANSICHAR/TCHAR command line handling diff --git a/Engine/Source/Runtime/Core/Public/HAL/PlatformCodeAnalysis.h b/Engine/Source/Runtime/Core/Public/HAL/PlatformCodeAnalysis.h deleted file mode 100644 index 604bfdd8fa86..000000000000 --- a/Engine/Source/Runtime/Core/Public/HAL/PlatformCodeAnalysis.h +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#pragma once - -#include "CoreTypes.h" - -#if PLATFORM_WINDOWS -#include "Windows/WindowsPlatformCodeAnalysis.h" -#endif diff --git a/Engine/Source/Runtime/Core/Public/HAL/PlatformFilemanager.h b/Engine/Source/Runtime/Core/Public/HAL/PlatformFilemanager.h index 3978a6389bec..de64718ab1c3 100644 --- a/Engine/Source/Runtime/Core/Public/HAL/PlatformFilemanager.h +++ b/Engine/Source/Runtime/Core/Public/HAL/PlatformFilemanager.h @@ -48,6 +48,11 @@ public: */ IPlatformFile* GetPlatformFile( const TCHAR* Name ); + /** + * calls Tick on the platform files in the TopmostPlatformFile chain + */ + void TickActivePlatformFile(); + /** * Permorms additional initialization when the new async IO is enabled. */ diff --git a/Engine/Source/Runtime/Core/Public/HAL/PlatformIncludes.h b/Engine/Source/Runtime/Core/Public/HAL/PlatformIncludes.h index 958f11aba624..9b58fb276fa1 100644 --- a/Engine/Source/Runtime/Core/Public/HAL/PlatformIncludes.h +++ b/Engine/Source/Runtime/Core/Public/HAL/PlatformIncludes.h @@ -7,7 +7,6 @@ MONOLITHIC_HEADER_BOILERPLATE() // All the different platform-specific includes #include "HAL/PlatformCrt.h" -#include "HAL/PlatformCodeAnalysis.h" #include "HAL/PlatformMemory.h" #include "HAL/PlatformString.h" #include "HAL/PlatformMisc.h" diff --git a/Engine/Source/Runtime/Core/Public/HAL/PlatformMemory.h b/Engine/Source/Runtime/Core/Public/HAL/PlatformMemory.h index 361a9731aafc..73cb6f94e54d 100644 --- a/Engine/Source/Runtime/Core/Public/HAL/PlatformMemory.h +++ b/Engine/Source/Runtime/Core/Public/HAL/PlatformMemory.h @@ -7,7 +7,13 @@ #if PLATFORM_WINDOWS #include "Windows/WindowsPlatformMemory.h" #elif PLATFORM_PS4 + +#if USE_NEW_PS4_MEMORY_SYSTEM +#include "PS4/PS4Memory2.h" +#else #include "PS4/PS4Memory.h" +#endif + #elif PLATFORM_XBOXONE #include "XboxOne/XboxOneMemory.h" #elif PLATFORM_MAC diff --git a/Engine/Source/Runtime/Core/Public/HAL/ThreadSingleton.h b/Engine/Source/Runtime/Core/Public/HAL/ThreadSingleton.h index 94cc5214d178..fe3778c6674a 100644 --- a/Engine/Source/Runtime/Core/Public/HAL/ThreadSingleton.h +++ b/Engine/Source/Runtime/Core/Public/HAL/ThreadSingleton.h @@ -68,5 +68,3 @@ public: } }; -#define DECLARE_THREAD_SINGLETON(ClassType) \ - EMIT_DEPRECATED_WARNING_MESSAGE("DECLARE_THREAD_SINGLETON is deprecated in 4.8. It's no longer needed and can be removed.") diff --git a/Engine/Source/Runtime/Core/Public/HTML5/HTML5CriticalSection.h b/Engine/Source/Runtime/Core/Public/HTML5/HTML5CriticalSection.h index 0092dbed09d1..7f6a7e95fffd 100644 --- a/Engine/Source/Runtime/Core/Public/HTML5/HTML5CriticalSection.h +++ b/Engine/Source/Runtime/Core/Public/HTML5/HTML5CriticalSection.h @@ -19,6 +19,16 @@ public: FORCEINLINE void Lock(void) { } + + /** + * Attempt to take a lock and returns whether or not a lock was taken. + * + * @return true if a lock was taken, false otherwise. + */ + FORCEINLINE bool TryLock() + { + return false; + } /** * Releases the lock on the critical seciton @@ -34,3 +44,4 @@ private: typedef FHTML5CriticalSection FCriticalSection; typedef FSystemWideCriticalSectionNotImplemented FSystemWideCriticalSection; +typedef TGenericPlatformRWLock FRWLock; diff --git a/Engine/Source/Runtime/Core/Public/HTML5/HTML5PlatformAtomics.h b/Engine/Source/Runtime/Core/Public/HTML5/HTML5PlatformAtomics.h index 8baf1812761e..238c2a1e4622 100644 --- a/Engine/Source/Runtime/Core/Public/HTML5/HTML5PlatformAtomics.h +++ b/Engine/Source/Runtime/Core/Public/HTML5/HTML5PlatformAtomics.h @@ -83,7 +83,6 @@ struct CORE_API FHTML5PlatformAtomics : public FGenericPlatformAtomics return Result; } -#if PLATFORM_64BITS static FORCEINLINE int64 InterlockedCompareExchange( volatile int64* Dest, int64 Exchange, int64 Comperand ) { int64 Result = *Dest; @@ -93,7 +92,11 @@ struct CORE_API FHTML5PlatformAtomics : public FGenericPlatformAtomics } return Result; } -#endif + + static FORCEINLINE int64 AtomicRead64(volatile const int64* Src) + { + return *Src; + } static FORCEINLINE void* InterlockedCompareExchangePointer( void** Dest, void* Exchange, void* Comperand ) { diff --git a/Engine/Source/Runtime/Core/Public/HTML5/HTML5PlatformCompilerPreSetup.h b/Engine/Source/Runtime/Core/Public/HTML5/HTML5PlatformCompilerPreSetup.h index 368c4ba979a4..2ee0c1076d25 100644 --- a/Engine/Source/Runtime/Core/Public/HTML5/HTML5PlatformCompilerPreSetup.h +++ b/Engine/Source/Runtime/Core/Public/HTML5/HTML5PlatformCompilerPreSetup.h @@ -106,15 +106,28 @@ _Pragma("clang diagnostic pop") #endif // PRAGMA_POP +#ifndef PRAGMA_DISABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS + #define PRAGMA_DISABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wdelete-non-virtual-dtor\"") +#endif // PRAGMA_DISABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS + +#ifndef PRAGMA_ENABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS + #define PRAGMA_ENABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS \ + _Pragma("clang diagnostic pop") +#endif // PRAGMA_ENABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS + // Disable common CA warnings around SDK includes #ifndef THIRD_PARTY_INCLUDES_START #define THIRD_PARTY_INCLUDES_START \ PRAGMA_DISABLE_SHADOW_VARIABLE_WARNINGS \ - PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS + PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS \ + PRAGMA_DISABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS #endif #ifndef THIRD_PARTY_INCLUDES_END #define THIRD_PARTY_INCLUDES_END \ + PRAGMA_ENABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS \ PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS \ PRAGMA_ENABLE_SHADOW_VARIABLE_WARNINGS #endif diff --git a/Engine/Source/Runtime/Core/Public/HTML5/HTML5PlatformMisc.h b/Engine/Source/Runtime/Core/Public/HTML5/HTML5PlatformMisc.h index 456b41f033e9..5cb3a55e3908 100644 --- a/Engine/Source/Runtime/Core/Public/HTML5/HTML5PlatformMisc.h +++ b/Engine/Source/Runtime/Core/Public/HTML5/HTML5PlatformMisc.h @@ -18,7 +18,7 @@ struct CORE_API FHTML5Misc : public FGenericPlatformMisc { static void PlatformInit(); - static void PlatformPostInit(bool ShowSplashScreen = false); + static void PlatformPostInit(); static class GenericApplication* CreateApplication(); static uint32 GetKeyMap(uint32* KeyCodes, FString* KeyNames, uint32 MaxMappings); static uint32 GetCharKeyMap(uint32* KeyCodes, FString* KeyNames, uint32 MaxMappings); diff --git a/Engine/Source/Runtime/Core/Public/IOS/IOSAppDelegate.h b/Engine/Source/Runtime/Core/Public/IOS/IOSAppDelegate.h index 8314e55294f1..230c98fbc351 100644 --- a/Engine/Source/Runtime/Core/Public/IOS/IOSAppDelegate.h +++ b/Engine/Source/Runtime/Core/Public/IOS/IOSAppDelegate.h @@ -75,9 +75,19 @@ UITextFieldDelegate> @property (retain) NSTimer* timer; +@property (retain) NSTimer* PeakMemoryTimer; + +/** Timer used for re-enabling the idle timer */ +@property (retain) NSTimer* IdleTimerEnableTimer; + +/** The time delay (in seconds) between idle timer enable requests and actually enabling the idle timer */ +@property (readonly) float IdleTimerEnablePeriod; + #if !UE_BUILD_SHIPPING && !PLATFORM_TVOS /** Properties for managing the console */ +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0 @property (nonatomic, retain) UIAlertView* ConsoleAlert; +#endif #ifdef __IPHONE_8_0 @property (nonatomic, assign) UIAlertController* ConsoleAlertController; #endif @@ -107,6 +117,7 @@ UITextFieldDelegate> -(int)GetAudioVolume; -(bool)AreHeadphonesPluggedIn; -(int)GetBatteryLevel; +-(bool)IsRunningOnBattery; /** TRUE if the device is playing background music and we want to allow that */ @property (assign) bool bUsingBackgroundMusic; diff --git a/Engine/Source/Runtime/Core/Public/IOS/IOSPlatform.h b/Engine/Source/Runtime/Core/Public/IOS/IOSPlatform.h index 6f8cceedd1fc..6e97526b4e4e 100644 --- a/Engine/Source/Runtime/Core/Public/IOS/IOSPlatform.h +++ b/Engine/Source/Runtime/Core/Public/IOS/IOSPlatform.h @@ -50,6 +50,9 @@ typedef FIOSPlatformTypes FPlatformTypes; #define PLATFORM_USES_ES2 1 #define PLATFORM_HAS_TOUCH_MAIN_SCREEN 1 #endif +#define PLATFORM_UI_HAS_MOBILE_SCROLLBARS 1 +#define PLATFORM_UI_NEEDS_TOOLTIPS 0 +#define PLATFORM_UI_NEEDS_FOCUS_OUTLINES 0 // @todo iOS: temporarily use Ansi allocator as wxWidgets cause problems with MallocTBB #define FORCE_ANSI_ALLOCATOR 1 diff --git a/Engine/Source/Runtime/Core/Public/IOS/IOSPlatformCompilerPreSetup.h b/Engine/Source/Runtime/Core/Public/IOS/IOSPlatformCompilerPreSetup.h index 3172e9dc781c..8ec92f365227 100644 --- a/Engine/Source/Runtime/Core/Public/IOS/IOSPlatformCompilerPreSetup.h +++ b/Engine/Source/Runtime/Core/Public/IOS/IOSPlatformCompilerPreSetup.h @@ -99,6 +99,17 @@ _Pragma("clang diagnostic pop") #endif // PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS +#ifndef PRAGMA_DISABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS + #define PRAGMA_DISABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wdelete-non-virtual-dtor\"") +#endif // PRAGMA_DISABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS + +#ifndef PRAGMA_ENABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS + #define PRAGMA_ENABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS \ + _Pragma("clang diagnostic pop") +#endif // PRAGMA_ENABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS + #ifndef PRAGMA_POP #define PRAGMA_POP \ _Pragma("clang diagnostic pop") @@ -131,6 +142,8 @@ #pragma clang diagnostic ignored "-Wundefined-bool-conversion" #pragma clang diagnostic ignored "-Wunused-local-typedef" #pragma clang diagnostic ignored "-Wdelete-non-virtual-dtor" +#pragma clang diagnostic ignored "-Wlogical-op-parentheses" +#pragma clang diagnostic ignored "-Wconstant-logical-operand" // Apple LLVM 8.1.0 (Xcode 8.3) introduced -Wundefined-var-template #if (__clang_major__ > 8) || (__clang_major__ == 8 && __clang_minor__ >= 1) @@ -143,7 +156,7 @@ #endif // We can pragma optimisation's on and off as of Apple LLVM 7.3.0 but not before. -#if __clang_major__ >= 7 && __clang_minor__ >= 3 +#if (__clang_major__ > 7) || (__clang_major__ == 7 && __clang_minor__ >= 3) #define PRAGMA_DISABLE_OPTIMIZATION_ACTUAL _Pragma("clang optimize off") #define PRAGMA_ENABLE_OPTIMIZATION_ACTUAL _Pragma("clang optimize on") #endif diff --git a/Engine/Source/Runtime/Core/Public/IOS/IOSPlatformMisc.h b/Engine/Source/Runtime/Core/Public/IOS/IOSPlatformMisc.h index 877d240878d7..85daba1f2be1 100644 --- a/Engine/Source/Runtime/Core/Public/IOS/IOSPlatformMisc.h +++ b/Engine/Source/Runtime/Core/Public/IOS/IOSPlatformMisc.h @@ -42,8 +42,9 @@ private: **/ struct CORE_API FIOSPlatformMisc : public FGenericPlatformMisc { + static void PlatformPreInit(); static void PlatformInit(); - static void PlatformPostInit(bool ShowSplashScreen = false); + static void PlatformHandleSplashScreen(bool ShowSplashScreen = false); static class GenericApplication* CreateApplication(); static void GetEnvironmentVariable(const TCHAR* VariableName, TCHAR* Result, int32 ResultLength); static void* GetHardwareWindow(); @@ -112,9 +113,7 @@ struct CORE_API FIOSPlatformMisc : public FGenericPlatformMisc FORCEINLINE static void MemoryBarrier() { -PRAGMA_DISABLE_DEPRECATION_WARNINGS - OSMemoryBarrier(); -PRAGMA_ENABLE_DEPRECATION_WARNINGS + __sync_synchronize(); } static void LowLevelOutputDebugString(const TCHAR *Message); @@ -140,6 +139,7 @@ PRAGMA_ENABLE_DEPRECATION_WARNINGS static FString GetLocalCurrencySymbol(); static void GetValidTargetPlatforms(class TArray& TargetPlatformNames); static bool HasActiveWiFiConnection(); + static EScreenPhysicalAccuracy ComputePhysicalScreenDensity(int32& ScreenDensity); static void ResetGamepadAssignments(); static void ResetGamepadAssignmentToController(int32 ControllerId); @@ -148,6 +148,7 @@ PRAGMA_ENABLE_DEPRECATION_WARNINGS static int GetAudioVolume(); static bool AreHeadphonesPluggedIn(); static int GetBatteryLevel(); + static bool IsRunningOnBattery(); static void RegisterForRemoteNotifications(); @@ -171,6 +172,8 @@ PRAGMA_ENABLE_DEPRECATION_WARNINGS * so all the caveats that apply to that API call apply here. */ static FString GetDeviceId(); + static FString GetOSVersion(); + static FString GetUniqueAdvertisingId(); // Possible iOS devices enum EIOSDevice @@ -242,7 +245,14 @@ PRAGMA_ENABLE_DEPRECATION_WARNINGS // look up into the string array by the enum return IOSDeviceNames[(int32)GetIOSDeviceType()]; } + + static FString GetCPUVendor(); + static FString GetCPUBrand(); + static void GetOSVersions(FString& out_OSVersionLabel, FString& out_OSSubVersionLabel); + static int32 IOSVersionCompare(uint8 Major, uint8 Minor, uint8 Revision); + static void SetGracefulTerminationHandler(); + static void SetCrashHandler(void(*CrashHandler)(const FGenericCrashContext& Context)); private: static class FIOSApplication* CachedApplication; }; diff --git a/Engine/Source/Runtime/Core/Public/IOS/IOSPlatformProcess.h b/Engine/Source/Runtime/Core/Public/IOS/IOSPlatformProcess.h index 2476a1de0c50..18547b1b0390 100644 --- a/Engine/Source/Runtime/Core/Public/IOS/IOSPlatformProcess.h +++ b/Engine/Source/Runtime/Core/Public/IOS/IOSPlatformProcess.h @@ -39,6 +39,7 @@ struct CORE_API FIOSPlatformProcess : public FGenericPlatformProcess static void SetupRenderThread(); static void SetThreadAffinityMask(uint64 AffinityMask); static const TCHAR* ExecutableName(bool bRemoveExtension = true); + static FString GenerateApplicationPath( const FString& AppName, EBuildConfigurations::Type BuildConfiguration); private: static void SetupThread(int Priority); diff --git a/Engine/Source/Runtime/Core/Public/IOS/IOSView.h b/Engine/Source/Runtime/Core/Public/IOS/IOSView.h index 811fddf02a96..f6d5220e9ee0 100644 --- a/Engine/Source/Runtime/Core/Public/IOS/IOSView.h +++ b/Engine/Source/Runtime/Core/Public/IOS/IOSView.h @@ -11,6 +11,19 @@ #import #endif +struct FKeyboardConfig +{ + UIKeyboardType KeyboardType; + UITextAutocorrectionType AutocorrectionType; + UITextAutocapitalizationType AutocapitalizationType; + BOOL bSecureTextEntry; + + FORCEINLINE FKeyboardConfig() : + KeyboardType(UIKeyboardTypeDefault), + AutocorrectionType(UITextAutocorrectionTypeNo), + AutocapitalizationType(UITextAutocapitalizationTypeNone), + bSecureTextEntry(NO) {} +}; @interface FIOSView : UIView { @@ -52,6 +65,13 @@ // caches for the TextInput NSString* CachedMarkedText; + + UIKeyboardType KeyboardType; + UITextAutocorrectionType AutocorrectionType; + UITextAutocapitalizationType AutocapitalizationType; + BOOL bSecureTextEntry; + + volatile int32 KeyboardShowCount; } @@ -80,6 +100,8 @@ //// KEYBOARD FUNCTIONALITY -(void)InitKeyboard; -(void)ActivateKeyboard:(bool)bInSendEscapeOnClose; +-(void)ActivateKeyboard:(bool)bInSendEscapeOnClose keyboardConfig:(FKeyboardConfig)KeyboardConfig; +-(void)DeactivateKeyboard; @end diff --git a/Engine/Source/Runtime/Core/Public/Linux/LinuxApplication.h b/Engine/Source/Runtime/Core/Public/Linux/LinuxApplication.h index 911dd51c30b9..3eee061039a4 100644 --- a/Engine/Source/Runtime/Core/Public/Linux/LinuxApplication.h +++ b/Engine/Source/Runtime/Core/Public/Linux/LinuxApplication.h @@ -63,8 +63,6 @@ public: virtual FPlatformRect GetWorkArea( const FPlatformRect& CurrentWindow ) const override; - virtual bool TryCalculatePopupWindowPosition( const FPlatformRect& InAnchor, const FVector2D& InSize, const EPopUpOrientation::Type Orientation, /*OUT*/ FVector2D* const CalculatedPopUpPosition ) const override; - virtual EWindowTransparency GetWindowTransparencySupport() const override { return EWindowTransparency::PerWindow; diff --git a/Engine/Source/Runtime/Core/Public/Linux/LinuxCriticalSection.h b/Engine/Source/Runtime/Core/Public/Linux/LinuxCriticalSection.h index e90daca9fe47..75693f9955a9 100644 --- a/Engine/Source/Runtime/Core/Public/Linux/LinuxCriticalSection.h +++ b/Engine/Source/Runtime/Core/Public/Linux/LinuxCriticalSection.h @@ -5,6 +5,7 @@ #include "CoreTypes.h" #include "Misc/Timespan.h" #include "HAL/PThreadCriticalSection.h" +#include "PThreadRWLock.h" /** * Linux implementation of the FSystemWideCriticalSection. Uses exclusive file locking. @@ -38,3 +39,4 @@ private: typedef FPThreadsCriticalSection FCriticalSection; typedef FLinuxSystemWideCriticalSection FSystemWideCriticalSection; +typedef FPThreadsRWLock FRWLock; diff --git a/Engine/Source/Runtime/Core/Public/Linux/LinuxPlatformAtomics.h b/Engine/Source/Runtime/Core/Public/Linux/LinuxPlatformAtomics.h index de892296bdaf..a720c4131785 100644 --- a/Engine/Source/Runtime/Core/Public/Linux/LinuxPlatformAtomics.h +++ b/Engine/Source/Runtime/Core/Public/Linux/LinuxPlatformAtomics.h @@ -67,12 +67,15 @@ struct CORE_API FLinuxPlatformAtomics return __sync_val_compare_and_swap(Dest, Comperand, Exchange); } -#if PLATFORM_64BITS static FORCEINLINE int64 InterlockedCompareExchange( volatile int64* Dest, int64 Exchange, int64 Comperand ) { return __sync_val_compare_and_swap(Dest, Comperand, Exchange); } -#endif + + static FORCEINLINE int64 AtomicRead64(volatile const int64* Src) + { + return InterlockedCompareExchange((volatile int64*)Src, 0, 0); + } static FORCEINLINE void* InterlockedCompareExchangePointer( void** Dest, void* Exchange, void* Comperand ) { @@ -81,4 +84,5 @@ struct CORE_API FLinuxPlatformAtomics }; + typedef FLinuxPlatformAtomics FPlatformAtomics; diff --git a/Engine/Source/Runtime/Core/Public/Linux/LinuxPlatformCompilerPreSetup.h b/Engine/Source/Runtime/Core/Public/Linux/LinuxPlatformCompilerPreSetup.h index 4362ce8b84e5..d227a17887a9 100644 --- a/Engine/Source/Runtime/Core/Public/Linux/LinuxPlatformCompilerPreSetup.h +++ b/Engine/Source/Runtime/Core/Public/Linux/LinuxPlatformCompilerPreSetup.h @@ -64,6 +64,17 @@ _Pragma("clang diagnostic pop") #endif // PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS +#ifndef PRAGMA_DISABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS + #define PRAGMA_DISABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wdelete-non-virtual-dtor\"") +#endif // PRAGMA_DISABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS + +#ifndef PRAGMA_ENABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS + #define PRAGMA_ENABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS \ + _Pragma("clang diagnostic pop") +#endif // PRAGMA_ENABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS + #ifndef PRAGMA_DISABLE_NULL_DEREFERENCE_WARNINGS #if (__clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 9)) #define PRAGMA_DISABLE_NULL_DEREFERENCE_WARNINGS \ @@ -91,11 +102,13 @@ #define THIRD_PARTY_INCLUDES_START \ PRAGMA_DISABLE_SHADOW_VARIABLE_WARNINGS \ PRAGMA_DISABLE_NULL_DEREFERENCE_WARNINGS \ - PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS + PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS \ + PRAGMA_DISABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS #endif #ifndef THIRD_PARTY_INCLUDES_END #define THIRD_PARTY_INCLUDES_END \ + PRAGMA_ENABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS \ PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS \ PRAGMA_ENABLE_NULL_DEREFERENCE_WARNINGS \ PRAGMA_ENABLE_SHADOW_VARIABLE_WARNINGS diff --git a/Engine/Source/Runtime/Core/Public/Linux/LinuxPlatformMisc.h b/Engine/Source/Runtime/Core/Public/Linux/LinuxPlatformMisc.h index c4d373480602..2ace16cec4fa 100644 --- a/Engine/Source/Runtime/Core/Public/Linux/LinuxPlatformMisc.h +++ b/Engine/Source/Runtime/Core/Public/Linux/LinuxPlatformMisc.h @@ -171,6 +171,7 @@ struct CORE_API FLinuxPlatformMisc : public FGenericPlatformMisc * @return true if the error code has been overriden, false if not */ static bool HasOverriddenReturnCode(uint8 * OverriddenReturnCodeToUsePtr); + static FString GetOSVersion(); }; typedef FLinuxPlatformMisc FPlatformMisc; diff --git a/Engine/Source/Runtime/Core/Public/Linux/LinuxSystemIncludes.h b/Engine/Source/Runtime/Core/Public/Linux/LinuxSystemIncludes.h index 85919b796c31..4f3bfccfc266 100644 --- a/Engine/Source/Runtime/Core/Public/Linux/LinuxSystemIncludes.h +++ b/Engine/Source/Runtime/Core/Public/Linux/LinuxSystemIncludes.h @@ -32,7 +32,7 @@ #include #include #include -#ifdef PLATFORM_ENABLE_VECTORINTRINSICS +#if PLATFORM_ENABLE_VECTORINTRINSICS #include #endif // PLATFORM_RASPBERRY #include diff --git a/Engine/Source/Runtime/Core/Public/Logging/LogMacros.h b/Engine/Source/Runtime/Core/Public/Logging/LogMacros.h index ab62c7141a31..23cc8618fba4 100644 --- a/Engine/Source/Runtime/Core/Public/Logging/LogMacros.h +++ b/Engine/Source/Runtime/Core/Public/Logging/LogMacros.h @@ -238,7 +238,7 @@ struct CORE_API FMsg } /** - * A macro to declare a logging category as a C++ "extern" + * A macro to declare a logging category as a C++ "extern", usually declared in the header and paired with DEFINE_LOG_CATEGORY in the source. Accessible by all files that include the header. * @param CategoryName, category to declare * @param DefaultVerbosity, default run time verbosity * @param CompileTimeVerbosity, maximum verbosity to compile into the code @@ -256,7 +256,7 @@ struct CORE_API FMsg #define DEFINE_LOG_CATEGORY(CategoryName) FLogCategory##CategoryName CategoryName; /** - * A macro to define a logging category as a C++ "static" + * A macro to define a logging category as a C++ "static". This should ONLY be declared in a source file. Only accessible in that single file. * @param CategoryName, category to declare * @param DefaultVerbosity, default run time verbosity * @param CompileTimeVerbosity, maximum verbosity to compile into the code @@ -278,7 +278,7 @@ struct CORE_API FMsg /** * A macro to define a logging category, usually paired with DECLARE_LOG_CATEGORY_CLASS from the header. - * @param CategoryName, category to definee + * @param CategoryName, category to define **/ #define DEFINE_LOG_CATEGORY_CLASS(Class, CategoryName) Class::FLogCategory##CategoryName Class::CategoryName; diff --git a/Engine/Source/Runtime/Core/Public/Mac/MacCriticalSection.h b/Engine/Source/Runtime/Core/Public/Mac/MacCriticalSection.h index c3ccbbdfa6f4..7beca6fdb966 100644 --- a/Engine/Source/Runtime/Core/Public/Mac/MacCriticalSection.h +++ b/Engine/Source/Runtime/Core/Public/Mac/MacCriticalSection.h @@ -3,6 +3,7 @@ #pragma once #include "PThreadCriticalSection.h" +#include "PThreadRWLock.h" #include "Containers/UnrealString.h" #include "Misc/Timespan.h" @@ -38,3 +39,4 @@ private: typedef FPThreadsCriticalSection FCriticalSection; typedef FMacSystemWideCriticalSection FSystemWideCriticalSection; +typedef FPThreadsRWLock FRWLock; diff --git a/Engine/Source/Runtime/Core/Public/Mac/MacPlatformCompilerPreSetup.h b/Engine/Source/Runtime/Core/Public/Mac/MacPlatformCompilerPreSetup.h index a30108823f11..c40371640d66 100644 --- a/Engine/Source/Runtime/Core/Public/Mac/MacPlatformCompilerPreSetup.h +++ b/Engine/Source/Runtime/Core/Public/Mac/MacPlatformCompilerPreSetup.h @@ -99,6 +99,17 @@ _Pragma("clang diagnostic pop") #endif // PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS +#ifndef PRAGMA_DISABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS + #define PRAGMA_DISABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wdelete-non-virtual-dtor\"") +#endif // PRAGMA_DISABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS + +#ifndef PRAGMA_ENABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS + #define PRAGMA_ENABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS \ + _Pragma("clang diagnostic pop") +#endif // PRAGMA_ENABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS + #ifndef PRAGMA_POP #define PRAGMA_POP \ _Pragma("clang diagnostic pop") @@ -108,11 +119,13 @@ #ifndef THIRD_PARTY_INCLUDES_START #define THIRD_PARTY_INCLUDES_START \ PRAGMA_DISABLE_SHADOW_VARIABLE_WARNINGS \ - PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS + PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS \ + PRAGMA_DISABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS #endif #ifndef THIRD_PARTY_INCLUDES_END #define THIRD_PARTY_INCLUDES_END \ + PRAGMA_ENABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS \ PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS \ PRAGMA_ENABLE_SHADOW_VARIABLE_WARNINGS #endif @@ -130,7 +143,8 @@ #pragma clang diagnostic ignored "-Winconsistent-missing-override" #pragma clang diagnostic ignored "-Wundefined-bool-conversion" #pragma clang diagnostic ignored "-Wunused-local-typedef" -#pragma clang diagnostic ignored "-Wdelete-non-virtual-dtor" +#pragma clang diagnostic ignored "-Wconstant-logical-operand" +#pragma clang diagnostic ignored "-Wreserved-user-defined-literal" // Apple LLVM 8.1.0 (Xcode 8.3) introduced -Wundefined-var-template #if (__clang_major__ > 8) || (__clang_major__ == 8 && __clang_minor__ >= 1) @@ -139,6 +153,7 @@ #pragma clang diagnostic ignored "-Wobjc-protocol-property-synthesis" #pragma clang diagnostic ignored "-Wnullability-completeness-on-arrays" #pragma clang diagnostic ignored "-Wnull-dereference" +#pragma clang diagnostic ignored "-Wnonportable-include-path" // Ideally this one would be set in MacToolChain, but we don't have a way to check the compiler version in there yet #endif // We can use pragma optimisation's on and off as of Apple LLVM 7.3.0 but not before. diff --git a/Engine/Source/Runtime/Core/Public/Mac/MacPlatformMisc.h b/Engine/Source/Runtime/Core/Public/Mac/MacPlatformMisc.h index 2f7348944b66..5d25e357af7c 100644 --- a/Engine/Source/Runtime/Core/Public/Mac/MacPlatformMisc.h +++ b/Engine/Source/Runtime/Core/Public/Mac/MacPlatformMisc.h @@ -21,7 +21,7 @@ struct CORE_API FMacPlatformMisc : public FGenericPlatformMisc { static void PlatformPreInit(); static void PlatformInit(); - static void PlatformPostInit(bool ShowSplashScreen = false); + static void PlatformPostInit(); static void PlatformTearDown(); static class GenericApplication* CreateApplication(); static void GetEnvironmentVariable(const TCHAR* VariableName, TCHAR* Result, int32 ResultLength); @@ -84,9 +84,7 @@ struct CORE_API FMacPlatformMisc : public FGenericPlatformMisc FORCEINLINE static void MemoryBarrier() { -PRAGMA_DISABLE_DEPRECATION_WARNINGS - OSMemoryBarrier(); -PRAGMA_ENABLE_DEPRECATION_WARNINGS + __sync_synchronize(); } static void PumpMessages(bool bFromMainLoop); @@ -108,6 +106,7 @@ PRAGMA_ENABLE_DEPRECATION_WARNINGS static FString GetPrimaryGPUBrand(); static struct FGPUDriverInfo GetGPUDriverInfo(const FString& DeviceDescription); static void GetOSVersions( FString& out_OSVersionLabel, FString& out_OSSubVersionLabel ); + static FString GetOSVersion(); static bool HasPlatformFeature(const TCHAR* FeatureName); static bool GetDiskTotalAndFreeSpace(const FString& InPath, uint64& TotalNumberOfBytes, uint64& NumberOfFreeBytes); static bool HasSeparateChannelForDebugOutput(); diff --git a/Engine/Source/Runtime/Core/Public/Mac/MacPlatformProperties.h b/Engine/Source/Runtime/Core/Public/Mac/MacPlatformProperties.h index fd137584c302..68879abfc284 100644 --- a/Engine/Source/Runtime/Core/Public/Mac/MacPlatformProperties.h +++ b/Engine/Source/Runtime/Core/Public/Mac/MacPlatformProperties.h @@ -117,4 +117,9 @@ struct FMacPlatformProperties { return true; } + + static FORCEINLINE bool SupportsAudioStreaming() + { + return !IsServerOnly(); + } }; diff --git a/Engine/Source/Runtime/Core/Public/Math/BigInt.h b/Engine/Source/Runtime/Core/Public/Math/BigInt.h index 514edaf4ed95..469a719bd3ca 100644 --- a/Engine/Source/Runtime/Core/Public/Math/BigInt.h +++ b/Engine/Source/Runtime/Core/Public/Math/BigInt.h @@ -1201,7 +1201,7 @@ namespace FEncryption } } -//~ APIDOCTOOL: Document=Off +/// @cond DOXYGEN_WARNINGS /** * Specialization for int type used in encryption (performance). Avoids using temporary results and most of the operations are inplace. @@ -1224,7 +1224,7 @@ FORCEINLINE TEncryptionInt FEncryption::ModularPow(TEncryptionInt Base, TEncrypt return Result; } -//~ APIDOCTOOL: Document=On +/// @endcond template struct FSignatureBase diff --git a/Engine/Source/Runtime/Core/Public/Math/BoxSphereBounds.h b/Engine/Source/Runtime/Core/Public/Math/BoxSphereBounds.h index 5321282faf4c..a236d0066b60 100644 --- a/Engine/Source/Runtime/Core/Public/Math/BoxSphereBounds.h +++ b/Engine/Source/Runtime/Core/Public/Math/BoxSphereBounds.h @@ -119,6 +119,21 @@ public: */ FORCEINLINE FBoxSphereBounds operator+( const FBoxSphereBounds& Other ) const; + /** + * Compare bounding volume this and Other. + * + * @param Other The other bounding volume. + * @return true of they match. + */ + FORCEINLINE bool operator==(const FBoxSphereBounds& Other) const; + + /** + * Compare bounding volume this and Other. + * + * @param Other The other bounding volume. + * @return true of they do not match. + */ + FORCEINLINE bool operator!=(const FBoxSphereBounds& Other) const; public: @@ -343,6 +358,15 @@ FORCEINLINE FBoxSphereBounds FBoxSphereBounds::operator+( const FBoxSphereBounds return Result; } +FORCEINLINE bool FBoxSphereBounds::operator==(const FBoxSphereBounds& Other) const +{ + return Origin == Other.Origin && BoxExtent == Other.BoxExtent && SphereRadius == Other.SphereRadius; +} + +FORCEINLINE bool FBoxSphereBounds::operator!=(const FBoxSphereBounds& Other) const +{ + return !(*this == Other); +} FORCEINLINE FString FBoxSphereBounds::ToString() const { diff --git a/Engine/Source/Runtime/Core/Public/Math/IntRect.h b/Engine/Source/Runtime/Core/Public/Math/IntRect.h index fdb35ea8f5e7..f1fd67cbbaae 100644 --- a/Engine/Source/Runtime/Core/Public/Math/IntRect.h +++ b/Engine/Source/Runtime/Core/Public/Math/IntRect.h @@ -8,7 +8,6 @@ #include "Math/IntPoint.h" #include "Math/Vector2D.h" -struct Rect; /** * Structure for integer rectangles in 2-d space. diff --git a/Engine/Source/Runtime/Core/Public/Math/NumericLimits.h b/Engine/Source/Runtime/Core/Public/Math/NumericLimits.h index f629140fd64c..a2d22d579286 100644 --- a/Engine/Source/Runtime/Core/Public/Math/NumericLimits.h +++ b/Engine/Source/Runtime/Core/Public/Math/NumericLimits.h @@ -73,17 +73,17 @@ struct TNumericLimits { typedef uint8 NumericType; - static NumericType Min() + static constexpr NumericType Min() { return MIN_uint8; } - static NumericType Max() + static constexpr NumericType Max() { return MAX_uint8; } - static NumericType Lowest() + static constexpr NumericType Lowest() { return Min(); } @@ -95,17 +95,17 @@ struct TNumericLimits { typedef uint16 NumericType; - static NumericType Min() + static constexpr NumericType Min() { return MIN_uint16; } - static NumericType Max() + static constexpr NumericType Max() { return MAX_uint16; } - static NumericType Lowest() + static constexpr NumericType Lowest() { return Min(); } @@ -117,17 +117,17 @@ struct TNumericLimits { typedef uint32 NumericType; - static NumericType Min() + static constexpr NumericType Min() { return MIN_uint32; } - static NumericType Max() + static constexpr NumericType Max() { return MAX_uint32; } - static NumericType Lowest() + static constexpr NumericType Lowest() { return Min(); } @@ -139,17 +139,17 @@ struct TNumericLimits { typedef uint64 NumericType; - static NumericType Min() + static constexpr NumericType Min() { return MIN_uint64; } - static NumericType Max() + static constexpr NumericType Max() { return MAX_uint64; } - static NumericType Lowest() + static constexpr NumericType Lowest() { return Min(); } @@ -161,17 +161,17 @@ struct TNumericLimits { typedef int8 NumericType; - static NumericType Min() + static constexpr NumericType Min() { return MIN_int8; } - static NumericType Max() + static constexpr NumericType Max() { return MAX_int8; } - static NumericType Lowest() + static constexpr NumericType Lowest() { return Min(); } @@ -183,17 +183,17 @@ struct TNumericLimits { typedef int16 NumericType; - static NumericType Min() + static constexpr NumericType Min() { return MIN_int16; } - static NumericType Max() + static constexpr NumericType Max() { return MAX_int16; } - static NumericType Lowest() + static constexpr NumericType Lowest() { return Min(); } @@ -205,17 +205,17 @@ struct TNumericLimits { typedef int32 NumericType; - static NumericType Min() + static constexpr NumericType Min() { return MIN_int32; } - static NumericType Max() + static constexpr NumericType Max() { return MAX_int32; } - static NumericType Lowest() + static constexpr NumericType Lowest() { return Min(); } @@ -227,17 +227,17 @@ struct TNumericLimits { typedef int64 NumericType; - static NumericType Min() + static constexpr NumericType Min() { return MIN_int64; } - static NumericType Max() + static constexpr NumericType Max() { return MAX_int64; } - static NumericType Lowest() + static constexpr NumericType Lowest() { return Min(); } @@ -249,17 +249,17 @@ struct TNumericLimits { typedef float NumericType; - static NumericType Min() + static constexpr NumericType Min() { return MIN_flt; } - static NumericType Max() + static constexpr NumericType Max() { return MAX_flt; } - static NumericType Lowest() + static constexpr NumericType Lowest() { return -Max(); } @@ -271,17 +271,17 @@ struct TNumericLimits { typedef double NumericType; - static NumericType Min() + static constexpr NumericType Min() { return MIN_dbl; } - static NumericType Max() + static constexpr NumericType Max() { return MAX_dbl; } - static NumericType Lowest() + static constexpr NumericType Lowest() { return -Max(); } diff --git a/Engine/Source/Runtime/Core/Public/Math/Sobol.h b/Engine/Source/Runtime/Core/Public/Math/Sobol.h new file mode 100644 index 000000000000..228947b330e1 --- /dev/null +++ b/Engine/Source/Runtime/Core/Public/Math/Sobol.h @@ -0,0 +1,109 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreTypes.h" +#include "Math/Vector2D.h" +#include "Math/Vector.h" + +/** + * Support for Sobol quasi-random numbers + */ +class CORE_API FSobol +{ +public: + // number of Sobol dimensions in DirectionNumbers and GrayNumbers tables (full Joe and Kuo table is 21201) + static const int32 MaxDimension = 15; + + // maximum number of bits in a 2D cell coordinate + // allows cell grids from 1x1 to 2^MaxCell2DBits x 2^MaxCell2DBits + static const int32 MaxCell2DBits = 15; + + // maximum number of bits in a 3D cell coordinate + // allows cell grids from 1x1x1 to 2^MaxCell3DBits x 2^MaxCell3DBits x 2^MaxCell3DBits + static const int32 MaxCell3DBits = 10; + +private: + // 24-bit Sobol direction numbers for 32-bit index + static const int32 DirectionNumbers[MaxDimension + 1][32]; + + // 24-bit Sobol direction numbers for Gray code order + static const int32 GrayNumbers[MaxDimension + 1][32]; + + // 24-bit Sobol direction numbers per cell + static const int32 Cell2DDirectionNumbers[MaxCell2DBits + 1][32][2]; + + // 24-bit Sobol direction numbers per cell in Gray-code order + static const int32 Cell2DGrayNumbers[MaxCell2DBits + 1][32][2]; + + // 24-bit Sobol direction numbers per cell + static const int32 Cell3DDirectionNumbers[MaxCell3DBits + 1][32][3]; + + // 24-bit Sobol direction numbers per cell in Gray-code order + static const int32 Cell3DGrayNumbers[MaxCell3DBits + 1][32][3]; + +public: + /** + * Evaluate Sobol number from one of the traditional Sobol dimensions at the given index + * + * @param Index - The index to evaluate. + * @param Dim - The Sobol dimension to use (0-15). + * @param Seed - A 24-bit random seed when reusing the same dimension + * @return The Sobol result at the given Index + */ + static float Evaluate(int32 Index, int32 Dim, int32 Seed = 0); + + /** + * Evaluate next Sobol number from one of the traditional Sobol dimensions + * + * @param Index - The index for the Sobol number to generate. + * @param Dim - The Sobol dimension to use (0-15) + * @param Value - The value for the Sobol number at Index-1. + * @return The Sobol result at the given Index + */ + static float Next(int32 Index, int32 Dim, float Value); + + + /** + * Evaluate Sobol number from within a 2D cell at given index + * + * @param Index - The index to evaluate. + * @param Cell - Integer cell coordinates. + * @param CellBits - Number of bits in cell coordinates. + * @param Seed - A 24-bit per component 2D seed for shuffling values + * @return The 2D Sobol result in the range 0-1 given Index + */ + static FVector2D Evaluate(int32 Index, int32 CellBits, FIntPoint Cell, FIntPoint Seed); + + /** + * Evaluate next Sobol number from within a 2D cell + * + * @param Index - The index for the Sobol number to generate. + * @param CellBits - Number of bits in cell coordinates. + * @param Value - The value for the Sobol number at Index-1. + * @return The 2D Sobol result in the range 0-1 given Index + */ + static FVector2D Next(int32 Index, int32 CellBits, FVector2D Value); + + + /** + * Evaluate Sobol number from within a 3D cell at given index + * + * @param Index - The index to evaluate. + * @param Cell - Integer cell coordinates. + * @param CellBits - Number of bits in cell coordinates. + * @param Seed - A seed for shuffling values (0-1) + * @return The Sobol result given Index + */ + static FVector Evaluate(int32 Index, int32 CellBits, FIntVector Cell, FIntVector Seed); + + /** + * Evaluate next Sobol number from within a 3D cell + * + * @param Index - The index for the Sobol number to generate. + * @param CellBits - Number of bits in cell coordinates. + * @param Value - The value for the Sobol number at Index-1. + * @return The Sobol result at given Index + */ + static FVector Next(int32 Index, int32 CellBits, FVector Value); +}; \ No newline at end of file diff --git a/Engine/Source/Runtime/Core/Public/Math/TransformCalculus2D.h b/Engine/Source/Runtime/Core/Public/Math/TransformCalculus2D.h index 96fb8b553b29..cab47224f838 100644 --- a/Engine/Source/Runtime/Core/Public/Math/TransformCalculus2D.h +++ b/Engine/Source/Runtime/Core/Public/Math/TransformCalculus2D.h @@ -661,6 +661,22 @@ public: return M.IsIdentity() && Trans == FVector2D::ZeroVector; } + /** + * Converts this affine 2D Transform into an affine 3D transform. + */ + FMatrix To3DMatrix() const + { + float A, B, C, D; + M.GetMatrix(A, B, C, D); + + return FMatrix( + FPlane( A, B, 0.0f, 0.0f), + FPlane( C, D, 0.0f, 0.0f), + FPlane( 0.0f, 0.0f, 1.0f, 0.0f), + FPlane(Trans.X, Trans.Y, 0.0f, 1.0f) + ); + } + private: FMatrix2x2 M; FVector2D Trans; diff --git a/Engine/Source/Runtime/Core/Public/Math/UnitConversion.h b/Engine/Source/Runtime/Core/Public/Math/UnitConversion.h index b4336b0811bc..29265bded72b 100644 --- a/Engine/Source/Runtime/Core/Public/Math/UnitConversion.h +++ b/Engine/Source/Runtime/Core/Public/Math/UnitConversion.h @@ -49,17 +49,20 @@ enum class EUnit : uint8 /** Time units */ Milliseconds, Seconds, Minutes, Hours, Days, Months, Years, + /** Pixel density units */ + PixelsPerInch, + /** Arbitrary multiplier */ Multiplier, - /** Symbolic entry, not specifyable on meta data */ + /** Symbolic entry, not specifiable on meta data */ Unspecified }; /** Enumeration that specifies particular classes of unit */ enum class EUnitType { - Distance, Angle, Speed, Temperature, Mass, Force, Frequency, DataSize, LuminousFlux, Time, Arbitrary, + Distance, Angle, Speed, Temperature, Mass, Force, Frequency, DataSize, LuminousFlux, Time, PixelDensity, Arbitrary, // Symbolic entry - do not use directly NumberOf, diff --git a/Engine/Source/Runtime/Core/Public/Math/Vector.h b/Engine/Source/Runtime/Core/Public/Math/Vector.h index 6b5cfe2ad7a9..dae6923931da 100644 --- a/Engine/Source/Runtime/Core/Public/Math/Vector.h +++ b/Engine/Source/Runtime/Core/Public/Math/Vector.h @@ -19,6 +19,10 @@ #include "Math/IntVector.h" #include "Math/Axis.h" +#if PLATFORM_VECTOR_CUBIC_INTERP_SSE +#include "UnrealMathSSE.h" +#endif + /** * A vector in 3-D space composed of components (X, Y, Z) with floating point precision. */ @@ -477,7 +481,7 @@ public: bool IsZero() const; /** - * Normalize this vector in-place if it is large enough, set it to (0,0,0) otherwise. + * Normalize this vector in-place if it is larger than a given tolerance. Leaves it unchanged if not. * * @param Tolerance Minimum squared length of vector for normalization. * @return true if the vector was normalized correctly, false otherwise. @@ -2094,3 +2098,29 @@ inline FVector FVector2D::SphericalToUnitCartesian() const const float SinTheta = FMath::Sin(X); return FVector(FMath::Cos(Y) * SinTheta, FMath::Sin(Y) * SinTheta, FMath::Cos(X)); } + +#if PLATFORM_VECTOR_CUBIC_INTERP_SSE +template<> +FORCEINLINE_DEBUGGABLE FVector FMath::CubicInterp(const FVector& P0, const FVector& T0, const FVector& P1, const FVector& T1, const float& A) +{ + static_assert(PLATFORM_ENABLE_VECTORINTRINSICS == 1, "Requires SSE intrinsics."); + FVector res; + + const float A2 = A * A; + const float A3 = A2 * A; + + float s0 = (2 * A3) - (3 * A2) + 1; + float s1 = A3 - (2 * A2) + A; + float s2 = (A3 - A2); + float s3 = (-2 * A3) + (3 * A2); + + VectorRegister v0 = VectorMultiply(VectorLoadFloat1(&s0), VectorLoadFloat3(&P0)); + VectorRegister v1 = VectorMultiply(VectorLoadFloat1(&s1), VectorLoadFloat3(&T0)); + VectorRegister v2 = VectorMultiply(VectorLoadFloat1(&s2), VectorLoadFloat3(&T1)); + VectorRegister v3 = VectorMultiply(VectorLoadFloat1(&s3), VectorLoadFloat3(&P1)); + + VectorStoreFloat3(VectorAdd(VectorAdd(v0, v1), VectorAdd(v2, v3)), &res); + + return res; +} +#endif \ No newline at end of file diff --git a/Engine/Source/Runtime/Core/Public/Misc/AssertionMacros.h b/Engine/Source/Runtime/Core/Public/Misc/AssertionMacros.h index 8124c990ba02..763a409c9e9d 100644 --- a/Engine/Source/Runtime/Core/Public/Misc/AssertionMacros.h +++ b/Engine/Source/Runtime/Core/Public/Misc/AssertionMacros.h @@ -18,6 +18,9 @@ struct CORE_API FDebug /** Records the calling of AssertFailed() */ static bool bHasAsserted; + /** Dumps the stack trace into the log, meant to be used for debugging purposes. */ + static void DumpStackTraceToLog(); + #if DO_CHECK || DO_GUARD_SLOW /** Failed assertion handler. Warning: May be called at library startup time. */ static void VARARGS LogAssertFailedMessage( const ANSICHAR* Expr, const ANSICHAR* File, int32 Line, const TCHAR* Format=TEXT(""), ... ); diff --git a/Engine/Source/Runtime/Core/Public/Misc/AutomationTest.h b/Engine/Source/Runtime/Core/Public/Misc/AutomationTest.h index 5d2fd5498252..98092c6138eb 100644 --- a/Engine/Source/Runtime/Core/Public/Misc/AutomationTest.h +++ b/Engine/Source/Runtime/Core/Public/Misc/AutomationTest.h @@ -26,13 +26,14 @@ #include "Math/Color.h" #include "PlatformProcess.h" #include "Misc/AutomationEvent.h" +#include "Internationalization/Regex.h" /** Flags for specifying automation test requirements/behavior */ namespace EAutomationTestFlags { enum Type { - //~ Application context required for the test - not specifying means it will be valid for any context + //~ Application context required for the test // Test is suitable for running within the editor EditorContext = 0x00000001, // Test is suitable for running within the client @@ -84,6 +85,30 @@ namespace EAutomationTestFlags }; }; +/** Flags for indicating the matching type to use for an expected error */ +namespace EAutomationExpectedErrorFlags +{ + enum MatchType + { + // When matching expected errors, do so exactly. + Exact, + // When matching expected errors, just see if the error string is contained in the string to be evaluated. + Contains, + }; + + inline const TCHAR* ToString(EAutomationExpectedErrorFlags::MatchType ThisType) + { + switch (ThisType) + { + case Contains: + return TEXT("Contains"); + case Exact: + return TEXT("Exact"); + } + return TEXT("Unknown"); + } +} + /** Simple class to store the results of the execution of a automation test */ class CORE_API FAutomationTestExecutionInfo { @@ -481,6 +506,43 @@ public: virtual void Run() = 0; }; +struct FAutomationExpectedError +{ + // Original regular expression pattern string matching expected error message. + // NOTE: using the Exact comparison type wraps the pattern string with ^ and $ tokens, + // but the base pattern string is preserved to allow checks for duplicate entries. + FString ErrorPatternString; + // Regular expression pattern for ErrorPatternString + FRegexPattern ErrorPattern; + // Type of comparison to perform on error message using ErrorPattern. + EAutomationExpectedErrorFlags::MatchType CompareType; + /** + * Number of occurrences expected for error. If set greater than 0, it will cause the test to fail if the + * exact number of occurrences expected is not matched. If set to 0, it will suppress all matching messages. + */ + int32 ExpectedNumberOfOccurrences; + int32 ActualNumberOfOccurrences; + + /** + * Constructor + */ + + FAutomationExpectedError(FString& InErrorPattern, EAutomationExpectedErrorFlags::MatchType InCompareType, int32 InExpectedNumberOfOccurrences = 1) + : ErrorPatternString(InErrorPattern) + , ErrorPattern((InCompareType == EAutomationExpectedErrorFlags::Exact) ? FString::Printf(TEXT("^%s$"), *InErrorPattern) : InErrorPattern) + , CompareType(InCompareType) + , ExpectedNumberOfOccurrences(InExpectedNumberOfOccurrences) + , ActualNumberOfOccurrences(0) + {} + + FAutomationExpectedError(FString& InErrorPattern, int32 InExpectedNumberOfOccurrences) + : ErrorPatternString(InErrorPattern) + , ErrorPattern(InErrorPattern) + , CompareType(EAutomationExpectedErrorFlags::Contains) + , ExpectedNumberOfOccurrences(InExpectedNumberOfOccurrences) + {} +}; + struct FAutomationScreenshotData { FString Name; @@ -571,6 +633,10 @@ DECLARE_DELEGATE_TwoParams(FOnTestScreenshotCaptured, const TArray&, con DECLARE_MULTICAST_DELEGATE_FiveParams(FOnTestScreenshotComparisonComplete, bool /*bWasNew*/, bool /*bWasSimilar*/, double /*MaxLocalDifference*/, double /*GlobalDifference*/, FString /*ErrorMessage*/); +DECLARE_MULTICAST_DELEGATE_TwoParams(FOnTestDataRetrieved, bool /*bWasNew*/, const FString& /*JsonData*/); + +DECLARE_MULTICAST_DELEGATE_TwoParams(FOnPerformanceDataRetrieved, bool /*bSuccess*/, const FString& /*ErrorMessage*/); + /** Class representing the main framework for running automation tests */ class CORE_API FAutomationTestFramework { @@ -584,6 +650,12 @@ public: /** Called when a screenshot comparison completes. */ FOnTestScreenshotComparisonComplete OnScreenshotCompared; + /** Called when the test data is retrieved. */ + FOnTestDataRetrieved OnTestDataRetrieved; + + /** Called when the performance data is retrieved. */ + FOnPerformanceDataRetrieved OnPerformanceDataRetrieved; + /** The final call related to screenshots, after they've been taken, and after they've been compared (or not if automation isn't running). */ FSimpleMulticastDelegate OnScreenshotTakenAndCompared; @@ -759,6 +831,8 @@ public: void SetTreatWarningsAsErrors(TOptional bTreatWarningsAsErrors); void NotifyScreenshotComparisonComplete(bool bWasNew, bool bWasSimilar, double MaxLocalDifference, double GlobalDifference, FString ErrorMessage); + void NotifyTestDataRetrieved(bool bWasNew, const FString& JsonData); + void NotifyPerformanceDataRetrieved(bool bSuccess, const FString& ErrorMessage); void NotifyScreenshotTakenAndCompared(); @@ -990,6 +1064,13 @@ public: */ bool HasAnyErrors() const; + /** + * Returns whether this test has encountered all expected errors defined for it + * + * @return true if this test has encountered all expected errors; false if not + */ + bool HasMetExpectedErrors(); + /** * Forcibly sets whether the test has succeeded or not * @@ -1010,6 +1091,25 @@ public: */ void GenerateTestNames( TArray& TestInfo ) const; + /** + * Adds a regex pattern to an internal list that this test will expect to encounter in error or warning logs during its execution. If an expected pattern + * is not encountered, it will cause this test to fail. + * + * @param ExpectedPatternString - The expected message string. Supports basic regex patterns. + * @param CompareType - How to match this string with an encountered error, should it match exactly or simply just contain the string. + * @param Occurrences - How many times to expect this error string to be seen. If > 0, the error must be seen the exact number of times + * specified or the test will fail. If == 0, the error must be seen one or more times (with no upper limit) or the test will fail. + */ + void AddExpectedError(FString ExpectedPatternString, EAutomationExpectedErrorFlags::MatchType CompareType = EAutomationExpectedErrorFlags::Contains, int32 Occurrences = 1); + + /** + * Populate the provided expected errors object with the expected errors contained within the test. Not particularly efficient, + * but providing direct access to the test's private execution errors list could result in errors. + * + * @param OutInfo - Array of Expected Errors to be populated with the same data contained within this test's expected errors list + */ + void GetExpectedErrors(TArray& OutInfo) const; + /** * Is this a complex tast - if so it will be a stress test. * @@ -1307,6 +1407,19 @@ protected: //allow framework to call protected function friend class FAutomationTestFramework; + +private: + /** + * Returns whether this test has defined any expected errors matching the given message. + * If a match is found, the expected error definition increments it actual occurrence count. + * + * @return true if this message matches any of the expected errors + */ + bool IsExpectedError(const FString& Error); + + /* Errors to be expected while processing this test.*/ + TArray< FAutomationExpectedError> ExpectedErrors; + }; class CORE_API FBDDAutomationTestBase : public FAutomationTestBase diff --git a/Engine/Source/Runtime/Core/Public/Misc/CoreDelegates.h b/Engine/Source/Runtime/Core/Public/Misc/CoreDelegates.h index 04b444bf13c7..53f7ecaae021 100644 --- a/Engine/Source/Runtime/Core/Public/Misc/CoreDelegates.h +++ b/Engine/Source/Runtime/Core/Public/Misc/CoreDelegates.h @@ -37,7 +37,6 @@ struct FCrashOverrideParameters FString CrashReportClientMessageText; }; - class CORE_API FCoreDelegates { public: @@ -129,9 +128,15 @@ public: // Called when an error occurred. static FSimpleMulticastDelegate OnShutdownAfterError; - // Called when appInit is called. + // Called when appInit is called, very early in startup static FSimpleMulticastDelegate OnInit; + // Called at the end of UEngine::Init, right before loading PostEngineInit modules for both normal execution and commandlets + static FSimpleMulticastDelegate OnPostEngineInit; + + // Called at the very end of engine initialization, right before the engine starts ticking. This is not called for commandlets + static FSimpleMulticastDelegate OnFEngineLoopInitComplete; + // Called when the application is about to exit. static FSimpleMulticastDelegate OnExit; @@ -147,6 +152,13 @@ public: /** Called when the user accepts an invitation to the current game */ static FOnInviteAccepted OnInviteAccepted; + // Called at the beginning of a frame + static FSimpleMulticastDelegate OnBeginFrame; + + // Called at the end of a frame + static FSimpleMulticastDelegate OnEndFrame; + + DECLARE_MULTICAST_DELEGATE_ThreeParams(FWorldOriginOffset, class UWorld*, FIntVector, FIntVector); /** called before world origin shifting */ static FWorldOriginOffset PreWorldOriginOffset; @@ -185,8 +197,8 @@ public: DECLARE_MULTICAST_DELEGATE_OneParam(FApplicationRegisteredForRemoteNotificationsDelegate, TArray); DECLARE_MULTICAST_DELEGATE_OneParam(FApplicationRegisteredForUserNotificationsDelegate, int); DECLARE_MULTICAST_DELEGATE_OneParam(FApplicationFailedToRegisterForRemoteNotificationsDelegate, FString); - DECLARE_MULTICAST_DELEGATE_OneParam(FApplicationReceivedRemoteNotificationDelegate, FString); - DECLARE_MULTICAST_DELEGATE_TwoParams(FApplicationReceivedLocalNotificationDelegate, FString, int); + DECLARE_MULTICAST_DELEGATE_TwoParams(FApplicationReceivedRemoteNotificationDelegate, FString, int); + DECLARE_MULTICAST_DELEGATE_ThreeParams(FApplicationReceivedLocalNotificationDelegate, FString, int, int); @@ -313,9 +325,6 @@ public: /* Sent just before the rendering thread is destroyed. */ static FRenderingThreadChanged PreRenderingThreadDestroyed; - // Called when appInit is called. - static FSimpleMulticastDelegate OnFEngineLoopInitComplete; - // Callback to allow custom resolution of package names. Arguments are InRequestedName, OutResolvedName. // Should return True of resolution occured. DECLARE_DELEGATE_RetVal_TwoParams(bool, FResolvePackageNameDelegate, const FString&, FString&); @@ -327,8 +336,12 @@ public: DECLARE_DELEGATE_RetVal_TwoParams(bool, FImageIntegrityChanged, const TCHAR*, int32); static FImageIntegrityChanged OnImageIntegrityChanged; + // Called to request that systems free whatever memory they are able to. Called early in LoadMap. + // Caller is responsible for flushing rendering etc. See UEngine::TrimMemory + static FSimpleMulticastDelegate& GetMemoryTrimDelegate(); + // Called when OOM event occurs, after backup memory has been freed, so there's some hope of being effective - static FSimpleMulticastDelegate OnOutOfMemory; + static FSimpleMulticastDelegate& GetOutOfMemoryDelegate(); enum class EOnScreenMessageSeverity : uint8 { diff --git a/Engine/Source/Runtime/Core/Public/Misc/CoreMisc.h b/Engine/Source/Runtime/Core/Public/Misc/CoreMisc.h index a20f3943e7ea..db271f3b9007 100644 --- a/Engine/Source/Runtime/Core/Public/Misc/CoreMisc.h +++ b/Engine/Source/Runtime/Core/Public/Misc/CoreMisc.h @@ -54,6 +54,7 @@ private: class FContextSupplier { public: + virtual ~FContextSupplier() {} virtual FString GetContext()=0; }; diff --git a/Engine/Source/Runtime/Core/Public/Misc/CoreMiscDefines.h b/Engine/Source/Runtime/Core/Public/Misc/CoreMiscDefines.h index 0431dbbcece5..3d5cfb6a750c 100644 --- a/Engine/Source/Runtime/Core/Public/Misc/CoreMiscDefines.h +++ b/Engine/Source/Runtime/Core/Public/Misc/CoreMiscDefines.h @@ -112,6 +112,9 @@ const FPlatformUserId PLATFORMUSERID_NONE = INDEX_NONE; #define PREPROCESSOR_IF_INNER_1(x, y) x #define PREPROCESSOR_IF_INNER_0(x, y) y +// Expands to the parameter list of the macro - used for when you need to pass a comma-separated identifier to another macro as a single parameter +#define PREPROCESSOR_COMMA_SEPARATED(first, second, ...) first, second, ##__VA_ARGS__ + // Expands to nothing - used as a placeholder #define PREPROCESSOR_NOTHING diff --git a/Engine/Source/Runtime/Core/Public/Misc/DateTime.h b/Engine/Source/Runtime/Core/Public/Misc/DateTime.h index 41ce546e09e5..7f37bb182635 100644 --- a/Engine/Source/Runtime/Core/Public/Misc/DateTime.h +++ b/Engine/Source/Runtime/Core/Public/Misc/DateTime.h @@ -698,6 +698,13 @@ protected: /** Holds the cumulative days per month in a non-leap year. */ static const int32 DaysToMonth[]; +private: +#ifdef COREUOBJECT_API + friend COREUOBJECT_API class UScriptStruct* Z_Construct_UScriptStruct_FDateTime(); +#else + friend class UScriptStruct* Z_Construct_UScriptStruct_FDateTime(); +#endif + private: /** Holds the ticks in 100 nanoseconds resolution since January 1, 0001 A.D. */ diff --git a/Engine/Source/Runtime/Core/Public/Misc/EngineVersion.h b/Engine/Source/Runtime/Core/Public/Misc/EngineVersion.h index 687452dd3c96..5170d730ff5c 100644 --- a/Engine/Source/Runtime/Core/Public/Misc/EngineVersion.h +++ b/Engine/Source/Runtime/Core/Public/Misc/EngineVersion.h @@ -50,6 +50,9 @@ public: return Branch.Replace( TEXT( "+" ), TEXT( "/" ) ); } + const FString& GetBranchDescriptor() const; + + private: /** Branch name. */ diff --git a/Engine/Source/Runtime/Core/Public/Misc/EnumClassFlags.h b/Engine/Source/Runtime/Core/Public/Misc/EnumClassFlags.h index 895cc2cfd0c6..fc4bc76a57bd 100644 --- a/Engine/Source/Runtime/Core/Public/Misc/EnumClassFlags.h +++ b/Engine/Source/Runtime/Core/Public/Misc/EnumClassFlags.h @@ -2,8 +2,6 @@ #pragma once -#include "CoreTypes.h" - // Defines all bitwise operators for enum classes so it can be (mostly) used as a regular flags enum #define ENUM_CLASS_FLAGS(Enum) \ inline Enum& operator|=(Enum& Lhs, Enum Rhs) { return Lhs = (Enum)((__underlying_type(Enum))Lhs | (__underlying_type(Enum))Rhs); } \ diff --git a/Engine/Source/Runtime/Core/Public/Misc/FrameValue.h b/Engine/Source/Runtime/Core/Public/Misc/FrameValue.h new file mode 100644 index 000000000000..836d3df964f5 --- /dev/null +++ b/Engine/Source/Runtime/Core/Public/Misc/FrameValue.h @@ -0,0 +1,92 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreGlobals.h" + +/** + * This struct allows you to cache a value for a frame, and automatically invalidates + * when the frame advances. + * If the value was set this frame, IsSet() returns true and GetValue() is valid. + */ +template +struct TFrameValue +{ +private: + uint64 FrameSet; + TOptional Value; + +public: + /** Construct an OptionaType with a valid value. */ + TFrameValue(const ValueType& InValue) + : FrameSet(GFrameCounter) + { + Value = InValue; + } + + TFrameValue(ValueType&& InValue) + : FrameSet(GFrameCounter) + { + Value = InValue; + } + + /** Construct an OptionalType with no value; i.e. unset */ + TFrameValue() + : FrameSet(GFrameCounter) + { + } + + /** Copy/Move construction */ + TFrameValue(const TFrameValue& InValue) + : FrameSet(GFrameCounter) + { + Value = InValue; + } + + TFrameValue(TFrameValue&& InValue) + : FrameSet(GFrameCounter) + { + Value = InValue; + } + + TFrameValue& operator=(const TFrameValue& InValue) + { + Value = InValue; + FrameSet = GFrameCounter; + return *this; + } + + TFrameValue& operator=(TFrameValue&& InValue) + { + Value = InValue; + FrameSet = GFrameCounter; + return *this; + } + + TFrameValue& operator=(const ValueType& InValue) + { + Value = InValue; + FrameSet = GFrameCounter; + return *this; + } + + TFrameValue& operator=(ValueType&& InValue) + { + Value = InValue; + FrameSet = GFrameCounter; + return *this; + } + +public: + + bool IsSet() const + { + return Value.IsSet() && FrameSet == GFrameCounter; + } + + const ValueType& GetValue() const + { + checkf(FrameSet == GFrameCounter, TEXT("Cannot get value on a different frame")); + return Value.GetValue(); + } +}; \ No newline at end of file diff --git a/Engine/Source/Runtime/Core/Public/Misc/Guid.h b/Engine/Source/Runtime/Core/Public/Misc/Guid.h index e2d165ccffa2..cb942a1cfab9 100644 --- a/Engine/Source/Runtime/Core/Public/Misc/Guid.h +++ b/Engine/Source/Runtime/Core/Public/Misc/Guid.h @@ -313,3 +313,14 @@ public: }; template <> struct TIsPODType { enum { Value = true }; }; + +namespace Lex +{ + /** + * Guid default string conversion. + */ + inline FString ToString(const FGuid& Value) + { + return Value.ToString(); + } +} \ No newline at end of file diff --git a/Engine/Source/Runtime/Core/Public/Misc/InlineValue.h b/Engine/Source/Runtime/Core/Public/Misc/InlineValue.h index f6874cc89c02..2d6954295f9b 100644 --- a/Engine/Source/Runtime/Core/Public/Misc/InlineValue.h +++ b/Engine/Source/Runtime/Core/Public/Misc/InlineValue.h @@ -83,9 +83,16 @@ public: */ void Reset(TInlineValue&& In) { - if (In.bIsValid || bIsValid) + Reset(); + + if (In.bIsValid) { - Swap(*this, In); + // Steal the object contained within 'In' + bIsValid = true; + In.bIsValid = false; + + bInline = In.bInline; + Data = In.Data; } } @@ -96,9 +103,11 @@ public: { if (bIsValid) { - DestructItem(&GetValue()); - ConditionallyDestroyAllocation(); + BaseType& Value = GetValue(); + // Set bIsValid immediately to avoid double-deletion on potential re-entry bIsValid = false; + Value.~BaseType(); + ConditionallyDestroyAllocation(); } } @@ -201,10 +210,10 @@ private: template void InitializeFrom(ArgsType&&... Args) { - bInline = sizeof(T) <= MaxInlineSize && ALIGNOF(T) <= DefaultAlignment; + bInline = sizeof(T) <= MaxInlineSize && alignof(T) <= DefaultAlignment; // Allocate the object - ConditionallyAllocateObject(sizeof(T), ALIGNOF(T)); + ConditionallyAllocateObject(sizeof(T), alignof(T)); bIsValid = true; // Placement new our value into the structure diff --git a/Engine/Source/Runtime/Core/Public/Misc/MemStack.h b/Engine/Source/Runtime/Core/Public/Misc/MemStack.h index d8e6a5a68a32..cbfde05f0343 100644 --- a/Engine/Source/Runtime/Core/Public/Misc/MemStack.h +++ b/Engine/Source/Runtime/Core/Public/Misc/MemStack.h @@ -5,7 +5,6 @@ #include "CoreTypes.h" #include "Misc/AssertionMacros.h" #include "HAL/UnrealMemory.h" -#include "Templates/AlignOf.h" #include "Containers/ContainerAllocationPolicies.h" #include "Math/UnrealMathUtility.h" #include "Templates/AlignmentTemplates.h" @@ -299,7 +298,7 @@ public: // Allocate memory from the stack. Data = (ElementType*)FMemStack::Get().PushBytes( NumElements * NumBytesPerElement, - FMath::Max(Alignment,(uint32)ALIGNOF(ElementType)) + FMath::Max(Alignment,(uint32)alignof(ElementType)) ); // If the container previously held elements, copy them into the new allocation. diff --git a/Engine/Source/Runtime/Core/Public/Misc/Optional.h b/Engine/Source/Runtime/Core/Public/Misc/Optional.h index 960f648af817..caca6fcef4d0 100644 --- a/Engine/Source/Runtime/Core/Public/Misc/Optional.h +++ b/Engine/Source/Runtime/Core/Public/Misc/Optional.h @@ -158,6 +158,6 @@ public: const OptionalType& Get(const OptionalType& DefaultValue) const { return IsSet() ? *(OptionalType*)&Value : DefaultValue; } private: - bool bIsSet; TTypeCompatibleBytes Value; + bool bIsSet; }; diff --git a/Engine/Source/Runtime/Core/Public/Misc/Paths.h b/Engine/Source/Runtime/Core/Public/Misc/Paths.h index aebccad81e0f..a0bed8565399 100644 --- a/Engine/Source/Runtime/Core/Public/Misc/Paths.h +++ b/Engine/Source/Runtime/Core/Public/Misc/Paths.h @@ -82,6 +82,20 @@ public: */ static FString EnginePluginsDir(); + /** + * Returns the base directory enterprise directory. + * + * @return enterprise directory + */ + static FString EnterpriseDir(); + + /** + * Returns the enterprise plugins directory + * + * @return Plugins directory. + */ + static FString EnterprisePluginsDir(); + /** * Returns the root directory of the engine directory tree * diff --git a/Engine/Source/Runtime/Core/Public/Misc/ScopeRWLock.h b/Engine/Source/Runtime/Core/Public/Misc/ScopeRWLock.h new file mode 100644 index 000000000000..745e5d03b8d8 --- /dev/null +++ b/Engine/Source/Runtime/Core/Public/Misc/ScopeRWLock.h @@ -0,0 +1,70 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreTypes.h" +#include "Misc/AssertionMacros.h" +#include "HAL/CriticalSection.h" + +// +// A scope lifetime controlled Read or Write lock of referenced mutex object +// +enum FRWScopeLockType +{ + SLT_ReadOnly = 0, + SLT_Write, +}; + +/** + * Implements a scope lock for RW locks. + * Notes: + * - PThreads and Win32 API's don't provide a mechanism for upgrading a ownership of a read lock to a write lock - to get round that this system unlocks then acquires a write lock so it can race between. + */ +class FRWScopeLock +{ +public: + FORCEINLINE FRWScopeLock(FRWLock& InLockObject,FRWScopeLockType InLockType) + : LockObject(InLockObject) + , LockType(InLockType) + { + if(LockType != SLT_ReadOnly) + { + LockObject.WriteLock(); + } + else + { + LockObject.ReadLock(); + } + } + + FORCEINLINE void RaiseLockToWrite() + { + if(LockType == SLT_ReadOnly) + { + LockObject.ReadUnlock(); + LockObject.WriteLock(); + LockType = SLT_Write; + } + } + + FORCEINLINE ~FRWScopeLock() + { + if(LockType == SLT_ReadOnly) + { + LockObject.ReadUnlock(); + } + else + { + LockObject.WriteUnlock(); + } + } + +private: + FRWScopeLock(); + FRWScopeLock(const FRWScopeLock&); + FRWScopeLock& operator=(const FRWScopeLock&); + +private: + FRWLock& LockObject; + FRWScopeLockType LockType; +}; diff --git a/Engine/Source/Runtime/Core/Public/Misc/ScopeTryLock.h b/Engine/Source/Runtime/Core/Public/Misc/ScopeTryLock.h new file mode 100644 index 000000000000..bf5782ad9fdd --- /dev/null +++ b/Engine/Source/Runtime/Core/Public/Misc/ScopeTryLock.h @@ -0,0 +1,65 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreTypes.h" +#include "Misc/AssertionMacros.h" +#include "HAL/CriticalSection.h" + +/** + * Implements a scope lock using TryLock. + * + * This is a utility class that handles scope level locking using TryLock. + * Scope locking helps to avoid programming errors by which a lock is acquired + * and never released. + * + * + * { + * // Try to acquire a lock on CriticalSection for the current scope. + * FScopeTryLock ScopeTryLock(CriticalSection); + * // Check that the lock was acquired. + * if (ScopeTryLock.IsLocked()) + * { + * // If the lock was acquired, we can safely access resources protected + * // by the lock. + * } + * // When ScopeTryLock goes out of scope, the critical section will be + * // released if it was ever acquired. + * } + * + */ +class FScopeTryLock +{ +public: + // Constructor that tries to lock the critical section. Note that you must + // call IsLocked to test that the lock was acquired. + FScopeTryLock(FCriticalSection *InCriticalSection) + : CriticalSection(InCriticalSection) + { + check(CriticalSection); + if (!CriticalSection->TryLock()) + { + CriticalSection = nullptr; + } + } + + // Destructor that will release the lock if it was ever acquired. + ~FScopeTryLock() + { + if (CriticalSection) + { + CriticalSection->Unlock(); + } + } + + FORCEINLINE bool IsLocked() const + { + return nullptr != CriticalSection; + } + +private: + FScopeTryLock(FScopeTryLock const &InScopeLock) = delete; + FScopeTryLock &operator=(FScopeTryLock &Rhs) = delete; + + FCriticalSection *CriticalSection; +}; diff --git a/Engine/Source/Runtime/Core/Public/Misc/ScopedEvent.h b/Engine/Source/Runtime/Core/Public/Misc/ScopedEvent.h index 6eba7349a10d..d521e4e28a46 100644 --- a/Engine/Source/Runtime/Core/Public/Misc/ScopedEvent.h +++ b/Engine/Source/Runtime/Core/Public/Misc/ScopedEvent.h @@ -31,6 +31,14 @@ public: Event->Trigger(); } + /** + * Checks if the event has been triggered (used for special early out cases of scope event) + * if this returns true once it will return true forever + * + * @return returns true if the scoped event has been triggered once + */ + CORE_API bool IsReady(); + /** * Retrieve the event, usually for passing around. * diff --git a/Engine/Source/Runtime/Core/Public/Misc/TimeGuard.h b/Engine/Source/Runtime/Core/Public/Misc/TimeGuard.h index 421f4f9f8be4..994b88a1a6dd 100644 --- a/Engine/Source/Runtime/Core/Public/Misc/TimeGuard.h +++ b/Engine/Source/Runtime/Core/Public/Misc/TimeGuard.h @@ -78,7 +78,6 @@ protected: static CORE_API void ReportHitch(const TCHAR* InName, float TimeMS); static TMap HitchData; static FCriticalSection ReportMutex; - static CORE_API double LastHitchTime; static CORE_API bool bEnabled; static CORE_API float FrameTimeThresholdMS; diff --git a/Engine/Source/Runtime/Core/Public/Misc/Timespan.h b/Engine/Source/Runtime/Core/Public/Misc/Timespan.h index 171938453682..b531aa2af0e5 100644 --- a/Engine/Source/Runtime/Core/Public/Misc/Timespan.h +++ b/Engine/Source/Runtime/Core/Public/Misc/Timespan.h @@ -651,6 +651,13 @@ protected: */ void CORE_API Assign(int32 Days, int32 Hours, int32 Minutes, int32 Seconds, int32 Milliseconds, int32 Microseconds); +private: +#ifdef COREUOBJECT_API + friend COREUOBJECT_API class UScriptStruct* Z_Construct_UScriptStruct_FTimespan(); +#else + friend class UScriptStruct* Z_Construct_UScriptStruct_FTimespan(); +#endif + private: /** Holds the time span in 100 nanoseconds resolution. */ diff --git a/Engine/Source/Runtime/Core/Public/Modules/Boilerplate/ModuleBoilerplate.h b/Engine/Source/Runtime/Core/Public/Modules/Boilerplate/ModuleBoilerplate.h index 979f9497d129..66711286ecc9 100644 --- a/Engine/Source/Runtime/Core/Public/Modules/Boilerplate/ModuleBoilerplate.h +++ b/Engine/Source/Runtime/Core/Public/Modules/Boilerplate/ModuleBoilerplate.h @@ -32,7 +32,11 @@ class FFixedUObjectArray; void operator delete ( void* Ptr ) OPERATOR_DELETE_THROW_SPEC { FMemory::Free( Ptr ); } \ void operator delete[]( void* Ptr ) OPERATOR_DELETE_THROW_SPEC { FMemory::Free( Ptr ); } \ void operator delete ( void* Ptr, const std::nothrow_t& ) OPERATOR_DELETE_NOTHROW_SPEC { FMemory::Free( Ptr ); } \ - void operator delete[]( void* Ptr, const std::nothrow_t& ) OPERATOR_DELETE_NOTHROW_SPEC { FMemory::Free( Ptr ); } + void operator delete[]( void* Ptr, const std::nothrow_t& ) OPERATOR_DELETE_NOTHROW_SPEC { FMemory::Free( Ptr ); } \ + void operator delete ( void* Ptr, size_t Size ) OPERATOR_DELETE_THROW_SPEC { FMemory::Free( Ptr ); } \ + void operator delete[]( void* Ptr, size_t Size ) OPERATOR_DELETE_THROW_SPEC { FMemory::Free( Ptr ); } \ + void operator delete ( void* Ptr, size_t Size, const std::nothrow_t& ) OPERATOR_DELETE_NOTHROW_SPEC { FMemory::Free( Ptr ); } \ + void operator delete[]( void* Ptr, size_t Size, const std::nothrow_t& ) OPERATOR_DELETE_NOTHROW_SPEC { FMemory::Free( Ptr ); } class FFixedUObjectArray; diff --git a/Engine/Source/Runtime/Core/Public/Modules/ModuleManager.h b/Engine/Source/Runtime/Core/Public/Modules/ModuleManager.h index 1c8cfc7a898f..39fcb9600747 100644 --- a/Engine/Source/Runtime/Core/Public/Modules/ModuleManager.h +++ b/Engine/Source/Runtime/Core/Public/Modules/ModuleManager.h @@ -779,11 +779,7 @@ class FDefaultGameModuleImpl * DebugGame modules will be loaded by specifying the -debug parameter on the command-line. */ #if IS_MONOLITHIC && UE_BUILD_DEVELOPMENT - #if defined(UE_BUILD_DEVELOPMENT_WITH_DEBUGGAME) && UE_BUILD_DEVELOPMENT_WITH_DEBUGGAME - #define IMPLEMENT_DEBUGGAME() extern const bool GIsDebugGame = true; - #else - #define IMPLEMENT_DEBUGGAME() extern const bool GIsDebugGame = false; - #endif + #define IMPLEMENT_DEBUGGAME() extern const bool GIsDebugGame = (UE_BUILD_DEVELOPMENT_WITH_DEBUGGAME != 0); #else #define IMPLEMENT_DEBUGGAME() #endif diff --git a/Engine/Source/Runtime/Core/Public/ProfilingDebugging/Histogram.h b/Engine/Source/Runtime/Core/Public/ProfilingDebugging/Histogram.h index db2d7c70daca..fa983d3f5b87 100644 --- a/Engine/Source/Runtime/Core/Public/ProfilingDebugging/Histogram.h +++ b/Engine/Source/Runtime/Core/Public/ProfilingDebugging/Histogram.h @@ -14,6 +14,7 @@ #include "Containers/UnrealString.h" #include "Containers/Map.h" #include "Logging/LogMacros.h" +#include "Containers/ArrayView.h" struct FHistogramBuilder; @@ -30,6 +31,9 @@ struct CORE_API FHistogram /** Inits histogram to mimic our existing hitch buckets */ void InitHitchTracking(); + /** Inits histogram with the specified bin boundaries, with the final bucket extending to infinity (e.g., passing in 0,5 creates a [0..5) bucket and a [5..infinity) bucket) */ + void InitFromArray(TArrayView Thresholds); + /** Resets measurements, without resetting the configured bins. */ void Reset(); diff --git a/Engine/Source/Runtime/Core/Public/ProfilingDebugging/InstanceCounter.h b/Engine/Source/Runtime/Core/Public/ProfilingDebugging/InstanceCounter.h new file mode 100644 index 000000000000..a2e71a361f6c --- /dev/null +++ b/Engine/Source/Runtime/Core/Public/ProfilingDebugging/InstanceCounter.h @@ -0,0 +1,112 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. +#pragma once + +#include "CoreTypes.h" +#include "Containers/UnrealString.h" +#include "Map.h" +#include "NameTypes.h" + +/* + A helper object for counting instances of struct or classes for debugging + purposes, e.g. to get an absolute count of the number of "Foo"'s in existence + + Suggested use + + class UFoo + { + public: + // etc etc + + protected: + COUNT_INSTANCES(FTypeIWantToCount) + }; + +*/ +class CORE_API FInstanceCountingObject +{ +public: + + /** + * Constructor, though geneerally these objects should be created using the COUNT_INSTANCES_ + * macro. + */ + FInstanceCountingObject(const TCHAR* InName, bool InLogConstruction=false); + + /** + * Copy-constructor for assigment + */ + FInstanceCountingObject(const FInstanceCountingObject& RHS); + + /** Destructor */ + virtual ~FInstanceCountingObject(); + + /** + * Returns the count of instances with "Name". + * + * @param: Name + * @return: int32 + */static int32 GetInstanceCount(const TCHAR* Name); + + /** + * Dumps stats for all counted instances to the provided output device. This + * is bound to the "LogCountedInstances" console command + * + * @param: OutputDevice + * @return: void + */static void LogCounts(FOutputDevice& OutputDevice); + +protected: + + /** Increments stats for objects of this type */ + void IncrementStats(); + + /** Decrements stats for objects of this type */ + void DecrementStats(); + +protected: + + /** Name we are tracking */ + FName Name; + + // Log increment/decrement? + bool DoLog; + + /** + * Vars used by our singleton + */ + struct CORE_API FGlobalVars + { + TMap InstanceCounts; + FCriticalSection Mutex; + }; + + /** + * Vars are stored as a pointer and initialized on demand due to avoid dependencies + * on global crot order + */ + static FGlobalVars* Globals; + static FGlobalVars& GetGlobals(); +}; + + +#if !UE_BUILD_SHIPPING + + /** + * Add to class body of TypeName to track counts of "TypeName". Counts can be accessed via code or console + */ + #define COUNT_INSTANCES(TypeName) \ + struct FCount##TypeName : FInstanceCountingObject { FCount##TypeName() : FInstanceCountingObject(TEXT(PREPROCESSOR_TO_STRING(TypeName))) {} }; FCount##TypeName TypeName##Count; + + /** + * Identical to COUNT_INSTANCES, but construction/destruction will be written to the log along with the address of this object (us, not the instance that contains us) + */ + #define COUNT_INSTANCES_AND_LOG(TypeName) \ + struct FCount##TypeName : FInstanceCountingObject { FCount##TypeName() : FInstanceCountingObject(TEXT(PREPROCESSOR_TO_STRING(TypeName)), true) {} }; FCount##TypeName TypeName##Count; + + +#else + + #define COUNT_INSTANCES(TypeName) + #define COUNT_INSTANCES_AND_LOG(TypeName) + +#endif // SHIPPING diff --git a/Engine/Source/Runtime/Core/Public/ProfilingDebugging/ScopedDebugInfo.h b/Engine/Source/Runtime/Core/Public/ProfilingDebugging/ScopedDebugInfo.h index 3d4e8e1e6c2e..ca399ab92a5c 100644 --- a/Engine/Source/Runtime/Core/Public/ProfilingDebugging/ScopedDebugInfo.h +++ b/Engine/Source/Runtime/Core/Public/ProfilingDebugging/ScopedDebugInfo.h @@ -26,7 +26,7 @@ public: FScopedDebugInfo(int32 InNumReplacedOuterCalls); /** Destructor. */ - ~FScopedDebugInfo(); + virtual ~FScopedDebugInfo(); /** @return The "function name" to display on the call stack for this debug info. */ virtual FString GetFunctionName() const = 0; diff --git a/Engine/Source/Runtime/Core/Public/Stats/Stats.h b/Engine/Source/Runtime/Core/Public/Stats/Stats.h index de4d81ba635f..5bdd7b291c1f 100644 --- a/Engine/Source/Runtime/Core/Public/Stats/Stats.h +++ b/Engine/Source/Runtime/Core/Public/Stats/Stats.h @@ -391,6 +391,7 @@ FORCEINLINE void StatsMasterEnableSubtract(int32 Value = 1) #define DECLARE_SCOPE_CYCLE_COUNTER(CounterName,StatId,GroupId) #define CONDITIONAL_SCOPE_CYCLE_COUNTER(Stat,bCondition) #define RETURN_QUICK_DECLARE_CYCLE_STAT(StatId,GroupId) return TStatId(); +#define QUICK_USE_CYCLE_STAT(StatId,GroupId) TStatId() #define DECLARE_CYCLE_STAT(CounterName,StatId,GroupId) #define DECLARE_FLOAT_COUNTER_STAT(CounterName,StatId,GroupId) #define DECLARE_DWORD_COUNTER_STAT(CounterName,StatId,GroupId) diff --git a/Engine/Source/Runtime/Core/Public/Stats/Stats2.h b/Engine/Source/Runtime/Core/Public/Stats/Stats2.h index f4d75b7cf649..51d5df54fda7 100644 --- a/Engine/Source/Runtime/Core/Public/Stats/Stats2.h +++ b/Engine/Source/Runtime/Core/Public/Stats/Stats2.h @@ -3,7 +3,6 @@ #pragma once #include "CoreTypes.h" -#include "Templates/AlignOf.h" #include "Templates/UnrealTemplate.h" #include "HAL/ThreadSafeCounter.h" #include "Math/NumericLimits.h" @@ -776,7 +775,7 @@ struct FStatMessage */ FORCEINLINE_STATS int64& GetValue_int64() { - static_assert(sizeof(int64) <= DATA_SIZE && ALIGNOF(int64) <= DATA_ALIGN, "Bad data for stat message."); + static_assert(sizeof(int64) <= DATA_SIZE && alignof(int64) <= DATA_ALIGN, "Bad data for stat message."); checkStats(NameAndInfo.GetField() == EStatDataType::ST_int64); return *(int64*)&StatData; } @@ -788,7 +787,7 @@ struct FStatMessage FORCEINLINE_STATS uint64& GetValue_Ptr() { - static_assert(sizeof(uint64) <= DATA_SIZE && ALIGNOF(uint64) <= DATA_ALIGN, "Bad data for stat message."); + static_assert(sizeof(uint64) <= DATA_SIZE && alignof(uint64) <= DATA_ALIGN, "Bad data for stat message."); checkStats(NameAndInfo.GetField() == EStatDataType::ST_Ptr); return *(uint64*)&StatData; } @@ -816,7 +815,7 @@ struct FStatMessage FORCEINLINE_STATS double& GetValue_double() { - static_assert(sizeof(double) <= DATA_SIZE && ALIGNOF(double) <= DATA_ALIGN, "Bad data for stat message."); + static_assert(sizeof(double) <= DATA_SIZE && alignof(double) <= DATA_ALIGN, "Bad data for stat message."); checkStats(NameAndInfo.GetField() == EStatDataType::ST_double); return *(double*)&StatData; } @@ -829,7 +828,7 @@ struct FStatMessage FORCEINLINE_STATS FMinimalName& GetValue_FMinimalName() { - static_assert(sizeof(FMinimalName) <= DATA_SIZE && ALIGNOF(FMinimalName) <= DATA_ALIGN, "Bad data for stat message."); + static_assert(sizeof(FMinimalName) <= DATA_SIZE && alignof(FMinimalName) <= DATA_ALIGN, "Bad data for stat message."); checkStats(NameAndInfo.GetField() == EStatDataType::ST_FName); return *(FMinimalName*)&StatData; } @@ -978,7 +977,7 @@ struct TStatMessage */ FORCEINLINE_STATS int64& GetValue_int64( typename TEnum::Type Index ) { - static_assert(sizeof(int64) <= DATA_SIZE && ALIGNOF(int64) <= DATA_ALIGN, "Bad data for stat message."); + static_assert(sizeof(int64) <= DATA_SIZE && alignof(int64) <= DATA_ALIGN, "Bad data for stat message."); checkStats(NameAndInfo.GetField() == EStatDataType::ST_int64); checkStats(Index() == EStatDataType::ST_double); double& Value = *((double*)&StatData+(uint32)Index); @@ -1252,6 +1251,9 @@ class FThreadStats : FNoncopyable /** Tracks current stack depth for cycle counters. **/ bool bSawExplicitFlush; + /** True if this is the stats thread, which needs special handling. **/ + bool bIsStatsThread; + /** Gathers information about the current thread and sets up the TLS value. **/ CORE_API FThreadStats(); @@ -1791,6 +1793,8 @@ struct FStat_##StatName\ static DEFINE_STAT(StatId) \ return GET_STATID(StatId); +#define QUICK_USE_CYCLE_STAT(StatId,GroupId) [](){ RETURN_QUICK_DECLARE_CYCLE_STAT(StatId, GroupId); }() + #define DECLARE_CYCLE_STAT(CounterName,StatId,GroupId) \ DECLARE_STAT(CounterName,StatId,GroupId,EStatDataType::ST_int64, true, true, FPlatformMemory::MCR_Invalid); \ static DEFINE_STAT(StatId) @@ -2035,8 +2039,8 @@ DECLARE_STATS_GROUP(TEXT("CPU Stalls"), STATGROUP_CPUStalls, STATCAT_Advanced); DECLARE_STATS_GROUP(TEXT("Canvas"),STATGROUP_Canvas, STATCAT_Advanced); DECLARE_STATS_GROUP(TEXT("Character"), STATGROUP_Character, STATCAT_Advanced); DECLARE_STATS_GROUP(TEXT("Collision"),STATGROUP_Collision, STATCAT_Advanced); +DECLARE_STATS_GROUP(TEXT("CollisionTags"), STATGROUP_CollisionTags, STATCAT_Advanced); DECLARE_STATS_GROUP_VERBOSE(TEXT("CollisionVerbose"),STATGROUP_CollisionVerbose, STATCAT_Advanced); -DECLARE_STATS_GROUP(TEXT("Crash Tracker"),STATGROUP_CrashTracker, STATCAT_Advanced); DECLARE_STATS_GROUP(TEXT("D3D11RHI"),STATGROUP_D3D11RHI, STATCAT_Advanced); DECLARE_STATS_GROUP(TEXT("DDC"),STATGROUP_DDC, STATCAT_Advanced); DECLARE_STATS_GROUP(TEXT("Default Stat Group"),STATGROUP_Default, STATCAT_Advanced); diff --git a/Engine/Source/Runtime/Core/Public/Stats/StatsData.h b/Engine/Source/Runtime/Core/Public/Stats/StatsData.h index ede9baa4211b..8a6146e21463 100644 --- a/Engine/Source/Runtime/Core/Public/Stats/StatsData.h +++ b/Engine/Source/Runtime/Core/Public/Stats/StatsData.h @@ -480,8 +480,10 @@ struct FEventData /** * Some of the FStatsThreadState data methods allow filtering. Derive your filter from this class */ -struct IItemFiler +struct IItemFilter { + virtual ~IItemFilter() { } + /** return true if you want to keep the item for the purposes of collecting stats **/ virtual bool Keep(FStatMessage const& Item) = 0; }; @@ -541,11 +543,11 @@ private: /** Reset the state of the regular stats. */ void ResetRegularStats(); - /** Prepares fake FGameThreadHudData to display the raw stats memory overhead. */ + /** Prepares fake FGameThreadStatsData to display the raw stats memory overhead. */ void UpdateStatMessagesMemoryUsage(); /** Generates a list of most memory expensive stats and dump to the log. */ - void FindAndDumpMemoryExtensiveStats( FStatPacketArray &Frame ); + void FindAndDumpMemoryExtensiveStats( const FStatPacketArray& Frame ); protected: /** Called in response to SetLongName messages to update ShortNameToLongName and NotClearedEveryFrame **/ @@ -662,22 +664,22 @@ public: } /** Gets the old-skool flat grouped inclusive stats. These ignore recursion, merge threads, etc and so generally the condensed callstack is less confusing. **/ - void GetInclusiveAggregateStackStats( const TArray& CondensedMessages, TArray& OutStats, IItemFiler* Filter = nullptr, bool bAddNonStackStats = true, TMap>* OptionalOutThreadBreakdownMap = nullptr ) const; + void GetInclusiveAggregateStackStats( const TArray& CondensedMessages, TArray& OutStats, IItemFilter* Filter = nullptr, bool bAddNonStackStats = true, TMap>* OptionalOutThreadBreakdownMap = nullptr ) const; /** Gets the old-skool flat grouped inclusive stats. These ignore recursion, merge threads, etc and so generally the condensed callstack is less confusing. **/ - void GetInclusiveAggregateStackStats(int64 TargetFrame, TArray& OutStats, IItemFiler* Filter = nullptr, bool bAddNonStackStats = true, TMap>* OptionalOutThreadBreakdownMap = nullptr) const; + void GetInclusiveAggregateStackStats(int64 TargetFrame, TArray& OutStats, IItemFilter* Filter = nullptr, bool bAddNonStackStats = true, TMap>* OptionalOutThreadBreakdownMap = nullptr) const; /** Gets the old-skool flat grouped exclusive stats. These merge threads, etc and so generally the condensed callstack is less confusing. **/ - void GetExclusiveAggregateStackStats( const TArray& CondensedMessages, TArray& OutStats, IItemFiler* Filter = nullptr, bool bAddNonStackStats = true ) const; + void GetExclusiveAggregateStackStats( const TArray& CondensedMessages, TArray& OutStats, IItemFilter* Filter = nullptr, bool bAddNonStackStats = true ) const; /** Gets the old-skool flat grouped exclusive stats. These merge threads, etc and so generally the condensed callstack is less confusing. **/ - void GetExclusiveAggregateStackStats(int64 TargetFrame, TArray& OutStats, IItemFiler* Filter = nullptr, bool bAddNonStackStats = true) const; + void GetExclusiveAggregateStackStats(int64 TargetFrame, TArray& OutStats, IItemFilter* Filter = nullptr, bool bAddNonStackStats = true) const; /** Used to turn the condensed version of stack stats back into a tree for easier handling. **/ - void UncondenseStackStats( const TArray& CondensedMessages, FRawStatStackNode& Root, IItemFiler* Filter = nullptr, TArray* OutNonStackStats = nullptr ) const; + void UncondenseStackStats( const TArray& CondensedMessages, FRawStatStackNode& Root, IItemFilter* Filter = nullptr, TArray* OutNonStackStats = nullptr ) const; /** Used to turn the condensed version of stack stats back into a tree for easier handling. **/ - void UncondenseStackStats(int64 TargetFrame, FRawStatStackNode& Root, IItemFiler* Filter = nullptr, TArray* OutNonStackStats = nullptr) const; + void UncondenseStackStats(int64 TargetFrame, FRawStatStackNode& Root, IItemFilter* Filter = nullptr, TArray* OutNonStackStats = nullptr) const; /** Adds missing stats to the group so it doesn't jitter. **/ void AddMissingStats(TArray& Dest, TSet const& EnabledItems) const; @@ -819,54 +821,8 @@ struct FComplexStatUtils //@todo split header -/** -* Predicate to sort stats into reverse order of definition, which historically is how people specified a preferred order. -*/ -struct FGroupSort -{ - FORCEINLINE bool operator()( FStatMessage const& A, FStatMessage const& B ) const - { - FName GroupA = A.NameAndInfo.GetGroupName(); - FName GroupB = B.NameAndInfo.GetGroupName(); - // first sort by group - if (GroupA == GroupB) - { - // cycle stats come first - if (A.NameAndInfo.GetFlag(EStatMetaFlags::IsCycle) && !B.NameAndInfo.GetFlag(EStatMetaFlags::IsCycle)) - { - return true; - } - if (!A.NameAndInfo.GetFlag(EStatMetaFlags::IsCycle) && B.NameAndInfo.GetFlag(EStatMetaFlags::IsCycle)) - { - return false; - } - // then memory - if (A.NameAndInfo.GetFlag(EStatMetaFlags::IsMemory) && !B.NameAndInfo.GetFlag(EStatMetaFlags::IsMemory)) - { - return true; - } - if (!A.NameAndInfo.GetFlag(EStatMetaFlags::IsMemory) && B.NameAndInfo.GetFlag(EStatMetaFlags::IsMemory)) - { - return false; - } - // otherwise, reverse order of definition - return A.NameAndInfo.GetRawName().GetComparisonIndex() > B.NameAndInfo.GetRawName().GetComparisonIndex(); - } - if (GroupA == NAME_None) - { - return false; - } - if (GroupB == NAME_None) - { - return true; - } - return GroupA.GetComparisonIndex() > GroupB.GetComparisonIndex(); - } -}; - - -/** Holds stats data used for displayed on the hud. */ -struct FHudGroup +/** Holds stats data used by various systems like the HUD stats*/ +struct FActiveStatGroupInfo { /** Array of all flat aggregates for the last n frames. */ TArray FlatAggregate; @@ -894,47 +850,59 @@ struct FHudGroup }; /** -* Information sent from the stats thread to the game thread to render on the HUD +* Information sent from the stats thread to the game thread to render and be used by other systems */ -struct FGameThreadHudData +struct FGameThreadStatsData { /** Initialization constructor. */ - FGameThreadHudData( bool bInDrawOnlyRawStats ) + FGameThreadStatsData( bool bInDrawOnlyRawStats, bool bInRenderStats ) : bDrawOnlyRawStats(bInDrawOnlyRawStats) + , bRenderStats(bInRenderStats) {} - TIndirectArray HudGroups; + /** NOTE: the returned pointer is only valid for this frame - do not hold on to it! */ + const FComplexStatMessage* GetStatData(const FName& StatName ) const + { + return NameToStatMap.FindRef(StatName); + } + + TIndirectArray ActiveStatGroups; TArray GroupNames; TArray GroupDescriptions; TMap PoolCapacity; TMap PoolAbbreviation; FString RootFilter; + TMap NameToStatMap; + /** Whether to display minimal stats for the raw stats mode. */ const bool bDrawOnlyRawStats; + + /** Whether to render the stats to HUD */ + const bool bRenderStats; }; /** -* Singleton that holds the last data sent from the stats thread to the game thread for HUD stats +* Singleton that holds the last data sent from the stats thread to the game thread for systems to use and display */ -struct FHUDGroupGameThreadRenderer +struct FLatestGameThreadStatsData { - FGameThreadHudData* Latest; + FGameThreadStatsData* Latest; - FHUDGroupGameThreadRenderer() + FLatestGameThreadStatsData() : Latest(nullptr) { } - ~FHUDGroupGameThreadRenderer() + ~FLatestGameThreadStatsData() { delete Latest; Latest = nullptr; } - void NewData(FGameThreadHudData* Data); + void NewData(FGameThreadStatsData* Data); - CORE_API static FHUDGroupGameThreadRenderer& Get(); + CORE_API static FLatestGameThreadStatsData& Get(); }; /** diff --git a/Engine/Source/Runtime/Core/Public/Templates/AlignOf.h b/Engine/Source/Runtime/Core/Public/Templates/AlignOf.h index a7cb945ff441..1a2536b32bca 100644 --- a/Engine/Source/Runtime/Core/Public/Templates/AlignOf.h +++ b/Engine/Source/Runtime/Core/Public/Templates/AlignOf.h @@ -2,62 +2,4 @@ #pragma once - -#include "CoreTypes.h" -#include "Templates/ChooseClass.h" -#include "Templates/IntegralConstant.h" -#include "Templates/IsClass.h" - - -/** Used to determine the alignment of an element type. */ -template::Value> -class TElementAlignmentCalculator -{ - /** - * We use a dummy FAlignedElement type that's used to calculate the padding added between the byte and the element - * to fulfill the type's required alignment. - * - * Its default constructor and destructor are declared but never implemented to avoid the need for a ElementType default constructor. - */ - -private: - /** - * In the case of class ElementTypes, we inherit it to allow abstract types to work. - */ - struct FAlignedElements : ElementType - { - uint8 MisalignmentPadding; - - FAlignedElements(); - ~FAlignedElements(); - }; - - // We calculate the alignment here and then handle the zero case in the result by forwarding it to the non-class variant. - // This is necessary because the compiler can perform empty-base-optimization to eliminate a redundant ElementType state. - // Forwarding it to the non-class implementation should always work because an abstract type should never be empty. - enum { CalculatedAlignment = sizeof(FAlignedElements) - sizeof(ElementType) }; - -public: - enum { Value = TChooseClass, TElementAlignmentCalculator>::Result::Value }; -}; - -template -class TElementAlignmentCalculator -{ -private: - /** - * In the case of non-class ElementTypes, we contain it because non-class types cannot be inherited. - */ - struct FAlignedElements - { - uint8 MisalignmentPadding; - ElementType Element; - - FAlignedElements(); - ~FAlignedElements(); - }; -public: - enum { Value = sizeof(FAlignedElements) - sizeof(ElementType) }; -}; - -#define ALIGNOF(T) (TElementAlignmentCalculator::Value) +#define ALIGNOF(x) DEPRECATED_MACRO(4.17, "ALIGNOF has been deprecated. Please use the alignof keyword instead.") alignof(x) diff --git a/Engine/Source/Runtime/Core/Public/Templates/AreTypesEqual.h b/Engine/Source/Runtime/Core/Public/Templates/AreTypesEqual.h index 243b31d5377a..c0cee5d4004e 100644 --- a/Engine/Source/Runtime/Core/Public/Templates/AreTypesEqual.h +++ b/Engine/Source/Runtime/Core/Public/Templates/AreTypesEqual.h @@ -2,8 +2,6 @@ #pragma once -#include "CoreTypes.h" - /** Tests whether two typenames refer to the same type. */ template struct TAreTypesEqual; diff --git a/Engine/Source/Runtime/Core/Public/Templates/Function.h b/Engine/Source/Runtime/Core/Public/Templates/Function.h index 651bd5f822b6..d44830d501a5 100644 --- a/Engine/Source/Runtime/Core/Public/Templates/Function.h +++ b/Engine/Source/Runtime/Core/Public/Templates/Function.h @@ -355,7 +355,7 @@ namespace UE4Function_Private * { * for (const FString& Str : SomeBunchOfStrings) * { - * int32 Int = Func(Str); + * int32 Int = Convert(Str); * DoSomething(Int); * } * } diff --git a/Engine/Source/Runtime/Core/Public/Templates/IsTriviallyDestructible.h b/Engine/Source/Runtime/Core/Public/Templates/IsTriviallyDestructible.h index cbe015f25b2f..51e4d6bf4fb6 100644 --- a/Engine/Source/Runtime/Core/Public/Templates/IsTriviallyDestructible.h +++ b/Engine/Source/Runtime/Core/Public/Templates/IsTriviallyDestructible.h @@ -2,7 +2,22 @@ #pragma once -#include "CoreTypes.h" +namespace UE4IsTriviallyDestructible_Private +{ + // We have this specialization for enums to avoid the need to have a full definition of + // the type. + template + struct TImpl + { + enum { Value = true }; + }; + + template + struct TImpl + { + enum { Value = __has_trivial_destructor(T) }; + }; +} /** * Traits class which tests if a type has a trivial destructor. @@ -10,5 +25,5 @@ template struct TIsTriviallyDestructible { - enum { Value = __has_trivial_destructor(T) }; + enum { Value = UE4IsTriviallyDestructible_Private::TImpl::Value }; }; diff --git a/Engine/Source/Runtime/Core/Public/Templates/Less.h b/Engine/Source/Runtime/Core/Public/Templates/Less.h index a85448c256c1..8a68419f1396 100644 --- a/Engine/Source/Runtime/Core/Public/Templates/Less.h +++ b/Engine/Source/Runtime/Core/Public/Templates/Less.h @@ -6,10 +6,11 @@ /** * Binary predicate class for sorting elements in order. Assumes < operator is defined for the template type. + * Forward declaration exists in ContainersFwd.h * * See: http://en.cppreference.com/w/cpp/utility/functional/less */ -template +template struct TLess { FORCEINLINE bool operator()(const T& A, const T& B) const diff --git a/Engine/Source/Runtime/Core/Public/Templates/MaxSizeof.h b/Engine/Source/Runtime/Core/Public/Templates/MaxSizeof.h new file mode 100644 index 000000000000..f6efbfdeff93 --- /dev/null +++ b/Engine/Source/Runtime/Core/Public/Templates/MaxSizeof.h @@ -0,0 +1,21 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreTypes.h" + +/** Finds the maximum sizeof the supplied types */ +template +struct TMaxSizeof; + +template <> +struct TMaxSizeof<> +{ + static const uint32 Value = 0; +}; + +template +struct TMaxSizeof +{ + static const uint32 Value = sizeof(T) > TMaxSizeof::Value ? sizeof(T) : TMaxSizeof::Value; +}; \ No newline at end of file diff --git a/Engine/Source/Runtime/Core/Public/Templates/MemoryOps.h b/Engine/Source/Runtime/Core/Public/Templates/MemoryOps.h index a7a08c9ced29..afc7d0abf501 100644 --- a/Engine/Source/Runtime/Core/Public/Templates/MemoryOps.h +++ b/Engine/Source/Runtime/Core/Public/Templates/MemoryOps.h @@ -63,6 +63,8 @@ FORCEINLINE typename TEnableIf::Value>::Type D * Destructs a single item in memory. * * @param Elements A pointer to the item to destruct. + * + * @note: This function is optimized for values of T, and so will not dynamically dispatch destructor calls if T's destructor is virtual. */ template FORCEINLINE typename TEnableIf::Value>::Type DestructItem(ElementType* Element) @@ -85,6 +87,8 @@ FORCEINLINE typename TEnableIf::Value>::Ty * * @param Elements A pointer to the first item to destruct. * @param Count The number of elements to destruct. + * + * @note: This function is optimized for values of T, and so will not dynamically dispatch destructor calls if T's destructor is virtual. */ template FORCEINLINE typename TEnableIf::Value>::Type DestructItems(ElementType* Element, int32 Count) diff --git a/Engine/Source/Runtime/Core/Public/Templates/RefCounting.h b/Engine/Source/Runtime/Core/Public/Templates/RefCounting.h index 9b2067071e5a..e5031fde6d01 100644 --- a/Engine/Source/Runtime/Core/Public/Templates/RefCounting.h +++ b/Engine/Source/Runtime/Core/Public/Templates/RefCounting.h @@ -10,6 +10,7 @@ class IRefCountedObject { public: + virtual ~IRefCountedObject() { } virtual uint32 AddRef() const = 0; virtual uint32 Release() const = 0; virtual uint32 GetRefCount() const = 0; diff --git a/Engine/Source/Runtime/Core/Public/Templates/ReversePredicate.h b/Engine/Source/Runtime/Core/Public/Templates/ReversePredicate.h new file mode 100644 index 000000000000..eaf0224e1044 --- /dev/null +++ b/Engine/Source/Runtime/Core/Public/Templates/ReversePredicate.h @@ -0,0 +1,23 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "Templates/UnrealTemplate.h" + +/** + * Helper class to reverse a predicate. + * Performs Predicate(B, A) + */ +template +class TReversePredicate +{ + const PredicateType& Predicate; + +public: + TReversePredicate( const PredicateType& InPredicate ) + : Predicate( InPredicate ) + {} + + template + FORCEINLINE bool operator()( T&& A, T&& B ) const { return Predicate( Forward(B), Forward(A) ); } +}; \ No newline at end of file diff --git a/Engine/Source/Runtime/Core/Public/Templates/Sorting.h b/Engine/Source/Runtime/Core/Public/Templates/Sorting.h index e99535a91b0e..9c954dd6e74d 100644 --- a/Engine/Source/Runtime/Core/Public/Templates/Sorting.h +++ b/Engine/Source/Runtime/Core/Public/Templates/Sorting.h @@ -5,6 +5,7 @@ #include "CoreTypes.h" #include "HAL/PlatformMath.h" #include "Templates/Less.h" +#include "Algo/BinarySearch.h" /** * Helper class for dereferencing pointer types in Sort function @@ -313,75 +314,20 @@ public: while (AStart < BStart && BStart < Num) { - int32 NewAOffset = BinarySearchLast(First + AStart, BStart - AStart, First[BStart], Predicate) + 1; + // Index after the last value == First[BStart] + int32 NewAOffset = AlgoImpl::UpperBoundInternal(First + AStart, BStart - AStart, First[BStart], FIdentityFunctor(), Predicate); AStart += NewAOffset; if (AStart >= BStart) // done break; - int32 NewBOffset = BinarySearchFirst(First + BStart, Num - BStart, First[AStart], Predicate); + // Index of the first value == First[AStart] + int32 NewBOffset = AlgoImpl::LowerBoundInternal(First + BStart, Num - BStart, First[AStart], FIdentityFunctor(), Predicate); TRotationPolicy::Rotate(First, AStart, BStart + NewBOffset, NewBOffset); BStart += NewBOffset; AStart += NewBOffset + 1; } } - -private: - /** - * Performs binary search, resulting in position of the first element with given value in an array. - * - * @param First Pointer to array. - * @param Num Number of elements in array. - * @param Value Value to look for. - * @param Predicate Predicate for comparison. - * - * @returns Position of the first element with value Value. - */ - template - static int32 BinarySearchFirst(T* First, const int32 Num, const T& Value, const PREDICATE_CLASS& Predicate) - { - int32 Start = 0; - int32 End = Num; - - while (End - Start > 1) - { - int32 Mid = (Start + End) / 2; - bool bComparison = Predicate(First[Mid], Value); - - Start = bComparison ? Mid : Start; - End = bComparison ? End : Mid; - } - - return Predicate(First[Start], Value) ? Start + 1 : Start; - } - - /** - * Performs binary search, resulting in position of the last element with given value in an array. - * - * @param First Pointer to array. - * @param Num Number of elements in array. - * @param Value Value to look for. - * @param Predicate Predicate for comparison. - * - * @returns Position of the last element with value Value. - */ - template - static int32 BinarySearchLast(T* First, const int32 Num, const T& Value, const PREDICATE_CLASS& Predicate) - { - int32 Start = 0; - int32 End = Num; - - while (End - Start > 1) - { - int32 Mid = (Start + End) / 2; - bool bComparison = !Predicate(Value, First[Mid]); - - Start = bComparison ? Mid : Start; - End = bComparison ? End : Mid; - } - - return Predicate(Value, First[Start]) ? Start - 1 : Start; - } }; /** diff --git a/Engine/Source/Runtime/Core/Public/Templates/Tuple.h b/Engine/Source/Runtime/Core/Public/Templates/Tuple.h index df0730022bb2..3e14007436e3 100644 --- a/Engine/Source/Runtime/Core/Public/Templates/Tuple.h +++ b/Engine/Source/Runtime/Core/Public/Templates/Tuple.h @@ -21,7 +21,7 @@ // Static analysis causes internal compiler errors with auto-deduced return types, // but some older VC versions still have return type deduction failures inside the delegate code // when they are enabled. So we currently only enable them for static analysis builds. -#if defined(_MSC_VER) +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) #define USE_TUPLE_AUTO_RETURN_TYPES (PLATFORM_COMPILER_HAS_AUTO_RETURN_TYPES && USING_CODE_ANALYSIS) #else #define USE_TUPLE_AUTO_RETURN_TYPES 1 diff --git a/Engine/Source/Runtime/Core/Public/Templates/TypeCompatibleBytes.h b/Engine/Source/Runtime/Core/Public/Templates/TypeCompatibleBytes.h index d9be550ed6d6..9e45b223eadd 100644 --- a/Engine/Source/Runtime/Core/Public/Templates/TypeCompatibleBytes.h +++ b/Engine/Source/Runtime/Core/Public/Templates/TypeCompatibleBytes.h @@ -4,7 +4,6 @@ #include "CoreTypes.h" -#include "Templates/AlignOf.h" /** * Used to declare an untyped array of data with compile-time alignment. @@ -58,6 +57,6 @@ template struct TTypeCompatibleBytes : public TAlignedBytes< sizeof(ElementType), - ALIGNOF(ElementType) + alignof(ElementType) > {}; diff --git a/Engine/Source/Runtime/Core/Public/Templates/UniquePtr.h b/Engine/Source/Runtime/Core/Public/Templates/UniquePtr.h index 26917f433f5f..e92a02b6912e 100644 --- a/Engine/Source/Runtime/Core/Public/Templates/UniquePtr.h +++ b/Engine/Source/Runtime/Core/Public/Templates/UniquePtr.h @@ -651,7 +651,7 @@ template FORCEINLINE typename TEnableIf::Value, TUniquePtr>::Type MakeUnique(SIZE_T Size) { typedef typename TRemoveExtent::Type ElementType; - return TUniquePtr(new ElementType[Size]); + return TUniquePtr(new ElementType[Size]()); } /** diff --git a/Engine/Source/Runtime/Core/Public/Templates/UnrealTemplate.h b/Engine/Source/Runtime/Core/Public/Templates/UnrealTemplate.h index 5be3d553ef1d..22af61019755 100644 --- a/Engine/Source/Runtime/Core/Public/Templates/UnrealTemplate.h +++ b/Engine/Source/Runtime/Core/Public/Templates/UnrealTemplate.h @@ -123,11 +123,16 @@ CONSTEXPR SIZE_T GetNum(std::initializer_list List) Standard macros. ----------------------------------------------------------------------------*/ -template -char (&ArrayCountHelper(const T (&)[N]))[N]; +#ifdef __clang__ + template + auto ArrayCountHelper(T& t) -> typename TEnableIf<__is_array(T), char(&)[sizeof(t) / sizeof(t[0]) + 1]>::Type; +#else + template + char (&ArrayCountHelper(const T (&)[N]))[N + 1]; +#endif // Number of elements in an array. -#define ARRAY_COUNT( array ) (sizeof(ArrayCountHelper(array))+0) +#define ARRAY_COUNT( array ) (sizeof(ArrayCountHelper(array)) - 1) // Offset of a struct member. #ifndef UNREAL_CODE_ANALYZER diff --git a/Engine/Source/Runtime/Core/Public/UObject/AnimPhysObjectVersion.h b/Engine/Source/Runtime/Core/Public/UObject/AnimPhysObjectVersion.h index 2b379bcfc853..1281b190807d 100644 --- a/Engine/Source/Runtime/Core/Public/UObject/AnimPhysObjectVersion.h +++ b/Engine/Source/Runtime/Core/Public/UObject/AnimPhysObjectVersion.h @@ -10,13 +10,17 @@ struct CORE_API FAnimPhysObjectVersion enum Type { // Before any version changes were made - BeforeCustomVersionWasAdded = 0, + BeforeCustomVersionWasAdded, // convert animnode look at to use just default axis instead of enum, which doesn't do much - ConvertAnimNodeLookAtAxis = 1, + ConvertAnimNodeLookAtAxis, // Change FKSphylElem and FKBoxElem to use Rotators not Quats for easier editing - BoxSphylElemsUseRotators = 2, + BoxSphylElemsUseRotators, // Change thumbnail scene info and asset import data to be transactional - ThumbnailSceneInfoAndAssetImportDataAreTransactional = 3, + ThumbnailSceneInfoAndAssetImportDataAreTransactional, + // Enabled clothing masks rather than painting parameters directly + AddedClothingMaskWorkflow, + // Remove UID from smart name serialize, it just breaks determinism + RemoveUIDFromSmartNameSerialize, // ------------------------------------------------------ VersionPlusOne, diff --git a/Engine/Source/Runtime/Core/Public/UObject/BlueprintsObjectVersion.h b/Engine/Source/Runtime/Core/Public/UObject/BlueprintsObjectVersion.h index 388f0cd1b369..8fd2d40dcd97 100644 --- a/Engine/Source/Runtime/Core/Public/UObject/BlueprintsObjectVersion.h +++ b/Engine/Source/Runtime/Core/Public/UObject/BlueprintsObjectVersion.h @@ -20,6 +20,7 @@ struct CORE_API FBlueprintsObjectVersion SCSHasComponentTemplateClass, ComponentTemplateClassSupport, ArrayGetFuncsReplacedByCustomNode, + DisallowObjectConfigVars, // ------------------------------------------------------ VersionPlusOne, diff --git a/Engine/Source/Runtime/Core/Public/UObject/FrameworkObjectVersion.h b/Engine/Source/Runtime/Core/Public/UObject/FrameworkObjectVersion.h index 47a779ddb1f9..9de641d4deab 100644 --- a/Engine/Source/Runtime/Core/Public/UObject/FrameworkObjectVersion.h +++ b/Engine/Source/Runtime/Core/Public/UObject/FrameworkObjectVersion.h @@ -85,6 +85,21 @@ struct CORE_API FFrameworkObjectVersion // Serialize hard references to sound files when possible HardSoundReferences, + // Enforce const correctness in Animation Blueprint function graphs + EnforceConstInAnimBlueprintFunctionGraphs, + + // Upgrade the InputKeySelector to use a text style + InputKeySelectorTextStyle, + + // Represent a pins container type as an enum not 3 independent booleans + EdGraphPinContainerType, + + // Switch asset pins to store as string instead of hard object reference + ChangeAssetPinsToString, + + // Fix Local Variables so that the properties are correctly flagged as blueprint visible + LocalVariablesBlueprintVisible, + // ------------------------------------------------------ VersionPlusOne, LatestVersion = VersionPlusOne - 1 diff --git a/Engine/Source/Runtime/Core/Public/UObject/NameTypes.h b/Engine/Source/Runtime/Core/Public/UObject/NameTypes.h index 1cfd1f6f7660..fae12a61aa42 100644 --- a/Engine/Source/Runtime/Core/Public/UObject/NameTypes.h +++ b/Engine/Source/Runtime/Core/Public/UObject/NameTypes.h @@ -26,6 +26,8 @@ #define WITH_CASE_PRESERVING_NAME WITH_EDITORONLY_DATA #endif +class FText; + /** Maximum size of name. */ enum {NAME_SIZE = 1024}; @@ -59,8 +61,8 @@ typedef int32 NAME_INDEX; /** These characters cannot be used in object names */ #define INVALID_OBJECTNAME_CHARACTERS TEXT("\"' ,/.:|&!~\n\r\t@#(){}[]=;^%$`") -/** These characters cannot be used in textboxes which take group names (i.e. Group1.Group2) */ -#define INVALID_GROUPNAME_CHARACTERS TEXT("\"' ,/:|&!~\n\r\t@#") +/** These characters cannot be used in ObjectPaths, which includes both the package path and part after the first . */ +#define INVALID_OBJECTPATH_CHARACTERS TEXT("\"' ,|&!~\n\r\t@#(){}[]=;^%$`") /** These characters cannot be used in long package names */ #define INVALID_LONGPACKAGE_CHARACTERS TEXT("\\:*?\"<>|' ,.&!~\n\r\t@#") @@ -351,7 +353,9 @@ class TStaticIndirectArrayThreadSafeRead { int32 ChunkIndex = Index / ElementsPerChunk; int32 WithinChunkIndex = Index % ElementsPerChunk; - check(IsValidIndex(Index) && ChunkIndex < NumChunks && Index < MaxTotalElements); + checkf(IsValidIndex(Index), TEXT("IsValidIndex(%d)"), Index); + checkf(ChunkIndex < NumChunks, TEXT("ChunkIndex (%d) < NumChunks (%d)"), ChunkIndex, NumChunks); + checkf(Index < MaxTotalElements, TEXT("Index (%d) < MaxTotalElements (%d)"), Index, MaxTotalElements); ElementType** Chunk = Chunks[ChunkIndex]; check(Chunk); return Chunk + WithinChunkIndex; @@ -664,7 +668,7 @@ public: * * @return true if the name is valid */ - static bool IsValidXName( const FString& InName, const FString& InInvalidChars, class FText* OutReason = nullptr, const class FText* InErrorCtx = nullptr ); + static bool IsValidXName( const FString& InName, const FString& InInvalidChars, FText* OutReason = nullptr, const FText* InErrorCtx = nullptr ); /** * Checks to see that a FName follows the rules that Unreal requires. @@ -675,7 +679,7 @@ public: * * @return true if the name is valid */ - bool IsValidXName( const FString& InInvalidChars = INVALID_NAME_CHARACTERS, class FText* OutReason = nullptr, const class FText* InErrorCtx = nullptr ) const + bool IsValidXName( const FString& InInvalidChars = INVALID_NAME_CHARACTERS, FText* OutReason = nullptr, const FText* InErrorCtx = nullptr ) const { return IsValidXName(ToString(), InInvalidChars, OutReason, InErrorCtx); } @@ -688,7 +692,7 @@ public: * * @return true if the name is valid */ - bool IsValidXName( class FText& OutReason, const FString& InInvalidChars = INVALID_NAME_CHARACTERS ) const + bool IsValidXName( FText& OutReason, const FString& InInvalidChars = INVALID_NAME_CHARACTERS ) const { return IsValidXName(ToString(), InInvalidChars, &OutReason); } @@ -700,7 +704,7 @@ public: * * @return true if the name is valid */ - bool IsValidObjectName( class FText& OutReason ) const + bool IsValidObjectName( FText& OutReason ) const { return IsValidXName(ToString(), INVALID_OBJECTNAME_CHARACTERS, &OutReason); } @@ -713,7 +717,7 @@ public: * * @return true if the name is valid */ - bool IsValidGroupName( class FText& OutReason, bool bIsGroupName=false ) const + bool IsValidGroupName( FText& OutReason, bool bIsGroupName=false ) const { return IsValidXName(ToString(), INVALID_LONGPACKAGE_CHARACTERS, &OutReason); } @@ -740,6 +744,23 @@ public: */ int32 Compare( const FName& Other ) const; + /** + * Fast compares name to passed in one using indexes. Sort is allocation order ascending. + * + * @param Other Name to compare this against + * @return < 0 is this < Other, 0 if this == Other, > 0 if this > Other + */ + FORCEINLINE int32 CompareIndexes(const FName& Other) const + { + int32 ComparisonDiff = GetComparisonIndexFast() - Other.GetComparisonIndexFast(); + + if (ComparisonDiff == 0) + { + return GetNumber() - Other.GetNumber(); + } + return ComparisonDiff; + } + /** * Create an FName with a hardcoded string index. * @@ -1179,3 +1200,11 @@ inline bool operator!=(const CharType *LHS, const FName &RHS) template <> struct TIsPODType { enum { Value = true }; }; +/** Sort predicate to sort FName by index instead of alphabetically, pass to anything that wants TLess */ +struct FNameSortIndexes +{ + FORCEINLINE bool operator()(const FName& A, const FName& B) const + { + return A.CompareIndexes(B) < 0; + } +}; \ No newline at end of file diff --git a/Engine/Source/Runtime/Core/Public/UObject/PropertyPortFlags.h b/Engine/Source/Runtime/Core/Public/UObject/PropertyPortFlags.h index 957b20268148..dbddda3000ee 100644 --- a/Engine/Source/Runtime/Core/Public/UObject/PropertyPortFlags.h +++ b/Engine/Source/Runtime/Core/Public/UObject/PropertyPortFlags.h @@ -11,11 +11,10 @@ // Property exporting flags. enum EPropertyPortFlags { - /** No special property exporint flags */ + /** No special property exporting flags */ PPF_None = 0x00000000, - /** Indicates that property data should be treated as text */ - PPF_Localized = 0x00000001, + // = 0x00000001, /** Indicates that property data should be wrapped in quotes (for some types of properties) */ PPF_Delimited = 0x00000002, @@ -27,7 +26,7 @@ enum EPropertyPortFlags PPF_AttemptNonQualifiedSearch = 0x00000010, - /** Indicates that importing values for config or localized properties is disallowed */ + /** Indicates that importing values for config properties is disallowed */ PPF_RestrictImportTypes = 0x00000020, // = 0x00000040, @@ -101,4 +100,7 @@ enum EPropertyPortFlags /** Ignores CPF_SkipSerialization flag when using tagged serialization */ PPF_ForceTaggedSerialization = 0x20000000, -}; \ No newline at end of file + + /** Set when duplicating objects verbatim (doesn't reset unique IDs) */ + PPF_DuplicateVerbatim = 0x40000000, +}; diff --git a/Engine/Source/Runtime/Core/Public/UObject/ReleaseObjectVersion.h b/Engine/Source/Runtime/Core/Public/UObject/ReleaseObjectVersion.h index 79cda6b82726..47e4a289f562 100644 --- a/Engine/Source/Runtime/Core/Public/UObject/ReleaseObjectVersion.h +++ b/Engine/Source/Runtime/Core/Public/UObject/ReleaseObjectVersion.h @@ -34,6 +34,12 @@ struct CORE_API FReleaseObjectVersion // Adding mesh section info data for existing billboard LOD models SpeedTreeBillboardSectionInfoFixup, + // Change FMovieSceneEventParameters::StructType to be a string asset reference from a TWeakObjectPtr + EventSectionParameterStringAssetRef, + + // Remove serialized irradiance map data from skylight. + SkyLightRemoveMobileIrradianceMap, + // ------------------------------------------------------ VersionPlusOne, LatestVersion = VersionPlusOne - 1 diff --git a/Engine/Source/Runtime/Core/Public/UObject/RenderingObjectVersion.h b/Engine/Source/Runtime/Core/Public/UObject/RenderingObjectVersion.h index 27689c1e0472..f164b349f5d4 100644 --- a/Engine/Source/Runtime/Core/Public/UObject/RenderingObjectVersion.h +++ b/Engine/Source/Runtime/Core/Public/UObject/RenderingObjectVersion.h @@ -49,6 +49,13 @@ struct CORE_API FRenderingObjectVersion ShaderResourceCodeSharing, + MotionBlurAndTAASupportInSceneCapture2d, + + AddedTextureRenderTargetFormats, + + // Triggers a rebuild of the mesh UV density while also adding an update in the postedit + FixedMeshUVDensity, + // ------------------------------------------------------ VersionPlusOne, LatestVersion = VersionPlusOne - 1 diff --git a/Engine/Source/Runtime/Core/Public/Windows/MinimalWindowsApi.h b/Engine/Source/Runtime/Core/Public/Windows/MinimalWindowsApi.h index 246f63009f99..624ed77b0974 100644 --- a/Engine/Source/Runtime/Core/Public/Windows/MinimalWindowsApi.h +++ b/Engine/Source/Runtime/Core/Public/Windows/MinimalWindowsApi.h @@ -72,6 +72,13 @@ namespace Windows typedef _OVERLAPPED* LPOVERLAPPED; typedef _LARGE_INTEGER* LPLARGE_INTEGER; + typedef struct _RTL_SRWLOCK + { + void* Ptr; + } RTL_SRWLOCK, *PRTL_SRWLOCK; + + typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK; + // Modules extern "C" __declspec(dllimport) HMODULE WINAPI LoadLibraryW(LPCTSTR lpFileName); extern "C" __declspec(dllimport) BOOL WINAPI FreeLibrary(HMODULE hModule); @@ -85,6 +92,12 @@ namespace Windows extern "C" __declspec(dllimport) void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection); extern "C" __declspec(dllimport) void WINAPI DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection); + extern "C" __declspec(dllimport) void WINAPI InitializeSRWLock(PSRWLOCK SRWLock); + extern "C" __declspec(dllimport) void WINAPI AcquireSRWLockShared(PSRWLOCK SRWLock); + extern "C" __declspec(dllimport) void WINAPI ReleaseSRWLockShared(PSRWLOCK SRWLock); + extern "C" __declspec(dllimport) void WINAPI AcquireSRWLockExclusive(PSRWLOCK SRWLock); + extern "C" __declspec(dllimport) void WINAPI ReleaseSRWLockExclusive(PSRWLOCK SRWLock); + // I/O extern "C" __declspec(dllimport) BOOL WINAPI ConnectNamedPipe(HANDLE hNamedPipe, LPOVERLAPPED lpOverlapped); extern "C" __declspec(dllimport) BOOL WINAPI GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped, LPDWORD lpNumberOfBytesTransferred, BOOL bWait); diff --git a/Engine/Source/Runtime/Core/Public/Windows/WIndowsPlatform.h b/Engine/Source/Runtime/Core/Public/Windows/WIndowsPlatform.h index c563f01b4e28..a13120207ff5 100644 --- a/Engine/Source/Runtime/Core/Public/Windows/WIndowsPlatform.h +++ b/Engine/Source/Runtime/Core/Public/Windows/WIndowsPlatform.h @@ -71,8 +71,6 @@ typedef FWindowsPlatformTypes FPlatformTypes; #define PLATFORM_SUPPORTS_STACK_SYMBOLS 1 -// Intrinsics for 64-bit atomics on Windows platform requires Windows Vista or higher (WINVER>=0x0600) -#define PLATFORM_HAS_64BIT_ATOMICS (WINVER >= 0x600) // Intrinsics for 128-bit atomics on Windows platform requires Windows 8 or higher (WINVER>=0x0602) // http://msdn.microsoft.com/en-us/library/windows/desktop/hh972640.aspx #define PLATFORM_HAS_128BIT_ATOMICS (!HACK_HEADER_GENERATOR && PLATFORM_64BITS && (WINVER >= 0x602)) diff --git a/Engine/Source/Runtime/Core/Public/Windows/WindowsApplication.h b/Engine/Source/Runtime/Core/Public/Windows/WindowsApplication.h index 3ffa4fd406ee..e7edbca6ab91 100644 --- a/Engine/Source/Runtime/Core/Public/Windows/WindowsApplication.h +++ b/Engine/Source/Runtime/Core/Public/Windows/WindowsApplication.h @@ -355,7 +355,6 @@ public: virtual FModifierKeysState GetModifierKeys() const override; virtual bool IsCursorDirectlyOverSlateWindow() const override; virtual FPlatformRect GetWorkArea( const FPlatformRect& CurrentWindow ) const override; - virtual bool TryCalculatePopupWindowPosition( const FPlatformRect& InAnchor, const FVector2D& InSize, const EPopUpOrientation::Type Orientation, /*OUT*/ FVector2D* const CalculatedPopUpPosition ) const override; virtual void GetInitialDisplayMetrics( FDisplayMetrics& OutDisplayMetrics ) const override; virtual EWindowTitleAlignment::Type GetWindowTitleAlignment() const override; virtual EWindowTransparency GetWindowTransparencySupport() const override; diff --git a/Engine/Source/Runtime/Core/Public/Windows/WindowsCriticalSection.h b/Engine/Source/Runtime/Core/Public/Windows/WindowsCriticalSection.h index 5d758fccccb6..4d45c4bb1d19 100644 --- a/Engine/Source/Runtime/Core/Public/Windows/WindowsCriticalSection.h +++ b/Engine/Source/Runtime/Core/Public/Windows/WindowsCriticalSection.h @@ -106,5 +106,47 @@ private: Windows::HANDLE Mutex; }; +/** + * FWindowsRWLock - Read/Write Mutex + * - Provides non-recursive Read/Write (or shared-exclusive) access. + * - Windows specific lock structures/calls Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/aa904937(v=vs.85).aspx + */ +class FWindowsRWLock +{ +public: + FORCEINLINE FWindowsRWLock(uint32 Level = 0) + { + Windows::InitializeSRWLock(&Mutex); + } + + FORCEINLINE ~FWindowsRWLock() + { + } + + FORCEINLINE void ReadLock() + { + Windows::AcquireSRWLockShared(&Mutex); + } + + FORCEINLINE void WriteLock() + { + Windows::AcquireSRWLockExclusive(&Mutex); + } + + FORCEINLINE void ReadUnlock() + { + Windows::ReleaseSRWLockShared(&Mutex); + } + + FORCEINLINE void WriteUnlock() + { + Windows::ReleaseSRWLockExclusive(&Mutex); + } + +private: + Windows::SRWLOCK Mutex; +}; + typedef FWindowsCriticalSection FCriticalSection; typedef FWindowsSystemWideCriticalSection FSystemWideCriticalSection; +typedef FWindowsRWLock FRWLock; diff --git a/Engine/Source/Runtime/Core/Public/Windows/WindowsPlatformAtomics.h b/Engine/Source/Runtime/Core/Public/Windows/WindowsPlatformAtomics.h index 40fad1f2eb93..e269daa8e747 100644 --- a/Engine/Source/Runtime/Core/Public/Windows/WindowsPlatformAtomics.h +++ b/Engine/Source/Runtime/Core/Public/Windows/WindowsPlatformAtomics.h @@ -90,7 +90,6 @@ struct CORE_API FWindowsPlatformAtomics return (int32)::_InterlockedExchange((long*)Value, (long)Exchange); } -#if PLATFORM_HAS_64BIT_ATOMICS static FORCEINLINE int64 InterlockedExchange( volatile int64* Value, int64 Exchange ) { #if PLATFORM_64BITS @@ -107,7 +106,6 @@ struct CORE_API FWindowsPlatformAtomics } #endif } -#endif static FORCEINLINE void* InterlockedExchangePtr( void** Dest, void* Exchange ) { @@ -142,6 +140,11 @@ struct CORE_API FWindowsPlatformAtomics return (int64)::_InterlockedCompareExchange64(Dest, Exchange, Comparand); } + static FORCEINLINE int64 AtomicRead64(volatile const int64* Src) + { + return InterlockedCompareExchange((volatile int64*)Src, 0, 0); + } + #endif /** @@ -170,6 +173,18 @@ struct CORE_API FWindowsPlatformAtomics return ::InterlockedCompareExchange128((int64 volatile *)Dest, Exchange.High, Exchange.Low, (int64*)Comparand) == 1; } + /** + * Atomic read of 128 bit value with a memory barrier + */ + static FORCEINLINE void AtomicRead128(const volatile FInt128* Src, FInt128* OutResult) + { + FInt128 Zero; + Zero.High = 0; + Zero.Low = 0; + *OutResult = Zero; + InterlockedCompareExchange128((volatile FInt128*)Src, Zero, OutResult); + } + #endif // PLATFORM_HAS_128BIT_ATOMICS static FORCEINLINE void* InterlockedCompareExchangePointer( void** Dest, void* Exchange, void* Comparand ) @@ -209,4 +224,5 @@ protected: }; + typedef FWindowsPlatformAtomics FPlatformAtomics; diff --git a/Engine/Source/Runtime/Core/Public/Windows/WindowsPlatformCodeAnalysis.h b/Engine/Source/Runtime/Core/Public/Windows/WindowsPlatformCodeAnalysis.h index a9036a4a589b..e26feb0a674b 100644 --- a/Engine/Source/Runtime/Core/Public/Windows/WindowsPlatformCodeAnalysis.h +++ b/Engine/Source/Runtime/Core/Public/Windows/WindowsPlatformCodeAnalysis.h @@ -95,9 +95,13 @@ #pragma warning(disable : 6320) // warning C6320: Exception-filter expression is the constant EXCEPTION_EXECUTE_HANDLER. This might mask exceptions that were not intended to be handled. //PVS-Studio settings: - //-V::505,668,677,688,690,703,704,720 + //-V::505,542,581,601,668,677,686,688,690,703,704,711,719,720,728,730,735,751 //-V:TRYCOMPRESSION:519,547 - //-V:check(:501,547,560 + //-V:check(:501,547,560,605 + //-V:checkf(:510 + //-V:dtAssert(:568 + //-V:rcAssert(:568 + //-V:GET_FUNCTION_NAME_CHECKED:521 //-V:ENABLE_TEXT_ERROR_CHECKING_RESULTS:560 //-V:ENABLE_LOC_TESTING:560,617 //-V:WITH_EDITOR:560 @@ -106,13 +110,17 @@ //-V:%n:609 //-V:UE_BUILD_SHIPPING:501 //-V:WITH_EDITOR:501 + //-V:TestTrueExpr:501 //-V:PLATFORM_:517,547 //-V:ensureMsgf:562 - //-V:WindowsMinorVersion:547 + //-V:WindowsMinorVersion:547 + //-V:Import.XObject:547,560 + //-V:MotionControllerComponent:547,560 //-V:AddUninitialized(sizeof(void*)/:514 //-V:TestTrue:678 //-V:SetViewTarget:678 //-V:Slot:607 + //-V:RESIDENCY_CHECK_RESULT:607 //-V:bHitTesting:581 //-V:OptionalType:580 //-V:GetNextNode:681 @@ -125,17 +133,32 @@ //-V:bIsRealTime:560 //-V:Position:519 //-V:DynamicParameterValue[ParameterIndex]:557 + //-V:ViewIndex:557 + //-V:DeviceIndex:557 //-V:Interpolation:560 //-V:storePortals:560 //-V:bDefaultShouldBeMaximized:560 //-V:bAllowPerfHUD:560 //-V:bUseClientStorage:560 + //-V:bCalculateThisMapping:560 + //-V:bDebugSelectedTaskOnly:560 + //-V:bDebugSelectedTaskOnly:560 + //-V:bIsPreview:560 + //-V:bSupportsFastClear:560 + //-V:bUseAPILibaries:560 + //-V:bUseCachedBlobs:560 + //-V:bWireframe:560 + //-V:Num():560 + //-V:PLATFORM_MAC:560 //-V:Particle->Size.Z:570 //-V:ComponentMaskParameter:601 + //-V:Format(:601 //-V:SelectedEmitter:519 //-V:MAX_VERTS_PER_POLY:512 //-V:127:547 //-V:0x7F:547 + //-V:WARN_COLOR:547 + //-V:<<:614 //-V:FT_LOAD_TARGET_NORMAL:616 //-V:OPENGL_PERFORMANCE_DATA_INVALID:564 //-V:HLSLCC_VersionMajor:616 @@ -159,18 +182,47 @@ //-V:bTryPerTrackBitwiseCompression:581 //-V:DataStripped:581 //-V:FromInt:601 - //-V:UE_CLOG(:501 - //-V:UE_LOG(:501 + //-V:UE_CLOG(:501,560 + //-V:UE_LOG(:501, 560 //-V:UGL_REQUIRED_VOID:501 //-V:ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER:601 //-V:AnimScriptInstance:595 //-V:Driver:595 //-V:PSceneAsync->lockWrite:595 //-V:Context.World():595 + //-V:UNIT_LOG:595 + //-V:ensure(:595 //-V:ALLOCATE_VERTEX_DATA_TEMPLATE:501 //-V:UGL_REQUIRED:501 //-V:DEBUG_LOG_HTTP:523 //-V:GIsEditor:560 //-V:bHasEditorToken:560 + //-V:GEventDrivenLoaderEnabled:501 + //-V:WALK_TO_CHARACTER:519 + //-V:IMPLEMENT_AI_INSTANT_TEST:773 + //-V:ENABLE_VERIFY_GL:564 + //-V:INC_MEMORY_STAT_BY:568 + //-V:DEC_MEMORY_STAT_BY:568 + //-V:Key():568 + //-V:Modify:762 + //-V:GetTransitionList:762 + //-V:Execute:768 + //-V:LAUNCHERSERVICES_SHAREABLEPROJECTPATHS:768 + //-V:SELECT_STATIC_MESH_VERTEX_TYPE:622 + //-V:GET_FUNCTION_NAME_CHECKED:685 + //-V:This(:678 + //-V:state->error:649 + //-V:ProjModifiers:616 + //-V:PERF_DETAILED_PER_CLASS_GC_STATS:686 + //-V:FMath:656 + //-V:->*:607 + //-V:GENERATED_UCLASS_BODY:764 + //-V:CalcSegmentCostOnPoly:764 + //-V:DrawLine:764 + //-V:vrapi_SubmitFrame:641 + //-V:VertexData:773 + //-V:Linker:678 + //-V:self:678 + //-V:AccumulateParentID:678 #endif diff --git a/Engine/Source/Runtime/Core/Public/Windows/WindowsPlatformCompilerPreSetup.h b/Engine/Source/Runtime/Core/Public/Windows/WindowsPlatformCompilerPreSetup.h index a90e782ed88d..0fc413c2fa08 100644 --- a/Engine/Source/Runtime/Core/Public/Windows/WindowsPlatformCompilerPreSetup.h +++ b/Engine/Source/Runtime/Core/Public/Windows/WindowsPlatformCompilerPreSetup.h @@ -76,6 +76,17 @@ _Pragma("clang diagnostic pop") #endif // PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS + #ifndef PRAGMA_DISABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS + #define PRAGMA_DISABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wdelete-non-virtual-dtor\"") + #endif // PRAGMA_DISABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS + + #ifndef PRAGMA_ENABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS + #define PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS \ + _Pragma("clang diagnostic pop") + #endif // PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS + #ifndef PRAGMA_POP #define PRAGMA_POP \ _Pragma("clang diagnostic pop") @@ -126,6 +137,17 @@ __pragma(warning(pop)) #endif // PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS + #ifndef PRAGMA_DISABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS + #define PRAGMA_DISABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS \ + __pragma(warning(push)) \ + __pragma(warning(disable:4265)) + #endif // PRAGMA_DISABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS + + #ifndef PRAGMA_ENABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS + #define PRAGMA_ENABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS \ + __pragma(warning(pop)) + #endif // PRAGMA_ENABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS + #ifndef PRAGMA_POP #define PRAGMA_POP \ __pragma(warning(pop)) @@ -141,8 +163,10 @@ __pragma(warning(disable: 4996)) /* '' was declared deprecated. */ \ __pragma(warning(disable: 6011)) /* Dereferencing NULL pointer ''. */ \ __pragma(warning(disable: 6101)) /* Returning uninitialized memory ''. A successful path through the function does not set the named _Out_ parameter. */ \ + __pragma(warning(disable: 6287)) /* Redundant code: the left and right sub-expressions are identical. */ \ __pragma(warning(disable: 6308)) /* 'realloc' might return null pointer: assigning null pointer to 'X', which is passed as an argument to 'realloc', will cause the original memory block to be leaked. */ \ __pragma(warning(disable: 6326)) /* Potential comparison of a constant with another constant. */ \ + __pragma(warning(disable: 6340)) /* Mismatch on sign: Incorrect type passed as parameter in call to function. */ \ __pragma(warning(disable: 6385)) /* Reading invalid data from '': the readable size is '' bytes, but '' bytes may be read. */ \ __pragma(warning(disable: 6386)) /* Buffer overrun while writing to '': the writable size is '' bytes, but '' bytes might be written. */ \ __pragma(warning(disable: 28182)) /* Dereferencing NULL pointer. '' contains the same NULL value as '' did. */ \ @@ -150,11 +174,13 @@ __pragma(warning(disable: 28252)) /* Inconsistent annotation for '': return/function has '' on the prior instance. */ \ __pragma(warning(disable: 28253)) /* Inconsistent annotation for '': _Param_() has '' on the prior instance. */ \ PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS \ - PRAGMA_DISABLE_SHADOW_VARIABLE_WARNINGS + PRAGMA_DISABLE_SHADOW_VARIABLE_WARNINGS \ + PRAGMA_DISABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS #endif #ifndef THIRD_PARTY_INCLUDES_END #define THIRD_PARTY_INCLUDES_END \ + PRAGMA_ENABLE_MISSING_VIRTUAL_DESTRUCTOR_WARNINGS \ PRAGMA_ENABLE_SHADOW_VARIABLE_WARNINGS \ PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS \ __pragma(warning(pop)) diff --git a/Engine/Source/Runtime/Core/Public/Windows/WindowsPlatformCompilerSetup.h b/Engine/Source/Runtime/Core/Public/Windows/WindowsPlatformCompilerSetup.h index 0161da460156..8ae368c1f486 100644 --- a/Engine/Source/Runtime/Core/Public/Windows/WindowsPlatformCompilerSetup.h +++ b/Engine/Source/Runtime/Core/Public/Windows/WindowsPlatformCompilerSetup.h @@ -6,8 +6,6 @@ #error PLATFORM_WINDOWS not defined #endif -/** Unreal Code Analyzer runs clang on Windows. */ -#ifndef UNREAL_CODE_ANALYZER /** * Future-proofing the min version check so we keep bumping it whenever we upgrade. */ @@ -16,10 +14,10 @@ #endif /** - * We require at least Visual Studio 2013 to compile + * We require at least Visual Studio 2015 Update 3 to compile */ -static_assert(_MSC_VER >= 1800, "Visual Studio 2013 or later is required to compile on Windows platform"); -#endif // UNREAL_CODE_ANALYZER +static_assert(_MSC_VER != 1900 || _MSC_FULL_VER >= 190024210, "Visual Studio 2015 Update 3 is required to compile on Windows (http://go.microsoft.com/fwlink/?LinkId=691129)"); +static_assert(_MSC_VER >= 1900, "Visual Studio 2015 or later is required to compile on Windows"); #pragma warning (error: 4001 4002 4003 4004 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099) #pragma warning (error: 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199) @@ -188,7 +186,7 @@ static_assert(_MSC_VER >= 1800, "Visual Studio 2013 or later is required to comp #endif // interesting ones to turn on and off at times -//#pragma warning(disable : 4265) // 'class' : class has virtual functions, but destructor is not virtual +#pragma warning(3 : 4265) // 'class' : class has virtual functions, but destructor is not virtual //#pragma warning(disable : 4266) // '' : no override available for virtual member function from base ''; function is hidden //#pragma warning(disable : 4296) // 'operator' : expression is always true / false //#pragma warning(disable : 4820) // 'bytes' bytes padding added after member 'member' diff --git a/Engine/Source/Runtime/Core/Public/Windows/WindowsPlatformMisc.h b/Engine/Source/Runtime/Core/Public/Windows/WindowsPlatformMisc.h index 32ed04ee4e64..e5f676bc1cbe 100644 --- a/Engine/Source/Runtime/Core/Public/Windows/WindowsPlatformMisc.h +++ b/Engine/Source/Runtime/Core/Public/Windows/WindowsPlatformMisc.h @@ -24,6 +24,7 @@ struct FWindowsOSVersionHelper }; static int32 GetOSVersions( FString& out_OSVersion, FString& out_OSSubVersion ); + static FString GetOSVersion(); }; @@ -204,6 +205,7 @@ struct CORE_API FWindowsPlatformMisc static FString GetPrimaryGPUBrand(); static struct FGPUDriverInfo GetGPUDriverInfo(const FString& DeviceDescription); static void GetOSVersions( FString& out_OSVersionLabel, FString& out_OSSubVersionLabel ); + static FString GetOSVersion(); static bool GetDiskTotalAndFreeSpace( const FString& InPath, uint64& TotalNumberOfBytes, uint64& NumberOfFreeBytes ); /** @@ -259,6 +261,15 @@ struct CORE_API FWindowsPlatformMisc /** @return Get the name of the platform specific file manager (Explorer) */ static FText GetFileManagerName(); + /** + * Returns whether WiFi connection is currently active + */ + static bool HasActiveWiFiConnection() + { + // for now return true + return true; + } + /** * Returns whether the platform is running on battery power or not. */ diff --git a/Engine/Source/Runtime/Core/Public/iOS/IOSCriticalSection.h b/Engine/Source/Runtime/Core/Public/iOS/IOSCriticalSection.h index 1e973c3e4491..02cacdf72a3b 100644 --- a/Engine/Source/Runtime/Core/Public/iOS/IOSCriticalSection.h +++ b/Engine/Source/Runtime/Core/Public/iOS/IOSCriticalSection.h @@ -4,6 +4,8 @@ #include "GenericPlatform/GenericPlatformCriticalSection.h" #include "PThreadCriticalSection.h" +#include "PThreadRWLock.h" typedef FPThreadsCriticalSection FCriticalSection; typedef FSystemWideCriticalSectionNotImplemented FSystemWideCriticalSection; +typedef FPThreadsRWLock FRWLock; diff --git a/Engine/Source/Runtime/Core/Public/iOS/IOSMallocZone.h b/Engine/Source/Runtime/Core/Public/iOS/IOSMallocZone.h new file mode 100644 index 000000000000..92f7410de9ce --- /dev/null +++ b/Engine/Source/Runtime/Core/Public/iOS/IOSMallocZone.h @@ -0,0 +1,68 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "MemoryBase.h" + +typedef struct _malloc_zone_t malloc_zone_t; +struct FIOSCrashContext; + +/* + * A malloc interface using a unique malloc zone + */ +class FIOSMallocZone : public FMalloc +{ +public: + FIOSMallocZone( uint64 const InitialSize ); + virtual ~FIOSMallocZone(); + + // FMalloc interface. + virtual void* Malloc( SIZE_T Size, uint32 Alignment ) override; + + virtual void* Realloc( void* Ptr, SIZE_T NewSize, uint32 Alignment ) override; + + virtual void Free( void* Ptr ) override; + + virtual bool GetAllocationSize(void *Original, SIZE_T &SizeOut) override; + + virtual bool IsInternallyThreadSafe() const override; + + virtual bool ValidateHeap() override; + + virtual const TCHAR* GetDescriptiveName() override; + +protected: + malloc_zone_t* MemoryZone; +}; + +/* + * Specific FIOSMallocZone for the crash handler malloc override so that we avoid malloc reentrancy problems + */ +class FIOSMallocCrashHandler : public FIOSMallocZone +{ +public: + FIOSMallocCrashHandler( uint64 const InitialSize ); + + virtual ~FIOSMallocCrashHandler(); + + void Enable( FIOSCrashContext* Context, uint32 CrashedThreadId ); + + // FMalloc interface. + virtual void* Malloc( SIZE_T Size, uint32 Alignment ) override; + + virtual void* Realloc( void* Ptr, SIZE_T NewSize, uint32 Alignment ) override; + + virtual void Free( void* Ptr ) override; + + virtual bool GetAllocationSize( void *Original, SIZE_T &SizeOut ) override; + + virtual const TCHAR* GetDescriptiveName() override; + +private: + bool IsOnCrashedThread(void); + +private: + FMalloc* OriginalHeap; + FIOSCrashContext* CrashContext; + int32 ThreadId; +}; diff --git a/Engine/Source/Runtime/Core/Public/iOS/IOSPlatformCrashContext.h b/Engine/Source/Runtime/Core/Public/iOS/IOSPlatformCrashContext.h new file mode 100644 index 000000000000..e6108a886992 --- /dev/null +++ b/Engine/Source/Runtime/Core/Public/iOS/IOSPlatformCrashContext.h @@ -0,0 +1,25 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "Apple/ApplePlatformCrashContext.h" + +struct CORE_API FIOSCrashContext : public FApplePlatformCrashContext +{ + /** Mimics Windows WER format */ + void GenerateWindowsErrorReport(char const* WERPath, bool bIsEnsure = false) const; + + /** Copies the PLCrashReporter minidump */ + void CopyMinidump(char const* OutputPath, char const* InputPath) const; + + /** Generates the ensure/crash info into the given folder */ + void GenerateInfoInFolder(char const* const InfoFolder, bool bIsEnsure = false) const; + + /** Generates information for crash reporter */ + void GenerateCrashInfo() const; + + /** Generates information for ensures sent via the CrashReporter */ + void GenerateEnsureInfo() const; +}; + +typedef FIOSCrashContext FPlatformCrashContext; diff --git a/Engine/Source/Runtime/CoreUObject/Private/Blueprint/BlueprintSupport.cpp b/Engine/Source/Runtime/CoreUObject/Private/Blueprint/BlueprintSupport.cpp index 461f87825178..c34a04b961b3 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/Blueprint/BlueprintSupport.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/Blueprint/BlueprintSupport.cpp @@ -319,7 +319,7 @@ FScopedClassDependencyGather::~FScopedClassDependencyGather() { // If this gatherer was the initial gatherer for the current scope, process // dependencies (unless compiling on load is explicitly disabled) - if( bMasterClass && !GForceDisableBlueprintCompileOnLoad ) + if( bMasterClass ) { auto DependencyIter = BatchClassDependencies.CreateIterator(); // implemented as a lambda, to prevent duplicated code between @@ -1135,7 +1135,7 @@ void FLinkerLoad::ResolveDeferredDependencies(UStruct* LoadStruct) { uint32 InternalLoadFlags = LoadFlags & (LOAD_NoVerify | LOAD_NoWarn | LOAD_Quiet); // make sure LoadAllObjects() is called for this package - LoadPackageInternal(/*Outer =*/nullptr, *SourceLinker->Filename, InternalLoadFlags, this); + LoadPackageInternal(/*Outer =*/nullptr, *SourceLinker->Filename, InternalLoadFlags, this); //-V595 } if (ULinkerPlaceholderClass* PlaceholderClass = Cast(Import.XObject)) @@ -1474,6 +1474,17 @@ void FLinkerLoad::FinalizeBlueprint(UClass* LoadClass) // we need it ran for any super-classes before we regen ResolveAllImports(); + // Now that imports have been resolved we optionally flush the compilation + // queue. This is only done for level blueprints, which will have instances + // of actors in them that cannot reliably be reinstanced on load (see useage + // of Scene pointers in things like UActorComponent::ExecuteRegisterEvents) + // - on load the Scene may not yet be created, meaning this code cannot + // correctly be run. We could address that, but avoiding reinstancings is + // also a performance win: +#if WITH_EDITOR + LoadClass->FlushCompilationQueueForLevel(); +#endif + // interfaces can invalidate classes which implement them (when the // interface is regenerated), they essentially define the makeup of the // implementing class; so here, like we do with the parent class above, we diff --git a/Engine/Source/Runtime/CoreUObject/Private/CoreUObjectPrivatePCH.h b/Engine/Source/Runtime/CoreUObject/Private/CoreUObjectPrivatePCH.h index f2f104d41605..36c8e46af037 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/CoreUObjectPrivatePCH.h +++ b/Engine/Source/Runtime/CoreUObject/Private/CoreUObjectPrivatePCH.h @@ -41,7 +41,6 @@ #include "Templates/EnableIf.h" #include "Templates/RemoveReference.h" #include "Templates/TypeCompatibleBytes.h" -#include "Templates/AlignOf.h" #include "Templates/ChooseClass.h" #include "Templates/IntegralConstant.h" #include "Templates/IsClass.h" diff --git a/Engine/Source/Runtime/CoreUObject/Private/Internationalization/PackageLocalizationCache.cpp b/Engine/Source/Runtime/CoreUObject/Private/Internationalization/PackageLocalizationCache.cpp index 071109a54652..75cfc1816d9a 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/Internationalization/PackageLocalizationCache.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/Internationalization/PackageLocalizationCache.cpp @@ -310,13 +310,13 @@ void FPackageLocalizationCache::ConditionalUpdatePackageNameToAssetGroupCache_No return; } - bPackageNameToAssetGroupDirty = false; - PackageNameToAssetGroup.Reset(); for (const auto& AssetClassGroupPair : AssetClassesToAssetGroups) { FindAssetGroupPackages(AssetClassGroupPair.Value, AssetClassGroupPair.Key); } + + bPackageNameToAssetGroupDirty = false; } void FPackageLocalizationCache::HandleContentPathMounted(const FString& InAssetPath, const FString& InFilesystemPath) diff --git a/Engine/Source/Runtime/CoreUObject/Private/Misc/ExclusiveLoadPackageTimeTracker.cpp b/Engine/Source/Runtime/CoreUObject/Private/Misc/ExclusiveLoadPackageTimeTracker.cpp index 974c972e4a23..5334c2f93629 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/Misc/ExclusiveLoadPackageTimeTracker.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/Misc/ExclusiveLoadPackageTimeTracker.cpp @@ -17,6 +17,10 @@ FExclusiveLoadPackageTimeTracker::FExclusiveLoadPackageTimeTracker() TEXT("LoadTimes.DumpReport"), *LOCTEXT("CommandText_DumpReport", "Dumps a report about the amount of time spent loading assets").ToString(), FConsoleCommandWithArgsDelegate::CreateRaw(this, &FExclusiveLoadPackageTimeTracker::DumpReportCommandHandler)) + , ResetReportCommand( + TEXT("LoadTimes.Reset"), + *LOCTEXT("CommandText_ResetReport", "Resets accumulated report data").ToString(), + FConsoleCommandWithArgsDelegate::CreateRaw(this, &FExclusiveLoadPackageTimeTracker::ResetReportCommandHandler)) { } @@ -223,6 +227,13 @@ void FExclusiveLoadPackageTimeTracker::InternalDumpReport() const } } +void FExclusiveLoadPackageTimeTracker::InternalResetReport() +{ + FScopeLock Lock(&TimesCritical); + LoadTimes.Reset(); + TimeStack.Reset(); +} + double FExclusiveLoadPackageTimeTracker::InternalGetExclusiveLoadTime(FName PackageName) const { FScopeLock Lock(&TimesCritical); @@ -257,6 +268,12 @@ void FExclusiveLoadPackageTimeTracker::DumpReportCommandHandler(const TArray& Args) +{ + ResetReport(); +} + + #undef LOCTEXT_NAMESPACE #endif //WITH_LOADPACKAGE_TIME_TRACKER diff --git a/Engine/Source/Runtime/CoreUObject/Private/Misc/PackageName.cpp b/Engine/Source/Runtime/CoreUObject/Private/Misc/PackageName.cpp index 1061266590a2..11aeada94ee2 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/Misc/PackageName.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/Misc/PackageName.cpp @@ -18,6 +18,7 @@ #include "Interfaces/IPluginManager.h" #include "Internationalization/PackageLocalizationManager.h" #include "HAL/ThreadHeartBeat.h" +#include "Misc/AutomationTest.h" DEFINE_LOG_CATEGORY_STATIC(LogPackageName, Log, All); @@ -285,6 +286,16 @@ FString FPackageName::InternalFilenameToLongPackageName(const FString& InFilenam if (!bIsValidLongPackageName) { Filename = IFileManager::Get().ConvertToRelativePath(*Filename); + if (InFilename.Len() > 0 && InFilename[InFilename.Len() - 1] == '/') + { + // If InFilename ends in / but converted doesn't, add the / back + bool bEndsInSlash = Filename.Len() > 0 && Filename[Filename.Len() - 1] == '/'; + + if (!bEndsInSlash) + { + Filename += TEXT("/"); + } + } } FString PackageName = FPaths::GetBaseFilename(Filename); @@ -309,9 +320,10 @@ bool FPackageName::TryConvertFilenameToLongPackageName(const FString& InFilename FString LongPackageName = InternalFilenameToLongPackageName(InFilename); // we don't support loading packages from outside of well defined places - const bool bContainsDot = LongPackageName.Contains(TEXT("."), ESearchCase::CaseSensitive); - const bool bContainsBackslash = LongPackageName.Contains(TEXT("\\"), ESearchCase::CaseSensitive); - const bool bContainsColon = LongPackageName.Contains(TEXT(":"), ESearchCase::CaseSensitive); + int32 CharacterIndex; + const bool bContainsDot = LongPackageName.FindChar(TEXT('.'), CharacterIndex); + const bool bContainsBackslash = LongPackageName.FindChar(TEXT('\\'), CharacterIndex); + const bool bContainsColon = LongPackageName.FindChar(TEXT(':'), CharacterIndex); const bool bResult = !(bContainsDot || bContainsBackslash || bContainsColon); if (bResult) @@ -446,16 +458,7 @@ bool FPackageName::SplitLongPackageName(const FString& InLongPackageName, FStrin FString FPackageName::GetLongPackageAssetName(const FString& InLongPackageName) { - int32 IndexOfLastSlash = INDEX_NONE; - if (InLongPackageName.FindLastChar('/', IndexOfLastSlash)) - { - return InLongPackageName.Mid(IndexOfLastSlash + 1); - } - else - { - return InLongPackageName; - } - + return GetShortName(InLongPackageName); } bool FPackageName::DoesPackageNameContainInvalidCharacters(const FString& InLongPackageName, FText* OutReason /*= NULL*/) @@ -477,7 +480,7 @@ bool FPackageName::DoesPackageNameContainInvalidCharacters(const FString& InLong { FFormatNamedArguments Args; Args.Add( TEXT("IllegalNameCharacters"), FText::FromString(MatchedInvalidChars) ); - *OutReason = FText::Format( NSLOCTEXT("Core", "PackageNameContainsInvalidCharacters", "Name may not contain the following characters: {IllegalNameCharacters}"), Args ); + *OutReason = FText::Format( NSLOCTEXT("Core", "PackageNameContainsInvalidCharacters", "Name may not contain the following characters: '{IllegalNameCharacters}'"), Args ); } return true; } @@ -565,6 +568,70 @@ bool FPackageName::IsValidLongPackageName(const FString& InLongPackageName, bool return bValidRoot; } +bool FPackageName::IsValidObjectPath(const FString& InObjectPath, FText* OutReason) +{ + FString PackageName; + FString RemainingObjectPath; + + // Check for package delimiter + int32 ObjectDelimiterIdx; + if (InObjectPath.FindChar('.', ObjectDelimiterIdx)) + { + if (ObjectDelimiterIdx == InObjectPath.Len() - 1) + { + if (OutReason) + { + *OutReason = NSLOCTEXT("Core", "ObjectPath_EndWithPeriod", "Object Path may not end with ."); + } + return false; + } + + PackageName = InObjectPath.Mid(0, ObjectDelimiterIdx); + RemainingObjectPath = InObjectPath.Mid(ObjectDelimiterIdx + 1); + } + else + { + PackageName = InObjectPath; + } + + if (!IsValidLongPackageName(PackageName, true, OutReason)) + { + return false; + } + + if (RemainingObjectPath.Len() > 0) + { + FText PathContext = NSLOCTEXT("Core", "ObjectPathContext", "Object Path"); + if (!FName::IsValidXName(RemainingObjectPath, INVALID_OBJECTPATH_CHARACTERS, OutReason, &PathContext)) + { + return false; + } + + TCHAR LastChar = RemainingObjectPath[RemainingObjectPath.Len() - 1]; + if (LastChar == '.' || LastChar == ':') + { + if (OutReason) + { + *OutReason = NSLOCTEXT("Core", "ObjectPath_PathWithTrailingSeperator", "Object Path may not end with : or ."); + } + return false; + } + + int32 SlashIndex; + if (RemainingObjectPath.FindChar('/', SlashIndex)) + { + if (OutReason) + { + *OutReason = NSLOCTEXT("Core", "ObjectPath_SlashAfterPeriod", "Object Path may not have / after first ."); + } + + return false; + } + } + + return true; +} + void FPackageName::RegisterMountPoint(const FString& RootPath, const FString& ContentPath) { FLongPackagePathsSingleton& Paths = FLongPackagePathsSingleton::Get(); @@ -659,6 +726,75 @@ bool FPackageName::FindPackageFileWithoutExtension(const FString& InPackageFilen return false; } +bool FPackageName::FixPackageNameCase(FString& LongPackageName, const FString& Extension) +{ + // Visitor which corrects the case of a filename against any matching item in a directory + struct FFixCaseVisitor : public IPlatformFile::FDirectoryVisitor + { + FString Name; + + FFixCaseVisitor(const FString&& InName) : Name(InName) + { + } + + virtual bool Visit(const TCHAR* FilenameOrDirectory, bool bIsDirectory) override + { + if (Name == FilenameOrDirectory) + { + Name = FilenameOrDirectory; + return false; + } + return true; + } + }; + + // Find the matching long package root + const FLongPackagePathsSingleton& Paths = FLongPackagePathsSingleton::Get(); + for (const FPathPair& Pair : Paths.ContentRootToPath) + { + if (LongPackageName.StartsWith(Pair.RootPath)) + { + // Construct a visitor with this mount point + FFixCaseVisitor Visitor(Pair.ContentPath.Left(Pair.ContentPath.Len() - 1)); + + // Normalize the extension to begin with a dot + FString DotExtension = Extension; + if (DotExtension.Len() > 0 && DotExtension[0] != '.') + { + DotExtension.InsertAt(0, '.'); + } + + // Iterate through each directory trying to match a file with the correct name + int32 BaseIdx = Pair.RootPath.Len(); + for (;;) + { + int32 NextIdx = LongPackageName.Find(TEXT("/"), ESearchCase::IgnoreCase, ESearchDir::FromStart, BaseIdx); + if(NextIdx == INDEX_NONE) + { + FString BaseDir = Visitor.Name; + Visitor.Name /= LongPackageName.Mid(BaseIdx) + DotExtension; + IFileManager::Get().IterateDirectory(*BaseDir, Visitor); + break; + } + else + { + FString BaseDir = Visitor.Name; + Visitor.Name /= LongPackageName.Mid(BaseIdx, NextIdx - BaseIdx); + IFileManager::Get().IterateDirectory(*BaseDir, Visitor); + } + BaseIdx = NextIdx + 1; + } + + // Construct the new long package name, and check it matches the original in all but case + FString NewLongPackageName = Pair.RootPath / Visitor.Name.Mid(Pair.ContentPath.Len(), Visitor.Name.Len() - DotExtension.Len() - Pair.ContentPath.Len()); + check(LongPackageName == NewLongPackageName); + LongPackageName = MoveTemp(NewLongPackageName); + return true; + } + } + return false; +} + bool FPackageName::DoesPackageExist(const FString& LongPackageName, const FGuid* Guid /*= NULL*/, FString* OutFilename /*= NULL*/) { bool bFoundFile = false; @@ -925,6 +1061,63 @@ FString FPackageName::GetDelegateResolvedPackagePath(const FString& InSourcePack return InSourcePackagePath; } +FString FPackageName::GetSourcePackagePath(const FString& InLocalizedPackagePath) +{ + // This function finds the start and end point of the "/L10N/" part of the path so that it can be removed + auto GetL10NTrimRange = [](const FString& InPath, int32& OutL10NStart, int32& OutL10NLength) + { + const TCHAR* CurChar = *InPath; + + // Must start with a slash + if (*CurChar++ != TEXT('/')) + { + return false; + } + + // Find the end of the first part of the path, eg /Game/ + while (*CurChar && *CurChar++ != TEXT('/')) {} + if (!*CurChar) + { + // Found end-of-string + return false; + } + + if (FCString::Strnicmp(CurChar, TEXT("L10N/"), 5) == 0) // StartsWith "L10N/" + { + CurChar -= 1; // -1 because we need to eat the slash before L10N + OutL10NStart = (CurChar - *InPath); + OutL10NLength = 6; // "/L10N/" + + // Walk to the next slash as that will be the end of the culture code + CurChar += OutL10NLength; + while (*CurChar && *CurChar++ != TEXT('/')) { ++OutL10NLength; } + + return true; + } + else if (FCString::Stricmp(CurChar, TEXT("L10N")) == 0) // Is "L10N" + { + CurChar -= 1; // -1 because we need to eat the slash before L10N + OutL10NStart = (CurChar - *InPath); + OutL10NLength = 5; // "/L10N" + + return true; + } + + return false; + }; + + FString SourcePackagePath = InLocalizedPackagePath; + + int32 L10NStart = INDEX_NONE; + int32 L10NLength = 0; + if (GetL10NTrimRange(SourcePackagePath, L10NStart, L10NLength)) + { + SourcePackagePath.RemoveAt(L10NStart, L10NLength); + } + + return SourcePackagePath; +} + FString FPackageName::GetLocalizedPackagePath(const FString& InSourcePackagePath) { const FName LocalizedPackageName = FPackageLocalizationManager::Get().FindLocalizedPackageName(*InSourcePackagePath); @@ -1147,3 +1340,51 @@ bool FPackageName::IsLocalizedPackage(const FString& InPackageName) return FCString::Strnicmp(CurChar, TEXT("L10N/"), 5) == 0 // StartsWith "L10N/" || FCString::Stricmp(CurChar, TEXT("L10N")) == 0; // Is "L10N" } + + +#if WITH_DEV_AUTOMATION_TESTS + +IMPLEMENT_SIMPLE_AUTOMATION_TEST(FPackageNameTests, "System.Core.Misc.PackageNames", EAutomationTestFlags::ApplicationContextMask | EAutomationTestFlags::SmokeFilter) + +bool FPackageNameTests::RunTest(const FString& Parameters) +{ + // Localized paths tests + { + auto TestIsLocalizedPackage = [&](const FString& InPath, const bool InExpected) + { + const bool bResult = FPackageName::IsLocalizedPackage(InPath); + if (bResult != InExpected) + { + AddError(FString::Printf(TEXT("Path '%s' failed FPackageName::IsLocalizedPackage (got '%d', expected '%d')."), *InPath, bResult, InExpected)); + } + }; + + TestIsLocalizedPackage(TEXT("/Game"), false); + TestIsLocalizedPackage(TEXT("/Game/MyAsset"), false); + TestIsLocalizedPackage(TEXT("/Game/L10N"), true); + TestIsLocalizedPackage(TEXT("/Game/L10N/en"), true); + TestIsLocalizedPackage(TEXT("/Game/L10N/en/MyAsset"), true); + } + + // Source path tests + { + auto TestGetSourcePackagePath = [this](const FString& InPath, const FString& InExpected) + { + const FString Result = FPackageName::GetSourcePackagePath(InPath); + if (Result != InExpected) + { + AddError(FString::Printf(TEXT("Path '%s' failed FPackageName::GetSourcePackagePath (got '%s', expected '%s')."), *InPath, *Result, *InExpected)); + } + }; + + TestGetSourcePackagePath(TEXT("/Game"), TEXT("/Game")); + TestGetSourcePackagePath(TEXT("/Game/MyAsset"), TEXT("/Game/MyAsset")); + TestGetSourcePackagePath(TEXT("/Game/L10N"), TEXT("/Game")); + TestGetSourcePackagePath(TEXT("/Game/L10N/en"), TEXT("/Game")); + TestGetSourcePackagePath(TEXT("/Game/L10N/en/MyAsset"), TEXT("/Game/MyAsset")); + } + + return true; +} + +#endif //WITH_DEV_AUTOMATION_TESTS diff --git a/Engine/Source/Runtime/CoreUObject/Private/Misc/RedirectCollector.cpp b/Engine/Source/Runtime/CoreUObject/Private/Misc/RedirectCollector.cpp index df5b6da4a2e9..102861df9a4e 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/Misc/RedirectCollector.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/Misc/RedirectCollector.cpp @@ -1,7 +1,5 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -// Core includes. #include "Misc/RedirectCollector.h" #include "Misc/CoreDelegates.h" #include "UObject/UObjectGlobals.h" @@ -13,48 +11,13 @@ #include "Misc/PackageName.h" #include "UObject/LinkerLoad.h" #include "UObject/UObjectThreadContext.h" -//#include "CookStats.h" + +#if WITH_EDITOR + DEFINE_LOG_CATEGORY_STATIC(LogRedirectors, Log, All); -static TArray StringAssetRefFilenameStack; - -void FRedirectCollector::OnRedirectorFollowed(const FString& InString, UObject* InObject) -{ - check(InObject); - - // the object had better be a redir - UObjectRedirector& Redirector = dynamic_cast(*InObject); - - // save the info if it matches the parameters we need to match on: - // if the string matches the package we were loading - // AND - // we aren't matching a particular package || the string matches the package - if (!FileToFixup.Len() || FileToFixup == FPackageName::FilenameToLongPackageName(Redirector.GetLinker()->Filename)) - { - FRedirection Redir; - Redir.PackageFilename = InString; - Redir.RedirectorName = Redirector.GetFullName(); - Redir.RedirectorPackageFilename = Redirector.GetLinker()->Filename; - Redir.DestinationObjectName = Redirector.DestinationObject->GetFullName(); - // we only want one of each redirection reported - Redirections.AddUnique(Redir); - - // and add a fake reference caused by a string redirectors - if (StringAssetRefFilenameStack.Num()) - { - Redir.PackageFilename = StringAssetRefFilenameStack[StringAssetRefFilenameStack.Num() - 1]; - UE_LOG(LogRedirectors, Verbose, TEXT("String Asset Reference fake redir %s(%s) -> %s"), *Redir.RedirectorName, *Redir.PackageFilename, *Redir.DestinationObjectName); - if (!Redir.PackageFilename.IsEmpty()) - { - Redirections.AddUnique(Redir); - } - } - } -} - void FRedirectCollector::OnStringAssetReferenceLoaded(const FString& InString) { - FUObjectThreadContext& ThreadContext = FUObjectThreadContext::Get(); FPackagePropertyPair ContainingPackageAndProperty; if (InString.IsEmpty()) @@ -63,27 +26,39 @@ void FRedirectCollector::OnStringAssetReferenceLoaded(const FString& InString) return; } - if (ThreadContext.SerializedObject) + FStringAssetReferenceThreadContext& ThreadContext = FStringAssetReferenceThreadContext::Get(); + + FName PackageName, PropertyName; + EStringAssetReferenceCollectType CollectType = EStringAssetReferenceCollectType::AlwaysCollect; + + ThreadContext.GetSerializationOptions(PackageName, PropertyName, CollectType); + + if (CollectType == EStringAssetReferenceCollectType::NeverCollect) { - FLinkerLoad* Linker = ThreadContext.SerializedObject->GetLinker(); - if (Linker) - { - ContainingPackageAndProperty.SetPackage(FName(*FPackageName::FilenameToLongPackageName(Linker->Filename))); - if (Linker->GetSerializedProperty()) - { - ContainingPackageAndProperty.SetProperty( FName(*FString::Printf(TEXT("%s:%s"), *ThreadContext.SerializedObject->GetPathName(), *Linker->GetSerializedProperty()->GetName()))); - } -#if WITH_EDITORONLY_DATA - ContainingPackageAndProperty.SetReferencedByEditorOnlyProperty( Linker->IsEditorOnlyPropertyOnTheStack() ); -#endif - } + // Do not track + return; } + + if (PackageName != NAME_None) + { + ContainingPackageAndProperty.SetPackage(PackageName); + if (PropertyName != NAME_None) + { + ContainingPackageAndProperty.SetProperty(PropertyName); + } + ContainingPackageAndProperty.SetReferencedByEditorOnlyProperty(CollectType == EStringAssetReferenceCollectType::EditorOnlyCollect); + } + + FScopeLock ScopeLock(&CriticalSection); + StringAssetReferences.AddUnique(FName(*InString), ContainingPackageAndProperty); } FString FRedirectCollector::OnStringAssetReferenceSaved(const FString& InString) { - FString* Found = StringAssetRemap.Find(InString); + FScopeLock ScopeLock(&CriticalSection); + + FString* Found = AssetPathRedirectionMap.Find(InString); if (Found) { return *Found; @@ -91,7 +66,6 @@ FString FRedirectCollector::OnStringAssetReferenceSaved(const FString& InString) return InString; } - #define REDIRECT_TIMERS 1 #if REDIRECT_TIMERS struct FRedirectScopeTimer @@ -121,15 +95,11 @@ double ResolveTimeDelegate; LOG_REDIRECT_TIMER(ResolveTimeDelegate);\ LOG_REDIRECT_TIMER(ResolveTimeTotal);\ - - - #else #define SCOPE_REDIRECT_TIMER(TimerName) #define LOG_REDIRECT_TIMERS() #endif - void FRedirectCollector::LogTimers() const { LOG_REDIRECT_TIMERS(); @@ -139,6 +109,8 @@ void FRedirectCollector::ResolveStringAssetReference(FName FilterPackageFName, b { SCOPE_REDIRECT_TIMER(ResolveTimeTotal); + FScopeLock ScopeLock(&CriticalSection); + TMultiMap SkippedReferences; SkippedReferences.Empty(StringAssetReferences.Num()); while ( StringAssetReferences.Num()) @@ -173,7 +145,6 @@ void FRedirectCollector::ResolveStringAssetReference(FName FilterPackageFName, b continue; } } -#if WITH_EDITOR if ( (bProcessAlreadyResolvedPackages == false) && AlreadyRemapped.Contains(ToLoadFName) ) { @@ -181,7 +152,6 @@ void FRedirectCollector::ResolveStringAssetReference(FName FilterPackageFName, b // once is enough for somethings. continue; } -#endif if (ToLoad.Len() > 0 ) { SCOPE_REDIRECT_TIMER(ResolveTimeLoad); @@ -189,8 +159,6 @@ void FRedirectCollector::ResolveStringAssetReference(FName FilterPackageFName, b UE_LOG(LogRedirectors, Verbose, TEXT("String Asset Reference '%s'"), *ToLoad); UE_CLOG(RefFilenameAndProperty.GetProperty().ToString().Len(), LogRedirectors, Verbose, TEXT(" Referenced by '%s'"), *RefFilenameAndProperty.GetProperty().ToString()); - StringAssetRefFilenameStack.Push(RefFilenameAndProperty.GetPackage().ToString()); - // LoadObject will mark any failed loads as "KnownMissing", so since we want to print out the referencer if it was missing and not-known-missing // then check here before attempting to load (TODO: Can we just not even do the load? Seems like we should be able to...) @@ -204,21 +172,7 @@ void FRedirectCollector::ResolveStringAssetReference(FName FilterPackageFName, b } UObject *Loaded = LoadObject(NULL, *ToLoad, NULL, RefFilenameAndProperty.GetReferencedByEditorOnlyProperty() ? LOAD_EditorOnly | LOAD_NoWarn : LOAD_NoWarn, NULL); - StringAssetRefFilenameStack.Pop(); - UObjectRedirector* Redirector = dynamic_cast(Loaded); - if (Redirector) - { - UE_LOG(LogRedirectors, Verbose, TEXT(" Found redir '%s'"), *Redirector->GetFullName()); - FRedirection Redir; - Redir.PackageFilename = RefFilenameAndProperty.GetPackage().ToString(); - Redir.RedirectorName = Redirector->GetFullName(); - Redir.RedirectorPackageFilename = Redirector->GetLinker()->Filename; - CA_SUPPRESS(28182) - Redir.DestinationObjectName = Redirector->DestinationObject->GetFullName(); - Redirections.AddUnique(Redir); - Loaded = Redirector->DestinationObject; - } if (Loaded) { if (FCoreUObjectDelegates::PackageLoadedFromStringAssetReference.IsBound()) @@ -229,11 +183,9 @@ void FRedirectCollector::ResolveStringAssetReference(FName FilterPackageFName, b UE_LOG(LogRedirectors, Verbose, TEXT(" Resolved to '%s'"), *Dest); if (Dest != ToLoad) { - StringAssetRemap.Add(ToLoad, Dest); + AssetPathRedirectionMap.Add(ToLoad, Dest); } -#if WITH_EDITOR AlreadyRemapped.Add(ToLoadFName); -#endif } else { @@ -252,37 +204,60 @@ void FRedirectCollector::ResolveStringAssetReference(FName FilterPackageFName, b check((StringAssetReferences.Num() == 0) || (FilterPackageFName != NAME_None)); } -void FRedirectCollector::GetStringAssetReferencePackageList(FName FilterPackage, TSet& ReferencedPackages) +void FRedirectCollector::ProcessStringAssetReferencePackageList(FName FilterPackage, bool bGetEditorOnly, TSet& OutReferencedPackages) { - for (const auto& CurrentReference : StringAssetReferences) + FScopeLock ScopeLock(&CriticalSection); + + // Iterate map, remove all matching and potentially add to OutReferencedPackages + for (auto It = StringAssetReferences.CreateIterator(); It; ++It) { - const FName& ToLoadFName = CurrentReference.Key; - const FPackagePropertyPair& RefFilenameAndProperty = CurrentReference.Value; + const FName& ToLoadFName = It->Key; + const FPackagePropertyPair& RefFilenameAndProperty = It->Value; // Package name may be null, if so return the set of things not associated with a package if (FilterPackage == RefFilenameAndProperty.GetCachedPackageName()) { FString PackageNameString = FPackageName::ObjectPathToPackageName(ToLoadFName.ToString()); - ReferencedPackages.Add(FName(*PackageNameString)); + if (!RefFilenameAndProperty.GetReferencedByEditorOnlyProperty() || bGetEditorOnly) + { + OutReferencedPackages.Add(FName(*PackageNameString)); + } + + It.RemoveCurrent(); } } + + StringAssetReferences.Compact(); +} + +void FRedirectCollector::AddAssetPathRedirection(const FString& OriginalPath, const FString& RedirectedPath) +{ + FScopeLock ScopeLock(&CriticalSection); + + // This replaces an existing mapping, can happen in the editor if things are renamed twice + AssetPathRedirectionMap.Add(OriginalPath, RedirectedPath); +} + +void FRedirectCollector::RemoveAssetPathRedirection(const FString& OriginalPath) +{ + FScopeLock ScopeLock(&CriticalSection); + + FString* Found = AssetPathRedirectionMap.Find(OriginalPath); + + if (ensureMsgf(Found, TEXT("Cannot remove redirection from %s, it was not registered"), *OriginalPath)) + { + AssetPathRedirectionMap.Remove(OriginalPath); + } } -void FRedirectCollector::AddStringAssetReferenceRedirection(const FString& OriginalPath, const FString& RedirectedPath) +FString* FRedirectCollector::GetAssetPathRedirection(const FString& OriginalPath) { - FString* Found = StringAssetRemap.Find(OriginalPath); + FScopeLock ScopeLock(&CriticalSection); - if (Found) - { - ensureMsgf(*Found == RedirectedPath, TEXT("Cannot remap %s to %s, it is already mapped to %s!"), *OriginalPath, *RedirectedPath, **Found); - } - else - { - StringAssetRemap.Add(OriginalPath, RedirectedPath); - } + return AssetPathRedirectionMap.Find(OriginalPath); } FRedirectCollector GRedirectCollector; - +#endif // WITH_EDITOR diff --git a/Engine/Source/Runtime/CoreUObject/Private/Misc/StringAssetReference.cpp b/Engine/Source/Runtime/CoreUObject/Private/Misc/StringAssetReference.cpp index c3abf5a48c39..bfb69495e46a 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/Misc/StringAssetReference.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/Misc/StringAssetReference.cpp @@ -5,7 +5,9 @@ #include "UObject/UnrealType.h" #include "UObject/ObjectRedirector.h" #include "Misc/PackageName.h" - +#include "UObject/LinkerLoad.h" +#include "UObject/UObjectThreadContext.h" +#include "Misc/RedirectCollector.h" FStringAssetReference::FStringAssetReference(const UObject* InObject) { @@ -15,7 +17,6 @@ FStringAssetReference::FStringAssetReference(const UObject* InObject) } } -PRAGMA_DISABLE_DEPRECATION_WARNINGS void FStringAssetReference::SetPath(FString Path) { if (Path.IsEmpty()) @@ -39,34 +40,74 @@ void FStringAssetReference::SetPath(FString Path) AssetLongPathname = MoveTemp(Path); } } -PRAGMA_POP + +void FStringAssetReference::PreSavePath() +{ +#if WITH_EDITOR + FString* FoundRedirection = GRedirectCollector.GetAssetPathRedirection(ToString()); + + if (FoundRedirection) + { + SetPath(*FoundRedirection); + } +#endif // WITH_EDITOR +} + +void FStringAssetReference::PostLoadPath() const +{ +#if WITH_EDITOR + GRedirectCollector.OnStringAssetReferenceLoaded(ToString()); +#endif // WITH_EDITOR +} bool FStringAssetReference::Serialize(FArchive& Ar) { -#if WITH_EDITOR - if (Ar.IsSaving() && Ar.IsPersistent() && FCoreUObjectDelegates::StringAssetReferenceSaving.IsBound()) - { - SetPath(FCoreUObjectDelegates::StringAssetReferenceSaving.Execute(ToString())); - } -#endif // WITH_EDITOR + // Archivers will call back into SerializePath for the various fixups Ar << *this; -#if WITH_EDITOR - if (Ar.IsLoading() && Ar.IsPersistent() && FCoreUObjectDelegates::StringAssetReferenceLoaded.IsBound()) - { - FCoreUObjectDelegates::StringAssetReferenceLoaded.Execute(ToString()); - } -#endif // WITH_EDITOR - - if (Ar.IsLoading() && (Ar.GetPortFlags()&PPF_DuplicateForPIE)) - { - // Remap unique ID if necessary - // only for fixing up cross-level references, inter-level references handled in FDuplicateDataReader - FixupForPIE(); - } return true; } +void FStringAssetReference::SerializePath(FArchive& Ar, bool bSkipSerializeIfArchiveHasSize) +{ +#if WITH_EDITOR + if (Ar.IsSaving()) + { + PreSavePath(); + } +#endif // WITH_EDITOR + + FString Path = ToString(); + + if (!bSkipSerializeIfArchiveHasSize || Ar.IsObjectReferenceCollector() || Ar.Tell() < 0) + { + Ar << Path; + } + + if (Ar.IsLoading()) + { + if (Ar.UE4Ver() < VER_UE4_KEEP_ONLY_PACKAGE_NAMES_IN_STRING_ASSET_REFERENCES_MAP) + { + Path = FPackageName::GetNormalizedObjectPath(Path); + } + + SetPath(MoveTemp(Path)); + +#if WITH_EDITOR + if (Ar.IsPersistent()) + { + PostLoadPath(); + } + if (Ar.GetPortFlags()&PPF_DuplicateForPIE) + { + // Remap unique ID if necessary + // only for fixing up cross-level references, inter-level references handled in FDuplicateDataReader + FixupForPIE(); + } +#endif // WITH_EDITOR + } +} + bool FStringAssetReference::operator==(FStringAssetReference const& Other) const { return ToString() == Other.ToString(); @@ -87,7 +128,11 @@ bool FStringAssetReference::ExportTextItem(FString& ValueStr, FStringAssetRefere if (IsValid()) { - ValueStr += ToString(); + // Fixup any redirectors + FStringAssetReference Temp = *this; + Temp.PreSavePath(); + + ValueStr += Temp.ToString(); } else { @@ -95,6 +140,7 @@ bool FStringAssetReference::ExportTextItem(FString& ValueStr, FStringAssetRefere } return true; } + bool FStringAssetReference::ImportTextItem(const TCHAR*& Buffer, int32 PortFlags, UObject* Parent, FOutputDevice* ErrorText) { FString ImportedPath = TEXT(""); @@ -112,6 +158,10 @@ bool FStringAssetReference::ImportTextItem(const TCHAR*& Buffer, int32 PortFlags { if (*Buffer == TCHAR('\'')) { + // A ' token likely means we're looking at an asset string in the form "Texture2d'/Game/UI/HUD/Actions/Barrel'" and we need to read and append the path part + // We have to skip over the first ' as UPropertyHelpers::ReadToken doesn't read single-quoted strings correctly, but does read a path correctly + Buffer++; // Skip the leading ' + ImportedPath.Reset(); NewBuffer = UPropertyHelpers::ReadToken(Buffer, ImportedPath, 1); if (!NewBuffer) { @@ -127,13 +177,8 @@ bool FStringAssetReference::ImportTextItem(const TCHAR*& Buffer, int32 PortFlags SetPath(MoveTemp(ImportedPath)); -#if WITH_EDITOR // Consider this a load, so Config string asset references get cooked - if (FCoreUObjectDelegates::StringAssetReferenceLoaded.IsBound()) - { - FCoreUObjectDelegates::StringAssetReferenceLoaded.Execute(ToString()); - } -#endif // WITH_EDITOR + PostLoadPath(); return true; } @@ -155,6 +200,7 @@ bool FStringAssetReference::SerializeFromMismatchedTag(struct FPropertyTag const if (Ar.IsLoading()) { SetPath(MoveTemp(Path)); + PostLoadPath(); } return bReturn; @@ -240,5 +286,77 @@ void FStringAssetReference::FixupForPIE() } } +bool FStringAssetReferenceThreadContext::GetSerializationOptions(FName& OutPackageName, FName& OutPropertyName, EStringAssetReferenceCollectType& OutCollectType) const +{ + FName CurrentPackageName, CurrentPropertyName; + EStringAssetReferenceCollectType CurrentCollectType = EStringAssetReferenceCollectType::AlwaysCollect; + bool bFoundAnything = false; + if (OptionStack.Num() > 0) + { + // Go from the top of the stack down + for (int32 i = OptionStack.Num() - 1; i >= 0; i--) + { + const FSerializationOptions& Options = OptionStack[i]; + // Find first valid package/property names. They may not necessarily match + if (Options.PackageName != NAME_None && CurrentPackageName == NAME_None) + { + CurrentPackageName = Options.PackageName; + } + if (Options.PropertyName != NAME_None && CurrentPropertyName == NAME_None) + { + CurrentPropertyName = Options.PropertyName; + } + + // Restrict based on lowest/most restrictive collect type + if (Options.CollectType < CurrentCollectType) + { + CurrentCollectType = Options.CollectType; + } + } + + bFoundAnything = true; + } + + // Check UObject thread context as a backup + FUObjectThreadContext& ThreadContext = FUObjectThreadContext::Get(); + if (ThreadContext.SerializedObject) + { + FLinkerLoad* Linker = ThreadContext.SerializedObject->GetLinker(); + if (Linker) + { + if (CurrentPackageName == NAME_None) + { + CurrentPackageName = FName(*FPackageName::FilenameToLongPackageName(Linker->Filename)); + } + if (Linker->GetSerializedProperty() && CurrentPropertyName == NAME_None) + { + CurrentPropertyName = Linker->GetSerializedProperty()->GetFName(); + } +#if WITH_EDITORONLY_DATA + bool bEditorOnly = Linker->IsEditorOnlyPropertyOnTheStack(); +#else + bool bEditorOnly = false; +#endif + // If we were always collect before and not overridden by stack options, set to editor only + if (bEditorOnly && CurrentCollectType == EStringAssetReferenceCollectType::AlwaysCollect) + { + CurrentCollectType = EStringAssetReferenceCollectType::EditorOnlyCollect; + } + + bFoundAnything = true; + } + } + + if (bFoundAnything) + { + OutPackageName = CurrentPackageName; + OutPropertyName = CurrentPropertyName; + OutCollectType = CurrentCollectType; + return true; + } + + return bFoundAnything; +} + FThreadSafeCounter FStringAssetReference::CurrentTag(1); TArray FStringAssetReference::PackageNamesBeingDuplicatedForPIE; diff --git a/Engine/Source/Runtime/CoreUObject/Private/Misc/StringClassReference.cpp b/Engine/Source/Runtime/CoreUObject/Private/Misc/StringClassReference.cpp index 12aceb18b187..4963f90f475e 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/Misc/StringClassReference.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/Misc/StringClassReference.cpp @@ -21,6 +21,7 @@ bool FStringClassReference::SerializeFromMismatchedTag(struct FPropertyTag const if (Ar.IsLoading()) { SetPath(MoveTemp(Path)); + PostLoadPath(); } return bReturn; diff --git a/Engine/Source/Runtime/CoreUObject/Private/Misc/StringReferenceTemplates.h b/Engine/Source/Runtime/CoreUObject/Private/Misc/StringReferenceTemplates.h index 3aea9212ef00..0227d7611509 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/Misc/StringReferenceTemplates.h +++ b/Engine/Source/Runtime/CoreUObject/Private/Misc/StringReferenceTemplates.h @@ -30,12 +30,6 @@ bool SerializeFromMismatchedTagTemplate(FString& Output, const FPropertyTag& Tag { Output = FString(); } -#if WITH_EDITOR - if (Ar.IsLoading() && Ar.IsPersistent() && FCoreUObjectDelegates::StringAssetReferenceLoaded.IsBound()) - { - FCoreUObjectDelegates::StringAssetReferenceLoaded.Execute(Output); - } -#endif // WITH_EDITOR return true; } else if (Tag.Type == NAME_StrProperty) @@ -44,12 +38,6 @@ bool SerializeFromMismatchedTagTemplate(FString& Output, const FPropertyTag& Tag Ar << String; Output = String; -#if WITH_EDITOR - if (Ar.IsLoading() && Ar.IsPersistent() && FCoreUObjectDelegates::StringAssetReferenceLoaded.IsBound()) - { - FCoreUObjectDelegates::StringAssetReferenceLoaded.Execute(Output); - } -#endif // WITH_EDITOR return true; } return false; diff --git a/Engine/Source/Runtime/CoreUObject/Private/Serialization/ArchiveUObject.cpp b/Engine/Source/Runtime/CoreUObject/Private/Serialization/ArchiveUObject.cpp index 4cf9ad710bce..d3763182552b 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/Serialization/ArchiveUObject.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/Serialization/ArchiveUObject.cpp @@ -45,8 +45,7 @@ FArchive& FArchiveUObject::operator<<(class FLazyObjectPtr& LazyObjectPtr) else #endif { - // Downcast from UObjectBase to UObject - UObject* Object = static_cast(LazyObjectPtr.Get()); + UObject* Object = LazyObjectPtr.Get(); Ar << Object; @@ -59,73 +58,34 @@ FArchive& FArchiveUObject::operator<<(class FLazyObjectPtr& LazyObjectPtr) return Ar; } -/** - * Asset pointer serialization. Asset pointers only have weak references to objects and - * won't serialize the object when gathering references for garbage collection. So in many cases, you - * don't need to bother serializing asset pointers. However, serialization is required if you - * want to load and save your object. - */ FArchive& FArchiveUObject::operator<<( class FAssetPtr& AssetPtr ) { FArchive& Ar = *this; - // We never serialize our reference while the garbage collector is harvesting references - // to objects, because we don't want weak object pointers to keep objects from being garbage - // collected. That would defeat the whole purpose of a weak object pointer! - // However, when modifying both kinds of references we want to serialize and writeback the updated value. - // We only want to write the modified value during reference fixup if the data is loaded - if( !IsObjectReferenceCollector() || IsModifyingWeakAndStrongReferences() ) + if (Ar.IsSaving() || Ar.IsLoading()) { -#if WITH_EDITORONLY_DATA - // When transacting, just serialize as a string since the object may - // not be in memory and you don't want to save a nullptr in this case. - if (IsTransacting()) - { - if (Ar.IsLoading()) - { - // Reset before serializing to clear the internal weak pointer. - AssetPtr.Reset(); - } - Ar << AssetPtr.GetUniqueID(); - } - else -#endif - { - // Downcast from UObjectBase to UObject - UObject* Object = static_cast< UObject* >( AssetPtr.Get() ); + // Reset before serializing to clear the internal weak pointer. + AssetPtr.ResetWeakPtr(); + Ar << AssetPtr.GetUniqueID(); + } + else if (!IsObjectReferenceCollector() || IsModifyingWeakAndStrongReferences()) + { + // Treat this like a weak pointer object, as we are doing something like replacing references in memory + UObject* Object = AssetPtr.Get(); - Ar << Object; + Ar << Object; - if( IsLoading() || (Object && IsModifyingWeakAndStrongReferences()) ) - { - AssetPtr = Object; - } + if (IsLoading() || (Object && IsModifyingWeakAndStrongReferences())) + { + AssetPtr = Object; } } + return Ar; } FArchive& FArchiveUObject::operator<<(struct FStringAssetReference& Value) { - FString Path = Value.ToString(); - - *this << Path; - - if (IsLoading()) - { - if (UE4Ver() < VER_UE4_KEEP_ONLY_PACKAGE_NAMES_IN_STRING_ASSET_REFERENCES_MAP) - { - FString NormalizedPath = FPackageName::GetNormalizedObjectPath(Path); - if (Value.ToString() != NormalizedPath) - { - Value.SetPath(NormalizedPath); - } - } - else - { - Value.SetPath(MoveTemp(Path)); - } - } - + Value.SerializePath(*this); return *this; } diff --git a/Engine/Source/Runtime/CoreUObject/Private/Serialization/AsyncLoading.cpp b/Engine/Source/Runtime/CoreUObject/Private/Serialization/AsyncLoading.cpp index 8c88459fe138..53e79446fc55 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/Serialization/AsyncLoading.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/Serialization/AsyncLoading.cpp @@ -37,6 +37,7 @@ #include "UniquePtr.h" #include "Serialization/BufferReader.h" #include "TaskGraphInterfaces.h" +#include "Blueprint/BlueprintSupport.h" #define FIND_MEMORY_STOMPS (1 && (PLATFORM_WINDOWS || PLATFORM_LINUX) && !WITH_EDITORONLY_DATA) @@ -157,6 +158,13 @@ static FAutoConsoleVariableRef CVar_MaxReadyRequestsToStallMB( TEXT("Controls the maximum amount memory for unhandled IO requests before we stall the pak precacher to let the CPU catch up (in megabytes).") ); +int32 GProcessPrestreamingRequests = 0; +static FAutoConsoleVariableRef CVar_ProcessPrestreamingRequests( + TEXT("s.ProcessPrestreamingRequests"), + GProcessPrestreamingRequests, + TEXT("If non-zero, then we process prestreaming requests in cooked builds.") + ); + int32 GEditorLoadPrecacheSizeKB = 0; static FAutoConsoleVariableRef CVar_EditorLoadPrecacheSizeKB( TEXT("s.EditorLoadPrecacheSizeKB"), @@ -964,7 +972,7 @@ FString FEventLoadNodePtr::HumanReadableStringForDebugging() const const TCHAR* NodeName = TEXT("Unknown"); FString Details; - FAsyncPackage* Pkg = &WaitingPackage.GetPackage(); + FAsyncPackage& Pkg = WaitingPackage.GetPackage(); if (ImportOrExportIndex.IsNull()) { switch (Phase) @@ -1012,12 +1020,8 @@ FString FEventLoadNodePtr::HumanReadableStringForDebugging() const default: check(0); } - Details = TEXT("Package or Linker Not Found"); - if (Pkg) - { - Details = Pkg->GetDebuggingPath(ImportOrExportIndex); - } + Details = Pkg.GetDebuggingPath(ImportOrExportIndex); } return FString::Printf(TEXT("%s %d %s %s"), *WaitingPackage.HumanReadableStringForDebugging().ToString(), ImportOrExportIndex.ForDebugging(), NodeName, *Details); } @@ -1935,6 +1939,7 @@ static bool IsFullyLoadedObj(UObject* Obj) return false; } +static const FName PrestreamPackageClassNameLoad = FName("PrestreamPackage"); EAsyncPackageState::Type FAsyncPackage::LoadImports_Event() { @@ -1971,6 +1976,15 @@ EAsyncPackageState::Type FAsyncPackage::LoadImports_Event() } } + bool bIsPrestreamRequest = Import->ClassName == PrestreamPackageClassNameLoad; + + if (!GProcessPrestreamingRequests && bIsPrestreamRequest) + { + UE_LOG(LogStreaming, Display, TEXT("%s is NOT prestreaming %s"), *Desc.NameToLoad.ToString(), *Import->ObjectName.ToString()); + Import->bImportFailed = true; + continue; + } + bool bForcePackageLoad = false; if (!Import->OuterIndex.IsNull() && !Import->bImportFailed) { @@ -1995,7 +2009,7 @@ EAsyncPackageState::Type FAsyncPackage::LoadImports_Event() // else don't set handled because bForcePackageLoad is false, meaning we might not set the thing anyway // @todoio: why do we need this? some UFunctions have null outer in the linker. - if (Import->ClassName != NAME_Package) + if (Import->ClassName != NAME_Package && !bIsPrestreamRequest) { check(0); continue; @@ -2029,8 +2043,8 @@ EAsyncPackageState::Type FAsyncPackage::LoadImports_Event() // This can happen with editor only classes, not sure if this should be a warning or a silent continue if (!GIsInitialLoad) { - UE_LOG(LogStreaming, Warning, TEXT("FAsyncPackage::LoadImports for %s: Skipping import %s, depends on missing native class"), *Desc.NameToLoad.ToString(), *OriginalImport->ObjectName.ToString()); - } + UE_LOG(LogStreaming, Warning, TEXT("FAsyncPackage::LoadImports for %s: Skipping import %s, depends on missing native class"), *Desc.NameToLoad.ToString(), *OriginalImport->ObjectName.ToString()); + } } else if (!ExistingPackage || bForcePackageLoad) { @@ -2040,6 +2054,10 @@ EAsyncPackageState::Type FAsyncPackage::LoadImports_Event() const FAsyncPackageDesc Info(INDEX_NONE, Import->ObjectName); PendingPackage = new FAsyncPackage(Info); PendingPackage->Desc.Priority = Desc.Priority; + if (bIsPrestreamRequest) + { + UE_LOG(LogStreaming, Display, TEXT("%s is prestreaming %s"), *Desc.NameToLoad.ToString(), *Import->ObjectName.ToString()); + } AsyncLoadingThread.InsertPackage(PendingPackage); bDidSomething = true; } @@ -2156,28 +2174,35 @@ EAsyncPackageState::Type FAsyncPackage::SetupImports_Event() if (Import.OuterIndex.IsNull()) { - UPackage* ImportPackage = Import.XObject ? CastChecked(Import.XObject) : nullptr; - if (!ImportPackage) + if (!Import.bImportFailed) { - ImportPackage = FindObjectFast(NULL, Import.ObjectName, false, false); - check(ImportPackage || FLinkerLoad::IsKnownMissingPackage(Import.ObjectName)); // We should have packages created for all imports by now - Import.XObject = ImportPackage; // this is an optimization to avoid looking up import packages multiple times, also, later we assume these are already filled in - if (Import.XObject) + UPackage* ImportPackage = Import.XObject ? CastChecked(Import.XObject) : nullptr; + if (!ImportPackage) { - AddObjectReference(Import.XObject); + ImportPackage = FindObjectFast(NULL, Import.ObjectName, false, false); + if (!ImportPackage) + { + Import.bImportFailed = true; + UE_CLOG(!FLinkerLoad::IsKnownMissingPackage(Import.ObjectName), LogStreaming, Error, TEXT("Missing native package (%s) for import of package %s"), *Import.ObjectName.ToString(), *Desc.NameToLoad.ToString()); + } + else + { + Import.XObject = ImportPackage; + AddObjectReference(Import.XObject); + } } - } - if (ImportPackage) - { - FLinkerLoad* ImportLinker = ImportPackage->LinkerLoad; - if (ImportLinker && ImportLinker->AsyncRoot) + if (ImportPackage) { - check(ImportLinker->AsyncRoot != this); - // make sure we wait for this package to serialize (and all of its dependents) before we start doing postloads - if (int32(ImportLinker->AsyncRoot->AsyncPackageLoadingState) <= int32(EAsyncPackageLoadingState::WaitingForPostLoad)) // no need to clutter dependencies with things that are already done + FLinkerLoad* ImportLinker = ImportPackage->LinkerLoad; + if (ImportLinker && ImportLinker->AsyncRoot) { - PackagesIMayBeWaitingForBeforePostload.Add(FWeakAsyncPackagePtr(ImportLinker->AsyncRoot)); + check(ImportLinker->AsyncRoot != this); + // make sure we wait for this package to serialize (and all of its dependents) before we start doing postloads + if (int32(ImportLinker->AsyncRoot->AsyncPackageLoadingState) <= int32(EAsyncPackageLoadingState::WaitingForPostLoad)) // no need to clutter dependencies with things that are already done + { + PackagesIMayBeWaitingForBeforePostload.Add(FWeakAsyncPackagePtr(ImportLinker->AsyncRoot)); + } } } } @@ -2205,10 +2230,14 @@ EAsyncPackageState::Type FAsyncPackage::SetupImports_Event() if (!ImportPackage) { ImportPackage = FindObjectFast(NULL, OuterMostImport.ObjectName, false, false); - check(ImportPackage || FLinkerLoad::IsKnownMissingPackage(OuterMostImport.ObjectName)); // We should have packages created for all imports by now - OuterMostImport.XObject = ImportPackage; // this is an optimization to avoid looking up import packages multiple times, also, later we assume these are already filled in - if (OuterMostImport.XObject) + if (!ImportPackage) { + Import.bImportFailed = true; + UE_CLOG(!FLinkerLoad::IsKnownMissingPackage(OuterMostImport.ObjectName), LogStreaming, Error, TEXT("Missing native package (%s) for import of %s in %s."), *OuterMostImport.ObjectName.ToString(), *Import.ObjectName.ToString(), *Desc.NameToLoad.ToString()); + } + else + { + OuterMostImport.XObject = ImportPackage; // this is an optimization to avoid looking up import packages multiple times, also, later we assume these are already filled in AddObjectReference(OuterMostImport.XObject); } } @@ -2222,7 +2251,6 @@ EAsyncPackageState::Type FAsyncPackage::SetupImports_Event() #if USE_EVENT_DRIVEN_ASYNC_LOAD_AT_BOOT_TIME if (GIsInitialLoad && !ImportLinker && ImportPackage->HasAnyPackageFlags(PKG_CompiledIn) && !bDynamicImport) { - check(ImportPackage->GetName().StartsWith(TEXT("/Script/"))); // sanity check though doesn't really matter; we just need to correctly identify compiled in things. // OuterMostNonPackageIndex is used here because if it is a CDO or subobject, etc, we wait for the outermost thing that is not a package bFireIfNoArcsAdded = !GetGEDLBootNotificationManager().AddWaitingPackage(this, OuterMostImport.ObjectName, Linker->Imp(OuterMostNonPackageIndex).ObjectName, FPackageIndex::FromImport(LocalImportIndex)); } @@ -2248,8 +2276,20 @@ EAsyncPackageState::Type FAsyncPackage::SetupImports_Event() check(ImportLinker->AsyncRoot != this); check(!Import.OuterIndex.IsNull()); check(Import.OuterIndex.IsImport()); - FName OuterName = Import.OuterIndex == OuterMostIndex ? NAME_None : // if the outer is the package, then that is just a null outer in the export table - Linker->Imp(Import.OuterIndex).ObjectName; + + TArray > OuterNames; + + { + FPackageIndex WorkingOuter = Import.OuterIndex; + while (WorkingOuter != OuterMostIndex) + { + check(WorkingOuter.IsImport()); + FObjectImport& WorkingImport = Linker->Imp(WorkingOuter); + OuterNames.Add(WorkingImport.ObjectName); + WorkingOuter = WorkingImport.OuterIndex; + } + } + FName OuterName = OuterNames.Num() ? OuterNames[0] : NAME_None; FPackageIndex LocalExportIndex; for (auto It = ImportLinker->AsyncRoot->ObjectNameToImportOrExport.CreateKeyIterator(Import.ObjectName); It; ++It) @@ -2258,16 +2298,26 @@ EAsyncPackageState::Type FAsyncPackage::SetupImports_Event() if (PotentialExport.IsExport()) { FObjectExport& Export = ImportLinker->Exp(PotentialExport); - // this logic might not cover all cases - bool bMatch = false; - if (Export.OuterIndex.IsNull()) + bool bMatch = true; + int32 Index = 0; + { - bMatch = OuterName == NAME_None; - } - else - { - check(Export.OuterIndex.IsExport()); - bMatch = ImportLinker->Exp(Export.OuterIndex).ObjectName == OuterName; + FPackageIndex WorkingOuter = Export.OuterIndex; + while (WorkingOuter.IsExport() && Index < OuterNames.Num()) + { + FObjectExport& WorkingExport = ImportLinker->Exp(WorkingOuter); + if (OuterNames[Index] != WorkingExport.ObjectName) + { + bMatch = false; + break; + } + Index++; + WorkingOuter = WorkingExport.OuterIndex; + } + if (Index < OuterNames.Num() || WorkingOuter.IsExport()) + { + bMatch = false; + } } if (bMatch) { @@ -2371,10 +2421,7 @@ EAsyncPackageState::Type FAsyncPackage::SetupImports_Event() { check(!Import.XObject || Import.XObject == Export.Object); Import.XObject = Export.Object; - if (Import.XObject) - { - AddObjectReference(Import.XObject); - } + AddObjectReference(Import.XObject); } if (!IsFullyLoadedObj(Export.Object)) { @@ -2725,8 +2772,12 @@ void FAsyncPackage::LinkImport(int32 LocalImportIndex) FObjectImport& OuterMostImport = Linker->Imp(OuterMostIndex); UPackage* ImportPackage = (UPackage*)OuterMostImport.XObject; // these were filled in a previous step - check(ImportPackage || FLinkerLoad::IsKnownMissingPackage(OuterMostImport.ObjectName)); // We should have packages created for all imports by now - if (ImportPackage) + if (!ImportPackage) + { + Import.bImportFailed = true; + UE_CLOG(!FLinkerLoad::IsKnownMissingPackage(OuterMostImport.ObjectName), LogStreaming, Error, TEXT("Missing native package (%s) for import of %s in %s."), *OuterMostImport.ObjectName.ToString(), *Import.ObjectName.ToString(), *Desc.NameToLoad.ToString()); + } + else { if (&OuterMostImport == &Import) { @@ -2941,7 +2992,7 @@ void FAsyncPackage::EventDrivenCreateExport(int32 LocalExportIndex) check(!Export.Object); // we should not have this yet if (!Export.Object && !Export.bExportLoadFailed) { - if (!Export.Object && !Linker->FilterExport(Export)) // for some acceptable position, it was not "not for" + if (!Linker->FilterExport(Export)) // for some acceptable position, it was not "not for" { if (Linker->GetFArchiveAsync2Loader()) { @@ -3070,10 +3121,20 @@ void FAsyncPackage::EventDrivenCreateExport(int32 LocalExportIndex) // Do this for all subobjects created in the native constructor. if (!Export.Object->HasAnyFlags(RF_LoadCompleted)) { - UE_LOG(LogStreaming, VeryVerbose, TEXT("Note2: %s was constructed during load and is an export and so needs loading."), *Export.Object->GetFullName()); - UE_CLOG(!Export.Object->HasAllFlags(RF_WillBeLoaded), LogStreaming, Fatal, TEXT("%s was found in memory and is an export but does not have all load flags."), *Export.Object->GetFullName()); - Export.Object->SetFlags(RF_NeedLoad | RF_NeedPostLoad | RF_NeedPostLoadSubobjects | RF_WasLoaded); - Export.Object->ClearFlags(RF_WillBeLoaded); + UE_LOG(LogStreaming, VeryVerbose, TEXT("Note2: %s was constructed during load and is an export and so needs loading."), *Export.Object->GetFullName()); + UE_CLOG(!Export.Object->HasAllFlags(RF_WillBeLoaded), LogStreaming, Fatal, TEXT("%s was found in memory and is an export but does not have all load flags."), *Export.Object->GetFullName()); + if(Export.Object->HasAnyFlags(RF_ClassDefaultObject)) + { + // never call PostLoadSubobjects on class default objects, this matches the behavior of the old linker where + // StaticAllocateObject prevents setting of RF_NeedPostLoad and RF_NeedPostLoadSubobjects, but FLinkerLoad::Preload + // assigns RF_NeedPostLoad for blueprint CDOs: + Export.Object->SetFlags(RF_NeedLoad | RF_NeedPostLoad | RF_WasLoaded); + } + else + { + Export.Object->SetFlags(RF_NeedLoad | RF_NeedPostLoad | RF_NeedPostLoadSubobjects | RF_WasLoaded); + } + Export.Object->ClearFlags(RF_WillBeLoaded); } } } @@ -4140,7 +4201,7 @@ EAsyncPackageState::Type FAsyncLoadingThread::ProcessAsyncLoading(int32& OutPack double TickStartTime = FPlatformTime::Seconds(); #if !UE_BUILD_SHIPPING && !UE_BUILD_TEST - FScopedRecursionNotAllowed RecursionGuard; + FScopedRecursionNotAllowed RecursionGuard; #endif if (GEventDrivenLoaderEnabled) @@ -4513,6 +4574,11 @@ EAsyncPackageState::Type FAsyncLoadingThread::ProcessLoadedPackages(bool bUseTim if (Result == EAsyncPackageState::Complete) { +#if WITH_EDITORONLY_DATA + // This needs to happen after loading new blueprints in the editor, and this is handled in EndLoad for synchronous loads + FBlueprintSupport::FlushReinstancingQueue(); +#endif + // We're not done until all packages have been deleted Result = PackagesToDelete.Num() ? EAsyncPackageState::PendingImports : EAsyncPackageState::Complete; } @@ -5134,7 +5200,7 @@ void FAsyncPackage::DetachLinker() { if (Linker) { - check(bLoadHasFinished || bLoadHasFailed); + checkf(bLoadHasFinished || bLoadHasFailed, TEXT("FAsyncPackage::DetachLinker called before load finished on package \"%s\""), *this->GetPackageName().ToString()); check(Linker->AsyncRoot == this || Linker->AsyncRoot == nullptr); Linker->AsyncRoot = nullptr; Linker = nullptr; @@ -5384,6 +5450,12 @@ EAsyncPackageState::Type FAsyncPackage::CreateLinker() { FGCScopeGuard GCGuard; Package = CreatePackage(nullptr, *Desc.Name.ToString()); + if (!Package) + { + UE_LOG(LogStreaming, Error, TEXT("Failed to create package %s requested by async loading code. NameToLoad: %s"), *Desc.Name.ToString(), *Desc.NameToLoad.ToString()); + bLoadHasFailed = true; + return EAsyncPackageState::TimeOut; + } AddObjectReference(Package); LinkerRoot = Package; } diff --git a/Engine/Source/Runtime/CoreUObject/Private/Serialization/AsyncLoadingPrivate.h b/Engine/Source/Runtime/CoreUObject/Private/Serialization/AsyncLoadingPrivate.h index 60153416f1f4..4e5017eab844 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/Serialization/AsyncLoadingPrivate.h +++ b/Engine/Source/Runtime/CoreUObject/Private/Serialization/AsyncLoadingPrivate.h @@ -23,7 +23,12 @@ public: enum { // this is used for the initial precache and should be large enough to find the actual Sum.TotalHeaderSize + // the editor packages may not have the AdditionalPackagesToCook array stripped so we need to allocate more memory +#if WITH_EDITORONLY_DATA + MAX_SUMMARY_SIZE = 16384 +#else MAX_SUMMARY_SIZE = 8192 +#endif }; FArchiveAsync2(const TCHAR* InFileName diff --git a/Engine/Source/Runtime/CoreUObject/Private/Serialization/DuplicateDataReader.cpp b/Engine/Source/Runtime/CoreUObject/Private/Serialization/DuplicateDataReader.cpp index 02fce77b5aa2..8aac5389d6d1 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/Serialization/DuplicateDataReader.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/Serialization/DuplicateDataReader.cpp @@ -30,7 +30,7 @@ FDuplicateDataReader::FDuplicateDataReader( class FUObjectAnnotationSparseIsTemplate() ) @@ -144,23 +136,11 @@ UObject* FDuplicateDataWriter::GetDuplicatedObject(UObject* Object, bool bCreate UObject* DupOuter = GetDuplicatedObject(Object->GetOuter()); if(DupOuter != nullptr) { - // First check if the duplicated outer already has an allocated duplicate of this object - Result = static_cast(FindObjectWithOuter(DupOuter, Object->GetClass(), Object->GetFName())); - - if (Result == nullptr) - { - // The object's outer is being duplicated, create a duplicate of this object. - Result = StaticConstructObject_Internal(Object->GetClass(), DupOuter, Object->GetFName(), - ApplyFlags | Object->GetMaskedFlags(FlagMask), - ApplyInternalFlags | (Object->GetInternalFlags() & InternalFlagMask), - Object->GetArchetype(), true, InstanceGraph); - } - else - { - // If we found the object then set the flags up such that it matches up with what would have been allocated - Result->SetFlags(ApplyFlags | Object->GetMaskedFlags(FlagMask)); - Result->SetInternalFlags(ApplyInternalFlags | (Object->GetInternalFlags() & InternalFlagMask)); - } + // The object's outer is being duplicated, create a duplicate of this object. + Result = StaticConstructObject_Internal(Object->GetClass(), DupOuter, Object->GetFName(), + ApplyFlags | Object->GetMaskedFlags(FlagMask), + ApplyInternalFlags | (Object->GetInternalFlags() & InternalFlagMask), + Object->GetArchetype(), true, InstanceGraph); AddDuplicate(Object, Result); } diff --git a/Engine/Source/Runtime/CoreUObject/Private/Serialization/ObjectReader.cpp b/Engine/Source/Runtime/CoreUObject/Private/Serialization/ObjectReader.cpp index 4d3f781aa149..113c30a30e50 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/Serialization/ObjectReader.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/Serialization/ObjectReader.cpp @@ -39,25 +39,13 @@ FArchive& FObjectReader::operator<<( class FLazyObjectPtr& LazyObjectPtr ) FArchive& FObjectReader::operator<<( class FAssetPtr& AssetPtr ) { - FArchive& Ar = *this; - FStringAssetReference ID; - ID.Serialize(Ar); - - AssetPtr = ID; - return Ar; + AssetPtr.ResetWeakPtr(); + return *this << AssetPtr.GetUniqueID(); } FArchive& FObjectReader::operator<<(FStringAssetReference& Value) { - FString Path = Value.ToString(); - - *this << Path; - - if (IsLoading()) - { - Value.SetPath(MoveTemp(Path)); - } - + Value.SerializePath(*this); return *this; } diff --git a/Engine/Source/Runtime/CoreUObject/Private/Serialization/ObjectWriter.cpp b/Engine/Source/Runtime/CoreUObject/Private/Serialization/ObjectWriter.cpp index 6e3864f81bd5..95c2fcf93d9d 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/Serialization/ObjectWriter.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/Serialization/ObjectWriter.cpp @@ -33,22 +33,13 @@ FArchive& FObjectWriter::operator<<( class FLazyObjectPtr& LazyObjectPtr ) FArchive& FObjectWriter::operator<<( class FAssetPtr& AssetPtr ) { - FStringAssetReference ID = AssetPtr.GetUniqueID(); - ID.Serialize(*this); - return *this; + AssetPtr.ResetWeakPtr(); + return *this << AssetPtr.GetUniqueID(); } FArchive& FObjectWriter::operator<<(FStringAssetReference& Value) { - FString Path = Value.ToString(); - - *this << Path; - - if (IsLoading()) - { - Value.SetPath(MoveTemp(Path)); - } - + Value.SerializePath(*this); return *this; } diff --git a/Engine/Source/Runtime/CoreUObject/Private/UObject/Class.cpp b/Engine/Source/Runtime/CoreUObject/Private/UObject/Class.cpp index abde86a75bc5..c1c4d8864174 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/UObject/Class.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/UObject/Class.cpp @@ -50,6 +50,10 @@ DEFINE_LOG_CATEGORY(LogClass); #endif #endif +// If we end up pushing class flags out beyond a uint32, there are various places +// casting it to uint32 that need to be fixed up (mostly printfs but also some serialization code) +static_assert(sizeof(__underlying_type(EClassFlags)) == sizeof(uint32), "expecting ClassFlags enum to fit in a uint32"); + ////////////////////////////////////////////////////////////////////////// FThreadSafeBool& InternalSafeGetTokenStreamDirtyFlag() @@ -668,32 +672,32 @@ void UStruct::Link(FArchive& Ar, bool bRelinkExistingProperties) FName ToTest = GetFName(); if ( ToTest == NAME_Matrix ) { - check(MinAlignment == ALIGNOF(FMatrix)); + check(MinAlignment == alignof(FMatrix)); check(PropertiesSize == sizeof(FMatrix)); } else if ( ToTest == NAME_Plane ) { - check(MinAlignment == ALIGNOF(FPlane)); + check(MinAlignment == alignof(FPlane)); check(PropertiesSize == sizeof(FPlane)); } else if ( ToTest == NAME_Vector4 ) { - check(MinAlignment == ALIGNOF(FVector4)); + check(MinAlignment == alignof(FVector4)); check(PropertiesSize == sizeof(FVector4)); } else if ( ToTest == NAME_Quat ) { - check(MinAlignment == ALIGNOF(FQuat)); + check(MinAlignment == alignof(FQuat)); check(PropertiesSize == sizeof(FQuat)); } else if ( ToTest == NAME_Double ) { - check(MinAlignment == ALIGNOF(double)); + check(MinAlignment == alignof(double)); check(PropertiesSize == sizeof(double)); } else if ( ToTest == NAME_Color ) { - check(MinAlignment == ALIGNOF(FColor)); + check(MinAlignment == alignof(FColor)); check(PropertiesSize == sizeof(FColor)); #if !PLATFORM_LITTLE_ENDIAN // Object.h declares FColor as BGRA which doesn't match up with what we'd like to use on @@ -2559,7 +2563,7 @@ class FRestoreClassInfo: public FRestoreForUObjectOverwrite /** Saved ClassDefaultObject **/ UObject* DefaultObject; /** Saved ClassFlags **/ - uint32 Flags; + EClassFlags Flags; /** Saved ClassCastFlags **/ EClassCastFlags CastFlags; /** Saved ClassConstructor **/ @@ -2789,7 +2793,7 @@ void UClass::DeferredRegister(UClass *UClassStaticClass,const TCHAR* PackageName // PVS-Studio justifiably complains about this cast, but we expect this to work because we 'know' that // we're coming from the UClass constructor that is used when 'statically linked'. V580 disables // a warning that indicates this is an 'odd explicit type casting'. - const TCHAR* InClassConfigName = *(TCHAR**)&ClassConfigName; //-V580 + const TCHAR* InClassConfigName = *(TCHAR**)&ClassConfigName; //-V580 //-V641 ClassConfigName = InClassConfigName; // Propagate inherited flags. @@ -3410,18 +3414,18 @@ void UClass::Serialize( FArchive& Ar ) // Class flags first. if (Ar.IsSaving()) { - auto SavedClassFlags = ClassFlags; + uint32 SavedClassFlags = ClassFlags; SavedClassFlags &= ~(CLASS_ShouldNeverBeLoaded | CLASS_TokenStreamAssembled); Ar << SavedClassFlags; } else if (Ar.IsLoading()) { - Ar << ClassFlags; + Ar << (uint32&)ClassFlags; ClassFlags &= ~(CLASS_ShouldNeverBeLoaded | CLASS_TokenStreamAssembled); } else { - Ar << ClassFlags; + Ar << (uint32&)ClassFlags; } if (Ar.UE4Ver() < VER_UE4_CLASS_NOTPLACEABLE_ADDED) { @@ -3696,7 +3700,7 @@ void UClass::PurgeClass(bool bRecompilingOnLoad) { ClassConstructor = nullptr; ClassVTableHelperCtorCaller = nullptr; - ClassFlags = 0; + ClassFlags = CLASS_None; ClassCastFlags = 0; ClassUnique = 0; ClassReps.Empty(); @@ -3794,7 +3798,7 @@ bool UClass::HasProperty(UProperty* InProperty) const UClass::UClass(const FObjectInitializer& ObjectInitializer) : UStruct( ObjectInitializer ) , ClassUnique(0) -, ClassFlags(0) +, ClassFlags(CLASS_None) , ClassCastFlags(0) , ClassWithin( UObject::StaticClass() ) , ClassGeneratedBy(nullptr) @@ -3811,7 +3815,7 @@ UClass::UClass(const FObjectInitializer& ObjectInitializer) UClass::UClass(const FObjectInitializer& ObjectInitializer, UClass* InBaseClass) : UStruct(ObjectInitializer, InBaseClass) , ClassUnique(0) -, ClassFlags(0) +, ClassFlags(CLASS_None) , ClassCastFlags(0) , ClassWithin(UObject::StaticClass()) , ClassGeneratedBy(nullptr) @@ -3849,7 +3853,7 @@ UClass::UClass EStaticConstructor, FName InName, uint32 InSize, - uint32 InClassFlags, + EClassFlags InClassFlags, EClassCastFlags InClassCastFlags, const TCHAR* InConfigName, EObjectFlags InFlags, @@ -3885,7 +3889,7 @@ UClass::UClass bool UClass::HotReloadPrivateStaticClass( uint32 InSize, - uint32 InClassFlags, + EClassFlags InClassFlags, EClassCastFlags InClassCastFlags, const TCHAR* InConfigName, ClassConstructorType InClassConstructor, @@ -4163,7 +4167,7 @@ const FString UClass::GetConfigName() const } else if( ClassConfigName == NAME_None ) { - UE_LOG(LogClass, Fatal,TEXT("UObject::GetConfigName() called on class with config name 'None'. Class flags = %d"), ClassFlags ); + UE_LOG(LogClass, Fatal,TEXT("UObject::GetConfigName() called on class with config name 'None'. Class flags = 0x%08X"), (uint32)ClassFlags ); return TEXT(""); } else @@ -4288,7 +4292,7 @@ void GetPrivateStaticClassBody( UClass*& ReturnClass, void(*RegisterNativeFunc)(), uint32 InSize, - uint32 InClassFlags, + EClassFlags InClassFlags, EClassCastFlags InClassCastFlags, const TCHAR* InConfigName, UClass::ClassConstructorType InClassConstructor, @@ -4338,7 +4342,7 @@ void GetPrivateStaticClassBody( if (!bIsDynamic) { - ReturnClass = (UClass*)GUObjectAllocator.AllocateUObject(sizeof(UClass), ALIGNOF(UClass), true); + ReturnClass = (UClass*)GUObjectAllocator.AllocateUObject(sizeof(UClass), alignof(UClass), true); ReturnClass = ::new (ReturnClass) UClass ( @@ -4357,7 +4361,7 @@ void GetPrivateStaticClassBody( } else { - ReturnClass = (UClass*)GUObjectAllocator.AllocateUObject(sizeof(UDynamicClass), ALIGNOF(UDynamicClass), GIsInitialLoad); + ReturnClass = (UClass*)GUObjectAllocator.AllocateUObject(sizeof(UDynamicClass), alignof(UDynamicClass), GIsInitialLoad); ReturnClass = ::new (ReturnClass) UDynamicClass ( @@ -4390,7 +4394,7 @@ void GetPrivateStaticClassBody( UFunction. -----------------------------------------------------------------------------*/ -UFunction::UFunction(const FObjectInitializer& ObjectInitializer, UFunction* InSuperFunction, uint32 InFunctionFlags, uint16 InRepOffset, SIZE_T ParamsSize ) +UFunction::UFunction(const FObjectInitializer& ObjectInitializer, UFunction* InSuperFunction, EFunctionFlags InFunctionFlags, uint16 InRepOffset, SIZE_T ParamsSize ) : UStruct( ObjectInitializer, InSuperFunction, ParamsSize ) , FunctionFlags(InFunctionFlags) , RepOffset(InRepOffset) @@ -4404,7 +4408,7 @@ UFunction::UFunction(const FObjectInitializer& ObjectInitializer, UFunction* InS { } -UFunction::UFunction(UFunction* InSuperFunction, uint32 InFunctionFlags, uint16 InRepOffset, SIZE_T ParamsSize) +UFunction::UFunction(UFunction* InSuperFunction, EFunctionFlags InFunctionFlags, uint16 InRepOffset, SIZE_T ParamsSize) : UStruct(InSuperFunction, ParamsSize) , FunctionFlags(InFunctionFlags) , RepOffset(InRepOffset) @@ -4822,13 +4826,13 @@ IMPLEMENT_CORE_INTRINSIC_CLASS(UFunction, UStruct, } ); -UDelegateFunction::UDelegateFunction(const FObjectInitializer& ObjectInitializer, UFunction* InSuperFunction, uint32 InFunctionFlags, uint16 InRepOffset, SIZE_T ParamsSize) +UDelegateFunction::UDelegateFunction(const FObjectInitializer& ObjectInitializer, UFunction* InSuperFunction, EFunctionFlags InFunctionFlags, uint16 InRepOffset, SIZE_T ParamsSize) : UFunction(ObjectInitializer, InSuperFunction, InFunctionFlags, InRepOffset, ParamsSize) { } -UDelegateFunction::UDelegateFunction(UFunction* InSuperFunction, uint32 InFunctionFlags, uint16 InRepOffset, SIZE_T ParamsSize) +UDelegateFunction::UDelegateFunction(UFunction* InSuperFunction, EFunctionFlags InFunctionFlags, uint16 InRepOffset, SIZE_T ParamsSize) : UFunction(InSuperFunction, InFunctionFlags, InRepOffset, ParamsSize) { @@ -4869,7 +4873,7 @@ UDynamicClass::UDynamicClass( EStaticConstructor, FName InName, uint32 InSize, - uint32 InClassFlags, + EClassFlags InClassFlags, EClassCastFlags InClassCastFlags, const TCHAR* InConfigName, EObjectFlags InFlags, diff --git a/Engine/Source/Runtime/CoreUObject/Private/UObject/CoreNative.cpp b/Engine/Source/Runtime/CoreUObject/Private/UObject/CoreNative.cpp index 33de08c908bf..33c74a941aeb 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/UObject/CoreNative.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/UObject/CoreNative.cpp @@ -45,7 +45,7 @@ IMPLEMENT_CLASS(UObject, 0); COREUOBJECT_API class UClass* Z_Construct_UClass_UObject(); UClass* Z_Construct_UClass_UObject() { - static UClass* OuterClass = NULL; + static UClass* OuterClass = nullptr; if (!OuterClass) { OuterClass = UObject::StaticClass(); @@ -63,8 +63,8 @@ UClass* Z_Construct_UClass_UObject() -----------------------------------------------------------------------------*/ FObjectInstancingGraph::FObjectInstancingGraph(bool bDisableInstancing) - : SourceRoot(NULL) - , DestinationRoot(NULL) + : SourceRoot(nullptr) + , DestinationRoot(nullptr) , bCreatingArchetype(false) , bEnableSubobjectInstancing(!bDisableInstancing) , bLoadingObject(false) @@ -72,8 +72,8 @@ FObjectInstancingGraph::FObjectInstancingGraph(bool bDisableInstancing) } FObjectInstancingGraph::FObjectInstancingGraph( UObject* DestinationSubobjectRoot ) - : SourceRoot(NULL) - , DestinationRoot(NULL) + : SourceRoot(nullptr) + , DestinationRoot(nullptr) , bCreatingArchetype(false) , bEnableSubobjectInstancing(true) , bLoadingObject(false) @@ -107,7 +107,7 @@ UObject* FObjectInstancingGraph::GetInstancedSubobject( UObject* SourceSubobject UObject* InstancedSubobject = INVALID_OBJECT; - if ( SourceSubobject != NULL && CurrentValue != NULL ) + if ( SourceSubobject != nullptr && CurrentValue != nullptr ) { bool bAllowedSelfReference = bAllowSelfReference && SourceSubobject == SourceRoot; @@ -127,7 +127,7 @@ UObject* FObjectInstancingGraph::GetInstancedSubobject( UObject* SourceSubobject { // search for the unique component instance that corresponds to this component template InstancedSubobject = GetDestinationObject(SourceSubobject); - if ( InstancedSubobject == NULL ) + if ( InstancedSubobject == nullptr ) { if (bDoNotCreateNewInstance) { @@ -177,20 +177,20 @@ UObject* FObjectInstancingGraph::GetInstancedSubobject( UObject* SourceSubobject // final archetype archetype will be the archetype of the template UObject* FinalSubobjectArchetype = CurrentValue->GetArchetype(); - // Don't seach for the existing subobjects on Blueprint-generated classes. What we'll find is a subobject + // Don't search for the existing subobjects on Blueprint-generated classes. What we'll find is a subobject // created by the constructor which may not have all of its fields initialized to the correct value (which // should be coming from a blueprint). // NOTE: Since this function is called ONLY for Blueprint-generated classes, we may as well delete this 'if'. if (!SubobjectOuter->GetClass()->HasAnyClassFlags(CLASS_CompiledFromBlueprint)) { - InstancedSubobject = StaticFindObjectFast(NULL, SubobjectOuter, SubobjectName); + InstancedSubobject = StaticFindObjectFast(nullptr, SubobjectOuter, SubobjectName); } if (InstancedSubobject && IsCreatingArchetype()) { // since we are updating an archetype, this needs to reconstruct as that is the mechanism used to copy properties // it will destroy the existing object and overwrite it - InstancedSubobject = NULL; + InstancedSubobject = nullptr; } if (!InstancedSubobject) @@ -253,16 +253,16 @@ UObject* FObjectInstancingGraph::InstancePropertyValue( class UObject* Component return NewValue; // not instancing } - // if the object we're instancing the components for (Owner) has the current component's outer in its archetype chain, and its archetype has a NULL value + // if the object we're instancing the components for (Owner) has the current component's outer in its archetype chain, and its archetype has a nullptr value // for this component property it means that the archetype didn't instance its component, so we shouldn't either. - if (ComponentTemplate == NULL && CurrentValue != NULL && (Owner && Owner->IsBasedOnArchetype(CurrentValue->GetOuter()))) + if (ComponentTemplate == nullptr && CurrentValue != nullptr && (Owner && Owner->IsBasedOnArchetype(CurrentValue->GetOuter()))) { - NewValue = NULL; + NewValue = nullptr; } else { - if ( ComponentTemplate == NULL ) + if ( ComponentTemplate == nullptr ) { // should only be here if our archetype doesn't contain this component property ComponentTemplate = CurrentValue; @@ -307,7 +307,7 @@ void FObjectInstancingGraph::AddNewInstance(UObject* ObjectInstance, UObject* In void FObjectInstancingGraph::RetrieveObjectInstances( UObject* SearchOuter, TArray& out_Objects ) { - if ( HasDestinationRoot() && SearchOuter != NULL && (SearchOuter == DestinationRoot || SearchOuter->IsIn(DestinationRoot)) ) + if ( HasDestinationRoot() && SearchOuter != nullptr && (SearchOuter == DestinationRoot || SearchOuter->IsIn(DestinationRoot)) ) { for ( TMap::TIterator It(SourceToDestinationMap); It; ++It ) { diff --git a/Engine/Source/Runtime/CoreUObject/Private/UObject/CoreNet.cpp b/Engine/Source/Runtime/CoreUObject/Private/UObject/CoreNet.cpp index db23f4ccbc2b..b353cf026191 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/UObject/CoreNet.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/UObject/CoreNet.cpp @@ -122,7 +122,7 @@ uint32 FClassNetCacheMgr::GetFunctionChecksum( const UFunction* Function, uint32 Checksum = FCrc::StrCrc32( *Function->GetName().ToLower(), Checksum ); // Evolve the checksum on function flags - Checksum = FCrc::StrCrc32( *FString::Printf( TEXT( "%u" ), Function->FunctionFlags ), Checksum ); + Checksum = FCrc::StrCrc32( *FString::Printf( TEXT( "%u" ), (uint32)Function->FunctionFlags ), Checksum ); #if 0 // This is disabled now that we have backwards compatibility for RPC parameters working in replays TArray< UProperty * > Parms; diff --git a/Engine/Source/Runtime/CoreUObject/Private/UObject/CoreRedirects.cpp b/Engine/Source/Runtime/CoreUObject/Private/UObject/CoreRedirects.cpp index 670e56474eba..54aae8dda586 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/UObject/CoreRedirects.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/UObject/CoreRedirects.cpp @@ -719,7 +719,6 @@ bool FCoreRedirects::ReadRedirectsFromIni(const FString& IniName) ConfigKeyMap.Add(TEXT("FunctionRedirects"), ECoreRedirectFlags::Type_Function); ConfigKeyMap.Add(TEXT("PropertyRedirects"), ECoreRedirectFlags::Type_Property); ConfigKeyMap.Add(TEXT("PackageRedirects"), ECoreRedirectFlags::Type_Package); - ConfigKeyMap.Add(TEXT("DelegateRedirects"), ECoreRedirectFlags::Type_Delegate); RegisterNativeRedirects(); diff --git a/Engine/Source/Runtime/CoreUObject/Private/UObject/GarbageCollection.cpp b/Engine/Source/Runtime/CoreUObject/Private/UObject/GarbageCollection.cpp index c0ded7a0e8a3..ea7bec9e420f 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/UObject/GarbageCollection.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/UObject/GarbageCollection.cpp @@ -65,7 +65,7 @@ static bool GObjCurrentPurgeObjectIndexResetPastPermanent = false; static bool GIsPurgingObject = false; /** Helpful constant for determining how many token slots we need to store a pointer **/ -static const uint32 GNumTokensPerPointer = sizeof(void*) / sizeof(uint32); +static const uint32 GNumTokensPerPointer = sizeof(void*) / sizeof(uint32); //-V514 FThreadSafeBool& FGCScopeLock::GetGarbageCollectingFlag() { @@ -94,106 +94,10 @@ bool IsGarbageCollectionLocked() return GGarbageCollectionGuardCritical.IsAsyncLocked(); } -/** - * Pool for reducing GC allocations - */ -class FGCArrayPool -{ -public: - - /** - * Gets the singleton instance of the FObjectArrayPool - * @return Pool singleton. - */ - FORCEINLINE static FGCArrayPool& Get() - { - static FGCArrayPool Singleton; - return Singleton; - } - - /** - * Gets an event from the pool or creates one if necessary. - * - * @return The array. - * @see ReturnToPool - */ - FORCEINLINE TArray* GetArrayFromPool() - { - TArray* Result = Pool.Pop(); - if (!Result) - { - Result = new TArray(); - } - check(Result); -#if UE_BUILD_DEBUG - NumberOfUsedArrays.Increment(); -#endif // UE_BUILD_DEBUG - return Result; - } - - /** - * Returns an array to the pool. - * - * @param Array The array to return. - * @see GetArrayFromPool - */ - FORCEINLINE void ReturnToPool(TArray* Array) - { -#if UE_BUILD_DEBUG - const int32 CheckUsedArrays = NumberOfUsedArrays.Decrement(); - checkSlow(CheckUsedArrays >= 0); -#endif // UE_BUILD_DEBUG - check(Array); - Array->Reset(); - Pool.Push(Array); - } - - /** Performs memory cleanup */ - void Cleanup() - { -#if UE_BUILD_DEBUG - const int32 CheckUsedArrays = NumberOfUsedArrays.GetValue(); - checkSlow(CheckUsedArrays == 0); -#endif // UE_BUILD_DEBUG - - uint32 FreedMemory = 0; - TArray< TArray* > AllArrays; - Pool.PopAll(AllArrays); - for (TArray* Array : AllArrays) - { - FreedMemory += Array->GetAllocatedSize(); - delete Array; - } - UE_LOG(LogGarbage, Log, TEXT("Freed %ub from %d GC array pools."), FreedMemory, AllArrays.Num()); - } - -#if UE_BUILD_DEBUG - void CheckLeaks() - { - // This function is called after GC has finished so at this point there should be no - // arrays used by GC and all should be returned to the pool - const int32 LeakedGCPoolArrays = NumberOfUsedArrays.GetValue(); - checkSlow(LeakedGCPoolArrays == 0); - } -#endif - -private: - - /** Holds the collection of recycled arrays. */ - TLockFreePointerListLIFO< TArray > Pool; - -#if UE_BUILD_DEBUG - /** Number of arrays currently acquired from the pool by GC */ - FThreadSafeCounter NumberOfUsedArrays; -#endif // UE_BUILD_DEBUG -}; - -void CleanupClusterArrayPools(); /** Called on shutdown to free GC memory */ void CleanupGCArrayPools() { FGCArrayPool::Get().Cleanup(); - CleanupClusterArrayPools(); } /** @@ -357,7 +261,6 @@ public: if (ReferencedMutableObjectItem->ThisThreadAtomicallyClearedRFUnreachable()) { // Needs doing because this is either a normal unclustered object (clustered objects are never unreachable) or a cluster root - ReferencedMutableObjectItem->ThisThreadAtomicallyClearedFlag(EInternalObjectFlags::NoStrongReference); ObjectsToSerialize.Add(static_cast(ReferencedMutableObjectItem->Object)); // So is this a cluster root maybe? @@ -379,7 +282,6 @@ public: // The root is also maybe unreachable so process it and all the referenced clusters if (ReferencedMutableObjectsClusterRootItem->ThisThreadAtomicallyClearedRFUnreachable()) { - ReferencedMutableObjectsClusterRootItem->ThisThreadAtomicallyClearedFlag(EInternalObjectFlags::NoStrongReference); MarkReferencedClustersAsReachable(ReferencedMutableObjectsClusterRootItem->GetClusterIndex(), ObjectsToSerialize); } } @@ -398,7 +300,7 @@ public: if (ReferencedMutableObjectItem->IsUnreachable()) { // Needs doing because this is either a normal unclustered object (clustered objects are never unreachable) or a cluster root - ReferencedMutableObjectItem->ClearFlags(EInternalObjectFlags::NoStrongReference | EInternalObjectFlags::Unreachable); + ReferencedMutableObjectItem->ClearFlags(EInternalObjectFlags::Unreachable); ObjectsToSerialize.Add(static_cast(ReferencedMutableObjectItem->Object)); // So is this a cluster root? @@ -416,7 +318,7 @@ public: FUObjectItem* ReferencedMutableObjectsClusterRootItem = GUObjectArray.IndexToObjectUnsafeForGC(ReferencedMutableObjectItem->GetOwnerIndex()); if (ReferencedMutableObjectsClusterRootItem->IsUnreachable()) { - ReferencedMutableObjectsClusterRootItem->ClearFlags(EInternalObjectFlags::NoStrongReference | EInternalObjectFlags::Unreachable); + ReferencedMutableObjectsClusterRootItem->ClearFlags(EInternalObjectFlags::Unreachable); MarkReferencedClustersAsReachable(ReferencedMutableObjectsClusterRootItem->GetClusterIndex(), ObjectsToSerialize); } } @@ -454,12 +356,12 @@ public: { if (ReferencedClusterRootObjectItem->IsUnreachable()) { - ReferencedClusterRootObjectItem->ThisThreadAtomicallyClearedFlag(EInternalObjectFlags::NoStrongReference | EInternalObjectFlags::Unreachable); + ReferencedClusterRootObjectItem->ThisThreadAtomicallyClearedFlag( EInternalObjectFlags::Unreachable); } } else { - ReferencedClusterRootObjectItem->ClearFlags(EInternalObjectFlags::NoStrongReference | EInternalObjectFlags::Unreachable); + ReferencedClusterRootObjectItem->ClearFlags(EInternalObjectFlags::Unreachable); } } else @@ -495,7 +397,7 @@ public: * @param ReferencingObject UObject which owns the reference (can be NULL) * @param bAllowReferenceElimination Whether to allow NULL'ing the reference if RF_PendingKill is set */ - FORCEINLINE void HandleObjectReference(TArray& ObjectsToSerialize, const UObject * const ReferencingObject, UObject*& Object, const bool bAllowReferenceElimination, const bool bStrongReference = true) + FORCEINLINE void HandleObjectReference(TArray& ObjectsToSerialize, const UObject * const ReferencingObject, UObject*& Object, const bool bAllowReferenceElimination) { // Disregard NULL objects and perform very fast check to see whether object is part of permanent // object pool and should therefore be disregarded. The check doesn't touch the object and is @@ -595,13 +497,8 @@ public: checkSlow(RootObjectItem->HasAnyFlags(EInternalObjectFlags::ClusterRoot)); if (bParallel) { - if (RootObjectItem->ThisThreadAtomicallyClearedRFUnreachable() || - (bStrongReference && RootObjectItem->ThisThreadAtomicallyClearedFlag(EInternalObjectFlags::NoStrongReference))) + if (RootObjectItem->ThisThreadAtomicallyClearedRFUnreachable()) { - if (bStrongReference) - { - RootObjectItem->ThisThreadAtomicallyClearedFlag(EInternalObjectFlags::NoStrongReference); - } // Make sure all referenced clusters are marked as reachable too MarkReferencedClustersAsReachable(RootObjectItem->GetClusterIndex(), ObjectsToSerialize); } @@ -609,21 +506,11 @@ public: else if (RootObjectItem->IsUnreachable()) { RootObjectItem->ClearFlags(EInternalObjectFlags::Unreachable); - if (bStrongReference) - { - RootObjectItem->ClearFlags(EInternalObjectFlags::NoStrongReference); - } // Make sure all referenced clusters are marked as reachable too MarkReferencedClustersAsReachable(RootObjectItem->GetClusterIndex(), ObjectsToSerialize); } } } - - // The second condition seems to improve perf for multithreaded GC - if (bStrongReference && ObjectItem->HasAnyFlags(EInternalObjectFlags::NoStrongReference)) - { - ObjectItem->ThisThreadAtomicallyClearedFlag(EInternalObjectFlags::NoStrongReference); - } #if PERF_DETAILED_PER_CLASS_GC_STATS GCurrentObjectRegularObjectRefs++; #endif @@ -682,17 +569,15 @@ template class FGCCollector : public FReferenceCollector { FGCReferenceProcessor& ReferenceProcessor; - TArray& ObjectArray; + FGCArrayStruct& ObjectArrayStruct; bool bAllowEliminatingReferences; - bool bShouldHandleAsWeakRef; public: - FGCCollector(FGCReferenceProcessor& InProcessor, TArray& InObjectArray) + FGCCollector(FGCReferenceProcessor& InProcessor, FGCArrayStruct& InObjectArrayStruct) : ReferenceProcessor(InProcessor) - , ObjectArray(InObjectArray) + , ObjectArrayStruct(InObjectArrayStruct) , bAllowEliminatingReferences(true) - , bShouldHandleAsWeakRef(false) { } @@ -707,7 +592,7 @@ public: ReferencingProperty ? *ReferencingProperty->GetFullName() : TEXT("NULL")); } #endif - ReferenceProcessor.HandleObjectReference(ObjectArray, const_cast(ReferencingObject), Object, bAllowEliminatingReferences, !bShouldHandleAsWeakRef); + ReferenceProcessor.HandleObjectReference(ObjectArrayStruct.ObjectsToSerialize, const_cast(ReferencingObject), Object, bAllowEliminatingReferences); } virtual void HandleObjectReference(UObject*& Object, const UObject* ReferencingObject, const UProperty* ReferencingProperty) override @@ -736,9 +621,10 @@ public: bAllowEliminatingReferences = bAllow; } - virtual void SetShouldHandleAsWeakRef(bool bWeakRef) override + virtual void MarkWeakObjectReferenceForClearing(UObject** WeakReference) override { - bShouldHandleAsWeakRef = bWeakRef; + // Track this references for later destruction if necessary. These should be relatively rare + ObjectArrayStruct.WeakReferences.Add(WeakReference); } }; @@ -901,7 +787,7 @@ public: } else { - ObjectItem->SetFlags(EInternalObjectFlags::Unreachable | EInternalObjectFlags::NoStrongReference); + ObjectItem->SetFlags(EInternalObjectFlags::Unreachable); } } } @@ -922,7 +808,7 @@ public: // if it is reachable via keep flags we will do this below (or maybe already have) if (RootObjectItem->IsUnreachable()) { - RootObjectItem->ClearFlags(EInternalObjectFlags::Unreachable | EInternalObjectFlags::NoStrongReference); + RootObjectItem->ClearFlags(EInternalObjectFlags::Unreachable); // Make sure all referenced clusters are marked as reachable too FGCReferenceProcessorSinglethreaded::MarkReferencedClustersAsReachable(RootObjectItem->GetClusterIndex(), ObjectsToSerialize); } @@ -948,7 +834,8 @@ public: DECLARE_SCOPE_CYCLE_COUNTER(TEXT("FRealtimeGC::PerformReachabilityAnalysis"), STAT_FArchiveRealtimeGC_PerformReachabilityAnalysis, STATGROUP_GC); /** Growing array of objects that require serialization */ - TArray& ObjectsToSerialize = *FGCArrayPool::Get().GetArrayFromPool(); + FGCArrayStruct* ArrayStruct = FGCArrayPool::Get().GetArrayStructFromPool(); + TArray& ObjectsToSerialize = ArrayStruct->ObjectsToSerialize; // Reset object count. GObjectCountDuringLastMarkPhase = 0; @@ -967,15 +854,15 @@ public: { FGCReferenceProcessorMultithreaded ReferenceProcessor; TFastReferenceCollector ReferenceCollector(ReferenceProcessor, FGCArrayPool::Get()); - ReferenceCollector.CollectReferences(ObjectsToSerialize); + ReferenceCollector.CollectReferences(*ArrayStruct); } else { FGCReferenceProcessorSinglethreaded ReferenceProcessor; TFastReferenceCollector ReferenceCollector(ReferenceProcessor, FGCArrayPool::Get()); - ReferenceCollector.CollectReferences(ObjectsToSerialize); + ReferenceCollector.CollectReferences(*ArrayStruct); } - FGCArrayPool::Get().ReturnToPool(&ObjectsToSerialize); + FGCArrayPool::Get().ReturnToPool(ArrayStruct); #if UE_BUILD_DEBUG FGCArrayPool::Get().CheckLeaks(); @@ -1368,7 +1255,7 @@ struct FScopedCBDProfile int32 NumPrint = 0; for (auto& Item : CBDTimings) { - UE_LOG(LogTemp, Log, TEXT(" %6d cnt %6.2fus per %6.2fms total %s"), Item.Value.Items, 1000.0f * 1000.0f * Item.Value.TotalTime / float(Item.Value.Items), 1000.0f * Item.Value.TotalTime, *Item.Key.ToString()); + UE_LOG(LogGarbage, Log, TEXT(" %6d cnt %6.2fus per %6.2fms total %s"), Item.Value.Items, 1000.0f * 1000.0f * Item.Value.TotalTime / float(Item.Value.Items), 1000.0f * Item.Value.TotalTime, *Item.Key.ToString()); if (NumPrint++ > 3000000000) { break; @@ -1518,8 +1405,8 @@ void CollectGarbageInternal(EObjectFlags KeepFlags, bool bPerformFullPurge) { const double StartTime = FPlatformTime::Seconds(); FRealtimeGC TagUsedRealtimeGC; - TagUsedRealtimeGC.PerformReachabilityAnalysis(KeepFlags, bForceSingleThreadedGC); - UE_LOG(LogGarbage, Log, TEXT("%f ms for GC"), (FPlatformTime::Seconds() - StartTime) * 1000); + TagUsedRealtimeGC.PerformReachabilityAnalysis( KeepFlags, bForceSingleThreadedGC ); + UE_LOG(LogGarbage, Log, TEXT("%f ms for GC"), (FPlatformTime::Seconds() - StartTime) * 1000 ); } // Reconstruct clusters if needed @@ -1544,6 +1431,9 @@ void CollectGarbageInternal(EObjectFlags KeepFlags, bool bPerformFullPurge) FCoreUObjectDelegates::PreGarbageCollectConditionalBeginDestroy.Broadcast(); + // This nulls all weak references to unreachable objects, and may clear the pools + FGCArrayPool::Get().ClearWeakReferences(bPerformFullPurge); + // Unhash all unreachable objects. const double StartTime = FPlatformTime::Seconds(); int32 ClustersRemoved = 0; @@ -1567,13 +1457,12 @@ void CollectGarbageInternal(EObjectFlags KeepFlags, bool bPerformFullPurge) UE_LOG(LogGarbage, Log, TEXT("Destroying cluster (%d) %s"), ObjectItem->GetClusterIndex(), *Object->GetFullName()); #endif // Nuke the entire cluster - ObjectItem->ClearFlags(EInternalObjectFlags::ClusterRoot | EInternalObjectFlags::NoStrongReference); + ObjectItem->ClearFlags(EInternalObjectFlags::ClusterRoot); const int32 ClusterRootIndex = It.GetIndex(); FUObjectCluster& Cluster = GUObjectClusters[ObjectItem->GetClusterIndex()]; for (int32 ClusterObjectIndex : Cluster.Objects) { FUObjectItem* ClusterObjectItem = GUObjectArray.IndexToObjectUnsafeForGC(ClusterObjectIndex); - ClusterObjectItem->ClearFlags(EInternalObjectFlags::NoStrongReference); ClusterObjectItem->SetOwnerIndex(0); if (!ClusterObjectItem->HasAnyFlags(EInternalObjectFlags::ReachableInCluster)) @@ -1599,22 +1488,8 @@ void CollectGarbageInternal(EObjectFlags KeepFlags, bool bPerformFullPurge) FScopedCBDProfile Profile(Object); Object->ConditionalBeginDestroy(); } - else if (ObjectItem->IsNoStrongReference()) - { - ObjectItem->ClearNoStrongReference(); - ObjectItem->SetPendingKill(); - if (ObjectItem->HasAnyFlags(EInternalObjectFlags::ClusterRoot)) - { - // If a cluster root has no strong reference then none of its object had a strong reference either, mark all as pending kill - FUObjectCluster& Cluster = GUObjectClusters[ObjectItem->GetClusterIndex()]; - for (int32 ClusterObjectIndex : Cluster.Objects) - { - FUObjectItem* ClusterObjectItem = GUObjectArray.IndexToObjectUnsafeForGC(ClusterObjectIndex); - ClusterObjectItem->SetPendingKill(); - } - } - } } + UE_LOG(LogGarbage, Log, TEXT("%f ms for unhashing unreachable objects. Clusters removed: %d. Items %d Cluster Items %d"), (FPlatformTime::Seconds() - StartTime) * 1000, ClustersRemoved, Items, ClusterItems); FCoreUObjectDelegates::PostGarbageCollectConditionalBeginDestroy.Broadcast(); } diff --git a/Engine/Source/Runtime/CoreUObject/Private/UObject/Linker.cpp b/Engine/Source/Runtime/CoreUObject/Private/UObject/Linker.cpp index bf0515de3a48..9c6e53e353b8 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/UObject/Linker.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/UObject/Linker.cpp @@ -636,6 +636,11 @@ FLinkerLoad* GetPackageLinker return nullptr; } +#if WITH_EDITORONLY_DATA + // Make sure the package name matches the name on disk + FPackageName::FixPackageNameCase(PackageNameToCreate, FPaths::GetExtension(NewFilename)); +#endif + // Create the package with the provided long package name. UPackage* FilenamePkg = (ExistingPackage ? ExistingPackage : (CreatedPackage = CreatePackage(nullptr, *PackageNameToCreate))); if (FilenamePkg && FilenamePkg != ExistingPackage && (LoadFlags & LOAD_PackageForPIE)) diff --git a/Engine/Source/Runtime/CoreUObject/Private/UObject/LinkerLoad.cpp b/Engine/Source/Runtime/CoreUObject/Private/UObject/LinkerLoad.cpp index 26bf45417d40..53ce50769a76 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/UObject/LinkerLoad.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/UObject/LinkerLoad.cpp @@ -511,16 +511,20 @@ void FLinkerLoad::PRIVATE_PatchNewObjectIntoExport(UObject* OldObject, UObject* FObjectExport& ObjExport = OldObjectLinker->ExportMap[CachedLinkerIndex]; // Detach the old object to make room for the new + const EObjectFlags OldObjectFlags = OldObject->GetFlags(); OldObject->ClearFlags(RF_NeedLoad|RF_NeedPostLoad); - OldObject->SetLinker(NULL, INDEX_NONE, true); + OldObject->SetLinker(nullptr, INDEX_NONE, true); + + // Copy flags from the old CDO. + NewObject->SetFlags(OldObjectFlags); // Move the new object into the old object's slot, so any references to this object will now reference the new NewObject->SetLinker(OldObjectLinker, CachedLinkerIndex); ObjExport.Object = NewObject; - auto& ObjLoaded = FUObjectThreadContext::Get().ObjLoaded; + TArray& ObjLoaded = FUObjectThreadContext::Get().ObjLoaded; // If the object was in the ObjLoaded queue (exported, but not yet serialized), swap out for our new object - int32 ObjLoadedIdx = ObjLoaded.Find(OldObject); + const int32 ObjLoadedIdx = ObjLoaded.Find(OldObject); if( ObjLoadedIdx != INDEX_NONE ) { ObjLoaded[ObjLoadedIdx] = NewObject; @@ -2196,9 +2200,6 @@ FLinkerLoad::EVerifyResult FLinkerLoad::VerifyImport(int32 ImportIndex) { Result = VERIFY_Redirected; - // send a callback saying we followed a redirector successfully - FCoreUObjectDelegates::RedirectorFollowed.Broadcast(Filename, Redir); - // now, fake our Import to be what the redirector pointed to Import.XObject = Redir->DestinationObject; FUObjectThreadContext::Get().ImportCount++; @@ -2254,6 +2255,20 @@ FLinkerLoad::EVerifyResult FLinkerLoad::VerifyImport(int32 ImportIndex) ); } + // Go through the depend map of the linker to find out what exports are referencing this import + const FPackageIndex ImportPackageIndex = FPackageIndex::FromImport(ImportIndex); + for (int32 CurrentExportIndex = 0; CurrentExportIndex < DependsMap.Num(); ++CurrentExportIndex) + { + const TArray& DependsList = DependsMap[CurrentExportIndex]; + if (DependsList.Contains(ImportPackageIndex)) + { + TokenizedMessage->AddToken(FTextToken::Create( + FText::Format(LOCTEXT("ImportFailureExportReference", "Referenced by export {0}"), + FText::FromName(GetExportClassName(CurrentExportIndex))))); + TokenizedMessage->AddToken(FAssetNameToken::Create(GetExportPathName(CurrentExportIndex))); + } + } + // try to get a pointer to the class of the original object so that we can display the class name of the missing resource UObject* ClassPackage = FindObject(nullptr, *Import.ClassPackage.ToString()); UClass* FindClass = ClassPackage ? FindObject(ClassPackage, *OriginalImport.ClassName.ToString()) : nullptr; @@ -2988,8 +3003,6 @@ UObject* FLinkerLoad::Create( UClass* ObjectClass, FName ObjectName, UObject* Ou // if we found what it was point to, then return it if (Redir->DestinationObject && Redir->DestinationObject->IsA(ObjectClass)) { - // send a callback saying we followed a redirector successfully - FCoreUObjectDelegates::RedirectorFollowed.Broadcast(Filename, Redir); // and return the object we are being redirected to return Redir->DestinationObject; } @@ -4220,7 +4233,7 @@ void FLinkerLoad::DetachExport( int32 i ) { const FLinkerLoad* ActualLinker = E.Object->GetLinker(); // TODO: verify the condition - const bool DynamicType = !ActualLinker && E.Object + const bool DynamicType = !ActualLinker && (E.Object->HasAnyFlags(RF_Dynamic) || (E.Object->GetClass()->HasAnyFlags(RF_Dynamic) && E.Object->HasAnyFlags(RF_ClassDefaultObject) )); if ((ActualLinker != this) && !DynamicType) diff --git a/Engine/Source/Runtime/CoreUObject/Private/UObject/LinkerPlaceholderBase.cpp b/Engine/Source/Runtime/CoreUObject/Private/UObject/LinkerPlaceholderBase.cpp index c5c1e29497f6..d45694b277d6 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/UObject/LinkerPlaceholderBase.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/UObject/LinkerPlaceholderBase.cpp @@ -356,11 +356,8 @@ bool FLinkerPlaceholderBase::AddReferencingPropertyValue(const UObjectProperty* check(PropertyChain.IsValid()); #endif // USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS - if (ReferencingContainer != nullptr) - { - ReferencingContainers.FindOrAdd(ReferencingContainer).Add(PropertyChain); - } - return (ReferencingContainer != nullptr); + ReferencingContainers.FindOrAdd(ReferencingContainer).Add(PropertyChain); + return true; } else { diff --git a/Engine/Source/Runtime/CoreUObject/Private/UObject/LinkerPlaceholderBase.h b/Engine/Source/Runtime/CoreUObject/Private/UObject/LinkerPlaceholderBase.h index 09216723b86d..290ec7f6bdad 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/UObject/LinkerPlaceholderBase.h +++ b/Engine/Source/Runtime/CoreUObject/Private/UObject/LinkerPlaceholderBase.h @@ -109,7 +109,6 @@ public: virtual UObject* GetPlaceholderAsUObject() PURE_VIRTUAL(FLinkerPlaceholderBase::GetPlaceholderAsUObject, return nullptr;) -protected: /** * Checks to see if ResolveAllPlaceholderReferences() has been called on * this placeholder. @@ -118,6 +117,7 @@ protected: */ bool IsMarkedResolved() const; +protected: /** * Flags this placeholder as resolved (so that IsMarkedResolved() and * HasBeenFullyResolved() can return true). diff --git a/Engine/Source/Runtime/CoreUObject/Private/UObject/Obj.cpp b/Engine/Source/Runtime/CoreUObject/Private/UObject/Obj.cpp index 4b7a45fd3cf1..d0cd32308867 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/UObject/Obj.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/UObject/Obj.cpp @@ -533,6 +533,12 @@ void UObject::PostEditUndo(TSharedPtr TransactionA UObject::PostEditUndo(); } + +bool UObject::IsSelectedInEditor() const +{ + return !IsPendingKill() && GSelectedObjectAnnotation.Get(this); +} + #endif // WITH_EDITOR @@ -857,14 +863,14 @@ bool UObject::ConditionalBeginDestroy() TotalTime += ThisTime; if ((++TotalCnt) % 1000 == 0) { - UE_LOG(LogTemp, Log, TEXT("ConditionalBeginDestroy %d cnt %fus"), TotalCnt, 1000.0f * 1000.0f * TotalTime / float(TotalCnt)); + UE_LOG(LogObj, Log, TEXT("ConditionalBeginDestroy %d cnt %fus"), TotalCnt, 1000.0f * 1000.0f * TotalTime / float(TotalCnt)); MyProfile.ValueSort(TLess()); int32 NumPrint = 0; for (auto& Item : MyProfile) { - UE_LOG(LogTemp, Log, TEXT(" %6d cnt %6.2fus per %6.2fms total %s"), Item.Value.Count, 1000.0f * 1000.0f * Item.Value.TotalTime / float(Item.Value.Count), 1000.0f * Item.Value.TotalTime, *Item.Key.ToString()); + UE_LOG(LogObj, Log, TEXT(" %6d cnt %6.2fus per %6.2fms total %s"), Item.Value.Count, 1000.0f * 1000.0f * Item.Value.TotalTime / float(Item.Value.Count), 1000.0f * Item.Value.TotalTime, *Item.Key.ToString()); if (NumPrint++ > 30) { break; @@ -1084,7 +1090,11 @@ bool UObject::Modify( bool bAlwaysMarkDirty/*=true*/ ) bool UObject::IsSelected() const { - return !IsPendingKill() && GSelectedAnnotation.Get(this); +#if WITH_EDITOR + return IsSelectedInEditor(); +#else + return false; +#endif } void UObject::GetPreloadDependencies(TArray& OutDeps) @@ -1558,9 +1568,9 @@ void UObject::FAssetRegistryTag::GetAssetRegistryTagsFromSearchableProperties(co // enums are alphabetical TagType = FAssetRegistryTag::TT_Alphabetical; } - else if ( Class->IsChildOf(UArrayProperty::StaticClass()) ) + else if ( Class->IsChildOf(UArrayProperty::StaticClass()) || Class->IsChildOf(UMapProperty::StaticClass()) || Class->IsChildOf(USetProperty::StaticClass()) ) { - // arrays are hidden, it is often too much information to display and sort + // arrays/maps/sets are hidden, it is often too much information to display and sort TagType = FAssetRegistryTag::TT_Hidden; } else @@ -2349,15 +2359,7 @@ void UObject::UpdateSinglePropertyInConfigFile(const UProperty* InProperty, cons const FString SectionName = Keys[0]; FString PropertyKey = InProperty->GetFName().ToString(); - - const bool bIsADefaultIniWrite = !InConfigIniName.Contains(FPaths::GameSavedDir()) - && !InConfigIniName.Contains(FPaths::EngineSavedDir()) - && (FPaths::GetBaseFilename(InConfigIniName).StartsWith(TEXT("Default")) || FPaths::GetBaseFilename(InConfigIniName).StartsWith(TEXT("User"))); - if (InProperty->GetOuter()->IsA() && bIsADefaultIniWrite) - { - PropertyKey = TEXT("+") + PropertyKey; - } - + #if WITH_EDITOR static FName ConsoleVariableFName(TEXT("ConsoleVariable")); FString CVarName = InProperty->GetMetaData(ConsoleVariableFName); @@ -3311,7 +3313,7 @@ bool StaticExec( UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar ) if (Class != NULL) { - Ar.Logf(TEXT("Listing functions introduced in class %s (class flags = %d)"), ClassName, Class->GetClassFlags()); + Ar.Logf(TEXT("Listing functions introduced in class %s (class flags = 0x%08X)"), ClassName, (uint32)Class->GetClassFlags()); for (TFieldIterator It(Class); It; ++It) { UFunction* Function = *It; @@ -4039,17 +4041,11 @@ void InitUObject() -#if WITH_EDITORONLY_DATA - const FString CommandLine = FCommandLine::Get(); - - // this is a hack to give fixup redirects insight into the startup packages - if (CommandLine.Contains(TEXT("fixupredirects")) ) - { - FCoreUObjectDelegates::RedirectorFollowed.AddRaw(&GRedirectCollector, &FRedirectCollector::OnRedirectorFollowed); - } - +#if WITH_EDITOR +PRAGMA_DISABLE_DEPRECATION_WARNINGS FCoreUObjectDelegates::StringAssetReferenceLoaded.BindRaw(&GRedirectCollector, &FRedirectCollector::OnStringAssetReferenceLoaded); FCoreUObjectDelegates::StringAssetReferenceSaving.BindRaw(&GRedirectCollector, &FRedirectCollector::OnStringAssetReferenceSaved); +PRAGMA_ENABLE_DEPRECATION_WARNINGS #endif // Object initialization. diff --git a/Engine/Source/Runtime/CoreUObject/Private/UObject/ObjectRedirector.cpp b/Engine/Source/Runtime/CoreUObject/Private/UObject/ObjectRedirector.cpp index 29a5786cd914..3cd1be8a0135 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/UObject/ObjectRedirector.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/UObject/ObjectRedirector.cpp @@ -91,48 +91,3 @@ IMPLEMENT_CORE_INTRINSIC_CLASS(UObjectRedirector, UObject, Class->EmitObjectReference(STRUCT_OFFSET(UObjectRedirector, DestinationObject), TEXT("DestinationObject")); } ); - -/** - * Constructor for the callback device, will register itself with the RedirectorFollowed delegate - * - * @param InObjectPathNameToMatch Full pathname of the object refrence that is being compiled by script - */ -FScopedRedirectorCatcher::FScopedRedirectorCatcher(const FString& InObjectPathNameToMatch) -: ObjectPathNameToMatch(InObjectPathNameToMatch) -, bWasRedirectorFollowed(false) -{ - // register itself on construction to see if the object is a redirector - FCoreUObjectDelegates::RedirectorFollowed.AddRaw(this, &FScopedRedirectorCatcher::OnRedirectorFollowed); -} - -/** - * Destructor. Will unregister the callback - */ -FScopedRedirectorCatcher::~FScopedRedirectorCatcher() -{ - // register itself on construction to see if the object is a redirector - FCoreUObjectDelegates::RedirectorFollowed.RemoveAll(this); -} - - -/** - * Responds to FCoreDelegates::RedirectorFollowed. Records all followed redirections - * so they can be cleaned later. - * - * @param InType Callback type (should only be FCoreDelegates::RedirectorFollowed) - * @param InString Name of the package that pointed to the redirect - * @param InObject The UObjectRedirector that was followed - */ -void FScopedRedirectorCatcher::OnRedirectorFollowed( const FString& InString, UObject* InObject) -{ - // this needs to be the redirector - check(dynamic_cast(InObject)); - - // if the path of the redirector was the same as the path to the object constant - // being compiled, then the script code has a text reference to a redirector, - // which will cause FixupRedirects to break the reference - if ( InObject->GetPathName() == ObjectPathNameToMatch ) - { - bWasRedirectorFollowed = true; - } -} diff --git a/Engine/Source/Runtime/CoreUObject/Private/UObject/PackageFileSummary.cpp b/Engine/Source/Runtime/CoreUObject/Private/UObject/PackageFileSummary.cpp index 3423fe6ab1e4..e53f17315753 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/UObject/PackageFileSummary.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/UObject/PackageFileSummary.cpp @@ -255,7 +255,10 @@ FArchive& operator<<( FArchive& Ar, FPackageFileSummary& Sum ) Ar << Sum.PackageSource; - Ar << Sum.AdditionalPackagesToCook; + // No longer used: List of additional packages that are needed to be cooked for this package (ie streaming levels) + // Keeping the serialization code for backwards compatibility without bumping the package version + TArray AdditionalPackagesToCook; + Ar << AdditionalPackagesToCook; if (LegacyFileVersion > -7) { diff --git a/Engine/Source/Runtime/CoreUObject/Private/UObject/Property.cpp b/Engine/Source/Runtime/CoreUObject/Private/UObject/Property.cpp index 384ecddb29d7..c3c88fbd0928 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/UObject/Property.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/UObject/Property.cpp @@ -493,9 +493,7 @@ bool UProperty::ValidateImportFlags( uint32 PortFlags, FOutputDevice* ErrorHandl // we should not allow config/localized properties to be imported here if ((PortFlags & PPF_RestrictImportTypes) && (PropertyFlags & CPF_Config)) { - FString PropertyType = (PropertyFlags & CPF_Config) ? TEXT("config") : TEXT("localized"); - - FString ErrorMsg = FString::Printf(TEXT("Import failed for '%s': property is %s (Check to see if the property is listed in the DefaultProperties. It should only be listed in the specific .ini/.int file)"), *GetName(), *PropertyType); + FString ErrorMsg = FString::Printf(TEXT("Import failed for '%s': property is config (Check to see if the property is listed in the DefaultProperties. It should only be listed in the specific .ini file)"), *GetName()); if (ErrorHandler) { @@ -1264,7 +1262,7 @@ const TCHAR* UProperty::ImportSingleProperty( const TCHAR* Str, void* DestData, Warn->Logf(ELogVerbosity::Warning, TEXT("%s"), *ImportErrors[ErrorIndex]); } } - else if ((Result == NULL && ArrayProperty == nullptr) || Result == Str) + else if (Result == Str) { Warn->Logf(ELogVerbosity::Warning, TEXT("Invalid property value in defaults: %s"), Start); } @@ -1298,7 +1296,7 @@ const TCHAR* UProperty::ImportSingleProperty( const TCHAR* Str, void* DestData, } else if ((Result == NULL && ArrayProperty == nullptr) || Result == Str) { - Warn->Logf(ELogVerbosity::Warning, TEXT("Invalid property value in defaults: %s"), Start); + UE_SUPPRESS(LogExec, Verbose, Warn->Logf(TEXT("Unknown property in %s: %s "), *ObjectStruct->GetName(), Start)); } // in the failure case, don't return NULL so the caller can potentially skip less and get values further in the string if (Result != NULL) diff --git a/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertyArray.cpp b/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertyArray.cpp index 126152fe0ea3..15727bbf6f07 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertyArray.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertyArray.cpp @@ -160,6 +160,7 @@ void UArrayProperty::SerializeItem( FArchive& Ar, void* Value, void const* Defau const FCustomPropertyListNode* CustomPropertyList = Ar.ArCustomPropertyList; const FCustomPropertyListNode* PropertyNode = CustomPropertyList; + FSerializedPropertyScope SerializedProperty(Ar, Inner, this); while (PropertyNode && i < n && !bSerializeRemainingItems) { if (PropertyNode->Property != Inner) @@ -197,6 +198,7 @@ void UArrayProperty::SerializeItem( FArchive& Ar, void* Value, void const* Defau Ar.ArUseCustomPropertyList = false; // Serialize each item until we get to the end of the array + FSerializedPropertyScope SerializedProperty(Ar, Inner, this); while (i < n) { #if WITH_EDITOR @@ -375,7 +377,7 @@ const TCHAR* UArrayProperty::ImportText_Internal( const TCHAR* Buffer, void* Dat if (*Buffer == TCHAR('\0') || *Buffer == TCHAR(')') || *Buffer == TCHAR(',')) { ArrayHelper.EmptyValues(); - return NULL; + return Buffer; } if ( *Buffer++ != TCHAR('(') ) diff --git a/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertyAssetObject.cpp b/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertyAssetObject.cpp index 46f1c87da2a5..bbd80436abce 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertyAssetObject.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertyAssetObject.cpp @@ -65,75 +65,45 @@ void UAssetObjectProperty::ExportTextItem( FString& ValueStr, const void* Proper { FAssetPtr& AssetPtr = *(FAssetPtr*)PropertyValue; - FStringAssetReference ID; + FStringAssetReference AssetReference; UObject *Object = AssetPtr.Get(); if (Object) { // Use object in case name has changed. - ID = FStringAssetReference(Object); + AssetReference = FStringAssetReference(Object); } else { - ID = AssetPtr.GetUniqueID(); + AssetReference = AssetPtr.GetUniqueID(); } if (0 != (PortFlags & PPF_ExportCpp)) { - ValueStr += FString::Printf(TEXT("FStringAssetReference(TEXT(\"%s\"))"), *ID.ToString().ReplaceCharWithEscapedChar()); + ValueStr += FString::Printf(TEXT("FStringAssetReference(TEXT(\"%s\"))"), *AssetReference.ToString().ReplaceCharWithEscapedChar()); return; } - if (!ID.ToString().IsEmpty()) - { - ValueStr += ID.ToString(); - } - else - { - ValueStr += TEXT("None"); - } + AssetReference.ExportTextItem(ValueStr, AssetReference, Parent, PortFlags, ExportRootScope); } const TCHAR* UAssetObjectProperty::ImportText_Internal( const TCHAR* InBuffer, void* Data, int32 PortFlags, UObject* Parent, FOutputDevice* ErrorText ) const { FAssetPtr& AssetPtr = *(FAssetPtr*)Data; - FString NewPath; - const TCHAR* Buffer = InBuffer; - const TCHAR* NewBuffer = UPropertyHelpers::ReadToken( Buffer, NewPath, 1 ); - if( !NewBuffer ) + FStringAssetReference AssetReference; + + if (AssetReference.ImportTextItem(InBuffer, PortFlags, Parent, ErrorText)) { - return NULL; - } - Buffer = NewBuffer; - if( NewPath==TEXT("None") ) - { - AssetPtr = NULL; - } - else - { - if( *Buffer == TCHAR('\'') ) - { - // A ' token likely means we're looking at an asset string in the form "Texture2d'/Game/UI/HUD/Actions/Barrel'" and we need to read and append the path part - // We have to skip over the first ' as UPropertyHelpers::ReadToken doesn't read single-quoted strings correctly, but does read a path correctly - NewPath += *Buffer++; // Append the leading ' - NewBuffer = UPropertyHelpers::ReadToken( Buffer, NewPath, 1 ); - if( !NewBuffer ) - { - return NULL; - } - Buffer = NewBuffer; - if( *Buffer != TCHAR('\'') ) - { - return NULL; - } - NewPath += *Buffer++; // Append the trailing ' - } - FStringAssetReference ID(NewPath); - AssetPtr = ID; + AssetPtr = AssetReference; + return InBuffer; } - return Buffer; + else + { + AssetPtr = nullptr; + return nullptr; + } } bool UAssetObjectProperty::ConvertFromType(const FPropertyTag& Tag, FArchive& Ar, uint8* Data, UStruct* DefaultsStruct, bool& bOutAdvanceProperty) diff --git a/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertyBool.cpp b/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertyBool.cpp index 3104070f4133..4a59be7d2a48 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertyBool.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertyBool.cpp @@ -78,13 +78,13 @@ int32 UBoolProperty::GetMinAlignment() const switch(ElementSize) { case sizeof(uint8): - Alignment = ALIGNOF(uint8); break; + Alignment = alignof(uint8); break; case sizeof(uint16): - Alignment = ALIGNOF(uint16); break; + Alignment = alignof(uint16); break; case sizeof(uint32): - Alignment = ALIGNOF(uint32); break; + Alignment = alignof(uint32); break; case sizeof(uint64): - Alignment = ALIGNOF(uint64); break; + Alignment = alignof(uint64); break; default: UE_LOG(LogProperty, Fatal, TEXT("Unsupported UBoolProperty %s size %d."), *GetName(), (int32)ElementSize); } diff --git a/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertyClass.cpp b/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertyClass.cpp index 1d3529047432..69f5f6d77853 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertyClass.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertyClass.cpp @@ -84,8 +84,12 @@ const TCHAR* UClassProperty::ImportText_Internal( const TCHAR* Buffer, void* Dat { #if USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING FLinkerLoad* ObjectLinker = (Parent != nullptr) ? Parent->GetClass()->GetLinker() : GetLinker(); - bool const bIsDeferringValueLoad = ((ObjectLinker == nullptr) || (ObjectLinker->LoadFlags & LOAD_DeferDependencyLoads)) && - (Cast(MetaClass) || Cast(AssignedPropertyClass)); + auto IsDeferringValueLoad = [](const UClass* Class)->bool + { + const ULinkerPlaceholderClass* Placeholder = Cast(Class); + return Placeholder && !Placeholder->IsMarkedResolved(); + }; + const bool bIsDeferringValueLoad = IsDeferringValueLoad(MetaClass) || ((!ObjectLinker || (ObjectLinker->LoadFlags & LOAD_DeferDependencyLoads) != 0) && IsDeferringValueLoad(AssignedPropertyClass)); #if USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS check( bIsDeferringValueLoad || !(Cast(MetaClass) || Cast(AssignedPropertyClass)) ); diff --git a/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertyMap.cpp b/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertyMap.cpp index b9f0c884ccd9..f4e438a84e43 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertyMap.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertyMap.cpp @@ -187,7 +187,7 @@ void UMapProperty::LinkInternal(FArchive& Ar) { check(KeyProp && ValueProp); - if (auto* MyLinker = GetLinker()) + if (FLinkerLoad* MyLinker = GetLinker()) { MyLinker->Preload(this); } @@ -279,6 +279,7 @@ void UMapProperty::SerializeItem(FArchive& Ar, void* Value, const void* Defaults TempKeyStorage = (uint8*)FMemory::Malloc(MapLayout.SetLayout.Size); KeyProp->InitializeValue(TempKeyStorage); + FSerializedPropertyScope SerializedProperty(Ar, KeyProp, this); for (; NumKeysToRemove; --NumKeysToRemove) { // Read key into temporary storage @@ -307,8 +308,11 @@ void UMapProperty::SerializeItem(FArchive& Ar, void* Value, const void* Defaults for (; NumEntries; --NumEntries) { // Read key into temporary storage - KeyProp->SerializeItem(Ar, TempKeyStorage); - + { + FSerializedPropertyScope SerializedProperty(Ar, KeyProp, this); + KeyProp->SerializeItem(Ar, TempKeyStorage); + } + // Add a new default value if the key doesn't currently exist in the map int32 NextPairIndex = MapHelper.FindMapIndexWithKey(TempKeyStorage); if (NextPairIndex == INDEX_NONE) @@ -322,7 +326,10 @@ void UMapProperty::SerializeItem(FArchive& Ar, void* Value, const void* Defaults KeyProp->CopyCompleteValue_InContainer(NextPairPtr, TempKeyStorage); // Deserialize value - ValueProp->SerializeItem(Ar, NextPairPtr + MapLayout.ValueOffset); + { + FSerializedPropertyScope SerializedProperty(Ar, ValueProp, this); + ValueProp->SerializeItem(Ar, NextPairPtr + MapLayout.ValueOffset); + } } MapHelper.Rehash(); @@ -356,9 +363,12 @@ void UMapProperty::SerializeItem(FArchive& Ar, void* Value, const void* Defaults // Write out the missing keys int32 MissingKeysNum = Indices.Num(); Ar << MissingKeysNum; - for (int32 Index : Indices) { - KeyProp->SerializeItem(Ar, DefaultsHelper.GetPairPtr(Index)); + FSerializedPropertyScope SerializedProperty(Ar, KeyProp, this); + for (int32 Index : Indices) + { + KeyProp->SerializeItem(Ar, DefaultsHelper.GetPairPtr(Index)); + } } // Write out differences from defaults @@ -388,8 +398,14 @@ void UMapProperty::SerializeItem(FArchive& Ar, void* Value, const void* Defaults { uint8* ValuePairPtr = MapHelper.GetPairPtrWithoutCheck(Index); - KeyProp ->SerializeItem(Ar, ValuePairPtr); - ValueProp->SerializeItem(Ar, ValuePairPtr + MapLayout.ValueOffset); + { + FSerializedPropertyScope SerializedProperty(Ar, KeyProp, this); + KeyProp->SerializeItem(Ar, ValuePairPtr); + } + { + FSerializedPropertyScope SerializedProperty(Ar, ValueProp, this); + ValueProp->SerializeItem(Ar, ValuePairPtr + MapLayout.ValueOffset); + } } } else @@ -402,8 +418,14 @@ void UMapProperty::SerializeItem(FArchive& Ar, void* Value, const void* Defaults { uint8* ValuePairPtr = MapHelper.GetPairPtrWithoutCheck(Index); - KeyProp ->SerializeItem(Ar, ValuePairPtr); - ValueProp->SerializeItem(Ar, ValuePairPtr + MapLayout.ValueOffset); + { + FSerializedPropertyScope SerializedProperty(Ar, KeyProp, this); + KeyProp->SerializeItem(Ar, ValuePairPtr); + } + { + FSerializedPropertyScope SerializedProperty(Ar, ValueProp, this); + ValueProp->SerializeItem(Ar, ValuePairPtr + MapLayout.ValueOffset); + } --Num; } @@ -490,7 +512,7 @@ void UMapProperty::ExportTextItem(FString& ValueStr, const void* PropertyValue, } uint8* StructDefaults = nullptr; - if (auto* StructValueProp = dynamic_cast(ValueProp)) + if (UStructProperty* StructValueProp = dynamic_cast(ValueProp)) { checkSlow(StructValueProp->Struct); @@ -805,7 +827,7 @@ void UMapProperty::InstanceSubobjects(void* Data, void const* DefaultData, UObje bool UMapProperty::SameType(const UProperty* Other) const { - auto* MapProp = (UMapProperty*)Other; + UMapProperty* MapProp = (UMapProperty*)Other; return Super::SameType(Other) && KeyProp && ValueProp && KeyProp->SameType(MapProp->KeyProp) && ValueProp->SameType(MapProp->ValueProp); } diff --git a/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertyObject.cpp b/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertyObject.cpp index 3a15dddf33ba..f4d82a6af55f 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertyObject.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertyObject.cpp @@ -50,37 +50,46 @@ bool UObjectProperty::ConvertFromType(const FPropertyTag& Tag, FArchive& Ar, uin void UObjectProperty::SerializeItem( FArchive& Ar, void* Value, void const* Defaults ) const { - UObject* ObjectValue = GetObjectPropertyValue(Value); - Ar << ObjectValue; - - UObject* CurrentValue = GetObjectPropertyValue(Value); - if (ObjectValue != CurrentValue) + if (Ar.IsObjectReferenceCollector()) { - SetObjectPropertyValue(Value, ObjectValue); + // Serialize in place + UObject** ObjectPtr = GetPropertyValuePtr(Value); + Ar << (*ObjectPtr); + } + else + { + UObject* ObjectValue = GetObjectPropertyValue(Value); + Ar << ObjectValue; -#if USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING - if (ULinkerPlaceholderExportObject* PlaceholderVal = Cast(ObjectValue)) + UObject* CurrentValue = GetObjectPropertyValue(Value); + if (ObjectValue != CurrentValue) { - PlaceholderVal->AddReferencingPropertyValue(this, Value); - } - else if (ULinkerPlaceholderClass* PlaceholderClass = Cast(ObjectValue)) - { - PlaceholderClass->AddReferencingPropertyValue(this, Value); - } - // NOTE: we don't remove this from CurrentValue if it is a - // ULinkerPlaceholderExportObject; this is because this property - // could be an array inner, and another member of that array (also - // referenced through this property)... if this becomes a problem, - // then we could inc/decrement a ref count per referencing property - // - // @TODO: if this becomes problematic (because ObjectValue doesn't match - // this property's PropertyClass), then we could spawn another - // placeholder object (of PropertyClass's type), or use null; but - // we'd have to modify ULinkerPlaceholderExportObject::ReplaceReferencingObjectValues() - // to accommodate this (as it depends on finding itself as the set value) -#endif // USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING + SetObjectPropertyValue(Value, ObjectValue); - CheckValidObject(Value); + #if USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING + if (ULinkerPlaceholderExportObject* PlaceholderVal = Cast(ObjectValue)) + { + PlaceholderVal->AddReferencingPropertyValue(this, Value); + } + else if (ULinkerPlaceholderClass* PlaceholderClass = Cast(ObjectValue)) + { + PlaceholderClass->AddReferencingPropertyValue(this, Value); + } + // NOTE: we don't remove this from CurrentValue if it is a + // ULinkerPlaceholderExportObject; this is because this property + // could be an array inner, and another member of that array (also + // referenced through this property)... if this becomes a problem, + // then we could inc/decrement a ref count per referencing property + // + // @TODO: if this becomes problematic (because ObjectValue doesn't match + // this property's PropertyClass), then we could spawn another + // placeholder object (of PropertyClass's type), or use null; but + // we'd have to modify ULinkerPlaceholderExportObject::ReplaceReferencingObjectValues() + // to accommodate this (as it depends on finding itself as the set value) + #endif // USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING + + CheckValidObject(Value); + } } } diff --git a/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertySet.cpp b/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertySet.cpp index 442c6921b6bf..2756db5b87e6 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertySet.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertySet.cpp @@ -251,6 +251,7 @@ void USetProperty::SerializeItem(FArchive& Ar, void* Value, const void* Defaults TempElementStorage = (uint8*)FMemory::Malloc(SetLayout.Size); ElementProp->InitializeValue(TempElementStorage); + FSerializedPropertyScope SerializedProperty(Ar, ElementProp, this); for (; NumElementsToRemove; --NumElementsToRemove) { // Read key into temporary storage @@ -275,6 +276,7 @@ void USetProperty::SerializeItem(FArchive& Ar, void* Value, const void* Defaults ElementProp->InitializeValue(TempElementStorage); } + FSerializedPropertyScope SerializedProperty(Ar, ElementProp, this); // Read remaining items into container for (; Num; --Num) { @@ -323,9 +325,12 @@ void USetProperty::SerializeItem(FArchive& Ar, void* Value, const void* Defaults // Write out the removed elements int32 RemovedElementsNum = Indices.Num(); Ar << RemovedElementsNum; - for (int32 Index : Indices) { - ElementProp->SerializeItem(Ar, DefaultsHelper.GetElementPtr(Index)); + FSerializedPropertyScope SerializedProperty(Ar, ElementProp, this); + for (int32 Index : Indices) + { + ElementProp->SerializeItem(Ar, DefaultsHelper.GetElementPtr(Index)); + } } // Write out added elements @@ -351,6 +356,8 @@ void USetProperty::SerializeItem(FArchive& Ar, void* Value, const void* Defaults // Write out differences from defaults int32 Num = Indices.Num(); Ar << Num; + + FSerializedPropertyScope SerializedProperty(Ar, ElementProp, this); for (int32 Index : Indices) { uint8* ElementPtr = SetHelper.GetElementPtrWithoutCheck(Index); @@ -362,6 +369,8 @@ void USetProperty::SerializeItem(FArchive& Ar, void* Value, const void* Defaults { int32 Num = SetHelper.Num(); Ar << Num; + + FSerializedPropertyScope SerializedProperty(Ar, ElementProp, this); for (int32 Index = 0; Num; ++Index) { if (SetHelper.IsValidIndex(Index)) diff --git a/Engine/Source/Runtime/CoreUObject/Private/UObject/SavePackage.cpp b/Engine/Source/Runtime/CoreUObject/Private/UObject/SavePackage.cpp index 18dfd24bc946..8956f2b7cfa9 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/UObject/SavePackage.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/UObject/SavePackage.cpp @@ -50,11 +50,13 @@ #include "UObject/DebugSerializationFlags.h" #include "EnumProperty.h" #include "BlueprintSupport.h" +#include "IConsoleManager.h" DEFINE_LOG_CATEGORY_STATIC(LogSavePackage, Log, All); static const int32 MAX_MERGED_COMPRESSION_CHUNKSIZE = 1024 * 1024; static const FName WorldClassName = FName("World"); +static const FName PrestreamPackageClassName = FName("PrestreamPackage"); #define VALIDATE_INITIALIZECORECLASSES 0 #define EXPORT_SORTING_DETAILED_LOGGING 0 @@ -794,6 +796,17 @@ static void ConditionallyExcludeObjectForTarget(UObject* Obj, EObjectMark Exclud InheritMark(SuperStruct, OBJECTMARK_NotForServer); } + // Check archetype, this may not have been covered in the case of components + UObject* Archetype = Obj->GetArchetype(); + + if (Archetype) + { + ConditionallyExcludeObjectForTarget(Archetype, ExcludedObjectMarks, TargetPlatform); + InheritMark(Archetype, OBJECTMARK_EditorOnly); + InheritMark(Archetype, OBJECTMARK_NotForClient); + InheritMark(Archetype, OBJECTMARK_NotForServer); + } + if (Obj->HasAnyFlags(RF_ClassDefaultObject)) { // If class is included, CDO must be included so only check inherited marks @@ -975,6 +988,12 @@ FArchive& FArchiveSaveTagExports::operator<<(UObject*& Obj) break; } } + + if(!bNeedsLoadForEditorGame && Obj->HasAnyFlags(RF_ClassDefaultObject)) + { + bNeedsLoadForEditorGame = Obj->GetClass()->NeedsLoadForEditorGame(); + } + if (!bNeedsLoadForEditorGame) { Obj->Mark(OBJECTMARK_NotAlwaysLoadedForEditorGame); @@ -1089,7 +1108,6 @@ public: virtual FArchive& operator<<(UObject*& Obj) override; virtual FArchive& operator<< (struct FWeakObjectPtr& Value) override; virtual FArchive& operator<<(FLazyObjectPtr& LazyObjectPtr) override; - virtual FArchive& operator<<(FAssetPtr& AssetPtr) override; virtual FArchive& operator<<(FStringAssetReference& Value) override; virtual FArchive& operator<<(FName& Name) override; @@ -1230,33 +1248,12 @@ FArchive& FArchiveSaveTagImports::operator<<( FLazyObjectPtr& LazyObjectPtr) return *this << ID; } -FArchive& FArchiveSaveTagImports::operator<<( FAssetPtr& AssetPtr) -{ - FStringAssetReference ID; - UObject *Object = AssetPtr.Get(); - - if (Object) - { - // Use object in case name has changed. - ID = FStringAssetReference(Object); - } - else - { - ID = AssetPtr.GetUniqueID(); - } - return *this << ID; -} - FArchive& FArchiveSaveTagImports::operator<<(FStringAssetReference& Value) { if (Value.IsValid()) { + Value.PreSavePath(); FString Path = Value.ToString(); - if (FCoreUObjectDelegates::StringAssetReferenceSaving.IsBound()) - { - // This picks up any redirectors - Path = FCoreUObjectDelegates::StringAssetReferenceSaving.Execute(Path); - } if (GetIniFilenameFromObjectsReference(Path) != nullptr) { @@ -2460,7 +2457,7 @@ public: } (*this) << (UObject*&)StructObject->Children; - CurrentClass = nullptr; + CurrentClass = nullptr; //-V519 (*this) << (UObject*&)StructObject->Next; @@ -3425,15 +3422,12 @@ FSavePackageResultStruct UPackage::Save(UPackage* InOuter, UObject* Base, EObjec } const bool FilterEditorOnly = InOuter->HasAnyPackageFlags(PKG_FilterEditorOnly); - // store a list of additional packages to cook when this is cooked (ie streaming levels) - TArray AdditionalPackagesToCook; - // Route PreSaveRoot to allow e.g. the world to attach components for the persistent level. bool bCleanupIsRequired = false; if (Base) { - bCleanupIsRequired = Base->PreSaveRoot(Filename, AdditionalPackagesToCook); + bCleanupIsRequired = Base->PreSaveRoot(Filename); } const FString BaseFilename = FPaths::GetBaseFilename(Filename); @@ -3686,6 +3680,7 @@ FSavePackageResultStruct UPackage::Save(UPackage* InOuter, UObject* Base, EObjec } // Import objects & names. + TSet PrestreamPackages; { TArray TagExpObjects; GetObjectsWithAnyMarks(TagExpObjects, OBJECTMARK_TagExp); @@ -3693,6 +3688,7 @@ FSavePackageResultStruct UPackage::Save(UPackage* InOuter, UObject* Base, EObjec { UObject* Obj = TagExpObjects[Index]; check(Obj->HasAnyMarks(OBJECTMARK_TagExp)); + // Build list. FArchiveSaveTagImports ImportTagger(Linker); ImportTagger.SetPortFlags(ComparisonFlags); @@ -3735,6 +3731,23 @@ FSavePackageResultStruct UPackage::Save(UPackage* InOuter, UObject* Base, EObjec ImportTagger << Dep; } } + static const IConsoleVariable* ProcessPrestreamingRequests = IConsoleManager::Get().FindConsoleVariable(TEXT("s.ProcessPrestreamingRequests")); + if (ProcessPrestreamingRequests->GetInt()) + { + Deps.Reset(); + Obj->GetPrestreamPackages(Deps); + for (UObject* Dep : Deps) + { + if (Dep) + { + UPackage* Pkg = Dep->GetOutermost(); + if (!Pkg->HasAnyPackageFlags(PKG_CompiledIn) && Obj->HasAnyMarks(OBJECTMARK_TagExp)) + { + PrestreamPackages.Add(Pkg); + } + } + } + } } if( Obj->IsIn(GetTransientPackage()) ) @@ -3759,6 +3772,19 @@ FSavePackageResultStruct UPackage::Save(UPackage* InOuter, UObject* Base, EObjec } } } + if (PrestreamPackages.Num()) + { + TSet KeptPrestreamPackages; + for (UPackage* Pkg : PrestreamPackages) + { + if (!Pkg->HasAnyMarks(OBJECTMARK_TagImp)) + { + Pkg->Mark(OBJECTMARK_TagImp); + KeptPrestreamPackages.Add(Pkg); + } + } + Exchange(PrestreamPackages, KeptPrestreamPackages); + } #if WITH_EDITOR // Remove TagExp from duplicate objects. @@ -3831,6 +3857,15 @@ FSavePackageResultStruct UPackage::Save(UPackage* InOuter, UObject* Base, EObjec // A was already marked by the cooker. M.xxx now has a private import to A, which is normally illegal, hence // the OBJECTMARK_MarkedByCooker check below UPackage* ObjPackage = Obj->GetOutermost(); + if (PrestreamPackages.Contains(ObjPackage)) + { + SavePackageState->MarkNameAsReferenced(PrestreamPackageClassName); + // These are not errors + UE_LOG(LogSavePackage, Display, TEXT("Prestreaming package %s "), *ObjPackage->GetPathName()); //-V595 + continue; + } + + if( !Obj->HasAnyFlags(RF_Public) && !Obj->HasAnyFlags(RF_Transient)) { if (!IsEventDrivenLoaderEnabledInCookedBuilds() || !TargetPlatform || !ObjPackage->HasAnyPackageFlags(PKG_CompiledIn)) @@ -3889,7 +3924,7 @@ FSavePackageResultStruct UPackage::Save(UPackage* InOuter, UObject* Base, EObjec } // The graph is linked to objects in a different map package! - if( IllegalObjectsInOtherMaps.Num() ) + if (IllegalObjectsInOtherMaps.Num() ) { UObject* MostLikelyCulprit = nullptr; const UProperty* PropertyRef = nullptr; @@ -3946,7 +3981,7 @@ FSavePackageResultStruct UPackage::Save(UPackage* InOuter, UObject* Base, EObjec } // The graph is linked to private objects! - if ( PrivateObjects.Num() ) + if (PrivateObjects.Num()) { UObject* MostLikelyCulprit = nullptr; const UProperty* PropertyRef = nullptr; @@ -3997,10 +4032,6 @@ FSavePackageResultStruct UPackage::Save(UPackage* InOuter, UObject* Base, EObjec return ESavePackageResult::Error; } - - // store the additional packages for cooking - Linker->Summary.AdditionalPackagesToCook = AdditionalPackagesToCook; - // Write fixed-length file summary to overwrite later. if( Conform ) { @@ -4154,8 +4185,12 @@ FSavePackageResultStruct UPackage::Save(UPackage* InOuter, UObject* Base, EObjec } } #endif //WITH_EDITOR - FObjectImport* LocObjectImport = nullptr; - LocObjectImport = new(Linker->ImportMap)FObjectImport(Obj, ObjClass); + FObjectImport* LocObjectImport = new(Linker->ImportMap)FObjectImport(Obj, ObjClass); + + if (PrestreamPackages.Contains((UPackage*)Obj)) + { + LocObjectImport->ClassName = PrestreamPackageClassName; + } #if WITH_EDITOR if (ReplacedName != NAME_None) { @@ -4272,50 +4307,47 @@ FSavePackageResultStruct UPackage::Save(UPackage* InOuter, UObject* Base, EObjec // add a dependency map entry also TArray& DependIndices = Linker->DependsMap[ExpIndex]; - if ( Object != nullptr ) + // find all the objects needed by this export + TArray* SrcDepends = ObjectDependencies.Find(Object); + checkf(SrcDepends,TEXT("Couldn't find dependency map for %s"), *Object->GetFullName()); + + // go through each object and... + for (int32 DependIndex = 0; DependIndex < SrcDepends->Num(); DependIndex++) { - // find all the objects needed by this export - TArray* SrcDepends = ObjectDependencies.Find(Object); - checkf(SrcDepends,TEXT("Couldn't find dependency map for %s"), *Object->GetFullName()); + UObject* DependentObject = (*SrcDepends)[DependIndex]; - // go through each object and... - for (int32 DependIndex = 0; DependIndex < SrcDepends->Num(); DependIndex++) + FPackageIndex DependencyIndex; + + // if the dependency is in the same pacakge, we need to save an index into our ExportMap + if (DependentObject->GetOutermost() == Linker->LinkerRoot) { - UObject* DependentObject = (*SrcDepends)[DependIndex]; - - FPackageIndex DependencyIndex; - - // if the dependency is in the same pacakge, we need to save an index into our ExportMap - if (DependentObject->GetOutermost() == Linker->LinkerRoot) - { - // ... find the associated ExportIndex - DependencyIndex = ExportToIndexMap.FindRef(DependentObject); - } - // otherwise we need to save an index into the ImportMap - else - { - // ... find the associated ImportIndex - DependencyIndex = ImportToIndexMap.FindRef(DependentObject); - } + // ... find the associated ExportIndex + DependencyIndex = ExportToIndexMap.FindRef(DependentObject); + } + // otherwise we need to save an index into the ImportMap + else + { + // ... find the associated ImportIndex + DependencyIndex = ImportToIndexMap.FindRef(DependentObject); + } #if WITH_EDITOR - // If we still didn't find index, maybe it was a duplicate export which got removed. - // Check if we have a redirect to original. - if (DependencyIndex.IsNull() && DuplicateRedirects.Contains(DependentObject)) + // If we still didn't find index, maybe it was a duplicate export which got removed. + // Check if we have a redirect to original. + if (DependencyIndex.IsNull() && DuplicateRedirects.Contains(DependentObject)) + { + UObject** const RedirectObj = DuplicateRedirects.Find(DependentObject); + if (RedirectObj) { - UObject** const RedirectObj = DuplicateRedirects.Find(DependentObject); - if (RedirectObj) - { - DependencyIndex = ExportToIndexMap.FindRef(*RedirectObj); - } + DependencyIndex = ExportToIndexMap.FindRef(*RedirectObj); } -#endif - // if we didn't find it (FindRef returns 0 on failure, which is good in this case), then we are in trouble, something went wrong somewhere - checkf(!DependencyIndex.IsNull(), TEXT("Failed to find dependency index for %s (%s)"), *DependentObject->GetFullName(), *Object->GetFullName()); - - // add the import as an import for this export - DependIndices.Add(DependencyIndex); } +#endif + // if we didn't find it (FindRef returns 0 on failure, which is good in this case), then we are in trouble, something went wrong somewhere + checkf(!DependencyIndex.IsNull(), TEXT("Failed to find dependency index for %s (%s)"), *DependentObject->GetFullName(), *Object->GetFullName()); + + // add the import as an import for this export + DependIndices.Add(DependencyIndex); } } @@ -5205,7 +5237,7 @@ FSavePackageResultStruct UPackage::Save(UPackage* InOuter, UObject* Base, EObjec SlowTask.EnterProgressFrame(); // Detach archive used for saving, closing file handle. - if (Linker && !bSaveAsync) + if (!bSaveAsync) { Linker->Detach(); } @@ -5223,30 +5255,27 @@ FSavePackageResultStruct UPackage::Save(UPackage* InOuter, UObject* Base, EObjec // Compress the temporarily file to destination. if (bSaveAsync) { - UE_LOG(LogSavePackage, Log, TEXT("Async saving from memory to '%s'"), *NewPath ); + UE_LOG(LogSavePackage, Log, TEXT("Async saving from memory to '%s'"), *NewPath); // Detach archive used for memory saving. - if (Linker) + FLargeMemoryWriter* Writer = (FLargeMemoryWriter*)(Linker->Saver); + int64 DataSize = Writer->TotalSize(); + + COOK_STAT(FScopedDurationTimer SaveTimer(SavePackageStats::AsyncWriteTimeSec)); + TotalPackageSizeUncompressed += DataSize; + + FLargeMemoryPtr DataPtr(Writer->GetData()); + Writer->ReleaseOwnership(); + if (IsEventDrivenLoaderEnabledInCookedBuilds() && Linker->IsCooking()) { - FLargeMemoryWriter* Writer = (FLargeMemoryWriter*)(Linker->Saver); - int64 DataSize = Writer->TotalSize(); - - COOK_STAT(FScopedDurationTimer SaveTimer(SavePackageStats::AsyncWriteTimeSec)); - TotalPackageSizeUncompressed += DataSize; - - FLargeMemoryPtr DataPtr(Writer->GetData()); - Writer->ReleaseOwnership(); - if (IsEventDrivenLoaderEnabledInCookedBuilds() && Linker->IsCooking()) - { - AsyncWriteFileWithSplitExports(MoveTemp(DataPtr), DataSize, Linker->Summary.TotalHeaderSize, *NewPath, FinalTimeStamp); - } - else - { - AsyncWriteFile(MoveTemp(DataPtr), DataSize, *NewPath, FinalTimeStamp); - } - - Linker->Detach(); + AsyncWriteFileWithSplitExports(MoveTemp(DataPtr), DataSize, Linker->Summary.TotalHeaderSize, *NewPath, FinalTimeStamp); } + else + { + AsyncWriteFile(MoveTemp(DataPtr), DataSize, *NewPath, FinalTimeStamp); + } + + Linker->Detach(); } // Move the temporary file. else diff --git a/Engine/Source/Runtime/CoreUObject/Private/UObject/ScriptCore.cpp b/Engine/Source/Runtime/CoreUObject/Private/UObject/ScriptCore.cpp index 13881832cf1f..8f7626ec6673 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/UObject/ScriptCore.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/UObject/ScriptCore.cpp @@ -1032,7 +1032,7 @@ bool UObject::CallFunctionByNameWithArguments(const TCHAR* Str, FOutputDevice& A uint8* Parms = (uint8*)FMemory_Alloca(Function->ParmsSize); FMemory::Memzero( Parms, Function->ParmsSize ); - const uint32 ExportFlags = PPF_Localized; + const uint32 ExportFlags = PPF_None; bool Failed = 0; int32 NumParamsEvaluated = 0; for( TFieldIterator It(Function); It && (It->PropertyFlags & (CPF_Parm|CPF_ReturnParm))==CPF_Parm; ++It, NumParamsEvaluated++ ) @@ -1385,7 +1385,7 @@ void UObject::execInstanceVariable(FFrame& Stack, RESULT_DECL) if (VarProperty == nullptr || !IsA((UClass*)VarProperty->GetOuter())) { - FBlueprintExceptionInfo ExceptionInfo(EBlueprintExceptionType::AccessViolation, LOCTEXT("MissingProperty", "Attempted to access missing property. If this is a packaged/cooked build, are you attempting to use an editor-only property?")); + FBlueprintExceptionInfo ExceptionInfo(EBlueprintExceptionType::AccessViolation, FText::Format(LOCTEXT("MissingProperty", "Attempted to access missing property '{0}'. If this is a packaged/cooked build, are you attempting to use an editor-only property?"), FText::FromString(GetNameSafe(VarProperty)))); FBlueprintCoreDelegates::ThrowScriptException(this, Stack, ExceptionInfo); Stack.MostRecentPropertyAddress = nullptr; @@ -2716,6 +2716,48 @@ void UObject::execArrayConst(FFrame& Stack, RESULT_DECL) } IMPLEMENT_VM_FUNCTION(EX_ArrayConst, execArrayConst); +void UObject::execSetConst(FFrame& Stack, RESULT_DECL) +{ + UProperty* InnerProperty = CastChecked(Stack.ReadObject()); + int32 Num = Stack.ReadInt(); + check(RESULT_PARAM); + + FScriptSetHelper SetHelper = FScriptSetHelper::CreateHelperFormElementProperty(InnerProperty, RESULT_PARAM); + SetHelper.EmptyElements(Num); + + while (*Stack.Code != EX_EndSetConst) + { + int32 Index = SetHelper.AddDefaultValue_Invalid_NeedsRehash(); + Stack.Step(Stack.Object, SetHelper.GetElementPtr(Index)); + } + SetHelper.Rehash(); + + P_FINISH; // EX_EndSetConst +} +IMPLEMENT_VM_FUNCTION(EX_SetConst, execSetConst); + +void UObject::execMapConst(FFrame& Stack, RESULT_DECL) +{ + UProperty* KeyProperty = CastChecked(Stack.ReadObject()); + UProperty* ValProperty = CastChecked(Stack.ReadObject()); + int32 Num = Stack.ReadInt(); + check(RESULT_PARAM); + + FScriptMapHelper MapHelper = FScriptMapHelper::CreateHelperFormInnerProperties(KeyProperty, ValProperty, RESULT_PARAM); + MapHelper.EmptyValues(Num); + + while (*Stack.Code != EX_EndMapConst) + { + int32 Index = MapHelper.AddDefaultValue_Invalid_NeedsRehash(); + Stack.Step(Stack.Object, MapHelper.GetKeyPtr(Index)); + Stack.Step(Stack.Object, MapHelper.GetValuePtr(Index)); + } + MapHelper.Rehash(); + + P_FINISH; // EX_EndMapConst +} +IMPLEMENT_VM_FUNCTION(EX_MapConst, execMapConst); + void UObject::execIntZero( FFrame& Stack, RESULT_DECL ) { *(int32*)RESULT_PARAM = 0; diff --git a/Engine/Source/Runtime/CoreUObject/Private/UObject/TextProperty.cpp b/Engine/Source/Runtime/CoreUObject/Private/UObject/TextProperty.cpp index ca2685a236d3..e40cbedb9649 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/UObject/TextProperty.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/UObject/TextProperty.cpp @@ -122,7 +122,7 @@ const TCHAR* UTextProperty::ImportText_Internal( const TCHAR* Buffer, void* Data FString PackageNamespace; #if USE_STABLE_LOCALIZATION_KEYS - if (GIsEditor && !(PortFlags & PPF_DuplicateForPIE)) + if (GIsEditor && !(PortFlags & (PPF_DuplicateVerbatim | PPF_DuplicateForPIE))) { PackageNamespace = TextNamespaceUtil::EnsurePackageNamespace(Parent); } diff --git a/Engine/Source/Runtime/CoreUObject/Private/UObject/UObjectBase.cpp b/Engine/Source/Runtime/CoreUObject/Private/UObject/UObjectBase.cpp index 92f16e1dec91..c6ff42b7a45d 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/UObject/UObjectBase.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/UObject/UObjectBase.cpp @@ -18,6 +18,7 @@ #include "Templates/Casts.h" #include "UObject/GCObject.h" #include "LinkerLoad.h" +#include "CommandLine.h" DEFINE_LOG_CATEGORY_STATIC(LogUObjectBase, Log, All); DEFINE_STAT(STAT_UObjectsStatGroupTester); @@ -934,6 +935,7 @@ static FAutoConsoleVariableRef CMaxObjectsInGame( ECVF_Default ); + /** * Final phase of UObject initialization. all auto register objects are added to the main data structures. */ @@ -951,10 +953,20 @@ void UObjectBaseInit() // FPlatformProperties::RequiresCookedData() will be false. Please note that GIsEditor and FApp::IsGame() are not valid at this point. if( FPlatformProperties::RequiresCookedData() ) { - GConfig->GetInt( TEXT("/Script/Engine.GarbageCollectionSettings"), TEXT("gc.MaxObjectsNotConsideredByGC"), MaxObjectsNotConsideredByGC, GEngineIni ); + FString Value; + bool bIsCookOnTheFly = FParse::Value(FCommandLine::Get(), TEXT("-filehostip="), Value); + if (bIsCookOnTheFly) + { + extern int32 GCreateGCClusters; + GCreateGCClusters = false; + } + else + { + GConfig->GetInt(TEXT("/Script/Engine.GarbageCollectionSettings"), TEXT("gc.MaxObjectsNotConsideredByGC"), MaxObjectsNotConsideredByGC, GEngineIni); - // Not used on PC as in-place creation inside bigger pool interacts with the exit purge and deleting UObject directly. - GConfig->GetInt( TEXT("/Script/Engine.GarbageCollectionSettings"), TEXT("gc.SizeOfPermanentObjectPool"), SizeOfPermanentObjectPool, GEngineIni ); + // Not used on PC as in-place creation inside bigger pool interacts with the exit purge and deleting UObject directly. + GConfig->GetInt(TEXT("/Script/Engine.GarbageCollectionSettings"), TEXT("gc.SizeOfPermanentObjectPool"), SizeOfPermanentObjectPool, GEngineIni); + } // Maximum number of UObjects in cooked game GConfig->GetInt(TEXT("/Script/Engine.GarbageCollectionSettings"), TEXT("gc.MaxObjectsInGame"), MaxUObjects, GEngineIni); diff --git a/Engine/Source/Runtime/CoreUObject/Private/UObject/UObjectClusters.cpp b/Engine/Source/Runtime/CoreUObject/Private/UObject/UObjectClusters.cpp index 8e78ecdece6c..3a85b2078687 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/UObject/UObjectClusters.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/UObject/UObjectClusters.cpp @@ -94,6 +94,39 @@ void FUObjectClusterContainer::FreeCluster(int32 InClusterIndex) check(NumAllocatedClusters >= 0); } +FUObjectCluster* FUObjectClusterContainer::GetObjectCluster(UObjectBaseUtility* ClusterRootOrObjectFromCluster) +{ + check(ClusterRootOrObjectFromCluster); + + const int32 OuterIndex = GUObjectArray.ObjectToIndex(ClusterRootOrObjectFromCluster); + FUObjectItem* OuterItem = GUObjectArray.IndexToObjectUnsafeForGC(OuterIndex); + int32 ClusterRootIndex = 0; + if (OuterItem->HasAnyFlags(EInternalObjectFlags::ClusterRoot)) + { + ClusterRootIndex = OuterIndex; + } + else + { + ClusterRootIndex = OuterItem->GetOwnerIndex(); + } + FUObjectCluster* Cluster = nullptr; + if (ClusterRootIndex != 0) + { + const int32 ClusterIndex = ClusterRootIndex > 0 ? GUObjectArray.IndexToObject(ClusterRootIndex)->GetClusterIndex() : OuterItem->GetClusterIndex(); + Cluster = &GUObjectClusters[ClusterIndex]; + } + return Cluster; +} + +void FUObjectClusterContainer::DissolveCluster(UObjectBaseUtility* ClusterRootOrObjectFromCluster) +{ + FUObjectCluster* Cluster = GetObjectCluster(ClusterRootOrObjectFromCluster); + if (Cluster) + { + DissolveCluster(*Cluster); + } +} + void FUObjectClusterContainer::DissolveCluster(FUObjectCluster& Cluster) { FUObjectItem* RootObjectItem = GUObjectArray.IndexToObjectUnsafeForGC(Cluster.RootIndex); @@ -149,7 +182,7 @@ void FUObjectClusterContainer::DissolveClusterAndMarkObjectsAsUnreachable(const ClusterObjectItem->SetOwnerIndex(0); if (ClusterObjectIndex < CurrentIndex) { - ClusterObjectItem->SetFlags(EInternalObjectFlags::Unreachable | EInternalObjectFlags::NoStrongReference); + ClusterObjectItem->SetFlags(EInternalObjectFlags::Unreachable); } } @@ -168,7 +201,7 @@ void FUObjectClusterContainer::DissolveClusterAndMarkObjectsAsUnreachable(const { if (ReferencedByClusterRootIndex < CurrentIndex) { - ReferencedByClusterRootItem->SetFlags(EInternalObjectFlags::Unreachable | EInternalObjectFlags::NoStrongReference); + ReferencedByClusterRootItem->SetFlags(EInternalObjectFlags::Unreachable); } DissolveClusterAndMarkObjectsAsUnreachable(CurrentIndex, ReferencedByClusterRootItem); } @@ -345,106 +378,6 @@ static FAutoConsoleCommand FindStaleClustersCommand( #endif // !UE_BUILD_SHIPPING -/** -* Pool for reducing allocations when constructing clusters -*/ -class FClusterArrayPool -{ -public: - - /** - * Gets the singleton instance of the FObjectArrayPool - * @return Pool singleton. - */ - FORCEINLINE static FClusterArrayPool& Get() - { - static FClusterArrayPool Singleton; - return Singleton; - } - - /** - * Gets an event from the pool or creates one if necessary. - * - * @return The array. - * @see ReturnToPool - */ - FORCEINLINE TArray* GetArrayFromPool() - { - TArray* Result = Pool.Pop(); - if (!Result) - { - Result = new TArray(); - } - check(Result); -#if UE_BUILD_DEBUG - NumberOfUsedArrays.Increment(); -#endif // UE_BUILD_DEBUG - return Result; - } - - /** - * Returns an array to the pool. - * - * @param Array The array to return. - * @see GetArrayFromPool - */ - FORCEINLINE void ReturnToPool(TArray* Array) - { -#if UE_BUILD_DEBUG - const int32 CheckUsedArrays = NumberOfUsedArrays.Decrement(); - checkSlow(CheckUsedArrays >= 0); -#endif // UE_BUILD_DEBUG - check(Array); - Array->Reset(); - Pool.Push(Array); - } - - /** Performs memory cleanup */ - void Cleanup() - { -#if UE_BUILD_DEBUG - const int32 CheckUsedArrays = NumberOfUsedArrays.GetValue(); - checkSlow(CheckUsedArrays == 0); -#endif // UE_BUILD_DEBUG - - uint32 FreedMemory = 0; - TArray< TArray* > AllArrays; - Pool.PopAll(AllArrays); - for (TArray* Array : AllArrays) - { - FreedMemory += Array->GetAllocatedSize(); - delete Array; - } - UE_LOG(LogObj, Log, TEXT("Freed %ub from %d cluster array pools."), FreedMemory, AllArrays.Num()); - } - -#if UE_BUILD_DEBUG - void CheckLeaks() - { - // This function is called after cluster has been created so at this point there should be no - // arrays used by cluster creation code and all should be returned to the pool - const int32 LeakedPoolArrays = NumberOfUsedArrays.GetValue(); - checkSlow(LeakedPoolArrays == 0); - } -#endif - -private: - - /** Holds the collection of recycled arrays. */ - TLockFreePointerListLIFO< TArray > Pool; - -#if UE_BUILD_DEBUG - /** Number of arrays currently acquired from the pool by clusters */ - FThreadSafeCounter NumberOfUsedArrays; -#endif // UE_BUILD_DEBUG -}; - -/** Called on shutdown to free cluster memory */ -void CleanupClusterArrayPools() -{ - FClusterArrayPool::Get().Cleanup(); -} - /** * Handles UObject references found by TFastReferenceCollector */ @@ -608,8 +541,10 @@ public: for (int32 OtherClusterReferencedCluster : OtherCluster.ReferencedClusters) { - check(OtherClusterReferencedCluster != ClusterRootIndex); - Cluster.ReferencedClusters.AddUnique(OtherClusterReferencedCluster); + if (OtherClusterReferencedCluster != ClusterRootIndex) + { + Cluster.ReferencedClusters.AddUnique(OtherClusterReferencedCluster); + } } for (int32 OtherClusterReferencedMutableObjectIndex : OtherCluster.MutableObjects) { @@ -644,24 +579,24 @@ template class TClusterCollector : public FReferenceCollector { TProcessor& Processor; - TArray& ObjectArray; + FGCArrayStruct& ObjectArrayStruct; public: - TClusterCollector(TProcessor& InProcessor, TArray& InObjectArray) + TClusterCollector(TProcessor& InProcessor, FGCArrayStruct& InObjectArrayStruct) : Processor(InProcessor) - , ObjectArray(InObjectArray) + , ObjectArrayStruct(InObjectArrayStruct) { } virtual void HandleObjectReference(UObject*& Object, const UObject* ReferencingObject, const UProperty* ReferencingProperty) override { - Processor.HandleTokenStreamObjectReference(ObjectArray, const_cast(ReferencingObject), Object, INDEX_NONE, false); + Processor.HandleTokenStreamObjectReference(ObjectArrayStruct.ObjectsToSerialize, const_cast(ReferencingObject), Object, INDEX_NONE, false); } virtual void HandleObjectReferences(UObject** InObjects, const int32 ObjectNum, const UObject* ReferencingObject, const UProperty* InReferencingProperty) override { for (int32 ObjectIndex = 0; ObjectIndex < ObjectNum; ++ObjectIndex) { UObject*& Object = InObjects[ObjectIndex]; - Processor.HandleTokenStreamObjectReference(ObjectArray, const_cast(ReferencingObject), Object, INDEX_NONE, false); + Processor.HandleTokenStreamObjectReference(ObjectArrayStruct.ObjectsToSerialize, const_cast(ReferencingObject), Object, INDEX_NONE, false); } } virtual bool IsIgnoringArchetypeRef() const override @@ -677,7 +612,7 @@ public: /** Looks through objects loaded with a package and creates clusters from them */ void CreateClustersFromPackage(FLinkerLoad* PackageLinker) { - if (FPlatformProperties::RequiresCookedData() && !GIsInitialLoad && GCreateGCClusters && !GUObjectArray.IsOpenForDisregardForGC()) + if (FPlatformProperties::RequiresCookedData() && !GIsInitialLoad && GCreateGCClusters && !GUObjectArray.IsOpenForDisregardForGC() && GUObjectArray.DisregardForGCEnabled() ) { check(PackageLinker); @@ -693,54 +628,49 @@ void CreateClustersFromPackage(FLinkerLoad* PackageLinker) void UObjectBaseUtility::AddToCluster(UObjectBaseUtility* ClusterRootOrObjectFromCluster, bool bAddAsMutableObject /* = false */) { - check(ClusterRootOrObjectFromCluster); - - const int32 OuterIndex = GUObjectArray.ObjectToIndex(ClusterRootOrObjectFromCluster); - FUObjectItem* OuterItem = GUObjectArray.IndexToObjectUnsafeForGC(OuterIndex); - int32 ClusterRootIndex = 0; - if (OuterItem->HasAnyFlags(EInternalObjectFlags::ClusterRoot)) + FUObjectCluster* Cluster = GUObjectClusters.GetObjectCluster(ClusterRootOrObjectFromCluster); + if (Cluster) { - ClusterRootIndex = OuterIndex; - } - else - { - ClusterRootIndex = OuterItem->GetOwnerIndex(); - } - if (ClusterRootIndex != 0) - { - const int32 ClusterIndex = ClusterRootIndex > 0 ? GUObjectArray.IndexToObject(ClusterRootIndex)->GetClusterIndex() : OuterItem->GetClusterIndex(); - FUObjectCluster& Cluster = GUObjectClusters[ClusterIndex]; + const int32 ClusterRootIndex = Cluster->RootIndex; if (!bAddAsMutableObject) { - FClusterReferenceProcessor Processor(ClusterRootIndex, Cluster); - TFastReferenceCollector, FClusterArrayPool, true> ReferenceCollector(Processor, FClusterArrayPool::Get()); - TArray ObjectsToProcess; + FClusterReferenceProcessor Processor(ClusterRootIndex, *Cluster); + TFastReferenceCollector, FGCArrayPool, true> ReferenceCollector(Processor, FGCArrayPool::Get()); + FGCArrayStruct ArrayStruct; + TArray& ObjectsToProcess = ArrayStruct.ObjectsToSerialize; UObject* ThisObject = static_cast(this); Processor.HandleTokenStreamObjectReference(ObjectsToProcess, static_cast(ClusterRootOrObjectFromCluster), ThisObject, INDEX_NONE, true); if (ObjectsToProcess.Num()) { - ReferenceCollector.CollectReferences(ObjectsToProcess); + ReferenceCollector.CollectReferences(ArrayStruct); } + +#if UE_GCCLUSTER_VERBOSE_LOGGING + UObject* ClusterRootObject = static_cast(GUObjectArray.IndexToObjectUnsafeForGC(Cluster->RootIndex)->Object); + UE_LOG(LogObj, Log, TEXT("Added %s to cluster %s:"), *ThisObject->GetFullName(), *ClusterRootObject->GetFullName()); + + DumpClusterToLog(*Cluster, true, false); +#endif } else { // Adds this object's index to the MutableObjects array keeping it sorted and unique const int32 ThisObjectIndex = GUObjectArray.ObjectToIndex(this); int32 InsertedAt = INDEX_NONE; - for (int32 MutableObjectIndex = 0; MutableObjectIndex < Cluster.MutableObjects.Num() && InsertedAt == INDEX_NONE; ++MutableObjectIndex) + for (int32 MutableObjectIndex = 0; MutableObjectIndex < Cluster->MutableObjects.Num() && InsertedAt == INDEX_NONE; ++MutableObjectIndex) { - if (Cluster.MutableObjects[MutableObjectIndex] > ThisObjectIndex) + if (Cluster->MutableObjects[MutableObjectIndex] > ThisObjectIndex) { - InsertedAt = Cluster.MutableObjects.Insert(ThisObjectIndex, MutableObjectIndex); + InsertedAt = Cluster->MutableObjects.Insert(ThisObjectIndex, MutableObjectIndex); } - else if (Cluster.MutableObjects[MutableObjectIndex] == ThisObjectIndex) + else if (Cluster->MutableObjects[MutableObjectIndex] == ThisObjectIndex) { InsertedAt = MutableObjectIndex; } } if (InsertedAt == INDEX_NONE) { - Cluster.MutableObjects.Add(ThisObjectIndex); + Cluster->MutableObjects.Add(ThisObjectIndex); } } } @@ -748,7 +678,7 @@ void UObjectBaseUtility::AddToCluster(UObjectBaseUtility* ClusterRootOrObjectFro bool UObjectBaseUtility::CanBeInCluster() const { - return true; + return OuterPrivate ? OuterPrivate->CanBeInCluster() : true; } void UObjectBaseUtility::CreateCluster() @@ -771,12 +701,13 @@ void UObjectBaseUtility::CreateCluster() // Collect all objects referenced by cluster root and by all objects it's referencing FClusterReferenceProcessor Processor(InternalIndex, Cluster); - TFastReferenceCollector, FClusterArrayPool, true> ReferenceCollector(Processor, FClusterArrayPool::Get()); - TArray ObjectsToProcess; + TFastReferenceCollector, FGCArrayPool, true> ReferenceCollector(Processor, FGCArrayPool::Get()); + FGCArrayStruct ArrayStruct; + TArray& ObjectsToProcess = ArrayStruct.ObjectsToSerialize; ObjectsToProcess.Add(static_cast(this)); - ReferenceCollector.CollectReferences(ObjectsToProcess); + ReferenceCollector.CollectReferences(ArrayStruct); #if UE_BUILD_DEBUG - FClusterArrayPool::Get().CheckLeaks(); + FGCArrayPool::Get().CheckLeaks(); #endif if (Cluster.Objects.Num()) @@ -973,9 +904,10 @@ bool VerifyClusterAssumptions(UObject* ClusterRootObject) { // Collect all objects referenced by cluster root and by all objects it's referencing FClusterVerifyReferenceProcessor Processor(ClusterRootObject); - TFastReferenceCollector, FClusterArrayPool> ReferenceCollector(Processor, FClusterArrayPool::Get()); - TArray ObjectsToProcess; + TFastReferenceCollector, FGCArrayPool> ReferenceCollector(Processor, FGCArrayPool::Get()); + FGCArrayStruct ArrayStruct; + TArray& ObjectsToProcess = ArrayStruct.ObjectsToSerialize; ObjectsToProcess.Add(ClusterRootObject); - ReferenceCollector.CollectReferences(ObjectsToProcess); + ReferenceCollector.CollectReferences(ArrayStruct); return Processor.NoExternalReferencesFound(); } diff --git a/Engine/Source/Runtime/CoreUObject/Private/UObject/UObjectGlobals.cpp b/Engine/Source/Runtime/CoreUObject/Private/UObject/UObjectGlobals.cpp index 55720b3dd5f9..1c282edaf734 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/UObject/UObjectGlobals.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/UObject/UObjectGlobals.cpp @@ -56,7 +56,7 @@ DEFINE_LOG_CATEGORY(LogUObjectGlobals); bool GIsSavingPackage = false; /** Object annotation used by the engine to keep track of which objects are selected */ -FUObjectAnnotationSparseBool GSelectedAnnotation; +FUObjectAnnotationSparseBool GSelectedObjectAnnotation; DEFINE_STAT(STAT_InitProperties); DEFINE_STAT(STAT_ConstructObject); @@ -100,6 +100,7 @@ FCoreUObjectDelegates::FIsPackageOKToSaveDelegate FCoreUObjectDelegates::IsPacka FCoreUObjectDelegates::FAutoPackageBackupDelegate FCoreUObjectDelegates::AutoPackageBackupDelegate; FCoreUObjectDelegates::FOnPackageReloaded FCoreUObjectDelegates::OnPackageReloaded; +FCoreUObjectDelegates::FNetworkFileRequestPackageReload FCoreUObjectDelegates::NetworkFileRequestPackageReload; FCoreUObjectDelegates::FOnPreObjectPropertyChanged FCoreUObjectDelegates::OnPreObjectPropertyChanged; FCoreUObjectDelegates::FOnObjectPropertyChanged FCoreUObjectDelegates::OnObjectPropertyChanged; @@ -112,7 +113,7 @@ FCoreUObjectDelegates::FOnAssetLoaded FCoreUObjectDelegates::OnAssetLoaded; FCoreUObjectDelegates::FOnObjectSaved FCoreUObjectDelegates::OnObjectSaved; #endif // WITH_EDITOR -FCoreUObjectDelegates::FOnRedirectorFollowed FCoreUObjectDelegates::RedirectorFollowed; + FSimpleMulticastDelegate FCoreUObjectDelegates::PreGarbageCollect; FSimpleMulticastDelegate FCoreUObjectDelegates::PostGarbageCollect; @@ -124,12 +125,13 @@ FCoreUObjectDelegates::FPreLoadMapDelegate FCoreUObjectDelegates::PreLoadMap; FCoreUObjectDelegates::FPostLoadMapDelegate FCoreUObjectDelegates::PostLoadMapWithWorld; PRAGMA_DISABLE_DEPRECATION_WARNINGS FSimpleMulticastDelegate FCoreUObjectDelegates::PostLoadMap; +FCoreUObjectDelegates::FStringAssetReferenceLoaded FCoreUObjectDelegates::StringAssetReferenceLoaded; +FCoreUObjectDelegates::FStringAssetReferenceSaving FCoreUObjectDelegates::StringAssetReferenceSaving; +FCoreUObjectDelegates::FOnRedirectorFollowed FCoreUObjectDelegates::RedirectorFollowed; PRAGMA_ENABLE_DEPRECATION_WARNINGS FSimpleMulticastDelegate FCoreUObjectDelegates::PostDemoPlay; FCoreUObjectDelegates::FOnLoadObjectsOnTop FCoreUObjectDelegates::ShouldLoadOnTop; -FCoreUObjectDelegates::FStringAssetReferenceLoaded FCoreUObjectDelegates::StringAssetReferenceLoaded; -FCoreUObjectDelegates::FStringAssetReferenceSaving FCoreUObjectDelegates::StringAssetReferenceSaving; FCoreUObjectDelegates::FPackageCreatedForLoad FCoreUObjectDelegates::PackageCreatedForLoad; FCoreUObjectDelegates::FPackageLoadedFromStringAssetReference FCoreUObjectDelegates::PackageLoadedFromStringAssetReference; FCoreUObjectDelegates::FGetPrimaryAssetIdForObject FCoreUObjectDelegates::GetPrimaryAssetIdForObject; @@ -881,8 +883,11 @@ UObject* StaticLoadObjectInternal(UClass* ObjectClass, UObject* InOuter, const T if (!Result) { - // now that we have one asset per package, we load the entire package whenever a single object is requested - LoadPackage(NULL, *InOuter->GetOutermost()->GetName(), LoadFlags & ~LOAD_Verify); + if (!InOuter->GetOutermost()->HasAnyPackageFlags(PKG_CompiledIn)) + { + // now that we have one asset per package, we load the entire package whenever a single object is requested + LoadPackage(NULL, *InOuter->GetOutermost()->GetName(), LoadFlags & ~LOAD_Verify); + } // now, find the object in the package Result = StaticFindObjectFast(ObjectClass, InOuter, *StrName); @@ -1122,12 +1127,21 @@ UPackage* LoadPackageInternal(UPackage* InOuter, const TCHAR* InLongPackageNameO FName PackageFName(*InPackageName); + Result = FindObjectFast(nullptr, PackageFName); + if (!Result || Result->LinkerLoad || !Result->IsFullyLoaded()) { int32 RequestID = LoadPackageAsync(InName, nullptr, *InPackageName); FlushAsyncLoading(RequestID); } - Result = FindObjectFast(nullptr, PackageFName); + if (InOuter) + { + return InOuter; + } + if (!Result) + { + Result = FindObjectFast(nullptr, PackageFName); + } return Result; } @@ -1224,12 +1238,28 @@ UPackage* LoadPackageInternal(UPackage* InOuter, const TCHAR* InLongPackageNameO }; #if WITH_EDITORONLY_DATA - if (!(LoadFlags & (LOAD_IsVerifying|LOAD_EditorOnly)) && - (!ImportLinker || !ImportLinker->GetSerializedProperty() || !ImportLinker->GetSerializedProperty()->IsEditorOnlyProperty())) + if (!(LoadFlags & (LOAD_IsVerifying|LOAD_EditorOnly))) { - // If this package hasn't been loaded as part of import verification and there's no import linker or the - // currently serialized property is not editor-only mark this package as runtime. - Result->SetLoadedByEditorPropertiesOnly(false); + bool bIsEditorOnly = false; + UProperty* SerializingProperty = ImportLinker ? ImportLinker->GetSerializedProperty() : nullptr; + + // Check property parent chain + while (SerializingProperty) + { + if (SerializingProperty->IsEditorOnlyProperty()) + { + bIsEditorOnly = true; + break; + } + SerializingProperty = Cast(SerializingProperty->GetOuter()); + } + + if (!bIsEditorOnly) + { + // If this package hasn't been loaded as part of import verification and there's no import linker or the + // currently serialized property is not editor-only mark this package as runtime. + Result->SetLoadedByEditorPropertiesOnly(false); + } } #endif @@ -1769,17 +1799,7 @@ FName MakeUniqueObjectName( UObject* Parent, UClass* Class, FName InBaseName/*=N */ FName MakeObjectNameFromDisplayLabel(const FString& DisplayLabel, const FName CurrentObjectName) { - FString GeneratedName = DisplayLabel; - - // Convert the display label, which may consist of just about any possible character, into a - // suitable name for a UObject (remove whitespace, certain symbols, etc.) - { - for( int32 BadCharacterIndex = 0; BadCharacterIndex < ARRAY_COUNT( INVALID_OBJECTNAME_CHARACTERS ) - 1; ++BadCharacterIndex ) - { - const TCHAR TestChar[2] = { INVALID_OBJECTNAME_CHARACTERS[ BadCharacterIndex ], 0 }; - const int32 NumReplacedChars = GeneratedName.ReplaceInline( TestChar, TEXT( "" ) ); - } - } + FString GeneratedName = SlugStringForValidName(DisplayLabel); // If the current object name (without a number) already matches our object's name, then use the existing name if( CurrentObjectName.GetPlainNameString() == GeneratedName ) @@ -3026,76 +3046,7 @@ void FObjectInitializer::InitProperties(UObject* Obj, UClass* DefaultsClass, UOb if (bCanUsePostConstructLink) { // Initialize remaining property values from defaults using an explicit custom post-construction property list returned by the class object. - if (const FCustomPropertyListNode* CustomPropertyList = Class->GetCustomPropertyListForPostConstruction()) - { - InitPropertiesFromCustomList(CustomPropertyList, Class, (uint8*)Obj, (uint8*)DefaultData); - } - } - } -} - -void FObjectInitializer::InitPropertiesFromCustomList(const FCustomPropertyListNode* InPropertyList, UStruct* InStruct, uint8* DataPtr, const uint8* DefaultDataPtr) -{ - for (const FCustomPropertyListNode* CustomPropertyListNode = InPropertyList; CustomPropertyListNode; CustomPropertyListNode = CustomPropertyListNode->PropertyListNext) - { - uint8* PropertyValue = CustomPropertyListNode->Property->ContainerPtrToValuePtr(DataPtr, CustomPropertyListNode->ArrayIndex); - const uint8* DefaultPropertyValue = CustomPropertyListNode->Property->ContainerPtrToValuePtr(DefaultDataPtr, CustomPropertyListNode->ArrayIndex); - - if (const UStructProperty* StructProperty = Cast(CustomPropertyListNode->Property)) - { - // This should never be NULL; we should not be recording the StructProperty without at least one sub property, but we'll verify just to be sure. - if (ensure(CustomPropertyListNode->SubPropertyList != nullptr)) - { - InitPropertiesFromCustomList(CustomPropertyListNode->SubPropertyList, StructProperty->Struct, PropertyValue, DefaultPropertyValue); - } - } - else if (const UArrayProperty* ArrayProperty = Cast(CustomPropertyListNode->Property)) - { - // Note: The sub-property list can be NULL here; in that case only the array size will differ from the default value, but the elements themselves will simply be initialized to defaults. - InitArrayPropertyFromCustomList(ArrayProperty, CustomPropertyListNode->SubPropertyList, PropertyValue, DefaultPropertyValue); - } - else - { - CustomPropertyListNode->Property->CopySingleValue(PropertyValue, DefaultPropertyValue); - } - } -} - -void FObjectInitializer::InitArrayPropertyFromCustomList(const UArrayProperty* ArrayProperty, const FCustomPropertyListNode* InPropertyList, uint8* DataPtr, const uint8* DefaultDataPtr) -{ - FScriptArrayHelper DstArrayValueHelper(ArrayProperty, DataPtr); - FScriptArrayHelper SrcArrayValueHelper(ArrayProperty, DefaultDataPtr); - - const int32 SrcNum = SrcArrayValueHelper.Num(); - const int32 DstNum = DstArrayValueHelper.Num(); - - if (SrcNum > DstNum) - { - DstArrayValueHelper.AddValues(SrcNum - DstNum); - } - else if (SrcNum < DstNum) - { - DstArrayValueHelper.RemoveValues(SrcNum, DstNum - SrcNum); - } - - for (const FCustomPropertyListNode* CustomArrayPropertyListNode = InPropertyList; CustomArrayPropertyListNode; CustomArrayPropertyListNode = CustomArrayPropertyListNode->PropertyListNext) - { - int32 ArrayIndex = CustomArrayPropertyListNode->ArrayIndex; - - uint8* DstArrayItemValue = DstArrayValueHelper.GetRawPtr(ArrayIndex); - const uint8* SrcArrayItemValue = SrcArrayValueHelper.GetRawPtr(ArrayIndex); - - if (const UStructProperty* InnerStructProperty = Cast(ArrayProperty->Inner)) - { - InitPropertiesFromCustomList(CustomArrayPropertyListNode->SubPropertyList, InnerStructProperty->Struct, DstArrayItemValue, SrcArrayItemValue); - } - else if (const UArrayProperty* InnerArrayProperty = Cast(ArrayProperty->Inner)) - { - InitArrayPropertyFromCustomList(InnerArrayProperty, CustomArrayPropertyListNode->SubPropertyList, DstArrayItemValue, SrcArrayItemValue); - } - else - { - ArrayProperty->Inner->CopyCompleteValue(DstArrayItemValue, SrcArrayItemValue); + Class->InitPropertiesFromCustomList((uint8*)Obj, (uint8*)DefaultData); } } } diff --git a/Engine/Source/Runtime/CoreUObject/Private/UObject/WeakObjectPtr.cpp b/Engine/Source/Runtime/CoreUObject/Private/UObject/WeakObjectPtr.cpp index 46532c3ae0ed..2fe7b7c28920 100644 --- a/Engine/Source/Runtime/CoreUObject/Private/UObject/WeakObjectPtr.cpp +++ b/Engine/Source/Runtime/CoreUObject/Private/UObject/WeakObjectPtr.cpp @@ -107,8 +107,7 @@ void FWeakObjectPtr::Serialize(FArchive& Ar) // However, when modifying both kinds of references we want to serialize and writeback the updated value. if (!Ar.IsObjectReferenceCollector() || Ar.IsModifyingWeakAndStrongReferences()) { - // Downcast from UObjectBase to UObject - UObject* Object = static_cast(Get(true)); + UObject* Object = Get(true); Ar << Object; diff --git a/Engine/Source/Runtime/CoreUObject/Public/CoreUObjectSharedPCH.h b/Engine/Source/Runtime/CoreUObject/Public/CoreUObjectSharedPCH.h index ea211ef00ae7..7268db063c87 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/CoreUObjectSharedPCH.h +++ b/Engine/Source/Runtime/CoreUObject/Public/CoreUObjectSharedPCH.h @@ -34,7 +34,6 @@ #include "Templates/EnableIf.h" #include "Templates/RemoveReference.h" #include "Templates/TypeCompatibleBytes.h" -#include "Templates/AlignOf.h" #include "Templates/ChooseClass.h" #include "Templates/IntegralConstant.h" #include "Templates/IsClass.h" diff --git a/Engine/Source/Runtime/CoreUObject/Public/Misc/ExclusiveLoadPackageTimeTracker.h b/Engine/Source/Runtime/CoreUObject/Public/Misc/ExclusiveLoadPackageTimeTracker.h index 86e1cd45804b..4349dfc7f586 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/Misc/ExclusiveLoadPackageTimeTracker.h +++ b/Engine/Source/Runtime/CoreUObject/Public/Misc/ExclusiveLoadPackageTimeTracker.h @@ -130,6 +130,14 @@ public: #endif } + /** Resets the data. */ + FORCEINLINE static void ResetReport() + { +#if WITH_LOADPACKAGE_TIME_TRACKER + Get().InternalResetReport(); +#endif + } + /** Returns the load time for the specified package, excluding its dependencies */ FORCEINLINE static double GetExclusiveLoadTime(FName PackageName) { @@ -190,6 +198,9 @@ private: /** Displays the data gathered in various ways. */ COREUOBJECT_API void InternalDumpReport() const; + /** Resets the data */ + COREUOBJECT_API void InternalResetReport(); + /** Returns the load time for the specified package, excluding its dependencies */ COREUOBJECT_API double InternalGetExclusiveLoadTime(FName PackageName) const; @@ -202,6 +213,9 @@ private: /** Handler for the DumpReportCommand */ void DumpReportCommandHandler(const TArray& Args); + /** Handler for the ResetReportCommand */ + void ResetReportCommandHandler(const TArray& Args); + /** Time stack for tracked code sections. Does not have inclusive time set. That is done in the LoadTimes map. */ TArray TimeStack; @@ -221,5 +235,8 @@ private: /** Auto-registered console command to call DumpReport() */ const FAutoConsoleCommand DumpReportCommand; + /** Auto-registered console command to call ResetReport() */ + const FAutoConsoleCommand ResetReportCommand; + #endif // WITH_LOADPACKAGE_TIME_TRACKER }; diff --git a/Engine/Source/Runtime/CoreUObject/Public/Misc/PackageName.h b/Engine/Source/Runtime/CoreUObject/Public/Misc/PackageName.h index 9792c2ff1ec3..4a73d25e6981 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/Misc/PackageName.h +++ b/Engine/Source/Runtime/CoreUObject/Public/Misc/PackageName.h @@ -36,7 +36,8 @@ public: static FName* FindScriptPackageName(FName InShortName); /** - * Tries to convert the supplied filename to long package name. Will attempt to find the package on disk (very slow). + * Tries to convert the supplied relative or absolute filename to a long package name/path starting with a root like /game + * This works on both package names and directories, and it does not validate that it actually exists on disk. * * @param InFilename Filename to convert. * @param OutPackageName The resulting long package name if the conversion was successful. @@ -44,37 +45,52 @@ public: * @return Returns true if the supplied filename properly maps to one of the long package roots. */ static bool TryConvertFilenameToLongPackageName(const FString& InFilename, FString& OutPackageName, FString* OutFailureReason = nullptr); + /** * Converts the supplied filename to long package name. - * Throws a fatal error if the conversion is not successfull. + * Throws a fatal error if the conversion is not successful. * * @param InFilename Filename to convert. * @return Long package name. */ static FString FilenameToLongPackageName(const FString& InFilename); + /** * Tries to convert a long package name to a file name with the supplied extension. + * This can be called on package paths as well, provide no extension in that case * * @param InLongPackageName Long Package Name * @param InExtension Package extension. * @return Package filename. */ static bool TryConvertLongPackageNameToFilename(const FString& InLongPackageName, FString& OutFilename, const FString& InExtension = TEXT("")); + /** * Converts a long package name to a file name with the supplied extension. + * Throws a fatal error if the conversion is not successful. * * @param InLongPackageName Long Package Name * @param InExtension Package extension. * @return Package filename. */ static FString LongPackageNameToFilename(const FString& InLongPackageName, const FString& InExtension = TEXT("")); + /** * Returns the path to the specified package, excluding the short package name * - * @param InLongPackageName Package Name. - * @return The path to the specified package. + * @param InLongPackageName Long Package Name. + * @return The path containing the specified package. */ static FString GetLongPackagePath(const FString& InLongPackageName); + + /** + * Returns the clean asset name for the specified package, same as GetShortName + * + * @param InLongPackageName Long Package Name + * @return Clean asset name. + */ + static FString GetLongPackageAssetName(const FString& InLongPackageName); + /** * Convert a long package name into root, path, and name components * @@ -86,21 +102,7 @@ public: * @return True if the conversion was possible, false otherwise */ static bool SplitLongPackageName(const FString& InLongPackageName, FString& OutPackageRoot, FString& OutPackagePath, FString& OutPackageName, const bool bStripRootLeadingSlash = false); - /** - * Returns the clean asset name for the specified package - * - * @param InLongPackageName Long Package Name - * @return Clean asset name. - */ - static FString GetLongPackageAssetName(const FString& InLongPackageName); - /** - * Convert a root path to the content path associated with it - * Similar to TryConvertLongPackageNameToFilename except doesn't require a file just returns the pat - * See also RegisterMountPoint and UnRegisterMountPoint - * @param RootPath The package root path, eg "/Game/" - * @param OutContentPath The path from the mount point to the package, eg "Maps/TestMaps/ - */ - static bool ConvertRootPathToContentPath(const FString& RootPath, FString& OutContentPath); + /** * Returns true if the path starts with a valid root (i.e. /Game/, /Engine/, etc) and contains no illegal characters. * @@ -109,7 +111,19 @@ public: * @param OutReason When returning false, this will provide a description of what was wrong with the name. * @return true if a valid long package name */ - static bool IsValidLongPackageName(const FString& InLongPackageName, bool bIncludeReadOnlyRoots = false, FText* OutReason = NULL); + static bool IsValidLongPackageName(const FString& InLongPackageName, bool bIncludeReadOnlyRoots = false, FText* OutReason = nullptr); + + /** + * Returns true if the path starts with a valid root (i.e. /Game/, /Engine/, etc) and contains no illegal characters. + * This validates that the packagename is valid, and also makes sure the object after package name is also correct. + * This will return false if passed a path starting with Classname' + * + * @param InObjectPath The object path to test + * @param OutReason When returning false, this will provide a description of what was wrong with the name. + * @return true if a valid object path + */ + static bool IsValidObjectPath(const FString& InObjectPath, FText* OutReason = nullptr); + /** * Checks if the given string is a long package name or not. * @@ -117,20 +131,16 @@ public: * @return true if the given name is a long package name, false otherwise. */ static bool IsShortPackageName(const FString& PossiblyLongName); - /** - * Checks if the given name is a long package name or not. - * - * @param PossiblyLongName Package name. - * @return true if the given name is a long package name, false otherwise. - */ static bool IsShortPackageName(const FName PossiblyLongName); + /** * Converts package name to short name. * - * @param Package Package which name to convert. + * @param Package Package with name to convert. * @return Short package name. */ static FString GetShortName(const UPackage* Package); + /** * Converts package name to short name. * @@ -138,20 +148,9 @@ public: * @return Short package name. */ static FString GetShortName(const FString& LongName); - /** - * Converts package name to short name. - * - * @param LongName Package name to convert. - * @return Short package name. - */ static FString GetShortName(const FName& LongName); - /** - * Converts package name to short name. - * - * @param LongName Package name to convert. - * @return Short package name. - */ static FString GetShortName(const TCHAR* LongName); + /** * Converts package name to short name. * @@ -159,33 +158,22 @@ public: * @return Short package name. */ static FName GetShortFName(const FString& LongName); - /** - * Converts package name to short name. - * - * @param LongName Package name to convert. - * @return Short package name. - */ static FName GetShortFName(const FName& LongName); - /** - * Converts package name to short name. - * - * @param LongName Package name to convert. - * @return Short package name. - */ static FName GetShortFName(const TCHAR* LongName); + /** * This will insert a mount point at the head of the search chain (so it can overlap an existing mount point and win). * - * @param RootPath Root Path. - * @param ContentPath Content Path. + * @param RootPath Logical Root Path. + * @param ContentPath Content Path on disk. */ static void RegisterMountPoint(const FString& RootPath, const FString& ContentPath); /** * This will remove a previously inserted mount point. * - * @param RootPath Root Path. - * @param ContentPath Content Path. + * @param RootPath Logical Root Path. + * @param ContentPath Content Path on disk. */ static void UnRegisterMountPoint(const FString& RootPath, const FString& ContentPath); @@ -245,6 +233,15 @@ public: */ static FString GetDelegateResolvedPackagePath(const FString& InSourcePackagePath); + /** + * Gets the source version of a localized long package path (it is also safe to pass non-localized paths into this function). + * + * @param InLocalizedPackagePath Path to the localized package. + * + * @returns Source package path. + */ + static FString GetSourcePackagePath(const FString& InLocalizedPackagePath); + /** * Gets the localized version of a long package path for the current culture, or returns the source package if there is no suitable localized package. * @@ -264,19 +261,10 @@ public: */ static FString GetLocalizedPackagePath(const FString& InSourcePackagePath, const FString& InCultureName); - /** - * Strips all path and extension information from a relative or fully qualified file name. - * - * @param InPathName a relative or fully qualified file name - * - * @return the passed in string, stripped of path and extensions - */ - static FString PackageFromPath(const TCHAR* InPathName); - /** * Returns the file extension for packages containing assets. * - * @return file extension for asset pacakges ( dot included ) + * @return file extension for asset packages ( dot included ) */ static FORCEINLINE const FString& GetAssetPackageExtension() { @@ -285,7 +273,7 @@ public: /** * Returns the file extension for packages containing assets. * - * @return file extension for asset pacakges ( dot included ) + * @return file extension for asset packages ( dot included ) */ static FORCEINLINE const FString& GetMapPackageExtension() { @@ -418,6 +406,21 @@ public: */ static bool FindPackageFileWithoutExtension(const FString& InPackageFilename, FString& OutFilename); + /** + * Converts a long package name to the case it exists as on disk. + * + * @param LongPackageName The long package name + * @param Extension The extension for this package + * @return True if the long package name was fixed up, false otherwise + */ + static bool FixPackageNameCase(FString& LongPackageName, const FString& Extension); + + DEPRECATED(4.17, "Deprecated. Call TryConvertLongPackageNameToFilename instead, which also works on nested paths") + static bool ConvertRootPathToContentPath(const FString& RootPath, FString& OutContentPath); + + DEPRECATED(4.17, "Deprecated. Call TryConvertFilenameToLongPackageName instead") + static FString PackageFromPath(const TCHAR* InPathName); + private: static FString AssetPackageExtension; diff --git a/Engine/Source/Runtime/CoreUObject/Public/Misc/RedirectCollector.h b/Engine/Source/Runtime/CoreUObject/Public/Misc/RedirectCollector.h index 3e1ba38d90de..d080c5b3686d 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/Misc/RedirectCollector.h +++ b/Engine/Source/Runtime/CoreUObject/Public/Misc/RedirectCollector.h @@ -1,46 +1,16 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. /*============================================================================= - CallbackDevice.h: Allows the engine to do callbacks into the editor + RedirectCollector: Editor-only global object that handles resolving redirectors and handling string asset cooking rules =============================================================================*/ #pragma once #include "CoreMinimal.h" +#include "Misc/ScopeLock.h" -/** - * Container struct that holds info about a redirector that was followed. - * Cannot contain a pointer to the actual UObjectRedirector as the object - * will be GC'd before it is used - */ -struct FRedirection -{ - FString PackageFilename; - FString RedirectorName; - FString RedirectorPackageFilename; - FString DestinationObjectName; +#if WITH_EDITOR - bool operator==(const FRedirection& Other) const - { - return PackageFilename == Other.PackageFilename && - RedirectorName == Other.RedirectorName && - RedirectorPackageFilename == Other.RedirectorPackageFilename; - } - - friend FArchive& operator<<(FArchive& Ar, FRedirection& Redir) - { - Ar << Redir.PackageFilename; - Ar << Redir.RedirectorName; - Ar << Redir.RedirectorPackageFilename; - Ar << Redir.DestinationObjectName; - return Ar; - } -}; - -/** - * Callback structure to respond to redirect-followed callbacks and store - * the information - */ class COREUOBJECT_API FRedirectCollector { private: @@ -112,27 +82,11 @@ private: public: /** - * Responds to FCoreDelegates::RedirectorFollowed. Records all followed redirections - * so they can be cleaned later. - * - * @param InString Name of the package that pointed to the redirect - * @param InObject The UObjectRedirector that was followed - */ - void OnRedirectorFollowed( const FString& InString, UObject* InObject); - - /** - * Responds to FCoreDelegates::StringAssetReferenceLoaded. Just saves it off for later use. + * Called from FStringAssetReference::PostLoadPath, registers this for later querying * @param InString Name of the asset that was loaded */ void OnStringAssetReferenceLoaded(const FString& InString); - /** - * Responds to FCoreDelegates::StringAssetReferenceSaved. Runs the string through the remap table. - * @param InString Name of the asset that will be saved - * @return actual value to save - */ - FString OnStringAssetReferenceSaved(const FString& InString); - /** * Load the string asset references to resolve them, add that to the remap table, and empty the array * @param FilterPackage If set, only fixup references that were created by FilterPackage. If empty, clear all of them @@ -142,14 +96,21 @@ public: void ResolveStringAssetReference(FName FilterPackage = NAME_None, bool bProcessAlreadyResolvedPackages = true); /** - * Returns the list of packages that would be loaded by ResolveStringAssetReference - * @param FilterPackage Return references made by loading this package. If passed null will return all references made before package loading - * @param ReferencedPackages Return list of packages referenced by FilterPackage + * Returns the list of packages referenced by string asset references loaded by FilterPackage, and remove them from the internal list + * @param FilterPackage Return references made by loading this package. If passed null will return all references made with no explicit package + * @param OutReferencedPackages Return list of packages referenced by FilterPackage + * @param bGetEditorOnly If true will return references loaded by editor only objects, if false it will not */ - void GetStringAssetReferencePackageList(FName FilterPackage, TSet& ReferencedPackages); + void ProcessStringAssetReferencePackageList(FName FilterPackage, bool bGetEditorOnly, TSet& OutReferencedPackages); - /** Adds a new mapping for redirector path to destination path, this is useful if you have external data about redirection */ - void AddStringAssetReferenceRedirection(const FString& OriginalPath, const FString& RedirectedPath); + /** Adds a new mapping for redirector path to destination path, this is called from the Asset Registry to register all redirects it knows about */ + void AddAssetPathRedirection(const FString& OriginalPath, const FString& RedirectedPath); + + /** Removes an asset path redirection, call this when deleting redirectors */ + void RemoveAssetPathRedirection(const FString& OriginalPath); + + /** Returns a remapped asset path, if it returns null there is no relevant redirector */ + FString* GetAssetPathRedirection(const FString& OriginalPath); /** * Do we have any references to resolve. @@ -160,19 +121,11 @@ public: return StringAssetReferences.Num() > 0; } - const TArray& GetRedirections() const - { - return Redirections; - } - + /** Writes out log info for how long string asset references took to resolve */ void LogTimers() const; -public: - /** If not an empty string, only fixup redirects in this package */ - FString FileToFixup; - - /** A gathered list of all non-script referenced redirections */ - TArray Redirections; + DEPRECATED(4.17, "OnStringAssetReferenceSaved is deprecated, call GetAssetPathRedirection") + FString OnStringAssetReferenceSaved(const FString& InString); private: @@ -180,12 +133,14 @@ private: TMultiMap StringAssetReferences; /** When saving, apply this remapping to all string asset references */ - TMap StringAssetRemap; -#if WITH_EDITOR + TMap AssetPathRedirectionMap; TSet AlreadyRemapped; -#endif + + /** For StringAssetReferences map */ + FCriticalSection CriticalSection; }; // global redirect collector callback structure COREUOBJECT_API extern FRedirectCollector GRedirectCollector; +#endif // WITH_EDITOR \ No newline at end of file diff --git a/Engine/Source/Runtime/CoreUObject/Public/Misc/StringAssetReference.h b/Engine/Source/Runtime/CoreUObject/Public/Misc/StringAssetReference.h index 560ef4027ecc..29d09fc33fc5 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/Misc/StringAssetReference.h +++ b/Engine/Source/Runtime/CoreUObject/Public/Misc/StringAssetReference.h @@ -5,6 +5,7 @@ #include "CoreMinimal.h" #include "HAL/ThreadSafeCounter.h" #include "UObject/Class.h" +#include "HAL/ThreadSingleton.h" /** * A struct that contains a string reference to an asset on disk. @@ -14,13 +15,7 @@ */ struct COREUOBJECT_API FStringAssetReference { - /** Asset path */ - DEPRECATED(4.9, "Please don't use AssetLongPathname directly. Instead use SetPath and ToString methods.") - FString AssetLongPathname; - - FStringAssetReference() - { - } + FStringAssetReference() {} /** Construct from another asset reference */ FStringAssetReference(const FStringAssetReference& Other) @@ -37,9 +32,6 @@ struct COREUOBJECT_API FStringAssetReference /** Construct from an existing object in memory */ FStringAssetReference(const UObject* InObject); -PRAGMA_DISABLE_DEPRECATION_WARNINGS - - /** Destructor, in deprecation block to avoid warnings */ ~FStringAssetReference() {} /** Returns string representation of reference, in form /package/path.assetname[.objectname] */ @@ -48,8 +40,6 @@ PRAGMA_DISABLE_DEPRECATION_WARNINGS return AssetLongPathname; } -PRAGMA_ENABLE_DEPRECATION_WARNINGS - /** Returns /package/path, leaving off the asset name */ FString GetLongPackageName() const { @@ -113,6 +103,15 @@ PRAGMA_ENABLE_DEPRECATION_WARNINGS bool ImportTextItem( const TCHAR*& Buffer, int32 PortFlags, UObject* Parent, FOutputDevice* ErrorText ); bool SerializeFromMismatchedTag(struct FPropertyTag const& Tag, FArchive& Ar); + /** Serializes the internal path and also handles save/PIE fixups. Call this from the archiver overrides */ + void SerializePath(FArchive& Ar, bool bSkipSerializeIfArchiveHasSize = false); + + /** Fixes up string asset reference for saving, call if saving with a method that skips SerializePath. This can modify the path */ + void PreSavePath(); + + /** Handles when a string asset reference has been loaded, call if loading with a method that skips SerializePath. This does not modify path but might call callbacks */ + void PostLoadPath() const; + FORCEINLINE friend uint32 GetTypeHash(FStringAssetReference const& This) { return GetTypeHash(This.ToString()); @@ -136,6 +135,9 @@ PRAGMA_ENABLE_DEPRECATION_WARNINGS static void ClearPackageNamesBeingDuplicatedForPIE(); private: + /** Asset path */ + FString AssetLongPathname; + /** Fixes up this StringAssetReference to add or remove the PIE prefix depending on what is currently active */ void FixupForPIE(); @@ -144,5 +146,66 @@ private: /** Package names currently being duplicated, needed by FixupForPIE */ static TArray PackageNamesBeingDuplicatedForPIE; + + friend COREUOBJECT_API UScriptStruct* Z_Construct_UScriptStruct_FStringAssetReference(); }; +enum class EStringAssetReferenceCollectType : uint8 +{ + /** References is not tracked in any situation, transient reference */ + NeverCollect, + /** Editor only reference, this is tracked for redirector fixup but not for cooking */ + EditorOnlyCollect, + /** Game reference, this is gathered for both redirector fixup and cooking */ + AlwaysCollect, +}; + +class COREUOBJECT_API FStringAssetReferenceThreadContext : public TThreadSingleton +{ + friend TThreadSingleton; + friend struct FStringAssetReferenceSerializationScope; + + FStringAssetReferenceThreadContext() {} + + struct FSerializationOptions + { + FName PackageName; + FName PropertyName; + EStringAssetReferenceCollectType CollectType; + + FSerializationOptions() : CollectType(EStringAssetReferenceCollectType::AlwaysCollect) {} + FSerializationOptions(FName InPackageName, FName InPropertyName, EStringAssetReferenceCollectType InCollectType) : PackageName(InPackageName), PropertyName(InPropertyName), CollectType(InCollectType) {} + }; + + TArray OptionStack; +public: + /** + * Returns the current serialization options that were added using SerializationScope or LinkerLoad + * + * @param OutPackageName Package that this string asset belongs to + * @param OutPropertyName Property that this string asset reference belongs to + * @param OutCollectType Type of collecting that should be done + */ + bool GetSerializationOptions(FName& OutPackageName, FName& OutPropertyName, EStringAssetReferenceCollectType& OutCollectType) const; +}; + +/** Helper class to set and restore serialization options for string asset references */ +struct FStringAssetReferenceSerializationScope +{ + /** + * Create a new serialization scope, which affects the way that string asset references are saved + * + * @param SerializingPackageName Package that this string asset belongs to + * @param SerializingPropertyName Property that this string asset reference belongs to + * @param CollectType Set type of collecting that should be done, can be used to disable tracking entirely + */ + FStringAssetReferenceSerializationScope(FName SerializingPackageName, FName SerializingPropertyName, EStringAssetReferenceCollectType CollectType) + { + FStringAssetReferenceThreadContext::Get().OptionStack.Emplace(SerializingPackageName, SerializingPropertyName, CollectType); + } + + ~FStringAssetReferenceSerializationScope() + { + FStringAssetReferenceThreadContext::Get().OptionStack.Pop(); + } +}; \ No newline at end of file diff --git a/Engine/Source/Runtime/CoreUObject/Public/Serialization/DuplicatedDataReader.h b/Engine/Source/Runtime/CoreUObject/Public/Serialization/DuplicatedDataReader.h index a3767b6cf35e..470373176883 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/Serialization/DuplicatedDataReader.h +++ b/Engine/Source/Runtime/CoreUObject/Public/Serialization/DuplicatedDataReader.h @@ -7,7 +7,6 @@ #include "UObject/UObjectAnnotation.h" #include "Serialization/DuplicatedObject.h" -class FAssetPtr; class FLazyObjectPtr; struct FStringAssetReference; @@ -31,7 +30,6 @@ private: virtual FArchive& operator<<(FName& N); virtual FArchive& operator<<(UObject*& Object); virtual FArchive& operator<<(FLazyObjectPtr& LazyObjectPtr); - virtual FArchive& operator<<(FAssetPtr& AssetPtr); virtual FArchive& operator<<(FStringAssetReference& StringAssetReference); void SerializeFail(); diff --git a/Engine/Source/Runtime/CoreUObject/Public/Serialization/DuplicatedDataWriter.h b/Engine/Source/Runtime/CoreUObject/Public/Serialization/DuplicatedDataWriter.h index 79560d476bb1..3eed47dee7f0 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/Serialization/DuplicatedDataWriter.h +++ b/Engine/Source/Runtime/CoreUObject/Public/Serialization/DuplicatedDataWriter.h @@ -7,7 +7,6 @@ #include "UObject/UObjectAnnotation.h" #include "Serialization/DuplicatedObject.h" -class FAssetPtr; class FLazyObjectPtr; struct FObjectInstancingGraph; @@ -40,7 +39,6 @@ private: virtual FArchive& operator<<(FName& N); virtual FArchive& operator<<(UObject*& Object); virtual FArchive& operator<<(FLazyObjectPtr& LazyObjectPtr); - virtual FArchive& operator<<(FAssetPtr& AssetPtr); virtual void Serialize(void* Data,int64 Num) { diff --git a/Engine/Source/Runtime/CoreUObject/Public/Serialization/ObjectReader.h b/Engine/Source/Runtime/CoreUObject/Public/Serialization/ObjectReader.h index 1ff3ba82c202..a0f66fca65c2 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/Serialization/ObjectReader.h +++ b/Engine/Source/Runtime/CoreUObject/Public/Serialization/ObjectReader.h @@ -27,7 +27,7 @@ public: ArIgnoreArchetypeRef = bIgnoreArchetypeRef; #if USE_STABLE_LOCALIZATION_KEYS - if (GIsEditor && !(ArPortFlags & PPF_DuplicateForPIE)) + if (GIsEditor && !(ArPortFlags & (PPF_DuplicateVerbatim | PPF_DuplicateForPIE))) { SetLocalizationNamespace(TextNamespaceUtil::EnsurePackageNamespace(Obj)); } diff --git a/Engine/Source/Runtime/CoreUObject/Public/Serialization/ObjectWriter.h b/Engine/Source/Runtime/CoreUObject/Public/Serialization/ObjectWriter.h index 6a7cbb14828e..21fa69529cf7 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/Serialization/ObjectWriter.h +++ b/Engine/Source/Runtime/CoreUObject/Public/Serialization/ObjectWriter.h @@ -28,7 +28,7 @@ public: ArPortFlags |= AdditionalPortFlags; #if USE_STABLE_LOCALIZATION_KEYS - if (GIsEditor && !(ArPortFlags & PPF_DuplicateForPIE)) + if (GIsEditor && !(ArPortFlags & (PPF_DuplicateVerbatim | PPF_DuplicateForPIE))) { SetLocalizationNamespace(TextNamespaceUtil::EnsurePackageNamespace(Obj)); } diff --git a/Engine/Source/Runtime/CoreUObject/Public/Serialization/SerializedPropertyScope.h b/Engine/Source/Runtime/CoreUObject/Public/Serialization/SerializedPropertyScope.h index 5976ccfb8371..14d2d65ed5ef 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/Serialization/SerializedPropertyScope.h +++ b/Engine/Source/Runtime/CoreUObject/Public/Serialization/SerializedPropertyScope.h @@ -19,12 +19,16 @@ class FSerializedPropertyScope void PopEditorOnlyProperty(); #endif public: - FSerializedPropertyScope(FArchive& InAr, UProperty* InProperty) + FSerializedPropertyScope(FArchive& InAr, UProperty* InProperty, const UProperty* OnlyIfOldProperty = nullptr) : Ar(InAr) , Property(InProperty) { OldProperty = Ar.GetSerializedProperty(); - Ar.SetSerializedProperty(Property); + if (!OnlyIfOldProperty || OldProperty == OnlyIfOldProperty) + { + Ar.SetSerializedProperty(Property); + } + #if WITH_EDITORONLY_DATA PushEditorOnlyProperty(); #endif diff --git a/Engine/Source/Runtime/CoreUObject/Public/UObject/Class.h b/Engine/Source/Runtime/CoreUObject/Public/UObject/Class.h index 08adf5039d4c..fc16fbae8848 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/UObject/Class.h +++ b/Engine/Source/Runtime/CoreUObject/Public/UObject/Class.h @@ -940,7 +940,7 @@ public: { typedef TStructOpsTypeTraits TTraits; TCppStructOps() - : ICppStructOps(sizeof(CPPSTRUCT), ALIGNOF(CPPSTRUCT)) + : ICppStructOps(sizeof(CPPSTRUCT), alignof(CPPSTRUCT)) { } virtual bool HasNoopConstructor() override @@ -1294,7 +1294,7 @@ class COREUOBJECT_API UFunction : public UStruct DECLARE_WITHIN(UClass) public: // Persistent variables. - uint32 FunctionFlags; + EFunctionFlags FunctionFlags; uint16 RepOffset; // Variables in memory only. @@ -1351,8 +1351,8 @@ public: void Invoke(UObject* Obj, FFrame& Stack, RESULT_DECL); // Constructors. - explicit UFunction(const FObjectInitializer& ObjectInitializer, UFunction* InSuperFunction, uint32 InFunctionFlags = 0, uint16 InRepOffset = 0, SIZE_T ParamsSize = 0 ); - explicit UFunction(UFunction* InSuperFunction, uint32 InFunctionFlags = 0, uint16 InRepOffset = 0, SIZE_T ParamsSize = 0); + explicit UFunction(const FObjectInitializer& ObjectInitializer, UFunction* InSuperFunction, EFunctionFlags InFunctionFlags = FUNC_None, uint16 InRepOffset = 0, SIZE_T ParamsSize = 0 ); + explicit UFunction(UFunction* InSuperFunction, EFunctionFlags InFunctionFlags = FUNC_None, uint16 InRepOffset = 0, SIZE_T ParamsSize = 0); void InitializeDerivedMembers(); @@ -1379,7 +1379,7 @@ public: * @return true if the passed in flag is set, false otherwise * (including no flag passed in, unless the FlagsToCheck is CLASS_AllFlags) */ - FORCEINLINE bool HasAnyFunctionFlags( uint32 FlagsToCheck ) const + FORCEINLINE bool HasAnyFunctionFlags( EFunctionFlags FlagsToCheck ) const { return (FunctionFlags&FlagsToCheck) != 0 || FlagsToCheck == FUNC_AllFlags; } @@ -1390,7 +1390,7 @@ public: * @param FlagsToCheck Function flags to check for * @return true if all of the passed in flags are set (including no flags passed in), false otherwise */ - FORCEINLINE bool HasAllFunctionFlags( uint32 FlagsToCheck ) const + FORCEINLINE bool HasAllFunctionFlags( EFunctionFlags FlagsToCheck ) const { return ((FunctionFlags & FlagsToCheck) == FlagsToCheck); } @@ -1436,8 +1436,8 @@ class COREUOBJECT_API UDelegateFunction : public UFunction DECLARE_CASTED_CLASS_INTRINSIC(UDelegateFunction, UFunction, 0, TEXT("/Script/CoreUObject"), CASTCLASS_UDelegateFunction) DECLARE_WITHIN(UObject) public: - explicit UDelegateFunction(const FObjectInitializer& ObjectInitializer, UFunction* InSuperFunction, uint32 InFunctionFlags = 0, uint16 InRepOffset = 0, SIZE_T ParamsSize = 0); - explicit UDelegateFunction(UFunction* InSuperFunction, uint32 InFunctionFlags = 0, uint16 InRepOffset = 0, SIZE_T ParamsSize = 0); + explicit UDelegateFunction(const FObjectInitializer& ObjectInitializer, UFunction* InSuperFunction, EFunctionFlags InFunctionFlags = FUNC_None, uint16 InRepOffset = 0, SIZE_T ParamsSize = 0); + explicit UDelegateFunction(UFunction* InSuperFunction, EFunctionFlags InFunctionFlags = FUNC_None, uint16 InRepOffset = 0, SIZE_T ParamsSize = 0); }; /*----------------------------------------------------------------------------- @@ -2011,7 +2011,7 @@ public: int32 ClassUnique; // Class flags; See EClassFlags for more information - uint32 ClassFlags; + EClassFlags ClassFlags; // Cast flags used to accelerate dynamic_cast on objects of this type for common T EClassCastFlags ClassCastFlags; @@ -2027,7 +2027,8 @@ public: * Conditionally recompiles the class after loading, in case any dependencies were also newly loaded * @param ObjLoaded If set this is the list of objects that are currently loading, usualy GObjLoaded */ - virtual void ConditionalRecompileClass(TArray* ObjLoaded) {}; + virtual void ConditionalRecompileClass(TArray* ObjLoaded) {} + virtual void FlushCompilationQueueForLevel() {} #endif //WITH_EDITOR // @@ -2124,7 +2125,7 @@ public: // Constructors UClass(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); explicit UClass(const FObjectInitializer& ObjectInitializer, UClass* InSuperClass); - UClass( EStaticConstructor, FName InName, uint32 InSize, uint32 InClassFlags, EClassCastFlags InClassCastFlags, + UClass( EStaticConstructor, FName InName, uint32 InSize, EClassFlags InClassFlags, EClassCastFlags InClassCastFlags, const TCHAR* InClassConfigName, EObjectFlags InFlags, ClassConstructorType InClassConstructor, ClassVTableHelperCtorCallerType InClassVTableHelperCtorCaller, ClassAddReferencedObjectsType InClassAddReferencedObjects); @@ -2142,7 +2143,7 @@ public: **/ bool HotReloadPrivateStaticClass( uint32 InSize, - uint32 InClassFlags, + EClassFlags InClassFlags, EClassCastFlags InClassCastFlags, const TCHAR* InConfigName, ClassConstructorType InClassConstructor, @@ -2297,10 +2298,13 @@ public: } /** - * Override to return a linked list of properties with default values that differ from the parent default object. If non-NULL, only these properties will - * be copied post-construction. Otherwise, all properties will be copied to the new instance, even if the default value matches the inherited default value. - */ - virtual const FCustomPropertyListNode* GetCustomPropertyListForPostConstruction() const { return nullptr; } + * Helper method to assist with initializing object properties from an explicit list. + * + * @param InStruct the current scope for which the given property list applies + * @param DataPtr destination address (where to start copying values to) + * @param DefaultDataPtr source address (where to start copying the defaults data from) + */ + virtual void InitPropertiesFromCustomList(uint8* DataPtr, const uint8* DefaultDataPtr) {} /** * Get the name of the CDO for the this class @@ -2355,14 +2359,14 @@ public: /** * Used to safely check whether the passed in flag is set. * - * @param FlagToCheck Class flag to check for + * @param FlagsToCheck Class flag(s) to check for * * @return true if the passed in flag is set, false otherwise * (including no flag passed in, unless the FlagsToCheck is CLASS_AllFlags) */ - FORCEINLINE bool HasAnyClassFlags( uint32 FlagsToCheck ) const + FORCEINLINE bool HasAnyClassFlags( EClassFlags FlagsToCheck ) const { - return (ClassFlags & FlagsToCheck) != 0; + return EnumHasAnyFlags(ClassFlags, FlagsToCheck) != 0; } /** @@ -2371,9 +2375,9 @@ public: * @param FlagsToCheck Class flags to check for * @return true if all of the passed in flags are set (including no flags passed in), false otherwise */ - FORCEINLINE bool HasAllClassFlags( uint32 FlagsToCheck ) const + FORCEINLINE bool HasAllClassFlags( EClassFlags FlagsToCheck ) const { - return ((ClassFlags & FlagsToCheck) == FlagsToCheck); + return EnumHasAllFlags(ClassFlags, FlagsToCheck); } /** @@ -2381,7 +2385,7 @@ public: * * @return The class flags. */ - FORCEINLINE uint32 GetClassFlags() const + FORCEINLINE EClassFlags GetClassFlags() const { return ClassFlags; } @@ -2609,7 +2613,7 @@ public: UDynamicClass(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); explicit UDynamicClass(const FObjectInitializer& ObjectInitializer, UClass* InSuperClass); - UDynamicClass(EStaticConstructor, FName InName, uint32 InSize, uint32 InClassFlags, EClassCastFlags InClassCastFlags, + UDynamicClass(EStaticConstructor, FName InName, uint32 InSize, EClassFlags InClassFlags, EClassCastFlags InClassCastFlags, const TCHAR* InClassConfigName, EObjectFlags InFlags, ClassConstructorType InClassConstructor, ClassVTableHelperCtorCallerType InClassVTableHelperCtorCaller, ClassAddReferencedObjectsType InClassAddReferencedObjects); @@ -2693,7 +2697,7 @@ COREUOBJECT_API void GetPrivateStaticClassBody( UClass*& ReturnClass, void(*RegisterNativeFunc)(), uint32 InSize, - uint32 InClassFlags, + EClassFlags InClassFlags, EClassCastFlags InClassCastFlags, const TCHAR* InConfigName, UClass::ClassConstructorType InClassConstructor, diff --git a/Engine/Source/Runtime/CoreUObject/Public/UObject/CoreNet.h b/Engine/Source/Runtime/CoreUObject/Public/UObject/CoreNet.h index 836ad538b5a8..03d0c903dd57 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/UObject/CoreNet.h +++ b/Engine/Source/Runtime/CoreUObject/Public/UObject/CoreNet.h @@ -113,6 +113,7 @@ class COREUOBJECT_API FClassNetCacheMgr { public: FClassNetCacheMgr() : bDebugChecksum( false ), DebugChecksumIndent( 0 ) { } + ~FClassNetCacheMgr() { ClearClassNetCache(); } /** get the cached field to index mappings for the given class */ const FClassNetCache* GetClassNetCache( const UClass* Class ); diff --git a/Engine/Source/Runtime/CoreUObject/Public/UObject/CoreOnline.h b/Engine/Source/Runtime/CoreUObject/Public/UObject/CoreOnline.h index fcf8b2f3aebe..e914f09c3ef9 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/UObject/CoreOnline.h +++ b/Engine/Source/Runtime/CoreUObject/Public/UObject/CoreOnline.h @@ -199,6 +199,10 @@ public: { } + virtual ~FUniqueNetIdWrapper() + { + } + /** Assignment operator */ FUniqueNetIdWrapper& operator=(const FUniqueNetIdWrapper& Other) { diff --git a/Engine/Source/Runtime/CoreUObject/Public/UObject/CoreRedirects.h b/Engine/Source/Runtime/CoreUObject/Public/UObject/CoreRedirects.h index c62b9ad65911..968921a8be13 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/UObject/CoreRedirects.h +++ b/Engine/Source/Runtime/CoreUObject/Public/UObject/CoreRedirects.h @@ -24,7 +24,6 @@ enum class ECoreRedirectFlags : int32 Type_Function = 0x00000010, // UFunction Type_Property = 0x00000020, // UProperty Type_Package = 0x00000040, // UPackage - Type_Delegate = 0x00000080, // Dynamic delegate, special type of UFunction // Option flags, specify rules for this redirect Option_InstanceOnly = 0x00010000, // Only redirect instances of this type, not the type itself diff --git a/Engine/Source/Runtime/CoreUObject/Public/UObject/FastReferenceCollector.h b/Engine/Source/Runtime/CoreUObject/Public/UObject/FastReferenceCollector.h index 50ab970170ee..16a4e486432d 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/UObject/FastReferenceCollector.h +++ b/Engine/Source/Runtime/CoreUObject/Public/UObject/FastReferenceCollector.h @@ -17,6 +17,138 @@ struct FStackEntry; FastReferenceCollector.h: Unreal realtime garbage collection helpers =============================================================================*/ +/** Struct to hold the objects to serialize array and the list of weak references. This is allocated by ArrayPool */ +struct FGCArrayStruct +{ + TArray ObjectsToSerialize; + TArray WeakReferences; +}; + +/** + * Pool for reducing GC allocations + */ +class FGCArrayPool +{ +public: + + /** + * Gets the singleton instance of the FObjectArrayPool + * @return Pool singleton. + */ + FORCEINLINE static FGCArrayPool& Get() + { + static FGCArrayPool Singleton; + return Singleton; + } + + /** + * Gets an event from the pool or creates one if necessary. + * + * @return The array. + * @see ReturnToPool + */ + FORCEINLINE FGCArrayStruct* GetArrayStructFromPool() + { + FGCArrayStruct* Result = Pool.Pop(); + if (!Result) + { + Result = new FGCArrayStruct(); + } + check(Result); +#if UE_BUILD_DEBUG + NumberOfUsedArrays.Increment(); +#endif // UE_BUILD_DEBUG + return Result; + } + + /** + * Returns an array to the pool. + * + * @param Array The array to return. + * @see GetArrayFromPool + */ + FORCEINLINE void ReturnToPool(FGCArrayStruct* ArrayStruct) + { +#if UE_BUILD_DEBUG + const int32 CheckUsedArrays = NumberOfUsedArrays.Decrement(); + checkSlow(CheckUsedArrays >= 0); +#endif // UE_BUILD_DEBUG + check(ArrayStruct); + ArrayStruct->ObjectsToSerialize.Reset(); + Pool.Push(ArrayStruct); + } + + /** Performs memory cleanup */ + void Cleanup() + { +#if UE_BUILD_DEBUG + const int32 CheckUsedArrays = NumberOfUsedArrays.GetValue(); + checkSlow(CheckUsedArrays == 0); +#endif // UE_BUILD_DEBUG + + uint32 FreedMemory = 0; + TArray AllArrays; + Pool.PopAll(AllArrays); + for (FGCArrayStruct* ArrayStruct : AllArrays) + { + // If we are cleaning up with active weak references the weak references will get corrupted + checkSlow(ArrayStruct->WeakReferences.Num() == 0); + FreedMemory += ArrayStruct->ObjectsToSerialize.GetAllocatedSize(); + FreedMemory += ArrayStruct->WeakReferences.GetAllocatedSize(); + delete ArrayStruct; + } + UE_LOG(LogGarbage, Log, TEXT("Freed %ub from %d GC array pools."), FreedMemory, AllArrays.Num()); + } + + /** Clears weak references for everything in the pool */ + void ClearWeakReferences(bool bClearPools) + { + TArray AllArrays; + Pool.PopAll(AllArrays); + for (FGCArrayStruct* ArrayStruct : AllArrays) + { + for (UObject** WeakReference : ArrayStruct->WeakReferences) + { + UObject*& ReferencedObject = *WeakReference; + if (ReferencedObject && ReferencedObject->IsUnreachable()) + { + ReferencedObject = nullptr; + } + } + ArrayStruct->WeakReferences.Reset(); + + if (bClearPools) + { + delete ArrayStruct; + } + else + { + Pool.Push(ArrayStruct); + } + } + } + +#if UE_BUILD_DEBUG + void CheckLeaks() + { + // This function is called after GC has finished so at this point there should be no + // arrays used by GC and all should be returned to the pool + const int32 LeakedGCPoolArrays = NumberOfUsedArrays.GetValue(); + checkSlow(LeakedGCPoolArrays == 0); + } +#endif + +private: + + /** Holds the collection of recycled arrays. */ + TLockFreePointerListLIFO< FGCArrayStruct > Pool; + +#if UE_BUILD_DEBUG + /** Number of arrays currently acquired from the pool by GC */ + FThreadSafeCounter NumberOfUsedArrays; +#endif // UE_BUILD_DEBUG +}; + /** * Helper class that looks for UObject references by traversing UClass token stream and calls AddReferencedObjects. * Provides a generic way of processing references that is used by Unreal Engine garbage collection. @@ -44,8 +176,8 @@ struct FStackEntry; class FSampleArrayPool { static FSampleArrayPool& Get(); - TArray* GetArrayFromPool(); - void ReturnToPool(TArray* Array); + FGCArrayStruct* GetArrayStryctFromPool(); + void ReturnToPool(FGCArrayStruct* ArrayStruct); }; */ template @@ -57,7 +189,7 @@ private: { TFastReferenceCollector* Owner; ArrayPoolType& ArrayPool; - TLockFreePointerListUnordered, PLATFORM_CACHE_LINE_SIZE> Tasks; + TLockFreePointerListUnordered Tasks; FCriticalSection WaitingThreadsLock; TArray WaitingThreads; @@ -84,10 +216,10 @@ private: FORCENOINLINE void AddTask(const TArray* InObjectsToSerialize, int32 StartIndex, int32 NumObjects) { - TArray* ObjectsToSerialize(ArrayPool.GetArrayFromPool()); - ObjectsToSerialize->AddUninitialized(NumObjects); - FMemory::Memcpy(ObjectsToSerialize->GetData(), InObjectsToSerialize->GetData() + StartIndex, NumObjects * sizeof(UObject*)); - Tasks.Push(ObjectsToSerialize); + FGCArrayStruct* ArrayStruct = ArrayPool.GetArrayStructFromPool(); + ArrayStruct->ObjectsToSerialize.AddUninitialized(NumObjects); + FMemory::Memcpy(ArrayStruct->ObjectsToSerialize.GetData(), InObjectsToSerialize->GetData() + StartIndex, NumObjects * sizeof(UObject*)); + Tasks.Push(ArrayStruct); FEvent* WaitingThread = nullptr; { @@ -116,8 +248,8 @@ private: } while (true) { - TArray* ObjectsToSerialize = Tasks.Pop(); - while (!ObjectsToSerialize) + FGCArrayStruct* ArrayStruct = Tasks.Pop(); + while (!ArrayStruct) { if (bDone) { @@ -130,8 +262,8 @@ private: { return; } - ObjectsToSerialize = Tasks.Pop(); - if (!ObjectsToSerialize) + ArrayStruct = Tasks.Pop(); + if (!ArrayStruct) { if (WaitingThreads.Num() + 1 == NumThreadsStarted) { @@ -151,7 +283,7 @@ private: } } } - if (ObjectsToSerialize) + if (ArrayStruct) { check(!WaitEvent); } @@ -160,12 +292,12 @@ private: check(WaitEvent); WaitEvent->Wait(); FPlatformProcess::ReturnSynchEventToPool(WaitEvent); - ObjectsToSerialize = Tasks.Pop(); - check(!ObjectsToSerialize || !bDone); + ArrayStruct = Tasks.Pop(); + check(!ArrayStruct || !bDone); } } - Owner->ProcessObjectArray(*ObjectsToSerialize, FGraphEventRef()); - ArrayPool.ReturnToPool(ObjectsToSerialize); + Owner->ProcessObjectArray(*ArrayStruct, FGraphEventRef()); + ArrayPool.ReturnToPool(ArrayStruct); } } }; @@ -203,21 +335,21 @@ private: class FCollectorTask { TFastReferenceCollector* Owner; - TArray* ObjectsToSerialize; + FGCArrayStruct* ArrayStruct; ArrayPoolType& ArrayPool; public: FCollectorTask(TFastReferenceCollector* InOwner, const TArray* InObjectsToSerialize, int32 StartIndex, int32 NumObjects, ArrayPoolType& InArrayPool) : Owner(InOwner) - , ObjectsToSerialize(InArrayPool.GetArrayFromPool()) + , ArrayStruct(InArrayPool.GetArrayStructFromPool()) , ArrayPool(InArrayPool) { - ObjectsToSerialize->AddUninitialized(NumObjects); - FMemory::Memcpy(ObjectsToSerialize->GetData(), InObjectsToSerialize->GetData() + StartIndex, NumObjects * sizeof(UObject*)); + ArrayStruct->ObjectsToSerialize.AddUninitialized(NumObjects); + FMemory::Memcpy(ArrayStruct->ObjectsToSerialize.GetData(), InObjectsToSerialize->GetData() + StartIndex, NumObjects * sizeof(UObject*)); } ~FCollectorTask() { - ArrayPool.ReturnToPool(ObjectsToSerialize); + ArrayPool.ReturnToPool(ArrayStruct); } FORCEINLINE TStatId GetStatId() const { @@ -255,7 +387,7 @@ private: } void DoTask(ENamedThreads::Type CurrentThread, FGraphEventRef& MyCompletionGraphEvent) { - Owner->ProcessObjectArray(*ObjectsToSerialize, MyCompletionGraphEvent); + Owner->ProcessObjectArray(*ArrayStruct, MyCompletionGraphEvent); } }; @@ -295,14 +427,15 @@ public: * @param ObjectsToCollectReferencesFor List of objects which references should be collected * @param bForceSingleThreaded Collect references on a single thread */ - void CollectReferences(TArray& ObjectsToCollectReferencesFor) + void CollectReferences(FGCArrayStruct& ArrayStruct) { + TArray& ObjectsToCollectReferencesFor = ArrayStruct.ObjectsToSerialize; if (ObjectsToCollectReferencesFor.Num()) { if (!bParallel) { FGraphEventRef InvalidRef; - ProcessObjectArray(ObjectsToCollectReferencesFor, InvalidRef); + ProcessObjectArray(ArrayStruct, InvalidRef); } else { @@ -356,20 +489,20 @@ private: * @param InObjectsToSerializeArray Objects to process * @param MyCompletionGraphEvent Task graph event */ - void ProcessObjectArray(TArray& InObjectsToSerializeArray, const FGraphEventRef& MyCompletionGraphEvent) + void ProcessObjectArray(FGCArrayStruct& InObjectsToSerializeStruct, const FGraphEventRef& MyCompletionGraphEvent) { DECLARE_SCOPE_CYCLE_COUNTER(TEXT("TFastReferenceCollector::ProcessObjectArray"), STAT_FFastReferenceCollector_ProcessObjectArray, STATGROUP_GC); - UObject* CurrentObject = NULL; + UObject* CurrentObject = nullptr; const int32 MinDesiredObjectsPerSubTask = ReferenceProcessor.GetMinDesiredObjectsPerSubTask(); // sometimes there will be less, a lot less /** Growing array of objects that require serialization */ - TArray& NewObjectsToSerializeArray = *ArrayPool.GetArrayFromPool(); + FGCArrayStruct& NewObjectsToSerializeStruct = *ArrayPool.GetArrayStructFromPool(); // Ping-pong between these two arrays if there's not enough objects to spawn a new task - TArray& ObjectsToSerialize = InObjectsToSerializeArray; - TArray& NewObjectsToSerialize = NewObjectsToSerializeArray; + TArray& ObjectsToSerialize = InObjectsToSerializeStruct.ObjectsToSerialize; + TArray& NewObjectsToSerialize = NewObjectsToSerializeStruct.ObjectsToSerialize; // Presized "recursion" stack for handling arrays and structs. TArray Stack; @@ -383,7 +516,7 @@ private: int32 CurrentIndex = 0; do { - CollectorType ReferenceCollector(ReferenceProcessor, NewObjectsToSerialize); + CollectorType ReferenceCollector(ReferenceProcessor, NewObjectsToSerializeStruct); while (CurrentIndex < ObjectsToSerialize.Num()) { #if PERF_DETAILED_PER_CLASS_GC_STATS @@ -662,6 +795,6 @@ EndLoop: ReferenceProcessor.LogDetailedStatsSummary(); #endif - ArrayPool.ReturnToPool(&NewObjectsToSerializeArray); + ArrayPool.ReturnToPool(&NewObjectsToSerializeStruct); } }; diff --git a/Engine/Source/Runtime/CoreUObject/Public/UObject/NoExportTypes.h b/Engine/Source/Runtime/CoreUObject/Public/UObject/NoExportTypes.h index f345ea288799..4e7caaeeca80 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/UObject/NoExportTypes.h +++ b/Engine/Source/Runtime/CoreUObject/Public/UObject/NoExportTypes.h @@ -330,7 +330,7 @@ struct FVector * A 4-D homogeneous vector. * The full C++ class is located here: Engine\Source\Runtime\Core\Public\Math\Vector4.h */ -USTRUCT(immutable, noexport) +USTRUCT(immutable, noexport, BlueprintType) struct FVector4 { UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Vector4, SaveGame) @@ -367,10 +367,10 @@ struct FVector2D USTRUCT(immutable, noexport) struct FTwoVectors { - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=TwoVectors, SaveGame) + UPROPERTY(EditAnywhere, Category=TwoVectors, SaveGame) FVector v1; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=TwoVectors, SaveGame) + UPROPERTY(EditAnywhere, Category=TwoVectors, SaveGame) FVector v2; }; @@ -380,7 +380,7 @@ struct FTwoVectors * A plane definition in 3D space. * The full C++ class is located here: Engine\Source\Runtime\Core\Public\Math\Plane.h */ -USTRUCT(immutable, noexport) +USTRUCT(immutable, noexport, BlueprintType) struct FPlane : public FVector { UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Plane, SaveGame) @@ -415,7 +415,7 @@ struct FRotator * Quaternion. * The full C++ class is located here: Engine\Source\Runtime\Core\Public\Math\Quat.h */ -USTRUCT(immutable, noexport) +USTRUCT(immutable, noexport, BlueprintType) struct FQuat { UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Quat, SaveGame) @@ -440,16 +440,16 @@ struct FQuat USTRUCT(immutable, noexport) struct FPackedNormal { - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=PackedNormal, SaveGame) + UPROPERTY(EditAnywhere, Category=PackedNormal, SaveGame) uint8 X; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=PackedNormal, SaveGame) + UPROPERTY(EditAnywhere, Category=PackedNormal, SaveGame) uint8 Y; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=PackedNormal, SaveGame) + UPROPERTY(EditAnywhere, Category=PackedNormal, SaveGame) uint8 Z; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=PackedNormal, SaveGame) + UPROPERTY(EditAnywhere, Category=PackedNormal, SaveGame) uint8 W; }; @@ -461,7 +461,7 @@ struct FPackedNormal USTRUCT(immutable, noexport) struct FPackedRGB10A2N { - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PackedBasis, SaveGame) + UPROPERTY(EditAnywhere, Category = PackedBasis, SaveGame) int32 Packed; }; @@ -472,10 +472,10 @@ struct FPackedRGB10A2N USTRUCT(immutable, noexport) struct FPackedRGBA16N { - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PackedNormal, SaveGame) + UPROPERTY(EditAnywhere, Category = PackedNormal, SaveGame) int32 XY; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PackedNormal, SaveGame) + UPROPERTY(EditAnywhere, Category = PackedNormal, SaveGame) int32 ZW; }; @@ -483,7 +483,7 @@ struct FPackedRGBA16N * Screen coordinates. * The full C++ class is located here: Engine\Source\Runtime\Core\Public\Math\IntPoint.h */ -USTRUCT(immutable, noexport) +USTRUCT(immutable, noexport, BlueprintType) struct FIntPoint { UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=IntPoint, SaveGame) @@ -516,7 +516,7 @@ struct FIntVector * A Color (BGRA). * The full C++ class is located here: Engine\Source\Runtime\Core\Public\Math\Color.h */ -USTRUCT(immutable, noexport) +USTRUCT(immutable, noexport, BlueprintType) struct FColor { UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Color, SaveGame, meta=(ClampMin="0", ClampMax="255")) @@ -597,7 +597,7 @@ struct FBox2D * A bounding box and bounding sphere with the same origin. * The full C++ class is located here : Engine\Source\Runtime\Core\Public\Math\BoxSphereBounds.h */ -USTRUCT(noexport) +USTRUCT(noexport, BlueprintType) struct FBoxSphereBounds { UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=BoxSphereBounds, SaveGame) @@ -618,25 +618,25 @@ struct FBoxSphereBounds USTRUCT(immutable, noexport) struct FOrientedBox { - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=OrientedBox, SaveGame) + UPROPERTY(EditAnywhere, Category=OrientedBox, SaveGame) FVector Center; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=OrientedBox, SaveGame) + UPROPERTY(EditAnywhere, Category=OrientedBox, SaveGame) FVector AxisX; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=OrientedBox, SaveGame) + UPROPERTY(EditAnywhere, Category=OrientedBox, SaveGame) FVector AxisY; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=OrientedBox, SaveGame) + UPROPERTY(EditAnywhere, Category=OrientedBox, SaveGame) FVector AxisZ; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=OrientedBox, SaveGame) + UPROPERTY(EditAnywhere, Category=OrientedBox, SaveGame) float ExtentX; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=OrientedBox, SaveGame) + UPROPERTY(EditAnywhere, Category=OrientedBox, SaveGame) float ExtentY; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=OrientedBox, SaveGame) + UPROPERTY(EditAnywhere, Category=OrientedBox, SaveGame) float ExtentZ; }; @@ -644,7 +644,7 @@ struct FOrientedBox * A 4x4 matrix. * The full C++ class is located here: Engine\Source\Runtime\Core\Public\Math\Matrix.h */ -USTRUCT(immutable, noexport) +USTRUCT(immutable, noexport, BlueprintType) struct FMatrix { UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Matrix, SaveGame) @@ -666,19 +666,19 @@ struct FMatrix USTRUCT(noexport) struct FInterpCurvePointFloat { - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointFloat) + UPROPERTY(EditAnywhere, Category=InterpCurvePointFloat) float InVal; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointFloat) + UPROPERTY(EditAnywhere, Category=InterpCurvePointFloat) float OutVal; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointFloat) + UPROPERTY(EditAnywhere, Category=InterpCurvePointFloat) float ArriveTangent; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointFloat) + UPROPERTY(EditAnywhere, Category=InterpCurvePointFloat) float LeaveTangent; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointFloat) + UPROPERTY(EditAnywhere, Category=InterpCurvePointFloat) TEnumAsByte InterpMode; }; @@ -688,13 +688,13 @@ struct FInterpCurvePointFloat USTRUCT(noexport) struct FInterpCurveFloat { - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurveFloat) + UPROPERTY(EditAnywhere, Category=InterpCurveFloat) TArray Points; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurveFloat) + UPROPERTY(EditAnywhere, Category=InterpCurveFloat) bool bIsLooped; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurveFloat) + UPROPERTY(EditAnywhere, Category=InterpCurveFloat) float LoopKeyOffset; }; @@ -703,19 +703,19 @@ struct FInterpCurveFloat USTRUCT(noexport) struct FInterpCurvePointVector2D { - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointVector2D) + UPROPERTY(EditAnywhere, Category=InterpCurvePointVector2D) float InVal; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointVector2D) + UPROPERTY(EditAnywhere, Category=InterpCurvePointVector2D) FVector2D OutVal; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointVector2D) + UPROPERTY(EditAnywhere, Category=InterpCurvePointVector2D) FVector2D ArriveTangent; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointVector2D) + UPROPERTY(EditAnywhere, Category=InterpCurvePointVector2D) FVector2D LeaveTangent; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointVector2D) + UPROPERTY(EditAnywhere, Category=InterpCurvePointVector2D) TEnumAsByte InterpMode; }; @@ -725,13 +725,13 @@ struct FInterpCurvePointVector2D USTRUCT(noexport) struct FInterpCurveVector2D { - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurveVector2D) + UPROPERTY(EditAnywhere, Category=InterpCurveVector2D) TArray Points; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurveVector2D) + UPROPERTY(EditAnywhere, Category=InterpCurveVector2D) bool bIsLooped; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurveVector2D) + UPROPERTY(EditAnywhere, Category=InterpCurveVector2D) float LoopKeyOffset; }; @@ -740,19 +740,19 @@ struct FInterpCurveVector2D USTRUCT(noexport) struct FInterpCurvePointVector { - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointVector) + UPROPERTY(EditAnywhere, Category=InterpCurvePointVector) float InVal; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointVector) + UPROPERTY(EditAnywhere, Category=InterpCurvePointVector) FVector OutVal; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointVector) + UPROPERTY(EditAnywhere, Category=InterpCurvePointVector) FVector ArriveTangent; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointVector) + UPROPERTY(EditAnywhere, Category=InterpCurvePointVector) FVector LeaveTangent; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointVector) + UPROPERTY(EditAnywhere, Category=InterpCurvePointVector) TEnumAsByte InterpMode; }; @@ -762,13 +762,13 @@ struct FInterpCurvePointVector USTRUCT(noexport) struct FInterpCurveVector { - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurveVector) + UPROPERTY(EditAnywhere, Category=InterpCurveVector) TArray Points; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurveVector) + UPROPERTY(EditAnywhere, Category=InterpCurveVector) bool bIsLooped; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurveVector) + UPROPERTY(EditAnywhere, Category=InterpCurveVector) float LoopKeyOffset; }; @@ -777,19 +777,19 @@ struct FInterpCurveVector USTRUCT(noexport) struct FInterpCurvePointQuat { - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointQuat) + UPROPERTY(EditAnywhere, Category=InterpCurvePointQuat) float InVal; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointQuat) + UPROPERTY(EditAnywhere, Category=InterpCurvePointQuat) FQuat OutVal; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointQuat) + UPROPERTY(EditAnywhere, Category=InterpCurvePointQuat) FQuat ArriveTangent; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointQuat) + UPROPERTY(EditAnywhere, Category=InterpCurvePointQuat) FQuat LeaveTangent; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointQuat) + UPROPERTY(EditAnywhere, Category=InterpCurvePointQuat) TEnumAsByte InterpMode; }; @@ -799,13 +799,13 @@ struct FInterpCurvePointQuat USTRUCT(noexport) struct FInterpCurveQuat { - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurveQuat) + UPROPERTY(EditAnywhere, Category=InterpCurveQuat) TArray Points; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurveQuat) + UPROPERTY(EditAnywhere, Category=InterpCurveQuat) bool bIsLooped; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurveQuat) + UPROPERTY(EditAnywhere, Category=InterpCurveQuat) float LoopKeyOffset; }; @@ -814,19 +814,19 @@ struct FInterpCurveQuat USTRUCT(noexport) struct FInterpCurvePointTwoVectors { - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointTwoVectors) + UPROPERTY(EditAnywhere, Category=InterpCurvePointTwoVectors) float InVal; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointTwoVectors) + UPROPERTY(EditAnywhere, Category=InterpCurvePointTwoVectors) FTwoVectors OutVal; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointTwoVectors) + UPROPERTY(EditAnywhere, Category=InterpCurvePointTwoVectors) FTwoVectors ArriveTangent; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointTwoVectors) + UPROPERTY(EditAnywhere, Category=InterpCurvePointTwoVectors) FTwoVectors LeaveTangent; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointTwoVectors) + UPROPERTY(EditAnywhere, Category=InterpCurvePointTwoVectors) TEnumAsByte InterpMode; }; @@ -836,13 +836,13 @@ struct FInterpCurvePointTwoVectors USTRUCT(noexport) struct FInterpCurveTwoVectors { - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurveTwoVectors) + UPROPERTY(EditAnywhere, Category=InterpCurveTwoVectors) TArray Points; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurveTwoVectors) + UPROPERTY(EditAnywhere, Category=InterpCurveTwoVectors) bool bIsLooped; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurveTwoVectors) + UPROPERTY(EditAnywhere, Category=InterpCurveTwoVectors) float LoopKeyOffset; }; @@ -851,19 +851,19 @@ struct FInterpCurveTwoVectors USTRUCT(noexport) struct FInterpCurvePointLinearColor { - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointLinearColor) + UPROPERTY(EditAnywhere, Category=InterpCurvePointLinearColor) float InVal; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointLinearColor) + UPROPERTY(EditAnywhere, Category=InterpCurvePointLinearColor) FLinearColor OutVal; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointLinearColor) + UPROPERTY(EditAnywhere, Category=InterpCurvePointLinearColor) FLinearColor ArriveTangent; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointLinearColor) + UPROPERTY(EditAnywhere, Category=InterpCurvePointLinearColor) FLinearColor LeaveTangent; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurvePointLinearColor) + UPROPERTY(EditAnywhere, Category=InterpCurvePointLinearColor) TEnumAsByte InterpMode; }; @@ -873,13 +873,13 @@ struct FInterpCurvePointLinearColor USTRUCT(noexport) struct FInterpCurveLinearColor { - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurveLinearColor) + UPROPERTY(EditAnywhere, Category=InterpCurveLinearColor) TArray Points; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurveLinearColor) + UPROPERTY(EditAnywhere, Category=InterpCurveLinearColor) bool bIsLooped; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpCurveLinearColor) + UPROPERTY(EditAnywhere, Category=InterpCurveLinearColor) float LoopKeyOffset; }; @@ -939,7 +939,7 @@ struct FTimespan // A string asset reference -USTRUCT(noexport, meta=(HasNativeMake="Engine.BlueprintFunctionLibrary.MakeStringAssetReference")) +USTRUCT(noexport, BlueprintType, meta=(HasNativeMake="Engine.BlueprintFunctionLibrary.MakeStringAssetReference")) struct FStringAssetReference { UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=StringAssetReference) @@ -957,9 +957,8 @@ struct FStringClassReference : public FStringAssetReference USTRUCT(noexport, BlueprintType) struct FPrimaryAssetType { -private: /** The Type of this object, by default it's base class's name */ - UPROPERTY() + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PrimaryAssetType) FName Name; }; @@ -983,7 +982,7 @@ struct FFallbackStruct { }; -UENUM() +UENUM(BlueprintType) namespace ERangeBoundTypes { /** @@ -1010,49 +1009,49 @@ namespace ERangeBoundTypes // A float range bound -USTRUCT(noexport) +USTRUCT(noexport, BlueprintType) struct FFloatRangeBound { - UPROPERTY(EditAnywhere, Category=Range) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Range) TEnumAsByte Type; - UPROPERTY(EditAnywhere, Category=Range) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Range) float Value; }; // A float range -USTRUCT(noexport) +USTRUCT(noexport, BlueprintType) struct FFloatRange { - UPROPERTY(EditAnywhere, Category=Range) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Range) FFloatRangeBound LowerBound; - UPROPERTY(EditAnywhere, Category=Range) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Range) FFloatRangeBound UpperBound; }; // An int32 range bound -USTRUCT(noexport) +USTRUCT(noexport, BlueprintType) struct FInt32RangeBound { - UPROPERTY(EditAnywhere, Category = Range) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Range) TEnumAsByte Type; - UPROPERTY(EditAnywhere, Category = Range) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Range) int32 Value; }; // An int32 range -USTRUCT(noexport) +USTRUCT(noexport, BlueprintType) struct FInt32Range { - UPROPERTY(EditAnywhere, Category = Range) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Range) FInt32RangeBound LowerBound; - UPROPERTY(EditAnywhere, Category = Range) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Range) FInt32RangeBound UpperBound; }; diff --git a/Engine/Source/Runtime/CoreUObject/Public/UObject/Object.h b/Engine/Source/Runtime/CoreUObject/Public/UObject/Object.h index d522a763fe78..a2c6798c64a8 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/UObject/Object.h +++ b/Engine/Source/Runtime/CoreUObject/Public/UObject/Object.h @@ -166,11 +166,10 @@ public: * PostSaveRoot. This is used to allow objects used as base to perform required actions before saving and cleanup * afterwards. * @param Filename: Name of the file being saved to (includes path) - * @param AdditionalPackagesToCook [out] Array of other packages the Root wants to make sure are cooked when this is cooked * * @return Whether PostSaveRoot needs to perform internal cleanup */ - virtual bool PreSaveRoot(const TCHAR* Filename, TArray& AdditionalPackagesToCook) + virtual bool PreSaveRoot(const TCHAR* Filename) { return false; } @@ -325,7 +324,15 @@ public: /** Called after applying a transaction to the object in cases where transaction annotation was provided. Default implementation simply calls PostEditChange. */ virtual void PostEditUndo(TSharedPtr TransactionAnnotation); - + /** + * Test the selection state of a UObject + * + * @return true if the object is selected, false otherwise. + * @todo UE4 this doesn't belong here, but it doesn't belong anywhere else any better + */ +private: + virtual bool IsSelectedInEditor() const; +public: #endif // WITH_EDITOR // @todo document @@ -390,12 +397,21 @@ public: } /** - * Called during cooking. Must return all objects that will be Preload()ed when this is serialized at load time + * Called during cooking. Must return all objects that will be Preload()ed when this is serialized at load time. Only used by the EDL. * * @param OutDeps all objects that will be preloaded when this is serialized at load time */ virtual void GetPreloadDependencies(TArray& OutDeps); + /** + * Called during cooking. Returns a list of objects. The packages containing those objects will be prestreamed, when the package containing this is loaded. Only used by the EDL. + * + * @param OutPrestream all objects that will be prestreamed when this packages is streamed + */ + virtual void GetPrestreamPackages(TArray& OutPrestream) + { + } + /** * Update the list of classes that we should exclude from dedicated server builds */ @@ -570,20 +586,43 @@ public: */ struct FAssetRegistryTag { + /** Enum specifying the type of this tag */ enum ETagType { + /** This tag should not be shown in the UI */ TT_Hidden, + /** This tag should be shown, and sorted alphabetically in the UI */ TT_Alphabetical, + /** This tag should be shown, and is a number */ TT_Numerical, - TT_Dimensional + /** This tag should be shown, and is an "x" delimited list of dimensions */ + TT_Dimensional, + /** This tag should be shown, and is a timestamp formatted via FDateTime::ToString */ + TT_Chronological, }; + /** Flags controlling how this tag should be shown in the UI */ + enum ETagDisplay + { + /** No special display */ + TD_None = 0, + /** For TT_Chronological, include the date */ + TD_Date = 1<<0, + /** For TT_Chronological, include the time */ + TD_Time = 1<<1, + /** For TT_Chronological, specifies that the timestamp should be displayed using the invariant timezone (typically for timestamps that are already in local time) */ + TD_InvariantTz = 1<<2, + /** For TT_Numerical, specifies that the number is a value in bytes that should be displayed using FText::AsMemory */ + TD_Memory = 1<<3, + }; + FName Name; - ETagType Type; FString Value; + ETagType Type; + uint32 DisplayFlags; - FAssetRegistryTag(FName InName, const FString& InValue, ETagType InType) - : Name(InName), Type(InType), Value(InValue) {} + FAssetRegistryTag(FName InName, const FString& InValue, ETagType InType, uint32 InDisplayFlags = TD_None) + : Name(InName), Value(InValue), Type(InType), DisplayFlags(InDisplayFlags) {} /** Gathers a list of asset registry searchable tags from given objects properties */ COREUOBJECT_API static void GetAssetRegistryTagsFromSearchableProperties(const UObject* Object, TArray& OutTags); @@ -1190,6 +1229,8 @@ public: DECLARE_FUNCTION(execSetSet); DECLARE_FUNCTION(execSetMap); DECLARE_FUNCTION(execArrayConst); + DECLARE_FUNCTION(execSetConst); + DECLARE_FUNCTION(execMapConst); // Object construction DECLARE_FUNCTION(execNew); diff --git a/Engine/Source/Runtime/CoreUObject/Public/UObject/ObjectMacros.h b/Engine/Source/Runtime/CoreUObject/Public/UObject/ObjectMacros.h index c94ef02f99e4..645f4a4d696c 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/UObject/ObjectMacros.h +++ b/Engine/Source/Runtime/CoreUObject/Public/UObject/ObjectMacros.h @@ -80,6 +80,7 @@ enum ELoadFlags LOAD_PackageForPIE = 0x00080000, // This package is being loaded for PIE, it must be flagged as such immediately LOAD_DeferDependencyLoads = 0x00100000, // Do not load external (blueprint) dependencies (instead, track them for deferred loading) LOAD_ForFileDiff = 0x00200000, // Load the package (not for diffing in the editor), instead verify at the two packages serialized output are the same, if they are not then debug break so that you can get the callstack and object information + LOAD_DisableCompileOnLoad = 0x00400000, // Prevent this load call from running compile on load for the loaded blueprint (intentionally not recursive, dependencies will still compile on load) }; // @@ -170,79 +171,79 @@ enum EClassFlags { /** @name Base flags */ //@{ - CLASS_None = 0x00000000, + CLASS_None = 0x00000000u, /** Class is abstract and can't be instantiated directly. */ - CLASS_Abstract = 0x00000001, + CLASS_Abstract = 0x00000001u, /** Save object configuration only to Default INIs, never to local INIs. Must be combined with CLASS_Config */ - CLASS_DefaultConfig = 0x00000002, + CLASS_DefaultConfig = 0x00000002u, /** Load object configuration at construction time. */ - CLASS_Config = 0x00000004, + CLASS_Config = 0x00000004u, /** This object type can't be saved; null it out at save time. */ - CLASS_Transient = 0x00000008, + CLASS_Transient = 0x00000008u, /** Successfully parsed. */ - CLASS_Parsed = 0x00000010, + CLASS_Parsed = 0x00000010u, /** */ - //CLASS_ = 0x00000020, + //CLASS_ = 0x00000020u, /** All the properties on the class are shown in the advanced section (which is hidden by default) unless SimpleDisplay is specified on the property */ - CLASS_AdvancedDisplay = 0x00000040, + CLASS_AdvancedDisplay = 0x00000040u, /** Class is a native class - native interfaces will have CLASS_Native set, but not RF_MarkAsNative */ - CLASS_Native = 0x00000080, + CLASS_Native = 0x00000080u, /** Don't export to C++ header. */ - CLASS_NoExport = 0x00000100, + CLASS_NoExport = 0x00000100u, /** Do not allow users to create in the editor. */ - CLASS_NotPlaceable = 0x00000200, + CLASS_NotPlaceable = 0x00000200u, /** Handle object configuration on a per-object basis, rather than per-class. */ - CLASS_PerObjectConfig = 0x00000400, + CLASS_PerObjectConfig = 0x00000400u, - /** pointers to this class default to weak. */ - CLASS_PointersDefaultToWeak = 0x00000800, + /** */ + //CLASS_ = 0x00000800u, /** Class can be constructed from editinline New button. */ - CLASS_EditInlineNew = 0x00001000, + CLASS_EditInlineNew = 0x00001000u, /** Display properties in the editor without using categories. */ - CLASS_CollapseCategories = 0x00002000, + CLASS_CollapseCategories = 0x00002000u, /** Class is an interface **/ - CLASS_Interface = 0x00004000, + CLASS_Interface = 0x00004000u, /** Do not export a constructor for this class, assuming it is in the cpptext **/ - CLASS_CustomConstructor = 0x00008000, + CLASS_CustomConstructor = 0x00008000u, /** all properties and functions in this class are const and should be exported as const */ - CLASS_Const = 0x00010000, + CLASS_Const = 0x00010000u, - /** pointers to this class default to weak. */ - CLASS_PointersDefaultToAutoWeak = 0x00020000, + /** */ + //CLASS_ = 0x00020000u, /** Indicates that the class was created from blueprint source material */ - CLASS_CompiledFromBlueprint = 0x00040000, + CLASS_CompiledFromBlueprint = 0x00040000u, /** Indicates that only the bare minimum bits of this class should be DLL exported/imported */ - CLASS_MinimalAPI = 0x00080000, + CLASS_MinimalAPI = 0x00080000u, /** Indicates this class must be DLL exported/imported (along with all of it's members) */ - CLASS_RequiredAPI = 0x00100000, + CLASS_RequiredAPI = 0x00100000u, /** Indicates that references to this class default to instanced. Used to be subclasses of UComponent, but now can be any UObject */ - CLASS_DefaultToInstanced = 0x00200000, + CLASS_DefaultToInstanced = 0x00200000u, /** Indicates that the parent token stream has been merged with ours. */ - CLASS_TokenStreamAssembled = 0x00400000, + CLASS_TokenStreamAssembled = 0x00400000u, /** Class has component properties. */ - CLASS_HasInstancedReference= 0x00800000, + CLASS_HasInstancedReference= 0x00800000u, /** Don't show this class in the editor class browser or edit inline new menus. */ - CLASS_Hidden = 0x01000000, + CLASS_Hidden = 0x01000000u, /** Don't save objects of this class when serializing */ - CLASS_Deprecated = 0x02000000, + CLASS_Deprecated = 0x02000000u, /** Class not shown in editor drop down for class selection */ - CLASS_HideDropDown = 0x04000000, + CLASS_HideDropDown = 0x04000000u, /** Class settings are saved to /..../Blah.ini (as opposed to CLASS_DefaultConfig) */ - CLASS_GlobalUserConfig = 0x08000000, + CLASS_GlobalUserConfig = 0x08000000u, /** Class was declared directly in C++ and has no boilerplate generated by UnrealHeaderTool */ - CLASS_Intrinsic = 0x10000000, + CLASS_Intrinsic = 0x10000000u, /** Class has already been constructed (maybe in a previous DLL version before hot-reload). */ - CLASS_Constructed = 0x20000000, + CLASS_Constructed = 0x20000000u, /** Indicates that object configuration will not check against ini base/defaults when serialized */ - CLASS_ConfigDoNotCheckDefaults = 0x40000000, + CLASS_ConfigDoNotCheckDefaults = 0x40000000u, /** Class has been consigned to oblivion as part of a blueprint recompile, and a newer version currently exists. */ - CLASS_NewerVersionExists = 0x80000000, + CLASS_NewerVersionExists = 0x80000000u, //@} @@ -250,8 +251,7 @@ enum EClassFlags /** @name Flags to inherit from base class */ //@{ CLASS_Inherit = CLASS_Transient | CLASS_DefaultConfig | CLASS_Config | CLASS_PerObjectConfig | CLASS_ConfigDoNotCheckDefaults | CLASS_NotPlaceable - | CLASS_PointersDefaultToAutoWeak | CLASS_PointersDefaultToWeak | CLASS_Const - | CLASS_HasInstancedReference | CLASS_Deprecated | CLASS_DefaultToInstanced | CLASS_GlobalUserConfig, + | CLASS_Const | CLASS_HasInstancedReference | CLASS_Deprecated | CLASS_DefaultToInstanced | CLASS_GlobalUserConfig, /** these flags will be cleared by the compiler when the class is parsed during script compilation */ CLASS_RecompilerClear = CLASS_Inherit | CLASS_Abstract | CLASS_NoExport | CLASS_Native | CLASS_Intrinsic | CLASS_TokenStreamAssembled, @@ -274,11 +274,9 @@ enum EClassFlags CLASS_NotPlaceable | CLASS_PerObjectConfig | CLASS_ConfigDoNotCheckDefaults | - CLASS_PointersDefaultToWeak | CLASS_EditInlineNew | CLASS_CollapseCategories | CLASS_Interface | - CLASS_PointersDefaultToAutoWeak | CLASS_DefaultToInstanced | CLASS_HasInstancedReference | CLASS_Hidden | @@ -290,10 +288,11 @@ enum EClassFlags CLASS_MinimalAPI | CLASS_RequiredAPI, - CLASS_AllFlags = 0xFFFFFFFF, + CLASS_AllFlags = 0xFFFFFFFFu, }; - +// Declare bitwise operators to allow EClassFlags to be combined but still retain type safety +ENUM_CLASS_FLAGS(EClassFlags); @@ -412,16 +411,13 @@ typedef uint64 EClassCastFlags; #define CPF_NonPIEDuplicateTransient DECLARE_UINT64(0x0000800000000000) // Property should only be copied in PIE #define CPF_ExposeOnSpawn DECLARE_UINT64(0x0001000000000000) // Property is exposed on spawn #define CPF_PersistentInstance DECLARE_UINT64(0x0002000000000000) // A object referenced by the property is duplicated like a component. (Each actor should have an own instance.) -#define CPF_UObjectWrapper DECLARE_UINT64(0x0004000000000000) // Property was parsed as a wrapper class like TSubobjectOf, FScriptInterface etc., rather than a USomething* +#define CPF_UObjectWrapper DECLARE_UINT64(0x0004000000000000) // Property was parsed as a wrapper class like TSubclassOf, FScriptInterface etc., rather than a USomething* #define CPF_HasGetValueTypeHash DECLARE_UINT64(0x0008000000000000) // This property can generate a meaningful hash value. #define CPF_NativeAccessSpecifierPublic DECLARE_UINT64(0x0010000000000000) // Public native access specifier #define CPF_NativeAccessSpecifierProtected DECLARE_UINT64(0x0020000000000000) // Protected native access specifier #define CPF_NativeAccessSpecifierPrivate DECLARE_UINT64(0x0040000000000000) // Private native access specifier #define CPF_SkipSerialization DECLARE_UINT64(0x0080000000000000) // Property shouldn't be serialized, can still be exported to text -#define CPF_NonPIETransient \ - EMIT_DEPRECATED_WARNING_MESSAGE("CPF_NonPIETransient is deprecated. Please use CPF_NonPIEDuplicateTransient instead.") \ - CPF_NonPIEDuplicateTransient /** @name Combinations flags */ //@{ @@ -539,11 +535,10 @@ enum class EInternalObjectFlags : int32 Unreachable = 1 << 28, ///< Object is not reachable on the object graph. PendingKill = 1 << 29, ///< Objects that are pending destruction (invalid for gameplay but valid objects) RootSet = 1 << 30, ///< Object will not be garbage collected, even if unreferenced. - NoStrongReference = 1 << 31, ///< The object is not referenced by any strong reference. The flag is used by GC. GarbageCollectionKeepFlags = Native | Async | AsyncLoading, // Make sure this is up to date! - AllFlags = ReachableInCluster | ClusterRoot | Native | Async | AsyncLoading | Unreachable | PendingKill | RootSet | NoStrongReference + AllFlags = ReachableInCluster | ClusterRoot | Native | Async | AsyncLoading | Unreachable | PendingKill | RootSet }; ENUM_CLASS_FLAGS(EInternalObjectFlags); @@ -811,12 +806,21 @@ namespace UF /// This function can be called from blueprint code and should be exposed to the user of blueprint editing tools. BlueprintCallable, + /// This function is used as the get accessor for a blueprint exposed property. Implies BlueprintPure and BlueprintCallable. + BlueprintGetter, + + /// This function is used as the set accessor for a blueprint exposed property. Implies BlueprintCallable. + BlueprintSetter, + /// This function will not execute from blueprint code if running on something without network authority BlueprintAuthorityOnly, /// This function is cosmetic and will not run on dedicated servers BlueprintCosmetic, + /// Indicates that a Blueprint exposed function should not be exposed to the end user + BlueprintInternalUseOnly, + /// This function can be called in the editor on selected instances via a button in the details panel. CallInEditor, @@ -930,9 +934,15 @@ namespace UP /// This property can be read by blueprints, but not modified. BlueprintReadOnly, + /// This property has an accessor to return the value. Implies BlueprintReadOnly if BlueprintSetter or BlueprintReadWrite is not specified. (usage: BlueprintGetter=FunctionName). + BlueprintGetter, + /// This property can be read or written from a blueprint. BlueprintReadWrite, + /// This property has an accessor to set the value. Implies BlueprintReadWrite. (usage: BlueprintSetter=FunctionName). + BlueprintSetter, + /// The AssetRegistrySearchable keyword indicates that this property and it's value will be automatically added /// to the asset registry for any asset class instances containing this as a member variable. It is not legal /// to use on struct properties or parameters. @@ -971,6 +981,9 @@ namespace US /// Exposes this struct as a type that can be used for variables in blueprints BlueprintType, + + /// Indicates that a BlueprintType struct should not be exposed to the end user + BlueprintInternalUseOnly }; } @@ -1354,7 +1367,7 @@ public: \ { \ return TPackage; \ } \ - /** Returns the StaticClassFlags for this class */ \ + /** Returns the static cast flags for this class */ \ inline static EClassCastFlags StaticClassCastFlags() \ { \ return TStaticCastFlags; \ @@ -1499,7 +1512,7 @@ public: \ PrivateStaticClass, \ StaticRegisterNatives##TClass, \ sizeof(TClass), \ - TClass::StaticClassFlags, \ + (EClassFlags)TClass::StaticClassFlags, \ TClass::StaticClassCastFlags(), \ TClass::StaticConfigName(), \ (UClass::ClassConstructorType)InternalConstructor, \ @@ -1559,7 +1572,7 @@ public: \ PrivateStaticClass, \ StaticRegisterNatives##TClass, \ sizeof(TClass), \ - TClass::StaticClassFlags, \ + (EClassFlags)TClass::StaticClassFlags, \ TClass::StaticClassCastFlags(), \ TClass::StaticConfigName(), \ (UClass::ClassConstructorType)InternalConstructor, \ diff --git a/Engine/Source/Runtime/CoreUObject/Public/UObject/ObjectRedirector.h b/Engine/Source/Runtime/CoreUObject/Public/UObject/ObjectRedirector.h index dbd11e868e30..e99648c9b6db 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/UObject/ObjectRedirector.h +++ b/Engine/Source/Runtime/CoreUObject/Public/UObject/ObjectRedirector.h @@ -40,48 +40,3 @@ class UObjectRedirector : public UObject */ virtual bool GetNativePropertyValues( TMap& out_PropertyValues, uint32 ExportFlags=0 ) const override; }; - -/** - * Callback structure to respond to redirect-followed callbacks to determine - * if a redirector was followed from a single object name. Will auto - * register and unregister the callback on construction/destruction - */ -class COREUOBJECT_API FScopedRedirectorCatcher -{ -public: - /** - * Constructor for the callback device, will register itself with the RedirectorFollowed delegate - * - * @param InObjectPathNameToMatch Full pathname of the object refrence that is being compiled by script - */ - FScopedRedirectorCatcher(const FString& InObjectPathNameToMatch); - - /** - * Destructor. Will unregister the callback - */ - ~FScopedRedirectorCatcher(); - - /** - * Returns whether or not a redirector was followed for the ObjectPathName - */ - inline bool WasRedirectorFollowed() - { - return bWasRedirectorFollowed; - } - - /** - * Responds to FCoreDelegates::RedirectorFollowed. Records all followed redirections - * so they can be cleaned later. - * - * @param InString Name of the package that pointed to the redirect - * @param InObject The UObjectRedirector that was followed - */ - virtual void OnRedirectorFollowed( const FString& InString, UObject* InObject); - -private: - /** The full path name of the object that we want to match */ - FString ObjectPathNameToMatch; - - /** Was a redirector followed, ONLY for the ObjectPathNameToMatch? */ - bool bWasRedirectorFollowed; -}; diff --git a/Engine/Source/Runtime/CoreUObject/Public/UObject/PackageFileSummary.h b/Engine/Source/Runtime/CoreUObject/Public/UObject/PackageFileSummary.h index 6d94112fc003..3fd83d54bc5c 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/UObject/PackageFileSummary.h +++ b/Engine/Source/Runtime/CoreUObject/Public/UObject/PackageFileSummary.h @@ -173,11 +173,6 @@ public: */ TArray CompressedChunks; - /** - * List of additional packages that are needed to be cooked for this package (ie streaming levels) - */ - TArray AdditionalPackagesToCook; - /** * If true, this file will not be saved with version numbers or was saved without version numbers. In this case they are assumed to be the current version. * This is only used for full cooks for distribution because it is hard to guarantee correctness diff --git a/Engine/Source/Runtime/CoreUObject/Public/UObject/PersistentObjectPtr.h b/Engine/Source/Runtime/CoreUObject/Public/UObject/PersistentObjectPtr.h index 5f251b95f2b1..46e1da37534f 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/UObject/PersistentObjectPtr.h +++ b/Engine/Source/Runtime/CoreUObject/Public/UObject/PersistentObjectPtr.h @@ -31,6 +31,13 @@ public: TagAtLastTest = 0; } + /** Resets the weak ptr only, call this when ObjectId may change */ + FORCEINLINE void ResetWeakPtr() + { + WeakPtr.Reset(); + TagAtLastTest = 0; + } + /** Construct from another pointer of the same type */ FORCEINLINE TPersistentObjectPtr(const TPersistentObjectPtr& Other) { diff --git a/Engine/Source/Runtime/CoreUObject/Public/UObject/Script.h b/Engine/Source/Runtime/CoreUObject/Public/UObject/Script.h index 926bd4385732..efe67256780b 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/UObject/Script.h +++ b/Engine/Source/Runtime/CoreUObject/Public/UObject/Script.h @@ -9,6 +9,7 @@ #include "CoreMinimal.h" #include "HAL/ThreadSingleton.h" #include "Stats/Stats.h" +#include "Misc/EnumClassFlags.h" struct FFrame; @@ -100,9 +101,11 @@ namespace FunctionCallspace // Function flags. // // Note: Please keep ParseFunctionFlags in sync when this enum is modified. -enum EFunctionFlags +enum EFunctionFlags : uint32 { // Function flags. + FUNC_None = 0x00000000, + FUNC_Final = 0x00000001, // Function is final (prebindable, non-overridable function). FUNC_RequiredAPI = 0x00000002, // Indicates this function is DLL exported/imported. FUNC_BlueprintAuthorityOnly= 0x00000004, // Function will only run if the object has network authority @@ -132,19 +135,27 @@ enum EFunctionFlags FUNC_BlueprintCallable = 0x04000000, // function can be called from blueprint code FUNC_BlueprintEvent = 0x08000000, // function can be overridden/implemented from a blueprint FUNC_BlueprintPure = 0x10000000, // function can be called from blueprint code, and is also pure (produces no side effects). If you set this, you should set FUNC_BlueprintCallable as well. - // FUNC_ = 0x20000000, // unused. + FUNC_EditorOnly = 0x20000000, // function can only be called from an editor scrippt. FUNC_Const = 0x40000000, // function can be called from blueprint code, and only reads state (never writes state) FUNC_NetValidate = 0x80000000, // function must supply a _Validate implementation - // Combinations of flags. - FUNC_FuncInherit = FUNC_Exec | FUNC_Event | FUNC_BlueprintCallable | FUNC_BlueprintEvent | FUNC_BlueprintAuthorityOnly | FUNC_BlueprintCosmetic, - FUNC_FuncOverrideMatch = FUNC_Exec | FUNC_Final | FUNC_Static | FUNC_Public | FUNC_Protected | FUNC_Private, - FUNC_NetFuncFlags = FUNC_Net | FUNC_NetReliable | FUNC_NetServer | FUNC_NetClient | FUNC_NetMulticast, - FUNC_AccessSpecifiers = FUNC_Public | FUNC_Private | FUNC_Protected, - FUNC_AllFlags = 0xFFFFFFFF, }; +FORCEINLINE FArchive& operator<<(FArchive& Ar, EFunctionFlags& Flags) +{ + Ar << (uint32&)Flags; + return Ar; +} + +ENUM_CLASS_FLAGS(EFunctionFlags) + +// Combinations of flags. +#define FUNC_FuncInherit ((EFunctionFlags)(FUNC_Exec | FUNC_Event | FUNC_BlueprintCallable | FUNC_BlueprintEvent | FUNC_BlueprintAuthorityOnly | FUNC_BlueprintCosmetic)) +#define FUNC_FuncOverrideMatch ((EFunctionFlags)(FUNC_Exec | FUNC_Final | FUNC_Static | FUNC_Public | FUNC_Protected | FUNC_Private)) +#define FUNC_NetFuncFlags ((EFunctionFlags)(FUNC_Net | FUNC_NetReliable | FUNC_NetServer | FUNC_NetClient | FUNC_NetMulticast)) +#define FUNC_AccessSpecifiers ((EFunctionFlags)(FUNC_Public | FUNC_Private | FUNC_Protected)) + // // Evaluatable expression item types. // @@ -212,10 +223,10 @@ enum EExprToken EX_EndSet = 0x3A, EX_SetMap = 0x3B, EX_EndMap = 0x3C, - // = 0x3D, - // = 0x3E, - // = 0x3F, - // = 0x40, + EX_SetConst = 0x3D, + EX_EndSetConst = 0x3E, + EX_MapConst = 0x3F, + EX_EndMapConst = 0x40, // = 0x41, EX_StructMemberContext = 0x42, // Context expression to address a property within a struct EX_LetMulticastDelegate = 0x43, // Assignment to a multi-cast delegate diff --git a/Engine/Source/Runtime/CoreUObject/Public/UObject/ScriptMacros.h b/Engine/Source/Runtime/CoreUObject/Public/UObject/ScriptMacros.h index 8f9fde4f41c7..0ad97affa007 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/UObject/ScriptMacros.h +++ b/Engine/Source/Runtime/CoreUObject/Public/UObject/ScriptMacros.h @@ -69,6 +69,12 @@ enum {MAX_VARIABLE_SIZE = 0x0FFF }; #define P_GET_TARRAY(ElementType,ParamName) PARAM_PASSED_BY_VAL(ParamName, UArrayProperty, TArray) #define P_GET_TARRAY_REF(ElementType,ParamName) PARAM_PASSED_BY_REF(ParamName, UArrayProperty, TArray) +#define P_GET_TMAP(KeyType,ValueType,ParamName) PARAM_PASSED_BY_VAL(ParamName, UMapProperty, PREPROCESSOR_COMMA_SEPARATED(TMap)) +#define P_GET_TMAP_REF(KeyType,ValueType,ParamName) PARAM_PASSED_BY_REF(ParamName, UMapProperty, PREPROCESSOR_COMMA_SEPARATED(TMap)) + +#define P_GET_TSET(ElementType,ParamName) PARAM_PASSED_BY_VAL(ParamName, USetProperty, TSet) +#define P_GET_TSET_REF(ElementType,ParamName) PARAM_PASSED_BY_REF(ParamName, USetProperty, TSet) + #define P_GET_TINTERFACE(ObjectType,ParamName) PARAM_PASSED_BY_VAL(ParamName, UInterfaceProperty, TScriptInterface) #define P_GET_TINTERFACE_REF(ObjectType,ParamName) PARAM_PASSED_BY_REF(ParamName, UInterfaceProperty, TScriptInterface) diff --git a/Engine/Source/Runtime/CoreUObject/Public/UObject/ScriptSerialization.h b/Engine/Source/Runtime/CoreUObject/Public/UObject/ScriptSerialization.h index a5fefc4c80b4..bb39e956ac82 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/UObject/ScriptSerialization.h +++ b/Engine/Source/Runtime/CoreUObject/Public/UObject/ScriptSerialization.h @@ -237,6 +237,10 @@ case EX_EndStructConst: case EX_EndArray: case EX_EndArrayConst: + case EX_EndSet: + case EX_EndMap: + case EX_EndSetConst: + case EX_EndMapConst: case EX_IntZero: case EX_IntOne: case EX_True: @@ -439,6 +443,21 @@ while (SerializeExpr(iCode, Ar) != EX_EndArrayConst); break; } + case EX_SetConst: + { + XFERPTR(UProperty*); // Inner property + XFER(int32); // Number of elements + while (SerializeExpr(iCode, Ar) != EX_EndSetConst); + break; + } + case EX_MapConst: + { + XFERPTR(UProperty*); // Key property + XFERPTR(UProperty*); // Val property + XFER(int32); // Number of elements + while (SerializeExpr(iCode, Ar) != EX_EndMapConst); + break; + } case EX_ByteConst: case EX_IntConstByte: { diff --git a/Engine/Source/Runtime/CoreUObject/Public/UObject/Stack.h b/Engine/Source/Runtime/CoreUObject/Public/UObject/Stack.h index 781d165db1c2..19afe8efff41 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/UObject/Stack.h +++ b/Engine/Source/Runtime/CoreUObject/Public/UObject/Stack.h @@ -41,10 +41,10 @@ enum EPropertyType CPT_Name, CPT_Delegate, CPT_Interface, - CPT_Range, + CPT_Unused_Index_19, CPT_Struct, - CPT_Vector, - CPT_Rotation, + CPT_Unused_Index_21, + CPT_Unused_Index_22, CPT_String, CPT_Text, CPT_MulticastDelegate, @@ -55,8 +55,6 @@ enum EPropertyType CPT_Map, CPT_Set, - // when you add new property types, make sure you add the corresponding entry - // in the PropertyTypeToNameMap array in ScriptCompiler.cpp!! CPT_MAX }; diff --git a/Engine/Source/Runtime/CoreUObject/Public/UObject/StructOnScope.h b/Engine/Source/Runtime/CoreUObject/Public/UObject/StructOnScope.h index 563a2c511016..9c4c5db94aff 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/UObject/StructOnScope.h +++ b/Engine/Source/Runtime/CoreUObject/Public/UObject/StructOnScope.h @@ -24,7 +24,7 @@ protected: { if (ScriptStruct.IsValid()) { - SampleStructMemory = (uint8*)FMemory::Malloc(ScriptStruct->GetStructureSize()); + SampleStructMemory = (uint8*)FMemory::Malloc(ScriptStruct->GetStructureSize() ? ScriptStruct->GetStructureSize() : 1); ScriptStruct.Get()->InitializeStruct(SampleStructMemory); OwnsMemory = true; } diff --git a/Engine/Source/Runtime/CoreUObject/Public/UObject/UObjectAnnotation.h b/Engine/Source/Runtime/CoreUObject/Public/UObject/UObjectAnnotation.h index 6f8b8f097759..0f084287fb95 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/UObject/UObjectAnnotation.h +++ b/Engine/Source/Runtime/CoreUObject/Public/UObject/UObjectAnnotation.h @@ -786,5 +786,5 @@ private: // Definition is in UObjectGlobals.cpp -extern COREUOBJECT_API FUObjectAnnotationSparseBool GSelectedAnnotation; +extern COREUOBJECT_API FUObjectAnnotationSparseBool GSelectedObjectAnnotation; diff --git a/Engine/Source/Runtime/CoreUObject/Public/UObject/UObjectArray.h b/Engine/Source/Runtime/CoreUObject/Public/UObject/UObjectArray.h index d65343a4fd28..d822882e04e7 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/UObject/UObjectArray.h +++ b/Engine/Source/Runtime/CoreUObject/Public/UObject/UObjectArray.h @@ -16,7 +16,9 @@ * Controls whether the number of available elements is being tracked in the ObjObjects array. * By default it is only tracked in WITH_EDITOR builds as it adds a small amount of tracking overhead */ +#if !defined(UE_GC_TRACK_OBJ_AVAILABLE) #define UE_GC_TRACK_OBJ_AVAILABLE (WITH_EDITOR) +#endif /** * Single item in the UObject array. @@ -182,18 +184,6 @@ struct FUObjectItem return !!(Flags & int32(EInternalObjectFlags::RootSet)); } - FORCEINLINE void SetNoStrongReference() - { - Flags |= int32(EInternalObjectFlags::NoStrongReference); - } - FORCEINLINE void ClearNoStrongReference() - { - Flags &= ~int32(EInternalObjectFlags::NoStrongReference); - } - FORCEINLINE bool IsNoStrongReference() const - { - return !!(Flags & int32(EInternalObjectFlags::NoStrongReference)); - } FORCEINLINE void ResetSerialNumberAndFlags() { Flags = 0; @@ -844,6 +834,19 @@ public: /** Frees the cluster at the specified index */ void FreeCluster(int32 InClusterIndex); + /** + * Gets the cluster the specified object is a root of or belongs to. + * @Param ClusterRootOrObjectFromCluster Root cluster object or object that belongs to a cluster + */ + FUObjectCluster* GetObjectCluster(UObjectBaseUtility* ClusterRootOrObjectFromCluster); + + + /** + * Dissolves a cluster and all clusters that reference it + * @Param ClusterRootOrObjectFromCluster Root cluster object or object that belongs to a cluster + */ + void DissolveCluster(UObjectBaseUtility* ClusterRootOrObjectFromCluster); + /** Dissolve all clusters marked for dissolving */ void DissolveClusters(); diff --git a/Engine/Source/Runtime/CoreUObject/Public/UObject/UObjectGlobals.h b/Engine/Source/Runtime/CoreUObject/Public/UObject/UObjectGlobals.h index f78ccfc748a2..ede8ff11f7bf 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/UObject/UObjectGlobals.h +++ b/Engine/Source/Runtime/CoreUObject/Public/UObject/UObjectGlobals.h @@ -714,10 +714,7 @@ template struct TIsPODType< TSubobjectPtrDeprecated > { enum { Value template struct TIsZeroConstructType< TSubobjectPtrDeprecated > { enum { Value = true }; }; template struct TIsWeakPointerType< TSubobjectPtrDeprecated > { enum { Value = false }; }; -#define TSubobjectPtr \ - EMIT_DEPRECATED_WARNING_MESSAGE("TSubobjectPtr is deprecated and should no longer be used. Please use pointers instead.") \ - TSubobjectPtrDeprecated - + /** * Internal class to finalize UObject creation (initialize properties) after the real C++ constructor is called. @@ -937,26 +934,6 @@ private: */ static void InitProperties(UObject* Obj, UClass* DefaultsClass, UObject* DefaultData, bool bCopyTransientsFromClassDefaults); - /** - * Helper method to assist with initializing object properties from an explicit list. - * - * @param InPropertyList only these properties will be copied from defaults - * @param InStruct the current scope for which the given property list applies - * @param DataPtr destination address (where to start copying values to) - * @param DefaultDataPtr source address (where to start copying the defaults data from) - */ - static void InitPropertiesFromCustomList(const FCustomPropertyListNode* InPropertyList, UStruct* InStruct, uint8* DataPtr, const uint8* DefaultDataPtr); - - /** - * Helper method to assist with initializing from an array property with an explicit item list. - * - * @param ArrayProperty the array property for which the given property list applies - * @param InPropertyList only these properties (indices) will be copied from defaults - * @param DataPtr destination address (where to start copying values to) - * @param DefaultDataPtr source address (where to start copying the defaults data from) - */ - static void InitArrayPropertyFromCustomList(const UArrayProperty* ArrayProperty, const FCustomPropertyListNode* InPropertyList, uint8* DataPtr, const uint8* DefaultDataPtr); - bool IsInstancingAllowed() const; /** @@ -1112,9 +1089,6 @@ private: #endif // USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING }; -#define FPostConstructInitializeProperties \ - FObjectInitializer \ - EMIT_DEPRECATED_WARNING_MESSAGE("FPostConstructInitializeProperties is deprecated and was renamed to FObjectInitializer. Please use that type instead.") /** * Helper class for script integrations to access some UObject innards. Needed for script-generated UObject classes @@ -1701,6 +1675,7 @@ public: } } + virtual ~FReferenceCollector() { } /** * If true archetype references should not be added to this collector. */ @@ -1714,15 +1689,17 @@ public: */ virtual void AllowEliminatingReferences(bool bAllow) {} /** - * Sets the property that is currently being serialized - */ + * Sets the property that is currently being serialized + */ virtual void SetSerializedProperty(class UProperty* Inproperty) {} /** - * Gets the property that is currently being serialized - */ + * Gets the property that is currently being serialized + */ virtual class UProperty* GetSerializedProperty() const { return nullptr; } - - virtual void SetShouldHandleAsWeakRef(bool bWeakRef) {} + /** + * Marks a specific object reference as a weak reference. This does not affect GC but will be freed at a later point + */ + virtual void MarkWeakObjectReferenceForClearing(UObject** WeakReference) {} protected: /** * Handle object reference. Called by AddReferencedObject. @@ -1847,6 +1824,10 @@ struct COREUOBJECT_API FCoreUObjectDelegates DECLARE_MULTICAST_DELEGATE_TwoParams(FOnPackageReloaded, EPackageReloadPhase, FPackageReloadedEvent*); static FOnPackageReloaded OnPackageReloaded; + /** Called when a package reload request is received from a network file server */ + DECLARE_DELEGATE_OneParam(FNetworkFileRequestPackageReload, const TArray& /*PackageNames*/); + static FNetworkFileRequestPackageReload NetworkFileRequestPackageReload; + #if WITH_EDITOR // Callback for all object modifications DECLARE_MULTICAST_DELEGATE_OneParam(FOnObjectModified, UObject*); @@ -1881,11 +1862,7 @@ struct COREUOBJECT_API FCoreUObjectDelegates #endif //WITH_EDITOR - // Delegate type for redirector followed events ( Params: const FString& PackageName, UObject* Redirector ) - DECLARE_MULTICAST_DELEGATE_TwoParams(FOnRedirectorFollowed, const FString&, UObject*); - // Sent when a UObjectRedirector was followed to find the destination object - static FOnRedirectorFollowed RedirectorFollowed; /** Delegate used by SavePackage() to create the package backup */ static FAutoPackageBackupDelegate AutoPackageBackupDelegate; @@ -1940,10 +1917,6 @@ struct COREUOBJECT_API FCoreUObjectDelegates /** Queries whether an object should be loaded on top ( replace ) an already existing one */ static FOnLoadObjectsOnTop ShouldLoadOnTop; - /** called when loading a string asset reference */ - DECLARE_DELEGATE_OneParam(FStringAssetReferenceLoaded, const FString&); - static FStringAssetReferenceLoaded StringAssetReferenceLoaded; - /** called when loading a string asset reference */ DECLARE_MULTICAST_DELEGATE_OneParam(FPackageLoadedFromStringAssetReference, const FName&); static FPackageLoadedFromStringAssetReference PackageLoadedFromStringAssetReference; @@ -1952,13 +1925,21 @@ struct COREUOBJECT_API FCoreUObjectDelegates DECLARE_MULTICAST_DELEGATE_OneParam(FPackageCreatedForLoad, class UPackage*); static FPackageCreatedForLoad PackageCreatedForLoad; - /** called when saving a string asset reference, can replace the value with something else */ - DECLARE_DELEGATE_RetVal_OneParam(FString, FStringAssetReferenceSaving, FString const& /*SavingAssetLongPathname*/); - static FStringAssetReferenceSaving StringAssetReferenceSaving; - /** Called when trying to figure out if a UObject is a primary asset, if it doesn't know */ DECLARE_DELEGATE_RetVal_OneParam(FPrimaryAssetId, FGetPrimaryAssetIdForObject, const UObject*); static FGetPrimaryAssetIdForObject GetPrimaryAssetIdForObject; + + DECLARE_DELEGATE_OneParam(FStringAssetReferenceLoaded, const FString&); + DEPRECATED(4.17, "StringAssetReferenceLoaded is deprecated, call FStringAssetReference::PostLoadPath instead") + static FStringAssetReferenceLoaded StringAssetReferenceLoaded; + + DECLARE_DELEGATE_RetVal_OneParam(FString, FStringAssetReferenceSaving, FString const& /*SavingAssetLongPathname*/); + DEPRECATED(4.17, "StringAssetReferenceSaving is deprecated, call FStringAssetReference::PreSavePath instead") + static FStringAssetReferenceSaving StringAssetReferenceSaving; + + DECLARE_MULTICAST_DELEGATE_TwoParams(FOnRedirectorFollowed, const FString&, UObject*); + DEPRECATED(4.17, "RedirectorFollowed is deprecated, FixeupRedirects was replaced with ResavePackages -FixupRedirect") + static FOnRedirectorFollowed RedirectorFollowed; }; /** Allows release builds to override not verifying GC assumptions. Useful for profiling as it's hitchy. */ diff --git a/Engine/Source/Runtime/CoreUObject/Public/UObject/UnrealType.h b/Engine/Source/Runtime/CoreUObject/Public/UObject/UnrealType.h index 60c9584ded88..2705fc686bea 100644 --- a/Engine/Source/Runtime/CoreUObject/Public/UObject/UnrealType.h +++ b/Engine/Source/Runtime/CoreUObject/Public/UObject/UnrealType.h @@ -897,7 +897,7 @@ public: enum { CPPSize = sizeof(TCppType), - CPPAlignment = ALIGNOF(TCppType) + CPPAlignment = alignof(TCppType) }; static FORCEINLINE TCHAR const* GetTypeName() @@ -3361,7 +3361,27 @@ public: return false; } + static FScriptMapHelper CreateHelperFormInnerProperties(UProperty* InKeyProperty, UProperty* InValProperty, const void *InMap) + { + check(InKeyProperty && InValProperty); + + FScriptMapHelper ScriptMapHelper; + ScriptMapHelper.KeyProp = InKeyProperty; + ScriptMapHelper.ValueProp = InValProperty; + ScriptMapHelper.Map = (FScriptMap*)InMap; + ScriptMapHelper.MapLayout = FScriptMap::GetScriptLayout(InKeyProperty->GetSize(), InKeyProperty->GetMinAlignment(), InValProperty->GetSize(), InValProperty->GetMinAlignment()); + + return ScriptMapHelper; + } + private: + FScriptMapHelper() + : KeyProp(nullptr) + , ValueProp(nullptr) + , Map(nullptr) + , MapLayout(FScriptMap::GetScriptLayout(0, 1, 0, 1)) + {} + /** * Internal function to call into the property system to construct / initialize elements. * @@ -3832,7 +3852,28 @@ public: return false; } -private: + static FScriptSetHelper CreateHelperFormElementProperty(UProperty* InElementProperty, const void *InSet) + { + check(InElementProperty); + + FScriptSetHelper ScriptSetHelper; + ScriptSetHelper.ElementProp = InElementProperty; + ScriptSetHelper.Set = (FScriptSet*)InSet; + + const int32 ElementPropSize = InElementProperty->GetSize(); + const int32 ElementPropAlignment = InElementProperty->GetMinAlignment(); + ScriptSetHelper.SetLayout = FScriptSet::GetScriptLayout(ElementPropSize, ElementPropAlignment); + + return ScriptSetHelper; + } + +private: + FScriptSetHelper() + : ElementProp(nullptr) + , Set(nullptr) + , SetLayout(FScriptSet::GetScriptLayout(0, 1)) + {} + /** * Internal function to call into the property system to construct / initialize elements. * @@ -4268,18 +4309,6 @@ struct FPropertyChangedEvent { } - - DEPRECATED(4.7, "The bInChangesTopology parameter has been removed, use the two-argument constructor of FPropertyChangedEvent instead") - FPropertyChangedEvent(UProperty* InProperty, const bool /*bInChangesTopology*/, EPropertyChangeType::Type InChangeType) - : Property(InProperty) - , MemberProperty(InProperty) - , ChangeType(InChangeType) - , ObjectIteratorIndex(INDEX_NONE) - , ArrayIndicesPerObject(nullptr) - , TopLevelObjects(nullptr) - { - } - void SetActiveMemberProperty( UProperty* InActiveMemberProperty ) { MemberProperty = InActiveMemberProperty; @@ -4325,6 +4354,14 @@ struct FPropertyChangedEvent */ const UObject* GetObjectBeingEdited(int32 Index) const { return TopLevelObjects ? (*TopLevelObjects)[Index] : nullptr; } + /** + * Simple utility to get the name of the property and takes care of the possible null property. + */ + FName GetPropertyName() const + { + return (Property != nullptr) ? Property->GetFName() : NAME_None; + } + /** * The actual property that changed */ @@ -4864,22 +4901,7 @@ inline bool UObject::IsBasedOnArchetype( const UObject* const SomeObject ) cons #define CPP_PROPERTY(name) FObjectInitializer(), EC_CppProperty, STRUCT_OFFSET(ThisClass, name) #define CPP_PROPERTY_BASE(name, base) FObjectInitializer(), EC_CppProperty, STRUCT_OFFSET(base, name) -/** - The mac does not interpret a pointer to a bool* that is say 0x40 as true!, so we need to use uint8 for that. - this littler helper provides the correct type to use for bitfield determination -**/ -template -struct FTestType -{ - typedef T TestType; -}; -template<> -struct FTestType -{ - static_assert(sizeof(bool) == sizeof(uint8), "Bool is not one byte."); - typedef uint8 TestType; -}; - +static_assert(sizeof(bool) == sizeof(uint8), "Bool is not one byte."); struct COREUOBJECT_API DetermineBitfieldOffsetAndMask { @@ -4925,26 +4947,21 @@ struct COREUOBJECT_API DetermineBitfieldOffsetAndMask * * @param SizeOf Size of the class with the bitfield. */ - template void DoDetermineBitfieldOffsetAndMask(const SIZE_T SizeOf) { - typedef typename FTestType::TestType TTestType; - static_assert(sizeof(TTestType) == sizeof(BitfieldType), "Wrong size for test type."); - - void* Buffer = AllocateBuffer(SizeOf); - TTestType* Test = (TTestType*)Buffer; + uint8* Buffer = (uint8*)AllocateBuffer(SizeOf); Offset = 0; BitMask = 0; SetBit(Buffer, true); // Here we are making the assumption that bitfields are aligned in the struct. Probably true. // If not, it may be ok unless we are on a page boundary or something, but the check will fire in that case. // Have faith. - for (uint32 TestOffset = 0; TestOffset < SizeOf / sizeof(BitfieldType); TestOffset++) + for (uint32 TestOffset = 0; TestOffset < SizeOf; TestOffset++) { - if (Test[TestOffset]) + if (Buffer[TestOffset]) { - Offset = TestOffset * sizeof(BitfieldType); - BitMask = (uint32)Test[TestOffset]; + Offset = TestOffset; + BitMask = (uint32)Buffer[TestOffset]; check(FMath::RoundUpToPowerOfTwo(uint32(BitMask)) == uint32(BitMask)); // better be only one bit on break; } @@ -4957,16 +4974,16 @@ protected: }; /** build a struct that has a method that will return the bitmask for a bitfield **/ -#define CPP_BOOL_PROPERTY_BITMASK_STRUCT(BitFieldName, ClassName, BitfieldType) \ +#define CPP_BOOL_PROPERTY_BITMASK_STRUCT(BitFieldName, ClassName) \ struct FDetermineBitMask_##ClassName##_##BitFieldName : public DetermineBitfieldOffsetAndMask\ { \ FDetermineBitMask_##ClassName##_##BitFieldName() \ { \ - DoDetermineBitfieldOffsetAndMask(sizeof(ClassName)); \ + DoDetermineBitfieldOffsetAndMask(sizeof(ClassName)); \ } \ virtual void SetBit(void* Scratch, bool Value) \ { \ - ((ClassName*)Scratch)->BitFieldName = (BitfieldType)Value; \ + ((ClassName*)Scratch)->BitFieldName = Value ? 1 : 0; \ } \ } DetermineBitMask_##ClassName##_##BitFieldName diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12Adapter.cpp b/Engine/Source/Runtime/D3D12RHI/Private/D3D12Adapter.cpp index 59610bc2680a..2c111bcaa787 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12Adapter.cpp +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12Adapter.cpp @@ -25,8 +25,6 @@ struct FRHICommandSignalFrameFence : public FRHICommand::ThisThreadObject = nullptr; - FD3D12Adapter::FD3D12Adapter(FD3D12AdapterDesc& DescIn) : Desc(DescIn) , bDeviceRemoved(false) @@ -468,7 +466,7 @@ void FD3D12Adapter::SignalFrameFence_RenderThread(FRHICommandListImmediate& RHIC const uint64 PreviousFence = FrameFence.IncrementCurrentFence(); // Queue a command to signal the frame fence is complete on the GPU (on the RHI thread timeline if using an RHI thread). - if (RHICmdList.Bypass() || !GRHIThread) + if (RHICmdList.Bypass() || !IsRunningRHIInSeparateThread()) { FRHICommandSignalFrameFence Cmd(pCommandQueue, &FrameFence, PreviousFence); Cmd.Execute(RHICmdList); diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12Adapter.h b/Engine/Source/Runtime/D3D12RHI/Private/D3D12Adapter.h index bd004f2a5533..6ca514a4a99e 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12Adapter.h +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12Adapter.h @@ -45,6 +45,12 @@ enum EMultiGPUMode static const bool GRedirectDefaultContextForAFR = true; +/// @cond DOXYGEN_WARNINGS + +void* FD3D12ThreadLocalObject::ThisThreadObject = nullptr; + +/// @endcond + struct FD3D12AdapterDesc { FD3D12AdapterDesc() @@ -82,6 +88,7 @@ class FD3D12Adapter : public FNoncopyable public: FD3D12Adapter(FD3D12AdapterDesc& DescIn); + virtual ~FD3D12Adapter() { } void Initialize(FD3D12DynamicRHI* RHI); void InitializeDevices(); @@ -303,6 +310,7 @@ protected: uint32 InUsage, FRHIResourceCreateInfo& CreateInfo, uint32 Alignment, + FD3D12TransientResource& TransientResource, FD3D12ResourceLocation& ResourceLocation); // Creates default root and execute indirect signatures diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12Allocation.cpp b/Engine/Source/Runtime/D3D12RHI/Private/D3D12Allocation.cpp index b936db3ddcc9..df2c8e0d8aa4 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12Allocation.cpp +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12Allocation.cpp @@ -785,7 +785,7 @@ void FD3D12BucketAllocator::ReleaseAllResources() while (ExpiredBlocks.Dequeue(Block)) { - if (Block.BucketIndex >= MinCleanupBucket) + if (Block.BucketIndex >= MinCleanupBucket) //-V547 { SAFE_RELEASE(Block.ResourceHeap); } diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12Buffer.cpp b/Engine/Source/Runtime/D3D12RHI/Private/D3D12Buffer.cpp index 43c583420079..91cc1b5b99d8 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12Buffer.cpp +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12Buffer.cpp @@ -81,6 +81,7 @@ void FD3D12Adapter::AllocateBuffer(FD3D12Device* Device, uint32 InUsage, FRHIResourceCreateInfo& CreateInfo, uint32 Alignment, + FD3D12TransientResource& TransientResource, FD3D12ResourceLocation& ResourceLocation) { // Explicitly check that the size is nonzero before allowing CreateBuffer to opaquely fail. @@ -120,6 +121,8 @@ BufferType* FD3D12Adapter::CreateRHIBuffer(FRHICommandListImmediate* RHICmdList, FRHIResourceCreateInfo& CreateInfo, bool SkipCreate) { + SCOPE_CYCLE_COUNTER(STAT_D3D12CreateBufferTime); + const bool bIsDynamic = (InUsage & BUF_AnyDynamic) ? true : false; BufferType* BufferOut = CreateLinkedObject([&](FD3D12Device* Device) @@ -127,9 +130,9 @@ BufferType* FD3D12Adapter::CreateRHIBuffer(FRHICommandListImmediate* RHICmdList, BufferType* NewBuffer = new BufferType(Device, Stride, Size, InUsage); NewBuffer->BufferAlignment = Alignment; - if (SkipCreate == false) + if (!SkipCreate) { - AllocateBuffer(Device, InDesc, Size, InUsage, CreateInfo, Alignment, NewBuffer->ResourceLocation); + AllocateBuffer(Device, InDesc, Size, InUsage, CreateInfo, Alignment, *NewBuffer, NewBuffer->ResourceLocation); } return NewBuffer; diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12CommandContext.cpp b/Engine/Source/Runtime/D3D12RHI/Private/D3D12CommandContext.cpp index 8b72e87aa852..6c6143f58acf 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12CommandContext.cpp +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12CommandContext.cpp @@ -11,7 +11,8 @@ D3D12CommandContext.cpp: RHI Command Context implementation. // @TODO: Fix and re-enable int32 GCommandListBatchingMode = CLB_NormalBatching; #else -int32 GCommandListBatchingMode = CLB_AggressiveBatching; +// @todo: CLB_AggressiveBatching disabled as it caused flickering in lighting on PC +int32 GCommandListBatchingMode = CLB_NormalBatching; #endif static FAutoConsoleVariableRef CVarCommandListBatchingMode( diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12CommandContext.h b/Engine/Source/Runtime/D3D12RHI/Private/D3D12CommandContext.h index aac75ab80080..2d77bc6c1c27 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12CommandContext.h +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12CommandContext.h @@ -290,7 +290,6 @@ public: virtual void RHIUpdateTextureReference(FTextureReferenceRHIParamRef TextureRef, FTextureRHIParamRef NewTexture) final override; virtual void RHIClearMRTImpl(bool bClearColor, int32 NumClearColors, const FLinearColor* ColorArray, bool bClearDepth, float Depth, bool bClearStencil, uint32 Stencil); - virtual void UpdateMemoryStats(); // When using Alternate Frame Rendering some temporal effects i.e. effects which consume GPU work from previous frames must sychronize their resources diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12CommandList.cpp b/Engine/Source/Runtime/D3D12RHI/Private/D3D12CommandList.cpp index 62d55fb0584b..bc346a70b69f 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12CommandList.cpp +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12CommandList.cpp @@ -19,6 +19,13 @@ void FD3D12CommandListHandle::AddUAVBarrier() CommandListData->CurrentOwningContext->numBarriers++; } +void FD3D12CommandListHandle::AddAliasingBarrier(FD3D12Resource* pResource) +{ + check(CommandListData); + CommandListData->ResourceBarrierBatcher.AddAliasingBarrier(pResource->GetResource()); + CommandListData->CurrentOwningContext->numBarriers++; +} + void FD3D12CommandListHandle::Create(FD3D12Device* ParentDevice, D3D12_COMMAND_LIST_TYPE CommandListType, FD3D12CommandAllocator& CommandAllocator, FD3D12CommandListManager* InCommandListManager) { check(!CommandListData); diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12CommandList.h b/Engine/Source/Runtime/D3D12RHI/Private/D3D12CommandList.h index 750e73f65f76..41bb3d797734 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12CommandList.h +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12CommandList.h @@ -64,7 +64,6 @@ private: if (!IsClosed) { FlushResourceBarriers(); - VERIFYD3D12RESULT(CommandList->Close()); D3DX12Residency::Close(ResidencySet); @@ -512,6 +511,8 @@ public: // Adds a UAV barrier to the barrier batch void AddUAVBarrier(); + void AddAliasingBarrier(FD3D12Resource* pResource); + // Flushes the batched resource barriers to the current command list void FlushResourceBarriers() { diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12Commands.cpp b/Engine/Source/Runtime/D3D12RHI/Private/D3D12Commands.cpp index 3d0da34b543a..5cfa5de3a51c 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12Commands.cpp +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12Commands.cpp @@ -63,11 +63,11 @@ void FD3D12DynamicRHI::SetupRecursiveResources() extern ENGINE_API TGlobalResource GScreenVertexDeclaration; // TODO: Waiting to integrate MSAA fix for ResolveShader.h - if (GMaxRHIShaderPlatform == SP_XBOXONE) + if (GMaxRHIShaderPlatform == SP_XBOXONE_D3D12) return; TShaderMapRef ResolveVertexShader(ShaderMap); - if (GMaxRHIShaderPlatform == SP_PCD3D_SM5 || GMaxRHIShaderPlatform == SP_XBOXONE) + if (GMaxRHIShaderPlatform == SP_PCD3D_SM5 || GMaxRHIShaderPlatform == SP_XBOXONE_D3D12) { TShaderMapRef ResolvePixelShader_Depth(ShaderMap); ResolvePixelShader_Depth->GetPixelShader(); @@ -209,6 +209,11 @@ void FD3D12CommandContext::RHIDispatchIndirectComputeShader(FVertexBufferRHIPara void FD3D12CommandContext::RHITransitionResources(EResourceTransitionAccess TransitionType, FTextureRHIParamRef* InTextures, int32 NumTextures) { #if !USE_D3D12RHI_RESOURCE_STATE_TRACKING + if (TransitionType == EResourceTransitionAccess::EMetaData) + { + return; + } + check(TransitionType == EResourceTransitionAccess::EReadable || TransitionType == EResourceTransitionAccess::EWritable || TransitionType == EResourceTransitionAccess::ERWSubResBarrier); // TODO: Remove this skip. // Skip for now because we don't have enough info about what mip to transition yet. diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12DescriptorCache.h b/Engine/Source/Runtime/D3D12RHI/Private/D3D12DescriptorCache.h index 8e1ac8322909..a96c02291cd4 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12DescriptorCache.h +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12DescriptorCache.h @@ -314,6 +314,7 @@ class FD3D12OnlineHeap : public FD3D12DeviceChild, public FD3D12SingleNodeGPUObj { public: FD3D12OnlineHeap(FD3D12Device* Device, GPUNodeMask Node, bool CanLoopAround, FD3D12DescriptorCache* _Parent = nullptr); + virtual ~FD3D12OnlineHeap() { } FORCEINLINE D3D12_CPU_DESCRIPTOR_HANDLE GetCPUSlotHandle(uint32 Slot) const { return{ CPUBase.ptr + Slot * DescriptorSize }; } FORCEINLINE D3D12_GPU_DESCRIPTOR_HANDLE GetGPUSlotHandle(uint32 Slot) const { return{ GPUBase.ptr + Slot * DescriptorSize }; } diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12Device.cpp b/Engine/Source/Runtime/D3D12RHI/Private/D3D12Device.cpp index 90318d8c9a42..cd84b4f91aaf 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12Device.cpp +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12Device.cpp @@ -30,9 +30,9 @@ FD3D12Device::FD3D12Device(GPUNodeMask Node, FD3D12Adapter* InAdapter) : OcclusionQueryHeap(this, D3D12_QUERY_HEAP_TYPE_OCCLUSION, 32768), DefaultBufferAllocator(this, Node), //Note: Cross node buffers are possible PendingCommandListsTotalWorkCommands(0), - CommandListManager(this, D3D12_COMMAND_LIST_TYPE_DIRECT), - CopyCommandListManager(this, D3D12_COMMAND_LIST_TYPE_COPY), - AsyncCommandListManager(this, D3D12_COMMAND_LIST_TYPE_COMPUTE), + CommandListManager(nullptr), + CopyCommandListManager(nullptr), + AsyncCommandListManager(nullptr), TextureStreamingCommandAllocatorManager(this, D3D12_COMMAND_LIST_TYPE_COPY), GlobalSamplerHeap(this, Node), GlobalViewHeap(this, Node), @@ -41,6 +41,7 @@ FD3D12Device::FD3D12Device(GPUNodeMask Node, FD3D12Adapter* InAdapter) : FD3D12SingleNodeGPUObject(Node), FD3D12AdapterChild(InAdapter) { + InitPlatformSpecific(); } ID3D12Device* FD3D12Device::GetDevice() @@ -111,7 +112,7 @@ void FD3D12Device::CreateCommandContexts() bool FD3D12Device::IsGPUIdle() { - FD3D12Fence& Fence = CommandListManager.GetFence(); + FD3D12Fence& Fence = CommandListManager->GetFence(); return Fence.GetLastCompletedFence() >= (Fence.GetCurrentFence() - 1); } @@ -158,9 +159,9 @@ void FD3D12Device::SetupAfterDeviceCreation() // Init the occlusion query heap OcclusionQueryHeap.Init(); - CommandListManager.Create(L"3D Queue"); - CopyCommandListManager.Create(L"Copy Queue"); - AsyncCommandListManager.Create(L"Async Compute Queue", 0, AsyncComputePriority_Default); + CommandListManager->Create(L"3D Queue"); + CopyCommandListManager->Create(L"Copy Queue"); + AsyncCommandListManager->Create(L"Async Compute Queue", 0, AsyncComputePriority_Default); // Needs to be called before creating command contexts UpdateConstantBufferPageProperties(); @@ -207,9 +208,9 @@ void FD3D12Device::UpdateMSAASettings() void FD3D12Device::Cleanup() { // Wait for the command queues to flush - CommandListManager.WaitForCommandQueueFlush(); - CopyCommandListManager.WaitForCommandQueueFlush(); - AsyncCommandListManager.WaitForCommandQueueFlush(); + CommandListManager->WaitForCommandQueueFlush(); + CopyCommandListManager->WaitForCommandQueueFlush(); + AsyncCommandListManager->WaitForCommandQueueFlush(); check(!GIsCriticalError); @@ -244,9 +245,9 @@ void FD3D12Device::Cleanup() } */ - CommandListManager.Destroy(); - CopyCommandListManager.Destroy(); - AsyncCommandListManager.Destroy(); + CommandListManager->Destroy(); + CopyCommandListManager->Destroy(); + AsyncCommandListManager->Destroy(); OcclusionQueryHeap.Destroy(); diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12Device.h b/Engine/Source/Runtime/D3D12RHI/Private/D3D12Device.h index 1979e5defd9e..77516cfd3449 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12Device.h +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12Device.h @@ -17,11 +17,19 @@ public: FD3D12Device(); FD3D12Device(GPUNodeMask Node, FD3D12Adapter* InAdapter); + virtual ~FD3D12Device() + { + delete CommandListManager; + delete CopyCommandListManager; + delete AsyncCommandListManager; + } + /** Intialized members*/ void Initialize(); void CreateCommandContexts(); + void InitPlatformSpecific(); /** * Cleanup the device. * This function must be called from the main game thread. @@ -53,9 +61,9 @@ public: #endif inline FD3D12OfflineDescriptorManager& GetSamplerDescriptorAllocator() { return SamplerAllocator; } - inline FD3D12CommandListManager& GetCommandListManager() { return CommandListManager; } - inline FD3D12CommandListManager& GetCopyCommandListManager() { return CopyCommandListManager; } - inline FD3D12CommandListManager& GetAsyncCommandListManager() { return AsyncCommandListManager; } + inline FD3D12CommandListManager& GetCommandListManager() { return *CommandListManager; } + inline FD3D12CommandListManager& GetCopyCommandListManager() { return *CopyCommandListManager; } + inline FD3D12CommandListManager& GetAsyncCommandListManager() { return *AsyncCommandListManager; } inline FD3D12CommandAllocatorManager& GetTextureStreamingCommandAllocatorManager() { return TextureStreamingCommandAllocatorManager; } inline FD3D12DefaultBufferAllocator& GetDefaultBufferAllocator() { return DefaultBufferAllocator; } inline FD3D12GlobalOnlineHeap& GetGlobalSamplerHeap() { return GlobalSamplerHeap; } @@ -101,9 +109,9 @@ public: protected: /** A pool of command lists we can cycle through for the global D3D device */ - FD3D12CommandListManager CommandListManager; - FD3D12CommandListManager CopyCommandListManager; - FD3D12CommandListManager AsyncCommandListManager; + FD3D12CommandListManager* CommandListManager; + FD3D12CommandListManager* CopyCommandListManager; + FD3D12CommandListManager* AsyncCommandListManager; /** A pool of command allocators that texture streaming threads share */ FD3D12CommandAllocatorManager TextureStreamingCommandAllocatorManager; diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12DirectCommandListManager.cpp b/Engine/Source/Runtime/D3D12RHI/Private/D3D12DirectCommandListManager.cpp index 23ac465becb4..309514452c0f 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12DirectCommandListManager.cpp +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12DirectCommandListManager.cpp @@ -475,11 +475,10 @@ uint32 FD3D12CommandListManager::GetResourceBarrierCommandList(FD3D12CommandList // Should only be doing this for the few resources that need state tracking check(PRB.Resource->RequiresResourceStateTracking()); - CResourceState* pResourceState = PRB.Resource->GetResourceState(); - check(pResourceState); + CResourceState& ResourceState = PRB.Resource->GetResourceState(); Desc.Transition.Subresource = PRB.SubResource; - const D3D12_RESOURCE_STATES Before = pResourceState->GetSubresourceState(Desc.Transition.Subresource); + const D3D12_RESOURCE_STATES Before = ResourceState.GetSubresourceState(Desc.Transition.Subresource); const D3D12_RESOURCE_STATES After = PRB.State; check(Before != D3D12_RESOURCE_STATE_TBD && Before != D3D12_RESOURCE_STATE_CORRUPT); @@ -499,7 +498,7 @@ uint32 FD3D12CommandListManager::GetResourceBarrierCommandList(FD3D12CommandList if (Before != LastState) { - pResourceState->SetSubresourceState(Desc.Transition.Subresource, LastState); + ResourceState.SetSubresourceState(Desc.Transition.Subresource, LastState); } } diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12DirectCommandListManager.h b/Engine/Source/Runtime/D3D12RHI/Private/D3D12DirectCommandListManager.h index ce4ad9c295ce..794cdcb70a28 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12DirectCommandListManager.h +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12DirectCommandListManager.h @@ -22,6 +22,7 @@ enum class CommandListState kFinished }; + struct FD3D12CommandListPayload { FD3D12CommandListPayload() : NumCommandLists(0) @@ -148,7 +149,7 @@ class FD3D12CommandListManager : public FD3D12DeviceChild, public FD3D12SingleNo { public: FD3D12CommandListManager(FD3D12Device* InParent, D3D12_COMMAND_LIST_TYPE CommandListType); - ~FD3D12CommandListManager(); + virtual ~FD3D12CommandListManager(); void Create(const TCHAR* Name, uint32 NumCommandLists = 0, uint32 Priority = 0); void Destroy(); @@ -165,7 +166,7 @@ public: void ReleaseCommandList(FD3D12CommandListHandle& hList); void ExecuteCommandList(FD3D12CommandListHandle& hList, bool WaitForCompletion = false); - void ExecuteCommandLists(TArray& Lists, bool WaitForCompletion = false); + virtual void ExecuteCommandLists(TArray& Lists, bool WaitForCompletion = false); uint32 GetResourceBarrierCommandList(FD3D12CommandListHandle& hList, FD3D12CommandListHandle& hResourceBarrierList); @@ -193,7 +194,7 @@ public: void ReleaseResourceBarrierCommandListAllocator(); -private: +protected: // Returns signaled Fence uint64 ExecuteAndIncrementFence(FD3D12CommandListPayload& Payload, FD3D12Fence &Fence); FD3D12CommandListHandle CreateCommandListHandle(FD3D12CommandAllocator& CommandAllocator); diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12IndexBuffer.cpp b/Engine/Source/Runtime/D3D12RHI/Private/D3D12IndexBuffer.cpp index 59e2500b232a..c8667dc1da01 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12IndexBuffer.cpp +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12IndexBuffer.cpp @@ -21,6 +21,11 @@ D3D12_RESOURCE_DESC CreateIndexBufferResourceDesc(uint32 Size, uint32 InUsage) Desc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE; } + if (InUsage & BUF_DrawIndirect) + { + Desc.Flags |= D3D12RHI_RESOURCE_FLAG_ALLOW_INDIRECT_BUFFER; + } + return Desc; } @@ -40,6 +45,11 @@ FIndexBufferRHIRef FD3D12DynamicRHI::RHICreateIndexBuffer(uint32 Stride, uint32 const uint32 Alignment = 4; FD3D12IndexBuffer* Buffer = GetAdapter().CreateRHIBuffer(nullptr, Desc, Alignment, Stride, Size, InUsage, CreateInfo, false); + if (Buffer->ResourceLocation.IsTransient()) + { + // TODO: this should ideally be set in platform-independent code, since this tracking is for the high level + Buffer->SetCommitted(false); + } UpdateBufferStats(&Buffer->ResourceLocation, true, D3D12_BUFFER_TYPE_INDEX); @@ -62,6 +72,11 @@ FIndexBufferRHIRef FD3D12DynamicRHI::CreateIndexBuffer_RenderThread(class FRHICo const uint32 Alignment = 4; FD3D12IndexBuffer* Buffer = GetAdapter().CreateRHIBuffer(&RHICmdList, Desc, Alignment, Stride, Size, InUsage, CreateInfo, false); + if (Buffer->ResourceLocation.IsTransient()) + { + // TODO: this should ideally be set in platform-independent code, since this tracking is for the high level + Buffer->SetCommitted(false); + } UpdateBufferStats(&Buffer->ResourceLocation, true, D3D12_BUFFER_TYPE_INDEX); @@ -89,6 +104,11 @@ FIndexBufferRHIRef FD3D12DynamicRHI::CreateAndLockIndexBuffer_RenderThread(class const bool bIsDynamic = (InUsage & BUF_AnyDynamic) ? true : false; FD3D12IndexBuffer* Buffer = GetAdapter().CreateRHIBuffer(&RHICmdList, Desc, Alignment, Stride, Size, InUsage, CreateInfo, bIsDynamic); + if (Buffer->ResourceLocation.IsTransient()) + { + // TODO: this should ideally be set in platform-independent code, since this tracking is for the high level + Buffer->SetCommitted(false); + } OutDataBuffer = LockIndexBuffer_RenderThread(RHICmdList, Buffer, 0, Size, RLM_WriteOnly); diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12PipelineState.h b/Engine/Source/Runtime/D3D12RHI/Private/D3D12PipelineState.h index 32b477289c4b..6ef12e2b6eb6 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12PipelineState.h +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12PipelineState.h @@ -86,24 +86,6 @@ template <> struct equality_pipeline_state_desc CVarD3D12ZeroBufferSizeInMB( ECVF_ReadOnly ); +/// @cond DOXYGEN_WARNINGS + FD3D12FastAllocator* FD3D12DynamicRHI::HelperThreadDynamicHeapAllocator = nullptr; +/// @endcond + FD3D12DynamicRHI* FD3D12DynamicRHI::SingleD3DRHI = nullptr; using namespace D3D12RHI; @@ -177,6 +181,9 @@ FD3D12DynamicRHI::FD3D12DynamicRHI(TArray& ChosenAdaptersIn) : if (!GIsEditor) { GRHISupportsRHIThread = true; +#if PLATFORM_XBOXONE + GRHISupportsRHIOnTaskThread = true; +#endif } GRHISupportsParallelRHIExecute = D3D12_SUPPORTS_PARALLEL_RHI_EXECUTE; diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12RHIPrivate.h b/Engine/Source/Runtime/D3D12RHI/Private/D3D12RHIPrivate.h index a08944426841..358189a3d288 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12RHIPrivate.h +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12RHIPrivate.h @@ -19,6 +19,8 @@ #define D3D12_SUPPORTS_PARALLEL_RHI_EXECUTE 1 +#define BATCH_COPYPAGEMAPPINGS 1 + #ifndef WITH_DX_PERF #define WITH_DX_PERF 0 #endif @@ -73,7 +75,7 @@ typedef FD3D12StateCacheBase FD3D12StateCache; #define EXECUTE_DEBUG_COMMAND_LISTS 0 #define ENABLE_PLACED_RESOURCES 0 // Disabled due to a couple of NVidia bugs related to placed resources. Works fine on Intel #define REMOVE_OLD_QUERY_BATCHES 1 // D3D12: MSFT: TODO: Works around a suspected UE4 InfiltratorDemo bug where a query is never released -#define NAME_OBJECTS !UE_BUILD_SHIPPING // Name objects in all builds except shipping +#define NAME_OBJECTS !(UE_BUILD_SHIPPING || UE_BUILD_TEST) // Name objects in all builds except shipping //@TODO: Improve allocator efficiency so we can increase these thresholds and improve performance // We measured 149MB of wastage in 340MB of allocations with DEFAULT_BUFFER_POOL_MAX_ALLOC_SIZE set to 512KB @@ -123,6 +125,12 @@ bool GIsDoingQuery = false; #define DEBUG_RHI_EXECUTE_COMMAND_LIST(scope) #endif +template< typename t_A, typename t_B > +inline t_A RoundUpToNextMultiple(const t_A& a, const t_B& b) +{ + return ((a - 1) / b + 1) * b; +} + using namespace D3D12RHI; static bool D3D12RHI_ShouldCreateWithD3DDebug() @@ -299,7 +307,6 @@ public: virtual class IRHIComputeContext* RHIGetDefaultAsyncComputeContext() final override; virtual class IRHICommandContextContainer* RHIGetCommandContextContainer(int32 Index, int32 Num) final override; - // FD3D12DynamicRHI interface. virtual uint32 GetDebugFlags(); virtual ID3D12CommandQueue* RHIGetD3DCommandQueue(); @@ -312,6 +319,7 @@ public: // virtual FVertexBufferRHIRef CreateVertexBuffer_RenderThread(class FRHICommandListImmediate& RHICmdList, uint32 Size, uint32 InUsage, FRHIResourceCreateInfo& CreateInfo); + virtual FStructuredBufferRHIRef CreateStructuredBuffer_RenderThread(class FRHICommandListImmediate& RHICmdList, uint32 Stride, uint32 Size, uint32 InUsage, FRHIResourceCreateInfo& CreateInfo); virtual void* LockVertexBuffer_RenderThread(class FRHICommandListImmediate& RHICmdList, FVertexBufferRHIParamRef VertexBuffer, uint32 Offset, uint32 SizeRHI, EResourceLockMode LockMode); virtual void UnlockVertexBuffer_RenderThread(class FRHICommandListImmediate& RHICmdList, FVertexBufferRHIParamRef VertexBuffer); virtual FVertexBufferRHIRef CreateAndLockVertexBuffer_RenderThread(class FRHICommandListImmediate& RHICmdList, uint32 Size, uint32 InUsage, FRHIResourceCreateInfo& CreateInfo, void*& OutDataBuffer); @@ -360,7 +368,7 @@ public: return false; } - if (RHICmdList->Bypass() || !GRHIThread) + if (RHICmdList->Bypass() || !IsRunningRHIInSeparateThread()) { return false; } @@ -1052,3 +1060,4 @@ private: } } }; + diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12RenderTarget.cpp b/Engine/Source/Runtime/D3D12RHI/Private/D3D12RenderTarget.cpp index 79b8951eb23c..e9fd86704875 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12RenderTarget.cpp +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12RenderTarget.cpp @@ -206,10 +206,7 @@ void FD3D12CommandContext::ResolveTextureUsingShader( DrawPrimitiveUP(RHICmdList, PT_TriangleStrip, 2, Vertices, sizeof(Vertices[0])); RHICmdList.Flush(); // always call flush when using a command list in RHI implementations before doing anything else. This is super hazardous. - if (SourceTexture) - { - ConditionalClearShaderResource(&SourceTexture->ResourceLocation); - } + ConditionalClearShaderResource(&SourceTexture->ResourceLocation); // Reset saved render targets CommitRenderTargetsAndUAVs(); @@ -608,6 +605,7 @@ static uint32 ComputeBytesPerPixel(DXGI_FORMAT Format) case DXGI_FORMAT_R10G10B10A2_UNORM: case DXGI_FORMAT_R11G11B10_FLOAT: case DXGI_FORMAT_R16G16_UNORM: + case DXGI_FORMAT_R32_UINT: BytesPerPixel = 4; break; case DXGI_FORMAT_R16G16B16A16_FLOAT: diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12Resources.cpp b/Engine/Source/Runtime/D3D12RHI/Private/D3D12Resources.cpp index 420ecb66e693..bde1ce35d6b0 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12Resources.cpp +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12Resources.cpp @@ -157,7 +157,6 @@ FD3D12Resource::FD3D12Resource(FD3D12Device* ParentDevice, , Desc(InDesc) , PlaneCount(::GetPlaneCount(Desc.Format)) , SubresourceCount(0) - , pResourceState(nullptr) , DefaultResourceState(D3D12_RESOURCE_STATE_TBD) , bRequiresResourceStateTracking(true) , bDepthStencil(false) @@ -183,12 +182,6 @@ FD3D12Resource::FD3D12Resource(FD3D12Device* ParentDevice, FD3D12Resource::~FD3D12Resource() { - if (pResourceState) - { - delete pResourceState; - pResourceState = nullptr; - } - if (D3DX12Residency::IsInitialized(ResidencyHandle)) { D3DX12Residency::EndTrackingObject(GetParentDevice()->GetResidencyManager(), ResidencyHandle); @@ -368,6 +361,7 @@ FD3D12ResourceLocation::FD3D12ResourceLocation(FD3D12Device* Parent) , OffsetFromBaseOfResource(0) , Allocator(nullptr) , FD3D12DeviceChild(Parent) + , bTransient(false) { FMemory::Memzero(AllocatorData); } diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12State.cpp b/Engine/Source/Runtime/D3D12RHI/Private/D3D12State.cpp index 1d029fb02531..be7827a1def9 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12State.cpp +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12State.cpp @@ -315,6 +315,11 @@ FGraphicsPipelineStateRHIRef FD3D12DynamicRHI::RHICreateGraphicsPipelineState(co FD3D12HighLevelGraphicsPipelineStateDesc GraphicsDesc = {}; + // Zero the RTV array - this is necessary to prevent uninitialized memory affecting the PSO cache hash generation + // Note that the above GraphicsDesc = {} does not clear down the array, probably because it's a TStaticArray rather + // than a standard C array. + FMemory::Memzero(&GraphicsDesc.RTVFormats[0], sizeof(GraphicsDesc.RTVFormats[0]) * GraphicsDesc.RTVFormats.Num()); + GraphicsDesc.BoundShaderState = FD3D12DynamicRHI::ResourceCast(BoundShaderState.GetReference()); GraphicsDesc.BlendState = &FD3D12DynamicRHI::ResourceCast(Initializer.BlendState)->Desc; GraphicsDesc.RasterizerState = &FD3D12DynamicRHI::ResourceCast(Initializer.RasterizerState)->Desc; diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12StateCache.cpp b/Engine/Source/Runtime/D3D12RHI/Private/D3D12StateCache.cpp index 0d079e4d5723..e63ab8dd0b5e 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12StateCache.cpp +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12StateCache.cpp @@ -135,6 +135,9 @@ void FD3D12StateCacheBase::ClearState() // Rasterizer State Cache PipelineState.Graphics.HighLevelDesc.RasterizerState = nullptr; + // Zero the RTV array - this is necessary to prevent uninitialized memory affecting the PSO cache hash generation + FMemory::Memzero(&PipelineState.Graphics.HighLevelDesc.RTVFormats[0], sizeof(PipelineState.Graphics.HighLevelDesc.RTVFormats[0]) * PipelineState.Graphics.HighLevelDesc.RTVFormats.Num()); + // Depth Stencil State Cache PipelineState.Graphics.CurrentReferenceStencil = 0; PipelineState.Graphics.HighLevelDesc.DepthStencilState = nullptr; @@ -1266,44 +1269,6 @@ void FD3D12StateCacheBase::SetRenderTargets(uint32 NumSimultaneousRenderTargets, PipelineState.Graphics.HighLevelDesc.NumRenderTargets = ActiveNumSimultaneousRenderTargets; } -template -void FD3D12StateCacheBase::SetPipelineState(FD3D12PipelineState* PSO) -{ - // Save the PSO - if (PSO) - { - if (IsCompute) - { - PipelineState.Compute.CurrentPipelineStateObject = PSO->GetPipelineState(); - check(!PipelineState.Compute.bNeedRebuildPSO); - } - else - { - PipelineState.Graphics.CurrentPipelineStateObject = PSO->GetPipelineState(); - check(!PipelineState.Graphics.bNeedRebuildPSO); - } - } - - // See if we need to set our PSO: - // In D3D11, you could Set dispatch arguments, then set Draw arguments, then call Draw/Dispatch/Draw/Dispatch without setting arguments again. - // In D3D12, we need to understand when the app switches between Draw/Dispatch and make sure the correct PSO is set. - bool bNeedSetPSO = PipelineState.Common.bNeedSetPSO; - auto& CurrentPSO = PipelineState.Common.CurrentPipelineStateObject; - auto& RequiredPSO = IsCompute ? PipelineState.Compute.CurrentPipelineStateObject : PipelineState.Graphics.CurrentPipelineStateObject; - if (CurrentPSO != RequiredPSO) - { - CurrentPSO = RequiredPSO; - bNeedSetPSO = true; - } - - // Set the PSO on the command list if necessary. - if (bNeedSetPSO) - { - CmdContext->CommandListHandle->SetPipelineState(CurrentPSO); - PipelineState.Common.bNeedSetPSO = false; - } -} - void FD3D12StateCacheBase::SetRenderDepthStencilTargetFormats( uint32 NumRenderTargets, const TRenderTargetFormatsArray& RenderTargetFormats, diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12StateCachePrivate.h b/Engine/Source/Runtime/D3D12RHI/Private/D3D12StateCachePrivate.h index ab40820bcc05..8861bb00a793 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12StateCachePrivate.h +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12StateCachePrivate.h @@ -713,7 +713,42 @@ public: } template - void SetPipelineState(FD3D12PipelineState* PipelineState); + D3D12_STATE_CACHE_INLINE void SetPipelineState(FD3D12PipelineState* PSO) + { + // Save the PSO + if (PSO) + { + if (IsCompute) + { + PipelineState.Compute.CurrentPipelineStateObject = PSO->GetPipelineState(); + check(!PipelineState.Compute.bNeedRebuildPSO); + } + else + { + PipelineState.Graphics.CurrentPipelineStateObject = PSO->GetPipelineState(); + check(!PipelineState.Graphics.bNeedRebuildPSO); + } + } + + // See if we need to set our PSO: + // In D3D11, you could Set dispatch arguments, then set Draw arguments, then call Draw/Dispatch/Draw/Dispatch without setting arguments again. + // In D3D12, we need to understand when the app switches between Draw/Dispatch and make sure the correct PSO is set. + bool bNeedSetPSO = PipelineState.Common.bNeedSetPSO; + auto& CurrentPSO = PipelineState.Common.CurrentPipelineStateObject; + auto& RequiredPSO = IsCompute ? PipelineState.Compute.CurrentPipelineStateObject : PipelineState.Graphics.CurrentPipelineStateObject; + if (CurrentPSO != RequiredPSO) + { + CurrentPSO = RequiredPSO; + bNeedSetPSO = true; + } + + // Set the PSO on the command list if necessary. + if (bNeedSetPSO) + { + CmdContext->CommandListHandle->SetPipelineState(CurrentPSO); + PipelineState.Common.bNeedSetPSO = false; + } + } void SetComputeShader(FD3D12ComputeShader* Shader); @@ -793,7 +828,7 @@ public: void Init(FD3D12Device* InParent, FD3D12CommandContext* InCmdContext, const FD3D12StateCacheBase* AncestralState, FD3D12SubAllocatedOnlineHeap::SubAllocationDesc& SubHeapDesc); - ~FD3D12StateCacheBase() + virtual ~FD3D12StateCacheBase() { } diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12Stats.h b/Engine/Source/Runtime/D3D12RHI/Private/D3D12Stats.h index ea2703955631..c14a29c1d221 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12Stats.h +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12Stats.h @@ -20,8 +20,11 @@ DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("Textures Released"), STAT_D3D12TexturesR DECLARE_CYCLE_STAT_EXTERN(TEXT("CreateTexture time"), STAT_D3D12CreateTextureTime, STATGROUP_D3D12RHI, ); DECLARE_CYCLE_STAT_EXTERN(TEXT("LockTexture time"), STAT_D3D12LockTextureTime, STATGROUP_D3D12RHI, ); DECLARE_CYCLE_STAT_EXTERN(TEXT("UnlockTexture time"), STAT_D3D12UnlockTextureTime, STATGROUP_D3D12RHI, ); +DECLARE_CYCLE_STAT_EXTERN(TEXT("CreateBuffer time"), STAT_D3D12CreateBufferTime, STATGROUP_D3D12RHI, ); DECLARE_CYCLE_STAT_EXTERN(TEXT("LockBuffer time"), STAT_D3D12LockBufferTime, STATGROUP_D3D12RHI, ); DECLARE_CYCLE_STAT_EXTERN(TEXT("UnlockBuffer time"), STAT_D3D12UnlockBufferTime, STATGROUP_D3D12RHI, ); +DECLARE_CYCLE_STAT_EXTERN(TEXT("Commit transient resource time"), STAT_D3D12CommitTransientResourceTime, STATGROUP_D3D12RHI, ); +DECLARE_CYCLE_STAT_EXTERN(TEXT("Decommit transient resource time"), STAT_D3D12DecommitTransientResourceTime, STATGROUP_D3D12RHI, ); DECLARE_CYCLE_STAT_EXTERN(TEXT("CreateBoundShaderState time"), STAT_D3D12CreateBoundShaderStateTime, STATGROUP_D3D12RHI, ); DECLARE_CYCLE_STAT_EXTERN(TEXT("New bound shader state time"), STAT_D3D12NewBoundShaderStateTime, STATGROUP_D3D12RHI, ); diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12StructuredBuffer.cpp b/Engine/Source/Runtime/D3D12RHI/Private/D3D12StructuredBuffer.cpp index fcf851977b7d..2d4b7c5d9312 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12StructuredBuffer.cpp +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12StructuredBuffer.cpp @@ -17,9 +17,38 @@ D3D12_RESOURCE_DESC CreateStructuredBufferResourceDesc(uint32 Size, uint32 InUsa Desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; } + if (InUsage & BUF_DrawIndirect) + { + Desc.Flags |= D3D12RHI_RESOURCE_FLAG_ALLOW_INDIRECT_BUFFER; + } + + return Desc; } +FStructuredBufferRHIRef FD3D12DynamicRHI::CreateStructuredBuffer_RenderThread(FRHICommandListImmediate& RHICmdList, uint32 Stride, uint32 Size, uint32 InUsage, FRHIResourceCreateInfo& CreateInfo) +{ + // Check for values that will cause D3D calls to fail + check(Size / Stride > 0 && Size % Stride == 0); + + const D3D12_RESOURCE_DESC Desc = CreateStructuredBufferResourceDesc(Size, InUsage); + + // Structured buffers, non-byte address buffers, need to be aligned to their stride to ensure that they + // can be addressed correctly with element based offsets. + const uint32 Alignment = ((InUsage & (BUF_ByteAddressBuffer | BUF_DrawIndirect)) == 0) ? Stride : 4; + + FD3D12StructuredBuffer* NewBuffer = GetAdapter().CreateRHIBuffer(&RHICmdList, Desc, Alignment, Stride, Size, InUsage, CreateInfo, false); + if (NewBuffer->ResourceLocation.IsTransient()) + { + // TODO: this should ideally be set in platform-independent code, since this tracking is for the high level + NewBuffer->SetCommitted(false); + } + + UpdateBufferStats(&NewBuffer->ResourceLocation, true, D3D12_BUFFER_TYPE_STRUCTURED); + + return NewBuffer; +} + FStructuredBufferRHIRef FD3D12DynamicRHI::RHICreateStructuredBuffer(uint32 Stride, uint32 Size, uint32 InUsage, FRHIResourceCreateInfo& CreateInfo) { // Check for values that will cause D3D calls to fail @@ -32,6 +61,11 @@ FStructuredBufferRHIRef FD3D12DynamicRHI::RHICreateStructuredBuffer(uint32 Strid const uint32 Alignment = ((InUsage & (BUF_ByteAddressBuffer | BUF_DrawIndirect)) == 0) ? Stride : 4; FD3D12StructuredBuffer* NewBuffer = GetAdapter().CreateRHIBuffer(nullptr, Desc, Alignment, Stride, Size, InUsage, CreateInfo, false); + if (NewBuffer->ResourceLocation.IsTransient()) + { + // TODO: this should ideally be set in platform-independent code, since this tracking is for the high level + NewBuffer->SetCommitted(false); + } UpdateBufferStats(&NewBuffer->ResourceLocation, true, D3D12_BUFFER_TYPE_STRUCTURED); diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12Texture.cpp b/Engine/Source/Runtime/D3D12RHI/Private/D3D12Texture.cpp index 56b3110b6c45..69accc0e45eb 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12Texture.cpp +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12Texture.cpp @@ -39,6 +39,8 @@ template TD3D12Texture2D::TD3D12Texture2D(class FD3D12Dev #endif ); +/// @cond DOXYGEN_WARNINGS + template void FD3D12TextureStats::D3D12TextureAllocated(TD3D12Texture2D& Texture); template void FD3D12TextureStats::D3D12TextureAllocated(TD3D12Texture2D& Texture); template void FD3D12TextureStats::D3D12TextureAllocated(TD3D12Texture2D& Texture); @@ -47,6 +49,8 @@ template void FD3D12TextureStats::D3D12TextureDeleted(TD3D12Texture2D& Texture); template void FD3D12TextureStats::D3D12TextureDeleted(TD3D12Texture2D& Texture); +/// @endcond + struct FRHICommandUpdateTexture : public FRHICommand { FD3D12TextureBase* TextureBase; @@ -201,7 +205,7 @@ void FD3D12TextureStats::D3D12TextureDeleted(TD3D12Texture2D& { const D3D12_RESOURCE_DESC& Desc = D3D12Texture2D->GetDesc(); const int64 TextureSize = Texture.GetMemorySize(); - check(TextureSize > 0); + check(TextureSize > 0 || (Texture.Flags & TexCreate_Virtual)); UpdateD3D12TextureStats(Desc, -TextureSize, false, Texture.IsCubemap()); } @@ -669,7 +673,7 @@ TD3D12Texture2D* FD3D12DynamicRHI::CreateD3D12Texture2D(uint32 // The state this resource will be in when it leaves this function const FD3D12Resource::FD3D12ResourceTypeHelper Type(TextureDesc, D3D12_HEAP_TYPE_DEFAULT); - const D3D12_RESOURCE_STATES DestinationState = Type.GetOptimalInitialState(); + const D3D12_RESOURCE_STATES DestinationState = Type.GetOptimalInitialState(false); TD3D12Texture2D* D3D12TextureOut = Adapter->CreateLinkedObject>([&](FD3D12Device* Device) { @@ -699,10 +703,13 @@ TD3D12Texture2D* FD3D12DynamicRHI::CreateD3D12Texture2D(uint32 if (bCreateRTV) { + const bool bCreateRTVsPerSlice = (Flags & TexCreate_TargetArraySlicesIndependently) && (bTextureArray || bCubeTexture); + NewTexture->SetNumRenderTargetViews(bCreateRTVsPerSlice ? NumMips * TextureDesc.DepthOrArraySize : NumMips); + // Create a render target view for each mip for (uint32 MipIndex = 0; MipIndex < NumMips; MipIndex++) { - if ((Flags & TexCreate_TargetArraySlicesIndependently) && (bTextureArray || bCubeTexture)) + if (bCreateRTVsPerSlice) { NewTexture->SetCreatedRTVsPerSlice(true, TextureDesc.DepthOrArraySize); @@ -717,7 +724,7 @@ TD3D12Texture2D* FD3D12DynamicRHI::CreateD3D12Texture2D(uint32 RTVDesc.Texture2DArray.MipSlice = MipIndex; RTVDesc.Texture2DArray.PlaneSlice = GetPlaneSliceFromViewFormat(PlatformResourceFormat, RTVDesc.Format); - NewTexture->SetRenderTargetView(FD3D12RenderTargetView::CreateRenderTargetView(Device, &Location, RTVDesc), RTVIndex++); + NewTexture->SetRenderTargetViewIndex(FD3D12RenderTargetView::CreateRenderTargetView(Device, &Location, RTVDesc), RTVIndex++); } } else @@ -740,7 +747,7 @@ TD3D12Texture2D* FD3D12DynamicRHI::CreateD3D12Texture2D(uint32 RTVDesc.Texture2D.PlaneSlice = GetPlaneSliceFromViewFormat(PlatformResourceFormat, RTVDesc.Format); } - NewTexture->SetRenderTargetView(FD3D12RenderTargetView::CreateRenderTargetView(Device, &Location, RTVDesc), RTVIndex++); + NewTexture->SetRenderTargetViewIndex(FD3D12RenderTargetView::CreateRenderTargetView(Device, &Location, RTVDesc), RTVIndex++); } } } @@ -963,7 +970,7 @@ FD3D12Texture3D* FD3D12DynamicRHI::CreateD3D12Texture3D(uint32 SizeX, uint32 Siz // The state this resource will be in when it leaves this function const FD3D12Resource::FD3D12ResourceTypeHelper Type(TextureDesc, D3D12_HEAP_TYPE_DEFAULT); - const D3D12_RESOURCE_STATES DestinationState = Type.GetOptimalInitialState(); + const D3D12_RESOURCE_STATES DestinationState = Type.GetOptimalInitialState(false); FD3D12Adapter* Adapter = &GetAdapter(); @@ -985,7 +992,7 @@ FD3D12Texture3D* FD3D12DynamicRHI::CreateD3D12Texture3D(uint32 SizeX, uint32 Siz RTVDesc.Texture3D.FirstWSlice = 0; RTVDesc.Texture3D.WSize = SizeZ; - Texture3D->SetRenderTargetView(FD3D12RenderTargetView::CreateRenderTargetView(Device, &Texture3D->ResourceLocation, RTVDesc), 0); + Texture3D->SetRenderTargetView(FD3D12RenderTargetView::CreateRenderTargetView(Device, &Texture3D->ResourceLocation, RTVDesc)); } // Create a shader resource view for the texture. @@ -1184,48 +1191,45 @@ FTexture2DRHIRef FD3D12DynamicRHI::RHIAsyncCreateTexture2D(uint32 SizeX, uint32 if (TextureOut) { - if (SubResourceData) + // SubResourceData is only used in async texture creation (RHIAsyncCreateTexture2D). We need to manually transition the resource to + // its 'default state', which is what the rest of the RHI (including InitializeTexture2DData) expects for SRV-only resources. + + check((TextureDesc.Flags & D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE) == 0); + + const uint64 Size = GetRequiredIntermediateSize(TextureOut->GetResource()->GetResource(), 0, NumMips); + FD3D12FastAllocator& FastAllocator = GetHelperThreadDynamicUploadHeapAllocator(); + FD3D12ResourceLocation TempResourceLocation(FastAllocator.GetParentDevice()); + FastAllocator.Allocate(Size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT, &TempResourceLocation); + + FD3D12Texture2D* CurrentTexture = TextureOut; + while (CurrentTexture != nullptr) { - // SubResourceData is only used in async texture creation (RHIAsyncCreateTexture2D). We need to manually transition the resource to - // its 'default state', which is what the rest of the RHI (including InitializeTexture2DData) expects for SRV-only resources. + FD3D12Device* Device = CurrentTexture->GetParentDevice(); + FD3D12Resource* Resource = CurrentTexture->GetResource(); - check((TextureDesc.Flags & D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE) == 0); + FD3D12CommandAllocatorManager& CommandAllocatorManager = Device->GetTextureStreamingCommandAllocatorManager(); + FD3D12CommandAllocator* CurrentCommandAllocator = CommandAllocatorManager.ObtainCommandAllocator(); + FD3D12CommandListHandle hCopyCommandList = Device->GetCopyCommandListManager().ObtainCommandList(*CurrentCommandAllocator); + hCopyCommandList.SetCurrentOwningContext(&Device->GetDefaultCommandContext()); - const uint64 Size = GetRequiredIntermediateSize(TextureOut->GetResource()->GetResource(), 0, NumMips); - FD3D12FastAllocator& FastAllocator = GetHelperThreadDynamicUploadHeapAllocator(); - FD3D12ResourceLocation TempResourceLocation(FastAllocator.GetParentDevice()); - FastAllocator.Allocate(Size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT, &TempResourceLocation); + hCopyCommandList.GetCurrentOwningContext()->numCopies++; + UpdateSubresources( + (ID3D12GraphicsCommandList*)hCopyCommandList.CommandList(), + Resource->GetResource(), + TempResourceLocation.GetResource()->GetResource(), + TempResourceLocation.GetOffsetFromBaseOfResource(), + 0, NumMips, + SubResourceData); - FD3D12Texture2D* CurrentTexture = TextureOut; - while (CurrentTexture != nullptr) - { - FD3D12Device* Device = CurrentTexture->GetParentDevice(); - FD3D12Resource* Resource = CurrentTexture->GetResource(); + hCopyCommandList.UpdateResidency(Resource); - FD3D12CommandAllocatorManager& CommandAllocatorManager = Device->GetTextureStreamingCommandAllocatorManager(); - FD3D12CommandAllocator* CurrentCommandAllocator = CommandAllocatorManager.ObtainCommandAllocator(); - FD3D12CommandListHandle hCopyCommandList = Device->GetCopyCommandListManager().ObtainCommandList(*CurrentCommandAllocator); - hCopyCommandList.SetCurrentOwningContext(&Device->GetDefaultCommandContext()); + // Wait for the copy context to finish before continuing as this function is only expected to return once all the texture streaming has finished. + hCopyCommandList.Close(); + Device->GetCopyCommandListManager().ExecuteCommandList(hCopyCommandList, true); - hCopyCommandList.GetCurrentOwningContext()->numCopies++; - UpdateSubresources( - (ID3D12GraphicsCommandList*)hCopyCommandList.CommandList(), - Resource->GetResource(), - TempResourceLocation.GetResource()->GetResource(), - TempResourceLocation.GetOffsetFromBaseOfResource(), - 0, NumMips, - SubResourceData); + CommandAllocatorManager.ReleaseCommandAllocator(CurrentCommandAllocator); - hCopyCommandList.UpdateResidency(Resource); - - // Wait for the copy context to finish before continuing as this function is only expected to return once all the texture streaming has finished. - hCopyCommandList.Close(); - Device->GetCopyCommandListManager().ExecuteCommandList(hCopyCommandList, true); - - CommandAllocatorManager.ReleaseCommandAllocator(CurrentCommandAllocator); - - CurrentTexture = (FD3D12Texture2D*)CurrentTexture->GetNextObject(); - } + CurrentTexture = (FD3D12Texture2D*)CurrentTexture->GetNextObject(); } FD3D12TextureStats::D3D12TextureAllocated(*TextureOut); @@ -1484,17 +1488,17 @@ void* TD3D12Texture2D::Lock(class FRHICommandListImmediate* RHI FD3D12Adapter* Adapter = Device->GetParentAdapter(); // Calculate the subresource index corresponding to the specified mip-map. - const uint32 Subresource = CalcSubresource(MipIndex, ArrayIndex, GetNumMips()); + const uint32 Subresource = CalcSubresource(MipIndex, ArrayIndex, this->GetNumMips()); check(LockedMap.Find(Subresource) == nullptr); FD3D12LockedResource* LockedResource = new FD3D12LockedResource(Device); // Calculate the dimensions of the mip-map. - const uint32 BlockSizeX = GPixelFormats[GetFormat()].BlockSizeX; - const uint32 BlockSizeY = GPixelFormats[GetFormat()].BlockSizeY; - const uint32 BlockBytes = GPixelFormats[GetFormat()].BlockBytes; - const uint32 MipSizeX = FMath::Max(GetSizeX() >> MipIndex, BlockSizeX); - const uint32 MipSizeY = FMath::Max(GetSizeY() >> MipIndex, BlockSizeY); + const uint32 BlockSizeX = GPixelFormats[this->GetFormat()].BlockSizeX; + const uint32 BlockSizeY = GPixelFormats[this->GetFormat()].BlockSizeY; + const uint32 BlockBytes = GPixelFormats[this->GetFormat()].BlockBytes; + const uint32 MipSizeX = FMath::Max(this->GetSizeX() >> MipIndex, BlockSizeX); + const uint32 MipSizeY = FMath::Max(this->GetSizeY() >> MipIndex, BlockSizeY); const uint32 NumBlocksX = (MipSizeX + BlockSizeX - 1) / BlockSizeX; const uint32 NumBlocksY = (MipSizeY + BlockSizeY - 1) / BlockSizeY; @@ -1648,14 +1652,14 @@ template void TD3D12Texture2D::UnlockInternal(class FRHICommandListImmediate* RHICmdList, TD3D12Texture2D* Previous, uint32 MipIndex, uint32 ArrayIndex) { // Calculate the subresource index corresponding to the specified mip-map. - const uint32 Subresource = CalcSubresource(MipIndex, ArrayIndex, GetNumMips()); + const uint32 Subresource = CalcSubresource(MipIndex, ArrayIndex, this->GetNumMips()); // Calculate the dimensions of the mip-map. - const uint32 BlockSizeX = GPixelFormats[GetFormat()].BlockSizeX; - const uint32 BlockSizeY = GPixelFormats[GetFormat()].BlockSizeY; - const uint32 BlockBytes = GPixelFormats[GetFormat()].BlockBytes; - const uint32 MipSizeX = FMath::Max(GetSizeX() >> MipIndex, BlockSizeX); - const uint32 MipSizeY = FMath::Max(GetSizeY() >> MipIndex, BlockSizeY); + const uint32 BlockSizeX = GPixelFormats[this->GetFormat()].BlockSizeX; + const uint32 BlockSizeY = GPixelFormats[this->GetFormat()].BlockSizeY; + const uint32 BlockBytes = GPixelFormats[this->GetFormat()].BlockBytes; + const uint32 MipSizeX = FMath::Max(this->GetSizeX() >> MipIndex, BlockSizeX); + const uint32 MipSizeY = FMath::Max(this->GetSizeY() >> MipIndex, BlockSizeY); TMap& Map = (Previous) ? Previous->LockedMap : LockedMap; FD3D12LockedResource* LockedResource = Map[Subresource]; @@ -1728,8 +1732,8 @@ void TD3D12Texture2D::UpdateTexture2D(class FRHICommandListImme UpdateRegion.DestX + UpdateRegion.Width, UpdateRegion.DestY + UpdateRegion.Height, 1 }; - check(GPixelFormats[GetFormat()].BlockSizeX == 1); - check(GPixelFormats[GetFormat()].BlockSizeY == 1); + check(GPixelFormats[this->GetFormat()].BlockSizeX == 1); + check(GPixelFormats[this->GetFormat()].BlockSizeY == 1); const uint32 AlignedSourcePitch = Align(SourcePitch, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT); const uint32 bufferSize = Align(UpdateRegion.Height*AlignedSourcePitch, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT); @@ -1743,7 +1747,7 @@ void TD3D12Texture2D::UpdateTexture2D(class FRHICommandListImme byte* pRowData = (byte*)pData; byte* pSourceRowData = (byte*)SourceData; - uint32 CopyPitch = UpdateRegion.Width * GPixelFormats[GetFormat()].BlockBytes; + uint32 CopyPitch = UpdateRegion.Width * GPixelFormats[this->GetFormat()].BlockBytes; check(CopyPitch <= SourcePitch); for (uint32 i = 0; i < UpdateRegion.Height; i++) { @@ -1756,7 +1760,7 @@ void TD3D12Texture2D::UpdateTexture2D(class FRHICommandListImme SourceSubresource.Depth = 1; SourceSubresource.Height = UpdateRegion.Height; SourceSubresource.Width = UpdateRegion.Width; - SourceSubresource.Format = (DXGI_FORMAT)GPixelFormats[GetFormat()].PlatformFormat; + SourceSubresource.Format = (DXGI_FORMAT)GPixelFormats[this->GetFormat()].PlatformFormat; SourceSubresource.RowPitch = AlignedSourcePitch; check(SourceSubresource.RowPitch % FD3D12_TEXTURE_DATA_PITCH_ALIGNMENT == 0); @@ -2113,6 +2117,8 @@ FTexture2DRHIRef FD3D12DynamicRHI::RHICreateTexture2DFromD3D12Resource(uint8 For if (bCreateRTV) { + Texture2D->SetCreatedRTVsPerSlice(false, NumMips); + // Create a render target view for each mip for (uint32 MipIndex = 0; MipIndex < NumMips; MipIndex++) { @@ -2123,7 +2129,7 @@ FTexture2DRHIRef FD3D12DynamicRHI::RHICreateTexture2DFromD3D12Resource(uint8 For RTVDesc.Texture2D.MipSlice = MipIndex; RTVDesc.Texture2D.PlaneSlice = GetPlaneSliceFromViewFormat(PlatformResourceFormat, RTVDesc.Format); - Texture2D->SetRenderTargetView(FD3D12RenderTargetView::CreateRenderTargetView(Device, &Location, RTVDesc), MipIndex); + Texture2D->SetRenderTargetViewIndex(FD3D12RenderTargetView::CreateRenderTargetView(Device, &Location, RTVDesc), MipIndex); } } diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12Texture.h b/Engine/Source/Runtime/D3D12RHI/Private/D3D12Texture.h index 9f29e19ddce9..0981ad659d83 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12Texture.h +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12Texture.h @@ -5,15 +5,8 @@ D3D12Texture.h: Implementation of D3D12 Texture =============================================================================*/ #pragma once -#if PLATFORM_WINDOWS -class FD3D12FastVRAMResource -{ - // Nothing special for fast ram -}; -#endif - /** Texture base class. */ -class FD3D12TextureBase : public FD3D12BaseShaderResource, public FD3D12FastVRAMResource, public FD3D12LinkedAdapterObject +class FD3D12TextureBase : public FD3D12BaseShaderResource, public FD3D12TransientResource, public FD3D12LinkedAdapterObject { public: @@ -22,9 +15,7 @@ public: , MemorySize(0) , BaseShaderResource(this) , bCreatedRTVsPerSlice(false) - , RTVArraySize(MaxNumRTVs) , NumDepthStencilViews(0) - , NumRenderTargetViews(0) { } @@ -36,6 +27,12 @@ public: RTVArraySize = InRTVArraySize; } + void SetNumRenderTargetViews(int32 InNumViews) + { + RenderTargetViews.Empty(InNumViews); + RenderTargetViews.AddDefaulted(InNumViews); + } + void SetDepthStencilView(FD3D12DepthStencilView* View, uint32 SubResourceIndex) { if (SubResourceIndex < FExclusiveDepthStencil::MaxIndex) @@ -49,12 +46,11 @@ public: } } - void SetRenderTargetView(FD3D12RenderTargetView* View, uint32 SubResourceIndex) + void SetRenderTargetViewIndex(FD3D12RenderTargetView* View, uint32 SubResourceIndex) { - if (SubResourceIndex < MaxNumRTVs) + if (SubResourceIndex < (uint32)RenderTargetViews.Num()) { RenderTargetViews[SubResourceIndex] = View; - NumRenderTargetViews = FMath::Max(SubResourceIndex + 1, NumRenderTargetViews); } else { @@ -62,6 +58,12 @@ public: } } + void SetRenderTargetView(FD3D12RenderTargetView* View) + { + RenderTargetViews.Empty(1); + RenderTargetViews.Add(View); + } + int32 GetMemorySize() const { return MemorySize; @@ -93,7 +95,7 @@ public: { check(ArraySliceIndex >= 0); ArrayIndex = MipIndex * RTVArraySize + ArraySliceIndex; - check(ArrayIndex < MaxNumRTVs); + check(ArrayIndex < RenderTargetViews.Num()); } else { @@ -101,7 +103,7 @@ public: check(ArraySliceIndex == -1 || ArraySliceIndex == 0); } - if ((uint32)ArrayIndex < NumRenderTargetViews) + if (ArrayIndex < RenderTargetViews.Num()) { return RenderTargetViews[ArrayIndex]; } @@ -121,7 +123,7 @@ public: inline bool HasRenderTargetViews() const { - return (NumRenderTargetViews > 0); + return (RenderTargetViews.Num() > 0); } void AliasResources(FD3D12TextureBase* Texture) @@ -136,7 +138,7 @@ public: { DepthStencilViews[Index] = Texture->DepthStencilViews[Index]; } - for (uint32 Index = 0; Index < Texture->NumRenderTargetViews; Index++) + for (int32 Index = 0; Index < Texture->RenderTargetViews.Num(); Index++) { RenderTargetViews[Index] = Texture->RenderTargetViews[Index]; } @@ -154,8 +156,7 @@ protected: TRefCountPtr ShaderResourceView; /** A render targetable view of the texture. */ - static const uint32 MaxNumRTVs = 64; - TRefCountPtr RenderTargetViews[MaxNumRTVs]; + TArray, TInlineAllocator<1>> RenderTargetViews; bool bCreatedRTVsPerSlice; @@ -166,7 +167,6 @@ protected: /** Number of Depth Stencil Views - used for fast call tracking. */ uint32 NumDepthStencilViews; - uint32 NumRenderTargetViews; TMap LockedMap; }; @@ -180,7 +180,7 @@ struct FD3D12TextureMipLayout struct FD3D12TextureLayout { - void FillFromDesc(const struct D3D12_RESOURCE_DESC& D3DTextureDesc, bool CubeTexture); + void FillFromDesc(const struct D3D12_RESOURCE_DESC& D3DTextureDesc); uint64 GetSubresourceOffset(uint32 Plane, uint32 Mip, uint32 Slice) const { @@ -270,7 +270,7 @@ public: return false; } - if (RHICmdList->Bypass() || !GRHIThread) + if (RHICmdList->Bypass() || !IsRunningRHIInSeparateThread()) { return false; } diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12Util.cpp b/Engine/Source/Runtime/D3D12RHI/Private/D3D12Util.cpp index f17e892a48b7..889bb4c8b8af 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12Util.cpp +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12Util.cpp @@ -419,7 +419,7 @@ FString ConvertToResourceStateString(uint32 ResourceState) return FString(TEXT("D3D12_RESOURCE_STATE_COMMON")); } - TCHAR* ResourceStateNames[] = + const TCHAR* ResourceStateNames[] = { TEXT("D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER"), TEXT("D3D12_RESOURCE_STATE_INDEX_BUFFER"), @@ -741,8 +741,11 @@ DEFINE_STAT(STAT_D3D12TexturesReleased); DEFINE_STAT(STAT_D3D12CreateTextureTime); DEFINE_STAT(STAT_D3D12LockTextureTime); DEFINE_STAT(STAT_D3D12UnlockTextureTime); +DEFINE_STAT(STAT_D3D12CreateBufferTime); DEFINE_STAT(STAT_D3D12LockBufferTime); DEFINE_STAT(STAT_D3D12UnlockBufferTime); +DEFINE_STAT(STAT_D3D12CommitTransientResourceTime); +DEFINE_STAT(STAT_D3D12DecommitTransientResourceTime); DEFINE_STAT(STAT_D3D12NewBoundShaderStateTime); DEFINE_STAT(STAT_D3D12CreateBoundShaderStateTime); diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12VertexBuffer.cpp b/Engine/Source/Runtime/D3D12RHI/Private/D3D12VertexBuffer.cpp index 0d3f30d63708..50b74d157d46 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12VertexBuffer.cpp +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12VertexBuffer.cpp @@ -28,6 +28,11 @@ D3D12_RESOURCE_DESC CreateVertexBufferResourceDesc(uint32 Size, uint32 InUsage) Desc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE; } + if (InUsage & BUF_DrawIndirect) + { + Desc.Flags |= D3D12RHI_RESOURCE_FLAG_ALLOW_INDIRECT_BUFFER; + } + return Desc; } @@ -58,6 +63,11 @@ FVertexBufferRHIRef FD3D12DynamicRHI::RHICreateVertexBuffer(uint32 Size, uint32 const uint32 Alignment = 4; FD3D12VertexBuffer* Buffer = GetAdapter().CreateRHIBuffer(nullptr, Desc, Alignment, 0, Size, InUsage, CreateInfo, false); + if (Buffer->ResourceLocation.IsTransient() ) + { + // TODO: this should ideally be set in platform-independent code, since this tracking is for the high level + Buffer->SetCommitted(false); + } UpdateBufferStats(&Buffer->ResourceLocation, true, D3D12_BUFFER_TYPE_VERTEX); @@ -80,7 +90,11 @@ FVertexBufferRHIRef FD3D12DynamicRHI::CreateVertexBuffer_RenderThread(FRHIComman const uint32 Alignment = 4; FD3D12VertexBuffer* Buffer = GetAdapter().CreateRHIBuffer(&RHICmdList, Desc, Alignment, 0, Size, InUsage, CreateInfo, false); - + if (Buffer->ResourceLocation.IsTransient()) + { + // TODO: this should ideally be set in platform-independent code, since this tracking is for the high level + Buffer->SetCommitted(false); + } UpdateBufferStats(&Buffer->ResourceLocation, true, D3D12_BUFFER_TYPE_VERTEX); return Buffer; @@ -144,7 +158,11 @@ FVertexBufferRHIRef FD3D12DynamicRHI::CreateAndLockVertexBuffer_RenderThread(FRH const uint32 Alignment = 4; FD3D12VertexBuffer* Buffer = GetAdapter().CreateRHIBuffer(nullptr, Desc, Alignment, 0, Size, InUsage, CreateInfo, false); - + if (Buffer->ResourceLocation.IsTransient()) + { + // TODO: this should ideally be set in platform-independent code, since this tracking is for the high level + Buffer->SetCommitted(false); + } OutDataBuffer = LockVertexBuffer_RenderThread(RHICmdList, Buffer, 0, Size, RLM_WriteOnly); UpdateBufferStats(&Buffer->ResourceLocation, true, D3D12_BUFFER_TYPE_VERTEX); diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12View.h b/Engine/Source/Runtime/D3D12RHI/Private/D3D12View.h index 35f0b8ce8f08..ab8dbe93cd59 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12View.h +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12View.h @@ -713,7 +713,7 @@ protected: void AllocateHeapSlot() { - FD3D12OfflineDescriptorManager& DescriptorAllocator = GetParentDevice()->GetViewDescriptorAllocator(); + FD3D12OfflineDescriptorManager& DescriptorAllocator = GetParentDevice()->template GetViewDescriptorAllocator(); Descriptor = DescriptorAllocator.AllocateHeapSlot(DescriptorHeapIndex); check(Descriptor.ptr != 0); } @@ -722,7 +722,7 @@ protected: { if (Descriptor.ptr) { - FD3D12OfflineDescriptorManager& DescriptorAllocator = GetParentDevice()->GetViewDescriptorAllocator(); + FD3D12OfflineDescriptorManager& DescriptorAllocator = GetParentDevice()->template GetViewDescriptorAllocator(); DescriptorAllocator.FreeHeapSlot(Descriptor, DescriptorHeapIndex); Descriptor.ptr = 0; } diff --git a/Engine/Source/Runtime/D3D12RHI/Private/D3D12Viewport.cpp b/Engine/Source/Runtime/D3D12RHI/Private/D3D12Viewport.cpp index da0248dae882..37a413121e6d 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/D3D12Viewport.cpp +++ b/Engine/Source/Runtime/D3D12RHI/Private/D3D12Viewport.cpp @@ -220,7 +220,7 @@ FD3D12Texture2D* GetSwapChainSurface(FD3D12Device* Parent, EPixelFormat PixelFor RTVDesc.Texture2D.MipSlice = 0; FD3D12RenderTargetView* BackBufferRenderTargetView = new FD3D12RenderTargetView(Parent, &RTVDesc, &NewTexture->ResourceLocation); - NewTexture->SetRenderTargetView(BackBufferRenderTargetView, 0); + NewTexture->SetRenderTargetView(BackBufferRenderTargetView); // create a shader resource view to allow using the backbuffer as a texture D3D12_SHADER_RESOURCE_VIEW_DESC SRVDesc = {}; diff --git a/Engine/Source/Runtime/D3D12RHI/Private/Windows/D3D12RHIBasePrivate.h b/Engine/Source/Runtime/D3D12RHI/Private/Windows/D3D12RHIBasePrivate.h index 71a4f8d2bc67..ff342967baa2 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/Windows/D3D12RHIBasePrivate.h +++ b/Engine/Source/Runtime/D3D12RHI/Private/Windows/D3D12RHIBasePrivate.h @@ -33,7 +33,8 @@ #pragma pack(pop) #pragma warning(pop) +#define D3D12RHI_RESOURCE_FLAG_ALLOW_INDIRECT_BUFFER D3D12_RESOURCE_FLAG_NONE #include "../Public/D3D12Util.h" #include "WindowsD3D12DiskCache.h" -#include "WindowsD3D12PipelineState.h" \ No newline at end of file +#include "WindowsD3D12PipelineState.h" diff --git a/Engine/Source/Runtime/D3D12RHI/Private/Windows/WindowsD3D12Device.cpp b/Engine/Source/Runtime/D3D12RHI/Private/Windows/WindowsD3D12Device.cpp index 17fcb055b794..0e484aebc9c9 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/Windows/WindowsD3D12Device.cpp +++ b/Engine/Source/Runtime/D3D12RHI/Private/Windows/WindowsD3D12Device.cpp @@ -33,6 +33,26 @@ static TAutoConsoleVariable CVarGraphicsAdapter( TEXT(" 1: Adpater #1, ..."), ECVF_RenderThreadSafe); +int D3D12RHI_PreferAdaperVendor() +{ + if (FParse::Param(FCommandLine::Get(), TEXT("preferAMD"))) + { + return 0x1002; + } + + if (FParse::Param(FCommandLine::Get(), TEXT("preferIntel"))) + { + return 0x8086; + } + + if (FParse::Param(FCommandLine::Get(), TEXT("preferNvidia"))) + { + return 0x10DE; + } + + return -1; +} + namespace D3D12RHI { @@ -260,6 +280,7 @@ void FD3D12DynamicRHIModule::FindAdapter() bool bIsAnyNVIDIA = false; bool bRequestedWARP = D3D12RHI_ShouldCreateWithWarp(); + int PreferredVendor = D3D12RHI_PreferAdaperVendor(); // Enumerate the DXGIFactory's adapters. for (uint32 AdapterIndex = 0; DXGIFactory->EnumAdapters(AdapterIndex, TempAdapter.GetInitReference()) != DXGI_ERROR_NOT_FOUND; ++AdapterIndex) { @@ -309,18 +330,13 @@ void FD3D12DynamicRHIModule::FindAdapter() // Requested WARP, reject all other adapters. const bool bSkipRequestedWARP = bRequestedWARP && !bIsWARP; - // Add special check to support WARP and HMDs, which do not have associated outputs. - // This device has no outputs. Reject it, - // http://msdn.microsoft.com/en-us/library/windows/desktop/bb205075%28v=vs.85%29.aspx#WARP_new_for_Win8 - const bool bSkipHmdGraphicsAdapter = !OutputCount && !bIsWARP && !bUseHmdGraphicsAdapter; - // we don't allow the PerfHUD adapter const bool bSkipPerfHUDAdapter = bIsPerfHUD && !bAllowPerfHUD; // the user wants a specific adapter, not this one const bool bSkipExplicitAdapter = CVarExplicitAdapterValue >= 0 && AdapterIndex != CVarExplicitAdapterValue; - const bool bSkipAdapter = bSkipRequestedWARP || bSkipHmdGraphicsAdapter || bSkipPerfHUDAdapter || bSkipExplicitAdapter; + const bool bSkipAdapter = bSkipRequestedWARP || bSkipPerfHUDAdapter || bSkipExplicitAdapter; if (!bSkipAdapter) { @@ -328,11 +344,19 @@ void FD3D12DynamicRHIModule::FindAdapter() { FirstWithoutIntegratedAdapter = CurrentAdapter; } + else if (PreferredVendor == AdapterDesc.VendorId && FirstWithoutIntegratedAdapter.IsValid()) + { + FirstWithoutIntegratedAdapter = CurrentAdapter; + } if (!FirstAdapter.IsValid()) { FirstAdapter = CurrentAdapter; } + else if (PreferredVendor == AdapterDesc.VendorId && FirstAdapter.IsValid()) + { + FirstAdapter = CurrentAdapter; + } } } } @@ -573,6 +597,13 @@ void FD3D12Device::Initialize() } +void FD3D12Device::InitPlatformSpecific() +{ + CommandListManager = new FD3D12CommandListManager(this, D3D12_COMMAND_LIST_TYPE_DIRECT); + CopyCommandListManager = new FD3D12CommandListManager(this, D3D12_COMMAND_LIST_TYPE_COPY); + AsyncCommandListManager = new FD3D12CommandListManager(this, D3D12_COMMAND_LIST_TYPE_COMPUTE); +} + void FD3D12Device::CreateSamplerInternal(const D3D12_SAMPLER_DESC& Desc, D3D12_CPU_DESCRIPTOR_HANDLE Descriptor) { GetDevice()->CreateSampler(&Desc, Descriptor); diff --git a/Engine/Source/Runtime/D3D12RHI/Private/Windows/WindowsD3D12DiskCache.cpp b/Engine/Source/Runtime/D3D12RHI/Private/Windows/WindowsD3D12DiskCache.cpp index a91557a7d7d0..0993cf9cf543 100644 --- a/Engine/Source/Runtime/D3D12RHI/Private/Windows/WindowsD3D12DiskCache.cpp +++ b/Engine/Source/Runtime/D3D12RHI/Private/Windows/WindowsD3D12DiskCache.cpp @@ -24,7 +24,6 @@ void FDiskCacheInterface::Init(FString &filename) mMapAddress = 0; mCurrentFileMapSize = 0; mCurrentOffset = 0; - mCacheExists = false; mInErrorState = false; mFileName = filename; @@ -36,10 +35,17 @@ void FDiskCacheInterface::Init(FString &filename) else { WIN32_FIND_DATA fileData; - FindFirstFile(mFileName.GetCharArray().GetData(), &fileData); - if (GetLastError() == ERROR_FILE_NOT_FOUND) + HANDLE Handle = FindFirstFile(mFileName.GetCharArray().GetData(), &fileData); + if (Handle == INVALID_HANDLE_VALUE) { - mCacheExists = false; + if (GetLastError() == ERROR_FILE_NOT_FOUND) + { + mCacheExists = false; + } + } + else + { + FindClose(Handle); } } bool fileFound = mCacheExists; diff --git a/Engine/Source/Runtime/D3D12RHI/Public/D3D12RHI.h b/Engine/Source/Runtime/D3D12RHI/Public/D3D12RHI.h index 8db39b2ebbcf..5efd1c9df995 100644 --- a/Engine/Source/Runtime/D3D12RHI/Public/D3D12RHI.h +++ b/Engine/Source/Runtime/D3D12RHI/Public/D3D12RHI.h @@ -28,8 +28,7 @@ // So outside callers can override this #ifndef USE_STATIC_ROOT_SIGNATURE - // Make sure this is in sync with the overrides! - #define USE_STATIC_ROOT_SIGNATURE PLATFORM_XBOXONE + #define USE_STATIC_ROOT_SIGNATURE 0 #endif // How many residency packets can be in flight before the rendering thread @@ -53,7 +52,7 @@ // Xbox doesn't have DXGI but common code needs this defined for headers #define DXGI_QUERY_VIDEO_MEMORY_INFO int #elif PLATFORM_WINDOWS - #define ENABLE_RESIDENCY_MANAGEMENT 1 + #define ENABLE_RESIDENCY_MANAGEMENT 0 #define ASYNC_DEFERRED_DELETION 1 #define PLATFORM_SUPPORTS_MGPU 1 #define PIPELINE_STATE_FILE_LOCATION FPaths::GameSavedDir() diff --git a/Engine/Source/Runtime/D3D12RHI/Public/D3D12Resources.h b/Engine/Source/Runtime/D3D12RHI/Public/D3D12Resources.h index 8d8f749eaf9e..1dddfb960f92 100644 --- a/Engine/Source/Runtime/D3D12RHI/Public/D3D12Resources.h +++ b/Engine/Source/Runtime/D3D12RHI/Public/D3D12Resources.h @@ -96,7 +96,7 @@ private: D3D12_RESOURCE_DESC Desc; uint8 PlaneCount; uint16 SubresourceCount; - CResourceState* pResourceState; + CResourceState ResourceState; D3D12_RESOURCE_STATES DefaultResourceState; D3D12_RESOURCE_STATES ReadableState; D3D12_RESOURCE_STATES WritableState; @@ -152,11 +152,12 @@ public: uint16 GetArraySize() const { return (Desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D) ? 1 : Desc.DepthOrArraySize; } uint8 GetPlaneCount() const { return PlaneCount; } uint16 GetSubresourceCount() const { return SubresourceCount; } - CResourceState* GetResourceState() + CResourceState& GetResourceState() { + check(bRequiresResourceStateTracking); // This state is used as the resource's "global" state between command lists. It's only needed for resources that // require state tracking. - return pResourceState; + return ResourceState; } D3D12_RESOURCE_STATES GetDefaultResourceState() const { check(!bRequiresResourceStateTracking); return DefaultResourceState; } D3D12_RESOURCE_STATES GetWritableState() const { return WritableState; } @@ -205,7 +206,7 @@ public: bReadBackResource(HeapType == D3D12_HEAP_TYPE_READBACK) {} - const D3D12_RESOURCE_STATES GetOptimalInitialState() const + const D3D12_RESOURCE_STATES GetOptimalInitialState(bool bAccurateWriteableStates) const { if (bSRVOnly) { @@ -215,9 +216,28 @@ public: { return (bReadBackResource) ? D3D12_RESOURCE_STATE_COPY_DEST : D3D12_RESOURCE_STATE_GENERIC_READ; } - else if (bWritable) // This things require tracking anyway + else if (bWritable) { - return D3D12_RESOURCE_STATE_COMMON; + if (bAccurateWriteableStates) + { + if (bDSV) + { + return D3D12_RESOURCE_STATE_DEPTH_WRITE; + } + else if (bRTV) + { + return D3D12_RESOURCE_STATE_RENDER_TARGET; + } + else if (bUAV) + { + return D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + } + } + else + { + // This things require tracking anyway + return D3D12_RESOURCE_STATE_COMMON; + } } return D3D12_RESOURCE_STATE_COMMON; @@ -242,9 +262,8 @@ private: if (bRequiresResourceStateTracking) { // Only a few resources (~1%) actually need resource state tracking - pResourceState = new CResourceState(); - pResourceState->Initialize(SubresourceCount); - pResourceState->SetResourceState(InitialState); + ResourceState.Initialize(SubresourceCount); + ResourceState.SetResourceState(InitialState); } } @@ -390,7 +409,7 @@ public: const inline bool IsValid() const { return Type != ResourceLocationType::eUndefined; } - inline void AsStandAlone(FD3D12Resource* Resource, uint32 BufferSize = 0) + inline void AsStandAlone(FD3D12Resource* Resource, uint32 BufferSize = 0, bool bInIsTransient = false ) { SetType(FD3D12ResourceLocation::ResourceLocationType::eStandAlone); SetResource(Resource); @@ -401,6 +420,7 @@ public: SetMappedBaseAddress(Resource->Map()); } SetGPUVirtualAddress(Resource->GetGPUVirtualAddress()); + SetTransient(bInIsTransient); } inline void AsFastAllocation(FD3D12Resource* Resource, uint32 BufferSize, D3D12_GPU_VIRTUAL_ADDRESS GPUBase, void* CPUBase, uint64 Offset) @@ -422,6 +442,15 @@ public: // it complicates the resource ownership model. static void Alias(FD3D12ResourceLocation& Destination, FD3D12ResourceLocation& Source); + void SetTransient(bool bInTransient) + { + bTransient = bInTransient; + } + bool IsTransient() const + { + return bTransient; + } + private: template @@ -451,6 +480,8 @@ private: // The size the application asked for uint64 Size; + + bool bTransient; }; class FD3D12DeferredDeletionQueue : public FD3D12AdapterChild @@ -526,6 +557,8 @@ struct FD3D12LockedResource : public FD3D12DeviceChild class FD3D12BaseShaderResource : public FD3D12DeviceChild, public IRefCountedObject { public: + FD3D12Resource* GetResource() const { return ResourceLocation.GetResource(); } + FD3D12ResourceLocation ResourceLocation; uint32 BufferAlignment; @@ -576,8 +609,15 @@ private: class FD3D12DynamicRHI* D3D12RHI; }; +#if PLATFORM_WINDOWS +class FD3D12TransientResource +{ + // Nothing special for fast ram +}; +#endif + /** Index buffer resource class that stores stride information. */ -class FD3D12IndexBuffer : public FRHIIndexBuffer, public FD3D12BaseShaderResource, public FD3D12LinkedAdapterObject +class FD3D12IndexBuffer : public FRHIIndexBuffer, public FD3D12BaseShaderResource, public FD3D12TransientResource, public FD3D12LinkedAdapterObject { public: @@ -609,7 +649,7 @@ public: }; /** Structured buffer resource class. */ -class FD3D12StructuredBuffer : public FRHIStructuredBuffer, public FD3D12BaseShaderResource, public FD3D12LinkedAdapterObject +class FD3D12StructuredBuffer : public FRHIStructuredBuffer, public FD3D12BaseShaderResource, public FD3D12TransientResource, public FD3D12LinkedAdapterObject { public: @@ -644,7 +684,7 @@ public: class FD3D12ShaderResourceView; /** Vertex buffer resource class. */ -class FD3D12VertexBuffer : public FRHIVertexBuffer, public FD3D12BaseShaderResource, public FD3D12LinkedAdapterObject +class FD3D12VertexBuffer : public FRHIVertexBuffer, public FD3D12BaseShaderResource, public FD3D12TransientResource, public FD3D12LinkedAdapterObject { public: // Current SRV @@ -720,6 +760,16 @@ public: Barrier.Transition.pResource = pResource; } + void AddAliasingBarrier(ID3D12Resource* pResource) + { + Barriers.AddUninitialized(); + D3D12_RESOURCE_BARRIER& Barrier = Barriers.Last(); + Barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_ALIASING; + Barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + Barrier.Aliasing.pResourceBefore = NULL; + Barrier.Aliasing.pResourceAfter = pResource; + } + // Flush the batch to the specified command list then reset. void Flush(ID3D12GraphicsCommandList* pCommandList) { diff --git a/Engine/Source/Runtime/D3D12RHI/Public/D3D12RootSignatureDefinitions.h b/Engine/Source/Runtime/D3D12RHI/Public/D3D12RootSignatureDefinitions.h index a42987fe9f27..d1017f024ea2 100644 --- a/Engine/Source/Runtime/D3D12RHI/Public/D3D12RootSignatureDefinitions.h +++ b/Engine/Source/Runtime/D3D12RHI/Public/D3D12RootSignatureDefinitions.h @@ -13,6 +13,7 @@ namespace D3D12ShaderUtils // Simple base class to help write out a root signature (subclass to generate either to a binary struct or a #define) struct FRootSignatureCreator { + virtual ~FRootSignatureCreator() { } virtual void AddRootFlag(D3D12_ROOT_SIGNATURE_FLAGS Flag) = 0; enum EType { diff --git a/Engine/Source/Runtime/D3D12RHI/Public/D3D12Util.h b/Engine/Source/Runtime/D3D12RHI/Public/D3D12Util.h index 15954c4bacdd..9ff57a61cb0c 100644 --- a/Engine/Source/Runtime/D3D12RHI/Public/D3D12Util.h +++ b/Engine/Source/Runtime/D3D12RHI/Public/D3D12Util.h @@ -283,7 +283,7 @@ private: // Only used if m_AllSubresourcesSame is 0. // The state of each subresources. Bits are from D3D12_RESOURCE_STATES. - TArray m_SubresourceState; + TArray> m_SubresourceState; }; //================================================================================================================================== diff --git a/Engine/Source/Runtime/DatabaseSupport/Private/Database.cpp b/Engine/Source/Runtime/DatabaseSupport/Private/Database.cpp index 37769defc133..d887e30d9ceb 100644 --- a/Engine/Source/Runtime/DatabaseSupport/Private/Database.cpp +++ b/Engine/Source/Runtime/DatabaseSupport/Private/Database.cpp @@ -319,7 +319,10 @@ FRemoteDataBaseRecordSet::~FRemoteDataBaseRecordSet() // using %COMMONFILES% works to hide the localization issues and non default program file folders. //#import "C:\Program files\Common Files\System\Ado\msado15.dll" rename("EOF", "ADOEOF") +#pragma warning(push) +#pragma warning(disable: 4471) // a forward declaration of an unscoped enumeration must have an underlying type (int assumed) #import "System\ADO\msado15.dll" rename("EOF", "ADOEOF") //lint !e322 +#pragma warning(pop) /*----------------------------------------------------------------------------- FADODataBaseRecordSet implementation. diff --git a/Engine/Source/Runtime/Engine/Classes/AI/Navigation/AvoidanceManager.h b/Engine/Source/Runtime/Engine/Classes/AI/Navigation/AvoidanceManager.h index a59bbb29730a..0c9e39df4391 100644 --- a/Engine/Source/Runtime/Engine/Classes/AI/Navigation/AvoidanceManager.h +++ b/Engine/Source/Runtime/Engine/Classes/AI/Navigation/AvoidanceManager.h @@ -139,11 +139,9 @@ class ENGINE_API UAvoidanceManager : public UObject, public FSelfRegisteringExec FVector GetAvoidanceVelocityForComponent(UMovementComponent* MovementComp); /** Only use if you want manual velocity planning. Provide your AvoidanceUID in order to avoid colliding with yourself. */ - UFUNCTION(BlueprintCallable, Category="AI") FVector GetAvoidanceVelocityIgnoringUID(const FNavAvoidanceData& AvoidanceData, float DeltaTime, int32 IgnoreThisUID); /** Only use if you want manual velocity planning. Will not ignore your own volume if you are registered. */ - UFUNCTION(BlueprintCallable, Category="AI") FVector GetAvoidanceVelocity(const FNavAvoidanceData& AvoidanceData, float DeltaTime); /** Update the RVO avoidance data for the participating UMovementComponent */ diff --git a/Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavAreas/NavArea.h b/Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavAreas/NavArea.h index 5af34b9ae8ca..417d1752f61d 100644 --- a/Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavAreas/NavArea.h +++ b/Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavAreas/NavArea.h @@ -80,6 +80,7 @@ public: virtual void FinishDestroy() override; virtual void PostLoad() override; + virtual void PostInitProperties() override; virtual void Serialize(FArchive& Ar) override; FORCEINLINE uint16 GetAreaFlags() const { return AreaFlags; } @@ -107,4 +108,6 @@ protected: /** these flags will be applied to navigation data along with AreaID */ uint16 AreaFlags; + + void RegisterArea(); }; diff --git a/Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavLinkDefinition.h b/Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavLinkDefinition.h index 26c536835721..77504262ee98 100644 --- a/Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavLinkDefinition.h +++ b/Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavLinkDefinition.h @@ -175,7 +175,7 @@ struct TStructOpsTypeTraits< FNavigationLinkBase > : public TStructOpsTypeTraits }; }; -USTRUCT() +USTRUCT(BlueprintType) struct ENGINE_API FNavigationLink : public FNavigationLinkBase { GENERATED_USTRUCT_BODY() @@ -183,7 +183,7 @@ struct ENGINE_API FNavigationLink : public FNavigationLinkBase UPROPERTY(EditAnywhere, Category=Default, BlueprintReadWrite, meta=(MakeEditWidget="")) FVector Left; - UPROPERTY(EditAnywhere, Category=Default, BlueprintReadWrite, meta=(MakeEditWidget="")) + UPROPERTY(EditAnywhere, Category=Default, meta=(MakeEditWidget="")) FVector Right; FNavigationLink() @@ -242,16 +242,16 @@ struct ENGINE_API FNavigationSegmentLink : public FNavigationLinkBase { GENERATED_USTRUCT_BODY() - UPROPERTY(EditAnywhere, Category=Default, BlueprintReadWrite, meta=(MakeEditWidget="")) + UPROPERTY(EditAnywhere, Category=Default, meta=(MakeEditWidget="")) FVector LeftStart; - UPROPERTY(EditAnywhere, Category=Default, BlueprintReadWrite, meta=(MakeEditWidget="")) + UPROPERTY(EditAnywhere, Category=Default, meta=(MakeEditWidget="")) FVector LeftEnd; - UPROPERTY(EditAnywhere, Category=Default, BlueprintReadWrite, meta=(MakeEditWidget="")) + UPROPERTY(EditAnywhere, Category=Default, meta=(MakeEditWidget="")) FVector RightStart; - UPROPERTY(EditAnywhere, Category=Default, BlueprintReadWrite, meta=(MakeEditWidget="")) + UPROPERTY(EditAnywhere, Category=Default, meta=(MakeEditWidget="")) FVector RightEnd; FNavigationSegmentLink() diff --git a/Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavLinkProxy.h b/Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavLinkProxy.h index 6100bb2d834e..6be04f91542a 100644 --- a/Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavLinkProxy.h +++ b/Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavLinkProxy.h @@ -34,9 +34,8 @@ class ENGINE_API ANavLinkProxy : public AActor, public INavLinkHostInterface, pu UPROPERTY() TArray SegmentLinks; -private_subobject: +private: /** Smart link: can affect path following */ - DEPRECATED_FORGAME(4.6, "SmartLinkComp should not be accessed directly, please use GetSmartLinkComp() function instead. SmartLinkComp will soon be private and your code will not compile.") UPROPERTY(VisibleAnywhere, Category=SmartLink) UNavLinkCustomComponent* SmartLinkComp; public: @@ -46,13 +45,11 @@ public: bool bSmartLinkIsRelevant; #if WITH_EDITORONLY_DATA -private_subobject: +private: /** Editor Preview */ - DEPRECATED_FORGAME(4.6, "EdRenderComp should not be accessed directly, please use GetEdRenderComp() function instead. EdRenderComp will soon be private and your code will not compile.") UPROPERTY() UNavLinkRenderingComponent* EdRenderComp; - DEPRECATED_FORGAME(4.6, "SpriteComponent should not be accessed directly, please use GetSpriteComponent() function instead. SpriteComponent will soon be private and your code will not compile.") UPROPERTY() UBillboardComponent* SpriteComponent; public: @@ -118,11 +115,11 @@ protected: public: /** Returns SmartLinkComp subobject **/ - UNavLinkCustomComponent* GetSmartLinkComp() const; + UNavLinkCustomComponent* GetSmartLinkComp() const { return SmartLinkComp; } #if WITH_EDITORONLY_DATA /** Returns EdRenderComp subobject **/ - UNavLinkRenderingComponent* GetEdRenderComp() const; + UNavLinkRenderingComponent* GetEdRenderComp() const { return EdRenderComp; } /** Returns SpriteComponent subobject **/ - UBillboardComponent* GetSpriteComponent() const; + UBillboardComponent* GetSpriteComponent() const { return SpriteComponent; } #endif }; diff --git a/Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavigationData.h b/Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavigationData.h index a70472061078..774ccb5fb861 100644 --- a/Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavigationData.h +++ b/Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavigationData.h @@ -586,6 +586,7 @@ public: bool CanBeMainNavData() const { return bCanBeMainNavData; } bool CanSpawnOnRebuild() const { return bCanSpawnOnRebuild; } + bool NeedsRebuildOnLoad() const { return bForceRebuildOnLoad; } protected: virtual void FillConfig(FNavDataConfig& Dest) { Dest = NavDataConfig; } diff --git a/Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavigationSystem.h b/Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavigationSystem.h index bb12c2f479ef..446b54c0690d 100644 --- a/Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavigationSystem.h +++ b/Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavigationSystem.h @@ -262,36 +262,36 @@ public: // Blueprint functions //----------------------------------------------------------------------// - UFUNCTION(BlueprintPure, Category = "AI|Navigation", meta = (WorldContext = "WorldContext")) - static UNavigationSystem* GetNavigationSystem(UObject* WorldContext); + UFUNCTION(BlueprintPure, Category = "AI|Navigation", meta = (WorldContext = "WorldContextObject")) + static UNavigationSystem* GetNavigationSystem(UObject* WorldContextObject); /** Project a point onto the NavigationData */ - UFUNCTION(BlueprintPure, Category = "AI|Navigation", meta = (WorldContext = "WorldContext", DisplayName = "ProjectPointToNavigation")) - static bool K2_ProjectPointToNavigation(UObject* WorldContext, const FVector& Point, FVector& ProjectedLocation, ANavigationData* NavData, TSubclassOf FilterClass, const FVector QueryExtent = FVector::ZeroVector); + UFUNCTION(BlueprintPure, Category = "AI|Navigation", meta = (WorldContext = "WorldContextObject", DisplayName = "ProjectPointToNavigation")) + static bool K2_ProjectPointToNavigation(UObject* WorldContextObject, const FVector& Point, FVector& ProjectedLocation, ANavigationData* NavData, TSubclassOf FilterClass, const FVector QueryExtent = FVector::ZeroVector); /** Generates a random location reachable from given Origin location. * @return Return Value represents if the call was successful */ - UFUNCTION(BlueprintPure, Category = "AI|Navigation", meta = (WorldContext = "WorldContext", DisplayName = "GetRandomReachablePointInRadius")) - static bool K2_GetRandomReachablePointInRadius(UObject* WorldContext, const FVector& Origin, FVector& RandomLocation, float Radius, ANavigationData* NavData = NULL, TSubclassOf FilterClass = NULL); + UFUNCTION(BlueprintPure, Category = "AI|Navigation", meta = (WorldContext = "WorldContextObject", DisplayName = "GetRandomReachablePointInRadius")) + static bool K2_GetRandomReachablePointInRadius(UObject* WorldContextObject, const FVector& Origin, FVector& RandomLocation, float Radius, ANavigationData* NavData = NULL, TSubclassOf FilterClass = NULL); /** Generates a random location in navigable space within given radius of Origin. * @return Return Value represents if the call was successful */ - UFUNCTION(BlueprintPure, Category = "AI|Navigation", meta = (WorldContext = "WorldContext", DisplayName = "GetRandomPointInNavigableRadius")) - static bool K2_GetRandomPointInNavigableRadius(UObject* WorldContext, const FVector& Origin, FVector& RandomLocation, float Radius, ANavigationData* NavData = NULL, TSubclassOf FilterClass = NULL); + UFUNCTION(BlueprintPure, Category = "AI|Navigation", meta = (WorldContext = "WorldContextObject", DisplayName = "GetRandomPointInNavigableRadius")) + static bool K2_GetRandomPointInNavigableRadius(UObject* WorldContextObject, const FVector& Origin, FVector& RandomLocation, float Radius, ANavigationData* NavData = NULL, TSubclassOf FilterClass = NULL); /** Potentially expensive. Use with caution. Consider using UPathFollowingComponent::GetRemainingPathCost instead */ - UFUNCTION(BlueprintPure, Category="AI|Navigation", meta=(WorldContext="WorldContext" ) ) - static ENavigationQueryResult::Type GetPathCost(UObject* WorldContext, const FVector& PathStart, const FVector& PathEnd, float& PathCost, ANavigationData* NavData = NULL, TSubclassOf FilterClass = NULL); + UFUNCTION(BlueprintPure, Category="AI|Navigation", meta=(WorldContext="WorldContextObject" ) ) + static ENavigationQueryResult::Type GetPathCost(UObject* WorldContextObject, const FVector& PathStart, const FVector& PathEnd, float& PathCost, ANavigationData* NavData = NULL, TSubclassOf FilterClass = NULL); /** Potentially expensive. Use with caution */ - UFUNCTION(BlueprintPure, Category="AI|Navigation", meta=(WorldContext="WorldContext" ) ) - static ENavigationQueryResult::Type GetPathLength(UObject* WorldContext, const FVector& PathStart, const FVector& PathEnd, float& PathLength, ANavigationData* NavData = NULL, TSubclassOf FilterClass = NULL); + UFUNCTION(BlueprintPure, Category="AI|Navigation", meta=(WorldContext="WorldContextObject" ) ) + static ENavigationQueryResult::Type GetPathLength(UObject* WorldContextObject, const FVector& PathStart, const FVector& PathEnd, float& PathLength, ANavigationData* NavData = NULL, TSubclassOf FilterClass = NULL); - UFUNCTION(BlueprintPure, Category="AI|Navigation", meta=(WorldContext="WorldContext" ) ) - static bool IsNavigationBeingBuilt(UObject* WorldContext); + UFUNCTION(BlueprintPure, Category="AI|Navigation", meta=(WorldContext="WorldContextObject" ) ) + static bool IsNavigationBeingBuilt(UObject* WorldContextObject); - UFUNCTION(BlueprintPure, Category = "AI|Navigation", meta = (WorldContext = "WorldContext")) - static bool IsNavigationBeingBuiltOrLocked(UObject* WorldContext); + UFUNCTION(BlueprintPure, Category = "AI|Navigation", meta = (WorldContext = "WorldContextObject")) + static bool IsNavigationBeingBuiltOrLocked(UObject* WorldContextObject); UFUNCTION(BlueprintCallable, Category="AI|Navigation") static void SimpleMoveToActor(AController* Controller, const AActor* Goal); @@ -301,21 +301,21 @@ public: /** Finds path instantly, in a FindPath Synchronously. * @param PathfindingContext could be one of following: NavigationData (like Navmesh actor), Pawn or Controller. This parameter determines parameters of specific pathfinding query */ - UFUNCTION(BlueprintCallable, Category = "AI|Navigation", meta = (WorldContext="WorldContext")) - static UNavigationPath* FindPathToLocationSynchronously(UObject* WorldContext, const FVector& PathStart, const FVector& PathEnd, AActor* PathfindingContext = NULL, TSubclassOf FilterClass = NULL); + UFUNCTION(BlueprintCallable, Category = "AI|Navigation", meta = (WorldContext="WorldContextObject")) + static UNavigationPath* FindPathToLocationSynchronously(UObject* WorldContextObject, const FVector& PathStart, const FVector& PathEnd, AActor* PathfindingContext = NULL, TSubclassOf FilterClass = NULL); /** Finds path instantly, in a FindPath Synchronously. Main advantage over FindPathToLocationSynchronously is that * the resulting path will automatically get updated if goal actor moves more than TetherDistance away from last path node * @param PathfindingContext could be one of following: NavigationData (like Navmesh actor), Pawn or Controller. This parameter determines parameters of specific pathfinding query */ - UFUNCTION(BlueprintCallable, Category = "AI|Navigation", meta = (WorldContext="WorldContext")) - static UNavigationPath* FindPathToActorSynchronously(UObject* WorldContext, const FVector& PathStart, AActor* GoalActor, float TetherDistance = 50.f, AActor* PathfindingContext = NULL, TSubclassOf FilterClass = NULL); + UFUNCTION(BlueprintCallable, Category = "AI|Navigation", meta = (WorldContext="WorldContextObject")) + static UNavigationPath* FindPathToActorSynchronously(UObject* WorldContextObject, const FVector& PathStart, AActor* GoalActor, float TetherDistance = 50.f, AActor* PathfindingContext = NULL, TSubclassOf FilterClass = NULL); /** Performs navigation raycast on NavigationData appropriate for given Querier. * @param Querier if not passed default navigation data will be used * @param HitLocation if line was obstructed this will be set to hit location. Otherwise it contains SegmentEnd * @return true if line from RayStart to RayEnd was obstructed. Also, true when no navigation data present */ - UFUNCTION(BlueprintCallable, Category="AI|Navigation", meta=(WorldContext="WorldContext" )) - static bool NavigationRaycast(UObject* WorldContext, const FVector& RayStart, const FVector& RayEnd, FVector& HitLocation, TSubclassOf FilterClass = NULL, AController* Querier = NULL); + UFUNCTION(BlueprintCallable, Category="AI|Navigation", meta=(WorldContext="WorldContextObject" )) + static bool NavigationRaycast(UObject* WorldContextObject, const FVector& RayStart, const FVector& RayEnd, FVector& HitLocation, TSubclassOf FilterClass = NULL, AController* Querier = NULL); /** will limit the number of simultaneously running navmesh tile generation jobs to specified number. * @param MaxNumberOfJobs gets trimmed to be at least 1. You cannot use this function to pause navmesh generation */ @@ -955,7 +955,7 @@ private: void AddNavigationBoundsUpdateRequest(const FNavigationBoundsUpdateRequest& UpdateRequest); /** Triggers navigation building on all eligible navigation data. */ - void RebuildAll(); + void RebuildAll(bool bIsLoadTime = false); /** Handler for FWorldDelegates::LevelAddedToWorld event */ void OnLevelAddedToWorld(ULevel* InLevel, UWorld* InWorld); @@ -1000,13 +1000,13 @@ public: DEPRECATED(4.11, "UpdateNavOctreeAll is deprecated. Use UpdateActorAndComponentsInNavOctree") static void UpdateNavOctreeAll(AActor* Actor); DEPRECATED(4.16, "This version of ProjectPointToNavigation is deprecated. Please use the new version") - UFUNCTION(BlueprintPure, Category = "AI|Navigation", meta = (WorldContext = "WorldContext", DisplayName = "ProjectPointToNavigation_DEPRECATED", DeprecatedFunction, DeprecationMessage = "This version of ProjectPointToNavigation is deprecated. Please use the new version")) - static FVector ProjectPointToNavigation(UObject* WorldContext, const FVector& Point, ANavigationData* NavData = NULL, TSubclassOf FilterClass = NULL, const FVector QueryExtent = FVector::ZeroVector); + UFUNCTION(BlueprintPure, Category = "AI|Navigation", meta = (WorldContext = "WorldContextObject", DisplayName = "ProjectPointToNavigation_DEPRECATED", DeprecatedFunction, DeprecationMessage = "This version of ProjectPointToNavigation is deprecated. Please use the new version")) + static FVector ProjectPointToNavigation(UObject* WorldContextObject, const FVector& Point, ANavigationData* NavData = NULL, TSubclassOf FilterClass = NULL, const FVector QueryExtent = FVector::ZeroVector); DEPRECATED(4.16, "This version of GetRandomReachablePointInRadius is deprecated. Please use the new version") - UFUNCTION(BlueprintPure, Category = "AI|Navigation", meta = (WorldContext = "WorldContext", DisplayName = "GetRandomReachablePointInRadius_DEPRECATED", DeprecatedFunction, DeprecationMessage = "This version of GetRandomReachablePointInRadius is deprecated. Please use the new version")) - static FVector GetRandomReachablePointInRadius(UObject* WorldContext, const FVector& Origin, float Radius, ANavigationData* NavData = NULL, TSubclassOf FilterClass = NULL); + UFUNCTION(BlueprintPure, Category = "AI|Navigation", meta = (WorldContext = "WorldContextObject", DisplayName = "GetRandomReachablePointInRadius_DEPRECATED", DeprecatedFunction, DeprecationMessage = "This version of GetRandomReachablePointInRadius is deprecated. Please use the new version")) + static FVector GetRandomReachablePointInRadius(UObject* WorldContextObject, const FVector& Origin, float Radius, ANavigationData* NavData = NULL, TSubclassOf FilterClass = NULL); DEPRECATED(4.16, "This version of GetRandomPointInNavigableRadius is deprecated. Please use the new version") - UFUNCTION(BlueprintPure, Category = "AI|Navigation", meta = (WorldContext = "WorldContext", DisplayName = "GetRandomPointInNavigableRadius_DEPRECATED", DeprecatedFunction, DeprecationMessage = "This version of GetRandomPointInNavigableRadius is deprecated. Please use the new version")) - static FVector GetRandomPointInNavigableRadius(UObject* WorldContext, const FVector& Origin, float Radius, ANavigationData* NavData = NULL, TSubclassOf FilterClass = NULL); + UFUNCTION(BlueprintPure, Category = "AI|Navigation", meta = (WorldContext = "WorldContextObject", DisplayName = "GetRandomPointInNavigableRadius_DEPRECATED", DeprecatedFunction, DeprecationMessage = "This version of GetRandomPointInNavigableRadius is deprecated. Please use the new version")) + static FVector GetRandomPointInNavigableRadius(UObject* WorldContextObject, const FVector& Origin, float Radius, ANavigationData* NavData = NULL, TSubclassOf FilterClass = NULL); }; diff --git a/Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavigationTestingActor.h b/Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavigationTestingActor.h index 56ac96b9787d..3035c39bfee0 100644 --- a/Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavigationTestingActor.h +++ b/Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavigationTestingActor.h @@ -45,14 +45,12 @@ class ENGINE_API ANavigationTestingActor : public AActor, public INavAgentInterf { GENERATED_UCLASS_BODY() -private_subobject: - DEPRECATED_FORGAME(4.6, "CapsuleComponent should not be accessed directly, please use GetCapsuleComponent() function instead. CapsuleComponent will soon be private and your code will not compile.") +private: UPROPERTY() class UCapsuleComponent* CapsuleComponent; #if WITH_EDITORONLY_DATA /** Editor Preview */ - DEPRECATED_FORGAME(4.6, "EdRenderComp should not be accessed directly, please use GetEdRenderComp() function instead. EdRenderComp will soon be private and your code will not compile.") UPROPERTY() class UNavTestRenderingComponent* EdRenderComp; #endif // WITH_EDITORONLY_DATA @@ -201,10 +199,10 @@ public: virtual FPathFindingQuery BuildPathFindingQuery(const ANavigationTestingActor* Goal) const; /** Returns CapsuleComponent subobject **/ - class UCapsuleComponent* GetCapsuleComponent() const; + class UCapsuleComponent* GetCapsuleComponent() const { return CapsuleComponent; } #if WITH_EDITORONLY_DATA /** Returns EdRenderComp subobject **/ - class UNavTestRenderingComponent* GetEdRenderComp() const; + class UNavTestRenderingComponent* GetEdRenderComp() const { return EdRenderComp; } #endif protected: diff --git a/Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavigationTypes.h b/Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavigationTypes.h index 3eb483f61979..dedc222bebc8 100644 --- a/Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavigationTypes.h +++ b/Engine/Source/Runtime/Engine/Classes/AI/Navigation/NavigationTypes.h @@ -421,7 +421,7 @@ typedef TSharedPtr FNavPathSharedPt typedef TWeakPtr FNavPathWeakPtr; /** Movement capabilities, determining available movement options for Pawns and used by AI for reachability tests. */ -USTRUCT() +USTRUCT(BlueprintType) struct FMovementProperties { GENERATED_USTRUCT_BODY() @@ -457,7 +457,7 @@ struct FMovementProperties }; /** Properties of representation of an 'agent' (or Pawn) used by AI navigation/pathfinding. */ -USTRUCT() +USTRUCT(BlueprintType) struct ENGINE_API FNavAgentProperties : public FMovementProperties { GENERATED_USTRUCT_BODY() @@ -522,7 +522,7 @@ inline uint32 GetTypeHash(const FNavAgentProperties& A) return ((int16(A.AgentRadius) << 16) | int16(A.AgentHeight)) ^ int32(A.AgentStepHeight); } -USTRUCT() +USTRUCT(BlueprintType) struct ENGINE_API FNavDataConfig : public FNavAgentProperties { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/Animation/AnimBlueprint.h b/Engine/Source/Runtime/Engine/Classes/Animation/AnimBlueprint.h index 25050693711e..6375e2d94470 100644 --- a/Engine/Source/Runtime/Engine/Classes/Animation/AnimBlueprint.h +++ b/Engine/Source/Runtime/Engine/Classes/Animation/AnimBlueprint.h @@ -115,6 +115,7 @@ class ENGINE_API UAnimBlueprint : public UBlueprint } virtual bool IsValidForBytecodeOnlyRecompile() const override { return false; } + virtual bool CanRecompileWhilePlayingInEditor() const override; // End of UBlueprint interface // Finds the index of the specified group, or creates a new entry for it (unless the name is NAME_None, which will return INDEX_NONE) diff --git a/Engine/Source/Runtime/Engine/Classes/Animation/AnimCompositeBase.h b/Engine/Source/Runtime/Engine/Classes/Animation/AnimCompositeBase.h index 99b390376d8f..7d328b65b958 100644 --- a/Engine/Source/Runtime/Engine/Classes/Animation/AnimCompositeBase.h +++ b/Engine/Source/Runtime/Engine/Classes/Animation/AnimCompositeBase.h @@ -60,26 +60,26 @@ struct FAnimSegment GENERATED_USTRUCT_BODY() /** Anim Reference to play - only allow AnimSequence or AnimComposite **/ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=AnimSegment) + UPROPERTY(EditAnywhere, Category=AnimSegment) UAnimSequenceBase* AnimReference; /** Start Pos within this AnimCompositeBase */ - UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category=AnimSegment) + UPROPERTY(VisibleAnywhere, Category=AnimSegment) float StartPos; /** Time to start playing AnimSequence at. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=AnimSegment) + UPROPERTY(EditAnywhere, Category=AnimSegment) float AnimStartTime; /** Time to end playing the AnimSequence at. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=AnimSegment) + UPROPERTY(EditAnywhere, Category=AnimSegment) float AnimEndTime; /** Playback speed of this animation. If you'd like to reverse, set -1*/ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=AnimSegment) + UPROPERTY(EditAnywhere, Category=AnimSegment) float AnimPlayRate; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=AnimSegment) + UPROPERTY(EditAnywhere, Category=AnimSegment) int32 LoopingCount; FAnimSegment() @@ -187,7 +187,7 @@ struct FAnimTrack { GENERATED_USTRUCT_BODY() - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=AnimTrack, EditFixedSize) + UPROPERTY(EditAnywhere, Category=AnimTrack, EditFixedSize) TArray AnimSegments; FAnimTrack() {} diff --git a/Engine/Source/Runtime/Engine/Classes/Animation/AnimInstance.h b/Engine/Source/Runtime/Engine/Classes/Animation/AnimInstance.h index 44f21af9fa22..d6e814278c2e 100644 --- a/Engine/Source/Runtime/Engine/Classes/Animation/AnimInstance.h +++ b/Engine/Source/Runtime/Engine/Classes/Animation/AnimInstance.h @@ -16,6 +16,9 @@ #include "Animation/AnimNotifies/AnimNotify.h" #include "AnimInstance.generated.h" +// Post Compile Validation requires WITH_EDITOR +#define ANIMINST_PostCompileValidation WITH_EDITOR + class FDebugDisplayInfo; class IAnimClassInterface; class UAnimInstance; @@ -707,14 +710,6 @@ private: /** Used to guard against recursive calls to UpdateAnimation */ bool bPostUpdatingAnimation; -#if WITH_EDITOR - /** Delegate for custom animation curve addition */ - TArray OnAddAnimationCurves; -public: - /** Add custom curve delegates */ - void AddDelegate_AddCustomAnimationCurve(FOnAddCustomAnimationCurves& InOnAddCustomAnimationCurves); - void RemoveDelegate_AddCustomAnimationCurve(FOnAddCustomAnimationCurves& InOnAddCustomAnimationCurves); -#endif // editor only for now public: /** Is this animation currently running post update */ @@ -820,7 +815,6 @@ public: /** Returns the baked sync group index from the compile step */ int32 GetSyncGroupIndexFromName(FName SyncGroupName) const; -protected: /** Gets the index of the state machine matching MachineName */ int32 GetStateMachineIndex(FName MachineName); @@ -931,6 +925,16 @@ public: static void AddReferencedObjects(UObject* InThis, FReferenceCollector& Collector); //~ End UObject Interface +#if WITH_EDITORONLY_DATA // ANIMINST_PostCompileValidation + /** Name of Class to do Post Compile Validation. + * See Class UAnimBlueprintPostCompileValidation. */ + UPROPERTY() + FStringClassReference PostCompileValidationClassName; + + /** Warn if AnimNodes are not using fast path during AnimBP compilation. */ + virtual bool PCV_ShouldWarnAboutNodesNotUsingFastPath() const { return false; } +#endif // WITH_EDITORONLY_DATA + virtual void OnUROSkipTickAnimation() {} virtual void OnUROPreInterpolation() {} @@ -1250,4 +1254,8 @@ public: /** Called when a montage hits a 'PlayMontageNotify' or 'PlayMontageNotifyWindow' end */ FPlayMontageAnimNotifyDelegate OnPlayMontageNotifyEnd; + +public: + /** Dispatch AnimEvents (AnimNotifies, Montage Events) queued during UpdateAnimation() */ + void DispatchQueuedAnimEvents(); }; diff --git a/Engine/Source/Runtime/Engine/Classes/Animation/AnimMontage.h b/Engine/Source/Runtime/Engine/Classes/Animation/AnimMontage.h index c1f7f48f4407..de3bd53cad33 100644 --- a/Engine/Source/Runtime/Engine/Classes/Animation/AnimMontage.h +++ b/Engine/Source/Runtime/Engine/Classes/Animation/AnimMontage.h @@ -361,7 +361,7 @@ public: * second is normal tick. This tick has to happen later when all node ticks * to accumulate and update curve data/notifies/branching points */ - void UpdateWeight(float DeltaTime); + ENGINE_API void UpdateWeight(float DeltaTime); //~ @fixme laurent can we make Advance use that, so we don't have 2 code paths which risk getting out of sync? /** Simulate is same as Advance, but without calling any events or touching any of the instance data. So it performs a simulation of advancing the timeline. */ bool SimulateAdvance(float DeltaTime, float& InOutPosition, struct FRootMotionMovementParams & OutRootMotionParams) const; diff --git a/Engine/Source/Runtime/Engine/Classes/Animation/AnimNodeBase.h b/Engine/Source/Runtime/Engine/Classes/Animation/AnimNodeBase.h index 71910022f89c..47043ce880ac 100644 --- a/Engine/Source/Runtime/Engine/Classes/Animation/AnimNodeBase.h +++ b/Engine/Source/Runtime/Engine/Classes/Animation/AnimNodeBase.h @@ -332,7 +332,7 @@ namespace EPinHidingMode #define ENABLE_ANIMGRAPH_TRAVERSAL_DEBUG 0 /** A pose link to another node */ -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ENGINE_API FPoseLinkBase { GENERATED_USTRUCT_BODY() @@ -390,7 +390,7 @@ public: #define ENABLE_ANIMNODE_POSE_DEBUG 0 /** A local-space pose link to another node */ -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ENGINE_API FPoseLink : public FPoseLinkBase { GENERATED_USTRUCT_BODY() @@ -407,7 +407,7 @@ private: }; /** A component-space pose link to another node */ -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ENGINE_API FComponentSpacePoseLink : public FPoseLinkBase { GENERATED_USTRUCT_BODY() @@ -425,6 +425,23 @@ enum class EPostCopyOperation : uint8 LogicalNegateBool, }; +UENUM() +enum class ECopyType : uint8 +{ + // Just copy the memory + MemCopy, + + // Read and write properties using bool property helpers, as source/dest could be bitfirld or boolean + BoolProperty, + + // Use struct copy operation, as this needs to correctly handle CPP struct ops + StructProperty, + + // Read and write properties using object property helpers, as source/dest could be regular/weak/lazy etc. + ObjectProperty, +}; + + USTRUCT() struct FExposedValueCopyRecord { @@ -440,9 +457,8 @@ struct FExposedValueCopyRecord , Size(0) , bInstanceIsTarget(false) , PostCopyOperation(EPostCopyOperation::None) - , CachedBoolSourceProperty(nullptr) - , CachedBoolDestProperty(nullptr) - , CachedStructDestProperty(nullptr) + , CopyType(ECopyType::MemCopy) + , CachedSourceProperty(nullptr) , CachedSourceContainer(nullptr) , CachedDestContainer(nullptr) , Source(nullptr) @@ -479,17 +495,12 @@ struct FExposedValueCopyRecord UPROPERTY() EPostCopyOperation PostCopyOperation; - // cached source property for performing boolean operations UPROPERTY(Transient) - UBoolProperty* CachedBoolSourceProperty; + ECopyType CopyType; - // cached dest property for performing boolean operations + // cached source property UPROPERTY(Transient) - UBoolProperty* CachedBoolDestProperty; - - // Cached dest property for copying structs - UPROPERTY(Transient) - UStructProperty* CachedStructDestProperty; + UProperty* CachedSourceProperty; // cached source container for use with boolean operations void* CachedSourceContainer; diff --git a/Engine/Source/Runtime/Engine/Classes/Animation/AnimNodeSpaceConversions.h b/Engine/Source/Runtime/Engine/Classes/Animation/AnimNodeSpaceConversions.h index 277cde5a4f5d..9fdf76281046 100644 --- a/Engine/Source/Runtime/Engine/Classes/Animation/AnimNodeSpaceConversions.h +++ b/Engine/Source/Runtime/Engine/Classes/Animation/AnimNodeSpaceConversions.h @@ -7,7 +7,7 @@ #include "Animation/AnimNodeBase.h" #include "AnimNodeSpaceConversions.generated.h" -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ENGINE_API FAnimNode_ConvertComponentToLocalSpace : public FAnimNode_Base { GENERATED_USTRUCT_BODY() @@ -29,7 +29,7 @@ public: }; -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ENGINE_API FAnimNode_ConvertLocalToComponentSpace : public FAnimNode_Base { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/Animation/AnimNode_ApplyMeshSpaceAdditive.h b/Engine/Source/Runtime/Engine/Classes/Animation/AnimNode_ApplyMeshSpaceAdditive.h index d0a466719fa2..7b77641e3fc9 100644 --- a/Engine/Source/Runtime/Engine/Classes/Animation/AnimNode_ApplyMeshSpaceAdditive.h +++ b/Engine/Source/Runtime/Engine/Classes/Animation/AnimNode_ApplyMeshSpaceAdditive.h @@ -8,7 +8,7 @@ #include "Animation/InputScaleBias.h" #include "AnimNode_ApplyMeshSpaceAdditive.generated.h" -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ENGINE_API FAnimNode_ApplyMeshSpaceAdditive : public FAnimNode_Base { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/Animation/AnimNode_AssetPlayerBase.h b/Engine/Source/Runtime/Engine/Classes/Animation/AnimNode_AssetPlayerBase.h index 04d8ba22d858..6e5b5d3534e1 100644 --- a/Engine/Source/Runtime/Engine/Classes/Animation/AnimNode_AssetPlayerBase.h +++ b/Engine/Source/Runtime/Engine/Classes/Animation/AnimNode_AssetPlayerBase.h @@ -9,7 +9,7 @@ #include "AnimNode_AssetPlayerBase.generated.h" /* Base class for any asset playing anim node */ -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ENGINE_API FAnimNode_AssetPlayerBase : public FAnimNode_Base { GENERATED_BODY(); diff --git a/Engine/Source/Runtime/Engine/Classes/Animation/AnimNode_SaveCachedPose.h b/Engine/Source/Runtime/Engine/Classes/Animation/AnimNode_SaveCachedPose.h index 5bd47b433097..a22f72b937d6 100644 --- a/Engine/Source/Runtime/Engine/Classes/Animation/AnimNode_SaveCachedPose.h +++ b/Engine/Source/Runtime/Engine/Classes/Animation/AnimNode_SaveCachedPose.h @@ -10,7 +10,7 @@ #include "Animation/AnimNodeBase.h" #include "AnimNode_SaveCachedPose.generated.h" -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ENGINE_API FAnimNode_SaveCachedPose : public FAnimNode_Base { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/Animation/AnimNode_SequencePlayer.h b/Engine/Source/Runtime/Engine/Classes/Animation/AnimNode_SequencePlayer.h index 03abe2811075..0c84451dc9b3 100644 --- a/Engine/Source/Runtime/Engine/Classes/Animation/AnimNode_SequencePlayer.h +++ b/Engine/Source/Runtime/Engine/Classes/Animation/AnimNode_SequencePlayer.h @@ -10,7 +10,7 @@ #pragma once // Sequence player node -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ENGINE_API FAnimNode_SequencePlayer : public FAnimNode_AssetPlayerBase { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/Animation/AnimNode_SubInstance.h b/Engine/Source/Runtime/Engine/Classes/Animation/AnimNode_SubInstance.h index 9e4dbf9630dd..41f10d8a7a5f 100644 --- a/Engine/Source/Runtime/Engine/Classes/Animation/AnimNode_SubInstance.h +++ b/Engine/Source/Runtime/Engine/Classes/Animation/AnimNode_SubInstance.h @@ -12,7 +12,7 @@ struct FAnimInstanceProxy; -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ENGINE_API FAnimNode_SubInstance : public FAnimNode_Base { GENERATED_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/Animation/AnimNode_TransitionPoseEvaluator.h b/Engine/Source/Runtime/Engine/Classes/Animation/AnimNode_TransitionPoseEvaluator.h index 7b72a558dda4..99c2ffc32676 100644 --- a/Engine/Source/Runtime/Engine/Classes/Animation/AnimNode_TransitionPoseEvaluator.h +++ b/Engine/Source/Runtime/Engine/Classes/Animation/AnimNode_TransitionPoseEvaluator.h @@ -41,7 +41,7 @@ namespace EEvaluatorMode /** Animation data node for state machine transitions. * Can be set to supply either the animation data from the transition source (From State) or the transition destination (To State). */ -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ENGINE_API FAnimNode_TransitionPoseEvaluator : public FAnimNode_Base { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/Animation/AnimNode_TransitionResult.h b/Engine/Source/Runtime/Engine/Classes/Animation/AnimNode_TransitionResult.h index a0282533050f..6944cc8d68b0 100644 --- a/Engine/Source/Runtime/Engine/Classes/Animation/AnimNode_TransitionResult.h +++ b/Engine/Source/Runtime/Engine/Classes/Animation/AnimNode_TransitionResult.h @@ -9,7 +9,7 @@ #include "AnimNode_TransitionResult.generated.h" // Root node of a state machine transition graph -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ENGINE_API FAnimNode_TransitionResult : public FAnimNode_Base { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/Animation/AnimNotifies/AnimNotify_PlayParticleEffect.h b/Engine/Source/Runtime/Engine/Classes/Animation/AnimNotifies/AnimNotify_PlayParticleEffect.h index e1b81f7400da..b412957706a8 100644 --- a/Engine/Source/Runtime/Engine/Classes/Animation/AnimNotifies/AnimNotify_PlayParticleEffect.h +++ b/Engine/Source/Runtime/Engine/Classes/Animation/AnimNotifies/AnimNotify_PlayParticleEffect.h @@ -34,15 +34,15 @@ public: // End UAnimNotify interface // Particle System to Spawn - UPROPERTY(EditAnywhere, Category="AnimNotify", meta=(DisplayName="Particle System")) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="AnimNotify", meta=(DisplayName="Particle System")) UParticleSystem* PSTemplate; // Location offset from the socket - UPROPERTY(EditAnywhere, Category="AnimNotify") + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="AnimNotify") FVector LocationOffset; // Rotation offset from socket - UPROPERTY(EditAnywhere, Category="AnimNotify") + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="AnimNotify") FRotator RotationOffset; private: @@ -52,11 +52,11 @@ private: public: // Should attach to the bone/socket - UPROPERTY(EditAnywhere, Category="AnimNotify") + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="AnimNotify") uint32 Attached:1; //~ Does not follow coding standard due to redirection from BP // SocketName to attach to - UPROPERTY(EditAnywhere, Category = "AnimNotify") + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AnimNotify") FName SocketName; }; diff --git a/Engine/Source/Runtime/Engine/Classes/Animation/AnimNotifies/AnimNotify_PlaySound.h b/Engine/Source/Runtime/Engine/Classes/Animation/AnimNotifies/AnimNotify_PlaySound.h index 3d84f50a128f..fef9bbc404d6 100644 --- a/Engine/Source/Runtime/Engine/Classes/Animation/AnimNotifies/AnimNotify_PlaySound.h +++ b/Engine/Source/Runtime/Engine/Classes/Animation/AnimNotifies/AnimNotify_PlaySound.h @@ -39,7 +39,7 @@ public: float PitchMultiplier; // If this sound should follow its owner - UPROPERTY(EditAnywhere, Category = "AnimNotify") + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AnimNotify") uint32 bFollow:1; // Socket or bone name to attach sound to diff --git a/Engine/Source/Runtime/Engine/Classes/Animation/MorphTarget.h b/Engine/Source/Runtime/Engine/Classes/Animation/MorphTarget.h index 3bc7b51b9f84..1ead703e5c35 100644 --- a/Engine/Source/Runtime/Engine/Classes/Animation/MorphTarget.h +++ b/Engine/Source/Runtime/Engine/Classes/Animation/MorphTarget.h @@ -148,7 +148,7 @@ public: bool HasDataForLOD(int32 LODIndex); /** Populates the given morph target LOD model with the provided deltas */ - ENGINE_API void PopulateDeltas(const TArray& Deltas, const int32 LODIndex); + ENGINE_API void PopulateDeltas(const TArray& Deltas, const int32 LODIndex, const bool bCompareNormal = false); public: diff --git a/Engine/Source/Runtime/Engine/Classes/Animation/SkeletalMeshActor.h b/Engine/Source/Runtime/Engine/Classes/Animation/SkeletalMeshActor.h index bff81ba3c624..e1cf86d34e69 100644 --- a/Engine/Source/Runtime/Engine/Classes/Animation/SkeletalMeshActor.h +++ b/Engine/Source/Runtime/Engine/Classes/Animation/SkeletalMeshActor.h @@ -24,6 +24,8 @@ class ENGINE_API ASkeletalMeshActor : public AActor, public IMatineeAnimInterfac { GENERATED_UCLASS_BODY() + virtual void GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const override; + /** Whether or not this actor should respond to anim notifies - CURRENTLY ONLY AFFECTS PlayParticleEffect NOTIFIES**/ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Animation, AdvancedDisplay) uint32 bShouldDoAnimNotifies:1; @@ -31,8 +33,7 @@ class ENGINE_API ASkeletalMeshActor : public AActor, public IMatineeAnimInterfac UPROPERTY() uint32 bWakeOnLevelStart_DEPRECATED:1; -private_subobject: - DEPRECATED_FORGAME(4.6, "SkeletalMeshComponent should not be accessed directly, please use GetSkeletalMeshComponent() function instead. SkeletalMeshComponent will soon be private and your code will not compile.") +private: UPROPERTY(Category = SkeletalMeshActor, VisibleAnywhere, BlueprintReadOnly, meta = (ExposeFunctionCategories = "Mesh,Components|SkeletalMesh,Animation,Physics", AllowPrivateAccess = "true")) class USkeletalMeshComponent* SkeletalMeshComponent; public: @@ -103,7 +104,7 @@ private: public: /** Returns SkeletalMeshComponent subobject **/ - class USkeletalMeshComponent* GetSkeletalMeshComponent(); + class USkeletalMeshComponent* GetSkeletalMeshComponent() { return SkeletalMeshComponent; } }; diff --git a/Engine/Source/Runtime/Engine/Classes/Animation/Skeleton.h b/Engine/Source/Runtime/Engine/Classes/Animation/Skeleton.h index 3329ec3afd90..28b4c850560f 100644 --- a/Engine/Source/Runtime/Engine/Classes/Animation/Skeleton.h +++ b/Engine/Source/Runtime/Engine/Classes/Animation/Skeleton.h @@ -21,7 +21,6 @@ class UAnimSequence; class UBlendProfile; -class UPreviewMeshCollection; class URig; class USkeletalMesh; class USkeletalMeshSocket; @@ -475,7 +474,7 @@ private: /** The additional skeletal meshes to use when previewing this skeleton */ UPROPERTY(duplicatetransient, AssetRegistrySearchable) - TAssetPtr AdditionalPreviewSkeletalMeshes; + TAssetPtr AdditionalPreviewSkeletalMeshes; UPROPERTY() FRigConfiguration RigConfig; @@ -557,10 +556,10 @@ public: ENGINE_API void LoadAdditionalPreviewSkeletalMeshes(); /** Get the additional skeletal meshes we use when previewing this skeleton */ - ENGINE_API UPreviewMeshCollection* GetAdditionalPreviewSkeletalMeshes() const; + ENGINE_API UDataAsset* GetAdditionalPreviewSkeletalMeshes() const; /** Set the additional skeletal meshes we use when previewing this skeleton */ - ENGINE_API void SetAdditionalPreviewSkeletalMeshes(UPreviewMeshCollection* PreviewMeshCollection); + ENGINE_API void SetAdditionalPreviewSkeletalMeshes(UDataAsset* InPreviewCollectionAsset); /** * Makes sure all attached objects are valid and removes any that aren't. diff --git a/Engine/Source/Runtime/Engine/Classes/Atmosphere/AtmosphericFog.h b/Engine/Source/Runtime/Engine/Classes/Atmosphere/AtmosphericFog.h index 42136ebbb096..c2d495e9e0e2 100644 --- a/Engine/Source/Runtime/Engine/Classes/Atmosphere/AtmosphericFog.h +++ b/Engine/Source/Runtime/Engine/Classes/Atmosphere/AtmosphericFog.h @@ -17,15 +17,13 @@ class AAtmosphericFog : public AInfo { GENERATED_UCLASS_BODY() -private_subobject: +private: /** Main fog component */ - DEPRECATED_FORGAME(4.6, "AtmosphericFogComponent should not be accessed directly, please use GetAtmosphericFogComponent() function instead. AtmosphericFogComponent will soon be private and your code will not compile.") UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = Atmosphere, meta = (AllowPrivateAccess = "true")) class UAtmosphericFogComponent* AtmosphericFogComponent; #if WITH_EDITORONLY_DATA /** Arrow component to indicate default sun rotation */ - DEPRECATED_FORGAME(4.6, "ArrowComponent should not be accessed directly, please use GetArrowComponent() function instead. ArrowComponent will soon be private and your code will not compile.") UPROPERTY() class UArrowComponent* ArrowComponent; #endif @@ -37,10 +35,10 @@ public: #endif /** Returns AtmosphericFogComponent subobject **/ - ENGINE_API class UAtmosphericFogComponent* GetAtmosphericFogComponent(); + ENGINE_API class UAtmosphericFogComponent* GetAtmosphericFogComponent() { return AtmosphericFogComponent; } #if WITH_EDITORONLY_DATA /** Returns ArrowComponent subobject **/ - ENGINE_API class UArrowComponent* GetArrowComponent(); + ENGINE_API class UArrowComponent* GetArrowComponent() { return ArrowComponent; } #endif }; diff --git a/Engine/Source/Runtime/Engine/Classes/Atmosphere/AtmosphericFogComponent.h b/Engine/Source/Runtime/Engine/Classes/Atmosphere/AtmosphericFogComponent.h index 0e8d22819c75..56627e6c2291 100644 --- a/Engine/Source/Runtime/Engine/Classes/Atmosphere/AtmosphericFogComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/Atmosphere/AtmosphericFogComponent.h @@ -10,7 +10,7 @@ #include "AtmosphericFogComponent.generated.h" /** Structure storing Data for pre-computation */ -USTRUCT() +USTRUCT(BlueprintType) struct FAtmospherePrecomputeParameters { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/Camera/CameraActor.h b/Engine/Source/Runtime/Engine/Classes/Camera/CameraActor.h index 283f026a272c..58ca4ac0da32 100644 --- a/Engine/Source/Runtime/Engine/Classes/Camera/CameraActor.h +++ b/Engine/Source/Runtime/Engine/Classes/Camera/CameraActor.h @@ -25,10 +25,9 @@ private: UPROPERTY(Category="AutoPlayerActivation", EditAnywhere) TEnumAsByte AutoActivateForPlayer; -private_subobject: +private: /** The camera component for this camera */ - DEPRECATED_FORGAME(4.6, "CameraComponent should not be accessed directly, please use GetCameraComponent() function instead. CameraComponent will soon be private and your code will not compile.") UPROPERTY(Category = CameraActor, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) class UCameraComponent* CameraComponent; @@ -79,7 +78,7 @@ protected: public: /** Returns CameraComponent subobject **/ - class UCameraComponent* GetCameraComponent() const; + class UCameraComponent* GetCameraComponent() const { return CameraComponent; } /** * Called to notify that this camera was cut to, so it can update things like interpolation if necessary. diff --git a/Engine/Source/Runtime/Engine/Classes/Camera/CameraAnimInst.h b/Engine/Source/Runtime/Engine/Classes/Camera/CameraAnimInst.h index 6e80b9509dce..8c370c14b7fd 100644 --- a/Engine/Source/Runtime/Engine/Classes/Camera/CameraAnimInst.h +++ b/Engine/Source/Runtime/Engine/Classes/Camera/CameraAnimInst.h @@ -23,9 +23,8 @@ class ENGINE_API UCameraAnimInst : public UObject UPROPERTY() class UCameraAnim* CamAnim; -private_subobject: +private: /** the UInterpGroupInst used to do the interpolation */ - DEPRECATED_FORGAME(4.6, "InterpGroupInst should not be accessed directly, please use GetInterpGroupInst() function instead. InterpGroupInst will soon be private and your code will not compile.") UPROPERTY(instanced) class UInterpGroupInst* InterpGroupInst; @@ -159,7 +158,7 @@ public: protected: /** Returns InterpGroupInst subobject **/ - class UInterpGroupInst* GetInterpGroupInst() const; + class UInterpGroupInst* GetInterpGroupInst() const { return InterpGroupInst; } }; diff --git a/Engine/Source/Runtime/Engine/Classes/Camera/CameraComponent.h b/Engine/Source/Runtime/Engine/Classes/Camera/CameraComponent.h index 87c2363df097..33d423863637 100644 --- a/Engine/Source/Runtime/Engine/Classes/Camera/CameraComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/Camera/CameraComponent.h @@ -106,6 +106,12 @@ public: #endif // End of UActorComponent interface + // USceneComponent interface +#if WITH_EDITOR + virtual bool GetEditorPreviewInfo(float DeltaTime, FMinimalViewInfo& ViewOut) override; +#endif + // End of USceneComponent interface + // UObject interface #if WITH_EDITORONLY_DATA virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; diff --git a/Engine/Source/Runtime/Engine/Classes/Camera/PlayerCameraManager.h b/Engine/Source/Runtime/Engine/Classes/Camera/PlayerCameraManager.h index 1f974f73ed0b..58054124658e 100644 --- a/Engine/Source/Runtime/Engine/Classes/Camera/PlayerCameraManager.h +++ b/Engine/Source/Runtime/Engine/Classes/Camera/PlayerCameraManager.h @@ -59,7 +59,7 @@ public: }; /** A ViewTarget is the primary actor the camera is associated with. */ -USTRUCT() +USTRUCT(BlueprintType) struct ENGINE_API FTViewTarget { GENERATED_USTRUCT_BODY() @@ -98,7 +98,7 @@ public: }; /** A set of parameters to describe how to transition between view targets. */ -USTRUCT() +USTRUCT(BlueprintType) struct FViewTargetTransitionParams { GENERATED_USTRUCT_BODY() @@ -177,9 +177,8 @@ class ENGINE_API APlayerCameraManager : public AActor UPROPERTY(transient) class APlayerController* PCOwner; -private_subobject: +private: /** Dummy component we can use to attach things to the camera. */ - DEPRECATED_FORGAME(4.6, "TransformComponent should not be accessed directly, please use GetTransformComponent() function instead. TransformComponent will soon be private and your code will not compile.") UPROPERTY(Category = PlayerCameraManager, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) class USceneComponent* TransformComponent; @@ -861,5 +860,5 @@ private: public: /** @return Returns TransformComponent subobject */ - class USceneComponent* GetTransformComponent() const; + class USceneComponent* GetTransformComponent() const { return TransformComponent; } }; diff --git a/Engine/Source/Runtime/Engine/Classes/Components/ActorComponent.h b/Engine/Source/Runtime/Engine/Classes/Components/ActorComponent.h index e4943743e83f..bed70139701a 100644 --- a/Engine/Source/Runtime/Engine/Classes/Components/ActorComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/Components/ActorComponent.h @@ -13,6 +13,7 @@ #include "UObject/ScriptMacros.h" #include "EdGraph/EdGraphPin.h" #include "Interfaces/Interface_AssetUserData.h" +#include "UObjectAnnotation.h" #include "ActorComponent.generated.h" class AActor; @@ -20,6 +21,11 @@ class UActorComponent; class UAssetUserData; class ULevel; +#if WITH_EDITOR +/** Annotation for component selection. This must be in engine isntead of editor for ::IsSelected to work */ +extern ENGINE_API FUObjectAnnotationSparseBool GSelectedComponentAnnotation; +#endif + UENUM() enum class EComponentCreationMethod : uint8 { @@ -763,6 +769,7 @@ public: virtual void PostEditChangeChainProperty( FPropertyChangedChainEvent& PropertyChangedEvent ) override; virtual void PreEditUndo() override; virtual void PostEditUndo() override; + virtual bool IsSelectedInEditor() const override; #endif // WITH_EDITOR //~ End UObject Interface. diff --git a/Engine/Source/Runtime/Engine/Classes/Components/AudioComponent.h b/Engine/Source/Runtime/Engine/Classes/Components/AudioComponent.h index 6207bc9837e5..dc4071a8917c 100644 --- a/Engine/Source/Runtime/Engine/Classes/Components/AudioComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/Components/AudioComponent.h @@ -37,7 +37,7 @@ DECLARE_MULTICAST_DELEGATE_ThreeParams(FOnAudioPlaybackPercentNative, const clas * Struct used for storing one per-instance named parameter for this AudioComponent. * Certain nodes in the SoundCue may reference parameters by name so they can be adjusted per-instance. */ -USTRUCT() +USTRUCT(BlueprintType) struct FAudioComponentParam { GENERATED_USTRUCT_BODY() @@ -174,7 +174,7 @@ class ENGINE_API UAudioComponent : public USceneComponent /** Configurable, serialized ID for audio plugins */ UPROPERTY() - uint64 AudioComponentUserID; + FName AudioComponentUserID; /** The lower bound to use when randomly determining a pitch multiplier */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Modulation) @@ -339,6 +339,14 @@ class ENGINE_API UAudioComponent : public USceneComponent UFUNCTION(BlueprintCallable, Category = "Audio|Components|Audio") void SetSubmixSend(USoundSubmix* Submix, float SendLevel); + /** Sets whether or not the low pass filter is enabled on the audio component. */ + UFUNCTION(BlueprintCallable, Category = "Audio|Components|Audio") + void SetLowPassFilterEnabled(bool InLowPassFilterEnabled); + + /** Sets lowpass filter frequency of the audio component. */ + UFUNCTION(BlueprintCallable, Category = "Audio|Components|Audio") + void SetLowPassFilterFrequency(float InLowPassFilterFrequency); + static void PlaybackCompleted(uint64 AudioComponentID, bool bFailedToStart); private: @@ -389,7 +397,7 @@ public: uint64 GetAudioComponentID() const { return AudioComponentID; } - uint64 GetAudioComponentUserID() const { return AudioComponentUserID; } + FName GetAudioComponentUserID() const { return AudioComponentUserID; } static UAudioComponent* GetAudioComponentFromID(uint64 AudioComponentID); diff --git a/Engine/Source/Runtime/Engine/Classes/Components/BoxComponent.h b/Engine/Source/Runtime/Engine/Classes/Components/BoxComponent.h index 1dc8e71367a4..9f64d80bc6a2 100644 --- a/Engine/Source/Runtime/Engine/Classes/Components/BoxComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/Components/BoxComponent.h @@ -63,7 +63,7 @@ public: FORCEINLINE FVector UBoxComponent::GetScaledBoxExtent() const { - return BoxExtent * ComponentToWorld.GetScale3D(); + return BoxExtent * GetComponentTransform().GetScale3D(); } FORCEINLINE FVector UBoxComponent::GetUnscaledBoxExtent() const diff --git a/Engine/Source/Runtime/Engine/Classes/Components/CapsuleComponent.h b/Engine/Source/Runtime/Engine/Classes/Components/CapsuleComponent.h index eb2942e64f89..20dd3f0f817a 100644 --- a/Engine/Source/Runtime/Engine/Classes/Components/CapsuleComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/Components/CapsuleComponent.h @@ -255,6 +255,6 @@ FORCEINLINE void UCapsuleComponent::GetUnscaledCapsuleSize_WithoutHemisphere(flo FORCEINLINE float UCapsuleComponent::GetShapeScale() const { - return ComponentToWorld.GetMinimumAxisScale(); + return GetComponentTransform().GetMinimumAxisScale(); } diff --git a/Engine/Source/Runtime/Engine/Classes/Components/ChildActorComponent.h b/Engine/Source/Runtime/Engine/Classes/Components/ChildActorComponent.h index 9ba8ce2637cb..d2592a0939e2 100644 --- a/Engine/Source/Runtime/Engine/Classes/Components/ChildActorComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/Components/ChildActorComponent.h @@ -71,12 +71,16 @@ private: /** Cached copy of the instance data when the ChildActor is destroyed to be available when needed */ mutable FChildActorComponentInstanceData* CachedInstanceData; + /** Flag indicating that when the component is registered that the child actor should be recreated */ + uint8 bNeedsRecreate:1; + public: //~ Begin Object Interface. #if WITH_EDITOR virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; virtual void PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent) override; + virtual void PostEditImport() override; virtual void PostEditUndo() override; virtual void PostLoad() override; #endif diff --git a/Engine/Source/Runtime/Engine/Classes/Components/DirectionalLightComponent.h b/Engine/Source/Runtime/Engine/Classes/Components/DirectionalLightComponent.h index d594e52835bd..f46f0c0d073d 100644 --- a/Engine/Source/Runtime/Engine/Classes/Components/DirectionalLightComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/Components/DirectionalLightComponent.h @@ -127,7 +127,7 @@ class ENGINE_API UDirectionalLightComponent : public ULightComponent float TraceDistance; /** The Lightmass settings for this object. */ - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Light, meta=(ShowOnlyInnerProperties)) + UPROPERTY(EditAnywhere, Category=Light, meta=(ShowOnlyInnerProperties)) struct FLightmassDirectionalLightSettings LightmassSettings; /** diff --git a/Engine/Source/Runtime/Engine/Classes/Components/ExponentialHeightFogComponent.h b/Engine/Source/Runtime/Engine/Classes/Components/ExponentialHeightFogComponent.h index e0362e73b3bb..f7d9aefc0bdd 100644 --- a/Engine/Source/Runtime/Engine/Classes/Components/ExponentialHeightFogComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/Components/ExponentialHeightFogComponent.h @@ -113,6 +113,14 @@ class ENGINE_API UExponentialHeightFogComponent : public USceneComponent UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = VolumetricFog, meta=(DisplayName = "Albedo")) FColor VolumetricFogAlbedo; + /** + * Light emitted by height fog. This is a density so more light is emitted the further you are looking through the fog. + * In most cases skylight is a better choice, however right now volumetric fog does not support precomputed lighting, + * So stationary skylights are unshadowed and static skylights don't affect volumetric fog at all. + */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = VolumetricFog, meta=(DisplayName = "Emissive")) + FLinearColor VolumetricFogEmissive; + /** Scales the height fog particle extinction amount used by volumetric fog. Values larger than 1 cause fog particles everywhere absorb more light. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = VolumetricFog, meta=(DisplayName = "Extinction Scale", UIMin = ".1", UIMax = "10")) float VolumetricFogExtinctionScale; @@ -186,6 +194,9 @@ public: UFUNCTION(BlueprintCallable, Category="Rendering|VolumetricFog") void SetVolumetricFogAlbedo(FColor NewValue); + UFUNCTION(BlueprintCallable, Category="Rendering|VolumetricFog") + void SetVolumetricFogEmissive(FLinearColor NewValue); + UFUNCTION(BlueprintCallable, Category="Rendering|VolumetricFog") void SetVolumetricFogDistance(float NewValue); diff --git a/Engine/Source/Runtime/Engine/Classes/Components/HierarchicalInstancedStaticMeshComponent.h b/Engine/Source/Runtime/Engine/Classes/Components/HierarchicalInstancedStaticMeshComponent.h index fa4cbdd9db80..c7126a604cf7 100644 --- a/Engine/Source/Runtime/Engine/Classes/Components/HierarchicalInstancedStaticMeshComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/Components/HierarchicalInstancedStaticMeshComponent.h @@ -128,9 +128,14 @@ class ENGINE_API UHierarchicalInstancedStaticMeshComponent : public UInstancedSt UPROPERTY() int32 OcclusionLayerNumNodes; + // The last mesh bounds that was cache + UPROPERTY() + FBoxSphereBounds CacheMeshExtendedBounds; + bool bIsAsyncBuilding; bool bDiscardAsyncBuildResults; bool bConcurrentRemoval; + bool bAutoRebuildTreeOnInstanceChanges; UPROPERTY() bool bDisableCollision; @@ -175,6 +180,7 @@ public: void BuildTree(); void BuildTreeAsync(); + void BuildTreeIfOutdated(bool Async, bool ForceUpdate); static void BuildTreeAnyThread( TArray& InstanceTransforms, const FBox& MeshBox, diff --git a/Engine/Source/Runtime/Engine/Classes/Components/InputComponent.h b/Engine/Source/Runtime/Engine/Classes/Components/InputComponent.h index 002dbdd807da..a167fbf1d908 100644 --- a/Engine/Source/Runtime/Engine/Classes/Components/InputComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/Components/InputComponent.h @@ -523,30 +523,6 @@ struct FInputGestureBinding : public FInputBinding }; -// ----------------------------------------------------------------- -// Helper macros to make setting up axis bindings more readable in native code. -// - -/** Creates and adds a new axis binding. */ -#define BIND_AXIS(Comp, AxisName, Delegate) \ - EMIT_DEPRECATED_WARNING_MESSAGE("BIND_AXIS macro is deprecated. Please use UInputComponent::BindAxis function instead.") \ - Comp->BindAxis(AxisName, this, Delegate) - -/** Creates and adds a new action binding. */ -#define BIND_ACTION(Comp, ActionName, KeyEvent, Delegate) \ - EMIT_DEPRECATED_WARNING_MESSAGE("BIND_ACTION macro is deprecated. Please use UInputComponent::BindAction function instead.") \ - Comp->BindAction(ActionName, KeyEvent, this, Delegate); - -/** Creates and adds a new axis binding. */ -#define BIND_AXIS_OBJ(Comp, AxisName, Delegate, DelegateObj) \ - EMIT_DEPRECATED_WARNING_MESSAGE("BIND_AXIS_OBJ macro is deprecated. Please use UInputComponent::BindAxis function instead.") \ - Comp->BindAxis(AxisName, DelegateObj, Delegate) - -/** Same as BIND_ACTION, except can be used to bind to a delegate in a specific object. */ -#define BIND_ACTION_OBJ(Comp, ActionName, KeyEvent, Delegate, DelegateObj) \ - EMIT_DEPRECATED_WARNING_MESSAGE("BIND_ACTION_OBJ macro is deprecated. Please use UInputComponent::BindAction function instead.") \ - Comp->BindAction(ActionName, KeyEvent, DelegateObj, Delegate); - UENUM() namespace EControllerAnalogStick diff --git a/Engine/Source/Runtime/Engine/Classes/Components/InterpToMovementComponent.h b/Engine/Source/Runtime/Engine/Classes/Components/InterpToMovementComponent.h index de689c56380c..24584e7278d0 100644 --- a/Engine/Source/Runtime/Engine/Classes/Components/InterpToMovementComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/Components/InterpToMovementComponent.h @@ -23,7 +23,7 @@ enum class EInterpToBehaviourType : uint8 PingPong }; -USTRUCT() +USTRUCT(BlueprintType) struct FInterpControlPoint { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/Components/PointLightComponent.h b/Engine/Source/Runtime/Engine/Classes/Components/PointLightComponent.h index 21edeb747d8c..040fcb441a57 100644 --- a/Engine/Source/Runtime/Engine/Classes/Components/PointLightComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/Components/PointLightComponent.h @@ -61,7 +61,7 @@ class ENGINE_API UPointLightComponent : public ULightComponent float SourceLength; /** The Lightmass settings for this object. */ - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Light, meta=(ShowOnlyInnerProperties)) + UPROPERTY(EditAnywhere, Category=Light, meta=(ShowOnlyInnerProperties)) struct FLightmassPointLightSettings LightmassSettings; UFUNCTION(BlueprintCallable, Category="Rendering|Lighting") diff --git a/Engine/Source/Runtime/Engine/Classes/Components/PrimitiveComponent.h b/Engine/Source/Runtime/Engine/Classes/Components/PrimitiveComponent.h index 589eb9f73700..67e0075cbc39 100644 --- a/Engine/Source/Runtime/Engine/Classes/Components/PrimitiveComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/Components/PrimitiveComponent.h @@ -736,7 +736,6 @@ public: void GetOverlappingComponents(TArray& InOverlappingComponents) const; /** Returns list of components this component is overlapping. */ - UFUNCTION(BlueprintCallable, Category="Collision", meta=(UnsafeDuringActorConstruction="true")) const TArray& GetOverlapInfos() const; /** @@ -1150,6 +1149,10 @@ public: UFUNCTION(BlueprintCallable, Category="Rendering") void SetCastShadow(bool NewCastShadow); + /** Changes the value of bSingleSampleShadowFromStationaryLights. */ + UFUNCTION(BlueprintCallable, Category="Rendering") + void SetSingleSampleShadowFromStationaryLights(bool bNewSingleSampleShadowFromStationaryLights); + /** Changes the value of TranslucentSortPriority. */ UFUNCTION(BlueprintCallable, Category="Rendering") void SetTranslucentSortPriority(int32 NewTranslucentSortPriority); @@ -1591,7 +1594,7 @@ protected: * accelerate simulation * * @param : UseBI - root body instsance - * @return : New ComponentToWorld to use + * @return : New GetComponentTransform() to use */ virtual FTransform GetComponentTransformFromBodyInstance(FBodyInstance* UseBI); public: diff --git a/Engine/Source/Runtime/Engine/Classes/Components/ReflectionCaptureComponent.h b/Engine/Source/Runtime/Engine/Classes/Components/ReflectionCaptureComponent.h index 5bc269103340..e27576fafec3 100644 --- a/Engine/Source/Runtime/Engine/Classes/Components/ReflectionCaptureComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/Components/ReflectionCaptureComponent.h @@ -245,9 +245,6 @@ class UReflectionCaptureComponent : public USceneComponent virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; virtual void PostEditImport() override; virtual void PreFeatureLevelChange(ERHIFeatureLevel::Type PendingFeatureLevel) override; - - // Test if editor needs to update mobile's reflection captures. - ENGINE_API static bool MobileReflectionCapturesNeedForcedUpdate(UWorld* WorldToUpdate); #endif // WITH_EDITOR virtual void BeginDestroy() override; virtual bool IsReadyForFinishDestroy() override; diff --git a/Engine/Source/Runtime/Engine/Classes/Components/SceneCaptureComponent.h b/Engine/Source/Runtime/Engine/Classes/Components/SceneCaptureComponent.h index 015f5b8149b2..46880bc75a78 100644 --- a/Engine/Source/Runtime/Engine/Classes/Components/SceneCaptureComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/Components/SceneCaptureComponent.h @@ -25,7 +25,7 @@ struct FSceneCaptureViewInfo EStereoscopicPass StereoPass; }; -USTRUCT() +USTRUCT(BlueprintType) struct FEngineShowFlagsSetting { GENERATED_USTRUCT_BODY() @@ -80,7 +80,7 @@ class ENGINE_API USceneCaptureComponent : public USceneComponent int32 CaptureSortPriority; /** ShowFlags for the SceneCapture's ViewFamily, to control rendering settings for this view. Hidden but accessible through details customization */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, interp, Category=SceneComponent) + UPROPERTY(EditAnywhere, interp, Category=SceneComponent) TArray ShowFlagSettings; // TODO: Make this a UStruct to set directly? diff --git a/Engine/Source/Runtime/Engine/Classes/Components/SceneCaptureComponent2D.h b/Engine/Source/Runtime/Engine/Classes/Components/SceneCaptureComponent2D.h index b068be1c7439..7aa0566cad4f 100644 --- a/Engine/Source/Runtime/Engine/Classes/Components/SceneCaptureComponent2D.h +++ b/Engine/Source/Runtime/Engine/Classes/Components/SceneCaptureComponent2D.h @@ -24,7 +24,7 @@ class ENGINE_API USceneCaptureComponent2D : public USceneCaptureComponent TEnumAsByte ProjectionType; /** Camera field of view (in degrees). */ - UPROPERTY(interp, Category=Projection, meta=(DisplayName = "Field of View", UIMin = "5.0", UIMax = "170", ClampMin = "0.001", ClampMax = "360.0")) + UPROPERTY(interp, EditAnywhere, BlueprintReadWrite, Category=Projection, meta=(DisplayName = "Field of View", UIMin = "5.0", UIMax = "170", ClampMin = "0.001", ClampMax = "360.0")) float FOVAngle; /** The desired width (in world units) of the orthographic view (ignored in Perspective mode) */ diff --git a/Engine/Source/Runtime/Engine/Classes/Components/SceneComponent.h b/Engine/Source/Runtime/Engine/Classes/Components/SceneComponent.h index 2960c9b7ab85..75a4155b111a 100644 --- a/Engine/Source/Runtime/Engine/Classes/Components/SceneComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/Components/SceneComponent.h @@ -16,13 +16,11 @@ class AActor; class APhysicsVolume; class USceneComponent; struct FLevelCollection; +struct FMinimalViewInfo; /** Overlap info consisting of the primitive and the body that is overlapping */ -USTRUCT() struct ENGINE_API FOverlapInfo { - GENERATED_USTRUCT_BODY() - FOverlapInfo() {} @@ -135,18 +133,11 @@ private: UPROPERTY(ReplicatedUsing = OnRep_AttachSocketName) FName AttachSocketName; -public: - DEPRECATED(4.11, "SceneComponent no longer supports custom locations.") - uint32 bRequiresCustomLocation:1; - -protected: - /** True if we have ever updated ComponentToWorld based on RelativeLocation/Rotation/Scale. Used at startup to make sure it is initialized. */ UPROPERTY(Transient) uint32 bWorldToComponentUpdated : 1; public: - /** If RelativeLocation should be considered relative to the world, rather than the parent */ UPROPERTY(EditAnywhere, AdvancedDisplay, BlueprintReadWrite, ReplicatedUsing=OnRep_Transform, Category=Transform) uint32 bAbsoluteLocation:1; @@ -210,10 +201,11 @@ public: FBoxSphereBounds Bounds; /** Current transform of the component, relative to the world */ + DEPRECATED_FORGAME(4.17, "ComponentToWorld will be made private, use GetComponentTransform() instead.") FTransform ComponentToWorld; private: - /** Cache that avoids Quat<->Rotator conversions if possible. Only to be used with ComponentToWorld.GetRotation(). */ + /** Cache that avoids Quat<->Rotator conversions if possible. Only to be used with GetComponentTransform().GetRotation(). */ FRotationConversionCache WorldRotationCache; public: @@ -622,6 +614,7 @@ public: * @param bWeldSimulatedBodies Whether to weld together simulated physics bodies. * @return True if attachment is successful (or already attached to requested parent/socket), false if attachment is rejected and there is no change in AttachParent. */ + DEPRECATED(4.17, "This function is deprecated, please use AttachToComponent instead.") UFUNCTION(BlueprintCallable, Category = "Utilities|Transformation", meta = (DisplayName = "AttachTo (Deprecated)", AttachType = "KeepRelativeOffset")) bool K2_AttachTo(USceneComponent* InParent, FName InSocketName = NAME_None, EAttachLocation::Type AttachType = EAttachLocation::KeepRelativeOffset, bool bWeldSimulatedBodies = true); @@ -649,7 +642,8 @@ public: bool K2_AttachToComponent(USceneComponent* Parent, FName SocketName, EAttachmentRule LocationRule, EAttachmentRule RotationRule, EAttachmentRule ScaleRule, bool bWeldSimulatedBodies); /** Zeroes out the relative transform of the component, and calls AttachTo(). Useful for attaching directly to a scene component or socket location */ - UFUNCTION(BlueprintCallable, meta=(DeprecatedFunction, DeprecationMessage = "Use AttachToComponent instead"), Category="Utilities|Transformation") + DEPRECATED(4.17, "Use AttachToComponent instead.") + UFUNCTION(BlueprintCallable, meta=(DeprecatedFunction, DeprecationMessage = "Use AttachToComponent instead."), Category="Utilities|Transformation") bool SnapTo(USceneComponent* InParent, FName InSocketName = NAME_None); /** @@ -755,10 +749,15 @@ protected: */ virtual void OnVisibilityChanged(); + /** + * Overridable internal function to respond to changes in the hidden in game value of the component. + */ + virtual void OnHiddenInGameChanged(); + private: /** - * Enum that dictates what propagation policy to follow when calling SetVisibility recursively + * Enum that dictates what propagation policy to follow when calling SetVisibility or SetHiddenInGame recursively */ enum class EVisibilityPropagation : uint8 { @@ -768,7 +767,7 @@ private: // If the visibility changed, mark all attached component's render states as dirty DirtyOnly, - // Call SetVisibility recursively on attached components and also mark their render state as dirty + // Call function recursively on attached components and also mark their render state as dirty Propagate }; @@ -777,6 +776,11 @@ private: */ void SetVisibility(bool bNewVisibility, EVisibilityPropagation PropagateToChildren); + /** + * Internal function to set hidden in game for the component. Enum controls propagation rules. + */ + void SetHiddenInGame(bool bNewHiddenInGame, EVisibilityPropagation PropagateToChildren); + public: /** @@ -802,7 +806,10 @@ public: * @param NewHidden - The value to assign to HiddenGame. */ UFUNCTION(BlueprintCallable, Category="Development") - virtual void SetHiddenInGame(bool NewHidden, bool bPropagateToChildren=false); + void SetHiddenInGame(bool NewHidden, bool bPropagateToChildren=false) + { + SetHiddenInGame(NewHidden, bPropagateToChildren ? EVisibilityPropagation::Propagate : EVisibilityPropagation::DirtyOnly); + } public: /** Delegate that will be called when PhysicsVolume has been changed **/ @@ -935,44 +942,53 @@ public: /** Return location of the component, in world space */ FORCEINLINE FVector GetComponentLocation() const { - return ComponentToWorld.GetLocation(); - } - - DEPRECATED(4.11, "Custom locations on SceneComponent are now deprecated.") - virtual FVector GetCustomLocation() const - { - check(0); - return ComponentToWorld.GetLocation(); + return GetComponentTransform().GetLocation(); } /** Return rotation of the component, in world space */ FORCEINLINE FRotator GetComponentRotation() const { - return WorldRotationCache.NormalizedQuatToRotator(ComponentToWorld.GetRotation()); + return WorldRotationCache.NormalizedQuatToRotator(GetComponentTransform().GetRotation()); } /** Return rotation quaternion of the component, in world space */ FORCEINLINE FQuat GetComponentQuat() const { - return ComponentToWorld.GetRotation(); + return GetComponentTransform().GetRotation(); } /** Return scale of the component, in world space */ FORCEINLINE FVector GetComponentScale() const { - return ComponentToWorld.GetScale3D(); + return GetComponentTransform().GetScale3D(); } - /** Get the current component-to-world transform for this component */ - FORCEINLINE FTransform GetComponentToWorld() const - { - return ComponentToWorld; // TODO: probably deprecate this in favor of GetComponentTransform - } - - /** Get the current component-to-world transform for this component */ - FORCEINLINE FTransform GetComponentTransform() const + /** Sets the cached component to world directly. This should be used very rarely. */ + FORCEINLINE void SetComponentToWorld(const FTransform& NewComponentToWorld) { + bWorldToComponentUpdated = true; + PRAGMA_DISABLE_DEPRECATION_WARNINGS + ComponentToWorld = NewComponentToWorld; + PRAGMA_ENABLE_DEPRECATION_WARNINGS + } + + /** + * Get the current component-to-world transform for this component + * TODO: probably deprecate this in favor of GetComponentTransform + */ + FORCEINLINE const FTransform& GetComponentToWorld() const + { + PRAGMA_DISABLE_DEPRECATION_WARNINGS return ComponentToWorld; + PRAGMA_ENABLE_DEPRECATION_WARNINGS + } + + /** Get the current component-to-world transform for this component */ + FORCEINLINE const FTransform& GetComponentTransform() const + { + PRAGMA_DISABLE_DEPRECATION_WARNINGS + return ComponentToWorld; + PRAGMA_ENABLE_DEPRECATION_WARNINGS } /** Update transforms of any components attached to this one. */ @@ -1045,6 +1061,13 @@ public: virtual const int32 GetNumUncachedStaticLightingInteractions() const; virtual void PreFeatureLevelChange(ERHIFeatureLevel::Type PendingFeatureLevel) {} + + /** + * Supplies the editor with a view specific to this component (think a view + * from a camera components POV, etc.). Used for PIP preview windows. + * @return True if the component overrides this, and fills out the view info output. + */ + virtual bool GetEditorPreviewInfo(float DeltaTime, FMinimalViewInfo& ViewOut) { return false; } #endif // WITH_EDITOR protected: diff --git a/Engine/Source/Runtime/Engine/Classes/Components/SkeletalMeshComponent.h b/Engine/Source/Runtime/Engine/Classes/Components/SkeletalMeshComponent.h index 3dad73a1e5cb..e8de322a43cb 100644 --- a/Engine/Source/Runtime/Engine/Classes/Components/SkeletalMeshComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/Components/SkeletalMeshComponent.h @@ -73,9 +73,6 @@ struct FAnimationEvaluationContext // Are we evaluating this tick bool bDoEvaluation; - // Are we updating the anim instance this tick - bool bDoUpdate; - // Are we storing data in cache bones this tick bool bDuplicateToCacheBones; @@ -99,7 +96,6 @@ struct FAnimationEvaluationContext Curve.CopyFrom(Other.Curve); bDoInterpolation = Other.bDoInterpolation; bDoEvaluation = Other.bDoEvaluation; - bDoUpdate = Other.bDoUpdate; bDuplicateToCacheBones = Other.bDuplicateToCacheBones; bDuplicateToCacheCurve = Other.bDuplicateToCacheCurve; } @@ -288,7 +284,7 @@ public: class TSubclassOf AnimClass; /** The active animation graph program instance. */ - UPROPERTY(transient) + UPROPERTY(transient, NonTransactional) UAnimInstance* AnimScriptInstance; /** Any running sub anim instances that need to be updates on the game thread */ @@ -310,6 +306,9 @@ public: /** Temporary storage for curves */ FBlendedHeapCurve AnimCurves; + /** Temporary fix for local space kinematics. This only works for bodies that have no constraints and is needed by vehicles. Proper support will remove this flag */ + bool bLocalSpaceKinematics; + // Update Rate /** Cached BoneSpaceTransforms for Update Rate optimization. */ @@ -429,6 +428,10 @@ public: * Optimization */ + /** Whether animation and world transform updates are deferred. If this is on, the kinematic bodies (scene query data) will not update until the next time the physics simulation is run */ + UPROPERTY(EditAnywhere, AdvancedDisplay, BlueprintReadOnly, Category = SkeletalMesh) + uint32 bDeferMovementFromSceneQueries : 1; + /** Skips Ticking and Bone Refresh. */ UPROPERTY(EditAnywhere, AdvancedDisplay, BlueprintReadWrite, Category=SkeletalMesh) uint32 bNoSkeletonUpdate:1; @@ -733,6 +736,17 @@ public: UFUNCTION(BlueprintCallable, Category = "Components|SkeletalMesh", meta = (DevelopmentOnly, UnsafeDuringActorConstruction = "true")) void SetUpdateAnimationInEditor(const bool NewUpdateState); +#if WITH_EDITOR + /** + * return true if currently updating in editor is true + * this is non BP because this is only used for slave component to detect master component ticking state + */ + bool GetUpdateAnimationInEditor() const + { + return bUpdateAnimationInEditor; + } +#endif + /** We detach the Component once we are done playing it. * * @param ParticleSystemComponent that finished @@ -1713,4 +1727,16 @@ private: * Cooking does not guarantee skeleton containing all names */ bool AreRequiredCurvesUpToDate() const; + +public: + void ConditionallyDispatchQueuedAnimEvents(); + + // Are we currently within PostAnimEvaluation + bool IsPostEvaluatingAnimation() const { return bPostEvaluatingAnimation; } + +private: + UPROPERTY(Transient) + bool bNeedsQueuedAnimEventsDispatched; + + bool bPostEvaluatingAnimation; }; diff --git a/Engine/Source/Runtime/Engine/Classes/Components/SkinnedMeshComponent.h b/Engine/Source/Runtime/Engine/Classes/Components/SkinnedMeshComponent.h index f977040b4d01..14b1372d97e6 100644 --- a/Engine/Source/Runtime/Engine/Classes/Components/SkinnedMeshComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/Components/SkinnedMeshComponent.h @@ -130,7 +130,7 @@ struct FSkelMeshSkinWeightInfo /** LOD specific setup for the skeletal mesh component. */ USTRUCT() -struct FSkelMeshComponentLODInfo +struct ENGINE_API FSkelMeshComponentLODInfo { GENERATED_USTRUCT_BODY() @@ -771,6 +771,8 @@ public: DEPRECATED(4.13, "SetSpaceBaseDoubleBuffering is now renamed SetComponentSpaceTransformsDoubleBuffering") void SetSpaceBaseDoubleBuffering(bool bInDoubleBufferedBlendSpaces) { SetComponentSpaceTransformsDoubleBuffering(bInDoubleBufferedBlendSpaces); } + const FBoxSphereBounds& GetCachedLocalBounds() { return CachedLocalBounds; } + protected: /** Flip the editable space base buffer */ diff --git a/Engine/Source/Runtime/Engine/Classes/Components/SkyLightComponent.h b/Engine/Source/Runtime/Engine/Classes/Components/SkyLightComponent.h index 46f4cf506459..540e6ac97109 100644 --- a/Engine/Source/Runtime/Engine/Classes/Components/SkyLightComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/Components/SkyLightComponent.h @@ -181,9 +181,6 @@ class ENGINE_API USkyLightComponent : public ULightComponentBase virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; virtual bool CanEditChange(const UProperty* InProperty) const override; virtual void CheckForErrors() override; - - // Test if editor needs to update mobile's reflection captures. - static bool MobileSkyCapturesNeedForcedUpdate(UWorld* WorldToUpdate); #endif // WITH_EDITOR virtual void BeginDestroy() override; virtual bool IsReadyForFinishDestroy() override; @@ -290,10 +287,6 @@ protected: FSkyLightSceneProxy* SceneProxy; - /** Indicate that the sky capture update was required from load, - used to trigger updates that have been delayed by shader compilation. */ - bool bSkyCaptureRequiredFromLoad; - /** * List of sky captures that need to be recaptured. * These have to be queued because we can only render the scene to update captures at certain points, after the level has loaded. diff --git a/Engine/Source/Runtime/Engine/Classes/Components/SphereComponent.h b/Engine/Source/Runtime/Engine/Classes/Components/SphereComponent.h index 03647b43aa2d..4112de30e58a 100644 --- a/Engine/Source/Runtime/Engine/Classes/Components/SphereComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/Components/SphereComponent.h @@ -80,5 +80,5 @@ FORCEINLINE float USphereComponent::GetUnscaledSphereRadius() const FORCEINLINE float USphereComponent::GetShapeScale() const { - return ComponentToWorld.GetMinimumAxisScale(); + return GetComponentTransform().GetMinimumAxisScale(); } diff --git a/Engine/Source/Runtime/Engine/Classes/Components/SplineMeshComponent.h b/Engine/Source/Runtime/Engine/Classes/Components/SplineMeshComponent.h index c9a91b5aeb24..ac7dca6d4cb9 100644 --- a/Engine/Source/Runtime/Engine/Classes/Components/SplineMeshComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/Components/SplineMeshComponent.h @@ -324,10 +324,8 @@ public: // Destroys the body setup, used to clear collision if the mesh goes missing void DestroyBodySetup(); -#if WITH_EDITOR || WITH_RUNTIME_PHYSICS_COOKING // Builds collision for the spline mesh (if collision is enabled) void RecreateCollision(); -#endif /** * Calculates the spline transform, including roll, scale, and offset along the spline at a specified distance diff --git a/Engine/Source/Runtime/Engine/Classes/Components/StaticMeshComponent.h b/Engine/Source/Runtime/Engine/Classes/Components/StaticMeshComponent.h index 8614116329d8..c2a5b3964b44 100644 --- a/Engine/Source/Runtime/Engine/Classes/Components/StaticMeshComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/Components/StaticMeshComponent.h @@ -313,7 +313,7 @@ class ENGINE_API UStaticMeshComponent : public UMeshComponent #endif /** The Lightmass settings for this object. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Lighting) + UPROPERTY(EditAnywhere, Category=Lighting) struct FLightmassPrimitiveSettings LightmassSettings; virtual ~UStaticMeshComponent(); diff --git a/Engine/Source/Runtime/Engine/Classes/Curves/CurveFloat.h b/Engine/Source/Runtime/Engine/Classes/Curves/CurveFloat.h index 3c425489f246..4c5d951514b5 100644 --- a/Engine/Source/Runtime/Engine/Classes/Curves/CurveFloat.h +++ b/Engine/Source/Runtime/Engine/Classes/Curves/CurveFloat.h @@ -8,7 +8,7 @@ #include "Curves/CurveBase.h" #include "CurveFloat.generated.h" -USTRUCT() +USTRUCT(BlueprintType) struct ENGINE_API FRuntimeFloatCurve { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/DeviceProfiles/DeviceProfile.h b/Engine/Source/Runtime/Engine/Classes/DeviceProfiles/DeviceProfile.h index 9af53b1275dc..2e20df50766c 100644 --- a/Engine/Source/Runtime/Engine/Classes/DeviceProfiles/DeviceProfile.h +++ b/Engine/Source/Runtime/Engine/Classes/DeviceProfiles/DeviceProfile.h @@ -72,12 +72,19 @@ public: */ UTextureLODSettings* GetTextureLODSettings() const; + bool ModifyCVarValue(const FString& CVarName, const FString& CVarValue, bool bAddIfNonExistant = false); + FString GetCVarValue(const FString& CVarName); private: - + // Make sure our TextureLODGroups array is sorted correctly and complete + void ValidateTextureLODGroups(); /** Delegate object fired when there has been any changes to the console variables */ FOnCVarsUpdated CVarsUpdatedDelegate; public: + /* ValidateProfile() + * Validate the Profile after changes by loading it's config (.ini) + */ + void ValidateProfile(); //~ Begin UObject Interface virtual void PostInitProperties() override; diff --git a/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionFloat.h b/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionFloat.h index 025fef1c7c29..cdd1197113c1 100644 --- a/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionFloat.h +++ b/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionFloat.h @@ -24,7 +24,7 @@ struct FFloatDistribution #endif USTRUCT() -struct FRawDistributionFloat : public FRawDistribution +struct ENGINE_API FRawDistributionFloat : public FRawDistribution { GENERATED_USTRUCT_BODY() @@ -54,7 +54,7 @@ public: /**` * Initialize a raw distribution from the original Unreal distribution */ - ENGINE_API void Initialize(); + void Initialize(); #endif /** @@ -65,7 +65,7 @@ public: /** * Get the value at the specified F */ - ENGINE_API float GetValue(float F=0.0f, UObject* Data=NULL, struct FRandomStream* InRandomStream = NULL); + float GetValue(float F=0.0f, UObject* Data=NULL, struct FRandomStream* InRandomStream = NULL); /** * Get the min and max values @@ -98,8 +98,8 @@ public: } }; -UCLASS(abstract, customconstructor,MinimalAPI) -class UDistributionFloat : public UDistribution +UCLASS(abstract, customconstructor) +class ENGINE_API UDistributionFloat : public UDistribution { GENERATED_UCLASS_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionFloatConstant.h b/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionFloatConstant.h index 644fbbfc4872..eca60104381c 100644 --- a/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionFloatConstant.h +++ b/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionFloatConstant.h @@ -8,8 +8,8 @@ #include "Distributions/DistributionFloat.h" #include "DistributionFloatConstant.generated.h" -UCLASS(collapsecategories, hidecategories=Object, editinlinenew,MinimalAPI) -class UDistributionFloatConstant : public UDistributionFloat +UCLASS(collapsecategories, hidecategories=Object, editinlinenew) +class ENGINE_API UDistributionFloatConstant : public UDistributionFloat { GENERATED_UCLASS_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionFloatConstantCurve.h b/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionFloatConstantCurve.h index 7daa0c1d285e..afb0d47dd14a 100644 --- a/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionFloatConstantCurve.h +++ b/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionFloatConstantCurve.h @@ -8,8 +8,8 @@ #include "Distributions/DistributionFloat.h" #include "DistributionFloatConstantCurve.generated.h" -UCLASS(collapsecategories, hidecategories=Object, editinlinenew,MinimalAPI) -class UDistributionFloatConstantCurve : public UDistributionFloat +UCLASS(collapsecategories, hidecategories=Object, editinlinenew) +class ENGINE_API UDistributionFloatConstantCurve : public UDistributionFloat { GENERATED_UCLASS_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionFloatParameterBase.h b/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionFloatParameterBase.h index 5c71da91eaca..748b882d00d3 100644 --- a/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionFloatParameterBase.h +++ b/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionFloatParameterBase.h @@ -9,7 +9,7 @@ #include "DistributionFloatParameterBase.generated.h" UCLASS(abstract, collapsecategories, hidecategories=Object, editinlinenew) -class UDistributionFloatParameterBase : public UDistributionFloatConstant +class ENGINE_API UDistributionFloatParameterBase : public UDistributionFloatConstant { GENERATED_UCLASS_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionFloatParticleParameter.h b/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionFloatParticleParameter.h index 22c9e050cb3d..5d5049d30e93 100644 --- a/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionFloatParticleParameter.h +++ b/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionFloatParticleParameter.h @@ -8,8 +8,8 @@ #include "Distributions/DistributionFloatParameterBase.h" #include "DistributionFloatParticleParameter.generated.h" -UCLASS(collapsecategories, hidecategories=Object, editinlinenew, MinimalAPI) -class UDistributionFloatParticleParameter : public UDistributionFloatParameterBase +UCLASS(collapsecategories, hidecategories=Object, editinlinenew) +class ENGINE_API UDistributionFloatParticleParameter : public UDistributionFloatParameterBase { GENERATED_UCLASS_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionFloatUniform.h b/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionFloatUniform.h index 833569ab31ed..90e6697bcb82 100644 --- a/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionFloatUniform.h +++ b/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionFloatUniform.h @@ -8,8 +8,8 @@ #include "Distributions/DistributionFloat.h" #include "DistributionFloatUniform.generated.h" -UCLASS(collapsecategories, hidecategories=Object, editinlinenew, MinimalAPI) -class UDistributionFloatUniform : public UDistributionFloat +UCLASS(collapsecategories, hidecategories=Object, editinlinenew) +class ENGINE_API UDistributionFloatUniform : public UDistributionFloat { GENERATED_UCLASS_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionFloatUniformCurve.h b/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionFloatUniformCurve.h index 91adc29ec175..bce86dacde4f 100644 --- a/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionFloatUniformCurve.h +++ b/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionFloatUniformCurve.h @@ -8,8 +8,8 @@ #include "Distributions/DistributionFloat.h" #include "DistributionFloatUniformCurve.generated.h" -UCLASS(collapsecategories, hidecategories=Object, editinlinenew, MinimalAPI) -class UDistributionFloatUniformCurve : public UDistributionFloat +UCLASS(collapsecategories, hidecategories=Object, editinlinenew) +class ENGINE_API UDistributionFloatUniformCurve : public UDistributionFloat { GENERATED_UCLASS_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionVector.h b/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionVector.h index a51a08ebeaf1..64f7e0dd71b3 100644 --- a/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionVector.h +++ b/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionVector.h @@ -55,7 +55,7 @@ struct FVector4Distribution #endif USTRUCT() -struct FRawDistributionVector : public FRawDistribution +struct ENGINE_API FRawDistributionVector : public FRawDistribution { GENERATED_USTRUCT_BODY() @@ -93,7 +93,7 @@ public: /** * Initialize a raw distribution from the original Unreal distribution */ - ENGINE_API void Initialize(); + void Initialize(); #endif /** @@ -104,7 +104,7 @@ public: /** * Get the value at the specified F */ - ENGINE_API FVector GetValue(float F=0.0f, UObject* Data=NULL, int32 LastExtreme=0, struct FRandomStream* InRandomStream = NULL); + FVector GetValue(float F=0.0f, UObject* Data=NULL, int32 LastExtreme=0, struct FRandomStream* InRandomStream = NULL); /** * Get the min and max values diff --git a/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionVectorConstantCurve.h b/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionVectorConstantCurve.h index a15d537d2e08..a1476910ebba 100644 --- a/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionVectorConstantCurve.h +++ b/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionVectorConstantCurve.h @@ -8,8 +8,8 @@ #include "Distributions/DistributionVector.h" #include "DistributionVectorConstantCurve.generated.h" -UCLASS(collapsecategories, hidecategories=Object, editinlinenew,MinimalAPI) -class UDistributionVectorConstantCurve : public UDistributionVector +UCLASS(collapsecategories, hidecategories=Object, editinlinenew) +class ENGINE_API UDistributionVectorConstantCurve : public UDistributionVector { GENERATED_UCLASS_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionVectorParameterBase.h b/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionVectorParameterBase.h index 5f37c3c77315..b38c6cccba0a 100644 --- a/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionVectorParameterBase.h +++ b/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionVectorParameterBase.h @@ -9,7 +9,7 @@ #include "DistributionVectorParameterBase.generated.h" UCLASS(abstract, collapsecategories, hidecategories=Object, editinlinenew) -class UDistributionVectorParameterBase : public UDistributionVectorConstant +class ENGINE_API UDistributionVectorParameterBase : public UDistributionVectorConstant { GENERATED_UCLASS_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionVectorParticleParameter.h b/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionVectorParticleParameter.h index 7bee9ab53a1f..c6da009d40b7 100644 --- a/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionVectorParticleParameter.h +++ b/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionVectorParticleParameter.h @@ -8,8 +8,8 @@ #include "Distributions/DistributionVectorParameterBase.h" #include "DistributionVectorParticleParameter.generated.h" -UCLASS(collapsecategories, hidecategories=Object, editinlinenew, MinimalAPI) -class UDistributionVectorParticleParameter : public UDistributionVectorParameterBase +UCLASS(collapsecategories, hidecategories=Object, editinlinenew) +class ENGINE_API UDistributionVectorParticleParameter : public UDistributionVectorParameterBase { GENERATED_UCLASS_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionVectorUniform.h b/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionVectorUniform.h index 3a0f7c166fb1..34e1e4edf50f 100644 --- a/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionVectorUniform.h +++ b/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionVectorUniform.h @@ -8,8 +8,8 @@ #include "Distributions/DistributionVector.h" #include "DistributionVectorUniform.generated.h" -UCLASS(collapsecategories, hidecategories=Object, editinlinenew, MinimalAPI) -class UDistributionVectorUniform : public UDistributionVector +UCLASS(collapsecategories, hidecategories=Object, editinlinenew) +class ENGINE_API UDistributionVectorUniform : public UDistributionVector { GENERATED_UCLASS_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionVectorUniformCurve.h b/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionVectorUniformCurve.h index 06b3b9c3902b..7cecbb60bdd5 100644 --- a/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionVectorUniformCurve.h +++ b/Engine/Source/Runtime/Engine/Classes/Distributions/DistributionVectorUniformCurve.h @@ -8,8 +8,8 @@ #include "Distributions/DistributionVector.h" #include "DistributionVectorUniformCurve.generated.h" -UCLASS(collapsecategories, hidecategories=Object, editinlinenew, MinimalAPI) -class UDistributionVectorUniformCurve : public UDistributionVector +UCLASS(collapsecategories, hidecategories=Object, editinlinenew) +class ENGINE_API UDistributionVectorUniformCurve : public UDistributionVector { GENERATED_UCLASS_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/EdGraph/EdGraph.h b/Engine/Source/Runtime/Engine/Classes/EdGraph/EdGraph.h index 3702840ccf67..c86afd160803 100644 --- a/Engine/Source/Runtime/Engine/Classes/EdGraph/EdGraph.h +++ b/Engine/Source/Runtime/Engine/Classes/EdGraph/EdGraph.h @@ -136,9 +136,18 @@ public: * a FGraphNodeCreator builder. */ template + DEPRECATED(4.17, "Use CreateIntermediateNode instead.") NodeClass* CreateBlankNode() { - return (NodeClass*)CreateNode(NodeClass::StaticClass()); + return CreateIntermediateNode(); + } + + template + NodeClass* CreateIntermediateNode() + { + NodeClass* Node = (NodeClass*)CreateNode(NodeClass::StaticClass()); + FSetAsIntermediateNode SetAsIntermediate(Node); + return Node; } /** diff --git a/Engine/Source/Runtime/Engine/Classes/EdGraph/EdGraphNode.h b/Engine/Source/Runtime/Engine/Classes/EdGraph/EdGraphNode.h index ea2b6fd3e9f8..b2022a1ac46f 100644 --- a/Engine/Source/Runtime/Engine/Classes/EdGraph/EdGraphNode.h +++ b/Engine/Source/Runtime/Engine/Classes/EdGraph/EdGraphNode.h @@ -20,6 +20,8 @@ class UEdGraphSchema; struct FEdGraphPinType; struct FPropertyChangedEvent; struct FSlateIcon; +struct FDiffResults; +struct FDiffSingleResult; /** * Struct used to define information for terminal types, e.g. types that can be contained @@ -73,6 +75,16 @@ enum EEdGraphPinDirection EGPD_MAX, }; +/** Enum used to define what container type a pin represents. */ +UENUM() +enum class EPinContainerType : uint8 +{ + None, + Array, + Set, + Map +}; + /** Enum to indicate what sort of title we want. */ UENUM() namespace ENodeTitleType @@ -174,20 +186,61 @@ class ENGINE_API UEdGraphNode : public UObject UPROPERTY() int32 NodeHeight; + /** Enum to indicate if a node has advanced-display-pins, and if they are shown */ + UPROPERTY() + TEnumAsByte AdvancedPinDisplay; + + /** Indicates in what state the node is enabled, which may eliminate it from being compiled */ + UPROPERTY() + ENodeEnabledState EnabledState; + + /** Indicates whether or not the user explicitly set the enabled state */ + UPROPERTY() + uint8 bUserSetEnabledState:1; + +protected: + /** (DEPRECATED) Value used for AllowSplitPins(). Do not override. */ + uint8 bAllowSplitPins_DEPRECATED:1; + +private: + /** (DEPRECATED) FALSE if the node is a disabled, which eliminates it from being compiled */ + UPROPERTY() + uint8 bIsNodeEnabled_DEPRECATED:1; + +public: + #if WITH_EDITORONLY_DATA /** If true, this node can be resized and should be drawn with a resize handle */ UPROPERTY() - uint32 bCanResizeNode:1; + uint8 bCanResizeNode:1; + #endif // WITH_EDITORONLY_DATA +private: + /** Whether the node was created as part of an expansion step */ + uint8 bIsIntermediateNode : 1; + +public: /** Flag to check for compile error/warning */ UPROPERTY() - uint32 bHasCompilerMessage:1; + uint8 bHasCompilerMessage:1; + + /** Comment bubble pinned state */ + UPROPERTY() + uint8 bCommentBubblePinned:1; + + /** Comment bubble visibility */ + UPROPERTY() + uint8 bCommentBubbleVisible:1; + + /** Make comment bubble visible */ + UPROPERTY(Transient) + uint8 bCommentBubbleMakeVisible:1; #if WITH_EDITORONLY_DATA /** If true, this node can be renamed in the editor */ UPROPERTY() - uint32 bCanRenameNode:1; + uint8 bCanRenameNode:1; /** Note for a node that lingers until saved */ UPROPERTY(Transient) @@ -198,18 +251,6 @@ class ENGINE_API UEdGraphNode : public UObject UPROPERTY() FString NodeComment; - /** Comment bubble pinned state */ - UPROPERTY() - bool bCommentBubblePinned; - - /** Comment bubble visibility */ - UPROPERTY() - bool bCommentBubbleVisible; - - /** Make comment bubble visible */ - UPROPERTY(Transient) - bool bCommentBubbleMakeVisible; - /** Flag to store node specific compile error/warning*/ UPROPERTY() int32 ErrorType; @@ -222,23 +263,6 @@ class ENGINE_API UEdGraphNode : public UObject UPROPERTY() FGuid NodeGuid; - /** Enum to indicate if a node has advanced-display-pins, and if they are shown */ - UPROPERTY() - TEnumAsByte AdvancedPinDisplay; - - /** Indicates in what state the node is enabled, which may eliminate it from being compiled */ - UPROPERTY() - ENodeEnabledState EnabledState; - - /** Indicates whether or not the user explicitly set the enabled state */ - UPROPERTY() - bool bUserSetEnabledState; - -private: - /** (DEPRECATED) FALSE if the node is a disabled, which eliminates it from being compiled */ - UPROPERTY() - bool bIsNodeEnabled_DEPRECATED; - public: /** Enables this node. */ FORCEINLINE void EnableNode() @@ -288,6 +312,7 @@ public: TArray GetAllPins() { return Pins; } /** Create a new pin on this node using the supplied info, and return the new pin */ + DEPRECATED(4.17, "Use version that takes PinContainerType instead of separate booleans for array, set, and map") UEdGraphPin* CreatePin( EEdGraphPinDirection Dir, const FString& PinCategory, @@ -302,6 +327,19 @@ public: bool bIsMap = false, const FEdGraphTerminalType& ValueTerminalType = FEdGraphTerminalType()); + /** Create a new pin on this node using the supplied info, and return the new pin */ + UEdGraphPin* CreatePin( + EEdGraphPinDirection Dir, + const FString& PinCategory, + const FString& PinSubCategory, + UObject* PinSubCategoryObject, + const FString& PinName, + EPinContainerType PinContainerType = EPinContainerType::None, + bool bIsReference = false, + bool bIsConst = false, + int32 Index = INDEX_NONE, + const FEdGraphTerminalType& ValueTerminalType = FEdGraphTerminalType()); + /** Create a new pin on this node using the supplied pin type, and return the new pin */ UEdGraphPin* CreatePin(EEdGraphPinDirection Dir, const FEdGraphPinType& InPinType, const FString& PinName, int32 Index = INDEX_NONE); @@ -323,6 +361,9 @@ public: /** Find a pin on this node with the supplied name and remove it, returns TRUE if successful */ bool RemovePin(UEdGraphPin* Pin); + /** Returns whether the node was created by UEdGraph::CreateIntermediateNode. */ + bool IsIntermediateNode() const { return bIsIntermediateNode; } + /** Whether or not this node should be given the chance to override pin names. If this returns true, then GetPinNameOverride() will be called for each pin, each frame */ virtual bool ShouldOverridePinNames() const { return false; } @@ -473,7 +514,7 @@ public: /** * Returns the link used for external documentation for the graph node */ - virtual FString GetDocumentationLink() const { return TEXT(""); } + virtual FString GetDocumentationLink() const { return FString(); } /** * Returns the name of the excerpt to display from the specified external documentation link for the graph node @@ -560,7 +601,7 @@ public: virtual void ValidateNodeDuringCompilation(class FCompilerResultsLog& MessageLog) const {} /** Gives the node the option to customize how diffs are discovered within it. */ - virtual void FindDiffs(class UEdGraphNode* OtherNode, struct FDiffResults& Results ) ; + virtual void FindDiffs(class UEdGraphNode* OtherNode, FDiffResults& Results); // This function gets menu items that can be created using this node given the specified context virtual void GetMenuEntries(struct FGraphContextMenuBuilder& ContextMenuBuilder) const {} @@ -624,13 +665,37 @@ public: /** Sets a flag if the comment bubble needs to be made visible immediately */ void SetMakeCommentBubbleVisible(bool MakeVisible); -#endif // WITH_EDITOR protected: + /** + * Finds the difference in properties of node instance + * + * @param StructA The struct of the class we are looking at LHS + * @param StructB The struct of the class we are looking at RHS + * @param DataA The raw data for the UObject we are comparing LHS + * @param DataB The raw data for the UObject we are comparing RHS + * @param Results The Results where differences are stored + * @param Diff The single result with default parameters setup + */ + virtual void DiffProperties(UClass* StructA, UClass* StructB, UObject* DataA, UObject* DataB, FDiffResults& Results, FDiffSingleResult& Diff) const; - /** (DEPRECATED) Value used for AllowSplitPins(). Do not override. */ - bool bAllowSplitPins_DEPRECATED; + // Returns a human-friendly description of the property in the form "PropertyName: Value" + virtual FString GetPropertyNameAndValueForDiff(const UProperty* Prop, const uint8* PropertyAddr) const; + +#endif // WITH_EDITOR + + friend struct FSetAsIntermediateNode; +}; + +struct FSetAsIntermediateNode +{ + friend UEdGraph; + +private: + FSetAsIntermediateNode(UEdGraphNode* GraphNode) + { + GraphNode->bIsIntermediateNode = true; + } }; - diff --git a/Engine/Source/Runtime/Engine/Classes/EdGraph/EdGraphPin.h b/Engine/Source/Runtime/Engine/Classes/EdGraph/EdGraphPin.h index 49b49bced5a2..a47a6fd3d5ff 100644 --- a/Engine/Source/Runtime/Engine/Classes/EdGraph/EdGraphPin.h +++ b/Engine/Source/Runtime/Engine/Classes/EdGraph/EdGraphPin.h @@ -104,55 +104,82 @@ struct FEdGraphPinType UPROPERTY() FEdGraphTerminalType PinValueType; - /** Whether or not this pin represents a map of keys to values */ UPROPERTY() - bool bIsMap; + EPinContainerType ContainerType; - /** Whether or not this pin represents a set of (unique) values */ +private: + /** DEPRECATED(4.17) Whether or not this pin represents a map of keys to values */ UPROPERTY() - bool bIsSet; + uint8 bIsMap_DEPRECATED:1; - /** Whether or not this pin represents an array of values */ + /** DEPRECATED(4.17) Whether or not this pin represents a set of (unique) values */ UPROPERTY() - bool bIsArray; + uint8 bIsSet_DEPRECATED:1; + /** DEPRECATED(4.17) Whether or not this pin represents an array of values */ + UPROPERTY() + uint8 bIsArray_DEPRECATED:1; + +public: /** Whether or not this pin is a value passed by reference or not */ UPROPERTY() - bool bIsReference; + uint8 bIsReference:1; /** Whether or not this pin is a immutable const value */ UPROPERTY() - bool bIsConst; + uint8 bIsConst:1; /** Whether or not this is a weak reference */ UPROPERTY() - bool bIsWeakPointer; + uint8 bIsWeakPointer:1; - FORCEINLINE bool IsContainer() const { return bIsMap || bIsSet || bIsArray; } + FORCEINLINE bool IsContainer() const { return (ContainerType != EPinContainerType::None); } + FORCEINLINE bool IsArray() const { return (ContainerType == EPinContainerType::Array); } + FORCEINLINE bool IsSet() const { return (ContainerType == EPinContainerType::Set); } + FORCEINLINE bool IsMap() const { return (ContainerType == EPinContainerType::Map); } public: FEdGraphPinType() + : PinSubCategoryObject(nullptr) + , ContainerType(EPinContainerType::None) + , bIsMap_DEPRECATED(false) + , bIsSet_DEPRECATED(false) + , bIsArray_DEPRECATED(false) + , bIsReference(false) + , bIsConst(false) + , bIsWeakPointer(false) { - PinSubCategoryObject = nullptr; - bIsMap = false; - bIsSet = false; - bIsArray = false; - bIsReference = false; - bIsConst = false; - bIsWeakPointer = false; } - FEdGraphPinType(const FString& InPinCategory, const FString& InPinSubCategory, UObject* InPinSubCategoryObject, bool bInIsArray, bool bInIsReference, bool bInIsSet, bool bInIsMap, const FEdGraphTerminalType& InValueTerminalType ) + + DEPRECATED(4.17, "Use version that takes PinContainerType instead of separate booleans for array, set, and map") + FEdGraphPinType(FString InPinCategory, FString InPinSubCategory, UObject* InPinSubCategoryObject, bool bInIsArray, bool bInIsReference, bool bInIsSet, bool bInIsMap, const FEdGraphTerminalType& InValueTerminalType ) + : PinCategory(MoveTemp(InPinCategory)) + , PinSubCategory(MoveTemp(InPinSubCategory)) + , PinSubCategoryObject(InPinSubCategoryObject) + , PinValueType(InValueTerminalType) + , ContainerType(ToPinContainerType(bInIsArray, bInIsSet, bInIsMap)) + , bIsMap_DEPRECATED(false) + , bIsSet_DEPRECATED(false) + , bIsArray_DEPRECATED(false) + , bIsReference(bInIsReference) + , bIsConst(false) + , bIsWeakPointer(false) + { + } + + FEdGraphPinType(FString InPinCategory, FString InPinSubCategory, UObject* InPinSubCategoryObject, EPinContainerType InPinContainerType, bool bInIsReference, const FEdGraphTerminalType& InValueTerminalType ) + : PinCategory(MoveTemp(InPinCategory)) + , PinSubCategory(MoveTemp(InPinSubCategory)) + , PinSubCategoryObject(InPinSubCategoryObject) + , PinValueType(InValueTerminalType) + , ContainerType(InPinContainerType) + , bIsMap_DEPRECATED(false) + , bIsSet_DEPRECATED(false) + , bIsArray_DEPRECATED(false) + , bIsReference(bInIsReference) + , bIsConst(false) + , bIsWeakPointer(false) { - PinCategory = InPinCategory; - PinSubCategory = InPinSubCategory; - PinSubCategoryObject = InPinSubCategoryObject; - PinValueType = InValueTerminalType; - bIsMap = bInIsMap; - bIsSet = bInIsSet; - bIsArray = bInIsArray; - bIsReference = bInIsReference; - bIsConst = false; - bIsWeakPointer = false; } bool operator == ( const FEdGraphPinType& Other ) const { @@ -160,9 +187,7 @@ public: && (PinSubCategory == Other.PinSubCategory) && (PinSubCategoryObject == Other.PinSubCategoryObject) && (PinValueType == Other.PinValueType) - && (bIsMap == Other.bIsMap) - && (bIsSet == Other.bIsSet) - && (bIsArray == Other.bIsArray) + && (ContainerType == Other.ContainerType) && (bIsReference == Other.bIsReference) && (bIsWeakPointer == Other.bIsWeakPointer) && (PinSubCategoryMemberReference == Other.PinSubCategoryMemberReference) @@ -170,28 +195,17 @@ public: } bool operator != ( const FEdGraphPinType& Other ) const { - return (PinCategory != Other.PinCategory) - || (PinSubCategory != Other.PinSubCategory) - || (PinSubCategoryObject != Other.PinSubCategoryObject) - || (PinValueType != Other.PinValueType) - || (bIsMap != Other.bIsMap) - || (bIsSet != Other.bIsSet) - || (bIsArray != Other.bIsArray) - || (bIsReference != Other.bIsReference) - || (bIsWeakPointer != Other.bIsWeakPointer) - || (bIsConst != Other.bIsConst); + return !(*this == Other); } void ResetToDefaults() { - PinCategory.Empty(); - PinSubCategory.Empty(); + PinCategory.Reset(); + PinSubCategory.Reset(); PinSubCategoryObject = nullptr; PinValueType = FEdGraphTerminalType(); PinSubCategoryMemberReference.Reset(); - bIsMap = false; - bIsSet = false; - bIsArray = false; + ContainerType = EPinContainerType::None; bIsReference = false; bIsWeakPointer = false; bIsConst = false; @@ -201,6 +215,29 @@ public: static ENGINE_API FEdGraphPinType GetPinTypeForTerminalType( const FEdGraphTerminalType& TerminalType ); static ENGINE_API FEdGraphPinType GetTerminalTypeForContainer( const FEdGraphPinType& ContainerType ); + + static EPinContainerType ToPinContainerType(const bool bInIsArray, const bool bInIsSet, const bool bInIsMap) + { + EPinContainerType ContainerType = EPinContainerType::None; + + if (bInIsArray) + { + check(!bInIsSet && !bInIsMap); + ContainerType = EPinContainerType::Array; + } + else if (bInIsSet) + { + check(!bInIsMap); + ContainerType = EPinContainerType::Set; + } + else if (bInIsMap) + { + ContainerType = EPinContainerType::Map; + } + + return ContainerType; + } + }; template<> @@ -397,6 +434,9 @@ public: /** Get the current DefaultObject path name, or DefaultValue if its null */ ENGINE_API FString GetDefaultAsString() const; + /** Returns true if the current default value matches the autogenerated default value */ + ENGINE_API bool DoesDefaultValueMatchAutogenerated() const; + #if WITH_EDITORONLY_DATA /** Returns how the name of the pin should be displayed in the UI */ ENGINE_API FText GetDisplayName() const; @@ -411,6 +451,7 @@ public: */ const FString GetLinkInfoString( const FString& InFunctionName, const FString& InInfoData, const UEdGraphPin* InToPin ) const; + /** Reset default values to empty. This should not be called when AutogeneratedDefaultValue needs to be respected! */ void ResetDefaultValue() { DefaultValue.Empty(); @@ -418,6 +459,7 @@ public: DefaultTextValue = FText::GetEmpty(); } + /** Resets node to default constructor state */ void ResetToDefaults() { check(LinkedTo.Num() == 0); diff --git a/Engine/Source/Runtime/Engine/Classes/EdGraph/EdGraphSchema.h b/Engine/Source/Runtime/Engine/Classes/EdGraph/EdGraphSchema.h index 7893d69f9668..e2accadce742 100644 --- a/Engine/Source/Runtime/Engine/Classes/EdGraph/EdGraphSchema.h +++ b/Engine/Source/Runtime/Engine/Classes/EdGraph/EdGraphSchema.h @@ -458,6 +458,10 @@ private: TArray< ActionGroup > Entries; public: + + /** Virtual destructor */ + virtual ~FGraphActionListBuilderBase() { } + /** Adds an action entry containing a single action */ ENGINE_API virtual void AddAction( const TSharedPtr& NewAction, FString const& Category = FString() ); diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/AssetManager.h b/Engine/Source/Runtime/Engine/Classes/Engine/AssetManager.h index 237c7ee2b265..fbce1e489193 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/AssetManager.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/AssetManager.h @@ -33,6 +33,9 @@ public: /** Returns the current AssetManager object */ static UAssetManager& Get(); + /** Returns the current AssetManager object if it exists, null otherwise */ + static UAssetManager* GetIfValid(); + /** Accesses the StreamableManager used by this Asset Manager. Static for easy access */ static FStreamableManager& GetStreamableManager() { return Get().StreamableManager; } @@ -114,6 +117,9 @@ public: /** Gets the list of all FStringAssetReferences for a given type, returns true if any found */ virtual bool GetPrimaryAssetPathList(FPrimaryAssetType PrimaryAssetType, TArray& AssetPathList) const; + /** Sees if the passed in object is a registered primary asset, if so return it. Returns invalid Identifier if not found */ + virtual FPrimaryAssetId GetPrimaryAssetIdForObject(UObject* Object) const; + /** Sees if the passed in object path is a registered primary asset, if so return it. Returns invalid Identifier if not found */ virtual FPrimaryAssetId GetPrimaryAssetIdForPath(const FStringAssetReference& ObjectPath) const; virtual FPrimaryAssetId GetPrimaryAssetIdForPath(FName ObjectPath) const; @@ -121,8 +127,8 @@ public: /** Sees if the package has a primary asset, useful if only the package name is available */ virtual FPrimaryAssetId GetPrimaryAssetIdForPackage(FName PackagePath) const; - /** Parses AssetData to extract the primary type/name from it. This works even if it isn't in the directory yet */ - virtual FPrimaryAssetId GetPrimaryAssetIdFromData(const FAssetData& AssetData, FPrimaryAssetType SuggestedType = NAME_None) const; + /** Returns the primary asset Id for the given FAssetData, only works if in directory */ + virtual FPrimaryAssetId GetPrimaryAssetIdForData(const FAssetData& AssetData) const; /** Gets list of all FPrimaryAssetId for a primary asset type, returns true if any were found */ virtual bool GetPrimaryAssetIdList(FPrimaryAssetType PrimaryAssetType, TArray& PrimaryAssetIdList) const; @@ -145,7 +151,7 @@ public: * @param LoadBundles List of bundles to load for those assets * @param DelegateToCall Delegate that will be called on completion, may be called before function returns if assets are already loaded * @param Priority Async loading priority for this request - * @return Streamable Handle that can be used to poll or wait + * @return Streamable Handle that can be used to poll or wait. You do not need to keep this handle to stop the assets from being unloaded */ virtual TSharedPtr LoadPrimaryAssets(const TArray& AssetsToLoad, const TArray& LoadBundles = TArray(), FStreamableDelegate DelegateToCall = FStreamableDelegate(), TAsyncLoadPriority Priority = FStreamableManager::DefaultAsyncLoadPriority); @@ -156,7 +162,8 @@ public: virtual TSharedPtr LoadPrimaryAssetsWithType(FPrimaryAssetType PrimaryAssetType, const TArray& LoadBundles = TArray(), FStreamableDelegate DelegateToCall = FStreamableDelegate(), TAsyncLoadPriority Priority = FStreamableManager::DefaultAsyncLoadPriority); /** - * Unloads a list of Primary Assets. This will drop hard references to these assets, but they may be in memory due to other references or GC delay + * Unloads a list of Primary Assets that were previously Loaded. + * If the only thing keeping these assets in memory was a prior Load call, they will be freed. * * @param AssetsToUnload List of primary assets to load * @return Number of assets unloaded @@ -180,10 +187,23 @@ public: * @param RemoveAllBundles If true, remove all existing bundles even if not in remove list * @param DelegateToCall Delegate that will be called on completion, may be called before function returns if assets are already loaded * @param Priority Async loading priority for this request - * @return Streamable Handle that can be used to poll or wait + * @return Streamable Handle that can be used to poll or wait. You do not need to keep this handle to stop the assets from being unloaded */ virtual TSharedPtr ChangeBundleStateForPrimaryAssets(const TArray& AssetsToChange, const TArray& AddBundles, const TArray& RemoveBundles, bool bRemoveAllBundles = false, FStreamableDelegate DelegateToCall = FStreamableDelegate(), TAsyncLoadPriority Priority = FStreamableManager::DefaultAsyncLoadPriority); + /** + * Changes the bundle state of all loaded primary assets. Only assets matching OldBundles will be modified + * You can wait on the returned streamable request or poll as needed. + * If there is no work to do, returned handle will be null and delegate will get called before function returns. + * + * @param NewBundles New bundle state for the assets that are changed + * @param OldBundles Old bundle state, it will remove these bundles and replace with NewBundles + * @param DelegateToCall Delegate that will be called on completion, may be called before function returns if assets are already loaded + * @param Priority Async loading priority for this request + * @return Streamable Handle that can be used to poll or wait. You do not need to keep this handle to stop the assets from being unloaded + */ + virtual TSharedPtr ChangeBundleStateForMatchingPrimaryAssets(const TArray& NewBundles, const TArray& OldBundles, FStreamableDelegate DelegateToCall = FStreamableDelegate(), TAsyncLoadPriority Priority = FStreamableManager::DefaultAsyncLoadPriority); + /** * Returns the loading handle associated with the primary asset, it can then be checked for progress or waited on * @@ -192,7 +212,7 @@ public: * @param Bundles If not null, will fill in with a list of the requested bundle state * @return Streamable Handle that can be used to poll or wait */ - TSharedPtr GetPrimaryAssetHandle(const FPrimaryAssetId& PrimaryAssetId, bool bForceCurrent = false, TArray* Bundles = nullptr); + TSharedPtr GetPrimaryAssetHandle(const FPrimaryAssetId& PrimaryAssetId, bool bForceCurrent = false, TArray* Bundles = nullptr) const ; /** * Returns a list of primary assets that are in the given bundle state. Only assets that are loaded or being loaded are valid @@ -204,10 +224,23 @@ public: * @param bForceCurrent If true, only use the current state. If false, use the current or pending * @return True if any found */ - bool GetPrimaryAssetsWithBundleState(TArray& PrimaryAssetList, const TArray& ValidTypes, const TArray& RequiredBundles, const TArray& ExcludedBundles = TArray(), bool bForceCurrent = false); + bool GetPrimaryAssetsWithBundleState(TArray& PrimaryAssetList, const TArray& ValidTypes, const TArray& RequiredBundles, const TArray& ExcludedBundles = TArray(), bool bForceCurrent = false) const; /** Fills in a TMap with the pending/active loading state of every asset */ - void GetPrimaryAssetBundleStateMap(TMap>& BundleStateMap, bool bForceCurrent = false); + void GetPrimaryAssetBundleStateMap(TMap>& BundleStateMap, bool bForceCurrent = false) const; + + /** + * Preloads data for a set of assets in a specific bundle state, and returns a handle you must keep active. + * These assets are not officially Loaded, so Unload/ChangeBundleState will not affect them and if you release the handle without otherwise loading the assets they will be freed. + * + * @param AssetsToLoad List of primary assets to load + * @param LoadBundles List of bundles to load for those assets + * @param bLoadRecursive If true, this will call RecursivelyExpandBundleData and recurse into sub bundles of other primary assets loaded by a bundle reference + * @param DelegateToCall Delegate that will be called on completion, may be called before function returns if assets are already loaded + * @param Priority Async loading priority for this request + * @return Streamable Handle that must be stored to keep the preloaded assets from being freed + */ + virtual TSharedPtr PreloadPrimaryAssets(const TArray& AssetsToLoad, const TArray& LoadBundles, bool bLoadRecursive, FStreamableDelegate DelegateToCall = FStreamableDelegate(), TAsyncLoadPriority Priority = FStreamableManager::DefaultAsyncLoadPriority); /** Quick wrapper to async load some non primary assets with the primary streamable manager. This will not auto release the handle, release it if needed */ virtual TSharedPtr LoadAssetList(const TArray& AssetList); @@ -234,11 +267,14 @@ public: virtual bool GetManagedPackageList(FPrimaryAssetId PrimaryAssetId, TArray& AssetPackageList) const; /** Returns list of PrimaryAssetIds that manage a package. Will optionally recurse up the management chain */ - virtual bool GetPackageManagerList(FName PackageName, bool bRecurseToParents, TArray& ManagerList) const; + virtual bool GetPackageManagers(FName PackageName, bool bRecurseToParents, TSet& ManagerSet) const; // GENERAL ASSET UTILITY FUNCTIONS + /** Parses AssetData to extract the primary type/name from it. This works even if it isn't in the directory */ + virtual FPrimaryAssetId ExtractPrimaryAssetIdFromData(const FAssetData& AssetData, FPrimaryAssetType SuggestedType = NAME_None) const; + /** Gets the FAssetData at a specific path, handles redirectors and blueprint classes correctly. Returns true if it found a valid data */ virtual bool GetAssetDataForPath(const FStringAssetReference& ObjectPath, FAssetData& AssetData) const; @@ -264,6 +300,9 @@ public: /** Dumps out list of loaded asset bundles to log */ static void DumpLoadedAssetState(); + /** Dumps information about the Asset Registry to log */ + static void DumpAssetRegistryInfo(); + /** Dumps out list of primary asset -> managed assets to log */ static void DumpReferencersForPackage(const TArray< FString >& PackageNames); @@ -285,8 +324,8 @@ public: #if WITH_EDITOR // EDITOR ONLY FUNCTIONALITY - /** Gets package names to add to the cook. Do this instead of loading assets so RAM can be properly managed on build machines */ - virtual void ModifyCook(TArray& PackageNames); + /** Gets package names to add to the cook, and packages to never cook even if in startup set memory or referenced */ + virtual void ModifyCook(TArray& PackagesToCook, TArray& PackagesToNeverCook); /** Returns cook rule for a package name using Management rules, games should override this to take into account their individual workflows */ virtual EPrimaryAssetCookRule GetPackageCookRule(FName PackageName) const; @@ -303,6 +342,9 @@ public: /** Refresh the entire set of asset data, can call from editor when things have changed dramatically */ virtual void RefreshPrimaryAssetDirectory(); + /** Resets all asset manager data, called in the editor to reinitialize the config */ + virtual void ReinitializeFromConfig(); + /** Updates the asset management database if needed */ virtual void UpdateManagementDatabase(bool bForceRefresh = false); @@ -400,9 +442,6 @@ protected: TMap> PrimaryAssetStateBeforePIE; #endif // WITH_EDITOR - /** Per-type asset information */ - TMap> AssetTypeMap; - /** Map from object path to Primary Asset Id */ TMap AssetPathMap; @@ -429,10 +468,6 @@ protected: UPROPERTY() bool bIsGlobalAsyncScanEnvironment; - /** True if we should keep hard references to loaded assets, to stop them from garbage collecting */ - UPROPERTY() - bool bShouldKeepHardRefs; - /** True if PrimaryAssetType/Name will be implied for loading assets that don't have it saved on disk. Won't work for all projects */ UPROPERTY() bool bShouldGuessTypeAndName; @@ -453,12 +488,19 @@ protected: UPROPERTY() bool bUpdateManagementDatabaseAfterScan; + /** Number of notifications seen in this update */ + UPROPERTY() + int32 NumberOfSpawnedNotifications; + /** Redirector maps loaded out of AssetMigrations.ini */ TMap PrimaryAssetTypeRedirects; TMap PrimaryAssetIdRedirects; TMap AssetPathRedirects; private: + /** Per-type asset information, cannot be accessed by children as it is defined in CPP file */ + TMap> AssetTypeMap; + mutable class IAssetRegistry* CachedAssetRegistry; mutable const class UAssetManagerSettings* CachedSettings; }; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/AssetManagerSettings.h b/Engine/Source/Runtime/Engine/Classes/Engine/AssetManagerSettings.h index 621d6dec32b9..d4b10f369747 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/AssetManagerSettings.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/AssetManagerSettings.h @@ -46,14 +46,14 @@ class ENGINE_API UAssetManagerSettings : public UDeveloperSettings GENERATED_BODY() public: - UAssetManagerSettings() : bOnlyCookProductionAssets(false) {} + UAssetManagerSettings() : bOnlyCookProductionAssets(false), bShouldGuessTypeAndNameInEditor(true) {} /** List of asset types to scan at startup */ UPROPERTY(config, EditAnywhere, Category = "Asset Manager") TArray PrimaryAssetTypesToScan; /** List of directories to exclude from scanning for Primary Assets, useful to exclude test assets */ - UPROPERTY(config, EditAnywhere, Category = "Asset Manager", meta = (RelativeToGameContentDir)) + UPROPERTY(config, EditAnywhere, Category = "Asset Manager", meta = (RelativeToGameContentDir, LongPackageName)) TArray DirectoriesToExclude; /** List of specific asset rule overrides */ @@ -64,6 +64,10 @@ public: UPROPERTY(config, EditAnywhere, Category = "Asset Manager") bool bOnlyCookProductionAssets; + /** If true, PrimaryAsset Type/Name will be implied for assets in the editor (cooked builds always must be explicit). This allows guessing for content that hasn't been resaved yet */ + UPROPERTY(config, EditAnywhere, Category = "Asset Manager") + bool bShouldGuessTypeAndNameInEditor; + /** Redirect from Type:Name to Type:NameNew */ UPROPERTY(config, EditAnywhere, Category = "Redirects") TArray PrimaryAssetIdRedirects; @@ -75,4 +79,8 @@ public: /** Redirect from /game/assetpath to /game/assetpathnew */ UPROPERTY(config, EditAnywhere, Category = "Redirects") TArray AssetPathRedirects; + +#if WITH_EDITOR + virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; +#endif }; \ No newline at end of file diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/AssetManagerTypes.h b/Engine/Source/Runtime/Engine/Classes/Engine/AssetManagerTypes.h index 2d2e606f11e0..5ddef10bd0f1 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/AssetManagerTypes.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/AssetManagerTypes.h @@ -103,7 +103,7 @@ public: private: /** Directories to search for this asset type */ - UPROPERTY(EditAnywhere, Category = AssetType, meta = (RelativeToGameContentDir)) + UPROPERTY(EditAnywhere, Category = AssetType, meta = (RelativeToGameContentDir, LongPackageName)) TArray Directories; /** Individual assets to scan */ diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/Attenuation.h b/Engine/Source/Runtime/Engine/Classes/Engine/Attenuation.h index bcbec01c7881..204ab31ed4d4 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/Attenuation.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/Attenuation.h @@ -38,7 +38,7 @@ namespace EAttenuationShape /* * Base class for attenuation settings. */ -USTRUCT() +USTRUCT(BlueprintType) struct ENGINE_API FBaseAttenuationSettings { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/Blueprint.h b/Engine/Source/Runtime/Engine/Classes/Engine/Blueprint.h index ffde54dfe5bc..f066585c161f 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/Blueprint.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/Blueprint.h @@ -391,6 +391,9 @@ class ENGINE_API UBlueprint : public UBlueprintCore UPROPERTY(transient) uint32 bForceFullEditor : 1; + UPROPERTY(transient) + uint32 bQueuedForCompilation : 1 ; + /**whether or not you want to continuously rerun the construction script for an actor as you drag it in the editor, or only when the drag operation is complete*/ UPROPERTY(EditAnywhere, Category=BlueprintOptions) uint32 bRunConstructionScriptOnDrag : 1; @@ -568,6 +571,10 @@ public: virtual bool IsValidForBytecodeOnlyRecompile() const { return true; } #if WITH_EDITORONLY_DATA + /** Delegate called when the debug object is set */ + DECLARE_EVENT_OneParam(UBlueprint, FOnSetObjectBeingDebugged, UObject* /*InDebugObj*/); + FOnSetObjectBeingDebugged& OnSetObjectBeingDebugged() { return OnSetObjectBeingDebuggedDelegate; } + protected: /** Current object being debugged for this blueprint */ TWeakObjectPtr< class UObject > CurrentObjectBeingDebugged; @@ -575,6 +582,9 @@ protected: /** Current world being debugged for this blueprint */ TWeakObjectPtr< class UWorld > CurrentWorldBeingDebugged; + /** Delegate called when the debug object is set */ + FOnSetObjectBeingDebugged OnSetObjectBeingDebuggedDelegate; + public: /** Information for thumbnail rendering */ @@ -687,6 +697,9 @@ public: */ virtual bool AlwaysCompileOnLoad() const { return false; } + /** Some Blueprints (and classes) can recompile while we are debugging a live session. This function controls whether this can occur. */ + virtual bool CanRecompileWhilePlayingInEditor() const { return false; } + private: /** Sets the current object being debugged */ diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/BlueprintGeneratedClass.h b/Engine/Source/Runtime/Engine/Classes/Engine/BlueprintGeneratedClass.h index 4a7b39074bb0..843370ff3ada 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/BlueprintGeneratedClass.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/BlueprintGeneratedClass.h @@ -698,6 +698,7 @@ public: virtual FPrimaryAssetId GetPrimaryAssetId() const override; virtual bool NeedsLoadForServer() const override; virtual bool NeedsLoadForClient() const override; + virtual bool NeedsLoadForEditorGame() const override; virtual bool CanBeClusterRoot() const override; // End UObject interface @@ -705,6 +706,7 @@ public: #if WITH_EDITOR virtual UClass* GetAuthoritativeClass() override; virtual void ConditionalRecompileClass(TArray* ObjLoaded) override; + virtual void FlushCompilationQueueForLevel() override; virtual UObject* GetArchetypeForCDO() const override; #endif //WITH_EDITOR virtual void SerializeDefaultObject(UObject* Object, FArchive& Ar) override; @@ -722,10 +724,8 @@ public: { return bHasInstrumentation; } - virtual const FCustomPropertyListNode* GetCustomPropertyListForPostConstruction() const override - { - return CustomPropertyListForPostConstruction.Num() > 0 ? *CustomPropertyListForPostConstruction.GetData() : nullptr; - } + + virtual void InitPropertiesFromCustomList(uint8* DataPtr, const uint8* DefaultDataPtr) override; protected: @@ -734,6 +734,35 @@ protected: virtual bool ArePropertyGuidsAvailable() const override; // End UClass interface + /** + * Returns a linked list of properties with default values that differ from the parent default object. If non-NULL, only these properties will + * be copied post-construction. Otherwise, all properties will be copied to the new instance, even if the default value matches the inherited default value. + */ + const FCustomPropertyListNode* GetCustomPropertyListForPostConstruction() const + { + return CustomPropertyListForPostConstruction.Num() > 0 ? *CustomPropertyListForPostConstruction.GetData() : nullptr; + } + + /** + * Helper method to assist with initializing object properties from an explicit list. + * + * @param InPropertyList only these properties will be copied from defaults + * @param InStruct the current scope for which the given property list applies + * @param DataPtr destination address (where to start copying values to) + * @param DefaultDataPtr source address (where to start copying the defaults data from) + */ + static void InitPropertiesFromCustomList(const FCustomPropertyListNode* InPropertyList, UStruct* InStruct, uint8* DataPtr, const uint8* DefaultDataPtr); + + /** + * Helper method to assist with initializing from an array property with an explicit item list. + * + * @param ArrayProperty the array property for which the given property list applies + * @param InPropertyList only these properties (indices) will be copied from defaults + * @param DataPtr destination address (where to start copying values to) + * @param DefaultDataPtr source address (where to start copying the defaults data from) + */ + static void InitArrayPropertyFromCustomList(const UArrayProperty* ArrayProperty, const FCustomPropertyListNode* InPropertyList, uint8* DataPtr, const uint8* DefaultDataPtr); + public: /** Called when the custom list of properties used during post-construct initialization needs to be rebuilt (e.g. after serialization and recompilation). */ @@ -792,4 +821,6 @@ private: TIndirectArray CustomPropertyListForPostConstruction; /** In some cases UObject::ConditionalPostLoad() code calls PostLoadDefaultObject() on a class that's still being serialized. */ FCriticalSection SerializeAndPostLoadCritical; + /** Flag to make sure the custom property list has been initialized */ + bool bCustomPropertyListForPostConstructionInitialized; }; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/Brush.h b/Engine/Source/Runtime/Engine/Classes/Engine/Brush.h index 848e41d74434..6da4e2113d0c 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/Brush.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/Brush.h @@ -105,8 +105,7 @@ class ENGINE_API ABrush UPROPERTY(Instanced) class UModel* Brush; -private_subobject: - DEPRECATED_FORGAME(4.6, "BrushComponent should not be accessed directly, please use GetBrushComponent() function instead. BrushComponent will soon be private and your code will not compile.") +private: UPROPERTY(Category = Collision, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) class UBrushComponent* BrushComponent; public: @@ -276,7 +275,7 @@ public: public: /** Returns BrushComponent subobject **/ - class UBrushComponent* GetBrushComponent() const; + class UBrushComponent* GetBrushComponent() const { return BrushComponent; } #if WITH_EDITOR /** Debug purposes only; an attempt to catch the cause of UE-36265 */ diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/Canvas.h b/Engine/Source/Runtime/Engine/Classes/Engine/Canvas.h index 4f3f51d61782..017e6aa1326e 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/Canvas.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/Canvas.h @@ -17,7 +17,7 @@ class UTexture; /** * Holds texture information with UV coordinates as well. */ -USTRUCT() +USTRUCT(BlueprintType) struct FCanvasIcon { GENERATED_USTRUCT_BODY() @@ -458,7 +458,7 @@ public: * Draw a CanvasItem at the given coordinates * * @param Item Item to draw - * @param InPostion Position to draw item + * @param InPosition Position to draw item */ void DrawItem( FCanvasItem& Item, const FVector2D& InPosition ); diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/CoreSettings.h b/Engine/Source/Runtime/Engine/Classes/Engine/CoreSettings.h index c8ad7f0e8251..97cbd1cda6d7 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/CoreSettings.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/CoreSettings.h @@ -11,7 +11,7 @@ struct FPropertyChangedEvent; /** - * Rendering settings. + * Streaming settings. */ UCLASS(config=Engine, defaultconfig, meta=(DisplayName="Streaming")) class ENGINE_API UStreamingSettings : public UDeveloperSettings @@ -49,11 +49,6 @@ protected: ToolTip = "Minimum time the time limit exceeded warning will be triggered by.")) int32 MinBulkDataSizeForAsyncLoading; - UPROPERTY(config, EditAnywhere, Category = IO, meta = ( - ConsoleVariable = "s.AsyncIOBandwidthLimit", DisplayName = "Asynchronous IO Bandwidth Limit", - ToolTip = "Constrain bandwidth if wanted. Value is in MByte/ sec.")) - float AsyncIOBandwidthLimit; - UPROPERTY(EditAnywhere, config, Category = LevelStreaming, meta = ( ConsoleVariable = "s.UseBackgroundLevelStreaming", DisplayName = "Use Background Level Streaming", ToolTip = "Whether to allow background level streaming.")) diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/CullDistanceVolume.h b/Engine/Source/Runtime/Engine/Classes/Engine/CullDistanceVolume.h index b78335028c10..bce585707929 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/CullDistanceVolume.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/CullDistanceVolume.h @@ -12,7 +12,7 @@ class UPrimitiveComponent; /** * Helper structure containing size and cull distance pair. */ -USTRUCT() +USTRUCT(BlueprintType) struct FCullDistanceSizePair { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/DataTable.h b/Engine/Source/Runtime/Engine/Classes/Engine/DataTable.h index 8a51378e6de6..4839a4fbca3c 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/DataTable.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/DataTable.h @@ -28,7 +28,7 @@ class UDataTable; /** * Base class for all table row structs to inherit from. */ -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct FTableRowBase { GENERATED_USTRUCT_BODY() @@ -333,7 +333,7 @@ struct TStructOpsTypeTraits< FDataTableRowHandle > : public TStructOpsTypeTraits }; /** Handle to a particular row in a table*/ -USTRUCT() +USTRUCT(BlueprintType) struct ENGINE_API FDataTableCategoryHandle { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/DecalActor.h b/Engine/Source/Runtime/Engine/Classes/Engine/DecalActor.h index 598b23754a8c..4abec737c9aa 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/DecalActor.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/DecalActor.h @@ -24,20 +24,17 @@ class ENGINE_API ADecalActor { GENERATED_UCLASS_BODY() -private_subobject: +private: /** The decal component for this decal actor */ - DEPRECATED_FORGAME(4.6, "Decal should not be accessed directly, please use GetDecal() function instead. Decal will soon be private and your code will not compile.") UPROPERTY(Category = Decal, VisibleAnywhere, BlueprintReadOnly, meta = (ExposeFunctionCategories = "Decal,Rendering|Components|Decal", AllowPrivateAccess = "true")) UDecalComponent* Decal; #if WITH_EDITORONLY_DATA /* Reference to the editor only arrow visualization component */ - DEPRECATED_FORGAME(4.6, "ArrowComponent should not be accessed directly, please use GetArrowComponent() function instead. ArrowComponent will soon be private and your code will not compile.") UPROPERTY() UArrowComponent* ArrowComponent; /* Reference to the billboard component */ - DEPRECATED_FORGAME(4.6, "SpriteComponent should not be accessed directly, please use GetSpriteComponent() function instead. SpriteComponent will soon be private and your code will not compile.") UPROPERTY() UBillboardComponent* SpriteComponent; @@ -77,11 +74,11 @@ public: public: /** Returns Decal subobject **/ - UDecalComponent* GetDecal() const; + UDecalComponent* GetDecal() const { return Decal; } #if WITH_EDITORONLY_DATA /** Returns ArrowComponent subobject **/ - UArrowComponent* GetArrowComponent() const; + UArrowComponent* GetArrowComponent() const { return ArrowComponent; } /** Returns SpriteComponent subobject **/ - UBillboardComponent* GetSpriteComponent() const; + UBillboardComponent* GetSpriteComponent() const { return SpriteComponent; } #endif }; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/DemoNetDriver.h b/Engine/Source/Runtime/Engine/Classes/Engine/DemoNetDriver.h index 3445288ea12c..9e0743f4dd6f 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/DemoNetDriver.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/DemoNetDriver.h @@ -344,6 +344,7 @@ private: * Maximum time allowed each frame to spend on saving a checkpoint. If 0, it will save the checkpoint in a single frame, regardless of how long it takes. * See also demo.CheckpointSaveMaxMSPerFrameOverride. */ + UPROPERTY(Config) float CheckpointSaveMaxMSPerFrame; /** A player controller that this driver should consider its viewpoint for actor prioritization purposes. */ diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/DeveloperSettings.h b/Engine/Source/Runtime/Engine/Classes/Engine/DeveloperSettings.h index 03956a177896..02c374c4dab6 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/DeveloperSettings.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/DeveloperSettings.h @@ -6,7 +6,8 @@ #include "UObject/ObjectMacros.h" #include "UObject/UObjectGlobals.h" #include "UObject/Object.h" -#include "Widgets/SWidget.h" +class SWidget; + #include "DeveloperSettings.generated.h" /** @@ -38,7 +39,7 @@ public: #endif /** Gets a custom widget for the settings. This is only for very custom situations. */ - virtual TSharedPtr GetCustomSettingsWidget() const; + virtual TSharedPtr GetCustomSettingsWidget() const; protected: /** diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/DirectionalLight.h b/Engine/Source/Runtime/Engine/Classes/Engine/DirectionalLight.h index 530ef7550b37..097935156e2a 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/DirectionalLight.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/DirectionalLight.h @@ -20,8 +20,7 @@ class ADirectionalLight #if WITH_EDITORONLY_DATA // Reference to editor visualization arrow -private_subobject: - DEPRECATED_FORGAME(4.6, "ArrowComponent should not be accessed directly, please use GetArrowComponent() function instead. ArrowComponent will soon be private and your code will not compile.") +private: UPROPERTY() UArrowComponent* ArrowComponent; #endif @@ -39,6 +38,6 @@ public: #if WITH_EDITORONLY_DATA /** Returns ArrowComponent subobject **/ - ENGINE_API UArrowComponent* GetArrowComponent() const; + ENGINE_API UArrowComponent* GetArrowComponent() const { return ArrowComponent; } #endif }; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/DocumentationActor.h b/Engine/Source/Runtime/Engine/Classes/Engine/DocumentationActor.h index efcec04facce..d69e40b96c96 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/DocumentationActor.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/DocumentationActor.h @@ -48,8 +48,7 @@ class ENGINE_API ADocumentationActor UPROPERTY(Category = HelpDocumentation, EditAnywhere, BlueprintReadWrite, AdvancedDisplay) FString DocumentLink; -private_subobject: - DEPRECATED_FORGAME(4.6, "Billboard should not be accessed directly, please use GetBillboard() function instead. Billboard will soon be private and your code will not compile.") +private: UPROPERTY(Category = Sprite, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) class UMaterialBillboardComponent* Billboard; #endif @@ -70,6 +69,6 @@ public: #if WITH_EDITORONLY_DATA /** Returns Billboard subobject **/ - class UMaterialBillboardComponent* GetBillboard() const; + class UMaterialBillboardComponent* GetBillboard() const { return Billboard; } #endif }; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/Engine.h b/Engine/Source/Runtime/Engine/Classes/Engine/Engine.h index 3441abb46ff4..abf1a4082f87 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/Engine.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/Engine.h @@ -559,7 +559,9 @@ class IAnalyticsProvider; DECLARE_DELEGATE_OneParam(FBeginStreamingPauseDelegate, FViewport*); DECLARE_DELEGATE(FEndStreamingPauseDelegate); -DECLARE_MULTICAST_DELEGATE_OneParam(FEngineHitchDetectedDelegate, float /*HitchDurationInSeconds*/); +enum class EFrameHitchType: uint8; + +DECLARE_MULTICAST_DELEGATE_TwoParams(FEngineHitchDetectedDelegate, EFrameHitchType /*HitchType*/, float /*HitchDurationInSeconds*/); /** @@ -573,7 +575,7 @@ class ENGINE_API UEngine { GENERATED_UCLASS_BODY() - // Called after GEngine->Init has been called + DEPRECATED(4.17, "UEngine::OnPostEngineInit is deprecated, bind to FCoreDelegates::OnPostEngineInit instead, which will also be called for commandlets") static FSimpleMulticastDelegate OnPostEngineInit; private: @@ -781,6 +783,14 @@ public: UPROPERTY(globalconfig) FStringAssetReference DefaultBokehTextureName; + /** Texture used to bloom when using FFT, mimics characteristic bloom produced in a camera from a signle bright source */ + UPROPERTY() + class UTexture2D* DefaultBloomKernelTexture; + + /** @todo document */ + UPROPERTY(globalconfig) + FStringAssetReference DefaultBloomKernelTextureName; + /** The material used to render wireframe meshes. */ UPROPERTY() class UMaterial* WireframeMaterial; @@ -1275,6 +1285,10 @@ public: UPROPERTY(EditAnywhere, Category=LevelStreaming, AdvancedDisplay) float StreamingDistanceFactor; + /** The save directory for newly created screenshots */ + UPROPERTY(config, EditAnywhere, Category = Screenshots) + FDirectoryPath GameScreenshotSaveDirectory; + /** The current transition type. */ UPROPERTY() TEnumAsByte TransitionType; @@ -2044,6 +2058,11 @@ public: */ virtual void StopFPSChart(const FString& MapName); + /** + * Attempts to reclaim any idle memory by performing a garbage collection and broadcasting FCoreDelegates::OnMemoryTrim. Pending rendering commands are first flushed. This is called + * between level loads and may be called at other times, but is expensive and should be used sparingly. Do + */ + static void TrimMemory(); /** * Calculates information about the previous frame and passes it to all active performance data consumers. diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/EngineTypes.h b/Engine/Source/Runtime/Engine/Classes/Engine/EngineTypes.h index 2c932bb07084..79dc5be73e7a 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/EngineTypes.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/EngineTypes.h @@ -357,7 +357,7 @@ enum ESceneCaptureCompositeMode #define NUM_LIGHTING_CHANNELS 3 -USTRUCT() +USTRUCT(BlueprintType) struct FLightingChannels { GENERATED_USTRUCT_BODY() @@ -465,7 +465,7 @@ enum EMaterialTessellationMode }; -UENUM() +UENUM(BlueprintType) enum EMaterialSamplerType { SAMPLERTYPE_Color UMETA(DisplayName="Color"), @@ -570,6 +570,9 @@ enum class ENetworkSmoothingMode : uint8 If(QueryIgnoreMask & ShapeFilter != 0) filter out */ typedef uint8 FMaskFilter; +// Number of bits used currently from FMaskFilter. +enum { NumExtraFilterBits = 6 }; + // NOTE!!Some of these values are used to index into FCollisionResponseContainers and must be kept in sync. // @see FCollisionResponseContainer::SetResponse(). @@ -869,7 +872,7 @@ struct FResponseChannel /** * Container for indicating a set of collision channels that this object will collide with. */ -USTRUCT() +USTRUCT(BlueprintType) struct ENGINE_API FCollisionResponseContainer { GENERATED_USTRUCT_BODY() @@ -1315,7 +1318,7 @@ struct FCollisionImpactData /** Struct used to hold effects for destructible damage events */ -USTRUCT() +USTRUCT(BlueprintType) struct FFractureEffect { GENERATED_USTRUCT_BODY() @@ -1336,7 +1339,7 @@ struct FFractureEffect /** Struct for handling positions relative to a base actor, which is potentially moving */ -USTRUCT() +USTRUCT(BlueprintType) struct ENGINE_API FBasedPosition { GENERATED_USTRUCT_BODY() @@ -1465,11 +1468,11 @@ struct FSubtitleCue GENERATED_USTRUCT_BODY() /** The text to appear in the subtitle. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=SubtitleCue) + UPROPERTY(EditAnywhere, Category=SubtitleCue) FText Text; /** The time at which the subtitle is to be displayed, in seconds relative to the beginning of the line. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=SubtitleCue) + UPROPERTY(EditAnywhere, Category=SubtitleCue) float Time; FSubtitleCue() @@ -1522,18 +1525,18 @@ struct FLightmassLightSettings GENERATED_USTRUCT_BODY() /** 0 will be completely desaturated, 1 will be unchanged */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Lightmass, meta=(UIMin = "0.0", UIMax = "4.0")) + UPROPERTY(EditAnywhere, Category=Lightmass, meta=(UIMin = "0.0", UIMax = "4.0")) float IndirectLightingSaturation; /** Controls the falloff of shadow penumbras */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Lightmass, meta=(UIMin = "0.1", UIMax = "4.0")) + UPROPERTY(EditAnywhere, Category=Lightmass, meta=(UIMin = "0.1", UIMax = "4.0")) float ShadowExponent; /** * Whether to use area shadows for stationary light precomputed shadowmaps. * Area shadows get softer the further they are from shadow casters, but require higher lightmap resolution to get the same quality where the shadow is sharp. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Lightmass) + UPROPERTY(EditAnywhere, Category=Lightmass) bool bUseAreaShadowsForStationaryLight; FLightmassLightSettings() @@ -1559,7 +1562,7 @@ struct FLightmassDirectionalLightSettings : public FLightmassLightSettings GENERATED_USTRUCT_BODY() /** Angle that the directional light's emissive surface extends relative to a receiver, affects penumbra sizes. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Lightmass, meta=(UIMin = ".0001", UIMax = "5")) + UPROPERTY(EditAnywhere, Category=Lightmass, meta=(UIMin = ".0001", UIMax = "5")) float LightSourceAngle; FLightmassDirectionalLightSettings() @@ -1576,22 +1579,22 @@ struct FLightmassPrimitiveSettings GENERATED_USTRUCT_BODY() /** If true, this object will be lit as if it receives light from both sides of its polygons. */ - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Lightmass) + UPROPERTY(EditAnywhere, Category=Lightmass) uint32 bUseTwoSidedLighting:1; /** If true, this object will only shadow indirect lighting. */ - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Lightmass) + UPROPERTY(EditAnywhere, Category=Lightmass) uint32 bShadowIndirectOnly:1; /** If true, allow using the emissive for static lighting. */ - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Lightmass) + UPROPERTY(EditAnywhere, Category=Lightmass) uint32 bUseEmissiveForStaticLighting:1; /** * Typically the triangle normal is used for hemisphere gathering which prevents incorrect self-shadowing from artist-tweaked vertex normals. * However in the case of foliage whose vertex normal has been setup to match the underlying terrain, gathering in the direction of the vertex normal is desired. */ - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Lightmass) + UPROPERTY(EditAnywhere, Category=Lightmass) uint32 bUseVertexNormalForHemisphereGather:1; /** Direct lighting falloff exponent for mesh area lights created from emissive areas on this primitive. */ @@ -1611,11 +1614,11 @@ struct FLightmassPrimitiveSettings float EmissiveBoost; /** Scales the diffuse contribution of all materials applied to this object. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Lightmass) + UPROPERTY(EditAnywhere, Category=Lightmass) float DiffuseBoost; /** Fraction of samples taken that must be occluded in order to reach full occlusion. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Lightmass) + UPROPERTY(EditAnywhere, Category=Lightmass) float FullyOccludedSamplesFraction; FLightmassPrimitiveSettings() @@ -1664,85 +1667,85 @@ struct FLightmassDebugOptions * If false, UnrealLightmass.exe is launched automatically (default) * If true, it must be launched manually (e.g. through a debugger) with the -debug command line parameter. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=LightmassDebugOptions) + UPROPERTY(EditAnywhere, Category=LightmassDebugOptions) uint32 bDebugMode:1; /** If true, all participating Lightmass agents will report back detailed stats to the log. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=LightmassDebugOptions) + UPROPERTY(EditAnywhere, Category=LightmassDebugOptions) uint32 bStatsEnabled:1; /** If true, BSP surfaces split across model components are joined into 1 mapping */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=LightmassDebugOptions) + UPROPERTY(EditAnywhere, Category=LightmassDebugOptions) uint32 bGatherBSPSurfacesAcrossComponents:1; /** The tolerance level used when gathering BSP surfaces. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=LightmassDebugOptions) + UPROPERTY(EditAnywhere, Category=LightmassDebugOptions) float CoplanarTolerance; /** * If true, Lightmass will import mappings immediately as they complete. * It will not process them, however. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=LightmassDebugOptions) + UPROPERTY(EditAnywhere, Category=LightmassDebugOptions) uint32 bUseImmediateImport:1; /** * If true, Lightmass will process appropriate mappings as they are imported. * NOTE: Requires ImmediateMode be enabled to actually work. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=LightmassDebugOptions) + UPROPERTY(EditAnywhere, Category=LightmassDebugOptions) uint32 bImmediateProcessMappings:1; /** If true, Lightmass will sort mappings by texel cost. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=LightmassDebugOptions) + UPROPERTY(EditAnywhere, Category=LightmassDebugOptions) uint32 bSortMappings:1; /** If true, the generate coefficients will be dumped to binary files. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=LightmassDebugOptions) + UPROPERTY(EditAnywhere, Category=LightmassDebugOptions) uint32 bDumpBinaryFiles:1; /** * If true, Lightmass will write out BMPs for each generated material property * sample to \ScreenShots\Materials. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=LightmassDebugOptions) + UPROPERTY(EditAnywhere, Category=LightmassDebugOptions) uint32 bDebugMaterials:1; /** If true, Lightmass will pad the calculated mappings to reduce/eliminate seams. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=LightmassDebugOptions) + UPROPERTY(EditAnywhere, Category=LightmassDebugOptions) uint32 bPadMappings:1; /** * If true, will fill padding of mappings with a color rather than the sampled edges. * Means nothing if bPadMappings is not enabled... */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=LightmassDebugOptions) + UPROPERTY(EditAnywhere, Category=LightmassDebugOptions) uint32 bDebugPaddings:1; /** * If true, only the mapping containing a debug texel will be calculated, all others * will be set to white */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=LightmassDebugOptions) + UPROPERTY(EditAnywhere, Category=LightmassDebugOptions) uint32 bOnlyCalcDebugTexelMappings:1; /** If true, color lightmaps a random color */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=LightmassDebugOptions) + UPROPERTY(EditAnywhere, Category=LightmassDebugOptions) uint32 bUseRandomColors:1; /** If true, a green border will be placed around the edges of mappings */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=LightmassDebugOptions) + UPROPERTY(EditAnywhere, Category=LightmassDebugOptions) uint32 bColorBordersGreen:1; /** * If true, Lightmass will overwrite lightmap data with a shade of red relating to * how long it took to calculate the mapping (Red = Time / ExecutionTimeDivisor) */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=LightmassDebugOptions) + UPROPERTY(EditAnywhere, Category=LightmassDebugOptions) uint32 bColorByExecutionTime:1; /** The amount of time that will be count as full red when bColorByExecutionTime is enabled */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=LightmassDebugOptions) + UPROPERTY(EditAnywhere, Category=LightmassDebugOptions) float ExecutionTimeDivisor; ENGINE_API FLightmassDebugOptions(); @@ -1761,14 +1764,14 @@ struct FSwarmDebugOptions * If true, Swarm will distribute jobs. * If false, only the local machine will execute the jobs. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=SwarmDebugOptions) + UPROPERTY(EditAnywhere, Category=SwarmDebugOptions) uint32 bDistributionEnabled:1; /** * If true, Swarm will force content to re-export rather than using the cached version. * If false, Swarm will attempt to use the cached version. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=SwarmDebugOptions) + UPROPERTY(EditAnywhere, Category=SwarmDebugOptions) uint32 bForceContentExport:1; UPROPERTY() @@ -2399,7 +2402,7 @@ public: /** * Point Of View type. */ -USTRUCT() +USTRUCT(BlueprintType) struct FPOV { GENERATED_USTRUCT_BODY() @@ -2564,7 +2567,7 @@ struct FMeshBuildSettings -USTRUCT() +USTRUCT(BlueprintType) struct ENGINE_API FDamageEvent { GENERATED_USTRUCT_BODY() @@ -2631,27 +2634,27 @@ struct ENGINE_API FPointDamageEvent : public FDamageEvent }; -USTRUCT() +USTRUCT(BlueprintType) struct ENGINE_API FRadialDamageParams { GENERATED_USTRUCT_BODY() - UPROPERTY(EditAnywhere, Category=RadialDamageParams) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=RadialDamageParams) float BaseDamage; - UPROPERTY(EditAnywhere, Category=RadialDamageParams) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=RadialDamageParams) float MinimumDamage; - UPROPERTY(EditAnywhere, Category=RadialDamageParams) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=RadialDamageParams) float InnerRadius; - UPROPERTY(EditAnywhere, Category=RadialDamageParams) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=RadialDamageParams) float OuterRadius; - UPROPERTY(EditAnywhere, Category=RadialDamageParams) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=RadialDamageParams) float DamageFalloff; -// UPROPERTY(EditAnywhere, Category=RadiusDamageParams) +// UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=RadiusDamageParams) // float BaseImpulseMag; FRadialDamageParams() @@ -3748,7 +3751,7 @@ struct FFontRenderInfo /** Simple 2d triangle with UVs */ -USTRUCT() +USTRUCT(BlueprintType) struct FCanvasUVTri { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/ExponentialHeightFog.h b/Engine/Source/Runtime/Engine/Classes/Engine/ExponentialHeightFog.h index 7e6f5081be36..e56678345ffc 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/ExponentialHeightFog.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/ExponentialHeightFog.h @@ -16,9 +16,10 @@ class AExponentialHeightFog { GENERATED_UCLASS_BODY() -private_subobject: + virtual void GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const override; + +private: /** @todo document */ - DEPRECATED_FORGAME(4.6, "Component should not be accessed directly, please use GetComponent() function instead. Component will soon be private and your code will not compile.") UPROPERTY(Category = ExponentialHeightFog, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) class UExponentialHeightFogComponent* Component; @@ -38,5 +39,5 @@ public: //End AActor Interface /** Returns Component subobject **/ - ENGINE_API class UExponentialHeightFogComponent* GetComponent() const; + ENGINE_API class UExponentialHeightFogComponent* GetComponent() const { return Component; } }; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/GameInstance.h b/Engine/Source/Runtime/Engine/Classes/Engine/GameInstance.h index c74212ecf5f9..75969450178b 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/GameInstance.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/GameInstance.h @@ -199,6 +199,8 @@ public: virtual bool JoinSession(ULocalPlayer* LocalPlayer, int32 SessionIndexInSearchResults) { return false; } virtual bool JoinSession(ULocalPlayer* LocalPlayer, const FOnlineSessionSearchResult& SearchResult) { return false; } + virtual void LoadComplete(const float LoadTime, const FString& MapName) {} + /** Local player access */ /** @@ -352,4 +354,8 @@ public: void NotifyPreClientTravel(const FString& PendingURL, ETravelType TravelType, bool bIsSeamlessTravel); /** @return delegate fired when client travel occurs */ FOnPreClientTravel& OnNotifyPreClientTravel() { return NotifyPreClientTravelDelegates; } + +protected: + /** Called when the game instance is started either normally or through PIE. */ + virtual void OnStart(); }; \ No newline at end of file diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/GameViewportClient.h b/Engine/Source/Runtime/Engine/Classes/Engine/GameViewportClient.h index 6951f5baac72..5584c8ad9bc3 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/GameViewportClient.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/GameViewportClient.h @@ -135,6 +135,7 @@ public: /* Returns the game viewport */ FSceneViewport* GetGameViewport(); + const FSceneViewport* GetGameViewport() const; /* Returns the widget for this viewport */ TSharedPtr GetGameViewportWidget(); @@ -251,6 +252,11 @@ public: */ void RemoveAllViewportWidgets(); + /** + * Recreates cursor widgets from UISettings class. + */ + void RebuildCursors(); + /** * Cleans up all rooted or referenced objects created or managed by the GameViewportClient. This method is called * when this GameViewportClient has been disassociated with the game engine (i.e. is no longer the engine's GameViewport). @@ -561,6 +567,10 @@ public: bool SetHardwareCursor(EMouseCursor::Type CursorShape, FName GameContentPath, FVector2D HotSpot); + /** + * @return @true if this viewport is currently being used for simulate in editors + */ + bool IsSimulateInEditorViewport() const; public: /** The show flags used by the viewport's players. */ FEngineShowFlags EngineShowFlags; @@ -761,6 +771,9 @@ public: } private: + /** Resets the platform type shape to nullptr, to restore it to the OS default. */ + void ResetHardwareCursorStates(); + /** * Set a specific stat to either enabled or disabled (returns the number of remaining enabled stats) */ @@ -918,8 +931,6 @@ private: /** Whether or not this audio device is in audio-focus */ bool bHasAudioFocus; - bool bMouseEnter; + /** Is the mouse currently over the viewport client */ + bool bIsMouseOverClient; }; - - - diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/LODActor.h b/Engine/Source/Runtime/Engine/Classes/Engine/LODActor.h index a7e035588c09..4fa07bd104f0 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/LODActor.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/LODActor.h @@ -25,7 +25,7 @@ class ENGINE_API ALODActor : public AActor { GENERATED_UCLASS_BODY() -private_subobject: +private: // disable display of this component UPROPERTY(Category=LODActor, VisibleAnywhere) UStaticMeshComponent* StaticMeshComponent; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/LatentActionManager.h b/Engine/Source/Runtime/Engine/Classes/Engine/LatentActionManager.h index 68739f1d6702..527db5176298 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/LatentActionManager.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/LatentActionManager.h @@ -10,7 +10,7 @@ class FPendingLatentAction; // Latent action info -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct ENGINE_API FLatentActionInfo { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/LevelStreaming.h b/Engine/Source/Runtime/Engine/Classes/Engine/LevelStreaming.h index 7d7e5f377d31..c4b8b0e329f9 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/LevelStreaming.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/LevelStreaming.h @@ -295,6 +295,14 @@ public: UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true")) ENGINE_API ALevelScriptActor* GetLevelScriptActor(); +#if WITH_EDITOR + /** Get the folder path for this level for use in the world browser. Only available in editor builds */ + ENGINE_API const FName& GetFolderPath() const; + + /** Sets the folder path for this level in the world browser. Only available in editor builds */ + ENGINE_API void SetFolderPath(const FName& InFolderPath); +#endif // WITH_EDITOR + //~============================================================================================== // Delegates @@ -380,6 +388,13 @@ private: UPROPERTY(transient) class ULevel* PendingUnloadLevel; +#if WITH_EDITORONLY_DATA + /** The folder path for this level within the world browser. This is only available in editor builds. + A NONE path indicates that it exists at the root. It is '/' separated. */ + UPROPERTY() + FName FolderPath; +#endif // WITH_EDITORONLY_DATA + /** The cached package name of the world asset that is loaded by the levelstreaming */ FName CachedWorldAssetPackageFName; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/LevelStreamingAlwaysLoaded.h b/Engine/Source/Runtime/Engine/Classes/Engine/LevelStreamingAlwaysLoaded.h index d68f32bdad3e..74acac66a5c5 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/LevelStreamingAlwaysLoaded.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/LevelStreamingAlwaysLoaded.h @@ -19,9 +19,15 @@ class ULevelStreamingAlwaysLoaded : public ULevelStreaming { GENERATED_UCLASS_BODY() + //~ Begin UObject Interface + virtual void GetPrestreamPackages(TArray& OutPrestream) override; + //~ End UObject Interface + //~ Begin ULevelStreaming Interface virtual bool ShouldBeLoaded() const override; virtual bool ShouldBeAlwaysLoaded() const override { return true; } //~ End ULevelStreaming Interface + + }; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/Light.h b/Engine/Source/Runtime/Engine/Classes/Engine/Light.h index 2cf3d81a5ee7..09708592340a 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/Light.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/Light.h @@ -14,13 +14,14 @@ class ENGINE_API ALight : public AActor { GENERATED_UCLASS_BODY() -private_subobject: +private: /** @todo document */ - DEPRECATED_FORGAME(4.6, "LightComponent should not be accessed directly, please use GetLightComponent() function instead. LightComponent will soon be private and your code will not compile.") UPROPERTY(Category = Light, VisibleAnywhere, BlueprintReadOnly, meta = (ExposeFunctionCategories = "Light,Rendering,Rendering|Components|Light", AllowPrivateAccess = "true")) class ULightComponent* LightComponent; public: + virtual void GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const override; + /** replicated copy of LightComponent's bEnabled property */ UPROPERTY(replicatedUsing=OnRep_bEnabled) uint32 bEnabled:1; @@ -77,7 +78,7 @@ public: //~ End AActor Interface. /** Returns LightComponent subobject **/ - class ULightComponent* GetLightComponent() const; + class ULightComponent* GetLightComponent() const { return LightComponent; } }; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/MemberReference.h b/Engine/Source/Runtime/Engine/Classes/Engine/MemberReference.h index ccb86d16d593..ad8052b2b1cf 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/MemberReference.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/MemberReference.h @@ -159,7 +159,7 @@ public: if ((ParentAsClass != NULL) && (SelfScope != NULL)) { #if WITH_EDITOR - UBlueprint::GetGuidFromClassByFieldName((ParentAsClass ? ParentAsClass : SelfScope), MemberName, MemberGuid); + UBlueprint::GetGuidFromClassByFieldName((ParentAsClass), MemberName, MemberGuid); #endif SetGivenSelfScope(MemberName, MemberGuid, ParentAsClass, SelfScope); } diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/NavigationObjectBase.h b/Engine/Source/Runtime/Engine/Classes/Engine/NavigationObjectBase.h index 973ba118dd0a..95c0c1c983b0 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/NavigationObjectBase.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/NavigationObjectBase.h @@ -14,18 +14,15 @@ class ENGINE_API ANavigationObjectBase : public AActor, public INavAgentInterfac { GENERATED_UCLASS_BODY() -private_subobject: - DEPRECATED_FORGAME(4.6, "CapsuleComponent should not be accessed directly, please use GetCapsuleComponent() function instead. CapsuleComponent will soon be private and your code will not compile.") +private: UPROPERTY() class UCapsuleComponent* CapsuleComponent; /** Normal editor sprite. */ - DEPRECATED_FORGAME(4.6, "GoodSprite should not be accessed directly, please use GetGoodSprite() function instead. GoodSprite will soon be private and your code will not compile.") UPROPERTY() class UBillboardComponent* GoodSprite; /** Used to draw bad collision intersection in editor. */ - DEPRECATED_FORGAME(4.6, "BadSprite should not be accessed directly, please use GetBadSprite() function instead. BadSprite will soon be private and your code will not compile.") UPROPERTY() class UBillboardComponent* BadSprite; public: @@ -66,11 +63,11 @@ public: public: /** Returns CapsuleComponent subobject **/ - class UCapsuleComponent* GetCapsuleComponent() const; + class UCapsuleComponent* GetCapsuleComponent() const { return CapsuleComponent; } /** Returns GoodSprite subobject **/ - class UBillboardComponent* GetGoodSprite() const; + class UBillboardComponent* GetGoodSprite() const { return GoodSprite; } /** Returns BadSprite subobject **/ - class UBillboardComponent* GetBadSprite() const; + class UBillboardComponent* GetBadSprite() const { return BadSprite; } }; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/NetDriver.h b/Engine/Source/Runtime/Engine/Classes/Engine/NetDriver.h index 6c1b4ebdb212..5782dacac618 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/NetDriver.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/NetDriver.h @@ -196,6 +196,14 @@ public: UPROPERTY(Config) float ConnectionTimeout; + /** + * A multiplier that is applied to the above values when we are running with unoptimized builds (debug) + * or data (uncooked). This allows us to retain normal timeout behavior while debugging without resorting + * to the nuclear 'notimeouts' option or bumping the values above. If ==0 multiplier = 1 + */ + UPROPERTY(Config) + float TimeoutMultiplierForUnoptimizedBuilds; + /** * If true, ignore timeouts completely. Should be used only in development */ diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/Note.h b/Engine/Source/Runtime/Engine/Classes/Engine/Note.h index 33aedd7422a0..fa751a1780d8 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/Note.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/Note.h @@ -22,13 +22,11 @@ class ANote : public AActor FString Text; // Reference to sprite visualization component -private_subobject: - DEPRECATED_FORGAME(4.6, "SpriteComponent should not be accessed directly, please use GetSpriteComponent() function instead. SpriteComponent will soon be private and your code will not compile.") +private: UPROPERTY() class UBillboardComponent* SpriteComponent; // Reference to arrow visualization component - DEPRECATED_FORGAME(4.6, "ArrowComponent should not be accessed directly, please use GetArrowComponent() function instead. ArrowComponent will soon be private and your code will not compile.") UPROPERTY() class UArrowComponent* ArrowComponent; public: @@ -43,9 +41,9 @@ public: #if WITH_EDITORONLY_DATA /** Returns SpriteComponent subobject **/ - ENGINE_API class UBillboardComponent* GetSpriteComponent() const; + ENGINE_API class UBillboardComponent* GetSpriteComponent() const { return SpriteComponent; } /** Returns ArrowComponent subobject **/ - ENGINE_API class UArrowComponent* GetArrowComponent() const; + ENGINE_API class UArrowComponent* GetArrowComponent() const { return ArrowComponent; } #endif }; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/PlanarReflection.h b/Engine/Source/Runtime/Engine/Classes/Engine/PlanarReflection.h index c87e54c79d28..0806b375ff77 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/PlanarReflection.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/PlanarReflection.h @@ -18,7 +18,7 @@ class APlanarReflection : public ASceneCapture { GENERATED_UCLASS_BODY() -private_subobject: +private: /** Planar reflection component. */ UPROPERTY(Category = SceneCapture, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) class UPlanarReflectionComponent* PlanarReflectionComponent; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/PreviewMeshCollection.h b/Engine/Source/Runtime/Engine/Classes/Engine/PreviewMeshCollection.h index 3b78e271606e..0c5667161105 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/PreviewMeshCollection.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/PreviewMeshCollection.h @@ -6,6 +6,7 @@ #include "UObject/ObjectMacros.h" #include "Engine/SkeletalMesh.h" #include "Engine/DataAsset.h" +#include "PreviewCollectionInterface.h" #include "PreviewMeshCollection.generated.h" class USkeleton; @@ -35,7 +36,7 @@ struct FPreviewMeshCollectionEntry /** A simple collection of skeletal meshes used for in-editor preview */ UCLASS(MinimalAPI, BlueprintType) -class UPreviewMeshCollection : public UDataAsset +class UPreviewMeshCollection : public UDataAsset, public IPreviewCollectionInterface { public: GENERATED_BODY() @@ -46,4 +47,7 @@ public: /** The skeletal meshes that this collection contains */ UPROPERTY(EditAnywhere, Category = "Skeletal Meshes") TArray SkeletalMeshes; + + /** return list of preview skeletalmeshes */ + virtual void GetPreviewSkeletalMeshes(TArray& OutList) const override; }; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/PrimaryAssetLabel.h b/Engine/Source/Runtime/Engine/Classes/Engine/PrimaryAssetLabel.h index 6606a90f9360..21a1bacff587 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/PrimaryAssetLabel.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/PrimaryAssetLabel.h @@ -27,6 +27,10 @@ public: UPROPERTY(EditAnywhere, Category = PrimaryAssetLabel) uint32 bLabelAssetsInMyDirectory : 1; + /** Set to true if the label asset itself should be cooked and available at runtime. This does not affect the assets that are labeled, they are set with cook rule */ + UPROPERTY(EditAnywhere, Category = PrimaryAssetLabel) + uint32 bIsRuntimeLabel : 1; + /** List of manually specified assets to label */ UPROPERTY(EditAnywhere, Category = PrimaryAssetLabel, meta = (AssetBundles = "Explicit")) TArray> ExplicitAssets; @@ -35,6 +39,12 @@ public: UPROPERTY(EditAnywhere, Category = PrimaryAssetLabel, meta = (AssetBundles = "Explicit", BlueprintBaseOnly)) TArray> ExplicitBlueprints; + /** Set to editor only if this is not available in a cooked build */ + virtual bool IsEditorOnly() const + { + return !bIsRuntimeLabel; + } + // TODO add collections #if WITH_EDITORONLY_DATA diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/ReflectionCapture.h b/Engine/Source/Runtime/Engine/Classes/Engine/ReflectionCapture.h index e40b8f179da0..700b5c3171db 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/ReflectionCapture.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/ReflectionCapture.h @@ -14,14 +14,12 @@ class AReflectionCapture : public AActor { GENERATED_UCLASS_BODY() -private_subobject: +private: /** Reflection capture component. */ - DEPRECATED_FORGAME(4.6, "CaptureComponent should not be accessed directly, please use GetCaptureComponent() function instead. CaptureComponent will soon be private and your code will not compile.") UPROPERTY(Category = DecalActor, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) class UReflectionCaptureComponent* CaptureComponent; #if WITH_EDITORONLY_DATA - DEPRECATED_FORGAME(4.6, "SpriteComponent should not be accessed directly, please use GetSpriteComponent() function instead. SpriteComponent will soon be private and your code will not compile.") UPROPERTY() UBillboardComponent* SpriteComponent; @@ -38,10 +36,10 @@ public: #endif // WITH_EDITOR /** Returns CaptureComponent subobject **/ - ENGINE_API class UReflectionCaptureComponent* GetCaptureComponent() const; + ENGINE_API class UReflectionCaptureComponent* GetCaptureComponent() const { return CaptureComponent; } #if WITH_EDITORONLY_DATA /** Returns SpriteComponent subobject **/ - ENGINE_API UBillboardComponent* GetSpriteComponent() const; + ENGINE_API UBillboardComponent* GetSpriteComponent() const { return SpriteComponent; } ENGINE_API UBillboardComponent* GetCaptureOffsetComponent() const { return CaptureOffsetComponent; } #endif }; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/RendererSettings.h b/Engine/Source/Runtime/Engine/Classes/Engine/RendererSettings.h index 5fee394635eb..0407b839871f 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/RendererSettings.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/RendererSettings.h @@ -378,6 +378,12 @@ class ENGINE_API URendererSettings : public UDeveloperSettings ToolTip = "Whether to use original CPU method (loop per morph then by vertex) or use a GPU-based method on Shader Model 5 hardware.")) uint32 bUseGPUMorphTargets : 1; + UPROPERTY(config, EditAnywhere, Category = Debugging, meta = ( + ConsoleVariable = "r.GPUCrashDebugging", DisplayName = "Enable vendor specific GPU crash analysis tools", + ToolTip = "Enables vendor specific GPU crash analysis tools. Currently only supports NVIDIA Aftermath on DX11.", + ConfigRestartRequired = true)) + uint32 bNvidiaAftermathEnabled : 1; + UPROPERTY(config, EditAnywhere, Category=VR, meta=( ConsoleVariable="vr.InstancedStereo", DisplayName="Instanced Stereo", ToolTip="Enable instanced stereo rendering (only available for D3D SM5 or PS4).", diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/Scene.h b/Engine/Source/Runtime/Engine/Classes/Engine/Scene.h index 662470431655..c08b77c10f73 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/Scene.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/Scene.h @@ -56,17 +56,17 @@ enum EBloomMethod BM_MAX, }; -USTRUCT() +USTRUCT(BlueprintType) struct FWeightedBlendable { GENERATED_USTRUCT_BODY() /** 0:no effect .. 1:full effect */ - UPROPERTY(interp, BlueprintReadWrite, Category=FWeightedBlendable, meta=(ClampMin = "0.0", ClampMax = "1.0", Delta = "0.01")) + UPROPERTY(interp, Category=FWeightedBlendable, meta=(ClampMin = "0.0", ClampMax = "1.0", Delta = "0.01")) float Weight; /** should be of the IBlendableInterface* type but UProperties cannot express that */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=FWeightedBlendable, meta=( AllowedClasses="BlendableInterface", Keywords="PostProcess" )) + UPROPERTY(EditAnywhere, Category=FWeightedBlendable, meta=( AllowedClasses="BlendableInterface", Keywords="PostProcess" )) UObject* Object; // default constructor @@ -91,7 +91,7 @@ struct FWeightedBlendables { GENERATED_USTRUCT_BODY() - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="PostProcessSettings", meta=( Keywords="PostProcess" )) + UPROPERTY(EditAnywhere, Category="PostProcessSettings", meta=( Keywords="PostProcess" )) TArray Array; }; @@ -269,7 +269,7 @@ struct FPostProcessSettings UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Overrides, meta=(PinHiddenByDefault, InlineEditConditionToggle)) uint32 bOverride_BloomSizeScale:1; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle)) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Overrides, meta=(PinHiddenByDefault, InlineEditConditionToggle)) uint32 bOverride_BloomConvolutionTexture : 1; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle)) @@ -428,7 +428,7 @@ struct FPostProcessSettings UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Overrides, meta=(PinHiddenByDefault, InlineEditConditionToggle)) uint32 bOverride_LPVEmissiveInjectionIntensity:1; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle)) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Overrides, meta=(PinHiddenByDefault, InlineEditConditionToggle)) uint32 bOverride_LPVFadeRange : 1; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle)) @@ -716,9 +716,7 @@ struct FPostProcessSettings UPROPERTY(interp, BlueprintReadWrite, Category="Lens|Bloom", AdvancedDisplay, meta=(editcondition = "bOverride_Bloom6Tint", DisplayName = "#6 Tint", HideAlphaChannel)) FLinearColor Bloom6Tint; - /** - * Texture that defines the convolution for bloom. - */ + /** Texture to replace default convolution bloom kernel */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Lens|Bloom", meta = (editcondition = "bOverride_BloomConvolutionTexture", DisplayName = "Convolution Kernel")) class UTexture2D* BloomConvolutionTexture; @@ -745,11 +743,11 @@ struct FPostProcessSettings class UTexture* BloomDirtMask; /** BloomDirtMask intensity */ - UPROPERTY(interp, BlueprintReadWrite, Category = "Lens|Dirt Mask", meta = (ClampMin = "0.0", UIMax = "8.0", editcondition = "bOverride_BloomDirtMaskIntensity", DisplayName = "Dirt Mask Intensity")) + UPROPERTY(interp, BlueprintReadWrite, Category="Lens|Dirt Mask", meta=(ClampMin = "0.0", UIMax = "8.0", editcondition = "bOverride_BloomDirtMaskIntensity", DisplayName = "Dirt Mask Intensity")) float BloomDirtMaskIntensity; /** BloomDirtMask tint color */ - UPROPERTY(interp, BlueprintReadWrite, Category = "Lens|Dirt Mask", meta = (editcondition = "bOverride_BloomDirtMaskTint", DisplayName = "Dirt Mask Tint", HideAlphaChannel)) + UPROPERTY(interp, BlueprintReadWrite, Category="Lens|Dirt Mask", meta=(editcondition = "bOverride_BloomDirtMaskTint", DisplayName = "Dirt Mask Tint", HideAlphaChannel)) FLinearColor BloomDirtMaskTint; /** AmbientCubemap tint color */ @@ -1261,7 +1259,7 @@ struct FPostProcessSettings Bloom6Size = 64.0f; BloomConvolutionSize = 1.f; BloomConvolutionCenterUV = FVector2D(0.5f, 0.5f); - BloomConvolutionPreFilter = FVector(0.f, -1.f, 1.f); + BloomConvolutionPreFilter = FVector(7.f, 15000.f, 15.f); BloomConvolutionBufferScale = 0.133f; BloomDirtMaskIntensity = 0.0f; BloomDirtMaskTint = FLinearColor(0.5f, 0.5f, 0.5f); diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/SceneCapture.h b/Engine/Source/Runtime/Engine/Classes/Engine/SceneCapture.h index d88bcb335afc..02953539cfd1 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/SceneCapture.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/SceneCapture.h @@ -17,15 +17,14 @@ class ASceneCapture : public AActor { GENERATED_UCLASS_BODY() -private_subobject: +private: /** To display the 3d camera in the editor. */ - DEPRECATED_FORGAME(4.6, "MeshComp should not be accessed directly, please use GetMeshComp() function instead. MeshComp will soon be private and your code will not compile.") UPROPERTY() class UStaticMeshComponent* MeshComp; public: /** Returns MeshComp subobject **/ - ENGINE_API class UStaticMeshComponent* GetMeshComp() const; + ENGINE_API class UStaticMeshComponent* GetMeshComp() const { return MeshComp; } }; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/SceneCapture2D.h b/Engine/Source/Runtime/Engine/Classes/Engine/SceneCapture2D.h index 3e19bfc5705e..707854c4a7c9 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/SceneCapture2D.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/SceneCapture2D.h @@ -17,13 +17,11 @@ class ASceneCapture2D : public ASceneCapture { GENERATED_UCLASS_BODY() -private_subobject: +private: /** Scene capture component. */ - DEPRECATED_FORGAME(4.6, "CaptureComponent2D should not be accessed directly, please use GetCaptureComponent2D() function instead. CaptureComponent2D will soon be private and your code will not compile.") UPROPERTY(Category = DecalActor, VisibleAnywhere, BlueprintReadOnly, meta=(AllowPrivateAccess = "true")) class USceneCaptureComponent2D* CaptureComponent2D; /** To allow drawing the camera frustum in the editor. */ - DEPRECATED_FORGAME(4.6, "DrawFrustum should not be accessed directly, please use GetDrawFrustum() function instead. DrawFrustum will soon be private and your code will not compile.") UPROPERTY() class UDrawFrustumComponent* DrawFrustum; @@ -40,9 +38,9 @@ public: void OnInterpToggle(bool bEnable); /** Returns CaptureComponent2D subobject **/ - ENGINE_API class USceneCaptureComponent2D* GetCaptureComponent2D() const; + ENGINE_API class USceneCaptureComponent2D* GetCaptureComponent2D() const { return CaptureComponent2D; } /** Returns DrawFrustum subobject **/ - ENGINE_API class UDrawFrustumComponent* GetDrawFrustum() const; + ENGINE_API class UDrawFrustumComponent* GetDrawFrustum() const { return DrawFrustum; } }; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/SceneCaptureCube.h b/Engine/Source/Runtime/Engine/Classes/Engine/SceneCaptureCube.h index cc75d6529b8e..d6058b0323fc 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/SceneCaptureCube.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/SceneCaptureCube.h @@ -17,14 +17,12 @@ class ENGINE_API ASceneCaptureCube : public ASceneCapture { GENERATED_UCLASS_BODY() -private_subobject: +private: /** Scene capture component. */ - DEPRECATED_FORGAME(4.6, "CaptureComponentCube should not be accessed directly, please use GetCaptureComponentCube() function instead. CaptureComponentCube will soon be private and your code will not compile.") UPROPERTY(Category = DecalActor, VisibleAnywhere, BlueprintReadOnly, meta=(AllowPrivateAccess = "true")) class USceneCaptureComponentCube* CaptureComponentCube; /** To allow drawing the camera frustum in the editor. */ - DEPRECATED_FORGAME(4.6, "DrawFrustum should not be accessed directly, please use GetDrawFrustum() function instead. DrawFrustum will soon be private and your code will not compile.") UPROPERTY() class UDrawFrustumComponent* DrawFrustum; @@ -44,9 +42,9 @@ public: void OnInterpToggle(bool bEnable); /** Returns CaptureComponentCube subobject **/ - class USceneCaptureComponentCube* GetCaptureComponentCube() const; + class USceneCaptureComponentCube* GetCaptureComponentCube() const { return CaptureComponentCube; } /** Returns DrawFrustum subobject **/ - class UDrawFrustumComponent* GetDrawFrustum() const; + class UDrawFrustumComponent* GetDrawFrustum() const { return DrawFrustum; } }; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/Selection.h b/Engine/Source/Runtime/Engine/Classes/Engine/Selection.h index 53875f62f68d..8e11268cd1c1 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/Selection.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/Selection.h @@ -67,6 +67,9 @@ public: USelection(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); + /** Initializes the selection set with an annotation used to quickly look up selection state */ + void Initialize(FUObjectAnnotationSparseBool* InSelectionAnnotation); + typedef ClassArray::TIterator TClassIterator; typedef ClassArray::TConstIterator TClassConstIterator; @@ -330,6 +333,8 @@ public: //~ Begin UObject Interface virtual void Serialize(FArchive& Ar) override; virtual bool Modify( bool bAlwaysMarkDirty=true) override; + virtual void BeginDestroy() override; + //~ End UObject Interface @@ -386,6 +391,10 @@ protected: /** Tracks whether the selection set changed during a batch selection operation */ bool bIsBatchDirty; + /** Selection annotation for fast lookup */ + FUObjectAnnotationSparseBool* SelectionAnnotation; + + bool bOwnsSelectionAnnotation; private: // Hide IsSelected(), as calling IsSelected() on a selection set almost always indicates // an error where the caller should use IsSelected(UObject* InObject). diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/SkeletalMesh.h b/Engine/Source/Runtime/Engine/Classes/Engine/SkeletalMesh.h index b99220617b3a..a30b0fe92b1f 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/SkeletalMesh.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/SkeletalMesh.h @@ -427,7 +427,7 @@ struct FClothingAssetData_Legacy }; //~ Begin Material Interface for USkeletalMesh - contains a material and a shadow casting flag -USTRUCT() +USTRUCT(BlueprintType) struct FSkeletalMaterial { GENERATED_USTRUCT_BODY() @@ -466,7 +466,7 @@ struct FSkeletalMaterial ENGINE_API friend bool operator==( const FSkeletalMaterial& LHS, const UMaterialInterface& RHS ); ENGINE_API friend bool operator==( const UMaterialInterface& LHS, const FSkeletalMaterial& RHS ); - UPROPERTY(EditAnywhere, BlueprintReadOnly, transient, Category=SkeletalMesh) + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=SkeletalMesh) class UMaterialInterface * MaterialInterface; UPROPERTY() bool bEnableShadowCasting_DEPRECATED; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/SkyLight.h b/Engine/Source/Runtime/Engine/Classes/Engine/SkyLight.h index 044399627163..165a286ed712 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/SkyLight.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/SkyLight.h @@ -12,9 +12,10 @@ class ENGINE_API ASkyLight : public AInfo { GENERATED_UCLASS_BODY() -private_subobject: + virtual void GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const override; + +private: /** @todo document */ - DEPRECATED_FORGAME(4.6, "LightComponent should not be accessed directly, please use GetLightComponent() function instead. LightComponent will soon be private and your code will not compile.") UPROPERTY(Category = Light, VisibleAnywhere, BlueprintReadOnly, meta = (ExposeFunctionCategories = "Light,Rendering,Rendering|Components|SkyLight", AllowPrivateAccess = "true")) class USkyLightComponent* LightComponent; public: @@ -28,7 +29,7 @@ public: virtual void OnRep_bEnabled(); /** Returns LightComponent subobject **/ - class USkyLightComponent* GetLightComponent() const; + class USkyLightComponent* GetLightComponent() const { return LightComponent; } }; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/SphereReflectionCapture.h b/Engine/Source/Runtime/Engine/Classes/Engine/SphereReflectionCapture.h index 613010c388d7..f3ae3c93e06a 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/SphereReflectionCapture.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/SphereReflectionCapture.h @@ -18,9 +18,8 @@ class ASphereReflectionCapture : public AReflectionCapture { GENERATED_UCLASS_BODY() -private_subobject: +private: /** Sphere component used to visualize the capture radius */ - DEPRECATED_FORGAME(4.6, "DrawCaptureRadius should not be accessed directly, please use GetDrawCaptureRadius() function instead. DrawCaptureRadius will soon be private and your code will not compile.") UPROPERTY() UDrawSphereComponent* DrawCaptureRadius; @@ -33,7 +32,7 @@ public: #endif /** Returns DrawCaptureRadius subobject **/ - ENGINE_API UDrawSphereComponent* GetDrawCaptureRadius() const; + ENGINE_API UDrawSphereComponent* GetDrawCaptureRadius() const { return DrawCaptureRadius; } }; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/SplineMeshActor.h b/Engine/Source/Runtime/Engine/Classes/Engine/SplineMeshActor.h index 73de66b25218..9aaed18b2fc4 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/SplineMeshActor.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/SplineMeshActor.h @@ -17,7 +17,7 @@ class ENGINE_API ASplineMeshActor : public AActor { GENERATED_UCLASS_BODY() -private_subobject: +private: UPROPERTY(Category = SplineMeshActor, VisibleAnywhere, BlueprintReadOnly, meta = (ExposeFunctionCategories = "Mesh,Rendering,Physics,Components|StaticMesh,Components|SplineMesh", AllowPrivateAccess = "true")) class USplineMeshComponent* SplineMeshComponent; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/SpotLight.h b/Engine/Source/Runtime/Engine/Classes/Engine/SpotLight.h index 6b5390a6c006..66580d531ca0 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/SpotLight.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/SpotLight.h @@ -17,8 +17,7 @@ class ASpotLight : public ALight #if WITH_EDITORONLY_DATA // Reference to editor arrow component visualization -private_subobject: - DEPRECATED_FORGAME(4.6, "ArrowComponent should not be accessed directly, please use GetArrowComponent() function instead. ArrowComponent will soon be private and your code will not compile.") +private: UPROPERTY() class UArrowComponent* ArrowComponent; public: @@ -53,7 +52,7 @@ public: public: #if WITH_EDITORONLY_DATA /** Returns ArrowComponent subobject **/ - ENGINE_API class UArrowComponent* GetArrowComponent() const; + ENGINE_API class UArrowComponent* GetArrowComponent() const { return ArrowComponent; } #endif }; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/StaticMesh.h b/Engine/Source/Runtime/Engine/Classes/Engine/StaticMesh.h index a370c8fc4a15..3f08b9324648 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/StaticMesh.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/StaticMesh.h @@ -310,7 +310,7 @@ DECLARE_MULTICAST_DELEGATE_OneParam(FOnPostMeshBuild, class UStaticMesh*); #endif //~ Begin Material Interface for UStaticMesh - contains a material and other stuff -USTRUCT() +USTRUCT(BlueprintType) struct FStaticMaterial { GENERATED_USTRUCT_BODY() @@ -347,7 +347,7 @@ struct FStaticMaterial ENGINE_API friend bool operator==(const FStaticMaterial& LHS, const UMaterialInterface& RHS); ENGINE_API friend bool operator==(const UMaterialInterface& LHS, const FStaticMaterial& RHS); - UPROPERTY(EditAnywhere, BlueprintReadOnly, transient, Category = StaticMesh) + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = StaticMesh) class UMaterialInterface* MaterialInterface; /*This name should be use by the gameplay to avoid error if the skeletal mesh Materials array topology change*/ @@ -413,6 +413,11 @@ class UStaticMesh : public UObject, public IInterface_CollisionDataProvider, pub { GENERATED_UCLASS_BODY() +#if WITH_EDITOR + /** Notification when bounds changed */ + DECLARE_MULTICAST_DELEGATE_OneParam(FOnExtendedBoundsChanged, const FBoxSphereBounds&); +#endif + /** Pointer to the data used to render this static mesh. */ TUniquePtr RenderData; @@ -514,9 +519,13 @@ class UStaticMesh : public UObject, public IInterface_CollisionDataProvider, pub UPROPERTY(EditAnywhere, AdvancedDisplay, Category=Navigation) uint32 bHasNavigationData:1; - /** If true, mesh will calculate data for fast uniform random sampling. This is approx 8 bytes per triangle so should not be enabled unless needed. */ + /** + Mesh supports uniformly distributed sampling in constant time. + Memory cost is 8 bytes per triangle. + Example usage is uniform spawning of particles. + */ UPROPERTY(EditAnywhere, AdvancedDisplay, Category = StaticMesh) - uint32 bRequiresAreaWeightedSampling : 1; + uint32 bSupportUniformlyDistributedSampling : 1; /** Bias multiplier for Light Propagation Volume lighting */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=StaticMesh, meta=(UIMin = "0.0", UIMax = "3.0")) @@ -591,6 +600,10 @@ class UStaticMesh : public UObject, public IInterface_CollisionDataProvider, pub UPROPERTY() FBoxSphereBounds ExtendedBounds; +#if WITH_EDITOR + FOnExtendedBoundsChanged OnExtendedBoundsChanged; +#endif + protected: /** * Index of an element to ignore while gathering streaming texture factors. @@ -625,7 +638,10 @@ public: ENGINE_API virtual void GetAssetRegistryTagMetadata(TMap& OutMetadata) const override; ENGINE_API void SetLODGroup(FName NewGroup, bool bRebuildImmediately = true); ENGINE_API void BroadcastNavCollisionChange(); + + FOnExtendedBoundsChanged& GetOnExtendedBoundsChanged() { return OnExtendedBoundsChanged; } #endif // WITH_EDITOR + ENGINE_API virtual void Serialize(FArchive& Ar) override; ENGINE_API virtual void PostInitProperties() override; ENGINE_API virtual void PostLoad() override; @@ -716,6 +732,7 @@ public: * * @return Requested material */ + UFUNCTION(BlueprintCallable, Category = "StaticMesh") ENGINE_API UMaterialInterface* GetMaterial(int32 MaterialIndex) const; /** @@ -723,6 +740,7 @@ public: * * @return Requested material */ + UFUNCTION(BlueprintCallable, Category = "StaticMesh") ENGINE_API int32 GetMaterialIndex(FName MaterialSlotName) const; /** diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/StaticMeshActor.h b/Engine/Source/Runtime/Engine/Classes/Engine/StaticMeshActor.h index 15486ac5be10..9ba1ca4fc2c3 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/StaticMeshActor.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/StaticMeshActor.h @@ -21,8 +21,7 @@ class ENGINE_API AStaticMeshActor : public AActor { GENERATED_UCLASS_BODY() -private_subobject: - DEPRECATED_FORGAME(4.6, "StaticMeshComponent should not be accessed directly, please use GetStaticMeshComponent() function instead. StaticMeshComponent will soon be private and your code will not compile.") +private: UPROPERTY(Category = StaticMeshActor, VisibleAnywhere, BlueprintReadOnly, meta = (ExposeFunctionCategories = "Mesh,Rendering,Physics,Components|StaticMesh", AllowPrivateAccess = "true")) class UStaticMeshComponent* StaticMeshComponent; @@ -64,7 +63,7 @@ protected: public: /** Returns StaticMeshComponent subobject **/ - class UStaticMeshComponent* GetStaticMeshComponent() const; + class UStaticMeshComponent* GetStaticMeshComponent() const { return StaticMeshComponent; } }; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/StreamableManager.h b/Engine/Source/Runtime/Engine/Classes/Engine/StreamableManager.h index 7ec5796fd05e..396b33e56e60 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/StreamableManager.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/StreamableManager.h @@ -297,7 +297,7 @@ private: UObject* GetStreamed(const FStringAssetReference& Target) const; void CheckCompletedRequests(const FStringAssetReference& Target, struct FStreamable* Existing); - void OnPostGarbageCollect(); + void OnPreGarbageCollect(); void AsyncLoadCallback(FStringAssetReference Request); /** Map of paths to streamable objects, this will be the post-redirector name */ diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/TargetPoint.h b/Engine/Source/Runtime/Engine/Classes/Engine/TargetPoint.h index 972c150fdae6..80a1296788f6 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/TargetPoint.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/TargetPoint.h @@ -17,12 +17,10 @@ class ATargetPoint : public AActor GENERATED_UCLASS_BODY() #if WITH_EDITORONLY_DATA -private_subobject: - DEPRECATED_FORGAME(4.6, "SpriteComponent should not be accessed directly, please use GetSpriteComponent() function instead. SpriteComponent will soon be private and your code will not compile.") +private: UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Display, meta = (AllowPrivateAccess = "true")) class UBillboardComponent* SpriteComponent; - DEPRECATED_FORGAME(4.6, "ArrowComponent should not be accessed directly, please use GetArrowComponent() function instead. ArrowComponent will soon be private and your code will not compile.") UPROPERTY() class UArrowComponent* ArrowComponent; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/TextRenderActor.h b/Engine/Source/Runtime/Engine/Classes/Engine/TextRenderActor.h index 5f8fd9dec93d..373aa96e0419 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/TextRenderActor.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/TextRenderActor.h @@ -20,25 +20,23 @@ class ATextRenderActor : public AActor friend class UActorFactoryTextRender; -private_subobject: +private: /** Component to render a text in 3d with a font */ - DEPRECATED_FORGAME(4.6, "TextRender should not be accessed directly, please use GetTextRender() function instead. TextRender will soon be private and your code will not compile.") UPROPERTY(Category = TextRenderActor, VisibleAnywhere, BlueprintReadOnly, meta = (ExposeFunctionCategories = "Rendering|Components|TextRender", AllowPrivateAccess = "true")) class UTextRenderComponent* TextRender; #if WITH_EDITORONLY_DATA // Reference to the billboard component - DEPRECATED_FORGAME(4.6, "SpriteComponent should not be accessed directly, please use GetSpriteComponent() function instead. SpriteComponent will soon be private and your code will not compile.") UPROPERTY() UBillboardComponent* SpriteComponent; #endif public: /** Returns TextRender subobject **/ - ENGINE_API class UTextRenderComponent* GetTextRender() const; + ENGINE_API class UTextRenderComponent* GetTextRender() const { return TextRender; } #if WITH_EDITORONLY_DATA /** Returns SpriteComponent subobject **/ - ENGINE_API UBillboardComponent* GetSpriteComponent() const; + ENGINE_API UBillboardComponent* GetSpriteComponent() const { return SpriteComponent; } #endif }; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/Texture.h b/Engine/Source/Runtime/Engine/Classes/Engine/Texture.h index bec7bec4ebb2..8e5ca246767b 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/Texture.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/Texture.h @@ -342,8 +342,8 @@ struct FTexturePlatformData void Cache( class UTexture& InTexture, const struct FTextureBuildSettings& InSettings, - uint32 InFlags - ); + uint32 InFlags, + class ITextureCompressorModule* Compressor); void FinishCache(); ENGINE_API bool TryInlineMipData(); bool AreDerivedMipsAvailable() const; @@ -649,7 +649,7 @@ public: * @param bAsyncCache spawn a thread to cache the platform data * @param bAllowAsyncBuild allow the building of the texture to happen on another thread !!!load BulkData and cache the Source mip data on the main thread before checking DDC!!! */ - void CachePlatformData(bool bAsyncCache = false, bool bAllowAsyncBuild = false); + void CachePlatformData(bool bAsyncCache = false, bool bAllowAsyncBuild = false, class ITextureCompressorModule* Compressor = nullptr); /** * Begins caching platform data in the background for the platform requested diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/Texture2D.h b/Engine/Source/Runtime/Engine/Classes/Engine/Texture2D.h index 28f3cfe4133c..de650cc3945c 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/Texture2D.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/Texture2D.h @@ -265,7 +265,7 @@ public: /** * Returns the number of mips in this texture that are not able to be streamed. */ - int32 GetNumNonStreamingMips() const; + ENGINE_API int32 GetNumNonStreamingMips() const; /** * Computes the minimum and maximum allowed mips for a texture. diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/TextureRenderTarget2D.h b/Engine/Source/Runtime/Engine/Classes/Engine/TextureRenderTarget2D.h index 1b8b8135a6b4..20e152cf4b5d 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/TextureRenderTarget2D.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/TextureRenderTarget2D.h @@ -15,6 +15,51 @@ struct FPropertyChangedEvent; extern ENGINE_API int32 GTextureRenderTarget2DMaxSizeX; extern ENGINE_API int32 GTextureRenderTarget2DMaxSizeY; +/** Subset of EPixelFormat exposed to UTextureRenderTarget2D */ +UENUM() +enum ETextureRenderTargetFormat +{ + /** R channel, 8 bit per channel fixed point, range [0, 1]. */ + RTF_R8, + /** RG channels, 8 bit per channel fixed point, range [0, 1]. */ + RTF_RG8, + /** RGBA channels, 8 bit per channel fixed point, range [0, 1]. */ + RTF_RGBA8, + /** R channel, 16 bit per channel floating point, range [-65504, 65504] */ + RTF_R16f, + /** RG channels, 16 bit per channel floating point, range [-65504, 65504] */ + RTF_RG16f, + /** RGBA channels, 16 bit per channel floating point, range [-65504, 65504] */ + RTF_RGBA16f, + /** R channel, 32 bit per channel floating point, range [-3.402823 x 10^38, 3.402823 x 10^38] */ + RTF_R32f, + /** RG channels, 32 bit per channel floating point, range [-3.402823 x 10^38, 3.402823 x 10^38] */ + RTF_RG32f, + /** RGBA channels, 32 bit per channel floating point, range [-3.402823 x 10^38, 3.402823 x 10^38] */ + RTF_RGBA32f +}; + +inline EPixelFormat GetPixelFormatFromRenderTargetFormat(ETextureRenderTargetFormat RTFormat) +{ + switch (RTFormat) + { + case RTF_R8: return PF_G8; break; + case RTF_RG8: return PF_R8G8; break; + case RTF_RGBA8: return PF_B8G8R8A8; break; + + case RTF_R16f: return PF_R16F; break; + case RTF_RG16f: return PF_G16R16F; break; + case RTF_RGBA16f: return PF_FloatRGBA; break; + + case RTF_R32f: return PF_R32_FLOAT; break; + case RTF_RG32f: return PF_G32R32F; break; + case RTF_RGBA32f: return PF_A32B32G32R32F; break; + } + + ensureMsgf(false, TEXT("Unhandled ETextureRenderTargetFormat entry %u"), (uint32)RTFormat); + return PF_Unknown; +} + /** * TextureRenderTarget2D * @@ -22,7 +67,7 @@ extern ENGINE_API int32 GTextureRenderTarget2DMaxSizeY; * for rendering as well as rendered as a regular 2D texture resource. * */ -UCLASS(hidecategories=Object, hidecategories=Texture, MinimalAPI) +UCLASS(hidecategories=Object, hidecategories=Texture, hidecategories=Compression, hidecategories=Adjustments, hidecategories=Compositing, MinimalAPI) class UTextureRenderTarget2D : public UTextureRenderTarget { GENERATED_UCLASS_BODY() @@ -52,8 +97,17 @@ class UTextureRenderTarget2D : public UTextureRenderTarget uint32 bForceLinearGamma:1; /** Whether to support storing HDR values, which requires more memory. */ + UPROPERTY() + uint32 bHDR_DEPRECATED:1; + + /** + * Format of the texture render target. + * Data written to the render target will be quantized to this format, which can limit the range and precision. + * The largest format (RTF_RGBA32f) uses 16x more memory and bandwidth than the smallest (RTF_R8) and can greatly affect performance. + * Use the smallest format that has enough precision and range for what you are doing. + */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=TextureRenderTarget2D, AssetRegistrySearchable) - uint32 bHDR:1; + TEnumAsByte RenderTargetFormat; /** Whether to support GPU sharing of the underlying native texture resource. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = TextureRenderTarget2D, meta=(DisplayName = "Shared"), AssetRegistrySearchable, AdvancedDisplay) @@ -63,7 +117,7 @@ class UTextureRenderTarget2D : public UTextureRenderTarget UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=TextureRenderTarget2D, AssetRegistrySearchable) uint32 bAutoGenerateMips:1; - /** Normally the format is derived from bHDR, this allows code to set the format explicitly. */ + /** Normally the format is derived from RenderTargetFormat, this allows code to set the format explicitly. */ UPROPERTY() TEnumAsByte OverrideFormat; @@ -109,6 +163,7 @@ class UTextureRenderTarget2D : public UTextureRenderTarget #if WITH_EDITOR ENGINE_API virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; #endif // WITH_EDITOR + ENGINE_API virtual void Serialize(FArchive& Ar) override; ENGINE_API virtual void PostLoad() override; ENGINE_API virtual void GetResourceSizeEx(FResourceSizeEx& CumulativeResourceSize) override; ENGINE_API virtual FString GetDesc() override; @@ -124,7 +179,7 @@ class UTextureRenderTarget2D : public UTextureRenderTarget { if (OverrideFormat == PF_Unknown) { - return bHDR ? PF_FloatRGBA : PF_B8G8R8A8; + return GetPixelFormatFromRenderTargetFormat(RenderTargetFormat); } else { diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/UserInterfaceSettings.h b/Engine/Source/Runtime/Engine/Classes/Engine/UserInterfaceSettings.h index 46d03e5786e7..7bb663ddc94e 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/UserInterfaceSettings.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/UserInterfaceSettings.h @@ -7,6 +7,8 @@ #include "Misc/StringClassReference.h" #include "Curves/CurveFloat.h" #include "Engine/DeveloperSettings.h" +#include "Widgets/SWidget.h" + #include "UserInterfaceSettings.generated.h" class UDPICustomScalingRule; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/WindDirectionalSource.h b/Engine/Source/Runtime/Engine/Classes/Engine/WindDirectionalSource.h index 159c9be73e62..557a6705859a 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/WindDirectionalSource.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/WindDirectionalSource.h @@ -12,24 +12,22 @@ class ENGINE_API AWindDirectionalSource : public AInfo { GENERATED_UCLASS_BODY() -private_subobject: - DEPRECATED_FORGAME(4.6, "Component should not be accessed directly, please use GetComponent() function instead. Component will soon be private and your code will not compile.") +private: UPROPERTY(Category = WindDirectionalSource, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) class UWindDirectionalSourceComponent* Component; #if WITH_EDITORONLY_DATA - DEPRECATED_FORGAME(4.6, "ArrowComponent should not be accessed directly, please use GetArrowComponent() function instead. ArrowComponent will soon be private and your code will not compile.") UPROPERTY() class UArrowComponent* ArrowComponent; #endif public: /** Returns Component subobject **/ - class UWindDirectionalSourceComponent* GetComponent() const; + class UWindDirectionalSourceComponent* GetComponent() const { return Component; } #if WITH_EDITORONLY_DATA /** Returns ArrowComponent subobject **/ - class UArrowComponent* GetArrowComponent() const; + class UArrowComponent* GetArrowComponent() const { return ArrowComponent; } #endif }; diff --git a/Engine/Source/Runtime/Engine/Classes/Engine/World.h b/Engine/Source/Runtime/Engine/Classes/Engine/World.h index 65442f4a35e1..5bdc403c5607 100644 --- a/Engine/Source/Runtime/Engine/Classes/Engine/World.h +++ b/Engine/Source/Runtime/Engine/Classes/Engine/World.h @@ -1152,6 +1152,16 @@ public: /** When non-'None', all line traces where the TraceTag match this will be drawn */ FName DebugDrawTraceTag; + /** When set to true, all scene queries will be drawn */ + bool bDebugDrawAllTraceTags; + +#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) + bool DebugDrawSceneQueries(const FName& UsedTraceTag) const + { + return (bDebugDrawAllTraceTags || ((DebugDrawTraceTag != NAME_None) && (DebugDrawTraceTag == UsedTraceTag))) && IsInGameThread(); + } +#endif + /** An array of post processing volumes, sorted in ascending order of priority. */ TArray< IInterface_PostProcessVolume * > PostProcessVolumes; @@ -2113,7 +2123,7 @@ public: virtual void Serialize( FArchive& Ar ) override; virtual void FinishDestroy() override; virtual void PostLoad() override; - virtual bool PreSaveRoot(const TCHAR* Filename, TArray& AdditionalPackagesToCook) override; + virtual bool PreSaveRoot(const TCHAR* Filename) override; virtual void PostSaveRoot( bool bCleanupIsRequired ) override; virtual UWorld* GetWorld() const override; virtual FPrimaryAssetId GetPrimaryAssetId() const override; @@ -2182,7 +2192,7 @@ public: ULevel* GetActiveLightingScenario() const; /** Propagates a change to the active lighting scenario. */ - void PropagateLightingScenarioChange(); + void PropagateLightingScenarioChange(bool bLevelWasMadeVisible); /** * Associates the passed in level with the world. The work to make the level visible is spread across several frames and this @@ -3019,7 +3029,10 @@ public: /** Returns true if this world is any kind of game world (including PIE worlds) */ bool IsGameWorld() const; - /** Returns true if this world is a preview game world (blueprint editor) */ + /** Returns true if this world is any kind of editor world (including editor preview worlds) */ + bool IsEditorWorld() const; + + /** Returns true if this world is a preview game world (editor or game) */ bool IsPreviewWorld() const; /** Returns true if this world should look at game hidden flags instead of editor hidden flags for the purposes of rendering */ @@ -3157,6 +3170,20 @@ public: return OwningGameInstance; } + /** Returns the OwningGameInstance cast to the template type. */ + template + T* GetGameInstance() const + { + return Cast(OwningGameInstance); + } + + /** Returns the OwningGameInstance cast to the template type, asserting that it is of the correct type. */ + template + T* GetGameInstanceChecked() const + { + return CastChecked(OwningGameInstance); + } + /** Retrieves information whether all navigation with this world has been rebuilt */ bool IsNavigationRebuilt() const; diff --git a/Engine/Source/Runtime/Engine/Classes/GameFramework/Actor.h b/Engine/Source/Runtime/Engine/Classes/GameFramework/Actor.h index e99a732b113f..da47569c8ce7 100644 --- a/Engine/Source/Runtime/Engine/Classes/GameFramework/Actor.h +++ b/Engine/Source/Runtime/Engine/Classes/GameFramework/Actor.h @@ -63,6 +63,11 @@ DECLARE_DELEGATE_RetVal_ThreeParams(bool, FOnProcessEvent, AActor*, UFunction*, DECLARE_CYCLE_STAT_EXTERN(TEXT("GetComponentsTime"),STAT_GetComponentsTime,STATGROUP_Engine,ENGINE_API); +#if WITH_EDITOR +/** Annotation for actor selection. This must be in engine instead of editor for ::IsSelected to work */ +extern ENGINE_API FUObjectAnnotationSparseBool GSelectedActorAnnotation; +#endif + /** * Actor is the base class for an Object that can be placed or spawned in a level. * Actors may contain a collection of ActorComponents, which can be used to control how actors move, how they are rendered, etc. @@ -383,9 +388,14 @@ public: /** Called on the actor when a subobject is dynamically destroyed via replication */ virtual void OnSubobjectDestroyFromReplication(UObject *Subobject); - /** Called on the actor right before replication occurs */ + /** Called on the actor right before replication occurs. + * Only called on Server, and for autonomous proxies if recording a Client Replay. */ virtual void PreReplication( IRepChangedPropertyTracker & ChangedPropertyTracker ); + /** Called on the actor right before replication occurs. + * Called for everyone when recording a Client Replay, including Simulated Proxies. */ + virtual void PreReplicationForReplay(IRepChangedPropertyTracker & ChangedPropertyTracker); + /** Called by the networking system to call PreReplication on this actor and its components using the given NetDriver to find or create RepChangedPropertyTrackers. */ void CallPreReplication(UNetDriver* NetDriver); @@ -459,7 +469,7 @@ protected: /** * Collision primitive that defines the transform (location, rotation, scale) of this Actor. */ - UPROPERTY() + UPROPERTY(BlueprintGetter=K2_GetRootComponent, Category="Utilities|Transformation") USceneComponent* RootComponent; #if WITH_EDITORONLY_DATA @@ -748,11 +758,7 @@ public: /** Get the local-to-world transform of the RootComponent. Identical to GetTransform(). */ FORCEINLINE FTransform ActorToWorld() const { - if( RootComponent != NULL ) - { - return RootComponent->ComponentToWorld; - } - return FTransform::Identity; + return (RootComponent ? RootComponent->GetComponentTransform() : FTransform::Identity); } @@ -799,7 +805,7 @@ public: void GetActorBounds(bool bOnlyCollidingComponents, FVector& Origin, FVector& BoxExtent) const; /** Returns the RootComponent of this Actor */ - UFUNCTION(BlueprintCallable, meta=(DisplayName = "GetRootComponent"), Category="Utilities|Transformation") + UFUNCTION(BlueprintGetter) USceneComponent* K2_GetRootComponent() const; /** Returns velocity (in cm/s (Unreal Units/second) of the rootcomponent if it is either using physics or has an associated MovementComponent */ @@ -1123,6 +1129,7 @@ public: class UActorComponent* AddComponent(FName TemplateName, bool bManualAttachment, const FTransform& RelativeTransform, const UObject* ComponentTemplateContext); /** DEPRECATED - Use Component::DestroyComponent */ + DEPRECATED(4.17, "Use Component.DestroyComponent instead") UFUNCTION(BlueprintCallable, meta=(DeprecatedFunction, DeprecationMessage = "Use Component.DestroyComponent instead", BlueprintProtected = "true", DisplayName = "DestroyComponent")) void K2_DestroyComponent(UActorComponent* Component); @@ -1137,6 +1144,7 @@ public: * Attaches the RootComponent of this Actor to the supplied component, optionally at a named socket. It is not valid to call this on components that are not Registered. * @param AttachLocationType Type of attachment, AbsoluteWorld to keep its world position, RelativeOffset to keep the object's relative offset and SnapTo to snap to the new parent. */ + DEPRECATED(4.17, "Use AttachToComponent instead.") UFUNCTION(BlueprintCallable, meta = (DisplayName = "AttachActorToComponent (Deprecated)", AttachLocationType = "KeepRelativeOffset"), Category = "Utilities|Transformation") void K2_AttachRootComponentTo(USceneComponent* InParent, FName InSocketName = NAME_None, EAttachLocation::Type AttachLocationType = EAttachLocation::KeepRelativeOffset, bool bWeldSimulatedBodies = true); @@ -1172,7 +1180,7 @@ public: * Attaches the RootComponent of this Actor to the supplied component, optionally at a named socket. It is not valid to call this on components that are not Registered. * @param AttachLocationType Type of attachment, AbsoluteWorld to keep its world position, RelativeOffset to keep the object's relative offset and SnapTo to snap to the new parent. */ - + DEPRECATED(4.17, "Use AttachToActor instead.") UFUNCTION(BlueprintCallable, meta = (DisplayName = "AttachActorToActor (Deprecated)", AttachLocationType = "KeepRelativeOffset"), Category = "Utilities|Transformation") void K2_AttachRootComponentToActor(AActor* InParentActor, FName InSocketName = NAME_None, EAttachLocation::Type AttachLocationType = EAttachLocation::KeepRelativeOffset, bool bWeldSimulatedBodies = true); @@ -1200,6 +1208,7 @@ public: * Snap the RootComponent of this Actor to the supplied Actor's root component, optionally at a named socket. It is not valid to call this on components that are not Registered. * If InSocketName == NAME_None, it will attach to origin of the InParentActor. */ + DEPRECATED(4.17, "Use AttachRootComponentTo with EAttachLocation::SnapToTarget option instead") UFUNCTION(BlueprintCallable, meta=(DeprecatedFunction, DeprecationMessage = "Use AttachRootComponentTo with EAttachLocation::SnapToTarget option instead", DisplayName = "SnapActorTo"), Category="Utilities|Transformation") void SnapRootComponentTo(AActor* InParentActor, FName InSocketName); @@ -1207,6 +1216,7 @@ public: * Detaches the RootComponent of this Actor from any SceneComponent it is currently attached to. * @param bMaintainWorldTransform If true, update the relative location/rotation of this component to keep its world position the same */ + DEPRECATED(4.17, "Use DetachFromActor instead") UFUNCTION(BlueprintCallable, meta=(DisplayName = "DetachActorFromActor (Deprecated)"), Category="Utilities|Transformation") void DetachRootComponentFromParent(bool bMaintainWorldPosition = true); @@ -1286,6 +1296,7 @@ public: void SetTickableWhenPaused(bool bTickableWhenPaused); /** Allocate a MID for a given parent material. */ + DEPRECATED(4.17, "Use PrimitiveComponent.CreateAndSetMaterialInstanceDynamic instead.") UFUNCTION(BlueprintCallable, meta=(DeprecatedFunction, DeprecationMessage="Use PrimitiveComponent.CreateAndSetMaterialInstanceDynamic instead.", BlueprintProtected = "true"), Category="Rendering|Material") class UMaterialInstanceDynamic* MakeMIDForMaterial(class UMaterialInterface* Parent); @@ -1543,6 +1554,7 @@ public: virtual void PreEditUndo() override; virtual void PostEditUndo() override; virtual void PostEditImport() override; + virtual bool IsSelectedInEditor() const override; struct FActorRootComponentReconstructionData { @@ -1730,12 +1742,14 @@ public: * Simple accessor to check if the actor is hidden upon editor startup * @return true if the actor is hidden upon editor startup; false if it is not */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Actor Editing") bool IsHiddenEdAtStartup() const { return bHiddenEd; } // Returns true if this actor is hidden in the editor viewports. + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Actor Editing") bool IsHiddenEd() const; /** @@ -1743,18 +1757,22 @@ public: * * @param bIsHidden True if the actor is hidden */ + UFUNCTION(BlueprintCallable, Category="Editor Scripting | Actor Editing") virtual void SetIsTemporarilyHiddenInEditor( bool bIsHidden ); /** * @param bIncludeParent - Whether to recurse up child actor hierarchy or not * @return Whether or not this actor is hidden in the editor for the duration of the current editor session */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Actor Editing") bool IsTemporarilyHiddenInEditor(bool bIncludeParent = false) const; /** @return Returns true if this actor is allowed to be displayed, selected and manipulated by the editor. */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Actor Editing") bool IsEditable() const; /** @return Returns true if this actor can EVER be selected in a level in the editor. Can be overridden by specific actors to make them unselectable. */ + UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Actor Editing") virtual bool IsSelectable() const { return true; } /** @return Returns true if this actor should be shown in the scene outliner */ diff --git a/Engine/Source/Runtime/Engine/Classes/GameFramework/Character.h b/Engine/Source/Runtime/Engine/Classes/GameFramework/Character.h index 7eba3cd42a9a..a9795f9520a2 100644 --- a/Engine/Source/Runtime/Engine/Classes/GameFramework/Character.h +++ b/Engine/Source/Runtime/Engine/Classes/GameFramework/Character.h @@ -800,6 +800,10 @@ public: void ClientCheatGhost(); virtual void ClientCheatGhost_Implementation(); + UFUNCTION(reliable, client) + void RootMotionDebugClientPrintOnScreen(const FString& InString); + virtual void RootMotionDebugClientPrintOnScreen_Implementation(const FString& InString); + // Root Motion public: /** @@ -871,8 +875,13 @@ public: UFUNCTION(BlueprintCallable, Category = Animation) float GetAnimRootMotionTranslationScale() const; - /** Called on the actor right before replication occurs */ - virtual void PreReplication( IRepChangedPropertyTracker & ChangedPropertyTracker ) override; + /** Called on the actor right before replication occurs. + * Only called on Server, and for autonomous proxies if recording a Client Replay. */ + virtual void PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker) override; + + /** Called on the actor right before replication occurs. + * Called for everyone when recording a Client Replay, including Simulated Proxies. */ + virtual void PreReplicationForReplay(IRepChangedPropertyTracker & ChangedPropertyTracker) override; public: /** Returns Mesh subobject **/ diff --git a/Engine/Source/Runtime/Engine/Classes/GameFramework/CharacterMovementComponent.h b/Engine/Source/Runtime/Engine/Classes/GameFramework/CharacterMovementComponent.h index cc42dc7b308b..15d75d4c31ae 100644 --- a/Engine/Source/Runtime/Engine/Classes/GameFramework/CharacterMovementComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/GameFramework/CharacterMovementComponent.h @@ -1518,6 +1518,9 @@ public: /** Perform rotation over deltaTime */ virtual void PhysicsRotation(float DeltaTime); + /** if true, DesiredRotation will be restricted to only Yaw component in PhysicsRotation() */ + virtual bool ShouldRemainVertical() const; + /** Delegate when PhysicsVolume of UpdatedComponent has been changed **/ virtual void PhysicsVolumeChanged(class APhysicsVolume* NewVolume) override; @@ -1968,9 +1971,9 @@ public: */ virtual void SmoothCorrection(const FVector& OldLocation, const FQuat& OldRotation, const FVector& NewLocation, const FQuat& NewRotation) override; - /** Get prediction data for a client game. Should not be used if not running as a client. Allocates the data on demand and can be overridden to allocate a custom override if desired. */ + /** Get prediction data for a client game. Should not be used if not running as a client. Allocates the data on demand and can be overridden to allocate a custom override if desired. Result must be a FNetworkPredictionData_Client_Character. */ virtual class FNetworkPredictionData_Client* GetPredictionData_Client() const override; - /** Get prediction data for a server game. Should not be used if not running as a server. Allocates the data on demand and can be overridden to allocate a custom override if desired. */ + /** Get prediction data for a server game. Should not be used if not running as a server. Allocates the data on demand and can be overridden to allocate a custom override if desired. Result must be a FNetworkPredictionData_Server_Character. */ virtual class FNetworkPredictionData_Server* GetPredictionData_Server() const override; class FNetworkPredictionData_Client_Character* GetPredictionData_Client_Character() const; @@ -2177,6 +2180,11 @@ public: void ClientAdjustRootMotionSourcePosition(float TimeStamp, FRootMotionSourceGroup ServerRootMotion, bool bHasAnimRootMotion, float ServerMontageTrackPosition, FVector ServerLoc, FVector_NetQuantizeNormal ServerRotation, float ServerVelZ, UPrimitiveComponent* ServerBase, FName ServerBoneName, bool bHasBase, bool bBaseRelativePosition, uint8 ServerMovementMode); void ClientAdjustRootMotionSourcePosition_Implementation(float TimeStamp, FRootMotionSourceGroup ServerRootMotion, bool bHasAnimRootMotion, float ServerMontageTrackPosition, FVector ServerLoc, FVector_NetQuantizeNormal ServerRotation, float ServerVelZ, UPrimitiveComponent* ServerBase, FName ServerBoneName, bool bHasBase, bool bBaseRelativePosition, uint8 ServerMovementMode); +protected: + + /** Event notification when client receives a correction from the server. Base implementation logs relevant data and draws debug info if "p.NetShowCorrections" is not equal to 0. */ + virtual void OnClientCorrectionReceived(class FNetworkPredictionData_Client_Character& ClientData, float TimeStamp, FVector NewLocation, FVector NewVelocity, UPrimitiveComponent* NewBase, FName NewBaseBoneName, bool bHasBase, bool bBaseRelativePosition, uint8 ServerMovementMode); + // Root Motion public: /** Root Motion Group containing active root motion sources being applied to movement */ @@ -2276,6 +2284,8 @@ public: /** allows modifing avoidance velocity, called when bUseRVOPostProcess is set */ virtual void PostProcessAvoidanceVelocity(FVector& NewVelocity); + virtual void FlushServerMoves(); + protected: /** called in Tick to update data in RVO avoidance manager */ diff --git a/Engine/Source/Runtime/Engine/Classes/GameFramework/Controller.h b/Engine/Source/Runtime/Engine/Classes/GameFramework/Controller.h index 0008daf9b7bd..e06ca6dc85bc 100644 --- a/Engine/Source/Runtime/Engine/Classes/GameFramework/Controller.h +++ b/Engine/Source/Runtime/Engine/Classes/GameFramework/Controller.h @@ -62,9 +62,8 @@ public: UPROPERTY(replicatedUsing=OnRep_PlayerState, BlueprintReadOnly, Category="Controller") class APlayerState* PlayerState; -private_subobject: +private: /** Component to give controllers a transform and enable attachment if desired. */ - DEPRECATED_FORGAME(4.6, "TransformComponent should not be accessed directly, please use GetTransformComponent() function instead. TransformComponent will soon be private and your code will not compile.") UPROPERTY() class USceneComponent* TransformComponent; @@ -368,7 +367,7 @@ private: protected: /** Returns TransformComponent subobject **/ - class USceneComponent* GetTransformComponent() const; + class USceneComponent* GetTransformComponent() const { return TransformComponent; } }; diff --git a/Engine/Source/Runtime/Engine/Classes/GameFramework/DefaultPawn.h b/Engine/Source/Runtime/Engine/Classes/GameFramework/DefaultPawn.h index e9abeeaa66a1..057a462da097 100644 --- a/Engine/Source/Runtime/Engine/Classes/GameFramework/DefaultPawn.h +++ b/Engine/Source/Runtime/Engine/Classes/GameFramework/DefaultPawn.h @@ -91,9 +91,8 @@ public: /** Name of the CollisionComponent. */ static FName CollisionComponentName; -private_subobject: +private: /** DefaultPawn collision component */ - DEPRECATED_FORGAME(4.6, "CollisionComponent should not be accessed directly, please use GetCollisionComponent() function instead. CollisionComponent will soon be private and your code will not compile.") UPROPERTY(Category = Pawn, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) USphereComponent* CollisionComponent; public: @@ -101,9 +100,8 @@ public: /** Name of the MeshComponent. Use this name if you want to prevent creation of the component (with ObjectInitializer.DoNotCreateDefaultSubobject). */ static FName MeshComponentName; -private_subobject: +private: /** The mesh associated with this Pawn. */ - DEPRECATED_FORGAME(4.6, "MeshComponent should not be accessed directly, please use GetMeshComponent() function instead. MeshComponent will soon be private and your code will not compile.") UPROPERTY(Category = Pawn, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) UStaticMeshComponent* MeshComponent; public: @@ -113,8 +111,8 @@ public: uint32 bAddDefaultMovementBindings:1; /** Returns CollisionComponent subobject **/ - USphereComponent* GetCollisionComponent() const; + USphereComponent* GetCollisionComponent() const { return CollisionComponent; } /** Returns MeshComponent subobject **/ - UStaticMeshComponent* GetMeshComponent() const; + UStaticMeshComponent* GetMeshComponent() const { return MeshComponent; } }; diff --git a/Engine/Source/Runtime/Engine/Classes/GameFramework/GameMode.h b/Engine/Source/Runtime/Engine/Classes/GameFramework/GameMode.h index b8d831cbf0f7..f40b6ef741a6 100644 --- a/Engine/Source/Runtime/Engine/Classes/GameFramework/GameMode.h +++ b/Engine/Source/Runtime/Engine/Classes/GameFramework/GameMode.h @@ -185,8 +185,9 @@ public: virtual void Say(const FString& Msg); /** Alters the synthetic bandwidth limit for a running game. */ - UFUNCTION(exec) - virtual void SetBandwidthLimit(float AsyncIOBandwidthLimit); + DEPRECATED(4.17, "AsyncIOBandwidthLimit is no longer configurable") + UFUNCTION(exec) + virtual void SetBandwidthLimit(float AsyncIOBandwidthLimit) {} /** Broadcast a string to all players. */ virtual void Broadcast( AActor* Sender, const FString& Msg, FName Type = NAME_None ); diff --git a/Engine/Source/Runtime/Engine/Classes/GameFramework/GameStateBase.h b/Engine/Source/Runtime/Engine/Classes/GameFramework/GameStateBase.h index 3192604568d0..e384c0e79581 100644 --- a/Engine/Source/Runtime/Engine/Classes/GameFramework/GameStateBase.h +++ b/Engine/Source/Runtime/Engine/Classes/GameFramework/GameStateBase.h @@ -82,6 +82,7 @@ class ENGINE_API AGameStateBase : public AInfo UFUNCTION(BlueprintCallable, Category=GameState) virtual float GetPlayerRespawnDelay(AController* Controller) const; + virtual void GetLifetimeReplicatedProps(TArray< FLifetimeProperty > &OutLifetimeProps) const; //~============================================================================= // Interaction with GameModeBase diff --git a/Engine/Source/Runtime/Engine/Classes/GameFramework/Info.h b/Engine/Source/Runtime/Engine/Classes/GameFramework/Info.h index f8ee41a0d609..8821f581cfe2 100644 --- a/Engine/Source/Runtime/Engine/Classes/GameFramework/Info.h +++ b/Engine/Source/Runtime/Engine/Classes/GameFramework/Info.h @@ -22,9 +22,8 @@ class AInfo : public AActor GENERATED_UCLASS_BODY() #if WITH_EDITORONLY_DATA -private_subobject: +private: /** Billboard Component displayed in editor */ - DEPRECATED_FORGAME(4.6, "SpriteComponent should not be accessed directly, please use GetSpriteComponent() function instead. SpriteComponent will soon be private and your code will not compile.") UPROPERTY() class UBillboardComponent* SpriteComponent; public: diff --git a/Engine/Source/Runtime/Engine/Classes/GameFramework/InputSettings.h b/Engine/Source/Runtime/Engine/Classes/GameFramework/InputSettings.h index 03518bccb440..20d28dcfd112 100644 --- a/Engine/Source/Runtime/Engine/Classes/GameFramework/InputSettings.h +++ b/Engine/Source/Runtime/Engine/Classes/GameFramework/InputSettings.h @@ -105,30 +105,49 @@ class ENGINE_API UInputSettings virtual void PostInitProperties() override; // End of UObject interface + /** Returns the game local machine settings (resolution, windowing mode, scalability settings, etc...) */ + UFUNCTION(BlueprintPure, Category = Settings) + static UInputSettings* GetInputSettings(); + /** Programmatically add an action mapping to the project defaults */ - void AddActionMapping(const FInputActionKeyMapping& KeyMapping); + UFUNCTION(BlueprintCallable, Category = Settings) + void AddActionMapping(const FInputActionKeyMapping& KeyMapping, bool bForceRebuildKeymaps = true); + + UFUNCTION(BlueprintPure, Category = Settings) + void GetActionMappingByName(const FName InActionName, TArray& OutMappings) const; /** Programmatically remove an action mapping to the project defaults */ - void RemoveActionMapping(const FInputActionKeyMapping& KeyMapping); + UFUNCTION(BlueprintCallable, Category = Settings) + void RemoveActionMapping(const FInputActionKeyMapping& KeyMapping, bool bForceRebuildKeymaps = true); /** Programmatically add an axis mapping to the project defaults */ - void AddAxisMapping(const FInputAxisKeyMapping& KeyMapping); + UFUNCTION(BlueprintCallable, Category = Settings) + void AddAxisMapping(const FInputAxisKeyMapping& KeyMapping, bool bForceRebuildKeymaps = true); + + /** Retrieve all axis mappings by a certain name. */ + UFUNCTION(BlueprintPure, Category = Settings) + void GetAxisMappingByName(const FName InAxisName, TArray& OutMappings) const; /** Programmatically remove an axis mapping to the project defaults */ - void RemoveAxisMapping(const FInputAxisKeyMapping& KeyMapping); + UFUNCTION(BlueprintCallable, Category = Settings) + void RemoveAxisMapping(const FInputAxisKeyMapping& KeyMapping, bool bForceRebuildKeymaps = true); /** Flush the current mapping values to the config file */ + UFUNCTION(BlueprintCallable, Category=Settings) void SaveKeyMappings(); /** Populate a list of all defined action names */ + UFUNCTION(BlueprintCallable, Category = Settings) void GetActionNames(TArray& ActionNames) const; /** Populate a list of all defined axis names */ + UFUNCTION(BlueprintCallable, Category = Settings) void GetAxisNames(TArray& AxisNames) const; -private: /** When changes are made to the default mappings, push those changes out to PlayerInput key maps */ + UFUNCTION(BlueprintCallable, Category = Settings) void ForceRebuildKeymaps(); +private: void PopulateAxisConfigs(); }; diff --git a/Engine/Source/Runtime/Engine/Classes/GameFramework/PlayerController.h b/Engine/Source/Runtime/Engine/Classes/GameFramework/PlayerController.h index e8dd964ad3f6..60c06d0b7365 100644 --- a/Engine/Source/Runtime/Engine/Classes/GameFramework/PlayerController.h +++ b/Engine/Source/Runtime/Engine/Classes/GameFramework/PlayerController.h @@ -95,6 +95,8 @@ struct FForceFeedbackEffectHistoryEntry struct ENGINE_API FInputModeDataBase { protected: + virtual ~FInputModeDataBase() { } + /** Derived classes override this function to apply the necessary settings for the desired input mode */ virtual void ApplyInputMode(class FReply& SlateOperations, class UGameViewportClient& GameViewportClient) const = 0; @@ -255,6 +257,10 @@ class ENGINE_API APlayerController : public AController UPROPERTY() TArray HiddenActors; + /** Explicit components the camera shouldn't see (helpful for external systems to hide a component from a single player) */ + UPROPERTY() + TArray< TWeakObjectPtr > HiddenPrimitiveComponents; + /** Used to make sure the client is kept synchronized when in a spectator state */ UPROPERTY() float LastSpectatorStateSynchTime; @@ -509,7 +515,7 @@ public: UFUNCTION(BlueprintCallable, Category = "Game|Player", meta = (DisplayName = "ConvertMouseLocationToWorldSpace", Keywords = "deproject")) bool DeprojectMousePositionToWorld(FVector& WorldLocation, FVector& WorldDirection) const; - /** Convert current mouse 2D position to World Space 3D position and direction. Returns false if unable to determine value. **/ + /** Convert 2D screen position to World Space 3D position and direction. Returns false if unable to determine value. **/ UFUNCTION(BlueprintCallable, Category = "Game|Player", meta = (DisplayName = "ConvertScreenLocationToWorldSpace", Keywords = "deproject")) bool DeprojectScreenPositionToWorld(float ScreenX, float ScreenY, FVector& WorldLocation, FVector& WorldDirection) const; @@ -1326,6 +1332,8 @@ public: virtual void SetPawn(APawn* InPawn) override; //~ End AController Interface + virtual void GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const override; + /** called on the server when the client sends a message indicating it was unable to initialize an Actor channel, * most commonly because the desired Actor's archetype couldn't be serialized * the default is to do nothing (Actor simply won't exist on the client), but this function gives the game code @@ -1344,7 +1352,7 @@ public: * @param ViewLocation the view point to hide/unhide from * @param HiddenComponents the list to add to/remove from */ - virtual void UpdateHiddenComponents(const FVector& ViewLocation, TSet& HiddenComponents) {} + virtual void UpdateHiddenComponents(const FVector& ViewLocation, TSet& /*HiddenComponents*/) {} /** * Builds a list of components that are hidden based upon gameplay. @@ -1352,7 +1360,7 @@ public: * @param ViewLocation the view point to hide/unhide from * @param HiddenComponents this list will have all components that should be hidden added to it */ - void BuildHiddenComponentList(const FVector& ViewLocation, TSet& HiddenComponents); + void BuildHiddenComponentList(const FVector& ViewLocation, TSet& HiddenComponentsOut); /** * Sets the Matinee director track instance that's currently possessing this player controller diff --git a/Engine/Source/Runtime/Engine/Classes/GameFramework/PlayerInput.h b/Engine/Source/Runtime/Engine/Classes/GameFramework/PlayerInput.h index f42deb54ee4e..05ab1a767648 100644 --- a/Engine/Source/Runtime/Engine/Classes/GameFramework/PlayerInput.h +++ b/Engine/Source/Runtime/Engine/Classes/GameFramework/PlayerInput.h @@ -136,7 +136,7 @@ struct FInputActionKeyMapping GENERATED_USTRUCT_BODY() /** Friendly name of action, e.g "jump" */ - UPROPERTY(EditAnywhere, Category="Input") + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Input") FName ActionName; /** Key to bind it to. */ @@ -204,15 +204,15 @@ struct FInputAxisKeyMapping GENERATED_USTRUCT_BODY() /** Friendly name of axis, e.g "MoveForward" */ - UPROPERTY(EditAnywhere, Category="Input") + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Input") FName AxisName; /** Key to bind it to. */ - UPROPERTY(EditAnywhere, Category="Input") + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Input") FKey Key; /** Multiplier to use for the mapping when accumulating the axis value */ - UPROPERTY(EditAnywhere, Category="Input") + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Input") float Scale; bool operator==(const FInputAxisKeyMapping& Other) const diff --git a/Engine/Source/Runtime/Engine/Classes/GameFramework/PlayerStart.h b/Engine/Source/Runtime/Engine/Classes/GameFramework/PlayerStart.h index 51be70f6953a..eb7c485f43eb 100644 --- a/Engine/Source/Runtime/Engine/Classes/GameFramework/PlayerStart.h +++ b/Engine/Source/Runtime/Engine/Classes/GameFramework/PlayerStart.h @@ -28,8 +28,7 @@ public: /** Arrow component to indicate forward direction of start */ #if WITH_EDITORONLY_DATA -private_subobject: - DEPRECATED_FORGAME(4.6, "ArrowComponent should not be accessed directly, please use GetArrowComponent() function instead. ArrowComponent will soon be private and your code will not compile.") +private: UPROPERTY() class UArrowComponent* ArrowComponent; public: diff --git a/Engine/Source/Runtime/Engine/Classes/GameFramework/PlayerState.h b/Engine/Source/Runtime/Engine/Classes/GameFramework/PlayerState.h index cde2400360f5..229f64f9a8a4 100644 --- a/Engine/Source/Runtime/Engine/Classes/GameFramework/PlayerState.h +++ b/Engine/Source/Runtime/Engine/Classes/GameFramework/PlayerState.h @@ -197,6 +197,8 @@ public: /** return true if PlayerState is primary (ie. non-splitscreen) player */ virtual bool IsPrimaryPlayer() const; + virtual void GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const override; + /** calls OverrideWith and triggers OnOverrideWith for BP extension */ void DispatchOverrideWith(APlayerState* PlayerState); diff --git a/Engine/Source/Runtime/Engine/Classes/GameFramework/RootMotionSource.h b/Engine/Source/Runtime/Engine/Classes/GameFramework/RootMotionSource.h index 1cf301338c88..2e689b936e01 100644 --- a/Engine/Source/Runtime/Engine/Classes/GameFramework/RootMotionSource.h +++ b/Engine/Source/Runtime/Engine/Classes/GameFramework/RootMotionSource.h @@ -21,6 +21,7 @@ struct ENGINE_API RootMotionSourceDebug { static TAutoConsoleVariable CVarDebugRootMotionSources; static void PrintOnScreen(const ACharacter& InCharacter, const FString& InString); + static void PrintOnScreenServerMsg(const FString& InString); }; #endif diff --git a/Engine/Source/Runtime/Engine/Classes/GameFramework/SpringArmComponent.h b/Engine/Source/Runtime/Engine/Classes/GameFramework/SpringArmComponent.h index e7974123889b..5dc07f9aba13 100644 --- a/Engine/Source/Runtime/Engine/Classes/GameFramework/SpringArmComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/GameFramework/SpringArmComponent.h @@ -46,6 +46,7 @@ class ENGINE_API USpringArmComponent : public USceneComponent /** * If this component is placed on a pawn, should it use the view/control rotation of the pawn where possible? + * When disabled, the component will revert to using the stored RelativeRotation of the component. * @see APawn::GetViewRotation() */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=CameraSettings) diff --git a/Engine/Source/Runtime/Engine/Classes/GameFramework/WorldSettings.h b/Engine/Source/Runtime/Engine/Classes/GameFramework/WorldSettings.h index 1c0bc89dcc4f..41d491e55ecc 100644 --- a/Engine/Source/Runtime/Engine/Classes/GameFramework/WorldSettings.h +++ b/Engine/Source/Runtime/Engine/Classes/GameFramework/WorldSettings.h @@ -279,6 +279,8 @@ class ENGINE_API AWorldSettings : public AInfo, public IInterface_AssetUserData { GENERATED_UCLASS_BODY() + virtual void GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const override; + /** DEFAULT BASIC PHYSICS SETTINGS **/ /** If true, enables CheckStillInWorld checks */ diff --git a/Engine/Source/Runtime/Engine/Classes/Kismet/BlueprintAsyncActionBase.h b/Engine/Source/Runtime/Engine/Classes/Kismet/BlueprintAsyncActionBase.h index 4f59233a673d..08502574684c 100644 --- a/Engine/Source/Runtime/Engine/Classes/Kismet/BlueprintAsyncActionBase.h +++ b/Engine/Source/Runtime/Engine/Classes/Kismet/BlueprintAsyncActionBase.h @@ -12,7 +12,10 @@ class ENGINE_API UBlueprintAsyncActionBase : public UObject { GENERATED_UCLASS_BODY() - // Called to trigger the action once the delegates have been bound + /** Called to trigger the action once the delegates have been bound */ UFUNCTION(BlueprintCallable, meta=(BlueprintInternalUseOnly="true")) virtual void Activate(); + + /** Call when the action is completely done, this makes the action free to delete */ + virtual void SetReadyToDestroy(); }; diff --git a/Engine/Source/Runtime/Engine/Classes/Kismet/BlueprintPlatformLibrary.h b/Engine/Source/Runtime/Engine/Classes/Kismet/BlueprintPlatformLibrary.h index 204a96b9c22f..472904d0c1df 100644 --- a/Engine/Source/Runtime/Engine/Classes/Kismet/BlueprintPlatformLibrary.h +++ b/Engine/Source/Runtime/Engine/Classes/Kismet/BlueprintPlatformLibrary.h @@ -42,6 +42,26 @@ namespace EScreenOrientation }; } +// application state when the game receives a notification +UENUM(BlueprintType) +namespace EApplicationState +{ + enum Type + { + /** The Application was in an unknown state when receiving the notification */ + Unknown, + + /** The Application was inactive when receiving the notification */ + Inactive, + + /** The Application was in the background when receiving the notification */ + Background, + + /** The Application was active when receiving the notification */ + Active, + }; +} + /** UObject based class for handling mobile events. Having this object as an option gives the app lifetime access to these global delegates. The component UApplicationLifecycleComponent is destroyed at level loads */ UCLASS(Blueprintable, BlueprintType, ClassGroup=Mobile) class ENGINE_API UPlatformGameInstance : public UGameInstance @@ -54,8 +74,8 @@ public: DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FPlatformRegisteredForRemoteNotificationsDelegate, const TArray&, inArray); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FPlatformRegisteredForUserNotificationsDelegate, int32, inInt); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FPlatformFailedToRegisterForRemoteNotificationsDelegate, FString, inString); - DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FPlatformReceivedRemoteNotificationDelegate, FString, inString); - DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FPlatformReceivedLocalNotificationDelegate, FString, inString, int32, inInt); + DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FPlatformReceivedRemoteNotificationDelegate, FString, inString, EApplicationState::Type, inAppState); + DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FPlatformReceivedLocalNotificationDelegate, FString, inString, int32, inInt, EApplicationState::Type, inAppState); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FPlatformScreenOrientationChangedDelegate, EScreenOrientation::Type, inScreenOrientation); // This is called when the application is about to be deactivated (e.g., due to a phone call or SMS or the sleep button). @@ -123,8 +143,8 @@ private: void ApplicationRegisteredForRemoteNotificationsDelegate_Handler(TArray inArray) { ApplicationRegisteredForRemoteNotificationsDelegate.Broadcast(inArray); } void ApplicationRegisteredForUserNotificationsDelegate_Handler(int32 inInt) { ApplicationRegisteredForUserNotificationsDelegate.Broadcast(inInt); } void ApplicationFailedToRegisterForRemoteNotificationsDelegate_Handler(FString inFString) { ApplicationFailedToRegisterForRemoteNotificationsDelegate.Broadcast(inFString); } - void ApplicationReceivedRemoteNotificationDelegate_Handler(FString inFString) { ApplicationReceivedRemoteNotificationDelegate.Broadcast(inFString); } - void ApplicationReceivedLocalNotificationDelegate_Handler(FString inFString, int32 inInt) { ApplicationReceivedLocalNotificationDelegate.Broadcast(inFString, inInt); } + void ApplicationReceivedRemoteNotificationDelegate_Handler(FString inFString, int32 inAppState); + void ApplicationReceivedLocalNotificationDelegate_Handler(FString inFString, int32 inInt, int32 inAppState); void ApplicationReceivedScreenOrientationChangedNotificationDelegate_Handler(int32 inScreenOrientation); }; @@ -141,7 +161,7 @@ public: /** Clear all pending local notifications. Typically this will be done before scheduling new notifications when going into the background */ UFUNCTION(BlueprintCallable, Category="Platform|LocalNotification") static void ClearAllLocalNotifications(); - + /** Schedule a local notification at a specific time, inLocalTime specifies the current local time or if UTC time should be used * @param FireDateTime The time at which to fire the local notification * @param LocalTime If true the provided time is in the local timezone, if false it is in UTC @@ -152,7 +172,7 @@ public: */ UFUNCTION(BlueprintCallable, Category="Platform|LocalNotification") static void ScheduleLocalNotificationAtTime(const FDateTime& FireDateTime, bool LocalTime, const FText& Title, const FText& Body, const FText& Action, const FString& ActivationEvent); - + /** Schedule a local notification to fire inSecondsFromNow from now * @param inSecondsFromNow The seconds until the notification should fire * @param LocalTime If true the provided time is in the local timezone, if false it is in UTC @@ -163,7 +183,22 @@ public: */ UFUNCTION(BlueprintCallable, Category="Platform|LocalNotification") static void ScheduleLocalNotificationFromNow(int32 inSecondsFromNow, const FText& Title, const FText& Body, const FText& Action, const FString& ActivationEvent); - + + /** Schedule a local notification badge at a specific time, inLocalTime specifies the current local time or if UTC time should be used + * @param FireDateTime The time at which to fire the local notification + * @param LocalTime If true the provided time is in the local timezone, if false it is in UTC + * @param ActivationEvent A string that is passed in the delegate callback when the app is brought into the foreground from the user activating the notification + */ + UFUNCTION(BlueprintCallable, Category = "Platform|LocalNotification") + static void ScheduleLocalNotificationBadgeAtTime(const FDateTime& FireDateTime, bool LocalTime, const FString& ActivationEvent); + + /** Schedule a local notification badge to fire inSecondsFromNow from now + * @param inSecondsFromNow The seconds until the notification should fire + * @param ActivationEvent A string that is passed in the delegate callback when the app is brought into the foreground from the user activating the notification + */ + UFUNCTION(BlueprintCallable, Category = "Platform|LocalNotification") + static void ScheduleLocalNotificationBadgeFromNow(int32 inSecondsFromNow, const FString& ActivationEvent); + /** Cancel a local notification given the ActivationEvent * @param ActivationEvent The string passed into the Schedule call for the notification to be cancelled */ diff --git a/Engine/Source/Runtime/Engine/Classes/Kismet/GameplayStatics.h b/Engine/Source/Runtime/Engine/Classes/Kismet/GameplayStatics.h index 9e1fa68fb099..b08bdc6ad39b 100644 --- a/Engine/Source/Runtime/Engine/Classes/Kismet/GameplayStatics.h +++ b/Engine/Source/Runtime/Engine/Classes/Kismet/GameplayStatics.h @@ -529,9 +529,9 @@ class ENGINE_API UGameplayStatics : public UBlueprintFunctionLibrary * @param AttenuationSettings - Override attenuation settings package to play sound with */ UFUNCTION(BlueprintCallable, Category="Audio", meta=(WorldContext="WorldContextObject", AdvancedDisplay = "4", UnsafeDuringActorConstruction = "true")) - static void PlayDialogueAtLocation(const UObject* WorldContextObject, class UDialogueWave* Dialogue, const struct FDialogueContext& Context, FVector Location, FRotator Rotation, float VolumeMultiplier = 1.f, float PitchMultiplier = 1.f, float StartTime = 0.f, class USoundAttenuation* AttenuationSettings = nullptr); + static void PlayDialogueAtLocation(const UObject* WorldContextObject, class UDialogueWave* Dialogue, const FDialogueContext& Context, FVector Location, FRotator Rotation, float VolumeMultiplier = 1.f, float PitchMultiplier = 1.f, float StartTime = 0.f, USoundAttenuation* AttenuationSettings = nullptr); - static void PlayDialogueAtLocation(const UObject* WorldContextObject, UDialogueWave* Dialogue, const struct FDialogueContext& Context, FVector Location, float VolumeMultiplier = 1.f, float PitchMultiplier = 1.f, float StartTime = 0.f, USoundAttenuation* AttenuationSettings = nullptr) + static void PlayDialogueAtLocation(const UObject* WorldContextObject, UDialogueWave* Dialogue, const FDialogueContext& Context, FVector Location, float VolumeMultiplier = 1.f, float PitchMultiplier = 1.f, float StartTime = 0.f, USoundAttenuation* AttenuationSettings = nullptr) { PlayDialogueAtLocation(WorldContextObject, Dialogue, Context, Location, FRotator::ZeroRotator, VolumeMultiplier, PitchMultiplier, StartTime, AttenuationSettings); } @@ -568,15 +568,15 @@ class ENGINE_API UGameplayStatics : public UBlueprintFunctionLibrary * @return Audio Component to manipulate the playing dialogue with */ UFUNCTION(BlueprintCallable, Category="Audio", meta=(AdvancedDisplay = "2", UnsafeDuringActorConstruction = "true", Keywords = "play")) - static UAudioComponent* SpawnDialogueAttached(UDialogueWave* Dialogue, const struct FDialogueContext& Context, USceneComponent* AttachToComponent, FName AttachPointName = NAME_None, FVector Location = FVector(ForceInit), FRotator Rotation = FRotator::ZeroRotator, EAttachLocation::Type LocationType = EAttachLocation::KeepRelativeOffset, bool bStopWhenAttachedToDestroyed = false, float VolumeMultiplier = 1.f, float PitchMultiplier = 1.f, float StartTime = 0.f, USoundAttenuation* AttenuationSettings = nullptr, bool bAutoDestroy = true); + static UAudioComponent* SpawnDialogueAttached(UDialogueWave* Dialogue, const FDialogueContext& Context, USceneComponent* AttachToComponent, FName AttachPointName = NAME_None, FVector Location = FVector(ForceInit), FRotator Rotation = FRotator::ZeroRotator, EAttachLocation::Type LocationType = EAttachLocation::KeepRelativeOffset, bool bStopWhenAttachedToDestroyed = false, float VolumeMultiplier = 1.f, float PitchMultiplier = 1.f, float StartTime = 0.f, USoundAttenuation* AttenuationSettings = nullptr, bool bAutoDestroy = true); DEPRECATED(4.9, "PlayDialogueAttached has been renamed SpawnDialogueAttached") - static UAudioComponent* PlayDialogueAttached(UDialogueWave* Dialogue, const struct FDialogueContext& Context, USceneComponent* AttachToComponent, FName AttachPointName = NAME_None, FVector Location = FVector(ForceInit), EAttachLocation::Type LocationType = EAttachLocation::KeepRelativeOffset, bool bStopWhenAttachedToDestroyed = false, float VolumeMultiplier = 1.f, float PitchMultiplier = 1.f, float StartTime = 0.f, USoundAttenuation* AttenuationSettings = nullptr) + static UAudioComponent* PlayDialogueAttached(UDialogueWave* Dialogue, const FDialogueContext& Context, USceneComponent* AttachToComponent, FName AttachPointName = NAME_None, FVector Location = FVector(ForceInit), EAttachLocation::Type LocationType = EAttachLocation::KeepRelativeOffset, bool bStopWhenAttachedToDestroyed = false, float VolumeMultiplier = 1.f, float PitchMultiplier = 1.f, float StartTime = 0.f, USoundAttenuation* AttenuationSettings = nullptr) { return SpawnDialogueAttached(Dialogue, Context, AttachToComponent, AttachPointName, Location, FRotator::ZeroRotator, LocationType, bStopWhenAttachedToDestroyed, VolumeMultiplier, PitchMultiplier, StartTime, AttenuationSettings); } - static UAudioComponent* SpawnDialogueAttached(UDialogueWave* Dialogue, const struct FDialogueContext& Context, USceneComponent* AttachToComponent, FName AttachPointName, FVector Location, EAttachLocation::Type LocationType = EAttachLocation::KeepRelativeOffset, bool bStopWhenAttachedToDestroyed = false, float VolumeMultiplier = 1.f, float PitchMultiplier = 1.f, float StartTime = 0.f, USoundAttenuation* AttenuationSettings = nullptr, bool bAutoDestroy = true) + static UAudioComponent* SpawnDialogueAttached(UDialogueWave* Dialogue, const FDialogueContext& Context, USceneComponent* AttachToComponent, FName AttachPointName, FVector Location, EAttachLocation::Type LocationType = EAttachLocation::KeepRelativeOffset, bool bStopWhenAttachedToDestroyed = false, float VolumeMultiplier = 1.f, float PitchMultiplier = 1.f, float StartTime = 0.f, USoundAttenuation* AttenuationSettings = nullptr, bool bAutoDestroy = true) { return SpawnDialogueAttached(Dialogue, Context, AttachToComponent, AttachPointName, Location, FRotator::ZeroRotator, LocationType, bStopWhenAttachedToDestroyed, VolumeMultiplier, PitchMultiplier, StartTime, AttenuationSettings, bAutoDestroy); } @@ -780,6 +780,21 @@ class ENGINE_API UGameplayStatics : public UBlueprintFunctionLibrary UFUNCTION(BlueprintCallable, Category="Game", meta=(DeprecatedFunction, DeprecationMessage="Use GameplayStatics.CreateSaveGameObject instead.")) static USaveGame* CreateSaveGameObjectFromBlueprint(UBlueprint* SaveGameBlueprint); + /** + * Serialize our USaveGame object into a given array of bytes + * @param SaveGameObject Object that contains data about the save game that we want to write out + * @return Whether we successfully wrote data + */ + static bool SaveGameToMemory(USaveGame * SaveGameObject, TArray& OutSaveData); + + /** + * Save the contents of the buffer to a slot/file + * @param InSaveData Data to save + * @param SlotName Name of save game slot to save to. + * @param UserIndex For some platforms, master user index to identify the user doing the saving. + */ + static bool SaveDataToSlot(const TArray & InSaveData, const FString & SlotName, const int32 UserIndex); + /** * Save the contents of the SaveGameObject to a slot. * @param SaveGameObject Object that contains data about the save game that we want to write out diff --git a/Engine/Source/Runtime/Engine/Classes/Kismet/ImportanceSamplingLibrary.h b/Engine/Source/Runtime/Engine/Classes/Kismet/ImportanceSamplingLibrary.h new file mode 100644 index 000000000000..6681921b7bca --- /dev/null +++ b/Engine/Source/Runtime/Engine/Classes/Kismet/ImportanceSamplingLibrary.h @@ -0,0 +1,207 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "ObjectMacros.h" +#include "Engine/Texture2D.h" +#include "Kismet/BlueprintFunctionLibrary.h" +#include "ImportanceSamplingLibrary.generated.h" + +/** Provides different weighting functions for texture importance sampling */ +UENUM(BlueprintType) +namespace EImportanceWeight +{ + enum Type + { + /** Importance from color luminance. */ + Luminance, + + /** Importance from red channel of texture. */ + Red, + + /** Importance from green channel of texture. */ + Green, + + /** Importance from blue channel of texture. */ + Blue, + + /** Importance from alpha channel of texture. */ + Alpha, + }; +} + +/** +* Texture processed for importance sampling +* Holds marginal PDF of the rows, as well as the PDF of each row +*/ +USTRUCT(BlueprintType, meta = (HasNativeMake = "Engine.ImportanceLibrary.MakeImportanceTexture", HasNativeBreak = "Engine.ImportanceLibrary.BreakImportanceTexture")) +struct FImportanceTexture +{ + GENERATED_BODY(); + + // active texture dimensions, capped to 1024 x 1024 + UPROPERTY() + FIntPoint Size; + + // active number of MIP levels + UPROPERTY() + int NumMips; + + // Unnormalized cumulative density of the image by rows (Size.Y+1) + // First entry is zero, final entry is the CDF normalization factor + UPROPERTY() + TArray MarginalCDF; + + // Unnormalized cumulative probability of each pixel in a row (Size.Y row CDFs of Size.X+1) + // First entry of each row is zero, final entry in each row is the CDF normalization factor for that row + UPROPERTY() + TArray ConditionalCDF; + + // packed copy of MIP level data for filtered sampling (capped to 1024x1024) + // local copy seems better than allocating and copying the same data temporarily for each sample + UPROPERTY() + TArray TextureData; + + // Original texture object for Break function + UPROPERTY() + TWeakObjectPtr Texture; + + // Original importance weight for Break function + UPROPERTY() + TEnumAsByte Weighting; + +public: + /* Default constructor, must Initialize before use */ + FImportanceTexture() : Texture(0) {} + + /* Constructor with initialization */ + FImportanceTexture(UTexture2D *SourceTexture, TEnumAsByte WeightingFunc) + { + Initialize(SourceTexture, WeightingFunc); + } + + /* Allocate and compute PDF arrays for a texture */ + void Initialize(UTexture2D *SourceTexture, TEnumAsByte WeightingFunc); + + /** + * Distribute sample points proportional to Texture2D luminance. + * @param Rand - Random 2D point with components evenly distributed between 0 and 1 + * @param Samples - Total number of samples that will be used + * @param Intensity - Overall target intensity scale + * @outparam SamplePosition - Importance sampled 2D output texture coordinate (0-1) + * @outparam SampleColor - Representative color near Position from MIP level for SampleSize + * @outparam SampleIntensity - Intensity of individual point + * @outparam SampleSize - Local density of points near Position (scaled for 1x1 texture space) + */ + void ImportanceSample(const FVector2D &Rand, int Samples, float Intensity, + FVector2D &SamplePosition, FLinearColor &SampleColor, float &SampleIntensity, float &SampleSize) const; + + /* return color of texel at given MIP level, clamped to available Mip levels */ + FLinearColor GetColorBilinear(FVector2D Position, int32 Mip) const; + + /* return color interpolated between MIP levels */ + FLinearColor GetColorTrilinear(FVector2D Position, float Mip) const; + + /* importance probability weight for given texel */ + float ImportanceWeight(FColor Texel, TEnumAsByte WeightingFunc) const; +}; + + +UCLASS(MinimalAPI) +class UImportanceSamplingLibrary : public UBlueprintFunctionLibrary +{ + GENERATED_UCLASS_BODY() + + // + // Sobol quasi-random generator functions + // + + /** + * @param Index - Which sequential point + * @param Dimension - Which Sobol dimension (0 to 15) + * @param Seed - Random seed (in the range 0-1) to randomize across multiple sequences + * @return Sobol-distributed random number between 0 and 1 + */ + UFUNCTION(BlueprintPure, Category = "Math|Random") + static ENGINE_API float RandomSobolFloat(int32 Index, int32 Dimension, float Seed); + + /** + * @param Index - Which sequential point + * @param Dimension - Which Sobol dimension (0 to 15) + * @param PreviousValue - The Sobol value for Index-1 + * @return Sobol-distributed random number between 0 and 1 + */ + UFUNCTION(BlueprintPure, Category = "Math|Random") + static ENGINE_API float NextSobolFloat(int32 Index, int32 Dimension, float PreviousValue); + + /** + * @param Index - Which sequential point in the cell (starting at 0) + * @param NumCells - Size of cell grid, 1 to 32768. Rounded up to the next power of two + * @param Cell - Give a point from this integer grid cell + * @param Seed - Random 2D seed (components in the range 0-1) to randomize across multiple sequences + * @return Sobol-distributed random 2D position in the given grid cell + */ + UFUNCTION(BlueprintPure, Category = "Math|Random") + static ENGINE_API FVector2D RandomSobolCell2D(int32 Index, int32 NumCells = 1, FVector2D Cell = FVector2D(0,0), FVector2D Seed = FVector2D(0,0)); + + /** + * @param Index - Which sequential point + * @param NumCells - Size of cell grid, 1 to 32768. Rounded up to the next power of two + * @param PreviousValue - The Sobol value for Index-1 + * @return Sobol-distributed random 2D position in the same grid cell + */ + UFUNCTION(BlueprintPure, Category = "Math|Random") + static ENGINE_API FVector2D NextSobolCell2D(int32 Index, int32 NumCells = 1, FVector2D PreviousValue = FVector2D(0,0)); + + /** + * @param Index - Which sequential point in the cell (starting at 0) + * @param NumCells - Size of cell grid, 1 to 1024. Rounded up to the next power of two + * @param Cell - Give a point from this integer grid cell + * @param Seed - Random 3D seed (components in the range 0-1) to randomize across multiple sequences + * @return Sobol-distributed random 3D vector in the given grid cell + */ + UFUNCTION(BlueprintPure, Category = "Math|Random") + static ENGINE_API FVector RandomSobolCell3D(int32 Index, int32 NumCells = 1, FVector Cell = FVector(0,0,0), FVector Seed = FVector(0,0,0)); + + /** + * @param Index - Which sequential point + * @param NumCells - Size of cell grid, 1 to 1024. Rounded up to the next power of two + * @param PreviousValue - The Sobol value for Index-1 + * @return Sobol-distributed random 3D position in the same grid cell + */ + UFUNCTION(BlueprintPure, Category = "Math|Random") + static ENGINE_API FVector NextSobolCell3D(int32 Index, int32 NumCells = 1, FVector PreviousValue = FVector(0,0,0)); + + /** + * Create an FImportanceTexture object for texture-driven importance sampling from a 2D RGBA8 texture + * @param Texture - Texture object to use. Must be RGBA8 format. + * @param WeightingFunc - How to turn the texture data into probability weights + * @return new ImportanceTexture object for use with ImportanceSample + */ + UFUNCTION(BlueprintPure, meta = (NativeMakeFunc), Category = "Math|Random") + static ENGINE_API FImportanceTexture MakeImportanceTexture(UTexture2D *Texture, TEnumAsByte WeightingFunc); + + /** + * Get texture used to create an ImportanceTexture object + * @param ImportanceTexture - The source ImportanceTexture object + * @outparam Texture - Texture object for this ImportanceTexture. + * @param WeightingFunc - How to turn the texture data into probability weights + * @return new ImportanceTexture object for use with ImportanceSample + */ + UFUNCTION(BlueprintPure, meta = (NativeBreakFunc), Category = "Math|Random") + static ENGINE_API void BreakImportanceTexture(const FImportanceTexture &ImportanceTexture, UTexture2D *&Texture, TEnumAsByte &WeightingFunc); + + /** + * Distribute sample points proportional to Texture2D luminance. + * @param Rand - Random 2D point with components evenly distributed between 0 and 1 + * @param Samples - Total number of samples that will be used + * @param Intensity - Total intensity for light + * @outparam SamplePosition - Importance sampled 2D output texture coordinate (0-1) + * @outparam SampleColor - Representative color near Position from MIP level for SampleSize + * @outparam SampleIntensity - Intensity of individual points, scaled by probability and number of samples + * @outparam SampleSize - Local density of points near Position (scaled for 1x1 texture space) + */ + UFUNCTION(BlueprintPure, Category = "Math|Random") + static ENGINE_API void ImportanceSample(const FImportanceTexture &Texture, const FVector2D &Rand, int Samples, float Intensity, + FVector2D &SamplePosition, FLinearColor &SampleColor, float &SampleIntensity, float &SampleSize); +}; \ No newline at end of file diff --git a/Engine/Source/Runtime/Engine/Classes/Kismet/KismetInputLibrary.h b/Engine/Source/Runtime/Engine/Classes/Kismet/KismetInputLibrary.h index 37dba0934415..10ce1117eb74 100644 --- a/Engine/Source/Runtime/Engine/Classes/Kismet/KismetInputLibrary.h +++ b/Engine/Source/Runtime/Engine/Classes/Kismet/KismetInputLibrary.h @@ -10,6 +10,17 @@ #include "Kismet/BlueprintFunctionLibrary.h" #include "KismetInputLibrary.generated.h" +UENUM(BlueprintType) +enum class ESlateGesture : uint8 +{ + None, + Scroll, + Magnify, + Swipe, + Rotate, + LongPress +}; + UCLASS() class ENGINE_API UKismetInputLibrary : public UBlueprintFunctionLibrary { @@ -40,43 +51,43 @@ class ENGINE_API UKismetInputLibrary : public UBlueprintFunctionLibrary /** * @returns True if the key is a modifier key: Ctrl, Command, Alt, Shift */ - UFUNCTION(BlueprintPure, Category="Utilities|Key") + UFUNCTION(BlueprintPure, meta = (DisplayName = "Is Modifier Key"), Category="Utilities|Key") static bool Key_IsModifierKey(const FKey& Key); /** * @returns True if the key is a gamepad button */ - UFUNCTION(BlueprintPure, Category="Utilities|Key") + UFUNCTION(BlueprintPure, meta = (DisplayName = "Is Gamepad Key"), Category="Utilities|Key") static bool Key_IsGamepadKey(const FKey& Key); /** * @returns True if the key is a mouse button */ - UFUNCTION(BlueprintPure, Category="Utilities|Key") + UFUNCTION(BlueprintPure, meta = (DisplayName = "Is Mouse Button"), Category="Utilities|Key") static bool Key_IsMouseButton(const FKey& Key); /** * @returns True if the key is a keyboard button */ - UFUNCTION(BlueprintPure, Category="Utilities|Key") + UFUNCTION(BlueprintPure, meta = (DisplayName = "Is Keyboard Key"), Category="Utilities|Key") static bool Key_IsKeyboardKey(const FKey& Key); /** * @returns True if the key is a float axis */ - UFUNCTION(BlueprintPure, Category="Utilities|Key") + UFUNCTION(BlueprintPure, meta = (DisplayName = "Is Float Axis"), Category="Utilities|Key") static bool Key_IsFloatAxis(const FKey& Key); /** * @returns True if the key is a vector axis */ - UFUNCTION(BlueprintPure, Category="Utilities|Key") + UFUNCTION(BlueprintPure, meta = (DisplayName = "Is Vector Axis"), Category="Utilities|Key") static bool Key_IsVectorAxis(const FKey& Key); /** * @returns The display name of the key. */ - UFUNCTION(BlueprintPure, Category="Utilities|Key") + UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Key Display Name"), Category="Utilities|Key") static FText Key_GetDisplayName(const FKey& Key); /** @@ -84,7 +95,7 @@ class ENGINE_API UKismetInputLibrary : public UBlueprintFunctionLibrary * * @return True if this character is a repeat */ - UFUNCTION(BlueprintPure, meta=( DisplayName = "IsRepeat" ), Category="Utilities|InputEvent") + UFUNCTION(BlueprintPure, meta=( DisplayName = "Is Repeat" ), Category="Utilities|InputEvent") static bool InputEvent_IsRepeat(const FInputEvent& Input); /** @@ -92,7 +103,7 @@ class ENGINE_API UKismetInputLibrary : public UBlueprintFunctionLibrary * * @return True if shift is pressed */ - UFUNCTION(BlueprintPure, meta=( DisplayName = "IsShiftDown" ), Category="Utilities|InputEvent") + UFUNCTION(BlueprintPure, meta=( DisplayName = "Is Shift Down" ), Category="Utilities|InputEvent") static bool InputEvent_IsShiftDown(const FInputEvent& Input); /** @@ -100,7 +111,7 @@ class ENGINE_API UKismetInputLibrary : public UBlueprintFunctionLibrary * * @return True if left shift is pressed. */ - UFUNCTION(BlueprintPure, meta=( DisplayName = "IsLeftShiftDown" ), Category="Utilities|InputEvent") + UFUNCTION(BlueprintPure, meta=( DisplayName = "Is Left Shift Down" ), Category="Utilities|InputEvent") static bool InputEvent_IsLeftShiftDown(const FInputEvent& Input); /** @@ -108,7 +119,7 @@ class ENGINE_API UKismetInputLibrary : public UBlueprintFunctionLibrary * * @return True if right shift is pressed. */ - UFUNCTION(BlueprintPure, meta=( DisplayName = "IsRightShiftDown" ), Category="Utilities|InputEvent") + UFUNCTION(BlueprintPure, meta=( DisplayName = "Is Right Shift Down" ), Category="Utilities|InputEvent") static bool InputEvent_IsRightShiftDown(const FInputEvent& Input); /** @@ -116,7 +127,7 @@ class ENGINE_API UKismetInputLibrary : public UBlueprintFunctionLibrary * * @return True if control is pressed */ - UFUNCTION(BlueprintPure, meta=( DisplayName = "IsControlDown" ), Category="Utilities|InputEvent") + UFUNCTION(BlueprintPure, meta=( DisplayName = "Is Control Down" ), Category="Utilities|InputEvent") static bool InputEvent_IsControlDown(const FInputEvent& Input); /** @@ -124,7 +135,7 @@ class ENGINE_API UKismetInputLibrary : public UBlueprintFunctionLibrary * * @return True if left control is pressed */ - UFUNCTION(BlueprintPure, meta=( DisplayName = "IsLeftControlDown" ), Category="Utilities|InputEvent") + UFUNCTION(BlueprintPure, meta=( DisplayName = "Is Left Control Down" ), Category="Utilities|InputEvent") static bool InputEvent_IsLeftControlDown(const FInputEvent& Input); /** @@ -132,7 +143,7 @@ class ENGINE_API UKismetInputLibrary : public UBlueprintFunctionLibrary * * @return True if left control is pressed */ - UFUNCTION(BlueprintPure, meta=( DisplayName = "IsRightControlDown" ), Category="Utilities|InputEvent") + UFUNCTION(BlueprintPure, meta=( DisplayName = "Is Right Control Down" ), Category="Utilities|InputEvent") static bool InputEvent_IsRightControlDown(const FInputEvent& Input); /** @@ -140,7 +151,7 @@ class ENGINE_API UKismetInputLibrary : public UBlueprintFunctionLibrary * * @return True if alt is pressed */ - UFUNCTION(BlueprintPure, meta=( DisplayName = "IsAltDown" ), Category="Utilities|InputEvent") + UFUNCTION(BlueprintPure, meta=( DisplayName = "Is Alt Down" ), Category="Utilities|InputEvent") static bool InputEvent_IsAltDown(const FInputEvent& Input); /** @@ -148,7 +159,7 @@ class ENGINE_API UKismetInputLibrary : public UBlueprintFunctionLibrary * * @return True if left alt is pressed */ - UFUNCTION(BlueprintPure, meta=( DisplayName = "IsLeftAltDown" ), Category="Utilities|InputEvent") + UFUNCTION(BlueprintPure, meta=( DisplayName = "Is Left Alt Down" ), Category="Utilities|InputEvent") static bool InputEvent_IsLeftAltDown(const FInputEvent& Input); /** @@ -156,7 +167,7 @@ class ENGINE_API UKismetInputLibrary : public UBlueprintFunctionLibrary * * @return True if right alt is pressed */ - UFUNCTION(BlueprintPure, meta=( DisplayName = "IsRightAltDown" ), Category="Utilities|InputEvent") + UFUNCTION(BlueprintPure, meta=( DisplayName = "Is Right Alt Down" ), Category="Utilities|InputEvent") static bool InputEvent_IsRightAltDown(const FInputEvent& Input); /** @@ -164,7 +175,7 @@ class ENGINE_API UKismetInputLibrary : public UBlueprintFunctionLibrary * * @return True if command is pressed */ - UFUNCTION(BlueprintPure, meta=( DisplayName = "IsCommandDown" ), Category="Utilities|InputEvent") + UFUNCTION(BlueprintPure, meta=( DisplayName = "Is Command Down" ), Category="Utilities|InputEvent") static bool InputEvent_IsCommandDown(const FInputEvent& Input); /** @@ -172,7 +183,7 @@ class ENGINE_API UKismetInputLibrary : public UBlueprintFunctionLibrary * * @return True if left command is pressed */ - UFUNCTION(BlueprintPure, meta=( DisplayName = "IsLeftCommandDown" ), Category="Utilities|InputEvent") + UFUNCTION(BlueprintPure, meta=( DisplayName = "Is Left Command Down" ), Category="Utilities|InputEvent") static bool InputEvent_IsLeftCommandDown(const FInputEvent& Input); /** @@ -180,7 +191,7 @@ class ENGINE_API UKismetInputLibrary : public UBlueprintFunctionLibrary * * @return True if right command is pressed */ - UFUNCTION(BlueprintPure, meta=( DisplayName = "IsRightCommandDown" ), Category="Utilities|InputEvent") + UFUNCTION(BlueprintPure, meta=( DisplayName = "Is Right Command Down" ), Category="Utilities|InputEvent") static bool InputEvent_IsRightCommandDown(const FInputEvent& Input); @@ -189,68 +200,66 @@ class ENGINE_API UKismetInputLibrary : public UBlueprintFunctionLibrary * * @return Key name */ - UFUNCTION(BlueprintCallable, Category="Utilities|KeyEvent") + UFUNCTION(BlueprintPure, Category="Utilities|KeyEvent") static FKey GetKey(const FKeyEvent& Input); - UFUNCTION(BlueprintCallable, Category = "Utilities|KeyEvent") + UFUNCTION(BlueprintPure, Category = "Utilities|KeyEvent") static int32 GetUserIndex(const FKeyEvent& Input); - UFUNCTION(BlueprintCallable, Category = "Utilities|FAnalogInputEvent") + UFUNCTION(BlueprintPure, Category = "Utilities|FAnalogInputEvent") static float GetAnalogValue(const FAnalogInputEvent& Input); /** @return The position of the cursor in screen space */ - UFUNCTION(BlueprintPure, meta=( DisplayName = "GetScreenSpacePosition" ), Category="Utilities|PointerEvent") + UFUNCTION(BlueprintPure, meta=( DisplayName = "Get Screen Space Position" ), Category="Utilities|PointerEvent") static FVector2D PointerEvent_GetScreenSpacePosition(const FPointerEvent& Input); /** @return The position of the cursor in screen space last time we handled an input event */ - UFUNCTION(BlueprintPure, meta=( DisplayName = "GetLastScreenSpacePosition" ), Category="Utilities|PointerEvent") + UFUNCTION(BlueprintPure, meta=( DisplayName = "Get Last Screen Space Position" ), Category="Utilities|PointerEvent") static FVector2D PointerEvent_GetLastScreenSpacePosition(const FPointerEvent& Input); /** @return the distance the mouse traveled since the last event was handled. */ - UFUNCTION(BlueprintPure, meta=( DisplayName = "GetCursorDelta" ), Category="Utilities|PointerEvent") + UFUNCTION(BlueprintPure, meta=( DisplayName = "Get Cursor Delta" ), Category="Utilities|PointerEvent") static FVector2D PointerEvent_GetCursorDelta(const FPointerEvent& Input); /** Mouse buttons that are currently pressed */ - UFUNCTION(BlueprintPure, meta=( DisplayName = "IsMouseButtonDown" ), Category="Utilities|PointerEvent") + UFUNCTION(BlueprintPure, meta=( DisplayName = "Is Mouse Button Down" ), Category="Utilities|PointerEvent") static bool PointerEvent_IsMouseButtonDown(const FPointerEvent& Input, FKey MouseButton); /** Mouse button that caused this event to be raised (possibly EB_None) */ - UFUNCTION(BlueprintPure, meta=( DisplayName = "GetEffectingButton" ), Category="Utilities|PointerEvent") + UFUNCTION(BlueprintPure, meta=( DisplayName = "Get Effecting Button" ), Category="Utilities|PointerEvent") static FKey PointerEvent_GetEffectingButton(const FPointerEvent& Input); /** How much did the mouse wheel turn since the last mouse event */ - UFUNCTION(BlueprintPure, meta=( DisplayName = "GetWheelDelta" ), Category="Utilities|PointerEvent") + UFUNCTION(BlueprintPure, meta=( DisplayName = "Get Wheel Delta" ), Category="Utilities|PointerEvent") static float PointerEvent_GetWheelDelta(const FPointerEvent& Input); /** @return The index of the user that caused the event */ - UFUNCTION(BlueprintPure, meta=( DisplayName = "GetUserIndex" ), Category="Utilities|PointerEvent") + UFUNCTION(BlueprintPure, meta=( DisplayName = "Get User Index" ), Category="Utilities|PointerEvent") static int32 PointerEvent_GetUserIndex(const FPointerEvent& Input); /** @return The unique identifier of the pointer (e.g., finger index) */ - UFUNCTION(BlueprintPure, meta=( DisplayName = "GetPointerIndex" ), Category="Utilities|PointerEvent") + UFUNCTION(BlueprintPure, meta=( DisplayName = "Get Pointer Index" ), Category="Utilities|PointerEvent") static int32 PointerEvent_GetPointerIndex(const FPointerEvent& Input); /** @return The index of the touch pad that generated this event (for platforms with multiple touch pads per user) */ - UFUNCTION(BlueprintPure, meta=( DisplayName = "GetTouchpadIndex" ), Category="Utilities|PointerEvent") + UFUNCTION(BlueprintPure, meta=( DisplayName = "Get Touchpad Index" ), Category="Utilities|PointerEvent") static int32 PointerEvent_GetTouchpadIndex(const FPointerEvent& Input); /** @return Is this event a result from a touch (as opposed to a mouse) */ - UFUNCTION(BlueprintPure, meta=( DisplayName = "IsTouchEvent" ), Category="Utilities|PointerEvent") + UFUNCTION(BlueprintPure, meta=( DisplayName = "Is Touch Event" ), Category="Utilities|PointerEvent") static bool PointerEvent_IsTouchEvent(const FPointerEvent& Input); - //TODO UMG Support GetGestureType() - - ///** @return The type of touch gesture */ - //UFUNCTION(BlueprintPure, meta=( DisplayName = "GetGestureType" ), Category="Utilities|PointerEvent") - //static EGestureEvent::Type PointerEvent_GetGestureType(const FPointerEvent& Input); + /** @return The type of touch gesture */ + UFUNCTION(BlueprintPure, meta=( DisplayName = "GetGestureType" ), Category="Utilities|PointerEvent") + static ESlateGesture PointerEvent_GetGestureType(const FPointerEvent& Input); /** @return The change in gesture value since the last gesture event of the same type. */ - UFUNCTION(BlueprintPure, meta=( DisplayName = "GetGestureDelta" ), Category="Utilities|PointerEvent") + UFUNCTION(BlueprintPure, meta=( DisplayName = "Get Gesture Delta" ), Category="Utilities|PointerEvent") static FVector2D PointerEvent_GetGestureDelta(const FPointerEvent& Input); /** @return The controller button that caused this event */ - UFUNCTION(BlueprintPure, meta = (DeprecatedFunction, DeprecationMessage = "Use GetKey() for KeyEvent instead", DisplayName = "GetEffectingButton"), Category = "Utilities|ControllerEvent") + UFUNCTION(BlueprintPure, meta = (DeprecatedFunction, DeprecationMessage = "Use GetKey() for KeyEvent instead", DisplayName = "Get Effecting Button"), Category = "Utilities|ControllerEvent") static FKey ControllerEvent_GetEffectingButton(const FControllerEvent& Input); /** @return The index of the user that caused the event */ diff --git a/Engine/Source/Runtime/Engine/Classes/Kismet/KismetInternationalizationLibrary.h b/Engine/Source/Runtime/Engine/Classes/Kismet/KismetInternationalizationLibrary.h new file mode 100644 index 000000000000..8e3e5019e41e --- /dev/null +++ b/Engine/Source/Runtime/Engine/Classes/Kismet/KismetInternationalizationLibrary.h @@ -0,0 +1,113 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "UObject/TextProperty.h" +#include "Kismet/BlueprintFunctionLibrary.h" +#include "KismetInternationalizationLibrary.generated.h" + +UCLASS(meta=(BlueprintThreadSafe)) +class ENGINE_API UKismetInternationalizationLibrary : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() + +public: + /** + * Set the current culture. + * @note This function is a sledgehammer, and will set both the language and locale, as well as clear out any asset group cultures that may be set. + * @param Culture The culture to set, as an IETF language tag (eg, "zh-Hans-CN"). + * @param SaveToConfig If true, save the new setting to the users' "GameUserSettings" config so that it persists after a reload. + * @return True if the culture was set, false otherwise. + */ + UFUNCTION(BlueprintCallable, Category="Utilities|Internationalization", meta=(AdvancedDisplay="1")) + static bool SetCurrentCulture(const FString& Culture, const bool SaveToConfig = false); + + /** + * Get the current culture as an IETF language tag: + * - A two-letter ISO 639-1 language code (eg, "zh"). + * - An optional four-letter ISO 15924 script code (eg, "Hans"). + * - An optional two-letter ISO 3166-1 country code (eg, "CN"). + * @note This function exists for legacy API parity with SetCurrentCulture and is equivalent to GetCurrentLanguage. + * @return The culture as an IETF language tag (eg, "zh-Hans-CN"). + */ + UFUNCTION(BlueprintPure, Category="Utilities|Internationalization") + static FString GetCurrentCulture(); + + /** + * Set *only* the current language (for localization). + * @note Unless you're doing something advanced, you likely want SetCurrentLanguageAndLocale or SetCurrentCulture instead. + * @param Culture The language to set, as an IETF language tag (eg, "zh-Hans-CN"). + * @param SaveToConfig If true, save the new setting to the users' "GameUserSettings" config so that it persists after a reload. + * @return True if the language was set, false otherwise. + */ + UFUNCTION(BlueprintCallable, Category="Utilities|Internationalization", meta=(AdvancedDisplay="1")) + static bool SetCurrentLanguage(const FString& Culture, const bool SaveToConfig = false); + + /** + * Get the current language (for localization) as an IETF language tag: + * - A two-letter ISO 639-1 language code (eg, "zh"). + * - An optional four-letter ISO 15924 script code (eg, "Hans"). + * - An optional two-letter ISO 3166-1 country code (eg, "CN"). + * @return The language as an IETF language tag (eg, "zh-Hans-CN"). + */ + UFUNCTION(BlueprintPure, Category="Utilities|Internationalization") + static FString GetCurrentLanguage(); + + /** + * Set *only* the current locale (for internationalization). + * @note Unless you're doing something advanced, you likely want SetCurrentLanguageAndLocale or SetCurrentCulture instead. + * @param Culture The locale to set, as an IETF language tag (eg, "zh-Hans-CN"). + * @param SaveToConfig If true, save the new setting to the users' "GameUserSettings" config so that it persists after a reload. + * @return True if the locale was set, false otherwise. + */ + UFUNCTION(BlueprintCallable, Category="Utilities|Internationalization", meta=(AdvancedDisplay="1")) + static bool SetCurrentLocale(const FString& Culture, const bool SaveToConfig = false); + + /** + * Get the current locale (for internationalization) as an IETF language tag: + * - A two-letter ISO 639-1 language code (eg, "zh"). + * - An optional four-letter ISO 15924 script code (eg, "Hans"). + * - An optional two-letter ISO 3166-1 country code (eg, "CN"). + * @return The locale as an IETF language tag (eg, "zh-Hans-CN"). + */ + UFUNCTION(BlueprintPure, Category="Utilities|Internationalization") + static FString GetCurrentLocale(); + + /** + * Set the current language (for localization) and locale (for internationalization). + * @param Culture The language and locale to set, as an IETF language tag (eg, "zh-Hans-CN"). + * @param SaveToConfig If true, save the new setting to the users' "GameUserSettings" config so that it persists after a reload. + * @return True if the language and locale were set, false otherwise. + */ + UFUNCTION(BlueprintCallable, Category="Utilities|Internationalization", meta=(AdvancedDisplay="1")) + static bool SetCurrentLanguageAndLocale(const FString& Culture, const bool SaveToConfig = false); + + /** + * Set the given asset group category culture from an IETF language tag (eg, "zh-Hans-CN"). + * @param AssetGroup The asset group to set the culture for. + * @param Culture The culture to set, as an IETF language tag (eg, "zh-Hans-CN"). + * @param SaveToConfig If true, save the new setting to the users' "GameUserSettings" config so that it persists after a reload. + * @return True if the culture was set, false otherwise. + */ + UFUNCTION(BlueprintCallable, Category="Utilities|Internationalization", meta=(AdvancedDisplay="2")) + static bool SetCurrentAssetGroupCulture(const FName AssetGroup, const FString& Culture, const bool SaveToConfig = false); + + /** + * Get the given asset group category culture. + * @note Returns the current language if the group category doesn't have a culture override. + * @param AssetGroup The asset group to get the culture for. + * @return The culture as an IETF language tag (eg, "zh-Hans-CN"). + */ + UFUNCTION(BlueprintPure, Category="Utilities|Internationalization") + static FString GetCurrentAssetGroupCulture(const FName AssetGroup); + + /** + * Clear the given asset group category culture. + * @param AssetGroup The asset group to clear the culture for. + * @param SaveToConfig If true, save the new setting to the users' "GameUserSettings" config so that it persists after a reload. + */ + UFUNCTION(BlueprintCallable, Category="Utilities|Internationalization", meta=(AdvancedDisplay="1")) + static void ClearCurrentAssetGroupCulture(const FName AssetGroup, const bool SaveToConfig = false); +}; diff --git a/Engine/Source/Runtime/Engine/Classes/Kismet/KismetMathLibrary.h b/Engine/Source/Runtime/Engine/Classes/Kismet/KismetMathLibrary.h index ed26de95c31b..86555515fd17 100644 --- a/Engine/Source/Runtime/Engine/Classes/Kismet/KismetMathLibrary.h +++ b/Engine/Source/Runtime/Engine/Classes/Kismet/KismetMathLibrary.h @@ -437,7 +437,10 @@ class ENGINE_API UKismetMathLibrary : public UBlueprintFunctionLibrary UFUNCTION(BlueprintPure, meta=(DisplayName = "NotEqual (float)", CompactNodeTitle = "!=", Keywords = "!= not equal"), Category="Math|Float") static bool NotEqual_FloatFloat(float A, float B); - /* Returns V clamped to be between A and B (inclusive) */ + /* Returns true if value is between Min and Max (V >= Min && V <= Max) + * If InclusiveMin is true, value needs to be equal or larger than Min, else it needs to be larger + * If InclusiveMax is true, value needs to be smaller or equal than Max, else it needs to be smaller + */ UFUNCTION(BlueprintPure, meta=(DisplayName = "InRange (float)", Min="0.0", Max="1.0"), Category="Math|Float") static bool InRange_FloatFloat(float Value, float Min, float Max, bool InclusiveMin = true, bool InclusiveMax = true); @@ -575,7 +578,7 @@ class ENGINE_API UKismetMathLibrary : public UBlueprintFunctionLibrary UFUNCTION(BlueprintPure, meta=(DisplayName = "Max (float)", CompactNodeTitle = "MAX", CommutativeAssociativeBinaryOperator = "true"), Category="Math|Float") static float FMax(float A, float B); - /* Returns V clamped to be between A and B (inclusive) */ + /* Returns Value clamped between A and B (inclusive) */ UFUNCTION(BlueprintPure, meta=(DisplayName = "Clamp (float)", Min="0.0", Max="1.0"), Category="Math|Float") static float FClamp(float Value, float Min, float Max); @@ -720,7 +723,7 @@ class ENGINE_API UKismetMathLibrary : public UBlueprintFunctionLibrary UFUNCTION(BlueprintPure, meta=(DisplayName = "vector / int", CompactNodeTitle = "/", Keywords = "/ divide division"), Category="Math|Vector") static FVector Divide_VectorInt(FVector A, int32 B = 1); - /* Vector divide by vector */ + /* Element-wise Vector division (Result = {A.x/B.x, A.y/B.y, A.z/B.z}) */ UFUNCTION(BlueprintPure, meta=(DisplayName = "vector / vector", CompactNodeTitle = "/", Keywords = "/ divide division"), Category="Math|Vector") static FVector Divide_VectorVector(FVector A, FVector B = FVector(1.f,1.f,1.f)); diff --git a/Engine/Source/Runtime/Engine/Classes/Kismet/KismetSystemLibrary.h b/Engine/Source/Runtime/Engine/Classes/Kismet/KismetSystemLibrary.h index 5d3f8d1e4e53..9a36fc0d19e1 100644 --- a/Engine/Source/Runtime/Engine/Classes/Kismet/KismetSystemLibrary.h +++ b/Engine/Source/Runtime/Engine/Classes/Kismet/KismetSystemLibrary.h @@ -63,7 +63,7 @@ namespace EQuitPreference }; } -USTRUCT() +USTRUCT(BlueprintInternalUseOnly) struct FGenericStruct { GENERATED_USTRUCT_BODY() @@ -169,14 +169,45 @@ class ENGINE_API UKismetSystemLibrary : public UBlueprintFunctionLibrary UFUNCTION(BlueprintPure, Category="Utilities|Platform") static FString GetDeviceId(); + /** Converts an interfance into an object */ UFUNCTION(BlueprintPure, meta=(DisplayName = "ToObject (interface)", CompactNodeTitle = "->"), Category="Utilities") static UObject* Conv_InterfaceToObject(const FScriptInterface& Interface); - UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Utilities") - static UObject* Conv_AssetToObject(const TAssetPtr& Asset); + /** Returns true if the Soft Object Reference is not null */ + UFUNCTION(BlueprintPure, Category = "Utilities") + static bool IsValidSoftObjectReference(const TAssetPtr& SoftObjectReference); + + /** Returns true if the values are equal (A == B) */ + UFUNCTION(BlueprintPure, meta = (DisplayName = "Equal (SoftObjectReference)", CompactNodeTitle = "=="), Category = "Utilities") + static bool EqualEqual_SoftObjectReference(const TAssetPtr& A, const TAssetPtr& B); + + /** Returns true if the values are not equal (A != B) */ + UFUNCTION(BlueprintPure, meta = (DisplayName = "NotEqual (SoftObjectReference)", CompactNodeTitle = "!="), Category = "Utilities") + static bool NotEqual_SoftObjectReference(const TAssetPtr& A, const TAssetPtr& B); + + /** Returns true if the Soft Class Reference is not null */ + UFUNCTION(BlueprintPure, Category = "Utilities") + static bool IsValidSoftClassReference(const TAssetSubclassOf& SoftClassReference); + + /** Returns true if the values are equal (A == B) */ + UFUNCTION(BlueprintPure, meta = (DisplayName = "Equal (SoftClassReference)", CompactNodeTitle = "=="), Category = "Utilities") + static bool EqualEqual_SoftClassReference(const TAssetSubclassOf& A, const TAssetSubclassOf& B); + + /** Returns true if the values are not equal (A != B) */ + UFUNCTION(BlueprintPure, meta = (DisplayName = "NotEqual (SoftClassReference)", CompactNodeTitle = "!="), Category = "Utilities") + static bool NotEqual_SoftClassReference(const TAssetSubclassOf& A, const TAssetSubclassOf& B); UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Utilities") - static TSubclassOf Conv_AssetClassToClass(const TAssetSubclassOf& AssetClass); + static UObject* Conv_SoftObjectReferenceToObject(const TAssetPtr& Asset); + + UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Utilities") + static TSubclassOf Conv_SoftClassReferenceToClass(const TAssetSubclassOf& AssetClass); + + UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Utilities") + static TAssetPtr Conv_ObjectToSoftObjectReference(UObject* Object); + + UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Utilities") + static TAssetSubclassOf Conv_ClassToSoftClassReference(const TSubclassOf& Class); DECLARE_DYNAMIC_DELEGATE_OneParam(FOnAssetLoaded, class UObject*, Loaded); @@ -1502,8 +1533,24 @@ class ENGINE_API UKismetSystemLibrary : public UBlueprintFunctionLibrary static TArray GetPreferredLanguages(); /** - * Returns the user's preferred language and region - * @return A language ID indicating the user's language and region + * Get the default language (for localization) used by this platform + * @note This is typically the same as GetDefaultLocale unless the platform distinguishes between the two + * @note This should be returned in IETF language tag form: + * - A two-letter ISO 639-1 language code (eg, "zh") + * - An optional four-letter ISO 15924 script code (eg, "Hans") + * - An optional two-letter ISO 3166-1 country code (eg, "CN") + * @return The language as an IETF language tag (eg, "zh-Hans-CN") + */ + UFUNCTION(BlueprintPure, Category = "Utilities|Platform") + static FString GetDefaultLanguage(); + + /** + * Get the default locale (for internationalization) used by this platform + * @note This should be returned in IETF language tag form: + * - A two-letter ISO 639-1 language code (eg, "zh") + * - An optional four-letter ISO 15924 script code (eg, "Hans") + * - An optional two-letter ISO 3166-1 country code (eg, "CN") + * @return The locale as an IETF language tag (eg, "zh-Hans-CN") */ UFUNCTION(BlueprintPure, Category = "Utilities|Platform") static FString GetDefaultLocale(); @@ -1524,11 +1571,18 @@ class ENGINE_API UKismetSystemLibrary : public UBlueprintFunctionLibrary /** * Requests permission to send remote notifications to the user's device. - * (iOS only) + * (Android and iOS only) */ UFUNCTION(BlueprintCallable, Category = "Utilities|Platform") static void RegisterForRemoteNotifications(); + /** + * Requests Requests unregistering from receiving remote notifications to the user's device. + * (Android only) + */ + UFUNCTION(BlueprintCallable, Category = "Utilities|Platform") + static void UnregisterForRemoteNotifications(); + /** * Tells the engine what the user is doing for debug, analytics, etc. */ @@ -1540,6 +1594,92 @@ class ENGINE_API UKismetSystemLibrary : public UBlueprintFunctionLibrary */ UFUNCTION(BlueprintCallable, Category="Utilities") static FString GetCommandLine(); + + // --- Asset Manager ------------------------------ + + /** Returns the Object associated with a Primary Asset Id, this will only return a valid object if it is in memory, it will not load it */ + UFUNCTION(BlueprintPure, Category = "AssetManager") + static UObject* GetObjectFromPrimaryAssetId(FPrimaryAssetId PrimaryAssetId); + + /** Returns the Blueprint Class associated with a Primary Asset Id, this will only return a valid object if it is in memory, it will not load it */ + UFUNCTION(BlueprintPure, Category = "AssetManager") + static TSubclassOf GetClassFromPrimaryAssetId(FPrimaryAssetId PrimaryAssetId); + + /** Returns the Object Id associated with a Primary Asset Id, this works even if the asset is not loaded */ + UFUNCTION(BlueprintPure, Category = "AssetManager") + static TAssetPtr GetSoftObjectReferenceFromPrimaryAssetId(FPrimaryAssetId PrimaryAssetId); + + /** Returns the Blueprint Class Id associated with a Primary Asset Id, this works even if the asset is not loaded */ + UFUNCTION(BlueprintPure, Category = "AssetManager") + static TAssetSubclassOf GetSoftClassReferenceFromPrimaryAssetId(FPrimaryAssetId PrimaryAssetId); + + /** Returns the Primary Asset Id for an Object, this can return an invalid one if not registered */ + UFUNCTION(BlueprintPure, Category = "AssetManager") + static FPrimaryAssetId GetPrimaryAssetIdFromObject(UObject* Object); + + /** Returns the Primary Asset Id for a Class, this can return an invalid one if not registered */ + UFUNCTION(BlueprintPure, Category = "AssetManager") + static FPrimaryAssetId GetPrimaryAssetIdFromClass(TSubclassOf Class); + + /** Returns the Primary Asset Id for a Soft Object Reference, this can return an invalid one if not registered */ + UFUNCTION(BlueprintPure, Category = "AssetManager") + static FPrimaryAssetId GetPrimaryAssetIdFromSoftObjectReference(TAssetPtr SoftObjectReference); + + /** Returns the Primary Asset Id for a Soft Class Reference, this can return an invalid one if not registered */ + UFUNCTION(BlueprintPure, Category = "AssetManager") + static FPrimaryAssetId GetPrimaryAssetIdFromSoftClassReference(TAssetSubclassOf SoftClassReference); + + /** Returns list of PrimaryAssetIds for a PrimaryAssetType */ + UFUNCTION(BlueprintCallable, Category = "AssetManager") + static void GetPrimaryAssetIdList(FPrimaryAssetType PrimaryAssetType, TArray& OutPrimaryAssetIdList); + + /** Returns true if the Primary Asset Id is valid */ + UFUNCTION(BlueprintPure, Category = "AssetManager") + static bool IsValidPrimaryAssetId(FPrimaryAssetId PrimaryAssetId); + + /** Returns true if the values are equal (A == B) */ + UFUNCTION(BlueprintPure, meta = (DisplayName = "Equal (PrimaryAssetId)", CompactNodeTitle = "=="), Category = "AssetManager") + static bool EqualEqual_PrimaryAssetId(FPrimaryAssetId A, FPrimaryAssetId B); + + /** Returns true if the values are not equal (A != B) */ + UFUNCTION(BlueprintPure, meta = (DisplayName = "NotEqual (PrimaryAssetId)", CompactNodeTitle = "!="), Category = "AssetManager") + static bool NotEqual_PrimaryAssetId(FPrimaryAssetId A, FPrimaryAssetId B); + + /** Returns list of PrimaryAssetIds for a PrimaryAssetType */ + UFUNCTION(BlueprintPure, Category = "AssetManager") + static bool IsValidPrimaryAssetType(FPrimaryAssetType PrimaryAssetType); + + /** Returns true if the values are equal (A == B) */ + UFUNCTION(BlueprintPure, meta = (DisplayName = "Equal (PrimaryAssetType)", CompactNodeTitle = "=="), Category = "AssetManager") + static bool EqualEqual_PrimaryAssetType(FPrimaryAssetType A, FPrimaryAssetType B); + + /** Returns true if the values are not equal (A != B) */ + UFUNCTION(BlueprintPure, meta = (DisplayName = "NotEqual (PrimaryAssetType)", CompactNodeTitle = "!="), Category = "AssetManager") + static bool NotEqual_PrimaryAssetType(FPrimaryAssetType A, FPrimaryAssetType B); + + /** Unloads a primary asset, which allows it to be garbage collected if nothing else is referencing it */ + UFUNCTION(BlueprintCallable, Category = "AssetManager") + static void UnloadPrimaryAsset(FPrimaryAssetId PrimaryAssetId); + + /** Unloads a primary asset, which allows it to be garbage collected if nothing else is referencing it */ + UFUNCTION(BlueprintCallable, Category = "AssetManager") + static void UnloadPrimaryAssetList(const TArray& PrimaryAssetIdList); + + /** + * Returns the list of loaded bundles for a given Primary Asset. This will return false if the asset is not loaded at all. + * If ForceCurrentState is true it will return the current state even if a load is in process + */ + UFUNCTION(BlueprintCallable, Category = "AssetManager") + static bool GetCurrentBundleState(FPrimaryAssetId PrimaryAssetId, bool bForceCurrentState, TArray& OutBundles); + + /** + * Returns the list of assets that are in a given bundle state. Required Bundles must be specified + * If ExcludedBundles is not empty, it will not return any assets in those bundle states + * If ValidTypes is not empty, it will only return assets of those types + * If ForceCurrentState is true it will use the current state even if a load is in process + */ + UFUNCTION(BlueprintCallable, Category = "AssetManager", meta=(AutoCreateRefTerm = "ExcludedBundles, ValidTypes")) + static void GetPrimaryAssetsWithBundleState(const TArray& RequiredBundles, const TArray& ExcludedBundles, const TArray& ValidTypes, bool bForceCurrentState, TArray& OutPrimaryAssetIdList); }; diff --git a/Engine/Source/Runtime/Engine/Classes/Kismet/KismetTextLibrary.h b/Engine/Source/Runtime/Engine/Classes/Kismet/KismetTextLibrary.h index f2f9a25c9bf6..b6fd42cd2cff 100644 --- a/Engine/Source/Runtime/Engine/Classes/Kismet/KismetTextLibrary.h +++ b/Engine/Source/Runtime/Engine/Classes/Kismet/KismetTextLibrary.h @@ -57,7 +57,7 @@ namespace EFormatArgumentType * Used to pass argument/value pairs into FText::Format. * The full C++ struct is located here: Engine\Source\Runtime\Core\Public\Internationalization\Text.h */ -USTRUCT(noexport) +USTRUCT(noexport, BlueprintInternalUseOnly) struct FFormatArgumentData { UPROPERTY(EditInstanceOnly, BlueprintReadWrite, Category=ArgumentName) @@ -85,27 +85,27 @@ class ENGINE_API UKismetTextLibrary : public UBlueprintFunctionLibrary { GENERATED_UCLASS_BODY() - /** Converts a vector value to a localizable text, in the form 'X= Y= Z=' */ + /** Converts a vector value to localized formatted text, in the form 'X= Y= Z=' */ UFUNCTION(BlueprintPure, meta = (DisplayName = "ToText (Vector)", CompactNodeTitle = "->", BlueprintAutocast), Category = "Utilities|Text") static FText Conv_VectorToText(FVector InVec); - /** Converts a vector2d value to a localizable text, in the form 'X= Y=' */ + /** Converts a vector2d value to localized formatted text, in the form 'X= Y=' */ UFUNCTION(BlueprintPure, meta = (DisplayName = "ToText (vector2d)", CompactNodeTitle = "->", BlueprintAutocast), Category = "Utilities|Text") static FText Conv_Vector2dToText(FVector2D InVec); - /** Converts a rotator value to a localizable text, in the form 'P= Y= R=' */ + /** Converts a rotator value to localized formatted text, in the form 'P= Y= R=' */ UFUNCTION(BlueprintPure, meta = (DisplayName = "ToText (rotator)", CompactNodeTitle = "->", BlueprintAutocast), Category = "Utilities|Text") static FText Conv_RotatorToText(FRotator InRot); - /** Converts a transform value to a localizable text, in the form 'Translation: X= Y= Z= Rotation: P= Y= R= Scale: X= Y= Z=' */ + /** Converts a transform value to localized formatted text, in the form 'Translation: X= Y= Z= Rotation: P= Y= R= Scale: X= Y= Z=' */ UFUNCTION(BlueprintPure, meta = (DisplayName = "ToText (transform)", CompactNodeTitle = "->", BlueprintAutocast), Category = "Utilities|Text") static FText Conv_TransformToText(const FTransform& InTrans); - /** Converts a UObject value to a localizable text by calling the object's GetName method */ - UFUNCTION(BlueprintPure, meta = (DisplayName = "ToText (object)", CompactNodeTitle = "->", BlueprintAutocast), Category = "Utilities|Text") + /** Converts a UObject value to culture invariant text by calling the object's GetName method */ + UFUNCTION(BlueprintPure, meta = (DisplayName = "ToText (object)", BlueprintAutocast), Category = "Utilities|Text") static FText Conv_ObjectToText(class UObject* InObj); - /** Converts a linear color value to a localizable text, in the form '(R=,G=,B=,A=)' */ + /** Converts a linear color value to localized formatted text, in the form '(R=,G=,B=,A=)' */ UFUNCTION(BlueprintPure, meta = (DisplayName = "ToText (linear color)", CompactNodeTitle = "->", BlueprintAutocast), Category = "Utilities|Text") static FText Conv_ColorToText(FLinearColor InColor); @@ -113,12 +113,12 @@ class ENGINE_API UKismetTextLibrary : public UBlueprintFunctionLibrary UFUNCTION(BlueprintPure, meta = (DisplayName = "ToString (text)", CompactNodeTitle = "->", BlueprintAutocast), Category = "Utilities|String") static FString Conv_TextToString(const FText& InText); - /** Converts string to localizable text */ - UFUNCTION(BlueprintPure, meta=(DisplayName = "ToText (string)", CompactNodeTitle = "->", BlueprintAutocast), Category="Utilities|Text") + /** Converts string to culture invariant text. Use Format or Make Literal Text to create localizable text */ + UFUNCTION(BlueprintPure, meta=(DisplayName = "ToText (string)", BlueprintAutocast), Category="Utilities|Text") static FText Conv_StringToText(const FString& InString); - /** Converts string to localizable text */ - UFUNCTION(BlueprintPure, meta=(DisplayName = "ToText (name)", CompactNodeTitle = "->", BlueprintAutocast), Category="Utilities|Text") + /** Converts Name to culture invariant text */ + UFUNCTION(BlueprintPure, meta=(DisplayName = "ToText (name)", BlueprintAutocast), Category="Utilities|Text") static FText Conv_NameToText(FName InName); /* Returns true if text is empty. */ @@ -183,21 +183,21 @@ class ENGINE_API UKismetTextLibrary : public UBlueprintFunctionLibrary UFUNCTION(BlueprintPure, meta=(DisplayName = "NotEqual, Case Insensitive (text)", CompactNodeTitle = "!="), Category="Utilities|Text") static bool NotEqual_IgnoreCase_TextText(const FText& A, const FText& B); - /** Converts a boolean value to text, either 'true' or 'false' */ + /** Converts a boolean value to formatted text, either 'true' or 'false' */ UFUNCTION(BlueprintPure, meta=(DisplayName = "ToText (boolean)", CompactNodeTitle = "->", BlueprintAutocast), Category="Utilities|Text") static FText Conv_BoolToText(bool InBool); - /** Converts a byte value to text */ + /** Converts a byte value to formatted text */ UFUNCTION(BlueprintPure, meta=(DisplayName = "ToText (byte)", CompactNodeTitle = "->", BlueprintAutocast), Category="Utilities|Text") static FText Conv_ByteToText(uint8 Value); // Default values are duplicated from FNumberFormattingOptions and should be replicated in all functions and in the struct when changed! - /* Converts a passed in integer to a text based on formatting options */ + /* Converts a passed in integer to text based on formatting options */ UFUNCTION(BlueprintPure, meta=(DisplayName = "ToText (int)", AdvancedDisplay = "1", BlueprintAutocast), Category="Utilities|Text") static FText Conv_IntToText(int32 Value, bool bUseGrouping = true, int32 MinimumIntegralDigits = 1, int32 MaximumIntegralDigits = 324); // Default values are duplicated from FNumberFormattingOptions and should be replicated in all functions and in the struct when changed! - /* Converts a passed in float to a text based on formatting options */ + /* Converts a passed in float to text based on formatting options */ UFUNCTION(BlueprintPure, meta=(DisplayName = "ToText (float)", AdvancedDisplay = "1", BlueprintAutocast), Category="Utilities|Text") static FText Conv_FloatToText(float Value, TEnumAsByte RoundingMode, bool bUseGrouping = true, int32 MinimumIntegralDigits = 1, int32 MaximumIntegralDigits = 324, int32 MinimumFractionalDigits = 0, int32 MaximumFractionalDigits = 3); diff --git a/Engine/Source/Runtime/Engine/Classes/Lightmass/LightmassPortal.h b/Engine/Source/Runtime/Engine/Classes/Lightmass/LightmassPortal.h index 4264b13bdb11..f0317f61158f 100644 --- a/Engine/Source/Runtime/Engine/Classes/Lightmass/LightmassPortal.h +++ b/Engine/Source/Runtime/Engine/Classes/Lightmass/LightmassPortal.h @@ -14,8 +14,8 @@ class ALightmassPortal : public AActor { GENERATED_UCLASS_BODY() -private_subobject: - UPROPERTY(Category = Portal, VisibleAnywhere, BlueprintReadOnly) +private: + UPROPERTY(Category = Portal, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) class ULightmassPortalComponent* PortalComponent; #if WITH_EDITORONLY_DATA diff --git a/Engine/Source/Runtime/Engine/Classes/Materials/Material.h b/Engine/Source/Runtime/Engine/Classes/Materials/Material.h index 41ebb42bf72a..fac4d65f23f6 100644 --- a/Engine/Source/Runtime/Engine/Classes/Materials/Material.h +++ b/Engine/Source/Runtime/Engine/Classes/Materials/Material.h @@ -274,6 +274,24 @@ struct FMaterialParameterCollectionInfo } }; +USTRUCT() +struct FParameterGroupData +{ + GENERATED_USTRUCT_BODY() + + UPROPERTY(VisibleAnywhere, Category = "Group Sorting") + FString GroupName; + + UPROPERTY(EditAnywhere, Category = "Group Sorting") + int32 GroupSortPriority; + + FParameterGroupData() + { + GroupName = FString(TEXT("")); + GroupSortPriority = 0; + } +}; + /** * A Material is an asset which can be applied to a mesh to control the visual look of the scene. * When light from the scene hits the surface, the shading model of the material is used to calculate how that light interacts with the surface. @@ -406,7 +424,7 @@ public: FScalarMaterialInput PixelDepthOffset; /** Indicates that the material should be rendered in the SeparateTranslucency Pass (not affected by DOF, requires bAllowSeparateTranslucency to be set in .ini). */ - UPROPERTY(EditAnywhere, Category=Translucency, meta=(DisplayName = "Separate Translucency"), AdvancedDisplay) + UPROPERTY(EditAnywhere, Category=Translucency, meta=(DisplayName = "Render After DOF"), AdvancedDisplay) uint32 bEnableSeparateTranslucency:1; /** Indicates that the translucent material should not be affected by bloom or DOF. (Note: Depth testing is not available) */ @@ -715,6 +733,10 @@ public: UPROPERTY() TArray EditorComments; + /** Controls where this parameter group is displayed in a material instance parameter list. The lower the number the higher up in the parameter list. */ + UPROPERTY(EditAnywhere, EditFixedSize, Category = "Group Sorting") + TArray ParameterGroupData; + #endif // WITH_EDITORONLY_DATA /** Array of all functions this material depends on. */ UPROPERTY() @@ -855,8 +877,8 @@ public: ENGINE_API virtual void OverrideVectorParameterDefault(FName ParameterName, const FLinearColor& Value, bool bOverride, ERHIFeatureLevel::Type FeatureLevel) override; ENGINE_API virtual void OverrideScalarParameterDefault(FName ParameterName, float Value, bool bOverride, ERHIFeatureLevel::Type FeatureLevel) override; ENGINE_API virtual float GetScalarParameterDefault(FName ParameterName, ERHIFeatureLevel::Type FeatureLevel) override; - ENGINE_API virtual bool CheckMaterialUsage(const EMaterialUsage Usage, const bool bSkipPrim = false) override; - ENGINE_API virtual bool CheckMaterialUsage_Concurrent(const EMaterialUsage Usage, const bool bSkipPrim = false) const override; + ENGINE_API virtual bool CheckMaterialUsage(const EMaterialUsage Usage) override; + ENGINE_API virtual bool CheckMaterialUsage_Concurrent(const EMaterialUsage Usage) const override; ENGINE_API virtual FMaterialResource* AllocateResource(); ENGINE_API virtual FMaterialResource* GetMaterialResource(ERHIFeatureLevel::Type InFeatureLevel, EMaterialQualityLevel::Type QualityLevel = EMaterialQualityLevel::Num) override; ENGINE_API virtual const FMaterialResource* GetMaterialResource(ERHIFeatureLevel::Type InFeatureLevel, EMaterialQualityLevel::Type QualityLevel = EMaterialQualityLevel::Num) const override; @@ -865,6 +887,8 @@ public: ENGINE_API virtual bool GetTerrainLayerWeightParameterValue(FName ParameterName, int32& OutWeightmapIndex, FGuid &OutExpressionGuid) const override; ENGINE_API virtual bool UpdateLightmassTextureTracking() override; #if WITH_EDITOR + ENGINE_API virtual bool GetParameterSortPriority(FName ParameterName, int32& OutSortPriority) const override; + ENGINE_API virtual bool GetGroupSortPriority(const FString& InGroupName, int32& OutSortPriority) const override; ENGINE_API virtual bool GetTexturesInPropertyChain(EMaterialProperty InProperty, TArray& OutTextures, TArray* OutTextureParamNames, class FStaticParameterSet* InStaticParameterSet) override; #endif @@ -1000,10 +1024,9 @@ public: * Set the given usage flag. * @param bNeedsRecompile - true if the material was recompiled for the usage change * @param Usage - The usage flag to set - * @param bSkipPrim - Bypass the primitive type checks * @return bool - true if the material can be used for rendering with the given type. */ - ENGINE_API bool SetMaterialUsage(bool &bNeedsRecompile, const EMaterialUsage Usage, const bool bSkipPrim = false); + ENGINE_API bool SetMaterialUsage(bool &bNeedsRecompile, const EMaterialUsage Usage); /** * Tests to see if this material needs a usage flag update @@ -1176,6 +1199,12 @@ public: */ void CacheExpressionTextureReferences(); + /** Rebuild ExpressionTextureReferences with all textures referenced by expressions in this material. */ + void RebuildExpressionTextureReferences(); + + /** Attempts to add a new group name to the Group Data struct. True if new name was added. */ + ENGINE_API bool AttemptInsertNewGroupName(const FString& InNewName); + private: /** * Flush existing resource shader maps and resets the material resource's Ids. @@ -1192,9 +1221,7 @@ private: * Rebuild the MaterialParameterCollectionInfos array with the current state of the material's parameter collection dependencies. */ void RebuildMaterialParameterCollectionInfo(); - - /** Rebuild ExpressionTextureReferences with all textures referenced by expressions in this material. */ - void RebuildExpressionTextureReferences(); + /** * Cache resource shaders for rendering. diff --git a/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpression.h b/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpression.h index 4e1529017129..0b191f53feb1 100644 --- a/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpression.h +++ b/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpression.h @@ -93,7 +93,7 @@ struct FExpressionOutput }; #endif -UCLASS(abstract, hidecategories=Object) +UCLASS(abstract, BlueprintType, hidecategories=Object) class ENGINE_API UMaterialExpression : public UObject { GENERATED_UCLASS_BODY() diff --git a/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionCollectionParameter.h b/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionCollectionParameter.h index d5058a17e91d..228e87265dcf 100644 --- a/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionCollectionParameter.h +++ b/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionCollectionParameter.h @@ -47,6 +47,7 @@ class UMaterialExpressionCollectionParameter : public UMaterialExpression virtual bool HasAParameterName() const override { return true; } virtual FName GetParameterName() const override { return ParameterName; } virtual void SetParameterName(const FName& Name) override { ParameterName = Name; } + virtual void ValidateParameterName() override {}; #endif virtual bool MatchesSearchQuery( const TCHAR* SearchQuery ) override; diff --git a/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionParameter.h b/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionParameter.h index 3540c0acadf1..f794ca0f93b2 100644 --- a/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionParameter.h +++ b/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionParameter.h @@ -26,6 +26,12 @@ class UMaterialExpressionParameter : public UMaterialExpression UPROPERTY(EditAnywhere, Category=MaterialExpressionParameter) FName Group; +#if WITH_EDITORONLY_DATA + /** Controls where the this parameter is displayed in a material instance parameter list. The lower the number the higher up in the parameter list. */ + UPROPERTY(EditAnywhere, Category=MaterialExpressionParameter) + int32 SortPriority; +#endif + //~ Begin UMaterialExpression Interface virtual bool MatchesSearchQuery( const TCHAR* SearchQuery ) override; diff --git a/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionPower.h b/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionPower.h index ac0f17132b6e..ecac4f07c8aa 100644 --- a/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionPower.h +++ b/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionPower.h @@ -28,6 +28,7 @@ class UMaterialExpressionPower : public UMaterialExpression #if WITH_EDITOR virtual int32 Compile(class FMaterialCompiler* Compiler, int32 OutputIndex) override; virtual void GetCaption(TArray& OutCaptions) const override; + virtual void GetExpressionToolTip(TArray& OutToolTip) override; #endif //~ End UMaterialExpression Interface diff --git a/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionSobol.h b/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionSobol.h new file mode 100644 index 000000000000..d453f2b64b92 --- /dev/null +++ b/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionSobol.h @@ -0,0 +1,49 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "Materials/MaterialExpression.h" +#include "MaterialExpressionSobol.generated.h" + +UCLASS(MinimalAPI) +class UMaterialExpressionSobol : public UMaterialExpression +{ + GENERATED_UCLASS_BODY() + + /** 2D integer cell in 256x256 grid. + * Uses cell (0,0) if not connected */ + UPROPERTY() + FExpressionInput Cell; + + UPROPERTY(meta = ( + RequiredInput = "false", + Tooltip="Sobol point number. Use Const Index if not connected.")) + FExpressionInput Index; + + UPROPERTY(meta = ( + RequiredInput = "false", + Tooltip="2D Seed for sequence randomization (0,0)-(1,1). Use Const Seed if not connected.")) + FExpressionInput Seed; + + UPROPERTY(EditAnywhere, Category = MaterialExpressionSobol, meta = ( + OverridingInputProperty = "Index", + Tooltip="Sobol point number. Only used if Index is not connected.")) + uint32 ConstIndex; + + UPROPERTY(EditAnywhere, Category = MaterialExpressionSobol, meta = ( + OverridingInputProperty = "Seed", + Tooltip="2D Seed for sequence randomization. Only used if Seed is not connected.")) + FVector2D ConstSeed; + + //~ Begin UMaterialExpression Interface +#if WITH_EDITOR + virtual int32 Compile(class FMaterialCompiler* Compiler, int32 OutputIndex) override; + virtual void GetCaption(TArray& OutCaptions) const override; +#endif + //~ End UMaterialExpression Interface +}; + + + diff --git a/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionTemporalSobol.h b/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionTemporalSobol.h new file mode 100644 index 000000000000..229d98199bf2 --- /dev/null +++ b/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionTemporalSobol.h @@ -0,0 +1,44 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "Materials/MaterialExpression.h" +#include "MaterialExpressionTemporalSobol.generated.h" + +UCLASS(MinimalAPI) +class UMaterialExpressionTemporalSobol : public UMaterialExpression +{ + GENERATED_UCLASS_BODY() + + UPROPERTY(meta = ( + RequiredInput = "false", + Tooltip="Sobol point number. Use Const Index if not connected.")) + FExpressionInput Index; + + UPROPERTY(meta = ( + RequiredInput = "false", + Tooltip="2D Seed for sequence randomization (0,0)-(1,1). Use Const Seed if not connected.")) + FExpressionInput Seed; + + UPROPERTY(EditAnywhere, Category = MaterialExpressionSobol, meta = ( + OverridingInputProperty = "Index", + Tooltip="Sobol point number. Only used if Index is not connected.")) + uint32 ConstIndex; + + UPROPERTY(EditAnywhere, Category = MaterialExpressionSobol, meta = ( + OverridingInputProperty = "Seed", + Tooltip="2D Seed for sequence randomization. Only used if Seed is not connected.")) + FVector2D ConstSeed; + + //~ Begin UMaterialExpression Interface +#if WITH_EDITOR + virtual int32 Compile(class FMaterialCompiler* Compiler, int32 OutputIndex) override; + virtual void GetCaption(TArray& OutCaptions) const override; +#endif + //~ End UMaterialExpression Interface +}; + + + diff --git a/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionTextureBase.h b/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionTextureBase.h index 174117eac5fd..5bfba6cc5ead 100644 --- a/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionTextureBase.h +++ b/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionTextureBase.h @@ -20,10 +20,10 @@ class ENGINE_API UMaterialExpressionTextureBase : public UMaterialExpression { GENERATED_UCLASS_BODY() - UPROPERTY(EditAnywhere, Category=MaterialExpressionTextureBase) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=MaterialExpressionTextureBase) class UTexture* Texture; - UPROPERTY(EditAnywhere, Category=MaterialExpressionTextureBase) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=MaterialExpressionTextureBase) TEnumAsByte SamplerType; /** Is default selected texture when using mesh paint mode texture painting */ diff --git a/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionTextureCoordinate.h b/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionTextureCoordinate.h index 0c3167af06d8..6abb39129cb4 100644 --- a/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionTextureCoordinate.h +++ b/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionTextureCoordinate.h @@ -14,15 +14,15 @@ class UMaterialExpressionTextureCoordinate : public UMaterialExpression GENERATED_UCLASS_BODY() /** Texture coordinate index */ - UPROPERTY(EditAnywhere, Category=MaterialExpressionTextureCoordinate) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = MaterialExpressionTextureCoordinate) int32 CoordinateIndex; /** Controls how much the texture tiles horizontally, by scaling the U component of the vertex UVs by the specified amount. */ - UPROPERTY(EditAnywhere, Category=MaterialExpressionTextureCoordinate) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=MaterialExpressionTextureCoordinate) float UTiling; /** Controls how much the texture tiles vertically, by scaling the V component of the vertex UVs by the specified amount. */ - UPROPERTY(EditAnywhere, Category=MaterialExpressionTextureCoordinate) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=MaterialExpressionTextureCoordinate) float VTiling; /** Would like to unmirror U or V diff --git a/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionTextureSampleParameter.h b/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionTextureSampleParameter.h index 237686562183..b8e97e0dae0a 100644 --- a/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionTextureSampleParameter.h +++ b/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionTextureSampleParameter.h @@ -27,6 +27,12 @@ class ENGINE_API UMaterialExpressionTextureSampleParameter : public UMaterialExp UPROPERTY(EditAnywhere, Category=MaterialExpressionTextureSampleParameter) FName Group; +#if WITH_EDITORONLY_DATA + /** Controls where the this parameter is displayed in a material instance parameter list. The lower the number the higher up in the parameter list. */ + UPROPERTY(EditAnywhere, Category = MaterialExpressionTextureSampleParameter) + int32 SortPriority; +#endif + //~ Begin UMaterialExpression Interface #if WITH_EDITOR virtual int32 Compile(class FMaterialCompiler* Compiler, int32 OutputIndex) override; diff --git a/Engine/Source/Runtime/Engine/Classes/Materials/MaterialInstance.h b/Engine/Source/Runtime/Engine/Classes/Materials/MaterialInstance.h index b7f645d5cf58..f5b7ad3ce8ae 100644 --- a/Engine/Source/Runtime/Engine/Classes/Materials/MaterialInstance.h +++ b/Engine/Source/Runtime/Engine/Classes/Materials/MaterialInstance.h @@ -28,7 +28,7 @@ class FMaterialShaderMapId; class FSHAHash; /** Editable font parameter. */ -USTRUCT() +USTRUCT(BlueprintType) struct FFontParameterValue { GENERATED_USTRUCT_BODY() @@ -58,7 +58,7 @@ struct FFontParameterValue }; /** Editable scalar parameter. */ -USTRUCT() +USTRUCT(BlueprintType) struct FScalarParameterValue { GENERATED_USTRUCT_BODY() @@ -84,7 +84,7 @@ struct FScalarParameterValue }; /** Editable texture parameter. */ -USTRUCT() +USTRUCT(BlueprintType) struct FTextureParameterValue { GENERATED_USTRUCT_BODY() @@ -110,7 +110,7 @@ struct FTextureParameterValue }; /** Editable vector parameter. */ -USTRUCT() +USTRUCT(BlueprintType) struct FVectorParameterValue { GENERATED_USTRUCT_BODY() @@ -213,7 +213,7 @@ class UMaterialInstance : public UMaterialInterface UPROPERTY() bool bOverrideBaseProperties_DEPRECATED; - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=MaterialInstance) + UPROPERTY(EditAnywhere, Category=MaterialInstance) struct FMaterialInstanceBasePropertyOverrides BasePropertyOverrides; //Cached copies of the base property overrides or the value from the parent to avoid traversing the parent chain for each access. @@ -280,8 +280,8 @@ public: virtual ENGINE_API void OverrideVectorParameterDefault(FName ParameterName, const FLinearColor& Value, bool bOverride, ERHIFeatureLevel::Type FeatureLevel) override; virtual ENGINE_API void OverrideScalarParameterDefault(FName ParameterName, float Value, bool bOverride, ERHIFeatureLevel::Type FeatureLevel) override; virtual ENGINE_API float GetScalarParameterDefault(FName ParameterName, ERHIFeatureLevel::Type FeatureLevel) override; - virtual ENGINE_API bool CheckMaterialUsage(const EMaterialUsage Usage, const bool bSkipPrim = false) override; - virtual ENGINE_API bool CheckMaterialUsage_Concurrent(const EMaterialUsage Usage, const bool bSkipPrim = false) const override; + virtual ENGINE_API bool CheckMaterialUsage(const EMaterialUsage Usage) override; + virtual ENGINE_API bool CheckMaterialUsage_Concurrent(const EMaterialUsage Usage) const override; virtual ENGINE_API bool GetStaticSwitchParameterValue(FName ParameterName, bool &OutValue, FGuid &OutExpressionGuid) const override; virtual ENGINE_API bool GetStaticComponentMaskParameterValue(FName ParameterName, bool &R, bool &G, bool &B, bool &A, FGuid &OutExpressionGuid) const override; virtual ENGINE_API bool GetTerrainLayerWeightParameterValue(FName ParameterName, int32& OutWeightmapIndex, FGuid &OutExpressionGuid) const override; diff --git a/Engine/Source/Runtime/Engine/Classes/Materials/MaterialInstanceActor.h b/Engine/Source/Runtime/Engine/Classes/Materials/MaterialInstanceActor.h index c775c06cdcb6..2f2bf8d73188 100644 --- a/Engine/Source/Runtime/Engine/Classes/Materials/MaterialInstanceActor.h +++ b/Engine/Source/Runtime/Engine/Classes/Materials/MaterialInstanceActor.h @@ -24,8 +24,7 @@ class AMaterialInstanceActor : public AActor TArray TargetActors; #if WITH_EDITORONLY_DATA -private_subobject: - DEPRECATED_FORGAME(4.6, "SpriteComponent should not be accessed directly, please use GetSpriteComponent() function instead. SpriteComponent will soon be private and your code will not compile.") +private: // Reference to actor sprite UBillboardComponent* SpriteComponent; #endif diff --git a/Engine/Source/Runtime/Engine/Classes/Materials/MaterialInterface.h b/Engine/Source/Runtime/Engine/Classes/Materials/MaterialInterface.h index 40d4c552b63e..3dd2bff8a9c8 100644 --- a/Engine/Source/Runtime/Engine/Classes/Materials/MaterialInterface.h +++ b/Engine/Source/Runtime/Engine/Classes/Materials/MaterialInterface.h @@ -25,6 +25,7 @@ class USubsurfaceProfile; class UTexture; struct FPrimitiveViewRelevance; +UENUM(BlueprintType) enum EMaterialUsage { MATUSAGE_SkeletalMesh, @@ -52,9 +53,11 @@ struct ENGINE_API FMaterialRelevance uint32 bOpaque : 1; uint32 bMasked : 1; uint32 bDistortion : 1; - uint32 bSeparateTranslucency : 1; + uint32 bSeparateTranslucency : 1; // Translucency After DOF uint32 bMobileSeparateTranslucency : 1; uint32 bNormalTranslucency : 1; + uint32 bUsesSceneColorCopy : 1; + uint32 bDisableOffscreenRendering : 1; // Blend Modulate uint32 bDisableDepthTest : 1; uint32 bOutputsVelocityInBasePass : 1; uint32 bUsesGlobalDistanceField : 1; @@ -102,7 +105,7 @@ struct FLightmassMaterialInterfaceSettings GENERATED_USTRUCT_BODY() /** If true, forces translucency to cast static shadows as if the material were masked. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Material) + UPROPERTY(EditAnywhere, Category=Material) uint32 bCastShadowAsMasked:1; /** Scales the emissive contribution of this material to static lighting. */ @@ -110,14 +113,14 @@ struct FLightmassMaterialInterfaceSettings float EmissiveBoost; /** Scales the diffuse contribution of this material to static lighting. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Material) + UPROPERTY(EditAnywhere, Category=Material) float DiffuseBoost; /** * Scales the resolution that this material's attributes were exported at. * This is useful for increasing material resolution when details are needed. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Material) + UPROPERTY(EditAnywhere, Category=Material) float ExportResolutionScale; /** Boolean override flags - only used in MaterialInstance* cases. */ @@ -211,7 +214,7 @@ class UMaterialInterface : public UObject, public IBlendableInterface protected: /** The Lightmass settings for this object. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Lightmass) + UPROPERTY(EditAnywhere, Category=Lightmass) struct FLightmassMaterialInterfaceSettings LightmassSettings; #if WITH_EDITORONLY_DATA @@ -349,14 +352,13 @@ public: * Checks if the material can be used with the given usage flag. * If the flag isn't set in the editor, it will be set and the material will be recompiled with it. * @param Usage - The usage flag to check - * @param bSkipPrim - Bypass the primitive type checks * @return bool - true if the material can be used for rendering with the given type. */ - virtual bool CheckMaterialUsage(const EMaterialUsage Usage, const bool bSkipPrim = false) PURE_VIRTUAL(UMaterialInterface::CheckMaterialUsage,return false;); + virtual bool CheckMaterialUsage(const EMaterialUsage Usage) PURE_VIRTUAL(UMaterialInterface::CheckMaterialUsage,return false;); /** * Same as above but is valid to call from any thread. In the editor, this might spin and stall for a shader compile */ - virtual bool CheckMaterialUsage_Concurrent(const EMaterialUsage Usage, const bool bSkipPrim = false) const PURE_VIRTUAL(UMaterialInterface::CheckMaterialUsage,return false;); + virtual bool CheckMaterialUsage_Concurrent(const EMaterialUsage Usage) const PURE_VIRTUAL(UMaterialInterface::CheckMaterialUsage,return false;); /** * Get the static permutation resource if the instance has one @@ -400,6 +402,26 @@ public: virtual bool GetTerrainLayerWeightParameterValue(FName ParameterName, int32& OutWeightmapIndex, FGuid &OutExpressionGuid) const PURE_VIRTUAL(UMaterialInterface::GetTerrainLayerWeightParameterValue,return false;); + /** + * Get the sort priority index of the given parameter + * + * @param ParameterName The name of the parameter + * @param OutSortPriority Will contain the sort priority of the parameter if successful + * @return True if successful + */ + virtual bool GetParameterSortPriority(FName ParameterName, int32& OutSortPriority) const + PURE_VIRTUAL(UMaterialInterface::GetParameterSortPriority, return false;); + + /** + * Get the sort priority index of the given parameter group + * + * @param InGroupName The name of the parameter group + * @param OutSortPriority Will contain the sort priority of the parameter group if successful + * @return True if successful + */ + virtual bool GetGroupSortPriority(const FString& InGroupName, int32& OutSortPriority) const + PURE_VIRTUAL(UMaterialInterface::GetGroupSortPriority, return false;); + /** @return The material's relevance. */ ENGINE_API FMaterialRelevance GetRelevance(ERHIFeatureLevel::Type InFeatureLevel) const; /** @return The material's relevance, from concurrent render thread updates. */ diff --git a/Engine/Source/Runtime/Engine/Classes/Matinee/InterpTrackParticleReplay.h b/Engine/Source/Runtime/Engine/Classes/Matinee/InterpTrackParticleReplay.h index 5a6e7db0227a..8f76dc16f878 100644 --- a/Engine/Source/Runtime/Engine/Classes/Matinee/InterpTrackParticleReplay.h +++ b/Engine/Source/Runtime/Engine/Classes/Matinee/InterpTrackParticleReplay.h @@ -26,11 +26,11 @@ struct FParticleReplayTrackKey float Time; /** Time length this clip should be captured/played for */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=ParticleReplayTrackKey) + UPROPERTY(EditAnywhere, Category=ParticleReplayTrackKey) float Duration; /** Replay clip ID number that identifies the clip we should capture to or playback from */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=ParticleReplayTrackKey) + UPROPERTY(EditAnywhere, Category=ParticleReplayTrackKey) int32 ClipIDNumber; diff --git a/Engine/Source/Runtime/Engine/Classes/Matinee/InterpTrackVisibility.h b/Engine/Source/Runtime/Engine/Classes/Matinee/InterpTrackVisibility.h index 4689395c1466..c6f459144490 100644 --- a/Engine/Source/Runtime/Engine/Classes/Matinee/InterpTrackVisibility.h +++ b/Engine/Source/Runtime/Engine/Classes/Matinee/InterpTrackVisibility.h @@ -53,7 +53,7 @@ struct FVisibilityTrackKey UPROPERTY() float Time; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=VisibilityTrackKey) + UPROPERTY(EditAnywhere, Category=VisibilityTrackKey) TEnumAsByte Action; /** Condition that must be satisfied for this key event to fire */ diff --git a/Engine/Source/Runtime/Engine/Classes/Matinee/MatineeActor.h b/Engine/Source/Runtime/Engine/Classes/Matinee/MatineeActor.h index 35a345167cc6..0a3a4e29552e 100644 --- a/Engine/Source/Runtime/Engine/Classes/Matinee/MatineeActor.h +++ b/Engine/Source/Runtime/Engine/Classes/Matinee/MatineeActor.h @@ -47,10 +47,10 @@ struct FInterpGroupActorInfo { GENERATED_USTRUCT_BODY() - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpGroupActorInfo) + UPROPERTY(EditAnywhere, Category=InterpGroupActorInfo) FName ObjectName; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=InterpGroupActorInfo) + UPROPERTY(EditAnywhere, Category=InterpGroupActorInfo) TArray Actors; }; @@ -60,6 +60,8 @@ class ENGINE_API AMatineeActor : public AActor { GENERATED_UCLASS_BODY() + virtual void GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const override; + /** The matinee data used by this actor*/ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=MatineeActor, replicated, meta=(ForceRebuildProperty = "GroupActorInfos")) class UInterpData* MatineeData; @@ -169,8 +171,7 @@ class ENGINE_API AMatineeActor : public AActor #if WITH_EDITORONLY_DATA // Reference to the actor sprite -private_subobject: - DEPRECATED_FORGAME(4.6, "SpriteComponent should not be accessed directly, please use GetSpriteComponent() function instead. SpriteComponent will soon be private and your code will not compile.") +private: UPROPERTY() class UBillboardComponent* SpriteComponent; public: diff --git a/Engine/Source/Runtime/Engine/Classes/Particles/Emitter.h b/Engine/Source/Runtime/Engine/Classes/Particles/Emitter.h index 0fedef228794..c34c3d507999 100644 --- a/Engine/Source/Runtime/Engine/Classes/Particles/Emitter.h +++ b/Engine/Source/Runtime/Engine/Classes/Particles/Emitter.h @@ -56,8 +56,9 @@ class ENGINE_API AEmitter : public AActor { GENERATED_UCLASS_BODY() -private_subobject: - DEPRECATED_FORGAME(4.6, "ParticleSystemComponent should not be accessed directly, please use GetParticleSystemComponent() function instead. ParticleSystemComponent will soon be private and your code will not compile.") + virtual void GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const override; + +private: UPROPERTY(Category = Emitter, VisibleAnywhere, BlueprintReadOnly, meta = (ExposeFunctionCategories = "Particles|Beam,Particles|Parameters,Particles,Effects|Components|ParticleSystem,Rendering,Activation,Components|Activation", AllowPrivateAccess = "true")) class UParticleSystemComponent* ParticleSystemComponent; public: @@ -86,12 +87,10 @@ public: #if WITH_EDITORONLY_DATA -private_subobject: - DEPRECATED_FORGAME(4.6, "SpriteComponent should not be accessed directly, please use GetSpriteComponent() function instead. SpriteComponent will soon be private and your code will not compile.") +private: UPROPERTY() class UBillboardComponent* SpriteComponent; - DEPRECATED_FORGAME(4.6, "ArrowComponent should not be accessed directly, please use GetArrowComponent() function instead. ArrowComponent will soon be private and your code will not compile.") UPROPERTY() class UArrowComponent* ArrowComponent; public: @@ -153,12 +152,12 @@ public: public: /** Returns ParticleSystemComponent subobject **/ - class UParticleSystemComponent* GetParticleSystemComponent(); + class UParticleSystemComponent* GetParticleSystemComponent() { return ParticleSystemComponent; } #if WITH_EDITORONLY_DATA /** Returns SpriteComponent subobject **/ - class UBillboardComponent* GetSpriteComponent() const; + class UBillboardComponent* GetSpriteComponent() const { return SpriteComponent; } /** Returns ArrowComponent subobject **/ - class UArrowComponent* GetArrowComponent() const; + class UArrowComponent* GetArrowComponent() const { return ArrowComponent; } #endif }; diff --git a/Engine/Source/Runtime/Engine/Classes/Particles/Parameter/ParticleModuleParameterDynamic.h b/Engine/Source/Runtime/Engine/Classes/Particles/Parameter/ParticleModuleParameterDynamic.h index bae766d5bbb5..53509717c23a 100644 --- a/Engine/Source/Runtime/Engine/Classes/Particles/Parameter/ParticleModuleParameterDynamic.h +++ b/Engine/Source/Runtime/Engine/Classes/Particles/Parameter/ParticleModuleParameterDynamic.h @@ -50,7 +50,7 @@ struct FEmitterDynamicParameter GENERATED_USTRUCT_BODY() /** The parameter name - from the material DynamicParameter expression. READ-ONLY */ - UPROPERTY(Category=EmitterDynamicParameter, VisibleAnywhere, BlueprintReadWrite) + UPROPERTY(Category=EmitterDynamicParameter, VisibleAnywhere) FName ParamName; /** If true, use the EmitterTime to retrieve the value, otherwise use Particle RelativeTime. */ diff --git a/Engine/Source/Runtime/Engine/Classes/Particles/ParticleSystemComponent.h b/Engine/Source/Runtime/Engine/Classes/Particles/ParticleSystemComponent.h index 641904aa3447..b6c2122265b1 100644 --- a/Engine/Source/Runtime/Engine/Classes/Particles/ParticleSystemComponent.h +++ b/Engine/Source/Runtime/Engine/Classes/Particles/ParticleSystemComponent.h @@ -694,7 +694,7 @@ public: check(bAsyncDataCopyIsValid); return AsyncComponentToWorld; } - return ComponentToWorld; + return GetComponentTransform(); } FORCEINLINE const TArray& GetAsyncInstanceParameters() diff --git a/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/BodyInstance.h b/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/BodyInstance.h index 7909e80adbbd..c4d03197de7c 100644 --- a/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/BodyInstance.h +++ b/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/BodyInstance.h @@ -188,7 +188,7 @@ enum class EDynamicActorScene : uint8 }; /** Container for a physics representation of an object */ -USTRUCT() +USTRUCT(BlueprintType) struct ENGINE_API FBodyInstance { GENERATED_USTRUCT_BODY() @@ -316,14 +316,14 @@ public: /** When initializing dynamic instances their component or velocity can override the bStartAwake flag */ uint32 bWokenExternally : 1; -protected: /** - * If true, this body will be put into the asynchronous physics scene. If false, it will be put into the synchronous physics scene. - * If the body is static, it will be placed into both scenes regardless of the value of bUseAsyncScene. - */ - UPROPERTY(EditAnywhere, AdvancedDisplay, BlueprintReadWrite, Category=Physics) - uint32 bUseAsyncScene:1; + * If true, this body will be put into the asynchronous physics scene. If false, it will be put into the synchronous physics scene. + * If the body is static, it will be placed into both scenes regardless of the value of bUseAsyncScene. + */ + UPROPERTY(EditAnywhere, AdvancedDisplay, BlueprintReadWrite, Category = Physics) + uint32 bUseAsyncScene : 1; +protected: /** Whether this body instance has its own custom MaxDepenetrationVelocity*/ UPROPERTY(EditAnywhere, Category = Physics, meta=(InlineEditConditionToggle)) @@ -497,7 +497,7 @@ public: /** Helper struct to specify spawn behavior */ struct FInitBodySpawnParams { - FInitBodySpawnParams(const UPrimitiveComponent* PrimComp); + ENGINE_API FInitBodySpawnParams(const UPrimitiveComponent* PrimComp); /** Whether the created physx actor will be static */ bool bStaticPhysics; @@ -505,6 +505,9 @@ public: /** Whether to use the BodySetup's PhysicsType to override if the instance simulates*/ bool bPhysicsTypeDeterminesSimulation; + /** Whether kinematic targets are used by scene queries */ + bool bKinematicTargetsUpdateSQ; + /** Whether to override the physics scene used for simulation */ EDynamicActorScene DynamicActorScene; }; @@ -632,7 +635,7 @@ public: DEPRECATED(4.8, "Please call GetPxRigidActor_AssumesLocked and make sure you obtain the appropriate PhysX scene locks") physx::PxRigidActor* GetPxRigidActor(int32 SceneType = -1) const { - return GetPxRigidActor_AssumesLocked(SceneType); + return GetPxRigidActorFromScene_AssumesLocked(SceneType); } /** @@ -641,7 +644,12 @@ public: * Invalid scene types will cause NULL to be returned. * Note: Reading/writing from/to PxRigidActor is not thread safe. If you use the actor make sure to obtain the appropriate PhysX scene lock */ - physx::PxRigidActor* GetPxRigidActor_AssumesLocked(int32 SceneType = -1) const; + physx::PxRigidActor* GetPxRigidActor_AssumesLocked() const + { + return RigidActorSync ? RigidActorSync : RigidActorAsync; + } + + physx::PxRigidActor* GetPxRigidActorFromScene_AssumesLocked(int32 SceneType) const; /** Return the PxRigidDynamic if it exists in one of the scenes (NULL otherwise). Currently a PxRigidDynamic can exist in only one of the two scenes. */ @@ -1134,6 +1142,8 @@ public: /** Returns the relative transform between root body and welded instance owned by the shape.*/ const FTransform& GetRelativeBodyTransform(const physx::PxShape* PShape) const; + /** Check if the shape is owned by this body instance */ + bool IsShapeBoundToBody(const physx::PxShape* PShape) const; private: /** * Trace a shape against just this bodyinstance @@ -1151,8 +1161,6 @@ private: */ void UpdatePhysicsShapeFilterData(uint32 ComponentID, bool bUseComplexAsSimple, bool bUseSimpleAsComplex, bool bPhysicsStatic, const TEnumAsByte * CollisionEnabledOverride, FCollisionResponseContainer * ResponseOverride, bool * bNotifyOverride); - /** Check if the shape is owned by this body instance */ - bool IsShapeBoundToBody(const physx::PxShape* PShape) const; #endif /** * Invalidate Collision Profile Name @@ -1268,13 +1276,15 @@ private: ////////////////////////////////////////////////////////////////////////// // BodyInstance inlines -//~ APIDOCTOOL: Document=Off +/// @cond DOXYGEN_WARNINGS + FORCEINLINE_DEBUGGABLE bool FBodyInstance::OverlapMulti(TArray& InOutOverlaps, const class UWorld* World, const FTransform* pWorldToComponent, const FVector& Pos, const FRotator& Rot, ECollisionChannel TestChannel, const FComponentQueryParams& Params, const FCollisionResponseParams& ResponseParams, const FCollisionObjectQueryParams& ObjectQueryParams) const { // Pass on to FQuat version return OverlapMulti(InOutOverlaps, World, pWorldToComponent, Pos, Rot.Quaternion(), TestChannel, Params, ResponseParams, ObjectQueryParams); } -//~ APIDOCTOOL: Document=On + +/// @endcond FORCEINLINE_DEBUGGABLE bool FBodyInstance::OverlapTestForBodies(const FVector& Position, const FQuat& Rotation, const TArray& Bodies) const { diff --git a/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/BodySetup.h b/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/BodySetup.h index fc23afb5860b..585c3bfa050a 100644 --- a/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/BodySetup.h +++ b/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/BodySetup.h @@ -11,6 +11,7 @@ #include "Serialization/BulkData.h" #include "PhysicsEngine/BodySetupEnums.h" #include "PhysicsEngine/AggregateGeom.h" +#include "Interfaces/Interface_CollisionDataProvider.h" #include "BodySetup.generated.h" class ITargetPlatform; @@ -19,6 +20,8 @@ class UPrimitiveComponent; struct FShapeData; enum class EPhysXMeshCookFlags : uint8; +DECLARE_DELEGATE(FOnAsyncPhysicsCookFinished); + namespace physx { class PxTriangleMesh; @@ -28,6 +31,7 @@ namespace physx class PxBoxGeometry; class PxCapsuleGeometry; class PxConvexMeshGeometry; + class PxConvexMesh; class PxTriangleMesh; class PxTriangleMeshGeometry; } @@ -58,8 +62,52 @@ struct FBodySetupUVInfo SIZE_T GetResourceSize() const; void GetResourceSizeEx(FResourceSizeEx& CumulativeResourceSize) const; SIZE_T GetResourceSizeBytes() const; + + void FillFromTriMesh(const FTriMeshCollisionData& TriMeshCollisionData); }; +/** Helper struct to indicate which geometry needs to be cooked */ +struct ENGINE_API FCookBodySetupInfo +{ + /** Trimesh data for cooking */ + FTriMeshCollisionData TriangleMeshDesc; + + /** Trimesh cook flags */ + EPhysXMeshCookFlags TriMeshCookFlags; + + /** Convex cook flags */ + EPhysXMeshCookFlags ConvexCookFlags; + + /** Vertices of NonMirroredConvex hulls */ + TArray> NonMirroredConvexVertices; + + /** Vertices of NonMirroredConvex hulls */ + TArray> MirroredConvexVertices; + + /** Debug name helpful for runtime cooking warnings */ + FString OuterDebugName; + + /** Whether to cook the regular convex hulls */ + bool bCookNonMirroredConvex; + + /** Whether to cook the mirror convex hulls */ + bool bCookMirroredConvex; + + /** Whether the convex being cooked comes from a deformable mesh */ + bool bConvexDeformableMesh; + + /** Whether to cook trimesh collision*/ + bool bCookTriMesh; + + /** Whether to support UV from hit results */ + bool bSupportUVFromHitResults; + + /** Error generating cook info for trimesh*/ + bool bTriMeshError; +}; + +struct FAsyncPhysicsCookHelper; + /** * BodySetup contains all collision information that is associated with a single asset. * A single BodySetup instance is shared among many BodyInstances so that geometry data is not duplicated. @@ -172,7 +220,7 @@ private: FFormatContainer CookedFormatDataRuntimeOnlyOptimization; #endif -#if WITH_PHYSX && (WITH_RUNTIME_PHYSICS_COOKING || WITH_EDITOR) +#if WITH_PHYSX /** Get cook flags for 'runtime only' cooked physics data */ EPhysXMeshCookFlags GetRuntimeOnlyCookOptimizationFlags() const; #endif @@ -226,6 +274,20 @@ public: /** Release Physics meshes (ConvexMeshes, TriMesh & TriMeshNegX). Must be called before the BodySetup is destroyed */ ENGINE_API virtual void CreatePhysicsMeshes(); + /** Create Physics meshes (ConvexMeshes, TriMesh & TriMeshNegX) from cooked data async (useful for runtime cooking as it can go wide off the game thread) */ + /** Release Physics meshes (ConvexMeshes, TriMesh & TriMeshNegX). Must be called before the BodySetup is destroyed */ + /** NOTE: You cannot use the body setup until this operation is done. You must create the physics state (call CreatePhysicsState, or InitBody, etc..) , this does not automatically update the BodyInstance state for you */ + ENGINE_API void CreatePhysicsMeshesAsync(FOnAsyncPhysicsCookFinished OnAsyncPhysicsCookFinished); + +private: + /** Finalize game thread data before calling back user's delegate */ + void FinishCreatePhysicsMeshesAsync(FAsyncPhysicsCookHelper* AsyncPhysicsCookHelper, FOnAsyncPhysicsCookFinished OnAsyncPhysicsCookFinished); + + /** Finish creating the physics meshes and update the body setup data with cooked data */ + void FinishCreatingPhysicsMeshes(const TArray& ConvexMeshes, const TArray& ConvexMeshesNegX, const TArray& TriMeshes); + +public: + /** Returns the volume of this element */ ENGINE_API virtual float GetVolume(const FVector& Scale) const; @@ -238,7 +300,6 @@ public: /** Returns the physics material used for this body. If none, specified, returns the default engine material. */ ENGINE_API class UPhysicalMaterial* GetPhysMaterial() const; -#if WITH_PHYSX && (WITH_RUNTIME_PHYSICS_COOKING || WITH_EDITOR) /** Clear all simple collision */ ENGINE_API void RemoveSimpleCollision(); @@ -263,8 +324,6 @@ public: */ ENGINE_API void CreateFromModel(class UModel* InModel, bool bRemoveExisting); -#endif // WITH_RUNTIME_PHYSICS_COOKING || WITH_EDITOR - /** * Converts the skinned data of a skeletal mesh into a tri mesh collision. This is used for per poly scene queries and is quite expensive. * In 99% of cases you should be fine using a physics asset created for the skeletal mesh @@ -303,6 +362,13 @@ public: */ FByteBulkData* GetCookedData(FName Format, bool bRuntimeOnlyOptimizedVersion = false); + /** + * Generates the information needed for cooking geometry. + * @param OutCookInfo Info needed during cooking + * @param InCookFlags Any flags desired for TriMesh cooking + */ + ENGINE_API void GetCookInfo(FCookBodySetupInfo& OutCookInfo, EPhysXMeshCookFlags InCookFlags) const; + /** * Given a location in body space, and face index, find the UV of the desired UV channel. * Note this ONLY works if 'Support UV From Hit Results' is enabled in Physics Settings. @@ -372,9 +438,13 @@ private: float MaxContactOffset; }; +/// @cond DOXYGEN_WARNINGS + //Explicit export of template instantiation extern template ENGINE_API void FBodySetupShapeIterator::ForEachShape(const TArray&, TFunctionRef) const; extern template ENGINE_API void FBodySetupShapeIterator::ForEachShape(const TArray&, TFunctionRef) const; extern template ENGINE_API void FBodySetupShapeIterator::ForEachShape(const TArray&, TFunctionRef) const; extern template ENGINE_API void FBodySetupShapeIterator::ForEachShape(const TArray&, TFunctionRef) const; -extern template ENGINE_API void FBodySetupShapeIterator::ForEachShape(const TArray&,TFunctionRef) const; \ No newline at end of file +extern template ENGINE_API void FBodySetupShapeIterator::ForEachShape(const TArray&,TFunctionRef) const; + +/// @endcond diff --git a/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/ConstraintDrives.h b/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/ConstraintDrives.h index ed2a8e3be095..2dfe3f5c25ad 100644 --- a/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/ConstraintDrives.h +++ b/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/ConstraintDrives.h @@ -77,11 +77,11 @@ struct ENGINE_API FLinearDriveConstraint /** Target position the linear drive.*/ - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = LinearMotor) + UPROPERTY(EditAnywhere, Category = LinearMotor) FVector PositionTarget; /** Target velocity the linear drive. */ - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = LinearMotor) + UPROPERTY(EditAnywhere, Category = LinearMotor) FVector VelocityTarget; UPROPERTY(EditAnywhere, Category = LinearMotor) @@ -142,15 +142,15 @@ struct ENGINE_API FAngularDriveConstraint FConstraintDrive SlerpDrive; /** Target orientation relative to the the body reference frame.*/ - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = AngularMotor) + UPROPERTY(EditAnywhere, Category = AngularMotor) FRotator OrientationTarget; /** Target angular velocity relative to the body reference frame. */ - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = AngularMotor) + UPROPERTY(EditAnywhere, Category = AngularMotor) FVector AngularVelocityTarget; /** Whether motors use SLERP (spherical lerp) or decompose into a Swing motor (cone constraints) and Twist motor (roll constraints). NOTE: SLERP will NOT work if any of the angular constraints are locked. */ - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = AngularMotor) + UPROPERTY(EditAnywhere, Category = AngularMotor) TEnumAsByte AngularDriveMode; FAngularDriveConstraint(); diff --git a/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/ConstraintInstance.h b/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/ConstraintInstance.h index 19b94e711522..a27e41f4d705 100644 --- a/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/ConstraintInstance.h +++ b/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/ConstraintInstance.h @@ -101,6 +101,10 @@ struct ENGINE_API FConstraintProfileProperties /** Updates physx joint flag based on profile properties */ void UpdatePhysXConstraintFlags_AssumesLocked(physx::PxD6Joint* Joint) const; #endif + +#if WITH_EDITOR + void SyncChangedConstraintProperties(struct FPropertyChangedChainEvent& PropertyChangedEvent); +#endif }; @@ -719,4 +723,4 @@ struct TStructOpsTypeTraits : public TStructOpsTypeTraitsBa WithSerializer = true, WithPostSerialize = true }; -}; +}; \ No newline at end of file diff --git a/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/DestructibleActor.h b/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/DestructibleActor.h index 74fd04306ad0..bcd1e151e977 100644 --- a/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/DestructibleActor.h +++ b/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/DestructibleActor.h @@ -22,8 +22,7 @@ class ENGINE_API ADestructibleActor : public AActor /** * The component which holds the skinned mesh and physics data for this actor. */ -private_subobject: - DEPRECATED_FORGAME(4.6, "DestructibleComponent should not be accessed directly, please use GetDestructibleComponent() function instead. DestructibleComponent will soon be private and your code will not compile.") +private: UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Destruction, meta = (ExposeFunctionCategories = "Destruction,Components|Destructible", AllowPrivateAccess = "true")) UDestructibleComponent* DestructibleComponent; public: @@ -46,7 +45,7 @@ public: public: /** Returns DestructibleComponent subobject **/ - UDestructibleComponent* GetDestructibleComponent() const; + UDestructibleComponent* GetDestructibleComponent() const { return DestructibleComponent; } }; diff --git a/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/PhysicsConstraintActor.h b/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/PhysicsConstraintActor.h index a41e95bdfaa1..811eefc6b251 100644 --- a/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/PhysicsConstraintActor.h +++ b/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/PhysicsConstraintActor.h @@ -16,8 +16,7 @@ class APhysicsConstraintActor : public ARigidBodyBase GENERATED_UCLASS_BODY() // Cached reference to constraint component -private_subobject: - DEPRECATED_FORGAME(4.6, "ConstraintComp should not be accessed directly, please use GetConstraintComp() function instead. ConstraintComp will soon be private and your code will not compile.") +private: UPROPERTY(Category = ConstraintActor, VisibleAnywhere, BlueprintReadOnly, meta = (ExposeFunctionCategories = "JointDrive,Physics|Components|PhysicsConstraint", AllowPrivateAccess = "true")) class UPhysicsConstraintComponent* ConstraintComp; public: @@ -38,7 +37,7 @@ public: public: /** Returns ConstraintComp subobject **/ - ENGINE_API class UPhysicsConstraintComponent* GetConstraintComp() const; + ENGINE_API class UPhysicsConstraintComponent* GetConstraintComp() const { return ConstraintComp; } }; diff --git a/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/PhysicsConstraintTemplate.h b/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/PhysicsConstraintTemplate.h index 54a768a8d91b..59aaa749538e 100644 --- a/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/PhysicsConstraintTemplate.h +++ b/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/PhysicsConstraintTemplate.h @@ -107,6 +107,7 @@ class UPhysicsConstraintTemplate : public UObject } + virtual void PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent) override; virtual void PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) override; ENGINE_API FName GetCurrentConstraintProfileName() const; diff --git a/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/PhysicsSettings.h b/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/PhysicsSettings.h index d1b6e4cbc9ef..a371cfe32c54 100644 --- a/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/PhysicsSettings.h +++ b/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/PhysicsSettings.h @@ -236,6 +236,10 @@ class ENGINE_API UPhysicsSettings : public UDeveloperSettings UPROPERTY(config, EditAnywhere, AdvancedDisplay, meta = (ClampMin = "0.0013", UIMin = "0.0013", ClampMax = "1.0", UIMax = "1.0"), Category = Framerate) float InitialAverageFrameRate; + /** The number of frames it takes to rebuild the PhysX scene query AABB tree. The bigger the number, the smaller fetchResults takes per frame, but the more the tree deteriorates until a new tree is built */ + UPROPERTY(config, EditAnywhere, AdvancedDisplay, meta = (ClampMin = "4", UIMin = "4"), Category = Framerate) + int PhysXTreeRebuildRate; + // PhysicalMaterial Surface Types UPROPERTY(config, EditAnywhere, Category=PhysicalSurfaces) TArray PhysicalSurfaces; diff --git a/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/PhysicsThruster.h b/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/PhysicsThruster.h index 877fc622afd3..6f096516d409 100644 --- a/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/PhysicsThruster.h +++ b/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/PhysicsThruster.h @@ -18,24 +18,22 @@ class APhysicsThruster : public ARigidBodyBase { GENERATED_UCLASS_BODY() -private_subobject: +private: /** Thruster component */ - DEPRECATED_FORGAME(4.6, "ThrusterComponent should not be accessed directly, please use GetThrusterComponent() function instead. ThrusterComponent will soon be private and your code will not compile.") UPROPERTY(Category = Physics, VisibleAnywhere, BlueprintReadOnly, meta = (ExposeFunctionCategories = "Activation,Components|Activation", AllowPrivateAccess = "true")) class UPhysicsThrusterComponent* ThrusterComponent; #if WITH_EDITORONLY_DATA - DEPRECATED_FORGAME(4.6, "ArrowComponent should not be accessed directly, please use GetArrowComponent() function instead. ArrowComponent will soon be private and your code will not compile.") UPROPERTY() class UArrowComponent* ArrowComponent; #endif public: /** Returns ThrusterComponent subobject **/ - ENGINE_API class UPhysicsThrusterComponent* GetThrusterComponent() const; + ENGINE_API class UPhysicsThrusterComponent* GetThrusterComponent() const { return ThrusterComponent; } #if WITH_EDITORONLY_DATA /** Returns ArrowComponent subobject **/ - ENGINE_API class UArrowComponent* GetArrowComponent() const; + ENGINE_API class UArrowComponent* GetArrowComponent() const { return ArrowComponent; } #endif }; diff --git a/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/RadialForceActor.h b/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/RadialForceActor.h index f19c456f2b74..aba0a3a1ab60 100644 --- a/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/RadialForceActor.h +++ b/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/RadialForceActor.h @@ -15,14 +15,12 @@ class ARadialForceActor : public ARigidBodyBase { GENERATED_UCLASS_BODY() -private_subobject: +private: /** Force component */ - DEPRECATED_FORGAME(4.6, "ForceComponent should not be accessed directly, please use GetForceComponent() function instead. ForceComponent will soon be private and your code will not compile.") UPROPERTY(Category = RadialForceActor, VisibleAnywhere, BlueprintReadOnly, meta = (ExposeFunctionCategories = "Activation,Components|Activation,Physics,Physics|Components|RadialForce", AllowPrivateAccess = "true")) class URadialForceComponent* ForceComponent; #if WITH_EDITORONLY_DATA - DEPRECATED_FORGAME(4.6, "SpriteComponent should not be accessed directly, please use GetSpriteComponent() function instead. SpriteComponent will soon be private and your code will not compile.") UPROPERTY() UBillboardComponent* SpriteComponent; #endif @@ -48,10 +46,10 @@ public: public: /** Returns ForceComponent subobject **/ - ENGINE_API class URadialForceComponent* GetForceComponent() const; + ENGINE_API class URadialForceComponent* GetForceComponent() const { return ForceComponent; } #if WITH_EDITORONLY_DATA /** Returns SpriteComponent subobject **/ - ENGINE_API UBillboardComponent* GetSpriteComponent() const; + ENGINE_API UBillboardComponent* GetSpriteComponent() const { return SpriteComponent; } #endif }; diff --git a/Engine/Source/Runtime/Engine/Classes/Sound/AmbientSound.h b/Engine/Source/Runtime/Engine/Classes/Sound/AmbientSound.h index 61a221939664..120662c974a7 100644 --- a/Engine/Source/Runtime/Engine/Classes/Sound/AmbientSound.h +++ b/Engine/Source/Runtime/Engine/Classes/Sound/AmbientSound.h @@ -13,9 +13,8 @@ class ENGINE_API AAmbientSound : public AActor { GENERATED_UCLASS_BODY() -private_subobject: +private: /** Audio component that handles sound playing */ - DEPRECATED_FORGAME(4.6, "AudioComponent should not be accessed directly, please use GetAudioComponent() function instead. AudioComponent will soon be private and your code will not compile.") UPROPERTY(Category = Sound, VisibleAnywhere, BlueprintReadOnly, meta = (ExposeFunctionCategories = "Sound,Audio,Audio|Components|Audio", AllowPrivateAccess = "true")) class UAudioComponent* AudioComponent; public: @@ -45,7 +44,7 @@ public: public: /** Returns AudioComponent subobject **/ - class UAudioComponent* GetAudioComponent() const; + class UAudioComponent* GetAudioComponent() const { return AudioComponent; } }; diff --git a/Engine/Source/Runtime/Engine/Classes/Sound/AudioSettings.h b/Engine/Source/Runtime/Engine/Classes/Sound/AudioSettings.h index 1c0f33912ede..6db897b8bf2b 100644 --- a/Engine/Source/Runtime/Engine/Classes/Sound/AudioSettings.h +++ b/Engine/Source/Runtime/Engine/Classes/Sound/AudioSettings.h @@ -8,6 +8,36 @@ #include "Engine/DeveloperSettings.h" #include "AudioSettings.generated.h" +struct ENGINE_API FAudioPlatformSettings +{ + /** Sample rate to use on the platform for the mixing engine. Higher sample rates will incur more CPU cost. */ + int32 SampleRate; + + /** The amount of audio to compute each callback block. Lower values decrease latency but may increase CPU cost. */ + int32 CallbackBufferFrameSize; + + /** The number of buffers to keep enqueued. More buffers increases latency, but can compensate for variable compute availability in audio callbacks on some platforms. */ + int32 NumBuffers; + + /** The max number of channels to limit for this platform. The max channels used will be the minimum of this value and the global audio quality settings. A value of 0 will not apply a platform channel count max. */ + int32 MaxChannels; + + /** The number of workers to use to compute source audio. Will only use up to the max number of sources. Will evenly divide sources to each source worker. */ + int32 NumSourceWorkers; + + static FAudioPlatformSettings GetPlatformSettings(const TCHAR* PlatformSettingsConfigFile); + + FAudioPlatformSettings() + : SampleRate(48000) + , CallbackBufferFrameSize(1024) + , NumBuffers(2) + , MaxChannels(0) + , NumSourceWorkers(0) + { + } +}; + + USTRUCT() struct ENGINE_API FAudioQualitySettings { @@ -96,6 +126,12 @@ class ENGINE_API UAudioSettings : public UDeveloperSettings const FAudioQualitySettings& GetQualityLevelSettings(int32 QualityLevel) const; + // Sets whether audio mixer is enabled. Set once an audio mixer platform modu le is loaded. + void SetAudioMixerEnabled(const bool bInAudioMixerEnabled); + + // Returns if the audio mixer is currently enabled + const bool IsAudioMixerEnabled() const; + private: #if WITH_EDITOR @@ -103,4 +139,7 @@ private: #endif void AddDefaultSettings(); + + // Whether or not the audio mixer is loaded/enabled. Used to toggle visibility of editor features. + bool bIsAudioMixerEnabled; }; diff --git a/Engine/Source/Runtime/Engine/Classes/Sound/AudioVolume.h b/Engine/Source/Runtime/Engine/Classes/Sound/AudioVolume.h index 25e62aa414d7..8c7f7c925ae0 100644 --- a/Engine/Source/Runtime/Engine/Classes/Sound/AudioVolume.h +++ b/Engine/Source/Runtime/Engine/Classes/Sound/AudioVolume.h @@ -244,6 +244,7 @@ public: #if WITH_EDITOR virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; #endif // WITH_EDITOR + virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; //~ End UObject Interface //~ Begin AActor Interface diff --git a/Engine/Source/Runtime/Engine/Classes/Sound/SoundBase.h b/Engine/Source/Runtime/Engine/Classes/Sound/SoundBase.h index 9d705adde4b5..c30e9fffd511 100644 --- a/Engine/Source/Runtime/Engine/Classes/Sound/SoundBase.h +++ b/Engine/Source/Runtime/Engine/Classes/Sound/SoundBase.h @@ -32,7 +32,7 @@ public: protected: /** Sound class this sound belongs to */ - UPROPERTY(EditAnywhere, Category=Sound, meta=(DisplayName = "Sound Class")) + UPROPERTY(EditAnywhere, Category=Sound, meta=(DisplayName = "Sound Class"), AssetRegistrySearchable) USoundClass* SoundClassObject; public: diff --git a/Engine/Source/Runtime/Engine/Classes/Sound/SoundNodeDistanceCrossFade.h b/Engine/Source/Runtime/Engine/Classes/Sound/SoundNodeDistanceCrossFade.h index 64a3caf002be..397f3c8b3786 100644 --- a/Engine/Source/Runtime/Engine/Classes/Sound/SoundNodeDistanceCrossFade.h +++ b/Engine/Source/Runtime/Engine/Classes/Sound/SoundNodeDistanceCrossFade.h @@ -21,23 +21,23 @@ struct FDistanceDatum /* The FadeInDistance at which to start hearing this sound. * If you want to hear the sound up close then setting this to 0 might be a good option. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=DistanceDatum ) + UPROPERTY(EditAnywhere, Category=DistanceDatum ) float FadeInDistanceStart; /* The distance at which this sound has faded in completely. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=DistanceDatum ) + UPROPERTY(EditAnywhere, Category=DistanceDatum ) float FadeInDistanceEnd; /* The distance at which this sound starts fading out. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=DistanceDatum ) + UPROPERTY(EditAnywhere, Category=DistanceDatum ) float FadeOutDistanceStart; /* The distance at which this sound is no longer audible. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=DistanceDatum ) + UPROPERTY(EditAnywhere, Category=DistanceDatum ) float FadeOutDistanceEnd; /* The volume for which this Input should be played. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=DistanceDatum) + UPROPERTY(EditAnywhere, Category=DistanceDatum) float Volume; diff --git a/Engine/Source/Runtime/Engine/Classes/VectorField/VectorFieldVolume.h b/Engine/Source/Runtime/Engine/Classes/VectorField/VectorFieldVolume.h index 5e696992a46d..9159e464ae3f 100644 --- a/Engine/Source/Runtime/Engine/Classes/VectorField/VectorFieldVolume.h +++ b/Engine/Source/Runtime/Engine/Classes/VectorField/VectorFieldVolume.h @@ -18,23 +18,21 @@ class AVectorFieldVolume : public AActor { GENERATED_UCLASS_BODY() -private_subobject: - DEPRECATED_FORGAME(4.6, "VectorFieldComponent should not be accessed directly, please use GetVectorFieldComponent() function instead. VectorFieldComponent will soon be private and your code will not compile.") +private: UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = VectorFieldVolume, meta = (AllowPrivateAccess = "true")) class UVectorFieldComponent* VectorFieldComponent; #if WITH_EDITORONLY_DATA - DEPRECATED_FORGAME(4.6, "SpriteComponent should not be accessed directly, please use GetSpriteComponent() function instead. SpriteComponent will soon be private and your code will not compile.") UPROPERTY() UBillboardComponent* SpriteComponent; #endif public: /** Returns VectorFieldComponent subobject **/ - ENGINE_API class UVectorFieldComponent* GetVectorFieldComponent() const; + ENGINE_API class UVectorFieldComponent* GetVectorFieldComponent() const { return VectorFieldComponent; } #if WITH_EDITORONLY_DATA /** Returns SpriteComponent subobject **/ - ENGINE_API UBillboardComponent* GetSpriteComponent() const; + ENGINE_API UBillboardComponent* GetSpriteComponent() const { return SpriteComponent; } #endif }; diff --git a/Engine/Source/Runtime/Engine/Engine.Build.cs b/Engine/Source/Runtime/Engine/Engine.Build.cs index 81dc79706769..444c9e8962bd 100644 --- a/Engine/Source/Runtime/Engine/Engine.Build.cs +++ b/Engine/Source/Runtime/Engine/Engine.Build.cs @@ -11,7 +11,7 @@ public class Engine : ModuleRules SharedPCHHeaderFile = "Public/EngineSharedPCH.h"; - PublicIncludePathModuleNames.AddRange(new string[] { "Renderer", "PacketHandler", "NetworkReplayStreaming" }); + PublicIncludePathModuleNames.AddRange(new string[] { "Renderer", "PacketHandler", "NetworkReplayStreaming", "AudioMixer" }); PrivateIncludePaths.AddRange( new string[] { @@ -26,6 +26,7 @@ public class Engine : ModuleRules "TargetPlatform", "ImageWrapper", "HeadMountedDisplay", + "MRMesh", "Advertising", "NetworkReplayStreaming", "MovieSceneCapture", @@ -80,17 +81,6 @@ public class Engine : ModuleRules } ); - if (Target.Type == TargetType.Editor) - { - PrivateIncludePathModuleNames.AddRange(new string[] { "CrashTracker" }); - DynamicallyLoadedModuleNames.AddRange(new string[] { "CrashTracker" }); - PublicDependencyModuleNames.AddRange( - new string[] { - } - ); - } - - PrivateDependencyModuleNames.AddRange( new string[] { "AppFramework", @@ -132,7 +122,11 @@ public class Engine : ModuleRules bVariadicTemplatesSupported = false; } } - } + + AddEngineThirdPartyPrivateStaticDependencies(Target, + "libOpus" + ); + } if (bVariadicTemplatesSupported) { @@ -178,14 +172,13 @@ public class Engine : ModuleRules "MovieSceneCapture", "MovieSceneTracks", "HeadMountedDisplay", + "MRMesh", "MeshEditingRuntime", - "StreamingPauseRendering", + "StreamingPauseRendering", "Niagara", } ); - PrivateIncludePathModuleNames.Add("LightPropagationVolumeRuntime"); - if (Target.Type != TargetType.Server) { PrivateIncludePathModuleNames.AddRange( @@ -244,6 +237,7 @@ public class Engine : ModuleRules "WindowsServerTargetPlatform", "WindowsClientTargetPlatform", "AllDesktopTargetPlatform", + "WindowsPlatformEditor", } ); } @@ -256,6 +250,7 @@ public class Engine : ModuleRules "MacServerTargetPlatform", "MacClientTargetPlatform", "AllDesktopTargetPlatform", + "MacPlatformEditor", } ); } @@ -268,6 +263,7 @@ public class Engine : ModuleRules "LinuxServerTargetPlatform", "LinuxClientTargetPlatform", "AllDesktopTargetPlatform", + "LinuxPlatformEditor", } ); } @@ -286,8 +282,7 @@ public class Engine : ModuleRules { DynamicallyLoadedModuleNames.AddRange( new string[] { - "ImageWrapper", - "GameLiveStreaming" + "ImageWrapper" } ); } @@ -329,13 +324,15 @@ public class Engine : ModuleRules DynamicallyLoadedModuleNames.Add("HierarchicalLODUtilities"); DynamicallyLoadedModuleNames.Add("AnimationModifiers"); + + PrivateIncludePathModuleNames.Add("AssetTools"); + DynamicallyLoadedModuleNames.Add("AssetTools"); } SetupModulePhysXAPEXSupport(Target); - if(UEBuildConfiguration.bCompilePhysX && (UEBuildConfiguration.bBuildEditor || UEBuildConfiguration.bRuntimePhysicsCooking)) + if(UEBuildConfiguration.bCompilePhysX && (UEBuildConfiguration.bBuildEditor || UEBuildConfiguration.bCompileAPEX)) { - DynamicallyLoadedModuleNames.Add("PhysXFormats"); - PrivateIncludePathModuleNames.Add("PhysXFormats"); + DynamicallyLoadedModuleNames.Add("PhysXCooking"); } if(UEBuildConfiguration.bCompilePhysX) diff --git a/Engine/Source/Runtime/Engine/Private/ADPCMAudioInfo.cpp b/Engine/Source/Runtime/Engine/Private/ADPCMAudioInfo.cpp index e187a39f3bc5..2c83079d248e 100644 --- a/Engine/Source/Runtime/Engine/Private/ADPCMAudioInfo.cpp +++ b/Engine/Source/Runtime/Engine/Private/ADPCMAudioInfo.cpp @@ -36,7 +36,6 @@ void FADPCMAudioInfo::SeekToTime(const float SeekTime) { CurrentUncompressedBlockSampleIndex = UncompressedBlockSize / sizeof(uint16); CurrentCompressedBlockIndex = 0; - TotalSamplesStreamed = 0; CurrentUncompressedBlockSampleIndex = 0; CurrentChunkIndex = 0; @@ -212,6 +211,7 @@ bool FADPCMAudioInfo::ReadCompressedData(uint8* Destination, bool bLooping, uint memcpy(OutData, WaveInfo.SampleDataStart + TotalSamplesStreamed * sizeof(uint16) * NumChannels, decompressedSamplesToCopy * sizeof(uint16) * NumChannels); TotalSamplesStreamed += decompressedSamplesToCopy; + BufferSize -= decompressedSamplesToCopy * sizeof(uint16) * NumChannels; // Check for the end of the audio samples and loop if needed if(TotalSamplesStreamed >= TotalSamplesPerChannel) diff --git a/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavAreas/NavArea.cpp b/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavAreas/NavArea.cpp index bb398848fc73..85c7b11b2853 100644 --- a/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavAreas/NavArea.cpp +++ b/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavAreas/NavArea.cpp @@ -12,7 +12,7 @@ UNavArea::UNavArea(const FObjectInitializer& ObjectInitializer) : Super(ObjectIn DrawColor = FColor::Magenta; SupportedAgentsBits = 0xffffffff; // NOTE! AreaFlags == 0 means UNWALKABLE! - AreaFlags = 1; + AreaFlags = 1; } void UNavArea::FinishDestroy() @@ -32,7 +32,17 @@ void UNavArea::FinishDestroy() void UNavArea::PostLoad() { Super::PostLoad(); + RegisterArea(); +} +void UNavArea::PostInitProperties() +{ + Super::PostInitProperties(); + RegisterArea(); +} + +void UNavArea::RegisterArea() +{ if (HasAnyFlags(RF_ClassDefaultObject) #if WITH_HOT_RELOAD && !GIsHotReload diff --git a/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavLinkComponent.cpp b/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavLinkComponent.cpp index c90fc6db5b03..9fac92fb8c9d 100644 --- a/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavLinkComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavLinkComponent.cpp @@ -38,7 +38,7 @@ FBoxSphereBounds UNavLinkComponent::CalcBounds(const FTransform &LocalToWorld) c void UNavLinkComponent::GetNavigationData(FNavigationRelevantData& Data) const { - NavigationHelper::ProcessNavLinkAndAppend(&Data.Modifiers, GetOwner(), Links); + NavigationHelper::ProcessNavLinkAndAppend(&Data.Modifiers, NavigationHelper::FNavLinkOwnerData(*this), Links); } bool UNavLinkComponent::IsNavigationRelevant() const diff --git a/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavLinkCustomComponent.cpp b/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavLinkCustomComponent.cpp index 62c92399e8d6..7d2f5e378d55 100644 --- a/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavLinkCustomComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavLinkCustomComponent.cpp @@ -265,8 +265,7 @@ void UNavLinkCustomComponent::CollectNearbyAgents(TArray OverlapsL, OverlapsR; const FVector LocationL = GetStartPoint(); diff --git a/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavLinkProxy.cpp b/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavLinkProxy.cpp index 808b7fa62f92..0e05c3ed4173 100644 --- a/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavLinkProxy.cpp +++ b/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavLinkProxy.cpp @@ -219,7 +219,7 @@ FBox ANavLinkProxy::GetComponentsBoundingBox(bool bNonColliding) const LinksBB += SegmentLink.RightEnd; } - LinksBB = LinksBB.TransformBy(RootComponent->ComponentToWorld); + LinksBB = LinksBB.TransformBy(RootComponent->GetComponentTransform()); if (SmartLinkComp && SmartLinkComp->IsNavigationRelevant()) { @@ -278,12 +278,3 @@ bool ANavLinkProxy::HasMovingAgents() const { return SmartLinkComp->HasMovingAgents(); } - -/** Returns SmartLinkComp subobject **/ -UNavLinkCustomComponent* ANavLinkProxy::GetSmartLinkComp() const { return SmartLinkComp; } -#if WITH_EDITORONLY_DATA -/** Returns EdRenderComp subobject **/ -UNavLinkRenderingComponent* ANavLinkProxy::GetEdRenderComp() const { return EdRenderComp; } -/** Returns SpriteComponent subobject **/ -UBillboardComponent* ANavLinkProxy::GetSpriteComponent() const { return SpriteComponent; } -#endif diff --git a/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavModifierComponent.cpp b/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavModifierComponent.cpp index b7af04ce3a6a..a7faa1fd17e9 100644 --- a/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavModifierComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavModifierComponent.cpp @@ -32,7 +32,7 @@ void UNavModifierComponent::CalcAndCacheBounds() const UBodySetup* BodySetup = PrimComp->GetBodySetup(); if (BodySetup) { - FTransform ParentTM = PrimComp->ComponentToWorld; + FTransform ParentTM = PrimComp->GetComponentTransform(); const FVector Scale3D = ParentTM.GetScale3D(); ParentTM.RemoveScaling(); Bounds += PrimComp->Bounds.GetBox(); diff --git a/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavigationModifier.cpp b/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavigationModifier.cpp index 3dfc70c97308..3956ecdf0fd9 100644 --- a/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavigationModifier.cpp +++ b/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavigationModifier.cpp @@ -355,7 +355,7 @@ FAreaNavModifier::FAreaNavModifier(const UBrushComponent* BrushComponent, const } Init(InAreaClass); - SetConvex(Verts.GetData(), 0, Verts.Num(), ENavigationCoordSystem::Unreal, BrushComponent->ComponentToWorld); + SetConvex(Verts.GetData(), 0, Verts.Num(), ENavigationCoordSystem::Unreal, BrushComponent->GetComponentTransform()); } void FAreaNavModifier::GetCylinder(FCylinderNavAreaData& Data) const @@ -789,17 +789,16 @@ void FCompositeNavModifier::CreateAreaModifiers(const UPrimitiveComponent* PrimC const FKBoxElem& BoxElem = BodySetup->AggGeom.BoxElems[Idx]; const FBox BoxSize = BoxElem.CalcAABB(FTransform::Identity, 1.0f); - FAreaNavModifier AreaMod(BoxSize, PrimComp->ComponentToWorld, AreaClass); + FAreaNavModifier AreaMod(BoxSize, PrimComp->GetComponentTransform(), AreaClass); Add(AreaMod); } for (int32 Idx = 0; Idx < BodySetup->AggGeom.SphylElems.Num(); Idx++) { const FKSphylElem& SphylElem = BodySetup->AggGeom.SphylElems[Idx]; - const float CapsuleHeight = SphylElem.Length + SphylElem.Radius; - const FTransform AreaOffset(FVector(0, 0, -CapsuleHeight)); + const FTransform AreaOffset(FVector(0, 0, -SphylElem.Length)); - FAreaNavModifier AreaMod(SphylElem.Radius, CapsuleHeight, AreaOffset * PrimComp->ComponentToWorld, AreaClass); + FAreaNavModifier AreaMod(SphylElem.Radius, SphylElem.Length * 2.0f, AreaOffset * PrimComp->GetComponentTransform(), AreaClass); Add(AreaMod); } @@ -807,15 +806,16 @@ void FCompositeNavModifier::CreateAreaModifiers(const UPrimitiveComponent* PrimC { const FKConvexElem& ConvexElem = BodySetup->AggGeom.ConvexElems[Idx]; - FAreaNavModifier AreaMod(ConvexElem.VertexData, 0, ConvexElem.VertexData.Num(), ENavigationCoordSystem::Unreal, PrimComp->ComponentToWorld, AreaClass); + FAreaNavModifier AreaMod(ConvexElem.VertexData, 0, ConvexElem.VertexData.Num(), ENavigationCoordSystem::Unreal, PrimComp->GetComponentTransform(), AreaClass); Add(AreaMod); } for (int32 Idx = 0; Idx < BodySetup->AggGeom.SphereElems.Num(); Idx++) { const FKSphereElem& SphereElem = BodySetup->AggGeom.SphereElems[Idx]; - - FAreaNavModifier AreaMod(SphereElem.Radius, SphereElem.Radius, PrimComp->ComponentToWorld, AreaClass); + const FTransform AreaOffset(FVector(0, 0, -SphereElem.Radius)); + + FAreaNavModifier AreaMod(SphereElem.Radius, SphereElem.Radius * 2.0f, AreaOffset * PrimComp->GetComponentTransform(), AreaClass); Add(AreaMod); } } diff --git a/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavigationSystem.cpp b/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavigationSystem.cpp index d703a85ad178..253198e18fad 100644 --- a/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavigationSystem.cpp +++ b/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavigationSystem.cpp @@ -317,7 +317,8 @@ UNavigationSystem::UNavigationSystem(const FObjectInitializer& ObjectInitializer #if WITH_EDITOR if (GIsEditor && HasAnyFlags(RF_ClassDefaultObject) == false) { - GLevelEditorModeTools().OnEditorModeChanged().AddUObject(this, &UNavigationSystem::OnEditorModeChanged); + FEditorDelegates::EditorModeEnter.AddUObject(this, &UNavigationSystem::OnEditorModeChanged, true); + FEditorDelegates::EditorModeExit.AddUObject(this, &UNavigationSystem::OnEditorModeChanged, false); } #endif // WITH_EDITOR } @@ -329,7 +330,8 @@ UNavigationSystem::~UNavigationSystem() #if WITH_EDITOR if (GIsEditor) { - GLevelEditorModeTools().OnEditorModeChanged().RemoveAll(this); + FEditorDelegates::EditorModeEnter.RemoveAll(this); + FEditorDelegates::EditorModeExit.RemoveAll(this); } #endif // WITH_EDITOR } @@ -720,17 +722,23 @@ void UNavigationSystem::OnWorldInitDone(FNavigationSystemRunMode Mode) } } - if (Mode == FNavigationSystemRunMode::EditorMode && bGenerateNavigationOnlyAroundNavigationInvokers) + if (Mode == FNavigationSystemRunMode::EditorMode) { - UWorld* MyWorld = GetWorld(); - // gather enforcers manually to be able to see the results in editor as well - for (TObjectIterator It; It; ++It) + // update navigation invokers + if (bGenerateNavigationOnlyAroundNavigationInvokers) { - if (MyWorld == It->GetWorld()) + for (TObjectIterator It; It; ++It) { - It->RegisterWithNavigationSystem(*this); + if (World == It->GetWorld()) + { + It->RegisterWithNavigationSystem(*this); + } } } + + // update navdata after loading world + const bool bIsLoadTime = true; + RebuildAll(bIsLoadTime); } bWorldInitDone = true; @@ -1325,7 +1333,7 @@ void UNavigationSystem::SimpleMoveToLocation(AController* Controller, const FVec } } -UNavigationPath* UNavigationSystem::FindPathToActorSynchronously(UObject* WorldContext, const FVector& PathStart, AActor* GoalActor, float TetherDistance, AActor* PathfindingContext, TSubclassOf FilterClass) +UNavigationPath* UNavigationSystem::FindPathToActorSynchronously(UObject* WorldContextObject, const FVector& PathStart, AActor* GoalActor, float TetherDistance, AActor* PathfindingContext, TSubclassOf FilterClass) { if (GoalActor == NULL) { @@ -1333,7 +1341,7 @@ UNavigationPath* UNavigationSystem::FindPathToActorSynchronously(UObject* WorldC } INavAgentInterface* NavAgent = Cast(GoalActor); - UNavigationPath* GeneratedPath = FindPathToLocationSynchronously(WorldContext, PathStart, NavAgent ? NavAgent->GetNavAgentLocation() : GoalActor->GetActorLocation(), PathfindingContext, FilterClass); + UNavigationPath* GeneratedPath = FindPathToLocationSynchronously(WorldContextObject, PathStart, NavAgent ? NavAgent->GetNavAgentLocation() : GoalActor->GetActorLocation(), PathfindingContext, FilterClass); if (GeneratedPath != NULL && GeneratedPath->GetPath().IsValid() == true) { GeneratedPath->GetPath()->SetGoalActorObservation(*GoalActor, TetherDistance); @@ -1342,13 +1350,13 @@ UNavigationPath* UNavigationSystem::FindPathToActorSynchronously(UObject* WorldC return GeneratedPath; } -UNavigationPath* UNavigationSystem::FindPathToLocationSynchronously(UObject* WorldContext, const FVector& PathStart, const FVector& PathEnd, AActor* PathfindingContext, TSubclassOf FilterClass) +UNavigationPath* UNavigationSystem::FindPathToLocationSynchronously(UObject* WorldContextObject, const FVector& PathStart, const FVector& PathEnd, AActor* PathfindingContext, TSubclassOf FilterClass) { UWorld* World = NULL; - if (WorldContext != NULL) + if (WorldContextObject != NULL) { - World = GEngine->GetWorldFromContextObject(WorldContext); + World = GEngine->GetWorldFromContextObject(WorldContextObject); } if (World == NULL && PathfindingContext != NULL) { @@ -3369,7 +3377,7 @@ void UNavigationSystem::RemoveNavigationBuildLock(uint8 Flags, bool bSkipRebuild } } -void UNavigationSystem::RebuildAll() +void UNavigationSystem::RebuildAll(bool bIsLoadTime) { const bool bIsInGame = GetWorld()->IsGameWorld(); @@ -3391,7 +3399,7 @@ void UNavigationSystem::RebuildAll() { ANavigationData* NavData = NavDataSet[NavDataIndex]; - if (NavData && (!bIsInGame || NavData->SupportsRuntimeGeneration())) + if (NavData && (!bIsLoadTime || NavData->NeedsRebuildOnLoad()) && (!bIsInGame || NavData->SupportsRuntimeGeneration())) { NavData->RebuildAll(); } @@ -3712,14 +3720,14 @@ void UNavigationSystem::DiscardNavigationDataChunks(UWorld* InWorld) //----------------------------------------------------------------------// // Blueprint functions //----------------------------------------------------------------------// -UNavigationSystem* UNavigationSystem::GetNavigationSystem(UObject* WorldContext) +UNavigationSystem* UNavigationSystem::GetNavigationSystem(UObject* WorldContextObject) { - return GetCurrent(WorldContext); + return GetCurrent(WorldContextObject); } -bool UNavigationSystem::K2_ProjectPointToNavigation(UObject* WorldContext, const FVector& Point, FVector& ProjectedLocation, ANavigationData* NavData, TSubclassOf FilterClass, const FVector QueryExtent) +bool UNavigationSystem::K2_ProjectPointToNavigation(UObject* WorldContextObject, const FVector& Point, FVector& ProjectedLocation, ANavigationData* NavData, TSubclassOf FilterClass, const FVector QueryExtent) { - UWorld* World = GEngine->GetWorldFromContextObject(WorldContext); + UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject); UNavigationSystem* NavSys = UNavigationSystem::GetCurrent(World); ProjectedLocation = Point; @@ -3732,7 +3740,7 @@ bool UNavigationSystem::K2_ProjectPointToNavigation(UObject* WorldContext, const if (UseNavData) { bResult = NavSys->ProjectPointToNavigation(Point, OutNavLocation, QueryExtent, NavData - , UNavigationQueryFilter::GetQueryFilter(*UseNavData, WorldContext, FilterClass)); + , UNavigationQueryFilter::GetQueryFilter(*UseNavData, WorldContextObject, FilterClass)); ProjectedLocation = OutNavLocation.Location; } } @@ -3740,19 +3748,19 @@ bool UNavigationSystem::K2_ProjectPointToNavigation(UObject* WorldContext, const return bResult; } -bool UNavigationSystem::K2_GetRandomReachablePointInRadius(UObject* WorldContext, const FVector& Origin, FVector& RandomLocation, float Radius, ANavigationData* NavData, TSubclassOf FilterClass) +bool UNavigationSystem::K2_GetRandomReachablePointInRadius(UObject* WorldContextObject, const FVector& Origin, FVector& RandomLocation, float Radius, ANavigationData* NavData, TSubclassOf FilterClass) { FNavLocation RandomPoint(Origin); bool bResult = false; - UWorld* World = GEngine->GetWorldFromContextObject(WorldContext); + UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject); UNavigationSystem* NavSys = UNavigationSystem::GetCurrent(World); if (NavSys) { ANavigationData* UseNavData = NavData ? NavData : NavSys->GetMainNavData(FNavigationSystem::DontCreate); if (UseNavData) { - bResult = NavSys->GetRandomReachablePointInRadius(Origin, Radius, RandomPoint, UseNavData, UNavigationQueryFilter::GetQueryFilter(*UseNavData, WorldContext, FilterClass)); + bResult = NavSys->GetRandomReachablePointInRadius(Origin, Radius, RandomPoint, UseNavData, UNavigationQueryFilter::GetQueryFilter(*UseNavData, WorldContextObject, FilterClass)); RandomLocation = RandomPoint.Location; } } @@ -3760,19 +3768,19 @@ bool UNavigationSystem::K2_GetRandomReachablePointInRadius(UObject* WorldContext return bResult; } -bool UNavigationSystem::K2_GetRandomPointInNavigableRadius(UObject* WorldContext, const FVector& Origin, FVector& RandomLocation, float Radius, ANavigationData* NavData, TSubclassOf FilterClass) +bool UNavigationSystem::K2_GetRandomPointInNavigableRadius(UObject* WorldContextObject, const FVector& Origin, FVector& RandomLocation, float Radius, ANavigationData* NavData, TSubclassOf FilterClass) { FNavLocation RandomPoint(Origin); bool bResult = false; - UWorld* World = GEngine->GetWorldFromContextObject(WorldContext); + UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject); UNavigationSystem* NavSys = UNavigationSystem::GetCurrent(World); if (NavSys) { ANavigationData* UseNavData = NavData ? NavData : NavSys->GetMainNavData(FNavigationSystem::DontCreate); if (UseNavData) { - bResult = NavSys->GetRandomPointInNavigableRadius(Origin, Radius, RandomPoint, UseNavData, UNavigationQueryFilter::GetQueryFilter(*UseNavData, WorldContext, FilterClass)); + bResult = NavSys->GetRandomPointInNavigableRadius(Origin, Radius, RandomPoint, UseNavData, UNavigationQueryFilter::GetQueryFilter(*UseNavData, WorldContextObject, FilterClass)); RandomLocation = RandomPoint.Location; } } @@ -4183,36 +4191,36 @@ FVector UNavigationSystem::ProjectPointToNavigation(UObject* WorldContextObject, return ProjectedPoint.Location; } -FVector UNavigationSystem::GetRandomReachablePointInRadius(UObject* WorldContext, const FVector& Origin, float Radius, ANavigationData* NavData, TSubclassOf FilterClass) +FVector UNavigationSystem::GetRandomReachablePointInRadius(UObject* WorldContextObject, const FVector& Origin, float Radius, ANavigationData* NavData, TSubclassOf FilterClass) { FNavLocation RandomPoint; - UWorld* World = GEngine->GetWorldFromContextObject(WorldContext); + UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject); UNavigationSystem* NavSys = UNavigationSystem::GetCurrent(World); if (NavSys) { ANavigationData* UseNavData = NavData ? NavData : NavSys->GetMainNavData(FNavigationSystem::DontCreate); if (UseNavData) { - NavSys->GetRandomReachablePointInRadius(Origin, Radius, RandomPoint, UseNavData, UNavigationQueryFilter::GetQueryFilter(*UseNavData, WorldContext, FilterClass)); + NavSys->GetRandomReachablePointInRadius(Origin, Radius, RandomPoint, UseNavData, UNavigationQueryFilter::GetQueryFilter(*UseNavData, WorldContextObject, FilterClass)); } } return RandomPoint.Location; } -FVector UNavigationSystem::GetRandomPointInNavigableRadius(UObject* WorldContext, const FVector& Origin, float Radius, ANavigationData* NavData, TSubclassOf FilterClass) +FVector UNavigationSystem::GetRandomPointInNavigableRadius(UObject* WorldContextObject, const FVector& Origin, float Radius, ANavigationData* NavData, TSubclassOf FilterClass) { FNavLocation RandomPoint; - UWorld* World = GEngine->GetWorldFromContextObject(WorldContext); + UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject); UNavigationSystem* NavSys = UNavigationSystem::GetCurrent(World); if (NavSys) { ANavigationData* UseNavData = NavData ? NavData : NavSys->GetMainNavData(FNavigationSystem::DontCreate); if (UseNavData) { - NavSys->GetRandomPointInNavigableRadius(Origin, Radius, RandomPoint, UseNavData, UNavigationQueryFilter::GetQueryFilter(*UseNavData, WorldContext, FilterClass)); + NavSys->GetRandomPointInNavigableRadius(Origin, Radius, RandomPoint, UseNavData, UNavigationQueryFilter::GetQueryFilter(*UseNavData, WorldContextObject, FilterClass)); } } diff --git a/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavigationSystemHelpers.cpp b/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavigationSystemHelpers.cpp index fbe445580f11..0a50450f0483 100644 --- a/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavigationSystemHelpers.cpp +++ b/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavigationSystemHelpers.cpp @@ -15,6 +15,18 @@ namespace NavigationHelper { + FNavLinkOwnerData::FNavLinkOwnerData(const AActor& InActor) + { + Actor = &InActor; + LinkToWorld = InActor.GetActorTransform(); + } + + FNavLinkOwnerData::FNavLinkOwnerData(const USceneComponent& InComponent) + { + Actor = InComponent.GetOwner(); + LinkToWorld = InComponent.GetComponentTransform(); + } + void GatherCollision(UBodySetup* RigidBody, TNavStatArray& OutVertexBuffer, TNavStatArray& OutIndexBuffer, const FTransform& LocalToWorld) { if (RigidBody == NULL) @@ -47,7 +59,7 @@ namespace NavigationHelper UE_VLOG_SEGMENT(Querier, LogNavigation, Log, FallStart, FallStart + FVector(0, 0, -FallLimit) , FColor::Red, TEXT("TerrainTrace")); - FCollisionQueryParams TraceParams(NAME_None, true, Querier); + FCollisionQueryParams TraceParams(SCENE_QUERY_STAT(RawGeometryFall), true, Querier); FHitResult Hit; const bool bHit = Querier->GetWorld()->LineTraceSingleByChannel(Hit, FallStart, FallStart+FVector(0,0,-FallLimit), ECC_WorldStatic, TraceParams); if( bHit ) @@ -65,10 +77,9 @@ namespace NavigationHelper return FallDownHeight; } - void DefaultNavLinkProcessorImpl(FCompositeNavModifier* OUT CompositeModifier, const AActor* Actor, const TArray& IN NavLinks) + void DefaultNavLinkProcessorImpl(FCompositeNavModifier* OUT CompositeModifier, const FNavLinkOwnerData& OwnerData, const TArray& IN NavLinks) { - const FTransform LocalToWorld = Actor->ActorToWorld(); - FSimpleLinkNavModifier SimpleLink(NavLinks, LocalToWorld); + FSimpleLinkNavModifier SimpleLink(NavLinks, OwnerData.LinkToWorld); // adjust links for (int32 LinkIndex = 0; LinkIndex < SimpleLink.Links.Num(); ++LinkIndex) @@ -83,14 +94,13 @@ namespace NavigationHelper if (Link.MaxFallDownLength > 0) { - const FVector WorldRight = LocalToWorld.TransformPosition(Link.Right); - const float FallDownHeight = RawGeometryFall(Actor, WorldRight, Link.MaxFallDownLength); + const FVector WorldRight = OwnerData.LinkToWorld.TransformPosition(Link.Right); + const float FallDownHeight = RawGeometryFall(OwnerData.Actor, WorldRight, Link.MaxFallDownLength); if (FallDownHeight > 0.f) { // @todo maybe it's a good idea to clear ModifiedLink.MaxFallDownLength here - UE_VLOG_SEGMENT(Actor, LogNavigation, Log, WorldRight, WorldRight + FVector(0, 0, -FallDownHeight) - , FColor::Green, TEXT("FallDownHeight %d"), LinkIndex); + UE_VLOG_SEGMENT(OwnerData.Actor, LogNavigation, Log, WorldRight, WorldRight + FVector(0, 0, -FallDownHeight), FColor::Green, TEXT("FallDownHeight %d"), LinkIndex); Link.Right.Z -= FallDownHeight; } @@ -98,14 +108,13 @@ namespace NavigationHelper if (Link.LeftProjectHeight > 0) { - const FVector WorldLeft = LocalToWorld.TransformPosition(Link.Left); - const float FallDownHeight = RawGeometryFall(Actor, WorldLeft, Link.LeftProjectHeight); + const FVector WorldLeft = OwnerData.LinkToWorld.TransformPosition(Link.Left); + const float FallDownHeight = RawGeometryFall(OwnerData.Actor, WorldLeft, Link.LeftProjectHeight); if (FallDownHeight > 0.f) { // @todo maybe it's a good idea to clear ModifiedLink.LeftProjectHeight here - UE_VLOG_SEGMENT(Actor, LogNavigation, Log, WorldLeft, WorldLeft + FVector(0, 0, -FallDownHeight) - , FColor::Green, TEXT("LeftProjectHeight %d"), LinkIndex); + UE_VLOG_SEGMENT(OwnerData.Actor, LogNavigation, Log, WorldLeft, WorldLeft + FVector(0, 0, -FallDownHeight), FColor::Green, TEXT("LeftProjectHeight %d"), LinkIndex); Link.Left.Z -= FallDownHeight; } @@ -115,12 +124,11 @@ namespace NavigationHelper CompositeModifier->Add(SimpleLink); } - void DefaultNavLinkSegmentProcessorImpl(FCompositeNavModifier* OUT CompositeModifier, const AActor* Actor, const TArray& IN NavLinks) + void DefaultNavLinkSegmentProcessorImpl(FCompositeNavModifier* OUT CompositeModifier, const FNavLinkOwnerData& OwnerData, const TArray& IN NavLinks) { - const FTransform LocalToWorld = Actor->ActorToWorld(); - FSimpleLinkNavModifier SimpleLink(NavLinks, LocalToWorld); + FSimpleLinkNavModifier SimpleLink(NavLinks, OwnerData.LinkToWorld); - // adjust links if needed + // adjust links if needed for (int32 LinkIndex = 0; LinkIndex < SimpleLink.SegmentLinks.Num(); ++LinkIndex) { FNavigationSegmentLink& Link = SimpleLink.SegmentLinks[LinkIndex]; @@ -134,25 +142,23 @@ namespace NavigationHelper if (Link.MaxFallDownLength > 0) { - const FVector WorldRightStart = LocalToWorld.TransformPosition(Link.RightStart); - const FVector WorldRightEnd = LocalToWorld.TransformPosition(Link.RightEnd); + const FVector WorldRightStart = OwnerData.LinkToWorld.TransformPosition(Link.RightStart); + const FVector WorldRightEnd = OwnerData.LinkToWorld.TransformPosition(Link.RightEnd); - const float FallDownHeightStart = RawGeometryFall(Actor, WorldRightStart, Link.MaxFallDownLength); - const float FallDownHeightEnd = RawGeometryFall(Actor, WorldRightEnd, Link.MaxFallDownLength); + const float FallDownHeightStart = RawGeometryFall(OwnerData.Actor, WorldRightStart, Link.MaxFallDownLength); + const float FallDownHeightEnd = RawGeometryFall(OwnerData.Actor, WorldRightEnd, Link.MaxFallDownLength); if (FallDownHeightStart > 0.f) { // @todo maybe it's a good idea to clear ModifiedLink.MaxFallDownLength here - UE_VLOG_SEGMENT(Actor, LogNavigation, Log, WorldRightStart, WorldRightStart + FVector(0, 0, -FallDownHeightStart) - , FColor::Green, TEXT("FallDownHeightStart %d"), LinkIndex); + UE_VLOG_SEGMENT(OwnerData.Actor, LogNavigation, Log, WorldRightStart, WorldRightStart + FVector(0, 0, -FallDownHeightStart), FColor::Green, TEXT("FallDownHeightStart %d"), LinkIndex); Link.RightStart.Z -= FallDownHeightStart; } if (FallDownHeightEnd > 0.f) { // @todo maybe it's a good idea to clear ModifiedLink.MaxFallDownLength here - UE_VLOG_SEGMENT(Actor, LogNavigation, Log, WorldRightEnd, WorldRightEnd + FVector(0, 0, -FallDownHeightEnd) - , FColor::Green, TEXT("FallDownHeightEnd %d"), LinkIndex); + UE_VLOG_SEGMENT(OwnerData.Actor, LogNavigation, Log, WorldRightEnd, WorldRightEnd + FVector(0, 0, -FallDownHeightEnd), FColor::Green, TEXT("FallDownHeightEnd %d"), LinkIndex); Link.RightEnd.Z -= FallDownHeightEnd; } @@ -162,38 +168,54 @@ namespace NavigationHelper CompositeModifier->Add(SimpleLink); } - FNavLinkProcessorDelegate NavLinkProcessor = FNavLinkProcessorDelegate::CreateStatic(DefaultNavLinkProcessorImpl); - FNavLinkSegmentProcessorDelegate NavLinkSegmentProcessor = FNavLinkSegmentProcessorDelegate::CreateStatic(DefaultNavLinkSegmentProcessorImpl); + FNavLinkProcessorDataDelegate NavLinkProcessor = FNavLinkProcessorDataDelegate::CreateStatic(DefaultNavLinkProcessorImpl); + FNavLinkSegmentProcessorDataDelegate NavLinkSegmentProcessor = FNavLinkSegmentProcessorDataDelegate::CreateStatic(DefaultNavLinkSegmentProcessorImpl); void ProcessNavLinkAndAppend(FCompositeNavModifier* OUT CompositeModifier, const AActor* Actor, const TArray& IN NavLinks) + { + if (Actor) + { + ProcessNavLinkAndAppend(CompositeModifier, FNavLinkOwnerData(*Actor), NavLinks); + } + } + + void ProcessNavLinkAndAppend(FCompositeNavModifier* OUT CompositeModifier, const FNavLinkOwnerData& OwnerData, const TArray& IN NavLinks) { SCOPE_CYCLE_COUNTER(STAT_Navigation_AdjustingNavLinks); if (NavLinks.Num()) { check(NavLinkProcessor.IsBound()); - NavLinkProcessor.Execute(CompositeModifier, Actor, NavLinks); + NavLinkProcessor.Execute(CompositeModifier, OwnerData, NavLinks); } } void ProcessNavLinkSegmentAndAppend(FCompositeNavModifier* OUT CompositeModifier, const AActor* Actor, const TArray& IN NavLinks) + { + if (Actor) + { + ProcessNavLinkSegmentAndAppend(CompositeModifier, FNavLinkOwnerData(*Actor), NavLinks); + } + } + + void ProcessNavLinkSegmentAndAppend(FCompositeNavModifier* OUT CompositeModifier, const FNavLinkOwnerData& OwnerData, const TArray& IN NavLinks) { SCOPE_CYCLE_COUNTER(STAT_Navigation_AdjustingNavLinks); if (NavLinks.Num()) { check(NavLinkSegmentProcessor.IsBound()); - NavLinkSegmentProcessor.Execute(CompositeModifier, Actor, NavLinks); + NavLinkSegmentProcessor.Execute(CompositeModifier, OwnerData, NavLinks); } } - void SetNavLinkProcessorDelegate(const FNavLinkProcessorDelegate& NewDelegate) + void SetNavLinkProcessorDelegate(const FNavLinkProcessorDataDelegate& NewDelegate) { check(NewDelegate.IsBound()); NavLinkProcessor = NewDelegate; } - void SetNavLinkSegmentProcessorDelegate(const FNavLinkSegmentProcessorDelegate& NewDelegate) + void SetNavLinkSegmentProcessorDelegate(const FNavLinkSegmentProcessorDataDelegate& NewDelegate) { check(NewDelegate.IsBound()); NavLinkSegmentProcessor = NewDelegate; @@ -208,4 +230,33 @@ namespace NavigationHelper // AND has full colliding capabilities && BodySetup.DefaultInstance.GetCollisionEnabled() == ECollisionEnabled::QueryAndPhysics; } + + ////////////////////////////////////////////////////////////////////////// + // DEPRECATED FUNCTIONS + + void SetNavLinkProcessorDelegate(const FNavLinkProcessorDelegate& NewDelegate) + { + // don't set delegate, custom navlink processor will not be registered with deprecated function + } + + void SetNavLinkSegmentProcessorDelegate(const FNavLinkSegmentProcessorDelegate& NewDelegate) + { + // don't set delegate, custom navlink processor will not be registered with deprecated function + } + + void DefaultNavLinkProcessorImpl(FCompositeNavModifier* OUT CompositeModifier, const AActor* Actor, const TArray& IN NavLinks) + { + if (Actor) + { + DefaultNavLinkProcessorImpl(CompositeModifier, FNavLinkOwnerData(*Actor), NavLinks); + } + } + + void DefaultNavLinkSegmentProcessorImpl(FCompositeNavModifier* OUT CompositeModifier, const AActor* Actor, const TArray& IN NavLinks) + { + if (Actor) + { + DefaultNavLinkSegmentProcessorImpl(CompositeModifier, FNavLinkOwnerData(*Actor), NavLinks); + } + } } diff --git a/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavigationTestingActor.cpp b/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavigationTestingActor.cpp index 9551c9647758..fb4ce6ff1f8a 100644 --- a/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavigationTestingActor.cpp +++ b/Engine/Source/Runtime/Engine/Private/AI/Navigation/NavigationTestingActor.cpp @@ -459,10 +459,3 @@ FPathFindingQuery ANavigationTestingActor::BuildPathFindingQuery(const ANavigati return FPathFindingQuery(); } - -/** Returns CapsuleComponent subobject **/ -UCapsuleComponent* ANavigationTestingActor::GetCapsuleComponent() const { return CapsuleComponent; } -#if WITH_EDITORONLY_DATA -/** Returns EdRenderComp subobject **/ -UNavTestRenderingComponent* ANavigationTestingActor::GetEdRenderComp() const { return EdRenderComp; } -#endif diff --git a/Engine/Source/Runtime/Engine/Private/AI/Navigation/RecastNavMeshGenerator.cpp b/Engine/Source/Runtime/Engine/Private/AI/Navigation/RecastNavMeshGenerator.cpp index 7f0495768722..26b4c7164157 100644 --- a/Engine/Source/Runtime/Engine/Private/AI/Navigation/RecastNavMeshGenerator.cpp +++ b/Engine/Source/Runtime/Engine/Private/AI/Navigation/RecastNavMeshGenerator.cpp @@ -492,7 +492,7 @@ void ExportPxHeightField(PxHeightField const * const HeightField, const FTransfo { for (int32 X = 0; X < NumCols - 1; X++) { - const int32 SampleIdx = (bMirrored ? X : (NumCols - X - 1))*NumCols + Y; + const int32 SampleIdx = (bMirrored ? X : (NumCols - X - 1 - 1))*NumCols + Y; const PxHeightFieldSample& Sample = HFSamples[SampleIdx]; const bool bIsHole = (Sample.materialIndex0 == PxHeightFieldMaterial::eHOLE); if (bIsHole) @@ -962,7 +962,7 @@ FORCEINLINE_DEBUGGABLE void ExportComponent(UActorComponent* Component, FRecastG UPrimitiveComponent* PrimComp = Cast(Component); if (PrimComp && PrimComp->IsNavigationRelevant() && (PrimComp->HasCustomNavigableGeometry() != EHasCustomNavigableGeometry::DontExport)) { - if (PrimComp->HasCustomNavigableGeometry() && !PrimComp->DoCustomNavigableGeometryExport(GeomExport)) + if ((PrimComp->HasCustomNavigableGeometry() != EHasCustomNavigableGeometry::Type::No) && !PrimComp->DoCustomNavigableGeometryExport(GeomExport)) { bHasData = true; } @@ -972,7 +972,7 @@ FORCEINLINE_DEBUGGABLE void ExportComponent(UActorComponent* Component, FRecastG { if (!bHasData) { - ExportRigidBodySetup(*BodySetup, GeomExport.VertexBuffer, GeomExport.IndexBuffer, GeomExport.Data->Bounds, PrimComp->ComponentToWorld); + ExportRigidBodySetup(*BodySetup, GeomExport.VertexBuffer, GeomExport.IndexBuffer, GeomExport.Data->Bounds, PrimComp->GetComponentTransform()); bHasData = true; } @@ -3646,7 +3646,7 @@ TArray FRecastNavMeshGenerator::RemoveTileLayers(const int32 TileX, cons if (DetourMesh != nullptr && DetourMesh->isEmpty() == false) { - const int32 NumLayers = DetourMesh != nullptr ? DetourMesh->getTileCountAt(TileX, TileY) : 0; + const int32 NumLayers = DetourMesh->getTileCountAt(TileX, TileY); if (NumLayers > 0) { diff --git a/Engine/Source/Runtime/Engine/Private/ActiveSound.cpp b/Engine/Source/Runtime/Engine/Private/ActiveSound.cpp index ab47341df325..1c026c3c54e7 100644 --- a/Engine/Source/Runtime/Engine/Private/ActiveSound.cpp +++ b/Engine/Source/Runtime/Engine/Private/ActiveSound.cpp @@ -519,14 +519,13 @@ void FActiveSound::CheckOcclusion(const FVector ListenerLocation, const FVector if (!bAsyncOcclusionPending && (PlaybackTime - LastOcclusionCheckTime) > OcclusionCheckInterval) { LastOcclusionCheckTime = PlaybackTime; - static FName NAME_SoundOcclusion = FName(TEXT("SoundOcclusion")); const bool bUseComplexCollisionForOcclusion = AttenuationSettingsPtr->bUseComplexCollisionForOcclusion; const ECollisionChannel OcclusionTraceChannel = AttenuationSettingsPtr->OcclusionTraceChannel; if (!bHasCheckedOcclusion) { - FCollisionQueryParams Params(NAME_SoundOcclusion, bUseComplexCollisionForOcclusion); + FCollisionQueryParams Params(SCENE_QUERY_STAT(SoundOcclusion), bUseComplexCollisionForOcclusion); if (OwnerID > 0) { Params.AddIgnoredActor(OwnerID); @@ -553,7 +552,7 @@ void FActiveSound::CheckOcclusion(const FVector ListenerLocation, const FVector { if (UWorld* WorldPtr = SoundWorld.Get()) { - FCollisionQueryParams Params(NAME_SoundOcclusion, bUseComplexCollisionForOcclusion); + FCollisionQueryParams Params(SCENE_QUERY_STAT(SoundOcclusion), bUseComplexCollisionForOcclusion); if (SoundOwnerID > 0) { Params.AddIgnoredActor(SoundOwnerID); diff --git a/Engine/Source/Runtime/Engine/Private/Actor.cpp b/Engine/Source/Runtime/Engine/Private/Actor.cpp index e6eb22779d6e..247104bd635d 100644 --- a/Engine/Source/Runtime/Engine/Private/Actor.cpp +++ b/Engine/Source/Runtime/Engine/Private/Actor.cpp @@ -53,6 +53,10 @@ DECLARE_CYCLE_STAT(TEXT("PostActorConstruction"), STAT_PostActorConstruction, ST FMakeNoiseDelegate AActor::MakeNoiseDelegate = FMakeNoiseDelegate::CreateStatic(&AActor::MakeNoiseImpl); +#if WITH_EDITOR +FUObjectAnnotationSparseBool GSelectedActorAnnotation; +#endif + #if !UE_BUILD_SHIPPING FOnProcessEvent AActor::ProcessEventDelegate; #endif @@ -949,7 +953,20 @@ void AActor::CallPreReplication(UNetDriver* NetDriver) return; } - PreReplication(*NetDriver->FindOrCreateRepChangedPropertyTracker(this).Get()); + IRepChangedPropertyTracker* const ActorChangedPropertyTracker = NetDriver->FindOrCreateRepChangedPropertyTracker(this).Get(); + + // PreReplication is only called on the server, except when we're recording a Client Replay. + // In that case we call PreReplication on the locally controlled Character as well. + if ((Role == ROLE_Authority) || ((Role == ROLE_AutonomousProxy) && GetWorld()->IsRecordingClientReplay())) + { + PreReplication(*ActorChangedPropertyTracker); + } + + // If we're recording a replay, call this for everyone (includes SimulatedProxies). + if (ActorChangedPropertyTracker->IsReplay()) + { + PreReplicationForReplay(*ActorChangedPropertyTracker); + } // Call PreReplication on all owned components that are replicated for (UActorComponent* Component : ReplicatedComponents) @@ -962,6 +979,10 @@ void AActor::CallPreReplication(UNetDriver* NetDriver) } } +void AActor::PreReplicationForReplay(IRepChangedPropertyTracker & ChangedPropertyTracker) +{ +} + void AActor::PostActorCreated() { // nothing at the moment @@ -1121,7 +1142,7 @@ FBox AActor::CalculateComponentsBoundingBoxInLocalSpace( bool bNonColliding ) co // Only use collidable components to find collision bounding box. if( PrimComp->IsRegistered() && ( bNonColliding || PrimComp->IsCollisionEnabled() ) ) { - const FTransform ComponentToActor = PrimComp->ComponentToWorld * WorldToActor; + const FTransform ComponentToActor = PrimComp->GetComponentTransform() * WorldToActor; FBoxSphereBounds ActorSpaceComponentBounds = PrimComp->CalcBounds( ComponentToActor ); Box += ActorSpaceComponentBounds.GetBox(); @@ -1576,7 +1597,7 @@ void AActor::SnapRootComponentTo(AActor* InParentActor, FName InSocketName/* = N USceneComponent* ParentDefaultAttachComponent = InParentActor->GetDefaultAttachComponent(); if (ParentDefaultAttachComponent) { - RootComponent->SnapTo(ParentDefaultAttachComponent, InSocketName); + RootComponent->AttachToComponent(ParentDefaultAttachComponent, FAttachmentTransformRules::SnapToTargetNotIncludingScale, InSocketName); } } } @@ -1614,14 +1635,13 @@ void AActor::DetachSceneComponentsFromParent(USceneComponent* InParentComponent, void AActor::DetachAllSceneComponents(USceneComponent* InParentComponent, const FDetachmentTransformRules& DetachmentRules) { - if (InParentComponent != NULL) + if (InParentComponent) { TInlineComponentArray Components; GetComponents(Components); - for (int32 Index = 0; Index < Components.Num(); ++Index) + for (USceneComponent* SceneComp : Components) { - USceneComponent* SceneComp = Components[Index]; if (SceneComp->GetAttachParent() == InParentComponent) { SceneComp->DetachFromComponent(DetachmentRules); @@ -1925,6 +1945,26 @@ void AActor::RouteEndPlay(const EEndPlayReason::Type EndPlayReason) { EndPlay(EndPlayReason); } + + // Behaviors specific to an actor being unloaded due to a streaming level removal + if (EndPlayReason == EEndPlayReason::RemovedFromWorld) + { + ClearComponentOverlaps(); + + bActorInitialized = false; + if (World) + { + World->RemoveNetworkActor(this); + } + } + + // Clear any ticking lifespan timers + if (TimerHandle_LifeSpanExpired.IsValid()) + { + SetLifeSpan(0.f); + } + + UNavigationSystem::OnActorUnregistered(this); } UninitializeComponents(); @@ -1951,23 +1991,6 @@ void AActor::EndPlay(const EEndPlayReason::Type EndPlayReason) } } } - - // Behaviors specific to an actor being unloaded due to a streaming level removal - if (EndPlayReason == EEndPlayReason::RemovedFromWorld) - { - ClearComponentOverlaps(); - - bActorInitialized = false; - GetWorld()->RemoveNetworkActor(this); - } - - // Clear any ticking lifespan timers - if (TimerHandle_LifeSpanExpired.IsValid()) - { - SetLifeSpan(0.f); - } - - UNavigationSystem::OnActorUnregistered(this); } FVector AActor::GetPlacementExtent() const @@ -2466,7 +2489,10 @@ void AActor::AddOwnedComponent(UActorComponent* Component) { check(Component->GetOwner() == this); - Modify(); + // Note: we do not mark dirty here because this can be called when in editor when modifying transient components + // if a component is added during this time it should not dirty. Higher level code in the editor should always dirty the package anyway + const bool bMarkDirty = false; + Modify(bMarkDirty); bool bAlreadyInSet = false; OwnedComponents.Add(Component, &bAlreadyInSet); @@ -2678,6 +2704,12 @@ void AActor::PostEditImport() DispatchOnComponentsCreated(this); } + +bool AActor::IsSelectedInEditor() const +{ + return !IsPendingKill() && GSelectedActorAnnotation.Get(this); +} + #endif /** Util that sets up the actor's component hierarchy (when users forget to do so, in their native ctor) */ @@ -2838,7 +2870,7 @@ void AActor::FinishSpawning(const FTransform& UserTransform, bool bIsDefaultTran { bHasFinishedSpawning = true; - FTransform FinalRootComponentTransform = (RootComponent ? RootComponent->ComponentToWorld : UserTransform); + FTransform FinalRootComponentTransform = (RootComponent ? RootComponent->GetComponentTransform() : UserTransform); // see if we need to adjust the transform (i.e. in deferred cases where the caller passes in a different transform here // than was passed in during the original SpawnActor call) @@ -2857,7 +2889,7 @@ void AActor::FinishSpawning(const FTransform& UserTransform, bool bIsDefaultTran // caller passed a different transform! // undo the original spawn transform to get back to the template transform, so we can recompute a good // final transform that takes into account the template's transform - FTransform const TemplateTransform = RootComponent->ComponentToWorld * OriginalSpawnTransform->Inverse(); + FTransform const TemplateTransform = RootComponent->GetComponentTransform() * OriginalSpawnTransform->Inverse(); FinalRootComponentTransform = TemplateTransform * UserTransform; } } diff --git a/Engine/Source/Runtime/Engine/Private/ActorConstruction.cpp b/Engine/Source/Runtime/Engine/Private/ActorConstruction.cpp index f0b7067e9d95..04119ab84619 100644 --- a/Engine/Source/Runtime/Engine/Private/ActorConstruction.cpp +++ b/Engine/Source/Runtime/Engine/Private/ActorConstruction.cpp @@ -286,7 +286,7 @@ void AActor::RerunConstructionScripts() USceneComponent* AttachParent = ActorTransactionAnnotation->RootComponentData.AttachedParentInfo.AttachParent.Get(); AttachParentComponent = (AttachParent ? AttachParent : FindObjectFast(Parent, ActorTransactionAnnotation->RootComponentData.AttachedParentInfo.AttachParentName)); SocketName = ActorTransactionAnnotation->RootComponentData.AttachedParentInfo.SocketName; - DetachRootComponentFromParent(); + DetachFromActor(FDetachmentTransformRules::KeepWorldTransform); } for (const FActorRootComponentReconstructionData::FAttachedActorInfo& CachedAttachInfo : ActorTransactionAnnotation->RootComponentData.AttachedToInfo) @@ -301,7 +301,7 @@ void AActor::RerunConstructionScripts() Info.RelativeTransform = CachedAttachInfo.RelativeTransform; AttachedActorInfos.Add(Info); - AttachedActor->DetachRootComponentFromParent(); + AttachedActor->DetachFromActor(FDetachmentTransformRules::KeepWorldTransform); } } @@ -365,7 +365,7 @@ void AActor::RerunConstructionScripts() // Update component transform and remember it so it can be reapplied to any new root component which exists after construction. // (Component transform may be stale if we are here following an Undo) RootComponent->UpdateComponentToWorld(); - OldTransform = RootComponent->ComponentToWorld; + OldTransform = RootComponent->GetComponentTransform(); } } diff --git a/Engine/Source/Runtime/Engine/Private/ActorEditor.cpp b/Engine/Source/Runtime/Engine/Private/ActorEditor.cpp index e93438565057..440eeaad6a01 100644 --- a/Engine/Source/Runtime/Engine/Private/ActorEditor.cpp +++ b/Engine/Source/Runtime/Engine/Private/ActorEditor.cpp @@ -231,7 +231,7 @@ void AActor::DebugShowOneComponentHierarchy( USceneComponent* SceneComp, int32& FString PosString; if( bShowPosition ) { - FVector Posn = SceneComp->ComponentToWorld.GetLocation(); + FVector Posn = SceneComp->GetComponentTransform().GetLocation(); //PosString = FString::Printf( TEXT("{R:%f,%f,%f- W:%f,%f,%f}"), SceneComp->RelativeLocation.X, SceneComp->RelativeLocation.Y, SceneComp->RelativeLocation.Z, Posn.X, Posn.Y, Posn.Z ); PosString = FString::Printf( TEXT("{R:%f- W:%f}"), SceneComp->RelativeLocation.Z, Posn.Z ); } @@ -252,7 +252,7 @@ void AActor::DebugShowOneComponentHierarchy( USceneComponent* SceneComp, int32& { if( bShowPosition ) { - FVector Posn = SceneComp->ComponentToWorld.GetLocation(); + FVector Posn = SceneComp->GetComponentTransform().GetLocation(); //PosString = FString::Printf( TEXT("{R:%f,%f,%f- W:%f,%f,%f}"), SceneComp->RelativeLocation.X, SceneComp->RelativeLocation.Y, SceneComp->RelativeLocation.Z, Posn.X, Posn.Y, Posn.Z ); PosString = FString::Printf( TEXT("{R:%f- W:%f}"), SceneComp->RelativeLocation.Z, Posn.Z ); } @@ -287,7 +287,7 @@ AActor::FActorTransactionAnnotation::FActorTransactionAnnotation(const AActor* A if (bCacheRootComponentData && ActorRootComponent && ActorRootComponent->IsCreatedByConstructionScript()) { bRootComponentDataCached = true; - RootComponentData.Transform = ActorRootComponent->ComponentToWorld; + RootComponentData.Transform = ActorRootComponent->GetComponentTransform(); RootComponentData.Transform.SetTranslation(ActorRootComponent->GetComponentLocation()); // take into account any custom location if (ActorRootComponent->GetAttachParent()) diff --git a/Engine/Source/Runtime/Engine/Private/AmbientSound.cpp b/Engine/Source/Runtime/Engine/Private/AmbientSound.cpp index e34a0b78a1d9..2070f4ae5ca6 100644 --- a/Engine/Source/Runtime/Engine/Private/AmbientSound.cpp +++ b/Engine/Source/Runtime/Engine/Private/AmbientSound.cpp @@ -137,5 +137,3 @@ void AAmbientSound::Stop() #undef LOCTEXT_NAMESPACE -/** Returns AudioComponent subobject **/ -UAudioComponent* AAmbientSound::GetAudioComponent() const { return AudioComponent; } diff --git a/Engine/Source/Runtime/Engine/Private/AnimBlueprint.cpp b/Engine/Source/Runtime/Engine/Private/AnimBlueprint.cpp index a9683208c562..cc74dedc05f8 100644 --- a/Engine/Source/Runtime/Engine/Private/AnimBlueprint.cpp +++ b/Engine/Source/Runtime/Engine/Private/AnimBlueprint.cpp @@ -3,7 +3,9 @@ #include "Animation/AnimBlueprint.h" #include "UObject/FrameworkObjectVersion.h" #include "Animation/AnimBlueprintGeneratedClass.h" - +#if WITH_EDITOR +#include "Settings/EditorExperimentalSettings.h" +#endif #if WITH_EDITORONLY_DATA #include "AnimationEditorUtils.h" #endif @@ -200,4 +202,10 @@ void UAnimBlueprint::SetPreviewMesh(USkeletalMesh* PreviewMesh) Modify(); PreviewSkeletalMesh = PreviewMesh; } + +bool UAnimBlueprint::CanRecompileWhilePlayingInEditor() const +{ + return GetDefault()->bEnableLiveRecompilationOfAnimationBlueprints; +} + #endif diff --git a/Engine/Source/Runtime/Engine/Private/Animation/AnimCompressionDerivedData.cpp b/Engine/Source/Runtime/Engine/Private/Animation/AnimCompressionDerivedData.cpp index fa0f4898d9c7..e088f19ef791 100644 --- a/Engine/Source/Runtime/Engine/Private/Animation/AnimCompressionDerivedData.cpp +++ b/Engine/Source/Runtime/Engine/Private/Animation/AnimCompressionDerivedData.cpp @@ -53,9 +53,10 @@ FString FDerivedDataAnimationCompression::GetPluginSpecificCacheKeySuffix() cons char AdditiveType = bCanBakeAdditive ? NibbleToTChar(OriginalAnimSequence->AdditiveAnimType) : '0'; char RefType = bCanBakeAdditive ? NibbleToTChar(OriginalAnimSequence->RefPoseType) : '0'; - FString Ret = FString::Printf(TEXT("%i_%i_%s%s%s_%c%c%i_%s_%s"), + FString Ret = FString::Printf(TEXT("%i_%i_%i_%s%s%s_%c%c%i_%s_%s"), (int32)UE_ANIMCOMPRESSION_DERIVEDDATA_VER, (int32)CURRENT_ANIMATION_ENCODING_PACKAGE_VERSION, + OriginalAnimSequence->CompressCommandletVersion, *OriginalAnimSequence->GetRawDataGuid().ToString(), *OriginalAnimSequence->GetSkeleton()->GetGuid().ToString(), *OriginalAnimSequence->GetSkeleton()->GetVirtualBoneGuid().ToString(), @@ -67,7 +68,6 @@ FString FDerivedDataAnimationCompression::GetPluginSpecificCacheKeySuffix() cons ); return Ret; - } bool FDerivedDataAnimationCompression::Build( TArray& OutData ) diff --git a/Engine/Source/Runtime/Engine/Private/Animation/AnimCompressionDerivedData.h b/Engine/Source/Runtime/Engine/Private/Animation/AnimCompressionDerivedData.h index 64a500f69961..a0ddea8e2fd4 100644 --- a/Engine/Source/Runtime/Engine/Private/Animation/AnimCompressionDerivedData.h +++ b/Engine/Source/Runtime/Engine/Private/Animation/AnimCompressionDerivedData.h @@ -44,7 +44,7 @@ public: // This is a version string that mimics the old versioning scheme. If you // want to bump this version, generate a new guid using VS->Tools->Create GUID and // return it here. Ex. - return TEXT("6EB5AB4335E64810B4A62A202EDEB094"); + return TEXT("2DB548BD65B84466AE8281E3748671C8"); } virtual FString GetPluginSpecificCacheKeySuffix() const override; diff --git a/Engine/Source/Runtime/Engine/Private/Animation/AnimInstance.cpp b/Engine/Source/Runtime/Engine/Private/Animation/AnimInstance.cpp index d6cde766a380..5862176c79bb 100644 --- a/Engine/Source/Runtime/Engine/Private/Animation/AnimInstance.cpp +++ b/Engine/Source/Runtime/Engine/Private/Animation/AnimInstance.cpp @@ -449,19 +449,6 @@ void UAnimInstance::PostUpdateAnimation() ExtractedRootMotion.MakeUpToFullWeight(); } - ///////////////////////////////////////////////////////////////////////////// - // Notify / Event Handling! - // This can do anything to our component (including destroy it) - // Any code added after this point needs to take that into account - ///////////////////////////////////////////////////////////////////////////// - { - // now trigger Notifies - TriggerAnimNotifies(Proxy.GetDeltaSeconds()); - - // Trigger Montage end events after notifies. In case Montage ending ends abilities or other states, we make sure notifies are processed before montage events. - TriggerQueuedMontageEvents(); - } - #if WITH_EDITOR && 0 { // Take a snapshot if the scrub control is locked to the end, we are playing, and we are the one being debugged @@ -482,6 +469,38 @@ void UAnimInstance::PostUpdateAnimation() #endif } +void UAnimInstance::DispatchQueuedAnimEvents() +{ + // now trigger Notifies + TriggerAnimNotifies(GetProxyOnGameThread().GetDeltaSeconds()); + + // Trigger Montage end events after notifies. In case Montage ending ends abilities or other states, we make sure notifies are processed before montage events. + TriggerQueuedMontageEvents(); + + // After queued Montage Events have been dispatched, it's now safe to delete invalid Montage Instances. + // And dispatch 'OnAllMontageInstancesEnded' + for (int32 InstanceIndex = 0; InstanceIndex < MontageInstances.Num(); InstanceIndex++) + { + // Should never be null + FAnimMontageInstance* MontageInstance = MontageInstances[InstanceIndex]; + ensure(MontageInstance); + if (MontageInstance && !MontageInstance->IsValid()) + { + // Make sure we've cleared our references before deleting memory + ClearMontageInstanceReferences(*MontageInstance); + + delete MontageInstance; + MontageInstances.RemoveAt(InstanceIndex); + --InstanceIndex; + + if (MontageInstances.Num() == 0) + { + OnAllMontageInstancesEnded.Broadcast(); + } + } + } +} + void UAnimInstance::ParallelUpdateAnimation() { GetProxyOnAnyThread().UpdateAnimation(); @@ -1154,22 +1173,6 @@ void UAnimInstance::UpdateCurves(const FBlendedHeapCurve& InCurve) AnimationCurves[(uint8)EAnimCurveType::MaterialCurve].Add(ParamsToClearCopy[i], DefaultValue); } - // @todo: delete me later when james g's change goes in - // this won't work well because pose needs to be handled in evaluate - // the question is that if we'd like to support preview in anim graph - // that will need better handling of the curves - currently UI curves are inserted to - // SignleNodeInstance->PreviewOverride -// #if WITH_EDITOR -// // if we're supporting this in-game, this code has to change to work with UID -// for (auto& AddAnimCurveDelegate : OnAddAnimationCurves) -// { -// if (AddAnimCurveDelegate.IsBound()) -// { -// AddAnimCurveDelegate.Execute(this); -// } -// } -// -// #endif // update curves to component UpdateCurvesToComponents(GetOwningComponent()); } @@ -1469,12 +1472,12 @@ void UAnimInstance::Montage_Advance(float DeltaSeconds) // go through all montage instances, and update them // and make sure their weight is updated properly - for (int32 InstanceIndex = 0; InstanceIndexIsValid()) { bool const bUsingBlendedRootMotion = (RootMotionMode == ERootMotionMode::RootMotionFromEverything); bool const bNoRootMotionExtraction = (RootMotionMode == ERootMotionMode::NoRootMotionExtraction); @@ -1495,28 +1498,14 @@ void UAnimInstance::Montage_Advance(float DeltaSeconds) MontageInstance->Advance(DeltaSeconds, RootMotionParams, bUsingBlendedRootMotion); MontageInstance->MontageSync_PostUpdate(); - if (!MontageInstance->IsValid()) - { - // Make sure we've cleared our references before deleting memory - ClearMontageInstanceReferences(*MontageInstance); - - delete MontageInstance; - MontageInstances.RemoveAt(InstanceIndex); - --InstanceIndex; - - if (MontageInstances.Num() == 0) - { - OnAllMontageInstancesEnded.Broadcast(); - } - } #if DO_CHECK && WITH_EDITORONLY_DATA && 0 - else + // We need to re-check IsValid() here because Advance() could have terminated this Montage. + if (MontageInstance.IsValid()) { - FAnimMontageInstance* AnimMontageInstance = MontageInstances(I); // print blending time and weight and montage name - UE_LOG(LogAnimMontage, Warning, TEXT("%d. Montage (%s), DesiredWeight(%0.2f), CurrentWeight(%0.2f), BlendingTime(%0.2f)"), - I+1, *AnimMontageInstance->Montage->GetName(), AnimMontageInstance->GetDesiredWeight(), AnimMontageInstance->GetWeight(), - AnimMontageInstance->GetBlendTime() ); + UE_LOG(LogAnimMontage, Warning, TEXT("%d. Montage (%s), DesiredWeight(%0.2f), CurrentWeight(%0.2f), BlendingTime(%0.2f)"), + I + 1, *MontageInstance->Montage->GetName(), MontageInstance->GetDesiredWeight(), MontageInstance->GetWeight(), + MontageInstance->GetBlendTime()); } #endif } @@ -1623,7 +1612,7 @@ float UAnimInstance::PlaySlotAnimation(UAnimSequenceBase* Asset, FName SlotNodeN USkeleton* AssetSkeleton = Asset->GetSkeleton(); if (!CurrentSkeleton->IsCompatible(AssetSkeleton)) { - UE_LOG(LogAnimMontage, Warning, TEXT("The Skeleton isn't compatible")); + UE_LOG(LogAnimMontage, Warning, TEXT("The Skeleton '%s' isn't compatible with '%s' in AnimSequence '%s'!"), *GetPathNameSafe(AssetSkeleton), *GetPathNameSafe(CurrentSkeleton), *Asset->GetName()); return 0.f; } @@ -1684,7 +1673,7 @@ UAnimMontage* UAnimInstance::PlaySlotAnimationAsDynamicMontage(UAnimSequenceBase USkeleton* AssetSkeleton = Asset->GetSkeleton(); if (!CurrentSkeleton->IsCompatible(AssetSkeleton)) { - UE_LOG(LogAnimMontage, Warning, TEXT("The Skeleton isn't compatible")); + UE_LOG(LogAnimMontage, Warning, TEXT("The Skeleton '%s' isn't compatible with '%s' in AnimSequence '%s'!"), *GetPathNameSafe(AssetSkeleton), *GetPathNameSafe(CurrentSkeleton), *Asset->GetName()); return nullptr; } @@ -2749,28 +2738,4 @@ void UAnimInstance::QueueRootMotionBlend(const FTransform& RootTransform, const RootMotionBlendQueue.Add(FQueuedRootMotionBlend(RootTransform, SlotName, Weight)); } -#if WITH_EDITOR -void UAnimInstance::AddDelegate_AddCustomAnimationCurve(FOnAddCustomAnimationCurves& InOnAddCustomAnimationCurves) -{ - if (InOnAddCustomAnimationCurves.IsBound()) - { - OnAddAnimationCurves.Add(InOnAddCustomAnimationCurves); - } -} - -void UAnimInstance::RemoveDelegate_AddCustomAnimationCurve(FOnAddCustomAnimationCurves& InOnAddCustomAnimationCurves) -{ - for (int32 DelegateId = 0; DelegateId < OnAddAnimationCurves.Num(); ++DelegateId) - { - if (InOnAddCustomAnimationCurves.GetHandle() == OnAddAnimationCurves[DelegateId].GetHandle()) - { - InOnAddCustomAnimationCurves.Unbind(); - OnAddAnimationCurves.RemoveAt(DelegateId); - break; - } - } -} - -#endif // WITH_EDITOR - #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Runtime/Engine/Private/Animation/AnimInstanceProxy.cpp b/Engine/Source/Runtime/Engine/Private/Animation/AnimInstanceProxy.cpp index 58a0bfda5f43..8b3281739ec5 100644 --- a/Engine/Source/Runtime/Engine/Private/Animation/AnimInstanceProxy.cpp +++ b/Engine/Source/Runtime/Engine/Private/Animation/AnimInstanceProxy.cpp @@ -226,7 +226,7 @@ void FAnimInstanceProxy::PreUpdate(UAnimInstance* InAnimInstance, float DeltaSec LODLevel = SkelMeshComp->PredictedLODLevel; // Cache these transforms, so nodes don't have to pull it off the gamethread manually. - SkelMeshCompLocalToWorld = SkelMeshComp->ComponentToWorld; + SkelMeshCompLocalToWorld = SkelMeshComp->GetComponentTransform(); if (const AActor* Owner = SkelMeshComp->GetOwner()) { SkelMeshCompOwnerTransform = Owner->GetTransform(); @@ -261,7 +261,7 @@ void FAnimInstanceProxy::PreUpdate(UAnimInstance* InAnimInstance, float DeltaSec bIsBeingDebugged = false; if (UAnimBlueprint* AnimBlueprint = GetAnimBlueprint()) { - bIsBeingDebugged = (InAnimInstance && (AnimBlueprint->GetObjectBeingDebugged() == InAnimInstance)); + bIsBeingDebugged = (AnimBlueprint->GetObjectBeingDebugged() == InAnimInstance); if(bIsBeingDebugged) { UAnimBlueprintGeneratedClass* AnimBlueprintGeneratedClass = Cast(InAnimInstance->GetClass()); diff --git a/Engine/Source/Runtime/Engine/Private/Animation/AnimMontage.cpp b/Engine/Source/Runtime/Engine/Private/Animation/AnimMontage.cpp index 11cc3d1a4dae..fc499cd5d70a 100644 --- a/Engine/Source/Runtime/Engine/Private/Animation/AnimMontage.cpp +++ b/Engine/Source/Runtime/Engine/Private/Animation/AnimMontage.cpp @@ -1235,6 +1235,7 @@ FAnimMontageInstance::FAnimMontageInstance() , PlayRate(1.f) , bInterrupted(false) , PreviousWeight(0.f) + , NotifyWeight(0.f) , DeltaMoved(0.f) , PreviousPosition(0.f) , SyncGroupIndex(INDEX_NONE) @@ -1288,8 +1289,11 @@ void FAnimMontageInstance::InitializeBlend(const FAlphaBlend& InAlphaBlend) void FAnimMontageInstance::Stop(const FAlphaBlend& InBlendOut, bool bInterrupt) { - UE_LOG(LogAnimMontage, Verbose, TEXT("Montage.Stop Before: AnimMontage: %s, (DesiredWeight:%0.2f, Weight:%0.2f)"), + if (Montage) + { + UE_LOG(LogAnimMontage, Verbose, TEXT("Montage.Stop Before: AnimMontage: %s, (DesiredWeight:%0.2f, Weight:%0.2f)"), *Montage->GetName(), GetDesiredWeight(), GetWeight()); + } // overwrite bInterrupted if it hasn't already interrupted // once interrupted, you don't go back to non-interrupted @@ -1342,8 +1346,11 @@ void FAnimMontageInstance::Stop(const FAlphaBlend& InBlendOut, bool bInterrupt) bPlaying = false; } - UE_LOG(LogAnimMontage, Verbose, TEXT("Montage.Stop After: AnimMontage: %s, (DesiredWeight:%0.2f, Weight:%0.2f)"), + if (Montage != nullptr) + { + UE_LOG(LogAnimMontage, Verbose, TEXT("Montage.Stop After: AnimMontage: %s, (DesiredWeight:%0.2f, Weight:%0.2f)"), *Montage->GetName(), GetDesiredWeight(), GetWeight()); + } } void FAnimMontageInstance::Pause() diff --git a/Engine/Source/Runtime/Engine/Private/Animation/AnimNodeBase.cpp b/Engine/Source/Runtime/Engine/Private/Animation/AnimNodeBase.cpp index 9161d040b711..0adf86f2c80e 100644 --- a/Engine/Source/Runtime/Engine/Private/Animation/AnimNodeBase.cpp +++ b/Engine/Source/Runtime/Engine/Private/Animation/AnimNodeBase.cpp @@ -450,14 +450,14 @@ void FExposedValueHandler::Initialize(FAnimNode_Base* AnimNode, UObject* AnimIns UProperty* SourceStructSubProperty = SourceStructProperty->Struct->FindPropertyByName(CopyRecord.SourceSubPropertyName); CopyRecord.Source = SourceStructSubProperty->ContainerPtrToValuePtr(Source, CopyRecord.SourceArrayIndex); CopyRecord.Size = SourceStructSubProperty->GetSize(); - CopyRecord.CachedBoolSourceProperty = Cast(SourceStructSubProperty); + CopyRecord.CachedSourceProperty = SourceStructSubProperty; CopyRecord.CachedSourceContainer = Source; } else { CopyRecord.Source = SourceProperty->ContainerPtrToValuePtr(AnimInstanceObject, CopyRecord.SourceArrayIndex); CopyRecord.Size = SourceProperty->GetSize(); - CopyRecord.CachedBoolSourceProperty = Cast(SourceProperty); + CopyRecord.CachedSourceProperty = SourceProperty; CopyRecord.CachedSourceContainer = AnimInstanceObject; } } @@ -467,7 +467,6 @@ void FExposedValueHandler::Initialize(FAnimNode_Base* AnimNode, UObject* AnimIns FScriptArrayHelper ArrayHelper(DestArrayProperty, CopyRecord.DestProperty->ContainerPtrToValuePtr(AnimNode)); check(ArrayHelper.IsValidIndex(CopyRecord.DestArrayIndex)); CopyRecord.Dest = ArrayHelper.GetRawPtr(CopyRecord.DestArrayIndex); - CopyRecord.CachedBoolDestProperty = Cast(CopyRecord.DestProperty); if(CopyRecord.bInstanceIsTarget) { @@ -491,9 +490,23 @@ void FExposedValueHandler::Initialize(FAnimNode_Base* AnimNode, UObject* AnimIns { CopyRecord.CachedDestContainer = AnimNode; } + } - CopyRecord.CachedBoolDestProperty = Cast(CopyRecord.DestProperty); - CopyRecord.CachedStructDestProperty = Cast(CopyRecord.DestProperty); + if(UBoolProperty* BoolProperty = Cast(CopyRecord.DestProperty)) + { + CopyRecord.CopyType = ECopyType::BoolProperty; + } + else if(UStructProperty* StructProperty = Cast(CopyRecord.DestProperty)) + { + CopyRecord.CopyType = ECopyType::StructProperty; + } + else if(UObjectPropertyBase* ObjectProperty = Cast(CopyRecord.DestProperty)) + { + CopyRecord.CopyType = ECopyType::ObjectProperty; + } + else + { + CopyRecord.CopyType = ECopyType::MemCopy; } } @@ -519,27 +532,36 @@ void FExposedValueHandler::Execute(const FAnimationBaseContext& Context) const { case EPostCopyOperation::None: { - if (CopyRecord.CachedBoolSourceProperty != nullptr && CopyRecord.CachedBoolDestProperty != nullptr) - { - bool bValue = CopyRecord.CachedBoolSourceProperty->GetPropertyValue_InContainer(CopyRecord.CachedSourceContainer); - CopyRecord.CachedBoolDestProperty->SetPropertyValue_InContainer(CopyRecord.CachedDestContainer, bValue, CopyRecord.DestArrayIndex); - } - else if(CopyRecord.CachedStructDestProperty != nullptr) - { - CopyRecord.CachedStructDestProperty->Struct->CopyScriptStruct(CopyRecord.Dest, CopyRecord.Source); - } - else + switch(CopyRecord.CopyType) { + default: + case ECopyType::MemCopy: FMemory::Memcpy(CopyRecord.Dest, CopyRecord.Source, CopyRecord.Size); + break; + case ECopyType::BoolProperty: + { + bool bValue = static_cast(CopyRecord.CachedSourceProperty)->GetPropertyValue_InContainer(CopyRecord.CachedSourceContainer); + static_cast(CopyRecord.DestProperty)->SetPropertyValue_InContainer(CopyRecord.CachedDestContainer, bValue, CopyRecord.DestArrayIndex); + } + break; + case ECopyType::StructProperty: + static_cast(CopyRecord.DestProperty)->Struct->CopyScriptStruct(CopyRecord.Dest, CopyRecord.Source); + break; + case ECopyType::ObjectProperty: + { + UObject* Value = static_cast(CopyRecord.CachedSourceProperty)->GetObjectPropertyValue_InContainer(CopyRecord.CachedSourceContainer); + static_cast(CopyRecord.DestProperty)->SetObjectPropertyValue_InContainer(CopyRecord.CachedDestContainer, Value, CopyRecord.DestArrayIndex); + } + break; } } break; case EPostCopyOperation::LogicalNegateBool: { - check(CopyRecord.CachedBoolSourceProperty != nullptr && CopyRecord.CachedBoolDestProperty != nullptr); + check(CopyRecord.CachedSourceProperty != nullptr && CopyRecord.DestProperty != nullptr); - bool bValue = CopyRecord.CachedBoolSourceProperty->GetPropertyValue_InContainer(CopyRecord.CachedSourceContainer); - CopyRecord.CachedBoolDestProperty->SetPropertyValue_InContainer(CopyRecord.CachedDestContainer, !bValue, CopyRecord.DestArrayIndex); + bool bValue = static_cast(CopyRecord.CachedSourceProperty)->GetPropertyValue_InContainer(CopyRecord.CachedSourceContainer); + static_cast(CopyRecord.DestProperty)->SetPropertyValue_InContainer(CopyRecord.CachedDestContainer, !bValue, CopyRecord.DestArrayIndex); } break; } diff --git a/Engine/Source/Runtime/Engine/Private/Animation/AnimNode_StateMachine.cpp b/Engine/Source/Runtime/Engine/Private/Animation/AnimNode_StateMachine.cpp index b0f35f062870..5e2f00dae8bf 100644 --- a/Engine/Source/Runtime/Engine/Private/Animation/AnimNode_StateMachine.cpp +++ b/Engine/Source/Runtime/Engine/Private/Animation/AnimNode_StateMachine.cpp @@ -431,7 +431,7 @@ void FAnimNode_StateMachine::Update(const FAnimationUpdateContext& Context) } // Push the transition onto the stack - const FAnimationTransitionBetweenStates& ReferenceTransition = GetTransitionInfo(PotentialTransition.TransitionRule->TransitionIndex); + const FAnimationTransitionBetweenStates& ReferenceTransition = GetTransitionInfo(PotentialTransition.TransitionRule->TransitionIndex); //-V595 FAnimationActiveTransitionEntry* NewTransition = new (ActiveTransitionArray) FAnimationActiveTransitionEntry(NextState, ExistingWeightOfNextState, PreviousTransitionForNextState, PreviousState, ReferenceTransition); if (NewTransition && PotentialTransition.TransitionRule) { diff --git a/Engine/Source/Runtime/Engine/Private/Animation/AnimNotify.cpp b/Engine/Source/Runtime/Engine/Private/Animation/AnimNotify.cpp index 72ed5e2e68fe..dc290dffcab9 100644 --- a/Engine/Source/Runtime/Engine/Private/Animation/AnimNotify.cpp +++ b/Engine/Source/Runtime/Engine/Private/Animation/AnimNotify.cpp @@ -36,6 +36,8 @@ class UWorld* UAnimNotify::GetWorld() const return (MeshContext ? MeshContext->GetWorld() : NULL); } +/// @cond DOXYGEN_WARNINGS + FString UAnimNotify::GetNotifyName_Implementation() const { UObject* ClassGeneratedBy = GetClass()->ClassGeneratedBy; @@ -57,6 +59,8 @@ FString UAnimNotify::GetNotifyName_Implementation() const return NotifyName; } +/// @endcond + void UAnimNotify::PostLoad() { Super::PostLoad(); diff --git a/Engine/Source/Runtime/Engine/Private/Animation/AnimNotifyState.cpp b/Engine/Source/Runtime/Engine/Private/Animation/AnimNotifyState.cpp index 448d8b426d7b..7bf00ce0b3fb 100644 --- a/Engine/Source/Runtime/Engine/Private/Animation/AnimNotifyState.cpp +++ b/Engine/Source/Runtime/Engine/Private/Animation/AnimNotifyState.cpp @@ -49,6 +49,8 @@ void UAnimNotifyState::BranchingPointNotifyEnd(FBranchingPointNotifyPayload& Bra NotifyEnd(BranchingPointPayload.SkelMeshComponent, BranchingPointPayload.SequenceAsset); } +/// @cond DOXYGEN_WARNINGS + FString UAnimNotifyState::GetNotifyName_Implementation() const { UObject* ClassGeneratedBy = GetClass()->ClassGeneratedBy; @@ -70,6 +72,8 @@ FString UAnimNotifyState::GetNotifyName_Implementation() const return NotifyName; } +/// @endcond + void UAnimNotifyState::PostLoad() { Super::PostLoad(); diff --git a/Engine/Source/Runtime/Engine/Private/Animation/AnimNotify_PlayParticleEffect.cpp b/Engine/Source/Runtime/Engine/Private/Animation/AnimNotify_PlayParticleEffect.cpp index 974ced75d811..0cf20558f9a5 100644 --- a/Engine/Source/Runtime/Engine/Private/Animation/AnimNotify_PlayParticleEffect.cpp +++ b/Engine/Source/Runtime/Engine/Private/Animation/AnimNotify_PlayParticleEffect.cpp @@ -46,7 +46,7 @@ void UAnimNotify_PlayParticleEffect::Notify(class USkeletalMeshComponent* MeshCo { if (PSTemplate->IsImmortal()) { - UE_LOG(LogParticles, Warning, TEXT("Particle Notify: Anim %s tried to spawn infinitely looping particle system %s. Spawning suppressed."), *GetNameSafe(Animation), *GetNameSafe(PSTemplate)); + UE_LOG(LogParticles, Warning, TEXT("Particle Notify: Anim '%s' tried to spawn infinitely looping particle system '%s'. Spawning suppressed."), *GetNameSafe(Animation), *GetNameSafe(PSTemplate)); return; } @@ -65,7 +65,7 @@ void UAnimNotify_PlayParticleEffect::Notify(class USkeletalMeshComponent* MeshCo } else { - UE_LOG(LogParticles, Warning, TEXT("Particle Notify: Null PSTemplate for particle notify in anim: %s"), *GetNameSafe(Animation)); + UE_LOG(LogParticles, Warning, TEXT("Particle Notify: Particle system is null for particle notify '%s' in anim: '%s'"), *GetNotifyName(), *GetPathNameSafe(Animation)); } } diff --git a/Engine/Source/Runtime/Engine/Private/Animation/AnimPhysicsSolver.cpp b/Engine/Source/Runtime/Engine/Private/Animation/AnimPhysicsSolver.cpp index 3b50c8f11991..836c092c1378 100644 --- a/Engine/Source/Runtime/Engine/Private/Animation/AnimPhysicsSolver.cpp +++ b/Engine/Source/Runtime/Engine/Private/Animation/AnimPhysicsSolver.cpp @@ -1028,7 +1028,7 @@ void FAnimPhysSpring::ApplyForces(float DeltaTime) Body1AngularAxis = Body1->GetPose().Orientation.GetAxisY(); break; case AnimPhysTwistAxis::AxisZ: - Body1AngularAxis = Body1->GetPose().Orientation.GetAxisZ(); + Body1AngularAxis = Body1->GetPose().Orientation.GetAxisZ(); //-V595 break; default: checkf(false, TEXT("Invalid target axis option")); diff --git a/Engine/Source/Runtime/Engine/Private/Animation/AnimSequence.cpp b/Engine/Source/Runtime/Engine/Private/Animation/AnimSequence.cpp index b4c8b7739dc0..60794f978a61 100644 --- a/Engine/Source/Runtime/Engine/Private/Animation/AnimSequence.cpp +++ b/Engine/Source/Runtime/Engine/Private/Animation/AnimSequence.cpp @@ -566,18 +566,18 @@ void UAnimSequence::PostLoad() #if WITH_EDITOR void ShowResaveMessage(const UAnimSequence* Sequence) { - if (!IsRunningGame()) + if (IsRunningCommandlet()) { - UE_LOG(LogAnimation, Warning, TEXT("Resave Animation Required(%s, %s): Fixing track data and recompressing."), *GetNameSafe(Sequence), *Sequence->GetPathName()); + UE_LOG(LogAnimation, Log, TEXT("Resave Animation Required(%s, %s): Fixing track data and recompressing."), *GetNameSafe(Sequence), *Sequence->GetPathName()); - static FName NAME_LoadErrors("LoadErrors"); + /*static FName NAME_LoadErrors("LoadErrors"); FMessageLog LoadErrors(NAME_LoadErrors); TSharedRef Message = LoadErrors.Warning(); Message->AddToken(FTextToken::Create(LOCTEXT("AnimationNeedsResave1", "The Animation "))); Message->AddToken(FAssetNameToken::Create(Sequence->GetPathName(), FText::FromString(GetNameSafe(Sequence)))); Message->AddToken(FTextToken::Create(LOCTEXT("AnimationNeedsResave2", " needs resave."))); - LoadErrors.Notify(); + LoadErrors.Notify();*/ } } @@ -4758,7 +4758,7 @@ void AdvanceMarkerBackwards(int32& Marker, FName MarkerToFind, bool bLooping, co { break; } - Counter = ++Counter % MarkerMax; + Counter = (Counter + 1) % MarkerMax; Marker = MarkerCounterSpaceTransform(MarkerMax, Counter); } diff --git a/Engine/Source/Runtime/Engine/Private/Animation/AnimSingleNodeInstance.cpp b/Engine/Source/Runtime/Engine/Private/Animation/AnimSingleNodeInstance.cpp index 5649b3824742..0f93a93203d4 100644 --- a/Engine/Source/Runtime/Engine/Private/Animation/AnimSingleNodeInstance.cpp +++ b/Engine/Source/Runtime/Engine/Private/Animation/AnimSingleNodeInstance.cpp @@ -48,12 +48,16 @@ void UAnimSingleNodeInstance::SetAnimationAsset(class UAnimationAsset* NewAsset, else if (CurrentAsset != nullptr) { // if we have an asset, make sure their skeleton matches, otherwise, null it - if (MeshComponent->SkeletalMesh == nullptr || MeshComponent->SkeletalMesh->Skeleton != CurrentAsset->GetSkeleton()) + if (MeshComponent->SkeletalMesh->Skeleton != CurrentAsset->GetSkeleton()) { // clear asset since we do not have matching skeleton CurrentAsset = nullptr; } } + + // We've changed the animation asset, and the next frame could be wildly different from the frame we're + // on now. In this case of a single node instance, we reset the clothing on the next update. + MeshComponent->ClothTeleportMode = EClothingTeleportMode::TeleportAndReset; } Proxy.SetAnimationAsset(NewAsset, GetSkelMeshComponent(), bInIsLooping, InPlayRate); diff --git a/Engine/Source/Runtime/Engine/Private/Animation/AnimationRuntime.cpp b/Engine/Source/Runtime/Engine/Private/Animation/AnimationRuntime.cpp index 18cc28f40e59..02e027add221 100644 --- a/Engine/Source/Runtime/Engine/Private/Animation/AnimationRuntime.cpp +++ b/Engine/Source/Runtime/Engine/Private/Animation/AnimationRuntime.cpp @@ -945,7 +945,21 @@ void FAnimationRuntime::BlendMeshPosesPerBoneWeights( /*out*/ FCompactPose& OutPose, /*out*/ struct FBlendedCurve& OutCurve) { - check(BasePose.GetNumBones() == BoneBlendWeights.Num()); + const int32 NumBones = BasePose.GetNumBones(); + check(BoneBlendWeights.Num() == NumBones); + check(OutPose.GetNumBones() == NumBones); + + const int32 NumPoses = BlendPoses.Num(); + for (const FPerBoneBlendWeight& PerBoneBlendWeight : BoneBlendWeights) + { + check(PerBoneBlendWeight.SourceIndex >= 0); + check(PerBoneBlendWeight.SourceIndex < NumPoses); + } + + for (const FCompactPose& BlendPose : BlendPoses) + { + check(BlendPose.GetNumBones() == NumBones); + } const FBoneContainer& BoneContainer = BasePose.GetBoneContainer(); @@ -953,16 +967,14 @@ void FAnimationRuntime::BlendMeshPosesPerBoneWeights( TCustomBoneIndexArray BlendRotations; TCustomBoneIndexArray TargetRotations; - SourceRotations.AddUninitialized(BasePose.GetNumBones()); - BlendRotations.AddUninitialized(BasePose.GetNumBones()); - TargetRotations.AddUninitialized(BasePose.GetNumBones()); - - int32 PoseNum = BlendPoses.Num(); + SourceRotations.AddUninitialized(NumBones); + BlendRotations.AddUninitialized(NumBones); + TargetRotations.AddUninitialized(NumBones); TArray MaxPoseWeights; - MaxPoseWeights.AddZeroed(PoseNum); + MaxPoseWeights.AddZeroed(NumPoses); - for (FCompactPoseBoneIndex BoneIndex : BasePose.ForEachBoneIndex()) + for (const FCompactPoseBoneIndex BoneIndex : BasePose.ForEachBoneIndex()) { const int32 PoseIndex = BoneBlendWeights[BoneIndex.GetInt()].SourceIndex; const FCompactPoseBoneIndex ParentIndex = BoneContainer.GetParentBoneIndex(BoneIndex); @@ -1033,13 +1045,13 @@ void FAnimationRuntime::BlendMeshPosesPerBoneWeights( TArray SourceCurves; TArray SourceWegihts; - SourceCurves.SetNumUninitialized(PoseNum+1); - SourceWegihts.SetNumUninitialized(PoseNum+1); + SourceCurves.SetNumUninitialized(NumPoses+1); + SourceWegihts.SetNumUninitialized(NumPoses +1); SourceCurves[0] = &BaseCurve; SourceWegihts[0] = 1.f; - for(int32 Idx=0; Idx= 0); + check(PerBoneBlendWeight.SourceIndex < NumPoses); + } + + for (const FCompactPose& BlendPose : BlendPoses) + { + check(BlendPose.GetNumBones() == NumBones); + } TArray MaxPoseWeights; - MaxPoseWeights.AddZeroed(PoseNum); + MaxPoseWeights.AddZeroed(NumPoses); for (FCompactPoseBoneIndex BoneIndex : BasePose.ForEachBoneIndex()) { @@ -1097,13 +1122,13 @@ void FAnimationRuntime::BlendLocalPosesPerBoneWeights( TArray SourceCurves; TArray SourceWegihts; - SourceCurves.SetNumUninitialized(PoseNum+1); - SourceWegihts.SetNumUninitialized(PoseNum+1); + SourceCurves.SetNumUninitialized(NumPoses +1); + SourceWegihts.SetNumUninitialized(NumPoses +1); SourceCurves[0] = &BaseCurve; SourceWegihts[0] = 1.f; - for (int32 Idx=0; Idx ZERO_ANIMWEIGHT_THRESH) + if (FAnimWeight::IsRelevant(TargetBlendWeight)) { TargetBoneBlendWeights[BoneIndex].SourceIndex = PoseIndex; TargetBoneBlendWeights[BoneIndex].BlendWeight = TargetBlendWeight; @@ -1171,9 +1198,9 @@ void FAnimationRuntime::CreateMaskWeights(TArray& BoneBlend { const FReferenceSkeleton& RefSkeleton = Skeleton->GetReferenceSkeleton(); - const int32 TotalNum = RefSkeleton.GetNum(); - BoneBlendWeights.Reset(TotalNum); - BoneBlendWeights.AddZeroed(TotalNum); + const int32 NumBones = RefSkeleton.GetNum(); + BoneBlendWeights.Reset(NumBones); + BoneBlendWeights.AddZeroed(NumBones); // base mask bone for (int32 PoseIndex=0; PoseIndex& BoneBlend for (int32 BranchIndex=0; BranchIndex(BoneBlendWeight.BlendWeight + BlendIncrease, 0.f, 1.f); + // go through skeleton bone hierarchy. + // Bones are ordered, parents before children. So we can start looking at MaskBoneIndex for children. + for (int32 BoneIndex = MaskBoneIndex; BoneIndex < NumBones; ++BoneIndex) + { + // if Depth == -1, it's not a child + const int32 Depth = RefSkeleton.GetDepthBetweenBones(BoneIndex, MaskBoneIndex); + if (Depth != -1) + { + // when you write to buffer, you'll need to match with BasePoses BoneIndex + FPerBoneBlendWeight& BoneBlendWeight = BoneBlendWeights[BoneIndex]; + + BoneBlendWeight.SourceIndex = PoseIndex; + const float BlendIncrease = IncreaseWeightPerDepth * (float)(Depth + 1); + BoneBlendWeight.BlendWeight = FMath::Clamp(BoneBlendWeight.BlendWeight + BlendIncrease, 0.f, 1.f); + } } } } diff --git a/Engine/Source/Runtime/Engine/Private/Animation/AnimationUtils.cpp b/Engine/Source/Runtime/Engine/Private/Animation/AnimationUtils.cpp index d2a976adac1c..61f89933ca85 100644 --- a/Engine/Source/Runtime/Engine/Private/Animation/AnimationUtils.cpp +++ b/Engine/Source/Runtime/Engine/Private/Animation/AnimationUtils.cpp @@ -441,13 +441,14 @@ bool FAnimationUtils::GetForcedRecompressionSetting() #define TRYCOMPRESSION_INNER(compressionname,winningcompressor_count,winningcompressor_error,winningcompressor_margin,compressionalgorithm) \ { \ /* try the alternative compressor */ \ - (compressionalgorithm)->Reduce( AnimSeq, CompressContext ); \ + AnimSeq->CompressionScheme = (compressionalgorithm); \ + (compressionalgorithm)->Reduce(AnimSeq, CompressContext); \ AnimSeq->SetUseRawDataOnly(false); \ const SIZE_T NewSize = AnimSeq->GetResourceSizeBytes(EResourceSizeMode::Inclusive); \ \ /* compute the savings and compression error*/ \ - const SIZE_T MemorySavingsFromOriginal = OriginalSize - NewSize; \ - const SIZE_T MemorySavingsFromPrevious = CurrentSize - NewSize; \ + const int32 MemorySavingsFromOriginal = OriginalSize - NewSize; \ + const int32 MemorySavingsFromPrevious = CurrentSize - NewSize; \ PctSaving = 0.f; \ /* figure out our new compression error*/ \ FAnimationUtils::ComputeCompressionError(AnimSeq, BoneData, NewErrorStats); \ @@ -457,14 +458,27 @@ bool FAnimationUtils::GetForcedRecompressionSetting() \ /* keep it if it we want to force the error below the threshold and it reduces error */ \ bKeepNewCompressionMethod = false; \ - bKeepNewCompressionMethod |= (bLowersError && (WinningCompressorError > MasterTolerance) && bForceBelowThreshold); \ + const bool bReducesErrorBelowThreshold = (bLowersError && (WinningCompressorError > MasterTolerance) && bForceBelowThreshold); \ + bKeepNewCompressionMethod |= bReducesErrorBelowThreshold; \ /* or if has an acceptable error and saves space */ \ - bKeepNewCompressionMethod |= bErrorUnderThreshold && (MemorySavingsFromPrevious > 0); \ + const bool bHasAcceptableErrorAndSavesSpace = bErrorUnderThreshold && (MemorySavingsFromPrevious > 0); \ + bKeepNewCompressionMethod |= bHasAcceptableErrorAndSavesSpace; \ /* or if saves the same amount and an acceptable error that is lower than the previous best */ \ - bKeepNewCompressionMethod |= bErrorUnderThreshold && bLowersError && (MemorySavingsFromPrevious >= 0); \ + const bool bLowersErrorAndSavesSameOrBetter = bErrorUnderThreshold && bLowersError && (MemorySavingsFromPrevious >= 0); \ + bKeepNewCompressionMethod |= bLowersErrorAndSavesSameOrBetter; \ + \ + PctSaving = (OriginalSize > 0) ? (100.f - (100.f * float(NewSize) / float(OriginalSize))) : 0.f; \ + UE_LOG(LogAnimation, Verbose, TEXT("- %s - bytes saved(%i) (%.1f%%) from previous(%i) MaxError(%.2f) bLowersError(%d) %s"), \ + compressionname, MemorySavingsFromOriginal, PctSaving, MemorySavingsFromPrevious, NewErrorStats.MaxError, bLowersError, bKeepNewCompressionMethod ? TEXT("(**Best so far**)") : TEXT("")); \ + \ + UE_LOG(LogAnimation, Verbose, TEXT(" bReducesErrorBelowThreshold(%d) bHasAcceptableErrorAndSavesSpace(%d) bLowersErrorAndSavesSameOrBetter(%d)"), \ + bReducesErrorBelowThreshold, bHasAcceptableErrorAndSavesSpace, bLowersErrorAndSavesSameOrBetter); \ + \ + UE_LOG(LogAnimation, Verbose, TEXT(" WinningCompressorError(%f) MasterTolerance(%f) bForceBelowThreshold(%d) bErrorUnderThreshold(%d)"), \ + WinningCompressorError, MasterTolerance, bForceBelowThreshold, bErrorUnderThreshold); \ \ if (bKeepNewCompressionMethod) \ - { \ + { \ WinningCompressorMarginalSavings = MemorySavingsFromPrevious; \ WinningCompressorCounter = &(winningcompressor_count); \ WinningCompressorErrorSum = &(winningcompressor_error); \ @@ -473,13 +487,21 @@ bool FAnimationUtils::GetForcedRecompressionSetting() CurrentSize = NewSize; \ WinningCompressorSavings = MemorySavingsFromOriginal; \ WinningCompressorError = NewErrorStats.MaxError; \ - } \ \ - PctSaving = OriginalSize > 0 ? 100.f - (100.f * float(NewSize) / float(OriginalSize)) : 0.f; \ - UE_LOG(LogAnimation, Warning, TEXT("- %s - bytes saved: %i (%3.1f%% saved), maxdiff: %f %s"), \ - compressionname, MemorySavingsFromOriginal, PctSaving, NewErrorStats.MaxError, bKeepNewCompressionMethod ? TEXT("(**Best so far**)") : TEXT("")); \ - \ - if( !bKeepNewCompressionMethod ) \ + /* backup key information from the sequence */ \ + SavedCompressionScheme = AnimSeq->CompressionScheme; \ + SavedTranslationCompressionFormat = AnimSeq->TranslationCompressionFormat; \ + SavedRotationCompressionFormat = AnimSeq->RotationCompressionFormat; \ + SavedKeyEncodingFormat = AnimSeq->KeyEncodingFormat; \ + SavedCompressedTrackOffsets = AnimSeq->CompressedTrackOffsets; \ + SavedCompressedScaleOffsets = AnimSeq->CompressedScaleOffsets; \ + SavedCompressedByteStream = AnimSeq->CompressedByteStream; \ + SavedTranslationCodec = AnimSeq->TranslationCodec; \ + SavedRotationCodec = AnimSeq->RotationCodec; \ + SavedScaleCodec = AnimSeq->ScaleCodec; \ + bSavedUseRawDataOnly = false; \ + } \ + else \ { \ /* revert back to the old method by copying back the data we cached */ \ AnimSeq->CompressionScheme = SavedCompressionScheme; \ @@ -498,21 +520,6 @@ bool FAnimationUtils::GetForcedRecompressionSetting() const SIZE_T RestoredSize = AnimSeq->GetResourceSizeBytes(EResourceSizeMode::Inclusive); \ check(RestoredSize == CurrentSize); \ } \ - else \ - { \ - /* backup key information from the sequence */ \ - SavedCompressionScheme = AnimSeq->CompressionScheme; \ - SavedTranslationCompressionFormat = AnimSeq->TranslationCompressionFormat; \ - SavedRotationCompressionFormat = AnimSeq->RotationCompressionFormat; \ - SavedKeyEncodingFormat = AnimSeq->KeyEncodingFormat; \ - SavedCompressedTrackOffsets = AnimSeq->CompressedTrackOffsets; \ - SavedCompressedScaleOffsets = AnimSeq->CompressedScaleOffsets; \ - SavedCompressedByteStream = AnimSeq->CompressedByteStream; \ - SavedTranslationCodec = AnimSeq->TranslationCodec; \ - SavedRotationCodec = AnimSeq->RotationCodec; \ - SavedScaleCodec = AnimSeq->ScaleCodec; \ - bSavedUseRawDataOnly = false; \ - } \ } #endif @@ -526,9 +533,6 @@ bool FAnimationUtils::GetForcedRecompressionSetting() static float Algorithm ## CompressorSumError = 0.0f; \ static int32 Algorithm ## CompressorWinMargin = 0 -/** Control animation recompression upon load. */ -bool GDisableAnimationRecompression = false; - /** * Utility function to compress an animation. If the animation is currently associated with a codec, it will be used to * compress the animation. Otherwise, the default codec will be used. If AllowAlternateCompressor is true, an @@ -616,11 +620,6 @@ void FAnimationUtils::CompressAnimSequenceExplicit( const bool bTryIntervalKeyRemoval) { #if WITH_EDITORONLY_DATA - if( GDisableAnimationRecompression ) - { - return; - } - DECLARE_ANIM_COMP_ALGORITHM(BitwiseACF_Float96); DECLARE_ANIM_COMP_ALGORITHM(BitwiseACF_Fixed48); DECLARE_ANIM_COMP_ALGORITHM(BitwiseACF_IntervalFixed32); @@ -692,11 +691,11 @@ void FAnimationUtils::CompressAnimSequenceExplicit( bool const bTryAlternateCompressor = MasterTolerance > 0.0f; // Get the current size - int32 OriginalSize = AnimSeq->GetResourceSizeBytes(EResourceSizeMode::Inclusive); + SIZE_T OriginalSize = AnimSeq->GetResourceSizeBytes(EResourceSizeMode::Inclusive); TotalSizeBefore += OriginalSize; // Estimate total uncompressed - TotalUncompressed += ((sizeof(FVector) + sizeof(FQuat)) * NumRawDataTracks * AnimSeq->NumFrames); + TotalUncompressed += ((sizeof(FVector) + sizeof(FQuat) + sizeof(FVector)) * NumRawDataTracks * AnimSeq->NumFrames); // Filter RAW data to get rid of mismatched tracks (translation/rotation data with a different number of keys than there are frames) // No trivial key removal is done at this point (impossible error metrics of -1), since all of the techniques will perform it themselves @@ -721,7 +720,8 @@ void FAnimationUtils::CompressAnimSequenceExplicit( { UAnimCompress* OriginalCompressionAlgorithm = AnimSeq->CompressionScheme ? AnimSeq->CompressionScheme : FAnimationUtils::GetDefaultAnimationCompressionAlgorithm(); - OriginalCompressionAlgorithm->Reduce( AnimSeq, CompressContext ); + AnimSeq->CompressionScheme = OriginalCompressionAlgorithm; + OriginalCompressionAlgorithm->Reduce(AnimSeq, CompressContext); AnimSeq->SetUseRawDataOnly(false); AfterOriginalRecompression = AnimSeq->GetResourceSizeBytes(EResourceSizeMode::Inclusive); @@ -735,7 +735,9 @@ void FAnimationUtils::CompressAnimSequenceExplicit( } // Check for global permission to try an alternative compressor - if( bTryAlternateCompressor && !AnimSeq->bDoNotOverrideCompression ) + // we don't check for bDoNotOverrideCompression here, as that is now used as part of the UAnimCompress_Automatic compressor + // And it's valid to manually recompress animations + if( bTryAlternateCompressor /*&& (!AnimSeq->bDoNotOverrideCompression */) { AnimationErrorStats NewErrorStats = OriginalErrorStats; if (bRaiseMaxErrorToExisting) @@ -765,7 +767,7 @@ void FAnimationUtils::CompressAnimSequenceExplicit( ++TotalRecompressions; // Prepare to compress - int32 CurrentSize = AnimSeq->GetResourceSizeBytes(EResourceSizeMode::Inclusive); + SIZE_T CurrentSize = AnimSeq->GetResourceSizeBytes(EResourceSizeMode::Inclusive); int32* WinningCompressorCounter = NULL; float* WinningCompressorErrorSum = NULL; int32* WinningCompressorMarginalSavingsSum = NULL; diff --git a/Engine/Source/Runtime/Engine/Private/Animation/BlendSpace1D.cpp b/Engine/Source/Runtime/Engine/Private/Animation/BlendSpace1D.cpp index 960164150319..80398e9f4945 100644 --- a/Engine/Source/Runtime/Engine/Private/Animation/BlendSpace1D.cpp +++ b/Engine/Source/Runtime/Engine/Private/Animation/BlendSpace1D.cpp @@ -13,12 +13,12 @@ UBlendSpace1D::UBlendSpace1D(const FObjectInitializer& ObjectInitializer) bool UBlendSpace1D::IsValidAdditive() const { - return ContainsMatchingSamples(AAT_LocalSpaceBase); + return ContainsMatchingSamples(AAT_LocalSpaceBase) || ContainsMatchingSamples(AAT_RotationOffsetMeshSpace); } bool UBlendSpace1D::IsValidAdditiveType(EAdditiveAnimationType AdditiveType) const { - return (AdditiveType == AAT_LocalSpaceBase || AdditiveType == AAT_None); + return (AdditiveType == AAT_LocalSpaceBase || AdditiveType == AAT_RotationOffsetMeshSpace || AdditiveType == AAT_None); } EBlendSpaceAxis UBlendSpace1D::GetAxisToScale() const diff --git a/Engine/Source/Runtime/Engine/Private/Animation/BlendSpaceBase.cpp b/Engine/Source/Runtime/Engine/Private/Animation/BlendSpaceBase.cpp index b727092a86f9..235ba67219dd 100644 --- a/Engine/Source/Runtime/Engine/Private/Animation/BlendSpaceBase.cpp +++ b/Engine/Source/Runtime/Engine/Private/Animation/BlendSpaceBase.cpp @@ -1237,7 +1237,7 @@ void UBlendSpaceBase::UpdatePreviewBasePose() { for (const FBlendSample& BlendSample : SampleData) { - if (BlendSample.Animation->RefPoseSeq) + if (BlendSample.Animation && BlendSample.Animation->RefPoseSeq) { PreviewBasePose = BlendSample.Animation->RefPoseSeq; break; diff --git a/Engine/Source/Runtime/Engine/Private/Animation/CachedAnimData.cpp b/Engine/Source/Runtime/Engine/Private/Animation/CachedAnimData.cpp new file mode 100644 index 000000000000..31b8a17ef8f0 --- /dev/null +++ b/Engine/Source/Runtime/Engine/Private/Animation/CachedAnimData.cpp @@ -0,0 +1,285 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#include "CachedAnimData.h" +#include "Animation/AnimInstance.h" +#include "Animation/AnimStateMachineTypes.h" + +bool FCachedAnimStateData::IsValid(UAnimInstance& InAnimInstance) const +{ + if (!bInitialized) + { + bInitialized = true; + if ((StateMachineName != NAME_None) && (StateName != NAME_None)) + { + const FBakedAnimationStateMachine* MachineDescription = nullptr; + InAnimInstance.GetStateMachineIndexAndDescription(StateMachineName, MachineIndex, &MachineDescription); + + if (MachineDescription) + { + check(MachineIndex != INDEX_NONE); + StateIndex = MachineDescription->FindStateIndex(StateName); + if (StateIndex == INDEX_NONE) + { + UE_LOG(LogAnimation, Warning, TEXT("FCachedAnimStateData::GetWeight StateName %s not found in StateMachineName %s in AnimBP: %s. Renamed or deleted?"), *StateName.ToString(), *StateMachineName.ToString(), *GetNameSafe(&InAnimInstance)); + } + } + else + { + UE_LOG(LogAnimation, Warning, TEXT("FCachedAnimStateData::GetWeight StateMachineName %s not found! (With State %s in AnimBP: %s) Renamed or deleted?"), *StateMachineName.ToString(), *StateName.ToString(), *GetNameSafe(&InAnimInstance)); + } + } + } + + return (StateIndex != INDEX_NONE); +} + +float FCachedAnimStateData::IsMachineRelevant(UAnimInstance& InAnimInstance) const +{ + return IsValid(InAnimInstance) ? FAnimWeight::IsRelevant(InAnimInstance.GetInstanceMachineWeight(MachineIndex)) : false; +} + +float FCachedAnimStateData::GetWeight(UAnimInstance& InAnimInstance) const +{ + return IsValid(InAnimInstance) ? InAnimInstance.GetInstanceStateWeight(MachineIndex, StateIndex) : 0.f; +} + +float FCachedAnimStateData::GetGlobalWeight(UAnimInstance& InAnimInstance) const +{ + return IsValid(InAnimInstance) ? (InAnimInstance.GetInstanceMachineWeight(MachineIndex) * InAnimInstance.GetInstanceStateWeight(MachineIndex, StateIndex)) : 0.f; +} + +bool FCachedAnimStateData::IsFullWeight(UAnimInstance& InAnimInstance) const +{ + return FAnimWeight::IsFullWeight(GetWeight(InAnimInstance)); +} + +bool FCachedAnimStateData::IsRelevant(UAnimInstance& InAnimInstance) const +{ + return FAnimWeight::IsRelevant(GetWeight(InAnimInstance)); +} + +bool FCachedAnimStateArray::IsValid(UAnimInstance& InAnimInstance) const +{ + // Make sure the setup validates our assumptions. + if (!bCheckedValidity) + { + bCheckedValidity = true; + bCachedIsValid = true; + + if (States.Num() > 1) + { + FName StateMachineName = NAME_None; + TArray UniqueStateNames; + + for (const FCachedAnimStateData& State : States) + { + if (StateMachineName == NAME_None) + { + StateMachineName = State.StateMachineName; + } + else if ((State.StateMachineName != NAME_None) && (State.StateMachineName != StateMachineName)) + { + UE_LOG(LogAnimation, Warning, TEXT("FCachedAnimStateArray::IsValid Mismatched StateMachineName found (%s VS %s) in AnimBP: %s. Renamed or deleted?"), *StateMachineName.ToString(), *State.StateMachineName.ToString(), *GetNameSafe(&InAnimInstance)); + bCachedIsValid = false; + } + + if (!UniqueStateNames.Contains(State.StateName)) + { + UniqueStateNames.Add(State.StateName); + } + else + { + UE_LOG(LogAnimation, Warning, TEXT("FCachedAnimStateArray::IsValid StateName included multiple times (%s) in AnimBP: %s. Renamed or deleted?"), *State.StateName.ToString(), *GetNameSafe(&InAnimInstance)); + bCachedIsValid = false; + } + } + } + } + + return bCachedIsValid; +} + +float FCachedAnimStateArray::GetTotalWeight(UAnimInstance& InAnimInstance) const +{ + if (IsValid(InAnimInstance)) + { + float TotalWeight = 0.f; + for (const FCachedAnimStateData& State : States) + { + TotalWeight += State.GetWeight(InAnimInstance); + } + return FMath::Min(TotalWeight, 1.f); + } + return 0.f; +} + +bool FCachedAnimStateArray::IsFullWeight(UAnimInstance& InAnimInstance) const +{ + return FAnimWeight::IsFullWeight(GetTotalWeight(InAnimInstance)); +} + +bool FCachedAnimStateArray::IsRelevant(UAnimInstance& InAnimInstance) const +{ + if (IsValid(InAnimInstance)) + { + for (const FCachedAnimStateData& State : States) + { + if (State.IsRelevant(InAnimInstance)) + { + return true; + } + } + } + + return false; +} + +void FCachedAnimAssetPlayerData::CacheIndices(UAnimInstance& InAnimInstance) const +{ + if(!bInitialized) + { + bInitialized = true; + if((StateMachineName != NAME_None) && (StateName != NAME_None)) + { + Index = InAnimInstance.GetInstanceAssetPlayerIndex(StateMachineName, StateName); + if(Index == INDEX_NONE) + { + UE_LOG(LogAnimation, Warning, TEXT("FCachedAnimAssetPlayerData::GetAssetPlayerTime StateName %s not found in StateMachineName %s in AnimBP: %s. Renamed or deleted?"), *StateName.ToString(), *StateMachineName.ToString(), *GetNameSafe(&InAnimInstance)); + } + } + } +} + +float FCachedAnimAssetPlayerData::GetAssetPlayerTime(UAnimInstance& InAnimInstance) const +{ + CacheIndices(InAnimInstance); + + if (Index != INDEX_NONE) + { + return InAnimInstance.GetInstanceAssetPlayerTime(Index); + } + + return 0.f; +} + +float FCachedAnimAssetPlayerData::GetAssetPlayerTimeRatio(UAnimInstance& InAnimInstance) const +{ + CacheIndices(InAnimInstance); + + if(Index != INDEX_NONE) + { + return InAnimInstance.GetInstanceAssetPlayerTimeFraction(Index); + } + + return 0.0f; +} + +void FCachedAnimRelevancyData::CacheIndices(UAnimInstance& InAnimInstance) const +{ + if (!bInitialized) + { + bInitialized = true; + if ((StateMachineName != NAME_None) && (StateName != NAME_None)) + { + if (MachineIndex == INDEX_NONE) + { + MachineIndex = InAnimInstance.GetStateMachineIndex(StateMachineName); + if (MachineIndex == INDEX_NONE) + { + UE_LOG(LogAnimation, Warning, TEXT("FCachedAnimRelevancyData::CacheIndices StateMachineName %s not found in AnimBP: %s. Renamed or deleted?"), *StateMachineName.ToString(), *GetNameSafe(&InAnimInstance)); + } + } + if (StateIndex == INDEX_NONE) + { + const FBakedAnimationStateMachine* MachinePtr = InAnimInstance.GetStateMachineInstanceDesc(StateMachineName); + if (MachinePtr) + { + StateIndex = MachinePtr->FindStateIndex(StateName); + if (StateIndex == INDEX_NONE) + { + UE_LOG(LogAnimation, Warning, TEXT("FCachedAnimRelevancyData::CacheIndices StateName %s not found in StateMachineName %s in AnimBP: %s. Renamed or deleted?"), *StateName.ToString(), *StateMachineName.ToString(), *GetNameSafe(&InAnimInstance)); + } + } + } + } + } +} + +float FCachedAnimRelevancyData::GetRelevantAnimTime(UAnimInstance& InAnimInstance) const +{ + CacheIndices(InAnimInstance); + + if (MachineIndex != INDEX_NONE && StateIndex != INDEX_NONE) + { + return InAnimInstance.GetRelevantAnimTime(MachineIndex, StateIndex); + } + + return 0.f; +} + +float FCachedAnimRelevancyData::GetRelevantAnimTimeRemaining(UAnimInstance& InAnimInstance) const +{ + CacheIndices(InAnimInstance); + + if (MachineIndex != INDEX_NONE && StateIndex != INDEX_NONE) + { + return InAnimInstance.GetRelevantAnimTimeRemaining(MachineIndex, StateIndex); + } + + return 0.f; +} + +float FCachedAnimRelevancyData::GetRelevantAnimTimeRemainingFraction(UAnimInstance& InAnimInstance) const +{ + CacheIndices(InAnimInstance); + + if (MachineIndex != INDEX_NONE && StateIndex != INDEX_NONE) + { + return InAnimInstance.GetRelevantAnimTimeRemainingFraction(MachineIndex, StateIndex); + } + + return 0.f; +} + +void FCachedAnimTransitionData::CacheIndices(UAnimInstance& InAnimInstance) const +{ + if (!bInitialized) + { + bInitialized = true; + if ((StateMachineName != NAME_None) && (FromStateName != NAME_None) && (ToStateName != NAME_None)) + { + if (MachineIndex == INDEX_NONE) + { + MachineIndex = InAnimInstance.GetStateMachineIndex(StateMachineName); + if (MachineIndex == INDEX_NONE) + { + UE_LOG(LogAnimation, Warning, TEXT("FCachedAnimTransitionData::CacheIndices StateMachineName %s in AnimBP: %s not found. Renamed or deleted?"), *StateMachineName.ToString(), *GetNameSafe(&InAnimInstance)); + } + } + if (TransitionIndex == INDEX_NONE) + { + const FBakedAnimationStateMachine* MachinePtr = InAnimInstance.GetStateMachineInstanceDesc(StateMachineName); + if (MachinePtr) + { + TransitionIndex = MachinePtr->FindTransitionIndex(FromStateName, ToStateName); + if (TransitionIndex == INDEX_NONE) + { + UE_LOG(LogAnimation, Warning, TEXT("FCachedAnimTransitionData::CacheIndices Transition from %s to %s not found in StateMachineName %s in AnimBP: %s. Renamed or deleted?"), *FromStateName.ToString(), *ToStateName.ToString(), *StateMachineName.ToString(), *GetNameSafe(&InAnimInstance)); + } + } + } + } + } +} + +float FCachedAnimTransitionData::GetCrossfadeDuration(UAnimInstance& InAnimInstance) const +{ + CacheIndices(InAnimInstance); + + if (MachineIndex != INDEX_NONE && TransitionIndex != INDEX_NONE) + { + return InAnimInstance.GetInstanceTransitionCrossfadeDuration(MachineIndex, TransitionIndex); + } + + return 0.f; +} diff --git a/Engine/Source/Runtime/Engine/Private/Animation/PreviewCollectionInterface.cpp b/Engine/Source/Runtime/Engine/Private/Animation/PreviewCollectionInterface.cpp new file mode 100644 index 000000000000..dd6db0330bf3 --- /dev/null +++ b/Engine/Source/Runtime/Engine/Private/Animation/PreviewCollectionInterface.cpp @@ -0,0 +1,8 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "Animation/PreviewCollectionInterface.h" + +UPreviewCollectionInterface::UPreviewCollectionInterface(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ +} diff --git a/Engine/Source/Runtime/Engine/Private/Animation/PreviewMeshCollection.cpp b/Engine/Source/Runtime/Engine/Private/Animation/PreviewMeshCollection.cpp new file mode 100644 index 000000000000..731b8d227ff0 --- /dev/null +++ b/Engine/Source/Runtime/Engine/Private/Animation/PreviewMeshCollection.cpp @@ -0,0 +1,18 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "Engine/PreviewMeshCollection.h" + +void UPreviewMeshCollection::GetPreviewSkeletalMeshes(TArray& OutList) const +{ + OutList.Empty(); + for (int32 MeshIndex = 0; MeshIndex < SkeletalMeshes.Num(); ++MeshIndex) + { + const FPreviewMeshCollectionEntry& Entry = SkeletalMeshes[MeshIndex]; + + // Load up our valid skeletal meshes + if (Entry.SkeletalMesh.LoadSynchronous()) + { + OutList.Add(Entry.SkeletalMesh.Get()); + } + } +} diff --git a/Engine/Source/Runtime/Engine/Private/Animation/SkeletalMeshActor.cpp b/Engine/Source/Runtime/Engine/Private/Animation/SkeletalMeshActor.cpp index 0e3a7cc1637d..4c6e18d096a4 100644 --- a/Engine/Source/Runtime/Engine/Private/Animation/SkeletalMeshActor.cpp +++ b/Engine/Source/Runtime/Engine/Private/Animation/SkeletalMeshActor.cpp @@ -298,9 +298,4 @@ void ASkeletalMeshActor::LoadedFromAnotherClass(const FName& OldClassName) } #endif -USkeletalMeshComponent* ASkeletalMeshActor::GetSkeletalMeshComponent() -{ - return SkeletalMeshComponent; -} - #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Runtime/Engine/Private/Animation/Skeleton.cpp b/Engine/Source/Runtime/Engine/Private/Animation/Skeleton.cpp index f0a63d6c6ab6..b3d679916d2c 100644 --- a/Engine/Source/Runtime/Engine/Private/Animation/Skeleton.cpp +++ b/Engine/Source/Runtime/Engine/Private/Animation/Skeleton.cpp @@ -341,7 +341,7 @@ bool USkeleton::IsCompatibleMesh(const USkeletalMesh* InSkelMesh) const // follow the parent chain to verify the chain is same if(!DoesParentChainMatch(SkeletonBoneIndex, InSkelMesh)) { - UE_LOG(LogAnimation, Warning, TEXT("%s : Hierarchy does not match."), *MeshBoneName.ToString()); + UE_LOG(LogAnimation, Verbose, TEXT("%s : Hierarchy does not match."), *MeshBoneName.ToString()); return false; } } @@ -374,14 +374,14 @@ bool USkeleton::IsCompatibleMesh(const USkeletalMesh* InSkelMesh) const // still no match, return false, no parent to look for if( SkeletonBoneIndex == INDEX_NONE ) { - UE_LOG(LogAnimation, Warning, TEXT("%s : Missing joint on skeleton. Make sure to assign to the skeleton."), *MeshBoneName.ToString()); + UE_LOG(LogAnimation, Verbose, TEXT("%s : Missing joint on skeleton. Make sure to assign to the skeleton."), *MeshBoneName.ToString()); return false; } // second follow the parent chain to verify the chain is same if( !DoesParentChainMatch(SkeletonBoneIndex, InSkelMesh) ) { - UE_LOG(LogAnimation, Warning, TEXT("%s : Hierarchy does not match."), *MeshBoneName.ToString()); + UE_LOG(LogAnimation, Verbose, TEXT("%s : Hierarchy does not match."), *MeshBoneName.ToString()); return false; } } @@ -936,16 +936,16 @@ void USkeleton::LoadAdditionalPreviewSkeletalMeshes() AdditionalPreviewSkeletalMeshes.LoadSynchronous(); } -UPreviewMeshCollection* USkeleton::GetAdditionalPreviewSkeletalMeshes() const +UDataAsset* USkeleton::GetAdditionalPreviewSkeletalMeshes() const { return AdditionalPreviewSkeletalMeshes.Get(); } -void USkeleton::SetAdditionalPreviewSkeletalMeshes(UPreviewMeshCollection* PreviewMeshCollection) +void USkeleton::SetAdditionalPreviewSkeletalMeshes(UDataAsset* InPreviewCollectionAsset) { Modify(); - AdditionalPreviewSkeletalMeshes = PreviewMeshCollection; + AdditionalPreviewSkeletalMeshes = InPreviewCollectionAsset; } int32 USkeleton::ValidatePreviewAttachedObjects() diff --git a/Engine/Source/Runtime/Engine/Private/Animation/SmartName.cpp b/Engine/Source/Runtime/Engine/Private/Animation/SmartName.cpp index aec787a2b186..fd301e0b17f9 100644 --- a/Engine/Source/Runtime/Engine/Private/Animation/SmartName.cpp +++ b/Engine/Source/Runtime/Engine/Private/Animation/SmartName.cpp @@ -3,6 +3,7 @@ #include "Animation/SmartName.h" #include "UObject/FrameworkObjectVersion.h" #include "Animation/Skeleton.h" +#include "AnimPhysObjectVersion.h" //////////////////////////////////////////////////////////////////////// // @@ -361,8 +362,13 @@ void FSmartNameContainer::InitializeCurveMetaData(class USkeleton* Skeleton) /////////////////////////////////////////////////////////////////////// bool FSmartName::Serialize(FArchive& Ar) { + Ar.UsingCustomVersion(FAnimPhysObjectVersion::GUID); Ar << DisplayName; - Ar << UID; + if (Ar.CustomVer(FAnimPhysObjectVersion::GUID) < FAnimPhysObjectVersion::RemoveUIDFromSmartNameSerialize) + { + SmartName::UID_Type TempUID; + Ar << TempUID; + } // only save if it's editor build and not cooking #if WITH_EDITORONLY_DATA diff --git a/Engine/Source/Runtime/Engine/Private/AssetManager.cpp b/Engine/Source/Runtime/Engine/Private/AssetManager.cpp index 28a9d5e3055e..bbac0f16d7c0 100644 --- a/Engine/Source/Runtime/Engine/Private/AssetManager.cpp +++ b/Engine/Source/Runtime/Engine/Private/AssetManager.cpp @@ -6,10 +6,13 @@ #include "AssetData.h" #include "ARFilter.h" #include "Engine/Engine.h" +#include "Engine/BlueprintGeneratedClass.h" #include "UObject/ConstructorHelpers.h" +#include "UObject/UObjectHash.h" #include "Misc/FileHelper.h" #include "Misc/ScopedSlowTask.h" #include "Misc/Paths.h" +#include "AssetRegistryState.h" #if WITH_EDITOR #include "Editor.h" @@ -96,18 +99,12 @@ const FPrimaryAssetType UAssetManager::PrimaryAssetLabelType = FName(TEXT("Prima UAssetManager::UAssetManager() { bIsGlobalAsyncScanEnvironment = false; - bShouldKeepHardRefs = !GIsEditor || IsRunningCommandlet(); - -#if WITH_EDITOR - // In editor builds guess the type/name, in cooked builds do not as it should be saved - bShouldGuessTypeAndName = true; -#else bShouldGuessTypeAndName = false; -#endif - - bShouldUseSynchronousLoad = IsRunningCommandlet(); + bShouldUseSynchronousLoad = false; bIsBulkScanning = false; bIsManagementDatabaseCurrent = false; + bUpdateManagementDatabaseAfterScan = false; + NumberOfSpawnedNotifications = 0; } void UAssetManager::PostInitProperties() @@ -116,7 +113,7 @@ void UAssetManager::PostInitProperties() if (!HasAnyFlags(RF_ClassDefaultObject)) { - + const UAssetManagerSettings& Settings = GetSettings(); #if WITH_EDITOR bIsGlobalAsyncScanEnvironment = GIsEditor && !IsRunningCommandlet(); @@ -128,11 +125,20 @@ void UAssetManager::PostInitProperties() AssetRegistry.OnFilesLoaded().AddUObject(this, &UAssetManager::OnAssetRegistryFilesLoaded); AssetRegistry.OnInMemoryAssetCreated().AddUObject(this, &UAssetManager::OnInMemoryAssetCreated); AssetRegistry.OnInMemoryAssetDeleted().AddUObject(this, &UAssetManager::OnInMemoryAssetDeleted); + AssetRegistry.OnAssetRenamed().AddUObject(this, &UAssetManager::OnAssetRenamed); } FEditorDelegates::PreBeginPIE.AddUObject(this, &UAssetManager::PreBeginPIE); FEditorDelegates::EndPIE.AddUObject(this, &UAssetManager::EndPIE); + + // In editor builds guess the type/name if allowed + bShouldGuessTypeAndName = GetSettings().bShouldGuessTypeAndNameInEditor; +#else + // Never guess type in cooked builds + bShouldGuessTypeAndName = false; #endif + bShouldUseSynchronousLoad = IsRunningCommandlet(); + LoadRedirectorMaps(); } } @@ -162,6 +168,16 @@ UAssetManager& UAssetManager::Get() } } +UAssetManager* UAssetManager::GetIfValid() +{ + if (GEngine && GEngine->AssetManager) + { + return GEngine->AssetManager; + } + + return nullptr; +} + IAssetRegistry& UAssetManager::GetAssetRegistry() const { if (!CachedAssetRegistry) @@ -281,7 +297,12 @@ int32 UAssetManager::ScanPathsForPrimaryAssets(FPrimaryAssetType PrimaryAssetTyp } else { - ARFilter.ClassNames.Add(UBlueprint::StaticClass()->GetFName()); + TArray BlueprintCoreDerivedClasses; + GetDerivedClasses(UBlueprintCore::StaticClass(), BlueprintCoreDerivedClasses); + for (UClass* BPCoreClass : BlueprintCoreDerivedClasses) + { + ARFilter.ClassNames.Add(BPCoreClass->GetFName()); + } // Make sure this works, if it does remove post load check ClassNames.Add(BaseClass->GetFName()); @@ -289,14 +310,14 @@ int32 UAssetManager::ScanPathsForPrimaryAssets(FPrimaryAssetType PrimaryAssetTyp /* DerivedClassNames are short names, GeneratedClass is a long name const FName GeneratedClassName = FName(TEXT("GeneratedClass")); - for (FName DerivedClassName : DerivedClassNames) + for (const FName& DerivedClassName : DerivedClassNames) { ARFilter.TagsAndValues.Add(GeneratedClassName, DerivedClassName.ToString()); // Add any old names to the list in case things haven't been resaved TArray OldNames = FLinkerLoad::FindPreviousNamesForClass(BaseClass->GetPathName(), false); - for (FName OldClassName : OldNames) + for (const FName& OldClassName : OldNames) { ARFilter.TagsAndValues.Add(GeneratedClassName, OldClassName.ToString()); } @@ -348,7 +369,7 @@ int32 UAssetManager::ScanPathsForPrimaryAssets(FPrimaryAssetType PrimaryAssetTyp ValidNames = FLinkerLoad::FindPreviousNamesForClass(BaseClass->GetPathName(), false); #endif ValidNames.Add(FName(*ClassName)); - for (FName ValidName : ValidNames) + for (const FName& ValidName : ValidNames) { if (DerivedClassNames.Contains(ValidName)) { @@ -365,7 +386,7 @@ int32 UAssetManager::ScanPathsForPrimaryAssets(FPrimaryAssetType PrimaryAssetTyp } } - FPrimaryAssetId PrimaryAssetId = GetPrimaryAssetIdFromData(Data, PrimaryAssetType); + FPrimaryAssetId PrimaryAssetId = ExtractPrimaryAssetIdFromData(Data, PrimaryAssetType); // Remove invalid or wrong type assets if (!PrimaryAssetId.IsValid() || PrimaryAssetId.PrimaryAssetType != PrimaryAssetType) @@ -391,6 +412,7 @@ void UAssetManager::StartBulkScanning() if (ensure(!bIsBulkScanning)) { bIsBulkScanning = true; + NumberOfSpawnedNotifications = 0; } } @@ -417,11 +439,8 @@ void UAssetManager::UpdateCachedAssetData(const FPrimaryAssetId& PrimaryAssetId, if (OldData && OldData->AssetPtr.ToStringReference() != NewStringReference) { - if (bAllowDuplicates) - { - UE_LOG(LogAssetManager, Warning, TEXT("Found Duplicate PrimaryAssetID %s during creation, this must be resolved before saving. Path %s is replacing path %s"), *PrimaryAssetId.ToString(), *OldData->AssetPtr.ToStringReference().ToString(), *NewStringReference.ToString()); - } - else + UE_LOG(LogAssetManager, Warning, TEXT("Found Duplicate PrimaryAssetID %s, this must be resolved before saving. Path %s is replacing path %s"), *PrimaryAssetId.ToString(), *OldData->AssetPtr.ToStringReference().ToString(), *NewStringReference.ToString()); + if (!bAllowDuplicates) { ensureMsgf(!OldData, TEXT("Found Duplicate PrimaryAssetID %s! Path %s is replacing path %s"), *PrimaryAssetId.ToString(), *OldData->AssetPtr.ToStringReference().ToString(), *NewStringReference.ToString()); } @@ -429,14 +448,18 @@ void UAssetManager::UpdateCachedAssetData(const FPrimaryAssetId& PrimaryAssetId, #if WITH_EDITOR if (GIsEditor) { - FNotificationInfo Info(FText::Format(LOCTEXT("DuplicateAssetId", "Duplicate Asset ID {0} used by {1} and {2}, you must delete or rename one!"), - FText::FromString(PrimaryAssetId.ToString()), FText::FromString(OldData->AssetPtr.ToStringReference().GetLongPackageName()), FText::FromString(NewStringReference.GetLongPackageName()))); - Info.ExpireDuration = 30.0f; - - TSharedPtr Notification = FSlateNotificationManager::Get().AddNotification(Info); - if (Notification.IsValid()) + const int MaxNotificationsPerFrame = 5; + if (NumberOfSpawnedNotifications++ < MaxNotificationsPerFrame) { - Notification->SetCompletionState(SNotificationItem::CS_Fail); + FNotificationInfo Info(FText::Format(LOCTEXT("DuplicateAssetId", "Duplicate Asset ID {0} used by {1} and {2}, you must delete or rename one!"), + FText::FromString(PrimaryAssetId.ToString()), FText::FromString(OldData->AssetPtr.ToStringReference().GetLongPackageName()), FText::FromString(NewStringReference.GetLongPackageName()))); + Info.ExpireDuration = 30.0f; + + TSharedPtr Notification = FSlateNotificationManager::Get().AddNotification(Info); + if (Notification.IsValid()) + { + Notification->SetCompletionState(SNotificationItem::CS_Fail); + } } } #endif @@ -467,6 +490,9 @@ void UAssetManager::UpdateCachedAssetData(const FPrimaryAssetId& PrimaryAssetId, CachedAssetBundles.Remove(PrimaryAssetId); } + // Mark these as editor only if our type is editor only + FStringAssetReferenceSerializationScope SerializationScope(NAME_None, NAME_None, TypeData.Info.bIsEditorOnly ? EStringAssetReferenceCollectType::EditorOnlyCollect : EStringAssetReferenceCollectType::AlwaysCollect); + FAssetBundleData BundleData; if (BundleData.SetFromAssetData(NewAssetData)) { @@ -677,7 +703,7 @@ bool UAssetManager::GetPrimaryAssetDataList(FPrimaryAssetType PrimaryAssetType, { const FPrimaryAssetTypeData& TypeData = FoundType->Get(); - for (TPair Pair : TypeData.AssetMap) + for (const TPair& Pair : TypeData.AssetMap) { const FAssetData* CachedAssetData = Registry.GetCachedAssetDataForObjectPath(Pair.Value.AssetDataPath); @@ -713,7 +739,7 @@ bool UAssetManager::GetPrimaryAssetObjectList(FPrimaryAssetType PrimaryAssetType { const FPrimaryAssetTypeData& TypeData = FoundType->Get(); - for (TPair Pair : TypeData.AssetMap) + for (const TPair& Pair : TypeData.AssetMap) { UObject* FoundObject = Pair.Value.AssetPtr.Get(); @@ -747,15 +773,29 @@ bool UAssetManager::GetPrimaryAssetPathList(FPrimaryAssetType PrimaryAssetType, { const FPrimaryAssetTypeData& TypeData = FoundType->Get(); - for (TPair Pair : TypeData.AssetMap) + for (const TPair& Pair : TypeData.AssetMap) { - AssetPathList.AddUnique(Pair.Value.AssetPtr.ToStringReference()); + if (!Pair.Value.AssetPtr.IsNull()) + { + AssetPathList.AddUnique(Pair.Value.AssetPtr.ToStringReference()); + } } } return AssetPathList.Num() > 0; } +FPrimaryAssetId UAssetManager::GetPrimaryAssetIdForObject(UObject* Object) const +{ + // Use path instead of calling on Object, we only want it if it's registered + return GetPrimaryAssetIdForPath(FName(*Object->GetPathName())); +} + +FPrimaryAssetId UAssetManager::GetPrimaryAssetIdForData(const FAssetData& AssetData) const +{ + return GetPrimaryAssetIdForPath(GetAssetPathForData(AssetData)); +} + FPrimaryAssetId UAssetManager::GetPrimaryAssetIdForPath(const FStringAssetReference& ObjectPath) const { FName PossibleAssetPath = FName(*ObjectPath.ToString(), FNAME_Find); @@ -822,7 +862,7 @@ FPrimaryAssetId UAssetManager::GetPrimaryAssetIdForPackage(FName PackagePath) co return FoundId; } -FPrimaryAssetId UAssetManager::GetPrimaryAssetIdFromData(const FAssetData& AssetData, FPrimaryAssetType SuggestedType) const +FPrimaryAssetId UAssetManager::ExtractPrimaryAssetIdFromData(const FAssetData& AssetData, FPrimaryAssetType SuggestedType) const { FPrimaryAssetId FoundId = AssetData.GetPrimaryAssetId(); @@ -855,7 +895,7 @@ bool UAssetManager::GetPrimaryAssetIdList(FPrimaryAssetType PrimaryAssetType, TA { const FPrimaryAssetTypeData& TypeData = FoundType->Get(); - for (TPair Pair : TypeData.AssetMap) + for (const TPair& Pair : TypeData.AssetMap) { PrimaryAssetIdList.Add(FPrimaryAssetId(PrimaryAssetType, Pair.Key)); } @@ -880,7 +920,7 @@ bool UAssetManager::GetPrimaryAssetTypeInfo(FPrimaryAssetType PrimaryAssetType, void UAssetManager::GetPrimaryAssetTypeInfoList(TArray& AssetTypeInfoList) const { - for (const TPair> TypePair : AssetTypeMap) + for (const TPair>& TypePair : AssetTypeMap) { const FPrimaryAssetTypeData& TypeData = TypePair.Value.Get(); @@ -911,13 +951,13 @@ TSharedPtr UAssetManager::ChangeBundleStateForPrimaryAssets(c { NewBundleState = CurrentBundleState; - for (FName RemoveBundle : RemoveBundles) + for (const FName& RemoveBundle : RemoveBundles) { NewBundleState.Remove(RemoveBundle); } } - for (FName AddBundle : AddBundles) + for (const FName& AddBundle : AddBundles) { NewBundleState.AddUnique(AddBundle); } @@ -951,7 +991,7 @@ TSharedPtr UAssetManager::ChangeBundleStateForPrimaryAssets(c PathsToLoad.Add(AssetPath); } - for (FName BundleName : NewBundleState) + for (const FName& BundleName : NewBundleState) { FAssetBundleEntry Entry = GetAssetBundleEntry(PrimaryAssetId, BundleName); @@ -959,7 +999,10 @@ TSharedPtr UAssetManager::ChangeBundleStateForPrimaryAssets(c { PathsToLoad.Append(Entry.BundleAssets); } - UE_LOG(LogAssetManager, Verbose, TEXT("ChangeBundleStateForPrimaryAssets: No assets for bundle %s::%s"), *PrimaryAssetId.ToString(), *BundleName.ToString()); + else + { + UE_LOG(LogAssetManager, Verbose, TEXT("ChangeBundleStateForPrimaryAssets: No assets for bundle %s::%s"), *PrimaryAssetId.ToString(), *BundleName.ToString()); + } } TSharedPtr NewHandle; @@ -1058,6 +1101,94 @@ TSharedPtr UAssetManager::ChangeBundleStateForPrimaryAssets(c return ReturnHandle; } +TSharedPtr UAssetManager::ChangeBundleStateForMatchingPrimaryAssets(const TArray& NewBundles, const TArray& OldBundles, FStreamableDelegate DelegateToCall, TAsyncLoadPriority Priority) +{ + TArray AssetsToChange; + + if (GetPrimaryAssetsWithBundleState(AssetsToChange, TArray(), OldBundles)) + { + // This will call delegate when done + return ChangeBundleStateForPrimaryAssets(AssetsToChange, NewBundles, OldBundles, false, DelegateToCall, Priority); + } + + // Nothing to transition, call delegate now + DelegateToCall.ExecuteIfBound(); + return nullptr; +} + +TSharedPtr UAssetManager::PreloadPrimaryAssets(const TArray& AssetsToLoad, const TArray& LoadBundles, bool bLoadRecursive, FStreamableDelegate DelegateToCall, TAsyncLoadPriority Priority) +{ + TSet PathsToLoad; + FString DebugName; + TSharedPtr ReturnHandle; + + for (const FPrimaryAssetId& PrimaryAssetId : AssetsToLoad) + { + FPrimaryAssetData* NameData = GetNameData(PrimaryAssetId); + + if (NameData) + { + // Gather asset refs + const FStringAssetReference& AssetPath = NameData->AssetPtr.ToStringReference(); + + if (!AssetPath.IsNull()) + { + // Dynamic types can have no base asset path + PathsToLoad.Add(AssetPath); + } + + // Construct a temporary bundle data with the bundles specified + FAssetBundleData TempBundleData; + for (const FName& BundleName : LoadBundles) + { + FAssetBundleEntry Entry = GetAssetBundleEntry(PrimaryAssetId, BundleName); + + if (Entry.IsValid()) + { + TempBundleData.Bundles.Add(Entry); + } + } + + if (bLoadRecursive) + { + RecursivelyExpandBundleData(TempBundleData); + } + + for (const FAssetBundleEntry& Entry : TempBundleData.Bundles) + { + PathsToLoad.Append(Entry.BundleAssets); + } + + if (DebugName.IsEmpty()) + { + DebugName += TEXT("Preloading "); + } + else + { + DebugName += TEXT(", "); + } + DebugName += PrimaryAssetId.ToString(); + } + } + + if (bShouldUseSynchronousLoad) + { + ReturnHandle = StreamableManager.RequestSyncLoad(PathsToLoad.Array(), false, DebugName); + FStreamableHandle::ExecuteDelegate(DelegateToCall); + } + else + { + ReturnHandle = StreamableManager.RequestAsyncLoad(PathsToLoad.Array(), DelegateToCall, Priority, false, DebugName); + } + + if (!ensureMsgf(ReturnHandle.IsValid(), TEXT("Requested preload of Primary Asset with no referenced assets!"))) + { + return nullptr; + } + + return ReturnHandle; +} + void UAssetManager::OnAssetStateChangeCompleted(FPrimaryAssetId PrimaryAssetId, TSharedPtr BoundHandle, FStreamableDelegate WrappedDelegate) { FPrimaryAssetData* NameData = GetNameData(PrimaryAssetId); @@ -1102,16 +1233,16 @@ TSharedPtr UAssetManager::LoadPrimaryAssetsWithType(FPrimaryA return LoadPrimaryAssets(Assets, LoadBundles, DelegateToCall, Priority); } -TSharedPtr UAssetManager::GetPrimaryAssetHandle(const FPrimaryAssetId& PrimaryAssetId, bool bForceCurrent, TArray* Bundles) +TSharedPtr UAssetManager::GetPrimaryAssetHandle(const FPrimaryAssetId& PrimaryAssetId, bool bForceCurrent, TArray* Bundles) const { - FPrimaryAssetData* NameData = GetNameData(PrimaryAssetId); + const FPrimaryAssetData* NameData = GetNameData(PrimaryAssetId); if (!NameData) { return nullptr; } - FPrimaryAssetLoadState& LoadState = (bForceCurrent || !NameData->PendingState.IsValid()) ? NameData->CurrentState : NameData->PendingState; + const FPrimaryAssetLoadState& LoadState = (bForceCurrent || !NameData->PendingState.IsValid()) ? NameData->CurrentState : NameData->PendingState; if (Bundles) { @@ -1120,25 +1251,25 @@ TSharedPtr UAssetManager::GetPrimaryAssetHandle(const FPrimar return LoadState.Handle; } -bool UAssetManager::GetPrimaryAssetsWithBundleState(TArray& PrimaryAssetList, const TArray& ValidTypes, const TArray& RequiredBundles, const TArray& ExcludedBundles, bool bForceCurrent) +bool UAssetManager::GetPrimaryAssetsWithBundleState(TArray& PrimaryAssetList, const TArray& ValidTypes, const TArray& RequiredBundles, const TArray& ExcludedBundles, bool bForceCurrent) const { bool bFoundAny = false; - for (TPair> TypePair : AssetTypeMap) + for (const TPair>& TypePair : AssetTypeMap) { - if (ValidTypes.Num() > 0 && !ValidTypes.Contains(TypePair.Key)) + if (ValidTypes.Num() > 0 && !ValidTypes.Contains(FPrimaryAssetType(TypePair.Key))) { // Skip this type continue; } - FPrimaryAssetTypeData& TypeData = TypePair.Value.Get(); + const FPrimaryAssetTypeData& TypeData = TypePair.Value.Get(); - for (TPair NamePair : TypeData.AssetMap) + for (const TPair& NamePair : TypeData.AssetMap) { - FPrimaryAssetData& NameData = NamePair.Value; + const FPrimaryAssetData& NameData = NamePair.Value; - FPrimaryAssetLoadState& LoadState = (bForceCurrent || !NameData.PendingState.IsValid()) ? NameData.CurrentState : NameData.PendingState; + const FPrimaryAssetLoadState& LoadState = (bForceCurrent || !NameData.PendingState.IsValid()) ? NameData.CurrentState : NameData.PendingState; if (!LoadState.IsValid()) { @@ -1149,7 +1280,7 @@ bool UAssetManager::GetPrimaryAssetsWithBundleState(TArray& Pri bool bFailedTest = false; // Check bundle requirements - for (FName RequiredName : RequiredBundles) + for (const FName& RequiredName : RequiredBundles) { if (!LoadState.BundleNames.Contains(RequiredName)) { @@ -1158,7 +1289,7 @@ bool UAssetManager::GetPrimaryAssetsWithBundleState(TArray& Pri } } - for (FName ExcludedName : ExcludedBundles) + for (const FName& ExcludedName : ExcludedBundles) { if (LoadState.BundleNames.Contains(ExcludedName)) { @@ -1178,19 +1309,19 @@ bool UAssetManager::GetPrimaryAssetsWithBundleState(TArray& Pri return bFoundAny; } -void UAssetManager::GetPrimaryAssetBundleStateMap(TMap>& BundleStateMap, bool bForceCurrent) +void UAssetManager::GetPrimaryAssetBundleStateMap(TMap>& BundleStateMap, bool bForceCurrent) const { BundleStateMap.Reset(); - for (TPair> TypePair : AssetTypeMap) + for (const TPair>& TypePair : AssetTypeMap) { - FPrimaryAssetTypeData& TypeData = TypePair.Value.Get(); + const FPrimaryAssetTypeData& TypeData = TypePair.Value.Get(); - for (TPair NamePair : TypeData.AssetMap) + for (const TPair& NamePair : TypeData.AssetMap) { - FPrimaryAssetData& NameData = NamePair.Value; + const FPrimaryAssetData& NameData = NamePair.Value; - FPrimaryAssetLoadState& LoadState = (bForceCurrent || !NameData.PendingState.IsValid()) ? NameData.CurrentState : NameData.PendingState; + const FPrimaryAssetLoadState& LoadState = (bForceCurrent || !NameData.PendingState.IsValid()) ? NameData.CurrentState : NameData.PendingState; if (!LoadState.IsValid()) { @@ -1289,7 +1420,6 @@ const FPrimaryAssetData* UAssetManager::GetNameData(const FPrimaryAssetId& Prima const TSharedRef* FoundType = AssetTypeMap.Find(PrimaryAssetId.PrimaryAssetType); // Try redirected name - if (FoundType) { const FPrimaryAssetData* FoundName = (*FoundType)->AssetMap.Find(PrimaryAssetId.PrimaryAssetName); @@ -1320,19 +1450,19 @@ void UAssetManager::RebuildObjectReferenceList() ObjectReferenceList.Reset(); // Iterate primary asset map - for (TPair> TypePair : AssetTypeMap) + for (TPair>& TypePair : AssetTypeMap) { FPrimaryAssetTypeData& TypeData = TypePair.Value.Get(); // Add base class in case it's a blueprint - if (bShouldKeepHardRefs && !TypeData.Info.bIsDynamicAsset) + if (!TypeData.Info.bIsDynamicAsset) { ObjectReferenceList.AddUnique(TypeData.Info.AssetBaseClassLoaded); } TypeData.Info.NumberOfAssets = TypeData.AssetMap.Num(); - for (TPair NamePair : TypeData.AssetMap) + for (TPair& NamePair : TypeData.AssetMap) { FPrimaryAssetData& NameData = NamePair.Value; @@ -1504,9 +1634,13 @@ void UAssetManager::ExtractStringAssetReferences(const UStruct* Struct, const vo } } - bool UAssetManager::GetAssetDataForPath(const FStringAssetReference& ObjectPath, FAssetData& AssetData) const { + if (ObjectPath.IsNull()) + { + return false; + } + IAssetRegistry& AssetRegistry = GetAssetRegistry(); FString AssetPath = ObjectPath.ToString(); @@ -1564,7 +1698,7 @@ void UAssetManager::GetAssetDataForPathInternal(IAssetRegistry& AssetRegistry, c bool bIsClass = AssetPath.EndsWith(TEXT("_C"), ESearchCase::CaseSensitive) && !AssetPath.Contains(TEXT("_C."), ESearchCase::CaseSensitive); // If we're a class, first look for the asset data without the trailing _C - // We do this first because in cooked builds you have to search the asset registery for the Blueprint, not the class itself + // We do this first because in cooked builds you have to search the asset registry for the Blueprint, not the class itself if (bIsClass) { // We need to strip the class suffix because the asset registry has it listed by blueprint name @@ -1599,8 +1733,7 @@ bool UAssetManager::WriteCustomReport(FString FileName, TArray& FileLin { for (int32 Index = 0; Index < FileLines.Num(); ++Index) { - FString LogEntry = FString::Printf(TEXT("%s"), - *FileLines[Index]) + LINE_TERMINATOR; + FString LogEntry = FString::Printf(TEXT("%s"), *FileLines[Index]) + LINE_TERMINATOR; LogFile->Serialize(TCHAR_TO_ANSI(*LogEntry), LogEntry.Len()); } @@ -1680,17 +1813,17 @@ void UAssetManager::DumpLoadedAssetState() FPrimaryAssetTypeData& TypeData = Manager.AssetTypeMap.Find(TypeInfo.PrimaryAssetType)->Get(); - for (TPair NamePair : TypeData.AssetMap) + for (const TPair& NamePair : TypeData.AssetMap) { - FPrimaryAssetData& NameData = NamePair.Value; + const FPrimaryAssetData& NameData = NamePair.Value; if (NameData.PendingState.IsValid() || NameData.CurrentState.IsValid()) { - FPrimaryAssetLoadState& LoadState = (!NameData.PendingState.IsValid()) ? NameData.CurrentState : NameData.PendingState; + const FPrimaryAssetLoadState& LoadState = (!NameData.PendingState.IsValid()) ? NameData.CurrentState : NameData.PendingState; FString BundleString; - for (FName BundleName : LoadState.BundleNames) + for (const FName& BundleName : LoadState.BundleNames) { if (!BundleString.IsEmpty()) { @@ -1717,6 +1850,35 @@ void UAssetManager::DumpLoadedAssetState() } } +static FAutoConsoleCommand CVarDumpAssetRegistryInfo( + TEXT("AssetManager.DumpAssetRegistryInfo"), + TEXT("Dumps extended info about asset registry to log"), + FConsoleCommandDelegate::CreateStatic(UAssetManager::DumpAssetRegistryInfo), + ECVF_Cheat); + +void UAssetManager::DumpAssetRegistryInfo() +{ + UE_LOG(LogAssetManager, Log, TEXT("=========== Asset Registry Summary ===========")); + UE_LOG(LogAssetManager, Log, TEXT("Current Registry Memory:")); + + UAssetManager& Manager = Get(); + + // Output sizes + Manager.GetAssetRegistry().GetAllocatedSize(true); + +#if WITH_EDITOR + UE_LOG(LogAssetManager, Log, TEXT("Estimated Cooked Registry Memory:")); + + FAssetRegistryState State; + FAssetRegistrySerializationOptions SaveOptions; + + Manager.GetAssetRegistry().InitializeSerializationOptions(SaveOptions); + Manager.GetAssetRegistry().InitializeTemporaryAssetRegistryState(State, SaveOptions); + + State.GetAllocatedSize(true); +#endif +} + static FAutoConsoleCommand CVarDumpReferencersForPackage( TEXT("AssetManager.DumpReferencersForPackage"), TEXT("Generates a graph viz and log file of all references to a specified package"), @@ -1737,7 +1899,7 @@ void UAssetManager::DumpReferencersForPackage(const TArray< FString >& PackageNa ReportLines.Add(TEXT("digraph { ")); - for (FString PackageString : PackageNames) + for (const FString& PackageString : PackageNames) { TArray FoundReferencers; @@ -1767,13 +1929,13 @@ void UAssetManager::ScanPrimaryAssetTypesFromConfig() for (FPrimaryAssetTypeInfo TypeInfo : Settings.PrimaryAssetTypesToScan) { - // Fill out runtime data on a copy - if (!TypeInfo.FillRuntimeData()) + if (TypeInfo.bIsEditorOnly && !GIsEditor) { continue; } - if (TypeInfo.bIsEditorOnly && !GIsEditor) + // Fill out runtime data on a copy, specifically not making a reference in this case + if (!TypeInfo.FillRuntimeData()) { continue; } @@ -1782,6 +1944,7 @@ void UAssetManager::ScanPrimaryAssetTypesFromConfig() SetPrimaryAssetTypeRules(TypeInfo.PrimaryAssetType, TypeInfo.Rules); } + StopBulkScanning(); // Read primary asset rule overrides @@ -1802,6 +1965,7 @@ void UAssetManager::PostInitialAssetScan() #if WITH_EDITOR if (bUpdateManagementDatabaseAfterScan) { + bUpdateManagementDatabaseAfterScan = false; UpdateManagementDatabase(true); } #endif @@ -1827,7 +1991,7 @@ bool UAssetManager::GetManagedPackageList(FPrimaryAssetId PrimaryAssetId, TArray return bFoundAny; } -bool UAssetManager::GetPackageManagerList(FName PackageName, bool bRecurseToParents, TArray& ManagerList) const +bool UAssetManager::GetPackageManagers(FName PackageName, bool bRecurseToParents, TSet& ManagerSet) const { IAssetRegistry& AssetRegistry = GetAssetRegistry(); @@ -1842,7 +2006,7 @@ bool UAssetManager::GetPackageManagerList(FName PackageName, bool bRecurseToPare if (PrimaryAssetId.IsValid()) { bFoundAny = true; - ManagerList.AddUnique(PrimaryAssetId); + ManagerSet.Add(PrimaryAssetId); if (bRecurseToParents) { @@ -1926,9 +2090,9 @@ void UAssetManager::FinishInitialLoading() // See if we have pending scans, if so defer result bool bWaitingOnDeferredScan = false; - for (TPair> TypePair : AssetTypeMap) + for (const TPair>& TypePair : AssetTypeMap) { - FPrimaryAssetTypeData& TypeData = TypePair.Value.Get(); + const FPrimaryAssetTypeData& TypeData = TypePair.Value.Get(); if (TypeData.DeferredAssetScanPaths.Num()) { @@ -2028,7 +2192,7 @@ void UAssetManager::OnAssetRegistryFilesLoaded() { StartBulkScanning(); - for (TPair> TypePair : AssetTypeMap) + for (TPair>& TypePair : AssetTypeMap) { FPrimaryAssetTypeData& TypeData = TypePair.Value.Get(); @@ -2079,13 +2243,13 @@ void UAssetManager::UpdateManagementDatabase(bool bForceRefresh) // List of references to not recurse on, priority doesn't matter TMultiMap NoReferenceManagementMap; - for (TPair> TypePair : AssetTypeMap) + for (const TPair>& TypePair : AssetTypeMap) { - FPrimaryAssetTypeData& TypeData = TypePair.Value.Get(); + const FPrimaryAssetTypeData& TypeData = TypePair.Value.Get(); - for (TPair NamePair : TypeData.AssetMap) + for (const TPair& NamePair : TypeData.AssetMap) { - FPrimaryAssetData& NameData = NamePair.Value; + const FPrimaryAssetData& NameData = NamePair.Value; FPrimaryAssetId PrimaryAssetId(TypePair.Key, NamePair.Key); FPrimaryAssetRules Rules = GetPrimaryAssetRules(PrimaryAssetId); @@ -2107,9 +2271,9 @@ void UAssetManager::UpdateManagementDatabase(bool bForceRefresh) // Add bundle references to manual reference list if (BundleMap) { - for (TPair& BundlePair : *BundleMap) + for (const TPair& BundlePair : *BundleMap) { - for (FStringAssetReference& BundleAssetRef : BundlePair.Value.BundleAssets) + for (const FStringAssetReference& BundleAssetRef : BundlePair.Value.BundleAssets) { FString PackageName = BundleAssetRef.GetLongPackageName(); @@ -2118,7 +2282,7 @@ void UAssetManager::UpdateManagementDatabase(bool bForceRefresh) } } - for (FName AssetPackage : AssetPackagesReferenced) + for (const FName& AssetPackage : AssetPackagesReferenced) { TMultiMap& ManagerMap = Rules.bApplyRecursively ? PriorityManagementMap.FindOrAdd(Rules.Priority) : NoReferenceManagementMap; @@ -2161,15 +2325,14 @@ void UAssetManager::UpdateManagementDatabase(bool bForceRefresh) TMultiMap PrimaryAssetIdManagementMap; - // Update management parent list, which is PrimaryAssetId -> PrimaryAssetId - for (TPair> TypePair : AssetTypeMap) + for (const TPair>& TypePair : AssetTypeMap) { - FPrimaryAssetTypeData& TypeData = TypePair.Value.Get(); + const FPrimaryAssetTypeData& TypeData = TypePair.Value.Get(); - for (TPair NamePair : TypeData.AssetMap) + for (const TPair& NamePair : TypeData.AssetMap) { - FPrimaryAssetData& NameData = NamePair.Value; + const FPrimaryAssetData& NameData = NamePair.Value; FPrimaryAssetId PrimaryAssetId(TypePair.Key, NamePair.Key); const FStringAssetReference& AssetRef = NameData.AssetPtr.ToStringReference(); @@ -2177,9 +2340,9 @@ void UAssetManager::UpdateManagementDatabase(bool bForceRefresh) { FName PackageName = FName(*AssetRef.GetLongPackageName()); - TArray Managers; + TSet Managers; - if (GetPackageManagerList(PackageName, false, Managers) && Managers.Num() > 1) + if (GetPackageManagers(PackageName, false, Managers) && Managers.Num() > 1) { // Find all managers that aren't this specific asset for (const FPrimaryAssetId& Manager : Managers) @@ -2208,7 +2371,9 @@ void UAssetManager::UpdateManagementDatabase(bool bForceRefresh) void UAssetManager::ApplyPrimaryAssetLabels() { - // Load all of them off disk + // Load all of them off disk. Turn off string asset reference tracking to avoid them getting cooked + FStringAssetReferenceSerializationScope SerializationScope(NAME_None, NAME_None, EStringAssetReferenceCollectType::NeverCollect); + TSharedPtr Handle = LoadPrimaryAssetsWithType(PrimaryAssetLabelType); if (Handle.IsValid()) @@ -2219,7 +2384,7 @@ void UAssetManager::ApplyPrimaryAssetLabels() // PostLoad in PrimaryAssetLabel sets PrimaryAssetRules overrides } -void UAssetManager::ModifyCook(TArray& PackageNames) +void UAssetManager::ModifyCook(TArray& PackagesToCook, TArray& PackagesToNeverCook) { // Make sure management database is set up UpdateManagementDatabase(); @@ -2232,11 +2397,7 @@ void UAssetManager::ModifyCook(TArray& PackageNames) // Get package names in the libraries that we care about for cooking. Only get ones that are needed in production for (const FPrimaryAssetTypeInfo& TypeInfo : TypeList) { - if (TypeInfo.bIsEditorOnly) - { - continue; - } - + // Cook these types TArray AssetDataList; GetPrimaryAssetDataList(TypeInfo.PrimaryAssetType, AssetDataList); @@ -2244,9 +2405,15 @@ void UAssetManager::ModifyCook(TArray& PackageNames) { EPrimaryAssetCookRule CookRule = GetPackageCookRule(AssetData.PackageName); - if (CookRule == EPrimaryAssetCookRule::AlwaysCook) + if (CookRule == EPrimaryAssetCookRule::AlwaysCook && !TypeInfo.bIsEditorOnly) { - PackageNames.AddUnique(AssetData.PackageName); + // If this is always cook and not editor only, cook it + PackagesToCook.AddUnique(AssetData.PackageName); + } + else if (!VerifyCanCookPackage(AssetData.PackageName, false)) + { + // If this package cannot be cooked, add to exclusion list + PackagesToNeverCook.AddUnique(AssetData.PackageName); } } } @@ -2256,8 +2423,8 @@ EPrimaryAssetCookRule UAssetManager::GetPackageCookRule(FName PackageName) const { FPrimaryAssetRules BestRules; FPrimaryAssetId BestId; - TArray Managers; - GetPackageManagerList(PackageName, true, Managers); + TSet Managers; + GetPackageManagers(PackageName, true, Managers); for (const FPrimaryAssetId& PrimaryAssetId : Managers) { @@ -2324,9 +2491,9 @@ bool UAssetManager::GetPackageChunkIds(FName PackageName, const ITargetPlatform* // Add all chunk ids from the asset rules of managers. By default priority will not override other chunks bool bFoundAny = false; - TArray Managers; + TSet Managers; - GetPackageManagerList(PackageName, true, Managers); + GetPackageManagers(PackageName, true, Managers); for (const FPrimaryAssetId& PrimaryAssetId : Managers) { @@ -2365,15 +2532,14 @@ void UAssetManager::PreBeginPIE(bool bStartSimulate) void UAssetManager::EndPIE(bool bStartSimulate) { // Reset asset load state - for (TPair> TypePair : AssetTypeMap) + for (const TPair>& TypePair : AssetTypeMap) { - FPrimaryAssetTypeData& TypeData = TypePair.Value.Get(); + const FPrimaryAssetTypeData& TypeData = TypePair.Value.Get(); - for (TPair NamePair : TypeData.AssetMap) + for (const TPair& NamePair : TypeData.AssetMap) { - FPrimaryAssetData& NameData = NamePair.Value; - - FPrimaryAssetLoadState& LoadState = (!NameData.PendingState.IsValid()) ? NameData.CurrentState : NameData.PendingState; + const FPrimaryAssetData& NameData = NamePair.Value; + const FPrimaryAssetLoadState& LoadState = (!NameData.PendingState.IsValid()) ? NameData.CurrentState : NameData.PendingState; if (!LoadState.IsValid()) { @@ -2403,7 +2569,7 @@ void UAssetManager::RefreshPrimaryAssetDirectory() { StartBulkScanning(); - for (TPair> TypePair : AssetTypeMap) + for (TPair>& TypePair : AssetTypeMap) { FPrimaryAssetTypeData& TypeData = TypePair.Value.Get(); @@ -2422,10 +2588,23 @@ void UAssetManager::RefreshPrimaryAssetDirectory() PostInitialAssetScan(); } +void UAssetManager::ReinitializeFromConfig() +{ + AssetPathMap.Reset(); + AssetRuleOverrides.Reset(); + ManagementParentMap.Reset(); + CachedAssetBundles.Reset(); + AlreadyScannedDirectories.Reset(); + AssetTypeMap.Reset(); + + LoadRedirectorMaps(); + ScanPrimaryAssetTypesFromConfig(); +} + void UAssetManager::OnInMemoryAssetCreated(UObject *Object) { - // Ignore PIE changes - if (GIsPlayInEditorWorld || !Object) + // Ignore PIE and CDO changes + if (GIsPlayInEditorWorld || !Object || Object->HasAnyFlags(RF_ClassDefaultObject)) { return; } @@ -2494,6 +2673,12 @@ void UAssetManager::OnAssetRenamed(const FAssetData& NewData, const FString& Old FPrimaryAssetId OldPrimaryAssetId = GetPrimaryAssetIdForPath(OldPath); + // This may be a blueprint, try with _C + if (!OldPrimaryAssetId.IsValid()) + { + OldPrimaryAssetId = GetPrimaryAssetIdForPath(OldPath + TEXT("_C")); + } + RemovePrimaryAssetId(OldPrimaryAssetId); // This will always be in memory @@ -2520,22 +2705,54 @@ void UAssetManager::RemovePrimaryAssetId(const FPrimaryAssetId& PrimaryAssetId) void UAssetManager::RefreshAssetData(UObject* ChangedObject) { - // Only update things it knows about - FPrimaryAssetId PrimaryAssetId = ChangedObject->GetPrimaryAssetId(); - FStringAssetReference ChangedObjectPath(ChangedObject); - - if (PrimaryAssetId.IsValid() && GetPrimaryAssetPath(PrimaryAssetId) == ChangedObjectPath) + // If this is a BP CDO, call on class instead + if (ChangedObject->HasAnyFlags(RF_ClassDefaultObject)) { - IAssetRegistry& AssetRegistry = GetAssetRegistry(); + UBlueprintGeneratedClass* AssetClass = Cast(ChangedObject->GetClass()); + if (AssetClass) + { + RefreshAssetData(AssetClass); + } + return; + } - // This will load it out of the in memory object + // Only update things it knows about + IAssetRegistry& AssetRegistry = GetAssetRegistry(); + FStringAssetReference ChangedObjectPath(ChangedObject); + FPrimaryAssetId PrimaryAssetId = ChangedObject->GetPrimaryAssetId(); + FPrimaryAssetId OldPrimaryAssetId = GetPrimaryAssetIdForPath(ChangedObjectPath); + + // This may be a blueprint, try with _C + if (!OldPrimaryAssetId.IsValid()) + { + OldPrimaryAssetId = GetPrimaryAssetIdForPath(ChangedObjectPath.ToString() + TEXT("_C")); + } + + if (PrimaryAssetId.IsValid() && OldPrimaryAssetId == PrimaryAssetId) + { + // Same AssetId, this will update cache out of the in memory object FAssetData NewData; GetAssetDataForPathInternal(AssetRegistry, ChangedObjectPath.ToString(), NewData); if (ensure(NewData.IsValid())) { UpdateCachedAssetData(PrimaryAssetId, NewData, false); - } + } + } + else + { + // AssetId changed + if (OldPrimaryAssetId.IsValid()) + { + // Remove old id if it was registered + RemovePrimaryAssetId(OldPrimaryAssetId); + } + + if (PrimaryAssetId.IsValid()) + { + // This will add new id + OnInMemoryAssetCreated(ChangedObject); + } } } diff --git a/Engine/Source/Runtime/Engine/Private/AssetManagerTypes.cpp b/Engine/Source/Runtime/Engine/Private/AssetManagerTypes.cpp index c113f74bb5ba..1748979e43a2 100644 --- a/Engine/Source/Runtime/Engine/Private/AssetManagerTypes.cpp +++ b/Engine/Source/Runtime/Engine/Private/AssetManagerTypes.cpp @@ -2,6 +2,7 @@ #include "Engine/AssetManagerTypes.h" #include "Engine/AssetManager.h" +#include "Engine/AssetManagerSettings.h" bool FPrimaryAssetTypeInfo::FillRuntimeData() { @@ -14,12 +15,30 @@ bool FPrimaryAssetTypeInfo::FillRuntimeData() for (const FStringAssetReference& AssetRef : SpecificAssets) { - AssetScanPaths.AddUnique(AssetRef.ToString()); + if (!AssetRef.IsNull()) + { + AssetScanPaths.AddUnique(AssetRef.ToString()); + } } for (const FDirectoryPath& PathRef : Directories) { - AssetScanPaths.AddUnique(PathRef.Path); + if (!PathRef.Path.IsEmpty()) + { + AssetScanPaths.AddUnique(PathRef.Path); + } + } + + if (AssetScanPaths.Num() == 0) + { + // No scan locations picked out + return false; + } + + if (PrimaryAssetType == NAME_None) + { + // Invalid type + return false; } return true; @@ -68,4 +87,15 @@ void FPrimaryAssetRules::PropagateCookRules(const FPrimaryAssetRules& ParentRule { CookRule = ParentRules.CookRule; } -} \ No newline at end of file +} + +#if WITH_EDITOR +void UAssetManagerSettings::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) +{ + Super::PostEditChangeProperty(PropertyChangedEvent); + if (PropertyChangedEvent.Property && UAssetManager::IsValid()) + { + UAssetManager::Get().ReinitializeFromConfig(); + } +} +#endif \ No newline at end of file diff --git a/Engine/Source/Runtime/Engine/Private/AsyncActionLoadPrimaryAsset.cpp b/Engine/Source/Runtime/Engine/Private/AsyncActionLoadPrimaryAsset.cpp new file mode 100644 index 000000000000..92b29a7b6c44 --- /dev/null +++ b/Engine/Source/Runtime/Engine/Private/AsyncActionLoadPrimaryAsset.cpp @@ -0,0 +1,169 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "AsyncActionLoadPrimaryAsset.h" +#include "Engine/AssetManager.h" + +void UAsyncActionLoadPrimaryAssetBase::Activate() +{ + if (UAssetManager* Manager = UAssetManager::GetIfValid()) + { + switch (Operation) + { + case EAssetManagerOperation::Load: + LoadHandle = Manager->LoadPrimaryAssets(AssetsToLoad, LoadBundles); + break; + case EAssetManagerOperation::ChangeBundleStateMatching: + LoadHandle = Manager->ChangeBundleStateForMatchingPrimaryAssets(LoadBundles, OldBundles); + break; + case EAssetManagerOperation::ChangeBundleStateList: + LoadHandle = Manager->ChangeBundleStateForPrimaryAssets(AssetsToLoad, LoadBundles, OldBundles); + break; + } + + if (LoadHandle.IsValid()) + { + if (!LoadHandle->HasLoadCompleted()) + { + LoadHandle->BindCompleteDelegate(FStreamableDelegate::CreateUObject(this, &UAsyncActionLoadPrimaryAssetBase::HandleLoadCompleted)); + return; + } + } + } + + // Either load already succeeded, or it failed + HandleLoadCompleted(); +} + +void UAsyncActionLoadPrimaryAssetBase::HandleLoadCompleted() +{ + LoadHandle.Reset(); + SetReadyToDestroy(); +} + +UAsyncActionLoadPrimaryAsset* UAsyncActionLoadPrimaryAsset::AsyncLoadPrimaryAsset(FPrimaryAssetId PrimaryAsset, const TArray& LoadBundles) +{ + UAsyncActionLoadPrimaryAsset* Action = NewObject(); + Action->AssetsToLoad.Add(PrimaryAsset); + Action->LoadBundles = LoadBundles; + Action->Operation = EAssetManagerOperation::Load; + + return Action; +} + +void UAsyncActionLoadPrimaryAsset::HandleLoadCompleted() +{ + UObject* AssetLoaded = nullptr; + if (LoadHandle.IsValid()) + { + AssetLoaded = LoadHandle->GetLoadedAsset(); + } + + Super::HandleLoadCompleted(); + Completed.Broadcast(AssetLoaded); +} + +UAsyncActionLoadPrimaryAssetClass* UAsyncActionLoadPrimaryAssetClass::AsyncLoadPrimaryAssetClass(FPrimaryAssetId PrimaryAsset, const TArray& LoadBundles) +{ + UAsyncActionLoadPrimaryAssetClass* Action = NewObject(); + Action->AssetsToLoad.Add(PrimaryAsset); + Action->LoadBundles = LoadBundles; + Action->Operation = EAssetManagerOperation::Load; + + return Action; +} + +void UAsyncActionLoadPrimaryAssetClass::HandleLoadCompleted() +{ + TSubclassOf AssetLoaded = nullptr; + if (LoadHandle.IsValid()) + { + AssetLoaded = Cast(LoadHandle->GetLoadedAsset()); + } + + Super::HandleLoadCompleted(); + Completed.Broadcast(AssetLoaded); +} + +UAsyncActionLoadPrimaryAssetList* UAsyncActionLoadPrimaryAssetList::AsyncLoadPrimaryAssetList(const TArray& PrimaryAssetList, const TArray& LoadBundles) +{ + UAsyncActionLoadPrimaryAssetList* Action = NewObject(); + Action->AssetsToLoad = PrimaryAssetList; + Action->LoadBundles = LoadBundles; + Action->Operation = EAssetManagerOperation::Load; + + return Action; +} + +void UAsyncActionLoadPrimaryAssetList::HandleLoadCompleted() +{ + TArray AssetList; + + if (LoadHandle.IsValid()) + { + LoadHandle->GetLoadedAssets(AssetList); + } + + Super::HandleLoadCompleted(); + Completed.Broadcast(AssetList); +} + +UAsyncActionLoadPrimaryAssetClassList* UAsyncActionLoadPrimaryAssetClassList::AsyncLoadPrimaryAssetClassList(const TArray& PrimaryAssetList, const TArray& LoadBundles) +{ + UAsyncActionLoadPrimaryAssetClassList* Action = NewObject(); + Action->AssetsToLoad = PrimaryAssetList; + Action->LoadBundles = LoadBundles; + Action->Operation = EAssetManagerOperation::Load; + + return Action; +} + +void UAsyncActionLoadPrimaryAssetClassList::HandleLoadCompleted() +{ + TArray> AssetClassList; + TArray AssetList; + + if (LoadHandle.IsValid()) + { + LoadHandle->GetLoadedAssets(AssetList); + + for (UObject* LoadedAsset : AssetList) + { + UClass* LoadedClass = Cast(LoadedAsset); + + if (LoadedClass) + { + AssetClassList.Add(LoadedClass); + } + } + } + + Super::HandleLoadCompleted(); + Completed.Broadcast(AssetClassList); +} + +UAsyncActionChangePrimaryAssetBundles* UAsyncActionChangePrimaryAssetBundles::AsyncChangeBundleStateForMatchingPrimaryAssets(const TArray& NewBundles, const TArray& OldBundles) +{ + UAsyncActionChangePrimaryAssetBundles* Action = NewObject(); + Action->LoadBundles = NewBundles; + Action->OldBundles = OldBundles; + Action->Operation = EAssetManagerOperation::ChangeBundleStateMatching; + + return Action; +} + +UAsyncActionChangePrimaryAssetBundles* UAsyncActionChangePrimaryAssetBundles::AsyncChangeBundleStateForPrimaryAssetList(const TArray& PrimaryAssetList, const TArray& AddBundles, const TArray& RemoveBundles) +{ + UAsyncActionChangePrimaryAssetBundles* Action = NewObject(); + Action->LoadBundles = AddBundles; + Action->OldBundles = RemoveBundles; + Action->AssetsToLoad = PrimaryAssetList; + Action->Operation = EAssetManagerOperation::ChangeBundleStateList; + + return Action; +} + +void UAsyncActionChangePrimaryAssetBundles::HandleLoadCompleted() +{ + Super::HandleLoadCompleted(); + Completed.Broadcast(); +} \ No newline at end of file diff --git a/Engine/Source/Runtime/Engine/Private/AsyncActionLoadPrimaryAsset.h b/Engine/Source/Runtime/Engine/Private/AsyncActionLoadPrimaryAsset.h new file mode 100644 index 000000000000..33dfade4b94b --- /dev/null +++ b/Engine/Source/Runtime/Engine/Private/AsyncActionLoadPrimaryAsset.h @@ -0,0 +1,174 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "Engine/StreamableManager.h" +#include "Kismet/BlueprintAsyncActionBase.h" +#include "Templates/SubclassOf.h" + +#include "AsyncActionLoadPrimaryAsset.generated.h" + +/** Base class of all asset manager load calls */ +UCLASS(Abstract) +class UAsyncActionLoadPrimaryAssetBase : public UBlueprintAsyncActionBase +{ + GENERATED_BODY() + +public: + /** Execute the actual load */ + virtual void Activate() override; + +protected: + + /** Called from asset manager */ + virtual void HandleLoadCompleted(); + + /** Specific assets requested */ + TArray AssetsToLoad; + + /** Bundle states */ + TArray LoadBundles; + + /** Bundle states */ + TArray OldBundles; + + /** Handle of load request */ + TSharedPtr LoadHandle; + + enum class EAssetManagerOperation : uint8 + { + Load, + ChangeBundleStateMatching, + ChangeBundleStateList + }; + + /** Which operation is being run */ + EAssetManagerOperation Operation; +}; + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnPrimaryAssetLoaded, UObject*, Loaded); + +UCLASS() +class UAsyncActionLoadPrimaryAsset : public UAsyncActionLoadPrimaryAssetBase +{ + GENERATED_BODY() + +public: + /** + * Load a primary asset into memory. The completed delegate will go off when the load succeeds or fails, you should cast the Loaded object to verify it is the correct type. + * If LoadBundles is specified, those bundles are loaded along with the asset + */ + UFUNCTION(BlueprintCallable, meta=(BlueprintInternalUseOnly="true", Category = "AssetManager", AutoCreateRefTerm = "LoadBundles")) + static UAsyncActionLoadPrimaryAsset* AsyncLoadPrimaryAsset(FPrimaryAssetId PrimaryAsset, const TArray& LoadBundles); + + UPROPERTY(BlueprintAssignable) + FOnPrimaryAssetLoaded Completed; + +protected: + + /** Called from asset manager */ + virtual void HandleLoadCompleted() override; +}; + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnPrimaryAssetClassLoaded, TSubclassOf, Loaded); + +UCLASS() +class UAsyncActionLoadPrimaryAssetClass : public UAsyncActionLoadPrimaryAssetBase +{ + GENERATED_BODY() + +public: + /** + * Load a primary asset class into memory. The completed delegate will go off when the load succeeds or fails, you should cast the Loaded class to verify it is the correct type + * If LoadBundles is specified, those bundles are loaded along with the asset + */ + UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true", Category = "AssetManager", AutoCreateRefTerm = "LoadBundles")) + static UAsyncActionLoadPrimaryAssetClass* AsyncLoadPrimaryAssetClass(FPrimaryAssetId PrimaryAsset, const TArray& LoadBundles); + + UPROPERTY(BlueprintAssignable) + FOnPrimaryAssetClassLoaded Completed; + +protected: + + /** Called from asset manager */ + virtual void HandleLoadCompleted() override; +}; + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnPrimaryAssetListLoaded, const TArray&, Loaded); + +UCLASS() +class UAsyncActionLoadPrimaryAssetList : public UAsyncActionLoadPrimaryAssetBase +{ + GENERATED_BODY() + +public: + /** + * Load a list primary assets into memory. The completed delegate will go off when the load succeeds or fails, you should cast the Loaded object list to verify it is the correct type + * If LoadBundles is specified, those bundles are loaded along with the asset list + */ + UFUNCTION(BlueprintCallable, meta=(BlueprintInternalUseOnly="true", Category = "AssetManager", AutoCreateRefTerm = "LoadBundles")) + static UAsyncActionLoadPrimaryAssetList* AsyncLoadPrimaryAssetList(const TArray& PrimaryAssetList, const TArray& LoadBundles); + + UPROPERTY(BlueprintAssignable) + FOnPrimaryAssetListLoaded Completed; + +protected: + + /** Called from asset manager */ + virtual void HandleLoadCompleted() override; +}; + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnPrimaryAssetClassListLoaded, const TArray>&, Loaded); + +UCLASS() +class UAsyncActionLoadPrimaryAssetClassList : public UAsyncActionLoadPrimaryAssetBase +{ + GENERATED_BODY() + +public: + /** + * Load a list primary asset classes into memory. The completed delegate will go off when the load succeeds or fails, you should cast the Loaded object list to verify it is the correct type + * If LoadBundles is specified, those bundles are loaded along with the asset list + */ + UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true", Category = "AssetManager", AutoCreateRefTerm = "LoadBundles")) + static UAsyncActionLoadPrimaryAssetClassList* AsyncLoadPrimaryAssetClassList(const TArray& PrimaryAssetList, const TArray& LoadBundles); + + UPROPERTY(BlueprintAssignable) + FOnPrimaryAssetClassListLoaded Completed; + +protected: + + /** Called from asset manager */ + virtual void HandleLoadCompleted() override; +}; + +DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnPrimaryAssetBundlesChanged); + +UCLASS() +class UAsyncActionChangePrimaryAssetBundles : public UAsyncActionLoadPrimaryAssetBase +{ + GENERATED_BODY() + +public: + /** + * Change the bundle state of all assets that match OldBundles to instead contain NewBundles. + */ + UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true", Category = "AssetManager")) + static UAsyncActionChangePrimaryAssetBundles* AsyncChangeBundleStateForMatchingPrimaryAssets(const TArray& NewBundles, const TArray& OldBundles); + + /** + * Change the bundle state of assets in PrimaryAssetList. AddBundles are added and RemoveBundles are removed, both must be filled in but an empty array is allowed + */ + UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true", Category = "AssetManager")) + static UAsyncActionChangePrimaryAssetBundles* AsyncChangeBundleStateForPrimaryAssetList(const TArray& PrimaryAssetList, const TArray& AddBundles, const TArray& RemoveBundles); + + UPROPERTY(BlueprintAssignable) + FOnPrimaryAssetBundlesChanged Completed; + +protected: + + /** Called from asset manager */ + virtual void HandleLoadCompleted() override; +}; diff --git a/Engine/Source/Runtime/Engine/Private/Atmosphere/Atmosphere.cpp b/Engine/Source/Runtime/Engine/Private/Atmosphere/Atmosphere.cpp index 2f9481ae9351..382185914bc7 100644 --- a/Engine/Source/Runtime/Engine/Private/Atmosphere/Atmosphere.cpp +++ b/Engine/Source/Runtime/Engine/Private/Atmosphere/Atmosphere.cpp @@ -870,9 +870,3 @@ static void AtmosphereRenderSinkFunction() FAutoConsoleVariableSink CVarAtmosphereRenderSink(FConsoleCommandDelegate::CreateStatic(&AtmosphereRenderSinkFunction)); -/** Returns AtmosphericFogComponent subobject **/ -UAtmosphericFogComponent* AAtmosphericFog::GetAtmosphericFogComponent() { return AtmosphericFogComponent; } -#if WITH_EDITORONLY_DATA -/** Returns ArrowComponent subobject **/ -UArrowComponent* AAtmosphericFog::GetArrowComponent() { return ArrowComponent; } -#endif diff --git a/Engine/Source/Runtime/Engine/Private/Audio.cpp b/Engine/Source/Runtime/Engine/Private/Audio.cpp index fe499370f60c..8c76b9ed2378 100644 --- a/Engine/Source/Runtime/Engine/Private/Audio.cpp +++ b/Engine/Source/Runtime/Engine/Private/Audio.cpp @@ -196,15 +196,13 @@ void FSoundSource::Stop() if (WaveInstance) { check(AudioDevice); - AudioDevice->FreeSources.AddUnique(this); AudioDevice->WaveInstanceSourceMap.Remove(WaveInstance); WaveInstance->NotifyFinished(true); WaveInstance = nullptr; } - else - { - check(AudioDevice->FreeSources.Find(this) != INDEX_NONE); - } + + // Remove this source from free list regardless of if this had a wave instance created + AudioDevice->FreeSources.AddUnique(this); } void FSoundSource::SetPauseByGame(bool bInIsPauseByGame) @@ -705,7 +703,6 @@ FWaveInstance::FWaveInstance( FActiveSound* InActiveSound ) , AmbientZoneFilterFrequency(MAX_FILTER_FREQUENCY) , AttenuationFilterFrequency(MAX_FILTER_FREQUENCY) , Pitch(0.0f) - , Velocity(FVector::ZeroVector) , Location(FVector::ZeroVector) , OmniRadius(0.0f) , StereoSpread(0.0f) diff --git a/Engine/Source/Runtime/Engine/Private/AudioDecompress.cpp b/Engine/Source/Runtime/Engine/Private/AudioDecompress.cpp index 71c1c8cf46b7..62c82aede8d3 100644 --- a/Engine/Source/Runtime/Engine/Private/AudioDecompress.cpp +++ b/Engine/Source/Runtime/Engine/Private/AudioDecompress.cpp @@ -22,6 +22,7 @@ IStreamedCompressedInfo::IStreamedCompressedInfo() , bStoringEndOfFile(false) , StreamingSoundWave(nullptr) , CurrentChunkIndex(0) + , bPrintChunkFailMessage(true) { } @@ -184,13 +185,18 @@ bool IStreamedCompressedInfo::StreamCompressedData(uint8* Destination, bool bLoo SrcBufferData = IStreamingManager::Get().GetAudioStreamingManager().GetLoadedChunk(StreamingSoundWave, CurrentChunkIndex); if (SrcBufferData) { + bPrintChunkFailMessage = true; SrcBufferDataSize = StreamingSoundWave->RunningPlatformData->Chunks[CurrentChunkIndex].DataSize; SrcBufferOffset = CurrentChunkIndex == 0 ? AudioDataOffset : 0; } else { // Still not loaded, zero remainder of current buffer - UE_LOG(LogAudio, Warning, TEXT("Unable to read from chunk %d of SoundWave'%s'"), CurrentChunkIndex, *StreamingSoundWave->GetName()); + if (bPrintChunkFailMessage) + { + UE_LOG(LogAudio, Verbose, TEXT("Chunk %d not loaded from streaming manager for SoundWave '%s'. Likely due to stall on game thread."), CurrentChunkIndex, *StreamingSoundWave->GetName()); + bPrintChunkFailMessage = false; + } ZeroBuffer(Destination + RawPCMOffset, BufferSize - RawPCMOffset); return false; } diff --git a/Engine/Source/Runtime/Engine/Private/AudioDevice.cpp b/Engine/Source/Runtime/Engine/Private/AudioDevice.cpp index 8ed3152c37ff..b4948dcfdf3d 100644 --- a/Engine/Source/Runtime/Engine/Private/AudioDevice.cpp +++ b/Engine/Source/Runtime/Engine/Private/AudioDevice.cpp @@ -105,11 +105,7 @@ void FDynamicParameter::Update(float DeltaTime) -----------------------------------------------------------------------------*/ FAudioDevice::FAudioDevice() - : MaxChannels(0) - , NumSourceWorkers(0) - , SampleRate(AUDIO_SAMPLE_RATE) - , DeviceOutputBufferLength(0) - , CommonAudioPool(nullptr) + : CommonAudioPool(nullptr) , CommonAudioPoolFreeBytes(0) , DeviceHandle(INDEX_NONE) , AudioPlugin(nullptr) @@ -174,31 +170,17 @@ bool FAudioDevice::Init(int32 InMaxChannels) bool bDeferStartupPrecache = false; - // initialize config variables - MaxChannels = InMaxChannels; + // initialize max channels taking into account platform configurations + // Get a copy of the platform-specific settings (overriden by platforms) + PlatformSettings = GetPlatformSettings(); - // Setup the desired sample rate and buffer length - DeviceOutputBufferLength = 1024; + // MaxChannels is the min of the platform-specific value and the max value in the quality settings (InMaxChannels) + MaxChannels = PlatformSettings.MaxChannels > 0 ? FMath::Min(PlatformSettings.MaxChannels, InMaxChannels) : InMaxChannels; - int32 ConfigBufferLength = 0; - if (GConfig->GetInt(TEXT("Audio"), TEXT("AudioMixerBufferLength"), ConfigBufferLength, GEngineIni)) - { - // only allow power of 2 buffer size - ConfigBufferLength = FMath::RoundUpToPowerOfTwo(ConfigBufferLength); + // Mixed sample rate is set by the platform + SampleRate = PlatformSettings.SampleRate; - // use a min buffer length of 128 - DeviceOutputBufferLength = FMath::Max(128, ConfigBufferLength); - } - - // Setup the number of desired source workers - NumSourceWorkers = 4; - - int32 ConfigSourceWorkers = 0; - if (GConfig->GetInt(TEXT("Audio"), TEXT("AudioMixerSourceWorkers"), ConfigSourceWorkers, GEngineIni)) - { - // Only allow workers in the range of our channels... - NumSourceWorkers = FMath::Clamp(ConfigSourceWorkers, 0, MaxChannels); - } + check(MaxChannels != 0); verify(GConfig->GetInt(TEXT("Audio"), TEXT("CommonAudioPoolSize"), CommonAudioPoolSize, GEngineIni)); @@ -229,7 +211,7 @@ bool FAudioDevice::Init(int32 InMaxChannels) InitSoundClasses(); InitSoundEffectPresets(); -// // Audio mixer needs to create effects manager before initing the plugins + // Audio mixer needs to create effects manager before initializing the plugins. if (IsAudioMixerEnabled()) { // create a platform specific effects manager @@ -255,7 +237,6 @@ bool FAudioDevice::Init(int32 InMaxChannels) // Initialize the plugin Plugin->Initialize(); - // Create feature override interfaces. Note these can be null if the audio plugin is not creating an override for the feature. SpatializationPluginInterface = Plugin->CreateSpatializationInterface(this); @@ -951,27 +932,14 @@ bool FAudioDevice::HandleResetSoundStateCommand(const TCHAR* Cmd, FOutputDevice& bool FAudioDevice::HandleToggleSpatializationExtensionCommand(const TCHAR* Cmd, FOutputDevice& Ar) { - FAudioThread::SuspendAudioThread(); - - bSpatializationInterfaceEnabled = !bSpatializationInterfaceEnabled; - - FAudioThread::ResumeAudioThread(); + SetSpatializationInterfaceEnabled(!bSpatializationInterfaceEnabled); return true; } bool FAudioDevice::HandleEnableHRTFForAllCommand(const TCHAR* Cmd, FOutputDevice& Ar) { - const bool bNewHRTFEnabledForAll = !bHRTFEnabledForAll_OnGameThread; - - bHRTFEnabledForAll_OnGameThread = bNewHRTFEnabledForAll; - - FAudioDevice* AudioDevice = this; - FAudioThread::RunCommandOnAudioThread([AudioDevice, bNewHRTFEnabledForAll]() - { - AudioDevice->bHRTFEnabledForAll = bNewHRTFEnabledForAll; - - }); + SetHRTFEnabledForAll(!bHRTFEnabledForAll_OnGameThread); return true; } @@ -3061,8 +3029,7 @@ void FAudioDevice::StartSources(TArray& WaveInstances, int32 Fir // This can happen if e.g. the USoundWave pointed to by the WaveInstance is not a valid sound file. // If we don't stop the wave file, it will continue to try initializing the file every frame, which is a perf hit UE_LOG(LogAudio, Warning, TEXT("Failed to start sound source for %s"), (WaveInstance->ActiveSound && WaveInstance->ActiveSound->Sound) ? *WaveInstance->ActiveSound->Sound->GetName() : TEXT("UNKNOWN") ); - WaveInstance->StopWithoutNotification(); - FreeSources.Add(Source); + Source->Stop(); } } else if (Source) @@ -3096,7 +3063,7 @@ void FAudioDevice::StartSources(TArray& WaveInstances, int32 Fir } } } - else if (!Source) + else { // This can happen if the streaming manager determines that this sound should not be started. // We stop the wave instance to prevent it from attempting to initialize every frame @@ -3221,8 +3188,13 @@ void FAudioDevice::Update(bool bGameTicking) UpdatePassiveSoundMixModifiers(ActiveWaveInstances, FirstActiveIndex); - // Update the playback time of the active sounds after we've processed passive mix modifiers - UpdateActiveSoundPlaybackTime(); + // If not paused, update the playback time of the active sounds after we've processed passive mix modifiers + // Note that for sounds which play while paused, this will result in longer active sound playback times, which will be ok. If we update the + // active sound is updated while paused (for a long time), most sounds will be stopped when unpaused. + if (bGameTicking) + { + UpdateActiveSoundPlaybackTime(); + } const int32 Channels = GetMaxChannels(); INC_DWORD_STAT_BY(STAT_WaveInstances, ActiveWaveInstances.Num()); diff --git a/Engine/Source/Runtime/Engine/Private/AudioDeviceManager.cpp b/Engine/Source/Runtime/Engine/Private/AudioDeviceManager.cpp index ad7d26442ef0..a07c2a8038a8 100644 --- a/Engine/Source/Runtime/Engine/Private/AudioDeviceManager.cpp +++ b/Engine/Source/Runtime/Engine/Private/AudioDeviceManager.cpp @@ -144,7 +144,7 @@ bool FAudioDeviceManager::CreateAudioDevice(bool bCreateNewDevice, FCreateAudioD ++NumActiveAudioDevices; const UAudioSettings* AudioSettings = GetDefault(); - if (!OutResults.AudioDevice->Init(AudioSettings->GetQualityLevelSettings(GEngine->GetGameUserSettings()->GetAudioQualityLevel()).MaxChannels)) + if (!OutResults.AudioDevice->Init(AudioSettings->GetQualityLevelSettings(GEngine->GetGameUserSettings()->GetAudioQualityLevel()).MaxChannels)) //-V595 { ShutdownAudioDevice(OutResults.Handle); OutResults = FCreateAudioDeviceResults(); diff --git a/Engine/Source/Runtime/Engine/Private/AudioSettings.cpp b/Engine/Source/Runtime/Engine/Private/AudioSettings.cpp index e87e175437c0..0a677c4d1772 100644 --- a/Engine/Source/Runtime/Engine/Private/AudioSettings.cpp +++ b/Engine/Source/Runtime/Engine/Private/AudioSettings.cpp @@ -14,6 +14,40 @@ #define LOCTEXT_NAMESPACE "AudioSettings" +FAudioPlatformSettings FAudioPlatformSettings::GetPlatformSettings(const TCHAR* PlatformSettingsConfigFile) +{ + FAudioPlatformSettings Settings; + + FString TempString; + + if (GConfig->GetString(PlatformSettingsConfigFile, TEXT("AudioSampleRate"), TempString, GEngineIni)) + { + Settings.SampleRate = FMath::Max(FCString::Atoi(*TempString), 8000); + } + + if (GConfig->GetString(PlatformSettingsConfigFile, TEXT("AudioCallbackBufferFrameSize"), TempString, GEngineIni)) + { + Settings.CallbackBufferFrameSize = FMath::Max(FCString::Atoi(*TempString), 256); + } + + if (GConfig->GetString(PlatformSettingsConfigFile, TEXT("AudioNumBuffersToEnqueue"), TempString, GEngineIni)) + { + Settings.NumBuffers = FMath::Max(FCString::Atoi(*TempString), 1); + } + + if (GConfig->GetString(PlatformSettingsConfigFile, TEXT("AudioMaxChannels"), TempString, GEngineIni)) + { + Settings.MaxChannels = FMath::Max(FCString::Atoi(*TempString), 0); + } + + if (GConfig->GetString(PlatformSettingsConfigFile, TEXT("AudioNumSourceWorkers"), TempString, GEngineIni)) + { + Settings.NumSourceWorkers = FMath::Max(FCString::Atoi(*TempString), 0); + } + + return Settings; +} + UAudioSettings::UAudioSettings(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { @@ -21,6 +55,7 @@ UAudioSettings::UAudioSettings(const FObjectInitializer& ObjectInitializer) AddDefaultSettings(); bAllowVirtualizedSounds = true; + bIsAudioMixerEnabled = false; } void UAudioSettings::AddDefaultSettings() @@ -102,4 +137,14 @@ const FAudioQualitySettings& UAudioSettings::GetQualityLevelSettings(int32 Quali return QualityLevels[FMath::Clamp(QualityLevel, 0, QualityLevels.Num() - 1)]; } +void UAudioSettings::SetAudioMixerEnabled(const bool bInAudioMixerEnabled) +{ + bIsAudioMixerEnabled = bInAudioMixerEnabled; +} + +const bool UAudioSettings::IsAudioMixerEnabled() const +{ + return bIsAudioMixerEnabled; +} + #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Runtime/Engine/Private/AudioStreaming.cpp b/Engine/Source/Runtime/Engine/Private/AudioStreaming.cpp index 61ab69919cd0..d3b3ef627318 100644 --- a/Engine/Source/Runtime/Engine/Private/AudioStreaming.cpp +++ b/Engine/Source/Runtime/Engine/Private/AudioStreaming.cpp @@ -13,6 +13,17 @@ AudioStreaming.cpp: Implementation of audio streaming classes. #include "HAL/PlatformFile.h" #include "HAL/PlatformFilemanager.h" #include "AsyncFileHandle.h" +#include "Misc/ScopeLock.h" +#include "HAL/IConsoleManager.h" + +static int32 SpoofFailedStreamChunkLoad = 0; +FAutoConsoleVariableRef CVarSpoofFailedStreamChunkLoad( + TEXT("au.SpoofFailedStreamChunkLoad"), + SpoofFailedStreamChunkLoad, + TEXT("Forces failing to load streamed chunks.\n") + TEXT("0: Not Enabled, 1: Enabled"), + ECVF_Default); + /*------------------------------------------------------------------------------ Streaming chunks from the derived data cache. @@ -71,6 +82,7 @@ void FAsyncStreamDerivedChunkWorker::DoWork() FStreamingWaveData::FStreamingWaveData() : SoundWave(NULL) , IORequestHandle(nullptr) + , AudioStreamingManager(nullptr) { } @@ -97,16 +109,24 @@ FStreamingWaveData::~FStreamingWaveData() } } -void FStreamingWaveData::Initialize(USoundWave* InSoundWave) +void FStreamingWaveData::Initialize(USoundWave* InSoundWave, FAudioStreamingManager* InAudioStreamingManager) { check(!IORequestHandle); SoundWave = InSoundWave; + AudioStreamingManager = InAudioStreamingManager; // Always get the first chunk of data so we can play immediately check(LoadedChunks.Num() == 0); check(LoadedChunkIndices.Num() == 0); - FLoadedAudioChunk* FirstChunk = AddNewLoadedChunk(SoundWave->RunningPlatformData->Chunks[0].DataSize); + + // Prepare 4 chunks of streaming wave data in loaded chunks array + LoadedChunks.Reset(4); + + const int32 FirstLoadedChunkIndex = AddNewLoadedChunk(SoundWave->RunningPlatformData->Chunks[0].DataSize); + + FLoadedAudioChunk* FirstChunk = &LoadedChunks[FirstLoadedChunkIndex]; + FirstChunk->Index = 0; SoundWave->GetChunkData(0, &FirstChunk->Data); @@ -249,10 +269,13 @@ void FStreamingWaveData::BeginPendingRequests(const TArray& IndicesToLoa const FStreamedAudioChunk& Chunk = SoundWave->RunningPlatformData->Chunks[Index]; int32 ChunkSize = Chunk.DataSize; - FLoadedAudioChunk* ChunkStorage = nullptr; - ChunkStorage = AddNewLoadedChunk(ChunkSize); + int32 LoadedChunkStorageIndex = AddNewLoadedChunk(ChunkSize); + FLoadedAudioChunk* ChunkStorage = &LoadedChunks[LoadedChunkStorageIndex]; + ChunkStorage->Index = Index; + check(LoadedChunkStorageIndex != INDEX_NONE); + // Pass the request on to the async io manager after increasing the request count. The request count // has been pre-incremented before fielding the update request so we don't have to worry about file // I/O immediately completing and the game thread kicking off again before this function @@ -292,25 +315,19 @@ void FStreamingWaveData::BeginPendingRequests(const TArray& IndicesToLoa check(Chunk.BulkData.GetBulkDataSize() == ChunkStorage->DataSize); FAsyncFileCallBack AsyncFileCallBack = - [this, ChunkStorage](bool bWasCancelled, IAsyncReadRequest* Req) + [this, LoadedChunkStorageIndex](bool bWasCancelled, IAsyncReadRequest* Req) { - FLoadedAudioChunk& LoadedChunk = *ChunkStorage; - uint8* Mem = Req->GetReadResults(); - if (Mem) - { - check(!LoadedChunk.Data); - LoadedChunk.Data = Mem; - DEC_MEMORY_STAT_BY(STAT_AsyncFileMemory, LoadedChunk.DataSize); - INC_DWORD_STAT_BY(STAT_AudioMemorySize, LoadedChunk.DataSize); - INC_DWORD_STAT_BY(STAT_AudioMemory, LoadedChunk.DataSize); - } - // else was canceled + AudioStreamingManager->OnAsyncFileCallback(this, LoadedChunkStorageIndex, Req); + PendingChunkChangeRequestStatus.Decrement(); }; + check(!ChunkStorage->Data); ChunkStorage->IORequest = IORequestHandle->ReadRequest(Chunk.BulkData.GetBulkDataOffsetInFile(), ChunkStorage->DataSize, AsyncIOPriority, &AsyncFileCallBack); if (!ChunkStorage->IORequest) { + UE_LOG(LogAudio, Error, TEXT("Audio streaming read request failed.")); + // we failed for some reason; file not found I guess. PendingChunkChangeRequestStatus.Decrement(); } @@ -382,14 +399,14 @@ bool FStreamingWaveData::FinishDDCRequests() } #endif //WITH_EDITORONLY_DATA -FLoadedAudioChunk* FStreamingWaveData::AddNewLoadedChunk(int32 ChunkSize) +int32 FStreamingWaveData::AddNewLoadedChunk(int32 ChunkSize) { int32 NewIndex = LoadedChunks.Num(); LoadedChunks.AddDefaulted(); LoadedChunks[NewIndex].DataSize = ChunkSize; - return &LoadedChunks[NewIndex]; + return NewIndex; } void FStreamingWaveData::FreeLoadedChunk(FLoadedAudioChunk& LoadedChunk) @@ -400,6 +417,9 @@ void FStreamingWaveData::FreeLoadedChunk(FLoadedAudioChunk& LoadedChunk) LoadedChunk.IORequest->WaitCompletion(); delete LoadedChunk.IORequest; LoadedChunk.IORequest = nullptr; + + // Process pending async requests after iorequest finishes + AudioStreamingManager->ProcessPendingAsyncFileResults(); } if (LoadedChunk.Data != NULL) @@ -427,13 +447,70 @@ FAudioStreamingManager::~FAudioStreamingManager() { } +void FAudioStreamingManager::OnAsyncFileCallback(FStreamingWaveData* StreamingWaveData, int32 LoadedAudioChunkIndex, IAsyncReadRequest* ReadRequest) +{ + // Check to see if we successfully managed to load anything + uint8* Mem = ReadRequest->GetReadResults(); + if (Mem) + { + // Create a new chunk load result object. Will be deleted on audio thread when TQueue is pumped. + FASyncAudioChunkLoadResult* NewAudioChunkLoadResult = new FASyncAudioChunkLoadResult(); + + // Copy the ptr which we will use to place the results of the read on the audio thread upon pumping. + NewAudioChunkLoadResult->StreamingWaveData = StreamingWaveData; + + // Grab the loaded chunk memory ptr since it will be invalid as soon as this callback finishes + NewAudioChunkLoadResult->DataResults = Mem; + + // The chunk index to load the results into + NewAudioChunkLoadResult->LoadedAudioChunkIndex = LoadedAudioChunkIndex; + + // Safely enqueue the results of the async file callback into a queue to be pumped on audio thread + AsyncAudioStreamChunkResults.Enqueue(NewAudioChunkLoadResult); + } +} + +void FAudioStreamingManager::ProcessPendingAsyncFileResults() +{ + // Pump the results of any async file loads in a protected critical section + FASyncAudioChunkLoadResult* AudioChunkLoadResult = nullptr; + while (AsyncAudioStreamChunkResults.Dequeue(AudioChunkLoadResult)) + { + // Copy the results to the chunk storage safely + const int32 LoadedAudioChunkIndex = AudioChunkLoadResult->LoadedAudioChunkIndex; + + check(AudioChunkLoadResult->StreamingWaveData != nullptr); + check(LoadedAudioChunkIndex != INDEX_NONE); + check(LoadedAudioChunkIndex < AudioChunkLoadResult->StreamingWaveData->LoadedChunks.Num()); + + FLoadedAudioChunk* ChunkStorage = &AudioChunkLoadResult->StreamingWaveData->LoadedChunks[LoadedAudioChunkIndex]; + + checkf(!ChunkStorage->Data, TEXT("Chunk storage already has data. (0x%p), datasize: %d"), ChunkStorage->Data, ChunkStorage->DataSize); + + ChunkStorage->Data = AudioChunkLoadResult->DataResults; + + DEC_MEMORY_STAT_BY(STAT_AsyncFileMemory, ChunkStorage->DataSize); + INC_DWORD_STAT_BY(STAT_AudioMemorySize, ChunkStorage->DataSize); + INC_DWORD_STAT_BY(STAT_AudioMemory, ChunkStorage->DataSize); + + // Cleanup the chunk load results + delete AudioChunkLoadResult; + AudioChunkLoadResult = nullptr; + } +} + void FAudioStreamingManager::UpdateResourceStreaming(float DeltaTime, bool bProcessEverything /*= false*/) { + FScopeLock Lock(&CriticalSection); + for (auto& WavePair : StreamingSoundWaves) { WavePair.Value->UpdateStreamingStatus(); } + // Process any async file requests after updating the stream status + ProcessPendingAsyncFileResults(); + for (auto Source : StreamingSoundSources) { const FWaveInstance* WaveInstance = Source->GetWaveInstance(); @@ -447,13 +524,16 @@ void FAudioStreamingManager::UpdateResourceStreaming(float DeltaTime, bool bProc FStreamingWaveData* WaveData = *WaveDataPtr; // Request the chunk the source is using and the one after that FWaveRequest& WaveRequest = GetWaveRequest(Wave); - int32 SourceChunk = Source->GetBuffer()->GetCurrentChunkIndex(); + const FSoundBuffer* SoundBuffer = Source->GetBuffer(); + if (SoundBuffer) + { + int32 SourceChunk = SoundBuffer->GetCurrentChunkIndex(); if (SourceChunk >= 0 && SourceChunk < Wave->RunningPlatformData->NumChunks) { WaveRequest.RequiredIndices.AddUnique(SourceChunk); WaveRequest.RequiredIndices.AddUnique((SourceChunk + 1) % Wave->RunningPlatformData->NumChunks); if (!WaveData->LoadedChunkIndices.Contains(SourceChunk) - || Source->GetBuffer()->GetCurrentChunkOffset() > Wave->RunningPlatformData->Chunks[SourceChunk].DataSize / 2) + || SoundBuffer->GetCurrentChunkOffset() > Wave->RunningPlatformData->Chunks[SourceChunk].DataSize / 2) { // currently not loaded or already read over half, request is high priority WaveRequest.bPrioritiseRequest = true; @@ -466,6 +546,7 @@ void FAudioStreamingManager::UpdateResourceStreaming(float DeltaTime, bool bProc } } } + } for (auto Iter = WaveRequests.CreateIterator(); Iter; ++Iter) { USoundWave* Wave = Iter.Key(); @@ -478,12 +559,19 @@ void FAudioStreamingManager::UpdateResourceStreaming(float DeltaTime, bool bProc Iter.RemoveCurrent(); } } + + // Process any async file requests after updating the streaming wave data stream statuses + ProcessPendingAsyncFileResults(); } int32 FAudioStreamingManager::BlockTillAllRequestsFinished(float TimeLimit, bool) { { + FScopeLock Lock(&CriticalSection); + QUICK_SCOPE_CYCLE_COUNTER(FAudioStreamingManager_BlockTillAllRequestsFinished); + int32 Result = 0; + if (TimeLimit == 0.0f) { for (auto& WavePair : StreamingSoundWaves) @@ -500,10 +588,16 @@ int32 FAudioStreamingManager::BlockTillAllRequestsFinished(float TimeLimit, bool if (ThisTimeLimit < .001f || // one ms is the granularity of the platform event system !WavePair.Value->BlockTillAllRequestsFinished(ThisTimeLimit)) { - return 1; // we don't report the actual number, just 1 for any number of outstanding requests + Result = 1; // we don't report the actual number, just 1 for any number of outstanding requests + break; } } } + + // After blocking to process all requests, pump the queue + ProcessPendingAsyncFileResults(); + + return Result; } // Not sure yet whether this will work the same as textures - aside from just before destroying @@ -532,16 +626,20 @@ void FAudioStreamingManager::RemoveLevel(class ULevel* Level) void FAudioStreamingManager::AddStreamingSoundWave(USoundWave* SoundWave) { - if (FPlatformProperties::SupportsAudioStreaming() && SoundWave->IsStreaming() - && StreamingSoundWaves.FindRef(SoundWave) == NULL) + if (FPlatformProperties::SupportsAudioStreaming() && SoundWave->IsStreaming()) + { + FScopeLock Lock(&CriticalSection); + if (StreamingSoundWaves.FindRef(SoundWave) == NULL) { FStreamingWaveData& WaveData = *StreamingSoundWaves.Add(SoundWave, new FStreamingWaveData); - WaveData.Initialize(SoundWave); + WaveData.Initialize(SoundWave, this); + } } } void FAudioStreamingManager::RemoveStreamingSoundWave(USoundWave* SoundWave) { + FScopeLock Lock(&CriticalSection); FStreamingWaveData* WaveData = StreamingSoundWaves.FindRef(SoundWave); if (WaveData) { @@ -553,11 +651,13 @@ void FAudioStreamingManager::RemoveStreamingSoundWave(USoundWave* SoundWave) bool FAudioStreamingManager::IsManagedStreamingSoundWave(const USoundWave* SoundWave) const { + FScopeLock Lock(&CriticalSection); return StreamingSoundWaves.FindRef(SoundWave) != NULL; } bool FAudioStreamingManager::IsStreamingInProgress(const USoundWave* SoundWave) { + FScopeLock Lock(&CriticalSection); FStreamingWaveData* WaveData = StreamingSoundWaves.FindRef(SoundWave); if (WaveData) { @@ -572,6 +672,8 @@ bool FAudioStreamingManager::CanCreateSoundSource(const FWaveInstance* WaveInsta { int32 MaxStreams = GetDefault()->MaximumConcurrentStreams; + FScopeLock Lock(&CriticalSection); + if ( StreamingSoundSources.Num() < MaxStreams ) { return true; @@ -602,6 +704,8 @@ void FAudioStreamingManager::AddStreamingSoundSource(FSoundSource* SoundSource) { int32 MaxStreams = GetDefault()->MaximumConcurrentStreams; + FScopeLock Lock(&CriticalSection); + // Add source sorted by priority so we can easily iterate over the amount of streams // that are allowed int32 OrderedIndex = -1; @@ -637,6 +741,8 @@ void FAudioStreamingManager::RemoveStreamingSoundSource(FSoundSource* SoundSourc const FWaveInstance* WaveInstance = SoundSource->GetWaveInstance(); if (WaveInstance && WaveInstance->WaveData && WaveInstance->WaveData->IsStreaming()) { + FScopeLock Lock(&CriticalSection); + // Make sure there is a request so that unused chunks // can be cleared if this was the last playing instance GetWaveRequest(WaveInstance->WaveData); @@ -646,11 +752,20 @@ void FAudioStreamingManager::RemoveStreamingSoundSource(FSoundSource* SoundSourc bool FAudioStreamingManager::IsManagedStreamingSoundSource(const FSoundSource* SoundSource) const { + FScopeLock Lock(&CriticalSection); return StreamingSoundSources.FindByKey(SoundSource) != NULL; } const uint8* FAudioStreamingManager::GetLoadedChunk(const USoundWave* SoundWave, uint32 ChunkIndex, uint32* OutChunkSize) const { + FScopeLock Lock(&CriticalSection); + + // Check for the spoof of failing to load a stream chunk + if (SpoofFailedStreamChunkLoad > 0) + { + return nullptr; + } + const FStreamingWaveData* WaveData = StreamingSoundWaves.FindRef(SoundWave); if (WaveData) { diff --git a/Engine/Source/Runtime/Engine/Private/BatchedElements.cpp b/Engine/Source/Runtime/Engine/Private/BatchedElements.cpp index 27ff9ebf005d..aca161dc0cb1 100644 --- a/Engine/Source/Runtime/Engine/Private/BatchedElements.cpp +++ b/Engine/Source/Runtime/Engine/Private/BatchedElements.cpp @@ -524,7 +524,7 @@ void FBatchedElements::PrepareShaders( FMatrix ColorWeights( FPlane(1, 0, 0, 0), FPlane(0, 1, 0, 0), FPlane(0, 0, 1, 0), FPlane(0, 0, 0, 0) ); // bEncodedHDR requires that blend states are disabled. - bool bEncodedHDR = bEnableHDREncoding && Is32BppHDREncoded(View, FeatureLevel); + bool bEncodedHDR = /*bEnableHDREncoding &&*/ Is32BppHDREncoded(View, FeatureLevel); float GammaToUse = Gamma; diff --git a/Engine/Source/Runtime/Engine/Private/Blueprint.cpp b/Engine/Source/Runtime/Engine/Private/Blueprint.cpp index b389e3ac1d6f..70ebc79add71 100644 --- a/Engine/Source/Runtime/Engine/Private/Blueprint.cpp +++ b/Engine/Source/Runtime/Engine/Private/Blueprint.cpp @@ -432,7 +432,7 @@ void UBlueprint::Serialize(FArchive& Ar) if (Ar.IsLoading()) { // Validate metadata keys/values on load only - FBlueprintEditorUtils::ValidateBlueprintVariableMetadata(Variable); + FBlueprintEditorUtils::FixupVariableDescription(this, Variable); } } @@ -582,9 +582,12 @@ UClass* UBlueprint::RegenerateClass(UClass* ClassToRegenerate, UObject* Previous UBlueprint::ForceLoadMembers(GeneratedClassResolved->ClassDefaultObject); } UBlueprint::ForceLoadMembers(this); + + FBlueprintEditorUtils::PreloadConstructionScript( this ); + + FBlueprintEditorUtils::LinkExternalDependencies( this ); FBlueprintEditorUtils::RefreshVariables(this); - FBlueprintEditorUtils::PreloadConstructionScript( this ); // Preload Overridden Components if (InheritableComponentHandler) @@ -592,8 +595,6 @@ UClass* UBlueprint::RegenerateClass(UClass* ClassToRegenerate, UObject* Previous InheritableComponentHandler->PreloadAll(); } - FBlueprintEditorUtils::LinkExternalDependencies( this ); - FBlueprintCompilationManager::NotifyBlueprintLoaded( this ); // clear this now that we're not in a re-entrrant context - bHasBeenRegenerated will guard against 'real' @@ -758,6 +759,7 @@ void UBlueprint::DebuggingWorldRegistrationHelper(UObject* ObjectProvidingWorld, if (ObjWorld != NULL) { ObjWorld->NotifyOfBlueprintDebuggingAssociation(this, ValueToRegister); + OnSetObjectBeingDebuggedDelegate.Broadcast(ValueToRegister); } } } @@ -1176,7 +1178,7 @@ void UBlueprint::BeginCacheForCookedPlatformData(const ITargetPlatform *TargetPl // If nativization is enabled and this Blueprint class will NOT be nativized, we need to determine if any of its parent Blueprints will be nativized and flag it for the runtime code. // Note: Currently, this flag is set on Actor-based Blueprint classes only. If it's ever needed for non-Actor-based Blueprint classes at runtime, then this needs to be updated to match. const IBlueprintNativeCodeGenCore* NativeCodeGenCore = IBlueprintNativeCodeGenCore::Get(); - if (GeneratedClass != nullptr && NativeCodeGenCore != nullptr && FParse::Param(FCommandLine::Get(), TEXT("NativizeAssets"))) + if (GeneratedClass != nullptr && NativeCodeGenCore != nullptr) { ensure(TargetPlatform); const FCompilerNativizationOptions& NativizationOptions = NativeCodeGenCore->GetNativizationOptionsForPlatform(TargetPlatform); @@ -1397,8 +1399,8 @@ ETimelineSigType UBlueprint::GetTimelineSignatureForFunctionByName(const FName& return UTimelineComponent::GetTimelineSignatureForFunction(Function); - UE_LOG(LogBlueprint, Log, TEXT("GetTimelineSignatureForFunction: No SkeletonGeneratedClass in Blueprint '%s'."), *GetName()); - return ETS_InvalidSignature; + //UE_LOG(LogBlueprint, Log, TEXT("GetTimelineSignatureForFunction: No SkeletonGeneratedClass in Blueprint '%s'."), *GetName()); + //return ETS_InvalidSignature; } FString UBlueprint::GetDesc(void) diff --git a/Engine/Source/Runtime/Engine/Private/BlueprintGeneratedClass.cpp b/Engine/Source/Runtime/Engine/Private/BlueprintGeneratedClass.cpp index 2556a900cabc..38d02211e3ba 100644 --- a/Engine/Source/Runtime/Engine/Private/BlueprintGeneratedClass.cpp +++ b/Engine/Source/Runtime/Engine/Private/BlueprintGeneratedClass.cpp @@ -24,6 +24,7 @@ #include "Kismet2/BlueprintEditorUtils.h" #include "Kismet2/KismetEditorUtilities.h" #include "BlueprintCompilationManager.h" +#include "Engine/LevelScriptBlueprint.h" #endif //WITH_EDITOR DEFINE_STAT(STAT_PersistentUberGraphFrameMemory); @@ -42,6 +43,7 @@ UBlueprintGeneratedClass::UBlueprintGeneratedClass(const FObjectInitializer& Obj NumReplicatedProperties = 0; bHasInstrumentation = false; bHasNativizedParent = false; + bCustomPropertyListForPostConstructionInitialized = false; } void UBlueprintGeneratedClass::PostInitProperties() @@ -305,6 +307,17 @@ void UBlueprintGeneratedClass::ConditionalRecompileClass(TArray* ObjLo } } +void UBlueprintGeneratedClass::FlushCompilationQueueForLevel() +{ + if(GBlueprintUseCompilationManager) + { + if(Cast(ClassGeneratedBy)) + { + FBlueprintCompilationManager::FlushCompilationQueue(); + } + } +} + UObject* UBlueprintGeneratedClass::GetArchetypeForCDO() const { if (OverridenArchetypeForCDO) @@ -523,6 +536,7 @@ void UBlueprintGeneratedClass::UpdateCustomPropertyListForPostConstruction() { // Empty the current list. CustomPropertyListForPostConstruction.Empty(); + bCustomPropertyListForPostConstructionInitialized = false; // Find the first native antecedent. All non-native decendant properties are attached to the PostConstructLink chain (see UStruct::Link), so we only need to worry about properties owned by native super classes here. UClass* SuperClass = GetSuperClass(); @@ -539,6 +553,85 @@ void UBlueprintGeneratedClass::UpdateCustomPropertyListForPostConstruction() FCustomPropertyListNode* PropertyList = nullptr; BuildCustomPropertyListForPostConstruction(PropertyList, SuperClass, (uint8*)ClassDefaultObject, (uint8*)SuperClass->GetDefaultObject(false)); } + + bCustomPropertyListForPostConstructionInitialized = true; +} + +void UBlueprintGeneratedClass::InitPropertiesFromCustomList(uint8* DataPtr, const uint8* DefaultDataPtr) +{ + FScopeLock SerializeAndPostLoadLock(&SerializeAndPostLoadCritical); + check(bCustomPropertyListForPostConstructionInitialized); // Something went wrong, probably a race condition + + if (const FCustomPropertyListNode* CustomPropertyList = GetCustomPropertyListForPostConstruction()) + { + InitPropertiesFromCustomList(CustomPropertyList, this, DataPtr, DefaultDataPtr); + } +} + +void UBlueprintGeneratedClass::InitPropertiesFromCustomList(const FCustomPropertyListNode* InPropertyList, UStruct* InStruct, uint8* DataPtr, const uint8* DefaultDataPtr) +{ + for (const FCustomPropertyListNode* CustomPropertyListNode = InPropertyList; CustomPropertyListNode; CustomPropertyListNode = CustomPropertyListNode->PropertyListNext) + { + uint8* PropertyValue = CustomPropertyListNode->Property->ContainerPtrToValuePtr(DataPtr, CustomPropertyListNode->ArrayIndex); + const uint8* DefaultPropertyValue = CustomPropertyListNode->Property->ContainerPtrToValuePtr(DefaultDataPtr, CustomPropertyListNode->ArrayIndex); + + if (const UStructProperty* StructProperty = Cast(CustomPropertyListNode->Property)) + { + // This should never be NULL; we should not be recording the StructProperty without at least one sub property, but we'll verify just to be sure. + if (ensure(CustomPropertyListNode->SubPropertyList != nullptr)) + { + InitPropertiesFromCustomList(CustomPropertyListNode->SubPropertyList, StructProperty->Struct, PropertyValue, DefaultPropertyValue); + } + } + else if (const UArrayProperty* ArrayProperty = Cast(CustomPropertyListNode->Property)) + { + // Note: The sub-property list can be NULL here; in that case only the array size will differ from the default value, but the elements themselves will simply be initialized to defaults. + InitArrayPropertyFromCustomList(ArrayProperty, CustomPropertyListNode->SubPropertyList, PropertyValue, DefaultPropertyValue); + } + else + { + CustomPropertyListNode->Property->CopySingleValue(PropertyValue, DefaultPropertyValue); + } + } +} + +void UBlueprintGeneratedClass::InitArrayPropertyFromCustomList(const UArrayProperty* ArrayProperty, const FCustomPropertyListNode* InPropertyList, uint8* DataPtr, const uint8* DefaultDataPtr) +{ + FScriptArrayHelper DstArrayValueHelper(ArrayProperty, DataPtr); + FScriptArrayHelper SrcArrayValueHelper(ArrayProperty, DefaultDataPtr); + + const int32 SrcNum = SrcArrayValueHelper.Num(); + const int32 DstNum = DstArrayValueHelper.Num(); + + if (SrcNum > DstNum) + { + DstArrayValueHelper.AddValues(SrcNum - DstNum); + } + else if (SrcNum < DstNum) + { + DstArrayValueHelper.RemoveValues(SrcNum, DstNum - SrcNum); + } + + for (const FCustomPropertyListNode* CustomArrayPropertyListNode = InPropertyList; CustomArrayPropertyListNode; CustomArrayPropertyListNode = CustomArrayPropertyListNode->PropertyListNext) + { + int32 ArrayIndex = CustomArrayPropertyListNode->ArrayIndex; + + uint8* DstArrayItemValue = DstArrayValueHelper.GetRawPtr(ArrayIndex); + const uint8* SrcArrayItemValue = SrcArrayValueHelper.GetRawPtr(ArrayIndex); + + if (const UStructProperty* InnerStructProperty = Cast(ArrayProperty->Inner)) + { + InitPropertiesFromCustomList(CustomArrayPropertyListNode->SubPropertyList, InnerStructProperty->Struct, DstArrayItemValue, SrcArrayItemValue); + } + else if (const UArrayProperty* InnerArrayProperty = Cast(ArrayProperty->Inner)) + { + InitArrayPropertyFromCustomList(InnerArrayProperty, CustomArrayPropertyListNode->SubPropertyList, DstArrayItemValue, SrcArrayItemValue); + } + else + { + ArrayProperty->Inner->CopyCompleteValue(DstArrayItemValue, SrcArrayItemValue); + } + } } bool UBlueprintGeneratedClass::IsFunctionImplementedInBlueprint(FName InFunctionName) const @@ -1215,7 +1308,12 @@ void UBlueprintGeneratedClass::GetPreloadDependencies(TArray& OutDeps) bool UBlueprintGeneratedClass::NeedsLoadForServer() const { - if (!HasAnyFlags(RF_ClassDefaultObject)) + // This logic can't be used for targets that use editor content because UBlueprint::NeedsLoadForEditorGame + // returns true and forces all UBlueprints to be loaded for -game or -server runs. The ideal fix would be + // to remove UBlueprint::NeedsLoadForEditorGame, after that it would be nice if we could just implement + // UBlueprint::NeedsLoadForEditorGame here, but we can't because then our CDO doesn't get loaded. We *could* + // fix that behavior, but instead I'm just abusing IsRunningCommandlet() so that this logic only runs during cook: + if (IsRunningCommandlet() && !HasAnyFlags(RF_ClassDefaultObject)) { if (ensure(GetSuperClass()) && !GetSuperClass()->NeedsLoadForServer()) { @@ -1231,7 +1329,12 @@ bool UBlueprintGeneratedClass::NeedsLoadForServer() const bool UBlueprintGeneratedClass::NeedsLoadForClient() const { - if (!HasAnyFlags(RF_ClassDefaultObject)) + // This logic can't be used for targets that use editor content because UBlueprint::NeedsLoadForEditorGame + // returns true and forces all UBlueprints to be loaded for -game or -server runs. The ideal fix would be + // to remove UBlueprint::NeedsLoadForEditorGame, after that it would be nice if we could just implement + // UBlueprint::NeedsLoadForEditorGame here, but we can't because then our CDO doesn't get loaded. We *could* + // fix that behavior, but instead I'm just abusing IsRunningCommandlet() so that this logic only runs during cook: + if (IsRunningCommandlet() && !HasAnyFlags(RF_ClassDefaultObject)) { if (ensure(GetSuperClass()) && !GetSuperClass()->NeedsLoadForClient()) { @@ -1245,6 +1348,11 @@ bool UBlueprintGeneratedClass::NeedsLoadForClient() const return Super::NeedsLoadForClient(); } +bool UBlueprintGeneratedClass::NeedsLoadForEditorGame() const +{ + return true; +} + bool UBlueprintGeneratedClass::CanBeClusterRoot() const { // Clustering level BPs doesn't work yet @@ -1265,7 +1373,7 @@ void UBlueprintGeneratedClass::Link(FArchive& Ar, bool bRelinkExistingProperties UFunction* ParentFunction = Function->GetSuperFunction(); if(ParentFunction != nullptr) { - const uint32 ParentNetFlags = (ParentFunction->FunctionFlags & FUNC_NetFuncFlags); + const EFunctionFlags ParentNetFlags = (ParentFunction->FunctionFlags & FUNC_NetFuncFlags); if(ParentNetFlags != (Function->FunctionFlags & FUNC_NetFuncFlags)) { Function->FunctionFlags &= ~FUNC_NetFuncFlags; @@ -1337,15 +1445,39 @@ protected: , SerializingObject ? *SerializingObject->GetFullName() : TEXT("NULL") , GetSerializedProperty() ? *GetSerializedProperty()->GetFullName() : TEXT("NULL") )) { - // clear the property value (it's garbage)... the ubergraph-frame + // clear the property value (it's garbage)... the ubergraph-frame // has just lost a reference to whatever it was attempting to hold onto Object = nullptr; } #endif + if (Object) + { + bool bWeakRef = false; - const bool bWeakRef = Object ? !Object->HasAnyFlags(RF_StrongRefOnFrame) : false; - Collector.SetShouldHandleAsWeakRef(bWeakRef); - return FSimpleObjectReferenceCollectorArchive::operator<<(Object); + // If the property that serialized us is not an object property we are in some native serializer, we have to treat these as strong + if (!Object->HasAnyFlags(RF_StrongRefOnFrame)) + { + UObjectProperty* ObjectProperty = Cast(GetSerializedProperty()); + + if (ObjectProperty) + { + bWeakRef = true; + } + } + + if (bWeakRef) + { + // This was a raw UObject * serialized by UObjectProperty, so just save the address + Collector.MarkWeakObjectReferenceForClearing(&Object); + } + else + { + // This is a hard reference or we don't know what's serializing it, so serialize it normally + return FSimpleObjectReferenceCollectorArchive::operator<<(Object); + } + } + + return *this; } }; @@ -1365,9 +1497,6 @@ void UBlueprintGeneratedClass::AddReferencedObjectsInUbergraphFrame(UObject* InT checkSlow(BPGC->UberGraphFunction); FPersistentFrameCollectorArchive ObjectReferenceCollector(InThis, Collector); BPGC->UberGraphFunction->SerializeBin(ObjectReferenceCollector, PointerToUberGraphFrame->RawPointer); - - // Reset the ShouldHandleAsWeakRef state, before the collector is used by a different archive. - Collector.SetShouldHandleAsWeakRef(false); } } } diff --git a/Engine/Source/Runtime/Engine/Private/BoneContainer.cpp b/Engine/Source/Runtime/Engine/Private/BoneContainer.cpp index 0f010ee1f58b..2217cf6f549e 100644 --- a/Engine/Source/Runtime/Engine/Private/BoneContainer.cpp +++ b/Engine/Source/Runtime/Engine/Private/BoneContainer.cpp @@ -166,14 +166,16 @@ void FBoneContainer::Initialize() SkeletonToCompactPose.Add(FCompactPoseBoneIndex(CompactIndex)); } - for (const FVirtualBoneRefData& VBRefBone : RefSkeleton->GetVirtualBoneRefData()) { - int32 VBInd = MeshIndexToCompactPoseIndex[VBRefBone.VBRefSkelIndex]; - int32 SourceInd = MeshIndexToCompactPoseIndex[VBRefBone.SourceRefSkelIndex]; - int32 TargetInd = MeshIndexToCompactPoseIndex[VBRefBone.TargetRefSkelIndex]; + const int32 VBInd = MeshIndexToCompactPoseIndex[VBRefBone.VBRefSkelIndex]; + const int32 SourceInd = MeshIndexToCompactPoseIndex[VBRefBone.SourceRefSkelIndex]; + const int32 TargetInd = MeshIndexToCompactPoseIndex[VBRefBone.TargetRefSkelIndex]; - VirtualBoneCompactPoseData.Add(FVirtualBoneCompactPoseData(FCompactPoseBoneIndex(VBInd), FCompactPoseBoneIndex(SourceInd), FCompactPoseBoneIndex(TargetInd))); + if ((VBInd != INDEX_NONE) && (SourceInd != INDEX_NONE) && (TargetInd != INDEX_NONE)) + { + VirtualBoneCompactPoseData.Add(FVirtualBoneCompactPoseData(FCompactPoseBoneIndex(VBInd), FCompactPoseBoneIndex(SourceInd), FCompactPoseBoneIndex(TargetInd))); + } } // cache required curve UID list according to new bone sets diff --git a/Engine/Source/Runtime/Engine/Private/Brush.cpp b/Engine/Source/Runtime/Engine/Private/Brush.cpp index 3b47863f85e6..6ef4a414fcc4 100644 --- a/Engine/Source/Runtime/Engine/Private/Brush.cpp +++ b/Engine/Source/Runtime/Engine/Private/Brush.cpp @@ -315,5 +315,3 @@ bool ABrush::Modify(bool bAlwaysMarkDirty) return bSavedToTransactionBuffer; } -/** Returns BrushComponent subobject **/ -UBrushComponent* ABrush::GetBrushComponent() const { return BrushComponent; } diff --git a/Engine/Source/Runtime/Engine/Private/Camera/CameraActor.cpp b/Engine/Source/Runtime/Engine/Private/Camera/CameraActor.cpp index 9aee11976612..acdf0afc5f44 100644 --- a/Engine/Source/Runtime/Engine/Private/Camera/CameraActor.cpp +++ b/Engine/Source/Runtime/Engine/Private/Camera/CameraActor.cpp @@ -128,5 +128,3 @@ void ACameraActor::BeginPlay() #undef LOCTEXT_NAMESPACE -/** Returns CameraComponent subobject **/ -UCameraComponent* ACameraActor::GetCameraComponent() const { return CameraComponent; } diff --git a/Engine/Source/Runtime/Engine/Private/Camera/CameraAnimInst.cpp b/Engine/Source/Runtime/Engine/Private/Camera/CameraAnimInst.cpp index 2b4fcdb11b08..464871ef9ab8 100644 --- a/Engine/Source/Runtime/Engine/Private/Camera/CameraAnimInst.cpp +++ b/Engine/Source/Runtime/Engine/Private/Camera/CameraAnimInst.cpp @@ -305,12 +305,6 @@ void UCameraAnimInst::SetPlaySpace(ECameraAnimPlaySpace::Type NewSpace, FRotator } -/** Returns InterpGroupInst subobject **/ -UInterpGroupInst* UCameraAnimInst::GetInterpGroupInst() const -{ - return InterpGroupInst; -} - void UCameraAnimInst::ApplyToView(FMinimalViewInfo& InOutPOV) const { if (CurrentBlendWeight > 0.f) diff --git a/Engine/Source/Runtime/Engine/Private/Camera/CameraComponent.cpp b/Engine/Source/Runtime/Engine/Private/Camera/CameraComponent.cpp index 6f986bd54dff..d251f1edda35 100644 --- a/Engine/Source/Runtime/Engine/Private/Camera/CameraComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Camera/CameraComponent.cpp @@ -246,7 +246,7 @@ void UCameraComponent::Serialize(FArchive& Ar) void UCameraComponent::GetCameraView(float DeltaTime, FMinimalViewInfo& DesiredView) { - if (bLockToHmd && GEngine->HMDDevice.IsValid() && GEngine->HMDDevice->IsHeadTrackingAllowed()) + if (bLockToHmd && GEngine->HMDDevice.IsValid() && GEngine->HMDDevice->IsHeadTrackingAllowed() && GetWorld()->WorldType != EWorldType::Editor) { const FTransform ParentWorld = CalcNewComponentToWorld(FTransform()); GEngine->HMDDevice->SetupLateUpdate(ParentWorld, this); @@ -322,6 +322,15 @@ void UCameraComponent::CheckForErrors() ->AddToken(FMapErrorToken::Create(FMapErrors::CameraAspectRatioIsZero)); } } + +bool UCameraComponent::GetEditorPreviewInfo(float DeltaTime, FMinimalViewInfo& ViewOut) +{ + if (bIsActive) + { + GetCameraView(DeltaTime, ViewOut); + } + return bIsActive; +} #endif // WITH_EDITOR diff --git a/Engine/Source/Runtime/Engine/Private/Camera/CameraShake.cpp b/Engine/Source/Runtime/Engine/Private/Camera/CameraShake.cpp index e0fbd4711621..741d20ffa7f8 100644 --- a/Engine/Source/Runtime/Engine/Private/Camera/CameraShake.cpp +++ b/Engine/Source/Runtime/Engine/Private/Camera/CameraShake.cpp @@ -345,11 +345,15 @@ bool UCameraShake::IsFinished() const ); } +/// @cond DOXYGEN_WARNINGS + bool UCameraShake::ReceiveIsFinished_Implementation() const { return true; } +/// @endcond + bool UCameraShake::IsLooping() const { return OscillationDuration < 0.0f; diff --git a/Engine/Source/Runtime/Engine/Private/Character.cpp b/Engine/Source/Runtime/Engine/Private/Character.cpp index a2c7292448f9..1eb90903a2a1 100644 --- a/Engine/Source/Runtime/Engine/Private/Character.cpp +++ b/Engine/Source/Runtime/Engine/Private/Character.cpp @@ -668,7 +668,7 @@ void ACharacter::SetBase( UPrimitiveComponent* NewBaseComponent, const FName InB { if( Loop == this ) { - UE_LOG(LogCharacter, Warning, TEXT(" SetBase failed! Recursion detected. Pawn %s already based on %s."), *GetName(), *NewBaseComponent->GetName()); + UE_LOG(LogCharacter, Warning, TEXT(" SetBase failed! Recursion detected. Pawn %s already based on %s."), *GetName(), *NewBaseComponent->GetName()); //-V595 return; } } @@ -1429,43 +1429,46 @@ void ACharacter::PreReplication( IRepChangedPropertyTracker & ChangedPropertyTra ReplicatedBasedMovement.Rotation = GetActorRotation(); } } - - if ( ChangedPropertyTracker.IsReplay() ) - { - // If this is a replay, we save out certain values we need to runtime to do smooth interpolation - // We'll be able to look ahead in the replay to have these ahead of time for smoother playback - FCharacterReplaySample ReplaySample; - - // If this is a client-recorded replay, use the mesh location and rotation, since these will always - // be smoothed - unlike the actor position and rotation. - const USkeletalMeshComponent* const MeshComponent = GetMesh(); - if (MeshComponent && GetWorld()->IsRecordingClientReplay()) - { - // Remove the base transform from the mesh's transform, since on playback the base transform - // will be stored in the mesh's RelativeLocation and RelativeRotation. - const FTransform BaseTransform(GetBaseRotationOffset(), GetBaseTranslationOffset()); - const FTransform MeshRootTransform = BaseTransform.Inverse() * MeshComponent->GetComponentTransform(); - - ReplaySample.Location = MeshRootTransform.GetLocation(); - ReplaySample.Rotation = MeshRootTransform.GetRotation().Rotator(); - } - else - { - ReplaySample.Location = GetActorLocation(); - ReplaySample.Rotation = GetActorRotation(); - } - - ReplaySample.Velocity = GetVelocity(); - ReplaySample.Acceleration = CharacterMovement->GetCurrentAcceleration(); - ReplaySample.RemoteViewPitch = RemoteViewPitch; - - FBitWriter Writer( 0, true ); - Writer << ReplaySample; - - ChangedPropertyTracker.SetExternalData( Writer.GetData(), Writer.GetNumBits() ); - } } +void ACharacter::PreReplicationForReplay(IRepChangedPropertyTracker & ChangedPropertyTracker) +{ + Super::PreReplicationForReplay(ChangedPropertyTracker); + + // If this is a replay, we save out certain values we need to runtime to do smooth interpolation + // We'll be able to look ahead in the replay to have these ahead of time for smoother playback + FCharacterReplaySample ReplaySample; + + // If this is a client-recorded replay, use the mesh location and rotation, since these will always + // be smoothed - unlike the actor position and rotation. + const USkeletalMeshComponent* const MeshComponent = GetMesh(); + if (MeshComponent && GetWorld()->IsRecordingClientReplay()) + { + // Remove the base transform from the mesh's transform, since on playback the base transform + // will be stored in the mesh's RelativeLocation and RelativeRotation. + const FTransform BaseTransform(GetBaseRotationOffset(), GetBaseTranslationOffset()); + const FTransform MeshRootTransform = BaseTransform.Inverse() * MeshComponent->GetComponentTransform(); + + ReplaySample.Location = MeshRootTransform.GetLocation(); + ReplaySample.Rotation = MeshRootTransform.GetRotation().Rotator(); + } + else + { + ReplaySample.Location = GetActorLocation(); + ReplaySample.Rotation = GetActorRotation(); + } + + ReplaySample.Velocity = GetVelocity(); + ReplaySample.Acceleration = CharacterMovement->GetCurrentAcceleration(); + ReplaySample.RemoteViewPitch = RemoteViewPitch; + + FBitWriter Writer(0, true); + Writer << ReplaySample; + + ChangedPropertyTracker.SetExternalData(Writer.GetData(), Writer.GetNumBits()); +} + + void ACharacter::GetLifetimeReplicatedProps( TArray< FLifetimeProperty > & OutLifetimeProps ) const { Super::GetLifetimeReplicatedProps( OutLifetimeProps ); @@ -1590,3 +1593,9 @@ void ACharacter::ClientCheatGhost_Implementation() #endif } +void ACharacter::RootMotionDebugClientPrintOnScreen_Implementation(const FString& InString) +{ +#if ROOT_MOTION_DEBUG + RootMotionSourceDebug::PrintOnScreenServerMsg(InString); +#endif +} diff --git a/Engine/Source/Runtime/Engine/Private/ChartCreation.cpp b/Engine/Source/Runtime/Engine/Private/ChartCreation.cpp index 93e8d5200705..0074ef2080c9 100644 --- a/Engine/Source/Runtime/Engine/Private/ChartCreation.cpp +++ b/Engine/Source/Runtime/Engine/Private/ChartCreation.cpp @@ -53,160 +53,124 @@ static FAutoConsoleVariableRef GMaximumFrameTimeToConsiderForHitchesAndBinningCV /** The engine-wide performance tracking chart */ FPerformanceTrackingSystem GPerformanceTrackingSystem; +// Comma separated list of interesting frame rates +static TAutoConsoleVariable GFPSChartInterestingFramerates( + TEXT("t.FPSChart.InterestingFramerates"), + TEXT("30,60,120"), + TEXT("Comma separated list of interesting frame rates\n") + TEXT(" default: 30,60,120")); + /** Array of interesting summary thresholds (e.g., 30 Hz, 60 Hz, 120 Hz) */ TArray GTargetFrameRatesForSummary; ////////////////////////////////////////////////////////////////////// +// FDumpFPSChartToEndpoint -// Prints the FPS chart summary to an endpoint -struct FDumpFPSChartToEndpoint +void FDumpFPSChartToEndpoint::FillOutMemberStats() { -protected: - const FPerformanceTrackingChart& Chart; + // Get OS info + FPlatformMisc::GetOSVersions(/*out*/ OSMajor, /*out*/ OSMinor); + OSMajor.Trim().TrimTrailing(); + OSMinor.Trim().TrimTrailing(); -public: - /** - * Dumps a chart, allowing subclasses to format the data in their own way via various protected virtuals to be overridden - */ - void DumpChart(double InWallClockTimeFromStartOfCharting, const FString& InMapName); + // Get CPU/GPU info + CPUVendor = FPlatformMisc::GetCPUVendor().Trim().TrimTrailing(); + CPUBrand = FPlatformMisc::GetCPUBrand().Trim().TrimTrailing(); + DesktopGPUBrand = FPlatformMisc::GetPrimaryGPUBrand().Trim().TrimTrailing(); + ActualGPUBrand = GRHIAdapterName.Trim().TrimTrailing(); - FDumpFPSChartToEndpoint(const FPerformanceTrackingChart& InChart) - : Chart(InChart) + // Get settings info + UGameUserSettings* UserSettingsObj = GEngine->GetGameUserSettings(); + check(UserSettingsObj); + ScalabilityQuality = UserSettingsObj->ScalabilityQuality; +} + +void FDumpFPSChartToEndpoint::HandleFPSBucket(float BucketTimePercentage, float BucketFramePercentage, double StartFPS, double EndFPS) +{ + // Log bucket index, time and frame Percentage. + PrintToEndpoint(FString::Printf(TEXT("Bucket: %.1f - %.1f Time: %5.2f Frame: %5.2f"), StartFPS, EndFPS, BucketTimePercentage, BucketFramePercentage)); +} + +void FDumpFPSChartToEndpoint::HandleHitchBucket(const FHistogram& HitchHistogram, int32 BucketIndex) +{ + const double LowerBound = HitchHistogram.GetBinLowerBound(BucketIndex); + const double UpperBound = HitchHistogram.GetBinUpperBound(BucketIndex); + + FString RangeName; + if (UpperBound == FLT_MAX) { - // Get OS info - FPlatformMisc::GetOSVersions(/*out*/ OSMajor, /*out*/ OSMinor); - OSMajor.Trim().TrimTrailing(); - OSMinor.Trim().TrimTrailing(); - - // Get CPU/GPU info - CPUVendor = FPlatformMisc::GetCPUVendor().Trim().TrimTrailing(); - CPUBrand = FPlatformMisc::GetCPUBrand().Trim().TrimTrailing(); - DesktopGPUBrand = FPlatformMisc::GetPrimaryGPUBrand().Trim().TrimTrailing(); - ActualGPUBrand = GRHIAdapterName.Trim().TrimTrailing(); - - // Get settings info - UGameUserSettings* UserSettingsObj = GEngine->GetGameUserSettings(); - check(UserSettingsObj); - ScalabilityQuality = UserSettingsObj->ScalabilityQuality; + RangeName = FString::Printf(TEXT("%0.2fs - inf"), LowerBound); + } + else + { + RangeName = FString::Printf(TEXT("%0.2fs - %0.2fs"), LowerBound, UpperBound); } -protected: - double TotalTime; - double WallClockTimeFromStartOfCharting; // This can be much larger than TotalTime if the chart was paused or long frames were omitted - int32 NumFrames; - FString MapName; + PrintToEndpoint(FString::Printf(TEXT("Bucket: %s Count: %i Time: %.2f s"), *RangeName, HitchHistogram.GetBinObservationsCount(BucketIndex), HitchHistogram.GetBinObservationsSum(BucketIndex))); +} - float AvgFPS; - float TimeDisregarded; - float AvgGPUFrameTime; +void FDumpFPSChartToEndpoint::HandleHitchSummary(int32 TotalHitchCount, double TotalTimeSpentInHitchBuckets) +{ + PrintToEndpoint(FString::Printf(TEXT("Total hitch count: %i"), TotalHitchCount)); - float BoundGameThreadPct; - float BoundRenderThreadPct; - float BoundGPUPct; + const double ReciprocalNumHitches = (TotalHitchCount > 0) ? (1.0 / (double)TotalHitchCount) : 0.0; + PrintToEndpoint(FString::Printf(TEXT("Hitch frames bound by game thread: %i (%0.1f percent)"), Chart.TotalGameThreadBoundHitchCount, ReciprocalNumHitches * Chart.TotalGameThreadBoundHitchCount)); + PrintToEndpoint(FString::Printf(TEXT("Hitch frames bound by render thread: %i (%0.1f percent)"), Chart.TotalRenderThreadBoundHitchCount, ReciprocalNumHitches * Chart.TotalRenderThreadBoundHitchCount)); + PrintToEndpoint(FString::Printf(TEXT("Hitch frames bound by GPU: %i (%0.1f percent)"), Chart.TotalGPUBoundHitchCount, ReciprocalNumHitches * Chart.TotalGPUBoundHitchCount)); + PrintToEndpoint(FString::Printf(TEXT("Hitches / min: %.2f"), Chart.GetAvgHitchesPerMinute())); + PrintToEndpoint(FString::Printf(TEXT("Time spent in hitch buckets: %.2f s"), TotalTimeSpentInHitchBuckets)); + PrintToEndpoint(FString::Printf(TEXT("Avg. hitch frame length: %.2f s"), Chart.GetAvgHitchFrameLength())); +} - Scalability::FQualityLevels ScalabilityQuality; - FString OSMajor; - FString OSMinor; +void FDumpFPSChartToEndpoint::HandleFPSThreshold(int32 TargetFPS, int32 NumFramesBelow, float PctTimeAbove, float PctMissedFrames) +{ + const float PercentFramesAbove = float(NumFrames - NumFramesBelow) / float(NumFrames)*100.0f; - FString CPUVendor; - FString CPUBrand; + PrintToEndpoint(FString::Printf(TEXT(" Target %d FPS: %.2f %% syncs missed, %4.2f %% of time spent > %d FPS (%.2f %% of frames)"), TargetFPS, PctMissedFrames, PctTimeAbove, TargetFPS, PercentFramesAbove)); +} - // The primary GPU for the desktop (may not be the one we ended up using, e.g., in an optimus laptop) - FString DesktopGPUBrand; +void FDumpFPSChartToEndpoint::HandleBasicStats() +{ + PrintToEndpoint(FString::Printf(TEXT("--- Begin : FPS chart dump for level '%s'"), *MapName)); - // The actual GPU adapter we initialized - FString ActualGPUBrand; + PrintToEndpoint(FString::Printf(TEXT("Dumping FPS chart at %s using build %s in config %s built from changelist %i"), *FDateTime::Now().ToString(), FApp::GetBuildVersion(), EBuildConfigurations::ToString(FApp::GetBuildConfiguration()), GetChangeListNumberForPerfTesting())); -protected: - virtual void PrintToEndpoint(const FString& Text) = 0; + PrintToEndpoint(TEXT("Machine info:")); + PrintToEndpoint(FString::Printf(TEXT("\tOS: %s %s"), *OSMajor, *OSMinor)); + PrintToEndpoint(FString::Printf(TEXT("\tCPU: %s %s"), *CPUVendor, *CPUBrand)); - virtual void HandleFPSBucket(float BucketTimePercentage, float BucketFramePercentage, double StartFPS, double EndFPS) + FString CompositeGPUString = FString::Printf(TEXT("\tGPU: %s"), *ActualGPUBrand); + if (ActualGPUBrand != DesktopGPUBrand) { - // Log bucket index, time and frame Percentage. - PrintToEndpoint(FString::Printf(TEXT("Bucket: %.1f - %.1f Time: %5.2f Frame: %5.2f"), StartFPS, EndFPS, BucketTimePercentage, BucketFramePercentage)); + CompositeGPUString += FString::Printf(TEXT(" (desktop adapter %s)"), *DesktopGPUBrand); } + PrintToEndpoint(CompositeGPUString); - virtual void HandleHitchBucket(const FHistogram& HitchHistogram, int32 BucketIndex) - { - const double LowerBound = HitchHistogram.GetBinLowerBound(BucketIndex); - const double UpperBound = HitchHistogram.GetBinUpperBound(BucketIndex); + PrintToEndpoint(FString::Printf(TEXT("\tResolution Quality: %.2f"), ScalabilityQuality.ResolutionQuality)); + PrintToEndpoint(FString::Printf(TEXT("\tView Distance Quality: %d"), ScalabilityQuality.ViewDistanceQuality)); + PrintToEndpoint(FString::Printf(TEXT("\tAnti-Aliasing Quality: %d"), ScalabilityQuality.AntiAliasingQuality)); + PrintToEndpoint(FString::Printf(TEXT("\tShadow Quality: %d"), ScalabilityQuality.ShadowQuality)); + PrintToEndpoint(FString::Printf(TEXT("\tPost-Process Quality: %d"), ScalabilityQuality.PostProcessQuality)); + PrintToEndpoint(FString::Printf(TEXT("\tTexture Quality: %d"), ScalabilityQuality.TextureQuality)); + PrintToEndpoint(FString::Printf(TEXT("\tEffects Quality: %d"), ScalabilityQuality.EffectsQuality)); + PrintToEndpoint(FString::Printf(TEXT("\tFoliage Quality: %d"), ScalabilityQuality.FoliageQuality)); - FString RangeName; - if (UpperBound == FLT_MAX) - { - RangeName = FString::Printf(TEXT("%0.2fs - inf"), LowerBound); - } - else - { - RangeName = FString::Printf(TEXT("%0.2fs - %0.2fs"), LowerBound, UpperBound); - } - - PrintToEndpoint(FString::Printf(TEXT("Bucket: %s Count: %i Time: %.2f s"), *RangeName, HitchHistogram.GetBinObservationsCount(BucketIndex), HitchHistogram.GetBinObservationsSum(BucketIndex))); - } - - virtual void HandleHitchSummary(int32 TotalHitchCount, double TotalTimeSpentInHitchBuckets) - { - PrintToEndpoint(FString::Printf(TEXT("Total hitch count: %i"), TotalHitchCount)); - - const double ReciprocalNumHitches = (TotalHitchCount > 0) ? (1.0 / (double)TotalHitchCount) : 0.0; - PrintToEndpoint(FString::Printf(TEXT("Hitch frames bound by game thread: %i (%0.1f percent)"), Chart.TotalGameThreadBoundHitchCount, ReciprocalNumHitches * Chart.TotalGameThreadBoundHitchCount)); - PrintToEndpoint(FString::Printf(TEXT("Hitch frames bound by render thread: %i (%0.1f percent)"), Chart.TotalRenderThreadBoundHitchCount, ReciprocalNumHitches * Chart.TotalRenderThreadBoundHitchCount)); - PrintToEndpoint(FString::Printf(TEXT("Hitch frames bound by GPU: %i (%0.1f percent)"), Chart.TotalGPUBoundHitchCount, ReciprocalNumHitches * Chart.TotalGPUBoundHitchCount)); - PrintToEndpoint(FString::Printf(TEXT("Hitches / min: %.2f"), Chart.GetAvgHitchesPerMinute())); - PrintToEndpoint(FString::Printf(TEXT("Time spent in hitch buckets: %.2f s"), TotalTimeSpentInHitchBuckets)); - PrintToEndpoint(FString::Printf(TEXT("Avg. hitch frame length: %.2f s"), Chart.GetAvgHitchFrameLength())); - } - - virtual void HandleFPSThreshold(int32 TargetFPS, int32 NumFramesBelow, float PctTimeAbove, float PctMissedFrames) - { - const float PercentFramesAbove = float(NumFrames - NumFramesBelow) / float(NumFrames)*100.0f; - - PrintToEndpoint(FString::Printf(TEXT(" Target %d FPS: %.2f %% syncs missed, %4.2f %% of time spent > %d FPS (%.2f %% of frames)"), TargetFPS, PctMissedFrames, PctTimeAbove, TargetFPS, PercentFramesAbove)); - } - - virtual void HandleBasicStats() - { - PrintToEndpoint(FString::Printf(TEXT("--- Begin : FPS chart dump for level '%s'"), *MapName)); - - PrintToEndpoint(FString::Printf(TEXT("Dumping FPS chart at %s using build %s in config %s built from changelist %i"), *FDateTime::Now().ToString(), FApp::GetBuildVersion(), EBuildConfigurations::ToString(FApp::GetBuildConfiguration()), GetChangeListNumberForPerfTesting())); - - PrintToEndpoint(TEXT("Machine info:")); - PrintToEndpoint(FString::Printf(TEXT("\tOS: %s %s"), *OSMajor, *OSMinor)); - PrintToEndpoint(FString::Printf(TEXT("\tCPU: %s %s"), *CPUVendor, *CPUBrand)); - - FString CompositeGPUString = FString::Printf(TEXT("\tGPU: %s"), *ActualGPUBrand); - if (ActualGPUBrand != DesktopGPUBrand) - { - CompositeGPUString += FString::Printf(TEXT(" (desktop adapter %s)"), *DesktopGPUBrand); - } - PrintToEndpoint(CompositeGPUString); - - PrintToEndpoint(FString::Printf(TEXT("\tResolution Quality: %.2f"), ScalabilityQuality.ResolutionQuality)); - PrintToEndpoint(FString::Printf(TEXT("\tView Distance Quality: %d"), ScalabilityQuality.ViewDistanceQuality)); - PrintToEndpoint(FString::Printf(TEXT("\tAnti-Aliasing Quality: %d"), ScalabilityQuality.AntiAliasingQuality)); - PrintToEndpoint(FString::Printf(TEXT("\tShadow Quality: %d"), ScalabilityQuality.ShadowQuality)); - PrintToEndpoint(FString::Printf(TEXT("\tPost-Process Quality: %d"), ScalabilityQuality.PostProcessQuality)); - PrintToEndpoint(FString::Printf(TEXT("\tTexture Quality: %d"), ScalabilityQuality.TextureQuality)); - PrintToEndpoint(FString::Printf(TEXT("\tEffects Quality: %d"), ScalabilityQuality.EffectsQuality)); - PrintToEndpoint(FString::Printf(TEXT("\tFoliage Quality: %d"), ScalabilityQuality.FoliageQuality)); - - PrintToEndpoint(FString::Printf(TEXT("%i frames collected over %4.2f seconds, disregarding %4.2f seconds for a %4.2f FPS average"), - NumFrames, - WallClockTimeFromStartOfCharting, - TimeDisregarded, - AvgFPS)); - PrintToEndpoint(FString::Printf(TEXT("Average GPU frametime: %4.2f ms"), AvgGPUFrameTime)); - PrintToEndpoint(FString::Printf(TEXT("BoundGameThreadPct: %4.2f"), BoundGameThreadPct)); - PrintToEndpoint(FString::Printf(TEXT("BoundRenderThreadPct: %4.2f"), BoundRenderThreadPct)); - PrintToEndpoint(FString::Printf(TEXT("BoundGPUPct: %4.2f"), BoundGPUPct)); - PrintToEndpoint(FString::Printf(TEXT("ExcludeIdleTime: %d"), GFPSChartExcludeIdleTime.GetValueOnGameThread())); - } -}; - -////////////////////////////////////////////////////////////////////// + PrintToEndpoint(FString::Printf(TEXT("%i frames collected over %4.2f seconds, disregarding %4.2f seconds for a %4.2f FPS average"), + NumFrames, + WallClockTimeFromStartOfCharting, + TimeDisregarded, + AvgFPS)); + PrintToEndpoint(FString::Printf(TEXT("Average GPU frametime: %4.2f ms"), AvgGPUFrameTime)); + PrintToEndpoint(FString::Printf(TEXT("BoundGameThreadPct: %4.2f"), BoundGameThreadPct)); + PrintToEndpoint(FString::Printf(TEXT("BoundRenderThreadPct: %4.2f"), BoundRenderThreadPct)); + PrintToEndpoint(FString::Printf(TEXT("BoundGPUPct: %4.2f"), BoundGPUPct)); + PrintToEndpoint(FString::Printf(TEXT("ExcludeIdleTime: %d"), GFPSChartExcludeIdleTime.GetValueOnGameThread())); +} void FDumpFPSChartToEndpoint::DumpChart(double InWallClockTimeFromStartOfCharting, const FString& InMapName) { + FillOutMemberStats(); + TotalTime = Chart.FramerateHistogram.GetSumOfAllMeasures(); WallClockTimeFromStartOfCharting = InWallClockTimeFromStartOfCharting; NumFrames = Chart.FramerateHistogram.GetNumMeasurements(); @@ -271,10 +235,7 @@ void FDumpFPSChartToEndpoint::DumpChart(double InWallClockTimeFromStartOfChartin const float PctTimeAbove = TimesSpentAboveThreshold[ThresholdIndex]; const int32 NumFramesBelow = FramesSpentBelowThreshold[ThresholdIndex]; - - const int32 TotalTargetFrames = TargetFPS * TotalTime; - const int32 MissedFrames = FMath::Max(TotalTargetFrames - NumFrames, 0); - const float PctMissedFrames = (float)((MissedFrames * 100.0) / (double)TotalTargetFrames); + const float PctMissedFrames = (float)Chart.GetPercentMissedVSync(TargetFPS); HandleFPSThreshold(TargetFPS, NumFramesBelow, PctTimeAbove, PctMissedFrames); } @@ -395,7 +356,7 @@ protected: ParamArray.Add(FAnalyticsEventAttribute(TEXT("BuildType"), EBuildConfigurations::ToString(FApp::GetBuildConfiguration()))); ParamArray.Add(FAnalyticsEventAttribute(TEXT("DateStamp"), FDateTime::Now().ToString())); - ParamArray.Add(FAnalyticsEventAttribute(TEXT("Platform"), FString::Printf(TEXT("%s"), ANSI_TO_TCHAR(FPlatformProperties::PlatformName())))); + ParamArray.Add(FAnalyticsEventAttribute(TEXT("Platform"), FString::Printf(TEXT("%s"), ANSI_TO_TCHAR(FPlatformProperties::IniPlatformName())))); ParamArray.Add(FAnalyticsEventAttribute(TEXT("OS"), FString::Printf(TEXT("%s %s"), *OSMajor, *OSMinor))); ParamArray.Add(FAnalyticsEventAttribute(TEXT("CPU"), FString::Printf(TEXT("%s %s"), *CPUVendor, *CPUBrand))); @@ -571,7 +532,7 @@ protected: // Add non-bucket params // ParamArray.Add(FAnalyticsEventAttribute(TEXT("BuildType"), EBuildConfigurations::ToString(FApp::GetBuildConfiguration()))); - // ParamArray.Add(FAnalyticsEventAttribute(TEXT("Platform"), FString::Printf(TEXT("%s"), ANSI_TO_TCHAR(FPlatformProperties::PlatformName())))); + // ParamArray.Add(FAnalyticsEventAttribute(TEXT("Platform"), FString::Printf(TEXT("%s"), ANSI_TO_TCHAR(FPlatformProperties::IniPlatformName())))); // Sum up FrameTimes and GameTimes FPSChartRow = FPSChartRow.Replace(TEXT("TOKEN_AVG_RENDTIME"), *FString::Printf(TEXT("%4.2f ms"), float((Chart.TotalFrameTime_RenderThread / NumFrames)*1000.0)), ESearchCase::CaseSensitive); @@ -754,7 +715,7 @@ void FPerformanceTrackingChart::DumpChartsToLogFile(double WallClockElapsed, con } #endif -void FPerformanceTrackingChart::DumpChartToAnalyticsParams(const FString& InMapName, TArray& InParamArray, bool bIncludeClientHWInfo) +void FPerformanceTrackingChart::DumpChartToAnalyticsParams(const FString& InMapName, TArray& InParamArray, bool bIncludeClientHWInfo) const { // Iterate over all buckets, gathering total frame count and cumulative time. const double TotalTime = FramerateHistogram.GetSumOfAllMeasures(); @@ -774,6 +735,8 @@ void FPerformanceTrackingChart::DumpChartToAnalyticsParams(const FString& InMapN FPlatformMemoryStats Stats = FPlatformMemory::GetStats(); InParamArray.Add(FAnalyticsEventAttribute(TEXT("TotalPhysical"), static_cast(Stats.TotalPhysical))); InParamArray.Add(FAnalyticsEventAttribute(TEXT("TotalVirtual"), static_cast(Stats.TotalVirtual))); + InParamArray.Add(FAnalyticsEventAttribute(TEXT("PeakPhysical"), static_cast(Stats.PeakUsedPhysical))); + InParamArray.Add(FAnalyticsEventAttribute(TEXT("PeakVirtual"), static_cast(Stats.PeakUsedVirtual))); // Get the texture memory stats FTextureMemoryStats TexMemStats; @@ -830,12 +793,13 @@ void FPerformanceTrackingChart::DumpChartToAnalyticsParams(const FString& InMapN const EWindowMode::Type FullscreenMode = UserSettingsObj->GetLastConfirmedFullscreenMode(); InParamArray.Add(FAnalyticsEventAttribute(TEXT("WindowMode"), (int32)FullscreenMode)); - if (ensure(GEngine && GEngine->GameViewport && GEngine->GameViewport->Viewport)) + FIntPoint ViewportSize(0, 0); + if (GEngine && GEngine->GameViewport && GEngine->GameViewport->Viewport) { - const FIntPoint ViewportSize = GEngine->GameViewport->Viewport->GetSizeXY(); - InParamArray.Add(FAnalyticsEventAttribute(TEXT("SizeX"), ViewportSize.X)); - InParamArray.Add(FAnalyticsEventAttribute(TEXT("SizeY"), ViewportSize.Y)); + ViewportSize = GEngine->GameViewport->Viewport->GetSizeXY(); } + InParamArray.Add(FAnalyticsEventAttribute(TEXT("SizeX"), ViewportSize.X)); + InParamArray.Add(FAnalyticsEventAttribute(TEXT("SizeY"), ViewportSize.Y)); const int32 VSyncValue = UserSettingsObj->IsVSyncEnabled() ? 1 : 0; InParamArray.Add(FAnalyticsEventAttribute(TEXT("VSync"), (int32)VSyncValue)); @@ -1000,6 +964,7 @@ FPerformanceTrackingSystem::FPerformanceTrackingSystem() FString FPerformanceTrackingSystem::CreateFileNameForChart(const FString& ChartType, const FString& InMapName, const FString& FileExtension) { + // Note: Using PlatformName() instead of IniPlatformName() here intentionally so we can easily spot FPS charts that came from an uncooked build const FString Platform = FPlatformProperties::PlatformName(); const FString Result = InMapName + TEXT("-FPS-") + Platform + FileExtension; return Result; @@ -1134,9 +1099,7 @@ IPerformanceDataConsumer::FFrameData FPerformanceTrackingSystem::AnalyzeFrame(fl // If our frame time is much larger than our last frame time, we'll count this as a hitch! if (DeltaSeconds > (LastDeltaSeconds * HitchMultiplierAmount)) { - // We have a hitch! - GEngine->OnHitchDetectedDelegate.Broadcast(DeltaSeconds); - + // Check to see what we were limited by this frame if (GGameThreadTime >= (MaxThreadTimeValue - EpsilonCycles)) { @@ -1159,6 +1122,9 @@ IPerformanceDataConsumer::FFrameData FPerformanceTrackingSystem::AnalyzeFrame(fl FrameData.HitchStatus = EFrameHitchType::UnknownUnit; } + // We have a hitch! + GEngine->OnHitchDetectedDelegate.Broadcast(FrameData.HitchStatus, DeltaSeconds); + LastHitchTime = CurrentTime; } } @@ -1178,12 +1144,15 @@ void FPerformanceTrackingSystem::StartCharting() // Signal that we haven't ticked before LastTimeChartCreationTicked = 0.0; - //@TODO: Drive this from a cvar + // Determine which frame rates we care about GTargetFrameRatesForSummary.Reset(); - GTargetFrameRatesForSummary.Add(30); - GTargetFrameRatesForSummary.Add(60); - GTargetFrameRatesForSummary.Add(90); - GTargetFrameRatesForSummary.Add(120); + TArray InterestingFramerateStrings; + GFPSChartInterestingFramerates.GetValueOnGameThread().ParseIntoArray(InterestingFramerateStrings, TEXT(",")); + for (FString FramerateString : InterestingFramerateStrings) + { + FramerateString.Trim().TrimTrailing(); + GTargetFrameRatesForSummary.Add(FCString::Atoi(*FramerateString)); + } GGPUFrameTime = 0; diff --git a/Engine/Source/Runtime/Engine/Private/CheatManager.cpp b/Engine/Source/Runtime/Engine/Private/CheatManager.cpp index 774eec8114e7..bf63bb6cd2f3 100644 --- a/Engine/Source/Runtime/Engine/Private/CheatManager.cpp +++ b/Engine/Source/Runtime/Engine/Private/CheatManager.cpp @@ -76,8 +76,7 @@ void UCheatManager::Teleport() FHitResult Hit; APawn* AssociatedPawn = GetOuterAPlayerController()->GetPawn(); - static FName NAME_TeleportTrace = FName(TEXT("TeleportTrace")); - FCollisionQueryParams TraceParams(NAME_TeleportTrace, true, AssociatedPawn); + FCollisionQueryParams TraceParams(SCENE_QUERY_STAT(TeleportTrace), true, AssociatedPawn); bool bHit = GetWorld()->LineTraceSingleByChannel(Hit, ViewLocation, ViewLocation + 1000000.f * ViewRotation.Vector(), ECC_Pawn, TraceParams); if ( bHit ) @@ -207,38 +206,38 @@ void UCheatManager::Slomo(float NewTimeDilation) void UCheatManager::DamageTarget(float DamageAmount) { - APlayerController* const MyPC = GetOuterAPlayerController(); - FHitResult Hit; + APlayerController* const MyPC = GetOuterAPlayerController(); + FHitResult Hit; AActor* TargetActor = GetTarget(MyPC, Hit); if (TargetActor) - { - FVector ActorForward, ActorSide, ActorUp; + { + FVector ActorForward, ActorSide, ActorUp; FQuatRotationMatrix(TargetActor->GetActorQuat()).GetScaledAxes(ActorForward, ActorSide, ActorUp); - FPointDamageEvent DamageEvent(DamageAmount, Hit, -ActorForward, UDamageType::StaticClass()); + FPointDamageEvent DamageEvent(DamageAmount, Hit, -ActorForward, UDamageType::StaticClass()); TargetActor->TakeDamage(DamageAmount, DamageEvent, MyPC, MyPC->GetPawn()); - } + } } void UCheatManager::DestroyTarget() { - APlayerController* const MyPC = GetOuterAPlayerController(); - FHitResult Hit; + APlayerController* const MyPC = GetOuterAPlayerController(); + FHitResult Hit; AActor* TargetActor = GetTarget(MyPC, Hit); if (TargetActor) - { + { APawn* Pawn = Cast(TargetActor); - if (Pawn != NULL) - { - if ((Pawn->Controller != NULL) && (Cast(Pawn->Controller) == NULL)) - { - // Destroy any associated controller as long as it's not a player controller. - Pawn->Controller->Destroy(); - } - } + if (Pawn != NULL) + { + if ((Pawn->Controller != NULL) && (Cast(Pawn->Controller) == NULL)) + { + // Destroy any associated controller as long as it's not a player controller. + Pawn->Controller->Destroy(); + } + } TargetActor->Destroy(); - } + } } void UCheatManager::DestroyAll(TSubclassOf aClass) @@ -264,29 +263,29 @@ void UCheatManager::DestroyAll(TSubclassOf aClass) void UCheatManager::DestroyAllPawnsExceptTarget() { - APlayerController* const MyPC = GetOuterAPlayerController(); - FHitResult Hit; + APlayerController* const MyPC = GetOuterAPlayerController(); + FHitResult Hit; APawn* HitPawnTarget = Cast(GetTarget(MyPC, Hit)); - // if we have a pawn target, destroy all other non-players - if (HitPawnTarget) - { - for (TActorIterator It(GetWorld(), APawn::StaticClass()); It; ++It) - { - APawn* Pawn = *It; - checkSlow(Pawn); - if (!Pawn->IsPendingKill()) - { - if ((Pawn != HitPawnTarget) && Cast(Pawn->Controller) == NULL) - { - if (Pawn->Controller != NULL) - { - Pawn->Controller->Destroy(); - } - Pawn->Destroy(); - } - } - } - } + // if we have a pawn target, destroy all other non-players + if (HitPawnTarget) + { + for (TActorIterator It(GetWorld(), APawn::StaticClass()); It; ++It) + { + APawn* Pawn = *It; + checkSlow(Pawn); + if (!Pawn->IsPendingKill()) + { + if ((Pawn != HitPawnTarget) && Cast(Pawn->Controller) == NULL) + { + if (Pawn->Controller != NULL) + { + Pawn->Controller->Destroy(); + } + Pawn->Destroy(); + } + } + } + } } void UCheatManager::DestroyPawns(TSubclassOf aClass) @@ -606,6 +605,8 @@ void UCheatManager::BeginDestroy() Super::BeginDestroy(); } +/// @cond DOXYGEN_WARNINGS + bool UCheatManager::ServerToggleAILogging_Validate() { return true; @@ -648,6 +649,8 @@ void UCheatManager::ServerToggleAILogging_Implementation() #endif } +/// @endcond + void UCheatManager::ToggleAILogging() { #if ENABLE_VISUAL_LOG @@ -688,8 +691,7 @@ void UCheatManager::TickCollisionDebug() FVector End = ViewLoc + (DebugTraceDistance * ViewDir); // Fill in params and do trace - static const FName TickCollisionDebugName(TEXT("TickCollisionDebug")); - FCollisionQueryParams CapsuleParams(TickCollisionDebugName, false, PC->GetPawn()); + FCollisionQueryParams CapsuleParams(SCENE_QUERY_STAT(TickCollisionDebug), false, PC->GetPawn()); CapsuleParams.bTraceComplex = bDebugCapsuleTraceComplex; if (bDebugCapsuleSweep) @@ -1207,7 +1209,7 @@ AActor* UCheatManager::GetTarget(APlayerController* PlayerController, struct FHi FVector const CamLoc = PlayerController->PlayerCameraManager->GetCameraLocation(); FRotator const CamRot = PlayerController->PlayerCameraManager->GetCameraRotation(); - FCollisionQueryParams TraceParams(NAME_None, true, PlayerController->GetPawn()); + FCollisionQueryParams TraceParams(NAME_None, FCollisionQueryParams::GetUnknownStatId(), true, PlayerController->GetPawn()); bool bHit = GetWorld()->LineTraceSingleByChannel(OutHit, CamLoc, CamRot.Vector() * 100000.f + CamLoc, ECC_Pawn, TraceParams); if (bHit) { diff --git a/Engine/Source/Runtime/Engine/Private/Collision/Collision.cpp b/Engine/Source/Runtime/Engine/Private/Collision/Collision.cpp index a9d364ee1aba..887da1e8db3c 100644 --- a/Engine/Source/Runtime/Engine/Private/Collision/Collision.cpp +++ b/Engine/Source/Runtime/Engine/Private/Collision/Collision.cpp @@ -49,7 +49,7 @@ bool FHitResult::NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSu } // pack bitfield with flags - uint8 Flags = (bBlockingHit << 0) | (bStartPenetrating << 1) | (bImpactPointEqualsLocation << 2) | (bImpactNormalEqualsNormal << 3) | (bInvalidItem << 4) | (bInvalidFaceIndex << 5) | (bInvalidFaceIndex << 6); + uint8 Flags = (bBlockingHit << 0) | (bStartPenetrating << 1) | (bImpactPointEqualsLocation << 2) | (bImpactNormalEqualsNormal << 3) | (bInvalidItem << 4) | (bInvalidFaceIndex << 5) | (bNoPenetrationDepth << 6); Ar.SerializeBits(&Flags, 7); bBlockingHit = (Flags & (1 << 0)) ? 1 : 0; bStartPenetrating = (Flags & (1 << 1)) ? 1 : 0; @@ -146,11 +146,12 @@ UPrimitiveComponent* FOverlapResult::GetComponent() const ////////////////////////////////////////////////////////////////////////// // FCollisionQueryParams -FCollisionQueryParams::FCollisionQueryParams(FName InTraceTag, bool bInTraceComplex, const AActor* InIgnoreActor) +FCollisionQueryParams::FCollisionQueryParams(FName InTraceTag, const TStatId& InStatId, bool bInTraceComplex, const AActor* InIgnoreActor) { bTraceComplex = bInTraceComplex; MobilityType = EQueryMobilityType::Any; TraceTag = InTraceTag; + StatId = InStatId; bTraceAsyncScene = false; bFindInitialOverlaps = true; bReturnFaceIndex = false; diff --git a/Engine/Source/Runtime/Engine/Private/Collision/PhysXCollision.cpp b/Engine/Source/Runtime/Engine/Private/Collision/PhysXCollision.cpp index 944bb1ece769..c8c21fa8040e 100644 --- a/Engine/Source/Runtime/Engine/Private/Collision/PhysXCollision.cpp +++ b/Engine/Source/Runtime/Engine/Private/Collision/PhysXCollision.cpp @@ -628,8 +628,8 @@ PxQueryHitType::Enum FPxQueryFilterCallback::preFilter(const PxFilterData& filte } // Check if the shape is the right complexity for the trace - PxFilterData ShapeFilter = shape->getQueryFilterData(); - PxFilterData ShapeSimFilter = shape->getSimulationFilterData(); //This is a bit of a hack. We do this because word2 has our component ID + const PxFilterData ShapeFilter = shape->getQueryFilterData(); + #define ENABLE_PREFILTER_LOGGING 0 #if ENABLE_PREFILTER_LOGGING static bool bLoggingEnabled=false; @@ -675,12 +675,19 @@ PxQueryHitType::Enum FPxQueryFilterCallback::preFilter(const PxFilterData& filte // If not already rejected, check ignore actor and component list. if (Result != PxQueryHitType::eNONE) { - // See if we are ignoring the actor this shape belongs to (word0 of shape filterdata is actorID) or the component (word2 of shape sim filter data is componentID) - if (IgnoreActors.Contains(ShapeFilter.word0) || IgnoreComponents.Contains(ShapeSimFilter.word2)) + // See if we are ignoring the actor this shape belongs to (word0 of shape filterdata is actorID) + if (IgnoreActors.Contains(ShapeFilter.word0)) { //UE_LOG(LogTemp, Log, TEXT("Ignoring Actor: %d"), ShapeFilter.word0); Result = PxQueryHitType::eNONE; } + + // We usually don't have ignore components so we try to avoid the virtual getSimulationFilterData() call below. 'word2' of shape sim filter data is componentID. + if (IgnoreComponents.Num() > 0 && IgnoreComponents.Contains(shape->getSimulationFilterData().word2)) + { + //UE_LOG(LogTemp, Log, TEXT("Ignoring Component: %d"), shape->getSimulationFilterData().word2); + Result = PxQueryHitType::eNONE; + } } #if ENABLE_PREFILTER_LOGGING @@ -904,7 +911,9 @@ bool RaycastTest(const UWorld* World, const FVector Start, const FVector End, EC { return false; } + SCOPE_CYCLE_COUNTER(STAT_Collision_SceneQueryTotal); SCOPE_CYCLE_COUNTER(STAT_Collision_RaycastAny); + FScopeCycleCounter Counter(Params.StatId); STARTQUERYTIMER(); bool bHaveBlockingHit = false; // Track if we get any 'blocking' hits @@ -959,7 +968,7 @@ bool RaycastTest(const UWorld* World, const FVector Start, const FVector End, EC TArray Hits; #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) - if ((World->DebugDrawTraceTag != NAME_None) && (World->DebugDrawTraceTag == Params.TraceTag) && IsInGameThread()) + if(World->DebugDrawSceneQueries(Params.TraceTag)) { DrawLineTraces(World, Start, End, Hits, DebugLineLifetime); } @@ -971,7 +980,9 @@ bool RaycastTest(const UWorld* World, const FVector Start, const FVector End, EC bool RaycastSingle(const UWorld* World, struct FHitResult& OutHit, const FVector Start, const FVector End, ECollisionChannel TraceChannel, const struct FCollisionQueryParams& Params, const struct FCollisionResponseParams& ResponseParams, const struct FCollisionObjectQueryParams& ObjectParams) { + SCOPE_CYCLE_COUNTER(STAT_Collision_SceneQueryTotal); SCOPE_CYCLE_COUNTER(STAT_Collision_RaycastSingle); + FScopeCycleCounter Counter(Params.StatId); STARTQUERYTIMER(); OutHit = FHitResult(); @@ -1074,7 +1085,7 @@ bool RaycastSingle(const UWorld* World, struct FHitResult& OutHit, const FVector #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) - if ((World->DebugDrawTraceTag != NAME_None) && (World->DebugDrawTraceTag == Params.TraceTag) && IsInGameThread()) + if (World->DebugDrawSceneQueries(Params.TraceTag)) { TArray Hits; if (bHaveBlockingHit) @@ -1143,7 +1154,9 @@ public: bool RaycastMulti(const UWorld* World, TArray& OutHits, const FVector& Start, const FVector& End, ECollisionChannel TraceChannel, const struct FCollisionQueryParams& Params, const struct FCollisionResponseParams& ResponseParams, const struct FCollisionObjectQueryParams& ObjectParams) { + SCOPE_CYCLE_COUNTER(STAT_Collision_SceneQueryTotal); SCOPE_CYCLE_COUNTER(STAT_Collision_RaycastMultiple); + FScopeCycleCounter Counter(Params.StatId); STARTQUERYTIMER(); OutHits.Reset(); @@ -1285,7 +1298,7 @@ bool RaycastMulti(const UWorld* World, TArray& OutHits, const } #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) - if((World->DebugDrawTraceTag != NAME_None) && (World->DebugDrawTraceTag == Params.TraceTag)) + if(World->DebugDrawSceneQueries(Params.TraceTag)) { DrawLineTraces(World, Start, End, OutHits, DebugLineLifetime); } @@ -1396,7 +1409,9 @@ bool GeomSweepTest(const UWorld* World, const struct FCollisionShape& CollisionS { return false; } + SCOPE_CYCLE_COUNTER(STAT_Collision_SceneQueryTotal); SCOPE_CYCLE_COUNTER(STAT_Collision_GeomSweepAny); + FScopeCycleCounter Counter(Params.StatId); STARTQUERYTIMER(); bool bHaveBlockingHit = false; // Track if we get any 'blocking' hits @@ -1443,7 +1458,7 @@ bool GeomSweepTest(const UWorld* World, const struct FCollisionShape& CollisionS } #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) - if((World->DebugDrawTraceTag != NAME_None) && (World->DebugDrawTraceTag == Params.TraceTag)) + if(World->DebugDrawSceneQueries(Params.TraceTag)) { TArray Hits; DrawGeomSweeps(World, Start, End, PGeom, PGeomRot, Hits, DebugLineLifetime); @@ -1467,7 +1482,9 @@ bool GeomSweepTest(const UWorld* World, const struct FCollisionShape& CollisionS bool GeomSweepSingle(const UWorld* World, const struct FCollisionShape& CollisionShape, const FQuat& Rot, FHitResult& OutHit, FVector Start, FVector End, ECollisionChannel TraceChannel, const struct FCollisionQueryParams& Params, const struct FCollisionResponseParams& ResponseParams, const struct FCollisionObjectQueryParams& ObjectParams) { + SCOPE_CYCLE_COUNTER(STAT_Collision_SceneQueryTotal); SCOPE_CYCLE_COUNTER(STAT_Collision_GeomSweepSingle); + FScopeCycleCounter Counter(Params.StatId); STARTQUERYTIMER(); OutHit = FHitResult(); @@ -1564,7 +1581,7 @@ bool GeomSweepSingle(const UWorld* World, const struct FCollisionShape& Collisio } #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) - if((World->DebugDrawTraceTag != NAME_None) && (World->DebugDrawTraceTag == Params.TraceTag)) + if (World->DebugDrawSceneQueries(Params.TraceTag)) { TArray Hits; if (bHaveBlockingHit) @@ -1596,7 +1613,9 @@ bool GeomSweepSingle(const UWorld* World, const struct FCollisionShape& Collisio bool GeomSweepMulti_PhysX(const UWorld* World, const PxGeometry& PGeom, const PxQuat& PGeomRot, TArray& OutHits, FVector Start, FVector End, ECollisionChannel TraceChannel, const struct FCollisionQueryParams& Params, const struct FCollisionResponseParams& ResponseParams, const struct FCollisionObjectQueryParams& ObjectParams) { + SCOPE_CYCLE_COUNTER(STAT_Collision_SceneQueryTotal); SCOPE_CYCLE_COUNTER(STAT_Collision_GeomSweepMultiple); + FScopeCycleCounter Counter(Params.StatId); STARTQUERYTIMER(); bool bBlockingHit = false; @@ -1684,7 +1703,7 @@ bool GeomSweepMulti_PhysX(const UWorld* World, const PxGeometry& PGeom, const Px } #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) - if ((World->DebugDrawTraceTag != NAME_None) && (World->DebugDrawTraceTag == Params.TraceTag) && IsInGameThread()) + if (World->DebugDrawSceneQueries(Params.TraceTag)) { TArray OnlyMyHits(OutHits); OnlyMyHits.RemoveAt(0, InitialHitCount, false); // Remove whatever was there initially. @@ -1707,8 +1726,6 @@ bool GeomSweepMulti_PhysX(const UWorld* World, const PxGeometry& PGeom, const Px bool GeomSweepMulti(const UWorld* World, const struct FCollisionShape& CollisionShape, const FQuat& Rot, TArray& OutHits, FVector Start, FVector End, ECollisionChannel TraceChannel, const struct FCollisionQueryParams& Params, const struct FCollisionResponseParams& ResponseParams, const struct FCollisionObjectQueryParams& ObjectParams) { - SCOPE_CYCLE_COUNTER(STAT_Collision_GeomSweepMultiple); - OutHits.Reset(); if ((World == NULL) || (World->GetPhysicsScene() == NULL)) @@ -1751,7 +1768,9 @@ namespace EQueryInfo template bool GeomOverlapMultiImp_PhysX(const UWorld* World, const PxGeometry& PGeom, const PxTransform& PGeomPose, TArray& OutOverlaps, ECollisionChannel TraceChannel, const struct FCollisionQueryParams& Params, const struct FCollisionResponseParams& ResponseParams, const struct FCollisionObjectQueryParams& ObjectParams) { + SCOPE_CYCLE_COUNTER(STAT_Collision_SceneQueryTotal); SCOPE_CYCLE_COUNTER(STAT_Collision_GeomOverlapMultiple); + FScopeCycleCounter Counter(Params.StatId); STARTQUERYTIMER(); bool bHaveBlockingHit = false; @@ -1837,7 +1856,7 @@ bool GeomOverlapMultiImp_PhysX(const UWorld* World, const PxGeometry& PGeom, con } #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) - if ((World->DebugDrawTraceTag != NAME_None) && (World->DebugDrawTraceTag == Params.TraceTag) && IsInGameThread()) + if (World->DebugDrawSceneQueries(Params.TraceTag)) { DrawGeomOverlaps(World, PGeom, PGeomPose, OutOverlaps, DebugLineLifetime); } diff --git a/Engine/Source/Runtime/Engine/Private/Collision/WorldCollision.cpp b/Engine/Source/Runtime/Engine/Private/Collision/WorldCollision.cpp index 25c5bc7a4880..200e29f54c3f 100644 --- a/Engine/Source/Runtime/Engine/Private/Collision/WorldCollision.cpp +++ b/Engine/Source/Runtime/Engine/Private/Collision/WorldCollision.cpp @@ -26,14 +26,13 @@ DEFINE_LOG_CATEGORY(LogCollision); /** Collision stats */ +DEFINE_STAT(STAT_Collision_SceneQueryTotal); DEFINE_STAT(STAT_Collision_RaycastAny); DEFINE_STAT(STAT_Collision_RaycastSingle); DEFINE_STAT(STAT_Collision_RaycastMultiple); DEFINE_STAT(STAT_Collision_GeomSweepAny); DEFINE_STAT(STAT_Collision_GeomSweepSingle); DEFINE_STAT(STAT_Collision_GeomSweepMultiple); -DEFINE_STAT(STAT_Collision_GeomOverlapAny); -DEFINE_STAT(STAT_Collision_GeomOverlapSingle); DEFINE_STAT(STAT_Collision_GeomOverlapMultiple); DEFINE_STAT(STAT_Collision_FBodyInstance_OverlapMulti); DEFINE_STAT(STAT_Collision_FBodyInstance_OverlapTest); @@ -47,8 +46,8 @@ FCollisionResponseContainer FCollisionResponseContainer::DefaultResponseContaine /* This is default response param that's used by trace query **/ FCollisionResponseParams FCollisionResponseParams::DefaultResponseParam; FCollisionObjectQueryParams FCollisionObjectQueryParams::DefaultObjectQueryParam; -FCollisionQueryParams FCollisionQueryParams::DefaultQueryParam(TEXT("DefaultQueryParam"),true); -FComponentQueryParams FComponentQueryParams::DefaultComponentQueryParams(TEXT("DefaultComponentQueryParam")); +FCollisionQueryParams FCollisionQueryParams::DefaultQueryParam(SCENE_QUERY_STAT(DefaultQueryParam), true); +FComponentQueryParams FComponentQueryParams::DefaultComponentQueryParams(SCENE_QUERY_STAT(DefaultComponentQueryParams)); FCollisionShape FCollisionShape::LineShape; // default being the 0. That isn't invalid, but ObjectQuery param overrides this @@ -391,7 +390,7 @@ bool UWorld::OverlapMultiByProfile(TArray& OutOverlaps, c } -bool UWorld::ComponentOverlapMulti(TArray& OutOverlaps, const class UPrimitiveComponent* PrimComp, const FVector& Pos, const FQuat& Quat, const struct FComponentQueryParams& Params, const struct FCollisionObjectQueryParams& ObjectQueryParams) const +bool UWorld::ComponentOverlapMulti(TArray& OutOverlaps, const class UPrimitiveComponent* PrimComp, const FVector& Pos, const FQuat& Quat, const FComponentQueryParams& Params, const FCollisionObjectQueryParams& ObjectQueryParams) const { if (PrimComp) { @@ -420,7 +419,7 @@ bool UWorld::ComponentOverlapMultiByChannel(TArray& OutOv } } -bool UWorld::ComponentSweepMulti(TArray& OutHits, class UPrimitiveComponent* PrimComp, const FVector& Start, const FVector& End, const FQuat& Quat, const struct FComponentQueryParams& Params) const +bool UWorld::ComponentSweepMulti(TArray& OutHits, class UPrimitiveComponent* PrimComp, const FVector& Start, const FVector& End, const FQuat& Quat, const FComponentQueryParams& Params) const { if (GetPhysicsScene() == NULL) { diff --git a/Engine/Source/Runtime/Engine/Private/ComponentInstanceDataCache.cpp b/Engine/Source/Runtime/Engine/Private/ComponentInstanceDataCache.cpp index 811381920204..874117a9ee4d 100644 --- a/Engine/Source/Runtime/Engine/Private/ComponentInstanceDataCache.cpp +++ b/Engine/Source/Runtime/Engine/Private/ComponentInstanceDataCache.cpp @@ -3,11 +3,150 @@ #include "ComponentInstanceDataCache.h" #include "Serialization/ObjectWriter.h" #include "Serialization/ObjectReader.h" +#include "Serialization/DuplicatedObject.h" +#include "UObject/Package.h" +#include "UObject/UObjectAnnotation.h" +#include "UObject/UObjectGlobals.h" +#include "UObject/UObjectHash.h" #include "Engine/EngineTypes.h" #include "Components/ActorComponent.h" #include "Components/SceneComponent.h" #include "GameFramework/Actor.h" +class FComponentPropertyWriter : public FObjectWriter +{ +public: + FComponentPropertyWriter(const UActorComponent* InComponent, TArray& InBytes, TArray& InInstancedObjects) + : FObjectWriter(InBytes) + , Component(InComponent) + , InstancedObjects(InInstancedObjects) + { + // Include properties that would normally skip tagged serialization (e.g. bulk serialization of array properties). + ArPortFlags |= PPF_ForceTaggedSerialization; + + if (Component) + { + UClass* ComponentClass = Component->GetClass(); + + Component->GetUCSModifiedProperties(PropertiesToSkip); + + if (AActor* ComponentOwner = Component->GetOwner()) + { + // If this is the owning Actor's root scene component, don't include relative transform properties. This is handled elsewhere. + if (Component == ComponentOwner->GetRootComponent()) + { + PropertiesToSkip.Add(ComponentClass->FindPropertyByName(GET_MEMBER_NAME_CHECKED(USceneComponent, RelativeLocation))); + PropertiesToSkip.Add(ComponentClass->FindPropertyByName(GET_MEMBER_NAME_CHECKED(USceneComponent, RelativeRotation))); + PropertiesToSkip.Add(ComponentClass->FindPropertyByName(GET_MEMBER_NAME_CHECKED(USceneComponent, RelativeScale3D))); + } + } + + ComponentClass->SerializeTaggedProperties(*this, (uint8*)Component, ComponentClass, (uint8*)Component->GetArchetype()); + } + } + + virtual ~FComponentPropertyWriter() + { + DuplicatedObjectAnnotation.RemoveAllAnnotations(); + } + + virtual bool ShouldSkipProperty(const UProperty* InProperty) const override + { + return ( InProperty->HasAnyPropertyFlags(CPF_Transient) + || !InProperty->HasAnyPropertyFlags(CPF_Edit | CPF_Interp) + || PropertiesToSkip.Contains(InProperty)); + } + + + UObject* GetDuplicatedObject(UObject* Object) + { + UObject* Result = Object; + if (IsValid(Object)) + { + // Check for an existing duplicate of the object. + FDuplicatedObject DupObjectInfo = DuplicatedObjectAnnotation.GetAnnotation( Object ); + if( !DupObjectInfo.IsDefault() ) + { + Result = DupObjectInfo.DuplicatedObject; + } + else if (Object->GetOuter() == Component) + { + Result = DuplicateObject(Object, GetTransientPackage()); + InstancedObjects.Add(Result); + } + else + { + check(Object->IsIn(Component)); + + // Check to see if the object's outer is being duplicated. + UObject* DupOuter = GetDuplicatedObject(Object->GetOuter()); + if (DupOuter != nullptr) + { + // First check if the duplicated outer already has an allocated duplicate of this object + Result = static_cast(FindObjectWithOuter(DupOuter, Object->GetClass(), Object->GetFName())); + + if (Result == nullptr) + { + // The object's outer is being duplicated, create a duplicate of this object. + Result = DuplicateObject(Object, DupOuter); + } + + DuplicatedObjectAnnotation.AddAnnotation( Object, FDuplicatedObject( Result ) ); + } + } + } + + return Result; + } + + virtual FArchive& operator<<(UObject*& Object) override + { + UObject* SerializedObject = Object; + if (Object && Object->IsIn(Component)) + { + SerializedObject = GetDuplicatedObject(Object); + } + + // store the pointer to this object + Serialize(&SerializedObject, sizeof(UObject*)); + + return *this; + } + +private: + + const UActorComponent* Component; + + TSet PropertiesToSkip; + + TArray& InstancedObjects; + + FUObjectAnnotationSparse DuplicatedObjectAnnotation; +}; + +class FComponentPropertyReader : public FObjectReader +{ +public: + FComponentPropertyReader(UActorComponent* InComponent, TArray& InBytes) + : FObjectReader(InBytes) + { + // Include properties that would normally skip tagged serialization (e.g. bulk serialization of array properties). + ArPortFlags |= PPF_ForceTaggedSerialization; + + InComponent->GetUCSModifiedProperties(PropertiesToSkip); + + UClass* Class = InComponent->GetClass(); + Class->SerializeTaggedProperties(*this, (uint8*)InComponent, Class, nullptr); + } + + virtual bool ShouldSkipProperty(const UProperty* InProperty) const override + { + return PropertiesToSkip.Contains(InProperty); + } + + TSet PropertiesToSkip; +}; + FActorComponentInstanceData::FActorComponentInstanceData() : SourceComponentTemplate(nullptr) , SourceComponentTypeSerializedIndex(-1) @@ -55,60 +194,20 @@ FActorComponentInstanceData::FActorComponentInstanceData(const UActorComponent* if (SourceComponent->IsEditableWhenInherited()) { - class FComponentPropertyWriter : public FObjectWriter - { - public: - FComponentPropertyWriter(const UActorComponent* Component, TArray& InBytes) - : FObjectWriter(InBytes) - { - // Include properties that would normally skip tagged serialization (e.g. bulk serialization of array properties). - ArPortFlags |= PPF_ForceTaggedSerialization; - - if (Component) - { - UClass* ComponentClass = Component->GetClass(); - - Component->GetUCSModifiedProperties(PropertiesToSkip); - - if (AActor* ComponentOwner = Component->GetOwner()) - { - // If this is the owning Actor's root scene component, don't include relative transform properties. This is handled elsewhere. - if (Component == ComponentOwner->GetRootComponent()) - { - PropertiesToSkip.Add(ComponentClass->FindPropertyByName(GET_MEMBER_NAME_CHECKED(USceneComponent, RelativeLocation))); - PropertiesToSkip.Add(ComponentClass->FindPropertyByName(GET_MEMBER_NAME_CHECKED(USceneComponent, RelativeRotation))); - PropertiesToSkip.Add(ComponentClass->FindPropertyByName(GET_MEMBER_NAME_CHECKED(USceneComponent, RelativeScale3D))); - } - } - - ComponentClass->SerializeTaggedProperties(*this, (uint8*)Component, ComponentClass, (uint8*)Component->GetArchetype()); - } - } - - virtual bool ShouldSkipProperty(const UProperty* InProperty) const override - { - return ( InProperty->HasAnyPropertyFlags(CPF_Transient | CPF_ContainsInstancedReference | CPF_InstancedReference) - || !InProperty->HasAnyPropertyFlags(CPF_Edit | CPF_Interp) - || PropertiesToSkip.Contains(InProperty)); - } - - private: - TSet PropertiesToSkip; - - }; - - FComponentPropertyWriter ComponentPropertyWriter(SourceComponent, SavedProperties); + FComponentPropertyWriter ComponentPropertyWriter(SourceComponent, SavedProperties, InstancedObjects); // Cache off the length of an array that will come from SerializeTaggedProperties that had no properties saved in to it. auto GetSizeOfEmptyArchive = [](const UActorComponent* DummyComponent) -> int32 { TArray NoWrittenPropertyReference; - FComponentPropertyWriter NullWriter(nullptr, NoWrittenPropertyReference); + TArray NoInstances; + FComponentPropertyWriter NullWriter(nullptr, NoWrittenPropertyReference, NoInstances); UClass* ComponentClass = DummyComponent->GetClass(); // By serializing the component with itself as its defaults we guarantee that no properties will be written out ComponentClass->SerializeTaggedProperties(NullWriter, (uint8*)DummyComponent, ComponentClass, (uint8*)DummyComponent); + check(NoInstances.Num() == 0); return NoWrittenPropertyReference.Num(); }; @@ -167,29 +266,12 @@ void FActorComponentInstanceData::ApplyToComponent(UActorComponent* Component, c { Component->DetermineUCSModifiedProperties(); - class FComponentPropertyReader : public FObjectReader + for (UObject* InstancedObject : InstancedObjects) { - public: - FComponentPropertyReader(UActorComponent* InComponent, TArray& InBytes) - : FObjectReader(InBytes) - { - // Include properties that would normally skip tagged serialization (e.g. bulk serialization of array properties). - ArPortFlags |= PPF_ForceTaggedSerialization; + InstancedObject->Rename(nullptr, Component); + } - InComponent->GetUCSModifiedProperties(PropertiesToSkip); - - UClass* Class = InComponent->GetClass(); - Class->SerializeTaggedProperties(*this, (uint8*)InComponent, Class, nullptr); - } - - virtual bool ShouldSkipProperty(const UProperty* InProperty) const override - { - return PropertiesToSkip.Contains(InProperty); - } - - TSet PropertiesToSkip; - - } ComponentPropertyReader(Component, SavedProperties); + FComponentPropertyReader ComponentPropertyReader(Component, SavedProperties); if (Component->IsRegistered()) { @@ -201,6 +283,7 @@ void FActorComponentInstanceData::ApplyToComponent(UActorComponent* Component, c void FActorComponentInstanceData::AddReferencedObjects(FReferenceCollector& Collector) { Collector.AddReferencedObject(SourceComponentTemplate); + Collector.AddReferencedObjects(InstancedObjects); } FComponentInstanceDataCache::FComponentInstanceDataCache(const AActor* Actor) @@ -231,6 +314,7 @@ FComponentInstanceDataCache::FComponentInstanceDataCache(const AActor* Actor) { if (SceneComponent->GetAttachParent() && SceneComponent->GetAttachParent()->IsCreatedByConstructionScript()) { + SceneComponent->ConditionalUpdateComponentToWorld(); InstanceComponentTransformToRootMap.Add(SceneComponent, SceneComponent->GetComponentTransform().GetRelativeTransform(Actor->GetRootComponent()->GetComponentTransform())); } } diff --git a/Engine/Source/Runtime/Engine/Private/Components/ActorComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/ActorComponent.cpp index e9f3910c84ac..bb5879c33dcc 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/ActorComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/ActorComponent.cpp @@ -49,9 +49,27 @@ DECLARE_CYCLE_STAT(TEXT("Component DestroyRenderState"), STAT_ComponentDestroyRe DECLARE_CYCLE_STAT(TEXT("Component CreatePhysicsState"), STAT_ComponentCreatePhysicsState, STATGROUP_Component); DECLARE_CYCLE_STAT(TEXT("Component DestroyPhysicsState"), STAT_ComponentDestroyPhysicsState, STATGROUP_Component); +// Should we tick latent actions fired for a component at the same time as the component? +// - Non-zero values behave the same way as actors do, ticking pending latent action when the component ticks, instead of later on in the frame +// - Prior to 4.16, components behaved as if the value were 0, which meant their latent actions behaved differently to actors +//DEPRECATED(4.16, "This CVar will be removed, with the behavior permanently changing in the future to always tick component latent actions along with the component") +int32 GTickComponentLatentActionsWithTheComponent = 1; + +// Should we tick latent actions fired for a component at the same time as the component? +FAutoConsoleVariableRef GTickComponentLatentActionsWithTheComponentCVar( + TEXT("t.TickComponentLatentActionsWithTheComponent"), + GTickComponentLatentActionsWithTheComponent, + TEXT("Should we tick latent actions fired for a component at the same time as the component?\n") + TEXT(" 0: Tick component latent actions later on in the frame (behavior prior to 4.16, provided for games relying on the old behavior but will be removed in the future)\n") + TEXT(" 1: Tick component latent actions at the same time as the component (default)")); + /** Enable to log out all render state create, destroy and updatetransform events */ #define LOG_RENDER_STATE 0 +#if WITH_EDITOR +FUObjectAnnotationSparseBool GSelectedComponentAnnotation; +#endif + /** Static var indicating activity of reregister context */ int32 FGlobalComponentReregisterContext::ActiveGlobalReregisterContextCount = 0; @@ -614,6 +632,11 @@ void UActorComponent::PostEditUndo() Super::PostEditUndo(); } +bool UActorComponent::IsSelectedInEditor() const +{ + return !IsPendingKill() && GSelectedComponentAnnotation.Get(this); +} + void UActorComponent::ConsolidatedPostEditChange(const FPropertyChangedEvent& PropertyChangedEvent) { static const FName NAME_CanEverAffectNavigation = GET_MEMBER_NAME_CHECKED(UActorComponent, bCanEverAffectNavigation); @@ -866,15 +889,17 @@ void UActorComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, F ReceiveTick(DeltaTime); - // Update any latent actions we have for this component, this will update even if paused if bUpdateWhilePaused is enabled - // If this tick is skipped on a frame because we've got a TickInterval, our latent actions will be ticked - // anyway by UWorld::Tick(). Given that, our latent actions don't need to be passed a larger - // DeltaSeconds to make up the frames that they missed (because they wouldn't have missed any). - // So pass in the world's DeltaSeconds value rather than our specific DeltaSeconds value. - UWorld* ComponentWorld = GetWorld(); - if (ComponentWorld) + if (GTickComponentLatentActionsWithTheComponent) { - ComponentWorld->GetLatentActionManager().ProcessLatentActions(this, ComponentWorld->GetDeltaSeconds()); + // Update any latent actions we have for this component, this will update even if paused if bUpdateWhilePaused is enabled + // If this tick is skipped on a frame because we've got a TickInterval, our latent actions will be ticked + // anyway by UWorld::Tick(). Given that, our latent actions don't need to be passed a larger + // DeltaSeconds to make up the frames that they missed (because they wouldn't have missed any). + // So pass in the world's DeltaSeconds value rather than our specific DeltaSeconds value. + if (UWorld* ComponentWorld = GetWorld()) + { + ComponentWorld->GetLatentActionManager().ProcessLatentActions(this, ComponentWorld->GetDeltaSeconds()); + } } } @@ -1668,7 +1693,7 @@ void UActorComponent::DetermineUCSModifiedProperties() virtual bool ShouldSkipProperty(const UProperty* InProperty) const override { - return ( InProperty->HasAnyPropertyFlags(CPF_Transient | CPF_ContainsInstancedReference | CPF_InstancedReference) + return ( InProperty->HasAnyPropertyFlags(CPF_Transient) || !InProperty->HasAnyPropertyFlags(CPF_Edit | CPF_Interp)); } } PropertySkipper; diff --git a/Engine/Source/Runtime/Engine/Private/Components/AudioComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/AudioComponent.cpp index bb63d8638e46..117fd2fcee9b 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/AudioComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/AudioComponent.cpp @@ -49,7 +49,6 @@ UAudioComponent::UAudioComponent(const FObjectInitializer& ObjectInitializer) AudioDeviceHandle = INDEX_NONE; AudioComponentID = ++AudioComponentIDCounter; - AudioComponentUserID = INDEX_NONE; // TODO: Consider only putting played/active components in to the map AudioIDToComponentMap.Add(AudioComponentID, this); @@ -194,7 +193,7 @@ void UAudioComponent::OnUpdateTransform(EUpdateTransformFlags UpdateTransformFla DECLARE_CYCLE_STAT(TEXT("FAudioThreadTask.UpdateTransform"), STAT_AudioUpdateTransform, STATGROUP_AudioThreadCommands); const uint64 MyAudioComponentID = AudioComponentID; - const FTransform& MyTransform = ComponentToWorld; + const FTransform& MyTransform = GetComponentTransform(); FAudioThread::RunCommandOnAudioThread([AudioDevice, MyAudioComponentID, MyTransform]() { @@ -238,7 +237,7 @@ void UAudioComponent::PlayInternal(const float StartTime, const float FadeInDura float MaxDistance = 0.0f; float FocusFactor = 0.0f; - FVector Location = ComponentToWorld.GetLocation(); + FVector Location = GetComponentTransform().GetLocation(); AudioDevice->GetMaxDistanceAndFocusFactor(Sound, World, Location, AttenuationSettingsToApply, MaxDistance, FocusFactor); @@ -289,7 +288,7 @@ void UAudioComponent::PlayInternal(const float StartTime, const float FadeInDura if (NewActiveSound.bLocationDefined) { - NewActiveSound.Transform = ComponentToWorld; + NewActiveSound.Transform = GetComponentTransform(); } NewActiveSound.bAllowSpatialization = bAllowSpatialization; @@ -960,3 +959,40 @@ void UAudioComponent::SetSubmixSend(USoundSubmix* Submix, float SendLevel) } } +void UAudioComponent::SetLowPassFilterEnabled(bool InLowPassFilterEnabled) +{ + if (FAudioDevice* AudioDevice = GetAudioDevice()) + { + DECLARE_CYCLE_STAT(TEXT("FAudioThreadTask.SetLowPassFilterFrequency"), STAT_AudioSetLowPassFilterEnabled, STATGROUP_AudioThreadCommands); + + const uint64 MyAudioComponentID = AudioComponentID; + FAudioThread::RunCommandOnAudioThread([AudioDevice, MyAudioComponentID, InLowPassFilterEnabled]() + { + FActiveSound* ActiveSound = AudioDevice->FindActiveSound(MyAudioComponentID); + if (ActiveSound) + { + ActiveSound->bEnableLowPassFilter = InLowPassFilterEnabled; + } + }, GET_STATID(STAT_AudioSetLowPassFilterEnabled)); + } +} + +void UAudioComponent::SetLowPassFilterFrequency(float InLowPassFilterFrequency) +{ + if (FAudioDevice* AudioDevice = GetAudioDevice()) + { + DECLARE_CYCLE_STAT(TEXT("FAudioThreadTask.SetLowPassFilterFrequency"), STAT_AudioSetLowPassFilterFrequency, STATGROUP_AudioThreadCommands); + + const uint64 MyAudioComponentID = AudioComponentID; + FAudioThread::RunCommandOnAudioThread([AudioDevice, MyAudioComponentID, InLowPassFilterFrequency]() + { + FActiveSound* ActiveSound = AudioDevice->FindActiveSound(MyAudioComponentID); + if (ActiveSound) + { + ActiveSound->LowPassFilterFrequency = InLowPassFilterFrequency; + } + }, GET_STATID(STAT_AudioSetLowPassFilterFrequency)); + } +} + + diff --git a/Engine/Source/Runtime/Engine/Private/Components/BillboardComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/BillboardComponent.cpp index 3cb9cf19cb0a..ed431ebde4ec 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/BillboardComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/BillboardComponent.cpp @@ -53,7 +53,7 @@ public: bWillEverBeLit = false; // Calculate the scale factor for the sprite. - float Scale = InComponent->ComponentToWorld.GetMaximumAxisScale(); + float Scale = InComponent->GetComponentTransform().GetMaximumAxisScale(); if(InComponent->Sprite) { @@ -258,6 +258,7 @@ private: UBillboardComponent::UBillboardComponent(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { +#if WITH_EDITORONLY_DATA // Structure to hold one-time initialization struct FConstructorStatics { @@ -272,8 +273,6 @@ UBillboardComponent::UBillboardComponent(const FObjectInitializer& ObjectInitial } }; - -#if WITH_EDITORONLY_DATA static FConstructorStatics ConstructorStatics; Sprite = ConstructorStatics.SpriteTexture.Object; #endif @@ -292,6 +291,7 @@ UBillboardComponent::UBillboardComponent(const FObjectInitializer& ObjectInitial bUseEditorCompositing = true; #if WITH_EDITORONLY_DATA + Sprite = ConstructorStatics.SpriteTexture.Object; SpriteInfo.Category = ConstructorStatics.ID_Misc; SpriteInfo.DisplayName = ConstructorStatics.NAME_Misc; bUseInEditorScaling = true; @@ -323,7 +323,7 @@ bool UBillboardComponent::ComponentIsTouchingSelectionBox(const FBox& InSelBBox, if (!bConsiderOnlyBSP && ShowFlags.BillboardSprites && Sprite != nullptr && Actor != nullptr) { - const float Scale = ComponentToWorld.GetMaximumAxisScale(); + const float Scale = GetComponentTransform().GetMaximumAxisScale(); // Construct a box representing the sprite const FBox SpriteBox( @@ -349,7 +349,7 @@ bool UBillboardComponent::ComponentIsTouchingSelectionFrustum(const FConvexVolum if (!bConsiderOnlyBSP && ShowFlags.BillboardSprites && Sprite != nullptr && Actor != nullptr) { - const float Scale = ComponentToWorld.GetMaximumAxisScale(); + const float Scale = GetComponentTransform().GetMaximumAxisScale(); const float MaxExtent = FMath::Max(Sprite->GetSizeX(), Sprite->GetSizeY()); const FVector Extent = Scale * MaxExtent * FVector(0.5f, 0.5f, 0.0f); diff --git a/Engine/Source/Runtime/Engine/Private/Components/BoxComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/BoxComponent.cpp index ef01e1893fc4..26ae18109d7f 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/BoxComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/BoxComponent.cpp @@ -31,7 +31,7 @@ void UBoxComponent::SetBoxExtent(FVector NewBoxExtent, bool bUpdateOverlaps) if (bPhysicsStateCreated) { // Update physics engine collision shapes - BodyInstance.UpdateBodyScale(ComponentToWorld.GetScale3D(), true); + BodyInstance.UpdateBodyScale(GetComponentTransform().GetScale3D(), true); if ( bUpdateOverlaps && IsCollisionEnabled() && GetOwner() ) { diff --git a/Engine/Source/Runtime/Engine/Private/Components/BrushComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/BrushComponent.cpp index 46df78b710e3..7caee4f30a66 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/BrushComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/BrushComponent.cpp @@ -536,12 +536,9 @@ void UBrushComponent::GetUsedMaterials( TArray& OutMaterial if( Brush && Brush->Polys ) { UPolys* Polys = Brush->Polys; - if( Polys ) + for( int32 ElementIdx = 0; ElementIdx < Polys->Element.Num(); ++ElementIdx ) { - for( int32 ElementIdx = 0; ElementIdx < Polys->Element.Num(); ++ElementIdx ) - { - OutMaterials.Add( Polys->Element[ ElementIdx ].Material ); - } + OutMaterials.Add( Polys->Element[ ElementIdx ].Material ); } } #endif // WITH_EDITOR @@ -631,7 +628,7 @@ bool UBrushComponent::ComponentIsTouchingSelectionBox(const FBox& InSelBBox, con { for (const auto& Vertex : Poly.Vertices) { - const FVector Location = ComponentToWorld.TransformPosition(Vertex); + const FVector Location = GetComponentTransform().TransformPosition(Vertex); const bool bLocationIntersected = FMath::PointBoxIntersection(Location, InSelBBox); // If the selection box doesn't have to encompass the entire component and any poly vertex intersects with the selection @@ -652,10 +649,10 @@ bool UBrushComponent::ComponentIsTouchingSelectionBox(const FBox& InSelBBox, con const int32 NumVerts = Poly.Vertices.Num(); if (NumVerts > 0) { - FVector StartVert = ComponentToWorld.TransformPosition(Poly.Vertices[NumVerts - 1]); + FVector StartVert = GetComponentTransform().TransformPosition(Poly.Vertices[NumVerts - 1]); for (int32 Index = 0; Index < NumVerts; ++Index) { - const FVector EndVert = ComponentToWorld.TransformPosition(Poly.Vertices[Index]); + const FVector EndVert = GetComponentTransform().TransformPosition(Poly.Vertices[Index]); if (FMath::LineBoxIntersection(InSelBBox, StartVert, EndVert, EndVert - StartVert)) { @@ -678,7 +675,7 @@ bool UBrushComponent::ComponentIsTouchingSelectionBox(const FBox& InSelBBox, con // The component must be entirely within the bounding box... for (const auto& Vertex : Poly.Vertices) { - const FVector Location = ComponentToWorld.TransformPosition(Vertex); + const FVector Location = GetComponentTransform().TransformPosition(Vertex); const bool bLocationIntersected = FMath::PointBoxIntersection(Location, InSelBBox); // If the selection box has to encompass the entire component and a poly vertex didn't intersect with the selection @@ -714,7 +711,7 @@ bool UBrushComponent::ComponentIsTouchingSelectionFrustum(const FConvexVolume& I { for (const auto& Vertex : Poly.Vertices) { - const FVector Location = ComponentToWorld.TransformPosition(Vertex); + const FVector Location = GetComponentTransform().TransformPosition(Vertex); const bool bIntersect = InFrustum.IntersectSphere(Location, 0.0f); if (bIntersect && !bMustEncompassEntireComponent) diff --git a/Engine/Source/Runtime/Engine/Private/Components/CapsuleComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/CapsuleComponent.cpp index 062c851e00ac..efe24001de0e 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/CapsuleComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/CapsuleComponent.cpp @@ -97,9 +97,9 @@ FBoxSphereBounds UCapsuleComponent::CalcBounds(const FTransform& LocalToWorld) c void UCapsuleComponent::CalcBoundingCylinder(float& CylinderRadius, float& CylinderHalfHeight) const { - const float Scale = ComponentToWorld.GetMaximumAxisScale(); + const float Scale = GetComponentTransform().GetMaximumAxisScale(); const float CapsuleEndCapCenter = FMath::Max(CapsuleHalfHeight - CapsuleRadius, 0.f); - const FVector ZAxis = ComponentToWorld.TransformVectorNoScale(FVector(0.f, 0.f, CapsuleEndCapCenter * Scale)); + const FVector ZAxis = GetComponentTransform().TransformVectorNoScale(FVector(0.f, 0.f, CapsuleEndCapCenter * Scale)); const float ScaledRadius = CapsuleRadius * Scale; @@ -165,7 +165,7 @@ void UCapsuleComponent::SetCapsuleSize(float NewRadius, float NewHalfHeight, boo if (bPhysicsStateCreated) { // Update physics engine collision shapes - BodyInstance.UpdateBodyScale(ComponentToWorld.GetScale3D(), true); + BodyInstance.UpdateBodyScale(GetComponentTransform().GetScale3D(), true); if ( bUpdateOverlaps && IsCollisionEnabled() && GetOwner() ) { diff --git a/Engine/Source/Runtime/Engine/Private/Components/CharacterMovementComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/CharacterMovementComponent.cpp index ea320040965d..5cbe6ecb8121 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/CharacterMovementComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/CharacterMovementComponent.cpp @@ -78,20 +78,6 @@ const float UCharacterMovementComponent::MAX_FLOOR_DIST = 2.4f; const float UCharacterMovementComponent::BRAKE_TO_STOP_VELOCITY = 10.f; const float UCharacterMovementComponent::SWEEP_EDGE_REJECT_DISTANCE = 0.15f; -// Statics -namespace CharacterMovementComponentStatics -{ - static const FName CrouchTraceName = FName(TEXT("CrouchTrace")); - static const FName FindWaterLineName = FName(TEXT("FindWaterLine")); - static const FName FallingTraceParamsTag = FName(TEXT("PhysFalling")); - static const FName CheckLedgeDirectionName = FName(TEXT("CheckLedgeDirection")); - static const FName ProjectLocationName = FName(TEXT("NavProjectLocation")); - static const FName CheckWaterJumpName = FName(TEXT("CheckWaterJump")); - static const FName ComputeFloorDistName = FName(TEXT("ComputeFloorDistSweep")); - static const FName FloorLineTraceName = FName(TEXT("ComputeFloorDistLineTrace")); - static const FName ImmersionDepthName = FName(TEXT("MovementComp_Character_ImmersionDepth")); -} - // CVars namespace CharacterMovementCVars { @@ -2363,7 +2349,7 @@ void UCharacterMovementComponent::Crouch(bool bClientSimulation) // Crouching to a larger height? (this is rare) if (ClampedCrouchedHalfHeight > OldUnscaledHalfHeight) { - FCollisionQueryParams CapsuleParams(CharacterMovementComponentStatics::CrouchTraceName, false, CharacterOwner); + FCollisionQueryParams CapsuleParams(SCENE_QUERY_STAT(CrouchTrace), false, CharacterOwner); FCollisionResponseParams ResponseParam; InitCollisionParams(CapsuleParams, ResponseParam); const bool bEncroached = GetWorld()->OverlapBlockingTestByChannel(UpdatedComponent->GetComponentLocation() - FVector(0.f,0.f,ScaledHalfHeightAdjust), FQuat::Identity, @@ -2445,7 +2431,7 @@ void UCharacterMovementComponent::UnCrouch(bool bClientSimulation) { // Try to stay in place and see if the larger capsule fits. We use a slightly taller capsule to avoid penetration. const float SweepInflation = KINDA_SMALL_NUMBER * 10.f; - FCollisionQueryParams CapsuleParams(CharacterMovementComponentStatics::CrouchTraceName, false, CharacterOwner); + FCollisionQueryParams CapsuleParams(SCENE_QUERY_STAT(CrouchTrace), false, CharacterOwner); FCollisionResponseParams ResponseParam; InitCollisionParams(CapsuleParams, ResponseParam); @@ -2856,7 +2842,7 @@ float UCharacterMovementComponent::ImmersionDepth() const const FVector TraceStart = UpdatedComponent->GetComponentLocation() + FVector(0.f,0.f,CollisionHalfHeight); const FVector TraceEnd = UpdatedComponent->GetComponentLocation() - FVector(0.f,0.f,CollisionHalfHeight); - FCollisionQueryParams NewTraceParams(CharacterMovementComponentStatics::ImmersionDepthName, true); + FCollisionQueryParams NewTraceParams(SCENE_QUERY_STAT(ImmersionDepth), true); VolumeBrushComp->LineTraceComponent( Hit, TraceStart, TraceEnd, NewTraceParams ); } @@ -3777,7 +3763,7 @@ FVector UCharacterMovementComponent::FindWaterLine(FVector InWater, FVector Outo FVector Result = OutofWater; TArray Hits; - GetWorld()->LineTraceMultiByChannel(Hits, OutofWater, InWater, UpdatedComponent->GetCollisionObjectType(), FCollisionQueryParams(CharacterMovementComponentStatics::FindWaterLineName, true, CharacterOwner)); + GetWorld()->LineTraceMultiByChannel(Hits, OutofWater, InWater, UpdatedComponent->GetCollisionObjectType(), FCollisionQueryParams(SCENE_QUERY_STAT(FindWaterLine), true, CharacterOwner)); for( int32 HitIdx = 0; HitIdx < Hits.Num(); HitIdx++ ) { @@ -4119,7 +4105,7 @@ bool UCharacterMovementComponent::FindAirControlImpact(float DeltaTime, float Ad if (!TestWalk.IsZero()) { - FCollisionQueryParams CapsuleQuery(CharacterMovementComponentStatics::FallingTraceParamsTag, false, CharacterOwner); + FCollisionQueryParams CapsuleQuery(SCENE_QUERY_STAT(FallingTraceParam), false, CharacterOwner); FCollisionResponseParams ResponseParam; InitCollisionParams(CapsuleQuery, ResponseParam); const FVector CapsuleLocation = UpdatedComponent->GetComponentLocation(); @@ -4164,7 +4150,7 @@ FVector UCharacterMovementComponent::LimitAirControl(float DeltaTime, const FVec bool UCharacterMovementComponent::CheckLedgeDirection(const FVector& OldLocation, const FVector& SideStep, const FVector& GravDir) const { const FVector SideDest = OldLocation + SideStep; - FCollisionQueryParams CapsuleParams(CharacterMovementComponentStatics::CheckLedgeDirectionName, false, CharacterOwner); + FCollisionQueryParams CapsuleParams(SCENE_QUERY_STAT(CheckLedgeDirection), false, CharacterOwner); FCollisionResponseParams ResponseParam; InitCollisionParams(CapsuleParams, ResponseParam); const FCollisionShape CapsuleShape = GetPawnCapsuleCollisionShape(SHRINK_None); @@ -4931,7 +4917,7 @@ void UCharacterMovementComponent::FindBestNavMeshLocation(const FVector& TraceSt // raycast to underlying mesh to allow us to more closely follow geometry // we use static objects here as a best approximation to accept only objects that // influence navmesh generation - FCollisionQueryParams Params(CharacterMovementComponentStatics::ProjectLocationName, false); + FCollisionQueryParams Params(SCENE_QUERY_STAT(ProjectLocation), false); // blocked by world static and optionally world dynamic FCollisionResponseParams ResponseParams(ECR_Ignore); @@ -5325,6 +5311,12 @@ FRotator UCharacterMovementComponent::ComputeOrientToMovementRotation(const FRot return Acceleration.GetSafeNormal().Rotation(); } +bool UCharacterMovementComponent::ShouldRemainVertical() const +{ + // Always remain vertical when walking or falling. + return IsMovingOnGround() || IsFalling(); +} + void UCharacterMovementComponent::PhysicsRotation(float DeltaTime) { if (!(bOrientRotationToMovement || bUseControllerDesiredRotation)) @@ -5357,8 +5349,7 @@ void UCharacterMovementComponent::PhysicsRotation(float DeltaTime) return; } - // Always remain vertical when walking or falling. - if (IsMovingOnGround() || IsFalling()) + if (ShouldRemainVertical()) { DesiredRotation.Pitch = 0.f; DesiredRotation.Yaw = FRotator::NormalizeAxis(DesiredRotation.Yaw); @@ -5472,7 +5463,7 @@ bool UCharacterMovementComponent::CheckWaterJump(FVector CheckPoint, FVector& Wa CheckPoint = UpdatedComponent->GetComponentLocation() + 1.2f * PawnCapsuleRadius * CheckNorm; FVector Extent(PawnCapsuleRadius, PawnCapsuleRadius, PawnCapsuleHalfHeight); FHitResult HitInfo(1.f); - FCollisionQueryParams CapsuleParams(CharacterMovementComponentStatics::CheckWaterJumpName, false, CharacterOwner); + FCollisionQueryParams CapsuleParams(SCENE_QUERY_STAT(CheckWaterJump), false, CharacterOwner); FCollisionResponseParams ResponseParam; InitCollisionParams(CapsuleParams, ResponseParam); FCollisionShape CapsuleShape = GetPawnCapsuleCollisionShape(SHRINK_None); @@ -5486,7 +5477,7 @@ bool UCharacterMovementComponent::CheckWaterJump(FVector CheckPoint, FVector& Wa FVector Start = UpdatedComponent->GetComponentLocation(); Start.Z += MaxOutOfWaterStepHeight; CheckPoint = Start + 3.2f * PawnCapsuleRadius * WallNormal; - FCollisionQueryParams LineParams(CharacterMovementComponentStatics::CheckWaterJumpName, true, CharacterOwner); + FCollisionQueryParams LineParams(SCENE_QUERY_STAT(CheckWaterJump), true, CharacterOwner); FCollisionResponseParams LineResponseParam; InitCollisionParams(LineParams, LineResponseParam); bHit = GetWorld()->LineTraceSingleByChannel( HitInfo, Start, CheckPoint, CollisionChannel, LineParams, LineResponseParam ); @@ -5704,7 +5695,7 @@ void UCharacterMovementComponent::ComputeFloorDist(const FVector& CapsuleLocatio } bool bBlockingHit = false; - FCollisionQueryParams QueryParams(NAME_None, false, CharacterOwner); + FCollisionQueryParams QueryParams(SCENE_QUERY_STAT(ComputeFloorDist), false, CharacterOwner); FCollisionResponseParams ResponseParam; InitCollisionParams(QueryParams, ResponseParam); const ECollisionChannel CollisionChannel = UpdatedComponent->GetCollisionObjectType(); @@ -5718,7 +5709,6 @@ void UCharacterMovementComponent::ComputeFloorDist(const FVector& CapsuleLocatio const float ShrinkScaleOverlap = 0.1f; float ShrinkHeight = (PawnHalfHeight - PawnRadius) * (1.f - ShrinkScale); float TraceDist = SweepDistance + ShrinkHeight; - QueryParams.TraceTag = CharacterMovementComponentStatics::ComputeFloorDistName; FCollisionShape CapsuleShape = FCollisionShape::MakeCapsule(SweepRadius, PawnHalfHeight - ShrinkHeight); FHitResult Hit(1.f); @@ -5777,7 +5767,7 @@ void UCharacterMovementComponent::ComputeFloorDist(const FVector& CapsuleLocatio const FVector LineTraceStart = CapsuleLocation; const float TraceDist = LineDistance + ShrinkHeight; const FVector Down = FVector(0.f, 0.f, -TraceDist); - QueryParams.TraceTag = CharacterMovementComponentStatics::FloorLineTraceName; + QueryParams.TraceTag = SCENE_QUERY_STAT_NAME_ONLY(FloorLineTrace); FHitResult Hit(1.f); bBlockingHit = GetWorld()->LineTraceSingleByChannel(Hit, LineTraceStart, LineTraceStart + Down, CollisionChannel, QueryParams, ResponseParam); @@ -7408,12 +7398,7 @@ void UCharacterMovementComponent::ForcePositionUpdate(float DeltaTime) FNetworkPredictionData_Client* UCharacterMovementComponent::GetPredictionData_Client() const { - // Should only be called on client or listen server (for remote clients) in network games - check(CharacterOwner != NULL); - checkSlow(CharacterOwner->Role < ROLE_Authority || (CharacterOwner->GetRemoteRole() == ROLE_AutonomousProxy && GetNetMode() == NM_ListenServer)); - checkSlow(GetNetMode() == NM_Client || GetNetMode() == NM_ListenServer); - - if (!ClientPredictionData) + if (ClientPredictionData == nullptr) { UCharacterMovementComponent* MutableThis = const_cast(this); MutableThis->ClientPredictionData = new FNetworkPredictionData_Client_Character(*this); @@ -7424,12 +7409,7 @@ FNetworkPredictionData_Client* UCharacterMovementComponent::GetPredictionData_Cl FNetworkPredictionData_Server* UCharacterMovementComponent::GetPredictionData_Server() const { - // Should only be called on server in network games - check(CharacterOwner != NULL); - check(CharacterOwner->Role == ROLE_Authority); - checkSlow(GetNetMode() < NM_Client); - - if (!ServerPredictionData) + if (ServerPredictionData == nullptr) { UCharacterMovementComponent* MutableThis = const_cast(this); MutableThis->ServerPredictionData = new FNetworkPredictionData_Server_Character(*this); @@ -7441,13 +7421,35 @@ FNetworkPredictionData_Server* UCharacterMovementComponent::GetPredictionData_Se FNetworkPredictionData_Client_Character* UCharacterMovementComponent::GetPredictionData_Client_Character() const { - return static_cast(GetPredictionData_Client()); + // Should only be called on client or listen server (for remote clients) in network games + checkSlow(CharacterOwner != NULL); + checkSlow(CharacterOwner->Role < ROLE_Authority || (CharacterOwner->GetRemoteRole() == ROLE_AutonomousProxy && GetNetMode() == NM_ListenServer)); + checkSlow(GetNetMode() == NM_Client || GetNetMode() == NM_ListenServer); + + if (ClientPredictionData == nullptr) + { + UCharacterMovementComponent* MutableThis = const_cast(this); + MutableThis->ClientPredictionData = static_cast(GetPredictionData_Client()); + } + + return ClientPredictionData; } FNetworkPredictionData_Server_Character* UCharacterMovementComponent::GetPredictionData_Server_Character() const { - return static_cast(GetPredictionData_Server()); + // Should only be called on server in network games + checkSlow(CharacterOwner != NULL); + checkSlow(CharacterOwner->Role == ROLE_Authority); + checkSlow(GetNetMode() < NM_Client); + + if (ServerPredictionData == nullptr) + { + UCharacterMovementComponent* MutableThis = const_cast(this); + MutableThis->ServerPredictionData = static_cast(GetPredictionData_Server()); + } + + return ServerPredictionData; } bool UCharacterMovementComponent::HasPredictionData_Client() const @@ -8271,11 +8273,11 @@ void UCharacterMovementComponent::ServerMoveHandleClientError(float ClientTimeSt { if (GetDefault()->ClientAuthorativePosition) { - const FVector LocDiff = UpdatedComponent->GetComponentLocation() - ClientLoc; + const FVector LocDiff = UpdatedComponent->GetComponentLocation() - ClientLoc; //-V595 if (!LocDiff.IsZero() || ClientMovementMode != PackNetworkMovementMode() || GetMovementBase() != ClientMovementBase || (CharacterOwner && CharacterOwner->GetBasedMovement().BoneName != ClientBaseBoneName)) { // Just set the position. On subsequent moves we will resolve initially overlapping conditions. - UpdatedComponent->SetWorldLocation(ClientLoc, false); + UpdatedComponent->SetWorldLocation(ClientLoc, false); //-V595 // Trust the client's movement mode. ApplyNetworkMovementMode(ClientMovementMode); @@ -8408,10 +8410,13 @@ void UCharacterMovementComponent::MoveAutonomous } // If not playing root motion, tick animations after physics. We do this here to keep events, notifies, states and transitions in sync with client updates. - if( !CharacterOwner->bClientUpdating && !CharacterOwner->IsPlayingRootMotion() && CharacterOwner->GetMesh() ) + if( CharacterOwner && !CharacterOwner->bClientUpdating && !CharacterOwner->IsPlayingRootMotion() && CharacterOwner->GetMesh() ) { TickCharacterPose(DeltaTime); // TODO: SaveBaseLocation() in case tick moves us? + + // Trigger Events right away, as we could be receiving multiple ServerMoves per frame. + CharacterOwner->GetMesh()->ConditionallyDispatchQueuedAnimEvents(); } if (CharacterOwner && UpdatedComponent) @@ -8625,28 +8630,9 @@ void UCharacterMovementComponent::ClientAdjustPosition_Implementation WorldShiftedNewLocation = FRepMovement::RebaseOntoLocalOrigin(NewLocation, this); } -#if !UE_BUILD_SHIPPING - if (CharacterMovementCVars::NetShowCorrections != 0) - { - const FVector LocDiff = UpdatedComponent->GetComponentLocation() - WorldShiftedNewLocation; - const FString NewBaseString = NewBase ? NewBase->GetPathName(NewBase->GetOutermost()) : TEXT("None"); - UE_LOG(LogNetPlayerMovement, Warning, TEXT("*** Client: Error for %s at Time=%.3f is %3.3f LocDiff(%s) ClientLoc(%s) ServerLoc(%s) NewBase: %s NewBone: %s ClientVel(%s) ServerVel(%s) SavedMoves %d"), - *GetNameSafe(CharacterOwner), TimeStamp, LocDiff.Size(), *LocDiff.ToString(), *UpdatedComponent->GetComponentLocation().ToString(), *WorldShiftedNewLocation.ToString(), *NewBaseString, *NewBaseBoneName.ToString(), *Velocity.ToString(), *NewVelocity.ToString(), ClientData->SavedMoves.Num()); - const float DebugLifetime = CharacterMovementCVars::NetCorrectionLifetime; - DrawDebugCapsule(GetWorld(), UpdatedComponent->GetComponentLocation() , CharacterOwner->GetSimpleCollisionHalfHeight(), CharacterOwner->GetSimpleCollisionRadius(), FQuat::Identity, FColor(255, 100, 100), true, DebugLifetime); - DrawDebugCapsule(GetWorld(), WorldShiftedNewLocation, CharacterOwner->GetSimpleCollisionHalfHeight(), CharacterOwner->GetSimpleCollisionRadius(), FQuat::Identity, FColor(100, 255, 100), true, DebugLifetime); - } -#endif //!UE_BUILD_SHIPPING -#if ROOT_MOTION_DEBUG - if (RootMotionSourceDebug::CVarDebugRootMotionSources.GetValueOnAnyThread() == 1) - { - const FVector VelocityCorrection = NewVelocity - Velocity; - FString AdjustedDebugString = FString::Printf(TEXT("PerformMovement ClientAdjustPosition_Implementation Velocity(%s) OldVelocity(%s) Correction(%s) TimeStamp(%f)"), - *NewVelocity.ToCompactString(), *Velocity.ToCompactString(), *VelocityCorrection.ToCompactString(), TimeStamp); - RootMotionSourceDebug::PrintOnScreen(*CharacterOwner, AdjustedDebugString); - } -#endif + // Trigger event + OnClientCorrectionReceived(*ClientData, TimeStamp, NewLocation, NewVelocity, NewBase, NewBaseBoneName, bHasBase, bBaseRelativePosition, ServerMovementMode); // Trust the server's positioning. UpdatedComponent->SetWorldLocation(WorldShiftedNewLocation, false); @@ -8668,7 +8654,7 @@ void UCharacterMovementComponent::ClientAdjustPosition_Implementation // If walking, we'd like to continue walking if possible, to avoid falling for a frame, so try to find a base where we moved to. if (PreviousBase) { - FindFloor(UpdatedComponent->GetComponentLocation(), CurrentFloor, false); + FindFloor(UpdatedComponent->GetComponentLocation(), CurrentFloor, false); //-V595 if (CurrentFloor.IsWalkableFloor()) { FinalBase = CurrentFloor.HitResult.Component.Get(); @@ -8698,6 +8684,34 @@ void UCharacterMovementComponent::ClientAdjustPosition_Implementation ClientData->bUpdatePosition = true; } + +void UCharacterMovementComponent::OnClientCorrectionReceived(FNetworkPredictionData_Client_Character& ClientData, float TimeStamp, FVector NewLocation, FVector NewVelocity, UPrimitiveComponent* NewBase, FName NewBaseBoneName, bool bHasBase, bool bBaseRelativePosition, uint8 ServerMovementMode) +{ +#if !UE_BUILD_SHIPPING + if (CharacterMovementCVars::NetShowCorrections != 0) + { + const FVector LocDiff = UpdatedComponent->GetComponentLocation() - NewLocation; + const FString NewBaseString = NewBase ? NewBase->GetPathName(NewBase->GetOutermost()) : TEXT("None"); + UE_LOG(LogNetPlayerMovement, Warning, TEXT("*** Client: Error for %s at Time=%.3f is %3.3f LocDiff(%s) ClientLoc(%s) ServerLoc(%s) NewBase: %s NewBone: %s ClientVel(%s) ServerVel(%s) SavedMoves %d"), + *GetNameSafe(CharacterOwner), TimeStamp, LocDiff.Size(), *LocDiff.ToString(), *UpdatedComponent->GetComponentLocation().ToString(), *NewLocation.ToString(), *NewBaseString, *NewBaseBoneName.ToString(), *Velocity.ToString(), *NewVelocity.ToString(), ClientData.SavedMoves.Num()); + const float DebugLifetime = CharacterMovementCVars::NetCorrectionLifetime; + DrawDebugCapsule(GetWorld(), UpdatedComponent->GetComponentLocation(), CharacterOwner->GetSimpleCollisionHalfHeight(), CharacterOwner->GetSimpleCollisionRadius(), FQuat::Identity, FColor(255, 100, 100), true, DebugLifetime); + DrawDebugCapsule(GetWorld(), NewLocation, CharacterOwner->GetSimpleCollisionHalfHeight(), CharacterOwner->GetSimpleCollisionRadius(), FQuat::Identity, FColor(100, 255, 100), true, DebugLifetime); + } +#endif //!UE_BUILD_SHIPPING + +#if ROOT_MOTION_DEBUG + if (RootMotionSourceDebug::CVarDebugRootMotionSources.GetValueOnAnyThread() == 1) + { + const FVector VelocityCorrection = NewVelocity - Velocity; + FString AdjustedDebugString = FString::Printf(TEXT("PerformMovement ClientAdjustPosition_Implementation Velocity(%s) OldVelocity(%s) Correction(%s) TimeStamp(%f)"), + *NewVelocity.ToCompactString(), *Velocity.ToCompactString(), *VelocityCorrection.ToCompactString(), TimeStamp); + RootMotionSourceDebug::PrintOnScreen(*CharacterOwner, AdjustedDebugString); + } +#endif +} + + void UCharacterMovementComponent::ClientAdjustRootMotionPosition_Implementation( float TimeStamp, float ServerMontageTrackPosition, @@ -9004,7 +9018,7 @@ void UCharacterMovementComponent::ApplyRepulsionForce(float DeltaSeconds) const TArray& Overlaps = UpdatedPrimitive->GetOverlapInfos(); if (Overlaps.Num() > 0) { - FCollisionQueryParams QueryParams; + FCollisionQueryParams QueryParams (SCENE_QUERY_STAT(CMC_ApplyRepulsionForce)); QueryParams.bReturnFaceIndex = false; QueryParams.bReturnPhysicalMaterial = false; @@ -10181,3 +10195,28 @@ void UCharacterMovementComponent::UpdateFromCompressedFlags(uint8 Flags) } } +void UCharacterMovementComponent::FlushServerMoves() +{ + // Send pendingMove to server if this character is replicating movement + if (CharacterOwner && CharacterOwner->bReplicateMovement) + { + FNetworkPredictionData_Client_Character* ClientData = GetPredictionData_Client_Character(); + if (!ClientData) + { + return; + } + + if (ClientData->PendingMove.IsValid() != false) + { + const UWorld* MyWorld = GetWorld(); + + ClientData->ClientUpdateTime = MyWorld->TimeSeconds; + + FSavedMovePtr NewMove = ClientData->PendingMove; + + ClientData->PendingMove = NULL; + CallServerMove(NewMove.Get(), nullptr); + } + } +} + diff --git a/Engine/Source/Runtime/Engine/Private/Components/ChildActorComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/ChildActorComponent.cpp index a5732eceac91..48370471410a 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/ChildActorComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/ChildActorComponent.cpp @@ -22,8 +22,9 @@ void UChildActorComponent::OnRegister() if (ChildActor) { - if (ChildActor->GetClass() != ChildActorClass) + if (bNeedsRecreate || ChildActor->GetClass() != ChildActorClass) { + bNeedsRecreate = false; DestroyChildActor(); CreateChildActor(); } @@ -119,6 +120,30 @@ void UChildActorComponent::Serialize(FArchive& Ar) } #if WITH_EDITOR +void UChildActorComponent::PostEditImport() +{ + Super::PostEditImport(); + + if (IsTemplate()) + { + TArray Children; + GetObjectsWithOuter(this, Children, false); + + for (UObject* Child : Children) + { + if (Child->GetClass() == ChildActorClass) + { + ChildActorTemplate = CastChecked(Child); + break; + } + } + } + else + { + ChildActorTemplate = CastChecked(GetArchetype())->ChildActorTemplate; + } +} + void UChildActorComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) { if (PropertyChangedEvent.Property && PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UChildActorComponent, ChildActorClass)) @@ -353,7 +378,7 @@ void UChildActorComponent::ApplyComponentInstanceData(FChildActorComponentInstan USceneComponent* ChildActorRoot = ChildActor->GetRootComponent(); if (ChildActorRoot) { - for (const auto& AttachInfo : ChildActorInstanceData->AttachedActors) + for (const FChildActorComponentInstanceData::FAttachedActorInfo& AttachInfo : ChildActorInstanceData->AttachedActors) { AActor* AttachedActor = AttachInfo.Actor.Get(); if (AttachedActor) @@ -361,7 +386,7 @@ void UChildActorComponent::ApplyComponentInstanceData(FChildActorComponentInstan USceneComponent* AttachedRootComponent = AttachedActor->GetRootComponent(); if (AttachedRootComponent) { - AttachedActor->DetachRootComponentFromParent(); + AttachedActor->DetachFromActor(FDetachmentTransformRules::KeepWorldTransform); AttachedRootComponent->AttachToComponent(ChildActorRoot, FAttachmentTransformRules::KeepWorldTransform, AttachInfo.SocketName); AttachedRootComponent->SetRelativeTransform(AttachInfo.RelativeTransform); AttachedRootComponent->UpdateComponentToWorld(); @@ -430,8 +455,7 @@ void UChildActorComponent::PostLoad() // Don't do this if there is no linker which implies component was created via duplication if (ChildActorTemplate && GetLinker()) { - ChildActor->MarkPendingKill(); - ChildActor = nullptr; + bNeedsRecreate = true; } else { @@ -487,7 +511,10 @@ void UChildActorComponent::CreateChildActor() Params.bAllowDuringConstructionScript = true; Params.OverrideLevel = (MyOwner ? MyOwner->GetLevel() : nullptr); Params.Name = ChildActorName; - Params.Template = ChildActorTemplate; + if (ChildActorTemplate && ChildActorTemplate->GetClass() == ChildActorClass) + { + Params.Template = ChildActorTemplate; + } Params.ObjectFlags |= (RF_TextExportTransient | RF_NonPIEDuplicateTransient); if (!HasAllFlags(RF_Transactional)) { @@ -510,7 +537,7 @@ void UChildActorComponent::CreateChildActor() // Parts that we deferred from SpawnActor const FComponentInstanceDataCache* ComponentInstanceData = (CachedInstanceData ? CachedInstanceData->ComponentInstanceData : nullptr); - ChildActor->FinishSpawning(ComponentToWorld, false, ComponentInstanceData); + ChildActor->FinishSpawning(GetComponentTransform(), false, ComponentInstanceData); ChildActor->AttachToComponent(this, FAttachmentTransformRules::SnapToTargetNotIncludingScale); diff --git a/Engine/Source/Runtime/Engine/Private/Components/DestructibleComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/DestructibleComponent.cpp index 072a659fbf75..2812580d9066 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/DestructibleComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/DestructibleComponent.cpp @@ -143,7 +143,7 @@ void UDestructibleComponent::OnUpdateTransform(EUpdateTransformFlags UpdateTrans return; } - const FTransform& CurrentLocalToWorld = ComponentToWorld; + const FTransform& CurrentLocalToWorld = GetComponentTransform(); #if !(UE_BUILD_SHIPPING) if(CurrentLocalToWorld.ContainsNaN()) @@ -253,9 +253,9 @@ void UDestructibleComponent::OnCreatePhysicsState() // Get the default actor descriptor NvParameterized data from the asset NvParameterized::Interface* ActorParams = TheDestructibleMesh->GetDestructibleActorDesc(PhysMat); - // Create PhysX transforms from ComponentToWorld - const PxTransform GlobalPose(U2PVector(ComponentToWorld.GetTranslation()), U2PQuat(ComponentToWorld.GetRotation())); - const PxVec3 Scale = U2PVector(ComponentToWorld.GetScale3D()); + // Create PhysX transforms from GetComponentTransform() + const PxTransform GlobalPose(U2PVector(GetComponentTransform().GetTranslation()), U2PQuat(GetComponentTransform().GetRotation())); + const PxVec3 Scale = U2PVector(GetComponentTransform().GetScale3D()); // Set the transform in the actor descriptor verify( NvParameterized::setParamTransform(*ActorParams,"globalPose",GlobalPose) ); @@ -837,7 +837,7 @@ void UDestructibleComponent::SetSkeletalMesh(USkeletalMesh* InSkelMesh, bool bRe if(TheDestructibleMesh != NULL) { // Resize the fracture effects array to the appropriate size - FractureEffects.AddZeroed(TheDestructibleMesh->ApexDestructibleAsset->getDepthCount()); + FractureEffects.SetNumZeroed(TheDestructibleMesh->ApexDestructibleAsset->getDepthCount()); } #else SetDestructibleMesh(TheDestructibleMesh); @@ -985,7 +985,7 @@ void UDestructibleComponent::UpdateDestructibleChunkTM(const TArraySyncComponentToRBPhysics(); } @@ -998,7 +998,7 @@ void UDestructibleComponent::UpdateDestructibleChunkTM(const TArray& UpdateInfos) { - const FQuat InvRotation = ComponentToWorld.GetRotation().Inverse(); + const FQuat InvRotation = GetComponentTransform().GetRotation().Inverse(); for (const FUpdateChunksInfo& UpdateInfo : UpdateInfos) { @@ -1008,7 +1008,7 @@ void UDestructibleComponent::SetChunksWorldTM(const TArray& U const FQuat WorldRotation = UpdateInfo.WorldTM.GetRotation(); const FQuat BoneRotation = InvRotation*WorldRotation; - const FVector BoneTranslation = InvRotation.RotateVector(WorldTranslation - ComponentToWorld.GetTranslation()) / ComponentToWorld.GetScale3D(); + const FVector BoneTranslation = InvRotation.RotateVector(WorldTranslation - GetComponentTransform().GetTranslation()) / GetComponentTransform().GetScale3D(); GetEditableComponentSpaceTransforms()[BoneIndex] = FTransform(BoneRotation, BoneTranslation); } @@ -1035,14 +1035,14 @@ void UDestructibleComponent::SetChunkWorldRT( int32 ChunkIndex, const FQuat& Wor MarkRenderDynamicDataDirty(); #if 0 - // Scale is already applied to the ComponentToWorld transform, and is carried into the bones _locally_. + // Scale is already applied to the GetComponentTransform() transform, and is carried into the bones _locally_. // So there is no need to set scale in the bone local transforms - const FTransform WorldRT(WorldRotation, WorldTranslation, ComponentToWorld.GetScale3D()); - SpaceBases(BoneIndex) = WorldRT*ComponentToWorld.Inverse(); + const FTransform WorldRT(WorldRotation, WorldTranslation, GetComponentTransform().GetScale3D()); + SpaceBases(BoneIndex) = WorldRT*GetComponentTransform().Inverse(); #elif 1 // More optimal form of the above - const FQuat BoneRotation = ComponentToWorld.GetRotation().Inverse()*WorldRotation; - const FVector BoneTranslation = ComponentToWorld.GetRotation().Inverse().RotateVector(WorldTranslation - ComponentToWorld.GetTranslation())/ComponentToWorld.GetScale3D(); + const FQuat BoneRotation = GetComponentTransform().GetRotation().Inverse()*WorldRotation; + const FVector BoneTranslation = GetComponentTransform().GetRotation().Inverse().RotateVector(WorldTranslation - GetComponentTransform().GetTranslation())/GetComponentTransform().GetScale3D(); GetEditableComponentSpaceTransforms()[BoneIndex] = FTransform(BoneRotation, BoneTranslation); #endif } @@ -1155,7 +1155,7 @@ bool UDestructibleComponent::DoCustomNavigableGeometryExport(FNavigableGeometryE #if WITH_EDITORONLY_DATA if (DestructibleMesh && DestructibleMesh->SourceStaticMesh) { - GeomExport.ExportRigidBodySetup(*DestructibleMesh->SourceStaticMesh->BodySetup, ComponentToWorld); + GeomExport.ExportRigidBodySetup(*DestructibleMesh->SourceStaticMesh->BodySetup, GetComponentTransform()); bExportFromBodySetup = false; } #endif // WITH_EDITORONLY_DATA @@ -1165,7 +1165,7 @@ bool UDestructibleComponent::DoCustomNavigableGeometryExport(FNavigableGeometryE apex::DestructibleActor* DestrActor = const_cast(ApexDestructibleActor); - const FTransform ComponentToWorldNoScale(ComponentToWorld.GetRotation(), ComponentToWorld.GetTranslation(), FVector(1.f)); + const FTransform ComponentToWorldNoScale(GetComponentTransform().GetRotation(), GetComponentTransform().GetTranslation(), FVector(1.f)); TArray Shapes; Shapes.AddUninitialized(8); PxRigidDynamic** PActorBuffer = NULL; diff --git a/Engine/Source/Runtime/Engine/Private/Components/HeightFogComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/HeightFogComponent.cpp index 20bbadff4848..4ad2760c17b7 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/HeightFogComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/HeightFogComponent.cpp @@ -283,6 +283,15 @@ void UExponentialHeightFogComponent::SetVolumetricFogAlbedo(FColor NewValue) } } +void UExponentialHeightFogComponent::SetVolumetricFogEmissive(FLinearColor NewValue) +{ + if (VolumetricFogEmissive != NewValue) + { + VolumetricFogEmissive = NewValue; + MarkRenderStateDirty(); + } +} + void UExponentialHeightFogComponent::SetVolumetricFogDistance(float NewValue) { if(VolumetricFogDistance != NewValue) @@ -349,5 +358,3 @@ void AExponentialHeightFog::OnRep_bEnabled() Component->SetVisibility(bEnabled); } -/** Returns Component subobject **/ -UExponentialHeightFogComponent* AExponentialHeightFog::GetComponent() const { return Component; } diff --git a/Engine/Source/Runtime/Engine/Private/Components/InterpToMovementComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/InterpToMovementComponent.cpp index 7b2f650624ab..41fa8471998d 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/InterpToMovementComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/InterpToMovementComponent.cpp @@ -81,7 +81,7 @@ void UInterpToMovementComponent::TickComponent(float DeltaTime, enum ELevelTick FVector WaitPos = FVector::ZeroVector; if (bIsWaiting == true) { - WaitPos = UpdatedComponent->GetComponentLocation(); + WaitPos = UpdatedComponent->GetComponentLocation(); //-V595 } while (RemainingTime >= MIN_TICK_TIME && (Iterations < MaxSimulationIterations) && !ActorOwner->IsPendingKill() && UpdatedComponent) { @@ -95,7 +95,7 @@ void UInterpToMovementComponent::TickComponent(float DeltaTime, enum ELevelTick FVector MoveDelta = ComputeMoveDelta(Time); // Update the rotation on the spline if required - FRotator CurrentRotation = UpdatedComponent->GetComponentRotation(); + FRotator CurrentRotation = UpdatedComponent->GetComponentRotation(); //-V595 // Move the component if ((bPauseOnImpact == false ) && (BehaviourType != EInterpToBehaviourType::OneShot)) diff --git a/Engine/Source/Runtime/Engine/Private/Components/LightComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/LightComponent.cpp index 833047fa5953..c2a4e556e6e5 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/LightComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/LightComponent.cpp @@ -358,9 +358,6 @@ ULightComponent::ULightComponent(const FObjectInitializer& ObjectInitializer) MaxDrawDistance = 0.0f; MaxDistanceFadeRange = 0.0f; bAddedToSceneVisible = false; - - MaxDrawDistance = 0.0f; - MaxDistanceFadeRange = 0.0f; } bool ULightComponent::AffectsPrimitive(const UPrimitiveComponent* Primitive) const @@ -575,6 +572,7 @@ void ULightComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChan PropertyName != GET_MEMBER_NAME_STRING_CHECKED(ULightComponent, bVisible) && PropertyName != GET_MEMBER_NAME_STRING_CHECKED(ULightComponent, LightingChannels) && PropertyName != GET_MEMBER_NAME_STRING_CHECKED(ULightComponent, VolumetricScatteringIntensity) && + PropertyName != GET_MEMBER_NAME_STRING_CHECKED(ULightComponent, bCastVolumetricShadow) && // Point light properties that shouldn't unbuild lighting PropertyName != GET_MEMBER_NAME_STRING_CHECKED(UPointLightComponent, SourceRadius) && PropertyName != GET_MEMBER_NAME_STRING_CHECKED(UPointLightComponent, SourceLength) && @@ -906,7 +904,7 @@ void ULightComponent::SetIESTexture(UTextureLightProfile* NewValue) // GetDirection FVector ULightComponent::GetDirection() const { - return ComponentToWorld.GetUnitAxis( EAxis::X ); + return GetComponentTransform().GetUnitAxis( EAxis::X ); } void ULightComponent::UpdateColorAndBrightness() @@ -979,7 +977,7 @@ class FPrecomputedLightInstanceData : public FSceneComponentInstanceData public: FPrecomputedLightInstanceData(const ULightComponent* SourceComponent) : FSceneComponentInstanceData(SourceComponent) - , Transform(SourceComponent->ComponentToWorld) + , Transform(SourceComponent->GetComponentTransform()) , LightGuid(SourceComponent->LightGuid) , PreviewShadowMapChannel(SourceComponent->PreviewShadowMapChannel) {} @@ -1005,7 +1003,7 @@ void ULightComponent::ApplyComponentInstanceData(FPrecomputedLightInstanceData* { check(LightMapData); - if (!LightMapData->Transform.Equals(ComponentToWorld)) + if (!LightMapData->Transform.Equals(GetComponentTransform())) { return; } diff --git a/Engine/Source/Runtime/Engine/Private/Components/MeshComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/MeshComponent.cpp index 9c211deb4cd3..47240f47ea33 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/MeshComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/MeshComponent.cpp @@ -47,11 +47,11 @@ void UMeshComponent::SetMaterial(int32 ElementIndex, UMaterialInterface* Materia OverrideMaterials.AddZeroed(ElementIndex + 1 - OverrideMaterials.Num()); } - // Check if we are setting a dynamic instance of the original material (if not we should dirty the material parameter name cache) - if (Material != nullptr && OverrideMaterials[ElementIndex] != nullptr) + // Check if we are setting a dynamic instance of the original material, or replacing a nullptr material (if not we should dirty the material parameter name cache) + if (Material != nullptr) { UMaterialInstanceDynamic* DynamicMaterial = Cast(Material); - if ( DynamicMaterial != nullptr && DynamicMaterial->Parent != OverrideMaterials[ElementIndex]) + if ( (DynamicMaterial != nullptr && DynamicMaterial->Parent != OverrideMaterials[ElementIndex]) || OverrideMaterials[ElementIndex] == nullptr) { // Mark cached material parameter names dirty MarkCachedMaterialParameterNameIndicesDirty(); @@ -63,7 +63,7 @@ void UMeshComponent::SetMaterial(int32 ElementIndex, UMaterialInterface* Materia MarkRenderStateDirty(); if (Material) { - Material->AddToCluster(this); + Material->AddToCluster(this, true); } FBodyInstance* BodyInst = GetBodyInstance(); @@ -267,9 +267,6 @@ void UMeshComponent::SetScalarParameterValueOnMaterials(const FName ParameterNam { UE_LOG(LogMaterialParameter, Log, TEXT("%s material parameter hasn't found on the component %s"), *ParameterName.ToString(), *GetPathName()); } - - // CreateAndSetMaterialInstanceDynamic should not flag the cached data as dirty, since only the type of material changes not the contents (UMaterialInstanceDynamic) - check(bCachedMaterialParameterIndicesAreDirty == false); } void UMeshComponent::SetVectorParameterValueOnMaterials(const FName ParameterName, const FVector ParameterValue) @@ -299,9 +296,6 @@ void UMeshComponent::SetVectorParameterValueOnMaterials(const FName ParameterNam } } } - - // CreateAndSetMaterialInstanceDynamic should not flag the cached data as dirty, since only the type of material changes not the contents (UMaterialInstanceDynamic) - check(bCachedMaterialParameterIndicesAreDirty == false); } void UMeshComponent::MarkCachedMaterialParameterNameIndicesDirty() diff --git a/Engine/Source/Runtime/Engine/Private/Components/ModelComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/ModelComponent.cpp index 12a6bf7ef001..6d91553d0891 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/ModelComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/ModelComponent.cpp @@ -449,7 +449,7 @@ void UModelComponent::GetStreamingTextureInfo(FStreamingTextureLevelContext& Lev const FBspNode& Node = Model->Nodes[SurfaceNodes[NodeIndex]]; for(int32 VertexIndex = 0;VertexIndex < Node.NumVertices;VertexIndex++) { - const FVector WorldVertex = ComponentToWorld.TransformPosition(Model->Points[Model->Verts[Node.iVertPool + VertexIndex].pVertex]); + const FVector WorldVertex = GetComponentTransform().TransformPosition(Model->Points[Model->Verts[Node.iVertPool + VertexIndex].pVertex]); SurfaceVertices.Add(WorldVertex); } } diff --git a/Engine/Source/Runtime/Engine/Private/Components/MovementComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/MovementComponent.cpp index 2a7477ecd6b6..f11f4d3fcbd0 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/MovementComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/MovementComponent.cpp @@ -300,7 +300,7 @@ bool UMovementComponent::ShouldSkipUpdate(float DeltaTime) const { const_cast(this)->bEditorWarnedStaticMobilityMove = true; FMessageLog("PIE").Warning(FText::Format(LOCTEXT("InvalidMove", "Mobility of {0} : {1} has to be 'Movable' if you'd like to move it with {2}. "), - FText::FromString(GetNameSafe(UpdatedComponent->GetOwner())), FText::FromString(UpdatedComponent->GetName()), FText::FromString(GetClass()->GetName()))); + FText::FromString(GetPathNameSafe(UpdatedComponent->GetOwner())), FText::FromString(UpdatedComponent->GetName()), FText::FromString(GetClass()->GetName()))); } } } @@ -375,7 +375,7 @@ void UMovementComponent::InitCollisionParams(FCollisionQueryParams &OutParams, F bool UMovementComponent::OverlapTest(const FVector& Location, const FQuat& RotationQuat, const ECollisionChannel CollisionChannel, const FCollisionShape& CollisionShape, const AActor* IgnoreActor) const { - FCollisionQueryParams QueryParams(MovementComponentStatics::TestOverlapName, false, IgnoreActor); + FCollisionQueryParams QueryParams(SCENE_QUERY_STAT(MovementOverlapTest), false, IgnoreActor); FCollisionResponseParams ResponseParam; InitCollisionParams(QueryParams, ResponseParam); return GetWorld()->OverlapBlockingTestByChannel(Location, RotationQuat, CollisionChannel, CollisionShape, QueryParams, ResponseParam); diff --git a/Engine/Source/Runtime/Engine/Private/Components/PointLightComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/PointLightComponent.cpp index b1e749377810..fb0c5160636a 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/PointLightComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/PointLightComponent.cpp @@ -172,7 +172,7 @@ void UPointLightComponent::SetSourceLength(float NewValue) bool UPointLightComponent::AffectsBounds(const FBoxSphereBounds& InBounds) const { - if((InBounds.Origin - ComponentToWorld.GetLocation()).SizeSquared() > FMath::Square(AttenuationRadius + InBounds.SphereRadius)) + if((InBounds.Origin - GetComponentTransform().GetLocation()).SizeSquared() > FMath::Square(AttenuationRadius + InBounds.SphereRadius)) { return false; } @@ -199,7 +199,7 @@ void UPointLightComponent::SendRenderTransform_Concurrent() // FVector4 UPointLightComponent::GetLightPosition() const { - return FVector4(ComponentToWorld.GetLocation(),1); + return FVector4(GetComponentTransform().GetLocation(),1); } /** @@ -232,7 +232,7 @@ FBox UPointLightComponent::GetBoundingBox() const FSphere UPointLightComponent::GetBoundingSphere() const { - return FSphere(ComponentToWorld.GetLocation(), AttenuationRadius); + return FSphere(GetComponentTransform().GetLocation(), AttenuationRadius); } void UPointLightComponent::Serialize(FArchive& Ar) diff --git a/Engine/Source/Runtime/Engine/Private/Components/PoseableMeshComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/PoseableMeshComponent.cpp index 081c33f6e92a..be319b795329 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/PoseableMeshComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/PoseableMeshComponent.cpp @@ -66,6 +66,8 @@ void UPoseableMeshComponent::RefreshBoneTransforms(FActorComponentTickFunction* FinalizeBoneTransform(); UpdateChildTransforms(); + UpdateBounds(); + MarkRenderTransformDirty(); MarkRenderDynamicDataDirty(); } @@ -206,7 +208,7 @@ FTransform GetBoneTransformByNameHelper(FName BoneName, EBoneSpaces::Type BoneSp } else { - return CSPose.GetComponentSpaceTransform(BoneIndex) * Component->ComponentToWorld; + return CSPose.GetComponentSpaceTransform(BoneIndex) * Component->GetComponentTransform(); } } diff --git a/Engine/Source/Runtime/Engine/Private/Components/PostProcessComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/PostProcessComponent.cpp index d76ecb3af485..fee191d05287 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/PostProcessComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/PostProcessComponent.cpp @@ -21,7 +21,7 @@ bool UPostProcessComponent::EncompassesPoint(FVector Point, float SphereRadius/* FVector ClosestPoint; float Distance = ParentShape->GetDistanceToCollision(Point, ClosestPoint); #else - FBoxSphereBounds Bounds = ParentShape->CalcBounds(ParentShape->ComponentToWorld); + FBoxSphereBounds Bounds = ParentShape->CalcBounds(ParentShape->GetComponentTransform()); float Distance = 0; if (ParentShape->IsA()) { diff --git a/Engine/Source/Runtime/Engine/Private/Components/PrimitiveComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/PrimitiveComponent.cpp index 6d24f14615a9..7cdfced8251d 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/PrimitiveComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/PrimitiveComponent.cpp @@ -42,8 +42,6 @@ namespace PrimitiveComponentStatics { static const FText MobilityWarnText = LOCTEXT("InvalidMove", "move"); - static const FName MoveComponentName(TEXT("MoveComponent")); - static const FName UpdateOverlapsName(TEXT("UpdateOverlaps")); } typedef TArray> TInlineOverlapInfoArray; @@ -614,7 +612,7 @@ void UPrimitiveComponent::OnCreatePhysicsState() if(BodySetup) { // Create new BodyInstance at given location. - FTransform BodyTransform = ComponentToWorld; + FTransform BodyTransform = GetComponentTransform(); // Here we make sure we don't have zero scale. This still results in a body being made and placed in // world (very small) but is consistent with a body scaled to zero. @@ -687,8 +685,8 @@ void UPrimitiveComponent::OnUpdateTransform(EUpdateTransformFlags UpdateTransfor void UPrimitiveComponent::SendPhysicsTransform(ETeleportType Teleport) { - BodyInstance.SetBodyTransform(ComponentToWorld, Teleport); - BodyInstance.UpdateBodyScale(ComponentToWorld.GetScale3D()); + BodyInstance.SetBodyTransform(GetComponentTransform(), Teleport); + BodyInstance.UpdateBodyScale(GetComponentTransform().GetScale3D()); } void UPrimitiveComponent::OnDestroyPhysicsState() @@ -728,8 +726,8 @@ void UPrimitiveComponent::SendRenderDebugPhysics(FPrimitiveSceneProxy* OverrideS FPrimitiveSceneProxy::FDebugMassData& RootMassData = DebugMassData[0]; const FTransform MassToWorld = BI->GetMassSpaceToWorldSpace(); - RootMassData.LocalCenterOfMass = ComponentToWorld.InverseTransformPosition(MassToWorld.GetLocation()); - RootMassData.LocalTensorOrientation = MassToWorld.GetRotation() * ComponentToWorld.GetRotation().Inverse(); + RootMassData.LocalCenterOfMass = GetComponentTransform().InverseTransformPosition(MassToWorld.GetLocation()); + RootMassData.LocalTensorOrientation = MassToWorld.GetRotation() * GetComponentTransform().GetRotation().Inverse(); RootMassData.MassSpaceInertiaTensor = BI->GetBodyInertiaTensor(); RootMassData.BoneIndex = INDEX_NONE; } @@ -747,7 +745,7 @@ void UPrimitiveComponent::SendRenderDebugPhysics(FPrimitiveSceneProxy* OverrideS FMatrix UPrimitiveComponent::GetRenderMatrix() const { - return ComponentToWorld.ToMatrixWithScale(); + return GetComponentTransform().ToMatrixWithScale(); } void UPrimitiveComponent::Serialize(FArchive& Ar) @@ -1228,6 +1226,15 @@ void UPrimitiveComponent::SetCastShadow(bool NewCastShadow) } } +void UPrimitiveComponent::SetSingleSampleShadowFromStationaryLights(bool bNewSingleSampleShadowFromStationaryLights) +{ + if (bNewSingleSampleShadowFromStationaryLights != bSingleSampleShadowFromStationaryLights) + { + bSingleSampleShadowFromStationaryLights = bNewSingleSampleShadowFromStationaryLights; + MarkRenderStateDirty(); + } +} + void UPrimitiveComponent::SetTranslucentSortPriority(int32 NewTranslucentSortPriority) { if (NewTranslucentSortPriority != TranslucencySortPriority) @@ -1674,7 +1681,7 @@ void UPrimitiveComponent::InitSweepCollisionParams(FCollisionQueryParams &OutPar void UPrimitiveComponent::SetMoveIgnoreMask(FMaskFilter InMoveIgnoreMask) { - if (ensure(InMoveIgnoreMask < 16)) // TODO: don't assert, and make this a nicer exposed value. + if (ensure(InMoveIgnoreMask < (1 << NumExtraFilterBits))) // We only have a limited nubmer of bits for the mask. TODO: don't assert, and make this a nicer exposed value. { MoveIgnoreMask = InMoveIgnoreMask; } @@ -1723,7 +1730,7 @@ bool UPrimitiveComponent::MoveComponentImpl( const FVector& Delta, const FQuat& const FVector TraceStart = GetComponentLocation(); const FVector TraceEnd = TraceStart + Delta; float DeltaSizeSq = (TraceEnd - TraceStart).SizeSquared(); // Recalc here to account for precision loss of float addition - const FQuat InitialRotationQuat = ComponentToWorld.GetRotation(); + const FQuat InitialRotationQuat = GetComponentTransform().GetRotation(); // ComponentSweepMulti does nothing if moving < KINDA_SMALL_NUMBER in distance, so it's important to not try to sweep distances smaller than that. const float MinMovementDistSq = (bSweep ? FMath::Square(4.f*KINDA_SMALL_NUMBER) : 0.f); @@ -1779,7 +1786,7 @@ bool UPrimitiveComponent::MoveComponentImpl( const FVector& Delta, const FQuat& ensureMsgf(IsRegistered(), TEXT("%s MovedComponent %s not initialized deleteme %d"),*Actor->GetName(), *GetName(), Actor->IsPendingKill()); } else - { + { //-V523 ensureMsgf(IsRegistered(), TEXT("MovedComponent %s not initialized"), *GetFullName()); } } @@ -1791,7 +1798,7 @@ bool UPrimitiveComponent::MoveComponentImpl( const FVector& Delta, const FQuat& UWorld* const MyWorld = GetWorld(); const bool bForceGatherOverlaps = !ShouldCheckOverlapFlagToQueueOverlaps(*this); - FComponentQueryParams Params(PrimitiveComponentStatics::MoveComponentName, Actor); + FComponentQueryParams Params(SCENE_QUERY_STAT(MoveComponent), Actor); FCollisionResponseParams ResponseParam; InitSweepCollisionParams(Params, ResponseParam); Params.bIgnoreTouches |= !(bGenerateOverlapEvents || bForceGatherOverlaps); @@ -2113,7 +2120,7 @@ bool UPrimitiveComponent::LineTraceComponent(struct FHitResult& OutHit, const FV bool bHaveHit = BodyInstance.LineTrace(OutHit, Start, End, Params.bTraceComplex, Params.bReturnPhysicalMaterial); #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) - if((GetWorld()->DebugDrawTraceTag != NAME_None) && (GetWorld()->DebugDrawTraceTag == Params.TraceTag)) + if (GetWorld()->DebugDrawSceneQueries(Params.TraceTag)) { TArray Hits; if (bHaveHit) @@ -2166,7 +2173,7 @@ bool UPrimitiveComponent::ComputePenetration(FMTDResult& OutMTD, const FCollisio return false; } -bool UPrimitiveComponent::IsOverlappingComponent(UPrimitiveComponent const* OtherComp) const +bool UPrimitiveComponent::IsOverlappingComponent(const UPrimitiveComponent* OtherComp) const { for (int32 i=0; i < OverlappingComponents.Num(); ++i) { @@ -2178,7 +2185,7 @@ bool UPrimitiveComponent::IsOverlappingComponent(UPrimitiveComponent const* Othe return false; } -bool UPrimitiveComponent::IsOverlappingComponent( const FOverlapInfo& Overlap ) const +bool UPrimitiveComponent::IsOverlappingComponent(const FOverlapInfo& Overlap) const { return OverlappingComponents.Find(Overlap) != INDEX_NONE; } @@ -2461,7 +2468,7 @@ const TArray* UPrimitiveComponent::ConvertSweptOverlapsToCurrentOv SCOPE_CYCLE_COUNTER(STAT_MoveComponent_FastOverlap); // Check components we hit during the sweep, keep only those still overlapping - const FCollisionQueryParams UnusedQueryParams; + const FCollisionQueryParams UnusedQueryParams(NAME_None, FCollisionQueryParams::GetUnknownStatId()); for (int32 Index = SweptOverlapsIndex; Index < SweptOverlaps.Num(); ++Index) { const FOverlapInfo& OtherOverlap = SweptOverlaps[Index]; @@ -2721,7 +2728,7 @@ void UPrimitiveComponent::UpdateOverlaps(const TArray* NewPendingO UWorld* const MyWorld = MyActor->GetWorld(); TArray Overlaps; // note this will optionally include overlaps with components in the same actor (depending on bIgnoreChildren). - FComponentQueryParams Params(PrimitiveComponentStatics::UpdateOverlapsName, bIgnoreChildren ? MyActor : nullptr); + FComponentQueryParams Params(SCENE_QUERY_STAT(UpdateOverlaps), bIgnoreChildren ? MyActor : nullptr); Params.bIgnoreBlocks = true; //We don't care about blockers since we only route overlap events to real overlaps FCollisionResponseParams ResponseParam; InitSweepCollisionParams(Params, ResponseParam); diff --git a/Engine/Source/Runtime/Engine/Private/Components/ReflectionCaptureComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/ReflectionCaptureComponent.cpp index 735119c77860..3cb19a38a1c6 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/ReflectionCaptureComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/ReflectionCaptureComponent.cpp @@ -888,7 +888,7 @@ void UReflectionCaptureComponent::OnRegister() Super::OnRegister(); UWorld* World = GetWorld(); - if (World->IsGameWorld() && GMaxRHIFeatureLevel < ERHIFeatureLevel::SM4) + if (World->FeatureLevel < ERHIFeatureLevel::SM4) { if (EncodedHDRDerivedData == nullptr) { @@ -900,7 +900,7 @@ void UReflectionCaptureComponent::OnRegister() void UReflectionCaptureComponent::OnUnregister() { UWorld* World = GetWorld(); - if (World->IsGameWorld() && GMaxRHIFeatureLevel < ERHIFeatureLevel::SM4) + if (World->FeatureLevel < ERHIFeatureLevel::SM4) { if (EncodedHDRDerivedData == nullptr && World->NumInvalidReflectionCaptureComponents > 0) { @@ -1310,7 +1310,7 @@ void UReflectionCaptureComponent::UpdatePreviewShape() { if (CaptureOffsetComponent) { - CaptureOffsetComponent->RelativeLocation = CaptureOffset / ComponentToWorld.GetScale3D(); + CaptureOffsetComponent->RelativeLocation = CaptureOffset / GetComponentTransform().GetScale3D(); } } @@ -1489,7 +1489,7 @@ void UReflectionCaptureComponent::ReadbackFromGPU(UWorld* WorldToUpdate) return; } - if (bDerivedDataDirty && !IsRunningCommandlet() && WorldToUpdate && WorldToUpdate->FeatureLevel >= ERHIFeatureLevel::SM4) + if (bDerivedDataDirty && (!IsRunningCommandlet() || IsAllowCommandletRendering()) && WorldToUpdate && WorldToUpdate->FeatureLevel >= ERHIFeatureLevel::SM4) { FReflectionCaptureFullHDR* NewDerivedData = new FReflectionCaptureFullHDR(); @@ -1518,28 +1518,6 @@ void UReflectionCaptureComponent::ReadbackFromGPU(UWorld* WorldToUpdate) } } -#if WITH_EDITOR -// If the feature level preview has been set before on-load captures have been built then the editor must update them. -bool UReflectionCaptureComponent::MobileReflectionCapturesNeedForcedUpdate(UWorld* WorldToUpdate) -{ - if (WorldToUpdate->Scene - && WorldToUpdate->Scene->GetFeatureLevel() <= ERHIFeatureLevel::ES3_1 - && (GShaderCompilingManager == NULL || !GShaderCompilingManager->IsCompiling())) - { - FScopeLock Lock(&ReflectionCapturesToUpdateForLoadLock); - for (int32 CaptureIndex = ReflectionCapturesToUpdateForLoad.Num() - 1; CaptureIndex >= 0; CaptureIndex--) - { - UReflectionCaptureComponent* CaptureComponent = ReflectionCapturesToUpdateForLoad[CaptureIndex]; - if (!CaptureComponent->GetOwner() || WorldToUpdate->ContainsActor(CaptureComponent->GetOwner())) - { - return true; - } - } - } - return false; -} -#endif - void UReflectionCaptureComponent::UpdateReflectionCaptureContents(UWorld* WorldToUpdate) { if (WorldToUpdate->Scene @@ -1721,7 +1699,7 @@ void UBoxReflectionCaptureComponent::UpdatePreviewShape() { if (PreviewCaptureBox) { - PreviewCaptureBox->InitBoxExtent(((ComponentToWorld.GetScale3D() - FVector(BoxTransitionDistance)) / ComponentToWorld.GetScale3D()).ComponentMax(FVector::ZeroVector)); + PreviewCaptureBox->InitBoxExtent(((GetComponentTransform().GetScale3D() - FVector(BoxTransitionDistance)) / GetComponentTransform().GetScale3D()).ComponentMax(FVector::ZeroVector)); } Super::UpdatePreviewShape(); @@ -1729,7 +1707,7 @@ void UBoxReflectionCaptureComponent::UpdatePreviewShape() float UBoxReflectionCaptureComponent::GetInfluenceBoundingRadius() const { - return (ComponentToWorld.GetScale3D() + FVector(BoxTransitionDistance)).Size(); + return (GetComponentTransform().GetScale3D() + FVector(BoxTransitionDistance)).Size(); } #if WITH_EDITOR @@ -1763,7 +1741,7 @@ void UPlaneReflectionCaptureComponent::UpdatePreviewShape() float UPlaneReflectionCaptureComponent::GetInfluenceBoundingRadius() const { - return FVector2D(ComponentToWorld.GetScale3D().Y, ComponentToWorld.GetScale3D().Z).Size() * InfluenceRadiusScale; + return FVector2D(GetComponentTransform().GetScale3D().Y, GetComponentTransform().GetScale3D().Z).Size() * InfluenceRadiusScale; } FReflectionCaptureProxy::FReflectionCaptureProxy(const UReflectionCaptureComponent* InComponent) @@ -1801,7 +1779,7 @@ FReflectionCaptureProxy::FReflectionCaptureProxy(const UReflectionCaptureCompone Component = InComponent; SM4FullHDRCubemap = InComponent->SM4FullHDRCubemapTexture; EncodedHDRCubemap = InComponent->EncodedHDRCubemapTexture; - SetTransform(InComponent->ComponentToWorld.ToMatrixWithScale()); + SetTransform(InComponent->GetComponentTransform().ToMatrixWithScale()); InfluenceRadius = InComponent->GetInfluenceBoundingRadius(); Brightness = InComponent->Brightness; Guid = GetTypeHash( Component->GetPathName() ); @@ -1841,12 +1819,3 @@ void FReflectionCaptureProxy::SetTransform(const FMatrix& InTransform) ReflectionXAxisAndYScale = ReflectionXAxis.GetSafeNormal() * ScaleVector.Y; ReflectionXAxisAndYScale.W = ScaleVector.Y / ScaleVector.Z; } - -/** Returns CaptureComponent subobject **/ -UReflectionCaptureComponent* AReflectionCapture::GetCaptureComponent() const { return CaptureComponent; } -#if WITH_EDITORONLY_DATA -/** Returns SpriteComponent subobject **/ -UBillboardComponent* AReflectionCapture::GetSpriteComponent() const { return SpriteComponent; } -#endif -/** Returns DrawCaptureRadius subobject **/ -UDrawSphereComponent* ASphereReflectionCapture::GetDrawCaptureRadius() const { return DrawCaptureRadius; } diff --git a/Engine/Source/Runtime/Engine/Private/Components/SceneCaptureComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/SceneCaptureComponent.cpp index a33f751d6c69..b875093f3323 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/SceneCaptureComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/SceneCaptureComponent.cpp @@ -391,8 +391,16 @@ USceneCaptureComponent2D::USceneCaptureComponent2D(const FObjectInitializer& Obj CaptureStereoPass = EStereoscopicPass::eSSP_FULL; CustomProjectionMatrix.SetIdentity(); ClipPlaneNormal = FVector(0, 0, 1); - // previous behavior was to capture 2d scene captures before cube scene captures. - CaptureSortPriority = 1; + + // Legacy initialization. + { + // previous behavior was to capture 2d scene captures before cube scene captures. + CaptureSortPriority = 1; + + // previous behavior was not exposing MotionBlur and Temporal AA in scene capture 2d. + ShowFlags.TemporalAA = false; + ShowFlags.MotionBlur = false; + } } void USceneCaptureComponent2D::OnRegister() @@ -522,9 +530,15 @@ void USceneCaptureComponent2D::Serialize(FArchive& Ar) { Super::Serialize(Ar); - if(Ar.IsLoading()) + if (Ar.IsLoading()) { PostProcessSettings.OnAfterLoad(); + + if (Ar.CustomVer(FRenderingObjectVersion::GUID) < FRenderingObjectVersion::MotionBlurAndTAASupportInSceneCapture2d) + { + ShowFlags.TemporalAA = false; + ShowFlags.MotionBlur = false; + } } } @@ -867,15 +881,4 @@ void USceneCaptureComponentCube::PostEditChangeProperty(FPropertyChangedEvent& P } #endif // WITH_EDITOR -/** Returns MeshComp subobject **/ -UStaticMeshComponent* ASceneCapture::GetMeshComp() const { return MeshComp; } -/** Returns CaptureComponent2D subobject **/ -USceneCaptureComponent2D* ASceneCapture2D::GetCaptureComponent2D() const { return CaptureComponent2D; } -/** Returns DrawFrustum subobject **/ -UDrawFrustumComponent* ASceneCapture2D::GetDrawFrustum() const { return DrawFrustum; } -/** Returns CaptureComponentCube subobject **/ -USceneCaptureComponentCube* ASceneCaptureCube::GetCaptureComponentCube() const { return CaptureComponentCube; } -/** Returns DrawFrustum subobject **/ -UDrawFrustumComponent* ASceneCaptureCube::GetDrawFrustum() const { return DrawFrustum; } - #undef LOCTEXT_NAMESPACE \ No newline at end of file diff --git a/Engine/Source/Runtime/Engine/Private/Components/SceneComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/SceneComponent.cpp index 52df4cfb39e8..6ee0683afdaa 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/SceneComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/SceneComponent.cpp @@ -1101,7 +1101,7 @@ void USceneComponent::UpdateBounds() else { // Calculate new bounds - Bounds = CalcBounds(ComponentToWorld); + Bounds = CalcBounds(GetComponentTransform()); } @@ -1216,26 +1216,26 @@ void USceneComponent::AddLocalTransform(const FTransform& DeltaTransform, bool b void USceneComponent::AddWorldOffset(FVector DeltaLocation, bool bSweep, FHitResult* OutSweepHitResult, ETeleportType Teleport) { - const FVector NewWorldLocation = DeltaLocation + ComponentToWorld.GetTranslation(); + const FVector NewWorldLocation = DeltaLocation + GetComponentTransform().GetTranslation(); SetWorldLocation(NewWorldLocation, bSweep, OutSweepHitResult, Teleport); } void USceneComponent::AddWorldRotation(FRotator DeltaRotation, bool bSweep, FHitResult* OutSweepHitResult, ETeleportType Teleport) { - const FQuat NewWorldRotation = DeltaRotation.Quaternion() * ComponentToWorld.GetRotation(); + const FQuat NewWorldRotation = DeltaRotation.Quaternion() * GetComponentTransform().GetRotation(); SetWorldRotation(NewWorldRotation, bSweep, OutSweepHitResult, Teleport); } void USceneComponent::AddWorldRotation(const FQuat& DeltaRotation, bool bSweep, FHitResult* OutSweepHitResult, ETeleportType Teleport) { - const FQuat NewWorldRotation = DeltaRotation * ComponentToWorld.GetRotation(); + const FQuat NewWorldRotation = DeltaRotation * GetComponentTransform().GetRotation(); SetWorldRotation(NewWorldRotation, bSweep, OutSweepHitResult, Teleport); } void USceneComponent::AddWorldTransform(const FTransform& DeltaTransform, bool bSweep, FHitResult* OutSweepHitResult, ETeleportType Teleport) { - const FQuat NewWorldRotation = DeltaTransform.GetRotation() * ComponentToWorld.GetRotation(); - const FVector NewWorldLocation = FTransform::AddTranslations(DeltaTransform, ComponentToWorld); + const FQuat NewWorldRotation = DeltaTransform.GetRotation() * GetComponentTransform().GetRotation(); + const FVector NewWorldLocation = FTransform::AddTranslations(DeltaTransform, ComponentToWorld); // ComponentToWorld is sure to be accurate due to GetComponentTransform() on previous line SetWorldTransform(FTransform(NewWorldRotation, NewWorldLocation, FVector(1,1,1)),bSweep, OutSweepHitResult, Teleport); } @@ -1306,10 +1306,25 @@ void USceneComponent::SetWorldRotation(const FQuat& NewRotation, bool bSweep, FH // If already attached to something, transform into local space if (GetAttachParent() != nullptr && !bAbsoluteRotation) { - const FQuat ParentToWorldQuat = GetAttachParent()->GetSocketQuaternion(GetAttachSocketName()); - // Quat multiplication works reverse way, make sure you do Parent(-1) * World = Local, not World*Parent(-) = Local (the way matrix does) - const FQuat NewRelQuat = ParentToWorldQuat.Inverse() * NewRotation; - NewRelRotation = NewRelQuat; + const FTransform ParentToWorld = GetAttachParent()->GetSocketTransform(GetAttachSocketName()); + // in order to support mirroring, you'll have to use FTransform.GetRelativeTransform + // because negative SCALE should flip the rotation + if (FTransform::AnyHasNegativeScale(RelativeScale3D, ParentToWorld.GetScale3D())) + { + FTransform NewTransform = GetComponentTransform(); + // set new desired rotation + NewTransform.SetRotation(NewRotation); + // Get relative transform from ParentToWorld + const FQuat NewRelQuat = NewTransform.GetRelativeTransform(ParentToWorld).GetRotation(); + NewRelRotation = NewRelQuat; + } + else + { + const FQuat ParentToWorldQuat = ParentToWorld.GetRotation(); + // Quat multiplication works reverse way, make sure you do Parent(-1) * World = Local, not World*Parent(-) = Local (the way matrix does) + const FQuat NewRelQuat = ParentToWorldQuat.Inverse() * NewRotation; + NewRelRotation = NewRelQuat; + } } SetRelativeRotation(NewRelRotation, bSweep, OutSweepHitResult, Teleport); @@ -1464,17 +1479,17 @@ FTransform USceneComponent::K2_GetComponentToWorld() const FVector USceneComponent::GetForwardVector() const { - return ComponentToWorld.GetUnitAxis( EAxis::X ); + return GetComponentTransform().GetUnitAxis( EAxis::X ); } FVector USceneComponent::GetRightVector() const { - return ComponentToWorld.GetUnitAxis( EAxis::Y ); + return GetComponentTransform().GetUnitAxis( EAxis::Y ); } FVector USceneComponent::GetUpVector() const { - return ComponentToWorld.GetUnitAxis( EAxis::Z ); + return GetComponentTransform().GetUnitAxis( EAxis::Z ); } FVector USceneComponent::K2_GetComponentLocation() const @@ -1559,10 +1574,16 @@ void USceneComponent::SetupAttachment(class USceneComponent* InParent, FName InS { if (ensureMsgf(!bRegistered, TEXT("SetupAttachment should only be used to initialize AttachParent and AttachSocketName for a future AttachTo. Once a component is registered you must use AttachTo."))) { - if (ensureMsgf(AttachParent == nullptr || !AttachParent->AttachChildren.Contains(this), TEXT("SetupAttachment cannot be used once a component has already had AttachTo used to connect it to a parent."))) + if (ensureMsgf(InParent != this, TEXT("Cannot attach a component to itself."))) { - AttachParent = InParent; - AttachSocketName = InSocketName; + if (ensureMsgf(InParent == nullptr || !InParent->IsAttachedTo(this), TEXT("Setting up attachment would create a cycle."))) + { + if (ensureMsgf(AttachParent == nullptr || !AttachParent->AttachChildren.Contains(this), TEXT("SetupAttachment cannot be used once a component has already had AttachTo used to connect it to a parent."))) + { + AttachParent = InParent; + AttachSocketName = InSocketName; + } + } } } } @@ -1758,7 +1779,7 @@ bool USceneComponent::AttachToComponent(USceneComponent* Parent, const FAttachme UpdateComponentToWorldWithParent(Parent, SocketName, EUpdateTransformFlags::None, RelativeRotationCache.RotatorToQuat(RelativeRotation)); if (AttachmentRules.LocationRule == EAttachmentRule::KeepRelative) { - RelativeLocation = ComponentToWorld.GetLocation(); // or GetComponentLocation(), but worried about custom location... + RelativeLocation = GetComponentLocation(); } if (AttachmentRules.RotationRule == EAttachmentRule::KeepRelative) { @@ -1814,7 +1835,7 @@ bool USceneComponent::AttachToComponent(USceneComponent* Parent, const FAttachme return false; } #endif - FTransform RelativeTM = ComponentToWorld.GetRelativeTransform(SocketTransform); + FTransform RelativeTM = GetComponentTransform().GetRelativeTransform(SocketTransform); #if ENABLE_NAN_DIAGNOSTIC if (RelativeTM.ContainsNaN()) { @@ -1831,7 +1852,7 @@ bool USceneComponent::AttachToComponent(USceneComponent* Parent, const FAttachme case EAttachmentRule::KeepWorld: if (bAbsoluteLocation) { - RelativeLocation = ComponentToWorld.GetTranslation(); + RelativeLocation = GetComponentTransform().GetTranslation(); } else { @@ -1871,7 +1892,7 @@ bool USceneComponent::AttachToComponent(USceneComponent* Parent, const FAttachme case EAttachmentRule::KeepWorld: if (bAbsoluteScale) { - RelativeScale3D = ComponentToWorld.GetScale3D(); + RelativeScale3D = GetComponentTransform().GetScale3D(); } else { @@ -1991,7 +2012,7 @@ void USceneComponent::DetachFromComponent(const FDetachmentTransformRules& Detac case EDetachmentRule::KeepRelative: break; case EDetachmentRule::KeepWorld: - RelativeLocation = ComponentToWorld.GetTranslation(); // or GetComponentLocation, but worried about custom location... + RelativeLocation = GetComponentTransform().GetTranslation(); // or GetComponentLocation, but worried about custom location... break; } @@ -2139,7 +2160,7 @@ void USceneComponent::UpdateChildTransforms(EUpdateTransformFlags UpdateTransfor SCOPE_CYCLE_COUNTER(STAT_UpdateChildTransforms); #if ENABLE_NAN_DIAGNOSTIC - if (!ComponentToWorld.IsValid()) + if (!GetComponentTransform().IsValid()) { logOrEnsureNanError(TEXT("USceneComponent::UpdateChildTransforms found NaN/INF in ComponentToWorld: %s"), *ComponentToWorld.ToString()); } @@ -2207,7 +2228,7 @@ FTransform USceneComponent::GetSocketTransform(FName SocketName, ERelativeTransf { case RTS_Actor: { - return ComponentToWorld.GetRelativeTransform( GetOwner()->GetTransform() ); + return GetComponentTransform().GetRelativeTransform( GetOwner()->GetTransform() ); break; } case RTS_Component: @@ -2217,7 +2238,7 @@ FTransform USceneComponent::GetSocketTransform(FName SocketName, ERelativeTransf } default: { - return ComponentToWorld; + return GetComponentTransform(); } } } @@ -2417,7 +2438,7 @@ void USceneComponent::UpdatePhysicsVolume( bool bTriggerNotifiers ) { // check for all volumes that overlap the component TArray Hits; - FComponentQueryParams Params(SceneComponentStatics::PhysicsVolumeTraceName, GetOwner()); + FComponentQueryParams Params(SCENE_QUERY_STAT(UpdatePhysicsVolume), GetOwner()); bool bOverlappedOrigin = false; const UPrimitiveComponent* SelfAsPrimitive = Cast(this); @@ -2618,7 +2639,7 @@ bool USceneComponent::CheckStaticMobilityAndWarn(const FText& ActionText) const { #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) FMessageLog("PIE").Warning(FText::Format(LOCTEXT("InvalidMustBeMovable", "Mobility of {0} : {1} has to be 'Movable' if you'd like to {2}. "), - FText::FromString(GetNameSafe(GetOwner())), FText::FromString(GetName()), ActionText)); + FText::FromString(GetPathNameSafe(GetOwner())), FText::FromString(GetName()), ActionText)); #endif return true; } @@ -2678,7 +2699,7 @@ bool USceneComponent::MoveComponentImpl(const FVector& Delta, const FQuat& NewRo if( Delta.IsZero() ) { // Skip if no vector or rotation. - if (NewRotation.Equals(ComponentToWorld.GetRotation(), SCENECOMPONENT_QUAT_TOLERANCE)) + if (NewRotation.Equals(GetComponentTransform().GetRotation(), SCENECOMPONENT_QUAT_TOLERANCE)) { return true; } @@ -2829,16 +2850,23 @@ void USceneComponent::SetVisibility(const bool bNewVisibility, const USceneCompo } } -void USceneComponent::SetHiddenInGame(bool NewHiddenGame, bool bPropagateToChildren) +void USceneComponent::OnHiddenInGameChanged() { - if( NewHiddenGame != bHiddenInGame ) + MarkRenderStateDirty(); +} + +void USceneComponent::SetHiddenInGame(const bool bNewHiddenGame, const USceneComponent::EVisibilityPropagation PropagateToChildren) +{ + bool bRecurseChildren = (PropagateToChildren == EVisibilityPropagation::Propagate); + if ( bNewHiddenGame != bHiddenInGame ) { - bHiddenInGame = NewHiddenGame; - MarkRenderStateDirty(); + bRecurseChildren = bRecurseChildren || (PropagateToChildren == EVisibilityPropagation::DirtyOnly); + bHiddenInGame = bNewHiddenGame; + OnHiddenInGameChanged(); } const TArray& AttachedChildren = GetAttachChildren(); - if (bPropagateToChildren && AttachedChildren.Num() > 0) + if (bRecurseChildren && AttachedChildren.Num() > 0) { // fully traverse down the attachment tree // we do it entirely inline here instead of recursing in case a primitivecomponent is a child of a non-primitivecomponent @@ -2854,12 +2882,14 @@ void USceneComponent::SetHiddenInGame(bool NewHiddenGame, bool bPropagateToChild { ComponentStack.Append(CurrentComp->GetAttachChildren()); - UPrimitiveComponent* const PrimComp = Cast(CurrentComp); - if (PrimComp) + if (PropagateToChildren == EVisibilityPropagation::Propagate) { - // don't propagate, we are handling it already - PrimComp->SetHiddenInGame(NewHiddenGame, false); + CurrentComp->SetHiddenInGame(bNewHiddenGame, EVisibilityPropagation::NoPropagation); } + + // Render state must be dirtied if any parent component's visibility has changed. Since we can't easily track whether + // any parent in the hierarchy was dirtied, we have to mark dirty always. + CurrentComp->MarkRenderStateDirty(); } } } @@ -3100,7 +3130,7 @@ FScopedPreventAttachedComponentMove::~FScopedPreventAttachedComponentMove() { // Need to keep RelativeLocation/Rotation/Scale in sync. ComponentToWorld() will remain correct because child isn't moving. const FTransform ParentToWorld = Owner->GetAttachParent()->GetSocketTransform(Owner->GetAttachSocketName()); - const FTransform ChildRelativeTM = Owner->ComponentToWorld.GetRelativeTransform(ParentToWorld); + const FTransform ChildRelativeTM = Owner->GetComponentTransform().GetRelativeTransform(ParentToWorld); if (!bSavedAbsoluteLocation) { diff --git a/Engine/Source/Runtime/Engine/Private/Components/ShapeComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/ShapeComponent.cpp index 3efa9401768a..0bee1f0d4211 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/ShapeComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/ShapeComponent.cpp @@ -138,7 +138,11 @@ void UShapeComponent::CreateShapeBodySetupIfNeeded() for(PxShape* PShape : PShapes) //The reason we iterate is we may have multiple scenes and thus multiple shapes, but they are all pointing to the same geometry { - SetShapeToNewGeom(PShape); + //Update shape with the new body setup. Make sure to only update shapes owned by this body instance + if(BodyInstance.IsShapeBoundToBody(PShape)) + { + SetShapeToNewGeom(PShape); + } } }); #endif diff --git a/Engine/Source/Runtime/Engine/Private/Components/SkeletalMeshComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/SkeletalMeshComponent.cpp index 1d1c64339818..2490b8275f65 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/SkeletalMeshComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/SkeletalMeshComponent.cpp @@ -146,7 +146,7 @@ USkeletalMeshComponent::USkeletalMeshComponent(const FObjectInitializer& ObjectI { bAutoActivate = true; PrimaryComponentTick.bCanEverTick = true; - PrimaryComponentTick.bTickEvenWhenPaused = true; + PrimaryComponentTick.bTickEvenWhenPaused = false; PrimaryComponentTick.TickGroup = TG_PrePhysics; bWantsInitializeComponent = true; @@ -217,6 +217,8 @@ USkeletalMeshComponent::USkeletalMeshComponent(const FObjectInitializer& ObjectI ClothingSimulation = nullptr; ClothingSimulationContext = nullptr; + + bPostEvaluatingAnimation = false; } void USkeletalMeshComponent::Serialize(FArchive& Ar) @@ -437,16 +439,12 @@ void USkeletalMeshComponent::OnRegister() Super::OnRegister(); - bool bForceReInit = false; -#if WITH_EDITOR - // In editor worlds we force a full re-init. This is to ensure that construction script-modified - // variables propogate to the anim instance. - // This is done only in this case to limit the surface area of when we force a re-init - // (which is an expensive operation). - const UWorld* OwnWorld = GetWorld(); - bForceReInit = GIsEditor && OwnWorld && !OwnWorld->IsGameWorld(); -#endif - InitAnim(bForceReInit); + // We force an initialization here because we're in one of two cases. + // 1) First register, no spawned instance, need to initialize + // 2) We're being re-registered, in which case we've went through + // OnUnregister and unconditionally uninitialized our anim instances + // so we need to force initialize them before we begin to tick. + InitAnim(true); if (MeshComponentUpdateFlag == EMeshComponentUpdateFlag::OnlyTickPoseWhenRendered && !FApp::CanEverRender()) { @@ -867,6 +865,9 @@ void USkeletalMeshComponent::TickAnimation(float DeltaTime, bool bNeedsValidRoot SCOPE_CYCLE_COUNTER(STAT_AnimTickTime); if (SkeletalMesh != nullptr) { + // We're about to UpdateAnimation, this will potentially queue events that we'll need to dispatch. + bNeedsQueuedAnimEventsDispatched = true; + // We update sub instances first incase we're using either root motion or non-threaded update. // This ensures that we go through the pre update process and initialize the proxies correctly. for(UAnimInstance* SubInstance : SubInstances) @@ -911,6 +912,17 @@ bool USkeletalMeshComponent::ShouldUpdateTransform(bool bLODHasChanged) const { return true; } + + // if master pose is ticking, slave also has to update it + if (MasterPoseComponent.IsValid()) + { + const USkeletalMeshComponent* Master = CastChecked(MasterPoseComponent.Get()); + if (Master->GetUpdateAnimationInEditor()) + { + return true; + } + } + if( !bLODHasChanged ) { return false; @@ -1071,8 +1083,47 @@ void USkeletalMeshComponent::TickComponent(float DeltaTime, enum ELevelTick Tick ThisTickFunction->SetPriorityIncludingPrerequisites(bDoHiPri); } } + + // If we are waiting for ParallelEval to complete or if we require Physics, + // then FinalizeBoneTransform will be called and Anim events will be dispatched there. + // We prefer doing it there so these events are triggered once we have a new updated pose. + // Note that it's possible that FinalizeBoneTransform has already been called here if not using ParallelUpdate. + // or it's possible that it hasn't been called at all if we're skipping Evaluate due to not being visible. + // ConditionallyDispatchQueuedAnimEvents will catch that and only Dispatch events if not already done. + if (!IsValidRef(ParallelAnimationEvaluationTask) && !bRequiresPhysics) + { + ///////////////////////////////////////////////////////////////////////////// + // Notify / Event Handling! + // This can do anything to our component (including destroy it) + // Any code added after this point needs to take that into account + ///////////////////////////////////////////////////////////////////////////// + + ConditionallyDispatchQueuedAnimEvents(); + } } +void USkeletalMeshComponent::ConditionallyDispatchQueuedAnimEvents() +{ + if (bNeedsQueuedAnimEventsDispatched) + { + bNeedsQueuedAnimEventsDispatched = false; + + for (UAnimInstance* SubInstance : SubInstances) + { + SubInstance->DispatchQueuedAnimEvents(); + } + + if (AnimScriptInstance) + { + AnimScriptInstance->DispatchQueuedAnimEvents(); + } + + if (PostProcessAnimInstance) + { + PostProcessAnimInstance->DispatchQueuedAnimEvents(); + } + } +} /** * Utility for taking two arrays of bone indices, which must be strictly increasing, and finding the intersection between them. @@ -1490,6 +1541,8 @@ void USkeletalMeshComponent::UpdateSlaveComponent() { check (MasterPoseComponent.IsValid()); + ResetMorphTargetCurves(); + if (USkeletalMeshComponent* MasterSMC = Cast(MasterPoseComponent.Get())) { // first set any animation-driven curves from the master SMC @@ -1533,16 +1586,12 @@ void USkeletalMeshComponent::PerformAnimationEvaluation(const USkeletalMesh* InS } // update anim instance - if(AnimEvaluationContext.bDoUpdate) + if(InAnimInstance && InAnimInstance->NeedsUpdate()) { InAnimInstance->ParallelUpdateAnimation(); - - if(PostProcessAnimInstance) - { - PostProcessAnimInstance->ParallelUpdateAnimation(); - } } - else if(!InAnimInstance && PostProcessAnimInstance) + + if(PostProcessAnimInstance && PostProcessAnimInstance->NeedsUpdate()) { // If we don't have an anim instance, we may still have a post physics instance PostProcessAnimInstance->ParallelUpdateAnimation(); @@ -1730,7 +1779,6 @@ void USkeletalMeshComponent::RefreshBoneTransforms(FActorComponentTickFunction* } AnimEvaluationContext.bDoEvaluation = bShouldDoEvaluation; - AnimEvaluationContext.bDoUpdate = AnimScriptInstance && AnimScriptInstance->NeedsUpdate(); AnimEvaluationContext.bDoInterpolation = bDoEvaluationRateOptimization && !bInvalidCachedBones && AnimUpdateRateParams->ShouldInterpolateSkippedFrames() && CurrentAnimCurveMappingNameUids != nullptr; AnimEvaluationContext.bDuplicateToCacheBones = bInvalidCachedBones || (bDoEvaluationRateOptimization && AnimEvaluationContext.bDoEvaluation && !AnimEvaluationContext.bDoInterpolation); @@ -1814,14 +1862,14 @@ void USkeletalMeshComponent::RefreshBoneTransforms(FActorComponentTickFunction* AnimCurves.CopyFrom(CachedCurve); } } - if(AnimEvaluationContext.bDoUpdate) + if(AnimScriptInstance && AnimScriptInstance->NeedsUpdate()) { AnimScriptInstance->ParallelUpdateAnimation(); + } - if(PostProcessAnimInstance) - { - PostProcessAnimInstance->ParallelUpdateAnimation(); - } + if (PostProcessAnimInstance && PostProcessAnimInstance->NeedsUpdate()) + { + PostProcessAnimInstance->ParallelUpdateAnimation(); } } @@ -1837,27 +1885,31 @@ void USkeletalMeshComponent::RefreshBoneTransforms(FActorComponentTickFunction* void USkeletalMeshComponent::PostAnimEvaluation(FAnimationEvaluationContext& EvaluationContext) { +#if DO_CHECK + checkf(!bPostEvaluatingAnimation, TEXT("PostAnimEvaluation already in progress, recursion detected for SkeletalMeshComponent [%s], AnimInstance [%s]"), *GetNameSafe(this), *GetNameSafe(EvaluationContext.AnimInstance)); + TGuardValue CircularGuard(bPostEvaluatingAnimation, true); +#endif + SCOPE_CYCLE_COUNTER(STAT_PostAnimEvaluation); - if(AnimEvaluationContext.bDoUpdate) + if (EvaluationContext.AnimInstance && EvaluationContext.AnimInstance->NeedsUpdate()) { EvaluationContext.AnimInstance->PostUpdateAnimation(); - for(UAnimInstance* SubInstance : SubInstances) + for (UAnimInstance* SubInstance : SubInstances) { SubInstance->PostUpdateAnimation(); } + } - if(PostProcessAnimInstance) - { - PostProcessAnimInstance->PostUpdateAnimation(); - } + if (PostProcessAnimInstance && PostProcessAnimInstance->NeedsUpdate()) + { + PostProcessAnimInstance->PostUpdateAnimation(); + } - AnimEvaluationContext.bDoUpdate = false; - if (!IsRegistered()) // Notify/Event has caused us to go away so cannot carry on from here - { - return; - } + if (!IsRegistered()) // Notify/Event has caused us to go away so cannot carry on from here + { + return; } if (EvaluationContext.bDuplicateToCacheCurve) @@ -2047,11 +2099,11 @@ void USkeletalMeshComponent::SetSkeletalMesh(USkeletalMesh* InSkelMesh, bool bRe UpdateHasValidBodies(); InitAnim(bReinitPose); - } #if WITH_APEX_CLOTHING - RecreateClothingActors(); + RecreateClothingActors(); #endif + } // Mark cached material parameter names dirty MarkCachedMaterialParameterNameIndicesDirty(); @@ -2220,7 +2272,7 @@ void USkeletalMeshComponent::DebugDrawBones(UCanvas* Canvas, bool bSimpleBones) { int32 BoneIndex = RequiredBones[Index]; int32 ParentIndex = SkeletalMesh->RefSkeleton.GetParentIndex(BoneIndex); - FTransform BoneTM = (GetComponentSpaceTransforms()[BoneIndex] * ComponentToWorld); + FTransform BoneTM = (GetComponentSpaceTransforms()[BoneIndex] * GetComponentTransform()); FVector Start, End; FLinearColor LineColor; @@ -2228,12 +2280,12 @@ void USkeletalMeshComponent::DebugDrawBones(UCanvas* Canvas, bool bSimpleBones) if (ParentIndex >=0) { - Start = (GetComponentSpaceTransforms()[ParentIndex] * ComponentToWorld).GetLocation(); + Start = (GetComponentSpaceTransforms()[ParentIndex] * GetComponentTransform()).GetLocation(); LineColor = FLinearColor::White; } else { - Start = ComponentToWorld.GetLocation(); + Start = GetComponentTransform().GetLocation(); LineColor = FLinearColor::Red; } @@ -2535,30 +2587,27 @@ bool USkeletalMeshComponent::PoseTickedThisFrame() const FTransform USkeletalMeshComponent::ConvertLocalRootMotionToWorld(const FTransform& InTransform) { // Make sure component to world is up to date - if (!bWorldToComponentUpdated) - { - UpdateComponentToWorld(); - } + ConditionalUpdateComponentToWorld(); #if !(UE_BUILD_SHIPPING) - if (ComponentToWorld.ContainsNaN()) + if (GetComponentTransform().ContainsNaN()) { - logOrEnsureNanError(TEXT("SkeletalMeshComponent: ComponentToWorld contains NaN!")); - ComponentToWorld = FTransform::Identity; + logOrEnsureNanError(TEXT("SkeletalMeshComponent: GetComponentTransform() contains NaN!")); + SetComponentToWorld(FTransform::Identity); } #endif //Calculate new actor transform after applying root motion to this component const FTransform ActorToWorld = GetOwner()->GetTransform(); - const FTransform ComponentToActor = ActorToWorld.GetRelativeTransform(ComponentToWorld); - const FTransform NewComponentToWorld = InTransform * ComponentToWorld; + const FTransform ComponentToActor = ActorToWorld.GetRelativeTransform(GetComponentTransform()); + const FTransform NewComponentToWorld = InTransform * GetComponentTransform(); const FTransform NewActorTransform = ComponentToActor * NewComponentToWorld; const FVector DeltaWorldTranslation = NewActorTransform.GetTranslation() - ActorToWorld.GetTranslation(); - const FQuat NewWorldRotation = ComponentToWorld.GetRotation() * InTransform.GetRotation(); - const FQuat DeltaWorldRotation = NewWorldRotation * ComponentToWorld.GetRotation().Inverse(); + const FQuat NewWorldRotation = GetComponentTransform().GetRotation() * InTransform.GetRotation(); + const FQuat DeltaWorldRotation = NewWorldRotation * GetComponentTransform().GetRotation().Inverse(); const FTransform DeltaWorldTransform(DeltaWorldRotation, DeltaWorldTranslation); @@ -2633,7 +2682,7 @@ bool USkeletalMeshComponent::ComponentIsTouchingSelectionBox(const FBox& InSelBB { for (const auto& Vertex : Section.SoftVertices) { - const FVector Location = ComponentToWorld.TransformPosition(Vertex.Position); + const FVector Location = GetComponentTransform().TransformPosition(Vertex.Position); const bool bLocationIntersected = FMath::PointBoxIntersection(Location, InSelBBox); // If the selection box doesn't have to encompass the entire component and a skeletal mesh vertex has intersected with @@ -2677,7 +2726,7 @@ bool USkeletalMeshComponent::ComponentIsTouchingSelectionFrustum(const FConvexVo { for (const auto& Vertex : Section.SoftVertices) { - const FVector Location = ComponentToWorld.TransformPosition(Vertex.Position); + const FVector Location = GetComponentTransform().TransformPosition(Vertex.Position); const bool bLocationIntersected = InFrustum.IntersectSphere(Location, 0.0f); // If the selection box doesn't have to encompass the entire component and a skeletal mesh vertex has intersected with @@ -2966,7 +3015,7 @@ void USkeletalMeshComponent::UnbindClothFromMasterPoseComponent(bool bRestoreSim bool USkeletalMeshComponent::DoCustomNavigableGeometryExport(FNavigableGeometryExport& GeomExport) const { UPhysicsAsset* PhysicsAsset = GetPhysicsAsset(); - if (PhysicsAsset && ComponentToWorld.GetScale3D().IsUniform()) + if (PhysicsAsset && GetComponentTransform().GetScale3D().IsUniform()) { const int32 MaxBodies = PhysicsAsset->SkeletalBodySetups.Num(); for (int32 Idx = 0; Idx < MaxBodies; Idx++) @@ -2976,7 +3025,7 @@ bool USkeletalMeshComponent::DoCustomNavigableGeometryExport(FNavigableGeometryE if (BoneIndex != INDEX_NONE) { - FTransform WorldBoneTransform = GetBoneTransform(BoneIndex, ComponentToWorld); + FTransform WorldBoneTransform = GetBoneTransform(BoneIndex, GetComponentTransform()); if (FMath::Abs(WorldBoneTransform.GetDeterminant()) > (float)KINDA_SMALL_NUMBER) { GeomExport.ExportRigidBodySetup(*BS, WorldBoneTransform); @@ -2993,6 +3042,17 @@ void USkeletalMeshComponent::FinalizeBoneTransform() { Super::FinalizeBoneTransform(); + // After pose has been finalized, dispatch AnimNotifyEvents in case they want to use up to date pose. + // (For example attaching particle systems to up to date sockets). + + ///////////////////////////////////////////////////////////////////////////// + // Notify / Event Handling! + // This can do anything to our component (including destroy it) + // Any code added after this point needs to take that into account + ///////////////////////////////////////////////////////////////////////////// + + ConditionallyDispatchQueuedAnimEvents(); + for(UAnimInstance* SubInstance : SubInstances) { SubInstance->PostEvaluateAnimation(); diff --git a/Engine/Source/Runtime/Engine/Private/Components/SkinnedMeshComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/SkinnedMeshComponent.cpp index 40397576443b..28dd32466e24 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/SkinnedMeshComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/SkinnedMeshComponent.cpp @@ -760,7 +760,7 @@ bool USkinnedMeshComponent::GetMaterialStreamingData(int32 MaterialIndex, FPrimi void USkinnedMeshComponent::GetStreamingTextureInfo(FStreamingTextureLevelContext& LevelContext, TArray& OutStreamingTextures) const { - GetStreamingTextureInfoInner(LevelContext, nullptr, ComponentToWorld.GetMaximumAxisScale(), OutStreamingTextures); + GetStreamingTextureInfoInner(LevelContext, nullptr, GetComponentTransform().GetMaximumAxisScale() * StreamingDistanceMultiplier, OutStreamingTextures); } bool USkinnedMeshComponent::ShouldUpdateBoneVisibility() const @@ -915,7 +915,7 @@ FMatrix USkinnedMeshComponent::GetBoneMatrix(int32 BoneIdx) const if ( !IsRegistered() ) { // if not registered, we don't have SpaceBases yet. - // also ComponentToWorld isn't set yet (They're set from relativetranslation, relativerotation, relativescale) + // also GetComponentTransform() isn't set yet (They're set from relativetranslation, relativerotation, relativescale) return FMatrix::Identity; } @@ -931,7 +931,7 @@ FMatrix USkinnedMeshComponent::GetBoneMatrix(int32 BoneIdx) const if( ParentBoneIndex != INDEX_NONE && ParentBoneIndex < MasterPoseComponentInst->GetNumComponentSpaceTransforms()) { - return MasterPoseComponentInst->GetComponentSpaceTransforms()[ParentBoneIndex].ToMatrixWithScale() * ComponentToWorld.ToMatrixWithScale(); + return MasterPoseComponentInst->GetComponentSpaceTransforms()[ParentBoneIndex].ToMatrixWithScale() * GetComponentTransform().ToMatrixWithScale(); } else { @@ -949,7 +949,7 @@ FMatrix USkinnedMeshComponent::GetBoneMatrix(int32 BoneIdx) const { if(GetNumComponentSpaceTransforms() && BoneIdx < GetNumComponentSpaceTransforms() ) { - return GetComponentSpaceTransforms()[BoneIdx].ToMatrixWithScale() * ComponentToWorld.ToMatrixWithScale(); + return GetComponentSpaceTransforms()[BoneIdx].ToMatrixWithScale() * GetComponentTransform().ToMatrixWithScale(); } else { @@ -964,11 +964,11 @@ FTransform USkinnedMeshComponent::GetBoneTransform(int32 BoneIdx) const if (!IsRegistered()) { // if not registered, we don't have SpaceBases yet. - // also ComponentToWorld isn't set yet (They're set from relativelocation, relativerotation, relativescale) + // also GetComponentTransform() isn't set yet (They're set from relativelocation, relativerotation, relativescale) return FTransform::Identity; } - return GetBoneTransform(BoneIdx, ComponentToWorld); + return GetBoneTransform(BoneIdx, GetComponentTransform()); } FTransform USkinnedMeshComponent::GetBoneTransform(int32 BoneIdx, const FTransform& LocalToWorld) const @@ -1389,7 +1389,7 @@ void USkinnedMeshComponent::UpdateMasterBoneMap() FTransform USkinnedMeshComponent::GetSocketTransform(FName InSocketName, ERelativeTransformSpace TransformSpace) const { - FTransform OutSocketTransform = ComponentToWorld; + FTransform OutSocketTransform = GetComponentTransform(); if (InSocketName != NAME_None) { @@ -1427,7 +1427,7 @@ FTransform USkinnedMeshComponent::GetSocketTransform(FName InSocketName, ERelati { return OutSocketTransform.GetRelativeTransform(GetBoneTransform(ParentIndex)); } - return OutSocketTransform.GetRelativeTransform(ComponentToWorld); + return OutSocketTransform.GetRelativeTransform(GetComponentTransform()); } } } @@ -1445,7 +1445,7 @@ FTransform USkinnedMeshComponent::GetSocketTransform(FName InSocketName, ERelati } case RTS_Component: { - return OutSocketTransform.GetRelativeTransform( ComponentToWorld ); + return OutSocketTransform.GetRelativeTransform( GetComponentTransform() ); } } @@ -1710,7 +1710,7 @@ FName USkinnedMeshComponent::FindClosestBone(FVector TestLocation, FVector* Bone } // transform the TestLocation into mesh local space so we don't have to transform the (mesh local) bone locations - TestLocation = ComponentToWorld.InverseTransformPosition(TestLocation); + TestLocation = GetComponentTransform().InverseTransformPosition(TestLocation); float IgnoreScaleSquared = FMath::Square(IgnoreScale); float BestDistSquared = BIG_NUMBER; @@ -1749,7 +1749,7 @@ FName USkinnedMeshComponent::FindClosestBone(FVector TestLocation, FVector* Bone // transform the bone location into world space if (BoneLocation != NULL) { - *BoneLocation = (GetComponentSpaceTransforms()[BestIndex] * ComponentToWorld).GetLocation(); + *BoneLocation = (GetComponentSpaceTransforms()[BestIndex] * GetComponentTransform()).GetLocation(); } return SkeletalMesh->RefSkeleton.GetBoneName(BestIndex); } @@ -1869,24 +1869,27 @@ FORCEINLINE FVector GetTypedSkinnedVertexPosition( for(int32 InfluenceIndex = 0;InfluenceIndex < Section.MaxBoneInfluences;InfluenceIndex++) #endif { - int32 BoneIndex = Section.BoneMap[SrcSkinWeights->InfluenceBones[InfluenceIndex]]; + const int32 MeshBoneIndex = Section.BoneMap[SrcSkinWeights->InfluenceBones[InfluenceIndex]]; + int32 TransformBoneIndex = MeshBoneIndex; + if(MasterPoseComponentInst) { const TArray& MasterBoneMap = SkinnedComp->GetMasterBoneMap(); check(MasterBoneMap.Num() == SkinnedComp->SkeletalMesh->RefSkeleton.GetNum()); - BoneIndex = MasterBoneMap[BoneIndex]; + TransformBoneIndex = MasterBoneMap[MeshBoneIndex]; } const float Weight = (float)SrcSkinWeights->InfluenceWeights[InfluenceIndex] / 255.0f; { if (bCachedMatrices) { - const FMatrix& RefToLocal = RefToLocals[BoneIndex]; + const FMatrix& RefToLocal = RefToLocals[MeshBoneIndex]; SkinnedPos += RefToLocal.TransformPosition(VertexBufferGPUSkin.GetVertexPositionFast(SrcSoftVertex)) * Weight; } else { - const FMatrix RefToLocal = SkinnedComp->SkeletalMesh->RefBasesInvMatrix[BoneIndex] * BaseComponent->GetComponentSpaceTransforms()[BoneIndex].ToMatrixWithScale(); + const FMatrix BoneTransformMatrix = (TransformBoneIndex != INDEX_NONE) ? BaseComponent->GetComponentSpaceTransforms()[TransformBoneIndex].ToMatrixWithScale() : FMatrix::Identity; + const FMatrix RefToLocal = SkinnedComp->SkeletalMesh->RefBasesInvMatrix[MeshBoneIndex] * BoneTransformMatrix; SkinnedPos += RefToLocal.TransformPosition(VertexBufferGPUSkin.GetVertexPositionFast(SrcSoftVertex)) * Weight; } } diff --git a/Engine/Source/Runtime/Engine/Private/Components/SkyLightComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/SkyLightComponent.cpp index 01db0fbdcbf8..a4a561832b56 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/SkyLightComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/SkyLightComponent.cpp @@ -19,7 +19,7 @@ #include "Misc/MapErrors.h" #include "ShaderCompiler.h" #include "Components/BillboardComponent.h" -#include "Interfaces/ITargetPlatform.h" +#include "ReleaseObjectVersion.h" #define LOCTEXT_NAMESPACE "SkyLightComponent" @@ -170,19 +170,16 @@ USkyLightComponent::USkyLightComponent(const FObjectInitializer& ObjectInitializ LowerHemisphereColor = FLinearColor::Black; AverageBrightness = 1.0f; BlendDestinationAverageBrightness = 1.0f; - bSkyCaptureRequiredFromLoad = false; bCastVolumetricShadow = true; } FSkyLightSceneProxy* USkyLightComponent::CreateSceneProxy() const { - // Mobile doesnt use SkyTexture. - const bool bMobileSkyLight = GetWorld()->FeatureLevel <= ERHIFeatureLevel::ES3_1; - if (ProcessedSkyTexture || bMobileSkyLight) + if (ProcessedSkyTexture) { return new FSkyLightSceneProxy(this); } - + return NULL; } @@ -276,10 +273,6 @@ void USkyLightComponent::PostLoad() FScopeLock Lock(&SkyCapturesToUpdateLock); SkyCapturesToUpdate.Remove(this); } - else - { - bSkyCaptureRequiredFromLoad = true; - } } /** @@ -427,33 +420,6 @@ void USkyLightComponent::CheckForErrors() } } -// If the feature level preview has been set before on-load captures have been built then the editor must update them. -bool USkyLightComponent::MobileSkyCapturesNeedForcedUpdate(UWorld* WorldToUpdate) -{ - if (WorldToUpdate->Scene - && WorldToUpdate->Scene->GetFeatureLevel() <= ERHIFeatureLevel::ES3_1 - && (GShaderCompilingManager == NULL || !GShaderCompilingManager->IsCompiling())) - { - FScopeLock Lock(&SkyCapturesToUpdateLock); - for (int32 CaptureIndex = SkyCapturesToUpdate.Num() - 1; CaptureIndex >= 0; CaptureIndex--) - { - USkyLightComponent* CaptureComponent = SkyCapturesToUpdate[CaptureIndex]; - AActor* Owner = CaptureComponent->GetOwner(); - if (CaptureComponent->bSkyCaptureRequiredFromLoad - && !CaptureComponent->IsPendingKill() - && CaptureComponent->bVisible - && CaptureComponent->bAffectsWorld - && Owner - && WorldToUpdate->ContainsActor(Owner) - && !WorldToUpdate->IsPendingKill()) - { - return true; - } - } - } - return false; -} - #endif // WITH_EDITOR void USkyLightComponent::BeginDestroy() @@ -585,7 +551,6 @@ void USkyLightComponent::UpdateSkyCaptureContentsArray(UWorld* WorldToUpdate, TA CaptureComponent->IrradianceMapFence.BeginFence(); CaptureComponent->bHasEverCaptured = true; - CaptureComponent->bSkyCaptureRequiredFromLoad = false; CaptureComponent->MarkRenderStateDirty(); } @@ -597,7 +562,7 @@ void USkyLightComponent::UpdateSkyCaptureContentsArray(UWorld* WorldToUpdate, TA void USkyLightComponent::UpdateSkyCaptureContents(UWorld* WorldToUpdate) { - if (WorldToUpdate->Scene && WorldToUpdate->FeatureLevel >= ERHIFeatureLevel::SM4) + if (WorldToUpdate->Scene) { QUICK_SCOPE_CYCLE_COUNTER(STAT_SkylightCaptures); if (SkyCapturesToUpdate.Num() > 0) @@ -792,24 +757,15 @@ void USkyLightComponent::RecaptureSky() void USkyLightComponent::Serialize(FArchive& Ar) { + Ar.UsingCustomVersion(FReleaseObjectVersion::GUID); + Super::Serialize(Ar); - if (Ar.UE4Ver() >= VER_UE4_SKYLIGHT_MOBILE_IRRADIANCE_MAP) + // if version is between VER_UE4_SKYLIGHT_MOBILE_IRRADIANCE_MAP and FReleaseObjectVersion::SkyLightRemoveMobileIrradianceMap then handle aborted attempt to serialize irradiance data on mobile. + if (Ar.UE4Ver() >= VER_UE4_SKYLIGHT_MOBILE_IRRADIANCE_MAP && !(Ar.CustomVer(FReleaseObjectVersion::GUID) >= FReleaseObjectVersion::SkyLightRemoveMobileIrradianceMap)) { - if (bHasEverCaptured) - { - IrradianceMapFence.Wait(); - } - Ar << IrradianceEnvironmentMap; - } - else - { - if(Ar.IsCooking() && Ar.CookingTarget()->SupportsFeature(ETargetPlatformFeatures::MobileRendering) ) - { - // Temporary warning until the cooker can do sky captures itself. - UE_LOG(LogMaterial, Warning, TEXT("Sky light's mobile data is not present. This light will provide no lighting contribution on mobile.")); - UE_LOG(LogMaterial, Warning, TEXT("Fix by resaving the map in the editor. %s."), *GetFullName()); - } + FSHVectorRGB3 DummyIrradianceEnvironmentMap; + Ar << DummyIrradianceEnvironmentMap; } } @@ -864,6 +820,3 @@ void ASkyLight::OnRep_bEnabled() } #undef LOCTEXT_NAMESPACE - -/** Returns LightComponent subobject **/ -USkyLightComponent* ASkyLight::GetLightComponent() const { return LightComponent; } diff --git a/Engine/Source/Runtime/Engine/Private/Components/SphereComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/SphereComponent.cpp index dfa39c44c281..5d284325134f 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/SphereComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/SphereComponent.cpp @@ -26,7 +26,7 @@ FBoxSphereBounds USphereComponent::CalcBounds(const FTransform& LocalToWorld) co void USphereComponent::CalcBoundingCylinder(float& CylinderRadius, float& CylinderHalfHeight) const { - CylinderRadius = SphereRadius * ComponentToWorld.GetMaximumAxisScale(); + CylinderRadius = SphereRadius * GetComponentTransform().GetMaximumAxisScale(); CylinderHalfHeight = CylinderRadius; } @@ -87,7 +87,7 @@ void USphereComponent::SetSphereRadius( float InSphereRadius, bool bUpdateOverla if (bPhysicsStateCreated) { // Update physics engine collision shapes - BodyInstance.UpdateBodyScale(ComponentToWorld.GetScale3D(), true); + BodyInstance.UpdateBodyScale(GetComponentTransform().GetScale3D(), true); if ( bUpdateOverlaps && IsCollisionEnabled() && GetOwner() ) { diff --git a/Engine/Source/Runtime/Engine/Private/Components/SplineComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/SplineComponent.cpp index a204ea2c1bde..0fc477cf1a2b 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/SplineComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/SplineComponent.cpp @@ -185,7 +185,7 @@ void FSplineCurves::UpdateSpline(bool bClosedLoop, bool bStationaryEndpoints, in void USplineComponent::UpdateSpline() { - SplineCurves.UpdateSpline(bClosedLoop, bStationaryEndpoints, ReparamStepsPerSegment, bLoopPositionOverride, LoopPosition, ComponentToWorld.GetScale3D()); + SplineCurves.UpdateSpline(bClosedLoop, bStationaryEndpoints, ReparamStepsPerSegment, bLoopPositionOverride, LoopPosition, GetComponentTransform().GetScale3D()); #if !UE_BUILD_SHIPPING if (bDrawDebug) @@ -264,7 +264,7 @@ float FSplineCurves::GetSegmentLength(const int32 Index, const float Param, bool float USplineComponent::GetSegmentLength(const int32 Index, const float Param) const { - return SplineCurves.GetSegmentLength(Index, Param, bClosedLoop, ComponentToWorld.GetScale3D()); + return SplineCurves.GetSegmentLength(Index, Param, bClosedLoop, GetComponentTransform().GetScale3D()); } float USplineComponent::GetSegmentParamFromLength(const int32 Index, const float Length, const float SegmentLength) const @@ -322,7 +322,7 @@ FVector USplineComponent::GetLocationAtSplineInputKey(float InKey, ESplineCoordi if (CoordinateSpace == ESplineCoordinateSpace::World) { - Location = ComponentToWorld.TransformPosition(Location); + Location = GetComponentTransform().TransformPosition(Location); } return Location; @@ -335,7 +335,7 @@ FVector USplineComponent::GetTangentAtSplineInputKey(float InKey, ESplineCoordin if (CoordinateSpace == ESplineCoordinateSpace::World) { - Tangent = ComponentToWorld.TransformVector(Tangent); + Tangent = GetComponentTransform().TransformVector(Tangent); } return Tangent; @@ -348,7 +348,7 @@ FVector USplineComponent::GetDirectionAtSplineInputKey(float InKey, ESplineCoord if (CoordinateSpace == ESplineCoordinateSpace::World) { - Direction = ComponentToWorld.TransformVectorNoScale(Direction); + Direction = GetComponentTransform().TransformVectorNoScale(Direction); } return Direction; @@ -373,7 +373,7 @@ FQuat USplineComponent::GetQuaternionAtSplineInputKey(float InKey, ESplineCoordi if (CoordinateSpace == ESplineCoordinateSpace::World) { - Rot = ComponentToWorld.GetRotation() * Rot; + Rot = GetComponentTransform().GetRotation() * Rot; } return Rot; @@ -387,7 +387,7 @@ FVector USplineComponent::GetUpVectorAtSplineInputKey(float InKey, ESplineCoordi if (CoordinateSpace == ESplineCoordinateSpace::World) { - UpVector = ComponentToWorld.TransformVectorNoScale(UpVector); + UpVector = GetComponentTransform().TransformVectorNoScale(UpVector); } return UpVector; @@ -401,7 +401,7 @@ FVector USplineComponent::GetRightVectorAtSplineInputKey(float InKey, ESplineCoo if (CoordinateSpace == ESplineCoordinateSpace::World) { - RightVector = ComponentToWorld.TransformVectorNoScale(RightVector); + RightVector = GetComponentTransform().TransformVectorNoScale(RightVector); } return RightVector; @@ -418,7 +418,7 @@ FTransform USplineComponent::GetTransformAtSplineInputKey(float InKey, ESplineCo if (CoordinateSpace == ESplineCoordinateSpace::World) { - Transform = Transform * ComponentToWorld; + Transform = Transform * GetComponentTransform(); } return Transform; @@ -589,7 +589,7 @@ void USplineComponent::AddPoints(const TArray& InSplinePoints, boo void USplineComponent::AddSplinePoint(const FVector& Position, ESplineCoordinateSpace::Type CoordinateSpace, bool bUpdateSpline) { const FVector TransformedPosition = (CoordinateSpace == ESplineCoordinateSpace::World) ? - ComponentToWorld.InverseTransformPosition(Position) : Position; + GetComponentTransform().InverseTransformPosition(Position) : Position; // Add the spline point at the end of the array, adding 1.0 to the current last input key. // This continues the former behavior in which spline points had to be separated by an interval of 1.0. @@ -613,7 +613,7 @@ void USplineComponent::AddSplinePoint(const FVector& Position, ESplineCoordinate void USplineComponent::AddSplinePointAtIndex(const FVector& Position, int32 Index, ESplineCoordinateSpace::Type CoordinateSpace, bool bUpdateSpline) { const FVector TransformedPosition = (CoordinateSpace == ESplineCoordinateSpace::World) ? - ComponentToWorld.InverseTransformPosition(Position) : Position; + GetComponentTransform().InverseTransformPosition(Position) : Position; int32 NumPoints = SplineCurves.Position.Points.Num(); @@ -689,7 +689,7 @@ void USplineComponent::SetSplinePoints(const TArray& Points, ESplineCoo for (const auto& Point : Points) { const FVector TransformedPoint = (CoordinateSpace == ESplineCoordinateSpace::World) ? - ComponentToWorld.InverseTransformPosition(Point) : Point; + GetComponentTransform().InverseTransformPosition(Point) : Point; SplineCurves.Position.Points.Emplace(InputKey, TransformedPoint, FVector::ZeroVector, FVector::ZeroVector, CIM_CurveAuto); SplineCurves.Rotation.Points.Emplace(InputKey, FQuat::Identity, FQuat::Identity, FQuat::Identity, CIM_CurveAuto); @@ -714,7 +714,7 @@ void USplineComponent::SetLocationAtSplinePoint(int32 PointIndex, const FVector& if ((PointIndex >= 0) && (PointIndex < NumPoints)) { const FVector TransformedLocation = (CoordinateSpace == ESplineCoordinateSpace::World) ? - ComponentToWorld.InverseTransformPosition(InLocation) : InLocation; + GetComponentTransform().InverseTransformPosition(InLocation) : InLocation; SplineCurves.Position.Points[PointIndex].OutVal = TransformedLocation; @@ -733,7 +733,7 @@ void USplineComponent::SetTangentAtSplinePoint(int32 PointIndex, const FVector& if ((PointIndex >= 0) && (PointIndex < NumPoints)) { const FVector TransformedTangent = (CoordinateSpace == ESplineCoordinateSpace::World) ? - ComponentToWorld.InverseTransformVector(InTangent) : InTangent; + GetComponentTransform().InverseTransformVector(InTangent) : InTangent; SplineCurves.Position.Points[PointIndex].LeaveTangent = TransformedTangent; SplineCurves.Position.Points[PointIndex].ArriveTangent = TransformedTangent; @@ -754,9 +754,9 @@ void USplineComponent::SetTangentsAtSplinePoint(int32 PointIndex, const FVector& if ((PointIndex >= 0) && (PointIndex < NumPoints)) { const FVector TransformedArriveTangent = (CoordinateSpace == ESplineCoordinateSpace::World) ? - ComponentToWorld.InverseTransformVector(InArriveTangent) : InArriveTangent; + GetComponentTransform().InverseTransformVector(InArriveTangent) : InArriveTangent; const FVector TransformedLeaveTangent = (CoordinateSpace == ESplineCoordinateSpace::World) ? - ComponentToWorld.InverseTransformVector(InLeaveTangent) : InLeaveTangent; + GetComponentTransform().InverseTransformVector(InLeaveTangent) : InLeaveTangent; SplineCurves.Position.Points[PointIndex].ArriveTangent = TransformedArriveTangent; SplineCurves.Position.Points[PointIndex].LeaveTangent = TransformedLeaveTangent; @@ -777,7 +777,7 @@ void USplineComponent::SetUpVectorAtSplinePoint(int32 PointIndex, const FVector& if ((PointIndex >= 0) && (PointIndex < NumPoints)) { const FVector TransformedUpVector = (CoordinateSpace == ESplineCoordinateSpace::World) ? - ComponentToWorld.InverseTransformVector(InUpVector.GetSafeNormal()) : InUpVector.GetSafeNormal(); + GetComponentTransform().InverseTransformVector(InUpVector.GetSafeNormal()) : InUpVector.GetSafeNormal(); FQuat Quat = FQuat::FindBetween(DefaultUpVector, TransformedUpVector); SplineCurves.Rotation.Points[PointIndex].OutVal = Quat; @@ -827,7 +827,7 @@ FVector USplineComponent::GetLocationAtSplinePoint(int32 PointIndex, ESplineCoor const int32 NumPoints = SplineCurves.Position.Points.Num(); const int32 ClampedIndex = (bClosedLoop && PointIndex >= NumPoints) ? 0 : FMath::Clamp(PointIndex, 0, NumPoints - 1); const FVector Location = SplineCurves.Position.Points[ClampedIndex].OutVal; - return (CoordinateSpace == ESplineCoordinateSpace::World) ? ComponentToWorld.TransformPosition(Location) : Location; + return (CoordinateSpace == ESplineCoordinateSpace::World) ? GetComponentTransform().TransformPosition(Location) : Location; } @@ -836,7 +836,7 @@ FVector USplineComponent::GetDirectionAtSplinePoint(int32 PointIndex, ESplineCoo const int32 NumPoints = SplineCurves.Position.Points.Num(); const int32 ClampedIndex = (bClosedLoop && PointIndex >= NumPoints) ? 0 : FMath::Clamp(PointIndex, 0, NumPoints - 1); const FVector Direction = SplineCurves.Position.Points[ClampedIndex].LeaveTangent.GetSafeNormal(); - return (CoordinateSpace == ESplineCoordinateSpace::World) ? ComponentToWorld.TransformVector(Direction) : Direction; + return (CoordinateSpace == ESplineCoordinateSpace::World) ? GetComponentTransform().TransformVector(Direction) : Direction; } @@ -845,7 +845,7 @@ FVector USplineComponent::GetTangentAtSplinePoint(int32 PointIndex, ESplineCoord const int32 NumPoints = SplineCurves.Position.Points.Num(); const int32 ClampedIndex = (bClosedLoop && PointIndex >= NumPoints) ? 0 : FMath::Clamp(PointIndex, 0, NumPoints - 1); const FVector Direction = SplineCurves.Position.Points[ClampedIndex].LeaveTangent; - return (CoordinateSpace == ESplineCoordinateSpace::World) ? ComponentToWorld.TransformVector(Direction) : Direction; + return (CoordinateSpace == ESplineCoordinateSpace::World) ? GetComponentTransform().TransformVector(Direction) : Direction; } @@ -854,7 +854,7 @@ FVector USplineComponent::GetArriveTangentAtSplinePoint(int32 PointIndex, ESplin const int32 NumPoints = SplineCurves.Position.Points.Num(); const int32 ClampedIndex = (bClosedLoop && PointIndex >= NumPoints) ? 0 : FMath::Clamp(PointIndex, 0, NumPoints - 1); const FVector Direction = SplineCurves.Position.Points[ClampedIndex].ArriveTangent; - return (CoordinateSpace == ESplineCoordinateSpace::World) ? ComponentToWorld.TransformVector(Direction) : Direction; + return (CoordinateSpace == ESplineCoordinateSpace::World) ? GetComponentTransform().TransformVector(Direction) : Direction; } @@ -863,7 +863,7 @@ FVector USplineComponent::GetLeaveTangentAtSplinePoint(int32 PointIndex, ESpline const int32 NumPoints = SplineCurves.Position.Points.Num(); const int32 ClampedIndex = (bClosedLoop && PointIndex >= NumPoints) ? 0 : FMath::Clamp(PointIndex, 0, NumPoints - 1); const FVector Direction = SplineCurves.Position.Points[ClampedIndex].LeaveTangent; - return (CoordinateSpace == ESplineCoordinateSpace::World) ? ComponentToWorld.TransformVector(Direction) : Direction; + return (CoordinateSpace == ESplineCoordinateSpace::World) ? GetComponentTransform().TransformVector(Direction) : Direction; } @@ -969,7 +969,7 @@ void USplineComponent::SetDefaultUpVector(const FVector& UpVector, ESplineCoordi { if (CoordinateSpace == ESplineCoordinateSpace::World) { - DefaultUpVector = ComponentToWorld.InverseTransformVector(UpVector); + DefaultUpVector = GetComponentTransform().InverseTransformVector(UpVector); } else { @@ -984,7 +984,7 @@ FVector USplineComponent::GetDefaultUpVector(ESplineCoordinateSpace::Type Coordi { if (CoordinateSpace == ESplineCoordinateSpace::World) { - return ComponentToWorld.TransformVector(DefaultUpVector); + return GetComponentTransform().TransformVector(DefaultUpVector); } else { @@ -1289,7 +1289,7 @@ FVector USplineComponent::GetScaleAtTime(float Time, bool bUseConstantVelocity) float USplineComponent::FindInputKeyClosestToWorldLocation(const FVector& WorldLocation) const { - const FVector LocalLocation = ComponentToWorld.InverseTransformPosition(WorldLocation); + const FVector LocalLocation = GetComponentTransform().InverseTransformPosition(WorldLocation); float Dummy; return SplineCurves.Position.InaccurateFindNearest(LocalLocation, Dummy); } diff --git a/Engine/Source/Runtime/Engine/Private/Components/SplineMeshComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/SplineMeshComponent.cpp index 7cc8522f9565..61b8c346eac3 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/SplineMeshComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/SplineMeshComponent.cpp @@ -595,10 +595,8 @@ void USplineMeshComponent::UpdateRenderStateAndCollision_Internal(bool bConcurre } } -#if WITH_EDITOR || WITH_RUNTIME_PHYSICS_COOKING CachedMeshBodySetupGuid.Invalidate(); RecreatePhysicsState(); -#endif // WITH_EDITOR || WITH_RUNTIME_PHYSICS_COOKING bMeshDirty = false; } @@ -998,20 +996,12 @@ void USplineMeshComponent::GetMeshId(FString& OutMeshId) void USplineMeshComponent::OnCreatePhysicsState() { -#if WITH_EDITOR || WITH_RUNTIME_PHYSICS_COOKING // With editor code we can recreate the collision if the mesh changes const FGuid MeshBodySetupGuid = (GetStaticMesh() != nullptr ? GetStaticMesh()->BodySetup->BodySetupGuid : FGuid()); if (CachedMeshBodySetupGuid != MeshBodySetupGuid) { RecreateCollision(); } -#else - // Without editor code we can only destroy the collision if the mesh is missing - if (GetStaticMesh() == NULL && BodySetup != NULL) - { - DestroyBodySetup(); - } -#endif return Super::OnCreatePhysicsState(); } @@ -1054,7 +1044,7 @@ bool USplineMeshComponent::DoCustomNavigableGeometryExport(FNavigableGeometryExp } GeomExport.ExportCustomMesh(VertexBuffer.GetData(), VertexBuffer.Num(), NavCollision->ConvexCollision.IndexBuffer.GetData(), NavCollision->ConvexCollision.IndexBuffer.Num(), - ComponentToWorld); + GetComponentTransform()); VertexBuffer.Reset(); for (int32 i = 0; i < NavCollision->TriMeshCollision.VertexBuffer.Num(); ++i) @@ -1065,7 +1055,7 @@ bool USplineMeshComponent::DoCustomNavigableGeometryExport(FNavigableGeometryExp } GeomExport.ExportCustomMesh(VertexBuffer.GetData(), VertexBuffer.Num(), NavCollision->TriMeshCollision.IndexBuffer.GetData(), NavCollision->TriMeshCollision.IndexBuffer.Num(), - ComponentToWorld); + GetComponentTransform()); return false; } @@ -1087,8 +1077,6 @@ void USplineMeshComponent::DestroyBodySetup() } } - -#if WITH_EDITOR || WITH_RUNTIME_PHYSICS_COOKING void USplineMeshComponent::RecreateCollision() { if (GetStaticMesh() && IsCollisionEnabled()) @@ -1189,7 +1177,6 @@ void USplineMeshComponent::RecreateCollision() DestroyBodySetup(); } } -#endif /** Used to store spline mesh data during RerunConstructionScripts */ class FSplineMeshInstanceData : public FSceneComponentInstanceData @@ -1282,7 +1269,7 @@ float USplineMeshComponent::GetTextureStreamingTransformScale() const // We do this by looking at the ratio between current bounds (including deformation) and undeformed (straight from staticmesh) const float MinExtent = 1.0f; - FBoxSphereBounds UndeformedBounds = GetStaticMesh()->GetBounds().TransformBy(ComponentToWorld); + FBoxSphereBounds UndeformedBounds = GetStaticMesh()->GetBounds().TransformBy(GetComponentTransform()); if (UndeformedBounds.BoxExtent.X >= MinExtent) { SplineDeformFactor = FMath::Max(SplineDeformFactor, Bounds.BoxExtent.X / UndeformedBounds.BoxExtent.X); diff --git a/Engine/Source/Runtime/Engine/Private/Components/SpotLightComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/SpotLightComponent.cpp index e4c01d29fcc7..a8b9e5f23d87 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/SpotLightComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/SpotLightComponent.cpp @@ -217,7 +217,7 @@ FSphere USpotLightComponent::GetBoundingSphere() const // Use the law of cosines to find the distance to the furthest edge of the spotlight cone from a position that is halfway down the spotlight direction const float BoundsRadius = FMath::Sqrt(1.25f * AttenuationRadius * AttenuationRadius - AttenuationRadius * AttenuationRadius * CosOuterCone); - return FSphere(ComponentToWorld.GetLocation() + .5f * GetDirection() * AttenuationRadius, BoundsRadius); + return FSphere(GetComponentTransform().GetLocation() + .5f * GetDirection() * AttenuationRadius, BoundsRadius); } bool USpotLightComponent::AffectsBounds(const FBoxSphereBounds& InBounds) const diff --git a/Engine/Source/Runtime/Engine/Private/Components/StaticMeshComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/StaticMeshComponent.cpp index 77c134785450..6b40ee7dcc2b 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/StaticMeshComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/StaticMeshComponent.cpp @@ -208,6 +208,8 @@ UStaticMeshComponent::~UStaticMeshComponent() // Empty, but required because we don't want to have to include LightMap.h and ShadowMap.h in StaticMeshComponent.h, and they are required to compile FLightMapRef and FShadowMapRef } +/// @cond DOXYGEN_WARNINGS + void UStaticMeshComponent::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); @@ -217,6 +219,8 @@ void UStaticMeshComponent::GetLifetimeReplicatedProps(TArray< FLifetimeProperty PRAGMA_ENABLE_DEPRECATION_WARNINGS } +/// @endcond + void UStaticMeshComponent::OnRep_StaticMesh(class UStaticMesh *OldStaticMesh) { PRAGMA_DISABLE_DEPRECATION_WARNINGS @@ -730,7 +734,7 @@ bool UStaticMeshComponent::BuildTextureStreamingData(ETextureStreamingBuildType MaterialStreamingRelativeBoxes.Empty(NumMaterials); for (int32 MaterialIndex = 0; MaterialIndex < NumMaterials; ++MaterialIndex) { - MaterialStreamingRelativeBoxes.Add(PackRelativeBox(Bounds.GetBox(), GetStaticMesh()->GetMaterialBox(MaterialIndex, ComponentToWorld))); + MaterialStreamingRelativeBoxes.Add(PackRelativeBox(Bounds.GetBox(), GetStaticMesh()->GetMaterialBox(MaterialIndex, GetComponentTransform()))); } // Update since proxy has a copy of the material bounds. @@ -821,7 +825,7 @@ bool UStaticMeshComponent::BuildTextureStreamingData(ETextureStreamingBuildType float UStaticMeshComponent::GetTextureStreamingTransformScale() const { - return ComponentToWorld.GetMaximumAxisScale(); + return GetComponentTransform().GetMaximumAxisScale(); } void UStaticMeshComponent::GetStreamingTextureInfo(FStreamingTextureLevelContext& LevelContext, TArray& OutStreamingTextures) const @@ -966,7 +970,7 @@ FTransform UStaticMeshComponent::GetSocketTransform(FName InSocketName, ERelativ } case RTS_Component: { - return SocketWorldTransform.GetRelativeTransform(ComponentToWorld); + return SocketWorldTransform.GetRelativeTransform(GetComponentTransform()); } } } @@ -1282,7 +1286,7 @@ void UStaticMeshComponent::PrivateFixupOverrideColors() const int32 NumVerts = CurRenderData.GetNumVertices(); check(NumVerts == NewOverrideColors.Num()); - LODInfo.PaintedVertices.Reserve(NumVerts); + LODInfo.PaintedVertices.Empty(NumVerts); for (int32 VertIndex = 0; VertIndex < NumVerts; ++VertIndex) { FPaintedVertex* Vertex = new(LODInfo.PaintedVertices) FPaintedVertex; @@ -1673,7 +1677,6 @@ void UStaticMeshComponent::PostLoad() // Remap the materials array if the static mesh materials may have been remapped to remove zero triangle sections. if (GetStaticMesh() && GetLinkerUE4Version() < VER_UE4_REMOVE_ZERO_TRIANGLE_SECTIONS && OverrideMaterials.Num()) { - GetStaticMesh()->ConditionalPostLoad(); if (GetStaticMesh()->HasValidRenderData() && GetStaticMesh()->RenderData->MaterialIndexToImportIndex.Num()) { @@ -2100,7 +2103,7 @@ void UStaticMeshComponent::GetUsedMaterials(TArray& OutMate int32 UStaticMeshComponent::GetBlueprintCreatedComponentIndex() const { int32 ComponentIndex = 0; - for(const auto& Component : GetOwner()->BlueprintCreatedComponents) + for (const UActorComponent* Component : GetOwner()->BlueprintCreatedComponents) { if(Component == this) { @@ -2120,7 +2123,8 @@ FActorComponentInstanceData* UStaticMeshComponent::GetComponentInstanceData() co StaticMeshInstanceData = new FStaticMeshComponentInstanceData(this); // Fill in info - StaticMeshInstanceData->CachedStaticLighting.Transform = ComponentToWorld; + const_cast(this)->ConditionalUpdateComponentToWorld(); // sadness + StaticMeshInstanceData->CachedStaticLighting.Transform = GetComponentTransform(); for (const FStaticMeshComponentLODInfo& LODDataEntry : LODData) { @@ -2169,7 +2173,7 @@ void UStaticMeshComponent::ApplyComponentInstanceData(FStaticMeshComponentInstan if (HasStaticLighting() && NumLODLightMaps > 0) { // See if data matches current state - if (StaticMeshInstanceData->CachedStaticLighting.Transform.Equals(ComponentToWorld, 1.e-3f)) + if (StaticMeshInstanceData->CachedStaticLighting.Transform.Equals(GetComponentTransform(), 1.e-3f)) { SetLODDataCount(NumLODLightMaps, NumLODLightMaps); @@ -2182,7 +2186,7 @@ void UStaticMeshComponent::ApplyComponentInstanceData(FStaticMeshComponentInstan { UE_LOG(LogStaticMesh, Warning, TEXT("Cached component instance data transform did not match! Discarding cached lighting data which will cause lighting to be unbuilt.\n%s\nCurrent: %s Cached: %s"), *GetPathName(), - *ComponentToWorld.ToString(), + *GetComponentTransform().ToString(), *StaticMeshInstanceData->CachedStaticLighting.Transform.ToString()); } } @@ -2214,15 +2218,15 @@ bool UStaticMeshComponent::DoCustomNavigableGeometryExport(FNavigableGeometryExp if (NavCollision->bHasConvexGeometry) { - const FVector Scale3D = ComponentToWorld.GetScale3D(); + const FVector Scale3D = GetComponentTransform().GetScale3D(); // if any of scales is 0 there's no point in exporting it if (!Scale3D.IsZero()) { GeomExport.ExportCustomMesh(NavCollision->ConvexCollision.VertexBuffer.GetData(), NavCollision->ConvexCollision.VertexBuffer.Num(), - NavCollision->ConvexCollision.IndexBuffer.GetData(), NavCollision->ConvexCollision.IndexBuffer.Num(), ComponentToWorld); + NavCollision->ConvexCollision.IndexBuffer.GetData(), NavCollision->ConvexCollision.IndexBuffer.Num(), GetComponentTransform()); GeomExport.ExportCustomMesh(NavCollision->TriMeshCollision.VertexBuffer.GetData(), NavCollision->TriMeshCollision.VertexBuffer.Num(), - NavCollision->TriMeshCollision.IndexBuffer.GetData(), NavCollision->TriMeshCollision.IndexBuffer.Num(), ComponentToWorld); + NavCollision->TriMeshCollision.IndexBuffer.GetData(), NavCollision->TriMeshCollision.IndexBuffer.Num(), GetComponentTransform()); } // regardless of above we don't want "regular" collision export for this mesh instance @@ -2287,7 +2291,7 @@ void UStaticMeshComponent::GetNavigationData(FNavigationRelevantData& Data) cons if (bExportAsObstacle) { - NavCollision->GetNavigationModifier(Data.Modifiers, ComponentToWorld); + NavCollision->GetNavigationModifier(Data.Modifiers, GetComponentTransform()); } } } @@ -2317,7 +2321,7 @@ bool UStaticMeshComponent::ComponentIsTouchingSelectionBox(const FBox& InSelBBox { int32 VertexIndex = Indices[FirstIndex + i]; FVector LocalPosition = LODModel.PositionVertexBuffer.VertexPosition(VertexIndex); - Vertex.Emplace(ComponentToWorld.TransformPosition(LocalPosition)); + Vertex.Emplace(GetComponentTransform().TransformPosition(LocalPosition)); } // Check if the triangle is colliding with the bounding box. @@ -2361,7 +2365,7 @@ bool UStaticMeshComponent::ComponentIsTouchingSelectionFrustum(const FConvexVolu for (uint32 VertexIndex = 0; VertexIndex < NumVertices; ++VertexIndex) { const FVector& LocalPosition = LODModel.PositionVertexBuffer.VertexPosition(VertexIndex); - const FVector WorldPosition = ComponentToWorld.TransformPosition(LocalPosition); + const FVector WorldPosition = GetComponentTransform().TransformPosition(LocalPosition); bool bLocationIntersected = InFrustum.IntersectSphere(WorldPosition, 0.0f); if (bLocationIntersected && !bMustEncompassEntireComponent) { diff --git a/Engine/Source/Runtime/Engine/Private/Components/TextRenderComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/TextRenderComponent.cpp index 6690a784a16c..5f6fc787ddca 100644 --- a/Engine/Source/Runtime/Engine/Private/Components/TextRenderComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/Components/TextRenderComponent.cpp @@ -711,7 +711,7 @@ FTextRenderSceneProxy::FTextRenderSceneProxy( UTextRenderComponent* Component) : TextMaterial = EffectiveMaterial; MaterialRelevance |= TextMaterial->GetMaterial()->GetRelevance(GetScene().GetFeatureLevel()); - if (TextMaterial && Font && Font->FontCacheType == EFontCacheType::Offline) + if (Font && Font->FontCacheType == EFontCacheType::Offline) { FontMIDs = FTextRenderComponentMIDCache::Get().GetMIDData(TextMaterial, Font); } @@ -1230,7 +1230,7 @@ FMatrix UTextRenderComponent::GetRenderMatrix() const const float VerticalAlignmentOffset = -ComputeVerticalAlignmentOffset(SizeY, VerticalAlignment, FirstLineHeight); VerticalTransform = VerticalTransform.ConcatTranslation(FVector(0.f, 0.f, VerticalAlignmentOffset)); - return VerticalTransform * ComponentToWorld.ToMatrixWithScale(); + return VerticalTransform * GetComponentTransform().ToMatrixWithScale(); } return UPrimitiveComponent::GetRenderMatrix(); @@ -1329,7 +1329,7 @@ FVector UTextRenderComponent::GetTextLocalSize() const FVector UTextRenderComponent::GetTextWorldSize() const { - const FBoxSphereBounds TextBounds = CalcBounds(ComponentToWorld); + const FBoxSphereBounds TextBounds = CalcBounds(GetComponentTransform()); return TextBounds.GetBox().GetSize(); } @@ -1381,11 +1381,4 @@ void UTextRenderComponent::ShutdownMIDCache() FTextRenderComponentMIDCache::Shutdown(); } -/** Returns TextRender subobject **/ -UTextRenderComponent* ATextRenderActor::GetTextRender() const { return TextRender; } -#if WITH_EDITORONLY_DATA -/** Returns SpriteComponent subobject **/ -UBillboardComponent* ATextRenderActor::GetSpriteComponent() const { return SpriteComponent; } -#endif - #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Runtime/Engine/Private/Controller.cpp b/Engine/Source/Runtime/Engine/Private/Controller.cpp index 38cfebf39bfd..22e980067b18 100644 --- a/Engine/Source/Runtime/Engine/Private/Controller.cpp +++ b/Engine/Source/Runtime/Engine/Private/Controller.cpp @@ -223,8 +223,7 @@ bool AController::LineOfSightTo(const AActor* Other, FVector ViewPoint, bool bAl GetActorEyesViewPoint(ViewPoint, ViewRotation); } - static FName NAME_LineOfSight = FName(TEXT("LineOfSight")); - FCollisionQueryParams CollisionParms(NAME_LineOfSight, true, Other); + FCollisionQueryParams CollisionParms(SCENE_QUERY_STAT(LineOfSight), true, Other); CollisionParms.AddIgnoredActor(this->GetPawn()); FVector TargetLocation = Other->GetTargetLocation(Pawn); bool bHit = GetWorld()->LineTraceTestByChannel(ViewPoint, TargetLocation, ECC_Visibility, CollisionParms); @@ -346,6 +345,8 @@ void AController::Reset() StartSpot = NULL; } +/// @cond DOXYGEN_WARNINGS + void AController::ClientSetLocation_Implementation( FVector NewLocation, FRotator NewRotation ) { ClientSetRotation(NewRotation); @@ -364,6 +365,8 @@ void AController::ClientSetRotation_Implementation( FRotator NewRotation, bool b } } +/// @endcond + void AController::RemovePawnTickDependency(APawn* InOldPawn) { if (InOldPawn != NULL) @@ -680,7 +683,4 @@ void AController::GetLifetimeReplicatedProps( TArray< FLifetimeProperty > & OutL DOREPLIFETIME_CONDITION_NOTIFY(AController, Pawn, COND_None, REPNOTIFY_Always); } -/** Returns TransformComponent subobject **/ -USceneComponent* AController::GetTransformComponent() const { return TransformComponent; } - #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Runtime/Engine/Private/CoreSettings.cpp b/Engine/Source/Runtime/Engine/Private/CoreSettings.cpp index 9f54d029523d..8ef2392a94fe 100644 --- a/Engine/Source/Runtime/Engine/Private/CoreSettings.cpp +++ b/Engine/Source/Runtime/Engine/Private/CoreSettings.cpp @@ -82,7 +82,6 @@ UStreamingSettings::UStreamingSettings() TimeLimitExceededMultiplier = 1.5f; TimeLimitExceededMinTime = 0.005f; MinBulkDataSizeForAsyncLoading = 131072; - AsyncIOBandwidthLimit = 0; UseBackgroundLevelStreaming = true; AsyncLoadingTimeLimit = 5.0f; AsyncLoadingUseFullTimeLimit = true; diff --git a/Engine/Source/Runtime/Engine/Private/CsvProfiler.cpp b/Engine/Source/Runtime/Engine/Private/CsvProfiler.cpp new file mode 100644 index 000000000000..23a1078f0769 --- /dev/null +++ b/Engine/Source/Runtime/Engine/Private/CsvProfiler.cpp @@ -0,0 +1,794 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +/** +* +* A lightweight single-threaded CSV profiler which can be used for profiling in Test/Shipping builds +*/ + +#include "CsvProfiler.h" +#include "CoreGlobals.h" +#include "HAL/RunnableThread.h" +#include "HAL/ThreadManager.h" +#include "HAL/FileManager.h" +#include "HAL/PlatformProcess.h" +#include "Misc/Paths.h" +#include "Misc/CommandLine.h" +#include "Misc/ScopeLock.h" +#include "RenderingThread.h" +#include "CoreDelegates.h" +#include "RenderCore.h" +#include "Modules/ModuleManager.h" +#include "EngineGlobals.h" + +#if CSV_PROFILER + +#define RECORD_TIMESTAMPS 1 + +DEFINE_LOG_CATEGORY_STATIC(LogCsvProfiler, Log, All); + +#define USE_THREAD_LOCAL 0 + +FCsvProfiler* FCsvProfiler::Instance = nullptr; + +static void HandleCSVProfileCommand(const TArray& Args) +{ + if (Args.Num() < 1) + { + return; + } + FString Param = Args[0]; + if (Param == TEXT("START")) + { + FCsvProfiler::Get()->BeginCapture(); + } + else if (Param == TEXT("STOP")) + { + FCsvProfiler::Get()->EndCapture(); + } + else + { + int32 CaptureFrames = 0; + if (FParse::Value(*Param, TEXT("FRAMES="), CaptureFrames)) + { + FCsvProfiler::Get()->BeginCapture(CaptureFrames); + } + } +} + +static void CsvProfilerBeginFrame() +{ + FCsvProfiler::Get()->BeginFrame(); +} + +static void CsvProfilerEndFrame() +{ + FCsvProfiler::Get()->EndFrame(); +} + + +static FAutoConsoleCommand HandleCSVProfileCmd( + TEXT("CsvProfile"), + TEXT("Starts or stops Csv Profiles"), + FConsoleCommandWithArgsDelegate::CreateStatic(&HandleCSVProfileCommand) +); + + +//----------------------------------------------------------------------------- +// TSingleProducerSingleConsumerList : fast lock-free single producer/single +// consumer list implementation. +// Uses a linked list of blocks for allocations. Note that one block will always +// leak, because removing the tail cannot be done without locking +//----------------------------------------------------------------------------- +template +class TSingleProducerSingleConsumerList +{ + // A block of BlockSize entries + struct FBlock + { + FBlock() : Next(nullptr) + { + } + T Entries[BlockSize]; + FBlock* Next; + }; + + //MS_ALIGN(PLATFORM_CACHE_LINE_SIZE) + struct FCacheLineAlignedCounter + { + #define NUM_PADDING_WORDS ( PLATFORM_CACHE_LINE_SIZE/4 - 2 ) + uint32 Pad[NUM_PADDING_WORDS]; + + volatile uint64 Value; + }; + //GCC_ALIGN(PLATFORM_CACHE_LINE_SIZE); + +public: + TSingleProducerSingleConsumerList() + { + HeadBlock = nullptr; + TailBlock = nullptr; +#if DO_CHECK + bElementReserved = false; +#endif + Counter.Value = 0; + ConsumerThreadLastReadIndex = 0; + } + + // Reserve an element prior to writing it + // Must be called from the Producer thread + T* ReserveElement() + { +#if DO_CHECK + check(!bElementReserved); + bElementReserved = true; +#endif + uint32 TailBlockSize = Counter.Value % BlockSize; + if (TailBlockSize == 0) + { + AddTailBlock(); + } + return &TailBlock->Entries[TailBlockSize]; + } + + // Commit an element after writing it + // Must be called from the Producer thread after a call to ReserveElement + void CommitElement() + { +#if DO_CHECK + check(bElementReserved); + bElementReserved = false; +#endif + FPlatformMisc::MemoryBarrier(); + + // Keep track of the count of all the elements we ever committed. This value is never reset, even on a PopAll + Counter.Value++; + } + + // Called from the consumer thread + void PopAll(TArray& ElementsOut) + { + volatile uint64 CurrentCounterValue = Counter.Value; + FPlatformMisc::MemoryBarrier(); + + uint32 ElementCount = uint32( CurrentCounterValue - ConsumerThreadLastReadIndex ); + ConsumerThreadLastReadIndex = CurrentCounterValue; + ElementsOut.AddUninitialized(ElementCount); + + uint32 IndexInBlock = 0; + for (uint32 i = 0; i < ElementCount; i++) + { + // if this block is full and it's completed, retire it and move to the next block (update the head) + if (i > 0 && ( i % BlockSize == 0) ) + { + // Both threads are done with the head block now, so we can safely delete it + // Note that the Producer thread only reads/writes to the HeadBlock pointer on startup, so it's safe to update it at this point + FBlock* PrevBlock = HeadBlock; + HeadBlock = HeadBlock->Next; + IndexInBlock = 0; + delete PrevBlock; + } + check(HeadBlock != nullptr); + ElementsOut[i] = HeadBlock->Entries[IndexInBlock++]; + } + } +private: + void AddTailBlock() + { + FBlock* NewTail = new FBlock; + if (TailBlock == nullptr) + { + // This must only happen on startup, otherwise it's not thread-safe + check(Counter.Value == 0); + check(HeadBlock == nullptr); + HeadBlock = NewTail; + } + else + { + TailBlock->Next = NewTail; + } + TailBlock = NewTail; + } + + + FBlock* HeadBlock; + FBlock* TailBlock; + + FCacheLineAlignedCounter Counter; + + // Used from the consumer thread + uint64 ConsumerThreadLastReadIndex; + +#if DO_CHECK + bool bElementReserved; +#endif + +}; + +//----------------------------------------------------------------------------- +// FCsvTimingMarker : records timestamps. Uses StatName pointer as a unique ID +//----------------------------------------------------------------------------- +namespace ECsvMarkerType +{ + enum Type + { + TimestampStart, + TimestampEnd, + CustomStat + }; +}; + +struct FCsvTimingMarker +{ + const char* StatName; + uint64 Timestamp; + float CustomValue; + ECsvMarkerType::Type MarkerType; +}; + +//----------------------------------------------------------------------------- +// FCsvProfilerThread class : records all timings for a particular thread +//----------------------------------------------------------------------------- +class FCsvProfilerThread +{ +public: + FCsvProfilerThread( uint32 InThreadId ) : ThreadId(InThreadId) + { + CurrentCaptureStartCycles = FPlatformTime::Cycles64(); + } + + void FlushResults(TArray& OutMarkers ) + { + uint64 ValidTimestampStart = CurrentCaptureStartCycles; + CurrentCaptureStartCycles = FPlatformTime::Cycles64(); + + TimingMarkers.PopAll(OutMarkers); + } + + void AddTimestamp(const char* StatName, const bool bBegin) + { + // TODO: fast pool allocator for timing markers + FCsvTimingMarker* Marker = TimingMarkers.ReserveElement(); + + Marker->MarkerType = bBegin ? ECsvMarkerType::TimestampStart : ECsvMarkerType::TimestampEnd; + Marker->StatName = StatName; + Marker->CustomValue = 0.0f; + Marker->Timestamp = FPlatformTime::Cycles64(); + + TimingMarkers.CommitElement(); + } + + void AddCustomStat(const char* StatName, const float Value ) + { + FCsvTimingMarker* Marker = TimingMarkers.ReserveElement(); + + Marker->MarkerType = ECsvMarkerType::CustomStat; + Marker->StatName = StatName; + Marker->CustomValue = Value; + Marker->Timestamp = FPlatformTime::Cycles64(); + + TimingMarkers.CommitElement(); + } + + uint32 ThreadId; + uint64 CurrentCaptureStartCycles; + TSingleProducerSingleConsumerList TimingMarkers; +}; + + +FCsvProfiler* FCsvProfiler::Get() +{ + if (Instance == nullptr) + { + Instance = new FCsvProfiler; + } + return Instance; +} + +FCsvProfiler::FCsvProfiler() + : NumFramesToCapture(-1) + , CaptureFrameNumber(0) + , bRequestStartCapture(false) + , bRequestStopCapture(false) + , bCapturing(false) +{ + check(IsInGameThread()); + GetProfilerThread(); + + FCoreDelegates::OnBeginFrame.AddStatic(CsvProfilerBeginFrame); + FCoreDelegates::OnEndFrame.AddStatic(CsvProfilerEndFrame); + +} + +/** Per-frame update */ +void FCsvProfiler::BeginFrame() +{ + check(IsInGameThread()); + if (bRequestStartCapture) + { + bCapturing = true; + bRequestStartCapture = false; + + UE_LOG(LogCsvProfiler, Display, TEXT("Capture Starting")); + + LastEndFrameTimestamp = FPlatformTime::Cycles64(); + } + + if (bCapturing) + { + FrameBeginTimestamps.Add(FPlatformTime::Cycles64()); + } + + ENQUEUE_UNIQUE_RENDER_COMMAND( + CSVBeginFrame, + { + FCsvProfiler::Get()->BeginFrameRT(); + }); + +} + +void FCsvProfiler::EndFrame() +{ + check(IsInGameThread()); + + ENQUEUE_UNIQUE_RENDER_COMMAND( + CSVEndFrame, + { + FCsvProfiler::Get()->EndFrameRT(); + }); + + if (!bCapturing) + { + return; + } + + + // CSV profiler + { + CSV_CUSTOM_STAT(RenderThreadTime, FPlatformTime::ToMilliseconds(GRenderThreadTime)); + CSV_CUSTOM_STAT(GameThreadTime, FPlatformTime::ToMilliseconds(GGameThreadTime)); + CSV_CUSTOM_STAT(GPUTime, FPlatformTime::ToMilliseconds(GGPUFrameTime)); + FPlatformMemoryStats MemoryStats = FPlatformMemory::GetStats(); + float PhysicalMBFree = float(MemoryStats.AvailablePhysical / 1024) / 1024.0f; + CSV_CUSTOM_STAT(MemoryFreeMB, PhysicalMBFree); + } + + { + // Record the frametime (measured since the last EndFrame) + uint64 CurrentTimeStamp = FPlatformTime::Cycles64(); + uint64 ElapsedCycles = CurrentTimeStamp - LastEndFrameTimestamp; + float ElapsedMs = FPlatformTime::ToMilliseconds64(ElapsedCycles); + CSV_CUSTOM_STAT(FrameTime, ElapsedMs); + LastEndFrameTimestamp = CurrentTimeStamp; + } + + if (NumFramesToCapture >= 0) + { + NumFramesToCapture--; + if (NumFramesToCapture == 0) + { + bRequestStopCapture = true; + } + } + + if (bRequestStopCapture) + { + FScopeLock Lock(&GetResultsLock); + + bCapturing = false; + + // We'd need to move this into engine to do this: + FlushRenderingCommands(); + + // Sleep for a bit to give the threads a chance to finish writing stats + // Doesn't matter massively if they haven't, since we're using a lock-free queue + //FPlatformProcess::Sleep(0.002f); + + WriteCaptureToFile(); + + FrameBeginTimestamps.Empty(); + FrameBeginTimestampsRT.Empty(); + + bRequestStopCapture = false; + } + + CaptureFrameNumber++; +} + + +/** Per-frame update */ +void FCsvProfiler::BeginFrameRT() +{ + check(IsInRenderingThread()); + if (bCapturing) + { + // Mark where the renderthread frames begin + FScopeLock Lock(&GetResultsLock); + FrameBeginTimestampsRT.Add(FPlatformTime::Cycles64()); + } +} + +void FCsvProfiler::EndFrameRT() +{ + check(IsInRenderingThread()); +} + + +/** Final cleanup */ +void FCsvProfiler::Release() +{ + +} + +void FCsvProfiler::BeginCapture(int InNumFramesToCapture) +{ + NumFramesToCapture = InNumFramesToCapture; + bRequestStartCapture = true; +} + +void FCsvProfiler::EndCapture() +{ + bRequestStopCapture = true; +} + +class FCsvColumn +{ +public: + FCsvColumn(const FString& InName) : Name(InName) {} + + float GetValue(uint32 Row) + { + if (Row < (uint32)Values.Num()) + { + return Values[Row]; + } + return 0.0f; + } + + void SetValue(uint32 Row, float Value) + { + // Grow the column if needed (pad with zeroes) + if (Row >= (uint32)Values.Num()) + { + Values.Reserve((int32)Row + 1); + int32 GrowBy = (int32)Row + 1 - Values.Num(); + for (int i = 0; i < GrowBy; i++) + { + Values.Add(0.0f); + } + } + Values[Row] = Value; + } + + FString Name; + TArray Values; +}; + +class FCSVTable +{ +public: + FCSVTable() : NumRows(0) + { + } + + ~FCSVTable() + { + for (int i = 0; i < Columns.Num(); i++) + { + delete Columns[i]; + } + } + + uint32 AddColumn(const FString& ColumnName) + { + Columns.Add(new FCsvColumn(ColumnName)); + return (uint32)Columns.Num() - 1; + } + + void SetValue(uint32 Row, uint32 Column, float Value) + { + if (Column < (uint32)Columns.Num()) + { + Columns[Column]->SetValue(Row, Value); + } + + if (Row >= NumRows) + { + NumRows = Row + 1; + } + + } + + void AccumulateValue(uint32 Row, uint32 Column, float Value) + { + if (Column < (uint32)Columns.Num()) + { + Columns[Column]->SetValue(Row, Columns[Column]->GetValue(Row) + Value); + } + if (Row >= NumRows) + { + NumRows = Row + 1; + } + } + + void WriteToFile(const FString& FileName) + { + char Comma = ','; + char NewLine = '\n'; + FArchive* OutputFile = IFileManager::Get().CreateDebugFileWriter(*FileName); + for (int c = 0; c< Columns.Num(); c++) + { + FCsvColumn& Column = *Columns[c]; + + auto AnsiStr = StringCast(*Column.Name); + OutputFile->Serialize( (void*)AnsiStr.Get(), AnsiStr.Length() ); + if (c < Columns.Num() - 1) + { + OutputFile->Serialize( (void*)&Comma, sizeof(ANSICHAR)); + } + } + OutputFile->Serialize((void*)&NewLine, sizeof(ANSICHAR)); + + // Write the data + char StringBuffer[256]; + for (int r = 0; r < (int)NumRows; r++) + { + for (int c = 0; c < Columns.Num(); c++) + { + FCsvColumn& Column = *Columns[c]; + float Value = Column.GetValue(r); + FCStringAnsi::Snprintf(StringBuffer, 256, "%.4f", Value); + OutputFile->Serialize((void*)StringBuffer, sizeof(ANSICHAR)*FCStringAnsi::Strlen(StringBuffer)); + + if (c < Columns.Num() - 1) + { + OutputFile->Serialize((void*)&Comma, sizeof(ANSICHAR)); + } + } + OutputFile->Serialize((void*)&NewLine, sizeof(ANSICHAR)); + } + + OutputFile->Close(); + } +private: + TArray Columns; + uint32 NumRows; +}; + +void FCsvProfiler::WriteCaptureToFile() +{ + + // Write the results out to a file + FString Filename = FString::Printf(TEXT("Profile(%s)"), *FDateTime::Now().ToString(TEXT("%Y%m%d_%H%M%S"))); + FString CSVRootPath = FPaths::ProfilingDir() + TEXT("CSV/"); + FString OutputFilename = CSVRootPath + Filename + TEXT(".csv"); + FCSVTable Csv; + + for (int t = 0; t < ProfilerThreads.Num(); t++) + { + FCsvProfilerThread* CurrentThread = ProfilerThreads[t]; + + // Get the thread name + FString ThreadName = FThreadManager::Get().GetThreadName(CurrentThread->ThreadId); + if (CurrentThread->ThreadId == GGameThreadId) + { + ThreadName = TEXT("GameThread"); + } + else if (CurrentThread->ThreadId == GRenderThreadId ) + { + ThreadName = TEXT("RenderThread"); + } + + // Read the results + TArray ThreadMarkers; + CurrentThread->FlushResults(ThreadMarkers); + + TMap StatNameToColumnIndex; + TArray MarkerFrameIndices; + TArray MarkerColumnIndices; + + FString Slash(TEXT("/")); + + MarkerFrameIndices.Reserve(ThreadMarkers.Num()); + MarkerColumnIndices.Reserve(ThreadMarkers.Num()); + + bool bUseRenderthreadTimeline = CurrentThread->ThreadId == GRenderThreadId; + const TArray& FrameBeginTimestampsForThread = bUseRenderthreadTimeline ? FrameBeginTimestampsRT : FrameBeginTimestamps; + + // Create a column in the CSV for each unique stat name + //static bool bCreateEndToEndMarkers = false; + uint32 CurrentFrameIndex = 0; + for (int i = 0; i < ThreadMarkers.Num(); i++) + { + FCsvTimingMarker& Marker = ThreadMarkers[i]; + FString StatName = (TCHAR*)StringCast((Marker.StatName)).Get(); + uint32 ColumnIndex = 0; + uint32* IndexPtr = StatNameToColumnIndex.Find(StatName); + + if (IndexPtr) + { + ColumnIndex = *IndexPtr; + } + else + { + FString ColumnName = (Marker.MarkerType == ECsvMarkerType::CustomStat) ? StatName : ThreadName + Slash + StatName; + ColumnIndex = Csv.AddColumn(ColumnName); + StatNameToColumnIndex.Add(StatName, ColumnIndex); +#if 0 + if (bCreateEndToEndMarkers && Marker.MarkerType != ECsvMarkerType::CustomStat) + { + // Add another column for the end to end markers + FString ColumnName2 = ThreadName + Slash + TEXT("EndToEnd_") + StatName; + Csv.AddColumn(ColumnName2); + } +#endif + } + MarkerColumnIndices.Add(ColumnIndex); + + while (CurrentFrameIndex + 1 < (uint32)FrameBeginTimestampsForThread.Num() && Marker.Timestamp > FrameBeginTimestampsForThread[CurrentFrameIndex + 1]) + { + CurrentFrameIndex++; + } + MarkerFrameIndices.Add(CurrentFrameIndex); + } + + // Process the markers + TArray MarkerStack; + for (int i = 0; i < ThreadMarkers.Num(); i++) + { + FCsvTimingMarker& Marker = ThreadMarkers[i]; + uint32 ColumnIndex = MarkerColumnIndices[i]; + uint32 FrameIndex = MarkerFrameIndices[i]; + + switch (Marker.MarkerType) + { + case ECsvMarkerType::TimestampStart: + { + MarkerStack.Push(&Marker); + } + break; + case ECsvMarkerType::TimestampEnd: + { + // Markers might not match up if they were truncated mid-frame, so we need to be robust to that + if (MarkerStack.Num() > 0) + { + FCsvTimingMarker* StartMarker = MarkerStack.Pop(); + if (Marker.Timestamp > StartMarker->Timestamp) + { + uint64 ElapsedCycles = Marker.Timestamp - StartMarker->Timestamp; + float ElapsedMs = FPlatformTime::ToMilliseconds64(ElapsedCycles); + + // Add the elapsed time to the table entry for this frame/stat + Csv.AccumulateValue(FrameIndex, ColumnIndex, ElapsedMs); + } + } + } + break; + case ECsvMarkerType::CustomStat: + { + // Add the elapsed time to the table entry for this frame/stat + Csv.AccumulateValue(FrameIndex, ColumnIndex, Marker.CustomValue); + } + break; + } + +#if 0 + if (bCreateEndToEndMarkers) + { + // Array sized by num CSV Columns + // Track frame of each + // Process the markers + TArray MarkerStack; + for (int i = 0; i < ThreadMarkers.Num(); i++) + { + FCsvTimingMarker& Marker = ThreadMarkers[i]; + uint32 ColumnIndex = MarkerColumnIndices[i]+1; + uint32 FrameIndex = MarkerFrameIndices[i]; + + switch (Marker.MarkerType) + { + case ECsvMarkerType::TimestampStart: + { + MarkerStack.Push(&Marker); + } + break; + case ECsvMarkerType::TimestampEnd: + { + // Markers might not match up if they were truncated mid-frame, so we need to be robust to that + if (MarkerStack.Num() > 0) + { + FCsvTimingMarker* StartMarker = MarkerStack.Pop(); + if (Marker.Timestamp > StartMarker->Timestamp) + { + uint64 ElapsedCycles = Marker.Timestamp - StartMarker->Timestamp; + float ElapsedMs = FPlatformTime::ToMilliseconds64(ElapsedCycles); + + // Add the elapsed time to the table entry for this frame/stat + Csv.AccumulateValue(FrameIndex, ColumnIndex, ElapsedMs); + } + } + } + break; + } + } +#endif + + } + + + } // Thread loop + + UE_LOG(LogCsvProfiler, Display, TEXT("Capture Ended. Writing CSV to file : %s"), *OutputFilename); + + Csv.WriteToFile(OutputFilename); +} + + +// Create the TLS profiler thread lazily +FCsvProfilerThread* FCsvProfiler::GetProfilerThread() +{ +#if USE_THREAD_LOCAL == 1 + static thread_local FCsvProfilerThread* ProfilerThread = nullptr; +#else + static uint32 TlsSlot = FPlatformTLS::AllocTlsSlot(); + FCsvProfilerThread* ProfilerThread = (FCsvProfilerThread*)FPlatformTLS::GetTlsValue(TlsSlot); +#endif + if (!ProfilerThread) + { + ProfilerThread = new FCsvProfilerThread(FPlatformTLS::GetCurrentThreadId()); +#if USE_THREAD_LOCAL == 0 + FPlatformTLS::SetTlsValue(TlsSlot, ProfilerThread); +#endif + { + FScopeLock Lock(&GetResultsLock); + ProfilerThreads.Add(ProfilerThread); + } + } + return ProfilerThread; +} + +/** Push/pop events */ +void FCsvProfiler::BeginStat(const char * StatName) +{ +#if RECORD_TIMESTAMPS + if (!bCapturing) + { + return; + } + GetProfilerThread()->AddTimestamp(StatName, true); +#endif +} + +void FCsvProfiler::EndStat(const char * StatName) +{ +#if RECORD_TIMESTAMPS + if (!bCapturing) + { + return; + } + GetProfilerThread()->AddTimestamp(StatName, false); +#endif +} + +void FCsvProfiler::RecordCustomStat(const char * StatName, float Value) +{ + if (!bCapturing) + { + return; + } + GetProfilerThread()->AddCustomStat(StatName, Value); +} + + +void FCsvProfiler::Init() +{ + int32 NumCsvFrames = 0; + if (FParse::Value(FCommandLine::Get(), TEXT("csvCaptureFrames="), NumCsvFrames)) + { + check(IsInGameThread()); + BeginCapture(NumCsvFrames); + BeginFrame(); + } +} + + +#endif // CSV_PROFILER \ No newline at end of file diff --git a/Engine/Source/Runtime/Engine/Private/DataChannel.cpp b/Engine/Source/Runtime/Engine/Private/DataChannel.cpp index 550bd730525f..033727dcbeab 100644 --- a/Engine/Source/Runtime/Engine/Private/DataChannel.cpp +++ b/Engine/Source/Runtime/Engine/Private/DataChannel.cpp @@ -603,7 +603,8 @@ bool UChannel::ReceivedNextBunch( FInBunch & Bunch, bool & bOutSkipAck ) { if ( ChType != CHTYPE_Voice ) // Voice channels can open from both side simultaneously, so ignore this logic until we resolve this { - check( !OpenedLocally ); // If we opened the channel, we shouldn't be receiving bOpen commands from the other side + // If we opened the channel, we shouldn't be receiving bOpen commands from the other side + checkf(!OpenedLocally, TEXT("Received channel open command for channel that was already opened locally. %s"), *Describe()); check( OpenPacketId.First == INDEX_NONE ); // This should be the first and only assignment of the packet range (we should only receive one bOpen bunch) check( OpenPacketId.Last == INDEX_NONE ); // This should be the first and only assignment of the packet range (we should only receive one bOpen bunch) } @@ -1646,7 +1647,7 @@ void UActorChannel::DestroyActorAndComponents() Connection->Driver->RepChangedPropertyTrackerMap.Remove( SubObject ); } - Actor->OnSubobjectDestroyFromReplication(SubObject); + Actor->OnSubobjectDestroyFromReplication(SubObject); //-V595 SubObject->PreDestroyFromReplication(); SubObject->MarkPendingKill(); } @@ -2462,7 +2463,7 @@ bool UActorChannel::ReplicateActor() RepFlags.bNetSimulated = ( Actor->GetRemoteRole() == ROLE_SimulatedProxy ); RepFlags.bRepPhysics = Actor->ReplicatedMovement.bRepPhysics; RepFlags.bReplay = ActorWorld && (ActorWorld->DemoNetDriver == Connection->GetDriver()); - RepFlags.bNetInitial = RepFlags.bNetInitial; + //RepFlags.bNetInitial = RepFlags.bNetInitial; UE_LOG(LogNetTraffic, Log, TEXT("Replicate %s, bNetInitial: %d, bNetOwner: %d"), *Actor->GetName(), RepFlags.bNetInitial, RepFlags.bNetOwner ); diff --git a/Engine/Source/Runtime/Engine/Private/DebugCameraController.cpp b/Engine/Source/Runtime/Engine/Private/DebugCameraController.cpp index 064b0ce5d4c1..3cc9e65316dc 100644 --- a/Engine/Source/Runtime/Engine/Private/DebugCameraController.cpp +++ b/Engine/Source/Runtime/Engine/Private/DebugCameraController.cpp @@ -252,11 +252,11 @@ FString ADebugCameraController::ConsoleCommand(const FString& Cmd,bool bWriteToL return TEXT(""); } -void ADebugCameraController::UpdateHiddenComponents(const FVector& ViewLocation,TSet& HiddenComponents) +void ADebugCameraController::UpdateHiddenComponents(const FVector& ViewLocation,TSet& HiddenComponentsOut) { if (OriginalControllerRef != NULL) { - OriginalControllerRef->UpdateHiddenComponents(ViewLocation,HiddenComponents); + OriginalControllerRef->UpdateHiddenComponents(ViewLocation, HiddenComponentsOut); } } @@ -447,7 +447,7 @@ void ADebugCameraController::SelectTargetedObject() GetPlayerViewPoint(CamLoc, CamRot); FHitResult Hit; - FCollisionQueryParams TraceParams(NAME_None, true, this); + FCollisionQueryParams TraceParams(NAME_None, FCollisionQueryParams::GetUnknownStatId(), true, this); bool const bHit = GetWorld()->LineTraceSingleByChannel(Hit, CamLoc, CamRot.Vector() * 5000.f * 20.f + CamLoc, ECC_Pawn, TraceParams); if( bHit) { diff --git a/Engine/Source/Runtime/Engine/Private/DebugCameraHUD.cpp b/Engine/Source/Runtime/Engine/Private/DebugCameraHUD.cpp index 3489a20798a4..05754c4ae94b 100644 --- a/Engine/Source/Runtime/Engine/Private/DebugCameraHUD.cpp +++ b/Engine/Source/Runtime/Engine/Private/DebugCameraHUD.cpp @@ -110,7 +110,7 @@ void ADebugCameraHUD::PostRender() bTraceComplex = CVarDebugCameraTraceComplex.GetValueOnGameThread() != 0; #endif - FCollisionQueryParams TraceParams(NAME_None, bTraceComplex, this); + FCollisionQueryParams TraceParams(NAME_None, FCollisionQueryParams::GetUnknownStatId(), bTraceComplex, this); FHitResult Hit; bool bHit = GetWorld()->LineTraceSingleByChannel(Hit, CamLoc, CamRot.Vector() * 100000.f + CamLoc, ECC_Pawn, TraceParams); diff --git a/Engine/Source/Runtime/Engine/Private/DecalActor.cpp b/Engine/Source/Runtime/Engine/Private/DecalActor.cpp index 9f985bb1ced3..2ba0202fc0fd 100644 --- a/Engine/Source/Runtime/Engine/Private/DecalActor.cpp +++ b/Engine/Source/Runtime/Engine/Private/DecalActor.cpp @@ -191,11 +191,3 @@ void ADecalActor::PostLoad() #endif } -/** Returns Decal subobject **/ -UDecalComponent* ADecalActor::GetDecal() const { return Decal; } -#if WITH_EDITORONLY_DATA -/** Returns ArrowComponent subobject **/ -UArrowComponent* ADecalActor::GetArrowComponent() const { return ArrowComponent; } -/** Returns SpriteComponent subobject **/ -UBillboardComponent* ADecalActor::GetSpriteComponent() const { return SpriteComponent; } -#endif diff --git a/Engine/Source/Runtime/Engine/Private/DefaultPawn.cpp b/Engine/Source/Runtime/Engine/Private/DefaultPawn.cpp index db1cac91d133..abb2b3308fcd 100644 --- a/Engine/Source/Runtime/Engine/Private/DefaultPawn.cpp +++ b/Engine/Source/Runtime/Engine/Private/DefaultPawn.cpp @@ -203,7 +203,3 @@ UPawnMovementComponent* ADefaultPawn::GetMovementComponent() const return MovementComponent; } -/** Returns CollisionComponent subobject **/ -USphereComponent* ADefaultPawn::GetCollisionComponent() const { return CollisionComponent; } -/** Returns MeshComponent subobject **/ -UStaticMeshComponent* ADefaultPawn::GetMeshComponent() const { return MeshComponent; } diff --git a/Engine/Source/Runtime/Engine/Private/DemoNetDriver.cpp b/Engine/Source/Runtime/Engine/Private/DemoNetDriver.cpp index d73776dcb886..069215453b78 100644 --- a/Engine/Source/Runtime/Engine/Private/DemoNetDriver.cpp +++ b/Engine/Source/Runtime/Engine/Private/DemoNetDriver.cpp @@ -379,7 +379,6 @@ bool UDemoNetDriver::InitBase( bool bInitAsClient, FNetworkNotify* InNotify, con ViewerOverride = nullptr; bPrioritizeActors = false; bPauseRecording = false; - CheckpointSaveMaxMSPerFrame = 0.0f; if ( RelevantTimeout == 0.0f ) { @@ -1050,42 +1049,39 @@ static bool DemoReplicateActor( AActor* Actor, UNetConnection* Connection, APlay bool bDidReplicateActor = false; - if ( Actor != NULL ) + // Handle role swapping if this is a client-recorded replay. + FScopedActorRoleSwap RoleSwap(Actor); + + if ((Actor->GetRemoteRole() != ROLE_None || Actor->bTearOff) && (Actor == Connection->PlayerController || Cast< APlayerController >(Actor) == NULL)) { - // Handle role swapping if this is a client-recorded replay. - FScopedActorRoleSwap RoleSwap(Actor); + const bool bShouldHaveChannel = + Actor->bRelevantForNetworkReplays && + !Actor->bTearOff && + (!Actor->IsNetStartupActor() || Connection->ClientHasInitializedLevelFor(Actor)); - if ( (Actor->GetRemoteRole() != ROLE_None || Actor->bTearOff) && ( Actor == Connection->PlayerController || Cast< APlayerController >( Actor ) == NULL ) ) + UActorChannel* Channel = Connection->ActorChannels.FindRef(Actor); + + if (bShouldHaveChannel && Channel == NULL) { - const bool bShouldHaveChannel = - Actor->bRelevantForNetworkReplays && - !Actor->bTearOff && - (!Actor->IsNetStartupActor() || Connection->ClientHasInitializedLevelFor(Actor)); - - UActorChannel* Channel = Connection->ActorChannels.FindRef(Actor); - - if (bShouldHaveChannel && Channel == NULL) + // Create a new channel for this actor. + Channel = (UActorChannel*)Connection->CreateChannel(CHTYPE_Actor, 1); + if (Channel != NULL) { - // Create a new channel for this actor. - Channel = (UActorChannel*)Connection->CreateChannel(CHTYPE_Actor, 1); - if (Channel != NULL) - { - Channel->SetChannelActor(Actor); - } + Channel->SetChannelActor(Actor); } + } - if (Channel != NULL && !Channel->Closing) + if (Channel != NULL && !Channel->Closing) + { + // Send it out! + bDidReplicateActor = Channel->ReplicateActor(); + + // Close the channel if this actor shouldn't have one + if (!bShouldHaveChannel) { - // Send it out! - bDidReplicateActor = Channel->ReplicateActor(); - - // Close the channel if this actor shouldn't have one - if (!bShouldHaveChannel) + if (!Connection->bResendAllDataSinceOpen) // Don't close the channel if we're forcing them to re-open for checkpoints { - if (!Connection->bResendAllDataSinceOpen) // Don't close the channel if we're forcing them to re-open for checkpoints - { - Channel->Close(); - } + Channel->Close(); } } } @@ -2401,7 +2397,7 @@ void UDemoNetDriver::FinalizeFastForward( const float StartTime ) GameState->OnRep_ReplicatedWorldTimeSeconds(); } - if (bIsFastForwardingForCheckpoint) + if ( ServerConnection != nullptr && bIsFastForwardingForCheckpoint ) { // Make a pass at OnReps for startup actors, since they were skipped during checkpoint loading. // At this point the shadow state of these actors should be the actual state from before the checkpoint, diff --git a/Engine/Source/Runtime/Engine/Private/DestructibleActor.cpp b/Engine/Source/Runtime/Engine/Private/DestructibleActor.cpp index 6f99c80c4d5d..9b1995bf16ef 100644 --- a/Engine/Source/Runtime/Engine/Private/DestructibleActor.cpp +++ b/Engine/Source/Runtime/Engine/Private/DestructibleActor.cpp @@ -49,5 +49,3 @@ void ADestructibleActor::PostLoad() } } -/** Returns DestructibleComponent subobject **/ -UDestructibleComponent* ADestructibleActor::GetDestructibleComponent() const { return DestructibleComponent; } diff --git a/Engine/Source/Runtime/Engine/Private/DeviceProfiles/DeviceProfile.cpp b/Engine/Source/Runtime/Engine/Private/DeviceProfiles/DeviceProfile.cpp index a437391a3b5e..e9de5df46984 100644 --- a/Engine/Source/Runtime/Engine/Private/DeviceProfiles/DeviceProfile.cpp +++ b/Engine/Source/Runtime/Engine/Private/DeviceProfiles/DeviceProfile.cpp @@ -53,13 +53,22 @@ UTextureLODSettings* UDeviceProfile::GetTextureLODSettings() const void UDeviceProfile::PostInitProperties() { Super::PostInitProperties(); + ValidateTextureLODGroups(); +} +void UDeviceProfile::ValidateProfile() +{ + ValidateTextureLODGroups(); +} + +void UDeviceProfile::ValidateTextureLODGroups() +{ // Ensure the Texture LOD Groups are in order of TextureGroup Enum TextureLODGroups.Sort([] - (const FTextureLODGroup& Lhs, const FTextureLODGroup& Rhs) - { - return (int32)Lhs.Group < (int32)Rhs.Group; - } + (const FTextureLODGroup& Lhs, const FTextureLODGroup& Rhs) + { + return (int32)Lhs.Group < (int32)Rhs.Group; + } ); // Make sure every Texture Group has an entry, any that aren't specified for this profile should use it's parents values, or the defaults. @@ -80,7 +89,15 @@ void UDeviceProfile::PostInitProperties() { if (TextureLODGroups.Num() < (GroupId + 1) || TextureLODGroups[GroupId].Group > GroupId) { - TextureLODGroups.Insert((ParentProfile ? ParentProfile->TextureLODGroups[GroupId] : FTextureLODGroup()), GroupId); + if (ParentProfile && (ParentProfile->TextureLODGroups.Num() > GroupId)) + { + TextureLODGroups.Insert(ParentProfile->TextureLODGroups[GroupId], GroupId); + } + else + { + TextureLODGroups.Insert(FTextureLODGroup(), GroupId); + } + TextureLODGroups[GroupId].Group = (TextureGroup)GroupId; } } @@ -169,4 +186,55 @@ void UDeviceProfile::PostEditChangeProperty( FPropertyChangedEvent& PropertyChan } } +bool UDeviceProfile::ModifyCVarValue(const FString& ChangeCVarName, const FString& NewCVarValue, bool bAddIfNonExistant) +{ + auto Index = CVars.IndexOfByPredicate( + [&ChangeCVarName](const FString& CVar) { + FString CVarName; + CVar.Split(TEXT("="), &CVarName, NULL); + return CVarName == ChangeCVarName; + } ); + + if (Index != INDEX_NONE) + { + FString CVarName; + CVars[Index].Split(TEXT("="), &CVarName, NULL); + check(CVarName == ChangeCVarName); + CVars[Index] = FString::Printf(TEXT("%s=%s"), *CVarName, *NewCVarValue); + + OnCVarsUpdated().ExecuteIfBound(); + return true; + } + else if(bAddIfNonExistant) + { + CVars.Add(FString::Printf(TEXT("%s=%s"), *ChangeCVarName, *NewCVarValue)); + + OnCVarsUpdated().ExecuteIfBound(); + return true; + } + + return false; +} + +FString UDeviceProfile::GetCVarValue(const FString& CVarName) +{ + auto Index = CVars.IndexOfByPredicate( + [&CVarName](const FString& CVar) { + FString Name; + CVar.Split(TEXT("="), &Name, NULL); + return Name == CVarName; + }); + + if (Index != INDEX_NONE) + { + FString Value; + CVars[Index].Split(TEXT("="), NULL, &Value); + return Value; + } + else + { + return FString(); + } +} + #endif diff --git a/Engine/Source/Runtime/Engine/Private/DeviceProfiles/DeviceProfileManager.cpp b/Engine/Source/Runtime/Engine/Private/DeviceProfiles/DeviceProfileManager.cpp index a51a3114075e..1e52b5ef6980 100644 --- a/Engine/Source/Runtime/Engine/Private/DeviceProfiles/DeviceProfileManager.cpp +++ b/Engine/Source/Runtime/Engine/Private/DeviceProfiles/DeviceProfileManager.cpp @@ -231,6 +231,7 @@ UDeviceProfile* UDeviceProfileManager::CreateProfile( const FString& ProfileName // if the config needs to come from a platform, set it now, then reload the config DeviceProfile->ConfigPlatform = ConfigPlatform; DeviceProfile->LoadConfig(); + DeviceProfile->ValidateProfile(); } // if the config didn't specify a DeviceType, use the passed in one diff --git a/Engine/Source/Runtime/Engine/Private/DocumentationActor.cpp b/Engine/Source/Runtime/Engine/Private/DocumentationActor.cpp index 8eb988f96b46..bbfa35c40fa1 100644 --- a/Engine/Source/Runtime/Engine/Private/DocumentationActor.cpp +++ b/Engine/Source/Runtime/Engine/Private/DocumentationActor.cpp @@ -91,8 +91,3 @@ void ADocumentationActor::UpdateLinkType() #endif } - -#if WITH_EDITORONLY_DATA -/** Returns Billboard subobject **/ -UMaterialBillboardComponent* ADocumentationActor::GetBillboard() const { return Billboard; } -#endif diff --git a/Engine/Source/Runtime/Engine/Private/DrawDebugHelpers.cpp b/Engine/Source/Runtime/Engine/Private/DrawDebugHelpers.cpp index cb74a0ff5ab4..b7502f60ec14 100644 --- a/Engine/Source/Runtime/Engine/Private/DrawDebugHelpers.cpp +++ b/Engine/Source/Runtime/Engine/Private/DrawDebugHelpers.cpp @@ -207,7 +207,7 @@ void DrawDebugSolidBox(const UWorld* InWorld, FBox const& Box, FColor const& Col if (GEngine->GetNetMode(InWorld) != NM_DedicatedServer) { ULineBatchComponent* const LineBatcher = GetDebugLineBatcher( InWorld, bPersistent, LifeTime, false ); - if(LineBatcher != nullptr) + if(LineBatcher != NULL) { float const ActualLifetime = (LifeTime > 0.f) ? LifeTime : LineBatcher->DefaultLifeTime; LineBatcher->DrawSolidBox(Box, Transform, Color, DepthPriority, ActualLifetime); @@ -461,52 +461,55 @@ void DrawDebugSphere(const UWorld* InWorld, FVector const& Center, float Radius, { // this means foreground lines can't be persistent ULineBatchComponent* const LineBatcher = GetDebugLineBatcher( InWorld, bPersistentLines, LifeTime, (DepthPriority == SDPG_Foreground) ); - float LineLifeTime = (LifeTime > 0.f) ? LifeTime : LineBatcher->DefaultLifeTime; - - // Need at least 4 segments - Segments = FMath::Max(Segments, 4); - - FVector Vertex1, Vertex2, Vertex3, Vertex4; - const float AngleInc = 2.f * PI / float(Segments); - int32 NumSegmentsY = Segments; - float Latitude = AngleInc; - int32 NumSegmentsX; - float Longitude; - float SinY1 = 0.0f, CosY1 = 1.0f, SinY2, CosY2; - float SinX, CosX; - - TArray Lines; - Lines.Empty(NumSegmentsY * Segments * 2); - while( NumSegmentsY-- ) + if (LineBatcher != NULL) { - SinY2 = FMath::Sin(Latitude); - CosY2 = FMath::Cos(Latitude); + float LineLifeTime = (LifeTime > 0.f) ? LifeTime : LineBatcher->DefaultLifeTime; - Vertex1 = FVector(SinY1, 0.0f, CosY1) * Radius + Center; - Vertex3 = FVector(SinY2, 0.0f, CosY2) * Radius + Center; - Longitude = AngleInc; + // Need at least 4 segments + Segments = FMath::Max(Segments, 4); - NumSegmentsX = Segments; - while( NumSegmentsX-- ) + FVector Vertex1, Vertex2, Vertex3, Vertex4; + const float AngleInc = 2.f * PI / float(Segments); + int32 NumSegmentsY = Segments; + float Latitude = AngleInc; + int32 NumSegmentsX; + float Longitude; + float SinY1 = 0.0f, CosY1 = 1.0f, SinY2, CosY2; + float SinX, CosX; + + TArray Lines; + Lines.Empty(NumSegmentsY * Segments * 2); + while (NumSegmentsY--) { - SinX = FMath::Sin(Longitude); - CosX = FMath::Cos(Longitude); + SinY2 = FMath::Sin(Latitude); + CosY2 = FMath::Cos(Latitude); - Vertex2 = FVector((CosX * SinY1), (SinX * SinY1), CosY1) * Radius + Center; - Vertex4 = FVector((CosX * SinY2), (SinX * SinY2), CosY2) * Radius + Center; + Vertex1 = FVector(SinY1, 0.0f, CosY1) * Radius + Center; + Vertex3 = FVector(SinY2, 0.0f, CosY2) * Radius + Center; + Longitude = AngleInc; - Lines.Add(FBatchedLine(Vertex1, Vertex2, Color, LineLifeTime, Thickness, DepthPriority)); - Lines.Add(FBatchedLine(Vertex1, Vertex3, Color, LineLifeTime, Thickness, DepthPriority)); + NumSegmentsX = Segments; + while (NumSegmentsX--) + { + SinX = FMath::Sin(Longitude); + CosX = FMath::Cos(Longitude); - Vertex1 = Vertex2; - Vertex3 = Vertex4; - Longitude += AngleInc; + Vertex2 = FVector((CosX * SinY1), (SinX * SinY1), CosY1) * Radius + Center; + Vertex4 = FVector((CosX * SinY2), (SinX * SinY2), CosY2) * Radius + Center; + + Lines.Add(FBatchedLine(Vertex1, Vertex2, Color, LineLifeTime, Thickness, DepthPriority)); + Lines.Add(FBatchedLine(Vertex1, Vertex3, Color, LineLifeTime, Thickness, DepthPriority)); + + Vertex1 = Vertex2; + Vertex3 = Vertex4; + Longitude += AngleInc; + } + SinY1 = SinY2; + CosY1 = CosY2; + Latitude += AngleInc; } - SinY1 = SinY2; - CosY1 = CosY2; - Latitude += AngleInc; + LineBatcher->DrawLines(Lines); } - LineBatcher->DrawLines(Lines); } } @@ -573,54 +576,58 @@ void DrawDebugAltCone(const UWorld* InWorld, FVector const& Origin, FRotator con // this means foreground lines can't be persistent ULineBatchComponent* const LineBatcher = GetDebugLineBatcher( InWorld, bPersistentLines, LifeTime, (DepthPriority == SDPG_Foreground) ); - float const LineLifeTime = (LifeTime > 0.f) ? LifeTime : LineBatcher->DefaultLifeTime; + if (LineBatcher != NULL) + { - FVector const EndPoint = Origin + AxisX * Length; - FVector const Up = FMath::Tan(AngleHeight * 0.5f) * AxisZ * Length; - FVector const Right = FMath::Tan(AngleWidth * 0.5f) * AxisY * Length; - FVector const HalfUp = Up * 0.5f; - FVector const HalfRight = Right * 0.5f; + float const LineLifeTime = (LifeTime > 0.f) ? LifeTime : LineBatcher->DefaultLifeTime; - TArray Lines; - Lines.Empty(); + FVector const EndPoint = Origin + AxisX * Length; + FVector const Up = FMath::Tan(AngleHeight * 0.5f) * AxisZ * Length; + FVector const Right = FMath::Tan(AngleWidth * 0.5f) * AxisY * Length; + FVector const HalfUp = Up * 0.5f; + FVector const HalfRight = Right * 0.5f; - FVector A = EndPoint + Up - Right; - FVector B = EndPoint + Up + Right; - FVector C = EndPoint - Up + Right; - FVector D = EndPoint - Up - Right; + TArray Lines; + Lines.Empty(); - // Corners - Lines.Add(FBatchedLine(Origin, A, DrawColor, LineLifeTime, Thickness, DepthPriority)); - Lines.Add(FBatchedLine(Origin, B, DrawColor, LineLifeTime, Thickness, DepthPriority)); - Lines.Add(FBatchedLine(Origin, C, DrawColor, LineLifeTime, Thickness, DepthPriority)); - Lines.Add(FBatchedLine(Origin, D, DrawColor, LineLifeTime, Thickness, DepthPriority)); + FVector A = EndPoint + Up - Right; + FVector B = EndPoint + Up + Right; + FVector C = EndPoint - Up + Right; + FVector D = EndPoint - Up - Right; - // Further most plane/frame - Lines.Add(FBatchedLine(A, B, DrawColor, LineLifeTime, Thickness, DepthPriority)); - Lines.Add(FBatchedLine(B, C, DrawColor, LineLifeTime, Thickness, DepthPriority)); - Lines.Add(FBatchedLine(C, D, DrawColor, LineLifeTime, Thickness, DepthPriority)); - Lines.Add(FBatchedLine(D, A, DrawColor, LineLifeTime, Thickness, DepthPriority)); + // Corners + Lines.Add(FBatchedLine(Origin, A, DrawColor, LineLifeTime, Thickness, DepthPriority)); + Lines.Add(FBatchedLine(Origin, B, DrawColor, LineLifeTime, Thickness, DepthPriority)); + Lines.Add(FBatchedLine(Origin, C, DrawColor, LineLifeTime, Thickness, DepthPriority)); + Lines.Add(FBatchedLine(Origin, D, DrawColor, LineLifeTime, Thickness, DepthPriority)); - // Mid points - Lines.Add(FBatchedLine(Origin, EndPoint + Up, DrawColor, LineLifeTime, Thickness, DepthPriority)); - Lines.Add(FBatchedLine(Origin, EndPoint - Up, DrawColor, LineLifeTime, Thickness, DepthPriority)); - Lines.Add(FBatchedLine(Origin, EndPoint + Right, DrawColor, LineLifeTime, Thickness, DepthPriority)); - Lines.Add(FBatchedLine(Origin, EndPoint - Right, DrawColor, LineLifeTime, Thickness, DepthPriority)); + // Further most plane/frame + Lines.Add(FBatchedLine(A, B, DrawColor, LineLifeTime, Thickness, DepthPriority)); + Lines.Add(FBatchedLine(B, C, DrawColor, LineLifeTime, Thickness, DepthPriority)); + Lines.Add(FBatchedLine(C, D, DrawColor, LineLifeTime, Thickness, DepthPriority)); + Lines.Add(FBatchedLine(D, A, DrawColor, LineLifeTime, Thickness, DepthPriority)); - // Inbetween - Lines.Add(FBatchedLine(Origin, EndPoint + Up - HalfRight, DrawColor, LineLifeTime, Thickness, DepthPriority)); - Lines.Add(FBatchedLine(Origin, EndPoint + Up + HalfRight, DrawColor, LineLifeTime, Thickness, DepthPriority)); + // Mid points + Lines.Add(FBatchedLine(Origin, EndPoint + Up, DrawColor, LineLifeTime, Thickness, DepthPriority)); + Lines.Add(FBatchedLine(Origin, EndPoint - Up, DrawColor, LineLifeTime, Thickness, DepthPriority)); + Lines.Add(FBatchedLine(Origin, EndPoint + Right, DrawColor, LineLifeTime, Thickness, DepthPriority)); + Lines.Add(FBatchedLine(Origin, EndPoint - Right, DrawColor, LineLifeTime, Thickness, DepthPriority)); - Lines.Add(FBatchedLine(Origin, EndPoint - Up - HalfRight, DrawColor, LineLifeTime, Thickness, DepthPriority)); - Lines.Add(FBatchedLine(Origin, EndPoint - Up + HalfRight, DrawColor, LineLifeTime, Thickness, DepthPriority)); + // Inbetween + Lines.Add(FBatchedLine(Origin, EndPoint + Up - HalfRight, DrawColor, LineLifeTime, Thickness, DepthPriority)); + Lines.Add(FBatchedLine(Origin, EndPoint + Up + HalfRight, DrawColor, LineLifeTime, Thickness, DepthPriority)); - Lines.Add(FBatchedLine(Origin, EndPoint + Right - HalfUp, DrawColor, LineLifeTime, Thickness, DepthPriority)); - Lines.Add(FBatchedLine(Origin, EndPoint + Right + HalfUp, DrawColor, LineLifeTime, Thickness, DepthPriority)); + Lines.Add(FBatchedLine(Origin, EndPoint - Up - HalfRight, DrawColor, LineLifeTime, Thickness, DepthPriority)); + Lines.Add(FBatchedLine(Origin, EndPoint - Up + HalfRight, DrawColor, LineLifeTime, Thickness, DepthPriority)); - Lines.Add(FBatchedLine(Origin, EndPoint - Right - HalfUp, DrawColor, LineLifeTime, Thickness, DepthPriority)); - Lines.Add(FBatchedLine(Origin, EndPoint - Right + HalfUp, DrawColor, LineLifeTime, Thickness, DepthPriority)); + Lines.Add(FBatchedLine(Origin, EndPoint + Right - HalfUp, DrawColor, LineLifeTime, Thickness, DepthPriority)); + Lines.Add(FBatchedLine(Origin, EndPoint + Right + HalfUp, DrawColor, LineLifeTime, Thickness, DepthPriority)); - LineBatcher->DrawLines(Lines); + Lines.Add(FBatchedLine(Origin, EndPoint - Right - HalfUp, DrawColor, LineLifeTime, Thickness, DepthPriority)); + Lines.Add(FBatchedLine(Origin, EndPoint - Right + HalfUp, DrawColor, LineLifeTime, Thickness, DepthPriority)); + + LineBatcher->DrawLines(Lines); + } } void DrawDebugCone(const UWorld* InWorld, FVector const& Origin, FVector const& Direction, float Length, float AngleWidth, float AngleHeight, int32 NumSides, FColor const& DrawColor, bool bPersistentLines, float LifeTime, uint8 DepthPriority, float Thickness) @@ -1058,4 +1065,16 @@ void DrawDebugCanvas2DCircle(UCanvas* Canvas, const FVector2D& Center, float Rad } } +void DrawDebugCanvas2DBox(UCanvas* Canvas, const FBox2D& Box, const FLinearColor& LineColor, const float& LineThickness) +{ + if (Canvas) + { + FCanvasBoxItem BoxItem(Box.Min, Box.GetSize()); + BoxItem.LineThickness = LineThickness; + BoxItem.SetColor(LineColor); + + Canvas->DrawItem(BoxItem); + } +} + #endif // ENABLE_DRAW_DEBUG diff --git a/Engine/Source/Runtime/Engine/Private/DynamicMeshBuilder.cpp b/Engine/Source/Runtime/Engine/Private/DynamicMeshBuilder.cpp index 7311b47b7987..1c7b515bea43 100644 --- a/Engine/Source/Runtime/Engine/Private/DynamicMeshBuilder.cpp +++ b/Engine/Source/Runtime/Engine/Private/DynamicMeshBuilder.cpp @@ -160,10 +160,8 @@ public: FVertexBufferRHIRef CreateResource(FGlobalDynamicMeshPoolPolicy::CreationArguments Args) { FGlobalDynamicMeshPoolPolicy::CreationArguments BufferSize = GetPoolBucketSize(GetPoolBucketIndex(Args)); - // The use of BUF_Static is deliberate - on OS X the buffer backing-store orphaning & reallocation will dominate execution time - // so to avoid this we don't reuse a buffer for several frames, thereby avoiding the pipeline stall and the reallocation cost. FRHIResourceCreateInfo CreateInfo; - FVertexBufferRHIRef VertexBuffer = RHICreateVertexBuffer(BufferSize, BUF_Static, CreateInfo); + FVertexBufferRHIRef VertexBuffer = RHICreateVertexBuffer(BufferSize, BUF_Volatile, CreateInfo); return VertexBuffer; } diff --git a/Engine/Source/Runtime/Engine/Private/EdGraph/EdGraphNode.cpp b/Engine/Source/Runtime/Engine/Private/EdGraph/EdGraphNode.cpp index 24d4efe0d75c..a0daeebb8c91 100644 --- a/Engine/Source/Runtime/Engine/Private/EdGraph/EdGraphNode.cpp +++ b/Engine/Source/Runtime/Engine/Private/EdGraph/EdGraphNode.cpp @@ -12,6 +12,7 @@ #include "UObject/PropertyPortFlags.h" #include "ScopedTransaction.h" #include "FindInBlueprintManager.h" +#include "Editor/GraphEditor/Public/DiffResults.h" #endif #define LOCTEXT_NAMESPACE "EdGraph" @@ -70,20 +71,75 @@ UEdGraphNode::UEdGraphNode(const FObjectInitializer& ObjectInitializer) , AdvancedPinDisplay(ENodeAdvancedPins::NoPins) , EnabledState(ENodeEnabledState::Enabled) , bUserSetEnabledState(false) - , bIsNodeEnabled_DEPRECATED(true) , bAllowSplitPins_DEPRECATED(false) -{ - + , bIsNodeEnabled_DEPRECATED(true) #if WITH_EDITORONLY_DATA - bCommentBubblePinned = false; - bCommentBubbleVisible = false; - bCommentBubbleMakeVisible = false; - bCanResizeNode = false; + , bCanResizeNode(false) #endif // WITH_EDITORONLY_DATA + , bCommentBubblePinned(false) + , bCommentBubbleVisible(false) + , bCommentBubbleMakeVisible(false) +{ } #if WITH_EDITOR +FString UEdGraphNode::GetPropertyNameAndValueForDiff(const UProperty* Prop, const uint8* PropertyAddr) const +{ + FString ExportedStringValue; + if (const UFloatProperty* FloatProp = Cast(Prop)) + { + // special case for floats to remove unnecessary zeros + const float FloatValue = FloatProp->GetPropertyValue(PropertyAddr); + ExportedStringValue = FString::SanitizeFloat(FloatValue); + } + else + { + Prop->ExportTextItem(ExportedStringValue, PropertyAddr, NULL, NULL, PPF_PropertyWindow, NULL); + } + + const bool bIsBool = Prop->IsA(UBoolProperty::StaticClass()); + return FString::Printf(TEXT("%s: %s"), *FName::NameToDisplayString(Prop->GetName(), bIsBool), *ExportedStringValue); +} + +void UEdGraphNode::DiffProperties(UClass* StructA, UClass* StructB, UObject* DataA, UObject* DataB, FDiffResults& Results, FDiffSingleResult& Diff) const +{ + // Find the common parent class in case the other node isn't of the same type + UClass* ClassToViewAs = StructA; + while (!DataB->IsA(ClassToViewAs)) + { + ClassToViewAs = ClassToViewAs->GetSuperClass(); + } + + // Run through all the properties + for (TFieldIterator PropertyIt(ClassToViewAs, EFieldIteratorFlags::IncludeSuper); PropertyIt; ++PropertyIt) + { + UProperty* Prop = *PropertyIt; + // skip properties we cant see + if (!Prop->HasAnyPropertyFlags(CPF_Edit | CPF_BlueprintVisible) || + Prop->HasAnyPropertyFlags(CPF_Transient) || + Prop->HasAnyPropertyFlags(CPF_DisableEditOnInstance) || + Prop->IsA(UDelegateProperty::StaticClass()) || + Prop->IsA(UMulticastDelegateProperty::StaticClass())) + { + continue; + } + + const FString ValueStringA = GetPropertyNameAndValueForDiff(Prop, Prop->ContainerPtrToValuePtr(DataA)); + const FString ValueStringB = GetPropertyNameAndValueForDiff(Prop, Prop->ContainerPtrToValuePtr(DataB)); + + if (ValueStringA != ValueStringB) + { + // Only bother setting up the display data if we're storing the result + if (Results.CanStoreResults()) + { + Diff.DisplayString = FText::Format(LOCTEXT("DIF_NodePropertyFmt", "Property Changed: {0} "), FText::FromString(Prop->GetName())); + } + Results.Add(Diff); + } + } +} + UEdGraphPin* UEdGraphNode::CreatePin(EEdGraphPinDirection Dir, const FEdGraphPinType& InPinType, const FString& PinName, int32 Index /*= INDEX_NONE*/) { UEdGraphPin* NewPin = UEdGraphPin::CreatePin(this); @@ -106,7 +162,12 @@ UEdGraphPin* UEdGraphNode::CreatePin(EEdGraphPinDirection Dir, const FEdGraphPin UEdGraphPin* UEdGraphNode::CreatePin(EEdGraphPinDirection Dir, const FString& PinCategory, const FString& PinSubCategory, UObject* PinSubCategoryObject, bool bIsArray, bool bIsReference, const FString& PinName, bool bIsConst /*= false*/, int32 Index /*= INDEX_NONE*/, bool bIsSet /*= false*/, bool bIsMap /*= false*/, const FEdGraphTerminalType& ValueTerminalType /*= FEdGraphTerminalType()*/) { - FEdGraphPinType PinType(PinCategory, PinSubCategory, PinSubCategoryObject, bIsArray, bIsReference, bIsSet, bIsMap, ValueTerminalType); + return CreatePin(Dir, PinCategory, PinSubCategory, PinSubCategoryObject, PinName, FEdGraphPinType::ToPinContainerType(bIsArray, bIsSet, bIsMap), bIsReference, bIsConst, Index, ValueTerminalType); +} + +UEdGraphPin* UEdGraphNode::CreatePin(EEdGraphPinDirection Dir, const FString& PinCategory, const FString& PinSubCategory, UObject* PinSubCategoryObject, const FString& PinName, EPinContainerType PinContainerType /* EPinContainerType::None */, bool bIsReference /* = false */, bool bIsConst /*= false*/, int32 Index /*= INDEX_NONE*/, const FEdGraphTerminalType& ValueTerminalType /*= FEdGraphTerminalType()*/) +{ + FEdGraphPinType PinType(PinCategory, PinSubCategory, PinSubCategoryObject, PinContainerType, bIsReference, ValueTerminalType); PinType.bIsConst = bIsConst; return CreatePin(Dir, PinType, PinName, Index); @@ -490,8 +551,20 @@ void UEdGraphNode::CreateNewGuid() NodeGuid = FGuid::NewGuid(); } -void UEdGraphNode::FindDiffs( class UEdGraphNode* OtherNode, struct FDiffResults& Results ) +void UEdGraphNode::FindDiffs(UEdGraphNode* OtherNode, struct FDiffResults& Results) { + if (OtherNode != nullptr) + { + FDiffSingleResult Diff; + Diff.Diff = EDiffType::NODE_PROPERTY; + Diff.Node1 = this; + Diff.Node2 = OtherNode; + Diff.ToolTip = LOCTEXT("DIF_NodePropertyToolTip", "A Property of the node has changed"); + Diff.DisplayColor = FLinearColor(0.25f, 0.71f, 0.85f); + + // Diff the properties between the nodes + DiffProperties(GetClass(), OtherNode->GetClass(), this, OtherNode, Results, Diff); + } } void UEdGraphNode::DestroyPin(UEdGraphPin* Pin) diff --git a/Engine/Source/Runtime/Engine/Private/EdGraph/EdGraphPin.cpp b/Engine/Source/Runtime/Engine/Private/EdGraph/EdGraphPin.cpp index 62331e750136..9de5c2b5f316 100644 --- a/Engine/Source/Runtime/Engine/Private/EdGraph/EdGraphPin.cpp +++ b/Engine/Source/Runtime/Engine/Private/EdGraph/EdGraphPin.cpp @@ -2,6 +2,7 @@ #include "EdGraph/EdGraphPin.h" #include "UObject/BlueprintsObjectVersion.h" +#include "UObject/FrameworkObjectVersion.h" #include "UObject/UnrealType.h" #include "UObject/TextProperty.h" #include "EdGraph/EdGraph.h" @@ -82,21 +83,46 @@ bool FEdGraphPinType::Serialize(FArchive& Ar) } } - Ar.UsingCustomVersion(FBlueprintsObjectVersion::GUID); - if (Ar.CustomVer(FBlueprintsObjectVersion::GUID) >= FBlueprintsObjectVersion::AdvancedContainerSupport) + Ar.UsingCustomVersion(FFrameworkObjectVersion::GUID); + if (Ar.CustomVer(FFrameworkObjectVersion::GUID) >= FFrameworkObjectVersion::EdGraphPinContainerType) { - Ar << bIsMap; - if (bIsMap) + Ar << ContainerType; + if (IsMap()) { Ar << PinValueType; } - Ar << bIsSet; + } + else + { + bool bIsMap = false; + bool bIsSet = false; + bool bIsArray = false; + + Ar.UsingCustomVersion(FBlueprintsObjectVersion::GUID); + if (Ar.CustomVer(FBlueprintsObjectVersion::GUID) >= FBlueprintsObjectVersion::AdvancedContainerSupport) + { + Ar << bIsMap; + if (bIsMap) + { + Ar << PinValueType; + } + Ar << bIsSet; + } + + Ar << bIsArray; + + if (Ar.IsLoading()) + { + ContainerType = ToPinContainerType(bIsArray, bIsSet, bIsMap); + } } - Ar << bIsArray; - Ar << bIsReference; - Ar << bIsWeakPointer; - + bool bIsReferenceBool = bIsReference; + bool bIsWeakPointerBool = bIsWeakPointer; + + Ar << bIsReferenceBool; + Ar << bIsWeakPointerBool; + if (Ar.UE4Ver() >= VER_UE4_MEMBERREFERENCE_IN_PINTYPE) { Ar << PinSubCategoryMemberReference; @@ -118,13 +144,18 @@ bool FEdGraphPinType::Serialize(FArchive& Ar) } } + bool bIsConstBool = false; + if (Ar.UE4Ver() >= VER_UE4_SERIALIZE_PINTYPE_CONST) { - Ar << bIsConst; + Ar << bIsConstBool; } - else if (Ar.IsLoading()) + + if (Ar.IsLoading()) { - bIsConst = false; + bIsReference = bIsReferenceBool; + bIsWeakPointer = bIsWeakPointerBool; + bIsConst = bIsConstBool; } return true; @@ -145,9 +176,7 @@ FEdGraphPinType FEdGraphPinType::GetTerminalTypeForContainer( const FEdGraphPinT ensure(ContainerType.IsContainer()); FEdGraphPinType TerminalType = ContainerType; - TerminalType.bIsArray = false; - TerminalType.bIsMap = false; - TerminalType.bIsSet = false; + TerminalType.ContainerType = EPinContainerType::None; return TerminalType; } @@ -352,7 +381,6 @@ void UEdGraphPin::BreakAllPinLinks() } } - void UEdGraphPin::CopyPersistentDataFromOldPin(const UEdGraphPin& SourcePin) { // The name matches already, doesn't get copied here @@ -361,7 +389,7 @@ void UEdGraphPin::CopyPersistentDataFromOldPin(const UEdGraphPin& SourcePin) PinId = SourcePin.PinId; // Only move the default value if it was modified; inherit the new default value otherwise - if (SourcePin.DefaultValue != SourcePin.AutogeneratedDefaultValue || SourcePin.DefaultObject != nullptr || SourcePin.DefaultTextValue.ToString() != SourcePin.AutogeneratedDefaultValue) + if (!SourcePin.DoesDefaultValueMatchAutogenerated()) { DefaultObject = SourcePin.DefaultObject; DefaultValue = SourcePin.DefaultValue; @@ -473,6 +501,12 @@ FString UEdGraphPin::GetDefaultAsString() const } } +bool UEdGraphPin::DoesDefaultValueMatchAutogenerated() const +{ + // Ignoring case on purpose to match default behavior + return GetDefaultAsString().Equals(AutogeneratedDefaultValue, ESearchCase::IgnoreCase); +} + #if WITH_EDITORONLY_DATA FText UEdGraphPin::GetDisplayName() const { diff --git a/Engine/Source/Runtime/Engine/Private/EditorFramework/AssetImportData.cpp b/Engine/Source/Runtime/Engine/Private/EditorFramework/AssetImportData.cpp index f212ef6fa1c8..a9d75c0aec12 100644 --- a/Engine/Source/Runtime/Engine/Private/EditorFramework/AssetImportData.cpp +++ b/Engine/Source/Runtime/Engine/Private/EditorFramework/AssetImportData.cpp @@ -9,6 +9,11 @@ #include "UObject/Package.h" #include "AnimPhysObjectVersion.h" +#if WITH_EDITOR +#include "Editor/EditorPerProjectUserSettings.h" +#endif + + // This whole class is compiled out in non-editor UAssetImportData::UAssetImportData(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) @@ -180,6 +185,28 @@ FString UAssetImportData::SanitizeImportFilename(const FString& InPath) const } } +#if WITH_EDITOR + FString BaseSourceFolder = GetDefault()->DataSourceFolder.Path; + if (!BaseSourceFolder.IsEmpty() && FPaths::DirectoryExists(BaseSourceFolder)) + { + //Make sure the source folder is clean to do relative operation + if (!BaseSourceFolder.EndsWith(TEXT("/")) && !BaseSourceFolder.EndsWith(TEXT("\\"))) + { + BaseSourceFolder += TEXT("/"); + } + //Look if the InPath is relative to the base source path, if yes we will store a relative path to this folder + FString RelativePath = InPath; + if (FPaths::MakePathRelativeTo(RelativePath, *BaseSourceFolder)) + { + //Make sure the path is under the base source folder + if (!RelativePath.StartsWith(TEXT(".."))) + { + return RelativePath; + } + } + } +#endif + return IFileManager::Get().ConvertToRelativePath(*InPath); } @@ -203,6 +230,27 @@ FString UAssetImportData::ResolveImportFilename(const FString& InRelativePath, c } } +#if WITH_EDITOR + FString BaseSourceFolder = GetDefault()->DataSourceFolder.Path; + if (!BaseSourceFolder.IsEmpty() && FPaths::DirectoryExists(BaseSourceFolder)) + { + //Make sure the source folder is clean to do relative operation + if (!BaseSourceFolder.EndsWith(TEXT("/")) && !BaseSourceFolder.EndsWith(TEXT("\\"))) + { + BaseSourceFolder += TEXT("/"); + } + FString FullPath = FPaths::Combine(BaseSourceFolder, InRelativePath); + if (FPaths::FileExists(FullPath)) + { + FString FullConvertPath = FPaths::ConvertRelativePathToFull(FullPath); + if (FullConvertPath.Find(TEXT("..")) == INDEX_NONE) + { + return FullConvertPath; + } + } + } +#endif + // Convert relative paths return FPaths::ConvertRelativePathToFull(RelativePath); } diff --git a/Engine/Source/Runtime/Engine/Private/EnginePrivatePCH.h b/Engine/Source/Runtime/Engine/Private/EnginePrivatePCH.h index 5258446ae331..154b11e6a45f 100644 --- a/Engine/Source/Runtime/Engine/Private/EnginePrivatePCH.h +++ b/Engine/Source/Runtime/Engine/Private/EnginePrivatePCH.h @@ -34,7 +34,6 @@ #include "Templates/EnableIf.h" #include "Templates/RemoveReference.h" #include "Templates/TypeCompatibleBytes.h" -#include "Templates/AlignOf.h" #include "Templates/ChooseClass.h" #include "Templates/IntegralConstant.h" #include "Templates/IsClass.h" @@ -378,7 +377,6 @@ // From AssetRegistry: #include "AssetData.h" -#include "SharedMapView.h" // From Engine: #include "EngineLogs.h" diff --git a/Engine/Source/Runtime/Engine/Private/EngineTypes.cpp b/Engine/Source/Runtime/Engine/Private/EngineTypes.cpp index 1ef88ff905c6..f9261f613528 100644 --- a/Engine/Source/Runtime/Engine/Private/EngineTypes.cpp +++ b/Engine/Source/Runtime/Engine/Private/EngineTypes.cpp @@ -346,6 +346,8 @@ FVector FRepMovement::RebaseOntoZeroOrigin(const struct FVector& Location, const return RebaseOntoZeroOrigin(Location, WorldContextActor->GetWorld()->OriginLocation); } +/// @cond DOXYGEN_WARNINGS + /** Rebase zero-origin position onto local world origin value based on an actor component's world. */ FVector FRepMovement::RebaseOntoLocalOrigin(const struct FVector& Location, const UActorComponent* const WorldContextActorComponent) { @@ -367,3 +369,5 @@ FVector FRepMovement::RebaseOntoZeroOrigin(const struct FVector& Location, const return RebaseOntoZeroOrigin(Location, WorldContextActorComponent->GetWorld()->OriginLocation); } + +/// @endcond diff --git a/Engine/Source/Runtime/Engine/Private/EngineUtils.cpp b/Engine/Source/Runtime/Engine/Private/EngineUtils.cpp index ed10b5cebe1e..6e4aa9bcc25f 100644 --- a/Engine/Source/Runtime/Engine/Private/EngineUtils.cpp +++ b/Engine/Source/Runtime/Engine/Private/EngineUtils.cpp @@ -415,8 +415,7 @@ TArray GetSubLevelsStatus( UWorld* World ) FHitResult Hit(1.f); // this will not work for flying around :-( - static FName NAME_FindLevel = FName(TEXT("FindLevel"), true); - PlayerController->GetWorld()->LineTraceSingleByObjectType(Hit,PlayerController->GetPawn()->GetActorLocation(), (PlayerController->GetPawn()->GetActorLocation()-FVector(0.f, 0.f, 256.f)), FCollisionObjectQueryParams(ECC_WorldStatic), FCollisionQueryParams(NAME_FindLevel, true, PlayerController->GetPawn())); + PlayerController->GetWorld()->LineTraceSingleByObjectType(Hit,PlayerController->GetPawn()->GetActorLocation(), (PlayerController->GetPawn()->GetActorLocation()-FVector(0.f, 0.f, 256.f)), FCollisionObjectQueryParams(ECC_WorldStatic), FCollisionQueryParams(SCENE_QUERY_STAT(FindLevel), true, PlayerController->GetPawn())); ULevel* LevelPlayerIsIn = NULL; diff --git a/Engine/Source/Runtime/Engine/Private/GPUSkinCache.cpp b/Engine/Source/Runtime/Engine/Private/GPUSkinCache.cpp index cc521f4822a5..dff9eea0894e 100644 --- a/Engine/Source/Runtime/Engine/Private/GPUSkinCache.cpp +++ b/Engine/Source/Runtime/Engine/Private/GPUSkinCache.cpp @@ -127,7 +127,6 @@ public: , GPUSkin(InGPUSkin) , MorphBuffer(0) , LOD(InGPUSkin->GetLOD()) - , IndexBuffer(nullptr) { const TArray& Sections = InGPUSkin->GetRenderSections(LOD); @@ -159,6 +158,9 @@ public: FGPUBaseSkinVertexFactory* SourceVertexFactory; FGPUSkinPassthroughVertexFactory* TargetVertexFactory; + // triangle index buffer (input for the RecomputeSkinTangents, might need special index buffer unique to position and normal, not considering UV/vertex color) + FShaderResourceViewRHIParamRef IndexBuffer; + const FSkelMeshSection* Section; // for debugging / draw events, -1 if not set @@ -189,11 +191,14 @@ public: uint32 IndexBufferOffsetValue; uint32 NumTriangles; + FRWBuffer* BoneBuffer; + FRWBuffer* PreviousBoneBuffer; FSectionDispatchData() : Allocation(nullptr) , SourceVertexFactory(nullptr) , TargetVertexFactory(nullptr) + , IndexBuffer(nullptr) , Section(nullptr) , SectionIndex(-1) , SkinType(0) @@ -205,27 +210,26 @@ public: , MorphBufferOffset(0) , IndexBufferOffsetValue(0) , NumTriangles(0) + , BoneBuffer(nullptr) + , PreviousBoneBuffer(nullptr) { } - inline FRWBuffer& GetPreviousRWBuffer() + inline FRWBuffer* GetPreviousRWBuffer() { - return Allocation->RWBuffers[Allocation->PreviousIndex]; + check(PreviousBoneBuffer); + return PreviousBoneBuffer; } - inline FRWBuffer& GetRWBuffer() + inline FRWBuffer* GetRWBuffer() { - return Allocation->RWBuffers[Allocation->CurrentIndex]; - } - - inline void Advance() - { - Allocation->Advance(); + check(BoneBuffer); + return BoneBuffer; } void UpdateVertexFactoryDeclaration() { - TargetVertexFactory->UpdateVertexDeclaration(SourceVertexFactory, &GetRWBuffer()); + TargetVertexFactory->UpdateVertexDeclaration(SourceVertexFactory, GetRWBuffer()); } }; @@ -236,7 +240,14 @@ public: bool IsSectionValid(int32 Section) { - return DispatchData[Section].SectionIndex == Section; + const FSectionDispatchData& SectionData = DispatchData[Section]; + return SectionData.SectionIndex == Section; + } + + bool IsSourceFactoryValid(int32 Section, FGPUBaseSkinVertexFactory* SourceVertexFactory) + { + const FSectionDispatchData& SectionData = DispatchData[Section]; + return SectionData.SourceVertexFactory == SourceVertexFactory; } bool IsValid(FSkeletalMeshObjectGPUSkin* InSkin) @@ -287,6 +298,21 @@ public: Data.InputWeightStart = (InputWeightStride * Section->BaseVertexIndex) / sizeof(float); Data.SourceVertexFactory = InSourceVertexFactory; Data.TargetVertexFactory = InTargetVertexFactory; + + int32 RecomputeTangentsMode = GForceRecomputeTangents > 0 ? 1 : GSkinCacheRecomputeTangents; + if (RecomputeTangentsMode > 0) + { + if (Section->bRecomputeTangent || RecomputeTangentsMode == 1) + { + FRawStaticIndexBuffer16or32Interface* IndexBuffer = LodModel.MultiSizeIndexContainer.GetIndexBuffer(); + Data.IndexBuffer = IndexBuffer->GetSRV(); + if (Data.IndexBuffer) + { + Data.NumTriangles = Section->NumTriangles; + Data.IndexBufferOffsetValue = Section->BaseIndex; + } + } + } } protected: @@ -299,9 +325,6 @@ protected: FShaderResourceViewRHIParamRef MorphBuffer; int32 LOD; - // triangle index buffer (input for the RecomputeSkinTangents, might need special index buffer unique to position and normal, not considering UV/vertex color) - FShaderResourceViewRHIParamRef IndexBuffer; - friend class FGPUSkinCache; friend class FBaseGPUSkinCacheCS; friend class FBaseRecomputeTangents; @@ -341,7 +364,8 @@ public: void SetParameters(FRHICommandListImmediate& RHICmdList, const FVertexBufferAndSRV& BoneBuffer, const FVector& MeshOrigin, const FVector& MeshExtension, FGPUSkinCacheEntry* Entry, - FGPUSkinCacheEntry::FSectionDispatchData& DispatchData) + FGPUSkinCacheEntry::FSectionDispatchData& DispatchData, + FUnorderedAccessViewRHIParamRef UnorderedAccessViewRHI) { FComputeShaderRHIParamRef ShaderRHI = GetComputeShader(); @@ -363,7 +387,7 @@ public: SetSRVParameter(RHICmdList, ShaderRHI, InputWeightStream, Entry->InputWeightStreamSRV); // output UAV - SetUAVParameter(RHICmdList, ShaderRHI, SkinCacheBufferUAV, DispatchData.GetRWBuffer().UAV); + SetUAVParameter(RHICmdList, ShaderRHI, SkinCacheBufferUAV, UnorderedAccessViewRHI); SetShaderValue(RHICmdList, ShaderRHI, SkinCacheStart, DispatchData.OutputStreamStart); const bool bMorph = DispatchData.SkinType == 1; @@ -587,10 +611,10 @@ public: SetShaderValue(RHICmdList, ShaderRHI, NumTriangles, DispatchData.NumTriangles); - SetSRVParameter(RHICmdList, ShaderRHI, GPUSkinCacheBuffer, DispatchData.GetRWBuffer().SRV); + SetSRVParameter(RHICmdList, ShaderRHI, GPUSkinCacheBuffer, DispatchData.GetRWBuffer()->SRV); SetShaderValue(RHICmdList, ShaderRHI, SkinCacheStart, DispatchData.OutputStreamStart); - SetSRVParameter(RHICmdList, ShaderRHI, IndexBuffer, Entry->IndexBuffer); + SetSRVParameter(RHICmdList, ShaderRHI, IndexBuffer, DispatchData.IndexBuffer); SetShaderValue(RHICmdList, ShaderRHI, IndexBufferOffset, DispatchData.IndexBufferOffsetValue); SetShaderValue(RHICmdList, ShaderRHI, InputStreamStart, DispatchData.InputStreamStart); @@ -721,7 +745,7 @@ public: // UAVs SetUAVParameter(RHICmdList, ShaderRHI, IntermediateAccumBufferUAV, StagingBuffer.UAV); - SetUAVParameter(RHICmdList, ShaderRHI, SkinCacheBufferUAV, DispatchData.GetRWBuffer().UAV); + SetUAVParameter(RHICmdList, ShaderRHI, SkinCacheBufferUAV, DispatchData.GetRWBuffer()->UAV); } void UnsetParameters(FRHICommandList& RHICmdList) @@ -846,8 +870,8 @@ void FGPUSkinCache::DispatchUpdateSkinTangents(FRHICommandListImmediate& RHICmdL FGPUSkinCache::FAllocation* FGPUSkinCache::TryAllocBuffer(uint32 NumFloatsRequired) { - uint64 MaxSizeInBytes = (uint64)(GSkinCacheSceneMemoryLimitInMB * 1024.0f * 1024.0f); - uint64 RequiredMemInBytes = sizeof(float) * NumFloatsRequired * FAllocation::NUM_BUFFERS; + uint64 MaxSizeInBytes = (uint64)(GSkinCacheSceneMemoryLimitInMB * 1024.0f * 1024.0f); + uint64 RequiredMemInBytes = FAllocation::CalulateRequiredMemory(NumFloatsRequired); if (bRequiresMemoryLimit && UsedMemoryInBytes + RequiredMemInBytes >= MaxSizeInBytes) { ExtraRequiredMemory += RequiredMemInBytes; @@ -856,18 +880,7 @@ FGPUSkinCache::FAllocation* FGPUSkinCache::TryAllocBuffer(uint32 NumFloatsRequir return nullptr; } - FAllocation* NewAllocation = new FAllocation; - for (int32 Index = 0; Index < FAllocation::NUM_BUFFERS; ++Index) - { - NewAllocation->RWBuffers[Index].Initialize(sizeof(float), NumFloatsRequired, PF_R32_FLOAT, BUF_Static); - -#if UE_BUILD_DEBUG || UE_BUILD_DEVELOPMENT - //FString Name = FString::Printf(TEXT("SkinCacheRWBuffer%d"), Index); - //RHICmdList.BindDebugLabelName(SkinCacheBuffer[Index].UAV, *Name); -#endif - } - NewAllocation->NumFloatsRequired = NumFloatsRequired; - + FAllocation* NewAllocation = new FAllocation(NumFloatsRequired); Allocations.Add(NewAllocation); UsedMemoryInBytes += RequiredMemInBytes; @@ -885,7 +898,7 @@ void FGPUSkinCache::DoDispatch(FRHICommandListImmediate& RHICmdList, FGPUSkinCac //RHICmdList.TransitionResource(EResourceTransitionAccess::ERWBarrier, EResourceTransitionPipeline::EGfxToCompute, DispatchData.GetRWBuffer()); SkinCacheEntry->UpdateVertexFactoryDeclaration(Section); - if (SkinCacheEntry->IndexBuffer) + if (SkinCacheEntry->DispatchData[Section].IndexBuffer) { DispatchUpdateSkinTangents(RHICmdList, SkinCacheEntry, Section); } @@ -923,7 +936,7 @@ void FGPUSkinCache::ProcessEntry(FRHICommandListImmediate& RHICmdList, FGPUBaseS } else { - if (!InOutEntry->IsSectionValid(Section)) + if (!InOutEntry->IsSectionValid(Section) || !InOutEntry->IsSourceFactoryValid(Section, VertexFactory)) { // This section might not be valid yet, so set it up int32 TotalNumVertices = VertexFactory->GetSkinVertexBuffer()->GetNumVertices(); @@ -941,7 +954,6 @@ void FGPUSkinCache::ProcessEntry(FRHICommandListImmediate& RHICmdList, FGPUBaseS } } - int32 RecomputeTangentsMode = GForceRecomputeTangents > 0 ? 1 : GSkinCacheRecomputeTangents; // Try to allocate a new entry if (!InOutEntry) { @@ -958,15 +970,6 @@ void FGPUSkinCache::ProcessEntry(FRHICommandListImmediate& RHICmdList, FGPUBaseS InOutEntry = new FGPUSkinCacheEntry(this, Skin); InOutEntry->GPUSkin = Skin; - if (RecomputeTangentsMode > 0) - { - if (BatchElement.bRecomputeTangent || RecomputeTangentsMode == 1) - { - FRawStaticIndexBuffer16or32Interface* IndexBuffer = LodModel.MultiSizeIndexContainer.GetIndexBuffer(); - InOutEntry->IndexBuffer = IndexBuffer->GetSRV(); - } - } - InOutEntry->SetupSection(Section, NewAllocation, &LodModel.Sections[Section], MorphVertexBuffer, NumVertices, InputStreamStart, StreamStrides[0], VertexFactory, TargetVertexFactory); Entries.Add(InOutEntry); } @@ -992,12 +995,6 @@ void FGPUSkinCache::ProcessEntry(FRHICommandListImmediate& RHICmdList, FGPUBaseS } InOutEntry->DispatchData[Section].SkinType = MorphVertexBuffer ? 1 : 0; - if (InOutEntry->IndexBuffer) - { - InOutEntry->DispatchData[Section].NumTriangles = BatchElement.NumTriangles; - InOutEntry->DispatchData[Section].IndexBufferOffsetValue = BatchElement.BaseIndex; - } - DoDispatch(RHICmdList, InOutEntry, Section, FrameNumber); InOutEntry->UpdateVertexFactoryDeclaration(Section); } @@ -1013,13 +1010,13 @@ void FGPUSkinCache::SetVertexStreams(FGPUSkinCacheEntry* Entry, int32 Section, F FGPUSkinCacheEntry::FSectionDispatchData& DispatchData = Entry->DispatchData[Section]; //UE_LOG(LogSkinCache, Warning, TEXT("*** SetVertexStreams E %p All %p Sec %d(%p) LOD %d"), Entry, Entry->DispatchData[Section].Allocation, Section, Entry->DispatchData[Section].Section, Entry->LOD); - RHICmdList.SetStreamSource(VertexFactory->GetStreamIndex(), DispatchData.GetRWBuffer().Buffer, RWStrideInFloats * sizeof(float), 0); + RHICmdList.SetStreamSource(VertexFactory->GetStreamIndex(), DispatchData.GetRWBuffer()->Buffer, RWStrideInFloats * sizeof(float), 0); FVertexShaderRHIParamRef ShaderRHI = Shader->GetVertexShader(); if (ShaderRHI && PreviousStreamBuffer.IsBound()) { SetShaderValue(RHICmdList, ShaderRHI, PreviousStreamFloatOffset, 0); - RHICmdList.SetShaderResourceViewParameter(ShaderRHI, PreviousStreamBuffer.GetBaseIndex(), DispatchData.GetPreviousRWBuffer().SRV); + RHICmdList.SetShaderResourceViewParameter(ShaderRHI, PreviousStreamBuffer.GetBaseIndex(), DispatchData.GetPreviousRWBuffer()->SRV); } } @@ -1050,21 +1047,54 @@ void FGPUSkinCache::DispatchUpdateSkinning(FRHICommandListImmediate& RHICmdList, default: check(0); } - - DispatchData.Allocation->Advance(); - const FVertexBufferAndSRV& BoneBuffer = ShaderData.GetBoneBufferForReading(false, FrameNumber); check(Shader); - RHICmdList.SetComputeShader(Shader->GetComputeShader()); - Shader->SetParameters(RHICmdList, BoneBuffer, ShaderData.MeshOrigin, ShaderData.MeshExtension, Entry, DispatchData); - RHICmdList.TransitionResource(EResourceTransitionAccess::EWritable, EResourceTransitionPipeline::EGfxToCompute, DispatchData.GetRWBuffer().UAV.GetReference()); + const FVertexBufferAndSRV& BoneBuffer = ShaderData.GetBoneBufferForReading(false, FrameNumber); + const FVertexBufferAndSRV& PrevBoneBuffer = ShaderData.GetBoneBufferForReading(true, FrameNumber); - uint32 VertexCountAlign64 = FMath::DivideAndRoundUp(DispatchData.NumVertices, (uint32)64); - INC_DWORD_STAT_BY(STAT_GPUSkinCache_TotalNumVertices, VertexCountAlign64 * 64); - RHICmdList.DispatchComputeShader(VertexCountAlign64, 1, 1); - Shader->UnsetParameters(RHICmdList); + uint32 CurrentRevision = FrameNumber; + uint32 PreviousRevision = FrameNumber - 1; + DispatchData.PreviousBoneBuffer = DispatchData.Allocation->Find(PrevBoneBuffer, PreviousRevision); + if (!DispatchData.PreviousBoneBuffer) + { + DispatchData.Allocation->Advance(PrevBoneBuffer, PreviousRevision, BoneBuffer, CurrentRevision); + DispatchData.PreviousBoneBuffer = DispatchData.Allocation->Find(PrevBoneBuffer, PreviousRevision); + check(DispatchData.PreviousBoneBuffer) - BuffersToTransition.Add(DispatchData.GetRWBuffer().UAV); + RHICmdList.SetComputeShader(Shader->GetComputeShader()); + Shader->SetParameters(RHICmdList, PrevBoneBuffer, ShaderData.MeshOrigin, ShaderData.MeshExtension, Entry, DispatchData, DispatchData.GetPreviousRWBuffer()->UAV); + + RHICmdList.TransitionResource(EResourceTransitionAccess::EWritable, EResourceTransitionPipeline::EGfxToCompute, DispatchData.GetPreviousRWBuffer()->UAV.GetReference()); + + uint32 VertexCountAlign64 = FMath::DivideAndRoundUp(DispatchData.NumVertices, (uint32)64); + INC_DWORD_STAT_BY(STAT_GPUSkinCache_TotalNumVertices, VertexCountAlign64 * 64); + RHICmdList.DispatchComputeShader(VertexCountAlign64, 1, 1); + Shader->UnsetParameters(RHICmdList); + + BuffersToTransition.Add(DispatchData.GetPreviousRWBuffer()->UAV); + } + + DispatchData.BoneBuffer = DispatchData.Allocation->Find(BoneBuffer, CurrentRevision); + if (!DispatchData.BoneBuffer) + { + DispatchData.Allocation->Advance(BoneBuffer, CurrentRevision, PrevBoneBuffer, PreviousRevision); + DispatchData.BoneBuffer = DispatchData.Allocation->Find(BoneBuffer, CurrentRevision); + check(DispatchData.BoneBuffer); + + RHICmdList.SetComputeShader(Shader->GetComputeShader()); + Shader->SetParameters(RHICmdList, BoneBuffer, ShaderData.MeshOrigin, ShaderData.MeshExtension, Entry, DispatchData, DispatchData.GetRWBuffer()->UAV.GetReference()); + + RHICmdList.TransitionResource(EResourceTransitionAccess::EWritable, EResourceTransitionPipeline::EGfxToCompute, DispatchData.GetRWBuffer()->UAV.GetReference()); + + uint32 VertexCountAlign64 = FMath::DivideAndRoundUp(DispatchData.NumVertices, (uint32)64); + INC_DWORD_STAT_BY(STAT_GPUSkinCache_TotalNumVertices, VertexCountAlign64 * 64); + RHICmdList.DispatchComputeShader(VertexCountAlign64, 1, 1); + Shader->UnsetParameters(RHICmdList); + + BuffersToTransition.Add(DispatchData.GetRWBuffer()->UAV); + } + + check(DispatchData.PreviousBoneBuffer != DispatchData.BoneBuffer); } void FGPUSkinCache::InternalRelease(FGPUSkinCacheEntry* SkinCacheEntry) @@ -1076,12 +1106,12 @@ void FGPUSkinCache::InternalRelease(FGPUSkinCacheEntry* SkinCacheEntry) FAllocation* Allocation = DispatchData.Allocation; if (Allocation) { - uint64 RequiredMemInBytes = sizeof(float) * Allocation->NumFloatsRequired * FAllocation::NUM_BUFFERS; + uint64 RequiredMemInBytes = Allocation->GetNumBytes(); SkinCache->UsedMemoryInBytes -= RequiredMemInBytes; DEC_MEMORY_STAT_BY(STAT_GPUSkinCache_TotalMemUsed, RequiredMemInBytes); SkinCache->Allocations.Remove(Allocation); - SkinCache->BuffersToTransition.Remove(DispatchData.GetRWBuffer().UAV); + Allocation->Release(SkinCache->BuffersToTransition); delete Allocation; DispatchData.Allocation = nullptr; diff --git a/Engine/Source/Runtime/Engine/Private/GPUSkinVertexFactory.cpp b/Engine/Source/Runtime/Engine/Private/GPUSkinVertexFactory.cpp index f2ccbac07b8a..f4257a52a76b 100644 --- a/Engine/Source/Runtime/Engine/Private/GPUSkinVertexFactory.cpp +++ b/Engine/Source/Runtime/Engine/Private/GPUSkinVertexFactory.cpp @@ -164,7 +164,7 @@ static TAutoConsoleVariable CVarRHICmdDeferSkeletalLockAndFillToRHIThread static bool DeferSkeletalLockAndFillToRHIThread() { - return GRHIThread && CVarRHICmdDeferSkeletalLockAndFillToRHIThread.GetValueOnRenderThread() > 0; + return IsRunningRHIInSeparateThread() && CVarRHICmdDeferSkeletalLockAndFillToRHIThread.GetValueOnRenderThread() > 0; } struct FRHICommandUpdateBoneBuffer : public FRHICommand @@ -229,7 +229,7 @@ bool FGPUBaseSkinVertexFactory::FShaderDataType::UpdateBoneData(FRHICommandListI check(IsInRenderingThread()); GoToNextFrame(FrameNumber); - CurrentBoneBuffer = &GetBoneBufferForWriting(false, FrameNumber); + CurrentBoneBuffer = &GetBoneBufferForWriting(FrameNumber); static FSharedPoolPolicyData PoolPolicy; uint32 NumVectors = NumBones*3; @@ -303,44 +303,6 @@ int32 FGPUBaseSkinVertexFactory::GetMaxGPUSkinBones() return GCVarMaxGPUSkinBones; } -/*----------------------------------------------------------------------------- - FBoneDataTexture - SizeX(32 * 1024) - Good size for UE3 ------------------------------------------------------------------------------*/ - -FBoneDataVertexBuffer::FBoneDataVertexBuffer() - : SizeX(80 * 1024) // todo: we will replace this fixed size using FGlobalDynamicVertexBuffer -{ -} - -float* FBoneDataVertexBuffer::LockData() -{ - checkSlow(IsInRenderingThread()); - checkSlow(GetSizeX()); - checkSlow(IsValidRef(BoneBuffer)); - - float* Data = (float*)RHILockVertexBuffer(BoneBuffer.VertexBufferRHI, 0, ComputeMemorySize(), RLM_WriteOnly); - checkSlow(Data); - - return Data; -} - -void FBoneDataVertexBuffer::UnlockData(uint32 SizeInBytes) -{ - checkSlow(IsValidRef(BoneBuffer)); - RHIUnlockVertexBuffer(BoneBuffer.VertexBufferRHI); -} - -uint32 FBoneDataVertexBuffer::GetSizeX() const -{ - return SizeX; -} - -uint32 FBoneDataVertexBuffer::ComputeMemorySize() -{ - return SizeX * sizeof(FVector4); -} - /*----------------------------------------------------------------------------- TGPUSkinVertexFactory -----------------------------------------------------------------------------*/ @@ -804,12 +766,12 @@ public: if(ClothSimulVertsPositionsNormalsParameter.IsBound()) { RHICmdList.SetShaderResourceViewParameter(Shader->GetVertexShader(), ClothSimulVertsPositionsNormalsParameter.GetBaseIndex(), - ClothShaderData.GetClothBufferForReading(false, FrameNumber).VertexBufferSRV); + ClothShaderData.GetClothBufferForReading(false, FrameNumber).VertexBufferSRV); } if(PreviousClothSimulVertsPositionsNormalsParameter.IsBound()) { RHICmdList.SetShaderResourceViewParameter(Shader->GetVertexShader(), PreviousClothSimulVertsPositionsNormalsParameter.GetBaseIndex(), - ClothShaderData.GetClothBufferForReading(true, FrameNumber).VertexBufferSRV); + ClothShaderData.GetClothBufferForReading(true, FrameNumber).VertexBufferSRV); } SetShaderValue( diff --git a/Engine/Source/Runtime/Engine/Private/GameEngine.cpp b/Engine/Source/Runtime/Engine/Private/GameEngine.cpp index d2b5a7622a2a..c6f105b23684 100644 --- a/Engine/Source/Runtime/Engine/Private/GameEngine.cpp +++ b/Engine/Source/Runtime/Engine/Private/GameEngine.cpp @@ -462,6 +462,11 @@ void UGameEngine::SwitchGameWindowToUseGameViewport() // Registration of the game viewport to that messages are correctly received. // Could be a re-register, however it's necessary after the window is set. FSlateApplication::Get().RegisterGameViewport(GameViewportWidgetRef); + + if (FSlateApplication::IsInitialized()) + { + FSlateApplication::Get().SetAllUserFocusToGameViewport(EFocusCause::SetDirectly); + } } } @@ -539,6 +544,8 @@ UEngine::UEngine(const FObjectInitializer& ObjectInitializer) FixedFrameRate = 30.f; bIsVanillaProduct = false; + + GameScreenshotSaveDirectory.Path = FPaths::ScreenShotDir(); } void UGameEngine::Init(IEngineLoop* InEngineLoop) @@ -736,7 +743,8 @@ bool UGameEngine::NetworkRemapPath(UNetDriver* Driver, FString& Str, bool bReadi // If the prefixed path matches the world package name or the name of a streaming level, // return the prefixed name. - const FString PackageNameOnly = FPackageName::PackageFromPath(*Str); + FString PackageNameOnly = Str; + FPackageName::TryConvertFilenameToLongPackageName(PackageNameOnly, PackageNameOnly); const FString PrefixedFullName = UWorld::ConvertToPIEPackageName(Str, Context.PIEInstance); const FString PrefixedPackageName = UWorld::ConvertToPIEPackageName(PackageNameOnly, Context.PIEInstance); @@ -1128,6 +1136,17 @@ void UGameEngine::Tick( float DeltaSeconds, bool bIdleMode ) TickWorldTravel(Context, DeltaSeconds); } + if (!bIdleMode) + { + SCOPE_TIME_GUARD(TEXT("UGameEngine::Tick - WorldTick")); + + // Tick the world. + GameCycles=0; + CLOCK_CYCLES(GameCycles); + Context.World()->Tick( LEVELTICK_All, DeltaSeconds ); + UNCLOCK_CYCLES(GameCycles); + } + if (!IsRunningDedicatedServer() && !IsRunningCommandlet()) { QUICK_SCOPE_CYCLE_COUNTER(STAT_UGameEngine_Tick_CheckCaptures); @@ -1141,16 +1160,7 @@ void UGameEngine::Tick( float DeltaSeconds, bool bIdleMode ) } } - if (!bIdleMode) - { - SCOPE_TIME_GUARD(TEXT("UGameEngine::Tick - WorldTick")); - // Tick the world. - GameCycles=0; - CLOCK_CYCLES(GameCycles); - Context.World()->Tick( LEVELTICK_All, DeltaSeconds ); - UNCLOCK_CYCLES(GameCycles); - } // Issue cause event after first tick to provide a chance for the game to spawn the player and such. if( Context.World()->bWorldWasLoadedThisTick ) diff --git a/Engine/Source/Runtime/Engine/Private/GameFramework/RootMotionSource.cpp b/Engine/Source/Runtime/Engine/Private/GameFramework/RootMotionSource.cpp index 75409f8d1453..1f980e80d6ed 100644 --- a/Engine/Source/Runtime/Engine/Private/GameFramework/RootMotionSource.cpp +++ b/Engine/Source/Runtime/Engine/Private/GameFramework/RootMotionSource.cpp @@ -7,6 +7,7 @@ #include "Curves/CurveVector.h" #include "Curves/CurveFloat.h" #include "Engine/Engine.h" +#include "GameFramework/PlayerController.h" #if ROOT_MOTION_DEBUG TAutoConsoleVariable RootMotionSourceDebug::CVarDebugRootMotionSources( @@ -25,12 +26,41 @@ static TAutoConsoleVariable CVarDebugRootMotionSourcesLifetime( void RootMotionSourceDebug::PrintOnScreen(const ACharacter& InCharacter, const FString& InString) { - const FString AdjustedDebugString = FString::Printf(TEXT("[%d] [%s] %s"), GFrameCounter, *InCharacter.GetName(), *InString); + // Skip bots, debug player networking. + if (InCharacter.IsPlayerControlled()) + { + const FString AdjustedDebugString = FString::Printf(TEXT("[%d] [%s] %s"), GFrameCounter, *InCharacter.GetName(), *InString); - const FColor DebugColor = (InCharacter.IsLocallyControlled()) ? FColor::Green : FColor::Red; - GEngine->AddOnScreenDebugMessage(INDEX_NONE, 0.f, DebugColor, AdjustedDebugString, false, FVector2D::UnitVector * 1.5f); + // If on the server, replicate this message to everyone. + if (!InCharacter.IsLocallyControlled() && (InCharacter.Role == ROLE_Authority)) + { + for (FConstPlayerControllerIterator Iterator = InCharacter.GetWorld()->GetPlayerControllerIterator(); Iterator; ++Iterator) + { + if (const APlayerController* const PlayerController = Iterator->Get()) + { + if (ACharacter* const Character = PlayerController->GetCharacter()) + { + Character->RootMotionDebugClientPrintOnScreen(AdjustedDebugString); + } + } + } + } + else + { + const FColor DebugColor = (InCharacter.IsLocallyControlled()) ? FColor::Green : FColor::Purple; + GEngine->AddOnScreenDebugMessage(INDEX_NONE, 0.f, DebugColor, AdjustedDebugString, false, FVector2D::UnitVector * 1.5f); - UE_LOG(LogRootMotion, Verbose, TEXT("%s"), *AdjustedDebugString); + UE_LOG(LogRootMotion, Verbose, TEXT("%s"), *AdjustedDebugString); + } + } +} + +void RootMotionSourceDebug::PrintOnScreenServerMsg(const FString& InString) +{ + const FColor DebugColor = FColor::Red; + GEngine->AddOnScreenDebugMessage(INDEX_NONE, 0.f, DebugColor, InString, false, FVector2D::UnitVector * 1.5f); + + UE_LOG(LogRootMotion, Verbose, TEXT("%s"), *InString); } #endif // !(UE_BUILD_SHIPPING || UE_BUILD_TEST) @@ -1106,7 +1136,7 @@ void FRootMotionSource_JumpForce::PrepareRootMotion // If we're beyond specified duration, we need to re-map times so that // we continue our desired ending velocity - if (CurrentTimeFraction > 1.f) + if (TargetTimeFraction > 1.f) { float TimeFractionPastAllowable = TargetTimeFraction - 1.0f; TargetTimeFraction -= TimeFractionPastAllowable; @@ -1122,10 +1152,10 @@ void FRootMotionSource_JumpForce::PrepareRootMotion TargetMoveFraction = TimeMappingCurve->GetFloatValue(TargetTimeFraction); } - FVector CurrentRelativeLocation = GetRelativeLocation(CurrentMoveFraction); - FVector TargetRelativeLocation = GetRelativeLocation(TargetMoveFraction); + const FVector CurrentRelativeLocation = GetRelativeLocation(CurrentMoveFraction); + const FVector TargetRelativeLocation = GetRelativeLocation(TargetMoveFraction); - FVector Force = (TargetRelativeLocation - CurrentRelativeLocation) / MovementTickTime; + const FVector Force = (TargetRelativeLocation - CurrentRelativeLocation) / MovementTickTime; // Debug #if ROOT_MOTION_DEBUG @@ -1171,10 +1201,16 @@ void FRootMotionSource_JumpForce::PrepareRootMotion GetTime(), GetTime() + SimulationTime, *CurrentLocation.ToString(), *CurrentTargetLocation.ToString(), *Force.ToString()); + + { + FString AdjustedDebugString = FString::Printf(TEXT(" FRootMotionSource_JumpForce::Prep Force(%s) SimTime(%.3f) MoveTime(%.3f) StartP(%.3f) EndP(%.3f)"), + *Force.ToCompactString(), SimulationTime, MovementTickTime, CurrentMoveFraction, TargetMoveFraction); + RootMotionSourceDebug::PrintOnScreen(Character, AdjustedDebugString); + } } #endif - FTransform NewTransform(Force); + const FTransform NewTransform(Force); RootMotionParams.Set(NewTransform); } else diff --git a/Engine/Source/Runtime/Engine/Private/GameFramework/SpringArmComponent.cpp b/Engine/Source/Runtime/Engine/Private/GameFramework/SpringArmComponent.cpp index 8b656c4e6f54..d5b46bbae30e 100644 --- a/Engine/Source/Runtime/Engine/Private/GameFramework/SpringArmComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/GameFramework/SpringArmComponent.cpp @@ -48,6 +48,18 @@ void USpringArmComponent::UpdateDesiredArmLocation(bool bDoTrace, bool bDoLocati { FRotator DesiredRot = GetComponentRotation(); + if (bUsePawnControlRotation) + { + if (APawn* OwningPawn = Cast(GetOwner())) + { + const FRotator PawnViewRotation = OwningPawn->GetViewRotation(); + if (DesiredRot != PawnViewRotation) + { + DesiredRot = PawnViewRotation; + } + } + } + // If inheriting rotation, check options for which components to inherit if(!bAbsoluteRotation) { @@ -157,8 +169,7 @@ void USpringArmComponent::UpdateDesiredArmLocation(bool bDoTrace, bool bDoLocati FVector ResultLoc; if (bDoTrace && (TargetArmLength != 0.0f)) { - static FName TraceTagName(TEXT("SpringArm")); - FCollisionQueryParams QueryParams(TraceTagName, false, GetOwner()); + FCollisionQueryParams QueryParams(SCENE_QUERY_STAT(SpringArm), false, GetOwner()); FHitResult Result; GetWorld()->SweepSingleByChannel(Result, ArmOrigin, DesiredLoc, FQuat::Identity, ProbeChannel, FCollisionShape::MakeSphere(ProbeSize), QueryParams); @@ -173,7 +184,7 @@ void USpringArmComponent::UpdateDesiredArmLocation(bool bDoTrace, bool bDoLocati // Form a transform for new world transform for camera FTransform WorldCamTM(DesiredRot, ResultLoc); // Convert to relative to component - FTransform RelCamTM = WorldCamTM.GetRelativeTransform(ComponentToWorld); + FTransform RelCamTM = WorldCamTM.GetRelativeTransform(GetComponentTransform()); // Update socket location/rotation RelativeSocketLocation = RelCamTM.GetLocation(); @@ -213,19 +224,6 @@ void USpringArmComponent::PostLoad() void USpringArmComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); - - if (bUsePawnControlRotation) - { - if (APawn* OwningPawn = Cast(GetOwner())) - { - const FRotator PawnViewRotation = OwningPawn->GetViewRotation(); - if (PawnViewRotation != GetComponentRotation()) - { - SetWorldRotation(PawnViewRotation); - } - } - } - UpdateDesiredArmLocation(bDoCollisionTest, bEnableCameraLag, bEnableCameraRotationLag, DeltaTime); } @@ -237,14 +235,14 @@ FTransform USpringArmComponent::GetSocketTransform(FName InSocketName, ERelative { case RTS_World: { - return RelativeTransform * ComponentToWorld; + return RelativeTransform * GetComponentTransform(); break; } case RTS_Actor: { if( const AActor* Actor = GetOwner() ) { - FTransform SocketTransform = RelativeTransform * ComponentToWorld; + FTransform SocketTransform = RelativeTransform * GetComponentTransform(); return SocketTransform.GetRelativeTransform(Actor->GetTransform()); } break; diff --git a/Engine/Source/Runtime/Engine/Private/GameInstance.cpp b/Engine/Source/Runtime/Engine/Private/GameInstance.cpp index 67427ec394dc..8d96cc68181e 100644 --- a/Engine/Source/Runtime/Engine/Private/GameInstance.cpp +++ b/Engine/Source/Runtime/Engine/Private/GameInstance.cpp @@ -246,6 +246,8 @@ bool UGameInstance::InitializePIE(bool bAnyBlueprintErrors, int32 PIEInstance, b FGameInstancePIEResult UGameInstance::StartPlayInEditorGameInstance(ULocalPlayer* LocalPlayer, const FGameInstancePIEParameters& Params) { + OnStart(); + UEditorEngine* const EditorEngine = CastChecked(GetEngine()); ULevelEditorPlaySettings const* PlayInSettings = GetDefault(); @@ -456,6 +458,13 @@ void UGameInstance::StartGameInstance() FPlatformMisc::RequestExit(false); return; } + + OnStart(); +} + +void UGameInstance::OnStart() +{ + } bool UGameInstance::HandleOpenCommand(const TCHAR* Cmd, FOutputDevice& Ar, UWorld* InWorld) diff --git a/Engine/Source/Runtime/Engine/Private/GameMode.cpp b/Engine/Source/Runtime/Engine/Private/GameMode.cpp index 085368c1e0f5..ab5f8a5b1d55 100644 --- a/Engine/Source/Runtime/Engine/Private/GameMode.cpp +++ b/Engine/Source/Runtime/Engine/Private/GameMode.cpp @@ -169,6 +169,8 @@ void AGameMode::HandleMatchIsWaitingToStart() } } +/// @cond DOXYGEN_WARNINGS + bool AGameMode::ReadyToStartMatch_Implementation() { // If bDelayed Start is set, wait for a manual match start @@ -188,6 +190,8 @@ bool AGameMode::ReadyToStartMatch_Implementation() return false; } +/// @endcond + void AGameMode::StartMatch() { if (HasMatchStarted()) @@ -249,12 +253,16 @@ void AGameMode::HandleMatchHasStarted() } } +/// @cond DOXYGEN_WARNINGS + bool AGameMode::ReadyToEndMatch_Implementation() { // By default don't explicitly end match return false; } +/// @endcond + void AGameMode::EndMatch() { if (!IsMatchInProgress()) @@ -800,11 +808,6 @@ bool AGameMode::IsHandlingReplays() return bHandleDedicatedServerReplays && GetNetMode() == ENetMode::NM_DedicatedServer; } -void AGameMode::SetBandwidthLimit(float AsyncIOBandwidthLimit) -{ - GAsyncIOBandwidthLimit = AsyncIOBandwidthLimit; -} - void AGameMode::MatineeCancelled() {} void AGameMode::PreCommitMapChange(const FString& PreviousMapName, const FString& NextMapName) {} diff --git a/Engine/Source/Runtime/Engine/Private/GameModeBase.cpp b/Engine/Source/Runtime/Engine/Private/GameModeBase.cpp index 01280a820175..8509bab20ee2 100644 --- a/Engine/Source/Runtime/Engine/Private/GameModeBase.cpp +++ b/Engine/Source/Runtime/Engine/Private/GameModeBase.cpp @@ -127,11 +127,15 @@ TSubclassOf AGameModeBase::GetGameSessionClass() const return AGameSession::StaticClass(); } +/// @cond DOXYGEN_WARNINGS + UClass* AGameModeBase::GetDefaultPawnClassForController_Implementation(AController* InController) { return DefaultPawnClass; } +/// @endcond + int32 AGameModeBase::GetNumPlayers() { int32 PlayerCount = 0; @@ -290,11 +294,15 @@ void AGameModeBase::Reset() InitGameState(); } +/// @cond DOXYGEN_WARNINGS + bool AGameModeBase::ShouldReset_Implementation(AActor* ActorToReset) { return true; } +/// @endcond + void AGameModeBase::ResetLevel() { UE_LOG(LogGameMode, Verbose, TEXT("Reset %s"), *GetName()); @@ -799,12 +807,16 @@ bool AGameModeBase::ShouldStartInCinematicMode(APlayerController* Player, bool& return false; } +/// @cond DOXYGEN_WARNINGS + void AGameModeBase::InitializeHUDForPlayer_Implementation(APlayerController* NewPlayer) { // Tell client what HUD class to use NewPlayer->ClientSetHUD(HUDClass); } +/// @endcond + void AGameModeBase::UpdateGameplayMuteList(APlayerController* aPlayer) { if (aPlayer) @@ -966,6 +978,8 @@ void AGameModeBase::Logout(AController* Exiting) } } +/// @cond DOXYGEN_WARNINGS + void AGameModeBase::HandleStartingNewPlayer_Implementation(APlayerController* NewPlayer) { // If players should start as spectators, leave them in the spectator state @@ -1037,11 +1051,15 @@ AActor* AGameModeBase::ChoosePlayerStart_Implementation(AController* Player) return FoundPlayerStart; } +/// @endcond + bool AGameModeBase::ShouldSpawnAtStartSpot(AController* Player) { return (Player != nullptr && Player->StartSpot != nullptr); } +/// @cond DOXYGEN_WARNINGS + AActor* AGameModeBase::FindPlayerStart_Implementation(AController* Player, const FString& IncomingName) { UWorld* World = GetWorld(); @@ -1087,11 +1105,15 @@ AActor* AGameModeBase::FindPlayerStart_Implementation(AController* Player, const return BestStart; } +/// @endcond + AActor* AGameModeBase::K2_FindPlayerStart(AController* Player, const FString& IncomingName) { return FindPlayerStart(Player, IncomingName); } +/// @cond DOXYGEN_WARNINGS + bool AGameModeBase::PlayerCanRestart_Implementation(APlayerController* Player) { if (Player == nullptr || Player->IsPendingKillPending()) @@ -1128,6 +1150,8 @@ APawn* AGameModeBase::SpawnDefaultPawnAtTransform_Implementation(AController* Ne return ResultPawn; } +/// @endcond + void AGameModeBase::RestartPlayer(AController* NewPlayer) { if (NewPlayer == nullptr || NewPlayer->IsPendingKillPending()) @@ -1166,7 +1190,7 @@ void AGameModeBase::RestartPlayerAtPlayerStart(AController* NewPlayer, AActor* S FRotator SpawnRotation = StartSpot->GetActorRotation(); - UE_LOG(LogGameMode, Verbose, TEXT("RestartPlayerAtPlayerStart %s"), (NewPlayer && NewPlayer->PlayerState) ? *NewPlayer->PlayerState->PlayerName : TEXT("Unknown")); + UE_LOG(LogGameMode, Verbose, TEXT("RestartPlayerAtPlayerStart %s"), NewPlayer->PlayerState ? *NewPlayer->PlayerState->PlayerName : TEXT("Unknown")); if (MustSpectate(Cast(NewPlayer))) { @@ -1205,7 +1229,7 @@ void AGameModeBase::RestartPlayerAtTransform(AController* NewPlayer, const FTran return; } - UE_LOG(LogGameMode, Verbose, TEXT("RestartPlayerAtTransform %s"), (NewPlayer && NewPlayer->PlayerState) ? *NewPlayer->PlayerState->PlayerName : TEXT("Unknown")); + UE_LOG(LogGameMode, Verbose, TEXT("RestartPlayerAtTransform %s"), NewPlayer->PlayerState ? *NewPlayer->PlayerState->PlayerName : TEXT("Unknown")); if (MustSpectate(Cast(NewPlayer))) { @@ -1260,11 +1284,16 @@ void AGameModeBase::FinishRestartPlayer(AController* NewPlayer, const FRotator& } } +/// @cond DOXYGEN_WARNINGS + void AGameModeBase::InitStartSpot_Implementation(AActor* StartSpot, AController* NewPlayer) { } +/// @endcond + + void AGameModeBase::SetPlayerDefaults(APawn* PlayerPawn) { PlayerPawn->SetPlayerDefaults(); diff --git a/Engine/Source/Runtime/Engine/Private/GameState.cpp b/Engine/Source/Runtime/Engine/Private/GameState.cpp index 2da60f2f9a13..f297628bf199 100644 --- a/Engine/Source/Runtime/Engine/Private/GameState.cpp +++ b/Engine/Source/Runtime/Engine/Private/GameState.cpp @@ -181,6 +181,8 @@ float AGameState::GetPlayerRespawnDelay(class AController* Controller) const return Super::GetPlayerRespawnDelay(Controller); } +/// @cond DOXYGEN_WARNINGS + void AGameState::GetLifetimeReplicatedProps( TArray< FLifetimeProperty > & OutLifetimeProps ) const { Super::GetLifetimeReplicatedProps( OutLifetimeProps ); @@ -188,3 +190,5 @@ void AGameState::GetLifetimeReplicatedProps( TArray< FLifetimeProperty > & OutLi DOREPLIFETIME( AGameState, MatchState ); DOREPLIFETIME_CONDITION( AGameState, ElapsedTime, COND_InitialOnly ); } + +/// @endcond diff --git a/Engine/Source/Runtime/Engine/Private/GameUserSettings.cpp b/Engine/Source/Runtime/Engine/Private/GameUserSettings.cpp index 3334be16197d..47fefb0c48bb 100644 --- a/Engine/Source/Runtime/Engine/Private/GameUserSettings.cpp +++ b/Engine/Source/Runtime/Engine/Private/GameUserSettings.cpp @@ -289,11 +289,7 @@ float UGameUserSettings::FindResolutionQualityForScreenSize(float Width, float H void UGameUserSettings::SetFrameRateLimitCVar(float InLimit) { - static IConsoleVariable* MaxFPSCVar = IConsoleManager::Get().FindConsoleVariable(TEXT("t.MaxFPS")); - if (ensure(MaxFPSCVar)) - { - MaxFPSCVar->Set(FMath::Max(InLimit, 0.0f), ECVF_SetByGameSetting); - } + GEngine->SetMaxFPS(FMath::Max(InLimit, 0.0f)); } float UGameUserSettings::GetEffectiveFrameRateLimit() diff --git a/Engine/Source/Runtime/Engine/Private/GameViewportClient.cpp b/Engine/Source/Runtime/Engine/Private/GameViewportClient.cpp index b5953c2d2aee..fd2cf235a1f0 100644 --- a/Engine/Source/Runtime/Engine/Private/GameViewportClient.cpp +++ b/Engine/Source/Runtime/Engine/Private/GameViewportClient.cpp @@ -39,7 +39,6 @@ #include "AudioDevice.h" #include "Sound/SoundWave.h" #include "HighResScreenshot.h" -#include "Runtime/GameLiveStreaming/Public/IGameLiveStreaming.h" #include "BufferVisualizationData.h" #include "GameFramework/InputSettings.h" #include "Components/LineBatchComponent.h" @@ -138,7 +137,7 @@ UGameViewportClient::UGameViewportClient(const FObjectInitializer& ObjectInitial , MouseLockMode(EMouseLockMode::LockOnCapture) , AudioDeviceHandle(INDEX_NONE) , bHasAudioFocus(false) - , bMouseEnter(false) + , bIsMouseOverClient(false) { TitleSafeZone.MaxPercentX = 0.9f; @@ -218,15 +217,14 @@ UGameViewportClient::~UGameViewportClient() delete StatHitchesData; StatHitchesData = NULL; } + if (StatUnitData) { delete StatUnitData; StatUnitData = NULL; } - } - void UGameViewportClient::PostInitProperties() { Super::PostInitProperties(); @@ -248,10 +246,10 @@ void UGameViewportClient::BeginDestroy() Super::BeginDestroy(); } - void UGameViewportClient::DetachViewportClient() { ViewportConsole = NULL; + ResetHardwareCursorStates(); RemoveAllViewportWidgets(); RemoveFromRoot(); } @@ -261,6 +259,12 @@ FSceneViewport* UGameViewportClient::GetGameViewport() return static_cast(Viewport); } +const FSceneViewport* UGameViewportClient::GetGameViewport() const +{ + return static_cast(Viewport); +} + + TSharedPtr UGameViewportClient::GetGameViewportWidget() { FSceneViewport* SceneViewport = GetGameViewport(); @@ -363,6 +367,22 @@ void UGameViewportClient::Init(struct FWorldContext& WorldContext, UGameInstance } } +void UGameViewportClient::RebuildCursors() +{ + UUserInterfaceSettings* UISettings = GetMutableDefault(UUserInterfaceSettings::StaticClass()); + // Set all the software cursors. + for (auto& Entry : UISettings->SoftwareCursors) + { + AddSoftwareCursor(Entry.Key, Entry.Value); + } + + // Set all the hardware cursors. + for (auto& Entry : UISettings->HardwareCursors) + { + SetHardwareCursor(Entry.Key, Entry.Value.CursorPath, Entry.Value.HotSpot); + } +} + UWorld* UGameViewportClient::GetWorld() const { return World; @@ -569,10 +589,12 @@ bool UGameViewportClient::InputMotion(FViewport* InViewport, int32 ControllerId, void UGameViewportClient::SetIsSimulateInEditorViewport(bool bInIsSimulateInEditorViewport) { +#if PLATFORM_DESKTOP if (GetDefault()->bUseMouseForTouch) { FSlateApplication::Get().SetGameIsFakingTouchEvents(!bInIsSimulateInEditorViewport); } +#endif for (ULocalPlayer* LocalPlayer : GetOuterUEngine()->GetGamePlayers(this)) { @@ -594,10 +616,12 @@ void UGameViewportClient::MouseEnter(FViewport* InViewport, int32 x, int32 y) { Super::MouseEnter(InViewport, x, y); +#if PLATFORM_DESKTOP if (GetDefault()->bUseMouseForTouch && !GetGameViewport()->GetPlayInEditorIsSimulate()) { FSlateApplication::Get().SetGameIsFakingTouchEvents(true); } +#endif // Replace all the cursors. TSharedPtr PlatformCursor = FSlateApplication::Get().GetPlatformCursor(); @@ -609,7 +633,7 @@ void UGameViewportClient::MouseEnter(FViewport* InViewport, int32 x, int32 y) } } - bMouseEnter = true; + bIsMouseOverClient = true; } void UGameViewportClient::MouseLeave(FViewport* InViewport) @@ -623,34 +647,41 @@ void UGameViewportClient::MouseLeave(FViewport* InViewport) { FIntPoint LastViewportCursorPos; InViewport->GetMousePos(LastViewportCursorPos, false); + +#if PLATFORM_DESKTOP FVector2D CursorPos(LastViewportCursorPos.X, LastViewportCursorPos.Y); FSlateApplication::Get().SetGameIsFakingTouchEvents(false, &CursorPos); +#endif } } #if WITH_EDITOR - bMouseEnter = true; - // NOTE: Only do this in editor builds where the editor is running. // We don't care about bothering to clear them otherwise, and it may negatively impact // things like drag/drop, since those would 'leave' the viewport. if ( !FSlateApplication::Get().IsDragDropping() ) { - // clear all the overridden hardware cursors - TSharedPtr PlatformCursor = FSlateApplication::Get().GetPlatformCursor(); - if ( ICursor* Cursor = PlatformCursor.Get() ) - { - for ( auto& Entry : HardwareCursors ) - { - Cursor->SetTypeShape(Entry.Key, nullptr); - } - } + bIsMouseOverClient = false; + ResetHardwareCursorStates(); } #endif } +void UGameViewportClient::ResetHardwareCursorStates() +{ + // clear all the overridden hardware cursors + TSharedPtr PlatformCursor = FSlateApplication::Get().GetPlatformCursor(); + if (ICursor* Cursor = PlatformCursor.Get()) + { + for (auto& Entry : HardwareCursors) + { + Cursor->SetTypeShape(Entry.Key, nullptr); + } + } +} + bool UGameViewportClient::GetMousePosition(FVector2D& MousePosition) const { bool bGotMousePosition = false; @@ -717,20 +748,24 @@ EMouseCursor::Type UGameViewportClient::GetCursor(FViewport* InViewport, int32 X void UGameViewportClient::AddSoftwareCursor(EMouseCursor::Type Cursor, const FStringClassReference& CursorClass) { - if ( CursorClass.IsValid() ) + if (ensureMsgf(CursorClass.IsValid(), TEXT("UGameViewportClient::AddCusor: Cursor class is not valid!"))) { UClass* Class = CursorClass.TryLoadClass(); - if ( Class ) + if (Class) { UUserWidget* UserWidget = CreateWidget(GetGameInstance(), Class); - if ( ensure(UserWidget) ) + if (UserWidget) { CursorWidgets.Add(Cursor, UserWidget->TakeWidget()); } + else + { + UE_LOG(LogPlayerManagement, Warning, TEXT("UGameViewportClient::AddCursor: Could not create cursor widget.")); + } } else { - FMessageLog("PIE").Error(FText::Format(LOCTEXT("CursorClassNotFoundFormat", "The cursor class '{0}' was not found, check your custom cursor settings."), FText::FromString(CursorClass.ToString()))); + UE_LOG(LogPlayerManagement, Warning, TEXT("UGameViewportClient::AddCursor: Could not load cursor class %s."), *CursorClass.GetAssetName()); } } } @@ -739,13 +774,20 @@ TOptional> UGameViewportClient::MapCursor(FViewport* InViewp { if (bUseSoftwareCursorWidgets) { - const TSharedRef* CursorWidgetPtr = CursorWidgets.Find(CursorReply.GetCursorType()); - if (CursorWidgetPtr != nullptr) + if (CursorReply.GetCursorType() != EMouseCursor::None) { - return *CursorWidgetPtr; + const TSharedRef* CursorWidgetPtr = CursorWidgets.Find(CursorReply.GetCursorType()); + + if (CursorWidgetPtr != nullptr) + { + return *CursorWidgetPtr; + } + else + { + UE_LOG(LogPlayerManagement, Warning, TEXT("UGameViewportClient::MapCursor: Could not find cursor to map to %d."),int32(CursorReply.GetCursorType())); + } } } - return TOptional>(); } @@ -1195,7 +1237,7 @@ void UGameViewportClient::Draw(FViewport* InViewport, FCanvas* SceneCanvas) bool bBufferCleared = false; if ( ViewFamily.Views.Num() == 0 || TotalArea != (MaxX-MinX)*(MaxY-MinY) || bDisableWorldRendering ) { - SceneCanvas->DrawTile(0,0,InViewport->GetSizeXY().X,InViewport->GetSizeXY().Y,0.0f,0.0f,1.0f,1.f,FLinearColor::Black,NULL,false); + SceneCanvas->Clear(FLinearColor::Black); bBufferCleared = true; } @@ -1345,7 +1387,7 @@ void UGameViewportClient::Draw(FViewport* InViewport, FCanvas* SceneCanvas) PostRender(DebugCanvasObject); // Render the console. - if (ViewportConsole) + if (ViewportConsole && DebugCanvas) { // Reset the debug canvas to be full-screen before drawing the console // (the debug draw service above has messed with the viewport size to fit it to a single player's subregion) @@ -1525,10 +1567,12 @@ void UGameViewportClient::LostFocus(FViewport* InViewport) void UGameViewportClient::ReceivedFocus(FViewport* InViewport) { +#if PLATFORM_DESKTOP if (GetDefault()->bUseMouseForTouch && GetGameViewport() && !GetGameViewport()->GetPlayInEditorIsSimulate()) { FSlateApplication::Get().SetGameIsFakingTouchEvents(true); } +#endif if (GEngine && GEngine->GetAudioDeviceManager()) { @@ -1561,7 +1605,9 @@ void UGameViewportClient::CloseRequested(FViewport* InViewport) { check(InViewport == Viewport); +#if PLATFORM_DESKTOP FSlateApplication::Get().SetGameIsFakingTouchEvents(false); +#endif // broadcast close request to anyone that registered an interest CloseRequestedDelegate.Broadcast(InViewport); @@ -1590,10 +1636,6 @@ void UGameViewportClient::PostRender(UCanvas* Canvas) // Draw the transition screen. DrawTransition(Canvas); - - // Draw default web cam. This only will draw something if a web camera is currently enabled in the live streaming settings - // and the user has activated it. Also, the game may override this functionality entirely, and draw the web cam video itself. - IGameLiveStreaming::Get().DrawSimpleWebCamVideo( Canvas ); } void UGameViewportClient::PeekTravelFailureMessages(UWorld* InWorld, ETravelFailure::Type FailureType, const FString& ErrorString) @@ -3264,9 +3306,8 @@ bool UGameViewportClient::SetHardwareCursor(EMouseCursor::Type CursorShape, FNam HardwareCursors.Add(CursorShape, HardwareCursor); - if ( bMouseEnter ) + if ( bIsMouseOverClient ) { - // clear all the overridden hardware cursors TSharedPtr PlatformCursor = FSlateApplication::Get().GetPlatformCursor(); if ( ICursor* Cursor = PlatformCursor.Get() ) { @@ -3277,4 +3318,11 @@ bool UGameViewportClient::SetHardwareCursor(EMouseCursor::Type CursorShape, FNam return true; } +bool UGameViewportClient::IsSimulateInEditorViewport() const +{ + const FSceneViewport* GameViewport = GetGameViewport(); + + return GameViewport ? GameViewport->GetPlayInEditorIsSimulate() : false; +} + #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Runtime/Engine/Private/GameplayStatics.cpp b/Engine/Source/Runtime/Engine/Private/GameplayStatics.cpp index 673b5fb6e730..835836c40e0e 100644 --- a/Engine/Source/Runtime/Engine/Private/GameplayStatics.cpp +++ b/Engine/Source/Runtime/Engine/Private/GameplayStatics.cpp @@ -225,8 +225,7 @@ bool UGameplayStatics::IsGamePaused(const UObject* WorldContextObject) /** @RETURN True if weapon trace from Origin hits component VictimComp. OutHitResult will contain properties of the hit. */ static bool ComponentIsDamageableFrom(UPrimitiveComponent* VictimComp, FVector const& Origin, AActor const* IgnoredActor, const TArray& IgnoreActors, ECollisionChannel TraceChannel, FHitResult& OutHitResult) { - static FName NAME_ComponentIsVisibleFrom = FName(TEXT("ComponentIsVisibleFrom")); - FCollisionQueryParams LineParams(NAME_ComponentIsVisibleFrom, true, IgnoredActor); + FCollisionQueryParams LineParams(SCENE_QUERY_STAT(ComponentIsVisibleFrom), true, IgnoredActor); LineParams.AddIgnoredActors( IgnoreActors ); // Do a trace from origin to middle of box @@ -275,8 +274,7 @@ bool UGameplayStatics::ApplyRadialDamage(const UObject* WorldContextObject, floa bool UGameplayStatics::ApplyRadialDamageWithFalloff(const UObject* WorldContextObject, float BaseDamage, float MinimumDamage, const FVector& Origin, float DamageInnerRadius, float DamageOuterRadius, float DamageFalloff, TSubclassOf DamageTypeClass, const TArray& IgnoreActors, AActor* DamageCauser, AController* InstigatedByController, ECollisionChannel DamagePreventionChannel) { - static FName NAME_ApplyRadialDamage = FName(TEXT("ApplyRadialDamage")); - FCollisionQueryParams SphereParams(NAME_ApplyRadialDamage, false, DamageCauser); + FCollisionQueryParams SphereParams(SCENE_QUERY_STAT(ApplyRadialDamage), false, DamageCauser); SphereParams.AddIgnoredActors(IgnoreActors); @@ -1590,6 +1588,56 @@ USaveGame* UGameplayStatics::CreateSaveGameObjectFromBlueprint(UBlueprint* SaveG return nullptr; } +bool UGameplayStatics::SaveGameToMemory(USaveGame* SaveGameObject, TArray& OutSaveData ) +{ + FMemoryWriter MemoryWriter(OutSaveData, true); + + // write file type tag. identifies this file type and indicates it's using proper versioning + // since older UE4 versions did not version this data. + int32 FileTypeTag = UE4_SAVEGAME_FILE_TYPE_TAG; + MemoryWriter << FileTypeTag; + + // Write version for this file format + int32 SavegameFileVersion = FSaveGameFileVersion::LatestVersion; + MemoryWriter << SavegameFileVersion; + + // Write out engine and UE4 version information + int32 PackageFileUE4Version = GPackageFileUE4Version; + MemoryWriter << PackageFileUE4Version; + FEngineVersion SavedEngineVersion = FEngineVersion::Current(); + MemoryWriter << SavedEngineVersion; + + // Write out custom version data + ECustomVersionSerializationFormat::Type const CustomVersionFormat = ECustomVersionSerializationFormat::Latest; + int32 CustomVersionFormatInt = static_cast(CustomVersionFormat); + MemoryWriter << CustomVersionFormatInt; + FCustomVersionContainer CustomVersions = FCustomVersionContainer::GetRegistered(); + CustomVersions.Serialize(MemoryWriter, CustomVersionFormat); + + // Write the class name so we know what class to load to + FString SaveGameClassName = SaveGameObject->GetClass()->GetName(); + MemoryWriter << SaveGameClassName; + + // Then save the object state, replacing object refs and names with strings + FObjectAndNameAsStringProxyArchive Ar(MemoryWriter, false); + SaveGameObject->Serialize(Ar); + + return true; // Not sure if there's a failure case here. +} + +bool UGameplayStatics::SaveDataToSlot(const TArray& InSaveData, const FString& SlotName, const int32 UserIndex) +{ + ISaveGameSystem* SaveSystem = IPlatformFeaturesModule::Get().GetSaveGameSystem(); + + if (SaveSystem && InSaveData.Num() > 0 && SlotName.Len() > 0) + { + // Stuff that data into the save system with the desired file name + return SaveSystem->SaveGame(false, *SlotName, UserIndex, InSaveData); + } + + return false; +} + bool UGameplayStatics::SaveGameToSlot(USaveGame* SaveGameObject, const FString& SlotName, const int32 UserIndex) { ISaveGameSystem* SaveSystem = IPlatformFeaturesModule::Get().GetSaveGameSystem(); @@ -1793,8 +1841,6 @@ bool UGameplayStatics::BlueprintSuggestProjectileVelocity(const UObject* WorldCo } // note: this will automatically fall back to line test if radius is small enough -static const FName NAME_SuggestProjVelTrace = FName(TEXT("SuggestProjVelTrace")); - // Based on analytic solution to ballistic angle of launch http://en.wikipedia.org/wiki/Trajectory_of_a_projectile#Angle_required_to_hit_coordinate_.28x.2Cy.29 bool UGameplayStatics::SuggestProjectileVelocity(const UObject* WorldContextObject, FVector& OutTossVelocity, FVector Start, FVector End, float TossSpeed, bool bFavorHighArc, float CollisionRadius, float OverrideGravityZ, ESuggestProjVelocityTraceOption::Type TraceOption, const FCollisionResponseParams& ResponseParam, const TArray& ActorsToIgnore, bool bDrawDebug) { @@ -1920,7 +1966,7 @@ bool UGameplayStatics::SuggestProjectileVelocity(const UObject* WorldContextObje } else { - FCollisionQueryParams QueryParams(NAME_SuggestProjVelTrace, true); + FCollisionQueryParams QueryParams(SCENE_QUERY_STAT(SuggestProjVelTrace), true); QueryParams.AddIgnoredActors(ActorsToIgnore); if (World->SweepTestByChannel(TraceStart, TraceEnd, FQuat::Identity, ECC_WorldDynamic, FCollisionShape::MakeSphere(CollisionRadius), QueryParams, ResponseParam)) { @@ -1969,9 +2015,6 @@ bool UGameplayStatics::SuggestProjectileVelocity(const UObject* WorldContextObje return bFoundAValidSolution; } - -static const FName NAME_PredictProjectilePath = FName(TEXT("PredictProjectilePath")); - // note: this will automatically fall back to line test if radius is small enough bool UGameplayStatics::PredictProjectilePath(const UObject* WorldContextObject, const FPredictProjectilePathParams& PredictParams, FPredictProjectilePathResult& PredictResult) { @@ -1985,7 +2028,7 @@ bool UGameplayStatics::PredictProjectilePath(const UObject* WorldContextObject, const float GravityZ = FMath::IsNearlyEqual(PredictParams.OverrideGravityZ, 0.0f) ? World->GetGravityZ() : PredictParams.OverrideGravityZ; const float ProjectileRadius = PredictParams.ProjectileRadius; - FCollisionQueryParams QueryParams(NAME_PredictProjectilePath, PredictParams.bTraceComplex); + FCollisionQueryParams QueryParams(SCENE_QUERY_STAT(PredictProjectilePath), PredictParams.bTraceComplex); FCollisionObjectQueryParams ObjQueryParams; const bool bTraceWithObjectType = (PredictParams.ObjectTypes.Num() > 0); const bool bTracePath = PredictParams.bTraceWithCollision && (PredictParams.bTraceWithChannel || bTraceWithObjectType); diff --git a/Engine/Source/Editor/EditorLiveStreaming/EditorLiveStreamingModule.h b/Engine/Source/Runtime/Engine/Private/GenericQuadTree.cpp similarity index 50% rename from Engine/Source/Editor/EditorLiveStreaming/EditorLiveStreamingModule.h rename to Engine/Source/Runtime/Engine/Private/GenericQuadTree.cpp index cd30d5149b8b..b9759eb3d939 100644 --- a/Engine/Source/Editor/EditorLiveStreaming/EditorLiveStreamingModule.h +++ b/Engine/Source/Runtime/Engine/Private/GenericQuadTree.cpp @@ -1,4 +1,5 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#pragma once +#include "GenericQuadTree.h" +DEFINE_LOG_CATEGORY(LogQuadTree); diff --git a/Engine/Source/Runtime/Engine/Private/HUD.cpp b/Engine/Source/Runtime/Engine/Private/HUD.cpp index 90cef9053402..22ad92f99727 100644 --- a/Engine/Source/Runtime/Engine/Private/HUD.cpp +++ b/Engine/Source/Runtime/Engine/Private/HUD.cpp @@ -423,7 +423,7 @@ void AHUD::ShowDebugInfo(float& YL, float& YPos) { FRotator CamRot; FVector CamLoc; PlayerOwner->GetPlayerViewPoint(CamLoc, CamRot); - FCollisionQueryParams TraceParams(NAME_None, true, PlayerOwner->PlayerCameraManager->ViewTarget.Target); + FCollisionQueryParams TraceParams(NAME_None, FCollisionQueryParams::GetUnknownStatId(), true, PlayerOwner->PlayerCameraManager->ViewTarget.Target); FHitResult Hit; bool bHit = GetWorld()->LineTraceSingleByChannel(Hit, CamLoc, CamRot.Vector() * 100000.f + CamLoc, ECC_WorldDynamic, TraceParams); if (bHit) @@ -590,6 +590,8 @@ void AHUD::DrawDebugTextList() } } +/// @cond DOXYGEN_WARNINGS + void AHUD::AddDebugText_Implementation(const FString& DebugText, AActor* SrcActor, float Duration, @@ -682,6 +684,8 @@ void AHUD::RemoveAllDebugStrings_Implementation() DebugTextList.Reset(); } +/// @endcond + void AHUD::NotifyHitBoxClick(FName BoxName) { // dispatch BP event diff --git a/Engine/Source/Runtime/Engine/Private/HierarchicalInstancedStaticMesh.cpp b/Engine/Source/Runtime/Engine/Private/HierarchicalInstancedStaticMesh.cpp index 55e0bdcb65fb..7c903c07fb2f 100644 --- a/Engine/Source/Runtime/Engine/Private/HierarchicalInstancedStaticMesh.cpp +++ b/Engine/Source/Runtime/Engine/Private/HierarchicalInstancedStaticMesh.cpp @@ -386,17 +386,10 @@ public: } TArray& SortedInstances = Result->SortedInstances; - SortedInstances.AddUninitialized(Num); - for (int32 Index = 0; Index < Num; Index++) - { - SortedInstances[Index] = SortIndex[Index]; - } + SortedInstances.Append(SortIndex); + NumRoots = Clusters.Num(); - Result->Nodes.Reserve(Clusters.Num()); - for (int32 Index = 0; Index < NumRoots; Index++) - { - Result->Nodes.Add(FClusterNode()); - } + Result->Nodes.Init(FClusterNode(), Clusters.Num()); for (int32 Index = 0; Index < NumRoots; Index++) { @@ -858,7 +851,7 @@ public: //int32 NumPerNode = (1 + ClusterTree[0].LastInstance - ClusterTree[0].FirstInstance) / NumNodes; //UE_LOG(LogTemp, Display, TEXT("Occlusion level %d %d inst / node"), NumNodes, NumPerNode); OcclusionBounds.Reserve(NumNodes); - FMatrix XForm = InComponent->ComponentToWorld.ToMatrixWithScale(); + FMatrix XForm = InComponent->GetComponentTransform().ToMatrixWithScale(); for (int32 Index = FirstOcclusionNode; Index <= LastOcclusionNode; Index++) { OcclusionBounds.Add(FBoxSphereBounds(FBox(ClusterTree[Index].BoundMin, ClusterTree[Index].BoundMax).TransformBy(XForm))); @@ -1766,6 +1759,7 @@ UHierarchicalInstancedStaticMeshComponent::UHierarchicalInstancedStaticMeshCompo , bIsAsyncBuilding(false) , bDiscardAsyncBuildResults(false) , bConcurrentRemoval(false) + , bAutoRebuildTreeOnInstanceChanges(true) , AccumulatedNavigationDirtyArea(ForceInit) { bCanEverAffectNavigation = true; @@ -1918,14 +1912,17 @@ bool UHierarchicalInstancedStaticMeshComponent::RemoveInstances(const TArrayGetBounds().GetBox().TransformBy(InstanceTransform); - UnbuiltInstanceBounds += NewInstanceBounds; - UnbuiltInstanceBoundsList.Add(NewInstanceBounds); - } + const FBox NewInstanceBounds = GetStaticMesh()->GetBounds().GetBox().TransformBy(InstanceTransform); + UnbuiltInstanceBounds += NewInstanceBounds; + UnbuiltInstanceBoundsList.Add(NewInstanceBounds); } return InstanceIndex; @@ -2196,6 +2200,7 @@ void UHierarchicalInstancedStaticMeshComponent::BuildTree() ClusterTreePtr = MakeShareable(new TArray(MoveTemp(Builder.Result->Nodes))); InstanceReorderTable = MoveTemp(Builder.Result->InstanceReorderTable); SortedInstances = MoveTemp(Builder.Result->SortedInstances); + CacheMeshExtendedBounds = GetStaticMesh()->GetBounds(); FlushAccumulatedNavigationUpdates(); @@ -2212,6 +2217,7 @@ void UHierarchicalInstancedStaticMeshComponent::BuildTree() UnbuiltInstanceBoundsList.Empty(); BuiltInstanceBounds.Init(); + CacheMeshExtendedBounds = FBoxSphereBounds(); } if (bIsAsyncBuilding) @@ -2334,6 +2340,7 @@ void UHierarchicalInstancedStaticMeshComponent::ApplyBuildTreeAsync(ENamedThread TArray& ClusterTree = *ClusterTreePtr; InstanceReorderTable = MoveTemp(Builder->Result->InstanceReorderTable); SortedInstances = MoveTemp(Builder->Result->SortedInstances); + CacheMeshExtendedBounds = GetStaticMesh()->GetBounds(); RemovedInstances.Empty(); OcclusionLayerNumNodes = Builder->Result->OutOcclusionLayerNum; BuiltInstanceBounds = (ClusterTree.Num() > 0 ? FBox(ClusterTree[0].BoundMin, ClusterTree[0].BoundMax) : FBox(ForceInit)); @@ -2361,6 +2368,39 @@ void UHierarchicalInstancedStaticMeshComponent::ApplyBuildTreeAsync(ENamedThread } } +void UHierarchicalInstancedStaticMeshComponent::BuildTreeIfOutdated(bool Async, bool ForceUpdate) +{ + if (ForceUpdate + || InstanceReorderTable.Num() != PerInstanceSMData.Num() + || NumBuiltInstances != PerInstanceSMData.Num() + || (GetStaticMesh() != nullptr && CacheMeshExtendedBounds != GetStaticMesh()->GetBounds()) + || UnbuiltInstanceBoundsList.Num() > 0 + || GetLinkerUE4Version() < VER_UE4_REBUILD_HIERARCHICAL_INSTANCE_TREES) + { + if (GetStaticMesh()) + { + GetStaticMesh()->ConditionalPostLoad(); + } + + if (Async) + { + if (IsAsyncBuilding()) + { + // invalidate the results of the current async build we need to modify the tree + bConcurrentRemoval = true; + } + else + { + BuildTreeAsync(); + } + } + else + { + BuildTree(); + } + } +} + void UHierarchicalInstancedStaticMeshComponent::BuildTreeAsync() { checkSlow(IsInGameThread()); @@ -2425,6 +2465,7 @@ void UHierarchicalInstancedStaticMeshComponent::BuildTreeAsync() InstanceReorderTable.Empty(); SortedInstances.Empty(); RemovedInstances.Empty(); + CacheMeshExtendedBounds = FBoxSphereBounds(); UnbuiltInstanceBoundsList.Empty(); BuiltInstanceBounds.Init(); @@ -2617,19 +2658,7 @@ void UHierarchicalInstancedStaticMeshComponent::PostLoad() #if WITH_EDITOR // If any of the data is out of sync, build the tree now! - if (InstanceReorderTable.Num() != PerInstanceSMData.Num() || - NumBuiltInstances != PerInstanceSMData.Num() || - UnbuiltInstanceBoundsList.Num() > 0 || - GetLinkerUE4Version() < VER_UE4_REBUILD_HIERARCHICAL_INSTANCE_TREES) - { - UE_LOG(LogStaticMesh, Warning, TEXT("Rebuilding hierarchical instanced mesh component, please resave map %s."), *GetFullName()); - check(!IsAsyncBuilding()); - if (GetStaticMesh()) - { - GetStaticMesh()->ConditionalPostLoad(); - } - BuildTree(); - } + BuildTreeIfOutdated(false, false); #endif if (CVarASyncInstaneBufferConversion.GetValueOnGameThread() > 0) @@ -2654,7 +2683,7 @@ static void GatherInstanceTransformsInArea(const UHierarchicalInstancedStaticMes if (ClusterTree.Num()) { const FClusterNode& ChildNode = ClusterTree[Child]; - const FBox WorldNodeBox = FBox(ChildNode.BoundMin, ChildNode.BoundMax).TransformBy(Component.ComponentToWorld); + const FBox WorldNodeBox = FBox(ChildNode.BoundMin, ChildNode.BoundMax).TransformBy(Component.GetComponentTransform()); if (AreaBox.Intersect(WorldNodeBox)) { @@ -2684,7 +2713,7 @@ static void GatherInstanceTransformsInArea(const UHierarchicalInstancedStaticMes if (!InstanceToComponent.GetScale3D().IsZero()) { - InstanceData.Add(InstanceToComponent*Component.ComponentToWorld); + InstanceData.Add(InstanceToComponent*Component.GetComponentTransform()); } } } @@ -2795,7 +2824,7 @@ void UHierarchicalInstancedStaticMeshComponent::PartialNavigationUpdate(int32 In if (NavSys && NavSys->GetObjectsNavOctreeId(this)) { FTransform InstanceTransform(PerInstanceSMData[InstanceIdx].Transform); - FBox InstanceBox = GetStaticMesh()->GetBounds().TransformBy(InstanceTransform*ComponentToWorld).GetBox(); // in world space + FBox InstanceBox = GetStaticMesh()->GetBounds().TransformBy(InstanceTransform*GetComponentTransform()).GetBox(); // in world space AccumulatedNavigationDirtyArea+= InstanceBox; } } @@ -2812,7 +2841,7 @@ void UHierarchicalInstancedStaticMeshComponent::FlushAccumulatedNavigationUpdate // Check if this component is registered in navigation system if (ClusterTree.Num() && NavSys && NavSys->GetObjectsNavOctreeId(this)) { - FBox NewBounds = FBox(ClusterTree[0].BoundMin, ClusterTree[0].BoundMax).TransformBy(ComponentToWorld); + FBox NewBounds = FBox(ClusterTree[0].BoundMin, ClusterTree[0].BoundMax).TransformBy(GetComponentTransform()); NavSys->UpdateNavOctreeElementBounds(this, NewBounds, AccumulatedNavigationDirtyArea); } @@ -2825,7 +2854,7 @@ static void GatherInstancesOverlappingArea(const UHierarchicalInstancedStaticMes { const TArray& ClusterTree = *Component.ClusterTreePtr; const FClusterNode& ChildNode = ClusterTree[Child]; - const FBox WorldNodeBox = FBox(ChildNode.BoundMin, ChildNode.BoundMax).TransformBy(Component.ComponentToWorld); + const FBox WorldNodeBox = FBox(ChildNode.BoundMin, ChildNode.BoundMax).TransformBy(Component.GetComponentTransform()); if (AreaBox.Intersect(WorldNodeBox)) { @@ -2869,11 +2898,11 @@ TArray UHierarchicalInstancedStaticMeshComponent::GetInstancesOverlapping FBox WorldSpaceAABB(Sphere.Center - FVector(Sphere.W), Sphere.Center + FVector(Sphere.W)); if (bSphereInWorldSpace) { - Sphere = Sphere.TransformBy(ComponentToWorld.Inverse()); + Sphere = Sphere.TransformBy(GetComponentTransform().Inverse()); } else { - WorldSpaceAABB = WorldSpaceAABB.TransformBy(ComponentToWorld); + WorldSpaceAABB = WorldSpaceAABB.TransformBy(GetComponentTransform()); } const float StaticMeshBoundsRadius = GetStaticMesh()->GetBounds().SphereRadius; @@ -2902,11 +2931,11 @@ TArray UHierarchicalInstancedStaticMeshComponent::GetInstancesOverlapping FBox LocalSpaceSpaceBox(InBox); if (bBoxInWorldSpace) { - LocalSpaceSpaceBox = LocalSpaceSpaceBox.TransformBy(ComponentToWorld.Inverse()); + LocalSpaceSpaceBox = LocalSpaceSpaceBox.TransformBy(GetComponentTransform().Inverse()); } else { - WorldSpaceBox = WorldSpaceBox.TransformBy(ComponentToWorld); + WorldSpaceBox = WorldSpaceBox.TransformBy(GetComponentTransform()); } const FBox StaticMeshBox = GetStaticMesh()->GetBounds().GetBox(); diff --git a/Engine/Source/Runtime/Engine/Private/HighResScreenshot.cpp b/Engine/Source/Runtime/Engine/Private/HighResScreenshot.cpp index 19c657d06636..cfe301f48598 100644 --- a/Engine/Source/Runtime/Engine/Private/HighResScreenshot.cpp +++ b/Engine/Source/Runtime/Engine/Private/HighResScreenshot.cpp @@ -290,10 +290,14 @@ bool FHighResScreenshotConfig::SaveImage(const FString& File, const TArray(const FString& File, const TArray& Bitmap, const FIntPoint& BitmapSize, FString* OutFilename) const; template ENGINE_API bool FHighResScreenshotConfig::SaveImage(const FString& File, const TArray& Bitmap, const FIntPoint& BitmapSize, FString* OutFilename) const; template ENGINE_API bool FHighResScreenshotConfig::SaveImage(const FString& File, const TArray& Bitmap, const FIntPoint& BitmapSize, FString* OutFilename) const; +/// @endcond + FHighResScreenshotConfig::FImageWriter::FImageWriter(const TSharedPtr& InWrapper) : ImageWrapper(InWrapper) { diff --git a/Engine/Source/Runtime/Engine/Private/HitProxies.cpp b/Engine/Source/Runtime/Engine/Private/HitProxies.cpp index eb87193624d9..d48a1702b7f6 100644 --- a/Engine/Source/Runtime/Engine/Private/HitProxies.cpp +++ b/Engine/Source/Runtime/Engine/Private/HitProxies.cpp @@ -7,9 +7,13 @@ #include "HitProxies.h" #include "Misc/ScopeLock.h" +/// @cond DOXYGEN_WARNINGS + IMPLEMENT_HIT_PROXY_BASE( HHitProxy, NULL ); IMPLEMENT_HIT_PROXY(HObject,HHitProxy); +/// @endcond + const FHitProxyId FHitProxyId::InvisibleHitProxyId( INDEX_NONE - 1 ); diff --git a/Engine/Source/Runtime/Engine/Private/InstancedStaticMesh.cpp b/Engine/Source/Runtime/Engine/Private/InstancedStaticMesh.cpp index f75b816aa9e8..9966fd47b67f 100644 --- a/Engine/Source/Runtime/Engine/Private/InstancedStaticMesh.cpp +++ b/Engine/Source/Runtime/Engine/Private/InstancedStaticMesh.cpp @@ -831,7 +831,7 @@ FActorComponentInstanceData* UInstancedStaticMeshComponent::GetComponentInstance InstanceData = StaticMeshInstanceData = new FInstancedStaticMeshComponentInstanceData(*this); // Fill in info (copied from UStaticMeshComponent::GetComponentInstanceData) - StaticMeshInstanceData->CachedStaticLighting.Transform = ComponentToWorld; + StaticMeshInstanceData->CachedStaticLighting.Transform = GetComponentTransform(); for (const FStaticMeshComponentLODInfo& LODDataEntry : LODData) { @@ -864,7 +864,7 @@ void UInstancedStaticMeshComponent::ApplyComponentInstanceData(FInstancedStaticM // Check for any instance having moved as that would invalidate static lighting if (PerInstanceSMData.Num() == InstancedMeshData->PerInstanceSMData.Num() && - InstancedMeshData->CachedStaticLighting.Transform.Equals(ComponentToWorld)) + InstancedMeshData->CachedStaticLighting.Transform.Equals(GetComponentTransform())) { bMatch = true; @@ -949,7 +949,7 @@ void UInstancedStaticMeshComponent::InitInstanceBody(int32 InstanceIdx, FBodyIns check(BodySetup); // Get transform of the instance - FTransform InstanceTransform = FTransform(PerInstanceSMData[InstanceIdx].Transform) * ComponentToWorld; + FTransform InstanceTransform = FTransform(PerInstanceSMData[InstanceIdx].Transform) * GetComponentTransform(); InstanceBodyInstance->CopyBodyInstancePropertiesFrom(&BodyInstance); InstanceBodyInstance->InstanceBodyIndex = InstanceIdx; // Set body index @@ -985,7 +985,7 @@ void UInstancedStaticMeshComponent::CreateAllInstanceBodies() Transforms.Reserve(NumBodies); for (int32 i = 0; i < NumBodies; ++i) { - const FTransform InstanceTM = FTransform(PerInstanceSMData[i].Transform) * ComponentToWorld; + const FTransform InstanceTM = FTransform(PerInstanceSMData[i].Transform) * GetComponentTransform(); if (InstanceTM.GetScale3D().IsNearlyZero()) { InstanceBodies[i] = nullptr; @@ -1341,7 +1341,7 @@ void UInstancedStaticMeshComponent::ReleasePerInstanceRenderData() // Resource will either be released here or by scene proxy on the render thread, whoever gets executed last delete InCleanupRenderDataPtr; }); - } + } //-V773 } void UInstancedStaticMeshComponent::PropagateLightingScenarioChange() @@ -1401,7 +1401,7 @@ int32 UInstancedStaticMeshComponent::AddInstance(const FTransform& InstanceTrans int32 UInstancedStaticMeshComponent::AddInstanceWorldSpace(const FTransform& WorldTransform) { // Transform from world space to local space - FTransform RelativeTM = WorldTransform.GetRelativeTransform(ComponentToWorld); + FTransform RelativeTM = WorldTransform.GetRelativeTransform(GetComponentTransform()); return AddInstance(RelativeTM); } @@ -1453,7 +1453,7 @@ bool UInstancedStaticMeshComponent::GetInstanceTransform(int32 InstanceIndex, FT OutInstanceTransform = FTransform(InstanceData.Transform); if (bWorldSpace) { - OutInstanceTransform = OutInstanceTransform * ComponentToWorld; + OutInstanceTransform = OutInstanceTransform * GetComponentTransform(); } return true; @@ -1472,7 +1472,7 @@ void UInstancedStaticMeshComponent::OnUpdateTransform(EUpdateTransformFlags Upda for (int32 i = 0; i < PerInstanceSMData.Num(); i++) { const FTransform InstanceTransform(PerInstanceSMData[i].Transform); - UpdateInstanceTransform(i, InstanceTransform * ComponentToWorld, /* bWorldSpace= */true, /* bMarkRenderStateDirty= */false, bTeleport); + UpdateInstanceTransform(i, InstanceTransform * GetComponentTransform(), /* bWorldSpace= */true, /* bMarkRenderStateDirty= */false, bTeleport); } } } @@ -1495,13 +1495,13 @@ bool UInstancedStaticMeshComponent::UpdateInstanceTransform(int32 InstanceIndex, // Should find some way around this for performance. // Render data uses local transform of the instance - FTransform LocalTransform = bWorldSpace ? NewInstanceTransform.GetRelativeTransform(ComponentToWorld) : NewInstanceTransform; + FTransform LocalTransform = bWorldSpace ? NewInstanceTransform.GetRelativeTransform(GetComponentTransform()) : NewInstanceTransform; InstanceData.Transform = LocalTransform.ToMatrixWithScale(); if (bPhysicsStateCreated) { // Physics uses world transform of the instance - FTransform WorldTransform = bWorldSpace ? NewInstanceTransform : (LocalTransform * ComponentToWorld); + FTransform WorldTransform = bWorldSpace ? NewInstanceTransform : (LocalTransform * GetComponentTransform()); FBodyInstance*& InstanceBodyInstance = InstanceBodies[InstanceIndex]; #if WITH_PHYSX if (NewInstanceTransform.GetScale3D().IsNearlyZero()) @@ -1552,7 +1552,7 @@ TArray UInstancedStaticMeshComponent::GetInstancesOverlappingSphere(const FSphere Sphere(Center, Radius); if (bSphereInWorldSpace) { - Sphere = Sphere.TransformBy(ComponentToWorld.Inverse()); + Sphere = Sphere.TransformBy(GetComponentTransform().Inverse()); } float StaticMeshBoundsRadius = GetStaticMesh()->GetBounds().SphereRadius; @@ -1578,7 +1578,7 @@ TArray UInstancedStaticMeshComponent::GetInstancesOverlappingBox(const FB FBox Box(InBox); if (bBoxInWorldSpace) { - Box = Box.TransformBy(ComponentToWorld.Inverse()); + Box = Box.TransformBy(GetComponentTransform().Inverse()); } FVector StaticMeshBoundsExtent = GetStaticMesh()->GetBounds().BoxExtent; @@ -1782,7 +1782,7 @@ void UInstancedStaticMeshComponent::GetNavigationPerInstanceTransforms(const FBo const FTransform InstanceToComponent(InstancedData.Transform); if (!InstanceToComponent.GetScale3D().IsZero()) { - InstanceData.Add(InstanceToComponent*ComponentToWorld); + InstanceData.Add(InstanceToComponent*GetComponentTransform()); } } } diff --git a/Engine/Source/Runtime/Engine/Private/InstancedStaticMesh.h b/Engine/Source/Runtime/Engine/Private/InstancedStaticMesh.h index b37924db4615..28cb8c4435ce 100644 --- a/Engine/Source/Runtime/Engine/Private/InstancedStaticMesh.h +++ b/Engine/Source/Runtime/Engine/Private/InstancedStaticMesh.h @@ -688,7 +688,7 @@ public: : FStaticMeshStaticLightingMesh(InPrimitive, LODIndex, InRelevantLights) { // override the local to world to combine the per instance transform with the component's standard transform - SetLocalToWorld(InPrimitive->PerInstanceSMData[InstanceIndex].Transform * InPrimitive->ComponentToWorld.ToMatrixWithScale()); + SetLocalToWorld(InPrimitive->PerInstanceSMData[InstanceIndex].Transform * InPrimitive->GetComponentTransform().ToMatrixWithScale()); } }; diff --git a/Engine/Source/Runtime/Engine/Private/Internationalization/EnginePackageLocalizationCache.cpp b/Engine/Source/Runtime/Engine/Private/Internationalization/EnginePackageLocalizationCache.cpp index 067cad0273c5..0d049e031698 100644 --- a/Engine/Source/Runtime/Engine/Private/Internationalization/EnginePackageLocalizationCache.cpp +++ b/Engine/Source/Runtime/Engine/Private/Internationalization/EnginePackageLocalizationCache.cpp @@ -5,6 +5,7 @@ #include "Modules/ModuleManager.h" #include "Misc/PackageName.h" #include "AssetData.h" +#include "ARFilter.h" #include "AssetRegistryModule.h" FEnginePackageLocalizationCache::FEnginePackageLocalizationCache() @@ -43,9 +44,8 @@ void FEnginePackageLocalizationCache::FindLocalizedPackages(const FString& InSou LocalizedPackagePaths.Add(InLocalizedRoot); // Set bIsScanningPath to avoid us processing newly added assets from this scan - bIsScanningPath = true; + TGuardValue SetIsScanningPath(bIsScanningPath, true); AssetRegistry.ScanPathsSynchronous(LocalizedPackagePaths); - bIsScanningPath = false; } #endif // WITH_EDITOR @@ -54,7 +54,7 @@ void FEnginePackageLocalizationCache::FindLocalizedPackages(const FString& InSou for (const FAssetData& LocalizedAssetData : LocalizedAssetDataArray) { - const FName SourcePackageName = *(InSourceRoot / LocalizedAssetData.PackageName.ToString().Mid(InLocalizedRoot.Len() + 1)); // +1 for the trailing slash that isn't part of the string + const FName SourcePackageName = *FPackageName::GetSourcePackagePath(LocalizedAssetData.PackageName.ToString()); TArray& PrioritizedLocalizedPackageNames = InOutSourcePackagesToLocalizedPackages.FindOrAdd(SourcePackageName); PrioritizedLocalizedPackageNames.AddUnique(LocalizedAssetData.PackageName); @@ -63,25 +63,44 @@ void FEnginePackageLocalizationCache::FindLocalizedPackages(const FString& InSou void FEnginePackageLocalizationCache::FindAssetGroupPackages(const FName InAssetGroupName, const FName InAssetClassName) { - // We only support finding asset groups paths in cooked games, as the asset registry scan time can take too long otherwise - if (!FPlatformProperties::RequiresCookedData()) - { - return; - } - FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(TEXT("AssetRegistry")); IAssetRegistry& AssetRegistry = AssetRegistryModule.Get(); - TArray AssetsOfClass; - AssetRegistry.GetAssetsByClass(InAssetClassName, AssetsOfClass); - - for (const FAssetData& AssetOfClass : AssetsOfClass) + // We use the localized paths to find the source assets for the group since it's much faster to scan those paths than perform a full scan + TArray LocalizedRootPaths; { - if (!FPackageName::IsLocalizedPackage(AssetOfClass.PackageName.ToString())) + TArray RootPaths; + FPackageName::QueryRootContentPaths(RootPaths); + for (const FString& RootPath : RootPaths) { - PackageNameToAssetGroup.Add(AssetOfClass.PackageName, InAssetGroupName); + LocalizedRootPaths.Add(RootPath / TEXT("L10N")); } } + +#if WITH_EDITOR + // Make sure the asset registry has the data we need + AssetRegistry.ScanPathsSynchronous(LocalizedRootPaths); +#endif // WITH_EDITOR + + // Build the filter to get all localized assets of the given class + FARFilter Filter; + Filter.bRecursivePaths = true; + for (const FString& LocalizedRootPath : LocalizedRootPaths) + { + Filter.PackagePaths.Add(*LocalizedRootPath); + } + Filter.bIncludeOnlyOnDiskAssets = false; + Filter.ClassNames.Add(InAssetClassName); + Filter.bRecursiveClasses = false; + + TArray LocalizedAssetsOfClass; + AssetRegistry.GetAssets(Filter, LocalizedAssetsOfClass); + + for (const FAssetData& LocalizedAssetOfClass : LocalizedAssetsOfClass) + { + const FName SourcePackageName = *FPackageName::GetSourcePackagePath(LocalizedAssetOfClass.PackageName.ToString()); + PackageNameToAssetGroup.Add(SourcePackageName, InAssetGroupName); + } } void FEnginePackageLocalizationCache::HandleAssetAdded(const FAssetData& InAssetData) diff --git a/Engine/Source/Runtime/Engine/Private/Interpolation.cpp b/Engine/Source/Runtime/Engine/Private/Interpolation.cpp index 77de2ba8f707..defe2eebc12d 100644 --- a/Engine/Source/Runtime/Engine/Private/Interpolation.cpp +++ b/Engine/Source/Runtime/Engine/Private/Interpolation.cpp @@ -8059,7 +8059,7 @@ void UInterpTrackSound::UpdateTrack(float NewPosition, UInterpTrackInst* TrInst, { SoundInst->PlayAudioComp->bAllowSpatialization = false; } - else if (Actor) + else { if (bAttach && Actor->GetRootComponent()) { diff --git a/Engine/Source/Runtime/Engine/Private/Kismet/BlueprintAsyncActionBase.cpp b/Engine/Source/Runtime/Engine/Private/Kismet/BlueprintAsyncActionBase.cpp index 8b1573cf8ff3..8a42bef7919a 100644 --- a/Engine/Source/Runtime/Engine/Private/Kismet/BlueprintAsyncActionBase.cpp +++ b/Engine/Source/Runtime/Engine/Private/Kismet/BlueprintAsyncActionBase.cpp @@ -8,9 +8,17 @@ UBlueprintAsyncActionBase::UBlueprintAsyncActionBase(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { - SetFlags(RF_StrongRefOnFrame); + if (!HasAnyFlags(RF_ClassDefaultObject)) + { + SetFlags(RF_StrongRefOnFrame); + } } void UBlueprintAsyncActionBase::Activate() { } + +void UBlueprintAsyncActionBase::SetReadyToDestroy() +{ + ClearFlags(RF_StrongRefOnFrame); +} diff --git a/Engine/Source/Runtime/Engine/Private/Kismet/BlueprintPlatformLibrary.cpp b/Engine/Source/Runtime/Engine/Private/Kismet/BlueprintPlatformLibrary.cpp index 0b54520146e4..49ceff6349bf 100644 --- a/Engine/Source/Runtime/Engine/Private/Kismet/BlueprintPlatformLibrary.cpp +++ b/Engine/Source/Runtime/Engine/Private/Kismet/BlueprintPlatformLibrary.cpp @@ -48,6 +48,16 @@ void UPlatformGameInstance::ApplicationReceivedScreenOrientationChangedNotificat ApplicationReceivedScreenOrientationChangedNotificationDelegate.Broadcast((EScreenOrientation::Type)inScreenOrientation); } +void UPlatformGameInstance::ApplicationReceivedRemoteNotificationDelegate_Handler(FString inFString, int32 inAppState) +{ + ApplicationReceivedRemoteNotificationDelegate.Broadcast(inFString, (EApplicationState::Type)inAppState); +} + +void UPlatformGameInstance::ApplicationReceivedLocalNotificationDelegate_Handler(FString inFString, int32 inInt, int32 inAppState) +{ + ApplicationReceivedLocalNotificationDelegate.Broadcast(inFString, inInt, (EApplicationState::Type)inAppState); +} + ////////////////////////////////////////////////////////////////////////// // UBlueprintPlatformLibrary @@ -55,20 +65,18 @@ void UPlatformGameInstance::ApplicationReceivedScreenOrientationChangedNotificat UBlueprintPlatformLibrary::UBlueprintPlatformLibrary(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { - platformService = NULL; - - FString ModuleName; - GConfig->GetString(TEXT("LocalNotification"), TEXT("DefaultPlatformService"), ModuleName, GEngineIni); - - if (ModuleName.Len() > 0) + if (platformService == nullptr) { - // load the module by name from the .ini - ILocalNotificationModule* module = FModuleManager::LoadModulePtr(*ModuleName); + FString ModuleName; + GConfig->GetString(TEXT("LocalNotification"), TEXT("DefaultPlatformService"), ModuleName, GEngineIni); - // did the module exist? - if (module != nullptr) + if (ModuleName.Len() > 0) { - platformService = module->GetLocalNotificationService(); + // load the module by name from the .ini + if (ILocalNotificationModule* Module = FModuleManager::LoadModulePtr(*ModuleName)) + { + platformService = Module->GetLocalNotificationService(); + } } } } @@ -99,10 +107,31 @@ void UBlueprintPlatformLibrary::ScheduleLocalNotificationAtTime(const FDateTime& void UBlueprintPlatformLibrary::ScheduleLocalNotificationFromNow(int32 inSecondsFromNow, const FText& Title, const FText& Body, const FText& Action, const FString& ActivationEvent) { - FDateTime dateTime = FDateTime::Now(); - dateTime += FTimespan(0, 0, inSecondsFromNow); + FDateTime TargetTime = FDateTime::Now(); + TargetTime += FTimespan(0, 0, inSecondsFromNow); - ScheduleLocalNotificationAtTime(dateTime, true, Title, Body, Action, ActivationEvent); + ScheduleLocalNotificationAtTime(TargetTime, true, Title, Body, Action, ActivationEvent); +} + +void UBlueprintPlatformLibrary::ScheduleLocalNotificationBadgeAtTime(const FDateTime& FireDateTime, bool inLocalTime, const FString& ActivationEvent) +{ + if (platformService == nullptr) + { + UE_LOG(LogBlueprintUserMessages, Warning, TEXT("ScheduleLocalNotificationBadgeAtTime(): No local notification service")); + return; + } + + UE_LOG(LogBlueprintUserMessages, Log, TEXT("Scheduling notification badge %s at %d/%d/%d %d:%d:%d %s"), *ActivationEvent, FireDateTime.GetMonth(), FireDateTime.GetDay(), FireDateTime.GetYear(), FireDateTime.GetHour(), FireDateTime.GetMinute(), FireDateTime.GetSecond(), inLocalTime ? TEXT("Local") : TEXT("UTC")); + + platformService->ScheduleLocalNotificationBadgeAtTime(FireDateTime, inLocalTime, ActivationEvent); +} + +void UBlueprintPlatformLibrary::ScheduleLocalNotificationBadgeFromNow(int32 inSecondsFromNow, const FString& ActivationEvent) +{ + FDateTime TargetTime = FDateTime::Now(); + TargetTime += FTimespan(0, 0, inSecondsFromNow); + + ScheduleLocalNotificationBadgeAtTime(TargetTime, true, ActivationEvent); } UFUNCTION(BlueprintCallable, Category="Platform|LocalNotification") @@ -130,4 +159,4 @@ void UBlueprintPlatformLibrary::GetLaunchNotification(bool& NotificationLaunched platformService->GetLaunchNotification(NotificationLaunchedApp, ActivationEvent, FireDate); } -ILocalNotificationService* UBlueprintPlatformLibrary::platformService; +ILocalNotificationService* UBlueprintPlatformLibrary::platformService = nullptr; diff --git a/Engine/Source/Runtime/Engine/Private/Kismet/ImportanceSamplingLibrary.cpp b/Engine/Source/Runtime/Engine/Private/Kismet/ImportanceSamplingLibrary.cpp new file mode 100644 index 000000000000..1ebe01f44085 --- /dev/null +++ b/Engine/Source/Runtime/Engine/Private/Kismet/ImportanceSamplingLibrary.cpp @@ -0,0 +1,256 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "Kismet/ImportanceSamplingLibrary.h" +#include "Math/Sobol.h" +#include "Math/UnrealMathUtility.h" +#include "Engine/Texture2D.h" +#include "Stack.h" +#include "NoExportTypes.h" + +#define LOCTEXT_NAMESPACE "ImportanceSamplingLibrary" + +// when to switch from binary to linear search +// branch prediction makes linear search faster for small sizes +// set to 1 to use binary search all the way down +#define BINARY_SEARCH_LIMIT 64 + +// max MIP size to store and use for texture calculation +// largest MarginalCDF entry is the sum of all texel probabilities. +// per-texel PDF precision is then 24-bit float mantissa - 2*(mips-1) +// for 1024x1024 with 2^20 texels and 11 mips, that's 24-20 = 4 bits of probability precision +#define MAX_MIP_LEVELS 11 + +FLinearColor FImportanceTexture::GetColorTrilinear(FVector2D Position, float Mip) const +{ + float IntMip = FMath::FloorToFloat(Mip); + float MipBlend = Mip - IntMip; + FLinearColor Color0 = GetColorBilinear(Position, IntMip); + FLinearColor Color1 = GetColorBilinear(Position, IntMip + 1.f); + return FMath::Lerp(Color0, Color1, MipBlend); +} + +FLinearColor FImportanceTexture::GetColorBilinear(FVector2D Position, int32 Mip) const +{ + int32 iMip = FMath::Clamp(Mip, 0, NumMips - 1); + FIntPoint MipSize(((Size.X - 1) >> iMip) + 1, ((Size.Y - 1) >> iMip) + 1); + size_t LevelStart = 4 * (Size.X * Size.Y - MipSize.X * MipSize.Y) / 3; + + FVector2D TexelPos = Position * FVector2D(MipSize - FIntPoint(1,1)); + FIntPoint IntPos( + FMath::Clamp(FMath::FloorToInt(TexelPos.X), 0, MipSize.X - 1), + FMath::Clamp(FMath::FloorToInt(TexelPos.Y), 0, MipSize.Y - 1)); + FVector2D TexelBlend = TexelPos - FVector2D(IntPos); + + // At bottom MIP, return single texel + size_t TextureOffset = LevelStart + IntPos.Y * MipSize.X + IntPos.X; + FLinearColor Color00(TextureData[TextureOffset]); + if (MipSize.X == 1 || MipSize.Y == 1) return Color00; + + // MIP texel blending should be in linear space, so this includes conversions to/from sRGB + FLinearColor Color01(TextureData[TextureOffset + MipSize.X]); + FLinearColor Color10(TextureData[TextureOffset + 1]); + FLinearColor Color11(TextureData[TextureOffset + MipSize.X + 1]); + return FMath::Lerp( + FMath::Lerp(Color00, Color10, TexelBlend.X), + FMath::Lerp(Color01, Color11, TexelBlend.X), TexelBlend.Y); +} + +float FImportanceTexture::ImportanceWeight(FColor Texel, TEnumAsByte WeightingFunc) const +{ + FLinearColor LinearTexel = (Texture.IsValid() && Texture->SRGB) ? FLinearColor(Texel) : Texel.ReinterpretAsLinear(); + + switch (WeightingFunc) { + case EImportanceWeight::Luminance: return LinearTexel.ComputeLuminance(); + case EImportanceWeight::Red: return LinearTexel.R; + case EImportanceWeight::Green: return LinearTexel.G; + case EImportanceWeight::Blue: return LinearTexel.B; + case EImportanceWeight::Alpha: return LinearTexel.A; + } + return 1.f; +} + +void FImportanceTexture::Initialize(UTexture2D *SourceTexture, TEnumAsByte WeightingFunc) +{ + if (!SourceTexture || SourceTexture->GetPixelFormat() != EPixelFormat::PF_B8G8R8A8) + { + Texture = 0; + FFrame::KismetExecutionMessage(TEXT("Importance Texture only supports RGBA8 textures"), ELogVerbosity::Error); + return; + } + + // after this, safe to re-initialize + Texture = SourceTexture; + Weighting = WeightingFunc; + + // Save a copy of all MIP data for later color lookups + // Doing GetMipData for each sample would allocate and copy the entire MIP chain for each access + TArray MipData; + int32 SourceMips = SourceTexture->GetNumMips(); + int32 FirstMip = FMath::Max(0, SourceMips - MAX_MIP_LEVELS); + NumMips = SourceMips - FirstMip; + MipData.AddZeroed(NumMips); + SourceTexture->GetMipData(FirstMip, (void**)MipData.GetData()); + + // Copy just the needed MIP data and adjust size + FIntPoint SrcSize = FIntPoint(SourceTexture->GetSizeX(), SourceTexture->GetSizeY()); + Size = FIntPoint(((SrcSize.X - 1) >> FirstMip) + 1, ((SrcSize.Y - 1) >> FirstMip) + 1); + FIntPoint LastMipSize(((Size.X - 1) >> (NumMips - 1)) + 1, ((Size.Y - 1) >> (NumMips - 1)) + 1); + size_t MipDataSize = (4 * Size.X * Size.Y - LastMipSize.X * LastMipSize.Y) / 3; + TextureData.SetNumUninitialized(MipDataSize); + for (int32 mip = 0; mip < NumMips; ++mip) { + FIntPoint LevelSize(((Size.X - 1) >> mip) + 1, ((Size.Y - 1) >> mip) + 1); + size_t LevelStart = (Size.X * Size.Y - LevelSize.X * LevelSize.Y) * 4 / 3; + FMemory::Memcpy((void*)&TextureData[LevelStart], (void*)MipData[mip], LevelSize.X*LevelSize.Y*sizeof(FColor)); + } + + // accumulate un-normalized marginal CDF for image, and conditional CDF for each row + MarginalCDF.SetNumUninitialized(Size.Y + 1); + ConditionalCDF.SetNumUninitialized((Size.X + 1) * Size.Y); + MarginalCDF[0] = 0.f; + for (int y = 1; y <= Size.Y; ++y) + { + // Accumulate along row + FColor *ColorRow = &MipData[0][(y - 1) * Size.X]; + float *CDFRow = &ConditionalCDF[(y - 1) * (Size.X + 1)]; + CDFRow[0] = 0.f; + for (int x = 1; x <= Size.X; ++x) + { + CDFRow[x] = CDFRow[x - 1] + ImportanceWeight(ColorRow[x - 1], WeightingFunc); + } + + // add row total to global total + MarginalCDF[y] = MarginalCDF[y - 1] + CDFRow[Size.X]; + } + + // get rid of temporary copy of MIP data + for (auto MipLevel : MipData) + { + FMemory::Free(MipLevel); + } +} + +void FImportanceTexture::ImportanceSample(const FVector2D & Rand, int Samples, float Intensity, FVector2D & SamplePosition, FLinearColor & SampleColor, float & SampleIntensity, float & SampleSize) const +{ + if (!Texture.IsValid()) + { + return; + } + + // find a row: binary search then linear + float YRand = MarginalCDF[Size.Y] * FMath::Frac(Rand.Y); // 0 <= YRand < PDFTotal normalization factor + FIntPoint YTexel(0, Size.Y); // range: X=low, Y=high + while (YTexel.Y - YTexel.X > BINARY_SEARCH_LIMIT) + { + int32 Mid = YTexel.X + ((YTexel.Y - YTexel.X) >> 1); + YTexel = (MarginalCDF[Mid] < YRand) ? FIntPoint(Mid, YTexel.Y) : FIntPoint(YTexel.X, Mid); + } + while (YTexel.X < YTexel.Y && MarginalCDF[YTexel.X + 1] < YRand) + { + ++YTexel.X; + } + YTexel.Y = YTexel.X + 1; + + // find a column + const float *CDFRow = &ConditionalCDF[(Size.X + 1) * YTexel.X]; + float XRand = CDFRow[Size.X] * FMath::Frac(Rand.X); // 0 <= XRand < row total + FIntPoint XTexel(0, Size.X); // range: X=low, Y=high + while (XTexel.Y - XTexel.X > BINARY_SEARCH_LIMIT) + { + int32 Mid = XTexel.X + ((XTexel.Y - XTexel.X) >> 1); + XTexel = (CDFRow[Mid] < XRand) ? FIntPoint(Mid, XTexel.Y) : FIntPoint(XTexel.X, Mid); + } + while (XTexel.X < XTexel.Y && CDFRow[XTexel.X + 1] < XRand) + { + ++XTexel.X; + } + XTexel.Y = XTexel.X + 1; + + // Final position + FVector2D IntervalStart(CDFRow[XTexel.X], MarginalCDF[YTexel.X]); + FVector2D IntervalEnd(CDFRow[XTexel.Y], MarginalCDF[YTexel.Y]); + FVector2D Interval = IntervalEnd - IntervalStart; + FVector2D TexelRand = (FVector2D(XRand, YRand) - IntervalStart) / Interval; + SamplePosition = (FVector2D(float(XTexel.X), float(YTexel.X)) + TexelRand) / FVector2D(Size); + + // Final scaled probability density, scaled by Jacobian of mapping from unit square to texels (aka texture size) and PDF total normalization + float Jacobian = Size.X * Size.Y / MarginalCDF[Size.Y]; + float Probability = Interval.X * Jacobian; + + // find size scaled by number of samples and probability + float Scale = 1.f / (float(Samples) * Probability); + SampleSize = 4.f * FMath::Sqrt(0.5f * Scale); + + // clamp size and position to fit inside texture + //SampleSize = FMath::Min3(SampleSize, 4.f * SamplePosition.X, 4.f - 4.f * SamplePosition.X); + //SampleSize = FMath::Min3(SampleSize, 4.f * SamplePosition.Y, 4.f - 4.f * SamplePosition.Y); + + // Color from mip texture, not normalized for total intensity so colors match texture. + // Need to use SampleColor * SampleIntensity to get expected total color + float MipLevel = 0.5 * FMath::Log2(Size.X * Size.Y * Scale); + SampleColor = GetColorTrilinear(SamplePosition, MipLevel); + SampleIntensity = Intensity * Scale * Jacobian; +} + +UImportanceSamplingLibrary::UImportanceSamplingLibrary(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ +} + +float UImportanceSamplingLibrary::RandomSobolFloat(int32 Index, int32 Dimension, float Seed) +{ + Dimension = FMath::Clamp(Dimension, 0, FSobol::MaxDimension); + return FSobol::Evaluate(Index, Dimension, int32(Seed * 0x1000000)); +} + +float UImportanceSamplingLibrary::NextSobolFloat(int32 Index, int32 Dimension, float Value) +{ + Dimension = FMath::Clamp(Dimension, 0, FSobol::MaxDimension); + return FSobol::Next(Index, Dimension, Value); +} + +FVector2D UImportanceSamplingLibrary::RandomSobolCell2D(int32 Index, int32 NumCells, FVector2D Cell, FVector2D Seed) +{ + int32 CellBits = FMath::Clamp(FGenericPlatformMath::CeilLogTwo(NumCells), 0, FSobol::MaxCell2DBits); + return FSobol::Evaluate(Index, CellBits, Cell.IntPoint(), (Seed * 0x1000000).IntPoint()); +} + +FVector2D UImportanceSamplingLibrary::NextSobolCell2D(int32 Index, int32 NumCells, FVector2D Value) +{ + int32 CellBits = FMath::Clamp(FGenericPlatformMath::CeilLogTwo(NumCells), 0, FSobol::MaxCell2DBits); + return FSobol::Next(Index, CellBits, Value); +} + +FVector UImportanceSamplingLibrary::RandomSobolCell3D(int32 Index, int32 NumCells, FVector Cell, FVector Seed) +{ + int32 CellBits = FMath::Clamp(FGenericPlatformMath::CeilLogTwo(NumCells), 0, FSobol::MaxCell3DBits); + FIntVector ICell = FIntVector(int32(Cell.X), int32(Cell.Y), int32(Cell.Z)); + FIntVector ISeed = FIntVector(int32(Seed.X * 0x1000000), int32(Seed.Y * 0x1000000), int32(Seed.Z * 0x1000000)); + return FSobol::Evaluate(Index, CellBits, ICell, ISeed); +} + +FVector UImportanceSamplingLibrary::NextSobolCell3D(int32 Index, int32 NumCells, FVector Value) +{ + int32 CellBits = FMath::Clamp(FGenericPlatformMath::CeilLogTwo(NumCells), 0, FSobol::MaxCell3DBits); + return FSobol::Next(Index, CellBits, Value); +} + +FImportanceTexture UImportanceSamplingLibrary::MakeImportanceTexture(UTexture2D *SourceTexture, TEnumAsByte WeightingFunc) +{ + return FImportanceTexture(SourceTexture, WeightingFunc); +} + +void UImportanceSamplingLibrary::BreakImportanceTexture(const FImportanceTexture &ImportanceTexture, UTexture2D *&Texture, TEnumAsByte &WeightingFunc) +{ + Texture = ImportanceTexture.Texture.Get(); + WeightingFunc = ImportanceTexture.Weighting; +} + +void UImportanceSamplingLibrary::ImportanceSample(const FImportanceTexture &Texture, const FVector2D &Rand, int Samples, float Intensity, + FVector2D &SamplePosition, FLinearColor &SampleColor, float &SampleIntensity, float &SampleSize) +{ + Texture.ImportanceSample(Rand, Samples, Intensity, SamplePosition, SampleColor, SampleIntensity, SampleSize); +} + +#undef LOCTEXT_NAMESPACE +#undef BINARY_SEARCH_LIMIT +#undef MAX_MIP_LEVELS \ No newline at end of file diff --git a/Engine/Source/Runtime/Engine/Private/KismetArrayLibrary.cpp b/Engine/Source/Runtime/Engine/Private/KismetArrayLibrary.cpp index 465471e11953..40ed826e6b61 100644 --- a/Engine/Source/Runtime/Engine/Private/KismetArrayLibrary.cpp +++ b/Engine/Source/Runtime/Engine/Private/KismetArrayLibrary.cpp @@ -253,10 +253,11 @@ void UKismetArrayLibrary::GenericArray_Get(void* TargetArray, const UArrayProper } else { - FFrame::KismetExecutionMessage(*FString::Printf(TEXT("Attempted to access index %d from array %s of length %d!"), + FFrame::KismetExecutionMessage(*FString::Printf(TEXT("Attempted to access index %d from array '%s' of length %d in '%s'!"), Index, *ArrayProp->GetName(), - ArrayHelper.Num()), + ArrayHelper.Num(), + *GetPathNameSafe(ArrayProp->GetOuter())), ELogVerbosity::Warning, GetOutOfBoundsWarning); InnerProp->InitializeValue(Item); diff --git a/Engine/Source/Runtime/Engine/Private/KismetInputLibrary.cpp b/Engine/Source/Runtime/Engine/Private/KismetInputLibrary.cpp index 4186c940a299..2ab2260c727a 100644 --- a/Engine/Source/Runtime/Engine/Private/KismetInputLibrary.cpp +++ b/Engine/Source/Runtime/Engine/Private/KismetInputLibrary.cpp @@ -199,17 +199,38 @@ bool UKismetInputLibrary::PointerEvent_IsTouchEvent(const FPointerEvent& Input) return Input.IsTouchEvent(); } -//EGestureEvent::Type UKismetInputLibrary::PointerEvent_GetGestureType(const FPointerEvent& Input) -//{ -// return Input.GetGestureType(); -//} +ESlateGesture UKismetInputLibrary::PointerEvent_GetGestureType(const FPointerEvent& Input) +{ + static_assert( (int32)EGestureEvent::None == (int32)ESlateGesture::None, "EGestureEvent == ESlateGesture" ); + static_assert( (int32)EGestureEvent::Scroll == (int32)ESlateGesture::Scroll, "EGestureEvent == ESlateGesture" ); + static_assert( (int32)EGestureEvent::Magnify == (int32)ESlateGesture::Magnify, "EGestureEvent == ESlateGesture" ); + static_assert( (int32)EGestureEvent::Swipe == (int32)ESlateGesture::Swipe, "EGestureEvent == ESlateGesture" ); + static_assert( (int32)EGestureEvent::Rotate == (int32)ESlateGesture::Rotate, "EGestureEvent == ESlateGesture" ); + static_assert( (int32)EGestureEvent::LongPress == (int32)ESlateGesture::LongPress, "EGestureEvent == ESlateGesture" ); + + switch ( Input.GetGestureType() ) + { + case EGestureEvent::Scroll: + return ESlateGesture::Scroll; + case EGestureEvent::Magnify: + return ESlateGesture::Magnify; + case EGestureEvent::Swipe: + return ESlateGesture::Swipe; + case EGestureEvent::Rotate: + return ESlateGesture::Rotate; + case EGestureEvent::LongPress: + return ESlateGesture::LongPress; + case EGestureEvent::None: + default: + return ESlateGesture::None; + } +} FVector2D UKismetInputLibrary::PointerEvent_GetGestureDelta(const FPointerEvent& Input) { return Input.GetGestureDelta(); } - FKey UKismetInputLibrary::ControllerEvent_GetEffectingButton(const FControllerEvent& Input) { return Input.GetEffectingButton(); diff --git a/Engine/Source/Runtime/Engine/Private/KismetInternationalizationLibrary.cpp b/Engine/Source/Runtime/Engine/Private/KismetInternationalizationLibrary.cpp new file mode 100644 index 000000000000..06a9ac23e446 --- /dev/null +++ b/Engine/Source/Runtime/Engine/Private/KismetInternationalizationLibrary.cpp @@ -0,0 +1,125 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "Kismet/KismetInternationalizationLibrary.h" +#include "Internationalization/Internationalization.h" +#include "Internationalization/Culture.h" +#include "ConfigCacheIni.h" + +#define LOCTEXT_NAMESPACE "Kismet" + +bool UKismetInternationalizationLibrary::SetCurrentCulture(const FString& Culture, const bool SaveToConfig) +{ + if (FInternationalization::Get().SetCurrentCulture(Culture)) + { + if (!GIsEditor && SaveToConfig) + { + GConfig->SetString(TEXT("Internationalization"), TEXT("Culture"), *Culture, GGameUserSettingsIni); + GConfig->EmptySection(TEXT("Internationalization.AssetGroupCultures"), GGameUserSettingsIni); + GConfig->Flush(false, GGameUserSettingsIni); + } + return true; + } + + return false; +} + +FString UKismetInternationalizationLibrary::GetCurrentCulture() +{ + return FInternationalization::Get().GetCurrentCulture()->GetName(); +} + +bool UKismetInternationalizationLibrary::SetCurrentLanguage(const FString& Culture, const bool SaveToConfig) +{ + if (FInternationalization::Get().SetCurrentLanguage(Culture)) + { + if (!GIsEditor && SaveToConfig) + { + GConfig->SetString(TEXT("Internationalization"), TEXT("Language"), *Culture, GGameUserSettingsIni); + GConfig->Flush(false, GGameUserSettingsIni); + } + return true; + } + + return false; +} + +FString UKismetInternationalizationLibrary::GetCurrentLanguage() +{ + return FInternationalization::Get().GetCurrentLanguage()->GetName(); +} + +bool UKismetInternationalizationLibrary::SetCurrentLocale(const FString& Culture, const bool SaveToConfig) +{ + if (FInternationalization::Get().SetCurrentLocale(Culture)) + { + if (!GIsEditor && SaveToConfig) + { + GConfig->SetString(TEXT("Internationalization"), TEXT("Locale"), *Culture, GGameUserSettingsIni); + GConfig->Flush(false, GGameUserSettingsIni); + } + return true; + } + + return false; +} + +FString UKismetInternationalizationLibrary::GetCurrentLocale() +{ + return FInternationalization::Get().GetCurrentLocale()->GetName(); +} + +bool UKismetInternationalizationLibrary::SetCurrentLanguageAndLocale(const FString& Culture, const bool SaveToConfig) +{ + if (FInternationalization::Get().SetCurrentLanguageAndLocale(Culture)) + { + if (!GIsEditor && SaveToConfig) + { + GConfig->SetString(TEXT("Internationalization"), TEXT("Language"), *Culture, GGameUserSettingsIni); + GConfig->SetString(TEXT("Internationalization"), TEXT("Locale"), *Culture, GGameUserSettingsIni); + GConfig->Flush(false, GGameUserSettingsIni); + } + return true; + } + + return false; +} + +bool UKismetInternationalizationLibrary::SetCurrentAssetGroupCulture(const FName AssetGroup, const FString& Culture, const bool SaveToConfig) +{ + if (FInternationalization::Get().SetCurrentAssetGroupCulture(AssetGroup, Culture)) + { + if (!GIsEditor && SaveToConfig) + { + if (FConfigSection* AssetGroupCulturesSection = GConfig->GetSectionPrivate(TEXT("Internationalization.AssetGroupCultures"), false, false, GGameUserSettingsIni)) + { + AssetGroupCulturesSection->Remove(AssetGroup); + AssetGroupCulturesSection->Add(AssetGroup, Culture); + } + GConfig->Flush(false, GGameUserSettingsIni); + } + return true; + } + + return false; +} + +FString UKismetInternationalizationLibrary::GetCurrentAssetGroupCulture(const FName AssetGroup) +{ + return FInternationalization::Get().GetCurrentAssetGroupCulture(AssetGroup)->GetName(); +} + +void UKismetInternationalizationLibrary::ClearCurrentAssetGroupCulture(const FName AssetGroup, const bool SaveToConfig) +{ + FInternationalization::Get().ClearCurrentAssetGroupCulture(AssetGroup); + + if (!GIsEditor && SaveToConfig) + { + if (FConfigSection* AssetGroupCulturesSection = GConfig->GetSectionPrivate(TEXT("Internationalization.AssetGroupCultures"), false, false, GGameUserSettingsIni)) + { + AssetGroupCulturesSection->Remove(AssetGroup); + } + GConfig->Flush(false, GGameUserSettingsIni); + } +} + +#undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Runtime/Engine/Private/KismetRenderingLibrary.cpp b/Engine/Source/Runtime/Engine/Private/KismetRenderingLibrary.cpp index 1d81815253d9..6dbf69d9fdb8 100644 --- a/Engine/Source/Runtime/Engine/Private/KismetRenderingLibrary.cpp +++ b/Engine/Source/Runtime/Engine/Private/KismetRenderingLibrary.cpp @@ -44,7 +44,7 @@ void UKismetRenderingLibrary::ClearRenderTarget2D(UObject* WorldContextObject, U [RenderTargetResource, ClearColor](FRHICommandList& RHICmdList) { SetRenderTarget(RHICmdList, RenderTargetResource->GetRenderTargetTexture(), FTextureRHIRef(), true); - DrawClearQuad(RHICmdList, GMaxRHIFeatureLevel, ClearColor); + DrawClearQuad(RHICmdList, ClearColor); }); } } @@ -207,8 +207,11 @@ void UKismetRenderingLibrary::ConvertRenderTargetToTexture2DEditorOnly( UObject* UTexture2D* NewTexture = RenderTarget->ConstructTexture2D(Texture->GetOuter(), Texture->GetName(), RenderTarget->GetMaskedFlags(), CTF_Default, NULL); check(NewTexture == Texture); - NewTexture->UpdateResource(); + NewTexture->Modify(); + NewTexture->MarkPackageDirty(); + NewTexture->PostEditChange(); + NewTexture->UpdateResource(); } else if (!RenderTarget) { @@ -357,7 +360,7 @@ void UKismetRenderingLibrary::EndDrawCanvasToRenderTarget(UObject* WorldContextO { FMessageLog("Blueprint").Warning(LOCTEXT("EndDrawCanvasToRenderTarget_InvalidWorldContextObject", "EndDrawCanvasToRenderTarget: WorldContextObject is not valid.")); } - else if (!Context.RenderTarget) + else { FMessageLog("Blueprint").Warning(LOCTEXT("EndDrawCanvasToRenderTarget_InvalidContext", "EndDrawCanvasToRenderTarget: Context must be valid.")); } diff --git a/Engine/Source/Runtime/Engine/Private/KismetSystemLibrary.cpp b/Engine/Source/Runtime/Engine/Private/KismetSystemLibrary.cpp index 6d4f7ee359b1..4d073ed6092d 100644 --- a/Engine/Source/Runtime/Engine/Private/KismetSystemLibrary.cpp +++ b/Engine/Source/Runtime/Engine/Private/KismetSystemLibrary.cpp @@ -31,6 +31,7 @@ #include "Net/OnlineEngineInterface.h" #include "UserActivityTracking.h" #include "KismetTraceUtils.h" +#include "Engine/AssetManager.h" ////////////////////////////////////////////////////////////////////////// // UKismetSystemLibrary @@ -829,16 +830,56 @@ void UKismetSystemLibrary::SetAssetClassPropertyByName(UObject* Object, FName Pr } } -UObject* UKismetSystemLibrary::Conv_AssetToObject(const TAssetPtr& Asset) +bool UKismetSystemLibrary::IsValidSoftObjectReference(const TAssetPtr& SoftObjectReference) +{ + return !SoftObjectReference.IsNull(); +} + +bool UKismetSystemLibrary::EqualEqual_SoftObjectReference(const TAssetPtr& A, const TAssetPtr& B) +{ + return A == B; +} + +bool UKismetSystemLibrary::NotEqual_SoftObjectReference(const TAssetPtr& A, const TAssetPtr& B) +{ + return A != B; +} + +bool UKismetSystemLibrary::IsValidSoftClassReference(const TAssetSubclassOf& SoftClassReference) +{ + return !SoftClassReference.IsNull(); +} + +bool UKismetSystemLibrary::EqualEqual_SoftClassReference(const TAssetSubclassOf& A, const TAssetSubclassOf& B) +{ + return A == B; +} + +bool UKismetSystemLibrary::NotEqual_SoftClassReference(const TAssetSubclassOf& A, const TAssetSubclassOf& B) +{ + return A != B; +} + +UObject* UKismetSystemLibrary::Conv_SoftObjectReferenceToObject(const TAssetPtr& Asset) { return ((const FAssetPtr*)&Asset)->Get(); } -TSubclassOf UKismetSystemLibrary::Conv_AssetClassToClass(const TAssetSubclassOf& AssetClass) +TSubclassOf UKismetSystemLibrary::Conv_SoftClassReferenceToClass(const TAssetSubclassOf& AssetClass) { return Cast(((const FAssetPtr*)&AssetClass)->Get()); } +TAssetPtr UKismetSystemLibrary::Conv_ObjectToSoftObjectReference(UObject *Object) +{ + return TAssetPtr(Object); +} + +TAssetSubclassOf UKismetSystemLibrary::Conv_ClassToSoftClassReference(const TSubclassOf& Class) +{ + return TAssetSubclassOf(*Class); +} + void UKismetSystemLibrary::SetTextPropertyByName(UObject* Object, FName PropertyName, const FText& Value) { if(Object != NULL) @@ -962,8 +1003,7 @@ bool UKismetSystemLibrary::SphereOverlapComponents(UObject* WorldContextObject, { OutComponents.Empty(); - static FName SphereOverlapComponentsName(TEXT("SphereOverlapComponents")); - FCollisionQueryParams Params(SphereOverlapComponentsName, false); + FCollisionQueryParams Params(SCENE_QUERY_STAT(SphereOverlapComponents), false); Params.AddIgnoredActors(ActorsToIgnore); Params.bTraceAsyncScene = true; TArray Overlaps; @@ -1017,8 +1057,7 @@ bool UKismetSystemLibrary::BoxOverlapComponents(UObject* WorldContextObject, con { OutComponents.Empty(); - static FName BoxOverlapComponentsName(TEXT("BoxOverlapComponents")); - FCollisionQueryParams Params(BoxOverlapComponentsName, false); + FCollisionQueryParams Params(SCENE_QUERY_STAT(BoxOverlapComponents), false); Params.bTraceAsyncScene = true; Params.AddIgnoredActors(ActorsToIgnore); @@ -1071,8 +1110,7 @@ bool UKismetSystemLibrary::CapsuleOverlapComponents(UObject* WorldContextObject, { OutComponents.Empty(); - static FName CapsuleOverlapComponentsName(TEXT("CapsuleOverlapComponents")); - FCollisionQueryParams Params(CapsuleOverlapComponentsName, false); + FCollisionQueryParams Params(SCENE_QUERY_STAT(CapsuleOverlapComponents), false); Params.bTraceAsyncScene = true; Params.AddIgnoredActors(ActorsToIgnore); @@ -1127,8 +1165,7 @@ bool UKismetSystemLibrary::ComponentOverlapComponents(UPrimitiveComponent* Compo if(Component != nullptr) { - static FName ComponentOverlapComponentsName(TEXT("ComponentOverlapComponents")); - FComponentQueryParams Params(ComponentOverlapComponentsName); + FComponentQueryParams Params(SCENE_QUERY_STAT(ComponentOverlapComponents)); Params.bTraceAsyncScene = true; Params.AddIgnoredActors(ActorsToIgnore); @@ -2261,6 +2298,11 @@ TArray UKismetSystemLibrary::GetPreferredLanguages() return FPlatformMisc::GetPreferredLanguages(); } +FString UKismetSystemLibrary::GetDefaultLanguage() +{ + return FPlatformMisc::GetDefaultLanguage(); +} + FString UKismetSystemLibrary::GetDefaultLocale() { return FPlatformMisc::GetDefaultLocale(); @@ -2392,6 +2434,11 @@ void UKismetSystemLibrary::RegisterForRemoteNotifications() FPlatformMisc::RegisterForRemoteNotifications(); } +void UKismetSystemLibrary::UnregisterForRemoteNotifications() +{ + FPlatformMisc::UnregisterForRemoteNotifications(); +} + void UKismetSystemLibrary::SetUserActivity(const FUserActivity& UserActivity) { FUserActivityTracking::SetActivity(UserActivity); @@ -2401,3 +2448,171 @@ FString UKismetSystemLibrary::GetCommandLine() { return FString(FCommandLine::Get()); } + +UObject* UKismetSystemLibrary::GetObjectFromPrimaryAssetId(FPrimaryAssetId PrimaryAssetId) +{ + if (UAssetManager* Manager = UAssetManager::GetIfValid()) + { + FPrimaryAssetTypeInfo Info; + if (Manager->GetPrimaryAssetTypeInfo(PrimaryAssetId.PrimaryAssetType, Info) && !Info.bHasBlueprintClasses) + { + return Manager->GetPrimaryAssetObject(PrimaryAssetId); + } + } + return nullptr; +} + +TSubclassOf UKismetSystemLibrary::GetClassFromPrimaryAssetId(FPrimaryAssetId PrimaryAssetId) +{ + if (UAssetManager* Manager = UAssetManager::GetIfValid()) + { + FPrimaryAssetTypeInfo Info; + if (Manager->GetPrimaryAssetTypeInfo(PrimaryAssetId.PrimaryAssetType, Info) && Info.bHasBlueprintClasses) + { + return Manager->GetPrimaryAssetObjectClass(PrimaryAssetId); + } + } + return nullptr; +} + +TAssetPtr UKismetSystemLibrary::GetSoftObjectReferenceFromPrimaryAssetId(FPrimaryAssetId PrimaryAssetId) +{ + if (UAssetManager* Manager = UAssetManager::GetIfValid()) + { + FPrimaryAssetTypeInfo Info; + if (Manager->GetPrimaryAssetTypeInfo(PrimaryAssetId.PrimaryAssetType, Info) && !Info.bHasBlueprintClasses) + { + return TAssetPtr(Manager->GetPrimaryAssetPath(PrimaryAssetId)); + } + } + return nullptr; +} + +TAssetSubclassOf UKismetSystemLibrary::GetSoftClassReferenceFromPrimaryAssetId(FPrimaryAssetId PrimaryAssetId) +{ + if (UAssetManager* Manager = UAssetManager::GetIfValid()) + { + FPrimaryAssetTypeInfo Info; + if (Manager->GetPrimaryAssetTypeInfo(PrimaryAssetId.PrimaryAssetType, Info) && Info.bHasBlueprintClasses) + { + return TAssetSubclassOf(Manager->GetPrimaryAssetPath(PrimaryAssetId)); + } + } + return nullptr; +} + +FPrimaryAssetId UKismetSystemLibrary::GetPrimaryAssetIdFromObject(UObject* Object) +{ + if (UAssetManager* Manager = UAssetManager::GetIfValid()) + { + if (Object) + { + return Manager->GetPrimaryAssetIdForObject(Object); + } + } + return FPrimaryAssetId(); +} + +FPrimaryAssetId UKismetSystemLibrary::GetPrimaryAssetIdFromClass(TSubclassOf Class) +{ + if (UAssetManager* Manager = UAssetManager::GetIfValid()) + { + if (Class) + { + return Manager->GetPrimaryAssetIdForObject(*Class); + } + } + return FPrimaryAssetId(); +} + +FPrimaryAssetId UKismetSystemLibrary::GetPrimaryAssetIdFromSoftObjectReference(TAssetPtr SoftObjectReference) +{ + if (UAssetManager* Manager = UAssetManager::GetIfValid()) + { + return Manager->GetPrimaryAssetIdForPath(SoftObjectReference.ToStringReference()); + } + return FPrimaryAssetId(); +} + +FPrimaryAssetId UKismetSystemLibrary::GetPrimaryAssetIdFromSoftClassReference(TAssetSubclassOf SoftClassReference) +{ + if (UAssetManager* Manager = UAssetManager::GetIfValid()) + { + return Manager->GetPrimaryAssetIdForPath(SoftClassReference.ToStringReference()); + } + return FPrimaryAssetId(); +} + +void UKismetSystemLibrary::GetPrimaryAssetIdList(FPrimaryAssetType PrimaryAssetType, TArray& OutPrimaryAssetIdList) +{ + if (UAssetManager* Manager = UAssetManager::GetIfValid()) + { + Manager->GetPrimaryAssetIdList(PrimaryAssetType, OutPrimaryAssetIdList); + } +} + +bool UKismetSystemLibrary::IsValidPrimaryAssetId(FPrimaryAssetId PrimaryAssetId) +{ + return PrimaryAssetId.IsValid(); +} + +bool UKismetSystemLibrary::EqualEqual_PrimaryAssetId(FPrimaryAssetId A, FPrimaryAssetId B) +{ + return A == B; +} + +bool UKismetSystemLibrary::NotEqual_PrimaryAssetId(FPrimaryAssetId A, FPrimaryAssetId B) +{ + return A != B; +} + +bool UKismetSystemLibrary::IsValidPrimaryAssetType(FPrimaryAssetType PrimaryAssetType) +{ + return PrimaryAssetType.IsValid(); +} + +bool UKismetSystemLibrary::EqualEqual_PrimaryAssetType(FPrimaryAssetType A, FPrimaryAssetType B) +{ + return A == B; +} + +bool UKismetSystemLibrary::NotEqual_PrimaryAssetType(FPrimaryAssetType A, FPrimaryAssetType B) +{ + return A != B; +} + +void UKismetSystemLibrary::UnloadPrimaryAsset(FPrimaryAssetId PrimaryAssetId) +{ + if (UAssetManager* Manager = UAssetManager::GetIfValid()) + { + Manager->UnloadPrimaryAsset(PrimaryAssetId); + } +} + +void UKismetSystemLibrary::UnloadPrimaryAssetList(const TArray& PrimaryAssetIdList) +{ + if (UAssetManager* Manager = UAssetManager::GetIfValid()) + { + Manager->UnloadPrimaryAssets(PrimaryAssetIdList); + } +} + +bool UKismetSystemLibrary::GetCurrentBundleState(FPrimaryAssetId PrimaryAssetId, bool bForceCurrentState, TArray& OutBundles) +{ + if (UAssetManager* Manager = UAssetManager::GetIfValid()) + { + if (Manager->GetPrimaryAssetHandle(PrimaryAssetId, bForceCurrentState, &OutBundles).IsValid()) + { + return true; + } + } + return false; +} + +void UKismetSystemLibrary::GetPrimaryAssetsWithBundleState(const TArray& RequiredBundles, const TArray& ExcludedBundles, const TArray& ValidTypes, bool bForceCurrentState, TArray& OutPrimaryAssetIdList) +{ + if (UAssetManager* Manager = UAssetManager::GetIfValid()) + { + Manager->GetPrimaryAssetsWithBundleState(OutPrimaryAssetIdList, ValidTypes, RequiredBundles, ExcludedBundles, bForceCurrentState); + } +} \ No newline at end of file diff --git a/Engine/Source/Runtime/Engine/Private/KismetTextLibrary.cpp b/Engine/Source/Runtime/Engine/Private/KismetTextLibrary.cpp index e9bb2d23224a..f69716fe7134 100644 --- a/Engine/Source/Runtime/Engine/Private/KismetTextLibrary.cpp +++ b/Engine/Source/Runtime/Engine/Private/KismetTextLibrary.cpp @@ -6,18 +6,10 @@ #define LOCTEXT_NAMESPACE "Kismet" - -/* UKismetTextLibrary structors - *****************************************************************************/ - UKismetTextLibrary::UKismetTextLibrary(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { } - -/* UKismetTextLibrary static functions - *****************************************************************************/ - FText UKismetTextLibrary::Conv_VectorToText(FVector InVec) { FFormatNamedArguments Args; @@ -28,7 +20,6 @@ FText UKismetTextLibrary::Conv_VectorToText(FVector InVec) return FText::Format(NSLOCTEXT("Core", "Vector3", "X={X} Y={Y} Z={Z}"), Args); } - FText UKismetTextLibrary::Conv_Vector2dToText(FVector2D InVec) { FFormatNamedArguments Args; @@ -38,7 +29,6 @@ FText UKismetTextLibrary::Conv_Vector2dToText(FVector2D InVec) return FText::Format(NSLOCTEXT("Core", "Vector2", "X={X} Y={Y}"), Args); } - FText UKismetTextLibrary::Conv_RotatorToText(FRotator InRot) { FFormatNamedArguments Args; @@ -49,18 +39,29 @@ FText UKismetTextLibrary::Conv_RotatorToText(FRotator InRot) return FText::Format(NSLOCTEXT("Core", "Rotator", "P={P} Y={Y} R={R}"), Args); } - FText UKismetTextLibrary::Conv_TransformToText(const FTransform& InTrans) { - return FText::FromString(InTrans.ToString()); -} + const FVector T(InTrans.GetTranslation()); + const FRotator R(InTrans.Rotator()); + const FVector S(InTrans.GetScale3D()); + FFormatNamedArguments Args; + Args.Add(TEXT("T"), Conv_VectorToText(T)); + Args.Add(TEXT("R"), Conv_RotatorToText(R)); + Args.Add(TEXT("S"), Conv_VectorToText(S)); + + return FText::Format(NSLOCTEXT("Core", "Transform", "Translation: {T} Rotation: {R} Scale: {S}"), Args); +} FText UKismetTextLibrary::Conv_ObjectToText(class UObject* InObj) { - return FText::FromString((InObj != NULL) ? InObj->GetName() : FString(TEXT("None"))); -} + if (InObj) + { + return FText::AsCultureInvariant(InObj->GetName()); + } + return GNone; +} FText UKismetTextLibrary::Conv_ColorToText(FLinearColor InColor) { @@ -73,121 +74,101 @@ FText UKismetTextLibrary::Conv_ColorToText(FLinearColor InColor) return FText::Format(NSLOCTEXT("Core", "LinearColor", "R={R} G={G} B={B} A={A}"), Args); } - FString UKismetTextLibrary::Conv_TextToString(const FText& InText) { return InText.ToString(); } - FText UKismetTextLibrary::Conv_StringToText(const FString& InString) { - return FText::FromString(InString); + return FText::AsCultureInvariant(InString); } - FText UKismetTextLibrary::Conv_NameToText(FName InName) { - return FText::FromName(InName); + return FText::AsCultureInvariant(InName.ToString()); } - bool UKismetTextLibrary::TextIsEmpty(const FText& InText) { return InText.IsEmpty(); } - bool UKismetTextLibrary::TextIsTransient(const FText& InText) { return InText.IsTransient(); } - bool UKismetTextLibrary::TextIsCultureInvariant(const FText& InText) { return InText.IsCultureInvariant(); } - FText UKismetTextLibrary::TextToLower(const FText& InText) { return InText.ToLower(); } - FText UKismetTextLibrary::TextToUpper(const FText& InText) { return InText.ToUpper(); } - FText UKismetTextLibrary::TextTrimPreceding(const FText& InText) { return FText::TrimPreceding(InText); } - FText UKismetTextLibrary::TextTrimTrailing(const FText& InText) { return FText::TrimTrailing(InText); } - FText UKismetTextLibrary::TextTrimPrecedingAndTrailing(const FText& InText) { return FText::TrimPrecedingAndTrailing(InText); } - FText UKismetTextLibrary::GetEmptyText() { return FText::GetEmpty(); } - bool UKismetTextLibrary::FindTextInLocalizationTable(const FString& Namespace, const FString& Key, FText& OutText) { return FText::FindText(Namespace, Key, OutText); } - bool UKismetTextLibrary::EqualEqual_IgnoreCase_TextText(const FText& A, const FText& B) { return A.EqualToCaseIgnored( B ); } - bool UKismetTextLibrary::EqualEqual_TextText(const FText& A, const FText& B) { return A.EqualTo( B ); } - bool UKismetTextLibrary::NotEqual_IgnoreCase_TextText(const FText& A, const FText& B) { return !A.EqualToCaseIgnored( B ); } - bool UKismetTextLibrary::NotEqual_TextText(const FText& A, const FText& B) { return !A.EqualTo( B ); } - FText UKismetTextLibrary::Conv_BoolToText(bool InBool) { return InBool ? LOCTEXT("True", "true") : LOCTEXT("False", "false"); } - FText UKismetTextLibrary::Conv_ByteToText(uint8 Value) { return FText::AsNumber(Value, &FNumberFormattingOptions::DefaultNoGrouping()); } - FText UKismetTextLibrary::Conv_IntToText(int32 Value, bool bUseGrouping/* = true*/, int32 MinimumIntegralDigits/* = 1*/, int32 MaximumIntegralDigits/* = 324*/) { // Only update the values that need to be changed from the default FNumberFormattingOptions, @@ -200,7 +181,6 @@ FText UKismetTextLibrary::Conv_IntToText(int32 Value, bool bUseGrouping/* = true return FText::AsNumber(Value, &NumberFormatOptions); } - FText UKismetTextLibrary::Conv_FloatToText(float Value, TEnumAsByte RoundingMode, bool bUseGrouping/* = true*/, int32 MinimumIntegralDigits/* = 1*/, int32 MaximumIntegralDigits/* = 324*/, int32 MinimumFractionalDigits/* = 0*/, int32 MaximumFractionalDigits/* = 3*/) { FNumberFormattingOptions NumberFormatOptions; @@ -258,67 +238,56 @@ FText UKismetTextLibrary::AsPercent_Float(float Value, TEnumAsByte InArgs) { return FTextFormatter::Format(MoveTemp(InPattern), MoveTemp(InArgs), false, false); } - bool UKismetTextLibrary::TextIsFromStringTable(const FText& Text) { return Text.IsFromStringTable(); } - FText UKismetTextLibrary::TextFromStringTable(const FName TableId, const FString& Key) { return FText::FromStringTable(TableId, Key); } - bool UKismetTextLibrary::StringTableIdAndKeyFromText(FText Text, FName& OutTableId, FString& OutKey) { return FStringTableRegistry::Get().FindTableIdAndKey(Text, OutTableId, OutKey); diff --git a/Engine/Source/Runtime/Engine/Private/KismetTraceUtils.cpp b/Engine/Source/Runtime/Engine/Private/KismetTraceUtils.cpp index 9dea2f0f2123..0b801bc56248 100644 --- a/Engine/Source/Runtime/Engine/Private/KismetTraceUtils.cpp +++ b/Engine/Source/Runtime/Engine/Private/KismetTraceUtils.cpp @@ -10,7 +10,7 @@ static const float KISMET_TRACE_DEBUG_IMPACTPOINT_SIZE = 16.f; FCollisionQueryParams ConfigureCollisionParams(FName TraceTag, bool bTraceComplex, const TArray& ActorsToIgnore, bool bIgnoreSelf, UObject* WorldContextObject) { - FCollisionQueryParams Params(TraceTag, bTraceComplex); + FCollisionQueryParams Params(TraceTag, SCENE_QUERY_STAT_ONLY(KismetTraceUtils), bTraceComplex); Params.bReturnPhysicalMaterial = true; Params.bReturnFaceIndex = !UPhysicsSettings::Get()->bSuppressFaceRemapTable; // Ask for face index, as long as we didn't disable globally Params.bTraceAsyncScene = true; @@ -112,7 +112,7 @@ void DrawDebugSweptBox(const UWorld* InWorld, FVector const& Start, FVector cons } /** Util for drawing result of single line trace */ -void DrawDebugLineTraceSingle(const UWorld* World, const FVector& Start, const FVector& End, EDrawDebugTrace::Type DrawDebugType, bool bHit, FHitResult& OutHit, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime) +void DrawDebugLineTraceSingle(const UWorld* World, const FVector& Start, const FVector& End, EDrawDebugTrace::Type DrawDebugType, bool bHit, const FHitResult& OutHit, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime) { if (DrawDebugType != EDrawDebugTrace::None) { @@ -166,7 +166,7 @@ void DrawDebugLineTraceMulti(const UWorld* World, const FVector& Start, const FV } } -void DrawDebugBoxTraceSingle(const UWorld* World, const FVector& Start, const FVector& End, const FVector HalfSize, const FRotator Orientation, EDrawDebugTrace::Type DrawDebugType, bool bHit, FHitResult& OutHit, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime) +void DrawDebugBoxTraceSingle(const UWorld* World, const FVector& Start, const FVector& End, const FVector HalfSize, const FRotator Orientation, EDrawDebugTrace::Type DrawDebugType, bool bHit, const FHitResult& OutHit, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime) { if (DrawDebugType != EDrawDebugTrace::None && (World != nullptr)) { @@ -188,7 +188,7 @@ void DrawDebugBoxTraceSingle(const UWorld* World, const FVector& Start, const FV } } -void DrawDebugBoxTraceMulti(const UWorld* World, const FVector& Start, const FVector& End, const FVector HalfSize, const FRotator Orientation, EDrawDebugTrace::Type DrawDebugType, bool bHit, TArray& OutHits, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime) +void DrawDebugBoxTraceMulti(const UWorld* World, const FVector& Start, const FVector& End, const FVector HalfSize, const FRotator Orientation, EDrawDebugTrace::Type DrawDebugType, bool bHit, const TArray& OutHits, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime) { if (DrawDebugType != EDrawDebugTrace::None && (World != nullptr)) { @@ -217,7 +217,7 @@ void DrawDebugBoxTraceMulti(const UWorld* World, const FVector& Start, const FVe } } -void DrawDebugSphereTraceSingle(const UWorld* World, const FVector& Start, const FVector& End, float Radius, EDrawDebugTrace::Type DrawDebugType, bool bHit, FHitResult& OutHit, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime) +void DrawDebugSphereTraceSingle(const UWorld* World, const FVector& Start, const FVector& End, float Radius, EDrawDebugTrace::Type DrawDebugType, bool bHit, const FHitResult& OutHit, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime) { if (DrawDebugType != EDrawDebugTrace::None) { @@ -239,7 +239,7 @@ void DrawDebugSphereTraceSingle(const UWorld* World, const FVector& Start, const } } -void DrawDebugSphereTraceMulti(const UWorld* World, const FVector& Start, const FVector& End, float Radius, EDrawDebugTrace::Type DrawDebugType, bool bHit, TArray& OutHits, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime) +void DrawDebugSphereTraceMulti(const UWorld* World, const FVector& Start, const FVector& End, float Radius, EDrawDebugTrace::Type DrawDebugType, bool bHit, const TArray& OutHits, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime) { if (DrawDebugType != EDrawDebugTrace::None) { @@ -268,7 +268,7 @@ void DrawDebugSphereTraceMulti(const UWorld* World, const FVector& Start, const } } -void DrawDebugCapsuleTraceSingle(const UWorld* World, const FVector& Start, const FVector& End, float Radius, float HalfHeight, EDrawDebugTrace::Type DrawDebugType, bool bHit, FHitResult& OutHit, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime) +void DrawDebugCapsuleTraceSingle(const UWorld* World, const FVector& Start, const FVector& End, float Radius, float HalfHeight, EDrawDebugTrace::Type DrawDebugType, bool bHit, const FHitResult& OutHit, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime) { if (DrawDebugType != EDrawDebugTrace::None) { @@ -296,7 +296,7 @@ void DrawDebugCapsuleTraceSingle(const UWorld* World, const FVector& Start, cons } } -void DrawDebugCapsuleTraceMulti(const UWorld* World, const FVector& Start, const FVector& End, float Radius, float HalfHeight, EDrawDebugTrace::Type DrawDebugType, bool bHit, TArray& OutHits, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime) +void DrawDebugCapsuleTraceMulti(const UWorld* World, const FVector& Start, const FVector& End, float Radius, float HalfHeight, EDrawDebugTrace::Type DrawDebugType, bool bHit, const TArray& OutHits, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime) { if (DrawDebugType != EDrawDebugTrace::None) { diff --git a/Engine/Source/Runtime/Engine/Private/KismetTraceUtils.h b/Engine/Source/Runtime/Engine/Private/KismetTraceUtils.h index 11c5bb5686c8..69601f046cfb 100644 --- a/Engine/Source/Runtime/Engine/Private/KismetTraceUtils.h +++ b/Engine/Source/Runtime/Engine/Private/KismetTraceUtils.h @@ -18,17 +18,17 @@ FCollisionObjectQueryParams ConfigureCollisionObjectParams(const TArray& OutHits, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime); -void DrawDebugBoxTraceSingle(const UWorld* World, const FVector& Start, const FVector& End, const FVector HalfSize, const FRotator Orientation, EDrawDebugTrace::Type DrawDebugType, bool bHit, FHitResult& OutHit, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime); -void DrawDebugBoxTraceMulti(const UWorld* World, const FVector& Start, const FVector& End, const FVector HalfSize, const FRotator Orientation, EDrawDebugTrace::Type DrawDebugType, bool bHit, TArray& OutHits, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime); +void DrawDebugBoxTraceSingle(const UWorld* World, const FVector& Start, const FVector& End, const FVector HalfSize, const FRotator Orientation, EDrawDebugTrace::Type DrawDebugType, bool bHit, const FHitResult& OutHit, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime); +void DrawDebugBoxTraceMulti(const UWorld* World, const FVector& Start, const FVector& End, const FVector HalfSize, const FRotator Orientation, EDrawDebugTrace::Type DrawDebugType, bool bHit, const TArray& OutHits, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime); -void DrawDebugSphereTraceSingle(const UWorld* World, const FVector& Start, const FVector& End, float Radius, EDrawDebugTrace::Type DrawDebugType, bool bHit, FHitResult& OutHit, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime); -void DrawDebugSphereTraceMulti(const UWorld* World, const FVector& Start, const FVector& End, float Radius, EDrawDebugTrace::Type DrawDebugType, bool bHit, TArray& OutHits, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime); +void DrawDebugSphereTraceSingle(const UWorld* World, const FVector& Start, const FVector& End, float Radius, EDrawDebugTrace::Type DrawDebugType, bool bHit, const FHitResult& OutHit, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime); +void DrawDebugSphereTraceMulti(const UWorld* World, const FVector& Start, const FVector& End, float Radius, EDrawDebugTrace::Type DrawDebugType, bool bHit, const TArray& OutHits, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime); -void DrawDebugCapsuleTraceSingle(const UWorld* World, const FVector& Start, const FVector& End, float Radius, float HalfHeight, EDrawDebugTrace::Type DrawDebugType, bool bHit, FHitResult& OutHit, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime); -void DrawDebugCapsuleTraceMulti(const UWorld* World, const FVector& Start, const FVector& End, float Radius, float HalfHeight, EDrawDebugTrace::Type DrawDebugType, bool bHit, TArray& OutHits, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime); +void DrawDebugCapsuleTraceSingle(const UWorld* World, const FVector& Start, const FVector& End, float Radius, float HalfHeight, EDrawDebugTrace::Type DrawDebugType, bool bHit, const FHitResult& OutHit, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime); +void DrawDebugCapsuleTraceMulti(const UWorld* World, const FVector& Start, const FVector& End, float Radius, float HalfHeight, EDrawDebugTrace::Type DrawDebugType, bool bHit, const TArray& OutHits, FLinearColor TraceColor, FLinearColor TraceHitColor, float DrawTime); #endif // ENABLE_DRAW_DEBUG diff --git a/Engine/Source/Runtime/Engine/Private/LODActor.cpp b/Engine/Source/Runtime/Engine/Private/LODActor.cpp index 6d4bd5f1089b..fe0385988ce6 100644 --- a/Engine/Source/Runtime/Engine/Private/LODActor.cpp +++ b/Engine/Source/Runtime/Engine/Private/LODActor.cpp @@ -483,6 +483,7 @@ void ALODActor::DetermineShadowingFlags() bool bCastsShadow = false; bool bCastsStaticShadow = false; bool bCastsDynamicShadow = false; + bool bCastFarShadow = false; for (AActor* Actor : SubActors) { TArray StaticMeshComponents; @@ -492,12 +493,14 @@ void ALODActor::DetermineShadowingFlags() bCastsShadow |= Component->CastShadow; bCastsStaticShadow |= Component->bCastStaticShadow; bCastsDynamicShadow |= Component->bCastDynamicShadow; + bCastFarShadow |= Component->bCastFarShadow; } } StaticMeshComponent->CastShadow = bCastsShadow; StaticMeshComponent->bCastStaticShadow = bCastsStaticShadow; StaticMeshComponent->bCastDynamicShadow = bCastsDynamicShadow; + StaticMeshComponent->bCastFarShadow = bCastFarShadow; StaticMeshComponent->MarkRenderStateDirty(); } @@ -676,16 +679,9 @@ void ALODActor::RecalculateDrawingDistance(const float InTransitionScreenSize) static const float FOVRad = 90.0f * (float)PI / 360.0f; static const FMatrix ProjectionMatrix = FPerspectiveMatrix(FOVRad, 1920, 1080, 0.01f); FBoxSphereBounds Bounds = GetStaticMeshComponent()->CalcBounds(FTransform()); + LODDrawDistance = ComputeBoundsDrawDistance(InTransitionScreenSize, Bounds.SphereRadius, ProjectionMatrix); - // Get projection multiple accounting for view scaling. - const float ScreenMultiple = FMath::Max(1920.0f / 2.0f * ProjectionMatrix.M[0][0], - 1080.0f / 2.0f * ProjectionMatrix.M[1][1]); - - // ScreenSize is the projected diameter, so halve it - const float ScreenRadius = FMath::Max(SMALL_NUMBER, InTransitionScreenSize * 0.5f); - - // Invert the calcs in ComputeBoundsScreenSize - LODDrawDistance = FMath::Sqrt(FMath::Abs((FMath::Square((ScreenMultiple * Bounds.SphereRadius) / ScreenRadius)) + FMath::Square(Bounds.SphereRadius))); + StaticMeshComponent->MinDrawDistance = LODDrawDistance; UpdateSubActorLODParents(); } diff --git a/Engine/Source/Runtime/Engine/Private/Level.cpp b/Engine/Source/Runtime/Engine/Private/Level.cpp index d01f6a54e300..1165e978d707 100644 --- a/Engine/Source/Runtime/Engine/Private/Level.cpp +++ b/Engine/Source/Runtime/Engine/Private/Level.cpp @@ -1851,7 +1851,7 @@ void ULevel::SetLightingScenario(bool bNewIsLightingScenario) { bIsLightingScenario = bNewIsLightingScenario; - OwningWorld->PropagateLightingScenarioChange(); + OwningWorld->PropagateLightingScenarioChange(true); } #if WITH_EDITOR @@ -1952,10 +1952,10 @@ void ULevel::CleanupLevelScriptBlueprint() void ULevel::OnLevelScriptBlueprintChanged(ULevelScriptBlueprint* InBlueprint) { - if( !InBlueprint->bIsRegeneratingOnLoad ) - { + if( !InBlueprint->bIsRegeneratingOnLoad && // Make sure this is OUR level scripting blueprint - check(InBlueprint == LevelScriptBlueprint); + ensureMsgf(InBlueprint == LevelScriptBlueprint, TEXT("Level ('%s') recieved OnLevelScriptBlueprintChanged notification for the wrong Blueprint ('%s')."), LevelScriptBlueprint ? *LevelScriptBlueprint->GetPathName() : TEXT("NULL"), *InBlueprint->GetPathName()) ) + { UClass* SpawnClass = (LevelScriptBlueprint->GeneratedClass) ? LevelScriptBlueprint->GeneratedClass : LevelScriptBlueprint->SkeletonGeneratedClass; // Get rid of the old LevelScriptActor diff --git a/Engine/Source/Runtime/Engine/Private/LevelActor.cpp b/Engine/Source/Runtime/Engine/Private/LevelActor.cpp index c076b22fa100..75b722504682 100644 --- a/Engine/Source/Runtime/Engine/Private/LevelActor.cpp +++ b/Engine/Source/Runtime/Engine/Private/LevelActor.cpp @@ -247,7 +247,7 @@ void LineCheckTracker::CaptureLineCheck(int32 LineCheckFlags, const FVector* Ext Level actor management. -----------------------------------------------------------------------------*/ // LOOKING_FOR_PERF_ISSUES -#define PERF_SHOW_MULTI_PAWN_SPAWN_FRAMES ((1 && !(UE_BUILD_SHIPPING || UE_BUILD_TEST)) || !WITH_EDITORONLY_DATA) +#define PERF_SHOW_MULTI_PAWN_SPAWN_FRAMES (!(UE_BUILD_SHIPPING || UE_BUILD_TEST)) && (LOOKING_FOR_PERF_ISSUES || !WITH_EDITORONLY_DATA) #if PERF_SHOW_MULTI_PAWN_SPAWN_FRAMES /** Array showing names of pawns spawned this frame. */ @@ -401,7 +401,7 @@ AActor* UWorld::SpawnActor( UClass* Class, FTransform const* UserTransformPtr, c // note: we can't handle all cases here, since we don't know the full component hierarchy until after the actor is spawned if (CollisionHandlingMethod == ESpawnActorCollisionHandlingMethod::DontSpawnIfColliding) { - USceneComponent* const TemplateRootComponent = Template ? Template->GetRootComponent() : nullptr; + USceneComponent* const TemplateRootComponent = Template->GetRootComponent(); // Note that we respect any initial transformation the root component may have from the CDO, so the final transform // might necessarily be exactly the passed-in UserTransform. @@ -605,7 +605,7 @@ bool UWorld::DestroyActor( AActor* ThisActor, bool bNetForce, bool bShouldModify OldParentActor->Modify(); } - ThisActor->DetachRootComponentFromParent(); + ThisActor->DetachFromActor(FDetachmentTransformRules::KeepWorldTransform); #if WITH_EDITOR if( GIsEditor ) @@ -793,8 +793,6 @@ bool UWorld::FindTeleportSpot(AActor* TestActor, FVector& TestLocation, FRotator return !EncroachingBlockingGeometry(TestActor, TestLocation, TestRotation, &Adjust); } -static const FName NAME_ComponentEncroachesBlockingGeometry_NoAdjustment = FName(TEXT("ComponentEncroachesBlockingGeometry_NoAdjustment")); - /** Tests shape components more efficiently than the with-adjustment case, but does less-efficient ppr-poly collision for meshes. */ static bool ComponentEncroachesBlockingGeometry_NoAdjustment(UWorld const* World, AActor const* TestActor, UPrimitiveComponent const* PrimComp, FTransform const& TestWorldTransform, const TArray& IgnoreActors) { @@ -815,7 +813,7 @@ static bool ComponentEncroachesBlockingGeometry_NoAdjustment(UWorld const* World { // must be registered TArray Overlaps; - FComponentQueryParams Params(NAME_ComponentEncroachesBlockingGeometry_NoAdjustment, TestActor); + FComponentQueryParams Params(SCENE_QUERY_STAT(ComponentEncroachesBlockingGeometry_NoAdjustment), TestActor); FCollisionResponseParams ResponseParams; PrimComp->InitSweepCollisionParams(Params, ResponseParams); Params.AddIgnoredActors(IgnoreActors); @@ -829,7 +827,7 @@ static bool ComponentEncroachesBlockingGeometry_NoAdjustment(UWorld const* World } else { - FCollisionQueryParams Params(NAME_ComponentEncroachesBlockingGeometry_NoAdjustment, false, TestActor); + FCollisionQueryParams Params(SCENE_QUERY_STAT(ComponentEncroachesBlockingGeometry_NoAdjustment), false, TestActor); FCollisionResponseParams ResponseParams; PrimComp->InitSweepCollisionParams(Params, ResponseParams); Params.AddIgnoredActors(IgnoreActors); @@ -840,8 +838,6 @@ static bool ComponentEncroachesBlockingGeometry_NoAdjustment(UWorld const* World return false; } -static const FName NAME_ComponentEncroachesBlockingGeometry_WithAdjustment = FName(TEXT("ComponentEncroachesBlockingGeometry_WithAdjustment")); - /** Tests shape components less efficiently than the no-adjustment case, but does quicker aabb collision for meshes. */ static bool ComponentEncroachesBlockingGeometry_WithAdjustment(UWorld const* World, AActor const* TestActor, UPrimitiveComponent const* PrimComp, FTransform const& TestWorldTransform, FVector& OutProposedAdjustment, const TArray& IgnoreActors) { @@ -867,7 +863,7 @@ static bool ComponentEncroachesBlockingGeometry_WithAdjustment(UWorld const* Wor if (PrimComp->IsRegistered()) { // must be registered - FComponentQueryParams Params(NAME_ComponentEncroachesBlockingGeometry_WithAdjustment, TestActor); + FComponentQueryParams Params(SCENE_QUERY_STAT(ComponentEncroachesBlockingGeometry_WithAdjustment), TestActor); FCollisionResponseParams ResponseParams; PrimComp->InitSweepCollisionParams(Params, ResponseParams); Params.AddIgnoredActors(IgnoreActors); @@ -882,7 +878,7 @@ static bool ComponentEncroachesBlockingGeometry_WithAdjustment(UWorld const* Wor else { // overlap our shape - FCollisionQueryParams Params(NAME_ComponentEncroachesBlockingGeometry_WithAdjustment, false, TestActor); + FCollisionQueryParams Params(SCENE_QUERY_STAT(ComponentEncroachesBlockingGeometry_WithAdjustment), false, TestActor); FCollisionResponseParams ResponseParams; PrimComp->InitSweepCollisionParams(Params, ResponseParams); Params.AddIgnoredActors(IgnoreActors); diff --git a/Engine/Source/Runtime/Engine/Private/LevelActorContainer.cpp b/Engine/Source/Runtime/Engine/Private/LevelActorContainer.cpp index 991f4ca316a3..57ce106b09ee 100644 --- a/Engine/Source/Runtime/Engine/Private/LevelActorContainer.cpp +++ b/Engine/Source/Runtime/Engine/Private/LevelActorContainer.cpp @@ -14,100 +14,6 @@ Level.cpp: Level-related functions DEFINE_LOG_CATEGORY_STATIC(LogLevelActorContainer, Log, All); -/** -* Pool for reducing allocations when constructing clusters -*/ -class FActorClusterArrayPool -{ -public: - - /** - * Gets the singleton instance of the FObjectArrayPool - * @return Pool singleton. - */ - FORCEINLINE static FActorClusterArrayPool& Get() - { - static FActorClusterArrayPool Singleton; - return Singleton; - } - - /** - * Gets an event from the pool or creates one if necessary. - * - * @return The array. - * @see ReturnToPool - */ - FORCEINLINE TArray* GetArrayFromPool() - { - TArray* Result = Pool.Pop(); - if (!Result) - { - Result = new TArray(); - } - check(Result); -#if UE_BUILD_DEBUG - NumberOfUsedArrays.Increment(); -#endif // UE_BUILD_DEBUG - return Result; - } - - /** - * Returns an array to the pool. - * - * @param Array The array to return. - * @see GetArrayFromPool - */ - FORCEINLINE void ReturnToPool(TArray* Array) - { -#if UE_BUILD_DEBUG - const int32 CheckUsedArrays = NumberOfUsedArrays.Decrement(); - checkSlow(CheckUsedArrays >= 0); -#endif // UE_BUILD_DEBUG - check(Array); - Array->Reset(); - Pool.Push(Array); - } - - /** Performs memory cleanup */ - void Cleanup() - { -#if UE_BUILD_DEBUG - const int32 CheckUsedArrays = NumberOfUsedArrays.GetValue(); - checkSlow(CheckUsedArrays == 0); -#endif // UE_BUILD_DEBUG - - uint32 FreedMemory = 0; - TArray< TArray* > AllArrays; - Pool.PopAll(AllArrays); - for (TArray* Array : AllArrays) - { - FreedMemory += Array->GetAllocatedSize(); - delete Array; - } - UE_LOG(LogLevelActorContainer, Log, TEXT("Freed %ub from %d cluster array pools."), FreedMemory, AllArrays.Num()); - } - -#if UE_BUILD_DEBUG - void CheckLeaks() - { - // This function is called after cluster has been created so at this point there should be no - // arrays used by cluster creation code and all should be returned to the pool - const int32 LeakedPoolArrays = NumberOfUsedArrays.GetValue(); - checkSlow(LeakedPoolArrays == 0); - } -#endif - -private: - - /** Holds the collection of recycled arrays. */ - TLockFreePointerListLIFO< TArray > Pool; - -#if UE_BUILD_DEBUG - /** Number of arrays currently acquired from the pool by clusters */ - FThreadSafeCounter NumberOfUsedArrays; -#endif // UE_BUILD_DEBUG -}; - /** * Handles UObject references found by TFastReferenceCollector */ @@ -251,8 +157,10 @@ public: for (int32 OtherClusterReferencedCluster : OtherCluster.ReferencedClusters) { - check(OtherClusterReferencedCluster != ClusterRootIndex); - Cluster.ReferencedClusters.AddUnique(OtherClusterReferencedCluster); + if (OtherClusterReferencedCluster != ClusterRootIndex) + { + Cluster.ReferencedClusters.AddUnique(OtherClusterReferencedCluster); + } } for (int32 OtherClusterReferencedMutableObjectIndex : OtherCluster.MutableObjects) { @@ -286,24 +194,24 @@ template class TActorClusterCollector : public FReferenceCollector { TProcessor& Processor; - TArray& ObjectArray; + FGCArrayStruct& ObjectArrayStruct; public: - TActorClusterCollector(TProcessor& InProcessor, TArray& InObjectArray) + TActorClusterCollector(TProcessor& InProcessor, FGCArrayStruct& InObjectArrayStruct) : Processor(InProcessor) - , ObjectArray(InObjectArray) + , ObjectArrayStruct(InObjectArrayStruct) { } virtual void HandleObjectReference(UObject*& Object, const UObject* ReferencingObject, const UProperty* ReferencingProperty) override { - Processor.HandleTokenStreamObjectReference(ObjectArray, const_cast(ReferencingObject), Object, INDEX_NONE, false); + Processor.HandleTokenStreamObjectReference(ObjectArrayStruct.ObjectsToSerialize, const_cast(ReferencingObject), Object, INDEX_NONE, false); } virtual void HandleObjectReferences(UObject** InObjects, const int32 ObjectNum, const UObject* ReferencingObject, const UProperty* InReferencingProperty) override { for (int32 ObjectIndex = 0; ObjectIndex < ObjectNum; ++ObjectIndex) { UObject*& Object = InObjects[ObjectIndex]; - Processor.HandleTokenStreamObjectReference(ObjectArray, const_cast(ReferencingObject), Object, INDEX_NONE, false); + Processor.HandleTokenStreamObjectReference(ObjectArrayStruct.ObjectsToSerialize, const_cast(ReferencingObject), Object, INDEX_NONE, false); } } virtual bool IsIgnoringArchetypeRef() const override @@ -336,12 +244,13 @@ void ULevelActorContainer::CreateCluster() // Collect all objects referenced by cluster root and by all objects it's referencing FActorClusterReferenceProcessor Processor(ContainerInternalIndex, Cluster, CastChecked(GetOuter())); - TFastReferenceCollector, FActorClusterArrayPool, true> ReferenceCollector(Processor, FActorClusterArrayPool::Get()); - TArray ObjectsToProcess; + TFastReferenceCollector, FGCArrayPool, true> ReferenceCollector(Processor, FGCArrayPool::Get()); + FGCArrayStruct ArrayStruct; + TArray& ObjectsToProcess = ArrayStruct.ObjectsToSerialize; ObjectsToProcess.Add(static_cast(this)); - ReferenceCollector.CollectReferences(ObjectsToProcess); + ReferenceCollector.CollectReferences(ArrayStruct); #if UE_BUILD_DEBUG - FActorClusterArrayPool::Get().CheckLeaks(); + FGCArrayPool::Get().CheckLeaks(); #endif if (Cluster.Objects.Num()) diff --git a/Engine/Source/Runtime/Engine/Private/LevelBounds.cpp b/Engine/Source/Runtime/Engine/Private/LevelBounds.cpp index c6a7df673306..28c99d46e609 100644 --- a/Engine/Source/Runtime/Engine/Private/LevelBounds.cpp +++ b/Engine/Source/Runtime/Engine/Private/LevelBounds.cpp @@ -43,7 +43,7 @@ FBox ALevelBounds::GetComponentsBoundingBox(bool bNonColliding) const { checkf(RootComponent != nullptr, TEXT("LevelBounds actor with null root component: %s"), *GetPathNameSafe(this)); FVector BoundsCenter = RootComponent->GetComponentLocation(); - FVector BoundsExtent = RootComponent->ComponentToWorld.GetScale3D() * 0.5f; + FVector BoundsExtent = RootComponent->GetComponentTransform().GetScale3D() * 0.5f; return FBox(BoundsCenter - BoundsExtent, BoundsCenter + BoundsExtent); } diff --git a/Engine/Source/Runtime/Engine/Private/LevelStreaming.cpp b/Engine/Source/Runtime/Engine/Private/LevelStreaming.cpp index 1d6051dd53c5..92ebeb88947c 100644 --- a/Engine/Source/Runtime/Engine/Private/LevelStreaming.cpp +++ b/Engine/Source/Runtime/Engine/Private/LevelStreaming.cpp @@ -227,7 +227,7 @@ void ULevelStreaming::PostLoad() // Convert the FName reference to a TAssetPtr, then broadcast that we loaded a reference // so this reference is gathered by the cooker without having to resave the package. SetWorldAssetByPackageName(PackageName_DEPRECATED); - FCoreUObjectDelegates::StringAssetReferenceLoaded.ExecuteIfBound(WorldAsset.ToStringReference().ToString()); + WorldAsset.GetUniqueID().PostLoadPath(); } else { @@ -899,7 +899,7 @@ FBox ULevelStreaming::GetStreamingVolumeBounds() ALevelStreamingVolume* StreamingVol = EditorStreamingVolumes[VolIdx]; if(StreamingVol && StreamingVol->GetBrushComponent()) { - Bounds += StreamingVol->GetBrushComponent()->BrushBodySetup->AggGeom.CalcAABB(StreamingVol->GetBrushComponent()->ComponentToWorld); + Bounds += StreamingVol->GetBrushComponent()->BrushBodySetup->AggGeom.CalcAABB(StreamingVol->GetBrushComponent()->GetComponentTransform()); } } @@ -991,6 +991,25 @@ void ULevelStreaming::PostEditUndo() #endif // WITH_EDITOR +#if WITH_EDITOR +const FName& ULevelStreaming::GetFolderPath() const +{ + return FolderPath; +} + +void ULevelStreaming::SetFolderPath(const FName& InFolderPath) +{ + if (FolderPath != InFolderPath) + { + Modify(); + + FolderPath = InFolderPath; + + // @TODO: Should this be broadcasted through the editor, similar to BroadcastLevelActorFolderChanged? + } +} +#endif // WITH_EDITOR + /*----------------------------------------------------------------------------- ULevelStreamingPersistent implementation. -----------------------------------------------------------------------------*/ @@ -1080,12 +1099,19 @@ ULevelStreamingKismet* ULevelStreamingKismet::LoadLevelInstance(UObject* WorldCo /*----------------------------------------------------------------------------- ULevelStreamingAlwaysLoaded implementation. -----------------------------------------------------------------------------*/ + ULevelStreamingAlwaysLoaded::ULevelStreamingAlwaysLoaded(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { bShouldBeVisible = true; } +void ULevelStreamingAlwaysLoaded::GetPrestreamPackages(TArray& OutPrestream) +{ + OutPrestream.Add(GetLoadedLevel()); // Nulls will be ignored later +} + + bool ULevelStreamingAlwaysLoaded::ShouldBeLoaded() const { return true; diff --git a/Engine/Source/Runtime/Engine/Private/LevelTick.cpp b/Engine/Source/Runtime/Engine/Private/LevelTick.cpp index 305ac0d65361..582849b0dff5 100644 --- a/Engine/Source/Runtime/Engine/Private/LevelTick.cpp +++ b/Engine/Source/Runtime/Engine/Private/LevelTick.cpp @@ -1155,48 +1155,53 @@ void EndTickDrawEvent(TDrawEvent* TickDrawEvent) } -void FTickableGameObject::TickObjects(UWorld* World, int32 InTickType, bool bIsPaused, float DeltaSeconds) +void FTickableGameObject::TickObjects(UWorld* World, const int32 InTickType, const bool bIsPaused, const float DeltaSeconds) { - check(!bIsTickingObjects); - bIsTickingObjects = true; - - bool bNeedsCleanup = false; - ELevelTick TickType = (ELevelTick)InTickType; - - for( int32 i=0; i < TickableObjects.Num(); ++i ) + if (TickableObjects.Num() > 0) { - if (FTickableGameObject* TickableObject = TickableObjects[i]) + check(!bIsTickingObjects); + bIsTickingObjects = true; + + bool bNeedsCleanup = false; + const ELevelTick TickType = (ELevelTick)InTickType; + + for (int32 i = 0; i < TickableObjects.Num(); ++i) { - const bool bTickIt = TickableObject->IsTickable() && (TickableObject->GetTickableGameObjectWorld() == World) && - ( - (TickType != LEVELTICK_TimeOnly && !bIsPaused) || - (bIsPaused && TickableObject->IsTickableWhenPaused()) || - (GIsEditor && (World == nullptr || !World->IsPlayInEditor()) && TickableObject->IsTickableInEditor()) - ); - - if (bTickIt) + if (FTickableGameObject* TickableObject = TickableObjects[i]) { - STAT(FScopeCycleCounter Context(TickableObject->GetStatId());) - TickableObject->Tick(DeltaSeconds); - - if (TickableObjects[i] == nullptr) + // If it is tickable and in this world + if (TickableObject->IsTickable() && (TickableObject->GetTickableGameObjectWorld() == World)) { - bNeedsCleanup = true; + const bool bIsGameWorld = InTickType == LEVELTICK_All || (World && World->IsGameWorld()); + // If we are in editor and it is editor tickable, always tick + // If this is a game world then tick if we are not doing a time only (paused) update and we are not paused or the object is tickable when paused + if ((GIsEditor && TickableObject->IsTickableInEditor()) || + (bIsGameWorld && ((!bIsPaused && TickType != LEVELTICK_TimeOnly) || (bIsPaused && TickableObject->IsTickableWhenPaused())))) + { + STAT(FScopeCycleCounter Context(TickableObject->GetStatId());) + TickableObject->Tick(DeltaSeconds); + + // In case it was removed during tick + if (TickableObjects[i] == nullptr) + { + bNeedsCleanup = true; + } + } } } + else + { + bNeedsCleanup = true; + } } - else + + if (bNeedsCleanup) { - bNeedsCleanup = true; + TickableObjects.RemoveAll([](FTickableGameObject* Object) { return Object == nullptr; }); } - } - if (bNeedsCleanup) - { - TickableObjects.RemoveAll([](FTickableGameObject* Object) { return Object == nullptr; }); + bIsTickingObjects = false; } - - bIsTickingObjects = false; } /** @@ -1205,6 +1210,8 @@ void FTickableGameObject::TickObjects(UWorld* World, int32 InTickType, bool bIsP */ void UWorld::Tick( ELevelTick TickType, float DeltaSeconds ) { + SCOPE_TIME_GUARD(TEXT("UWorld::Tick")); + if (GIntraFrameDebuggingGameThread) { return; @@ -1256,6 +1263,7 @@ void UWorld::Tick( ELevelTick TickType, float DeltaSeconds ) { SCOPE_CYCLE_COUNTER(STAT_NetWorldTickTime); + SCOPE_TIME_GUARD(TEXT("UWorld::Tick - NetTick")); // Update the net code and fetch all incoming packets. BroadcastTickDispatch(DeltaSeconds); @@ -1369,6 +1377,7 @@ void UWorld::Tick( ELevelTick TickType, float DeltaSeconds ) SCOPE_CYCLE_COUNTER(STAT_TickTime); { + SCOPE_TIME_GUARD_MS(TEXT("UWorld::Tick - TG_PrePhysics"), 10); SCOPE_CYCLE_COUNTER(STAT_TG_PrePhysics); RunTickGroup(TG_PrePhysics); } @@ -1376,20 +1385,23 @@ void UWorld::Tick( ELevelTick TickType, float DeltaSeconds ) EnsureCollisionTreeIsBuilt(); bInTick = true; { - SCOPE_CYCLE_COUNTER(STAT_TG_StartPhysics); + SCOPE_TIME_GUARD_MS(TEXT("UWorld::Tick - TG_StartPhysics"), 10); RunTickGroup(TG_StartPhysics); } { SCOPE_CYCLE_COUNTER(STAT_TG_DuringPhysics); + SCOPE_TIME_GUARD_MS(TEXT("UWorld::Tick - TG_DuringPhysics"), 10); RunTickGroup(TG_DuringPhysics, false); // No wait here, we should run until idle though. We don't care if all of the async ticks are done before we start running post-phys stuff } TickGroup = TG_EndPhysics; // set this here so the current tick group is correct during collision notifies, though I am not sure it matters. 'cause of the false up there^^^ { SCOPE_CYCLE_COUNTER(STAT_TG_EndPhysics); + SCOPE_TIME_GUARD_MS(TEXT("UWorld::Tick - TG_EndPhysics"), 10); RunTickGroup(TG_EndPhysics); } { SCOPE_CYCLE_COUNTER(STAT_TG_PostPhysics); + SCOPE_TIME_GUARD_MS(TEXT("UWorld::Tick - TG_PostPhysics"), 10); RunTickGroup(TG_PostPhysics); } @@ -1423,11 +1435,15 @@ void UWorld::Tick( ELevelTick TickType, float DeltaSeconds ) if (TickType != LEVELTICK_TimeOnly && !bIsPaused) { + SCOPE_TIME_GUARD_MS(TEXT("UWorld::Tick - TimerManager"), 5); STAT(FScopeCycleCounter Context(GetTimerManager().GetStatId());) GetTimerManager().Tick(DeltaSeconds); } - FTickableGameObject::TickObjects(this, TickType, bIsPaused, DeltaSeconds); + { + SCOPE_TIME_GUARD_MS(TEXT("UWorld::Tick - TickObjects"), 5); + FTickableGameObject::TickObjects(this, TickType, bIsPaused, DeltaSeconds); + } } // Update cameras and streaming volumes @@ -1468,10 +1484,12 @@ void UWorld::Tick( ELevelTick TickType, float DeltaSeconds ) SCOPE_CYCLE_COUNTER(STAT_TickTime); { SCOPE_CYCLE_COUNTER(STAT_TG_PostUpdateWork); + SCOPE_TIME_GUARD_MS(TEXT("UWorld::Tick - PostUpdateWork"), 5); RunTickGroup(TG_PostUpdateWork); } { SCOPE_CYCLE_COUNTER(STAT_TG_LastDemotable); + SCOPE_TIME_GUARD_MS(TEXT("UWorld::Tick - TG_LastDemotable"), 5); RunTickGroup(TG_LastDemotable); } @@ -1491,6 +1509,7 @@ void UWorld::Tick( ELevelTick TickType, float DeltaSeconds ) // All tick is done, execute async trace { SCOPE_CYCLE_COUNTER(STAT_FinishAsyncTraceTickTime); + SCOPE_TIME_GUARD_MS(TEXT("UWorld::Tick - FinishAsyncTrace"), 5); FinishAsyncTrace(); } } @@ -1521,6 +1540,7 @@ void UWorld::Tick( ELevelTick TickType, float DeltaSeconds ) // Tick the FX system. if (!bIsPaused && FXSystem != NULL) { + SCOPE_TIME_GUARD_MS(TEXT("UWorld::Tick - FX"), 5); FXSystem->Tick(DeltaSeconds); } diff --git a/Engine/Source/Runtime/Engine/Private/Light.cpp b/Engine/Source/Runtime/Engine/Private/Light.cpp index 77f15c877ff7..abd1051131b8 100644 --- a/Engine/Source/Runtime/Engine/Private/Light.cpp +++ b/Engine/Source/Runtime/Engine/Private/Light.cpp @@ -349,9 +349,3 @@ bool ALight::IsToggleable() const return !LightComponent->HasStaticLighting(); } -/** Returns LightComponent subobject **/ -ULightComponent* ALight::GetLightComponent() const { return LightComponent; } -#if WITH_EDITORONLY_DATA -/** Returns ArrowComponent subobject **/ -UArrowComponent* ADirectionalLight::GetArrowComponent() const { return ArrowComponent; } -#endif diff --git a/Engine/Source/Runtime/Engine/Private/LightMap.cpp b/Engine/Source/Runtime/Engine/Private/LightMap.cpp index 4b5e1ecd96ca..a8a51634b9cc 100644 --- a/Engine/Source/Runtime/Engine/Private/LightMap.cpp +++ b/Engine/Source/Runtime/Engine/Private/LightMap.cpp @@ -111,11 +111,11 @@ void FLightMap::FinishCleanup() ULightMapTexture2D::ULightMapTexture2D(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { + LODGroup = TEXTUREGROUP_Lightmap; } + void ULightMapTexture2D::Serialize(FArchive& Ar) { - LODGroup = TEXTUREGROUP_Lightmap; - Super::Serialize(Ar); uint32 Flags = LightmapFlags; @@ -380,7 +380,7 @@ struct FLightMapPendingTexture : public FTextureLayout ULightMapTexture2D* SkyOcclusionTexture; ULightMapTexture2D* AOMaterialMaskTexture; - TArray Allocations; + TArray> Allocations; UObject* Outer; TWeakObjectPtr OwningWorld; /** Bounding volume for all mappings within this texture. */ @@ -427,7 +427,7 @@ struct FLightMapPendingTexture : public FTextureLayout /** * Processes the textures and starts asynchronous compression tasks for all mip-levels. */ - void StartEncoding(ULevel* Unused); + void StartEncoding(ULevel* Unused, ITextureCompressorModule* UnusedCompressor); /** * Call this function after the IsFinishedEncoding function returns true @@ -568,7 +568,7 @@ void FLightMapPendingTexture::PostEncode() for (int32 AllocationIndex = 0; AllocationIndex < Allocations.Num(); AllocationIndex++) { - FLightMapAllocation* Allocation = Allocations[AllocationIndex]; + auto& Allocation = Allocations[AllocationIndex]; int32 PaddedSizeX = Allocation->TotalSizeX; int32 PaddedSizeY = Allocation->TotalSizeY; @@ -1142,7 +1142,7 @@ bool FLightMapPendingTexture::NeedsSkyOcclusionTexture() const for (int32 AllocationIndex = 0; AllocationIndex < Allocations.Num(); AllocationIndex++) { - FLightMapAllocation* Allocation = Allocations[AllocationIndex]; + auto& Allocation = Allocations[AllocationIndex]; if (Allocation->bHasSkyShadowing) { @@ -1169,7 +1169,7 @@ bool FLightMapPendingTexture::NeedsAOMaterialMaskTexture() const return false; } -void FLightMapPendingTexture::StartEncoding(ULevel* Unused) +void FLightMapPendingTexture::StartEncoding(ULevel* Unused, ITextureCompressorModule* UnusedCompressor) { if (!bUObjectsCreated) { @@ -1222,7 +1222,7 @@ void FLightMapPendingTexture::StartEncoding(ULevel* Unused) FIntRect TextureRect( MAX_int32, MAX_int32, MIN_int32, MIN_int32 ); for(int32 AllocationIndex = 0;AllocationIndex < Allocations.Num();AllocationIndex++) { - FLightMapAllocation* Allocation = Allocations[AllocationIndex]; + auto& Allocation = Allocations[AllocationIndex]; // Link the light-map to the texture. Allocation->LightMap->SkyOcclusionTexture = Texture; @@ -1310,7 +1310,7 @@ void FLightMapPendingTexture::StartEncoding(ULevel* Unused) FIntRect TextureRect( MAX_int32, MAX_int32, MIN_int32, MIN_int32 ); for(int32 AllocationIndex = 0;AllocationIndex < Allocations.Num();AllocationIndex++) { - FLightMapAllocation* Allocation = Allocations[AllocationIndex]; + auto& Allocation = Allocations[AllocationIndex]; // Link the light-map to the texture. Allocation->LightMap->AOMaterialMaskTexture = Texture; @@ -1400,7 +1400,7 @@ void FLightMapPendingTexture::StartEncoding(ULevel* Unused) for(int32 AllocationIndex = 0;AllocationIndex < Allocations.Num();AllocationIndex++) { - FLightMapAllocation* Allocation = Allocations[AllocationIndex]; + auto& Allocation = Allocations[AllocationIndex]; // Link the light-map to the texture. Allocation->LightMap->Textures[ CoefficientIndex / 2 ] = Texture; for( int k = 0; k < 2; k++ ) @@ -1970,7 +1970,7 @@ void FLightMap2D::EncodeTextures( UWorld* InWorld, bool bLightingSuccessful, boo // Give the texture ownership of the allocations for (auto& Allocation : PendingGroup.Allocations) { - Texture->Allocations.Add(Allocation.Release()); + Texture->Allocations.Add(MoveTemp(Allocation)); } } PendingLightMaps.Empty(); @@ -1985,7 +1985,7 @@ void FLightMap2D::EncodeTextures( UWorld* InWorld, bool bLightingSuccessful, boo // precreate the UObjects then give them to some threads to process // need to precreate Uobjects Texture->CreateUObjects(); - auto AsyncEncodeTask = new (AsyncEncodeTasks)FAsyncEncode(Texture,NULL,Counter); + auto AsyncEncodeTask = new (AsyncEncodeTasks)FAsyncEncode(Texture,nullptr,Counter,nullptr); GLargeThreadPool->AddQueuedWork(AsyncEncodeTask); } @@ -2005,7 +2005,7 @@ void FLightMap2D::EncodeTextures( UWorld* InWorld, bool bLightingSuccessful, boo GWarn->UpdateProgress(TextureIndex, PendingTextures.Num()); } FLightMapPendingTexture* PendingTexture = PendingTextures[TextureIndex]; - PendingTexture->StartEncoding(NULL); + PendingTexture->StartEncoding(nullptr,nullptr); } } diff --git a/Engine/Source/Runtime/Engine/Private/MapBuildData.cpp b/Engine/Source/Runtime/Engine/Private/MapBuildData.cpp index 394fcd45838d..3dc3ab2d45d2 100644 --- a/Engine/Source/Runtime/Engine/Private/MapBuildData.cpp +++ b/Engine/Source/Runtime/Engine/Private/MapBuildData.cpp @@ -43,7 +43,7 @@ ULevel* UWorld::GetActiveLightingScenario() const return NULL; } -void UWorld::PropagateLightingScenarioChange() +void UWorld::PropagateLightingScenarioChange(bool bLevelWasMadeVisible) { for (FActorIterator It(this); It; ++It) { @@ -68,8 +68,13 @@ void UWorld::PropagateLightingScenarioChange() } } - //@todo - store reflection capture data in UMapBuildDataRegistry so it can work with multiple lighting scenarios without forcing a recapture - UpdateAllReflectionCaptures(); + // Skipping the reflection capture update if made invisible, in most cases another lighting scenario level will be made visible shortly after, + // Or we're unloading all levels and then it doesn't matter if lighting is updated. + if (bLevelWasMadeVisible) + { + //@todo - store reflection capture data in UMapBuildDataRegistry so it can work with multiple lighting scenarios without forcing a recapture + UpdateAllReflectionCaptures(); + } } UMapBuildDataRegistry* CreateRegistryForLegacyMap(ULevel* Level) @@ -87,17 +92,12 @@ void ULevel::HandleLegacyMapBuildData() || GLevelsWithLegacyBuildData.GetAnnotationMap().Num() > 0 || GLightComponentsWithLegacyBuildData.GetAnnotationMap().Num() > 0) { - UMapBuildDataRegistry* Registry = NULL; - FLevelLegacyMapBuildData LegacyLevelData = GLevelsWithLegacyBuildData.GetAndRemoveAnnotation(this); + UMapBuildDataRegistry* Registry = NULL; if (LegacyLevelData.Id != FGuid()) { - if (!Registry) - { - Registry = CreateRegistryForLegacyMap(this); - } - + Registry = CreateRegistryForLegacyMap(this); Registry->AddLevelBuildData(LegacyLevelData.Id, LegacyLevelData.Data); } diff --git a/Engine/Source/Runtime/Engine/Private/Materials/HLSLMaterialTranslator.h b/Engine/Source/Runtime/Engine/Private/Materials/HLSLMaterialTranslator.h index 1e8cf4f15668..fee9f383b3a9 100644 --- a/Engine/Source/Runtime/Engine/Private/Materials/HLSLMaterialTranslator.h +++ b/Engine/Source/Runtime/Engine/Private/Materials/HLSLMaterialTranslator.h @@ -514,9 +514,9 @@ public: if (Domain == MD_Surface) { - if (Material->GetBlendMode() == BLEND_Modulate && Material->IsSeparateTranslucencyEnabled()) + if (Material->GetBlendMode() == BLEND_Modulate && Material->IsTranslucencyAfterDOFEnabled()) { - Errorf(TEXT("Separate translucency with BLEND_Modulate is not supported. Consider using BLEND_Translucent with black emissive")); + Errorf(TEXT("Translucency after DOF with BLEND_Modulate is not supported. Consider using BLEND_Translucent with black emissive")); } } @@ -3113,7 +3113,7 @@ protected: if(MipValueMode == TMVM_None) { - SampleCode += FString(TEXT("(%s,")) + SamplerStateCode + TEXT(",%s)"); + SampleCode += TEXT("(%s,") + SamplerStateCode + TEXT(",%s)"); } else if(MipValueMode == TMVM_MipLevel) { @@ -3126,11 +3126,11 @@ protected: return INDEX_NONE; } - SampleCode += TEXT("Level(%s,%sSampler,%s,%s)"); + SampleCode += TEXT("Level(%s,") + SamplerStateCode + TEXT(",%s,%s)"); } else if(MipValueMode == TMVM_MipBias) { - SampleCode += TEXT("Bias(%s,%sSampler,%s,%s)"); + SampleCode += TEXT("Bias(%s,") + SamplerStateCode + TEXT(",%s,%s)"); } else if(MipValueMode == TMVM_Derivative) { @@ -3143,7 +3143,7 @@ protected: return Errorf(TEXT("Missing DDY(UVs) parameter")); } - SampleCode += TEXT("Grad(%s,%sSampler,%s,%s,%s)"); + SampleCode += TEXT("Grad(%s,") + SamplerStateCode + TEXT(",%s,%s,%s)"); MipValue0Code = CoerceParameter(MipValue0Index, UVsType); MipValue1Code = CoerceParameter(MipValue1Index, UVsType); @@ -4468,6 +4468,11 @@ protected: CodeStr.ReplaceInline(TEXT(""), *GetParameterCode(A)); + if (ShaderFrequency != SF_Vertex && (DestCoordBasis == MCB_Tangent || SourceCoordBasis == MCB_Tangent)) + { + bUsesTransformVector = true; + } + return AddCodeChunk( MCT_Float3, *CodeStr @@ -4718,6 +4723,25 @@ protected: *GetParameterCode(Depth), FunctionValueIndex); } + virtual int32 Sobol(int32 Cell, int32 Index, int32 Seed) override + { + return AddCodeChunk(MCT_Float2, + TEXT("floor(%s) + float2(DirectSobol(PixelSobol(uint2(%s), uint(%s) & 7u), uint(%s) >> 3u).xy ^ uint2(%s * 0x10000) & 0xffff) / 0x10000"), + *GetParameterCode(Cell), + *GetParameterCode(Cell), + *GetParameterCode(Index), + *GetParameterCode(Index), + *GetParameterCode(Seed)); + } + + virtual int32 TemporalSobol(int32 Index, int32 Seed) override + { + return AddCodeChunk(MCT_Float2, + TEXT("float2(DirectSobol(PixelSobol(uint2(Parameters.SvPosition.xy), View.FrameNumber), uint(%s)).xy ^ uint2(%s * 0x10000) & 0xffff) / 0x10000"), + *GetParameterCode(Index), + *GetParameterCode(Seed)); + } + virtual int32 Noise(int32 Position, float Scale, int32 Quality, uint8 NoiseFunction, bool bTurbulence, int32 Levels, float OutputMin, float OutputMax, float LevelScale, int32 FilterWidth, bool bTiling, uint32 RepeatSize) override { // GradientTex3D uses 3D texturing, which is not available on ES2 diff --git a/Engine/Source/Runtime/Engine/Private/Materials/Material.cpp b/Engine/Source/Runtime/Engine/Private/Materials/Material.cpp index d5d250b9f04c..f6a99fd02fa5 100644 --- a/Engine/Source/Runtime/Engine/Private/Materials/Material.cpp +++ b/Engine/Source/Runtime/Engine/Private/Materials/Material.cpp @@ -136,22 +136,26 @@ int32 FMaterialResource::CompilePropertyAndSetMaterialProperty(EMaterialProperty }; EMaterialValueType AttributeType = FMaterialAttributeDefinitionMap::GetValueType(Property); - FMaterialUniformExpression* Expression = Compiler->GetParameterUniformExpression(Ret); - if (Expression && Expression->IsConstant()) + if (Ret != INDEX_NONE) { - // Where possible we want to preserve constant expressions allowing default value checks - EMaterialValueType ResultType = Compiler->GetParameterType(Ret); - EMaterialValueType ExactAttributeType = (AttributeType == MCT_Float) ? MCT_Float1 : AttributeType; - EMaterialValueType ExactResultType = (ResultType == MCT_Float) ? MCT_Float1 : ResultType; + FMaterialUniformExpression* Expression = Compiler->GetParameterUniformExpression(Ret); - if (ExactAttributeType == ExactResultType) + if (Expression && Expression->IsConstant()) { - return Ret; - } - else if (ResultType == MCT_Float || (ExactAttributeType == MCT_Float1 && ResultType & MCT_Float)) - { - return Compiler->ComponentMask(Ret, true, ExactAttributeType >= MCT_Float2, ExactAttributeType >= MCT_Float3, ExactAttributeType >= MCT_Float4); + // Where possible we want to preserve constant expressions allowing default value checks + EMaterialValueType ResultType = Compiler->GetParameterType(Ret); + EMaterialValueType ExactAttributeType = (AttributeType == MCT_Float) ? MCT_Float1 : AttributeType; + EMaterialValueType ExactResultType = (ResultType == MCT_Float) ? MCT_Float1 : ResultType; + + if (ExactAttributeType == ExactResultType) + { + return Ret; + } + else if (ResultType == MCT_Float || (ExactAttributeType == MCT_Float1 && ResultType & MCT_Float)) + { + return Compiler->ComponentMask(Ret, true, ExactAttributeType >= MCT_Float2, ExactAttributeType >= MCT_Float3, ExactAttributeType >= MCT_Float4); + } } } @@ -474,7 +478,7 @@ void UMaterialInterface::PostLoadDefaultMaterials() UMaterial* Material = GDefaultMaterials[Domain]; #if USE_EVENT_DRIVEN_ASYNC_LOAD_AT_BOOT_TIME check(Material || (GIsInitialLoad && GEventDrivenLoaderEnabled)); - check((GIsInitialLoad && GEventDrivenLoaderEnabled) || !Material->HasAnyFlags(RF_NeedLoad)); + check((GIsInitialLoad && GEventDrivenLoaderEnabled) || !Material->HasAnyFlags(RF_NeedLoad)); //-V595 if (Material && !Material->HasAnyFlags(RF_NeedLoad)) #else check(Material); @@ -1239,21 +1243,21 @@ FString UMaterial::GetUsageName(EMaterialUsage Usage) const } -bool UMaterial::CheckMaterialUsage(EMaterialUsage Usage, const bool bSkipPrim) +bool UMaterial::CheckMaterialUsage(EMaterialUsage Usage) { check(IsInGameThread()); bool bNeedsRecompile = false; - return SetMaterialUsage(bNeedsRecompile, Usage, bSkipPrim); + return SetMaterialUsage(bNeedsRecompile, Usage); } -bool UMaterial::CheckMaterialUsage_Concurrent(EMaterialUsage Usage, const bool bSkipPrim) const +bool UMaterial::CheckMaterialUsage_Concurrent(EMaterialUsage Usage) const { bool bUsageSetSuccessfully = false; if (NeedsSetMaterialUsage_Concurrent(bUsageSetSuccessfully, Usage)) { if (IsInGameThread()) { - bUsageSetSuccessfully = const_cast(this)->CheckMaterialUsage(Usage, bSkipPrim); + bUsageSetSuccessfully = const_cast(this)->CheckMaterialUsage(Usage); } else { @@ -1261,23 +1265,21 @@ bool UMaterial::CheckMaterialUsage_Concurrent(EMaterialUsage Usage, const bool b { UMaterial* Material; EMaterialUsage Usage; - bool bSkipPrim; - FCallSMU(UMaterial* InMaterial, EMaterialUsage InUsage, bool bInSkipPrim) + FCallSMU(UMaterial* InMaterial, EMaterialUsage InUsage) : Material(InMaterial) , Usage(InUsage) - , bSkipPrim(bInSkipPrim) { } void Task() { - Material->CheckMaterialUsage(Usage, bSkipPrim); + Material->CheckMaterialUsage(Usage); } }; UE_LOG(LogMaterial, Log, TEXT("Had to pass SMU back to game thread. Please ensure correct material usage flags.")); - TSharedRef CallSMU = MakeShareable(new FCallSMU(const_cast(this), Usage, bSkipPrim)); + TSharedRef CallSMU = MakeShareable(new FCallSMU(const_cast(this), Usage)); bUsageSetSuccessfully = false; DECLARE_CYCLE_STAT(TEXT("FSimpleDelegateGraphTask.CheckMaterialUsage"), @@ -1338,7 +1340,7 @@ bool UMaterial::NeedsSetMaterialUsage_Concurrent(bool &bOutHasUsage, EMaterialUs return false; } -bool UMaterial::SetMaterialUsage(bool &bNeedsRecompile, EMaterialUsage Usage, const bool bSkipPrim) +bool UMaterial::SetMaterialUsage(bool &bNeedsRecompile, EMaterialUsage Usage) { bNeedsRecompile = false; @@ -2422,6 +2424,26 @@ void UMaterial::CacheExpressionTextureReferences() } } +bool UMaterial::AttemptInsertNewGroupName(const FString & InNewName) +{ +#if WITH_EDITOR + FParameterGroupData* ParameterGroupDataElement = ParameterGroupData.FindByPredicate([&InNewName](const FParameterGroupData& DataElement) + { + return InNewName == DataElement.GroupName; + }); + + if (ParameterGroupDataElement == nullptr) + { + FParameterGroupData NewGroupData; + NewGroupData.GroupName = InNewName; + NewGroupData.GroupSortPriority = 0; + ParameterGroupData.Add(NewGroupData); + return true; + } +#endif + return false; +} + void UMaterial::RebuildExpressionTextureReferences() { // Note: builds without editor only data will have an incorrect shader map id due to skipping this @@ -3540,6 +3562,14 @@ void UMaterial::BeginDestroy() { Super::BeginDestroy(); + for (int32 InstanceIndex = 0; InstanceIndex < 3; ++InstanceIndex) + { + if (DefaultMaterialInstances[InstanceIndex]) + { + BeginReleaseResource(DefaultMaterialInstances[InstanceIndex]); + } + } + ReleaseFence.BeginFence(); } @@ -3677,20 +3707,6 @@ void UMaterial::UpdateMaterialShaders(TArray& ShaderTypesToFlush, { FMaterialUpdateContext UpdateContext(FMaterialUpdateContext::EOptions::Default, ShaderPlatform); - // Go through all material shader maps and flush the appropriate shaders - FMaterialShaderMap::FlushShaderTypes(ShaderTypesToFlush, ShaderPipelineTypesToFlush, VFTypesToFlush); - - // There should be no references to the given material shader types at this point - // If there still are shaders of the given types, they may be reused when we call CacheResourceShaders instead of compiling new shaders - for (int32 ShaderTypeIndex = 0; ShaderTypeIndex < ShaderTypesToFlush.Num(); ShaderTypeIndex++) - { - FShaderType* CurrentType = ShaderTypesToFlush[ShaderTypeIndex]; - if (CurrentType->GetMaterialShaderType() || CurrentType->GetMeshMaterialShaderType()) - { - checkf(CurrentType->GetNumShaders() == 0, TEXT("Type %s, Shaders %u"), CurrentType->GetName(), CurrentType->GetNumShaders()); - } - } - int32 NumMaterials = 0; for( TObjectIterator It; It; ++It ) @@ -4033,7 +4049,45 @@ bool UMaterial::GetExpressionsInPropertyChain(EMaterialProperty InProperty, return true; } -bool UMaterial::GetTexturesInPropertyChain(EMaterialProperty InProperty, TArray& OutTextures, +bool UMaterial::GetParameterSortPriority(FName ParameterName, int32& OutSortPriority) const +{ +#if WITH_EDITOR + for (UMaterialExpression* Expression : Expressions) + { + UMaterialExpressionParameter* Parameter = Cast(Expression); + if (Parameter && Expression->GetParameterName() == ParameterName) + { + OutSortPriority = Parameter->SortPriority; + return true; + } + UMaterialExpressionTextureSampleParameter* TextureParameter = Cast(Expression); + if (TextureParameter && Expression->GetParameterName() == ParameterName) + { + OutSortPriority = TextureParameter->SortPriority; + return true; + } + } +#endif + return false; +} + +bool UMaterial::GetGroupSortPriority(const FString& InGroupName, int32& OutSortPriority) const +{ +#if WITH_EDITOR + const FParameterGroupData* ParameterGroupDataElement = ParameterGroupData.FindByPredicate([&InGroupName](const FParameterGroupData& DataElement) + { + return InGroupName == DataElement.GroupName; + }); + if (ParameterGroupDataElement != nullptr) + { + OutSortPriority = ParameterGroupDataElement->GroupSortPriority; + return true; + } +#endif + return false; +} + +bool UMaterial::GetTexturesInPropertyChain(EMaterialProperty InProperty, TArray& OutTextures, TArray* OutTextureParamNames, class FStaticParameterSet* InStaticParameterSet) { TArray ChainExpressions; diff --git a/Engine/Source/Runtime/Engine/Private/Materials/MaterialExpressions.cpp b/Engine/Source/Runtime/Engine/Private/Materials/MaterialExpressions.cpp index 960f4b6e6a43..ef11bc7e57a6 100644 --- a/Engine/Source/Runtime/Engine/Private/Materials/MaterialExpressions.cpp +++ b/Engine/Source/Runtime/Engine/Private/Materials/MaterialExpressions.cpp @@ -149,6 +149,7 @@ #include "Materials/MaterialExpressionSceneTexture.h" #include "Materials/MaterialExpressionScreenPosition.h" #include "Materials/MaterialExpressionSine.h" +#include "Materials/MaterialExpressionSobol.h" #include "Materials/MaterialExpressionSpeedTree.h" #include "Materials/MaterialExpressionSphereMask.h" #include "Materials/MaterialExpressionSphericalParticleOpacity.h" @@ -158,6 +159,7 @@ #include "Materials/MaterialExpressionSubtract.h" #include "Materials/MaterialExpressionTangent.h" #include "Materials/MaterialExpressionTangentOutput.h" +#include "Materials/MaterialExpressionTemporalSobol.h" #include "Materials/MaterialExpressionTextureBase.h" #include "Materials/MaterialExpressionTextureObject.h" #include "Materials/MaterialExpressionTextureProperty.h" @@ -1686,6 +1688,7 @@ UMaterialExpressionTextureSampleParameter::UMaterialExpressionTextureSampleParam #if WITH_EDITORONLY_DATA MenuCategories.Empty(); MenuCategories.Add( ConstructorStatics.NAME_Obsolete); + SortPriority = 0; #endif } @@ -1697,17 +1700,14 @@ int32 UMaterialExpressionTextureSampleParameter::Compile(class FMaterialCompiler return CompilerError(Compiler, GetRequirements()); } - if (Texture) + if (!TextureIsValid(Texture)) { - if (!TextureIsValid(Texture)) - { - return CompilerError(Compiler, GetRequirements()); - } + return CompilerError(Compiler, GetRequirements()); + } - if (!VerifySamplerType(Compiler, (Desc.Len() > 0 ? *Desc : TEXT("TextureSampleParameter")), Texture, SamplerType)) - { - return INDEX_NONE; - } + if (!VerifySamplerType(Compiler, (Desc.Len() > 0 ? *Desc : TEXT("TextureSampleParameter")), Texture, SamplerType)) + { + return INDEX_NONE; } if (!ParameterName.IsValid() || ParameterName.IsNone()) @@ -5182,6 +5182,7 @@ UMaterialExpressionParameter::UMaterialExpressionParameter(const FObjectInitiali #if WITH_EDITORONLY_DATA MenuCategories.Add(ConstructorStatics.NAME_Parameters); + SortPriority = 0; #endif bCollapsed = false; @@ -6917,6 +6918,11 @@ void UMaterialExpressionPower::GetCaption(TArray& OutCaptions) const OutCaptions.Add(ret); } + +void UMaterialExpressionPower::GetExpressionToolTip(TArray& OutToolTip) +{ + ConvertToMultilineToolTip(TEXT("Returns the Base value raised to the power of Exponent. Base value must be positive, values less than 0 will be clamped."), 40, OutToolTip); +} #endif // WITH_EDITOR UMaterialExpressionLogarithm2::UMaterialExpressionLogarithm2(const FObjectInitializer& ObjectInitializer) @@ -7410,7 +7416,10 @@ int32 UMaterialExpressionFresnel::Compile(class FMaterialCompiler* Compiler, int int32 MaxArg = Compiler->Max(Compiler->Constant(0.f),DotArg); int32 MinusArg = Compiler->Sub(Compiler->Constant(1.f),MaxArg); int32 ExponentArg = ExponentIn.GetTracedInput().Expression ? ExponentIn.Compile(Compiler) : Compiler->Constant(Exponent); - int32 PowArg = Compiler->Power(MinusArg,ExponentArg); + // Compiler->Power got changed to call PositiveClampedPow instead of ClampedPow + // Manually implement ClampedPow to maintain backwards compatibility in the case where the input normal is not normalized (length > 1) + int32 AbsBaseArg = Compiler->Abs(MinusArg); + int32 PowArg = Compiler->Power(AbsBaseArg,ExponentArg); int32 BaseReflectFractionArg = BaseReflectFractionIn.GetTracedInput().Expression ? BaseReflectFractionIn.Compile(Compiler) : Compiler->Constant(BaseReflectFraction); int32 ScaleArg = Compiler->Mul(PowArg, Compiler->Sub(Compiler->Constant(1.f), BaseReflectFractionArg)); @@ -7488,7 +7497,7 @@ int32 UMaterialExpressionFontSample::Compile(class FMaterialCompiler* Compiler, if( !Texture ) { UE_LOG(LogMaterial, Log, TEXT("Invalid font texture. Using default texture")); - Texture = Texture = GEngine->DefaultTexture; + Texture = GEngine->DefaultTexture; } check(Texture); @@ -7595,7 +7604,7 @@ int32 UMaterialExpressionFontSampleParameter::Compile(class FMaterialCompiler* C if( !Texture ) { UE_LOG(LogMaterial, Log, TEXT("Invalid font texture. Using default texture")); - Texture = Texture = GEngine->DefaultTexture; + Texture = GEngine->DefaultTexture; } check(Texture); @@ -10586,6 +10595,91 @@ void UMaterialExpressionSphereMask::GetCaption(TArray& OutCaptions) con } #endif // WITH_EDITOR +/////////////////////////////////////////////////////////////////////////////// +// UMaterialExpressionSobol +/////////////////////////////////////////////////////////////////////////////// +UMaterialExpressionSobol::UMaterialExpressionSobol(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + // Structure to hold one-time initialization + struct FConstructorStatics + { + FText NAME_Utility; + FConstructorStatics() + : NAME_Utility(LOCTEXT("Utility", "Utility")) + { + } + }; + static FConstructorStatics ConstructorStatics; + + ConstIndex = 0; + ConstSeed = FVector2D(0.f, 0.f); +} + +#if WITH_EDITOR +int32 UMaterialExpressionSobol::Compile(class FMaterialCompiler* Compiler, int32 OutputIndex) +{ + int32 CellInput = Cell.GetTracedInput().Expression ? Cell.Compile(Compiler) : Compiler->Constant2(0.f, 0.f); + int32 IndexInput = Index.GetTracedInput().Expression ? Index.Compile(Compiler) : Compiler->Constant(ConstIndex); + int32 SeedInput = Seed.GetTracedInput().Expression ? Seed.Compile(Compiler) : Compiler->Constant2(ConstSeed.X, ConstSeed.Y); + return Compiler->Sobol(CellInput, IndexInput, SeedInput); +} + +void UMaterialExpressionSobol::GetCaption(TArray& OutCaptions) const +{ + FString Caption = TEXT("Sobol"); + + if (!Index.GetTracedInput().Expression) + { + Caption += FString::Printf(TEXT(" (%d)"), ConstIndex);; + } + + OutCaptions.Add(Caption); +} +#endif // WITH_EDITOR + +/////////////////////////////////////////////////////////////////////////////// +// UMaterialExpressionTemporalSobol +/////////////////////////////////////////////////////////////////////////////// +UMaterialExpressionTemporalSobol::UMaterialExpressionTemporalSobol(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + // Structure to hold one-time initialization + struct FConstructorStatics + { + FText NAME_Utility; + FConstructorStatics() + : NAME_Utility(LOCTEXT("Utility", "Utility")) + { + } + }; + static FConstructorStatics ConstructorStatics; + + ConstIndex = 0; + ConstSeed = FVector2D(0.f, 0.f); +} + +#if WITH_EDITOR +int32 UMaterialExpressionTemporalSobol::Compile(class FMaterialCompiler* Compiler, int32 OutputIndex) +{ + int32 IndexInput = Index.GetTracedInput().Expression ? Index.Compile(Compiler) : Compiler->Constant(ConstIndex); + int32 SeedInput = Seed.GetTracedInput().Expression ? Seed.Compile(Compiler) : Compiler->Constant2(ConstSeed.X, ConstSeed.Y); + return Compiler->TemporalSobol(IndexInput, SeedInput); +} + +void UMaterialExpressionTemporalSobol::GetCaption(TArray& OutCaptions) const +{ + FString Caption = TEXT("Temporal Sobol"); + + if (!Index.GetTracedInput().Expression) + { + Caption += FString::Printf(TEXT(" (%d)"), ConstIndex);; + } + + OutCaptions.Add(Caption); +} +#endif // WITH_EDITOR + /////////////////////////////////////////////////////////////////////////////// // UMaterialExpressionNoise /////////////////////////////////////////////////////////////////////////////// @@ -10680,6 +10774,9 @@ int32 UMaterialExpressionNoise::Compile(class FMaterialCompiler* Compiler, int32 void UMaterialExpressionNoise::GetCaption(TArray& OutCaptions) const { + const UEnum* NFEnum = FindObject(nullptr, TEXT("Engine.ENoiseFunction")); + check(NFEnum); + OutCaptions.Add(NFEnum->GetDisplayNameTextByValue(NoiseFunction).ToString()); OutCaptions.Add(TEXT("Noise")); } #endif // WITH_EDITOR @@ -10753,6 +10850,9 @@ int32 UMaterialExpressionVectorNoise::Compile(class FMaterialCompiler* Compiler, void UMaterialExpressionVectorNoise::GetCaption(TArray& OutCaptions) const { + const UEnum* VNFEnum = FindObject(nullptr, TEXT("Engine.EVectorNoiseFunction")); + check(VNFEnum); + OutCaptions.Add(VNFEnum->GetDisplayNameTextByValue(NoiseFunction).ToString()); OutCaptions.Add(TEXT("Vector Noise")); } #endif // WITH_EDITOR diff --git a/Engine/Source/Runtime/Engine/Private/Materials/MaterialInstance.cpp b/Engine/Source/Runtime/Engine/Private/Materials/MaterialInstance.cpp index b64725014dca..63b13f0b50f5 100644 --- a/Engine/Source/Runtime/Engine/Private/Materials/MaterialInstance.cpp +++ b/Engine/Source/Runtime/Engine/Private/Materials/MaterialInstance.cpp @@ -1061,14 +1061,14 @@ float UMaterialInstance::GetScalarParameterDefault(FName ParameterName, ERHIFeat return 0.f; } -bool UMaterialInstance::CheckMaterialUsage(const EMaterialUsage Usage, const bool bSkipPrim) +bool UMaterialInstance::CheckMaterialUsage(const EMaterialUsage Usage) { check(IsInGameThread()); UMaterial* Material = GetMaterial(); if(Material) { bool bNeedsRecompile = false; - bool bUsageSetSuccessfully = Material->SetMaterialUsage(bNeedsRecompile, Usage, bSkipPrim); + bool bUsageSetSuccessfully = Material->SetMaterialUsage(bNeedsRecompile, Usage); if (bNeedsRecompile) { CacheResourceShadersForRendering(); @@ -1082,7 +1082,7 @@ bool UMaterialInstance::CheckMaterialUsage(const EMaterialUsage Usage, const boo } } -bool UMaterialInstance::CheckMaterialUsage_Concurrent(const EMaterialUsage Usage, const bool bSkipPrim) const +bool UMaterialInstance::CheckMaterialUsage_Concurrent(const EMaterialUsage Usage) const { TMicRecursionGuard RecursionGuard; UMaterial const* Material = GetMaterial_Concurrent(RecursionGuard); @@ -1093,7 +1093,7 @@ bool UMaterialInstance::CheckMaterialUsage_Concurrent(const EMaterialUsage Usage { if (IsInGameThread()) { - bUsageSetSuccessfully = const_cast(this)->CheckMaterialUsage(Usage, bSkipPrim); + bUsageSetSuccessfully = const_cast(this)->CheckMaterialUsage(Usage); } else { @@ -1101,23 +1101,21 @@ bool UMaterialInstance::CheckMaterialUsage_Concurrent(const EMaterialUsage Usage { UMaterialInstance* Material; EMaterialUsage Usage; - bool bSkipPrim; - FCallSMU(UMaterialInstance* InMaterial, EMaterialUsage InUsage, bool bInSkipPrim) + FCallSMU(UMaterialInstance* InMaterial, EMaterialUsage InUsage) : Material(InMaterial) , Usage(InUsage) - , bSkipPrim(bInSkipPrim) { } void Task() { - Material->CheckMaterialUsage(Usage, bSkipPrim); + Material->CheckMaterialUsage(Usage); } }; UE_LOG(LogMaterial, Log, TEXT("Had to pass SMU back to game thread. Please ensure correct material usage flags.")); - TSharedRef CallSMU = MakeShareable(new FCallSMU(const_cast(this), Usage, bSkipPrim)); + TSharedRef CallSMU = MakeShareable(new FCallSMU(const_cast(this), Usage)); bUsageSetSuccessfully = false; DECLARE_CYCLE_STAT(TEXT("FSimpleDelegateGraphTask.CheckMaterialUsage"), @@ -2116,6 +2114,17 @@ void UMaterialInstance::BeginDestroy() { Super::BeginDestroy(); + if (!HasAnyFlags(RF_ClassDefaultObject)) + { + BeginReleaseResource(Resources[0]); + + if(GIsEditor) + { + BeginReleaseResource(Resources[1]); + BeginReleaseResource(Resources[2]); + } + } + ReleaseFence.BeginFence(); } diff --git a/Engine/Source/Runtime/Engine/Private/Materials/MaterialInterface.cpp b/Engine/Source/Runtime/Engine/Private/Materials/MaterialInterface.cpp index 96640adfd431..aa4c401b9204 100644 --- a/Engine/Source/Runtime/Engine/Private/Materials/MaterialInterface.cpp +++ b/Engine/Source/Runtime/Engine/Private/Materials/MaterialInterface.cpp @@ -14,6 +14,7 @@ #include "Engine/Texture2D.h" #include "Engine/SubsurfaceProfile.h" #include "Engine/TextureStreamingTypes.h" +#include "Algo/BinarySearch.h" #include "Interfaces/ITargetPlatform.h" #include "Components.h" @@ -32,6 +33,8 @@ void FMaterialRelevance::SetPrimitiveViewRelevance(FPrimitiveViewRelevance& OutV OutViewRelevance.bSeparateTranslucencyRelevance = bSeparateTranslucency; OutViewRelevance.bMobileSeparateTranslucencyRelevance = bMobileSeparateTranslucency; OutViewRelevance.bNormalTranslucencyRelevance = bNormalTranslucency; + OutViewRelevance.bUsesSceneColorCopy = bUsesSceneColorCopy; + OutViewRelevance.bDisableOffscreenRendering = bDisableOffscreenRendering; OutViewRelevance.ShadingModelMaskRelevance = ShadingModelMask; OutViewRelevance.bUsesGlobalDistanceField = bUsesGlobalDistanceField; OutViewRelevance.bUsesWorldPositionOffset = bUsesWorldPositionOffset; @@ -88,7 +91,8 @@ FMaterialRelevance UMaterialInterface::GetRelevance_Internal(const UMaterial* Ma if(Material) { const FMaterialResource* MaterialResource = Material->GetMaterialResource(InFeatureLevel); - const bool bIsTranslucent = IsTranslucentBlendMode((EBlendMode)GetBlendMode()); + const EBlendMode BlendMode = (EBlendMode)GetBlendMode(); + const bool bIsTranslucent = IsTranslucentBlendMode(BlendMode); EMaterialShadingModel ShadingModel = GetShadingModel(); EMaterialDomain Domain = (EMaterialDomain)MaterialResource->GetMaterialDomain(); @@ -112,7 +116,9 @@ FMaterialRelevance UMaterialInterface::GetRelevance_Internal(const UMaterial* Ma MaterialRelevance.bSeparateTranslucency = bIsTranslucent && Material->bEnableSeparateTranslucency; MaterialRelevance.bMobileSeparateTranslucency = bIsTranslucent && Material->bEnableMobileSeparateTranslucency; MaterialRelevance.bNormalTranslucency = bIsTranslucent && !Material->bEnableSeparateTranslucency; - MaterialRelevance.bDisableDepthTest = bIsTranslucent && Material->bDisableDepthTest; + MaterialRelevance.bDisableDepthTest = bIsTranslucent && Material->bDisableDepthTest; + MaterialRelevance.bUsesSceneColorCopy = bIsTranslucent && MaterialResource->RequiresSceneColorCopy_GameThread(); + MaterialRelevance.bDisableOffscreenRendering = BlendMode == BLEND_Modulate; // Blend Modulate must be rendered directly in the scene color. MaterialRelevance.bOutputsVelocityInBasePass = Material->bOutputVelocityOnBasePass; MaterialRelevance.bUsesGlobalDistanceField = MaterialResource->UsesGlobalDistanceField_GameThread(); MaterialRelevance.bUsesWorldPositionOffset = MaterialResource->UsesWorldPositionOffset_GameThread(); @@ -429,35 +435,6 @@ void UMaterialInterface::UpdateMaterialRenderProxy(FMaterialRenderProxy& Proxy) } } -namespace Algo -{ - template - int32 BinarySearch(const TArray& Container, PredType Pred) - { - int32 Min = 0; // Min is included - int32 Max = Container.Num(); // Max is excluded - - while (Min != Max) - { - const int32 Curr = (Min + Max) / 2; - const int32 Comp = Pred(Container[Curr]); - if (Comp < 0) // Pred < Ele - { - Max = Curr; - } - else if (Comp > 0) // Pred > Ele - { - Min = Curr + 1; - } - else // Pred == Ele - { - return Curr; - } - } - return INDEX_NONE; - } -} - bool FMaterialTextureInfo::IsValid(bool bCheckTextureIndex) const { #if WITH_EDITORONLY_DATA @@ -507,13 +484,6 @@ extern TAutoConsoleVariable CVarStreamingUseMaterialData; bool UMaterialInterface::FindTextureStreamingDataIndexRange(FName TextureName, int32& LowerIndex, int32& HigherIndex) const { - struct FNameSearch - { - FName Name; - FNameSearch(FName InName) : Name(InName) {} - FORCEINLINE int32 operator()(const FMaterialTextureInfo& Rhs) const { return Name.Compare(Rhs.TextureName); } - }; - #if WITH_EDITORONLY_DATA // Because of redirectors (when textures are renammed), the texture names might be invalid and we need to udpate the data at every load. // Normally we would do that in the post load, but since the process needs to resolve the StringAssetReference, this is forbidden at that place. @@ -526,17 +496,13 @@ bool UMaterialInterface::FindTextureStreamingDataIndexRange(FName TextureName, i return false; } - const int32 MatchingIndex = Algo::BinarySearch(TextureStreamingData, FNameSearch(TextureName)); + const int32 MatchingIndex = Algo::BinarySearchBy(TextureStreamingData, TextureName, &FMaterialTextureInfo::TextureName); if (MatchingIndex != INDEX_NONE) { // Find the range of entries for this texture. // This is possible because the same texture could be bound to several register and also be used with different sampling UV. LowerIndex = MatchingIndex; HigherIndex = MatchingIndex; - while (LowerIndex > 0 && TextureStreamingData[LowerIndex - 1].TextureName == TextureName) - { - --LowerIndex; - } while (HigherIndex + 1 < TextureStreamingData.Num() && TextureStreamingData[HigherIndex + 1].TextureName == TextureName) { ++HigherIndex; diff --git a/Engine/Source/Runtime/Engine/Private/Materials/MaterialShader.cpp b/Engine/Source/Runtime/Engine/Private/Materials/MaterialShader.cpp index 05b34c0bfb95..2319b7c7d71b 100644 --- a/Engine/Source/Runtime/Engine/Private/Materials/MaterialShader.cpp +++ b/Engine/Source/Runtime/Engine/Private/Materials/MaterialShader.cpp @@ -852,11 +852,11 @@ void FMaterialShaderMap::FixupShaderTypes(EShaderPlatform Platform, const TMap& InOutShaderMap) +void FMaterialShaderMap::LoadFromDerivedDataCache(const FMaterial* Material, const FMaterialShaderMapId& ShaderMapId, EShaderPlatform InPlatform, TRefCountPtr& InOutShaderMap) { if (InOutShaderMap != NULL) { - check(InOutShaderMap->Platform == Platform); + check(InOutShaderMap->GetShaderPlatform() == InPlatform); // If the shader map was non-NULL then it was found in memory but is incomplete, attempt to load the missing entries from memory InOutShaderMap->LoadMissingShadersFromMemory(Material); } @@ -869,12 +869,12 @@ void FMaterialShaderMap::LoadFromDerivedDataCache(const FMaterial* Material, con COOK_STAT(auto Timer = MaterialShaderCookStats::UsageStats.TimeSyncWork()); TArray CachedData; - const FString DataKey = GetMaterialShaderMapKeyString(ShaderMapId, Platform); + const FString DataKey = GetMaterialShaderMapKeyString(ShaderMapId, InPlatform); if (GetDerivedDataCacheRef().GetSynchronous(*DataKey, CachedData)) { COOK_STAT(Timer.AddHit(CachedData.Num())); - InOutShaderMap = new FMaterialShaderMap(); + InOutShaderMap = new FMaterialShaderMap(InPlatform); FMemoryReader Ar(CachedData, true); // Deserialize from the cached data @@ -884,7 +884,7 @@ void FMaterialShaderMap::LoadFromDerivedDataCache(const FMaterial* Material, con checkSlow(InOutShaderMap->GetShaderMapId() == ShaderMapId); // Register in the global map - InOutShaderMap->Register(Platform); + InOutShaderMap->Register(InPlatform); } else { @@ -904,7 +904,7 @@ void FMaterialShaderMap::SaveToDerivedDataCache() FMemoryWriter Ar(SaveData, true); Serialize(Ar); - GetDerivedDataCacheRef().Put(*GetMaterialShaderMapKeyString(ShaderMapId, Platform), SaveData); + GetDerivedDataCacheRef().Put(*GetMaterialShaderMapKeyString(ShaderMapId, GetShaderPlatform()), SaveData); COOK_STAT(Timer.AddMiss(SaveData.Num())); } @@ -1100,7 +1100,7 @@ void FMaterialShaderMap::LoadForRemoteRecompile(FArchive& Ar, EShaderPlatform Sh if (bIsValid) { - FMaterialShaderMap* ShaderMap = new FMaterialShaderMap; + FMaterialShaderMap* ShaderMap = new FMaterialShaderMap(ShaderPlatform); // serialize the id and the material shader map ShaderMap->Serialize(Ar, false); @@ -1285,7 +1285,7 @@ void FMaterialShaderMap::Compile( { // Create a new mesh material shader map. MeshShaderMapIndex = MeshShaderMaps.Num(); - MeshShaderMap = new(MeshShaderMaps) FMeshMaterialShaderMap(VertexFactoryType); + MeshShaderMap = new(MeshShaderMaps) FMeshMaterialShaderMap(InPlatform, VertexFactoryType); } // Enqueue compilation all mesh material shaders for this material and vertex factory type combo. @@ -1385,10 +1385,7 @@ void FMaterialShaderMap::Compile( } } - if (!CorrespondingMaterials) - { - UE_LOG(LogShaders, Warning, TEXT(" %u Shaders among %u VertexFactories"), NumShaders, NumVertexFactories); - } + UE_LOG(LogShaders, Warning, TEXT(" %u Shaders among %u VertexFactories"), NumShaders, NumVertexFactories); // Register this shader map in the global map with the material's ID. Register(InPlatform); @@ -1471,6 +1468,7 @@ FShader* FMaterialShaderMap::ProcessCompilationResultsForSingleJob(FShaderCompil bool FMaterialShaderMap::ProcessCompilationResults(const TArray& InCompilationResults, int32& InOutJobIndex, float& TimeBudget, TMap >& SharedPipelines) { check(InOutJobIndex < InCompilationResults.Num()); + check(!bCompilationFinalized); double StartTime = FPlatformTime::Seconds(); @@ -1656,7 +1654,7 @@ bool FMaterialShaderMap::TryToAddToExistingCompilationTask(FMaterial* Material) bool FMaterialShaderMap::IsMaterialShaderComplete(const FMaterial* Material, const FMaterialShaderType* ShaderType, const FShaderPipelineType* Pipeline, bool bSilent) { // If we should cache this material, it's incomplete if the pipeline is missing or the shader itself is missing - if (ShouldCacheMaterialShader(ShaderType, Platform, Material) && + if (ShouldCacheMaterialShader(ShaderType, GetShaderPlatform(), Material) && ((Pipeline && !HasShaderPipeline(Pipeline)) || (!Pipeline && !HasShader((FShaderType*)ShaderType)))) { if (!bSilent) @@ -1698,7 +1696,7 @@ bool FMaterialShaderMap::IsComplete(const FMaterial* Material, bool bSilent) { // Find the shaders for this vertex factory type. const FMeshMaterialShaderMap* MeshShaderMap = GetMeshShaderMap(VertexFactoryType); - if (!FMeshMaterialShaderMap::IsComplete(MeshShaderMap,Platform,Material,VertexFactoryType,bSilent)) + if (!FMeshMaterialShaderMap::IsComplete(MeshShaderMap,GetShaderPlatform(),Material,VertexFactoryType,bSilent)) { if (!MeshShaderMap && !bSilent) { @@ -1733,7 +1731,7 @@ bool FMaterialShaderMap::IsComplete(const FMaterial* Material, bool bSilent) for (int32 Index = 0; Index < StageTypes.Num(); ++Index) { auto* ShaderType = StageTypes[Index]->GetMaterialShaderType(); - if (ShouldCacheMaterialShader(ShaderType, Platform, Material)) + if (ShouldCacheMaterialShader(ShaderType, GetShaderPlatform(), Material)) { ++NumShouldCache; } @@ -1781,9 +1779,9 @@ void FMaterialShaderMap::LoadMissingShadersFromMemory(const FMaterial* Material) for (TLinkedList::TIterator ShaderTypeIt(FShaderType::GetTypeList());ShaderTypeIt;ShaderTypeIt.Next()) { FMaterialShaderType* ShaderType = ShaderTypeIt->GetMaterialShaderType(); - if (ShaderType && ShouldCacheMaterialShader(ShaderType, Platform, Material) && !HasShader(ShaderType)) + if (ShaderType && ShouldCacheMaterialShader(ShaderType, GetShaderPlatform(), Material) && !HasShader(ShaderType)) { - FShaderId ShaderId(MaterialShaderMapHash, nullptr, nullptr, ShaderType, FShaderTarget(ShaderType->GetFrequency(), Platform)); + FShaderId ShaderId(MaterialShaderMapHash, nullptr, nullptr, ShaderType, FShaderTarget(ShaderType->GetFrequency(), GetShaderPlatform())); FShader* FoundShader = ShaderType->FindShaderById(ShaderId); if (FoundShader) { @@ -1804,7 +1802,7 @@ void FMaterialShaderMap::LoadMissingShadersFromMemory(const FMaterial* Material) for (const FShaderType* Shader : Stages) { FMaterialShaderType* ShaderType = (FMaterialShaderType*)Shader->GetMaterialShaderType(); - if (ShaderType && ShouldCacheMaterialShader(ShaderType, Platform, Material)) + if (ShaderType && ShouldCacheMaterialShader(ShaderType, GetShaderPlatform(), Material)) { ++NumShaders; } @@ -1818,7 +1816,7 @@ void FMaterialShaderMap::LoadMissingShadersFromMemory(const FMaterial* Material) FMaterialShaderType* ShaderType = (FMaterialShaderType*)Shader->GetMaterialShaderType(); if (!HasShader(ShaderType)) { - FShaderId ShaderId(MaterialShaderMapHash, PipelineType->ShouldOptimizeUnusedOutputs() ? PipelineType : nullptr, nullptr, ShaderType, FShaderTarget(ShaderType->GetFrequency(), Platform)); + FShaderId ShaderId(MaterialShaderMapHash, PipelineType->ShouldOptimizeUnusedOutputs() ? PipelineType : nullptr, nullptr, ShaderType, FShaderTarget(ShaderType->GetFrequency(), GetShaderPlatform())); FShader* FoundShader = ShaderType->FindShaderById(ShaderId); if (FoundShader) { @@ -1849,7 +1847,7 @@ void FMaterialShaderMap::LoadMissingShadersFromMemory(const FMaterial* Material) if (MeshShaderMap) { - MeshShaderMap->LoadMissingShadersFromMemory(MaterialShaderMapHash, Material, Platform); + MeshShaderMap->LoadMissingShadersFromMemory(MaterialShaderMapHash, Material, GetShaderPlatform()); } } } @@ -1879,7 +1877,7 @@ void FMaterialShaderMap::GetShaderPipelineList(TArray& OutShad void FMaterialShaderMap::Register(EShaderPlatform InShaderPlatform) { extern int32 GCreateShadersOnLoad; - if (GCreateShadersOnLoad && Platform == InShaderPlatform) + if (GCreateShadersOnLoad && GetShaderPlatform() == InShaderPlatform) { for (auto KeyValue : GetShaders()) { @@ -1909,7 +1907,7 @@ void FMaterialShaderMap::Register(EShaderPlatform InShaderPlatform) INC_DWORD_STAT_BY(STAT_Shaders_ShaderMapMemory, GetSizeBytes()); } - GIdToMaterialShaderMap[Platform].Add(ShaderMapId,this); + GIdToMaterialShaderMap[GetShaderPlatform()].Add(ShaderMapId,this); bRegistered = true; } @@ -1929,7 +1927,7 @@ void FMaterialShaderMap::Release() DEC_DWORD_STAT(STAT_Shaders_NumShaderMaps); DEC_DWORD_STAT_BY(STAT_Shaders_ShaderMapMemory, GetSizeBytes()); - GIdToMaterialShaderMap[Platform].Remove(ShaderMapId); + GIdToMaterialShaderMap[GetShaderPlatform()].Remove(ShaderMapId); bRegistered = false; } @@ -1937,8 +1935,8 @@ void FMaterialShaderMap::Release() } } -FMaterialShaderMap::FMaterialShaderMap() : - Platform(SP_NumPlatforms), +FMaterialShaderMap::FMaterialShaderMap(EShaderPlatform InPlatform) : + TShaderMap(InPlatform), CompilingId(1), NumRefs(0), bDeletedThroughDeferredCleanup(false), @@ -2035,7 +2033,7 @@ void FMaterialShaderMap::Serialize(FArchive& Ar, bool bInlineShaderResources) ShaderMapId.Serialize(Ar); // serialize the platform enum as a uint8 - int32 TempPlatform = (int32)Platform; + int32 TempPlatform = (int32)GetShaderPlatform(); Ar << TempPlatform; Platform = (EShaderPlatform)TempPlatform; @@ -2106,7 +2104,7 @@ void FMaterialShaderMap::Serialize(FArchive& Ar, bool bInlineShaderResources) if (VertexFactoryType->IsUsedWithMaterials()) { - new(MeshShaderMaps) FMeshMaterialShaderMap(VertexFactoryType); + new(MeshShaderMaps) FMeshMaterialShaderMap(GetShaderPlatform(), VertexFactoryType); } } diff --git a/Engine/Source/Runtime/Engine/Private/Materials/MaterialShared.cpp b/Engine/Source/Runtime/Engine/Private/Materials/MaterialShared.cpp index 1f8036c9e601..64564acb6d7d 100644 --- a/Engine/Source/Runtime/Engine/Private/Materials/MaterialShared.cpp +++ b/Engine/Source/Runtime/Engine/Private/Materials/MaterialShared.cpp @@ -35,6 +35,14 @@ DEFINE_LOG_CATEGORY(LogMaterial); +int32 GDeferUniformExpressionCaching = 1; +FAutoConsoleVariableRef CVarDeferUniformExpressionCaching( + TEXT("r.DeferUniformExpressionCaching"), + GDeferUniformExpressionCaching, + TEXT("Whether to defer caching of uniform expressions until a rendering command needs them up to date. Deferring updates is more efficient because multiple SetVectorParameterValue calls in a frame will only result in one update."), + ECVF_RenderThreadSafe + ); + FName MaterialQualityLevelNames[] = { FName(TEXT("Low")), @@ -501,12 +509,7 @@ const TArray >& FMaterial::GetUniformSc bool FMaterial::RequiresSceneColorCopy_GameThread() const { - check(IsInGameThread()); - if (GameThreadShaderMap) - { - return GameThreadShaderMap->RequiresSceneColorCopy(); - } - return false; + return GameThreadShaderMap.GetReference() ? GameThreadShaderMap->RequiresSceneColorCopy() : false; } bool FMaterial::RequiresSceneColorCopy_RenderThread() const @@ -899,7 +902,7 @@ bool FMaterialResource::IsCrackFreeDisplacementEnabled() const return Material->bEnableCrackFreeDisplacement; } -bool FMaterialResource::IsSeparateTranslucencyEnabled() const +bool FMaterialResource::IsTranslucencyAfterDOFEnabled() const { return Material->bEnableSeparateTranslucency && !IsUIMaterial() && !IsDeferredDecal(); } @@ -1553,6 +1556,17 @@ void FMaterial::SetupMaterialEnvironment( static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.StencilForLODDither")); OutEnvironment.SetDefine(TEXT("USE_STENCIL_LOD_DITHER_DEFAULT"), CVar->GetValueOnAnyThread() != 0 ? 1 : 0); } + + { + switch (GetMaterialDomain()) + { + case MD_Surface: OutEnvironment.SetDefine(TEXT("MATERIALDOMAIN_SURFACE"), 1u); break; + case MD_DeferredDecal: OutEnvironment.SetDefine(TEXT("MATERIALDOMAIN_DEFERREDDECAL"), 1u); break; + case MD_LightFunction: OutEnvironment.SetDefine(TEXT("MATERIALDOMAIN_LIGHTFUNCTION"), 1u); break; + case MD_PostProcess: OutEnvironment.SetDefine(TEXT("MATERIALDOMAIN_POSTPROCESS"), 1u); break; + case MD_UI: OutEnvironment.SetDefine(TEXT("MATERIALDOMAIN_UI"), 1u); break; + } + } } /** @@ -1976,36 +1990,17 @@ void FMaterialRenderProxy::CacheUniformExpressions() check((bUsingNewLoader && GIsInitialLoad) || // The EDL at boot time maybe not load the default materials first; we need to intialize materials before the default materials are done UMaterial::GetDefaultMaterial(MD_Surface)); + DeferredUniformExpressionCacheRequests.Add(this); + UMaterialInterface::IterateOverActiveFeatureLevels([&](ERHIFeatureLevel::Type InFeatureLevel) { - const FMaterial* MaterialNoFallback = GetMaterialNoFallback(InFeatureLevel); - - if (MaterialNoFallback && MaterialNoFallback->GetRenderingThreadShaderMap()) - { - const FMaterial* Material = bUsingNewLoader ? MaterialNoFallback : GetMaterial(InFeatureLevel); - - // Do not cache uniform expressions for fallback materials. This step could - // be skipped where we don't allow for asynchronous shader compiling. - bool bIsFallbackMaterial = bUsingNewLoader ? false : (Material != MaterialNoFallback); - - if (!bIsFallbackMaterial) - { - FMaterialRenderContext MaterialRenderContext(this , *Material, nullptr); - MaterialRenderContext.bShowSelection = GIsEditor; - EvaluateUniformExpressions(UniformExpressionCache[(int32)InFeatureLevel], MaterialRenderContext); - } - else - { - InvalidateUniformExpressionCache(); - return; - } - } - else - { - InvalidateUniformExpressionCache(); - return; - } + InvalidateUniformExpressionCache(); }); + + if (!GDeferUniformExpressionCaching) + { + FMaterialRenderProxy::UpdateDeferredCachedUniformExpressions(); + } } void FMaterialRenderProxy::CacheUniformExpressions_GameThread() @@ -2072,16 +2067,60 @@ FMaterialRenderProxy::~FMaterialRenderProxy() void FMaterialRenderProxy::InitDynamicRHI() { - FMaterialRenderProxy::MaterialRenderProxyMap.Add(this); + // MaterialRenderProxyMap is only used by shader compiling + if (!FPlatformProperties::RequiresCookedData()) + { + FMaterialRenderProxy::MaterialRenderProxyMap.Add(this); + } } void FMaterialRenderProxy::ReleaseDynamicRHI() { - FMaterialRenderProxy::MaterialRenderProxyMap.Remove(this); + if (!FPlatformProperties::RequiresCookedData()) + { + FMaterialRenderProxy::MaterialRenderProxyMap.Remove(this); + } + + DeferredUniformExpressionCacheRequests.Remove(this); + InvalidateUniformExpressionCache(); } +void FMaterialRenderProxy::UpdateDeferredCachedUniformExpressions() +{ + check(IsInRenderingThread()); + + for (TSet::TConstIterator It(DeferredUniformExpressionCacheRequests); It; ++It) + { + FMaterialRenderProxy* MaterialProxy = *It; + + UMaterialInterface::IterateOverActiveFeatureLevels([&](ERHIFeatureLevel::Type InFeatureLevel) + { + const FMaterial* MaterialNoFallback = MaterialProxy->GetMaterialNoFallback(InFeatureLevel); + + if (MaterialNoFallback && MaterialNoFallback->GetRenderingThreadShaderMap()) + { + const FMaterial* Material = MaterialProxy->GetMaterial(InFeatureLevel); + + // Do not cache uniform expressions for fallback materials. This step could + // be skipped where we don't allow for asynchronous shader compiling. + bool bIsFallbackMaterial = (Material != MaterialNoFallback); + + if (!bIsFallbackMaterial) + { + FMaterialRenderContext MaterialRenderContext(MaterialProxy, *Material, nullptr); + MaterialRenderContext.bShowSelection = GIsEditor; + MaterialProxy->EvaluateUniformExpressions(MaterialProxy->UniformExpressionCache[(int32)InFeatureLevel], MaterialRenderContext); + } + } + }); + } + + DeferredUniformExpressionCacheRequests.Reset(); +} + TSet FMaterialRenderProxy::MaterialRenderProxyMap; +TSet FMaterialRenderProxy::DeferredUniformExpressionCacheRequests; /*----------------------------------------------------------------------------- FColoredMaterialRenderProxy diff --git a/Engine/Source/Runtime/Engine/Private/Materials/MaterialUniformExpressions.h b/Engine/Source/Runtime/Engine/Private/Materials/MaterialUniformExpressions.h index 2dbe092a1ba4..0805df5f97a3 100644 --- a/Engine/Source/Runtime/Engine/Private/Materials/MaterialUniformExpressions.h +++ b/Engine/Source/Runtime/Engine/Private/Materials/MaterialUniformExpressions.h @@ -139,7 +139,7 @@ public: { OutValue.R = OutValue.G = OutValue.B = OutValue.A = 0; - if(!Context.MaterialRenderProxy->GetVectorValue(ParameterName, &OutValue, Context)) + if(!Context.MaterialRenderProxy || !Context.MaterialRenderProxy->GetVectorValue(ParameterName, &OutValue, Context)) { GetDefaultValue(OutValue); } @@ -212,7 +212,7 @@ public: // inefficient compared to GetGameThreadNumberValue(), for editor purpose virtual void GetNumberValue(const FMaterialRenderContext& Context,FLinearColor& OutValue) const { - if(Context.MaterialRenderProxy->GetScalarValue(ParameterName, &OutValue.R, Context)) + if(Context.MaterialRenderProxy && Context.MaterialRenderProxy->GetScalarValue(ParameterName, &OutValue.R, Context)) { OutValue.G = OutValue.B = OutValue.A = OutValue.R; } @@ -319,7 +319,7 @@ public: else { OutValue = NULL; - if(!Context.MaterialRenderProxy->GetTextureValue(ParameterName,&OutValue,Context)) + if(!Context.MaterialRenderProxy || !Context.MaterialRenderProxy->GetTextureValue(ParameterName,&OutValue,Context)) { OutValue = GetIndexedTexture(Material, TextureIndex); } diff --git a/Engine/Source/Runtime/Engine/Private/Materials/MeshMaterialShader.cpp b/Engine/Source/Runtime/Engine/Private/Materials/MeshMaterialShader.cpp index 9facc403c310..75c42c73185c 100644 --- a/Engine/Source/Runtime/Engine/Private/Materials/MeshMaterialShader.cpp +++ b/Engine/Source/Runtime/Engine/Private/Materials/MeshMaterialShader.cpp @@ -156,7 +156,7 @@ uint32 FMeshMaterialShaderMap::BeginCompile( const FMaterialShaderMapId& InShaderMapId, const FMaterial* Material, FShaderCompilerEnvironment* MaterialEnvironment, - EShaderPlatform Platform, + EShaderPlatform InPlatform, TArray& NewJobs ) { @@ -173,7 +173,7 @@ uint32 FMeshMaterialShaderMap::BeginCompile( for (TLinkedList::TIterator ShaderTypeIt(FShaderType::GetTypeList());ShaderTypeIt;ShaderTypeIt.Next()) { FMeshMaterialShaderType* ShaderType = ShaderTypeIt->GetMeshMaterialShaderType(); - if (ShaderType && ShouldCacheMeshShader(ShaderType, Platform, Material, VertexFactoryType)) + if (ShaderType && ShouldCacheMeshShader(ShaderType, InPlatform, Material, VertexFactoryType)) { // Verify that the shader map Id contains inputs for any shaders that will be put into this shader map check(InShaderMapId.ContainsVertexFactoryType(VertexFactoryType)); @@ -186,7 +186,7 @@ uint32 FMeshMaterialShaderMap::BeginCompile( // Compile this mesh material shader for this material and vertex factory type. auto* Job = ShaderType->BeginCompileShader( ShaderMapId, - Platform, + InPlatform, Material, MaterialEnvironment, VertexFactoryType, @@ -211,7 +211,7 @@ uint32 FMeshMaterialShaderMap::BeginCompile( for (auto* Shader : StageTypes) { const FMeshMaterialShaderType* ShaderType = Shader->GetMeshMaterialShaderType(); - if (ShouldCacheMeshShader(ShaderType, Platform, Material, VertexFactoryType)) + if (ShouldCacheMeshShader(ShaderType, InPlatform, Material, VertexFactoryType)) { ++NumShaderStagesToCompile; } @@ -241,7 +241,7 @@ uint32 FMeshMaterialShaderMap::BeginCompile( } // Make a pipeline job with all the stages - FMeshMaterialShaderType::BeginCompileShaderPipeline(ShaderMapId, Platform, Material, MaterialEnvironment, VertexFactoryType, Pipeline, ShaderStagesToCompile, NewJobs); + FMeshMaterialShaderType::BeginCompileShaderPipeline(ShaderMapId, InPlatform, Material, MaterialEnvironment, VertexFactoryType, Pipeline, ShaderStagesToCompile, NewJobs); } else { @@ -358,14 +358,14 @@ bool FMeshMaterialShaderMap::IsComplete( void FMeshMaterialShaderMap::LoadMissingShadersFromMemory( const FSHAHash& MaterialShaderMapHash, const FMaterial* Material, - EShaderPlatform Platform) + EShaderPlatform InPlatform) { for (TLinkedList::TIterator ShaderTypeIt(FShaderType::GetTypeList());ShaderTypeIt;ShaderTypeIt.Next()) { FMeshMaterialShaderType* ShaderType = ShaderTypeIt->GetMeshMaterialShaderType(); - if (ShaderType && ShouldCacheMeshShader(ShaderType, Platform, Material, VertexFactoryType) && !HasShader((FShaderType*)ShaderType)) + if (ShaderType && ShouldCacheMeshShader(ShaderType, InPlatform, Material, VertexFactoryType) && !HasShader((FShaderType*)ShaderType)) { - const FShaderId ShaderId(MaterialShaderMapHash, nullptr, VertexFactoryType, (FShaderType*)ShaderType, FShaderTarget(ShaderType->GetFrequency(), Platform)); + const FShaderId ShaderId(MaterialShaderMapHash, nullptr, VertexFactoryType, (FShaderType*)ShaderType, FShaderTarget(ShaderType->GetFrequency(), InPlatform)); FShader* FoundShader = ((FShaderType*)ShaderType)->FindShaderById(ShaderId); if (FoundShader) @@ -387,7 +387,7 @@ void FMeshMaterialShaderMap::LoadMissingShadersFromMemory( for (const FShaderType* Shader : Stages) { FMeshMaterialShaderType* ShaderType = (FMeshMaterialShaderType*)Shader->GetMeshMaterialShaderType(); - if (ShaderType && ShouldCacheMeshShader(ShaderType, Platform, Material, VertexFactoryType)) + if (ShaderType && ShouldCacheMeshShader(ShaderType, InPlatform, Material, VertexFactoryType)) { ++NumShaders; } @@ -405,7 +405,7 @@ void FMeshMaterialShaderMap::LoadMissingShadersFromMemory( FMeshMaterialShaderType* ShaderType = (FMeshMaterialShaderType*)Shader->GetMeshMaterialShaderType(); if (!HasShader(ShaderType)) { - const FShaderId ShaderId(MaterialShaderMapHash, PipelineType->ShouldOptimizeUnusedOutputs() ? PipelineType : nullptr, VertexFactoryType, ShaderType, FShaderTarget(ShaderType->GetFrequency(), Platform)); + const FShaderId ShaderId(MaterialShaderMapHash, PipelineType->ShouldOptimizeUnusedOutputs() ? PipelineType : nullptr, VertexFactoryType, ShaderType, FShaderTarget(ShaderType->GetFrequency(), InPlatform)); FShader* FoundShader = ShaderType->FindShaderById(ShaderId); if (FoundShader) { diff --git a/Engine/Source/Runtime/Engine/Private/ModelRender.cpp b/Engine/Source/Runtime/Engine/Private/ModelRender.cpp index e68ce1887f07..e1f10be2d5c1 100644 --- a/Engine/Source/Runtime/Engine/Private/ModelRender.cpp +++ b/Engine/Source/Runtime/Engine/Private/ModelRender.cpp @@ -505,23 +505,20 @@ public: if (Elements.Num() > 0) { - for(int32 ElementIndex = 0;ElementIndex < Elements.Num();ElementIndex++) + for (int32 ElementIndex = 0;ElementIndex < Elements.Num();ElementIndex++) { - const FElementInfo* LCI = &Elements[ElementIndex]; - if (LCI) + const FElementInfo& LCI = Elements[ElementIndex]; + ELightInteractionType InteractionType = LCI.GetInteraction(LightSceneProxy).GetType(); + if (InteractionType != LIT_CachedIrrelevant) { - ELightInteractionType InteractionType = LCI->GetInteraction(LightSceneProxy).GetType(); - if(InteractionType != LIT_CachedIrrelevant) + bRelevant = true; + if (InteractionType != LIT_CachedLightMap) { - bRelevant = true; - if(InteractionType != LIT_CachedLightMap) - { - bLightMapped = false; - } - if(InteractionType != LIT_Dynamic) - { - bDynamic = false; - } + bLightMapped = false; + } + if (InteractionType != LIT_Dynamic) + { + bDynamic = false; } } } diff --git a/Engine/Source/Runtime/Engine/Private/MorphTools.cpp b/Engine/Source/Runtime/Engine/Private/MorphTools.cpp index b6e5037ad4be..0b61a02bff2b 100644 --- a/Engine/Source/Runtime/Engine/Private/MorphTools.cpp +++ b/Engine/Source/Runtime/Engine/Private/MorphTools.cpp @@ -150,7 +150,7 @@ void UMorphTarget::CreateMorphMeshStreams( const FMorphMeshRawSource& BaseSource MorphModel.Vertices.Shrink(); } -void UMorphTarget::PopulateDeltas(const TArray& Deltas, const int32 LODIndex) +void UMorphTarget::PopulateDeltas(const TArray& Deltas, const int32 LODIndex, const bool bCompareNormal) { // create the LOD entry if it doesn't already exist if (LODIndex >= MorphLODModels.Num()) @@ -172,7 +172,8 @@ void UMorphTarget::PopulateDeltas(const TArray& Deltas, const // Still keep this (could remove in long term due to incoming data) for (const FMorphTargetDelta& Delta : Deltas) { - if (Delta.PositionDelta.SizeSquared() > FMath::Square(THRESH_POINTS_ARE_NEAR)) + if (Delta.PositionDelta.SizeSquared() > FMath::Square(THRESH_POINTS_ARE_NEAR) || + ( bCompareNormal && Delta.TangentZDelta.SizeSquared() > 0.01f)) { MorphModel.Vertices.Add(Delta); } diff --git a/Engine/Source/Runtime/Engine/Private/NavigationObjectBase.cpp b/Engine/Source/Runtime/Engine/Private/NavigationObjectBase.cpp index c5f5a89cbdad..c0d6b5c7c530 100644 --- a/Engine/Source/Runtime/Engine/Private/NavigationObjectBase.cpp +++ b/Engine/Source/Runtime/Engine/Private/NavigationObjectBase.cpp @@ -154,9 +154,7 @@ void ANavigationObjectBase::FindBase() const FVector TraceStart = GetActorLocation(); const FVector TraceEnd = GetActorLocation() - FVector(0.f,0.f, 4.f * CapsuleComponent->GetScaledCapsuleHalfHeight()); - static FName NAME_NavFindBase = FName(TEXT("NavFindBase")); - - GetWorld()->SweepSingleByObjectType( Hit, TraceStart, TraceEnd, FQuat::Identity, FCollisionObjectQueryParams(ECC_WorldStatic), FCollisionShape::MakeBox(CollisionSlice), FCollisionQueryParams(NAME_NavFindBase, false)); + GetWorld()->SweepSingleByObjectType( Hit, TraceStart, TraceEnd, FQuat::Identity, FCollisionObjectQueryParams(ECC_WorldStatic), FCollisionShape::MakeBox(CollisionSlice), FCollisionQueryParams(SCENE_QUERY_STAT(NavFindBase), false)); // @fixme, ensure object is on the navmesh? // if( Hit.Actor != NULL ) @@ -198,7 +196,7 @@ void ANavigationObjectBase::Validate() FHitResult Hit(ForceInit); const FVector TraceStart = GetActorLocation(); const FVector TraceEnd = GetActorLocation() - FVector(0.f,0.f, 4.f * CapsuleComponent->GetScaledCapsuleHalfHeight()); - GetWorld()->SweepSingleByChannel(Hit, TraceStart, TraceEnd, FQuat::Identity, ECC_Pawn, FCollisionShape::MakeBox(Slice), FCollisionQueryParams(NAME_None, false, this)); + GetWorld()->SweepSingleByChannel(Hit, TraceStart, TraceEnd, FQuat::Identity, ECC_Pawn, FCollisionShape::MakeBox(Slice), FCollisionQueryParams(SCENE_QUERY_STAT(NavObjectBase_Validate),false, this)); if( Hit.bBlockingHit ) { const FVector HitLocation = TraceStart + (TraceEnd - TraceStart) * Hit.Time; @@ -238,9 +236,3 @@ void ANavigationObjectBase::GetMoveGoalReachTest(const AActor* MovingActor, cons GetSimpleCollisionCylinder(GoalRadius, GoalHalfHeight); } -/** Returns CapsuleComponent subobject **/ -UCapsuleComponent* ANavigationObjectBase::GetCapsuleComponent() const { return CapsuleComponent; } -/** Returns GoodSprite subobject **/ -UBillboardComponent* ANavigationObjectBase::GetGoodSprite() const { return GoodSprite; } -/** Returns BadSprite subobject **/ -UBillboardComponent* ANavigationObjectBase::GetBadSprite() const { return BadSprite; } diff --git a/Engine/Source/Runtime/Engine/Private/NetConnection.cpp b/Engine/Source/Runtime/Engine/Private/NetConnection.cpp index 59c5c049bb41..fd9e07dd786d 100644 --- a/Engine/Source/Runtime/Engine/Private/NetConnection.cpp +++ b/Engine/Source/Runtime/Engine/Private/NetConnection.cpp @@ -1554,6 +1554,13 @@ float UNetConnection::GetTimeoutValue() Timeout = bPendingDestroy ? 2.f : ConnectionTimeout; } +#if WITH_EDITOR || UE_BUILD_DEBUG + if (Driver->TimeoutMultiplierForUnoptimizedBuilds > 0) + { + Timeout *= Driver->TimeoutMultiplierForUnoptimizedBuilds; + } +#endif + return Timeout; } diff --git a/Engine/Source/Runtime/Engine/Private/NetworkDriver.cpp b/Engine/Source/Runtime/Engine/Private/NetworkDriver.cpp index 27fff5097874..95ff90e97036 100644 --- a/Engine/Source/Runtime/Engine/Private/NetworkDriver.cpp +++ b/Engine/Source/Runtime/Engine/Private/NetworkDriver.cpp @@ -1161,6 +1161,12 @@ void UNetDriver::Shutdown() } } + // Empty our replication map here before we're destroyed, + // even though we use AddReferencedObjects to keep the referenced properties + // in here from being collected, when we're all GC'd the order seems non-deterministic + RepLayoutMap.Empty(); + ReplicationChangeListMap.Empty(); + ConnectionlessHandler.Reset(nullptr); #if DO_ENABLE_NET_TEST @@ -2168,6 +2174,34 @@ void UNetDriver::AddReferencedObjects(UObject* InThis, FReferenceCollector& Coll { UNetDriver* This = CastChecked(InThis); Super::AddReferencedObjects(This, Collector); + + for (auto It = This->RepLayoutMap.CreateIterator(); It; ++It) + { + if (It.Value().IsValid()) + { + It.Value()->AddReferencedObjects(Collector); + } + else + { + It.RemoveCurrent(); + } + } + + for (auto It = This->ReplicationChangeListMap.CreateIterator(); It; ++It) + { + if (It.Value().IsValid()) + { + FRepChangelistState* const ChangelistState = It.Value()->GetRepChangelistState(); + if (ChangelistState && ChangelistState->RepLayout.IsValid()) + { + ChangelistState->RepLayout->AddReferencedObjects(Collector); + } + } + else + { + It.RemoveCurrent(); + } + } } #if DO_ENABLE_NET_TEST @@ -2398,7 +2432,6 @@ FNetViewer::FNetViewer(UNetConnection* InConnection, float DeltaSeconds) : FHitResult Hit(1.0f); FVector PredictedLocation = ViewLocation + Ahead; - static FName NAME_ServerForwardView = FName(TEXT("ServerForwardView")); UWorld* World = NULL; if( InConnection->PlayerController ) { @@ -2409,7 +2442,7 @@ FNetViewer::FNetViewer(UNetConnection* InConnection, float DeltaSeconds) : World = ViewerPawn->GetWorld(); } check( World ); - if (World->LineTraceSingleByObjectType(Hit, ViewLocation, PredictedLocation, FCollisionObjectQueryParams(ECC_WorldStatic), FCollisionQueryParams(NAME_ServerForwardView, true, ViewTarget))) + if (World->LineTraceSingleByObjectType(Hit, ViewLocation, PredictedLocation, FCollisionObjectQueryParams(ECC_WorldStatic), FCollisionQueryParams(SCENE_QUERY_STAT(ServerForwardView), true, ViewTarget))) { // hit something, view location is hit location ViewLocation = Hit.Location; diff --git a/Engine/Source/Runtime/Engine/Private/Note.cpp b/Engine/Source/Runtime/Engine/Private/Note.cpp index 9757b558907c..4f7eab7b105f 100644 --- a/Engine/Source/Runtime/Engine/Private/Note.cpp +++ b/Engine/Source/Runtime/Engine/Private/Note.cpp @@ -62,10 +62,3 @@ ANote::ANote(const FObjectInitializer& ObjectInitializer) bHidden = true; bCanBeDamaged = false; } - -#if WITH_EDITORONLY_DATA -/** Returns SpriteComponent subobject **/ -UBillboardComponent* ANote::GetSpriteComponent() const { return SpriteComponent; } -/** Returns ArrowComponent subobject **/ -UArrowComponent* ANote::GetArrowComponent() const { return ArrowComponent; } -#endif diff --git a/Engine/Source/Runtime/Engine/Private/OpusAudioInfo.cpp b/Engine/Source/Runtime/Engine/Private/OpusAudioInfo.cpp index a942b53ad26b..ce850fe97fab 100644 --- a/Engine/Source/Runtime/Engine/Private/OpusAudioInfo.cpp +++ b/Engine/Source/Runtime/Engine/Private/OpusAudioInfo.cpp @@ -5,7 +5,7 @@ #include "ContentStreaming.h" #include "Interfaces/IAudioFormat.h" -#define WITH_OPUS (PLATFORM_WINDOWS || PLATFORM_MAC || PLATFORM_LINUX) +#define WITH_OPUS (PLATFORM_WINDOWS || PLATFORM_MAC || PLATFORM_LINUX || PLATFORM_XBOXONE) #if WITH_OPUS THIRD_PARTY_INCLUDES_START @@ -180,6 +180,10 @@ uint32 FOpusAudioInfo::GetMaxFrameSizeSamples() const int32 FOpusAudioInfo::Decode(const uint8* FrameData, uint16 FrameSize, int16* OutPCMData, int32 SampleSize) { - return OpusDecoderWrapper->Decode(FrameData, FrameSize, OutPCMData, SampleSize); + if (OpusDecoderWrapper) + { + return OpusDecoderWrapper->Decode(FrameData, FrameSize, OutPCMData, SampleSize); + } + return INDEX_NONE; } diff --git a/Engine/Source/Runtime/Engine/Private/PacketHandlers/StatelessConnectHandlerComponent.cpp b/Engine/Source/Runtime/Engine/Private/PacketHandlers/StatelessConnectHandlerComponent.cpp index 07cd66613bc7..1da7c298a826 100644 --- a/Engine/Source/Runtime/Engine/Private/PacketHandlers/StatelessConnectHandlerComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/PacketHandlers/StatelessConnectHandlerComponent.cpp @@ -211,7 +211,7 @@ void StatelessConnectHandlerComponent::SendConnectChallenge(FString ClientAddres { FBitWriter ChallengePacket(HANDSHAKE_PACKET_SIZE_BITS + 1 /* Termination bit */); uint8 bHandshakePacket = 1; - float Timestamp = (Driver != nullptr ? Driver->Time : -1.f); + float Timestamp = Driver->Time; uint8 Cookie[20]; GenerateCookie(ClientAddress, ActiveSecret, Timestamp, Cookie); diff --git a/Engine/Source/Runtime/Engine/Private/Particles/Emitter.cpp b/Engine/Source/Runtime/Engine/Private/Particles/Emitter.cpp index d6d1ff33ec36..0329414ed3bd 100644 --- a/Engine/Source/Runtime/Engine/Private/Particles/Emitter.cpp +++ b/Engine/Source/Runtime/Engine/Private/Particles/Emitter.cpp @@ -294,13 +294,4 @@ bool AEmitter::GetReferencedContentObjects(TArray& Objects) const } #endif -/** Returns ParticleSystemComponent subobject **/ -UParticleSystemComponent* AEmitter::GetParticleSystemComponent() { return ParticleSystemComponent; } -#if WITH_EDITORONLY_DATA -/** Returns SpriteComponent subobject **/ -UBillboardComponent* AEmitter::GetSpriteComponent() const { return SpriteComponent; } -/** Returns ArrowComponent subobject **/ -UArrowComponent* AEmitter::GetArrowComponent() const { return ArrowComponent; } -#endif - #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Runtime/Engine/Private/Particles/FXSystem.cpp b/Engine/Source/Runtime/Engine/Private/Particles/FXSystem.cpp index 2643a6dce739..b5cd5157a952 100644 --- a/Engine/Source/Runtime/Engine/Private/Particles/FXSystem.cpp +++ b/Engine/Source/Runtime/Engine/Private/Particles/FXSystem.cpp @@ -130,6 +130,12 @@ namespace FXConsoleVariables TEXT("Allow emitters to be culled."), ECVF_Cheat ); + int32 bAllowGPUParticles = true; + FAutoConsoleVariableRef CVarAllowGPUParticles( + TEXT("FX.AllowGPUParticles"), + bAllowGPUParticles, + TEXT("If true, allow the usage of GPU particles.") + ); } /*------------------------------------------------------------------------------ @@ -217,7 +223,7 @@ void FFXSystem::AddVectorField( UVectorFieldComponent* VectorFieldComponent ) FAddVectorFieldCommand, FFXSystem*, FXSystem, this, FVectorFieldInstance*, Instance, Instance, - FMatrix, ComponentToWorld, VectorFieldComponent->ComponentToWorld.ToMatrixWithScale(), + FMatrix, ComponentToWorld, VectorFieldComponent->GetComponentTransform().ToMatrixWithScale(), { Instance->UpdateTransforms( ComponentToWorld ); Instance->Index = FXSystem->VectorFields.AddUninitialized().Index; @@ -273,7 +279,7 @@ void FFXSystem::UpdateVectorField( UVectorFieldComponent* VectorFieldComponent ) FUpdateVectorFieldParams UpdateParams; UpdateParams.Bounds = VectorFieldComponent->Bounds.GetBox(); - UpdateParams.ComponentToWorld = VectorFieldComponent->ComponentToWorld.ToMatrixWithScale(); + UpdateParams.ComponentToWorld = VectorFieldComponent->GetComponentTransform().ToMatrixWithScale(); UpdateParams.Intensity = VectorFieldComponent->Intensity; UpdateParams.Tightness = VectorFieldComponent->Tightness; diff --git a/Engine/Source/Runtime/Engine/Private/Particles/ParticleBeam2EmitterInstance.cpp b/Engine/Source/Runtime/Engine/Private/Particles/ParticleBeam2EmitterInstance.cpp index a3e31a185aaf..2eaab40d3d8f 100644 --- a/Engine/Source/Runtime/Engine/Private/Particles/ParticleBeam2EmitterInstance.cpp +++ b/Engine/Source/Runtime/Engine/Private/Particles/ParticleBeam2EmitterInstance.cpp @@ -658,7 +658,7 @@ void FParticleBeam2EmitterInstance::UpdateBoundingBox(float DeltaTime) } // Take scale into account as well - FVector Scale = Component->ComponentToWorld.GetScale3D(); + FVector Scale = Component->GetComponentTransform().GetScale3D(); // Take each particle into account for (int32 i=0; iComponentToWorld.GetScale3D(); + FVector Scale = Component->GetComponentTransform().GetScale3D(); // Take each particle into account for (int32 i=0; iTemplate ? - *(Component->Template->GetName()) : - TEXT("No template") : - TEXT("No component")); + Component->Template ? *Component->Template->GetName() : TEXT("No template")); FColor ErrorColor(255,0,0); GEngine->AddOnScreenDebugMessage((uint64)((PTRINT)this), 5.0f, ErrorColor,ErrorMessage); UE_LOG(LogParticles, Log, TEXT("%s"), *ErrorMessage); diff --git a/Engine/Source/Runtime/Engine/Private/Particles/ParticleBeamModules.cpp b/Engine/Source/Runtime/Engine/Private/Particles/ParticleBeamModules.cpp index 8fc7a09db9db..ce394f37e110 100644 --- a/Engine/Source/Runtime/Engine/Private/Particles/ParticleBeamModules.cpp +++ b/Engine/Source/Runtime/Engine/Private/Particles/ParticleBeamModules.cpp @@ -126,7 +126,7 @@ void UParticleModuleTypeDataBeam2::Spawn(FParticleEmitterInstance* Owner, int32 if (BeamInst->BeamModule_Source == NULL) { BeamData->SourcePoint = Component->GetComponentLocation(); - BeamData->SourceTangent = Component->ComponentToWorld.GetScaledAxis( EAxis::X ); + BeamData->SourceTangent = Component->GetComponentTransform().GetScaledAxis( EAxis::X ); BeamData->SourceStrength = 1.0f; } @@ -136,7 +136,7 @@ void UParticleModuleTypeDataBeam2::Spawn(FParticleEmitterInstance* Owner, int32 // Set the particle target based on the distance float TotalDistance = Distance.GetValue(Particle.RelativeTime, Component); // Always use the X-axis of the component as the direction - FVector Direction = Component->ComponentToWorld.GetScaledAxis( EAxis::X ); + FVector Direction = Component->GetComponentTransform().GetScaledAxis( EAxis::X ); Direction.Normalize(); // Calculate the final target point BeamData->TargetPoint = BeamData->SourcePoint + Direction * TotalDistance; @@ -245,7 +245,7 @@ void UParticleModuleTypeDataBeam2::Update(FParticleEmitterInstance* Owner, int32 if (BeamInst->BeamModule_Source == NULL) { BeamData->SourcePoint = Component->GetComponentLocation(); - BeamData->SourceTangent = Component->ComponentToWorld.GetScaledAxis( EAxis::X ); + BeamData->SourceTangent = Component->GetComponentTransform().GetScaledAxis( EAxis::X ); } // If the method is set for distance, or there is no target, determine the target point @@ -253,7 +253,7 @@ void UParticleModuleTypeDataBeam2::Update(FParticleEmitterInstance* Owner, int32 { // Set the particle target based on the distance float TotalDistance = Distance.GetValue(Particle.RelativeTime, Component); - FVector Direction = Component->ComponentToWorld.GetScaledAxis( EAxis::X ); + FVector Direction = Component->GetComponentTransform().GetScaledAxis( EAxis::X ); Direction.Normalize(); BeamData->TargetPoint = BeamData->SourcePoint + Direction * TotalDistance; BeamData->TargetTangent = -Direction; @@ -496,7 +496,7 @@ void UParticleModuleTypeDataBeam2::Update(FParticleEmitterInstance* Owner, int32 #endif //#if defined(_BEAM2_TYPEDATA_NORMAL_TANGENTS_) if (SourceTangent.IsNearlyZero()) { - SourceTangent = Component->ComponentToWorld.GetScaledAxis( EAxis::X ); + SourceTangent = Component->GetComponentTransform().GetScaledAxis( EAxis::X ); } SourceTangent *= BeamData->SourceStrength; @@ -507,7 +507,7 @@ void UParticleModuleTypeDataBeam2::Update(FParticleEmitterInstance* Owner, int32 #endif //#if defined(_BEAM2_TYPEDATA_NORMAL_TANGENTS_) if (TargetTangent.IsNearlyZero()) { - TargetTangent = Component->ComponentToWorld.GetScaledAxis( EAxis::X ); + TargetTangent = Component->GetComponentTransform().GetScaledAxis( EAxis::X ); } TargetTangent *= BeamData->TargetStrength; @@ -2010,7 +2010,7 @@ bool UParticleModuleBeamSource::ResolveSourceData(FParticleBeam2EmitterInstance* else { // Use the value as a local space position. - BeamData->SourcePoint = BeamInst->Component->ComponentToWorld.TransformPosition( + BeamData->SourcePoint = BeamInst->Component->GetComponentTransform().TransformPosition( Source.GetValue(BeamInst->EmitterTime, BeamInst->Component)); } } @@ -2024,7 +2024,7 @@ bool UParticleModuleBeamSource::ResolveSourceData(FParticleBeam2EmitterInstance* { case PEB2STTM_Direct: // Use the emitter direction as the tangent - BeamData->SourceTangent = BeamInst->Component->ComponentToWorld.GetScaledAxis( EAxis::X ); + BeamData->SourceTangent = BeamInst->Component->GetComponentTransform().GetScaledAxis( EAxis::X ); bSetSourceTangent = true; break; case PEB2STTM_UserSet: @@ -2050,7 +2050,7 @@ bool UParticleModuleBeamSource::ResolveSourceData(FParticleBeam2EmitterInstance* break; case PEB2STTM_Emitter: // Use the emitter direction as the tangent - BeamData->SourceTangent = BeamInst->Component->ComponentToWorld.GetScaledAxis( EAxis::X ); + BeamData->SourceTangent = BeamInst->Component->GetComponentTransform().GetScaledAxis( EAxis::X ); bSetSourceTangent = true; break; } @@ -2063,7 +2063,7 @@ bool UParticleModuleBeamSource::ResolveSourceData(FParticleBeam2EmitterInstance* if (bSourceAbsolute == false) { // If not tagged as absolute, transform it to world space - BeamData->SourceTangent = BeamInst->Component->ComponentToWorld.TransformVector(BeamData->SourceTangent); + BeamData->SourceTangent = BeamInst->Component->GetComponentTransform().TransformVector(BeamData->SourceTangent); } } } @@ -2318,7 +2318,7 @@ bool UParticleModuleBeamTarget::ResolveTargetData(FParticleBeam2EmitterInstance* { Distance = 0.001f; } - FVector Direction = BeamInst->Component->ComponentToWorld.GetScaledAxis( EAxis::X ); + FVector Direction = BeamInst->Component->GetComponentTransform().GetScaledAxis( EAxis::X ); Direction.Normalize(); BeamData->TargetPoint = BeamData->SourcePoint + Direction * Distance; bSetTarget = true; @@ -2471,7 +2471,7 @@ bool UParticleModuleBeamTarget::ResolveTargetData(FParticleBeam2EmitterInstance* } else { - BeamData->TargetPoint = BeamInst->Component->ComponentToWorld.TransformPosition( + BeamData->TargetPoint = BeamInst->Component->GetComponentTransform().TransformPosition( Target.GetValue(BeamInst->EmitterTime, BeamInst->Component)); } } @@ -2484,7 +2484,7 @@ bool UParticleModuleBeamTarget::ResolveTargetData(FParticleBeam2EmitterInstance* switch (TargetTangentMethod) { case PEB2STTM_Direct: - BeamData->TargetTangent = BeamInst->Component->ComponentToWorld.GetScaledAxis( EAxis::X ); + BeamData->TargetTangent = BeamInst->Component->GetComponentTransform().GetScaledAxis( EAxis::X ); bSetTargetTangent = true; break; case PEB2STTM_UserSet: @@ -2507,7 +2507,7 @@ bool UParticleModuleBeamTarget::ResolveTargetData(FParticleBeam2EmitterInstance* bSetTargetTangent = true; break; case PEB2STTM_Emitter: - BeamData->TargetTangent = BeamInst->Component->ComponentToWorld.GetScaledAxis( EAxis::X ); + BeamData->TargetTangent = BeamInst->Component->GetComponentTransform().GetScaledAxis( EAxis::X ); bSetTargetTangent = true; break; } @@ -2518,7 +2518,7 @@ bool UParticleModuleBeamTarget::ResolveTargetData(FParticleBeam2EmitterInstance* BeamData->TargetTangent = TargetTangent.GetValue(Particle.RelativeTime, BeamInst->Component); if (bTargetAbsolute == false) { - BeamData->TargetTangent = BeamInst->Component->ComponentToWorld.TransformVector(BeamData->TargetTangent); + BeamData->TargetTangent = BeamInst->Component->GetComponentTransform().TransformVector(BeamData->TargetTangent); } } } diff --git a/Engine/Source/Runtime/Engine/Private/Particles/ParticleComponents.cpp b/Engine/Source/Runtime/Engine/Private/Particles/ParticleComponents.cpp index f5e0dd806aa7..6b6cf1509a00 100644 --- a/Engine/Source/Runtime/Engine/Private/Particles/ParticleComponents.cpp +++ b/Engine/Source/Runtime/Engine/Private/Particles/ParticleComponents.cpp @@ -115,8 +115,8 @@ int32 GParticleLODBias = 0; FAutoConsoleVariableRef CVarParticleLODBias( TEXT("r.ParticleLODBias"), GParticleLODBias, - TEXT("LOD bias for particle systems. Development feature, default is 0"), - ECVF_Cheat + TEXT("LOD bias for particle systems, default is 0"), + ECVF_Scalability ); /** Whether to allow particle systems to perform work. */ @@ -1977,8 +1977,8 @@ UParticleSystem::UParticleSystem(const FObjectInitializer& ObjectInitializer) EditorLODSetting = 0; #endif // WITH_EDITORONLY_DATA FixedRelativeBoundingBox.Min = FVector(-1.0f, -1.0f, -1.0f); - FixedRelativeBoundingBox.Max = FVector(1.0f, 1.0f, 1.0f); + FixedRelativeBoundingBox.IsValid = true; LODMethod = PARTICLESYSTEMLODMETHOD_Automatic; LODDistanceCheckTime = 0.25f; @@ -3468,18 +3468,15 @@ void UParticleSystemComponent::GetResourceSizeEx(FResourceSizeEx& CumulativeReso bool UParticleSystemComponent::ParticleLineCheck(FHitResult& Hit, AActor* SourceActor, const FVector& End, const FVector& Start, const FVector& HalfExtent, const FCollisionObjectQueryParams& ObjectParams) { check(GetWorld()); - static FName NAME_ParticleCollision = FName(TEXT("ParticleCollision")); - if ( HalfExtent.IsZero() ) { - FCollisionQueryParams QueryParams(NAME_ParticleCollision, true, SourceActor); + FCollisionQueryParams QueryParams(SCENE_QUERY_STAT(ParticleCollision), true, SourceActor); QueryParams.bReturnPhysicalMaterial = true; return GetWorld()->LineTraceSingleByObjectType(Hit, Start, End, ObjectParams, QueryParams); } else { - FCollisionQueryParams BoxParams; - BoxParams.TraceTag = NAME_ParticleCollision; + FCollisionQueryParams BoxParams(SCENE_QUERY_STAT(ParticleCollision)); BoxParams.AddIgnoredActor(SourceActor); BoxParams.bReturnPhysicalMaterial = true; return GetWorld()->SweepSingleByObjectType(Hit, Start, End, FQuat::Identity, ObjectParams, FCollisionShape::MakeBox(HalfExtent), BoxParams); @@ -3849,7 +3846,7 @@ FParticleDynamicData* UParticleSystemComponent::CreateDynamicData(ERHIFeatureLev if (Template) { - ParticleDynamicData->SystemPositionForMacroUVs = ComponentToWorld.TransformPosition(Template->MacroUVPosition); + ParticleDynamicData->SystemPositionForMacroUVs = GetComponentTransform().TransformPosition(Template->MacroUVPosition); ParticleDynamicData->SystemRadiusForMacroUVs = Template->MacroUVRadius; } @@ -4053,6 +4050,24 @@ void UParticleSystemComponent::SetMaterial(int32 ElementIndex, UMaterialInterfac } EmitterMaterials[ElementIndex] = Material; bIsViewRelevanceDirty = true; + + for (int32 EmitterIndex = 0; EmitterIndex < EmitterInstances.Num(); ++EmitterIndex) + { + if (FParticleEmitterInstance* Inst = EmitterInstances[EmitterIndex]) + { + if (!Inst->Tick_MaterialOverrides()) + { + if (EmitterMaterials.IsValidIndex(EmitterIndex)) + { + if (EmitterMaterials[EmitterIndex]) + { + Inst->CurrentMaterial = EmitterMaterials[EmitterIndex]; + } + } + } + } + } + MarkRenderDynamicDataDirty(); } } @@ -4166,7 +4181,7 @@ void UParticleSystemComponent::OrientZAxisTowardCamera() DirToCamera.Normalize(); // Convert the camera direction to local space - DirToCamera = ComponentToWorld.InverseTransformVectorNoScale(DirToCamera); + DirToCamera = GetComponentTransform().InverseTransformVectorNoScale(DirToCamera); // Local Z axis const FVector LocalZAxis = FVector(0,0,1); @@ -4513,7 +4528,7 @@ void UParticleSystemComponent::TickComponent(float DeltaTime, enum ELevelTick Ti { bool bCalculateLODLevel = (bOverrideLODMethod == true) ? (LODMethod == PARTICLESYSTEMLODMETHOD_Automatic) : - (Template ? (Template->LODMethod == PARTICLESYSTEMLODMETHOD_Automatic) : false); + (Template->LODMethod == PARTICLESYSTEMLODMETHOD_Automatic); if (bCalculateLODLevel == true) { FVector EffectPosition = GetComponentLocation(); @@ -4611,7 +4626,7 @@ void UParticleSystemComponent::TickComponent(float DeltaTime, enum ELevelTick Ti SCOPE_CYCLE_COUNTER(STAT_UParticleSystemComponent_Marshall) bAsyncDataCopyIsValid = true; check(!bParallelRenderThreadUpdate); - AsyncComponentToWorld = ComponentToWorld; + AsyncComponentToWorld = GetComponentTransform(); AsyncInstanceParameters.Reset(); AsyncInstanceParameters.Append(InstanceParameters); AsyncBounds = Bounds; @@ -5350,10 +5365,7 @@ void UParticleSystemComponent::ActivateSystem(bool bFlagAsJustAttached) { FVector EffectPosition = GetComponentLocation(); int32 DesiredLODLevel = DetermineLODLevelForLocation(EffectPosition); - if (DesiredLODLevel != LODLevel) - { - SetLODLevel(DesiredLODLevel); - } + SetLODLevel(DesiredLODLevel); } else { @@ -6217,11 +6229,12 @@ int32 UParticleSystemComponent::DetermineLODLevelForLocation(const FVector& Effe return 0; } - // Don't bother if we only have 1 LOD level... - if (Template->LODDistances.Num() <= 1) + // Don't bother if we only have 1 LOD level... Or if we want to ignore distance comparisons. + if (Template->LODDistances.Num() <= 1 || Template->LODMethod == PARTICLESYSTEMLODMETHOD_DirectSet) { return 0; } + check(IsInGameThread()); int32 Retval = 0; @@ -6252,10 +6265,10 @@ int32 UParticleSystemComponent::DetermineLODLevelForLocation(const FVector& Effe // This will now put everything in LODLevel 0 (high detail) by default float LODDistanceSqr = (PlayerViewLocations.Num() ? FMath::Square(WORLD_MAX) : 0.0f); for (const FVector& ViewLocation : PlayerViewLocations) - { + { const float DistanceToEffectSqr = FVector(ViewLocation - EffectLocation).SizeSquared(); if (DistanceToEffectSqr < LODDistanceSqr) - { + { LODDistanceSqr = DistanceToEffectSqr; } } @@ -6288,7 +6301,7 @@ void UParticleSystemComponent::SetLODLevel(int32 InLODLevel) return; } - int32 NewLODLevel = FMath::Clamp(InLODLevel + GParticleLODBias,0,Template->GetLODLevelCount()-1); + int32 NewLODLevel = FMath::Clamp(InLODLevel + GParticleLODBias, 0, Template->GetLODLevelCount() - 1); if (LODLevel != NewLODLevel) { MarkRenderStateDirty(); diff --git a/Engine/Source/Runtime/Engine/Private/Particles/ParticleEmitterInstances.cpp b/Engine/Source/Runtime/Engine/Private/Particles/ParticleEmitterInstances.cpp index 6f85845f2c47..7c52d1e40aa3 100644 --- a/Engine/Source/Runtime/Engine/Private/Particles/ParticleEmitterInstances.cpp +++ b/Engine/Source/Runtime/Engine/Private/Particles/ParticleEmitterInstances.cpp @@ -198,8 +198,11 @@ FParticleEmitterBuildInfo::FParticleEmitterBuildInfo() , MaxSizeScaleBySpeed(1.0f, 1.0f) , bEnableCollision(false) , CollisionResponse(EParticleCollisionResponse::Bounce) + , CollisionMode(EParticleCollisionMode::SceneDepth) , CollisionRadiusScale(1.0f) , CollisionRadiusBias(0.0f) + , CollisionRandomSpread(0.0f) + , CollisionRandomDistribution(1.0f) , Friction(0.0f) , PointAttractorPosition(FVector::ZeroVector) , PointAttractorRadius(0.0f) @@ -1129,7 +1132,7 @@ void FParticleEmitterInstance::UpdateBoundingBox(float DeltaTime) bool bUpdateBox = ((Component->bWarmingUp == false) && (Component->Template != NULL) && (Component->Template->bUseFixedRelativeBoundingBox == false)); // Take component scale into account - FVector Scale = Component->ComponentToWorld.GetScale3D(); + FVector Scale = Component->GetComponentTransform().GetScale3D(); UParticleLODLevel* LODLevel = GetCurrentLODLevelChecked(); @@ -1264,7 +1267,7 @@ void FParticleEmitterInstance::ForceUpdateBoundingBox() if ( Component ) { // Take component scale into account - FVector Scale = Component->ComponentToWorld.GetScale3D(); + FVector Scale = Component->GetComponentTransform().GetScale3D(); UParticleLODLevel* LODLevel = GetCurrentLODLevelChecked(); UParticleLODLevel* HighestLODLevel = SpriteTemplate->LODLevels[0]; @@ -1773,7 +1776,7 @@ void FParticleEmitterInstance::CheckSpawnCount(int32 InNewCount, int32 InMaxCoun InMaxCount, (float)(InMaxCount * 4 * SizeScalar) / 1024.0f, InNewCount - ActiveParticles, - Component ? Component->Template ? *(Component->Template->GetPathName()) : TEXT("No template") : TEXT("No component")); + Component->Template ? *Component->Template->GetPathName() : TEXT("No template")); FColor ErrorColor(255,255,0); if (GEngine->OnScreenDebugMessageExists((uint64)(0x8000000 | (PTRINT)this)) == false) { @@ -2539,7 +2542,7 @@ bool FParticleEmitterInstance::FillReplayData( FDynamicEmitterReplayDataBase& Ou OutData.Scale = FVector(1.0f, 1.0f, 1.0f); if (Component) { - OutData.Scale = Component->ComponentToWorld.GetScale3D(); + OutData.Scale = Component->GetComponentTransform().GetScale3D(); } int32 ParticleMemSize = MaxActiveParticles * ParticleStride; @@ -2704,7 +2707,7 @@ void FParticleEmitterInstance::GetScreenAlignmentAndScale(int32& OutScreenAlign, OutScale = FVector(1.0f, 1.0f, 1.0f); if (Component) { - OutScale = Component->ComponentToWorld.GetScale3D(); + OutScale = Component->GetComponentTransform().GetScale3D(); } } @@ -3136,7 +3139,7 @@ void FParticleMeshEmitterInstance::UpdateBoundingBox(float DeltaTime) (Component->Template != NULL) && (Component->Template->bUseFixedRelativeBoundingBox == false)); // Take scale into account - FVector Scale = Component->ComponentToWorld.GetScale3D(); + FVector Scale = Component->GetComponentTransform().GetScale3D(); // Get the static mesh bounds FBoxSphereBounds MeshBound; @@ -3618,7 +3621,7 @@ bool FParticleMeshEmitterInstance::FillReplayData( FDynamicEmitterReplayDataBase { if (!bIgnoreComponentScale) { - NewReplayData->Scale = Component->ComponentToWorld.GetScale3D(); + NewReplayData->Scale = Component->GetComponentTransform().GetScale3D(); } } } diff --git a/Engine/Source/Runtime/Engine/Private/Particles/ParticleGpuSimulation.cpp b/Engine/Source/Runtime/Engine/Private/Particles/ParticleGpuSimulation.cpp index 4584d6cb1ca9..2dcf8db4d9d5 100644 --- a/Engine/Source/Runtime/Engine/Private/Particles/ParticleGpuSimulation.cpp +++ b/Engine/Source/Runtime/Engine/Private/Particles/ParticleGpuSimulation.cpp @@ -43,6 +43,7 @@ #include "Particles/ParticleLODLevel.h" #include "Particles/ParticleModuleRequired.h" #include "VectorField/VectorField.h" +#include "CoreDelegates.h" #include "PipelineStateCache.h" DECLARE_CYCLE_STAT(TEXT("GPUSpriteEmitterInstance Init"), STAT_GPUSpriteEmitterInstance_Init, STATGROUP_Particles); @@ -3154,7 +3155,7 @@ public: UParticleSystem *Template = Component->Template; const bool bLocalSpace = EmitterInfo.RequiredModule->bUseLocalSpace; - const FMatrix ComponentToWorldMatrix = Component->ComponentToWorld.ToMatrixWithScale(); + const FMatrix ComponentToWorldMatrix = Component->GetComponentTransform().ToMatrixWithScale(); const FMatrix ComponentToWorld = (bLocalSpace || EmitterInfo.LocalVectorField.bIgnoreComponentTransform) ? FMatrix::Identity : ComponentToWorldMatrix; const FRotationMatrix VectorFieldTransform(LocalVectorFieldRotation); @@ -3177,7 +3178,7 @@ public: DynamicData->bUseLocalSpace = EmitterInfo.RequiredModule->bUseLocalSpace; // Account for LocalToWorld scaling - FVector ComponentScale = Component->ComponentToWorld.GetScale3D(); + FVector ComponentScale = Component->GetComponentTransform().GetScale3D(); // Figure out if we need to replicate the X channel of size to Y. const bool bSquare = (EmitterInfo.ScreenAlignment == PSA_Square) || (EmitterInfo.ScreenAlignment == PSA_FacingCameraPosition) @@ -4573,6 +4574,15 @@ void FFXSystem::SimulateGPUParticles( static TArray SimulationCommands; static TArray TilesToClear; static TArray NewParticles; + + // One-time register delegate with Trim() so the data above can be freed on demand + static FDelegateHandle Clear = FCoreDelegates::GetMemoryTrimDelegate().AddLambda([]() + { + SimulationCommands.Empty(); + TilesToClear.Empty(); + NewParticles.Empty(); + }); + for (TSparseArray::TIterator It(GPUSimulations); It; ++It) { //SCOPE_CYCLE_COUNTER(STAT_GPUParticleBuildSimCmdsTime); diff --git a/Engine/Source/Runtime/Engine/Private/Particles/ParticleModules.cpp b/Engine/Source/Runtime/Engine/Private/Particles/ParticleModules.cpp index d8ce1f69b2a2..c043da1b6d3d 100644 --- a/Engine/Source/Runtime/Engine/Private/Particles/ParticleModules.cpp +++ b/Engine/Source/Runtime/Engine/Private/Particles/ParticleModules.cpp @@ -2543,7 +2543,7 @@ void UParticleModuleAccelerationConstant::Spawn(FParticleEmitterInstance* Owner, check(LODLevel); if (bAlwaysInWorldSpace && LODLevel->RequiredModule->bUseLocalSpace) { - FVector LocalAcceleration = Owner->Component->ComponentToWorld.InverseTransformVector(Acceleration); + FVector LocalAcceleration = Owner->Component->GetComponentTransform().InverseTransformVector(Acceleration); Particle.Velocity += LocalAcceleration * SpawnTime; Particle.BaseVelocity += LocalAcceleration * SpawnTime; } @@ -2572,7 +2572,7 @@ void UParticleModuleAccelerationConstant::Update(FParticleEmitterInstance* Owner FPlatformMisc::Prefetch(Owner->ParticleData, (Owner->ParticleIndices[0] * Owner->ParticleStride) + PLATFORM_CACHE_LINE_SIZE); if (bAlwaysInWorldSpace && LODLevel->RequiredModule->bUseLocalSpace) { - FTransform Mat = Owner->Component->ComponentToWorld; + FTransform Mat = Owner->Component->GetComponentTransform(); FVector LocalAcceleration = Mat.InverseTransformVector(Acceleration); BEGIN_UPDATE_LOOP; { @@ -2866,14 +2866,14 @@ void UParticleModuleAcceleration::Spawn(FParticleEmitterInstance* Owner, int32 O UsedAcceleration = Acceleration.GetValue(Owner->EmitterTime, Owner->Component); if ((bApplyOwnerScale == true) && Owner && Owner->Component) { - FVector Scale = Owner->Component->ComponentToWorld.GetScale3D(); + FVector Scale = Owner->Component->GetComponentTransform().GetScale3D(); UsedAcceleration *= Scale; } UParticleLODLevel* LODLevel = Owner->SpriteTemplate->GetCurrentLODLevel(Owner); check(LODLevel); if (bAlwaysInWorldSpace && LODLevel->RequiredModule->bUseLocalSpace) { - FVector TempUsedAcceleration = Owner->Component->ComponentToWorld.InverseTransformVector(UsedAcceleration); + FVector TempUsedAcceleration = Owner->Component->GetComponentTransform().InverseTransformVector(UsedAcceleration); Particle.Velocity += TempUsedAcceleration * SpawnTime; Particle.BaseVelocity += TempUsedAcceleration * SpawnTime; } @@ -2901,7 +2901,7 @@ void UParticleModuleAcceleration::Update(FParticleEmitterInstance* Owner, int32 FPlatformMisc::Prefetch(Owner->ParticleData, (Owner->ParticleIndices[0] * Owner->ParticleStride) + PLATFORM_CACHE_LINE_SIZE); if (bAlwaysInWorldSpace && LODLevel->RequiredModule->bUseLocalSpace) { - FTransform Mat = Owner->Component->ComponentToWorld; + FTransform Mat = Owner->Component->GetComponentTransform(); BEGIN_UPDATE_LOOP; { FVector& UsedAcceleration = *((FVector*)(ParticleBase + CurrentOffset)); \ @@ -2991,7 +2991,7 @@ void UParticleModuleAccelerationOverLifetime::Update(FParticleEmitterInstance* O check(LODLevel); if (bAlwaysInWorldSpace && LODLevel->RequiredModule->bUseLocalSpace) { - FTransform Mat = Owner->Component->ComponentToWorld; + FTransform Mat = Owner->Component->GetComponentTransform(); BEGIN_UPDATE_LOOP; // Acceleration should always be in world space... FVector Accel = AccelOverLife.GetValue(Particle.RelativeTime, Owner->Component); @@ -3338,7 +3338,7 @@ void UParticleModuleLight::Render3DPreview(FParticleEmitterInstance* Owner, cons int32 Offset = 0; UParticleLODLevel* LODLevel = Owner->SpriteTemplate->GetCurrentLODLevel(Owner); const bool bLocalSpace = LODLevel->RequiredModule->bUseLocalSpace; - const FVector Scale = Owner->Component->ComponentToWorld.GetScale3D(); + const FVector Scale = Owner->Component->GetComponentTransform().GetScale3D(); const FMatrix LocalToWorld = Owner->EmitterToSimulation * Owner->SimulationToWorld; check(LODLevel); @@ -3607,11 +3607,11 @@ void UParticleModuleKillBox::Update(FParticleEmitterInstance* Owner, int32 Offse if (LODLevel->RequiredModule->bUseLocalSpace) { - Position = Owner->Component->ComponentToWorld.TransformVector(Position); + Position = Owner->Component->GetComponentTransform().TransformVector(Position); } else if ((bAxisAlignedAndFixedSize == false) && (bAbsolute == false)) { - Position = Owner->Component->ComponentToWorld.InverseTransformPosition(Position) + Owner->Component->ComponentToWorld.GetLocation(); + Position = Owner->Component->GetComponentTransform().InverseTransformPosition(Position) + Owner->Component->GetComponentTransform().GetLocation(); } // Determine if the particle is inside the box @@ -3656,7 +3656,7 @@ void UParticleModuleKillBox::Render3DPreview(FParticleEmitterInstance* Owner, co { for (int32 i = 0; i < 8; ++i) { - KillboxVerts[i] = Owner->Component->ComponentToWorld.TransformPosition(KillboxVerts[i]); + KillboxVerts[i] = Owner->Component->GetComponentTransform().TransformPosition(KillboxVerts[i]); } } else @@ -3736,7 +3736,7 @@ void UParticleModuleKillHeight::Update(FParticleEmitterInstance* Owner, int32 Of float CheckHeight = Height.GetValue(Owner->EmitterTime, Owner->Component); if (bApplyPSysScale == true) { - FVector OwnerScale = Owner->Component->ComponentToWorld.GetScale3D(); + FVector OwnerScale = Owner->Component->GetComponentTransform().GetScale3D(); CheckHeight *= OwnerScale.Z; } @@ -3751,7 +3751,7 @@ void UParticleModuleKillHeight::Update(FParticleEmitterInstance* Owner, int32 Of if (LODLevel->RequiredModule->bUseLocalSpace) { - Position = Owner->Component->ComponentToWorld.TransformVector(Position); + Position = Owner->Component->GetComponentTransform().TransformVector(Position); } if ((bFloor == true) && (Position.Z < CheckHeight)) @@ -3780,7 +3780,7 @@ void UParticleModuleKillHeight::Render3DPreview(FParticleEmitterInstance* Owner, float ScaleValue = 1.0f; if (bApplyPSysScale == true) { - FVector OwnerScale = Owner->Component->ComponentToWorld.GetScale3D(); + FVector OwnerScale = Owner->Component->GetComponentTransform().GetScale3D(); ScaleValue = OwnerScale.Z; } CheckHeight *= ScaleValue; @@ -4296,11 +4296,11 @@ void UParticleModuleAttractorParticle::Update(FParticleEmitterInstance* Owner, i { if (bSrcUseLocalSpace) { - SrcLocation = Owner->Component->ComponentToWorld.TransformVector(SrcLocation); + SrcLocation = Owner->Component->GetComponentTransform().TransformVector(SrcLocation); } if (bUseLocalSpace) { - ParticleLocation = Owner->Component->ComponentToWorld.TransformVector(Particle.Location); + ParticleLocation = Owner->Component->GetComponentTransform().TransformVector(Particle.Location); } } @@ -4416,9 +4416,9 @@ void UParticleModuleAttractorPoint::Update(FParticleEmitterInstance* Owner, int3 if ( (LODLevel->RequiredModule->bUseLocalSpace == false) && ( bUseWorldSpacePosition == false ) ) { // Transform the attractor into world space - AttractorPosition = Component->ComponentToWorld.TransformPosition(AttractorPosition); + AttractorPosition = Component->GetComponentTransform().TransformPosition(AttractorPosition); - Scale *= Component->ComponentToWorld.GetScale3D(); + Scale *= Component->GetComponentTransform().GetScale3D(); } float ScaleSize = Scale.Size(); diff --git a/Engine/Source/Runtime/Engine/Private/Particles/ParticleModules_Location.cpp b/Engine/Source/Runtime/Engine/Private/Particles/ParticleModules_Location.cpp index f9d33dc1db31..d5380be9ba95 100644 --- a/Engine/Source/Runtime/Engine/Private/Particles/ParticleModules_Location.cpp +++ b/Engine/Source/Runtime/Engine/Private/Particles/ParticleModules_Location.cpp @@ -232,7 +232,7 @@ void UParticleModuleLocationWorldOffset::SpawnEx(FParticleEmitterInstance* Owner else { // We need to inverse transform the location so that the bUseLocalSpace transform uses the proper value - FMatrix InvMat = Owner->Component->ComponentToWorld.ToMatrixWithScale().InverseFast(); + FMatrix InvMat = Owner->Component->GetComponentTransform().ToMatrixWithScale().InverseFast(); FVector StartLoc = StartLocation.GetValue(Owner->EmitterTime, Owner->Component, 0, InRandomStream); Particle.Location += InvMat.TransformVector(StartLoc); } @@ -339,7 +339,7 @@ void UParticleModuleLocationDirect::Spawn(FParticleEmitterInstance* Owner, int32 else { FVector StartLoc = Location.GetValue(Particle.RelativeTime, Owner->Component); - StartLoc = Owner->Component->ComponentToWorld.TransformPosition(StartLoc); + StartLoc = Owner->Component->GetComponentTransform().TransformPosition(StartLoc); Particle.Location = StartLoc; } @@ -509,12 +509,12 @@ void UParticleModuleLocationEmitter::Spawn(FParticleEmitterInstance* Owner, int3 else if ((bSourceIsInLocalSpace == true) && (bInLocalSpace == false)) { // We need to transform it into world space - Particle.Location = LocationEmitterInst->Component->ComponentToWorld.TransformPosition(pkParticle->Location); + Particle.Location = LocationEmitterInst->Component->GetComponentTransform().TransformPosition(pkParticle->Location); } else //if ((bSourceIsInLocalSpace == false) && (bInLocalSpace == true)) { // We need to transform it into local space - Particle.Location = LocationEmitterInst->Component->ComponentToWorld.InverseTransformPosition(pkParticle->Location); + Particle.Location = LocationEmitterInst->Component->GetComponentTransform().InverseTransformPosition(pkParticle->Location); } } if (InheritSourceVelocity) @@ -1652,7 +1652,7 @@ void UParticleModuleLocationBoneSocket::Spawn(FParticleEmitterInstance* Owner, i PayloadData->Rotation = RotationQuat.Euler(); if (Owner->CurrentLODLevel->RequiredModule->bUseLocalSpace == true) { - PayloadData->Rotation = Owner->Component->ComponentToWorld.InverseTransformVectorNoScale(PayloadData->Rotation); + PayloadData->Rotation = Owner->Component->GetComponentTransform().InverseTransformVectorNoScale(PayloadData->Rotation); } } } @@ -2154,7 +2154,7 @@ bool UParticleModuleLocationBoneSocket::GetParticleLocation(FModuleLocationBoneS if (Owner->CurrentLODLevel->RequiredModule->bUseLocalSpace == true) { - OutPosition = Owner->Component->ComponentToWorld.InverseTransformPosition(OutPosition); + OutPosition = Owner->Component->GetComponentTransform().InverseTransformPosition(OutPosition); } return true; @@ -2445,7 +2445,7 @@ void UParticleModuleLocationSkelVertSurface::Spawn(FParticleEmitterInstance* Own FVector Rot = SourceRotation.Euler(); if (Owner->CurrentLODLevel->RequiredModule->bUseLocalSpace == true) { - Rot = Owner->Component->ComponentToWorld.InverseTransformVectorNoScale(Rot); + Rot = Owner->Component->GetComponentTransform().InverseTransformVectorNoScale(Rot); } PayloadData->Rotation = Rot; PayloadData->InitRotation = Rot; @@ -2809,7 +2809,7 @@ bool UParticleModuleLocationSkelVertSurface::GetParticleLocation(FParticleEmitte if (SourceType == VERTSURFACESOURCE_Vert) { FVector VertPos = InSkelMeshComponent->GetSkinnedVertexPosition(InPrimaryVertexIndex); - OutPosition = InSkelMeshComponent->ComponentToWorld.TransformPosition(VertPos); + OutPosition = InSkelMeshComponent->GetComponentTransform().TransformPosition(VertPos); OutRotation = FQuat::Identity; } else if (SourceType == VERTSURFACESOURCE_Surface) @@ -2821,9 +2821,9 @@ bool UParticleModuleLocationSkelVertSurface::GetParticleLocation(FParticleEmitte VertIndex[0] = LODModel.MultiSizeIndexContainer.GetIndexBuffer()->Get( InPrimaryVertexIndex ); VertIndex[1] = LODModel.MultiSizeIndexContainer.GetIndexBuffer()->Get( InPrimaryVertexIndex+1 ); VertIndex[2] = LODModel.MultiSizeIndexContainer.GetIndexBuffer()->Get( InPrimaryVertexIndex+2 ); - Verts[0] = InSkelMeshComponent->ComponentToWorld.TransformPosition(InSkelMeshComponent->GetSkinnedVertexPosition(VertIndex[0])); - Verts[1] = InSkelMeshComponent->ComponentToWorld.TransformPosition(InSkelMeshComponent->GetSkinnedVertexPosition(VertIndex[1])); - Verts[2] = InSkelMeshComponent->ComponentToWorld.TransformPosition(InSkelMeshComponent->GetSkinnedVertexPosition(VertIndex[2])); + Verts[0] = InSkelMeshComponent->GetComponentTransform().TransformPosition(InSkelMeshComponent->GetSkinnedVertexPosition(VertIndex[0])); + Verts[1] = InSkelMeshComponent->GetComponentTransform().TransformPosition(InSkelMeshComponent->GetSkinnedVertexPosition(VertIndex[1])); + Verts[2] = InSkelMeshComponent->GetComponentTransform().TransformPosition(InSkelMeshComponent->GetSkinnedVertexPosition(VertIndex[2])); FVector V0ToV2 = (Verts[2] - Verts[0]); V0ToV2.Normalize(); @@ -2869,7 +2869,7 @@ bool UParticleModuleLocationSkelVertSurface::GetParticleLocation(FParticleEmitte if (Owner->CurrentLODLevel->RequiredModule->bUseLocalSpace == true) { - OutPosition = Owner->Component->ComponentToWorld.InverseTransformPosition(OutPosition); + OutPosition = Owner->Component->GetComponentTransform().InverseTransformPosition(OutPosition); } OutPosition += UniversalOffset; diff --git a/Engine/Source/Runtime/Engine/Private/Particles/ParticleModules_Velocity.cpp b/Engine/Source/Runtime/Engine/Private/Particles/ParticleModules_Velocity.cpp index 4d01f914d413..00de45eb8863 100644 --- a/Engine/Source/Runtime/Engine/Private/Particles/ParticleModules_Velocity.cpp +++ b/Engine/Source/Runtime/Engine/Private/Particles/ParticleModules_Velocity.cpp @@ -86,7 +86,7 @@ void UParticleModuleVelocity::SpawnEx(FParticleEmitterInstance* Owner, int32 Off FVector OwnerScale(1.0f); if ((bApplyOwnerScale == true) && Owner->Component) { - OwnerScale = Owner->Component->ComponentToWorld.GetScale3D(); + OwnerScale = Owner->Component->GetComponentTransform().GetScale3D(); } UParticleLODLevel* LODLevel = Owner->SpriteTemplate->GetCurrentLODLevel(Owner); @@ -195,7 +195,7 @@ void UParticleModuleVelocityInheritParent::Spawn(FParticleEmitterInstance* Owner check(LODLevel); if (LODLevel->RequiredModule->bUseLocalSpace) { - Vel = Owner->Component->ComponentToWorld.InverseTransformVector(Owner->Component->PartSysVelocity); + Vel = Owner->Component->GetComponentTransform().InverseTransformVector(Owner->Component->PartSysVelocity); } else { @@ -255,7 +255,7 @@ void UParticleModuleVelocityOverLifetime::Spawn(FParticleEmitterInstance* Owner, FVector OwnerScale(1.0f); if ((bApplyOwnerScale == true) && Owner && Owner->Component) { - OwnerScale = Owner->Component->ComponentToWorld.GetScale3D(); + OwnerScale = Owner->Component->GetComponentTransform().GetScale3D(); } FVector Vel = VelOverLife.GetValue(Particle.RelativeTime, Owner->Component) * OwnerScale; Particle.Velocity = Vel; @@ -270,7 +270,7 @@ void UParticleModuleVelocityOverLifetime::Update(FParticleEmitterInstance* Owner check(LODLevel); FVector OwnerScale(1.0f); const FTransform& OwnerTM = Owner->Component->GetAsyncComponentToWorld(); - if ((bApplyOwnerScale == true) && Owner->Component) + if (bApplyOwnerScale == true) { OwnerScale = OwnerTM.GetScale3D(); } @@ -431,7 +431,7 @@ void UParticleModuleVelocityCone::SpawnEx(FParticleEmitterInstance* Owner, int32 FVector OwnerScale(1.0f); if ((bApplyOwnerScale == true) && Owner->Component) { - OwnerScale = Owner->Component->ComponentToWorld.GetScale3D(); + OwnerScale = Owner->Component->GetComponentTransform().GetScale3D(); } // Spawn particles @@ -471,11 +471,11 @@ void UParticleModuleVelocityCone::SpawnEx(FParticleEmitterInstance* Owner, int32 // Transform according to world and local space flags if (!LODLevel->RequiredModule->bUseLocalSpace && !bInWorldSpace) { - SpawnDirection = Owner->Component->ComponentToWorld.TransformVector(SpawnDirection); + SpawnDirection = Owner->Component->GetComponentTransform().TransformVector(SpawnDirection); } else if (LODLevel->RequiredModule->bUseLocalSpace && bInWorldSpace) { - SpawnDirection = Owner->Component->ComponentToWorld.InverseTransformVector(SpawnDirection); + SpawnDirection = Owner->Component->GetComponentTransform().InverseTransformVector(SpawnDirection); } // Set final velocity vector @@ -548,13 +548,13 @@ void UParticleModuleVelocityCone::Render3DPreview(FParticleEmitterInstance* Owne { if (bApplyOwnerScale == true) { - OwnerScale = Owner->Component->ComponentToWorld.GetScale3D(); + OwnerScale = Owner->Component->GetComponentTransform().GetScale3D(); } OwnerRotation = FQuatRotationMatrix(Actor->GetActorQuat()); } - LocalToWorldOrigin = Owner->Component->ComponentToWorld.GetLocation(); - LocalToWorld = Owner->Component->ComponentToWorld.ToMatrixWithScale().RemoveTranslation(); + LocalToWorldOrigin = Owner->Component->GetComponentTransform().GetLocation(); + LocalToWorld = Owner->Component->GetComponentTransform().ToMatrixWithScale().RemoveTranslation(); LocalToWorld.RemoveScaling(); } FMatrix Transform; diff --git a/Engine/Source/Runtime/Engine/Private/Particles/ParticleSystemRender.cpp b/Engine/Source/Runtime/Engine/Private/Particles/ParticleSystemRender.cpp index 0ed8d15e2252..bb02fe7a99f6 100644 --- a/Engine/Source/Runtime/Engine/Private/Particles/ParticleSystemRender.cpp +++ b/Engine/Source/Runtime/Engine/Private/Particles/ParticleSystemRender.cpp @@ -1102,7 +1102,7 @@ void FDynamicSpriteEmitterData::GetDynamicMeshElementsEmitter(const FParticleSys FParticleOrder* ParticleOrder = NULL; if (bSort) { - ParticleOrder = (FParticleOrder*)FMemStack::Get().Alloc(sizeof(FParticleOrder)* ParticleCount, ALIGNOF(FParticleOrder)); + ParticleOrder = (FParticleOrder*)FMemStack::Get().Alloc(sizeof(FParticleOrder)* ParticleCount, alignof(FParticleOrder)); SortSpriteParticles(SourceData->SortMode, SourceData->bUseLocalSpace, SourceData->ActiveParticleCount, SourceData->DataContainer.ParticleData, SourceData->ParticleStride, SourceData->DataContainer.ParticleIndices, View, Proxy->GetLocalToWorld(), ParticleOrder); @@ -1573,6 +1573,21 @@ void FDynamicMeshEmitterData::GetDynamicMeshElementsEmitter(const FParticleSyste FDynamicMeshEmitterCollectorResources& CollectorResources = Collector.AllocateOneFrameResource(); CollectorResources.VertexFactory = MeshVertexFactory; + const FDynamicSpriteEmitterReplayDataBase* SourceData = GetSourceData(); + FMeshParticleUniformParameters UniformParameters; + UniformParameters.SubImageSize = FVector4( + 1.0f / (SourceData ? SourceData->SubImages_Horizontal : 1), + 1.0f / (SourceData ? SourceData->SubImages_Vertical : 1), + 0, 0); + + // A weight is used to determine whether the mesh texture coordinates or SubUVs are passed from the vertex shader to the pixel shader. + const uint32 TexCoordWeight = (SourceData && SourceData->SubUVDataOffset > 0) ? 1 : 0; + UniformParameters.TexCoordWeightA = TexCoordWeight; + UniformParameters.TexCoordWeightB = 1 - TexCoordWeight; + UniformParameters.PrevTransformAvailable = Source.MeshMotionBlurOffset ? 1 : 0; + + CollectorResources.UniformBuffer = FMeshParticleUniformBufferRef::CreateUniformBufferImmediate(UniformParameters, UniformBuffer_SingleFrame); + MeshVertexFactory->SetUniformBuffer(CollectorResources.UniformBuffer); // For OpenGL & Metal we can't assume that it is OK to leave the PrevTransformBuffer buffer unbound. // Doing so can lead to undefined behaviour if the buffer is referenced in the shader even if protected by a branch that is not meant to be taken. @@ -1636,23 +1651,6 @@ void FDynamicMeshEmitterData::GetDynamicMeshElementsEmitter(const FParticleSyste if (Allocation.IsValid() && (!bUsesDynamicParameter || DynamicParameterAllocation.IsValid())) { - const FDynamicSpriteEmitterReplayDataBase* SourceData = GetSourceData(); - FMeshParticleUniformParameters UniformParameters; - UniformParameters.SubImageSize = FVector4( - 1.0f / (SourceData ? SourceData->SubImages_Horizontal : 1), - 1.0f / (SourceData ? SourceData->SubImages_Vertical : 1), - 0, 0); - - // A weight is used to determine whether the mesh texture coordinates or SubUVs are passed from the vertex shader to the pixel shader. - const uint32 TexCoordWeight = (SourceData && SourceData->SubUVDataOffset > 0) ? 1 : 0; - UniformParameters.TexCoordWeightA = TexCoordWeight; - UniformParameters.TexCoordWeightB = 1 - TexCoordWeight; - UniformParameters.PrevTransformAvailable = Source.MeshMotionBlurOffset ? 1 : 0; - - CollectorResources.UniformBuffer = FMeshParticleUniformBufferRef::CreateUniformBufferImmediate(UniformParameters, UniformBuffer_SingleFrame); - MeshVertexFactory->SetUniformBuffer(CollectorResources.UniformBuffer); - - // Fill instance buffer. if (Collector.ShouldUseTasks()) { @@ -1741,10 +1739,14 @@ void FDynamicMeshEmitterData::GetDynamicMeshElementsEmitter(const FParticleSyste { for (int32 SectionIndex = 0; SectionIndex < LODModel.Sections.Num(); SectionIndex++) { - FMaterialRenderProxy* MaterialProxy = MeshMaterials[SectionIndex]->GetRenderProxy(bSelected); + FMaterialRenderProxy* MaterialProxy = nullptr; + if (SectionIndex < MeshMaterials.Num() && MeshMaterials[SectionIndex]) + { + MaterialProxy = MeshMaterials[SectionIndex]->GetRenderProxy(bSelected); + } const FStaticMeshSection& Section = LODModel.Sections[SectionIndex]; - if ((Section.NumTriangles == 0) || (MaterialProxy == NULL)) + if ((Section.NumTriangles == 0) || (MaterialProxy == nullptr)) { //@todo. This should never occur, but it does occasionally. continue; diff --git a/Engine/Source/Runtime/Engine/Private/Particles/ParticleTrail2EmitterInstance.cpp b/Engine/Source/Runtime/Engine/Private/Particles/ParticleTrail2EmitterInstance.cpp index a9befcc20aaa..8f6cfa1173a8 100644 --- a/Engine/Source/Runtime/Engine/Private/Particles/ParticleTrail2EmitterInstance.cpp +++ b/Engine/Source/Runtime/Engine/Private/Particles/ParticleTrail2EmitterInstance.cpp @@ -186,7 +186,7 @@ void FParticleTrailsEmitterInstance_Base::UpdateBoundingBox(float DeltaTime) ParticleBoundingBox.IsValid = true; // Take scale into account - FVector Scale = Component->ComponentToWorld.GetScale3D(); + FVector Scale = Component->GetComponentTransform().GetScale3D(); // As well as each particle int32 LocalActiveParticles = ActiveParticles; @@ -240,7 +240,7 @@ void FParticleTrailsEmitterInstance_Base::UpdateBoundingBox(float DeltaTime) { if (LODLevel->RequiredModule->bUseLocalSpace) { - ParticleBoundingBox = ParticleBoundingBox.TransformBy(Component->ComponentToWorld); + ParticleBoundingBox = ParticleBoundingBox.TransformBy(Component->GetComponentTransform()); } } } @@ -272,7 +272,7 @@ void FParticleTrailsEmitterInstance_Base::ForceUpdateBoundingBox() ParticleBoundingBox.IsValid = true; // Take scale into account - FVector Scale = Component->ComponentToWorld.GetScale3D(); + FVector Scale = Component->GetComponentTransform().GetScale3D(); // As well as each particle int32 LocalActiveParticles = ActiveParticles; @@ -299,7 +299,7 @@ void FParticleTrailsEmitterInstance_Base::ForceUpdateBoundingBox() // Transform bounding box into world space if the emitter uses a local space coordinate system. if (LODLevel->RequiredModule->bUseLocalSpace) { - ParticleBoundingBox = ParticleBoundingBox.TransformBy(Component->ComponentToWorld); + ParticleBoundingBox = ParticleBoundingBox.TransformBy(Component->GetComponentTransform()); } } } @@ -1294,7 +1294,7 @@ float FParticleRibbonEmitterInstance::Spawn(float DeltaTime) FVector CurrentUp; if (TrailTypeData->RenderAxis == Trails_SourceUp) { - CurrentUp = Component->ComponentToWorld.GetScaledAxis( EAxis::Z ); + CurrentUp = Component->GetComponentTransform().GetScaledAxis( EAxis::Z ); } else { @@ -1432,7 +1432,7 @@ float FParticleRibbonEmitterInstance::Spawn(float DeltaTime) FString ErrorMessage = FString::Printf(TEXT("Ribbon with too many particles: %5d vs. %5d, %s"), ActiveParticles, LocalMaxParticleInTrailCount, - Component ? Component->Template ? *(Component->Template->GetName()) : TEXT("No template") : TEXT("No component")); + Component->Template ? *Component->Template->GetName() : TEXT("No template")); FColor ErrorColor(255,0,0); GEngine->AddOnScreenDebugMessage((uint64)((PTRINT)this), 5.0f, ErrorColor,ErrorMessage); UE_LOG(LogParticles, Log, TEXT("%s"), *ErrorMessage); @@ -1768,7 +1768,7 @@ bool FParticleRibbonEmitterInstance::Spawn_Source(float DeltaTime) float InvCount = 1.0f / MovementSpawnCount; float Increment = DeltaTime / MovementSpawnCount; - FTransform SavedComponentToWorld = Component->ComponentToWorld; + FTransform SavedComponentToWorld = Component->GetComponentTransform(); // Spawn the given number of particles, interpolating between the current and last position/tangent float CurrTimeStep = InvCount; @@ -1805,7 +1805,7 @@ bool FParticleRibbonEmitterInstance::Spawn_Source(float DeltaTime) float SpawnTime = DeltaTime - (SpawnIdx * Increment); float TrueSpawnTime = Diff * TimeStep; - Component->ComponentToWorld = FTransform(CurrRotation, CurrPosition); + Component->SetComponentToWorld(FTransform(CurrRotation, CurrPosition)); // Standard spawn setup PreSpawn(Particle, CurrPosition, FVector::ZeroVector); @@ -1835,7 +1835,7 @@ bool FParticleRibbonEmitterInstance::Spawn_Source(float DeltaTime) Particle->Size.Z = Particle->Size.Z; Particle->BaseSize = Particle->Size; - Component->ComponentToWorld = SavedComponentToWorld; + Component->SetComponentToWorld(SavedComponentToWorld); // Trail specific... // Clear the next and previous - just to be safe @@ -2326,7 +2326,7 @@ bool FParticleRibbonEmitterInstance::ResolveSourcePoint(int32 InTrailIdx, } OutTangentStrength = OutTangent.SizeSquared(); //@todo. Allow particle rotation to define up?? - OutUp = SourceEmitter->Component->ComponentToWorld.GetScaledAxis(EAxis::Z); + OutUp = SourceEmitter->Component->GetComponentTransform().GetScaledAxis(EAxis::Z); //@todo. Where to get rotation from???? OutRotation = FQuat(0,0,0,1); @@ -2374,7 +2374,7 @@ bool FParticleRibbonEmitterInstance::ResolveSourcePoint(int32 InTrailIdx, if (CurrentLODLevel && (CurrentLODLevel->RequiredModule->bUseLocalSpace == false)) { // Transform it - SourceOffsetValue = Component->ComponentToWorld.TransformVector(SourceOffsetValue); + SourceOffsetValue = Component->GetComponentTransform().TransformVector(SourceOffsetValue); } OutPosition += SourceOffsetValue; } @@ -2382,7 +2382,7 @@ bool FParticleRibbonEmitterInstance::ResolveSourcePoint(int32 InTrailIdx, OutRotation = Component->GetComponentQuat(); OutTangent = Component->PartSysVelocity; OutTangentStrength = OutTangent.SizeSquared(); - OutUp = Component->ComponentToWorld.GetScaledAxis(EAxis::Z); + OutUp = Component->GetComponentTransform().GetScaledAxis(EAxis::Z); bSourceWasSet = true; } @@ -2776,8 +2776,7 @@ bool FParticleRibbonEmitterInstance::FillReplayData(FDynamicEmitterReplayDataBas FString ErrorMessage = FString::Printf(TEXT("RIBBON: GetDynamicData -- TriangleCount == %d (APC = %4d) for PSys %s"), TriangleCount, ActiveParticles, - Component ? (Component->Template ? *Component->Template->GetName() : - TEXT("No Template")) : TEXT("No Component")); + Component->Template ? *Component->Template->GetName() : TEXT("No Template")); FColor ErrorColor(255,0,0); GEngine->AddOnScreenDebugMessage((uint64)((PTRINT)this), 5.0f, ErrorColor,ErrorMessage); UE_LOG(LogParticles, Log, TEXT("%s"), *ErrorMessage); @@ -3009,7 +3008,7 @@ struct FAnimTrailParticleSpawnParams //TODO - These params are for interpolated spawn particles which are currently disabled. - ///** The ComponentToWorld transform of the particle component before spawning began. */ + ///** The GetComponentTransform() transform of the particle component before spawning began. */ //FTransform SavedComponentToWorld; ///** True if this particle is interpolated. False otherwise. */ //bool bInterpolated; @@ -3038,7 +3037,7 @@ void FParticleAnimTrailEmitterInstance::SpawnParticle( int32& StartParticleIndex // FVector InterpSourcePos = FMath::Lerp(PreviousComponentTransform.GetLocation(), Params.SavedComponentToWorld.GetLocation(), InterpFactor); // FQuat InterpSourceRot = FQuat::Slerp(PreviousComponentTransform.GetRotation(), Params.SavedComponentToWorld.GetRotation(), InterpFactor); // FTransform InterpSourceTransform = FTransform(InterpSourceRot, InterpSourcePos); -// Component->ComponentToWorld = InterpSourceTransform; +// Component->GetComponentTransform() = InterpSourceTransform; // } //TODO - Multiple trails. @@ -3419,8 +3418,8 @@ float FParticleAnimTrailEmitterInstance::Spawn(float DeltaTime) TrailSpawnTimes[TrailIdx] = RunningTime; //TODO - If I enable interpolated spawning then the component transform needs restoring and storing. - //Component->ComponentToWorld = SpawnParams.SavedComponentToWorld; - //PreviousComponentTransform = Component->ComponentToWorld; + //Component->GetComponentTransform() = SpawnParams.SavedComponentToWorld; + //PreviousComponentTransform = Component->GetComponentTransform(); if (bTagTrailAsDead == true) { @@ -3523,7 +3522,7 @@ void FParticleAnimTrailEmitterInstance::UpdateBoundingBox(float DeltaTime) ParticleBoundingBox.IsValid = true; // Take scale into account - FVector Scale = Component->ComponentToWorld.GetScale3D(); + FVector Scale = Component->GetComponentTransform().GetScale3D(); // As well as each particle int32 LocalActiveParticles = ActiveParticles; @@ -3594,7 +3593,7 @@ void FParticleAnimTrailEmitterInstance::UpdateBoundingBox(float DeltaTime) { if (LODLevel->RequiredModule->bUseLocalSpace) { - ParticleBoundingBox = ParticleBoundingBox.TransformBy(Component->ComponentToWorld); + ParticleBoundingBox = ParticleBoundingBox.TransformBy(Component->GetComponentTransform()); } } } @@ -3626,7 +3625,7 @@ void FParticleAnimTrailEmitterInstance::ForceUpdateBoundingBox() ParticleBoundingBox.IsValid = true; // Take scale into account - FVector Scale = Component->ComponentToWorld.GetScale3D(); + FVector Scale = Component->GetComponentTransform().GetScale3D(); // As well as each particle int32 LocalActiveParticles = ActiveParticles; @@ -3678,7 +3677,7 @@ void FParticleAnimTrailEmitterInstance::ForceUpdateBoundingBox() // Transform bounding box into world space if the emitter uses a local space coordinate system. if (LODLevel->RequiredModule->bUseLocalSpace) { - ParticleBoundingBox = ParticleBoundingBox.TransformBy(Component->ComponentToWorld); + ParticleBoundingBox = ParticleBoundingBox.TransformBy(Component->GetComponentTransform()); } } } @@ -4126,8 +4125,7 @@ bool FParticleAnimTrailEmitterInstance::FillReplayData( FDynamicEmitterReplayDat FString ErrorMessage = FString::Printf(TEXT("ANIMTRAIL: GetDynamicData -- TriangleCount == 0 (APC = %4d) for PSys %s"), ActiveParticles, - Component ? (Component->Template ? *Component->Template->GetName() : - TEXT("No Template")) : TEXT("No Component")); + Component->Template ? *Component->Template->GetName() : TEXT("No Template")); FColor ErrorColor(255,0,0); GEngine->AddOnScreenDebugMessage((uint64)((PTRINT)this), 5.0f, ErrorColor,ErrorMessage); UE_LOG(LogParticles, Log, TEXT("%s"), *ErrorMessage); diff --git a/Engine/Source/Runtime/Engine/Private/Pawn.cpp b/Engine/Source/Runtime/Engine/Private/Pawn.cpp index 060e9aebe0cd..353ea3fe7ea8 100644 --- a/Engine/Source/Runtime/Engine/Private/Pawn.cpp +++ b/Engine/Source/Runtime/Engine/Private/Pawn.cpp @@ -105,17 +105,19 @@ void APawn::PostInitializeComponents() GetWorld()->AddPawn( this ); // Automatically add Controller to AI Pawns if we are allowed to. - if (AutoPossessPlayer == EAutoReceiveInput::Disabled) + if (AutoPossessPlayer == EAutoReceiveInput::Disabled + && AutoPossessAI != EAutoPossessAI::Disabled && Controller == NULL && GetNetMode() != NM_Client +#if WITH_EDITOR + && (GIsEditor == false || GetWorld()->IsGameWorld()) +#endif // WITH_EDITOR + ) { - if (AutoPossessAI != EAutoPossessAI::Disabled && Controller == NULL && GetNetMode() != NM_Client) + const bool bPlacedInWorld = (GetWorld()->bStartup); + if ((AutoPossessAI == EAutoPossessAI::PlacedInWorldOrSpawned) || + (AutoPossessAI == EAutoPossessAI::PlacedInWorld && bPlacedInWorld) || + (AutoPossessAI == EAutoPossessAI::Spawned && !bPlacedInWorld)) { - const bool bPlacedInWorld = (GetWorld()->bStartup); - if ((AutoPossessAI == EAutoPossessAI::PlacedInWorldOrSpawned) || - (AutoPossessAI == EAutoPossessAI::PlacedInWorld && bPlacedInWorld) || - (AutoPossessAI == EAutoPossessAI::Spawned && !bPlacedInWorld)) - { - SpawnDefaultController(); - } + SpawnDefaultController(); } } diff --git a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/BodyInstance.cpp b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/BodyInstance.cpp index af825f374339..1fb5191db81a 100644 --- a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/BodyInstance.cpp +++ b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/BodyInstance.cpp @@ -1422,7 +1422,7 @@ struct FInitBodiesHelper return PNewDynamic; } - bool CreateShapes_PhysX_AssumesLocked(FBodyInstance* Instance, physx::PxRigidActor* PNewDynamic) const + bool CreateShapes_PhysX_AssumesLocked(FBodyInstance* Instance, physx::PxRigidActor* PNewDynamic, bool bKinematicTargetForSQ) const { UPhysicalMaterial* SimplePhysMat = Instance->GetSimplePhysicalMaterial(); TArray ComplexPhysMats = Instance->GetComplexPhysicalMaterials(); @@ -1439,7 +1439,7 @@ struct FInitBodiesHelper { ModifyRigidBodyFlag(ShapeData.SyncBodyFlags, true); } - ModifyRigidBodyFlag(ShapeData.SyncBodyFlags, true); + ModifyRigidBodyFlag(ShapeData.SyncBodyFlags, bKinematicTargetForSQ); } bool bInitFail = false; @@ -1567,7 +1567,7 @@ struct FInitBodiesHelper if (!bFoundBinaryData) { PNewDynamic = CreateActor_PhysX_AssumesLocked(Instance, U2PTransform(Transform)); - const bool bInitFail = CreateShapes_PhysX_AssumesLocked(Instance, PNewDynamic); + const bool bInitFail = CreateShapes_PhysX_AssumesLocked(Instance, PNewDynamic, SpawnParams.bKinematicTargetsUpdateSQ); if (bInitFail) { @@ -1947,8 +1947,18 @@ struct FInitBodiesHelper FBodyInstance::FInitBodySpawnParams::FInitBodySpawnParams(const UPrimitiveComponent* PrimComp) { bStaticPhysics = PrimComp == nullptr || PrimComp->Mobility != EComponentMobility::Movable; - bPhysicsTypeDeterminesSimulation = PrimComp && PrimComp->IsA(); DynamicActorScene = EDynamicActorScene::Default; + + if(const USkeletalMeshComponent* SKOwner = Cast(PrimComp)) + { + bPhysicsTypeDeterminesSimulation = true; + bKinematicTargetsUpdateSQ = !SKOwner->bDeferMovementFromSceneQueries; + } + else + { + bPhysicsTypeDeterminesSimulation = false; + bKinematicTargetsUpdateSQ = true; + } } void FBodyInstance::InitBody(class UBodySetup* Setup, const FTransform& Transform, class UPrimitiveComponent* PrimComp, class FPhysScene* InRBScene, const FInitBodySpawnParams& SpawnParams, PhysXAggregateType InAggregate /*= NULL*/) @@ -3417,7 +3427,7 @@ int32 FBodyInstance::GetSceneIndex(int32 SceneType /* = -1 */) const return -1; } -PxRigidActor* FBodyInstance::GetPxRigidActor_AssumesLocked(int32 SceneType) const +PxRigidActor* FBodyInstance::GetPxRigidActorFromScene_AssumesLocked(int32 SceneType) const { // Negative scene type means to return whichever is not NULL, preferring the sync scene. if( SceneType < 0 ) @@ -4408,6 +4418,7 @@ FString FBodyInstance::GetBodyDebugName() const bool FBodyInstance::LineTrace(struct FHitResult& OutHit, const FVector& Start, const FVector& End, bool bTraceComplex, bool bReturnPhysicalMaterial) const { + SCOPE_CYCLE_COUNTER(STAT_Collision_SceneQueryTotal); SCOPE_CYCLE_COUNTER(STAT_Collision_FBodyInstance_LineTrace); OutHit.TraceStart = Start; @@ -4549,7 +4560,7 @@ bool FBodyInstance::InternalSweepPhysX(struct FHitResult& OutHit, const FVector& UPrimitiveComponent* OwnerComponentInst = OwnerComponent.Get(); PxTransform PStartTM(U2PVector(Start), ShapeAdaptor.GetGeomOrientation()); - PxTransform PCompTM(U2PTransform(OwnerComponentInst->ComponentToWorld)); + PxTransform PCompTM(U2PTransform(OwnerComponentInst->GetComponentTransform())); PxVec3 PDir = U2PVector(Delta/DeltaMag); @@ -4706,11 +4717,10 @@ bool FBodyInstance::OverlapTestForBodiesImpl(const FVector& Pos, const FQuat& Ro } // Calc shape global pose - const PxGeometry& PGeom = PTargetShape->getGeometry().any(); PxTransform PShapeGlobalPose = PTestGlobalPose.transform(PTargetShape->getLocalPose()); for (const FBodyInstance* BodyInstance : Bodies) { - bHaveOverlap = BodyInstance->OverlapPhysX_AssumesLocked(PGeom, PShapeGlobalPose); + bHaveOverlap = BodyInstance->OverlapPhysX_AssumesLocked(PTargetShape->getGeometry().any(), PShapeGlobalPose); if (bHaveOverlap) { return; @@ -4729,6 +4739,7 @@ template bool FBodyInstance::OverlapTestForBodiesImpl(const FVector& Pos, const bool FBodyInstance::OverlapTest(const FVector& Position, const FQuat& Rotation, const struct FCollisionShape& CollisionShape, FMTDResult* OutMTD) const { + SCOPE_CYCLE_COUNTER(STAT_Collision_SceneQueryTotal); SCOPE_CYCLE_COUNTER(STAT_Collision_FBodyInstance_OverlapTest); bool bHasOverlap = false; @@ -4768,8 +4779,9 @@ FTransform RootSpaceToWeldedSpace(const FBodyInstance* BI, const FTransform& Roo return RootTM; } -bool FBodyInstance::OverlapMulti(TArray& InOutOverlaps, const class UWorld* World, const FTransform* pWorldToComponent, const FVector& Pos, const FQuat& Quat, ECollisionChannel TestChannel, const struct FComponentQueryParams& Params, const struct FCollisionResponseParams& ResponseParams, const struct FCollisionObjectQueryParams& ObjectQueryParams) const +bool FBodyInstance::OverlapMulti(TArray& InOutOverlaps, const class UWorld* World, const FTransform* pWorldToComponent, const FVector& Pos, const FQuat& Quat, ECollisionChannel TestChannel, const struct FComponentQueryParams& Params, const struct FCollisionResponseParams& ResponseParams, const FCollisionObjectQueryParams& ObjectQueryParams) const { + SCOPE_CYCLE_COUNTER(STAT_Collision_SceneQueryTotal); SCOPE_CYCLE_COUNTER(STAT_Collision_FBodyInstance_OverlapMulti); if ( !IsValidBodyInstance() && (!WeldParent || !WeldParent->IsValidBodyInstance())) diff --git a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/BodySetup.cpp b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/BodySetup.cpp index 40df472a8cfe..17429f29baa5 100644 --- a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/BodySetup.cpp +++ b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/BodySetup.cpp @@ -20,16 +20,20 @@ #include "DerivedDataCacheInterface.h" #include "UObject/UObjectIterator.h" #include "UObject/PropertyPortFlags.h" +#include "Components/SplineMeshComponent.h" #if WITH_PHYSX #include "PhysXPublic.h" #include "PhysicsEngine/PhysXSupport.h" #endif // WITH_PHYSX -#if WITH_PHYSX && (WITH_RUNTIME_PHYSICS_COOKING || WITH_EDITOR) - #include "IPhysXFormat.h" +#include "ModuleManager.h" +#if WITH_PHYSX + #include "IPhysXCookingModule.h" + #include "IPhysXCooking.h" #endif + #include "PhysicsEngine/PhysDerivedData.h" #include "PhysicalMaterials/PhysicalMaterial.h" #include "ProfilingDebugging/CookStats.h" @@ -46,6 +50,22 @@ namespace PhysXBodySetupCookStats } #endif +IPhysXCookingModule* GetPhysXCookingModule() +{ + check(IsInGameThread()); +#if WITH_PHYSX_COOKING + return FModuleManager::LoadModulePtr("PhysXCooking"); //in some configurations (for example the editor) we must have physx cooking +#else + return FModuleManager::LoadModulePtr("RuntimePhysXCooking"); //in some configurations (mobile) we can choose to opt in for physx cooking via plugin +#endif +} + +bool IsRuntimeCookingEnabled() +{ + return FModuleManager::LoadModulePtr("RuntimePhysXCooking") != nullptr; +} + + #if WITH_PHYSX // Quaternion that converts Sphyls from UE space to PhysX space (negate Y, swap X & Z) // This is equivalent to a 180 degree rotation around the normalized (1, 0, 1) axis @@ -150,6 +170,156 @@ void UBodySetup::AddCollisionFrom(const FKAggregateGeom& FromAggGeom) } } +void UBodySetup::GetCookInfo(FCookBodySetupInfo& OutCookInfo, EPhysXMeshCookFlags InCookFlags) const +{ + check(IsInGameThread()); + + OutCookInfo.OuterDebugName = GetOuter()->GetPathName(); + + // Cook convex meshes, but only if we are not forcing complex collision to be used as simple collision as well + if (GetCollisionTraceFlag() != CTF_UseComplexAsSimple && AggGeom.ConvexElems.Num() > 0) + { + OutCookInfo.bCookNonMirroredConvex = bGenerateNonMirroredCollision; + OutCookInfo.bCookMirroredConvex = bGenerateMirroredCollision; + for (int32 ElementIndex = 0; ElementIndex < AggGeom.ConvexElems.Num(); ElementIndex++) + { + const FKConvexElem& ConvexElem = AggGeom.ConvexElems[ElementIndex]; + const int32 NumVertices = ConvexElem.VertexData.Num(); + + TArray* NonMirroredConvexVertices = nullptr; + TArray* MirroredConvexVertices = nullptr; + + if (bGenerateNonMirroredCollision) + { + OutCookInfo.NonMirroredConvexVertices.AddDefaulted(); + NonMirroredConvexVertices = &OutCookInfo.NonMirroredConvexVertices.Last(); + NonMirroredConvexVertices->AddUninitialized(NumVertices); + } + + if (bGenerateMirroredCollision) + { + OutCookInfo.MirroredConvexVertices.AddDefaulted(); + MirroredConvexVertices = &OutCookInfo.MirroredConvexVertices.Last(); + MirroredConvexVertices->AddUninitialized(NumVertices); + } + + FTransform ConvexTransform = ConvexElem.GetTransform(); + if (!ConvexTransform.IsValid()) + { + UE_LOG(LogPhysics, Warning, TEXT("UBodySetup::GetCookInfoConvex: [%s] ConvexElem[%d] has invalid transform"), *GetPathNameSafe(GetOuter()), ElementIndex); + ConvexTransform = FTransform::Identity; + } + + // Transform verts from element to body space, and mirror if desired + for (int32 VertIdx = 0; VertIdx< NumVertices; VertIdx++) + { + FVector BodySpaceVert = ConvexTransform.TransformPosition(ConvexElem.VertexData[VertIdx]); + if (NonMirroredConvexVertices) + { + (*NonMirroredConvexVertices)[VertIdx] = BodySpaceVert; + } + + if (MirroredConvexVertices) + { + (*MirroredConvexVertices)[VertIdx] = BodySpaceVert * FVector(-1, 1, 1); + } + } + + // Get cook flags to use + OutCookInfo.ConvexCookFlags = InCookFlags; + OutCookInfo.bConvexDeformableMesh = GetOuter()->IsA(USplineMeshComponent::StaticClass()); + if (OutCookInfo.bConvexDeformableMesh) + { + OutCookInfo.ConvexCookFlags |= EPhysXMeshCookFlags::DeformableMesh; + } + } + } + else + { + OutCookInfo.bCookNonMirroredConvex = false; + OutCookInfo.bCookMirroredConvex = false; + } + + // Cook trimesh, but only if we do not force simple collision to be used as complex collision as well + const bool bUsingAllTriData = bMeshCollideAll; + OutCookInfo.bCookTriMesh = false; + OutCookInfo.bTriMeshError = false; + + IInterface_CollisionDataProvider* CDP = Cast(GetOuter()); + if (GetCollisionTraceFlag() != CTF_UseSimpleAsComplex && CDP && CDP->ContainsPhysicsTriMeshData(bUsingAllTriData)) + { + OutCookInfo.bCookTriMesh = true; + const bool bHaveTriMeshData = CDP->GetPhysicsTriMeshData(&OutCookInfo.TriangleMeshDesc, bUsingAllTriData); + const FTriMeshCollisionData& TriangleMeshDesc = OutCookInfo.TriangleMeshDesc; + + if (bHaveTriMeshData) + { + // If any of the below checks gets hit this usually means + // IInterface_CollisionDataProvider::ContainsPhysicsTriMeshData did not work properly. + const int32 NumIndices = TriangleMeshDesc.Indices.Num(); + const int32 NumVerts = TriangleMeshDesc.Vertices.Num(); + if (NumIndices == 0 || NumVerts == 0 || TriangleMeshDesc.MaterialIndices.Num() > NumIndices) + { + UE_LOG(LogPhysics, Warning, TEXT("UBodySetup::GetCookInfo: Triangle data from '%s' invalid (%d verts, %d indices)."), *((UObject*)CDP)->GetPathName(), NumVerts, NumIndices); + OutCookInfo.bTriMeshError = true; + } + + // Set up cooking flags + EPhysXMeshCookFlags CookFlags = InCookFlags; + + if (TriangleMeshDesc.bDeformableMesh) + { + CookFlags |= EPhysXMeshCookFlags::DeformableMesh; + } + + if (TriangleMeshDesc.bFastCook) + { + CookFlags |= EPhysXMeshCookFlags::FastCook; + } + + OutCookInfo.TriMeshCookFlags = CookFlags; + } + } + + OutCookInfo.bSupportUVFromHitResults = UPhysicsSettings::Get()->bSupportUVFromHitResults; +} + +void FBodySetupUVInfo::FillFromTriMesh(const FTriMeshCollisionData& TriangleMeshDesc) +{ + // Store index buffer + const int32 NumVerts = TriangleMeshDesc.Vertices.Num(); + const int32 NumTris = TriangleMeshDesc.Indices.Num(); + IndexBuffer.Empty(); + IndexBuffer.AddUninitialized(NumTris * 3); + for (int32 TriIdx = 0; TriIdx < TriangleMeshDesc.Indices.Num(); TriIdx++) + { + IndexBuffer[TriIdx * 3 + 0] = TriangleMeshDesc.Indices[TriIdx].v0; + IndexBuffer[TriIdx * 3 + 1] = TriangleMeshDesc.Indices[TriIdx].v1; + IndexBuffer[TriIdx * 3 + 2] = TriangleMeshDesc.Indices[TriIdx].v2; + } + + // Store vertex positions + VertPositions.Empty(); + VertPositions.AddUninitialized(NumVerts); + for (int32 VertIdx = 0; VertIdx < TriangleMeshDesc.Vertices.Num(); VertIdx++) + { + VertPositions[VertIdx] = TriangleMeshDesc.Vertices[VertIdx]; + } + + // Copy UV channels (checking they are correct size) + for (int32 UVIndex = 0; UVIndex < TriangleMeshDesc.UVs.Num(); UVIndex++) + { + if (TriangleMeshDesc.UVs[UVIndex].Num() == NumVerts) + { + VertUVs.Add(TriangleMeshDesc.UVs[UVIndex]); + } + else + { + break; + } + } +} + void UBodySetup::AddCollisionFrom(class UBodySetup* FromSetup) { AddCollisionFrom(FromSetup->AggGeom); @@ -157,7 +327,6 @@ void UBodySetup::AddCollisionFrom(class UBodySetup* FromSetup) DECLARE_CYCLE_STAT(TEXT("Create Physics Meshes"), STAT_CreatePhysicsMeshes, STATGROUP_Physics); - void UBodySetup::CreatePhysicsMeshes() { SCOPE_CYCLE_COUNTER(STAT_CreatePhysicsMeshes); @@ -186,7 +355,7 @@ void UBodySetup::CreatePhysicsMeshes() return; } - FPhysXFormatDataReader CookedDataReader(*FormatData, &UVInfo); + FPhysXCookingDataReader CookedDataReader(*FormatData, &UVInfo); if (GetCollisionTraceFlag() != CTF_UseComplexAsSimple) { @@ -201,49 +370,58 @@ void UBodySetup::CreatePhysicsMeshes() #endif } } - - ClearPhysicsMeshes(); - if (GetCollisionTraceFlag() != CTF_UseComplexAsSimple) - { - - ensure(!bGenerateNonMirroredCollision || CookedDataReader.ConvexMeshes.Num() == 0 || CookedDataReader.ConvexMeshes.Num() == AggGeom.ConvexElems.Num()); - ensure(!bGenerateMirroredCollision || CookedDataReader.ConvexMeshesNegX.Num() == 0 || CookedDataReader.ConvexMeshesNegX.Num() == AggGeom.ConvexElems.Num()); - - //If the cooked data no longer has convex meshes, make sure to empty AggGeom.ConvexElems - otherwise we leave NULLS which cause issues, and we also read past the end of CookedDataReader.ConvexMeshes - if ((bGenerateNonMirroredCollision && CookedDataReader.ConvexMeshes.Num() == 0) || (bGenerateMirroredCollision && CookedDataReader.ConvexMeshesNegX.Num() == 0)) - { - AggGeom.ConvexElems.Empty(); - } - - for (int32 ElementIndex = 0; ElementIndex < AggGeom.ConvexElems.Num(); ElementIndex++) - { - FKConvexElem& ConvexElem = AggGeom.ConvexElems[ElementIndex]; - - if (bGenerateNonMirroredCollision) - { - ConvexElem.SetConvexMesh(CookedDataReader.ConvexMeshes[ElementIndex]); - FPhysxSharedData::Get().Add(ConvexElem.GetConvexMesh()); - } - - if (bGenerateMirroredCollision) - { - ConvexElem.SetMirroredConvexMesh(CookedDataReader.ConvexMeshesNegX[ElementIndex]); - FPhysxSharedData::Get().Add(ConvexElem.GetMirroredConvexMesh()); - } - } - } - - for(PxTriangleMesh* TriMesh : CookedDataReader.TriMeshes) - { - check(TriMesh); - TriMeshes.Add(TriMesh); - FPhysxSharedData::Get().Add(TriMesh); - } + FinishCreatingPhysicsMeshes(CookedDataReader.ConvexMeshes, CookedDataReader.ConvexMeshesNegX, CookedDataReader.TriMeshes); } else { - ClearPhysicsMeshes(); // Make sure all are cleared then + ClearPhysicsMeshes(); + } + + bCreatedPhysicsMeshes = true; +#endif +} + +void UBodySetup::FinishCreatingPhysicsMeshes(const TArray& ConvexMeshes, const TArray& ConvexMeshesNegX, const TArray& CookedTriMeshes) +{ + check(IsInGameThread()); + ClearPhysicsMeshes(); + +#if WITH_PHYSX + if (GetCollisionTraceFlag() != CTF_UseComplexAsSimple) + { + ensure(!bGenerateNonMirroredCollision || ConvexMeshes.Num() == 0 || ConvexMeshes.Num() == AggGeom.ConvexElems.Num()); + ensure(!bGenerateMirroredCollision || ConvexMeshesNegX.Num() == 0 || ConvexMeshesNegX.Num() == AggGeom.ConvexElems.Num()); + + //If the cooked data no longer has convex meshes, make sure to empty AggGeom.ConvexElems - otherwise we leave NULLS which cause issues, and we also read past the end of CookedDataReader.ConvexMeshes + if ((bGenerateNonMirroredCollision && ConvexMeshes.Num() == 0) || (bGenerateMirroredCollision && ConvexMeshesNegX.Num() == 0)) + { + AggGeom.ConvexElems.Empty(); + } + + for (int32 ElementIndex = 0; ElementIndex < AggGeom.ConvexElems.Num(); ElementIndex++) + { + FKConvexElem& ConvexElem = AggGeom.ConvexElems[ElementIndex]; + + if (bGenerateNonMirroredCollision) + { + ConvexElem.SetConvexMesh(ConvexMeshes[ElementIndex]); + FPhysxSharedData::Get().Add(ConvexElem.GetConvexMesh()); + } + + if (bGenerateMirroredCollision) + { + ConvexElem.SetMirroredConvexMesh(ConvexMeshesNegX[ElementIndex]); + FPhysxSharedData::Get().Add(ConvexElem.GetMirroredConvexMesh()); + } + } + } + + for (PxTriangleMesh* TriMesh : CookedTriMeshes) + { + check(TriMesh); + TriMeshes.Add(TriMesh); + FPhysxSharedData::Get().Add(TriMesh); } // Clear the cooked data @@ -252,10 +430,136 @@ void UBodySetup::CreatePhysicsMeshes() CookedFormatData.FlushData(); } - bCreatedPhysicsMeshes = true; #endif + + bCreatedPhysicsMeshes = true; } +struct FAsyncPhysicsCookHelper +{ + FAsyncPhysicsCookHelper(IPhysXCookingModule* InPhysXCookingModule, const FCookBodySetupInfo& InCookInfo) + : CookInfo(InCookInfo) + , PhysXCookingModule(InPhysXCookingModule) + { + } + + void CreatePhysicsMeshesAsync_Concurrent(FSimpleDelegateGraphTask::FDelegate FinishDelegate) + { + CreateConvexElements(CookInfo.NonMirroredConvexVertices, OutNonMirroredConvexMeshes, false); + CreateConvexElements(CookInfo.MirroredConvexVertices, OutMirroredConvexMeshes, true); + + if (CookInfo.bCookTriMesh && !CookInfo.bTriMeshError) + { + OutTriangleMeshes.AddZeroed(); + const bool bError = !PhysXCookingModule->GetPhysXCooking()->CreateTriMesh(FPlatformProperties::GetPhysicsFormat(), CookInfo.TriMeshCookFlags, CookInfo.TriangleMeshDesc.Vertices, CookInfo.TriangleMeshDesc.Indices, CookInfo.TriangleMeshDesc.MaterialIndices, CookInfo.TriangleMeshDesc.bFlipNormals, OutTriangleMeshes[0]); + if(bError) + { + UE_LOG(LogPhysics, Warning, TEXT("Failed to cook TriMesh: %s."), *CookInfo.OuterDebugName); + } + else if(CookInfo.bSupportUVFromHitResults) + { + OutUVInfo.FillFromTriMesh(CookInfo.TriangleMeshDesc); + } + } + + FSimpleDelegateGraphTask::CreateAndDispatchWhenReady(FinishDelegate, GET_STATID(STAT_PhysXCooking), nullptr, ENamedThreads::GameThread); + } + + void CreateConvexElements(const TArray>& Elements, TArray& OutConvexMeshes, bool bFlipped) + { + OutMirroredConvexMeshes.Reserve(Elements.Num()); + for (int32 ElementIndex = 0; ElementIndex < Elements.Num(); ++ElementIndex) + { + OutConvexMeshes.AddZeroed(); + const EPhysXCookingResult Result = PhysXCookingModule->GetPhysXCooking()->CreateConvex(FPlatformProperties::GetPhysicsFormat(), CookInfo.ConvexCookFlags, Elements[ElementIndex], OutConvexMeshes.Last()); + switch (Result) + { + case EPhysXCookingResult::Succeeded: + break; + case EPhysXCookingResult::Failed: + UE_LOG(LogPhysics, Warning, TEXT("Failed to cook convex: %s %d (FlipX:%d). The remaining elements will not get cooked."), *CookInfo.OuterDebugName, ElementIndex, bFlipped ? 1 : 0); + break; + case EPhysXCookingResult::SucceededWithInflation: + if (!CookInfo.bConvexDeformableMesh) + { + UE_LOG(LogPhysics, Warning, TEXT("Cook convex: %s %d (FlipX:%d) failed but succeeded with inflation. The mesh should be looked at."), *CookInfo.OuterDebugName, ElementIndex, bFlipped ? 1 : 0); + } + else + { + UE_LOG(LogPhysics, Log, TEXT("Cook convex: %s %d (FlipX:%d) required inflation. You may wish to adjust the mesh so this is not necessary."), *CookInfo.OuterDebugName, ElementIndex, bFlipped ? 1 : 0); + } + break; + default: + check(false); + } + } + } + + FCookBodySetupInfo CookInfo; + IPhysXCookingModule* PhysXCookingModule; + + //output + TArray OutNonMirroredConvexMeshes; + TArray OutMirroredConvexMeshes; + TArray OutTriangleMeshes; + FBodySetupUVInfo OutUVInfo; +}; + +void UBodySetup::CreatePhysicsMeshesAsync(FOnAsyncPhysicsCookFinished OnAsyncPhysicsCookFinished) +{ +#if WITH_PHYSX_COOKING + UActorComponent* OwningComp = Cast(GetOuter()); + UWorld* World = OwningComp ? OwningComp->GetWorld() : nullptr; + const bool bIsRuntime = World && World->IsGameWorld(); + + if (bIsRuntime && !IsRuntimeCookingEnabled()) + { + UE_LOG(LogPhysics, Error, TEXT("Attempting to build physics data for %s at runtime, but runtime cooking is disabled (see the RuntimePhysXCooking plugin)."), *GetPathName()); + FinishCreatePhysicsMeshesAsync(nullptr, OnAsyncPhysicsCookFinished); + return; + } +#endif + + if(IPhysXCookingModule* PhysXCookingModule = GetPhysXCookingModule()) + { + FCookBodySetupInfo CookInfo; + GetCookInfo(CookInfo, EPhysXMeshCookFlags::Default); //TODO: pass in different flags? + + if(CookInfo.bCookTriMesh || CookInfo.bCookNonMirroredConvex || CookInfo.bCookMirroredConvex) + { + FAsyncPhysicsCookHelper* AsyncPhysicsCookHelper = new FAsyncPhysicsCookHelper(PhysXCookingModule, CookInfo); + FSimpleDelegateGraphTask::CreateAndDispatchWhenReady(FSimpleDelegateGraphTask::FDelegate::CreateRaw(AsyncPhysicsCookHelper, &FAsyncPhysicsCookHelper::CreatePhysicsMeshesAsync_Concurrent, + /*FinishDelegate=*/FSimpleDelegateGraphTask::FDelegate::CreateUObject(this, &UBodySetup::FinishCreatePhysicsMeshesAsync, AsyncPhysicsCookHelper, OnAsyncPhysicsCookFinished)), + GET_STATID(STAT_PhysXCooking), nullptr, ENamedThreads::AnyThread); + } + else + { + FinishCreatePhysicsMeshesAsync(nullptr, OnAsyncPhysicsCookFinished); + } + } + else + { + FinishCreatePhysicsMeshesAsync(nullptr, OnAsyncPhysicsCookFinished); + } +} + +void UBodySetup::FinishCreatePhysicsMeshesAsync(FAsyncPhysicsCookHelper* AsyncPhysicsCookHelper, FOnAsyncPhysicsCookFinished OnAsyncPhysicsCookFinished) +{ + if(AsyncPhysicsCookHelper) + { + FinishCreatingPhysicsMeshes(AsyncPhysicsCookHelper->OutNonMirroredConvexMeshes, AsyncPhysicsCookHelper->OutMirroredConvexMeshes, AsyncPhysicsCookHelper->OutTriangleMeshes); + UVInfo = AsyncPhysicsCookHelper->OutUVInfo; + delete AsyncPhysicsCookHelper; + + } + else + { + ClearPhysicsMeshes(); + bCreatedPhysicsMeshes = true; + } + + OnAsyncPhysicsCookFinished.ExecuteIfBound(); +} void UBodySetup::ClearPhysicsMeshes() { @@ -624,10 +928,8 @@ template <> FString FBodySetupShapeIterator::GetDebugName() con void UBodySetup::AddShapesToRigidActor_AssumesLocked(FBodyInstance* OwningInstance, physx::PxRigidActor* PDestActor, EPhysicsSceneType SceneType, FVector& Scale3D, physx::PxMaterial* SimpleMaterial, TArray& ComplexMaterials, FShapeData& ShapeData, const FTransform& RelativeTM, TArray* NewShapes, bool bShapeSharing) { -#if WITH_RUNTIME_PHYSICS_COOKING || WITH_EDITOR // in editor, there are a lot of things relying on body setup to create physics meshes CreatePhysicsMeshes(); -#endif // if almost zero, set min scale // @todo fixme @@ -715,9 +1017,6 @@ void UBodySetup::AddShapesToRigidActor_AssumesLocked(FBodyInstance* OwningInstan #endif // WITH_PHYSX - -#if WITH_RUNTIME_PHYSICS_COOKING || WITH_EDITOR - void UBodySetup::RemoveSimpleCollision() { AggGeom.EmptyElements(); @@ -793,8 +1092,6 @@ void UBodySetup::InvalidatePhysicsData() CookedFormatData.FlushData(); } } -#endif // WITH_RUNTIME_PHYSICS_COOKING || WITH_EDITOR - void UBodySetup::BeginDestroy() { @@ -816,7 +1113,6 @@ void UBodySetup::Serialize(FArchive& Ar) { Super::Serialize(Ar); - // Load GUID (or create one for older versions) Ar << BodySetupGuid; @@ -833,13 +1129,6 @@ void UBodySetup::Serialize(FArchive& Ar) bool bDuplicating = (Ar.GetPortFlags() & PPF_Duplicate) != 0; -#if !WITH_RUNTIME_PHYSICS_COOKING - if (FPlatformProperties::RequiresCookedData() && !bCooked && Ar.IsLoading() && !bDuplicating) - { - UE_LOG(LogPhysics, Fatal, TEXT("This platform requires cooked packages, and physX data was not cooked into %s."), *GetFullName()); - } -#endif //!WITH_RUNTIME_PHYSICS_COOKING - if (bCooked) { #if WITH_EDITOR @@ -1066,7 +1355,7 @@ void UBodySetup::ClearCachedCookedPlatformData( const ITargetPlatform* TargetPla } #endif -#if WITH_PHYSX && (WITH_RUNTIME_PHYSICS_COOKING || WITH_EDITOR) +#if WITH_PHYSX EPhysXMeshCookFlags UBodySetup::GetRuntimeOnlyCookOptimizationFlags() const { EPhysXMeshCookFlags RuntimeCookFlags = EPhysXMeshCookFlags::Default; @@ -1134,19 +1423,25 @@ FByteBulkData* UBodySetup::GetCookedData(FName Format, bool bRuntimeOnlyOptimize bool bContainedData = UseCookedData->Contains(Format); FByteBulkData* Result = &UseCookedData->GetFormat(Format); + #if WITH_PHYSX if (!bContainedData) { -#if !defined(WITH_RUNTIME_PHYSICS_COOKING) || !WITH_RUNTIME_PHYSICS_COOKING - if (FPlatformProperties::RequiresCookedData()) + SCOPE_CYCLE_COUNTER(STAT_PhysXCooking); + + UActorComponent* OwningComp = Cast(GetOuter()); + UWorld* World = OwningComp ? OwningComp->GetWorld() : nullptr; + const bool bIsRuntime = World && World->IsGameWorld(); + + if(bIsRuntime && !IsRuntimeCookingEnabled()) { - UE_LOG(LogPhysics, Error, TEXT("Attempt to build physics data for %s when we are unable to. This platform requires cooked packages."), *GetPathName()); + UE_LOG(LogPhysics, Error, TEXT("Attempting to build physics data for %s at runtime, but runtime cooking is disabled (see the RuntimePhysXCooking plugin)."), *GetPathName()); + return nullptr; } -#endif if (AggGeom.ConvexElems.Num() == 0 && (CDP == NULL || CDP->ContainsPhysicsTriMeshData(bMeshCollideAll) == false)) { - return NULL; + return nullptr; } #if WITH_EDITOR @@ -1155,30 +1450,35 @@ FByteBulkData* UBodySetup::GetCookedData(FName Format, bool bRuntimeOnlyOptimize const bool bEligibleForRuntimeOptimization = CookedFormatDataOverride == nullptr; //We don't support runtime cook optimization for per poly skeletal mesh. This is an edge case we may want to support (only helps memory savings) #endif -#if WITH_RUNTIME_PHYSICS_COOKING || WITH_EDITOR - TArray OutData; - const EPhysXMeshCookFlags CookingFlags = bEligibleForRuntimeOptimization ? GetRuntimeOnlyCookOptimizationFlags() : EPhysXMeshCookFlags::Default; - FDerivedDataPhysXCooker* DerivedPhysXData = new FDerivedDataPhysXCooker(Format, CookingFlags, this); - if (DerivedPhysXData->CanBuild()) + + TArray OutData; + FDerivedDataPhysXCooker* DerivedPhysXData = new FDerivedDataPhysXCooker(Format, CookingFlags, this); //TODO: runtime cook (sync or async) should not used the derived data cooker + if(!bIsRuntime) { - #if WITH_EDITOR - COOK_STAT(auto Timer = PhysXBodySetupCookStats::UsageStats.TimeSyncWork()); - bool bDataWasBuilt = false; - bool DDCHit = GetDerivedDataCacheRef().GetSynchronous(DerivedPhysXData, OutData, &bDataWasBuilt); - #elif WITH_RUNTIME_PHYSICS_COOKING - DerivedPhysXData->Build(OutData); - #endif - COOK_STAT(Timer.AddHitOrMiss(!DDCHit || bDataWasBuilt ? FCookStats::CallStats::EHitOrMiss::Miss : FCookStats::CallStats::EHitOrMiss::Hit, OutData.Num())); - if (OutData.Num()) +#if WITH_EDITOR + + if (DerivedPhysXData->CanBuild()) { - Result->Lock(LOCK_READ_WRITE); - FMemory::Memcpy(Result->Realloc(OutData.Num()), OutData.GetData(), OutData.Num()); - Result->Unlock(); + COOK_STAT(auto Timer = PhysXBodySetupCookStats::UsageStats.TimeSyncWork()); + bool bDataWasBuilt = false; + bool DDCHit = GetDerivedDataCacheRef().GetSynchronous(DerivedPhysXData, OutData, &bDataWasBuilt); + COOK_STAT(Timer.AddHitOrMiss(!DDCHit || bDataWasBuilt ? FCookStats::CallStats::EHitOrMiss::Miss : FCookStats::CallStats::EHitOrMiss::Hit, OutData.Num())); } +#endif + } + else + { + DerivedPhysXData->Build(OutData); + } + + if (OutData.Num()) + { + Result->Lock(LOCK_READ_WRITE); + FMemory::Memcpy(Result->Realloc(OutData.Num()), OutData.GetData(), OutData.Num()); + Result->Unlock(); } else -#endif { UE_LOG(LogPhysics, Warning, TEXT("Attempt to build physics data for %s when we are unable to."), *GetPathName()); } @@ -1767,8 +2067,13 @@ TEnumAsByte UBodySetup::GetCollisionTraceFlag() const TEnumAsByte DefaultFlag = UPhysicsSettings::Get()->DefaultShapeComplexity; return CollisionTraceFlag == ECollisionTraceFlag::CTF_UseDefault ? DefaultFlag : CollisionTraceFlag; } + +/// @cond DOXYGEN_WARNINGS + template void FBodySetupShapeIterator::ForEachShape(const TArray&, TFunctionRef) const; template void FBodySetupShapeIterator::ForEachShape(const TArray&, TFunctionRef) const; template void FBodySetupShapeIterator::ForEachShape(const TArray&, TFunctionRef) const; template void FBodySetupShapeIterator::ForEachShape(const TArray&, TFunctionRef) const; -template void FBodySetupShapeIterator::ForEachShape(const TArray&, TFunctionRef) const; \ No newline at end of file +template void FBodySetupShapeIterator::ForEachShape(const TArray&, TFunctionRef) const; + +/// @endcond diff --git a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/ConstraintInstance.cpp b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/ConstraintInstance.cpp index b1dfe7a72479..8c3d5401269c 100644 --- a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/ConstraintInstance.cpp +++ b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/ConstraintInstance.cpp @@ -12,6 +12,10 @@ #include "Logging/MessageLog.h" #include "Misc/UObjectToken.h" +#if WITH_EDITOR +#include "UObject/UnrealType.h" +#endif + #define LOCTEXT_NAMESPACE "ConstraintInstance" TAutoConsoleVariable CVarConstraintDampingScale( @@ -46,6 +50,67 @@ physx::PxD6Joint* FConstraintInstance::GetUnbrokenJoint_AssumesLocked() const return (ConstraintData && !(ConstraintData->getConstraintFlags()&PxConstraintFlag::eBROKEN)) ? ConstraintData : nullptr; } +#if WITH_EDITOR +void FConstraintProfileProperties::SyncChangedConstraintProperties(FPropertyChangedChainEvent& PropertyChangedEvent) +{ + static const FName StiffnessProperty = GET_MEMBER_NAME_CHECKED(FConstraintDrive, Stiffness); + static const FName MaxForceName = GET_MEMBER_NAME_CHECKED(FConstraintDrive, MaxForce); + static const FName DampingName = GET_MEMBER_NAME_CHECKED(FConstraintDrive, Damping); + + if (TDoubleLinkedList::TDoubleLinkedListNode* PropertyNode = PropertyChangedEvent.PropertyChain.GetTail()) + { + if (TDoubleLinkedList::TDoubleLinkedListNode* ParentProeprtyNode = PropertyNode->GetPrevNode()) + { + if (UProperty* Property = PropertyNode->GetValue()) + { + if (UProperty* ParentProperty = ParentProeprtyNode->GetValue()) + { + const FName PropertyName = Property->GetFName(); + const FName ParentPropertyName = ParentProperty->GetFName(); + + if (ParentPropertyName == GET_MEMBER_NAME_CHECKED(FLinearDriveConstraint, XDrive)) + { + if (StiffnessProperty == PropertyName) + { + LinearDrive.YDrive.Stiffness = LinearDrive.XDrive.Stiffness; + LinearDrive.ZDrive.Stiffness = LinearDrive.XDrive.Stiffness; + } + else if (MaxForceName == PropertyName) + { + LinearDrive.YDrive.MaxForce = LinearDrive.XDrive.MaxForce; + LinearDrive.ZDrive.MaxForce = LinearDrive.XDrive.MaxForce; + } + else if (DampingName == PropertyName) + { + LinearDrive.YDrive.Damping = LinearDrive.XDrive.Damping; + LinearDrive.ZDrive.Damping = LinearDrive.XDrive.Damping; + } + } + else if (ParentPropertyName == GET_MEMBER_NAME_CHECKED(FAngularDriveConstraint, SlerpDrive)) + { + if (StiffnessProperty == PropertyName) + { + AngularDrive.SwingDrive.Stiffness = AngularDrive.SlerpDrive.Stiffness; + AngularDrive.TwistDrive.Stiffness = AngularDrive.SlerpDrive.Stiffness; + } + else if (MaxForceName == PropertyName) + { + AngularDrive.SwingDrive.MaxForce = AngularDrive.SlerpDrive.MaxForce; + AngularDrive.TwistDrive.MaxForce = AngularDrive.SlerpDrive.MaxForce; + } + else if (DampingName == PropertyName) + { + AngularDrive.SwingDrive.Damping = AngularDrive.SlerpDrive.Damping; + AngularDrive.TwistDrive.Damping = AngularDrive.SlerpDrive.Damping; + } + } + } + } + } + } +} +#endif + bool FConstraintInstance::ExecuteOnUnbrokenJointReadOnly(TFunctionRef Func) const { if(ConstraintData) @@ -364,13 +429,13 @@ bool GetPActors_AssumesLocked(const FBodyInstance* Body1, const FBodyInstance* B if (PActor1->is() && PActor2->is()) { const uint32 SceneType = Body2->RigidActorSync != NULL ? PST_Sync : PST_Async; - PActor1 = Body1->GetPxRigidActor_AssumesLocked(SceneType); + PActor1 = Body1->GetPxRigidActorFromScene_AssumesLocked(SceneType); } else if (PActor2->is() && PActor1->is()) { const uint32 SceneType = Body1->RigidActorSync != NULL ? PST_Sync : PST_Async; - PActor2 = Body2->GetPxRigidActor_AssumesLocked(SceneType); + PActor2 = Body2->GetPxRigidActorFromScene_AssumesLocked(SceneType); } } diff --git a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysAnim.cpp b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysAnim.cpp index 20ef83ab99e4..c27fdb9ffa83 100644 --- a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysAnim.cpp +++ b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysAnim.cpp @@ -108,7 +108,7 @@ public: } }; -typedef TArray> TAssetWorldBoneTMArray; +typedef TArray> TAssetWorldBoneTMArray; // Use current pose to calculate world-space position of this bone without physics now. void UpdateWorldBoneTM(TAssetWorldBoneTMArray& WorldBoneTMs, const TArray& InBoneSpaceTransforms, int32 BoneIndex, USkeletalMeshComponent* SkelComp, const FTransform &LocalToWorldTM, const FVector& Scale3D) { @@ -144,7 +144,7 @@ void USkeletalMeshComponent::PerformBlendPhysicsBones(const TArray& EditableComponentSpaceTransforms = GetEditableComponentSpaceTransforms(); @@ -185,7 +185,7 @@ void USkeletalMeshComponent::PerformBlendPhysicsBones(const TArray> PendingBodyTMs; + TArray> PendingBodyTMs; #endif #if WITH_PHYSX @@ -204,7 +204,7 @@ void USkeletalMeshComponent::PerformBlendPhysicsBones(const TArrayFindBodyIndex(SkeletalMesh->RefSkeleton.GetBoneName(BoneIndex)) : INDEX_NONE; + int32 BodyIndex = PhysicsAsset->FindBodyIndex(SkeletalMesh->RefSkeleton.GetBoneName(BoneIndex)); // need to update back to physX so that physX knows where it was after blending #if DEPERCATED_PHYSBLEND_UPDATES_PHYSX bool bUpdatePhysics = false; @@ -220,11 +220,8 @@ void USkeletalMeshComponent::PerformBlendPhysicsBones(const TArraySkeletalBodySetups.Num(), Bodies.Num(), BodyIndex); - } + UE_LOG(LogPhysics, Warning, TEXT(" - # of BodySetup (%d), # of Bodies (%d), Invalid BodyIndex(%d)"), + PhysicsAsset->SkeletalBodySetups.Num(), Bodies.Num(), BodyIndex); continue; } #endif @@ -295,7 +292,7 @@ void USkeletalMeshComponent::PerformBlendPhysicsBones(const TArrayIsInstanceSimulatingPhysics()) + if(bLocalSpaceKinematics || BodyIndex == INDEX_NONE || Bodies[BodyIndex]->IsInstanceSimulatingPhysics()) { const int32 ParentIndex = SkeletalMesh->RefSkeleton.GetParentIndex(BoneIndex); EditableComponentSpaceTransforms[BoneIndex] = InBoneSpaceTransforms[BoneIndex] * EditableComponentSpaceTransforms[ParentIndex]; @@ -321,7 +318,7 @@ void USkeletalMeshComponent::PerformBlendPhysicsBones(const TArrayBI = PhysicsAssetBodyInstance; - BodyTMPair->TM = EditableComponentSpaceTransforms[BoneIndex] * ComponentToWorld; + BodyTMPair->TM = EditableComponentSpaceTransforms[BoneIndex] * GetComponentTransform(); } #endif } @@ -490,7 +487,7 @@ void USkeletalMeshComponent::UpdateKinematicBonesToAnim(const TArray return; } - const FTransform& CurrentLocalToWorld = ComponentToWorld; + const FTransform& CurrentLocalToWorld = GetComponentTransform(); #if !(UE_BUILD_SHIPPING) // Gracefully handle NaN @@ -502,7 +499,7 @@ void USkeletalMeshComponent::UpdateKinematicBonesToAnim(const TArray #endif // If we are only using bodies for physics, don't need to move them right away, can defer until simulation (unless told not to) - if(BodyInstance.GetCollisionEnabled() == ECollisionEnabled::PhysicsOnly && DeferralAllowed == EAllowKinematicDeferral::AllowDeferral) + if(DeferralAllowed == EAllowKinematicDeferral::AllowDeferral && (bDeferMovementFromSceneQueries || BodyInstance.GetCollisionEnabled() == ECollisionEnabled::PhysicsOnly)) { PhysScene->MarkForPreSimKinematicUpdate(this, Teleport, bNeedsSkinning); return; @@ -546,7 +543,8 @@ void USkeletalMeshComponent::UpdateKinematicBonesToAnim(const TArray return; } #endif - + const int32 NumComponentSpaceTransforms = GetNumComponentSpaceTransforms(); + const int32 NumBodies = Bodies.Num(); #if WITH_PHYSX const uint32 SceneType = GetPhysicsSceneType(*PhysicsAsset, *PhysScene, UseAsyncScene); @@ -555,18 +553,17 @@ void USkeletalMeshComponent::UpdateKinematicBonesToAnim(const TArray #endif // Iterate over each body - for (int32 i = 0; i < Bodies.Num(); i++) + for (int32 i = 0; i < NumBodies; i++) { - // If we have a physics body, and its kinematic... FBodyInstance* BodyInst = Bodies[i]; - check(BodyInst); + PxRigidActor* RigidActor = BodyInst->GetPxRigidActor_AssumesLocked(); - if (BodyInst->IsValidBodyInstance() && (bTeleport || !BodyInst->IsInstanceSimulatingPhysics())) + if (RigidActor && (bTeleport || !BodyInst->IsInstanceSimulatingPhysics())) //If we have a body and it's kinematic, or we are teleporting a simulated body { const int32 BoneIndex = BodyInst->InstanceBoneIndex; // If we could not find it - warn. - if (BoneIndex == INDEX_NONE || BoneIndex >= GetNumComponentSpaceTransforms()) + if (BoneIndex == INDEX_NONE || BoneIndex >= NumComponentSpaceTransforms) { const FName BodyName = PhysicsAsset->SkeletalBodySetups[i]->BoneName; UE_LOG(LogPhysics, Log, TEXT("UpdateRBBones: WARNING: Failed to find bone '%s' need by PhysicsAsset '%s' in SkeletalMesh '%s'."), *BodyName.ToString(), *PhysicsAsset->GetName(), *SkeletalMesh->GetName()); @@ -585,8 +582,8 @@ void USkeletalMeshComponent::UpdateKinematicBonesToAnim(const TArray continue; } - // If kinematic and not teleporting, set kinematic target - if (!BodyInst->IsInstanceSimulatingPhysics() && !bTeleport) + // If not teleporting (must be kinematic) set kinematic target + if (!bTeleport) { PhysScene->SetKinematicTarget_AssumesLocked(BodyInst, BoneTransform, true); } @@ -595,7 +592,6 @@ void USkeletalMeshComponent::UpdateKinematicBonesToAnim(const TArray { const PxTransform PNewPose = U2PTransform(BoneTransform); ensure(PNewPose.isValid()); - PxRigidActor* RigidActor = BodyInst->GetPxRigidActor_AssumesLocked(); // This should never fail because IsValidBodyInstance() passed above RigidActor->setGlobalPose(PNewPose); } #endif diff --git a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysDerivedData.cpp b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysDerivedData.cpp index 47f621763ed7..a9b9643c2ab7 100644 --- a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysDerivedData.cpp +++ b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysDerivedData.cpp @@ -9,9 +9,11 @@ #include "PhysicsEngine/BodySetup.h" #include "Interfaces/ITargetPlatformManagerModule.h" -#if WITH_PHYSX && (WITH_RUNTIME_PHYSICS_COOKING || WITH_EDITOR) +#if WITH_PHYSX/* && WITH_EDITOR*/ //TODO: sync and async cooking should not use the derived data cooker - existing paths exist just need hooking up -#include "IPhysXFormatModule.h" +#include "IPhysXCookingModule.h" + +DEFINE_STAT(STAT_PhysXCooking); FDerivedDataPhysXCooker::FDerivedDataPhysXCooker(FName InFormat, EPhysXMeshCookFlags InRuntimeCookFlags, UBodySetup* InBodySetup) : BodySetup( InBodySetup ) @@ -41,19 +43,17 @@ void FDerivedDataPhysXCooker::InitCooker() static ITargetPlatformManagerModule* TPM = GetTargetPlatformManager(); if (TPM) { - Cooker = TPM->FindPhysXFormat( Format ); + Cooker = TPM->FindPhysXCooking( Format ); } -#elif WITH_RUNTIME_PHYSICS_COOKING - if (IPhysXFormatModule* Module = FModuleManager::LoadModulePtr("PhysXFormats")) +#elif WITH_PHYSX_COOKING + IPhysXCookingModule* Module = FModuleManager::LoadModulePtr("PhysXCooking"); + if (Module) { - Cooker = Module->GetPhysXFormat(); + Cooker = Module->GetPhysXCooking(); } #endif } -DECLARE_CYCLE_STAT(TEXT("PhysX Cooking"), STAT_PhysXCooking, STATGROUP_Physics); - - bool FDerivedDataPhysXCooker::Build( TArray& OutData ) { SCOPE_CYCLE_COUNTER(STAT_PhysXCooking); @@ -75,26 +75,30 @@ bool FDerivedDataPhysXCooker::Build( TArray& OutData ) bool bSuccess = true; - // Cook convex meshes, but only if we are not forcing complex collision to be used as simple collision as well - if( BodySetup && BodySetup->GetCollisionTraceFlag() != CTF_UseComplexAsSimple && BodySetup->AggGeom.ConvexElems.Num() > 0 ) + FCookBodySetupInfo CookInfo; + BodySetup->GetCookInfo(CookInfo, RuntimeCookFlags); + + if(CookInfo.bCookNonMirroredConvex) { - if( bGenerateNormalMesh ) - { - bSuccess = BuildConvex( OutData, false, NumConvexElementsCooked) && bSuccess; - } - if ( bGenerateMirroredMesh ) - { - bSuccess = BuildConvex( OutData, true, NumMirroredElementsCooked) && bSuccess; - } + bSuccess = BuildConvex(OutData, CookInfo.bConvexDeformableMesh, false, CookInfo.NonMirroredConvexVertices, CookInfo.ConvexCookFlags, NumConvexElementsCooked) && bSuccess; + } + + if(CookInfo.bCookMirroredConvex) + { + bSuccess = BuildConvex(OutData, CookInfo.bConvexDeformableMesh, true, CookInfo.MirroredConvexVertices, CookInfo.ConvexCookFlags, NumMirroredElementsCooked) && bSuccess; } FBodySetupUVInfo UVInfo; - - // Cook trimeshes, but only if we do not frce simple collision to be used as complex collision as well - bool bUsingAllTriData = BodySetup != NULL ? BodySetup->bMeshCollideAll : false; - if( (BodySetup == NULL || BodySetup->GetCollisionTraceFlag() != CTF_UseSimpleAsComplex) && ShouldGenerateTriMeshData(bUsingAllTriData) ) + if(CookInfo.bCookTriMesh) { - bSuccess = BuildTriMesh( OutData, bUsingAllTriData, UPhysicsSettings::Get()->bSupportUVFromHitResults ? &UVInfo : nullptr, NumTriMeshesCooked) && bSuccess; + if(!CookInfo.bTriMeshError) + { + bSuccess = BuildTriMesh(OutData, CookInfo.TriangleMeshDesc, CookInfo.TriMeshCookFlags, CookInfo.bSupportUVFromHitResults ? &UVInfo : nullptr, NumTriMeshesCooked) && bSuccess; + } + else + { + bSuccess = false; + } } // Seek to end, serialize UV info @@ -110,47 +114,17 @@ bool FDerivedDataPhysXCooker::Build( TArray& OutData ) return bSuccess; } -bool FDerivedDataPhysXCooker::BuildConvex( TArray& OutData, bool InMirrored, int32& NumConvexCooked ) +bool FDerivedDataPhysXCooker::BuildConvex( TArray& OutData, bool bDeformableMesh, bool InMirrored, const TArray>& Elements, EPhysXMeshCookFlags CookFlags, int32& NumConvexCooked ) { bool bSuccess = true; - check( BodySetup != NULL ); - for( int32 ElementIndex = 0; ElementIndex < BodySetup->AggGeom.ConvexElems.Num(); ElementIndex++ ) + for( int32 ElementIndex = 0; ElementIndex < Elements.Num(); ElementIndex++ ) { - const FKConvexElem& ConvexElem = BodySetup->AggGeom.ConvexElems[ElementIndex]; - - FVector Scaling = InMirrored ? FVector(-1, 1, 1) : FVector(1, 1, 1); - - TArray MeshVertices; - MeshVertices.AddUninitialized(ConvexElem.VertexData.Num()); - - FTransform ConvexTransform = ConvexElem.GetTransform(); - if (!ConvexTransform.IsValid()) - { - UE_LOG(LogPhysics, Warning, TEXT("Cook Convex: [%s] ConvexElem[%d] has invalid transform"), *GetPathNameSafe(BodySetup->GetOuter()), ElementIndex); - ConvexTransform = FTransform::Identity; - } - - // Transform verts from element to body space, and mirror if desired - for(int32 VertIdx=0; VertIdxIsA(USplineMeshComponent::StaticClass()); - EPhysXMeshCookFlags CookFlags = RuntimeCookFlags; - if (bDeformableMesh) - { - CookFlags |= EPhysXMeshCookFlags::DeformableMesh; - } + int32 ResultInfoOffset = OutData.Add(false); // Cook and store Result at ResultInfoOffset UE_LOG(LogPhysics, Log, TEXT("Cook Convex: %s %d (FlipX:%d)"), *BodySetup->GetOuter()->GetPathName(), ElementIndex, InMirrored); - const EPhysXCookingResult Result = Cooker->CookConvex(Format, CookFlags, MeshVertices, OutData); + const EPhysXCookingResult Result = Cooker->CookConvex(Format, CookFlags, Elements[ElementIndex], OutData); switch (Result) { case EPhysXCookingResult::Succeeded: @@ -178,7 +152,7 @@ bool FDerivedDataPhysXCooker::BuildConvex( TArray& OutData, bool InMirror OutData[ ResultInfoOffset ] = (Result != EPhysXCookingResult::Failed) ? 1 : 0; } - NumConvexCooked = BodySetup->AggGeom.ConvexElems.Num(); + NumConvexCooked = Elements.Num(); return bSuccess; } @@ -191,89 +165,25 @@ bool FDerivedDataPhysXCooker::ShouldGenerateTriMeshData(bool InUseAllTriData) return bPerformCook; } -bool FDerivedDataPhysXCooker::BuildTriMesh( TArray& OutData, bool InUseAllTriData, FBodySetupUVInfo* UVInfo, int32& NumTrimeshCooked) +bool FDerivedDataPhysXCooker::BuildTriMesh( TArray& OutData, const FTriMeshCollisionData& TriangleMeshDesc, EPhysXMeshCookFlags CookFlags, FBodySetupUVInfo* UVInfo, int32& NumTrimeshCooked) { check(Cooker != NULL); bool bError = false; bool bResult = false; - FTriMeshCollisionData TriangleMeshDesc; - IInterface_CollisionDataProvider* CDP = Cast(CollisionDataProvider); - check(CDP != NULL); // It's all been checked before getting into this function - - bool bHaveTriMeshData = CDP->GetPhysicsTriMeshData(&TriangleMeshDesc, InUseAllTriData); - if(bHaveTriMeshData) + + UE_LOG(LogPhysics, Log, TEXT("Cook TriMesh: %s"), *CollisionDataProvider->GetPathName()); + bResult = Cooker->CookTriMesh( Format, CookFlags, TriangleMeshDesc.Vertices, TriangleMeshDesc.Indices, TriangleMeshDesc.MaterialIndices, TriangleMeshDesc.bFlipNormals, OutData); + if( !bResult ) { - // If any of the below checks gets hit this usually means - // IInterface_CollisionDataProvider::ContainsPhysicsTriMeshData did not work properly. - const int32 NumIndices = TriangleMeshDesc.Indices.Num(); - const int32 NumVerts = TriangleMeshDesc.Vertices.Num(); - if(NumIndices == 0 || NumVerts == 0 || TriangleMeshDesc.MaterialIndices.Num() > NumIndices) - { - UE_LOG(LogPhysics, Warning, TEXT("FDerivedDataPhysXCooker::BuildTriMesh: Triangle data from '%s' invalid (%d verts, %d indices)."), *CollisionDataProvider->GetPathName(), NumVerts, NumIndices ); - bError = true; - return bResult; - } + bError = true; + UE_LOG(LogPhysics, Warning, TEXT("Failed to cook TriMesh: %s."), *CollisionDataProvider->GetPathName()); + } - TArray* MeshVertices = NULL; - MeshVertices = &TriangleMeshDesc.Vertices; - - // Set up cooking flags - EPhysXMeshCookFlags CookFlags = RuntimeCookFlags; - - if (TriangleMeshDesc.bDeformableMesh) - { - CookFlags |= EPhysXMeshCookFlags::DeformableMesh; - } - - if (TriangleMeshDesc.bFastCook) - { - CookFlags |= EPhysXMeshCookFlags::FastCook; - } - - UE_LOG(LogPhysics, Log, TEXT("Cook TriMesh: %s"), *CollisionDataProvider->GetPathName()); - bResult = Cooker->CookTriMesh( Format, CookFlags, *MeshVertices, TriangleMeshDesc.Indices, TriangleMeshDesc.MaterialIndices, TriangleMeshDesc.bFlipNormals, OutData); - if( !bResult ) - { - bError = true; - UE_LOG(LogPhysics, Warning, TEXT("Failed to cook TriMesh: %s."), *CollisionDataProvider->GetPathName()); - } - - // If we want UV info, copy that now - if (bResult && UVInfo) - { - // Store index buffer - const int32 NumTris = TriangleMeshDesc.Indices.Num(); - UVInfo->IndexBuffer.Empty(); - UVInfo->IndexBuffer.AddUninitialized(NumTris * 3); - for (int32 TriIdx = 0; TriIdx < TriangleMeshDesc.Indices.Num(); TriIdx++) - { - UVInfo->IndexBuffer[TriIdx * 3 + 0] = TriangleMeshDesc.Indices[TriIdx].v0; - UVInfo->IndexBuffer[TriIdx * 3 + 1] = TriangleMeshDesc.Indices[TriIdx].v1; - UVInfo->IndexBuffer[TriIdx * 3 + 2] = TriangleMeshDesc.Indices[TriIdx].v2; - } - - // Store vertex positions - UVInfo->VertPositions.Empty(); - UVInfo->VertPositions.AddUninitialized(NumVerts); - for (int32 VertIdx = 0; VertIdx < TriangleMeshDesc.Vertices.Num(); VertIdx++) - { - UVInfo->VertPositions[VertIdx] = TriangleMeshDesc.Vertices[VertIdx]; - } - - // Copy UV channels (checking they are correct size) - for (int32 UVIndex = 0; UVIndex < TriangleMeshDesc.UVs.Num(); UVIndex++) - { - if (TriangleMeshDesc.UVs[UVIndex].Num() == NumVerts) - { - UVInfo->VertUVs.Add(TriangleMeshDesc.UVs[UVIndex]); - } - else - { - break; - } - } - } + // If we want UV info, copy that now + if (bResult && UVInfo) + { + UVInfo->FillFromTriMesh(TriangleMeshDesc); } NumTrimeshCooked = bResult == true ? 1 : 0; //the cooker only generates 1 or 0 trimeshes. We save an int because we support multiple trimeshes for welding and we might want to do this per static mesh in the future. @@ -308,14 +218,12 @@ void FDerivedDataPhysXBinarySerializer::SerializeRigidActors(TArray& OutD void FDerivedDataPhysXBinarySerializer::InitSerializer() { -#if WITH_EDITOR // static here as an optimization static ITargetPlatformManagerModule* TPM = GetTargetPlatformManager(); if (TPM) { - Serializer = TPM->FindPhysXFormat(Format); + Serializer = TPM->FindPhysXCooking(Format); } -#endif } diff --git a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysDerivedData.h b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysDerivedData.h index 12be8643e8e2..dbe59ce845e8 100644 --- a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysDerivedData.h +++ b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysDerivedData.h @@ -6,17 +6,21 @@ #include "Misc/Guid.h" #include "EngineDefines.h" #include "PhysXIncludes.h" +#include "Stats/Stats.h" -#if WITH_PHYSX && (WITH_RUNTIME_PHYSICS_COOKING || WITH_EDITOR) +#if WITH_PHYSX/* && WITH_EDITOR*/ //TODO: sync and async cooking should not use the derived data cooker - existing paths exist just need hooking up #include "DerivedDataPluginInterface.h" -#include "IPhysXFormat.h" +#include "IPhysXCooking.h" #endif class UBodySetup; struct FBodyInstance; struct FBodySetupUVInfo; +struct FTriMeshCollisionData; -#if WITH_PHYSX && (WITH_RUNTIME_PHYSICS_COOKING || WITH_EDITOR) +DECLARE_CYCLE_STAT_EXTERN(TEXT("PhysX Cooking"), STAT_PhysXCooking, STATGROUP_Physics, ); + +#if WITH_PHYSX/* && WITH_EDITOR*/ //TODO: sync and async cooking should not use the derived data cooker - existing paths exist just need hooking up ////////////////////////////////////////////////////////////////////////// // PhysX Cooker @@ -31,7 +35,7 @@ private: bool bGenerateMirroredMesh; bool bGenerateUVInfo; EPhysXMeshCookFlags RuntimeCookFlags; - const class IPhysXFormat* Cooker; + const class IPhysXCooking* Cooker; FGuid DataGuid; FString MeshId; @@ -92,8 +96,8 @@ public: private: void InitCooker(); - bool BuildConvex( TArray& OutData, bool InMirrored, int32& NumConvexCooked ); - bool BuildTriMesh( TArray& OutData, bool InUseAllTriData, FBodySetupUVInfo* UVInfo, int32& NumTriMeshCooked); + bool BuildConvex( TArray& OutData, bool bDeformableMesh, bool InMirrored, const TArray>& Elements, EPhysXMeshCookFlags CookFlags, int32& NumConvexCooked); + bool BuildTriMesh( TArray& OutData, const FTriMeshCollisionData& TriangleMeshDesc, EPhysXMeshCookFlags CookFlags, FBodySetupUVInfo* UVInfo, int32& NumTriMeshCooked); bool ShouldGenerateTriMeshData(bool InUseAllTriData); }; @@ -108,7 +112,7 @@ private: const TArray& PhysicalMaterials; FName Format; FGuid DataGuid; - const class IPhysXFormat* Serializer; + const class IPhysXCooking* Serializer; int64 PhysXDataStart; //important to keep track of this for alignment requirements public: diff --git a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysDrawing.cpp b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysDrawing.cpp index b81e9140bb85..00fd63946be9 100644 --- a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysDrawing.cpp +++ b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysDrawing.cpp @@ -64,7 +64,7 @@ void FKSphereElem::DrawElemWire(class FPrimitiveDrawInterface* PDI, const FTrans void FKSphereElem::DrawElemSolid(class FPrimitiveDrawInterface* PDI, const FTransform& ElemTM, const FVector& Scale3D, const FMaterialRenderProxy* MaterialRenderProxy) const { - DrawSphere(PDI, ElemTM.GetLocation(), FVector(this->Radius * Scale3D.GetAbsMin()), DrawCollisionSides, DrawCollisionSides / 2, MaterialRenderProxy, SDPG_World); + DrawSphere(PDI, ElemTM.GetLocation(), FRotator::ZeroRotator, FVector(this->Radius * Scale3D.GetAbsMin()), DrawCollisionSides, DrawCollisionSides / 2, MaterialRenderProxy, SDPG_World); } void FKSphereElem::GetElemSolid(const FTransform& ElemTM, const FVector& Scale3D, const FMaterialRenderProxy* MaterialRenderProxy, int32 ViewIndex, FMeshElementCollector& Collector) const @@ -965,7 +965,7 @@ void FConstraintInstance::DrawConstraintImp(const FPDIOrCollector& PDIOrCollecto } else { - DrawSphere(PDI, Con1Pos, FVector(Length * 0.9f), DrawConeLimitSides, DrawConeLimitSides, LimitMaterialX->GetRenderProxy(false), Layer); + DrawSphere(PDI, Con1Pos, FRotator::ZeroRotator, FVector(Length * 0.9f), DrawConeLimitSides, DrawConeLimitSides, LimitMaterialX->GetRenderProxy(false), Layer); } } else diff --git a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysLevel.cpp b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysLevel.cpp index 1d589b11bfeb..e73ec5aa6955 100644 --- a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysLevel.cpp +++ b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysLevel.cpp @@ -11,6 +11,10 @@ #include "Engine/World.h" #include "PhysicsPublic.h" +#include "IPhysXCookingModule.h" +#include "IPhysXCooking.h" +#include "Modules/ModuleManager.h" + #if WITH_PHYSX #include "PhysicsEngine/PhysXSupport.h" #endif @@ -19,6 +23,7 @@ #include "../PhysicsEngine2D/Box2DIntegration.h" #endif #include "PhysicsEngine/PhysicsSettings.h" +#include "CoreDelegates.h" #ifndef APEX_STATICALLY_LINKED #define APEX_STATICALLY_LINKED 0 @@ -34,13 +39,13 @@ FPhysicsDelegates::FOnPhysSceneInit FPhysicsDelegates::OnPhysSceneInit; FPhysicsDelegates::FOnPhysSceneTerm FPhysicsDelegates::OnPhysSceneTerm; // CVars -static TAutoConsoleVariable CVarToleranceScaleLength( +TAutoConsoleVariable CVarToleranceScaleLength( TEXT("p.ToleranceScale_Length"), 100.f, TEXT("The approximate size of objects in the simulation. Default: 100"), ECVF_ReadOnly); -static TAutoConsoleVariable CVarToleranceScaleSpeed( +TAutoConsoleVariable CVarToleranceScaleSpeed( TEXT("p.ToleranceScale_Speed"), 1000.f, TEXT("The typical magnitude of velocities of objects in simulation. Default: 1000"), @@ -270,7 +275,7 @@ void InitGamePhys() } // Make sure - LoadPhysXModules(); + LoadPhysXModules(/*bLoadCookingModule=*/ false); // Create Foundation GPhysXAllocator = new FPhysXAllocator(); @@ -323,28 +328,21 @@ void InitGamePhys() PvdConnect(TEXT("localhost"), true); } - -#if WITH_PHYSICS_COOKING || WITH_RUNTIME_PHYSICS_COOKING // Create Cooking - PxCookingParams PCookingParams(PScale); - PCookingParams.meshWeldTolerance = 0.1f; // Weld to 1mm precision - PCookingParams.meshPreprocessParams = PxMeshPreprocessingFlags(PxMeshPreprocessingFlag::eWELD_VERTICES); - // Force any cooking in PhysX or APEX to use older incremental hull method - // This is because the new 'quick hull' method can generate degenerate geometry in some cases (very thin meshes etc.) - //PCookingParams.convexMeshCookingType = PxConvexMeshCookingType::eINFLATION_INCREMENTAL_HULL; - PCookingParams.targetPlatform = PxPlatform::ePC; - //PCookingParams.meshCookingHint = PxMeshCookingHint::eCOOKING_PERFORMANCE; - //PCookingParams.meshSizePerformanceTradeOff = 0.0f; - GPhysXCooking = PxCreateCooking(PX_PHYSICS_VERSION, *GPhysXFoundation, PCookingParams); - check(GPhysXCooking); -#endif + PxCooking* PhysXCooking = nullptr; + if (IPhysXCookingModule* Module = GetPhysXCookingModule()) + { + PhysXCooking = Module->GetPhysXCooking()->GetCooking(); + } #if WITH_APEX + check(PhysXCooking); //APEX requires cooking + // Build the descriptor for the APEX SDK apex::ApexSDKDesc ApexDesc; ApexDesc.foundation = GPhysXFoundation; // Pointer to the PxFoundation ApexDesc.physXSDK = GPhysXSDK; // Pointer to the PhysXSDK - ApexDesc.cooking = GPhysXCooking; // Pointer to the cooking library + ApexDesc.cooking = PhysXCooking; // Pointer to the cooking library ApexDesc.renderResourceManager = &GApexNullRenderResourceManager; // We will not be using the APEX rendering API, so just use a dummy render resource manager ApexDesc.resourceCallback = &GApexResourceCallback; // The resource callback is how APEX asks the application to find assets when it needs them @@ -435,6 +433,12 @@ void InitGamePhys() #endif // #if WITH_APEX + // One-time register delegate with Trim() to run our deferred cleanup upon request + static FDelegateHandle Clear = FCoreDelegates::GetMemoryTrimDelegate().AddLambda([]() + { + DeferredPhysResourceCleanup(); + }); + #endif // WITH_PHYSX } @@ -495,15 +499,10 @@ void TermGamePhys() } } - - -#if WITH_PHYSICS_COOKING || WITH_RUNTIME_PHYSICS_COOKING - if(GPhysXCooking != NULL) + if(IPhysXCookingModule* PhysXCookingModule = GetPhysXCookingModule()) { - GPhysXCooking->release(); - GPhysXCooking = NULL; + PhysXCookingModule->Terminate(); } -#endif if (GPhysXSDK != NULL) { diff --git a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysScene.cpp b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysScene.cpp index b35ae470d477..dd2bcddfa070 100644 --- a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysScene.cpp +++ b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysScene.cpp @@ -75,14 +75,12 @@ DECLARE_DWORD_COUNTER_STAT(TEXT("(ASync) Static Bodies"), STAT_NumStaticBodiesAs DECLARE_DWORD_COUNTER_STAT(TEXT("(ASync) Shapes"), STAT_NumShapesAsync, STATGROUP_Physics); static int16 PhysXSceneCount = 1; -static const int PhysXSlowRebuildRate = 10; EPhysicsSceneType FPhysScene::SceneType_AssumesLocked(const FBodyInstance* BodyInstance) const { #if WITH_PHYSX //This is a helper function for dynamic actors - static actors are in both scenes - check(BodyInstance->GetPxRigidBody_AssumesLocked()); - return UPhysicsSettings::Get()->bEnableAsyncScene && BodyInstance->UseAsyncScene(this) ? PST_Async : PST_Sync; + return HasAsyncScene() && BodyInstance->bUseAsyncScene ? PST_Async : PST_Sync; #endif return PST_Sync; @@ -154,22 +152,41 @@ FAutoConsoleTaskPriority CPrio_FPhysXTask_Cloth( DECLARE_STATS_GROUP(TEXT("PhysXTasks"), STATGROUP_PhysXTasks, STATCAT_Advanced); +struct FPhysXRingBuffer +{ + static const int32 Size = 16; + + PxBaseTask* Buffer[Size]; + int32 Start; + int32 End; + int32 Num; +}; + +int32 GBatchPhysXTasksSize = 3; //NOTE: FPhysXRingBuffer::Size should be twice as big as this value +TAutoConsoleVariable CVarBatchPhysXTasksSize(TEXT("p.BatchPhysXTasksSize"), GBatchPhysXTasksSize, TEXT("Number of tasks to batch together (max 8). 1 will go as wide as possible, but more overhead on small tasks"), ECVF_Default); + +struct FBatchPhysXTasks +{ + static void SetPhysXTasksSinkFunc() + { + GBatchPhysXTasksSize = FMath::Max(1, FMath::Min(FPhysXRingBuffer::Size / 2, CVarBatchPhysXTasksSize.GetValueOnGameThread())); + } +}; + +static FAutoConsoleVariableSink CVarBatchPhysXTasks(FConsoleCommandDelegate::CreateStatic(&FBatchPhysXTasks::SetPhysXTasksSinkFunc)); + + + +template +struct FPhysXCPUDispatcher; template class FPhysXTask { - PxBaseTask& Task; - public: - FPhysXTask(PxBaseTask* InTask) - : Task(*InTask) - { - } - - ~FPhysXTask() - { - Task.release(); - } + FPhysXTask(PxBaseTask& InTask, FPhysXCPUDispatcher& InDispatcher); + FPhysXTask(FPhysXRingBuffer& RingBuffer, FPhysXCPUDispatcher& InDispatcher); + ~FPhysXTask(); static FORCEINLINE TStatId GetStatId() { @@ -199,6 +216,22 @@ public: return ESubsequentsMode::TrackSubsequents; } + void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent); + + FPhysXRingBuffer RingBuffer; + FPhysXCPUDispatcher& Dispatcher; +private: + + struct FStatLookup + { + const char* StatName; + TStatId Stat; + }; + static FStatLookup Stats[100]; + + static int NumStats; + static FCriticalSection CS; + FORCEINLINE TStatId FindOrCreateStatId(const char* StatName) { #if STATS @@ -237,37 +270,114 @@ public: #endif // STATS return TStatId(); } +}; - void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent) +/** Used to dispatch physx tasks to task graph */ +template +struct FPhysXCPUDispatcher : public PxCpuDispatcher +{ + FPhysXCPUDispatcher() { -#if STATS - const char* StatName = Task.getName(); - FScopeCycleCounter CycleCounter(FindOrCreateStatId(StatName)); - - - FPlatformMisc::BeginNamedEvent(FColor::Black, StatName); -#endif - - Task.run(); - -#if STATS - FPlatformMisc::EndNamedEvent(); -#endif + check(IsInGameThread()); + TLSKey = FPlatformTLS::AllocTlsSlot(); } -private: - - struct FStatLookup + ~FPhysXCPUDispatcher() { - const char* StatName; - TStatId Stat; - }; - static FStatLookup Stats[100]; + check(IsInGameThread()); + FPlatformTLS::FreeTlsSlot(TLSKey); + } - static int NumStats; - static FCriticalSection CS; + virtual void submitTask(PxBaseTask& Task) override + { + if (IsInGameThread()) + { + //Game thread enqueues on task graph + TGraphTask>::CreateTask(NULL).ConstructAndDispatchWhenReady(Task, *this); + } + else + { + //See if we can use local queue + FPhysXRingBuffer& RingBuffer = *(FPhysXRingBuffer*)FPlatformTLS::GetTlsValue(TLSKey); + RingBuffer.Buffer[RingBuffer.End] = &Task; + RingBuffer.End = (RingBuffer.End + 1) % FPhysXRingBuffer::Size; + RingBuffer.Num++; + + if (RingBuffer.Num >= GBatchPhysXTasksSize * 2) + { + TGraphTask>::CreateTask(NULL).ConstructAndDispatchWhenReady(RingBuffer, *this); + } + } + } + + virtual PxU32 getWorkerCount() const override + { + return FTaskGraphInterface::Get().GetNumWorkerThreads(); + } + + uint32 TLSKey; }; +template +FPhysXTask::FPhysXTask(PxBaseTask& Task, FPhysXCPUDispatcher& InDispatcher) + : Dispatcher(InDispatcher) +{ + RingBuffer.Buffer[0] = &Task; + RingBuffer.Start = 0; + RingBuffer.End = 1; + RingBuffer.Num = 1; +} + +template +FPhysXTask::FPhysXTask(FPhysXRingBuffer& InRingBuffer, FPhysXCPUDispatcher& InDispatcher) + : Dispatcher(InDispatcher) +{ + int32 NumToSteal = InRingBuffer.Num / 2; + ensureMsgf(NumToSteal > 0, TEXT("Trying to steal 0 items")); + + const int32 StartPos = (InRingBuffer.Start + NumToSteal); + for (int32 Count = 0; Count < NumToSteal; ++Count) + { + RingBuffer.Buffer[Count] = InRingBuffer.Buffer[(StartPos + Count) % FPhysXRingBuffer::Size]; + } + + RingBuffer.Start = 0; + RingBuffer.End = NumToSteal; + RingBuffer.Num = NumToSteal; + + + InRingBuffer.Num -= NumToSteal; + InRingBuffer.End = (StartPos) % FPhysXRingBuffer::Size; +} + +template +FPhysXTask::~FPhysXTask() +{ + FPlatformTLS::SetTlsValue(Dispatcher.TLSKey, nullptr); +} + +template +void FPhysXTask::DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent) +{ + FPlatformTLS::SetTlsValue(Dispatcher.TLSKey, &RingBuffer); + + while (RingBuffer.Num) + { + PxBaseTask* Task = RingBuffer.Buffer[RingBuffer.Start]; + +#if STATS + const char* StatName = Task->getName(); + FScopeCycleCounter CycleCounter(FindOrCreateStatId(StatName)); +#endif + Task->run(); + Task->release(); + + RingBuffer.Start = (RingBuffer.Start + 1) % RingBuffer.Size; + --RingBuffer.Num; + + } +} + template<> int FPhysXTask::NumStats = 0; template<> int FPhysXTask::NumStats = 0; template<> FCriticalSection FPhysXTask::CS = {}; @@ -275,23 +385,6 @@ template<> FCriticalSection FPhysXTask::CS = {}; template<> FPhysXTask::FStatLookup FPhysXTask::Stats[100] = {}; template<> FPhysXTask::FStatLookup FPhysXTask::Stats[100] = {}; - -/** Used to dispatch physx tasks to task graph */ -template -class FPhysXCPUDispatcher : public PxCpuDispatcher -{ -public: - virtual void submitTask(PxBaseTask& Task) override - { - TGraphTask>::CreateTask(NULL).ConstructAndDispatchWhenReady(&Task); - } - - virtual PxU32 getWorkerCount() const override - { - return FTaskGraphInterface::Get().GetNumWorkerThreads(); - } -}; - DECLARE_CYCLE_STAT(TEXT("PhysX Single Thread Task"), STAT_PhysXSingleThread, STATGROUP_Physics); /** Used to dispatch physx tasks to the game thread */ @@ -337,6 +430,26 @@ TSharedPtr FPhysScene::SimEventCallbackFactory; #endif // WITH_PHYSX +static void StaticSetPhysXTreeRebuildRate(const TArray& Args, UWorld* World) +{ + if (Args.Num() > 0) + { + const int32 NewRate = FCString::Atoi(*Args[0]); + if(World && World->GetPhysicsScene()) + { + World->GetPhysicsScene()->SetPhysXTreeRebuildRate(NewRate); + } + } + else + { + UE_LOG(LogPhysics, Warning, TEXT("Usage: p.PhysXTreeRebuildRate ")); + } +} + +static FAutoConsoleCommandWithWorldAndArgs GSetPhysXTreeRebuildRate(TEXT("p.PhysXTreeRebuildRate"), TEXT("Utility function to change PhysXTreeRebuildRate, useful when profiling fetchResults vs scene queries."), + FConsoleCommandWithWorldAndArgsDelegate::CreateStatic(&StaticSetPhysXTreeRebuildRate) +); + /** Exposes creation of physics-engine scene outside Engine (for use with PhAT for example). */ FPhysScene::FPhysScene() @@ -359,6 +472,8 @@ FPhysScene::FPhysScene() bSubsteppingAsync = PhysSetting->bSubsteppingAsync; bAsyncSceneEnabled = PhysSetting->bEnableAsyncScene; NumPhysScenes = bAsyncSceneEnabled ? PST_Async + 1 : PST_Cloth + 1; + + PhysXTreeRebuildRate = PhysSetting->PhysXTreeRebuildRate; // Create scenes of all scene types for (uint32 SceneType = 0; SceneType < NumPhysScenes; ++SceneType) @@ -502,29 +617,24 @@ void FPhysScene::SetKinematicTarget_AssumesLocked(FBodyInstance* BodyInstance, c #if WITH_PHYSX if (PxRigidDynamic * PRigidDynamic = BodyInstance->GetPxRigidDynamic_AssumesLocked()) { - FTransform CurrentPose = P2UTransform(PRigidDynamic->getGlobalPose()); - if (!TargetTransform.EqualsNoScale(CurrentPose)) + const bool bIsKinematicTarget = IsRigidBodyKinematicAndInSimulationScene_AssumesLocked(PRigidDynamic); + if(bIsKinematicTarget) { - const bool bIsKinematicTarget = IsRigidBodyKinematicAndInSimulationScene_AssumesLocked(PRigidDynamic); - if(bIsKinematicTarget) + uint32 BodySceneType = SceneType_AssumesLocked(BodyInstance); + if (bAllowSubstepping && IsSubstepping(BodySceneType)) { - uint32 BodySceneType = SceneType_AssumesLocked(BodyInstance); - if (bAllowSubstepping && IsSubstepping(BodySceneType)) - { - FPhysSubstepTask * PhysSubStepper = PhysSubSteppers[BodySceneType]; - PhysSubStepper->SetKinematicTarget_AssumesLocked(BodyInstance, TargetTransform); - } + FPhysSubstepTask * PhysSubStepper = PhysSubSteppers[BodySceneType]; + PhysSubStepper->SetKinematicTarget_AssumesLocked(BodyInstance, TargetTransform); + } - const PxTransform PNewPose = U2PTransform(TargetTransform); - PRigidDynamic->setKinematicTarget(PNewPose); //If we interpolate, we will end up setting the kinematic target once per sub-step. However, for the sake of scene queries we should do this right away - } - else - { - const PxTransform PNewPose = U2PTransform(TargetTransform); - PRigidDynamic->setGlobalPose(PNewPose); - } + const PxTransform PNewPose = U2PTransform(TargetTransform); + PRigidDynamic->setKinematicTarget(PNewPose); //If we interpolate, we will end up setting the kinematic target once per sub-step. However, for the sake of scene queries we should do this right away + } + else + { + const PxTransform PNewPose = U2PTransform(TargetTransform); + PRigidDynamic->setGlobalPose(PNewPose); } - } #endif } @@ -639,7 +749,7 @@ void FPhysScene::RemoveActiveBody_AssumesLocked(FBodyInstance* BodyInstance, uin ActiveBodyInstances[SceneType][BodyIndex] = nullptr; } - PendingSleepEvents[SceneType].Remove(BodyInstance->GetPxRigidActor_AssumesLocked(SceneType)); + PendingSleepEvents[SceneType].Remove(BodyInstance->GetPxRigidActorFromScene_AssumesLocked(SceneType)); } #endif void FPhysScene::TermBody_AssumesLocked(FBodyInstance* BodyInstance) @@ -1224,9 +1334,9 @@ void FPhysScene::SyncComponentsToBodies_AssumesLocked(uint32 SceneType) // See if the transform is actually different, and if so, move the component to match physics const FTransform NewTransform = BodyInstance->GetUnrealWorldTransform_AssumesLocked(); - if (!NewTransform.EqualsNoScale(BodyInstance->OwnerComponent->ComponentToWorld)) + if (!NewTransform.EqualsNoScale(BodyInstance->OwnerComponent->GetComponentTransform())) { - const FVector MoveBy = NewTransform.GetLocation() - BodyInstance->OwnerComponent->ComponentToWorld.GetLocation(); + const FVector MoveBy = NewTransform.GetLocation() - BodyInstance->OwnerComponent->GetComponentTransform().GetLocation(); const FQuat NewRotation = NewTransform.GetRotation(); //@warning: do not reference BodyInstance again after calling MoveComponent() - events from the move could have made it unusable (destroying the actor, SetPhysics(), etc) @@ -1619,6 +1729,17 @@ void FPhysScene::EnsureCollisionTreeIsBuilt(UWorld* World) } void FPhysScene::SetIsStaticLoading(bool bStaticLoading) +{ + SetPhysXTreeRebuildRateImp(bStaticLoading ? 5 : PhysXTreeRebuildRate); +} + +void FPhysScene::SetPhysXTreeRebuildRate(int32 RebuildRate) +{ + PhysXTreeRebuildRate = FMath::Max(4, RebuildRate); + SetPhysXTreeRebuildRateImp(RebuildRate); +} + +void FPhysScene::SetPhysXTreeRebuildRateImp(int32 RebuildRate) { #if WITH_PHYSX // Loop through scene types to get all scenes @@ -1631,7 +1752,7 @@ void FPhysScene::SetIsStaticLoading(bool bStaticLoading) SCENE_LOCK_WRITE(PScene); // Sets the rebuild rate hint, to 1 frame if static loading - PScene->setDynamicTreeRebuildRateHint(bStaticLoading ? 5 : PhysXSlowRebuildRate); + PScene->setDynamicTreeRebuildRateHint(PhysXTreeRebuildRate); // Unlock scene lock, in case it is required SCENE_UNLOCK_WRITE(PScene); @@ -1644,15 +1765,24 @@ void FPhysScene::SetIsStaticLoading(bool bStaticLoading) /** Utility for looking up the PxScene associated with this FPhysScene. */ PxScene* FPhysScene::GetPhysXScene(uint32 SceneType) const { - check(SceneType < NumPhysScenes); - return GetPhysXSceneFromIndex(PhysXSceneIndex[SceneType]); + if(SceneType < NumPhysScenes) + { + return GetPhysXSceneFromIndex(PhysXSceneIndex[SceneType]); + } + + return nullptr; } #if WITH_APEX apex::Scene* FPhysScene::GetApexScene(uint32 SceneType) const { - check(SceneType < NumPhysScenes); - return GetApexSceneFromIndex(PhysXSceneIndex[SceneType]); + if(SceneType < NumPhysScenes) + { + return GetApexSceneFromIndex(PhysXSceneIndex[SceneType]); + } + + return nullptr; + } #endif // WITH_APEX @@ -1897,7 +2027,7 @@ void FPhysScene::InitPhysScene(uint32 SceneType) // Do this to improve loading times, esp. for streaming in sublevels PSceneDesc.staticStructure = PxPruningStructureType::eDYNAMIC_AABB_TREE; // Default to rebuilding tree slowly - PSceneDesc.dynamicTreeRebuildRateHint = PhysXSlowRebuildRate; + PSceneDesc.dynamicTreeRebuildRateHint = PhysXTreeRebuildRate; #if PHYSX_ENABLE_ENHANCED_DETERMINISM PSceneDesc.flags |= PxSceneFlag::eENABLE_ENHANCED_DETERMINISM; diff --git a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysUtils.cpp b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysUtils.cpp index 362fa697586d..44e90887596a 100644 --- a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysUtils.cpp +++ b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysUtils.cpp @@ -59,54 +59,50 @@ static bool ModelToHullsWorker(FKAggregateGeom* outGeom, bool bOutside, TArray &planes) { - FBspNode* node = &inModel->Nodes[nodeIx]; - if(node) + FBspNode& node = inModel->Nodes[nodeIx]; + // BACK + if (node.iBack != INDEX_NONE) // If there is a child, recurse into it. { - // BACK - if(node->iBack != INDEX_NONE) // If there is a child, recurse into it. + planes.Add(node.Plane); + if (!ModelToHullsWorker(outGeom, inModel, node.iBack, node.ChildOutside(0, bOutside), planes)) { - planes.Add(node->Plane); - if ( !ModelToHullsWorker(outGeom, inModel, node->iBack, node->ChildOutside(0, bOutside), planes) ) - { - return false; - } - planes.RemoveAt(planes.Num()-1); + return false; } - else if(!node->ChildOutside(0, bOutside)) // If its a leaf, and solid (inside) + planes.RemoveAt(planes.Num() - 1); + } + else if (!node.ChildOutside(0, bOutside)) // If its a leaf, and solid (inside) + { + planes.Add(node.Plane); + if (!AddConvexPrim(outGeom, planes, inModel)) { - planes.Add(node->Plane); - if ( !AddConvexPrim(outGeom, planes, inModel) ) - { - return false; - } - planes.RemoveAt(planes.Num()-1); + return false; } + planes.RemoveAt(planes.Num() - 1); + } - // FRONT - if(node->iFront != INDEX_NONE) + // FRONT + if (node.iFront != INDEX_NONE) + { + planes.Add(node.Plane.Flip()); + if (!ModelToHullsWorker(outGeom, inModel, node.iFront, node.ChildOutside(1, bOutside), planes)) { - planes.Add(node->Plane.Flip()); - if ( !ModelToHullsWorker(outGeom, inModel, node->iFront, node->ChildOutside(1, bOutside), planes) ) - { - return false; - } - planes.RemoveAt(planes.Num()-1); + return false; } - else if(!node->ChildOutside(1, bOutside)) + planes.RemoveAt(planes.Num() - 1); + } + else if (!node.ChildOutside(1, bOutside)) + { + planes.Add(node.Plane.Flip()); + if (!AddConvexPrim(outGeom, planes, inModel)) { - planes.Add(node->Plane.Flip()); - if ( !AddConvexPrim(outGeom, planes, inModel) ) - { - return false; - } - planes.RemoveAt(planes.Num()-1); + return false; } + planes.RemoveAt(planes.Num() - 1); } return true; } -#if WITH_RUNTIME_PHYSICS_COOKING || WITH_EDITOR void UBodySetup::CreateFromModel(UModel* InModel, bool bRemoveExisting) { if ( bRemoveExisting ) @@ -130,7 +126,6 @@ void UBodySetup::CreateFromModel(UModel* InModel, bool bRemoveExisting) // Create new GUID InvalidatePhysicsData(); } -#endif // WITH_RUNTIME_PHYSICS_COOKING || WITH_EDITOR ////////////////////////////////////////////////////////////////////////// // FRigidBodyCollisionInfo @@ -595,11 +590,15 @@ bool ExecPhysCommands(const TCHAR* Cmd, FOutputDevice* Ar, UWorld* InWorld) #else Ar->Logf(TEXT(" Configuration: PROFILE")); #endif -#if WITH_PHYSICS_COOKING || WITH_RUNTIME_PHYSICS_COOKING - Ar->Logf(TEXT(" Cooking Module: TRUE")); -#else - Ar->Logf(TEXT(" Cooking Module: FALSE")); -#endif + if(GetPhysXCookingModule()) + { + Ar->Logf(TEXT(" Cooking Module: TRUE")); + } + else + { + Ar->Logf(TEXT(" Cooking Module: FALSE")); + } + return 1; } diff --git a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysXLibs.cpp b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysXLibs.cpp index 988d89a2c135..db625c80fc2d 100644 --- a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysXLibs.cpp +++ b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysXLibs.cpp @@ -13,6 +13,7 @@ #if WITH_PHYSX // PhysX library imports + #if PLATFORM_WINDOWS || PLATFORM_MAC @@ -20,9 +21,7 @@ void* PhysX3CommonHandle = nullptr; void* PhysX3Handle = nullptr; void* PxPvdSDKHandle = nullptr; - #if WITH_PHYSICS_COOKING || WITH_RUNTIME_PHYSICS_COOKING - void* PhysX3CookingHandle = nullptr; - #endif + void* PhysX3CookingHandle = nullptr; void* nvToolsExtHandle = nullptr; #if WITH_APEX void* APEXFrameworkHandle = nullptr; @@ -37,10 +36,8 @@ /** * Load the required modules for PhysX */ -ENGINE_API void LoadPhysXModules() +ENGINE_API void LoadPhysXModules(bool bLoadCookingModule) { - - #if PLATFORM_WINDOWS FString PhysXBinariesRoot = FPaths::EngineDir() / TEXT("Binaries/ThirdParty/PhysX/"); FString APEXBinariesRoot = FPaths::EngineDir() / TEXT("Binaries/ThirdParty/PhysX/"); @@ -98,9 +95,11 @@ ENGINE_API void LoadPhysXModules() PxPvdSDKHandle = LoadPhysicsLibrary(RootSharedPath + "PxPvdSDK" + PhysXSuffix); PhysX3Handle = LoadPhysicsLibrary(RootPhysXPath + "PhysX3" + PhysXSuffix); - #if WITH_PHYSICS_COOKING || WITH_RUNTIME_PHYSICS_COOKING + if(bLoadCookingModule) + { PhysX3CookingHandle = LoadPhysicsLibrary(RootPhysXPath + "PhysX3Cooking" + PhysXSuffix); - #endif + } + #if WITH_APEX APEXFrameworkHandle = LoadPhysicsLibrary(RootAPEXPath + "APEXFramework" + APEXSuffix); APEX_DestructibleHandle = LoadPhysicsLibrary(RootAPEXPath + "APEX_Destructible" + APEXSuffix); @@ -148,10 +147,12 @@ ENGINE_API void LoadPhysXModules() const FString PhysX3LibName = FString::Printf(TEXT("%slibPhysX3%s"), *PhysXBinariesRoot, *PhysXSuffix); PhysX3Handle = LoadPhysicsLibrary(PhysX3LibName); - #if WITH_PHYSICS_COOKING || WITH_RUNTIME_PHYSICS_COOKING + if(bLoadCookingModule) + { const FString PhysX3CookinLibName = FString::Printf(TEXT("%slibPhysX3Cooking%s"), *PhysXBinariesRoot, *PhysXSuffix); PhysX3CookingHandle = LoadPhysicsLibrary(PhysX3CookinLibName); - #endif + } + #if WITH_APEX const FString APEXFrameworkLibName = FString::Printf(TEXT("%slibAPEXFramework%s"), *PhysXBinariesRoot, *APEXSuffix); APEXFrameworkHandle = LoadPhysicsLibrary(APEXFrameworkLibName); @@ -177,9 +178,10 @@ void UnloadPhysXModules() #if PLATFORM_WINDOWS || PLATFORM_MAC FPlatformProcess::FreeDllHandle(PxPvdSDKHandle); FPlatformProcess::FreeDllHandle(PhysX3Handle); - #if WITH_PHYSICS_COOKING || WITH_RUNTIME_PHYSICS_COOKING + if(PhysX3CookingHandle) + { FPlatformProcess::FreeDllHandle(PhysX3CookingHandle); - #endif + } FPlatformProcess::FreeDllHandle(PhysX3CommonHandle); FPlatformProcess::FreeDllHandle(PxFoundationHandle); #if WITH_APEX diff --git a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysXSupport.cpp b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysXSupport.cpp index d1c9d5d71db9..2bc47d6f80f9 100644 --- a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysXSupport.cpp +++ b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysXSupport.cpp @@ -20,9 +20,6 @@ PxFoundation* GPhysXFoundation = NULL; PxPvd* GPhysXVisualDebugger = NULL; PxPhysics* GPhysXSDK = NULL; -#if WITH_PHYSICS_COOKING || WITH_RUNTIME_PHYSICS_COOKING -PxCooking* GPhysXCooking = NULL; -#endif FPhysXAllocator* GPhysXAllocator = NULL; #if WITH_APEX @@ -575,9 +572,9 @@ void FPhysXSimEventCallback::onSleep(PxActor** Actors, PxU32 Count) ////////////////////////////////////////////////////////////////////////// -// FPhysXFormatDataReader +// FPhysXCookingDataReader -FPhysXFormatDataReader::FPhysXFormatDataReader( FByteBulkData& InBulkData, FBodySetupUVInfo* UVInfo ) +FPhysXCookingDataReader::FPhysXCookingDataReader( FByteBulkData& InBulkData, FBodySetupUVInfo* UVInfo ) { // Read cooked physics data uint8* DataPtr = (uint8*)InBulkData.Lock( LOCK_READ_ONLY ); @@ -622,7 +619,7 @@ FPhysXFormatDataReader::FPhysXFormatDataReader( FByteBulkData& InBulkData, FBody InBulkData.Unlock(); } -PxConvexMesh* FPhysXFormatDataReader::ReadConvexMesh( FBufferReader& Ar, uint8* InBulkDataPtr, int32 InBulkDataSize ) +PxConvexMesh* FPhysXCookingDataReader::ReadConvexMesh( FBufferReader& Ar, uint8* InBulkDataPtr, int32 InBulkDataSize ) { PxConvexMesh* CookedMesh = NULL; uint8 IsMeshCooked = false; @@ -637,7 +634,7 @@ PxConvexMesh* FPhysXFormatDataReader::ReadConvexMesh( FBufferReader& Ar, uint8* return CookedMesh; } -PxTriangleMesh* FPhysXFormatDataReader::ReadTriMesh( FBufferReader& Ar, uint8* InBulkDataPtr, int32 InBulkDataSize ) +PxTriangleMesh* FPhysXCookingDataReader::ReadTriMesh( FBufferReader& Ar, uint8* InBulkDataPtr, int32 InBulkDataSize ) { FPhysXInputStream Buffer( InBulkDataPtr + Ar.Tell(), InBulkDataSize - Ar.Tell() ); PxTriangleMesh* CookedMesh = GPhysXSDK->createTriangleMesh(Buffer); diff --git a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysXSupport.h b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysXSupport.h index 0e319fed092a..ad2cfdd01e76 100644 --- a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysXSupport.h +++ b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysXSupport.h @@ -112,10 +112,14 @@ inline bool IsRigidBodyNonKinematic(PxRigidBody* PRigidBody) /////// GLOBAL POINTERS /** Pointer to PhysX Foundation singleton */ -extern PxFoundation* GPhysXFoundation; +extern ENGINE_API PxFoundation* GPhysXFoundation; /** Pointer to PhysX debugger */ extern PxPvd* GPhysXVisualDebugger; +extern ENGINE_API TAutoConsoleVariable CVarToleranceScaleLength; + +extern ENGINE_API TAutoConsoleVariable CVarToleranceScaleSpeed; + #if WITH_APEX /** * Map from SceneIndex to actual ApexScene. This indirection allows us to set it to null when we kill the scene, @@ -229,14 +233,14 @@ public: }; /** Utility class for reading cooked physics data. */ -class FPhysXFormatDataReader +class FPhysXCookingDataReader { public: TArray ConvexMeshes; TArray ConvexMeshesNegX; TArray TriMeshes; - FPhysXFormatDataReader( FByteBulkData& InBulkData, struct FBodySetupUVInfo* UVInfo ); + FPhysXCookingDataReader( FByteBulkData& InBulkData, struct FBodySetupUVInfo* UVInfo ); private: diff --git a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsConstraintActor.cpp b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsConstraintActor.cpp index ad07d90d87bd..1c239747b81e 100644 --- a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsConstraintActor.cpp +++ b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsConstraintActor.cpp @@ -67,5 +67,3 @@ void APhysicsConstraintActor::LoadedFromAnotherClass( const FName& OldClassName } #endif // WITH_EDITOR -/** Returns ConstraintComp subobject **/ -UPhysicsConstraintComponent* APhysicsConstraintActor::GetConstraintComp() const { return ConstraintComp; } diff --git a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsConstraintComponent.cpp b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsConstraintComponent.cpp index f4340f316bf6..44bc21b5d768 100644 --- a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsConstraintComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsConstraintComponent.cpp @@ -137,8 +137,8 @@ FTransform UPhysicsConstraintComponent::GetBodyTransformInternal(EConstraintFram return FTransform::Identity; } - //Use ComponentToWorld by default for all components - FTransform ResultTM = PrimComp->ComponentToWorld; + //Use GetComponentTransform() by default for all components + FTransform ResultTM = PrimComp->GetComponentTransform(); // Skeletal case if(const USkeletalMeshComponent* SkelComp = Cast(PrimComp)) @@ -392,64 +392,7 @@ void UPhysicsConstraintComponent::PostLoad() #if WITH_EDITOR void UPhysicsConstraintComponent::PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent) { - static const FName StiffnessName = GET_MEMBER_NAME_CHECKED(FConstraintDrive, Stiffness); - static const FName MaxForceName = GET_MEMBER_NAME_CHECKED(FConstraintDrive, MaxForce); - static const FName DampingName = GET_MEMBER_NAME_CHECKED(FConstraintDrive, Damping); - - if (TDoubleLinkedList::TDoubleLinkedListNode* PropertyNode = PropertyChangedEvent.PropertyChain.GetTail()) - { - if (TDoubleLinkedList::TDoubleLinkedListNode* ParentProeprtyNode = PropertyNode->GetPrevNode()) - { - if (UProperty* Property = PropertyNode->GetValue()) - { - if (UProperty* ParentProperty = ParentProeprtyNode->GetValue()) - { - const FName PropertyName = Property->GetFName(); - const FName ParentPropertyName = ParentProperty->GetFName(); - - if (ParentPropertyName == GET_MEMBER_NAME_CHECKED(FLinearDriveConstraint, XDrive)) - { - FLinearDriveConstraint& LinearDriveConstraint = ConstraintInstance.ProfileInstance.LinearDrive; - if (StiffnessName == PropertyName) - { - LinearDriveConstraint.YDrive.Stiffness = LinearDriveConstraint.XDrive.Stiffness; - LinearDriveConstraint.ZDrive.Stiffness = LinearDriveConstraint.XDrive.Stiffness; - } - else if (MaxForceName == PropertyName) - { - LinearDriveConstraint.YDrive.MaxForce = LinearDriveConstraint.XDrive.MaxForce; - LinearDriveConstraint.ZDrive.MaxForce = LinearDriveConstraint.XDrive.MaxForce; - } - else if (DampingName == PropertyName) - { - LinearDriveConstraint.YDrive.Damping = LinearDriveConstraint.XDrive.Damping; - LinearDriveConstraint.ZDrive.Damping = LinearDriveConstraint.XDrive.Damping; - } - } - else if (ParentPropertyName == GET_MEMBER_NAME_CHECKED(FAngularDriveConstraint, SlerpDrive)) - { - FAngularDriveConstraint& AngularDriveConstraint = ConstraintInstance.ProfileInstance.AngularDrive; - if (StiffnessName == PropertyName) - { - AngularDriveConstraint.SwingDrive.Stiffness = AngularDriveConstraint.SlerpDrive.Stiffness; - AngularDriveConstraint.TwistDrive.Stiffness = AngularDriveConstraint.SlerpDrive.Stiffness; - } - else if (MaxForceName == PropertyName) - { - AngularDriveConstraint.SwingDrive.MaxForce = AngularDriveConstraint.SlerpDrive.MaxForce; - AngularDriveConstraint.TwistDrive.MaxForce = AngularDriveConstraint.SlerpDrive.MaxForce; - } - else if (DampingName == PropertyName) - { - AngularDriveConstraint.SwingDrive.Damping = AngularDriveConstraint.SlerpDrive.Damping; - AngularDriveConstraint.TwistDrive.Damping = AngularDriveConstraint.SlerpDrive.Damping; - } - } - } - } - } - } - + ConstraintInstance.ProfileInstance.SyncChangedConstraintProperties(PropertyChangedEvent); Super::PostEditChangeChainProperty(PropertyChangedEvent); } @@ -524,8 +467,8 @@ void UPhysicsConstraintComponent::UpdateConstraintFrames() // World ref frame const FVector WPos = GetComponentLocation(); - const FVector WPri = ComponentToWorld.GetUnitAxis( EAxis::X ); - const FVector WOrth = ComponentToWorld.GetUnitAxis( EAxis::Y ); + const FVector WPri = GetComponentTransform().GetUnitAxis( EAxis::X ); + const FVector WOrth = GetComponentTransform().GetUnitAxis( EAxis::Y ); ConstraintInstance.Pos1 = A1Transform.InverseTransformPosition(WPos); ConstraintInstance.PriAxis1 = A1Transform.InverseTransformVectorNoScale(WPri); @@ -533,8 +476,8 @@ void UPhysicsConstraintComponent::UpdateConstraintFrames() const FVector RotatedX = ConstraintInstance.AngularRotationOffset.RotateVector(FVector(1,0,0)); const FVector RotatedY = ConstraintInstance.AngularRotationOffset.RotateVector(FVector(0,1,0)); - const FVector WPri2 = ComponentToWorld.TransformVectorNoScale(RotatedX); - const FVector WOrth2 = ComponentToWorld.TransformVectorNoScale(RotatedY); + const FVector WPri2 = GetComponentTransform().TransformVectorNoScale(RotatedX); + const FVector WOrth2 = GetComponentTransform().TransformVectorNoScale(RotatedY); ConstraintInstance.Pos2 = A2Transform.InverseTransformPosition(WPos); diff --git a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsConstraintTemplate.cpp b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsConstraintTemplate.cpp index 1907034686f8..8455770f80f6 100644 --- a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsConstraintTemplate.cpp +++ b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsConstraintTemplate.cpp @@ -62,6 +62,12 @@ void UPhysicsConstraintTemplate::Serialize(FArchive& Ar) } #if WITH_EDITOR +void UPhysicsConstraintTemplate::PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent) +{ + DefaultInstance.ProfileInstance.SyncChangedConstraintProperties(PropertyChangedEvent); + Super::PostEditChangeChainProperty(PropertyChangedEvent); +} + void UPhysicsConstraintTemplate::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) { //If anything changes, update the profile instance diff --git a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsSerializer.cpp b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsSerializer.cpp index eaa6b2eeed2f..b18bc43b23cf 100644 --- a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsSerializer.cpp +++ b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsSerializer.cpp @@ -39,7 +39,8 @@ FByteBulkData* UPhysicsSerializer::GetBinaryData(FName Format, const TArray OutData; - FDerivedDataPhysXBinarySerializer* DerivedPhysXSerializer = new FDerivedDataPhysXBinarySerializer(Format, Bodies, BodySetups, PhysicalMaterials, FGuid::NewGuid()); //TODO: Maybe it's worth adding this to the DDC. For now there's a lot of complexity with the guid invalidation so I've left it out. + // Changed from raw pointer to unique pointer to fix static analysis warning, but unclear if this code path is used anymore. + TUniquePtr DerivedPhysXSerializer(new FDerivedDataPhysXBinarySerializer(Format, Bodies, BodySetups, PhysicalMaterials, FGuid::NewGuid())); //TODO: Maybe it's worth adding this to the DDC. For now there's a lot of complexity with the guid invalidation so I've left it out. if (DerivedPhysXSerializer->CanBuild()) { diff --git a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsSettings.cpp b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsSettings.cpp index 94db3b70082c..c6617fd58f0b 100644 --- a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsSettings.cpp +++ b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsSettings.cpp @@ -38,6 +38,7 @@ UPhysicsSettings::UPhysicsSettings(const FObjectInitializer& ObjectInitializer) , SyncSceneSmoothingFactor(0.0f) , AsyncSceneSmoothingFactor(0.99f) , InitialAverageFrameRate(1.f / 60.f) + , PhysXTreeRebuildRate(10) { SectionName = TEXT("Physics"); } diff --git a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsSpring.cpp b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsSpring.cpp index 4f0091e2e3fc..20f758c827ff 100644 --- a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsSpring.cpp +++ b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsSpring.cpp @@ -27,12 +27,12 @@ UPhysicsSpringComponent::UPhysicsSpringComponent(const FObjectInitializer& Objec } FVector UPhysicsSpringComponent::SpringPositionFromLength(float Length) const { - return ComponentToWorld.GetLocation() + Length * GetSpringDirection(); + return GetComponentTransform().GetLocation() + Length * GetSpringDirection(); } FVector UPhysicsSpringComponent::GetSpringDirection() const { - return ComponentToWorld.TransformVectorNoScale(FVector(1.f, 0.f, 0.f)); + return GetComponentTransform().TransformVectorNoScale(FVector(1.f, 0.f, 0.f)); } float UPhysicsSpringComponent::GetNormalizedCompressionScalar() const @@ -57,8 +57,7 @@ UPrimitiveComponent* UPhysicsSpringComponent::GetSpringCollision(const FVector& UWorld* World = GetWorld(); AActor* IgnoreActor = bIgnoreSelf ? GetOwner() : nullptr; - static FName NAME_Spring = FName(TEXT("SpringComponent")); - FCollisionQueryParams QueryParams(NAME_Spring, true, IgnoreActor); + FCollisionQueryParams QueryParams(SCENE_QUERY_STAT(SpringComponent), true, IgnoreActor); FHitResult Hit; UPrimitiveComponent* CollidedComponent = nullptr; @@ -104,7 +103,7 @@ void UPhysicsSpringComponent::TickComponent(float DeltaTime, enum ELevelTick Tic { if (bIsActive) { - const FVector SpringStart = ComponentToWorld.GetLocation(); + const FVector SpringStart = GetComponentTransform().GetLocation(); const FVector SpringDesiredEnd = SpringPositionFromLength(SpringLengthAtRest); float CollisionTime = 1.f; diff --git a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsThruster.cpp b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsThruster.cpp index 10e37ee0a518..1c9de302d253 100644 --- a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsThruster.cpp +++ b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsThruster.cpp @@ -45,7 +45,7 @@ void UPhysicsThrusterComponent::TickComponent(float DeltaTime, enum ELevelTick T // Applied force to the base, so if we don't have one, do nothing. if( bIsActive && GetAttachParent()) { - FVector WorldForce = ThrustStrength * ComponentToWorld.TransformVectorNoScale( FVector(-1.f,0.f,0.f) ); + FVector WorldForce = ThrustStrength * GetComponentTransform().TransformVectorNoScale( FVector(-1.f,0.f,0.f) ); UPrimitiveComponent* BasePrimComp = Cast(GetAttachParent()); if(BasePrimComp) @@ -83,11 +83,4 @@ APhysicsThruster::APhysicsThruster(const FObjectInitializer& ObjectInitializer) #endif // WITH_EDITORONLY_DATA } -/** Returns ThrusterComponent subobject **/ -UPhysicsThrusterComponent* APhysicsThruster::GetThrusterComponent() const { return ThrusterComponent; } -#if WITH_EDITORONLY_DATA -/** Returns ArrowComponent subobject **/ -UArrowComponent* APhysicsThruster::GetArrowComponent() const { return ArrowComponent; } -#endif - #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/RadialForceComponent.cpp b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/RadialForceComponent.cpp index f370084f55ca..82b1cfb1952f 100644 --- a/Engine/Source/Runtime/Engine/Private/PhysicsEngine/RadialForceComponent.cpp +++ b/Engine/Source/Runtime/Engine/Private/PhysicsEngine/RadialForceComponent.cpp @@ -42,10 +42,9 @@ void URadialForceComponent::TickComponent(float DeltaTime, enum ELevelTick TickT const FVector Origin = GetComponentLocation(); // Find objects within the sphere - static FName AddForceOverlapName = FName(TEXT("AddForceOverlap")); TArray Overlaps; - FCollisionQueryParams Params(AddForceOverlapName, false); + FCollisionQueryParams Params(SCENE_QUERY_STAT(AddForceOverlap), false); Params.bTraceAsyncScene = true; // want to hurt stuff in async scene // Ignore owner actor if desired @@ -112,10 +111,9 @@ void URadialForceComponent::FireImpulse() const FVector Origin = GetComponentLocation(); // Find objects within the sphere - static FName FireImpulseOverlapName = FName(TEXT("FireImpulseOverlap")); TArray Overlaps; - FCollisionQueryParams Params(FireImpulseOverlapName, false); + FCollisionQueryParams Params(SCENE_QUERY_STAT(FireImpulseOverlap), false); Params.bTraceAsyncScene = true; // want to hurt stuff in async scene // Ignore owner actor if desired @@ -307,12 +305,4 @@ void ARadialForceActor::ToggleForce() { ForceComponent->ToggleActive(); } -} - - -/** Returns ForceComponent subobject **/ -URadialForceComponent* ARadialForceActor::GetForceComponent() const { return ForceComponent; } -#if WITH_EDITORONLY_DATA -/** Returns SpriteComponent subobject **/ -UBillboardComponent* ARadialForceActor::GetSpriteComponent() const { return SpriteComponent; } -#endif +} \ No newline at end of file diff --git a/Engine/Source/Runtime/Engine/Private/PhysicsEngine2D/Box2DIntegration.cpp b/Engine/Source/Runtime/Engine/Private/PhysicsEngine2D/Box2DIntegration.cpp index afd67c152f7a..0163589347df 100644 --- a/Engine/Source/Runtime/Engine/Private/PhysicsEngine2D/Box2DIntegration.cpp +++ b/Engine/Source/Runtime/Engine/Private/PhysicsEngine2D/Box2DIntegration.cpp @@ -243,7 +243,7 @@ void FStartPhysics2DTickFunction::ExecuteTick(float DeltaTime, enum ELevelTick T { // See if the transform is actually different, and if so, move the component to match physics const FTransform NewTransform = UnrealBodyInstance->GetUnrealWorldTransform(); - const FTransform& OldTransform = UnrealBodyInstance->OwnerComponent->ComponentToWorld; + const FTransform& OldTransform = UnrealBodyInstance->OwnerComponent->GetComponentTransform(); if (!NewTransform.Equals(OldTransform)) { const FVector MoveBy = NewTransform.GetLocation() - OldTransform.GetLocation(); diff --git a/Engine/Source/Runtime/Engine/Private/PlanarReflectionSceneProxy.cpp b/Engine/Source/Runtime/Engine/Private/PlanarReflectionSceneProxy.cpp index 482399e6ec29..9a76648e0039 100644 --- a/Engine/Source/Runtime/Engine/Private/PlanarReflectionSceneProxy.cpp +++ b/Engine/Source/Runtime/Engine/Private/PlanarReflectionSceneProxy.cpp @@ -41,7 +41,7 @@ FPlanarReflectionSceneProxy::FPlanarReflectionSceneProxy(UPlanarReflectionCompon OwnerName = Component->GetOwner() ? Component->GetOwner()->GetFName() : NAME_None; - UpdateTransform(Component->ComponentToWorld.ToMatrixWithScale()); + UpdateTransform(Component->GetComponentTransform().ToMatrixWithScale()); PlanarReflectionId = Component->GetPlanarReflectionId(); PrefilterRoughness = Component->PrefilterRoughness; diff --git a/Engine/Source/Runtime/Engine/Private/PlayerCameraManager.cpp b/Engine/Source/Runtime/Engine/Private/PlayerCameraManager.cpp index 2c434f3d1ab0..5298bda65f4e 100644 --- a/Engine/Source/Runtime/Engine/Private/PlayerCameraManager.cpp +++ b/Engine/Source/Runtime/Engine/Private/PlayerCameraManager.cpp @@ -59,6 +59,8 @@ APlayerCameraManager::APlayerCameraManager(const FObjectInitializer& ObjectIniti DefaultModifiers.Add(UCameraModifier_CameraShake::StaticClass()); } +/// @cond DOXYGEN_WARNINGS + void APlayerCameraManager::PhotographyCameraModify_Implementation(const FVector NewCameraLocation, const FVector PreviousCameraLocation, const FVector OriginalCameraLocation, FVector& OutCameraLocation) { // let proposed camera through unmodified by default OutCameraLocation = NewCameraLocation; @@ -80,6 +82,8 @@ void APlayerCameraManager::OnPhotographyMultiPartCaptureEnd_Implementation() { // do nothing by default } +/// @endcond + APlayerController* APlayerCameraManager::GetOwningPlayerController() const { @@ -523,7 +527,7 @@ void APlayerCameraManager::UpdateViewTarget(FTViewTarget& OutVT, float DeltaTime } FVector Pos = Loc + ViewTargetOffset + FRotationMatrix(Rotator).TransformVector(FreeCamOffset) - Rotator.Vector() * FreeCamDistance; - FCollisionQueryParams BoxParams(NAME_FreeCam, false, this); + FCollisionQueryParams BoxParams(SCENE_QUERY_STAT(FreeCam), false, this); BoxParams.AddIgnoredActor(OutVT.Target); FHitResult Result; @@ -1430,6 +1434,3 @@ void FTViewTarget::CheckViewTarget(APlayerController* OwningController) } } } - -/** Returns TransformComponent subobject **/ -USceneComponent* APlayerCameraManager::GetTransformComponent() const { return TransformComponent; } diff --git a/Engine/Source/Runtime/Engine/Private/PlayerController.cpp b/Engine/Source/Runtime/Engine/Private/PlayerController.cpp index 18d204773bee..b084028853a7 100644 --- a/Engine/Source/Runtime/Engine/Private/PlayerController.cpp +++ b/Engine/Source/Runtime/Engine/Private/PlayerController.cpp @@ -207,6 +207,7 @@ void APlayerController::FailedToSpawnPawn() ClientGotoState(NAME_Inactive); } +/// @cond DOXYGEN_WARNINGS void APlayerController::ClientUpdateLevelStreamingStatus_Implementation(FName PackageName, bool bNewShouldBeLoaded, bool bNewShouldBeVisible, bool bNewShouldBlockOnLoad, int32 LODIndex ) { @@ -375,6 +376,8 @@ void APlayerController::ClientAddTextureStreamingLoc_Implementation(FVector InLo } } +/// @endcond + void APlayerController::SetNetSpeed(int32 NewSpeed) { UNetDriver* Driver = GetWorld()->GetNetDriver(); @@ -539,6 +542,8 @@ UInterpTrackInstDirector* APlayerController::GetControllingDirector() return ControllingDirTrackInst; } +/// @cond DOXYGEN_WARNINGS + bool APlayerController::ServerNotifyLoadedWorld_Validate(FName WorldPackageName) { RPC_VALIDATE( WorldPackageName.IsValid() ); @@ -575,6 +580,8 @@ void APlayerController::ServerNotifyLoadedWorld_Implementation(FName WorldPackag } } +/// @cond DOXYGEN_WARNINGS + bool APlayerController::HasClientLoadedCurrentWorld() { UNetConnection* Connection = Cast(Player); @@ -685,6 +692,8 @@ void APlayerController::SafeRetryClientRestart() } +/// @cond DOXYGEN_WARNINGS + /** Avoid calling ClientRestart if we have already accepted this pawn */ void APlayerController::ClientRetryClientRestart_Implementation(APawn* NewPawn) { @@ -746,6 +755,8 @@ void APlayerController::ClientRestart_Implementation(APawn* NewPawn) } } +/// @endcond + void APlayerController::Possess(APawn* PawnToPossess) { if (!HasAuthority()) @@ -966,6 +977,8 @@ void APlayerController::PostInitializeComponents() StateName = NAME_Spectating; // Don't use ChangeState, because we want to defer spawning the SpectatorPawn until the Player is received } +/// @cond DOXYGEN_WARNINGS + bool APlayerController::ServerShortTimeout_Validate() { return true; @@ -1016,6 +1029,8 @@ void APlayerController::ServerShortTimeout_Implementation() } } +/// @cond DOXYGEN_WARNINGS + void APlayerController::AddCheats(bool bForce) { UWorld* World = GetWorld(); @@ -1146,6 +1161,8 @@ void APlayerController::Reset() ChangeState(NAME_Spectating); } +/// @cond DOXYGEN_WARNINGS + void APlayerController::ClientReset_Implementation() { ResetCameraMode(); @@ -1160,6 +1177,9 @@ void APlayerController::ClientGotoState_Implementation(FName NewState) ChangeState(NewState); } +/// @endcond + + void APlayerController::UnFreeze() {} bool APlayerController::IsFrozen() @@ -1167,6 +1187,8 @@ bool APlayerController::IsFrozen() return GetWorldTimerManager().IsTimerActive(TimerHandle_UnFreeze); } +/// @cond DOXYGEN_WARNINGS + void APlayerController::ServerAcknowledgePossession_Implementation(APawn* P) { UE_LOG(LogPlayerController, Verbose, TEXT("ServerAcknowledgePossession_Implementation %s"), *GetNameSafe(P)); @@ -1183,6 +1205,8 @@ bool APlayerController::ServerAcknowledgePossession_Validate(APawn* P) return true; } +/// @endcond + void APlayerController::UnPossess() { if (GetPawn() != NULL) @@ -1201,6 +1225,8 @@ void APlayerController::UnPossess() SetPawn(NULL); } +/// @cond DOXYGEN_WARNINGS + void APlayerController::ClientSetHUD_Implementation(TSubclassOf NewHUDClass) { if ( MyHUD != NULL ) @@ -1218,6 +1244,8 @@ void APlayerController::ClientSetHUD_Implementation(TSubclassOf NewHUDClas MyHUD = GetWorld()->SpawnActor(NewHUDClass, SpawnInfo ); } +/// @endcond + void APlayerController::CleanupPlayerState() { if (PlayerState) @@ -1291,6 +1319,8 @@ void APlayerController::OnNetCleanup(UNetConnection* Connection) UNetConnection::GNetConnectionBeingCleanedUp = NULL; } +/// @cond DOXYGEN_WARNINGS + void APlayerController::ClientReceiveLocalizedMessage_Implementation( TSubclassOf Message, int32 Switch, APlayerState* RelatedPlayerState_1, APlayerState* RelatedPlayerState_2, UObject* OptionalObject ) { // Wait for player to be up to date with replication when joining a server, before stacking up messages @@ -1368,6 +1398,8 @@ void APlayerController::ServerToggleAILogging_Implementation() } } +/// @endcond + void APlayerController::PawnLeavingGame() { if (GetPawn() != NULL) @@ -1497,6 +1529,8 @@ void APlayerController::Camera( FName NewMode ) ServerCamera(NewMode); } +/// @cond DOXYGEN_WARNINGS + void APlayerController::ServerCamera_Implementation( FName NewMode ) { SetCameraMode(NewMode); @@ -1516,6 +1550,7 @@ void APlayerController::ClientSetCameraMode_Implementation( FName NewCamMode ) } } +/// @endcond void APlayerController::SetCameraMode( FName NewCamMode ) { @@ -1541,6 +1576,8 @@ void APlayerController::ResetCameraMode() SetCameraMode(DefaultMode); } +/// @cond DOXYGEN_WARNINGS + void APlayerController::ClientSetCameraFade_Implementation(bool bEnableFading, FColor FadeColor, FVector2D FadeAlpha, float FadeTime, bool bFadeAudio) { if (PlayerCameraManager != nullptr) @@ -1556,6 +1593,8 @@ void APlayerController::ClientSetCameraFade_Implementation(bool bEnableFading, F } } +/// @endcond + void APlayerController::SendClientAdjustment() { if (AcknowledgedPawn != GetPawn() && !GetSpectatorPawn()) @@ -1576,6 +1615,7 @@ void APlayerController::SendClientAdjustment() } } +/// @cond DOXYGEN_WARNINGS void APlayerController::ClientCapBandwidth_Implementation(int32 Cap) { @@ -1586,6 +1626,7 @@ void APlayerController::ClientCapBandwidth_Implementation(int32 Cap) } } +/// @endcond void APlayerController::UpdatePing(float InPing) { @@ -1613,6 +1654,7 @@ void APlayerController::SetInitialLocationAndRotation(const FVector& NewLocation } } +/// @cond DOXYGEN_WARNINGS bool APlayerController::ServerUpdateCamera_Validate(FVector_NetQuantize CamLoc, int32 CamPitchAndYaw) { @@ -1654,6 +1696,8 @@ void APlayerController::ServerUpdateCamera_Implementation(FVector_NetQuantize Ca } } +/// @endcond + void APlayerController::RestartLevel() { if( GetNetMode()==NM_Standalone ) @@ -1670,6 +1714,8 @@ void APlayerController::LocalTravel( const FString& FURL ) } } +/// @cond DOXYGEN_WARNINGS + void APlayerController::ClientReturnToMainMenu_Implementation(const FString& ReturnReason) { UWorld* World = GetWorld(); @@ -1683,6 +1729,7 @@ void APlayerController::ClientReturnToMainMenu_Implementation(const FString& Ret } } +/// @endcond bool APlayerController::SetPause( bool bPause, FCanUnpause CanUnpauseDelegate) { @@ -1717,6 +1764,8 @@ void APlayerController::Pause() ServerPause(); } +/// @cond DOXYGEN_WARNINGS + bool APlayerController::ServerPause_Validate() { #if UE_BUILD_SHIPPING @@ -1732,6 +1781,8 @@ void APlayerController::ServerPause_Implementation() SetPause(!IsPaused()); } +/// @endcond + void APlayerController::SetName(const FString& S) { if (!S.IsEmpty()) @@ -1741,6 +1792,8 @@ void APlayerController::SetName(const FString& S) } } +/// @cond DOXYGEN_WARNINGS + void APlayerController::ServerChangeName_Implementation( const FString& S ) { AGameModeBase* GameMode = GetWorld()->GetAuthGameMode(); @@ -1756,6 +1809,8 @@ bool APlayerController::ServerChangeName_Validate( const FString& S ) return true; } +/// @endcond + void APlayerController::SwitchLevel(const FString& FURL) { const ENetMode NetMode = GetNetMode(); @@ -1788,12 +1843,15 @@ void APlayerController::GameHasEnded(AActor* EndGameFocus, bool bIsWinner) ClientGameEnded(EndGameFocus, bIsWinner); } +/// @cond DOXYGEN_WARNINGS void APlayerController::ClientGameEnded_Implementation(AActor* EndGameFocus, bool bIsWinner) { SetViewTarget(EndGameFocus); } +/// @endcond + bool APlayerController::GetHitResultUnderCursor(ECollisionChannel TraceChannel, bool bTraceComplex, FHitResult& HitResult) const { ULocalPlayer* LocalPlayer = Cast(Player); @@ -1951,18 +2009,24 @@ bool APlayerController::ProjectWorldLocationToScreen(FVector WorldLocation, FVec bool APlayerController::ProjectWorldLocationToScreenWithDistance(FVector WorldLocation, FVector& ScreenLocation, bool bPlayerViewportRelative) const { - FVector2D ScreenLoc2D; - if (UGameplayStatics::ProjectWorldToScreen(this, WorldLocation, ScreenLoc2D, bPlayerViewportRelative)) + // find distance + ULocalPlayer const* const LP = GetLocalPlayer(); + if (LP && LP->ViewportClient) { - // find distance - ULocalPlayer const* const LP = GetLocalPlayer(); - if (LP && LP->ViewportClient) + // get the projection data + FSceneViewProjectionData ProjectionData; + if (LP->GetProjectionData(LP->ViewportClient->Viewport, eSSP_FULL, /*out*/ ProjectionData)) { - // get the projection data - FSceneViewProjectionData ProjectionData; - if (LP->GetProjectionData(LP->ViewportClient->Viewport, eSSP_FULL, /*out*/ ProjectionData)) + FVector2D ScreenPosition2D; + FMatrix const ViewProjectionMatrix = ProjectionData.ComputeViewProjectionMatrix(); + if ( FSceneView::ProjectWorldToScreen(WorldLocation, ProjectionData.GetConstrainedViewRect(), ViewProjectionMatrix, ScreenPosition2D) ) { - ScreenLocation = FVector(ScreenLoc2D.X, ScreenLoc2D.Y, FVector::Dist(ProjectionData.ViewOrigin, WorldLocation)); + if ( bPlayerViewportRelative ) + { + ScreenPosition2D -= FVector2D(ProjectionData.GetConstrainedViewRect().Min); + } + + ScreenLocation = FVector(ScreenPosition2D.X, ScreenPosition2D.Y, FVector::Dist(ProjectionData.ViewOrigin, WorldLocation)); return true; } @@ -1990,11 +2054,9 @@ bool APlayerController::GetHitResultAtScreenPosition(const FVector2D ScreenPosit return false; } -static const FName NAME_ClickableTrace("ClickableTrace"); - bool APlayerController::GetHitResultAtScreenPosition(const FVector2D ScreenPosition, const ECollisionChannel TraceChannel, bool bTraceComplex, FHitResult& HitResult) const { - FCollisionQueryParams CollisionQueryParams( NAME_ClickableTrace, bTraceComplex ); + FCollisionQueryParams CollisionQueryParams(SCENE_QUERY_STAT(ClickableTrace), bTraceComplex ); return GetHitResultAtScreenPosition( ScreenPosition, TraceChannel, CollisionQueryParams, HitResult ); } @@ -2016,7 +2078,7 @@ bool APlayerController::GetHitResultAtScreenPosition(const FVector2D ScreenPosit if (UGameplayStatics::DeprojectScreenToWorld(this, ScreenPosition, WorldOrigin, WorldDirection) == true) { FCollisionObjectQueryParams const ObjParam(ObjectTypes); - return GetWorld()->LineTraceSingleByObjectType(HitResult, WorldOrigin, WorldOrigin + WorldDirection * HitResultTraceDistance, ObjParam, FCollisionQueryParams("ClickableTrace", bTraceComplex)); + return GetWorld()->LineTraceSingleByObjectType(HitResult, WorldOrigin, WorldOrigin + WorldDirection * HitResultTraceDistance, ObjParam, FCollisionQueryParams(SCENE_QUERY_STAT(ClickableTrace), bTraceComplex)); } return false; @@ -2444,6 +2506,8 @@ void APlayerController::SetViewTargetWithBlend(AActor* NewViewTarget, float Blen SetViewTarget(NewViewTarget, TransitionParams); } +/// @cond DOXYGEN_WARNINGS + void APlayerController::ClientSetViewTarget_Implementation( AActor* A, FViewTargetTransitionParams TransitionParams ) { if (PlayerCameraManager && !PlayerCameraManager->bClientSimulatingViewTarget) @@ -2477,6 +2541,8 @@ void APlayerController::ServerVerifyViewTarget_Implementation() ClientSetViewTarget( TheViewTarget ); } +/// @endcond + void APlayerController::SpawnPlayerCameraManager() { // servers and owning clients get cameras @@ -2549,6 +2615,8 @@ void APlayerController::ClearAudioListenerOverride() AudioListenerComponent = nullptr; } +/// @cond DOXYGEN_WARNINGS + bool APlayerController::ServerCheckClientPossession_Validate() { return true; @@ -2574,6 +2642,7 @@ void APlayerController::ServerCheckClientPossessionReliable_Implementation() ServerCheckClientPossession_Implementation(); } +/// @endcond void APlayerController::SafeServerCheckClientPossession() { @@ -2599,6 +2668,8 @@ void APlayerController::SafeServerUpdateSpectatorState() } } +/// @cond DOXYGEN_WARNINGS + bool APlayerController::ServerSetSpectatorLocation_Validate(FVector NewLoc, FRotator NewRot) { return true; @@ -2633,7 +2704,6 @@ void APlayerController::ServerSetSpectatorLocation_Implementation(FVector NewLoc } } - bool APlayerController::ServerSetSpectatorWaiting_Validate(bool bWaiting) { return true; @@ -2655,7 +2725,6 @@ void APlayerController::ClientSetSpectatorWaiting_Implementation(bool bWaiting) } } - bool APlayerController::ServerViewNextPlayer_Validate() { return true; @@ -2682,6 +2751,7 @@ void APlayerController::ServerViewPrevPlayer_Implementation() } } +/// @endcond APlayerState* APlayerController::GetNextViewablePlayer(int32 dir) { @@ -2730,7 +2800,6 @@ APlayerState* APlayerController::GetNextViewablePlayer(int32 dir) return nullptr; } - void APlayerController::ViewAPlayer(int32 dir) { APlayerState* const NextPlayerState = GetNextViewablePlayer(dir); @@ -2741,6 +2810,8 @@ void APlayerController::ViewAPlayer(int32 dir) } } +/// @cond DOXYGEN_WARNINGS + bool APlayerController::ServerViewSelf_Validate(FViewTargetTransitionParams TransitionParams) { return true; @@ -2756,6 +2827,8 @@ void APlayerController::ServerViewSelf_Implementation(FViewTargetTransitionParam } } +/// @endcond + void APlayerController::StartFire( uint8 FireModeNum ) { if ( ((IsInState(NAME_Spectating) && bPlayerIsWaiting) || IsInState(NAME_Inactive)) && !IsFrozen() ) @@ -2772,7 +2845,6 @@ void APlayerController::StartFire( uint8 FireModeNum ) } } - bool APlayerController::NotifyServerReceivedClientData(APawn* InPawn, float TimeStamp) { if (GetPawn() != InPawn || (GetNetMode() == NM_Client)) @@ -2789,6 +2861,8 @@ bool APlayerController::NotifyServerReceivedClientData(APawn* InPawn, float Time return true; } +/// @cond DOXYGEN_WARNINGS + bool APlayerController::ServerRestartPlayer_Validate() { return true; @@ -2824,11 +2898,15 @@ void APlayerController::ServerRestartPlayer_Implementation() } } +/// @endcond + bool APlayerController::CanRestartPlayer() { return PlayerState && !PlayerState->bOnlySpectator && HasClientLoadedCurrentWorld() && PendingSwapConnection == NULL; } +/// @cond DOXYGEN_WARNINGS + void APlayerController::ClientIgnoreMoveInput_Implementation(bool bIgnore) { SetIgnoreMoveInput(bIgnore); @@ -2839,6 +2917,7 @@ void APlayerController::ClientIgnoreLookInput_Implementation(bool bIgnore) SetIgnoreLookInput(bIgnore); } +/// @endcond void APlayerController::DisplayDebug(class UCanvas* Canvas, const FDebugDisplayInfo& DebugDisplay, float& YL, float& YPos) { @@ -2980,6 +3059,8 @@ void APlayerController::SetCinematicMode(bool bInCinematicMode, bool bHidePlayer ClientSetCinematicMode(bCinematicMode, bAffectsMovement, bAffectsTurning, bAffectsHUD); } +/// @cond DOXYGEN_WARNINGS + void APlayerController::ClientSetCinematicMode_Implementation(bool bInCinematicMode, bool bAffectsMovement, bool bAffectsTurning, bool bAffectsHUD) { bCinematicMode = bInCinematicMode; @@ -3004,11 +3085,15 @@ void APlayerController::ClientForceGarbageCollection_Implementation() GetWorld()->ForceGarbageCollection(); } +/// @endcond + void APlayerController::LevelStreamingStatusChanged(ULevelStreaming* LevelObject, bool bNewShouldBeLoaded, bool bNewShouldBeVisible, bool bNewShouldBlockOnLoad, int32 LODIndex ) { ClientUpdateLevelStreamingStatus(LevelObject->GetWorldAssetPackageFName(),bNewShouldBeLoaded,bNewShouldBeVisible,bNewShouldBlockOnLoad,LODIndex); } +/// @cond DOXYGEN_WARNINGS + void APlayerController::ClientPrepareMapChange_Implementation(FName LevelName, bool bFirst, bool bLast) { // Only call on the first local player controller to handle it being called on multiple PCs for splitscreen. @@ -3035,6 +3120,8 @@ void APlayerController::ClientPrepareMapChange_Implementation(FName LevelName, b } } +/// @endcond + void APlayerController::DelayedPrepareMapChange() { if (GetWorld()->IsPreparingMapChange()) @@ -3048,6 +3135,7 @@ void APlayerController::DelayedPrepareMapChange() } } +/// @cond DOXYGEN_WARNINGS void APlayerController::ClientCommitMapChange_Implementation() { @@ -3077,12 +3165,12 @@ void APlayerController::ClientCancelPendingMapChange_Implementation() GetWorld()->CancelPendingMapChange(); } - void APlayerController::ClientSetBlockOnAsyncLoading_Implementation() { GetWorld()->bRequestedBlockOnAsyncLoading = true; } +/// @endcond void APlayerController::GetSeamlessTravelActorList(bool bToEntry, TArray& ActorList) { @@ -3129,11 +3217,15 @@ void APlayerController::PostSeamlessTravel() } +/// @cond DOXYGEN_WARNINGS + void APlayerController::ClientEnableNetworkVoice_Implementation(bool bEnable) { ToggleSpeaking(bEnable); } +/// @endcond + void APlayerController::StartTalking() { ToggleSpeaking(true); @@ -3161,11 +3253,15 @@ void APlayerController::ToggleSpeaking(bool bSpeaking) } } +/// @cond DOXYGEN_WARNINGS + void APlayerController::ClientVoiceHandshakeComplete_Implementation() { MuteList.bHasVoiceHandshakeCompleted = true; } +/// @endcond + void APlayerController::GameplayMutePlayer(const FUniqueNetIdRepl& PlayerNetId) { if (PlayerNetId.IsValid()) @@ -3182,6 +3278,8 @@ void APlayerController::GameplayUnmutePlayer(const FUniqueNetIdRepl& PlayerNetId } } +/// @cond DOXYGEN_WARNINGS + void APlayerController::ServerMutePlayer_Implementation(FUniqueNetIdRepl PlayerId) { MuteList.ServerMutePlayer(this, PlayerId); @@ -3222,6 +3320,8 @@ void APlayerController::ClientUnmutePlayer_Implementation(FUniqueNetIdRepl Playe MuteList.ClientUnmutePlayer(this, PlayerId); } +/// @endcond + bool APlayerController::IsPlayerMuted(const FUniqueNetId& PlayerId) { return MuteList.IsPlayerMuted(PlayerId); @@ -3237,6 +3337,8 @@ void APlayerController::NotifyDirectorControl(bool bNowControlling, AMatineeActo } } +/// @cond DOXYGEN_WARNINGS + void APlayerController::ClientWasKicked_Implementation(const FText& KickReason) { } @@ -3257,6 +3359,8 @@ void APlayerController::ClientEndOnlineSession_Implementation() } } +/// @endcond + void APlayerController::ConsoleKey(FKey Key) { #if ALLOW_CONSOLE @@ -3476,6 +3580,7 @@ int32 APlayerController::GetSplitscreenPlayerCount() const return Result; } +/// @cond DOXYGEN_WARNINGS void APlayerController::ClientSetForceMipLevelsToBeResident_Implementation( UMaterialInterface* Material, float ForceDuration, int32 CinematicTextureGroups ) { @@ -3485,7 +3590,6 @@ void APlayerController::ClientSetForceMipLevelsToBeResident_Implementation( UMat } } - void APlayerController::ClientPrestreamTextures_Implementation( AActor* ForcedActor, float ForceDuration, bool bEnableStreaming, int32 CinematicTextureGroups) { if ( ForcedActor != NULL && IsPrimaryPlayer() ) @@ -3536,6 +3640,8 @@ void APlayerController::ClientStopForceFeedback_Implementation( UForceFeedbackEf } } +/// @endcond + /** Action that interpolates a component over time to a desired position */ class FDynamicForceFeedbackAction : public FPendingLatentAction { @@ -3572,15 +3678,14 @@ public: { } - virtual void UpdateOperation(FLatentResponse& Response) + virtual void UpdateOperation(FLatentResponse& Response) override { // Update elapsed time TimeElapsed += Response.ElapsedTime(); const bool bComplete = (!bRunning || (TotalTime >= 0.f && TimeElapsed >= TotalTime) || !PlayerController.IsValid()); - APlayerController* PC = PlayerController.Get(); - if (PC) + if (APlayerController* PC = PlayerController.Get()) { if (bComplete) { @@ -3594,6 +3699,22 @@ public: Response.FinishAndTriggerIf(bComplete, ExecutionFunction, OutputLink, CallbackTarget); } + + virtual void NotifyObjectDestroyed() override + { + if (APlayerController* PC = PlayerController.Get()) + { + PC->DynamicForceFeedbacks.Remove(LatentUUID); + } + } + + virtual void NotifyActionAborted() override + { + if (APlayerController* PC = PlayerController.Get()) + { + PC->DynamicForceFeedbacks.Remove(LatentUUID); + } + } }; void APlayerController::PlayDynamicForceFeedback(float Intensity, float Duration, bool bAffectsLeftLarge, bool bAffectsLeftSmall, bool bAffectsRightLarge, bool bAffectsRightSmall, TEnumAsByte Action, FLatentActionInfo LatentInfo) @@ -3842,6 +3963,8 @@ void APlayerController::ProcessForceFeedbackAndHaptics(const float DeltaTime, co } } +/// @cond DOXYGEN_WARNINGS + void APlayerController::ClientPlayCameraShake_Implementation( TSubclassOf Shake, float Scale, ECameraAnimPlaySpace::Type PlaySpace, FRotator UserPlaySpaceRot ) { if (PlayerCameraManager != NULL) @@ -3876,7 +3999,6 @@ void APlayerController::ClientStopCameraAnim_Implementation(UCameraAnim* AnimToS } } - void APlayerController::ClientSpawnCameraLensEffect_Implementation( TSubclassOf LensEffectEmitterClass ) { if (PlayerCameraManager != NULL) @@ -3893,6 +4015,8 @@ void APlayerController::ClientClearCameraLensEffects_Implementation() } } +/// @endcond + void APlayerController::ReceivedGameModeClass(TSubclassOf GameModeClass) { } @@ -3908,19 +4032,6 @@ void APlayerController::ReceivedSpectatorClass(TSubclassOf Spect } } -void APlayerController::GetLifetimeReplicatedProps( TArray< FLifetimeProperty > & OutLifetimeProps ) const -{ - Super::GetLifetimeReplicatedProps( OutLifetimeProps ); - - // These used to only replicate if PlayerCameraManager->GetViewTargetPawn() != GetPawn() - // But, since they also don't update unless that condition is true, these values won't change, thus won't send - // This is a little less efficient, but fits into the new condition system well, and shouldn't really add much overhead - DOREPLIFETIME_CONDITION( APlayerController, TargetViewRotation, COND_OwnerOnly ); - - // Replicate SpawnLocation for remote spectators - DOREPLIFETIME_CONDITION( APlayerController, SpawnLocation, COND_OwnerOnly ); -} - void APlayerController::SetPawn(APawn* InPawn) { if (InPawn == NULL) @@ -3944,6 +4055,18 @@ void APlayerController::SetPawn(APawn* InPawn) } } +void APlayerController::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const +{ + Super::GetLifetimeReplicatedProps(OutLifetimeProps); + + // These used to only replicate if PlayerCameraManager->GetViewTargetPawn() != GetPawn() + // But, since they also don't update unless that condition is true, these values won't change, thus won't send + // This is a little less efficient, but fits into the new condition system well, and shouldn't really add much overhead + DOREPLIFETIME_CONDITION(APlayerController, TargetViewRotation, COND_OwnerOnly); + + // Replicate SpawnLocation for remote spectators + DOREPLIFETIME_CONDITION(APlayerController, SpawnLocation, COND_OwnerOnly); +} void APlayerController::SetPlayer( UPlayer* InPlayer ) { @@ -4201,6 +4324,8 @@ void APlayerController::ClientTravel(const FString& URL, ETravelType TravelType, ClientTravelInternal(URL, TravelType, bSeamless, MapPackageGuid); } +/// @cond DOXYGEN_WARNINGS + void APlayerController::ClientTravelInternal_Implementation(const FString& URL, ETravelType TravelType, bool bSeamless, FGuid MapPackageGuid) { UWorld* World = GetWorld(); @@ -4223,6 +4348,8 @@ void APlayerController::ClientTravelInternal_Implementation(const FString& URL, } } +/// @endcond + FString APlayerController::GetPlayerNetworkAddress() { if( Player && Player->IsA(UNetConnection::StaticClass()) ) @@ -4806,7 +4933,7 @@ void APlayerController::UpdateCameraManager(float DeltaSeconds) } } -void APlayerController::BuildHiddenComponentList(const FVector& ViewLocation, TSet& HiddenComponents) +void APlayerController::BuildHiddenComponentList(const FVector& ViewLocation, TSet& HiddenComponentsOut) { // Translate the hidden actors list to a hidden primitive list. UpdateHiddenActors(ViewLocation); @@ -4824,14 +4951,14 @@ void APlayerController::BuildHiddenComponentList(const FVector& ViewLocation, TS UPrimitiveComponent* PrimitiveComponent = Components[ComponentIndex]; if (PrimitiveComponent->IsRegistered()) { - HiddenComponents.Add(PrimitiveComponent->ComponentId); + HiddenComponentsOut.Add(PrimitiveComponent->ComponentId); for (USceneComponent* AttachedChild : PrimitiveComponent->GetAttachChildren()) { UPrimitiveComponent* AttachChildPC = Cast(AttachedChild); if (AttachChildPC && AttachChildPC->IsRegistered()) { - HiddenComponents.Add(AttachChildPC->ComponentId); + HiddenComponentsOut.Add(AttachChildPC->ComponentId); } } } @@ -4844,15 +4971,37 @@ void APlayerController::BuildHiddenComponentList(const FVector& ViewLocation, TS } } + // iterate backwards to we can remove as we go + for (int32 ComponentIndx = HiddenPrimitiveComponents.Num() - 1; ComponentIndx >= 0; --ComponentIndx) + { + TWeakObjectPtr ComponentPtr = HiddenPrimitiveComponents[ComponentIndx]; + if (ComponentPtr.IsValid()) + { + UPrimitiveComponent* Component = ComponentPtr.Get(); + if (Component->IsRegistered()) + { + HiddenComponentsOut.Add(Component->ComponentId); + } + } + else + { + HiddenPrimitiveComponents.RemoveAt(ComponentIndx); + } + } + // Allow a chance to operate on a per primitive basis - UpdateHiddenComponents(ViewLocation, HiddenComponents); + UpdateHiddenComponents(ViewLocation, HiddenComponentsOut); } +/// @cond DOXYGEN_WARNINGS + void APlayerController::ClientRepObjRef_Implementation(UObject *Object) { UE_LOG(LogPlayerController, Warning, TEXT("APlayerController::ClientRepObjRef repped: %s"), Object ? *Object->GetName() : TEXT("NULL") ); } +/// @endcond + void FDynamicForceFeedbackDetails::Update(FForceFeedbackValues& Values) const { if (bAffectsLeftLarge) @@ -4873,6 +5022,8 @@ void FDynamicForceFeedbackDetails::Update(FForceFeedbackValues& Values) const } } +/// @cond DOXYGEN_WARNINGS + void APlayerController::OnServerStartedVisualLogger_Implementation(bool bIsLogging) { #if ENABLE_VISUAL_LOG @@ -4881,6 +5032,8 @@ void APlayerController::OnServerStartedVisualLogger_Implementation(bool bIsLoggi #endif } +/// @endcond + bool APlayerController::ShouldPerformFullTickWhenPaused() const { return bShouldPerformFullTickWhenPaused || (/*bIsInVr =*/GEngine->HMDDevice.IsValid() && GEngine->HMDDevice->IsStereoEnabled() && GEngine->HMDDevice->IsHMDConnected()); diff --git a/Engine/Source/Runtime/Engine/Private/PostProcessVolume.cpp b/Engine/Source/Runtime/Engine/Private/PostProcessVolume.cpp index 4eefbdc7b9b8..7e7fb7371602 100644 --- a/Engine/Source/Runtime/Engine/Private/PostProcessVolume.cpp +++ b/Engine/Source/Runtime/Engine/Private/PostProcessVolume.cpp @@ -141,18 +141,14 @@ bool APostProcessVolume::CanEditChange(const UProperty* InProperty) const return (Settings.BloomMethod == EBloomMethod::BM_SOG); } - if (PropertyName == GET_MEMBER_NAME_STRING_CHECKED(FPostProcessSettings, BloomConvolutionTexture)) - { - return (Settings.BloomMethod == EBloomMethod::BM_FFT); - } - // Parameters that are only of use with the bloom texture based fft - if (PropertyName == GET_MEMBER_NAME_STRING_CHECKED(FPostProcessSettings, BloomConvolutionSize) || + if (PropertyName == GET_MEMBER_NAME_STRING_CHECKED(FPostProcessSettings, BloomConvolutionTexture) || + PropertyName == GET_MEMBER_NAME_STRING_CHECKED(FPostProcessSettings, BloomConvolutionSize) || PropertyName == GET_MEMBER_NAME_STRING_CHECKED(FPostProcessSettings, BloomConvolutionCenterUV) || PropertyName == GET_MEMBER_NAME_STRING_CHECKED(FPostProcessSettings, BloomConvolutionPreFilter) || PropertyName == GET_MEMBER_NAME_STRING_CHECKED(FPostProcessSettings, BloomConvolutionBufferScale)) { - return (Settings.BloomMethod == EBloomMethod::BM_FFT && Settings.bOverride_BloomConvolutionTexture); + return (Settings.BloomMethod == EBloomMethod::BM_FFT); } } diff --git a/Engine/Source/Runtime/Engine/Private/PrecomputedLightVolume.cpp b/Engine/Source/Runtime/Engine/Private/PrecomputedLightVolume.cpp index 45ec86f4de31..fbe5da2516b4 100644 --- a/Engine/Source/Runtime/Engine/Private/PrecomputedLightVolume.cpp +++ b/Engine/Source/Runtime/Engine/Private/PrecomputedLightVolume.cpp @@ -115,7 +115,7 @@ FPrecomputedLightVolumeData::~FPrecomputedLightVolumeData() static void LoadVolumeLightSamples(FArchive& Ar, int32 ArchiveNumSHSamples, TArray& Samples) { // If it's the same number as what is currently compiled - if (ArchiveNumSHSamples == NUM_INDIRECT_LIGHTING_SH_COEFFICIENTS) + if (ArchiveNumSHSamples == NUM_INDIRECT_LIGHTING_SH_COEFFICIENTS) //-V517 { Ar << Samples; } diff --git a/Engine/Source/Runtime/Engine/Private/PreviewScene.cpp b/Engine/Source/Runtime/Engine/Private/PreviewScene.cpp index f59624ce0fdb..6daee19560f1 100644 --- a/Engine/Source/Runtime/Engine/Private/PreviewScene.cpp +++ b/Engine/Source/Runtime/Engine/Private/PreviewScene.cpp @@ -84,7 +84,7 @@ FPreviewScene::~FPreviewScene() GEngine->DestroyWorldContext(GetWorld()); } -void FPreviewScene::AddComponent(UActorComponent* Component,const FTransform& LocalToWorld) +void FPreviewScene::AddComponent(UActorComponent* Component,const FTransform& LocalToWorld, bool bAttachToRoot /*= false*/) { Components.AddUnique(Component); @@ -143,7 +143,7 @@ void FPreviewScene::ClearLineBatcher() /** Accessor for finding the current direction of the preview scene's DirectionalLight. */ FRotator FPreviewScene::GetLightDirection() { - return DirectionalLight->ComponentToWorld.GetUnitAxis( EAxis::X ).Rotation(); + return DirectionalLight->GetComponentTransform().GetUnitAxis( EAxis::X ).Rotation(); } /** Function for modifying the current direction of the preview scene's DirectionalLight. */ diff --git a/Engine/Source/Runtime/Engine/Private/PrimaryAssetLabel.cpp b/Engine/Source/Runtime/Engine/Private/PrimaryAssetLabel.cpp index 530325a8a6a6..c708084cc86d 100644 --- a/Engine/Source/Runtime/Engine/Private/PrimaryAssetLabel.cpp +++ b/Engine/Source/Runtime/Engine/Private/PrimaryAssetLabel.cpp @@ -12,6 +12,7 @@ const FName UPrimaryAssetLabel::DirectoryBundle = FName("Directory"); UPrimaryAssetLabel::UPrimaryAssetLabel() { bLabelAssetsInMyDirectory = false; + bIsRuntimeLabel = false; // By default have low priority and don't recurse Rules.bApplyRecursively = false; @@ -38,12 +39,20 @@ void UPrimaryAssetLabel::UpdateAssetBundleData() TArray DirectoryAssets; AssetRegistry.GetAssetsByPath(PackagePath, DirectoryAssets, true); + TArray NewPaths; + for (const FAssetData& AssetData : DirectoryAssets) { FStringAssetReference AssetRef = Manager.GetAssetPathForData(AssetData); - AssetBundleData.AddBundleAsset(DirectoryBundle, AssetRef); + if (!AssetRef.IsNull()) + { + NewPaths.Add(AssetRef); + } } + + // Fast set, destroys NewPaths + AssetBundleData.SetBundleAssets(DirectoryBundle, MoveTemp(NewPaths)); } // Update rules diff --git a/Engine/Source/Runtime/Engine/Private/PrimitiveComponentPhysics.cpp b/Engine/Source/Runtime/Engine/Private/PrimitiveComponentPhysics.cpp index 33f597d2d8ea..af632fd54808 100644 --- a/Engine/Source/Runtime/Engine/Private/PrimitiveComponentPhysics.cpp +++ b/Engine/Source/Runtime/Engine/Private/PrimitiveComponentPhysics.cpp @@ -552,9 +552,9 @@ FVector UPrimitiveComponent::GetInertiaTensor(FName BoneName /* = NAME_None */) FVector UPrimitiveComponent::ScaleByMomentOfInertia(FVector InputVector, FName BoneName /* = NAME_None */) const { const FVector LocalInertiaTensor = GetInertiaTensor(BoneName); - const FVector InputVectorLocal = ComponentToWorld.InverseTransformVectorNoScale(InputVector); + const FVector InputVectorLocal = GetComponentTransform().InverseTransformVectorNoScale(InputVector); const FVector LocalScaled = InputVectorLocal * LocalInertiaTensor; - const FVector WorldScaled = ComponentToWorld.TransformVectorNoScale(LocalScaled); + const FVector WorldScaled = GetComponentTransform().TransformVectorNoScale(LocalScaled); return WorldScaled; } @@ -658,9 +658,9 @@ void UPrimitiveComponent::SyncComponentToRBPhysics() // See if the transform is actually different, and if so, move the component to match physics const FTransform NewTransform = GetComponentTransformFromBodyInstance(UseBI); - if(!NewTransform.EqualsNoScale(ComponentToWorld)) + if(!NewTransform.EqualsNoScale(GetComponentTransform())) { - const FVector MoveBy = NewTransform.GetLocation() - ComponentToWorld.GetLocation(); + const FVector MoveBy = NewTransform.GetLocation() - GetComponentTransform().GetLocation(); const FRotator NewRotation = NewTransform.Rotator(); //@warning: do not reference BodyInstance again after calling MoveComponent() - events from the move could have made it unusable (destroying the actor, SetPhysics(), etc) @@ -1047,8 +1047,7 @@ void UPrimitiveComponent::OnComponentCollisionSettingsChanged() bool UPrimitiveComponent::K2_LineTraceComponent(FVector TraceStart, FVector TraceEnd, bool bTraceComplex, bool bShowTrace, FVector& HitLocation, FVector& HitNormal, FName& BoneName, FHitResult& OutHit) { - static FName KismetTraceComponentName(TEXT("KismetTraceComponent")); - FCollisionQueryParams LineParams(KismetTraceComponentName, bTraceComplex); + FCollisionQueryParams LineParams(SCENE_QUERY_STAT(KismetTraceComponent), bTraceComplex); const bool bDidHit = LineTraceComponent(OutHit, TraceStart, TraceEnd, LineParams); if( bDidHit ) diff --git a/Engine/Source/Runtime/Engine/Private/PrimitiveDrawingUtils.cpp b/Engine/Source/Runtime/Engine/Private/PrimitiveDrawingUtils.cpp index 4bd61e3d13e0..ce1bd35ebd00 100644 --- a/Engine/Source/Runtime/Engine/Private/PrimitiveDrawingUtils.cpp +++ b/Engine/Source/Runtime/Engine/Private/PrimitiveDrawingUtils.cpp @@ -312,7 +312,7 @@ extern ENGINE_API void GetSphereMesh(const FVector& Center, const FVector& Radii GetHalfSphereMesh(Center, Radii, NumSides, NumRings, 0, PI, MaterialRenderProxy, DepthPriority, bDisableBackfaceCulling, ViewIndex, Collector, bUseSelectionOutline, HitProxy); } -void DrawSphere(FPrimitiveDrawInterface* PDI,const FVector& Center,const FVector& Radii,int32 NumSides,int32 NumRings,const FMaterialRenderProxy* MaterialRenderProxy,uint8 DepthPriority,bool bDisableBackfaceCulling) +void DrawSphere(FPrimitiveDrawInterface* PDI,const FVector& Center,const FRotator& Orientation,const FVector& Radii,int32 NumSides,int32 NumRings,const FMaterialRenderProxy* MaterialRenderProxy,uint8 DepthPriority,bool bDisableBackfaceCulling) { // Use a mesh builder to draw the sphere. FDynamicMeshBuilder MeshBuilder; @@ -392,7 +392,7 @@ void DrawSphere(FPrimitiveDrawInterface* PDI,const FVector& Center,const FVector FMemory::Free(Verts); FMemory::Free(ArcVerts); } - MeshBuilder.Draw(PDI, FScaleMatrix( Radii ) * FTranslationMatrix( Center ), MaterialRenderProxy, DepthPriority,bDisableBackfaceCulling); + MeshBuilder.Draw(PDI, FScaleMatrix( Radii ) * FRotationMatrix(Orientation) * FTranslationMatrix( Center ), MaterialRenderProxy, DepthPriority,bDisableBackfaceCulling); } FVector CalcConeVert(float Angle1, float Angle2, float AzimuthAngle) diff --git a/Engine/Source/Runtime/Engine/Private/ProfilingDebugging/MallocLeakReporter.cpp b/Engine/Source/Runtime/Engine/Private/ProfilingDebugging/MallocLeakReporter.cpp new file mode 100644 index 000000000000..d26bb6e4ef95 --- /dev/null +++ b/Engine/Source/Runtime/Engine/Private/ProfilingDebugging/MallocLeakReporter.cpp @@ -0,0 +1,201 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "MallocLeakReporter.h" +#include "Parse.h" +#include "Ticker.h" +#include "UObjectGlobals.h" +#include "Paths.h" + + +DEFINE_LOG_CATEGORY_STATIC(LogLeakDetector, Log, All); + +FMallocLeakReporter& FMallocLeakReporter::Get() +{ + static FMallocLeakReporter Singleton; + return Singleton; +} + +FMallocLeakReporter::FMallocLeakReporter() + : Enabled(false) + , ReportCount(0) +{ + // Default options for leak report + DefaultLeakReportOptions.OnlyNonDeleters = true; + DefaultLeakReportOptions.RateFilter = 0.1f; + DefaultLeakReportOptions.SizeFilter = 512 * 1024; + DefaultLeakReportOptions.SortBy = FMallocLeakReportOptions::ESortOption::SortRate; + + // default options for alloc report + DefaultAllocReportOptions.SizeFilter = 1024 * 1024; + DefaultAllocReportOptions.SortBy = FMallocLeakReportOptions::ESortOption::SortSize; +} + +void FMallocLeakReporter::Start(int32 FilterSize/*=0*/, float ReportOnTime /*= 0.0f*/) +{ + // assume they want to change options so stop/start + if (Enabled) + { + Stop(); + } + +#if !MALLOC_LEAKDETECTION || PLATFORM_USES_FIXED_GMalloc_CLASS + + UE_LOG(LogLeakDetector, Error, TEXT("Cannot track leaks, MALLOC_LEAKDETECTION=%d, PLATFORM_USES_FIXED_GMalloc_CLASS=%d (should be set as 1 & 0 in your GameTarget.cs file)"), + MALLOC_LEAKDETECTION, PLATFORM_USES_FIXED_GMalloc_CLASS); + +#else + UE_LOG(LogLeakDetector, Log, TEXT("Started Tracking Allocations > %d KB"), FilterSize / 1024); + FMallocLeakDetection::Get().SetAllocationCollection(true, FilterSize); + + // Create a ticker to issue checkpoints + CheckpointTicker = FTicker::GetCoreTicker().AddTicker(FTickerDelegate::CreateLambda([this](const float TimeDelta) + { + Checkpoint(); + return Enabled; + }), 120.0f); + + // If specified, create a handler to generate reports periodically + if (ReportOnTime > 0.0f) + { + ReportTicker = FTicker::GetCoreTicker().AddTicker(FTickerDelegate::CreateLambda([this](const float TimeDelta) + { + WriteReports(); + return true; + }), ReportOnTime); + } + + Enabled = true; +#endif +} + +void FMallocLeakReporter::Stop() +{ + if (!Enabled) + { + return; + } + +#if MALLOC_LEAKDETECTION + UE_LOG(LogLeakDetector, Log, TEXT("Stopped tracking allocations")); + FMallocLeakDetection::Get().SetAllocationCollection(false); + + FTicker::GetCoreTicker().RemoveTicker(CheckpointTicker); + FTicker::GetCoreTicker().RemoveTicker(ReportTicker); + + CheckpointTicker.Reset(); + ReportTicker.Reset(); + + Enabled = false; +#endif // MALLOC_LEAKDETECTION +} + +void FMallocLeakReporter::Clear() +{ +#if MALLOC_LEAKDETECTION + FMallocLeakDetection::Get().ClearData(); +#endif +} + +void FMallocLeakReporter::Checkpoint() +{ +#if MALLOC_LEAKDETECTION + FMallocLeakDetection::Get().CheckpointLinearFit(); +#endif +} + +int32 FMallocLeakReporter::WriteReports(const uint32 ReportFlags /*=EReportOption::ReportAll*/) +{ + FString MapName = FPaths::GetBaseFilename(GWorld->GetName()); + + FString BaseName = FString::Printf(TEXT("%03d_%s"), ReportCount++, *MapName); + FString LeakName = BaseName + TEXT("_Leaks.txt"); + FString AllocName = BaseName + TEXT("_Allocs.txt"); + + // write out leaks + int32 LeakCount = WriteReport(*LeakName, DefaultLeakReportOptions); + + if (LeakCount > 0) + { + UE_LOG(LogLeakDetector, Log, TEXT("Found %d leaks, report written to %s"), LeakCount, *LeakName); + + ReportDelegate.Broadcast(ReportCount, LeakCount); + } + else + { + UE_LOG(LogLeakDetector, Log, TEXT("No leaks found")); + } + + // write out allocations + if (ReportFlags & EReportOption::ReportAllocs) + { + WriteReport(*AllocName, DefaultAllocReportOptions); + } + + // write out memreport +#if !UE_BUILD_SHIPPING + if (ReportFlags & EReportOption::ReportMemReport) + { + FString Args = FString::Printf(TEXT(" -full -name=%s"), *BaseName); + GEngine->HandleMemReportCommand(*Args, *GLog, GWorld); + } +#endif + + return LeakCount; +} + +int32 FMallocLeakReporter::WriteReport(const TCHAR* ReportName, const FMallocLeakReportOptions& Options) +{ +#if MALLOC_LEAKDETECTION + return FMallocLeakDetection::Get().DumpOpenCallstacks(ReportName, Options); +#else + UE_LOG(LogLeakDetector, Log, TEXT("Cannot report leaks. MALLOC_LEAKDETECTION=0")); + return 0; +#endif // MALLOC_LEAKDETECTION +} + +/** + CLI interface for leak tracker. +*/ + +static FAutoConsoleCommand LeakReporterStartCommand( + TEXT("mallocleak.start"), + TEXT("Starts tracking allocations. Args -report=[secs] -size=[filter]"), + FConsoleCommandWithArgsDelegate::CreateLambda([](const TArray& Args) { + FString ArgString = FString::Join(Args, TEXT(" ")); + int32 Size = 0; + float ReportTime = 0; + FParse::Value(*ArgString, TEXT("size="), Size); + FParse::Value(*ArgString, TEXT("report="), ReportTime); + + FMallocLeakReporter::Get().Start(Size * 1024, ReportTime); + + UE_LOG(LogConsoleResponse, Display, TEXT("Tracking allocations >= %d KB and reporting every %d seconds"), Size / 1024, ReportTime); + }) +); + +static FAutoConsoleCommand LeakReporterStopCommand( + TEXT("mallocleak.stop"), + TEXT("Stops tracking allocations"), + FConsoleCommandDelegate::CreateLambda([]() { + FMallocLeakReporter::Get().Stop(); + UE_LOG(LogConsoleResponse, Display, TEXT("Stopped tracking allocations.")); + }) +); + +static FAutoConsoleCommand LeakReporterClearCommand( + TEXT("mallocleak.clear"), + TEXT("Clears recorded allocation info"), + FConsoleCommandDelegate::CreateLambda([]() { + FMallocLeakReporter::Get().Clear(); + UE_LOG(LogConsoleResponse, Display, TEXT("Cleared recorded data.")); + }) +); + +static FAutoConsoleCommand LeakReporterReportCommand( + TEXT("mallocleak.report"), + TEXT("Writes malloc leak reports "), + FConsoleCommandDelegate::CreateLambda([]() { + FMallocLeakReporter::Get().WriteReports(); + UE_LOG(LogConsoleResponse, Display, TEXT("Wrote out memory reports")); + }) +); \ No newline at end of file diff --git a/Engine/Source/Runtime/Engine/Private/Rendering/SubsurfaceProfile.cpp b/Engine/Source/Runtime/Engine/Private/Rendering/SubsurfaceProfile.cpp index 33ca0e79b27f..26dc084622c7 100644 --- a/Engine/Source/Runtime/Engine/Private/Rendering/SubsurfaceProfile.cpp +++ b/Engine/Source/Runtime/Engine/Private/Rendering/SubsurfaceProfile.cpp @@ -14,12 +14,6 @@ ENGINE_API TGlobalResource GSubsurfaceProfileTextureO // Texture with one or more SubSurfaceProfiles or 0 if there is no user static TRefCountPtr GSSProfiles; -static TAutoConsoleVariable CVarFastVRamSubsurfaceProfile( - TEXT("r.FastVRamSubsurfaceProfile"), - 0, - TEXT("Whether to store subsurfaceprofile in fast VRAM"), - ECVF_Scalability | ECVF_RenderThreadSafe); - FSubsurfaceProfileTexture::FSubsurfaceProfileTexture() { check(IsInGameThread()); @@ -141,10 +135,6 @@ void FSubsurfaceProfileTexture::CreateTexture(FRHICommandListImmediate& RHICmdLi // at minimum 64 lines (less reallocations) FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(FIntPoint(Width, FMath::Max(Height, (uint32)64)), PF_B8G8R8A8, FClearValueBinding::None, 0, TexCreate_None, false)); - if (CVarFastVRamSubsurfaceProfile.GetValueOnRenderThread() >= 1) - { - Desc.Flags |= TexCreate_FastVRAM; - } if (b16Bit) { Desc.Format = PF_A16B16G16R16; diff --git a/Engine/Source/Runtime/Engine/Private/RepLayout.cpp b/Engine/Source/Runtime/Engine/Private/RepLayout.cpp index f5d0a6f1a443..fa15290e4873 100644 --- a/Engine/Source/Runtime/Engine/Private/RepLayout.cpp +++ b/Engine/Source/Runtime/Engine/Private/RepLayout.cpp @@ -1118,7 +1118,7 @@ void FRepLayout::MergeChangeList_r( const uint8* NewData = ( uint8* )Array->GetData(); - TArray< FHandleToCmdIndex >& ArrayHandleToCmdIndex = ActiveIterator1 ? *ActiveIterator1->HandleToCmdIndex[Cmd.RelativeHandle - 1].HandleToCmdIndex : *ActiveIterator2->HandleToCmdIndex[Cmd.RelativeHandle - 1].HandleToCmdIndex; + TArray< FHandleToCmdIndex >& ArrayHandleToCmdIndex = ActiveIterator1 ? *ActiveIterator1->HandleToCmdIndex[Cmd.RelativeHandle - 1].HandleToCmdIndex : *ActiveIterator2->HandleToCmdIndex[Cmd.RelativeHandle - 1].HandleToCmdIndex; //-V595 if ( !ActiveIterator1 ) { @@ -3432,33 +3432,33 @@ void FRepLayout::RebuildConditionalProperties( FRepState * RESTRICT RepState, co RepState->ConditionMap[COND_None] = true; RepState->ConditionMap[COND_InitialOnly] = bIsInitial; - RepState->ConditionMap[COND_OwnerOnly] = bIsOwner; - RepState->ConditionMap[COND_SkipOwner] = !bIsOwner; + RepState->ConditionMap[COND_OwnerOnly] = bIsOwner; + RepState->ConditionMap[COND_SkipOwner] = !bIsOwner; - RepState->ConditionMap[COND_SimulatedOnly] = bIsSimulated; - RepState->ConditionMap[COND_SimulatedOnlyNoReplay] = bIsSimulated && !bIsReplay; - RepState->ConditionMap[COND_AutonomousOnly] = !bIsSimulated; + RepState->ConditionMap[COND_SimulatedOnly] = bIsSimulated; + RepState->ConditionMap[COND_SimulatedOnlyNoReplay] = bIsSimulated && !bIsReplay; + RepState->ConditionMap[COND_AutonomousOnly] = !bIsSimulated; - RepState->ConditionMap[COND_SimulatedOrPhysics] = bIsSimulated || bIsPhysics; - RepState->ConditionMap[COND_SimulatedOrPhysicsNoReplay] = ( bIsSimulated || bIsPhysics ) && !bIsReplay; + RepState->ConditionMap[COND_SimulatedOrPhysics] = bIsSimulated || bIsPhysics; + RepState->ConditionMap[COND_SimulatedOrPhysicsNoReplay] = (bIsSimulated || bIsPhysics) && !bIsReplay; - RepState->ConditionMap[COND_InitialOrOwner] = bIsInitial || bIsOwner; - RepState->ConditionMap[COND_ReplayOrOwner] = bIsReplay || bIsOwner; - RepState->ConditionMap[COND_ReplayOnly] = bIsReplay; - RepState->ConditionMap[COND_SkipReplay] = !bIsReplay; + RepState->ConditionMap[COND_InitialOrOwner] = bIsInitial || bIsOwner; + RepState->ConditionMap[COND_ReplayOrOwner] = bIsReplay || bIsOwner; + RepState->ConditionMap[COND_ReplayOnly] = bIsReplay; + RepState->ConditionMap[COND_SkipReplay] = !bIsReplay; - RepState->ConditionMap[COND_Custom] = true; + RepState->ConditionMap[COND_Custom] = true; RepState->RepFlags = RepFlags; } -void FRepLayout::InitChangedTracker( FRepChangedPropertyTracker * ChangedTracker ) const +void FRepLayout::InitChangedTracker(FRepChangedPropertyTracker * ChangedTracker) const { - ChangedTracker->Parents.SetNum( Parents.Num() ); + ChangedTracker->Parents.SetNum(Parents.Num()); - for ( int32 i = 0; i < Parents.Num(); i++ ) + for (int32 i = 0; i < Parents.Num(); i++) { - ChangedTracker->Parents[i].IsConditional = ( Parents[i].Flags & PARENT_IsConditional ) ? 1 : 0; + ChangedTracker->Parents[i].IsConditional = (Parents[i].Flags & PARENT_IsConditional) ? 1 : 0; } } @@ -3530,9 +3530,9 @@ void FRepLayout::InitProperties( TArray< uint8, TAlignedHeapAllocator<16> >& Sha } } -void FRepLayout::DestructProperties( FRepState * RepState ) const +void FRepLayout::DestructProperties( FRepStateStaticBuffer& RepStateStaticBuffer ) const { - uint8* StoredData = RepState->StaticBuffer.GetData(); + uint8* StoredData = RepStateStaticBuffer.GetData(); // Destruct all items for ( int32 i = 0; i < Parents.Num(); i++ ) @@ -3541,13 +3541,13 @@ void FRepLayout::DestructProperties( FRepState * RepState ) const if ( Parents[i].ArrayIndex == 0 ) { PTRINT Offset = Parents[i].Property->ContainerPtrToValuePtr( StoredData ) - StoredData; - check( Offset >= 0 && Offset < RepState->StaticBuffer.Num() ); + check( Offset >= 0 && Offset < RepStateStaticBuffer.Num() ); Parents[i].Property->DestroyValue( StoredData + Offset ); } } - RepState->StaticBuffer.Empty(); + RepStateStaticBuffer.Empty(); } void FRepLayout::GetLifetimeCustomDeltaProperties(TArray< int32 > & OutCustom, TArray< ELifetimeCondition > & OutConditions) @@ -3567,10 +3567,30 @@ void FRepLayout::GetLifetimeCustomDeltaProperties(TArray< int32 > & OutCustom, T } } +void FRepLayout::AddReferencedObjects(FReferenceCollector& Collector) +{ + for (int32 i = 0; i < Parents.Num(); i++) + { + if (Parents[i].Property != nullptr) + { + Collector.AddReferencedObject(Parents[i].Property); + } + } +} + + FRepState::~FRepState() { if (RepLayout.IsValid() && StaticBuffer.Num() > 0) { - RepLayout->DestructProperties( this ); + RepLayout->DestructProperties( StaticBuffer ); + } +} + +FRepChangelistState::~FRepChangelistState() +{ + if (RepLayout.IsValid() && StaticBuffer.Num() > 0) + { + RepLayout->DestructProperties( StaticBuffer ); } } diff --git a/Engine/Source/Runtime/Engine/Private/SceneManagement.cpp b/Engine/Source/Runtime/Engine/Private/SceneManagement.cpp index 5e915deef340..b76060777ffa 100644 --- a/Engine/Source/Runtime/Engine/Private/SceneManagement.cpp +++ b/Engine/Source/Runtime/Engine/Private/SceneManagement.cpp @@ -183,8 +183,8 @@ FMeshBatchAndRelevance::FMeshBatchAndRelevance(const FMeshBatch& InMesh, const F PrimitiveSceneProxy(InPrimitiveSceneProxy) { QUICK_SCOPE_CYCLE_COUNTER(STAT_FMeshBatchAndRelevance); - EBlendMode BlendMode = InMesh.MaterialRenderProxy->GetMaterial(FeatureLevel)->GetBlendMode(); - bHasOpaqueOrMaskedMaterial = !IsTranslucentBlendMode(BlendMode); + const FMaterial* Material = InMesh.MaterialRenderProxy->GetMaterial(FeatureLevel); + bHasOpaqueOrMaskedMaterial = !IsTranslucentBlendMode(Material->GetBlendMode()); bRenderInMainPass = PrimitiveSceneProxy->ShouldRenderInMainPass(); } @@ -546,6 +546,8 @@ FViewUniformShaderParameters::FViewUniformShaderParameters() PerlinNoise3DTexture = BlackVolume; PerlinNoise3DTextureSampler = TStaticSamplerState::GetRHI(); + SobolSamplingTexture = GWhiteTexture->TextureRHI; + GlobalDistanceFieldTexture0_UB = BlackVolume; GlobalDistanceFieldSampler0_UB = TStaticSamplerState::GetRHI(); GlobalDistanceFieldTexture1_UB = BlackVolume; diff --git a/Engine/Source/Runtime/Engine/Private/SceneUtils.cpp b/Engine/Source/Runtime/Engine/Private/SceneUtils.cpp index 777b31dd13c5..3e00514689e5 100644 --- a/Engine/Source/Runtime/Engine/Private/SceneUtils.cpp +++ b/Engine/Source/Runtime/Engine/Private/SceneUtils.cpp @@ -63,7 +63,7 @@ template struct TDrawEvent; void FDrawEventRHIExecute::Start(IRHIComputeContext& InRHICommandContext, FColor Color, const TCHAR* Fmt, ...) { - check(IsInParallelRenderingThread() || IsInRHIThread() || (!GRHIThread && IsInRenderingThread())); + check(IsInParallelRenderingThread() || IsInRHIThread() || (!IsRunningRHIInSeparateThread() && IsInRenderingThread())); { va_list ptr; va_start(ptr, Fmt); @@ -106,12 +106,45 @@ bool IsMobileHDRMosaic() case 1: return true; case 2: + case 3: return false; default: return !(GSupportsHDR32bppEncodeModeIntrinsic && GSupportsShaderFramebufferFetch); } } +ENGINE_API EMobileHDRMode GetMobileHDRMode() +{ + EMobileHDRMode HDRMode = EMobileHDRMode::EnabledFloat16; + + if (IsMobileHDR() == false) + { + HDRMode = EMobileHDRMode::Disabled; + } + + if (IsMobileHDR32bpp()) + { + static auto* MobileHDR32bppMode = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.MobileHDR32bppMode")); + switch (MobileHDR32bppMode->GetValueOnAnyThread()) + { + case 1: + HDRMode = EMobileHDRMode::EnabledMosaic; + break; + case 2: + HDRMode = EMobileHDRMode::EnabledRGBE; + break; + case 3: + HDRMode = EMobileHDRMode::EnabledRGBA8; + break; + default: + HDRMode = (GSupportsHDR32bppEncodeModeIntrinsic && GSupportsShaderFramebufferFetch) ? EMobileHDRMode::EnabledRGBE : EMobileHDRMode::EnabledMosaic; + break; + } + } + + return HDRMode; +} + #if HAS_GPU_STATS static const int32 NumGPUProfilerBufferedFrames = 4; diff --git a/Engine/Source/Runtime/Engine/Private/SceneView.cpp b/Engine/Source/Runtime/Engine/Private/SceneView.cpp index c96622a960ee..c79cbdc69d33 100644 --- a/Engine/Source/Runtime/Engine/Private/SceneView.cpp +++ b/Engine/Source/Runtime/Engine/Private/SceneView.cpp @@ -18,7 +18,7 @@ #include "Engine/TextureCube.h" #include "IHeadMountedDisplay.h" #include "Engine/RendererSettings.h" -#include "LightPropagationVolumeBlendable.h" +#include "LightPropagationVolumeSettings.h" #include "Materials/MaterialInstanceDynamic.h" #include "HighResScreenshot.h" #include "Slate/SceneViewport.h" @@ -311,6 +311,16 @@ static TAutoConsoleVariable CVarRoughnessMax( ECVF_Cheat | ECVF_RenderThreadSafe ); +static TAutoConsoleVariable CVarAllowTranslucencyAfterDOF( + TEXT("r.SeparateTranslucency"), + 1, + TEXT("Allows to disable the separate translucency feature (all translucency is rendered in separate RT and composited\n") + TEXT("after DOF, if not specified otherwise in the material).\n") + TEXT(" 0: off (translucency is affected by depth of field)\n") + TEXT(" 1: on costs GPU performance and memory but keeps translucency unaffected by Depth of Field. (default)"), + ECVF_RenderThreadSafe); + + /** Global vertex color view mode setting when SHOW_VertexColors show flag is set */ EVertexColorViewMode::Type GVertexColorViewMode = EVertexColorViewMode::Color; @@ -2460,6 +2470,17 @@ const FSceneView& FSceneViewFamily::GetStereoEyeView(const EStereoscopicPass Eye } } +bool FSceneViewFamily::AllowTranslucencyAfterDOF() const +{ + return CVarAllowTranslucencyAfterDOF.GetValueOnRenderThread() != 0 + && GetFeatureLevel() >= ERHIFeatureLevel::SM4 + // && EngineShowFlags.PostProcessing + && !UseDebugViewPS() + && EngineShowFlags.SeparateTranslucency; + // If not, translucency after DOF will be rendered in standard translucency. +} + + FSceneViewFamilyContext::~FSceneViewFamilyContext() { // Cleanup the views allocated for this view family. diff --git a/Engine/Source/Runtime/Engine/Private/Selection.cpp b/Engine/Source/Runtime/Engine/Private/Selection.cpp index 106586d7366f..99b7ec15398d 100644 --- a/Engine/Source/Runtime/Engine/Private/Selection.cpp +++ b/Engine/Source/Runtime/Engine/Private/Selection.cpp @@ -16,16 +16,33 @@ USelection::USelection(const FObjectInitializer& ObjectInitializer) : UObject(ObjectInitializer) , SelectionMutex( 0 ) , bIsBatchDirty(false) +, SelectionAnnotation(nullptr) +, bOwnsSelectionAnnotation(false) { + } +void USelection::Initialize(FUObjectAnnotationSparseBool* InSelectionAnnotation) +{ + if (InSelectionAnnotation) + { + SelectionAnnotation = InSelectionAnnotation; + bOwnsSelectionAnnotation = false; + } + else + { + SelectionAnnotation = new FUObjectAnnotationSparseBool; + bOwnsSelectionAnnotation = true; + } +} + void USelection::Select(UObject* InObject) { check( InObject ); - const bool bSelectionChanged = !InObject->IsSelected(); - GSelectedAnnotation.Set(InObject); + const bool bSelectionChanged = !SelectionAnnotation->Get(InObject); + SelectionAnnotation->Set(InObject); if(bSelectionChanged) { @@ -59,7 +76,7 @@ void USelection::Deselect(UObject* InObject) check( InObject ); const bool bSelectionChanged = InObject->IsSelected(); - GSelectedAnnotation.Clear(InObject); + SelectionAnnotation->Clear(InObject); // Remove from selected list. SelectedObjects.Remove( InObject ); @@ -137,7 +154,7 @@ void USelection::DeselectAll( UClass* InClass ) // if the object is of type InClass then all objects of that same type will be removed RemovedClasses.Add(FSelectedClassInfo(Object->GetClass())); - GSelectedAnnotation.Clear(Object); + SelectionAnnotation->Clear(Object); SelectedObjects.RemoveAt( i ); // Call this after the item has been removed from the selection set. @@ -200,13 +217,13 @@ void USelection::Serialize(FArchive& Ar) // The set of selected objects may have changed, so make sure our annotations exactly match the list, otherwise // UObject::IsSelected() could return a result that was different from the list of objects returned by GetSelectedObjects() // This needs to happen in serialize because other code may check the selection state in PostEditUndo and the order of PostEditUndo is indeterminate. - GSelectedAnnotation.ClearAll(); + SelectionAnnotation->ClearAll(); for(TWeakObjectPtr& ObjectPtr : SelectedObjects) { if (UObject* Object = ObjectPtr.Get(true)) { - GSelectedAnnotation.Set(Object); + SelectionAnnotation->Set(Object); } } } @@ -226,3 +243,15 @@ bool USelection::Modify(bool bAlwaysMarkDirty/* =true */) return Super::Modify(bAlwaysMarkDirty); } + +void USelection::BeginDestroy() +{ + Super::BeginDestroy(); + + if (bOwnsSelectionAnnotation) + { + delete SelectionAnnotation; + SelectionAnnotation = nullptr; + } +} + diff --git a/Engine/Source/Runtime/Engine/Private/ShaderCompiler/ShaderCompiler.cpp b/Engine/Source/Runtime/Engine/Private/ShaderCompiler/ShaderCompiler.cpp index aac795a243d1..35e00e72437d 100644 --- a/Engine/Source/Runtime/Engine/Private/ShaderCompiler/ShaderCompiler.cpp +++ b/Engine/Source/Runtime/Engine/Private/ShaderCompiler/ShaderCompiler.cpp @@ -109,8 +109,9 @@ static int32 GDumpShaderDebugInfo = 0; static FAutoConsoleVariableRef CVarDumpShaderDebugInfo( TEXT("r.DumpShaderDebugInfo"), GDumpShaderDebugInfo, - TEXT("When set to 1, will cause any shaders that are then compiled to dump debug info to GameName/Saved/ShaderDebugInfo\n") + TEXT("When set to 1, will cause any material shaders that are then compiled to dump debug info to GameName/Saved/ShaderDebugInfo\n") TEXT("The debug info is platform dependent, but usually includes a preprocessed version of the shader source.\n") + TEXT("Global shaders automatically dump debug info if r.ShaderDevelopmentMode is enabled, this cvar is not necessary.\n") TEXT("On iOS, if the PowerVR graphics SDK is installed to the default path, the PowerVR shader compiler will be called and errors will be reported during the cook.") ); @@ -1533,7 +1534,7 @@ FProcHandle FShaderCompilingManager::LaunchWorker(const FString& WorkingDirector { WorkerParameters += FString(TEXT(" -buildmachine ")); } - if (PLATFORM_LINUX && UE_BUILD_DEBUG) + if (PLATFORM_LINUX && UE_BUILD_DEBUG) //-V560 { // when running a debug build under Linux, make SCW crash with core for easier debugging WorkerParameters += FString(TEXT(" -core ")); @@ -2106,7 +2107,7 @@ bool FShaderCompilingManager::HandlePotentialRetryOnError(TMapInput; Input.Target = Target; Input.ShaderFormat = LegacyShaderPlatformToShaderFormat(EShaderPlatform(Target.Platform)); - Input.SourceFilename = SourceFilename; + Input.SourceFilename = *FindShaderRelativePath(SourceFilename); Input.EntryPointName = FunctionName; Input.bCompilingForShaderPipeline = false; Input.bIncludeUsedOutputs = false; @@ -2612,7 +2613,10 @@ void GlobalBeginCompileShader( } } - if (GDumpShaderDebugInfo != 0) + static const auto CVarShaderDevelopmentMode = IConsoleManager::Get().FindConsoleVariable(TEXT("r.ShaderDevelopmentMode")); + + // Setup the debug info path if requested, or if this is a global shader and shader development mode is enabled + if (GDumpShaderDebugInfo != 0 || (ShaderType->GetGlobalShaderType() != NULL && CVarShaderDevelopmentMode->GetInt() != 0)) { Input.DumpDebugInfoPath = Input.DumpDebugInfoRootPath / Input.DebugGroupName; @@ -3847,7 +3851,7 @@ void VerifyGlobalShaders(EShaderPlatform Platform, bool bLoadedFromCacheFile) check(!FPlatformProperties::IsServerOnly()); check(GGlobalShaderMap[Platform]); - UE_LOG(LogShaders, Log, TEXT("Verifying Global Shaders for %s"), *LegacyShaderPlatformToShaderFormat(Platform).ToString()); + UE_LOG(LogMaterial, Log, TEXT("Verifying Global Shaders for %s"), *LegacyShaderPlatformToShaderFormat(Platform).ToString()); // Ensure that the global shader map contains all global shader types. TShaderMap* GlobalShaderMap = GetGlobalShaderMap(Platform); @@ -4135,7 +4139,7 @@ void CompileGlobalShaderMap(EShaderPlatform Platform, bool bRefreshShaderMap) { if (!GGlobalShaderMap[Platform]) { - GGlobalShaderMap[Platform] = new TShaderMap(); + GGlobalShaderMap[Platform] = new TShaderMap(Platform); } return; } @@ -4163,7 +4167,7 @@ void CompileGlobalShaderMap(EShaderPlatform Platform, bool bRefreshShaderMap) SlowTask.EnterProgressFrame(20); VerifyShaderSourceFiles(); - GGlobalShaderMap[Platform] = new TShaderMap(); + GGlobalShaderMap[Platform] = new TShaderMap(Platform); bool bLoadedFromCacheFile = false; diff --git a/Engine/Source/Runtime/Engine/Private/ShadowMap.cpp b/Engine/Source/Runtime/Engine/Private/ShadowMap.cpp index 2b57bc531aa2..a0a2e5cbb621 100644 --- a/Engine/Source/Runtime/Engine/Private/ShadowMap.cpp +++ b/Engine/Source/Runtime/Engine/Private/ShadowMap.cpp @@ -14,6 +14,9 @@ #include "GameFramework/WorldSettings.h" #if WITH_EDITOR + + #include "TextureCompressorModule.h" + // NOTE: We're only counting the top-level mip-map for the following variables. /** Total number of texels allocated for all shadowmap textures. */ ENGINE_API uint64 GNumShadowmapTotalTexels = 0; @@ -178,7 +181,7 @@ extern bool GGroupComponentLightmaps; struct FShadowMapPendingTexture : FTextureLayout { - TArray Allocations; + TArray> Allocations; UObject* Outer; @@ -218,7 +221,7 @@ struct FShadowMapPendingTexture : FTextureLayout * * @param InWorld World in which the textures exist */ - void StartEncoding(ULevel* LightingScenario); + void StartEncoding(ULevel* LightingScenario, ITextureCompressorModule* Compressor); /** * Create UObjects required in the encoding step, this is so we can multithread teh encode step @@ -330,7 +333,7 @@ void FShadowMapPendingTexture::CreateUObjects() bCreatedUObjects = true; } -void FShadowMapPendingTexture::StartEncoding(ULevel* LightingScenario) +void FShadowMapPendingTexture::StartEncoding(ULevel* LightingScenario, ITextureCompressorModule* Compressor) { // Create the shadow-map texture. CreateUObjects(); @@ -381,7 +384,7 @@ void FShadowMapPendingTexture::StartEncoding(ULevel* LightingScenario) } // Update the texture resource. - Texture->CachePlatformData(true, true); + Texture->CachePlatformData(true, true, Compressor); bFinishedEncoding = true; } @@ -754,6 +757,8 @@ void FShadowMap2D::EncodeTextures(UWorld* InWorld, ULevel* LightingScenario, boo GWarn->BeginSlowTask( NSLOCTEXT("ShadowMap2D", "BeginEncodingShadowMapsTask", "Encoding shadow-maps"), false ); const int32 PackedLightAndShadowMapTextureSize = InWorld->GetWorldSettings()->PackedLightAndShadowMapTextureSize; + ITextureCompressorModule* TextureCompressorModule = &FModuleManager::LoadModuleChecked(TEXTURE_COMPRESSOR_MODULENAME); + // Reset the pending shadow-map size. PendingShadowMapSize = 0; @@ -819,7 +824,7 @@ void FShadowMap2D::EncodeTextures(UWorld* InWorld, ULevel* LightingScenario, boo // Give the texture ownership of the allocations for (auto& Allocation : PendingGroup.Allocations) { - Texture->Allocations.Add(Allocation.Release()); + Texture->Allocations.Add(MoveTemp(Allocation)); } } PendingShadowMaps.Empty(); @@ -833,7 +838,7 @@ void FShadowMap2D::EncodeTextures(UWorld* InWorld, ULevel* LightingScenario, boo for (auto& PendingTexture : PendingTextures) { PendingTexture.CreateUObjects(); - auto AsyncEncodeTask = new (AsyncEncodeTasks)FAsyncEncode(&PendingTexture, LightingScenario, Counter); + auto AsyncEncodeTask = new (AsyncEncodeTasks)FAsyncEncode(&PendingTexture, LightingScenario, Counter, TextureCompressorModule); GThreadPool->AddQueuedWork(AsyncEncodeTask); } @@ -849,7 +854,7 @@ void FShadowMap2D::EncodeTextures(UWorld* InWorld, ULevel* LightingScenario, boo for (int32 TextureIndex = 0; TextureIndex < PendingTextures.Num(); TextureIndex++) { FShadowMapPendingTexture& PendingTexture = PendingTextures[TextureIndex]; - PendingTexture.StartEncoding(LightingScenario); + PendingTexture.StartEncoding(LightingScenario, TextureCompressorModule); } } @@ -1174,7 +1179,7 @@ int32 FShadowMap2D::EncodeSingleTexture(ULevel* LightingScenario, FShadowMapPend } } - for (FShadowMapAllocation* Allocation : PendingTexture.Allocations) + for (auto& Allocation : PendingTexture.Allocations) { Allocation->PostEncode(); } diff --git a/Engine/Source/Runtime/Engine/Private/SimpleConstructionScript.cpp b/Engine/Source/Runtime/Engine/Private/SimpleConstructionScript.cpp index c7d27df76212..191828a74e6a 100644 --- a/Engine/Source/Runtime/Engine/Private/SimpleConstructionScript.cpp +++ b/Engine/Source/Runtime/Engine/Private/SimpleConstructionScript.cpp @@ -1271,7 +1271,7 @@ USCS_Node* USimpleConstructionScript::CreateNodeAndRenameComponent(UActorCompone check(NewComponentTemplate); // note that naming logic is duplicated in CreateNode: - FName NewComponentVariableName = GenerateNewComponentName(NewComponentTemplate->GetClass()); + FName NewComponentVariableName = GenerateNewComponentName(NewComponentTemplate->GetClass(), NewComponentTemplate->GetFName()); // At this point we should have a unique, explicit name to use for the template object. check(NewComponentVariableName != NAME_None); diff --git a/Engine/Source/Runtime/Engine/Private/SkeletalMesh.cpp b/Engine/Source/Runtime/Engine/Private/SkeletalMesh.cpp index f87dd4c9061a..76dbcd336066 100644 --- a/Engine/Source/Runtime/Engine/Private/SkeletalMesh.cpp +++ b/Engine/Source/Runtime/Engine/Private/SkeletalMesh.cpp @@ -42,6 +42,7 @@ #include "Engine/Engine.h" #include "Animation/NodeMappingContainer.h" #include "GPUSkinCache.h" +#include "Misc/ConfigCacheIni.h" #if WITH_EDITOR #include "MeshUtilities.h" @@ -1198,34 +1199,35 @@ FArchive& operator<<(FArchive& Ar,FSkelMeshSection& S) void FMorphTargetVertexInfoBuffers::InitRHI() { - if (PerVertexInfoList.Num() > 0) + check(NumTotalWorkItems > 0); + { FRHIResourceCreateInfo CreateInfo; - void* PerVertexInfoListVBData = nullptr; - PerVertexInfoVB = RHICreateAndLockVertexBuffer(PerVertexInfoList.GetAllocatedSize(), BUF_Static | BUF_ShaderResource, CreateInfo, PerVertexInfoListVBData); - FMemory::Memcpy(PerVertexInfoListVBData, PerVertexInfoList.GetData(), PerVertexInfoList.GetAllocatedSize()); - RHIUnlockVertexBuffer(PerVertexInfoVB); - PerVertexInfoSRV = RHICreateShaderResourceView(PerVertexInfoVB, sizeof(uint32), PF_R32_UINT); - - void* FlattenedDeltasVBData = nullptr; - FlattenedDeltasVB = RHICreateAndLockVertexBuffer(FlattenedDeltaList.GetAllocatedSize(), BUF_Static | BUF_ShaderResource, CreateInfo, FlattenedDeltasVBData); - FMemory::Memcpy(FlattenedDeltasVBData, FlattenedDeltaList.GetData(), FlattenedDeltaList.GetAllocatedSize()); - RHIUnlockVertexBuffer(FlattenedDeltasVB); - FlattenedDeltasSRV = RHICreateShaderResourceView(FlattenedDeltasVB, sizeof(uint32), PF_R32_UINT); - - NumInfluencedVerticesByMorphs = (uint32)PerVertexInfoList.Num(); - - PerVertexInfoList.Empty(); - FlattenedDeltaList.Empty(); + void* VertexIndicesVBData = nullptr; + VertexIndicesVB = RHICreateAndLockVertexBuffer(VertexIndices.GetAllocatedSize(), BUF_Static | BUF_ShaderResource, CreateInfo, VertexIndicesVBData); + FMemory::Memcpy(VertexIndicesVBData, VertexIndices.GetData(), VertexIndices.GetAllocatedSize()); + RHIUnlockVertexBuffer(VertexIndicesVB); + VertexIndicesSRV = RHICreateShaderResourceView(VertexIndicesVB, 4, PF_R32_UINT); } + { + FRHIResourceCreateInfo CreateInfo; + void* MorphDeltasVBData = nullptr; + MorphDeltasVB = RHICreateAndLockVertexBuffer(MorphDeltas.GetAllocatedSize(), BUF_Static | BUF_ShaderResource, CreateInfo, MorphDeltasVBData); + FMemory::Memcpy(MorphDeltasVBData, MorphDeltas.GetData(), MorphDeltas.GetAllocatedSize()); + RHIUnlockVertexBuffer(MorphDeltasVB); + MorphDeltasSRV = RHICreateShaderResourceView(MorphDeltasVB, 2, PF_R16F); + } + + VertexIndices.Empty(); + MorphDeltas.Empty(); } void FMorphTargetVertexInfoBuffers::ReleaseRHI() { - PerVertexInfoVB.SafeRelease(); - PerVertexInfoSRV.SafeRelease(); - FlattenedDeltasVB.SafeRelease(); - FlattenedDeltasSRV.SafeRelease(); + VertexIndicesVB.SafeRelease(); + VertexIndicesSRV.SafeRelease(); + MorphDeltasVB.SafeRelease(); + MorphDeltasSRV.SafeRelease(); } /*----------------------------------------------------------------------------- @@ -1543,44 +1545,67 @@ void FStaticLODModel::InitResources(bool bNeedsVertexColors, int32 LODIndex, TAr if (RHISupportsComputeShaders(GMaxRHIShaderPlatform) && InMorphTargets.Num() > 0) { + MorphTargetVertexInfoBuffers.VertexIndices.Empty(); + MorphTargetVertexInfoBuffers.MorphDeltas.Empty(); + MorphTargetVertexInfoBuffers.WorkItemsPerMorph.Empty(); + MorphTargetVertexInfoBuffers.StartOffsetPerMorph.Empty(); + MorphTargetVertexInfoBuffers.MaximumValuePerMorph.Empty(); + MorphTargetVertexInfoBuffers.MinimumValuePerMorph.Empty(); + MorphTargetVertexInfoBuffers.NumTotalWorkItems = 0; + // Populate the arrays to be filled in later in the render thread - - // Auxiliary mapping for affected vertex indices by morph to its weights - TMap> AuxDeltaList; - - int32 TotalNumDeltas = 0; for (int32 AnimIdx = 0; AnimIdx < InMorphTargets.Num(); ++AnimIdx) { + uint32 StartOffset = MorphTargetVertexInfoBuffers.NumTotalWorkItems; + MorphTargetVertexInfoBuffers.StartOffsetPerMorph.Add(StartOffset); + + float MaximumValues[4] = { -FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX }; + float MinimumValues[4] = { +FLT_MAX, +FLT_MAX, +FLT_MAX, +FLT_MAX }; UMorphTarget* MorphTarget = InMorphTargets[AnimIdx]; - int32 NumSrcDeltas = 0; - FMorphTargetDelta* SrcDelta = MorphTarget->GetMorphTargetDelta(LODIndex, NumSrcDeltas); - for (int32 SrcDeltaIndex = 0; SrcDeltaIndex < NumSrcDeltas; ++SrcDeltaIndex, ++SrcDelta) + FMorphTargetDelta* MorphDeltas = MorphTarget->GetMorphTargetDelta(LODIndex, NumSrcDeltas); + for (int32 DeltaIndex = 0; DeltaIndex < NumSrcDeltas; DeltaIndex++) { - TArray& FlattenedDeltas = AuxDeltaList.FindOrAdd(SrcDelta->SourceIdx); - FMorphTargetVertexInfoBuffers::FFlattenedDelta* NewDelta = new(FlattenedDeltas) FMorphTargetVertexInfoBuffers::FFlattenedDelta; - NewDelta->PosDelta = SrcDelta->PositionDelta; - NewDelta->TangentDelta = SrcDelta->TangentZDelta; - NewDelta->WeightIndex = AnimIdx; - ++TotalNumDeltas; + const auto& MorphDelta = MorphDeltas[DeltaIndex]; + if (!(MorphDelta.PositionDelta.IsNearlyZero(0.0000001f) && MorphDelta.TangentZDelta.IsNearlyZero(0.0000001f))) + { + MaximumValues[0] = FMath::Max(MaximumValues[0], MorphDelta.PositionDelta.X); + MaximumValues[1] = FMath::Max(MaximumValues[1], MorphDelta.PositionDelta.Y); + MaximumValues[2] = FMath::Max(MaximumValues[2], MorphDelta.PositionDelta.Z); + MaximumValues[3] = FMath::Max(MaximumValues[3], FMath::Max(MorphDelta.TangentZDelta.X, FMath::Max(MorphDelta.TangentZDelta.Y, MorphDelta.TangentZDelta.Z))); + + MinimumValues[0] = FMath::Min(MinimumValues[0], MorphDelta.PositionDelta.X); + MinimumValues[1] = FMath::Min(MinimumValues[1], MorphDelta.PositionDelta.Y); + MinimumValues[2] = FMath::Min(MinimumValues[2], MorphDelta.PositionDelta.Z); + MinimumValues[3] = FMath::Min(MinimumValues[3], FMath::Min(MorphDelta.TangentZDelta.X, FMath::Min(MorphDelta.TangentZDelta.Y, MorphDelta.TangentZDelta.Z))); + + MorphTargetVertexInfoBuffers.VertexIndices.Add(MorphDelta.SourceIdx); + MorphTargetVertexInfoBuffers.MorphDeltas.Emplace(MorphDelta.PositionDelta, MorphDelta.TangentZDelta); + MorphTargetVertexInfoBuffers.NumTotalWorkItems++; + } } + + uint32 MorphTargetSize = MorphTargetVertexInfoBuffers.NumTotalWorkItems - StartOffset; + if (MorphTargetSize > 0) + { + ensureMsgf(MaximumValues[0] < +32752.0f && MaximumValues[1] < +32752.0f && MaximumValues[2] < +32752.0f && MaximumValues[3] < +32752.0f, TEXT("Huge MorphTarget Delta found in %s at index %i, might break down because we use half float storage"), *MorphTarget->GetName(), AnimIdx); + ensureMsgf(MinimumValues[0] > -32752.0f && MinimumValues[1] > -32752.0f && MinimumValues[2] > -32752.0f && MaximumValues[3] > -32752.0f, TEXT("Huge MorphTarget Delta found in %s at index %i, might break down because we use half float storage"), *MorphTarget->GetName(), AnimIdx); + } + else + { + bool bSuppressWarningOnEmptyMorphTargetAnimation = false; + GConfig->GetBool(TEXT("/Script/Engine.Engine"), TEXT("bSuppressWarningOnEmptyMorphTargetAnimation"), bSuppressWarningOnEmptyMorphTargetAnimation, GEngineIni); + UE_CLOG(!bSuppressWarningOnEmptyMorphTargetAnimation, LogSkeletalMesh, Warning, TEXT("PerformanceWarning: Empty MorphTarget Animation found in %s at index %i. Check if this asset should contain any morphs and reimport without them or remove the empty targets if possible."), *MorphTarget->GetFullName(), AnimIdx); + } + MorphTargetVertexInfoBuffers.WorkItemsPerMorph.Add(MorphTargetSize); + MorphTargetVertexInfoBuffers.MaximumValuePerMorph.Add(FVector4(MaximumValues[0], MaximumValues[1], MaximumValues[2], MaximumValues[3])); + MorphTargetVertexInfoBuffers.MinimumValuePerMorph.Add(FVector4(MinimumValues[0], MinimumValues[1], MinimumValues[2], MinimumValues[3])); } - MorphTargetVertexInfoBuffers.FlattenedDeltaList.Empty(TotalNumDeltas); - MorphTargetVertexInfoBuffers.PerVertexInfoList.AddUninitialized(AuxDeltaList.Num()); - int32 StartDelta = 0; - FMorphTargetVertexInfoBuffers::FPerVertexInfo* NewPerVertexInfo = MorphTargetVertexInfoBuffers.PerVertexInfoList.GetData(); - for (auto& Pair : AuxDeltaList) - { - NewPerVertexInfo->DestVertexIndex = Pair.Key; - NewPerVertexInfo->StartDelta = StartDelta; - NewPerVertexInfo->NumDeltas = Pair.Value.Num(); - MorphTargetVertexInfoBuffers.FlattenedDeltaList.Append(Pair.Value); - StartDelta += Pair.Value.Num(); - ++NewPerVertexInfo; - } - - if (AuxDeltaList.Num() > 0) + check(MorphTargetVertexInfoBuffers.WorkItemsPerMorph.Num() == MorphTargetVertexInfoBuffers.StartOffsetPerMorph.Num()); + check(MorphTargetVertexInfoBuffers.WorkItemsPerMorph.Num() == MorphTargetVertexInfoBuffers.MaximumValuePerMorph.Num()); + check(MorphTargetVertexInfoBuffers.WorkItemsPerMorph.Num() == MorphTargetVertexInfoBuffers.MinimumValuePerMorph.Num()); + if (MorphTargetVertexInfoBuffers.NumTotalWorkItems > 0) { BeginInitResource(&MorphTargetVertexInfoBuffers); } @@ -2846,6 +2871,8 @@ void USkeletalMesh::PostEditChangeProperty(FPropertyChangedEvent& PropertyChange FMultiComponentReregisterContext ReregisterContext(ComponentsToReregister); } + UpdateUVChannelData(true); + Super::PostEditChangeProperty(PropertyChangedEvent); } @@ -3305,6 +3332,11 @@ void USkeletalMesh::PostLoad() } } } + + if (GetLinkerCustomVersion(FRenderingObjectVersion::GUID) < FRenderingObjectVersion::FixedMeshUVDensity) + { + UpdateUVChannelData(true); + } #endif // WITH_EDITOR // initialize rendering resources @@ -4807,7 +4839,7 @@ bool USkeletalMeshSocket::AttachActor(AActor* Actor, class USkeletalMeshComponen Actor->SetActorLocation(SocketTM.GetOrigin(), false); Actor->SetActorRotation(SocketTM.Rotator()); - Actor->GetRootComponent()->SnapTo( SkelComp, SocketName ); + Actor->GetRootComponent()->AttachToComponent(SkelComp, FAttachmentTransformRules::SnapToTargetNotIncludingScale, SocketName); #if WITH_EDITOR if (GIsEditor) @@ -5126,7 +5158,7 @@ public: if (ActualPreviewSectionIdx != INDEX_NONE && Sections.IsValidIndex(ActualPreviewSectionIdx)) { const FSkelMeshSection& PreviewSection = Sections[ActualPreviewSectionIdx]; - if (PreviewSection.CorrespondClothSectionIndex != INDEX_NONE) + if (PreviewSection.bDisabled && PreviewSection.CorrespondClothSectionIndex != INDEX_NONE) { ActualPreviewSectionIdx = PreviewSection.CorrespondClothSectionIndex; } @@ -5149,7 +5181,7 @@ public: if (ActualPreviewSectionIdx != INDEX_NONE) { const FSkelMeshSection& PreviewSection = Sections[ActualPreviewSectionIdx]; - if (PreviewSection.CorrespondClothSectionIndex != INDEX_NONE) + if (PreviewSection.bDisabled && PreviewSection.CorrespondClothSectionIndex != INDEX_NONE) { ActualPreviewSectionIdx = PreviewSection.CorrespondClothSectionIndex; } @@ -5255,6 +5287,19 @@ void FSkeletalMeshSceneProxy::GetMeshElementsConditionallySelectable(const TArra check(LODSection.SectionElements.Num() == LODModel.Sections.Num()); +#if WITH_EDITORONLY_DATA + //Find the real editor selected section + int32 RealSelectedEditorSection = SkeletalMeshForDebug->SelectedEditorSection; + if (RealSelectedEditorSection != INDEX_NONE && LODModel.Sections.IsValidIndex(SkeletalMeshForDebug->SelectedEditorSection)) + { + const FSkelMeshSection& SelectEditorSection = LODModel.Sections[SkeletalMeshForDebug->SelectedEditorSection]; + if (SelectEditorSection.bDisabled && SelectEditorSection.CorrespondClothSectionIndex != INDEX_NONE && LODModel.Sections.IsValidIndex(SelectEditorSection.CorrespondClothSectionIndex)) + { + RealSelectedEditorSection = SelectEditorSection.CorrespondClothSectionIndex; + } + } +#endif + for (FSkeletalMeshSectionIter Iter(LODIndex, *MeshObject, LODModel, LODSection); Iter; ++Iter) { const FSkelMeshSection& Section = Iter.GetSection(); @@ -5272,7 +5317,7 @@ void FSkeletalMeshSceneProxy::GetMeshElementsConditionallySelectable(const TArra } else { - bSectionSelected = (SkeletalMeshForDebug->SelectedEditorSection == Iter.GetSectionElementIndex()); + bSectionSelected = (RealSelectedEditorSection == SectionIndex); } #endif @@ -5302,7 +5347,7 @@ void FSkeletalMeshSceneProxy::GetMeshElementsConditionallySelectable(const TArra DebugDrawPhysicsAsset(ViewIndex, Collector, ViewFamily.EngineShowFlags); } - if (EngineShowFlags.MassProperties && DebugMassData.Num() > 0 && MeshObject) + if (EngineShowFlags.MassProperties && DebugMassData.Num() > 0) { FPrimitiveDrawInterface* PDI = Collector.GetPDI(ViewIndex); const TArray& ComponentSpaceTransforms = *MeshObject->GetComponentSpaceTransforms(); diff --git a/Engine/Source/Runtime/Engine/Private/SkeletalMeshComponentPhysics.cpp b/Engine/Source/Runtime/Engine/Private/SkeletalMeshComponentPhysics.cpp index 7872fb1e5320..3e4631685243 100644 --- a/Engine/Source/Runtime/Engine/Private/SkeletalMeshComponentPhysics.cpp +++ b/Engine/Source/Runtime/Engine/Private/SkeletalMeshComponentPhysics.cpp @@ -534,7 +534,7 @@ void USkeletalMeshComponent::InitArticulated(FPhysScene* PhysScene) return; } - FVector Scale3D = ComponentToWorld.GetScale3D(); + FVector Scale3D = GetComponentTransform().GetScale3D(); // Find root physics body RootBodyData.BodyIndex = INDEX_NONE; //Reset the root body index just in case we need to refind a new one @@ -1315,7 +1315,7 @@ void USkeletalMeshComponent::SendRenderDebugPhysics(FPrimitiveSceneProxy* Overri FPrimitiveSceneProxy::FDebugMassData& MassData = DebugMassData.Last(); const FTransform MassToWorld = BI->GetMassSpaceToWorldSpace(); const FTransform& BoneTM = GetComponentSpaceTransforms()[BoneIndex]; - const FTransform BoneToWorld = BoneTM * ComponentToWorld; + const FTransform BoneToWorld = BoneTM * GetComponentTransform(); MassData.LocalCenterOfMass = BoneToWorld.InverseTransformPosition(MassToWorld.GetLocation()); MassData.LocalTensorOrientation = MassToWorld.GetRotation() * BoneToWorld.GetRotation().Inverse(); @@ -1753,22 +1753,36 @@ void USkeletalMeshComponent::UpdateHasValidBodies() void USkeletalMeshComponent::UpdateBoneBodyMapping() { - if(Bodies.Num() > 0) //If using per poly then there's no bodies to update indices on + if (Bodies.Num() > 0) //If using per poly then there's no bodies to update indices on { // If we have a physics asset.. if (const UPhysicsAsset* const PhysicsAsset = GetPhysicsAsset()) { + bool bNeedsReInit = false; + // For each body in physics asset.. for (int32 BodyIndex = 0; BodyIndex < PhysicsAsset->SkeletalBodySetups.Num(); BodyIndex++) { // .. find the matching graphics bone index int32 BoneIndex = GetBoneIndex(PhysicsAsset->SkeletalBodySetups[BodyIndex]->BoneName); - Bodies[BodyIndex]->InstanceBoneIndex = BoneIndex; + FBodyInstance* Inst = Bodies[BodyIndex]; + check(Inst); - if (BoneIndex == INDEX_NONE) + // Make sure physics state matches presence of bone + bool bHasValidBone = (BoneIndex != INDEX_NONE); + if (bHasValidBone != Inst->IsValidBodyInstance()) { - //TODO: warn that body was found without corresponding bone + // If not, we need to recreate physics asset to clean up bodies or create new ones + bNeedsReInit = true; } + + Inst->InstanceBoneIndex = BoneIndex; + } + + // If the set of bodies needs to change, we recreate physics asset + if (bNeedsReInit) + { + RecreatePhysicsState(); } } } @@ -1845,7 +1859,7 @@ FVector USkeletalMeshComponent::GetSkinnedVertexPosition(int32 VertexIndex) cons { // a simulated position is in world space and convert this to local space // because SkinnedMeshComponent::GetSkinnedVertexPosition() returns the position in local space - SimulatedPos = ComponentToWorld.InverseTransformPosition(SimulatedPos); + SimulatedPos = GetComponentTransform().InverseTransformPosition(SimulatedPos); // if blend weight is 1.0, doesn't need to blend with a skinned position if (ClothBlendWeight < 1.0f) @@ -1939,7 +1953,7 @@ bool USkeletalMeshComponent::GetClosestPointOnPhysicsAsset(const FVector& WorldP { const TArray& BoneTransforms = GetComponentSpaceTransforms(); const bool bHasMasterPoseComponent = MasterPoseComponent.IsValid(); - const FVector ComponentPosition = ComponentToWorld.InverseTransformPosition(WorldPosition); + const FVector ComponentPosition = GetComponentTransform().InverseTransformPosition(WorldPosition); float CurrentClosestDistance = FLT_MAX; int32 CurrentClosestBoneIndex = INDEX_NONE; @@ -1970,7 +1984,7 @@ bool USkeletalMeshComponent::GetClosestPointOnPhysicsAsset(const FVector& WorldP { bSuccess = true; - const FTransform BoneTM = bHasMasterPoseComponent ? GetBoneTransform(CurrentClosestBoneIndex) : (BoneTransforms[CurrentClosestBoneIndex] * ComponentToWorld); + const FTransform BoneTM = bHasMasterPoseComponent ? GetBoneTransform(CurrentClosestBoneIndex) : (BoneTransforms[CurrentClosestBoneIndex] * GetComponentTransform()); ClosestPointOnPhysicsAsset.Distance = CurrentClosestBodySetup->GetClosestPointAndNormal(WorldPosition, BoneTM, ClosestPointOnPhysicsAsset.ClosestWorldPosition, ClosestPointOnPhysicsAsset.Normal); ClosestPointOnPhysicsAsset.BoneName = CurrentClosestBodySetup->BoneName; } @@ -2022,7 +2036,7 @@ bool USkeletalMeshComponent::LineTraceComponent(struct FHitResult& OutHit, const } #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) - if(World && (World->DebugDrawTraceTag != NAME_None) && (World->DebugDrawTraceTag == Params.TraceTag)) + if(World && World->DebugDrawSceneQueries(Params.TraceTag)) { TArray Hits; if (bHaveHit) @@ -2091,7 +2105,7 @@ bool USkeletalMeshComponent::ComponentOverlapMultiImpl(TArrayCreateActor(this, Asset, BaseAssetIndex); } + + WritebackClothingSimulationData(); } } @@ -2191,7 +2207,7 @@ void USkeletalMeshComponent::GetWindForCloth_GameThread(FVector& WindDirection, // set wind if(IsWindEnabled()) { - FVector Position = ComponentToWorld.GetTranslation(); + FVector Position = GetComponentTransform().GetTranslation(); float WindSpeed; float WindMinGust; @@ -2296,8 +2312,7 @@ void USkeletalMeshComponent::ProcessClothCollisionWithEnvironment() // to collide with other clothing objects ObjectParams.AddObjectTypesToQuery(ECollisionChannel::ECC_PhysicsBody); - static FName ClothOverlapComponentsName(TEXT("ClothOverlapComponents")); - FCollisionQueryParams Params(ClothOverlapComponentsName, false); + FCollisionQueryParams Params(SCENE_QUERY_STAT(ClothOverlapComponents), false); GetWorld()->OverlapMultiByObjectType(Overlaps, Bounds.Origin, FQuat::Identity, ObjectParams, FCollisionShape::MakeBox(Bounds.BoxExtent), Params); @@ -2331,9 +2346,9 @@ void USkeletalMeshComponent::ProcessClothCollisionWithEnvironment() // Matrices required to transform shapes into sim space (component space) // Transform of external component and matrix describing external component -> this component - FTransform Transform = Component->ComponentToWorld; + FTransform Transform = Component->GetComponentTransform(); FMatrix TransformMatrix = Transform.ToMatrixWithScale(); - FMatrix ComponentToClothMatrix = TransformMatrix * ComponentToWorld.ToMatrixWithScale().Inverse(); + FMatrix ComponentToClothMatrix = TransformMatrix * GetComponentTransform().ToMatrixWithScale().Inverse(); for(PxShape* Shape : AllShapes) { @@ -2561,15 +2576,17 @@ void USkeletalMeshComponent::UpdateClothTransformImp() #endif // WITH_CLOTH_COLLISION_DETECTION #if !(UE_BUILD_SHIPPING) - if (ComponentToWorld.GetRotation().ContainsNaN()) + FTransform ComponentTransform = GetComponentTransform(); + if (ComponentTransform.GetRotation().ContainsNaN()) { - logOrEnsureNanError(TEXT("SkeletalMeshComponent::UpdateClothTransform found NaN in ComponentToWorld.GetRotation()")); - ComponentToWorld.SetRotation(FQuat(0.0f, 0.0f, 0.0f, 1.0f)); + logOrEnsureNanError(TEXT("SkeletalMeshComponent::UpdateClothTransform found NaN in GetComponentTransform().GetRotation()")); + ComponentTransform.SetRotation(FQuat(0.0f, 0.0f, 0.0f, 1.0f)); + SetComponentToWorld(ComponentTransform); } - if (ComponentToWorld.ContainsNaN()) + if (ComponentTransform.ContainsNaN()) { - logOrEnsureNanError(TEXT("SkeletalMeshComponent::UpdateClothTransform still found NaN in ComponentToWorld (wasn't the rotation)")); - ComponentToWorld.SetIdentity(); + logOrEnsureNanError(TEXT("SkeletalMeshComponent::UpdateClothTransform still found NaN in GetComponentTransform() (wasn't the rotation)")); + SetComponentToWorld(FTransform::Identity); } #endif } @@ -2768,7 +2785,7 @@ bool USkeletalMeshComponent::GetClothSimulatedPosition_GameThread(const FGuid& A if(ActorData && ActorData->Positions.IsValidIndex(VertexIndex)) { - OutSimulPos = ComponentToWorld.TransformPosition(ActorData->Positions[VertexIndex]); + OutSimulPos = GetComponentTransform().TransformPosition(ActorData->Positions[VertexIndex]); bSucceed = true; } @@ -2935,7 +2952,7 @@ FTransform USkeletalMeshComponent::GetComponentTransformFromBodyInstance(FBodyIn } else { - return ComponentToWorld; + return GetComponentTransform(); } } #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Runtime/Engine/Private/SkeletalRender.cpp b/Engine/Source/Runtime/Engine/Private/SkeletalRender.cpp index 0f2b5c3a8482..b79955b40e8d 100644 --- a/Engine/Source/Runtime/Engine/Private/SkeletalRender.cpp +++ b/Engine/Source/Runtime/Engine/Private/SkeletalRender.cpp @@ -84,7 +84,7 @@ void FSkeletalMeshObject::UpdateMinDesiredLODLevel(const FSceneView* View, const int32 NewLODLevel = 0; // Look for a lower LOD if the EngineShowFlags is enabled - Thumbnail rendering disables LODs - if( View && View->Family && 1==View->Family->EngineShowFlags.LOD ) + if( View->Family && 1==View->Family->EngineShowFlags.LOD ) { // Iterate from worst to best LOD for(int32 LODLevel = SkeletalMeshResource->LODModels.Num()-1; LODLevel > 0; LODLevel--) diff --git a/Engine/Source/Runtime/Engine/Private/SkeletalRenderGPUSkin.cpp b/Engine/Source/Runtime/Engine/Private/SkeletalRenderGPUSkin.cpp index 7f1432a631b7..0e99d3b166dd 100644 --- a/Engine/Source/Runtime/Engine/Private/SkeletalRenderGPUSkin.cpp +++ b/Engine/Source/Runtime/Engine/Private/SkeletalRenderGPUSkin.cpp @@ -10,7 +10,7 @@ #include "SkeletalRender.h" #include "GPUSkinCache.h" #include "Animation/MorphTarget.h" - +#include "ClearQuad.h" #include "ShaderParameterUtils.h" @@ -18,7 +18,6 @@ DEFINE_LOG_CATEGORY_STATIC(LogSkeletalGPUSkinMesh, Warning, All); // 0/1 #define UPDATE_PER_BONE_DATA_ONLY_FOR_OBJECT_BEEN_VISIBLE 1 -#define MORPH_TARGETS_USE_BYTE_BUFFER_UAV 0 DECLARE_CYCLE_STAT(TEXT("Morph Vertex Buffer Update"),STAT_MorphVertexBuffer_Update,STATGROUP_MorphTarget); DECLARE_CYCLE_STAT(TEXT("Morph Vertex Buffer Init"),STAT_MorphVertexBuffer_Init,STATGROUP_MorphTarget); @@ -58,40 +57,41 @@ void FMorphVertexBuffer::InitDynamicRHI() // Create the buffer rendering resource uint32 Size = LodModel.NumVertices * sizeof(FMorphGPUSkinVertex); FRHIResourceCreateInfo CreateInfo; - void* BufferData = nullptr; bool bSupportsComputeShaders = RHISupportsComputeShaders(GMaxRHIShaderPlatform); bUsesComputeShader = GUseGPUMorphTargets != 0 && bSupportsComputeShaders; #if PLATFORM_PS4 // PS4 requires non-static buffers in order to be updated on the GPU while the CPU is writing into it - EBufferUsageFlags Flags = BUF_Dynamic; + EBufferUsageFlags Flags = bUsesComputeShader ? (EBufferUsageFlags)(BUF_Dynamic | BUF_UnorderedAccess) : BUF_Dynamic; #else EBufferUsageFlags Flags = bUsesComputeShader ? (EBufferUsageFlags)(BUF_Static | BUF_UnorderedAccess) : BUF_Dynamic; -#if MORPH_TARGETS_USE_BYTE_BUFFER_UAV - Flags = (EBufferUsageFlags)(Flags | (bUsesComputeShader ? BUF_ByteAddressBuffer : 0)); -#endif #endif // BUF_ShaderResource is needed for Morph support of the SkinCache Flags = (EBufferUsageFlags)(Flags | BUF_ShaderResource); - VertexBufferRHI = RHICreateAndLockVertexBuffer(Size, Flags, CreateInfo, BufferData); + VertexBufferRHI = RHICreateVertexBuffer(Size, Flags, CreateInfo); bool bUsesSkinCache = bSupportsComputeShaders && IsGPUSkinCacheAvailable() && GEnableGPUSkinCache; if (bUsesSkinCache) { SRVValue = RHICreateShaderResourceView(VertexBufferRHI, 4, PF_R32_FLOAT); } - // Lock the buffer. - FMorphGPUSkinVertex* Buffer = (FMorphGPUSkinVertex*)BufferData; - FMemory::Memzero(&Buffer[0], sizeof(FMorphGPUSkinVertex)*LodModel.NumVertices); - // Unlock the buffer. - RHIUnlockVertexBuffer(VertexBufferRHI); - - if (bUsesComputeShader) + if (!bUsesComputeShader) + { + // Lock the buffer. + void* BufferData = RHILockVertexBuffer(VertexBufferRHI, 0, sizeof(FMorphGPUSkinVertex)*LodModel.NumVertices, RLM_WriteOnly); + FMorphGPUSkinVertex* Buffer = (FMorphGPUSkinVertex*)BufferData; + FMemory::Memzero(&Buffer[0], sizeof(FMorphGPUSkinVertex)*LodModel.NumVertices); + // Unlock the buffer. + RHIUnlockVertexBuffer(VertexBufferRHI); + bNeedsInitialClear = false; + } + else { UAVValue = RHICreateUnorderedAccessView(VertexBufferRHI, PF_R32_UINT); + bNeedsInitialClear = true; } // hasn't been updated yet @@ -195,21 +195,6 @@ void FSkeletalMeshObjectGPUSkin::InitMorphResources(bool bInUsePerBoneMotionBlur SkelLOD.InitMorphResources(MeshLODInfo,bInUsePerBoneMotionBlur, FeatureLevel); } bMorphResourcesInitialized = true; - - if (MorphTargetWeights.Num() > 0) - { - int32 NumWeights = MorphTargetWeights.Num(); - FVertexBufferAndSRV* MorphWeightsVertexBufferPtr = &MorphWeightsVertexBuffer; - ENQUEUE_RENDER_COMMAND(InitMorphWeightsVertexBuffer)( - [NumWeights, MorphWeightsVertexBufferPtr](FRHICommandList& RHICmdList) - { - const uint32 Size = (uint32)NumWeights * sizeof(float); - FRHIResourceCreateInfo CreateInfo; - MorphWeightsVertexBufferPtr->VertexBufferRHI = RHICreateVertexBuffer(Size, BUF_Dynamic | BUF_ShaderResource, CreateInfo); - MorphWeightsVertexBufferPtr->VertexBufferSRV = RHICreateShaderResourceView(MorphWeightsVertexBufferPtr->VertexBufferRHI, sizeof(float), PF_R32_UINT); - } - ); - } } void FSkeletalMeshObjectGPUSkin::ReleaseMorphResources() @@ -221,18 +206,6 @@ void FSkeletalMeshObjectGPUSkin::ReleaseMorphResources() SkelLOD.ReleaseMorphResources(); } - if (MorphWeightsVertexBuffer.VertexBufferRHI) - { - FVertexBufferAndSRV* MorphWeightsVertexBufferPtr = &MorphWeightsVertexBuffer; - ENQUEUE_RENDER_COMMAND(InitMorphWeightsVertexBuffer)( - [MorphWeightsVertexBufferPtr](FRHICommandList& RHICmdList) - { - MorphWeightsVertexBufferPtr->VertexBufferRHI.SafeRelease(); - MorphWeightsVertexBufferPtr->VertexBufferSRV.SafeRelease(); - } - ); - } - bMorphResourcesInitialized = false; } @@ -385,6 +358,15 @@ void FSkeletalMeshObjectGPUSkin::ProcessUpdatedDynamicData(FGPUSkinCache* GPUSki bool bGPUSkinCacheEnabled = GEnableGPUSkinCache && (FeatureLevel >= ERHIFeatureLevel::SM5); + if (LOD.MorphVertexBuffer.bNeedsInitialClear && !(bMorph && bMorphNeedsUpdate)) + { + if (IsValidRef(LOD.MorphVertexBuffer.GetUAV())) + { + ClearUAV(RHICmdList, LOD.MorphVertexBuffer.GetUAV(), LOD.MorphVertexBuffer.GetUAVSize(), 0); + } + } + LOD.MorphVertexBuffer.bNeedsInitialClear = false; + if(bMorph) { bDataPresent = true; @@ -393,17 +375,16 @@ void FSkeletalMeshObjectGPUSkin::ProcessUpdatedDynamicData(FGPUSkinCache* GPUSki // only update if the morph data changed and there are weighted morph targets if(bMorphNeedsUpdate) { - if (GUseGPUMorphTargets) + if (GUseGPUMorphTargets && RHISupportsComputeShaders(GMaxRHIShaderPlatform)) { - SCOPE_CYCLE_COUNTER(STAT_MorphVertexBuffer_RhiLockAndCopy); - const uint32 MorphWeightsSize = DynamicData->MorphTargetWeights.GetAllocatedSize(); - void* NewMorphWeights = RHICmdList.LockVertexBuffer(MorphWeightsVertexBuffer.VertexBufferRHI, 0, MorphWeightsSize, RLM_WriteOnly); - FMemory::Memcpy(NewMorphWeights, DynamicData->MorphTargetWeights.GetData(), MorphWeightsSize); - RHICmdList.UnlockVertexBuffer(MorphWeightsVertexBuffer.VertexBufferRHI); + // update the morph data for the lod (before SkinCache) + LOD.UpdateMorphVertexBufferGPU(RHICmdList, DynamicData->MorphTargetWeights, LODModel.MorphTargetVertexInfoBuffers); } - - // update the morph data for the lod (before SkinCache) - LOD.UpdateMorphVertexBuffer(RHICmdList, DynamicData->ActiveMorphTargets, DynamicData->MorphTargetWeights, MorphWeightsVertexBuffer.VertexBufferSRV, LODModel.MorphTargetVertexInfoBuffers.GetNumInfluencedVerticesByMorphs(), LODModel.MorphTargetVertexInfoBuffers.PerVertexInfoSRV, LODModel.MorphTargetVertexInfoBuffers.FlattenedDeltasSRV); + else + { + // update the morph data for the lod (before SkinCache) + LOD.UpdateMorphVertexBufferCPU(DynamicData->ActiveMorphTargets, DynamicData->MorphTargetWeights); + } } } else @@ -500,209 +481,287 @@ void FSkeletalMeshObjectGPUSkin::ProcessUpdatedDynamicData(FGPUSkinCache* GPUSki } } -void FMorphTargetBaseShader::SetParameters(FRHICommandList& RHICmdList, int32 NumLODVertices, int32 NumMorphVertices, FShaderResourceViewRHIRef MorphWeightsSRV, FShaderResourceViewRHIRef PerVertexInfoListSRV, FShaderResourceViewRHIRef FlattenedDeltaListSRV, FUnorderedAccessViewRHIParamRef UAV) +TArray FSkeletalMeshObjectGPUSkin::FSkeletalMeshObjectLOD::MorphAccumulatedWeightArray; + +void FGPUMorphUpdateCS::SetParameters(FRHICommandList& RHICmdList, const FVector4& LocalScale, const FMorphTargetVertexInfoBuffers& MorphTargetVertexInfoBuffers, FMorphVertexBuffer& MorphVertexBuffer) { FComputeShaderRHIRef CS = GetComputeShader(); RHICmdList.SetComputeShader(CS); - FVector4 MorphTargetCounts(NumLODVertices, NumMorphVertices, 0, 0); - SetShaderValue(RHICmdList, CS, MorphTargetCountsParameter, MorphTargetCounts); - SetSRVParameter(RHICmdList, CS, PerVertexInfoListParameter, PerVertexInfoListSRV); + SetUAVParameter(RHICmdList, CS, MorphVertexBufferParameter, MorphVertexBuffer.GetUAV()); - SetSRVParameter(RHICmdList, CS, FlattenedDeltaListParameter, FlattenedDeltaListSRV); + SetShaderValue(RHICmdList, CS, PositionScaleParameter, LocalScale); - SetSRVParameter(RHICmdList, CS, AllWeightsPerMorphsParameter, MorphWeightsSRV); + SetSRVParameter(RHICmdList, CS, VertexIndicesParameter, MorphTargetVertexInfoBuffers.VertexIndicesSRV); + SetSRVParameter(RHICmdList, CS, MorphDeltasParameter, MorphTargetVertexInfoBuffers.MorphDeltasSRV); +} - SetUAVParameter(RHICmdList, CS, MorphVertexBufferParameter, UAV); +void FGPUMorphUpdateCS::SetOffsetAndSize(FRHICommandList& RHICmdList, uint32 Offset, uint32 Size, float Weight) +{ + FComputeShaderRHIRef CS = GetComputeShader(); + uint32 OffsetAndSize[2] = { Offset, Offset + Size }; + SetShaderValue(RHICmdList, CS, OffsetAndSizeParameter, OffsetAndSize); + SetShaderValue(RHICmdList, CS, MorphTargetWeightParameter, Weight); } -class FGPUMorphUpdateCS : public FMorphTargetBaseShader +void FGPUMorphUpdateCS::Dispatch(FRHICommandList& RHICmdList, uint32 Size) { -public: - DECLARE_SHADER_TYPE(FGPUMorphUpdateCS, Global); + RHICmdList.DispatchComputeShader(1, (Size + 31) / 32, 1); +} - FGPUMorphUpdateCS() {} - - FGPUMorphUpdateCS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) - : FMorphTargetBaseShader(Initializer) - { - } - - static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment) - { - OutEnvironment.SetDefine(TEXT("USE_BYTE_BUFFER"), MORPH_TARGETS_USE_BYTE_BUFFER_UAV); - } - - void Dispatch(FRHICommandList& RHICmdList, int32 NumLODVertices, int32 NumMorphVertices, FShaderResourceViewRHIRef MorphWeightsSRV, FShaderResourceViewRHIRef PerVertexInfoListSRV, FShaderResourceViewRHIRef FlattenedDeltaListSRV, FUnorderedAccessViewRHIParamRef UAV) - { - FComputeShaderRHIRef CS = GetComputeShader(); - FMorphTargetBaseShader::SetParameters(RHICmdList, NumLODVertices, NumMorphVertices, MorphWeightsSRV, PerVertexInfoListSRV, FlattenedDeltaListSRV, UAV); - RHICmdList.DispatchComputeShader((NumMorphVertices + 63) / 64, 1, 1); - SetUAVParameter(RHICmdList, CS, MorphVertexBufferParameter, nullptr); - } -}; +void FGPUMorphUpdateCS::EndAllDispatches(FRHICommandList& RHICmdList) +{ + FComputeShaderRHIRef CS = GetComputeShader(); + SetUAVParameter(RHICmdList, CS, MorphVertexBufferParameter, nullptr); +} IMPLEMENT_SHADER_TYPE(, FGPUMorphUpdateCS, TEXT("MorphTargets"), TEXT("GPUMorphUpdateCS"), SF_Compute); +void FGPUMorphNormalizeCS::SetParameters(FRHICommandList& RHICmdList, uint32 NumVerticies, const FVector4& InvLocalScale, const float AccumulatedWeight, FMorphVertexBuffer& MorphVertexBuffer) +{ + FComputeShaderRHIRef CS = GetComputeShader(); + RHICmdList.SetComputeShader(CS); -TArray FSkeletalMeshObjectGPUSkin::FSkeletalMeshObjectLOD::MorphDeltaTangentZAccumulationArray; -TArray FSkeletalMeshObjectGPUSkin::FSkeletalMeshObjectLOD::MorphAccumulatedWeightArray; + SetUAVParameter(RHICmdList, CS, MorphVertexBufferParameter, MorphVertexBuffer.GetUAV()); -void FSkeletalMeshObjectGPUSkin::FSkeletalMeshObjectLOD::UpdateMorphVertexBuffer(FRHICommandListImmediate& RHICmdList, const TArray& ActiveMorphTargets, const TArray& MorphTargetWeights, FShaderResourceViewRHIRef MorphWeightsSRV, int32 NumInfluencedVerticesByMorph, FShaderResourceViewRHIRef MorphPerVertexInfoSRV, FShaderResourceViewRHIRef MorphFlattenedSRV) + SetShaderValue(RHICmdList, CS, MorphTargetWeightParameter, AccumulatedWeight); + SetShaderValue(RHICmdList, CS, MorphWorkItemsParameter, NumVerticies); + SetShaderValue(RHICmdList, CS, PositionScaleParameter, InvLocalScale); +} + +void FGPUMorphNormalizeCS::Dispatch(FRHICommandList& RHICmdList, uint32 NumVerticies, const FVector4& InvLocalScale, const float AccumulatedWeight, FMorphVertexBuffer& MorphVertexBuffer) +{ + FComputeShaderRHIRef CS = GetComputeShader(); + FGPUMorphNormalizeCS::SetParameters(RHICmdList, NumVerticies, InvLocalScale, AccumulatedWeight, MorphVertexBuffer); + RHICmdList.DispatchComputeShader(1, (NumVerticies + 31) / 32, 1); + SetUAVParameter(RHICmdList, CS, MorphVertexBufferParameter, nullptr); +} + +IMPLEMENT_SHADER_TYPE(, FGPUMorphNormalizeCS, TEXT("MorphTargets"), TEXT("GPUMorphNormalizeCS"), SF_Compute); + +static const float MorphTargetWeightCutoffThreshold = 0.00000001f; + +static void CalculateMorphDeltaBounds(const TArray& MorphTargetWeights, const FMorphTargetVertexInfoBuffers& MorphTargetVertexInfoBuffers, FVector4& MorphScale, FVector4& InvMorphScale, float &InvTotalAccumulatedWeight) +{ + double TotalAccumulatedWeight = 0.0; + double MinAccumScale[4] = { 0, 0, 0, 0 }; + double MaxAccumScale[4] = { 0, 0, 0, 0 }; + double MaxScale[4] = { 0, 0, 0, 0 }; + for (uint32 i = 0; i < MorphTargetVertexInfoBuffers.GetNumMorphs(); i++) + { + float AbsoluteMorphTargetWeight = FMath::Abs(MorphTargetWeights[i]); + if (AbsoluteMorphTargetWeight > MorphTargetWeightCutoffThreshold) + { + TotalAccumulatedWeight += AbsoluteMorphTargetWeight; + FVector4 MinMorphScale = MorphTargetVertexInfoBuffers.GetMinimumMorphScale(i); + FVector4 MaxMorphScale = MorphTargetVertexInfoBuffers.GetMaximumMorphScale(i); + + for (uint32 j = 0; j < 4; j++) + { + MinAccumScale[j] += MorphTargetWeights[i] * MinMorphScale[j]; + MaxAccumScale[j] += MorphTargetWeights[i] * MaxMorphScale[j]; + + double AbsMorphScale = FMath::Max(FMath::Abs(MinMorphScale[j]), FMath::Abs(MaxMorphScale[j])); + double AbsAccumScale = FMath::Max(FMath::Abs(MinAccumScale[j]), FMath::Abs(MaxAccumScale[j])); + //the maximum accumulated and the maximum local value have to fit into out int24 + MaxScale[j] = FMath::Max(MaxScale[j], FMath::Max(AbsMorphScale, AbsAccumScale)); + } + } + } + + const double ScaleToInt24 = 16777216.0; + MorphScale = FVector4 + ( + ScaleToInt24 / (double)((uint64)(MaxScale[0] + 1.0)), + ScaleToInt24 / (double)((uint64)(MaxScale[1] + 1.0)), + ScaleToInt24 / (double)((uint64)(MaxScale[2] + 1.0)), + ScaleToInt24 / (double)((uint64)(MaxScale[3] + 1.0)) + ); + + InvMorphScale = FVector4 + ( + (double)((uint64)(MaxScale[0] + 1.0)) / ScaleToInt24, + (double)((uint64)(MaxScale[1] + 1.0)) / ScaleToInt24, + (double)((uint64)(MaxScale[2] + 1.0)) / ScaleToInt24, + (double)((uint64)(MaxScale[3] + 1.0)) / ScaleToInt24 + ); + + InvTotalAccumulatedWeight = (float)(1.0 / TotalAccumulatedWeight); +} + +void FSkeletalMeshObjectGPUSkin::FSkeletalMeshObjectLOD::UpdateMorphVertexBufferGPU(FRHICommandListImmediate& RHICmdList, const TArray& MorphTargetWeights, const FMorphTargetVertexInfoBuffers& MorphTargetVertexInfoBuffers) { SCOPE_CYCLE_COUNTER(STAT_MorphVertexBuffer_Update); - if( IsValidRef(MorphVertexBuffer.VertexBufferRHI) ) + if (IsValidRef(MorphVertexBuffer.VertexBufferRHI)) { - extern ENGINE_API bool DoRecomputeSkinTangentsOnGPU_RT(); - bool bBlendTangentsOnCPU = !DoRecomputeSkinTangentsOnGPU_RT(); - -/* // TODO: Need to finish this to avoid artifacts if the SkinCache is not handing all objects - if(!bBlendTangentsOnCPU) - { - // It's possible that we reject the object from the SkinCache (e.g. all memory is used up), the we want to render the normal way. - // Unfortunately we don't know that at this point and code needs to be changed to get the info here. - if(!GGPUSkinCache.IsElementProcessed()) - { - bBlendTangentsOnCPU = true; - } - } -*/ // LOD of the skel mesh is used to find number of vertices in buffer FStaticLODModel& LodModel = SkelMeshResource->LODModels[LODIndex]; MorphVertexBuffer.RecreateResourcesIfRequired(GUseGPUMorphTargets != 0); - if (GUseGPUMorphTargets && RHISupportsComputeShaders(GMaxRHIShaderPlatform)) - { - SCOPED_GPU_STAT(RHICmdList, Stat_GPU_MorphTargets); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_MorphTargets); - SCOPED_DRAW_EVENTF(RHICmdList, MorphUpdate, - TEXT("MorphUpdate LodVertices=%d InflVerts=%d"), - LodModel.NumVertices, - NumInfluencedVerticesByMorph); - RHICmdList.TransitionResource(EResourceTransitionAccess::EWritable, EResourceTransitionPipeline::EGfxToCompute, MorphVertexBuffer.GetUAV()); + SCOPED_DRAW_EVENTF(RHICmdList, MorphUpdate, + TEXT("MorphUpdate LodVertices=%d Threads=%d"), + LodModel.NumVertices, + MorphTargetVertexInfoBuffers.GetNumWorkItems()); + RHICmdList.TransitionResource(EResourceTransitionAccess::EWritable, EResourceTransitionPipeline::EGfxToCompute, MorphVertexBuffer.GetUAV()); - RHICmdList.ClearTinyUAV(MorphVertexBuffer.GetUAV(), {0, 0, 0, 0}); + ClearUAV(RHICmdList, MorphVertexBuffer.GetUAV(), MorphVertexBuffer.GetUAVSize(), 0); + { + SCOPE_CYCLE_COUNTER(STAT_MorphVertexBuffer_ApplyDelta); + + FVector4 MorphScale; + FVector4 InvMorphScale; + float InvTotalAccumulatedWeight; + CalculateMorphDeltaBounds(MorphTargetWeights, MorphTargetVertexInfoBuffers, MorphScale, InvMorphScale, InvTotalAccumulatedWeight); + + TShaderMapRef GPUMorphUpdateCS(GetGlobalShaderMap(ERHIFeatureLevel::SM5)); + for (uint32 i = 0; i < MorphTargetVertexInfoBuffers.GetNumMorphs(); i++) { - SCOPE_CYCLE_COUNTER(STAT_MorphVertexBuffer_ApplyDelta); - TShaderMapRef GPUMorphUpdateCS(GetGlobalShaderMap(ERHIFeatureLevel::SM5)); - GPUMorphUpdateCS->Dispatch(RHICmdList, LodModel.NumVertices, NumInfluencedVerticesByMorph, MorphWeightsSRV, MorphPerVertexInfoSRV, MorphFlattenedSRV, MorphVertexBuffer.GetUAV()); + uint32 NumMorphDeltas = MorphTargetVertexInfoBuffers.GetNumWorkItems(i); + if (FMath::Abs(MorphTargetWeights[i]) > MorphTargetWeightCutoffThreshold && NumMorphDeltas > 0) + { + GPUMorphUpdateCS->SetParameters(RHICmdList, MorphScale, MorphTargetVertexInfoBuffers, MorphVertexBuffer); + GPUMorphUpdateCS->SetOffsetAndSize(RHICmdList, MorphTargetVertexInfoBuffers.GetStartOffset(i), NumMorphDeltas, MorphTargetWeights[i]); + GPUMorphUpdateCS->Dispatch(RHICmdList, NumMorphDeltas); + RHICmdList.TransitionResource(EResourceTransitionAccess::ERWNoBarrier, EResourceTransitionPipeline::EComputeToCompute, MorphVertexBuffer.GetUAV()); + } + } + GPUMorphUpdateCS->EndAllDispatches(RHICmdList); + RHICmdList.TransitionResource(EResourceTransitionAccess::ERWBarrier, EResourceTransitionPipeline::EComputeToCompute, MorphVertexBuffer.GetUAV()); + + TShaderMapRef GPUMorphNormalizeCS(GetGlobalShaderMap(ERHIFeatureLevel::SM5)); + GPUMorphNormalizeCS->Dispatch(RHICmdList, LodModel.NumVertices, InvMorphScale, InvTotalAccumulatedWeight, MorphVertexBuffer); + } + + RHICmdList.TransitionResource(EResourceTransitionAccess::EReadable, EResourceTransitionPipeline::EComputeToGfx, MorphVertexBuffer.GetUAV()); + + // set update flag + MorphVertexBuffer.bHasBeenUpdated = true; + } +} + +void FSkeletalMeshObjectGPUSkin::FSkeletalMeshObjectLOD::UpdateMorphVertexBufferCPU(const TArray& ActiveMorphTargets, const TArray& MorphTargetWeights) +{ + SCOPE_CYCLE_COUNTER(STAT_MorphVertexBuffer_Update); + + if (IsValidRef(MorphVertexBuffer.VertexBufferRHI)) + { + extern ENGINE_API bool DoRecomputeSkinTangentsOnGPU_RT(); + bool bBlendTangentsOnCPU = !DoRecomputeSkinTangentsOnGPU_RT(); + + // LOD of the skel mesh is used to find number of vertices in buffer + FStaticLODModel& LodModel = SkelMeshResource->LODModels[LODIndex]; + + MorphVertexBuffer.RecreateResourcesIfRequired(GUseGPUMorphTargets != 0); + + uint32 Size = LodModel.NumVertices * sizeof(FMorphGPUSkinVertex); + + FMorphGPUSkinVertex* Buffer = nullptr; + { + SCOPE_CYCLE_COUNTER(STAT_MorphVertexBuffer_Alloc); + Buffer = (FMorphGPUSkinVertex*)FMemory::Malloc(Size); + } + + { + SCOPE_CYCLE_COUNTER(STAT_MorphVertexBuffer_Init); + + if (bBlendTangentsOnCPU) + { + // zero everything + int32 vertsToAdd = static_cast(LodModel.NumVertices) - MorphAccumulatedWeightArray.Num(); + if (vertsToAdd > 0) + { + MorphAccumulatedWeightArray.AddUninitialized(vertsToAdd); + } + + FMemory::Memzero(MorphAccumulatedWeightArray.GetData(), sizeof(float)*LodModel.NumVertices); } - RHICmdList.TransitionResource(EResourceTransitionAccess::EReadable, EResourceTransitionPipeline::EComputeToGfx, MorphVertexBuffer.GetUAV()); + // PackedNormals will be wrong init with 0, but they'll be overwritten later + FMemory::Memzero(&Buffer[0], sizeof(FMorphGPUSkinVertex)*LodModel.NumVertices); + } + { + SCOPE_CYCLE_COUNTER(STAT_MorphVertexBuffer_ApplyDelta); + + // iterate over all active morph targets and accumulate their vertex deltas + for (int32 AnimIdx = 0; AnimIdx < ActiveMorphTargets.Num(); AnimIdx++) + { + const FActiveMorphTarget& MorphTarget = ActiveMorphTargets[AnimIdx]; + checkSlow(MorphTarget.MorphTarget != NULL); + checkSlow(MorphTarget.MorphTarget->HasDataForLOD(LODIndex)); + const float MorphTargetWeight = MorphTargetWeights[MorphTarget.WeightIndex]; + const float MorphAbsWeight = FMath::Abs(MorphTargetWeight); + checkSlow(MorphAbsWeight >= MinMorphTargetBlendWeight && MorphAbsWeight <= MaxMorphTargetBlendWeight); + + + // Get deltas + int32 NumDeltas; + FMorphTargetDelta* Deltas = MorphTarget.MorphTarget->GetMorphTargetDelta(LODIndex, NumDeltas); + + // iterate over the vertices that this lod model has changed + for (int32 MorphVertIdx = 0; MorphVertIdx < NumDeltas; MorphVertIdx++) + { + const FMorphTargetDelta& MorphVertex = Deltas[MorphVertIdx]; + + // @TODO FIXMELH : temp hack until we fix importing issue + if ((MorphVertex.SourceIdx < LodModel.NumVertices)) + { + FMorphGPUSkinVertex& DestVertex = Buffer[MorphVertex.SourceIdx]; + + DestVertex.DeltaPosition += MorphVertex.PositionDelta * MorphTargetWeight; + + // todo: could be moved out of the inner loop to be more efficient + if (bBlendTangentsOnCPU) + { + DestVertex.DeltaTangentZ += MorphVertex.TangentZDelta * MorphTargetWeight; + // accumulate the weight so we can normalized it later + MorphAccumulatedWeightArray[MorphVertex.SourceIdx] += MorphAbsWeight; + } + } + } // for all vertices + } // for all morph targets + + if (bBlendTangentsOnCPU) + { + // copy back all the tangent values (can't use Memcpy, since we have to pack the normals) + for (uint32 iVertex = 0; iVertex < LodModel.NumVertices; ++iVertex) + { + FMorphGPUSkinVertex& DestVertex = Buffer[iVertex]; + float AccumulatedWeight = MorphAccumulatedWeightArray[iVertex]; + + // if accumulated weight is >1.f + // previous code was applying the weight again in GPU if less than 1, but it doesn't make sense to do so + // so instead, we just divide by AccumulatedWeight if it's more than 1. + // now DeltaTangentZ isn't FPackedNormal, so you can apply any value to it. + if (AccumulatedWeight > 1.f) + { + DestVertex.DeltaTangentZ /= AccumulatedWeight; + } + } + } + } // ApplyDelta + + // Lock the real buffer. + { + SCOPE_CYCLE_COUNTER(STAT_MorphVertexBuffer_RhiLockAndCopy); + FMorphGPUSkinVertex* ActualBuffer = (FMorphGPUSkinVertex*)RHILockVertexBuffer(MorphVertexBuffer.VertexBufferRHI, 0, Size, RLM_WriteOnly); + FMemory::Memcpy(ActualBuffer, Buffer, Size); + FMemory::Free(Buffer); + } + + { + SCOPE_CYCLE_COUNTER(STAT_MorphVertexBuffer_RhiUnlock); + // Unlock the buffer. + RHIUnlockVertexBuffer(MorphVertexBuffer.VertexBufferRHI); // set update flag MorphVertexBuffer.bHasBeenUpdated = true; } - else - { - uint32 Size = LodModel.NumVertices * sizeof(FMorphGPUSkinVertex); - - FMorphGPUSkinVertex* Buffer = nullptr; - { - SCOPE_CYCLE_COUNTER(STAT_MorphVertexBuffer_Alloc); - Buffer = (FMorphGPUSkinVertex*)FMemory::Malloc(Size); - } - - { - SCOPE_CYCLE_COUNTER(STAT_MorphVertexBuffer_Init); - - if (bBlendTangentsOnCPU) - { - // zero everything - int32 vertsToAdd = static_cast(LodModel.NumVertices) - MorphAccumulatedWeightArray.Num(); - if (vertsToAdd > 0) - { - MorphAccumulatedWeightArray.AddUninitialized(vertsToAdd); - } - - FMemory::Memzero(MorphAccumulatedWeightArray.GetData(), sizeof(float)*LodModel.NumVertices); - } - - // PackedNormals will be wrong init with 0, but they'll be overwritten later - FMemory::Memzero(&Buffer[0], sizeof(FMorphGPUSkinVertex)*LodModel.NumVertices); - } - - { - SCOPE_CYCLE_COUNTER(STAT_MorphVertexBuffer_ApplyDelta); - - // iterate over all active morph targets and accumulate their vertex deltas - for (int32 AnimIdx=0; AnimIdx < ActiveMorphTargets.Num(); AnimIdx++) - { - const FActiveMorphTarget& MorphTarget = ActiveMorphTargets[AnimIdx]; - checkSlow(MorphTarget.MorphTarget != NULL); - checkSlow(MorphTarget.MorphTarget->HasDataForLOD(LODIndex)); - const float MorphTargetWeight = MorphTargetWeights[MorphTarget.WeightIndex]; - const float MorphAbsWeight = FMath::Abs(MorphTargetWeight); - checkSlow(MorphAbsWeight >= MinMorphTargetBlendWeight && MorphAbsWeight <= MaxMorphTargetBlendWeight); - - - // Get deltas - int32 NumDeltas; - FMorphTargetDelta* Deltas = MorphTarget.MorphTarget->GetMorphTargetDelta(LODIndex, NumDeltas); - - // iterate over the vertices that this lod model has changed - for (int32 MorphVertIdx=0; MorphVertIdx < NumDeltas; MorphVertIdx++) - { - const FMorphTargetDelta& MorphVertex = Deltas[MorphVertIdx]; - - // @TODO FIXMELH : temp hack until we fix importing issue - if ((MorphVertex.SourceIdx < LodModel.NumVertices)) - { - FMorphGPUSkinVertex& DestVertex = Buffer[MorphVertex.SourceIdx]; - - DestVertex.DeltaPosition += MorphVertex.PositionDelta * MorphTargetWeight; - - // todo: could be moved out of the inner loop to be more efficient - if (bBlendTangentsOnCPU) - { - DestVertex.DeltaTangentZ += MorphVertex.TangentZDelta * MorphTargetWeight; - // accumulate the weight so we can normalized it later - MorphAccumulatedWeightArray[MorphVertex.SourceIdx] += MorphAbsWeight; - } - } - } // for all vertices - } // for all morph targets - - if (bBlendTangentsOnCPU) - { - // copy back all the tangent values (can't use Memcpy, since we have to pack the normals) - for (uint32 iVertex = 0; iVertex < LodModel.NumVertices; ++iVertex) - { - FMorphGPUSkinVertex& DestVertex = Buffer[iVertex]; - float AccumulatedWeight = MorphAccumulatedWeightArray[iVertex]; - - // if accumulated weight is >1.f - // previous code was applying the weight again in GPU if less than 1, but it doesn't make sense to do so - // so instead, we just divide by AccumulatedWeight if it's more than 1. - // now DeltaTangentZ isn't FPackedNormal, so you can apply any value to it. - if (AccumulatedWeight > 1.f) - { - DestVertex.DeltaTangentZ /= AccumulatedWeight; - } - } - } - } // ApplyDelta - - // Lock the real buffer. - { - SCOPE_CYCLE_COUNTER(STAT_MorphVertexBuffer_RhiLockAndCopy); - FMorphGPUSkinVertex* ActualBuffer = (FMorphGPUSkinVertex*)RHILockVertexBuffer(MorphVertexBuffer.VertexBufferRHI, 0, Size, RLM_WriteOnly); - FMemory::Memcpy(ActualBuffer, Buffer, Size); - FMemory::Free(Buffer); - } - - { - SCOPE_CYCLE_COUNTER(STAT_MorphVertexBuffer_RhiUnlock); - // Unlock the buffer. - RHIUnlockVertexBuffer(MorphVertexBuffer.VertexBufferRHI); - // set update flag - MorphVertexBuffer.bHasBeenUpdated = true; - } - } } } diff --git a/Engine/Source/Runtime/Engine/Private/SkeletalRenderGPUSkin.h b/Engine/Source/Runtime/Engine/Private/SkeletalRenderGPUSkin.h index 32a312355b15..507be61d1f6e 100644 --- a/Engine/Source/Runtime/Engine/Private/SkeletalRenderGPUSkin.h +++ b/Engine/Source/Runtime/Engine/Private/SkeletalRenderGPUSkin.h @@ -153,6 +153,7 @@ public: */ FMorphVertexBuffer(FSkeletalMeshResource* InSkelMeshResource, int32 InLODIdx) : bHasBeenUpdated(false) + , bNeedsInitialClear(true) , LODIdx(InLODIdx) , SkelMeshResource(InSkelMeshResource) { @@ -202,9 +203,31 @@ public: return ResourceSize; } + /** + * Get Resource Size : only get the size of the GPU resource + */ + SIZE_T GetUAVSize() + { + SIZE_T ResourceSize = 0; + + if (VertexBufferRHI) + { + // LOD of the skel mesh is used to find number of vertices in buffer + FStaticLODModel& LodModel = SkelMeshResource->LODModels[LODIdx]; + + // Create the buffer rendering resource + ResourceSize += LodModel.NumVertices * sizeof(FMorphGPUSkinVertex); + } + + return ResourceSize; + } + /** Has been updated or not by UpdateMorphVertexBuffer**/ bool bHasBeenUpdated; + /** DX12 cannot clear the buffer in InitDynamicRHI with UAV flag enables, we should really have a Zero initzialized flag instead**/ + bool bNeedsInitialClear; + // @param guaranteed only to be valid if the vertex buffer is valid FShaderResourceViewRHIParamRef GetSRV() const { @@ -292,8 +315,6 @@ public: { LODs[I].GetResourceSizeEx(CumulativeResourceSize); } - - CumulativeResourceSize.AddUnknownMemoryBytes(MorphWeightsVertexBuffer.VertexBufferRHI ? MorphWeightsVertexBuffer.VertexBufferRHI->GetSize() : 0); } //~ End FSkeletalMeshObject Interface @@ -486,7 +507,8 @@ private: * @param ActiveMorphTargets - Morph to accumulate. assumed to be weighted and have valid targets * @param MorphTargetWeights - All Morph weights */ - void UpdateMorphVertexBuffer(FRHICommandListImmediate& RHICmdList, const TArray& ActiveMorphTargets, const TArray& MorphTargetWeights, FShaderResourceViewRHIRef MorphWeightsSRV, int32 NumInfluencedVerticesByMorph, FShaderResourceViewRHIRef MorphPerVertexInfoSRV, FShaderResourceViewRHIRef MorphFlattenedSRV); + void UpdateMorphVertexBufferCPU(const TArray& ActiveMorphTargets, const TArray& MorphTargetWeights); + void UpdateMorphVertexBufferGPU(FRHICommandListImmediate& RHICmdList, const TArray& MorphTargetWeights, const FMorphTargetVertexInfoBuffers& MorphTargetVertexInfoBuffers); /** * Determine the current vertex buffers valid for this LOD @@ -496,7 +518,6 @@ private: void GetVertexBuffers(FVertexFactoryBuffers& OutVertexBuffers,FStaticLODModel& LODModel); // Temporary arrays used on UpdateMorphVertexBuffer(); these grow to the max and are not thread safe. - static TArray MorphDeltaTangentZAccumulationArray; static TArray MorphAccumulatedWeightArray; }; @@ -531,36 +552,93 @@ private: /** true if the morph resources have been initialized */ bool bMorphResourcesInitialized; - - /** Vertex buffer that stores the weights for all morph targets (matches USkeletalMesh::MorphTargets). */ - FVertexBufferAndSRV MorphWeightsVertexBuffer; }; -class FMorphTargetBaseShader : public FGlobalShader +class FGPUMorphUpdateCS : public FGlobalShader { public: - FMorphTargetBaseShader() {} + DECLARE_SHADER_TYPE(FGPUMorphUpdateCS, Global); - FMorphTargetBaseShader(const ShaderMetaType::CompiledShaderInitializerType& Initializer) + FGPUMorphUpdateCS() {} + + FGPUMorphUpdateCS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) : FGlobalShader(Initializer) { - MorphTargetCountsParameter.Bind(Initializer.ParameterMap, TEXT("MorphTargetCounts")); MorphVertexBufferParameter.Bind(Initializer.ParameterMap, TEXT("MorphVertexBuffer")); - PerVertexInfoListParameter.Bind(Initializer.ParameterMap, TEXT("PerVertexInfoList")); - FlattenedDeltaListParameter.Bind(Initializer.ParameterMap, TEXT("FlattenedDeltaList")); - AllWeightsPerMorphsParameter.Bind(Initializer.ParameterMap, TEXT("AllWeightsPerMorphs")); + + MorphTargetWeightParameter.Bind(Initializer.ParameterMap, TEXT("MorphTargetWeight")); + OffsetAndSizeParameter.Bind(Initializer.ParameterMap, TEXT("OffsetAndSize")); + PositionScaleParameter.Bind(Initializer.ParameterMap, TEXT("PositionScale")); + + VertexIndicesParameter.Bind(Initializer.ParameterMap, TEXT("VertexIndicies")); + MorphDeltasParameter.Bind(Initializer.ParameterMap, TEXT("MorphDeltas")); } // FShader interface. virtual bool Serialize(FArchive& Ar) override { bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar); - Ar << MorphTargetCountsParameter; Ar << MorphVertexBufferParameter; - Ar << PerVertexInfoListParameter; - Ar << FlattenedDeltaListParameter; - Ar << AllWeightsPerMorphsParameter; + + Ar << MorphTargetWeightParameter; + Ar << OffsetAndSizeParameter; + Ar << PositionScaleParameter; + + Ar << VertexIndicesParameter; + Ar << MorphDeltasParameter; + return bShaderHasOutdatedParameters; + } + + void SetParameters(FRHICommandList& RHICmdList, const FVector4& LocalScale, const FMorphTargetVertexInfoBuffers& MorphTargetVertexInfoBuffers, FMorphVertexBuffer& MorphVertexBuffer); + void SetOffsetAndSize(FRHICommandList& RHICmdList, uint32 Offset, uint32 Size, float Weight); + + void Dispatch(FRHICommandList& RHICmdList, uint32 Size); + void EndAllDispatches(FRHICommandList& RHICmdList); + + static bool ShouldCache(EShaderPlatform Platform) + { + return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5); + } + +protected: + FShaderResourceParameter MorphVertexBufferParameter; + + FShaderParameter MorphTargetWeightParameter; + FShaderParameter OffsetAndSizeParameter; + FShaderParameter PositionScaleParameter; + + FShaderResourceParameter VertexIndicesParameter; + FShaderResourceParameter MorphDeltasParameter; +}; + +class FGPUMorphNormalizeCS : public FGlobalShader +{ +public: + DECLARE_SHADER_TYPE(FGPUMorphNormalizeCS, Global); + + FGPUMorphNormalizeCS() {} + + FGPUMorphNormalizeCS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) + : FGlobalShader(Initializer) + { + MorphVertexBufferParameter.Bind(Initializer.ParameterMap, TEXT("MorphVertexBuffer")); + + MorphTargetWeightParameter.Bind(Initializer.ParameterMap, TEXT("MorphTargetWeight")); + MorphWorkItemsParameter.Bind(Initializer.ParameterMap, TEXT("MorphWorkItems")); + PositionScaleParameter.Bind(Initializer.ParameterMap, TEXT("PositionScale")); + } + + // FShader interface. + virtual bool Serialize(FArchive& Ar) override + { + bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar); + Ar << MorphVertexBufferParameter; + + Ar << MorphTargetWeightParameter; + Ar << MorphWorkItemsParameter; + Ar << PositionScaleParameter; + return bShaderHasOutdatedParameters; } @@ -569,14 +647,14 @@ public: return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5); } - void SetParameters(FRHICommandList& RHICmdList, int32 NumLODVertices, int32 NumMorphVertices, FShaderResourceViewRHIRef MorphWeightsSRV, FShaderResourceViewRHIRef PerVertexInfoListSRV, FShaderResourceViewRHIRef FlattenedDeltaListSRV, FUnorderedAccessViewRHIParamRef UAV); - void Dispatch(FRHICommandList& RHICmdList, int32 NumLODVertices, int32 NumMorphVertices, FShaderResourceViewRHIRef MorphWeightsSRV, FShaderResourceViewRHIRef PerVertexInfoListSRV, FShaderResourceViewRHIRef FlattenedDeltaListSRV, FUnorderedAccessViewRHIParamRef UAV); + void SetParameters(FRHICommandList& RHICmdList, uint32 NumVerticies, const FVector4& LocalScale, const float AccumulatedWeight, FMorphVertexBuffer& MorphVertexBuffer); + + void Dispatch(FRHICommandList& RHICmdList, uint32 NumVerticies, const FVector4& LocalScale, const float AccumulatedWeight, FMorphVertexBuffer& MorphVertexBuffer); protected: - FShaderParameter MorphTargetCountsParameter; FShaderResourceParameter MorphVertexBufferParameter; - FShaderResourceParameter PerVertexInfoListParameter; - FShaderResourceParameter FlattenedDeltaListParameter; - FShaderResourceParameter AllWeightsPerMorphsParameter; -}; + FShaderParameter MorphTargetWeightParameter; + FShaderParameter MorphWorkItemsParameter; + FShaderParameter PositionScaleParameter; +}; \ No newline at end of file diff --git a/Engine/Source/Runtime/Engine/Private/Slate/SGameLayerManager.cpp b/Engine/Source/Runtime/Engine/Private/Slate/SGameLayerManager.cpp index d2dac93512c0..722e6d242ee1 100644 --- a/Engine/Source/Runtime/Engine/Private/Slate/SGameLayerManager.cpp +++ b/Engine/Source/Runtime/Engine/Private/Slate/SGameLayerManager.cpp @@ -133,6 +133,18 @@ const FGeometry& SGameLayerManager::GetViewportWidgetHostGeometry() const return WidgetHost->GetCachedGeometry(); } +const FGeometry& SGameLayerManager::GetPlayerWidgetHostGeometry(ULocalPlayer* Player) const +{ + TSharedPtr PlayerLayer = PlayerLayers.FindRef(Player); + if ( PlayerLayer.IsValid() ) + { + return PlayerLayer->Widget->GetCachedGeometry(); + } + + static FGeometry Identity; + return Identity; +} + void SGameLayerManager::NotifyPlayerAdded(int32 PlayerIndex, ULocalPlayer* AddedPlayer) { UpdateLayout(); @@ -166,20 +178,19 @@ void SGameLayerManager::RemoveWidgetForPlayer(ULocalPlayer* Player, TSharedRef* PlayerLayerPtr = PlayerLayers.Find(Player); - if ( PlayerLayerPtr ) + TSharedPtr PlayerLayer = PlayerLayers.FindRef(Player); + if ( PlayerLayer.IsValid() ) { - TSharedPtr PlayerLayer = *PlayerLayerPtr; PlayerLayer->Widget->ClearChildren(); } } TSharedPtr SGameLayerManager::FindLayerForPlayer(ULocalPlayer* Player, const FName& LayerName) { - TSharedPtr* PlayerLayerPtr = PlayerLayers.Find(Player); - if ( PlayerLayerPtr ) + TSharedPtr PlayerLayer = PlayerLayers.FindRef(Player); + if ( PlayerLayer.IsValid() ) { - return (*PlayerLayerPtr)->Layers.FindRef(LayerName); + return PlayerLayer->Layers.FindRef(LayerName); } return TSharedPtr(); diff --git a/Engine/Source/Runtime/Engine/Private/Slate/SceneViewport.cpp b/Engine/Source/Runtime/Engine/Private/Slate/SceneViewport.cpp index 60b855d36ad5..437935083c63 100644 --- a/Engine/Source/Runtime/Engine/Private/Slate/SceneViewport.cpp +++ b/Engine/Source/Runtime/Engine/Private/Slate/SceneViewport.cpp @@ -1367,6 +1367,15 @@ FCanvas* FSceneViewport::GetDebugCanvas() return DebugCanvasDrawer->GetGameThreadDebugCanvas(); } +float FSceneViewport::GetDisplayGamma() const +{ + if (ViewportGammaOverride.IsSet()) + { + return ViewportGammaOverride.GetValue(); + } + return FViewport::GetDisplayGamma(); +} + const FTexture2DRHIRef& FSceneViewport::GetRenderTargetTexture() const { if (IsInRenderingThread()) @@ -1482,7 +1491,7 @@ void FSceneViewport::EnqueueBeginRenderFrame() // If we dont have the ViewportRHI then we need to get it before rendering // Note, we need ViewportRHI even if UseSeparateRenderTarget() is true when stereo rendering // is enabled. - if (!IsValidRef(ViewportRHI) && (!UseSeparateRenderTarget() || (GEngine->StereoRenderingDevice.IsValid() && GEngine->StereoRenderingDevice->IsStereoEnabled())) ) + if (!IsValidRef(ViewportRHI) && (!UseSeparateRenderTarget() || (GEngine->StereoRenderingDevice.IsValid() && GEngine->StereoRenderingDevice->IsStereoEnabled() && IsStereoRenderingAllowed())) ) { // Get the viewport for this window from the renderer so we can render directly to the backbuffer TSharedPtr Renderer = FSlateApplication::Get().GetRenderer(); @@ -1515,7 +1524,7 @@ void FSceneViewport::EnqueueBeginRenderFrame() FViewport::EnqueueBeginRenderFrame(); - if (GEngine->StereoRenderingDevice.IsValid()) + if (GEngine->StereoRenderingDevice.IsValid() && IsStereoRenderingAllowed()) { GEngine->StereoRenderingDevice->UpdateViewport(UseSeparateRenderTarget(), *this, ViewportWidget.Pin().Get()); } diff --git a/Engine/Source/Runtime/Engine/Private/Slate/SlateGameResources.cpp b/Engine/Source/Runtime/Engine/Private/Slate/SlateGameResources.cpp index 82207c6407d7..369d1dfa4ecd 100644 --- a/Engine/Source/Runtime/Engine/Private/Slate/SlateGameResources.cpp +++ b/Engine/Source/Runtime/Engine/Private/Slate/SlateGameResources.cpp @@ -304,13 +304,5 @@ FName FSlateGameResources::GetCleanName(const FName& AssetName) const void FSlateGameResources::AddReferencedObjects( FReferenceCollector& Collector ) { - //We only add references to our style assets when in Game. - //We don't add them during normal editor execution so the user can delete the assets. - //We add them during Game so they don't get unloaded. - //In Editor all style assets are marked with StandAlone so they are never unloaded. - - if ( !GIsEditor ) - { - Collector.AddReferencedObjects( UIResources ); - } + Collector.AddReferencedObjects( UIResources ); } diff --git a/Engine/Source/Runtime/Engine/Private/Slate/SlateTextures.cpp b/Engine/Source/Runtime/Engine/Private/Slate/SlateTextures.cpp index d2f611f776c1..8066269bfd39 100644 --- a/Engine/Source/Runtime/Engine/Private/Slate/SlateTextures.cpp +++ b/Engine/Source/Runtime/Engine/Private/Slate/SlateTextures.cpp @@ -73,7 +73,10 @@ void FSlateTexture2DRHIRef::InitDynamicRHI() } else { - checkf(GPixelFormats[PixelFormat].BlockSizeX == GPixelFormats[PixelFormat].BlockSizeY == GPixelFormats[PixelFormat].BlockSizeZ == 1, TEXT("Tried to use compressed format?")); + checkf(GPixelFormats[PixelFormat].BlockSizeX == 1 + && GPixelFormats[PixelFormat].BlockSizeY == 1 + && GPixelFormats[PixelFormat].BlockSizeZ == 1, + TEXT("Tried to use compressed format?")); for (uint32 i = 0; i < Height; i++) { FMemory::Memcpy(DestTextureData, SourceTextureData, DataStride); diff --git a/Engine/Source/Runtime/Engine/Private/SoundCue.cpp b/Engine/Source/Runtime/Engine/Private/SoundCue.cpp index c2fefe336b65..e4c3ce776c3c 100644 --- a/Engine/Source/Runtime/Engine/Private/SoundCue.cpp +++ b/Engine/Source/Runtime/Engine/Private/SoundCue.cpp @@ -5,6 +5,7 @@ #include "EngineDefines.h" #include "EngineGlobals.h" #include "Engine/Engine.h" +#include "Misc/CoreDelegates.h" #include "Components/AudioComponent.h" #include "UObject/UObjectIterator.h" #include "EngineUtils.h" @@ -121,13 +122,13 @@ void USoundCue::PostLoad() } else { - OnPostEngineInitHandle = UEngine::OnPostEngineInit.AddUObject(this, &USoundCue::OnPostEngineInit); + OnPostEngineInitHandle = FCoreDelegates::OnPostEngineInit.AddUObject(this, &USoundCue::OnPostEngineInit); } } void USoundCue::OnPostEngineInit() { - UEngine::OnPostEngineInit.Remove(OnPostEngineInitHandle); + FCoreDelegates::OnPostEngineInit.Remove(OnPostEngineInitHandle); OnPostEngineInitHandle.Reset(); EvaluateNodes(true); diff --git a/Engine/Source/Runtime/Engine/Private/SoundWave.cpp b/Engine/Source/Runtime/Engine/Private/SoundWave.cpp index 29711e3c6957..f79699fa5486 100644 --- a/Engine/Source/Runtime/Engine/Private/SoundWave.cpp +++ b/Engine/Source/Runtime/Engine/Private/SoundWave.cpp @@ -108,7 +108,7 @@ void USoundWave::GetResourceSizeEx(FResourceSizeEx& CumulativeResourceSize) CumulativeResourceSize.AddDedicatedSystemMemoryBytes(MONO_PCM_BUFFER_SIZE * NumChannels); } - if ((!FPlatformProperties::SupportsAudioStreaming() || !IsStreaming())) + if (!FPlatformProperties::SupportsAudioStreaming() || !IsStreaming()) { CumulativeResourceSize.AddDedicatedSystemMemoryBytes(GetCompressedDataSize(LocalAudioDevice->GetRuntimeFormat(this))); } @@ -395,7 +395,7 @@ void USoundWave::PostLoad() } // Only add this streaming sound if we're not a dedicated server or if there is an audio device manager - if (IsStreaming() && !IsRunningDedicatedServer() && GEngine && GEngine->GetAudioDeviceManager()) + if (IsStreaming() && FPlatformProperties::SupportsAudioStreaming()) { #if WITH_EDITORONLY_DATA FinishCachePlatformData(); diff --git a/Engine/Source/Runtime/Engine/Private/SpotLight.cpp b/Engine/Source/Runtime/Engine/Private/SpotLight.cpp index 72e55f0b8252..af7d7ff58aa6 100644 --- a/Engine/Source/Runtime/Engine/Private/SpotLight.cpp +++ b/Engine/Source/Runtime/Engine/Private/SpotLight.cpp @@ -139,7 +139,3 @@ void ASpotLight::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEv } #endif -#if WITH_EDITORONLY_DATA -/** Returns ArrowComponent subobject **/ -UArrowComponent* ASpotLight::GetArrowComponent() const { return ArrowComponent; } -#endif diff --git a/Engine/Source/Runtime/Engine/Private/StaticMesh.cpp b/Engine/Source/Runtime/Engine/Private/StaticMesh.cpp index b91a3f9bd7c9..70533c24a5b4 100644 --- a/Engine/Source/Runtime/Engine/Private/StaticMesh.cpp +++ b/Engine/Source/Runtime/Engine/Private/StaticMesh.cpp @@ -1156,7 +1156,7 @@ static FString BuildStaticMeshDerivedDataKey(UStaticMesh* Mesh, const FStaticMes } } - KeySuffix.AppendChar(Mesh->bRequiresAreaWeightedSampling ? TEXT('1') : TEXT('0')); + KeySuffix.AppendChar(Mesh->bSupportUniformlyDistributedSampling ? TEXT('1') : TEXT('0')); return FDerivedDataCacheInterface::BuildCacheKey( TEXT("STATICMESH"), @@ -1282,7 +1282,7 @@ void FStaticMeshRenderData::Cache(UStaticMesh* Owner, const FStaticMeshLODSettin IMeshUtilities& MeshUtilities = FModuleManager::Get().LoadModuleChecked(TEXT("MeshUtilities")); MeshUtilities.BuildStaticMesh(*this, Owner->SourceModels, LODGroup, Owner->LightmapUVVersion, Owner->ImportVersion); ComputeUVDensities(); - if(Owner->bRequiresAreaWeightedSampling) + if(Owner->bSupportUniformlyDistributedSampling) { BuildAreaWeighedSamplingData(); } @@ -1393,7 +1393,7 @@ UStaticMesh::UStaticMesh(const FObjectInitializer& ObjectInitializer) LpvBiasMultiplier = 1.0f; MinLOD = 0; - bRequiresAreaWeightedSampling = false; + bSupportUniformlyDistributedSampling = false; } void UStaticMesh::PostInitProperties() @@ -1802,6 +1802,8 @@ void UStaticMesh::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedE SetLightingGuid(); } + UpdateUVChannelData(true); + Super::PostEditChangeProperty(PropertyChangedEvent); } @@ -2233,6 +2235,10 @@ void UStaticMesh::CalculateExtendedBounds() } ExtendedBounds = Bounds; + +#if WITH_EDITOR + OnExtendedBoundsChanged.Broadcast(Bounds); +#endif } @@ -2645,6 +2651,13 @@ void UStaticMesh::PostLoad() } #endif // #if WITH_EDITOR +#if WITH_EDITORONLY_DATA + if (GetLinkerCustomVersion(FRenderingObjectVersion::GUID) < FRenderingObjectVersion::FixedMeshUVDensity) + { + UpdateUVChannelData(true); + } +#endif + EnforceLightmapRestrictions(); if (!GVertexElementTypeSupport.IsSupported(VET_Half2)) @@ -2690,17 +2703,37 @@ void UStaticMesh::PostLoad() CalculateExtendedBounds(); } - if (SectionInfoMap.Map.Num() == 0) + //Always redo the whole SectionInfoMap to be sure it contain only valid data + //This will reuse everything valid from the just serialize SectionInfoMap. + FMeshSectionInfoMap TempOldSectionInfoMap = SectionInfoMap; + SectionInfoMap.Clear(); + for (int32 LODResourceIndex = 0; LODResourceIndex < RenderData->LODResources.Num(); ++LODResourceIndex) { - // Before this serialization issue was fixed, some assets were resaved and permanently lost their section info map. - // This attempts to recreate it based on the render data. - SectionInfoMap.Clear(); - for (int32 LODResourceIndex = 0; LODResourceIndex < RenderData->LODResources.Num(); ++LODResourceIndex) + FStaticMeshLODResources& LOD = RenderData->LODResources[LODResourceIndex]; + for (int32 SectionIndex = 0; SectionIndex < LOD.Sections.Num(); ++SectionIndex) { - FStaticMeshLODResources& LOD = RenderData->LODResources[LODResourceIndex]; - const int32 NumSections = LOD.Sections.Num(); - for (int32 SectionIndex = 0; SectionIndex < NumSections; ++SectionIndex) + if (TempOldSectionInfoMap.IsValidSection(LODResourceIndex, SectionIndex)) { + FMeshSectionInfo Info = TempOldSectionInfoMap.Get(LODResourceIndex, SectionIndex); + if (StaticMaterials.IsValidIndex(Info.MaterialIndex)) + { + //Reuse the valid data that come from the serialize + SectionInfoMap.Set(LODResourceIndex, SectionIndex, Info); + } + else + { + //Use the render data material index, but keep the flags (collision, shadow...) + const int32 MaterialIndex = LOD.Sections[SectionIndex].MaterialIndex; + if (StaticMaterials.IsValidIndex(MaterialIndex)) + { + Info.MaterialIndex = MaterialIndex; + SectionInfoMap.Set(LODResourceIndex, SectionIndex, Info); + } + } + } + else + { + //Create a new SectionInfoMap from the render data const int32 MaterialIndex = LOD.Sections[SectionIndex].MaterialIndex; if (StaticMaterials.IsValidIndex(MaterialIndex)) { @@ -3536,14 +3569,14 @@ UStaticMeshSocket::UStaticMeshSocket(const FObjectInitializer& ObjectInitializer bool UStaticMeshSocket::GetSocketMatrix(FMatrix& OutMatrix, UStaticMeshComponent const* MeshComp) const { check( MeshComp ); - OutMatrix = FScaleRotationTranslationMatrix( RelativeScale, RelativeRotation, RelativeLocation ) * MeshComp->ComponentToWorld.ToMatrixWithScale(); + OutMatrix = FScaleRotationTranslationMatrix( RelativeScale, RelativeRotation, RelativeLocation ) * MeshComp->GetComponentTransform().ToMatrixWithScale(); return true; } bool UStaticMeshSocket::GetSocketTransform(FTransform& OutTransform, class UStaticMeshComponent const* MeshComp) const { check( MeshComp ); - OutTransform = FTransform(RelativeRotation, RelativeLocation, RelativeScale) * MeshComp->ComponentToWorld; + OutTransform = FTransform(RelativeRotation, RelativeLocation, RelativeScale) * MeshComp->GetComponentTransform(); return true; } @@ -3561,7 +3594,7 @@ bool UStaticMeshSocket::AttachActor(AActor* Actor, UStaticMeshComponent* MeshCo Actor->SetActorLocation(SocketTM.GetOrigin(), false); Actor->SetActorRotation(SocketTM.Rotator()); - Actor->GetRootComponent()->SnapTo( MeshComp, SocketName ); + Actor->GetRootComponent()->AttachToComponent(MeshComp, FAttachmentTransformRules::SnapToTargetNotIncludingScale, SocketName); #if WITH_EDITOR if (GIsEditor) diff --git a/Engine/Source/Runtime/Engine/Private/StaticMeshActor.cpp b/Engine/Source/Runtime/Engine/Private/StaticMeshActor.cpp index d9f88a86a765..7adc61cde9e5 100644 --- a/Engine/Source/Runtime/Engine/Private/StaticMeshActor.cpp +++ b/Engine/Source/Runtime/Engine/Private/StaticMeshActor.cpp @@ -181,7 +181,7 @@ void AStaticMeshActor::CheckForErrors() } else { - FCollisionQueryParams SphereParams(FName(TEXT("CheckForErrors")), false, this); + FCollisionQueryParams SphereParams(SCENE_QUERY_STAT(CheckForErrors), false, this); TArray Overlaps; GetWorld()->OverlapMultiByChannel(Overlaps, GetActorLocation(), FQuat::Identity, ECC_Pawn, FCollisionShape::MakeSphere(1.f), SphereParams); @@ -246,5 +246,3 @@ void AStaticMeshActor::CheckForErrors() #undef LOCTEXT_NAMESPACE -/** Returns StaticMeshComponent subobject **/ -UStaticMeshComponent* AStaticMeshActor::GetStaticMeshComponent() const { return StaticMeshComponent; } diff --git a/Engine/Source/Runtime/Engine/Private/StaticMeshLight.cpp b/Engine/Source/Runtime/Engine/Private/StaticMeshLight.cpp index b2dd647c5002..c6d6a15412fd 100644 --- a/Engine/Source/Runtime/Engine/Private/StaticMeshLight.cpp +++ b/Engine/Source/Runtime/Engine/Private/StaticMeshLight.cpp @@ -65,7 +65,7 @@ FStaticMeshStaticLightingMesh::FStaticMeshStaticLightingMesh(const UStaticMeshCo StaticMesh(InPrimitive->GetStaticMesh()), Primitive(InPrimitive), LODRenderData(InPrimitive->GetStaticMesh()->RenderData->LODResources[InLODIndex]), - bReverseWinding(InPrimitive->ComponentToWorld.GetDeterminant() < 0.0f) + bReverseWinding(InPrimitive->GetComponentTransform().GetDeterminant() < 0.0f) { LODIndexBuffer = LODRenderData.IndexBuffer.GetArrayView(); @@ -167,7 +167,7 @@ FLightRayIntersection FStaticMeshStaticLightingMesh::IntersectLightRay(const FVe // Do the line check FHitResult NewHitInfo; - FCollisionQueryParams NewTraceParams( FStaticMeshStaticLightingMesh_IntersectLightRayName, true ); + FCollisionQueryParams NewTraceParams( SCENE_QUERY_STAT(FStaticMeshStaticLightingMesh_IntersectLightRay), true ); UStaticMeshComponent* StaticMeshComp = const_cast(Primitive); const bool bIntersects = StaticMeshComp->LineTraceComponent( Result, Start, End, NewTraceParams ); diff --git a/Engine/Source/Runtime/Engine/Private/StaticMeshRender.cpp b/Engine/Source/Runtime/Engine/Private/StaticMeshRender.cpp index aad164ae75a5..567ea7d3dea4 100644 --- a/Engine/Source/Runtime/Engine/Private/StaticMeshRender.cpp +++ b/Engine/Source/Runtime/Engine/Private/StaticMeshRender.cpp @@ -1299,31 +1299,28 @@ void FStaticMeshSceneProxy::GetLightRelevance(const FLightSceneProxy* LightScene { for (int32 LODIndex = 0; LODIndex < LODs.Num(); LODIndex++) { - const FLODInfo* LCI = &LODs[LODIndex]; + const FLODInfo& LCI = LODs[LODIndex]; - if (LCI) + ELightInteractionType InteractionType = LCI.GetInteraction(LightSceneProxy).GetType(); + + if (InteractionType != LIT_CachedIrrelevant) { - ELightInteractionType InteractionType = LCI->GetInteraction(LightSceneProxy).GetType(); + bRelevant = true; + } - if (InteractionType != LIT_CachedIrrelevant) - { - bRelevant = true; - } + if (InteractionType != LIT_CachedLightMap && InteractionType != LIT_CachedIrrelevant) + { + bLightMapped = false; + } - if (InteractionType != LIT_CachedLightMap && InteractionType != LIT_CachedIrrelevant) - { - bLightMapped = false; - } + if (InteractionType != LIT_Dynamic) + { + bDynamic = false; + } - if (InteractionType != LIT_Dynamic) - { - bDynamic = false; - } - - if (InteractionType != LIT_CachedSignedDistanceFieldShadowMap2D) - { - bShadowMapped = false; - } + if (InteractionType != LIT_CachedSignedDistanceFieldShadowMap2D) + { + bShadowMapped = false; } } } diff --git a/Engine/Source/Runtime/Engine/Private/StatsRender2.cpp b/Engine/Source/Runtime/Engine/Private/StatsRender2.cpp index af91db7a8a6f..da0ed458e86d 100644 --- a/Engine/Source/Runtime/Engine/Private/StatsRender2.cpp +++ b/Engine/Source/Runtime/Engine/Private/StatsRender2.cpp @@ -538,7 +538,7 @@ static FString GetMemoryString( const double Value, const bool bAutoType = true return FString::Printf( TEXT( "%.2f MB" ), float( Value / (1024.0 * 1024.0) ) ); } -static int32 RenderMemoryCounter( const FGameThreadHudData& ViewData, const FComplexStatMessage& All, class FCanvas* Canvas, const int32 X, const int32 Y, const float Budget, const bool bIsBudgetIgnored ) +static int32 RenderMemoryCounter( const FGameThreadStatsData& ViewData, const FComplexStatMessage& All, class FCanvas* Canvas, const int32 X, const int32 Y, const float Budget, const bool bIsBudgetIgnored ) { FPlatformMemory::EMemoryCounterRegion Region = FPlatformMemory::EMemoryCounterRegion(All.NameAndInfo.GetField()); // At this moment we only have memory stats that are marked as non frame stats, so can't be cleared every frame. @@ -575,7 +575,7 @@ static int32 RenderMemoryCounter( const FGameThreadHudData& ViewData, const FCom return Globals.GetFontHeight(); } -static int32 RenderCounter( const FGameThreadHudData& ViewData, const FComplexStatMessage& All, class FCanvas* Canvas, const int32 X, const int32 Y, const float Budget, const bool bIsBudgetIgnored ) +static int32 RenderCounter( const FGameThreadStatsData& ViewData, const FComplexStatMessage& All, class FCanvas* Canvas, const int32 X, const int32 Y, const float Budget, const bool bIsBudgetIgnored ) { const FStatRenderGlobals& Globals = GetStatRenderGlobals(); @@ -622,7 +622,7 @@ static int32 RenderCounter( const FGameThreadHudData& ViewData, const FComplexSt return Globals.GetFontHeight(); } -void RenderHierCycles( FCanvas* Canvas, const int32 X, int32& Y, const FHudGroup& HudGroup ) +void RenderHierCycles( FCanvas* Canvas, const int32 X, int32& Y, const FActiveStatGroupInfo& HudGroup ) { const FStatRenderGlobals& Globals = GetStatRenderGlobals(); const FTexture* BackgroundTexture = Globals.GetBackgroundTexture(); @@ -670,7 +670,7 @@ int32 RenderGroupBudget( FCanvas* Canvas, const int32 X, const int32 Y, const u } template< typename T > -void RenderArrayOfStats( FCanvas* Canvas, const int32 X, int32& Y, const TArray& Aggregates, const FGameThreadHudData& ViewData, const TSet& IgnoreBudgetStats, const float TotalGroupBudget, const T& FunctionToCall ) +void RenderArrayOfStats( FCanvas* Canvas, const int32 X, int32& Y, const TArray& Aggregates, const FGameThreadStatsData& ViewData, const TSet& IgnoreBudgetStats, const float TotalGroupBudget, const T& FunctionToCall ) { const FStatRenderGlobals& Globals = GetStatRenderGlobals(); const FTexture* BackgroundTexture = Globals.GetBackgroundTexture(); @@ -710,7 +710,7 @@ void RenderArrayOfStats( FCanvas* Canvas, const int32 X, int32& Y, const TArray< } } -static int32 RenderFlatCycle( const FGameThreadHudData& ViewData, const FComplexStatMessage& Item, class FCanvas* Canvas, const int32 X, const int32 Y, const float Budget, const bool bIsBudgetIgnored ) +static int32 RenderFlatCycle( const FGameThreadStatsData& ViewData, const FComplexStatMessage& Item, class FCanvas* Canvas, const int32 X, const int32 Y, const float Budget, const bool bIsBudgetIgnored ) { return RenderCycle( Item, Canvas, X, Y, 0, true, Budget, bIsBudgetIgnored); } @@ -723,7 +723,7 @@ static int32 RenderFlatCycle( const FGameThreadHudData& ViewData, const FComplex * @param X the X location to start rendering at * @param Y the Y location to start rendering at */ -static void RenderGroupedWithHierarchy(const FGameThreadHudData& ViewData, FViewport* Viewport, class FCanvas* Canvas, const int32 X, int32& Y) +static void RenderGroupedWithHierarchy(const FGameThreadStatsData& ViewData, FViewport* Viewport, class FCanvas* Canvas, const int32 X, int32& Y) { // Grab texture for rendering text background. UTexture2D* BackgroundTexture = UCanvas::StaticClass()->GetDefaultObject()->DefaultTexture; @@ -731,13 +731,13 @@ static void RenderGroupedWithHierarchy(const FGameThreadHudData& ViewData, FView const FStatRenderGlobals& Globals = GetStatRenderGlobals(); // Render all groups. - for( int32 GroupIndex = 0; GroupIndex < ViewData.HudGroups.Num(); ++GroupIndex ) + for( int32 GroupIndex = 0; GroupIndex < ViewData.ActiveStatGroups.Num(); ++GroupIndex ) { - const FHudGroup& HudGroup = ViewData.HudGroups[GroupIndex]; - const bool bBudget = HudGroup.ThreadBudgetMap.Num() > 0; - const int32 NumThreadsBreakdown = bBudget ? HudGroup.FlatAggregateThreadBreakdown.Num() : 1; + const FActiveStatGroupInfo& StatGroup = ViewData.ActiveStatGroups[GroupIndex]; + const bool bBudget = StatGroup.ThreadBudgetMap.Num() > 0; + const int32 NumThreadsBreakdown = bBudget ? StatGroup.FlatAggregateThreadBreakdown.Num() : 1; TArray ThreadNames; - HudGroup.FlatAggregateThreadBreakdown.GetKeys(ThreadNames); + StatGroup.FlatAggregateThreadBreakdown.GetKeys(ThreadNames); for(int32 ThreadBreakdownIdx = 0; ThreadBreakdownIdx < NumThreadsBreakdown; ++ThreadBreakdownIdx) { @@ -772,8 +772,8 @@ static void RenderGroupedWithHierarchy(const FGameThreadHudData& ViewData, FView Y += Globals.GetFontHeight(); - const bool bHasHierarchy = !!HudGroup.HierAggregate.Num(); - const bool bHasFlat = !!HudGroup.FlatAggregate.Num(); + const bool bHasHierarchy = !!StatGroup.HierAggregate.Num(); + const bool bHasFlat = !!StatGroup.FlatAggregate.Num(); if (bHasHierarchy || bHasFlat) { @@ -784,34 +784,34 @@ static void RenderGroupedWithHierarchy(const FGameThreadHudData& ViewData, FView // Render hierarchy. if (bHasHierarchy) { - RenderHierCycles(Canvas, X, Y, HudGroup); + RenderHierCycles(Canvas, X, Y, StatGroup); Y += Globals.GetFontHeight(); } - const float* BudgetPtr = ShortThreadName != NAME_None ? HudGroup.ThreadBudgetMap.Find(ShortThreadName) : nullptr; + const float* BudgetPtr = ShortThreadName != NAME_None ? StatGroup.ThreadBudgetMap.Find(ShortThreadName) : nullptr; const float Budget = BudgetPtr ? *BudgetPtr : -1.f; // Render flat. if (bHasFlat) { - RenderArrayOfStats(Canvas, X, Y, bBudget ? HudGroup.FlatAggregateThreadBreakdown[ThreadName] : HudGroup.FlatAggregate, ViewData, HudGroup.BudgetIgnoreStats, Budget, RenderFlatCycle); + RenderArrayOfStats(Canvas, X, Y, bBudget ? StatGroup.FlatAggregateThreadBreakdown[ThreadName] : StatGroup.FlatAggregate, ViewData, StatGroup.BudgetIgnoreStats, Budget, RenderFlatCycle); Y += Globals.GetFontHeight(); } } // Render memory counters. - if (HudGroup.MemoryAggregate.Num()) + if (StatGroup.MemoryAggregate.Num()) { Y += RenderMemoryHeadings(Canvas, X, Y); - RenderArrayOfStats(Canvas, X, Y, HudGroup.MemoryAggregate, ViewData, HudGroup.BudgetIgnoreStats, -1.f, RenderMemoryCounter); + RenderArrayOfStats(Canvas, X, Y, StatGroup.MemoryAggregate, ViewData, StatGroup.BudgetIgnoreStats, -1.f, RenderMemoryCounter); Y += Globals.GetFontHeight(); } // Render remaining counters. - if (HudGroup.CountersAggregate.Num()) + if (StatGroup.CountersAggregate.Num()) { Y += RenderCounterHeadings(Canvas, X, Y); - RenderArrayOfStats(Canvas, X, Y, HudGroup.CountersAggregate, ViewData, HudGroup.BudgetIgnoreStats, -1.f, RenderCounter); + RenderArrayOfStats(Canvas, X, Y, StatGroup.CountersAggregate, ViewData, StatGroup.BudgetIgnoreStats, -1.f, RenderCounter); Y += Globals.GetFontHeight(); } } @@ -830,12 +830,12 @@ void RenderStats(FViewport* Viewport, class FCanvas* Canvas, int32 X, int32 Y, i { DECLARE_SCOPE_CYCLE_COUNTER( TEXT( "RenderStats" ), STAT_RenderStats, STATGROUP_StatSystem ); - FGameThreadHudData* ViewData = FHUDGroupGameThreadRenderer::Get().Latest; - if (!ViewData) + FGameThreadStatsData* ViewData = FLatestGameThreadStatsData::Get().Latest; + if (!ViewData || !ViewData->bRenderStats) { return; } - + FStatRenderGlobals& Globals = GetStatRenderGlobals(); // SizeX is used to clip/arrange the rendered stats to avoid overlay in stereo mode. const bool bIsStereo = Canvas->IsStereoRendering(); diff --git a/Engine/Source/Runtime/Engine/Private/StreamableManager.cpp b/Engine/Source/Runtime/Engine/Private/StreamableManager.cpp index 0d9ebe8b229e..f6ec8eefbcaa 100644 --- a/Engine/Source/Runtime/Engine/Private/StreamableManager.cpp +++ b/Engine/Source/Runtime/Engine/Private/StreamableManager.cpp @@ -242,24 +242,9 @@ void FStreamableHandle::GetLoadedAssets(TArray& LoadedAssets) const void FStreamableHandle::GetLoadedCount(int32& LoadedCount, int32& RequestedCount) const { - LoadedCount = 0; RequestedCount = RequestedAssets.Num(); - - if (HasLoadCompleted()) - { - LoadedCount = RequestedAssets.Num(); - } - else if (IsActive()) - { - for (const FStringAssetReference& Ref : RequestedAssets) - { - if (OwningManager->IsAsyncLoadComplete(Ref)) - { - LoadedCount++; - } - } - } - + LoadedCount = RequestedCount - StreamablesLoading; + // Check child handles for (TSharedPtr ChildHandle : ChildHandles) { @@ -437,13 +422,13 @@ void FStreamableHandle::UpdateCombinedHandle() } // Check all our children, complete if done - bool bAllInactive = true; + bool bAllCompleted = true; bool bAllCanceled = true; for (TSharedPtr ChildHandle : ChildHandles) { - if (ChildHandle->IsActive()) + if (ChildHandle->IsLoadingInProgress()) { - bAllInactive = false; + bAllCompleted = false; } if (!ChildHandle->WasCanceled()) { @@ -451,12 +436,12 @@ void FStreamableHandle::UpdateCombinedHandle() } } - // If all our sub handles were canceled, cancel us. Otherwise complete us if at least one was completed and there are no active + // If all our sub handles were canceled, cancel us. Otherwise complete us if at least one was completed and there are none in progress if (bAllCanceled) { CancelHandle(); } - else if (bAllInactive) + else if (bAllCompleted) { CompleteLoad(); @@ -584,13 +569,13 @@ struct FStreamable FStreamableManager::FStreamableManager() { - FCoreUObjectDelegates::PostGarbageCollect.AddRaw(this, &FStreamableManager::OnPostGarbageCollect); + FCoreUObjectDelegates::PreGarbageCollect.AddRaw(this, &FStreamableManager::OnPreGarbageCollect); bForceSynchronousLoads = false; } FStreamableManager::~FStreamableManager() { - FCoreUObjectDelegates::PostGarbageCollect.RemoveAll(this); + FCoreUObjectDelegates::PreGarbageCollect.RemoveAll(this); for (TStreamableMap::TIterator It(StreamableItems); It; ++It) { @@ -599,7 +584,7 @@ FStreamableManager::~FStreamableManager() } } -void FStreamableManager::OnPostGarbageCollect() +void FStreamableManager::OnPreGarbageCollect() { TSet RedirectsToRemove; @@ -766,6 +751,7 @@ FStreamable* FStreamableManager::StreamInternal(const FStringAssetReference& InT } Existing->bAsyncLoadRequestOutstanding = true; + Existing->bLoadFailed = false; LoadPackageAsync(Package, FLoadPackageAsyncDelegate::CreateSP(Handle, &FStreamableHandle::AsyncLoadCallbackWrapper, TargetName), Priority); } } @@ -1081,7 +1067,7 @@ void FStreamableManager::RemoveReferencedAsset(const FStringAssetReference& Targ { return; } - + ensureMsgf(Handle->OwningManager == this, TEXT("RemoveReferencedAsset called on wrong streamable manager for target %s"), *Target.ToString()); FStreamable* Existing = FindStreamable(Target); @@ -1178,7 +1164,7 @@ bool FStreamableManager::GetActiveHandles(const FStringAssetReference& Target, T { check(IsInGameThread()); FStreamable* Existing = FindStreamable(Target); - if (Existing) + if (Existing && Existing->ActiveHandles.Num() > 0) { for (TWeakPtr WeakHandle : Existing->ActiveHandles) { diff --git a/Engine/Source/Runtime/Engine/Private/Streaming/DynamicTextureInstanceManager.cpp b/Engine/Source/Runtime/Engine/Private/Streaming/DynamicTextureInstanceManager.cpp index 8b788ee044cb..b8198757ca4d 100644 --- a/Engine/Source/Runtime/Engine/Private/Streaming/DynamicTextureInstanceManager.cpp +++ b/Engine/Source/Runtime/Engine/Private/Streaming/DynamicTextureInstanceManager.cpp @@ -160,7 +160,7 @@ void FDynamicTextureInstanceManager::Remove(const UPrimitiveComponent* Component check(!Component || Component->IsValidLowLevelFast()); if (Component && Component->bAttachedToStreamingManagerAsDynamic) { - PendingComponents.Remove(Component); + PendingComponents.RemoveSwap(Component); // If the component is used, stop any task possibly indirecting it, and clear references. if (StateSync.GetState()->HasComponentReferences(Component)) diff --git a/Engine/Source/Runtime/Engine/Private/Streaming/TextureInstanceState.cpp b/Engine/Source/Runtime/Engine/Private/Streaming/TextureInstanceState.cpp index c7371856e5c1..14ec5b5c14d5 100644 --- a/Engine/Source/Runtime/Engine/Private/Streaming/TextureInstanceState.cpp +++ b/Engine/Source/Runtime/Engine/Private/Streaming/TextureInstanceState.cpp @@ -226,11 +226,6 @@ void FTextureInstanceState::RemoveElement(int32 ElementIndex, int32& NextCompone } } -static bool operator==(const FBoxSphereBounds& A, const FBoxSphereBounds& B) -{ - return A.Origin == B.Origin && A.BoxExtent == B.BoxExtent && A.SphereRadius == B.SphereRadius; -} - bool FTextureInstanceState::AddComponent(const UPrimitiveComponent* Component, FStreamingTextureLevelContext& LevelContext) { TArray TextureInstanceInfos; diff --git a/Engine/Source/Runtime/Engine/Private/Streaming/TextureStreamingBuild.cpp b/Engine/Source/Runtime/Engine/Private/Streaming/TextureStreamingBuild.cpp index c57eeb1e539f..597dbf38a3ec 100644 --- a/Engine/Source/Runtime/Engine/Private/Streaming/TextureStreamingBuild.cpp +++ b/Engine/Source/Runtime/Engine/Private/Streaming/TextureStreamingBuild.cpp @@ -159,6 +159,16 @@ ENGINE_API bool BuildTextureStreamingComponentData(UWorld* InWorld, EMaterialQua #undef LOCTEXT_NAMESPACE +/** + * Checks whether a UTexture2D is supposed to be streaming. + * @param Texture Texture to check + * @return true if the UTexture2D is supposed to be streaming + */ +bool IsStreamingTexture( const UTexture2D* Texture2D ) +{ + return Texture2D && Texture2D->bIsStreamable && !Texture2D->NeverStream && Texture2D->GetNumMips() > Texture2D->GetNumNonStreamingMips(); +} + uint32 PackRelativeBox(const FVector& RefOrigin, const FVector& RefExtent, const FVector& Origin, const FVector& Extent) { const FVector RefMin = RefOrigin - RefExtent; diff --git a/Engine/Source/Runtime/Engine/Private/Streaming/TextureStreamingHelpers.cpp b/Engine/Source/Runtime/Engine/Private/Streaming/TextureStreamingHelpers.cpp index a15a124b26e2..ec917bdd8ea1 100644 --- a/Engine/Source/Runtime/Engine/Private/Streaming/TextureStreamingHelpers.cpp +++ b/Engine/Source/Runtime/Engine/Private/Streaming/TextureStreamingHelpers.cpp @@ -246,16 +246,6 @@ float GShadowmapStreamingFactor = 0.09f; */ bool GNeverStreamOutTextures = false; -/** - * Checks whether a UTexture2D is supposed to be streaming. - * @param Texture Texture to check - * @return true if the UTexture2D is supposed to be streaming - */ -bool IsStreamingTexture( const UTexture2D* Texture2D ) -{ - return Texture2D && Texture2D->bIsStreamable && !Texture2D->NeverStream && Texture2D->GetNumMips() > Texture2D->GetNumNonStreamingMips(); -} - void FTextureStreamingStats::Apply() { diff --git a/Engine/Source/Runtime/Engine/Private/Tests/EngineAutomationTests.cpp b/Engine/Source/Runtime/Engine/Private/Tests/EngineAutomationTests.cpp index 204146409636..685160d3fa21 100644 --- a/Engine/Source/Runtime/Engine/Private/Tests/EngineAutomationTests.cpp +++ b/Engine/Source/Runtime/Engine/Private/Tests/EngineAutomationTests.cpp @@ -547,9 +547,7 @@ PRAGMA_ENABLE_DEPRECATION_WARNINGS Test->TestTrue(FString::Printf(TEXT("Child world rotation was incorrect after attachment (was %s, should be %s)"), *ChildActor->GetActorQuat().ToString(), *LegacyExpectedChildTransforms[LocationInteger][0].GetRotation().ToString()), ChildActor->GetActorQuat().Equals(LegacyExpectedChildTransforms[LocationInteger][0].GetRotation(), KINDA_SMALL_NUMBER)); Test->TestTrue(FString::Printf(TEXT("Child world scale was incorrect after attachment (was %s, should be %s)"), *ChildActor->GetActorScale3D().ToString(), *LegacyExpectedChildTransforms[LocationInteger][0].GetScale3D().ToString()), ChildActor->GetActorScale3D().Equals(LegacyExpectedChildTransforms[LocationInteger][0].GetScale3D(), KINDA_SMALL_NUMBER)); -PRAGMA_DISABLE_DEPRECATION_WARNINGS - ChildActor->DetachRootComponentFromParent(true); -PRAGMA_ENABLE_DEPRECATION_WARNINGS + ChildActor->DetachFromActor(FDetachmentTransformRules::KeepWorldTransform); // check we have expected values after detachment Test->TestEqual(TEXT("Parent location was affected by detachment"), ParentActor->GetActorLocation(), AttachTestConstants::ParentLocation); diff --git a/Engine/Source/Runtime/Engine/Private/TextureDerivedData.cpp b/Engine/Source/Runtime/Engine/Private/TextureDerivedData.cpp index c2254b7385c6..c7d60a48f3c9 100644 --- a/Engine/Source/Runtime/Engine/Private/TextureDerivedData.cpp +++ b/Engine/Source/Runtime/Engine/Private/TextureDerivedData.cpp @@ -754,27 +754,22 @@ class FTextureCacheDerivedDataWorker : public FNonAbandonableTask /** Build the texture. This function is safe to call from any thread. */ void BuildTexture() - { + { ensure(Compressor); if (Compressor && SourceMips.Num()) - { - // Adding some extra logs to track crash UE-42168 - FTextureMemoryStats Stats; - RHIGetTextureMemoryStats(Stats); - + { FFormatNamedArguments Args; Args.Add( TEXT("TextureName"), FText::FromString( Texture.GetName() ) ); Args.Add( TEXT("TextureFormatName"), FText::FromString( BuildSettings.TextureFormatName.GetPlainNameString() ) ); Args.Add( TEXT("TextureResolutionX"), FText::FromString( FString::FromInt(SourceMips[0].SizeX) ) ); Args.Add( TEXT("TextureResolutionY"), FText::FromString( FString::FromInt(SourceMips[0].SizeY) ) ); - Args.Add( TEXT("UsedVRAM"), FText::FromString( FString::FromInt(Stats.AllocatedMemorySize / 1024 / 1024 ) ) ); - FTextureStatusMessageContext StatusMessage( FText::Format( NSLOCTEXT("Engine", "BuildTextureStatus", "Building textures: {TextureName} ({TextureFormatName}, {TextureResolutionX}X{TextureResolutionY}) - {UsedVRAM} MB total VRAM"), Args ) ); + FTextureStatusMessageContext StatusMessage( FText::Format( NSLOCTEXT("Engine", "BuildTextureStatus", "Building textures: {TextureName} ({TextureFormatName}, {TextureResolutionX}X{TextureResolutionY})"), Args ) ); check(DerivedData->Mips.Num() == 0); DerivedData->SizeX = 0; DerivedData->SizeY = 0; DerivedData->PixelFormat = PF_Unknown; - + // Compress the texture. TArray CompressedMips; if (Compressor->BuildTexture(SourceMips, CompositeSourceMips, BuildSettings, CompressedMips)) @@ -981,7 +976,8 @@ struct FTextureAsyncCacheDerivedDataTask : public FAsyncTask(TEXTURE_COMPRESSOR_MODULENAME); + if (!Compressor) + { + Compressor = &FModuleManager::LoadModuleChecked(TEXTURE_COMPRESSOR_MODULENAME); + } if (bAsync && !bForceRebuild) { @@ -1491,7 +1490,7 @@ void UTexture::UpdateCachedLODBias( bool bIncTextureMips ) } #if WITH_EDITOR -void UTexture::CachePlatformData(bool bAsyncCache, bool bAllowAsyncBuild) +void UTexture::CachePlatformData(bool bAsyncCache, bool bAllowAsyncBuild, ITextureCompressorModule* Compressor) { FTexturePlatformData** PlatformDataLinkPtr = GetRunningPlatformData(); if (PlatformDataLinkPtr) @@ -1519,7 +1518,7 @@ void UTexture::CachePlatformData(bool bAsyncCache, bool bAllowAsyncBuild) (bAsyncCache ? ETextureCacheFlags::Async : ETextureCacheFlags::None) | (bAllowAsyncBuild? ETextureCacheFlags::AllowAsyncBuild : ETextureCacheFlags::None); - PlatformDataLink->Cache(*this, BuildSettings, CacheFlags); + PlatformDataLink->Cache(*this, BuildSettings, CacheFlags, Compressor); } } else if (PlatformDataLink == NULL) @@ -1618,7 +1617,8 @@ void UTexture::BeginCacheForCookedPlatformData( const ITargetPlatform *TargetPla PlatformDataToCache->Cache( *this, BuildSettingsToCache[SettingsIndex], - CurrentCacheFlags + CurrentCacheFlags, + nullptr ); CookedPlatformData.Add( DerivedDataKey, PlatformDataToCache ); } @@ -1718,17 +1718,14 @@ bool UTexture::IsCachedCookedPlatformDataLoaded( const ITargetPlatform* TargetPl if ( !PlatformData ) return false; - if (PlatformData) + if ( (PlatformData->AsyncTask != NULL) && ( PlatformData->AsyncTask->IsWorkDone() == true ) ) { - if ( (PlatformData->AsyncTask != NULL) && ( PlatformData->AsyncTask->IsWorkDone() == true ) ) - { - PlatformData->FinishCache(); - } + PlatformData->FinishCache(); + } - if ( PlatformData->AsyncTask) - { - return false; - } + if ( PlatformData->AsyncTask) + { + return false; } } // if we get here all our stuff is cached :) @@ -1839,7 +1836,8 @@ void UTexture::ForceRebuildPlatformData() PlatformDataLink->Cache( *this, BuildSettings, - ETextureCacheFlags::ForceRebuild + ETextureCacheFlags::ForceRebuild, + nullptr ); } } @@ -1962,7 +1960,7 @@ void UTexture::SerializeCookedPlatformData(FArchive& Ar) if (PlatformDataPtr == NULL) { PlatformDataPtr = new FTexturePlatformData(); - PlatformDataPtr->Cache(*this, BuildSettings, ETextureCacheFlags::InlineMips | ETextureCacheFlags::Async); + PlatformDataPtr->Cache(*this, BuildSettings, ETextureCacheFlags::InlineMips | ETextureCacheFlags::Async, nullptr); CookedPlatformDataPtr->Add(DerivedDataKey, PlatformDataPtr); diff --git a/Engine/Source/Runtime/Engine/Private/TextureRenderTarget2D.cpp b/Engine/Source/Runtime/Engine/Private/TextureRenderTarget2D.cpp index f7cd59864932..96acaa0de5c3 100644 --- a/Engine/Source/Runtime/Engine/Private/TextureRenderTarget2D.cpp +++ b/Engine/Source/Runtime/Engine/Private/TextureRenderTarget2D.cpp @@ -11,6 +11,7 @@ #include "UnrealEngine.h" #include "DeviceProfiles/DeviceProfile.h" #include "DeviceProfiles/DeviceProfileManager.h" +#include "RenderingObjectVersion.h" int32 GTextureRenderTarget2DMaxSizeX = 999999999; int32 GTextureRenderTarget2DMaxSizeY = 999999999; @@ -22,7 +23,8 @@ int32 GTextureRenderTarget2DMaxSizeY = 999999999; UTextureRenderTarget2D::UTextureRenderTarget2D(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { - bHDR = true; + bHDR_DEPRECATED = true; + RenderTargetFormat = RTF_RGBA16f; bAutoGenerateMips = false; NumMips = 0; ClearColor = FLinearColor(0.0f, 0.0f, 0.0f, 1.0f); @@ -157,6 +159,18 @@ void UTextureRenderTarget2D::PostEditChangeProperty(FPropertyChangedEvent& Prope } #endif // WITH_EDITOR +void UTextureRenderTarget2D::Serialize(FArchive& Ar) +{ + Super::Serialize(Ar); + + Ar.UsingCustomVersion(FRenderingObjectVersion::GUID); + + if (Ar.CustomVer(FRenderingObjectVersion::GUID) < FRenderingObjectVersion::AddedTextureRenderTargetFormats) + { + RenderTargetFormat = bHDR_DEPRECATED ? RTF_RGBA16f : RTF_RGBA8; + } +} + void UTextureRenderTarget2D::PostLoad() { float OriginalSizeX = SizeX; @@ -172,7 +186,7 @@ void UTextureRenderTarget2D::PostLoad() SizeX = FMath::Min(SizeX, GTextureRenderTarget2DMaxSizeX); SizeY = FMath::Min(SizeY, GTextureRenderTarget2DMaxSizeY); - + // Maintain aspect ratio if clamped if( SizeX != OriginalSizeX || SizeY != OriginalSizeY ) { diff --git a/Engine/Source/Runtime/Engine/Private/TickTaskManager.cpp b/Engine/Source/Runtime/Engine/Private/TickTaskManager.cpp index 213b57225fe6..19563eb7868d 100644 --- a/Engine/Source/Runtime/Engine/Private/TickTaskManager.cpp +++ b/Engine/Source/Runtime/Engine/Private/TickTaskManager.cpp @@ -1832,6 +1832,10 @@ void FTickFunction::QueueTickFunctionParallel(const struct FTickContext& TickCon // stale prereq, delete it Prerequisites.RemoveAtSwap(PrereqIndex--); } + else if (StackForCycleDetection.Contains(Prereq)) + { + UE_LOG(LogTick, Warning, TEXT("While processing prerequisites for %s, could use %s because it would form a cycle."), *DiagnosticMessage(), *Prereq->DiagnosticMessage()); + } else if (Prereq->bRegistered) { // recursive call to make sure my prerequisite is set up so I can use its completion handle diff --git a/Engine/Source/Runtime/Engine/Private/Timeline.cpp b/Engine/Source/Runtime/Engine/Private/Timeline.cpp index 0efcc7a447bd..8772379c5e33 100644 --- a/Engine/Source/Runtime/Engine/Private/Timeline.cpp +++ b/Engine/Source/Runtime/Engine/Private/Timeline.cpp @@ -939,6 +939,8 @@ void UTimelineComponent::OnRep_Timeline() } } +/// @cond DOXYGEN_WARNINGS + void UTimelineComponent::GetLifetimeReplicatedProps( TArray< FLifetimeProperty > & OutLifetimeProps ) const { Super::GetLifetimeReplicatedProps( OutLifetimeProps ); @@ -946,6 +948,8 @@ void UTimelineComponent::GetLifetimeReplicatedProps( TArray< FLifetimeProperty > DOREPLIFETIME( UTimelineComponent, TheTimeline ); } +/// @endcond + void UTimelineComponent::GetAllCurves(TSet& InOutCurves) const { TheTimeline.GetAllCurves(InOutCurves); diff --git a/Engine/Source/Runtime/Engine/Private/TriggerBase.cpp b/Engine/Source/Runtime/Engine/Private/TriggerBase.cpp index 6e2f57a46cd5..fc7cd964eacc 100644 --- a/Engine/Source/Runtime/Engine/Private/TriggerBase.cpp +++ b/Engine/Source/Runtime/Engine/Private/TriggerBase.cpp @@ -43,6 +43,7 @@ ATriggerBase::ATriggerBase(const FObjectInitializer& ObjectInitializer) SpriteComponent->Sprite = ConstructorStatics.TriggerTextureObject.Get(); SpriteComponent->RelativeScale3D = FVector(0.5f, 0.5f, 0.5f); SpriteComponent->bHiddenInGame = false; + SpriteComponent->Sprite = ConstructorStatics.TriggerTextureObject.Get(); SpriteComponent->SpriteInfo.Category = ConstructorStatics.ID_Triggers; SpriteComponent->SpriteInfo.DisplayName = ConstructorStatics.NAME_Triggers; SpriteComponent->bIsScreenSizeScaled = true; diff --git a/Engine/Source/Runtime/Engine/Private/UnrealClient.cpp b/Engine/Source/Runtime/Engine/Private/UnrealClient.cpp index be7dbd8479a7..f7d86374b925 100644 --- a/Engine/Source/Runtime/Engine/Private/UnrealClient.cpp +++ b/Engine/Source/Runtime/Engine/Private/UnrealClient.cpp @@ -19,6 +19,7 @@ #include "Matinee/MatineeActor.h" #include "EditorSupportDelegates.h" #include "HighResScreenshot.h" +#include "GameFramework/GameUserSettings.h" #include "HModel.h" #include "Framework/Notifications/NotificationManager.h" #include "Widgets/Notifications/SNotificationList.h" @@ -345,7 +346,7 @@ void FScreenshotRequest::CreateViewportScreenShotFilename(FString& InOutFilename InOutFilename = TypeName; if (!TypeName.Contains(TEXT("/"))) { - InOutFilename = FPaths::ScreenShotDir() / TypeName; + InOutFilename = GetDefault()->GameScreenshotSaveDirectory.Path / TypeName; } } @@ -799,7 +800,7 @@ FViewport::FViewport(FViewportClient* InViewportClient): ViewportClient(InViewportClient), SizeX(0), SizeY(0), - WindowMode(EWindowMode::Windowed), + WindowMode(IsRunningGame() ? GEngine->GetGameUserSettings()->GetDefaultWindowMode() : EWindowMode::Windowed), bHitProxiesCached(false), bHasRequestedToggleFreeze(false), bIsSlateViewport(false), diff --git a/Engine/Source/Runtime/Engine/Private/UnrealEngine.cpp b/Engine/Source/Runtime/Engine/Private/UnrealEngine.cpp index b9bc08114dd8..f74535d9a4a6 100644 --- a/Engine/Source/Runtime/Engine/Private/UnrealEngine.cpp +++ b/Engine/Source/Runtime/Engine/Private/UnrealEngine.cpp @@ -126,7 +126,7 @@ #include "Particles/ParticleModuleRequired.h" #include "Components/TextRenderComponent.h" - +#include "Classes/Sound/AudioSettings.h" // @todo this is here only due to circular dependency to AIModule. To be removed @@ -134,6 +134,10 @@ #include "ObjectEditorUtils.h" #endif +#if WITH_EDITOR +#include "AudioEditorModule.h" +#endif + #include "HardwareInfo.h" #include "EngineModule.h" #include "UnrealExporter.h" @@ -187,6 +191,8 @@ #include "GeneralProjectSettings.h" #include "ProfilingDebugging/LoadTimeTracker.h" +#include "ObjectKey.h" +#include "AssetRegistryModule.h" DEFINE_LOG_CATEGORY(LogEngine); IMPLEMENT_MODULE( FEngineModule, Engine ); @@ -267,6 +273,15 @@ static TAutoConsoleVariable CVarSetOverrideFPS( ECVF_Cheat); #endif // !UE_BUILD_SHIPPING +// Should we show errors and warnings (when DurationOfErrorsAndWarningsOnHUD is greater than zero), or only errors? +int32 GSupressWarningsInOnScreenDisplay = 0; +static FAutoConsoleVariableRef GSupressWarningsInOnScreenDisplayCVar( + TEXT("Engine.SupressWarningsInOnScreenDisplay"), + GSupressWarningsInOnScreenDisplay, + TEXT("0: Show both errors and warnings on screen, 1: Show only errors on screen (in either case only when DurationOfErrorsAndWarningsOnHUD is greater than zero)"), + ECVF_Default +); + /** Whether texture memory has been corrupted because we ran out of memory in the pool. */ bool GIsTextureMemoryCorrupted = false; @@ -275,7 +290,9 @@ bool GIsTextureMemoryCorrupted = false; bool GIsPrepareMapChangeBroken = false; #endif +PRAGMA_DISABLE_DEPRECATION_WARNINGS FSimpleMulticastDelegate UEngine::OnPostEngineInit; +PRAGMA_ENABLE_DEPRECATION_WARNINGS // We expose these variables to everyone as we need to access them in other files via an extern ENGINE_API float GAverageFPS = 0.0f; @@ -1366,6 +1383,9 @@ void UEngine::UpdateTimeAndHandleMaxTickRate() double ActualWaitTime = 0.f; if( WaitTime > 0 ) { + // track all this waiting so that Game Thread is correct + FThreadIdleStats::FScopeIdle Scope; + FSimpleScopeSecondsCounter ActualWaitTimeCounter(ActualWaitTime); double WaitEndTime = FApp::GetCurrentTime() + WaitTime; @@ -1654,6 +1674,11 @@ void UEngine::InitializeObjectReferences() DefaultBokehTexture = LoadObject(NULL, *DefaultBokehTextureName.ToString(), NULL, LOAD_None, NULL); } + if (DefaultBloomKernelTexture == NULL) + { + DefaultBloomKernelTexture = LoadObject(NULL, *DefaultBloomKernelTextureName.ToString(), NULL, LOAD_None, NULL); + } + if( PreIntegratedSkinBRDFTexture == NULL ) { PreIntegratedSkinBRDFTexture = LoadObject(NULL, *PreIntegratedSkinBRDFTextureName.ToString(), NULL, LOAD_None, NULL); @@ -2026,6 +2051,18 @@ bool UEngine::InitializeAudioDeviceManager() // did the module exist? if (AudioDeviceModule) { + const bool bIsAudioMixerEnabled = AudioDeviceModule->IsAudioMixerModule(); + GetMutableDefault()->SetAudioMixerEnabled(bIsAudioMixerEnabled); + +#if WITH_EDITOR + if (bIsAudioMixerEnabled) + { + IAudioEditorModule* AudioEditorModule = &FModuleManager::LoadModuleChecked("AudioEditor"); + AudioEditorModule->RegisterAudioMixerAssetActions(); + AudioEditorModule->RegisterEffectPresetAssetActions(); + } +#endif + // Create the audio device manager and register the platform module to the device manager AudioDeviceManager = new FAudioDeviceManager(); AudioDeviceManager->RegisterAudioDeviceModule(AudioDeviceModule); @@ -2275,7 +2312,7 @@ bool UEngine::InitializeHMDDevice() void UEngine::RecordHMDAnalytics() { - if(HMDDevice.IsValid() && !FParse::Param(FCommandLine::Get(),TEXT("nohmd"))) + if(HMDDevice.IsValid() && !FParse::Param(FCommandLine::Get(),TEXT("nohmd")) && HMDDevice->IsHMDConnected()) { HMDDevice->RecordAnalytics(); } @@ -3784,6 +3821,7 @@ bool UEngine::HandleListTexturesCommand( const TCHAR* Cmd, FOutputDevice& Ar ) const bool bShouldOnlyListNonStreaming = FParse::Command(&Cmd, TEXT("NONSTREAMING")) && !bShouldOnlyListStreaming; const bool bShouldOnlyListForced = FParse::Command(&Cmd, TEXT("FORCED")) && !bShouldOnlyListStreaming && !bShouldOnlyListNonStreaming; const bool bAlphaSort = FParse::Param( Cmd, TEXT("ALPHASORT") ); + const bool bCSV = FParse::Param( Cmd, TEXT("CSV") ); Ar.Logf( TEXT("Listing %s textures."), bShouldOnlyListForced ? TEXT("forced") : bShouldOnlyListNonStreaming ? TEXT("non streaming") : bShouldOnlyListStreaming ? TEXT("streaming") : TEXT("all") ); @@ -3877,13 +3915,17 @@ bool UEngine::HandleListTexturesCommand( const TCHAR* Cmd, FOutputDevice& Ar ) int32 TotalMaxAllowedSize = 0; int32 TotalCurrentSize = 0; - if (!FPlatformProperties::RequiresCookedData()) + if (bCSV) { - Ar.Logf(TEXT("MaxAllowedSize: Width x Height (Size in KB, Bias from Authored), Current/InMem: Width x Height (Size in KB), Format, LODGroup, Name, Streaming, Usage Count")); + Ar.Logf(TEXT(",Max Width,Max Height,Max Size (KB),Bias Authored,Current Width,Current Height,Current Size (KB),Format,LODGroup,Name,Streaming,Usage Count")); + } + else if (!FPlatformProperties::RequiresCookedData()) + { + Ar.Logf(TEXT("MaxAllowedSize: Width x Height (Size in KB, Authored Bias), Current/InMem: Width x Height (Size in KB), Format, LODGroup, Name, Streaming, Usage Count")); } else { - Ar.Logf(TEXT("Cooked/OnDisk: Width x Height (Size in KB), Current/InMem: Width x Height (Size in KB), Format, LODGroup, Name, Streaming, Usage Count")); + Ar.Logf(TEXT("Cooked/OnDisk: Width x Height (Size in KB, Authored Bias), Current/InMem: Width x Height (Size in KB), Format, LODGroup, Name, Streaming, Usage Count")); } for( int32 TextureIndex=0; TextureIndexLogf( TEXT( "CommandLine Options: %s" ) LINE_TERMINATOR, FCommandLine::Get() ); + ReportAr->Logf(TEXT( "CommandLine Options: %s" ), FCommandLine::Get() ); + ReportAr->Logf(TEXT("Time Since Boot: %.02f Seconds") LINE_TERMINATOR, FPlatformTime::Seconds() - GStartTime); // Run commands from the ini FConfigSection* CommandsToRun = GConfig->GetSectionPrivate(TEXT("MemReportCommands"), 0, 1, GEngineIni); @@ -4716,11 +4753,17 @@ bool UEngine::HandleMemCommand( const TCHAR* Cmd, FOutputDevice& Ar ) if( bDetailed || bReport) { - Ar.CategorizedLogf( CategoryName, ELogVerbosity::Log, TEXT("Memory Stats:") ); - Ar.CategorizedLogf( CategoryName, ELogVerbosity::Log, TEXT("FMemStack (gamethread) current size = %.2f MB"), FMemStack::Get().GetByteCount() / (1024.0f * 1024.0f)); + Ar.CategorizedLogf(CategoryName, ELogVerbosity::Log, TEXT("Memory Stats:") ); + Ar.CategorizedLogf(CategoryName, ELogVerbosity::Log, TEXT("FMemStack (gamethread) current size = %.2f MB"), FMemStack::Get().GetByteCount() / (1024.0f * 1024.0f)); Ar.CategorizedLogf(CategoryName, ELogVerbosity::Log, TEXT("FPageAllocator (all threads) allocation size [used/ unused] = [%.2f / %.2f] MB"), (FPageAllocator::BytesUsed()) / (1024.0f * 1024.0f), (FPageAllocator::BytesFree()) / (1024.0f * 1024.0f)); Ar.CategorizedLogf(CategoryName, ELogVerbosity::Log, TEXT("Nametable memory usage = %.2f MB"), FName::GetNameTableMemorySize() / (1024.0f * 1024.0f)); + FAssetRegistryModule* AssetRegistryModule = FModuleManager::LoadModulePtr(AssetRegistryConstants::ModuleName); + if (AssetRegistryModule) + { + Ar.CategorizedLogf(CategoryName, ELogVerbosity::Log, TEXT("AssetRegistry memory usage = %.2f MB"), AssetRegistryModule->Get().GetAllocatedSize() / (1024.0f * 1024.0f)); + } + #if STATS TArray Stats; GetPermanentStats(Stats); @@ -5384,6 +5427,24 @@ bool UEngine::HandleObjCommand( const TCHAR* Cmd, FOutputDevice& Ar ) } else if( FParse::Command(&Cmd,TEXT("LIST")) ) { + static TSet ForgottenObjects; + + // "obj list forget" will prevent all current objects from being reported in future "obj list" commands. + // "obj list remember" clears that list + if (FParse::Command(&Cmd, TEXT("FORGET"))) + { + for (FObjectIterator It; It; ++It) + { + ForgottenObjects.Add(FObjectKey(*It)); + } + return true; + } + else if (FParse::Command(&Cmd, TEXT("REMEMBER"))) + { + ForgottenObjects.Empty(); + return true; + } + FString CmdLineOut = FString::Printf(TEXT("Obj List: %s"), Cmd); Ar.Log( *CmdLineOut ); Ar.Log( TEXT("Objects:") ); @@ -5441,6 +5502,10 @@ bool UEngine::HandleObjCommand( const TCHAR* Cmd, FOutputDevice& Ar ) for( FObjectIterator It; It; ++It ) { + if (ForgottenObjects.Contains(FObjectKey(*It))) + { + continue; + } if (It->IsTemplate(RF_ClassDefaultObject)) { if( !bShouldIncludeDefaultObjects ) @@ -7017,7 +7082,11 @@ float UEngine::GetMaxFPS() const void UEngine::SetMaxFPS(const float MaxFPS) { IConsoleVariable* ConsoleVariable = CVarMaxFPS.AsVariable(); - ConsoleVariable->Set(MaxFPS); + + const EConsoleVariableFlags LastSetReason = (EConsoleVariableFlags)(ConsoleVariable->GetFlags() & ECVF_SetByMask); + const EConsoleVariableFlags ThisSetReason = (LastSetReason == ECVF_SetByConstructor) ? ECVF_SetByScalability : LastSetReason; + + ConsoleVariable->Set(MaxFPS, ThisSetReason); } /** @@ -7213,12 +7282,12 @@ UEngine::FErrorsAndWarningsCollector::FErrorsAndWarningsCollector() void UEngine::FErrorsAndWarningsCollector::Initialize() { - DisplayTime = 0; + DisplayTime = 0.0f; GConfig->GetFloat(TEXT("/Script/Engine.Engine"), TEXT("DurationOfErrorsAndWarningsOnHUD"), DisplayTime, GEngineIni); - if (DisplayTime > 0) + if (DisplayTime > 0.0f) { - SetVerbosity(ELogVerbosity::Warning); + SetVerbosity((GSupressWarningsInOnScreenDisplay != 0) ? ELogVerbosity::Error : ELogVerbosity::Warning); TickerHandle = FTicker::GetCoreTicker().AddTicker(FTickerDelegate::CreateRaw(this, &UEngine::FErrorsAndWarningsCollector::Tick), DisplayTime); FOutputDeviceRedirector::Get()->AddOutputDevice(this); } @@ -7235,6 +7304,9 @@ UEngine::FErrorsAndWarningsCollector::~FErrorsAndWarningsCollector() bool UEngine::FErrorsAndWarningsCollector::Tick(float Seconds) { + // Set this each tick, in case the cvar is changed at runtime + SetVerbosity((GSupressWarningsInOnScreenDisplay != 0) ? ELogVerbosity::Error : ELogVerbosity::Warning); + if (BufferedLines.Num()) { int DupeCount = 0; @@ -7275,9 +7347,8 @@ bool UEngine::FErrorsAndWarningsCollector::Tick(float Seconds) { Msg = FString::Printf(TEXT("%s (x%d)"), *Msg, DupeCount); } - - FColor LineColor = Verbosity <= ELogVerbosity::Error ? FColor::Red : FColor::Yellow; + const FColor LineColor = Verbosity <= ELogVerbosity::Error ? FColor::Red : FColor::Yellow; GEngine->AddOnScreenDebugMessage(-1, DisplayTime, LineColor, Msg); } @@ -7414,7 +7485,7 @@ static void DrawVolumeOnCanvas(const AVolume* Volume, FCanvas* Canvas, const FVe { if(Volume && Volume->GetBrushComponent() && Volume->GetBrushComponent()->BrushBodySetup) { - FTransform BrushTM = Volume->GetBrushComponent()->ComponentToWorld; + FTransform BrushTM = Volume->GetBrushComponent()->GetComponentTransform(); // Iterate over each piece for(int32 ConIdx=0; ConIdxGetBrushComponent()->BrushBodySetup->AggGeom.ConvexElems.Num(); ConIdx++) @@ -7915,11 +7986,18 @@ float DrawMapWarnings(UWorld* World, FViewport* Viewport, FCanvas* Canvas, UCanv MessageY += FontSizeY; } - // Warn about invalid reflection captures, this can appear only in game with FeatureLevel < SM4 + // Warn about invalid reflection captures, this can appear only with FeatureLevel < SM4 if (World->NumInvalidReflectionCaptureComponents > 0) { SmallTextItem.SetColor(FLinearColor::Red); - SmallTextItem.Text = FText::FromString(FString::Printf(TEXT("INVALID REFLECTION CAPTURES (%u Components, resave map in the editor)"), World->NumInvalidReflectionCaptureComponents)); + if( World->IsGameWorld()) + { + SmallTextItem.Text = FText::FromString(FString::Printf(TEXT("INVALID REFLECTION CAPTURES (%u Components, resave map in the editor)"), World->NumInvalidReflectionCaptureComponents)); + } + else + { + SmallTextItem.Text = FText::FromString(FString::Printf(TEXT("REFLECTION CAPTURE UPDATE REQUIRED (%u out-of-date reflection capture(s))"), World->NumInvalidReflectionCaptureComponents)); + } Canvas->DrawItem(SmallTextItem, FVector2D(MessageX, MessageY)); MessageY += FontSizeY; } @@ -9953,20 +10031,8 @@ bool UEngine::LoadMap( FWorldContext& WorldContext, FURL URL, class UPendingNetG WorldContext.SetCurrentWorld(nullptr); } - // Clean up the previous level out of memory. - CollectGarbage( GARBAGE_COLLECTION_KEEPFLAGS, true ); - - // For platforms which manage GPU memory directly we must Enqueue a flush, and wait for it to be processed - // so that any pending frees that depend on the GPU will be processed. Otherwise a whole map's worth of GPU memory - // may be unavailable to load the next one. - ENQUEUE_UNIQUE_RENDER_COMMAND(FlushCommand, - { - GRHICommandList.GetImmediateCommandList().ImmediateFlush(EImmediateFlushType::FlushRHIThreadFlushResources); - RHIFlushResources(); - GRHICommandList.GetImmediateCommandList().ImmediateFlush(EImmediateFlushType::FlushRHIThreadFlushResources); - } - ); - FlushRenderingCommands(); + // trim memory to clear up allocations from the previous level (also flushes rendering) + TrimMemory(); // Cancels the Forced StreamType for textures using a timer. if (!IStreamingManager::HasShutdown()) @@ -10303,11 +10369,33 @@ bool UEngine::LoadMap( FWorldContext& WorldContext, FURL URL, class UPendingNetG UE_LOG(LogLoad, Log, TEXT("Took %f seconds to LoadMap(%s)"), StopTime - StartTime, *URL.Map); FLoadTimeTracker::Get().DumpRawLoadTimes(); + WorldContext.OwningGameInstance->LoadComplete(StopTime - StartTime, *URL.Map); // Successfully started local level. return true; } +void UEngine::TrimMemory() +{ + // Clean up the previous level out of memory. + CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS, true); + + // For platforms which manage GPU memory directly we must Enqueue a flush, and wait for it to be processed + // so that any pending frees that depend on the GPU will be processed. Otherwise a whole map's worth of GPU memory + // may be unavailable to load the next one. + ENQUEUE_UNIQUE_RENDER_COMMAND(FlushCommand, + { + GRHICommandList.GetImmediateCommandList().ImmediateFlush(EImmediateFlushType::FlushRHIThreadFlushResources); + RHIFlushResources(); + GRHICommandList.GetImmediateCommandList().ImmediateFlush(EImmediateFlushType::FlushRHIThreadFlushResources); + } + ); + FlushRenderingCommands(); + + // Ask systems to trim memory where possible + FCoreDelegates::GetMemoryTrimDelegate().Broadcast(); +} + void UEngine::BlockTillLevelStreamingCompleted(UWorld* InWorld) { QUICK_SCOPE_CYCLE_COUNTER(STAT_UEngine_BlockTillLevelStreamingCompleted); @@ -11466,7 +11554,7 @@ public: ArPortFlags |= Params.bCopyDeprecatedProperties ? PPF_UseDeprecatedProperties : PPF_None; #if USE_STABLE_LOCALIZATION_KEYS - if (GIsEditor && !(ArPortFlags & PPF_DuplicateForPIE)) + if (GIsEditor && !(ArPortFlags & (PPF_DuplicateVerbatim | PPF_DuplicateForPIE))) { SetLocalizationNamespace(TextNamespaceUtil::EnsurePackageNamespace(DstObject)); } @@ -11525,7 +11613,7 @@ public: ArIgnoreClassRef = true; #if USE_STABLE_LOCALIZATION_KEYS - if (GIsEditor && !(ArPortFlags & PPF_DuplicateForPIE)) + if (GIsEditor && !(ArPortFlags & (PPF_DuplicateVerbatim | PPF_DuplicateForPIE))) { SetLocalizationNamespace(TextNamespaceUtil::EnsurePackageNamespace(DstObject)); } @@ -11588,14 +11676,13 @@ void UEngine::CopyPropertiesForUnrelatedObjects(UObject* OldObject, UObject* New TArray Components; OldObject->CollectDefaultSubobjects(Components, true); - for (int32 Index = 0; Index < Components.Num(); Index++) + for (UObject* OldInstance : Components) { FInstancedObjectRecord* pRecord = new(SavedInstances) FInstancedObjectRecord(); - UObject* OldInstance = Components[Index]; pRecord->OldInstance = OldInstance; OldInstanceMap.Add(OldInstance->GetPathName(OldObject), SavedInstances.Num() - 1); const uint32 AdditionalPortFlags = Params.bCopyDeprecatedProperties ? PPF_UseDeprecatedProperties : PPF_None; - FObjectWriter SubObjWriter(OldInstance, pRecord->SavedProperties, true, true, true, AdditionalPortFlags); + FObjectWriter SubObjWriter(OldInstance, pRecord->SavedProperties, true, true, Params.bDoDelta, AdditionalPortFlags); } } @@ -12592,7 +12679,7 @@ static void SetupThreadAffinity(const TArray& Args) FSimpleDelegateGraphTask::CreateAndDispatchWhenReady( FSimpleDelegateGraphTask::FDelegate::CreateStatic(&SetAffinityOnThread), TStatId(), NULL, ENamedThreads::RenderThread); - if (GRHIThread) + if (GRHIThread_InternalUseOnly) { FSimpleDelegateGraphTask::CreateAndDispatchWhenReady( FSimpleDelegateGraphTask::FDelegate::CreateStatic(&SetAffinityOnThread), diff --git a/Engine/Source/Runtime/Engine/Private/UnrealExporter.cpp b/Engine/Source/Runtime/Engine/Private/UnrealExporter.cpp index 81add98cbaf4..f551276a611c 100644 --- a/Engine/Source/Runtime/Engine/Private/UnrealExporter.cpp +++ b/Engine/Source/Runtime/Engine/Private/UnrealExporter.cpp @@ -496,7 +496,7 @@ void UExporter::EmitBeginObject( FOutputDevice& Ar, UObject* Obj, uint32 PortFla if (!(PortFlags & PPF_SeparateDefine)) { - Ar.Logf(TEXT(" Class=%s"), *Obj->GetClass()->GetName()); + Ar.Logf(TEXT(" Class=%s"), *Obj->GetClass()->GetPathName()); } // always need a name, adding "" for space handling @@ -508,7 +508,9 @@ void UExporter::EmitBeginObject( FOutputDevice& Ar, UObject* Obj, uint32 PortFla if (!bIsExportingDefaultObject) { UObject* Archetype = Obj->GetArchetype(); - Ar.Logf(TEXT(" Archetype=%s"), *UObjectPropertyBase::GetExportPath(Archetype, Archetype->GetOutermost(), Archetype->GetOuter(), PortFlags)); + // since we could have two object owners with the same name (like named Blueprints in different folders), + // we need the fully qualified path for the archetype (so we don't get confused when unpacking this) + Ar.Logf(TEXT(" Archetype=%s"), *UObjectPropertyBase::GetExportPath(Archetype, Archetype->GetOutermost(), /*ExportRootScope =*/nullptr, PortFlags & ~PPF_ExportsNotFullyQualified)); } } diff --git a/Engine/Source/Runtime/Engine/Private/UserInterface/Canvas.cpp b/Engine/Source/Runtime/Engine/Private/UserInterface/Canvas.cpp index 681b39a14fc9..697e4841d635 100644 --- a/Engine/Source/Runtime/Engine/Private/UserInterface/Canvas.cpp +++ b/Engine/Source/Runtime/Engine/Private/UserInterface/Canvas.cpp @@ -923,7 +923,7 @@ void FCanvas::Clear(const FLinearColor& ClearColor) { ::SetRenderTarget(RHICmdList, CanvasRenderTarget->GetRenderTargetTexture(), FTextureRHIRef(), true); RHICmdList.SetViewport(0, 0, 0.0f, CanvasRenderTarget->GetSizeXY().X, CanvasRenderTarget->GetSizeXY().Y, 1.0f); - DrawClearQuad(RHICmdList, GMaxRHIFeatureLevel, ClearColor); + DrawClearQuad(RHICmdList, ClearColor); } else { @@ -1936,6 +1936,7 @@ void UCanvas::K2_DrawMaterial(UMaterialInterface* RenderMaterial, FVector2D Scre FCanvasTileItem TileItem(ScreenPosition, RenderMaterial->GetRenderProxy(0), ScreenSize, CoordinatePosition, CoordinatePosition + CoordinateSize); TileItem.Rotation = FRotator(0, Rotation, 0); TileItem.PivotPoint = PivotPoint; + TileItem.SetColor(DrawColor); DrawItem(TileItem); } } diff --git a/Engine/Source/Runtime/Engine/Private/UserInterface/CanvasItem.cpp b/Engine/Source/Runtime/Engine/Private/UserInterface/CanvasItem.cpp index de7c7559c0e9..fff029d3cf56 100644 --- a/Engine/Source/Runtime/Engine/Private/UserInterface/CanvasItem.cpp +++ b/Engine/Source/Runtime/Engine/Private/UserInterface/CanvasItem.cpp @@ -436,7 +436,7 @@ void FCanvasTileItem::Draw( class FCanvas* InCanvas ) FLinearColor ActualColor = Color; ActualColor.A *= InCanvas->AlphaModulate; - const FTexture* FinalTexture = Texture ? Texture : GWhiteTexture; + const FTexture* FinalTexture = Texture; FBatchedElements* BatchedElements = InCanvas->GetBatchedElements(FCanvas::ET_Triangle, BatchedElementParameters, FinalTexture, BlendMode); FHitProxyId HitProxyId = InCanvas->GetHitProxyId(); @@ -541,7 +541,7 @@ void FCanvasBorderItem::Draw( class FCanvas* InCanvas ) FLinearColor ActualColor = Color; ActualColor.A *= InCanvas->AlphaModulate; - const FTexture* const CornersTexture = BorderTexture ? BorderTexture : GWhiteTexture; + const FTexture* const CornersTexture = BorderTexture; const FTexture* const BackTexture = BackgroundTexture ? BackgroundTexture : GWhiteTexture; const FTexture* const LeftTexture = BorderLeftTexture ? BorderLeftTexture : GWhiteTexture; const FTexture* const RightTexture = BorderRightTexture ? BorderRightTexture : GWhiteTexture; diff --git a/Engine/Source/Runtime/Engine/Private/UserInterface/Console.cpp b/Engine/Source/Runtime/Engine/Private/UserInterface/Console.cpp index f5f3716473e3..41d7476b327a 100644 --- a/Engine/Source/Runtime/Engine/Private/UserInterface/Console.cpp +++ b/Engine/Source/Runtime/Engine/Private/UserInterface/Console.cpp @@ -70,7 +70,7 @@ public: const UConsoleSettings* ConsoleSettings = GetDefault(); // can be optimized - int32 NewIdx = Sink.AddZeroed(1); + int32 NewIdx = Sink.AddDefaulted(); FAutoCompleteCommand& Cmd = Sink[NewIdx]; Cmd.Command = Name; @@ -204,7 +204,16 @@ void UConsole::BuildRuntimeAutoCompleteList(bool bForce) FuncName = FString(TEXT("ce ")) + FuncName; } - const int32 NewIdx = AutoCompleteList.AddDefaulted(); + int32 Idx = 0; + for (; Idx < AutoCompleteList.Num(); ++Idx) + { + if (AutoCompleteList[Idx].Command.ToLower() == FuncName) + { + break; + } + } + + const int32 NewIdx = (Idx < AutoCompleteList.Num()) ? Idx : AutoCompleteList.AddDefaulted(); AutoCompleteList[NewIdx].Command = FuncName; AutoCompleteList[NewIdx].Color = ConsoleSettings->AutoCompleteCommandColor; @@ -217,7 +226,7 @@ void UConsole::BuildRuntimeAutoCompleteList(bool bForce) UProperty *Prop = *PropIt; Desc += FString::Printf(TEXT("%s[%s] "),*Prop->GetName(),*Prop->GetCPPType()); } - AutoCompleteList[NewIdx].Desc = Desc; + AutoCompleteList[NewIdx].Desc = Desc + AutoCompleteList[NewIdx].Desc; } } @@ -279,16 +288,24 @@ void UConsole::BuildRuntimeAutoCompleteList(bool bForce) // stat commands { const TSet& StatGroupNames = FStatGroupGameThreadNotifier::Get().StatGroupNames; - - int32 NewIdx = AutoCompleteList.AddDefaulted(StatGroupNames.Num()); for (const FName& StatGroupName : StatGroupNames) { FString Command = FString(TEXT("Stat ")); Command += StatGroupName.ToString().RightChop(sizeof("STATGROUP_") - 1); + const FString CommandLower = Command.ToLower(); - AutoCompleteList[NewIdx].Command = Command; - AutoCompleteList[NewIdx].Color = ConsoleSettings->AutoCompleteCommandColor; - NewIdx++; + int32 Idx = 0; + for (; Idx < AutoCompleteList.Num(); ++Idx) + { + if (AutoCompleteList[Idx].Command.ToLower() == CommandLower) + { + break; + } + } + + Idx = (Idx < AutoCompleteList.Num()) ? Idx : AutoCompleteList.AddDefaulted(); + AutoCompleteList[Idx].Command = Command; + AutoCompleteList[Idx].Color = ConsoleSettings->AutoCompleteCommandColor; } } #endif @@ -308,7 +325,7 @@ void UConsole::BuildRuntimeAutoCompleteList(bool bForce) FText LocName; FEngineShowFlags::FindShowFlagDisplayName(InName, LocName); - int32 NewIdx = AutoCompleteList.AddZeroed(1); + int32 NewIdx = AutoCompleteList.AddDefaulted(); AutoCompleteList[NewIdx].Command = TEXT("show ") + InName; AutoCompleteList[NewIdx].Desc = FString::Printf(TEXT("(toggles the %s showflag)"),*LocName.ToString()); AutoCompleteList[NewIdx].Color = GetDefault()->AutoCompleteCommandColor; diff --git a/Engine/Source/Runtime/Engine/Private/UserInterface/InputSettings.cpp b/Engine/Source/Runtime/Engine/Private/UserInterface/InputSettings.cpp index 36109e64c293..6df2ab29ec1e 100644 --- a/Engine/Source/Runtime/Engine/Private/UserInterface/InputSettings.cpp +++ b/Engine/Source/Runtime/Engine/Private/UserInterface/InputSettings.cpp @@ -137,13 +137,36 @@ void UInputSettings::SaveKeyMappings() SaveConfig(); } -void UInputSettings::AddActionMapping(const FInputActionKeyMapping& KeyMapping) +UInputSettings* UInputSettings::GetInputSettings() { - ActionMappings.AddUnique(KeyMapping); - ForceRebuildKeymaps(); + return GetMutableDefault(); } -void UInputSettings::RemoveActionMapping(const FInputActionKeyMapping& KeyMapping) +void UInputSettings::AddActionMapping(const FInputActionKeyMapping& KeyMapping, const bool bForceRebuildKeymaps) +{ + ActionMappings.AddUnique(KeyMapping); + if (bForceRebuildKeymaps) + { + ForceRebuildKeymaps(); + } +} + +void UInputSettings::GetActionMappingByName(const FName InActionName, TArray& OutMappings) const +{ + if (InActionName.IsValid()) + { + for (int32 ActionIndex = ActionMappings.Num() - 1; ActionIndex >= 0; --ActionIndex) + { + if (ActionMappings[ActionIndex].ActionName == InActionName) + { + OutMappings.Add(ActionMappings[ActionIndex]); + // we don't break because the mapping may have been in the array twice + } + } + } +} + +void UInputSettings::RemoveActionMapping(const FInputActionKeyMapping& KeyMapping, const bool bForceRebuildKeymaps) { for (int32 ActionIndex = ActionMappings.Num() - 1; ActionIndex >= 0; --ActionIndex) { @@ -153,16 +176,37 @@ void UInputSettings::RemoveActionMapping(const FInputActionKeyMapping& KeyMappin // we don't break because the mapping may have been in the array twice } } - ForceRebuildKeymaps(); + if (bForceRebuildKeymaps) + { + ForceRebuildKeymaps(); + } } -void UInputSettings::AddAxisMapping(const FInputAxisKeyMapping& KeyMapping) +void UInputSettings::AddAxisMapping(const FInputAxisKeyMapping& KeyMapping, const bool bForceRebuildKeymaps) { AxisMappings.AddUnique(KeyMapping); - ForceRebuildKeymaps(); + if (bForceRebuildKeymaps) + { + ForceRebuildKeymaps(); + } } -void UInputSettings::RemoveAxisMapping(const FInputAxisKeyMapping& InKeyMapping) +void UInputSettings::GetAxisMappingByName(const FName InAxisName, TArray& OutMappings) const +{ + if (InAxisName.IsValid()) + { + for (int32 AxisIndex = AxisMappings.Num() - 1; AxisIndex >= 0; --AxisIndex) + { + if (AxisMappings[AxisIndex].AxisName == InAxisName) + { + OutMappings.Add(AxisMappings[AxisIndex]); + // we don't break because the mapping may have been in the array twice + } + } + } +} + +void UInputSettings::RemoveAxisMapping(const FInputAxisKeyMapping& InKeyMapping, const bool bForceRebuildKeymaps) { for (int32 AxisIndex = AxisMappings.Num() - 1; AxisIndex >= 0; --AxisIndex) { @@ -174,7 +218,10 @@ void UInputSettings::RemoveAxisMapping(const FInputAxisKeyMapping& InKeyMapping) // we don't break because the mapping may have been in the array twice } } - ForceRebuildKeymaps(); + if (bForceRebuildKeymaps) + { + ForceRebuildKeymaps(); + } } void UInputSettings::GetActionNames(TArray& ActionNames) const diff --git a/Engine/Source/Runtime/Engine/Private/UserInterface/PlayerInput.cpp b/Engine/Source/Runtime/Engine/Private/UserInterface/PlayerInput.cpp index d3b5cd4bac01..331f6eafb676 100644 --- a/Engine/Source/Runtime/Engine/Private/UserInterface/PlayerInput.cpp +++ b/Engine/Source/Runtime/Engine/Private/UserInterface/PlayerInput.cpp @@ -1286,12 +1286,9 @@ void UPlayerInput::FinishProcessingPlayerInput() // finished processing input for this frame, clean up for next update for (TMap::TIterator It(KeyStateMap); It; ++It) { - FKeyState* const KeyState = &It.Value(); - if (KeyState) - { - KeyState->bDownPrevious = KeyState->bDown; - KeyState->bConsumed = false; - } + FKeyState& KeyState = It.Value(); + KeyState.bDownPrevious = KeyState.bDown; + KeyState.bConsumed = false; } } diff --git a/Engine/Source/Runtime/Engine/Private/UserInterfaceSettings.cpp b/Engine/Source/Runtime/Engine/Private/UserInterfaceSettings.cpp index 2c08a17e1112..4f347810c064 100644 --- a/Engine/Source/Runtime/Engine/Private/UserInterfaceSettings.cpp +++ b/Engine/Source/Runtime/Engine/Private/UserInterfaceSettings.cpp @@ -136,12 +136,17 @@ void UUserInterfaceSettings::ForceLoadResources() LoadedClasses.Add(Entry.Value.TryLoad()); } - for (UObject* Cursor : LoadedClasses) + for (int32 i = 0; i < LoadedClasses.Num(); ++i) { + UObject* Cursor = LoadedClasses[i]; if (Cursor) { CursorClasses.Add(Cursor); } + else + { + UE_LOG(LogLoad, Warning, TEXT("UUserInterfaceSettings::ForceLoadResources: Failed to load cursor resource %d."), i); + } } CustomScalingRuleClassInstance = CustomScalingRuleClass.TryLoadClass(); diff --git a/Engine/Source/Runtime/Engine/Private/VectorField.cpp b/Engine/Source/Runtime/Engine/Private/VectorField.cpp index 480f34d20726..f80ca385c27a 100644 --- a/Engine/Source/Runtime/Engine/Private/VectorField.cpp +++ b/Engine/Source/Runtime/Engine/Private/VectorField.cpp @@ -520,7 +520,7 @@ void UVectorFieldComponent::OnRegister() { FVectorFieldInstance* Instance = new FVectorFieldInstance(); VectorField->InitInstance(Instance, /*bPreviewInstance=*/ true); - Instance->UpdateTransforms(ComponentToWorld.ToMatrixWithScale()); + Instance->UpdateTransforms(GetComponentTransform().ToMatrixWithScale()); VectorFieldInstance = Instance; } else diff --git a/Engine/Source/Runtime/Engine/Private/VectorFieldVolume.cpp b/Engine/Source/Runtime/Engine/Private/VectorFieldVolume.cpp index 3e16aa5d3838..beaaf98e4ce8 100644 --- a/Engine/Source/Runtime/Engine/Private/VectorFieldVolume.cpp +++ b/Engine/Source/Runtime/Engine/Private/VectorFieldVolume.cpp @@ -43,10 +43,3 @@ AVectorFieldVolume::AVectorFieldVolume(const FObjectInitializer& ObjectInitializ #endif // WITH_EDITORONLY_DATA } - -/** Returns VectorFieldComponent subobject **/ -UVectorFieldComponent* AVectorFieldVolume::GetVectorFieldComponent() const { return VectorFieldComponent; } -#if WITH_EDITORONLY_DATA -/** Returns SpriteComponent subobject **/ -UBillboardComponent* AVectorFieldVolume::GetSpriteComponent() const { return SpriteComponent; } -#endif diff --git a/Engine/Source/Runtime/Engine/Private/VisualLogger/VisualLogger.cpp b/Engine/Source/Runtime/Engine/Private/VisualLogger/VisualLogger.cpp index fe47845cb80c..4d3bf1a6a803 100644 --- a/Engine/Source/Runtime/Engine/Private/VisualLogger/VisualLogger.cpp +++ b/Engine/Source/Runtime/Engine/Private/VisualLogger/VisualLogger.cpp @@ -239,7 +239,7 @@ FVisualLogEntry* FVisualLogger::GetEntryToWrite(const UObject* Object, float Tim } } - return CurrentEntry && CurrentEntry->bIsAllowedToLog ? CurrentEntry : nullptr; + return CurrentEntry->bIsAllowedToLog ? CurrentEntry : nullptr; } diff --git a/Engine/Source/Runtime/Engine/Private/Volume.cpp b/Engine/Source/Runtime/Engine/Private/Volume.cpp index 12f4222cd7bf..ed2cb77f714b 100644 --- a/Engine/Source/Runtime/Engine/Private/Volume.cpp +++ b/Engine/Source/Runtime/Engine/Private/Volume.cpp @@ -72,7 +72,7 @@ bool AVolume::EncompassesPoint(FVector Point, float SphereRadius/*=0.f*/, float* return false; } #else - FBoxSphereBounds Bounds = BrushComponent->CalcBounds(BrushComponent->ComponentToWorld); + FBoxSphereBounds Bounds = BrushComponent->CalcBounds(BrushComponent->GetComponentTransform()); const float DistanceSqr = Bounds.GetBox().ComputeSquaredDistanceToPoint(Point); #endif diff --git a/Engine/Source/Runtime/Engine/Private/WindDirectionalSource.cpp b/Engine/Source/Runtime/Engine/Private/WindDirectionalSource.cpp index 16372436f1ae..4ca8951f1bc7 100644 --- a/Engine/Source/Runtime/Engine/Private/WindDirectionalSource.cpp +++ b/Engine/Source/Runtime/Engine/Private/WindDirectionalSource.cpp @@ -253,7 +253,7 @@ FWindSourceSceneProxy* UWindDirectionalSourceComponent::CreateSceneProxy() const if (bPointWind) { return new FWindSourceSceneProxy( - ComponentToWorld.GetLocation(), + GetComponentTransform().GetLocation(), Strength, Speed, MinGustAmount, @@ -264,7 +264,7 @@ FWindSourceSceneProxy* UWindDirectionalSourceComponent::CreateSceneProxy() const else { return new FWindSourceSceneProxy( - ComponentToWorld.GetUnitAxis(EAxis::X), + GetComponentTransform().GetUnitAxis(EAxis::X), Strength, Speed, MinGustAmount, @@ -280,21 +280,15 @@ bool UWindDirectionalSourceComponent::GetWindParameters(const FVector& EvaluateP if(bPointWind) { - FWindSourceSceneProxy LocalProxy = FWindSourceSceneProxy(ComponentToWorld.GetLocation(), Strength, Speed, MinGustAmount, MaxGustAmount, Radius); + FWindSourceSceneProxy LocalProxy = FWindSourceSceneProxy(GetComponentTransform().GetLocation(), Strength, Speed, MinGustAmount, MaxGustAmount, Radius); bFoundWind = LocalProxy.GetWindParameters(EvaluatePosition, OutData, Weight); } else { - FWindSourceSceneProxy LocalProxy = FWindSourceSceneProxy(ComponentToWorld.GetUnitAxis(EAxis::X), Strength, Speed, MinGustAmount, MaxGustAmount); + FWindSourceSceneProxy LocalProxy = FWindSourceSceneProxy(GetComponentTransform().GetUnitAxis(EAxis::X), Strength, Speed, MinGustAmount, MaxGustAmount); bFoundWind = LocalProxy.GetWindParameters(EvaluatePosition, OutData, Weight); } return bFoundWind; } -/** Returns Component subobject **/ -UWindDirectionalSourceComponent* AWindDirectionalSource::GetComponent() const { return Component; } -#if WITH_EDITORONLY_DATA -/** Returns ArrowComponent subobject **/ -UArrowComponent* AWindDirectionalSource::GetArrowComponent() const { return ArrowComponent; } -#endif diff --git a/Engine/Source/Runtime/Engine/Private/World.cpp b/Engine/Source/Runtime/Engine/Private/World.cpp index 5dfa80cd579a..417b905bcd8d 100644 --- a/Engine/Source/Runtime/Engine/Private/World.cpp +++ b/Engine/Source/Runtime/Engine/Private/World.cpp @@ -600,7 +600,7 @@ void UWorld::PostDuplicate(bool bDuplicateForPIE) // We're duplicating the world, also duplicate UObjects which are map data but don't have the UWorld in their Outer chain. There are two cases: // 1) legacy lightmap textures and MapBuildData object will be in the same package as the UWorld // 2) MapBuildData will be in a separate package with lightmap textures underneath it - if (PersistentLevel && PersistentLevel->MapBuildData) + if (PersistentLevel->MapBuildData) { UPackage* BuildDataPackage = MyPackage; FName NewMapBuildDataName = PersistentLevel->MapBuildData->GetFName(); @@ -854,23 +854,8 @@ void UWorld::PostLoad() } -bool UWorld::PreSaveRoot(const TCHAR* Filename, TArray& AdditionalPackagesToCook) +bool UWorld::PreSaveRoot(const TCHAR* Filename) { - // add any streaming sublevels to the list of extra packages to cook - for (int32 LevelIndex = 0; LevelIndex < StreamingLevels.Num(); LevelIndex++) - { - ULevelStreaming* StreamingLevel = StreamingLevels[LevelIndex]; - if (StreamingLevel) - { - // Load package if found. - const FString WorldAssetPackageName = StreamingLevel->GetWorldAssetPackageName(); - FString PackageFilename; - if (FPackageName::DoesPackageExist(WorldAssetPackageName, NULL, &PackageFilename)) - { - AdditionalPackagesToCook.Add(WorldAssetPackageName); - } - } - } #if WITH_EDITOR // Rebuild all level blueprints now to ensure no stale data is stored on the actors if( !IsRunningCommandlet() ) @@ -1220,6 +1205,9 @@ void UWorld::InitWorld(const InitializationValues IVS) DefaultBrush->Brush->SetFlags( RF_Transactional ); DefaultBrush->Brush->Polys->SetFlags( RF_Transactional ); + // The default brush is legacy but has to exist for some old bsp operations. However it should not be interacted with in the editor. + DefaultBrush->SetIsTemporarilyHiddenInEditor(true); + // Find the index in the array the default brush has been spawned at. Not necessarily // the last index as the code might spawn the default physics volume afterwards. const int32 DefaultBrushActorIndex = PersistentLevel->Actors.Find( DefaultBrush ); @@ -2107,7 +2095,7 @@ void UWorld::AddToWorld( ULevel* Level, const FTransform& LevelTransform ) // We don't need to rerun construction scripts if we have cooked data or we are playing in editor unless the PIE world was loaded // from disk rather than duplicated - const bool bRerunConstructionScript = !(FPlatformProperties::RequiresCookedData() || (IsGameWorld() && (Level->bHasRerunConstructionScripts || Level->bWasDuplicatedForPIE || !bRerunConstructionDuringEditorStreaming))); + const bool bRerunConstructionScript = !(FPlatformProperties::RequiresCookedData() || (IsGameWorld() && (Level->bHasRerunConstructionScripts || !bRerunConstructionDuringEditorStreaming))); // Incrementally update components. int32 NumComponentsToUpdate = GLevelStreamingComponentsRegistrationGranularity; @@ -2670,6 +2658,8 @@ UWorld* UWorld::DuplicateWorldForPIE(const FString& PackageName, UWorld* OwningW ULevel* EditorLevel = EditorLevelWorld->PersistentLevel; ULevel* PIELevel = PIELevelWorld->PersistentLevel; + PIELevel->bHasRerunConstructionScripts = EditorLevel->bHasRerunConstructionScripts; + // Fixup model components. The index buffers have been created for the components in the EditorWorld and the order // in which components were post-loaded matters. So don't try to guarantee a particular order here, just copy the // elements over. @@ -2965,7 +2955,7 @@ void UWorld::ConditionallyBuildStreamingData() bool UWorld::IsVisibilityRequestPending() const { - return (CurrentLevelPendingVisibility != nullptr && CurrentLevelPendingInvisibility != nullptr); + return (CurrentLevelPendingVisibility != nullptr || CurrentLevelPendingInvisibility != nullptr); } bool UWorld::AreAlwaysLoadedLevelsLoaded() const @@ -3105,6 +3095,11 @@ bool UWorld::Exec( UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar ) { return HandleTraceTagCommand( Cmd, Ar ); } + else if( FParse::Command( &Cmd, TEXT("TRACETAGALL"))) + { + bDebugDrawAllTraceTags = !bDebugDrawAllTraceTags; + return true; + } else if( FParse::Command( &Cmd, TEXT("FLUSHPERSISTENTDEBUGLINES") ) ) { return HandleFlushPersistentDebugLinesCommand( Cmd, Ar ); @@ -3315,14 +3310,17 @@ void UWorld::InitializeActorsForPlay(const FURL& InURL, bool bResetTime) UE_LOG(LogWorld, Warning, TEXT("*** WARNING - PATHS MAY NOT BE VALID ***")); } - // Lock the level. - if(IsPreviewWorld()) + if (GEngine != NULL) { - UE_LOG(LogWorld, Verbose, TEXT("Bringing preview %s up for play (max tick rate %i) at %s"), *GetFullName(), FMath::RoundToInt(GEngine->GetMaxTickRate(0,false)), *FDateTime::Now().ToString() ); - } - else - { - UE_LOG(LogWorld, Log, TEXT("Bringing %s up for play (max tick rate %i) at %s"), *GetFullName(), FMath::RoundToInt(GEngine->GetMaxTickRate(0,false)), *FDateTime::Now().ToString() ); + // Lock the level. + if (IsPreviewWorld()) + { + UE_LOG(LogWorld, Verbose, TEXT("Bringing preview %s up for play (max tick rate %i) at %s"), *GetFullName(), FMath::RoundToInt(GEngine->GetMaxTickRate(0, false)), *FDateTime::Now().ToString()); + } + else + { + UE_LOG(LogWorld, Log, TEXT("Bringing %s up for play (max tick rate %i) at %s"), *GetFullName(), FMath::RoundToInt(GEngine->GetMaxTickRate(0, false)), *FDateTime::Now().ToString()); + } } // Initialize network actors and start execution. @@ -3757,7 +3755,7 @@ bool UWorld::AreActorsInitialized() const float UWorld::GetMonoFarFieldCullingDistance() const { float Result = 0.0f; - const AWorldSettings* const WorldSettings = GetWorldSettings(); + const AWorldSettings* const WorldSettings = GetWorldSettings(false, false); if (WorldSettings != nullptr) { Result = WorldSettings->MonoCullingDistance; @@ -4759,7 +4757,16 @@ void FSeamlessTravelHandler::SeamlessTravelLoadCallback(const FName& PackageName { if (World->WorldType == EWorldType::PIE) { - World->StreamingLevelsPrefix = UWorld::BuildPIEPackagePrefix(LevelPackage->PIEInstanceID); + if (LevelPackage->PIEInstanceID != -1) + { + World->StreamingLevelsPrefix = UWorld::BuildPIEPackagePrefix(LevelPackage->PIEInstanceID); + } + else + { + // If this is a PIE world but the PIEInstanceID is -1, that implies this world is a temporary save + // for multi-process PIE which should have been saved with the correct StreamingLevelsPrefix. + ensure(!World->StreamingLevelsPrefix.IsEmpty()); + } } if (World->PersistentLevel) @@ -5696,6 +5703,11 @@ bool UWorld::IsGameWorld() const return WorldType == EWorldType::Game || WorldType == EWorldType::PIE || WorldType == EWorldType::GamePreview; } +bool UWorld::IsEditorWorld() const +{ + return WorldType == EWorldType::Editor || WorldType == EWorldType::EditorPreview || WorldType == EWorldType::PIE; +} + bool UWorld::IsPreviewWorld() const { return WorldType == EWorldType::EditorPreview || WorldType == EWorldType::GamePreview; @@ -6076,17 +6088,23 @@ void UWorld::SetGameState(AGameStateBase* NewGameState) GameState = NewGameState; // Set the GameState on the LevelCollection it's associated with. - const ULevel* const CachedLevel = NewGameState->GetLevel(); - FLevelCollection* const FoundCollection = NewGameState ? CachedLevel->GetCachedLevelCollection() : nullptr; - if (FoundCollection) + if (NewGameState != nullptr) { - FoundCollection->SetGameState(NewGameState); - - // For now the static levels use the same GameState as the source dynamic levels. - if (FoundCollection->GetType() == ELevelCollectionType::DynamicSourceLevels) + const ULevel* const CachedLevel = NewGameState->GetLevel(); + if(CachedLevel != nullptr) { - FLevelCollection& StaticLevels = FindOrAddCollectionByType(ELevelCollectionType::StaticLevels); - StaticLevels.SetGameState(NewGameState); + FLevelCollection* const FoundCollection = CachedLevel->GetCachedLevelCollection(); + if (FoundCollection) + { + FoundCollection->SetGameState(NewGameState); + + // For now the static levels use the same GameState as the source dynamic levels. + if (FoundCollection->GetType() == ELevelCollectionType::DynamicSourceLevels) + { + FLevelCollection& StaticLevels = FindOrAddCollectionByType(ELevelCollectionType::StaticLevels); + StaticLevels.SetGameState(NewGameState); + } + } } } } @@ -6444,8 +6462,8 @@ void UWorld::GetAssetRegistryTags(TArray& OutTags) const // Save/Display the file size and modify date FDateTime AssetDateModified = IFileManager::Get().GetTimeStamp(*FullFilePath); - OutTags.Add(FAssetRegistryTag("DateModified", FText::AsDate(AssetDateModified, EDateTimeStyle::Short).ToString(), FAssetRegistryTag::TT_Dimensional)); - OutTags.Add(FAssetRegistryTag("MapFileSize", FText::AsMemory(IFileManager::Get().FileSize(*FullFilePath)).ToString(), FAssetRegistryTag::TT_Numerical)); + OutTags.Add(FAssetRegistryTag("DateModified", AssetDateModified.ToString(), FAssetRegistryTag::TT_Chronological, FAssetRegistryTag::TD_Date)); + OutTags.Add(FAssetRegistryTag("MapFileSize", Lex::ToString(IFileManager::Get().FileSize(*FullFilePath)), FAssetRegistryTag::TT_Numerical, FAssetRegistryTag::TD_Memory)); FWorldDelegates::GetAssetTags.Broadcast(this, OutTags); } diff --git a/Engine/Source/Runtime/Engine/Private/WorldSettings.cpp b/Engine/Source/Runtime/Engine/Private/WorldSettings.cpp index a29f46590162..8506401e4314 100644 --- a/Engine/Source/Runtime/Engine/Private/WorldSettings.cpp +++ b/Engine/Source/Runtime/Engine/Private/WorldSettings.cpp @@ -104,14 +104,18 @@ void AWorldSettings::PreInitializeComponents() // only create once - if (World->MyParticleEventManager == NULL && !GEngine->ParticleEventManagerClassPath.IsEmpty()) { - TSubclassOf ParticleEventManagerClass = Cast(StaticLoadObject(UClass::StaticClass(), NULL, *GEngine->ParticleEventManagerClassPath, NULL, LOAD_NoWarn, NULL)); - if (ParticleEventManagerClass != NULL) + UObject* Object = StaticLoadObject(UClass::StaticClass(), NULL, *GEngine->ParticleEventManagerClassPath, NULL, LOAD_NoWarn, NULL); + if (Object != NULL) { - FActorSpawnParameters SpawnParameters; - SpawnParameters.Owner = this; - SpawnParameters.Instigator = Instigator; - SpawnParameters.ObjectFlags |= RF_Transient; // We never want to save particle event managers into a map - World->MyParticleEventManager = World->SpawnActor(ParticleEventManagerClass, SpawnParameters ); + TSubclassOf ParticleEventManagerClass = Cast(Object); + if (ParticleEventManagerClass != NULL) + { + FActorSpawnParameters SpawnParameters; + SpawnParameters.Owner = this; + SpawnParameters.Instigator = Instigator; + SpawnParameters.ObjectFlags |= RF_Transient; // We never want to save particle event managers into a map + World->MyParticleEventManager = World->SpawnActor(ParticleEventManagerClass, SpawnParameters); + } } } } diff --git a/Engine/Source/Runtime/Engine/Public/AI/NavigationSystemHelpers.h b/Engine/Source/Runtime/Engine/Public/AI/NavigationSystemHelpers.h index 129bc5e62434..04ef823c0af5 100644 --- a/Engine/Source/Runtime/Engine/Public/AI/NavigationSystemHelpers.h +++ b/Engine/Source/Runtime/Engine/Public/AI/NavigationSystemHelpers.h @@ -44,28 +44,55 @@ struct FNavigableGeometryExport namespace NavigationHelper { + struct FNavLinkOwnerData + { + const AActor* Actor; + FTransform LinkToWorld; + + FNavLinkOwnerData() : Actor(nullptr) {} + FNavLinkOwnerData(const AActor& InActor); + FNavLinkOwnerData(const USceneComponent& InComponent); + }; + void GatherCollision(UBodySetup* RigidBody, TNavStatArray& OutVertexBuffer, TNavStatArray& OutIndexBuffer, const FTransform& ComponentToWorld = FTransform::Identity); void GatherCollision(UBodySetup* RigidBody, UNavCollision* NavCollision); DECLARE_DELEGATE_ThreeParams(FNavLinkProcessorDelegate, FCompositeNavModifier*, const AActor*, const TArray&); DECLARE_DELEGATE_ThreeParams(FNavLinkSegmentProcessorDelegate, FCompositeNavModifier*, const AActor*, const TArray&); + DECLARE_DELEGATE_ThreeParams(FNavLinkProcessorDataDelegate, FCompositeNavModifier*, const FNavLinkOwnerData&, const TArray&); + DECLARE_DELEGATE_ThreeParams(FNavLinkSegmentProcessorDataDelegate, FCompositeNavModifier*, const FNavLinkOwnerData&, const TArray&); + /** Set new implementation of nav link processor, a function that will be * be used to process/transform links before adding them to CompositeModifier. * This function is supposed to be called once during the engine/game * setup phase. Not intended to be toggled at runtime */ - ENGINE_API void SetNavLinkProcessorDelegate(const FNavLinkProcessorDelegate& NewDelegate); - ENGINE_API void SetNavLinkSegmentProcessorDelegate(const FNavLinkSegmentProcessorDelegate& NewDelegate); + ENGINE_API void SetNavLinkProcessorDelegate(const FNavLinkProcessorDataDelegate& NewDelegate); + ENGINE_API void SetNavLinkSegmentProcessorDelegate(const FNavLinkSegmentProcessorDataDelegate& NewDelegate); /** called to do any necessary processing on NavLinks and put results in CompositeModifier */ ENGINE_API void ProcessNavLinkAndAppend(FCompositeNavModifier* OUT CompositeModifier, const AActor* Actor, const TArray& IN NavLinks); + ENGINE_API void ProcessNavLinkAndAppend(FCompositeNavModifier* OUT CompositeModifier, const FNavLinkOwnerData& OwnerData, const TArray& IN NavLinks); /** called to do any necessary processing on NavLinks and put results in CompositeModifier */ ENGINE_API void ProcessNavLinkSegmentAndAppend(FCompositeNavModifier* OUT CompositeModifier, const AActor* Actor, const TArray& IN NavLinks); + ENGINE_API void ProcessNavLinkSegmentAndAppend(FCompositeNavModifier* OUT CompositeModifier, const FNavLinkOwnerData& OwnerData, const TArray& IN NavLinks); - ENGINE_API void DefaultNavLinkProcessorImpl(FCompositeNavModifier* OUT CompositeModifier, const AActor* Actor, const TArray& IN NavLinks); - - ENGINE_API void DefaultNavLinkSegmentProcessorImpl(FCompositeNavModifier* OUT CompositeModifier, const AActor* Actor, const TArray& IN NavLinks); + ENGINE_API void DefaultNavLinkProcessorImpl(FCompositeNavModifier* OUT CompositeModifier, const FNavLinkOwnerData& OwnerData, const TArray& IN NavLinks); + ENGINE_API void DefaultNavLinkSegmentProcessorImpl(FCompositeNavModifier* OUT CompositeModifier, const FNavLinkOwnerData& OwnerData, const TArray& IN NavLinks); ENGINE_API bool IsBodyNavigationRelevant(const UBodySetup& IN BodySetup); + + // deprecated functions + DEPRECATED_FORGAME(4.17, "FNavLinkProcessorDelegate type is now deprecated, please use FNavLinkProcessorDataDelegate instead.") + ENGINE_API void SetNavLinkProcessorDelegate(const FNavLinkProcessorDelegate& NewDelegate); + + DEPRECATED_FORGAME(4.17, "FNavLinkSegmentProcessorDelegate type is now deprecated, please use FNavLinkSegmentProcessorDataDelegate instead.") + ENGINE_API void SetNavLinkSegmentProcessorDelegate(const FNavLinkSegmentProcessorDelegate& NewDelegate); + + DEPRECATED_FORGAME(4.17, "This function is now deprecated, please use override with OwnerData argument.") + ENGINE_API void DefaultNavLinkProcessorImpl(FCompositeNavModifier* OUT CompositeModifier, const AActor* Actor, const TArray& IN NavLinks); + + DEPRECATED_FORGAME(4.17, "This function is now deprecated, please use override with OwnerData argument.") + ENGINE_API void DefaultNavLinkSegmentProcessorImpl(FCompositeNavModifier* OUT CompositeModifier, const AActor* Actor, const TArray& IN NavLinks); } diff --git a/Engine/Source/Runtime/Engine/Public/ActiveSound.h b/Engine/Source/Runtime/Engine/Public/ActiveSound.h index 8e9faa3bae41..a96764b89081 100644 --- a/Engine/Source/Runtime/Engine/Public/ActiveSound.h +++ b/Engine/Source/Runtime/Engine/Public/ActiveSound.h @@ -180,7 +180,7 @@ private: class USoundBase* Sound; uint64 AudioComponentID; - uint64 AudioComponentUserID; + FName AudioComponentUserID; uint32 OwnerID; FName AudioComponentName; @@ -189,7 +189,7 @@ private: public: uint64 GetAudioComponentID() const { return AudioComponentID; } - uint64 GetAudioComponentUserID() const { return AudioComponentUserID; } + FName GetAudioComponentUserID() const { return AudioComponentUserID; } void SetAudioComponent(UAudioComponent* Component); FString GetAudioComponentName() const; FString GetOwnerName() const; diff --git a/Engine/Source/Runtime/Engine/Public/Animation/AnimCurveTypes.h b/Engine/Source/Runtime/Engine/Public/Animation/AnimCurveTypes.h index dc5f182001ae..ea693dab0ab0 100644 --- a/Engine/Source/Runtime/Engine/Public/Animation/AnimCurveTypes.h +++ b/Engine/Source/Runtime/Engine/Public/Animation/AnimCurveTypes.h @@ -40,7 +40,7 @@ struct ENGINE_API FAnimCurveParam { GENERATED_USTRUCT_BODY() - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = FAnimCurveParam) + UPROPERTY(EditAnywhere, Category = FAnimCurveParam) FName Name; // name UID for fast access diff --git a/Engine/Source/Runtime/Engine/Public/Animation/AnimSingleNodeInstanceProxy.h b/Engine/Source/Runtime/Engine/Public/Animation/AnimSingleNodeInstanceProxy.h index ad7a2a6b5844..629ebd5f94ef 100644 --- a/Engine/Source/Runtime/Engine/Public/Animation/AnimSingleNodeInstanceProxy.h +++ b/Engine/Source/Runtime/Engine/Public/Animation/AnimSingleNodeInstanceProxy.h @@ -16,8 +16,8 @@ struct FAnimSingleNodeInstanceProxy; * Local anim node for extensible processing. * Cant be used outside of this context as it has no graph node counterpart */ -USTRUCT() -struct FAnimNode_SingleNode : public FAnimNode_Base +USTRUCT(BlueprintInternalUseOnly) +struct ENGINE_API FAnimNode_SingleNode : public FAnimNode_Base { friend struct FAnimSingleNodeInstanceProxy; diff --git a/Engine/Source/Runtime/Engine/Public/Animation/AnimTypes.h b/Engine/Source/Runtime/Engine/Public/Animation/AnimTypes.h index 92f14679a52d..3b992ca85c1c 100644 --- a/Engine/Source/Runtime/Engine/Public/Animation/AnimTypes.h +++ b/Engine/Source/Runtime/Engine/Public/Animation/AnimTypes.h @@ -188,7 +188,7 @@ public: * Triggers an animation notify. Each AnimNotifyEvent contains an AnimNotify object * which has its Notify method called and passed to the animation. */ -USTRUCT() +USTRUCT(BlueprintType) struct FAnimNotifyEvent : public FAnimLinkableElement { GENERATED_USTRUCT_BODY() @@ -343,7 +343,7 @@ FORCEINLINE bool FAnimNotifyEvent::operator<(const FAnimNotifyEvent& Other) cons } } -USTRUCT() +USTRUCT(BlueprintType) struct FAnimSyncMarker { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/Engine/Public/Animation/CachedAnimData.h b/Engine/Source/Runtime/Engine/Public/Animation/CachedAnimData.h new file mode 100644 index 000000000000..7f5b0a0e66d8 --- /dev/null +++ b/Engine/Source/Runtime/Engine/Public/Animation/CachedAnimData.h @@ -0,0 +1,175 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "Animation/AnimInstance.h" +#include "CachedAnimData.generated.h" + +class UAnimInstance; + +/** + * This file contains a number of helper structures that can be used to process state-machine- + * related data in C++. This includes relevancy, state weights, animation time etc. + */ + +USTRUCT(BlueprintType) +struct ENGINE_API FCachedAnimStateData +{ + GENERATED_USTRUCT_BODY() + + FCachedAnimStateData() + : MachineIndex(INDEX_NONE) + , StateIndex(INDEX_NONE) + , bInitialized(false) + {} + + /** Name of StateMachine State is in */ + UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "State Machine") + FName StateMachineName; + + /** Name of State to Cache */ + UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "State Machine") + FName StateName; + + /** Did it find a matching StateMachine and State in the AnimGraph? */ + bool IsValid(UAnimInstance& InAnimInstance) const; + + /** Is the State Machine relevant? (Has any weight) */ + float IsMachineRelevant(UAnimInstance& InAnimInstance) const; + + /** Global weight of state in AnimGraph */ + float GetGlobalWeight(UAnimInstance& InAnimInstance) const; + + /** Local weight of state inside of state machine. */ + float GetWeight(UAnimInstance& InAnimInstance) const; + + /** Is State Full Weight? */ + bool IsFullWeight(UAnimInstance& InAnimInstance) const; + + /** Is State relevant? */ + bool IsRelevant(UAnimInstance& InAnimInstance) const; + +private: + mutable int32 MachineIndex; + mutable int32 StateIndex; + mutable bool bInitialized; +}; + +USTRUCT(BlueprintType) +struct ENGINE_API FCachedAnimStateArray +{ + GENERATED_USTRUCT_BODY() + + FCachedAnimStateArray() + : bCheckedValidity(false) + , bCachedIsValid(true) + {} + + /** Array of states */ + UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "State Machine") + TArray States; + + float GetTotalWeight(UAnimInstance& InAnimInstance) const; + bool IsFullWeight(UAnimInstance& InAnimInstance) const; + bool IsRelevant(UAnimInstance& InAnimInstance) const; + +private: + bool IsValid(UAnimInstance& InAnimInstance) const; + mutable bool bCheckedValidity; + mutable bool bCachedIsValid; +}; + +USTRUCT(BlueprintType) +struct ENGINE_API FCachedAnimAssetPlayerData +{ + GENERATED_USTRUCT_BODY() + + FCachedAnimAssetPlayerData() + : Index(INDEX_NONE) + , bInitialized(false) + {} + + /** Name of StateMachine State is in */ + UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "State Machine") + FName StateMachineName; + + /** Name of State to Cache */ + UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "State Machine") + FName StateName; + + float GetAssetPlayerTime(UAnimInstance& InAnimInstance) const; + + float GetAssetPlayerTimeRatio(UAnimInstance& InAnimInstance) const; + +private: + void CacheIndices(UAnimInstance& InAnimInstance) const; + + mutable int32 Index; + mutable bool bInitialized; +}; + +USTRUCT(BlueprintType) +struct ENGINE_API FCachedAnimRelevancyData +{ + GENERATED_USTRUCT_BODY() + + FCachedAnimRelevancyData() + : MachineIndex(INDEX_NONE) + , StateIndex(INDEX_NONE) + , bInitialized(false) + {} + + /** Name of StateMachine State is in */ + UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "State Machine") + FName StateMachineName; + + /** Name of State to Cache */ + UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "State Machine") + FName StateName; + + float GetRelevantAnimTime(UAnimInstance& InAnimInstance) const; + float GetRelevantAnimTimeRemaining(UAnimInstance& InAnimInstance) const; + float GetRelevantAnimTimeRemainingFraction(UAnimInstance& InAnimInstance) const; + +private: + void CacheIndices(UAnimInstance& InAnimInstance) const; + +private: + mutable int32 MachineIndex; + mutable int32 StateIndex; + mutable bool bInitialized; +}; + +USTRUCT(BlueprintType) +struct ENGINE_API FCachedAnimTransitionData +{ + GENERATED_USTRUCT_BODY() + + FCachedAnimTransitionData() + : MachineIndex(INDEX_NONE) + , TransitionIndex(INDEX_NONE) + , bInitialized(false) + {} + + /** Name of StateMachine State is in */ + UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "State Machine") + FName StateMachineName; + + /** Name of From State to Cache */ + UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "State Machine") + FName FromStateName; + + /** Name of To State to Cache */ + UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "State Machine") + FName ToStateName; + + float GetCrossfadeDuration(UAnimInstance& InAnimInstance) const; + +private: + void CacheIndices(UAnimInstance& InAnimInstance) const; + +private: + mutable int32 MachineIndex; + mutable int32 TransitionIndex; + mutable bool bInitialized; +}; \ No newline at end of file diff --git a/Engine/Source/Runtime/Engine/Public/Animation/PreviewCollectionInterface.h b/Engine/Source/Runtime/Engine/Public/Animation/PreviewCollectionInterface.h new file mode 100644 index 000000000000..9264234a2101 --- /dev/null +++ b/Engine/Source/Runtime/Engine/Public/Animation/PreviewCollectionInterface.h @@ -0,0 +1,26 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "UObject/Object.h" +#include "Interface.h" +#include "PreviewCollectionInterface.generated.h" + +class USkeletalMesh; + +UINTERFACE(meta = (CannotImplementInterfaceInBlueprint)) +class ENGINE_API UPreviewCollectionInterface : public UInterface +{ + GENERATED_UINTERFACE_BODY() +}; + +/** Preview Collection options. If you have native UDataAsset class that implements this, you can preview all in the animation editor using Additional Mesh section */ +class ENGINE_API IPreviewCollectionInterface +{ + GENERATED_IINTERFACE_BODY() + + /** Returns nodes that needs for them to map */ + virtual void GetPreviewSkeletalMeshes(TArray& OutList) const = 0; +}; \ No newline at end of file diff --git a/Engine/Source/Runtime/Engine/Public/AnimationRuntime.h b/Engine/Source/Runtime/Engine/Public/AnimationRuntime.h index 3c3552d22061..b0b24c603463 100644 --- a/Engine/Source/Runtime/Engine/Public/AnimationRuntime.h +++ b/Engine/Source/Runtime/Engine/Public/AnimationRuntime.h @@ -37,10 +37,7 @@ namespace ETransformBlendMode } template -void BlendTransform(const FTransform& Source, FTransform& Dest, const float BlendWeight) -{ - check(false); /// should never call this -} +FORCEINLINE void BlendTransform(const FTransform& Source, FTransform& Dest, const float BlendWeight); template<> FORCEINLINE void BlendTransform(const FTransform& Source, FTransform& Dest, const float BlendWeight) diff --git a/Engine/Source/Runtime/Engine/Public/AnimationUtils.h b/Engine/Source/Runtime/Engine/Public/AnimationUtils.h index 5bfc20d01bb8..618cf00c00cc 100644 --- a/Engine/Source/Runtime/Engine/Public/AnimationUtils.h +++ b/Engine/Source/Runtime/Engine/Public/AnimationUtils.h @@ -104,9 +104,6 @@ enum EConvertToAdditive CTA_MAX // Always last one }; -/** Control animation recompression upon load. */ -extern ENGINE_API bool GDisableAnimationRecompression; - /** * A collection of useful functions for skeletal mesh animation. */ diff --git a/Engine/Source/Runtime/Engine/Public/Audio.h b/Engine/Source/Runtime/Engine/Public/Audio.h index bd2d18c3b7ca..e7d3eecc13be 100644 --- a/Engine/Source/Runtime/Engine/Public/Audio.h +++ b/Engine/Source/Runtime/Engine/Public/Audio.h @@ -57,8 +57,6 @@ ENGINE_API DECLARE_LOG_CATEGORY_EXTERN(LogAudioDebug, Display, All); #define DEFAULT_SUBTITLE_PRIORITY 10000.0f -#define AUDIO_SAMPLE_RATE 48000 - /** * Some filters don't work properly with extreme values, so these are the limits */ @@ -346,8 +344,6 @@ struct ENGINE_API FWaveInstance float AttenuationFilterFrequency; /** Current pitch */ float Pitch; - /** Current velocity */ - FVector Velocity; /** Current location */ FVector Location; /** At what distance we start transforming into omnidirectional soundsource */ diff --git a/Engine/Source/Runtime/Engine/Public/AudioDecompress.h b/Engine/Source/Runtime/Engine/Public/AudioDecompress.h index 54ca7fa6fcf6..588a5cb7e1dd 100644 --- a/Engine/Source/Runtime/Engine/Public/AudioDecompress.h +++ b/Engine/Source/Runtime/Engine/Public/AudioDecompress.h @@ -238,6 +238,8 @@ protected: USoundWave* StreamingSoundWave; /** The current chunk index in the streamed chunks. */ int32 CurrentChunkIndex; + /** Whether or not to print the chunk fail message. */ + bool bPrintChunkFailMessage; }; diff --git a/Engine/Source/Runtime/Engine/Public/AudioDevice.h b/Engine/Source/Runtime/Engine/Public/AudioDevice.h index 012d9215a62b..bf862ba3d2ab 100644 --- a/Engine/Source/Runtime/Engine/Public/AudioDevice.h +++ b/Engine/Source/Runtime/Engine/Public/AudioDevice.h @@ -12,6 +12,7 @@ #include "Sound/AudioVolume.h" #include "Sound/SoundConcurrency.h" #include "Sound/SoundMix.h" +#include "Sound/AudioSettings.h" #include "AudioDeviceManager.h" #include "EngineGlobals.h" @@ -919,6 +920,29 @@ public: /** Whether or not HRTF spatialization is enabled for all. */ bool IsHRTFEnabledForAll() const; + void SetHRTFEnabledForAll(bool InbHRTFEnabledForAll) + { + const bool bNewHRTFEnabledForAll = InbHRTFEnabledForAll; + + bHRTFEnabledForAll_OnGameThread = bNewHRTFEnabledForAll; + + FAudioDevice* AudioDevice = this; + FAudioThread::RunCommandOnAudioThread([AudioDevice, bNewHRTFEnabledForAll]() + { + AudioDevice->bHRTFEnabledForAll = bNewHRTFEnabledForAll; + + }); + } + + void SetSpatializationInterfaceEnabled(bool InbSpatializationInterfaceEnabled) + { + FAudioThread::SuspendAudioThread(); + + bSpatializationInterfaceEnabled = InbSpatializationInterfaceEnabled; + + FAudioThread::ResumeAudioThread(); + } + bool IsAudioDeviceMuted() const; void SetDeviceMuted(bool bMuted); @@ -994,7 +1018,7 @@ public: float GetSampleRate() const { return SampleRate; } /** Returns the buffer length of the audio device. */ - int32 GetBufferLength() const { return DeviceOutputBufferLength; } + int32 GetBufferLength() const { return PlatformSettings.CallbackBufferFrameSize; } /** Whether or not there's a spatialization plugin enabled. */ bool IsSpatializationPluginEnabled() const @@ -1167,6 +1191,9 @@ private: return Adjuster * InterpValue + 1.0f - InterpValue; } + /** Allow platforms to optionally specify low-level audio platform settings. */ + virtual FAudioPlatformSettings GetPlatformSettings() const { return FAudioPlatformSettings(); } + public: /** @@ -1331,14 +1358,11 @@ public: /** The maximum number of concurrent audible sounds */ int32 MaxChannels; - /** The number of worker threads to use to process sources. (audio mixer feature) */ - int32 NumSourceWorkers; - - /** The sample rate of the audio device */ + /** The sample rate of all the audio devices */ int32 SampleRate; - /** The length of output callback buffer */ - int32 DeviceOutputBufferLength; + /** The platform specific audio settings. */ + FAudioPlatformSettings PlatformSettings; /** The length of output callback buffer */ @@ -1535,6 +1559,7 @@ class IAudioDeviceModule : public IModuleInterface public: /** Creates a new instance of the audio device implemented by the module. */ + virtual bool IsAudioMixerModule() const { return false; } virtual FAudioDevice* CreateAudioDevice() = 0; }; diff --git a/Engine/Source/Runtime/Engine/Public/AudioStreaming.h b/Engine/Source/Runtime/Engine/Public/AudioStreaming.h index b87124f7c115..8f3dd23db301 100644 --- a/Engine/Source/Runtime/Engine/Public/AudioStreaming.h +++ b/Engine/Source/Runtime/Engine/Public/AudioStreaming.h @@ -9,6 +9,7 @@ AudioStreaming.h: Definitions of classes used for audio streaming. #include "CoreMinimal.h" #include "HAL/ThreadSafeCounter.h" #include "Containers/IndirectArray.h" +#include "Containers/Queue.h" #include "Stats/Stats.h" #include "ContentStreaming.h" #include "Async/AsyncWork.h" @@ -16,6 +17,7 @@ AudioStreaming.h: Definitions of classes used for audio streaming. class FSoundSource; class USoundWave; +struct FAudioStreamingManager; struct FWaveInstance; /** Lists possible states used by Thread-safe counter. */ @@ -108,6 +110,11 @@ struct FLoadedAudioChunk , Index(0) { } + + ~FLoadedAudioChunk() + { + checkf(Data == nullptr, TEXT("Audio chunk Data ptr not null (%p), DataSize: %d"), Data, DataSize); + } }; /** @@ -123,7 +130,7 @@ struct FStreamingWaveData final * * @param SoundWave The SoundWave we are managing */ - void Initialize(USoundWave* SoundWave); + void Initialize(USoundWave* SoundWave, FAudioStreamingManager* InStreamingManager); /** * Updates the streaming status of the sound wave and performs finalization when appropriate. The function returns @@ -177,7 +184,8 @@ private: FStreamingWaveData(const FStreamingWaveData& that); FStreamingWaveData& operator=(FStreamingWaveData const&); - FLoadedAudioChunk* AddNewLoadedChunk(int32 ChunkSize); + // Creates a new chunk, returns the chunk index + int32 AddNewLoadedChunk(int32 ChunkSize); void FreeLoadedChunk(FLoadedAudioChunk& LoadedChunk); public: @@ -202,8 +210,31 @@ public: /** Pending async derived data streaming tasks */ TIndirectArray PendingAsyncStreamDerivedChunkTasks; #endif // #if WITH_EDITORONLY_DATA + + /** Ptr to owning audio streaming manager. */ + FAudioStreamingManager* AudioStreamingManager; }; +/** Struct used to store results of an async file load. */ +struct FASyncAudioChunkLoadResult +{ + // Place to safely copy the ptr of a loaded audio chunk when load result is finished + uint8* DataResults; + + // Actual storage of the loaded audio chunk, will be filled on audio thread. + FStreamingWaveData* StreamingWaveData; + + // Loaded audio chunk index + int32 LoadedAudioChunkIndex; + + FASyncAudioChunkLoadResult() + : DataResults(nullptr) + , StreamingWaveData(nullptr) + , LoadedAudioChunkIndex(INDEX_NONE) + {} +}; + + /** * Streaming manager dealing with audio. */ @@ -236,7 +267,14 @@ struct FAudioStreamingManager : public IAudioStreamingManager virtual const uint8* GetLoadedChunk(const USoundWave* SoundWave, uint32 ChunkIndex, uint32* OutChunkSize = NULL) const override; // End IAudioStreamingManager interface + /** Called when an async callback is made on an async loading audio chunk request. */ + void OnAsyncFileCallback(FStreamingWaveData* StreamingWaveData, int32 LoadedAudioChunkIndex, IAsyncReadRequest* ReadRequest); + + /** Processes pending async file IO results. */ + void ProcessPendingAsyncFileResults(); + protected: + /** * Gets Wave request associated with a specific wave * @@ -253,4 +291,10 @@ protected: /** Map of requests to make next time sound waves are ready */ TMap WaveRequests; + + /** Results of async loading audio chunks. */ + TQueue AsyncAudioStreamChunkResults; + + /** Critical section to protect usage of shared gamethread/audiothread members */ + mutable FCriticalSection CriticalSection; }; diff --git a/Engine/Source/Runtime/Engine/Public/BatchedElements.h b/Engine/Source/Runtime/Engine/Public/BatchedElements.h index 8d0418a27a7d..7807897ccb12 100644 --- a/Engine/Source/Runtime/Engine/Public/BatchedElements.h +++ b/Engine/Source/Runtime/Engine/Public/BatchedElements.h @@ -16,6 +16,7 @@ #include "StaticBoundShaderState.h" struct FBatchedPoint; +struct FDrawingPolicyRenderState; namespace EBlendModeFilter { @@ -203,7 +204,7 @@ public: * @param DepthTexture DepthTexture for manual depth testing with editor compositing in the pixel shader */ DEPRECATED(4.14, "Deprecated. Use the FBatchedElements::Draw method that takes a non-optional FSceneView parameter instead") - bool Draw(FRHICommandList& RHICmdList, const struct FDrawingPolicyRenderState& DrawRenderState, ERHIFeatureLevel::Type FeatureLevel, bool bNeedToSwitchVerticalAxis, const FMatrix& Transform, uint32 ViewportSizeX, uint32 ViewportSizeY, bool bHitTesting, float Gamma = 1.0f, const FSceneView* View = NULL, FTexture2DRHIRef DepthTexture = FTexture2DRHIRef(), EBlendModeFilter::Type Filter = EBlendModeFilter::All) const; + bool Draw(FRHICommandList& RHICmdList, const FDrawingPolicyRenderState& DrawRenderState, ERHIFeatureLevel::Type FeatureLevel, bool bNeedToSwitchVerticalAxis, const FMatrix& Transform, uint32 ViewportSizeX, uint32 ViewportSizeY, bool bHitTesting, float Gamma = 1.0f, const FSceneView* View = nullptr, FTexture2DRHIRef DepthTexture = FTexture2DRHIRef(), EBlendModeFilter::Type Filter = EBlendModeFilter::All) const; /** * Draws the batch @@ -213,7 +214,7 @@ public: * @param Gamma Optional gamma override * @param DepthTexture DepthTexture for manual depth testing with editor compositing in the pixel shader */ - bool Draw(FRHICommandList& RHICmdList, const struct FDrawingPolicyRenderState& DrawRenderState, ERHIFeatureLevel::Type FeatureLevel, bool bNeedToSwitchVerticalAxis, const FSceneView& View, bool bHitTesting, float Gamma = 1.0f, FTexture2DRHIRef DepthTexture = FTexture2DRHIRef(), EBlendModeFilter::Type Filter = EBlendModeFilter::All) const; + bool Draw(FRHICommandList& RHICmdList, const FDrawingPolicyRenderState& DrawRenderState, ERHIFeatureLevel::Type FeatureLevel, bool bNeedToSwitchVerticalAxis, const FSceneView& View, bool bHitTesting, float Gamma = 1.0f, FTexture2DRHIRef DepthTexture = FTexture2DRHIRef(), EBlendModeFilter::Type Filter = EBlendModeFilter::All) const; /** * Creates a proxy FSceneView for operations that are not tied directly to a scene but still require batched elements to be drawn. diff --git a/Engine/Source/Runtime/Engine/Public/BlendableManager.h b/Engine/Source/Runtime/Engine/Public/BlendableManager.h index 996988bd4667..75900b5c125d 100644 --- a/Engine/Source/Runtime/Engine/Public/BlendableManager.h +++ b/Engine/Source/Runtime/Engine/Public/BlendableManager.h @@ -45,7 +45,7 @@ public: FName BlendableType = T::GetFName(); // at least 4 byte alignment - uint32 Alignment = FMath::Max((uint32)4, (uint32)ALIGNOF(T)); + uint32 Alignment = FMath::Max((uint32)4, (uint32)alignof(T)); FBlendableEntry* Entry = PushBlendableDataPtr(InWeight, BlendableType, (const uint8*)&InData, sizeof(T), Alignment); diff --git a/Engine/Source/Runtime/Engine/Public/BonePose.h b/Engine/Source/Runtime/Engine/Public/BonePose.h index 0148ac8b7b4e..3eb305b102a0 100644 --- a/Engine/Source/Runtime/Engine/Public/BonePose.h +++ b/Engine/Source/Runtime/Engine/Public/BonePose.h @@ -796,18 +796,21 @@ void FCSPose::ConvertToLocalPoses(PoseType& OutPose) const // that doesn't mean this local has to change // go from child to parent since I need parent inverse to go back to local // root is same, so no need to do Index == 0 - for (const BoneIndexType BoneIndex : Pose.ForEachBoneIndexReverse()) + const BoneIndexType RootBoneIndex(0); + if (ComponentSpaceFlags[RootBoneIndex]) { - if (!BoneIndex.IsRootBone()) - { - // root is already verified, so root should not come here - if (ComponentSpaceFlags[BoneIndex]) - { - const FCompactPoseBoneIndex ParentIndex = Pose.GetParentBoneIndex(BoneIndex); + OutPose[RootBoneIndex] = Pose[RootBoneIndex]; + } - OutPose[BoneIndex].SetToRelativeTransform(OutPose[ParentIndex]); - OutPose[BoneIndex].NormalizeRotation(); - } + const int32 NumBones = Pose.GetNumBones(); + for (int32 Index = NumBones - 1; Index > 0; Index--) + { + const BoneIndexType BoneIndex(Index); + if (ComponentSpaceFlags[BoneIndex]) + { + const BoneIndexType ParentIndex = Pose.GetParentBoneIndex(BoneIndex); + OutPose[BoneIndex].SetToRelativeTransform(OutPose[ParentIndex]); + OutPose[BoneIndex].NormalizeRotation(); } } } \ No newline at end of file diff --git a/Engine/Source/Runtime/Engine/Public/CanvasItem.h b/Engine/Source/Runtime/Engine/Public/CanvasItem.h index 4bd745184545..0d416e89e61d 100644 --- a/Engine/Source/Runtime/Engine/Public/CanvasItem.h +++ b/Engine/Source/Runtime/Engine/Public/CanvasItem.h @@ -37,6 +37,10 @@ public: , BatchedElementParameters( nullptr ) , Color( FLinearColor::White ) {}; + virtual ~FCanvasItem() + { + } + virtual void Draw( FCanvas* InCanvas ) = 0; /** diff --git a/Engine/Source/Runtime/Engine/Public/ChartCreation.h b/Engine/Source/Runtime/Engine/Public/ChartCreation.h index 5f6d2d1de712..17298d47b8e3 100644 --- a/Engine/Source/Runtime/Engine/Public/ChartCreation.h +++ b/Engine/Source/Runtime/Engine/Public/ChartCreation.h @@ -9,6 +9,7 @@ #include "CoreMinimal.h" #include "ProfilingDebugging/Histogram.h" +#include "Scalability.h" ////////////////////////////////////////////////////////////////////// @@ -138,6 +139,18 @@ public: public: FPerformanceTrackingChart(const FDateTime& InStartTime, const FString& InChartLabel); + double GetAverageFramerate() const + { + return FramerateHistogram.GetNumMeasurements() / FramerateHistogram.GetSumOfAllMeasures(); + } + + double GetPercentMissedVSync(int32 TargetFPS) const + { + const int64 TotalTargetFrames = TargetFPS * FramerateHistogram.GetSumOfAllMeasures(); + const int64 MissedFrames = FMath::Max(TotalTargetFrames - FramerateHistogram.GetNumMeasurements(), 0); + return ((MissedFrames * 100.0) / (double)TotalTargetFrames); + } + double GetAvgHitchesPerMinute() const { const double TotalTime = FramerateHistogram.GetSumOfAllMeasures(); @@ -154,6 +167,11 @@ public: return (TotalTime > 0.0) ? (TotalHitchFrameTime / TotalTime) : 0.0; } + int64 GetNumFrames() const + { + return FramerateHistogram.GetNumMeasurements(); + } + void ChangeLabel(const FString& NewLabel) { ChartLabel = NewLabel; @@ -162,7 +180,7 @@ public: void DumpFPSChart(const FString& InMapName); // Dumps the FPS chart information to an analytic event param array. - void DumpChartToAnalyticsParams(const FString& InMapName, TArray& InParamArray, bool bIncludeClientHWInfo); + void DumpChartToAnalyticsParams(const FString& InMapName, TArray& InParamArray, bool bIncludeClientHWInfo) const; // Dumps the FPS chart information to the log. @@ -279,3 +297,62 @@ private: /** Keep track of the last time we saw a hitch (used to suppress knock on hitches for a short period) */ double LastHitchTime; }; + +////////////////////////////////////////////////////////////////////// + +// Prints the FPS chart summary to an endpoint +struct ENGINE_API FDumpFPSChartToEndpoint +{ +protected: + const FPerformanceTrackingChart& Chart; + +public: + /** + * Dumps a chart, allowing subclasses to format the data in their own way via various protected virtuals to be overridden + */ + void DumpChart(double InWallClockTimeFromStartOfCharting, const FString& InMapName); + + FDumpFPSChartToEndpoint(const FPerformanceTrackingChart& InChart) + : Chart(InChart) + { + } + + virtual ~FDumpFPSChartToEndpoint() { } + +protected: + double TotalTime; + double WallClockTimeFromStartOfCharting; // This can be much larger than TotalTime if the chart was paused or long frames were omitted + int32 NumFrames; + FString MapName; + + float AvgFPS; + float TimeDisregarded; + float AvgGPUFrameTime; + + float BoundGameThreadPct; + float BoundRenderThreadPct; + float BoundGPUPct; + + Scalability::FQualityLevels ScalabilityQuality; + FString OSMajor; + FString OSMinor; + + FString CPUVendor; + FString CPUBrand; + + // The primary GPU for the desktop (may not be the one we ended up using, e.g., in an optimus laptop) + FString DesktopGPUBrand; + + // The actual GPU adapter we initialized + FString ActualGPUBrand; + +protected: + virtual void PrintToEndpoint(const FString& Text) = 0; + + virtual void FillOutMemberStats(); + virtual void HandleFPSBucket(float BucketTimePercentage, float BucketFramePercentage, double StartFPS, double EndFPS); + virtual void HandleHitchBucket(const FHistogram& HitchHistogram, int32 BucketIndex); + virtual void HandleHitchSummary(int32 TotalHitchCount, double TotalTimeSpentInHitchBuckets); + virtual void HandleFPSThreshold(int32 TargetFPS, int32 NumFramesBelow, float PctTimeAbove, float PctMissedFrames); + virtual void HandleBasicStats(); +}; diff --git a/Engine/Source/Runtime/Engine/Public/Collision.h b/Engine/Source/Runtime/Engine/Public/Collision.h index 06c0c1f552fb..c6454cec52e6 100644 --- a/Engine/Source/Runtime/Engine/Public/Collision.h +++ b/Engine/Source/Runtime/Engine/Public/Collision.h @@ -14,14 +14,13 @@ /** * Collision stats */ +DECLARE_CYCLE_STAT_EXTERN(TEXT("SceneQueryTotal"), STAT_Collision_SceneQueryTotal, STATGROUP_Collision, ); DECLARE_CYCLE_STAT_EXTERN(TEXT("RaycastAny"),STAT_Collision_RaycastAny,STATGROUP_Collision, ); DECLARE_CYCLE_STAT_EXTERN(TEXT("RaycastSingle"),STAT_Collision_RaycastSingle,STATGROUP_Collision, ); DECLARE_CYCLE_STAT_EXTERN(TEXT("RaycastMultiple"),STAT_Collision_RaycastMultiple,STATGROUP_Collision, ); DECLARE_CYCLE_STAT_EXTERN(TEXT("GeomSweepAny"),STAT_Collision_GeomSweepAny,STATGROUP_Collision, ); DECLARE_CYCLE_STAT_EXTERN(TEXT("GeomSweepSingle"),STAT_Collision_GeomSweepSingle,STATGROUP_Collision, ); DECLARE_CYCLE_STAT_EXTERN(TEXT("GeomSweepMultiple"),STAT_Collision_GeomSweepMultiple,STATGROUP_Collision, ); -DECLARE_CYCLE_STAT_EXTERN(TEXT("GeomOverlapAny"),STAT_Collision_GeomOverlapAny,STATGROUP_Collision, ); -DECLARE_CYCLE_STAT_EXTERN(TEXT("GeomOverlapSingle"),STAT_Collision_GeomOverlapSingle,STATGROUP_Collision, ); DECLARE_CYCLE_STAT_EXTERN(TEXT("GeomOverlapMultiple"),STAT_Collision_GeomOverlapMultiple,STATGROUP_Collision, ); DECLARE_CYCLE_STAT_EXTERN(TEXT("BodyInstanceOverlapMulti"), STAT_Collision_FBodyInstance_OverlapMulti, STATGROUP_Collision, ); DECLARE_CYCLE_STAT_EXTERN(TEXT("BodyInstanceOverlapTest"), STAT_Collision_FBodyInstance_OverlapTest, STATGROUP_Collision, ); diff --git a/Engine/Source/Runtime/Engine/Public/CollisionQueryParams.h b/Engine/Source/Runtime/Engine/Public/CollisionQueryParams.h index 50cfd58e1769..191e6442e4d1 100644 --- a/Engine/Source/Runtime/Engine/Public/CollisionQueryParams.h +++ b/Engine/Source/Runtime/Engine/Public/CollisionQueryParams.h @@ -22,6 +22,14 @@ enum class EQueryMobilityType Dynamic //Any shape that is considered dynamic by physx (movable/stationary mobility) }; +/** Set to 1 so the compiler can find all QueryParams that don't take in a stat id. + * Note this will not include any queries taking a default SceneQuery param + */ +#define FIND_UNKNOWN_SCENE_QUERIES 0 +#define SCENE_QUERY_STAT_ONLY(QueryName) QUICK_USE_CYCLE_STAT(QueryName, STATGROUP_CollisionTags) +#define SCENE_QUERY_STAT_NAME_ONLY(QueryName) [](){ static FName StaticName(#QueryName); return StaticName;}() +#define SCENE_QUERY_STAT(QueryName) SCENE_QUERY_STAT_NAME_ONLY(QueryName), SCENE_QUERY_STAT_ONLY(QueryName) + /** Structure that defines parameters passed into collision function */ struct ENGINE_API FCollisionQueryParams { @@ -64,6 +72,14 @@ struct ENGINE_API FCollisionQueryParams /** Extra filtering done on the query. See declaration for filtering logic */ FMaskFilter IgnoreMask; + /** StatId used for profiling individual expensive scene queries */ + TStatId StatId; + + static FORCEINLINE TStatId GetUnknownStatId() + { + RETURN_QUICK_DECLARE_CYCLE_STAT(UnknownSceneQuery, STATGROUP_Collision); + } + private: /** Tracks whether the IgnoreComponents list is verified unique. */ @@ -102,7 +118,7 @@ public: void SetNumIgnoredComponents(int32 NewNum); // Constructors - +#if !FIND_UNKNOWN_SCENE_QUERIES /** * DEPRECATED! * Please instead provide a FName parameter when constructing a FCollisionQueryParams object which will use the other constructor. @@ -124,6 +140,7 @@ public: IgnoreMask = 0; bIgnoreBlocks = false; bIgnoreTouches = false; + StatId = GetUnknownStatId(); } FCollisionQueryParams() @@ -139,11 +156,17 @@ public: IgnoreMask = 0; bIgnoreBlocks = false; bIgnoreTouches = false; + StatId = GetUnknownStatId(); } + FCollisionQueryParams(FName InTraceTag, bool bInTraceComplex=false, const AActor* InIgnoreActor=NULL) + : FCollisionQueryParams(InTraceTag, GetUnknownStatId(), bInTraceComplex, InIgnoreActor) + { + } +#endif - FCollisionQueryParams(FName InTraceTag, bool bInTraceComplex=false, const AActor* InIgnoreActor=NULL); + FCollisionQueryParams(FName InTraceTag, const TStatId& InStatId, bool bInTraceComplex = false, const AActor* InIgnoreActor = NULL); // Utils @@ -186,13 +209,20 @@ public: /** Structure when performing a collision query using a component's geometry */ struct ENGINE_API FComponentQueryParams : public FCollisionQueryParams { - FComponentQueryParams() - : FCollisionQueryParams(NAME_None,false) +#if !FIND_UNKNOWN_SCENE_QUERIES + FComponentQueryParams() + : FCollisionQueryParams(NAME_None, FCollisionQueryParams::GetUnknownStatId(),false) { } FComponentQueryParams(FName InTraceTag, const AActor* InIgnoreActor=NULL) - : FCollisionQueryParams(InTraceTag, false, InIgnoreActor) + : FComponentQueryParams(InTraceTag, GetUnknownStatId(), InIgnoreActor) + { + } +#endif + + FComponentQueryParams(FName InTraceTag, const TStatId& InStatId, const AActor* InIgnoreActor = NULL) + : FCollisionQueryParams(InTraceTag, InStatId, false, InIgnoreActor) { } diff --git a/Engine/Source/Runtime/Engine/Public/ComponentInstanceDataCache.h b/Engine/Source/Runtime/Engine/Public/ComponentInstanceDataCache.h index 8c731c220be8..496f1154c82f 100644 --- a/Engine/Source/Runtime/Engine/Public/ComponentInstanceDataCache.h +++ b/Engine/Source/Runtime/Engine/Public/ComponentInstanceDataCache.h @@ -54,6 +54,7 @@ protected: EComponentCreationMethod SourceComponentCreationMethod; TArray SavedProperties; + TArray InstancedObjects; }; /** diff --git a/Engine/Source/Runtime/Engine/Public/Components.h b/Engine/Source/Runtime/Engine/Public/Components.h index 76791e835252..8bda9d9f57e7 100644 --- a/Engine/Source/Runtime/Engine/Public/Components.h +++ b/Engine/Source/Runtime/Engine/Public/Components.h @@ -30,7 +30,7 @@ struct FStaticMeshBuildVertex /** The world size for each texcoord mapping. Used by the texture streaming. */ -USTRUCT() +USTRUCT(BlueprintType) struct FMeshUVChannelInfo { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/Engine/Public/CsvProfiler.h b/Engine/Source/Runtime/Engine/Public/CsvProfiler.h new file mode 100644 index 000000000000..464c8b9a0250 --- /dev/null +++ b/Engine/Source/Runtime/Engine/Public/CsvProfiler.h @@ -0,0 +1,96 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +/** +* +* A lightweight single-threaded CSV profiler which can be used for profiling in Test/Shipping builds +*/ + +#pragma once + +#include "Modules/ModuleInterface.h" +#include "Modules/ModuleManager.h" +#include "CoreTypes.h" +#include "CoreMinimal.h" + +#define CSV_PROFILER (WITH_ENGINE && !UE_BUILD_SHIPPING) + +#if CSV_PROFILER + #define CSV_SCOPED_STAT(StatName) FScopedCsvStat ScopedStat_ ## StatName (#StatName); + #define CSV_CUSTOM_STAT(StatName,Value) FCsvProfiler::Get()->RecordCustomStat(#StatName, Value) +#else + #define CSV_SCOPED_STAT(StatName) + #define CSV_CUSTOM_STAT(StatName,Value) +#endif + +#if CSV_PROFILER +class FCsvProfilerFrame; +class FCsvProfilerThread; + +/** +* FCsvProfiler class. This manages recording and reporting all for CSV stats +*/ +class FCsvProfiler +{ +private: + static FCsvProfiler* Instance; + FCsvProfiler(); +public: + static ENGINE_API FCsvProfiler* Get(); + + ENGINE_API void Init(); + + /** Push/pop events */ + ENGINE_API void BeginStat(const char * StatName); + ENGINE_API void EndStat(const char * StatName); + + ENGINE_API void RecordCustomStat(const char * StatName, float Value); + + /** Per-frame update */ + void BeginFrame(); + void EndFrame(); + + /** Begin/End Capture */ + void BeginCapture(int InNumFramesToCapture = -1); + void EndCapture(); + + /** Final cleanup */ + void Release(); + +private: + /** Renderthread begin/end frame */ + void BeginFrameRT(); + void EndFrameRT(); + + void WriteCaptureToFile(); + FCsvProfilerThread* GetProfilerThread(); + + int32 NumFramesToCapture; + int32 CaptureFrameNumber; + bool bRequestStartCapture; + bool bRequestStopCapture; + volatile bool bCapturing; + uint64 LastEndFrameTimestamp; + + FCriticalSection GetResultsLock; + TArray ProfilerThreads; + TArray FrameBeginTimestamps; + TArray FrameBeginTimestampsRT; + +}; + +class FScopedCsvStat +{ +public: + FScopedCsvStat(const char * InStatName) + : StatName(InStatName) + { + FCsvProfiler::Get()->BeginStat(StatName); + } + + ~FScopedCsvStat() + { + FCsvProfiler::Get()->EndStat(StatName); + } + const char * StatName; +}; +#endif //CSV_PROFILER \ No newline at end of file diff --git a/Engine/Source/Runtime/Engine/Public/DrawDebugHelpers.h b/Engine/Source/Runtime/Engine/Public/DrawDebugHelpers.h index 83a1d621213f..e4831fd3fdf6 100644 --- a/Engine/Source/Runtime/Engine/Public/DrawDebugHelpers.h +++ b/Engine/Source/Runtime/Engine/Public/DrawDebugHelpers.h @@ -82,6 +82,7 @@ ENGINE_API void DrawDebugFloatHistory(UWorld const & WorldRef, FDebugFloatHistor ENGINE_API void DrawDebugCanvas2DLine(UCanvas* Canvas, const FVector& Start, const FVector& End, const FLinearColor& LineColor); ENGINE_API void DrawDebugCanvas2DLine(UCanvas* Canvas, const FVector2D& StartPosition, const FVector2D& EndPosition, const FLinearColor& LineColor, const float& LineThickness = 1.f); ENGINE_API void DrawDebugCanvas2DCircle(UCanvas* Canvas, const FVector2D& Center, float Radius, int32 NumSides, const FLinearColor& LineColor, const float& LineThickness = 1.f); +ENGINE_API void DrawDebugCanvas2DBox(UCanvas* Canvas, const FBox2D& Box, const FLinearColor& LineColor, const float& LineThickness = 1.f); /** @@ -166,6 +167,7 @@ FORCEINLINE void DrawDebugFloatHistory(UWorld const & WorldRef, FDebugFloatHisto FORCEINLINE void DrawDebugCanvas2DLine(UCanvas* Canvas, const FVector& Start, const FVector& End, const FLinearColor& LineColor) {} FORCEINLINE void DrawDebugCanvas2DLine(UCanvas* Canvas, const FVector2D& StartPosition, const FVector2D& EndPosition, const FLinearColor& LineColor, const float& LineThickness = 1.f) {} FORCEINLINE void DrawDebugCanvas2DCircle(UCanvas* Canvas, const FVector2D& Center, float Radius, int32 NumSides, const FLinearColor& LineColor, const float& LineThickness = 1.f) {} +FORCEINLINE void DrawDebugCanvas2DBox(UCanvas* Canvas, const FBox2D& Box, const FLinearColor& LineColor, const float& LineThickness = 1.f) {} FORCEINLINE void DrawDebugCanvasLine(UCanvas* Canvas, const FVector& Start, const FVector& End, const FLinearColor& LineColor) {} FORCEINLINE void DrawDebugCanvasCircle(UCanvas* Canvas, const FVector& Base, const FVector& X, const FVector& Y, FColor Color, float Radius, int32 NumSides) {} FORCEINLINE void DrawDebugCanvasWireSphere(UCanvas* Canvas, const FVector& Base, FColor Color, float Radius, int32 NumSides) {} diff --git a/Engine/Source/Runtime/Engine/Public/EngineSharedPCH.h b/Engine/Source/Runtime/Engine/Public/EngineSharedPCH.h index ec7ae24c9d75..259131de0b26 100644 --- a/Engine/Source/Runtime/Engine/Public/EngineSharedPCH.h +++ b/Engine/Source/Runtime/Engine/Public/EngineSharedPCH.h @@ -34,7 +34,6 @@ #include "Templates/EnableIf.h" #include "Templates/RemoveReference.h" #include "Templates/TypeCompatibleBytes.h" -#include "Templates/AlignOf.h" #include "Templates/ChooseClass.h" #include "Templates/IntegralConstant.h" #include "Templates/IsClass.h" @@ -418,7 +417,6 @@ #include "Framework/Commands/UICommandList.h" #include "Framework/Application/SlateApplication.h" #include "Framework/Application/MenuStack.h" -#include "Runtime/Slate/Private/Framework/Application/Menu.h" #include "Widgets/Layout/SBox.h" #include "Widgets/Layout/SScrollBar.h" #include "Framework/Layout/InertialScrollManager.h" @@ -463,7 +461,6 @@ // From AssetRegistry: #include "AssetData.h" -#include "SharedMapView.h" // From PacketHandler: #include "PacketHandler.h" diff --git a/Engine/Source/Runtime/Engine/Public/FXSystem.h b/Engine/Source/Runtime/Engine/Public/FXSystem.h index 1d1ac47254a9..115e83de8a00 100644 --- a/Engine/Source/Runtime/Engine/Public/FXSystem.h +++ b/Engine/Source/Runtime/Engine/Public/FXSystem.h @@ -79,6 +79,8 @@ namespace FXConsoleVariables extern float GPUCollisionDepthBounds; /** Specify a sorting test to run. */ extern TAutoConsoleVariable TestGPUSort; + /** true if GPU particles are allowed. */ + extern int32 bAllowGPUParticles; } /** @@ -99,7 +101,8 @@ inline bool SupportsGPUParticles(EShaderPlatform Platform) // RHI on the current hardware is able to support GPU particles. inline bool RHISupportsGPUParticles() { - return GSupportsMultipleRenderTargets + return FXConsoleVariables::bAllowGPUParticles + && GSupportsMultipleRenderTargets && GSupportsWideMRT && GPixelFormats[PF_G32R32F].Supported && GSupportsTexture3D diff --git a/Engine/Source/Runtime/Engine/Public/Features/ILiveStreamingService.h b/Engine/Source/Runtime/Engine/Public/Features/ILiveStreamingService.h deleted file mode 100644 index c9debd7a509e..000000000000 --- a/Engine/Source/Runtime/Engine/Public/Features/ILiveStreamingService.h +++ /dev/null @@ -1,335 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "CoreMinimal.h" -#include "Features/IModularFeature.h" - -/** - * Contains information about the status of the live streaming service. This is passed along to a user's - * function through the FLiveStreamingStatusCallback delegate - */ -struct FLiveStreamingStatus -{ - /** Types of statuses */ - enum class EStatusType - { - /** An error of some sort */ - Failure, - - /** Progress message while we're getting setup to stream, such as login state */ - Progress, - - /** Success message that streaming is now live */ - BroadcastStarted, - - /** Sent when broadcasting stops */ - BroadcastStopped, - - /** Web cam is now active */ - WebCamStarted, - - /** Web cam is stopped */ - WebCamStopped, - - /** Web cam texture is ready (now safe to call GetWebCamTexture()) */ - WebCamTextureReady, - - /** Web cam texture is no longer valid (GetWebCamTexture() will return null) */ - WebCamTextureNotReady, - - /** Connected to chat server. You can now send messages! */ - ChatConnected, - - /** Disconnected from chat */ - ChatDisconnected, - }; - - /** Status type */ - EStatusType StatusType; - - /** Customized description of the current status from the live streaming service. This string may include - extra detail about the service's status, specific to that streaming system. Unless the status is - an error condition, this text should be brief enough that it can be displayed as an editor notification.*/ - FText CustomStatusDescription; -}; - - - -/** - * Defines parameters for initiating a new broadcast. Keep in mind that different live streaming services have - * different restrictions on streaming buffer size and formats - */ -struct FBroadcastConfig -{ - /** Login user name, used only for direct authentication with a broadcasting end-point */ - FString LoginUserName; - - /** Login password, used only for direct authentication with a broadcasting end-point */ - FString LoginPassword; - - /** Width of the streaming buffer. If this changes, you'll need to stop and restart broadcasting. Note that some streaming services - require the Width to be a multiple of 32 (for SSE compression). Call MakeValidVideoBufferResolution() first to make sure it's valid. */ - int VideoBufferWidth; - - /** Height of the streaming buffer. If this changes, you'll need to stop and restart broadcasting. Note that some streaming services - require the height to be a multiple of 16 (for SSE compression). Call MakeValidVideoBufferResolution() first to make sure it's valid. */ - int VideoBufferHeight; - - /** Target frame rate of this broadcast */ - int FramesPerSecond; - - /** Defines the possible pixel formats the output streaming buffer can be in */ - enum class EBroadcastPixelFormat - { - /** Four bytes per pixel, red channel first, alpha last */ - R8G8B8A8, - - /** Four bytes per pixel, blue channel first, alpha last */ - B8G8R8A8, - - /** Four bytes per pixel, alpha first, blue channel last */ - A8R8G8B8, - - /** Four bytes per pixel, alpha first, red channel last */ - A8B8G8R8, - }; - - /** Desired pixel format for the buffer. */ - EBroadcastPixelFormat PixelFormat; - - /** True to capture output audio from the local computer */ - bool bCaptureAudioFromComputer; - - /** True to capture audio from the default microphone */ - bool bCaptureAudioFromMicrophone; - - - /** Default constructor */ - FBroadcastConfig() - : LoginUserName(), - LoginPassword(), - VideoBufferWidth( 1280 ), - VideoBufferHeight( 720 ), - FramesPerSecond( 30 ), - PixelFormat( EBroadcastPixelFormat::B8G8R8A8 ), - bCaptureAudioFromComputer( true ), - bCaptureAudioFromMicrophone( true ) - { - } -}; - - - -/** - * Defines parameters for displaying a live web cam over your broadcast - */ -struct FWebCamConfig -{ - /** Desired web cam capture resolution width. The web cam may only support a limited number of resolutions, so we'll - choose one that matches as closely to this as possible */ - int DesiredWebCamWidth; - - /** Desired web cam capture resolution height. */ - int DesiredWebCamHeight; - - - /** Default constructor */ - FWebCamConfig() - : DesiredWebCamWidth( 320 ), - DesiredWebCamHeight( 240 ) - { - } -}; - - - -/** - * Contains information about an existing live streaming game. Some services support querying for live broadcasts that - * are currently in progress - */ -struct FLiveStreamInfo -{ - /** Name of the game that is streaming */ - FString GameName; - - /** The title of the stream itself */ - FString StreamName; - - /** URL for the stream */ - FString URL; - - - /** Default constructor */ - FLiveStreamInfo() - { - } -}; - - -/** - * Generic interface to an implementation of a live streaming system, usually capable of capturing video and audio - * and streaming live content to the internet - */ -class ILiveStreamingService : public IModularFeature -{ - // @todo livestream: We should replace IDVRStreamingSystem with the new ILiveStreamingService, and update existing use cases (see FPS4PlatformFeaturesModule) - -public: - - DECLARE_MULTICAST_DELEGATE_OneParam( FOnStatusChanged, const FLiveStreamingStatus& ); - - /** Event to register with to find out when the status of the streaming system changes, such as when transitioning between - login phases, or a web cam becomes active */ - virtual FOnStatusChanged& OnStatusChanged() = 0; - - - /** - * Broadcasting - */ - - /** - * Called to start broadcasting video and audio. Note that the actual streaming may not begin immediately. - * - * @param Config Configuration for this broadcast. If you want to change this later, you'll need to stop and restart the broadcast. - */ - virtual void StartBroadcasting( const FBroadcastConfig& Config ) = 0; - - /** Called to stop broadcasting video and audio. There may be a delay before streaming actually stops. */ - virtual void StopBroadcasting() = 0; - - /** - * Checks to see if we've currently initiated a broadcast. Note that even though we've asked to broadcast, the live stream - * may not have actually started yet. For example, we could still be waiting for the login authentication to complete - * - * @return True if we're currently broadcasting - */ - virtual bool IsBroadcasting() const = 0; - - /** - * Checks to see if this streaming service is currently broadcasting and ready to accept new video frames. - * - * @return True if we're broadcasting right now! - */ - virtual bool IsReadyForVideoFrames() const = 0; - - /** - * Given a desired streaming resolution, allows the streaming service to change the resolution to be valid for - * broadcasting on this service. Some streaming systems have specific requirements about resolutions, such as - * multiples of 32 or 16. Note that image aspect ratio can be affected by this call (that is, aspect ratio is - * not always preserved, so it will be up to you to compensate.) - * - * @param VideoBufferWidth (In/Out) Set this to the width that you want, and you'll get back a width that it actually valid. - * @param VideoBufferHeight (In/Out) Set this to the height that you want, and you'll get back a height that it actually valid. - */ - virtual void MakeValidVideoBufferResolution( int& VideoBufferWidth, int& VideoBufferHeight ) const = 0; - - /** - * Queries information about the current broadcast. Should only be called while IsBroadcasting() is true. - * - * @param BroadcastConfig (Out) Filled with information about the current broadcast. - */ - virtual void QueryBroadcastConfig( FBroadcastConfig& OutBroadcastConfig ) const = 0; - - /** - * Broadcasts a new video frame. Should only be called while IsReadyForVideoFrames() is true. The frame buffer data must match - * the format and resolution that the live streaming service expects. You can call QueryBroadcastConfig() to find that out. - * - * @param VideoFrameBuffer The new video data to push to the live stream. The size of the buffer must match the expected buffer resolution returned from QueryBroadcastConfig()! - */ - virtual void PushVideoFrame( const FColor* VideoFrameBuffer ) = 0; - - - /** - * Web cam - */ - - /** - * Enables broadcasting from your web camera device - * - * @param Config Settings for the web cam - */ - virtual void StartWebCam( const FWebCamConfig& Config ) = 0; - - /** - * Turns off the web cam - */ - virtual void StopWebCam() = 0; - - /** - * Checks to see if the web cam is currently enabled - * - * @return True if the web camera is active - */ - virtual bool IsWebCamEnabled() const = 0; - - /** - * For services that support web cams, this function will return the current picture on the web cam as a GPU texture - * - * @param bIsImageFlippedHorizontally [Out] True if the image is flipped left to right - * @param bIsImageFlippedVertically [Out] True if the image is flipped top to bottom - * - * @return Current web cam frame as a 2D texture - */ - virtual class UTexture2D* GetWebCamTexture( bool& bIsImageFlippedHorizontally, bool& bIsImageFlippedVertically ) = 0; - - - /** - * Chat - */ - - /** Called when a chat message is received and should be displayed in the UI */ - DECLARE_MULTICAST_DELEGATE_TwoParams( FOnChatMessage, const FText& /* UserName */, const FText& /* ChatMessage */ ); - - /** Event to register with to handle incoming chat messages when connected to a chat server */ - virtual FOnChatMessage& OnChatMessage() = 0; - - /** - * Attempts to connect to the chat server for receiving and sending chat messages. Make sure to bind a function to - * the OnChatMessage() event so that you find out about incoming chat messages - */ - virtual void ConnectToChat() = 0; - - /** - * Disconnects from the chat server - */ - virtual void DisconnectFromChat() = 0; - - /** - * Checks to see if chat is currently enabled. This doesn't necessarily mean that the user is connected to the chat - * server at this time. You need to listen for OnStatusChanged events to know for sure whether it is safe to - * send chat messages at any given moment. This may return true while a connection is still pending! - * - * @return True if the chat system is enabled and we're either already connected or a connection attempt is in progress - */ - virtual bool IsChatEnabled() const = 0; - - /** - * Sends text to the chat channel, attributed to the currently logged in user. In order for this to work, you must - * have already successfully connected to a chat server. You can listen for OnStatusChanged events to find out - * when you are connected and it is possible to send chat messages - * - * @param ChatMessage The text to send - */ - virtual void SendChatMessage( const FString& ChatMessage ) = 0; - - - /** - * Miscellaneous - */ - - /** Completion callback for the QueryLiveStreams() function, that passes back the list of live streams along with a boolean - variable that indicates whether the query was successful or not */ - DECLARE_DELEGATE_TwoParams( FQueryLiveStreamsCallback, const TArray< FLiveStreamInfo >& /* LiveStreams */, bool /* bQueryWasSuccessful */ ); - - /** - * Asynchronously queries a list of live streams that are currently in progress for the specified game name. Note that some - * services may not support this feature. Your callback function will be called with the list of live streams that were found. - * In the case there was an error or this feature wasn't supported, your callback will still be executed but will contain - * a status variable that indicates failure - * - * @param GameName The name of the game to search for - * @param CompletionCallback The function to invoke when the query has finished (or if an error occurs) - */ - virtual void QueryLiveStreams( const FString& GameName, FQueryLiveStreamsCallback CompletionCallback ) = 0; -}; diff --git a/Engine/Source/Runtime/Engine/Public/GPUSkinCache.h b/Engine/Source/Runtime/Engine/Public/GPUSkinCache.h index 509ecd9f747f..e4f1355e93b6 100644 --- a/Engine/Source/Runtime/Engine/Public/GPUSkinCache.h +++ b/Engine/Source/Runtime/Engine/Public/GPUSkinCache.h @@ -46,6 +46,7 @@ class FGPUBaseSkinVertexFactory; class FMorphVertexBuffer; class FSkeletalMeshObjectGPUSkin; struct FSkelMeshSection; +struct FVertexBufferAndSRV; // Can the skin cache be used (ie shaders added, etc) extern ENGINE_API bool IsGPUSkinCacheAvailable(); @@ -121,24 +122,32 @@ public: struct FAllocation { - enum + static uint64 CalulateRequiredMemory(uint32 NumFloatsRequired) { - NUM_BUFFERS = 3, - }; + return sizeof(float) * (uint64)NumFloatsRequired * NUM_BUFFERS; + } - // Output of the GPU skinning (ie Pos, Normals) - FRWBuffer RWBuffers[NUM_BUFFERS]; - - int32 CurrentIndex; - int32 PreviousIndex; - - uint32 NumFloatsRequired; - - FAllocation() - : CurrentIndex(0) - , PreviousIndex(0) - , NumFloatsRequired(0) + FAllocation(uint32 InNumFloatsRequired) + : NumFloatsRequired(InNumFloatsRequired) { + for (int32 Index = 0; Index < NUM_BUFFERS; ++Index) + { + RWBuffers[Index].Initialize(sizeof(float), NumFloatsRequired, PF_R32_FLOAT, BUF_Static); + Revisions[Index] = 0; + BoneBuffers[Index] = nullptr; + } + } + + void Release(TArray& InBuffersToTransition) + { + for (uint32 i = 0; i < NUM_BUFFERS; i++) + { + FRWBuffer& RWBuffer = RWBuffers[i]; + if (RWBuffer.UAV.IsValid()) + { + InBuffersToTransition.Remove(RWBuffer.UAV); + } + } } ~FAllocation() @@ -149,11 +158,62 @@ public: } } - void Advance() + FRWBuffer* Find(const FVertexBufferAndSRV& BoneBuffer, uint32 Revision) { - PreviousIndex = CurrentIndex; - CurrentIndex = (CurrentIndex + 1) % NUM_BUFFERS; + for (int32 Index = 0; Index < NUM_BUFFERS; ++Index) + { + if (Revisions[Index] == Revision && BoneBuffers[Index] == &BoneBuffer) + { + return &RWBuffers[Index]; + } + } + + return nullptr; } + + void Advance(const FVertexBufferAndSRV& BoneBuffer1, uint32 Revision1, const FVertexBufferAndSRV& BoneBuffer2, uint32 Revision2) + { + const FVertexBufferAndSRV* InBoneBuffers[2] = { &BoneBuffer1 , &BoneBuffer2 }; + uint32 InRevisions[2] = { Revision1 , Revision2 }; + + for (int32 Index = 0; Index < NUM_BUFFERS; ++Index) + { + bool Needed = false; + for (int32 i = 0; i < 2; ++i) + { + if (Revisions[Index] == InRevisions[i] && BoneBuffers[Index] == InBoneBuffers[i]) + { + Needed = true; + } + } + + if (!Needed) + { + Revisions[Index] = Revision1; + BoneBuffers[Index] = &BoneBuffer1; + break; + } + } + } + + uint64 GetNumBytes() + { + return CalulateRequiredMemory(NumFloatsRequired); + } + + private: + enum + { + NUM_BUFFERS = 2, + }; + + uint32 NumFloatsRequired; + + // Output of the GPU skinning (ie Pos, Normals) + FRWBuffer RWBuffers[NUM_BUFFERS]; + + uint32 Revisions[NUM_BUFFERS]; + const FVertexBufferAndSRV* BoneBuffers[NUM_BUFFERS]; }; ENGINE_API void TransitionAllToReadable(FRHICommandList& RHICmdList); diff --git a/Engine/Source/Runtime/Engine/Public/GPUSkinVertexFactory.h b/Engine/Source/Runtime/Engine/Public/GPUSkinVertexFactory.h index cf48c0eb19a4..164724d89b56 100644 --- a/Engine/Source/Runtime/Engine/Public/GPUSkinVertexFactory.h +++ b/Engine/Source/Runtime/Engine/Public/GPUSkinVertexFactory.h @@ -93,6 +93,7 @@ enum { MAX_GPU_BONE_MATRICES_UNIFORMBUFFER = 75, }; + BEGIN_UNIFORM_BUFFER_STRUCT(FBoneMatricesUniformShaderParameters,) DECLARE_UNIFORM_BUFFER_STRUCT_MEMBER_ARRAY(FSkinMatrix3x4, BoneMatrices, [MAX_GPU_BONE_MATRICES_UNIFORMBUFFER]) END_UNIFORM_BUFFER_STRUCT(FBoneMatricesUniformShaderParameters) @@ -214,64 +215,6 @@ public: // From FTickableObjectRenderThread }; -/** for motion blur skinning */ -class FBoneDataVertexBuffer : public FRenderResource -{ -public: - /** constructor */ - FBoneDataVertexBuffer(); - - /** - * call UnlockData() after this one - * @return never 0 - */ - float* LockData(); - /** - * Needs to be called after LockData() - */ - void UnlockData(uint32 SizeInBytes); - - /** Returns the size of the buffer in pixels. */ - uint32 GetSizeX() const; - - bool IsValid() const - { - return IsValidRef(BoneBuffer); - } - - // interface FRenderResource ------------------------------------------ - - virtual void ReleaseRHI() override - { - DEC_DWORD_STAT_BY( STAT_SkeletalMeshMotionBlurSkinningMemory, ComputeMemorySize()); - BoneBuffer.SafeRelease(); - FRenderResource::ReleaseRHI(); - } - - virtual void InitDynamicRHI() override - { - if(SizeX) - { - INC_DWORD_STAT_BY( STAT_SkeletalMeshMotionBlurSkinningMemory, ComputeMemorySize()); - const int32 TileBufferSize = ComputeMemorySize(); - FRHIResourceCreateInfo CreateInfo; - // BUF_Dynamic as it can be too large (e.g. 100 characters each 100 bones with 48 bytes per bone is about 1/2 MB) to do it as BUF_Volatile - BoneBuffer.VertexBufferRHI = RHICreateVertexBuffer( TileBufferSize, BUF_Dynamic | BUF_ShaderResource, CreateInfo ); - BoneBuffer.VertexBufferSRV = RHICreateShaderResourceView( BoneBuffer.VertexBufferRHI, sizeof(FVector4), PF_A32B32G32R32F ); - } - } - - /** Bone buffer reference. */ - FVertexBufferAndSRV BoneBuffer; - -private: // ------------------------------------------------------- - /** Buffer size in texels */ - uint32 SizeX; - - /** @return in bytes */ - uint32 ComputeMemorySize(); -}; - /** Vertex factory with vertex stream components for GPU skinned vertices */ class FGPUBaseSkinVertexFactory : public FVertexFactory { @@ -343,12 +286,12 @@ public: // @param bPrevious true:previous, false:current // @param FrameNumber usually from View.Family->FrameNumber // @return IsValid() can fail, then you have to create the buffers first (or if the size changes) - FVertexBufferAndSRV& GetBoneBufferForWriting(bool bPrevious, uint32 FrameNumber) + FVertexBufferAndSRV& GetBoneBufferForWriting(uint32 FrameNumber) { const FShaderDataType* This = (const FShaderDataType*)this; // non const version maps to const version - return (FVertexBufferAndSRV&)This->GetBoneBufferInternal(bPrevious, FrameNumber); + return (FVertexBufferAndSRV&)This->GetBoneBufferInternal(false, FrameNumber); } private: @@ -691,7 +634,6 @@ public: Index = 1 - Index; } - // we always return a valid buffer check(ClothSimulPositionNormalBuffer[Index].VertexBufferRHI.IsValid()); return ClothSimulPositionNormalBuffer[Index]; } @@ -715,13 +657,13 @@ public: { if(BufferFrameNumber[0] == -1) { - ensure(BufferFrameNumber[1] != -1); + //ensure(BufferFrameNumber[1] != -1); return 1; } else if(BufferFrameNumber[1] == -1) { - ensure(BufferFrameNumber[0] != -1); + //ensure(BufferFrameNumber[0] != -1); return 0; } diff --git a/Engine/Source/Runtime/Engine/Public/GenericQuadTree.h b/Engine/Source/Runtime/Engine/Public/GenericQuadTree.h index 29e87ecc8017..17c46ff7d5e1 100644 --- a/Engine/Source/Runtime/Engine/Public/GenericQuadTree.h +++ b/Engine/Source/Runtime/Engine/Public/GenericQuadTree.h @@ -4,7 +4,7 @@ #include "CoreMinimal.h" -DEFINE_LOG_CATEGORY_STATIC(LogQuadTree, Log, Warning); +ENGINE_API DECLARE_LOG_CATEGORY_EXTERN(LogQuadTree, Log, Warning); template class TQuadTree diff --git a/Engine/Source/Runtime/Engine/Public/IAudioExtensionPlugin.h b/Engine/Source/Runtime/Engine/Public/IAudioExtensionPlugin.h index 8134c31e9165..0869ca0a4606 100644 --- a/Engine/Source/Runtime/Engine/Public/IAudioExtensionPlugin.h +++ b/Engine/Source/Runtime/Engine/Public/IAudioExtensionPlugin.h @@ -127,8 +127,13 @@ public: { } - /** Apply the spatialization settings for the source. */ - virtual void SetSpatializationSettings(const uint32 SourceId, USpatializationPluginSourceSettingsBase* InSettings) + /** Called when a source is assigned to a voice. */ + virtual void OnInitSource(const uint32 SourceId, const FName& AudioComponentUserId, USpatializationPluginSourceSettingsBase* InSettings) + { + } + + /** Called when a source is done playing and is released. */ + virtual void OnReleaseSource(const uint32 SourceId) { } @@ -181,8 +186,13 @@ public: { } - /** Apply the occlusion settings for the source. */ - virtual void SetOcclusionSettings(const uint32 SourceId, UOcclusionPluginSourceSettingsBase* InSettings) + /** Called when a source is assigned to a voice. */ + virtual void OnInitSource(const uint32 SourceId, const FName& AudioComponentUserId, UOcclusionPluginSourceSettingsBase* InSettings) + { + } + + /** Called when a source is done playing and is released. */ + virtual void OnReleaseSource(const uint32 SourceId) { } @@ -198,7 +208,7 @@ class ENGINE_API UReverbPluginSourceSettingsBase : public UObject { GENERATED_BODY() }; - + class IAudioReverb { public: @@ -212,10 +222,11 @@ public: { } - /** Apply the reverb settings for the source. */ - virtual void SetReverbSettings(const uint32 SourceId, const uint32 AudioComponentUserId, UReverbPluginSourceSettingsBase* InSettings) - { - } + /** Called when a source is assigned to a voice. */ + virtual void OnInitSource(const uint32 SourceId, const FName& AudioComponentUserId, UReverbPluginSourceSettingsBase* InSettings) = 0; + + /** Called when a source is done playing and is released. */ + virtual void OnReleaseSource(const uint32 SourceId) = 0; virtual class FSoundEffectSubmix* GetEffectSubmix(class USoundSubmix* Submix) = 0; diff --git a/Engine/Source/Runtime/Engine/Public/IStereoLayers.h b/Engine/Source/Runtime/Engine/Public/IStereoLayers.h index 2bd8f1be47a8..8b302e9ae5a2 100644 --- a/Engine/Source/Runtime/Engine/Public/IStereoLayers.h +++ b/Engine/Source/Runtime/Engine/Public/IStereoLayers.h @@ -30,10 +30,14 @@ public: enum ELayerFlags { - LAYER_FLAG_TEX_CONTINUOUS_UPDATE = 0x00000001, // Internally copies the texture on every frame for video, etc. - LAYER_FLAG_TEX_NO_ALPHA_CHANNEL = 0x00000002, // Ignore the textures alpha channel, this makes the stereo layer opaque - LAYER_FLAG_QUAD_PRESERVE_TEX_RATIO = 0x00000004, // Quad Y component will be calculated based on the texture dimensions - LAYER_FLAG_SUPPORT_DEPTH = 0x00000008, // The layer will intersect with the scene's depth + // Internally copies the texture on every frame for video, etc. + LAYER_FLAG_TEX_CONTINUOUS_UPDATE = 0x00000001, + // Ignore the textures alpha channel, this makes the stereo layer opaque. Flag is ignored on Steam VR. + LAYER_FLAG_TEX_NO_ALPHA_CHANNEL = 0x00000002, + // Quad Y component will be calculated based on the texture dimensions + LAYER_FLAG_QUAD_PRESERVE_TEX_RATIO = 0x00000004, + // The layer will intersect with the scene's depth. Currently only supported on Oculus platforms. + LAYER_FLAG_SUPPORT_DEPTH = 0x00000008, }; /** @@ -41,19 +45,30 @@ public: */ struct FLayerDesc { - FTransform Transform = FTransform::Identity; // View space transform - FVector2D QuadSize = FVector2D(1.0f, 1.0f); // Size of rendered quad - FBox2D UVRect = FBox2D(FVector2D(0.0f, 0.0f), FVector2D(1.0f, 1.0f)); // UVs of rendered quad - int32 Priority = 0; // Render order priority, higher priority render on top of lower priority - ELayerType PositionType = ELayerType::FaceLocked; // Which space the layer is locked within - ELayerShape ShapeType = ELayerShape::QuadLayer; // which shape of layer it is + // View space transform + FTransform Transform = FTransform::Identity; + // Size of rendered quad + FVector2D QuadSize = FVector2D(1.0f, 1.0f); + // UVs of rendered quad + FBox2D UVRect = FBox2D(FVector2D(0.0f, 0.0f), FVector2D(1.0f, 1.0f)); + // Render order priority, higher priority render on top of lower priority. Face-Locked layers are rendered on top of other layer types regardless of priority. + int32 Priority = 0; + // Which space the layer is locked within + ELayerType PositionType = ELayerType::FaceLocked; + // which shape of layer it is. ELayerShape::QuadLayer is the only shape supported by all VR platforms. + ELayerShape ShapeType = ELayerShape::QuadLayer; FVector2D CylinderSize = FVector2D(1.0f, 1.0f); float CylinderHeight = 1.0f; - FTextureRHIRef Texture = nullptr; // Texture mapped for right eye (if one texture provided, mono assumed) - FTextureRHIRef LeftTexture = nullptr; // Texture mapped for left eye (if one texture provided, mono assumed) - uint32 Flags = 0; // Uses LAYER_FLAG_... + // Texture mapped for right eye (if one texture provided, mono assumed) + FTextureRHIRef Texture = nullptr; + // Texture mapped for left eye (if one texture provided, mono assumed) + FTextureRHIRef LeftTexture = nullptr; + // Uses LAYER_FLAG_... -- See: ELayerFlags + uint32 Flags = 0; }; + virtual ~IStereoLayers() { } + /** * Creates a new layer from a given texture resource, which is projected on top of the world as a quad * diff --git a/Engine/Source/Runtime/Engine/Public/LocalNotification.h b/Engine/Source/Runtime/Engine/Public/LocalNotification.h index 17f6cfbb0e38..4dc57f1e6ec8 100644 --- a/Engine/Source/Runtime/Engine/Public/LocalNotification.h +++ b/Engine/Source/Runtime/Engine/Public/LocalNotification.h @@ -28,6 +28,13 @@ public: */ virtual void ScheduleLocalNotificationAtTime(const FDateTime& FireDateTime, bool LocalTime, const FText& Title, const FText& Body, const FText& Action, const FString& ActivationEvent) = 0; + /** Schedule a local notification badge at a specific time, inLocalTime specifies the current local time or if UTC time should be used + * @param FireDateTime The time at which to fire the local notification + * @param LocalTime If true the provided time is in the local timezone, if false it is in UTC + * @param ActivationEvent A string that is passed in the delegate callback when the app is brought into the foreground from the user activating the notification + */ + virtual void ScheduleLocalNotificationBadgeAtTime(const FDateTime& FireDateTime, bool LocalTime, const FString& ActivationEvent) = 0; + /** Get the local notification that was used to launch the app * @param NotificationLaunchedApp Return true if a notification was used to launch the app * @param ActivationEvent Returns the name of the ActivationEvent if a notification was used to launch the app diff --git a/Engine/Source/Runtime/Engine/Public/MaterialCompiler.h b/Engine/Source/Runtime/Engine/Public/MaterialCompiler.h index 0c1b169042c9..0ff4ab275f18 100644 --- a/Engine/Source/Runtime/Engine/Public/MaterialCompiler.h +++ b/Engine/Source/Runtime/Engine/Public/MaterialCompiler.h @@ -34,6 +34,8 @@ enum EMaterialForceCastFlags class FMaterialCompiler { public: + virtual ~FMaterialCompiler() { } + // sets internal state CurrentShaderFrequency // @param OverrideShaderFrequency SF_NumFrequencies to not override virtual void SetMaterialProperty(EMaterialProperty InProperty, EShaderFrequency OverrideShaderFrequency = SF_NumFrequencies, bool bUsePreviousFrameTime = false) = 0; @@ -243,6 +245,8 @@ public: virtual int32 PerInstanceRandom() = 0; virtual int32 PerInstanceFadeAmount() = 0; virtual int32 AntialiasedTextureMask(int32 Tex, int32 UV, float Threshold, uint8 Channel) = 0; + virtual int32 Sobol(int32 Cell, int32 Index, int32 Seed) = 0; + virtual int32 TemporalSobol(int32 Index, int32 Seed) = 0; virtual int32 Noise(int32 Position, float Scale, int32 Quality, uint8 NoiseFunction, bool bTurbulence, int32 Levels, float OutputMin, float OutputMax, float LevelScale, int32 FilterWidth, bool bTiling, uint32 RepeatSize) = 0; virtual int32 VectorNoise(int32 Position, int32 Quality, uint8 NoiseFunction, bool bTiling, uint32 RepeatSize) = 0; virtual int32 BlackBody( int32 Temp ) = 0; @@ -442,6 +446,8 @@ public: { return Compiler->AntialiasedTextureMask(Tex, UV, Threshold, Channel); } + virtual int32 Sobol(int32 Cell, int32 Index, int32 Seed) override { return Compiler->Sobol(Cell, Index, Seed); } + virtual int32 TemporalSobol(int32 Index, int32 Seed) override { return Compiler->TemporalSobol(Index, Seed); } virtual int32 Noise(int32 Position, float Scale, int32 Quality, uint8 NoiseFunction, bool bTurbulence, int32 Levels, float OutputMin, float OutputMax, float LevelScale, int32 FilterWidth, bool bTiling, uint32 TileSize) override { return Compiler->Noise(Position, Scale, Quality, NoiseFunction, bTurbulence, Levels, OutputMin, OutputMax, LevelScale, FilterWidth, bTiling, TileSize); diff --git a/Engine/Source/Runtime/Engine/Public/MaterialExpressionIO.h b/Engine/Source/Runtime/Engine/Public/MaterialExpressionIO.h index de89a76f0ea7..b85b4cbbab6d 100644 --- a/Engine/Source/Runtime/Engine/Public/MaterialExpressionIO.h +++ b/Engine/Source/Runtime/Engine/Public/MaterialExpressionIO.h @@ -16,14 +16,14 @@ struct FExpressionInput #if WITH_EDITORONLY_DATA /** * Material expression that this input is connected to, or NULL if not connected. - * If you want to be safe when checking against dangling Reroute nodes, please use GetCheckedInput before accessing this property. + * If you want to be safe when checking against dangling Reroute nodes, please use GetTracedInput before accessing this property. */ class UMaterialExpression* Expression; #endif /** * Index into Expression's outputs array that this input is connected to. - * If you want to be safe when checking against dangling Reroute nodes, please use GetCheckedInput before accessing this property. + * If you want to be safe when checking against dangling Reroute nodes, please use GetTracedInput before accessing this property. */ int32 OutputIndex; diff --git a/Engine/Source/Runtime/Engine/Public/MaterialShared.h b/Engine/Source/Runtime/Engine/Public/MaterialShared.h index 0b68075e5683..b12b0875b8e1 100644 --- a/Engine/Source/Runtime/Engine/Public/MaterialShared.h +++ b/Engine/Source/Runtime/Engine/Public/MaterialShared.h @@ -110,6 +110,13 @@ enum EMaterialCommonBasis MCB_MAX, }; +//when setting deferred scene resources whether to throw warnings when we fall back to defaults. +enum struct EDeferredParamStrictness +{ + ELoose, // no warnings + EStrict, // throw warnings +}; + /** Defines the domain of a material. */ UENUM() enum EMaterialDomain @@ -530,8 +537,9 @@ class FMeshMaterialShaderMap : public TShaderMap { public: - FMeshMaterialShaderMap(FVertexFactoryType* InVFType) : - VertexFactoryType(InVFType) + FMeshMaterialShaderMap(EShaderPlatform InPlatform, FVertexFactoryType* InVFType) + : TShaderMap(InPlatform) + , VertexFactoryType(InVFType) {} /** @@ -620,7 +628,8 @@ public: */ static void LoadFromDerivedDataCache(const FMaterial* Material, const FMaterialShaderMapId& ShaderMapId, EShaderPlatform Platform, TRefCountPtr& InOutShaderMap); - FMaterialShaderMap(); + inline FMaterialShaderMap() : FMaterialShaderMap(EShaderPlatform::SP_NumPlatforms) {} + FMaterialShaderMap(EShaderPlatform InPlatform); // Destructor. ~FMaterialShaderMap(); @@ -743,7 +752,6 @@ public: // Accessors. ENGINE_API const FMeshMaterialShaderMap* GetMeshShaderMap(FVertexFactoryType* VertexFactoryType) const; const FMaterialShaderMapId& GetShaderMapId() const { return ShaderMapId; } - EShaderPlatform GetShaderPlatform() const { return Platform; } const FString& GetFriendlyName() const { return FriendlyName; } uint32 GetCompilingId() const { return CompilingId; } bool IsCompilationFinalized() const { return bCompilationFinalized; } @@ -794,9 +802,6 @@ private: /** The material's user friendly name, typically the object name. */ FString FriendlyName; - /** The platform this shader map was compiled with */ - EShaderPlatform Platform; - /** The static parameter set that this shader map was compiled with */ FMaterialShaderMapId ShaderMapId; @@ -1060,7 +1065,7 @@ public: virtual float GetTranslucentSelfShadowSecondDensityScale() const { return 1.0f; } virtual float GetTranslucentSelfShadowSecondOpacity() const { return 1.0f; } virtual float GetTranslucentBackscatteringExponent() const { return 1.0f; } - virtual bool IsSeparateTranslucencyEnabled() const { return false; } + virtual bool IsTranslucencyAfterDOFEnabled() const { return false; } virtual bool IsMobileSeparateTranslucencyEnabled() const { return false; } virtual FLinearColor GetTranslucentMultipleScatteringExtinction() const { return FLinearColor::White; } virtual float GetTranslucentShadowStartOffset() const { return 0.0f; } @@ -1493,6 +1498,7 @@ public: ENGINE_API static const TSet& GetMaterialRenderProxyMap() { + check(!FPlatformProperties::RequiresCookedData()); return MaterialRenderProxyMap; } @@ -1522,6 +1528,13 @@ public: #endif } + ENGINE_API static void UpdateDeferredCachedUniformExpressions(); + + static inline bool HasDeferredUniformExpressionCacheRequests() + { + return DeferredUniformExpressionCacheRequests.Num() > 0; + } + private: /** true if the material is selected. */ @@ -1542,6 +1555,8 @@ private: * This is used to propagate new shader maps to materials being used for rendering. */ ENGINE_API static TSet MaterialRenderProxyMap; + + ENGINE_API static TSet DeferredUniformExpressionCacheRequests; }; /** @@ -1710,7 +1725,7 @@ public: ENGINE_API virtual float GetTranslucentSelfShadowSecondDensityScale() const override; ENGINE_API virtual float GetTranslucentSelfShadowSecondOpacity() const override; ENGINE_API virtual float GetTranslucentBackscatteringExponent() const override; - ENGINE_API virtual bool IsSeparateTranslucencyEnabled() const override; + ENGINE_API virtual bool IsTranslucencyAfterDOFEnabled() const override; ENGINE_API virtual bool IsMobileSeparateTranslucencyEnabled() const override; ENGINE_API virtual FLinearColor GetTranslucentMultipleScatteringExtinction() const override; ENGINE_API virtual float GetTranslucentShadowStartOffset() const override; @@ -2029,8 +2044,8 @@ private: EMaterialValueType ValueType, const FVector4& DefaultValue, EShaderFrequency ShaderFrequency, int32 TexCoordIndex = INDEX_NONE, bool bIsHidden = false, MaterialAttributeBlendFunction BlendFunction = nullptr); - FMaterialAttributeDefintion* Find(const FGuid& AttributeID); - FMaterialAttributeDefintion* Find(EMaterialProperty Property); + ENGINE_API FMaterialAttributeDefintion* Find(const FGuid& AttributeID); + ENGINE_API FMaterialAttributeDefintion* Find(EMaterialProperty Property); ENGINE_API static FMaterialAttributeDefinitionMap GMaterialPropertyAttributesMap; diff --git a/Engine/Source/Runtime/Engine/Public/Net/RepLayout.h b/Engine/Source/Runtime/Engine/Public/Net/RepLayout.h index 53f407076a34..923f6462b849 100644 --- a/Engine/Source/Runtime/Engine/Public/Net/RepLayout.h +++ b/Engine/Source/Runtime/Engine/Public/Net/RepLayout.h @@ -18,6 +18,10 @@ class UActorChannel; class UNetConnection; class UPackageMapClient; +// Properties will be copied in here so memory needs aligned to largest type +typedef TArray< uint8, TAlignedHeapAllocator<16> > FRepStateStaticBuffer; + + class FRepChangedParent { public: @@ -124,6 +128,8 @@ public: CompareIndex( 0 ) { } + ~FRepChangelistState(); + TSharedPtr< FRepLayout > RepLayout; static const int32 MAX_CHANGE_HISTORY = 64; @@ -133,8 +139,7 @@ public: int32 HistoryEnd; int32 CompareIndex; - // Properties will be copied in here so memory needs aligned to largest type - TArray< uint8, TAlignedHeapAllocator<16> > StaticBuffer; + FRepStateStaticBuffer StaticBuffer; }; /** FRepState @@ -155,8 +160,7 @@ public: ~FRepState(); - // Properties will be copied in here so memory needs aligned to largest type - TArray< uint8, TAlignedHeapAllocator<16> > StaticBuffer; + FRepStateStaticBuffer StaticBuffer; FGuidReferencesMap GuidReferencesMap; @@ -359,6 +363,7 @@ public: class FRepLayout { friend class FRepState; + friend class FRepChangelistState; friend class UPackageMapClient; public: @@ -460,6 +465,8 @@ public: const uint8* RESTRICT Data, const FReplicationFlags& RepFlags ) const; + void AddReferencedObjects(FReferenceCollector& Collector); + private: void RebuildConditionalProperties( FRepState * RESTRICT RepState, const FRepChangedPropertyTracker& ChangedTracker, const FReplicationFlags& RepFlags ) const; @@ -602,7 +609,7 @@ private: void ConstructProperties( TArray< uint8, TAlignedHeapAllocator<16> >& ShadowData ) const; void InitProperties( TArray< uint8, TAlignedHeapAllocator<16> >& ShadowData, uint8* Src ) const; - void DestructProperties( FRepState * RepState ) const; + void DestructProperties( FRepStateStaticBuffer& RepStateStaticBuffer ) const; TArray< FRepParentCmd > Parents; TArray< FRepLayoutCmd > Cmds; diff --git a/Engine/Source/Runtime/Engine/Public/PhysXPublic.h b/Engine/Source/Runtime/Engine/Public/PhysXPublic.h index 3b4d12bcaed3..8c5932e8f6fa 100644 --- a/Engine/Source/Runtime/Engine/Public/PhysXPublic.h +++ b/Engine/Source/Runtime/Engine/Public/PhysXPublic.h @@ -173,9 +173,9 @@ struct FPhysXSupport * returns true if the requested actor is non-null */ template - static bool ExecuteOnPxRigidActorReadOnly(const FBodyInstance* BI, const LambdaType& Func, int32 SceneType = -1) + static bool ExecuteOnPxRigidActorReadOnly(const FBodyInstance* BI, const LambdaType& Func) { - if (const PxRigidActor* PRigidActor = BI->GetPxRigidActor_AssumesLocked(SceneType)) + if (const PxRigidActor* PRigidActor = BI->GetPxRigidActor_AssumesLocked()) { const int32 SceneIndex = (PRigidActor == BI->RigidActorSync ? BI->SceneIndexSync : BI->SceneIndexAsync); PxScene* PScene = GetPhysXSceneFromIndex(SceneIndex); @@ -327,7 +327,7 @@ struct FPhysXSupport }; // Utility functions for obtaining locks and executing lambda. This indirection is needed for vs2012 but should be inlined -template bool ExecuteOnPxRigidActorReadOnly(const FBodyInstance* BI, const LambdaType& Func, int32 SceneType = -1){ return FPhysXSupport::ExecuteOnPxRigidActorReadOnly(BI, Func, SceneType); } +template bool ExecuteOnPxRigidActorReadOnly(const FBodyInstance* BI, const LambdaType& Func){ return FPhysXSupport::ExecuteOnPxRigidActorReadOnly(BI, Func); } template bool ExecuteOnPxRigidBodyReadOnly(const FBodyInstance* BI, const LambdaType& Func) { return FPhysXSupport::ExecuteOnPxRigidBodyReadOnly(BI, Func); } template bool ExecuteOnPxRigidBodyReadWrite(const FBodyInstance* BI, const LambdaType& Func){ return FPhysXSupport::ExecuteOnPxRigidBodyReadWrite(BI, Func); } template bool ExecuteOnPxRigidDynamicReadOnly(const FBodyInstance* BI, const LambdaType& Func){ return FPhysXSupport::ExecuteOnPxRigidDynamicReadOnly(BI, Func); } diff --git a/Engine/Source/Runtime/PhysXFormats/Public/IPhysXFormat.h b/Engine/Source/Runtime/Engine/Public/Physics/IPhysXCooking.h similarity index 64% rename from Engine/Source/Runtime/PhysXFormats/Public/IPhysXFormat.h rename to Engine/Source/Runtime/Engine/Public/Physics/IPhysXCooking.h index 5ccf3a74fbf3..fd94ad318c97 100644 --- a/Engine/Source/Runtime/PhysXFormats/Public/IPhysXFormat.h +++ b/Engine/Source/Runtime/Engine/Public/Physics/IPhysXCooking.h @@ -33,10 +33,18 @@ enum class EPhysXMeshCookFlags : uint8 }; ENUM_CLASS_FLAGS(EPhysXMeshCookFlags); +namespace physx +{ + class PxCooking; + class PxConvexMesh; + class PxTriangleMesh; + class PxHeightField; +} + /** - * IPhysXFormat, PhysX cooking and serialization abstraction + * IPhysXCooking, PhysX cooking and serialization abstraction **/ -class IPhysXFormat +class IPhysXCooking { public: @@ -63,6 +71,17 @@ public: */ virtual EPhysXCookingResult CookConvex( FName Format, EPhysXMeshCookFlags CookFlags, const TArray& SrcBuffer, TArray& OutBuffer ) const = 0; + /** + * Cooks the source convex data for the platform and returns the PhysX geometry directly (meant for runtime when you just need the geometry directly without serializing out) + * + * @param Format The desired format + * @param CookFlags Flags used to provide options for this cook + * @param SrcBuffer The source buffer + * @param OutBuffer The resulting cooked data + * @return The cooked convex mesh geometry + */ + virtual EPhysXCookingResult CreateConvex(FName Format, EPhysXMeshCookFlags CookFlags, const TArray& SrcBuffer, physx::PxConvexMesh*& OutBuffer) const = 0; + /** * Cooks the source Tri-Mesh data for the platform and stores the cooked data internally. * @@ -73,7 +92,17 @@ public: * @return true on success, false otherwise. */ virtual bool CookTriMesh( FName Format, EPhysXMeshCookFlags CookFlags, const TArray& SrcVertices, const TArray& SrcIndices, const TArray& SrcMaterialIndices, const bool FlipNormals, TArray& OutBuffer) const = 0; - + + /** + * Cooks the source Tri-Mesh data for the platform and returns the PhysX geometry directly (meant for runtime when you just need the geometry directly without serializing out) + * + * @param Format The desired format. + * @param CookFlags Flags used to provide options for this cook + * @param SrcBuffer The source buffer. + * @param OutBuffer The resulting cooked data. + * @return true on success, false otherwise. + */ + virtual bool CreateTriMesh(FName Format, EPhysXMeshCookFlags CookFlags, const TArray& SrcVertices, const TArray& SrcIndices, const TArray& SrcMaterialIndices, const bool FlipNormals, physx::PxTriangleMesh*& OutTriangleMesh) const = 0; /** * Cooks the source height field data for the platform and stores the cooked data internally. * @@ -85,6 +114,17 @@ public: */ virtual bool CookHeightField( FName Format, FIntPoint HFSize, const void* Samples, uint32 SamplesStride, TArray& OutBuffer ) const = 0; + /** + * Cooks the source height field data for the platform and returns the PhysX geometry directly (meant for runtime when you just need the geometry directly without serializing out) + * + * @param Format The desired format + * @param HFSize Size of height field [NumColumns, NumRows] + * @param SrcBuffer The source buffer + * @param OutBuffer The resulting cooked data + * @return true on success, false otherwise. + */ + virtual bool CreateHeightField(FName Format, FIntPoint HFSize, const void* Samples, uint32 SamplesStride, physx::PxHeightField*& OutHeightField) const = 0; + /** * Serializes the BodyInstance * @@ -112,11 +152,14 @@ public: */ virtual uint16 GetVersion( FName Format ) const = 0; + /** Get the actual physx cooker object */ + virtual physx::PxCooking* GetCooking() const = 0; + public: /** * Virtual destructor. */ - virtual ~IPhysXFormat( ) { } + virtual ~IPhysXCooking( ) { } }; diff --git a/Engine/Source/Runtime/PhysXFormats/Public/IPhysXFormatModule.h b/Engine/Source/Runtime/Engine/Public/Physics/IPhysXCookingModule.h similarity index 62% rename from Engine/Source/Runtime/PhysXFormats/Public/IPhysXFormatModule.h rename to Engine/Source/Runtime/Engine/Public/Physics/IPhysXCookingModule.h index e78249743148..e5e3f2492062 100644 --- a/Engine/Source/Runtime/PhysXFormats/Public/IPhysXFormatModule.h +++ b/Engine/Source/Runtime/Engine/Public/Physics/IPhysXCookingModule.h @@ -1,7 +1,7 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. /*============================================================================= - IPhysXFormatModule.h: Declares the IPhysXFormatModule interface. + IPhysXCookingModule.h: Declares the IPhysXCookingModule interface. =============================================================================*/ #pragma once @@ -9,12 +9,12 @@ #include "CoreMinimal.h" #include "Modules/ModuleInterface.h" -class IPhysXFormat; +class IPhysXCooking; /** * Interface for PhysX format modules. */ -class IPhysXFormatModule +class IPhysXCookingModule : public IModuleInterface { public: @@ -22,12 +22,15 @@ public: /** * Gets the PhysX format. */ - virtual IPhysXFormat* GetPhysXFormat( ) = 0; + virtual IPhysXCooking* GetPhysXCooking( ) = 0; + + /** Terminates any physx state related to cooking */ + virtual void Terminate() = 0; public: /** * Virtual destructor. */ - ~IPhysXFormatModule( ) { } + ~IPhysXCookingModule( ) { } }; diff --git a/Engine/Source/Runtime/Engine/Public/Physics/PhysicsFiltering.h b/Engine/Source/Runtime/Engine/Public/Physics/PhysicsFiltering.h index 7bbd19379c97..e50d36e4792a 100644 --- a/Engine/Source/Runtime/Engine/Public/Physics/PhysicsFiltering.h +++ b/Engine/Source/Runtime/Engine/Public/Physics/PhysicsFiltering.h @@ -25,6 +25,14 @@ enum EPhysXFilterDataFlags EPDF_ModifyContacts = 0x0020 }; + +// Bit counts for Word3 of filter data. +// (ExtraFilter (top NumExtraFilterBits) + MyChannel (next NumCollisionChannelBits) as ECollisionChannel + Flags (remaining NumFilterDataFlagBits) +// [NumExtraFilterBits] [NumCollisionChannelBits] [NumFilterDataFlagBits] = 32 bits +enum { NumCollisionChannelBits = 5 }; +enum { NumFilterDataFlagBits = 32 - NumExtraFilterBits - NumCollisionChannelBits }; + + struct FPhysicsFilterBuilder { ENGINE_API FPhysicsFilterBuilder(TEnumAsByte InObjectType, FMaskFilter MaskFilter, const struct FCollisionResponseContainer& ResponseToChannels); @@ -37,13 +45,6 @@ struct FPhysicsFilterBuilder } } - inline void SetExtraFiltering(uint32 ExtraFiltering) - { - check(ExtraFiltering < 16); //we only have 4 bits of extra filtering - uint32 ExtraFilterMask = ExtraFiltering >> 28; - Word3 |= ExtraFilterMask; - } - inline void GetQueryData(uint32 ActorID, uint32& OutWord0, uint32& OutWord1, uint32& OutWord2, uint32& OutWord3) const { /** @@ -51,7 +52,7 @@ struct FPhysicsFilterBuilder * word0 (object ID) * word1 (blocking channels) * word2 (touching channels) - * word3 (ExtraFilter (top 4) MyChannel (top 5) as ECollisionChannel + Flags (lower 23)) + * word3 (ExtraFilter (top NumExtraFilterBits) + MyChannel (next NumCollisionChannelBits) as ECollisionChannel + Flags (remaining NumFilterDataFlagBits) */ OutWord0 = ActorID; OutWord1 = BlockingBits; @@ -66,7 +67,7 @@ struct FPhysicsFilterBuilder * word0 (body index) * word1 (blocking channels) * word2 (skeletal mesh component ID) - * word3 (ExtraFilter (top 4) MyChannel (top 5) as ECollisionChannel + Flags (lower 23)) + * word3 (ExtraFilter (top NumExtraFilterBits) + MyChannel (next NumCollisionChannelBits) as ECollisionChannel + Flags (remaining NumFilterDataFlagBits) */ OutWord0 = BodyIndex; OutWord1 = BlockingBits; @@ -118,29 +119,28 @@ inline void CreateShapeFilterData( inline ECollisionChannel GetCollisionChannel(uint32 Word3) { - uint32 NonFlagMask = Word3 >> 23; - uint32 ChannelMask = NonFlagMask & 0x1F; //we only want the first 5 bits because there's only 32 channels: 0b11111 + uint32 ChannelMask = (Word3 << NumExtraFilterBits) >> (32 - NumCollisionChannelBits); return (ECollisionChannel)ChannelMask; } inline ECollisionChannel GetCollisionChannelAndExtraFilter(uint32 Word3, FMaskFilter& OutMaskFilter) { - uint32 NonFlagMask = Word3 >> 23; - uint32 ChannelMask = NonFlagMask & 0x1F; //we only want the first 5 bits because there's only 32 channels: 0b11111 - OutMaskFilter = NonFlagMask >> 5; + uint32 ChannelMask = GetCollisionChannel(Word3); + OutMaskFilter = Word3 >> (32 - NumExtraFilterBits); return (ECollisionChannel)ChannelMask; } inline uint32 CreateChannelAndFilter(ECollisionChannel CollisionChannel, FMaskFilter MaskFilter) { - uint32 ResultMask = (MaskFilter << 5) | (uint32)CollisionChannel; - return ResultMask << 23; + uint32 ResultMask = (uint32(MaskFilter) << NumCollisionChannelBits) | (uint32)CollisionChannel; + return ResultMask << NumFilterDataFlagBits; } inline void UpdateMaskFilter(uint32& Word3, FMaskFilter NewMaskFilter) { - Word3 &= 0x0FFFFFFF; //we ignore the top 4 bits because that's where the new mask filter is going - Word3 |= NewMaskFilter << 28; + static_assert(NumExtraFilterBits <= 8, "Only up to 8 extra filter bits are supported."); + Word3 &= (0xFFFFFFFFu >> NumExtraFilterBits); //we drop the top NumExtraFilterBits bits because that's where the new mask filter is going + Word3 |= uint32(NewMaskFilter) << (32 - NumExtraFilterBits); } #if WITH_PHYSX diff --git a/Engine/Source/Runtime/Engine/Public/PhysicsPublic.h b/Engine/Source/Runtime/Engine/Public/PhysicsPublic.h index e50cbe3024a9..8264bf880043 100644 --- a/Engine/Source/Runtime/Engine/Public/PhysicsPublic.h +++ b/Engine/Source/Runtime/Engine/Public/PhysicsPublic.h @@ -640,6 +640,9 @@ public: /** Remove this SkeletalMeshComponent from set needing kinematic update before simulating physics*/ void ClearPreSimKinematicUpdate(USkeletalMeshComponent* InSkelComp); + /** The number of frames it takes to rebuild the PhysX scene query AABB tree. The bigger the number, the smaller fetchResults takes per frame, but the more the tree deteriorates until a new tree is built */ + void SetPhysXTreeRebuildRate(int32 RebuildRate); + private: /** Initialize a scene of the given type. Must only be called once for each scene type. */ void InitPhysScene(uint32 SceneType); @@ -662,6 +665,9 @@ private: /** Set whether we're doing a static load and want to stall, or are during gameplay and want to distribute over many frames */ void SetIsStaticLoading(bool bStaticLoading); + /** The number of frames it takes to rebuild the PhysX scene query AABB tree. The bigger the number, the smaller fetchResults takes per frame, but the more the tree deteriorates until a new tree is built */ + void SetPhysXTreeRebuildRateImp(int32 RebuildRate); + #if WITH_PHYSX /** User data wrapper passed to physx */ struct FPhysxUserData PhysxUserData; @@ -714,6 +720,8 @@ private: TMap DeferredKinematicUpdateSkelMeshes; FDelegateHandle PreGarbageCollectDelegateHandle; + + int32 PhysXTreeRebuildRate; }; /** @@ -848,7 +856,7 @@ public: /** * Load the required modules for PhysX */ -ENGINE_API void LoadPhysXModules(); +ENGINE_API void LoadPhysXModules(bool bLoadCooking); /** * Unload the required modules for PhysX */ @@ -884,3 +892,5 @@ public: static FOnPhysSceneTerm OnPhysSceneTerm; }; + +extern ENGINE_API class IPhysXCookingModule* GetPhysXCookingModule(); diff --git a/Engine/Source/Runtime/Engine/Public/PreviewScene.h b/Engine/Source/Runtime/Engine/Public/PreviewScene.h index bc9b009b31d4..aa87ff4441a9 100644 --- a/Engine/Source/Runtime/Engine/Public/PreviewScene.h +++ b/Engine/Source/Runtime/Engine/Public/PreviewScene.h @@ -61,7 +61,7 @@ public: /** * Adds a component to the preview scene. This attaches the component to the scene, and takes ownership of it. */ - virtual void AddComponent(class UActorComponent* Component,const FTransform& LocalToWorld); + virtual void AddComponent(class UActorComponent* Component,const FTransform& LocalToWorld, bool bAttachToRoot=false); /** * Removes a component from the preview scene. This detaches the component from the scene, and returns ownership of it. diff --git a/Engine/Source/Runtime/Engine/Public/PrimitiveViewRelevance.h b/Engine/Source/Runtime/Engine/Public/PrimitiveViewRelevance.h index 7cb41b1c5255..da2e4f5555df 100644 --- a/Engine/Source/Runtime/Engine/Public/PrimitiveViewRelevance.h +++ b/Engine/Source/Runtime/Engine/Public/PrimitiveViewRelevance.h @@ -30,6 +30,10 @@ struct FPrimitiveViewRelevance uint32 bMobileSeparateTranslucencyRelevance : 1; /** The primitive has one or more elements that have normal translucency. */ uint32 bNormalTranslucencyRelevance : 1; + /** For translucent primitives reading the scene color. */ + uint32 bUsesSceneColorCopy : 1; + /** For primitive that can't render in offscreen buffers (blend modulate). */ + uint32 bDisableOffscreenRendering : 1; /** */ uint32 bUsesGlobalDistanceField : 1; diff --git a/Engine/Source/Runtime/Engine/Public/ProfilingDebugging/MallocLeakReporter.h b/Engine/Source/Runtime/Engine/Public/ProfilingDebugging/MallocLeakReporter.h new file mode 100644 index 000000000000..ad389ca33b0f --- /dev/null +++ b/Engine/Source/Runtime/Engine/Public/ProfilingDebugging/MallocLeakReporter.h @@ -0,0 +1,136 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "Engine/Engine.h" +#include "Private/HAL/MallocLeakDetection.h" +#include "Delegates/Delegate.h" +#include "Delegates/DelegateCombinations.h" + + +/** + + FMallocLeakReporter is a helper class that works alongside FMallocLeakDetection to provide easy access to + reports of low-level memory leaks. + + The reporter can be operated from the console where it can be started/stopped and used to periodically + or manually report leaks, or it can be called from game code to implemnent this funtionality at desired times. + + Example Console Usage: + + "mallocleak.start report=300" - start tracking leaks and generate a report every 300 secs + "mallocleak report" - report allocations and leaks + "mallocleak stop" - stop tracking leaks + + Example Code usage + + FMallocLeakReporter::Get().Start(0, 300) - start tracking allocs > 0KB and generate a report every 300 secs + FMallocLeakReporter::Get().WriteReports() - Writes reports and returns the number of suspected leaks + FMallocLeakReporter::Get().WriteReport(TEXT("BigAllocs"), Options); - Write custom report of allocations that matches "Options" + FMallocLeakReporter::Get().Stop() - stop tracking allocations + + + Reports are written to the profiling dir, e,g GameName/Saved/Profiling/SessionName + + */ +class ENGINE_API FMallocLeakReporter +{ + DECLARE_MULTICAST_DELEGATE_TwoParams(FMallocLeakReportDelegate, const int32, const int32); + +public: + struct EReportOption + { + enum + { + ReportLeaks = (1 << 0), + ReportAllocs = (1 << 1), + ReportMemReport = (1 << 2), + + ReportAll = ReportLeaks | ReportAllocs | ReportMemReport, + }; + }; + + /** Return singleton instance */ + static FMallocLeakReporter& Get(); + + /** + * Starts tracking allocations. + * + * @param: FilterSize Only track allocations >= this value in KB. Higher values affect performance less + * @param: ReportOnTime Write out a report every N seconds + * @return: void + */void Start(int32 FilterSize = 0, float ReportOnTime = 0.0f); + + /** + * Stop tracking leaks + */ + void Stop(); + + /** + * Clears all accumulated data + */ + void Clear(); + + /** + * Returns our enabled state + * + * @return: bool + */ + bool IsEnabled() const { return Enabled; } + + /** + * Writes out a set of reports according to our defaults + */ + int32 WriteReports(const uint32 ReportFlags= EReportOption::ReportAll); + + /** + * Writes out a report according to the passed in options + */ + int32 WriteReport(const TCHAR* ReportName, const FMallocLeakReportOptions& Options); + + /** + * Sets default options for what are considered memory leaks + * + * @param: Options + * @return: void + */ + void SetDefaultLeakReportOptions(const FMallocLeakReportOptions& Options) + { + DefaultLeakReportOptions = Options; + } + + /** + * Sets default options for reporting allocations + * + * @param: Options + * @return: void + */ + void SetDefaultAllocReportOptions(const FMallocLeakReportOptions& Options) + { + DefaultAllocReportOptions = Options; + } + +protected: + + /** + * Private constructor + */ + FMallocLeakReporter(); + + /** + * Called internally to generate rate checkpoints + */ + void Checkpoint(); + + bool Enabled; + int32 ReportCount; + FDelegateHandle CheckpointTicker; + FDelegateHandle ReportTicker; + FMallocLeakReportDelegate ReportDelegate; + + // Report vars + FMallocLeakReportOptions DefaultLeakReportOptions; + FMallocLeakReportOptions DefaultAllocReportOptions; + +}; + diff --git a/Engine/Source/Runtime/Engine/Public/ReferenceSkeleton.h b/Engine/Source/Runtime/Engine/Public/ReferenceSkeleton.h index a4628e2f2a7d..a3915c41c703 100644 --- a/Engine/Source/Runtime/Engine/Public/ReferenceSkeleton.h +++ b/Engine/Source/Runtime/Engine/Public/ReferenceSkeleton.h @@ -153,9 +153,13 @@ private: int32 GetParentIndexInternal(const int32 BoneIndex, const TArray& BoneInfo) const { - // Parent must be valid. Either INDEX_NONE for Root, or before us. - checkSlow(((BoneIndex == 0) && (BoneInfo[BoneIndex].ParentIndex == INDEX_NONE)) || ((BoneIndex > 0) && BoneInfo.IsValidIndex(BoneInfo[BoneIndex].ParentIndex))); - return BoneInfo[BoneIndex].ParentIndex; + const int32 ParentIndex = BoneInfo[BoneIndex].ParentIndex; + + // Parent must be valid. Either INDEX_NONE for Root, or before children for non root bones. + checkSlow(((BoneIndex == 0) && (ParentIndex == INDEX_NONE)) + || ((BoneIndex > 0) && BoneInfo.IsValidIndex(ParentIndex) && (ParentIndex < BoneIndex))); + + return ParentIndex; } void UpdateRefPoseTransform(const int32 BoneIndex, const FTransform& BonePose) @@ -180,8 +184,9 @@ private: // Normalize Quaternion to be safe. RawRefBonePose[BoneIndex].NormalizeRotation(); - // Parent must be valid. Either INDEX_NONE for Root, or before us. - check(((BoneIndex == 0) && (BoneInfo.ParentIndex == INDEX_NONE)) || ((BoneIndex > 0) && RawRefBoneInfo.IsValidIndex(BoneInfo.ParentIndex))); + // Parent must be valid. Either INDEX_NONE for Root, or before children for non root bones. + check(((BoneIndex == 0) && (BoneInfo.ParentIndex == INDEX_NONE)) + || ((BoneIndex > 0) && RawRefBoneInfo.IsValidIndex(BoneInfo.ParentIndex) && (BoneInfo.ParentIndex < BoneIndex))); } // Help us translate a virtual bone source into a raw bone source (for evaluating virtual bone transform) diff --git a/Engine/Source/Runtime/Engine/Public/SaveGameSystem.h b/Engine/Source/Runtime/Engine/Public/SaveGameSystem.h index d1d5dbd23e91..6869e771a23b 100644 --- a/Engine/Source/Runtime/Engine/Public/SaveGameSystem.h +++ b/Engine/Source/Runtime/Engine/Public/SaveGameSystem.h @@ -16,12 +16,25 @@ class ISaveGameSystem { public: + // Possible result codes when using DoesSaveGameExist. + // Not all codes are guaranteed to be returned on all platforms. + enum class ESaveExistsResult + { + OK, // Operation on the file completely successfully. + DoesNotExist, // Operation on the file failed, because the file was not found / does not exist. + Corrupt, // Operation on the file failed, because the file was corrupt. + UnspecifiedError // Operation on the file failed due to an unspecified error. + }; + /** Returns true if the platform has a native UI (like many consoles) */ virtual bool PlatformHasNativeUI() = 0; /** Return true if the named savegame exists (probably not useful with NativeUI */ virtual bool DoesSaveGameExist(const TCHAR* Name, const int32 UserIndex) = 0; + /** Similar to DoesSaveGameExist, except returns a result code with more information. */ + virtual ESaveExistsResult DoesSaveGameExistWithResult(const TCHAR* Name, const int32 UserIndex) = 0; + /** Saves the game, blocking until complete. Platform may use FGameDelegates to get more information from the game */ virtual bool SaveGame(bool bAttemptToUseUI, const TCHAR* Name, const int32 UserIndex, const TArray& Data) = 0; @@ -42,9 +55,18 @@ public: return false; } + virtual ESaveExistsResult DoesSaveGameExistWithResult(const TCHAR* Name, const int32 UserIndex) override + { + if (IFileManager::Get().FileSize(*GetSaveGamePath(Name)) >= 0) + { + return ESaveExistsResult::OK; + } + return ESaveExistsResult::DoesNotExist; + } + virtual bool DoesSaveGameExist(const TCHAR* Name, const int32 UserIndex) override { - return IFileManager::Get().FileSize(*GetSaveGamePath(Name)) >= 0; + return ESaveExistsResult::OK == DoesSaveGameExistWithResult(Name, UserIndex); } virtual bool SaveGame(bool bAttemptToUseUI, const TCHAR* Name, const int32 UserIndex, const TArray& Data) override diff --git a/Engine/Source/Runtime/Engine/Public/SceneManagement.h b/Engine/Source/Runtime/Engine/Public/SceneManagement.h index 2945749adff4..07d00e872ec8 100644 --- a/Engine/Source/Runtime/Engine/Public/SceneManagement.h +++ b/Engine/Source/Runtime/Engine/Public/SceneManagement.h @@ -599,6 +599,10 @@ public: { } + virtual ~FLightCacheInterface() + { + } + // @param LightSceneProxy must not be 0 virtual FLightInteraction GetInteraction(const class FLightSceneProxy* LightSceneProxy) const = 0; @@ -664,9 +668,11 @@ private: TPendingTextureType* PendingTexture; FThreadSafeCounter& Counter; ULevel* LightingScenario; + class ITextureCompressorModule* Compressor; + public: - FAsyncEncode(TPendingTextureType* InPendingTexture, ULevel* InLightingScenario, FThreadSafeCounter& InCounter) : PendingTexture(nullptr), Counter(InCounter) + FAsyncEncode(TPendingTextureType* InPendingTexture, ULevel* InLightingScenario, FThreadSafeCounter& InCounter, ITextureCompressorModule* InCompressor) : PendingTexture(nullptr), Counter(InCounter), Compressor(InCompressor) { LightingScenario = InLightingScenario; PendingTexture = InPendingTexture; @@ -674,13 +680,13 @@ public: void Abandon() { - PendingTexture->StartEncoding(LightingScenario); + PendingTexture->StartEncoding(LightingScenario, Compressor); Counter.Decrement(); } void DoThreadedWork() { - PendingTexture->StartEncoding(LightingScenario); + PendingTexture->StartEncoding(LightingScenario, Compressor); Counter.Decrement(); } }; @@ -810,7 +816,7 @@ public: inline bool DoesPlatformSupportDistanceFieldShadowing(EShaderPlatform Platform) { // Hasn't been tested elsewhere yet - return Platform == SP_PCD3D_SM5 || Platform == SP_PS4 || Platform == SP_METAL_SM5 || Platform == SP_XBOXONE; + return Platform == SP_PCD3D_SM5 || Platform == SP_PS4 || Platform == SP_METAL_SM5 || Platform == SP_XBOXONE_D3D12 || Platform == SP_XBOXONE_D3D11; } /** Represents a USkyLightComponent to the rendering thread. */ @@ -1410,6 +1416,10 @@ public: View(InView) {} + virtual ~FPrimitiveDrawInterface() + { + } + virtual bool IsHitTesting() = 0; virtual void SetHitProxy(HHitProxy* HitProxy) = 0; @@ -1476,6 +1486,7 @@ public: class FStaticPrimitiveDrawInterface { public: + virtual ~FStaticPrimitiveDrawInterface() { } virtual void SetHitProxy(HHitProxy* HitProxy) = 0; virtual void DrawMesh( const FMeshBatch& Mesh, @@ -1911,7 +1922,7 @@ private: // 10x10 tessellated plane at x=-1..1 y=-1...1 z=0 extern ENGINE_API void DrawPlane10x10(class FPrimitiveDrawInterface* PDI,const FMatrix& ObjectToWorld,float Radii,FVector2D UVMin, FVector2D UVMax,const FMaterialRenderProxy* MaterialRenderProxy,uint8 DepthPriority); extern ENGINE_API void DrawBox(class FPrimitiveDrawInterface* PDI,const FMatrix& BoxToWorld,const FVector& Radii,const FMaterialRenderProxy* MaterialRenderProxy,uint8 DepthPriority); -extern ENGINE_API void DrawSphere(class FPrimitiveDrawInterface* PDI,const FVector& Center,const FVector& Radii,int32 NumSides,int32 NumRings,const FMaterialRenderProxy* MaterialRenderProxy,uint8 DepthPriority,bool bDisableBackfaceCulling=false); +extern ENGINE_API void DrawSphere(class FPrimitiveDrawInterface* PDI,const FVector& Center,const FRotator& Orientation,const FVector& Radii,int32 NumSides,int32 NumRings,const FMaterialRenderProxy* MaterialRenderProxy,uint8 DepthPriority,bool bDisableBackfaceCulling=false); extern ENGINE_API void DrawCone(class FPrimitiveDrawInterface* PDI,const FMatrix& ConeToWorld, float Angle1, float Angle2, int32 NumSides, bool bDrawSideLines, const FLinearColor& SideLineColor, const FMaterialRenderProxy* MaterialRenderProxy, uint8 DepthPriority); extern ENGINE_API void DrawCylinder(class FPrimitiveDrawInterface* PDI,const FVector& Base, const FVector& XAxis, const FVector& YAxis, const FVector& ZAxis, diff --git a/Engine/Source/Runtime/Engine/Public/SceneTypes.h b/Engine/Source/Runtime/Engine/Public/SceneTypes.h index 94c2d1595f5e..9dcce713feb0 100644 --- a/Engine/Source/Runtime/Engine/Public/SceneTypes.h +++ b/Engine/Source/Runtime/Engine/Public/SceneTypes.h @@ -3,6 +3,7 @@ #pragma once #include "CoreMinimal.h" +#include "ObjectMacros.h" #include "Templates/RefCounting.h" #include "Containers/List.h" @@ -126,7 +127,7 @@ namespace EMaterialQualityLevel // // EMaterialProperty // - +UENUM(BlueprintType) enum EMaterialProperty { MP_EmissiveColor = 0, diff --git a/Engine/Source/Runtime/Engine/Public/SceneUtils.h b/Engine/Source/Runtime/Engine/Public/SceneUtils.h index 20208825c113..e82285191a22 100644 --- a/Engine/Source/Runtime/Engine/Public/SceneUtils.h +++ b/Engine/Source/Runtime/Engine/Public/SceneUtils.h @@ -252,6 +252,16 @@ public: }; #endif // HAS_GPU_STATS +enum class EMobileHDRMode +{ + Unset, + Disabled, + EnabledFloat16, + EnabledMosaic, + EnabledRGBE, + EnabledRGBA8 +}; + /** True if HDR is enabled for the mobile renderer. */ ENGINE_API bool IsMobileHDR(); @@ -261,6 +271,8 @@ ENGINE_API bool IsMobileHDR32bpp(); /** True if the mobile renderer is emulating HDR with mosaic. */ ENGINE_API bool IsMobileHDRMosaic(); +ENGINE_API EMobileHDRMode GetMobileHDRMode(); + /** * A pool of render (e.g. occlusion/timer) queries which are allocated individually, and returned to the pool as a group. */ diff --git a/Engine/Source/Runtime/Engine/Public/SceneView.h b/Engine/Source/Runtime/Engine/Public/SceneView.h index d752b45410cf..ed04e9ef3a9a 100644 --- a/Engine/Source/Runtime/Engine/Public/SceneView.h +++ b/Engine/Source/Runtime/Engine/Public/SceneView.h @@ -24,7 +24,6 @@ class FSceneViewStateInterface; class FViewElementDrawer; class ISceneViewExtension; class FSceneViewFamily; -class FForwardLightingViewResources; class FVolumetricFogViewResources; // Projection data for a FSceneView @@ -713,6 +712,7 @@ BEGIN_UNIFORM_BUFFER_STRUCT_WITH_CONSTRUCTOR(FViewUniformShaderParameters, ENGIN DECLARE_UNIFORM_BUFFER_STRUCT_MEMBER_SAMPLER(SamplerState, PerlinNoiseGradientTextureSampler) DECLARE_UNIFORM_BUFFER_STRUCT_MEMBER_TEXTURE(Texture3D, PerlinNoise3DTexture) DECLARE_UNIFORM_BUFFER_STRUCT_MEMBER_SAMPLER(SamplerState, PerlinNoise3DTextureSampler) + DECLARE_UNIFORM_BUFFER_STRUCT_MEMBER_TEXTURE(Texture2D, SobolSamplingTexture) END_UNIFORM_BUFFER_STRUCT(FViewUniformShaderParameters) @@ -1427,6 +1427,8 @@ public: { return MonoParameters.bEnabled && MonoParameters.Mode != EMonoscopicFarFieldMode::Off; } + + bool AllowTranslucencyAfterDOF() const; }; /** diff --git a/Engine/Source/Runtime/Engine/Public/SingleAnimationPlayData.h b/Engine/Source/Runtime/Engine/Public/SingleAnimationPlayData.h index b94500dad092..36d758ee7082 100644 --- a/Engine/Source/Runtime/Engine/Public/SingleAnimationPlayData.h +++ b/Engine/Source/Runtime/Engine/Public/SingleAnimationPlayData.h @@ -8,7 +8,7 @@ class UAnimSingleNodeInstance; -USTRUCT() +USTRUCT(BlueprintType) struct FSingleAnimationPlayData { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/Engine/Public/SkeletalMeshTypes.h b/Engine/Source/Runtime/Engine/Public/SkeletalMeshTypes.h index c40f8514f832..81c7907c8cb2 100644 --- a/Engine/Source/Runtime/Engine/Public/SkeletalMeshTypes.h +++ b/Engine/Source/Runtime/Engine/Public/SkeletalMeshTypes.h @@ -1095,48 +1095,78 @@ private: class FMorphTargetVertexInfoBuffers : public FRenderResource { public: - FMorphTargetVertexInfoBuffers() - : NumInfluencedVerticesByMorphs(0) + FMorphTargetVertexInfoBuffers() : NumTotalWorkItems(0) { } ENGINE_API virtual void InitRHI() override; ENGINE_API virtual void ReleaseRHI() override; - uint32 GetNumInfluencedVerticesByMorphs() const + uint32 GetNumWorkItems(uint32 index = UINT_MAX) const { - return NumInfluencedVerticesByMorphs; + check(index == UINT_MAX || index < (uint32)WorkItemsPerMorph.Num()); + return index != UINT_MAX ? WorkItemsPerMorph[index] : NumTotalWorkItems; } - FVertexBufferRHIRef PerVertexInfoVB; - FShaderResourceViewRHIRef PerVertexInfoSRV; + uint32 GetNumMorphs() const + { + return WorkItemsPerMorph.Num(); + } - FVertexBufferRHIRef FlattenedDeltasVB; - FShaderResourceViewRHIRef FlattenedDeltasSRV; + uint32 GetStartOffset(uint32 Index) const + { + check(Index < (uint32)StartOffsetPerMorph.Num()); + return StartOffsetPerMorph[Index]; + } + + const FVector4& GetMaximumMorphScale(uint32 Index) const + { + check(Index < (uint32)MaximumValuePerMorph.Num()); + return MaximumValuePerMorph[Index]; + } + + const FVector4& GetMinimumMorphScale(uint32 Index) const + { + check(Index < (uint32)MinimumValuePerMorph.Num()); + return MinimumValuePerMorph[Index]; + } + + FVertexBufferRHIRef VertexIndicesVB; + FShaderResourceViewRHIRef VertexIndicesSRV; + + FVertexBufferRHIRef MorphDeltasVB; + FShaderResourceViewRHIRef MorphDeltasSRV; // Changes to this struct must be reflected in MorphTargets.usf - struct FPerVertexInfo + struct FMorphDelta { - uint32 DestVertexIndex; - uint32 StartDelta; - uint32 NumDeltas; - }; + FMorphDelta(FVector InPosDelta, FVector InTangentDelta) + { + PosDelta[0] = FFloat16(InPosDelta.X); + PosDelta[1] = FFloat16(InPosDelta.Y); + PosDelta[2] = FFloat16(InPosDelta.Z); - // Changes to this struct must be reflected in MorphTargets.usf - struct FFlattenedDelta - { - FVector PosDelta; - FVector TangentDelta; - uint32 WeightIndex; + TangentDelta[0] = FFloat16(InTangentDelta.X); + TangentDelta[1] = FFloat16(InTangentDelta.Y); + TangentDelta[2] = FFloat16(InTangentDelta.Z); + } + + FFloat16 PosDelta[3]; + FFloat16 TangentDelta[3]; }; protected: // Transient data used while creating the vertex buffers, gets deleted as soon as VB gets initialized. - TArray PerVertexInfoList; + TArray VertexIndices; // Transient data used while creating the vertex buffers, gets deleted as soon as VB gets initialized. - TArray FlattenedDeltaList; - // Transient data used while creating the vertex buffers, gets deleted as soon as VB gets initialized. - uint32 NumInfluencedVerticesByMorphs; + TArray MorphDeltas; + + //x,y,y separate for position and shared w for tangent + TArray MaximumValuePerMorph; + TArray MinimumValuePerMorph; + TArray StartOffsetPerMorph; + TArray WorkItemsPerMorph; + uint32 NumTotalWorkItems; friend class FStaticLODModel; }; diff --git a/Engine/Source/Runtime/Engine/Public/Slate/SGameLayerManager.h b/Engine/Source/Runtime/Engine/Public/Slate/SGameLayerManager.h index c2dd48e2176d..44f9b5b3edca 100644 --- a/Engine/Source/Runtime/Engine/Public/Slate/SGameLayerManager.h +++ b/Engine/Source/Runtime/Engine/Public/Slate/SGameLayerManager.h @@ -51,6 +51,7 @@ class IGameLayerManager { public: virtual const FGeometry& GetViewportWidgetHostGeometry() const = 0; + virtual const FGeometry& GetPlayerWidgetHostGeometry(ULocalPlayer* Player) const = 0; virtual void NotifyPlayerAdded(int32 PlayerIndex, ULocalPlayer* AddedPlayer) = 0; virtual void NotifyPlayerRemoved(int32 PlayerIndex, ULocalPlayer* RemovedPlayer) = 0; @@ -102,6 +103,7 @@ public: // Begin IGameLayerManager virtual const FGeometry& GetViewportWidgetHostGeometry() const override; + virtual const FGeometry& GetPlayerWidgetHostGeometry(ULocalPlayer* Player) const override; virtual void NotifyPlayerAdded(int32 PlayerIndex, ULocalPlayer* AddedPlayer) override; virtual void NotifyPlayerRemoved(int32 PlayerIndex, ULocalPlayer* RemovedPlayer) override; diff --git a/Engine/Source/Runtime/Engine/Public/Slate/SceneViewport.h b/Engine/Source/Runtime/Engine/Public/Slate/SceneViewport.h index 70d191841188..580cf2b0f6b9 100644 --- a/Engine/Source/Runtime/Engine/Public/Slate/SceneViewport.h +++ b/Engine/Source/Runtime/Engine/Public/Slate/SceneViewport.h @@ -52,6 +52,7 @@ public: virtual bool IsSoftwareCursorVisible() const override { return bIsSoftwareCursorVisible; } virtual FVector2D GetSoftwareCursorPosition() const override { return SoftwareCursorPosition; } virtual FCanvas* GetDebugCanvas() override; + virtual float GetDisplayGamma() const override; /** Gets the proper RenderTarget based on the current thread*/ virtual const FTexture2DRHIRef& GetRenderTargetTexture() const; @@ -257,6 +258,13 @@ public: /** Get the cached viewport geometry. */ const FGeometry& GetCachedGeometry() const { return CachedGeometry; } + + /** Set an optional display gamma to use for this viewport */ + void SetGammaOverride(const float InGammaOverride) + { + ViewportGammaOverride = InGammaOverride; + }; + private: /** * Called when this viewport is destroyed @@ -420,4 +428,7 @@ private: /** Tracks the number of touches currently active on the viewport */ int32 NumTouches; + + /** The optional gamma value to use for this viewport */ + TOptional ViewportGammaOverride; }; diff --git a/Engine/Source/Runtime/Engine/Public/TextureResource.h b/Engine/Source/Runtime/Engine/Public/TextureResource.h index 8ea97fd7ecc6..0d4508b1758e 100644 --- a/Engine/Source/Runtime/Engine/Public/TextureResource.h +++ b/Engine/Source/Runtime/Engine/Public/TextureResource.h @@ -249,7 +249,7 @@ public: * Called from the game thread to kick off a change in ResidentMips after modifying RequestedMips. * @param bShouldPrioritizeAsyncIORequest - Whether the Async I/O request should have higher priority */ - void BeginUpdateMipCount( bool bShouldPrioritizeAsyncIORequest ); + ENGINE_API void BeginUpdateMipCount( bool bShouldPrioritizeAsyncIORequest ); /** * Called from the game thread to kick off async I/O to load in new mips. */ diff --git a/Engine/Source/Runtime/Engine/Public/UpdateTextureShaders.h b/Engine/Source/Runtime/Engine/Public/UpdateTextureShaders.h index 4d3a6ab71e26..093fd60e0ca3 100644 --- a/Engine/Source/Runtime/Engine/Public/UpdateTextureShaders.h +++ b/Engine/Source/Runtime/Engine/Public/UpdateTextureShaders.h @@ -95,13 +95,14 @@ public: { SrcTexture.Bind(Initializer.ParameterMap, TEXT("SrcTexture"), SPF_Mandatory); DestTexture.Bind(Initializer.ParameterMap, TEXT("DestTexture"), SPF_Mandatory); + DestPosSize.Bind(Initializer.ParameterMap, TEXT("DestPosSize"), SPF_Mandatory); } // FShader interface. virtual bool Serialize(FArchive& Ar) override { bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar); - Ar << SrcTexture << DestTexture; + Ar << SrcTexture << DestTexture << DestPosSize; return bShaderHasOutdatedParameters; } @@ -113,6 +114,7 @@ public: //protected: FShaderResourceParameter SrcTexture; FShaderResourceParameter DestTexture; + FShaderParameter DestPosSize; }; template diff --git a/Engine/Source/Runtime/Engine/Public/VisualLogger/VisualLoggerTypes.h b/Engine/Source/Runtime/Engine/Public/VisualLogger/VisualLoggerTypes.h index 8f0aab6ffcec..acf9f895053f 100644 --- a/Engine/Source/Runtime/Engine/Public/VisualLogger/VisualLoggerTypes.h +++ b/Engine/Source/Runtime/Engine/Public/VisualLogger/VisualLoggerTypes.h @@ -247,7 +247,7 @@ public: FVisualLogEntry Entry; }; - + virtual ~FVisualLogDevice() { } virtual void Serialize(const UObject* LogOwner, FName OwnerName, FName InOwnerClassName, const FVisualLogEntry& LogEntry) = 0; virtual void Cleanup(bool bReleaseMemory = false) { /* Empty */ } virtual void StartRecordingToFile(float TImeStamp) { /* Empty */ } @@ -300,6 +300,8 @@ struct IVisualLoggerEditorInterface class FVisualLogExtensionInterface { public: + virtual ~FVisualLogExtensionInterface() { } + virtual void ResetData(IVisualLoggerEditorInterface* EdInterface) = 0; virtual void DrawData(IVisualLoggerEditorInterface* EdInterface, UCanvas* Canvas) = 0; diff --git a/Engine/Source/Runtime/Engine/Public/WeightedRandomSampler.h b/Engine/Source/Runtime/Engine/Public/WeightedRandomSampler.h index eeda155c7dcd..ac1f3d4d4c7b 100644 --- a/Engine/Source/Runtime/Engine/Public/WeightedRandomSampler.h +++ b/Engine/Source/Runtime/Engine/Public/WeightedRandomSampler.h @@ -28,6 +28,7 @@ struct ENGINE_API FWeightedRandomSampler { public: FWeightedRandomSampler(); + virtual ~FWeightedRandomSampler() { } /** Gets the weight of all elements and returns their sum. */ virtual float GetWeights(TArray& OutWeights) = 0; diff --git a/Engine/Source/Runtime/Engine/Public/WeightedRandomSampler.tps b/Engine/Source/Runtime/Engine/Public/WeightedRandomSampler.tps new file mode 100644 index 000000000000..516bb8cb34fd --- /dev/null +++ b/Engine/Source/Runtime/Engine/Public/WeightedRandomSampler.tps @@ -0,0 +1,15 @@ + + + Alias method algorithm from Darts, Dice, and Coins site + /Engine/Source/Runtime/Engine/Private/WeightedRandomSampler.cpp + 2017-01-20T14:01:08.4868419+00:00 + Algorithm which allows weighted random sampling of elements in constant time + Initially for sampling meshes for particle systesm. Will likely use it for other things in future. + http://www.keithschwarz.com/darts-dice-coins/ + + Licensees + Git + P4 + + None + \ No newline at end of file diff --git a/Engine/Source/Runtime/Engine/Public/WorldCollision.h b/Engine/Source/Runtime/Engine/Public/WorldCollision.h index f630bb75a919..c029571dec63 100644 --- a/Engine/Source/Runtime/Engine/Public/WorldCollision.h +++ b/Engine/Source/Runtime/Engine/Public/WorldCollision.h @@ -275,6 +275,11 @@ struct FCollisionParameters /** Contains Collision Shape data including dimension of the shape **/ struct FCollisionShape CollisionShape; + + FCollisionParameters() + : CollisionQueryParam(NAME_None, TStatId()) + { + } }; /** diff --git a/Engine/Source/Runtime/Foliage/Private/FoliageInstanceBase.cpp b/Engine/Source/Runtime/Foliage/Private/FoliageInstanceBase.cpp index d77de6af3036..4b481cfd79cc 100644 --- a/Engine/Source/Runtime/Foliage/Private/FoliageInstanceBase.cpp +++ b/Engine/Source/Runtime/Foliage/Private/FoliageInstanceBase.cpp @@ -140,12 +140,16 @@ FFoliageInstanceBaseId FFoliageInstanceBaseCache::AddInstanceBaseId(UActorCompon FFoliageInstanceBaseId FFoliageInstanceBaseCache::GetInstanceBaseId(UActorComponent* InComponent) const { - FFoliageInstanceBasePtr BasePtr(InComponent); - if (!BasePtr.IsValid()) + if(InstanceBaseInvMap.Num() > 0) { - return InvalidBaseId; + FFoliageInstanceBasePtr BasePtr(InComponent); + if (BasePtr.IsValid()) + { + return GetInstanceBaseId(BasePtr); + } } - return GetInstanceBaseId(BasePtr); + + return InvalidBaseId; } FFoliageInstanceBaseId FFoliageInstanceBaseCache::GetInstanceBaseId(const FFoliageInstanceBasePtr& BasePtr) const diff --git a/Engine/Source/Runtime/Foliage/Private/InstancedFoliage.cpp b/Engine/Source/Runtime/Foliage/Private/InstancedFoliage.cpp index 6012fd2ef941..20ee0e92c1ac 100644 --- a/Engine/Source/Runtime/Foliage/Private/InstancedFoliage.cpp +++ b/Engine/Source/Runtime/Foliage/Private/InstancedFoliage.cpp @@ -40,6 +40,7 @@ InstancedFoliage.cpp: Instanced foliage implementation. #include "EngineUtils.h" #include "EngineGlobals.h" #include "Engine/StaticMesh.h" +#include "DrawDebugHelpers.h" #define LOCTEXT_NAMESPACE "InstancedFoliage" @@ -605,6 +606,19 @@ void UFoliageType::PostEditChangeProperty(struct FPropertyChangedEvent& Property } } +void UFoliageType::PreEditChange(UProperty* PropertyAboutToChange) +{ + Super::PreEditChange(PropertyAboutToChange); + + if (PropertyAboutToChange && PropertyAboutToChange->GetFName() == GET_MEMBER_NAME_CHECKED(UFoliageType_InstancedStaticMesh, Mesh)) + { + for (TObjectIterator It(RF_ClassDefaultObject, /** bIncludeDerivedClasses */ true, /** InternalExcludeFalgs */ EInternalObjectFlags::PendingKill); It; ++It) + { + It->NotifyFoliageTypeWillChange(this, true); + } + } +} + void UFoliageType::OnHiddenEditorViewMaskChanged(UWorld* InWorld) { for (TActorIterator It(InWorld); It; ++It) @@ -655,6 +669,9 @@ FFoliageMeshInfo::FFoliageMeshInfo() #endif { } +FFoliageMeshInfo::~FFoliageMeshInfo() +{ } + #if WITH_EDITOR @@ -747,6 +764,7 @@ void FFoliageMeshInfo::CreateNewComponent(AInstancedFoliageActor* InIFA, const U Component->bSelectable = true; Component->bHasPerInstanceHitProxies = true; Component->InstancingRandomSeed = FMath::Rand(); + Component->GetStaticMesh()->GetOnExtendedBoundsChanged().AddRaw(this, &FFoliageMeshInfo::HandleComponentMeshBoundsChanged); #if WITH_EDITOR FoliageComponent->FoliageHiddenEditorViews = InSettings->HiddenEditorViews; @@ -762,7 +780,7 @@ void FFoliageMeshInfo::CreateNewComponent(AInstancedFoliageActor* InIFA, const U } // Use only instance translation as a component transform - Component->SetWorldTransform(InIFA->GetRootComponent()->ComponentToWorld); + Component->SetWorldTransform(InIFA->GetRootComponent()->GetComponentTransform()); // Add the new component to the transaction buffer so it will get destroyed on undo Component->Modify(); @@ -770,6 +788,14 @@ void FFoliageMeshInfo::CreateNewComponent(AInstancedFoliageActor* InIFA, const U Component->ClearFlags(RF_Transactional); } +void FFoliageMeshInfo::HandleComponentMeshBoundsChanged(const FBoxSphereBounds& NewBounds) +{ + if (Component != nullptr) + { + Component->BuildTreeIfOutdated(true, false); + } +} + void FFoliageMeshInfo::CheckComponentClass(AInstancedFoliageActor* InIFA, const UFoliageType* InSettings) { if (Component) @@ -975,14 +1001,14 @@ void FFoliageMeshInfo::UpdateComponentSettings(const UFoliageType* InSettings) } } -void FFoliageMeshInfo::AddInstance(AInstancedFoliageActor* InIFA, const UFoliageType* InSettings, const FFoliageInstance& InNewInstance, UActorComponent* InBaseComponent) +void FFoliageMeshInfo::AddInstance(AInstancedFoliageActor* InIFA, const UFoliageType* InSettings, const FFoliageInstance& InNewInstance, UActorComponent* InBaseComponent, bool RebuildFoliageTree) { FFoliageInstance Instance = InNewInstance; Instance.BaseId = InIFA->InstanceBaseCache.AddInstanceBaseId(InBaseComponent); - AddInstance(InIFA, InSettings, Instance); + AddInstance(InIFA, InSettings, Instance, RebuildFoliageTree); } -void FFoliageMeshInfo::AddInstance(AInstancedFoliageActor* InIFA, const UFoliageType* InSettings, const FFoliageInstance& InNewInstance) +void FFoliageMeshInfo::AddInstance(AInstancedFoliageActor* InIFA, const UFoliageType* InSettings, const FFoliageInstance& InNewInstance, bool RebuildFoliageTree) { InIFA->Modify(); @@ -996,6 +1022,9 @@ void FFoliageMeshInfo::AddInstance(AInstancedFoliageActor* InIFA, const UFoliage Component->InvalidateLightingCache(); } + bool PreviousbAutoRebuildTreeOnInstanceChanges = Component->bAutoRebuildTreeOnInstanceChanges; + Component->bAutoRebuildTreeOnInstanceChanges = RebuildFoliageTree; + // Add the instance taking either a free slot or adding a new item. int32 InstanceIndex = Instances.Add(InNewInstance); FFoliageInstance& AddedInstance = Instances[InstanceIndex]; @@ -1010,15 +1039,21 @@ void FFoliageMeshInfo::AddInstance(AInstancedFoliageActor* InIFA, const UFoliage Component->AddInstanceWorldSpace(InstanceToWorld); CheckValid(); + + Component->bAutoRebuildTreeOnInstanceChanges = PreviousbAutoRebuildTreeOnInstanceChanges; } -void FFoliageMeshInfo::RemoveInstances(AInstancedFoliageActor* InIFA, const TArray& InInstancesToRemove) +void FFoliageMeshInfo::RemoveInstances(AInstancedFoliageActor* InIFA, const TArray& InInstancesToRemove, bool RebuildFoliageTree) { if (InInstancesToRemove.Num()) { check(Component); InIFA->Modify(); + bool PreviousbAutoRebuildTreeOnInstanceChanges = Component->bAutoRebuildTreeOnInstanceChanges; + Component->bAutoRebuildTreeOnInstanceChanges = RebuildFoliageTree; + + TSet InstancesToRemove; for (int32 Instance : InInstancesToRemove) { @@ -1082,6 +1117,13 @@ void FFoliageMeshInfo::RemoveInstances(AInstancedFoliageActor* InIFA, const TArr // Remove the removed item from the removal list InstancesToRemove.Remove(InstanceIndexToRemove); } + + Component->bAutoRebuildTreeOnInstanceChanges = PreviousbAutoRebuildTreeOnInstanceChanges; + + if (RebuildFoliageTree) + { + Component->BuildTreeIfOutdated(true, true); + } CheckValid(); } @@ -1133,10 +1175,21 @@ void FFoliageMeshInfo::PostMoveInstances(AInstancedFoliageActor* InIFA, const TA void FFoliageMeshInfo::DuplicateInstances(AInstancedFoliageActor* InIFA, UFoliageType* InSettings, const TArray& InInstancesToDuplicate) { + if (Component != nullptr) + { + Component->bAutoRebuildTreeOnInstanceChanges = false; + } + for (int32 InstanceIndex : InInstancesToDuplicate) { const FFoliageInstance TempInstance = Instances[InstanceIndex]; - AddInstance(InIFA, InSettings, TempInstance); + AddInstance(InIFA, InSettings, TempInstance, false); + } + + if (Component != nullptr) + { + Component->bAutoRebuildTreeOnInstanceChanges = true; + Component->BuildTreeIfOutdated(true, true); } } @@ -1196,9 +1249,14 @@ void FFoliageMeshInfo::ReallocateClusters(AInstancedFoliageActor* InIFA, UFoliag { if ((Instance.Flags & FOLIAGE_InstanceDeleted) == 0) { - AddInstance(InIFA, InSettings, Instance); + AddInstance(InIFA, InSettings, Instance, false); } } + + if (Component != nullptr) + { + Component->BuildTreeIfOutdated(true, true); + } } void FFoliageMeshInfo::ReapplyInstancesToComponent() @@ -1212,11 +1270,16 @@ void FFoliageMeshInfo::ReapplyInstancesToComponent() Component->UnregisterComponent(); Component->ClearInstances(); + Component->bAutoRebuildTreeOnInstanceChanges = false; + for (auto& Instance : Instances) { Component->AddInstanceWorldSpace(Instance.GetInstanceWorldTransform()); } + Component->bAutoRebuildTreeOnInstanceChanges = true; + Component->BuildTreeIfOutdated(true, true); + Component->ClearInstanceSelection(); if (SelectedIndices.Num()) @@ -1331,6 +1394,8 @@ void FFoliageMeshInfo::SelectInstances(AInstancedFoliageActor* InIFA, bool bSele { InIFA->Modify(); + SelectedIndices.Reserve(InInstances.Num()); + for (int32 i : InInstances) { SelectedIndices.Add(i); @@ -1611,7 +1676,7 @@ void AInstancedFoliageActor::DeleteInstancesForComponent(UActorComponent* InComp const auto* InstanceSet = MeshInfo.ComponentHash.Find(BaseId); if (InstanceSet) { - MeshInfo.RemoveInstances(this, InstanceSet->Array()); + MeshInfo.RemoveInstances(this, InstanceSet->Array(), true); } } } @@ -1631,7 +1696,7 @@ void AInstancedFoliageActor::DeleteInstancesForComponent(UActorComponent* InComp const auto* InstanceSet = MeshInfo->ComponentHash.Find(BaseId); if (InstanceSet) { - MeshInfo->RemoveInstances(this, InstanceSet->Array()); + MeshInfo->RemoveInstances(this, InstanceSet->Array(), true); } } } @@ -1663,7 +1728,7 @@ void AInstancedFoliageActor::DeleteInstancesForProceduralFoliageComponent(const if (InstancesToRemove.Num()) { - MeshInfo.RemoveInstances(this, InstancesToRemove); + MeshInfo.RemoveInstances(this, InstancesToRemove, true); } } } @@ -1724,11 +1789,13 @@ void AInstancedFoliageActor::MoveInstancesForComponentToCurrentLevel(UActorCompo // Add the foliage to the new level for (int32 InstanceIndex : *InstanceSet) { - TargetMeshInfo->AddInstance(NewIFA, TargetFoliageType, MeshInfo.Instances[InstanceIndex], InComponent); + TargetMeshInfo->AddInstance(NewIFA, TargetFoliageType, MeshInfo.Instances[InstanceIndex], InComponent, false); } + TargetMeshInfo->Component->BuildTreeIfOutdated(true, true); + // Remove from old level - MeshInfo.RemoveInstances(IFA, InstanceSet->Array()); + MeshInfo.RemoveInstances(IFA, InstanceSet->Array(), true); } } } @@ -1777,11 +1844,16 @@ void AInstancedFoliageActor::MoveInstancesToNewComponent(UPrimitiveComponent* In { FFoliageInstance NewInstance = MeshInfo.Instances[InstanceIndex]; NewInstance.BaseId = NewBaseId; - TargetMeshInfo->AddInstance(TargetIFA, TargetFoliageType, NewInstance); + TargetMeshInfo->AddInstance(TargetIFA, TargetFoliageType, NewInstance, false); + } + + if (TargetMeshInfo->Component != nullptr) + { + TargetMeshInfo->Component->BuildTreeIfOutdated(true, true); } // Remove from old level - MeshInfo.RemoveInstances(this, InstanceSet.Array()); + MeshInfo.RemoveInstances(this, InstanceSet.Array(), true); } } } @@ -1823,11 +1895,16 @@ void AInstancedFoliageActor::MoveSelectedInstancesToLevel(ULevel* InTargetLevel) for (int32 InstanceIndex : MeshInfo.SelectedIndices) { FFoliageInstance& Instance = MeshInfo.Instances[InstanceIndex]; - TargetMeshInfo->AddInstance(TargetIFA, TargetFoliageType, Instance, InstanceBaseCache.GetInstanceBasePtr(Instance.BaseId).Get()); + TargetMeshInfo->AddInstance(TargetIFA, TargetFoliageType, Instance, InstanceBaseCache.GetInstanceBasePtr(Instance.BaseId).Get(), false); + } + + if (TargetMeshInfo->Component != nullptr) + { + TargetMeshInfo->Component->BuildTreeIfOutdated(true, true); } // Remove selected instances from this actor - MeshInfo.RemoveInstances(this, MeshInfo.SelectedIndices.Array()); + MeshInfo.RemoveInstances(this, MeshInfo.SelectedIndices.Array(), true); } } } @@ -2013,6 +2090,7 @@ void AInstancedFoliageActor::RemoveFoliageType(UFoliageType** InFoliageTypes, in { if (MeshInfo->Component) { + MeshInfo->Component->GetStaticMesh()->GetOnExtendedBoundsChanged().RemoveAll(MeshInfo); MeshInfo->Component->ClearInstances(); MeshInfo->Component->SetFlags(RF_Transactional); MeshInfo->Component->Modify(); @@ -2104,6 +2182,21 @@ bool AInstancedFoliageActor::HasSelectedInstances() const return false; } +TMap AInstancedFoliageActor::GetSelectedInstancesFoliageType() +{ + TMap SelectedInstanceFoliageTypes; + + for (auto& MeshPair : FoliageMeshes) + { + if (MeshPair.Value->SelectedIndices.Num() > 0) + { + SelectedInstanceFoliageTypes.Add(MeshPair.Key, &MeshPair.Value.Get()); + } + } + + return SelectedInstanceFoliageTypes; +} + void AInstancedFoliageActor::Destroyed() { if (GIsEditor && !GetWorld()->IsGameWorld()) @@ -2262,7 +2355,7 @@ void AInstancedFoliageActor::MapRebuild() FVector End(InstanceToWorld.TransformPosition(Down)); FHitResult Result; - bool bHit = World->LineTraceSingleByObjectType(Result, Start, End, FCollisionObjectQueryParams(ECC_WorldStatic), FCollisionQueryParams(NAME_None, true)); + bool bHit = World->LineTraceSingleByObjectType(Result, Start, End, FCollisionObjectQueryParams(ECC_WorldStatic), FCollisionQueryParams(NAME_None, FCollisionQueryParams::GetUnknownStatId(), true)); if (bHit && Result.Component.IsValid() && Result.Component->IsA(UModelComponent::StaticClass())) { @@ -2288,8 +2381,10 @@ void AInstancedFoliageActor::MapRebuild() FFoliageMeshInfo& MeshInfo = *FindOrAddMesh(Settings); for (FFoliageInstance& Instance : NewInstancePair.Value) { - MeshInfo.AddInstance(this, Settings, Instance); + MeshInfo.AddInstance(this, Settings, Instance, false); } + + MeshInfo.Component->BuildTreeIfOutdated(true, true); } } @@ -2579,9 +2674,11 @@ void AInstancedFoliageActor::RepairDuplicateIFA(AInstancedFoliageActor* Duplicat { if ((Instance.Flags & FOLIAGE_InstanceDeleted) == 0) { - TargetMeshInfo->AddInstance(this, TargetFoliageType, Instance); + TargetMeshInfo->AddInstance(this, TargetFoliageType, Instance, false); } } + + TargetMeshInfo->Component->BuildTreeIfOutdated(true, true); } GetWorld()->DestroyActor(DuplicateIFA); @@ -2605,6 +2702,32 @@ void AInstancedFoliageActor::NotifyFoliageTypeChanged(UFoliageType* FoliageType, { RemoveFoliageType(&FoliageType, 1); } + + // Change bounds delegate bindings + if (TypeInfo->Component != nullptr) + { + TypeInfo->Component->GetStaticMesh()->GetOnExtendedBoundsChanged().AddRaw(TypeInfo, &FFoliageMeshInfo::HandleComponentMeshBoundsChanged); + + // Mesh changed, so we must update the occlusion tree + TypeInfo->Component->BuildTreeIfOutdated(true, false); + } + } + } +} + +void AInstancedFoliageActor::NotifyFoliageTypeWillChange(UFoliageType* FoliageType, bool bMeshChanged) +{ + if (bMeshChanged) + { + FFoliageMeshInfo* TypeInfo = FindMesh(FoliageType); + + // Change bounds delegate bindings + if (TypeInfo) + { + if (TypeInfo->Component != nullptr) + { + TypeInfo->Component->GetStaticMesh()->GetOnExtendedBoundsChanged().RemoveAll(TypeInfo); + } } } } @@ -2685,7 +2808,7 @@ void AInstancedFoliageActor::CleanupDeletedFoliageType() if (InstancesToRemove.Num()) { - MeshInfo.RemoveInstances(this, InstancesToRemove); + MeshInfo.RemoveInstances(this, InstancesToRemove, true); } } @@ -2721,7 +2844,7 @@ void AInstancedFoliageActor::AddReferencedObjects(UObject* InThis, FReferenceCol #if WITH_EDITOR bool AInstancedFoliageActor::FoliageTrace(const UWorld* InWorld, FHitResult& OutHit, const FDesiredFoliageInstance& DesiredInstance, FName InTraceTag, bool InbReturnFaceIndex, const FFoliageTraceFilterFunc& FilterFunc) { - FCollisionQueryParams QueryParams(InTraceTag, true); + FCollisionQueryParams QueryParams(InTraceTag, SCENE_QUERY_STAT_ONLY(IFA_FoliageTrace), true); QueryParams.bReturnFaceIndex = InbReturnFaceIndex; //It's possible that with the radius of the shape we will end up with an initial overlap which would place the instance at the top of the procedural volume. @@ -2819,55 +2942,68 @@ bool AInstancedFoliageActor::FoliageTrace(const UWorld* InWorld, FHitResult& Out return false; } -bool AInstancedFoliageActor::CheckCollisionWithWorld(const UWorld* InWorld, const UFoliageType* Settings, const FFoliageInstance& Inst, const FVector& HitNormal, const FVector& HitLocation) +bool AInstancedFoliageActor::CheckCollisionWithWorld(const UWorld* InWorld, const UFoliageType* Settings, const FFoliageInstance& Inst, const FVector& HitNormal, const FVector& HitLocation, UPrimitiveComponent* HitComponent) { - FMatrix InstTransform = Inst.GetInstanceWorldTransform().ToMatrixWithScale(); - FVector LocalHit = InstTransform.InverseTransformPosition(HitLocation); - - if (Settings->CollisionWithWorld) + if (!Settings->CollisionWithWorld) { - // Check for overhanging ledge + return true; + } + + FTransform OriginalTransform = Inst.GetInstanceWorldTransform(); + OriginalTransform.SetRotation(FQuat::Identity); + + FMatrix InstTransformNoRotation = OriginalTransform.ToMatrixWithScale(); + OriginalTransform = Inst.GetInstanceWorldTransform(); + + // Check for overhanging ledge + const int32 SamplePositionCount = 4; + { + FVector LocalSamplePos[SamplePositionCount] = { + FVector(Settings->LowBoundOriginRadius.Z, 0, 0), + FVector(-Settings->LowBoundOriginRadius.Z, 0, 0), + FVector(0, Settings->LowBoundOriginRadius.Z, 0), + FVector(0, -Settings->LowBoundOriginRadius.Z, 0) + }; + + for (uint32 i = 0; i < SamplePositionCount; ++i) { - FVector LocalSamplePos[4] = { - FVector(Settings->LowBoundOriginRadius.Z, 0, 0), - FVector(-Settings->LowBoundOriginRadius.Z, 0, 0), - FVector(0, Settings->LowBoundOriginRadius.Z, 0), - FVector(0, -Settings->LowBoundOriginRadius.Z, 0) - }; + FVector SamplePos = InstTransformNoRotation.TransformPosition(Settings->LowBoundOriginRadius + LocalSamplePos[i]); + float WorldRadius = (Settings->LowBoundOriginRadius.Z + Settings->LowBoundOriginRadius.Z)*FMath::Max(Inst.DrawScale3D.X, Inst.DrawScale3D.Y); + FVector NormalVector = Settings->AlignToNormal ? HitNormal : OriginalTransform.GetRotation().GetUpVector(); + //::DrawDebugSphere(InWorld, SamplePos, 10, 6, FColor::Red, true, 30.0f); + //::DrawDebugSphere(InWorld, SamplePos - NormalVector*WorldRadius, 10, 6, FColor::Orange, true, 30.0f); + //::DrawDebugDirectionalArrow(InWorld, SamplePos, SamplePos - NormalVector*WorldRadius, 10.0f, FColor::Red, true, 30.0f); - for (uint32 i = 0; i < 4; ++i) + FHitResult Hit; + if (AInstancedFoliageActor::FoliageTrace(InWorld, Hit, FDesiredFoliageInstance(SamplePos, SamplePos - NormalVector*WorldRadius))) { - FHitResult Hit; - FVector SamplePos = InstTransform.TransformPosition(FVector(Settings->LowBoundOriginRadius.X, Settings->LowBoundOriginRadius.Y, 2.f) + LocalSamplePos[i]); - float WorldRadius = (Settings->LowBoundOriginRadius.Z + 2.f)*FMath::Max(Inst.DrawScale3D.X, Inst.DrawScale3D.Y); - FVector NormalVector = Settings->AlignToNormal ? HitNormal : FVector(0, 0, 1); - if (AInstancedFoliageActor::FoliageTrace(InWorld, Hit, FDesiredFoliageInstance(SamplePos, SamplePos - NormalVector*WorldRadius))) + FVector LocalHit = OriginalTransform.InverseTransformPosition(Hit.Location); + + if (LocalHit.Z - Inst.ZOffset < Settings->LowBoundOriginRadius.Z && Hit.Component.Get() == HitComponent) { - if (LocalHit.Z - Inst.ZOffset < Settings->LowBoundOriginRadius.Z) - { - continue; - } + //::DrawDebugSphere(InWorld, Hit.Location, 6, 6, FColor::Green, true, 30.0f); + continue; } - return false; } - } - // Check collision with Bounding Box - { - FBox MeshBox = Settings->MeshBounds.GetBox(); - MeshBox.Min.Z = FMath::Min(MeshBox.Max.Z, LocalHit.Z + Settings->MeshBounds.BoxExtent.Z * 0.05f); - FBoxSphereBounds ShrinkBound(MeshBox); - FBoxSphereBounds WorldBound = ShrinkBound.TransformBy(InstTransform); - //::DrawDebugBox(World, WorldBound.Origin, WorldBound.BoxExtent, FColor::Red, true, 10.f); - static FName NAME_FoliageCollisionWithWorld = FName(TEXT("FoliageCollisionWithWorld")); - if (InWorld->OverlapBlockingTestByChannel(WorldBound.Origin, FQuat(Inst.Rotation), ECC_WorldStatic, FCollisionShape::MakeBox(ShrinkBound.BoxExtent * Inst.DrawScale3D * Settings->CollisionScale), FCollisionQueryParams(NAME_FoliageCollisionWithWorld, false))) - { - return false; - } + //::DrawDebugSphere(InWorld, SamplePos, 6, 6, FColor::Cyan, true, 30.0f); + + return false; } } + FBoxSphereBounds LocalBound(Settings->MeshBounds.GetBox()); + FBoxSphereBounds WorldBound = LocalBound.TransformBy(OriginalTransform); + + static FName NAME_FoliageCollisionWithWorld = FName(TEXT("FoliageCollisionWithWorld")); + if (InWorld->OverlapBlockingTestByChannel(WorldBound.Origin, FQuat(Inst.Rotation), ECC_WorldStatic, FCollisionShape::MakeBox(LocalBound.BoxExtent * Inst.DrawScale3D * Settings->CollisionScale), FCollisionQueryParams(NAME_FoliageCollisionWithWorld, false, HitComponent != nullptr ? HitComponent->GetOwner() : nullptr))) + { + return false; + } + + //::DrawDebugBox(InWorld, WorldBound.Origin, LocalBound.BoxExtent * Inst.DrawScale3D * Settings->CollisionScale, FQuat(Inst.Rotation), FColor::Red, true, 30.f); + return true; } @@ -2938,7 +3074,7 @@ bool FPotentialInstance::PlaceInstance(const UWorld* InWorld, const UFoliageType } } - return bSkipCollision || AInstancedFoliageActor::CheckCollisionWithWorld(InWorld, Settings, Inst, HitNormal, HitLocation); + return bSkipCollision || AInstancedFoliageActor::CheckCollisionWithWorld(InWorld, Settings, Inst, HitNormal, HitLocation, HitComponent); } #endif diff --git a/Engine/Source/Runtime/Foliage/Private/ProceduralFoliageTile.cpp b/Engine/Source/Runtime/Foliage/Private/ProceduralFoliageTile.cpp index df8b8359ad83..fdf237d40f0c 100644 --- a/Engine/Source/Runtime/Foliage/Private/ProceduralFoliageTile.cpp +++ b/Engine/Source/Runtime/Foliage/Private/ProceduralFoliageTile.cpp @@ -463,7 +463,7 @@ void UProceduralFoliageTile::ExtractDesiredInstances(TArray& InInstancesToRemove); + FOLIAGE_API void AddInstance(AInstancedFoliageActor* InIFA, const UFoliageType* InSettings, const FFoliageInstance& InNewInstance, bool RebuildFoliageTree); + FOLIAGE_API void AddInstance(AInstancedFoliageActor* InIFA, const UFoliageType* InSettings, const FFoliageInstance& InNewInstance, UActorComponent* InBaseComponent, bool RebuildFoliageTree); + FOLIAGE_API void RemoveInstances(AInstancedFoliageActor* InIFA, const TArray& InInstancesToRemove, bool RebuildFoliageTree); // Apply changes in the FoliageType to the component FOLIAGE_API void UpdateComponentSettings(const UFoliageType* InSettings); // Recreate the component if the FoliageType's ComponentClass doesn't match the Component's class @@ -232,6 +230,8 @@ struct FFoliageMeshInfo // For debugging. Validate state after editing. void CheckValid(); + + FOLIAGE_API void HandleComponentMeshBoundsChanged(const FBoxSphereBounds& NewBounds); #endif friend FArchive& operator<<(FArchive& Ar, FFoliageMeshInfo& MeshInfo); diff --git a/Engine/Source/Runtime/Foliage/Public/InstancedFoliageActor.h b/Engine/Source/Runtime/Foliage/Public/InstancedFoliageActor.h index 7c05dc985644..93b1881ccf14 100644 --- a/Engine/Source/Runtime/Foliage/Public/InstancedFoliageActor.h +++ b/Engine/Source/Runtime/Foliage/Public/InstancedFoliageActor.h @@ -102,7 +102,7 @@ public: #if WITH_EDITOR static FOLIAGE_API bool FoliageTrace(const UWorld* InWorld, FHitResult& OutHit, const FDesiredFoliageInstance& DesiredInstance, FName InTraceTag = NAME_None, bool InbReturnFaceIndex = false, const FFoliageTraceFilterFunc& FilterFunc = FFoliageTraceFilterFunc()); - static FOLIAGE_API bool CheckCollisionWithWorld(const UWorld* InWorld, const UFoliageType* Settings, const FFoliageInstance& Inst, const FVector& HitNormal, const FVector& HitLocation); + static FOLIAGE_API bool CheckCollisionWithWorld(const UWorld* InWorld, const UFoliageType* Settings, const FFoliageInstance& Inst, const FVector& HitNormal, const FVector& HitLocation, UPrimitiveComponent* HitComponent); virtual void PostEditUndo() override; virtual bool ShouldExport() override; @@ -158,6 +158,9 @@ public: // Whether actor has selected instances FOLIAGE_API bool HasSelectedInstances() const; + // Will return all the foliage type used by currently selected instances + FOLIAGE_API TMap GetSelectedInstancesFoliageType(); + // Propagate the selected instances to the actual render components FOLIAGE_API void ApplySelectionToComponents(bool bApply); @@ -169,6 +172,7 @@ public: /* Called to notify InstancedFoliageActor that a UFoliageType has been modified */ void NotifyFoliageTypeChanged(UFoliageType* FoliageType, bool bMeshChanged); + void NotifyFoliageTypeWillChange(UFoliageType* FoliageType, bool bMeshChanged); DECLARE_EVENT_OneParam(AInstancedFoliageActor, FOnFoliageTypeMeshChanged, UFoliageType*); FOnFoliageTypeMeshChanged& OnFoliageTypeMeshChanged() { return OnFoliageTypeMeshChangedEvent; } diff --git a/Engine/Source/Runtime/GameLiveStreaming/GameLiveStreaming.Build.cs b/Engine/Source/Runtime/GameLiveStreaming/GameLiveStreaming.Build.cs deleted file mode 100644 index f29fe953cc6c..000000000000 --- a/Engine/Source/Runtime/GameLiveStreaming/GameLiveStreaming.Build.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -namespace UnrealBuildTool.Rules -{ - public class GameLiveStreaming : ModuleRules - { - public GameLiveStreaming( ReadOnlyTargetRules Target ) : base(Target) - { - PublicDependencyModuleNames.AddRange( - new string[] - { - "Core", - } - ); - - PrivateDependencyModuleNames.AddRange( - new string[] - { - "CoreUObject", - "Engine", - "Slate", - "SlateCore", - "RenderCore", - "ShaderCore", - "RHI", - } - ); - } - } -} diff --git a/Engine/Source/Runtime/GameLiveStreaming/GameLiveStreaming.cpp b/Engine/Source/Runtime/GameLiveStreaming/GameLiveStreaming.cpp deleted file mode 100644 index c71a12b1326b..000000000000 --- a/Engine/Source/Runtime/GameLiveStreaming/GameLiveStreaming.cpp +++ /dev/null @@ -1,614 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "GameLiveStreaming.h" -#include "UObject/Package.h" -#include "EngineGlobals.h" -#include "RenderingThread.h" -#include "RendererInterface.h" -#include "Shader.h" -#include "Engine/Texture2D.h" -#include "StaticBoundShaderState.h" -#include "RHIStaticStates.h" -#include "Engine/Engine.h" -#include "Engine/Canvas.h" -#include "Framework/Application/SlateApplication.h" -#include "Features/IModularFeatures.h" -#include "Features/ILiveStreamingService.h" -#include "ScreenRendering.h" -#include "PipelineStateCache.h" - -IMPLEMENT_MODULE( FGameLiveStreaming, GameLiveStreaming ); - -#define LOCTEXT_NAMESPACE "GameLiveStreaming" - -FGameLiveStreaming::FGameLiveStreaming() - : BroadcastStartCommand - ( - TEXT( "GameLiveStreaming.StartBroadcasting" ), - TEXT( "Starts broadcasting game video and audio using a live internet streaming service\n" ) - TEXT( "\n" ) - TEXT( "Optional parameters:\n" ) - TEXT( " LoginUserName= For direct authentication, the user name to login as\n" ) - TEXT( " LoginPassword= For direct authentication, the password to use\n" ) - TEXT( " FrameRate= Frame rate to stream video when broadcasting\n") - TEXT( " ScreenScaling= How much to scale the broadcast video resolution down\n" ) - TEXT( " bStartWebCam= If enabled, starts capturing video from your web camera right away\n" ) - TEXT( " DesiredWebCamWidth= Horizontal resolution for web camera capture\n" ) - TEXT( " DesiredWebCamHeight= Veritcal resolution for web camera capture\n" ) - TEXT( " bMirrorWebCamImage= Flips the web camera image horizontally\n" ) - TEXT( " bDrawSimpleWebCamVideo= Draws a simple web cam video on top of the viewport\n" ) - TEXT( " bCaptureAudioFromComputer= Enables capturing sound that is played back through your PC\n" ) - TEXT( " bCaptureAudioFromMicrophone= Enables capturing sound from your default microphone\n" ) - TEXT( " CoverUpImage=<2D Texture Path> Broadcasts the specified texture instead of what's on screen\n" ), - FConsoleCommandWithArgsDelegate::CreateStatic( - []( const TArray< FString >& Args ) - { - FGameBroadcastConfig Config; - for( FString Arg : Args ) - { - FParse::Value( *Arg, TEXT( "LoginUserName=" ), Config.LoginUserName ); - FParse::Value( *Arg, TEXT( "LoginPassword=" ), Config.LoginPassword ); - FParse::Value( *Arg, TEXT( "FrameRate="), Config.FrameRate ); - FParse::Value( *Arg, TEXT( "ScreenScaling="), Config.ScreenScaling ); - FParse::Bool( *Arg, TEXT( "bStartWebCam="), Config.bStartWebCam ); - FParse::Value( *Arg, TEXT( "DesiredWebCamWidth="), Config.WebCamConfig.DesiredWebCamWidth ); - FParse::Value( *Arg, TEXT( "DesiredWebCamHeight="), Config.WebCamConfig.DesiredWebCamHeight ); - FParse::Bool( *Arg, TEXT( "bMirrorWebCamImage="), Config.WebCamConfig.bMirrorWebCamImage ); - FParse::Bool( *Arg, TEXT( "bDrawSimpleWebCamVideo=" ), Config.WebCamConfig.bDrawSimpleWebCamVideo ); - FParse::Bool( *Arg, TEXT( "bCaptureAudioFromComputer="), Config.bCaptureAudioFromComputer ); - FParse::Bool( *Arg, TEXT( "bCaptureAudioFromMicrophone="), Config.bCaptureAudioFromMicrophone ); - - FString CoverUpImagePath; - FParse::Value( *Arg, TEXT( "CoverUpImage" ), CoverUpImagePath ); - if( !CoverUpImagePath.IsEmpty() ) - { - Config.CoverUpImage = LoadObject( GetTransientPackage(), *CoverUpImagePath ); - } - } - IGameLiveStreaming::Get().StartBroadcastingGame( Config ); - } ) - ), - BroadcastStopCommand - ( - TEXT( "GameLiveStreaming.StopBroadcasting" ), - TEXT( "Stops broadcasting game video" ), - FConsoleCommandDelegate::CreateStatic( - [] - { - IGameLiveStreaming::Get().StopBroadcastingGame(); - } ) - ), - WebCamStartCommand - ( - TEXT( "GameLiveStreaming.StartWebCam" ), - TEXT( "Starts capturing web camera video and previewing it on screen\n" ) - TEXT( "\n" ) - TEXT( "Optional parameters:\n" ) - TEXT( " DesiredWebCamWidth= Horizontal resolution for web camera capture\n" ) - TEXT( " DesiredWebCamHeight= Veritcal resolution for web camera capture\n" ) - TEXT( " bMirrorWebCamImage= Flips the web camera image horizontally\n" ) - TEXT( " bDrawSimpleWebCamVideo= Draws a simple web cam video on top of the viewport\n" ), - FConsoleCommandWithArgsDelegate::CreateStatic( - []( const TArray< FString >& Args ) - { - FGameWebCamConfig Config; - for( FString Arg : Args ) - { - FParse::Value( *Arg, TEXT( "DesiredWebCamWidth="), Config.DesiredWebCamWidth ); - FParse::Value( *Arg, TEXT( "DesiredWebCamHeight="), Config.DesiredWebCamHeight ); - FParse::Bool( *Arg, TEXT( "bMirrorWebCamImage="), Config.bMirrorWebCamImage ); - FParse::Bool( *Arg, TEXT( "bDrawSimpleWebCamVideo=" ), Config.bDrawSimpleWebCamVideo ); - } - IGameLiveStreaming::Get().StartWebCam( Config ); - } ) - ), - WebCamStopCommand - ( - TEXT( "GameLiveStreaming.StopWebCam" ), - TEXT( "Stops capturing web camera video" ), - FConsoleCommandDelegate::CreateStatic( - [] - { - IGameLiveStreaming::Get().StopWebCam(); - } ) - ) -{ - bIsBroadcasting = false; - bIsWebCamEnabled = false; - LiveStreamer = nullptr; - ReadbackTextureIndex = 0; - ReadbackBufferIndex = 0; - ReadbackBuffers[0] = nullptr; - ReadbackBuffers[1] = nullptr; - bMirrorWebCamImage = false; - bDrawSimpleWebCamVideo = true; - CoverUpImage = nullptr; -} - - -void FGameLiveStreaming::StartupModule() -{ -} - - -void FGameLiveStreaming::ShutdownModule() -{ - if( LiveStreamer != nullptr ) - { - // Make sure the LiveStreaming plugin is actually still loaded. During shutdown, it may have been unloaded before us, - // and we can't dereference our LiveStreamer pointer if the memory was deleted already! - static const FName LiveStreamingFeatureName( "LiveStreaming" ); - if( IModularFeatures::Get().IsModularFeatureAvailable( LiveStreamingFeatureName ) ) // Make sure the feature hasn't been destroyed before us - { - // Turn off the web camera. It's important this happens first to avoid a shutdown crash. - StopWebCam(); - - // Stop broadcasting at shutdown - StopBroadcastingGame(); - - LiveStreamer->OnStatusChanged().RemoveAll( this ); - LiveStreamer->OnChatMessage().RemoveAll( this ); - } - LiveStreamer = nullptr; - } -} - - - -bool FGameLiveStreaming::IsBroadcastingGame() const -{ - return bIsBroadcasting && LiveStreamer != nullptr && LiveStreamer->IsBroadcasting(); -} - - -void FGameLiveStreaming::StartBroadcastingGame( const FGameBroadcastConfig& GameBroadcastConfig ) -{ - if( !IsBroadcastingGame() ) - { - if( bIsBroadcasting ) - { - FSlateRenderer* SlateRenderer = FSlateApplication::Get().GetRenderer().Get(); - SlateRenderer->OnSlateWindowRendered().RemoveAll( this ); - bIsBroadcasting = false; - } - - // We can GetLiveStreamingService() here to fill in our LiveStreamer variable lazily, to make sure the service plugin is loaded - // before we try to cache it's interface pointer - if( GetLiveStreamingService() != nullptr ) - { - CoverUpImage = GameBroadcastConfig.CoverUpImage; - - FSlateRenderer* SlateRenderer = FSlateApplication::Get().GetRenderer().Get(); - SlateRenderer->OnSlateWindowRendered().AddRaw( this, &FGameLiveStreaming::OnSlateWindowRenderedDuringBroadcasting ); - - FBroadcastConfig BroadcastConfig; - BroadcastConfig.LoginUserName = GameBroadcastConfig.LoginUserName; - BroadcastConfig.LoginPassword = GameBroadcastConfig.LoginPassword; - - // @todo livestream: This will interfere with editor live streaming if both are running at the same time! The editor live - // streaming does check to make sure that game isn't already broadcasting, but the game currently doesn't have a good way to - // do that, besides asking the LiveStreamer itself. - - UGameViewportClient* GameViewportClient = GEngine->GameViewport; - check( GameViewportClient != nullptr ); - - // @todo livestream: What about if viewport size changes while we are still broadcasting? We need to restart the broadcast! - BroadcastConfig.VideoBufferWidth = GameViewportClient->Viewport->GetSizeXY().X; - BroadcastConfig.VideoBufferHeight = GameViewportClient->Viewport->GetSizeXY().Y; - - BroadcastConfig.VideoBufferWidth = FPlatformMath::FloorToInt( (float)BroadcastConfig.VideoBufferWidth * GameBroadcastConfig.ScreenScaling ); - BroadcastConfig.VideoBufferHeight = FPlatformMath::FloorToInt( (float)BroadcastConfig.VideoBufferHeight * GameBroadcastConfig.ScreenScaling ); - - // Fix up the desired resolution so that it will work with the streaming system. Some broadcasters require the - // video buffer to be multiples of specific values, such as 32 - // @todo livestream: This could cause the aspect ratio to be changed and the buffer to be stretched non-uniformly, but usually the aspect only changes slightly - LiveStreamer->MakeValidVideoBufferResolution( BroadcastConfig.VideoBufferWidth, BroadcastConfig.VideoBufferHeight ); - - // Setup readback buffer textures - { - for( int32 TextureIndex = 0; TextureIndex < 2; ++TextureIndex ) - { - ReadbackTextures[ TextureIndex ] = nullptr; - } - ENQUEUE_UNIQUE_RENDER_COMMAND_THREEPARAMETER( - FWebMRecordCreateBufers, - int32,InVideoWidth,BroadcastConfig.VideoBufferWidth, - int32,InVideoHeight,BroadcastConfig.VideoBufferHeight, - FTexture2DRHIRef*,InReadbackTextures,ReadbackTextures, - { - for (int32 TextureIndex = 0; TextureIndex < 2; ++TextureIndex) - { - FRHIResourceCreateInfo CreateInfo; - InReadbackTextures[ TextureIndex ] = RHICreateTexture2D( - InVideoWidth, - InVideoHeight, - PF_B8G8R8A8, - 1, - 1, - TexCreate_CPUReadback, - CreateInfo - ); - } - }); - FlushRenderingCommands(); - for (int32 TextureIndex = 0; TextureIndex < 2; ++TextureIndex) - { - check(ReadbackTextures[TextureIndex].GetReference()); - } - - ReadbackTextureIndex = 0; - - ReadbackBuffers[0] = nullptr; - ReadbackBuffers[1] = nullptr; - ReadbackBufferIndex = 0; - } - - BroadcastConfig.FramesPerSecond = GameBroadcastConfig.FrameRate; - BroadcastConfig.PixelFormat = FBroadcastConfig::EBroadcastPixelFormat::B8G8R8A8; // Matches viewport backbuffer format - BroadcastConfig.bCaptureAudioFromComputer = GameBroadcastConfig.bCaptureAudioFromComputer; - BroadcastConfig.bCaptureAudioFromMicrophone = GameBroadcastConfig.bCaptureAudioFromMicrophone; - LiveStreamer->StartBroadcasting( BroadcastConfig ); - - if( GameBroadcastConfig.bStartWebCam && !bIsWebCamEnabled ) - { - this->StartWebCam( GameBroadcastConfig.WebCamConfig ); - } - - bIsBroadcasting = true; - } - } -} - - -void FGameLiveStreaming::StopBroadcastingGame() -{ - if( bIsBroadcasting ) - { - if( LiveStreamer != nullptr ) - { - if( LiveStreamer->IsBroadcasting() ) - { - LiveStreamer->StopBroadcasting(); - } - } - if( FSlateApplication::IsInitialized() ) // During shutdown, Slate may have already been destroyed by the time our viewport gets cleaned up - { - FSlateRenderer* SlateRenderer = FSlateApplication::Get().GetRenderer().Get(); - SlateRenderer->OnSlateWindowRendered().RemoveAll( this ); - } - - // Cleanup readback buffer textures - { - FlushRenderingCommands(); - - ReadbackTextures[0].SafeRelease(); - ReadbackTextures[1].SafeRelease(); - ReadbackTextureIndex = 0; - ReadbackBuffers[0] = nullptr; - ReadbackBuffers[1] = nullptr; - ReadbackBufferIndex = 0; - } - } - - // Turn off the web camera, too. - StopWebCam(); -} - - -bool FGameLiveStreaming::IsWebCamEnabled() const -{ - return bIsWebCamEnabled && LiveStreamer != nullptr && LiveStreamer->IsWebCamEnabled(); -} - - -void FGameLiveStreaming::StartWebCam( const FGameWebCamConfig& GameWebCamConfig ) -{ - if( !bIsWebCamEnabled ) - { - this->bMirrorWebCamImage = GameWebCamConfig.bMirrorWebCamImage; - this->bDrawSimpleWebCamVideo = GameWebCamConfig.bDrawSimpleWebCamVideo; - - // We can GetLiveStreamingService() here to fill in our LiveStreamer variable lazily, to make sure the service plugin is loaded - // before we try to cache it's interface pointer - if( GetLiveStreamingService() != nullptr ) - { - FWebCamConfig WebCamConfig; - WebCamConfig.DesiredWebCamWidth = GameWebCamConfig.DesiredWebCamWidth; - WebCamConfig.DesiredWebCamHeight = GameWebCamConfig.DesiredWebCamHeight; - - LiveStreamer->StartWebCam( WebCamConfig ); - - bIsWebCamEnabled = true; - } - } -} - - -void FGameLiveStreaming::StopWebCam() -{ - if( bIsWebCamEnabled ) - { - if( LiveStreamer != nullptr ) - { - if( LiveStreamer->IsWebCamEnabled() ) - { - LiveStreamer->StopWebCam(); - } - } - - bIsWebCamEnabled = false; - } -} - - -void FGameLiveStreaming::OnSlateWindowRenderedDuringBroadcasting( SWindow& SlateWindow, void* ViewportRHIPtr ) -{ - // If we're streaming live video/audio, we'll go ahead and push new video frames here - UGameViewportClient* GameViewportClient = GEngine->GameViewport; - if( IsBroadcastingGame() && GameViewportClient != nullptr ) - { - // We only care about our own Slate window - if( GameViewportClient->GetWindow() == SlateWindow.AsShared() ) - { - // Check to see if we're streaming live video. If so, we'll want to push new frames to be broadcast. - if( LiveStreamer->IsReadyForVideoFrames() ) - { - // Check to see if there are any video frames ready to push - BroadcastGameVideoFrame(); - - // Start copying next game video frame - const FViewportRHIRef* ViewportRHI = ( const FViewportRHIRef* )ViewportRHIPtr; - StartCopyingNextGameVideoFrame( *ViewportRHI ); - } - } - } - else - { - // No longer broadcasting. The live streaming service may have been interrupted. - StopBroadcastingGame(); - } -} - - -void FGameLiveStreaming::BroadcastGameVideoFrame() -{ - if( ReadbackBuffers[ ReadbackBufferIndex ] != nullptr ) - { - // Great, we have a new frame back from the GPU. Upload the video frame! - LiveStreamer->PushVideoFrame( (FColor*)ReadbackBuffers[ ReadbackBufferIndex ] ); - - // Unmap the buffer now that we've pushed out the frame - { - struct FReadbackFromStagingBufferContext - { - FGameLiveStreaming* This; - }; - FReadbackFromStagingBufferContext ReadbackFromStagingBufferContext = - { - this - }; - ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER( - ReadbackFromStagingBuffer, - FReadbackFromStagingBufferContext,Context,ReadbackFromStagingBufferContext, - { - RHICmdList.UnmapStagingSurface(Context.This->ReadbackTextures[Context.This->ReadbackTextureIndex]); - }); - } - } - else - { - // Frame hasn't finished copying from the GPU, so we can't broadcast a frame yet - } -} - - -void FGameLiveStreaming::StartCopyingNextGameVideoFrame( const FViewportRHIRef& ViewportRHI ) -{ - // Check the video buffer size, in case we were configured to downscale the image - FBroadcastConfig BroadcastConfig; - LiveStreamer->QueryBroadcastConfig( BroadcastConfig ); - - const FIntPoint ResizeTo( BroadcastConfig.VideoBufferWidth, BroadcastConfig.VideoBufferHeight ); - - static const FName RendererModuleName( "Renderer" ); - IRendererModule& RendererModule = FModuleManager::GetModuleChecked( RendererModuleName ); - - UGameViewportClient* GameViewportClient = GEngine->GameViewport; - check( GameViewportClient != nullptr ); - - struct FCopyVideoFrame - { - FViewportRHIRef ViewportRHI; - IRendererModule* RendererModule; - FIntPoint ResizeTo; - FTexture2DRHIRef CoverUpImage; - FGameLiveStreaming* This; - }; - FCopyVideoFrame CopyVideoFrame = - { - ViewportRHI, - &RendererModule, - ResizeTo, - CoverUpImage != nullptr ? ( (FTexture2DResource*)( CoverUpImage->Resource ) )->GetTexture2DRHI() : nullptr, - this - }; - - FCopyVideoFrame Context = CopyVideoFrame; - ENQUEUE_RENDER_COMMAND(ReadSurfaceCommand)( - [Context](FRHICommandListImmediate& RHICmdList) - { - FPooledRenderTargetDesc OutputDesc(FPooledRenderTargetDesc::Create2DDesc(Context.ResizeTo, PF_B8G8R8A8, FClearValueBinding::None, TexCreate_None, TexCreate_RenderTargetable, false)); - - const auto FeatureLevel = GMaxRHIFeatureLevel; - - TRefCountPtr ResampleTexturePooledRenderTarget; - Context.RendererModule->RenderTargetPoolFindFreeElement(RHICmdList, OutputDesc, ResampleTexturePooledRenderTarget, TEXT("ResampleTexture")); - check( ResampleTexturePooledRenderTarget ); - - const FSceneRenderTargetItem& DestRenderTarget = ResampleTexturePooledRenderTarget->GetRenderTargetItem(); - - SetRenderTarget(RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); - RHICmdList.SetViewport(0, 0, 0.0f, Context.ResizeTo.X, Context.ResizeTo.Y, 1.0f); - - FGraphicsPipelineStateInitializer GraphicsPSOInit; - RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit); - - GraphicsPSOInit.BlendState = TStaticBlendState::GetRHI(); - GraphicsPSOInit.RasterizerState = TStaticRasterizerState<>::GetRHI(); - GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState::GetRHI(); - - FTexture2DRHIRef SourceTexture = - Context.CoverUpImage.IsValid() ? Context.CoverUpImage : RHICmdList.GetViewportBackBuffer(Context.ViewportRHI); - - auto ShaderMap = GetGlobalShaderMap(FeatureLevel); - TShaderMapRef VertexShader(ShaderMap); - TShaderMapRef PixelShader(ShaderMap); - - GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = Context.RendererModule->GetFilterVertexDeclaration().VertexDeclarationRHI; - GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(*VertexShader); - GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(*PixelShader); - GraphicsPSOInit.PrimitiveType = PT_TriangleList; - - SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit); - - if( Context.ResizeTo != FIntPoint( SourceTexture->GetSizeX(), SourceTexture->GetSizeY() ) ) - { - // We're scaling down the window, so use bilinear filtering - PixelShader->SetParameters(RHICmdList, TStaticSamplerState::GetRHI(), SourceTexture); - } - else - { - // Drawing 1:1, so no filtering needed - PixelShader->SetParameters(RHICmdList, TStaticSamplerState::GetRHI(), SourceTexture); - } - - Context.RendererModule->DrawRectangle( - RHICmdList, - 0, 0, // Dest X, Y - Context.ResizeTo.X, Context.ResizeTo.Y, // Dest Width, Height - 0, 0, // Source U, V - 1, 1, // Source USize, VSize - Context.ResizeTo, // Target buffer size - FIntPoint(1, 1), // Source texture size - *VertexShader, - EDRF_Default); - - // Asynchronously copy render target from GPU to CPU - const bool bKeepOriginalSurface = false; - RHICmdList.CopyToResolveTarget( - DestRenderTarget.TargetableTexture, - Context.This->ReadbackTextures[ Context.This->ReadbackTextureIndex ], - bKeepOriginalSurface, - FResolveParams()); - }); - - - // Start mapping the newly-rendered buffer - { - struct FReadbackFromStagingBufferContext - { - FGameLiveStreaming* This; - }; - FReadbackFromStagingBufferContext ReadbackFromStagingBufferContext = - { - this - }; - ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER( - ReadbackFromStagingBuffer, - FReadbackFromStagingBufferContext,Context,ReadbackFromStagingBufferContext, - { - int32 UnusedWidth = 0; - int32 UnusedHeight = 0; - RHICmdList.MapStagingSurface(Context.This->ReadbackTextures[Context.This->ReadbackTextureIndex], Context.This->ReadbackBuffers[Context.This->ReadbackBufferIndex], UnusedWidth, UnusedHeight); - - // Ping pong between readback textures - Context.This->ReadbackTextureIndex = ( Context.This->ReadbackTextureIndex + 1 ) % 2; - }); - } - - // Ping pong between readback buffers - ReadbackBufferIndex = ( ReadbackBufferIndex + 1 ) % 2; -} - - -void FGameLiveStreaming::DrawSimpleWebCamVideo( UCanvas* Canvas ) -{ - if( IsWebCamEnabled() && bDrawSimpleWebCamVideo && LiveStreamer->IsWebCamEnabled() ) - { - bool bIsImageFlippedHorizontally = false; - bool bIsImageFlippedVertically = false; - UTexture2D* WebCamTexture = LiveStreamer->GetWebCamTexture( bIsImageFlippedHorizontally, bIsImageFlippedVertically ); - if( WebCamTexture != nullptr ) - { - // Give the user a chance to customize the image mirroring - if( this->bMirrorWebCamImage ) - { - bIsImageFlippedHorizontally = !bIsImageFlippedHorizontally; - } - - const float BorderPadding = 6.0f; - Canvas->Canvas->DrawTile( - Canvas->SizeX - WebCamTexture->GetSizeX() - BorderPadding, BorderPadding, // Top right justify - WebCamTexture->GetSizeX(), WebCamTexture->GetSizeY(), - bIsImageFlippedHorizontally ? 1.0f : 0.0f, bIsImageFlippedVertically ? 1.0f : 0.0f, - bIsImageFlippedHorizontally ? -1.0f : 1.0f, bIsImageFlippedVertically ? -1.0f : 1.0f, - FLinearColor::White, - WebCamTexture->Resource, - false ); // Alpha blend? - } - } -} - - -UTexture2D* FGameLiveStreaming::GetWebCamTexture( bool& bIsImageFlippedHorizontally, bool& bIsImageFlippedVertically ) -{ - bIsImageFlippedHorizontally = false; - bIsImageFlippedVertically = false; - - UTexture2D* WebCamTexture = nullptr; - if( IsWebCamEnabled() && bDrawSimpleWebCamVideo && LiveStreamer->IsWebCamEnabled() ) - { - WebCamTexture = LiveStreamer->GetWebCamTexture( bIsImageFlippedHorizontally, bIsImageFlippedVertically ); - } - return WebCamTexture; -} - - -ILiveStreamingService* FGameLiveStreaming::GetLiveStreamingService() -{ - if( LiveStreamer == nullptr ) - { - static const FName LiveStreamingFeatureName( "LiveStreaming" ); - if( IModularFeatures::Get().IsModularFeatureAvailable( LiveStreamingFeatureName ) ) - { - // Select a live streaming service - LiveStreamer = &IModularFeatures::Get().GetModularFeature( LiveStreamingFeatureName ); - - // Register to find out about status changes - LiveStreamer->OnStatusChanged().AddRaw( this, &FGameLiveStreaming::BroadcastStatusCallback ); - LiveStreamer->OnChatMessage().AddRaw( this, &FGameLiveStreaming::OnChatMessage ); - } - } - return LiveStreamer; -} - - - -void FGameLiveStreaming::BroadcastStatusCallback( const FLiveStreamingStatus& Status ) -{ - // @todo livestream: Hook this up to provide C++ users and Blueprints with status about the live streaming startup/webcam/shutdown -} - - -void FGameLiveStreaming::OnChatMessage( const FText& UserName, const FText& Text ) -{ - // @todo livestream: Add support (and also, connecting, disconnecting, sending messages, etc.) -} - - -void FGameLiveStreaming::AddReferencedObjects( FReferenceCollector& Collector ) -{ - Collector.AddReferencedObject( CoverUpImage ); -} - - -#undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Runtime/GameLiveStreaming/GameLiveStreaming.h b/Engine/Source/Runtime/GameLiveStreaming/GameLiveStreaming.h deleted file mode 100644 index c07bafbfa046..000000000000 --- a/Engine/Source/Runtime/GameLiveStreaming/GameLiveStreaming.h +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#pragma once - -#include "CoreMinimal.h" -#include "HAL/IConsoleManager.h" -#include "UObject/GCObject.h" -#include "RHI.h" -#include "IGameLiveStreaming.h" - -class SWindow; -class UCanvas; - -/** - * Implements support for broadcasting gameplay to a live internet stream - */ -class FGameLiveStreaming - : public IGameLiveStreaming, public FGCObject -{ - -public: - - /** Default constructor */ - FGameLiveStreaming(); - - /** IModuleInterface overrides */ - virtual void StartupModule() override; - virtual void ShutdownModule() override; - - /** IGameLiveStreaming overrides */ - virtual bool IsBroadcastingGame() const override; - virtual void StartBroadcastingGame( const FGameBroadcastConfig& GameBroadcastConfig ) override; - virtual void StopBroadcastingGame() override; - virtual bool IsWebCamEnabled() const override; - virtual void StartWebCam( const FGameWebCamConfig& GameWebCamConfig ) override; - virtual void StopWebCam() override; - virtual void DrawSimpleWebCamVideo( UCanvas* Canvas ) override; - virtual class UTexture2D* GetWebCamTexture( bool& bIsImageFlippedHorizontally, bool& bIsImageFlippedVertically ) override; - virtual class ILiveStreamingService* GetLiveStreamingService() override; - - /** FGCObject overrides */ - virtual void AddReferencedObjects( FReferenceCollector& Collector ) override; - - -protected: - - /** Called by the live streaming service when streaming status has changed or an error has occurred */ - void BroadcastStatusCallback( const struct FLiveStreamingStatus& Status ); - - /** Called by the live streaming service when a chat message is received */ - void OnChatMessage( const FText& UserName, const FText& Text ); - - /** - * Called by the Slate rendered on the game thread right after a window has been rendered, to allow us to - * capture frame buffer content after everything has been rendered, including debug canvas graphics - * - * @param SlateWindow The window that was just rendered - * @param ViewportRHIPtr The viewport we rendered this window to (cast to FViewportRHIRef*) - */ - void OnSlateWindowRenderedDuringBroadcasting( SWindow& SlateWindow, void* ViewportRHIPtr ); - - /** Broadcasts a new video frame, only if the frame's data has finished copying from the GPU to system memory */ - void BroadcastGameVideoFrame(); - - /** Starts copying the last rendered game frame from the GPU back buffer to a mapped system memory texture */ - void StartCopyingNextGameVideoFrame( const FViewportRHIRef& ViewportRHI ); - -private: - - /** Whether we're currently trying to broadcast */ - bool bIsBroadcasting; - - /** Whether the web camera is active */ - bool bIsWebCamEnabled; - - /** The live streaming service we're using. Only valid while broadcasting. */ - class ILiveStreamingService* LiveStreamer; - - /** Static: Readback textures for asynchronously reading the viewport frame buffer back to the CPU. We ping-pong between the buffers to avoid stalls. */ - FTexture2DRHIRef ReadbackTextures[2]; - - /** Static: We ping pong between the textures in case the GPU is a frame behind (GSystemSettings.bAllowOneFrameThreadLag) */ - int32 ReadbackTextureIndex; - - /** Static: Pointers to mapped system memory readback textures that game frames will be asynchronously copied to */ - void* ReadbackBuffers[2]; - - /** The current buffer index. We bounce between them to avoid stalls. */ - int32 ReadbackBufferIndex; - - /** True if the user prefers to flip the web camera image horizontally */ - bool bMirrorWebCamImage; - - /** True if we should draw a simple web cam video on top of the viewport while broadcasting */ - bool bDrawSimpleWebCamVideo; - - /** Console command for starting broadcast */ - FAutoConsoleCommand BroadcastStartCommand; - - /** Console command for stopping broadcast */ - FAutoConsoleCommand BroadcastStopCommand; - - /** Console command for starting web camera capture/preview */ - FAutoConsoleCommand WebCamStartCommand; - - /** Console command for stopping the web camera */ - FAutoConsoleCommand WebCamStopCommand; - - /** Optional image to broadcast, instead of what you're looking at on screen. This is useful if you don't want to publicly share the visuals on screen. */ - class UTexture2D* CoverUpImage; -}; diff --git a/Engine/Source/Runtime/GameLiveStreaming/GameLiveStreamingFunctionLibrary.cpp b/Engine/Source/Runtime/GameLiveStreaming/GameLiveStreamingFunctionLibrary.cpp deleted file mode 100644 index a1c4d5031bc7..000000000000 --- a/Engine/Source/Runtime/GameLiveStreaming/GameLiveStreamingFunctionLibrary.cpp +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "GameLiveStreamingFunctionLibrary.h" -#include "IGameLiveStreaming.h" - -#define LOCTEXT_NAMESPACE "GameLiveStreaming" - - -UGameLiveStreamingFunctionLibrary::UGameLiveStreamingFunctionLibrary( const FObjectInitializer& ObjectInitializer ) - : Super(ObjectInitializer) -{ -} - - -bool UGameLiveStreamingFunctionLibrary::IsBroadcastingGame() -{ - return IGameLiveStreaming::Get().IsBroadcastingGame(); -} - - -void UGameLiveStreamingFunctionLibrary::StartBroadcastingGame( - const FString& LoginUserName, - const FString& LoginPassword, - int32 FrameRate, - float ScreenScaling, - bool bStartWebCam, - int32 DesiredWebCamWidth, - int32 DesiredWebCamHeight, - bool bMirrorWebCamImage, - bool bDrawSimpleWebCamVideo, - bool bCaptureAudioFromComputer, - bool bCaptureAudioFromMicrophone, - UTexture2D* CoverUpImage ) -{ - FGameBroadcastConfig Config; - Config.LoginUserName = LoginUserName; - Config.LoginPassword = LoginPassword; - Config.FrameRate = FrameRate; - Config.ScreenScaling = ScreenScaling; - Config.bStartWebCam = bStartWebCam; - Config.WebCamConfig.DesiredWebCamWidth = DesiredWebCamWidth; - Config.WebCamConfig.DesiredWebCamHeight = DesiredWebCamHeight; - Config.WebCamConfig.bMirrorWebCamImage = bMirrorWebCamImage; - Config.WebCamConfig.bDrawSimpleWebCamVideo = bDrawSimpleWebCamVideo; - Config.bCaptureAudioFromComputer = bCaptureAudioFromComputer; - Config.bCaptureAudioFromMicrophone = bCaptureAudioFromMicrophone; - Config.CoverUpImage = CoverUpImage; - IGameLiveStreaming::Get().StartBroadcastingGame( Config ); -} - - -void UGameLiveStreamingFunctionLibrary::StopBroadcastingGame() -{ - IGameLiveStreaming::Get().StopBroadcastingGame(); -} - - -bool UGameLiveStreamingFunctionLibrary::IsWebCamEnabled() -{ - return IGameLiveStreaming::Get().IsWebCamEnabled(); -} - - -void UGameLiveStreamingFunctionLibrary::StartWebCam( - int32 DesiredWebCamWidth, - int32 DesiredWebCamHeight, - bool bMirrorWebCamImage, - bool bDrawSimpleWebCamVideo ) -{ - FGameWebCamConfig Config; - Config.DesiredWebCamWidth = DesiredWebCamWidth; - Config.DesiredWebCamHeight = DesiredWebCamHeight; - Config.bMirrorWebCamImage = bMirrorWebCamImage; - Config.bDrawSimpleWebCamVideo = bDrawSimpleWebCamVideo; - IGameLiveStreaming::Get().StartWebCam( Config ); -} - - -void UGameLiveStreamingFunctionLibrary::StopWebCam() -{ - IGameLiveStreaming::Get().StopWebCam(); -} - - -#undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Runtime/GameLiveStreaming/GameLiveStreamingFunctionLibrary.h b/Engine/Source/Runtime/GameLiveStreaming/GameLiveStreamingFunctionLibrary.h deleted file mode 100644 index b08e4cca7d17..000000000000 --- a/Engine/Source/Runtime/GameLiveStreaming/GameLiveStreamingFunctionLibrary.h +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#pragma once - -#include "CoreMinimal.h" -#include "UObject/ObjectMacros.h" -#include "Kismet/BlueprintFunctionLibrary.h" -#include "GameLiveStreamingFunctionLibrary.generated.h" - -UCLASS() -class UGameLiveStreamingFunctionLibrary : public UBlueprintFunctionLibrary -{ - GENERATED_UCLASS_BODY() - - /** - * Checks to see if we are currently broadcasting live video (and possibly audio) from the game's viewport - * - * @return True if we are currently transmitting - */ - UFUNCTION( BlueprintPure, Category="LiveStreaming" ) - static bool IsBroadcastingGame(); - - /** - * Starts broadcasting the game's video (and optionally audio) using an internet streaming service, if one is available - * - * @param FrameRate Frame rate to stream video from when broadcasting to services like Twitch. - * @param ScreenScaling How much to scale the broadcast video resolution down to reduce streaming bandwidth. We recommend broadcasting at resolutions of 1280x720 or lower. Some live streaming providers will not be able to transcode your video to a lower resolution, so using a high resolution stream may prevent low-bandwidth users from having a good viewing experience. - * @param bStartWebCam Starts your web camera right away. When the web camera is active, video from your web camera will be captured and displayed while broadcasting, so that your viewers can see your presence. - * @param DesiredWebCamWidth Desired web cam capture resolution width. The web cam may only support a limited number of resolutions, so we'll choose one that matches as closely to this as possible - * @param DesiredWebCamHeight Desired web cam capture resolution height. - * @param bMirrorWebCamImage You can enable this to flip the web camera image horizontally, so that it looks like a mirror - * @param bDrawSimpleWebCamVideo If enabled, the engine will draw a simple web cam image on top of the game viewport. If you turn this off, it's up to you to draw the web cam image yourself. You can access the web cam texture by calling IGameLiveStreaming::Get().GetWebCamTexture(). - * @param bCaptureAudioFromComputer Enables broadcast of audio being played by your computer, such as in-game sounds - * @param bCaptureAudioFromMicrophone Enables broadcast of audio from your default microphone recording device - * @param CoverUpImage Optional image to broadcast, instead of what you're looking at on screen. This is useful if you don't want to publicly share the visuals on screen. - */ - UFUNCTION( BlueprintCallable, Category="LiveStreaming") - static void StartBroadcastingGame( - const FString& LoginUserName, - const FString& LoginPassword, - int32 FrameRate = 30, - float ScreenScaling = 1.f, - bool bStartWebCam = true, - int32 DesiredWebCamWidth = 320, - int32 DesiredWebCamHeight = 240, - bool bMirrorWebCamImage = false, - bool bDrawSimpleWebCamVideo = true, - bool bCaptureAudioFromComputer = true, - bool bCaptureAudioFromMicrophone = true, - class UTexture2D* CoverUpImage = nullptr); - - /** Stops broadcasting the game */ - UFUNCTION( BlueprintCallable, Category="LiveStreaming" ) - static void StopBroadcastingGame(); - - /** - * Returns whether or not the web camera is actively capturing - * - * @return True if the web camera is available and currently capturing - */ - UFUNCTION( BlueprintPure, Category="LiveStreaming" ) - static bool IsWebCamEnabled(); - - /** - * Starts capturing and displaying web camera video, if one is plugged in - * - * @param DesiredWebCamWidth Desired web cam capture resolution width. The web cam may only support a limited number of resolutions, so we'll choose one that matches as closely to this as possible - * @param DesiredWebCamHeight Desired web cam capture resolution height. - * @param bMirrorWebCamImage You can enable this to flip the web camera image horizontally, so that it looks like a mirror - * @param bDrawSimpleWebCamVideo If enabled, the engine will draw a simple web cam image on top of the game viewport. If you turn this off, it's up to you to draw the web cam image yourself. You can access the web cam texture by calling IGameLiveStreaming::Get().GetWebCamTexture(). - */ - UFUNCTION( BlueprintCallable, Category="LiveStreaming") - static void StartWebCam( - int32 DesiredWebCamWidth = 320, - int32 DesiredWebCamHeight = 240, - bool bMirrorWebCamImage = false, - bool bDrawSimpleWebCamVideo = true); - - /** Stops the web camera, if it's currently capturing */ - UFUNCTION( BlueprintCallable, Category="LiveStreaming" ) - static void StopWebCam(); - - // @todo livestream: Add Blueprint APIs for chat -}; diff --git a/Engine/Source/Runtime/GameLiveStreaming/GameLiveStreamingModule.h b/Engine/Source/Runtime/GameLiveStreaming/GameLiveStreamingModule.h deleted file mode 100644 index cd30d5149b8b..000000000000 --- a/Engine/Source/Runtime/GameLiveStreaming/GameLiveStreamingModule.h +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#pragma once - - diff --git a/Engine/Source/Runtime/GameLiveStreaming/Public/IGameLiveStreaming.h b/Engine/Source/Runtime/GameLiveStreaming/Public/IGameLiveStreaming.h deleted file mode 100644 index 3cc175152f91..000000000000 --- a/Engine/Source/Runtime/GameLiveStreaming/Public/IGameLiveStreaming.h +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#pragma once - -#include "CoreMinimal.h" -#include "Modules/ModuleInterface.h" -#include "Modules/ModuleManager.h" - -class UCanvas; - -/** - * Web camera settings for game broadcasting - */ -struct FGameWebCamConfig -{ - /** Desired web cam capture resolution width. The web cam may only support a limited number of resolutions, so we'll - choose one that matches as closely to this as possible */ - int32 DesiredWebCamWidth; - - /** Desired web cam capture resolution height. */ - int32 DesiredWebCamHeight; - - /** You can enable this to flip the web camera image horizontally, so that it looks like a mirror */ - bool bMirrorWebCamImage; - - /** If enabled, the engine will draw a simple web cam image on top of the game viewport. If you turn this off, it's up to you to draw the web cam image yourself. You can access the web cam texture by calling IGameLiveStreaming::Get().GetWebCamTexture(). */ - bool bDrawSimpleWebCamVideo; - - - /** - * Default constructor - */ - FGameWebCamConfig() - : DesiredWebCamWidth( 320 ), - DesiredWebCamHeight( 240 ), - bMirrorWebCamImage( false ), - bDrawSimpleWebCamVideo( true ) - { - } -}; - - -/** - * Settings for a live game broadcast - */ -struct FGameBroadcastConfig -{ - /** Login user name, used only for direct authentication with a broadcasting end-point */ - FString LoginUserName; - - /** Login password, used only for direct authentication with a broadcasting end-point */ - FString LoginPassword; - - /** Frame rate to stream video when broadcasting to services like Twitch. */ - int32 FrameRate; - - /** How much to scale the broadcast video resolution down to reduce streaming bandwidth. We recommend broadcasting at resolutions of 1280x720 or lower. Some live streaming providers will not be able to transcode your video to a lower resolution, so using a high resolution stream may prevent low-bandwidth users from having a good viewing experience.*/ - float ScreenScaling; - - /** If enabled, video from your web camera will be captured and displayed while broadcasting, so that your viewers can see your presence. You can turn this on and off - independently using the other API functions instead, if you want. */ - bool bStartWebCam; - - /** If bStartWebCam is enabled, this contains the settings for the web camera */ - FGameWebCamConfig WebCamConfig; - - /** Enables broadcast of audio being played by your computer, such as in-game sounds */ - bool bCaptureAudioFromComputer; - - /** Enables broadcast of audio from your default microphone recording device */ - bool bCaptureAudioFromMicrophone; - - /** Optional image to broadcast, instead of what you're looking at on screen. This is useful if you don't want to publicly share the visuals on screen. */ - class UTexture2D* CoverUpImage; - - - /** - * Default constructor - */ - FGameBroadcastConfig() - : LoginUserName(), - LoginPassword(), - FrameRate( 30 ), - ScreenScaling( 1.0f ), - bStartWebCam( true ), - WebCamConfig(), - bCaptureAudioFromComputer( true ), - bCaptureAudioFromMicrophone( true ), - CoverUpImage( nullptr ) - { - } -}; - - -/** - * Interface to the GameLiveStreaming module's functionality for broadcasting live gameplay to the internet - */ -class IGameLiveStreaming - : public IModuleInterface -{ - -public: - - /** - * Checks to see if we are currently broadcasting live video (and possibly audio) from the game's viewport - * - * @return True if we are currently transmitting - */ - virtual bool IsBroadcastingGame() const = 0; - - /** - * Starts broadcasting the game's video (and optionally audio) using an internet streaming service, if one is available - * - * @param GameBroadcastConfig Settings for this game broadcast - */ - virtual void StartBroadcastingGame( const FGameBroadcastConfig& GameBroadcastConfig ) = 0; - - /** Stops broadcasting the game */ - virtual void StopBroadcastingGame() = 0; - - /** - * Returns whether or not the web camera is actively capturing - * - * @return True if the web camera is available and currently capturing - */ - virtual bool IsWebCamEnabled() const = 0; - - /** - * Starts capturing and displaying web camera video, if one is plugged in - * - * @param GameWebCamConfig Settings for this game broadcast - */ - virtual void StartWebCam( const FGameWebCamConfig& GameWebCamConfig ) = 0; - - /** Stops the web camera, if it's currently capturing */ - virtual void StopWebCam() = 0; - - /** - * Call this in your game's UI rendering code to draw a simple default web cam image while broadcasting. Instead of - * using this, you can grab the web cam texture yourself by calling GetWebCamTexture() and draw it however you want! - * - * @param Canvas The canvas to draw the web cam image to - */ - virtual void DrawSimpleWebCamVideo( UCanvas* Canvas ) = 0; - - /** - * Exposes access to the web cam video feed as a 2D texture - * - * @param bIsImageFlippedHorizontally [Out] True if the image is flipped left to right, and you should compensate while drawing by mirroring the texture U coordinates - * @param bIsImageFlippedVertically [Out] True if the image is flipped top to bottom, and you should compensate while drawing by mirroring the texture V coordinates - * - * @return The web cam video feed texture, or null if the web cam isn't enabled - */ - virtual class UTexture2D* GetWebCamTexture( bool& bIsImageFlippedHorizontally, bool& bIsImageFlippedVertically ) = 0; - - /** - * Gets direct access to the live streaming service we are using, or nullptr if we haven't selected one yet - * - * @return Live streaming service interface - */ - virtual class ILiveStreamingService* GetLiveStreamingService() = 0; - - -public: - - /** - * Singleton-like access to IGameLiveStreaming - * - * @return Returns instance of IGameLiveStreaming object - */ - static inline IGameLiveStreaming& Get() - { - return FModuleManager::LoadModuleChecked< IGameLiveStreaming >( "GameLiveStreaming" ); - } - -}; - - diff --git a/Engine/Source/Runtime/GameLiveStreaming/QueryLiveStreamsCallbackProxy.cpp b/Engine/Source/Runtime/GameLiveStreaming/QueryLiveStreamsCallbackProxy.cpp deleted file mode 100644 index 7fa4c09651d3..000000000000 --- a/Engine/Source/Runtime/GameLiveStreaming/QueryLiveStreamsCallbackProxy.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "QueryLiveStreamsCallbackProxy.h" -#include "Features/ILiveStreamingService.h" -#include "IGameLiveStreaming.h" - -UQueryLiveStreamsCallbackProxy::UQueryLiveStreamsCallbackProxy( const FObjectInitializer& ObjectInitializer ) - : Super(ObjectInitializer) -{ -} - - -UQueryLiveStreamsCallbackProxy* UQueryLiveStreamsCallbackProxy::QueryLiveStreams( const FString& GameName ) -{ - UQueryLiveStreamsCallbackProxy* Proxy = NewObject(); - Proxy->GameName = GameName; - - return Proxy; -} - - -void UQueryLiveStreamsCallbackProxy::Activate() -{ - // Query the live streaming system to find out about which live streams are available for the game that was requested. This - // will call back later on with results. - IGameLiveStreaming::Get().GetLiveStreamingService()->QueryLiveStreams( - this->GameName, - ILiveStreamingService::FQueryLiveStreamsCallback::CreateStatic( []( const TArray< FLiveStreamInfo >& LiveStreams, bool bQueryWasSuccessful, TWeakObjectPtr< UQueryLiveStreamsCallbackProxy > WeakThis ) - { - // Make sure our UObject hasn't been destroyed at the time that the live streaming system calls back with results - UQueryLiveStreamsCallbackProxy* This = WeakThis.Get(); - if( This != nullptr ) - { - TArray< FBlueprintLiveStreamInfo > BlueprintLiveStreams; - for( const auto& LiveStream : LiveStreams ) - { - FBlueprintLiveStreamInfo& BlueprintLiveStream = *new( BlueprintLiveStreams )FBlueprintLiveStreamInfo; - BlueprintLiveStream.GameName = LiveStream.GameName; - BlueprintLiveStream.StreamName = LiveStream.StreamName; - BlueprintLiveStream.URL = LiveStream.URL; - } - - // We have results! - This->OnQueriedLiveStreams.Broadcast( BlueprintLiveStreams, bQueryWasSuccessful ); - } - }, - TWeakObjectPtr< UQueryLiveStreamsCallbackProxy>( this ) ) - ); -} diff --git a/Engine/Source/Runtime/GameLiveStreaming/QueryLiveStreamsCallbackProxy.h b/Engine/Source/Runtime/GameLiveStreaming/QueryLiveStreamsCallbackProxy.h deleted file mode 100644 index 232cc2e937df..000000000000 --- a/Engine/Source/Runtime/GameLiveStreaming/QueryLiveStreamsCallbackProxy.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#pragma once - -#include "CoreMinimal.h" -#include "UObject/ObjectMacros.h" -#include "Net/OnlineBlueprintCallProxyBase.h" -#include "QueryLiveStreamsCallbackProxy.generated.h" - -USTRUCT( BlueprintType ) -struct FBlueprintLiveStreamInfo -{ - GENERATED_USTRUCT_BODY() - - /** Name of the game that is streaming */ - UPROPERTY( EditAnywhere, Category="LiveStreaming" ) - FString GameName; - - /** The title of the stream itself */ - UPROPERTY( EditAnywhere, Category="LiveStreaming" ) - FString StreamName; - - /** URL for the stream */ - UPROPERTY( EditAnywhere, Category="LiveStreaming" ) - FString URL; -}; - - -DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams( FOnQueryLiveStreamsCompleted, const TArray&, LiveStreams, bool, bWasSuccessful ); - -UCLASS() -class UQueryLiveStreamsCallbackProxy : public UOnlineBlueprintCallProxyBase -{ - GENERATED_UCLASS_BODY() - - // Called when the asynchronous request for live streams completes, passing along the list of live streams currently active, along with a boolean value that indicates whether the request was successful at all - UPROPERTY( BlueprintAssignable ) - FOnQueryLiveStreamsCompleted OnQueriedLiveStreams; - - /** Requests a list of live internet streams for the specified game name. This will usually hit the internet so it could take a second or two. */ - UFUNCTION( BlueprintCallable, Category="LiveStreaming", meta=( BlueprintInternalUseOnly="true" ) ) - static UQueryLiveStreamsCallbackProxy* QueryLiveStreams( const FString& GameName ); - - /** UOnlineBlueprintCallProxyBase interface */ - virtual void Activate() override; - - -protected: - - /** Name of the game that we're querying about */ - FString GameName; -}; diff --git a/Engine/Source/Runtime/GameMenuBuilder/Private/SGameMenuPageWidget.cpp b/Engine/Source/Runtime/GameMenuBuilder/Private/SGameMenuPageWidget.cpp index 594be4c1b47d..f5b5dcc6b0d3 100644 --- a/Engine/Source/Runtime/GameMenuBuilder/Private/SGameMenuPageWidget.cpp +++ b/Engine/Source/Runtime/GameMenuBuilder/Private/SGameMenuPageWidget.cpp @@ -939,9 +939,9 @@ FReply SGameMenuPageWidget::OnKeyDown(const FGeometry& MyGeometry, const FKeyEve { FReply Result = FReply::Unhandled(); - if ((CurrentMenu.IsValid() == true) && (!bControlsLocked)) + if ((CurrentMenu.IsValid() == true) && !bControlsLocked) { - bool bNavigationLocked = bControlsLocked || PendingMainMenu.IsValid() || PendingSubMenu.IsValid(); + bool bNavigationLocked = PendingMainMenu.IsValid() || PendingSubMenu.IsValid(); const FKey Key = InKeyEvent.GetKey(); if (bNavigationLocked == false) diff --git a/Engine/Source/Runtime/GameplayTags/Classes/GameplayTagContainer.h b/Engine/Source/Runtime/GameplayTags/Classes/GameplayTagContainer.h index 6d5c2bad46cd..2ab35f0cede6 100644 --- a/Engine/Source/Runtime/GameplayTags/Classes/GameplayTagContainer.h +++ b/Engine/Source/Runtime/GameplayTags/Classes/GameplayTagContainer.h @@ -234,7 +234,7 @@ PRAGMA_DISABLE_DEPRECATION_WARNINGS PRAGMA_ENABLE_DEPRECATION_WARNINGS -private: +protected: /** Intentionally private so only the tag manager can use */ explicit FGameplayTag(FName InTagName); @@ -855,6 +855,13 @@ struct TStructOpsTypeTraits : public TStructOpsTypeTraits }; }; +struct GAMEPLAYTAGS_API FGameplayTagNativeAdder +{ + FGameplayTagNativeAdder(); + + virtual void AddTags() = 0; +}; + /** * Helper struct for viewing tag references (assets that reference a tag). Drop this into a struct and set the OnGetgameplayStatName. A details customization * will display a tree view of assets referencing the tag @@ -881,6 +888,13 @@ struct FGameplayTagReferenceHelper FOnGetGameplayTagName OnGetGameplayTagName; }; +/** Helper struct: drop this in another struct to get an embedded create new tag widget. */ +USTRUCT() +struct FGameplayTagCreationWidgetHelper +{ + GENERATED_USTRUCT_BODY() +}; + /** Enumerates the list of supported query expression types. */ UENUM() namespace EGameplayTagQueryExprType diff --git a/Engine/Source/Runtime/GameplayTags/Classes/GameplayTagsManager.h b/Engine/Source/Runtime/GameplayTags/Classes/GameplayTagsManager.h index 26fb1a8c132b..129d09925346 100644 --- a/Engine/Source/Runtime/GameplayTags/Classes/GameplayTagsManager.h +++ b/Engine/Source/Runtime/GameplayTags/Classes/GameplayTagsManager.h @@ -9,6 +9,7 @@ #include "UObject/ScriptMacros.h" #include "GameplayTagContainer.h" #include "Engine/DataTable.h" + #include "GameplayTagsManager.generated.h" class UGameplayTagsList; @@ -207,6 +208,12 @@ class GAMEPLAYTAGS_API UGameplayTagsManager : public UObject */ FGameplayTag RequestGameplayTag(FName TagName, bool ErrorIfNotFound=true) const; + /** + * Searches for a gameplay tag given a partial string. This is slow and intended mainly for console commands/utilities to make + * developer life's easier. This will attempt to match as best as it can. If you pass "A.b" it will match on "A.b." before it matches "a.b.c". + */ + FGameplayTag FindGameplayTagFromPartialString_Slow(FString PartialString) const; + /** * Registers the given name as a gameplay tag, and tracks that it is being directly referenced from code * This can only be called during engine initialization, the table needs to be locked down before replication @@ -220,6 +227,8 @@ class GAMEPLAYTAGS_API UGameplayTagsManager : public UObject /** Call to flush the list of native tags, once called it is unsafe to add more */ void DoneAddingNativeTags(); + static FSimpleMulticastDelegate& OnLastChanceToAddNativeTags(); + /** * Gets a Tag Container containing the supplied tag and all of it's parents as explicit tags * @@ -380,6 +389,11 @@ class GAMEPLAYTAGS_API UGameplayTagsManager : public UObject /** Gets a Filtered copy of the GameplayRootTags Array based on the comma delimited filter string passed in */ void GetFilteredGameplayRootTags(const FString& InFilterString, TArray< TSharedPtr >& OutTagArray) const; + /** Returns "Categories" meta property from given handle, used for filtering by tag wiodget */ + FString GetCategoriesMetaFromPropertyHandle(TSharedPtr PropertyHandle) const; + + FString GetCategoriesMetaFromFunction(UFunction* Func) const; + /** Gets a list of all gameplay tag nodes added by the specific source */ void GetAllTagsFromSource(FName TagSource, TArray< TSharedPtr >& OutTagArray) const; @@ -395,6 +409,25 @@ class GAMEPLAYTAGS_API UGameplayTagsManager : public UObject /** Gets a Tag Container containing the all tags in the hierarchy that are children of this tag, and were explicitly added to the dictionary */ FGameplayTagContainer RequestGameplayTagChildrenInDictionary(const FGameplayTag& GameplayTag) const; + /** This is called when EditorRefreshGameplayTagTree. Useful if you need to do anything editor related when tags are added or removed */ + static FSimpleMulticastDelegate OnEditorRefreshGameplayTagTree; + + DECLARE_MULTICAST_DELEGATE_TwoParams(FOnGameplayTagDoubleClickedEditor, FGameplayTag, FSimpleMulticastDelegate& /* OUT */) + FOnGameplayTagDoubleClickedEditor OnGatherGameplayTagDoubleClickedEditor; + + /** Chance to dynamically change filter string based on a property handle */ + DECLARE_MULTICAST_DELEGATE_TwoParams(FOnGetCategoriesMetaFromPropertyHandle, TSharedPtr, FString& /* OUT */) + FOnGetCategoriesMetaFromPropertyHandle OnGetCategoriesMetaFromPropertyHandle; + + /** Allows dynamic hiding of gameplay tags in SGameplayTagWidget. Allows higher order structs to dynamically change which tags are visible based on its own data */ + DECLARE_MULTICAST_DELEGATE_ThreeParams(FOnFilterGameplayTagChildren, const FString& /** FilterString */, TSharedPtr& /* TagNode */, bool& /* OUT OutShouldHide */) + FOnFilterGameplayTagChildren OnFilterGameplayTagChildren; + + void NotifyGameplayTagDoubleClickedEditor(FString TagName); + + bool ShowGameplayTagAsHyperLinkEditor(FString TagName); + + #endif //WITH_EDITOR DEPRECATED(4.15, "Call MatchesTag on FGameplayTag instead") @@ -419,6 +452,8 @@ class GAMEPLAYTAGS_API UGameplayTagsManager : public UObject return bResult; } + void PrintReplicationIndices(); + #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) /** Mechanism for tracking what tags are frequently replicated */ diff --git a/Engine/Source/Runtime/GameplayTags/Private/GameplayTagContainer.cpp b/Engine/Source/Runtime/GameplayTags/Private/GameplayTagContainer.cpp index 0185e58d0df0..7f5aae2e6951 100644 --- a/Engine/Source/Runtime/GameplayTags/Private/GameplayTagContainer.cpp +++ b/Engine/Source/Runtime/GameplayTags/Private/GameplayTagContainer.cpp @@ -1339,6 +1339,12 @@ void FGameplayTag::FromExportString(FString ExportString) FGameplayTag::StaticStruct()->ImportText(*ExportString, this, nullptr, 0, &NullOut, TEXT("FGameplayTag"), true); } +FGameplayTagNativeAdder::FGameplayTagNativeAdder() +{ + UE_LOG(LogGameplayTags, Display, TEXT("FGameplayTagNativeAdder::FGameplayTagNativeAdder")); + UGameplayTagsManager::OnLastChanceToAddNativeTags().AddRaw(this, &FGameplayTagNativeAdder::AddTags); +} + FGameplayTagQuery::FGameplayTagQuery() : TokenStreamVersion(EGameplayTagQueryStreamVersion::LatestVersion) { @@ -1894,6 +1900,16 @@ FAutoConsoleCommand GameplayTagPrintReplicationMapCmd( FConsoleCommandDelegate::CreateStatic(GameplayTagPrintReplicationMap) ); +static void GameplayTagPrintReplicationIndices() +{ + UGameplayTagsManager::Get().PrintReplicationIndices(); +} + +FAutoConsoleCommand GameplayTagPrintReplicationIndicesCmd( + TEXT("GameplayTags.PrintNetIndices"), + TEXT( "Prints net indices for all known tags" ), + FConsoleCommandDelegate::CreateStatic(GameplayTagPrintReplicationIndices) +); static void TagPackingTest() { diff --git a/Engine/Source/Runtime/GameplayTags/Private/GameplayTagsManager.cpp b/Engine/Source/Runtime/GameplayTags/Private/GameplayTagsManager.cpp index 582e419132c8..43708539a1ff 100644 --- a/Engine/Source/Runtime/GameplayTags/Private/GameplayTagsManager.cpp +++ b/Engine/Source/Runtime/GameplayTags/Private/GameplayTagsManager.cpp @@ -15,13 +15,17 @@ #include "GameplayTagsModule.h" #include "Framework/Notifications/NotificationManager.h" #include "Widgets/Notifications/SNotificationList.h" -#include "Engine/Engine.h" +#include "Misc/CoreDelegates.h" #if WITH_EDITOR #include "SourceControlHelpers.h" #include "ISourceControlModule.h" #include "Editor.h" +#include "PropertyHandle.h" +FSimpleMulticastDelegate UGameplayTagsManager::OnEditorRefreshGameplayTagTree; #endif +#include "IConsoleManager.h" + #define LOCTEXT_NAMESPACE "GameplayTagManager" @@ -67,7 +71,10 @@ struct FCompareFGameplayTagNodeByTag { FORCEINLINE bool operator()( const TSharedPtr& A, const TSharedPtr& B ) const { - return (A->GetSimpleTagName().Compare(B->GetSimpleTagName())) < 0; + // Note: GetSimpleTagName() is not good enough here. The individual tag nodes are share frequently (E.g, Dog.Tail, Cat.Tail have sub nodes with the same simple tag name) + // Compare with equal FNames will look at the backing number/indice to the FName. For FNames used elsewhere, like "A" for example, this can cause non determinism in platforms + // (For example if static order initialization differs on two platforms, the "version" of the "A" FName that two places get could be different, causing this comparison to also be) + return (A->GetCompleteTagName().Compare(B->GetCompleteTagName())) < 0; } }; @@ -268,11 +275,21 @@ void UGameplayTagsManager::ConstructGameplayTagTree() FGameplayTag OldTag = RequestGameplayTag(OldTagName, false); //< This only succeeds if OldTag is in the Table! if (OldTag.IsValid()) { - UE_LOG(LogGameplayTags, Warning, - TEXT("Old tag (%s) which is being redirected still exists in the table! Generally you should " + FGameplayTagContainer MatchingChildren = RequestGameplayTagChildren(OldTag); + + FString Msg = FString::Printf(TEXT("Old tag (%s) which is being redirected still exists in the table! Generally you should " TEXT("remove the old tags from the table when you are redirecting to new tags, or else users will ") - TEXT("still be able to add the old tags to containers.")), *OldTagName.ToString() - ); + TEXT("still be able to add the old tags to containers.")), *OldTagName.ToString()); + + if (MatchingChildren.Num() == 0) + { + UE_LOG(LogGameplayTags, Warning, TEXT("%s"), *Msg); + } + else + { + Msg += TEXT("\nSuppressed warning due to redirected tag being a single component that matched other hierarchy elements."); + UE_LOG(LogGameplayTags, Log, TEXT("%s"), *Msg); + } } FGameplayTag NewTag = (NewTagName != NAME_None) ? RequestGameplayTag(NewTagName, false) : FGameplayTag(); @@ -314,6 +331,8 @@ void UGameplayTagsManager::ConstructGameplayTagTree() } } +int32 PrintNetIndiceAssignment = 0; +static FAutoConsoleVariableRef CVarPrintNetIndiceAssignment(TEXT("GameplayTags.PrintNetIndiceAssignment"), PrintNetIndiceAssignment, TEXT("Logs GameplayTag NetIndice assignment"), ECVF_Default ); void UGameplayTagsManager::ConstructNetIndex() { NetworkGameplayTagNodeIndex.Empty(); @@ -359,11 +378,21 @@ void UGameplayTagsManager::ConstructNetIndex() NetworkGameplayTagNodeIndex.SetNum(INVALID_TAGNETINDEX - 1); } + + + UE_CLOG(PrintNetIndiceAssignment, LogGameplayTags, Display, TEXT("Assigning NetIndices to %d tags."), NetworkGameplayTagNodeIndex.Num() ); + for (FGameplayTagNetIndex i = 0; i < NetworkGameplayTagNodeIndex.Num(); i++) { if (NetworkGameplayTagNodeIndex[i].IsValid()) { NetworkGameplayTagNodeIndex[i]->NetIndex = i; + + UE_CLOG(PrintNetIndiceAssignment, LogGameplayTags, Display, TEXT("Assigning NetIndex (%d) to Tag (%s)"), i, *NetworkGameplayTagNodeIndex[i]->GetCompleteTag().ToString()); + } + else + { + UE_LOG(LogGameplayTags, Warning, TEXT("TagNode Indice %d is invalid!"), i); } } } @@ -515,7 +544,7 @@ void UGameplayTagsManager::InitializeManager() SingletonManager->ConstructGameplayTagTree(); // Bind to end of engine init to be done adding native tags - UEngine::OnPostEngineInit.AddUObject(SingletonManager, &UGameplayTagsManager::DoneAddingNativeTags); + FCoreDelegates::OnPostEngineInit.AddUObject(SingletonManager, &UGameplayTagsManager::DoneAddingNativeTags); } void UGameplayTagsManager::PopulateTreeFromDataTable(class UDataTable* InTable) @@ -646,6 +675,21 @@ int32 UGameplayTagsManager::InsertTagIntoNodeArray(FName Tag, TSharedPtr Node = It.Value; + + UE_LOG(LogGameplayTags, Display, TEXT("Tag %s NetIndex: %d"), *Tag.ToString(), Node->GetNetIndex()); + } + +} + #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) void UGameplayTagsManager::PrintReplicationFrequencyReport() { @@ -843,6 +887,81 @@ void UGameplayTagsManager::GetFilteredGameplayRootTags(const FString& InFilterSt } } +FString UGameplayTagsManager::GetCategoriesMetaFromPropertyHandle(TSharedPtr PropertyHandle) const +{ + // Global delegate override. Useful for parent structs that want to override tag categories based on their data (e.g. not static property meta data) + FString DelegateOverrideString; + OnGetCategoriesMetaFromPropertyHandle.Broadcast(PropertyHandle, DelegateOverrideString); + if (DelegateOverrideString.IsEmpty() == false) + { + return DelegateOverrideString; + } + + + const FName CategoriesName = TEXT("Categories"); + FString Categories; + + auto GetMetaData = ([&](UField* Field) + { + if (Field->HasMetaData(CategoriesName)) + { + Categories = Field->GetMetaData(CategoriesName); + return true; + } + + return false; + }); + + while(PropertyHandle.IsValid()) + { + if (UProperty* Property = PropertyHandle->GetProperty()) + { + /** + * UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (Categories="GameplayCue")) + * FGameplayTag GameplayCueTag; + */ + if (GetMetaData(Property)) + { + break; + } + + /** + * USTRUCT(meta=(Categories="EventKeyword")) + * struct FGameplayEventKeywordTag : public FGameplayTag + */ + if (UStructProperty* StructProperty = Cast(Property)) + { + if (GetMetaData(StructProperty->Struct)) + { + break; + } + } + + /** TArray QualifierTagTestList; */ + if (UArrayProperty* ArrayProperty = Cast(Property)) + { + if (GetMetaData(ArrayProperty->Inner)) + { + break; + } + } + } + PropertyHandle = PropertyHandle->GetParentHandle(); + } + + return Categories; +} + +FString UGameplayTagsManager::GetCategoriesMetaFromFunction(UFunction* ThisFunction) const +{ + FString FilterString; + if (ThisFunction->HasMetaData(TEXT("GameplayTagFilter"))) + { + FilterString = ThisFunction->GetMetaData(TEXT("GameplayTagFilter")); + } + return FilterString; +} + void UGameplayTagsManager::GetAllTagsFromSource(FName TagSource, TArray< TSharedPtr >& OutTagArray) const { for (const TPair>& NodePair : GameplayTagNodeMap) @@ -882,6 +1001,8 @@ void UGameplayTagsManager::EditorRefreshGameplayTagTree() DestroyGameplayTagTree(); LoadGameplayTagTables(); ConstructGameplayTagTree(); + + OnEditorRefreshGameplayTagTree.Broadcast(); } FGameplayTagContainer UGameplayTagsManager::RequestGameplayTagChildrenInDictionary(const FGameplayTag& GameplayTag) const @@ -897,6 +1018,29 @@ FGameplayTagContainer UGameplayTagsManager::RequestGameplayTagChildrenInDictiona return TagContainer; } +void UGameplayTagsManager::NotifyGameplayTagDoubleClickedEditor(FString TagName) +{ + FGameplayTag Tag = RequestGameplayTag(FName(*TagName), false); + if(Tag.IsValid()) + { + FSimpleMulticastDelegate Delegate; + OnGatherGameplayTagDoubleClickedEditor.Broadcast(Tag, Delegate); + Delegate.Broadcast(); + } +} + +bool UGameplayTagsManager::ShowGameplayTagAsHyperLinkEditor(FString TagName) +{ + FGameplayTag Tag = RequestGameplayTag(FName(*TagName), false); + if(Tag.IsValid()) + { + FSimpleMulticastDelegate Delegate; + OnGatherGameplayTagDoubleClickedEditor.Broadcast(Tag, Delegate); + return Delegate.IsBound(); + } + return false; +} + #endif // WITH_EDITOR const FGameplayTagSource* UGameplayTagsManager::FindTagSource(FName TagSourceName) const @@ -976,6 +1120,43 @@ FGameplayTag UGameplayTagsManager::RequestGameplayTag(FName TagName, bool ErrorI return FGameplayTag(); } +FGameplayTag UGameplayTagsManager::FindGameplayTagFromPartialString_Slow(FString PartialString) const +{ +#if WITH_EDITOR + // This critical section is to handle and editor-only issue where tag requests come from another thread when async loading from a background thread in FGameplayTagContainer::Serialize. + // This function is not generically threadsafe. + FScopeLock Lock(&GameplayTagMapCritical); +#endif + + // Exact match first + FGameplayTag PossibleTag(*PartialString); + if (GameplayTagNodeMap.Contains(PossibleTag)) + { + return PossibleTag; + } + + // Find shortest tag name that contains the match string + FGameplayTag FoundTag; + FGameplayTagContainer AllTags; + RequestAllGameplayTags(AllTags, false); + + int32 BestMatchLength = MAX_int32; + for (FGameplayTag MatchTag : AllTags) + { + FString Str = MatchTag.ToString(); + if (Str.Contains(PartialString)) + { + if (Str.Len() < BestMatchLength) + { + FoundTag = MatchTag; + BestMatchLength = Str.Len(); + } + } + } + + return FoundTag; +} + FGameplayTag UGameplayTagsManager::AddNativeGameplayTag(FName TagName) { if (TagName.IsNone()) @@ -1001,11 +1182,19 @@ FGameplayTag UGameplayTagsManager::AddNativeGameplayTag(FName TagName) return FGameplayTag(); } +FSimpleMulticastDelegate& UGameplayTagsManager::OnLastChanceToAddNativeTags() +{ + static FSimpleMulticastDelegate Delegate; + return Delegate; +} + void UGameplayTagsManager::DoneAddingNativeTags() { // Safe to call multiple times, only works the first time if (!bDoneAddingNativeTags) { + UE_LOG(LogGameplayTags, Display, TEXT("UGameplayTagsManager::DoneAddingNativeTags. DelegateIsBound: %d"), (int32)OnLastChanceToAddNativeTags().IsBound()); + OnLastChanceToAddNativeTags().Broadcast(); bDoneAddingNativeTags = true; if (ShouldUseFastReplication()) diff --git a/Engine/Source/Runtime/GameplayTasks/Classes/GameplayTask.h b/Engine/Source/Runtime/GameplayTasks/Classes/GameplayTask.h index 0c2da42f376c..0cff0a311e26 100644 --- a/Engine/Source/Runtime/GameplayTasks/Classes/GameplayTask.h +++ b/Engine/Source/Runtime/GameplayTasks/Classes/GameplayTask.h @@ -135,7 +135,7 @@ public: FString GetDebugDescription() const; }; -UCLASS(Abstract, meta = (ExposedAsyncProxy), config = Game) +UCLASS(Abstract, BlueprintType, meta = (ExposedAsyncProxy), config = Game) class GAMEPLAYTASKS_API UGameplayTask : public UObject, public IGameplayTaskOwnerInterface { GENERATED_BODY() diff --git a/Engine/Source/Runtime/GameplayTasks/Classes/GameplayTasksComponent.h b/Engine/Source/Runtime/GameplayTasks/Classes/GameplayTasksComponent.h index 3d9c884aa6e7..c0647980fc96 100644 --- a/Engine/Source/Runtime/GameplayTasks/Classes/GameplayTasksComponent.h +++ b/Engine/Source/Runtime/GameplayTasks/Classes/GameplayTasksComponent.h @@ -81,6 +81,10 @@ protected: UPROPERTY() TArray TickingTasks; + /** All known tasks (processed by this component) referenced for GC */ + UPROPERTY(transient) + TArray KnownTasks; + /** Indicates what's the highest priority among currently running tasks */ uint8 TopActivePriority; @@ -137,10 +141,12 @@ public: #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) FString GetTickingTasksDescription() const; + FString GetKnownTasksDescription() const; FString GetTasksPriorityQueueDescription() const; static FString GetTaskStateName(EGameplayTaskState Value); #endif // !(UE_BUILD_SHIPPING || UE_BUILD_TEST) FConstGameplayTaskIterator GetTickingTaskIterator() const; + FConstGameplayTaskIterator GetKnownTaskIterator() const; FConstGameplayTaskIterator GetPriorityQueueIterator() const; #if ENABLE_VISUAL_LOG diff --git a/Engine/Source/Runtime/GameplayTasks/Private/GameplayTask.cpp b/Engine/Source/Runtime/GameplayTasks/Private/GameplayTask.cpp index 9282d2623d21..467600e0c8e6 100644 --- a/Engine/Source/Runtime/GameplayTasks/Private/GameplayTask.cpp +++ b/Engine/Source/Runtime/GameplayTasks/Private/GameplayTask.cpp @@ -143,10 +143,18 @@ void UGameplayTask::TaskOwnerEnded() , TEXT("%s TaskOwnerEnded called, current State: %s") , *GetName(), *GetTaskStateName()); - if (TaskState != EGameplayTaskState::Finished && !IsPendingKill()) + if (TaskState != EGameplayTaskState::Finished) { bOwnerFinished = true; - OnDestroy(true); + if (IsPendingKill() == false) + { + OnDestroy(true); + } + else + { + // mark as finished, just to be on the safe side + TaskState = EGameplayTaskState::Finished; + } } } @@ -156,9 +164,17 @@ void UGameplayTask::EndTask() , TEXT("%s EndTask called, current State: %s") , *GetName(), *GetTaskStateName()); - if (TaskState != EGameplayTaskState::Finished && !IsPendingKill()) + if (TaskState != EGameplayTaskState::Finished) { - OnDestroy(false); + if (IsPendingKill() == false) + { + OnDestroy(false); + } + else + { + // mark as finished, just to be on the safe side + TaskState = EGameplayTaskState::Finished; + } } } diff --git a/Engine/Source/Runtime/GameplayTasks/Private/GameplayTasksComponent.cpp b/Engine/Source/Runtime/GameplayTasks/Private/GameplayTasksComponent.cpp index f7288598f8b4..cbbf0adde0ad 100644 --- a/Engine/Source/Runtime/GameplayTasks/Private/GameplayTasksComponent.cpp +++ b/Engine/Source/Runtime/GameplayTasks/Private/GameplayTasksComponent.cpp @@ -60,6 +60,7 @@ void UGameplayTasksComponent::OnGameplayTaskActivated(UGameplayTask& Task) { // process events after finishing all operations FEventLock ScopeEventLock(this); + KnownTasks.Add(&Task); if (Task.IsTickingTask()) { @@ -72,6 +73,7 @@ void UGameplayTasksComponent::OnGameplayTaskActivated(UGameplayTask& Task) UpdateShouldTick(); } } + if (Task.IsSimulatedTask()) { check(SimulatedTasks.Contains(&Task) == false); @@ -109,6 +111,11 @@ void UGameplayTasksComponent::OnGameplayTaskDeactivated(UGameplayTask& Task) TickingTasks.RemoveSingleSwap(&Task); } + if (bIsFinished) + { + KnownTasks.RemoveSingleSwap(&Task); + } + if (Task.IsSimulatedTask()) { SimulatedTasks.RemoveSingleSwap(&Task); @@ -322,17 +329,9 @@ UGameplayTask* UGameplayTasksComponent::FindResourceConsumingTaskByName(const FN bool UGameplayTasksComponent::HasActiveTasks(UClass* TaskClass) const { - for (int32 Idx = 0; Idx < TaskPriorityQueue.Num(); Idx++) + for (int32 Idx = 0; Idx < KnownTasks.Num(); Idx++) { - if (TaskPriorityQueue[Idx] && TaskPriorityQueue[Idx]->IsA(TaskClass)) - { - return true; - } - } - - for (int32 Idx = 0; Idx < TickingTasks.Num(); Idx++) - { - if (TickingTasks[Idx] && TickingTasks[Idx]->IsA(TaskClass)) + if (KnownTasks[Idx] && KnownTasks[Idx]->IsA(TaskClass)) { return true; } @@ -482,7 +481,9 @@ void UGameplayTasksComponent::UpdateTaskActivations() for (int32 Idx = 0; Idx < ActivationList.Num(); Idx++) { // check if task wasn't already finished as a result of activating previous elements of this list - if (ActivationList[Idx] && !ActivationList[Idx]->IsFinished()) + if (ActivationList[Idx] != nullptr + && ActivationList[Idx]->IsFinished() == false + && ActivationList[Idx]->IsPendingKill() == false) { ActivationList[Idx]->ActivateInTaskQueue(); } @@ -530,6 +531,23 @@ FString UGameplayTasksComponent::GetTickingTasksDescription() const return TasksDescription; } +FString UGameplayTasksComponent::GetKnownTasksDescription() const +{ + FString TasksDescription; + for (auto& Task : KnownTasks) + { + if (Task) + { + TasksDescription += FString::Printf(TEXT("\n%s %s"), *GetTaskStateName(Task->GetState()), *Task->GetDebugDescription()); + } + else + { + TasksDescription += TEXT("\nNULL"); + } + } + return TasksDescription; +} + FString UGameplayTasksComponent::GetTasksPriorityQueueDescription() const { FString TasksDescription; @@ -560,6 +578,11 @@ FConstGameplayTaskIterator UGameplayTasksComponent::GetTickingTaskIterator() con return TickingTasks.CreateConstIterator(); } +FConstGameplayTaskIterator UGameplayTasksComponent::GetKnownTaskIterator() const +{ + return KnownTasks.CreateConstIterator(); +} + FConstGameplayTaskIterator UGameplayTasksComponent::GetPriorityQueueIterator() const { return TaskPriorityQueue.CreateConstIterator(); @@ -569,17 +592,35 @@ FConstGameplayTaskIterator UGameplayTasksComponent::GetPriorityQueueIterator() c void UGameplayTasksComponent::DescribeSelfToVisLog(FVisualLogEntry* Snapshot) const { static const FString CategoryName = TEXT("GameplayTasks"); - static const FString TickingTasksName = TEXT("Ticking tasks"); static const FString PriorityQueueName = TEXT("Priority Queue"); + static const FString OtherTasksName = TEXT("Other tasks"); if (IsPendingKill()) { return; } - FVisualLogStatusCategory StatusCategory(CategoryName); + FString NotInQueueDesc; + for (auto& Task : KnownTasks) + { + if (Task) + { + if (!Task->RequiresPriorityOrResourceManagement()) + { + NotInQueueDesc += FString::Printf(TEXT("\n%s %s %s %s"), + *GetTaskStateName(Task->GetState()), *Task->GetDebugDescription(), + Task->IsTickingTask() ? TEXT("[TICK]") : TEXT(""), + Task->IsSimulatedTask() ? TEXT("[REP]") : TEXT("")); + } + } + else + { + NotInQueueDesc += TEXT("\nNULL"); + } + } - StatusCategory.Add(TickingTasksName, GetTickingTasksDescription()); + FVisualLogStatusCategory StatusCategory(CategoryName); + StatusCategory.Add(OtherTasksName, NotInQueueDesc); StatusCategory.Add(PriorityQueueName, GetTasksPriorityQueueDescription()); Snapshot->Status.Add(StatusCategory); diff --git a/Engine/Source/Runtime/GameplayTasks/Private/Tasks/GameplayTask_TimeLimitedExecution.cpp b/Engine/Source/Runtime/GameplayTasks/Private/Tasks/GameplayTask_TimeLimitedExecution.cpp index 306f7100c9a2..33e6cb7ff8aa 100644 --- a/Engine/Source/Runtime/GameplayTasks/Private/Tasks/GameplayTask_TimeLimitedExecution.cpp +++ b/Engine/Source/Runtime/GameplayTasks/Private/Tasks/GameplayTask_TimeLimitedExecution.cpp @@ -3,6 +3,8 @@ #include "Tasks/GameplayTask_TimeLimitedExecution.h" #include "Engine/EngineTypes.h" #include "TimerManager.h" +#include "VisualLogger/VisualLogger.h" +#include "GameplayTasksComponent.h" #include "Engine/World.h" UGameplayTask_TimeLimitedExecution::UGameplayTask_TimeLimitedExecution(const FObjectInitializer& ObjectInitializer) @@ -47,6 +49,7 @@ void UGameplayTask_TimeLimitedExecution::Activate() // Use a dummy timer handle as we don't need to store it for later but we don't need to look for something to clear FTimerHandle TimerHandle; World->GetTimerManager().SetTimer(TimerHandle, this, &UGameplayTask_TimeLimitedExecution::OnTimer, Time, false); + UE_VLOG(GetGameplayTasksComponent(), LogGameplayTasks, Verbose, TEXT("%s> started timeout: %.2fs for task:%s"), *GetName(), Time, *ChildTask->GetName()); if (!ChildTask->IsActive()) { @@ -82,6 +85,7 @@ void UGameplayTask_TimeLimitedExecution::OnTimer() { if (!bTimeExpired && !bChildTaskFinished) { + UE_VLOG(GetGameplayTasksComponent(), LogGameplayTasks, Verbose, TEXT("%s> time expired!"), *GetName()); OnTimeExpired.Broadcast(); } diff --git a/Engine/Source/Runtime/GeometryCache/Classes/GeometryCacheActor.h b/Engine/Source/Runtime/GeometryCache/Classes/GeometryCacheActor.h index 2490b5b11a6d..63e0ca20ecd1 100644 --- a/Engine/Source/Runtime/GeometryCache/Classes/GeometryCacheActor.h +++ b/Engine/Source/Runtime/GeometryCache/Classes/GeometryCacheActor.h @@ -20,7 +20,7 @@ class GEOMETRYCACHE_API AGeometryCacheActor : public AActor virtual bool GetReferencedContentObjects(TArray& Objects) const override; #endif // WITH_EDITOR // End AActor overrides. -private_subobject: +private: UPROPERTY(Category = GeometryCacheActor, VisibleAnywhere, BlueprintReadOnly, meta = (ExposeFunctionCategories = "Mesh,Rendering,Physics,Components|GeometryCache", AllowPrivateAccess = "true")) UGeometryCacheComponent* GeometryCacheComponent; public: diff --git a/Engine/Source/Runtime/GeometryCache/Private/GeometryCache.cpp b/Engine/Source/Runtime/GeometryCache/Private/GeometryCache.cpp index 365a44d85ced..f0a5383ef86a 100644 --- a/Engine/Source/Runtime/GeometryCache/Private/GeometryCache.cpp +++ b/Engine/Source/Runtime/GeometryCache/Private/GeometryCache.cpp @@ -29,7 +29,7 @@ void UGeometryCache::Serialize(FArchive& Ar) { Ar.UsingCustomVersion(FFrameworkObjectVersion::GUID); #if WITH_EDITORONLY_DATA - if (( !Ar.IsCooking() || (Ar.CookingTarget() && Ar.CookingTarget()->HasEditorOnlyData()))) + if ( !Ar.IsCooking() || (Ar.CookingTarget() && Ar.CookingTarget()->HasEditorOnlyData())) { Ar << AssetImportData; } @@ -55,7 +55,7 @@ void UGeometryCache::GetResourceSizeEx(FResourceSizeEx& CumulativeResourceSize) Super::GetResourceSizeEx(CumulativeResourceSize); #if WITH_EDITORONLY_DATA - CumulativeResourceSize.AddDedicatedSystemMemoryBytes(sizeof(AssetImportData)); + CumulativeResourceSize.AddDedicatedSystemMemoryBytes(sizeof(AssetImportData)); //-V568 #endif // Calculate Resource Size according to what is serialized const int32 NumTracks = Tracks.Num(); diff --git a/Engine/Source/Runtime/HTML5/HTML5PlatformFeatures/Private/HTML5SaveGameSystem.cpp b/Engine/Source/Runtime/HTML5/HTML5PlatformFeatures/Private/HTML5SaveGameSystem.cpp index 0d6af9b42727..22f343003082 100644 --- a/Engine/Source/Runtime/HTML5/HTML5PlatformFeatures/Private/HTML5SaveGameSystem.cpp +++ b/Engine/Source/Runtime/HTML5/HTML5PlatformFeatures/Private/HTML5SaveGameSystem.cpp @@ -46,9 +46,9 @@ void FHTML5SaveGameSystem::Shutdown() // ); } -bool FHTML5SaveGameSystem::DoesSaveGameExist(const TCHAR* Name, const int32 UserIndex) +ISaveGameSystem::ESaveExistsResult FHTML5SaveGameSystem::DoesSaveGameExistWithResult(const TCHAR* Name, const int32 UserIndex) { - return UE_DoesSaveGameExist(GetSaveGamePath(Name, UserIndex)); + return UE_DoesSaveGameExist(GetSaveGamePath(Name, UserIndex)) ? ESaveExistsResult::OK : ESaveExistsResult::DoesNotExist; } bool FHTML5SaveGameSystem::SaveGame(bool bAttemptToUseUI, const TCHAR* Name, const int32 UserIndex, const TArray& Data) diff --git a/Engine/Source/Runtime/HTML5/HTML5PlatformFeatures/Private/HTML5SaveGameSystem.h b/Engine/Source/Runtime/HTML5/HTML5PlatformFeatures/Private/HTML5SaveGameSystem.h index 9c6a33909442..8ee51c8d295f 100644 --- a/Engine/Source/Runtime/HTML5/HTML5PlatformFeatures/Private/HTML5SaveGameSystem.h +++ b/Engine/Source/Runtime/HTML5/HTML5PlatformFeatures/Private/HTML5SaveGameSystem.h @@ -18,7 +18,12 @@ public: return false; } - virtual bool DoesSaveGameExist(const TCHAR* Name, const int32 UserIndex) override; + virtual bool DoesSaveGameExist(const TCHAR* Name, const int32 UserIndex) override + { + return ESaveExistsResult::OK == DoesSaveGameExistWithResult(Name, UserIndex); + } + + virtual ESaveExistsResult DoesSaveGameExistWithResult(const TCHAR* Name, const int32 UserIndex) override; virtual bool SaveGame(bool bAttemptToUseUI, const TCHAR* Name, const int32 UserIndex, const TArray& Data) override; diff --git a/Engine/Source/Runtime/HeadMountedDisplay/Private/DefaultStereoLayers.cpp b/Engine/Source/Runtime/HeadMountedDisplay/Private/DefaultStereoLayers.cpp index 9fd5ca4761a9..073774391863 100644 --- a/Engine/Source/Runtime/HeadMountedDisplay/Private/DefaultStereoLayers.cpp +++ b/Engine/Source/Runtime/HeadMountedDisplay/Private/DefaultStereoLayers.cpp @@ -64,7 +64,16 @@ void FDefaultStereoLayers::StereoLayerRender(FRHICommandListImmediate& RHICmdLis // Set render state FGraphicsPipelineStateInitializer GraphicsPSOInit; RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit); - GraphicsPSOInit.BlendState = TStaticBlendState::GetRHI(); + bool bLastNoAlpha = (RenderThreadLayers[LayersToRender[0]].Flags & LAYER_FLAG_TEX_NO_ALPHA_CHANNEL) != 0; + if (bLastNoAlpha) + { + GraphicsPSOInit.BlendState = TStaticBlendState::GetRHI(); + } + else + { + GraphicsPSOInit.BlendState = TStaticBlendState::GetRHI(); + } + GraphicsPSOInit.RasterizerState = TStaticRasterizerState::GetRHI(); GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState::GetRHI(); RHICmdList.SetScissorRect(false, 0, 0, 0, 0); @@ -86,19 +95,37 @@ void FDefaultStereoLayers::StereoLayerRender(FRHICommandListImmediate& RHICmdLis { const FLayerDesc& Layer = RenderThreadLayers[LayerIndex]; check(Layer.Texture.IsValid()); + const bool bNoAlpha = (Layer.Flags & LAYER_FLAG_TEX_NO_ALPHA_CHANNEL) != 0; + if (bNoAlpha != bLastNoAlpha) + { + // Updater render state + if (bNoAlpha) + { + GraphicsPSOInit.BlendState = TStaticBlendState::GetRHI(); + } + else + { + GraphicsPSOInit.BlendState = TStaticBlendState::GetRHI(); + } + SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit); + bLastNoAlpha = bNoAlpha; + } FMatrix LayerMatrix = ConvertTransform(Layer.Transform); FVector2D QuadSize = Layer.QuadSize * 0.5f; if (Layer.Flags & LAYER_FLAG_QUAD_PRESERVE_TEX_RATIO) { - const FRHITexture2D* Tex2D = Layer.Texture.GetReference()->GetTexture2D(); + const FRHITexture2D* Tex2D = Layer.Texture->GetTexture2D(); if (Tex2D) { const float SizeX = Tex2D->GetSizeX(); const float SizeY = Tex2D->GetSizeY(); - const float AspectRatio = SizeY / SizeX; - QuadSize.Y = QuadSize.X * AspectRatio; + if (SizeX != 0) + { + const float AspectRatio = SizeY / SizeX; + QuadSize.Y = QuadSize.X * AspectRatio; + } } } @@ -177,8 +204,11 @@ void FDefaultStereoLayers::PostRenderView_RenderThread(FRHICommandListImmediate& { return; } - const FMatrix& ProjectionMatrix = InView.ViewMatrices.GetProjectionMatrix(); - const FMatrix& ViewProjectionMatrix = InView.ViewMatrices.GetViewProjectionMatrix(); + + FViewMatrices ModifiedViewMatrices = InView.ViewMatrices; + ModifiedViewMatrices.HackRemoveTemporalAAProjectionJitter(); + const FMatrix& ProjectionMatrix = ModifiedViewMatrices.GetProjectionMatrix(); + const FMatrix& ViewProjectionMatrix = ModifiedViewMatrices.GetViewProjectionMatrix(); // Calculate a view matrix that only adjusts for eye position, ignoring head position, orientation and world position. FVector EyeShift = FVector(0, (InView.StereoPass == EStereoscopicPass::eSSP_LEFT_EYE ? .5 : -.5) * IPD * InView.WorldToMetersScale, 0); @@ -215,7 +245,7 @@ void FDefaultStereoLayers::PostRenderView_RenderThread(FRHICommandListImmediate& if (OverlayRenderTarget.IsValid()) { SetRenderTarget(RHICmdList, OverlayRenderTarget, FTextureRHIRef()); - DrawClearQuad(RHICmdList, GMaxRHIFeatureLevel, FLinearColor(0.0f, 0.0f, 0.0f, 0.0f)); + DrawClearQuad(RHICmdList, FLinearColor(0.0f, 0.0f, 0.0f, 0.0f)); RHICmdList.SetViewport(RenderParams.Viewport.Min.X, RenderParams.Viewport.Min.Y, 0, RenderParams.Viewport.Max.X, RenderParams.Viewport.Max.Y, 1.0f); } diff --git a/Engine/Source/Runtime/HeadMountedDisplay/Private/HeadMountedDisplayConsoleCommands.cpp b/Engine/Source/Runtime/HeadMountedDisplay/Private/HeadMountedDisplayConsoleCommands.cpp index 8ef55dd01b5b..deff804efda1 100644 --- a/Engine/Source/Runtime/HeadMountedDisplay/Private/HeadMountedDisplayConsoleCommands.cpp +++ b/Engine/Source/Runtime/HeadMountedDisplay/Private/HeadMountedDisplayConsoleCommands.cpp @@ -38,6 +38,13 @@ static TAutoConsoleVariable CVarEnableDevOverrides( 0, *LOCTEXT("CVarText_EnableDevOverrides", "Enables or disables console commands that modify various developer-only settings.").ToString()); +static TAutoConsoleVariable CVarMixLayerPriorities( + TEXT("vr.StereoLayers.bMixLayerPriorities"), + 0, + *LOCTEXT("CVarText_MixLayerPriorities", "By default, Face-Locked Stereo Layers are always rendered on top of any other layer position types.\nSet this to a non-zero value to disable this behavior (not supported on all platforms.)").ToString(), + ECVF_RenderThreadSafe); + + #if !UE_BUILD_SHIPPING static void DrawDebugTrackingSensorLocations(UCanvas* Canvas, APlayerController* PlayerController, UWorld* World) @@ -447,3 +454,6 @@ static bool CompatExec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) } static FStaticSelfRegisteringExec CompatExecRegistration(CompatExec); + +#undef LOCTEXT_NAMESPACE + diff --git a/Engine/Source/Runtime/HeadMountedDisplay/Private/HeadMountedDisplayTypes.cpp b/Engine/Source/Runtime/HeadMountedDisplay/Private/HeadMountedDisplayTypes.cpp index cf68fa014aa3..fae5ad677209 100644 --- a/Engine/Source/Runtime/HeadMountedDisplay/Private/HeadMountedDisplayTypes.cpp +++ b/Engine/Source/Runtime/HeadMountedDisplay/Private/HeadMountedDisplayTypes.cpp @@ -3,6 +3,9 @@ #include "HeadMountedDisplayTypes.h" #include "RendererInterface.h" +DEFINE_LOG_CATEGORY(LogHMD); +DEFINE_LOG_CATEGORY(LogLoadingSplash); + FHMDViewMesh::FHMDViewMesh() : pVertices(nullptr), pIndices(nullptr), diff --git a/Engine/Source/Runtime/HeadMountedDisplay/Public/HeadMountedDisplay.h b/Engine/Source/Runtime/HeadMountedDisplay/Public/HeadMountedDisplay.h index f1cb22145eeb..8ced612755c5 100644 --- a/Engine/Source/Runtime/HeadMountedDisplay/Public/HeadMountedDisplay.h +++ b/Engine/Source/Runtime/HeadMountedDisplay/Public/HeadMountedDisplay.h @@ -5,4 +5,3 @@ #include "IHeadMountedDisplayModule.h" #include "HeadMountedDisplayTypes.h" #include "IHeadMountedDisplay.h" - diff --git a/Engine/Source/Runtime/HeadMountedDisplay/Public/HeadMountedDisplayTypes.h b/Engine/Source/Runtime/HeadMountedDisplay/Public/HeadMountedDisplayTypes.h index fe4fa96817ae..bf85a8bfe78a 100644 --- a/Engine/Source/Runtime/HeadMountedDisplay/Public/HeadMountedDisplayTypes.h +++ b/Engine/Source/Runtime/HeadMountedDisplay/Public/HeadMountedDisplayTypes.h @@ -48,3 +48,6 @@ public: unsigned NumIndices; unsigned NumTriangles; }; + +HEADMOUNTEDDISPLAY_API DECLARE_LOG_CATEGORY_EXTERN(LogHMD, Log, All); +HEADMOUNTEDDISPLAY_API DECLARE_LOG_CATEGORY_EXTERN(LogLoadingSplash, Log, All); diff --git a/Engine/Source/Runtime/IOS/IOSAudio/Private/IOSAudioSource.cpp b/Engine/Source/Runtime/IOS/IOSAudio/Private/IOSAudioSource.cpp index 1af577c3c676..77e22cf6a3d1 100644 --- a/Engine/Source/Runtime/IOS/IOSAudio/Private/IOSAudioSource.cpp +++ b/Engine/Source/Runtime/IOS/IOSAudio/Private/IOSAudioSource.cpp @@ -180,6 +180,12 @@ bool FIOSAudioSoundSource::Init(FWaveInstance* InWaveInstance) UE_CLOG(Status != noErr, LogIOSAudio, Error, TEXT("Failed to set k3DMixerParam_Azimuth for audio mixer unit: BusNumber=%d, Channel=%d"), BusNumber, Channel); } + // Seek into the file if we've been given a non-zero start time. + if (WaveInstance->StartTime > 0.0f) + { + IOSBuffer->DecompressionState->SeekToTime(WaveInstance->StartTime); + } + // Start in a disabled state DetachFromAUGraph(); Update(); @@ -274,16 +280,17 @@ void FIOSAudioSoundSource::Play(void) void FIOSAudioSoundSource::Stop(void) { + // Wait for the render callback to finish and then prevent it from being entered again in case this object is deleted after being stopped + while (!LockCallback(&CallbackLock)) + { + UE_LOG(LogIOSAudio, Log, TEXT("Waiting for source to unlock")); + + // Allow time for other threads to run + FPlatformProcess::Sleep(0.0f); + } + if (WaveInstance) { - // Wait for the render callback to finish and then prevent it from being entered again in case this object is deleted after being stopped - while (!LockCallback(&CallbackLock)) - { - UE_LOG(LogIOSAudio, Log, TEXT("Waiting for source to unlock")); - - // Allow time for other threads to run - FPlatformProcess::Sleep(0.0f); - } // At this point we are no longer in the render callback and we will not re-enter it either @@ -292,17 +299,21 @@ void FIOSAudioSoundSource::Stop(void) Paused = false; Playing = false; + } - FSoundSource::Stop(); + // Call parent class version regardless of if there's a wave instance + FSoundSource::Stop(); + if (WaveInstance) + { if(IOSBuffer != NULL) { IOSBuffer->DecompressionState->SeekToTime(0.0f); } - - // It's now safe to unlock the callback - UnlockCallback(&CallbackLock); } + + // It's now safe to unlock the callback + UnlockCallback(&CallbackLock); } void FIOSAudioSoundSource::Pause(void) diff --git a/Engine/Source/Runtime/IOS/IOSLocalNotification/Private/IOSLocalNotification.cpp b/Engine/Source/Runtime/IOS/IOSLocalNotification/Private/IOSLocalNotification.cpp index de62dae855e7..26dff56db96a 100644 --- a/Engine/Source/Runtime/IOS/IOSLocalNotification/Private/IOSLocalNotification.cpp +++ b/Engine/Source/Runtime/IOS/IOSLocalNotification/Private/IOSLocalNotification.cpp @@ -33,6 +33,48 @@ public: return oneTrueLocalNotificationService; } + +#if !PLATFORM_TVOS + static UILocalNotification* CreateLocalNotification(const FDateTime& FireDateTime, bool bLocalTime, const FString& ActivationEvent) + { + UIApplication* application = [UIApplication sharedApplication]; + + NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar]; + NSDateComponents *dateComps = [[NSDateComponents alloc] init]; + [dateComps setDay : FireDateTime.GetDay()]; + [dateComps setMonth : FireDateTime.GetMonth()]; + [dateComps setYear : FireDateTime.GetYear()]; + [dateComps setHour : FireDateTime.GetHour()]; + [dateComps setMinute : FireDateTime.GetMinute()]; + [dateComps setSecond : FireDateTime.GetSecond()]; + NSDate *itemDate = [calendar dateFromComponents : dateComps]; + + UILocalNotification *localNotif = [[UILocalNotification alloc] init]; + if (localNotif != nil) + { + localNotif.fireDate = itemDate; + if (bLocalTime) + { + localNotif.timeZone = [NSTimeZone defaultTimeZone]; + } + else + { + localNotif.timeZone = nil; + } + + NSString* activateEventNSString = [NSString stringWithFString:ActivationEvent]; + if (activateEventNSString != nil) + { + NSDictionary* infoDict = [NSDictionary dictionaryWithObject:activateEventNSString forKey:@"ActivationEvent"]; + if (infoDict != nil) + { + localNotif.userInfo = infoDict; + } + } + } + return localNotif; + } +#endif }; IMPLEMENT_MODULE(FIOSLocalNotificationModule, IOSLocalNotification); @@ -58,34 +100,12 @@ void FIOSLocalNotificationService::ClearAllLocalNotifications() void FIOSLocalNotificationService::ScheduleLocalNotificationAtTime(const FDateTime& FireDateTime, bool LocalTime, const FText& Title, const FText& Body, const FText& Action, const FString& ActivationEvent) { #if !PLATFORM_TVOS - UIApplication* application = [UIApplication sharedApplication]; - - NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar]; - NSDateComponents *dateComps = [[NSDateComponents alloc] init]; - [dateComps setDay:FireDateTime.GetDay()]; - [dateComps setMonth:FireDateTime.GetMonth()]; - [dateComps setYear:FireDateTime.GetYear()]; - [dateComps setHour:FireDateTime.GetHour()]; - [dateComps setMinute:FireDateTime.GetMinute()]; - [dateComps setSecond:FireDateTime.GetSecond()]; - NSDate *itemDate = [calendar dateFromComponents:dateComps]; - - UILocalNotification *localNotif = [[UILocalNotification alloc] init]; + UILocalNotification *localNotif = FIOSLocalNotificationModule::CreateLocalNotification(FireDateTime, LocalTime, ActivationEvent); if (localNotif == nil) return; - localNotif.fireDate = itemDate; - - if(LocalTime) - { - localNotif.timeZone = [NSTimeZone defaultTimeZone]; - } - else - { - localNotif.timeZone = nil; - } - - NSString* alertBody = [NSString stringWithFString:Body.ToString()]; - if(alertBody != nil) + + NSString* alertBody = [NSString stringWithFString : Body.ToString()]; + if (alertBody != nil) { localNotif.alertBody = alertBody; } @@ -108,16 +128,21 @@ void FIOSLocalNotificationService::ScheduleLocalNotificationAtTime(const FDateTi localNotif.soundName = UILocalNotificationDefaultSoundName; localNotif.applicationIconBadgeNumber = 1; - NSString* activateEventNSString = [NSString stringWithFString:ActivationEvent]; - if(activateEventNSString != nil) - { - NSDictionary* infoDict = [NSDictionary dictionaryWithObject:activateEventNSString forKey:@"ActivationEvent"]; + [[UIApplication sharedApplication] scheduleLocalNotification:localNotif]; +#endif +} - if(infoDict != nil) - { - localNotif.userInfo = infoDict; - } - } +void FIOSLocalNotificationService::ScheduleLocalNotificationBadgeAtTime(const FDateTime& FireDateTime, bool LocalTime, const FString& ActivationEvent) +{ +#if !PLATFORM_TVOS + UILocalNotification *localNotif = FIOSLocalNotificationModule::CreateLocalNotification(FireDateTime, LocalTime, ActivationEvent); + if (localNotif == nil) + return; + + // As per Apple documentation, a nil 'alertBody' results in 'no alert' + // https://developer.apple.com/reference/uikit/uilocalnotification/1616646-alertbody?language=objc + localNotif.alertBody = nil; + localNotif.applicationIconBadgeNumber = 1; [[UIApplication sharedApplication] scheduleLocalNotification:localNotif]; #endif diff --git a/Engine/Source/Runtime/IOS/IOSLocalNotification/Public/IOSLocalNotification.h b/Engine/Source/Runtime/IOS/IOSLocalNotification/Public/IOSLocalNotification.h index d2ff2f573159..d4c01f3cf667 100644 --- a/Engine/Source/Runtime/IOS/IOSLocalNotification/Public/IOSLocalNotification.h +++ b/Engine/Source/Runtime/IOS/IOSLocalNotification/Public/IOSLocalNotification.h @@ -32,6 +32,13 @@ public: * @param ActivationEvent A string that is passed in the delegate callback when the app is brought into the foreground from the user activating the notification */ virtual void ScheduleLocalNotificationAtTime(const FDateTime& FireDateTime, bool LocalTime, const FText& Title, const FText& Body, const FText& Action, const FString& ActivationEvent); + + /** Schedule a local notification badge at a specific time, inLocalTime specifies the current local time or if UTC time should be used + * @param FireDateTime The time at which to fire the local notification + * @param LocalTime If true the provided time is in the local timezone, if false it is in UTC + * @param ActivationEvent A string that is passed in the delegate callback when the app is brought into the foreground from the user activating the notification + */ + virtual void ScheduleLocalNotificationBadgeAtTime(const FDateTime& FireDateTime, bool LocalTime, const FString& ActivationEvent); /** Get the local notification that was used to launch the app * @param NotificationLaunchedApp Return true if a notification was used to launch the app diff --git a/Engine/Source/Runtime/IOS/IOSRuntimeSettings/Classes/IOSRuntimeSettings.h b/Engine/Source/Runtime/IOS/IOSRuntimeSettings/Classes/IOSRuntimeSettings.h index 9a81302f8289..72295c8f25ea 100644 --- a/Engine/Source/Runtime/IOS/IOSRuntimeSettings/Classes/IOSRuntimeSettings.h +++ b/Engine/Source/Runtime/IOS/IOSRuntimeSettings/Classes/IOSRuntimeSettings.h @@ -372,7 +372,31 @@ public: // The maximum supported Metal shader langauge version. // This defines what features may be used and OS versions supported. UPROPERTY(EditAnywhere, config, Category=Rendering, meta = (DisplayName = "Max. Metal Shader Standard To Target", ConfigRestartRequired = true)) - uint8 MaxShaderLanguageVersion; + uint8 MaxShaderLanguageVersion; + + // Whether or not the keyboard should be usable on it's own without a UITextField + UPROPERTY(GlobalConfig, EditAnywhere, Category = Input) + bool bUseIntegratedKeyboard; + + /** Sample rate to run the audio mixer with. */ + UPROPERTY(config, EditAnywhere, Category = "Audio", Meta = (DisplayName = "Audio Mixer Sample Rate")) + int32 AudioSampleRate; + + /** The amount of audio to compute each callback block. Lower values decrease latency but may increase CPU cost. */ + UPROPERTY(config, EditAnywhere, Category = "Audio", meta = (ClampMin = "512", ClampMax = "4096", DisplayName = "Callback Buffer Size")) + int32 AudioCallbackBufferFrameSize; + + /** The number of buffers to keep enqueued. More buffers increases latency, but can compensate for variable compute availability in audio callbacks on some platforms. */ + UPROPERTY(config, EditAnywhere, Category = "Audio", meta = (ClampMin = "1", UIMin = "1", DisplayName = "Number of Buffers To Enqueue")) + int32 AudioNumBuffersToEnqueue; + + /** The max number of channels (voices) to limit for this platform. The max channels used will be the minimum of this value and the global audio quality settings. A value of 0 will not apply a platform channel count max. */ + UPROPERTY(config, EditAnywhere, Category = "Audio", meta = (ClampMin = "0", UIMin = "0", DisplayName = "Max Channels")) + int32 AudioMaxChannels; + + /** The number of workers to use to compute source audio. Will only use up to the max number of sources. Will evenly divide sources to each source worker. */ + UPROPERTY(config, EditAnywhere, Category = "Audio", meta = (ClampMin = "0", UIMin = "0", DisplayName = "Number of Source Workers")) + int32 AudioNumSourceWorkers; #if WITH_EDITOR // UObject interface diff --git a/Engine/Source/Runtime/InputCore/Classes/InputCoreTypes.h b/Engine/Source/Runtime/InputCore/Classes/InputCoreTypes.h index 7e27828922ba..8733c113c03c 100644 --- a/Engine/Source/Runtime/InputCore/Classes/InputCoreTypes.h +++ b/Engine/Source/Runtime/InputCore/Classes/InputCoreTypes.h @@ -124,16 +124,16 @@ struct INPUTCORE_API FKeyDetails FKeyDetails(const FKey InKey, const TAttribute& InDisplayName, const uint8 InKeyFlags = 0, const FName InMenuCategory = NAME_None); - bool IsModifierKey() const { return bIsModifierKey != 0; } - bool IsGamepadKey() const { return bIsGamepadKey != 0; } - bool IsMouseButton() const { return bIsMouseButton != 0; } - bool IsFloatAxis() const { return AxisType == EInputAxisType::Float; } - bool IsVectorAxis() const { return AxisType == EInputAxisType::Vector; } - bool IsBindableInBlueprints() const { return bIsBindableInBlueprints != 0; } - bool ShouldUpdateAxisWithoutSamples() const { return bShouldUpdateAxisWithoutSamples != 0; } - FName GetMenuCategory() const { return MenuCategory; } + FORCEINLINE bool IsModifierKey() const { return bIsModifierKey != 0; } + FORCEINLINE bool IsGamepadKey() const { return bIsGamepadKey != 0; } + FORCEINLINE bool IsMouseButton() const { return bIsMouseButton != 0; } + FORCEINLINE bool IsFloatAxis() const { return AxisType == EInputAxisType::Float; } + FORCEINLINE bool IsVectorAxis() const { return AxisType == EInputAxisType::Vector; } + FORCEINLINE bool IsBindableInBlueprints() const { return bIsBindableInBlueprints != 0; } + FORCEINLINE bool ShouldUpdateAxisWithoutSamples() const { return bShouldUpdateAxisWithoutSamples != 0; } + FORCEINLINE FName GetMenuCategory() const { return MenuCategory; } FText GetDisplayName() const; - const FKey& GetKey() const { return Key; } + FORCEINLINE const FKey& GetKey() const { return Key; } private: diff --git a/Engine/Source/Runtime/InputDevice/Public/IInputDevice.h b/Engine/Source/Runtime/InputDevice/Public/IInputDevice.h index de90b1d87835..f87cfa970cfb 100644 --- a/Engine/Source/Runtime/InputDevice/Public/IInputDevice.h +++ b/Engine/Source/Runtime/InputDevice/Public/IInputDevice.h @@ -15,6 +15,7 @@ enum class FForceFeedbackChannelType; class IInputDevice { public: + virtual ~IInputDevice() {} /** Tick the interface (e.g. check for new controllers) */ virtual void Tick( float DeltaTime ) = 0; diff --git a/Engine/Source/Runtime/Json/Public/Serialization/JsonSerializerMacros.h b/Engine/Source/Runtime/Json/Public/Serialization/JsonSerializerMacros.h index 30f755e726a5..47364f551217 100644 --- a/Engine/Source/Runtime/Json/Public/Serialization/JsonSerializerMacros.h +++ b/Engine/Source/Runtime/Json/Public/Serialization/JsonSerializerMacros.h @@ -163,6 +163,10 @@ public: { } + virtual ~FJsonSerializerWriter() + { + } + /** Is the JSON being read from */ virtual bool IsLoading() const override { return false; } /** Is the JSON being written to */ @@ -381,6 +385,10 @@ public: { } + virtual ~FJsonSerializerReader() + { + } + /** Is the JSON being read from */ virtual bool IsLoading() const override { return true; } /** Is the JSON being written to */ diff --git a/Engine/Source/Runtime/JsonUtilities/Private/JsonObjectConverter.cpp b/Engine/Source/Runtime/JsonUtilities/Private/JsonObjectConverter.cpp index de7e1950bf58..6b4939c22115 100644 --- a/Engine/Source/Runtime/JsonUtilities/Private/JsonObjectConverter.cpp +++ b/Engine/Source/Runtime/JsonUtilities/Private/JsonObjectConverter.cpp @@ -272,13 +272,8 @@ bool FJsonObjectConverter::UStructToJsonObjectString(const UStruct* StructDefini return false; } -//template bool FJsonObjectConverter::UStructToJsonObjectString(const UStruct* StructDefinition, const void* Struct, FString& OutJsonString, int64 CheckFlags, int64 SkipFlags, int32 Indent, const CustomExportCallback* ExportCb); - -namespace -{ - -/** Convert a JSON object into a culture invariant string based on current locale */ -bool GetTextFromObject(const TSharedRef& Obj, FText& TextOut) +//static +bool FJsonObjectConverter::GetTextFromObject(const TSharedRef& Obj, FText& TextOut) { // get the prioritized culture name list FCultureRef CurrentCulture = FInternationalization::Get().GetCurrentCulture(); @@ -299,6 +294,11 @@ bool GetTextFromObject(const TSharedRef& Obj, FText& TextOut) return false; } +//template bool FJsonObjectConverter::UStructToJsonObjectString(const UStruct* StructDefinition, const void* Struct, FString& OutJsonString, int64 CheckFlags, int64 SkipFlags, int32 Indent, const CustomExportCallback* ExportCb); + +namespace +{ + /** Convert JSON to property, assuming either the property is not an array or the value is an individual array element */ bool ConvertScalarJsonValueToUProperty(TSharedPtr JsonValue, UProperty* Property, void* OutValue, int64 CheckFlags, int64 SkipFlags) { @@ -487,7 +487,7 @@ bool ConvertScalarJsonValueToUProperty(TSharedPtr JsonValue, UProper // import the subvalue as a culture invariant string FText Text; - if (!GetTextFromObject(Obj.ToSharedRef(), Text)) + if (!FJsonObjectConverter::GetTextFromObject(Obj.ToSharedRef(), Text)) { UE_LOG(LogJson, Error, TEXT("JsonValueToUProperty - Attempted to import FText from JSON object with invalid keys for property %s"), *Property->GetNameCPP()); return false; diff --git a/Engine/Source/Runtime/JsonUtilities/Public/JsonObjectConverter.h b/Engine/Source/Runtime/JsonUtilities/Public/JsonObjectConverter.h index 2b3692b827ab..d5638d7cad81 100644 --- a/Engine/Source/Runtime/JsonUtilities/Public/JsonObjectConverter.h +++ b/Engine/Source/Runtime/JsonUtilities/Public/JsonObjectConverter.h @@ -17,6 +17,9 @@ public: /** FName case insensitivity can make the casing of UPROPERTIES unpredictable. Attempt to standardize output. */ static FString StandardizeCase(const FString &StringIn); + /** Parse an FText from a json object (assumed to be of the form where keys are culture codes and values are strings) */ + static bool GetTextFromObject(const TSharedRef& Obj, FText& TextOut); + public: // UStruct -> JSON /** diff --git a/Engine/Source/Runtime/JsonUtilities/Public/JsonObjectWrapper.h b/Engine/Source/Runtime/JsonUtilities/Public/JsonObjectWrapper.h index 7749e8fd1567..5d605d7c414a 100644 --- a/Engine/Source/Runtime/JsonUtilities/Public/JsonObjectWrapper.h +++ b/Engine/Source/Runtime/JsonUtilities/Public/JsonObjectWrapper.h @@ -12,7 +12,7 @@ class FJsonObject; /** UStruct that holds a JsonObject, can be used by structs passed to JsonObjectConverter to pass through JsonObjects directly */ -USTRUCT() +USTRUCT(BlueprintType) struct JSONUTILITIES_API FJsonObjectWrapper { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/Landscape/Classes/LandscapeGizmoActor.h b/Engine/Source/Runtime/Landscape/Classes/LandscapeGizmoActor.h index 7a41b239a349..d310ff1afe4c 100644 --- a/Engine/Source/Runtime/Landscape/Classes/LandscapeGizmoActor.h +++ b/Engine/Source/Runtime/Landscape/Classes/LandscapeGizmoActor.h @@ -37,8 +37,7 @@ class ALandscapeGizmoActor : public AActor UPROPERTY(EditAnywhere, transient, Category=Gizmo) class ULandscapeInfo* TargetLandscapeInfo; -private_subobject: - DEPRECATED_FORGAME(4.6, "SpriteComponent should not be accessed directly, please use GetSpriteComponent() function instead. SpriteComponent will soon be private and your code will not compile.") +private: UPROPERTY() UBillboardComponent* SpriteComponent; #endif // WITH_EDITORONLY_DATA diff --git a/Engine/Source/Runtime/Landscape/Landscape.Build.cs b/Engine/Source/Runtime/Landscape/Landscape.Build.cs index 185cd75e30c3..588f310353b4 100644 --- a/Engine/Source/Runtime/Landscape/Landscape.Build.cs +++ b/Engine/Source/Runtime/Landscape/Landscape.Build.cs @@ -36,10 +36,9 @@ public class Landscape : ModuleRules ); SetupModulePhysXAPEXSupport(Target); - if (UEBuildConfiguration.bCompilePhysX && (UEBuildConfiguration.bBuildEditor || UEBuildConfiguration.bRuntimePhysicsCooking)) + if (UEBuildConfiguration.bCompilePhysX && UEBuildConfiguration.bBuildEditor) { - DynamicallyLoadedModuleNames.Add("PhysXFormats"); - PrivateIncludePathModuleNames.Add("PhysXFormats"); + DynamicallyLoadedModuleNames.Add("PhysXCooking"); } if (UEBuildConfiguration.bBuildDeveloperTools && Target.Type != TargetType.Server) diff --git a/Engine/Source/Runtime/Landscape/Private/LandscapeCollision.cpp b/Engine/Source/Runtime/Landscape/Private/LandscapeCollision.cpp index b9ebe94aa69b..260ea4c19aa7 100644 --- a/Engine/Source/Runtime/Landscape/Private/LandscapeCollision.cpp +++ b/Engine/Source/Runtime/Landscape/Private/LandscapeCollision.cpp @@ -43,7 +43,7 @@ #include "Engine/Engine.h" #include "Materials/MaterialInstanceConstant.h" #if WITH_EDITOR - #include "IPhysXFormat.h" + #include "IPhysXCooking.h" #endif #if ENABLE_COOK_STATS @@ -241,6 +241,8 @@ void ULandscapeHeightfieldCollisionComponent::OnCreatePhysicsState() HeightFieldShapeSync->setFlag(PxShapeFlag::eVISUALIZATION, true); HeightFieldActorSync->attachShape(*HeightFieldShapeSync); + + // attachShape holds its own ref(), so release this here. HeightFieldShapeSync->release(); if (bCreateSimpleCollision) @@ -262,6 +264,8 @@ void ULandscapeHeightfieldCollisionComponent::OnCreatePhysicsState() HeightFieldShapeSimpleSync->setFlag(PxShapeFlag::eVISUALIZATION, true); HeightFieldActorSync->attachShape(*HeightFieldShapeSimpleSync); + + // attachShape holds its own ref(), so release this here. HeightFieldShapeSimpleSync->release(); } @@ -287,6 +291,8 @@ void ULandscapeHeightfieldCollisionComponent::OnCreatePhysicsState() HeightFieldEdShapeSync->setFlag(PxShapeFlag::eSCENE_QUERY_SHAPE, true); HeightFieldActorSync->attachShape(*HeightFieldEdShapeSync); + + // attachShape holds its own ref(), so release this here. HeightFieldEdShapeSync->release(); } } @@ -310,6 +316,8 @@ void ULandscapeHeightfieldCollisionComponent::OnCreatePhysicsState() HeightFieldShapeAsync->setFlag(PxShapeFlag::eVISUALIZATION, true); HeightFieldActorAsync->attachShape(*HeightFieldShapeAsync); + + // attachShape holds its own ref(), so release this here. HeightFieldShapeAsync->release(); if (bCreateSimpleCollision) @@ -332,6 +340,8 @@ void ULandscapeHeightfieldCollisionComponent::OnCreatePhysicsState() HeightFieldShapeSimpleAsync->setFlag(PxShapeFlag::eVISUALIZATION, true); HeightFieldActorAsync->attachShape(*HeightFieldShapeSimpleAsync); + + // attachShape holds its own ref(), so release this here. HeightFieldShapeSimpleAsync->release(); } } @@ -598,7 +608,7 @@ bool ULandscapeHeightfieldCollisionComponent::CookCollisionData(const FName& For UPhysicalMaterial* DefMaterial = Proxy->DefaultPhysMaterial ? Proxy->DefaultPhysMaterial : GEngine->DefaultPhysMaterial; - // ComponentToWorld might not be initialized at this point, so use landscape transform + // GetComponentTransform() might not be initialized at this point, so use landscape transform const FVector LandscapeScale = Proxy->GetRootComponent()->RelativeScale3D; const bool bIsMirrored = (LandscapeScale.X*LandscapeScale.Y*LandscapeScale.Z) < 0.f; @@ -649,7 +659,7 @@ bool ULandscapeHeightfieldCollisionComponent::CookCollisionData(const FName& For TArray OutData; ITargetPlatformManagerModule* TPM = GetTargetPlatformManager(); - const IPhysXFormat* Cooker = TPM->FindPhysXFormat(Format); + const IPhysXCooking* Cooker = TPM->FindPhysXCooking(Format); bool Result = Cooker->CookHeightField(Format, HFSize, Samples.GetData(), Samples.GetTypeSize(), OutData); if (Result && bGenerateSimpleCollision) @@ -856,7 +866,7 @@ bool ULandscapeMeshCollisionComponent::CookCollisionData(const FName& Format, bo bool bFlipNormals = true; TArray OutData; ITargetPlatformManagerModule* TPM = GetTargetPlatformManager(); - const IPhysXFormat* Cooker = TPM->FindPhysXFormat(Format); + const IPhysXCooking* Cooker = TPM->FindPhysXCooking(Format); bool Result = Cooker->CookTriMesh(Format, EPhysXMeshCookFlags::Default, Vertices, Indices, MaterialIndices, bFlipNormals, OutData); if (Result) @@ -1291,7 +1301,7 @@ void ULandscapeHeightfieldCollisionComponent::SnapFoliageInstances(const FBox& I if (InstanceSet) { float TraceExtentSize = Bounds.SphereRadius * 2.f + 10.f; // extend a little - FVector TraceVector = GetOwner()->GetRootComponent()->ComponentToWorld.GetUnitAxis(EAxis::Z) * TraceExtentSize; + FVector TraceVector = GetOwner()->GetRootComponent()->GetComponentTransform().GetUnitAxis(EAxis::Z) * TraceExtentSize; bool bFirst = true; TArray InstancesToRemove; @@ -1317,12 +1327,11 @@ void ULandscapeHeightfieldCollisionComponent::SnapFoliageInstances(const FBox& I FVector Start = TestLocation + TraceVector; FVector End = TestLocation - TraceVector; - static FName TraceTag = FName(TEXT("FoliageSnapToLandscape")); TArray Results; UWorld* World = GetWorld(); check(World); // Editor specific landscape heightfield uses ECC_Visibility collision channel - World->LineTraceMultiByObjectType(Results, Start, End, FCollisionObjectQueryParams(ECollisionChannel::ECC_Visibility), FCollisionQueryParams(TraceTag, true)); + World->LineTraceMultiByObjectType(Results, Start, End, FCollisionObjectQueryParams(ECollisionChannel::ECC_Visibility), FCollisionQueryParams(SCENE_QUERY_STAT(FoliageSnapToLandscape), true)); bool bFoundHit = false; for (const FHitResult& Hit : Results) @@ -1376,7 +1385,7 @@ void ULandscapeHeightfieldCollisionComponent::SnapFoliageInstances(const FBox& I } // Remove any unused instances - MeshInfo.RemoveInstances(IFA, InstancesToRemove); + MeshInfo.RemoveInstances(IFA, InstancesToRemove, true); for (UHierarchicalInstancedStaticMeshComponent* FoliageComp : AffectedFoliageComponets) { @@ -1544,7 +1553,7 @@ bool ULandscapeHeightfieldCollisionComponent::DoCustomNavigableGeometryExport(FN #if WITH_PHYSX if (IsValidRef(HeightfieldRef) && HeightfieldRef->RBHeightfield) { - FTransform HFToW = ComponentToWorld; + FTransform HFToW = GetComponentTransform(); if (HeightfieldRef->RBHeightfieldSimple) { const float SimpleCollisionScale = CollisionScale * CollisionSizeQuads / SimpleCollisionSizeQuads; @@ -1566,7 +1575,7 @@ void ULandscapeHeightfieldCollisionComponent::GatherGeometrySlice(FNavigableGeom // note that this function can get called off game thread if (CachedHeightFieldSamples.IsEmpty() == false) { - FTransform HFToW = ComponentToWorld; + FTransform HFToW = GetComponentTransform(); HFToW.MultiplyScale3D(FVector(CollisionScale, CollisionScale, LANDSCAPE_ZSCALE)); GeomExport.ExportHeightFieldSlice(CachedHeightFieldSamples, HeightfieldRowsCount, HeightfieldColumnsCount, HFToW, SliceBox); @@ -1620,7 +1629,7 @@ bool ULandscapeMeshCollisionComponent::DoCustomNavigableGeometryExport(FNavigabl #if WITH_PHYSX if (IsValidRef(MeshRef) && MeshRef->RBTriangleMesh != nullptr) { - FTransform MeshToW = ComponentToWorld; + FTransform MeshToW = GetComponentTransform(); MeshToW.MultiplyScale3D(FVector(CollisionScale, CollisionScale, 1.f)); if (MeshRef->RBTriangleMesh->getTriangleMeshFlags() & PxTriangleMeshFlag::e16_BIT_INDICES) diff --git a/Engine/Source/Runtime/Landscape/Private/LandscapeDataAccess.cpp b/Engine/Source/Runtime/Landscape/Private/LandscapeDataAccess.cpp index 66932e6225f5..a100c69a8cda 100644 --- a/Engine/Source/Runtime/Landscape/Private/LandscapeDataAccess.cpp +++ b/Engine/Source/Runtime/Landscape/Private/LandscapeDataAccess.cpp @@ -142,7 +142,7 @@ LANDSCAPE_API FVector FLandscapeComponentDataInterface::GetLocalVertex(int32 Loc LANDSCAPE_API FVector FLandscapeComponentDataInterface::GetWorldVertex(int32 LocalX, int32 LocalY) const { - return Component->ComponentToWorld.TransformPosition(GetLocalVertex(LocalX, LocalY)); + return Component->GetComponentTransform().TransformPosition(GetLocalVertex(LocalX, LocalY)); } LANDSCAPE_API void FLandscapeComponentDataInterface::GetWorldTangentVectors(int32 LocalX, int32 LocalY, FVector& WorldTangentX, FVector& WorldTangentY, FVector& WorldTangentZ) const @@ -154,9 +154,9 @@ LANDSCAPE_API void FLandscapeComponentDataInterface::GetWorldTangentVectors(int3 WorldTangentX = FVector(-WorldTangentZ.Z, 0.f, WorldTangentZ.X); WorldTangentY = FVector(0.f, WorldTangentZ.Z, -WorldTangentZ.Y); - WorldTangentX = Component->ComponentToWorld.TransformVectorNoScale(WorldTangentX); - WorldTangentY = Component->ComponentToWorld.TransformVectorNoScale(WorldTangentY); - WorldTangentZ = Component->ComponentToWorld.TransformVectorNoScale(WorldTangentZ); + WorldTangentX = Component->GetComponentTransform().TransformVectorNoScale(WorldTangentX); + WorldTangentY = Component->GetComponentTransform().TransformVectorNoScale(WorldTangentY); + WorldTangentZ = Component->GetComponentTransform().TransformVectorNoScale(WorldTangentZ); } LANDSCAPE_API void FLandscapeComponentDataInterface::GetWorldPositionTangents(int32 LocalX, int32 LocalY, FVector& WorldPos, FVector& WorldTangentX, FVector& WorldTangentY, FVector& WorldTangentZ) const @@ -174,10 +174,10 @@ LANDSCAPE_API void FLandscapeComponentDataInterface::GetWorldPositionTangents(in const float ScaleFactor = (float)Component->ComponentSizeQuads / (float)(ComponentSizeVerts - 1); float XOffset, YOffset; GetXYOffset(LocalX, LocalY, XOffset, YOffset); - WorldPos = Component->ComponentToWorld.TransformPosition(FVector(LocalX * ScaleFactor + XOffset, LocalY * ScaleFactor + YOffset, LandscapeDataAccess::GetLocalHeight(Height))); - WorldTangentX = Component->ComponentToWorld.TransformVectorNoScale(WorldTangentX); - WorldTangentY = Component->ComponentToWorld.TransformVectorNoScale(WorldTangentY); - WorldTangentZ = Component->ComponentToWorld.TransformVectorNoScale(WorldTangentZ); + WorldPos = Component->GetComponentTransform().TransformPosition(FVector(LocalX * ScaleFactor + XOffset, LocalY * ScaleFactor + YOffset, LandscapeDataAccess::GetLocalHeight(Height))); + WorldTangentX = Component->GetComponentTransform().TransformVectorNoScale(WorldTangentX); + WorldTangentY = Component->GetComponentTransform().TransformVectorNoScale(WorldTangentY); + WorldTangentZ = Component->GetComponentTransform().TransformVectorNoScale(WorldTangentZ); } #endif // WITH_EDITOR diff --git a/Engine/Source/Runtime/Landscape/Private/LandscapeGrass.cpp b/Engine/Source/Runtime/Landscape/Private/LandscapeGrass.cpp index fa3cb0344cf3..d117275e4091 100644 --- a/Engine/Source/Runtime/Landscape/Private/LandscapeGrass.cpp +++ b/Engine/Source/Runtime/Landscape/Private/LandscapeGrass.cpp @@ -708,7 +708,7 @@ public: }; FLandscapeComponentGrassData::FLandscapeComponentGrassData(ULandscapeComponent* Component) - : RotationForWPO(Component->GetLandscapeMaterial()->GetMaterial()->WorldPositionOffset.IsConnected() ? Component->ComponentToWorld.GetRotation() : FQuat(0, 0, 0, 0)) + : RotationForWPO(Component->GetLandscapeMaterial()->GetMaterial()->WorldPositionOffset.IsConnected() ? Component->GetComponentTransform().GetRotation() : FQuat(0, 0, 0, 0)) { UMaterialInterface* Material = Component->GetLandscapeMaterial(); for (UMaterialInstanceConstant* MIC = Cast(Material); MIC; MIC = Cast(Material)) @@ -757,7 +757,7 @@ bool ULandscapeComponent::IsGrassMapOutdated() const return true; } - FQuat RotationForWPO = GetLandscapeMaterial()->GetMaterial()->WorldPositionOffset.IsConnected() ? ComponentToWorld.GetRotation() : FQuat(0, 0, 0, 0); + FQuat RotationForWPO = GetLandscapeMaterial()->GetMaterial()->WorldPositionOffset.IsConnected() ? GetComponentTransform().GetRotation() : FQuat(0, 0, 0, 0); if (GrassData->RotationForWPO != RotationForWPO) { return true; @@ -1304,7 +1304,7 @@ struct FGrassBuilderBase bHaveValidData = false; } const FRotator DrawRot = Landscape->GetActorRotation(); - LandscapeToWorld = Landscape->GetRootComponent()->ComponentToWorld.ToMatrixNoScale(); + LandscapeToWorld = Landscape->GetRootComponent()->GetComponentTransform().ToMatrixNoScale(); if (bHaveValidData && SqrtSubsections != 1) { @@ -1416,7 +1416,7 @@ struct FAsyncGrassBuilder : public FGrassBuilderBase , AlignToSurface(GrassVariety.AlignToSurface) , PlacementJitter(GrassVariety.PlacementJitter) , RandomStream(HierarchicalInstancedStaticMeshComponent->InstancingRandomSeed) - , XForm(LandscapeToWorld * HierarchicalInstancedStaticMeshComponent->ComponentToWorld.ToMatrixWithScale().Inverse()) + , XForm(LandscapeToWorld * HierarchicalInstancedStaticMeshComponent->GetComponentTransform().ToMatrixWithScale().Inverse()) , MeshBox(GrassVariety.GrassMesh->GetBounds().GetBox()) , DesiredInstancesPerLeaf(HierarchicalInstancedStaticMeshComponent->DesiredInstancesPerLeaf()) @@ -1985,7 +1985,7 @@ void ALandscapeProxy::UpdateGrass(const TArray& Cameras, bool bForceSyn continue; } - FBoxSphereBounds WorldBounds = Component->CalcBounds(Component->ComponentToWorld); + FBoxSphereBounds WorldBounds = Component->CalcBounds(Component->GetComponentTransform()); float MinDistanceToComp = Cameras.Num() ? MAX_flt : 0.0f; for (auto& Pos : Cameras) @@ -2053,7 +2053,7 @@ void ALandscapeProxy::UpdateGrass(const TArray& Cameras, bool bForceSyn BoxMax.Z = LocalBox.Max.Z; FBox LocalSubBox(BoxMin, BoxMax); - FBox WorldSubBox = LocalSubBox.TransformBy(Component->ComponentToWorld); + FBox WorldSubBox = LocalSubBox.TransformBy(Component->GetComponentTransform()); MinDistanceToSubComp = Cameras.Num() ? MAX_flt : 0.0f; for (auto& Pos : Cameras) @@ -2203,7 +2203,7 @@ void ALandscapeProxy::UpdateGrass(const TArray& Cameras, bool bForceSyn QUICK_SCOPE_CYCLE_COUNTER(STAT_GrassAttachComp); HierarchicalInstancedStaticMeshComponent->AttachToComponent(GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform); - FTransform DesiredTransform = GetRootComponent()->ComponentToWorld; + FTransform DesiredTransform = GetRootComponent()->GetComponentTransform(); DesiredTransform.RemoveScaling(); HierarchicalInstancedStaticMeshComponent->SetWorldTransform(DesiredTransform); diff --git a/Engine/Source/Runtime/Landscape/Private/LandscapeLight.cpp b/Engine/Source/Runtime/Landscape/Private/LandscapeLight.cpp index 765b061c360d..1afe6fd84b2a 100644 --- a/Engine/Source/Runtime/Landscape/Private/LandscapeLight.cpp +++ b/Engine/Source/Runtime/Landscape/Private/LandscapeLight.cpp @@ -143,7 +143,7 @@ FLandscapeStaticLightingMesh::FLandscapeStaticLightingMesh(ULandscapeComponent* , ExpandQuadsY(InExpandQuadsY) { const float LODScale = (float)InComponent->ComponentSizeQuads / (((InComponent->ComponentSizeQuads + 1) >> InLOD) - 1); - LocalToWorld = FTransform(FQuat::Identity, FVector::ZeroVector, FVector(LODScale, LODScale, 1)) * InComponent->ComponentToWorld; + LocalToWorld = FTransform(FQuat::Identity, FVector::ZeroVector, FVector(LODScale, LODScale, 1)) * InComponent->GetComponentTransform(); ComponentSizeQuads = ((InComponent->ComponentSizeQuads + 1) >> InLOD) - 1; NumVertices = ComponentSizeQuads + 2*InExpandQuadsX + 1; NumQuads = NumVertices - 1; @@ -632,7 +632,6 @@ void FLandscapeStaticLightingMesh::GetTriangleIndices(int32 TriangleIndex,int32& } -const static FName FLandscapeStaticLightingMesh_IntersectLightRayName(TEXT("FLandscapeStaticLightingMesh_IntersectLightRay")); FLightRayIntersection FLandscapeStaticLightingMesh::IntersectLightRay(const FVector& Start,const FVector& End,bool bFindNearestIntersection) const { @@ -640,7 +639,7 @@ FLightRayIntersection FLandscapeStaticLightingMesh::IntersectLightRay(const FVec FHitResult Result(1.0f); FHitResult NewHitInfo; - FCollisionQueryParams NewTraceParams( FLandscapeStaticLightingMesh_IntersectLightRayName, true ); + FCollisionQueryParams NewTraceParams(SCENE_QUERY_STAT(FLandscapeStaticLightingMesh_IntersectLightRay), true ); const bool bIntersects = LandscapeComponent->LineTraceComponent( Result, Start, End, NewTraceParams ); diff --git a/Engine/Source/Runtime/Landscape/Private/LandscapeRender.cpp b/Engine/Source/Runtime/Landscape/Private/LandscapeRender.cpp index 0aee54922ce9..e6493394d7c0 100644 --- a/Engine/Source/Runtime/Landscape/Private/LandscapeRender.cpp +++ b/Engine/Source/Runtime/Landscape/Private/LandscapeRender.cpp @@ -2627,82 +2627,13 @@ public: static const FName LocalVertexFactory = FName(TEXT("FLocalVertexFactory")); if (VertexFactoryType->GetFName() == LocalVertexFactory) { - // reduce the number of shaders compiled for the thumbnail materials by only compiling with shader types known to be used by the preview scene - static const TArray AllowedShaderTypes = - { - FName(TEXT("TBasePassVSFNoLightMapPolicy")), - FName(TEXT("TBasePassPSFNoLightMapPolicy")), - FName(TEXT("TBasePassVSFCachedPointIndirectLightingPolicy")), - FName(TEXT("TBasePassPSFCachedPointIndirectLightingPolicy")), - FName(TEXT("TShadowDepthVSVertexShadowDepth_OutputDepthfalse")), - FName(TEXT("TShadowDepthVSVertexShadowDepth_OutputDepthtrue")), // used by LPV - FName(TEXT("TShadowDepthPSPixelShadowDepth_NonPerspectiveCorrectfalse")), - FName(TEXT("TShadowDepthPSPixelShadowDepth_NonPerspectiveCorrecttrue")), // used by LPV - FName(TEXT("TDepthOnlyVS")), - FName(TEXT("TDepthOnlyVS")), - FName(TEXT("FDepthOnlyPS")), - }; - // shader types known *not* to be used by the preview scene - static const TArray ExcludedShaderTypes = - { - // This is not an exhaustive list - FName(TEXT("FDebugViewModeVS")), - FName(TEXT("FConvertToUniformMeshVS")), - FName(TEXT("FConvertToUniformMeshGS")), - FName(TEXT("FVelocityVS")), - FName(TEXT("FVelocityPS")), - FName(TEXT("FHitProxyVS")), - FName(TEXT("FHitProxyPS")), - FName(TEXT("TLightMapDensityVSFNoLightMapPolicy")), - FName(TEXT("TLightMapDensityPSFNoLightMapPolicy")), - FName(TEXT("TLightMapDensityVSFDummyLightMapPolicy")), - FName(TEXT("TLightMapDensityPSFDummyLightMapPolicy")), - - FName(TEXT("TBasePassPSFNoLightMapPolicySkylight")), - FName(TEXT("TBasePassPSFCachedPointIndirectLightingPolicySkylight")), - FName(TEXT("TBasePassVSFCachedVolumeIndirectLightingPolicy")), - FName(TEXT("TBasePassPSFCachedVolumeIndirectLightingPolicy")), - FName(TEXT("TBasePassPSFCachedVolumeIndirectLightingPolicySkylight")), - - FName(TEXT("TBasePassVSFNoLightMapPolicyAtmosphericFog")), - FName(TEXT("TBasePassVSFCachedPointIndirectLightingPolicyAtmosphericFog")), - FName(TEXT("TBasePassVSFSelfShadowedCachedPointIndirectLightingPolicy")), - FName(TEXT("TBasePassPSFSelfShadowedCachedPointIndirectLightingPolicy")), - FName(TEXT("TBasePassPSFSelfShadowedCachedPointIndirectLightingPolicySkylight")), - FName(TEXT("TBasePassVSFSelfShadowedCachedPointIndirectLightingPolicyAtmosphericFog")), - FName(TEXT("TBasePassVSFSelfShadowedTranslucencyPolicy")), - FName(TEXT("TBasePassPSFSelfShadowedTranslucencyPolicy")), - FName(TEXT("TBasePassPSFSelfShadowedTranslucencyPolicySkylight")), - FName(TEXT("TBasePassVSFSelfShadowedTranslucencyPolicyAtmosphericFog")), - - FName(TEXT("TShadowDepthVSVertexShadowDepth_PerspectiveCorrectfalse")), - FName(TEXT("TShadowDepthVSVertexShadowDepth_PerspectiveCorrecttrue")), - FName(TEXT("TShadowDepthVSVertexShadowDepth_OnePassPointLightfalse")), - FName(TEXT("TShadowDepthPSPixelShadowDepth_PerspectiveCorrectfalse")), - FName(TEXT("TShadowDepthPSPixelShadowDepth_PerspectiveCorrecttrue")), - FName(TEXT("TShadowDepthPSPixelShadowDepth_OnePassPointLightfalse")), - FName(TEXT("TShadowDepthPSPixelShadowDepth_OnePassPointLighttrue")), - - FName(TEXT("TShadowDepthVSForGSVertexShadowDepth_OutputDepthfalse")), - FName(TEXT("TShadowDepthVSForGSVertexShadowDepth_OutputDepthtrue")), - FName(TEXT("TShadowDepthVSForGSVertexShadowDepth_PerspectiveCorrectfalse")), - FName(TEXT("TShadowDepthVSForGSVertexShadowDepth_PerspectiveCorrecttrue")), - FName(TEXT("TShadowDepthVSForGSVertexShadowDepth_OnePassPointLightfalse")), - FName(TEXT("FOnePassPointShadowDepthGS")), - - FName(TEXT("TTranslucencyShadowDepthVS")), - FName(TEXT("TTranslucencyShadowDepthPS")), - FName(TEXT("TTranslucencyShadowDepthVS")), - FName(TEXT("TTranslucencyShadowDepthPS")), - }; - - if (Algo::Find(AllowedShaderTypes, ShaderType->GetFName())) + if (Algo::Find(GetAllowedShaderTypes(), ShaderType->GetFName())) { return FMaterialResource::ShouldCache(Platform, ShaderType, VertexFactoryType); } else { - if (Algo::Find(ExcludedShaderTypes, ShaderType->GetFName())) + if (Algo::Find(GetExcludedShaderTypes(), ShaderType->GetFName())) { UE_LOG(LogLandscape, VeryVerbose, TEXT("Excluding shader %s from landscape thumbnail material"), ShaderType->GetName()); return false; @@ -2733,6 +2664,85 @@ public: return false; } + + static const TArray& GetAllowedShaderTypes() + { + // reduce the number of shaders compiled for the thumbnail materials by only compiling with shader types known to be used by the preview scene + static const TArray AllowedShaderTypes = + { + FName(TEXT("TBasePassVSFNoLightMapPolicy")), + FName(TEXT("TBasePassPSFNoLightMapPolicy")), + FName(TEXT("TBasePassVSFCachedPointIndirectLightingPolicy")), + FName(TEXT("TBasePassPSFCachedPointIndirectLightingPolicy")), + FName(TEXT("TShadowDepthVSVertexShadowDepth_OutputDepthfalse")), + FName(TEXT("TShadowDepthVSVertexShadowDepth_OutputDepthtrue")), // used by LPV + FName(TEXT("TShadowDepthPSPixelShadowDepth_NonPerspectiveCorrectfalse")), + FName(TEXT("TShadowDepthPSPixelShadowDepth_NonPerspectiveCorrecttrue")), // used by LPV + FName(TEXT("TDepthOnlyVS")), + FName(TEXT("TDepthOnlyVS")), + FName(TEXT("FDepthOnlyPS")), + // UE-44519, masked material with landscape layers requires FHitProxy shaders. + FName(TEXT("FHitProxyVS")), + FName(TEXT("FHitProxyPS")), + }; + return AllowedShaderTypes; + } + + static const TArray& GetExcludedShaderTypes() + { + // shader types known *not* to be used by the preview scene + static const TArray ExcludedShaderTypes = + { + // This is not an exhaustive list + FName(TEXT("FDebugViewModeVS")), + FName(TEXT("FConvertToUniformMeshVS")), + FName(TEXT("FConvertToUniformMeshGS")), + FName(TEXT("FVelocityVS")), + FName(TEXT("FVelocityPS")), + FName(TEXT("TLightMapDensityVSFNoLightMapPolicy")), + FName(TEXT("TLightMapDensityPSFNoLightMapPolicy")), + FName(TEXT("TLightMapDensityVSFDummyLightMapPolicy")), + FName(TEXT("TLightMapDensityPSFDummyLightMapPolicy")), + + FName(TEXT("TBasePassPSFNoLightMapPolicySkylight")), + FName(TEXT("TBasePassPSFCachedPointIndirectLightingPolicySkylight")), + FName(TEXT("TBasePassVSFCachedVolumeIndirectLightingPolicy")), + FName(TEXT("TBasePassPSFCachedVolumeIndirectLightingPolicy")), + FName(TEXT("TBasePassPSFCachedVolumeIndirectLightingPolicySkylight")), + + FName(TEXT("TBasePassVSFNoLightMapPolicyAtmosphericFog")), + FName(TEXT("TBasePassVSFCachedPointIndirectLightingPolicyAtmosphericFog")), + FName(TEXT("TBasePassVSFSelfShadowedCachedPointIndirectLightingPolicy")), + FName(TEXT("TBasePassPSFSelfShadowedCachedPointIndirectLightingPolicy")), + FName(TEXT("TBasePassPSFSelfShadowedCachedPointIndirectLightingPolicySkylight")), + FName(TEXT("TBasePassVSFSelfShadowedCachedPointIndirectLightingPolicyAtmosphericFog")), + FName(TEXT("TBasePassVSFSelfShadowedTranslucencyPolicy")), + FName(TEXT("TBasePassPSFSelfShadowedTranslucencyPolicy")), + FName(TEXT("TBasePassPSFSelfShadowedTranslucencyPolicySkylight")), + FName(TEXT("TBasePassVSFSelfShadowedTranslucencyPolicyAtmosphericFog")), + + FName(TEXT("TShadowDepthVSVertexShadowDepth_PerspectiveCorrectfalse")), + FName(TEXT("TShadowDepthVSVertexShadowDepth_PerspectiveCorrecttrue")), + FName(TEXT("TShadowDepthVSVertexShadowDepth_OnePassPointLightfalse")), + FName(TEXT("TShadowDepthPSPixelShadowDepth_PerspectiveCorrectfalse")), + FName(TEXT("TShadowDepthPSPixelShadowDepth_PerspectiveCorrecttrue")), + FName(TEXT("TShadowDepthPSPixelShadowDepth_OnePassPointLightfalse")), + FName(TEXT("TShadowDepthPSPixelShadowDepth_OnePassPointLighttrue")), + + FName(TEXT("TShadowDepthVSForGSVertexShadowDepth_OutputDepthfalse")), + FName(TEXT("TShadowDepthVSForGSVertexShadowDepth_OutputDepthtrue")), + FName(TEXT("TShadowDepthVSForGSVertexShadowDepth_PerspectiveCorrectfalse")), + FName(TEXT("TShadowDepthVSForGSVertexShadowDepth_PerspectiveCorrecttrue")), + FName(TEXT("TShadowDepthVSForGSVertexShadowDepth_OnePassPointLightfalse")), + FName(TEXT("FOnePassPointShadowDepthGS")), + + FName(TEXT("TTranslucencyShadowDepthVS")), + FName(TEXT("TTranslucencyShadowDepthPS")), + FName(TEXT("TTranslucencyShadowDepthVS")), + FName(TEXT("TTranslucencyShadowDepthPS")), + }; + return ExcludedShaderTypes; + } }; FMaterialResource* ULandscapeMaterialInstanceConstant::AllocatePermutationResource() diff --git a/Engine/Source/Runtime/Landscape/Private/LandscapeSplineRaster.cpp b/Engine/Source/Runtime/Landscape/Private/LandscapeSplineRaster.cpp index bdabf04eee96..af1fc7ea1fda 100644 --- a/Engine/Source/Runtime/Landscape/Private/LandscapeSplineRaster.cpp +++ b/Engine/Source/Runtime/Landscape/Private/LandscapeSplineRaster.cpp @@ -440,7 +440,7 @@ bool ULandscapeInfo::ApplySplinesInternal(bool bOnlySelected, ALandscapeProxy* L FScopedTransaction Transaction(LOCTEXT("LandscapeSpline_ApplySplines", "Apply Splines to Landscape")); - const FTransform SplineToLandscape = Landscape->SplineComponent->ComponentToWorld.GetRelativeTransform(Landscape->LandscapeActorToWorld()); + const FTransform SplineToLandscape = Landscape->SplineComponent->GetComponentTransform().GetRelativeTransform(Landscape->LandscapeActorToWorld()); FLandscapeEditDataInterface LandscapeEdit(this); TSet ModifiedComponents; diff --git a/Engine/Source/Runtime/Landscape/Private/LandscapeSplines.cpp b/Engine/Source/Runtime/Landscape/Private/LandscapeSplines.cpp index b0cfcb507cfc..6cdfdded18ed 100644 --- a/Engine/Source/Runtime/Landscape/Private/LandscapeSplines.cpp +++ b/Engine/Source/Runtime/Landscape/Private/LandscapeSplines.cpp @@ -835,7 +835,7 @@ ULandscapeSplinesComponent* ULandscapeSplinesComponent::GetStreamingSplinesCompo // this is fine, we won't have any cross-level meshes in this case anyway OuterLandscape->GetLandscapeGuid().IsValid()) { - FVector LandscapeLocalLocation = ComponentToWorld.GetRelativeTransform(OuterLandscape->LandscapeActorToWorld()).TransformPosition(LocalLocation); + FVector LandscapeLocalLocation = GetComponentTransform().GetRelativeTransform(OuterLandscape->LandscapeActorToWorld()).TransformPosition(LocalLocation); const int32 ComponentIndexX = (LandscapeLocalLocation.X >= 0.0f) ? FMath::FloorToInt(LandscapeLocalLocation.X / OuterLandscape->ComponentSizeQuads) : FMath::CeilToInt(LandscapeLocalLocation.X / OuterLandscape->ComponentSizeQuads); const int32 ComponentIndexY = (LandscapeLocalLocation.Y >= 0.0f) ? FMath::FloorToInt(LandscapeLocalLocation.Y / OuterLandscape->ComponentSizeQuads) : FMath::CeilToInt(LandscapeLocalLocation.Y / OuterLandscape->ComponentSizeQuads); ULandscapeComponent* LandscapeComponent = OuterLandscape->GetLandscapeInfo()->XYtoComponentMap.FindRef(FIntPoint(ComponentIndexX, ComponentIndexY)); @@ -998,10 +998,7 @@ void ULandscapeSplinesComponent::RemoveForeignMeshComponent(ULandscapeSplineSegm verifySlow(SegmentData->MeshComponents.RemoveSingle(Component) == 1); if (SegmentData->MeshComponents.Num() == 0) { - if (SegmentData != nullptr) - { - verifySlow(ForeignWorldSplineData->ForeignSplineSegmentData.RemoveSingle(*SegmentData) == 1); - } + verifySlow(ForeignWorldSplineData->ForeignSplineSegmentData.RemoveSingle(*SegmentData) == 1); if (ForeignWorldSplineData->IsEmpty()) { @@ -1522,7 +1519,7 @@ void ULandscapeSplineControlPoint::UpdateSplinePoints(bool bUpdateCollision, boo FRotator MeshRotation = Rotation; if (MeshComponentOuterSplines != OuterSplines) { - const FTransform RelativeTransform = OuterSplines->ComponentToWorld.GetRelativeTransform(MeshComponentOuterSplines->ComponentToWorld); + const FTransform RelativeTransform = OuterSplines->GetComponentTransform().GetRelativeTransform(MeshComponentOuterSplines->GetComponentTransform()); MeshLocation = RelativeTransform.TransformPosition(MeshLocation); } @@ -2384,7 +2381,7 @@ void ULandscapeSplineSegment::UpdateSplinePoints(bool bUpdateCollision) auto* const MeshComponentOuterSplines = MeshComponent->GetAttachParent(); if (MeshComponentOuterSplines != nullptr && MeshComponentOuterSplines != OuterSplines) { - const FTransform RelativeTransform = OuterSplines->ComponentToWorld.GetRelativeTransform(MeshComponentOuterSplines->ComponentToWorld); + const FTransform RelativeTransform = OuterSplines->GetComponentTransform().GetRelativeTransform(MeshComponentOuterSplines->GetComponentTransform()); MeshComponent->SplineParams.StartPos = RelativeTransform.TransformPosition(MeshComponent->SplineParams.StartPos); MeshComponent->SplineParams.EndPos = RelativeTransform.TransformPosition(MeshComponent->SplineParams.EndPos); } diff --git a/Engine/Source/Runtime/Launch/Launch.Build.cs b/Engine/Source/Runtime/Launch/Launch.Build.cs index 63801bf78541..64a37d5a57eb 100644 --- a/Engine/Source/Runtime/Launch/Launch.Build.cs +++ b/Engine/Source/Runtime/Launch/Launch.Build.cs @@ -48,12 +48,17 @@ public class Launch : ModuleRules PrivateDependencyModuleNames.Add("LauncherCheck"); Definitions.Add("WITH_LAUNCHERCHECK=1"); } + else + { + Definitions.Add("WITH_LAUNCHERCHECK=0"); + } if (Target.Type != TargetType.Server) { PrivateDependencyModuleNames.AddRange( new string[] { "HeadMountedDisplay", + "MRMesh", } ); @@ -98,6 +103,7 @@ public class Launch : ModuleRules new string[] { "NetworkFile", "StreamingFile", + "CookedIterativeFile", "AutomationWorker", } ); @@ -181,6 +187,7 @@ public class Launch : ModuleRules { PrivateDependencyModuleNames.Add("OpenGLDrv"); PrivateDependencyModuleNames.Add("IOSAudio"); + PrivateDependencyModuleNames.Add("AudioMixerAudioUnit"); DynamicallyLoadedModuleNames.Add("IOSRuntimeSettings"); DynamicallyLoadedModuleNames.Add("IOSLocalNotification"); PublicFrameworks.Add("OpenGLES"); @@ -194,6 +201,7 @@ public class Launch : ModuleRules { PrivateDependencyModuleNames.Add("OpenGLDrv"); PrivateDependencyModuleNames.Add("AndroidAudio"); + PrivateDependencyModuleNames.Add("AudioMixerAndroid"); DynamicallyLoadedModuleNames.Add("AndroidRuntimeSettings"); DynamicallyLoadedModuleNames.Add("AndroidLocalNotification"); } diff --git a/Engine/Source/Runtime/Launch/Private/Android/AndroidJNI.cpp b/Engine/Source/Runtime/Launch/Private/Android/AndroidJNI.cpp index 257d09cecd50..41dc543172fd 100644 --- a/Engine/Source/Runtime/Launch/Private/Android/AndroidJNI.cpp +++ b/Engine/Source/Runtime/Launch/Private/Android/AndroidJNI.cpp @@ -82,10 +82,15 @@ void FJavaWrapper::FindClassesAndMethods(JNIEnv* Env) AndroidThunkJava_LocalNotificationGetLaunchNotification = FindMethod(Env, GameActivityClassID, "AndroidThunkJava_LocalNotificationGetLaunchNotification", "()Lcom/epicgames/ue4/GameActivity$LaunchNotification;", bIsOptional); //AndroidThunkJava_LocalNotificationDestroyIfExists = FindMethod(Env, GameActivityClassID, "AndroidThunkJava_LocalNotificationDestroyIfExists", "(I)Z", bIsOptional); AndroidThunkJava_HasActiveWiFiConnection = FindMethod(Env, GameActivityClassID, "AndroidThunkJava_HasActiveWiFiConnection", "()Z", bIsOptional); + AndroidThunkJava_GetAndroidId = FindMethod(Env, GameActivityClassID, "AndroidThunkJava_GetAndroidId", "()Ljava/lang/String;", bIsOptional); // this is optional - only inserted if GearVR plugin enabled AndroidThunkJava_IsGearVRApplication = FindMethod(Env, GameActivityClassID, "AndroidThunkJava_IsGearVRApplication", "()Z", true); + // this is optional - only inserted if GCM plugin enabled + AndroidThunkJava_RegisterForRemoteNotifications = FindMethod(Env, GameActivityClassID, "AndroidThunkJava_RegisterForRemoteNotifications", "()V", true); + AndroidThunkJava_UnregisterForRemoteNotifications = FindMethod(Env, GameActivityClassID, "AndroidThunkJava_UnregisterForRemoteNotifications", "()V", true); + // get field IDs for InputDeviceInfo class members jclass localInputDeviceInfoClass = FindClass(Env, "com/epicgames/ue4/GameActivity$InputDeviceInfo", bIsOptional); InputDeviceInfoClass = (jclass)Env->NewGlobalRef(localInputDeviceInfoClass); @@ -132,6 +137,7 @@ void FJavaWrapper::FindGooglePlayMethods(JNIEnv* Env) AndroidThunkJava_IsInterstitialAdAvailable = FindMethod(Env, GoogleServicesClassID, "AndroidThunkJava_IsInterstitialAdAvailable", "()Z", bIsOptional); AndroidThunkJava_IsInterstitialAdRequested = FindMethod(Env, GoogleServicesClassID, "AndroidThunkJava_IsInterstitialAdRequested", "()Z", bIsOptional); AndroidThunkJava_ShowInterstitialAd = FindMethod(Env, GoogleServicesClassID, "AndroidThunkJava_ShowInterstitialAd", "()V", bIsOptional); + AndroidThunkJava_GetAdvertisingId = FindMethod(Env, GoogleServicesClassID, "AndroidThunkJava_GetAdvertisingId", "()Ljava/lang/String;", bIsOptional); AndroidThunkJava_GoogleClientConnect = FindMethod(Env, GoogleServicesClassID, "AndroidThunkJava_GoogleClientConnect", "()V", bIsOptional); AndroidThunkJava_GoogleClientDisconnect = FindMethod(Env, GoogleServicesClassID, "AndroidThunkJava_GoogleClientDisconnect", "()V", bIsOptional); } @@ -269,12 +275,15 @@ jmethodID FJavaWrapper::AndroidThunkJava_GetMetaDataBoolean; jmethodID FJavaWrapper::AndroidThunkJava_GetMetaDataInt; jmethodID FJavaWrapper::AndroidThunkJava_GetMetaDataString; jmethodID FJavaWrapper::AndroidThunkJava_IsGearVRApplication; +jmethodID FJavaWrapper::AndroidThunkJava_RegisterForRemoteNotifications; +jmethodID FJavaWrapper::AndroidThunkJava_UnregisterForRemoteNotifications; jmethodID FJavaWrapper::AndroidThunkJava_ShowHiddenAlertDialog; jmethodID FJavaWrapper::AndroidThunkJava_LocalNotificationScheduleAtTime; jmethodID FJavaWrapper::AndroidThunkJava_LocalNotificationClearAll; jmethodID FJavaWrapper::AndroidThunkJava_LocalNotificationGetLaunchNotification; //jmethodID FJavaWrapper::AndroidThunkJava_LocalNotificationDestroyIfExists; jmethodID FJavaWrapper::AndroidThunkJava_HasActiveWiFiConnection; +jmethodID FJavaWrapper::AndroidThunkJava_GetAndroidId; jclass FJavaWrapper::InputDeviceInfoClass; jfieldID FJavaWrapper::InputDeviceInfo_VendorId; @@ -293,6 +302,7 @@ jmethodID FJavaWrapper::AndroidThunkJava_LoadInterstitialAd; jmethodID FJavaWrapper::AndroidThunkJava_IsInterstitialAdAvailable; jmethodID FJavaWrapper::AndroidThunkJava_IsInterstitialAdRequested; jmethodID FJavaWrapper::AndroidThunkJava_ShowInterstitialAd; +jmethodID FJavaWrapper::AndroidThunkJava_GetAdvertisingId; jmethodID FJavaWrapper::AndroidThunkJava_GoogleClientConnect; jmethodID FJavaWrapper::AndroidThunkJava_GoogleClientDisconnect; @@ -511,6 +521,30 @@ bool AndroidThunkCpp_IsGearVRApplication() return IsGearVRApplication == 1; } +// call optional remote notification registration +void AndroidThunkCpp_RegisterForRemoteNotifications() +{ + if (FJavaWrapper::AndroidThunkJava_RegisterForRemoteNotifications) + { + if (JNIEnv* Env = FAndroidApplication::GetJavaEnv()) + { + FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, FJavaWrapper::AndroidThunkJava_RegisterForRemoteNotifications); + } + } +} + +// call optional remote notification unregistration +void AndroidThunkCpp_UnregisterForRemoteNotifications() +{ + if (FJavaWrapper::AndroidThunkJava_UnregisterForRemoteNotifications) + { + if (JNIEnv* Env = FAndroidApplication::GetJavaEnv()) + { + FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, FJavaWrapper::AndroidThunkJava_UnregisterForRemoteNotifications); + } + } +} + void AndroidThunkCpp_ShowConsoleWindow() { if (JNIEnv* Env = FAndroidApplication::GetJavaEnv()) @@ -574,7 +608,29 @@ void AndroidThunkCpp_HideVirtualKeyboardInputDialog() // call the java side FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, FJavaWrapper::AndroidThunkJava_HideVirtualKeyboardInputDialog); - } + + if (FTaskGraphInterface::IsRunning()) + { + FGraphEventRef VirtualKeyboardShown = FFunctionGraphTask::CreateAndDispatchWhenReady([&]() + { + FAndroidApplication::Get()->OnVirtualKeyboardHidden().Broadcast(); + }, TStatId(), NULL, ENamedThreads::GameThread); + } + } +} + +// This is called from the ViewTreeObserver.OnGlobalLayoutListener in GameActivity +JNI_METHOD void Java_com_epicgames_ue4_GameActivity_nativeVirtualKeyboardShown(JNIEnv* jenv, jobject thiz, jint left, jint top, jint right, jint bottom) +{ + FPlatformRect ScreenRect(left, top, right, bottom); + + if (FTaskGraphInterface::IsRunning()) + { + FGraphEventRef VirtualKeyboardShown = FFunctionGraphTask::CreateAndDispatchWhenReady([ScreenRect]() + { + FAndroidApplication::Get()->OnVirtualKeyboardShown().Broadcast(ScreenRect); + }, TStatId(), NULL, ENamedThreads::GameThread); + } } void AndroidThunkCpp_ShowVirtualKeyboardInput(TSharedPtr TextWidget, int32 InputType, const FString& Label, const FString& Contents) @@ -619,20 +675,6 @@ void AndroidThunkCpp_HideVirtualKeyboardInput() } } -// This is called from the ViewTreeObserver.OnGlobalLayoutListener in GameActivity -JNI_METHOD void Java_com_epicgames_ue4_GameActivity_nativeVirtualKeyboardShown(JNIEnv* jenv, jobject thiz, jint left, jint top, jint right, jint bottom) -{ - FPlatformRect ScreenRect( left, top, right, bottom ); - - if( FTaskGraphInterface::IsRunning() ) - { - FGraphEventRef VirtualKeyboardShown = FFunctionGraphTask::CreateAndDispatchWhenReady( [ScreenRect]() - { - FAndroidApplication::Get()->OnVirtualKeyboardShown().Broadcast( ScreenRect ); - }, TStatId(), NULL, ENamedThreads::GameThread ); - } -} - //This function is declared in the Java-defined class, GameActivity.java: "public native void nativeVirtualKeyboardResult(bool update, String contents);" JNI_METHOD void Java_com_epicgames_ue4_GameActivity_nativeVirtualKeyboardResult(JNIEnv* jenv, jobject thiz, jboolean update, jstring contents) { @@ -766,6 +808,42 @@ void AndroidThunkCpp_ShowInterstitialAd() } } +FString AndroidThunkCpp_GetAdvertisingId() +{ + FString adIdResult = FString(""); + + if (JNIEnv* Env = FAndroidApplication::GetJavaEnv()) + { + jstring adId =(jstring)FJavaWrapper::CallObjectMethod(Env, FJavaWrapper::GoogleServicesThis, FJavaWrapper::AndroidThunkJava_GetAdvertisingId); + if (!Env->IsSameObject(adId, NULL)) + { + const char *nativeAdIdString = Env->GetStringUTFChars(adId, 0); + adIdResult = FString(nativeAdIdString); + Env->ReleaseStringUTFChars(adId, nativeAdIdString); + Env->DeleteLocalRef(adId); + } + } + return adIdResult; +} + +FString AndroidThunkCpp_GetAndroidId() +{ + FString androidIdResult = FString(""); + + if (JNIEnv* Env = FAndroidApplication::GetJavaEnv()) + { + jstring androidId = (jstring)FJavaWrapper::CallObjectMethod(Env, FJavaWrapper::GameActivityThis, FJavaWrapper::AndroidThunkJava_GetAndroidId); + if (!Env->IsSameObject(androidId, NULL)) + { + const char *nativeandroidIdString = Env->GetStringUTFChars(androidId, 0); + androidIdResult = FString(nativeandroidIdString); + Env->ReleaseStringUTFChars(androidId, nativeandroidIdString); + Env->DeleteLocalRef(androidId); + } + } + return androidIdResult; +} + void AndroidThunkCpp_GoogleClientConnect() { if (JNIEnv* Env = FAndroidApplication::GetJavaEnv()) diff --git a/Engine/Source/Runtime/Launch/Private/IOS/IOSAppDelegateConsoleHandling.cpp b/Engine/Source/Runtime/Launch/Private/IOS/IOSAppDelegateConsoleHandling.cpp index ba55c95808df..5a7ca149836c 100644 --- a/Engine/Source/Runtime/Launch/Private/IOS/IOSAppDelegateConsoleHandling.cpp +++ b/Engine/Source/Runtime/Launch/Private/IOS/IOSAppDelegateConsoleHandling.cpp @@ -78,6 +78,7 @@ extern bool GShowSplashScreen; else #endif { +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0 self.ConsoleAlert = [[UIAlertView alloc] initWithTitle:@"Type a console command" message:@"" delegate:self @@ -107,6 +108,7 @@ extern bool GShowSplashScreen; [TextField addGestureRecognizer : SwipeRightGesture]; [self.ConsoleAlert show]; +#endif } } @@ -188,6 +190,7 @@ extern bool GShowSplashScreen; else #endif { +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0 // set up the alert message and buttons UIAlertView* Alert = [[[UIAlertView alloc] initWithTitle:[StringArray objectAtIndex : 0] message : [StringArray objectAtIndex : 1] @@ -205,13 +208,16 @@ extern bool GShowSplashScreen; // show it! [Alert show]; +#endif } } - (BOOL)textFieldShouldReturn:(UITextField *)alertTextField { [alertTextField resignFirstResponder];// to dismiss the keyboard. +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0 [self.ConsoleAlert dismissWithClickedButtonIndex:1 animated:YES];//this is called on alertview to dismiss it. +#endif return YES; } @@ -220,6 +226,7 @@ extern bool GShowSplashScreen; /** * An alert button was pressed */ +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0 - (void)alertView:(UIAlertView*)AlertView didDismissWithButtonIndex:(NSInteger)ButtonIndex { // just set our AlertResponse property, all we need to do @@ -235,6 +242,7 @@ extern bool GShowSplashScreen; } } } +#endif - (void)SwipeLeftAction:(id)Ignored { @@ -248,13 +256,16 @@ extern bool GShowSplashScreen; if ([UIAlertController class]) { TextField = self.ConsoleAlertController.textFields.firstObject; - } + TextField.text = [self.ConsoleHistoryValues objectAtIndex : self.ConsoleHistoryValuesIndex]; + } else #endif { - TextField = [self.ConsoleAlert textFieldAtIndex:0]; +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0 + TextField = [self.ConsoleAlert textFieldAtIndex : 0]; + TextField.text = [self.ConsoleHistoryValues objectAtIndex : self.ConsoleHistoryValuesIndex]; +#endif } - TextField.text = [self.ConsoleHistoryValues objectAtIndex:self.ConsoleHistoryValuesIndex]; } } @@ -270,13 +281,16 @@ extern bool GShowSplashScreen; if ([UIAlertController class]) { TextField = self.ConsoleAlertController.textFields.firstObject; - } + TextField.text = [self.ConsoleHistoryValues objectAtIndex : self.ConsoleHistoryValuesIndex]; + } else #endif { - TextField = [self.ConsoleAlert textFieldAtIndex:0]; +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0 + TextField = [self.ConsoleAlert textFieldAtIndex : 0]; + TextField.text = [self.ConsoleHistoryValues objectAtIndex : self.ConsoleHistoryValuesIndex]; +#endif } - TextField.text = [self.ConsoleHistoryValues objectAtIndex:self.ConsoleHistoryValuesIndex]; } } diff --git a/Engine/Source/Runtime/Launch/Private/LaunchEngineLoop.cpp b/Engine/Source/Runtime/Launch/Private/LaunchEngineLoop.cpp index b275faecb2a6..aabb43c5ec11 100644 --- a/Engine/Source/Runtime/Launch/Private/LaunchEngineLoop.cpp +++ b/Engine/Source/Runtime/Launch/Private/LaunchEngineLoop.cpp @@ -126,6 +126,7 @@ #if !UE_SERVER #include "IHeadMountedDisplayModule.h" #include "HeadMountedDisplay.h" + #include "MRMeshModule.h" #include "Interfaces/ISlateRHIRendererModule.h" #include "Interfaces/ISlateNullRendererModule.h" #include "EngineFontServices.h" @@ -176,6 +177,7 @@ class FFeedbackContext; #if ENABLE_VISUAL_LOG #include "VisualLogger/VisualLogger.h" #endif + #include "CsvProfiler.h" #endif #if defined(WITH_LAUNCHERCHECK) && WITH_LAUNCHERCHECK @@ -329,7 +331,7 @@ static void RHIExitAndStopRHIThread() RHIExit(); // Stop the RHI Thread - if (GUseRHIThread) + if (GRHIThread_InternalUseOnly) { DECLARE_CYCLE_STAT(TEXT("Wait For RHIThread Finish"), STAT_WaitForRHIThreadFinish, STATGROUP_TaskGraphTasks); FGraphEventRef QuitTask = TGraphTask::CreateTask(nullptr, ENamedThreads::GameThread).ConstructAndDispatchWhenReady(ENamedThreads::RHIThread); @@ -338,6 +340,8 @@ static void RHIExitAndStopRHIThread() } #endif +extern void DeferredPhysResourceCleanup(); + /** * Initializes std out device and adds it to GLog @@ -619,9 +623,20 @@ bool LaunchCheckForFileOverride(const TCHAR* CmdLine, bool& OutFileOverrideFound FPlatformFileManager::Get().SetPlatformFile(*CurrentPlatformFile); } + bool bShouldUseCookedIterativeFile = false; + if ( !bShouldUseStreamingFile && !NetworkPlatformFile ) + { + NetworkPlatformFile = ConditionallyCreateFileWrapper(TEXT("CookedIterativeFile"), CurrentPlatformFile, CmdLine, &bNetworkFailedToInitialize, &bShouldUseCookedIterativeFile); + if (NetworkPlatformFile) + { + CurrentPlatformFile = NetworkPlatformFile; + FPlatformFileManager::Get().SetPlatformFile(*CurrentPlatformFile); + } + } + // if streaming network platform file was tried this loop don't try this one // Network file wrapper (only create if the streaming wrapper hasn't been created) - if ( !bShouldUseStreamingFile && !NetworkPlatformFile) + if ( !bShouldUseStreamingFile && !bShouldUseCookedIterativeFile && !NetworkPlatformFile) { NetworkPlatformFile = ConditionallyCreateFileWrapper(TEXT("NetworkFile"), CurrentPlatformFile, CmdLine, &bNetworkFailedToInitialize); if (NetworkPlatformFile) @@ -885,6 +900,10 @@ int32 FEngineLoop::PreInit( const TCHAR* CmdLine ) return -1; } +#if WITH_ENGINE + FCoreUObjectDelegates::PostGarbageCollectConditionalBeginDestroy.AddStatic(DeferredPhysResourceCleanup); +#endif + #if defined(WITH_LAUNCHERCHECK) && WITH_LAUNCHERCHECK if (ILauncherCheckModule::Get().WasRanFromLauncher() == false) { @@ -1023,6 +1042,9 @@ int32 FEngineLoop::PreInit( const TCHAR* CmdLine ) FCString::Strcpy( CommandLineCopy, CommandLineSize, CmdLine ); const TCHAR* ParsedCmdLine = CommandLineCopy; + // Add the default engine shader dir + FGenericPlatformProcess::AddShaderDir(FGenericPlatformProcess::ShaderDir()); + FString Token = FParse::Token( ParsedCmdLine, 0); #if WITH_ENGINE @@ -1296,6 +1318,12 @@ int32 FEngineLoop::PreInit( const TCHAR* CmdLine ) UE_LOG(LogInit, Warning, TEXT("Could not find a valid project file, the engine will exit now.")); return 1; } + + if (IProjectManager::Get().GetCurrentProject() && IProjectManager::Get().GetCurrentProject()->bIsEnterpriseProject && FPaths::DirectoryExists(FPaths::EnterpriseDir())) + { + // Add the enterprise binaries directory if we're an enterprise project + FModuleManager::Get().AddBinariesDirectory( *FPaths::Combine( FPaths::EnterpriseDir(), TEXT("Binaries"), FPlatformProcess::GetBinariesSubdirectory() ), false ); + } } #if !IS_PROGRAM @@ -1303,6 +1331,7 @@ int32 FEngineLoop::PreInit( const TCHAR* CmdLine ) { // Tell the module manager what the game binaries folder is const FString GameBinariesDirectory = FPaths::Combine( FPlatformMisc::GameDir(), TEXT( "Binaries" ), FPlatformProcess::GetBinariesSubdirectory() ); + FPlatformProcess::AddDllDirectory(*GameBinariesDirectory); FModuleManager::Get().SetGameBinariesDirectory(*GameBinariesDirectory); LaunchFixGameNameCase(); @@ -1381,6 +1410,10 @@ int32 FEngineLoop::PreInit( const TCHAR* CmdLine ) LoadPreInitModules(); +#if WITH_ENGINE && CSV_PROFILER + FCsvProfiler::Get()->Init(); +#endif + // Start the application if(!AppInit()) { @@ -1712,14 +1745,14 @@ int32 FEngineLoop::PreInit( const TCHAR* CmdLine ) if(GRHISupportsRHIThread) { const bool DefaultUseRHIThread = true; - GUseRHIThread = DefaultUseRHIThread; + GUseRHIThread_InternalUseOnly = DefaultUseRHIThread; if(FParse::Param(FCommandLine::Get(), TEXT("rhithread"))) { - GUseRHIThread = true; + GUseRHIThread_InternalUseOnly = true; } else if(FParse::Param(FCommandLine::Get(), TEXT("norhithread"))) { - GUseRHIThread = false; + GUseRHIThread_InternalUseOnly = false; } } @@ -1750,7 +1783,7 @@ int32 FEngineLoop::PreInit( const TCHAR* CmdLine ) GetMoviePlayer()->Initialize(SlateRenderer); // hide splash screen now - FPlatformMisc::PlatformPostInit(false); + FPlatformMisc::PlatformHandleSplashScreen(false); // only allowed to play any movies marked as early startup. These movies or widgets can have no interaction whatsoever with uobjects or engine features GetMoviePlayer()->PlayEarlyStartupMovies(); @@ -1834,18 +1867,8 @@ int32 FEngineLoop::PreInit( const TCHAR* CmdLine ) } #endif -#if !UE_SERVER - if ( !IsRunningDedicatedServer() ) - { - // do any post appInit processing, before the render thread is started. - FPlatformMisc::PlatformPostInit(!GetMoviePlayer()->IsMovieCurrentlyPlaying()); - } - else -#endif - { - // do any post appInit processing, before the render thread is started. - FPlatformMisc::PlatformPostInit(true); - } + // do any post appInit processing, before the render thread is started. + FPlatformMisc::PlatformPostInit(); SlowTask.EnterProgressFrame(5); #if !PLATFORM_SUPPORTS_EARLY_MOVIE_PLAYBACK @@ -1856,14 +1879,14 @@ int32 FEngineLoop::PreInit( const TCHAR* CmdLine ) if (GRHISupportsRHIThread) { const bool DefaultUseRHIThread = true; - GUseRHIThread = DefaultUseRHIThread; + GUseRHIThread_InternalUseOnly = DefaultUseRHIThread; if (FParse::Param(FCommandLine::Get(),TEXT("rhithread"))) { - GUseRHIThread = true; + GUseRHIThread_InternalUseOnly = true; } else if (FParse::Param(FCommandLine::Get(),TEXT("norhithread"))) { - GUseRHIThread = false; + GUseRHIThread_InternalUseOnly = false; } } StartRenderingThread(); @@ -1877,10 +1900,22 @@ int32 FEngineLoop::PreInit( const TCHAR* CmdLine ) { // Play any non-early startup loading movies. GetMoviePlayer()->PlayMovie(); - } #endif +#if !UE_SERVER + if (!IsRunningDedicatedServer()) + { + // show or hide splash screen based on movie + FPlatformMisc::PlatformHandleSplashScreen(!GetMoviePlayer()->IsMovieCurrentlyPlaying()); + } + else +#endif + { + // show splash screen + FPlatformMisc::PlatformHandleSplashScreen(true); + } + { FCoreUObjectDelegates::PreGarbageCollectConditionalBeginDestroy.AddStatic(StartRenderCommandFenceBundler); FCoreUObjectDelegates::PostGarbageCollectConditionalBeginDestroy.AddStatic(StopRenderCommandFenceBundler); @@ -2041,6 +2076,9 @@ int32 FEngineLoop::PreInit( const TCHAR* CmdLine ) } } + // Call init callbacks + FCoreDelegates::OnPostEngineInit.Broadcast(); + // Load all the post-engine init modules ensure(IProjectManager::Get().LoadModulesForProject(ELoadingPhase::PostEngineInit)); ensure(IPluginManager::Get().LoadModulesForEnabledPlugins(ELoadingPhase::PostEngineInit)); @@ -2086,7 +2124,7 @@ int32 FEngineLoop::PreInit( const TCHAR* CmdLine ) UE_LOG(LogInit, Display, TEXT("-----------------------------------")); const int32 MaxMessagesToShow = (GIsBuildMachine || FParse::Param(FCommandLine::Get(), TEXT("DUMPALLWARNINGS"))) ? - FMath::Max(AllErrors.Num(), AllWarnings.Num()) : 50; + (AllErrors.Num() + AllWarnings.Num()) : 50; TSet ShownMessages; ShownMessages.Empty(MaxMessagesToShow); @@ -2306,6 +2344,7 @@ void FEngineLoop::LoadPreInitModules() // compress asynchronously and that can lead to a race condition. FModuleManager::Get().LoadModule(TEXT("TextureCompressor")); #endif + #endif // WITH_ENGINE #if (WITH_EDITOR && !(UE_BUILD_SHIPPING || UE_BUILD_TEST)) @@ -2344,6 +2383,14 @@ bool FEngineLoop::LoadStartupCoreModules() FModuleManager::LoadModuleChecked("Messaging"); } + // Init Scene Reconstruction support +#if !UE_SERVER + if (!IsRunningDedicatedServer()) + { + FModuleManager::LoadModuleChecked("MRMesh"); + } +#endif + SlowTask.EnterProgressFrame(10); #if WITH_EDITOR FModuleManager::LoadModuleChecked("EditorStyle"); @@ -2437,7 +2484,6 @@ bool FEngineLoop::LoadStartupCoreModules() // Load runtime client modules (which are also needed at cook-time) if( !IsRunningDedicatedServer() ) { - FModuleManager::Get().LoadModule(TEXT("GameLiveStreaming")); FModuleManager::Get().LoadModule(TEXT("MediaAssets")); } #endif @@ -2583,7 +2629,11 @@ int32 FEngineLoop::Init() GEngine->Init(this); + // Call init callbacks + PRAGMA_DISABLE_DEPRECATION_WARNINGS UEngine::OnPostEngineInit.Broadcast(); + PRAGMA_ENABLE_DEPRECATION_WARNINGS + FCoreDelegates::OnPostEngineInit.Broadcast(); SlowTask.EnterProgressFrame(30); @@ -2713,6 +2763,13 @@ void FEngineLoop::Exit() } #endif +#if WITH_EDITOR + // This module must be shut down first because other modules may try to access it during shutdown. + // Accessing this module at shutdown causes instability since the object system will have been shut down and this module uses uobjects internally. + FModuleManager::Get().UnloadModule("AssetTools", true); +#endif // WITH_EDITOR + + #if !PLATFORM_ANDROID // AppPreExit doesn't work on Android AppPreExit(); @@ -2834,7 +2891,7 @@ bool FEngineLoop::ShouldUseIdleMode() const return bIdleMode; } -#if !UE_BUILD_SHIPPING && !UE_BUILD_TEST +#if !UE_BUILD_SHIPPING && !UE_BUILD_TEST && MALLOC_GT_HOOKS #include "Containers/StackTracker.h" static TAutoConsoleVariable CVarLogGameThreadMallocChurn( @@ -2958,7 +3015,7 @@ uint64 FScopedSampleMallocChurn::DumpFrame = 0; void FEngineLoop::Tick() { -#if !UE_BUILD_SHIPPING && !UE_BUILD_TEST +#if !UE_BUILD_SHIPPING && !UE_BUILD_TEST && MALLOC_GT_HOOKS FScopedSampleMallocChurn ChurnTracker; #endif @@ -3001,6 +3058,8 @@ void FEngineLoop::Tick() RHICmdList.BeginFrame(); }); + FCoreDelegates::OnBeginFrame.Broadcast(); + { QUICK_SCOPE_CYCLE_COUNTER(STAT_FEngineLoop_FlushThreadedLogs); // Flush debug output which has been buffered by other threads. @@ -3097,6 +3156,9 @@ void FEngineLoop::Tick() } #endif // WITH_ENGINE + // tick the currently active platform files + FPlatformFileManager::Get().TickActivePlatformFile(); + if (FSlateApplication::IsInitialized() && !bIdleMode) { SCOPE_TIME_GUARD(TEXT("SlateInput")); @@ -3262,6 +3324,8 @@ void FEngineLoop::Tick() GEngine->TickDeferredCommands(); } + FCoreDelegates::OnEndFrame.Broadcast(); + ENQUEUE_UNIQUE_RENDER_COMMAND( EndFrame, { @@ -3580,11 +3644,13 @@ bool FEngineLoop::AppInit( ) } #endif + // Put the command line and config info into the suppression system (before plugins start loading) + FLogSuppressionInterface::Get().ProcessConfigAndCommandLine(); + // NOTE: This is the earliest place to init the online subsystems (via plugins) // Code needs GConfigFile to be valid // Must be after FThreadStats::StartThread(); - // Must be before Render/RHI subsystem D3DCreate() - // For platform services that need D3D hooks like Steam + // Must be before Render/RHI subsystem D3DCreate() for platform services that need D3D hooks like Steam // Load "pre-init" plugin modules if (!IProjectManager::Get().LoadModulesForProject(ELoadingPhase::PostConfigInit) || !IPluginManager::Get().LoadModulesForEnabledPlugins(ELoadingPhase::PostConfigInit)) @@ -3600,9 +3666,6 @@ bool FEngineLoop::AppInit( ) PreInitHMDDevice(); - // Put the command line and config info into the suppression system - FLogSuppressionInterface::Get().ProcessConfigAndCommandLine(); - // after the above has run we now have the REQUIRED set of engine .INIs (all of the other .INIs) // that are gotten from .h files' config() are not requires and are dynamically loaded when the .u files are loaded @@ -3787,6 +3850,11 @@ void FEngineLoop::AppPreExit( ) void FEngineLoop::AppExit( ) { +#if !WITH_ENGINE + // when compiled WITH_ENGINE, this will happen in FEngineLoop::Exit() + FTaskGraphInterface::Shutdown(); +#endif // WITH_ENGINE + UE_LOG(LogExit, Log, TEXT("Exiting.")); FPlatformMisc::PlatformTearDown(); diff --git a/Engine/Source/Runtime/Launch/Private/Mac/LaunchMac.cpp b/Engine/Source/Runtime/Launch/Private/Mac/LaunchMac.cpp index d06c77784ead..a36777e13ea2 100644 --- a/Engine/Source/Runtime/Launch/Private/Mac/LaunchMac.cpp +++ b/Engine/Source/Runtime/Launch/Private/Mac/LaunchMac.cpp @@ -25,6 +25,7 @@ static FString GSavedCommandLine; extern int32 GuardedMain( const TCHAR* CmdLine ); extern void LaunchStaticShutdownAfterError(); +static int32 GGuardedMainErrorLevel = 0; /** * Game-specific crash reporter @@ -198,7 +199,7 @@ void EngineCrashHandler(const FGenericCrashContext& GenericContext) { // Don't use exception handling when a debugger is attached to exactly trap the crash. This does NOT check // whether we are the first instance or not! - GuardedMain( *GSavedCommandLine ); + GGuardedMainErrorLevel = GuardedMain( *GSavedCommandLine ); } else { @@ -208,7 +209,7 @@ void EngineCrashHandler(const FGenericCrashContext& GenericContext) } GIsGuarded = 1; // Run the guarded code. - GuardedMain( *GSavedCommandLine ); + GGuardedMainErrorLevel = GuardedMain( *GSavedCommandLine ); GIsGuarded = 0; } @@ -293,5 +294,5 @@ INT32_MAIN_INT32_ARGC_TCHAR_ARGV() [NSApplication sharedApplication]; [NSApp setDelegate:[UE4AppDelegate new]]; [NSApp run]; - return 0; -} \ No newline at end of file + return GGuardedMainErrorLevel; +} diff --git a/Engine/Source/Runtime/Launch/Public/Android/AndroidJNI.h b/Engine/Source/Runtime/Launch/Public/Android/AndroidJNI.h index 25a01e79d146..bd39eeb3671f 100644 --- a/Engine/Source/Runtime/Launch/Public/Android/AndroidJNI.h +++ b/Engine/Source/Runtime/Launch/Public/Android/AndroidJNI.h @@ -46,6 +46,7 @@ public: static jmethodID AndroidThunkJava_LocalNotificationGetLaunchNotification; //static jmethodID AndroidThunkJava_LocalNotificationDestroyIfExists; - This is not needed yet but will be soon so just leaving commented out for now static jmethodID AndroidThunkJava_HasActiveWiFiConnection; + static jmethodID AndroidThunkJava_GetAndroidId; // InputDeviceInfo member field ids static jclass InputDeviceInfoClass; @@ -66,9 +67,14 @@ public: static jmethodID AndroidThunkJava_IsInterstitialAdAvailable; static jmethodID AndroidThunkJava_IsInterstitialAdRequested; static jmethodID AndroidThunkJava_ShowInterstitialAd; + static jmethodID AndroidThunkJava_GetAdvertisingId; static jmethodID AndroidThunkJava_GoogleClientConnect; static jmethodID AndroidThunkJava_GoogleClientDisconnect; + // Optionally added if GCM plugin (or other remote notification system) enabled + static jmethodID AndroidThunkJava_RegisterForRemoteNotifications; + static jmethodID AndroidThunkJava_UnregisterForRemoteNotifications; + // In app purchase functionality static jclass JavaStringClass; static jmethodID AndroidThunkJava_IapSetupService; diff --git a/Engine/Source/Runtime/Launch/Public/LaunchEngineLoop.h b/Engine/Source/Runtime/Launch/Public/LaunchEngineLoop.h index 2b4cbbaa0f0e..0b6f731b81f8 100644 --- a/Engine/Source/Runtime/Launch/Public/LaunchEngineLoop.h +++ b/Engine/Source/Runtime/Launch/Public/LaunchEngineLoop.h @@ -27,6 +27,8 @@ public: */ FEngineLoop(); + virtual ~FEngineLoop() { } + public: /** diff --git a/Engine/Source/Runtime/Launch/Resources/Windows/PCLaunch.rc b/Engine/Source/Runtime/Launch/Resources/Windows/PCLaunch.rc index 6ff3a0534290..120b48fff40f 100644 --- a/Engine/Source/Runtime/Launch/Resources/Windows/PCLaunch.rc +++ b/Engine/Source/Runtime/Launch/Resources/Windows/PCLaunch.rc @@ -49,6 +49,16 @@ BEGIN LTEXT "Static",IDC_MESSAGE,16,14,265,66 END +IDD_YESNOYESTOALL DIALOGEX 0, 0, 297, 126 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + PUSHBUTTON "Yes",IDC_YES,69,98,50,14 + PUSHBUTTON "No",IDC_NO_B,124,98,50,14 + PUSHBUTTON "Yes to all",IDC_YESTOALL,178,98,50,14 + LTEXT "Static",IDC_MESSAGE,16,14,265,66 +END ///////////////////////////////////////////////////////////////////////////// // @@ -73,6 +83,10 @@ BEGIN TOPMARGIN, 7 BOTTOMMARGIN, 119 END + + IDD_YESNOYESTOALL, DIALOG + BEGIN + END END #endif // APSTUDIO_INVOKED diff --git a/Engine/Source/Runtime/Launch/Resources/Windows/resource.h b/Engine/Source/Runtime/Launch/Resources/Windows/resource.h index afde4dadaadc..dcea597816ed 100644 --- a/Engine/Source/Runtime/Launch/Resources/Windows/resource.h +++ b/Engine/Source/Runtime/Launch/Resources/Windows/resource.h @@ -6,6 +6,7 @@ // #define IDD_YESNO2ALL 101 #define IDD_YESNO2ALLCANCEL 102 +#define IDD_YESNOYESTOALL 103 // If IDICON_UE4Game is modified, please also modify IconResourceId in Engine\Source\Programs\UnrealBuildTool\Windows\WindowsDeploy.cs #define IDICON_UE4Game 123 #define IDC_YESTOALL 1000 @@ -20,7 +21,7 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_RESOURCE_VALUE 104 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1010 #define _APS_NEXT_SYMED_VALUE 101 diff --git a/Engine/Source/Runtime/LevelSequence/Private/LevelSequence.cpp b/Engine/Source/Runtime/LevelSequence/Private/LevelSequence.cpp index a9d6f3b5063a..03e57b300e53 100644 --- a/Engine/Source/Runtime/LevelSequence/Private/LevelSequence.cpp +++ b/Engine/Source/Runtime/LevelSequence/Private/LevelSequence.cpp @@ -113,7 +113,7 @@ void ULevelSequence::ConvertPersistentBindingsToDefault(UObject* FixupContext) { FGuid ObjectId; FGuid::Parse(Pair.Key, ObjectId); - ObjectReferences.CreateBinding(ObjectId, Object, FixupContext); + BindingReferences.AddBinding(ObjectId, Object, FixupContext); } } PossessedObjects_DEPRECATED.Empty(); @@ -123,15 +123,10 @@ void ULevelSequence::BindPossessableObject(const FGuid& ObjectId, UObject& Posse { if (Context) { - ObjectReferences.CreateBinding(ObjectId, &PossessedObject, Context); + BindingReferences.AddBinding(ObjectId, &PossessedObject, Context); } } -void ULevelSequence::BindPossessableObject(const FGuid& ObjectId, const FLevelSequenceObjectReference& ObjectReference) -{ - ObjectReferences.CreateBinding(ObjectId, ObjectReference); -} - bool ULevelSequence::CanPossessObject(UObject& Object, UObject* InPlaybackContext) const { return Object.IsA() || Object.IsA(); @@ -139,12 +134,14 @@ bool ULevelSequence::CanPossessObject(UObject& Object, UObject* InPlaybackContex void ULevelSequence::LocateBoundObjects(const FGuid& ObjectId, UObject* Context, TArray>& OutObjects) const { - // @todo: support multiple bindings + // Handle legacy object references UObject* Object = Context ? ObjectReferences.ResolveBinding(ObjectId, Context) : nullptr; if (Object) { OutObjects.Add(Object); } + + BindingReferences.ResolveBinding(ObjectId, Context, OutObjects); } UMovieScene* ULevelSequence::GetMovieScene() const @@ -176,5 +173,8 @@ bool ULevelSequence::CanRebindPossessable(const FMovieScenePossessable& InPosses void ULevelSequence::UnbindPossessableObjects(const FGuid& ObjectId) { - ObjectReferences.RemoveBinding(ObjectId); + BindingReferences.RemoveBinding(ObjectId); + + // Legacy object references + ObjectReferences.Map.Remove(ObjectId); } diff --git a/Engine/Source/Runtime/LevelSequence/Private/LevelSequenceActor.cpp b/Engine/Source/Runtime/LevelSequence/Private/LevelSequenceActor.cpp index 6d8ed21f9198..1520e73a73be 100644 --- a/Engine/Source/Runtime/LevelSequence/Private/LevelSequenceActor.cpp +++ b/Engine/Source/Runtime/LevelSequence/Private/LevelSequenceActor.cpp @@ -65,6 +65,10 @@ void ALevelSequenceActor::BeginPlay() { InitializePlayer(); } + if (SequencePlayer) + { + SequencePlayer->BeginPlay(); + } } @@ -146,9 +150,33 @@ void ALevelSequenceActor::UpdateObjectFromProxy(FStructOnScope& Proxy, IProperty #endif -ULevelSequence* ALevelSequenceActor::GetSequence(bool Load) const + +void ALevelSequenceActor::OnSequenceLoaded(const FName& PackageName, UPackage* Package, EAsyncLoadingResult::Type Result, bool bInitializePlayer) { - return Cast(Load ? LevelSequence.TryLoad() : LevelSequence.ResolveObject()); + if (bInitializePlayer) + { + InitializePlayer(); + } +} + +ULevelSequence* ALevelSequenceActor::GetSequence(bool bLoad, bool bInitializePlayer) const +{ + if (LevelSequence.IsValid()) + { + ULevelSequence* Sequence = Cast(LevelSequence.ResolveObject()); + if (Sequence) + { + return Sequence; + } + + if (bLoad) + { + LoadPackageAsync(LevelSequence.GetLongPackageName(), FLoadPackageAsyncDelegate::CreateUObject(this, &ALevelSequenceActor::OnSequenceLoaded, bInitializePlayer)); + return nullptr; + } + } + + return nullptr; } @@ -172,7 +200,7 @@ void ALevelSequenceActor::SetEventReceivers(TArray InAdditionalReceiver void ALevelSequenceActor::InitializePlayer() { - ULevelSequence* LevelSequenceAsset = GetSequence(true); + ULevelSequence* LevelSequenceAsset = GetSequence(true, true); if (GetWorld()->IsGameWorld() && (LevelSequenceAsset != nullptr)) { diff --git a/Engine/Source/Runtime/LevelSequence/Private/LevelSequenceBindingReference.cpp b/Engine/Source/Runtime/LevelSequence/Private/LevelSequenceBindingReference.cpp new file mode 100644 index 000000000000..4869767894c7 --- /dev/null +++ b/Engine/Source/Runtime/LevelSequence/Private/LevelSequenceBindingReference.cpp @@ -0,0 +1,176 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "LevelSequenceBindingReference.h" +#include "LevelSequenceLegacyObjectReference.h" +#include "UObject/Package.h" +#include "UObject/ObjectMacros.h" +#include "MovieSceneFwd.h" +#include "PackageName.h" +#include "Engine/World.h" + +FLevelSequenceBindingReference::FLevelSequenceBindingReference(UObject* InObject, UObject* InContext) +{ + check(InContext && InObject); + + if (!InContext->IsA() && InObject->IsIn(InContext)) + { + ObjectPath = InObject->GetPathName(InContext); + } + else + { + UPackage* ObjectPackage = InObject->GetOutermost(); + if (!ensure(ObjectPackage)) + { + return; + } + + PackageName = ObjectPackage->GetName(); + #if WITH_EDITORONLY_DATA + if (ObjectPackage->PIEInstanceID != INDEX_NONE) + { + FString PIEPrefix = FString::Printf(PLAYWORLD_PACKAGE_PREFIX TEXT("_%d_"), ObjectPackage->PIEInstanceID); + PackageName.ReplaceInline(*PIEPrefix, TEXT("")); + } + #endif + + ObjectPath = InObject->GetPathName(ObjectPackage); + } +} + +UObject* FLevelSequenceBindingReference::Resolve(UObject* InContext) const +{ + if (PackageName.Len() == 0) + { + return FindObject(InContext, *ObjectPath, false); + } + else + { + const TCHAR* SearchWithinPackage = *PackageName; + FString FixupPIEPackageName; + + #if WITH_EDITORONLY_DATA + int32 PIEInstanceID = InContext ? InContext->GetOutermost()->PIEInstanceID : INDEX_NONE; + if (PIEInstanceID != INDEX_NONE) + { + const FString ShortPackageOuterAndName = FPackageName::GetLongPackageAssetName(PackageName); + if (ensureMsgf(!ShortPackageOuterAndName.StartsWith(PLAYWORLD_PACKAGE_PREFIX), TEXT("Detected PIE world prefix in level sequence binding - this should not happen"))) + { + FixupPIEPackageName = FPackageName::GetLongPackagePath(PackageName) / FString::Printf(PLAYWORLD_PACKAGE_PREFIX TEXT("_%d_"), PIEInstanceID) + ShortPackageOuterAndName; + SearchWithinPackage = *FixupPIEPackageName; + } + } + #endif + + UPackage* Package = FindPackage(nullptr, SearchWithinPackage); + return Package ? FindObject(Package, *ObjectPath, false) : nullptr; + } +} + +UObject* FLevelSequenceLegacyObjectReference::Resolve(UObject* InContext) const +{ + if (ObjectId.IsValid() && InContext != nullptr) + { + int32 PIEInstanceID = InContext->GetOutermost()->PIEInstanceID; + FUniqueObjectGuid FixedUpId = PIEInstanceID == -1 ? ObjectId : ObjectId.FixupForPIE(PIEInstanceID); + + FLazyObjectPtr LazyPtr; + LazyPtr = FixedUpId; + + if (UObject* FoundObject = LazyPtr.Get()) + { + return FoundObject; + } + } + + if (!ObjectPath.IsEmpty()) + { + if (UObject* FoundObject = FindObject(InContext, *ObjectPath, false)) + { + return FoundObject; + } + + if (UObject* FoundObject = FindObject(ANY_PACKAGE, *ObjectPath, false)) + { + return FoundObject; + } + } + + return nullptr; +} + +bool FLevelSequenceObjectReferenceMap::Serialize(FArchive& Ar) +{ + int32 Num = Map.Num(); + Ar << Num; + + if (Ar.IsLoading()) + { + while(Num-- > 0) + { + FGuid Key; + Ar << Key; + + FLevelSequenceLegacyObjectReference Value; + Ar << Value; + + Map.Add(Key, Value); + } + } + else if (Ar.IsSaving() || Ar.IsCountingMemory() || Ar.IsObjectReferenceCollector()) + { + for (auto& Pair : Map) + { + Ar << Pair.Key; + Ar << Pair.Value; + } + } + return true; +} + +bool FLevelSequenceBindingReferences::HasBinding(const FGuid& ObjectId) const +{ + return BindingIdToReferences.Contains(ObjectId); +} + +void FLevelSequenceBindingReferences::AddBinding(const FGuid& ObjectId, UObject* InObject, UObject* InContext) +{ + BindingIdToReferences.FindOrAdd(ObjectId).References.Emplace(InObject, InContext); +} + +void FLevelSequenceBindingReferences::RemoveBinding(const FGuid& ObjectId) +{ + BindingIdToReferences.Remove(ObjectId); +} + +void FLevelSequenceBindingReferences::ResolveBinding(const FGuid& ObjectId, UObject* InContext, TArray>& OutObjects) const +{ + const FLevelSequenceBindingReferenceArray* ReferenceArray = BindingIdToReferences.Find(ObjectId); + if (!ReferenceArray) + { + return; + } + + for (const FLevelSequenceBindingReference& Reference : ReferenceArray->References) + { + UObject* ResolvedObject = Reference.Resolve(InContext); + + // if the resolved object does not have a valid world (e.g. world is being torn down), dont resolve + if (ResolvedObject && ResolvedObject->GetWorld()) + { + OutObjects.Add(ResolvedObject); + } + } +} + + +UObject* FLevelSequenceObjectReferenceMap::ResolveBinding(const FGuid& ObjectId, UObject* InContext) const +{ + const FLevelSequenceLegacyObjectReference* Reference = Map.Find(ObjectId); + UObject* ResolvedObject = Reference ? Reference->Resolve(InContext) : nullptr; + if (ResolvedObject != nullptr) + { + // if the resolved object does not have a valid world (e.g. world is being torn down), dont resolve + return ResolvedObject->GetWorld() != nullptr ? ResolvedObject : nullptr; + } + return nullptr; +} \ No newline at end of file diff --git a/Engine/Source/Runtime/LevelSequence/Private/LevelSequenceObjectReference.cpp b/Engine/Source/Runtime/LevelSequence/Private/LevelSequenceObjectReference.cpp deleted file mode 100644 index ee8fbd62e22e..000000000000 --- a/Engine/Source/Runtime/LevelSequence/Private/LevelSequenceObjectReference.cpp +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#include "LevelSequenceObjectReference.h" -#include "Components/ActorComponent.h" -#include "GameFramework/Actor.h" -#include "UObject/Package.h" -#include "UObject/ObjectMacros.h" -#include "MovieSceneFwd.h" - -FLevelSequenceObjectReference::FLevelSequenceObjectReference(UObject* InObject, UObject* InContext) -{ - if (InObject->IsA() || InObject->IsA()) - { - if (InContext->IsA()) - { - // When the context is an actor, we only use path name lookup within the actor since it's assumed the actor will be a spawnable - // As such, a persistent identifier for a dynamically spawned actor is not tenable - ObjectPath = InObject->GetPathName(InContext); - ObjectId = FUniqueObjectGuid(); - } - else - { - ObjectId = FLazyObjectPtr(InObject).GetUniqueID(); - ObjectPath = InObject->GetPathName(InContext); - } - } - else if(InObject->GetOuter() && InObject->GetOuter()->IsA()) - { - ObjectId = FLazyObjectPtr(InObject).GetUniqueID(); - ObjectPath = InObject->GetPathName(InContext); - } -} - -FLevelSequenceObjectReference::FLevelSequenceObjectReference(const FUniqueObjectGuid& InObjectId, const FString& InObjectPath) - : ObjectId(InObjectId) - , ObjectPath(InObjectPath) -{ -} - -UObject* FLevelSequenceObjectReference::Resolve(UObject* InContext) const -{ - if (ObjectId.IsValid() && InContext != nullptr) - { - int32 PIEInstanceID = InContext->GetOutermost()->PIEInstanceID; - FUniqueObjectGuid FixedUpId = PIEInstanceID == -1 ? ObjectId : ObjectId.FixupForPIE(PIEInstanceID); - - if (PIEInstanceID != -1 && FixedUpId == ObjectId) - { - UE_LOG(LogMovieScene, Warning, TEXT("Attempted to resolve object with a PIE instance that has not been fixed up yet. This is probably due to a streamed level not being available yet.")); - return nullptr; - } - - FLazyObjectPtr LazyPtr; - LazyPtr = FixedUpId; - - if (UObject* FoundObject = LazyPtr.Get()) - { - return FoundObject; - } - } - - if (!ObjectPath.IsEmpty()) - { - if (UObject* FoundObject = FindObject(InContext, *ObjectPath, false)) - { - return FoundObject; - } - - if (UObject* FoundObject = FindObject(ANY_PACKAGE, *ObjectPath, false)) - { - return FoundObject; - } - } - - return nullptr; -} - -bool FLevelSequenceObjectReferenceMap::Serialize(FArchive& Ar) -{ - int32 Num = Map.Num(); - Ar << Num; - - if (Ar.IsLoading()) - { - while(Num-- > 0) - { - FGuid Key; - Ar << Key; - - FLevelSequenceObjectReference Value; - Ar << Value; - - Map.Add(Key, Value); - } - } - else if (Ar.IsSaving() || Ar.IsCountingMemory() || Ar.IsObjectReferenceCollector()) - { - for (auto& Pair : Map) - { - Ar << Pair.Key; - Ar << Pair.Value; - } - } - return true; -} - -bool FLevelSequenceObjectReferenceMap::HasBinding(const FGuid& ObjectId) const -{ - if (const FLevelSequenceObjectReference* Reference = Map.Find(ObjectId)) - { - return Reference->IsValid(); - } - return false; -} - -void FLevelSequenceObjectReferenceMap::CreateBinding(const FGuid& ObjectId, UObject* InObject, UObject* InContext) -{ - FLevelSequenceObjectReference NewReference(InObject, InContext); - - if (ensureMsgf(NewReference.IsValid(), TEXT("Unable to generate a reference for the specified object and context"))) - { - Map.FindOrAdd(ObjectId) = NewReference; - } -} - -void FLevelSequenceObjectReferenceMap::CreateBinding(const FGuid& ObjectId, const FLevelSequenceObjectReference& ObjectReference) -{ - if (ensureMsgf(ObjectReference.IsValid(), TEXT("Invalid object reference specifed for binding"))) - { - Map.FindOrAdd(ObjectId) = ObjectReference; - } -} - -void FLevelSequenceObjectReferenceMap::RemoveBinding(const FGuid& ObjectId) -{ - Map.Remove(ObjectId); -} - -UObject* FLevelSequenceObjectReferenceMap::ResolveBinding(const FGuid& ObjectId, UObject* InContext) const -{ - const FLevelSequenceObjectReference* Reference = Map.Find(ObjectId); - UObject* ResolvedObject = Reference ? Reference->Resolve(InContext) : nullptr; - if (ResolvedObject != nullptr) - { - // if the resolved object does not have a valid world (e.g. world is being torn down), dont resolve - return ResolvedObject->GetWorld() != nullptr ? ResolvedObject : nullptr; - } - return nullptr; -} - -FGuid FLevelSequenceObjectReferenceMap::FindBindingId(UObject* InObject, UObject* InContext) const -{ - for (const auto& Pair : Map) - { - if (Pair.Value.Resolve(InContext) == InObject) - { - return Pair.Key; - } - } - return FGuid(); -} diff --git a/Engine/Source/Runtime/LevelSequence/Private/LevelSequencePlayer.cpp b/Engine/Source/Runtime/LevelSequence/Private/LevelSequencePlayer.cpp index f7a84c4932f2..b42e4ba98e70 100644 --- a/Engine/Source/Runtime/LevelSequence/Private/LevelSequencePlayer.cpp +++ b/Engine/Source/Runtime/LevelSequence/Private/LevelSequencePlayer.cpp @@ -73,12 +73,17 @@ bool ULevelSequencePlayer::CanPlay() const return World.IsValid(); } -void ULevelSequencePlayer::OnStartedPlaying() +void ULevelSequencePlayer::BeginPlay() { + EnableCinematicMode(true); + + Super::BeginPlay(); } void ULevelSequencePlayer::OnStopped() { + EnableCinematicMode(false); + AActor* LevelSequenceActor = Cast(GetOuter()); if (LevelSequenceActor == nullptr) { @@ -255,8 +260,10 @@ void ULevelSequencePlayer::TakeFrameSnapshot(FLevelSequencePlayerSnapshot& OutSn return; } + const float StartTimeWithoutWarmupFrames = SnapshotOffsetTime.IsSet() ? StartTime + SnapshotOffsetTime.GetValue() : StartTime; + // Use the actual last evaluation time as per the play position, which accounts for fixed time step offsetting - const float CurrentTime = StartTime + PlayPosition.GetLastPlayEvalPostition().Get(TimeCursorPosition); + const float CurrentTime = StartTimeWithoutWarmupFrames + PlayPosition.GetLastPlayEvalPostition().Get(TimeCursorPosition); OutSnapshot.Settings = SnapshotSettings; @@ -322,3 +329,24 @@ void ULevelSequencePlayer::TakeFrameSnapshot(FLevelSequencePlayerSnapshot& OutSn } } +void ULevelSequencePlayer::EnableCinematicMode(bool bEnable) +{ + // iterate through the controller list and set cinematic mode if necessary + bool bNeedsCinematicMode = PlaybackSettings.bDisableMovementInput || PlaybackSettings.bDisableLookAtInput || PlaybackSettings.bHidePlayer || PlaybackSettings.bHideHud; + + if (bNeedsCinematicMode) + { + if (World.IsValid()) + { + for (FConstPlayerControllerIterator Iterator = World->GetPlayerControllerIterator(); Iterator; ++Iterator) + { + APlayerController *PC = Iterator->Get(); + if (PC->IsLocalController()) + { + PC->SetCinematicMode(bEnable, PlaybackSettings.bHidePlayer, PlaybackSettings.bHideHud, PlaybackSettings.bDisableMovementInput, PlaybackSettings.bDisableLookAtInput); + } + } + } + } +} + diff --git a/Engine/Source/Runtime/LevelSequence/Public/LevelSequence.h b/Engine/Source/Runtime/LevelSequence/Public/LevelSequence.h index 661882c3927c..317c58207e2f 100644 --- a/Engine/Source/Runtime/LevelSequence/Public/LevelSequence.h +++ b/Engine/Source/Runtime/LevelSequence/Public/LevelSequence.h @@ -6,7 +6,8 @@ #include "UObject/ObjectMacros.h" #include "MovieSceneSequence.h" #include "LevelSequenceObject.h" -#include "LevelSequenceObjectReference.h" +#include "LevelSequenceBindingReference.h" +#include "LevelSequenceLegacyObjectReference.h" #include "LevelSequence.generated.h" class UMovieScene; @@ -50,15 +51,16 @@ public: virtual void PostLoad() override; - /** Bind a posessable object with an explicitly-supplied ObjectReference */ - void BindPossessableObject(const FGuid& ObjectId, const FLevelSequenceObjectReference& ObjectReference); - protected: - /** Collection of possessed objects. */ + /** Legacy object references - should be read-only. Not deprecated because they need to still be saved */ UPROPERTY() FLevelSequenceObjectReferenceMap ObjectReferences; + /** References to bound objects. */ + UPROPERTY() + FLevelSequenceBindingReferences BindingReferences; + /** Deprecated property housing old possessed object bindings */ UPROPERTY() TMap PossessedObjects_DEPRECATED; diff --git a/Engine/Source/Runtime/LevelSequence/Public/LevelSequenceActor.h b/Engine/Source/Runtime/LevelSequence/Public/LevelSequenceActor.h index c6922cb71b17..ff3a5254a189 100644 --- a/Engine/Source/Runtime/LevelSequence/Public/LevelSequenceActor.h +++ b/Engine/Source/Runtime/LevelSequence/Public/LevelSequenceActor.h @@ -94,12 +94,13 @@ public: /** * Get the level sequence being played by this actor. * - * @param Whether to load the sequence object if it is not already in memory. + * @param bLoad Whether to load the sequence object if it is not already in memory. + * @param bInitializePlayer Whether to initialize the player when the sequence has been loaded. * @return Level sequence, or nullptr if not assigned or if it cannot be loaded. * @see SetSequence */ UFUNCTION(BlueprintCallable, Category="Game|Cinematic") - ULevelSequence* GetSequence(bool Load = false) const; + ULevelSequence* GetSequence(bool bLoad = false, bool bInitializePlayer = false) const; /** * Set the level sequence being played by this actor. @@ -130,7 +131,7 @@ public: BindingOverrides->SetBinding(Binding, TArray(Actors), bAllowBindingsFromAsset); if (SequencePlayer) { - SequencePlayer->State.Invalidate(Binding.GetObjectBindingID(), Binding.GetSequenceID()); + SequencePlayer->State.Invalidate(Binding.GetGuid(), Binding.GetSequenceID()); } } @@ -141,7 +142,7 @@ public: BindingOverrides->AddBinding(Binding, Actor); if (SequencePlayer) { - SequencePlayer->State.Invalidate(Binding.GetObjectBindingID(), Binding.GetSequenceID()); + SequencePlayer->State.Invalidate(Binding.GetGuid(), Binding.GetSequenceID()); } } @@ -152,7 +153,7 @@ public: BindingOverrides->RemoveBinding(Binding, Actor); if (SequencePlayer) { - SequencePlayer->State.Invalidate(Binding.GetObjectBindingID(), Binding.GetSequenceID()); + SequencePlayer->State.Invalidate(Binding.GetGuid(), Binding.GetSequenceID()); } } @@ -163,7 +164,7 @@ public: BindingOverrides->ResetBinding(Binding); if (SequencePlayer) { - SequencePlayer->State.Invalidate(Binding.GetObjectBindingID(), Binding.GetSequenceID()); + SequencePlayer->State.Invalidate(Binding.GetGuid(), Binding.GetSequenceID()); } } @@ -195,6 +196,8 @@ public: void InitializePlayer(); + void OnSequenceLoaded(const FName& PackageName, UPackage* Package, EAsyncLoadingResult::Type Result, bool bInitializePlayer); + #if WITH_EDITOR virtual TSharedPtr GetObjectPickerProxy(TSharedPtr PropertyHandle) override; virtual void UpdateObjectFromProxy(FStructOnScope& Proxy, IPropertyHandle& ObjectPropertyHandle) override; diff --git a/Engine/Source/Runtime/LevelSequence/Public/LevelSequenceBindingReference.h b/Engine/Source/Runtime/LevelSequence/Public/LevelSequenceBindingReference.h new file mode 100644 index 000000000000..89d34e8a2154 --- /dev/null +++ b/Engine/Source/Runtime/LevelSequence/Public/LevelSequenceBindingReference.h @@ -0,0 +1,108 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "Misc/Guid.h" +#include "LevelSequenceBindingReference.generated.h" + +/** + * An external reference to an level sequence object, resolvable through an arbitrary context. + * + * Bindings consist of an optional package name, and the path to the object within that package. + * Where package name is empty, the reference is a relative path from a specific outer (the context). + * Currently, the package name should only ever be empty for component references, which must remain relative bindings to work correctly with spawnables and reinstanced actors. + */ +USTRUCT() +struct FLevelSequenceBindingReference +{ + GENERATED_BODY(); + + /** + * Default construction only used for serialization + */ + FLevelSequenceBindingReference() {} + + /** + * Construct a new binding reference from an object, and a given context (expected to be either a UWorld, or an AActor) + */ + LEVELSEQUENCE_API FLevelSequenceBindingReference(UObject* InObject, UObject* InContext); + + /** + * Resolve this reference within the specified context + * + * @param InContext The context to resolve the binding within. Either a UWorld or an AActor where this binding relates to an actor component + * @return The object (usually an Actor or an ActorComponent). + */ + LEVELSEQUENCE_API UObject* Resolve(UObject* InContext) const; + +private: + + /** The package name in which the object resides */ + UPROPERTY() + FString PackageName; + + /** The path of the object within the package, or from its outer (where PackageName is empty) */ + UPROPERTY() + FString ObjectPath; +}; + +/** + * An array of binding references + */ +USTRUCT() +struct FLevelSequenceBindingReferenceArray +{ + GENERATED_BODY() + + UPROPERTY() + TArray References; +}; + + +/** + * Structure that stores a one to many mapping from object binding ID, to object references that pertain to that ID. + */ +USTRUCT() +struct FLevelSequenceBindingReferences +{ + GENERATED_BODY() + + /** + * Check whether this map has a binding for the specified object id + * @return true if this map contains a binding for the id, false otherwise + */ + bool HasBinding(const FGuid& ObjectId) const; + + /** + * Remove a binding for the specified ID + * + * @param ObjectId The ID to remove + */ + void RemoveBinding(const FGuid& ObjectId); + + /** + * Add a binding for the specified ID + * + * @param ObjectId The ID to associate the object with + * @param InObject The object to associate + * @param InContext A context in which InObject resides (either a UWorld, or an AActor) + */ + void AddBinding(const FGuid& ObjectId, UObject* InObject, UObject* InContext); + + /** + * Resolve a binding for the specified ID using a given context + * + * @param ObjectId The ID to associate the object with + * @param InContext A context in which InObject resides + * @param OutObjects Array to populate with resolved object bindings + */ + void ResolveBinding(const FGuid& ObjectId, UObject* InContext, TArray>& OutObjects) const; + +private: + + /** The map from object binding ID to an array of references that pertain to that ID */ + UPROPERTY() + TMap BindingIdToReferences; +}; \ No newline at end of file diff --git a/Engine/Source/Runtime/LevelSequence/Public/LevelSequenceLegacyObjectReference.h b/Engine/Source/Runtime/LevelSequence/Public/LevelSequenceLegacyObjectReference.h new file mode 100644 index 000000000000..f9c02ec647c6 --- /dev/null +++ b/Engine/Source/Runtime/LevelSequence/Public/LevelSequenceLegacyObjectReference.h @@ -0,0 +1,89 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "Misc/Guid.h" +#include "UObject/Class.h" +#include "UObject/LazyObjectPtr.h" +#include "LevelSequenceLegacyObjectReference.generated.h" + +/** + * Legacy method by which objects were referenced within a level sequence. No longer used. See FLevelSequenceBindingReference for up-to-date implementation. + */ +USTRUCT() +struct FLevelSequenceLegacyObjectReference +{ + GENERATED_BODY(); + + /** + * Resolve this reference within the specified context + * + * @return The object (usually an Actor or an ActorComponent). + */ + UObject* Resolve(UObject* InContext) const; + + /** + * Serialization operator + */ + friend FArchive& operator<<(FArchive& Ar, FLevelSequenceLegacyObjectReference& Ref) + { + Ar << Ref.ObjectId; + Ar << Ref.ObjectPath; + return Ar; + } + + friend bool operator==(const FLevelSequenceLegacyObjectReference& A, const FLevelSequenceLegacyObjectReference& B) + { + if (A.ObjectId.IsValid() && A.ObjectId == B.ObjectId) + { + return true; + } + return A.ObjectPath == B.ObjectPath; + } + +private: + + /** Primary method of resolution - object ID, stored as an annotation on the object in the world, resolvable through TLazyObjectPtr */ + FUniqueObjectGuid ObjectId; + + /** Secondary method of resolution - path to the object within the context */ + FString ObjectPath; +}; + +USTRUCT() +struct FLevelSequenceObjectReferenceMap +{ +public: + + GENERATED_BODY(); + + UObject* ResolveBinding(const FGuid& ObjectId, UObject* InContext) const; + + /** + * Equality comparator required for proper UObject serialization (so we can compare against defaults) + */ + friend bool operator==(const FLevelSequenceObjectReferenceMap& A, const FLevelSequenceObjectReferenceMap& B) + { + return A.Map.OrderIndependentCompareEqual(B.Map); + } + + /** + * Serialization function + */ + bool Serialize(FArchive& Ar); + + typedef TMap MapType; + FORCEINLINE friend MapType::TIterator begin( FLevelSequenceObjectReferenceMap& Impl) { return begin(Impl.Map); } + FORCEINLINE friend MapType::TConstIterator begin(const FLevelSequenceObjectReferenceMap& Impl) { return begin(Impl.Map); } + FORCEINLINE friend MapType::TIterator end ( FLevelSequenceObjectReferenceMap& Impl) { return end(Impl.Map); } + FORCEINLINE friend MapType::TConstIterator end (const FLevelSequenceObjectReferenceMap& Impl) { return end(Impl.Map); } + + TMap Map; +}; + +template<> struct TStructOpsTypeTraits : public TStructOpsTypeTraitsBase2 +{ + enum { WithSerializer = true, WithIdenticalViaEquality = true }; +}; \ No newline at end of file diff --git a/Engine/Source/Runtime/LevelSequence/Public/LevelSequenceObjectReference.h b/Engine/Source/Runtime/LevelSequence/Public/LevelSequenceObjectReference.h deleted file mode 100644 index 34a1442dad39..000000000000 --- a/Engine/Source/Runtime/LevelSequence/Public/LevelSequenceObjectReference.h +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "CoreMinimal.h" -#include "UObject/ObjectMacros.h" -#include "Misc/Guid.h" -#include "UObject/Class.h" -#include "UObject/LazyObjectPtr.h" -#include "LevelSequenceObjectReference.generated.h" - -/** - * An external reference to an level sequence object, resolvable through an arbitrary context. - */ -USTRUCT() -struct FLevelSequenceObjectReference -{ - /** - * Default construction to a null reference - */ - FLevelSequenceObjectReference() : ObjectPath() {} - - /** - * Generates a new reference to an object within a given context. - * - * @param InObject The object to generate a reference for (e.g. an AActor) - * @param InContext The object to use as a context for the generation (e.g. a UWorld) - */ - LEVELSEQUENCE_API FLevelSequenceObjectReference(UObject* InObject, UObject* InContext); - - /** - * Generates a new reference to an object. - * - * @param InObjectId Primary method of resolution - object ID, stored as an annotation on the object in the world, resolvable through TLazyObjectPtr - * @param InObjectPath Secondary method of resolution - path to the object within the context - */ - LEVELSEQUENCE_API FLevelSequenceObjectReference(const FUniqueObjectGuid& InObjectId, const FString& InObjectPath); - - GENERATED_BODY(); - - /** - * Check whether this object reference is valid or not - */ - bool IsValid() const - { - return !ObjectPath.IsEmpty(); - } - - /** - * Resolve this reference within the specified context - * - * @return The object (usually an Actor or an ActorComponent). - */ - LEVELSEQUENCE_API UObject* Resolve(UObject* InContext) const; - - /** - * Equality comparator - */ - friend bool operator==(const FLevelSequenceObjectReference& A, const FLevelSequenceObjectReference& B) - { - if (A.ObjectId.IsValid() && A.ObjectId == B.ObjectId) - { - return true; - } - return A.ObjectPath == B.ObjectPath; - } - - /** - * Serialization operator - */ - friend FArchive& operator<<(FArchive& Ar, FLevelSequenceObjectReference& Ref) - { - Ar << Ref.ObjectId; - Ar << Ref.ObjectPath; - return Ar; - } - -private: - - /** Primary method of resolution - object ID, stored as an annotation on the object in the world, resolvable through TLazyObjectPtr */ - FUniqueObjectGuid ObjectId; - - /** Secondary method of resolution - path to the object within the context */ - FString ObjectPath; -}; - -USTRUCT() -struct FLevelSequenceObjectReferenceMap -{ - /** - * Check whether this map has a binding for the specified object id - * @return true if this map contains a binding for the id, false otherwise - */ - bool HasBinding(const FGuid& ObjectId) const; - - /** - * Remove a binding for the specified ID - * - * @param ObjectId The ID to remove - */ - void RemoveBinding(const FGuid& ObjectId); - - /** - * Create a binding for the specified ID - * - * @param ObjectId The ID to associate the object with - * @param InObject The object to associate - * @param InContext A context in which InObject resides - */ - void CreateBinding(const FGuid& ObjectId, UObject* InObject, UObject* InContext); - - /** - * Create a binding for the specified ID - * - * @param ObjectId The ID to associate the object with - * @param ObjectReference The object reference to bind - */ - void CreateBinding(const FGuid& ObjectId, const FLevelSequenceObjectReference& ObjectReference); - - /** - * Resolve a binding for the specified ID using a given context - * - * @param ObjectId The ID to associate the object with - * @param InContext A context in which InObject resides - * - * @return The object if found, nullptr otherwise. - */ - UObject* ResolveBinding(const FGuid& ObjectId, UObject* InContext) const; - - /** - * Find an object ID that the specified object is bound with - * - * @param InObject The object to find an ID for - * @param InContext The context in which InObject resides - * - * @return The object's bound ID, or an empty FGuid - */ - FGuid FindBindingId(UObject* InObject, UObject* InContext) const; - -public: - - GENERATED_BODY(); - - /** - * Equality comparator required for proper UObject serialization (so we can compare against defaults) - */ - friend bool operator==(const FLevelSequenceObjectReferenceMap& A, const FLevelSequenceObjectReferenceMap& B) - { - return A.Map.OrderIndependentCompareEqual(B.Map); - } - - /** - * Serialization function - */ - bool Serialize(FArchive& Ar); - - typedef TMap MapType; - FORCEINLINE friend MapType::TIterator begin( FLevelSequenceObjectReferenceMap& Impl) { return begin(Impl.Map); } - FORCEINLINE friend MapType::TConstIterator begin(const FLevelSequenceObjectReferenceMap& Impl) { return begin(Impl.Map); } - FORCEINLINE friend MapType::TIterator end ( FLevelSequenceObjectReferenceMap& Impl) { return end(Impl.Map); } - FORCEINLINE friend MapType::TConstIterator end (const FLevelSequenceObjectReferenceMap& Impl) { return end(Impl.Map); } - -private: - - // @todo sequencer: need support for UStruct keys in TMap so this can be a UPROPERTY - TMap Map; -}; - -template<> struct TStructOpsTypeTraits : public TStructOpsTypeTraitsBase2 -{ - enum { WithSerializer = true, WithIdenticalViaEquality = true }; -}; diff --git a/Engine/Source/Runtime/LevelSequence/Public/LevelSequencePlayer.h b/Engine/Source/Runtime/LevelSequence/Public/LevelSequencePlayer.h index e39d8a928a54..b36dce4b9303 100644 --- a/Engine/Source/Runtime/LevelSequence/Public/LevelSequencePlayer.h +++ b/Engine/Source/Runtime/LevelSequence/Public/LevelSequencePlayer.h @@ -131,7 +131,6 @@ protected: //~ UMovieSceneSequencePlayer interface virtual bool CanPlay() const override; - virtual void OnStartedPlaying() override; virtual void OnStopped() override; public: @@ -139,6 +138,8 @@ public: /** Populate the specified array with any given event contexts for the specified world */ static void GetEventContexts(UWorld& InWorld, TArray& OutContexts); + virtual void BeginPlay() override; + /** * Set an array of additional actors that will receive events triggerd from this sequence player * @@ -149,6 +150,9 @@ public: /** Take a snapshot of the current state of this player */ void TakeFrameSnapshot(FLevelSequencePlayerSnapshot& OutSnapshot) const; + /** Set the offset time for the snapshot */ + void SetSnapshotOffsetTime(float InTime) {SnapshotOffsetTime = TOptional(InTime); } + private: /** Add tick prerequisites so that the level sequence actor ticks before all the actors it controls */ @@ -156,6 +160,8 @@ private: void SetTickPrerequisites(FMovieSceneSequenceID SequenceID, UMovieSceneSequence* Sequence, bool bAddTickPrerequisites); + void EnableCinematicMode(bool bEnable); + private: /** The world this player will spawn actors in, if needed */ @@ -172,6 +178,8 @@ protected: /** How to take snapshots */ FLevelSequenceSnapshotSettings SnapshotSettings; + TOptional SnapshotOffsetTime; + TWeakObjectPtr CachedCameraComponent; /** Array of additional event receivers */ diff --git a/Engine/Source/Runtime/MRMesh/MRMesh.build.cs b/Engine/Source/Runtime/MRMesh/MRMesh.build.cs new file mode 100644 index 000000000000..50464bb458c2 --- /dev/null +++ b/Engine/Source/Runtime/MRMesh/MRMesh.build.cs @@ -0,0 +1,25 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +namespace UnrealBuildTool.Rules +{ + public class MRMesh : ModuleRules + { + public MRMesh(ReadOnlyTargetRules Target) : base(Target) + { + PrivateIncludePaths.Add("Runtime/MRMesh/Private"); + PublicIncludePaths.Add("Runtime/MRMesh/Public"); + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "Core", + "CoreUObject", + "Engine", + "RenderCore", + "ShaderCore", + "RHI" + } + ); + } + } +} diff --git a/Engine/Source/Runtime/MRMesh/Private/MRMeshComponent.cpp b/Engine/Source/Runtime/MRMesh/Private/MRMeshComponent.cpp new file mode 100644 index 000000000000..47db5c88a3c2 --- /dev/null +++ b/Engine/Source/Runtime/MRMesh/Private/MRMeshComponent.cpp @@ -0,0 +1,364 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "MRMeshComponent.h" +#include "PrimitiveSceneProxy.h" +#include "DynamicMeshBuilder.h" +#include "LocalVertexFactory.h" +#include "Containers/ResourceArray.h" +#include "SceneManagement.h" +#include "MaterialShared.h" +#include "Materials/Material.h" +#include "RenderingThread.h" +#include "BaseMeshReconstructorModule.h" + + + +class FMRMeshVertexResourceArray : public FResourceArrayInterface +{ +public: + FMRMeshVertexResourceArray(void* InData, uint32 InSize) + : Data(InData) + , Size(InSize) + { + } + + virtual const void* GetResourceData() const override { return Data; } + virtual uint32 GetResourceDataSize() const override { return Size; } + virtual void Discard() override { } + virtual bool IsStatic() const override { return false; } + virtual bool GetAllowCPUAccess() const override { return false; } + virtual void SetAllowCPUAccess(bool bInNeedsCPUAccess) override { } + +private: + void* Data; + uint32 Size; +}; + + +class FMRMeshVertexBuffer : public FVertexBuffer +{ +public: + int32 NumVerts = 0; + void InitRHIWith( TArray& Vertices ) + { + NumVerts = Vertices.Num(); + + const uint32 SizeInBytes = Vertices.Num() * sizeof(FDynamicMeshVertex); + + FMRMeshVertexResourceArray ResourceArray(Vertices.GetData(), SizeInBytes); + FRHIResourceCreateInfo CreateInfo(&ResourceArray); + VertexBufferRHI = RHICreateVertexBuffer(SizeInBytes, BUF_Static, CreateInfo); + } + +}; + +class FMRMeshIndexBuffer : public FIndexBuffer +{ +public: + int32 NumIndices = 0; + void InitRHIWith( const TArray& Indices ) + { + NumIndices = Indices.Num(); + + FRHIResourceCreateInfo CreateInfo; + void* Buffer = nullptr; + IndexBufferRHI = RHICreateAndLockIndexBuffer(sizeof(int32), Indices.Num() * sizeof(int32), BUF_Static, CreateInfo, Buffer); + + // Write the indices to the index buffer. + FMemory::Memcpy(Buffer, Indices.GetData(), Indices.Num() * sizeof(int32)); + RHIUnlockIndexBuffer(IndexBufferRHI); + } +}; + +class FMRMeshVertexFactory : public FLocalVertexFactory +{ +public: + + FMRMeshVertexFactory() + {} + + /** Init function that should only be called on render thread. */ + void Init_RenderThread(const FMRMeshVertexBuffer* VertexBuffer) + { + check(IsInRenderingThread()); + + // Initialize the vertex factory's stream components. + FDataType NewData; + NewData.PositionComponent = STRUCTMEMBER_VERTEXSTREAMCOMPONENT(VertexBuffer, FDynamicMeshVertex, Position, VET_Float3); + NewData.TextureCoordinates.Add( + FVertexStreamComponent(VertexBuffer, STRUCT_OFFSET(FDynamicMeshVertex, TextureCoordinate), sizeof(FDynamicMeshVertex), VET_Float2) + ); + NewData.TangentBasisComponents[0] = STRUCTMEMBER_VERTEXSTREAMCOMPONENT(VertexBuffer, FDynamicMeshVertex, TangentX, VET_PackedNormal); + NewData.TangentBasisComponents[1] = STRUCTMEMBER_VERTEXSTREAMCOMPONENT(VertexBuffer, FDynamicMeshVertex, TangentZ, VET_PackedNormal); + NewData.ColorComponent = STRUCTMEMBER_VERTEXSTREAMCOMPONENT(VertexBuffer, FDynamicMeshVertex, Color, VET_Color); + SetData(NewData); + } + + /** Init function that can be called on any thread, and will do the right thing (enqueue command if called on main thread) */ + void Init(const FMRMeshVertexBuffer* VertexBuffer) + { + if (IsInRenderingThread()) + { + Init_RenderThread(VertexBuffer); + } + else + { + ENQUEUE_UNIQUE_RENDER_COMMAND_TWOPARAMETER( + InitProcMeshVertexFactory, + FMRMeshVertexFactory*, VertexFactory, this, + const FMRMeshVertexBuffer*, VertexBuffer, VertexBuffer, + { + VertexFactory->Init_RenderThread(VertexBuffer); + }); + } + } +}; + + +struct FMRMeshProxySection +{ + /** Which brick this section represents */ + FIntVector BrickId; + /** Vertex buffer for this section */ + FMRMeshVertexBuffer VertexBuffer; + /** Index buffer for this section */ + FMRMeshIndexBuffer IndexBuffer; + /** Vertex factory for this section */ + FMRMeshVertexFactory VertexFactory; + + FMRMeshProxySection(FIntVector InBrickId) + : BrickId(InBrickId) + { + } + + void ReleaseResources() + { + VertexBuffer.ReleaseResource(); + IndexBuffer.ReleaseResource(); + VertexFactory.ReleaseResource(); + } + + FMRMeshProxySection(const FMRMeshVertexFactory&) = delete; + void operator==(const FMRMeshVertexFactory&) = delete; +}; + +class FMRMeshProxy : public FPrimitiveSceneProxy +{ +public: + FMRMeshProxy(const UMRMeshComponent* InComponent) + : FPrimitiveSceneProxy(InComponent) + , MaterialToUse((InComponent->Material!=nullptr) ? InComponent->Material : UMaterial::GetDefaultMaterial(MD_Surface) ) + { + } + + virtual ~FMRMeshProxy() + { + for (FMRMeshProxySection* Section : ProxySections) + { + if (Section != nullptr) + { + Section->ReleaseResources(); + delete Section; + } + } + } + + void RenderThread_UploadNewSection(IMRMesh::FSendBrickDataArgs Args) + { + check(IsInRenderingThread() || IsInRHIThread()); + + FMRMeshProxySection* NewSection = new FMRMeshProxySection(Args.BrickCoords); + ProxySections.Add(NewSection); + + // VERTEX BUFFER + { + NewSection->VertexBuffer.InitResource(); + NewSection->VertexBuffer.InitRHIWith(Args.Vertices); + } + + // INDEX BUFFER + { + NewSection->IndexBuffer.InitResource(); + NewSection->IndexBuffer.InitRHIWith(Args.Indices); + } + + // VERTEX FACTORY + { + NewSection->VertexFactory.Init(&NewSection->VertexBuffer); + NewSection->VertexFactory.InitResource(); + } + } + + bool RenderThread_RemoveSection(FIntVector BrickCoords) + { + check(IsInRenderingThread() || IsInRHIThread()); + for (int32 i = 0; i < ProxySections.Num(); ++i) + { + if (ProxySections[i]->BrickId == BrickCoords) + { + ProxySections[i]->ReleaseResources(); + delete ProxySections[i]; + ProxySections.RemoveAtSwap(i); + return true; + } + } + return false; + } + +private: + //~ FPrimitiveSceneProxy + virtual uint32 GetMemoryFootprint(void) const override + { + return 0; + } + + virtual void GetDynamicMeshElements(const TArray& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, class FMeshElementCollector& Collector) const override + { + static const FBoxSphereBounds InfiniteBounds(FSphere(FVector::ZeroVector, HALF_WORLD_MAX)); + + // Iterate over sections + for (const FMRMeshProxySection* Section : ProxySections) + { + if (Section != nullptr) + { + const bool bIsSelected = false; + FMaterialRenderProxy* MaterialProxy = MaterialToUse->GetRenderProxy(bIsSelected); + + // For each view.. + for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) + { + if (VisibilityMap & (1 << ViewIndex)) + { + const FSceneView* View = Views[ViewIndex]; + // Draw the mesh. + FMeshBatch& Mesh = Collector.AllocateMesh(); + FMeshBatchElement& BatchElement = Mesh.Elements[0]; + BatchElement.IndexBuffer = &Section->IndexBuffer; + Mesh.bWireframe = false; + Mesh.VertexFactory = &Section->VertexFactory; + Mesh.MaterialRenderProxy = MaterialProxy; + BatchElement.PrimitiveUniformBuffer = CreatePrimitiveUniformBufferImmediate(GetLocalToWorld(), InfiniteBounds, InfiniteBounds, true, UseEditorDepthTest()); + BatchElement.FirstIndex = 0; + BatchElement.NumPrimitives = Section->IndexBuffer.NumIndices / 3; + BatchElement.MinVertexIndex = 0; + BatchElement.MaxVertexIndex = Section->VertexBuffer.NumVerts - 1; + Mesh.ReverseCulling = IsLocalToWorldDeterminantNegative(); + Mesh.Type = PT_TriangleList; + Mesh.DepthPriorityGroup = SDPG_World; + Mesh.bCanApplyViewModeOverrides = false; + Collector.AddMesh(ViewIndex, Mesh); + } + } + } + } + } + + virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView* View) const + { + FPrimitiveViewRelevance Result; + Result.bDrawRelevance = IsShown(View); + Result.bShadowRelevance = IsShadowCast(View); + Result.bDynamicRelevance = true; + Result.bRenderInMainPass = ShouldRenderInMainPass(); + Result.bUsesLightingChannels = GetLightingChannelMask() != GetDefaultLightingChannelMask(); + Result.bRenderCustomDepth = ShouldRenderCustomDepth(); + //MaterialRelevance.SetPrimitiveViewRelevance(Result); + return Result; + } + //~ FPrimitiveSceneProxy + +private: + TArray ProxySections; + UMaterialInterface* MaterialToUse; +}; + + +UMRMeshComponent::UMRMeshComponent(const FObjectInitializer& ObjectInitializer) +: Super(ObjectInitializer) +, MeshReconstructor(nullptr) +{ + +} + +FPrimitiveSceneProxy* UMRMeshComponent::CreateSceneProxy() +{ + // The render thread owns the memory, so if this function is + // being called, it's safe to just re-allocate. + + if ( FBaseMeshReconstructorModule::IsAvailable() ) + { + MeshReconstructor = &FBaseMeshReconstructorModule::Get(); + MeshReconstructor->PairWithComponent(*this); + } + + return new FMRMeshProxy(this); +} + +void UMRMeshComponent::GetUsedMaterials(TArray& OutMaterials, bool bGetDebugMaterials /*= false*/) const +{ + if (Material != nullptr) + { + OutMaterials.Add(Material); + } +} + +FBoxSphereBounds UMRMeshComponent::CalcBounds(const FTransform& LocalToWorld) const +{ + return FBoxSphereBounds(FSphere(FVector::ZeroVector, HALF_WORLD_MAX)); +} + +void UMRMeshComponent::SendBrickData(IMRMesh::FSendBrickDataArgs Args, const FOnProcessingComplete& OnProcessingComplete /*= FOnProcessingComplete()*/) +{ + auto BrickDataTask = FSimpleDelegateGraphTask::FDelegate::CreateUObject(this, &UMRMeshComponent::SendBrickData_Internal, Args, OnProcessingComplete); + + DECLARE_CYCLE_STAT(TEXT("UMRMeshComponent.SendBrickData"), + STAT_UMRMeshComponent_SendBrickData, + STATGROUP_MRMESH); + + // The render thread might not be around, in which case + // queue the task into the game thread for later processing. + FSimpleDelegateGraphTask::CreateAndDispatchWhenReady(BrickDataTask, GET_STATID(STAT_UMRMeshComponent_SendBrickData), nullptr, ENamedThreads::GameThread); + +} + +void UMRMeshComponent::SendBrickData_Internal(IMRMesh::FSendBrickDataArgs Args, FOnProcessingComplete OnProcessingComplete) +{ + check(IsInGameThread()); + if (!IsPendingKill() && SceneProxy != nullptr) + { + check(GRenderingThread != nullptr); + check(SceneProxy != nullptr); + + ENQUEUE_UNIQUE_RENDER_COMMAND_THREEPARAMETER( + FSendBrickDataLambda, + UMRMeshComponent*, This, this, + IMRMesh::FSendBrickDataArgs, Args, Args, + FOnProcessingComplete, OnProcessingComplete, OnProcessingComplete, + { + FMRMeshProxy* MRMeshProxy = static_cast(This->SceneProxy); + if (MRMeshProxy) + { + MRMeshProxy->RenderThread_RemoveSection(Args.BrickCoords); + MRMeshProxy->RenderThread_UploadNewSection(Args); + + if (OnProcessingComplete.IsBound()) + { + OnProcessingComplete.Execute(); + } + } + }); + } +} + +void UMRMeshComponent::BeginDestroy() +{ + if (MeshReconstructor != nullptr) + { + MeshReconstructor->Stop(); + MeshReconstructor = nullptr; + } + + Super::BeginDestroy(); + +} + diff --git a/Engine/Source/Runtime/MRMesh/Private/MRMeshModule.cpp b/Engine/Source/Runtime/MRMesh/Private/MRMeshModule.cpp new file mode 100644 index 000000000000..281e2e3a2ce5 --- /dev/null +++ b/Engine/Source/Runtime/MRMesh/Private/MRMeshModule.cpp @@ -0,0 +1,10 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "MRMeshModule.h" +#include "Modules/ModuleManager.h" + +class FMRMeshModule : public IMRMeshModule +{ +}; + +IMPLEMENT_MODULE(FMRMeshModule, MRMesh); \ No newline at end of file diff --git a/Engine/Source/Runtime/MRMesh/Public/BaseMeshReconstructorModule.h b/Engine/Source/Runtime/MRMesh/Public/BaseMeshReconstructorModule.h new file mode 100644 index 000000000000..be91729e0f06 --- /dev/null +++ b/Engine/Source/Runtime/MRMesh/Public/BaseMeshReconstructorModule.h @@ -0,0 +1,73 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "Modules/ModuleInterface.h" +#include "Features/IModularFeatures.h" +#include "Features/IModularFeature.h" + +class IMRMesh; + +class FBaseMeshReconstructorModule : public IModuleInterface, public IModularFeature +{ +public: + // + // MESH RECONSTRUCTION API + // + + /** Invoked when a new MRMesh instance wants to render and is requesting that data be sent to it. */ + virtual void PairWithComponent(IMRMesh& MRMeshComponent) = 0; + + /** A signal to stop any running threads. */ + virtual void Stop() = 0; + +public: + // + // MODULAR FEATURE SUPPORT + // + + /** + * Part of the pattern for supporting modular features. + * + * @return the name of the feature. + */ + static FName GetModularFeatureName() + { + static const FName ModularFeatureName = FName(TEXT("MeshReconstructor")); + return ModularFeatureName; + } + + /** + * Singleton-like access to a MeshReconstructorModule. + * + * @return Returns reference to the highest priority MeshReconstructorModule module + */ + static inline FBaseMeshReconstructorModule& Get() + { + //@todo implement priority for choosing the most appropriate implementation + + TArray MeshReconstructors = IModularFeatures::Get().GetModularFeatureImplementations(GetModularFeatureName()); + check(MeshReconstructors.Num() > 0); + return *MeshReconstructors[0]; + } + + /** + * Check to see that there is a MeshReconstructor module available. + * + * @return True if there exists a MeshReconstructor module registered. + */ + static inline bool IsAvailable() + { + return IModularFeatures::Get().IsModularFeatureAvailable(GetModularFeatureName()); + } + + /** + * Register module as a MeshReconstructor on startup. + */ + virtual void StartupModule() override + { + IModularFeatures::Get().RegisterModularFeature(GetModularFeatureName(), this); + } + +}; \ No newline at end of file diff --git a/Engine/Source/Runtime/MRMesh/Public/MRMeshComponent.h b/Engine/Source/Runtime/MRMesh/Public/MRMeshComponent.h new file mode 100644 index 000000000000..1af9b7c04adf --- /dev/null +++ b/Engine/Source/Runtime/MRMesh/Public/MRMeshComponent.h @@ -0,0 +1,59 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "Components/PrimitiveComponent.h" +#include "MRMeshComponent.generated.h" + + +class UMaterial; +class FBaseMeshReconstructorModule; +struct FDynamicMeshVertex; + +DECLARE_STATS_GROUP(TEXT("MRMesh"), STATGROUP_MRMESH, STATCAT_Advanced); + +DECLARE_DELEGATE(FOnProcessingComplete) +class IMRMesh +{ +public: + struct FSendBrickDataArgs + { + FIntVector BrickCoords; + TArray& Vertices; + TArray& Indices; + }; + + virtual void SendBrickData(FSendBrickDataArgs Args, const FOnProcessingComplete& OnProcessingComplete = FOnProcessingComplete()) = 0; +}; + + + +UCLASS(meta = (BlueprintSpawnableComponent), ClassGroup = Rendering) +class MRMESH_API UMRMeshComponent : public UPrimitiveComponent, public IMRMesh +{ + friend class FMRMeshProxy; + + GENERATED_UCLASS_BODY() +private: + //~ UPrimitiveComponent + virtual FPrimitiveSceneProxy* CreateSceneProxy() override; + virtual void GetUsedMaterials(TArray& OutMaterials, bool bGetDebugMaterials = false) const override; + virtual FBoxSphereBounds CalcBounds(const FTransform& LocalToWorld) const override; + virtual void BeginDestroy() override; + //~ UPrimitiveComponent + + //~ IMRMesh + virtual void SendBrickData(IMRMesh::FSendBrickDataArgs Args, const FOnProcessingComplete& OnProcessingComplete = FOnProcessingComplete()) override; + //~ IMRMesh + + +private: + void SendBrickData_Internal(IMRMesh::FSendBrickDataArgs Args, FOnProcessingComplete OnProcessingComplete); + + UPROPERTY(EditAnywhere, Category = Appearance) + UMaterial* Material; + + FBaseMeshReconstructorModule* MeshReconstructor = nullptr; + +}; \ No newline at end of file diff --git a/Engine/Source/Runtime/MRMesh/Public/MRMeshModule.h b/Engine/Source/Runtime/MRMesh/Public/MRMeshModule.h new file mode 100644 index 000000000000..c7508ab2bb6f --- /dev/null +++ b/Engine/Source/Runtime/MRMesh/Public/MRMeshModule.h @@ -0,0 +1,10 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "Modules/ModuleInterface.h" + +class IMRMeshModule : public IModuleInterface +{ +}; \ No newline at end of file diff --git a/Engine/Source/Runtime/Mac/CoreAudio/Private/CoreAudioBuffer.cpp b/Engine/Source/Runtime/Mac/CoreAudio/Private/CoreAudioBuffer.cpp index 46a1e81ffe2d..9547bcc81566 100644 --- a/Engine/Source/Runtime/Mac/CoreAudio/Private/CoreAudioBuffer.cpp +++ b/Engine/Source/Runtime/Mac/CoreAudio/Private/CoreAudioBuffer.cpp @@ -354,7 +354,7 @@ FCoreAudioSoundBuffer* FCoreAudioSoundBuffer::Init( FAudioDevice* AudioDevice, U // Allow the precache to happen if necessary EDecompressionType DecompressionType = Wave->DecompressionType; - if (bForceRealtime && DecompressionType != DTYPE_Setup ) + if (bForceRealtime && DecompressionType != DTYPE_Setup && DecompressionType != DTYPE_Streaming) { DecompressionType = DTYPE_RealTime; } @@ -419,3 +419,23 @@ FCoreAudioSoundBuffer* FCoreAudioSoundBuffer::Init( FAudioDevice* AudioDevice, U return Buffer; } + +int32 FCoreAudioSoundBuffer::GetCurrentChunkIndex() const +{ + if (DecompressionState == NULL) + { + return -1; + } + + return DecompressionState->GetCurrentChunkIndex(); +} + +int32 FCoreAudioSoundBuffer::GetCurrentChunkOffset() const +{ + if (DecompressionState == NULL) + { + return -1; + } + + return DecompressionState->GetCurrentChunkOffset(); +} \ No newline at end of file diff --git a/Engine/Source/Runtime/Mac/CoreAudio/Private/CoreAudioDevice.cpp b/Engine/Source/Runtime/Mac/CoreAudio/Private/CoreAudioDevice.cpp index 7a8a226be645..9dd889cbd5e4 100644 --- a/Engine/Source/Runtime/Mac/CoreAudio/Private/CoreAudioDevice.cpp +++ b/Engine/Source/Runtime/Mac/CoreAudio/Private/CoreAudioDevice.cpp @@ -10,6 +10,7 @@ #include "CoreAudioDevice.h" #include "VorbisAudioInfo.h" +#include "OpusAudioInfo.h" #include "AudioEffect.h" #include "CoreAudioEffects.h" @@ -506,9 +507,30 @@ bool FCoreAudioDevice::HasCompressedAudioInfoClass(USoundWave* SoundWave) class ICompressedAudioInfo* FCoreAudioDevice::CreateCompressedAudioInfo(USoundWave* SoundWave) { + check(SoundWave); + + if (SoundWave->IsStreaming()) + { + return new FOpusAudioInfo(); + } + #if WITH_OGGVORBIS - return new FVorbisAudioInfo(); + static const FName NAME_OGG(TEXT("OGG")); + if (FPlatformProperties::RequiresCookedData() ? SoundWave->HasCompressedData(NAME_OGG) : (SoundWave->GetCompressedData(NAME_OGG) != nullptr)) + { + ICompressedAudioInfo* CompressedInfo = new FVorbisAudioInfo(); + if (!CompressedInfo) + { + UE_LOG(LogAudio, Error, TEXT("Failed to create new FVorbisAudioInfo for SoundWave %s: out of memory."), *SoundWave->GetName()); + return nullptr; + } + return CompressedInfo; + } + else + { + return nullptr; + } #else - return NULL; + return nullptr; #endif } diff --git a/Engine/Source/Runtime/Mac/CoreAudio/Private/CoreAudioSource.cpp b/Engine/Source/Runtime/Mac/CoreAudio/Private/CoreAudioSource.cpp index a763d2410796..e15b7fb44a49 100644 --- a/Engine/Source/Runtime/Mac/CoreAudio/Private/CoreAudioSource.cpp +++ b/Engine/Source/Runtime/Mac/CoreAudio/Private/CoreAudioSource.cpp @@ -34,8 +34,8 @@ */ FCoreAudioSoundSource::FCoreAudioSoundSource( FAudioDevice* InAudioDevice ) : FSoundSource( InAudioDevice ), - Buffer( NULL ), - CoreAudioConverter( NULL ), + CoreAudioBuffer(nullptr), + CoreAudioConverter(nullptr), RealtimeAsyncTask(nullptr), bStreamedSound( false ), bBuffersToFlush( false ), @@ -99,10 +99,13 @@ void FCoreAudioSoundSource::FreeResources( void ) } // Buffers without a valid resource ID are transient and need to be deleted. - if( Buffer ) + if( CoreAudioBuffer ) { - check( Buffer->ResourceID == 0 ); - delete Buffer; + check( CoreAudioBuffer->ResourceID == 0 ); + delete CoreAudioBuffer; + CoreAudioBuffer = nullptr; + + // Null out the base-class ptr Buffer = nullptr; } @@ -124,8 +127,8 @@ void FCoreAudioSoundSource::SubmitPCMBuffers( void ) NumActiveBuffers=1; BufferInUse=0; - CoreAudioBuffers[0].AudioData = Buffer->PCMData; - CoreAudioBuffers[0].AudioDataSize = Buffer->PCMDataSize; + CoreAudioBuffers[0].AudioData = CoreAudioBuffer->PCMData; + CoreAudioBuffers[0].AudioDataSize = CoreAudioBuffer->PCMDataSize; } bool FCoreAudioSoundSource::ReadMorePCMData( const int32 BufferIndex, EDataReadMode DataReadMode ) @@ -135,7 +138,7 @@ bool FCoreAudioSoundSource::ReadMorePCMData( const int32 BufferIndex, EDataReadM USoundWave* WaveData = WaveInstance->WaveData; if( WaveData && WaveData->bProcedural ) { - const int32 MaxSamples = ( MONO_PCM_BUFFER_SIZE * Buffer->NumChannels ) / sizeof( int16 ); + const int32 MaxSamples = ( MONO_PCM_BUFFER_SIZE * CoreAudioBuffer->NumChannels ) / sizeof( int16 ); if (DataReadMode == EDataReadMode::Synchronous || WaveData->bCanProcessAsync == false) { @@ -161,11 +164,11 @@ bool FCoreAudioSoundSource::ReadMorePCMData( const int32 BufferIndex, EDataReadM if (DataReadMode == EDataReadMode::Synchronous) { ++NumActiveBuffers; - return Buffer->ReadCompressedData( CoreAudioBuffers[BufferIndex].AudioData, WaveInstance->LoopingMode != LOOP_Never ); + return CoreAudioBuffer->ReadCompressedData( CoreAudioBuffers[BufferIndex].AudioData, WaveInstance->LoopingMode != LOOP_Never ); } else { - RealtimeAsyncTask = new FAsyncRealtimeAudioTask(Buffer, (uint8*)CoreAudioBuffers[BufferIndex].AudioData, WaveInstance->LoopingMode != LOOP_Never, DataReadMode == EDataReadMode::AsynchronousSkipFirstFrame); + RealtimeAsyncTask = new FAsyncRealtimeAudioTask(CoreAudioBuffer, (uint8*)CoreAudioBuffers[BufferIndex].AudioData, WaveInstance->LoopingMode != LOOP_Never, DataReadMode == EDataReadMode::AsynchronousSkipFirstFrame); RealtimeAsyncTask->StartBackgroundTask(); return false; } @@ -183,7 +186,7 @@ void FCoreAudioSoundSource::SubmitPCMRTBuffers( void ) bStreamedSound = true; - const uint32 BufferSize = MONO_PCM_BUFFER_SIZE * Buffer->NumChannels; + const uint32 BufferSize = MONO_PCM_BUFFER_SIZE * CoreAudioBuffer->NumChannels; // Set up double buffer area to decompress to CoreAudioBuffers[0].AudioData = (uint8*)FMemory::Malloc(BufferSize); @@ -215,7 +218,7 @@ void FCoreAudioSoundSource::SubmitPCMRTBuffers( void ) // Start the async population of the next buffer EDataReadMode DataReadMode = EDataReadMode::Asynchronous; - if (Buffer->SoundFormat == ESoundFormat::SoundFormat_Streaming) + if (CoreAudioBuffer->SoundFormat == ESoundFormat::SoundFormat_Streaming) { DataReadMode = EDataReadMode::Synchronous; } @@ -240,14 +243,14 @@ bool FCoreAudioSoundSource::Init( FWaveInstance* InWaveInstance ) if (InWaveInstance->OutputTarget != EAudioOutputTarget::Controller) { // Find matching buffer. - Buffer = FCoreAudioSoundBuffer::Init( AudioDevice, InWaveInstance->WaveData, InWaveInstance->StartTime > 0.f ); - - // Buffer failed to be created, or there was an error with the compressed data - if( Buffer && Buffer->NumChannels > 0 ) + CoreAudioBuffer = FCoreAudioSoundBuffer::Init( AudioDevice, InWaveInstance->WaveData, InWaveInstance->StartTime > 0.f ); + Buffer = nullptr; + + if( CoreAudioBuffer && CoreAudioBuffer->NumChannels > 0 ) { SCOPE_CYCLE_COUNTER( STAT_AudioSourceInitTime ); - if (Buffer->NumChannels < 3) + if (CoreAudioBuffer->NumChannels < 3) { MixerInputNumber = AudioDevice->GetFreeMixer3DInput(); } @@ -268,6 +271,7 @@ bool FCoreAudioSoundSource::Init( FWaveInstance* InWaveInstance ) } + Buffer = CoreAudioBuffer; WaveInstance = InWaveInstance; // Set whether to apply reverb @@ -275,11 +279,11 @@ bool FCoreAudioSoundSource::Init( FWaveInstance* InWaveInstance ) if (WaveInstance->StartTime > 0.f) { - Buffer->Seek(WaveInstance->StartTime); + CoreAudioBuffer->Seek(WaveInstance->StartTime); } // Submit audio buffers - switch( Buffer->SoundFormat ) + switch( CoreAudioBuffer->SoundFormat ) { case SoundFormat_PCM: case SoundFormat_PCMPreview: @@ -328,7 +332,7 @@ void FCoreAudioSoundSource::Update( void ) Volume *= AudioDevice->GetPlatformAudioHeadroom(); - if( Buffer->NumChannels < 3 ) + if( CoreAudioBuffer->NumChannels < 3 ) { float Azimuth = 0.0f; float Elevation = 0.0f; @@ -420,8 +424,10 @@ void FCoreAudioSoundSource::Play( void ) */ void FCoreAudioSoundSource::Stop( void ) { + FScopeLock Lock(&CriticalSection); + if( WaveInstance ) - { + { if( Playing && AudioChannel ) { DetachFromAUGraph(); @@ -432,7 +438,7 @@ void FCoreAudioSoundSource::Stop( void ) Paused = false; Playing = false; - Buffer = NULL; + CoreAudioBuffer = nullptr; bBuffersToFlush = false; } @@ -480,6 +486,8 @@ void FCoreAudioSoundSource::HandleRealTimeSourceData(bool bLooped) */ void FCoreAudioSoundSource::HandleRealTimeSource(bool bBlockForData) { + FScopeLock Lock(&CriticalSection); + const bool bGetMoreData = bBlockForData || (RealtimeAsyncTask == nullptr); int32 BufferIndex = (BufferInUse + NumActiveBuffers) % 3; if (RealtimeAsyncTask) @@ -526,7 +534,7 @@ void FCoreAudioSoundSource::HandleRealTimeSource(bool bBlockForData) if (bGetMoreData) { // Get the next bit of streaming data - const bool bLooped = ReadMorePCMData(BufferIndex, (Buffer->SoundFormat == ESoundFormat::SoundFormat_Streaming ? EDataReadMode::Synchronous : EDataReadMode::Asynchronous)); + const bool bLooped = ReadMorePCMData(BufferIndex, (CoreAudioBuffer->SoundFormat == ESoundFormat::SoundFormat_Streaming ? EDataReadMode::Synchronous : EDataReadMode::Asynchronous)); if (RealtimeAsyncTask == nullptr) { @@ -551,6 +559,8 @@ bool FCoreAudioSoundSource::IsFinished( void ) if( WaveInstance ) { + FScopeLock Lock(&CriticalSection); + // If not rendering, we're either at the end of a sound, or starved // and we are expecting the sound to be finishing if (NumActiveBuffers == 0 && (bBuffersToFlush || !bStreamedSound)) @@ -798,12 +808,12 @@ bool FCoreAudioSoundSource::AttachToAUGraph() AUNode FinalNode = -1; AudioStreamBasicDescription* StreamFormat = NULL; - if (Buffer->NumChannels < 3) + if (CoreAudioBuffer->NumChannels < 3) { - ErrorStatus = AudioConverterNew( &Buffer->PCMFormat, &AudioDevice->Mixer3DFormat, &CoreAudioConverter ); + ErrorStatus = AudioConverterNew( &CoreAudioBuffer->PCMFormat, &AudioDevice->Mixer3DFormat, &CoreAudioConverter ); FinalNode = AudioDevice->GetMixer3DNode(); - uint32 SpatialSetting = ( Buffer->NumChannels == 1 ) ? kSpatializationAlgorithm_SoundField : kSpatializationAlgorithm_StereoPassThrough; + uint32 SpatialSetting = ( CoreAudioBuffer->NumChannels == 1 ) ? kSpatializationAlgorithm_SoundField : kSpatializationAlgorithm_StereoPassThrough; ErrorStatus = AudioUnitSetProperty( AudioDevice->GetMixer3DUnit(), kAudioUnitProperty_SpatializationAlgorithm, kAudioUnitScope_Input, MixerInputNumber, &SpatialSetting, sizeof( SpatialSetting ) ); check(ErrorStatus == noErr); @@ -817,11 +827,11 @@ bool FCoreAudioSoundSource::AttachToAUGraph() FinalNode = AudioDevice->GetMatrixMixerNode(); StreamFormat = &AudioDevice->MatrixMixerInputFormat; - ErrorStatus = AudioConverterNew( &Buffer->PCMFormat, &AudioDevice->MatrixMixerInputFormat, &CoreAudioConverter ); + ErrorStatus = AudioConverterNew( &CoreAudioBuffer->PCMFormat, &AudioDevice->MatrixMixerInputFormat, &CoreAudioConverter ); check(ErrorStatus == noErr); - bool bIs6ChannelOGG = Buffer->NumChannels == 6 - && ((Buffer->DecompressionState && Buffer->DecompressionState->UsesVorbisChannelOrdering()) + bool bIs6ChannelOGG = CoreAudioBuffer->NumChannels == 6 + && ((CoreAudioBuffer->DecompressionState && CoreAudioBuffer->DecompressionState->UsesVorbisChannelOrdering()) || WaveInstance->WaveData->bDecompressedFromOgg); AudioDevice->SetupMatrixMixerInput( MixerInputNumber, bIs6ChannelOGG ); @@ -937,7 +947,7 @@ bool FCoreAudioSoundSource::DetachFromAUGraph() if( AudioChannel ) { - if( Buffer->NumChannels < 3 ) + if( CoreAudioBuffer->NumChannels < 3 ) { SAFE_CA_CALL( AUGraphDisconnectNodeInput( AudioDevice->GetAudioUnitGraph(), AudioDevice->GetMixer3DNode(), MixerInputNumber ) ); AudioDevice->SetFreeMixer3DInput( MixerInputNumber ); @@ -1005,6 +1015,7 @@ OSStatus FCoreAudioSoundSource::CoreAudioRenderCallback( void *InRefCon, AudioUn { OSStatus Status = noErr; FCoreAudioSoundSource *Source = ( FCoreAudioSoundSource *)InRefCon; + FScopeLock Lock(&Source->CriticalSection); uint32 DataByteSize = InNumberFrames * sizeof( Float32 ); uint32 PacketsRequested = InNumberFrames; @@ -1020,7 +1031,7 @@ OSStatus FCoreAudioSoundSource::CoreAudioRenderCallback( void *InRefCon, AudioUn AudioBufferList *LocalBufferList = &LocalBuffers.BufferList; LocalBufferList->mNumberBuffers = IOData->mNumberBuffers; - if( Source->Buffer && Source->Playing ) + if( Source->CoreAudioBuffer && Source->Playing ) { while( PacketsObtained < PacketsRequested ) { @@ -1069,19 +1080,20 @@ OSStatus FCoreAudioSoundSource::CoreAudioConvertCallback( AudioConverterRef Conv AudioStreamPacketDescription **OutPacketDescription, void *InUserData ) { FCoreAudioSoundSource *Source = ( FCoreAudioSoundSource *)InUserData; + FScopeLock Lock(&Source->CriticalSection); uint8 *Buffer = Source->CoreAudioBuffers[Source->BufferInUse].AudioData; int32 BufferSize = Source->CoreAudioBuffers[Source->BufferInUse].AudioDataSize; int32 ReadCursor = Source->CoreAudioBuffers[Source->BufferInUse].ReadCursor; - int32 PacketsAvailable = Source->Buffer ? ( BufferSize - ReadCursor ) / Source->Buffer->PCMFormat.mBytesPerPacket : 0; + int32 PacketsAvailable = Source->CoreAudioBuffer ? ( BufferSize - ReadCursor ) / Source->CoreAudioBuffer->PCMFormat.mBytesPerPacket : 0; if( PacketsAvailable < *IONumberDataPackets ) { *IONumberDataPackets = PacketsAvailable; } IOData->mBuffers[0].mData = *IONumberDataPackets ? Buffer + ReadCursor : NULL; - IOData->mBuffers[0].mDataByteSize = Source->Buffer ? *IONumberDataPackets * Source->Buffer->PCMFormat.mBytesPerPacket : 0; + IOData->mBuffers[0].mDataByteSize = Source->CoreAudioBuffer ? *IONumberDataPackets * Source->CoreAudioBuffer->PCMFormat.mBytesPerPacket : 0; ReadCursor += IOData->mBuffers[0].mDataByteSize; Source->CoreAudioBuffers[Source->BufferInUse].ReadCursor = ReadCursor; diff --git a/Engine/Source/Runtime/Mac/CoreAudio/Public/CoreAudioDevice.h b/Engine/Source/Runtime/Mac/CoreAudio/Public/CoreAudioDevice.h index 316069e4debf..f3f8b4cf7d40 100644 --- a/Engine/Source/Runtime/Mac/CoreAudio/Public/CoreAudioDevice.h +++ b/Engine/Source/Runtime/Mac/CoreAudio/Public/CoreAudioDevice.h @@ -43,7 +43,7 @@ enum ESoundFormat SoundFormat_Streaming }; -struct CoreAudioBuffer +struct FCoreAudioBuffer { uint8 *AudioData; int32 AudioDataSize; @@ -153,6 +153,10 @@ public: */ int32 GetSize( void ); + // These are used by the streaming engine to manage loading/unloading of chunks + virtual int32 GetCurrentChunkIndex() const override; + virtual int32 GetCurrentChunkOffset() const override; + /** Audio device this buffer is attached to */ FAudioDevice* AudioDevice; @@ -278,7 +282,7 @@ protected: FCoreAudioEffectsManager* Effects; /** Cached sound buffer associated with currently bound wave instance. */ - FCoreAudioSoundBuffer* Buffer; + FCoreAudioSoundBuffer* CoreAudioBuffer; AudioConverterRef CoreAudioConverter; @@ -288,7 +292,7 @@ protected: /** Which sound buffer should be written to next - used for double buffering. */ bool bStreamedSound; /** A pair of sound buffers to allow notification when a sound loops. */ - CoreAudioBuffer CoreAudioBuffers[3]; + FCoreAudioBuffer CoreAudioBuffers[3]; /** Set when we wish to let the buffers play themselves out */ bool bBuffersToFlush; @@ -317,6 +321,8 @@ protected: int32 MixerInputNumber; + FCriticalSection CriticalSection; + private: void FreeResources(); @@ -377,6 +383,12 @@ class FCoreAudioDevice : public FAudioDevice virtual FName GetRuntimeFormat(USoundWave* SoundWave) override { + static FName NAME_OPUS(TEXT("OPUS")); + + if (SoundWave->IsStreaming()) + { + return NAME_OPUS; + } static FName NAME_OGG(TEXT("OGG")); return NAME_OGG; } diff --git a/Engine/Source/Runtime/Media/Public/IMediaTextureSink.h b/Engine/Source/Runtime/Media/Public/IMediaTextureSink.h index 957e3ab524b6..ac289e6f8529 100644 --- a/Engine/Source/Runtime/Media/Public/IMediaTextureSink.h +++ b/Engine/Source/Runtime/Media/Public/IMediaTextureSink.h @@ -290,5 +290,5 @@ public: public: /** Virtual destructor. */ - ~IMediaTextureSink() { } + virtual ~IMediaTextureSink() { } }; diff --git a/Engine/Source/Runtime/Media/Public/IMediaTracks.h b/Engine/Source/Runtime/Media/Public/IMediaTracks.h index 9cf638db89e9..d0e27de29ed6 100644 --- a/Engine/Source/Runtime/Media/Public/IMediaTracks.h +++ b/Engine/Source/Runtime/Media/Public/IMediaTracks.h @@ -166,7 +166,7 @@ public: return 0.0f; } - return Dimensions.X / Dimensions.Y; + return (float)(Dimensions.X) / Dimensions.Y; } public: diff --git a/Engine/Source/Runtime/MediaAssets/Private/Assets/MediaTexture.cpp b/Engine/Source/Runtime/MediaAssets/Private/Assets/MediaTexture.cpp index d9b172947d4d..1d7960bad4dc 100644 --- a/Engine/Source/Runtime/MediaAssets/Private/Assets/MediaTexture.cpp +++ b/Engine/Source/Runtime/MediaAssets/Private/Assets/MediaTexture.cpp @@ -41,7 +41,7 @@ float UMediaTexture::GetAspectRatio() const return 0.0f; } - return Dimensions.X / Dimensions.Y; + return (float)(Dimensions.X) / Dimensions.Y; } diff --git a/Engine/Source/Runtime/MediaAssets/Private/Misc/MediaTextureResource.h b/Engine/Source/Runtime/MediaAssets/Private/Misc/MediaTextureResource.h index 0b497744dee2..a75ab2c50d25 100644 --- a/Engine/Source/Runtime/MediaAssets/Private/Misc/MediaTextureResource.h +++ b/Engine/Source/Runtime/MediaAssets/Private/Misc/MediaTextureResource.h @@ -192,6 +192,20 @@ private: /** The media texture that owns this resource. */ UMediaTexture& Owner; + /** + * Texture resources for buffered mode or pixel conversions. + * + * In Buffered mode, all three resources are used for triple buffering. + * If no pixel format conversion is required, the triple buffer's Read + * buffer is used as the output resource. Otherwise the Read buffer is + * converted into a separate output resource. + * + * In Unbuffered mode when pixel format conversion is required, only the + * third buffer (index = 2) is used. Otherwise data is written directly + * to a separate output resource. + */ + FResource BufferResources[3]; + /** Triple-buffer for texture resources. */ TTripleBuffer TripleBuffer; @@ -213,20 +227,6 @@ private: /** Number of bytes per row in buffer resources. */ SIZE_T BufferPitch; - /** - * Texture resources for buffered mode or pixel conversions. - * - * In Buffered mode, all three resources are used for triple buffering. - * If no pixel format conversion is required, the triple buffer's Read - * buffer is used as the output resource. Otherwise the Read buffer is - * converted into a separate output resource. - * - * In Unbuffered mode when pixel format conversion is required, only the - * third buffer (index = 2) is used. Otherwise data is written directly - * to a separate output resource. - */ - FResource BufferResources[3]; - /** Total size of this resource.*/ SIZE_T CachedResourceSizeBytes; diff --git a/Engine/Source/Runtime/Messaging/Public/Helpers/MessageHandlers.h b/Engine/Source/Runtime/Messaging/Public/Helpers/MessageHandlers.h index aeb41cb8e634..11a1261114a5 100644 --- a/Engine/Source/Runtime/Messaging/Public/Helpers/MessageHandlers.h +++ b/Engine/Source/Runtime/Messaging/Public/Helpers/MessageHandlers.h @@ -97,7 +97,8 @@ public: virtual void HandleMessage(const TSharedRef& Context) override { - if (Context->GetMessageType() == MessageType::StaticStruct()->GetFName()) + UStruct* Struct = MessageType::StaticStruct(); + if (Struct && Context->GetMessageType() == Struct->GetFName()) { (Handler->*Func)(*static_cast(Context->GetMessage()), Context); } diff --git a/Engine/Source/Runtime/Messaging/Public/IMessageTransport.h b/Engine/Source/Runtime/Messaging/Public/IMessageTransport.h index 55f1be1c2487..01ba44184319 100644 --- a/Engine/Source/Runtime/Messaging/Public/IMessageTransport.h +++ b/Engine/Source/Runtime/Messaging/Public/IMessageTransport.h @@ -63,8 +63,8 @@ public: protected: - /** Virtual constructor. */ - ~IMessageTransport() { } + /** Virtual destructor. */ + virtual ~IMessageTransport() { } }; diff --git a/Engine/Source/Runtime/MoviePlayer/Private/DefaultGameMoviePlayer.cpp b/Engine/Source/Runtime/MoviePlayer/Private/DefaultGameMoviePlayer.cpp index f714caaafb85..e60c5518e7d9 100644 --- a/Engine/Source/Runtime/MoviePlayer/Private/DefaultGameMoviePlayer.cpp +++ b/Engine/Source/Runtime/MoviePlayer/Private/DefaultGameMoviePlayer.cpp @@ -383,7 +383,10 @@ void FDefaultGameMoviePlayer::WaitForMovieToFinish() } // Continue to wait until the user calls finish (if enabled) or when loading completes or the minimum enforced time (if any) has been reached. - while ( (bWaitForManualStop && !bUserCalledFinish) || (!bUserCalledFinish && ((!bEnforceMinimumTime && !IsMovieStreamingFinished() && !bAutoCompleteWhenLoadingCompletes) || (bEnforceMinimumTime && (FPlatformTime::Seconds() - LastPlayTime) < LoadingScreenAttributes.MinimumLoadingScreenDisplayTime)))) + while ( + (bWaitForManualStop && !bUserCalledFinish) + || (!bUserCalledFinish && !bEnforceMinimumTime && !IsMovieStreamingFinished() && !bAutoCompleteWhenLoadingCompletes) + || (bEnforceMinimumTime && (FPlatformTime::Seconds() - LastPlayTime) < LoadingScreenAttributes.MinimumLoadingScreenDisplayTime)) { // If we are in a loading loop, and this is the last movie in the playlist.. assume you can break out. if (MovieStreamer.IsValid() && LoadingScreenAttributes.PlaybackType == MT_LoadingLoop && MovieStreamer->IsLastMovieInPlaylist()) @@ -473,8 +476,8 @@ void FDefaultGameMoviePlayer::WaitForMovieToFinish() { GameEngine->SwitchGameWindowToUseGameViewport(); } - } + } bool FDefaultGameMoviePlayer::IsLoadingFinished() const diff --git a/Engine/Source/Runtime/MovieScene/Private/Compilation/MovieSceneEvaluationTemplateGenerator.cpp b/Engine/Source/Runtime/MovieScene/Private/Compilation/MovieSceneEvaluationTemplateGenerator.cpp index 2631dc446546..e955fb97ef46 100644 --- a/Engine/Source/Runtime/MovieScene/Private/Compilation/MovieSceneEvaluationTemplateGenerator.cpp +++ b/Engine/Source/Runtime/MovieScene/Private/Compilation/MovieSceneEvaluationTemplateGenerator.cpp @@ -110,37 +110,32 @@ FMovieSceneSequenceTransform FMovieSceneEvaluationTemplateGenerator::GetSequence return ensure(Data) ? Data->RootToSequenceTransform : FMovieSceneSequenceTransform(); } -FMovieSceneSequenceID FMovieSceneEvaluationTemplateGenerator::GenerateSequenceID(FMovieSceneSubSequenceData SequenceData, FMovieSceneSequenceIDRef ParentID) +void FMovieSceneEvaluationTemplateGenerator::AddSubSequence(FMovieSceneSubSequenceData SequenceData, FMovieSceneSequenceIDRef ParentID, FMovieSceneSequenceID SequenceID) { FMovieSceneSequenceHierarchyNode* ParentNode = Template.Hierarchy.FindNode(ParentID); checkf(ParentNode, TEXT("Cannot generate a sequence ID for a ParentID that doesn't yet exist")); - FMovieSceneSequenceID ThisID = SequenceData.DeterministicSequenceID; - + check(SequenceID.IsValid()); + +#if WITH_EDITORONLY_DATA if (const FMovieSceneSubSequenceData* ParentSubSequenceData = Template.Hierarchy.FindSubData(ParentID)) { -#if WITH_EDITORONLY_DATA // Clamp this sequence's valid play range by its parent's valid play range TRange ParentPlayRangeChildSpace = ParentSubSequenceData->ValidPlayRange * (SequenceData.RootToSequenceTransform * ParentSubSequenceData->RootToSequenceTransform.Inverse()); SequenceData.ValidPlayRange = TRange::Intersection(ParentPlayRangeChildSpace, SequenceData.ValidPlayRange); -#endif - // Determine its ID from its parent's - ThisID = SequenceData.DeterministicSequenceID.AccumulateParentID(ParentSubSequenceData->DeterministicSequenceID); } +#endif // Ensure we have a unique ID. This should never happen in reality. - while(!ensureMsgf(!Template.Hierarchy.FindNode(ThisID), TEXT("CRC collision on deterministic hashes. Manually hashing a random new one."))) + while(!ensureMsgf(!Template.Hierarchy.FindNode(SequenceID), TEXT("CRC collision on deterministic hashes. Manually hashing a random new one."))) { - ThisID = ThisID.AccumulateParentID(ThisID); + SequenceID = SequenceID.AccumulateParentID(SequenceID); } - SequenceData.DeterministicSequenceID = ThisID; - - ParentNode->Children.Add(ThisID); - Template.Hierarchy.Add(SequenceData, ThisID, ParentID); - - return ThisID; + Template.Hierarchy.Add(SequenceData, SequenceID, ParentID); } + + void FMovieSceneEvaluationTemplateGenerator::Generate(FMovieSceneTrackCompilationParams InParams) { Template.Hierarchy = FMovieSceneSequenceHierarchy(); diff --git a/Engine/Source/Runtime/MovieScene/Private/Compilation/MovieSceneSegmentCompiler.cpp b/Engine/Source/Runtime/MovieScene/Private/Compilation/MovieSceneSegmentCompiler.cpp index 83bfecc1c682..c1e946430703 100644 --- a/Engine/Source/Runtime/MovieScene/Private/Compilation/MovieSceneSegmentCompiler.cpp +++ b/Engine/Source/Runtime/MovieScene/Private/Compilation/MovieSceneSegmentCompiler.cpp @@ -78,8 +78,10 @@ bool FMovieSceneSegmentCompilerRules::InsertSegment(TArray& return true; } -TArray FMovieSceneSegmentCompiler::Compile(const TArrayView& Data, const FMovieSceneSegmentCompilerRules* Rules) +TArray FMovieSceneSegmentCompiler::Compile(TArrayView Data, const FMovieSceneSegmentCompilerRules* Rules, EMovieSceneSegmentIndexSpace InIndexSpace) { + SourceData = Data; + IndexSpace = InIndexSpace; OverlappingSections.Reset(16); OverlappingRefCounts.Reset(16); LowerBounds.Reset(Data.Num()); @@ -95,9 +97,14 @@ TArray FMovieSceneSegmentCompiler::Compile(const TArrayView< const FMovieSceneSectionData& Section = Data[Index]; if (!Section.Bounds.IsEmpty()) { - ensure(Section.EvalData.ImplIndex != -1); - LowerBounds.Add(FBound(Section.EvalData, Section.Bounds.GetLowerBound())); - UpperBounds.Add(FBound(Section.EvalData, Section.Bounds.GetUpperBound())); + FSectionEvaluationData EvalData = Section.EvalData; + + // Regardless of what IndexSpace was specified, we always run the compiler with the source data index + // then translate afterwards so we have a consistent way of writing compiler rules + EvalData.ImplIndex = Index; + + LowerBounds.Add(FBound(EvalData, Section.Bounds.GetLowerBound())); + UpperBounds.Add(FBound(EvalData, Section.Bounds.GetUpperBound())); } } @@ -126,8 +133,8 @@ TArray FMovieSceneSegmentCompiler::Compile(const TArrayView< // Add the currently overlapping sections for any sections starting at exactly this time do { - // Reference count how many times this section is overlapping the current time. This is to support multiple references to the same section. - const int32 OverlapIndex = OverlappingSections.IndexOfByKey(LowerBounds[LowerReadIndex].EvalData); + // Reference count how many times this section is overlapping the current time with the same flags. This is to support multiple references to the same section. + const int32 OverlapIndex = FindOverlappingIndex(LowerBounds[LowerReadIndex].EvalData); if (OverlapIndex == INDEX_NONE) { OverlappingSections.Add(LowerBounds[LowerReadIndex].EvalData); @@ -155,9 +162,52 @@ TArray FMovieSceneSegmentCompiler::Compile(const TArrayView< Rules->ProcessSegments(CompiledSegments, Data); } + if (IndexSpace == EMovieSceneSegmentIndexSpace::ActualImplIndex) + { + for (int32 Index = 0; Index < CompiledSegments.Num();) + { + FMovieSceneSegment& CompiledSegment = CompiledSegments[Index]; + // Assign what are currently source data indices to the actual implemntation index specified in the source data + for (FSectionEvaluationData& EvalData : CompiledSegment.Impls) + { + EvalData.ImplIndex = Data[EvalData.ImplIndex].EvalData.ImplIndex; + } + + if (Index > 0 && (CompiledSegment.Impls.Num() != 0 || (Rules && Rules->AllowEmptySegments()))) + { + FMovieSceneSegment& PreviousSegment = CompiledSegments[Index - 1]; + + // If this is the same as the previous segment, and it ajoins the previous segment's range, just increase the range of the previous segment + if (PreviousSegment.Range.Adjoins(CompiledSegment.Range) && PreviousSegment.Impls == CompiledSegment.Impls) + { + PreviousSegment.Range = FFloatRange::Hull(PreviousSegment.Range, CompiledSegment.Range); + + CompiledSegments.RemoveAtSwap(Index, 1, false); + // continue immediately to avoid incrementing the index + continue; + } + } + + ++Index; + } + } + return MoveTemp(CompiledSegments); } +int32 FMovieSceneSegmentCompiler::FindOverlappingIndex(FSectionEvaluationData In) const +{ + In.ImplIndex = SourceData[In.ImplIndex].EvalData.ImplIndex; + + return OverlappingSections.IndexOfByPredicate( + [this, In](FSectionEvaluationData InEvalData) + { + InEvalData.ImplIndex = SourceData[InEvalData.ImplIndex].EvalData.ImplIndex; + return InEvalData == In; + } + ); +} + void FMovieSceneSegmentCompiler::CloseCompletedSegments() { if (!CompiledSegments.Num()) @@ -202,7 +252,7 @@ void FMovieSceneSegmentCompiler::CloseCompletedSegments() // Remove all sections that finish on this time while (UpperReadIndex < UpperBounds.Num() && UpperBounds[UpperReadIndex].Bound == ClosingBound) { - int32 OverlappingIndex = OverlappingSections.IndexOfByKey(UpperBounds[UpperReadIndex].EvalData); + const int32 OverlappingIndex = FindOverlappingIndex(UpperBounds[UpperReadIndex].EvalData); if (ensure(OverlappingIndex != INDEX_NONE)) { if (--OverlappingRefCounts[OverlappingIndex] == 0) @@ -225,7 +275,6 @@ void FMovieSceneSegmentCompiler::CloseCompletedSegments() } } - FMovieSceneTrackCompiler::FRows::FRows(const TArray& Sections, const FMovieSceneSegmentCompilerRules* CompileRules) { for (int32 Index = 0; Index < Sections.Num(); ++Index) @@ -244,10 +293,10 @@ FMovieSceneTrackCompiler::FRows::FRows(const TArray& Sectio const TRange Range = Section->IsInfinite() ? TRange::All() : Section->GetRange(); - FSectionEvaluationData EvalData(Rows[RowIndex].Sections.Num()); + FSectionEvaluationData EvalData(Index); Rows[RowIndex].Sections.Add( - FMovieSceneSectionRowData(Index, Range, EvalData, Section->GetOverlapPriority()) + FMovieSceneSectionData(Range, EvalData, Section->GetOverlapPriority()) ); if (!Range.GetLowerBound().IsOpen() && Section->GetPreRollTime() > 0) @@ -255,7 +304,7 @@ FMovieSceneTrackCompiler::FRows::FRows(const TArray& Sectio EvalData.Flags = ESectionEvaluationFlags::PreRoll; TRange PreRollRange(Range.GetLowerBoundValue() - Section->GetPreRollTime(), TRangeBound::FlipInclusion(Range.GetLowerBoundValue())); Rows[RowIndex].Sections.Add( - FMovieSceneSectionRowData(Index, PreRollRange, EvalData, Section->GetOverlapPriority()) + FMovieSceneSectionData(PreRollRange, EvalData, Section->GetOverlapPriority()) ); } if (!Range.GetUpperBound().IsOpen() && Section->GetPostRollTime() > 0) @@ -263,7 +312,7 @@ FMovieSceneTrackCompiler::FRows::FRows(const TArray& Sectio EvalData.Flags = ESectionEvaluationFlags::PostRoll; TRange PostRollRange(TRangeBound::FlipInclusion(Range.GetUpperBoundValue()), Range.GetUpperBoundValue() + Section->GetPostRollTime()); Rows[RowIndex].Sections.Add( - FMovieSceneSectionRowData(Index, PostRollRange, EvalData, Section->GetOverlapPriority()) + FMovieSceneSectionData(PostRollRange, EvalData, Section->GetOverlapPriority()) ); } } @@ -280,7 +329,7 @@ FMovieSceneTrackCompiler::FRows::FRows(const TArray& Sectio } } -FMovieSceneTrackEvaluationField FMovieSceneTrackCompiler::Compile(const TArrayView& Rows, const FMovieSceneSegmentCompilerRules* Rules) +FMovieSceneTrackEvaluationField FMovieSceneTrackCompiler::Compile(TArrayView Rows, const FMovieSceneSegmentCompilerRules* Rules) { FMovieSceneTrackEvaluationField Result; @@ -291,7 +340,6 @@ FMovieSceneTrackEvaluationField FMovieSceneTrackCompiler::Compile(const TArrayVi // This allows us to do blending on a row basis, without considering individual row blending rules // - TArray SourceTrackDataToActualIndex; TArray TrackCompileData; // Compile each row @@ -308,19 +356,15 @@ FMovieSceneTrackEvaluationField FMovieSceneTrackCompiler::Compile(const TArrayVi // Compile this row into segments TArray RowSegments = Compiler.Compile( TArray(Row.Sections), - Row.CompileRules); + Row.CompileRules, + EMovieSceneSegmentIndexSpace::ActualImplIndex); const int32 Priority = Rows.Num() - RowIndex; for (FMovieSceneSegment& Segment : RowSegments) { + // Add each implementation in this segment as a separate entry in the source data to ensure that the correct evaluation flags are compiled for (FSectionEvaluationData& EvalData : Segment.Impls) { - // Add the real section index to a LUT that corresponds to the source track compile data index - // The is the index that's actually used at runtime - SourceTrackDataToActualIndex.Add(Row.Sections[EvalData.ImplIndex].ActualSectionIndex); - - // The track compilation data requires impl indices into the source data (TrackCompileData) for the compiler rules' consideration - EvalData.ImplIndex = TrackCompileData.Num(); TrackCompileData.Add(FMovieSceneSectionData(Segment.Range, EvalData, Priority)); } } @@ -328,7 +372,7 @@ FMovieSceneTrackEvaluationField FMovieSceneTrackCompiler::Compile(const TArrayVi // Boil down each row into a single, blended field FMovieSceneSegmentCompiler Compiler; - TArray TrackSegments = Compiler.Compile(TrackCompileData, nullptr); + TArray TrackSegments = Compiler.Compile(TrackCompileData, nullptr, EMovieSceneSegmentIndexSpace::SourceDataIndex); // At this point, ImplIndex members correspond to the source data array (TrackCompileData) if (Rules) @@ -343,7 +387,7 @@ FMovieSceneTrackEvaluationField FMovieSceneTrackCompiler::Compile(const TArrayVi for (FSectionEvaluationData& SectionEvalData : Segment.Impls) { // Remap the index to the actual section index - SectionEvalData.ImplIndex = SourceTrackDataToActualIndex[SectionEvalData.ImplIndex]; + SectionEvalData.ImplIndex = TrackCompileData[SectionEvalData.ImplIndex].EvalData.ImplIndex; } if (Segment.Impls.Num() != 0 || (Rules && Rules->AllowEmptySegments())) diff --git a/Engine/Source/Runtime/MovieScene/Private/Evaluation/MovieSceneEvaluationTemplate.cpp b/Engine/Source/Runtime/MovieScene/Private/Evaluation/MovieSceneEvaluationTemplate.cpp index 3f520a91e7e7..099a250d2722 100644 --- a/Engine/Source/Runtime/MovieScene/Private/Evaluation/MovieSceneEvaluationTemplate.cpp +++ b/Engine/Source/Runtime/MovieScene/Private/Evaluation/MovieSceneEvaluationTemplate.cpp @@ -101,7 +101,7 @@ void FMovieSceneEvaluationTemplate::PostSerialize(const FArchive& Ar) { for (auto& Pair : Tracks) { - if (Ledger.LastTrackIdentifier == FMovieSceneTrackIdentifier::Invalid() || Ledger.LastTrackIdentifier.Value < Pair.Key) + if (TemplateLedger.LastTrackIdentifier == FMovieSceneTrackIdentifier::Invalid() || TemplateLedger.LastTrackIdentifier.Value < Pair.Key) { // Reset previously serialized, invalid data ResetGeneratedData(); @@ -113,8 +113,8 @@ void FMovieSceneEvaluationTemplate::PostSerialize(const FArchive& Ar) void FMovieSceneEvaluationTemplate::ResetGeneratedData() { - Ledger.TrackSignatureToTrackIdentifier.Reset(); - Ledger.TrackReferenceCounts.Reset(); + TemplateLedger.TrackSignatureToTrackIdentifier.Reset(); + TemplateLedger.TrackReferenceCounts.Reset(); Tracks.Reset(); StaleTracks.Reset(); @@ -125,20 +125,20 @@ void FMovieSceneEvaluationTemplate::ResetGeneratedData() FMovieSceneTrackIdentifier FMovieSceneEvaluationTemplate::AddTrack(const FGuid& InSignature, FMovieSceneEvaluationTrack&& InTrack) { - FMovieSceneTrackIdentifier NewIdentifier = ++Ledger.LastTrackIdentifier; + FMovieSceneTrackIdentifier NewIdentifier = ++TemplateLedger.LastTrackIdentifier; InTrack.SetupOverrides(); Tracks.Add(NewIdentifier.Value, MoveTemp(InTrack)); - Ledger.AddTrack(InSignature, NewIdentifier); + TemplateLedger.AddTrack(InSignature, NewIdentifier); return NewIdentifier; } void FMovieSceneEvaluationTemplate::RemoveTrack(const FGuid& InSignature) { - for (FMovieSceneTrackIdentifier TrackIdentifier : Ledger.FindTracks(InSignature)) + for (FMovieSceneTrackIdentifier TrackIdentifier : TemplateLedger.FindTracks(InSignature)) { - int32* RefCount = Ledger.TrackReferenceCounts.Find(TrackIdentifier); + int32* RefCount = TemplateLedger.TrackReferenceCounts.Find(TrackIdentifier); if (ensure(RefCount) && --(*RefCount) == 0) { if (bKeepStaleTracks) @@ -150,10 +150,10 @@ void FMovieSceneEvaluationTemplate::RemoveTrack(const FGuid& InSignature) } Tracks.Remove(TrackIdentifier.Value); - Ledger.TrackReferenceCounts.Remove(TrackIdentifier); + TemplateLedger.TrackReferenceCounts.Remove(TrackIdentifier); } } - Ledger.TrackSignatureToTrackIdentifier.Remove(InSignature); + TemplateLedger.TrackSignatureToTrackIdentifier.Remove(InSignature); } const TMap& FMovieSceneEvaluationTemplate::GetTracks() const @@ -172,5 +172,5 @@ TMap& FMovieSceneEvaluat TArrayView FMovieSceneEvaluationTemplate::FindTracks(const FGuid& InSignature) { - return Ledger.FindTracks(InSignature); + return TemplateLedger.FindTracks(InSignature); } diff --git a/Engine/Source/Runtime/MovieScene/Private/Evaluation/MovieSceneEvaluationTemplateInstance.cpp b/Engine/Source/Runtime/MovieScene/Private/Evaluation/MovieSceneEvaluationTemplateInstance.cpp index b9de534237a0..e72fbb51ba0c 100644 --- a/Engine/Source/Runtime/MovieScene/Private/Evaluation/MovieSceneEvaluationTemplateInstance.cpp +++ b/Engine/Source/Runtime/MovieScene/Private/Evaluation/MovieSceneEvaluationTemplateInstance.cpp @@ -12,6 +12,38 @@ DECLARE_CYCLE_STAT(TEXT("Gather Entries For Frame"), MovieSceneEval_GatherEntrie DECLARE_CYCLE_STAT(TEXT("Call Setup() and TearDown()"), MovieSceneEval_CallSetupTearDown, STATGROUP_MovieSceneEval); DECLARE_CYCLE_STAT(TEXT("Evaluate Group"), MovieSceneEval_EvaluateGroup, STATGROUP_MovieSceneEval); +/** Scoped helper class that facilitates the delayed restoration of preanimated state for specific evaluation keys */ +struct FDelayedPreAnimatedStateRestore +{ + FDelayedPreAnimatedStateRestore(IMovieScenePlayer& InPlayer) + : Player(InPlayer) + {} + + ~FDelayedPreAnimatedStateRestore() + { + RestoreNow(); + } + + void Add(FMovieSceneEvaluationKey Key) + { + KeysToRestore.Add(Key); + } + + void RestoreNow() + { + for (FMovieSceneEvaluationKey Key : KeysToRestore) + { + Player.PreAnimatedState.RestorePreAnimatedState(Player, Key); + } + KeysToRestore.Reset(); + } + +private: + /** The movie scene player to restore with */ + IMovieScenePlayer& Player; + /** The array of keys to restore */ + TArray KeysToRestore; +}; FMovieSceneEvaluationTemplateInstance::FMovieSceneEvaluationTemplateInstance(UMovieSceneSequence& InSequence, const FMovieSceneEvaluationTemplate& InTemplate) : Sequence(&InSequence) @@ -175,9 +207,28 @@ void FMovieSceneRootEvaluationTemplateInstance::Evaluate(FMovieSceneContext Cont return; } + // Construct a path that allows us to remap sequence IDs from the local (OverrideRootID) template, to the master template + ReverseOverrideRootPath.Reset(); + { + FMovieSceneSequenceID CurrentSequenceID = OverrideRootID; + const FMovieSceneSequenceHierarchy& Hierarchy = GetHierarchy(); + while (CurrentSequenceID != MovieSceneSequenceID::Root) + { + const FMovieSceneSequenceHierarchyNode* CurrentNode = Hierarchy.FindNode(CurrentSequenceID); + const FMovieSceneSubSequenceData* SubData = Hierarchy.FindSubData(CurrentSequenceID); + if (!ensureAlwaysMsgf(CurrentNode && SubData, TEXT("Malformed sequence hierarchy"))) + { + return; + } + + ReverseOverrideRootPath.Add(SubData->DeterministicSequenceID); + CurrentSequenceID = CurrentNode->ParentID; + } + } + const FMovieSceneEvaluationGroup& Group = Instance->Template->EvaluationField.Groups[FieldIndex]; - GatherEntities(Group, Player, OverrideRootID); + GatherEntities(Group, Player); // Gather the active sequences for this frame, remapping them to the root if necessary ActiveSequencesThisFrame = Instance->Template->EvaluationField.MetaData[FieldIndex].ActiveSequences; @@ -185,26 +236,29 @@ void FMovieSceneRootEvaluationTemplateInstance::Evaluate(FMovieSceneContext Cont { for (FMovieSceneSequenceID& ID : ActiveSequencesThisFrame) { - ID = GetSequenceIdForRoot(ID, OverrideRootID); + ID = GetSequenceIdForRoot(ID); } } + // Cause stale tracks to not restore until after evaluation. This fixes issues when tracks that are set to 'Restore State' are regenerated, causing the state to be restored then re-animated by the new track + FDelayedPreAnimatedStateRestore DelayedRestore(Player); + // Run the post root evaluate steps which invoke tear downs for anything no longer evaluated. // Do this now to ensure they don't undo any of the current frame's execution tokens - CallSetupTearDown(Player); + CallSetupTearDown(Player, &DelayedRestore); // Ensure any null objects are not cached Player.State.InvalidateExpiredObjects(); // Accumulate execution tokens into this structure FMovieSceneExecutionTokens ExecutionTokens; - EvaluateGroup(Group, Context, Player, ExecutionTokens, OverrideRootID); + EvaluateGroup(Group, Context, Player, ExecutionTokens); // Process execution tokens ExecutionTokens.Apply(Player); } -void FMovieSceneRootEvaluationTemplateInstance::GatherEntities(const FMovieSceneEvaluationGroup& Group, IMovieScenePlayer& Player, FMovieSceneSequenceID OverrideRootID) +void FMovieSceneRootEvaluationTemplateInstance::GatherEntities(const FMovieSceneEvaluationGroup& Group, IMovieScenePlayer& Player) { MOVIESCENE_DETAILED_SCOPE_CYCLE_COUNTER(MovieSceneEval_GatherEntries); @@ -216,7 +270,7 @@ void FMovieSceneRootEvaluationTemplateInstance::GatherEntities(const FMovieScene FMovieSceneEvaluationFieldSegmentPtr SegmentPtr = Group.SegmentPtrLUT[PreEvalTrackIndex]; // Ensure we're able to find the sequence instance in our root if we've overridden - SegmentPtr.SequenceID = GetSequenceIdForRoot(SegmentPtr.SequenceID, OverrideRootID); + SegmentPtr.SequenceID = GetSequenceIdForRoot(SegmentPtr.SequenceID); const FMovieSceneEvaluationTemplateInstance& Instance = GetInstanceChecked(SegmentPtr.SequenceID); @@ -240,7 +294,7 @@ void FMovieSceneRootEvaluationTemplateInstance::GatherEntities(const FMovieScene } } -void FMovieSceneRootEvaluationTemplateInstance::EvaluateGroup(const FMovieSceneEvaluationGroup& Group, const FMovieSceneContext& RootContext, IMovieScenePlayer& Player, FMovieSceneExecutionTokens& ExecutionTokens, FMovieSceneSequenceID OverrideRootID) const +void FMovieSceneRootEvaluationTemplateInstance::EvaluateGroup(const FMovieSceneEvaluationGroup& Group, const FMovieSceneContext& RootContext, IMovieScenePlayer& Player, FMovieSceneExecutionTokens& ExecutionTokens) const { MOVIESCENE_DETAILED_SCOPE_CYCLE_COUNTER(MovieSceneEval_EvaluateGroup); @@ -261,7 +315,7 @@ void FMovieSceneRootEvaluationTemplateInstance::EvaluateGroup(const FMovieSceneE FMovieSceneEvaluationFieldSegmentPtr SegmentPtr = Group.SegmentPtrLUT[TrackIndex]; // Ensure we're able to find the sequence instance in our root if we've overridden - SegmentPtr.SequenceID = GetSequenceIdForRoot(SegmentPtr.SequenceID, OverrideRootID); + SegmentPtr.SequenceID = GetSequenceIdForRoot(SegmentPtr.SequenceID); const FMovieSceneEvaluationTemplateInstance& Instance = GetInstanceChecked(SegmentPtr.SequenceID); const FMovieSceneEvaluationTrack* Track = Instance.Template->FindTrack(SegmentPtr.TrackIdentifier); @@ -300,7 +354,7 @@ void FMovieSceneRootEvaluationTemplateInstance::EvaluateGroup(const FMovieSceneE FMovieSceneEvaluationFieldSegmentPtr SegmentPtr = Group.SegmentPtrLUT[TrackIndex]; // Ensure we're able to find the sequence instance in our root if we've overridden - SegmentPtr.SequenceID = GetSequenceIdForRoot(SegmentPtr.SequenceID, OverrideRootID); + SegmentPtr.SequenceID = GetSequenceIdForRoot(SegmentPtr.SequenceID); const FMovieSceneEvaluationTemplateInstance& Instance = GetInstanceChecked(SegmentPtr.SequenceID); const FMovieSceneEvaluationTrack* Track = Instance.Template->FindTrack(SegmentPtr.TrackIdentifier); @@ -344,7 +398,7 @@ void FMovieSceneRootEvaluationTemplateInstance::EvaluateGroup(const FMovieSceneE } } -void FMovieSceneRootEvaluationTemplateInstance::CallSetupTearDown(IMovieScenePlayer& Player) +void FMovieSceneRootEvaluationTemplateInstance::CallSetupTearDown(IMovieScenePlayer& Player, FDelayedPreAnimatedStateRestore* DelayedRestore) { MOVIESCENE_DETAILED_SCOPE_CYCLE_COUNTER(MovieSceneEval_CallSetupTearDown); @@ -366,6 +420,7 @@ void FMovieSceneRootEvaluationTemplateInstance::CallSetupTearDown(IMovieScenePla } const FMovieSceneEvaluationTrack* Track = Instance->Template->FindTrack(Key.TrackIdentifier); + const bool bStaleTrack = Instance->Template->IsTrackStale(Key.TrackIdentifier); // Track data key may be required by both tracks and sections PersistentDataProxy.SetTrackKey(Key.AsTrack()); @@ -376,8 +431,7 @@ void FMovieSceneRootEvaluationTemplateInstance::CallSetupTearDown(IMovieScenePla { Track->OnEndEvaluation(PersistentDataProxy, Player); } - - Player.PreAnimatedState.RestorePreAnimatedState(Player, Key); + PersistentDataProxy.ResetTrackData(); } else @@ -387,10 +441,18 @@ void FMovieSceneRootEvaluationTemplateInstance::CallSetupTearDown(IMovieScenePla { Track->GetChildTemplate(Key.SectionIdentifier).OnEndEvaluation(PersistentDataProxy, Player); } - - Player.PreAnimatedState.RestorePreAnimatedState(Player, Key); + PersistentDataProxy.ResetSectionData(); } + + if (bStaleTrack && DelayedRestore) + { + DelayedRestore->Add(Key); + } + else + { + Player.PreAnimatedState.RestorePreAnimatedState(Player, Key); + } } for (const FMovieSceneEvaluationKey& Key : EntitiesEvaluatedThisFrame.OrderedKeys) diff --git a/Engine/Source/Runtime/MovieScene/Private/MovieScene.cpp b/Engine/Source/Runtime/MovieScene/Private/MovieScene.cpp index 4fa462c74a98..e449b435a247 100644 --- a/Engine/Source/Runtime/MovieScene/Private/MovieScene.cpp +++ b/Engine/Source/Runtime/MovieScene/Private/MovieScene.cpp @@ -704,96 +704,6 @@ void UMovieScene::UpgradeTimeRanges() #endif } - -void UMovieScene::UpgradeTrackRows() -{ - int32 NumMasterTracks = MasterTracks.Num(); - for (int32 MasterTrackIndex = 0; MasterTrackIndex < NumMasterTracks; ++MasterTrackIndex) - { - UpgradeTrackRow(MasterTracks[MasterTrackIndex]); - } - - for (auto& Binding : ObjectBindings) - { - int32 NumTracks = Binding.GetTracks().Num(); - for (int32 TrackIndex = 0; TrackIndex < NumTracks; ++TrackIndex) - { - UpgradeTrackRow(Binding.GetTracks()[TrackIndex]); - } - } -} - -void UMovieScene::UpgradeTrackRow(UMovieSceneTrack* InTrack) -{ - if (GetLinkerCustomVersion(FSequencerObjectVersion::GUID) >= FSequencerObjectVersion::ConvertMultipleRowsToTracks) - { - return; - } - - // Skeletal animation tracks and audio tracks went through a brief period of expanding their rows out to multiple tracks - // but that upgrade path was short-lived since we added better support for such tracks in the sequencer front-end. - // it was impossible to reliably implement such upgrades due the legacy 'evaluate nearest section' behavior on each of the duplicated tracks - static const FName SkeletalAnimationTrack("MovieSceneSkeletalAnimationTrack"); - static const FName AudioTrack("MovieSceneAudioTrack"); - - FName TrackName = InTrack->GetClass()->GetFName(); - if (TrackName != SkeletalAnimationTrack && TrackName != AudioTrack) - { - return; - } - - // Even still, there is a small amount of upgrade to be done to ensure that blending does not occur on sections that were - // previously overridden by another, so we upgrade these cases by weighting such areas with keys at 0 or 1 - - // If there aren't sections on multiple rows, disregard - auto ContainsMultipleRows = [](UMovieSceneSection* InSection){ return InSection->GetRowIndex() > 0; }; - if (!InTrack->GetAllSections().ContainsByPredicate(ContainsMultipleRows)) - { - return; - } - - // Deal with overlapping sections. For example, skeletal animation sections should be weighted along their evaluation bounds. - // - // For example, - // - // [----A----] - // [-----B-----] - // - // - // Evaluation segments result in: - // - // [----A----] - // [---B---] - // - // OR (depending upon order in the original track): - // - // [--A--] - // [------B----] - // - - TInlineValue RowCompilerRules = InTrack->GetRowCompilerRules(); - FMovieSceneTrackCompiler::FRows TrackRows(InTrack->GetAllSections(), RowCompilerRules.GetPtr(nullptr)); - FMovieSceneTrackEvaluationField EvaluationField = FMovieSceneTrackCompiler().Compile(TrackRows.Rows, InTrack->GetTrackCompilerRules().GetPtr(nullptr)); - - for (const FMovieSceneSegment& EvalSegment : EvaluationField.Segments) - { - if (EvalSegment.Range.IsDegenerate() || EvalSegment.Range.IsEmpty()) - { - continue; - } - - for (FSectionEvaluationData EvalData : EvalSegment.Impls) - { - UMovieSceneSection* Section = InTrack->GetAllSections()[EvalData.ImplIndex]; - Section->ConditionalPostLoad(); - Section->PostLoadUpgradeTrackRow(EvalSegment.Range); - } - } - - InTrack->MarkAsChanged(); -} - - /* UObject interface *****************************************************************************/ @@ -813,7 +723,6 @@ void UMovieScene::PostLoad() } UpgradeTimeRanges(); - UpgradeTrackRows(); for (FMovieSceneSpawnable& Spawnable : Spawnables) { diff --git a/Engine/Source/Runtime/MovieScene/Private/MovieSceneBindingOverrides.cpp b/Engine/Source/Runtime/MovieScene/Private/MovieSceneBindingOverrides.cpp index bfec1f1415d0..49553b98bdb3 100644 --- a/Engine/Source/Runtime/MovieScene/Private/MovieSceneBindingOverrides.cpp +++ b/Engine/Source/Runtime/MovieScene/Private/MovieSceneBindingOverrides.cpp @@ -54,7 +54,7 @@ void UMovieSceneBindingOverrides::SetBinding(FMovieSceneObjectBindingID Binding, continue; } - LookupMap.Add(Binding.GetObjectBindingID(), BindingData.Num()); + LookupMap.Add(Binding.GetGuid(), BindingData.Num()); FMovieSceneBindingOverrideData NewBinding; NewBinding.ObjectBindingId = Binding; @@ -68,7 +68,7 @@ void UMovieSceneBindingOverrides::AddBinding(FMovieSceneObjectBindingID Binding, { if (Object) { - LookupMap.Add(Binding.GetObjectBindingID(), BindingData.Num()); + LookupMap.Add(Binding.GetGuid(), BindingData.Num()); FMovieSceneBindingOverrideData NewBinding; NewBinding.ObjectBindingId = Binding; @@ -118,7 +118,7 @@ void UMovieSceneBindingOverrides::RebuildLookupMap() const for (int32 Index = 0; Index < BindingData.Num(); ++Index) { - LookupMap.Add(BindingData[Index].ObjectBindingId.GetObjectBindingID(), Index); + LookupMap.Add(BindingData[Index].ObjectBindingId.GetGuid(), Index); } bLookupDirty = false; diff --git a/Engine/Source/Runtime/MovieScene/Private/MovieSceneClipboard.cpp b/Engine/Source/Runtime/MovieScene/Private/MovieSceneClipboard.cpp index d91cb9780113..5c0889583f0d 100644 --- a/Engine/Source/Runtime/MovieScene/Private/MovieSceneClipboard.cpp +++ b/Engine/Source/Runtime/MovieScene/Private/MovieSceneClipboard.cpp @@ -10,34 +10,28 @@ TMap> FMovieSce FMovieSceneClipboardKey::FMovieSceneClipboardKey(const FMovieSceneClipboardKey& In) : Time(In.Time) - , bIsSet(In.bIsSet) { - if (In.bIsSet) + if (In.Data.IsValid()) { - auto& Impl = reinterpret_cast(In.Data); - Impl.CopyTo(Data); + In.Data->CopyTo(Data); } } FMovieSceneClipboardKey& FMovieSceneClipboardKey::operator=(const FMovieSceneClipboardKey& In) { Time = In.Time; - bIsSet = In.bIsSet; - - if (bIsSet) + if (In.Data.IsValid()) { - auto& Impl = reinterpret_cast(In.Data); - Impl.CopyTo(Data); + In.Data->CopyTo(Data); + } + else + { + Data.Reset(); } return *this; } -FMovieSceneClipboardKey::~FMovieSceneClipboardKey() -{ - Destroy(); -} - float FMovieSceneClipboardKey::GetTime() const { return Time; @@ -48,15 +42,6 @@ void FMovieSceneClipboardKey::SetTime(float InTime) Time = InTime; } -void FMovieSceneClipboardKey::Destroy() -{ - if (bIsSet) - { - reinterpret_cast(Data).~IKey(); - bIsSet = false; - } -} - FMovieSceneClipboardKeyTrack::FMovieSceneClipboardKeyTrack(FMovieSceneClipboardKeyTrack&& In) : Keys(MoveTemp(In.Keys)) , TypeName(MoveTemp(In.TypeName)) diff --git a/Engine/Source/Runtime/MovieScene/Private/MovieSceneObjectBindingID.cpp b/Engine/Source/Runtime/MovieScene/Private/MovieSceneObjectBindingID.cpp new file mode 100644 index 000000000000..1a733b29508f --- /dev/null +++ b/Engine/Source/Runtime/MovieScene/Private/MovieSceneObjectBindingID.cpp @@ -0,0 +1,27 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "MovieSceneObjectBindingID.h" +#include "MovieSceneSequenceHierarchy.h" + +FMovieSceneObjectBindingID FMovieSceneObjectBindingID::ResolveLocalToRoot(FMovieSceneSequenceID LocalSequenceID, const FMovieSceneSequenceHierarchy& Hierarchy) const +{ + FMovieSceneSequenceID NewSequenceID = FMovieSceneSequenceID(uint32(SequenceID)); + + if (Space == EMovieSceneObjectBindingSpace::Local && LocalSequenceID != MovieSceneSequenceID::Root) + { + while (LocalSequenceID != MovieSceneSequenceID::Root) + { + const FMovieSceneSequenceHierarchyNode* CurrentNode = Hierarchy.FindNode(LocalSequenceID); + const FMovieSceneSubSequenceData* SubData = Hierarchy.FindSubData(LocalSequenceID); + if (!ensureAlwaysMsgf(CurrentNode && SubData, TEXT("Malformed sequence hierarchy"))) + { + return FMovieSceneObjectBindingID(Guid, NewSequenceID); + } + + NewSequenceID = NewSequenceID.AccumulateParentID(SubData->DeterministicSequenceID); + LocalSequenceID = CurrentNode->ParentID; + } + } + + return FMovieSceneObjectBindingID(Guid, NewSequenceID); +} \ No newline at end of file diff --git a/Engine/Source/Runtime/MovieScene/Private/MovieSceneSequencePlayer.cpp b/Engine/Source/Runtime/MovieScene/Private/MovieSceneSequencePlayer.cpp index f064fb536c05..517ea0b0c5eb 100644 --- a/Engine/Source/Runtime/MovieScene/Private/MovieSceneSequencePlayer.cpp +++ b/Engine/Source/Runtime/MovieScene/Private/MovieSceneSequencePlayer.cpp @@ -19,7 +19,7 @@ bool FMovieSceneSequencePlaybackSettings::SerializeFromMismatchedTag( const FPro UMovieSceneSequencePlayer::UMovieSceneSequencePlayer(const FObjectInitializer& Init) : Super(Init) - , bIsPlaying(false) + , Status(EMovieScenePlayerStatus::Stopped) , bReversePlayback(false) , bIsEvaluating(false) , Sequence(nullptr) @@ -32,7 +32,7 @@ UMovieSceneSequencePlayer::UMovieSceneSequencePlayer(const FObjectInitializer& I EMovieScenePlayerStatus::Type UMovieSceneSequencePlayer::GetPlaybackStatus() const { - return bIsPlaying ? EMovieScenePlayerStatus::Playing : EMovieScenePlayerStatus::Stopped; + return Status; } FMovieSceneSpawnRegister& UMovieSceneSequencePlayer::GetSpawnRegister() @@ -76,7 +76,7 @@ void UMovieSceneSequencePlayer::PlayLooping(int32 NumLoops) void UMovieSceneSequencePlayer::PlayInternal() { - if (!bIsPlaying) + if (!IsPlaying()) { // Start playing StartPlayingNextTick(); @@ -113,7 +113,7 @@ void UMovieSceneSequencePlayer::PlayInternal() void UMovieSceneSequencePlayer::StartPlayingNextTick() { - if (bIsPlaying || !Sequence || !CanPlay()) + if (IsPlaying() || !Sequence || !CanPlay()) { return; } @@ -129,12 +129,12 @@ void UMovieSceneSequencePlayer::StartPlayingNextTick() OnStartedPlaying(); bPendingFirstUpdate = true; - bIsPlaying = true; + Status = EMovieScenePlayerStatus::Playing; } void UMovieSceneSequencePlayer::Pause() { - if (bIsPlaying) + if (IsPlaying()) { if (bIsEvaluating) { @@ -142,7 +142,7 @@ void UMovieSceneSequencePlayer::Pause() return; } - bIsPlaying = false; + Status = EMovieScenePlayerStatus::Stopped; // Evaluate the sequence at its current time, with a status of 'stopped' to ensure that animated state pauses correctly { @@ -168,9 +168,22 @@ void UMovieSceneSequencePlayer::Pause() } } +void UMovieSceneSequencePlayer::Scrub() +{ + // @todo Sequencer playback: Should we recreate the instance every time? + // We must not recreate the instance since it holds stateful information (such as which objects it has spawned). Recreating the instance would break any + // @todo: Is this still the case now that eval state is stored (correctly) in the player? + if (!RootTemplateInstance.IsValid()) + { + RootTemplateInstance.Initialize(*Sequence, *this); + } + + Status = EMovieScenePlayerStatus::Scrubbing; +} + void UMovieSceneSequencePlayer::Stop() { - if (bIsPlaying) + if (IsPlaying()) { if (bIsEvaluating) { @@ -178,7 +191,7 @@ void UMovieSceneSequencePlayer::Stop() return; } - bIsPlaying = false; + Status = EMovieScenePlayerStatus::Stopped; TimeCursorPosition = bReversePlayback ? GetLength() : 0.f; CurrentNumLoops = 0; @@ -200,6 +213,13 @@ void UMovieSceneSequencePlayer::Stop() } } +void UMovieSceneSequencePlayer::StopAndGoToEnd() +{ + Stop(); + + SetPlaybackPosition(GetLength()); +} + float UMovieSceneSequencePlayer::GetPlaybackPosition() const { return TimeCursorPosition; @@ -210,9 +230,14 @@ void UMovieSceneSequencePlayer::SetPlaybackPosition(float NewPlaybackPosition) UpdateTimeCursorPosition(NewPlaybackPosition); } +void UMovieSceneSequencePlayer::JumpToPosition(float NewPlaybackPosition) +{ + UpdateTimeCursorPosition(NewPlaybackPosition, EMovieScenePlayerStatus::Scrubbing); +} + bool UMovieSceneSequencePlayer::IsPlaying() const { - return bIsPlaying; + return Status == EMovieScenePlayerStatus::Playing; } float UMovieSceneSequencePlayer::GetLength() const @@ -241,13 +266,16 @@ void UMovieSceneSequencePlayer::SetPlaybackRange( const float NewStartTime, cons bool UMovieSceneSequencePlayer::ShouldStopOrLoop(float NewPosition) const { bool bShouldStopOrLoop = false; - if (!bReversePlayback) + if (IsPlaying()) { - bShouldStopOrLoop = NewPosition >= GetLength(); - } - else - { - bShouldStopOrLoop = NewPosition < 0.f; + if (!bReversePlayback) + { + bShouldStopOrLoop = NewPosition >= GetLength(); + } + else + { + bShouldStopOrLoop = NewPosition < 0.f; + } } return bShouldStopOrLoop; @@ -276,14 +304,14 @@ void UMovieSceneSequencePlayer::Initialize(UMovieSceneSequence* InSequence, cons void UMovieSceneSequencePlayer::Update(const float DeltaSeconds) { - if (bIsPlaying) + if (IsPlaying()) { float PlayRate = bReversePlayback ? -PlaybackSettings.PlayRate : PlaybackSettings.PlayRate; UpdateTimeCursorPosition(TimeCursorPosition + DeltaSeconds * PlayRate); } } -void UMovieSceneSequencePlayer::UpdateTimeCursorPosition(float NewPosition) +void UMovieSceneSequencePlayer::UpdateTimeCursorPosition(float NewPosition, TOptional OptionalStatus) { float Length = GetLength(); @@ -313,7 +341,7 @@ void UMovieSceneSequencePlayer::UpdateTimeCursorPosition(float NewPosition) SpawnRegister->ForgetExternallyOwnedSpawnedObjects(State, *this); } - UpdateMovieSceneInstance(Range); + UpdateMovieSceneInstance(Range, OptionalStatus); OnLooped(); } @@ -321,11 +349,20 @@ void UMovieSceneSequencePlayer::UpdateTimeCursorPosition(float NewPosition) // stop playback else { + FMovieSceneEvaluationRange Range = PlayPosition.PlayTo(GetSequencePosition(), FixedFrameInterval); + + UpdateMovieSceneInstance(Range, OptionalStatus); + Stop(); // When playback stops naturally, the time cursor is put at the boundary that was crossed to make ping-pong playback easy TimeCursorPosition = bReversePlayback ? 0.f : GetLength(); PlayPosition.Reset(TimeCursorPosition); + + if (OnFinished.IsBound()) + { + OnFinished.Broadcast(); + } } } else @@ -334,15 +371,15 @@ void UMovieSceneSequencePlayer::UpdateTimeCursorPosition(float NewPosition) TimeCursorPosition = NewPosition; FMovieSceneEvaluationRange Range = PlayPosition.PlayTo(NewPosition + StartTime, FixedFrameInterval); - UpdateMovieSceneInstance(Range); + UpdateMovieSceneInstance(Range, OptionalStatus); } } -void UMovieSceneSequencePlayer::UpdateMovieSceneInstance(FMovieSceneEvaluationRange InRange) +void UMovieSceneSequencePlayer::UpdateMovieSceneInstance(FMovieSceneEvaluationRange InRange, TOptional OptionalStatus) { bIsEvaluating = true; - const FMovieSceneContext Context(InRange, GetPlaybackStatus()); + const FMovieSceneContext Context(InRange, OptionalStatus.Get(GetPlaybackStatus())); RootTemplateInstance.Evaluate(Context, *this); #if WITH_EDITOR @@ -372,7 +409,7 @@ void UMovieSceneSequencePlayer::ApplyLatentActions() TArray UMovieSceneSequencePlayer::GetBoundObjects(FMovieSceneObjectBindingID ObjectBinding) { TArray Objects; - for (TWeakObjectPtr<> WeakObject : FindBoundObjects(ObjectBinding.GetObjectBindingID(), ObjectBinding.GetSequenceID())) + for (TWeakObjectPtr<> WeakObject : FindBoundObjects(ObjectBinding.GetGuid(), ObjectBinding.GetSequenceID())) { if (UObject* Object = WeakObject.Get()) { @@ -380,4 +417,4 @@ TArray UMovieSceneSequencePlayer::GetBoundObjects(FMovieSceneObjectBin } } return Objects; -} \ No newline at end of file +} diff --git a/Engine/Source/Runtime/MovieScene/Private/MovieSceneSignedObject.cpp b/Engine/Source/Runtime/MovieScene/Private/MovieSceneSignedObject.cpp index 459db6668f4a..b66473660fd2 100644 --- a/Engine/Source/Runtime/MovieScene/Private/MovieSceneSignedObject.cpp +++ b/Engine/Source/Runtime/MovieScene/Private/MovieSceneSignedObject.cpp @@ -8,13 +8,14 @@ UMovieSceneSignedObject::UMovieSceneSignedObject(const FObjectInitializer& Init) { if (!HasAnyFlags(RF_ClassDefaultObject)) { - MarkAsChanged(); + Signature = FGuid::NewGuid(); } } void UMovieSceneSignedObject::MarkAsChanged() { Signature = FGuid::NewGuid(); + OnSignatureChangedEvent.Broadcast(); UObject* Outer = GetOuter(); diff --git a/Engine/Source/Runtime/MovieScene/Private/MovieSceneTrack.cpp b/Engine/Source/Runtime/MovieScene/Private/MovieSceneTrack.cpp index 40aca748d34a..73005ffa84f3 100644 --- a/Engine/Source/Runtime/MovieScene/Private/MovieSceneTrack.cpp +++ b/Engine/Source/Runtime/MovieScene/Private/MovieSceneTrack.cpp @@ -109,7 +109,7 @@ FMovieSceneEvaluationTrack UMovieSceneTrack::GenerateTrackTemplate() const virtual void AddLegacyTrack(FMovieSceneEvaluationTrack&& InTrackTemplate, const UMovieSceneTrack& SourceTrack) override {} virtual void AddExternalSegments(TRange RootRange, TArrayView SegmentPtrs, ESectionEvaluationFlags Flags) override {} virtual FMovieSceneSequenceTransform GetSequenceTransform(FMovieSceneSequenceIDRef InSequenceID) const override { return FMovieSceneSequenceTransform(); } - virtual FMovieSceneSequenceID GenerateSequenceID(FMovieSceneSubSequenceData SequenceData, FMovieSceneSequenceIDRef ParentID) override { return MovieSceneSequenceID::Root; } + virtual void AddSubSequence(FMovieSceneSubSequenceData SequenceData, FMovieSceneSequenceIDRef ParentID, FMovieSceneSequenceID SpecificID) override { } } Generator; FMovieSceneSequenceTemplateStore Store; diff --git a/Engine/Source/Runtime/MovieScene/Private/Tests/MovieSceneSegmentCompilerTests.cpp b/Engine/Source/Runtime/MovieScene/Private/Tests/MovieSceneSegmentCompilerTests.cpp new file mode 100644 index 000000000000..a86249318d77 --- /dev/null +++ b/Engine/Source/Runtime/MovieScene/Private/Tests/MovieSceneSegmentCompilerTests.cpp @@ -0,0 +1,451 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "MovieSceneSegmentCompilerTests.h" +#include "CoreMinimal.h" +#include "Misc/AutomationTest.h" +#include "Compilation/MovieSceneSegmentCompiler.h" +#include "Compilation/MovieSceneCompilerRules.h" +#include "MovieSceneTestsCommon.h" +#include "Package.h" + +namespace Impl +{ + static const TRangeBound Inf = TRangeBound::Open(); + + /** Compiler rules to sort by priority */ + struct FSortByPriorityCompilerRules : FMovieSceneSegmentCompilerRules + { + int32 MaxImplIndex; + + FSortByPriorityCompilerRules(int32 InMaxImplIndex, bool bInAllowEmptySegments) + : MaxImplIndex(InMaxImplIndex) + { + bAllowEmptySegments = bInAllowEmptySegments; + } + + virtual TOptional InsertEmptySpace(const TRange& Range, const FMovieSceneSegment* PreviousSegment, const FMovieSceneSegment* NextSegment) const override + { + return bAllowEmptySegments ? FMovieSceneSegment(Range) : TOptional(); + } + + virtual void BlendSegment(FMovieSceneSegment& Segment, const TArrayView& SourceData) const + { + Segment.Impls.Sort( + [&](const FSectionEvaluationData& A, const FSectionEvaluationData& B) + { + return SourceData[A.ImplIndex].Priority > SourceData[B.ImplIndex].Priority; + } + ); + } + + virtual void PostProcessSegments(TArray& Segments, const TArrayView& SourceData) const override + { + for (FMovieSceneSegment& Segment : Segments) + { + for (FSectionEvaluationData EvalData : Segment.Impls) + { + ensureMsgf(SourceData.IsValidIndex(EvalData.ImplIndex), + TEXT("Compiled segment data does not correctly map to the source data array")); + + const int32 ThisImpl = SourceData[EvalData.ImplIndex].EvalData.ImplIndex; + ensureMsgf(ThisImpl >= 0 && ThisImpl <= MaxImplIndex, + TEXT("Compiled segment data does not correctly map to either the designated implementation range")); + } + } + } + + }; + + FORCEINLINE void AssertSegmentValues(FAutomationTestBase* Test, TArrayView Expected, TArrayView Actual) + { + auto Join = [](TArrayView Stuff) -> FString + { + FString Result; + for (const FSectionEvaluationData& Thing : Stuff) + { + if (Result.Len()) + { + Result += TEXT(", "); + } + + Result += FString::Printf(TEXT("(Impl: %d, ForcedTime: %.7f, Flags: %u)"), Thing.ImplIndex, Thing.ForcedTime, (uint8)Thing.Flags); + } + + return Result; + }; + + using namespace Lex; + if (Actual.Num() != Expected.Num()) + { + Test->AddError(FString::Printf(TEXT("Wrong number of compiled segments. Expected %d, actual %d."), Expected.Num(), Actual.Num())); + } + else for (int32 Index = 0; Index < Expected.Num(); ++Index) + { + const FMovieSceneSegment& ExpectedSegment = Expected[Index]; + const FMovieSceneSegment& ActualSegment = Actual[Index]; + + if (ExpectedSegment.Range != ActualSegment.Range) + { + Test->AddError(FString::Printf(TEXT("Incorrect compiled segment range at segment index %d. Expected:\n%s\nActual:\n%s"), Index, *Lex::ToString(ExpectedSegment.Range), *Lex::ToString(ActualSegment.Range))); + } + else if (ExpectedSegment.Impls.Num() != ActualSegment.Impls.Num()) + { + Test->AddError(FString::Printf(TEXT("Incorrect number of implementation references compiled into segment index %d. Expected %d, actual %d."), Index, ExpectedSegment.Impls.Num(), ActualSegment.Impls.Num())); + } + else + { + FString ActualImpls = Join(ActualSegment.Impls); + FString ExpectedImpls = Join(ExpectedSegment.Impls); + + if (ActualImpls != ExpectedImpls) + { + Test->AddError(FString::Printf(TEXT("Compiled data does not match for segment index %d.\nExpected: %s\nActual: %s."), Index, *ExpectedImpls, *ActualImpls)); + } + } + } + } +} + +IMPLEMENT_SIMPLE_AUTOMATION_TEST(FMovieSceneCompilerBasicTest, "System.Engine.Sequencer.Compiler.Basic", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter) +bool FMovieSceneCompilerBasicTest::RunTest(const FString& Parameters) +{ + using namespace Impl; + + // Specify descending priorities on the segments so we always sort the compiled segments in the order they're defined within the data + // This is our test layout + // Time -inf 10 20 25 30 inf + // [============= 0 ===========] + // [============== 1 ==================] + // [========================== 2 ==================================] + // [================== 3 ==========================] + // [================== 4 ==========================] + //---------------------------------------------------------------------------------------------------------------------------------------- + // Expected Impls [ 3 | 0,2,3 | 1,2 | 1,2,4 | 4 ] + + const FMovieSceneSectionData SegmentData[] = { + FMovieSceneSectionData(TRange(10.f, 20.f), FSectionEvaluationData(0), 4), + FMovieSceneSectionData(TRange(20.f, 30.f), FSectionEvaluationData(1), 3), + FMovieSceneSectionData(TRange(10.f, 30.f), FSectionEvaluationData(2), 2), + FMovieSceneSectionData(TRange(Inf, TRangeBound::Exclusive(20.f)), FSectionEvaluationData(3), 1), + FMovieSceneSectionData(TRange(25.f, Inf), FSectionEvaluationData(4), 0) + }; + + FSortByPriorityCompilerRules DefaultRules(4, false); + TArray Segments = FMovieSceneSegmentCompiler().Compile(SegmentData, &DefaultRules); + + FMovieSceneSegment Expected[] = { + FMovieSceneSegment(FFloatRange(Inf, TRangeBound::Exclusive(10.f)), { FSectionEvaluationData(3) }), + FMovieSceneSegment(FFloatRange(10.f, 20.f), { FSectionEvaluationData(0), FSectionEvaluationData(2), FSectionEvaluationData(3) }), + FMovieSceneSegment(FFloatRange(20.f, 25.f), { FSectionEvaluationData(1), FSectionEvaluationData(2) }), + FMovieSceneSegment(FFloatRange(25.f, 30.f), { FSectionEvaluationData(1), FSectionEvaluationData(2), FSectionEvaluationData(4) }), + FMovieSceneSegment(FFloatRange(30.f, Inf), { FSectionEvaluationData(4) }) + }; + AssertSegmentValues(this, Expected, Segments); + return true; +} + +IMPLEMENT_SIMPLE_AUTOMATION_TEST(FMovieSceneCompilerEmptySpaceTest, "System.Engine.Sequencer.Compiler.Empty Space", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter) +bool FMovieSceneCompilerEmptySpaceTest::RunTest(const FString& Parameters) +{ + using namespace Impl; + + // Specify descending priorities on the segments so we always sort the compiled segments in the order they're defined within the data + // This is our test layout + // Time -Inf 10 20 30 40 Inf + // [====== 0 ======] [====== 1 ======] + //---------------------------------------------------------------------------------------------------------------------------------------- + // Expected Impls [ Empty | 0 | Empty | 1 | Empty ] + + const FMovieSceneSectionData SegmentData[] = { + FMovieSceneSectionData(TRange(10.f, 20.f), FSectionEvaluationData(0), 1), + FMovieSceneSectionData(TRange(30.f, 40.f), FSectionEvaluationData(1), 0) + }; + + FSortByPriorityCompilerRules DefaultRules(1, true); + TArray Segments = FMovieSceneSegmentCompiler().Compile(SegmentData, &DefaultRules); + + FMovieSceneSegment Expected[] = { + FMovieSceneSegment(FFloatRange(Inf, TRangeBound::Exclusive(10.f)), { }), + FMovieSceneSegment(FFloatRange(10.f, 20.f), { FSectionEvaluationData(0) }), + FMovieSceneSegment(FFloatRange(20.f, 30.f), { }), + FMovieSceneSegment(FFloatRange(30.f, 40.f), { FSectionEvaluationData(1) }), + FMovieSceneSegment(FFloatRange(40.f, Inf), { }) + }; + AssertSegmentValues(this, Expected, Segments); + return true; +} + +IMPLEMENT_SIMPLE_AUTOMATION_TEST(FMovieSceneCustomCompilerTest, "System.Engine.Sequencer.Compiler.Custom", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter) +bool FMovieSceneCustomCompilerTest::RunTest(const FString& Parameters) +{ + using namespace Impl; + + // Specify descending priorities on the segments so we always sort the compiled segments in the order they're defined within the data + // This is our test layout + // Time -Inf 10 15 20 25 30 40 Inf + // [===== 0 (preroll) =====] + // [========== 0 ==========] + // [========== 0 ==========][========== 0 =========] + //---------------------------------------------------------------------------------------------------------------------------------------- + // Expected Impls [ 0 (p) | (0, 0(p)) | 0 ] + + const FMovieSceneSectionData SegmentData[] = { + FMovieSceneSectionData(TRange(TRangeBound::Inclusive(10.f), TRangeBound::Exclusive(20.f)), FSectionEvaluationData(0, ESectionEvaluationFlags::PreRoll), 4), + FMovieSceneSectionData(TRange(TRangeBound::Inclusive(15.f), TRangeBound::Exclusive(25.f)), FSectionEvaluationData(0), 1), + FMovieSceneSectionData(TRange(TRangeBound::Inclusive(20.f), TRangeBound::Exclusive(30.f)), FSectionEvaluationData(0), 1), + FMovieSceneSectionData(TRange(TRangeBound::Inclusive(30.f), TRangeBound::Exclusive(40.f)), FSectionEvaluationData(0), 1), + }; + + FSortByPriorityCompilerRules DefaultRules(0, false); + TArray Segments = FMovieSceneSegmentCompiler().Compile(SegmentData, &DefaultRules); + + FMovieSceneSegment Expected[] = { + FMovieSceneSegment(TRange(TRangeBound::Inclusive(10.f), TRangeBound::Exclusive(15.f)), { FSectionEvaluationData(0, ESectionEvaluationFlags::PreRoll) }), + FMovieSceneSegment(TRange(TRangeBound::Inclusive(15.f), TRangeBound::Exclusive(20.f)), { FSectionEvaluationData(0, ESectionEvaluationFlags::PreRoll), FSectionEvaluationData(0) }), + FMovieSceneSegment(TRange(TRangeBound::Inclusive(20.f), TRangeBound::Exclusive(40.f)), { FSectionEvaluationData(0) }), + }; + + AssertSegmentValues(this, Expected, Segments); + return true; +} + +IMPLEMENT_SIMPLE_AUTOMATION_TEST(FMovieSceneTrackCompilerTest, "System.Engine.Sequencer.Compiler.Tracks", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter) +bool FMovieSceneTrackCompilerTest::RunTest(const FString& Parameters) +{ + using namespace Impl; + + // Track 0 test layout: + // Time -inf 10 20 25 30 inf + // ------------------------------------------------------------------------------------------------------------------------------------------------------ + // Track 0: [====================== 0 ==================] + // [=============== 1 =================] + // ------------------------------------------------------------------------------------------------------------------------------------------------------ + // Additive Camera Rules Expected [ | 0 | (0,1) | 1 | ] + // Nearest Section Expected [ 0 (10.f) | 0 | (0,1) | 1 | 1 (30.f) ] + // No Nearest Section Expected [ | 0 | (0,1) | 1 | ] + // High-pass Filter Expected [ | 0 | 1 | ] + + { + UMovieSceneSegmentCompilerTestTrack* Track = NewObject(GetTransientPackage()); + Track->EvalOptions.bCanEvaluateNearestSection = true; + + UMovieSceneSegmentCompilerTestSection* Section0 = NewObject(Track); + Section0->SetStartTime(10.f); + Section0->SetEndTime(25.f); + Section0->SetRowIndex(0); + + UMovieSceneSegmentCompilerTestSection* Section1 = NewObject(Track); + Section1->SetStartTime(20.f); + Section1->SetEndTime(30.f); + Section1->SetRowIndex(1); + + Track->SectionArray.Add(Section0); + Track->SectionArray.Add(Section1); + + FMovieSceneTrackCompiler::FRows Rows(Track->SectionArray, &Track->GetRowCompilerRules().GetValue()); + + // Test compiling the track with the additive camera rules + { + FMovieSceneAdditiveCameraRules AdditiveCameraRules(Track); + FMovieSceneTrackEvaluationField Field = FMovieSceneTrackCompiler().Compile(Rows.Rows, &AdditiveCameraRules); + + FMovieSceneSegment Expected[] = { + FMovieSceneSegment(FFloatRange(TRangeBound::Inclusive(10.f), TRangeBound::Exclusive(20.f)), { FSectionEvaluationData(0) }), + FMovieSceneSegment(FFloatRange(TRangeBound::Inclusive(20.f), TRangeBound::Inclusive(25.f)), { FSectionEvaluationData(0), FSectionEvaluationData(1) }), + FMovieSceneSegment(FFloatRange(TRangeBound::Exclusive(25.f), TRangeBound::Inclusive(30.f)), { FSectionEvaluationData(1) }), + }; + AssertSegmentValues(this, Expected, Field.Segments); + } + + // Test compiling with 'evaluate nearest section' enabled + { + Track->EvalOptions.bEvaluateNearestSection = true; + FMovieSceneTrackEvaluationField Field = FMovieSceneTrackCompiler().Compile(Rows.Rows, Track->GetTrackCompilerRules().GetPtr(nullptr)); + + FMovieSceneSegment Expected[] = { + FMovieSceneSegment(FFloatRange(Inf, TRangeBound::Exclusive(10.f)), { FSectionEvaluationData(0, 10.f) }), + FMovieSceneSegment(FFloatRange(TRangeBound::Inclusive(10.f), TRangeBound::Exclusive(20.f)), { FSectionEvaluationData(0) }), + FMovieSceneSegment(FFloatRange(TRangeBound::Inclusive(20.f), TRangeBound::Inclusive(25.f)), { FSectionEvaluationData(0), FSectionEvaluationData(1) }), + FMovieSceneSegment(FFloatRange(TRangeBound::Exclusive(25.f), TRangeBound::Inclusive(30.f)), { FSectionEvaluationData(1) }), + FMovieSceneSegment(FFloatRange(TRangeBound::Exclusive(30.f), Inf), { FSectionEvaluationData(1, 30.f) }), + }; + AssertSegmentValues(this, Expected, Field.Segments); + } + + // Test compiling without 'evaluate nearest section' enabled + { + Track->EvalOptions.bEvaluateNearestSection = false; + FMovieSceneTrackEvaluationField Field = FMovieSceneTrackCompiler().Compile(Rows.Rows, Track->GetTrackCompilerRules().GetPtr(nullptr)); + + FMovieSceneSegment Expected[] = { + FMovieSceneSegment(FFloatRange(TRangeBound::Inclusive(10.f), TRangeBound::Exclusive(20.f)), { FSectionEvaluationData(0) }), + FMovieSceneSegment(FFloatRange(TRangeBound::Inclusive(20.f), TRangeBound::Inclusive(25.f)), { FSectionEvaluationData(0), FSectionEvaluationData(1) }), + FMovieSceneSegment(FFloatRange(TRangeBound::Exclusive(25.f), TRangeBound::Inclusive(30.f)), { FSectionEvaluationData(1) }), + }; + AssertSegmentValues(this, Expected, Field.Segments); + } + + // Test high-pass filter + { + Track->EvalOptions.bEvaluateNearestSection = false; + Track->bHighPassFilter = true; + FMovieSceneTrackEvaluationField Field = FMovieSceneTrackCompiler().Compile(Rows.Rows, Track->GetTrackCompilerRules().GetPtr(nullptr)); + + FMovieSceneSegment Expected[] = { + FMovieSceneSegment(FFloatRange(TRangeBound::Inclusive(10.f), TRangeBound::Inclusive(25.f)), { FSectionEvaluationData(0) }), + FMovieSceneSegment(FFloatRange(TRangeBound::Exclusive(25.f), TRangeBound::Inclusive(30.f)), { FSectionEvaluationData(1) }), + }; + AssertSegmentValues(this, Expected, Field.Segments); + } + } + + // Track 1 test layout: + // Time -inf 10 15 20 25 30 inf + // ----------------------------------------------------------------------------------------------------------------------------------------------------- + // Track 1: [==== 3 ====(==== 3,2 ======)======= 2 =========] + // [============================ 0 ============================] + // [================================================ 1 ========================================================] + // ----------------------------------------------------------------------------------------------------------------------------------------------------- + // Additive Camera Rules Expected [ 1 | (1,0) | (1,0,3) | (1,0,2) | 1 ] + // Nearest Section Expected [ 1 | (0,1) | (3,0,1) | (2,0,1) | 1 ] + // No Nearest Section Expected [ 1 | (0,1) | (3,0,1) | (2,0,1) | 1 ] + // High-Pass Filter Expected [ 1 | 0 | 3 | 2 | 1 ] + { + UMovieSceneSegmentCompilerTestTrack* Track = NewObject(GetTransientPackage()); + + UMovieSceneSegmentCompilerTestSection* Section0 = NewObject(Track); + Section0->SetStartTime(10.f); + Section0->SetEndTime(30.f); + Section0->SetRowIndex(1); + + UMovieSceneSegmentCompilerTestSection* Section1 = NewObject(Track); + Section1->SetIsInfinite(true); + Section1->SetRowIndex(2); + + UMovieSceneSegmentCompilerTestSection* Section2 = NewObject(Track); + Section2->SetStartTime(20.f); + Section2->SetEndTime(30.f); + Section2->SetRowIndex(0); + + UMovieSceneSegmentCompilerTestSection* Section3 = NewObject(Track); + Section3->SetStartTime(15.f); + Section3->SetEndTime(25.f); + Section3->SetRowIndex(0); + Section3->SetOverlapPriority(100.f); + + Track->SectionArray.Add(Section0); + Track->SectionArray.Add(Section1); + Track->SectionArray.Add(Section2); + Track->SectionArray.Add(Section3); + + auto RowCompilerRules = Track->GetRowCompilerRules(); + FMovieSceneTrackCompiler::FRows Rows(Track->SectionArray, RowCompilerRules.GetPtr(nullptr)); + + // Additive camera rules prescribe that they are evaluated in order of start time + FMovieSceneSegment Expected[] = { + FMovieSceneSegment(FFloatRange(Inf, TRangeBound::Exclusive(10.f)), { }), + FMovieSceneSegment(FFloatRange(TRangeBound::Inclusive(10.f), TRangeBound::Exclusive(15.f)), { }), + FMovieSceneSegment(FFloatRange(TRangeBound::Inclusive(15.f), TRangeBound::Inclusive(25.f)), { }), + FMovieSceneSegment(FFloatRange(TRangeBound::Exclusive(25.f), TRangeBound::Inclusive(30.f)), { }), + FMovieSceneSegment(FFloatRange(TRangeBound::Exclusive(30.f), Inf), { }), + }; + + // Test compiling the track with the additive camera rules + { + FMovieSceneAdditiveCameraRules AdditiveCameraRules(Track); + FMovieSceneTrackEvaluationField Field = FMovieSceneTrackCompiler().Compile(Rows.Rows, &AdditiveCameraRules); + + // Additive camera rules prescribe that they are evaluated in order of start time + Expected[0].Impls = { FSectionEvaluationData(1) }; + Expected[1].Impls = { FSectionEvaluationData(1), FSectionEvaluationData(0) }; + Expected[2].Impls = { FSectionEvaluationData(1), FSectionEvaluationData(0), FSectionEvaluationData(3) }; + Expected[3].Impls = { FSectionEvaluationData(1), FSectionEvaluationData(0), FSectionEvaluationData(2) }; + Expected[4].Impls = { FSectionEvaluationData(1) }; + + AssertSegmentValues(this, Expected, Field.Segments); + } + + // Test compiling with 'evaluate nearest section' enabled + { + Track->EvalOptions.bEvaluateNearestSection = true; + FMovieSceneTrackEvaluationField Field = FMovieSceneTrackCompiler().Compile(Rows.Rows, Track->GetTrackCompilerRules().GetPtr(nullptr)); + + Expected[0].Impls = { FSectionEvaluationData(1) }; + Expected[1].Impls = { FSectionEvaluationData(0), FSectionEvaluationData(1) }; + Expected[2].Impls = { FSectionEvaluationData(3), FSectionEvaluationData(0), FSectionEvaluationData(1) }; + Expected[3].Impls = { FSectionEvaluationData(2), FSectionEvaluationData(0), FSectionEvaluationData(1) }; + Expected[4].Impls = { FSectionEvaluationData(1) }; + + AssertSegmentValues(this, Expected, Field.Segments); + } + + // Test compiling without 'evaluate nearest section' enabled + { + Track->EvalOptions.bEvaluateNearestSection = false; + FMovieSceneTrackEvaluationField Field = FMovieSceneTrackCompiler().Compile(Rows.Rows, Track->GetTrackCompilerRules().GetPtr(nullptr)); + + Expected[0].Impls = { FSectionEvaluationData(1) }; + Expected[1].Impls = { FSectionEvaluationData(0), FSectionEvaluationData(1) }; + Expected[2].Impls = { FSectionEvaluationData(3), FSectionEvaluationData(0), FSectionEvaluationData(1) }; + Expected[3].Impls = { FSectionEvaluationData(2), FSectionEvaluationData(0), FSectionEvaluationData(1) }; + Expected[4].Impls = { FSectionEvaluationData(1) }; + + AssertSegmentValues(this, Expected, Field.Segments); + } + + // Test compiling with high pass filter + { + Track->EvalOptions.bEvaluateNearestSection = false; + Track->bHighPassFilter = true; + FMovieSceneTrackEvaluationField Field = FMovieSceneTrackCompiler().Compile(Rows.Rows, Track->GetTrackCompilerRules().GetPtr(nullptr)); + + Expected[0].Impls = { FSectionEvaluationData(1) }; + Expected[1].Impls = { FSectionEvaluationData(0) }; + Expected[2].Impls = { FSectionEvaluationData(3) }; + Expected[3].Impls = { FSectionEvaluationData(2) }; + Expected[4].Impls = { FSectionEvaluationData(1) }; + + AssertSegmentValues(this, Expected, Field.Segments); + } + } + + return true; +} + + +TInlineValue UMovieSceneSegmentCompilerTestTrack::GetTrackCompilerRules() const +{ + struct FRules : FMovieSceneSegmentCompilerRules + { + bool bHighPass; + bool bEvaluateNearest; + + FRules(bool bInHighPassFilter, bool bInEvaluateNearest) + : bHighPass(bInHighPassFilter) + , bEvaluateNearest(bInEvaluateNearest) + {} + + virtual void BlendSegment(FMovieSceneSegment& Segment, const TArrayView& SourceData) const + { + if (bHighPass) + { + MovieSceneSegmentCompiler::BlendSegmentHighPass(Segment, SourceData); + } + + // Always sort by priority + Segment.Impls.Sort( + [&](const FSectionEvaluationData& A, const FSectionEvaluationData& B) + { + return SourceData[A.ImplIndex].Priority > SourceData[B.ImplIndex].Priority; + } + ); + } + virtual TOptional InsertEmptySpace(const TRange& Range, const FMovieSceneSegment* PreviousSegment, const FMovieSceneSegment* NextSegment) const + { + return bEvaluateNearest ? MovieSceneSegmentCompiler::EvaluateNearestSegment(Range, PreviousSegment, NextSegment) : TOptional(); + } + }; + + // Evaluate according to bEvaluateNearestSection preference + return FRules(bHighPassFilter, EvalOptions.bCanEvaluateNearestSection && EvalOptions.bEvaluateNearestSection); +} \ No newline at end of file diff --git a/Engine/Source/Runtime/MovieScene/Private/Tests/MovieSceneSegmentCompilerTests.h b/Engine/Source/Runtime/MovieScene/Private/Tests/MovieSceneSegmentCompilerTests.h new file mode 100644 index 000000000000..9ab9a85ea03b --- /dev/null +++ b/Engine/Source/Runtime/MovieScene/Private/Tests/MovieSceneSegmentCompilerTests.h @@ -0,0 +1,34 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "MovieSceneTrack.h" +#include "MovieSceneSection.h" +#include "MovieSceneSegmentCompilerTests.generated.h" + +UCLASS(MinimalAPI) +class UMovieSceneSegmentCompilerTestTrack : public UMovieSceneTrack +{ +public: + + GENERATED_BODY() + + virtual const TArray& GetAllSections() const override { return SectionArray; } + virtual TInlineValue GetTrackCompilerRules() const override; + + UPROPERTY() + bool bHighPassFilter; + + UPROPERTY() + TArray SectionArray; +}; + +UCLASS(MinimalAPI) +class UMovieSceneSegmentCompilerTestSection : public UMovieSceneSection +{ +public: + GENERATED_BODY() +}; + diff --git a/Engine/Source/Runtime/MovieScene/Private/Tests/MovieSceneTestsCommon.h b/Engine/Source/Runtime/MovieScene/Private/Tests/MovieSceneTestsCommon.h new file mode 100644 index 000000000000..ad2c7bdd721a --- /dev/null +++ b/Engine/Source/Runtime/MovieScene/Private/Tests/MovieSceneTestsCommon.h @@ -0,0 +1,11 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "Range.h" +#include "UnrealString.h" + +namespace Lex +{ + MOVIESCENE_API FString ToString(const TRange& InRange); +} \ No newline at end of file diff --git a/Engine/Source/Runtime/MovieScene/Private/Tests/MovieSceneTransformTests.cpp b/Engine/Source/Runtime/MovieScene/Private/Tests/MovieSceneTransformTests.cpp index d601b8d69bdc..700bc859a06d 100644 --- a/Engine/Source/Runtime/MovieScene/Private/Tests/MovieSceneTransformTests.cpp +++ b/Engine/Source/Runtime/MovieScene/Private/Tests/MovieSceneTransformTests.cpp @@ -5,8 +5,9 @@ #include "Evaluation/MovieSceneSectionParameters.h" #include "Containers/ArrayView.h" #include "Misc/AutomationTest.h" +#include "MovieSceneTestsCommon.h" -#define LOCTEXT_NAMESPACE "MovieSceneSubTrack" +#define LOCTEXT_NAMESPACE "MovieSceneTransformTests" bool IsNearly(TRangeBound A, TRangeBound B) { @@ -34,15 +35,15 @@ namespace Lex TRangeBound SourceLower = InRange.GetLowerBound(); TRangeBound SourceUpper = InRange.GetUpperBound(); - return *FString::Printf(TEXT("%s, %s"), + return *FString::Printf(TEXT("%s-%s"), SourceLower.IsOpen() ? - TEXT("...") : + TEXT("[...") : SourceLower.IsInclusive() ? *FString::Printf(TEXT("[%.5f"), SourceLower.GetValue()) : *FString::Printf(TEXT("(%.5f"), SourceLower.GetValue()), SourceUpper.IsOpen() ? - TEXT("...") : + TEXT("...]") : SourceUpper.IsInclusive() ? *FString::Printf(TEXT("%.5f]"), SourceUpper.GetValue()) : *FString::Printf(TEXT("%.5f)"), SourceUpper.GetValue()) diff --git a/Engine/Source/Runtime/MovieScene/Public/Compilation/IMovieSceneTemplateGenerator.h b/Engine/Source/Runtime/MovieScene/Public/Compilation/IMovieSceneTemplateGenerator.h index 40292691bb8f..d1b006dfd45b 100644 --- a/Engine/Source/Runtime/MovieScene/Public/Compilation/IMovieSceneTemplateGenerator.h +++ b/Engine/Source/Runtime/MovieScene/Public/Compilation/IMovieSceneTemplateGenerator.h @@ -7,6 +7,7 @@ #include "MovieSceneFwd.h" #include "MovieSceneSegment.h" #include "Containers/ArrayView.h" +#include "MovieSceneSequenceID.h" class UMovieSceneTrack; struct FMovieSceneEvaluationFieldSegmentPtr; @@ -61,11 +62,15 @@ struct IMovieSceneTemplateGenerator virtual FMovieSceneSequenceTransform GetSequenceTransform(FMovieSceneSequenceIDRef InSequenceID) const = 0; /** - * Generate a new sequence ID for the specified sub sequence + * Add the specified sub sequence data to this generator * * @param SequenceData Data pertaining to the sequence to add * @param ParentID ID of the parent sequence + * @param SequenceID Specific ID to use to identify this sub sequence in the template. Must not already exist in the template. */ - virtual FMovieSceneSequenceID GenerateSequenceID(FMovieSceneSubSequenceData SequenceData, FMovieSceneSequenceIDRef ParentID) = 0; + virtual void AddSubSequence(FMovieSceneSubSequenceData SequenceData, FMovieSceneSequenceIDRef ParentID, FMovieSceneSequenceID SequenceID) = 0; + +protected: + virtual ~IMovieSceneTemplateGenerator() { } }; diff --git a/Engine/Source/Runtime/MovieScene/Public/Compilation/MovieSceneCompilerRules.h b/Engine/Source/Runtime/MovieScene/Public/Compilation/MovieSceneCompilerRules.h index 2b3d6e917626..7f1466ac4845 100644 --- a/Engine/Source/Runtime/MovieScene/Public/Compilation/MovieSceneCompilerRules.h +++ b/Engine/Source/Runtime/MovieScene/Public/Compilation/MovieSceneCompilerRules.h @@ -101,9 +101,21 @@ public: // sort by start time to match application order of player camera Segment.Impls.Sort( [&](FSectionEvaluationData A, FSectionEvaluationData B){ - const int32 SectionIndexA = SourceData[A.ImplIndex].EvalData.ImplIndex; - const int32 SectionIndexB = SourceData[B.ImplIndex].EvalData.ImplIndex; - return Sections[SectionIndexA]->GetStartTime() < Sections[SectionIndexB]->GetStartTime(); + UMovieSceneSection* SectionA = Sections[SourceData[A.ImplIndex].EvalData.ImplIndex]; + UMovieSceneSection* SectionB = Sections[SourceData[B.ImplIndex].EvalData.ImplIndex]; + + if (SectionA->IsInfinite()) + { + return true; + } + else if (SectionB->IsInfinite()) + { + return false; + } + else + { + return SectionA->GetStartTime() < SectionB->GetStartTime(); + } } ); } diff --git a/Engine/Source/Runtime/MovieScene/Public/Compilation/MovieSceneEvaluationTemplateGenerator.h b/Engine/Source/Runtime/MovieScene/Public/Compilation/MovieSceneEvaluationTemplateGenerator.h index 3b113eb838f7..4a370688e760 100644 --- a/Engine/Source/Runtime/MovieScene/Public/Compilation/MovieSceneEvaluationTemplateGenerator.h +++ b/Engine/Source/Runtime/MovieScene/Public/Compilation/MovieSceneEvaluationTemplateGenerator.h @@ -23,7 +23,7 @@ class UMovieSceneSequence; /** * Class responsible for generating up-to-date evaluation template data */ -class FMovieSceneEvaluationTemplateGenerator : IMovieSceneTemplateGenerator +class FMovieSceneEvaluationTemplateGenerator final : IMovieSceneTemplateGenerator { public: @@ -71,7 +71,7 @@ private: virtual void AddSharedTrack(FMovieSceneEvaluationTrack&& InTrackTemplate, FMovieSceneSharedDataId SharedId, const UMovieSceneTrack& SourceTrack) override; virtual void AddExternalSegments(TRange RootRange, TArrayView SegmentPtrs, ESectionEvaluationFlags Flags) override; virtual FMovieSceneSequenceTransform GetSequenceTransform(FMovieSceneSequenceIDRef InSequenceID) const override; - virtual FMovieSceneSequenceID GenerateSequenceID(FMovieSceneSubSequenceData SequenceData, FMovieSceneSequenceIDRef ParentID) override; + virtual void AddSubSequence(FMovieSceneSubSequenceData SequenceData, FMovieSceneSequenceIDRef ParentID, FMovieSceneSequenceID SequenceID) override; private: diff --git a/Engine/Source/Runtime/MovieScene/Public/Compilation/MovieSceneSegmentCompiler.h b/Engine/Source/Runtime/MovieScene/Public/Compilation/MovieSceneSegmentCompiler.h index b59b9b44a083..19b482138419 100644 --- a/Engine/Source/Runtime/MovieScene/Public/Compilation/MovieSceneSegmentCompiler.h +++ b/Engine/Source/Runtime/MovieScene/Public/Compilation/MovieSceneSegmentCompiler.h @@ -6,59 +6,128 @@ #include "Evaluation/MovieSceneSegment.h" #include "MovieSceneSection.h" +/** Data structure supplied to the segment compiler that represents a section range, evaluation data (including the section's index), and a priority */ struct FMovieSceneSectionData { MOVIESCENE_API FMovieSceneSectionData(const TRange& InBounds, FSectionEvaluationData InEvalData, int32 InPriority = 0); + /** The time range in which this section is considered active */ TRange Bounds; + /** Evaluation data with which the section is to be evaluated */ FSectionEvaluationData EvalData; + /** Priority for the data (ie OverlapPriority where this represents sections in a row, or row index in the case of rows in a track) */ int32 Priority; }; +/** Structure that defines how the segment compiler should combine overlapping sections, insert empty space, sort evaluation order, and other arbitrary processing. */ struct FMovieSceneSegmentCompilerRules { + /** Default constructor */ FMovieSceneSegmentCompilerRules() { bAllowEmptySegments = false; } - bool AllowEmptySegments() const { return bAllowEmptySegments; } + virtual ~FMovieSceneSegmentCompilerRules() {} + /** + * Public entry point to process an array of compiled segments using the specified SourceData + * + * @param Segments (In/Out) Mutable array of compiled segments to be processed + * @param SourceData The source section data that is being compiled. + */ + MOVIESCENE_API void ProcessSegments(TArray& Segments, const TArrayView& SourceData) const; + + /** + * Check whether the resulting segments be empty + */ + bool AllowEmptySegments() const + { + return bAllowEmptySegments; + } + + /** + * Implementation function to insert empty space between two other segments or at the start/end + * + * @param Range The time range for the potential new segment + * @param PreviousSegment A pointer to the previous segment if there is one. Null if the empty space is before the first segment. + * @param Next A pointer to the subsequent segment if there is one. Null if the empty space is after the last segment. + * + * @return An optional new segment to define + */ virtual TOptional InsertEmptySpace(const TRange& Range, const FMovieSceneSegment* PreviousSegment, const FMovieSceneSegment* NextSegment) const { return TOptional(); } + /** + * Blend the specified segment by performing some specific processing such as sorting or filtering + * + * @param Segment The segment to process. Segment.Impls[].ImplIndex relates to indices with SourceData + * @param SourceData The source section data that is being compiled. + */ virtual void BlendSegment(FMovieSceneSegment& Segment, const TArrayView& SourceData) const { } + /** + * Called after all segments have been calculated and blended for any additional processing + * + * @param Segments The segments to process. Segments[].Impls[].ImplIndex relates to indices with SourceData + * @param SourceData The source section data that is being compiled. + */ virtual void PostProcessSegments(TArray& Segments, const TArrayView& SourceData) const { } - MOVIESCENE_API void ProcessSegments(TArray& Segments, const TArrayView& SourceData) const; - protected: + /** Private implementation function for inserting a segment at the specified index */ bool InsertSegment(TArray& Segments, int32 Index, const TArrayView& SourceData) const; + /** Whether we allow empty segments or not */ bool bAllowEmptySegments; }; -struct FMovieSceneSegmentCompilerResult +/** Enumeration specifying how impl indices should be specified in resulting FMovieSceneSegments */ +enum class EMovieSceneSegmentIndexSpace : uint8 { - TArray Segments; + /** FSectionEvaluationData::ImplIndex should point to indices within the original source data */ + SourceDataIndex, + /** FSectionEvaluationData::ImplIndex should match those specified within the original source data */ + ActualImplIndex, }; +/** Movie scene segment compiler that takes an unordered, arbitrary array of section data, and produces an ordered array of segments that define which implementations occur at which time ranges */ struct FMovieSceneSegmentCompiler { - MOVIESCENE_API TArray Compile(const TArrayView& Data, const FMovieSceneSegmentCompilerRules* Rules = nullptr); + /** + * Compiles the specified source data into an array of segments + * + * @param SourceData Unordered data to compile. May contain duplicates or overlapping time ranges. + * @param Rules (Optional) Compiler rulse structure to compile with + * @param IndexSpace (Optional) How the resulting segments should relate to the source data (either indices into the data, or actual indices specified from the data) + * + * @return An ordered array of segments that define unique combinations of overlapping source data. Segments are guaranteed to not overlap, may be contiguous and may contain gaps depending on compiler rules + */ + MOVIESCENE_API TArray Compile(TArrayView Data, const FMovieSceneSegmentCompilerRules* Rules = nullptr, EMovieSceneSegmentIndexSpace IndexSpace = EMovieSceneSegmentIndexSpace::ActualImplIndex); private: + /** + * Add any EvalData currently considered as overlapping to their relevant segments + */ void CloseCompletedSegments(); + /** + * Find and index into OverlappingSections where the supplied eval data is considered to match + * + * @param InEvalData Evaluation data to find an index for + * @return A valid index into OverlappingSections, or INDEX_NONE + */ + int32 FindOverlappingIndex(FSectionEvaluationData InEvalData) const; + + /** Private structure that specifies where a particular evaluation starts or ends */ struct FBound { FBound(FSectionEvaluationData InEvalData, TRangeBound InBound) : EvalData(InEvalData), Bound(InBound) {} @@ -67,45 +136,60 @@ private: TRangeBound Bound; }; + /** Current read indices for the lower and upper bounds */ int32 LowerReadIndex, UpperReadIndex; + /** Arrays of lower and upper bounds sorted ascending and descending respectively. */ TArray LowerBounds, UpperBounds; + /** Ordered array of compiled segments */ TArray CompiledSegments; + /** Section evaluation data for sections that are being evaluated at the current time of processing */ TArray> OverlappingSections; + /** Reference counts for any of the entries in OverlappingSections that map to the same object (necessary for when the same eval data is specified in multiple source data elements) */ TArray> OverlappingRefCounts; + /** The index space that we are generating for */ + EMovieSceneSegmentIndexSpace IndexSpace; + /** The source section data */ + TArrayView SourceData; }; +/** Resulting structure from FMovieSceneTrackCompiler::Compile */ struct FMovieSceneTrackEvaluationField { + /** The compiled segments, ordered by time range, with no overlaps. May contain empty space */ TArray Segments; }; +/** Structure used for compiling a UMovieSceneTrack using specific rules for compiling its rows, and combining such rows */ struct FMovieSceneTrackCompiler { - struct FMovieSceneSectionRowData : FMovieSceneSectionData - { - FMovieSceneSectionRowData(int32 InActualSectionIndex, const TRange& InBounds, FSectionEvaluationData InRowEvalData, int32 InPriority = 0) - : FMovieSceneSectionData(InBounds, InRowEvalData, InPriority) - , ActualSectionIndex(InActualSectionIndex) - {} - - int32 ActualSectionIndex; - }; - + /** A row in a track */ struct FRow { - TArray> Sections; + /** All the sections contained in the row */ + TArray> Sections; + /** Compiler rules used to compile this row */ const FMovieSceneSegmentCompilerRules* CompileRules; }; struct FRows { + /** Construction from an unordered array of sections, and an optional compiler rules object for compiling each row */ MOVIESCENE_API FRows(const TArray& Sections, const FMovieSceneSegmentCompilerRules* CompileRules = nullptr); + /** Array of rows */ TArray> Rows; }; - MOVIESCENE_API FMovieSceneTrackEvaluationField Compile(const TArrayView& Rows, const FMovieSceneSegmentCompilerRules* Rules = nullptr); + /** + * Compile the specified rows using the specified compiler rules for combining each row + * + * @param Rows The rows to compile + * @param Rules Compiler rules that define how the rows should be blended together + * + * @return An ordered array of segments that define unique combinations of overlapping sections. Segments are guaranteed to not overlap, may be contiguous and may contain gaps depending on compiler rules + */ + MOVIESCENE_API FMovieSceneTrackEvaluationField Compile(TArrayView Rows, const FMovieSceneSegmentCompilerRules* Rules = nullptr); }; diff --git a/Engine/Source/Runtime/MovieScene/Public/Evaluation/MovieSceneEvaluationTemplate.h b/Engine/Source/Runtime/MovieScene/Public/Evaluation/MovieSceneEvaluationTemplate.h index 5c04030d7f0d..91c255771467 100644 --- a/Engine/Source/Runtime/MovieScene/Public/Evaluation/MovieSceneEvaluationTemplate.h +++ b/Engine/Source/Runtime/MovieScene/Public/Evaluation/MovieSceneEvaluationTemplate.h @@ -138,6 +138,14 @@ public: return bKeepStaleTracks ? StaleTracks.Find(Identifier.Value) : nullptr; } + /** + * Test whether the specified track identifier relates to a stale track + */ + bool IsTrackStale(FMovieSceneTrackIdentifier Identifier) const + { + return bKeepStaleTracks ? StaleTracks.Contains(Identifier.Value) : false; + } + /** * Add a new track for the specified identifier */ @@ -185,7 +193,7 @@ public: */ const FMovieSceneTemplateGenerationLedger& GetLedger() const { - return Ledger; + return TemplateLedger; } private: @@ -210,7 +218,7 @@ public: private: UPROPERTY() - FMovieSceneTemplateGenerationLedger Ledger; + FMovieSceneTemplateGenerationLedger TemplateLedger; public: diff --git a/Engine/Source/Runtime/MovieScene/Public/Evaluation/MovieSceneEvaluationTemplateInstance.h b/Engine/Source/Runtime/MovieScene/Public/Evaluation/MovieSceneEvaluationTemplateInstance.h index ba25302ed371..2197ada4f8bf 100644 --- a/Engine/Source/Runtime/MovieScene/Public/Evaluation/MovieSceneEvaluationTemplateInstance.h +++ b/Engine/Source/Runtime/MovieScene/Public/Evaluation/MovieSceneEvaluationTemplateInstance.h @@ -11,6 +11,7 @@ #include "Evaluation/MovieSceneEvaluationTemplate.h" class UMovieSceneSequence; +struct FDelayedPreAnimatedStateRestore; /** * An instance of an evaluation template. Fast to initialize and evaluate. @@ -205,28 +206,36 @@ private: /** * Gather entities that are to be evaluated this frame */ - void GatherEntities(const FMovieSceneEvaluationGroup& Group, IMovieScenePlayer& Player, FMovieSceneSequenceID OverrideRootID); + void GatherEntities(const FMovieSceneEvaluationGroup& Group, IMovieScenePlayer& Player); /** * Process entities that are newly evaluated, and those that are no longer being evaluated */ - void CallSetupTearDown(IMovieScenePlayer& Player); + void CallSetupTearDown(IMovieScenePlayer& Player, FDelayedPreAnimatedStateRestore* DelayedRestore = nullptr); /** * Evaluate a particular group of a segment */ - void EvaluateGroup(const FMovieSceneEvaluationGroup& Group, const FMovieSceneContext& Context, IMovieScenePlayer& Player, FMovieSceneExecutionTokens& ExecutionTokens, FMovieSceneSequenceID OverrideRootID) const; + void EvaluateGroup(const FMovieSceneEvaluationGroup& Group, const FMovieSceneContext& Context, IMovieScenePlayer& Player, FMovieSceneExecutionTokens& ExecutionTokens) const; /** - * Remap the specified sequence ID from relative to OverrideRootID, to the Root + * Remap the specified sequence ID based on the currently evaluating sequence path, to the Root * * @param SequenceID The sequence ID to find a template for - * @param OverrideRootID Overriden ID that we're treating as the root * @return Pointer to a template instance, or nullptr if the ID was not found */ - FORCEINLINE FMovieSceneSequenceID GetSequenceIdForRoot(FMovieSceneSequenceID SequenceID, FMovieSceneSequenceID OverrideRootID) const + FORCEINLINE FMovieSceneSequenceID GetSequenceIdForRoot(FMovieSceneSequenceID SequenceID) const { - return OverrideRootID == MovieSceneSequenceID::Root ? SequenceID : SequenceID.AccumulateParentID(OverrideRootID); + if (!ReverseOverrideRootPath.Num()) + { + return SequenceID; + } + + for (FMovieSceneSequenceID Parent : ReverseOverrideRootPath) + { + SequenceID = SequenceID.AccumulateParentID(Parent); + } + return SequenceID; } /** @@ -237,7 +246,7 @@ private: */ FORCEINLINE const FMovieSceneEvaluationTemplateInstance& GetInstanceChecked(FMovieSceneSequenceIDRef SequenceID) const { - return SequenceID == MovieSceneSequenceID::Root ? RootInstance : *SubInstances.Find(SequenceID); + return SequenceID == MovieSceneSequenceID::Root ? RootInstance : SubInstances.FindChecked(SequenceID); } /** @@ -280,6 +289,9 @@ private: /** Template store responsible for supplying templates for a given sequence */ TSharedPtr TemplateStore; + /** A reverse path of deterministic sequence IDs required to accumulate from local -> root */ + TArray> ReverseOverrideRootPath; + /** True when any of our templates are out of date, and need reinitializing */ bool bIsDirty; diff --git a/Engine/Source/Runtime/MovieScene/Public/Evaluation/MovieSceneSegment.h b/Engine/Source/Runtime/MovieScene/Public/Evaluation/MovieSceneSegment.h index 7e70fc011976..b4b323a864cc 100644 --- a/Engine/Source/Runtime/MovieScene/Public/Evaluation/MovieSceneSegment.h +++ b/Engine/Source/Runtime/MovieScene/Public/Evaluation/MovieSceneSegment.h @@ -29,8 +29,23 @@ struct FSectionEvaluationData { GENERATED_BODY() - FSectionEvaluationData() : ForcedTime(TNumericLimits::Lowest()), Flags(ESectionEvaluationFlags::None) {} - explicit FSectionEvaluationData(int32 InImplIndex, float InForcedTime = TNumericLimits::Lowest()) : ImplIndex(InImplIndex), ForcedTime(InForcedTime), Flags(ESectionEvaluationFlags::None) {} + /** Default constructor */ + FSectionEvaluationData() : ImplIndex(-1), ForcedTime(TNumericLimits::Lowest()), Flags(ESectionEvaluationFlags::None) {} + + /** Construction from an implementaiton index (probably a section) */ + explicit FSectionEvaluationData(int32 InImplIndex) + : ImplIndex(InImplIndex), ForcedTime(TNumericLimits::Lowest()), Flags(ESectionEvaluationFlags::None) + {} + + /** Construction from an implementaiton index and a time to force evaluation at */ + FSectionEvaluationData(int32 InImplIndex, float InForcedTime) + : ImplIndex(InImplIndex), ForcedTime(InForcedTime), Flags(ESectionEvaluationFlags::None) + {} + + /** Construction from an implementaiton index and custom eval flags */ + FSectionEvaluationData(int32 InImplIndex, ESectionEvaluationFlags InFlags) + : ImplIndex(InImplIndex), ForcedTime(TNumericLimits::Lowest()), Flags(InFlags) + {} friend bool operator==(FSectionEvaluationData A, FSectionEvaluationData B) { @@ -76,7 +91,7 @@ struct FMovieSceneSegment : Range(InRange) {} - FMovieSceneSegment(const TRange& InRange, TArrayView InApplicationImpls) + FMovieSceneSegment(const TRange& InRange, TArrayView InApplicationImpls) : Range(InRange) { Impls.Reserve(InApplicationImpls.Num()); @@ -86,11 +101,6 @@ struct FMovieSceneSegment } } - FMovieSceneSegment(const TRange& InRange, std::initializer_list InSectionEvaluationData) - : Range(InRange) - , Impls(InSectionEvaluationData) - {} - /** Custom serializer to accomodate the inline allocator on our array */ bool Serialize(FArchive& Ar) { diff --git a/Engine/Source/Runtime/MovieScene/Public/IMovieScenePlayer.h b/Engine/Source/Runtime/MovieScene/Public/IMovieScenePlayer.h index ef83c9b19430..77a28943d1e2 100644 --- a/Engine/Source/Runtime/MovieScene/Public/IMovieScenePlayer.h +++ b/Engine/Source/Runtime/MovieScene/Public/IMovieScenePlayer.h @@ -53,6 +53,7 @@ struct EMovieSceneViewportParams class IMovieScenePlayer { public: + virtual ~IMovieScenePlayer() { } /** * Access the evaluation template that we are playing back diff --git a/Engine/Source/Runtime/MovieScene/Public/MovieScene.h b/Engine/Source/Runtime/MovieScene/Public/MovieScene.h index 67e4b3ab4479..f572e9f7238b 100644 --- a/Engine/Source/Runtime/MovieScene/Public/MovieScene.h +++ b/Engine/Source/Runtime/MovieScene/Public/MovieScene.h @@ -13,66 +13,13 @@ #include "MovieScenePossessable.h" #include "MovieSceneSignedObject.h" #include "MovieSceneSequenceID.h" +#include "MovieSceneObjectBindingID.h" #include "MovieScene.generated.h" class UMovieSceneFolder; class UMovieSceneSection; class UMovieSceneTrack; -USTRUCT(BlueprintType, meta=(HasNativeMake)) -struct FMovieSceneObjectBindingID -{ - FMovieSceneObjectBindingID() - : SequenceID(int32(MovieSceneSequenceID::Root.GetInternalValue())) - { - } - - FMovieSceneObjectBindingID(const FGuid& InGuid, FMovieSceneSequenceID InSequenceID) - : SequenceID(int32(InSequenceID.GetInternalValue())), Guid(InGuid) - { - } - - GENERATED_BODY() - - /** Access the identifier for the sequence in which the object resides */ - FMovieSceneSequenceID GetSequenceID() const - { - return FMovieSceneSequenceID(uint32(SequenceID)); - } - - /** Access the guid that identifies the object binding within the sequence */ - const FGuid& GetObjectBindingID() const - { - return Guid; - } - - friend uint32 GetTypeHash(const FMovieSceneObjectBindingID& A) - { - return GetTypeHash(A.Guid) ^ GetTypeHash(A.SequenceID); - } - - friend bool operator==(const FMovieSceneObjectBindingID& A, const FMovieSceneObjectBindingID& B) - { - return A.Guid == B.Guid && A.SequenceID == B.SequenceID; - } - - friend bool operator!=(const FMovieSceneObjectBindingID& A, const FMovieSceneObjectBindingID& B) - { - return A.Guid != B.Guid || A.SequenceID != B.SequenceID; - } - -private: - - /** Sequence ID stored as an int32 so that it can be used in the blueprint VM */ - UPROPERTY() - int32 SequenceID; - - /** Identifier for the object binding within the sequence */ - UPROPERTY(EditAnywhere, Category="Binding") - FGuid Guid; -}; - - /** @todo: remove this type when support for intrinsics on TMap values is added? */ USTRUCT() struct FMovieSceneExpansionState @@ -641,10 +588,6 @@ protected: /** Perform legacy upgrade of time ranges */ void UpgradeTimeRanges(); - /** Perform legacy upgrade of track rows */ - void UpgradeTrackRows(); - void UpgradeTrackRow(UMovieSceneTrack*); - private: // Small value added for fixed frame interval calculations to make up for consistency in diff --git a/Engine/Source/Runtime/MovieScene/Public/MovieSceneBindingOverridesInterface.h b/Engine/Source/Runtime/MovieScene/Public/MovieSceneBindingOverridesInterface.h index 3b7eba1dd47e..0bef138a67b4 100644 --- a/Engine/Source/Runtime/MovieScene/Public/MovieSceneBindingOverridesInterface.h +++ b/Engine/Source/Runtime/MovieScene/Public/MovieSceneBindingOverridesInterface.h @@ -5,6 +5,7 @@ #include "UObject/Interface.h" #include "UObject/ObjectMacros.h" +#include "MovieSceneSequenceID.h" #include "MovieSceneBindingOverridesInterface.generated.h" diff --git a/Engine/Source/Runtime/MovieScene/Public/MovieSceneClipboard.h b/Engine/Source/Runtime/MovieScene/Public/MovieSceneClipboard.h index b39ae400658d..c80636b45db4 100644 --- a/Engine/Source/Runtime/MovieScene/Public/MovieSceneClipboard.h +++ b/Engine/Source/Runtime/MovieScene/Public/MovieSceneClipboard.h @@ -4,6 +4,7 @@ #include "CoreMinimal.h" #include "MovieSceneTrack.h" +#include "InlineValue.h" #if WITH_EDITOR @@ -33,19 +34,14 @@ public: template FMovieSceneClipboardKey(float InTime, T InValue) : Time(InTime) - , bIsSet(true) + , Data(TKey(MoveTemp(InValue))) { - static_assert(sizeof(TKey) <= MaxDataSizeBytes, "Cannot use objects greater than MaxDataSizeBytes with this type"); - new(Data) TKey(MoveTemp(InValue)); } /** Copy construction/assignment */ FMovieSceneClipboardKey(const FMovieSceneClipboardKey& In); FMovieSceneClipboardKey& operator=(const FMovieSceneClipboardKey& In); - /** Destructor */ - ~FMovieSceneClipboardKey(); - /** Get the time at which this key is defined */ float GetTime() const; @@ -74,21 +70,24 @@ public: template bool TryGetValue(T& Value) const { - auto& Impl = reinterpret_cast(Data); + if (!Data.IsValid()) + { + return false; + } // Check for same type - if (Impl.GetTypeName() == MovieSceneClipboard::GetKeyTypeName()) + if (Data->GetTypeName() == MovieSceneClipboard::GetKeyTypeName()) { - Value = static_cast&>(Impl).Value; + Value = static_cast&>(Data.GetValue()).Value; return true; } // Check for conversion possibility - FConversionFunction* ConversionFunction = Impl.FindConversionTo(MovieSceneClipboard::GetKeyTypeName()); + FConversionFunction* ConversionFunction = Data->FindConversionTo(MovieSceneClipboard::GetKeyTypeName()); if (ConversionFunction) { FMovieSceneClipboardKey Key = ConversionFunction->operator()(*this); - Value = reinterpret_cast&>(Key.Data).Value; + Value = static_cast&>(Key.Data.GetValue()).Value; return true; } @@ -99,16 +98,11 @@ private: typedef TFunction FConversionFunction; - /** - * Destroy the data contained within this key - */ - void Destroy(); - /** Abstract base class for all key types */ struct IKey { virtual ~IKey() {} - virtual void CopyTo(void* Ptr) const = 0; + virtual void CopyTo(TInlineValue& OutDest) const = 0; virtual FConversionFunction* FindConversionTo(FName DestinationTypeName) const = 0; virtual FName GetTypeName() const = 0; }; @@ -137,9 +131,9 @@ private: } /** Copy this value to another destination ptr */ - virtual void CopyTo(void* Ptr) const + virtual void CopyTo(TInlineValue& OutDest) const { - new (Ptr) TKey(*this); + OutDest = TKey(Value); } /** The actual value */ @@ -150,11 +144,7 @@ private: float Time; /** Type-erased bytes containing the key's value */ - static const uint32 MaxDataSizeBytes = 48; - uint8 Data[MaxDataSizeBytes]; - - /** true when Data is a valid IKey&, false otherwise */ - bool bIsSet; + TInlineValue Data; public: @@ -163,7 +153,7 @@ public: static void DefineConversion(TFunction InFunction) { auto Facade = [=](const FMovieSceneClipboardKey& InKey) -> FMovieSceneClipboardKey { - const TKey& TypedKey = reinterpret_cast&>(InKey.Data); + const TKey& TypedKey = static_cast&>(InKey.Data.GetValue()); return FMovieSceneClipboardKey(InKey.GetTime(), InFunction(TypedKey.Value)); }; diff --git a/Engine/Source/Runtime/MovieScene/Public/MovieSceneExecutionToken.h b/Engine/Source/Runtime/MovieScene/Public/MovieSceneExecutionToken.h index 596548a5a81d..3d9a4351c4d2 100644 --- a/Engine/Source/Runtime/MovieScene/Public/MovieSceneExecutionToken.h +++ b/Engine/Source/Runtime/MovieScene/Public/MovieSceneExecutionToken.h @@ -78,6 +78,8 @@ typedef TInlineValue IMovieScenePreAnimat */ struct IMovieScenePreAnimatedGlobalTokenProducer { + virtual ~IMovieScenePreAnimatedGlobalTokenProducer() { } + /** * Perform any initial set up required to animate the playback environment * @note Only ever called when environment is in an unanimated state, as according to the AnimTypeID that this producer is operating on. diff --git a/Engine/Source/Runtime/MovieScene/Public/MovieSceneFwd.h b/Engine/Source/Runtime/MovieScene/Public/MovieSceneFwd.h index a75c843d1122..7d55993243a5 100644 --- a/Engine/Source/Runtime/MovieScene/Public/MovieSceneFwd.h +++ b/Engine/Source/Runtime/MovieScene/Public/MovieSceneFwd.h @@ -6,6 +6,7 @@ #include "Stats/Stats.h" #include "MovieSceneSequenceID.h" +UENUM() namespace EMovieScenePlayerStatus { enum Type diff --git a/Engine/Source/Runtime/MovieScene/Public/MovieSceneObjectBindingID.h b/Engine/Source/Runtime/MovieScene/Public/MovieSceneObjectBindingID.h new file mode 100644 index 000000000000..b001d8b9559b --- /dev/null +++ b/Engine/Source/Runtime/MovieScene/Public/MovieSceneObjectBindingID.h @@ -0,0 +1,111 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "Misc/Guid.h" +#include "MovieSceneFwd.h" +#include "MovieSceneSequenceID.h" +#include "MovieSceneObjectBindingID.generated.h" + +struct FMovieSceneSequenceHierarchy; + +/** Enumeration specifying how a movie scene object binding ID relates to the sequence */ +UENUM() +enum class EMovieSceneObjectBindingSpace : uint8 +{ + /** The object binding sequence ID resolves from a local sequence (ie, it may need to accumulate a parent sequence ID before it resolves correctly) */ + Local, + /** The object binding sequence ID resolves from the root of the sequence */ + Root, +}; + + +/** Persistent identifier to a specific object binding within a sequence hierarchy. */ +USTRUCT(BlueprintType, meta=(HasNativeMake)) +struct FMovieSceneObjectBindingID +{ + GENERATED_BODY() + + /** Default construction to an invalid object binding ID */ + FMovieSceneObjectBindingID() + : SequenceID(int32(MovieSceneSequenceID::Root.GetInternalValue())), Space(EMovieSceneObjectBindingSpace::Root) + { + } + + /** Construction from an object binding guid, and the specific sequence instance ID in which it resides */ + FMovieSceneObjectBindingID(const FGuid& InGuid, FMovieSceneSequenceID InSequenceID, EMovieSceneObjectBindingSpace InSpace = EMovieSceneObjectBindingSpace::Root) + : SequenceID(int32(InSequenceID.GetInternalValue())), Space(InSpace), Guid(InGuid) + { + } + + /** + * Check whether this object binding ID has been set to something valied + * @note: does not imply that the ID resolves to a valid object + */ + bool IsValid() const + { + return Guid.IsValid(); + } + + /** + * Access the identifier for the sequence in which the object binding resides + */ + FMovieSceneSequenceID GetSequenceID() const + { + return FMovieSceneSequenceID(uint32(SequenceID)); + } + + /** + * Access the guid that identifies the object binding within the sequence + */ + const FGuid& GetGuid() const + { + return Guid; + } + + /** + * Access how this binding's sequence ID relates to the master sequence + */ + EMovieSceneObjectBindingSpace GetBindingSpace() const + { + return Space; + } + + /** + * Resolve this binding ID from a local binding to be accessible from the root, by treating the specified local sequence ID as this binding's root + */ + MOVIESCENE_API FMovieSceneObjectBindingID ResolveLocalToRoot(FMovieSceneSequenceID LocalSequenceID, const FMovieSceneSequenceHierarchy& Hierarchy) const; + +public: + + friend uint32 GetTypeHash(const FMovieSceneObjectBindingID& A) + { + return GetTypeHash(A.Guid) ^ GetTypeHash(A.SequenceID); + } + + friend bool operator==(const FMovieSceneObjectBindingID& A, const FMovieSceneObjectBindingID& B) + { + return A.Guid == B.Guid && A.SequenceID == B.SequenceID; + } + + friend bool operator!=(const FMovieSceneObjectBindingID& A, const FMovieSceneObjectBindingID& B) + { + return A.Guid != B.Guid || A.SequenceID != B.SequenceID; + } + +private: + + /** Sequence ID stored as an int32 so that it can be used in the blueprint VM */ + UPROPERTY() + int32 SequenceID; + + /** The binding's resolution space */ + UPROPERTY() + EMovieSceneObjectBindingSpace Space; + + /** Identifier for the object binding within the sequence */ + UPROPERTY(EditAnywhere, Category="Binding") + FGuid Guid; +}; \ No newline at end of file diff --git a/Engine/Source/Runtime/MovieScene/Public/MovieSceneSection.h b/Engine/Source/Runtime/MovieScene/Public/MovieSceneSection.h index 078e84e7848d..90bf4432746b 100644 --- a/Engine/Source/Runtime/MovieScene/Public/MovieSceneSection.h +++ b/Engine/Source/Runtime/MovieScene/Public/MovieSceneSection.h @@ -335,12 +335,6 @@ public: /** Sets the time for the key referenced by the supplied key handle. */ virtual void SetKeyTime( FKeyHandle KeyHandle, float Time ) PURE_VIRTUAL( UAISenseEvent::SetKeyTime, ); - /** For backwards compatibility, allow this section to do work when upgrading the section's track rows - * - * @param InEvaluationRange The new evaluation range for this section - */ - virtual void PostLoadUpgradeTrackRow(const TRange& InEvaluationRange) { } - /** * When guid bindings are updated to allow this section to fix-up any internal bindings * diff --git a/Engine/Source/Runtime/MovieScene/Public/MovieSceneSequenceID.h b/Engine/Source/Runtime/MovieScene/Public/MovieSceneSequenceID.h index a4e38d8efcdb..5c5cd8c4b387 100644 --- a/Engine/Source/Runtime/MovieScene/Public/MovieSceneSequenceID.h +++ b/Engine/Source/Runtime/MovieScene/Public/MovieSceneSequenceID.h @@ -61,6 +61,12 @@ struct FMovieSceneSequenceID { return Value; } + + FORCEINLINE bool IsValid() const + { + return Value != -1; + } + private: UPROPERTY() diff --git a/Engine/Source/Runtime/MovieScene/Public/MovieSceneSequencePlayer.h b/Engine/Source/Runtime/MovieScene/Public/MovieSceneSequencePlayer.h index 50b8d3e2d176..5e2b28df6a99 100644 --- a/Engine/Source/Runtime/MovieScene/Public/MovieSceneSequencePlayer.h +++ b/Engine/Source/Runtime/MovieScene/Public/MovieSceneSequencePlayer.h @@ -25,6 +25,10 @@ struct FMovieSceneSequencePlaybackSettings , bRandomStartTime(false) , StartTime(0.f) , bRestoreState(false) + , bDisableMovementInput(false) + , bDisableLookAtInput(false) + , bHidePlayer(false) + , bHideHud(false) { } GENERATED_BODY() @@ -49,6 +53,22 @@ struct FMovieSceneSequencePlaybackSettings UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Playback") bool bRestoreState; + /** Disable Input from player during play */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Cinematic") + bool bDisableMovementInput; + + /** Disable LookAt Input from player during play */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Cinematic") + bool bDisableLookAtInput; + + /** Hide Player Pawn during play */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Cinematic") + bool bHidePlayer; + + /** Hide HUD during play */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Cinematic") + bool bHideHud; + /** Interface that defines overridden bindings for this sequence */ UPROPERTY() TScriptInterface BindingOverrides; @@ -101,10 +121,18 @@ public: UFUNCTION(BlueprintCallable, Category="Game|Cinematic") void Pause(); + /** Scrub playback. */ + UFUNCTION(BlueprintCallable, Category="Game|Cinematic") + void Scrub(); + /** Stop playback. */ UFUNCTION(BlueprintCallable, Category="Game|Cinematic") void Stop(); + /** Stop playback and go to the end. */ + UFUNCTION(BlueprintCallable, Category="Game|Cinematic") + void StopAndGoToEnd(); + /** Get the current playback position */ UFUNCTION(BlueprintCallable, Category="Game|Cinematic") float GetPlaybackPosition() const; @@ -117,6 +145,14 @@ public: UFUNCTION(BlueprintCallable, Category="Game|Cinematic") void SetPlaybackPosition(float NewPlaybackPosition); + /** + * Jump to new playback position + * @param NewPlaybackPosition - The new playback position to set. + * This can be used to update sequencer repeatedly, as if in a scrubbing state + */ + UFUNCTION(BlueprintCallable, Category="Game|Cinematic") + void JumpToPosition(float NewPlaybackPosition); + /** Check whether the sequence is actively playing. */ UFUNCTION(BlueprintCallable, Category="Game|Cinematic") bool IsPlaying() const; @@ -169,6 +205,10 @@ public: UPROPERTY(BlueprintAssignable, Category="Game|Cinematic") FOnMovieSceneSequencePlayerEvent OnPause; + /** Event triggered when the level sequence player finishes naturally (without explicitly calling stop) */ + UPROPERTY(BlueprintAssignable, Category = "Game|Cinematic") + FOnMovieSceneSequencePlayerEvent OnFinished; + public: @@ -184,6 +224,9 @@ public: /** Initialize this player with a sequence and some settings */ void Initialize(UMovieSceneSequence* InSequence, const FMovieSceneSequencePlaybackSettings& InSettings); + /** Begin play called */ + virtual void BeginPlay() {}; + public: /** @@ -196,9 +239,9 @@ protected: void PlayInternal(); - void UpdateMovieSceneInstance(FMovieSceneEvaluationRange InRange); + void UpdateMovieSceneInstance(FMovieSceneEvaluationRange InRange, TOptional OptionalStatus = TOptional()); - void UpdateTimeCursorPosition(float NewPosition); + void UpdateTimeCursorPosition(float NewPosition, TOptional OptionalStatus = TOptional()); bool ShouldStopOrLoop(float NewPosition) const; @@ -233,9 +276,9 @@ private: protected: - /** Whether we're currently playing. If false, then sequence playback is paused or was never started. */ + /** Movie player status. */ UPROPERTY() - uint32 bIsPlaying : 1; + TEnumAsByte Status; /** Whether we're currently playing in reverse. */ UPROPERTY() diff --git a/Engine/Source/Runtime/MovieScene/Public/MovieSceneSpawnable.h b/Engine/Source/Runtime/MovieScene/Public/MovieSceneSpawnable.h index 3d496615a138..381b1418178f 100644 --- a/Engine/Source/Runtime/MovieScene/Public/MovieSceneSpawnable.h +++ b/Engine/Source/Runtime/MovieScene/Public/MovieSceneSpawnable.h @@ -78,6 +78,17 @@ public: return ObjectTemplate; } + /** + * Get the template object for this spawnable + * + * @return Object template + * @see GetGuid, GetName + */ + const UObject* GetObjectTemplate() const + { + return ObjectTemplate; + } + /** * Copy the specified object into this spawnable's template * diff --git a/Engine/Source/Runtime/MovieSceneCapture/Private/AutomatedLevelSequenceCapture.cpp b/Engine/Source/Runtime/MovieSceneCapture/Private/AutomatedLevelSequenceCapture.cpp index 2377f957d7a0..ef550370291e 100644 --- a/Engine/Source/Runtime/MovieSceneCapture/Private/AutomatedLevelSequenceCapture.cpp +++ b/Engine/Source/Runtime/MovieSceneCapture/Private/AutomatedLevelSequenceCapture.cpp @@ -389,6 +389,10 @@ void UAutomatedLevelSequenceCapture::SetupFrameRange() Actor->SequencePlayer->SetPlaybackRange( (float)PlaybackStartFrame / (float)Settings.FrameRate, (float)PlaybackEndFrame / (float)Settings.FrameRate ); + Actor->SequencePlayer->SetPlaybackPosition(0.f); + + const float WarmupTime = WarmUpFrameCount / CachedState.Settings.FrameRate; + Actor->SequencePlayer->SetSnapshotOffsetTime(WarmupTime); } } } @@ -421,6 +425,8 @@ void UAutomatedLevelSequenceCapture::Tick(float DeltaSeconds) // textures to stream in or post processing effects to settle. if( CaptureState == ELevelSequenceCaptureState::DelayBeforeWarmUp ) { + Actor->SequencePlayer->SetPlaybackPosition(0.f); + RemainingDelaySeconds -= DeltaSeconds; if( RemainingDelaySeconds <= 0.0f ) { diff --git a/Engine/Source/Runtime/MovieSceneCapture/Private/FrameGrabber.cpp b/Engine/Source/Runtime/MovieSceneCapture/Private/FrameGrabber.cpp index 8a44c0de9673..2ac32061d135 100644 --- a/Engine/Source/Runtime/MovieSceneCapture/Private/FrameGrabber.cpp +++ b/Engine/Source/Runtime/MovieSceneCapture/Private/FrameGrabber.cpp @@ -76,10 +76,30 @@ void FViewportSurfaceReader::BlockUntilAvailable() void FViewportSurfaceReader::ResolveRenderTarget(const FViewportRHIRef& ViewportRHI, TFunction Callback) { static const FName RendererModuleName( "Renderer" ); + // @todo: JIRA UE-41879 and UE-43829 - added defensive guards against memory trampling on this render command to try and ascertain why it occasionally crashes + uint32 MemoryGuard1 = 0xaffec7ed; + + // Load the renderermodule on the main thread, as the module manager is not thread-safe, and copy the ptr into the render command, along with 'this' (which is protected by BlockUntilAvailable in ~FViewportSurfaceReader()) IRendererModule* RendererModule = &FModuleManager::GetModuleChecked(RendererModuleName); + uint32 MemoryGuard2 = 0xaffec7ed; + IRendererModule* RendererModuleDebug = RendererModule; + auto RenderCommand = [=](FRHICommandListImmediate& RHICmdList){ + // @todo: JIRA UE-41879 and UE-43829. If any of these ensures go off, something has overwritten the memory for this render command (buffer underflow/overflow?) + bool bMemoryTrample = !ensureMsgf(RendererModule, TEXT("RendererModule has become null. This indicates a memory trample.")) || + !ensureMsgf(RendererModule == RendererModuleDebug, TEXT("RendererModule and RendererModuleDebug are not equal (0x%016x != 0x%016x). This indicates a memory trample."), (void*)RendererModule, (void*)RendererModuleDebug) || + !ensureMsgf(MemoryGuard1 == 0xaffec7ed, TEXT("Memory guard 1 is now 0x%08x, expected 0xaffec7ed."), MemoryGuard1) || + !ensureMsgf(MemoryGuard2 == 0xaffec7ed, TEXT("Memory guard 2 is now 0x%08x, expected 0xaffec7ed."), MemoryGuard2); + + if (bMemoryTrample) + { + // In the hope that 'this' is still ok, triggering the event will prevent a deadlock. If it's not ok, this may crash, but it was going to crash anyway + AvailableEvent->Trigger(); + return; + } + const FIntPoint TargetSize(ReadbackTexture->GetSizeX(), ReadbackTexture->GetSizeY()); FPooledRenderTargetDesc OutputDesc = FPooledRenderTargetDesc::Create2DDesc( @@ -90,6 +110,19 @@ void FViewportSurfaceReader::ResolveRenderTarget(const FViewportRHIRef& Viewport TexCreate_RenderTargetable, false); + // @todo: JIRA UE-41879 and UE-43829. If any of these ensures go off, something has overwritten the memory for this render command (buffer underflow/overflow?) + bMemoryTrample = !ensureMsgf(RendererModule, TEXT("RendererModule has become null. This indicates a memory trample.")) || + !ensureMsgf(RendererModule == RendererModuleDebug, TEXT("RendererModule and RendererModuleDebug are not equal (0x%16x != 0x%16x). This indicates a memory trample."), (void*)RendererModule, (void*)RendererModuleDebug) || + !ensureMsgf(MemoryGuard1 == 0xaffec7ed, TEXT("Memory guard 1 is now 0x%08x, expected 0xaffec7ed."), MemoryGuard1) || + !ensureMsgf(MemoryGuard2 == 0xaffec7ed, TEXT("Memory guard 2 is now 0x%08x, expected 0xaffec7ed."), MemoryGuard2); + + if (bMemoryTrample) + { + // In the hope that 'this' is still ok, triggering the event will prevent a deadlock. If it's not ok, this may crash, but it was going to crash anyway + AvailableEvent->Trigger(); + return; + } + TRefCountPtr ResampleTexturePooledRenderTarget; RendererModule->RenderTargetPoolFindFreeElement(RHICmdList, OutputDesc, ResampleTexturePooledRenderTarget, TEXT("ResampleTexture")); check(ResampleTexturePooledRenderTarget); diff --git a/Engine/Source/Runtime/MovieSceneTracks/Private/Evaluation/MovieScene3DAttachTemplate.cpp b/Engine/Source/Runtime/MovieSceneTracks/Private/Evaluation/MovieScene3DAttachTemplate.cpp index 87374f554a50..76053747f795 100644 --- a/Engine/Source/Runtime/MovieSceneTracks/Private/Evaluation/MovieScene3DAttachTemplate.cpp +++ b/Engine/Source/Runtime/MovieSceneTracks/Private/Evaluation/MovieScene3DAttachTemplate.cpp @@ -15,11 +15,31 @@ DECLARE_CYCLE_STAT(TEXT("Attach Track Evaluate"), MovieSceneEval_AttachTrack_Eva DECLARE_CYCLE_STAT(TEXT("Attach Track Token Execute"), MovieSceneEval_AttachTrack_TokenExecute, STATGROUP_MovieSceneEval); -/** A token that sets a component's attach */ -struct F3DAttachTrackToken +struct F3DAttachRuleState { - F3DAttachTrackToken(USceneComponent* InAttachParent, FName InAttachSocketName, bool bInShouldbeAttached) - : AttachParent(InAttachParent) + F3DAttachRuleState(EAttachmentRule InAttachmentLocationRule, EAttachmentRule InAttachmentRotationRule, EAttachmentRule InAttachmentScaleRule, EDetachmentRule InDetachmentLocationRule, EDetachmentRule InDetachmentRotationRule, EDetachmentRule InDetachmentScaleRule) + : AttachmentLocationRule(InAttachmentLocationRule) + , AttachmentRotationRule(InAttachmentRotationRule) + , AttachmentScaleRule(InAttachmentScaleRule) + , DetachmentLocationRule(InDetachmentLocationRule) + , DetachmentRotationRule(InDetachmentRotationRule) + , DetachmentScaleRule(InDetachmentScaleRule) + {} + + EAttachmentRule AttachmentLocationRule; + EAttachmentRule AttachmentRotationRule; + EAttachmentRule AttachmentScaleRule; + EDetachmentRule DetachmentLocationRule; + EDetachmentRule DetachmentRotationRule; + EDetachmentRule DetachmentScaleRule; +}; + + +/** A token that sets a component's attach */ +struct F3DAttachTrackToken : public F3DAttachRuleState +{ + F3DAttachTrackToken(USceneComponent* InAttachParent, FName InAttachSocketName, bool bInShouldbeAttached, EAttachmentRule InAttachmentLocationRule, EAttachmentRule InAttachmentRotationRule, EAttachmentRule InAttachmentScaleRule, EDetachmentRule InDetachmentLocationRule, EDetachmentRule InDetachmentRotationRule, EDetachmentRule InDetachmentScaleRule) + : F3DAttachRuleState(InAttachmentLocationRule, InAttachmentRotationRule, InAttachmentScaleRule, InDetachmentLocationRule, InDetachmentRotationRule, InDetachmentScaleRule) , AttachSocketName(InAttachSocketName) , bShouldBeAttached(bInShouldbeAttached) {} @@ -30,12 +50,23 @@ struct F3DAttachTrackToken { if (SceneComponent.GetAttachParent() != AttachParent.Get() || SceneComponent.GetAttachSocketName() != AttachSocketName) { - SceneComponent.AttachToComponent(AttachParent.Get(), FAttachmentTransformRules::KeepRelativeTransform, AttachSocketName); + FAttachmentTransformRules AttachmentRules(AttachmentLocationRule, AttachmentRotationRule, AttachmentScaleRule, false); + + SceneComponent.AttachToComponent(AttachParent.Get(), AttachmentRules, AttachSocketName); + } + + // Match the component velocity of the parent. If the attached child has any transformation, the velocity will be + // computed by the 3d transform template. + if (SceneComponent.GetAttachParent()) + { + SceneComponent.ComponentVelocity = SceneComponent.GetAttachParent()->GetComponentVelocity(); } } else { - SceneComponent.DetachFromComponent(FDetachmentTransformRules::KeepRelativeTransform); + FDetachmentTransformRules DetachmentRules(DetachmentLocationRule, DetachmentRotationRule, DetachmentScaleRule, false); + + SceneComponent.DetachFromComponent(DetachmentRules); } } @@ -47,8 +78,8 @@ struct F3DAttachTrackToken /** A movie scene pre-animated token that stores a pre-animated component attachment */ struct F3DAttachTrackPreAnimatedToken : F3DAttachTrackToken, IMovieScenePreAnimatedToken { - F3DAttachTrackPreAnimatedToken(USceneComponent& SceneComponent) - : F3DAttachTrackToken(SceneComponent.GetAttachParent(), SceneComponent.GetAttachSocketName(), true) + F3DAttachTrackPreAnimatedToken(USceneComponent& SceneComponent, EAttachmentRule InAttachmentLocationRule, EAttachmentRule InAttachmentRotationRule, EAttachmentRule InAttachmentScaleRule, EDetachmentRule InDetachmentLocationRule, EDetachmentRule InDetachmentRotationRule, EDetachmentRule InDetachmentScaleRule) + : F3DAttachTrackToken(SceneComponent.GetAttachParent(), SceneComponent.GetAttachSocketName(), true, InAttachmentLocationRule, InAttachmentRotationRule, InAttachmentScaleRule, InDetachmentLocationRule, InDetachmentRotationRule, InDetachmentScaleRule) {} virtual void RestoreState(UObject& InObject, IMovieScenePlayer& Player) override @@ -60,18 +91,24 @@ struct F3DAttachTrackPreAnimatedToken : F3DAttachTrackToken, IMovieScenePreAnima // Detach if there was no pre-existing parent if (!AttachParent.IsValid()) { - SceneComponent->DetachFromComponent(FDetachmentTransformRules::KeepRelativeTransform); + FDetachmentTransformRules DetachmentRules(DetachmentLocationRule, DetachmentRotationRule, DetachmentScaleRule, false); + + SceneComponent->DetachFromComponent(DetachmentRules); } } }; -struct F3DAttachTokenProducer : IMovieScenePreAnimatedTokenProducer +struct F3DAttachTokenProducer : F3DAttachRuleState, IMovieScenePreAnimatedTokenProducer { + F3DAttachTokenProducer(EAttachmentRule InAttachmentLocationRule, EAttachmentRule InAttachmentRotationRule, EAttachmentRule InAttachmentScaleRule, EDetachmentRule InDetachmentLocationRule, EDetachmentRule InDetachmentRotationRule, EDetachmentRule InDetachmentScaleRule) + : F3DAttachRuleState(InAttachmentLocationRule, InAttachmentRotationRule, InAttachmentScaleRule, InDetachmentLocationRule, InDetachmentRotationRule, InDetachmentScaleRule) + {} + /** Cache the existing state of an object before moving it */ virtual IMovieScenePreAnimatedTokenPtr CacheExistingState(UObject& Object) const override { USceneComponent* SceneComponent = CastChecked(&Object); - return F3DAttachTrackPreAnimatedToken(*SceneComponent); + return F3DAttachTrackPreAnimatedToken(*SceneComponent, AttachmentLocationRule, AttachmentRotationRule, AttachmentScaleRule, DetachmentLocationRule, DetachmentRotationRule, DetachmentScaleRule); } }; @@ -80,8 +117,8 @@ struct F3DAttachExecutionToken : IMovieSceneExecutionToken , F3DAttachTrackToken { - F3DAttachExecutionToken(FGuid InAttachGuid, FName InAttachSocketName, FName InAttachComponentName, bool bInShouldBeAttached) - : F3DAttachTrackToken(nullptr, InAttachSocketName, bInShouldBeAttached) + F3DAttachExecutionToken(FGuid InAttachGuid, FName InAttachSocketName, FName InAttachComponentName, bool bInShouldBeAttached, EAttachmentRule InAttachmentLocationRule, EAttachmentRule InAttachmentRotationRule, EAttachmentRule InAttachmentScaleRule, EDetachmentRule InDetachmentLocationRule, EDetachmentRule InDetachmentRotationRule, EDetachmentRule InDetachmentScaleRule) + : F3DAttachTrackToken(nullptr, InAttachSocketName, bInShouldBeAttached, InAttachmentLocationRule, InAttachmentRotationRule, InAttachmentScaleRule, InDetachmentLocationRule, InDetachmentRotationRule, InDetachmentScaleRule) , AttachGuid(InAttachGuid) , AttachComponentName(InAttachComponentName) {} @@ -158,7 +195,11 @@ struct F3DAttachExecutionToken if (SceneComponent) { Player.SavePreAnimatedState(*SceneComponent, FMobilityTokenProducer::GetAnimTypeID(), FMobilityTokenProducer()); - Player.SavePreAnimatedState(*SceneComponent, TMovieSceneAnimTypeID(), F3DAttachTokenProducer()); + + // Attachment can affect transform as well, so save transform state. + Player.SavePreAnimatedState(*SceneComponent, F3DTransformTokenProducer::GetAnimTypeID(), F3DTransformTokenProducer()); + + Player.SavePreAnimatedState(*SceneComponent, TMovieSceneAnimTypeID(), F3DAttachTokenProducer(AttachmentLocationRule, AttachmentRotationRule, AttachmentScaleRule, DetachmentLocationRule, DetachmentRotationRule, DetachmentScaleRule)); AttachParent = GetAttachComponent(ParentActor); @@ -177,6 +218,12 @@ FMovieScene3DAttachSectionTemplate::FMovieScene3DAttachSectionTemplate(const UMo : AttachGuid(Section.GetConstraintId()) , AttachSocketName(Section.AttachSocketName) , AttachComponentName(Section.AttachComponentName) + , AttachmentLocationRule(Section.AttachmentLocationRule) + , AttachmentRotationRule(Section.AttachmentRotationRule) + , AttachmentScaleRule(Section.AttachmentScaleRule) + , DetachmentLocationRule(Section.DetachmentLocationRule) + , DetachmentRotationRule(Section.DetachmentRotationRule) + , DetachmentScaleRule(Section.DetachmentScaleRule) { } @@ -186,5 +233,5 @@ void FMovieScene3DAttachSectionTemplate::Evaluate(const FMovieSceneEvaluationOpe const bool bShouldBeAttached = true; - ExecutionTokens.Add(F3DAttachExecutionToken(AttachGuid, AttachSocketName, AttachComponentName, bShouldBeAttached)); + ExecutionTokens.Add(F3DAttachExecutionToken(AttachGuid, AttachSocketName, AttachComponentName, bShouldBeAttached, AttachmentLocationRule, AttachmentRotationRule, AttachmentScaleRule, DetachmentLocationRule, DetachmentRotationRule, DetachmentScaleRule)); } diff --git a/Engine/Source/Runtime/MovieSceneTracks/Private/Evaluation/MovieScene3DAttachTemplate.h b/Engine/Source/Runtime/MovieSceneTracks/Private/Evaluation/MovieScene3DAttachTemplate.h index 0b06c72bf64f..8b909e0520a8 100644 --- a/Engine/Source/Runtime/MovieSceneTracks/Private/Evaluation/MovieScene3DAttachTemplate.h +++ b/Engine/Source/Runtime/MovieSceneTracks/Private/Evaluation/MovieScene3DAttachTemplate.h @@ -4,6 +4,7 @@ #include "CoreMinimal.h" #include "UObject/ObjectMacros.h" +#include "Engine/EngineTypes.h" #include "Misc/Guid.h" #include "Evaluation/MovieSceneEvalTemplate.h" #include "MovieScene3DAttachTemplate.generated.h" @@ -30,6 +31,30 @@ struct FMovieScene3DAttachSectionTemplate : public FMovieSceneEvalTemplate UPROPERTY() FName AttachComponentName; + /** The attachment location rule */ + UPROPERTY() + EAttachmentRule AttachmentLocationRule; + + /** The attachment rotation rule */ + UPROPERTY() + EAttachmentRule AttachmentRotationRule; + + /** The attachment scale rule */ + UPROPERTY() + EAttachmentRule AttachmentScaleRule; + + /** The detachment location rule */ + UPROPERTY() + EDetachmentRule DetachmentLocationRule; + + /** The detachment rotation rule */ + UPROPERTY() + EDetachmentRule DetachmentRotationRule; + + /** The detachment scale rule */ + UPROPERTY() + EDetachmentRule DetachmentScaleRule; + private: virtual UScriptStruct& GetScriptStructImpl() const override { return *StaticStruct(); } diff --git a/Engine/Source/Runtime/MovieSceneTracks/Private/Evaluation/MovieSceneAudioTemplate.cpp b/Engine/Source/Runtime/MovieSceneTracks/Private/Evaluation/MovieSceneAudioTemplate.cpp index 48378443f219..e63fe6eedc83 100644 --- a/Engine/Source/Runtime/MovieSceneTracks/Private/Evaluation/MovieSceneAudioTemplate.cpp +++ b/Engine/Source/Runtime/MovieSceneTracks/Private/Evaluation/MovieSceneAudioTemplate.cpp @@ -304,7 +304,6 @@ void FMovieSceneAudioSectionTemplateData::EnsureAudioIsPlaying(UAudioComponent& if (bPlaySound) { AudioComponent.bAllowSpatialization = bAllowSpatialization; - AudioComponent.bOverrideAttenuation = bAllowSpatialization; AudioComponent.Stop(); AudioComponent.SetSound(Sound); #if WITH_EDITOR @@ -319,6 +318,7 @@ void FMovieSceneAudioSectionTemplateData::EnsureAudioIsPlaying(UAudioComponent& { AudioComponent.bIsUISound = false; } + AudioComponent.Play((Context.GetTime() - AudioRange.GetLowerBoundValue()) + FMath::Max(AudioStartOffset, 0.f)); if (Context.GetStatus() == EMovieScenePlayerStatus::Scrubbing) diff --git a/Engine/Source/Runtime/MovieSceneTracks/Private/Evaluation/MovieSceneEventTemplate.cpp b/Engine/Source/Runtime/MovieSceneTracks/Private/Evaluation/MovieSceneEventTemplate.cpp index 3a885fc82012..20c5a720f626 100644 --- a/Engine/Source/Runtime/MovieSceneTracks/Private/Evaluation/MovieSceneEventTemplate.cpp +++ b/Engine/Source/Runtime/MovieSceneTracks/Private/Evaluation/MovieSceneEventTemplate.cpp @@ -24,7 +24,7 @@ struct FMovieSceneEventData struct FEventTrackExecutionToken : IMovieSceneExecutionToken { - FEventTrackExecutionToken(TArray InEvents) : Events(MoveTemp(InEvents)) {} + FEventTrackExecutionToken(TArray InEvents, const TArray& InEventReceivers) : Events(MoveTemp(InEvents)), EventReceivers(InEventReceivers) {} /** Execute this token, operating on all objects referenced by 'Operand' */ virtual void Execute(const FMovieSceneContext& Context, const FMovieSceneEvaluationOperand& Operand, FPersistentEvaluationData& PersistentData, IMovieScenePlayer& Player) override @@ -33,7 +33,35 @@ struct FEventTrackExecutionToken TArray PerformanceCaptureEventPositions; - for (UObject* EventContextObject : Player.GetEventContexts()) + // Resolve event contexts to trigger the event on + TArray EventContexts; + + // If we have specified event receivers, use those + if (EventReceivers.Num()) + { + EventContexts.Reserve(EventReceivers.Num()); + for (FMovieSceneObjectBindingID ID : EventReceivers) + { + // Ensure that this ID is resolvable from the root, based on the current local sequence ID + ID = ID.ResolveLocalToRoot(Operand.SequenceID, Player.GetEvaluationTemplate().GetHierarchy()); + + // Lookup the object(s) specified by ID in the player + for (TWeakObjectPtr<> WeakEventContext : Player.FindBoundObjects(ID.GetGuid(), ID.GetSequenceID())) + { + if (UObject* EventContext = WeakEventContext.Get()) + { + EventContexts.Add(EventContext); + } + } + } + } + else + { + // If we haven't specified event receivers, use the default set defined on the player + EventContexts = Player.GetEventContexts(); + } + + for (UObject* EventContextObject : EventContexts) { if (!EventContextObject) { @@ -128,10 +156,12 @@ struct FEventTrackExecutionToken } TArray Events; + TArray> EventReceivers; }; FMovieSceneEventSectionTemplate::FMovieSceneEventSectionTemplate(const UMovieSceneEventSection& Section, const UMovieSceneEventTrack& Track) : EventData(Section.GetEventData()) + , EventReceivers(Track.EventReceivers) , bFireEventsWhenForwards(Track.bFireEventsWhenForwards) , bFireEventsWhenBackwards(Track.bFireEventsWhenBackwards) { @@ -193,6 +223,6 @@ void FMovieSceneEventSectionTemplate::EvaluateSwept(const FMovieSceneEvaluationO if (Events.Num()) { - ExecutionTokens.Add(FEventTrackExecutionToken(MoveTemp(Events))); + ExecutionTokens.Add(FEventTrackExecutionToken(MoveTemp(Events), EventReceivers)); } } diff --git a/Engine/Source/Runtime/MovieSceneTracks/Private/Evaluation/MovieSceneEventTemplate.h b/Engine/Source/Runtime/MovieSceneTracks/Private/Evaluation/MovieSceneEventTemplate.h index f8386545f7fd..83842abadb60 100644 --- a/Engine/Source/Runtime/MovieSceneTracks/Private/Evaluation/MovieSceneEventTemplate.h +++ b/Engine/Source/Runtime/MovieSceneTracks/Private/Evaluation/MovieSceneEventTemplate.h @@ -6,6 +6,7 @@ #include "UObject/ObjectMacros.h" #include "Sections/MovieSceneEventSection.h" #include "Evaluation/MovieSceneEvalTemplate.h" +#include "MovieSceneObjectBindingID.h" #include "MovieSceneEventTemplate.generated.h" @@ -23,6 +24,9 @@ struct FMovieSceneEventSectionTemplate : public FMovieSceneEvalTemplate UPROPERTY() FMovieSceneEventSectionData EventData; + UPROPERTY() + TArray EventReceivers; + UPROPERTY() uint32 bFireEventsWhenForwards : 1; diff --git a/Engine/Source/Runtime/MovieSceneTracks/Private/Evaluation/MovieSceneSkeletalAnimationTemplate.cpp b/Engine/Source/Runtime/MovieSceneTracks/Private/Evaluation/MovieSceneSkeletalAnimationTemplate.cpp index 1170db7050f9..2651817426d6 100644 --- a/Engine/Source/Runtime/MovieSceneTracks/Private/Evaluation/MovieSceneSkeletalAnimationTemplate.cpp +++ b/Engine/Source/Runtime/MovieSceneTracks/Private/Evaluation/MovieSceneSkeletalAnimationTemplate.cpp @@ -126,7 +126,7 @@ struct FSkeletalAnimationTrackData : IPersistentEvaluationData if (SkeletalMeshComponent) { - UAnimSequencerInstance::BindToSkeletalMeshComponent(SkeletalMeshComponent); + UAnimCustomInstance::BindToSkeletalMeshComponent(SkeletalMeshComponent); static const bool bLooping = false; diff --git a/Engine/Source/Runtime/MovieSceneTracks/Private/Evaluation/MovieSceneTemplateCommon.cpp b/Engine/Source/Runtime/MovieSceneTracks/Private/Evaluation/MovieSceneTemplateCommon.cpp index cd97d67d5cbd..69b5e6403be0 100644 --- a/Engine/Source/Runtime/MovieSceneTracks/Private/Evaluation/MovieSceneTemplateCommon.cpp +++ b/Engine/Source/Runtime/MovieSceneTracks/Private/Evaluation/MovieSceneTemplateCommon.cpp @@ -59,8 +59,6 @@ void F3DTransformTrackToken::Apply(USceneComponent& SceneComponent, float DeltaT FVector CurrentPosition = SceneComponent.GetComponentLocation(); FVector ComponentVelocity = (CurrentPosition - PreviousPosition) / DeltaTime; SceneComponent.ComponentVelocity = ComponentVelocity; - - //TODO: Set Component Velocity for attached objects } }; diff --git a/Engine/Source/Runtime/MovieSceneTracks/Private/Sections/MovieScene3DAttachSection.cpp b/Engine/Source/Runtime/MovieSceneTracks/Private/Sections/MovieScene3DAttachSection.cpp index 96336b5ab4ec..1be5d6948da6 100644 --- a/Engine/Source/Runtime/MovieSceneTracks/Private/Sections/MovieScene3DAttachSection.cpp +++ b/Engine/Source/Runtime/MovieSceneTracks/Private/Sections/MovieScene3DAttachSection.cpp @@ -1,7 +1,6 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "Sections/MovieScene3DAttachSection.h" -#include "GameFramework/Actor.h" UMovieScene3DAttachSection::UMovieScene3DAttachSection( const FObjectInitializer& ObjectInitializer ) @@ -9,115 +8,17 @@ UMovieScene3DAttachSection::UMovieScene3DAttachSection( const FObjectInitializer { AttachSocketName = NAME_None; AttachComponentName = NAME_None; - bConstrainTx = true; - bConstrainTy = true; - bConstrainTz = true; - bConstrainRx = true; - bConstrainRy = true; - bConstrainRz = true; + AttachmentLocationRule = EAttachmentRule::KeepRelative; + AttachmentRotationRule = EAttachmentRule::KeepRelative; + AttachmentScaleRule = EAttachmentRule::KeepRelative; + DetachmentLocationRule = EDetachmentRule::KeepRelative; + DetachmentRotationRule = EDetachmentRule::KeepRelative; + DetachmentScaleRule = EDetachmentRule::KeepRelative; EvalOptions.EnableAndSetCompletionMode(EMovieSceneCompletionMode::RestoreState); } -void UMovieScene3DAttachSection::Eval( USceneComponent* SceneComponent, float Position, AActor* ParentActor, FVector& OutTranslation, FRotator& OutRotation ) const -{ - bool bFoundAttachment = false; - if(AttachSocketName != NAME_None) - { - if(AttachComponentName != NAME_None ) - { - TInlineComponentArray PotentialAttachComponents(ParentActor); - for(USceneComponent* PotentialAttachComponent : PotentialAttachComponents) - { - if(PotentialAttachComponent->GetFName() == AttachComponentName && PotentialAttachComponent->DoesSocketExist(AttachSocketName)) - { - FTransform SocketTransform = PotentialAttachComponent->GetSocketTransform(AttachSocketName); - OutTranslation = SocketTransform.GetLocation(); - OutRotation = SocketTransform.GetRotation().Rotator(); - bFoundAttachment = true; - break; - } - } - } - else if (ParentActor->GetRootComponent()->DoesSocketExist(AttachSocketName)) - { - FTransform SocketTransform = ParentActor->GetRootComponent()->GetSocketTransform(AttachSocketName); - OutTranslation = SocketTransform.GetLocation(); - OutRotation = SocketTransform.GetRotation().Rotator(); - bFoundAttachment = true; - } - } - else if(AttachComponentName != NAME_None ) - { - TInlineComponentArray PotentialAttachComponents(ParentActor); - for(USceneComponent* PotentialAttachComponent : PotentialAttachComponents) - { - if(PotentialAttachComponent->GetFName() == AttachComponentName) - { - FTransform ComponentTransform = PotentialAttachComponent->GetComponentToWorld(); - OutTranslation = ComponentTransform.GetLocation(); - OutRotation = ComponentTransform.GetRotation().Rotator(); - bFoundAttachment = true; - break; - } - } - } - - if (!bFoundAttachment) - { - if (ParentActor->GetDefaultAttachComponent()) - { - OutTranslation = ParentActor->GetDefaultAttachComponent()->GetComponentLocation(); - OutRotation = ParentActor->GetDefaultAttachComponent()->GetComponentRotation(); - } - else - { - OutTranslation = ParentActor->GetActorLocation(); - OutRotation = ParentActor->GetActorRotation(); - } - } - - FTransform ParentTransform(OutRotation, OutTranslation); - FTransform RelativeTransform = SceneComponent->GetRelativeTransform(); - - FTransform NewRelativeTransform = RelativeTransform * ParentTransform; - - OutTranslation = NewRelativeTransform.GetLocation(); - OutRotation = NewRelativeTransform.GetRotation().Rotator(); - - if (!bConstrainTx) - { - OutTranslation[0] = SceneComponent->GetRelativeTransform().GetLocation()[0]; - } - - if (!bConstrainTy) - { - OutTranslation[1] = SceneComponent->GetRelativeTransform().GetLocation()[1]; - } - - if (!bConstrainTz) - { - OutTranslation[2] = SceneComponent->GetRelativeTransform().GetLocation()[2]; - } - - if (!bConstrainRx) - { - OutRotation.Roll = SceneComponent->GetRelativeTransform().GetRotation().Rotator().Roll; - } - - if (!bConstrainRx) - { - OutRotation.Pitch = SceneComponent->GetRelativeTransform().GetRotation().Rotator().Pitch; - } - - if (!bConstrainRx) - { - OutRotation.Yaw = SceneComponent->GetRelativeTransform().GetRotation().Rotator().Yaw; - } -} - - void UMovieScene3DAttachSection::AddAttach( float Time, float SequenceEndTime, const FGuid& InAttachId ) { if (TryModify()) diff --git a/Engine/Source/Runtime/MovieSceneTracks/Private/Sections/MovieSceneEventSection.cpp b/Engine/Source/Runtime/MovieSceneTracks/Private/Sections/MovieSceneEventSection.cpp index 93a15263fc20..891c509540f6 100644 --- a/Engine/Source/Runtime/MovieSceneTracks/Private/Sections/MovieSceneEventSection.cpp +++ b/Engine/Source/Runtime/MovieSceneTracks/Private/Sections/MovieSceneEventSection.cpp @@ -3,9 +3,29 @@ #include "Sections/MovieSceneEventSection.h" #include "EngineGlobals.h" #include "IMovieScenePlayer.h" +#include "ReleaseObjectVersion.h" #include "Curves/KeyFrameAlgorithms.h" +bool FMovieSceneEventParameters::Serialize(FArchive& Ar) +{ + Ar.UsingCustomVersion(FReleaseObjectVersion::GUID); + + if (Ar.IsLoading() && Ar.CustomVer(FReleaseObjectVersion::GUID) < FReleaseObjectVersion::EventSectionParameterStringAssetRef) + { + UStruct* StructPtr = nullptr; + Ar << StructPtr; + StructType = StructPtr; + } + else + { + Ar << StructType; + } + + Ar << StructBytes; + + return true; +} /* UMovieSceneSection structors *****************************************************************************/ diff --git a/Engine/Source/Runtime/MovieSceneTracks/Private/Sections/MovieSceneParameterSection.cpp b/Engine/Source/Runtime/MovieSceneTracks/Private/Sections/MovieSceneParameterSection.cpp index c548fcf4b8bd..903ad2d65a92 100644 --- a/Engine/Source/Runtime/MovieSceneTracks/Private/Sections/MovieSceneParameterSection.cpp +++ b/Engine/Source/Runtime/MovieSceneTracks/Private/Sections/MovieSceneParameterSection.cpp @@ -42,6 +42,15 @@ void UMovieSceneParameterSection::AddScalarParameterKey( FName InParameterName, ExistingCurve = &ScalarParameterNamesAndCurves[NewIndex].ParameterCurve; } ExistingCurve->AddKey(InTime, InValue); + + if (GetStartTime() > InTime) + { + SetStartTime(InTime); + } + if (GetEndTime() < InTime) + { + SetEndTime(InTime); + } } void UMovieSceneParameterSection::AddVectorParameterKey( FName InParameterName, float InTime, FVector InValue ) @@ -64,6 +73,15 @@ void UMovieSceneParameterSection::AddVectorParameterKey( FName InParameterName, ExistingCurves->XCurve.AddKey( InTime, InValue.X ); ExistingCurves->YCurve.AddKey( InTime, InValue.Y ); ExistingCurves->ZCurve.AddKey( InTime, InValue.Z ); + + if (GetStartTime() > InTime) + { + SetStartTime(InTime); + } + if (GetEndTime() < InTime) + { + SetEndTime(InTime); + } } void UMovieSceneParameterSection::AddColorParameterKey( FName InParameterName, float InTime, FLinearColor InValue ) @@ -87,6 +105,15 @@ void UMovieSceneParameterSection::AddColorParameterKey( FName InParameterName, f ExistingCurves->GreenCurve.AddKey( InTime, InValue.G ); ExistingCurves->BlueCurve.AddKey( InTime, InValue.B ); ExistingCurves->AlphaCurve.AddKey( InTime, InValue.A ); + + if (GetStartTime() > InTime) + { + SetStartTime(InTime); + } + if (GetEndTime() < InTime) + { + SetEndTime(InTime); + } } bool UMovieSceneParameterSection::RemoveScalarParameter( FName InParameterName ) diff --git a/Engine/Source/Runtime/MovieSceneTracks/Private/Sections/MovieSceneSkeletalAnimationSection.cpp b/Engine/Source/Runtime/MovieSceneTracks/Private/Sections/MovieSceneSkeletalAnimationSection.cpp index f1df4e7f2855..23b519776539 100644 --- a/Engine/Source/Runtime/MovieSceneTracks/Private/Sections/MovieSceneSkeletalAnimationSection.cpp +++ b/Engine/Source/Runtime/MovieSceneTracks/Private/Sections/MovieSceneSkeletalAnimationSection.cpp @@ -128,27 +128,6 @@ FMovieSceneEvalTemplatePtr UMovieSceneSkeletalAnimationSection::GenerateTemplate return FMovieSceneSkeletalAnimationSectionTemplate(*this); } -void UMovieSceneSkeletalAnimationSection::PostLoadUpgradeTrackRow(const TRange& InEvaluationRange) -{ - if (!Params.Weight.IsKeyHandleValid(Params.Weight.FindKey(GetStartTime()))) - { - FKeyHandle StartKeyHandle = Params.Weight.UpdateOrAddKey(GetStartTime(), 1.f); - Params.Weight.SetKeyInterpMode(StartKeyHandle, RCIM_Constant); - } - - if (InEvaluationRange.HasLowerBound()) - { - FKeyHandle EvalInKeyHandle = Params.Weight.UpdateOrAddKey(InEvaluationRange.GetLowerBoundValue(), 1.f); - Params.Weight.SetKeyInterpMode(EvalInKeyHandle, RCIM_Constant); - } - - if (InEvaluationRange.HasUpperBound()) - { - FKeyHandle EvalOutKeyHandle = Params.Weight.UpdateOrAddKey(InEvaluationRange.GetUpperBoundValue(), 0.f); - Params.Weight.SetKeyInterpMode(EvalOutKeyHandle, RCIM_Constant); - } -} - void UMovieSceneSkeletalAnimationSection::MoveSection( float DeltaTime, TSet& KeyHandles ) { Super::MoveSection(DeltaTime, KeyHandles); diff --git a/Engine/Source/Runtime/MovieSceneTracks/Private/Tracks/MovieSceneSpawnTrack.cpp b/Engine/Source/Runtime/MovieSceneTracks/Private/Tracks/MovieSceneSpawnTrack.cpp index ac41574d037f..dc69977c734b 100644 --- a/Engine/Source/Runtime/MovieSceneTracks/Private/Tracks/MovieSceneSpawnTrack.cpp +++ b/Engine/Source/Runtime/MovieSceneTracks/Private/Tracks/MovieSceneSpawnTrack.cpp @@ -35,6 +35,7 @@ void UMovieSceneSpawnTrack::PostLoad() UMovieSceneBoolSection* BoolSection = ExactCast(Sections[Index]); if (BoolSection) { + BoolSection->ConditionalPostLoad(); Bytes.Reset(); FObjectWriter(BoolSection, Bytes); diff --git a/Engine/Source/Runtime/MovieSceneTracks/Private/Tracks/MovieSceneSubTrack.cpp b/Engine/Source/Runtime/MovieSceneTracks/Private/Tracks/MovieSceneSubTrack.cpp index f101ce91f301..831496fa500c 100644 --- a/Engine/Source/Runtime/MovieSceneTracks/Private/Tracks/MovieSceneSubTrack.cpp +++ b/Engine/Source/Runtime/MovieSceneTracks/Private/Tracks/MovieSceneSubTrack.cpp @@ -265,7 +265,7 @@ struct FSubTrackRemapper const UMovieSceneSubSection* SubSection = CastChecked(Sections[SectionIndex]); // Remap the tracks contained within this sequence only within the range of the section - FMovieSceneSequenceTransform InnerSequenceTransform = Args.Generator.GetSequenceTransform(Cache->RemappedID); + FMovieSceneSequenceTransform InnerSequenceTransform = Args.Generator.GetSequenceTransform(Cache->SequenceID); TRange OverlappingSegments = Cache->Template->EvaluationField.OverlapRange(Segment.Range * InnerSequenceTransform); for (int32 Index = OverlappingSegments.GetLowerBoundValue(); Index < OverlappingSegments.GetUpperBoundValue(); ++Index) @@ -294,10 +294,14 @@ struct FSubTrackRemapper FMovieSceneEvaluationTemplate& Template = SubSection->GenerateTemplateForSubSequence(Args); - // Remap it into the template generator - FMovieSceneSequenceID RemappedID = Args.Generator.GenerateSequenceID(SubSection->GenerateSubSequenceData(), MovieSceneSequenceID::Root); + FMovieSceneSubSequenceData SubSequenceData = SubSection->GenerateSubSequenceData(); - FSectionData Cache(RemappedID, &Template, Args.SubSequenceStore); + FMovieSceneSequenceID SubSequenceID = SubSequenceData.DeterministicSequenceID; + + // Add this sub sequence as a direct descendent of the current template. + Args.Generator.AddSubSequence(SubSequenceData, MovieSceneSequenceID::Root, SubSequenceID); + + FSectionData Cache(SubSequenceID, &Template, Args.SubSequenceStore); // For editor previews, we remap all sub sequences regardless of whether they are actually used in the sub sequence or not if (Args.Params.bForEditorPreview) @@ -317,8 +321,8 @@ private: struct FSectionData { - FSectionData(FMovieSceneSequenceIDRef InRemappedID, const FMovieSceneEvaluationTemplate* InTemplate, FMovieSceneSequenceTemplateStore& SequenceStore) - : RemappedID(InRemappedID), Template(InTemplate) + FSectionData(FMovieSceneSequenceIDRef InSequenceID, const FMovieSceneEvaluationTemplate* InTemplate, FMovieSceneSequenceTemplateStore& SequenceStore) + : SequenceID(InSequenceID), Template(InTemplate) { for (auto& Pair : InTemplate->Hierarchy.AllSubSequenceData()) { @@ -341,7 +345,7 @@ private: } FSectionData& operator=(FSectionData&& RHS) { - RemappedID = MoveTemp(RHS.RemappedID); + SequenceID = MoveTemp(RHS.SequenceID); Template = MoveTemp(RHS.Template); SubTemplates = MoveTemp(RHS.SubTemplates); ChildrenRemappedIDs = MoveTemp(RHS.ChildrenRemappedIDs); @@ -349,12 +353,12 @@ private: } #endif /** The ID of this section's sequence in the master sequecne */ - FMovieSceneSequenceID RemappedID; + FMovieSceneSequenceID SequenceID; /** The compiled template (stored in the sequence itself) */ const FMovieSceneEvaluationTemplate* Template; /** Map of all sub sequence templates, mapped by source ID (before remapping) */ TMap SubTemplates; - /** A map of remapped sequence IDs originating from this sequence's external tracks*/ + /** A map from original sub-sequence IDs held within this track, to such IDs accumulated with this sub sequence's ID (ie, local sequenceID -> sequenceID from the master */ TMap ChildrenRemappedIDs; }; @@ -389,7 +393,7 @@ private: // Root tracks use the cache's remapped ID if (SourceID == MovieSceneSequenceID::Root) { - return Cache.RemappedID; + return Cache.SequenceID; } // Nested tracks tracks - may need to remap the outer sequence @@ -406,23 +410,25 @@ private: FMovieSceneSubSequenceData SubDataCopy = *SubData; // Accumulate the parent's sequence transform - SubDataCopy.RootToSequenceTransform = SubDataCopy.RootToSequenceTransform * Args.Generator.GetSequenceTransform(Cache.RemappedID); + SubDataCopy.RootToSequenceTransform = SubDataCopy.RootToSequenceTransform * Args.Generator.GetSequenceTransform(Cache.SequenceID); - FMovieSceneSequenceID RemappedParentID = HierarchyNode->ParentID == MovieSceneSequenceID::Root ? Cache.RemappedID : RemapSubSequence(Cache, HierarchyNode->ParentID); + FMovieSceneSequenceID RemappedParentID = HierarchyNode->ParentID == MovieSceneSequenceID::Root ? Cache.SequenceID : RemapSubSequence(Cache, HierarchyNode->ParentID); // Accumulate the hierarchical bias const FMovieSceneSubSequenceData* ParentData = Cache.Template->Hierarchy.FindSubData(RemappedParentID); - SubDataCopy.HierarchicalBias = SubDataCopy.HierarchicalBias; if (ParentData != nullptr) { SubDataCopy.HierarchicalBias += ParentData->HierarchicalBias; } - // Remap this sequence within the main generator, under this section as a parent - FMovieSceneSequenceID RemappedID = Args.Generator.GenerateSequenceID(SubDataCopy, RemappedParentID); - Cache.ChildrenRemappedIDs.Add(SourceID, RemappedID); + // Hash this source ID with the owning sequence ID to make it unique + FMovieSceneSequenceID InnerSequenceID = SourceID.AccumulateParentID(Cache.SequenceID); - return RemappedID; + // Remap this sequence within the main generator, under this section as a parent + Args.Generator.AddSubSequence(SubDataCopy, RemappedParentID, InnerSequenceID); + Cache.ChildrenRemappedIDs.Add(SourceID, InnerSequenceID); + + return InnerSequenceID; } const FMovieSceneEvaluationTrack* FindTrack(FMovieSceneEvaluationFieldTrackPtr TrackPtr, const FSectionData& SectionData) const diff --git a/Engine/Source/Runtime/MovieSceneTracks/Public/MovieSceneHitProxy.h b/Engine/Source/Runtime/MovieSceneTracks/Public/MovieSceneHitProxy.h index 3fcc2f193ef5..1447358887e4 100644 --- a/Engine/Source/Runtime/MovieSceneTracks/Public/MovieSceneHitProxy.h +++ b/Engine/Source/Runtime/MovieSceneTracks/Public/MovieSceneHitProxy.h @@ -4,15 +4,17 @@ #include "CoreMinimal.h" #include "HitProxies.h" +#include "MovieSceneSection.h" +#include "MovieSceneTrack.h" struct HMovieSceneKeyProxy : public HHitProxy { DECLARE_HIT_PROXY( MOVIESCENETRACKS_API ); /** The track that contains the section */ - class UMovieSceneTrack* MovieSceneTrack; + TWeakObjectPtr MovieSceneTrack; /** The section that contains the keyframe */ - class UMovieSceneSection* MovieSceneSection; + TWeakObjectPtr MovieSceneSection; /** The time of the key that is selected */ float Time; diff --git a/Engine/Source/Runtime/MovieSceneTracks/Public/Sections/MovieScene3DAttachSection.h b/Engine/Source/Runtime/MovieSceneTracks/Public/Sections/MovieScene3DAttachSection.h index 6f5d3f3939ec..0eb14487e390 100644 --- a/Engine/Source/Runtime/MovieSceneTracks/Public/Sections/MovieScene3DAttachSection.h +++ b/Engine/Source/Runtime/MovieSceneTracks/Public/Sections/MovieScene3DAttachSection.h @@ -4,6 +4,7 @@ #include "CoreMinimal.h" #include "UObject/ObjectMacros.h" +#include "Engine/EngineTypes.h" #include "Sections/MovieScene3DConstraintSection.h" #include "MovieScene3DAttachSection.generated.h" @@ -21,13 +22,6 @@ class UMovieScene3DAttachSection public: - /** - * Evaluates the attach track - * - * @param Time The position in time within the movie scene - */ - void Eval(USceneComponent* SceneComponent, float Time, AActor* Actor, FVector& OutTranslation, FRotator& OutRotation) const; - /** * Adds an attach to the section * @@ -46,20 +40,20 @@ public: FName AttachComponentName; UPROPERTY(EditAnywhere, Category="Attach") - uint32 bConstrainTx:1; + EAttachmentRule AttachmentLocationRule; UPROPERTY(EditAnywhere, Category="Attach") - uint32 bConstrainTy:1; + EAttachmentRule AttachmentRotationRule; UPROPERTY(EditAnywhere, Category="Attach") - uint32 bConstrainTz:1; + EAttachmentRule AttachmentScaleRule; UPROPERTY(EditAnywhere, Category="Attach") - uint32 bConstrainRx:1; + EDetachmentRule DetachmentLocationRule; UPROPERTY(EditAnywhere, Category="Attach") - uint32 bConstrainRy:1; + EDetachmentRule DetachmentRotationRule; UPROPERTY(EditAnywhere, Category="Attach") - uint32 bConstrainRz:1; + EDetachmentRule DetachmentScaleRule; }; diff --git a/Engine/Source/Runtime/MovieSceneTracks/Public/Sections/MovieSceneEventSection.h b/Engine/Source/Runtime/MovieSceneTracks/Public/Sections/MovieSceneEventSection.h index 1fb475b7b55d..7c25d16be047 100644 --- a/Engine/Source/Runtime/MovieSceneTracks/Public/Sections/MovieSceneEventSection.h +++ b/Engine/Source/Runtime/MovieSceneTracks/Public/Sections/MovieSceneEventSection.h @@ -12,6 +12,7 @@ #include "UObject/StructOnScope.h" #include "Serialization/MemoryReader.h" #include "Engine/Engine.h" +#include "StringAssetReference.h" #include "MovieSceneEventSection.generated.h" struct EventData; @@ -55,7 +56,7 @@ struct FMovieSceneEventParameters void GetInstance(FStructOnScope& OutStruct) const { - UStruct* StructPtr = StructType.Get(); + UStruct* StructPtr = GetStructType(); OutStruct.Initialize(StructPtr); uint8* Memory = OutStruct.GetStructMemory(); if (StructPtr && StructPtr->GetStructureSize() > 0 && StructBytes.Num()) @@ -67,7 +68,7 @@ struct FMovieSceneEventParameters UStruct* GetStructType() const { - return StructType.Get(); + return Cast(StructType.TryLoad()); } void Reassign(UStruct* NewStruct) @@ -80,16 +81,7 @@ struct FMovieSceneEventParameters } } - bool Serialize(FArchive& Ar) - { - UStruct* StructTypePtr = StructType.Get(); - Ar << StructTypePtr; - StructType = StructTypePtr; - - Ar << StructBytes; - - return true; - } + MOVIESCENETRACKS_API bool Serialize(FArchive& Ar); friend FArchive& operator<<(FArchive& Ar, FMovieSceneEventParameters& Payload) { @@ -99,7 +91,7 @@ struct FMovieSceneEventParameters private: - TWeakObjectPtr StructType; + FStringAssetReference StructType; TArray StructBytes; }; diff --git a/Engine/Source/Runtime/MovieSceneTracks/Public/Sections/MovieSceneSkeletalAnimationSection.h b/Engine/Source/Runtime/MovieSceneTracks/Public/Sections/MovieSceneSkeletalAnimationSection.h index e850358690ce..4d044e6fae2c 100644 --- a/Engine/Source/Runtime/MovieSceneTracks/Public/Sections/MovieSceneSkeletalAnimationSection.h +++ b/Engine/Source/Runtime/MovieSceneTracks/Public/Sections/MovieSceneSkeletalAnimationSection.h @@ -77,7 +77,6 @@ public: virtual TOptional GetKeyTime( FKeyHandle KeyHandle ) const override { return TOptional(); } virtual void SetKeyTime( FKeyHandle KeyHandle, float Time ) override { } virtual FMovieSceneEvalTemplatePtr GenerateTemplate() const override; - virtual void PostLoadUpgradeTrackRow(const TRange& InEvaluationRange) override; /** ~UObject interface */ virtual void PostLoad() override; diff --git a/Engine/Source/Runtime/MovieSceneTracks/Public/Tracks/MovieSceneEventTrack.h b/Engine/Source/Runtime/MovieSceneTracks/Public/Tracks/MovieSceneEventTrack.h index 20095f646967..5e6919375ca7 100644 --- a/Engine/Source/Runtime/MovieSceneTracks/Public/Tracks/MovieSceneEventTrack.h +++ b/Engine/Source/Runtime/MovieSceneTracks/Public/Tracks/MovieSceneEventTrack.h @@ -6,6 +6,7 @@ #include "UObject/ObjectMacros.h" #include "MovieSceneNameableTrack.h" #include "Tracks/MovieSceneSpawnTrack.h" +#include "MovieSceneObjectBindingID.h" #include "MovieSceneEventTrack.generated.h" struct FMovieSceneEvaluationTrack; @@ -77,6 +78,10 @@ public: UPROPERTY(EditAnywhere, Category=TrackEvent) EFireEventsAtPosition EventPosition; + /** Defines a list of object bindings on which to trigger the events in this track. When empty, events will trigger in the default event contexts for the playback environment (such as the level blueprint, or widget). */ + UPROPERTY(EditAnywhere, Category=TrackEvent) + TArray EventReceivers; + private: /** The track's sections. */ diff --git a/Engine/Source/Runtime/Navmesh/Private/Detour/DetourNavMesh.cpp b/Engine/Source/Runtime/Navmesh/Private/Detour/DetourNavMesh.cpp index 19c676cef4d7..87be4d2d58df 100644 --- a/Engine/Source/Runtime/Navmesh/Private/Detour/DetourNavMesh.cpp +++ b/Engine/Source/Runtime/Navmesh/Private/Detour/DetourNavMesh.cpp @@ -827,14 +827,14 @@ const dtNavMeshParams* dtNavMesh::getParams() const ////////////////////////////////////////////////////////////////////////////////////////// int dtNavMesh::findConnectingPolys(const float* va, const float* vb, - const dtMeshTile* fromTile, int fromPolyIdx, - const dtMeshTile* tile, int side, - dtPolyRef* con, float* conarea, int maxcon) const + const dtMeshTile* fromTile, int fromPolyIdx, + const dtMeshTile* tile, int side, + dtChunkArray& cons) const { if (!tile) return 0; - + float amin[2], amax[2], apt[3]; - calcSlabEndPoints(va,vb, amin,amax, side); + calcSlabEndPoints(va, vb, amin, amax, side); const float apos = getSlabCoord(va, side); dtVcopy(apt, va); @@ -842,9 +842,9 @@ int dtNavMesh::findConnectingPolys(const float* va, const float* vb, float bmin[2], bmax[2], bpt[3]; unsigned short m = DT_EXT_LINK | (unsigned short)side; int n = 0; - + dtPolyRef base = getPolyRefBase(tile); - + for (int i = 0; i < tile->header->polyCount; ++i) { dtPoly* poly = &tile->polys[i]; @@ -853,21 +853,21 @@ int dtNavMesh::findConnectingPolys(const float* va, const float* vb, { // Skip edges which do not point to the right side. if (poly->neis[j] != m) continue; - - const float* vc = &tile->verts[poly->verts[j]*3]; - const float* vd = &tile->verts[poly->verts[(j+1) % nv]*3]; + + const float* vc = &tile->verts[poly->verts[j] * 3]; + const float* vd = &tile->verts[poly->verts[(j + 1) % nv] * 3]; const float bpos = getSlabCoord(vc, side); - + // Segments are not close enough. - if (dtAbs(apos-bpos) > 0.01f) + if (dtAbs(apos - bpos) > 0.01f) continue; - + // Check if the segments touch. - calcSlabEndPoints(vc,vd, bmin,bmax, side); - + calcSlabEndPoints(vc, vd, bmin, bmax, side); + unsigned char overlapMode = 0; - if (!overlapSlabs(amin,amax, bmin,bmax, 0.01f, tile->header->walkableClimb, &overlapMode)) continue; - + if (!overlapSlabs(amin, amax, bmin, bmax, 0.01f, tile->header->walkableClimb, &overlapMode)) continue; + // if overlapping with only one side, verify height difference using detailed mesh if (overlapMode == SLABOVERLAP_Max || overlapMode == SLABOVERLAP_Min) { @@ -884,16 +884,16 @@ int dtNavMesh::findConnectingPolys(const float* va, const float* vb, } // Add return value. - if (n < maxcon) - { - conarea[n*2+0] = dtMax(amin[0], bmin[0]); - conarea[n*2+1] = dtMin(amax[0], bmax[0]); - con[n] = base | (dtPolyRef)i; - n++; - } + FConnectingPolyData NewPolyData; + NewPolyData.min = dtMax(amin[0], bmin[0]); + NewPolyData.max = dtMin(amax[0], bmax[0]); + NewPolyData.ref = base | (dtPolyRef)i; + cons.push(NewPolyData); + n++; break; } } + return n; } @@ -946,6 +946,8 @@ void dtNavMesh::connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side, { if (!tile) return; + dtChunkArray cons(16); + // Connect border links. for (int i = 0; i < tile->header->polyCount; ++i) { @@ -968,16 +970,19 @@ void dtNavMesh::connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side, // Create new links const float* va = &tile->verts[poly->verts[j]*3]; const float* vb = &tile->verts[poly->verts[(j+1) % nv]*3]; - dtPolyRef nei[4]; - float neia[4*2]; - int nnei = findConnectingPolys(va,vb, tile, i, target, dtOppositeTile(dir), nei,neia,4); - for (int k = 0; k < nnei; ++k) + + // reset array before using + cons.resize(0); + findConnectingPolys(va,vb, tile, i, target, dtOppositeTile(dir), cons); + + for (int k = 0; k < cons.size(); ++k) { + const FConnectingPolyData& NeiData = cons[k]; unsigned int idx = allocLink(tile, CREATE_LINK_PREALLOCATED); if (idx != DT_NULL_LINK) { dtLink* link = &tile->links[idx]; - link->ref = nei[k]; + link->ref = NeiData.ref; link->edge = (unsigned char)j; link->side = (unsigned char)dir; @@ -987,8 +992,8 @@ void dtNavMesh::connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side, // Compress portal limits to a byte value. if (dir == 0 || dir == 4) { - float tmin = (neia[k*2+0]-va[2]) / (vb[2]-va[2]); - float tmax = (neia[k*2+1]-va[2]) / (vb[2]-va[2]); + float tmin = (NeiData.min-va[2]) / (vb[2]-va[2]); + float tmax = (NeiData.max-va[2]) / (vb[2]-va[2]); if (tmin > tmax) dtSwap(tmin,tmax); link->bmin = (unsigned char)(dtClamp(tmin, 0.0f, 1.0f)*255.0f); @@ -996,8 +1001,8 @@ void dtNavMesh::connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side, } else if (dir == 2 || dir == 6) { - float tmin = (neia[k*2+0]-va[0]) / (vb[0]-va[0]); - float tmax = (neia[k*2+1]-va[0]) / (vb[0]-va[0]); + float tmin = (NeiData.min-va[0]) / (vb[0]-va[0]); + float tmax = (NeiData.max-va[0]) / (vb[0]-va[0]); if (tmin > tmax) dtSwap(tmin,tmax); link->bmin = (unsigned char)(dtClamp(tmin, 0.0f, 1.0f)*255.0f); @@ -1007,7 +1012,7 @@ void dtNavMesh::connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side, if (updateCLinks) { - unsigned int targetIdx = decodePolyIdPoly(nei[k]); + unsigned int targetIdx = decodePolyIdPoly(NeiData.ref); if (tile->polyClusters && target->polyClusters && i < tile->header->offMeshBase && targetIdx < (unsigned int)target->header->offMeshBase) diff --git a/Engine/Source/Runtime/Navmesh/Public/Detour/DetourNavMesh.h b/Engine/Source/Runtime/Navmesh/Public/Detour/DetourNavMesh.h index d4e126c8772e..8d15f0501269 100644 --- a/Engine/Source/Runtime/Navmesh/Public/Detour/DetourNavMesh.h +++ b/Engine/Source/Runtime/Navmesh/Public/Detour/DetourNavMesh.h @@ -783,6 +783,14 @@ public: private: + // [UE4] result struct for findConnectingPolys + struct FConnectingPolyData + { + float min; + float max; + dtPolyRef ref; + }; + /// Returns pointer to tile in the tile array. dtMeshTile* getTile(int i); @@ -794,12 +802,12 @@ private: int getNeighbourTilesAt(const int x, const int y, const int side, dtMeshTile** tiles, const int maxTiles) const; - /// Returns all polygons in neighbour tile based on portal defined by the segment. + /// [UE4] Returns all polygons in neighbour tile based on portal defined by the segment. int findConnectingPolys(const float* va, const float* vb, - const dtMeshTile* fromTile, int fromPolyIdx, - const dtMeshTile* tile, int side, - dtPolyRef* con, float* conarea, int maxcon) const; - + const dtMeshTile* fromTile, int fromPolyIdx, + const dtMeshTile* tile, int side, + dtChunkArray& cons) const; + /// Builds internal polygons links for a tile. void connectIntLinks(dtMeshTile* tile); /// Builds internal polygons links for a tile. diff --git a/Engine/Source/Runtime/NetworkFile/NetworkFile.Build.cs b/Engine/Source/Runtime/NetworkFile/NetworkFile.Build.cs index 76bc963e0625..cbe380c5a161 100644 --- a/Engine/Source/Runtime/NetworkFile/NetworkFile.Build.cs +++ b/Engine/Source/Runtime/NetworkFile/NetworkFile.Build.cs @@ -10,6 +10,8 @@ public class NetworkFile : ModuleRules PrivateDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Sockets" }); PublicIncludePaths.Add("Runtime/CoreUObject/Public/Interfaces"); + PublicIncludePaths.Add("Runtime/CoreUObject/Public/UObject"); + PublicIncludePaths.Add("Runtime/CoreUObject/Public"); if (!UEBuildConfiguration.bBuildRequiresCookedData) { @@ -24,7 +26,7 @@ public class NetworkFile : ModuleRules if (Target.Platform == UnrealTargetPlatform.HTML5) { - Definitions.Add("ENABLE_HTTP_FOR_NFS=1"); + Definitions.Add("ENABLE_HTTP_FOR_NF=1"); if (Target.Architecture == "-win32") { PrivateDependencyModuleNames.Add("HTML5Win32"); @@ -36,7 +38,7 @@ public class NetworkFile : ModuleRules } else { - Definitions.Add("ENABLE_HTTP_FOR_NFS=0"); + Definitions.Add("ENABLE_HTTP_FOR_NF=0"); } } } diff --git a/Engine/Source/Runtime/NetworkFile/Private/HTTPTransport.cpp b/Engine/Source/Runtime/NetworkFile/Private/HTTPTransport.cpp index ec2c8b5b5a3f..1a8fe7cdb8d7 100644 --- a/Engine/Source/Runtime/NetworkFile/Private/HTTPTransport.cpp +++ b/Engine/Source/Runtime/NetworkFile/Private/HTTPTransport.cpp @@ -2,7 +2,7 @@ #include "HTTPTransport.h" -#if ENABLE_HTTP_FOR_NFS +#if ENABLE_HTTP_FOR_NF #include "Serialization/BufferArchive.h" #include "NetworkMessage.h" diff --git a/Engine/Source/Runtime/NetworkFile/Private/HTTPTransport.h b/Engine/Source/Runtime/NetworkFile/Private/HTTPTransport.h index 140804527cc9..82d2e645d10c 100644 --- a/Engine/Source/Runtime/NetworkFile/Private/HTTPTransport.h +++ b/Engine/Source/Runtime/NetworkFile/Private/HTTPTransport.h @@ -6,7 +6,7 @@ class ITransport; -#if ENABLE_HTTP_FOR_NFS +#if ENABLE_HTTP_FOR_NF #include "ITransport.h" #if !PLATFORM_HTML5 diff --git a/Engine/Source/Runtime/NetworkFile/Private/NetworkPlatformFile.cpp b/Engine/Source/Runtime/NetworkFile/Private/NetworkPlatformFile.cpp index 9169863f53a7..00413fecb920 100644 --- a/Engine/Source/Runtime/NetworkFile/Private/NetworkPlatformFile.cpp +++ b/Engine/Source/Runtime/NetworkFile/Private/NetworkPlatformFile.cpp @@ -23,6 +23,8 @@ #include "HAL/IPlatformFileModule.h" #include "UniquePtr.h" +#include "Object.h" + #if WITH_UNREAL_DEVELOPER_TOOLS #include "Developer/PackageDependencyInfo/Public/PackageDependencyInfo.h" #endif //WITH_UNREAL_DEVELOPER_TOOLS @@ -40,10 +42,27 @@ FNetworkPlatformFile::FNetworkPlatformFile() : bHasLoadedDDCDirectories(false) , InnerPlatformFile(NULL) , bIsUsable(false) + , FileServerPort(0) + , ConnectionFlags(EConnectionFlags::None) + , HeartbeatFrequency(5.0f) , FinishedAsyncNetworkReadUnsolicitedFiles(NULL) , FinishedAsyncWriteUnsolicitedFiles(NULL) , Transport(NULL) { + + + + TotalWriteTime = 0.0; // total non async time spent writing to disk + TotalNetworkSyncTime = 0.0; // total non async time spent syncing to network + TotalTimeSpentInUnsolicitedPackages = 0.0; // total time async processing unsolicited packages + TotalWaitForAsyncUnsolicitedPackages = 0.0; // total time spent waiting for unsolicited packages + TotalFilesSynced = 0; // total number files synced from network + TotalFilesFoundLocally = 0; + TotalUnsolicitedPackages = 0; // total number unsolicited files synced + UnsolicitedPackagesHits = 0; // total number of hits from waiting on unsolicited packages + UnsolicitedPackageWaits = 0; // total number of waits on unsolicited packages + + } bool FNetworkPlatformFile::ShouldBeUsed(IPlatformFile* Inner, const TCHAR* CmdLine) const @@ -61,7 +80,7 @@ ITransport *CreateTransportForHostAddress(const FString &HostIp ) if ( HostIp.StartsWith(TEXT("http://"))) { -#if ENABLE_HTTP_FOR_NFS +#if ENABLE_HTTP_FOR_NF return new FHTTPTransport(); #endif } @@ -157,10 +176,13 @@ bool FNetworkPlatformFile::InitializeInternal(IPlatformFile* Inner, const TCHAR* bool FNetworkPlatformFile::SendPayloadAndReceiveResponse(TArray& In, TArray& Out) { - if ( FinishedAsyncNetworkReadUnsolicitedFiles ) { - delete FinishedAsyncNetworkReadUnsolicitedFiles; - FinishedAsyncNetworkReadUnsolicitedFiles = NULL; + FScopeLock ScopeLock(&SynchronizationObject); + if ( FinishedAsyncNetworkReadUnsolicitedFiles ) + { + delete FinishedAsyncNetworkReadUnsolicitedFiles; + FinishedAsyncNetworkReadUnsolicitedFiles = NULL; + } } return Transport->SendPayloadAndReceiveResponse( In, Out ); @@ -180,7 +202,7 @@ void FNetworkPlatformFile::InitializeAfterSetActive() // send the filenames and timestamps to the server FNetworkFileArchive Payload(NFS_Messages::GetFileList); - FillGetFileList(Payload, false); + FillGetFileList(Payload); // send the directories over, and wait for a response FArrayReader Response; @@ -195,147 +217,7 @@ void FNetworkPlatformFile::InitializeAfterSetActive() int32 ServerPackageVersion = 0; int32 ServerPackageLicenseeVersion = 0; ProcessServerInitialResponse(Response, ServerPackageVersion, ServerPackageLicenseeVersion); - - - /* The server root content directories */ - TArray ServerRootContentDirectories; - Response << ServerRootContentDirectories; - - // receive a list of the cache files and their timestamps - TMap ServerCachedFiles; - Response << ServerCachedFiles; - - bool bDeleteAllFiles = true; - // Check the stored cooked version - FString CookedVersionFile = FPaths::GeneratedConfigDir() / TEXT("CookedVersion.txt"); - - if (InnerPlatformFile->FileExists(*CookedVersionFile) == true) - { - IFileHandle* FileHandle = InnerPlatformFile->OpenRead(*CookedVersionFile); - if (FileHandle != NULL) - { - int32 StoredPackageCookedVersion; - int32 StoredPackageCookedLicenseeVersion; - if (FileHandle->Read((uint8*)&StoredPackageCookedVersion, sizeof(int32)) == true) - { - if (FileHandle->Read((uint8*)&StoredPackageCookedLicenseeVersion, sizeof(int32)) == true) - { - if ((ServerPackageVersion == StoredPackageCookedVersion) && - (ServerPackageLicenseeVersion == StoredPackageCookedLicenseeVersion)) - { - bDeleteAllFiles = false; - } - else - { - UE_LOG(LogNetworkPlatformFile, Display, - TEXT("Engine version mismatch: Server %d.%d, Stored %d.%d\n"), - ServerPackageVersion, ServerPackageLicenseeVersion, - StoredPackageCookedVersion, StoredPackageCookedLicenseeVersion); - } - } - } - - delete FileHandle; - } - } - else - { - UE_LOG(LogNetworkPlatformFile, Display, TEXT("Cooked version file missing: %s\n"), *CookedVersionFile); - } - - if (bDeleteAllFiles == true) - { - // Make sure the config file exists... - InnerPlatformFile->CreateDirectoryTree(*(FPaths::GeneratedConfigDir())); - // Update the cooked version file - IFileHandle* FileHandle = InnerPlatformFile->OpenWrite(*CookedVersionFile); - if (FileHandle != NULL) - { - FileHandle->Write((const uint8*)&ServerPackageVersion, sizeof(int32)); - FileHandle->Write((const uint8*)&ServerPackageLicenseeVersion, sizeof(int32)); - delete FileHandle; - } - } - - // list of directories to skip - TArray DirectoriesToSkip; - TArray DirectoriesToNotRecurse; - // use the timestamp grabbing visitor to get all the content times - FLocalTimestampDirectoryVisitor Visitor(*InnerPlatformFile, DirectoriesToSkip, DirectoriesToNotRecurse, false); - - /*TArray RootContentPaths; - FPackageName::QueryRootContentPaths(RootContentPaths); */ - for (TArray::TConstIterator RootPathIt(ServerRootContentDirectories); RootPathIt; ++RootPathIt) - { - /*const FString& RootPath = *RootPathIt; - const FString& ContentFolder = FPackageName::LongPackageNameToFilename(RootPath);*/ - const FString& ContentFolder = *RootPathIt; - InnerPlatformFile->IterateDirectory( *ContentFolder, Visitor); - } - - // delete out of date files using the server cached files - for (TMap::TIterator It(ServerCachedFiles); It; ++It) - { - bool bDeleteFile = bDeleteAllFiles; - FString ServerFile = It.Key(); - - // Convert the filename to the client version - ConvertServerFilenameToClientFilename(ServerFile); - - // Set it in the visitor file times list - // If there is any pathing difference (relative path, or whatever) between the server's filelist and the results - // of platform directory iteration then this will Add a new entry rather than override the existing one. This causes local file deletes - // and longer loads as we will never see the benefits of local device caching. - Visitor.FileTimes.Add(ServerFile, FDateTime::MinValue()); - - if (bDeleteFile == false) - { - // Check the time stamps... - // get local time - FDateTime LocalTime = InnerPlatformFile->GetTimeStamp(*ServerFile); - // If local time == MinValue than the file does not exist in the cache. - if (LocalTime != FDateTime::MinValue()) - { - FDateTime ServerTime = It.Value(); - // delete if out of date - // We will use 1.0 second as the tolerance to cover any platform differences in resolution - FTimespan TimeDiff = LocalTime - ServerTime; - double TimeDiffInSeconds = TimeDiff.GetTotalSeconds(); - bDeleteFile = (TimeDiffInSeconds > 1.0) || (TimeDiffInSeconds < -1.0); - if (bDeleteFile == true) - { - if (InnerPlatformFile->FileExists(*ServerFile) == true) - { - UE_LOG(LogNetworkPlatformFile, Display, TEXT("Deleting cached file: TimeDiff %5.3f, %s"), TimeDiffInSeconds, *It.Key()); - } - else - { - // It's a directory - bDeleteFile = false; - } - } - else - { - UE_LOG(LogNetworkPlatformFile, Display, TEXT("Keeping cached file: %s, TimeDiff worked out ok"), *ServerFile); - } - } - } - if (bDeleteFile == true) - { - InnerPlatformFile->DeleteFile(*ServerFile); - } - } - - // Any content files we have locally that were not cached, delete them - for (TMap::TIterator It(Visitor.FileTimes); It; ++It) - { - if (It.Value() != FDateTime::MinValue()) - { - // This was *not* found in the server file list... delete it - UE_LOG(LogNetworkPlatformFile, Display, TEXT("Deleting cached file: %s"), *It.Key()); - InnerPlatformFile->DeleteFile(*It.Key()); - } - } + ProcessServerCachedFilesResponse(Response, ServerPackageVersion, ServerPackageLicenseeVersion); // make sure we can sync a file FString TestSyncFile = FPaths::Combine(*(FPaths::EngineDir()), TEXT("Config/BaseEngine.ini")); @@ -360,10 +242,160 @@ void FNetworkPlatformFile::InitializeAfterSetActive() } +void FNetworkPlatformFile::ProcessServerCachedFilesResponse(FArrayReader& Response, const int32 ServerPackageVersion, const int32 ServerPackageLicenseeVersion) +{ + /* The server root content directories */ + TArray ServerRootContentDirectories; + Response << ServerRootContentDirectories; + + // receive a list of the cache files and their timestamps + TMap ServerCachedFiles; + Response << ServerCachedFiles; + + bool bDeleteAllFiles = true; + // Check the stored cooked version + FString CookedVersionFile = FPaths::GeneratedConfigDir() / TEXT("CookedVersion.txt"); + + if (InnerPlatformFile->FileExists(*CookedVersionFile) == true) + { + IFileHandle* FileHandle = InnerPlatformFile->OpenRead(*CookedVersionFile); + if (FileHandle != NULL) + { + int32 StoredPackageCookedVersion; + int32 StoredPackageCookedLicenseeVersion; + if (FileHandle->Read((uint8*)&StoredPackageCookedVersion, sizeof(int32)) == true) + { + if (FileHandle->Read((uint8*)&StoredPackageCookedLicenseeVersion, sizeof(int32)) == true) + { + if ((ServerPackageVersion == StoredPackageCookedVersion) && + (ServerPackageLicenseeVersion == StoredPackageCookedLicenseeVersion)) + { + bDeleteAllFiles = false; + } + else + { + UE_LOG(LogNetworkPlatformFile, Display, + TEXT("Engine version mismatch: Server %d.%d, Stored %d.%d\n"), + ServerPackageVersion, ServerPackageLicenseeVersion, + StoredPackageCookedVersion, StoredPackageCookedLicenseeVersion); + } + } + } + + delete FileHandle; + } + } + else + { + UE_LOG(LogNetworkPlatformFile, Display, TEXT("Cooked version file missing: %s\n"), *CookedVersionFile); + } + + if (bDeleteAllFiles == true) + { + // Make sure the config file exists... + InnerPlatformFile->CreateDirectoryTree(*(FPaths::GeneratedConfigDir())); + // Update the cooked version file + IFileHandle* FileHandle = InnerPlatformFile->OpenWrite(*CookedVersionFile); + if (FileHandle != NULL) + { + FileHandle->Write((const uint8*)&ServerPackageVersion, sizeof(int32)); + FileHandle->Write((const uint8*)&ServerPackageLicenseeVersion, sizeof(int32)); + delete FileHandle; + } + } + + // list of directories to skip + TArray DirectoriesToSkip; + TArray DirectoriesToNotRecurse; + // use the timestamp grabbing visitor to get all the content times + FLocalTimestampDirectoryVisitor Visitor(*InnerPlatformFile, DirectoriesToSkip, DirectoriesToNotRecurse, false); + + /*TArray RootContentPaths; + FPackageName::QueryRootContentPaths(RootContentPaths); */ + for (TArray::TConstIterator RootPathIt(ServerRootContentDirectories); RootPathIt; ++RootPathIt) + { + /*const FString& RootPath = *RootPathIt; + const FString& ContentFolder = FPackageName::LongPackageNameToFilename(RootPath);*/ + const FString& ContentFolder = *RootPathIt; + InnerPlatformFile->IterateDirectory(*ContentFolder, Visitor); + } + + // delete out of date files using the server cached files + for (TMap::TIterator It(ServerCachedFiles); It; ++It) + { + bool bDeleteFile = bDeleteAllFiles; + FString ServerFile = It.Key(); + + // Convert the filename to the client version + ConvertServerFilenameToClientFilename(ServerFile); + + // Set it in the visitor file times list + // If there is any pathing difference (relative path, or whatever) between the server's filelist and the results + // of platform directory iteration then this will Add a new entry rather than override the existing one. This causes local file deletes + // and longer loads as we will never see the benefits of local device caching. + Visitor.FileTimes.Add(ServerFile, FDateTime::MinValue()); + + if (bDeleteFile == false) + { + // Check the time stamps... + // get local time + FDateTime LocalTime = InnerPlatformFile->GetTimeStamp(*ServerFile); + // If local time == MinValue than the file does not exist in the cache. + if (LocalTime != FDateTime::MinValue()) + { + FDateTime ServerTime = It.Value(); + // delete if out of date + // We will use 1.0 second as the tolerance to cover any platform differences in resolution + FTimespan TimeDiff = LocalTime - ServerTime; + double TimeDiffInSeconds = TimeDiff.GetTotalSeconds(); + bDeleteFile = (TimeDiffInSeconds > 1.0) || (TimeDiffInSeconds < -1.0); + if (bDeleteFile == true) + { + if (InnerPlatformFile->FileExists(*ServerFile) == true) + { + UE_LOG(LogNetworkPlatformFile, Display, TEXT("Deleting cached file: TimeDiff %5.3f, %s"), TimeDiffInSeconds, *It.Key()); + } + else + { + // It's a directory + bDeleteFile = false; + } + } + else + { + UE_LOG(LogNetworkPlatformFile, Display, TEXT("Keeping cached file: %s, TimeDiff worked out ok"), *ServerFile); + } + } + } + if (bDeleteFile == true) + { + UE_LOG(LogNetworkPlatformFile, Display, TEXT("Deleting cached file: %s"), *ServerFile); + InnerPlatformFile->DeleteFile(*ServerFile); + } + } + + // Any content files we have locally that were not cached, delete them + for (TMap::TIterator It(Visitor.FileTimes); It; ++It) + { + if ( FCString::Stricmp( *FPaths::GetExtension( It.Key() ), TEXT("pak")) == 0 ) + { + // ignore pak files they won't be mounted anyway + continue; + } + if (It.Value() != FDateTime::MinValue()) + { + // This was *not* found in the server file list... delete it + UE_LOG(LogNetworkPlatformFile, Display, TEXT("Deleting cached file: %s"), *It.Key()); + InnerPlatformFile->DeleteFile(*It.Key()); + } + } +} + FNetworkPlatformFile::~FNetworkPlatformFile() { if (!GIsRequestingExit) // the socket subsystem is probably already gone, so it will crash if we clean up { + FScopeLock ScopeLock(&SynchronizationObject); if ( FinishedAsyncNetworkReadUnsolicitedFiles ) { delete FinishedAsyncNetworkReadUnsolicitedFiles; // wait here for any async unsolicited files to finish reading being read from the network @@ -752,7 +784,7 @@ void FNetworkPlatformFile::ConvertServerFilenameToClientFilename(FString& Filena FNetworkPlatformFile::ConvertServerFilenameToClientFilename(FilenameToConvert, ServerEngineDir, ServerGameDir); } -void FNetworkPlatformFile::FillGetFileList(FNetworkFileArchive& Payload, bool bInStreamingFileRequest) +void FNetworkPlatformFile::FillGetFileList(FNetworkFileArchive& Payload) { TArray TargetPlatformNames; FPlatformMisc::GetValidTargetPlatforms(TargetPlatformNames); @@ -778,10 +810,13 @@ void FNetworkPlatformFile::FillGetFileList(FNetworkFileArchive& Payload, bool bI Payload << EngineRelPath; Payload << GameRelPath; Payload << Directories; - Payload << bInStreamingFileRequest; + Payload << ConnectionFlags; + + FString VersionInfo = GetVersionInfo(); + Payload << VersionInfo; } -void FNetworkPlatformFile::ProcessServerInitialResponse(FArrayReader& InResponse, int32 OutServerPackageVersion, int32 OutServerPackageLicenseeVersion) +void FNetworkPlatformFile::ProcessServerInitialResponse(FArrayReader& InResponse, int32& OutServerPackageVersion, int32& OutServerPackageLicenseeVersion) { // Receive the cooked version information. InResponse << OutServerPackageVersion; @@ -807,6 +842,12 @@ void FNetworkPlatformFile::ProcessServerInitialResponse(FArrayReader& InResponse } } + +FString FNetworkPlatformFile::GetVersionInfo() const +{ + return FString(""); +} + bool FNetworkPlatformFile::SendReadMessage(uint8* Destination, int64 BytesToRead) { // FScopeLock ScopeLock(&SynchronizationObject); @@ -1083,6 +1124,8 @@ void FNetworkPlatformFile::EnsureFileIsLocal(const FString& Filename) float ThisTime; StartTime = FPlatformTime::Seconds(); + UE_LOG(LogNetworkPlatformFile, Verbose, TEXT("Searching for %s locally "), *Filename); + { FScopeLock ScopeLock(&SynchronizationObject); // have we already cached this file? @@ -1092,42 +1135,58 @@ void FNetworkPlatformFile::EnsureFileIsLocal(const FString& Filename) } } - if ( FinishedAsyncNetworkReadUnsolicitedFiles ) + bool bIncrimentedPackageWaits = false; + if (FinishedAsyncNetworkReadUnsolicitedFiles) { + if (FinishedAsyncNetworkReadUnsolicitedFiles->Get() == 0) + { + ++UnsolicitedPackageWaits; + bIncrimentedPackageWaits = true; + } delete FinishedAsyncNetworkReadUnsolicitedFiles; // wait here for any async unsolicited files to finish reading being read from the network FinishedAsyncNetworkReadUnsolicitedFiles = NULL; } - if( FinishedAsyncWriteUnsolicitedFiles) + if (FinishedAsyncWriteUnsolicitedFiles) { + if (bIncrimentedPackageWaits == false && FinishedAsyncNetworkReadUnsolicitedFiles->Get() == 0) + { + ++UnsolicitedPackageWaits; + } delete FinishedAsyncWriteUnsolicitedFiles; // wait here for any async unsolicited files to finish writing to disk FinishedAsyncWriteUnsolicitedFiles = NULL; } - - - FScopeLock ScopeLock(&SynchronizationObject); - ThisTime = 1000.0f * float(FPlatformTime::Seconds() - StartTime); + TotalWaitForAsyncUnsolicitedPackages += ThisTime; //UE_LOG(LogNetworkPlatformFile, Display, TEXT("Lock and wait for old async writes %6.2fms"), ThisTime); - // have we already cached this file? (test again, since some other thread might have done this between waits) if (CachedLocalFiles.Find(Filename) != NULL) { + ++UnsolicitedPackagesHits; return; } + + UE_LOG(LogNetworkPlatformFile, Verbose, TEXT("Attempting to get %s from server"), *Filename); + // even if an error occurs later, we still want to remember not to try again CachedLocalFiles.Add(Filename); - + UE_LOG(LogNetworkPlatformFile, Warning, TEXT("Cached file %s"), *Filename) StartTime = FPlatformTime::Seconds(); // no need to read it if it already exists // @todo: Handshake with server to delete files that are out of date if (InnerPlatformFile->FileExists(*Filename)) { + ++TotalFilesFoundLocally; + UE_LOG(LogNetworkPlatformFile, Verbose, TEXT("File %s exists locally but wasn't in cache"), *Filename); return; } + ++TotalFilesSynced; + + + ThisTime = 1000.0f * float(FPlatformTime::Seconds() - StartTime); //UE_LOG(LogNetworkPlatformFile, Display, TEXT("Check for local file %6.2fms - %s"), ThisTime, *Filename); @@ -1141,6 +1200,9 @@ void FNetworkPlatformFile::EnsureFileIsLocal(const FString& Filename) { // Uncomment this to have the server file list dumped // the first time a file requested is not found. + + UE_LOG(LogNetworkPlatformFile, Verbose, TEXT("Didn't find %s in server files list"), *Filename); + #if 0 static bool sb_DumpedServer = false; if (sb_DumpedServer == false) @@ -1174,6 +1236,7 @@ void FNetworkPlatformFile::EnsureFileIsLocal(const FString& Filename) return; } ThisTime = 1000.0f * float(FPlatformTime::Seconds() - StartTime); + TotalNetworkSyncTime += ThisTime; //UE_LOG(LogNetworkPlatformFile, Display, TEXT("Send and receive %6.2fms"), ThisTime); StartTime = FPlatformTime::Seconds(); @@ -1187,6 +1250,15 @@ void FNetworkPlatformFile::EnsureFileIsLocal(const FString& Filename) FDateTime ServerTimeStamp; Response << ServerTimeStamp; + if (ServerTimeStamp != FDateTime::MinValue()) // if the file didn't actually exist on the server, don't create a zero byte file + { + UE_LOG(LogNetworkPlatformFile, Verbose, TEXT("Succeeded in getting %s from server"), *Filename); + } + else + { + UE_LOG(LogNetworkPlatformFile, Verbose, TEXT("File not found %s from server"), *Filename); + } + // write the file in chunks, synchronously SyncWriteFile(&Response, ReplyFile, ServerTimeStamp, *InnerPlatformFile); @@ -1195,6 +1267,7 @@ void FNetworkPlatformFile::EnsureFileIsLocal(const FString& Filename) if (NumUnsolictedFiles) { + TotalUnsolicitedPackages += NumUnsolictedFiles; check( FinishedAsyncNetworkReadUnsolicitedFiles == NULL ); check( FinishedAsyncWriteUnsolicitedFiles == NULL ); FinishedAsyncNetworkReadUnsolicitedFiles = new FScopedEvent; @@ -1203,6 +1276,7 @@ void FNetworkPlatformFile::EnsureFileIsLocal(const FString& Filename) } ThisTime = 1000.0f * float(FPlatformTime::Seconds() - StartTime); + TotalWriteTime += ThisTime; //UE_LOG(LogNetworkPlatformFile, Display, TEXT("Write file to local %6.2fms"), ThisTime); } @@ -1268,6 +1342,8 @@ void FNetworkPlatformFile::PerformHeartbeat() // send the filename over (cast away const here because we know this << will not modify the string) FNetworkFileArchive Payload(NFS_Messages::Heartbeat); + + // send the filename over FArrayReader Response; if (!SendPayloadAndReceiveResponse(Payload, Response)) @@ -1282,17 +1358,44 @@ void FNetworkPlatformFile::PerformHeartbeat() // delete any outdated files from the client // @todo: This may need a critical section around all calls to LowLevel in the other functions // because we don't want to delete files while other threads are using them! + + TArray PackageNames; for (int32 FileIndex = 0; FileIndex < UpdatedFiles.Num(); FileIndex++) { - UE_LOG(LogNetworkPlatformFile, Log, TEXT("Server updated file '%s', deleting local copy"), *UpdatedFiles[FileIndex]); - if (InnerPlatformFile->DeleteFile(*UpdatedFiles[FileIndex]) == false) + // clean up the linkers for this package + FString LocalFileName = UpdatedFiles[FileIndex]; + ConvertServerFilenameToClientFilename( LocalFileName ); + + UE_LOG(LogNetworkPlatformFile, Log, TEXT("Server updated file '%s', deleting local copy %s"), *UpdatedFiles[FileIndex], *LocalFileName); + + FString PackageName; + if (FPackageName::TryConvertFilenameToLongPackageName(LocalFileName, PackageName)) { - UE_LOG(LogNetworkPlatformFile, Error, TEXT("Failed to delete %s, someone is probably accessing without FNetworkPlatformFile, or we need better thread protection"), *UpdatedFiles[FileIndex]); + PackageNames.Add(PackageName); } + else + { + UE_LOG(LogNetworkPlatformFile, Log, TEXT("Unable to convert filename to package name %s"), *LocalFileName); + } + + OnFileUpdated(LocalFileName); + } + + if ( PackageNames.Num() > 0 ) + { + FCoreUObjectDelegates::NetworkFileRequestPackageReload.ExecuteIfBound(PackageNames); } } - +void FNetworkPlatformFile::OnFileUpdated(const FString& LocalFileName) +{ + if (InnerPlatformFile->FileExists(*LocalFileName) && InnerPlatformFile->DeleteFile(*LocalFileName) == false) + { + UE_LOG(LogNetworkPlatformFile, Error, TEXT("Failed to delete %s, someone is probably accessing without FNetworkPlatformFile, or we need better thread protection"), *LocalFileName); + } + CachedLocalFiles.Remove(LocalFileName); + ServerFiles.AddFileOrDirectory(LocalFileName, FDateTime::UtcNow()); +} void FNetworkPlatformFile::ConvertServerFilenameToClientFilename(FString& FilenameToConvert, const FString& InServerEngineDir, const FString& InServerGameDir) { @@ -1306,6 +1409,82 @@ void FNetworkPlatformFile::ConvertServerFilenameToClientFilename(FString& Filena } } +void FNetworkPlatformFile::Tick() +{ + // try send a heart beat every 5 seconds as long as we are not async loading + static double StartTime = FPlatformTime::Seconds(); + + bool bShouldPerformHeartbeat = true; + if ((FPlatformTime::Seconds() - StartTime) > HeartbeatFrequency && HeartbeatFrequency >= 0 ) + { + + + if (IsAsyncLoading() && bShouldPerformHeartbeat) + { + bShouldPerformHeartbeat = false; + } + + { + FScopeLock S(&SynchronizationObject); + if (FinishedAsyncNetworkReadUnsolicitedFiles && bShouldPerformHeartbeat) + { + if ( FinishedAsyncNetworkReadUnsolicitedFiles->IsReady() ) + { + delete FinishedAsyncNetworkReadUnsolicitedFiles; + FinishedAsyncNetworkReadUnsolicitedFiles = nullptr; + } + else + { + bShouldPerformHeartbeat = false; + } + } + } + + if ( bShouldPerformHeartbeat ) + { + StartTime = FPlatformTime::Seconds(); + + //DeleteLoaders(); + PerformHeartbeat(); + } + } +} + +bool FNetworkPlatformFile::Exec(class UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar ) +{ + if (FParse::Command(&Cmd, TEXT("networkfile"))) + { + if ( FParse::Command(&Cmd, TEXT("stats"))) + { + + Ar.Logf(TEXT("Network platform file %s stats\n" + "TotalWriteTime \t%fms \n" + "TotalNetworkSyncTime \t%fms \n" + "TotalTimeSpentInUnsolicitedPackages \t%fms \n" + "TotalWaitForAsyncUnsolicitedPackages \t%fms \n" + "TotalFilesSynced \t%d \n" + "TotalFilesFoundLocally \t%d\n" + "TotalUnsolicitedPackages \t%d \n" + "UnsolicitedPackagesHits \t%d \n" + "UnsolicitedPackageWaits \t%d \n"), + GetTypeName(), + TotalWriteTime, + TotalNetworkSyncTime, + TotalTimeSpentInUnsolicitedPackages, + TotalWaitForAsyncUnsolicitedPackages, + TotalFilesSynced, + TotalFilesFoundLocally, + TotalUnsolicitedPackages, + UnsolicitedPackagesHits, + UnsolicitedPackageWaits); + + // there could be multiple network platform files so let them all report their stats + return false; + } + } + return false; +} + /** * Module for the network file */ diff --git a/Engine/Source/Runtime/NetworkFile/Public/NetworkPlatformFile.h b/Engine/Source/Runtime/NetworkFile/Public/NetworkPlatformFile.h index fcf7baf28fde..1be3f25277cd 100644 --- a/Engine/Source/Runtime/NetworkFile/Public/NetworkPlatformFile.h +++ b/Engine/Source/Runtime/NetworkFile/Public/NetworkPlatformFile.h @@ -6,19 +6,22 @@ #include "GenericPlatform/GenericPlatformFile.h" #include "NetworkMessage.h" #include "ServerTOC.h" +#include "CoreMisc.h" // included for FSelfRegisteringExec class FScopedEvent; DECLARE_LOG_CATEGORY_EXTERN(LogNetworkPlatformFile, Log, All); + /** * Wrapper to redirect the low level file system to a server */ -class NETWORKFILE_API FNetworkPlatformFile : public IPlatformFile +class NETWORKFILE_API FNetworkPlatformFile : public IPlatformFile, public FSelfRegisteringExec { friend class FAsyncFileSync; friend void ReadUnsolicitedFile(int32 InNumUnsolictedFiles, FNetworkPlatformFile& InNetworkFile, IPlatformFile& InInnerPlatformFile, FString& InServerEngineDir, FString& InServerGameDir); +protected: /** * Initialize network platform file give the specified host IP * @@ -28,7 +31,10 @@ class NETWORKFILE_API FNetworkPlatformFile : public IPlatformFile */ virtual bool InitializeInternal(IPlatformFile* Inner, const TCHAR* HostIP); + virtual void OnFileUpdated(const FString& LocalFilename); + public: + static const TCHAR* GetTypeName() { @@ -136,6 +142,7 @@ public: virtual bool SendMessageToServer(const TCHAR* Message, IPlatformFile::IFileServerMessageHandler* Handler) override; + virtual void Tick() override; @@ -147,6 +154,16 @@ public: static void ConvertServerFilenameToClientFilename(FString& FilenameToConvert, const FString& InServerEngineDir, const FString& InServerGameDir); + + virtual FString GetVersionInfo() const; + + + + ////////////////////////////////////////////////////////////////////////// + // FSelfRegisteringExec interface + virtual bool Exec(class UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar ) override; + + protected: /** @@ -165,9 +182,10 @@ protected: */ virtual void ConvertServerFilenameToClientFilename(FString& FilenameToConvert); - virtual void FillGetFileList(FNetworkFileArchive& Payload, bool bInStreamingFileRequest); + virtual void FillGetFileList(FNetworkFileArchive& Payload); - virtual void ProcessServerInitialResponse(FArrayReader& InResponse, int32 OutServerPackageVersion, int32 OutServerPackageLicenseeVersion); + virtual void ProcessServerInitialResponse(FArrayReader& InResponse, int32& OutServerPackageVersion, int32& OutServerPackageLicenseeVersion); + virtual void ProcessServerCachedFilesResponse(FArrayReader& InReponse, const int32 ServerPackageVersion, const int32 ServerPackageLicenseeVersion ); private: @@ -240,6 +258,26 @@ protected: bool bIsUsable; int32 FileServerPort; + // the connection flags are passed to the server during GetFileList + // the server may cache them + EConnectionFlags ConnectionFlags; + // Frequency to send heartbeats to server in seconds set to negative number to disable + float HeartbeatFrequency; + + + // some stats for messuring network platform file performance + double TotalWriteTime; // total non async time spent writing to disk + double TotalNetworkSyncTime; // total non async time spent syncing to network + int32 TotalFilesSynced; // total number files synced from network + int32 TotalUnsolicitedPackages; // total number unsolicited files synced + int32 TotalFilesFoundLocally; + int32 UnsolicitedPackagesHits; // total number of hits from waiting on unsolicited packages + int32 UnsolicitedPackageWaits; // total number of waits on unsolicited packages + double TotalTimeSpentInUnsolicitedPackages; // total time async processing unsolicited packages + double TotalWaitForAsyncUnsolicitedPackages; // total time spent waiting for unsolicited packages + + + private: /* Unsolicitied files events */ diff --git a/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileServer.cpp b/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileServer.cpp index ff1b8a418be8..da63dc126ac9 100644 --- a/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileServer.cpp +++ b/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileServer.cpp @@ -16,21 +16,20 @@ class FNetworkFileServerClientConnectionThreaded { public: - FNetworkFileServerClientConnectionThreaded(FSocket* InSocket, const FFileRequestDelegate& InFileRequestDelegate, - const FRecompileShadersDelegate& InRecompileShadersDelegate, const TArray& InActiveTargetPlatforms ) - : FNetworkFileServerClientConnection( InFileRequestDelegate,InRecompileShadersDelegate,InActiveTargetPlatforms) + FNetworkFileServerClientConnectionThreaded(FSocket* InSocket, const FNetworkFileDelegateContainer* NetworkFileDelegates, const TArray& InActiveTargetPlatforms ) + : FNetworkFileServerClientConnection( NetworkFileDelegates, InActiveTargetPlatforms) ,Socket(InSocket) { Running.Set(true); StopRequested.Reset(); - + #if UE_BUILD_DEBUG - // this thread needs more space in debug builds as it tries to log messages and such - const static uint32 NetworkFileServerThreadSize = 2 * 1024 * 1024; + // this thread needs more space in debug builds as it tries to log messages and such + const static uint32 NetworkFileServerThreadSize = 2 * 1024 * 1024; #else - const static uint32 NetworkFileServerThreadSize = 1 * 1024 * 1024; + const static uint32 NetworkFileServerThreadSize = 1 * 1024 * 1024; #endif - WorkerThread = FRunnableThread::Create(this, TEXT("FNetworkFileServerClientConnection"), NetworkFileServerThreadSize, TPri_AboveNormal); + WorkerThread = FRunnableThread::Create(this, TEXT("FNetworkFileServerClientConnection"), NetworkFileServerThreadSize, TPri_AboveNormal); } @@ -102,7 +101,6 @@ public: } private: - FSocket* Socket; FThreadSafeCounter StopRequested; FThreadSafeCounter Running; @@ -114,7 +112,8 @@ private: /* FNetworkFileServer constructors *****************************************************************************/ -FNetworkFileServer::FNetworkFileServer( int32 InPort, const FFileRequestDelegate* InFileRequestDelegate,const FRecompileShadersDelegate* InRecompileShadersDelegate, const TArray& InActiveTargetPlatforms ) +FNetworkFileServer::FNetworkFileServer( int32 InPort, FNetworkFileDelegateContainer InNetworkFileDelegateContainer, + const TArray& InActiveTargetPlatforms ) :ActiveTargetPlatforms(InActiveTargetPlatforms) { if(InPort <0) @@ -126,15 +125,7 @@ FNetworkFileServer::FNetworkFileServer( int32 InPort, const FFileRequestDelegate StopRequested.Set(false); UE_LOG(LogFileServer, Warning, TEXT("Unreal Network File Server starting up...")); - if (InFileRequestDelegate && InFileRequestDelegate->IsBound()) - { - FileRequestDelegate = *InFileRequestDelegate; - } - - if (InRecompileShadersDelegate && InRecompileShadersDelegate->IsBound()) - { - RecompileShadersDelegate = *InRecompileShadersDelegate; - } + NetworkFileDelegates = InNetworkFileDelegateContainer; // make sure sockets are going ISocketSubsystem* SocketSubsystem = ISocketSubsystem::Get(); @@ -256,7 +247,7 @@ uint32 FNetworkFileServer::Run( ) } } - FNetworkFileServerClientConnectionThreaded* Connection = new FNetworkFileServerClientConnectionThreaded(ClientSocket, FileRequestDelegate, RecompileShadersDelegate, ActiveTargetPlatforms); + FNetworkFileServerClientConnectionThreaded* Connection = new FNetworkFileServerClientConnectionThreaded(ClientSocket, &NetworkFileDelegates, ActiveTargetPlatforms); Connections.Add(Connection); UE_LOG(LogFileServer, Display, TEXT( "Client %s connected." ), *Connection->GetDescription() ); } @@ -315,6 +306,7 @@ bool FNetworkFileServer::GetAddressList( TArray >& Out return (OutAddresses.Num() > 0); } + bool FNetworkFileServer::IsItReadyToAcceptConnections(void) const { return (Running.GetValue() != 0); diff --git a/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileServer.h b/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileServer.h index fb0d9a456b0e..dc703f23dfed 100644 --- a/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileServer.h +++ b/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileServer.h @@ -27,8 +27,7 @@ public: * @param InPort The port number to bind to (0 = any available port). * @param InFileRequestDelegate */ - FNetworkFileServer( int32 InPort, const FFileRequestDelegate* InFileRequestDelegate, - const FRecompileShadersDelegate* InRecompileShadersDelegate, const TArray& InActiveTargetPlatforms ); + FNetworkFileServer( int32 InPort, FNetworkFileDelegateContainer InNetworkFileDelegateContainer, const TArray& InActiveTargetPlatforms ); /** * Destructor. @@ -62,7 +61,6 @@ public: virtual FString GetSupportedProtocol() const override; virtual int32 NumConnections() const override; virtual void Shutdown() override; - private: // Holds the server (listening) socket. @@ -82,11 +80,7 @@ private: public: - // Holds a delegate to be invoked on every sync request. - FFileRequestDelegate FileRequestDelegate; - - // Holds a delegate to be invoked when a client requests a shader recompile. - FRecompileShadersDelegate RecompileShadersDelegate; + FNetworkFileDelegateContainer NetworkFileDelegates; // cached copy of the active target platforms (if any) const TArray ActiveTargetPlatforms; diff --git a/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileServerConnection.cpp b/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileServerConnection.cpp index 46f1816dcff9..8c271217bef3 100644 --- a/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileServerConnection.cpp +++ b/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileServerConnection.cpp @@ -13,31 +13,60 @@ #include "NetworkFileSystemLog.h" #include "Misc/PackageName.h" #include "Interfaces/ITargetPlatform.h" +#include "HAL/PlatformTime.h" + + +/** + * Helper function for resolving engine and game sandbox paths + */ +void GetSandboxRootDirectories(FSandboxPlatformFile* Sandbox, FString& SandboxEngine, FString& SandboxGame, const FString& LocalEngineDir, const FString& LocalGameDir) +{ + SandboxEngine = Sandbox->ConvertToSandboxPath(*LocalEngineDir); + if (SandboxEngine.EndsWith(TEXT("/"), ESearchCase::CaseSensitive) == false) + { + SandboxEngine += TEXT("/"); + } + + // we need to add an extra bit to the game path to make the sandbox convert it correctly (investigate?) + // @todo: double check this + SandboxGame = Sandbox->ConvertToSandboxPath(*(LocalGameDir + TEXT("a.txt"))).Replace(TEXT("a.txt"), TEXT("")); +} /* FNetworkFileServerClientConnection structors *****************************************************************************/ -FNetworkFileServerClientConnection::FNetworkFileServerClientConnection( const FFileRequestDelegate& InFileRequestDelegate, - const FRecompileShadersDelegate& InRecompileShadersDelegate, const TArray& InActiveTargetPlatforms ) +FNetworkFileServerClientConnection::FNetworkFileServerClientConnection( const FNetworkFileDelegateContainer* InNetworkFileDelegates, const TArray& InActiveTargetPlatforms ) : LastHandleId(0) , Sandbox(NULL) + , NetworkFileDelegates(InNetworkFileDelegates) , ActiveTargetPlatforms(InActiveTargetPlatforms) -{ - if (InFileRequestDelegate.IsBound()) - { - FileRequestDelegate = InFileRequestDelegate; - } +{ + //stats + FileRequestDelegateTime = 0.0; + PackageFileTime = 0.0; + UnsolicitedFilesTime = 0.0; - if (InRecompileShadersDelegate.IsBound()) + FileRequestCount = 0; + UnsolicitedFilesCount = 0; + PackageRequestsSucceeded = 0; + PackageRequestsFailed = 0; + FileBytesSent = 0; + + if ( NetworkFileDelegates && NetworkFileDelegates->OnFileModifiedCallback ) { - RecompileShadersDelegate = InRecompileShadersDelegate; + NetworkFileDelegates->OnFileModifiedCallback->AddRaw(this, &FNetworkFileServerClientConnection::FileModifiedCallback); } } FNetworkFileServerClientConnection::~FNetworkFileServerClientConnection( ) { + if (NetworkFileDelegates && NetworkFileDelegates->OnFileModifiedCallback) + { + NetworkFileDelegates->OnFileModifiedCallback->RemoveAll(this); + } + // close all the files the client had opened through us when the client disconnects for (TMap::TIterator It(OpenFiles); It; ++It) { @@ -73,44 +102,51 @@ void FNetworkFileServerClientConnection::ConvertClientFilenameToServerFilename(F } } + /** * Fixup sandbox paths to match what package loading will request on the client side. e.g. * Sandbox path: "../../../Elemental/Content/Elemental/Effects/FX_Snow_Cracks/Crack_02/Materials/M_SnowBlast.uasset -> * client path: "../../../Samples/Showcases/Elemental/Content/Elemental/Effects/FX_Snow_Cracks/Crack_02/Materials/M_SnowBlast.uasset" * This ensures that devicelocal-cached files will be properly timestamp checked before deletion. */ -static TMap FixupSandboxPathsForClient(FSandboxPlatformFile* Sandbox, const TMap& SandboxPaths, const FString& LocalEngineDir, const FString& LocalGameDir, bool bLowerCaseFiles) +TMap FNetworkFileServerClientConnection::FixupSandboxPathsForClient(const TMap& SandboxPaths) { - TMap FixedFiletimes; - FString SandboxEngine = Sandbox->ConvertToSandboxPath(*LocalEngineDir); - if (SandboxEngine.EndsWith(TEXT("/"), ESearchCase::CaseSensitive) == false) - { - SandboxEngine += TEXT("/"); - } + TMap FixedFiletimes; - // we need to add an extra bit to the game path to make the sandbox convert it correctly (investigate?) - // @todo: double check this - FString SandboxGame = Sandbox->ConvertToSandboxPath(*(LocalGameDir + TEXT("a.txt"))).Replace(TEXT("a.txt"), TEXT("")); - // since the sandbox remaps from A/B/C to C, and the client has no idea of this, we need to put the files // into terms of the actual LocalGameDir, which is all that the client knows about for (TMap::TConstIterator It(SandboxPaths); It; ++It) { - FString Fixed = Sandbox->ConvertToSandboxPath(*It.Key()); - Fixed = Fixed.Replace(*SandboxEngine, *LocalEngineDir); - Fixed = Fixed.Replace(*SandboxGame, *LocalGameDir); - - if (bLowerCaseFiles) - { - Fixed = Fixed.ToLower(); - } - FixedFiletimes.Add(Fixed, It.Value()); + FixedFiletimes.Add(FixupSandboxPathForClient(It.Key()), It.Value()); } return FixedFiletimes; } -void FNetworkFileServerClientConnection::ConvertServerFilenameToClientFilename(FString& FilenameToConvert) +/** + * Fixup sandbox paths to match what package loading will request on the client side. e.g. + * Sandbox path: "../../../Elemental/Content/Elemental/Effects/FX_Snow_Cracks/Crack_02/Materials/M_SnowBlast.uasset -> + * client path: "../../../Samples/Showcases/Elemental/Content/Elemental/Effects/FX_Snow_Cracks/Crack_02/Materials/M_SnowBlast.uasset" + * This ensures that devicelocal-cached files will be properly timestamp checked before deletion. + */ +FString FNetworkFileServerClientConnection::FixupSandboxPathForClient(const FString& Filename) { + const FString& LocalEngineDir = FPaths::EngineDir(); + const FString& LocalGameDir = FPaths::GameDir(); + + FString Fixed = Sandbox->ConvertToSandboxPath(*Filename); + Fixed = Fixed.Replace(*SandboxEngine, *LocalEngineDir); + Fixed = Fixed.Replace(*SandboxGame, *LocalGameDir); + + if (bSendLowerCase) + { + Fixed = Fixed.ToLower(); + } + return Fixed; +} + +/*void FNetworkFileServerClientConnection::ConvertServerFilenameToClientFilename(FString& FilenameToConvert) +{ + if (FilenameToConvert.StartsWith(FPaths::EngineDir())) { FilenameToConvert = FilenameToConvert.Replace(*(FPaths::EngineDir()), *ConnectedEngineDir); @@ -130,7 +166,7 @@ void FNetworkFileServerClientConnection::ConvertServerFilenameToClientFilename(F FilenameToConvert = FilenameToConvert.Replace(*(FPaths::GameDir()), *ConnectedGameDir); } #endif -} +}*/ static FCriticalSection SocketCriticalSection; @@ -292,6 +328,8 @@ bool FNetworkFileServerClientConnection::ProcessPayload(FArchive& Ar) if (bSendUnsolicitedFiles && Result ) { + double StartTime; + StartTime = FPlatformTime::Seconds(); for (int32 Index = 0; Index < NumUnsolictedFiles; Index++) { FBufferArchive OutUnsolicitedFile; @@ -300,8 +338,12 @@ bool FNetworkFileServerClientConnection::ProcessPayload(FArchive& Ar) UE_LOG(LogFileServer, Display, TEXT("Returning unsolicited file %s with %d bytes"), *UnsolictedFiles[Index], OutUnsolicitedFile.Num()); Result &= SendPayload(OutUnsolicitedFile); + ++UnsolicitedFilesCount; } UnsolictedFiles.RemoveAt(0, NumUnsolictedFiles); + + + UnsolicitedFilesTime += 1000.0f * float(FPlatformTime::Seconds() - StartTime); } } @@ -339,7 +381,7 @@ void FNetworkFileServerClientConnection::ProcessOpenFile( FArchive& In, FArchive } TArray NewUnsolictedFiles; - FileRequestDelegate.ExecuteIfBound(Filename, ConnectedPlatformName, NewUnsolictedFiles); + NetworkFileDelegates->FileRequestDelegate.ExecuteIfBound(Filename, ConnectedPlatformName, NewUnsolictedFiles); FDateTime ServerTimeStamp = Sandbox->GetTimeStamp(*Filename); int64 ServerFileSize = 0; @@ -486,7 +528,7 @@ void FNetworkFileServerClientConnection::ProcessGetFileInfo( FArchive& In, FArch if (Info.FileExists) { TArray NewUnsolictedFiles; - FileRequestDelegate.ExecuteIfBound(Filename, ConnectedPlatformName, NewUnsolictedFiles); + NetworkFileDelegates->FileRequestDelegate.ExecuteIfBound(Filename, ConnectedPlatformName, NewUnsolictedFiles); } // get the rest of the info @@ -672,19 +714,37 @@ bool FNetworkFileServerClientConnection::ProcessGetFileList( FArchive& In, FArch FString EngineRelativePath; FString GameRelativePath; TArray RootDirectories; - bool bIsStreamingRequest = false; + + EConnectionFlags ConnectionFlags; + + FString ClientVersionInfo; In << TargetPlatformNames; In << GameName; In << EngineRelativePath; In << GameRelativePath; In << RootDirectories; - In << bIsStreamingRequest; + In << ConnectionFlags; + In << ClientVersionInfo; + + if ( NetworkFileDelegates->NewConnectionDelegate.IsBound() ) + { + bool bIsValidVersion = true; + for ( const FString& TargetPlatform : TargetPlatformNames ) + { + bIsValidVersion &= NetworkFileDelegates->NewConnectionDelegate.Execute(ClientVersionInfo, TargetPlatform ); + } + if ( bIsValidVersion == false ) + { + return false; + } + } + + const bool bIsStreamingRequest = (ConnectionFlags & EConnectionFlags::Streaming) == EConnectionFlags::Streaming; + const bool bIsPrecookedIterativeRequest = (ConnectionFlags & EConnectionFlags::PreCookedIterative) == EConnectionFlags::PreCookedIterative; ConnectedPlatformName = TEXT(""); - bool bSendLowerCase = false; - // if we didn't find one (and this is a dumb server - no active platforms), then just use what was sent if (ActiveTargetPlatforms.Num() == 0) { @@ -756,10 +816,23 @@ bool FNetworkFileServerClientConnection::ProcessGetFileList( FArchive& In, FArch // figure out the sandbox directory // @todo: This should use FPlatformMisc::SavedDirectory(GameName) FString SandboxDirectory; - if ( FPaths::IsProjectFilePathSet() ) + if (NetworkFileDelegates->SandboxPathOverrideDelegate.IsBound() ) + { + SandboxDirectory = NetworkFileDelegates->SandboxPathOverrideDelegate.Execute(); + // if the sandbox directory delegate returns a path with the platform name in it then replace it :) + SandboxDirectory.ReplaceInline(TEXT("[Platform]"), *ConnectedPlatformName); + } + else if ( FPaths::IsProjectFilePathSet() ) { FString ProjectDir = FPaths::GetPath(FPaths::GetProjectFilePath()); SandboxDirectory = FPaths::Combine(*ProjectDir, TEXT("Saved"), TEXT("Cooked"), *ConnectedPlatformName); + + // this is a workaround because the cooker and the networkfile server don't have access to eachother and therefore don't share the same Sandbox + // the cooker in cook in editor saves to the EditorCooked directory + if ( GIsEditor && !IsRunningCommandlet()) + { + SandboxDirectory = FPaths::Combine(*ProjectDir, TEXT("Saved"), TEXT("EditorCooked"), *ConnectedPlatformName); + } if( bIsStreamingRequest ) { RootDirectories.Add(ProjectDir); @@ -785,6 +858,9 @@ bool FNetworkFileServerClientConnection::ProcessGetFileList( FArchive& In, FArch Sandbox = new FSandboxPlatformFile(false); Sandbox->Initialize(&FPlatformFileManager::Get().GetPlatformFile(), *FString::Printf(TEXT("-sandbox=\"%s\""), *SandboxDirectory)); + GetSandboxRootDirectories(Sandbox, SandboxEngine, SandboxGame, LocalEngineDir, LocalGameDir); + + // make sure the global shaders are up to date before letting the client read any shaders // @todo: This will probably add about 1/2 second to the boot-up time of the client while the server does this // @note: We assume the delegate will write to the proper sandbox directory, should we pass in SandboxDirectory, or Sandbox? @@ -794,7 +870,7 @@ bool FNetworkFileServerClientConnection::ProcessGetFileList( FArchive& In, FArch RecompileData.ShaderPlatform = -1; RecompileData.ModifiedFiles = NULL; RecompileData.MeshMaterialMaps = NULL; - RecompileShadersDelegate.ExecuteIfBound(RecompileData); + NetworkFileDelegates->RecompileShadersDelegate.ExecuteIfBound(RecompileData); UE_LOG(LogFileServer, Display, TEXT("Getting files for %d directories, game = %s, platform = %s"), RootDirectories.Num(), *GameName, *ConnectedPlatformName); UE_LOG(LogFileServer, Display, TEXT(" Sandbox dir = %s"), *SandboxDirectory); @@ -824,6 +900,7 @@ bool FNetworkFileServerClientConnection::ProcessGetFileList( FArchive& In, FArch DirectoriesToSkip.Add(FString(RootDirectories[DirIndex] / TEXT("Saved/Logs"))); DirectoriesToSkip.Add(FString(RootDirectories[DirIndex] / TEXT("Saved/Sandboxes"))); DirectoriesToSkip.Add(FString(RootDirectories[DirIndex] / TEXT("Saved/Cooked"))); + DirectoriesToSkip.Add(FString(RootDirectories[DirIndex] / TEXT("Saved/EditorCooked"))); DirectoriesToSkip.Add(FString(RootDirectories[DirIndex] / TEXT("Saved/ShaderDebugInfo"))); DirectoriesToSkip.Add(FString(RootDirectories[DirIndex] / TEXT("Saved/StagedBuilds"))); DirectoriesToSkip.Add(FString(RootDirectories[DirIndex] / TEXT("Intermediate"))); @@ -853,9 +930,15 @@ bool FNetworkFileServerClientConnection::ProcessGetFileList( FArchive& In, FArch Out << LocalGameDir; // return the files and their timestamps - TMap FixedTimes = FixupSandboxPathsForClient(Sandbox, Visitor.FileTimes, LocalEngineDir, LocalGameDir, bSendLowerCase); + TMap FixedTimes = FixupSandboxPathsForClient(Visitor.FileTimes); Out << FixedTimes; +#if 0 // dump the list of files + for ( const auto& FileTime : Visitor.FileTimes) + { + UE_LOG(LogFileServer, Display, TEXT("Server list of files %s time %d"), *FileTime.Key, *FileTime.Value.ToString() ); + } +#endif // Do it again, preventing access to non-cooked files if( bIsStreamingRequest == false ) { @@ -921,20 +1004,52 @@ bool FNetworkFileServerClientConnection::ProcessGetFileList( FArchive& In, FArch } // return the cached files and their timestamps - FixedTimes = FixupSandboxPathsForClient(Sandbox, VisitorForCacheDates.FileTimes, LocalEngineDir, LocalGameDir, bSendLowerCase); + FixedTimes = FixupSandboxPathsForClient(VisitorForCacheDates.FileTimes); Out << FixedTimes; } + + + + if ( bIsPrecookedIterativeRequest ) + { + TMap PrecookedList; + NetworkFileDelegates->InitialPrecookedListDelegate.ExecuteIfBound(ConnectedPlatformName, PrecookedList); + + FixedTimes = FixupSandboxPathsForClient(PrecookedList); + Out << FixedTimes; + } + return true; } +void FNetworkFileServerClientConnection::FileModifiedCallback( const FString& Filename) +{ + FScopeLock Lock(&ModifiedFilesSection); + + // do we care about this file??? + + // translation here? + ModifiedFiles.AddUnique(Filename); +} void FNetworkFileServerClientConnection::ProcessHeartbeat( FArchive& In, FArchive& Out ) { + TArray FixedupModifiedFiles; // Protect the array - FScopeLock Lock(&ModifiedFilesSection); - + if (Sandbox) + { + FScopeLock Lock(&ModifiedFilesSection); + + for (const auto& ModifiedFile : ModifiedFiles) + { + FixedupModifiedFiles.Add(FixupSandboxPathForClient(ModifiedFile)); + } + ModifiedFiles.Empty(); + } // return the list of modified files - Out << ModifiedFiles; + Out << FixedupModifiedFiles; + + // @todo: note the last received time, and toss clients that don't heartbeat enough! @@ -956,18 +1071,25 @@ bool FNetworkFileServerClientConnection::PackageFile( FString& Filename, FArchiv // open file IFileHandle* File = Sandbox->OpenRead(*Filename); + if (!File) { + ++PackageRequestsFailed; + + UE_LOG(LogFileServer, Warning, TEXT("Opening file %s failed"), *Filename); ServerTimeStamp = FDateTime::MinValue(); // if this was a directory, this will make sure it is not confused with a zero byte file } else { + ++PackageRequestsSucceeded; + if (!File->Size()) { UE_LOG(LogFileServer, Warning, TEXT("Sending empty file %s...."), *Filename); } else { + FileBytesSent += File->Size(); // read it Contents.AddUninitialized(File->Size()); File->Read(Contents.GetData(), Contents.Num()); @@ -1003,7 +1125,7 @@ void FNetworkFileServerClientConnection::ProcessRecompileShaders( FArchive& In, In << RecompileData.SerializedShaderResources; In << RecompileData.bCompileChangedShaders; - RecompileShadersDelegate.ExecuteIfBound(RecompileData); + NetworkFileDelegates->RecompileShadersDelegate.ExecuteIfBound(RecompileData); // tell other side what to do! Out << RecompileModifiedFiles; @@ -1013,10 +1135,16 @@ void FNetworkFileServerClientConnection::ProcessRecompileShaders( FArchive& In, void FNetworkFileServerClientConnection::ProcessSyncFile( FArchive& In, FArchive& Out ) { + + double StartTime; + StartTime = FPlatformTime::Seconds(); + // get filename FString Filename; In << Filename; + UE_LOG(LogFileServer, Verbose, TEXT("Try sync file %s"), *Filename); + ConvertClientFilenameToServerFilename(Filename); //FString AbsFile(FString(*Sandbox->ConvertToAbsolutePathForExternalApp(*Filename)).MakeStandardFilename()); @@ -1024,7 +1152,11 @@ void FNetworkFileServerClientConnection::ProcessSyncFile( FArchive& In, FArchive TArray NewUnsolictedFiles; - FileRequestDelegate.ExecuteIfBound(Filename, ConnectedPlatformName, NewUnsolictedFiles); + NetworkFileDelegates->FileRequestDelegate.ExecuteIfBound(Filename, ConnectedPlatformName, NewUnsolictedFiles); + + FileRequestDelegateTime += 1000.0f * float(FPlatformTime::Seconds() - StartTime); + StartTime = FPlatformTime::Seconds(); + for (int32 Index = 0; Index < NewUnsolictedFiles.Num(); Index++) { @@ -1035,10 +1167,46 @@ void FNetworkFileServerClientConnection::ProcessSyncFile( FArchive& In, FArchive } PackageFile(Filename, Out); + + PackageFileTime += 1000.0f * float(FPlatformTime::Seconds() - StartTime); } + FString FNetworkFileServerClientConnection::GetDescription() const { return FString("Client For " ) + ConnectedPlatformName; } +bool FNetworkFileServerClientConnection::Exec(class UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar ) +{ + if (FParse::Command(&Cmd, TEXT("networkserverconnection"))) + { + if (FParse::Command(&Cmd, TEXT("stats"))) + { + + Ar.Logf(TEXT("Network server connection %s stats\n" + "FileRequestDelegateTime \t%fms \n" + "PackageFileTime \t%fms \n" + "UnsolicitedFilesTime \t%fms \n" + "FileRequestCount \t%d \n" + "UnsolicitedFilesCount \t%d \n" + "PackageRequestsSucceeded \t%d \n" + "PackageRequestsFailed \t%d \n" + "FileBytesSent \t%d \n"), + *GetDescription(), + FileRequestDelegateTime, + PackageFileTime, + UnsolicitedFilesTime, + FileRequestCount, + UnsolicitedFilesCount, + PackageRequestsSucceeded, + PackageRequestsFailed, + FileBytesSent); + + // there could be multiple network platform files so let them all report their stats + return false; + } + } + return false; +} + diff --git a/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileServerConnection.h b/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileServerConnection.h index d007f7fe79dd..e3963f5ef9e3 100644 --- a/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileServerConnection.h +++ b/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileServerConnection.h @@ -4,6 +4,7 @@ #include "CoreMinimal.h" #include "Interfaces/INetworkFileSystemModule.h" +#include "CoreMisc.h" class FSandboxPlatformFile; class ITargetPlatform; @@ -11,7 +12,7 @@ class ITargetPlatform; /** * This class processes all incoming messages from the client. */ -class FNetworkFileServerClientConnection +class FNetworkFileServerClientConnection : public FSelfRegisteringExec { public: @@ -19,10 +20,9 @@ public: * Creates and initializes a new instance. * * @param InSocket - The client socket to use. - * @param InFileRequestDelegate - A delegate to be invoked when the client requests a file. + * @param NetworkFileDelegates- delegates the client calls when events from the client happen */ - FNetworkFileServerClientConnection(const FFileRequestDelegate& InFileRequestDelegate, - const FRecompileShadersDelegate& InRecompileShadersDelegate, const TArray& InActiveTargetPlatforms ); + FNetworkFileServerClientConnection( const FNetworkFileDelegateContainer* NetworkFileDelegates , const TArray& InActiveTargetPlatforms ); /** * Destructor. @@ -62,7 +62,7 @@ protected: * * @param FilenameToConvert Upon input, the server version of the filename. After the call, the client version */ - void ConvertServerFilenameToClientFilename(FString& FilenameToConvert); + // void ConvertServerFilenameToClientFilename(FString& FilenameToConvert); /** Opens a file for reading or writing. */ void ProcessOpenFile(FArchive& In, FArchive& Out, bool bIsWriting); @@ -154,6 +154,36 @@ protected: virtual bool SendPayload( TArray &Out ) = 0; + + /** + * When a file is modified this callback is triggered + * cleans up any cached information about the file and notifies client + * + * @param Filename of the file which has been modified + */ + void FileModifiedCallback( const FString& Filename ); + + + virtual bool Exec(class UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) override; + + + /** + * Convert a path to a sandbox path and translate so the client can understand it + * + * @param Filename to convert + * @param bLowerCaseFiles conver the file name to all lower case + * @return Resulting fixed up path + */ + FString FixupSandboxPathForClient(const FString& Filename); + + /** + * Convert a path to a sandbox path and translate so the client can understand it + * + * @param Filename to convert + * @param bLowerCaseFiles conver the file name to all lower case + * @return Resulting fixed up path + */ + TMap FixupSandboxPathsForClient(const TMap& SandboxPaths); private: @@ -166,6 +196,15 @@ private: // Hold the game directory from the connected platform. FString ConnectedGameDir; + // Hold the sandbox engine directory for the connected platform + FString SandboxEngine; + + // hold the sandbox game directory for the connected platform + FString SandboxGame; + + // Should we send the filenames in lowercase + bool bSendLowerCase; + // Holds the last assigned handle id (0 = invalid). uint64 LastHandleId; @@ -187,12 +226,22 @@ private: // Holds the list of directories being watched. TArray WatchedDirectories; - // Holds a delegate to be invoked on every sync request. - FFileRequestDelegate FileRequestDelegate; - - // Holds a delegate to be invoked when a client requests a shader recompile. - FRecompileShadersDelegate RecompileShadersDelegate; + const FNetworkFileDelegateContainer* NetworkFileDelegates; // cached copy of the active target platforms (if any) const TArray& ActiveTargetPlatforms; + + + ////////////////////////////////////////////////////////////////////////// + //stats + double FileRequestDelegateTime; + double PackageFileTime; + double UnsolicitedFilesTime; + + int32 FileRequestCount; + int32 UnsolicitedFilesCount; + int32 PackageRequestsSucceeded; + int32 PackageRequestsFailed; + int32 FileBytesSent; + }; diff --git a/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileServerHttp.cpp b/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileServerHttp.cpp index b8aac650eb3f..514745ff267f 100644 --- a/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileServerHttp.cpp +++ b/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileServerHttp.cpp @@ -17,9 +17,8 @@ class FNetworkFileServerClientConnectionHTTP : public FNetworkFileServerClientCo { public: - FNetworkFileServerClientConnectionHTTP(const FFileRequestDelegate& InFileRequestDelegate, - const FRecompileShadersDelegate& InRecompileShadersDelegate, const TArray& InActiveTargetPlatforms ) - : FNetworkFileServerClientConnection( InFileRequestDelegate,InRecompileShadersDelegate,InActiveTargetPlatforms) + FNetworkFileServerClientConnectionHTTP(const FNetworkFileDelegateContainer* NetworkFileDelegates, const TArray& InActiveTargetPlatforms ) + : FNetworkFileServerClientConnection( NetworkFileDelegates, InActiveTargetPlatforms) { } @@ -81,8 +80,7 @@ static struct lws_protocols Protocols[] = { FNetworkFileServerHttp::FNetworkFileServerHttp( int32 InPort, - const FFileRequestDelegate* InFileRequestDelegate, - const FRecompileShadersDelegate* InRecompileShadersDelegate, + FNetworkFileDelegateContainer InNetworkFileDelegateContainer, const TArray& InActiveTargetPlatforms ) :ActiveTargetPlatforms(InActiveTargetPlatforms) @@ -95,16 +93,7 @@ FNetworkFileServerHttp::FNetworkFileServerHttp( UE_LOG(LogFileServer, Warning, TEXT("Unreal Network Http File Server starting up...")); - if (InFileRequestDelegate && InFileRequestDelegate->IsBound()) - { - FileRequestDelegate = *InFileRequestDelegate; - } - - if (InRecompileShadersDelegate && InRecompileShadersDelegate->IsBound()) - { - RecompileShadersDelegate = *InRecompileShadersDelegate; - } - + NetworkFileDelegates = InNetworkFileDelegateContainer; StopRequested.Reset(); Ready.Reset(); @@ -250,7 +239,7 @@ FNetworkFileServerHttp::~FNetworkFileServerHttp() FNetworkFileServerClientConnectionHTTP* FNetworkFileServerHttp::CreateNewConnection() { - return new FNetworkFileServerClientConnectionHTTP(FileRequestDelegate,RecompileShadersDelegate,ActiveTargetPlatforms); + return new FNetworkFileServerClientConnectionHTTP(&NetworkFileDelegates,ActiveTargetPlatforms); } // Have a similar process function for the normal tcp connection. diff --git a/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileServerHttp.h b/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileServerHttp.h index c243c3702458..e7c0019d778a 100644 --- a/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileServerHttp.h +++ b/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileServerHttp.h @@ -48,8 +48,7 @@ class FNetworkFileServerHttp { public: - FNetworkFileServerHttp(int32 InPort, const FFileRequestDelegate* InFileRequestDelegate, - const FRecompileShadersDelegate* InRecompileShadersDelegate, const TArray& InActiveTargetPlatforms ); + FNetworkFileServerHttp(int32 InPort, FNetworkFileDelegateContainer InNetworkFileDelegateContainer, const TArray& InActiveTargetPlatforms ); // INetworkFileServer Interface. @@ -81,11 +80,7 @@ private: // factory method for creating a new Client Connection. class FNetworkFileServerClientConnectionHTTP* CreateNewConnection(); - // Holds a delegate to be invoked on every sync request. - FFileRequestDelegate FileRequestDelegate; - - // Holds a delegate to be invoked when a client requests a shader recompile. - FRecompileShadersDelegate RecompileShadersDelegate; + FNetworkFileDelegateContainer NetworkFileDelegates; // cached copy of the active target platforms (if any) const TArray ActiveTargetPlatforms; diff --git a/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileSystemModule.cpp b/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileSystemModule.cpp index 41a0d4d408fa..157301e93bad 100644 --- a/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileSystemModule.cpp +++ b/Engine/Source/Runtime/NetworkFileSystem/Private/NetworkFileSystemModule.cpp @@ -23,7 +23,7 @@ public: // INetworkFileSystemModule interface - virtual INetworkFileServer* CreateNetworkFileServer( bool bLoadTargetPlatforms, int32 Port, const FFileRequestDelegate* InFileRequestDelegate, const FRecompileShadersDelegate* InRecompileShadersDelegate, const ENetworkFileServerProtocol Protocol ) const override + virtual INetworkFileServer* CreateNetworkFileServer( bool bLoadTargetPlatforms, int32 Port, FNetworkFileDelegateContainer NetworkFileDelegateContainer, const ENetworkFileServerProtocol Protocol ) const override { TArray ActiveTargetPlatforms; if (bLoadTargetPlatforms) @@ -46,10 +46,10 @@ public: { #if ENABLE_HTTP_FOR_NFS case NFSP_Http: - return new FNetworkFileServerHttp(Port, InFileRequestDelegate, InRecompileShadersDelegate, ActiveTargetPlatforms); + return new FNetworkFileServerHttp(Port, NetworkFileDelegateContainer, ActiveTargetPlatforms); #endif case NFSP_Tcp: - return new FNetworkFileServer(Port, InFileRequestDelegate, InRecompileShadersDelegate, ActiveTargetPlatforms); + return new FNetworkFileServer(Port, NetworkFileDelegateContainer, ActiveTargetPlatforms); } return NULL; diff --git a/Engine/Source/Runtime/NetworkFileSystem/Public/Interfaces/INetworkFileServer.h b/Engine/Source/Runtime/NetworkFileSystem/Public/Interfaces/INetworkFileServer.h index 195500db71ca..84f86114535c 100644 --- a/Engine/Source/Runtime/NetworkFileSystem/Public/Interfaces/INetworkFileServer.h +++ b/Engine/Source/Runtime/NetworkFileSystem/Public/Interfaces/INetworkFileServer.h @@ -29,6 +29,7 @@ public: */ virtual bool GetAddressList( TArray >& OutAddresses ) const = 0; + /** * Gets the list of local network addresses that the file server listens on. * diff --git a/Engine/Source/Runtime/NetworkFileSystem/Public/Interfaces/INetworkFileSystemModule.h b/Engine/Source/Runtime/NetworkFileSystem/Public/Interfaces/INetworkFileSystemModule.h index 8a4f807f3ea0..4c23972d6092 100644 --- a/Engine/Source/Runtime/NetworkFileSystem/Public/Interfaces/INetworkFileSystemModule.h +++ b/Engine/Source/Runtime/NetworkFileSystem/Public/Interfaces/INetworkFileSystemModule.h @@ -51,6 +51,60 @@ struct FShaderRecompileData */ DECLARE_DELEGATE_OneParam(FRecompileShadersDelegate, const FShaderRecompileData&); +/** + * Delegate which returns an override for the sandbox path + */ +DECLARE_DELEGATE_RetVal( FString, FSandboxPathDelegate); + +/** + * Delegate which is called when an outside system modifies a file + */ +DECLARE_MULTICAST_DELEGATE_OneParam( FOnFileModifiedDelegate, const FString& ); + + +/** + * Delegate which is called when a new connection is made to a file server client + * + * @param 1 Version string + * @param 2 Platform name + * @return return false if the connection should be destroyed + */ +DECLARE_DELEGATE_RetVal_TwoParams( bool, FNewConnectionDelegate, const FString&, const FString& ); + + +/** + * Delegate which returns a list of all the files which should already be deployed to the devkit + * + * @param 1 IN, Platform to get precooked file list + * @param 2 OUT, list of precooked files + */ +typedef TMap FFileTimeMap; +DECLARE_DELEGATE_TwoParams( FInitialPrecookedListDelegate, const FString&, FFileTimeMap& ); + + + +// container struct for delegates which the network file system uses +struct FNetworkFileDelegateContainer +{ +public: + FNetworkFileDelegateContainer() : + NewConnectionDelegate(nullptr), + InitialPrecookedListDelegate(nullptr), + SandboxPathOverrideDelegate(nullptr), + FileRequestDelegate(nullptr), + RecompileShadersDelegate(nullptr), + OnFileModifiedCallback(nullptr) + {} + FNewConnectionDelegate NewConnectionDelegate; + FInitialPrecookedListDelegate InitialPrecookedListDelegate; + FSandboxPathDelegate SandboxPathOverrideDelegate; + FFileRequestDelegate FileRequestDelegate; + FRecompileShadersDelegate RecompileShadersDelegate; + + FOnFileModifiedDelegate* OnFileModifiedCallback; // this is called from other systems to notify the network file system that a file has been modified hence the terminology callback +}; + + enum ENetworkFileServerProtocol { NFSP_Tcp, @@ -75,7 +129,7 @@ public: * * @return The new file server, or nullptr if creation failed. */ - virtual INetworkFileServer* CreateNetworkFileServer( bool bLoadTargetPlatforms, int32 Port = -1, const FFileRequestDelegate* InFileRequestDelegate = nullptr, const FRecompileShadersDelegate* InRecompileShadersDelegate = nullptr, const ENetworkFileServerProtocol Protocol = NFSP_Tcp ) const = 0; + virtual INetworkFileServer* CreateNetworkFileServer( bool bLoadTargetPlatforms, int32 Port = -1, FNetworkFileDelegateContainer InNetworkFileDelegateContainer = FNetworkFileDelegateContainer(), const ENetworkFileServerProtocol Protocol = NFSP_Tcp ) const = 0; public: diff --git a/Engine/Source/Runtime/NetworkReplayStreaming/HttpNetworkReplayStreaming/Private/HttpNetworkReplayStreaming.cpp b/Engine/Source/Runtime/NetworkReplayStreaming/HttpNetworkReplayStreaming/Private/HttpNetworkReplayStreaming.cpp index c172d4a93d16..56fa2a278b8e 100644 --- a/Engine/Source/Runtime/NetworkReplayStreaming/HttpNetworkReplayStreaming/Private/HttpNetworkReplayStreaming.cpp +++ b/Engine/Source/Runtime/NetworkReplayStreaming/HttpNetworkReplayStreaming/Private/HttpNetworkReplayStreaming.cpp @@ -1075,7 +1075,7 @@ void FHttpNetworkReplayStreamer::ConditionallyDownloadNextChunk() return; // Unless it's critical (i.e. bReallyNeedToDownloadChunk is true), never try faster than MIN_WAIT_FOR_NEXT_CHUNK_IN_SECONDS } - if ( DownloadElapsedTime < MAX_WAIT_FOR_NEXT_CHUNK_IN_SECONDS && ( StreamTimeRangeEnd - StreamTimeRangeStart ) > 0 && StreamArchive.Buffer.Num() > 0 ) + if ( DownloadElapsedTime < MAX_WAIT_FOR_NEXT_CHUNK_IN_SECONDS && StreamTimeRangeEnd > StreamTimeRangeStart && StreamArchive.Buffer.Num() > 0 ) { // Make a guess on how far we're in const float PercentIn = StreamArchive.Buffer.Num() > 0 ? ( float )StreamArchive.Pos / ( float )StreamArchive.Buffer.Num() : 0.0f; diff --git a/Engine/Source/Runtime/Niagara/Classes/NiagaraDataInterfaceSpline.h b/Engine/Source/Runtime/Niagara/Classes/NiagaraDataInterfaceSpline.h index 72ec9bb7d498..db8486fd8302 100644 --- a/Engine/Source/Runtime/Niagara/Classes/NiagaraDataInterfaceSpline.h +++ b/Engine/Source/Runtime/Niagara/Classes/NiagaraDataInterfaceSpline.h @@ -60,7 +60,7 @@ private: //Cached ptr to component we sample from. USplineComponent* Component; - //Cached ComponentToWorld. + //Cached GetComponentTransform(). FMatrix Transform; //InverseTranspose of above for transforming normals/tangents. FMatrix TransformInverseTransposed; diff --git a/Engine/Source/Runtime/Niagara/Classes/NiagaraDataInterfaceStaticMesh.h b/Engine/Source/Runtime/Niagara/Classes/NiagaraDataInterfaceStaticMesh.h index ac5c79646b29..2c711a92d386 100644 --- a/Engine/Source/Runtime/Niagara/Classes/NiagaraDataInterfaceStaticMesh.h +++ b/Engine/Source/Runtime/Niagara/Classes/NiagaraDataInterfaceStaticMesh.h @@ -176,12 +176,12 @@ private: //Cached ptr to actual mesh we sample from. UStaticMesh* Mesh; - //Cached ComponentToWorld. + //Cached GetComponentTransform(). FMatrix Transform; //InverseTranspose of above for transforming normals/tangents. FMatrix TransformInverseTransposed; - //Cached ComponentToWorld from previous tick. + //Cached GetComponentTransform() from previous tick. FMatrix PrevTransform; //InverseTranspose of above for transforming normals/tangents. FMatrix PrevTransformInverseTransposed; diff --git a/Engine/Source/Runtime/Niagara/Classes/NiagaraSimulation.h b/Engine/Source/Runtime/Niagara/Classes/NiagaraSimulation.h index 727dc0ca0765..1d2307d3be14 100644 --- a/Engine/Source/Runtime/Niagara/Classes/NiagaraSimulation.h +++ b/Engine/Source/Runtime/Niagara/Classes/NiagaraSimulation.h @@ -197,7 +197,7 @@ private: FNiagaraDataSet Data; /** Keep partial particle spawns from last frame */ float SpawnRemainder; - /** The cached ComponentToWorld transform. */ + /** The cached GetComponentTransform() transform. */ FTransform CachedComponentToWorld; NiagaraEffectRenderer *EffectRenderer; diff --git a/Engine/Source/Runtime/Niagara/Private/NiagaraActor.cpp b/Engine/Source/Runtime/Niagara/Private/NiagaraActor.cpp index 6f9955ca6702..f5f87c37a469 100644 --- a/Engine/Source/Runtime/Niagara/Private/NiagaraActor.cpp +++ b/Engine/Source/Runtime/Niagara/Private/NiagaraActor.cpp @@ -64,15 +64,6 @@ ANiagaraActor::ANiagaraActor(const FObjectInitializer& ObjectInitializer) #endif // WITH_EDITORONLY_DATA } -/** Returns NiagaraComponent subobject **/ -UNiagaraComponent* ANiagaraActor::GetNiagaraComponent() const { return NiagaraComponent; } -#if WITH_EDITORONLY_DATA -/** Returns SpriteComponent subobject **/ -UBillboardComponent* ANiagaraActor::GetSpriteComponent() const { return SpriteComponent; } -/** Returns ArrowComponent subobject **/ -UArrowComponent* ANiagaraActor::GetArrowComponent() const { return ArrowComponent; } -#endif - #if WITH_EDITOR bool ANiagaraActor::GetReferencedContentObjects(TArray& Objects) const { diff --git a/Engine/Source/Runtime/Niagara/Private/NiagaraCollision.cpp b/Engine/Source/Runtime/Niagara/Private/NiagaraCollision.cpp index b1052e91662b..491c9837d1a9 100644 --- a/Engine/Source/Runtime/Niagara/Private/NiagaraCollision.cpp +++ b/Engine/Source/Runtime/Niagara/Private/NiagaraCollision.cpp @@ -39,7 +39,7 @@ void FNiagaraCollisionBatch::KickoffNewBatch(FNiagaraSimulation *Sim, float Delt PosIt.Get(Position); VelIt.Get(Velocity); - FCollisionQueryParams QueryParams; + FCollisionQueryParams QueryParams(SCENE_QUERY_STAT(NiagraAsync)); QueryParams.OwnerTag = "Niagara"; FTraceHandle Handle = EffectWorld->AsyncLineTraceByChannel(EAsyncTraceType::Single, Position, Position + Velocity*DeltaSeconds, ECollisionChannel::ECC_WorldStatic, QueryParams, FCollisionResponseParams::DefaultResponseParam, nullptr, i); FNiagaraCollisionTrace Trace; diff --git a/Engine/Source/Runtime/Niagara/Private/NiagaraComponent.cpp b/Engine/Source/Runtime/Niagara/Private/NiagaraComponent.cpp index 09670986187c..602498f47646 100644 --- a/Engine/Source/Runtime/Niagara/Private/NiagaraComponent.cpp +++ b/Engine/Source/Runtime/Niagara/Private/NiagaraComponent.cpp @@ -363,6 +363,11 @@ FPrimitiveSceneProxy* UNiagaraComponent::CreateSceneProxy() void UNiagaraComponent::GetUsedMaterials(TArray& OutMaterials, bool bGetDebugMaterials) const { + if (!EffectInstance.IsValid()) + { + return; + } + for (TSharedRef Sim : EffectInstance->GetEmitters()) { #if WITH_EDITORONLY_DATA @@ -463,7 +468,7 @@ FNiagaraVariable* UNiagaraComponent::CopyOnWriteParameter(FGuid ParameterId) // Add if the existing override variable doesn't exist, make one and force invalidation to happen so it // propagates through to the effects. - if (ExistingVar == nullptr && SrcVariable != nullptr) + if (ExistingVar == nullptr) { int32 AddIndex = EffectParameterLocalOverrides.Add(*SrcVariable); ExistingVar = &EffectParameterLocalOverrides[AddIndex]; @@ -503,7 +508,7 @@ FNiagaraVariable* UNiagaraComponent::CopyOnWriteParameter(FName VarName, FNiagar // Add if the existing override variable doesn't exist, make one and force invalidation to happen so it // propagates through to the effects. - if (ExistingVar == nullptr && SrcVariable != nullptr) + if (ExistingVar == nullptr) { int32 AddIndex = EffectParameterLocalOverrides.Add(*SrcVariable); ExistingVar = &EffectParameterLocalOverrides[AddIndex]; @@ -663,7 +668,7 @@ FNiagaraScriptDataInterfaceInfo* UNiagaraComponent::CopyOnWriteDataInterface(FNa return nullptr; } - if (SrcVariable->DataInterface == nullptr || !SrcVariable->DataInterface->GetClass()->IsChildOf(RequiredClass)) + if (!SrcVariable->DataInterface->GetClass()->IsChildOf(RequiredClass)) { UE_LOG(LogNiagara, Warning, TEXT("%s FNiagaraScriptDataInterfaceInfo exists, but class is %s, not %s."), *VarName.ToString(), *SrcVariable->DataInterface->GetClass()->GetName(), *RequiredClass->GetName()); return nullptr; @@ -671,7 +676,7 @@ FNiagaraScriptDataInterfaceInfo* UNiagaraComponent::CopyOnWriteDataInterface(FNa bool bInvalidate = false; FNiagaraScriptDataInterfaceInfo* ExistingVar = GetLocalOverrideDataInterface(SrcVariable->Id); - if (ExistingVar == nullptr && SrcVariable != nullptr) + if (ExistingVar == nullptr) { int32 AddIndex = EffectDataInterfaceLocalOverrides.AddDefaulted(); ExistingVar = &EffectDataInterfaceLocalOverrides[AddIndex]; @@ -679,12 +684,12 @@ FNiagaraScriptDataInterfaceInfo* UNiagaraComponent::CopyOnWriteDataInterface(FNa bInvalidate = true; } - if (ExistingVar != nullptr && ExistingVar->DataInterface->GetClass() != SrcVariable->DataInterface->GetClass()) + if (ExistingVar->DataInterface->GetClass() != SrcVariable->DataInterface->GetClass()) { SrcVariable->CopyTo(ExistingVar, this); } - if (ExistingVar != nullptr && ExistingVar->Name != SrcVariable->Name) + if (ExistingVar->Name != SrcVariable->Name) { ExistingVar->Name = SrcVariable->Name; } diff --git a/Engine/Source/Runtime/Niagara/Private/NiagaraDataInterfaceSpline.cpp b/Engine/Source/Runtime/Niagara/Private/NiagaraDataInterfaceSpline.cpp index e57a62d50223..9832ae8df4ec 100644 --- a/Engine/Source/Runtime/Niagara/Private/NiagaraDataInterfaceSpline.cpp +++ b/Engine/Source/Runtime/Niagara/Private/NiagaraDataInterfaceSpline.cpp @@ -361,8 +361,7 @@ bool UNiagaraDataInterfaceSpline::PreSimulationTick(FNiagaraEffectInstance* Effe TransformInverseTransposed = FMatrix::Identity; if (Source) { - USplineComponent* SourceComp = nullptr; - SourceComp = Source->FindComponentByClass(); + USplineComponent* SourceComp = Source->FindComponentByClass(); if (SourceComp) { diff --git a/Engine/Source/Runtime/Niagara/Private/NiagaraDataInterfaceStaticMesh.cpp b/Engine/Source/Runtime/Niagara/Private/NiagaraDataInterfaceStaticMesh.cpp index 26d92d615367..2d7043ef7381 100644 --- a/Engine/Source/Runtime/Niagara/Private/NiagaraDataInterfaceStaticMesh.cpp +++ b/Engine/Source/Runtime/Niagara/Private/NiagaraDataInterfaceStaticMesh.cpp @@ -760,7 +760,7 @@ bool UNiagaraDataInterfaceStaticMesh::ResetRequired() bool bReset = false; if (Mesh) { - bIsAreaWeightedSampling = Mesh->bRequiresAreaWeightedSampling; + bIsAreaWeightedSampling = Mesh->bSupportUniformlyDistributedSampling; bSupportingVertexColorSampling = bEnableVertexColorRangeSorting && MeshHasColors(); bReset = !Mesh->bAllowCPUAccess || bIsAreaWeightedSampling != bPrevAreaWeighted || bSupportingVertexColorSampling != bPrevVCSampling; } diff --git a/Engine/Source/Runtime/Niagara/Private/NiagaraEffectRenderer.cpp b/Engine/Source/Runtime/Niagara/Private/NiagaraEffectRenderer.cpp index b579457db0a2..6c7bc08e52e4 100644 --- a/Engine/Source/Runtime/Niagara/Private/NiagaraEffectRenderer.cpp +++ b/Engine/Source/Runtime/Niagara/Private/NiagaraEffectRenderer.cpp @@ -62,9 +62,6 @@ FNiagaraDynamicDataBase *NiagaraEffectRendererLights::GenerateVertexData(const F { SCOPE_CYCLE_COUNTER(STAT_NiagaraGenLights); - FNiagaraDynamicDataLights *DynamicData = new FNiagaraDynamicDataLights; - - SimpleTimer VertexDataTimer; //I'm not a great fan of pulling scalar components out to a structured vert buffer like this. @@ -79,6 +76,8 @@ FNiagaraDynamicDataBase *NiagaraEffectRendererLights::GenerateVertexData(const F return nullptr; } + FNiagaraDynamicDataLights *DynamicData = new FNiagaraDynamicDataLights; + DynamicData->LightArray.Empty(); for (uint32 ParticleIndex = 0; ParticleIndex < Data.GetNumInstances(); ParticleIndex++) diff --git a/Engine/Source/Runtime/Niagara/Private/NiagaraEffectRendererSprites.cpp b/Engine/Source/Runtime/Niagara/Private/NiagaraEffectRendererSprites.cpp index f2cbe7b6c7e3..5ebed0ce00cd 100644 --- a/Engine/Source/Runtime/Niagara/Private/NiagaraEffectRendererSprites.cpp +++ b/Engine/Source/Runtime/Niagara/Private/NiagaraEffectRendererSprites.cpp @@ -193,17 +193,13 @@ void NiagaraEffectRendererSprites::GetDynamicMeshElements(const TArrayCustomFacingVectorMask; + PerViewUniformParameters.SubImageSize = FVector4(Properties->SubImageSize.X, Properties->SubImageSize.Y, 1.0f / Properties->SubImageSize.X, 1.0f / Properties->SubImageSize.Y); - if (Properties) + if (Properties->Alignment == ENiagaraSpriteAlignment::VelocityAligned) { - PerViewUniformParameters.SubImageSize = FVector4(Properties->SubImageSize.X, Properties->SubImageSize.Y, 1.0f / Properties->SubImageSize.X, 1.0f / Properties->SubImageSize.Y); - - if (Properties->Alignment == ENiagaraSpriteAlignment::VelocityAligned) - { - // velocity aligned - PerViewUniformParameters.RotationScale = 0.0f; - PerViewUniformParameters.TangentSelector = FVector4(0.0f, 1.0f, 0.0f, 0.0f); - } + // velocity aligned + PerViewUniformParameters.RotationScale = 0.0f; + PerViewUniformParameters.TangentSelector = FVector4(0.0f, 1.0f, 0.0f, 0.0f); } // Collector.AllocateOneFrameResource uses default ctor, initialize the vertex factory diff --git a/Engine/Source/Runtime/Niagara/Private/NiagaraSimulation.cpp b/Engine/Source/Runtime/Niagara/Private/NiagaraSimulation.cpp index 0fd53978d8d5..3c9dfc9e8ade 100644 --- a/Engine/Source/Runtime/Niagara/Private/NiagaraSimulation.cpp +++ b/Engine/Source/Runtime/Niagara/Private/NiagaraSimulation.cpp @@ -295,7 +295,7 @@ void FNiagaraSimulation::ResetSimulation() SpawnRate = PinnedProps->SpawnRate; //Check for various failure conditions and bail. - if (!PinnedProps || !PinnedProps->UpdateScriptProps.Script || !PinnedProps->SpawnScriptProps.Script) + if (!PinnedProps->UpdateScriptProps.Script || !PinnedProps->SpawnScriptProps.Script) { //TODO - Arbitrary named scripts. Would need some base functionality for Spawn/Udpate to be called that can be overriden in BPs for emitters with custom scripts. UE_LOG(LogNiagara, Error, TEXT("Emitter cannot be enabled because it's doesn't have both an update and spawn script."), *PinnedProps->GetFullName()); @@ -631,15 +631,14 @@ void FNiagaraSimulation::PreTick() { const UNiagaraEmitterProperties* PinnedProps = EmitterHandle->GetInstance(); - const FNiagaraEventScriptProperties &EventHandlerProps = PinnedProps->EventHandlerScriptProps; - - if (!PinnedProps || !bIsEnabled || !bDataInterfacesEnabled || !bHasValidPropertiesAndScripts || TickState == NTS_Suspended || TickState == NTS_Dead) { return; } + const FNiagaraEventScriptProperties &EventHandlerProps = PinnedProps->EventHandlerScriptProps; + if (ExternalSpawnFunctionTable.Num() == 0 && PinnedProps->SpawnScriptProps.Script != nullptr && PinnedProps->SpawnScriptProps.Script->DataInterfaceInfo.Num() != 0) { if (!UpdateFunctionTableInternal(ExternalSpawnDataInterfaces, ExternalSpawnFunctionTable, PinnedProps->SpawnScriptProps.Script)) @@ -711,12 +710,13 @@ void FNiagaraSimulation::Tick(float DeltaSeconds) SimpleTimer TickTime; const UNiagaraEmitterProperties* PinnedProps = EmitterHandle->GetInstance(); - const FNiagaraEventScriptProperties &EventHandlerProps = PinnedProps->EventHandlerScriptProps; if (!PinnedProps || !bIsEnabled || !bDataInterfacesEnabled || !bHasValidPropertiesAndScripts || TickState == NTS_Suspended || TickState == NTS_Dead) { return; } + const FNiagaraEventScriptProperties &EventHandlerProps = PinnedProps->EventHandlerScriptProps; + Age += DeltaSeconds; check(Data.GetNumVariables() > 0); diff --git a/Engine/Source/Runtime/Niagara/Public/NiagaraActor.h b/Engine/Source/Runtime/Niagara/Public/NiagaraActor.h index d6356e3eb3b1..dda0ff4d1a14 100644 --- a/Engine/Source/Runtime/Niagara/Public/NiagaraActor.h +++ b/Engine/Source/Runtime/Niagara/Public/NiagaraActor.h @@ -12,20 +12,17 @@ class ANiagaraActor : public AActor { GENERATED_UCLASS_BODY() -private_subobject: +private: /** Pointer to effect component */ - DEPRECATED_FORGAME(4.6, "NiagaraComponent should not be accessed directly, please use GetNiagaraComponent() function instead. NiagaraComponent will soon be private and your code will not compile.") UPROPERTY(VisibleAnywhere, Category=NiagaraActor) class UNiagaraComponent* NiagaraComponent; #if WITH_EDITORONLY_DATA // Reference to sprite visualization component - DEPRECATED_FORGAME(4.6, "SpriteComponent should not be accessed directly, please use GetSpriteComponent() function instead. SpriteComponent will soon be private and your code will not compile.") UPROPERTY() class UBillboardComponent* SpriteComponent; // Reference to arrow visualization component - DEPRECATED_FORGAME(4.6, "ArrowComponent should not be accessed directly, please use GetArrowComponent() function instead. ArrowComponent will soon be private and your code will not compile.") UPROPERTY() class UArrowComponent* ArrowComponent; @@ -33,12 +30,12 @@ private_subobject: public: /** Returns NiagaraComponent subobject **/ - NIAGARA_API class UNiagaraComponent* GetNiagaraComponent() const; + NIAGARA_API class UNiagaraComponent* GetNiagaraComponent() const { return NiagaraComponent; } #if WITH_EDITORONLY_DATA /** Returns SpriteComponent subobject **/ - class UBillboardComponent* GetSpriteComponent() const; + class UBillboardComponent* GetSpriteComponent() const { return SpriteComponent; } /** Returns ArrowComponent subobject **/ - class UArrowComponent* GetArrowComponent() const; + class UArrowComponent* GetArrowComponent() const { return ArrowComponent; } #endif #if WITH_EDITOR diff --git a/Engine/Source/Runtime/Niagara/Public/NiagaraTypes.h b/Engine/Source/Runtime/Niagara/Public/NiagaraTypes.h index 3a26fec324e6..39edf07a6005 100644 --- a/Engine/Source/Runtime/Niagara/Public/NiagaraTypes.h +++ b/Engine/Source/Runtime/Niagara/Public/NiagaraTypes.h @@ -124,7 +124,7 @@ struct FNiagaraTypeLayoutInfo * Can convert a UStruct with fields of base types only (float, int... - will likely add native vector types here as well) * to an FNiagaraTypeDefinition (internal representation) */ -class FNiagaraTypeHelper +class NIAGARA_API FNiagaraTypeHelper { public: static FString ToString(const uint8* ValueData, const UScriptStruct* Struct); diff --git a/Engine/Source/Runtime/Online/BuildPatchServices/Private/BuildPatchCompactifier.cpp b/Engine/Source/Runtime/Online/BuildPatchServices/Private/BuildPatchCompactifier.cpp index a37e0d826377..072560c2d491 100644 --- a/Engine/Source/Runtime/Online/BuildPatchServices/Private/BuildPatchCompactifier.cpp +++ b/Engine/Source/Runtime/Online/BuildPatchServices/Private/BuildPatchCompactifier.cpp @@ -114,7 +114,7 @@ bool FBuildDataCompactifier::Compactify(float DataAgeThreshold, const FString& D uint64 BytesSkipped = 0; uint64 NonPatchBytesProcessed = 0; uint64 BytesDeleted = 0; - uint64 CurrentFileSize; + int64 CurrentFileSize; FGuid FileGuid; TArray DeletedChunks; diff --git a/Engine/Source/Runtime/Online/HTTP/Private/Apple/AppleHTTP.cpp b/Engine/Source/Runtime/Online/HTTP/Private/Apple/AppleHTTP.cpp index 82e1b3e83553..fc2bc246a3f6 100644 --- a/Engine/Source/Runtime/Online/HTTP/Private/Apple/AppleHTTP.cpp +++ b/Engine/Source/Runtime/Online/HTTP/Private/Apple/AppleHTTP.cpp @@ -263,7 +263,7 @@ bool FAppleHttpRequest::StartRequest() const FString UserAgent = GetHeader("User-Agent"); if(UserAgent.IsEmpty()) { - NSString* Tag = FString::Printf(TEXT("UE4-%s,UE4Ver(%s)"), FApp::GetGameName(), *FEngineVersion::Current().ToString()).GetNSString(); + NSString* Tag = FPlatformHttp::GetDefaultUserAgent().GetNSString(); [Request addValue:Tag forHTTPHeaderField:@"User-Agent"]; } else diff --git a/Engine/Source/Runtime/Online/HTTP/Private/Curl/CurlHttp.cpp b/Engine/Source/Runtime/Online/HTTP/Private/Curl/CurlHttp.cpp index e76e39680e4f..db4c518a593d 100644 --- a/Engine/Source/Runtime/Online/HTTP/Private/Curl/CurlHttp.cpp +++ b/Engine/Source/Runtime/Online/HTTP/Private/Curl/CurlHttp.cpp @@ -608,7 +608,7 @@ bool FCurlHttpRequest::SetupRequest() // set up headers if (GetHeader("User-Agent").IsEmpty()) { - SetHeader(TEXT("User-Agent"), FString::Printf(TEXT("game=%s, engine=UE4, version=%s"), FApp::GetGameName(), *FEngineVersion::Current().ToString())); + SetHeader(TEXT("User-Agent"), FPlatformHttp::GetDefaultUserAgent()); } // content-length should be present http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4 diff --git a/Engine/Source/Runtime/Online/HTTP/Private/GenericPlatform/GenericPlatformHttp.cpp b/Engine/Source/Runtime/Online/HTTP/Private/GenericPlatform/GenericPlatformHttp.cpp index 189a5377526a..e0bf465c9167 100644 --- a/Engine/Source/Runtime/Online/HTTP/Private/GenericPlatform/GenericPlatformHttp.cpp +++ b/Engine/Source/Runtime/Online/HTTP/Private/GenericPlatform/GenericPlatformHttp.cpp @@ -3,7 +3,8 @@ #include "GenericPlatform/GenericPlatformHttp.h" #include "Interfaces/IHttpRequest.h" #include "Paths.h" - +#include "EngineVersion.h" +#include "App.h" /** * A generic http request @@ -238,4 +239,10 @@ FString FGenericPlatformHttp::GetMimeType(const FString& FilePath) } return TEXT("application/unknown"); -} \ No newline at end of file +} + +FString FGenericPlatformHttp::GetDefaultUserAgent() +{ + static FString CachedUserAgent = FString::Printf(TEXT("game=%s, engine=UE4, version=%s, platform=%s, osver=%s"), FApp::GetGameName(), *FEngineVersion::Current().ToString(), *FString(FPlatformProperties::IniPlatformName()), *FPlatformMisc::GetOSVersion()); + return CachedUserAgent; +} diff --git a/Engine/Source/Runtime/Online/HTTP/Private/Windows/HttpWinInet.cpp b/Engine/Source/Runtime/Online/HTTP/Private/Windows/HttpWinInet.cpp index 72ae6cef9915..d4d36cb3e11f 100644 --- a/Engine/Source/Runtime/Online/HTTP/Private/Windows/HttpWinInet.cpp +++ b/Engine/Source/Runtime/Online/HTTP/Private/Windows/HttpWinInet.cpp @@ -297,7 +297,7 @@ bool FWinInetConnection::InitConnection() // setup net connection InternetHandle = InternetOpen( - *FString::Printf(TEXT("game=%s, engine=UE4, version=%u"), FApp::GetGameName(), FNetworkVersion::GetNetworkCompatibleChangelist()), + *FPlatformHttp::GetDefaultUserAgent(), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, diff --git a/Engine/Source/Runtime/Online/HTTP/Public/GenericPlatform/GenericPlatformHttp.h b/Engine/Source/Runtime/Online/HTTP/Public/GenericPlatform/GenericPlatformHttp.h index 1158ac9203dc..7364731ac0f0 100644 --- a/Engine/Source/Runtime/Online/HTTP/Public/GenericPlatform/GenericPlatformHttp.h +++ b/Engine/Source/Runtime/Online/HTTP/Public/GenericPlatform/GenericPlatformHttp.h @@ -70,4 +70,13 @@ public: * Returns the mime type for the file. */ static FString GetMimeType(const FString& FilePath); + + + /** + * Returns the default User-Agent string to use in HTTP requests. + * Requests that explicitly set the User-Agent header will not use this value. + * + * @return the default User-Agent string that requests should use. + */ + static FString GetDefaultUserAgent(); }; diff --git a/Engine/Source/Runtime/Online/Voice/Private/VoicePrivate.h b/Engine/Source/Runtime/Online/Voice/Private/VoicePrivate.h index c6f2cbf277a2..e32170f24ec7 100644 --- a/Engine/Source/Runtime/Online/Voice/Private/VoicePrivate.h +++ b/Engine/Source/Runtime/Online/Voice/Private/VoicePrivate.h @@ -22,7 +22,7 @@ THIRD_PARTY_INCLUDES_END #endif // PLATFORM_WINDOWS -#define ANDROIDVOICE_SUPPORTED_PLATFORMS (PLATFORM_ANDROID && PLATFORM_ANDROID_ARM && PLATFORM_ANDROID_ARM64 && PLATFORM_ANDROID_X64) +#define ANDROIDVOICE_SUPPORTED_PLATFORMS (PLATFORM_ANDROID && (PLATFORM_ANDROID_ARM || PLATFORM_ANDROID_ARM64 || PLATFORM_ANDROID_X64)) #define PLATFORM_SUPPORTS_VOICE_CAPTURE (PLATFORM_WINDOWS || PLATFORM_MAC || ANDROIDVOICE_SUPPORTED_PLATFORMS) // Module includes diff --git a/Engine/Source/Runtime/Online/Voice/Private/Windows/VoiceModuleWindows.cpp b/Engine/Source/Runtime/Online/Voice/Private/Windows/VoiceModuleWindows.cpp index 062a55d5680a..5bace3fc2fc3 100644 --- a/Engine/Source/Runtime/Online/Voice/Private/Windows/VoiceModuleWindows.cpp +++ b/Engine/Source/Runtime/Online/Voice/Private/Windows/VoiceModuleWindows.cpp @@ -139,7 +139,7 @@ public: hr = pSessionControl2->SetDuckingPreference((::BOOL)bDuckingOptOutChecked); if (FAILED(hr)) { - UE_LOG(LogVoiceCapture, Display, TEXT("Failed to duck audio endpoint. Error: %0x08x"), hr); + UE_LOG(LogVoiceCapture, Display, TEXT("Failed to duck audio endpoint. Error: 0x%08x"), hr); } pSessionControl2->Release(); @@ -241,7 +241,7 @@ public: if (FAILED(hr)) { - UE_LOG(LogVoiceCapture, Warning, TEXT("Failed to duck audio endpoint. Error: %0x08x"), hr); + UE_LOG(LogVoiceCapture, Warning, TEXT("Failed to duck audio endpoint. Error: 0x%08x"), hr); } return SUCCEEDED(hr); diff --git a/Engine/Source/Runtime/Online/WebSockets/Private/Lws/LwsWebSocket.cpp b/Engine/Source/Runtime/Online/WebSockets/Private/Lws/LwsWebSocket.cpp index 5632086542f4..1523d8ce0d82 100644 --- a/Engine/Source/Runtime/Online/WebSockets/Private/Lws/LwsWebSocket.cpp +++ b/Engine/Source/Runtime/Online/WebSockets/Private/Lws/LwsWebSocket.cpp @@ -34,6 +34,8 @@ FLwsWebSocket::FLwsWebSocket(const FString& InUrl, const TArray& InProt , CloseCode(0) , CloseReason() , bIsConnecting(false) + , bIsConnected(false) + , bClientInitiatedClose(false) { } @@ -133,9 +135,9 @@ void FLwsWebSocket::Close(int32 Code, const FString& Reason) void FLwsWebSocket::Send(const void* Data, SIZE_T Size, bool bIsBinary) { - bool QueueWasEmpty = SendQueue.IsEmpty(); + bool bQueueWasEmpty = SendQueue.IsEmpty(); SendQueue.Enqueue(MakeShareable(new FLwsSendBuffer((const uint8*) Data, Size, bIsBinary))); - if (LwsConnection != nullptr && QueueWasEmpty) + if (LwsConnection != nullptr && bQueueWasEmpty) { lws_callback_on_writable(LwsConnection); } @@ -184,7 +186,6 @@ bool FLwsSendBuffer::Write(struct lws* LwsConnection) if (BytesWritten > 0) { WriteProtocol = LWS_WRITE_CONTINUATION; - UE_LOG(LogWebSockets, Verbose, TEXT("Flooby")); } else { @@ -212,7 +213,9 @@ int FLwsWebSocket::LwsCallback(lws* Instance, lws_callback_reasons Reason, void* switch (Reason) { case LWS_CALLBACK_CLIENT_ESTABLISHED: + { bIsConnecting = false; + bIsConnected = true; LwsConnection = Instance; if (!SendQueue.IsEmpty()) { @@ -220,6 +223,7 @@ int FLwsWebSocket::LwsCallback(lws* Instance, lws_callback_reasons Reason, void* } OnConnected().Broadcast(); break; + } case LWS_CALLBACK_CLIENT_RECEIVE: { SIZE_T BytesLeft = lws_remaining_packet_payload(Instance); @@ -238,7 +242,8 @@ int FLwsWebSocket::LwsCallback(lws* Instance, lws_callback_reasons Reason, void* } case LWS_CALLBACK_WS_PEER_INITIATED_CLOSE: { - LwsConnection = nullptr; + bClientInitiatedClose = true; + bIsConnected = false; FlushQueues(); if (OnClosed().IsBound()) { @@ -254,33 +259,29 @@ int FLwsWebSocket::LwsCallback(lws* Instance, lws_callback_reasons Reason, void* break; } case LWS_CALLBACK_WSI_DESTROY: + { // Getting a WSI_DESTROY before a connection has been established and no errors reported usually means there was a timeout establishing a connection if (bIsConnecting) { - //OnConnectionError().Broadcast(TEXT("Connection timed out")); - //bIsConnecting = false; - } - if (LwsConnection) - { - LwsConnection = nullptr; + OnConnectionError().Broadcast(TEXT("Connection timed out")); + bIsConnecting = false; } + LwsConnection = nullptr; break; + } case LWS_CALLBACK_CLOSED: { - bool ClientInitiated = LwsConnection == nullptr; - LwsConnection = nullptr; - OnClosed().Broadcast(LWS_CLOSE_STATUS_NORMAL, ClientInitiated?TEXT("Successfully closed connection to server"):TEXT("Connection closed by server"), ClientInitiated); + bIsConnected = false; + OnClosed().Broadcast(LWS_CLOSE_STATUS_NORMAL, bClientInitiatedClose ? TEXT("Successfully closed connection to server") : TEXT("Connection closed by server"), bClientInitiatedClose); FlushQueues(); break; } case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: { - LwsConnection = nullptr; FUTF8ToTCHAR Convert((const ANSICHAR*)Data, Length); OnConnectionError().Broadcast(Convert.Get()); FlushQueues(); return -1; - break; } case LWS_CALLBACK_RECEIVE_PONG: break; @@ -289,10 +290,9 @@ int FLwsWebSocket::LwsCallback(lws* Instance, lws_callback_reasons Reason, void* { if (CloseCode != 0) { - LwsConnection = nullptr; FTCHARToUTF8 Convert(*CloseReason); // This only sets the reason for closing the connection: - lws_close_reason(Instance, (enum lws_close_status)CloseCode, (unsigned char *)Convert.Get(), (size_t)Convert.Length()); + lws_close_reason(Instance, (enum lws_close_status)CloseCode, (unsigned char*)Convert.Get(), (size_t)Convert.Length()); CloseCode = 0; CloseReason = FString(); FlushQueues(); @@ -320,4 +320,4 @@ int FLwsWebSocket::LwsCallback(lws* Instance, lws_callback_reasons Reason, void* return 0; } -#endif // #if WITH_WEBSOCKETS \ No newline at end of file +#endif // #if WITH_WEBSOCKETS diff --git a/Engine/Source/Runtime/Online/WebSockets/Private/Lws/LwsWebSocket.h b/Engine/Source/Runtime/Online/WebSockets/Private/Lws/LwsWebSocket.h index e97a429f53d8..312badcbaca0 100644 --- a/Engine/Source/Runtime/Online/WebSockets/Private/Lws/LwsWebSocket.h +++ b/Engine/Source/Runtime/Online/WebSockets/Private/Lws/LwsWebSocket.h @@ -57,7 +57,7 @@ public: virtual bool IsConnected() override { - return LwsConnection != nullptr; + return bIsConnected; } virtual void Send(const FString& Data); @@ -138,6 +138,8 @@ private: int32 CloseCode; FString CloseReason; bool bIsConnecting; + bool bIsConnected; + bool bClientInitiatedClose; friend class FLwsWebSocketsManager; }; diff --git a/Engine/Source/Runtime/Online/WebSockets/Private/Lws/LwsWebSocketsManager.cpp b/Engine/Source/Runtime/Online/WebSockets/Private/Lws/LwsWebSocketsManager.cpp index 5397d6690c92..9a20049a313b 100644 --- a/Engine/Source/Runtime/Online/WebSockets/Private/Lws/LwsWebSocketsManager.cpp +++ b/Engine/Source/Runtime/Online/WebSockets/Private/Lws/LwsWebSocketsManager.cpp @@ -5,9 +5,13 @@ #if WITH_WEBSOCKETS && WITH_LIBWEBSOCKETS #include "Ssl.h" +#include "WebSocketsLog.h" void FLwsWebSocketsManager::InitWebSockets(TArrayView Protocols) { + // Subscribe to log events. Everything except LLL_PARSER + lws_set_log_level(LLL_ERR|LLL_WARN|LLL_NOTICE|LLL_INFO|LLL_DEBUG|LLL_HEADER|LLL_EXT|LLL_CLIENT|LLL_LATENCY, &FLwsWebSocketsManager::LwsLog); + check(!LwsContext && LwsProtocols.Num() == 0); LwsProtocols.Reserve(Protocols.Num() + 1); @@ -45,22 +49,74 @@ void FLwsWebSocketsManager::ShutdownWebSockets() DeleteLwsProtocols(); } +static inline bool LwsLogLevelIsWarning(int Level) +{ + return Level == LLL_ERR || + Level == LLL_WARN; +} + +static inline const TCHAR* LwsLogLevelToString(int Level) +{ + switch (Level) + { + case LLL_ERR: return TEXT("Error"); + case LLL_WARN: return TEXT("Warning"); + case LLL_NOTICE: return TEXT("Notice"); + case LLL_INFO: return TEXT("Info"); + case LLL_DEBUG: return TEXT("Debug"); + case LLL_PARSER: return TEXT("Parser"); + case LLL_HEADER: return TEXT("Header"); + case LLL_EXT: return TEXT("Ext"); + case LLL_CLIENT: return TEXT("Client"); + case LLL_LATENCY: return TEXT("Latency"); + } + return TEXT("Invalid"); +} + +void FLwsWebSocketsManager::LwsLog(int Level, const char* LogLine) +{ + bool bIsWarning = LwsLogLevelIsWarning(Level); + if (bIsWarning || UE_LOG_ACTIVE(LogWebSockets, Verbose)) + { + FUTF8ToTCHAR Converter(LogLine); + // Trim trailing newline + FString ConvertedLogLine(Converter.Get()); + if (ConvertedLogLine.EndsWith(TEXT("\n"))) + { + ConvertedLogLine[ConvertedLogLine.Len() - 1] = TEXT(' '); + } + if (bIsWarning) + { + UE_LOG(LogWebSockets, Warning, TEXT("Lws(%s): %s"), LwsLogLevelToString(Level), *ConvertedLogLine); + } + else + { + UE_LOG(LogWebSockets, Verbose, TEXT("Lws(%s): %s"), LwsLogLevelToString(Level), *ConvertedLogLine); + } + } +} + int FLwsWebSocketsManager::CallbackWrapper(lws* Connection, lws_callback_reasons Reason, void* UserData, void* Data, size_t Length) { + FLwsWebSocket* Socket = static_cast(UserData); + switch (Reason) { - default: - return 0; - case LWS_CALLBACK_RECEIVE_PONG: return 0; - case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS: case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS: + { FSslModule::Get().GetCertificateManager().AddCertificatesToSslContext(static_cast(UserData)); return 0; - + } case LWS_CALLBACK_WSI_DESTROY: + { + TSharedRef SharedSocket = Socket->AsShared(); + Sockets.RemoveSwap(SharedSocket); + SocketsPendingDelete.Emplace(SharedSocket); + break; + } case LWS_CALLBACK_CLIENT_ESTABLISHED: case LWS_CALLBACK_CLIENT_RECEIVE: case LWS_CALLBACK_WS_PEER_INITIATED_CLOSE: @@ -70,14 +126,8 @@ int FLwsWebSocketsManager::CallbackWrapper(lws* Connection, lws_callback_reasons case LWS_CALLBACK_SERVER_WRITEABLE: case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER: break; - } - - FLwsWebSocket* Socket = static_cast(UserData); - if (Reason == LWS_CALLBACK_WSI_DESTROY) - { - TSharedRef SharedSocket = Socket->AsShared(); - Sockets.RemoveSwap(SharedSocket); - SocketsPendingDelete.Emplace(SharedSocket); + default: + return 0; } return Socket->LwsCallback(Connection, Reason, Data, Length); diff --git a/Engine/Source/Runtime/Online/WebSockets/Private/Lws/LwsWebSocketsManager.h b/Engine/Source/Runtime/Online/WebSockets/Private/Lws/LwsWebSocketsManager.h index 95a8793f8788..b58a3224017c 100644 --- a/Engine/Source/Runtime/Online/WebSockets/Private/Lws/LwsWebSocketsManager.h +++ b/Engine/Source/Runtime/Online/WebSockets/Private/Lws/LwsWebSocketsManager.h @@ -43,6 +43,7 @@ private: // TickerObjectBase override virtual bool Tick(float DeltaTime) override; + static void LwsLog(int Level, const char* LogLine); static int CallbackWrapper(lws* Connection, lws_callback_reasons Reason, void* UserData, void* Data, size_t Length); void DeleteLwsProtocols(); diff --git a/Engine/Source/Runtime/Online/XMPP/Private/XmppJingle/XmppMultiUserChatJingle.cpp b/Engine/Source/Runtime/Online/XMPP/Private/XmppJingle/XmppMultiUserChatJingle.cpp index f8c4b496fe88..83e4d3af537c 100644 --- a/Engine/Source/Runtime/Online/XMPP/Private/XmppJingle/XmppMultiUserChatJingle.cpp +++ b/Engine/Source/Runtime/Online/XMPP/Private/XmppJingle/XmppMultiUserChatJingle.cpp @@ -293,7 +293,7 @@ public: if (bIsOwner && bWasSuccessful) { - Muc.InternalConfigureRoom(RoomId, FXmppRoomConfig(*RoomCreateConfig), EConfigureRoomTypeJingle::UseCreateCallback); + Muc.InternalConfigureRoom(RoomId, FXmppRoomConfig(*RoomCreateConfig), EConfigureRoomTypeJingle::UseCreateCallback); //-V595 } else { diff --git a/Engine/Source/Runtime/OpenGLDrv/Private/Android/AndroidESDeferredOpenGL.h b/Engine/Source/Runtime/OpenGLDrv/Private/Android/AndroidESDeferredOpenGL.h index 61ddb710ca8b..80ecc0782eda 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Private/Android/AndroidESDeferredOpenGL.h +++ b/Engine/Source/Runtime/OpenGLDrv/Private/Android/AndroidESDeferredOpenGL.h @@ -525,6 +525,11 @@ struct FAndroidESDeferredOpenGL : public FOpenGLESDeferred return bSupportsMobileMultiView; } + static FORCEINLINE bool SupportsImageExternal() + { + return false; + } + static FORCEINLINE GLuint64 GetTextureSamplerHandle(GLuint Texture, GLuint Sampler) { return glGetTextureSamplerHandleNV(Texture, Sampler); diff --git a/Engine/Source/Runtime/OpenGLDrv/Private/Android/AndroidOpenGL.cpp b/Engine/Source/Runtime/OpenGLDrv/Private/Android/AndroidOpenGL.cpp index e5045ac87c3d..ecfff3eb5ad2 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Private/Android/AndroidOpenGL.cpp +++ b/Engine/Source/Runtime/OpenGLDrv/Private/Android/AndroidOpenGL.cpp @@ -407,6 +407,7 @@ bool FAndroidOpenGL::bES31Support = false; bool FAndroidOpenGL::bSupportsInstancing = false; bool FAndroidOpenGL::bHasHardwareHiddenSurfaceRemoval = false; bool FAndroidOpenGL::bSupportsMobileMultiView = false; +bool FAndroidOpenGL::bSupportsImageExternal = false; GLint FAndroidOpenGL::MaxMSAASamplesTileMem = 1; FAndroidOpenGL::EFeatureLevelSupport FAndroidOpenGL::CurrentFeatureLevelSupport = FAndroidOpenGL::EFeatureLevelSupport::Invalid; @@ -469,6 +470,13 @@ void FAndroidOpenGL::ProcessExtensions(const FString& ExtensionsString) MaxMSAASamplesTileMem = 1; } + if (ExtensionsString.Contains(TEXT("GL_OES_EGL_image_external")) && + ExtensionsString.Contains(TEXT("OES_EGL_image_external_essl3"))) + { + bSupportsImageExternal = true; + UE_LOG(LogRHI, Log, TEXT("Image external enabled.")); + } + bSupportsETC2 = bES30Support; bUseES30ShadingLanguage = bES30Support; diff --git a/Engine/Source/Runtime/OpenGLDrv/Private/Android/AndroidOpenGL.h b/Engine/Source/Runtime/OpenGLDrv/Private/Android/AndroidOpenGL.h index d7cdc1346c0c..170e3d39d2fc 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Private/Android/AndroidOpenGL.h +++ b/Engine/Source/Runtime/OpenGLDrv/Private/Android/AndroidOpenGL.h @@ -459,6 +459,7 @@ struct FAndroidOpenGL : public FOpenGLES2 static FORCEINLINE bool SupportsResourceView() { return bSupportsTextureBuffer; } static FORCEINLINE bool SupportsTexture3D() { return bES30Support; } static FORCEINLINE bool SupportsMobileMultiView() { return bSupportsMobileMultiView; } + static FORCEINLINE bool SupportsImageExternal() { return bSupportsImageExternal; } static FORCEINLINE bool UseES30ShadingLanguage() { return bUseES30ShadingLanguage; @@ -496,6 +497,9 @@ struct FAndroidOpenGL : public FOpenGLES2 /** Whether device supports mobile multi-view */ static bool bSupportsMobileMultiView; + /** Whether device supports image external */ + static bool bSupportsImageExternal; + /** Maximum number of MSAA samples supported on chip in tile memory, or 1 if not available */ static GLint MaxMSAASamplesTileMem; diff --git a/Engine/Source/Runtime/OpenGLDrv/Private/HTML5/HTML5OpenGL.h b/Engine/Source/Runtime/OpenGLDrv/Private/HTML5/HTML5OpenGL.h index 9c3ed68c8463..398db66a8c4c 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Private/HTML5/HTML5OpenGL.h +++ b/Engine/Source/Runtime/OpenGLDrv/Private/HTML5/HTML5OpenGL.h @@ -125,7 +125,12 @@ struct FHTML5OpenGL : public FOpenGLES2 static FORCEINLINE void BlitFramebuffer(GLint SrcX0, GLint SrcY0, GLint SrcX1, GLint SrcY1, GLint DstX0, GLint DstY0, GLint DstX1, GLint DstY1, GLbitfield Mask, GLenum Filter) { - glBlitFramebuffer(SrcX0, SrcY0, SrcX1, SrcY1, DstX0, DstY0, DstX1, DstY1, Mask, Filter); +#ifdef UE4_HTML5_TARGET_WEBGL2 + if (bIsWebGL2) + { + glBlitFramebuffer(SrcX0, SrcY0, SrcX1, SrcY1, DstX0, DstY0, DstX1, DstY1, Mask, Filter); + } +#endif } static FORCEINLINE void DrawArraysInstanced(GLenum Mode, GLint First, GLsizei Count, GLsizei InstanceCount) @@ -154,17 +159,32 @@ struct FHTML5OpenGL : public FOpenGLES2 static FORCEINLINE void ClearBufferfv(GLenum Buffer, GLint DrawBufferIndex, const GLfloat* Value) { - glClearBufferfv(Buffer, DrawBufferIndex, Value); +#ifdef UE4_HTML5_TARGET_WEBGL2 + if (bIsWebGL2) + { + glClearBufferfv(Buffer, DrawBufferIndex, Value); + } +#endif } static FORCEINLINE void ClearBufferfi(GLenum Buffer, GLint DrawBufferIndex, GLfloat Depth, GLint Stencil) { - glClearBufferfi(Buffer, DrawBufferIndex, Depth, Stencil); +#ifdef UE4_HTML5_TARGET_WEBGL2 + if (bIsWebGL2) + { + glClearBufferfi(Buffer, DrawBufferIndex, Depth, Stencil); + } +#endif } static FORCEINLINE void ClearBufferiv(GLenum Buffer, GLint DrawBufferIndex, const GLint* Value) { - glClearBufferiv(Buffer, DrawBufferIndex, Value); +#ifdef UE4_HTML5_TARGET_WEBGL2 + if (bIsWebGL2) + { + glClearBufferiv(Buffer, DrawBufferIndex, Value); + } +#endif } static FORCEINLINE void BufferSubData(GLenum Target, GLintptr Offset, GLsizeiptr Size, const GLvoid* Data) @@ -179,7 +199,12 @@ struct FHTML5OpenGL : public FOpenGLES2 static FORCEINLINE void BindBufferRange(GLenum Target, GLuint Index, GLuint Buffer, GLintptr Offset, GLsizeiptr Size) { - glBindBufferRange(Target, Index, Buffer, Offset, Size); +#ifdef UE4_HTML5_TARGET_WEBGL2 + if (bIsWebGL2) + { + glBindBufferRange(Target, Index, Buffer, Offset, Size); + } +#endif } static FORCEINLINE GLuint GetUniformBlockIndex(GLuint Program, const GLchar* UniformBlockName) @@ -206,7 +231,15 @@ struct FHTML5OpenGL : public FOpenGLES2 // TODO: Make this true or false depending on whether WebGL 2 is available or not. static FORCEINLINE bool UseES30ShadingLanguage() { return false;} - static FORCEINLINE void ProgramUniform4uiv(GLuint Program, GLint Location, GLsizei Count, const GLuint *Value) { glUniform4uiv(Location, Count, Value); } + static FORCEINLINE void ProgramUniform4uiv(GLuint Program, GLint Location, GLsizei Count, const GLuint *Value) + { +#ifdef UE4_HTML5_TARGET_WEBGL2 + if (bIsWebGL2) + { + glUniform4uiv(Location, Count, Value); + } +#endif + } static FORCEINLINE GLsizei GetLabelObject(GLenum Type, GLuint Object, GLsizei BufferSize, ANSICHAR* OutName) { diff --git a/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLDevice.cpp b/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLDevice.cpp index 017f600f985a..d159aa8d8674 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLDevice.cpp +++ b/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLDevice.cpp @@ -5,6 +5,7 @@ =============================================================================*/ #include "CoreMinimal.h" +#include "CoreDelegates.h" #include "Misc/CommandLine.h" #include "Misc/ScopeLock.h" #include "Stats/Stats.h" @@ -23,6 +24,10 @@ #include "HardwareInfo.h" +#if PLATFORM_ANDROID +#include +#endif + #ifndef GL_STEREO #define GL_STEREO 0x0C33 #endif @@ -197,7 +202,29 @@ void FOpenGLDynamicRHI::RHIEndScene() ResourceTableFrameCounter = INDEX_NONE; } +#if PLATFORM_ANDROID +JNI_METHOD void Java_com_epicgames_ue4_MediaPlayer14_nativeClearCachedAttributeState(JNIEnv* jenv, jobject thiz, jint PositionAttrib, jint TexCoordsAttrib) +{ + FOpenGLContextState& ContextState = PrivateOpenGLDevicePtr->GetContextStateForCurrentContext(); + + // update vertex attributes state + ContextState.VertexAttrs[PositionAttrib].bEnabled = false; + ContextState.VertexAttrs[PositionAttrib].Stride = -1; + + ContextState.VertexAttrs[TexCoordsAttrib].bEnabled = false; + ContextState.VertexAttrs[TexCoordsAttrib].Stride = -1; + + // make sure the texture is set again + ContextState.ActiveTexture = 0; + ContextState.Textures[0].Texture = nullptr; + ContextState.Textures[0].Target = 0; + + // restore previous program + FOpenGL::BindProgramPipeline(ContextState.Program); +} + +#endif bool GDisableOpenGLDebugOutput = false; @@ -782,6 +809,7 @@ static void InitRHICapabilitiesForGL() GSupportsWideMRT = FOpenGL::SupportsWideMRT(); GSupportsTexture3D = FOpenGL::SupportsTexture3D(); GSupportsMobileMultiView = FOpenGL::SupportsMobileMultiView(); + GSupportsImageExternal = FOpenGL::SupportsImageExternal(); GSupportsResourceView = FOpenGL::SupportsResourceView(); GSupportsShaderFramebufferFetch = FOpenGL::SupportsShaderFramebufferFetch(); diff --git a/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLDrv.cpp b/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLDrv.cpp index efc3cecec088..24de4c7ddd61 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLDrv.cpp +++ b/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLDrv.cpp @@ -524,6 +524,13 @@ void FOpenGLBase::ProcessExtensions( const FString& ExtensionsString ) bAmdWorkaround = true; #endif } +#if PLATFORM_LINUX + else if (VendorName.Contains(TEXT("X.Org"))) + { + GRHIVendorId = 0x1002; + bAmdWorkaround = true; + } +#endif else if (VendorName.Contains(TEXT("Intel ")) || VendorName == TEXT("Intel")) { GRHIVendorId = 0x8086; @@ -547,6 +554,23 @@ void FOpenGLBase::ProcessExtensions( const FString& ExtensionsString ) { GRHIVendorId = 0x5143; } + + if (GRHIVendorId == 0x0) + { + // Fix for Mesa Radeon + const ANSICHAR* AnsiVersion = (const ANSICHAR*)glGetString(GL_VERSION); + const ANSICHAR* AnsiRenderer = (const ANSICHAR*)glGetString(GL_RENDERER); + if (AnsiVersion && AnsiRenderer) + { + if (FCStringAnsi::Strstr(AnsiVersion, "Mesa") && + (FCStringAnsi::Strstr(AnsiRenderer, "AMD") || FCStringAnsi::Strstr(AnsiRenderer, "ATI"))) + { + // Radeon + GRHIVendorId = 0x1002; + } + } + } + #if PLATFORM_WINDOWS auto* CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("OpenGL.UseStagingBuffer")); if (CVar) diff --git a/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLRenderTarget.cpp b/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLRenderTarget.cpp index eb2f2ae2d76d..a4e225469f4a 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLRenderTarget.cpp +++ b/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLRenderTarget.cpp @@ -197,6 +197,9 @@ GLuint FOpenGLDynamicRHI::GetOpenGLFramebuffer(uint32 NumSimultaneousRenderTarge switch (RenderTarget->Target) { case GL_TEXTURE_2D: +#if PLATFORM_ANDROID + case GL_TEXTURE_EXTERNAL_OES: +#endif case GL_TEXTURE_2D_MULTISAMPLE: { #if PLATFORM_ANDROID @@ -233,6 +236,9 @@ GLuint FOpenGLDynamicRHI::GetOpenGLFramebuffer(uint32 NumSimultaneousRenderTarge switch( RenderTarget->Target ) { case GL_TEXTURE_2D: +#if PLATFORM_ANDROID + case GL_TEXTURE_EXTERNAL_OES: +#endif case GL_TEXTURE_2D_MULTISAMPLE: { check(ArrayIndices[RenderTargetIndex] == 0); @@ -278,6 +284,9 @@ GLuint FOpenGLDynamicRHI::GetOpenGLFramebuffer(uint32 NumSimultaneousRenderTarge switch (DepthStencilTarget->Target) { case GL_TEXTURE_2D: +#if PLATFORM_ANDROID + case GL_TEXTURE_EXTERNAL_OES: +#endif case GL_TEXTURE_2D_MULTISAMPLE: { #if PLATFORM_ANDROID diff --git a/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLShaders.cpp b/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLShaders.cpp index dc5ff0454411..a40d6b9303f2 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLShaders.cpp +++ b/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLShaders.cpp @@ -13,6 +13,7 @@ #include "OpenGLDrvPrivate.h" #include "Shader.h" #include "GlobalShader.h" +#include "SceneUtils.h" #define CHECK_FOR_GL_SHADERS_TO_REPLACE 0 @@ -689,6 +690,9 @@ void OPENGLDRV_API GLSLToDeviceCompatibleGLSL(FAnsiCharArray& GlslCodeOriginal, // Whether we need to emit mobile multi-view code or not. const bool bEmitMobileMultiView = (FCStringAnsi::Strstr(GlslCodeOriginal.GetData(), "gl_ViewID_OVR") != nullptr); + + // Whether we need to emit texture external code or not. + const bool bEmitTextureExternal = (FCStringAnsi::Strstr(GlslCodeOriginal.GetData(), "samplerExternalOES") != nullptr); if (Capabilities.TargetPlatform == EOpenGLShaderTargetPlatform::OGLSTP_Android || Capabilities.TargetPlatform == EOpenGLShaderTargetPlatform::OGLSTP_HTML5) { @@ -734,6 +738,23 @@ void OPENGLDRV_API GLSLToDeviceCompatibleGLSL(FAnsiCharArray& GlslCodeOriginal, } } + if (bEmitTextureExternal) + { + MoveHashLines(GlslCode, GlslCodeOriginal); + + if (GSupportsImageExternal) + { + AppendCString(GlslCode, "\n\n"); + AppendCString(GlslCode, "#extension GL_OES_EGL_image_external_essl3 : require\n"); + AppendCString(GlslCode, "\n\n"); + } + else + { + // Strip out texture external for devices that don't support it. + AppendCString(GlslCode, "#define samplerExternalOES sampler2D\n"); + } + } + // Only desktop with separable shader platform can use GL_ARB_separate_shader_objects for reduced shader compile/link hitches // however ES3.1 relies on layout(location=) support bool const bNeedsBindLocation = OpenGLShaderPlatformNeedsBindLocation(Capabilities.MaxRHIShaderPlatform) && !bES31; @@ -806,22 +827,28 @@ void OPENGLDRV_API GLSLToDeviceCompatibleGLSL(FAnsiCharArray& GlslCodeOriginal, if (IsES2Platform(Capabilities.MaxRHIShaderPlatform) && !bES31) { - if (Capabilities.bSupportsRenderTargetFormat_PF_FloatRGBA || !IsMobileHDR()) + const ANSICHAR * EncodeModeDefine = nullptr; + + switch (GetMobileHDRMode()) { - AppendCString(GlslCode, "#define HDR_32BPP_ENCODE_MODE 0.0\n"); - } - else - { - if (!Capabilities.bSupportsShaderFramebufferFetch) - { - // mosaic - AppendCString(GlslCode, "#define HDR_32BPP_ENCODE_MODE 1.0\n"); - } - else - { - AppendCString(GlslCode, "#define HDR_32BPP_ENCODE_MODE 2.0\n"); - } + case EMobileHDRMode::Disabled: + case EMobileHDRMode::EnabledFloat16: + EncodeModeDefine = "#define HDR_32BPP_ENCODE_MODE 0.0\n"; + break; + case EMobileHDRMode::EnabledMosaic: + EncodeModeDefine = "#define HDR_32BPP_ENCODE_MODE 1.0\n"; + break; + case EMobileHDRMode::EnabledRGBE: + EncodeModeDefine = "#define HDR_32BPP_ENCODE_MODE 2.0\n"; + break; + case EMobileHDRMode::EnabledRGBA8: + EncodeModeDefine = "#define HDR_32BPP_ENCODE_MODE 3.0\n"; + break; + default: + checkNoEntry(); + break; } + AppendCString(GlslCode, EncodeModeDefine); if (Capabilities.bRequiresARMShaderFramebufferFetchDepthStencilUndef && TypeEnum == GL_FRAGMENT_SHADER) { @@ -2836,10 +2863,22 @@ void FOpenGLShaderParameterCache::CommitPackedGlobals(const FOpenGLLinkedProgram case CrossCompiler::PACKED_TYPEINDEX_INT: FOpenGL::ProgramUniform4iv(LinkedProgram->Config.Shaders[Stage].Resource, Location, NumDirtyVectors, (GLint*)UniformData); - break; + break; case CrossCompiler::PACKED_TYPEINDEX_UINT: +#if PLATFORM_ANDROID || PLATFORM_IOS + if (FOpenGL::GetFeatureLevel() == ERHIFeatureLevel::ES2) + { + // uint is not supported with ES2, set as int type. + FOpenGL::ProgramUniform4iv(LinkedProgram->Config.Shaders[Stage].Resource, Location, NumDirtyVectors, (GLint*)UniformData); + } + else + { + FOpenGL::ProgramUniform4uiv(LinkedProgram->Config.Shaders[Stage].Resource, Location, NumDirtyVectors, (GLuint*)UniformData); + } +#else FOpenGL::ProgramUniform4uiv(LinkedProgram->Config.Shaders[Stage].Resource, Location, NumDirtyVectors, (GLuint*)UniformData); +#endif break; } @@ -2923,9 +2962,9 @@ void FOpenGLShaderParameterCache::CommitPackedUniformBuffers(FOpenGLLinkedProgra // Upload the split buffers to the program const auto& UniformBufferUploadInfoList = PackedUniformBufferInfos[BufferIndex]; - auto& UBInfo = Bindings.PackedUniformBuffers[BufferIndex]; for (int32 InfoIndex = 0; InfoIndex < UniformBufferUploadInfoList.Num(); ++InfoIndex) { + auto& UBInfo = Bindings.PackedUniformBuffers[BufferIndex]; const auto& UniformInfo = UniformBufferUploadInfoList[InfoIndex]; const void* RESTRICT UniformData = PackedUniformsScratch[UniformInfo.Index]; int32 NumVectors = UBInfo[InfoIndex].Size / SizeOfFloat4; @@ -2943,7 +2982,19 @@ void FOpenGLShaderParameterCache::CommitPackedUniformBuffers(FOpenGLLinkedProgra break; case CrossCompiler::PACKED_TYPEINDEX_UINT: +#if PLATFORM_ANDROID || PLATFORM_IOS + if (FOpenGL::GetFeatureLevel() == ERHIFeatureLevel::ES2) + { + // uint is not supported with ES2, set as int type. + FOpenGL::ProgramUniform4iv(LinkedProgram->Config.Shaders[Stage].Resource, UniformInfo.Location, NumVectors, (GLint*)UniformData); + } + else + { + FOpenGL::ProgramUniform4uiv(LinkedProgram->Config.Shaders[Stage].Resource, UniformInfo.Location, NumVectors, (GLuint*)UniformData); + } +#else FOpenGL::ProgramUniform4uiv(LinkedProgram->Config.Shaders[Stage].Resource, UniformInfo.Location, NumVectors, (GLuint*)UniformData); +#endif break; } } diff --git a/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLTexture.cpp b/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLTexture.cpp index be61cea7c574..88a6012110c2 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLTexture.cpp +++ b/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLTexture.cpp @@ -237,7 +237,7 @@ bool FOpenGLDynamicRHI::RHIGetTextureMemoryVisualizeData( FColor* /*TextureData* -FRHITexture* FOpenGLDynamicRHI::CreateOpenGLTexture(uint32 SizeX, uint32 SizeY, bool bCubeTexture, bool bArrayTexture, uint8 Format, uint32 NumMips, uint32 NumSamples, uint32 ArraySize, uint32 Flags, const FClearValueBinding& InClearValue, FResourceBulkDataInterface* BulkData) +FRHITexture* FOpenGLDynamicRHI::CreateOpenGLTexture(uint32 SizeX, uint32 SizeY, bool bCubeTexture, bool bArrayTexture, bool bIsExternal, uint8 Format, uint32 NumMips, uint32 NumSamples, uint32 ArraySize, uint32 Flags, const FClearValueBinding& InClearValue, FResourceBulkDataInterface* BulkData) { VERIFY_GL_SCOPE(); @@ -245,9 +245,9 @@ FRHITexture* FOpenGLDynamicRHI::CreateOpenGLTexture(uint32 SizeX, uint32 SizeY, bool bAllocatedStorage = false; - if(NumMips == 0) + if (NumMips == 0) { - if(NumSamples <= 1) + if (NumSamples <= 1) { NumMips = FindMaxMipmapLevel(SizeX, SizeY); } @@ -258,8 +258,8 @@ FRHITexture* FOpenGLDynamicRHI::CreateOpenGLTexture(uint32 SizeX, uint32 SizeY, } #if UE_BUILD_DEBUG - check( !( NumSamples > 1 && bCubeTexture) ); - check( bArrayTexture != (ArraySize == 1)); + check(!(NumSamples > 1 && bCubeTexture)); + check(bArrayTexture != (ArraySize == 1)); #endif // Move NumSamples to on-chip MSAA if supported @@ -278,7 +278,7 @@ FRHITexture* FOpenGLDynamicRHI::CreateOpenGLTexture(uint32 SizeX, uint32 SizeY, // Some android devices does not support BGRA as a color attachment Format = PF_R8G8B8A8; } - + if (bNoSRGBSupport) { // Remove sRGB read flag when not supported @@ -289,9 +289,9 @@ FRHITexture* FOpenGLDynamicRHI::CreateOpenGLTexture(uint32 SizeX, uint32 SizeY, FOpenGL::GenTextures(1, &TextureID); GLenum Target = GL_NONE; - if(bCubeTexture) + if (bCubeTexture) { - if ( FOpenGL::SupportsTexture3D() ) + if (FOpenGL::SupportsTexture3D()) { Target = bArrayTexture ? GL_TEXTURE_CUBE_MAP_ARRAY : GL_TEXTURE_CUBE_MAP; } @@ -302,6 +302,20 @@ FRHITexture* FOpenGLDynamicRHI::CreateOpenGLTexture(uint32 SizeX, uint32 SizeY, } check(SizeX == SizeY); } +#if PLATFORM_ANDROID + else if (bIsExternal) + { + if (FOpenGL::SupportsImageExternal()) + { + Target = GL_TEXTURE_EXTERNAL_OES; + } + else + { + // Fall back to a regular 2d texture if we don't have support. Texture samplers in the shader will also fall back to a regular sampler2D. + Target = GL_TEXTURE_2D; + } + } +#endif else { Target = (NumSamples > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D; @@ -1466,7 +1480,20 @@ void TOpenGLTexture::CloneViaPBO( TOpenGLTexture(1,SizeX >> MipIndex) * GPixelFormats[Format].BlockBytes; @@ -1665,7 +1692,7 @@ FTexture3DRHIRef FOpenGLDynamicRHI::RHICreateTexture3D(uint32 SizeX,uint32 SizeY /*SizeZ=*/ FMath::Max(1,(SizeZ >> MipIndex)), /*Format=*/ GLFormat.Format, /*Type=*/ GLFormat.Type, - /*Data=*/ Data ? &Data[MipOffset] : NULL + /*Data=*/ &Data[MipOffset] ); uint32 SysMemPitch = FMath::Max(1,SizeX >> MipIndex) * GPixelFormats[Format].BlockBytes; @@ -2008,7 +2035,7 @@ FTexture2DRHIRef FOpenGLDynamicRHI::RHIAsyncReallocateTexture2D(FTexture2DRHIPar FOpenGLTexture2D* Texture2D = ResourceCast(Texture2DRHI); // Allocate a new texture. - FOpenGLTexture2D* NewTexture2D = (FOpenGLTexture2D*)CreateOpenGLTexture(NewSizeX,NewSizeY,false,false, Texture2D->GetFormat(),NewMipCount,1,1, Texture2D->GetFlags(), Texture2DRHI->GetClearBinding()); + FOpenGLTexture2D* NewTexture2D = (FOpenGLTexture2D*)CreateOpenGLTexture(NewSizeX,NewSizeY,false,false,false, Texture2D->GetFormat(),NewMipCount,1,1, Texture2D->GetFlags(), Texture2DRHI->GetClearBinding()); const uint32 BlockSizeX = GPixelFormats[Texture2D->GetFormat()].BlockSizeX; const uint32 BlockSizeY = GPixelFormats[Texture2D->GetFormat()].BlockSizeY; @@ -2246,7 +2273,7 @@ FTextureCubeRHIRef FOpenGLDynamicRHI::RHICreateTextureCube( uint32 Size, uint8 F // not yet supported check(!CreateInfo.BulkData); - return (FRHITextureCube*)CreateOpenGLTexture(Size,Size,true, false, Format, NumMips, 1, 1, Flags, CreateInfo.ClearValueBinding); + return (FRHITextureCube*)CreateOpenGLTexture(Size,Size,true, false, false, Format, NumMips, 1, 1, Flags, CreateInfo.ClearValueBinding); } FTextureCubeRHIRef FOpenGLDynamicRHI::RHICreateTextureCubeArray( uint32 Size, uint32 ArraySize, uint8 Format, uint32 NumMips, uint32 Flags, FRHIResourceCreateInfo& CreateInfo ) @@ -2254,7 +2281,7 @@ FTextureCubeRHIRef FOpenGLDynamicRHI::RHICreateTextureCubeArray( uint32 Size, ui // not yet supported check(!CreateInfo.BulkData); - return (FRHITextureCube*)CreateOpenGLTexture(Size, Size, true, true, Format, NumMips, 1, 6 * ArraySize, Flags, CreateInfo.ClearValueBinding); + return (FRHITextureCube*)CreateOpenGLTexture(Size, Size, true, true, false, Format, NumMips, 1, 6 * ArraySize, Flags, CreateInfo.ClearValueBinding); } void* FOpenGLDynamicRHI::RHILockTextureCubeFace(FTextureCubeRHIParamRef TextureCubeRHI,uint32 FaceIndex,uint32 ArrayIndex,uint32 MipIndex,EResourceLockMode LockMode,uint32& DestStride,bool bLockWithinMiptail) diff --git a/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLViewport.cpp b/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLViewport.cpp index c16b5e839c17..a16698a402d4 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLViewport.cpp +++ b/Engine/Source/Runtime/OpenGLDrv/Private/OpenGLViewport.cpp @@ -277,7 +277,7 @@ void FOpenGLViewport::Resize(uint32 InSizeX,uint32 InSizeY,bool bInIsFullscreen) BackBuffer = (FOpenGLTexture2D*)PlatformCreateBuiltinBackBuffer(OpenGLRHI, InSizeX, InSizeY); if (!BackBuffer) { - BackBuffer = (FOpenGLTexture2D*)OpenGLRHI->CreateOpenGLTexture(InSizeX, InSizeY, false, false, PixelFormat, 1, 1, 1, TexCreate_RenderTargetable, FClearValueBinding::Transparent); + BackBuffer = (FOpenGLTexture2D*)OpenGLRHI->CreateOpenGLTexture(InSizeX, InSizeY, false, false, false, PixelFormat, 1, 1, 1, TexCreate_RenderTargetable, FClearValueBinding::Transparent); } PlatformResizeGLContext(OpenGLRHI->PlatformDevice, OpenGLContext, InSizeX, InSizeY, bInIsFullscreen, bIsFullscreen, BackBuffer->Target, BackBuffer->Resource); diff --git a/Engine/Source/Runtime/OpenGLDrv/Public/OpenGL.h b/Engine/Source/Runtime/OpenGLDrv/Public/OpenGL.h index 83effdac80c2..c38428dc2156 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Public/OpenGL.h +++ b/Engine/Source/Runtime/OpenGLDrv/Public/OpenGL.h @@ -98,6 +98,7 @@ public: static FORCEINLINE bool SupportsSamplerObjects() { return true; } static FORCEINLINE bool SupportsTexture3D() { return true; } static FORCEINLINE bool SupportsMobileMultiView() { return false; } + static FORCEINLINE bool SupportsImageExternal() { return false; } static FORCEINLINE bool SupportsTextureLODBias() { return true; } static FORCEINLINE bool SupportsTextureCompare() { return true; } static FORCEINLINE bool SupportsTextureBaseLevel() { return true; } diff --git a/Engine/Source/Runtime/OpenGLDrv/Public/OpenGLDrv.h b/Engine/Source/Runtime/OpenGLDrv/Public/OpenGLDrv.h index 9f25bf8ee1a9..1aa3850fa9ee 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Public/OpenGLDrv.h +++ b/Engine/Source/Runtime/OpenGLDrv/Public/OpenGLDrv.h @@ -352,6 +352,7 @@ public: virtual FTextureReferenceRHIRef RHICreateTextureReference(FLastRenderTimeContainer* LastRenderTime) final override; virtual void RHIUpdateTextureReference(FTextureReferenceRHIParamRef TextureRef, FTextureRHIParamRef NewTexture) final override; virtual FTexture2DRHIRef RHICreateTexture2D(uint32 SizeX, uint32 SizeY, uint8 Format, uint32 NumMips, uint32 NumSamples, uint32 Flags, FRHIResourceCreateInfo& CreateInfo) final override; + virtual FTexture2DRHIRef RHICreateTextureExternal2D(uint32 SizeX, uint32 SizeY, uint8 Format, uint32 NumMips, uint32 NumSamples, uint32 Flags, FRHIResourceCreateInfo& CreateInfo) final override; virtual FTexture2DRHIRef RHIAsyncCreateTexture2D(uint32 SizeX, uint32 SizeY, uint8 Format, uint32 NumMips, uint32 Flags, void** InitialMipData, uint32 NumInitialMips) final override; virtual void RHICopySharedMips(FTexture2DRHIParamRef DestTexture2D, FTexture2DRHIParamRef SrcTexture2D) final override; virtual FTexture2DArrayRHIRef RHICreateTexture2DArray(uint32 SizeX, uint32 SizeY, uint32 SizeZ, uint8 Format, uint32 NumMips, uint32 Flags, FRHIResourceCreateInfo& CreateInfo) final override; @@ -562,7 +563,7 @@ public: FOpenGLSamplerState* GetPointSamplerState() const { return (FOpenGLSamplerState*)PointSamplerState.GetReference(); } - FRHITexture* CreateOpenGLTexture(uint32 SizeX, uint32 SizeY, bool CubeTexture, bool ArrayTexture, uint8 Format, uint32 NumMips, uint32 NumSamples, uint32 ArraySize, uint32 Flags, const FClearValueBinding& InClearValue, FResourceBulkDataInterface* BulkData = NULL); + FRHITexture* CreateOpenGLTexture(uint32 SizeX, uint32 SizeY, bool CubeTexture, bool ArrayTexture, bool bIsExternal, uint8 Format, uint32 NumMips, uint32 NumSamples, uint32 ArraySize, uint32 Flags, const FClearValueBinding& InClearValue, FResourceBulkDataInterface* BulkData = NULL); void SetCustomPresent(class FRHICustomPresent* InCustomPresent); private: diff --git a/Engine/Source/Runtime/OpenGLDrv/Public/OpenGLES2.h b/Engine/Source/Runtime/OpenGLDrv/Public/OpenGLES2.h index ecf973bb854b..642e9f51124d 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Public/OpenGLES2.h +++ b/Engine/Source/Runtime/OpenGLDrv/Public/OpenGLES2.h @@ -92,6 +92,7 @@ struct FOpenGLES2 : public FOpenGLBase static FORCEINLINE bool SupportsSamplerObjects() { return false; } static FORCEINLINE bool SupportsTexture3D() { return false; } static FORCEINLINE bool SupportsMobileMultiView() { return false; } + static FORCEINLINE bool SupportsImageExternal() { return false; } static FORCEINLINE bool SupportsTextureLODBias() { return false; } static FORCEINLINE bool SupportsTextureCompare() { return false; } static FORCEINLINE bool SupportsTextureBaseLevel() { return false; } diff --git a/Engine/Source/Runtime/OpenGLDrv/Public/OpenGLESDeferred.h b/Engine/Source/Runtime/OpenGLDrv/Public/OpenGLESDeferred.h index ebffd03a2490..9530b67a860e 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Public/OpenGLESDeferred.h +++ b/Engine/Source/Runtime/OpenGLDrv/Public/OpenGLESDeferred.h @@ -54,6 +54,7 @@ struct FOpenGLESDeferred : public FOpenGLBase static FORCEINLINE bool SupportsSamplerObjects() { return !bES2Fallback; } static FORCEINLINE bool SupportsTexture3D() { return !bES2Fallback; } static FORCEINLINE bool SupportsMobileMultiView() { return false; } + static FORCEINLINE bool SupportsImageExternal() { return false; } static FORCEINLINE bool SupportsTextureLODBias() { return false; } static FORCEINLINE bool SupportsTextureCompare() { return !bES2Fallback; } static FORCEINLINE bool SupportsTextureBaseLevel() { return !bES2Fallback; } diff --git a/Engine/Source/Runtime/OpenGLDrv/Public/OpenGLResources.h b/Engine/Source/Runtime/OpenGLDrv/Public/OpenGLResources.h index d6f2f0097678..d2a7856604b0 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Public/OpenGLResources.h +++ b/Engine/Source/Runtime/OpenGLDrv/Public/OpenGLResources.h @@ -958,13 +958,23 @@ public: Tex.Z = InArraySize; break; } +#if PLATFORM_ANDROID + case GL_TEXTURE_EXTERNAL_OES: + { + Tex.Type = SCTT_TextureExternal2D; + break; + } +#endif default: { - check(false); + Tex.Type = SCTT_Invalid; } } - - FShaderCache::LogTexture(Tex, this); + + if (Tex.Type != SCTT_Invalid) + { + FShaderCache::LogTexture(Tex, this); + } } } diff --git a/Engine/Source/Runtime/OpenGLDrv/Public/OpenGLState.h b/Engine/Source/Runtime/OpenGLDrv/Public/OpenGLState.h index 400508fbd72a..0245d387365a 100644 --- a/Engine/Source/Runtime/OpenGLDrv/Public/OpenGLState.h +++ b/Engine/Source/Runtime/OpenGLDrv/Public/OpenGLState.h @@ -268,7 +268,7 @@ struct FOpenGLCommonState , UAVs(NULL) {} - ~FOpenGLCommonState() + virtual ~FOpenGLCommonState() { CleanupResources(); } diff --git a/Engine/Source/Runtime/PakFile/Private/IPlatformFilePak.cpp b/Engine/Source/Runtime/PakFile/Private/IPlatformFilePak.cpp index ae3e0ca1db19..4a0bd1e36bff 100644 --- a/Engine/Source/Runtime/PakFile/Private/IPlatformFilePak.cpp +++ b/Engine/Source/Runtime/PakFile/Private/IPlatformFilePak.cpp @@ -901,7 +901,7 @@ class FPakPrecacher { CacheBlocks[IndexInner] = IntervalTreeInvalidIndex; } - uint64 StartingLastByte = FMath::Max((uint64)TotalSize, (uint64)PAK_CACHE_GRANULARITY); + uint64 StartingLastByte = FMath::Max((uint64)TotalSize, uint64(PAK_CACHE_GRANULARITY + 1)); StartingLastByte--; { @@ -932,7 +932,7 @@ class FPakPrecacher } MaxNode = MAX_uint64 >> StartShift; check(MaxNode >= StartingLastByte && (MaxNode >> 1) < StartingLastByte); - //UE_LOG(LogTemp, Warning, TEXT("Test %d %llX %llX "), MaxShift, (uint64(PAK_CACHE_GRANULARITY) << (MaxShift + 1)), (uint64(PAK_CACHE_GRANULARITY) << MaxShift)); +// UE_LOG(LogTemp, Warning, TEXT("Test %d %llX %llX "), MaxShift, (uint64(PAK_CACHE_GRANULARITY) << (MaxShift + 1)), (uint64(PAK_CACHE_GRANULARITY) << MaxShift)); check(MaxShift && (uint64(PAK_CACHE_GRANULARITY) << (MaxShift + 1)) == 0 && (uint64(PAK_CACHE_GRANULARITY) << MaxShift) != 0); } } @@ -1310,6 +1310,8 @@ private: // below here we assume CachedFilesScopeLock until we get to the next s void ClearBlock(FCacheBlock &Block) { + UE_LOG(LogPakFile, Verbose, TEXT("FPakReadRequest[%016llX, %016llX) ClearBlock"), Block.OffsetAndPakIndex, Block.OffsetAndPakIndex + Block.Size); + if (Block.Memory) { check(Block.Size); @@ -1368,6 +1370,7 @@ private: // below here we assume CachedFilesScopeLock until we get to the next s FCacheBlock &Block = CacheBlockAllocator.Get(BlockIndex); if (!Block.InRequestRefCount) { + UE_LOG(LogPakFile, Verbose, TEXT("FPakReadRequest[%016llX, %016llX) Discard Cached"), Block.OffsetAndPakIndex, Block.OffsetAndPakIndex + Block.Size); ClearBlock(Block); return true; } @@ -1412,6 +1415,7 @@ private: // below here we assume CachedFilesScopeLock until we get to the next s { if (GPakCache_NumUnreferencedBlocksToCache && GetRequestOffset(Block.OffsetAndPakIndex) + Block.Size > OffsetOfLastByte) // last block { + OffsetAndPakIndexOfSavedBlocked.Remove(Block.OffsetAndPakIndex); OffsetAndPakIndexOfSavedBlocked.Add(Block.OffsetAndPakIndex); return false; } @@ -1904,6 +1908,7 @@ private: // below here we assume CachedFilesScopeLock until we get to the next s if (Block.InRequestRefCount == 0 || bWasCanceled) { FMemory::Free(Memory); + UE_LOG(LogPakFile, Verbose, TEXT("FPakReadRequest[%016llX, %016llX) Cancelled"), Block.OffsetAndPakIndex, Block.OffsetAndPakIndex + Block.Size); ClearBlock(Block); } else @@ -2866,8 +2871,8 @@ void FPakPrecacher::DoSignatureCheck(bool bWasCanceled, IAsyncReadRequest* Reque ensure(bChunkHashesMatch); if (!ensure(bChunkHashesMatch)) { - UE_LOG(LogPakFile, Fatal, TEXT("Pak chunk signing mismatch! Pak file has been corrupted or tampered with!")); - FPlatformMisc::RequestExit(true); + UE_LOG(LogPakFile, Warning, TEXT("Pak chunk signing mismatch! Pak file has been corrupted or tampered with!")); + //FPlatformMisc::RequestExit(true); } } @@ -4071,7 +4076,13 @@ bool FPakPlatformFile::Initialize(IPlatformFile* Inner, const TCHAR* CmdLine) //if we are using a fileserver, then dont' mount paks automatically. We only want to read files from the server. FString FileHostIP; const bool bCookOnTheFly = FParse::Value(FCommandLine::Get(), TEXT("filehostip"), FileHostIP); - bMountPaks = !bCookOnTheFly; + const bool bPreCookedNetwork = FParse::Param(FCommandLine::Get(), TEXT("precookednetwork") ); + if (bPreCookedNetwork) + { + // precooked network builds are dependent on cook on the fly + check(bCookOnTheFly); + } + bMountPaks &= (!bCookOnTheFly || bPreCookedNetwork); #endif if (bMountPaks) diff --git a/Engine/Source/Runtime/PerfCounters/Private/PerfCounters.cpp b/Engine/Source/Runtime/PerfCounters/Private/PerfCounters.cpp index 1371593ba3da..b7ad8f4aac28 100644 --- a/Engine/Source/Runtime/PerfCounters/Private/PerfCounters.cpp +++ b/Engine/Source/Runtime/PerfCounters/Private/PerfCounters.cpp @@ -14,17 +14,21 @@ #include "IPAddress.h" #include "Sockets.h" #include "PlatformHttp.h" +#include "Interfaces/IHttpResponse.h" #define JSON_ARRAY_NAME TEXT("PerfCounters") #define JSON_PERFCOUNTER_NAME TEXT("Name") #define JSON_PERFCOUNTER_SIZE_IN_BYTES TEXT("SizeInBytes") +#define PERF_COUNTER_CONNECTION_TIMEOUT 5.0f + FPerfCounters::FPerfCounters(const FString& InUniqueInstanceId) -: UniqueInstanceId(InUniqueInstanceId) -, InternalCountersUpdateInterval(60) -, Socket(nullptr) -, ZeroLoadThread(nullptr) -, ZeroLoadRunnable(nullptr) + : SocketSubsystem(nullptr) + , UniqueInstanceId(InUniqueInstanceId) + , InternalCountersUpdateInterval(60) + , Socket(nullptr) + , ZeroLoadThread(nullptr) + , ZeroLoadRunnable(nullptr) { } @@ -60,15 +64,17 @@ bool FPerfCounters::Initialize() } // get the socket subsystem - ISocketSubsystem* SocketSystem = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM); - if (SocketSystem == nullptr) + SocketSubsystem = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM); + if (SocketSubsystem == nullptr) { UE_LOG(LogPerfCounters, Error, TEXT("FPerfCounters unable to get socket subsystem")); return false; } + ScratchIPAddr = SocketSubsystem->CreateInternetAddr(); + // make our listen socket - Socket = SocketSystem->CreateSocket(NAME_Stream, TEXT("FPerfCounters")); + Socket = SocketSubsystem->CreateSocket(NAME_Stream, TEXT("FPerfCounters")); if (Socket == nullptr) { UE_LOG(LogPerfCounters, Error, TEXT("FPerfCounters unable to allocate stream socket")); @@ -79,7 +85,7 @@ bool FPerfCounters::Initialize() Socket->SetNonBlocking(true); // create a localhost binding for the requested port - TSharedRef LocalhostAddr = SocketSystem->CreateInternetAddr(0x7f000001 /* 127.0.0.1 */, StatsPort); + TSharedRef LocalhostAddr = SocketSubsystem->CreateInternetAddr(0x7f000001 /* 127.0.0.1 */, StatsPort); if (!Socket->Bind(*LocalhostAddr)) { UE_LOG(LogPerfCounters, Error, TEXT("FPerfCounters unable to bind to %s"), *LocalhostAddr->ToString(true)); @@ -156,12 +162,23 @@ void FPerfCounters::ResetStatsForNextPeriod() } }; - static bool SendAsUtf8(FSocket* Conn, const FString& Message) { FTCHARToUTF8 ConvertToUtf8(*Message); int32 BytesSent = 0; - return Conn->Send(reinterpret_cast(ConvertToUtf8.Get()), ConvertToUtf8.Length(), BytesSent) && BytesSent == ConvertToUtf8.Length(); + const bool bSendSuccess = Conn->Send(reinterpret_cast(ConvertToUtf8.Get()), ConvertToUtf8.Length(), BytesSent); + const bool bSendSizeSuccess = (BytesSent == ConvertToUtf8.Length()); + + if (!bSendSuccess) + { + UE_LOG(LogPerfCounters, Warning, TEXT("Failed to send buffer size: %d"), ConvertToUtf8.Length()); + } + else if (!bSendSizeSuccess) + { + UE_LOG(LogPerfCounters, Warning, TEXT("Failed to send entire buffer size: %d sent: %d"), ConvertToUtf8.Length(), BytesSent); + } + + return bSendSuccess && bSendSizeSuccess; } bool FPerfCounters::Tick(float DeltaTime) @@ -205,11 +222,11 @@ void FPerfCounters::TickSocket(float DeltaTime) FSocket* IncomingConnection = Socket->Accept(PerfCounterRequest); if (IncomingConnection) { - if (0) + const bool bLogConnections = true; + if (bLogConnections) { - TSharedRef FromAddr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr(); - IncomingConnection->GetPeerAddress(*FromAddr); - UE_LOG(LogPerfCounters, Log, TEXT("New connection from %s"), *FromAddr->ToString(true)); + IncomingConnection->GetPeerAddress(*ScratchIPAddr); + UE_LOG(LogPerfCounters, Log, TEXT("New connection from %s"), *ScratchIPAddr->ToString(true)); } // make sure this is non-blocking @@ -217,6 +234,16 @@ void FPerfCounters::TickSocket(float DeltaTime) new (Connections) FPerfConnection(IncomingConnection); } + else + { + ESocketErrors ErrorCode = SocketSubsystem->GetLastErrorCode(); + if (ErrorCode != SE_EWOULDBLOCK && + ErrorCode != SE_NO_ERROR) + { + const TCHAR* ErrorStr = SocketSubsystem->GetSocketError(); + UE_LOG(LogPerfCounters, Warning, TEXT("Error accepting connection [%d] %s"), (int32)ErrorCode, ErrorStr); + } + } TArray ConnectionsToClose; for (FPerfConnection& Connection : Connections) @@ -230,14 +257,21 @@ void FPerfCounters::TickSocket(float DeltaTime) int32 DataLen = 0; if (ExistingSocket->Recv(Buffer, sizeof(Buffer) - 1, DataLen, ESocketReceiveFlags::None)) { + double StartTime = FPlatformTime::Seconds(); + FResponse Response; if (ProcessRequest(Buffer, DataLen, Response)) { + if (!EHttpResponseCodes::IsOk(Response.Code)) + { + UE_LOG(LogPerfCounters, Warning, TEXT("Sending error response: [%d] %s"), Response.Code, *Response.Body); + } + if (SendAsUtf8(ExistingSocket, Response.Header)) { if (!SendAsUtf8(ExistingSocket, Response.Body)) { - UE_LOG(LogPerfCounters, Warning, TEXT("Unable to send full HTTP response body")); + UE_LOG(LogPerfCounters, Warning, TEXT("Unable to send full HTTP response body size: %d"), Response.Body.Len()); } } else @@ -245,6 +279,14 @@ void FPerfCounters::TickSocket(float DeltaTime) UE_LOG(LogPerfCounters, Warning, TEXT("Unable to send HTTP response header: %s"), *Response.Header); } } + else + { + UE_LOG(LogPerfCounters, Warning, TEXT("Failed to process request")); + } + + double EndTime = FPlatformTime::Seconds(); + ExistingSocket->GetPeerAddress(*ScratchIPAddr); + UE_LOG(LogPerfCounters, Log, TEXT("Request for %s processed in %0.2f s"), *ScratchIPAddr->ToString(true), EndTime - StartTime); } else { @@ -253,8 +295,9 @@ void FPerfCounters::TickSocket(float DeltaTime) ConnectionsToClose.Add(Connection); } - else if (Connection.ElapsedTime > 5.0f) + else if (Connection.ElapsedTime > PERF_COUNTER_CONNECTION_TIMEOUT) { + UE_LOG(LogPerfCounters, Warning, TEXT("Closing connection due to timeout %d"), Connection.ElapsedTime); ConnectionsToClose.Add(Connection); } @@ -268,14 +311,16 @@ void FPerfCounters::TickSocket(float DeltaTime) FSocket* ClosingSocket = Connection.Connection; if (ClosingSocket) { + const bool bLogConnectionClosure = true; + if (bLogConnectionClosure) + { + ClosingSocket->GetPeerAddress(*ScratchIPAddr); + UE_LOG(LogPerfCounters, Log, TEXT("Closed connection to %s."), *ScratchIPAddr->ToString(true)); + } + // close the socket (whether we processed or not) ClosingSocket->Close(); - ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(ClosingSocket); - - if (0) - { - UE_LOG(LogPerfCounters, Log, TEXT("Closed connection.")); - } + SocketSubsystem->DestroySocket(ClosingSocket); } } } @@ -342,13 +387,13 @@ bool FPerfCounters::ProcessRequest(uint8* Buffer, int32 BufferLen, FResponse& Re if (Tokens.Num() >= 2) { FString ContentType(TEXT("application/json")); - Response.Code = 200; + Response.Code = EHttpResponseCodes::Ok; // handle the request if (Tokens[0] != TEXT("GET")) { Response.Body = FString::Printf(TEXT("{ \"error\": \"Method %s not allowed\" }"), *Tokens[0]); - Response.Code = 405; + Response.Code = EHttpResponseCodes::BadMethod; } else if (Tokens[1].StartsWith(TEXT("/stats"))) { @@ -374,12 +419,12 @@ bool FPerfCounters::ProcessRequest(uint8* Buffer, int32 BufferLen, FResponse& Re Response.Body = FString::Printf(TEXT("{ \"error\": \"exec handler not found\" }")); } - Response.Code = bResult ? 200 : 404; + Response.Code = bResult ? EHttpResponseCodes::Ok : EHttpResponseCodes::NotFound; } else { Response.Body = FString::Printf(TEXT("{ \"error\": \"%s not found\" }"), *Tokens[1]); - Response.Code = 404; + Response.Code = EHttpResponseCodes::NotFound; } // send the response headers @@ -393,7 +438,7 @@ bool FPerfCounters::ProcessRequest(uint8* Buffer, int32 BufferLen, FResponse& Re } else { - UE_LOG(LogPerfCounters, Warning, TEXT("Unable to immediately receive full request header")); + UE_LOG(LogPerfCounters, Warning, TEXT("ProcessRequest: request incomplete")); } return bSuccess; diff --git a/Engine/Source/Runtime/PerfCounters/Private/PerfCounters.h b/Engine/Source/Runtime/PerfCounters/Private/PerfCounters.h index 57590394798f..13995b1aff9a 100644 --- a/Engine/Source/Runtime/PerfCounters/Private/PerfCounters.h +++ b/Engine/Source/Runtime/PerfCounters/Private/PerfCounters.h @@ -8,8 +8,10 @@ #include "Containers/Ticker.h" #include "ProfilingDebugging/Histogram.h" +class ISocketSubsystem; class FSocket; class FZeroLoad; +class FInternetAddr; DECLARE_LOG_CATEGORY_EXTERN(LogPerfCounters, Log, All); @@ -98,6 +100,12 @@ private: } }; + /** Reference to the socket subsystem in use */ + ISocketSubsystem* SocketSubsystem; + + /** Scratch IP address to save on memory allocations */ + TSharedPtr ScratchIPAddr; + /** all active connections */ TArray Connections; diff --git a/Engine/Source/Runtime/PhysXCooking/PhysXCooking.Build.cs b/Engine/Source/Runtime/PhysXCooking/PhysXCooking.Build.cs new file mode 100644 index 000000000000..5dd1d8ab6037 --- /dev/null +++ b/Engine/Source/Runtime/PhysXCooking/PhysXCooking.Build.cs @@ -0,0 +1,30 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +using UnrealBuildTool; +using System.IO; + +public class PhysXCooking : ModuleRules +{ + public PhysXCooking(ReadOnlyTargetRules Target) : base(Target) + { + PrivateIncludePathModuleNames.Add("TargetPlatform"); + + PrivateDependencyModuleNames.AddRange( + new string[] { + "Core", + "CoreUObject", // @todo Mac: for some reason it's needed to link in debug on Mac + "Engine", + "PhysXCookingLib" + } + ); + + PrivateIncludePaths.AddRange( + new string[] { + "Runtime/Engine/Private", //A bit hacky, but we don't want to expose the low level physx structs to other modules + } + ); + + + SetupModulePhysXAPEXSupport(Target); + } +} diff --git a/Engine/Source/Runtime/PhysXCooking/Private/PhysXCooking.cpp b/Engine/Source/Runtime/PhysXCooking/Private/PhysXCooking.cpp new file mode 100644 index 000000000000..12d797521732 --- /dev/null +++ b/Engine/Source/Runtime/PhysXCooking/Private/PhysXCooking.cpp @@ -0,0 +1,516 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "PhysXCooking.h" +#include "Serialization/MemoryWriter.h" +#include "Modules/ModuleManager.h" +#include "Interfaces/Interface_CollisionDataProvider.h" +#include "IPhysXCookingModule.h" +#include "PhysicsPublic.h" +#include "PhysicsEngine/PhysXSupport.h" + +static_assert(WITH_PHYSX, "No point in compiling PhysX cooker, if we don't have PhysX."); + +static FName NAME_PhysXPC(TEXT("PhysXPC")); +static FName NAME_PhysXXboxOne(TEXT("PhysXXboxOne")); +static FName NAME_PhysXPS4(TEXT("PhysXPS4")); + +bool GetPhysXCooking(FName InFormatName, PxPlatform::Enum& OutFormat) +{ + if ((InFormatName == NAME_PhysXPC) || (InFormatName == NAME_PhysXXboxOne) || (InFormatName == NAME_PhysXPS4)) + { + OutFormat = PxPlatform::ePC; + } + else + { + return false; + } + return true; +} + +/** +* Validates PhysX format name. +*/ +bool CheckPhysXCooking(FName InFormatName) +{ + PxPlatform::Enum Format = PxPlatform::ePC; + return GetPhysXCooking(InFormatName, Format); +} + +FPhysXCooking::FPhysXCooking() +{ +#if WITH_PHYSX + PxTolerancesScale PScale; + PScale.length = CVarToleranceScaleLength.GetValueOnAnyThread(); + PScale.speed = CVarToleranceScaleSpeed.GetValueOnAnyThread(); + + PxCookingParams PCookingParams(PScale); + PCookingParams.meshWeldTolerance = 0.1f; // Weld to 1mm precision + PCookingParams.meshPreprocessParams = PxMeshPreprocessingFlags(PxMeshPreprocessingFlag::eWELD_VERTICES); + // Force any cooking in PhysX or APEX to use older incremental hull method + // This is because the new 'quick hull' method can generate degenerate geometry in some cases (very thin meshes etc.) + //PCookingParams.convexMeshCookingType = PxConvexMeshCookingType::eINFLATION_INCREMENTAL_HULL; + PCookingParams.targetPlatform = PxPlatform::ePC; + //PCookingParams.meshCookingHint = PxMeshCookingHint::eCOOKING_PERFORMANCE; + //PCookingParams.meshSizePerformanceTradeOff = 0.0f; + + PhysXCooking = PxCreateCooking(PX_PHYSICS_VERSION, *GPhysXFoundation, PCookingParams); +#endif +} + +physx::PxCooking* FPhysXCooking::GetCooking() const +{ + return PhysXCooking; +} + +bool FPhysXCooking::AllowParallelBuild() const +{ + return true; +} + +uint16 FPhysXCooking::GetVersion(FName Format) const +{ + check(CheckPhysXCooking(Format)); + return UE_PHYSX_PC_VER; +} + + +void FPhysXCooking::GetSupportedFormats(TArray& OutFormats) const +{ + OutFormats.Add(NAME_PhysXPC); + OutFormats.Add(NAME_PhysXXboxOne); + OutFormats.Add(NAME_PhysXPS4); +} + +/** Utility wrapper for a uint8 TArray for saving into PhysX. */ +class FPhysXOutputStream : public PxOutputStream +{ +public: + /** Raw byte data */ + TArray *Data; + + FPhysXOutputStream() + : Data(NULL) + {} + + FPhysXOutputStream(TArray *InData) + : Data(InData) + {} + + PxU32 write(const void* Src, PxU32 Count) + { + check(Data); + if (Count) //PhysX serializer can pass us 0 bytes to write + { + check(Src); + int32 CurrentNum = (*Data).Num(); + (*Data).AddUninitialized(Count); + FMemory::Memcpy(&(*Data)[CurrentNum], Src, Count); + } + + return Count; + } +}; + +template +EPhysXCookingResult FPhysXCooking::CookConvexImp(FName Format, EPhysXMeshCookFlags CookFlags, const TArray& SrcBuffer, TArray& OutBuffer, PxConvexMesh*& OutConvexMesh) const +{ + EPhysXCookingResult CookResult = EPhysXCookingResult::Failed; + OutConvexMesh = nullptr; + +#if WITH_PHYSX + PxPlatform::Enum PhysXFormat = PxPlatform::ePC; + bool bIsPhysXCookingValid = GetPhysXCooking(Format, PhysXFormat); + check(bIsPhysXCookingValid); + + PxConvexMeshDesc PConvexMeshDesc; + PConvexMeshDesc.points.data = SrcBuffer.GetData(); + PConvexMeshDesc.points.count = SrcBuffer.Num(); + PConvexMeshDesc.points.stride = sizeof(FVector); + PConvexMeshDesc.flags = PxConvexFlag::eCOMPUTE_CONVEX | PxConvexFlag::eSHIFT_VERTICES; + + // Set up cooking + const PxCookingParams CurrentParams = PhysXCooking->getParams(); + PxCookingParams NewParams = CurrentParams; + NewParams.targetPlatform = PhysXFormat; + + if (!!(CookFlags & EPhysXMeshCookFlags::SuppressFaceRemapTable)) + { + NewParams.suppressTriangleMeshRemapTable = true; + } + + if (!!(CookFlags & EPhysXMeshCookFlags::DeformableMesh)) + { + // Meshes which can be deformed need different cooking parameters to inhibit vertex welding and add an extra skin around the collision mesh for safety. + // We need to set the meshWeldTolerance to zero, even when disabling 'clean mesh' as PhysX will attempt to perform mesh cleaning anyway according to this meshWeldTolerance + // if the convex hull is not well formed. + // Set the skin thickness as a proportion of the overall size of the mesh as PhysX's internal tolerances also use the overall size to calculate the epsilon used. + const FBox Bounds(SrcBuffer); + const float MaxExtent = (Bounds.Max - Bounds.Min).Size(); + + NewParams.meshPreprocessParams = PxMeshPreprocessingFlags(PxMeshPreprocessingFlag::eDISABLE_CLEAN_MESH); + NewParams.meshWeldTolerance = 0.0f; + } + + // Do we want to do a 'fast' cook on this mesh, may slow down collision performance at runtime + if (!!(CookFlags & EPhysXMeshCookFlags::FastCook)) + { + NewParams.meshCookingHint = PxMeshCookingHint::eCOOKING_PERFORMANCE; + } + + PhysXCooking->setParams(NewParams); + + if (bUseBuffer) + { + // Cook the convex mesh to a temp buffer + TArray CookedMeshBuffer; + FPhysXOutputStream Buffer(&CookedMeshBuffer); + if (PhysXCooking->cookConvexMesh(PConvexMeshDesc, Buffer)) + { + CookResult = EPhysXCookingResult::Succeeded; + } + else + { + if (!(PConvexMeshDesc.flags & PxConvexFlag::eINFLATE_CONVEX)) + { + // We failed to cook without inflating convex. Let's try again with inflation + //This is not ideal since it makes the collision less accurate. It's needed if given verts are extremely close. + PConvexMeshDesc.flags |= PxConvexFlag::eINFLATE_CONVEX; + if (PhysXCooking->cookConvexMesh(PConvexMeshDesc, Buffer)) + { + CookResult = EPhysXCookingResult::SucceededWithInflation; + } + } + } + + if (CookedMeshBuffer.Num() == 0) + { + CookResult = EPhysXCookingResult::Failed; + } + + if (CookResult != EPhysXCookingResult::Failed) + { + // Append the cooked data into cooked buffer + OutBuffer.Append(CookedMeshBuffer); + } + } + else + { + OutConvexMesh = PhysXCooking->createConvexMesh(PConvexMeshDesc, GPhysXSDK->getPhysicsInsertionCallback()); //NOTE: getPhysicsInsertionCallback probably not thread safe! + if (OutConvexMesh) + { + CookResult = EPhysXCookingResult::Succeeded; + } + else + { + if (!(PConvexMeshDesc.flags & PxConvexFlag::eINFLATE_CONVEX)) + { + // We failed to cook without inflating convex. Let's try again with inflation + //This is not ideal since it makes the collision less accurate. It's needed if given verts are extremely close. + PConvexMeshDesc.flags |= PxConvexFlag::eINFLATE_CONVEX; + OutConvexMesh = PhysXCooking->createConvexMesh(PConvexMeshDesc, GPhysXSDK->getPhysicsInsertionCallback()); //NOTE: getPhysicsInsertionCallback probably not thread safe! + if (OutConvexMesh) + { + CookResult = EPhysXCookingResult::SucceededWithInflation; + } + } + } + + if (!OutConvexMesh) + { + CookResult = EPhysXCookingResult::Failed; + } + } + + + // Return default cooking params to normal + PhysXCooking->setParams(CurrentParams); +#endif // WITH_PHYSX + + return CookResult; +} + +EPhysXCookingResult FPhysXCooking::CookConvex(FName Format, EPhysXMeshCookFlags CookFlags, const TArray& SrcBuffer, TArray& OutBuffer) const +{ + PxConvexMesh* JunkConvexMesh; + return CookConvexImp(Format, CookFlags, SrcBuffer, OutBuffer, JunkConvexMesh); +} + +EPhysXCookingResult FPhysXCooking::CreateConvex(FName Format, EPhysXMeshCookFlags CookFlags, const TArray& SrcBuffer, physx::PxConvexMesh*& OutConvexMesh) const +{ + TArray JunkBuffer; + return CookConvexImp(Format, CookFlags, SrcBuffer, JunkBuffer, OutConvexMesh); +} + +template +bool FPhysXCooking::CookTriMeshImp(FName Format, EPhysXMeshCookFlags CookFlags, const TArray& SrcVertices, const TArray& SrcIndices, const TArray& SrcMaterialIndices, const bool FlipNormals, TArray& OutBuffer, PxTriangleMesh*& OutTriangleMesh) const +{ + OutTriangleMesh = nullptr; +#if WITH_PHYSX + PxPlatform::Enum PhysXFormat = PxPlatform::ePC; + bool bIsPhysXCookingValid = GetPhysXCooking(Format, PhysXFormat); + check(bIsPhysXCookingValid); + + PxTriangleMeshDesc PTriMeshDesc; + PTriMeshDesc.points.data = SrcVertices.GetData(); + PTriMeshDesc.points.count = SrcVertices.Num(); + PTriMeshDesc.points.stride = sizeof(FVector); + PTriMeshDesc.triangles.data = SrcIndices.GetData(); + PTriMeshDesc.triangles.count = SrcIndices.Num(); + PTriMeshDesc.triangles.stride = sizeof(FTriIndices); + PTriMeshDesc.materialIndices.data = SrcMaterialIndices.GetData(); + PTriMeshDesc.materialIndices.stride = sizeof(PxMaterialTableIndex); + PTriMeshDesc.flags = FlipNormals ? PxMeshFlag::eFLIPNORMALS : (PxMeshFlags)0; + + // Set up cooking + const PxCookingParams CurrentParams = PhysXCooking->getParams(); + PxCookingParams NewParams = CurrentParams; + NewParams.targetPlatform = PhysXFormat; + + if (!!(CookFlags & EPhysXMeshCookFlags::SuppressFaceRemapTable)) + { + NewParams.suppressTriangleMeshRemapTable = true; + } + + if (!!(CookFlags & EPhysXMeshCookFlags::DeformableMesh)) + { + // In the case of a deformable mesh, we have to change the cook params + NewParams.meshPreprocessParams = PxMeshPreprocessingFlag::eDISABLE_CLEAN_MESH; + } + + PhysXCooking->setParams(NewParams); + + bool bResult = false; + + // Cook TriMesh Data + if (bUseBuffer) + { + FPhysXOutputStream Buffer(&OutBuffer); + bResult = PhysXCooking->cookTriangleMesh(PTriMeshDesc, Buffer); + } + else + { + FPhysXOutputStream Buffer(&OutBuffer); + OutTriangleMesh = PhysXCooking->createTriangleMesh(PTriMeshDesc, GPhysXSDK->getPhysicsInsertionCallback()); //NOTE: getPhysicsInsertionCallback probably not thread safe! + bResult = !!OutTriangleMesh; + } + + + // Restore cooking params + PhysXCooking->setParams(CurrentParams); + return bResult; +#else + return false; +#endif // WITH_PHYSX +} + +bool FPhysXCooking::CookTriMesh(FName Format, EPhysXMeshCookFlags CookFlags, const TArray& SrcVertices, const TArray& SrcIndices, const TArray& SrcMaterialIndices, const bool FlipNormals, TArray& OutBuffer) const +{ + PxTriangleMesh* JunkTriangleMesh = nullptr; + return CookTriMeshImp(Format, CookFlags, SrcVertices, SrcIndices, SrcMaterialIndices, FlipNormals, OutBuffer, JunkTriangleMesh); +} + +bool FPhysXCooking::CreateTriMesh(FName Format, EPhysXMeshCookFlags CookFlags, const TArray& SrcVertices, const TArray& SrcIndices, const TArray& SrcMaterialIndices, const bool FlipNormals, physx::PxTriangleMesh*& OutTriangleMesh) const +{ + TArray JunkBuffer; + return CookTriMeshImp(Format, CookFlags, SrcVertices, SrcIndices, SrcMaterialIndices, FlipNormals, JunkBuffer, OutTriangleMesh); +} + +template +bool FPhysXCooking::CookHeightFieldImp(FName Format, FIntPoint HFSize, const void* Samples, uint32 SamplesStride, TArray& OutBuffer, PxHeightField*& OutHeightField) const +{ + OutHeightField = nullptr; +#if WITH_PHYSX + PxPlatform::Enum PhysXFormat = PxPlatform::ePC; + bool bIsPhysXCookingValid = GetPhysXCooking(Format, PhysXFormat); + check(bIsPhysXCookingValid); + + PxHeightFieldDesc HFDesc; + HFDesc.format = PxHeightFieldFormat::eS16_TM; + HFDesc.nbColumns = HFSize.X; + HFDesc.nbRows = HFSize.Y; + HFDesc.samples.data = Samples; + HFDesc.samples.stride = SamplesStride; + HFDesc.flags = PxHeightFieldFlag::eNO_BOUNDARY_EDGES; + + // Set up cooking + const PxCookingParams& Params = PhysXCooking->getParams(); + PxCookingParams NewParams = Params; + NewParams.targetPlatform = PhysXFormat; + PhysXCooking->setParams(NewParams); + + // Cook to a temp buffer + TArray CookedBuffer; + FPhysXOutputStream Buffer(&CookedBuffer); + + if (bUseBuffer) + { + if (PhysXCooking->cookHeightField(HFDesc, Buffer) && CookedBuffer.Num() > 0) + { + // Append the cooked data into cooked buffer + OutBuffer.Append(CookedBuffer); + return true; + } + } + else + { + OutHeightField = PhysXCooking->createHeightField(HFDesc, GPhysXSDK->getPhysicsInsertionCallback()); //NOTE: getPhysicsInsertionCallback probably not thread safe! + if (OutHeightField) + { + return true; + } + } + + + return false; +#else + return false; +#endif // WITH_PHYSX +} + +bool FPhysXCooking::CookHeightField(FName Format, FIntPoint HFSize, const void* Samples, uint32 SamplesStride, TArray& OutBuffer) const +{ + physx::PxHeightField* JunkHeightField = nullptr; + return CookHeightFieldImp(Format, HFSize, Samples, SamplesStride, OutBuffer, JunkHeightField); +} + +bool FPhysXCooking::CreateHeightField(FName Format, FIntPoint HFSize, const void* Samples, uint32 SamplesStride, physx::PxHeightField*& OutHeightField) const +{ + TArray JunkBuffer; + return CookHeightFieldImp(Format, HFSize, Samples, SamplesStride, JunkBuffer, OutHeightField); +} + +bool FPhysXCooking::SerializeActors(FName Format, const TArray& Bodies, const TArray& BodySetups, const TArray& PhysicalMaterials, TArray& OutBuffer) const +{ +#if WITH_PHYSX + PxSerializationRegistry* PRegistry = PxSerialization::createSerializationRegistry(*GPhysXSDK); + PxCollection* PCollection = PxCreateCollection(); + + PxBase* PLastObject = nullptr; + + for (FBodyInstance* BodyInstance : Bodies) + { + if (BodyInstance->RigidActorSync) + { + PCollection->add(*BodyInstance->RigidActorSync, BodyInstance->RigidActorSyncId); + PLastObject = BodyInstance->RigidActorSync; + } + + if (BodyInstance->RigidActorAsync) + { + PCollection->add(*BodyInstance->RigidActorAsync, BodyInstance->RigidActorAsyncId); + PLastObject = BodyInstance->RigidActorAsync; + } + } + + PxSerialization::createSerialObjectIds(*PCollection, PxSerialObjectId(1)); //we get physx to assign an id for each actor + + //Note that rigid bodies may have assigned ids. It's important to let them go first because we rely on that id for deserialization. + //One this is done we must find out the next available ID, and use that for naming the shared resources. We have to save this for deserialization + uint64 BaseId = PLastObject ? (PCollection->getId(*PLastObject) + 1) : 1; + + PxCollection* PExceptFor = MakePhysXCollection(PhysicalMaterials, BodySetups, BaseId); + + for (FBodyInstance* BodyInstance : Bodies) //and then we mark that id back into the bodyinstance so we can pair the two later + { + if (BodyInstance->RigidActorSync) + { + BodyInstance->RigidActorSyncId = PCollection->getId(*BodyInstance->RigidActorSync); + } + + if (BodyInstance->RigidActorAsync) + { + BodyInstance->RigidActorAsyncId = PCollection->getId(*BodyInstance->RigidActorAsync); + } + } + + //We must store the BaseId for shared resources. + FMemoryWriter Ar(OutBuffer); + uint8 bIsLittleEndian = PLATFORM_LITTLE_ENDIAN; //TODO: We should pass the target platform into this function and write it. Then swap the endian on the writer so the reader doesn't have to do it at runtime + Ar << bIsLittleEndian; + Ar << BaseId; + //Note that PhysX expects the binary data to be 128-byte aligned. Because of this we must pad + int32 BytesToPad = PHYSX_SERIALIZATION_ALIGNMENT - (Ar.Tell() % PHYSX_SERIALIZATION_ALIGNMENT); + OutBuffer.AddZeroed(BytesToPad); + + FPhysXOutputStream Buffer(&OutBuffer); + PxSerialization::complete(*PCollection, *PRegistry, PExceptFor); + PxSerialization::serializeCollectionToBinary(Buffer, *PCollection, *PRegistry, PExceptFor); + +#if PHYSX_MEMORY_VALIDATION + GPhysXAllocator->ValidateHeaders(); +#endif + PCollection->release(); + PExceptFor->release(); + PRegistry->release(); + +#if PHYSX_MEMORY_VALIDATION + GPhysXAllocator->ValidateHeaders(); +#endif + return true; +#endif + return false; +} + + +FPhysXPlatformModule::FPhysXPlatformModule() +{ + PhysXCookerTLS = FPlatformTLS::AllocTlsSlot(); +} + +FPhysXPlatformModule::~FPhysXPlatformModule() +{ + //NOTE: we don't bother cleaning up TLS, this is only closed during real shutdown +} + +IPhysXCooking* FPhysXPlatformModule::GetPhysXCooking() +{ + FPhysXCooking* PhysXCooking = (FPhysXCooking*)FPlatformTLS::GetTlsValue(PhysXCookerTLS); + if (!PhysXCooking) + { + InitPhysXCooking(); + PhysXCooking = new FPhysXCooking(); + FPlatformTLS::SetTlsValue(PhysXCookerTLS, PhysXCooking); + } + + return PhysXCooking; +} + +physx::PxCooking* FPhysXPlatformModule::CreatePhysXCooker(uint32 version, physx::PxFoundation& foundation, const physx::PxCookingParams& params) +{ +#if WITH_PHYSX + return PxCreateCooking(PX_PHYSICS_VERSION, foundation, params); +#endif + return nullptr; +} + +void FPhysXPlatformModule::Terminate() +{ + ShutdownPhysXCooking(); +} + +/** +* Load the required modules for PhysX +*/ +void FPhysXPlatformModule::InitPhysXCooking() +{ + if (IsInGameThread()) + { + // Make sure PhysX libs are loaded + LoadPhysXModules(/*bLoadCookingModule=*/true); + } +} + +void FPhysXPlatformModule::ShutdownPhysXCooking() +{ +#if WITH_PHYSX + if (PxCooking* PhysXCooking = GetPhysXCooking()->GetCooking()) + { + PhysXCooking->release(); + PhysXCooking = nullptr; + } + + //TODO: is it worth killing all the TLS objects? +#endif +} + +IMPLEMENT_MODULE(FPhysXPlatformModule, PhysXCooking); diff --git a/Engine/Source/Runtime/PhysXCooking/Public/PhysXCooking.h b/Engine/Source/Runtime/PhysXCooking/Public/PhysXCooking.h new file mode 100644 index 000000000000..b5c021809263 --- /dev/null +++ b/Engine/Source/Runtime/PhysXCooking/Public/PhysXCooking.h @@ -0,0 +1,93 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "Physics/IPhysXCooking.h" +#include "Physics/IPhysXCookingModule.h" + +namespace physx +{ + class PxCooking; + class PxTriangleMesh; + class PxConvexMesh; + class PxHeightField; + class PxFoundation; + struct PxCookingParams; +} + +/** +* FPhysXCooking. Cooks physics data. +**/ +class PHYSXCOOKING_API FPhysXCooking : public IPhysXCooking +{ +public: + + FPhysXCooking(); + virtual physx::PxCooking* GetCooking() const override; + virtual bool AllowParallelBuild() const override; + virtual uint16 GetVersion(FName Format) const override; + virtual void GetSupportedFormats(TArray& OutFormats) const override; + + virtual EPhysXCookingResult CookConvex(FName Format, EPhysXMeshCookFlags CookFlags, const TArray& SrcBuffer, TArray& OutBuffer) const override; + EPhysXCookingResult CreateConvex(FName Format, EPhysXMeshCookFlags CookFlags, const TArray& SrcBuffer, physx::PxConvexMesh*& OutConvexMesh) const override; + + virtual bool CookTriMesh(FName Format, EPhysXMeshCookFlags CookFlags, const TArray& SrcVertices, const TArray& SrcIndices, const TArray& SrcMaterialIndices, const bool FlipNormals, TArray& OutBuffer) const override; + virtual bool CreateTriMesh(FName Format, EPhysXMeshCookFlags CookFlags, const TArray& SrcVertices, const TArray& SrcIndices, const TArray& SrcMaterialIndices, const bool FlipNormals, physx::PxTriangleMesh*& OutTriangleMesh) const override; + + virtual bool CookHeightField(FName Format, FIntPoint HFSize, const void* Samples, uint32 SamplesStride, TArray& OutBuffer) const override; + virtual bool CreateHeightField(FName Format, FIntPoint HFSize, const void* Samples, uint32 SamplesStride, physx::PxHeightField*& OutHeightField) const override; + + virtual bool SerializeActors(FName Format, const TArray& Bodies, const TArray& BodySetups, const TArray& PhysicalMaterials, TArray& OutBuffer) const override; + +private: + + template + EPhysXCookingResult CookConvexImp(FName Format, EPhysXMeshCookFlags CookFlags, const TArray& SrcBuffer, TArray& OutBuffer, physx::PxConvexMesh*& OutConvexMesh) const; + + template + bool CookHeightFieldImp(FName Format, FIntPoint HFSize, const void* Samples, uint32 SamplesStride, TArray& OutBuffer, physx::PxHeightField*& OutHeightField) const; + + template + bool CookTriMeshImp(FName Format, EPhysXMeshCookFlags CookFlags, const TArray& SrcVertices, const TArray& SrcIndices, const TArray& SrcMaterialIndices, const bool FlipNormals, TArray& OutBuffer, physx::PxTriangleMesh*& OutTriangleMesh) const; + +private: + enum + { + /** Version for PhysX format, this becomes part of the DDC key. */ + UE_PHYSX_PC_VER = 0, + }; + +private: + physx::PxCooking* PhysXCooking; + +}; + + +/** +* Module for PhysX cooking +*/ + +class PHYSXCOOKING_API FPhysXPlatformModule : public IPhysXCookingModule +{ +public: + FPhysXPlatformModule(); + + virtual ~FPhysXPlatformModule(); + + virtual IPhysXCooking* GetPhysXCooking(); + + virtual physx::PxCooking* CreatePhysXCooker(uint32 version, physx::PxFoundation& foundation, const physx::PxCookingParams& params); + + virtual void Terminate() override; + +private: + + /** + * Load the required modules for PhysX + */ + void InitPhysXCooking(); + + void ShutdownPhysXCooking(); + + uint32 PhysXCookerTLS; +}; \ No newline at end of file diff --git a/Engine/Source/Runtime/PhysXFormats/PhysXFormats.Build.cs b/Engine/Source/Runtime/PhysXFormats/PhysXFormats.Build.cs deleted file mode 100644 index 445456a6d9d6..000000000000 --- a/Engine/Source/Runtime/PhysXFormats/PhysXFormats.Build.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -using UnrealBuildTool; -using System.IO; - -public class PhysXFormats : ModuleRules -{ - public PhysXFormats(ReadOnlyTargetRules Target) : base(Target) - { - PrivateIncludePathModuleNames.Add("TargetPlatform"); - - PrivateDependencyModuleNames.AddRange( - new string[] { - "Core", - "CoreUObject", // @todo Mac: for some reason it's needed to link in debug on Mac - "Engine" - } - ); - - PrivateIncludePaths.AddRange( - new string[] { - "Runtime/Engine/Private", //Not sure why this is its own format. The two modules depend on eachother. - } - ); - - SetupModulePhysXAPEXSupport(Target); - } -} diff --git a/Engine/Source/Runtime/PhysXFormats/Private/PhysXFormats.cpp b/Engine/Source/Runtime/PhysXFormats/Private/PhysXFormats.cpp deleted file mode 100644 index 8b6eeeb0c044..000000000000 --- a/Engine/Source/Runtime/PhysXFormats/Private/PhysXFormats.cpp +++ /dev/null @@ -1,378 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#include "PhysXFormats.h" -#include "Serialization/MemoryWriter.h" -#include "Modules/ModuleManager.h" -#include "Interfaces/Interface_CollisionDataProvider.h" -#include "IPhysXFormat.h" -#include "IPhysXFormatModule.h" -#include "PhysicsEngine/PhysXSupport.h" - -static_assert(WITH_PHYSX, "No point in compiling PhysX cooker, if we don't have PhysX."); - -static FName NAME_PhysXPC(TEXT("PhysXPC")); -static FName NAME_PhysXXboxOne(TEXT("PhysXXboxOne")); -static FName NAME_PhysXPS4(TEXT("PhysXPS4")); - -/** - * FPhysXFormats. Cooks physics data. -**/ -class FPhysXFormats : public IPhysXFormat -{ - enum - { - /** Version for PhysX format, this becomes part of the DDC key. */ - UE_PHYSX_PC_VER = 0, - }; - - PxCooking* PhysXCooking; - - /** - * Validates format name and returns its PhysX enum value. - * - * @param InFormatName PhysX format name. - * @param OutFormat PhysX enum - * @return true if InFormatName is a valid and supported PhysX format - */ - bool GetPhysXFormat(FName InFormatName, PxPlatform::Enum& OutFormat) const - { - if ((InFormatName == NAME_PhysXPC) || (InFormatName == NAME_PhysXXboxOne) || (InFormatName == NAME_PhysXPS4)) - { - OutFormat = PxPlatform::ePC; - } - else - { - return false; - } - return true; - } - - /** - * Valudates PhysX format name. - */ - bool CheckPhysXFormat(FName InFormatName) const - { - PxPlatform::Enum PhysXFormat = PxPlatform::ePC; - return GetPhysXFormat(InFormatName, PhysXFormat); - } - -public: - - FPhysXFormats( PxCooking* InCooking ) - : PhysXCooking( InCooking ) - {} - - virtual bool AllowParallelBuild() const override - { - return false; - } - - virtual uint16 GetVersion(FName Format) const override - { - check(CheckPhysXFormat(Format)); - return UE_PHYSX_PC_VER; - } - - - virtual void GetSupportedFormats(TArray& OutFormats) const override - { - OutFormats.Add(NAME_PhysXPC); - OutFormats.Add(NAME_PhysXXboxOne); - OutFormats.Add(NAME_PhysXPS4); - } - - virtual EPhysXCookingResult CookConvex(FName Format, EPhysXMeshCookFlags CookFlags, const TArray& SrcBuffer, TArray& OutBuffer) const override - { - EPhysXCookingResult CookResult = EPhysXCookingResult::Failed; - -#if WITH_PHYSX - PxPlatform::Enum PhysXFormat = PxPlatform::ePC; - bool bIsPhysXFormatValid = GetPhysXFormat(Format, PhysXFormat); - check(bIsPhysXFormatValid); - - PxConvexMeshDesc PConvexMeshDesc; - PConvexMeshDesc.points.data = SrcBuffer.GetData(); - PConvexMeshDesc.points.count = SrcBuffer.Num(); - PConvexMeshDesc.points.stride = sizeof(FVector); - PConvexMeshDesc.flags = PxConvexFlag::eCOMPUTE_CONVEX | PxConvexFlag::eSHIFT_VERTICES; - - // Set up cooking - const PxCookingParams CurrentParams = PhysXCooking->getParams(); - PxCookingParams NewParams = CurrentParams; - NewParams.targetPlatform = PhysXFormat; - - if(!!(CookFlags & EPhysXMeshCookFlags::SuppressFaceRemapTable)) - { - NewParams.suppressTriangleMeshRemapTable = true; - } - - if (!!(CookFlags & EPhysXMeshCookFlags::DeformableMesh)) - { - // Meshes which can be deformed need different cooking parameters to inhibit vertex welding and add an extra skin around the collision mesh for safety. - // We need to set the meshWeldTolerance to zero, even when disabling 'clean mesh' as PhysX will attempt to perform mesh cleaning anyway according to this meshWeldTolerance - // if the convex hull is not well formed. - // Set the skin thickness as a proportion of the overall size of the mesh as PhysX's internal tolerances also use the overall size to calculate the epsilon used. - const FBox Bounds(SrcBuffer); - const float MaxExtent = (Bounds.Max - Bounds.Min).Size(); - - NewParams.meshPreprocessParams = PxMeshPreprocessingFlags(PxMeshPreprocessingFlag::eDISABLE_CLEAN_MESH); - NewParams.meshWeldTolerance = 0.0f; - } - - // Do we want to do a 'fast' cook on this mesh, may slow down collision performance at runtime - if (!!(CookFlags & EPhysXMeshCookFlags::FastCook)) - { - NewParams.meshCookingHint = PxMeshCookingHint::eCOOKING_PERFORMANCE; - } - - PhysXCooking->setParams(NewParams); - - // Cook the convex mesh to a temp buffer - TArray CookedMeshBuffer; - FPhysXOutputStream Buffer(&CookedMeshBuffer); - if (PhysXCooking->cookConvexMesh(PConvexMeshDesc, Buffer)) - { - CookResult = EPhysXCookingResult::Succeeded; - } - else - { - if (!(PConvexMeshDesc.flags & PxConvexFlag::eINFLATE_CONVEX)) - { - // We failed to cook without inflating convex. Let's try again with inflation - //This is not ideal since it makes the collision less accurate. It's needed if given verts are extremely close. - PConvexMeshDesc.flags |= PxConvexFlag::eINFLATE_CONVEX; - if (PhysXCooking->cookConvexMesh(PConvexMeshDesc, Buffer)) - { - CookResult = EPhysXCookingResult::SucceededWithInflation; - } - } - } - - // Return default cooking params to normal - PhysXCooking->setParams(CurrentParams); - - if (CookedMeshBuffer.Num() == 0) - { - CookResult = EPhysXCookingResult::Failed; - } - - if (CookResult != EPhysXCookingResult::Failed) - { - // Append the cooked data into cooked buffer - OutBuffer.Append( CookedMeshBuffer ); - } -#endif // WITH_PHYSX - - return CookResult; - } - - virtual bool CookTriMesh(FName Format, EPhysXMeshCookFlags CookFlags, const TArray& SrcVertices, const TArray& SrcIndices, const TArray& SrcMaterialIndices, const bool FlipNormals, TArray& OutBuffer) const override - { -#if WITH_PHYSX - PxPlatform::Enum PhysXFormat = PxPlatform::ePC; - bool bIsPhysXFormatValid = GetPhysXFormat(Format, PhysXFormat); - check(bIsPhysXFormatValid); - - PxTriangleMeshDesc PTriMeshDesc; - PTriMeshDesc.points.data = SrcVertices.GetData(); - PTriMeshDesc.points.count = SrcVertices.Num(); - PTriMeshDesc.points.stride = sizeof(FVector); - PTriMeshDesc.triangles.data = SrcIndices.GetData(); - PTriMeshDesc.triangles.count = SrcIndices.Num(); - PTriMeshDesc.triangles.stride = sizeof(FTriIndices); - PTriMeshDesc.materialIndices.data = SrcMaterialIndices.GetData(); - PTriMeshDesc.materialIndices.stride = sizeof(PxMaterialTableIndex); - PTriMeshDesc.flags = FlipNormals ? PxMeshFlag::eFLIPNORMALS : (PxMeshFlags)0; - - // Set up cooking - const PxCookingParams CurrentParams = PhysXCooking->getParams(); - PxCookingParams NewParams = CurrentParams; - NewParams.targetPlatform = PhysXFormat; - - if (!!(CookFlags & EPhysXMeshCookFlags::SuppressFaceRemapTable)) - { - NewParams.suppressTriangleMeshRemapTable = true; - } - - if (!!(CookFlags & EPhysXMeshCookFlags::DeformableMesh)) - { - // In the case of a deformable mesh, we have to change the cook params - NewParams.meshPreprocessParams = PxMeshPreprocessingFlag::eDISABLE_CLEAN_MESH; - } - - PhysXCooking->setParams(NewParams); - - - // Cook TriMesh Data - FPhysXOutputStream Buffer(&OutBuffer); - bool Result = PhysXCooking->cookTriangleMesh(PTriMeshDesc, Buffer); - - // Restore cooking params - PhysXCooking->setParams(CurrentParams); - return Result; -#else - return false; -#endif // WITH_PHYSX - } - - virtual bool CookHeightField(FName Format, FIntPoint HFSize, const void* Samples, uint32 SamplesStride, TArray& OutBuffer) const override - { -#if WITH_PHYSX - PxPlatform::Enum PhysXFormat = PxPlatform::ePC; - bool bIsPhysXFormatValid = GetPhysXFormat(Format, PhysXFormat); - check(bIsPhysXFormatValid); - - PxHeightFieldDesc HFDesc; - HFDesc.format = PxHeightFieldFormat::eS16_TM; - HFDesc.nbColumns = HFSize.X; - HFDesc.nbRows = HFSize.Y; - HFDesc.samples.data = Samples; - HFDesc.samples.stride = SamplesStride; - HFDesc.flags = PxHeightFieldFlag::eNO_BOUNDARY_EDGES; - - // Set up cooking - const PxCookingParams& Params = PhysXCooking->getParams(); - PxCookingParams NewParams = Params; - NewParams.targetPlatform = PhysXFormat; - PhysXCooking->setParams(NewParams); - - // Cook to a temp buffer - TArray CookedBuffer; - FPhysXOutputStream Buffer(&CookedBuffer); - - if (PhysXCooking->cookHeightField(HFDesc, Buffer) && CookedBuffer.Num() > 0) - { - // Append the cooked data into cooked buffer - OutBuffer.Append(CookedBuffer); - return true; - } - return false; -#else - return false; -#endif // WITH_PHYSX - } - - virtual bool SerializeActors(FName Format, const TArray& Bodies, const TArray& BodySetups, const TArray& PhysicalMaterials, TArray& OutBuffer) const override - { -#if WITH_PHYSX - PxSerializationRegistry* PRegistry = PxSerialization::createSerializationRegistry(*GPhysXSDK); - PxCollection* PCollection = PxCreateCollection(); - - PxBase* PLastObject = nullptr; - - for(FBodyInstance* BodyInstance : Bodies) - { - if(BodyInstance->RigidActorSync) - { - PCollection->add(*BodyInstance->RigidActorSync, BodyInstance->RigidActorSyncId); - PLastObject = BodyInstance->RigidActorSync; - } - - if(BodyInstance->RigidActorAsync) - { - PCollection->add(*BodyInstance->RigidActorAsync, BodyInstance->RigidActorAsyncId); - PLastObject = BodyInstance->RigidActorAsync; - } - } - - PxSerialization::createSerialObjectIds(*PCollection, PxSerialObjectId(1)); //we get physx to assign an id for each actor - - //Note that rigid bodies may have assigned ids. It's important to let them go first because we rely on that id for deserialization. - //One this is done we must find out the next available ID, and use that for naming the shared resources. We have to save this for deserialization - uint64 BaseId = PLastObject ? (PCollection->getId(*PLastObject) + 1) : 1; - - PxCollection* PExceptFor = MakePhysXCollection(PhysicalMaterials, BodySetups, BaseId); - - for (FBodyInstance* BodyInstance : Bodies) //and then we mark that id back into the bodyinstance so we can pair the two later - { - if (BodyInstance->RigidActorSync) - { - BodyInstance->RigidActorSyncId = PCollection->getId(*BodyInstance->RigidActorSync); - } - - if (BodyInstance->RigidActorAsync) - { - BodyInstance->RigidActorAsyncId = PCollection->getId(*BodyInstance->RigidActorAsync); - } - } - - //We must store the BaseId for shared resources. - FMemoryWriter Ar(OutBuffer); - uint8 bIsLittleEndian = PLATFORM_LITTLE_ENDIAN; //TODO: We should pass the target platform into this function and write it. Then swap the endian on the writer so the reader doesn't have to do it at runtime - Ar << bIsLittleEndian; - Ar << BaseId; - //Note that PhysX expects the binary data to be 128-byte aligned. Because of this we must pad - int32 BytesToPad = PHYSX_SERIALIZATION_ALIGNMENT - (Ar.Tell() % PHYSX_SERIALIZATION_ALIGNMENT); - OutBuffer.AddZeroed(BytesToPad); - - FPhysXOutputStream Buffer(&OutBuffer); - PxSerialization::complete(*PCollection, *PRegistry, PExceptFor); - PxSerialization::serializeCollectionToBinary(Buffer, *PCollection, *PRegistry, PExceptFor); - -#if PHYSX_MEMORY_VALIDATION - GPhysXAllocator->ValidateHeaders(); -#endif - PCollection->release(); - PExceptFor->release(); - PRegistry->release(); - -#if PHYSX_MEMORY_VALIDATION - GPhysXAllocator->ValidateHeaders(); -#endif - return true; -#endif - return false; - } - -}; - - -/** - * Module for PhysX cooking - */ -static IPhysXFormat* Singleton = NULL; - -class FPhysXPlatformModule : public IPhysXFormatModule -{ -public: - FPhysXPlatformModule() - { - - } - - virtual ~FPhysXPlatformModule() - { - ShutdownPhysXCooking(); - - delete Singleton; - Singleton = NULL; - } - virtual IPhysXFormat* GetPhysXFormat() - { - if (!Singleton) - { - InitPhysXCooking(); - Singleton = new FPhysXFormats(GPhysXCooking); - } - return Singleton; - } - -private: - - /** - * Load the required modules for PhysX - */ - void InitPhysXCooking() - { - // Make sure PhysX libs are loaded - LoadPhysXModules(); - } - - void ShutdownPhysXCooking() - { - // Ideally PhysX cooking should be initialized in InitPhysXCooking and released here - // but Apex is still being setup in the engine and it also requires PhysX cooking singleton. - } -}; - -IMPLEMENT_MODULE( FPhysXPlatformModule, PhysXFormats ); diff --git a/Engine/Source/Runtime/PhysXFormats/Private/PhysXFormats.h b/Engine/Source/Runtime/PhysXFormats/Private/PhysXFormats.h deleted file mode 100644 index 292239fcc27d..000000000000 --- a/Engine/Source/Runtime/PhysXFormats/Private/PhysXFormats.h +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "CoreMinimal.h" -#include "EngineDefines.h" - -#if WITH_PHYSX - -#ifdef _MSC_VER -#pragma warning( push ) -#pragma warning( disable : 4946 ) // reinterpret_cast used between related classes -#endif - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wshadow" -#endif - -#if USING_CODE_ANALYSIS -#pragma warning( push ) -#pragma warning( disable : ALL_CODE_ANALYSIS_WARNINGS ) -#endif // USING_CODE_ANALYSIS - -// on Linux 32-bit, PhysX is compiled differently -#if (PLATFORM_LINUX && PLATFORM_CPU_X86_FAMILY && !PLATFORM_64BITS) - #pragma pack(push,16) -#else - #pragma pack(push,8) -#endif // (PLATFORM_LINUX && PLATFORM_CPU_X86) - -#include "Px.h" -#include "PxPhysicsAPI.h" -#include "PxRenderBuffer.h" -#include "PxExtensionsAPI.h" -#include "PxPvd.h" -#include "PxCollectionExt.h" -//#include "PxDefaultCpuDispatcher.h" - -// vehicle related header files -//#include "PxVehicleSDK.h" -//#include "PxVehicleUtils.h" - -// utils -#include "PxGeometryQuery.h" -#include "PxMeshQuery.h" -#include "PxTriangle.h" - -#pragma pack(pop) - -#if USING_CODE_ANALYSIS -#pragma warning( pop ) -#endif // USING_CODE_ANALYSIS - -#ifdef _MSC_VER -#pragma warning( pop ) -#endif - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -using namespace physx; - -/** Utility wrapper for a uint8 TArray for saving into PhysX. */ -class FPhysXOutputStream : public PxOutputStream -{ -public: - /** Raw byte data */ - TArray *Data; - - FPhysXOutputStream() - : Data(NULL) - {} - - FPhysXOutputStream(TArray *InData) - : Data(InData) - {} - - virtual PxU32 write(const void* Src, PxU32 Count) override - { - check(Data); - if(Count) //PhysX serializer can pass us 0 bytes to write - { - check(Src); - int32 CurrentNum = (*Data).Num(); - (*Data).AddUninitialized(Count); - FMemory::Memcpy(&(*Data)[CurrentNum], Src, Count); - } - - return Count; - } -}; - -#endif // WITH_PHYSX diff --git a/Engine/Source/Runtime/Portal/LauncherCheck/LauncherCheck.Build.cs b/Engine/Source/Runtime/Portal/LauncherCheck/LauncherCheck.Build.cs index 2a78f5726185..9dccc125ef5f 100644 --- a/Engine/Source/Runtime/Portal/LauncherCheck/LauncherCheck.Build.cs +++ b/Engine/Source/Runtime/Portal/LauncherCheck/LauncherCheck.Build.cs @@ -6,19 +6,24 @@ public class LauncherCheck : ModuleRules { public LauncherCheck(ReadOnlyTargetRules Target) : base(Target) { + PublicIncludePaths.Add("Runtime/Portal/LauncherCheck/Public"); + PublicDependencyModuleNames.AddRange( new string[] { "Core", - "HTTP", + "HTTP", } ); - // Need to make this an option as it pulls in a developer module - if (UEBuildConfiguration.bUseLauncherChecks) + if (UEBuildConfiguration.bUseLauncherChecks) + { + Definitions.Add("WITH_LAUNCHERCHECK=1"); + PublicDependencyModuleNames.Add("LauncherPlatform"); + } + else { - Definitions.Add("WITH_LAUNCHERCHECK=1"); - PublicDependencyModuleNames.Add("DesktopPlatform"); + Definitions.Add("WITH_LAUNCHERCHECK=0"); } } } diff --git a/Engine/Source/Runtime/Portal/LauncherCheck/Private/LauncherCheckModule.cpp b/Engine/Source/Runtime/Portal/LauncherCheck/Private/LauncherCheckModule.cpp index 3cae6f69f660..eee9867b6f84 100644 --- a/Engine/Source/Runtime/Portal/LauncherCheck/Private/LauncherCheckModule.cpp +++ b/Engine/Source/Runtime/Portal/LauncherCheck/Private/LauncherCheckModule.cpp @@ -13,8 +13,8 @@ #if defined(WITH_LAUNCHERCHECK) && WITH_LAUNCHERCHECK #include "GenericPlatformHttp.h" -#include "IDesktopPlatform.h" -#include "DesktopPlatformModule.h" +#include "ILauncherPlatform.h" +#include "LauncherPlatformModule.h" /** * Log categories for LauncherCheck module @@ -49,8 +49,8 @@ public: virtual bool RunLauncher(ELauncherAction Action, FString Payload = FString()) const override { - IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get(); - if (DesktopPlatform != nullptr) + ILauncherPlatform* LauncherPlatform = FLauncherPlatformModule::Get(); + if (LauncherPlatform != nullptr) { // Construct a url to tell the launcher of this app and what we want to do with it FOpenLauncherOptions LauncherOptions; @@ -74,7 +74,7 @@ public: { LauncherOptions.LauncherRelativeUrl.Append(MoveTemp(Payload)); } - return DesktopPlatform->OpenLauncher(LauncherOptions); + return LauncherPlatform->OpenLauncher(LauncherOptions); } return false; } diff --git a/Engine/Source/Runtime/Portal/LauncherPlatform/LauncherPlatform.Build.cs b/Engine/Source/Runtime/Portal/LauncherPlatform/LauncherPlatform.Build.cs new file mode 100644 index 000000000000..e8ae1017a2eb --- /dev/null +++ b/Engine/Source/Runtime/Portal/LauncherPlatform/LauncherPlatform.Build.cs @@ -0,0 +1,22 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +using UnrealBuildTool; + +public class LauncherPlatform : ModuleRules +{ + public LauncherPlatform(ReadOnlyTargetRules Target) : base(Target) + { + PrivateIncludePaths.Add("Runtime/Portal/LauncherPlatform/Private"); + + PrivateDependencyModuleNames.AddRange( + new string[] { + "Core", + } + ); + + if (Target.Platform != UnrealTargetPlatform.Linux && Target.Platform != UnrealTargetPlatform.Win32 && Target.Platform != UnrealTargetPlatform.Win64 && Target.Platform != UnrealTargetPlatform.Mac) + { + PrecompileForTargets = PrecompileTargetsType.None; + } + } +} diff --git a/Engine/Source/Runtime/Portal/LauncherPlatform/Private/LauncherPlatformModule.cpp b/Engine/Source/Runtime/Portal/LauncherPlatform/Private/LauncherPlatformModule.cpp new file mode 100644 index 000000000000..bffe3d7f939f --- /dev/null +++ b/Engine/Source/Runtime/Portal/LauncherPlatform/Private/LauncherPlatformModule.cpp @@ -0,0 +1,27 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "LauncherPlatformModule.h" +#if PLATFORM_WINDOWS +#include "Windows/LauncherPlatformWindows.h" +#elif PLATFORM_MAC +#include "Mac/LauncherPlatformMac.h" +#elif PLATFORM_LINUX +#include "Linux/LauncherPlatformLinux.h" +#endif + +IMPLEMENT_MODULE( FLauncherPlatformModule, LauncherPlatform ); +DEFINE_LOG_CATEGORY(LogLauncherPlatform); + +void FLauncherPlatformModule::StartupModule() +{ + LauncherPlatform = new FLauncherPlatform(); +} + +void FLauncherPlatformModule::ShutdownModule() +{ + if (LauncherPlatform != NULL) + { + delete LauncherPlatform; + LauncherPlatform = NULL; + } +} \ No newline at end of file diff --git a/Engine/Source/Runtime/Portal/LauncherPlatform/Private/LauncherPlatformPrivatePCH.h b/Engine/Source/Runtime/Portal/LauncherPlatform/Private/LauncherPlatformPrivatePCH.h new file mode 100644 index 000000000000..ecb99bc507b5 --- /dev/null +++ b/Engine/Source/Runtime/Portal/LauncherPlatform/Private/LauncherPlatformPrivatePCH.h @@ -0,0 +1,17 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" + +DECLARE_LOG_CATEGORY_EXTERN(LogLauncherPlatform, Log, All); + +#include "ILauncherPlatform.h" + +#if PLATFORM_WINDOWS +#include "Windows/LauncherPlatformWindows.h" +#elif PLATFORM_MAC +#include "Mac/LauncherPlatformMac.h" +#elif PLATFORM_LINUX +#include "Linux/LauncherPlatformLinux.h" +#endif diff --git a/Engine/Source/Runtime/Portal/LauncherPlatform/Private/Linux/LauncherPlatformLinux.cpp b/Engine/Source/Runtime/Portal/LauncherPlatform/Private/Linux/LauncherPlatformLinux.cpp new file mode 100644 index 000000000000..4f3b8d18d43e --- /dev/null +++ b/Engine/Source/Runtime/Portal/LauncherPlatform/Private/Linux/LauncherPlatformLinux.cpp @@ -0,0 +1,15 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "LauncherPlatformLinux.h" + +bool FLauncherPlatformLinux::CanOpenLauncher(bool Install) +{ + // TODO: no launcher support at the moment + return false; +} + +bool FLauncherPlatformLinux::OpenLauncher(const FOpenLauncherOptions& Options) +{ + // TODO: support launcher for realz + return true; +} diff --git a/Engine/Source/Runtime/Portal/LauncherPlatform/Private/Linux/LauncherPlatformLinux.h b/Engine/Source/Runtime/Portal/LauncherPlatform/Private/Linux/LauncherPlatformLinux.h new file mode 100644 index 000000000000..985bea0e7c58 --- /dev/null +++ b/Engine/Source/Runtime/Portal/LauncherPlatform/Private/Linux/LauncherPlatformLinux.h @@ -0,0 +1,16 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "ILauncherPlatform.h" + +class FLauncherPlatformLinux : public ILauncherPlatform +{ +public: + // ILauncherPlatform Implementation + virtual bool CanOpenLauncher(bool Install) override; + virtual bool OpenLauncher(const FOpenLauncherOptions& Options) override; +}; + +typedef FLauncherPlatformLinux FLauncherPlatform; diff --git a/Engine/Source/Runtime/Portal/LauncherPlatform/Private/Mac/LauncherPlatformMac.cpp b/Engine/Source/Runtime/Portal/LauncherPlatform/Private/Mac/LauncherPlatformMac.cpp new file mode 100644 index 000000000000..00732676d28b --- /dev/null +++ b/Engine/Source/Runtime/Portal/LauncherPlatform/Private/Mac/LauncherPlatformMac.cpp @@ -0,0 +1,90 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "LauncherPlatformMac.h" +#include "MacPlatformProcess.h" +#include "Paths.h" + +bool FLauncherPlatformMac::CanOpenLauncher(bool Install) +{ + FString Path; + return IsLauncherInstalled() || (Install && GetLauncherInstallerPath(Path)); +} + +bool FLauncherPlatformMac::OpenLauncher(const FOpenLauncherOptions& Options) +{ + FString LauncherUriRequest = Options.GetLauncherUriRequest(); + + // If the launcher is already running, bring it to front + NSArray* RunningLaunchers = [NSRunningApplication runningApplicationsWithBundleIdentifier: @"com.epicgames.EpicGamesLauncher"]; + if ([RunningLaunchers count] == 0) + { + RunningLaunchers = [NSRunningApplication runningApplicationsWithBundleIdentifier: @"com.epicgames.UnrealEngineLauncher"]; + } + + if ([RunningLaunchers count] > 0) + { + NSRunningApplication* Launcher = [RunningLaunchers objectAtIndex: 0]; + if ( !Launcher.hidden || Options.bInstall ) // If the launcher is running, but hidden, don't activate on editor startup + { + [Launcher activateWithOptions : NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps]; + FString Error; + FPlatformProcess::LaunchURL(*LauncherUriRequest, nullptr, &Error); + } + return true; + } + + if (IsLauncherInstalled()) + { + FString Error; + FPlatformProcess::LaunchURL(*LauncherUriRequest, nullptr, &Error); + return true; + } + + // Try to install it + FString InstallerPath; + if (GetLauncherInstallerPath(InstallerPath)) + { + FPlatformProcess::LaunchFileInDefaultExternalApplication(*InstallerPath); + return true; + } + + return false; +} + +bool FLauncherPlatformMac::IsLauncherInstalled() const +{ + // Otherwise search for it... + NSWorkspace* Workspace = [NSWorkspace sharedWorkspace]; + NSString* Path = [Workspace fullPathForApplication:@"Epic Games Launcher"]; + if( Path ) + { + return true; + } + + // Otherwise search for the old Launcher... + Path = [Workspace fullPathForApplication:@"Unreal Engine"]; + if( Path ) + { + return true; + } + + return false; +} + +bool FLauncherPlatformMac::GetLauncherInstallerPath(FString& OutInstallerPath) const +{ + // Check if the installer exists + FString InstallerPath = FPaths::ConvertRelativePathToFull(FPaths::Combine(*FPaths::EngineDir(), TEXT("Extras/UnrealEngineLauncher/EpicGamesLauncher.dmg"))); + if (FPaths::FileExists(InstallerPath)) + { + OutInstallerPath = InstallerPath; + return true; + } + InstallerPath = FPaths::ConvertRelativePathToFull(FPaths::Combine(*FPaths::EngineDir(), TEXT("Extras/UnrealEngineLauncher/UnrealEngine.dmg"))); + if (FPaths::FileExists(InstallerPath)) + { + OutInstallerPath = InstallerPath; + return true; + } + return false; +} diff --git a/Engine/Source/Runtime/Portal/LauncherPlatform/Private/Mac/LauncherPlatformMac.h b/Engine/Source/Runtime/Portal/LauncherPlatform/Private/Mac/LauncherPlatformMac.h new file mode 100644 index 000000000000..9c8ec04a4117 --- /dev/null +++ b/Engine/Source/Runtime/Portal/LauncherPlatform/Private/Mac/LauncherPlatformMac.h @@ -0,0 +1,20 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "ILauncherPlatform.h" + +class FLauncherPlatformMac : public ILauncherPlatform +{ +public: + // ILauncherPlatform Implementation + virtual bool CanOpenLauncher(bool Install) override; + virtual bool OpenLauncher(const FOpenLauncherOptions& Options) override; + +private: + bool IsLauncherInstalled() const; + bool GetLauncherInstallerPath(FString& OutInstallerPath) const; +}; + +typedef FLauncherPlatformMac FLauncherPlatform; diff --git a/Engine/Source/Runtime/Portal/LauncherPlatform/Private/Windows/LauncherPlatformWindows.cpp b/Engine/Source/Runtime/Portal/LauncherPlatform/Private/Windows/LauncherPlatformWindows.cpp new file mode 100644 index 000000000000..c006d2b29d87 --- /dev/null +++ b/Engine/Source/Runtime/Portal/LauncherPlatform/Private/Windows/LauncherPlatformWindows.cpp @@ -0,0 +1,61 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "LauncherPlatformWindows.h" +#include "WindowsPlatformProcess.h" +#include "WindowsHWrapper.h" +#include "Paths.h" + +bool FLauncherPlatformWindows::CanOpenLauncher(bool Install) +{ + // Check if the launcher exists, or (optionally) if the installer exists + FString Path; + return IsLauncherInstalled() || (Install && GetLauncherInstallerPath(Path)); +} + +bool FLauncherPlatformWindows::OpenLauncher(const FOpenLauncherOptions& Options) +{ + // Try to launch it directly + FString InstallerPath; + if (IsLauncherInstalled()) + { + FString LauncherUriRequest = Options.GetLauncherUriRequest(); + + FString Error; + FPlatformProcess::LaunchURL(*LauncherUriRequest, nullptr, &Error); + return true; + } + // Otherwise see if we can install it + else if(Options.bInstall && GetLauncherInstallerPath(InstallerPath)) + { + FPlatformProcess::LaunchFileInDefaultExternalApplication(*InstallerPath); + return true; + } + + return false; +} + +bool FLauncherPlatformWindows::IsLauncherInstalled() const +{ + bool bRes = false; + + HKEY hKey; + if (RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("com.epicgames.launcher"), 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + RegCloseKey(hKey); + bRes = true; + } + + return bRes; +} + +bool FLauncherPlatformWindows::GetLauncherInstallerPath(FString& OutInstallerPath) +{ + FString InstallerPath = FPaths::ConvertRelativePathToFull(FPaths::Combine(*FPaths::EngineDir(), TEXT("Extras/UnrealEngineLauncher/EpicGamesLauncherInstaller.msi"))); + if (FPaths::FileExists(InstallerPath)) + { + OutInstallerPath = InstallerPath; + return true; + } + + return false; +} diff --git a/Engine/Source/Runtime/Portal/LauncherPlatform/Private/Windows/LauncherPlatformWindows.h b/Engine/Source/Runtime/Portal/LauncherPlatform/Private/Windows/LauncherPlatformWindows.h new file mode 100644 index 000000000000..5c072d3c2649 --- /dev/null +++ b/Engine/Source/Runtime/Portal/LauncherPlatform/Private/Windows/LauncherPlatformWindows.h @@ -0,0 +1,20 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "ILauncherPlatform.h" + +class FLauncherPlatformWindows : public ILauncherPlatform +{ +public: + // ILauncherPlatform Implementation + virtual bool CanOpenLauncher(bool Install) override; + virtual bool OpenLauncher(const FOpenLauncherOptions& Options) override; + +private: + bool IsLauncherInstalled() const; + bool GetLauncherInstallerPath(FString& OutInstallerPath); +}; + +typedef FLauncherPlatformWindows FLauncherPlatform; diff --git a/Engine/Source/Runtime/Portal/LauncherPlatform/Public/ILauncherPlatform.h b/Engine/Source/Runtime/Portal/LauncherPlatform/Public/ILauncherPlatform.h new file mode 100644 index 000000000000..c66dceda715b --- /dev/null +++ b/Engine/Source/Runtime/Portal/LauncherPlatform/Public/ILauncherPlatform.h @@ -0,0 +1,96 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +class FOpenLauncherOptions +{ +public: + FOpenLauncherOptions() + : bInstall(false) + , bSilent(true) + , LauncherRelativeUrl() + { + } + + FOpenLauncherOptions(FString InLauncherRelativeUrl) + : bInstall(false) + , bSilent(true) + , LauncherRelativeUrl(InLauncherRelativeUrl) + { + if ( !LauncherRelativeUrl.IsEmpty() ) + { + bSilent = false; + } + } + + FOpenLauncherOptions(bool DoInstall, FString InLauncherRelativeUrl) + : bInstall(DoInstall) + , bSilent(true) + , LauncherRelativeUrl(InLauncherRelativeUrl) + { + if ( !LauncherRelativeUrl.IsEmpty() || bInstall ) + { + bSilent = false; + } + } + + FString GetLauncherUriRequest() const + { + FString LauncherUriRequest; + if ( LauncherRelativeUrl.IsEmpty() ) + { + LauncherUriRequest = TEXT("com.epicgames.launcher:"); + } + else + { + LauncherUriRequest = FString::Printf(TEXT("com.epicgames.launcher://%s"), *LauncherRelativeUrl); + } + + // Append silent query string arg. + if ( bSilent ) + { + if ( LauncherUriRequest.Contains("?") ) + { + LauncherUriRequest += TEXT("&silent=true"); + } + else + { + LauncherUriRequest += TEXT("?silent=true"); + } + } + + return LauncherUriRequest; + } + +public: + + bool bInstall; + bool bSilent; + FString LauncherRelativeUrl; +}; + + +class ILauncherPlatform +{ +public: + /** Virtual destructor */ + virtual ~ILauncherPlatform() {} + + /** + * Determines whether the launcher can be opened. + * + * @param Install Whether to include the possibility of installing the launcher in the check. + * @return true if the launcher can be opened (or installed). + */ + virtual bool CanOpenLauncher(bool Install) = 0; + + /** + * Opens the marketplace user interface. + * + * @param Install Whether to install the marketplace if it is missing. + * @param LauncherRelativeUrl A url relative to the launcher which you'd like the launcher to navigate to. Empty defaults to the UE homepage + * @param CommandLineParams Optional command to open the launcher with if it is not already open + * @return true if the marketplace was opened, false if it is not installed or could not be installed/opened. + */ + virtual bool OpenLauncher(const FOpenLauncherOptions& Options) = 0; +}; \ No newline at end of file diff --git a/Engine/Source/Runtime/Portal/LauncherPlatform/Public/LauncherPlatformModule.h b/Engine/Source/Runtime/Portal/LauncherPlatform/Public/LauncherPlatformModule.h new file mode 100644 index 000000000000..5f6670f6e394 --- /dev/null +++ b/Engine/Source/Runtime/Portal/LauncherPlatform/Public/LauncherPlatformModule.h @@ -0,0 +1,26 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "ModuleManager.h" +#include "ILauncherPlatform.h" + +DECLARE_LOG_CATEGORY_EXTERN(LogLauncherPlatform, Log, All); + +class FLauncherPlatformModule : public IModuleInterface +{ +public: + virtual void StartupModule(); + virtual void ShutdownModule(); + + static ILauncherPlatform* Get() + { + FLauncherPlatformModule& LauncherPlatformModule = FModuleManager::Get().LoadModuleChecked("LauncherPlatform"); + return LauncherPlatformModule.GetSingleton(); + } + +private: + virtual ILauncherPlatform* GetSingleton() const { return LauncherPlatform; } + + ILauncherPlatform* LauncherPlatform; +}; diff --git a/Engine/Source/Runtime/Portal/Rpc/Public/IPortalRpcLocator.h b/Engine/Source/Runtime/Portal/Rpc/Public/IPortalRpcLocator.h index 0c11d5422ea2..e003d197b1af 100644 --- a/Engine/Source/Runtime/Portal/Rpc/Public/IPortalRpcLocator.h +++ b/Engine/Source/Runtime/Portal/Rpc/Public/IPortalRpcLocator.h @@ -42,5 +42,5 @@ public: public: /** Virtual destructor. */ - ~IPortalRpcLocator() { } + virtual ~IPortalRpcLocator() { } }; diff --git a/Engine/Source/Runtime/Portal/Rpc/Public/IPortalRpcResponder.h b/Engine/Source/Runtime/Portal/Rpc/Public/IPortalRpcResponder.h index 2e974475bc8e..fa118f4fe2f0 100644 --- a/Engine/Source/Runtime/Portal/Rpc/Public/IPortalRpcResponder.h +++ b/Engine/Source/Runtime/Portal/Rpc/Public/IPortalRpcResponder.h @@ -21,5 +21,5 @@ public: public: /** Virtual destructor. */ - ~IPortalRpcResponder() { } + virtual ~IPortalRpcResponder() { } }; diff --git a/Engine/Source/Runtime/Portal/Rpc/Public/IPortalRpcServer.h b/Engine/Source/Runtime/Portal/Rpc/Public/IPortalRpcServer.h index ba2e65bad77a..8c384ee3d7c7 100644 --- a/Engine/Source/Runtime/Portal/Rpc/Public/IPortalRpcServer.h +++ b/Engine/Source/Runtime/Portal/Rpc/Public/IPortalRpcServer.h @@ -24,5 +24,5 @@ public: public: /** Virtual destructor. */ - ~IPortalRpcServer() { } + virtual ~IPortalRpcServer() { } }; diff --git a/Engine/Source/Runtime/Projects/Private/ModuleDescriptor.cpp b/Engine/Source/Runtime/Projects/Private/ModuleDescriptor.cpp index 2922c6ec2fbc..6626f0282932 100644 --- a/Engine/Source/Runtime/Projects/Private/ModuleDescriptor.cpp +++ b/Engine/Source/Runtime/Projects/Private/ModuleDescriptor.cpp @@ -172,6 +172,28 @@ bool FModuleDescriptor::Read(const FJsonObject& Object, FText& OutFailReason) } } + // Read the whitelisted targets + TSharedPtr WhitelistTargetsValue = Object.TryGetField(TEXT("WhitelistTargets")); + if (WhitelistTargetsValue.IsValid() && WhitelistTargetsValue->Type == EJson::Array) + { + const TArray< TSharedPtr< FJsonValue > >& TargetsArray = WhitelistTargetsValue->AsArray(); + for (int Idx = 0; Idx < TargetsArray.Num(); Idx++) + { + WhitelistTargets.Add(TargetsArray[Idx]->AsString()); + } + } + + // Read the blacklisted targets + TSharedPtr BlacklistTargetsValue = Object.TryGetField(TEXT("BlacklistTargets")); + if (BlacklistTargetsValue.IsValid() && BlacklistTargetsValue->Type == EJson::Array) + { + const TArray< TSharedPtr< FJsonValue > >& TargetsArray = BlacklistTargetsValue->AsArray(); + for (int Idx = 0; Idx < TargetsArray.Num(); Idx++) + { + BlacklistTargets.Add(TargetsArray[Idx]->AsString()); + } + } + // Read the additional dependencies TSharedPtr AdditionalDependenciesValue = Object.TryGetField(TEXT("AdditionalDependencies")); if (AdditionalDependenciesValue.IsValid() && AdditionalDependenciesValue->Type == EJson::Array) @@ -244,6 +266,24 @@ void FModuleDescriptor::Write(TJsonWriter<>& Writer) const } Writer.WriteArrayEnd(); } + if (WhitelistTargets.Num() > 0) + { + Writer.WriteArrayStart(TEXT("WhitelistTargets")); + for (int Idx = 0; Idx < WhitelistTargets.Num(); Idx++) + { + Writer.WriteValue(WhitelistTargets[Idx]); + } + Writer.WriteArrayEnd(); + } + if (BlacklistTargets.Num() > 0) + { + Writer.WriteArrayStart(TEXT("BlacklistTargets")); + for (int Idx = 0; Idx < BlacklistTargets.Num(); Idx++) + { + Writer.WriteValue(BlacklistTargets[Idx]); + } + Writer.WriteArrayEnd(); + } if (AdditionalDependencies.Num() > 0) { Writer.WriteArrayStart(TEXT("AdditionalDependencies")); @@ -286,6 +326,20 @@ bool FModuleDescriptor::IsCompiledInCurrentConfiguration() const return false; } + static FString UBTTarget(FPlatformMisc::GetUBTTarget()); + + // Check the target is whitelisted + if (WhitelistTargets.Num() > 0 && !WhitelistTargets.Contains(UBTTarget)) + { + return false; + } + + // Check the target is not blacklisted + if (BlacklistTargets.Num() > 0 && BlacklistTargets.Contains(UBTTarget)) + { + return false; + } + // Check the module is compatible with this target. This should match ModuleDescriptor.IsCompiledInConfiguration in UBT switch (Type) { diff --git a/Engine/Source/Runtime/Projects/Private/PluginDescriptor.cpp b/Engine/Source/Runtime/Projects/Private/PluginDescriptor.cpp index ce5bc65b1632..731450b24e51 100644 --- a/Engine/Source/Runtime/Projects/Private/PluginDescriptor.cpp +++ b/Engine/Source/Runtime/Projects/Private/PluginDescriptor.cpp @@ -12,13 +12,13 @@ FPluginDescriptor::FPluginDescriptor() : FileVersion(EPluginDescriptorVersion::Latest) , Version(0) - , CompatibleChangelist(0) , bEnabledByDefault(false) , bCanContainContent(false) , bIsBetaVersion(false) , bIsMod(false) , bInstalled(false) , bRequiresBuildPlatform(true) + , bIsHidden(false) { } @@ -98,7 +98,6 @@ bool FPluginDescriptor::Read(const FString& Text, bool bPluginTypeEnabledByDefau Object.TryGetStringField(TEXT("MarketplaceURL"), MarketplaceURL); Object.TryGetStringField(TEXT("SupportURL"), SupportURL); Object.TryGetStringField(TEXT("EngineVersion"), EngineVersion); - Object.TryGetNumberField(TEXT("CompatibleChangelist"), CompatibleChangelist); if (!FModuleDescriptor::ReadArray(Object, TEXT("Modules"), Modules, OutFailReason)) { @@ -124,10 +123,16 @@ bool FPluginDescriptor::Read(const FString& Text, bool bPluginTypeEnabledByDefau { bRequiresBuildPlatform = true; } + Object.TryGetBoolField(TEXT("Hidden"), bIsHidden); PreBuildSteps.Read(Object, TEXT("PreBuildSteps")); PostBuildSteps.Read(Object, TEXT("PostBuildSteps")); + if (!FPluginReferenceDescriptor::ReadArray(Object, TEXT("Plugins"), Plugins, OutFailReason)) + { + return false; + } + return true; } @@ -170,10 +175,6 @@ void FPluginDescriptor::Write(FString& Text, bool bPluginTypeEnabledByDefault) c { Writer.WriteValue(TEXT("EngineVersion"), EngineVersion); } - if (CompatibleChangelist != 0) - { - Writer.WriteValue(TEXT("CompatibleChangelist"), CompatibleChangelist); - } if(bEnabledByDefault != bPluginTypeEnabledByDefault) { Writer.WriteValue(TEXT("EnabledByDefault"), bEnabledByDefault); @@ -195,6 +196,11 @@ void FPluginDescriptor::Write(FString& Text, bool bPluginTypeEnabledByDefault) c Writer.WriteValue(TEXT("RequiresBuildPlatform"), bRequiresBuildPlatform); } + if (bIsHidden) + { + Writer.WriteValue(TEXT("Hidden"), bIsHidden); + } + if(!PreBuildSteps.IsEmpty()) { PreBuildSteps.Write(Writer, TEXT("PreBuildSteps")); @@ -205,216 +211,10 @@ void FPluginDescriptor::Write(FString& Text, bool bPluginTypeEnabledByDefault) c PostBuildSteps.Write(Writer, TEXT("PostBuildSteps")); } + FPluginReferenceDescriptor::WriteArray(Writer, TEXT("Plugins"), Plugins); + Writer.WriteObjectEnd(); Writer.Close(); } -////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -FPluginReferenceDescriptor::FPluginReferenceDescriptor( const FString& InName, bool bInEnabled, const FString& InMarketplaceURL ) - : Name(InName) - , bEnabled(bInEnabled) - , bOptional(false) - , MarketplaceURL(InMarketplaceURL) -{ } - - -bool FPluginReferenceDescriptor::IsEnabledForPlatform( const FString& Platform ) const -{ - // If it's not enabled at all, return false - if(!bEnabled) - { - return false; - } - - // If there is a list of whitelisted platforms, and this isn't one of them, return false - if(WhitelistPlatforms.Num() > 0 && !WhitelistPlatforms.Contains(Platform)) - { - return false; - } - - // If this platform is blacklisted, also return false - if(BlacklistPlatforms.Contains(Platform)) - { - return false; - } - - return true; -} - -bool FPluginReferenceDescriptor::IsEnabledForTarget(const FString& Target) const -{ - // If it's not enabled at all, return false - if (!bEnabled) - { - return false; - } - - // If there is a list of whitelisted platforms, and this isn't one of them, return false - if (WhitelistTargets.Num() > 0 && !WhitelistTargets.Contains(Target)) - { - return false; - } - - // If this platform is blacklisted, also return false - if (BlacklistTargets.Contains(Target)) - { - return false; - } - - return true; -} - -bool FPluginReferenceDescriptor::Read( const FJsonObject& Object, FText& OutFailReason ) -{ - // Get the name - if(!Object.TryGetStringField(TEXT("Name"), Name)) - { - OutFailReason = LOCTEXT("PluginReferenceWithoutName", "Plugin references must have a 'Name' field"); - return false; - } - - // Get the enabled field - if(!Object.TryGetBoolField(TEXT("Enabled"), bEnabled)) - { - OutFailReason = LOCTEXT("PluginReferenceWithoutEnabled", "Plugin references must have an 'Enabled' field"); - return false; - } - - // Read the optional field - Object.TryGetBoolField(TEXT("Optional"), bOptional); - - // Read the metadata for users that don't have the plugin installed - Object.TryGetStringField(TEXT("Description"), Description); - Object.TryGetStringField(TEXT("MarketplaceURL"), MarketplaceURL); - - // Get the platform lists - Object.TryGetStringArrayField(TEXT("WhitelistPlatforms"), WhitelistPlatforms); - Object.TryGetStringArrayField(TEXT("BlacklistPlatforms"), BlacklistPlatforms); - - // Get the target lists - Object.TryGetStringArrayField(TEXT("WhitelistTargets"), WhitelistTargets); - Object.TryGetStringArrayField(TEXT("BlacklistTargets"), BlacklistTargets); - - return true; -} - - -bool FPluginReferenceDescriptor::ReadArray( const FJsonObject& Object, const TCHAR* Name, TArray& OutPlugins, FText& OutFailReason ) -{ - const TArray< TSharedPtr > *Array; - - if (Object.TryGetArrayField(Name, Array)) - { - for (const TSharedPtr &Item : *Array) - { - const TSharedPtr *ObjectPtr; - - if (Item.IsValid() && Item->TryGetObject(ObjectPtr)) - { - FPluginReferenceDescriptor Plugin; - - if (!Plugin.Read(*ObjectPtr->Get(), OutFailReason)) - { - return false; - } - - OutPlugins.Add(Plugin); - } - } - } - - return true; -} - - -void FPluginReferenceDescriptor::Write( TJsonWriter<>& Writer ) const -{ - Writer.WriteObjectStart(); - Writer.WriteValue(TEXT("Name"), Name); - Writer.WriteValue(TEXT("Enabled"), bEnabled); - - if (bEnabled && bOptional) - { - Writer.WriteValue(TEXT("Optional"), bOptional); - } - - if (Description.Len() > 0) - { - Writer.WriteValue(TEXT("Description"), Description); - } - - if (MarketplaceURL.Len() > 0) - { - Writer.WriteValue(TEXT("MarketplaceURL"), MarketplaceURL); - } - - if (WhitelistPlatforms.Num() > 0) - { - Writer.WriteArrayStart(TEXT("WhitelistPlatforms")); - - for (int Idx = 0; Idx < WhitelistPlatforms.Num(); Idx++) - { - Writer.WriteValue(WhitelistPlatforms[Idx]); - } - - Writer.WriteArrayEnd(); - } - - if (BlacklistPlatforms.Num() > 0) - { - Writer.WriteArrayStart(TEXT("BlacklistPlatforms")); - - for (int Idx = 0; Idx < BlacklistPlatforms.Num(); Idx++) - { - Writer.WriteValue(BlacklistPlatforms[Idx]); - } - - Writer.WriteArrayEnd(); - } - - if (WhitelistTargets.Num() > 0) - { - Writer.WriteArrayStart(TEXT("WhitelistTargets")); - - for (int Idx = 0; Idx < WhitelistTargets.Num(); Idx++) - { - Writer.WriteValue(WhitelistTargets[Idx]); - } - - Writer.WriteArrayEnd(); - } - - if (BlacklistTargets.Num() > 0) - { - Writer.WriteArrayStart(TEXT("BlacklistTargets")); - - for (int Idx = 0; Idx < BlacklistTargets.Num(); Idx++) - { - Writer.WriteValue(BlacklistTargets[Idx]); - } - - Writer.WriteArrayEnd(); - } - - Writer.WriteObjectEnd(); -} - - -void FPluginReferenceDescriptor::WriteArray( TJsonWriter<>& Writer, const TCHAR* Name, const TArray& Plugins ) -{ - if( Plugins.Num() > 0) - { - Writer.WriteArrayStart(Name); - - for (int Idx = 0; Idx < Plugins.Num(); Idx++) - { - Plugins[Idx].Write(Writer); - } - - Writer.WriteArrayEnd(); - } -} - - #undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Runtime/Projects/Private/PluginManager.cpp b/Engine/Source/Runtime/Projects/Private/PluginManager.cpp index 41470e0585f9..c4ac2bbf9630 100644 --- a/Engine/Source/Runtime/Projects/Private/PluginManager.cpp +++ b/Engine/Source/Runtime/Projects/Private/PluginManager.cpp @@ -120,6 +120,11 @@ bool FPlugin::IsEnabled() const return bEnabled; } +bool FPlugin::IsHidden() const +{ + return Descriptor.bIsHidden; +} + bool FPlugin::CanContainContent() const { return Descriptor.bCanContainContent; @@ -225,6 +230,12 @@ void FPluginManager::ReadAllPlugins(TMap>& Plugins, { ReadPluginsInDirectory(Dir, EPluginLoadedFrom::Engine, Plugins); } + + // For enterprise projects, add plugins in EnterprisePluginsDir + if (Project->bIsEnterpriseProject) + { + ReadPluginsInDirectory(FPaths::EnterprisePluginsDir(), EPluginLoadedFrom::Engine, Plugins); + } } for (const FString& ExtraSearchPath : ExtraSearchPaths) @@ -350,35 +361,6 @@ public: } }; -bool FPluginManager::IsPluginSupportedByCurrentTarget(TSharedRef Plugin) const -{ - bool bSupported = false; - if (Plugin->GetDescriptor().Modules.Num()) - { - for (const FModuleDescriptor& Module : Plugin->GetDescriptor().Modules) - { - // Programs support only program type plugins - // Non-program targets don't support from plugins -#if IS_PROGRAM - if (Module.Type == EHostType::Program) - { - bSupported = true; - } -#else - if (Module.Type != EHostType::Program) - { - bSupported = true; - } -#endif - } - } - else - { - bSupported = true; - } - return bSupported; -} - bool FPluginManager::ConfigureEnabledPlugins() { if(!bHaveConfiguredEnabledPlugins) @@ -386,138 +368,55 @@ bool FPluginManager::ConfigureEnabledPlugins() // Don't need to run this again bHaveConfiguredEnabledPlugins = true; - // If a current project is set, check that we know about any plugin that's explicitly enabled - const FProjectDescriptor *Project = IProjectManager::Get().GetCurrentProject(); - const bool bHasProjectFile = Project != nullptr; - // Get all the enabled plugin names - TArray< FString > EnabledPluginNames; + TArray InitialPluginNames; + TMap NameToPluginReference; #if IS_PROGRAM // Programs can also define the list of enabled plugins in ini - GConfig->GetArray(TEXT("Plugins"), TEXT("ProgramEnabledPlugins"), EnabledPluginNames, GEngineIni); + GConfig->GetArray(TEXT("Plugins"), TEXT("ProgramEnabledPlugins"), InitialPluginNames, GEngineIni); #endif #if !IS_PROGRAM || HACK_HEADER_GENERATOR if (!FParse::Param(FCommandLine::Get(), TEXT("NoEnginePlugins"))) { - FProjectManager::Get().GetEnabledPlugins(EnabledPluginNames); - } -#endif - - // Build a set from the array - TSet< FString > AllEnabledPlugins; - AllEnabledPlugins.Append(MoveTemp(EnabledPluginNames)); - - // Enable all the plugins by name - for (const TPair> PluginPair : AllPlugins) - { - const TSharedRef& Plugin = PluginPair.Value; - if (AllEnabledPlugins.Contains(Plugin->Name)) + // Find all the plugin references in the project file + const FProjectDescriptor* ProjectDescriptor = IProjectManager::Get().GetCurrentProject(); + if (ProjectDescriptor != nullptr) { -#if IS_PROGRAM - Plugin->bEnabled = !bHasProjectFile || IsPluginSupportedByCurrentTarget(Plugin); - if (!Plugin->bEnabled) + for (const FPluginReferenceDescriptor& PluginReference : ProjectDescriptor->Plugins) { - AllEnabledPlugins.Remove(Plugin->Name); + NameToPluginReference.FindOrAdd(PluginReference.Name) = &PluginReference; } -#else - Plugin->bEnabled = true; -#endif + } - if (Plugin->bEnabled && FPlatformMisc::ShouldDisablePluginAtRuntime(Plugin->Name)) + // Get the default list of plugin names + for (const TPair>& PluginPair : AllPlugins) + { + const FPluginReferenceDescriptor* PluginReference = NameToPluginReference.FindRef(PluginPair.Key); + if ((PluginReference == nullptr && PluginPair.Value->Descriptor.bEnabledByDefault) || (PluginReference != nullptr && PluginReference->bEnabled)) { - Plugin->bEnabled = false; - AllEnabledPlugins.Remove(Plugin->Name); - } - - if (Plugin->bEnabled && Plugin->Descriptor.EngineVersion.Len() > 0) - { - FEngineVersion Version; - if (!FEngineVersion::Parse(Plugin->Descriptor.EngineVersion, Version)) - { - UE_LOG(LogPluginManager, Warning, TEXT("Engine version string in %s could not be parsed (\"%s\")"), *Plugin->FileName, *Plugin->Descriptor.EngineVersion); - } - else - { - EVersionComparison Comparison = FEngineVersion::GetNewest(FEngineVersion::CompatibleWith(), Version, nullptr); - if (Comparison != EVersionComparison::Neither) - { - FText Title = LOCTEXT("IncompatiblePluginTitle", "Incompatible Plugin"); - if (FMessageDialog::Open(EAppMsgType::YesNo, FText::Format(LOCTEXT("IncompatiblePluginMessage", "The '{0}' plugin was designed for a different version of the engine. Attempt to load it anyway?"), FText::FromString(Plugin->Descriptor.FriendlyName)), &Title) != EAppReturnType::Yes) - { - Plugin->bEnabled = false; - AllEnabledPlugins.Remove(Plugin->Name); - UE_LOG(LogPluginManager, Log, TEXT("Disabled plugin '%s' due to incompatibility"), *Plugin->FileName); - } - else - { - UE_LOG(LogPluginManager, Log, TEXT("Enabled plugin '%s' despite being built for CL %d"), *Plugin->FileName, Plugin->Descriptor.CompatibleChangelist); - } - } - } - } - else if (Plugin->bEnabled && Plugin->Descriptor.CompatibleChangelist != 0 && FEngineVersion::CompatibleWith().HasChangelist() && Plugin->Descriptor.CompatibleChangelist != FEngineVersion::CompatibleWith().GetChangelist()) - { - FText Title = LOCTEXT("IncompatiblePluginTitle", "Incompatible Plugin"); - if (FMessageDialog::Open(EAppMsgType::YesNo, FText::Format(LOCTEXT("IncompatiblePluginMessage", "'{0}' was designed for a different version of the game. Attempt to load it anyway?"), FText::FromString(Plugin->Descriptor.FriendlyName)), &Title) != EAppReturnType::Yes) - { - Plugin->bEnabled = false; - AllEnabledPlugins.Remove(Plugin->Name); - UE_LOG(LogPluginManager, Log, TEXT("Disabled plugin '%s' due to incompatibility"), *Plugin->FileName); - } - else - { - UE_LOG(LogPluginManager, Log, TEXT("Enabled plugin '%s' despite being built for CL %d"), *Plugin->FileName, Plugin->Descriptor.CompatibleChangelist); - } + InitialPluginNames.Add(PluginPair.Key); } } } - - if (bHasProjectFile) - { - // Take a copy of the Project's plugins as we may remove some - TArray PluginsCopy = Project->Plugins; - for(const FPluginReferenceDescriptor& Plugin: PluginsCopy) - { - bool bShouldBeEnabled = Plugin.bEnabled && Plugin.IsEnabledForPlatform(FPlatformMisc::GetUBTPlatform()) && Plugin.IsEnabledForTarget(FPlatformMisc::GetUBTTarget()); - if (bShouldBeEnabled && !FindPluginInstance(Plugin.Name).IsValid() && !Plugin.bOptional -#if IS_PROGRAM - && AllEnabledPlugins.Contains(Plugin.Name) // skip if this is a program and the plugin is not enabled #endif - ) + + // Enable all the plugins + TSet EnabledPluginNames; + for (const FString& PluginName : InitialPluginNames) + { + const FPluginReferenceDescriptor* EnabledPluginReference = NameToPluginReference.FindRef(PluginName); + if (EnabledPluginReference == nullptr) + { + if (!ConfigureEnabledPlugin(FPluginReferenceDescriptor(PluginName, true), EnabledPluginNames)) { - if (FApp::IsUnattended()) - { - UE_LOG(LogPluginManager, Error, TEXT("This project requires the '%s' plugin. Install it and try again, or remove it from the project's required plugin list."), *Plugin.Name); - return false; - } - - FText Caption(LOCTEXT("PluginMissingCaption", "Plugin missing")); - if(Plugin.MarketplaceURL.Len() > 0) - { - if(FMessageDialog::Open(EAppMsgType::YesNo, FText::Format(LOCTEXT("PluginMissingError", "This project requires the {0} plugin.\n\nWould you like to download it from the the Marketplace?"), FText::FromString(Plugin.Name)), &Caption) == EAppReturnType::Yes) - { - FString Error; - FPlatformProcess::LaunchURL(*Plugin.MarketplaceURL, nullptr, &Error); - if(Error.Len() > 0) FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(Error)); - return false; - } - } - else - { - FString Description = (Plugin.Description.Len() > 0) ? FString::Printf(TEXT("\n\n%s"), *Plugin.Description) : FString(); - FMessageDialog::Open(EAppMsgType::Ok, FText::Format(LOCTEXT("PluginRequiredError", "This project requires the {0} plugin. {1}"), FText::FromString(Plugin.Name), FText::FromString(Description)), &Caption); - - if (FMessageDialog::Open(EAppMsgType::YesNo, FText::Format(LOCTEXT("PluginMissingDisable", "Would you like to disable {0}? You will no longer be able to open any assets created using it."), FText::FromString(Plugin.Name)), &Caption) == EAppReturnType::No) - { - return false; - } - - FText FailReason; - if (!IProjectManager::Get().SetPluginEnabled(*Plugin.Name, false, FailReason)) - { - FMessageDialog::Open(EAppMsgType::Ok, FailReason); - } - } + return false; + } + } + else + { + if (!ConfigureEnabledPlugin(*EnabledPluginReference, EnabledPluginNames)) + { + return false; } } } @@ -525,58 +424,42 @@ bool FPluginManager::ConfigureEnabledPlugins() // If we made it here, we have all the required plugins bHaveAllRequiredPlugins = true; + // Mount all the enabled plugins for(const TPair>& PluginPair: AllPlugins) { - const TSharedRef& Plugin = PluginPair.Value; - if (Plugin->bEnabled) + const FPlugin& Plugin = *PluginPair.Value; + if (Plugin.bEnabled) { - // Add the plugin binaries directory - const FString PluginBinariesPath = FPaths::Combine(*FPaths::GetPath(Plugin->FileName), TEXT("Binaries"), FPlatformProcess::GetBinariesSubdirectory()); - FModuleManager::Get().AddBinariesDirectory(*PluginBinariesPath, Plugin->LoadedFrom == EPluginLoadedFrom::GameProject); - -#if !IS_MONOLITHIC - // Only check this when in a non-monolithic build where modules could be in separate binaries - if (Project != NULL && Project->Modules.Num() == 0) + // Plugins can have their own shaders + // Add potential plugin shader directory only if the plugin is loaded in PostConfigInit. Not supported otherwise + for (const FModuleDescriptor& Module : Plugin.GetDescriptor().Modules) { - // Content only project - check whether any plugins are incompatible and offer to disable instead of trying to build them later - TArray IncompatibleFiles; - if (!FModuleDescriptor::CheckModuleCompatibility(Plugin->Descriptor.Modules, Plugin->LoadedFrom == EPluginLoadedFrom::GameProject, IncompatibleFiles)) + if (Module.LoadingPhase == ELoadingPhase::PostConfigInit) { - // Ask whether to disable plugin if incompatible - FText Caption(LOCTEXT("IncompatiblePluginCaption", "Plugin missing or incompatible")); - if (FMessageDialog::Open(EAppMsgType::YesNo, FText::Format(LOCTEXT("IncompatiblePluginText", "Missing or incompatible modules in {0} plugin - would you like to disable it? You will no longer be able to open any assets created using it."), FText::FromString(Plugin->Name)), &Caption) == EAppReturnType::No) - { - return false; - } - - FText FailReason; - if (!IProjectManager::Get().SetPluginEnabled(*Plugin->Name, false, FailReason)) - { - FMessageDialog::Open(EAppMsgType::Ok, FailReason); - } + FGenericPlatformProcess::AddShaderDir(FPaths::Combine(*Plugin.GetBaseDir(), TEXT("Shaders"))); + break; } } -#endif //!IS_MONOLITHIC - // Build the list of content folders - if (Plugin->Descriptor.bCanContainContent) + // Build the list of content folders + if (Plugin.Descriptor.bCanContainContent) { if (FConfigFile* EngineConfigFile = GConfig->Find(GEngineIni, false)) { if (FConfigSection* CoreSystemSection = EngineConfigFile->Find(TEXT("Core.System"))) { - CoreSystemSection->AddUnique("Paths", Plugin->GetContentDir()); + CoreSystemSection->AddUnique("Paths", Plugin.GetContentDir()); } } } // Load .ini config file if it exists - FString PluginConfigDir = FPaths::GetPath(Plugin->FileName) / TEXT("Config/"); + FString PluginConfigDir = FPaths::GetPath(Plugin.FileName) / TEXT("Config/"); FString EngineConfigDir = FPaths::EngineConfigDir(); FString SourceConfigDir = FPaths::SourceConfigDir(); // Load Engine plugins out of BasePluginName.ini and the engine directory, game plugins out of DefaultPluginName.ini - if (Plugin->LoadedFrom == EPluginLoadedFrom::Engine) + if (Plugin.LoadedFrom == EPluginLoadedFrom::Engine) { EngineConfigDir = PluginConfigDir; } @@ -585,11 +468,11 @@ bool FPluginManager::ConfigureEnabledPlugins() SourceConfigDir = PluginConfigDir; } - FString PluginConfigFilename = FString::Printf(TEXT("%s%s/%s.ini"), *FPaths::GeneratedConfigDir(), ANSI_TO_TCHAR(FPlatformProperties::PlatformName()), *Plugin->Name); + FString PluginConfigFilename = FString::Printf(TEXT("%s%s/%s.ini"), *FPaths::GeneratedConfigDir(), ANSI_TO_TCHAR(FPlatformProperties::PlatformName()), *Plugin.Name); FConfigFile& PluginConfig = GConfig->Add(PluginConfigFilename, FConfigFile()); // This will write out an ini to PluginConfigFilename - if (!FConfigCacheIni::LoadExternalIniFile(PluginConfig, *Plugin->Name, *EngineConfigDir, *SourceConfigDir, true, nullptr, false, true)) + if (!FConfigCacheIni::LoadExternalIniFile(PluginConfig, *Plugin.Name, *EngineConfigDir, *SourceConfigDir, true, nullptr, false, true)) { // Nothing to add, remove from map GConfig->Remove(PluginConfigFilename); @@ -617,7 +500,6 @@ bool FPluginManager::ConfigureEnabledPlugins() } } } - } } @@ -656,6 +538,237 @@ bool FPluginManager::ConfigureEnabledPlugins() return bHaveAllRequiredPlugins; } +bool FPluginManager::ConfigureEnabledPlugin(const FPluginReferenceDescriptor& FirstReference, TSet& EnabledPluginNames) +{ + if (!EnabledPluginNames.Contains(FirstReference.Name)) + { + // Set of plugin names we've added to the queue for processing + TSet NewPluginNames; + NewPluginNames.Add(FirstReference.Name); + + // Queue of plugin references to consider + TArray NewPluginReferences; + NewPluginReferences.Add(&FirstReference); + + // Loop through the queue of plugin references that need to be enabled, queuing more items as we go + TArray> NewPlugins; + for (int32 Idx = 0; Idx < NewPluginReferences.Num(); Idx++) + { + const FPluginReferenceDescriptor& Reference = *NewPluginReferences[Idx]; + + // Check if the plugin is required for this platform + if(!Reference.IsEnabledForPlatform(FPlatformMisc::GetUBTPlatform()) || !Reference.IsEnabledForTarget(FPlatformMisc::GetUBTTarget())) + { + UE_LOG(LogPluginManager, Verbose, TEXT("Ignoring plugin '%s' for platform/configuration"), *Reference.Name); + continue; + } + + // Find the plugin being enabled + TSharedRef* PluginPtr = AllPlugins.Find(Reference.Name); + if (PluginPtr == nullptr) + { + // Ignore any optional plugins + if (Reference.bOptional) + { + UE_LOG(LogPluginManager, Verbose, TEXT("Ignored optional reference to '%s' plugin; plugin was not found."), *Reference.Name); + continue; + } + + // If we're in unattended mode, don't open any windows + if (FApp::IsUnattended()) + { + UE_LOG(LogPluginManager, Error, TEXT("This project requires the '%s' plugin. Install it and try again, or remove it from the project's required plugin list."), *Reference.Name); + return false; + } + +#if !IS_MONOLITHIC + // Try to download it from the marketplace + if (Reference.MarketplaceURL.Len() > 0 && PromptToDownloadPlugin(Reference.Name, Reference.MarketplaceURL)) + { + UE_LOG(LogPluginManager, Display, TEXT("Downloading '%s' plugin from marketplace (%s)."), *Reference.Name, *Reference.MarketplaceURL); + return false; + } + + // Prompt to disable it in the project file, if possible + if (PromptToDisableMissingPlugin(FirstReference.Name, Reference.Name)) + { + UE_LOG(LogPluginManager, Display, TEXT("Disabled plugin '%s', continuing."), *FirstReference.Name); + return true; + } +#endif + + // Unable to continue + UE_LOG(LogPluginManager, Error, TEXT("Unable to load plugin '%s'. Aborting."), *Reference.Name); + return false; + } + + // Check the plugin is not disabled by the platform + FPlugin& Plugin = PluginPtr->Get(); + + // Allow the platform to disable it + if (FPlatformMisc::ShouldDisablePluginAtRuntime(Plugin.Name)) + { + UE_LOG(LogPluginManager, Verbose, TEXT("Plugin '%s' was disabled by platform."), *Reference.Name); + continue; + } + +#if !IS_MONOLITHIC + // Mount the binaries directory, and check the modules are valid + if (Plugin.Descriptor.Modules.Num() > 0) + { + // Mount the binaries directory + const FString PluginBinariesPath = FPaths::Combine(*FPaths::GetPath(Plugin.FileName), TEXT("Binaries"), FPlatformProcess::GetBinariesSubdirectory()); + FModuleManager::Get().AddBinariesDirectory(*PluginBinariesPath, Plugin.LoadedFrom == EPluginLoadedFrom::GameProject); + + // Check if the modules are valid + TArray IncompatibleFiles; + if (!FModuleDescriptor::CheckModuleCompatibility(Plugin.Descriptor.Modules, Plugin.LoadedFrom == EPluginLoadedFrom::GameProject, IncompatibleFiles)) + { + if (PromptToDisableIncompatiblePlugin(FirstReference.Name, Reference.Name)) + { + UE_LOG(LogPluginManager, Display, TEXT("Disabled plugin '%s', continuing."), *FirstReference.Name); + return true; + } + } + } + + // Check the declared engine version. This is a soft requirement, so allow the user to skip over it. + if (!IsPluginCompatible(Plugin) && !PromptToLoadIncompatiblePlugin(Plugin, FirstReference.Name)) + { + UE_LOG(LogPluginManager, Display, TEXT("Skipping load of '%s'."), *Plugin.Name); + return true; + } +#endif + + // Add references to all its dependencies + for (const FPluginReferenceDescriptor& NextReference : Plugin.Descriptor.Plugins) + { + if (!EnabledPluginNames.Contains(NextReference.Name) && !NewPluginNames.Contains(NextReference.Name)) + { + NewPluginNames.Add(NextReference.Name); + NewPluginReferences.Add(&NextReference); + } + } + + // Add the plugin + NewPlugins.Add(*PluginPtr); + } + + // Mark all the plugins as enabled + for (TSharedRef& NewPlugin : NewPlugins) + { + NewPlugin->bEnabled = true; + EnabledPluginNames.Add(NewPlugin->Name); + } + } + return true; +} + +bool FPluginManager::PromptToDownloadPlugin(const FString& PluginName, const FString& MarketplaceURL) +{ + FText Caption = FText::Format(LOCTEXT("DownloadPluginCaption", "Missing {0} Plugin"), FText::FromString(PluginName)); + FText Message = FText::Format(LOCTEXT("DownloadPluginMessage", "This project requires the {0} plugin.\n\nWould you like to download it from the Unreal Engine Marketplace?"), FText::FromString(PluginName)); + if(FMessageDialog::Open(EAppMsgType::YesNo, Message, &Caption) == EAppReturnType::Yes) + { + FString Error; + FPlatformProcess::LaunchURL(*MarketplaceURL, nullptr, &Error); + if (Error.Len() == 0) + { + return true; + } + FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(Error)); + } + return false; +} + +bool FPluginManager::PromptToDisableMissingPlugin(const FString& PluginName, const FString& MissingPluginName) +{ + FText Message; + if (PluginName == MissingPluginName) + { + Message = FText::Format(LOCTEXT("DisablePluginMessage_NotFound", "This project requires the '{0}' plugin, which could not be found.\n\nWould you like to disable it? You will no longer be able to open any assets created using it."), FText::FromString(PluginName)); + } + else + { + Message = FText::Format(LOCTEXT("DisablePluginMessage_MissingDependency", "This project requires the '{0}' plugin, which has a missing dependency on the '{1}' plugin.\n\nWould you like to disable it? You will no longer be able to open any assets created using it."), FText::FromString(PluginName), FText::FromString(MissingPluginName)); + } + + FText Caption(LOCTEXT("DisablePluginCaption", "Missing Plugin")); + return PromptToDisablePlugin(Caption, Message, PluginName); +} + +bool FPluginManager::PromptToDisableIncompatiblePlugin(const FString& PluginName, const FString& IncompatiblePluginName) +{ + FText Message; + if (PluginName == IncompatiblePluginName) + { + Message = FText::Format(LOCTEXT("DisablePluginMessage_IncompatibleEngineVersion", "This project requires the '{0}' plugin, which is not compatible with the current engine version.\n\nWould you like to disable it? You will no longer be able to open any assets created using it."), FText::FromString(PluginName)); + } + else + { + Message = FText::Format(LOCTEXT("DisablePluginMessage_IncompatibleDependency", "This project requires the '{0}' plugin, which has a dependency on the '{1}' plugin, which is not compatible with the current engine version.\n\nWould you like to disable it? You will no longer be able to open any assets created using it."), FText::FromString(PluginName), FText::FromString(IncompatiblePluginName)); + } + + FText Caption(LOCTEXT("DisablePluginCaption", "Missing Plugin")); + return PromptToDisablePlugin(Caption, Message, PluginName); +} + +bool FPluginManager::PromptToDisablePlugin(const FText& Caption, const FText& Message, const FString& PluginName) +{ + // Check we have a project file. If this is a missing engine/program plugin referenced by something, we can't disable it through this method. + if (IProjectManager::Get().GetCurrentProject() != nullptr) + { + if (FMessageDialog::Open(EAppMsgType::YesNo, Message, &Caption) == EAppReturnType::Yes) + { + FText FailReason; + if (IProjectManager::Get().SetPluginEnabled(*PluginName, false, FailReason)) + { + return true; + } + FMessageDialog::Open(EAppMsgType::Ok, FailReason); + } + } + return false; +} + +bool FPluginManager::IsPluginCompatible(const FPlugin& Plugin) +{ + if (Plugin.Descriptor.EngineVersion.Len() > 0) + { + FEngineVersion Version; + if (!FEngineVersion::Parse(Plugin.Descriptor.EngineVersion, Version)) + { + UE_LOG(LogPluginManager, Warning, TEXT("Engine version string in %s could not be parsed (\"%s\")"), *Plugin.FileName, *Plugin.Descriptor.EngineVersion); + return true; + } + + EVersionComparison Comparison = FEngineVersion::GetNewest(FEngineVersion::CompatibleWith(), Version, nullptr); + if (Comparison != EVersionComparison::Neither) + { + UE_LOG(LogPluginManager, Warning, TEXT("Plugin '%s' is not compatible with the current engine version (%s)"), *Plugin.Name, *Plugin.Descriptor.EngineVersion); + return false; + } + } + return true; +} + +bool FPluginManager::PromptToLoadIncompatiblePlugin(const FPlugin& Plugin, const FString& ReferencingPluginName) +{ + // Format the message dependning on whether the plugin is referenced directly, or as a dependency + FText Message; + if (Plugin.Name == ReferencingPluginName) + { + Message = FText::Format(LOCTEXT("LoadIncompatiblePlugin", "The '{0}' plugin was designed for build {1}. Attempt to load it anyway?"), FText::FromString(Plugin.Name), FText::FromString(Plugin.Descriptor.EngineVersion)); + } + else + { + Message = FText::Format(LOCTEXT("LoadIncompatibleDependencyPlugin", "The '{0}' plugin is required by the '{1}' plugin, but was designed for build {2}. Attempt to load it anyway?"), FText::FromString(Plugin.Name), FText::FromString(ReferencingPluginName), FText::FromString(Plugin.Descriptor.EngineVersion)); + } + + FText Caption = FText::Format(LOCTEXT("IncompatiblePluginCaption", "'{0}' is Incompatible"), FText::FromString(Plugin.Name)); + return FMessageDialog::Open(EAppMsgType::YesNo, Message, &Caption) == EAppReturnType::Yes; +} + TSharedPtr FPluginManager::FindPluginInstance(const FString& Name) { const TSharedRef* Instance = AllPlugins.Find(Name); @@ -671,56 +784,56 @@ TSharedPtr FPluginManager::FindPluginInstance(const FString& Name) static bool TryLoadModulesForPlugin( const FPlugin& Plugin, const ELoadingPhase::Type LoadingPhase ) - { - TMap ModuleLoadFailures; +{ + TMap ModuleLoadFailures; FModuleDescriptor::LoadModulesForPhase(LoadingPhase, Plugin.Descriptor.Modules, ModuleLoadFailures); - FText FailureMessage; - for( auto FailureIt( ModuleLoadFailures.CreateConstIterator() ); FailureIt; ++FailureIt ) - { - const FName ModuleNameThatFailedToLoad = FailureIt.Key(); - const EModuleLoadResult FailureReason = FailureIt.Value(); + FText FailureMessage; + for( auto FailureIt( ModuleLoadFailures.CreateConstIterator() ); FailureIt; ++FailureIt ) + { + const FName ModuleNameThatFailedToLoad = FailureIt.Key(); + const EModuleLoadResult FailureReason = FailureIt.Value(); - if( FailureReason != EModuleLoadResult::Success ) - { + if( FailureReason != EModuleLoadResult::Success ) + { const FText PluginNameText = FText::FromString(Plugin.Name); - const FText TextModuleName = FText::FromName(FailureIt.Key()); + const FText TextModuleName = FText::FromName(FailureIt.Key()); - if ( FailureReason == EModuleLoadResult::FileNotFound ) - { - FailureMessage = FText::Format( LOCTEXT("PluginModuleNotFound", "Plugin '{0}' failed to load because module '{1}' could not be found. Please ensure the plugin is properly installed, otherwise consider disabling the plugin for this project."), PluginNameText, TextModuleName ); - } - else if ( FailureReason == EModuleLoadResult::FileIncompatible ) - { - FailureMessage = FText::Format( LOCTEXT("PluginModuleIncompatible", "Plugin '{0}' failed to load because module '{1}' does not appear to be compatible with the current version of the engine. The plugin may need to be recompiled."), PluginNameText, TextModuleName ); - } - else if ( FailureReason == EModuleLoadResult::CouldNotBeLoadedByOS ) - { - FailureMessage = FText::Format( LOCTEXT("PluginModuleCouldntBeLoaded", "Plugin '{0}' failed to load because module '{1}' could not be loaded. There may be an operating system error or the module may not be properly set up."), PluginNameText, TextModuleName ); - } - else if ( FailureReason == EModuleLoadResult::FailedToInitialize ) - { - FailureMessage = FText::Format( LOCTEXT("PluginModuleFailedToInitialize", "Plugin '{0}' failed to load because module '{1}' could not be initialized successfully after it was loaded."), PluginNameText, TextModuleName ); - } - else - { - ensure(0); // If this goes off, the error handling code should be updated for the new enum values! - FailureMessage = FText::Format( LOCTEXT("PluginGenericLoadFailure", "Plugin '{0}' failed to load because module '{1}' could not be loaded for an unspecified reason. This plugin's functionality will not be available. Please report this error."), PluginNameText, TextModuleName ); - } - - // Don't need to display more than one module load error per plugin that failed to load - break; - } - } - - if( !FailureMessage.IsEmpty() ) + if ( FailureReason == EModuleLoadResult::FileNotFound ) { - FMessageDialog::Open(EAppMsgType::Ok, FailureMessage); - return false; + FailureMessage = FText::Format( LOCTEXT("PluginModuleNotFound", "Plugin '{0}' failed to load because module '{1}' could not be found. Please ensure the plugin is properly installed, otherwise consider disabling the plugin for this project."), PluginNameText, TextModuleName ); } + else if ( FailureReason == EModuleLoadResult::FileIncompatible ) + { + FailureMessage = FText::Format( LOCTEXT("PluginModuleIncompatible", "Plugin '{0}' failed to load because module '{1}' does not appear to be compatible with the current version of the engine. The plugin may need to be recompiled."), PluginNameText, TextModuleName ); + } + else if ( FailureReason == EModuleLoadResult::CouldNotBeLoadedByOS ) + { + FailureMessage = FText::Format( LOCTEXT("PluginModuleCouldntBeLoaded", "Plugin '{0}' failed to load because module '{1}' could not be loaded. There may be an operating system error or the module may not be properly set up."), PluginNameText, TextModuleName ); + } + else if ( FailureReason == EModuleLoadResult::FailedToInitialize ) + { + FailureMessage = FText::Format( LOCTEXT("PluginModuleFailedToInitialize", "Plugin '{0}' failed to load because module '{1}' could not be initialized successfully after it was loaded."), PluginNameText, TextModuleName ); + } + else + { + ensure(0); // If this goes off, the error handling code should be updated for the new enum values! + FailureMessage = FText::Format( LOCTEXT("PluginGenericLoadFailure", "Plugin '{0}' failed to load because module '{1}' could not be loaded for an unspecified reason. This plugin's functionality will not be available. Please report this error."), PluginNameText, TextModuleName ); + } + + // Don't need to display more than one module load error per plugin that failed to load + break; + } + } + + if( !FailureMessage.IsEmpty() ) + { + FMessageDialog::Open(EAppMsgType::Ok, FailureMessage); + return false; + } return true; - } +} bool FPluginManager::LoadModulesForEnabledPlugins( const ELoadingPhase::Type LoadingPhase ) { diff --git a/Engine/Source/Runtime/Projects/Private/PluginManager.h b/Engine/Source/Runtime/Projects/Private/PluginManager.h index 55d15166f3e9..b71b9468fca4 100644 --- a/Engine/Source/Runtime/Projects/Private/PluginManager.h +++ b/Engine/Source/Runtime/Projects/Private/PluginManager.h @@ -44,6 +44,7 @@ public: virtual FString GetContentDir() const override; virtual FString GetMountedAssetPath() const override; virtual bool IsEnabled() const override; + virtual bool IsHidden() const override; virtual bool CanContainContent() const override; virtual EPluginLoadedFrom GetLoadedFrom() const override; virtual const FPluginDescriptor& GetDescriptor() const override; @@ -53,7 +54,7 @@ public: /** * FPluginManager manages available code and content extensions (both loaded and not loaded.) */ -class FPluginManager : public IPluginManager +class FPluginManager final : public IPluginManager { public: /** Constructor */ @@ -96,12 +97,30 @@ private: /** Sets the bPluginEnabled flag on all plugins found from DiscoverAllPlugins that are enabled in config */ bool ConfigureEnabledPlugins(); + /** Adds a single enabled plugin, and all its dependencies */ + bool ConfigureEnabledPlugin(const FPluginReferenceDescriptor& FirstReference, TSet& EnabledPluginNames); + + /** Prompts the user to download a missing plugin from the given URL */ + static bool PromptToDownloadPlugin(const FString& PluginName, const FString& MarketplaceURL); + + /** Prompts the user to disable a plugin */ + static bool PromptToDisableMissingPlugin(const FString& PluginName, const FString& MissingPluginName); + + /** Prompts the user to disable a plugin */ + static bool PromptToDisableIncompatiblePlugin(const FString& PluginName, const FString& IncompatiblePluginName); + + /** Prompts the user to disable a plugin */ + static bool PromptToDisablePlugin(const FText& Caption, const FText& Message, const FString& PluginName); + + /** Checks whether a plugin is compatible with the current engine version */ + static bool IsPluginCompatible(const FPlugin& Plugin); + + /** Prompts the user to disable a plugin */ + static bool PromptToLoadIncompatiblePlugin(const FPlugin& Plugin, const FString& ReferencingPluginName); + /** Gets the instance of a given plugin */ TSharedPtr FindPluginInstance(const FString& Name); - /** Returns true if the plugin is supported by the current target (program/game) */ - bool IsPluginSupportedByCurrentTarget(TSharedRef Plugin) const; - private: /** All of the plugins that we know about */ TMap< FString, TSharedRef< FPlugin > > AllPlugins; diff --git a/Engine/Source/Runtime/Projects/Private/PluginReferenceDescriptor.cpp b/Engine/Source/Runtime/Projects/Private/PluginReferenceDescriptor.cpp new file mode 100644 index 000000000000..18bc2620257e --- /dev/null +++ b/Engine/Source/Runtime/Projects/Private/PluginReferenceDescriptor.cpp @@ -0,0 +1,217 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "PluginReferenceDescriptor.h" +#include "Misc/FileHelper.h" +#include "Serialization/JsonReader.h" +#include "Serialization/JsonSerializer.h" +#include "ProjectDescriptor.h" + +#define LOCTEXT_NAMESPACE "PluginDescriptor" + +FPluginReferenceDescriptor::FPluginReferenceDescriptor( const FString& InName, bool bInEnabled, const FString& InMarketplaceURL ) + : Name(InName) + , bEnabled(bInEnabled) + , bOptional(false) + , MarketplaceURL(InMarketplaceURL) +{ } + + +bool FPluginReferenceDescriptor::IsEnabledForPlatform( const FString& Platform ) const +{ + // If it's not enabled at all, return false + if(!bEnabled) + { + return false; + } + + // If there is a list of whitelisted platforms, and this isn't one of them, return false + if(WhitelistPlatforms.Num() > 0 && !WhitelistPlatforms.Contains(Platform)) + { + return false; + } + + // If this platform is blacklisted, also return false + if(BlacklistPlatforms.Contains(Platform)) + { + return false; + } + + return true; +} + +bool FPluginReferenceDescriptor::IsEnabledForTarget(const FString& Target) const +{ + // If it's not enabled at all, return false + if (!bEnabled) + { + return false; + } + + // If there is a list of whitelisted platforms, and this isn't one of them, return false + if (WhitelistTargets.Num() > 0 && !WhitelistTargets.Contains(Target)) + { + return false; + } + + // If this platform is blacklisted, also return false + if (BlacklistTargets.Contains(Target)) + { + return false; + } + + return true; +} + +bool FPluginReferenceDescriptor::Read( const FJsonObject& Object, FText& OutFailReason ) +{ + // Get the name + if(!Object.TryGetStringField(TEXT("Name"), Name)) + { + OutFailReason = LOCTEXT("PluginReferenceWithoutName", "Plugin references must have a 'Name' field"); + return false; + } + + // Get the enabled field + if(!Object.TryGetBoolField(TEXT("Enabled"), bEnabled)) + { + OutFailReason = LOCTEXT("PluginReferenceWithoutEnabled", "Plugin references must have an 'Enabled' field"); + return false; + } + + // Read the optional field + Object.TryGetBoolField(TEXT("Optional"), bOptional); + + // Read the metadata for users that don't have the plugin installed + Object.TryGetStringField(TEXT("Description"), Description); + Object.TryGetStringField(TEXT("MarketplaceURL"), MarketplaceURL); + + // Get the platform lists + Object.TryGetStringArrayField(TEXT("WhitelistPlatforms"), WhitelistPlatforms); + Object.TryGetStringArrayField(TEXT("BlacklistPlatforms"), BlacklistPlatforms); + + // Get the target lists + Object.TryGetStringArrayField(TEXT("WhitelistTargets"), WhitelistTargets); + Object.TryGetStringArrayField(TEXT("BlacklistTargets"), BlacklistTargets); + + return true; +} + + +bool FPluginReferenceDescriptor::ReadArray( const FJsonObject& Object, const TCHAR* Name, TArray& OutPlugins, FText& OutFailReason ) +{ + const TArray< TSharedPtr > *Array; + + if (Object.TryGetArrayField(Name, Array)) + { + for (const TSharedPtr &Item : *Array) + { + const TSharedPtr *ObjectPtr; + + if (Item.IsValid() && Item->TryGetObject(ObjectPtr)) + { + FPluginReferenceDescriptor Plugin; + + if (!Plugin.Read(*ObjectPtr->Get(), OutFailReason)) + { + return false; + } + + OutPlugins.Add(Plugin); + } + } + } + + return true; +} + + +void FPluginReferenceDescriptor::Write( TJsonWriter<>& Writer ) const +{ + Writer.WriteObjectStart(); + Writer.WriteValue(TEXT("Name"), Name); + Writer.WriteValue(TEXT("Enabled"), bEnabled); + + if (bEnabled && bOptional) + { + Writer.WriteValue(TEXT("Optional"), bOptional); + } + + if (Description.Len() > 0) + { + Writer.WriteValue(TEXT("Description"), Description); + } + + if (MarketplaceURL.Len() > 0) + { + Writer.WriteValue(TEXT("MarketplaceURL"), MarketplaceURL); + } + + if (WhitelistPlatforms.Num() > 0) + { + Writer.WriteArrayStart(TEXT("WhitelistPlatforms")); + + for (int Idx = 0; Idx < WhitelistPlatforms.Num(); Idx++) + { + Writer.WriteValue(WhitelistPlatforms[Idx]); + } + + Writer.WriteArrayEnd(); + } + + if (BlacklistPlatforms.Num() > 0) + { + Writer.WriteArrayStart(TEXT("BlacklistPlatforms")); + + for (int Idx = 0; Idx < BlacklistPlatforms.Num(); Idx++) + { + Writer.WriteValue(BlacklistPlatforms[Idx]); + } + + Writer.WriteArrayEnd(); + } + + if (WhitelistTargets.Num() > 0) + { + Writer.WriteArrayStart(TEXT("WhitelistTargets")); + + for (int Idx = 0; Idx < WhitelistTargets.Num(); Idx++) + { + Writer.WriteValue(WhitelistTargets[Idx]); + } + + Writer.WriteArrayEnd(); + } + + if (BlacklistTargets.Num() > 0) + { + Writer.WriteArrayStart(TEXT("BlacklistTargets")); + + for (int Idx = 0; Idx < BlacklistTargets.Num(); Idx++) + { + Writer.WriteValue(BlacklistTargets[Idx]); + } + + Writer.WriteArrayEnd(); + } + + Writer.WriteObjectEnd(); +} + + +void FPluginReferenceDescriptor::WriteArray( TJsonWriter<>& Writer, const TCHAR* Name, const TArray& Plugins ) +{ + if( Plugins.Num() > 0) + { + Writer.WriteArrayStart(Name); + + for (int Idx = 0; Idx < Plugins.Num(); Idx++) + { + Plugins[Idx].Write(Writer); + } + + Writer.WriteArrayEnd(); + } +} + + +#undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Runtime/Projects/Private/ProjectDescriptor.cpp b/Engine/Source/Runtime/Projects/Private/ProjectDescriptor.cpp index 9bbd0f56349f..c52353bdf94b 100644 --- a/Engine/Source/Runtime/Projects/Private/ProjectDescriptor.cpp +++ b/Engine/Source/Runtime/Projects/Private/ProjectDescriptor.cpp @@ -13,6 +13,7 @@ FProjectDescriptor::FProjectDescriptor() { FileVersion = EProjectDescriptorVersion::Latest; EpicSampleNameHash = 0; + bIsEnterpriseProject = false; } void FProjectDescriptor::Sign(const FString& FilePath) @@ -104,6 +105,7 @@ bool FProjectDescriptor::Read(const FJsonObject& Object, const FString& PathToPr Object.TryGetStringField(TEXT("EngineAssociation"), EngineAssociation); Object.TryGetStringField(TEXT("Category"), Category); Object.TryGetStringField(TEXT("Description"), Description); + Object.TryGetBoolField(TEXT("Enterprise"), bIsEnterpriseProject); // Read the modules if(!FModuleDescriptor::ReadArray(Object, TEXT("Modules"), Modules, OutFailReason)) @@ -204,6 +206,12 @@ void FProjectDescriptor::Write(TJsonWriter<>& Writer, const FString& PathToProje Writer.WriteValue(TEXT("Category"), Category); Writer.WriteValue(TEXT("Description"), Description); + // Write the enterprise flag + if (bIsEnterpriseProject) + { + Writer.WriteValue(TEXT("Enterprise"), bIsEnterpriseProject); + } + // Write the module list FModuleDescriptor::WriteArray(Writer, TEXT("Modules"), Modules); diff --git a/Engine/Source/Runtime/Projects/Private/ProjectManager.cpp b/Engine/Source/Runtime/Projects/Private/ProjectManager.cpp index 686227b0a6c0..8f1663e58cdd 100644 --- a/Engine/Source/Runtime/Projects/Private/ProjectManager.cpp +++ b/Engine/Source/Runtime/Projects/Private/ProjectManager.cpp @@ -8,6 +8,7 @@ #include "Interfaces/IPluginManager.h" #include "ProjectDescriptor.h" #include "Modules/ModuleManager.h" +#include "GenericPlatform/GenericPlatformProcess.h" DEFINE_LOG_CATEGORY_STATIC( LogProjectManager, Log, All ); @@ -30,6 +31,10 @@ bool FProjectManager::LoadProjectFile( const FString& InProjectFile ) TSharedPtr Descriptor = MakeShareable(new FProjectDescriptor()); if(Descriptor->Load(InProjectFile, FailureReason)) { + // Projects can have their own shaders + // Add potential project shader directory + FGenericPlatformProcess::AddShaderDir(FPaths::Combine(FPaths::GetPath(InProjectFile), TEXT("Shaders"))); + // Create the project CurrentProject = Descriptor; return true; @@ -244,33 +249,20 @@ void FProjectManager::ClearSupportedTargetPlatformsForCurrentProject() OnTargetPlatformsForCurrentProjectChangedEvent.Broadcast(); } -void FProjectManager::GetEnabledPlugins(TArray& OutPluginNames) const +bool FProjectManager::IsNonDefaultPluginEnabled() const { - // Get the default list of plugin names - GetDefaultEnabledPlugins(OutPluginNames, true); + TSet EnabledPlugins; - // Modify that with the list of plugins in the project file - const FProjectDescriptor *Project = GetCurrentProject(); - if(Project != NULL) + if (CurrentProject.IsValid()) { - for(const FPluginReferenceDescriptor& Plugin: Project->Plugins) + for (const FPluginReferenceDescriptor& PluginReference : CurrentProject->Plugins) { - if(Plugin.IsEnabledForPlatform(FPlatformMisc::GetUBTPlatform()) && Plugin.IsEnabledForTarget(FPlatformMisc::GetUBTTarget())) + if (PluginReference.bEnabled) { - OutPluginNames.AddUnique(Plugin.Name); - } - else - { - OutPluginNames.Remove(Plugin.Name); + EnabledPlugins.Add(PluginReference.Name); } } } -} - -bool FProjectManager::IsNonDefaultPluginEnabled() const -{ - TArray EnabledPlugins; - GetEnabledPlugins(EnabledPlugins); for(const FPluginStatus& Plugin: IPluginManager::Get().QueryStatusForAllPlugins()) { @@ -335,6 +327,28 @@ bool FProjectManager::SetPluginEnabled(const FString& PluginName, bool bEnabled, return true; } +bool FProjectManager::RemovePluginReference(const FString& PluginName, FText& OutFailReason) +{ + // Don't go any further if there's no project loaded + if (!CurrentProject.IsValid()) + { + OutFailReason = LOCTEXT("NoProjectLoaded", "No project is currently loaded"); + return false; + } + + bool bPluginFound = false; + for (int32 PluginRefIdx = CurrentProject->Plugins.Num() - 1; PluginRefIdx >= 0 && !bPluginFound; --PluginRefIdx) + { + if (CurrentProject->Plugins[PluginRefIdx].Name == PluginName) + { + CurrentProject->Plugins.RemoveAt(PluginRefIdx); + bPluginFound = true; + break; + } + } + return bPluginFound; +} + void FProjectManager::GetDefaultEnabledPlugins(TArray& OutPluginNames, bool bIncludeInstalledPlugins) { // Add all the game plugins and everything marked as enabled by default diff --git a/Engine/Source/Runtime/Projects/Private/ProjectManager.h b/Engine/Source/Runtime/Projects/Private/ProjectManager.h index 04cf93395ebb..80a526ec15f2 100644 --- a/Engine/Source/Runtime/Projects/Private/ProjectManager.h +++ b/Engine/Source/Runtime/Projects/Private/ProjectManager.h @@ -10,7 +10,7 @@ struct FProjectDescriptor; /** * ProjectAndPluginManager manages available code and content extensions (both loaded and not loaded.) */ -class FProjectManager : public IProjectManager +class FProjectManager final : public IProjectManager { public: FProjectManager(); @@ -29,9 +29,9 @@ public: virtual void ClearSupportedTargetPlatformsForProject(const FString& FilePath) override; virtual void ClearSupportedTargetPlatformsForCurrentProject() override; virtual FOnTargetPlatformsForCurrentProjectChangedEvent& OnTargetPlatformsForCurrentProjectChanged() override { return OnTargetPlatformsForCurrentProjectChangedEvent; } - virtual void GetEnabledPlugins(TArray& OutPluginNames) const override; virtual bool IsNonDefaultPluginEnabled() const override; virtual bool SetPluginEnabled(const FString& PluginName, bool bEnabled, FText& OutFailReason, const FString& MarketplaceURL) override; + virtual bool RemovePluginReference(const FString& PluginName, FText& OutFailReason) override; virtual void UpdateAdditionalPluginDirectory(const FString& Dir, const bool bAddOrRemove) override; virtual bool IsCurrentProjectDirty() const override; virtual bool SaveCurrentProjectToDisk(FText& OutFailReason) override; diff --git a/Engine/Source/Runtime/Projects/Public/Interfaces/IPluginManager.h b/Engine/Source/Runtime/Projects/Public/Interfaces/IPluginManager.h index 4aad4fb8a963..86a799f214b3 100644 --- a/Engine/Source/Runtime/Projects/Public/Interfaces/IPluginManager.h +++ b/Engine/Source/Runtime/Projects/Public/Interfaces/IPluginManager.h @@ -91,6 +91,13 @@ public: */ virtual bool IsEnabled() const = 0; + /** + * Determines if the plugin is should be displayed in-editor for the user to enable/disable freely. + * + * @return True if the plugin should be hidden. + */ + virtual bool IsHidden() const = 0; + /** * Determines if the plugin can contain content. * @@ -128,6 +135,7 @@ public: class IPluginManager { public: + virtual ~IPluginManager() { } /** * Updates the list of plugins. diff --git a/Engine/Source/Runtime/Projects/Public/Interfaces/IProjectManager.h b/Engine/Source/Runtime/Projects/Public/Interfaces/IProjectManager.h index 3927892efa69..bc1ca159de60 100644 --- a/Engine/Source/Runtime/Projects/Public/Interfaces/IProjectManager.h +++ b/Engine/Source/Runtime/Projects/Public/Interfaces/IProjectManager.h @@ -70,6 +70,7 @@ class IProjectManager { public: + virtual ~IProjectManager() { } /** * Static: Access singleton instance @@ -179,13 +180,6 @@ public: DECLARE_MULTICAST_DELEGATE(FOnTargetPlatformsForCurrentProjectChangedEvent); virtual FOnTargetPlatformsForCurrentProjectChangedEvent& OnTargetPlatformsForCurrentProjectChanged() = 0; - /** - * Gets a list of plugins enabled for the current project. - * - * @param OutPluginNames Array to receive the list of plugin names - */ - virtual void GetEnabledPlugins(TArray& OutPluginNames) const = 0; - /** * Hack to checks whether the current project has a non-default plugin enabled (ie. one which is not included by default in UE4Game). * @@ -204,6 +198,11 @@ public: */ virtual bool SetPluginEnabled(const FString& PluginName, bool bEnabled, FText& OutFailReason, const FString& MarketplaceURL = TEXT("")) = 0; + /** + * + */ + virtual bool RemovePluginReference(const FString& PluginName, FText& OutFailReason) = 0; + /** * Updates a directory to be scanned for plugins (added or removed) * diff --git a/Engine/Source/Runtime/Projects/Public/ModuleDescriptor.h b/Engine/Source/Runtime/Projects/Public/ModuleDescriptor.h index d3b08efaa08f..2a4f5ad18ef6 100644 --- a/Engine/Source/Runtime/Projects/Public/ModuleDescriptor.h +++ b/Engine/Source/Runtime/Projects/Public/ModuleDescriptor.h @@ -116,6 +116,12 @@ struct PROJECTS_API FModuleDescriptor /** List of disallowed platforms */ TArray BlacklistPlatforms; + /** List of allowed targets */ + TArray WhitelistTargets; + + /** List of disallowed targets */ + TArray BlacklistTargets; + /** List of additional dependencies for building this module. */ TArray AdditionalDependencies; diff --git a/Engine/Source/Runtime/Projects/Public/PluginDescriptor.h b/Engine/Source/Runtime/Projects/Public/PluginDescriptor.h index 46d0101f61a6..3791137da49e 100644 --- a/Engine/Source/Runtime/Projects/Public/PluginDescriptor.h +++ b/Engine/Source/Runtime/Projects/Public/PluginDescriptor.h @@ -6,6 +6,7 @@ #include "ModuleDescriptor.h" #include "CustomBuildSteps.h" #include "LocalizationDescriptor.h" +#include "PluginReferenceDescriptor.h" class FJsonObject; @@ -72,9 +73,6 @@ struct PROJECTS_API FPluginDescriptor /** Version of the engine that this plugin is compatible with */ FString EngineVersion; - /** For packaged plugins, contains the compatible changelist of the engine that built this plugin */ - int32 CompatibleChangelist; - /** List of all modules associated with this plugin */ TArray Modules; @@ -99,12 +97,18 @@ struct PROJECTS_API FPluginDescriptor /** For plugins that are under a platform folder (eg. /PS4/), determines whether compiling the plugin requires the build platform and/or SDK to be available */ bool bRequiresBuildPlatform; + /** For auto-generated plugins that should not be listed in the plugin browser for users to disable freely. */ + bool bIsHidden; + /** Pre-build steps for each host platform */ FCustomBuildSteps PreBuildSteps; /** Pre-build steps for each host platform */ FCustomBuildSteps PostBuildSteps; + /** Dependent plugins */ + TArray Plugins; + /** Constructor. */ FPluginDescriptor(); @@ -121,57 +125,3 @@ struct PROJECTS_API FPluginDescriptor void Write(FString& Text, bool bPluginTypeEnabledByDefault) const; }; -/** - * Descriptor for a plugin reference. Contains the information required to enable or disable a plugin for a given platform. - */ -struct PROJECTS_API FPluginReferenceDescriptor -{ - /** Name of the plugin */ - FString Name; - - /** Whether it should be enabled by default */ - bool bEnabled; - - /** Whether this plugin is optional, and the game should silently ignore it not being present */ - bool bOptional; - - /** Description of the plugin for users that do not have it installed. */ - FString Description; - - /** URL for this plugin on the marketplace, if the user doesn't have it installed. */ - FString MarketplaceURL; - - /** If enabled, list of platforms for which the plugin should be enabled (or all platforms if blank). */ - TArray WhitelistPlatforms; - - /** If enabled, list of platforms for which the plugin should be disabled. */ - TArray BlacklistPlatforms; - - /** If enabled, list of targets for which the plugin should be enabled (or all targets if blank). */ - TArray WhitelistTargets; - - /** If enabled, list of targets for which the plugin should be disabled. */ - TArray BlacklistTargets; - - /** Constructor */ - FPluginReferenceDescriptor(const FString& InName = TEXT(""), bool bInEnabled = false, const FString& InMarketplaceURL = TEXT("")); - - /** Determines whether the plugin is enabled for the given platform */ - bool IsEnabledForPlatform(const FString& Platform) const; - - /** Determines whether the plugin is enabled for the given target */ - bool IsEnabledForTarget(const FString& Target) const; - - /** Reads the descriptor from the given JSON object */ - bool Read(const FJsonObject& Object, FText& OutFailReason); - - /** Reads an array of modules from the given JSON object */ - static bool ReadArray(const FJsonObject& Object, const TCHAR* Name, TArray& OutModules, FText& OutFailReason); - - /** Writes a descriptor to JSON */ - void Write(TJsonWriter<>& Writer) const; - - /** Writes an array of modules to JSON */ - static void WriteArray(TJsonWriter<>& Writer, const TCHAR* Name, const TArray& Modules); -}; - diff --git a/Engine/Source/Runtime/Projects/Public/PluginReferenceDescriptor.h b/Engine/Source/Runtime/Projects/Public/PluginReferenceDescriptor.h new file mode 100644 index 000000000000..7eff6f4df9f7 --- /dev/null +++ b/Engine/Source/Runtime/Projects/Public/PluginReferenceDescriptor.h @@ -0,0 +1,63 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "ModuleDescriptor.h" +#include "CustomBuildSteps.h" +#include "LocalizationDescriptor.h" + +/** + * Descriptor for a plugin reference. Contains the information required to enable or disable a plugin for a given platform. + */ +struct PROJECTS_API FPluginReferenceDescriptor +{ + /** Name of the plugin */ + FString Name; + + /** Whether it should be enabled by default */ + bool bEnabled; + + /** Whether this plugin is optional, and the game should silently ignore it not being present */ + bool bOptional; + + /** Description of the plugin for users that do not have it installed. */ + FString Description; + + /** URL for this plugin on the marketplace, if the user doesn't have it installed. */ + FString MarketplaceURL; + + /** If enabled, list of platforms for which the plugin should be enabled (or all platforms if blank). */ + TArray WhitelistPlatforms; + + /** If enabled, list of platforms for which the plugin should be disabled. */ + TArray BlacklistPlatforms; + + /** If enabled, list of targets for which the plugin should be enabled (or all targets if blank). */ + TArray WhitelistTargets; + + /** If enabled, list of targets for which the plugin should be disabled. */ + TArray BlacklistTargets; + + /** Constructor */ + FPluginReferenceDescriptor(const FString& InName = TEXT(""), bool bInEnabled = false, const FString& InMarketplaceURL = TEXT("")); + + /** Determines whether the plugin is enabled for the given platform */ + bool IsEnabledForPlatform(const FString& Platform) const; + + /** Determines whether the plugin is enabled for the given target */ + bool IsEnabledForTarget(const FString& Target) const; + + /** Reads the descriptor from the given JSON object */ + bool Read(const FJsonObject& Object, FText& OutFailReason); + + /** Reads an array of modules from the given JSON object */ + static bool ReadArray(const FJsonObject& Object, const TCHAR* Name, TArray& OutModules, FText& OutFailReason); + + /** Writes a descriptor to JSON */ + void Write(TJsonWriter<>& Writer) const; + + /** Writes an array of modules to JSON */ + static void WriteArray(TJsonWriter<>& Writer, const TCHAR* Name, const TArray& Modules); +}; + diff --git a/Engine/Source/Runtime/Projects/Public/ProjectDescriptor.h b/Engine/Source/Runtime/Projects/Public/ProjectDescriptor.h index d0176409a679..86dbf7ad326d 100644 --- a/Engine/Source/Runtime/Projects/Public/ProjectDescriptor.h +++ b/Engine/Source/Runtime/Projects/Public/ProjectDescriptor.h @@ -5,7 +5,7 @@ #include "CoreMinimal.h" #include "ModuleDescriptor.h" #include "CustomBuildSteps.h" -#include "PluginDescriptor.h" +#include "PluginReferenceDescriptor.h" class FJsonObject; @@ -91,6 +91,9 @@ struct PROJECTS_API FProjectDescriptor /** Custom steps to execute after building targets in this project */ FCustomBuildSteps PostBuildSteps; + /** Indicates if this project is an Enterprise project */ + bool bIsEnterpriseProject; + /** Constructor. */ FProjectDescriptor(); diff --git a/Engine/Source/Runtime/RHI/Private/DynamicRHI.cpp b/Engine/Source/Runtime/RHI/Private/DynamicRHI.cpp index a0e1812a8f60..ff0b5dc51ed5 100644 --- a/Engine/Source/Runtime/RHI/Private/DynamicRHI.cpp +++ b/Engine/Source/Runtime/RHI/Private/DynamicRHI.cpp @@ -251,7 +251,7 @@ void FDynamicRHI::EnableIdealGPUCaptureOptions(bool bEnabled) const bool bDrawEvents = GEmitDrawEvents != 0; const bool bMaterialDrawEvents = ShowMaterialDrawEventVar ? ShowMaterialDrawEventVar->GetInt() != 0 : false; - const bool bRHIThread = GRHIThread != nullptr; + const bool bRHIThread = IsRunningRHIInSeparateThread(); const bool bRHIBypass = RHICmdBypassVar ? RHICmdBypassVar->GetInt() != 0 : false; UE_LOG(LogRHI, Display, TEXT("Setting GPU Capture Options: %i"), bEnabled ? 1 : 0); diff --git a/Engine/Source/Runtime/RHI/Private/GPUDefragAllocator.cpp b/Engine/Source/Runtime/RHI/Private/GPUDefragAllocator.cpp index 957b717d7fad..9cd598cc05ba 100644 --- a/Engine/Source/Runtime/RHI/Private/GPUDefragAllocator.cpp +++ b/Engine/Source/Runtime/RHI/Private/GPUDefragAllocator.cpp @@ -1362,11 +1362,8 @@ void FGPUDefragAllocator::PartialDefragmentationSlow(FRelocationStats& Stats, do } else { - if (!BestChunk) - { - //1. Merge with chunk from the end of the pool (well-fitting) - BestChunk = FindAny(FreeChunk); - } + //1. Merge with chunk from the end of the pool (well-fitting) + BestChunk = FindAny(FreeChunk); } if (BestChunk) @@ -1453,25 +1450,21 @@ void FGPUDefragAllocator::FullDefragmentation(FRelocationStats& Stats) FMemoryChunk* FreeChunk = FirstFreeChunk; while (FreeChunk) { - FMemoryChunk* BestChunk = nullptr; + // Try merging with a used chunk adjacent to hole (to make that hole larger). + FMemoryChunk* BestChunk = FindAdjacentToHole(FreeChunk); + if (!BestChunk) { - // Try merging with a used chunk adjacent to hole (to make that hole larger). - BestChunk = FindAdjacentToHole(FreeChunk); + // Try merging with chunk from the end of the pool (well-fitting) + BestChunk = FindAny(FreeChunk); if (!BestChunk) { - // Try merging with chunk from the end of the pool (well-fitting) - BestChunk = FindAny(FreeChunk); - - if (!BestChunk) + // Try merging with Right, if it fits (brute-force downshifting) + BestChunk = FindAdjacent(FreeChunk->NextChunk, true); + if (BestChunk) { - // Try merging with Right, if it fits (brute-force downshifting) - BestChunk = FindAdjacent(FreeChunk->NextChunk, true); - if (BestChunk) - { - Stats.NumBytesDownShifted += BestChunk->Size; - } + Stats.NumBytesDownShifted += BestChunk->Size; } } } @@ -1722,7 +1715,7 @@ bool FGPUDefragAllocator::GetTextureMemoryVisualizeData(FColor* TextureData, int CurrentType = ChunkType; CurrentChunk = Chunk; NumBytes += Chunk->Size; - Chunk = Chunk ? Chunk->NextChunk : nullptr; + Chunk = Chunk->NextChunk; } // Fill rest of pixels with black. diff --git a/Engine/Source/Runtime/RHI/Private/PipelineStateCache.cpp b/Engine/Source/Runtime/RHI/Private/PipelineStateCache.cpp index 6c2d076616f4..588e3cb7bf8e 100644 --- a/Engine/Source/Runtime/RHI/Private/PipelineStateCache.cpp +++ b/Engine/Source/Runtime/RHI/Private/PipelineStateCache.cpp @@ -5,7 +5,7 @@ PipelineStateCache.cpp: Pipeline state cache implementation. =============================================================================*/ #include "PipelineStateCache.h" -#include "Misc/ScopeLock.h" +#include "Misc/ScopeRWLock.h" extern RHI_API FRHIComputePipelineState* ExecuteSetComputePipelineState(FComputePipelineState* ComputePipelineState); extern RHI_API FRHIGraphicsPipelineState* ExecuteSetGraphicsPipelineState(FGraphicsPipelineState* GraphicsPipelineState); @@ -47,14 +47,15 @@ static inline uint32 GetTypeHash(const FGraphicsPipelineStateInitializer& Initia } -static FCriticalSection GComputeLock; +static FRWLock GComputeLock; static TMap GComputePipelines; -static FCriticalSection GGraphicsLock; +static FRWLock GGraphicsLock; static TMap GGraphicsPipelines; class FPipelineState { public: + virtual ~FPipelineState() { } virtual bool IsCompute() const = 0; FGraphEventRef CompletionEvent; }; @@ -135,7 +136,7 @@ public: static bool IsAsyncCompilationAllowed(FRHICommandList& RHICmdList) { - return GCVarAsyncPipelineCompile.GetValueOnAnyThread() && !RHICmdList.Bypass() && GRHIThread; + return GCVarAsyncPipelineCompile.GetValueOnAnyThread() && !RHICmdList.Bypass() && IsRunningRHIInSeparateThread(); } FComputePipelineState* GetAndOrCreateComputePipelineState(FRHICommandList& RHICmdList, FRHIComputeShader* ComputeShader) @@ -144,7 +145,7 @@ FComputePipelineState* GetAndOrCreateComputePipelineState(FRHICommandList& RHICm { // Should be hitting this case more often once the cache is hot - FScopeLock ScopeLock(&GComputeLock); + FRWScopeLock ScopeLock(GComputeLock, SLT_ReadOnly); FComputePipelineState** Found = GComputePipelines.Find(ComputeShader); if (Found) @@ -156,22 +157,36 @@ FComputePipelineState* GetAndOrCreateComputePipelineState(FRHICommandList& RHICm } return *Found; } - - FComputePipelineState* PipelineState = new FComputePipelineState(ComputeShader); - - if (IsAsyncCompilationAllowed(RHICmdList)) + + ScopeLock.RaiseLockToWrite(); + Found = GComputePipelines.Find(ComputeShader); + if (Found) { - PipelineState->CompletionEvent = TGraphTask::CreateTask().ConstructAndDispatchWhenReady(PipelineState); - RHICmdList.QueueAsyncPipelineStateCompile(PipelineState->CompletionEvent); + if (IsAsyncCompilationAllowed(RHICmdList)) + { + FGraphEventRef& CompletionEvent = (*Found)->CompletionEvent; + RHICmdList.QueueAsyncPipelineStateCompile(CompletionEvent); + } + return *Found; } else { - PipelineState->RHIPipeline = RHICreateComputePipelineState(PipelineState->ComputeShader); + FComputePipelineState* PipelineState = new FComputePipelineState(ComputeShader); + + if (IsAsyncCompilationAllowed(RHICmdList)) + { + PipelineState->CompletionEvent = TGraphTask::CreateTask().ConstructAndDispatchWhenReady(PipelineState); + RHICmdList.QueueAsyncPipelineStateCompile(PipelineState->CompletionEvent); + } + else + { + PipelineState->RHIPipeline = RHICreateComputePipelineState(PipelineState->ComputeShader); + } + + GComputePipelines.Add(ComputeShader, PipelineState); + + return PipelineState; } - - GComputePipelines.Add(ComputeShader, PipelineState); - - return PipelineState; } return nullptr; @@ -239,7 +254,7 @@ FGraphicsPipelineState* GetAndOrCreateGraphicsPipelineState(FRHICommandList& RHI { // Should be hitting this case more often once the cache is hot - FScopeLock ScopeLock(&GGraphicsLock); + FRWScopeLock ScopeLock(GGraphicsLock, SLT_ReadOnly); FGraphicsPipelineState** Found = GGraphicsPipelines.Find(*Initializer); if (Found) @@ -252,21 +267,34 @@ FGraphicsPipelineState* GetAndOrCreateGraphicsPipelineState(FRHICommandList& RHI return *Found; } - FGraphicsPipelineState* PipelineState = new FGraphicsPipelineState(*Initializer); - - if (IsAsyncCompilationAllowed(RHICmdList)) + ScopeLock.RaiseLockToWrite(); + Found = GGraphicsPipelines.Find(*Initializer); + if (Found) { - PipelineState->CompletionEvent = TGraphTask::CreateTask().ConstructAndDispatchWhenReady(PipelineState); - RHICmdList.QueueAsyncPipelineStateCompile(PipelineState->CompletionEvent); + if (IsAsyncCompilationAllowed(RHICmdList)) + { + FGraphEventRef& CompletionEvent = (*Found)->CompletionEvent; + RHICmdList.QueueAsyncPipelineStateCompile(CompletionEvent); + } + return *Found; } else { - PipelineState->RHIPipeline = RHICreateGraphicsPipelineState(*Initializer); + FGraphicsPipelineState* PipelineState = new FGraphicsPipelineState(*Initializer); + + if (IsAsyncCompilationAllowed(RHICmdList)) + { + PipelineState->CompletionEvent = TGraphTask::CreateTask().ConstructAndDispatchWhenReady(PipelineState); + RHICmdList.QueueAsyncPipelineStateCompile(PipelineState->CompletionEvent); + } + else + { + PipelineState->RHIPipeline = RHICreateGraphicsPipelineState(*Initializer); + } + + GGraphicsPipelines.Add(*Initializer, PipelineState); + return PipelineState; } - - GGraphicsPipelines.Add(*Initializer, PipelineState); - - return PipelineState; } return nullptr; diff --git a/Engine/Source/Runtime/RHI/Private/RHI.cpp b/Engine/Source/Runtime/RHI/Private/RHI.cpp index 1802ea9659c5..0e6a7c0a927e 100644 --- a/Engine/Source/Runtime/RHI/Private/RHI.cpp +++ b/Engine/Source/Runtime/RHI/Private/RHI.cpp @@ -91,7 +91,8 @@ const FClearValueBinding FClearValueBinding::DepthZero(0.0f, 0); const FClearValueBinding FClearValueBinding::DepthNear((float)ERHIZBuffer::NearPlane, 0); const FClearValueBinding FClearValueBinding::DepthFar((float)ERHIZBuffer::FarPlane, 0); const FClearValueBinding FClearValueBinding::Green(FLinearColor(0.0f, 1.0f, 0.0f, 1.0f)); -const FClearValueBinding FClearValueBinding::MidGray(FLinearColor(0.5f, 0.5f, 0.5f, 1.0f)); +// Note: this is used as the default normal for DBuffer decals. It must decode to a value of 0 in DecodeDBufferData. +const FClearValueBinding FClearValueBinding::DefaultNormal8Bit(FLinearColor(128.0f / 255.0f, 128.0f / 255.0f, 128.0f / 255.0f, 1.0f)); TLockFreePointerListUnordered FRHIResource::PendingDeletes; FRHIResource* FRHIResource::CurrentlyDeleting = nullptr; @@ -216,6 +217,13 @@ static TAutoConsoleVariable GGPUHitchThresholdCVar( TEXT("Threshold for detecting hitches on the GPU (in milliseconds).") ); +static TAutoConsoleVariable CVarGPUCrashDebugging( + TEXT("r.GPUCrashDebugging"), + 0, + TEXT("Enable vendor specific GPU crash analysis tools"), + ECVF_ReadOnly + ); + namespace RHIConfig { bool ShouldSaveScreenshotAfterProfilingGPU() @@ -265,6 +273,7 @@ bool GSupportsDepthRenderTargetWithoutColorRenderTarget = true; bool GRHINeedsUnatlasedCSMDepthsWorkaround = false; bool GSupportsTexture3D = true; bool GSupportsMobileMultiView = false; +bool GSupportsImageExternal = false; bool GSupportsResourceView = true; bool GSupportsMultipleRenderTargets = true; bool GSupportsWideMRT = true; @@ -290,10 +299,12 @@ bool GRHISupportsInstancing = true; bool GRHISupportsFirstInstance = false; bool GRHIRequiresEarlyBackBufferRenderTarget = true; bool GRHISupportsRHIThread = false; +bool GRHISupportsRHIOnTaskThread = false; bool GRHISupportsParallelRHIExecute = false; bool GSupportsHDR32bppEncodeModeIntrinsic = false; bool GSupportsParallelOcclusionQueries = false; bool GSupportsRenderTargetWriteMask = false; +bool GSupportsTransientResourceAliasing = false; bool GRHISupportsMSAADepthSampleAccess = false; bool GRHISupportsResolveCubemapFaces = false; @@ -380,7 +391,8 @@ static FName NAME_PCD3D_ES2(TEXT("PCD3D_ES2")); static FName NAME_GLSL_150(TEXT("GLSL_150")); static FName NAME_GLSL_150_MAC(TEXT("GLSL_150_MAC")); static FName NAME_SF_PS4(TEXT("SF_PS4")); -static FName NAME_SF_XBOXONE(TEXT("SF_XBOXONE")); +static FName NAME_SF_XBOXONE_D3D11(TEXT("SF_XBOXONE_D3D11")); +static FName NAME_SF_XBOXONE_D3D12(TEXT("SF_XBOXONE_D3D12")); static FName NAME_GLSL_430(TEXT("GLSL_430")); static FName NAME_GLSL_150_ES2(TEXT("GLSL_150_ES2")); static FName NAME_GLSL_150_ES2_NOUB(TEXT("GLSL_150_ES2_NOUB")); @@ -423,8 +435,10 @@ FName LegacyShaderPlatformToShaderFormat(EShaderPlatform Platform) return NAME_GLSL_150_MAC; case SP_PS4: return NAME_SF_PS4; - case SP_XBOXONE: - return NAME_SF_XBOXONE; + case SP_XBOXONE_D3D11: + return NAME_SF_XBOXONE_D3D11; + case SP_XBOXONE_D3D12: + return NAME_SF_XBOXONE_D3D12; case SP_OPENGL_SM5: return NAME_GLSL_430; case SP_OPENGL_PCES2: @@ -489,7 +503,8 @@ EShaderPlatform ShaderFormatToLegacyShaderPlatform(FName ShaderFormat) if (ShaderFormat == NAME_GLSL_150) return SP_OPENGL_SM4; if (ShaderFormat == NAME_GLSL_150_MAC) return SP_OPENGL_SM4_MAC; if (ShaderFormat == NAME_SF_PS4) return SP_PS4; - if (ShaderFormat == NAME_SF_XBOXONE) return SP_XBOXONE; + if (ShaderFormat == NAME_SF_XBOXONE_D3D11) return SP_XBOXONE_D3D11; + if (ShaderFormat == NAME_SF_XBOXONE_D3D12) return SP_XBOXONE_D3D12; if (ShaderFormat == NAME_GLSL_430) return SP_OPENGL_SM5; if (ShaderFormat == NAME_GLSL_150_ES2) return SP_OPENGL_PCES2; if (ShaderFormat == NAME_GLSL_150_ES2_NOUB) return SP_OPENGL_PCES2; @@ -581,7 +596,7 @@ RHI_API bool RHISupportsTessellation(const EShaderPlatform Platform) { if (IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5) && !IsMetalPlatform(Platform)) { - return (Platform == SP_PCD3D_SM5) || (Platform == SP_XBOXONE) || (Platform == SP_OPENGL_SM5) || (Platform == SP_OPENGL_ES31_EXT) || (Platform == SP_VULKAN_SM5); + return (Platform == SP_PCD3D_SM5) || (Platform == SP_XBOXONE_D3D12) || (Platform == SP_XBOXONE_D3D11) || (Platform == SP_OPENGL_SM5) || (Platform == SP_OPENGL_ES31_EXT) || (Platform == SP_VULKAN_SM5); } // For Metal we can only support tessellation if we are willing to sacrifice backward compatibility with OS versions. // As such it becomes an opt-in project setting. diff --git a/Engine/Source/Runtime/RHI/Private/RHICommandList.cpp b/Engine/Source/Runtime/RHI/Private/RHICommandList.cpp index cb92aa958438..d4579e18291e 100644 --- a/Engine/Source/Runtime/RHI/Private/RHICommandList.cpp +++ b/Engine/Source/Runtime/RHI/Private/RHICommandList.cpp @@ -8,6 +8,7 @@ #include "Misc/App.h" #include "Async/TaskGraphInterfaces.h" #include "RHI.h" +#include "ScopeLock.h" DECLARE_CYCLE_STAT(TEXT("Nonimmed. Command List Execute"), STAT_NonImmedCmdListExecuteTime, STATGROUP_RHICMDLIST); DECLARE_DWORD_COUNTER_STAT(TEXT("Nonimmed. Command List memory"), STAT_NonImmedCmdListMemory, STATGROUP_RHICMDLIST); @@ -21,8 +22,6 @@ DECLARE_DWORD_COUNTER_STAT(TEXT("Immed. Command count"), STAT_ImmedCmdListCount, #include "RHICommandListCommandExecutes.inl" #endif -int32 FRHICommandListBase::StateCacheEnabled = 1; - static TAutoConsoleVariable CVarRHICmdBypass( TEXT("r.RHICmdBypass"), FRHICommandListExecutor::DefaultBypass, @@ -105,11 +104,12 @@ static TAutoConsoleVariable CVarRHICmdMinCmdlistSizeForParallelTranslate( 32, TEXT("In kilobytes. Cmdlists are merged into one parallel translate until we have at least this much memory to process. For a given pass, we won't do more translates than we have task threads. Only relevant if r.RHICmdBalanceTranslatesAfterTasks is on.")); -static FAutoConsoleVariableRef CVarRHICmdListStateCache( - TEXT("r.RHICmdStateCacheEnable"), - FRHICommandListBase::StateCacheEnabled, - TEXT("If > 0, then enable a minor state cache on the from of cmdlist recording.") - ); + +bool GUseRHIThread_InternalUseOnly = false; +bool GUseRHITaskThreads_InternalUseOnly = false; +bool GIsRunningRHIInSeparateThread_InternalUseOnly = false; +bool GIsRunningRHIInDedicatedThread_InternalUseOnly = false; +bool GIsRunningRHIInTaskThread_InternalUseOnly = false; RHI_API bool GEnableAsyncCompute = true; RHI_API FRHICommandListExecutor GRHICommandList; @@ -265,6 +265,16 @@ void FRHICommandListExecutor::ExecuteInner_DoExecute(FRHICommandListBase& CmdLis } +static FAutoConsoleTaskPriority CPrio_RHIThreadOnTaskThreads( + TEXT("TaskGraph.TaskPriorities.RHIThreadOnTaskThreads"), + TEXT("Task and thread priority for when we are running 'RHI thread' tasks on any thread."), + ENamedThreads::NormalThreadPriority, + ENamedThreads::NormalTaskPriority + ); + + +static FCriticalSection GRHIThreadOnTasksCritical; + class FExecuteRHIThreadTask { @@ -284,8 +294,8 @@ public: ENamedThreads::Type GetDesiredThread() { - check(GRHIThread); // this should never be used on a platform that doesn't support the RHI thread - return ENamedThreads::RHIThread; + check(IsRunningRHIInSeparateThread()); // this should never be used on a platform that doesn't support the RHI thread + return IsRunningRHIInDedicatedThread() ? ENamedThreads::RHIThread : CPrio_RHIThreadOnTaskThreads.Get(); } static ESubsequentsMode::Type GetSubsequentsMode() { return ESubsequentsMode::TrackSubsequents; } @@ -293,8 +303,19 @@ public: void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent) { SCOPE_CYCLE_COUNTER(STAT_RHIThreadExecute); - FRHICommandListExecutor::ExecuteInner_DoExecute(*RHICmdList); - delete RHICmdList; + if (IsRunningRHIInTaskThread()) + { + GRHIThreadId = FPlatformTLS::GetCurrentThreadId(); + } + { + FScopeLock Lock(&GRHIThreadOnTasksCritical); + FRHICommandListExecutor::ExecuteInner_DoExecute(*RHICmdList); + delete RHICmdList; + } + if (IsRunningRHIInTaskThread()) + { + GRHIThreadId = 0; + } } }; @@ -320,8 +341,8 @@ public: { // If we are using async dispatch, this task is somewhat redundant, but it does allow things to wait for dispatch without waiting for execution. // since in that case we will be queuing an rhithread task from an rhithread task, the overhead is minor. - check(GRHIThread); // this should never be used on a platform that doesn't support the RHI thread - return bRHIThread ? ENamedThreads::RHIThread : ENamedThreads::RenderThread_Local; + check(IsRunningRHIInSeparateThread()); // this should never be used on a platform that doesn't support the RHI thread + return bRHIThread ? (IsRunningRHIInDedicatedThread() ? ENamedThreads::RHIThread : CPrio_RHIThreadOnTaskThreads.Get()) : ENamedThreads::RenderThread_Local; } static ESubsequentsMode::Type GetSubsequentsMode() { return ESubsequentsMode::TrackSubsequents; } @@ -338,15 +359,13 @@ public: } }; - - void FRHICommandListExecutor::ExecuteInner(FRHICommandListBase& CmdList) { check(CmdList.HasCommands()); bool bIsInRenderingThread = IsInRenderingThread(); bool bIsInGameThread = IsInGameThread(); - if (GRHIThread) + if (IsRunningRHIInSeparateThread()) { bool bAsyncSubmit = false; if (bIsInRenderingThread) @@ -362,9 +381,9 @@ void FRHICommandListExecutor::ExecuteInner(FRHICommandListBase& CmdList) { RenderThreadSublistDispatchTask = nullptr; if (bAsyncSubmit && RHIThreadTask.GetReference() && RHIThreadTask->IsComplete()) - { - RHIThreadTask = nullptr; - } + { + RHIThreadTask = nullptr; + } } if (!bAsyncSubmit && RHIThreadTask.GetReference() && RHIThreadTask->IsComplete()) { @@ -529,7 +548,7 @@ void FRHICommandListExecutor::ExecuteList(FRHICommandListImmediate& CmdList) void FRHICommandListExecutor::LatchBypass() { #if CAN_TOGGLE_COMMAND_LIST_BYPASS - if (GRHIThread) + if (IsRunningRHIInSeparateThread()) { if (bLatchedBypass) { @@ -637,7 +656,7 @@ struct FRHICommandRHIThreadFence : public FRHICommand { check(IsInRHIThread()); static TArray NewTasks; - Fence->DispatchSubsequents(NewTasks, ENamedThreads::RHIThread); + Fence->DispatchSubsequents(NewTasks, IsRunningRHIInDedicatedThread() ? ENamedThreads::RHIThread : ENamedThreads::AnyThread); Fence = nullptr; } }; @@ -645,7 +664,7 @@ struct FRHICommandRHIThreadFence : public FRHICommand FGraphEventRef FRHICommandListImmediate::RHIThreadFence(bool bSetLockFence) { - check(IsInRenderingThread() && GRHIThread); + check(IsInRenderingThread() && IsRunningRHIInSeparateThread()); FRHICommandRHIThreadFence* Cmd = new (AllocCommand()) FRHICommandRHIThreadFence(); if (bSetLockFence) { @@ -689,7 +708,7 @@ void FRHICommandListExecutor::WaitOnRHIThreadFence(FGraphEventRef& Fence) QUICK_SCOPE_CYCLE_COUNTER(STAT_WaitOnRHIThreadFence_Dispatch); GetImmediateCommandList().ImmediateFlush(EImmediateFlushType::DispatchToRHIThread); // necessary to prevent deadlock } - check(GRHIThread); + check(IsRunningRHIInSeparateThread()); QUICK_SCOPE_CYCLE_COUNTER(STAT_WaitOnRHIThreadFence_Wait); if (FTaskGraphInterface::Get().IsThreadProcessingTasks(ENamedThreads::RenderThread_Local)) { @@ -746,7 +765,6 @@ void FRHICommandListBase::Reset() RenderThreadContexts[Index] = nullptr; } ExecuteStat = TStatId(); - FlushStateCache(); } @@ -843,7 +861,7 @@ struct FRHICommandWaitForAndSubmitSubListParallel : public FRHICommandIsComplete() && !(!GRHIThread || !IsInRHIThread())) + if (EventToWaitFor.GetReference() && !EventToWaitFor->IsComplete() && !(!IsRunningRHIInSeparateThread() || !IsInRHIThread())) { GEventToWaitFor = EventToWaitFor.GetReference(); FPlatformMisc::DebugBreak(); @@ -885,7 +903,7 @@ struct FRHICommandWaitForAndSubmitSubList : public FRHICommandIsComplete()) { - check(!GRHIThread || !IsInRHIThread()); // things should not be dispatched if they can't complete without further waits + check(!IsRunningRHIInSeparateThread() || !IsInRHIThread()); // things should not be dispatched if they can't complete without further waits SCOPE_CYCLE_COUNTER(STAT_ChainWait); if (IsInRenderingThread()) { @@ -1020,8 +1038,8 @@ void FRHICommandListBase::QueueParallelAsyncCommandListSubmit(FGraphEventRef* An { QUICK_SCOPE_CYCLE_COUNTER(STAT_FRHICommandListBase_QueueParallelAsyncCommandListSubmit); check(IsInRenderingThread() && IsImmediate() && Num); - FlushStateCache(); - if (GRHIThread) + + if (IsRunningRHIInSeparateThread()) { FRHICommandListExecutor::GetImmediateCommandList().ImmediateFlush(EImmediateFlushType::DispatchToRHIThread); // we should start on the stuff before this async list @@ -1039,14 +1057,14 @@ void FRHICommandListBase::QueueParallelAsyncCommandListSubmit(FGraphEventRef* An } #endif - if (Num && GRHIThread) + if (Num && IsRunningRHIInSeparateThread()) { static const auto ICVarRHICmdBalanceParallelLists = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.RHICmdBalanceParallelLists")); if (ICVarRHICmdBalanceParallelLists->GetValueOnRenderThread() == 0 && CVarRHICmdBalanceTranslatesAfterTasks.GetValueOnRenderThread() > 0 && GRHISupportsParallelRHIExecute && CVarRHICmdUseDeferredContexts.GetValueOnAnyThread() > 0) { FGraphEventArray Prereq; - FRHICommandListBase** RHICmdLists = (FRHICommandListBase**)Alloc(sizeof(FRHICommandListBase*) * Num, ALIGNOF(FRHICommandListBase*)); + FRHICommandListBase** RHICmdLists = (FRHICommandListBase**)Alloc(sizeof(FRHICommandListBase*) * Num, alignof(FRHICommandListBase*)); for (int32 Index = 0; Index < Num; Index++) { FGraphEventRef& AnyThreadCompletionEvent = AnyThreadCompletionEvents[Index]; @@ -1068,7 +1086,7 @@ void FRHICommandListBase::QueueParallelAsyncCommandListSubmit(FGraphEventRef* An FGraphEventRef TranslateSetupCompletionEvent = TGraphTask::CreateTask(&Prereq, ENamedThreads::RenderThread).ConstructAndDispatchWhenReady(CmdList, &RHICmdLists[0], Num, bIsPrepass); QueueCommandListSubmit(CmdList); AllOutstandingTasks.Add(TranslateSetupCompletionEvent); - if (GRHIThread) + if (IsRunningRHIInSeparateThread()) { FRHICommandListExecutor::GetImmediateCommandList().ImmediateFlush(EImmediateFlushType::DispatchToRHIThread); // we don't want stuff after the async cmd list to be bundled with it } @@ -1136,7 +1154,7 @@ void FRHICommandListBase::QueueParallelAsyncCommandListSubmit(FGraphEventRef* An check(ContextContainer); FGraphEventArray Prereq; - FRHICommandListBase** RHICmdLists = (FRHICommandListBase**)Alloc(sizeof(FRHICommandListBase*) * (1 + Last - Start), ALIGNOF(FRHICommandListBase*)); + FRHICommandListBase** RHICmdLists = (FRHICommandListBase**)Alloc(sizeof(FRHICommandListBase*) * (1 + Last - Start), alignof(FRHICommandListBase*)); for (int32 Index = Start; Index <= Last; Index++) { FGraphEventRef& AnyThreadCompletionEvent = AnyThreadCompletionEvents[Index]; @@ -1161,7 +1179,7 @@ void FRHICommandListBase::QueueParallelAsyncCommandListSubmit(FGraphEventRef* An AllOutstandingTasks.Add(TranslateCompletionEvent); new (AllocCommand()) FRHICommandWaitForAndSubmitSubListParallel(TranslateCompletionEvent, ContextContainer, EffectiveThreads, ThreadIndex++); - if (GRHIThread) + if (IsRunningRHIInSeparateThread()) { FRHICommandListExecutor::GetImmediateCommandList().ImmediateFlush(EImmediateFlushType::DispatchToRHIThread); // we don't want stuff after the async cmd list to be bundled with it } @@ -1185,7 +1203,7 @@ void FRHICommandListBase::QueueParallelAsyncCommandListSubmit(FGraphEventRef* An FRHICommandList* CmdList = CmdLists[Index]; if (AnyThreadCompletionEvent.GetReference()) { - if (GRHIThread) + if (IsRunningRHIInSeparateThread()) { AllOutstandingTasks.Add(AnyThreadCompletionEvent); } @@ -1193,7 +1211,7 @@ void FRHICommandListBase::QueueParallelAsyncCommandListSubmit(FGraphEventRef* An } new (AllocCommand()) FRHICommandWaitForAndSubmitSubList(AnyThreadCompletionEvent, CmdList); } - if (GRHIThread) + if (IsRunningRHIInSeparateThread()) { FRHICommandListExecutor::GetImmediateCommandList().ImmediateFlush(EImmediateFlushType::DispatchToRHIThread); // we don't want stuff after the async cmd list to be bundled with it } @@ -1202,22 +1220,21 @@ void FRHICommandListBase::QueueParallelAsyncCommandListSubmit(FGraphEventRef* An void FRHICommandListBase::QueueAsyncCommandListSubmit(FGraphEventRef& AnyThreadCompletionEvent, class FRHICommandList* CmdList) { check(IsInRenderingThread() && IsImmediate()); - FlushStateCache(); - if (GRHIThread) + if (IsRunningRHIInSeparateThread()) { FRHICommandListExecutor::GetImmediateCommandList().ImmediateFlush(EImmediateFlushType::DispatchToRHIThread); // we should start on the stuff before this async list } if (AnyThreadCompletionEvent.GetReference()) { - if (GRHIThread) + if (IsRunningRHIInSeparateThread()) { AllOutstandingTasks.Add(AnyThreadCompletionEvent); } WaitOutstandingTasks.Add(AnyThreadCompletionEvent); } new (AllocCommand()) FRHICommandWaitForAndSubmitSubList(AnyThreadCompletionEvent, CmdList); - if (GRHIThread) + if (IsRunningRHIInSeparateThread()) { FRHICommandListExecutor::GetImmediateCommandList().ImmediateFlush(EImmediateFlushType::DispatchToRHIThread); // we don't want stuff after the async cmd list to be bundled with it } @@ -1243,7 +1260,7 @@ struct FRHICommandWaitForAndSubmitRTSubList : public FRHICommandIsComplete()) { SCOPE_CYCLE_COUNTER(STAT_RTChainWait); - check(!GRHIThread || !IsInRHIThread()); // things should not be dispatched if they can't complete without further waits + check(!IsRunningRHIInSeparateThread() || !IsInRHIThread()); // things should not be dispatched if they can't complete without further waits if (IsInRenderingThread()) { if (FTaskGraphInterface::Get().IsThreadProcessingTasks(ENamedThreads::RenderThread_Local)) @@ -1270,7 +1287,7 @@ struct FRHICommandWaitForAndSubmitRTSubList : public FRHICommand void FRHICommandListBase::QueueCommandListSubmit(class FRHICommandList* CmdList) { - FlushStateCache(); new (AllocCommand()) FRHICommandSubmitSubList(CmdList); } @@ -1320,7 +1336,7 @@ void FRHICommandList::BeginScene() return; } new (AllocCommand()) FRHICommandBeginScene(); - if (!GRHIThread) + if (!IsRunningRHIInSeparateThread()) { // if we aren't running an RHIThread, there is no good reason to buffer this frame advance stuff and that complicates state management, so flush everything out now QUICK_SCOPE_CYCLE_COUNTER(BeginScene_Flush); @@ -1336,7 +1352,7 @@ void FRHICommandList::EndScene() return; } new (AllocCommand()) FRHICommandEndScene(); - if (!GRHIThread) + if (!IsRunningRHIInSeparateThread()) { // if we aren't running an RHIThread, there is no good reason to buffer this frame advance stuff and that complicates state management, so flush everything out now QUICK_SCOPE_CYCLE_COUNTER(EndScene_Flush); @@ -1354,7 +1370,7 @@ void FRHICommandList::BeginDrawingViewport(FViewportRHIParamRef Viewport, FTextu return; } new (AllocCommand()) FRHICommandBeginDrawingViewport(Viewport, RenderTargetRHI); - if (!GRHIThread) + if (!IsRunningRHIInSeparateThread()) { // if we aren't running an RHIThread, there is no good reason to buffer this frame advance stuff and that complicates state management, so flush everything out now QUICK_SCOPE_CYCLE_COUNTER(BeginDrawingViewport_Flush); @@ -1373,7 +1389,7 @@ void FRHICommandList::EndDrawingViewport(FViewportRHIParamRef Viewport, bool bPr { new (AllocCommand()) FRHICommandEndDrawingViewport(Viewport, bPresent, bLockToVsync); - if ( GRHIThread ) + if (IsRunningRHIInSeparateThread()) { // Insert a fence to prevent the renderthread getting more than a frame ahead of the RHIThread GRHIThreadEndDrawingViewportFences[GRHIThreadEndDrawingViewportFenceIndex] = static_cast(this)->RHIThreadFence(); @@ -1385,7 +1401,7 @@ void FRHICommandList::EndDrawingViewport(FViewportRHIParamRef Viewport, bool bPr } } - if ( GRHIThread ) + if (IsRunningRHIInSeparateThread()) { // Wait on the previous frame's RHI thread fence (we never want the rendering thread to get more than a frame ahead) uint32 PreviousFrameFenceIndex = 1 - GRHIThreadEndDrawingViewportFenceIndex; @@ -1407,7 +1423,7 @@ void FRHICommandList::BeginFrame() return; } new (AllocCommand()) FRHICommandBeginFrame(); - if (!GRHIThread) + if (!IsRunningRHIInSeparateThread()) { // if we aren't running an RHIThread, there is no good reason to buffer this frame advance stuff and that complicates state management, so flush everything out now QUICK_SCOPE_CYCLE_COUNTER(BeginFrame_Flush); @@ -1424,7 +1440,7 @@ void FRHICommandList::EndFrame() return; } new (AllocCommand()) FRHICommandEndFrame(); - if (!GRHIThread) + if (!IsRunningRHIInSeparateThread()) { // if we aren't running an RHIThread, there is no good reason to buffer this frame advance stuff and that complicates state management, so flush everything out now QUICK_SCOPE_CYCLE_COUNTER(EndFrame_Flush); @@ -1464,7 +1480,7 @@ FScopedCommandListWaitForTasks::~FScopedCommandListWaitForTasks() check(IsInRenderingThread()); if (bWaitForTasks) { - if (GRHIThread) + if (IsRunningRHIInSeparateThread()) { #if 0 { @@ -1513,42 +1529,8 @@ void FRHICommandListBase::WaitForDispatch() DECLARE_CYCLE_STAT(TEXT("Explicit wait for RHI thread"), STAT_ExplicitWaitRHIThread, STATGROUP_RHICMDLIST); DECLARE_CYCLE_STAT(TEXT("Explicit wait for RHI thread async dispatch"), STAT_ExplicitWaitRHIThread_Dispatch, STATGROUP_RHICMDLIST); DECLARE_CYCLE_STAT(TEXT("Deep spin for stray resource init"), STAT_SpinWaitRHIThread, STATGROUP_RHICMDLIST); -DECLARE_CYCLE_STAT(TEXT("Spin RHIThread unstall"), STAT_SpinWaitRHIThreadUnstall, STATGROUP_RHICMDLIST); DECLARE_CYCLE_STAT(TEXT("Spin RHIThread wait for stall"), STAT_SpinWaitRHIThreadStall, STATGROUP_RHICMDLIST); -static FGraphEventRef GRHIThreadStallTask; -static FEvent* GRHIThreadStallEvent = nullptr; - -class FStallRHIThreadTask -{ - FEvent* RHIThreadStallEvent; -public: - - FStallRHIThreadTask(FEvent* InRHIThreadStallEvent) - : RHIThreadStallEvent(InRHIThreadStallEvent) - { - } - - FORCEINLINE TStatId GetStatId() const - { - RETURN_QUICK_DECLARE_CYCLE_STAT(STAT_STallRHIThread, STATGROUP_TaskGraphTasks); - } - - ENamedThreads::Type GetDesiredThread() - { - check(GRHIThread); // this should never be used on a platform that doesn't support the RHI thread - return ENamedThreads::RHIThread; - } - - static ESubsequentsMode::Type GetSubsequentsMode() { return ESubsequentsMode::TrackSubsequents; } - - void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent) - { - GRHIThreadStallTask = MyCompletionGraphEvent; - FPlatformMisc::MemoryBarrier(); - RHIThreadStallEvent->Wait(); - } -}; int32 StallCount = 0; bool FRHICommandListImmediate::IsStalled() @@ -1558,9 +1540,7 @@ bool FRHICommandListImmediate::IsStalled() bool FRHICommandListImmediate::StallRHIThread() { - FPlatformAtomics::InterlockedIncrement(&StallCount); - - check(IsInRenderingThread() && GRHIThread && !GRHIThreadStallTask.GetReference()); + check(IsInRenderingThread() && IsRunningRHIInSeparateThread()); bool bAsyncSubmit = CVarRHICmdAsyncRHIThreadDispatch.GetValueOnRenderThread() > 0; if (bAsyncSubmit) { @@ -1579,15 +1559,10 @@ bool FRHICommandListImmediate::StallRHIThread() return false; } } - if (!GRHIThreadStallEvent) + FPlatformAtomics::InterlockedIncrement(&StallCount); { - GRHIThreadStallEvent = FPlatformProcess::GetSynchEventFromPool(); - } - TGraphTask::CreateTask(nullptr, ENamedThreads::RenderThread).ConstructAndDispatchWhenReady(GRHIThreadStallEvent); - SCOPE_CYCLE_COUNTER(STAT_SpinWaitRHIThreadStall); - while (!GRHIThreadStallTask.GetReference()) - { - FPlatformProcess::SleepNoStats(0); + SCOPE_CYCLE_COUNTER(STAT_SpinWaitRHIThreadStall); + GRHIThreadOnTasksCritical.Lock(); } return true; } @@ -1600,18 +1575,11 @@ bool FRHICommandListImmediate::StallRHIThread() void FRHICommandListImmediate::UnStallRHIThread() { - check(IsInRenderingThread() && GRHIThread && GRHIThreadStallTask.GetReference() && !GRHIThreadStallTask->IsComplete() && GRHIThreadStallEvent); - GRHIThreadStallEvent->Trigger(); - SCOPE_CYCLE_COUNTER(STAT_SpinWaitRHIThreadUnstall); - while (!GRHIThreadStallTask->IsComplete()) - { - FPlatformProcess::SleepNoStats(0); - } - GRHIThreadStallTask = nullptr; + check(IsInRenderingThread() && IsRunningRHIInSeparateThread()); + GRHIThreadOnTasksCritical.Unlock(); FPlatformAtomics::InterlockedDecrement(&StallCount); } - void FRHICommandListBase::WaitForRHIThreadTasks() { check(IsImmediate() && IsInRenderingThread()); @@ -1742,6 +1710,13 @@ FVertexBufferRHIRef FDynamicRHI::CreateVertexBuffer_RenderThread(class FRHIComma FScopedRHIThreadStaller StallRHIThread(RHICmdList); return GDynamicRHI->RHICreateVertexBuffer(Size, InUsage, CreateInfo); } + +FStructuredBufferRHIRef FDynamicRHI::CreateStructuredBuffer_RenderThread(class FRHICommandListImmediate& RHICmdList, uint32 Stride, uint32 Size, uint32 InUsage, FRHIResourceCreateInfo& CreateInfo) +{ + FScopedRHIThreadStaller StallRHIThread(RHICmdList); + return GDynamicRHI->RHICreateStructuredBuffer(Stride, Size, InUsage, CreateInfo); +} + FIndexBufferRHIRef FDynamicRHI::CreateIndexBuffer_RenderThread(class FRHICommandListImmediate& RHICmdList, uint32 Stride, uint32 Size, uint32 InUsage, FRHIResourceCreateInfo& CreateInfo) { FScopedRHIThreadStaller StallRHIThread(RHICmdList); @@ -1869,7 +1844,7 @@ void* FDynamicRHI::LockVertexBuffer_RenderThread(class FRHICommandListImmediate& check(IsInRenderingThread()); bool bBuffer = CVarRHICmdBufferWriteLocks.GetValueOnRenderThread() > 0; void* Result; - if (!bBuffer || LockMode != RLM_WriteOnly || RHICmdList.Bypass() || !GRHIThread) + if (!bBuffer || LockMode != RLM_WriteOnly || RHICmdList.Bypass() || !IsRunningRHIInSeparateThread()) { QUICK_SCOPE_CYCLE_COUNTER(STAT_RHIMETHOD_LockVertexBuffer_Flush); RHICmdList.ImmediateFlush(EImmediateFlushType::FlushRHIThread); @@ -1891,7 +1866,7 @@ void FDynamicRHI::UnlockVertexBuffer_RenderThread(class FRHICommandListImmediate check(IsInRenderingThread()); bool bBuffer = CVarRHICmdBufferWriteLocks.GetValueOnRenderThread() > 0; FLockTracker::FLockParams Params = GLockTracker.Unlock(VertexBuffer); - if (!bBuffer || Params.LockMode != RLM_WriteOnly || RHICmdList.Bypass() || !GRHIThread) + if (!bBuffer || Params.LockMode != RLM_WriteOnly || RHICmdList.Bypass() || !IsRunningRHIInSeparateThread()) { QUICK_SCOPE_CYCLE_COUNTER(STAT_RHIMETHOD_UnlockVertexBuffer_Flush); RHICmdList.ImmediateFlush(EImmediateFlushType::FlushRHIThread); @@ -1918,7 +1893,7 @@ void* FDynamicRHI::LockIndexBuffer_RenderThread(class FRHICommandListImmediate& check(IsInRenderingThread()); bool bBuffer = CVarRHICmdBufferWriteLocks.GetValueOnRenderThread() > 0; void* Result; - if (!bBuffer || LockMode != RLM_WriteOnly || RHICmdList.Bypass() || !GRHIThread) + if (!bBuffer || LockMode != RLM_WriteOnly || RHICmdList.Bypass() || !IsRunningRHIInSeparateThread()) { QUICK_SCOPE_CYCLE_COUNTER(STAT_RHIMETHOD_LockIndexBuffer_Flush); RHICmdList.ImmediateFlush(EImmediateFlushType::FlushRHIThread); @@ -1940,7 +1915,7 @@ void FDynamicRHI::UnlockIndexBuffer_RenderThread(class FRHICommandListImmediate& check(IsInRenderingThread()); bool bBuffer = CVarRHICmdBufferWriteLocks.GetValueOnRenderThread() > 0; FLockTracker::FLockParams Params = GLockTracker.Unlock(IndexBuffer); - if (!bBuffer || Params.LockMode != RLM_WriteOnly || RHICmdList.Bypass() || !GRHIThread) + if (!bBuffer || Params.LockMode != RLM_WriteOnly || RHICmdList.Bypass() || !IsRunningRHIInSeparateThread()) { QUICK_SCOPE_CYCLE_COUNTER(STAT_RHIMETHOD_UnlockIndexBuffer_Flush); RHICmdList.ImmediateFlush(EImmediateFlushType::FlushRHIThread); @@ -2113,6 +2088,12 @@ FTexture2DRHIRef FDynamicRHI::RHICreateTexture2D_RenderThread(class FRHICommandL return GDynamicRHI->RHICreateTexture2D(SizeX, SizeY, Format, NumMips, NumSamples, Flags, CreateInfo); } +FTexture2DRHIRef FDynamicRHI::RHICreateTextureExternal2D_RenderThread(class FRHICommandListImmediate& RHICmdList, uint32 SizeX, uint32 SizeY, uint8 Format, uint32 NumMips, uint32 NumSamples, uint32 Flags, FRHIResourceCreateInfo& CreateInfo) +{ + FScopedRHIThreadStaller StallRHIThread(RHICmdList); + return GDynamicRHI->RHICreateTextureExternal2D(SizeX, SizeY, Format, NumMips, NumSamples, Flags, CreateInfo); +} + FTexture2DArrayRHIRef FDynamicRHI::RHICreateTexture2DArray_RenderThread(class FRHICommandListImmediate& RHICmdList, uint32 SizeX, uint32 SizeY, uint32 SizeZ, uint8 Format, uint32 NumMips, uint32 Flags, FRHIResourceCreateInfo& CreateInfo) { FScopedRHIThreadStaller StallRHIThread(RHICmdList); @@ -2213,7 +2194,7 @@ FRenderQueryRHIRef FDynamicRHI::RHICreateRenderQuery_RenderThread(class FRHIComm void FRHICommandListImmediate::UpdateTextureReference(FTextureReferenceRHIParamRef TextureRef, FTextureRHIParamRef NewTexture) { - if (Bypass() || !GRHIThread || CVarRHICmdFlushUpdateTextureReference.GetValueOnRenderThread() > 0) + if (Bypass() || !IsRunningRHIInSeparateThread() || CVarRHICmdFlushUpdateTextureReference.GetValueOnRenderThread() > 0) { { QUICK_SCOPE_CYCLE_COUNTER(STAT_RHIMETHOD_UpdateTextureReference_FlushRHI); diff --git a/Engine/Source/Runtime/RHI/Public/DynamicRHI.h b/Engine/Source/Runtime/RHI/Public/DynamicRHI.h index 16c15e9b6af4..223efb503230 100644 --- a/Engine/Source/Runtime/RHI/Public/DynamicRHI.h +++ b/Engine/Source/Runtime/RHI/Public/DynamicRHI.h @@ -853,6 +853,21 @@ public: // FlushType: Wait RHI Thread virtual FTexture2DRHIRef RHICreateTexture2D(uint32 SizeX, uint32 SizeY, uint8 Format, uint32 NumMips, uint32 NumSamples, uint32 Flags, FRHIResourceCreateInfo& CreateInfo) = 0; + /** + * Creates a 2D RHI texture external resource + * @param SizeX - width of the texture to create + * @param SizeY - height of the texture to create + * @param Format - EPixelFormat texture format + * @param NumMips - number of mips to generate or 0 for full mip pyramid + * @param NumSamples - number of MSAA samples, usually 1 + * @param Flags - ETextureCreateFlags creation flags + */ + // FlushType: Wait RHI Thread + virtual FTexture2DRHIRef RHICreateTextureExternal2D(uint32 SizeX, uint32 SizeY, uint8 Format, uint32 NumMips, uint32 NumSamples, uint32 Flags, FRHIResourceCreateInfo& CreateInfo) + { + return nullptr; + } + /** * Creates an FStructuredBuffer for the RT write mask of a render target * @param RenderTarget - the RT to create the buffer for @@ -1302,6 +1317,7 @@ public: virtual FIndexBufferRHIRef CreateAndLockIndexBuffer_RenderThread(class FRHICommandListImmediate& RHICmdList, uint32 Stride, uint32 Size, uint32 InUsage, FRHIResourceCreateInfo& CreateInfo, void*& OutDataBuffer); virtual FVertexBufferRHIRef CreateVertexBuffer_RenderThread(class FRHICommandListImmediate& RHICmdList, uint32 Size, uint32 InUsage, FRHIResourceCreateInfo& CreateInfo); + virtual FStructuredBufferRHIRef CreateStructuredBuffer_RenderThread(class FRHICommandListImmediate& RHICmdList, uint32 Stride, uint32 Size, uint32 InUsage, FRHIResourceCreateInfo& CreateInfo); virtual FShaderResourceViewRHIRef CreateShaderResourceView_RenderThread(class FRHICommandListImmediate& RHICmdList, FVertexBufferRHIParamRef VertexBuffer, uint32 Stride, uint8 Format); virtual FShaderResourceViewRHIRef CreateShaderResourceView_RenderThread(class FRHICommandListImmediate& RHICmdList, FIndexBufferRHIParamRef Buffer); virtual void* LockVertexBuffer_RenderThread(class FRHICommandListImmediate& RHICmdList, FVertexBufferRHIParamRef VertexBuffer, uint32 Offset, uint32 SizeRHI, EResourceLockMode LockMode); @@ -1333,6 +1349,7 @@ public: virtual void UpdateTexture3D_RenderThread(class FRHICommandListImmediate& RHICmdList, FTexture3DRHIParamRef Texture, uint32 MipIndex, const struct FUpdateTextureRegion3D& UpdateRegion, uint32 SourceRowPitch, uint32 SourceDepthPitch, const uint8* SourceData); virtual FTexture2DRHIRef RHICreateTexture2D_RenderThread(class FRHICommandListImmediate& RHICmdList, uint32 SizeX, uint32 SizeY, uint8 Format, uint32 NumMips, uint32 NumSamples, uint32 Flags, FRHIResourceCreateInfo& CreateInfo); + virtual FTexture2DRHIRef RHICreateTextureExternal2D_RenderThread(class FRHICommandListImmediate& RHICmdList, uint32 SizeX, uint32 SizeY, uint8 Format, uint32 NumMips, uint32 NumSamples, uint32 Flags, FRHIResourceCreateInfo& CreateInfo); virtual FTexture2DArrayRHIRef RHICreateTexture2DArray_RenderThread(class FRHICommandListImmediate& RHICmdList, uint32 SizeX, uint32 SizeY, uint32 SizeZ, uint8 Format, uint32 NumMips, uint32 Flags, FRHIResourceCreateInfo& CreateInfo); virtual FTexture3DRHIRef RHICreateTexture3D_RenderThread(class FRHICommandListImmediate& RHICmdList, uint32 SizeX, uint32 SizeY, uint32 SizeZ, uint8 Format, uint32 NumMips, uint32 Flags, FRHIResourceCreateInfo& CreateInfo); virtual FUnorderedAccessViewRHIRef RHICreateUnorderedAccessView_RenderThread(class FRHICommandListImmediate& RHICmdList, FStructuredBufferRHIParamRef StructuredBuffer, bool bUseUAVCounter, bool bAppendBuffer); @@ -1349,6 +1366,13 @@ public: virtual FTextureCubeRHIRef RHICreateTextureCube_RenderThread(class FRHICommandListImmediate& RHICmdList, uint32 Size, uint8 Format, uint32 NumMips, uint32 Flags, FRHIResourceCreateInfo& CreateInfo); virtual FTextureCubeRHIRef RHICreateTextureCubeArray_RenderThread(class FRHICommandListImmediate& RHICmdList, uint32 Size, uint32 ArraySize, uint8 Format, uint32 NumMips, uint32 Flags, FRHIResourceCreateInfo& CreateInfo); virtual FRenderQueryRHIRef RHICreateRenderQuery_RenderThread(class FRHICommandListImmediate& RHICmdList, ERenderQueryType QueryType); + + virtual void RHIAcquireTransientResource_RenderThread(FTextureRHIParamRef Texture) { } + virtual void RHIDiscardTransientResource_RenderThread(FTextureRHIParamRef Texture) { } + virtual void RHIAcquireTransientResource_RenderThread(FVertexBufferRHIParamRef Buffer) { } + virtual void RHIDiscardTransientResource_RenderThread(FVertexBufferRHIParamRef Buffer) { } + virtual void RHIAcquireTransientResource_RenderThread(FStructuredBufferRHIParamRef Buffer) { } + virtual void RHIDiscardTransientResource_RenderThread(FStructuredBufferRHIParamRef Buffer) { } //Utilities virtual void EnableIdealGPUCaptureOptions(bool bEnable); @@ -1556,4 +1580,3 @@ public: * Called to create the instance of the dynamic RHI. */ FDynamicRHI* PlatformCreateDynamicRHI(); - diff --git a/Engine/Source/Runtime/RHI/Public/GPUDefragAllocator.h b/Engine/Source/Runtime/RHI/Public/GPUDefragAllocator.h index 77354aad2c9d..54698feabb00 100644 --- a/Engine/Source/Runtime/RHI/Public/GPUDefragAllocator.h +++ b/Engine/Source/Runtime/RHI/Public/GPUDefragAllocator.h @@ -399,6 +399,10 @@ public: , bBenchmarkMode(false) {} + virtual ~FGPUDefragAllocator() + { + } + /** * Initialize this allocator with a preallocated block of memory. * @@ -938,7 +942,7 @@ protected: // Resize base chunk. BaseChunk->Size = FirstSize; - } + } //-V773 /** * Marks the specified chunk as 'allocated' and updates tracking variables. diff --git a/Engine/Source/Runtime/RHI/Public/GPUProfiler.h b/Engine/Source/Runtime/RHI/Public/GPUProfiler.h index 8a607deabd75..c17de3cf032c 100644 --- a/Engine/Source/Runtime/RHI/Public/GPUProfiler.h +++ b/Engine/Source/Runtime/RHI/Public/GPUProfiler.h @@ -219,6 +219,10 @@ struct RHI_API FGPUProfiler { } + virtual ~FGPUProfiler() + { + } + void RegisterGPUWork(uint32 NumPrimitives = 0, uint32 NumVertices = 0) { if (bTrackingEvents && CurrentEventNode) diff --git a/Engine/Source/Runtime/RHI/Public/RHI.h b/Engine/Source/Runtime/RHI/Public/RHI.h index c0d478d87fac..c5629823ad3c 100644 --- a/Engine/Source/Runtime/RHI/Public/RHI.h +++ b/Engine/Source/Runtime/RHI/Public/RHI.h @@ -153,6 +153,9 @@ extern RHI_API bool GSupportsTexture3D; /** true if the RHI supports mobile multi-view */ extern RHI_API bool GSupportsMobileMultiView; +/** true if the RHI supports image external */ +extern RHI_API bool GSupportsImageExternal; + /** true if the RHI supports SRVs */ extern RHI_API bool GSupportsResourceView; @@ -177,6 +180,9 @@ extern RHI_API bool GSupportsHDR32bppEncodeModeIntrinsic; /** True if the RHI supports getting the result of occlusion queries when on a thread other than the renderthread */ extern RHI_API bool GSupportsParallelOcclusionQueries; +/** true if the RHI supports aliasing of transient resources */ +extern RHI_API bool GSupportsTransientResourceAliasing; + /** The minimum Z value in clip space for the RHI. */ extern RHI_API float GMinClipZ; @@ -293,6 +299,8 @@ Requirements for RHI thread * BeginDrawingViewport, and 5 or so other frame advance methods are queued with an RHIThread. Without an RHIThread, these just flush internally. ***/ extern RHI_API bool GRHISupportsRHIThread; +/* as above, but we run the commands on arbitrary task threads */ +extern RHI_API bool GRHISupportsRHIOnTaskThread; /** Whether or not the RHI supports parallel RHIThread executes / translates Requirements: @@ -818,7 +826,7 @@ struct FVRamAllocation { } - bool IsValid() { return AllocationSize > 0; } + bool IsValid() const { return AllocationSize > 0; } // in bytes uint32 AllocationStart; @@ -932,7 +940,7 @@ struct FClearValueBinding static RHI_API const FClearValueBinding DepthNear; static RHI_API const FClearValueBinding DepthFar; static RHI_API const FClearValueBinding Green; - static RHI_API const FClearValueBinding MidGray; + static RHI_API const FClearValueBinding DefaultNormal8Bit; }; struct FRHIResourceCreateInfo @@ -941,6 +949,7 @@ struct FRHIResourceCreateInfo : BulkData(nullptr) , ResourceArray(nullptr) , ClearValueBinding(FLinearColor::Transparent) + , DebugName(NULL) {} // for CreateTexture calls @@ -948,6 +957,7 @@ struct FRHIResourceCreateInfo : BulkData(InBulkData) , ResourceArray(nullptr) , ClearValueBinding(FLinearColor::Transparent) + , DebugName(NULL) {} // for CreateVertexBuffer/CreateStructuredBuffer calls @@ -955,12 +965,14 @@ struct FRHIResourceCreateInfo : BulkData(nullptr) , ResourceArray(InResourceArray) , ClearValueBinding(FLinearColor::Transparent) + , DebugName(NULL) {} FRHIResourceCreateInfo(const FClearValueBinding& InClearValueBinding) : BulkData(nullptr) , ResourceArray(nullptr) , ClearValueBinding(InClearValueBinding) + , DebugName(NULL) { } @@ -971,6 +983,7 @@ struct FRHIResourceCreateInfo // for binding clear colors to rendertargets. FClearValueBinding ClearValueBinding; + const TCHAR* DebugName; }; // Forward-declaration. diff --git a/Engine/Source/Runtime/RHI/Public/RHICommandList.h b/Engine/Source/Runtime/RHI/Public/RHICommandList.h index 418f04c639f6..a63c31436dc2 100644 --- a/Engine/Source/Runtime/RHI/Public/RHICommandList.h +++ b/Engine/Source/Runtime/RHI/Public/RHICommandList.h @@ -8,7 +8,6 @@ #include "CoreTypes.h" #include "Misc/AssertionMacros.h" #include "HAL/UnrealMemory.h" -#include "Templates/AlignOf.h" #include "Templates/UnrealTemplate.h" #include "Math/Color.h" #include "Math/IntPoint.h" @@ -57,6 +56,7 @@ class FGraphicsPipelineState; DECLARE_STATS_GROUP(TEXT("RHICmdList"), STATGROUP_RHICMDLIST, STATCAT_Advanced); + // set this one to get a stat for each RHI command #define RHI_STATS 0 @@ -66,7 +66,40 @@ DECLARE_STATS_GROUP(TEXT("RHICommands"),STATGROUP_RHI_COMMANDS, STATCAT_Advanced #else #define RHISTAT(Method) #endif -/** Thread used for RHI */ + +extern RHI_API bool GUseRHIThread_InternalUseOnly; +extern RHI_API bool GUseRHITaskThreads_InternalUseOnly; +extern RHI_API bool GIsRunningRHIInSeparateThread_InternalUseOnly; +extern RHI_API bool GIsRunningRHIInDedicatedThread_InternalUseOnly; +extern RHI_API bool GIsRunningRHIInTaskThread_InternalUseOnly; + +/** +* Whether the RHI commands are being run in a thread other than the render thread +*/ +bool FORCEINLINE IsRunningRHIInSeparateThread() +{ + return GIsRunningRHIInSeparateThread_InternalUseOnly; +} + +/** +* Whether the RHI commands are being run on a dedicated thread other than the render thread +*/ +bool FORCEINLINE IsRunningRHIInDedicatedThread() +{ + return GIsRunningRHIInDedicatedThread_InternalUseOnly; +} + +/** +* Whether the RHI commands are being run on a dedicated thread other than the render thread +*/ +bool FORCEINLINE IsRunningRHIInTaskThread() +{ + return GIsRunningRHIInTaskThread_InternalUseOnly; +} + + + + extern RHI_API bool GEnableAsyncCompute; extern RHI_API TAutoConsoleVariable CVarRHICmdWidth; extern RHI_API TAutoConsoleVariable CVarRHICmdFlushRenderThreadTasks; @@ -187,7 +220,7 @@ public: template FORCEINLINE_DEBUGGABLE void* Alloc() { - return Alloc(sizeof(T), ALIGNOF(T)); + return Alloc(sizeof(T), alignof(T)); } template @@ -305,7 +338,6 @@ public: Num }; void *RenderThreadContexts[(int32)ERenderThreadContext::Num]; - static int32 StateCacheEnabled; protected: //the values of this struct must be copied when the commandlist is split @@ -316,9 +348,6 @@ protected: FRHIDepthRenderTargetView CachedDepthStencilTarget; } PSOContext; - struct FRHICommandSetRasterizerState* CachedRasterizerState; - struct FRHICommandSetDepthStencilState* CachedDepthStencilState; - void CacheActiveRenderTargets( uint32 NewNumSimultaneousRenderTargets, const FRHIRenderTargetView* NewRenderTargetsRHI, @@ -336,13 +365,6 @@ protected: } public: - void FORCEINLINE FlushStateCache() - { - CachedRasterizerState = nullptr; - CachedDepthStencilState = nullptr; - } - - void CopyRenderThreadContexts(const FRHICommandListBase& ParentCommandList) { for (int32 Index = 0; ERenderThreadContext(Index) < ERenderThreadContext::Num; Index++) @@ -1006,18 +1028,14 @@ struct FRHICommandCopyToResolveTarget : public FRHICommand { - static const int32 MaxTexturesToTransition = 16; int32 NumTextures; - FTextureRHIParamRef Textures[MaxTexturesToTransition]; + FTextureRHIParamRef* Textures; // Pointer to an array of textures, allocated inline with the command list EResourceTransitionAccess TransitionType; FORCEINLINE_DEBUGGABLE FRHICommandTransitionTextures(EResourceTransitionAccess InTransitionType, FTextureRHIParamRef* InTextures, int32 InNumTextures) : NumTextures(InNumTextures) + , Textures(InTextures) , TransitionType(InTransitionType) { - for (int32 i = 0; i < NumTextures; ++i) - { - Textures[i] = InTextures[i]; - } } RHI_API void Execute(FRHICommandListBase& CmdList); }; @@ -1857,11 +1875,7 @@ public: CMD_CONTEXT(RHISetRasterizerState)(State); return; } - if (StateCacheEnabled && CachedRasterizerState && CachedRasterizerState->State == State) - { - return; - } - CachedRasterizerState = new(AllocCommand()) FRHICommandSetRasterizerState(State); + new (AllocCommand()) FRHICommandSetRasterizerState(State); } DEPRECATED(4.15, "Use GraphicsPipelineState Interface") @@ -1923,11 +1937,7 @@ public: CMD_CONTEXT(RHISetDepthStencilState)(NewStateRHI, StencilRef); return; } - if (StateCacheEnabled && CachedDepthStencilState && CachedDepthStencilState->State == NewStateRHI && CachedDepthStencilState->StencilRef == StencilRef) - { - return; - } - CachedDepthStencilState = new(AllocCommand()) FRHICommandSetDepthStencilState(NewStateRHI, StencilRef); + new (AllocCommand()) FRHICommandSetDepthStencilState(NewStateRHI, StencilRef); } FORCEINLINE_DEBUGGABLE void SetStencilRef(uint32 StencilRef) @@ -1937,12 +1947,6 @@ public: CMD_CONTEXT(RHISetStencilRef)(StencilRef); return; } - - if (StateCacheEnabled && CachedDepthStencilState && CachedDepthStencilState->StencilRef == StencilRef) - { - return; - } - new(AllocCommand()) FRHICommandSetStencilRef(StencilRef); } @@ -2341,12 +2345,17 @@ public: FORCEINLINE_DEBUGGABLE void TransitionResource(EResourceTransitionAccess TransitionType, FTextureRHIParamRef InTexture) { FTextureRHIParamRef Texture = InTexture; + check(Texture == nullptr || Texture->IsCommitted()); if (Bypass()) { CMD_CONTEXT(RHITransitionResources)(TransitionType, &Texture, 1); return; } - new (AllocCommand()) FRHICommandTransitionTextures(TransitionType, &Texture, 1); + + // Allocate space to hold the single texture pointer inline in the command list itself. + FTextureRHIParamRef* TextureArray = (FTextureRHIParamRef*)Alloc(sizeof(FTextureRHIParamRef), alignof(FTextureRHIParamRef)); + TextureArray[0] = Texture; + new (AllocCommand()) FRHICommandTransitionTextures(TransitionType, TextureArray, 1); } FORCEINLINE_DEBUGGABLE void TransitionResources(EResourceTransitionAccess TransitionType, FTextureRHIParamRef* InTextures, int32 NumTextures) @@ -2356,7 +2365,15 @@ public: CMD_CONTEXT(RHITransitionResources)(TransitionType, InTextures, NumTextures); return; } - new (AllocCommand()) FRHICommandTransitionTextures(TransitionType, InTextures, NumTextures); + + // Allocate space to hold the list of textures inline in the command list itself. + FTextureRHIParamRef* InlineTextureArray = (FTextureRHIParamRef*)Alloc(sizeof(FTextureRHIParamRef) * NumTextures, alignof(FTextureRHIParamRef)); + for (int32 Index = 0; Index < NumTextures; ++Index) + { + InlineTextureArray[Index] = InTextures[Index]; + } + + new (AllocCommand()) FRHICommandTransitionTextures(TransitionType, InlineTextureArray, NumTextures); } FORCEINLINE_DEBUGGABLE void TransitionResourceArrayNoCopy(EResourceTransitionAccess TransitionType, TArray& InTextures) @@ -2372,6 +2389,7 @@ public: FORCEINLINE_DEBUGGABLE void TransitionResource(EResourceTransitionAccess TransitionType, EResourceTransitionPipeline TransitionPipeline, FUnorderedAccessViewRHIParamRef InUAV, FComputeFenceRHIParamRef WriteFence) { FUnorderedAccessViewRHIParamRef UAV = InUAV; + check(InUAV == nullptr || InUAV->IsCommitted()); if (Bypass()) { CMD_CONTEXT(RHITransitionResources)(TransitionType, TransitionPipeline, &UAV, 1, WriteFence); @@ -2382,6 +2400,7 @@ public: FORCEINLINE_DEBUGGABLE void TransitionResource(EResourceTransitionAccess TransitionType, EResourceTransitionPipeline TransitionPipeline, FUnorderedAccessViewRHIParamRef InUAV) { + check(InUAV == nullptr || InUAV->IsCommitted()); TransitionResource(TransitionType, TransitionPipeline, InUAV, nullptr); } @@ -2907,8 +2926,7 @@ public: FORCEINLINE FStructuredBufferRHIRef CreateStructuredBuffer(uint32 Stride, uint32 Size, uint32 InUsage, FRHIResourceCreateInfo& CreateInfo) { - FScopedRHIThreadStaller StallRHIThread(*this); - return GDynamicRHI->RHICreateStructuredBuffer(Stride, Size, InUsage, CreateInfo); + return GDynamicRHI->CreateStructuredBuffer_RenderThread(*this, Stride, Size, InUsage, CreateInfo); } FORCEINLINE void* LockStructuredBuffer(FStructuredBufferRHIParamRef StructuredBuffer, uint32 Offset, uint32 SizeRHI, EResourceLockMode LockMode) @@ -2995,6 +3013,11 @@ public: return GDynamicRHI->RHICreateTexture2D_RenderThread(*this, SizeX, SizeY, Format, NumMips, NumSamples, Flags, CreateInfo); } + FORCEINLINE FTexture2DRHIRef CreateTextureExternal2D(uint32 SizeX, uint32 SizeY, uint8 Format, uint32 NumMips, uint32 NumSamples, uint32 Flags, FRHIResourceCreateInfo& CreateInfo) + { + return GDynamicRHI->RHICreateTextureExternal2D_RenderThread(*this, SizeX, SizeY, Format, NumMips, NumSamples, Flags, CreateInfo); + } + FORCEINLINE FStructuredBufferRHIRef CreateRTWriteMaskBuffer(FTexture2DRHIRef RenderTarget) { return GDynamicRHI->RHICreateRTWriteMaskBuffer(RenderTarget); @@ -3194,7 +3217,79 @@ public: FScopedRHIThreadStaller StallRHIThread(*this); return GDynamicRHI->RHICreateRenderQuery(QueryType); } - + + FORCEINLINE void AcquireTransientResource_RenderThread(FTextureRHIParamRef Texture) + { + if (!Texture->IsCommitted() ) + { + if (GSupportsTransientResourceAliasing) + { + GDynamicRHI->RHIAcquireTransientResource_RenderThread(Texture); + } + Texture->SetCommitted(true); + } + } + + FORCEINLINE void DiscardTransientResource_RenderThread(FTextureRHIParamRef Texture) + { + if (Texture->IsCommitted()) + { + if (GSupportsTransientResourceAliasing) + { + GDynamicRHI->RHIDiscardTransientResource_RenderThread(Texture); + } + Texture->SetCommitted(false); + } + } + + FORCEINLINE void AcquireTransientResource_RenderThread(FVertexBufferRHIParamRef Buffer) + { + if (!Buffer->IsCommitted()) + { + if (GSupportsTransientResourceAliasing) + { + GDynamicRHI->RHIAcquireTransientResource_RenderThread(Buffer); + } + Buffer->SetCommitted(true); + } + } + + FORCEINLINE void DiscardTransientResource_RenderThread(FVertexBufferRHIParamRef Buffer) + { + if (Buffer->IsCommitted()) + { + if (GSupportsTransientResourceAliasing) + { + GDynamicRHI->RHIDiscardTransientResource_RenderThread(Buffer); + } + Buffer->SetCommitted(false); + } + } + + FORCEINLINE void AcquireTransientResource_RenderThread(FStructuredBufferRHIParamRef Buffer) + { + if (!Buffer->IsCommitted()) + { + if (GSupportsTransientResourceAliasing) + { + GDynamicRHI->RHIAcquireTransientResource_RenderThread(Buffer); + } + Buffer->SetCommitted(true); + } + } + + FORCEINLINE void DiscardTransientResource_RenderThread(FStructuredBufferRHIParamRef Buffer) + { + if (Buffer->IsCommitted()) + { + if (GSupportsTransientResourceAliasing) + { + GDynamicRHI->RHIDiscardTransientResource_RenderThread(Buffer); + } + Buffer->SetCommitted(false); + } + } + FORCEINLINE bool GetRenderQueryResult(FRenderQueryRHIParamRef RenderQuery, uint64& OutResult, bool bWait) { return RHIGetRenderQueryResult(RenderQuery, OutResult, bWait); @@ -3799,6 +3894,36 @@ FORCEINLINE FRenderQueryRHIRef RHICreateRenderQuery(ERenderQueryType QueryType) return FRHICommandListExecutor::GetImmediateCommandList().CreateRenderQuery(QueryType); } +FORCEINLINE void RHIAcquireTransientResource(FTextureRHIParamRef Resource) +{ + FRHICommandListExecutor::GetImmediateCommandList().AcquireTransientResource_RenderThread(Resource); +} + +FORCEINLINE void RHIDiscardTransientResource(FTextureRHIParamRef Resource) +{ + FRHICommandListExecutor::GetImmediateCommandList().DiscardTransientResource_RenderThread(Resource); +} + +FORCEINLINE void RHIAcquireTransientResource(FVertexBufferRHIParamRef Resource) +{ + FRHICommandListExecutor::GetImmediateCommandList().AcquireTransientResource_RenderThread(Resource); +} + +FORCEINLINE void RHIDiscardTransientResource(FVertexBufferRHIParamRef Resource) +{ + FRHICommandListExecutor::GetImmediateCommandList().DiscardTransientResource_RenderThread(Resource); +} + +FORCEINLINE void RHIAcquireTransientResource(FStructuredBufferRHIParamRef Resource) +{ + FRHICommandListExecutor::GetImmediateCommandList().AcquireTransientResource_RenderThread(Resource); +} + +FORCEINLINE void RHIDiscardTransientResource(FStructuredBufferRHIParamRef Resource) +{ + FRHICommandListExecutor::GetImmediateCommandList().DiscardTransientResource_RenderThread(Resource); +} + FORCEINLINE void RHIAcquireThreadOwnership() { return FRHICommandListExecutor::GetImmediateCommandList().AcquireThreadOwnership(); diff --git a/Engine/Source/Runtime/RHI/Public/RHICommandList.inl b/Engine/Source/Runtime/RHI/Public/RHICommandList.inl index e03e7d5a8c7f..717515b14430 100644 --- a/Engine/Source/Runtime/RHI/Public/RHICommandList.inl +++ b/Engine/Source/Runtime/RHI/Public/RHICommandList.inl @@ -41,7 +41,7 @@ FORCEINLINE_DEBUGGABLE bool FRHICommandListBase::Bypass() FORCEINLINE_DEBUGGABLE FScopedRHIThreadStaller::FScopedRHIThreadStaller(class FRHICommandListImmediate& InImmed) : Immed(nullptr) { - if (GRHIThread) + if (IsRunningRHIInSeparateThread()) { check(IsInRenderingThread()); if (InImmed.StallRHIThread()) @@ -93,7 +93,7 @@ FORCEINLINE_DEBUGGABLE void FRHICommandListImmediate::ImmediateFlush(EImmediateF GRHICommandList.ExecuteList(*this); } WaitForDispatch(); - if (GRHIThread) + if (IsRunningRHIInSeparateThread()) { WaitForRHIThreadTasks(); } diff --git a/Engine/Source/Runtime/RHI/Public/RHIDefinitions.h b/Engine/Source/Runtime/RHI/Public/RHIDefinitions.h index 3fb32c7975ca..1dcb5c6ff275 100644 --- a/Engine/Source/Runtime/RHI/Public/RHIDefinitions.h +++ b/Engine/Source/Runtime/RHI/Public/RHIDefinitions.h @@ -34,7 +34,7 @@ enum EShaderPlatform SP_PS4 = 2, /** Used when running in Feature Level ES2 in OpenGL. */ SP_OPENGL_PCES2 = 3, - SP_XBOXONE = 4, + SP_XBOXONE_D3D12 = 4, SP_PCD3D_SM4 = 5, SP_OPENGL_SM5 = 6, /** Used when running in Feature Level ES2 in D3D11. */ @@ -62,8 +62,9 @@ enum EShaderPlatform SP_SWITCH = 26, SP_SWITCH_FORWARD = 27, SP_METAL_MRT_MAC = 28, + SP_XBOXONE_D3D11 = 29, - SP_NumPlatforms = 29, + SP_NumPlatforms = 30, SP_NumBits = 5, }; static_assert(SP_NumPlatforms <= (1 << SP_NumBits), "SP_NumPlatforms will not fit on SP_NumBits"); @@ -491,6 +492,8 @@ static_assert(PT_Num <= (1 << PT_NumBits), "PT_NumBits is too small"); */ enum EBufferUsageFlags { + BUF_None = 0x0000, + // Mutually exclusive write-frequency flags BUF_Static = 0x0001, // The buffer will be written to once. BUF_Dynamic = 0x0002, // The buffer will be written to occasionally, GPU read only, CPU write only. The data lifetime is until the next update, or the buffer is destroyed. @@ -525,9 +528,12 @@ enum EBufferUsageFlags */ BUF_ZeroStride = 0x0800, - /** Buffer should go in fast vram (hint only) */ + /** Buffer should go in fast vram (hint only). Requires BUF_Transient */ BUF_FastVRAM = 0x1000, + /** Buffer should be allocated from transient memory. */ + BUF_Transient = 0x2000, + // Helper bit-masks BUF_AnyDynamic = (BUF_Dynamic | BUF_Volatile), }; @@ -629,7 +635,9 @@ enum ETextureCreateFlags // Hint to the driver that this resource is managed properly by the engine for Alternate-Frame-Rendering in mGPU usage. TexCreate_AFRManual = 1 << 29, // Workaround for 128^3 volume textures getting bloated 4x due to tiling mode on PS4 - TexCreate_ReduceMemoryWithTilingMode = 1 << 30 + TexCreate_ReduceMemoryWithTilingMode = 1 << 30, + /** Texture should be allocated from transient memory. */ + TexCreate_Transient = 1 << 31 }; enum EAsyncComputePriority @@ -750,7 +758,12 @@ inline bool IsMetalPlatform(const EShaderPlatform Platform) inline bool IsConsolePlatform(const EShaderPlatform Platform) { - return Platform == SP_PS4 || Platform == SP_XBOXONE; + return Platform == SP_PS4 || Platform == SP_XBOXONE_D3D12 || Platform == SP_XBOXONE_D3D11; +} + +inline bool IsSwitchPlatform(const EShaderPlatform Platform) +{ + return Platform == SP_SWITCH || Platform == SP_SWITCH_FORWARD; } inline bool IsVulkanPlatform(const EShaderPlatform Platform) @@ -777,7 +790,8 @@ inline bool IsD3DPlatform(const EShaderPlatform Platform, bool bIncludeXboxOne) case SP_PCD3D_ES3_1: case SP_PCD3D_ES2: return true; - case SP_XBOXONE: + case SP_XBOXONE_D3D12: + case SP_XBOXONE_D3D11: return bIncludeXboxOne; default: break; @@ -786,6 +800,11 @@ inline bool IsD3DPlatform(const EShaderPlatform Platform, bool bIncludeXboxOne) return false; } +inline bool IsHlslccShaderPlatform(const EShaderPlatform Platform) +{ + return IsMetalPlatform(Platform) || IsVulkanPlatform(Platform) || IsSwitchPlatform(Platform) || IsOpenGLPlatform(Platform); +} + inline ERHIFeatureLevel::Type GetMaxSupportedFeatureLevel(EShaderPlatform InShaderPlatform) { switch (InShaderPlatform) @@ -793,7 +812,8 @@ inline ERHIFeatureLevel::Type GetMaxSupportedFeatureLevel(EShaderPlatform InShad case SP_PCD3D_SM5: case SP_OPENGL_SM5: case SP_PS4: - case SP_XBOXONE: + case SP_XBOXONE_D3D12: + case SP_XBOXONE_D3D11: case SP_OPENGL_ES31_EXT: case SP_METAL_SM5: case SP_VULKAN_SM5: @@ -803,8 +823,8 @@ inline ERHIFeatureLevel::Type GetMaxSupportedFeatureLevel(EShaderPlatform InShad case SP_PCD3D_SM4: case SP_OPENGL_SM4: case SP_OPENGL_SM4_MAC: - case SP_METAL_MRT: - case SP_METAL_MRT_MAC: + case SP_METAL_MRT: + case SP_METAL_MRT_MAC: case SP_METAL_SM4: return ERHIFeatureLevel::SM4; case SP_PCD3D_ES2: @@ -847,7 +867,7 @@ inline bool RHINeedsToSwitchVerticalAxis(EShaderPlatform Platform) // ES2 & ES3.1 need to flip when rendering to an RT that will be post processed return IsOpenGLPlatform(Platform) && IsMobilePlatform(Platform) && !IsPCPlatform(Platform) && Platform != SP_METAL && !IsVulkanPlatform(Platform) - && Platform != SP_SWITCH && Platform != SP_SWITCH_FORWARD; + && Platform != SP_SWITCH && Platform != SP_SWITCH_FORWARD; } inline bool RHISupportsSeparateMSAAAndResolveTextures(const EShaderPlatform Platform) @@ -876,7 +896,7 @@ inline bool RHISupportsGeometryShaders(const EShaderPlatform Platform) inline bool RHISupportsShaderCompression(const EShaderPlatform Platform) { - return Platform != SP_XBOXONE; // Handled automatically with hardware decompress + return ( Platform != SP_XBOXONE_D3D12) && ( Platform != SP_XBOXONE_D3D11 ); // Handled automatically with hardware decompress } inline bool RHIHasTiledGPU(const EShaderPlatform Platform) diff --git a/Engine/Source/Runtime/RHI/Public/RHIResources.h b/Engine/Source/Runtime/RHI/Public/RHIResources.h index a23adad138fa..027711a71bb1 100644 --- a/Engine/Source/Runtime/RHI/Public/RHIResources.h +++ b/Engine/Source/Runtime/RHI/Public/RHIResources.h @@ -32,6 +32,7 @@ public: FRHIResource(bool InbDoNotDeferDelete = false) : MarkedForDelete(0) , bDoNotDeferDelete(InbDoNotDeferDelete) + , bCommitted(true) { } virtual ~FRHIResource() @@ -87,10 +88,25 @@ public: static bool Bypass(); + // Transient resource tracking + // We do this at a high level so we can catch errors even when transient resources are not supported + void SetCommitted(bool bInCommitted) + { + check(IsInRenderingThread()); + bCommitted = bInCommitted; + } + bool IsCommitted() const + { + check(IsInRenderingThread()); + return bCommitted; + } + private: mutable FThreadSafeCounter NumRefs; mutable int32 MarkedForDelete; bool bDoNotDeferDelete; + bool bCommitted; + static TLockFreePointerListUnordered PendingDeletes; static FRHIResource* CurrentlyDeleting; diff --git a/Engine/Source/Runtime/RHI/Public/RHIUtilities.h b/Engine/Source/Runtime/RHI/Public/RHIUtilities.h index 1c575bc73216..048567a5a8f1 100644 --- a/Engine/Source/Runtime/RHI/Public/RHIUtilities.h +++ b/Engine/Source/Runtime/RHI/Public/RHIUtilities.h @@ -49,21 +49,47 @@ struct FRWBuffer FShaderResourceViewRHIRef SRV; uint32 NumBytes; - FRWBuffer(): NumBytes(0) {} + FRWBuffer() + : NumBytes(0) + {} + + ~FRWBuffer() + { + Release(); + } // @param AdditionalUsage passed down to RHICreateVertexBuffer(), get combined with "BUF_UnorderedAccess | BUF_ShaderResource" e.g. BUF_Static - void Initialize(uint32 BytesPerElement, uint32 NumElements, EPixelFormat Format, uint32 AdditionalUsage = 0) + void Initialize(uint32 BytesPerElement, uint32 NumElements, EPixelFormat Format, uint32 AdditionalUsage = 0, const TCHAR* InDebugName = NULL) { check(GMaxRHIFeatureLevel == ERHIFeatureLevel::SM5); + // Provide a debug name if using Fast VRAM so the allocators diagnostics will work + ensure(!((AdditionalUsage & BUF_FastVRAM) && !InDebugName)); NumBytes = BytesPerElement * NumElements; FRHIResourceCreateInfo CreateInfo; + CreateInfo.DebugName = InDebugName; Buffer = RHICreateVertexBuffer(NumBytes, BUF_UnorderedAccess | BUF_ShaderResource | AdditionalUsage, CreateInfo); UAV = RHICreateUnorderedAccessView(Buffer, Format); SRV = RHICreateShaderResourceView(Buffer, BytesPerElement, Format); } + void AcquireTransientResource() + { + RHIAcquireTransientResource(Buffer); + } + void DiscardTransientResource() + { + RHIDiscardTransientResource(Buffer); + } + void Release() { + int32 BufferRefCount = Buffer ? Buffer->GetRefCount() : -1; + + if (BufferRefCount == 1) + { + DiscardTransientResource(); + } + NumBytes = 0; Buffer.SafeRelease(); UAV.SafeRelease(); @@ -107,11 +133,20 @@ struct FRWBufferStructured FRWBufferStructured(): NumBytes(0) {} - void Initialize(uint32 BytesPerElement, uint32 NumElements, uint32 AdditionalUsage = 0, bool bUseUavCounter = false, bool bAppendBuffer = false) + ~FRWBufferStructured() + { + Release(); + } + + void Initialize(uint32 BytesPerElement, uint32 NumElements, uint32 AdditionalUsage = 0, const TCHAR* InDebugName = NULL, bool bUseUavCounter = false, bool bAppendBuffer = false) { check(GMaxRHIFeatureLevel == ERHIFeatureLevel::SM5); + // Provide a debug name if using Fast VRAM so the allocators diagnostics will work + ensure(!((AdditionalUsage & BUF_FastVRAM) && !InDebugName)); + NumBytes = BytesPerElement * NumElements; FRHIResourceCreateInfo CreateInfo; + CreateInfo.DebugName = InDebugName; Buffer = RHICreateStructuredBuffer(BytesPerElement, NumBytes, BUF_UnorderedAccess | BUF_ShaderResource | AdditionalUsage, CreateInfo); UAV = RHICreateUnorderedAccessView(Buffer, bUseUavCounter, bAppendBuffer); SRV = RHICreateShaderResourceView(Buffer); @@ -119,11 +154,27 @@ struct FRWBufferStructured void Release() { + int32 BufferRefCount = Buffer ? Buffer->GetRefCount() : -1; + + if (BufferRefCount == 1) + { + DiscardTransientResource(); + } + NumBytes = 0; Buffer.SafeRelease(); UAV.SafeRelease(); SRV.SafeRelease(); } + + void AcquireTransientResource() + { + RHIAcquireTransientResource(Buffer); + } + void DiscardTransientResource() + { + RHIDiscardTransientResource(Buffer); + } }; /** Encapsulates a GPU read/write ByteAddress buffer with its UAV and SRV. */ @@ -167,7 +218,7 @@ struct FDynamicReadBuffer : public FReadBuffer { } - ~FDynamicReadBuffer() + virtual ~FDynamicReadBuffer() { Release(); } @@ -797,7 +848,6 @@ private: extern RHI_API void EnableDepthBoundsTest(FRHICommandList& RHICmdList, float WorldSpaceDepthNear, float WorldSpaceDepthFar, const FMatrix& ProjectionMatrix); extern RHI_API void DisableDepthBoundsTest(FRHICommandList& RHICmdList); - struct FRHILockTracker { struct FLockParams diff --git a/Engine/Source/Runtime/RHI/RHI.Build.cs b/Engine/Source/Runtime/RHI/RHI.Build.cs index 9b5efa20e613..613bf110dfb1 100644 --- a/Engine/Source/Runtime/RHI/RHI.Build.cs +++ b/Engine/Source/Runtime/RHI/RHI.Build.cs @@ -24,7 +24,7 @@ public class RHI : ModuleRules if ((Target.Platform == UnrealTargetPlatform.Win64) || (Target.Platform == UnrealTargetPlatform.Win32) || - (Target.Platform == UnrealTargetPlatform.Linux)) + (Target.Platform == UnrealTargetPlatform.Linux && Target.Architecture.StartsWith("x86_64"))) // temporary, not all archs can support Vulkan atm { DynamicallyLoadedModuleNames.Add("VulkanRHI"); } diff --git a/Engine/Source/Runtime/RenderCore/Private/RenderCore.cpp b/Engine/Source/Runtime/RenderCore/Private/RenderCore.cpp index bac7a5a6efc4..277b89137fb6 100644 --- a/Engine/Source/Runtime/RenderCore/Private/RenderCore.cpp +++ b/Engine/Source/Runtime/RenderCore/Private/RenderCore.cpp @@ -172,16 +172,25 @@ DEFINE_STAT(STAT_RenderWholeSceneReflectiveShadowMapsTime); DEFINE_STAT(STAT_ShadowmapAtlasMemory); DEFINE_STAT(STAT_CachedShadowmapMemory); -#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) +#define EXPOSE_FORCE_LOD !(UE_BUILD_SHIPPING || UE_BUILD_TEST) + +#if EXPOSE_FORCE_LOD static TAutoConsoleVariable CVarForceLOD( TEXT("r.ForceLOD"), -1, TEXT("LOD level to force, -1 is off."), - ECVF_Cheat | ECVF_RenderThreadSafe + ECVF_Scalability | ECVF_Default | ECVF_RenderThreadSafe ); -#endif // !(UE_BUILD_SHIPPING || UE_BUILD_TEST) +static TAutoConsoleVariable CVarForceLODShadow( + TEXT("r.ForceLODShadow"), + -1, + TEXT("LOD level to force for the shadow map generation only, -1 is off."), + ECVF_Scalability | ECVF_Default | ECVF_RenderThreadSafe +); + +#endif // EXPOSE_FORCE_LOD /** Whether to pause the global realtime clock for the rendering thread (read and write only on main thread). */ bool GPauseRenderingRealtimeClock; @@ -242,11 +251,24 @@ RENDERCORE_API int32 GetCVarForceLOD() { int32 Ret = -1; -#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) +#if EXPOSE_FORCE_LOD { Ret = CVarForceLOD.GetValueOnRenderThread(); } -#endif // !(UE_BUILD_SHIPPING || UE_BUILD_TEST) +#endif // EXPOSE_FORCE_LOD + + return Ret; +} + +RENDERCORE_API int32 GetCVarForceLODShadow() +{ + int32 Ret = -1; + +#if EXPOSE_FORCE_LOD + { + Ret = CVarForceLODShadow.GetValueOnRenderThread(); + } +#endif // EXPOSE_FORCE_LOD return Ret; } diff --git a/Engine/Source/Runtime/RenderCore/Private/RenderUtils.cpp b/Engine/Source/Runtime/RenderCore/Private/RenderUtils.cpp index b0779d61e5e2..0aa8dad2d56e 100644 --- a/Engine/Source/Runtime/RenderCore/Private/RenderUtils.cpp +++ b/Engine/Source/Runtime/RenderCore/Private/RenderUtils.cpp @@ -829,13 +829,15 @@ RENDERCORE_API bool IsSimpleForwardShadingEnabled(EShaderPlatform Platform) return CVar->GetValueOnAnyThread() != 0 && PlatformSupportsSimpleForwardShading(Platform); } -RENDERCORE_API bool IsForwardShadingEnabled(ERHIFeatureLevel::Type FeatureLevel) -{ - static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.ForwardShading")); - return CVar->GetValueOnAnyThread() != 0 - // Culling uses compute shader - && FeatureLevel >= ERHIFeatureLevel::SM5; -} +RENDERCORE_API int32 bUseForwardShading = 0; +static FAutoConsoleVariableRef CVarForwardShading( + TEXT("r.ForwardShading"), + bUseForwardShading, + TEXT("Whether to use forward shading on desktop platforms - requires Shader Model 5 hardware.\n") + TEXT("Forward shading has lower constant cost, but fewer features supported. 0:off, 1:on\n") + TEXT("This rendering path is a work in progress with many unimplemented features, notably only a single reflection capture is applied per object and no translucency dynamic shadow receiving."), + ECVF_RenderThreadSafe | ECVF_ReadOnly + ); class FUnitCubeVertexBuffer : public FVertexBuffer { diff --git a/Engine/Source/Runtime/RenderCore/Private/RenderingThread.cpp b/Engine/Source/Runtime/RenderCore/Private/RenderingThread.cpp index c67396d1b3d2..2d623248e58a 100644 --- a/Engine/Source/Runtime/RenderCore/Private/RenderingThread.cpp +++ b/Engine/Source/Runtime/RenderCore/Private/RenderingThread.cpp @@ -12,6 +12,7 @@ #include "Misc/CoreStats.h" #include "Misc/TimeGuard.h" #include "Misc/CoreDelegates.h" +#include "Misc/ScopeLock.h" #include "RenderCore.h" #include "RenderCommandFence.h" #include "RHI.h" @@ -19,6 +20,7 @@ #include "Stats/StatsData.h" #include "HAL/ThreadHeartBeat.h" #include "RenderResource.h" +#include "ScopeLock.h" // // Globals @@ -28,7 +30,6 @@ RENDERCORE_API bool GIsThreadedRendering = false; RENDERCORE_API bool GUseThreadedRendering = false; -RENDERCORE_API bool GUseRHIThread = false; #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) RENDERCORE_API bool GMainThreadBlockedOnRenderThread = false; @@ -412,7 +413,7 @@ public: GRenderThreadId = FPlatformTLS::GetCurrentThreadId(); // Acquire rendering context ownership on the current thread, unless using an RHI thread, which will be the real owner - if (!GUseRHIThread) + if (!IsRunningRHIInSeparateThread()) { bAcquiredThreadOwnership = true; RHIAcquireThreadOwnership(); @@ -631,7 +632,7 @@ public: **/ void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent) { - // note that this task is the first task run on the thread, before GRHIThread is assigned, so we can't check IsInRHIThread() + // note that this task is the first task run on the thread, before GRHIThread_InternalUseOnly is assigned, so we can't check IsInRHIThread() if (bAcquireOwnership) { @@ -654,8 +655,9 @@ void StartRenderingThread() static uint32 ThreadCount = 0; check(!GIsThreadedRendering && GUseThreadedRendering); - check(!GRHIThread) - if (GUseRHIThread) + check(!GRHIThread_InternalUseOnly && !GIsRunningRHIInSeparateThread_InternalUseOnly && !GIsRunningRHIInDedicatedThread_InternalUseOnly && !GIsRunningRHIInTaskThread_InternalUseOnly); + + if (GUseRHIThread_InternalUseOnly) { FRHICommandListExecutor::GetImmediateCommandList().ImmediateFlush(EImmediateFlushType::DispatchToRHIThread); if (!FTaskGraphInterface::Get().IsThreadProcessingTasks(ENamedThreads::RHIThread)) @@ -667,9 +669,17 @@ void StartRenderingThread() FGraphEventRef CompletionEvent = TGraphTask::CreateTask(NULL, ENamedThreads::GameThread).ConstructAndDispatchWhenReady(true, GET_STATID(STAT_WaitForRHIThread)); QUICK_SCOPE_CYCLE_COUNTER(STAT_StartRenderingThread); FTaskGraphInterface::Get().WaitUntilTaskCompletes(CompletionEvent, ENamedThreads::GameThread_Local); - GRHIThread = FRHIThread::Get().Thread; - check(GRHIThread); + GRHIThread_InternalUseOnly = FRHIThread::Get().Thread; + check(GRHIThread_InternalUseOnly); GRHICommandList.LatchBypass(); + GIsRunningRHIInDedicatedThread_InternalUseOnly = true; + GIsRunningRHIInSeparateThread_InternalUseOnly = true; + GRHIThreadId = GRHIThread_InternalUseOnly->GetThreadID(); + } + else if (GUseRHITaskThreads_InternalUseOnly) + { + GIsRunningRHIInSeparateThread_InternalUseOnly = true; + GIsRunningRHIInTaskThread_InternalUseOnly = true; } // Turn on the threaded rendering flag. @@ -735,15 +745,21 @@ void StopRenderingThread() // The rendering thread may have already been stopped during the call to GFlushStreamingFunc or FlushRenderingCommands. if ( GIsThreadedRendering ) { - if (GRHIThread) + if (GRHIThread_InternalUseOnly) { DECLARE_CYCLE_STAT(TEXT("Wait For RHIThread Finish"), STAT_WaitForRHIThreadFinish, STATGROUP_TaskGraphTasks); FGraphEventRef ReleaseTask = TGraphTask::CreateTask(NULL, ENamedThreads::GameThread).ConstructAndDispatchWhenReady(false, GET_STATID(STAT_WaitForRHIThreadFinish)); QUICK_SCOPE_CYCLE_COUNTER(STAT_StopRenderingThread_RHIThread); FTaskGraphInterface::Get().WaitUntilTaskCompletes(ReleaseTask, ENamedThreads::GameThread_Local); - GRHIThread = nullptr; + GRHIThread_InternalUseOnly = nullptr; + GRHIThreadId = 0; } + GIsRunningRHIInSeparateThread_InternalUseOnly = false; + GIsRunningRHIInDedicatedThread_InternalUseOnly = false; + GIsRunningRHIInTaskThread_InternalUseOnly = false; + + check( GRenderingThread ); check(!GIsRenderingThreadSuspended); @@ -786,18 +802,12 @@ void StopRenderingThread() delete PendingCleanupObjects; } - check(!GRHIThread); + check(!GRHIThread_InternalUseOnly); } void CheckRenderingThreadHealth() { - bool IsGpuAlive = true; - if (GDynamicRHI) - { - IsGpuAlive = GDynamicRHI->CheckGpuHeartbeat(); - } - - if(!GIsRenderingThreadHealthy || !IsGpuAlive) + if(!GIsRenderingThreadHealthy) { GErrorHist[0] = 0; GIsCriticalError = false; @@ -1082,7 +1092,7 @@ void FlushRenderingCommands() void FlushPendingDeleteRHIResources_GameThread() { - if (!GRHIThread) + if (!IsRunningRHIInSeparateThread()) { ENQUEUE_UNIQUE_RENDER_COMMAND( FlushPendingDeleteRHIResources, @@ -1094,7 +1104,7 @@ void FlushPendingDeleteRHIResources_GameThread() } void FlushPendingDeleteRHIResources_RenderThread() { - if (!GRHIThread) + if (!IsRunningRHIInSeparateThread()) { FRHIResource::FlushPendingDeletes(); } @@ -1106,6 +1116,43 @@ FRHICommandListImmediate& GetImmediateCommandList_ForRenderCommand() return FRHICommandListExecutor::GetImmediateCommandList(); } +#if WITH_EDITOR || IS_PROGRAM + +// mainly concerned about the cooker here, but anyway, the editor can run without a frame for a very long time (hours) and we do not have enough lock free links. + +/** The set of deferred cleanup objects which are pending cleanup. */ +TArray PendingCleanupObjectsList; +FCriticalSection PendingCleanupObjectsListLock; + +FPendingCleanupObjects::FPendingCleanupObjects() +{ + check(IsInGameThread()); + { + FScopeLock Lock(&PendingCleanupObjectsListLock); + Exchange(CleanupArray, PendingCleanupObjectsList); + } +} + +FPendingCleanupObjects::~FPendingCleanupObjects() +{ + QUICK_SCOPE_CYCLE_COUNTER(STAT_FPendingCleanupObjects_Destruct); + + for (int32 ObjectIndex = 0; ObjectIndex < CleanupArray.Num(); ObjectIndex++) + { + CleanupArray[ObjectIndex]->FinishCleanup(); + } +} + +void BeginCleanup(FDeferredCleanupInterface* CleanupObject) +{ + { + FScopeLock Lock(&PendingCleanupObjectsListLock); + PendingCleanupObjectsList.Add(CleanupObject); + } +} + +#else + /** The set of deferred cleanup objects which are pending cleanup. */ static TLockFreePointerListUnordered PendingCleanupObjectsList; @@ -1119,7 +1166,7 @@ FPendingCleanupObjects::~FPendingCleanupObjects() { QUICK_SCOPE_CYCLE_COUNTER(STAT_FPendingCleanupObjects_Destruct); - for(int32 ObjectIndex = 0;ObjectIndex < CleanupArray.Num();ObjectIndex++) + for (int32 ObjectIndex = 0; ObjectIndex < CleanupArray.Num(); ObjectIndex++) { CleanupArray[ObjectIndex]->FinishCleanup(); } @@ -1130,52 +1177,80 @@ void BeginCleanup(FDeferredCleanupInterface* CleanupObject) PendingCleanupObjectsList.Push(CleanupObject); } +#endif + FPendingCleanupObjects* GetPendingCleanupObjects() { return new FPendingCleanupObjects; } -void SetRHIThreadEnabled(bool bEnable) +void SetRHIThreadEnabled(bool bEnableDedicatedThread, bool bEnableRHIOnTaskThreads) { - if (bEnable != GUseRHIThread) + if (bEnableDedicatedThread != GUseRHIThread_InternalUseOnly || bEnableRHIOnTaskThreads != GUseRHITaskThreads_InternalUseOnly) { - if (GRHISupportsRHIThread) + if ((bEnableRHIOnTaskThreads || bEnableDedicatedThread) && !GIsThreadedRendering) { - if (!GIsThreadedRendering) - { - check(!GRHIThread); - UE_LOG(LogRendererCore, Display, TEXT("Can't switch to RHI thread mode when we are not running a multithreaded renderer.")); - } - else - { - StopRenderingThread(); - GUseRHIThread = bEnable; - StartRenderingThread(); - } - UE_LOG(LogRendererCore, Display, TEXT("RHIThread is now %s."), GRHIThread ? TEXT("active") : TEXT("inactive")); + check(!IsRunningRHIInSeparateThread()); + UE_LOG(LogConsoleResponse, Display, TEXT("Can't switch to RHI thread mode when we are not running a multithreaded renderer.")); } else { - UE_LOG(LogRendererCore, Display, TEXT("This RHI does not support the RHI thread.")); + StopRenderingThread(); + if (bEnableRHIOnTaskThreads) + { + GUseRHIThread_InternalUseOnly = false; + GUseRHITaskThreads_InternalUseOnly = true; + } + else if (bEnableDedicatedThread) + { + GUseRHIThread_InternalUseOnly = true; + GUseRHITaskThreads_InternalUseOnly = false; + } + else + { + GUseRHIThread_InternalUseOnly = false; + GUseRHITaskThreads_InternalUseOnly = false; + } + StartRenderingThread(); } } + if (IsRunningRHIInSeparateThread()) + { + if (IsRunningRHIInDedicatedThread()) + { + UE_LOG(LogConsoleResponse, Display, TEXT("RHIThread is now running on a dedicated thread.")); + } + else + { + check(IsRunningRHIInTaskThread()); + UE_LOG(LogConsoleResponse, Display, TEXT("RHIThread is now running on task threads.")); + } + } + else + { + check(!IsRunningRHIInTaskThread() && !IsRunningRHIInDedicatedThread()); + UE_LOG(LogConsoleResponse, Display, TEXT("RHIThread is disabled.")); + } + } static void HandleRHIThreadEnableChanged(const TArray& Args) { if (Args.Num() > 0) { - const bool bUseRHIThread = Args[0].ToBool(); - SetRHIThreadEnabled(bUseRHIThread); + const int32 UseRHIThread = FCString::Atoi(*Args[0]); + SetRHIThreadEnabled(UseRHIThread == 1, UseRHIThread == 2); } else { - UE_LOG(LogRendererCore, Display, TEXT("Usage: r.RHIThread.Enable 0/1; Currently %d"), (int32)GUseRHIThread); + UE_LOG(LogConsoleResponse, Display, TEXT("Usage: r.RHIThread.Enable 0=off, 1=dedicated thread, 2=task threads; Currently %d"), IsRunningRHIInSeparateThread() ? (IsRunningRHIInDedicatedThread() ? 1 : 2) : 0); } } static FAutoConsoleCommand CVarRHIThreadEnable( TEXT("r.RHIThread.Enable"), - TEXT("Enables/disabled the RHI Thread\n"), + TEXT("Enables/disabled the RHI Thread and determine if the RHI work runs on a dedicated thread or not.\n"), FConsoleCommandWithArgsDelegate::CreateStatic(&HandleRHIThreadEnableChanged) ); + + diff --git a/Engine/Source/Runtime/RenderCore/Public/RenderCore.h b/Engine/Source/Runtime/RenderCore/Public/RenderCore.h index 956dba235ede..6249aefab97e 100644 --- a/Engine/Source/Runtime/RenderCore/Public/RenderCore.h +++ b/Engine/Source/Runtime/RenderCore/Public/RenderCore.h @@ -278,3 +278,5 @@ extern RENDERCORE_API uint32 GSwapBufferTime; // shared by renderer and engine, compiles down to a constant in final release RENDERCORE_API int32 GetCVarForceLOD(); +RENDERCORE_API int32 GetCVarForceLODShadow(); + diff --git a/Engine/Source/Runtime/RenderCore/Public/RenderUtils.h b/Engine/Source/Runtime/RenderCore/Public/RenderUtils.h index bcd55156c936..e838dbe680a0 100644 --- a/Engine/Source/Runtime/RenderCore/Public/RenderUtils.h +++ b/Engine/Source/Runtime/RenderCore/Public/RenderUtils.h @@ -316,7 +316,13 @@ RENDERCORE_API bool PlatformSupportsSimpleForwardShading(EShaderPlatform Platfor RENDERCORE_API bool IsSimpleForwardShadingEnabled(EShaderPlatform Platform); -RENDERCORE_API bool IsForwardShadingEnabled(ERHIFeatureLevel::Type FeatureLevel); +inline bool IsForwardShadingEnabled(ERHIFeatureLevel::Type FeatureLevel) +{ + extern RENDERCORE_API int32 bUseForwardShading; + return bUseForwardShading + // Culling uses compute shader + && FeatureLevel >= ERHIFeatureLevel::SM5; +} inline bool IsAnyForwardShadingEnabled(EShaderPlatform Platform) { diff --git a/Engine/Source/Runtime/RenderCore/Public/RendererInterface.h b/Engine/Source/Runtime/RenderCore/Public/RendererInterface.h index 39b93225930f..bdc8e928a7c3 100644 --- a/Engine/Source/Runtime/RenderCore/Public/RendererInterface.h +++ b/Engine/Source/Runtime/RenderCore/Public/RendererInterface.h @@ -175,7 +175,7 @@ public: auto LhsFlags = Flags; auto RhsFlags = rhs.Flags; - if (!bExact || !FPlatformProperties::SupportsFastVRAMMemory()) + if (!bExact || !FPlatformMemory::SupportsFastVRAMMemory()) { LhsFlags &= (~TexCreate_FastVRAM); RhsFlags &= (~TexCreate_FastVRAM); @@ -237,6 +237,11 @@ public: && ((TargetableFlags & TexCreate_UAV) == 0 || GMaxRHIFeatureLevel == ERHIFeatureLevel::SM5); } + FIntVector GetSize() const + { + return FIntVector(Extent.X, Extent.Y, Depth); + } + /** * for debugging purpose * @return e.g. (2D 128x64 PF_R8) @@ -271,6 +276,11 @@ public: FlagsString += TEXT(" VRam"); } + if (LocalFlags & TexCreate_Transient) + { + FlagsString += TEXT(" Transient"); + } + FString ArrayString; if(IsArray()) @@ -337,7 +347,7 @@ public: /** Whether the shader-resource and targetable texture must be separate textures. */ bool bForceSeparateTargetAndShaderResource; /** only set a pointer to memory that never gets released */ - const TCHAR *DebugName; + const TCHAR* DebugName; /** automatically set to writable via barrier during */ bool AutoWritable; /** create render target write mask (supported only on specific platforms) */ @@ -393,10 +403,12 @@ struct FSceneRenderTargetItem }; /** - * Render thread side, use TRefCountPtr, allows to use sharing and VisualizeTexture + * Render thread side, use TRefCountPtr, allows sharing and VisualizeTexture */ -struct IPooledRenderTarget : public IRefCountedObject +struct IPooledRenderTarget { + virtual ~IPooledRenderTarget() {} + /** Checks if the reference count indicated that the rendertarget is unused and can be reused. */ virtual bool IsFree() const = 0; /** Get all the data that is needed to create the render target. */ @@ -413,8 +425,22 @@ struct IPooledRenderTarget : public IRefCountedObject /** Get the low level internals (texture/surface) */ inline const FSceneRenderTargetItem& GetRenderTargetItem() const { return RenderTargetItem; } + // Refcounting + virtual uint32 AddRef() const = 0; + virtual uint32 Release() = 0; + virtual uint32 GetRefCount() const = 0; + protected: + /** For pool management (only if NumRef == 0 the element can be reused) */ + mutable int32 NumRefs; + + /** Snapshots are sortof fake pooled render targets, they don't own anything and can outlive the things that created them. These are for threaded rendering. */ + bool bSnapshot; + + /** Pointer back to the pool for render targets which are actually pooled, otherwise NULL. */ + class FRenderTargetPool* RenderTargetPool; + /** The internal references to the created render target */ FSceneRenderTargetItem RenderTargetItem; }; diff --git a/Engine/Source/Runtime/RenderCore/Public/RenderingThread.h b/Engine/Source/Runtime/RenderCore/Public/RenderingThread.h index 3ff60b250eda..7abe9f091519 100644 --- a/Engine/Source/Runtime/RenderCore/Public/RenderingThread.h +++ b/Engine/Source/Runtime/RenderCore/Public/RenderingThread.h @@ -27,12 +27,8 @@ extern RENDERCORE_API bool GIsThreadedRendering; * Currently set by command line parameter and by the ToggleRenderingThread console command. */ extern RENDERCORE_API bool GUseThreadedRendering; -/** - * Whether the RHI thread should be created or not, requires rendering thread - * Currently set by command line parameter and by the r.rhithread.enable cvar. - */ -extern RENDERCORE_API bool GUseRHIThread; -extern RENDERCORE_API void SetRHIThreadEnabled(bool bEnable); + +extern RENDERCORE_API void SetRHIThreadEnabled(bool bEnableDedicatedThread, bool bEnableRHIOnTaskThreads); #if (UE_BUILD_SHIPPING || UE_BUILD_TEST) static FORCEINLINE void CheckNotBlockedOnRenderThread() {} diff --git a/Engine/Source/Runtime/Renderer/Private/AtmosphereRendering.cpp b/Engine/Source/Runtime/Renderer/Private/AtmosphereRendering.cpp index 5f550168193c..370715c93299 100644 --- a/Engine/Source/Runtime/Renderer/Private/AtmosphereRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/AtmosphereRendering.cpp @@ -1737,7 +1737,7 @@ FAtmosphericFogSceneInfo::FAtmosphericFogSceneInfo(UAtmosphericFogComponent* InC RenderFlag |= (InComponent->bDisableGroundScattering) ? EAtmosphereRenderFlag::E_DisableGroundScattering : EAtmosphereRenderFlag::E_EnableAll; // Should be same as UpdateAtmosphericFogTransform GroundOffset += InComponent->GetComponentLocation().Z; - FMatrix WorldToLight = InComponent->ComponentToWorld.ToMatrixNoScale().InverseFast(); + FMatrix WorldToLight = InComponent->GetComponentTransform().ToMatrixNoScale().InverseFast(); DefaultSunDirection = FVector(WorldToLight.M[0][0],WorldToLight.M[1][0],WorldToLight.M[2][0]); #if WITH_EDITORONLY_DATA diff --git a/Engine/Source/Runtime/Renderer/Private/CapsuleShadowRendering.cpp b/Engine/Source/Runtime/Renderer/Private/CapsuleShadowRendering.cpp index 518c9a29f439..a7093cb60ac4 100644 --- a/Engine/Source/Runtime/Renderer/Private/CapsuleShadowRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/CapsuleShadowRendering.cpp @@ -258,7 +258,7 @@ public: check(!ReceiverBentNormalTexture.IsBound()); } - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_PostProcess); SetShaderValue(RHICmdList, ShaderRHI, NumGroups, NumGroupsValue); @@ -545,7 +545,7 @@ public: const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader(); FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View.ViewUniformBuffer); - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_PostProcess); SetTextureParameter(RHICmdList, ShaderRHI, ShadowFactorsTexture, ShadowFactorsSampler, TStaticSamplerState::GetRHI(), ShadowFactorsTextureValue->GetRenderTargetItem().ShaderResourceTexture); @@ -670,8 +670,9 @@ void AllocateCapsuleTileIntersectionCountsBuffer(FIntPoint GroupSize, FSceneView } bool FDeferredShadingSceneRenderer::RenderCapsuleDirectShadows( - const FLightSceneInfo& LightSceneInfo, FRHICommandListImmediate& RHICmdList, + const FLightSceneInfo& LightSceneInfo, + IPooledRenderTarget* ScreenShadowMaskTexture, const TArray& CapsuleShadows, bool bProjectingForForwardShading) const { @@ -771,7 +772,7 @@ bool FDeferredShadingSceneRenderer::RenderCapsuleDirectShadows( AllocateCapsuleTileIntersectionCountsBuffer(GroupSize, View.ViewState); - ClearUAV(RHICmdList, GMaxRHIFeatureLevel, View.ViewState->CapsuleTileIntersectionCountsBuffer, 0); + ClearUAV(RHICmdList, View.ViewState->CapsuleTileIntersectionCountsBuffer, 0); { SCOPED_DRAW_EVENT(RHICmdList, TiledCapsuleShadowing); @@ -837,7 +838,7 @@ bool FDeferredShadingSceneRenderer::RenderCapsuleDirectShadows( SCOPED_DRAW_EVENTF(RHICmdList, Upsample, TEXT("Upsample %dx%d"), ScissorRect.Width(), ScissorRect.Height()); - FSceneRenderTargets::Get(RHICmdList).BeginRenderingLightAttenuation(RHICmdList); + SetRenderTarget(RHICmdList, ScreenShadowMaskTexture->GetRenderTargetItem().TargetableTexture, FSceneRenderTargets::Get(RHICmdList).GetSceneDepthSurface(), ESimpleRenderTargetMode::EExistingColorAndDepth, FExclusiveDepthStencil::DepthRead_StencilWrite, true); FGraphicsPipelineStateInitializer GraphicsPSOInit; RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit); @@ -945,7 +946,7 @@ void FDeferredShadingSceneRenderer::CreateIndirectCapsuleShadows() } } -void FDeferredShadingSceneRenderer::SetupIndirectCapsuleShadows(FRHICommandListImmediate& RHICmdList, const FViewInfo& View, bool bPrepareLightData, int32& NumCapsuleShapes, int32& NumMeshDistanceFieldCasters) const +void FDeferredShadingSceneRenderer::SetupIndirectCapsuleShadows(FRHICommandListImmediate& RHICmdList, const FViewInfo& View, bool bPrepareLightData, int32& NumCapsuleShapes, int32& NumMeshesWithCapsules, int32& NumMeshDistanceFieldCasters) const { const float CosFadeStartAngle = FMath::Cos(GCapsuleShadowFadeAngleFromVertical); const FSkyLightSceneProxy* SkyLight = Scene ? Scene->SkyLight : NULL; @@ -1054,6 +1055,8 @@ void FDeferredShadingSceneRenderer::SetupIndirectCapsuleShadows(FRHICommandListI { DistanceFieldCasterLightSourceData.Add(PackedLightDirection); } + + NumMeshesWithCapsules++; } } @@ -1198,8 +1201,9 @@ void FDeferredShadingSceneRenderer::RenderIndirectCapsuleShadows( SCOPED_GPU_STAT(RHICmdList, Stat_GPU_CapsuleShadows); int32 NumCapsuleShapes = 0; + int32 NumMeshesWithCapsules = 0; int32 NumMeshDistanceFieldCasters = 0; - SetupIndirectCapsuleShadows(RHICmdList, View, true, NumCapsuleShapes, NumMeshDistanceFieldCasters); + SetupIndirectCapsuleShadows(RHICmdList, View, true, NumCapsuleShapes, NumMeshesWithCapsules, NumMeshDistanceFieldCasters); if (NumCapsuleShapes > 0 || NumMeshDistanceFieldCasters > 0) { @@ -1213,10 +1217,10 @@ void FDeferredShadingSceneRenderer::RenderIndirectCapsuleShadows( AllocateCapsuleTileIntersectionCountsBuffer(GroupSize, View.ViewState); - ClearUAV(RHICmdList, GMaxRHIFeatureLevel, View.ViewState->CapsuleTileIntersectionCountsBuffer, 0); + ClearUAV(RHICmdList, View.ViewState->CapsuleTileIntersectionCountsBuffer, 0); { - SCOPED_DRAW_EVENT(RHICmdList, TiledCapsuleShadowing); + SCOPED_DRAW_EVENTF(RHICmdList, TiledCapsuleShadowing, TEXT("TiledCapsuleShadowing %u capsules among %u meshes"), NumCapsuleShapes, NumMeshesWithCapsules); FSceneRenderTargetItem& RayTracedShadowsRTI = RayTracedShadowsRT->GetRenderTargetItem(); { @@ -1406,8 +1410,9 @@ void FDeferredShadingSceneRenderer::RenderCapsuleShadowsForMovableSkylight(FRHIC SCOPED_GPU_STAT(RHICmdList, Stat_GPU_CapsuleShadows); int32 NumCapsuleShapes = 0; + int32 NumMeshesWithCapsules = 0; int32 NumMeshDistanceFieldCasters = 0; - SetupIndirectCapsuleShadows(RHICmdList, View, true, NumCapsuleShapes, NumMeshDistanceFieldCasters); + SetupIndirectCapsuleShadows(RHICmdList, View, true, NumCapsuleShapes, NumMeshesWithCapsules, NumMeshDistanceFieldCasters); if (NumCapsuleShapes > 0 || NumMeshDistanceFieldCasters > 0) { @@ -1420,7 +1425,7 @@ void FDeferredShadingSceneRenderer::RenderCapsuleShadowsForMovableSkylight(FRHIC uint32 GroupSizeY = FMath::DivideAndRoundUp(ScissorRect.Size().Y / GAODownsampleFactor, GShadowShapeTileSize); { - SCOPED_DRAW_EVENT(RHICmdList, TiledCapsuleShadowing); + SCOPED_DRAW_EVENTF(RHICmdList, TiledCapsuleShadowing, TEXT("TiledCapsuleShadowing %u capsules among %u meshes"), NumCapsuleShapes, NumMeshesWithCapsules); FSceneRenderTargetItem& RayTracedShadowsRTI = NewBentNormal->GetRenderTargetItem(); { diff --git a/Engine/Source/Runtime/Renderer/Private/CapsuleShadowRendering.h b/Engine/Source/Runtime/Renderer/Private/CapsuleShadowRendering.h index 1c810f886ea9..1fdbefd4420e 100644 --- a/Engine/Source/Runtime/Renderer/Private/CapsuleShadowRendering.h +++ b/Engine/Source/Runtime/Renderer/Private/CapsuleShadowRendering.h @@ -14,7 +14,7 @@ extern int32 GCapsuleShadows; inline bool DoesPlatformSupportCapsuleShadows(EShaderPlatform Platform) { // Hasn't been tested elsewhere yet - return Platform == SP_PCD3D_SM5 || Platform == SP_PS4 || Platform == SP_METAL_SM5; + return Platform == SP_PCD3D_SM5 || Platform == SP_PS4 || Platform == SP_XBOXONE_D3D11 || Platform == SP_XBOXONE_D3D12 || Platform == SP_METAL_SM5; } inline bool SupportsCapsuleShadows(ERHIFeatureLevel::Type FeatureLevel, EShaderPlatform ShaderPlatform) diff --git a/Engine/Source/Runtime/Renderer/Private/CompositionLighting/CompositionLighting.cpp b/Engine/Source/Runtime/Renderer/Private/CompositionLighting/CompositionLighting.cpp index f9fc91b3429a..d7df5b6e03af 100644 --- a/Engine/Source/Runtime/Renderer/Private/CompositionLighting/CompositionLighting.cpp +++ b/Engine/Source/Runtime/Renderer/Private/CompositionLighting/CompositionLighting.cpp @@ -14,7 +14,7 @@ #include "CompositionLighting/PostProcessAmbientOcclusion.h" #include "CompositionLighting/PostProcessDeferredDecals.h" #include "PostProcess/PostProcessSubsurface.h" -#include "LightPropagationVolumeBlendable.h" +#include "LightPropagationVolumeSettings.h" /** The global center for all deferred lighting activities. */ FCompositionLighting GCompositionLighting; diff --git a/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessAmbient.cpp b/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessAmbient.cpp index f1b38e472535..9e0b294ee978 100644 --- a/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessAmbient.cpp +++ b/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessAmbient.cpp @@ -57,7 +57,7 @@ public: FGlobalShader::SetParameters(RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); - DeferredParameters.Set(RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(RHICmdList, ShaderRHI, Context.View, MD_PostProcess); CubemapShaderParameters.SetParameters(RHICmdList, ShaderRHI, Entry); SetTextureParameter(RHICmdList, ShaderRHI, PreIntegratedGF, PreIntegratedGFSampler, TStaticSamplerState::GetRHI(), GSystemTextures.PreintegratedGF->GetRenderTargetItem().ShaderResourceTexture ); } diff --git a/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessAmbientOcclusion.cpp b/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessAmbientOcclusion.cpp index a52ebeaf3f33..2236ddf83b8d 100644 --- a/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessAmbientOcclusion.cpp +++ b/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessAmbientOcclusion.cpp @@ -273,7 +273,7 @@ public: FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); // e.g. 4 means the input texture is 4x smaller than the buffer size uint32 ScaleToFullRes = FSceneRenderTargets::Get(Context.RHICmdList).GetBufferSizeXY().X / Context.Pass->GetOutput(ePId_Output0)->RenderTargetDesc.Extent.X; @@ -529,7 +529,7 @@ public: // SF_Point is better than bilinear to avoid halos around objects PostprocessParameter.SetCS(ShaderRHI, Context, RHICmdList, TStaticSamplerState::GetRHI()); - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_PostProcess); SetTextureParameter(RHICmdList, ShaderRHI, RandomNormalTexture, RandomNormalTextureSampler, TStaticSamplerState::GetRHI(), SSAORandomization.ShaderResourceTexture); ScreenSpaceAOParams.Set(RHICmdList, View, ShaderRHI, InputTextureSize); @@ -548,7 +548,7 @@ public: // SF_Point is better than bilinear to avoid halos around objects PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_PostProcess); SetTextureParameter(RHICmdList, ShaderRHI, RandomNormalTexture, RandomNormalTextureSampler, TStaticSamplerState::GetRHI(), SSAORandomization.ShaderResourceTexture); ScreenSpaceAOParams.Set(RHICmdList, View, ShaderRHI, InputTextureSize); @@ -896,7 +896,7 @@ public: FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); ScreenSpaceAOParams.Set(Context.RHICmdList, Context.View, ShaderRHI, InputTextureSize); } diff --git a/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessDeferredDecals.cpp b/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessDeferredDecals.cpp index c61a17a84830..855adfe9823a 100644 --- a/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessDeferredDecals.cpp +++ b/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessDeferredDecals.cpp @@ -104,7 +104,7 @@ static TAutoConsoleVariable CVarStencilSizeThreshold( TEXT(" <0: optimization is disabled\n") TEXT(" 0: optimization is enabled no matter how small (screen space) the decal is\n") TEXT("0..1: optimization is enabled, value defines the minimum size (screen space) to trigger the optimization (default 0.1)") - ); +); enum EDecalDepthInputState { @@ -146,11 +146,11 @@ enum EDecalRasterizerState // @param RenderState 0:before BasePass, 1:before lighting, (later we could add "after lighting" and multiply) FBlendStateRHIParamRef GetDecalBlendState(const ERHIFeatureLevel::Type SMFeatureLevel, EDecalRenderStage InDecalRenderStage, EDecalBlendMode DecalBlendMode, bool bHasNormal) { - if(InDecalRenderStage == DRS_BeforeBasePass) + if (InDecalRenderStage == DRS_BeforeBasePass) { // before base pass (for DBuffer decals) - if(SMFeatureLevel == ERHIFeatureLevel::SM4) + if (SMFeatureLevel == ERHIFeatureLevel::SM4) { // DX10 doesn't support masking/using different blend modes per MRT. // We set the opacity in the shader to 0 so we can use the same frame buffer blend. @@ -166,138 +166,138 @@ FBlendStateRHIParamRef GetDecalBlendState(const ERHIFeatureLevel::Type SMFeature // As we set the opacity in the shader we don't need to set different frame buffer blend modes but we like to hint to the driver that we // don't need to output there. We also could replace this with many SetRenderTarget calls but it might be slower (needs to be tested). - switch(DecalBlendMode) + switch (DecalBlendMode) { case DBM_DBuffer_ColorNormalRoughness: return TStaticBlendState< - CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add,BF_Zero,BF_InverseSourceAlpha, - CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add,BF_Zero,BF_InverseSourceAlpha, - CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add,BF_Zero,BF_InverseSourceAlpha >::GetRHI(); + CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha, + CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha, + CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha >::GetRHI(); case DBM_DBuffer_Color: // we can optimize using less MRT later return TStaticBlendState< - CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add,BF_Zero,BF_InverseSourceAlpha, - CW_RGBA, BO_Add, BF_Zero, BF_One, BO_Add,BF_Zero,BF_One, - CW_RGBA, BO_Add, BF_Zero, BF_One, BO_Add,BF_Zero,BF_One>::GetRHI(); + CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha, + CW_RGBA, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, + CW_RGBA, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One>::GetRHI(); case DBM_DBuffer_ColorNormal: // we can optimize using less MRT later return TStaticBlendState< - CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add,BF_Zero,BF_InverseSourceAlpha, - CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add,BF_Zero,BF_InverseSourceAlpha, - CW_RGBA, BO_Add, BF_Zero, BF_One, BO_Add,BF_Zero,BF_One >::GetRHI(); + CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha, + CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha, + CW_RGBA, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One >::GetRHI(); case DBM_DBuffer_ColorRoughness: // we can optimize using less MRT later return TStaticBlendState< - CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add,BF_Zero,BF_InverseSourceAlpha, - CW_RGBA, BO_Add, BF_Zero, BF_One, BO_Add,BF_Zero,BF_One, - CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add,BF_Zero,BF_InverseSourceAlpha >::GetRHI(); + CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha, + CW_RGBA, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, + CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha >::GetRHI(); case DBM_DBuffer_Normal: // we can optimize using less MRT later return TStaticBlendState< - CW_RGBA, BO_Add, BF_Zero, BF_One, BO_Add,BF_Zero,BF_One, - CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add,BF_Zero,BF_InverseSourceAlpha, - CW_RGBA, BO_Add, BF_Zero, BF_One, BO_Add,BF_Zero,BF_One>::GetRHI(); + CW_RGBA, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, + CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha, + CW_RGBA, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One>::GetRHI(); case DBM_DBuffer_NormalRoughness: // we can optimize using less MRT later return TStaticBlendState< - CW_RGBA, BO_Add, BF_Zero, BF_One, BO_Add,BF_Zero,BF_One, - CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add,BF_Zero,BF_InverseSourceAlpha, - CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add,BF_Zero,BF_InverseSourceAlpha >::GetRHI(); + CW_RGBA, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, + CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha, + CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha >::GetRHI(); case DBM_DBuffer_Roughness: // we can optimize using less MRT later return TStaticBlendState< - CW_RGBA, BO_Add, BF_Zero, BF_One, BO_Add,BF_Zero,BF_One, - CW_RGBA, BO_Add, BF_Zero, BF_One, BO_Add,BF_Zero,BF_One, - CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add,BF_Zero,BF_InverseSourceAlpha >::GetRHI(); + CW_RGBA, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, + CW_RGBA, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, + CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha >::GetRHI(); default: // the decal type should not be rendered in this pass - internal error - check(0); + check(0); return nullptr; } } } - else if(InDecalRenderStage == DRS_AfterBasePass) + else if (InDecalRenderStage == DRS_AfterBasePass) { ensure(DecalBlendMode == DBM_Volumetric_DistanceFunction); return TStaticBlendState<>::GetRHI(); - } + } else { // before lighting (for non DBuffer decals) - switch(DecalBlendMode) + switch (DecalBlendMode) { case DBM_Translucent: // @todo: Feature Level 10 does not support separate blends modes for each render target. This could result in the // translucent and stain blend modes looking incorrect when running in this mode. - if(GSupportsSeparateRenderTargetBlendState) + if (GSupportsSeparateRenderTargetBlendState) { - if(bHasNormal) + if (bHasNormal) { return TStaticBlendState< - CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive - CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Normal - CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness - CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor + CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive + CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Normal + CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness + CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); } else { return TStaticBlendState< - CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive - CW_RGB, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal - CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness - CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor + CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive + CW_RGB, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal + CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness + CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); } } - else if(SMFeatureLevel == ERHIFeatureLevel::SM4) + else if (SMFeatureLevel == ERHIFeatureLevel::SM4) { return TStaticBlendState< - CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive - CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Normal - CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness - CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One // BaseColor + CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive + CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Normal + CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness + CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); } case DBM_Stain: - if(GSupportsSeparateRenderTargetBlendState) + if (GSupportsSeparateRenderTargetBlendState) { - if(bHasNormal) + if (bHasNormal) { return TStaticBlendState< - CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive - CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Normal - CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness - CW_RGB, BO_Add, BF_DestColor, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor + CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive + CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Normal + CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness + CW_RGB, BO_Add, BF_DestColor, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); } else { return TStaticBlendState< - CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive - CW_RGB, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal - CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness - CW_RGB, BO_Add, BF_DestColor, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor + CW_RGB, BO_Add, BF_SourceAlpha, BF_One, BO_Add, BF_Zero, BF_One, // Emissive + CW_RGB, BO_Add, BF_Zero, BF_One, BO_Add, BF_Zero, BF_One, // Normal + CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness + CW_RGB, BO_Add, BF_DestColor, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); } } - else if(SMFeatureLevel == ERHIFeatureLevel::SM4) + else if (SMFeatureLevel == ERHIFeatureLevel::SM4) { return TStaticBlendState< - CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Emissive - CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Normal - CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness - CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor + CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Emissive + CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Normal + CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness + CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); } @@ -310,7 +310,7 @@ FBlendStateRHIParamRef GetDecalBlendState(const ERHIFeatureLevel::Type SMFeature default: // the decal type should not be rendered in this pass - internal error - check(0); + check(0); return nullptr; } } @@ -324,19 +324,19 @@ bool RenderPreStencil(FRenderingCompositePassContext& Context, const FMatrix& Co float Radius = ComponentToWorldMatrix.GetMaximumAxisScale(); // if not inside - if(Distance > Radius) + if (Distance > Radius) { float EstimatedDecalSize = Radius / Distance; - + float StencilSizeThreshold = CVarStencilSizeThreshold.GetValueOnRenderThread(); // Check if it's large enough on screen - if(EstimatedDecalSize < StencilSizeThreshold) + if (EstimatedDecalSize < StencilSizeThreshold) { return false; } } - + FGraphicsPipelineStateInitializer GraphicsPSOInit; Context.RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit); @@ -345,10 +345,10 @@ bool RenderPreStencil(FRenderingCompositePassContext& Context, const FMatrix& Co // all the same to have DX10 working GraphicsPSOInit.BlendState = TStaticBlendState< - CW_NONE, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Emissive - CW_NONE, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Normal - CW_NONE, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness - CW_NONE, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor + CW_NONE, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Emissive + CW_NONE, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Normal + CW_NONE, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One, // Metallic, Specular, Roughness + CW_NONE, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One // BaseColor >::GetRHI(); // Carmack's reverse the sandbox stencil bit on the bounds @@ -380,12 +380,12 @@ static EDecalRasterizerState ComputeDecalRasterizerState(bool bInsideDecal, bool { bool bClockwise = bInsideDecal; - if(View.bReverseCulling) + if (View.bReverseCulling) { bClockwise = !bClockwise; } - if (bIsInverted) + if (bIsInverted) { bClockwise = !bClockwise; } @@ -402,8 +402,8 @@ static FDecalDepthState ComputeDecalDepthState(EDecalRenderStage LocalDecalStage FDecalDepthState Ret; Ret.bDepthOutput = (LocalDecalStage == DRS_AfterBasePass); - - if(Ret.bDepthOutput) + + if (Ret.bDepthOutput) { // can be made one enum Ret.DepthTest = DDS_DepthTest; @@ -412,9 +412,9 @@ static FDecalDepthState ComputeDecalDepthState(EDecalRenderStage LocalDecalStage const bool bGBufferDecal = LocalDecalStage == DRS_BeforeLighting; - if(bInsideDecal) + if (bInsideDecal) { - if(bThisDecalUsesStencil) + if (bThisDecalUsesStencil) { Ret.DepthTest = bGBufferDecal ? DDS_DepthAlways_StencilEqual1 : DDS_DepthAlways_StencilEqual1_IgnoreMask; } @@ -425,7 +425,7 @@ static FDecalDepthState ComputeDecalDepthState(EDecalRenderStage LocalDecalStage } else { - if(bThisDecalUsesStencil) + if (bThisDecalUsesStencil) { Ret.DepthTest = bGBufferDecal ? DDS_DepthTest_StencilEqual1 : DDS_DepthTest_StencilEqual1_IgnoreMask; } @@ -440,82 +440,82 @@ static FDecalDepthState ComputeDecalDepthState(EDecalRenderStage LocalDecalStage static FDepthStencilStateRHIParamRef GetDecalDepthState(uint32& StencilRef, FDecalDepthState DecalDepthState) { - switch(DecalDepthState.DepthTest) + switch (DecalDepthState.DepthTest) { - case DDS_DepthAlways_StencilEqual1: - check(!DecalDepthState.bDepthOutput); // todo - StencilRef = STENCIL_SANDBOX_MASK | GET_STENCIL_BIT_MASK(RECEIVE_DECAL, 1); - return TStaticDepthStencilState< - false, CF_Always, - true, CF_Equal, SO_Zero, SO_Zero, SO_Zero, - true, CF_Equal, SO_Zero, SO_Zero, SO_Zero, - STENCIL_SANDBOX_MASK | GET_STENCIL_BIT_MASK(RECEIVE_DECAL, 1), STENCIL_SANDBOX_MASK>::GetRHI(); - - case DDS_DepthAlways_StencilEqual1_IgnoreMask: - check(!DecalDepthState.bDepthOutput); // todo - StencilRef = STENCIL_SANDBOX_MASK; - return TStaticDepthStencilState< - false, CF_Always, - true, CF_Equal, SO_Zero, SO_Zero, SO_Zero, - true, CF_Equal, SO_Zero, SO_Zero, SO_Zero, - STENCIL_SANDBOX_MASK, STENCIL_SANDBOX_MASK>::GetRHI(); + case DDS_DepthAlways_StencilEqual1: + check(!DecalDepthState.bDepthOutput); // todo + StencilRef = STENCIL_SANDBOX_MASK | GET_STENCIL_BIT_MASK(RECEIVE_DECAL, 1); + return TStaticDepthStencilState< + false, CF_Always, + true, CF_Equal, SO_Zero, SO_Zero, SO_Zero, + true, CF_Equal, SO_Zero, SO_Zero, SO_Zero, + STENCIL_SANDBOX_MASK | GET_STENCIL_BIT_MASK(RECEIVE_DECAL, 1), STENCIL_SANDBOX_MASK>::GetRHI(); - case DDS_DepthAlways_StencilEqual0: - check(!DecalDepthState.bDepthOutput); // todo - StencilRef = GET_STENCIL_BIT_MASK(RECEIVE_DECAL, 1); - return TStaticDepthStencilState< - false, CF_Always, - true, CF_Equal, SO_Keep, SO_Keep, SO_Keep, - false, CF_Always, SO_Keep, SO_Keep, SO_Keep, - STENCIL_SANDBOX_MASK | GET_STENCIL_BIT_MASK(RECEIVE_DECAL, 1), 0x00>::GetRHI(); + case DDS_DepthAlways_StencilEqual1_IgnoreMask: + check(!DecalDepthState.bDepthOutput); // todo + StencilRef = STENCIL_SANDBOX_MASK; + return TStaticDepthStencilState< + false, CF_Always, + true, CF_Equal, SO_Zero, SO_Zero, SO_Zero, + true, CF_Equal, SO_Zero, SO_Zero, SO_Zero, + STENCIL_SANDBOX_MASK, STENCIL_SANDBOX_MASK>::GetRHI(); - case DDS_Always: - check(!DecalDepthState.bDepthOutput); // todo + case DDS_DepthAlways_StencilEqual0: + check(!DecalDepthState.bDepthOutput); // todo + StencilRef = GET_STENCIL_BIT_MASK(RECEIVE_DECAL, 1); + return TStaticDepthStencilState< + false, CF_Always, + true, CF_Equal, SO_Keep, SO_Keep, SO_Keep, + false, CF_Always, SO_Keep, SO_Keep, SO_Keep, + STENCIL_SANDBOX_MASK | GET_STENCIL_BIT_MASK(RECEIVE_DECAL, 1), 0x00>::GetRHI(); + + case DDS_Always: + check(!DecalDepthState.bDepthOutput); // todo + StencilRef = 0; + return TStaticDepthStencilState::GetRHI(); + + case DDS_DepthTest_StencilEqual1: + check(!DecalDepthState.bDepthOutput); // todo + StencilRef = STENCIL_SANDBOX_MASK | GET_STENCIL_BIT_MASK(RECEIVE_DECAL, 1); + return TStaticDepthStencilState< + false, CF_DepthNearOrEqual, + true, CF_Equal, SO_Zero, SO_Zero, SO_Zero, + true, CF_Equal, SO_Zero, SO_Zero, SO_Zero, + STENCIL_SANDBOX_MASK | GET_STENCIL_BIT_MASK(RECEIVE_DECAL, 1), STENCIL_SANDBOX_MASK>::GetRHI(); + + case DDS_DepthTest_StencilEqual1_IgnoreMask: + check(!DecalDepthState.bDepthOutput); // todo + StencilRef = STENCIL_SANDBOX_MASK; + return TStaticDepthStencilState< + false, CF_DepthNearOrEqual, + true, CF_Equal, SO_Zero, SO_Zero, SO_Zero, + true, CF_Equal, SO_Zero, SO_Zero, SO_Zero, + STENCIL_SANDBOX_MASK, STENCIL_SANDBOX_MASK>::GetRHI(); + + case DDS_DepthTest_StencilEqual0: + check(!DecalDepthState.bDepthOutput); // todo + StencilRef = GET_STENCIL_BIT_MASK(RECEIVE_DECAL, 1); + return TStaticDepthStencilState< + false, CF_DepthNearOrEqual, + true, CF_Equal, SO_Keep, SO_Keep, SO_Keep, + false, CF_Always, SO_Keep, SO_Keep, SO_Keep, + STENCIL_SANDBOX_MASK | GET_STENCIL_BIT_MASK(RECEIVE_DECAL, 1), 0x00>::GetRHI(); + + case DDS_DepthTest: + if (DecalDepthState.bDepthOutput) + { StencilRef = 0; - return TStaticDepthStencilState::GetRHI(); + return TStaticDepthStencilState::GetRHI(); + } + else + { + StencilRef = 0; + return TStaticDepthStencilState::GetRHI(); + } - case DDS_DepthTest_StencilEqual1: - check(!DecalDepthState.bDepthOutput); // todo - StencilRef = STENCIL_SANDBOX_MASK | GET_STENCIL_BIT_MASK(RECEIVE_DECAL, 1); - return TStaticDepthStencilState< - false, CF_DepthNearOrEqual, - true, CF_Equal, SO_Zero, SO_Zero, SO_Zero, - true, CF_Equal, SO_Zero, SO_Zero, SO_Zero, - STENCIL_SANDBOX_MASK | GET_STENCIL_BIT_MASK(RECEIVE_DECAL, 1), STENCIL_SANDBOX_MASK>::GetRHI(); - - case DDS_DepthTest_StencilEqual1_IgnoreMask: - check(!DecalDepthState.bDepthOutput); // todo - StencilRef = STENCIL_SANDBOX_MASK; - return TStaticDepthStencilState< - false, CF_DepthNearOrEqual, - true, CF_Equal, SO_Zero, SO_Zero, SO_Zero, - true, CF_Equal, SO_Zero, SO_Zero, SO_Zero, - STENCIL_SANDBOX_MASK, STENCIL_SANDBOX_MASK>::GetRHI(); - - case DDS_DepthTest_StencilEqual0: - check(!DecalDepthState.bDepthOutput); // todo - StencilRef = GET_STENCIL_BIT_MASK(RECEIVE_DECAL, 1); - return TStaticDepthStencilState< - false, CF_DepthNearOrEqual, - true, CF_Equal, SO_Keep, SO_Keep, SO_Keep, - false, CF_Always, SO_Keep, SO_Keep, SO_Keep, - STENCIL_SANDBOX_MASK | GET_STENCIL_BIT_MASK(RECEIVE_DECAL, 1), 0x00>::GetRHI(); - - case DDS_DepthTest: - if(DecalDepthState.bDepthOutput) - { - StencilRef = 0; - return TStaticDepthStencilState::GetRHI(); - } - else - { - StencilRef = 0; - return TStaticDepthStencilState::GetRHI(); - } - - default: - check(0); - return nullptr; + default: + check(0); + return nullptr; } } @@ -523,9 +523,9 @@ static FRasterizerStateRHIParamRef GetDecalRasterizerState(EDecalRasterizerState { switch (DecalRasterizerState) { - case DRS_CW: return TStaticRasterizerState::GetRHI(); - case DRS_CCW: return TStaticRasterizerState::GetRHI(); - default: check(0); return nullptr; + case DRS_CW: return TStaticRasterizerState::GetRHI(); + case DRS_CCW: return TStaticRasterizerState::GetRHI(); + default: check(0); return nullptr; } } @@ -538,12 +538,12 @@ const TCHAR* GetStageName(EDecalRenderStage Stage) { // could be implemented with enum reflections as well - switch(Stage) + switch (Stage) { - case DRS_BeforeBasePass: return TEXT("DRS_BeforeBasePass"); - case DRS_AfterBasePass: return TEXT("DRS_AfterBasePass"); - case DRS_BeforeLighting: return TEXT("DRS_BeforeLighting"); - case DRS_Mobile: return TEXT("DRS_Mobile"); + case DRS_BeforeBasePass: return TEXT("DRS_BeforeBasePass"); + case DRS_AfterBasePass: return TEXT("DRS_AfterBasePass"); + case DRS_BeforeLighting: return TEXT("DRS_BeforeLighting"); + case DRS_Mobile: return TEXT("DRS_Mobile"); } return TEXT(""); } @@ -628,20 +628,11 @@ void FRCPassPostProcessDeferredDecals::Process(FRenderingCompositePassContext& C const FSceneViewFamily& ViewFamily = *(View.Family); bool bNeedsDBufferTargets = false; - // Delay creating and clearing the DBuffers since if they're not used, we can use small textures and not eat the mem/perf cost of the clearing them (and fetching in the base pass) - FDelayedRendererAction DelayedCreateAndClearDBuffers; - struct FDelayedCreateAndClearDBuffersData - { - FRenderingCompositePassContext* Context; - FSceneRenderTargets* SceneContext; - bool bUseDummyDBuffers; - } DelayedCreateAndClearDBuffersData = {&Context, &SceneContext, false}; - if (CurrentStage == DRS_BeforeBasePass) { // before BasePass, only if DBuffer is enabled check(bDBuffer); - + // If we're rendering dbuffer decals but there are no decals in the scene, we avoid the // clears/decompresses and set the targets to NULL // The DBufferA-C will be replaced with dummy textures in FDeferredPixelShaderParameters @@ -655,66 +646,60 @@ void FRCPassPostProcessDeferredDecals::Process(FRenderingCompositePassContext& C } // If we need dbuffer targets, initialize them - if ( bNeedsDBufferTargets ) + if (bNeedsDBufferTargets) { - auto CreateAndClearDBuffers = [](FRHICommandListImmediate& InRHICommandList, void* UserData) + FPooledRenderTargetDesc GBufferADesc; + SceneContext.GetGBufferADesc(GBufferADesc); + + // DBuffer: Decal buffer + FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(GBufferADesc.Extent, + PF_B8G8R8A8, + FClearValueBinding::None, + TexCreate_None, + TexCreate_ShaderResource | TexCreate_RenderTargetable, + false, + 1, + true, + true)); + + if (!SceneContext.DBufferA) { - FDelayedCreateAndClearDBuffersData* DelayedData = (FDelayedCreateAndClearDBuffersData*)UserData; - FPooledRenderTargetDesc GBufferADesc; - DelayedData->SceneContext->GetGBufferADesc(GBufferADesc); + Desc.ClearValue = FClearValueBinding::Black; + GRenderTargetPool.FindFreeElement(RHICmdList, Desc, SceneContext.DBufferA, TEXT("DBufferA")); + } - // DBuffer: Decal buffer - FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc( - DelayedData->bUseDummyDBuffers ? FIntPoint(1, 1) : GBufferADesc.Extent, - PF_B8G8R8A8, - FClearValueBinding::None, - TexCreate_None, - TexCreate_ShaderResource | TexCreate_RenderTargetable, - false, - 1, - true, - true)); + if (!SceneContext.DBufferB) + { + Desc.ClearValue = FClearValueBinding(FLinearColor(128.0f / 255.0f, 128.0f / 255.0f, 128.0f / 255.0f, 1)); + GRenderTargetPool.FindFreeElement(RHICmdList, Desc, SceneContext.DBufferB, TEXT("DBufferB")); + } - if (!DelayedData->SceneContext->DBufferA) - { - Desc.ClearValue = FClearValueBinding::Black; - GRenderTargetPool.FindFreeElement(InRHICommandList, Desc, DelayedData->SceneContext->DBufferA, TEXT("DBufferA")); - } + Desc.Format = PF_R8G8; - if (!DelayedData->SceneContext->DBufferB) - { - Desc.ClearValue = FClearValueBinding(FLinearColor(128.0f / 255.0f, 128.0f / 255.0f, 128.0f / 255.0f, 1)); - GRenderTargetPool.FindFreeElement(InRHICommandList, Desc, DelayedData->SceneContext->DBufferB, TEXT("DBufferB")); - } + if (!SceneContext.DBufferC) + { + Desc.ClearValue = FClearValueBinding(FLinearColor(0, 1, 0, 1)); + GRenderTargetPool.FindFreeElement(RHICmdList, Desc, SceneContext.DBufferC, TEXT("DBufferC")); + } - Desc.Format = PF_R8G8; + // we assume views are non overlapping, then we need to clear only once in the beginning, otherwise we would need to set scissor rects + // and don't get FastClear any more. + bool bFirstView = Context.View.Family->Views[0] == &Context.View; - if (!DelayedData->SceneContext->DBufferC) - { - Desc.ClearValue = FClearValueBinding(FLinearColor(0, 1, 0, 1)); - GRenderTargetPool.FindFreeElement(InRHICommandList, Desc, DelayedData->SceneContext->DBufferC, TEXT("DBufferC")); - } + if (bFirstView) + { + SCOPED_DRAW_EVENT(RHICmdList, DBufferClear); - // we assume views are non overlapping, then we need to clear only once in the beginning, otherwise we would need to set scissor rects - // and don't get FastClear any more. - bool bFirstView = DelayedData->Context->View.Family->Views[0] == &DelayedData->Context->View; - if (bFirstView) - { - SCOPED_DRAW_EVENT(InRHICommandList, DBufferClear); + FRHIRenderTargetView RenderTargets[3]; + RenderTargets[0] = FRHIRenderTargetView(SceneContext.DBufferA->GetRenderTargetItem().TargetableTexture, 0, -1, ERenderTargetLoadAction::EClear, ERenderTargetStoreAction::EStore); + RenderTargets[1] = FRHIRenderTargetView(SceneContext.DBufferB->GetRenderTargetItem().TargetableTexture, 0, -1, ERenderTargetLoadAction::EClear, ERenderTargetStoreAction::EStore); + RenderTargets[2] = FRHIRenderTargetView(SceneContext.DBufferC->GetRenderTargetItem().TargetableTexture, 0, -1, ERenderTargetLoadAction::EClear, ERenderTargetStoreAction::EStore); - FRHIRenderTargetView RenderTargets[3]; - RenderTargets[0] = FRHIRenderTargetView(DelayedData->SceneContext->DBufferA->GetRenderTargetItem().TargetableTexture, 0, -1, ERenderTargetLoadAction::EClear, ERenderTargetStoreAction::EStore); - RenderTargets[1] = FRHIRenderTargetView(DelayedData->SceneContext->DBufferB->GetRenderTargetItem().TargetableTexture, 0, -1, ERenderTargetLoadAction::EClear, ERenderTargetStoreAction::EStore); - RenderTargets[2] = FRHIRenderTargetView(DelayedData->SceneContext->DBufferC->GetRenderTargetItem().TargetableTexture, 0, -1, ERenderTargetLoadAction::EClear, ERenderTargetStoreAction::EStore); + FRHIDepthRenderTargetView DepthView(SceneContext.GetSceneDepthTexture(), ERenderTargetLoadAction::ELoad, ERenderTargetStoreAction::ENoAction, ERenderTargetLoadAction::ELoad, ERenderTargetStoreAction::ENoAction, FExclusiveDepthStencil(FExclusiveDepthStencil::DepthRead_StencilWrite)); - FRHIDepthRenderTargetView DepthView(DelayedData->SceneContext->GetSceneDepthTexture(), ERenderTargetLoadAction::ELoad, ERenderTargetStoreAction::ENoAction, ERenderTargetLoadAction::ELoad, ERenderTargetStoreAction::ENoAction, FExclusiveDepthStencil(FExclusiveDepthStencil::DepthRead_StencilWrite)); - - // If we don't need the DBuffers, don't clear depth as it won't match the dummy sizes - FRHISetRenderTargetsInfo Info(3, RenderTargets, DelayedData->bUseDummyDBuffers ? FRHIDepthRenderTargetView() : DepthView); - InRHICommandList.SetRenderTargetsAndClear(Info); - } - }; - DelayedCreateAndClearDBuffers.SetDelayedFunction(CreateAndClearDBuffers, &DelayedCreateAndClearDBuffersData); + FRHISetRenderTargetsInfo Info(3, RenderTargets, DepthView); + RHICmdList.SetRenderTargetsAndClear(Info); + } } // if ( bNeedsDBufferTargets ) } @@ -726,7 +711,6 @@ void FRCPassPostProcessDeferredDecals::Process(FRenderingCompositePassContext& C { if (Context.View.MeshDecalPrimSet.NumPrims() > 0) { - DelayedCreateAndClearDBuffers.RunFunctionOnce(RHICmdList); check(bNeedsDBufferTargets || CurrentStage != DRS_BeforeBasePass); RenderMeshDecals(Context, CurrentStage); } @@ -737,7 +721,7 @@ void FRCPassPostProcessDeferredDecals::Process(FRenderingCompositePassContext& C //don't early return. Resolves must be run for fast clears to work. if (Scene.Decals.Num()) { - check(bNeedsDBufferTargets || CurrentStage != DRS_BeforeBasePass ); + check(bNeedsDBufferTargets || CurrentStage != DRS_BeforeBasePass); FDecalRenderTargetManager RenderTargetManager(RHICmdList, Context.GetShaderPlatform(), CurrentStage); // Build a list of decals that need to be rendered for this view @@ -746,7 +730,6 @@ void FRCPassPostProcessDeferredDecals::Process(FRenderingCompositePassContext& C if (SortedDecals.Num() > 0) { - DelayedCreateAndClearDBuffers.RunFunctionOnce(RHICmdList); SCOPED_DRAW_EVENTF(RHICmdList, DeferredDecalsInner, TEXT("DeferredDecalsInner %d/%d"), SortedDecals.Num(), Scene.Decals.Num()); FGraphicsPipelineStateInitializer GraphicsPSOInit; @@ -787,9 +770,9 @@ void FRCPassPostProcessDeferredDecals::Process(FRenderingCompositePassContext& C // Here we assume that GBuffer can only be WorldNormal since it is the only GBufferTarget handled correctly. if (RenderTargetManager.bGufferADirty && DecalData.MaterialResource->NeedsGBuffer()) - { + { RHICmdList.CopyToResolveTarget(SceneContext.GBufferA->GetRenderTargetItem().TargetableTexture, SceneContext.GBufferA->GetRenderTargetItem().TargetableTexture, true, FResolveParams()); - RenderTargetManager.TargetsToResolve[FDecalRenderTargetManager::GBufferAIndex] = nullptr; + RenderTargetManager.TargetsToResolve[FDecalRenderTargetManager::GBufferAIndex] = nullptr; RenderTargetManager.bGufferADirty = false; } @@ -841,7 +824,7 @@ void FRCPassPostProcessDeferredDecals::Process(FRenderingCompositePassContext& C { // Account for the reversal of handedness caused by negative scale on the decal const auto& Scale3d = DecalProxy.ComponentTrans.GetScale3D(); - bReverseHanded = Scale3d[0] * Scale3d[1] * Scale3d[2] < 0.f; + bReverseHanded = Scale3d[0] * Scale3d[1] * Scale3d[2] < 0.f; } EDecalRasterizerState DecalRasterizerState = ComputeDecalRasterizerState(bInsideDecal, bReverseHanded, View); @@ -874,19 +857,11 @@ void FRCPassPostProcessDeferredDecals::Process(FRenderingCompositePassContext& C // we don't modify stencil but if out input was having stencil for us (after base pass - we need to clear) // Clear stencil to 0, which is the assumed default by other passes - DrawClearQuad(RHICmdList, SMFeatureLevel, false, FLinearColor(), false, 0, true, 0, SceneContext.GetSceneDepthSurface()->GetSizeXY(), FIntRect()); + DrawClearQuad(RHICmdList, false, FLinearColor(), false, 0, true, 0, SceneContext.GetSceneDepthSurface()->GetSizeXY(), FIntRect()); } if (CurrentStage == DRS_BeforeBasePass) { - if (!DelayedCreateAndClearDBuffers.HasBeenCalled()) - { - // If we don't need the DBuffers, use 1x1 textures instead - DelayedCreateAndClearDBuffersData.bUseDummyDBuffers = true; - } - - DelayedCreateAndClearDBuffers.RunFunctionOnce(RHICmdList); - // combine DBuffer RTWriteMasks; will end up in one texture we can load from in the base pass PS and decide whether to do the actual work or not RenderTargetManager.FlushMetaData(); @@ -900,7 +875,7 @@ void FRCPassPostProcessDeferredDecals::Process(FRenderingCompositePassContext& C RenderTargetManager.ResolveTargets(); } - if (CurrentStage == DRS_BeforeBasePass && bNeedsDBufferTargets ) + if (CurrentStage == DRS_BeforeBasePass && bNeedsDBufferTargets) { // before BasePass GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SceneContext.DBufferA); @@ -922,7 +897,7 @@ FPooledRenderTargetDesc FRCPassPostProcessDeferredDecals::ComputeOutputDesc(EPas { // This pass creates it's own output so the compositing graph output isn't needed. FPooledRenderTargetDesc Ret; - + Ret.DebugName = TEXT("DeferredDecals"); return Ret; @@ -941,11 +916,16 @@ void FDecalRenderTargetManager::ResolveTargets() TargetsToResolve[FDecalRenderTargetManager::GBufferAIndex] = SceneContext.GBufferA->GetRenderTargetItem().TargetableTexture; } + //those have been cleared or rendered to and need to be resolved + TargetsToResolve[FDecalRenderTargetManager::DBufferAIndex] = SceneContext.DBufferA ? SceneContext.DBufferA->GetRenderTargetItem().TargetableTexture : nullptr; + TargetsToResolve[FDecalRenderTargetManager::DBufferBIndex] = SceneContext.DBufferB ? SceneContext.DBufferB->GetRenderTargetItem().TargetableTexture : nullptr; + TargetsToResolve[FDecalRenderTargetManager::DBufferCIndex] = SceneContext.DBufferC ? SceneContext.DBufferC->GetRenderTargetItem().TargetableTexture : nullptr; + // resolve the targets we wrote to. FResolveParams ResolveParams; for (int32 i = 0; i < ResolveBufferMax; ++i) { - if (TargetsToResolve[i] ) + if (TargetsToResolve[i]) { RHICmdList.CopyToResolveTarget(TargetsToResolve[i], TargetsToResolve[i], true, ResolveParams); } @@ -1051,4 +1031,4 @@ void FDecalRenderTargetManager::SetRenderTargetMode(FDecalRenderingCommon::ERend void FDecalRenderTargetManager::FlushMetaData() { RHICmdList.TransitionResource(EResourceTransitionAccess::EMetaData, nullptr); -} +} \ No newline at end of file diff --git a/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessLpvIndirect.cpp b/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessLpvIndirect.cpp index 092e38956e16..35c0683262a8 100644 --- a/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessLpvIndirect.cpp +++ b/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessLpvIndirect.cpp @@ -21,7 +21,7 @@ #include "ScenePrivate.h" #include "PostProcess/SceneFilterRendering.h" #include "PostProcess/PostProcessing.h" -#include "LightPropagationVolumeBlendable.h" +#include "LightPropagationVolumeSettings.h" #include "PipelineStateCache.h" IMPLEMENT_UNIFORM_BUFFER_STRUCT(FLpvReadUniformBufferParameters,TEXT("LpvRead")); @@ -99,7 +99,7 @@ public: } FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); SetTextureParameter(Context.RHICmdList, ShaderRHI, PreIntegratedGF, PreIntegratedGFSampler, TStaticSamplerState::GetRHI(), GSystemTextures.PreintegratedGF->GetRenderTargetItem().ShaderResourceTexture); } @@ -190,7 +190,7 @@ public: FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); } // FShader interface. diff --git a/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessMeshDecals.cpp b/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessMeshDecals.cpp index eb4c1213a538..5ac9e6772555 100644 --- a/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessMeshDecals.cpp +++ b/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessMeshDecals.cpp @@ -576,7 +576,7 @@ static void RenderPrimitive(FRenderingCompositePassContext& Context, FDecalDrawi View, DrawContext, StaticMesh, - StaticMesh.Elements.Num() == 1 ? 1 : View.StaticMeshBatchVisibility[StaticMesh.Id], + StaticMesh.bRequiresPerElementVisibility ? View.StaticMeshBatchVisibility[StaticMesh.BatchVisibilityId] : ((1ull << StaticMesh.Elements.Num()) - 1), false, DrawRenderStateLocal, PrimitiveSceneInfo->Proxy, diff --git a/Engine/Source/Runtime/Renderer/Private/CustomDepthRendering.cpp b/Engine/Source/Runtime/Renderer/Private/CustomDepthRendering.cpp index 911350173e80..cdede5fddb63 100644 --- a/Engine/Source/Runtime/Renderer/Private/CustomDepthRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/CustomDepthRendering.cpp @@ -95,7 +95,7 @@ bool FCustomDepthPrimSet::DrawPrims(FRHICommandListImmediate& RHICmdList, const View, Context, StaticMesh, - StaticMesh.bRequiresPerElementVisibility ? View.StaticMeshBatchVisibility[StaticMesh.Id] : ((1ull << StaticMesh.Elements.Num()) - 1), + StaticMesh.bRequiresPerElementVisibility ? View.StaticMeshBatchVisibility[StaticMesh.BatchVisibilityId] : ((1ull << StaticMesh.Elements.Num()) - 1), true, DrawRenderStateLocal2, PrimitiveSceneProxy, diff --git a/Engine/Source/Runtime/Renderer/Private/DeferredShadingRenderer.cpp b/Engine/Source/Runtime/Renderer/Private/DeferredShadingRenderer.cpp index 4017ea8806ce..03aa7c30db55 100644 --- a/Engine/Source/Runtime/Renderer/Private/DeferredShadingRenderer.cpp +++ b/Engine/Source/Runtime/Renderer/Private/DeferredShadingRenderer.cpp @@ -427,17 +427,9 @@ static void SetAndClearViewGBuffer(FRHICommandListImmediate& RHICmdList, FViewIn FSceneRenderTargets::Get(RHICmdList).BeginRenderingGBuffer(RHICmdList, ERenderTargetLoadAction::EClear, DepthLoadAction, DepthStencilAccess, View.Family->EngineShowFlags.ShaderComplexity, ClearColor); } -static TAutoConsoleVariable CVarOcclusionQueryLocation( - TEXT("r.OcclusionQueryLocation"), - 0, - TEXT("Controls when occlusion queries are rendered. Rendering before the base pass may give worse occlusion (because not all occluders generally render in the earlyzpass). ") - TEXT("However, it may reduce CPU waiting for query result stalls on some platforms and increase overall performance.") - TEXT("0: After BasePass.") - TEXT("1: After EarlyZPass, but before BasePass.")); - -void FDeferredShadingSceneRenderer::RenderOcclusion(FRHICommandListImmediate& RHICmdList, bool bRenderQueries, bool bRenderHZB) +void FDeferredShadingSceneRenderer::RenderOcclusion(FRHICommandListImmediate& RHICmdList, bool bRenderQueries) { - if (bRenderQueries || bRenderHZB) + if (bRenderQueries) { FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); @@ -454,7 +446,6 @@ void FDeferredShadingSceneRenderer::RenderOcclusion(FRHICommandListImmediate& RH // This is done after the downsampled depth buffer is created so that it can be used for issuing queries BeginOcclusionTests(RHICmdList, bRenderQueries); - if (bRenderHZB) { RHICmdList.TransitionResource( EResourceTransitionAccess::EReadable, SceneContext.GetSceneDepthSurface() ); @@ -494,7 +485,7 @@ void FDeferredShadingSceneRenderer::RenderOcclusion(FRHICommandListImmediate& RH // for these query results on some platforms. RHICmdList.SubmitCommandsHint(); - if (bRenderQueries && GRHIThread) + if (bRenderQueries && IsRunningRHIInSeparateThread()) { SCOPE_CYCLE_COUNTER(STAT_OcclusionSubmittedFence_Dispatch); int32 NumFrames = FOcclusionQueryHelpers::GetNumBufferedFrames(); @@ -532,7 +523,7 @@ static TAutoConsoleVariable CVarStallInitViews( void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList) { FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); - + //make sure all the targets we're going to use will be safely writable. GRenderTargetPool.TransitionTargetsWritable(RHICmdList); @@ -541,7 +532,7 @@ void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList) bool bDBuffer = IsDBufferEnabled(); - if (GRHIThread) + if (IsRunningRHIInSeparateThread()) { SCOPE_CYCLE_COUNTER(STAT_OcclusionSubmittedFence_Wait); int32 BlockFrame = FOcclusionQueryHelpers::GetNumBufferedFrames() - 1; @@ -568,6 +559,7 @@ void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList) // Allocate the maximum scene render target space for the current view family. SceneContext.Allocate(RHICmdList, ViewFamily); } + SceneContext.AllocDummyGBufferTargets(RHICmdList); FGraphEventArray SortEvents; FILCUpdatePrimTaskData ILCTaskData; @@ -621,7 +613,7 @@ void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList) } } - if (GRHIThread) + if (IsRunningRHIInSeparateThread()) { // we will probably stall on occlusion queries, so might as well have the RHI thread and GPU work while we wait. SCOPE_CYCLE_COUNTER(STAT_PostInitViews_FlushDel); @@ -788,13 +780,11 @@ void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList) SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_AllocGBufferTargets); SceneContext.PreallocGBufferTargets(); // Even if !bShouldRenderVelocities, the velocity buffer must be bound because it's a compile time option for the shader. SceneContext.AllocGBufferTargets(RHICmdList); - } + } - //occlusion can't run before basepass if there's no prepass to fill in some depth to occlude against. - bool bOcclusionBeforeBasePass = ((CVarOcclusionQueryLocation.GetValueOnRenderThread() == 1) && bNeedsPrePass) || IsForwardShadingEnabled(FeatureLevel); - bool bHZBBeforeBasePass = bOcclusionBeforeBasePass && (EarlyZPassMode == EDepthDrawingMode::DDM_AllOccluders || EarlyZPassMode == EDepthDrawingMode::DDM_AllOpaque); + const bool bOcclusionBeforeBasePass = (EarlyZPassMode == EDepthDrawingMode::DDM_AllOccluders) || (EarlyZPassMode == EDepthDrawingMode::DDM_AllOpaque); - RenderOcclusion(RHICmdList, bOcclusionBeforeBasePass, bHZBBeforeBasePass); + RenderOcclusion(RHICmdList, bOcclusionBeforeBasePass); ServiceLocalQueue(); if (bOcclusionBeforeBasePass) @@ -918,7 +908,7 @@ void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList) { // clear out emissive and baked lighting (not too efficient but simple and only needed for this debug view) SceneContext.BeginRenderingSceneColor(RHICmdList); - DrawClearQuad(RHICmdList, GMaxRHIFeatureLevel, FLinearColor(0, 0, 0, 0)); + DrawClearQuad(RHICmdList, FLinearColor(0, 0, 0, 0)); } SceneContext.DBufferA.SafeRelease(); @@ -944,10 +934,15 @@ void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList) SceneContext.ResolveSceneDepthToAuxiliaryTexture(RHICmdList); bool bOcclusionAfterBasePass = bIsOcclusionTesting && !bOcclusionBeforeBasePass; - bool bHZBAfterBasePass = !bHZBBeforeBasePass; - RenderOcclusion(RHICmdList, bOcclusionAfterBasePass, bHZBAfterBasePass); + RenderOcclusion(RHICmdList, bOcclusionAfterBasePass); ServiceLocalQueue(); + if (bUseGBuffer) + { + SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_Resolve_After_Basepass); + SceneContext.FinishRenderingGBuffer(RHICmdList); + } + if (!bOcclusionBeforeBasePass) { RenderShadowDepthMaps(RHICmdList); @@ -955,12 +950,6 @@ void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList) ServiceLocalQueue(); } - if (bUseGBuffer) - { - SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_Resolve_After_Basepass); - SceneContext.FinishRenderingGBuffer(RHICmdList); - } - if(GetCustomDepthPassLocation() == 1) { QUICK_SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_CustomDepthPass1); @@ -1012,6 +1001,10 @@ void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList) SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_AfterBasePass); GRenderTargetPool.AddPhaseEvent(TEXT("AfterBasePass")); + if (!IsForwardShadingEnabled(FeatureLevel)) + { + SceneContext.ResolveSceneDepthTexture(RHICmdList, FResolveRect(0, 0, ViewFamily.FamilySizeX, ViewFamily.FamilySizeY)); + } for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) { @@ -1103,6 +1096,8 @@ void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList) RenderDeferredReflections(RHICmdList, DynamicBentNormalAO, VelocityRT); ServiceLocalQueue(); + DynamicBentNormalAO = NULL; + // Post-lighting composition lighting stage // e.g. ScreenSpaceSubsurfaceScattering for(int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex) @@ -1183,7 +1178,19 @@ void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList) SCOPE_CYCLE_COUNTER(STAT_TranslucencyDrawTime); RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_Translucency)); - RenderTranslucency(RHICmdList); + + // For now there is only one resolve for all translucency passes. This can be changed by enabling the resolve in RenderTranslucency() + ConditionalResolveSceneColorForTranslucentMaterials(RHICmdList); + if (ViewFamily.AllowTranslucencyAfterDOF()) + { + RenderTranslucency(RHICmdList, ETranslucencyPass::TPT_StandardTranslucency); + // Translucency after DOF is rendered now, but stored in the separate translucency RT for later use. + RenderTranslucency(RHICmdList, ETranslucencyPass::TPT_TranslucencyAfterDOF); + } + else // Otherwise render translucent primitives in a single bucket. + { + RenderTranslucency(RHICmdList, ETranslucencyPass::TPT_AllTranslucency); + } ServiceLocalQueue(); static const auto DisableDistortionCVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.DisableDistortion")); @@ -1198,6 +1205,7 @@ void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList) RenderDistortion(RHICmdList); ServiceLocalQueue(); } + RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_AfterTranslucency)); } @@ -1265,7 +1273,7 @@ void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList) } // End of frame, we don't need it anymore - FSceneRenderTargets::Get(RHICmdList).FreeSeparateTranslucencyDepth(); + FSceneRenderTargets::Get(RHICmdList).FreeDownsampledTranslucencyDepth(); // we rendered to it during the frame, seems we haven't made use of it, because it should be released check(!FSceneRenderTargets::Get(RHICmdList).SeparateTranslucencyRT); diff --git a/Engine/Source/Runtime/Renderer/Private/DeferredShadingRenderer.h b/Engine/Source/Runtime/Renderer/Private/DeferredShadingRenderer.h index 63a17493907e..369e098780c9 100644 --- a/Engine/Source/Runtime/Renderer/Private/DeferredShadingRenderer.h +++ b/Engine/Source/Runtime/Renderer/Private/DeferredShadingRenderer.h @@ -112,7 +112,7 @@ public: /** Finishes the view family rendering. */ void RenderFinish(FRHICommandListImmediate& RHICmdList); - void RenderOcclusion(FRHICommandListImmediate& RHICmdList, bool bRenderQueries, bool bRenderHZB); + void RenderOcclusion(FRHICommandListImmediate& RHICmdList, bool bRenderQueries); /** Renders the view family. */ virtual void Render(FRHICommandListImmediate& RHICmdList) override; @@ -251,15 +251,15 @@ private: /** Issues a timestamp query for the end of the separate translucency pass. */ void EndTimingSeparateTranslucencyPass(FRHICommandListImmediate& RHICmdList, const FViewInfo& View); - /** - * Renders the scene's translucency, parallel version - */ - void RenderTranslucencyParallel(FRHICommandListImmediate& RHICmdList); - /** - * Renders the scene's translucency. - */ - void RenderTranslucency(FRHICommandListImmediate& RHICmdList); + /** Setup the downsampled view uniform buffer if it was not already built */ + void SetupDownsampledTranslucencyViewUniformBuffer(FRHICommandListImmediate& RHICmdList, FViewInfo& View); + + /** Resolve the scene color if any translucent material needs it. */ + void ConditionalResolveSceneColorForTranslucentMaterials(FRHICommandListImmediate& RHICmdList); + + /** Renders the scene's translucency. */ + void RenderTranslucency(FRHICommandListImmediate& RHICmdList, ETranslucencyPass::Type TranslucencyPass); /** Renders the scene's light shafts */ void RenderLightShaftOcclusion(FRHICommandListImmediate& RHICmdList, FLightShaftsOutput& Output); @@ -298,13 +298,14 @@ private: /** Renders capsule shadows for all per-object shadows using it for the given light. */ bool RenderCapsuleDirectShadows( - const FLightSceneInfo& LightSceneInfo, FRHICommandListImmediate& RHICmdList, + const FLightSceneInfo& LightSceneInfo, + IPooledRenderTarget* ScreenShadowMaskTexture, const TArray& CapsuleShadows, bool bProjectingForForwardShading) const; /** Sets up ViewState buffers for rendering capsule shadows. */ - void SetupIndirectCapsuleShadows(FRHICommandListImmediate& RHICmdList, const FViewInfo& View, bool bPrepareLightData, int32& NumCapsuleShapes, int32& NumMeshDistanceFieldCasters) const; + void SetupIndirectCapsuleShadows(FRHICommandListImmediate& RHICmdList, const FViewInfo& View, bool bPrepareLightData, int32& NumCapsuleShapes, int32& NumMeshesWithCapsules, int32& NumMeshDistanceFieldCasters) const; /** Renders indirect shadows from capsules modulated onto scene color. */ void RenderIndirectCapsuleShadows( @@ -316,7 +317,7 @@ private: void RenderCapsuleShadowsForMovableSkylight(FRHICommandListImmediate& RHICmdList, TRefCountPtr& BentNormalOutput) const; /** Render deferred projections of shadows for a given light into the light attenuation buffer. */ - bool RenderShadowProjections(FRHICommandListImmediate& RHICmdList, const FLightSceneInfo* LightSceneInfo, bool& bInjectedTranslucentVolume); + bool RenderShadowProjections(FRHICommandListImmediate& RHICmdList, const FLightSceneInfo* LightSceneInfo, IPooledRenderTarget* ScreenShadowMaskTexture, bool& bInjectedTranslucentVolume); /** Render shadow projections when forward rendering. */ void RenderForwardShadingShadowProjections(FRHICommandListImmediate& RHICmdList); @@ -327,15 +328,16 @@ private: * @param LightSceneInfo Represents the current light * @param LightIndex The light's index into FScene::Lights */ - bool RenderLightFunction(FRHICommandListImmediate& RHICmdList, const FLightSceneInfo* LightSceneInfo, bool bLightAttenuationCleared, bool bProjectingForForwardShading); + bool RenderLightFunction(FRHICommandListImmediate& RHICmdList, const FLightSceneInfo* LightSceneInfo, IPooledRenderTarget* ScreenShadowMaskTexture, bool bLightAttenuationCleared, bool bProjectingForForwardShading); /** Renders a light function indicating that whole scene shadowing being displayed is for previewing only, and will go away in game. */ - bool RenderPreviewShadowsIndicator(FRHICommandListImmediate& RHICmdList, const FLightSceneInfo* LightSceneInfo, bool bLightAttenuationCleared); + bool RenderPreviewShadowsIndicator(FRHICommandListImmediate& RHICmdList, const FLightSceneInfo* LightSceneInfo, IPooledRenderTarget* ScreenShadowMaskTexture, bool bLightAttenuationCleared); /** Renders a light function with the given material. */ bool RenderLightFunctionForMaterial( FRHICommandListImmediate& RHICmdList, const FLightSceneInfo* LightSceneInfo, + IPooledRenderTarget* ScreenShadowMaskTexture, const FMaterialRenderProxy* MaterialProxy, bool bLightAttenuationCleared, bool bProjectingForForwardShading, @@ -348,7 +350,7 @@ private: * @param LightIndex The light's index into FScene::Lights * @return true if anything got rendered */ - void RenderLight(FRHICommandList& RHICmdList, const FLightSceneInfo* LightSceneInfo, bool bRenderOverlap, bool bIssueDrawEvent); + void RenderLight(FRHICommandList& RHICmdList, const FLightSceneInfo* LightSceneInfo, IPooledRenderTarget* ScreenShadowMaskTexture, bool bRenderOverlap, bool bIssueDrawEvent); /** Renders an array of simple lights using standard deferred shading. */ void RenderSimpleLightsStandardDeferred(FRHICommandListImmediate& RHICmdList, const FSimpleLightArray& SimpleLights); @@ -385,8 +387,9 @@ private: void RenderLocalLightsForVolumetricFog( FRHICommandListImmediate& RHICmdList, FViewInfo& View, + bool bUseTemporalReprojection, + const struct FVolumetricFogIntegrationParameterData& IntegrationData, const FExponentialHeightFogSceneInfo& FogInfo, - IPooledRenderTarget* VBufferA, FIntVector VolumetricFogGridSize, FVector GridZParams, const FPooledRenderTargetDesc& VolumeDesc, @@ -404,11 +407,10 @@ private: void VoxelizeFogVolumePrimitives( FRHICommandListImmediate& RHICmdList, const FViewInfo& View, + const FVolumetricFogIntegrationParameterData& IntegrationData, FIntVector VolumetricFogGridSize, FVector GridZParams, - float VolumetricFogDistance, - IPooledRenderTarget* VBufferA, - IPooledRenderTarget* VBufferB); + float VolumetricFogDistance); void ComputeVolumetricFog(FRHICommandListImmediate& RHICmdList); @@ -437,7 +439,8 @@ private: void UpdateGlobalDistanceFieldObjectBuffers(FRHICommandListImmediate& RHICmdList); - void DrawAllTranslucencyPasses(FRHICommandListImmediate& RHICmdList, const FViewInfo& View, const FDrawingPolicyRenderState& DrawRenderState, ETranslucencyPass::Type TranslucenyPassType); + void RenderViewTranslucency(FRHICommandListImmediate& RHICmdList, const FViewInfo& View, const FDrawingPolicyRenderState& DrawRenderState, ETranslucencyPass::Type TranslucenyPass); + void RenderViewTranslucencyParallel(FRHICommandListImmediate& RHICmdList, const FViewInfo& View, const FDrawingPolicyRenderState& DrawRenderState, ETranslucencyPass::Type TranslucencyPass); void CopySceneCaptureComponentToTarget(FRHICommandListImmediate& RHICmdList); diff --git a/Engine/Source/Runtime/Renderer/Private/DepthRendering.cpp b/Engine/Source/Runtime/Renderer/Private/DepthRendering.cpp index 41cb231fa97e..9e3ace04f8e5 100644 --- a/Engine/Source/Runtime/Renderer/Private/DepthRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/DepthRendering.cpp @@ -232,7 +232,7 @@ public: FMeshMaterialShader::SetParameters(RHICmdList, GetPixelShader(),MaterialRenderProxy,MaterialResource,*View,ViewUniformBuffer,ESceneRenderTargetsMode::DontSet); // For debug view shaders, don't apply the depth offset as their base pass PS are using global shaders with depth equal. - SetShaderValue(RHICmdList, GetPixelShader(), ApplyDepthOffsetParameter, !View || !View->Family->UseDebugViewPS()); + SetShaderValue(RHICmdList, GetPixelShader(), ApplyDepthOffsetParameter, !View->Family->UseDebugViewPS()); SetShaderValue(RHICmdList, GetPixelShader(), MobileColorValue, InMobileColorValue); } @@ -915,7 +915,8 @@ static void RenderHiddenAreaMaskView(FRHICommandList& RHICmdList, FGraphicsPipel const auto ShaderMap = GetGlobalShaderMap(FeatureLevel); TShaderMapRef > VertexShader(ShaderMap); - GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GetVertexDeclarationFVector4(); + extern TGlobalResource GFilterVertexDeclaration; + GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI; GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(*VertexShader); GraphicsPSOInit.PrimitiveType = PT_TriangleList; @@ -1309,7 +1310,7 @@ bool FDeferredShadingSceneRenderer::RenderPrePass(FRHICommandListImmediate& RHIC } RHICmdList.SetViewport(FullViewRect.Min.X, FullViewRect.Min.Y, 0, FullViewRect.Max.X, FullViewRect.Max.Y, 1); } - DrawClearQuad(RHICmdList, GMaxRHIFeatureLevel, false, FLinearColor::Transparent, false, 0, true, 0); + DrawClearQuad(RHICmdList, false, FLinearColor::Transparent, false, 0, true, 0); } SceneContext.FinishRenderingPrePass(RHICmdList); diff --git a/Engine/Source/Runtime/Renderer/Private/DistanceFieldAmbientOcclusion.cpp b/Engine/Source/Runtime/Renderer/Private/DistanceFieldAmbientOcclusion.cpp index 33b6d7b28ced..eb2f05938272 100644 --- a/Engine/Source/Runtime/Renderer/Private/DistanceFieldAmbientOcclusion.cpp +++ b/Engine/Source/Runtime/Renderer/Private/DistanceFieldAmbientOcclusion.cpp @@ -91,7 +91,15 @@ FAutoConsoleVariableRef CVarAOOverwriteSceneColor( ECVF_RenderThreadSafe ); -int32 GMaxDistanceFieldObjectsPerCullTile = 256; +int32 GAOJitterConeDirections = 0; +FAutoConsoleVariableRef CVarAOJitterConeDirections( + TEXT("r.AOJitterConeDirections"), + GAOJitterConeDirections, + TEXT(""), + ECVF_RenderThreadSafe + ); + +int32 GMaxDistanceFieldObjectsPerCullTile = 512; FAutoConsoleVariableRef CVarMaxDistanceFieldObjectsPerCullTile( TEXT("r.AOMaxObjectsPerCullTile"), GMaxDistanceFieldObjectsPerCullTile, @@ -160,7 +168,21 @@ const FVector RelaxedSpacedVectors9[] = FVector(0.032967, -0.435625, 0.899524) }; -void GetSpacedVectors(TArray >& OutVectors) +float TemporalHalton2( int32 Index, int32 Base ) +{ + float Result = 0.0f; + float InvBase = 1.0f / Base; + float Fraction = InvBase; + while( Index > 0 ) + { + Result += ( Index % Base ) * Fraction; + Index /= Base; + Fraction *= InvBase; + } + return Result; +} + +void GetSpacedVectors(uint32 FrameNumber, TArray >& OutVectors) { OutVectors.Empty(ARRAY_COUNT(SpacedVectors9)); @@ -178,6 +200,22 @@ void GetSpacedVectors(TArray >& OutVectors) OutVectors.Add(RelaxedSpacedVectors9[i]); } } + + if (GAOJitterConeDirections) + { + float RandomAngle = TemporalHalton2(FrameNumber & 1023, 2) * 2 * PI; + float CosRandomAngle = FMath::Cos(RandomAngle); + float SinRandomAngle = FMath::Sin(RandomAngle); + + for (int32 i = 0; i < OutVectors.Num(); i++) + { + FVector ConeDirection = OutVectors[i]; + FVector2D ConeDirectionXY(ConeDirection.X, ConeDirection.Y); + ConeDirectionXY = FVector2D(FVector2D::DotProduct(ConeDirectionXY, FVector2D(CosRandomAngle, -SinRandomAngle)), FVector2D::DotProduct(ConeDirectionXY, FVector2D(SinRandomAngle, CosRandomAngle))); + OutVectors[i].X = ConeDirectionXY.X; + OutVectors[i].Y = ConeDirectionXY.Y; + } + } } // Cone half angle derived from each cone covering an equal solid angle @@ -247,7 +285,7 @@ public: FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View.ViewUniformBuffer); AOParameters.Set(RHICmdList, ShaderRHI, Parameters); - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_PostProcess); } // FShader interface. virtual bool Serialize(FArchive& Ar) override @@ -305,7 +343,7 @@ public: RHICmdList.TransitionResource(EResourceTransitionAccess::ERWBarrier, EResourceTransitionPipeline::EComputeToCompute, DistanceFieldNormalValue.UAV); DistanceFieldNormal.SetTexture(RHICmdList, ShaderRHI, DistanceFieldNormalValue.ShaderResourceTexture, DistanceFieldNormalValue.UAV); AOParameters.Set(RHICmdList, ShaderRHI, Parameters); - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_PostProcess); } void UnsetParameters(FRHICommandList& RHICmdList, FSceneRenderTargetItem& DistanceFieldNormalValue) @@ -774,6 +812,7 @@ bool FDeferredShadingSceneRenderer::RenderDistanceFieldLighting( { const FIntPoint BufferSize = GetBufferSizeForAO(); FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, PF_FloatRGBA, FClearValueBinding::Transparent, TexCreate_None, TexCreate_RenderTargetable | TexCreate_UAV, false)); + Desc.Flags |= GetTextureFastVRamFlag_DynamicLayout(); GRenderTargetPool.FindFreeElement(RHICmdList, Desc, DistanceFieldNormal, TEXT("DistanceFieldNormal")); } @@ -808,6 +847,14 @@ bool FDeferredShadingSceneRenderer::RenderDistanceFieldLighting( BentNormalOutput, IrradianceOutput); + if ( IsTransientResourceBufferAliasingEnabled() ) + { + GAOCulledObjectBuffers.Buffers.DiscardTransientResource(); + + FTileIntersectionResources* TileIntersectionResources = ((FSceneViewState*)View.State)->AOTileIntersectionResources; + TileIntersectionResources->DiscardTransientResource(); + } + RenderCapsuleShadowsForMovableSkylight(RHICmdList, BentNormalOutput); GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, BentNormalOutput); @@ -819,8 +866,10 @@ bool FDeferredShadingSceneRenderer::RenderDistanceFieldLighting( else { FPooledRenderTargetDesc Desc = SceneContext.GetSceneColor()->GetDesc(); - // Make sure we get a signed format - Desc.Format = PF_FloatRGBA; + Desc.Flags &= ~(TexCreate_FastVRAM | TexCreate_Transient); + // Bent normals are signed so we will have to pack / unpack + Desc.Format = PF_FloatR11G11B10; + Desc.Flags |= GetTextureFastVRamFlag_DynamicLayout(); GRenderTargetPool.FindFreeElement(RHICmdList, Desc, OutDynamicBentNormalAO, TEXT("DynamicBentNormalAO")); if (bUseDistanceFieldGI) @@ -914,7 +963,7 @@ public: { const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader(); FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View.ViewUniformBuffer); - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_PostProcess); SetTextureParameter(RHICmdList, ShaderRHI, DynamicBentNormalAOTexture, DynamicBentNormalAOSampler, TStaticSamplerState::GetRHI(), DynamicBentNormalAO); diff --git a/Engine/Source/Runtime/Renderer/Private/DistanceFieldAmbientOcclusion.h b/Engine/Source/Runtime/Renderer/Private/DistanceFieldAmbientOcclusion.h index 6c2406ee7a8b..47a3d4ac4449 100644 --- a/Engine/Source/Runtime/Renderer/Private/DistanceFieldAmbientOcclusion.h +++ b/Engine/Source/Runtime/Renderer/Private/DistanceFieldAmbientOcclusion.h @@ -28,7 +28,7 @@ extern const uint32 UpdateObjectsGroupSize; inline bool DoesPlatformSupportDistanceFieldAO(EShaderPlatform Platform) { - return Platform == SP_PCD3D_SM5 || Platform == SP_PS4 || Platform == SP_XBOXONE || Platform == SP_METAL_SM5; + return Platform == SP_PCD3D_SM5 || Platform == SP_PS4 || Platform == SP_XBOXONE_D3D12 || Platform == SP_XBOXONE_D3D11 || Platform == SP_METAL_SM5; } extern FIntPoint GetBufferSizeForAO(); @@ -77,6 +77,8 @@ public: virtual void InitDynamicRHI() override; + + virtual void ReleaseDynamicRHI() override { TileConeAxisAndCos.Release(); @@ -88,6 +90,24 @@ public: ObjectTilesIndirectArguments.Release(); } + void AcquireTransientResource() + { + TileConeAxisAndCos.AcquireTransientResource(); + TileConeDepthRanges.AcquireTransientResource(); + NumCulledTilesArray.AcquireTransientResource(); + CulledTilesStartOffsetArray.AcquireTransientResource(); + CulledTileDataArray.AcquireTransientResource(); + } + + void DiscardTransientResource() + { + TileConeAxisAndCos.DiscardTransientResource(); + TileConeDepthRanges.DiscardTransientResource(); + NumCulledTilesArray.DiscardTransientResource(); + CulledTilesStartOffsetArray.DiscardTransientResource(); + CulledTileDataArray.DiscardTransientResource(); + } + size_t GetSizeBytes() const { return TileConeAxisAndCos.NumBytes + TileConeDepthRanges.NumBytes @@ -213,6 +233,28 @@ public: HeightfieldIrradiance.Release(); } + void AcquireTransientResource() + { + ScreenGridConeVisibility.AcquireTransientResource(); + if (bAllocateResourceForGI) + { + StepBentNormal.AcquireTransientResource(); + SurfelIrradiance.AcquireTransientResource(); + HeightfieldIrradiance.AcquireTransientResource(); + } + } + + void DiscardTransientResource() + { + ScreenGridConeVisibility.DiscardTransientResource(); + if (bAllocateResourceForGI) + { + StepBentNormal.DiscardTransientResource(); + SurfelIrradiance.DiscardTransientResource(); + HeightfieldIrradiance.DiscardTransientResource(); + } + } + FIntPoint ScreenGridDimensions; FRWBuffer ScreenGridConeVisibility; @@ -234,7 +276,7 @@ public: } }; -extern void GetSpacedVectors(TArray >& OutVectors); +extern void GetSpacedVectors(uint32 FrameNumber, TArray >& OutVectors); BEGIN_UNIFORM_BUFFER_STRUCT(FAOSampleData2,) DECLARE_UNIFORM_BUFFER_STRUCT_MEMBER_ARRAY(FVector4,SampleDirections,[NumConeSampleDirections]) diff --git a/Engine/Source/Runtime/Renderer/Private/DistanceFieldGlobalIllumination.cpp b/Engine/Source/Runtime/Renderer/Private/DistanceFieldGlobalIllumination.cpp index b24045840d12..12ecbba87f95 100644 --- a/Engine/Source/Runtime/Renderer/Private/DistanceFieldGlobalIllumination.cpp +++ b/Engine/Source/Runtime/Renderer/Private/DistanceFieldGlobalIllumination.cpp @@ -372,7 +372,7 @@ void PlaceVPLs( GVPLResources.AllocateFor(GVPLGridDimension * GVPLGridDimension); { - ClearUAV(RHICmdList, GMaxRHIFeatureLevel, GVPLResources.VPLParameterBuffer, 0); + ClearUAV(RHICmdList, GVPLResources.VPLParameterBuffer, 0); } const FLightSceneProxy* DirectionalLightProxy = NULL; @@ -530,7 +530,7 @@ void PlaceVPLs( { GCulledVPLResources.AllocateFor(GVPLGridDimension * GVPLGridDimension); - ClearUAV(RHICmdList, GMaxRHIFeatureLevel, GCulledVPLResources.VPLParameterBuffer, 0); + ClearUAV(RHICmdList, GCulledVPLResources.VPLParameterBuffer, 0); TShaderMapRef ComputeShader(GetGlobalShaderMap(Scene->GetFeatureLevel())); RHICmdList.SetComputeShader(ComputeShader->GetComputeShader()); @@ -863,7 +863,7 @@ void UpdateVPLs( } else { - ClearUAV(RHICmdList, GMaxRHIFeatureLevel, Scene->DistanceFieldSceneData.InstancedSurfelBuffers->VPLFlux, 0); + ClearUAV(RHICmdList, Scene->DistanceFieldSceneData.InstancedSurfelBuffers->VPLFlux, 0); } } else @@ -922,7 +922,7 @@ public: FAOSampleData2 AOSampleData; TArray > SampleDirections; - GetSpacedVectors(SampleDirections); + GetSpacedVectors(View.Family->FrameNumber, SampleDirections); for (int32 SampleIndex = 0; SampleIndex < NumConeSampleDirections; SampleIndex++) { @@ -1025,7 +1025,7 @@ public: { FComputeShaderRHIParamRef ShaderRHI = GetComputeShader(); FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View.ViewUniformBuffer); - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_PostProcess); extern TGlobalResource GAOCulledObjectBuffers; ObjectParameters.Set(RHICmdList, ShaderRHI, GAOCulledObjectBuffers.Buffers); @@ -1181,8 +1181,8 @@ void ComputeIrradianceForScreenGrid( const uint32 GroupSizeX = FMath::DivideAndRoundUp(View.ViewRect.Size().X / GAODownsampleFactor, GScreenGridIrradianceThreadGroupSizeX); const uint32 GroupSizeY = FMath::DivideAndRoundUp(View.ViewRect.Size().Y / GAODownsampleFactor, GScreenGridIrradianceThreadGroupSizeX); - ClearUAV(RHICmdList, GMaxRHIFeatureLevel, ScreenGridResources.HeightfieldIrradiance, 0); - ClearUAV(RHICmdList, GMaxRHIFeatureLevel, ScreenGridResources.SurfelIrradiance, 0); + ClearUAV(RHICmdList, ScreenGridResources.HeightfieldIrradiance, 0); + ClearUAV(RHICmdList, ScreenGridResources.SurfelIrradiance, 0); View.HeightfieldLightingViewInfo. ComputeIrradianceForScreenGrid(View, RHICmdList, DistanceFieldNormal, ScreenGridResources, Parameters); diff --git a/Engine/Source/Runtime/Renderer/Private/DistanceFieldLightingPost.cpp b/Engine/Source/Runtime/Renderer/Private/DistanceFieldLightingPost.cpp index e7f70f767b3d..89ffd5ecfcf9 100644 --- a/Engine/Source/Runtime/Renderer/Private/DistanceFieldLightingPost.cpp +++ b/Engine/Source/Runtime/Renderer/Private/DistanceFieldLightingPost.cpp @@ -20,6 +20,14 @@ FAutoConsoleVariableRef CVarAOUseHistory( ECVF_RenderThreadSafe ); +int32 GAOClearHistory = 0; +FAutoConsoleVariableRef CVarAOClearHistory( + TEXT("r.AOClearHistory"), + GAOClearHistory, + TEXT(""), + ECVF_RenderThreadSafe + ); + int32 GAOHistoryStabilityPass = 1; FAutoConsoleVariableRef CVarAOHistoryStabilityPass( TEXT("r.AOHistoryStabilityPass"), @@ -121,7 +129,7 @@ public: const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader(); FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View.ViewUniformBuffer); - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_PostProcess); SetTextureParameter( RHICmdList, @@ -388,13 +396,13 @@ IMPLEMENT_SHADER_TYPE(template<>,TFilterHistoryPS,TEXT("DistanceFieldLight IMPLEMENT_SHADER_TYPE(template<>,TFilterHistoryPS,TEXT("DistanceFieldLightingPost"),TEXT("FilterHistoryPS"),SF_Pixel); -void AllocateOrReuseAORenderTarget(FRHICommandList& RHICmdList, TRefCountPtr& Target, const TCHAR* Name, EPixelFormat Format) +void AllocateOrReuseAORenderTarget(FRHICommandList& RHICmdList, TRefCountPtr& Target, const TCHAR* Name, EPixelFormat Format, uint32 Flags) { if (!Target) { FIntPoint BufferSize = GetBufferSizeForAO(); - FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, Format, FClearValueBinding::None, TexCreate_None, TexCreate_RenderTargetable | TexCreate_UAV, false)); + FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, Format, FClearValueBinding::None, Flags, TexCreate_RenderTargetable | TexCreate_UAV, false)); Desc.AutoWritable = false; GRenderTargetPool.FindFreeElement(RHICmdList, Desc, Target, Name); } @@ -426,17 +434,23 @@ void UpdateHistory( { const bool bUseDistanceFieldGI = IsDistanceFieldGIAllowed(View); + FIntPoint BufferSize = GetBufferSizeForAO(); + if (*BentNormalHistoryState && !View.bCameraCut && !View.bPrevTransformsReset - && (!bUseDistanceFieldGI || (IrradianceHistoryState && *IrradianceHistoryState))) + && (!bUseDistanceFieldGI || (IrradianceHistoryState && *IrradianceHistoryState)) + && !GAOClearHistory + // If the scene render targets reallocate, toss the history so we don't read uninitialized data + && (*BentNormalHistoryState)->GetDesc().Extent == BufferSize) { + uint32 HistoryPassOutputFlags = GAOHistoryStabilityPass ? GetTextureFastVRamFlag_DynamicLayout() : 0; // Reuse a render target from the pool with a consistent name, for vis purposes TRefCountPtr NewBentNormalHistory; - AllocateOrReuseAORenderTarget(RHICmdList, NewBentNormalHistory, BentNormalHistoryRTName, PF_FloatRGBA); + AllocateOrReuseAORenderTarget(RHICmdList, NewBentNormalHistory, BentNormalHistoryRTName, PF_FloatRGBA, HistoryPassOutputFlags); TRefCountPtr NewConfidenceHistory; - AllocateOrReuseAORenderTarget(RHICmdList, NewConfidenceHistory, ConfidenceHistoryRTName, PF_G8); + AllocateOrReuseAORenderTarget(RHICmdList, NewConfidenceHistory, ConfidenceHistoryRTName, PF_G8, HistoryPassOutputFlags); TRefCountPtr NewIrradianceHistory; @@ -679,7 +693,7 @@ public: const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader(); FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View.ViewUniformBuffer); - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_PostProcess); SetTextureParameter(RHICmdList, ShaderRHI, BentNormalAOTexture, BentNormalAOSampler, TStaticSamplerState::GetRHI(), DistanceFieldAOBentNormal->GetRenderTargetItem().ShaderResourceTexture); diff --git a/Engine/Source/Runtime/Renderer/Private/DistanceFieldLightingPost.h b/Engine/Source/Runtime/Renderer/Private/DistanceFieldLightingPost.h index 3934699fe2e7..e45caa7b7af3 100644 --- a/Engine/Source/Runtime/Renderer/Private/DistanceFieldLightingPost.h +++ b/Engine/Source/Runtime/Renderer/Private/DistanceFieldLightingPost.h @@ -11,7 +11,7 @@ class FDistanceFieldAOParameters; -extern void AllocateOrReuseAORenderTarget(FRHICommandList& RHICmdList, TRefCountPtr& Target, const TCHAR* Name, EPixelFormat Format); +extern void AllocateOrReuseAORenderTarget(FRHICommandList& RHICmdList, TRefCountPtr& Target, const TCHAR* Name, EPixelFormat Format, uint32 Flags = 0); extern void UpdateHistory( FRHICommandList& RHICmdList, diff --git a/Engine/Source/Runtime/Renderer/Private/DistanceFieldLightingShared.h b/Engine/Source/Runtime/Renderer/Private/DistanceFieldLightingShared.h index c8e96684137b..224a0e122f7f 100644 --- a/Engine/Source/Runtime/Renderer/Private/DistanceFieldLightingShared.h +++ b/Engine/Source/Runtime/Renderer/Private/DistanceFieldLightingShared.h @@ -14,6 +14,7 @@ #include "RHIStaticStates.h" #include "DistanceFieldAtlas.h" #include "UniquePtr.h" +#include "SceneRendering.h" class FLightSceneProxy; class FMaterialRenderProxy; @@ -291,18 +292,40 @@ public: { if (MaxObjects > 0) { + const uint32 FastVRamFlag = IsTransientResourceBufferAliasingEnabled() ? ( BUF_FastVRAM | BUF_Transient ) : BUF_None; + ObjectIndirectArguments.Initialize(sizeof(uint32), 5, PF_R32_UINT, BUF_Static | BUF_DrawIndirect); ObjectIndirectDispatch.Initialize(sizeof(uint32), 3, PF_R32_UINT, BUF_Static | BUF_DrawIndirect); - Bounds.Initialize(sizeof(FVector4), MaxObjects, BUF_Static); - Data.Initialize(sizeof(FVector4), MaxObjects * ObjectDataStride, BUF_Static); + Bounds.Initialize(sizeof(FVector4), MaxObjects, BUF_Static | FastVRamFlag, TEXT("FDistanceFieldCulledObjectBuffers::Bounds")); + Data.Initialize(sizeof(FVector4), MaxObjects * ObjectDataStride, BUF_Static | FastVRamFlag, TEXT("FDistanceFieldCulledObjectBuffers::Data")); if (bWantBoxBounds) { - BoxBounds.Initialize(sizeof(FVector4), MaxObjects * ObjectBoxBoundsStride, BUF_Static); + BoxBounds.Initialize(sizeof(FVector4), MaxObjects * ObjectBoxBoundsStride, BUF_Static | FastVRamFlag, TEXT("FDistanceFieldCulledObjectBuffers::BoxBounds")); } } } + void AcquireTransientResource() + { + Bounds.AcquireTransientResource(); + Data.AcquireTransientResource(); + if (bWantBoxBounds) + { + BoxBounds.AcquireTransientResource(); + } + } + + void DiscardTransientResource() + { + Bounds.DiscardTransientResource(); + Data.DiscardTransientResource(); + if (bWantBoxBounds) + { + BoxBounds.DiscardTransientResource(); + } + } + void Release() { ObjectIndirectArguments.Release(); diff --git a/Engine/Source/Runtime/Renderer/Private/DistanceFieldObjectCulling.cpp b/Engine/Source/Runtime/Renderer/Private/DistanceFieldObjectCulling.cpp index b94a9ab2da95..1766cc842343 100644 --- a/Engine/Source/Runtime/Renderer/Private/DistanceFieldObjectCulling.cpp +++ b/Engine/Source/Runtime/Renderer/Private/DistanceFieldObjectCulling.cpp @@ -76,16 +76,22 @@ TGlobalResource GAOCulledObjectBuffers; void FTileIntersectionResources::InitDynamicRHI() { - TileConeAxisAndCos.Initialize(sizeof(float)* 4, TileDimensions.X * TileDimensions.Y, PF_A32B32G32R32F, BUF_Static); - TileConeDepthRanges.Initialize(sizeof(float)* 4, TileDimensions.X * TileDimensions.Y, PF_A32B32G32R32F, BUF_Static); + const uint32 FastVRamFlag = IsTransientResourceBufferAliasingEnabled() ? (BUF_FastVRAM | BUF_Transient) : BUF_None; + TileConeAxisAndCos.Initialize(sizeof(FVector4), TileDimensions.X * TileDimensions.Y, PF_A32B32G32R32F, BUF_Static | FastVRamFlag, TEXT("TileConeAxisAndCos")); + TileConeDepthRanges.Initialize(sizeof(FVector4), TileDimensions.X * TileDimensions.Y, PF_A32B32G32R32F, BUF_Static | FastVRamFlag, TEXT("TileConeDepthRanges")); - NumCulledTilesArray.Initialize(sizeof(uint32), MaxSceneObjects, PF_R32_UINT, BUF_Static); - CulledTilesStartOffsetArray.Initialize(sizeof(uint32), MaxSceneObjects, PF_R32_UINT, BUF_Static); + NumCulledTilesArray.Initialize(sizeof(uint32), MaxSceneObjects, PF_R32_UINT, BUF_Static | FastVRamFlag, TEXT("NumCulledTilesArray")); + CulledTilesStartOffsetArray.Initialize(sizeof(uint32), MaxSceneObjects, PF_R32_UINT, BUF_Static | FastVRamFlag, TEXT("CulledTilesStartOffsetArray")); // Can only use 16 bit for CulledTileDataArray if few enough objects and tiles const bool b16BitObjectIndices = MaxSceneObjects < (1 << 16); const bool b16BitCulledTileIndexBuffer = bAllow16BitIndices && b16BitObjectIndices && TileDimensions.X * TileDimensions.Y < (1 << 16); - CulledTileDataArray.Initialize(b16BitCulledTileIndexBuffer ? sizeof(uint16) : sizeof(uint32), GMaxDistanceFieldObjectsPerCullTile * TileDimensions.X * TileDimensions.Y * CulledTileDataStride, b16BitCulledTileIndexBuffer ? PF_R16_UINT : PF_R32_UINT); + CulledTileDataArray.Initialize( + b16BitCulledTileIndexBuffer ? sizeof(uint16) : sizeof(uint32), + GMaxDistanceFieldObjectsPerCullTile * TileDimensions.X * TileDimensions.Y * CulledTileDataStride, + b16BitCulledTileIndexBuffer ? PF_R16_UINT : PF_R32_UINT, + BUF_Static | FastVRamFlag, + TEXT("CulledTileDataArray")); ObjectTilesIndirectArguments.Initialize(sizeof(uint32), 3, PF_R32_UINT, BUF_Static | BUF_DrawIndirect); } @@ -187,16 +193,18 @@ void CullObjectsToView(FRHICommandListImmediate& RHICmdList, FScene* Scene, cons { SCOPED_DRAW_EVENT(RHICmdList, ObjectFrustumCulling); - if (CulledObjectBuffers.Buffers.MaxObjects < Scene->DistanceFieldSceneData.NumObjectsInBuffer + if (!CulledObjectBuffers.IsInitialized() + || CulledObjectBuffers.Buffers.MaxObjects < Scene->DistanceFieldSceneData.NumObjectsInBuffer || CulledObjectBuffers.Buffers.MaxObjects > 3 * Scene->DistanceFieldSceneData.NumObjectsInBuffer) { CulledObjectBuffers.Buffers.MaxObjects = Scene->DistanceFieldSceneData.NumObjectsInBuffer * 5 / 4; - CulledObjectBuffers.Buffers.Release(); - CulledObjectBuffers.Buffers.Initialize(); + CulledObjectBuffers.ReleaseResource(); + CulledObjectBuffers.InitResource(); } + CulledObjectBuffers.Buffers.AcquireTransientResource(); { - ClearUAV(RHICmdList, GMaxRHIFeatureLevel, CulledObjectBuffers.Buffers.ObjectIndirectArguments, 0); + ClearUAV(RHICmdList, CulledObjectBuffers.Buffers.ObjectIndirectArguments, 0); TShaderMapRef ComputeShader(GetGlobalShaderMap(Scene->GetFeatureLevel())); RHICmdList.SetComputeShader(ComputeShader->GetComputeShader()); @@ -250,7 +258,7 @@ public: FComputeShaderRHIParamRef ShaderRHI = GetComputeShader(); FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View.ViewUniformBuffer); - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_PostProcess); AOParameters.Set(RHICmdList, ShaderRHI, Parameters); FTileIntersectionResources* TileIntersectionResources = ((FSceneViewState*)View.State)->AOTileIntersectionResources; @@ -598,7 +606,9 @@ FIntPoint BuildTileObjectLists(FRHICommandListImmediate& RHICmdList, FScene* Sce FTileIntersectionResources*& TileIntersectionResources = ((FSceneViewState*)View.State)->AOTileIntersectionResources; - if (!TileIntersectionResources || !TileIntersectionResources->HasAllocatedEnoughFor(TileListGroupSize, Scene->DistanceFieldSceneData.NumObjectsInBuffer)) + if (!TileIntersectionResources + || !TileIntersectionResources->IsInitialized() + || !TileIntersectionResources->HasAllocatedEnoughFor(TileListGroupSize, Scene->DistanceFieldSceneData.NumObjectsInBuffer)) { if (TileIntersectionResources) { @@ -608,10 +618,11 @@ FIntPoint BuildTileObjectLists(FRHICommandListImmediate& RHICmdList, FScene* Sce { TileIntersectionResources = new FTileIntersectionResources(!IsMetalPlatform(GShaderPlatformForFeatureLevel[View.FeatureLevel])); } - + TileIntersectionResources->SetupParameters(TileListGroupSize, Scene->DistanceFieldSceneData.NumObjectsInBuffer); TileIntersectionResources->InitResource(); } + TileIntersectionResources->AcquireTransientResource(); if (GAOScatterTileCulling) { @@ -630,7 +641,7 @@ FIntPoint BuildTileObjectLists(FRHICommandListImmediate& RHICmdList, FScene* Sce SCOPED_DRAW_EVENT(RHICmdList, CountTileObjectIntersections); // Start at 0 tiles per object - ClearUAV(RHICmdList, GMaxRHIFeatureLevel, TileIntersectionResources->NumCulledTilesArray, 0); + ClearUAV(RHICmdList, TileIntersectionResources->NumCulledTilesArray, 0); // Rasterize object bounding shapes and intersect with screen tiles to compute how many tiles intersect each object ScatterTilesToObjects(RHICmdList, View, TileListGroupSize, Parameters); @@ -639,7 +650,7 @@ FIntPoint BuildTileObjectLists(FRHICommandListImmediate& RHICmdList, FScene* Sce { SCOPED_DRAW_EVENT(RHICmdList, ComputeStartOffsets); // Start at 0 threadgroups - ClearUAV(RHICmdList, GMaxRHIFeatureLevel, TileIntersectionResources->ObjectTilesIndirectArguments, 0); + ClearUAV(RHICmdList, TileIntersectionResources->ObjectTilesIndirectArguments, 0); // Accumulate how many cone trace threadgroups we should dispatch, and also compute the start offset for each object's culled tile data TShaderMapRef ComputeShader(View.ShaderMap); @@ -657,7 +668,7 @@ FIntPoint BuildTileObjectLists(FRHICommandListImmediate& RHICmdList, FScene* Sce SCOPED_DRAW_EVENT(RHICmdList, CullTilesToObjects); // Start at 0 tiles per object - ClearUAV(RHICmdList, GMaxRHIFeatureLevel, TileIntersectionResources->NumCulledTilesArray, 0); + ClearUAV(RHICmdList, TileIntersectionResources->NumCulledTilesArray, 0); // Rasterize object bounding shapes and intersect with screen tiles, and write out intersecting tile indices for the cone tracing pass ScatterTilesToObjects(RHICmdList, View, TileListGroupSize, Parameters); diff --git a/Engine/Source/Runtime/Renderer/Private/DistanceFieldObjectManagement.cpp b/Engine/Source/Runtime/Renderer/Private/DistanceFieldObjectManagement.cpp index 14eb90dcdbde..1b1b013311ad 100644 --- a/Engine/Source/Runtime/Renderer/Private/DistanceFieldObjectManagement.cpp +++ b/Engine/Source/Runtime/Renderer/Private/DistanceFieldObjectManagement.cpp @@ -931,7 +931,7 @@ void ProcessPrimitiveUpdate( if (GAOLogGlobalDistanceFieldModifiedPrimitives) { - UE_LOG(LogDistanceField,Warning,TEXT("Global Distance Field primitive %s %s %s bounding radius %.1f"), (bIsAddOperation ? TEXT("add") : TEXT("update")), *PrimitiveSceneInfo->Proxy->GetOwnerName().ToString(), *PrimitiveSceneInfo->Proxy->GetResourceName().ToString(), BoundingRadius); + UE_LOG(LogDistanceField,Log,TEXT("Global Distance Field %s primitive %s %s %s bounding radius %.1f"), PrimitiveSceneInfo->Proxy->IsOftenMoving() ? TEXT("CACHED") : TEXT("Movable"), (bIsAddOperation ? TEXT("add") : TEXT("update")), *PrimitiveSceneInfo->Proxy->GetOwnerName().ToString(), *PrimitiveSceneInfo->Proxy->GetResourceName().ToString(), BoundingRadius); } } else if (bIsAddOperation) diff --git a/Engine/Source/Runtime/Renderer/Private/DistanceFieldScreenGridLighting.cpp b/Engine/Source/Runtime/Renderer/Private/DistanceFieldScreenGridLighting.cpp index 5a21f8a72408..31cbeb6bc67e 100644 --- a/Engine/Source/Runtime/Renderer/Private/DistanceFieldScreenGridLighting.cpp +++ b/Engine/Source/Runtime/Renderer/Private/DistanceFieldScreenGridLighting.cpp @@ -65,15 +65,16 @@ FVector2D GetJitterOffset(int32 SampleIndex) void FAOScreenGridResources::InitDynamicRHI() { //@todo - 2d textures - ScreenGridConeVisibility.Initialize(sizeof(uint32), NumConeSampleDirections * ScreenGridDimensions.X * ScreenGridDimensions.Y, PF_R32_UINT, BUF_Static); + const uint32 FastVRamFlag = IsTransientResourceBufferAliasingEnabled() ? (BUF_FastVRAM | BUF_Transient) : BUF_None; + ScreenGridConeVisibility.Initialize(sizeof(uint32), NumConeSampleDirections * ScreenGridDimensions.X * ScreenGridDimensions.Y, PF_R32_UINT, BUF_Static | FastVRamFlag, TEXT("ScreenGridConeVisibility")); if (bAllocateResourceForGI) { ConeDepthVisibilityFunction.Initialize(sizeof(float), NumConeSampleDirections * NumVisibilitySteps * ScreenGridDimensions.X * ScreenGridDimensions.Y, PF_R32_FLOAT, BUF_Static); //@todo - fp16 StepBentNormal.Initialize(sizeof(float) * 4, NumVisibilitySteps * ScreenGridDimensions.X * ScreenGridDimensions.Y, PF_A32B32G32R32F, BUF_Static); - SurfelIrradiance.Initialize(sizeof(FFloat16Color), ScreenGridDimensions.X * ScreenGridDimensions.Y, PF_FloatRGBA, BUF_Static); - HeightfieldIrradiance.Initialize(sizeof(FFloat16Color), ScreenGridDimensions.X * ScreenGridDimensions.Y, PF_FloatRGBA, BUF_Static); + SurfelIrradiance.Initialize(sizeof(FFloat16Color), ScreenGridDimensions.X * ScreenGridDimensions.Y, PF_FloatRGBA, BUF_Static | FastVRamFlag, TEXT("SurfelIrradiance")); + HeightfieldIrradiance.Initialize(sizeof(FFloat16Color), ScreenGridDimensions.X * ScreenGridDimensions.Y, PF_FloatRGBA, BUF_Static | FastVRamFlag, TEXT("HeightfieldIrradiance")); } } @@ -128,7 +129,7 @@ public: { FComputeShaderRHIParamRef ShaderRHI = GetComputeShader(); FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View.ViewUniformBuffer); - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_PostProcess); ObjectParameters.Set(RHICmdList, ShaderRHI, GAOCulledObjectBuffers.Buffers); AOParameters.Set(RHICmdList, ShaderRHI, Parameters); ScreenGridParameters.Set(RHICmdList, ShaderRHI, View, DistanceFieldNormal); @@ -141,7 +142,7 @@ public: FAOSampleData2 AOSampleData; TArray > SampleDirections; - GetSpacedVectors(SampleDirections); + GetSpacedVectors(View.Family->FrameNumber, SampleDirections); for (int32 SampleIndex = 0; SampleIndex < NumConeSampleDirections; SampleIndex++) { @@ -279,7 +280,7 @@ public: { FComputeShaderRHIParamRef ShaderRHI = GetComputeShader(); FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View.ViewUniformBuffer); - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_PostProcess); ObjectParameters.Set(RHICmdList, ShaderRHI, GAOCulledObjectBuffers.Buffers); AOParameters.Set(RHICmdList, ShaderRHI, Parameters); ScreenGridParameters.Set(RHICmdList, ShaderRHI, View, DistanceFieldNormal); @@ -288,7 +289,7 @@ public: FAOSampleData2 AOSampleData; TArray > SampleDirections; - GetSpacedVectors(SampleDirections); + GetSpacedVectors(View.Family->FrameNumber, SampleDirections); for (int32 SampleIndex = 0; SampleIndex < NumConeSampleDirections; SampleIndex++) { @@ -424,7 +425,7 @@ public: FAOSampleData2 AOSampleData; TArray > SampleDirections; - GetSpacedVectors(SampleDirections); + GetSpacedVectors(View.Family->FrameNumber, SampleDirections); for (int32 SampleIndex = 0; SampleIndex < NumConeSampleDirections; SampleIndex++) { @@ -755,7 +756,8 @@ void FDeferredShadingSceneRenderer::RenderDistanceFieldAOScreenGrid( if (!ScreenGridResources || ScreenGridResources->ScreenGridDimensions != ConeTraceBufferSize - || ScreenGridResources->bAllocateResourceForGI != bUseDistanceFieldGI) + || ScreenGridResources->bAllocateResourceForGI != bUseDistanceFieldGI + || !ScreenGridResources->IsInitialized()) { if (ScreenGridResources) { @@ -771,6 +773,7 @@ void FDeferredShadingSceneRenderer::RenderDistanceFieldAOScreenGrid( ScreenGridResources->InitResource(); } + ScreenGridResources->AcquireTransientResource(); SetRenderTarget(RHICmdList, NULL, NULL); @@ -779,7 +782,7 @@ void FDeferredShadingSceneRenderer::RenderDistanceFieldAOScreenGrid( SCOPED_DRAW_EVENT(RHICmdList, ConeTraceGlobal); float ConeVisibilityClearValue = 1.0f; - ClearUAV(RHICmdList, GMaxRHIFeatureLevel, ScreenGridResources->ScreenGridConeVisibility, *(uint32*)&ConeVisibilityClearValue); + ClearUAV(RHICmdList, ScreenGridResources->ScreenGridConeVisibility, *(uint32*)&ConeVisibilityClearValue); const uint32 GroupSizeX = FMath::DivideAndRoundUp(View.ViewRect.Size().X / GAODownsampleFactor / GConeTraceDownsampleFactor, GConeTraceGlobalDFTileSize); const uint32 GroupSizeY = FMath::DivideAndRoundUp(View.ViewRect.Size().Y / GAODownsampleFactor / GConeTraceDownsampleFactor, GConeTraceGlobalDFTileSize); @@ -886,6 +889,7 @@ void FDeferredShadingSceneRenderer::RenderDistanceFieldAOScreenGrid( { FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(ConeTraceBufferSize, PF_FloatRGBA, FClearValueBinding::None, TexCreate_None, TexCreate_RenderTargetable | TexCreate_UAV, false)); + Desc.Flags |= GetTextureFastVRamFlag_DynamicLayout(); GRenderTargetPool.FindFreeElement(RHICmdList, Desc, DownsampledBentNormal, TEXT("DownsampledBentNormal")); } @@ -902,6 +906,11 @@ void FDeferredShadingSceneRenderer::RenderDistanceFieldAOScreenGrid( ComputeShader->UnsetParameters(RHICmdList, DownsampledBentNormal->GetRenderTargetItem()); } + if ( IsTransientResourceBufferAliasingEnabled() ) + { + ScreenGridResources->DiscardTransientResource(); + } + GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, DownsampledBentNormal); PostProcessBentNormalAOScreenGrid( diff --git a/Engine/Source/Runtime/Renderer/Private/DistanceFieldShadowing.cpp b/Engine/Source/Runtime/Renderer/Private/DistanceFieldShadowing.cpp index 0cd4a9a2b34a..8065eb784a0f 100644 --- a/Engine/Source/Runtime/Renderer/Private/DistanceFieldShadowing.cpp +++ b/Engine/Source/Runtime/Renderer/Private/DistanceFieldShadowing.cpp @@ -44,14 +44,6 @@ FAutoConsoleVariableRef CVarFullResolutionDFShadowing( ECVF_Scalability | ECVF_RenderThreadSafe ); -int32 GAsyncComputeDFShadowing = 0; -FAutoConsoleVariableRef CVarAsyncComputeDFShadowing( - TEXT("r.DFShadowAsyncCompute"), - GAsyncComputeDFShadowing, - TEXT("Whether to use async compute for ray marching distance fields."), - ECVF_Scalability | ECVF_RenderThreadSafe - ); - int32 GShadowScatterTileCulling = 1; FAutoConsoleVariableRef CVarShadowScatterTileCulling( TEXT("r.DFShadowScatterTileCulling"), @@ -453,7 +445,7 @@ public: ShadowFactors.SetTexture(RHICmdList, ShaderRHI, ShadowFactorsValue.ShaderResourceTexture, ShadowFactorsValue.UAV); ObjectParameters.Set(RHICmdList, ShaderRHI, GShadowCulledObjectBuffers.Buffers); - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_PostProcess); SetShaderValue(RHICmdList, ShaderRHI, NumGroups, NumGroupsValue); @@ -602,7 +594,7 @@ public: const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader(); FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View.ViewUniformBuffer); - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_PostProcess); SetTextureParameter(RHICmdList, ShaderRHI, ShadowFactorsTexture, ShadowFactorsSampler, TStaticSamplerState::GetRHI(), ShadowFactorsTextureValue->GetRenderTargetItem().ShaderResourceTexture); @@ -677,17 +669,19 @@ void CullDistanceFieldObjectsForLight( SCOPED_DRAW_EVENT(RHICmdList, CullObjectsForLight); { - if (GShadowCulledObjectBuffers.Buffers.MaxObjects < Scene->DistanceFieldSceneData.NumObjectsInBuffer + if (!GShadowCulledObjectBuffers.IsInitialized() + || GShadowCulledObjectBuffers.Buffers.MaxObjects < Scene->DistanceFieldSceneData.NumObjectsInBuffer || GShadowCulledObjectBuffers.Buffers.MaxObjects > 3 * Scene->DistanceFieldSceneData.NumObjectsInBuffer) { GShadowCulledObjectBuffers.Buffers.bWantBoxBounds = true; GShadowCulledObjectBuffers.Buffers.MaxObjects = Scene->DistanceFieldSceneData.NumObjectsInBuffer * 5 / 4; - GShadowCulledObjectBuffers.Buffers.Release(); - GShadowCulledObjectBuffers.Buffers.Initialize(); + GShadowCulledObjectBuffers.ReleaseResource(); + GShadowCulledObjectBuffers.InitResource(); } + GShadowCulledObjectBuffers.Buffers.AcquireTransientResource(); { - ClearUAV(RHICmdList, GMaxRHIFeatureLevel, GShadowCulledObjectBuffers.Buffers.ObjectIndirectArguments, 0); + ClearUAV(RHICmdList, GShadowCulledObjectBuffers.Buffers.ObjectIndirectArguments, 0); TShaderMapRef ComputeShader(GetGlobalShaderMap(Scene->GetFeatureLevel())); RHICmdList.SetComputeShader(ComputeShader->GetComputeShader()); @@ -914,49 +908,27 @@ void FProjectedShadowInfo::BeginRenderRayTracedDistanceFieldProjection(FRHIComma { const FIntPoint BufferSize = GetBufferSizeForDFShadows(); FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, PF_G16R16F, FClearValueBinding::None, TexCreate_None, TexCreate_RenderTargetable | TexCreate_UAV, false)); + Desc.Flags |= GetTextureFastVRamFlag_DynamicLayout(); GRenderTargetPool.FindFreeElement(RHICmdList, Desc, RayTracedShadowsRT, TEXT("RayTracedShadows")); } SCOPED_DRAW_EVENT(RHICmdList, RayTraceShadows); SetRenderTarget(RHICmdList, NULL, NULL); - if (GAsyncComputeDFShadowing) - { - FRHIAsyncComputeCommandListImmediate& RHICmdListComputeImmediate = FRHICommandListExecutor::GetImmediateAsyncComputeCommandList(); - static const FName RTShadowBeginComputeName(TEXT("RTShadowComputeBegin")); - static const FName RTShadowComputeEndName(TEXT("RTShadowComputeEnd")); - FComputeFenceRHIRef BeginFence = RHICmdList.CreateComputeFence(RTShadowBeginComputeName); - RayTracedShadowsEndFence = RHICmdList.CreateComputeFence(RTShadowComputeEndName); - - RHICmdList.TransitionResources(EResourceTransitionAccess::EReadable, EResourceTransitionPipeline::EGfxToCompute, nullptr, 0, BeginFence); - RHICmdListComputeImmediate.WaitComputeFence(BeginFence); - - RayTraceShadows(RHICmdListComputeImmediate, View, this, TileIntersectionResources); - - RHICmdListComputeImmediate.TransitionResources(EResourceTransitionAccess::EReadable, EResourceTransitionPipeline::EComputeToGfx, nullptr, 0, RayTracedShadowsEndFence); - - FRHIAsyncComputeCommandListImmediate::ImmediateDispatch(RHICmdListComputeImmediate); - } - else - { RayTraceShadows(RHICmdList, View, this, TileIntersectionResources); } } - } } -void FProjectedShadowInfo::RenderRayTracedDistanceFieldProjection(FRHICommandListImmediate& RHICmdList, const FViewInfo& View, bool bProjectingForForwardShading) +void FProjectedShadowInfo::RenderRayTracedDistanceFieldProjection(FRHICommandListImmediate& RHICmdList, const FViewInfo& View, IPooledRenderTarget* ScreenShadowMaskTexture, bool bProjectingForForwardShading ) { + BeginRenderRayTracedDistanceFieldProjection(RHICmdList, View); + if (RayTracedShadowsRT) { QUICK_SCOPE_CYCLE_COUNTER(STAT_RenderRayTracedDistanceFieldShadows); SCOPED_DRAW_EVENT(RHICmdList, RayTracedDistanceFieldShadow); - if (GAsyncComputeDFShadowing) - { - RHICmdList.WaitComputeFence(RayTracedShadowsEndFence); - } - FIntRect ScissorRect; if (!LightSceneInfo->Proxy->GetScissorRect(ScissorRect, View)) @@ -964,14 +936,19 @@ void FProjectedShadowInfo::RenderRayTracedDistanceFieldProjection(FRHICommandLis ScissorRect = View.ViewRect; } + if ( IsTransientResourceBufferAliasingEnabled() ) { - FSceneRenderTargets::Get(RHICmdList).BeginRenderingLightAttenuation(RHICmdList); + GShadowCulledObjectBuffers.Buffers.DiscardTransientResource(); + } + + { + SetRenderTarget(RHICmdList, ScreenShadowMaskTexture->GetRenderTargetItem().TargetableTexture, FSceneRenderTargets::Get(RHICmdList).GetSceneDepthSurface(), ESimpleRenderTargetMode::EExistingColorAndDepth, FExclusiveDepthStencil::DepthRead_StencilWrite, true); SCOPED_DRAW_EVENT(RHICmdList, Upsample); FGraphicsPipelineStateInitializer GraphicsPSOInit; RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit); - + RHICmdList.SetViewport(ScissorRect.Min.X, ScissorRect.Min.Y, 0.0f, ScissorRect.Max.X, ScissorRect.Max.Y, 1.0f); GraphicsPSOInit.RasterizerState = TStaticRasterizerState::GetRHI(); GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState::GetRHI(); diff --git a/Engine/Source/Runtime/Renderer/Private/DistanceFieldVisualization.cpp b/Engine/Source/Runtime/Renderer/Private/DistanceFieldVisualization.cpp index ea36d0ac563e..42b0bc2883e0 100644 --- a/Engine/Source/Runtime/Renderer/Private/DistanceFieldVisualization.cpp +++ b/Engine/Source/Runtime/Renderer/Private/DistanceFieldVisualization.cpp @@ -68,7 +68,7 @@ public: ObjectParameters.Set(RHICmdList, ShaderRHI, GAOCulledObjectBuffers.Buffers); AOParameters.Set(RHICmdList, ShaderRHI, Parameters); - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_PostProcess); if (bUseGlobalDistanceField) { @@ -142,7 +142,7 @@ public: const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader(); FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View.ViewUniformBuffer); - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_PostProcess); SetTextureParameter(RHICmdList, ShaderRHI, VisualizeDistanceFieldTexture, VisualizeDistanceFieldSampler, TStaticSamplerState::GetRHI(), VisualizeDistanceField->GetRenderTargetItem().ShaderResourceTexture); } @@ -237,6 +237,11 @@ void FDeferredShadingSceneRenderer::RenderMeshDistanceFieldVisualization(FRHICom } } + if ( IsTransientResourceBufferAliasingEnabled()) + { + GAOCulledObjectBuffers.Buffers.DiscardTransientResource(); + } + { FSceneRenderTargets::Get(RHICmdList).BeginRenderingSceneColor(RHICmdList, ESimpleRenderTargetMode::EExistingColorAndDepth, FExclusiveDepthStencil::DepthRead_StencilRead); diff --git a/Engine/Source/Runtime/Renderer/Private/DistortionRendering.cpp b/Engine/Source/Runtime/Renderer/Private/DistortionRendering.cpp index b5f89cb28037..7487db9e4930 100644 --- a/Engine/Source/Runtime/Renderer/Private/DistortionRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/DistortionRendering.cpp @@ -37,12 +37,6 @@ static TAutoConsoleVariable CVarDisableDistortion( TEXT("Prevents distortion effects from rendering. Saves a full-screen framebuffer's worth of memory."), ECVF_Default); -static TAutoConsoleVariable CVarFastVRamDistortion( - TEXT("r.FastVRamDistortion"), - 0, - TEXT("Whether to store distortion in fast VRAM"), - ECVF_Scalability | ECVF_RenderThreadSafe); - /** * A pixel shader for rendering the full screen refraction pass */ @@ -906,7 +900,7 @@ bool FDistortionPrimSet::DrawAccumulatedOffsets(FRHICommandListImmediate& RHICmd &View, bInitializeOffsets, StaticMesh, - StaticMesh.bRequiresPerElementVisibility ? View.StaticMeshBatchVisibility[StaticMesh.Id] : ((1ull << StaticMesh.Elements.Num()) - 1), + StaticMesh.bRequiresPerElementVisibility ? View.StaticMeshBatchVisibility[StaticMesh.BatchVisibilityId] : ((1ull << StaticMesh.Elements.Num()) - 1), DrawRenderState, PrimitiveSceneProxy, StaticMesh.BatchHitProxyId @@ -1062,10 +1056,7 @@ void FSceneRenderer::RenderDistortion(FRHICommandListImmediate& RHICmdList) // Create a texture to store the resolved light attenuation values, and a render-targetable surface to hold the unresolved light attenuation values. { FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(SceneContext.GetBufferSizeXY(), PF_B8G8R8A8, FClearValueBinding::Transparent, TexCreate_None, TexCreate_RenderTargetable, false)); - if (CVarFastVRamDistortion.GetValueOnRenderThread() >= 1) - { - Desc.Flags |= TexCreate_FastVRAM; - } + Desc.Flags |= GetTextureFastVRamFlag_DynamicLayout(); Desc.NumSamples = MSAACount; GRenderTargetPool.FindFreeElement(RHICmdList, Desc, DistortionRT, TEXT("Distortion")); @@ -1127,12 +1118,11 @@ void FSceneRenderer::RenderDistortion(FRHICommandListImmediate& RHICmdList) RHICmdList.TransitionResource(EResourceTransitionAccess::EReadable, SceneContext.GetSceneColor()->GetRenderTargetItem().TargetableTexture); -// OCULUS BEGIN: select ONE render target for all views (eyes) TRefCountPtr NewSceneColor; - // we don't create a new name to make it easier to use "vis SceneColor" and get the last HDRSceneColor - GRenderTargetPool.FindFreeElement(RHICmdList, SceneContext.GetSceneColor()->GetDesc(), NewSceneColor, TEXT("SceneColor")); + FPooledRenderTargetDesc Desc = SceneContext.GetSceneColor()->GetDesc(); + Desc.Flags &= ~(TexCreate_FastVRAM | TexCreate_Transient); + GRenderTargetPool.FindFreeElement(RHICmdList, Desc, NewSceneColor, TEXT("DistortedSceneColor")); const FSceneRenderTargetItem& DestRenderTarget = NewSceneColor->GetRenderTargetItem(); -// OCULUS END // Apply distortion and store off-screen SetRenderTarget(RHICmdList, DestRenderTarget.TargetableTexture, SceneContext.GetSceneDepthSurface(), ESimpleRenderTargetMode::EExistingColorAndDepth, FExclusiveDepthStencil::DepthRead_StencilWrite); @@ -1209,7 +1199,9 @@ void FSceneRenderer::RenderDistortionES2(FRHICommandListImmediate& RHICmdList) RHICmdList.CopyToResolveTarget(SceneContext.GetSceneColorSurface(), SceneContext.GetSceneColorTexture(), true, FResolveRect(0, 0, ViewFamily.FamilySizeX, ViewFamily.FamilySizeY)); TRefCountPtr SceneColorDistorted; - GRenderTargetPool.FindFreeElement(RHICmdList, SceneContext.GetSceneColor()->GetDesc(), SceneColorDistorted, TEXT("SceneColorDistorted")); + FPooledRenderTargetDesc Desc = SceneContext.GetSceneColor()->GetDesc(); + Desc.Flags &= ~(TexCreate_FastVRAM | TexCreate_Transient); + GRenderTargetPool.FindFreeElement(RHICmdList, Desc, SceneColorDistorted, TEXT("SceneColorDistorted")); const FSceneRenderTargetItem& DistortedRenderTarget = SceneColorDistorted->GetRenderTargetItem(); FGraphicsPipelineStateInitializer GraphicsPSOInit; diff --git a/Engine/Source/Runtime/Renderer/Private/GPUBenchmark.cpp b/Engine/Source/Runtime/Renderer/Private/GPUBenchmark.cpp index b6c5c973715a..f606013a2ba7 100644 --- a/Engine/Source/Runtime/Renderer/Private/GPUBenchmark.cpp +++ b/Engine/Source/Runtime/Renderer/Private/GPUBenchmark.cpp @@ -25,8 +25,6 @@ static const uint32 GBenchmarkResolution = 512; static const uint32 GBenchmarkPrimitives = 200000; static const uint32 GBenchmarkVertices = GBenchmarkPrimitives * 3; -DEFINE_LOG_CATEGORY_STATIC(LogSynthBenchmark, Log, All); - /** Encapsulates the post processing down sample pixel shader. */ template class FPostProcessBenchmarkPS : public FGlobalShader diff --git a/Engine/Source/Runtime/Renderer/Private/GammaCorrection.cpp b/Engine/Source/Runtime/Renderer/Private/GammaCorrection.cpp index c99db5976909..bc7c025428f3 100644 --- a/Engine/Source/Runtime/Renderer/Private/GammaCorrection.cpp +++ b/Engine/Source/Runtime/Renderer/Private/GammaCorrection.cpp @@ -102,7 +102,7 @@ void FSceneRenderer::GammaCorrectToViewportRenderTarget(FRHICommandList& RHICmdL else { SetRenderTarget(RHICmdList, ViewFamily.RenderTarget->GetRenderTargetTexture(), FTextureRHIRef()); - DrawClearQuad(RHICmdList, GMaxRHIFeatureLevel, FLinearColor::Black); + DrawClearQuad(RHICmdList, FLinearColor::Black); } ViewFamily.bDeferClear = false; } diff --git a/Engine/Source/Runtime/Renderer/Private/GlobalDistanceField.cpp b/Engine/Source/Runtime/Renderer/Private/GlobalDistanceField.cpp index b6bf87927ff9..015da2d98f8c 100644 --- a/Engine/Source/Runtime/Renderer/Private/GlobalDistanceField.cpp +++ b/Engine/Source/Runtime/Renderer/Private/GlobalDistanceField.cpp @@ -11,7 +11,7 @@ int32 GAOGlobalDistanceField = 1; FAutoConsoleVariableRef CVarAOGlobalDistanceField( - TEXT("r.AOGlobalDistanceField"), + TEXT("r.AOGlobalDistanceField"), GAOGlobalDistanceField, TEXT("Whether to use a global distance field to optimize occlusion cone traces.\n") TEXT("The global distance field is created by compositing object distance fields into clipmaps as the viewer moves through the level."), @@ -375,9 +375,25 @@ private: IMPLEMENT_SHADER_TYPE(,FCullObjectsToGridCS,TEXT("GlobalDistanceField"),TEXT("CullObjectsToGridCS"),SF_Compute); -const int32 CompositeTileSize = 4; +enum EFlattenedDimension +{ + Flatten_XAxis = 0, + Flatten_YAxis = 1, + Flatten_ZAxis = 2, + Flatten_None +}; -template +int32 GetCompositeTileSize(int32 Dimension, EFlattenedDimension FlattenedDimension) +{ + if (FlattenedDimension == Flatten_None) + { + return 4; + } + + return Dimension == (int32)FlattenedDimension ? 1 : 8; +} + +template class TCompositeObjectDistanceFieldsCS : public FGlobalShader { DECLARE_SHADER_TYPE(TCompositeObjectDistanceFieldsCS,Global) @@ -391,7 +407,9 @@ public: static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment) { FGlobalShader::ModifyCompilationEnvironment(Platform,OutEnvironment); - OutEnvironment.SetDefine(TEXT("COMPOSITE_THREADGROUP_SIZE"), CompositeTileSize); + OutEnvironment.SetDefine(TEXT("COMPOSITE_THREADGROUP_SIZEX"), GetCompositeTileSize(0, FlattenedDimension)); + OutEnvironment.SetDefine(TEXT("COMPOSITE_THREADGROUP_SIZEY"), GetCompositeTileSize(1, FlattenedDimension)); + OutEnvironment.SetDefine(TEXT("COMPOSITE_THREADGROUP_SIZEZ"), GetCompositeTileSize(2, FlattenedDimension)); OutEnvironment.SetDefine(TEXT("CULL_GRID_TILE_SIZE"), GCullGridTileSize); OutEnvironment.SetDefine(TEXT("MAX_GRID_CULLED_DF_OBJECTS"), GMaxGridCulledObjects); OutEnvironment.SetDefine(TEXT("USE_PARENT_DISTANCE_FIELD"), bUseParentDistanceField ? 1 : 0); @@ -505,8 +523,19 @@ private: FShaderParameter AOGlobalMaxSphereQueryRadius; }; -IMPLEMENT_SHADER_TYPE(template<>,TCompositeObjectDistanceFieldsCS,TEXT("GlobalDistanceField"),TEXT("CompositeObjectDistanceFieldsCS"),SF_Compute); -IMPLEMENT_SHADER_TYPE(template<>,TCompositeObjectDistanceFieldsCS,TEXT("GlobalDistanceField"),TEXT("CompositeObjectDistanceFieldsCS"),SF_Compute); +#define IMPLEMENT_GLOBALDF_COMPOSITE_CS_TYPE(bUseParentDistanceField, FlattenedDimension) \ + typedef TCompositeObjectDistanceFieldsCS TCompositeObjectDistanceFieldsCS##bUseParentDistanceField##FlattenedDimension; \ + IMPLEMENT_SHADER_TYPE(template<>,TCompositeObjectDistanceFieldsCS##bUseParentDistanceField##FlattenedDimension,TEXT("GlobalDistanceField"),TEXT("CompositeObjectDistanceFieldsCS"),SF_Compute); + +IMPLEMENT_GLOBALDF_COMPOSITE_CS_TYPE(true, Flatten_None); +IMPLEMENT_GLOBALDF_COMPOSITE_CS_TYPE(true, Flatten_XAxis); +IMPLEMENT_GLOBALDF_COMPOSITE_CS_TYPE(true, Flatten_YAxis); +IMPLEMENT_GLOBALDF_COMPOSITE_CS_TYPE(true, Flatten_ZAxis); + +IMPLEMENT_GLOBALDF_COMPOSITE_CS_TYPE(false, Flatten_None); +IMPLEMENT_GLOBALDF_COMPOSITE_CS_TYPE(false, Flatten_XAxis); +IMPLEMENT_GLOBALDF_COMPOSITE_CS_TYPE(false, Flatten_YAxis); +IMPLEMENT_GLOBALDF_COMPOSITE_CS_TYPE(false, Flatten_ZAxis); const int32 HeightfieldCompositeTileSize = 8; @@ -1259,13 +1288,15 @@ void UpdateGlobalDistanceFieldVolume( { SCOPED_DRAW_EVENT(RHICmdList, UpdateGlobalDistanceFieldVolume); - if (GGlobalDistanceFieldCulledObjectBuffers.Buffers.MaxObjects < Scene->DistanceFieldSceneData.NumObjectsInBuffer + if (!GGlobalDistanceFieldCulledObjectBuffers.IsInitialized() + || GGlobalDistanceFieldCulledObjectBuffers.Buffers.MaxObjects < Scene->DistanceFieldSceneData.NumObjectsInBuffer || GGlobalDistanceFieldCulledObjectBuffers.Buffers.MaxObjects > 3 * Scene->DistanceFieldSceneData.NumObjectsInBuffer) { GGlobalDistanceFieldCulledObjectBuffers.Buffers.MaxObjects = Scene->DistanceFieldSceneData.NumObjectsInBuffer * 5 / 4; - GGlobalDistanceFieldCulledObjectBuffers.Buffers.Release(); - GGlobalDistanceFieldCulledObjectBuffers.Buffers.Initialize(); + GGlobalDistanceFieldCulledObjectBuffers.ReleaseResource(); + GGlobalDistanceFieldCulledObjectBuffers.InitResource(); } + GGlobalDistanceFieldCulledObjectBuffers.Buffers.AcquireTransientResource(); const uint32 MaxCullGridDimension = GAOGlobalDFResolution / GCullGridTileSize; @@ -1285,7 +1316,7 @@ void UpdateGlobalDistanceFieldVolume( for (int32 ClipmapIndex = 0; ClipmapIndex < Clipmaps.Num(); ClipmapIndex++) { - SCOPED_DRAW_EVENTF(RHICmdList, Clipmap, TEXT("CacheType %u Clipmap %u"), CacheType, ClipmapIndex); + SCOPED_DRAW_EVENTF(RHICmdList, Clipmap, TEXT("CacheType %s Clipmap %u"), CacheType == GDF_MostlyStatic ? TEXT("MostlyStatic") : TEXT("Movable"), ClipmapIndex); FGlobalDistanceFieldClipmap& Clipmap = Clipmaps[ClipmapIndex]; @@ -1300,7 +1331,7 @@ void UpdateGlobalDistanceFieldVolume( // Cull the global objects to the volume being updated { - ClearUAV(RHICmdList, GMaxRHIFeatureLevel, GGlobalDistanceFieldCulledObjectBuffers.Buffers.ObjectIndirectArguments, 0); + ClearUAV(RHICmdList, GGlobalDistanceFieldCulledObjectBuffers.Buffers.ObjectIndirectArguments, 0); TShaderMapRef ComputeShader(View.ShaderMap); RHICmdList.SetComputeShader(ComputeShader->GetComputeShader()); @@ -1330,24 +1361,93 @@ void UpdateGlobalDistanceFieldVolume( { SCOPED_DRAW_EVENTF(RHICmdList, TileCullAndComposite, TEXT("TileCullAndComposite %ux%ux%u"), UpdateRegion.CellsSize.X, UpdateRegion.CellsSize.Y, UpdateRegion.CellsSize.Z); - //@todo - match typical update sizes. Camera movement creates narrow slabs. - const uint32 NumGroupsX = FMath::DivideAndRoundUp(UpdateRegion.CellsSize.X, CompositeTileSize); - const uint32 NumGroupsY = FMath::DivideAndRoundUp(UpdateRegion.CellsSize.Y, CompositeTileSize); - const uint32 NumGroupsZ = FMath::DivideAndRoundUp(UpdateRegion.CellsSize.Z, CompositeTileSize); + int32 MinDimension = 2; + + if (UpdateRegion.CellsSize.X < UpdateRegion.CellsSize.Y && UpdateRegion.CellsSize.X < UpdateRegion.CellsSize.Z) + { + MinDimension = 0; + } + else if (UpdateRegion.CellsSize.Y < UpdateRegion.CellsSize.X && UpdateRegion.CellsSize.Y < UpdateRegion.CellsSize.Z) + { + MinDimension = 1; + } + + int32 MinSize = UpdateRegion.CellsSize[MinDimension]; + int32 MaxSize = FMath::Max(UpdateRegion.CellsSize.X, FMath::Max(UpdateRegion.CellsSize.Y, UpdateRegion.CellsSize.Z)); + const EFlattenedDimension FlattenedDimension = MaxSize >= MinSize * 8 ? (EFlattenedDimension)MinDimension : Flatten_None; + + const uint32 NumGroupsX = FMath::DivideAndRoundUp(UpdateRegion.CellsSize.X, GetCompositeTileSize(0, FlattenedDimension)); + const uint32 NumGroupsY = FMath::DivideAndRoundUp(UpdateRegion.CellsSize.Y, GetCompositeTileSize(1, FlattenedDimension)); + const uint32 NumGroupsZ = FMath::DivideAndRoundUp(UpdateRegion.CellsSize.Z, GetCompositeTileSize(2, FlattenedDimension)); IPooledRenderTarget* ParentDistanceField = GlobalDistanceFieldInfo.MostlyStaticClipmaps[ClipmapIndex].RenderTarget; if (CacheType == GDF_Full && GAOGlobalDistanceFieldCacheMostlyStaticSeparately && ParentDistanceField) { - TShaderMapRef> ComputeShader(View.ShaderMap); + if (FlattenedDimension == Flatten_None) + { + TShaderMapRef> ComputeShader(View.ShaderMap); + RHICmdList.SetComputeShader(ComputeShader->GetComputeShader()); + ComputeShader->SetParameters(RHICmdList, Scene, View, MaxOcclusionDistance, GlobalDistanceFieldInfo.ParameterData, Clipmap, ParentDistanceField, ClipmapIndex, UpdateRegion); + DispatchComputeShader(RHICmdList, *ComputeShader, NumGroupsX, NumGroupsY, NumGroupsZ); + ComputeShader->UnsetParameters(RHICmdList, Clipmap); + } + else if (FlattenedDimension == Flatten_XAxis) + { + TShaderMapRef> ComputeShader(View.ShaderMap); + RHICmdList.SetComputeShader(ComputeShader->GetComputeShader()); + ComputeShader->SetParameters(RHICmdList, Scene, View, MaxOcclusionDistance, GlobalDistanceFieldInfo.ParameterData, Clipmap, ParentDistanceField, ClipmapIndex, UpdateRegion); + DispatchComputeShader(RHICmdList, *ComputeShader, NumGroupsX, NumGroupsY, NumGroupsZ); + ComputeShader->UnsetParameters(RHICmdList, Clipmap); + } + else if (FlattenedDimension == Flatten_YAxis) + { + TShaderMapRef> ComputeShader(View.ShaderMap); + RHICmdList.SetComputeShader(ComputeShader->GetComputeShader()); + ComputeShader->SetParameters(RHICmdList, Scene, View, MaxOcclusionDistance, GlobalDistanceFieldInfo.ParameterData, Clipmap, ParentDistanceField, ClipmapIndex, UpdateRegion); + DispatchComputeShader(RHICmdList, *ComputeShader, NumGroupsX, NumGroupsY, NumGroupsZ); + ComputeShader->UnsetParameters(RHICmdList, Clipmap); + } + else + { + check(FlattenedDimension == Flatten_ZAxis); + TShaderMapRef> ComputeShader(View.ShaderMap); RHICmdList.SetComputeShader(ComputeShader->GetComputeShader()); ComputeShader->SetParameters(RHICmdList, Scene, View, MaxOcclusionDistance, GlobalDistanceFieldInfo.ParameterData, Clipmap, ParentDistanceField, ClipmapIndex, UpdateRegion); DispatchComputeShader(RHICmdList, *ComputeShader, NumGroupsX, NumGroupsY, NumGroupsZ); ComputeShader->UnsetParameters(RHICmdList, Clipmap); } + } else { - TShaderMapRef> ComputeShader(View.ShaderMap); + if (FlattenedDimension == Flatten_None) + { + TShaderMapRef> ComputeShader(View.ShaderMap); + RHICmdList.SetComputeShader(ComputeShader->GetComputeShader()); + ComputeShader->SetParameters(RHICmdList, Scene, View, MaxOcclusionDistance, GlobalDistanceFieldInfo.ParameterData, Clipmap, NULL, ClipmapIndex, UpdateRegion); + DispatchComputeShader(RHICmdList, *ComputeShader, NumGroupsX, NumGroupsY, NumGroupsZ); + ComputeShader->UnsetParameters(RHICmdList, Clipmap); + } + else if (FlattenedDimension == Flatten_XAxis) + { + TShaderMapRef> ComputeShader(View.ShaderMap); + RHICmdList.SetComputeShader(ComputeShader->GetComputeShader()); + ComputeShader->SetParameters(RHICmdList, Scene, View, MaxOcclusionDistance, GlobalDistanceFieldInfo.ParameterData, Clipmap, NULL, ClipmapIndex, UpdateRegion); + DispatchComputeShader(RHICmdList, *ComputeShader, NumGroupsX, NumGroupsY, NumGroupsZ); + ComputeShader->UnsetParameters(RHICmdList, Clipmap); + } + else if (FlattenedDimension == Flatten_YAxis) + { + TShaderMapRef> ComputeShader(View.ShaderMap); + RHICmdList.SetComputeShader(ComputeShader->GetComputeShader()); + ComputeShader->SetParameters(RHICmdList, Scene, View, MaxOcclusionDistance, GlobalDistanceFieldInfo.ParameterData, Clipmap, NULL, ClipmapIndex, UpdateRegion); + DispatchComputeShader(RHICmdList, *ComputeShader, NumGroupsX, NumGroupsY, NumGroupsZ); + ComputeShader->UnsetParameters(RHICmdList, Clipmap); + } + else + { + check(FlattenedDimension == Flatten_ZAxis); + TShaderMapRef> ComputeShader(View.ShaderMap); RHICmdList.SetComputeShader(ComputeShader->GetComputeShader()); ComputeShader->SetParameters(RHICmdList, Scene, View, MaxOcclusionDistance, GlobalDistanceFieldInfo.ParameterData, Clipmap, NULL, ClipmapIndex, UpdateRegion); DispatchComputeShader(RHICmdList, *ComputeShader, NumGroupsX, NumGroupsY, NumGroupsZ); @@ -1355,6 +1455,7 @@ void UpdateGlobalDistanceFieldVolume( } } } + } if (UpdateRegion.UpdateType & VUT_Heightfields) { @@ -1363,6 +1464,11 @@ void UpdateGlobalDistanceFieldVolume( } } } + + if ( IsTransientResourceBufferAliasingEnabled() ) + { + GGlobalDistanceFieldCulledObjectBuffers.Buffers.DiscardTransientResource(); + } } } } diff --git a/Engine/Source/Runtime/Renderer/Private/HeightfieldLighting.cpp b/Engine/Source/Runtime/Renderer/Private/HeightfieldLighting.cpp index 5cf170c9ef63..58d877e40f18 100644 --- a/Engine/Source/Runtime/Renderer/Private/HeightfieldLighting.cpp +++ b/Engine/Source/Runtime/Renderer/Private/HeightfieldLighting.cpp @@ -1277,7 +1277,7 @@ public: FAOSampleData2 AOSampleData; TArray > SampleDirections; - GetSpacedVectors(SampleDirections); + GetSpacedVectors(View.Family->FrameNumber, SampleDirections); for (int32 SampleIndex = 0; SampleIndex < NumConeSampleDirections; SampleIndex++) { @@ -1433,7 +1433,7 @@ public: FAOSampleData2 AOSampleData; TArray > SampleDirections; - GetSpacedVectors(SampleDirections); + GetSpacedVectors(View.Family->FrameNumber, SampleDirections); for (int32 SampleIndex = 0; SampleIndex < NumConeSampleDirections; SampleIndex++) { diff --git a/Engine/Source/Runtime/Renderer/Private/IndirectLightingCache.cpp b/Engine/Source/Runtime/Renderer/Private/IndirectLightingCache.cpp index def330b09611..ce79464f27e3 100644 --- a/Engine/Source/Runtime/Renderer/Private/IndirectLightingCache.cpp +++ b/Engine/Source/Runtime/Renderer/Private/IndirectLightingCache.cpp @@ -462,14 +462,13 @@ bool FIndirectLightingCache::IndirectLightingAllowed(FScene* Scene, FSceneRender return bAnyViewAllowsIndirectLightingCache; } -void FIndirectLightingCache::ProcessPrimitiveUpdate(FScene* Scene, FViewInfo& View, int32 PrimitiveIndex, bool bAllowUnbuiltPreview, TMap& OutBlocksToUpdate, TArray& OutTransitionsOverTimeToUpdate) +void FIndirectLightingCache::ProcessPrimitiveUpdate(FScene* Scene, FViewInfo& View, int32 PrimitiveIndex, bool bAllowUnbuiltPreview, bool bAllowVolumeSample, TMap& OutBlocksToUpdate, TArray& OutTransitionsOverTimeToUpdate) { FPrimitiveSceneInfo* PrimitiveSceneInfo = Scene->Primitives[PrimitiveIndex]; const bool bPrecomputedLightingBufferWasDirty = PrimitiveSceneInfo->NeedsPrecomputedLightingBufferUpdate(); - const FPrimitiveViewRelevance& PrimitiveRelevance = View.PrimitiveViewRelevanceMap[PrimitiveIndex]; const TMap& AttachmentGroups = Scene->AttachmentGroups; - UpdateCachePrimitive(AttachmentGroups, PrimitiveSceneInfo, bAllowUnbuiltPreview, PrimitiveRelevance.bOpaqueRelevance, OutBlocksToUpdate, OutTransitionsOverTimeToUpdate); + UpdateCachePrimitive(AttachmentGroups, PrimitiveSceneInfo, bAllowUnbuiltPreview, bAllowVolumeSample, OutBlocksToUpdate, OutTransitionsOverTimeToUpdate); // If it was already dirty, then the primitive is already in one of the view dirty primitive list at this point. // This also ensures that a primitive does not get added twice to the list, which could create an array reallocation. @@ -531,7 +530,9 @@ void FIndirectLightingCache::UpdateCachePrimitivesInternal(FScene* Scene, FScene for (FSceneSetBitIterator BitIt(View.PrimitiveVisibilityMap); BitIt; ++BitIt) { uint32 PrimitiveIndex = BitIt.GetIndex(); - ProcessPrimitiveUpdate(Scene, View, PrimitiveIndex, bAllowUnbuiltPreview, OutBlocksToUpdate, OutTransitionsOverTimeToUpdate); + // FDrawTranslucentMeshAction::AllowIndirectLightingCacheVolumeTexture doesn't allow volume samples on translucency, so we only need to support one if the primitive has at least one opaque material + const bool bAllowVolumeSample = View.PrimitiveViewRelevanceMap[PrimitiveIndex].bOpaqueRelevance; + ProcessPrimitiveUpdate(Scene, View, PrimitiveIndex, bAllowUnbuiltPreview, bAllowVolumeSample, OutBlocksToUpdate, OutTransitionsOverTimeToUpdate); } // Any visible primitives with an indirect shadow need their ILC updated, since that determines the indirect shadow direction @@ -541,7 +542,7 @@ void FIndirectLightingCache::UpdateCachePrimitivesInternal(FScene* Scene, FScene if (!View.PrimitiveVisibilityMap[PrimitiveIndex]) { - ProcessPrimitiveUpdate(Scene, View, PrimitiveIndex, bAllowUnbuiltPreview, OutBlocksToUpdate, OutTransitionsOverTimeToUpdate); + ProcessPrimitiveUpdate(Scene, View, PrimitiveIndex, bAllowUnbuiltPreview, true, OutBlocksToUpdate, OutTransitionsOverTimeToUpdate); } } } @@ -647,11 +648,10 @@ void FIndirectLightingCache::UpdateCachePrimitive( const TMap& AttachmentGroups, FPrimitiveSceneInfo* PrimitiveSceneInfo, bool bAllowUnbuiltPreview, - bool bOpaqueRelevance, + bool bAllowVolumeSample, TMap& BlocksToUpdate, TArray& TransitionsOverTimeToUpdate) { - FPrimitiveSceneProxy* PrimitiveSceneProxy = PrimitiveSceneInfo->Proxy; FIndirectLightingCacheAllocation** PrimitiveAllocationPtr = PrimitiveAllocations.Find(PrimitiveSceneInfo->PrimitiveComponentId); FIndirectLightingCacheAllocation* PrimitiveAllocation = PrimitiveAllocationPtr != NULL ? *PrimitiveAllocationPtr : NULL; @@ -686,7 +686,7 @@ void FIndirectLightingCache::UpdateCachePrimitive( { FIndirectLightingCacheAllocation* OriginalAllocation = PrimitiveAllocation; const bool bUnbuiltPreview = bAllowUnbuiltPreview && !bIsMovable; - const bool bPointSample = !bUnbuiltPreview && ( PrimitiveSceneProxy->GetIndirectLightingCacheQuality() == ILCQ_Point || !bOpaqueRelevance ); + const bool bPointSample = PrimitiveSceneProxy->GetIndirectLightingCacheQuality() == ILCQ_Point || bUnbuiltPreview || !bAllowVolumeSample; const int32 BlockSize = bPointSample ? 1 : GLightingCacheMovableObjectAllocationSize; // Light with the cumulative bounds of the entire attachment group diff --git a/Engine/Source/Runtime/Renderer/Private/LightFunctionRendering.cpp b/Engine/Source/Runtime/Renderer/Private/LightFunctionRendering.cpp index 3cff73446c9c..eb8b30de8999 100644 --- a/Engine/Source/Runtime/Renderer/Private/LightFunctionRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/LightFunctionRendering.cpp @@ -154,7 +154,7 @@ public: LightSceneInfo->Proxy->GetLightFunctionDisabledBrightness(), bRenderingPreviewShadowIndicator ? 1.0f : 0.0f)); - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_LightFunction); auto DeferredLightParameter = GetUniformBufferParameter(); @@ -250,21 +250,21 @@ bool FDeferredShadingSceneRenderer::CheckForLightFunction( const FLightSceneInfo * * @param LightSceneInfo Represents the current light */ -bool FDeferredShadingSceneRenderer::RenderLightFunction(FRHICommandListImmediate& RHICmdList, const FLightSceneInfo* LightSceneInfo, bool bLightAttenuationCleared, bool bProjectingForForwardShading) +bool FDeferredShadingSceneRenderer::RenderLightFunction(FRHICommandListImmediate& RHICmdList, const FLightSceneInfo* LightSceneInfo, IPooledRenderTarget* ScreenShadowMaskTexture, bool bLightAttenuationCleared, bool bProjectingForForwardShading) { if (ViewFamily.EngineShowFlags.LightFunctions) { - return RenderLightFunctionForMaterial(RHICmdList, LightSceneInfo, LightSceneInfo->Proxy->GetLightFunctionMaterial(), bLightAttenuationCleared, bProjectingForForwardShading, false); + return RenderLightFunctionForMaterial(RHICmdList, LightSceneInfo, ScreenShadowMaskTexture, LightSceneInfo->Proxy->GetLightFunctionMaterial(), bLightAttenuationCleared, bProjectingForForwardShading, false); } return false; } -bool FDeferredShadingSceneRenderer::RenderPreviewShadowsIndicator(FRHICommandListImmediate& RHICmdList, const FLightSceneInfo* LightSceneInfo, bool bLightAttenuationCleared) +bool FDeferredShadingSceneRenderer::RenderPreviewShadowsIndicator(FRHICommandListImmediate& RHICmdList, const FLightSceneInfo* LightSceneInfo, IPooledRenderTarget* ScreenShadowMaskTexture, bool bLightAttenuationCleared) { if (GEngine->PreviewShadowsIndicatorMaterial) { - return RenderLightFunctionForMaterial(RHICmdList, LightSceneInfo, GEngine->PreviewShadowsIndicatorMaterial->GetRenderProxy(false), bLightAttenuationCleared, false, true); + return RenderLightFunctionForMaterial(RHICmdList, LightSceneInfo, ScreenShadowMaskTexture, GEngine->PreviewShadowsIndicatorMaterial->GetRenderProxy(false), bLightAttenuationCleared, false, true); } return false; @@ -273,6 +273,7 @@ bool FDeferredShadingSceneRenderer::RenderPreviewShadowsIndicator(FRHICommandLis bool FDeferredShadingSceneRenderer::RenderLightFunctionForMaterial( FRHICommandListImmediate& RHICmdList, const FLightSceneInfo* LightSceneInfo, + IPooledRenderTarget* ScreenShadowMaskTexture, const FMaterialRenderProxy* MaterialProxy, bool bLightAttenuationCleared, bool bProjectingForForwardShading, @@ -280,9 +281,10 @@ bool FDeferredShadingSceneRenderer::RenderLightFunctionForMaterial( { bool bRenderedLightFunction = false; - if (MaterialProxy && MaterialProxy->GetMaterial(Scene->GetFeatureLevel())->IsLightFunction()) + check(ScreenShadowMaskTexture); + if (MaterialProxy && MaterialProxy->GetMaterial(Scene->GetFeatureLevel())->IsLightFunction() ) { - FSceneRenderTargets::Get(RHICmdList).BeginRenderingLightAttenuation(RHICmdList); + SetRenderTarget(RHICmdList, ScreenShadowMaskTexture->GetRenderTargetItem().TargetableTexture, FSceneRenderTargets::Get(RHICmdList).GetSceneDepthSurface(), ESimpleRenderTargetMode::EExistingColorAndDepth, FExclusiveDepthStencil::DepthRead_StencilWrite, true); bRenderedLightFunction = true; diff --git a/Engine/Source/Runtime/Renderer/Private/LightGridInjection.cpp b/Engine/Source/Runtime/Renderer/Private/LightGridInjection.cpp index 40343d1f617f..8634f65fd16b 100644 --- a/Engine/Source/Runtime/Renderer/Private/LightGridInjection.cpp +++ b/Engine/Source/Runtime/Renderer/Private/LightGridInjection.cpp @@ -108,16 +108,16 @@ public: } template - void Set(FRHICommandList& RHICmdList, const ShaderRHIParamRef& ShaderRHI, const FViewInfo& View) + void Set(FRHICommandList& RHICmdList, const ShaderRHIParamRef& ShaderRHI, const FForwardLightingCullingResources& ForwardLightingCullingResources) { - NextCulledLightLink.SetBuffer(RHICmdList, ShaderRHI, View.ForwardLightingResources->NextCulledLightLink); - StartOffsetGrid.SetBuffer(RHICmdList, ShaderRHI, View.ForwardLightingResources->StartOffsetGrid); - CulledLightLinks.SetBuffer(RHICmdList, ShaderRHI, View.ForwardLightingResources->CulledLightLinks); - NextCulledLightData.SetBuffer(RHICmdList, ShaderRHI, View.ForwardLightingResources->NextCulledLightData); + NextCulledLightLink.SetBuffer(RHICmdList, ShaderRHI, ForwardLightingCullingResources.NextCulledLightLink); + StartOffsetGrid.SetBuffer(RHICmdList, ShaderRHI, ForwardLightingCullingResources.StartOffsetGrid); + CulledLightLinks.SetBuffer(RHICmdList, ShaderRHI, ForwardLightingCullingResources.CulledLightLinks); + NextCulledLightData.SetBuffer(RHICmdList, ShaderRHI, ForwardLightingCullingResources.NextCulledLightData); } template - void UnsetParameters(FRHICommandList& RHICmdList, const ShaderRHIParamRef& ShaderRHI, const FViewInfo& View) + void UnsetParameters(FRHICommandList& RHICmdList, const ShaderRHIParamRef& ShaderRHI, const FForwardLightingCullingResources& ForwardLightingCullingResources) { NextCulledLightLink.UnsetUAV(RHICmdList, ShaderRHI); StartOffsetGrid.UnsetUAV(RHICmdList, ShaderRHI); @@ -128,22 +128,22 @@ public: if (NextCulledLightLink.IsUAVBound()) { - OutUAVs.Add(View.ForwardLightingResources->NextCulledLightLink.UAV); + OutUAVs.Add(ForwardLightingCullingResources.NextCulledLightLink.UAV); } if (StartOffsetGrid.IsUAVBound()) { - OutUAVs.Add(View.ForwardLightingResources->StartOffsetGrid.UAV); + OutUAVs.Add(ForwardLightingCullingResources.StartOffsetGrid.UAV); } if (CulledLightLinks.IsUAVBound()) { - OutUAVs.Add(View.ForwardLightingResources->CulledLightLinks.UAV); + OutUAVs.Add(ForwardLightingCullingResources.CulledLightLinks.UAV); } if (NextCulledLightData.IsUAVBound()) { - OutUAVs.Add(View.ForwardLightingResources->NextCulledLightData.UAV); + OutUAVs.Add(ForwardLightingCullingResources.NextCulledLightData.UAV); } if (OutUAVs.Num() > 0) @@ -204,18 +204,18 @@ public: { } - void SetParameters(FRHICommandList& RHICmdList, const FViewInfo& View) + void SetParameters(FRHICommandList& RHICmdList, const FViewInfo& View, const FForwardLightingCullingResources& ForwardLightingCullingResources) { FComputeShaderRHIParamRef ShaderRHI = GetComputeShader(); FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View.ViewUniformBuffer); ForwardLightingParameters.Set(RHICmdList, ShaderRHI, View); - ForwardCullingParameters.Set(RHICmdList, ShaderRHI, View); + ForwardCullingParameters.Set(RHICmdList, ShaderRHI, ForwardLightingCullingResources); } - void UnsetParameters(FRHICommandList& RHICmdList, const FViewInfo& View) + void UnsetParameters(FRHICommandList& RHICmdList, const FViewInfo& View, const FForwardLightingCullingResources& ForwardLightingCullingResources) { ForwardLightingParameters.UnsetParameters(RHICmdList, GetComputeShader(), View); - ForwardCullingParameters.UnsetParameters(RHICmdList, GetComputeShader(), View); + ForwardCullingParameters.UnsetParameters(RHICmdList, GetComputeShader(), ForwardLightingCullingResources); } virtual bool Serialize(FArchive& Ar) @@ -265,18 +265,18 @@ public: { } - void SetParameters(FRHICommandList& RHICmdList, const FViewInfo& View) + void SetParameters(FRHICommandList& RHICmdList, const FViewInfo& View, const FForwardLightingCullingResources& ForwardLightingCullingResources) { FComputeShaderRHIParamRef ShaderRHI = GetComputeShader(); FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View.ViewUniformBuffer); ForwardLightingParameters.Set(RHICmdList, ShaderRHI, View); - ForwardCullingParameters.Set(RHICmdList, ShaderRHI, View); + ForwardCullingParameters.Set(RHICmdList, ShaderRHI, ForwardLightingCullingResources); } - void UnsetParameters(FRHICommandList& RHICmdList, const FViewInfo& View) + void UnsetParameters(FRHICommandList& RHICmdList, const FViewInfo& View, const FForwardLightingCullingResources& ForwardLightingCullingResources) { ForwardLightingParameters.UnsetParameters(RHICmdList, GetComputeShader(), View); - ForwardCullingParameters.UnsetParameters(RHICmdList, GetComputeShader(), View); + ForwardCullingParameters.UnsetParameters(RHICmdList, GetComputeShader(), ForwardLightingCullingResources); } virtual bool Serialize(FArchive& Ar) @@ -343,17 +343,21 @@ void FDeferredShadingSceneRenderer::ComputeLightGrid(FRHICommandListImmediate& R GatherSimpleLights(ViewFamily, Views, SimpleLights); } + TArray> GlobalLightDataForAllViews; + GlobalLightDataForAllViews.Empty(Views.Num()); + GlobalLightDataForAllViews.AddDefaulted(Views.Num()); + for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) { FViewInfo& View = Views[ViewIndex]; + FForwardGlobalLightData& GlobalLightData = GlobalLightDataForAllViews[ViewIndex]; - FForwardGlobalLightData GlobalLightData; TArray ForwardLocalLightData; float FurthestLight = 1000; if (bCullLightsToGrid) { - ForwardLocalLightData.Empty(Scene->Lights.Num()); + ForwardLocalLightData.Empty(Scene->Lights.Num() + SimpleLights.InstanceData.Num()); for (TSparseArray::TConstIterator LightIt(Scene->Lights); LightIt; ++LightIt) { @@ -509,6 +513,10 @@ void FDeferredShadingSceneRenderer::ComputeLightGrid(FRHICommandListImmediate& R // Pack both values into a single float to keep float4 alignment const FFloat16 SimpleLightSourceLength16f = FFloat16(0); + FLightingChannels SimpleLightLightingChannels; + // Put simple lights in all lighting channels + SimpleLightLightingChannels.bChannel0 = SimpleLightLightingChannels.bChannel1 = SimpleLightLightingChannels.bChannel2 = true; + const uint32 SimpleLightLightingChannelMask = GetLightingChannelMaskForStruct(SimpleLightLightingChannels); for (int32 SimpleLightIndex = 0; SimpleLightIndex < SimpleLights.InstanceData.Num(); SimpleLightIndex++) { @@ -520,7 +528,10 @@ void FDeferredShadingSceneRenderer::ComputeLightGrid(FRHICommandListImmediate& R LightData.LightPositionAndInvRadius = FVector4(SimpleLightPerViewData.Position, 1.0f / FMath::Max(SimpleLight.Radius, KINDA_SMALL_NUMBER)); LightData.LightColorAndFalloffExponent = FVector4(SimpleLight.Color, SimpleLight.Exponent); + // No shadowmap channels for simple lights uint32 ShadowMapChannelMask = 0; + ShadowMapChannelMask |= SimpleLightLightingChannelMask << 8; + LightData.LightDirectionAndShadowMapChannelMask = FVector4(FVector(1, 0, 0), *((float*)&ShadowMapChannelMask)); // Pack both values into a single float to keep float4 alignment @@ -592,6 +603,7 @@ void FDeferredShadingSceneRenderer::ComputeLightGrid(FRHICommandListImmediate& R for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) { FViewInfo& View = Views[ViewIndex]; + const FForwardGlobalLightData& GlobalLightData = GlobalLightDataForAllViews[ViewIndex]; const FIntPoint LightGridSizeXY = FIntPoint::DivideAndRoundUp(View.ViewRect.Size(), GLightGridPixelSize); const int32 NumCells = LightGridSizeXY.X * LightGridSizeXY.Y * GLightGridSizeZ * NumCulledGridPrimitiveTypes; @@ -599,52 +611,75 @@ void FDeferredShadingSceneRenderer::ComputeLightGrid(FRHICommandListImmediate& R if (View.ForwardLightingResources->NumCulledLightsGrid.NumBytes != NumCells * NumCulledLightsGridStride * sizeof(uint32)) { View.ForwardLightingResources->NumCulledLightsGrid.Initialize(sizeof(uint32), NumCells * NumCulledLightsGridStride, PF_R32_UINT); - View.ForwardLightingResources->NextCulledLightLink.Initialize(sizeof(uint32), 1, PF_R32_UINT); - View.ForwardLightingResources->StartOffsetGrid.Initialize(sizeof(uint32), NumCells, PF_R32_UINT); - View.ForwardLightingResources->NextCulledLightData.Initialize(sizeof(uint32), 1, PF_R32_UINT); } if (View.ForwardLightingResources->CulledLightDataGrid.NumBytes != NumCells * GMaxCulledLightsPerCell * sizeof(FLightIndexType)) { View.ForwardLightingResources->CulledLightDataGrid.Initialize(sizeof(FLightIndexType), NumCells * GMaxCulledLightsPerCell, sizeof(FLightIndexType) == sizeof(uint16) ? PF_R16_UINT : PF_R32_UINT); - View.ForwardLightingResources->CulledLightLinks.Initialize(sizeof(uint32), NumCells * GMaxCulledLightsPerCell * LightLinkStride, PF_R32_UINT); + } + + const bool bShouldCacheTemporaryBuffers = View.ViewState != nullptr; + FForwardLightingCullingResources LocalCullingResources; + FForwardLightingCullingResources& ForwardLightingCullingResources = bShouldCacheTemporaryBuffers ? View.ViewState->ForwardLightingCullingResources : LocalCullingResources; + + if (ForwardLightingCullingResources.CulledLightLinks.NumBytes != NumCells * GMaxCulledLightsPerCell * LightLinkStride) + { + const uint32 FastVRamFlag = IsTransientResourceBufferAliasingEnabled() ? (BUF_FastVRAM | BUF_Transient) : BUF_None; + ForwardLightingCullingResources.CulledLightLinks.Initialize(sizeof(uint32), NumCells * GMaxCulledLightsPerCell * LightLinkStride, PF_R32_UINT, FastVRamFlag, TEXT("CulledLightLinks")); + ForwardLightingCullingResources.NextCulledLightLink.Initialize(sizeof(uint32), 1, PF_R32_UINT, FastVRamFlag, TEXT("NextCulledLightLink")); + ForwardLightingCullingResources.StartOffsetGrid.Initialize(sizeof(uint32), NumCells, PF_R32_UINT, FastVRamFlag, TEXT("StartOffsetGrid")); + ForwardLightingCullingResources.NextCulledLightData.Initialize(sizeof(uint32), 1, PF_R32_UINT, FastVRamFlag, TEXT("NextCulledLightData")); + } + + if (IsTransientResourceBufferAliasingEnabled()) + { + // Acquire resources + ForwardLightingCullingResources.CulledLightLinks.AcquireTransientResource(); + ForwardLightingCullingResources.NextCulledLightLink.AcquireTransientResource(); + ForwardLightingCullingResources.StartOffsetGrid.AcquireTransientResource(); + ForwardLightingCullingResources.NextCulledLightData.AcquireTransientResource(); } const FIntVector NumGroups = FIntVector::DivideAndRoundUp(FIntVector(LightGridSizeXY.X, LightGridSizeXY.Y, GLightGridSizeZ), LightGridInjectionGroupSize); { - SCOPED_DRAW_EVENT(RHICmdList, CullLights); + SCOPED_DRAW_EVENTF(RHICmdList, CullLights, TEXT("CullLights %ux%ux%u NumLights %u NumCaptures %u"), + GlobalLightData.CulledGridSize.X, + GlobalLightData.CulledGridSize.Y, + GlobalLightData.CulledGridSize.Z, + GlobalLightData.NumLocalLights, + GlobalLightData.NumReflectionCaptures); TArray> OutUAVs; OutUAVs.Add(View.ForwardLightingResources->NumCulledLightsGrid.UAV); OutUAVs.Add(View.ForwardLightingResources->CulledLightDataGrid.UAV); - OutUAVs.Add(View.ForwardLightingResources->NextCulledLightLink.UAV); - OutUAVs.Add(View.ForwardLightingResources->StartOffsetGrid.UAV); - OutUAVs.Add(View.ForwardLightingResources->CulledLightLinks.UAV); - OutUAVs.Add(View.ForwardLightingResources->NextCulledLightData.UAV); + OutUAVs.Add(ForwardLightingCullingResources.NextCulledLightLink.UAV); + OutUAVs.Add(ForwardLightingCullingResources.StartOffsetGrid.UAV); + OutUAVs.Add(ForwardLightingCullingResources.CulledLightLinks.UAV); + OutUAVs.Add(ForwardLightingCullingResources.NextCulledLightData.UAV); RHICmdList.TransitionResources(EResourceTransitionAccess::EWritable, EResourceTransitionPipeline::EGfxToCompute, OutUAVs.GetData(), OutUAVs.Num()); if (GLightLinkedListCulling) { - ClearUAV(RHICmdList, GMaxRHIFeatureLevel, View.ForwardLightingResources->StartOffsetGrid, 0xFFFFFFFF); - ClearUAV(RHICmdList, GMaxRHIFeatureLevel, View.ForwardLightingResources->NextCulledLightLink, 0); - ClearUAV(RHICmdList, GMaxRHIFeatureLevel, View.ForwardLightingResources->NextCulledLightData, 0); + ClearUAV(RHICmdList, ForwardLightingCullingResources.StartOffsetGrid, 0xFFFFFFFF); + ClearUAV(RHICmdList, ForwardLightingCullingResources.NextCulledLightLink, 0); + ClearUAV(RHICmdList, ForwardLightingCullingResources.NextCulledLightData, 0); TShaderMapRef > ComputeShader(View.ShaderMap); RHICmdList.SetComputeShader(ComputeShader->GetComputeShader()); - ComputeShader->SetParameters(RHICmdList, View); + ComputeShader->SetParameters(RHICmdList, View, ForwardLightingCullingResources); DispatchComputeShader(RHICmdList, *ComputeShader, NumGroups.X, NumGroups.Y, NumGroups.Z); - ComputeShader->UnsetParameters(RHICmdList, View); + ComputeShader->UnsetParameters(RHICmdList, View, ForwardLightingCullingResources); } else { - ClearUAV(RHICmdList, GMaxRHIFeatureLevel, View.ForwardLightingResources->NumCulledLightsGrid, 0); + ClearUAV(RHICmdList, View.ForwardLightingResources->NumCulledLightsGrid, 0); TShaderMapRef > ComputeShader(View.ShaderMap); RHICmdList.SetComputeShader(ComputeShader->GetComputeShader()); - ComputeShader->SetParameters(RHICmdList, View); + ComputeShader->SetParameters(RHICmdList, View, ForwardLightingCullingResources); DispatchComputeShader(RHICmdList, *ComputeShader, NumGroups.X, NumGroups.Y, NumGroups.Z); - ComputeShader->UnsetParameters(RHICmdList, View); + ComputeShader->UnsetParameters(RHICmdList, View, ForwardLightingCullingResources); } } @@ -654,9 +689,16 @@ void FDeferredShadingSceneRenderer::ComputeLightGrid(FRHICommandListImmediate& R TShaderMapRef ComputeShader(View.ShaderMap); RHICmdList.SetComputeShader(ComputeShader->GetComputeShader()); - ComputeShader->SetParameters(RHICmdList, View); + ComputeShader->SetParameters(RHICmdList, View, ForwardLightingCullingResources); DispatchComputeShader(RHICmdList, *ComputeShader, NumGroups.X, NumGroups.Y, NumGroups.Z); - ComputeShader->UnsetParameters(RHICmdList, View); + ComputeShader->UnsetParameters(RHICmdList, View, ForwardLightingCullingResources); + } + if (IsTransientResourceBufferAliasingEnabled()) + { + ForwardLightingCullingResources.CulledLightLinks.DiscardTransientResource(); + ForwardLightingCullingResources.NextCulledLightLink.DiscardTransientResource(); + ForwardLightingCullingResources.StartOffsetGrid.DiscardTransientResource(); + ForwardLightingCullingResources.NextCulledLightData.DiscardTransientResource(); } } } @@ -700,14 +742,14 @@ void FDeferredShadingSceneRenderer::RenderForwardShadingShadowProjections(FRHICo if (VisibleLightInfo.ShadowsToProject.Num() > 0) { - FSceneRenderer::RenderShadowProjections(RHICmdList, LightSceneInfo, true, false); + FSceneRenderer::RenderShadowProjections(RHICmdList, LightSceneInfo, SceneRenderTargets.GetLightAttenuation(), true, false); } - RenderCapsuleDirectShadows(*LightSceneInfo, RHICmdList, VisibleLightInfo.CapsuleShadowsToProject, true); + RenderCapsuleDirectShadows(RHICmdList, *LightSceneInfo, SceneRenderTargets.GetLightAttenuation(), VisibleLightInfo.CapsuleShadowsToProject, true); if (LightSceneInfo->GetDynamicShadowMapChannel() >= 0 && LightSceneInfo->GetDynamicShadowMapChannel() < 4) { - RenderLightFunction(RHICmdList, LightSceneInfo, true, true); + RenderLightFunction(RHICmdList, LightSceneInfo, SceneRenderTargets.GetLightAttenuation(), true, true); } } diff --git a/Engine/Source/Runtime/Renderer/Private/LightPropagationVolume.cpp b/Engine/Source/Runtime/Renderer/Private/LightPropagationVolume.cpp index aef2682355fa..492213098fc3 100644 --- a/Engine/Source/Runtime/Renderer/Private/LightPropagationVolume.cpp +++ b/Engine/Source/Runtime/Renderer/Private/LightPropagationVolume.cpp @@ -18,7 +18,7 @@ #include "GlobalShader.h" #include "DeferredShadingRenderer.h" #include "ScenePrivate.h" -#include "LightPropagationVolumeBlendable.h" +#include "LightPropagationVolumeSettings.h" DECLARE_FLOAT_COUNTER_STAT(TEXT("LPV"), Stat_GPU_LPV, STATGROUP_GPU); @@ -823,13 +823,13 @@ FLightPropagationVolume::FLightPropagationVolume() : int32 RSMResolution = FSceneRenderTargets::Get_FrameConstantsOnly().GetReflectiveShadowMapResolution(); int32 GvListBufferSize = RSMResolution * RSMResolution * 16; // Allow 16 layers of depth per every pixel of the RSM (on average) int32 VplListBufferSize = RSMResolution * RSMResolution * 4; // Allow 4 layers of depth per pixel in the RSM (1 for the RSM injection + 3 for light injection) - mVplListBuffer->Initialize( sizeof( VplListEntry ), VplListBufferSize, 0, true, false ); + mVplListBuffer->Initialize( sizeof( VplListEntry ), VplListBufferSize, 0, TEXT("mVplListBuffer"), true, false ); mVplListHeadBuffer = new FRWBufferByteAddress(); mVplListHeadBuffer->Initialize( LPV_GRIDRES*LPV_GRIDRES*LPV_GRIDRES*4, BUF_ByteAddressBuffer ); // Geometry volume buffers GvListBuffer = new FRWBufferStructured(); - GvListBuffer->Initialize( sizeof( VplListEntry ), GvListBufferSize, 0, true, false ); + GvListBuffer->Initialize( sizeof( VplListEntry ), GvListBufferSize, 0, TEXT("GvListBuffer"), true, false ); GvListHeadBuffer = new FRWBufferByteAddress(); GvListHeadBuffer->Initialize( LPV_GRIDRES*LPV_GRIDRES*LPV_GRIDRES*4, BUF_ByteAddressBuffer ); @@ -1163,7 +1163,7 @@ void FLightPropagationVolume::InjectDirectionalLightRSM( { SCOPED_DRAW_EVENT(RHICmdList, LpvInjectDirectionalLightRSM); - SetVplInjectionConstants(ProjectedShadowInfo, LightProxy ); + SetVplInjectionConstants(ProjectedShadowInfo, LightProxy ); //-V595 TShaderMapRef Shader(View.ShaderMap); RHICmdList.SetComputeShader(Shader->GetComputeShader()); diff --git a/Engine/Source/Runtime/Renderer/Private/LightRendering.cpp b/Engine/Source/Runtime/Renderer/Private/LightRendering.cpp index 6fe35fa05816..d2dc4cf7e7c5 100644 --- a/Engine/Source/Runtime/Renderer/Private/LightRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/LightRendering.cpp @@ -79,17 +79,17 @@ public: { } - void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, const FLightSceneInfo* LightSceneInfo) + void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, const FLightSceneInfo* LightSceneInfo, IPooledRenderTarget* ScreenShadowMaskTexture) { const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader(); - SetParametersBase(RHICmdList, ShaderRHI, View, LightSceneInfo->Proxy->GetIESTextureResource()); + SetParametersBase(RHICmdList, ShaderRHI, View, ScreenShadowMaskTexture, LightSceneInfo->Proxy->GetIESTextureResource()); SetDeferredLightParameters(RHICmdList, ShaderRHI, GetUniformBufferParameter(), LightSceneInfo, View); } void SetParametersSimpleLight(FRHICommandList& RHICmdList, const FSceneView& View, const FSimpleLightEntry& SimpleLight, const FSimpleLightPerViewEntry& SimpleLightPerViewData) { const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader(); - SetParametersBase(RHICmdList, ShaderRHI, View, NULL); + SetParametersBase(RHICmdList, ShaderRHI, View, NULL, NULL); SetSimpleDeferredLightParameters(RHICmdList, ShaderRHI, GetUniformBufferParameter(), SimpleLight, SimpleLightPerViewData, View); } @@ -110,10 +110,10 @@ public: private: - void SetParametersBase(FRHICommandList& RHICmdList, const FPixelShaderRHIParamRef ShaderRHI, const FSceneView& View, FTexture* IESTextureResource) + void SetParametersBase(FRHICommandList& RHICmdList, const FPixelShaderRHIParamRef ShaderRHI, const FSceneView& View, IPooledRenderTarget* ScreenShadowMaskTexture, FTexture* IESTextureResource) { FGlobalShader::SetParameters(RHICmdList, ShaderRHI,View.ViewUniformBuffer); - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_PostProcess); FSceneRenderTargets& SceneRenderTargets = FSceneRenderTargets::Get(RHICmdList); @@ -125,7 +125,7 @@ private: LightAttenuationTexture, LightAttenuationTextureSampler, TStaticSamplerState::GetRHI(), - SceneRenderTargets.GetEffectiveLightAttenuationTexture(true) + ScreenShadowMaskTexture ? ScreenShadowMaskTexture->GetRenderTargetItem().ShaderResourceTexture : GWhiteTexture->TextureRHI ); } @@ -236,7 +236,7 @@ public: FGlobalShader::SetParameters(RHICmdList, ShaderRHI,View.ViewUniformBuffer); const float HasValidChannelValue = LightSceneInfo->Proxy->GetPreviewShadowMapChannel() == INDEX_NONE ? 0.0f : 1.0f; SetShaderValue(RHICmdList, ShaderRHI, HasValidChannel, HasValidChannelValue); - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_PostProcess); SetDeferredLightParameters(RHICmdList, ShaderRHI, GetUniformBufferParameter(), LightSceneInfo, View); } @@ -350,7 +350,7 @@ void FDeferredShadingSceneRenderer::RenderLights(FRHICommandListImmediate& RHICm { if (LightSceneInfo->ShouldRenderLight(Views[ViewIndex])) { - FSortedLightSceneInfo* SortedLightInfo = new(SortedLights) FSortedLightSceneInfo(LightSceneInfoCompact); + FSortedLightSceneInfo* SortedLightInfo = new(SortedLights) FSortedLightSceneInfo(LightSceneInfo); // Check for shadows and light functions. SortedLightInfo->SortKey.Fields.LightType = LightSceneInfoCompact.LightType; @@ -426,7 +426,6 @@ void FDeferredShadingSceneRenderer::RenderLights(FRHICommandListImmediate& RHICm { SCOPED_DRAW_EVENT(RHICmdList, NonShadowedLights); INC_DWORD_STAT_BY(STAT_NumUnshadowedLights, AttenuationLightStart); - SceneContext.SetLightAttenuationMode(false); int32 StandardDeferredStart = 0; @@ -470,11 +469,10 @@ void FDeferredShadingSceneRenderer::RenderLights(FRHICommandListImmediate& RHICm for (int32 LightIndex = StandardDeferredStart; LightIndex < AttenuationLightStart; LightIndex++) { const FSortedLightSceneInfo& SortedLightInfo = SortedLights[LightIndex]; - const FLightSceneInfoCompact& LightSceneInfoCompact = SortedLightInfo.SceneInfo; - const FLightSceneInfo* const LightSceneInfo = LightSceneInfoCompact.LightSceneInfo; + const FLightSceneInfo* const LightSceneInfo = SortedLightInfo.LightSceneInfo; // Render the light to the scene color buffer, using a 1x1 white texture as input - RenderLight(RHICmdList, LightSceneInfo, false, false); + RenderLight(RHICmdList, LightSceneInfo, NULL, false, false); } } @@ -506,8 +504,7 @@ void FDeferredShadingSceneRenderer::RenderLights(FRHICommandListImmediate& RHICm for (int32 LightIndex = AttenuationLightStart; LightIndex < SortedLights.Num(); LightIndex++) { const FSortedLightSceneInfo& SortedLightInfo = SortedLights[LightIndex]; - const FLightSceneInfoCompact& LightSceneInfoCompact = SortedLightInfo.SceneInfo; - const FLightSceneInfo& LightSceneInfo = *LightSceneInfoCompact.LightSceneInfo; + const FLightSceneInfo& LightSceneInfo = *SortedLightInfo.LightSceneInfo; // Render any reflective shadow maps (if necessary) if ( LightSceneInfo.Proxy && LightSceneInfo.Proxy->NeedsLPVInjection() ) { @@ -526,8 +523,7 @@ void FDeferredShadingSceneRenderer::RenderLights(FRHICommandListImmediate& RHICm for (int32 LightIndex = 0; LightIndex < SortedLights.Num(); LightIndex++) { const FSortedLightSceneInfo& SortedLightInfo = SortedLights[LightIndex]; - const FLightSceneInfoCompact& LightSceneInfoCompact = SortedLightInfo.SceneInfo; - const FLightSceneInfo* const LightSceneInfo = LightSceneInfoCompact.LightSceneInfo; + const FLightSceneInfo* const LightSceneInfo = SortedLightInfo.LightSceneInfo; // Render any reflective shadow maps (if necessary) if ( LightSceneInfo && LightSceneInfo->Proxy && LightSceneInfo->Proxy->NeedsLPVInjection() ) @@ -566,18 +562,28 @@ void FDeferredShadingSceneRenderer::RenderLights(FRHICommandListImmediate& RHICm bool bDirectLighting = ViewFamily.EngineShowFlags.DirectLighting; + TRefCountPtr ScreenShadowMaskTexture; + // Draw shadowed and light function lights for (int32 LightIndex = AttenuationLightStart; LightIndex < SortedLights.Num(); LightIndex++) { const FSortedLightSceneInfo& SortedLightInfo = SortedLights[LightIndex]; - const FLightSceneInfoCompact& LightSceneInfoCompact = SortedLightInfo.SceneInfo; - const FLightSceneInfo& LightSceneInfo = *LightSceneInfoCompact.LightSceneInfo; + const FLightSceneInfo& LightSceneInfo = *SortedLightInfo.LightSceneInfo; bool bDrawShadows = SortedLightInfo.SortKey.Fields.bShadowed; bool bDrawLightFunction = SortedLightInfo.SortKey.Fields.bLightFunction; + bool bDrawPreviewIndicator = ViewFamily.EngineShowFlags.PreviewShadowsIndicator && !LightSceneInfo.IsPrecomputedLightingValid() && LightSceneInfo.Proxy->HasStaticShadowing(); bool bInjectedTranslucentVolume = false; - bool bUsedLightAttenuation = false; + bool bUsedShadowMaskTexture = false; FScopeCycleCounter Context(LightSceneInfo.Proxy->GetStatId()); + if ((bDrawShadows || bDrawLightFunction || bDrawPreviewIndicator) && !ScreenShadowMaskTexture.IsValid()) + { + FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(SceneContext.GetBufferSizeXY(), PF_B8G8R8A8, FClearValueBinding::White, TexCreate_None, TexCreate_RenderTargetable, false)); + Desc.Flags |= GetTextureFastVRamFlag_DynamicLayout(); + Desc.NumSamples = SceneContext.GetNumSceneColorMSAASamples(SceneContext.GetCurrentFeatureLevel()); + GRenderTargetPool.FindFreeElement(RHICmdList, Desc, ScreenShadowMaskTexture, TEXT("ScreenShadowMaskTexture")); + } + FString LightNameWithLevel; GetLightNameForDrawEvent(LightSceneInfo.Proxy, LightNameWithLevel); SCOPED_DRAW_EVENTF(RHICmdList, EventLightPass, *LightNameWithLevel); @@ -593,11 +599,11 @@ void FDeferredShadingSceneRenderer::RenderLights(FRHICommandListImmediate& RHICm } // Clear light attenuation for local lights with a quad covering their extents - const bool bClearLightScreenExtentsOnly = SortedLightInfo.SceneInfo.LightType != LightType_Directional; - + const bool bClearLightScreenExtentsOnly = SortedLightInfo.SortKey.Fields.LightType != LightType_Directional; // All shadows render with min blending bool bClearToWhite = !bClearLightScreenExtentsOnly; - SceneContext.BeginRenderingLightAttenuation(RHICmdList, bClearToWhite); + + SetRenderTarget(RHICmdList, ScreenShadowMaskTexture->GetRenderTargetItem().TargetableTexture, SceneContext.GetSceneDepthSurface(), bClearToWhite ? ESimpleRenderTargetMode::EClearColorExistingDepth : ESimpleRenderTargetMode::EExistingColorAndDepth, FExclusiveDepthStencil::DepthRead_StencilWrite, true); if (bClearLightScreenExtentsOnly) { @@ -614,13 +620,13 @@ void FDeferredShadingSceneRenderer::RenderLights(FRHICommandListImmediate& RHICm } RHICmdList.SetViewport(ScissorRect.Min.X, ScissorRect.Min.Y, 0.0f, ScissorRect.Max.X, ScissorRect.Max.Y, 1.0f); - DrawClearQuad(RHICmdList, FeatureLevel, true, FLinearColor(1, 1, 1, 1), false, 0, false, 0); + DrawClearQuad(RHICmdList, true, FLinearColor(1, 1, 1, 1), false, 0, false, 0); } } - RenderShadowProjections(RHICmdList, &LightSceneInfo, bInjectedTranslucentVolume); + RenderShadowProjections(RHICmdList, &LightSceneInfo, ScreenShadowMaskTexture, bInjectedTranslucentVolume); - bUsedLightAttenuation = true; + bUsedShadowMaskTexture = true; } for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) @@ -632,14 +638,15 @@ void FDeferredShadingSceneRenderer::RenderLights(FRHICommandListImmediate& RHICm // Render light function to the attenuation buffer. if (bDirectLighting) { - const bool bLightFunctionRendered = RenderLightFunction(RHICmdList, &LightSceneInfo, bDrawShadows, false); - bUsedLightAttenuation |= bLightFunctionRendered; - - if (ViewFamily.EngineShowFlags.PreviewShadowsIndicator - && !LightSceneInfo.IsPrecomputedLightingValid() - && LightSceneInfo.Proxy->HasStaticShadowing()) + if (bDrawLightFunction) { - RenderPreviewShadowsIndicator(RHICmdList, &LightSceneInfo, bUsedLightAttenuation); + const bool bLightFunctionRendered = RenderLightFunction(RHICmdList, &LightSceneInfo, ScreenShadowMaskTexture, bDrawShadows, false); + bUsedShadowMaskTexture |= bLightFunctionRendered; + } + + if (bDrawPreviewIndicator) + { + RenderPreviewShadowsIndicator(RHICmdList, &LightSceneInfo, ScreenShadowMaskTexture, bUsedShadowMaskTexture); } if (!bDrawShadows) @@ -648,10 +655,9 @@ void FDeferredShadingSceneRenderer::RenderLights(FRHICommandListImmediate& RHICm } } - if( bUsedLightAttenuation ) + if (bUsedShadowMaskTexture) { - // Resolve light attenuation buffer - SceneContext.FinishRenderingLightAttenuation(RHICmdList); + RHICmdList.CopyToResolveTarget(ScreenShadowMaskTexture->GetRenderTargetItem().TargetableTexture, ScreenShadowMaskTexture->GetRenderTargetItem().ShaderResourceTexture, false, FResolveParams(FResolveRect())); } if(bDirectLighting && !bInjectedTranslucentVolume) @@ -661,19 +667,14 @@ void FDeferredShadingSceneRenderer::RenderLights(FRHICommandListImmediate& RHICm InjectTranslucentVolumeLighting(RHICmdList, LightSceneInfo, NULL); } - SceneContext.SetLightAttenuationMode(bUsedLightAttenuation); SceneContext.BeginRenderingSceneColor(RHICmdList, ESimpleRenderTargetMode::EExistingColorAndDepth, FExclusiveDepthStencil::DepthRead_StencilWrite); // Render the light to the scene color buffer, conditionally using the attenuation buffer or a 1x1 white texture as input if(bDirectLighting) { - RenderLight(RHICmdList, &LightSceneInfo, false, true); + RenderLight(RHICmdList, &LightSceneInfo, ScreenShadowMaskTexture, false, true); } } - - // Restore the default mode - SceneContext.SetLightAttenuationMode(true); - } } } @@ -705,7 +706,7 @@ void FDeferredShadingSceneRenderer::RenderLightArrayForOverlapViewmode(FRHIComma && !LightSceneInfo->Proxy->HasStaticLighting() && LightSceneInfo->Proxy->CastsStaticShadow()) { - RenderLight(RHICmdList, LightSceneInfo, true, false); + RenderLight(RHICmdList, LightSceneInfo, NULL, true, false); } } } @@ -717,7 +718,7 @@ void FDeferredShadingSceneRenderer::RenderStationaryLightOverlap(FRHICommandList FSceneRenderTargets::Get(RHICmdList).BeginRenderingSceneColor(RHICmdList, ESimpleRenderTargetMode::EUninitializedColorExistingDepth, FExclusiveDepthStencil::DepthRead_StencilWrite); // Clear to discard base pass values in scene color since we didn't skip that, to have valid scene depths - DrawClearQuad(RHICmdList, GMaxRHIFeatureLevel, FLinearColor::Black); + DrawClearQuad(RHICmdList, FLinearColor::Black); RenderLightArrayForOverlapViewmode(RHICmdList, Scene->Lights); @@ -764,7 +765,8 @@ static void SetShaderTemplLighting( FGraphicsPipelineStateInitializer& GraphicsPSOInit, const FViewInfo& View, FShader* VertexShader, - const FLightSceneInfo* LightSceneInfo) + const FLightSceneInfo* LightSceneInfo, + IPooledRenderTarget* ScreenShadowMaskTexture) { if(View.Family->EngineShowFlags.VisualizeLightCulling) { @@ -773,7 +775,7 @@ static void SetShaderTemplLighting( GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(VertexShader); GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(*PixelShader); SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit); - PixelShader->SetParameters(RHICmdList, View, LightSceneInfo); + PixelShader->SetParameters(RHICmdList, View, LightSceneInfo, ScreenShadowMaskTexture); } else { @@ -784,7 +786,7 @@ static void SetShaderTemplLighting( GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(VertexShader); GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(*PixelShader); SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit); - PixelShader->SetParameters(RHICmdList, View, LightSceneInfo); + PixelShader->SetParameters(RHICmdList, View, LightSceneInfo, ScreenShadowMaskTexture); } else { @@ -793,7 +795,7 @@ static void SetShaderTemplLighting( GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(VertexShader); GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(*PixelShader); SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit); - PixelShader->SetParameters(RHICmdList, View, LightSceneInfo); + PixelShader->SetParameters(RHICmdList, View, LightSceneInfo, ScreenShadowMaskTexture); } } } @@ -865,7 +867,7 @@ void CalculateLightNearFarDepthFromBounds(const FViewInfo& View, const FSphere & * @param LightIndex The light's index into FScene::Lights * @return true if anything got rendered */ -void FDeferredShadingSceneRenderer::RenderLight(FRHICommandList& RHICmdList, const FLightSceneInfo* LightSceneInfo, bool bRenderOverlap, bool bIssueDrawEvent) +void FDeferredShadingSceneRenderer::RenderLight(FRHICommandList& RHICmdList, const FLightSceneInfo* LightSceneInfo, IPooledRenderTarget* ScreenShadowMaskTexture, bool bRenderOverlap, bool bIssueDrawEvent) { SCOPE_CYCLE_COUNTER(STAT_DirectLightRenderingTime); INC_DWORD_STAT(STAT_NumLightsUsingStandardDeferred); @@ -922,11 +924,11 @@ void FDeferredShadingSceneRenderer::RenderLight(FRHICommandList& RHICmdList, con { if(bUseIESTexture) { - SetShaderTemplLighting(RHICmdList, GraphicsPSOInit, View, *VertexShader, LightSceneInfo); + SetShaderTemplLighting(RHICmdList, GraphicsPSOInit, View, *VertexShader, LightSceneInfo, ScreenShadowMaskTexture); } else { - SetShaderTemplLighting(RHICmdList, GraphicsPSOInit, View, *VertexShader, LightSceneInfo); + SetShaderTemplLighting(RHICmdList, GraphicsPSOInit, View, *VertexShader, LightSceneInfo, ScreenShadowMaskTexture); } } @@ -966,22 +968,22 @@ void FDeferredShadingSceneRenderer::RenderLight(FRHICommandList& RHICmdList, con { if(bUseIESTexture) { - SetShaderTemplLighting(RHICmdList, GraphicsPSOInit, View, *VertexShader, LightSceneInfo); + SetShaderTemplLighting(RHICmdList, GraphicsPSOInit, View, *VertexShader, LightSceneInfo, ScreenShadowMaskTexture); } else { - SetShaderTemplLighting(RHICmdList, GraphicsPSOInit, View, *VertexShader, LightSceneInfo); + SetShaderTemplLighting(RHICmdList, GraphicsPSOInit, View, *VertexShader, LightSceneInfo, ScreenShadowMaskTexture); } } else { if(bUseIESTexture) { - SetShaderTemplLighting(RHICmdList, GraphicsPSOInit, View, *VertexShader, LightSceneInfo); + SetShaderTemplLighting(RHICmdList, GraphicsPSOInit, View, *VertexShader, LightSceneInfo, ScreenShadowMaskTexture); } else { - SetShaderTemplLighting(RHICmdList, GraphicsPSOInit, View, *VertexShader, LightSceneInfo); + SetShaderTemplLighting(RHICmdList, GraphicsPSOInit, View, *VertexShader, LightSceneInfo, ScreenShadowMaskTexture); } } } @@ -1029,7 +1031,7 @@ void FDeferredShadingSceneRenderer::RenderLight(FRHICommandList& RHICmdList, con if (bStencilDirty) { // Clear the stencil buffer to 0. - DrawClearQuad(RHICmdList, GMaxRHIFeatureLevel, false, FLinearColor::Transparent, false, 0, true, 1); + DrawClearQuad(RHICmdList, false, FLinearColor::Transparent, false, 0, true, 1); } } diff --git a/Engine/Source/Runtime/Renderer/Private/LightSceneInfo.cpp b/Engine/Source/Runtime/Renderer/Private/LightSceneInfo.cpp index 9f9ee52fc3b5..bbb88ad0e0d1 100644 --- a/Engine/Source/Runtime/Renderer/Private/LightSceneInfo.cpp +++ b/Engine/Source/Runtime/Renderer/Private/LightSceneInfo.cpp @@ -104,7 +104,7 @@ void FLightSceneInfo::AddToScene() */ void FLightSceneInfo::CreateLightPrimitiveInteraction(const FLightSceneInfoCompact& LightSceneInfoCompact, const FPrimitiveSceneInfoCompact& PrimitiveSceneInfoCompact) { - if( LightSceneInfoCompact.AffectsPrimitive(PrimitiveSceneInfoCompact)) + if( LightSceneInfoCompact.AffectsPrimitive(PrimitiveSceneInfoCompact.Bounds, PrimitiveSceneInfoCompact.Proxy)) { // create light interaction and add to light/primitive lists FLightPrimitiveInteraction::Create(this,PrimitiveSceneInfoCompact.PrimitiveSceneInfo); @@ -218,14 +218,14 @@ FORCEINLINE bool AreSpheresNotIntersecting( * @param CompactPrimitiveSceneInfo - The primitive to test. * @return True if the light affects the primitive. */ -bool FLightSceneInfoCompact::AffectsPrimitive(const FPrimitiveSceneInfoCompact& CompactPrimitiveSceneInfo) const +bool FLightSceneInfoCompact::AffectsPrimitive(const FBoxSphereBounds& PrimitiveBounds, const FPrimitiveSceneProxy* PrimitiveSceneProxy) const { // Check if the light's bounds intersect the primitive's bounds. if(AreSpheresNotIntersecting( BoundingSphereVector, VectorReplicate(BoundingSphereVector,3), - VectorLoadFloat3(&CompactPrimitiveSceneInfo.Bounds.Origin), - VectorLoadFloat1(&CompactPrimitiveSceneInfo.Bounds.SphereRadius) + VectorLoadFloat3(&PrimitiveBounds.Origin), + VectorLoadFloat1(&PrimitiveBounds.SphereRadius) )) { return false; @@ -233,17 +233,17 @@ bool FLightSceneInfoCompact::AffectsPrimitive(const FPrimitiveSceneInfoCompact& // Cull based on information in the full scene infos. - if(!LightSceneInfo->Proxy->AffectsBounds(CompactPrimitiveSceneInfo.Bounds)) + if(!LightSceneInfo->Proxy->AffectsBounds(PrimitiveBounds)) { return false; } - if (LightSceneInfo->Proxy->CastsShadowsFromCinematicObjectsOnly() && !CompactPrimitiveSceneInfo.Proxy->CastsCinematicShadow()) + if (LightSceneInfo->Proxy->CastsShadowsFromCinematicObjectsOnly() && !PrimitiveSceneProxy->CastsCinematicShadow()) { return false; } - if (!(LightSceneInfo->Proxy->GetLightingChannelMask() & CompactPrimitiveSceneInfo.Proxy->GetLightingChannelMask())) + if (!(LightSceneInfo->Proxy->GetLightingChannelMask() & PrimitiveSceneProxy->GetLightingChannelMask())) { return false; } diff --git a/Engine/Source/Runtime/Renderer/Private/LightSceneInfo.h b/Engine/Source/Runtime/Renderer/Private/LightSceneInfo.h index 0a0b673bbf88..b140a651d41d 100644 --- a/Engine/Source/Runtime/Renderer/Private/LightSceneInfo.h +++ b/Engine/Source/Runtime/Renderer/Private/LightSceneInfo.h @@ -58,7 +58,7 @@ public: * @param CompactPrimitiveSceneInfo - The primitive to test. * @return True if the light affects the primitive. */ - bool AffectsPrimitive(const FPrimitiveSceneInfoCompact& CompactPrimitiveSceneInfo) const; + bool AffectsPrimitive(const FBoxSphereBounds& PrimitiveBounds, const FPrimitiveSceneProxy* PrimitiveSceneProxy) const; }; /** Information for sorting lights. */ @@ -82,17 +82,23 @@ struct FSortedLightSceneInfo /** Sort key bits packed into an integer. */ int32 Packed; } SortKey; - /** The compact light scene info. */ - FLightSceneInfoCompact SceneInfo; + + const FLightSceneInfo* LightSceneInfo; /** Initialization constructor. */ - explicit FSortedLightSceneInfo(const FLightSceneInfoCompact& InSceneInfo) - : SceneInfo(InSceneInfo) + explicit FSortedLightSceneInfo(const FLightSceneInfo* InLightSceneInfo) + : LightSceneInfo(InLightSceneInfo) { SortKey.Packed = 0; } }; +template <> +struct TUseBitwiseSwap +{ + enum { Value = false }; +}; + /** The type of the octree used by FScene to find lights. */ typedef TOctree FSceneLightOctree; diff --git a/Engine/Source/Runtime/Renderer/Private/LightShaftRendering.cpp b/Engine/Source/Runtime/Renderer/Private/LightShaftRendering.cpp index 87b5686d6caa..aa5a2e6062c6 100644 --- a/Engine/Source/Runtime/Renderer/Private/LightShaftRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/LightShaftRendering.cpp @@ -52,10 +52,10 @@ static FAutoConsoleVariableRef CVarCacheLightShaftDownsampleFactor( ECVF_RenderThreadSafe ); -int32 GLightShaftRenderToSeparateTranslucency = 0; -static FAutoConsoleVariableRef CVarRenderLightshaftsToSeparateTranslucency( +int32 GLightShaftRenderAfterDOF = 0; +static FAutoConsoleVariableRef CVarRenderLightshaftsAfterDOF( TEXT("r.LightShaftRenderToSeparateTranslucency"), - GLightShaftRenderToSeparateTranslucency, + GLightShaftRenderAfterDOF, TEXT("If enabled, light shafts will be rendered to the separate translucency buffer.\n") TEXT("This ensures postprocess materials with BL_BeforeTranslucnecy are applied before light shafts"), ECVF_RenderThreadSafe @@ -921,7 +921,7 @@ void ApplyLightShaftBloom(FRHICommandListImmediate& RHICmdList, const FViewInfo& FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); bool bUseSeparateTranslucency = false; - if (SceneContext.IsSeparateTranslucencyActive(View) && GLightShaftRenderToSeparateTranslucency ) + if (View.Family->AllowTranslucencyAfterDOF() && GLightShaftRenderAfterDOF) { SceneContext.BeginRenderingSeparateTranslucency(RHICmdList, View, false); bUseSeparateTranslucency = true; @@ -968,6 +968,11 @@ void ApplyLightShaftBloom(FRHICommandListImmediate& RHICmdList, const FViewInfo& FIntPoint(View.ViewRect.Width(), View.ViewRect.Height()), FilterBufferSize, *ScreenVertexShader, EDRF_UseTriangleOptimization); + + if (bUseSeparateTranslucency) + { + SceneContext.FinishRenderingSeparateTranslucency(RHICmdList, View); + } } void FSceneViewState::TrimHistoryRenderTargets(const FScene* Scene) @@ -1023,48 +1028,48 @@ void FDeferredShadingSceneRenderer::RenderLightShaftBloom(FRHICommandListImmedia if (bWillRenderLightShafts) { - // Allocate light shaft render targets on demand, using the pool - AllocateOrReuseLightShaftRenderTarget(RHICmdList, LightShafts0, TEXT("LightShafts0")); - AllocateOrReuseLightShaftRenderTarget(RHICmdList, LightShafts1, TEXT("LightShafts1")); + // Allocate light shaft render targets on demand, using the pool + AllocateOrReuseLightShaftRenderTarget(RHICmdList, LightShafts0, TEXT("LightShafts0")); + AllocateOrReuseLightShaftRenderTarget(RHICmdList, LightShafts1, TEXT("LightShafts1")); for (int ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) - { - FViewInfo& View = Views[ViewIndex]; - - SCOPED_DRAW_EVENTF(RHICmdList, RenderLightShaftBloom, TEXT("RenderLightShaftBloom %dx%d"), View.ViewRect.Width(), View.ViewRect.Height()); - - if (ShouldRenderLightShaftsForLight(View, LightSceneInfo)) { - INC_DWORD_STAT(STAT_LightShaftsLights); + FViewInfo& View = Views[ViewIndex]; - // Generate the bloom source from scene color, masked by depth and downsampled - DownsamplePass(RHICmdList, View, LightSceneInfo, LightShafts0, LightShafts1); + SCOPED_DRAW_EVENTF(RHICmdList, RenderLightShaftBloom, TEXT("RenderLightShaftBloom %dx%d"), View.ViewRect.Width(), View.ViewRect.Height()); - FSceneViewState* ViewState = (FSceneViewState*)View.State; - TRefCountPtr* HistoryState = NULL; - - if (ViewState) + if (ShouldRenderLightShaftsForLight(View, LightSceneInfo)) { - // Find the previous frame's bloom source for this light - HistoryState = &ViewState->LightShaftBloomHistoryRTs.FindOrAdd(LightSceneInfo->Proxy->GetLightComponent()); - } + INC_DWORD_STAT(STAT_LightShaftsLights); - TRefCountPtr HistoryOutput; + // Generate the bloom source from scene color, masked by depth and downsampled + DownsamplePass(RHICmdList, View, LightSceneInfo, LightShafts0, LightShafts1); - // Apply temporal AA to the occlusion mask - // Result will be in HistoryOutput - ApplyTemporalAA(RHICmdList, View, TEXT("LSBloomHistory"), HistoryState, LightShafts0, HistoryOutput); + FSceneViewState* ViewState = (FSceneViewState*)View.State; + TRefCountPtr* HistoryState = NULL; - // Apply radial blur passes - // Send HistoryOutput in as the first pass input only, so it will not be overwritten by any subsequent passes, since it is needed for next frame - ApplyRadialBlurPasses(RHICmdList, View, LightSceneInfo, HistoryOutput, LightShafts0, LightShafts1); + if (ViewState) + { + // Find the previous frame's bloom source for this light + HistoryState = &ViewState->LightShaftBloomHistoryRTs.FindOrAdd(LightSceneInfo->Proxy->GetLightComponent()); + } + + TRefCountPtr HistoryOutput; + + // Apply temporal AA to the occlusion mask + // Result will be in HistoryOutput + ApplyTemporalAA(RHICmdList, View, TEXT("LSBloomHistory"), HistoryState, LightShafts0, HistoryOutput); + + // Apply radial blur passes + // Send HistoryOutput in as the first pass input only, so it will not be overwritten by any subsequent passes, since it is needed for next frame + ApplyRadialBlurPasses(RHICmdList, View, LightSceneInfo, HistoryOutput, LightShafts0, LightShafts1); - // Add light shaft bloom to scene color in full res - ApplyLightShaftBloom(RHICmdList, View, LightSceneInfo, LightShafts0); + // Add light shaft bloom to scene color in full res + ApplyLightShaftBloom(RHICmdList, View, LightSceneInfo, LightShafts0); + } } } } } } } -} diff --git a/Engine/Source/Runtime/Renderer/Private/MobileBasePassRendering.h b/Engine/Source/Runtime/Renderer/Private/MobileBasePassRendering.h index cd4b3d304cba..72272a053dc6 100644 --- a/Engine/Source/Runtime/Renderer/Private/MobileBasePassRendering.h +++ b/Engine/Source/Runtime/Renderer/Private/MobileBasePassRendering.h @@ -713,10 +713,10 @@ public: else { - bool bEncodedHDR = IsMobileHDR32bpp() && !IsMobileHDRMosaic(); + bool bEncodedHDR = GetMobileHDRMode() == EMobileHDRMode::EnabledRGBE && MaterialResource->GetMaterialDomain() != MD_UI;; static const auto CVarMonoscopicFarField = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("vr.MonoscopicFarField")); - const bool bIsMobileMonoscopic = CVarMonoscopicFarField && (CVarMonoscopicFarField->GetValueOnGameThread() != 0); + const bool bIsMobileMonoscopic = CVarMonoscopicFarField && (CVarMonoscopicFarField->GetValueOnRenderThread() != 0); if (bEncodedHDR == false) { diff --git a/Engine/Source/Runtime/Renderer/Private/MobileDecalRendering.cpp b/Engine/Source/Runtime/Renderer/Private/MobileDecalRendering.cpp index 3e4feb5c7b64..cb177f29355d 100644 --- a/Engine/Source/Runtime/Renderer/Private/MobileDecalRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/MobileDecalRendering.cpp @@ -48,7 +48,7 @@ void FMobileSceneRenderer::RenderDecals(FRHICommandListImmediate& RHICmdList) TOptional LastDecalBlendMode; TOptional LastDecalDepthState; - bool bEncodedHDR = IsMobileHDR32bpp() && !IsMobileHDRMosaic(); + bool bEncodedHDR = GetMobileHDRMode() == EMobileHDRMode::EnabledRGBE; if (bEncodedHDR) { GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI(); diff --git a/Engine/Source/Runtime/Renderer/Private/MobileReflectionEnvironmentCapture.cpp b/Engine/Source/Runtime/Renderer/Private/MobileReflectionEnvironmentCapture.cpp new file mode 100644 index 000000000000..edf950d90f9d --- /dev/null +++ b/Engine/Source/Runtime/Renderer/Private/MobileReflectionEnvironmentCapture.cpp @@ -0,0 +1,383 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +/*============================================================================= + +=============================================================================*/ +#include "MobileReflectionEnvironmentCapture.h" +#include "ReflectionEnvironmentCapture.h" +#include "ShaderParameterUtils.h" +#include "RHIStaticStates.h" +#include "SceneRenderTargets.h" +#include "SceneUtils.h" +#include "ScreenRendering.h" +#include "PipelineStateCache.h" +#include "SceneFilterRendering.h" +#include "OneColorShader.h" + +extern int32 GDiffuseIrradianceCubemapSize; +extern float ComputeSingleAverageBrightnessFromCubemap(FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, int32 TargetSize, FSceneRenderTargetItem& Cubemap); +extern void FullyResolveReflectionScratchCubes(FRHICommandListImmediate& RHICmdList); + +class FMobileDownsamplePS : public FGlobalShader +{ + DECLARE_SHADER_TYPE(FMobileDownsamplePS, Global); +public: + + static bool ShouldCache(EShaderPlatform Platform) + { + return IsMobilePlatform(Platform); + } + + FMobileDownsamplePS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) : + FGlobalShader(Initializer) + { + CubeFace.Bind(Initializer.ParameterMap, TEXT("CubeFace")); + SourceMipIndex.Bind(Initializer.ParameterMap, TEXT("SourceMipIndex")); + SourceTexture.Bind(Initializer.ParameterMap, TEXT("SourceTexture")); + SourceTextureSampler.Bind(Initializer.ParameterMap, TEXT("SourceTextureSampler")); + } + FMobileDownsamplePS() {} + + void SetParameters(FRHICommandList& RHICmdList, int32 CubeFaceValue, int32 SourceMipIndexValue, FSceneRenderTargetItem& SourceTextureValue) + { + SetShaderValue(RHICmdList, GetPixelShader(), CubeFace, CubeFaceValue); + SetShaderValue(RHICmdList, GetPixelShader(), SourceMipIndex, SourceMipIndexValue); + + SetTextureParameter( + RHICmdList, + GetPixelShader(), + SourceTexture, + SourceTextureSampler, + TStaticSamplerState::GetRHI(), + SourceTextureValue.ShaderResourceTexture); + } + + virtual bool Serialize(FArchive& Ar) override + { + bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar); + Ar << CubeFace; + Ar << SourceMipIndex; + Ar << SourceTexture; + Ar << SourceTextureSampler; + return bShaderHasOutdatedParameters; + } + +private: + FShaderParameter CubeFace; + FShaderParameter SourceMipIndex; + FShaderResourceParameter SourceTexture; + FShaderResourceParameter SourceTextureSampler; +}; + +IMPLEMENT_SHADER_TYPE(, FMobileDownsamplePS, TEXT("ReflectionEnvironmentShaders"), TEXT("DownsamplePS_Mobile"), SF_Pixel); +namespace MobileReflectionEnvironmentCapture +{ + /** Encapsulates render target picking logic for cubemap mip generation. */ + FSceneRenderTargetItem& GetEffectiveRenderTarget(FSceneRenderTargets& SceneContext, bool bDownsamplePass, int32 TargetMipIndex) + { + int32 ScratchTextureIndex = TargetMipIndex % 2; + + if (!bDownsamplePass) + { + ScratchTextureIndex = 1 - ScratchTextureIndex; + } + + return SceneContext.ReflectionColorScratchCubemap[ScratchTextureIndex]->GetRenderTargetItem(); + } + + /** Encapsulates source texture picking logic for cubemap mip generation. */ + FSceneRenderTargetItem& GetEffectiveSourceTexture(FSceneRenderTargets& SceneContext, bool bDownsamplePass, int32 TargetMipIndex) + { + int32 ScratchTextureIndex = TargetMipIndex % 2; + + if (bDownsamplePass) + { + ScratchTextureIndex = 1 - ScratchTextureIndex; + } + + return SceneContext.ReflectionColorScratchCubemap[ScratchTextureIndex]->GetRenderTargetItem(); + } + + void ComputeAverageBrightness(FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, int32 CubmapSize, float& OutAverageBrightness) + { + SCOPED_DRAW_EVENT(RHICmdList, ComputeAverageBrightness); + + const int32 EffectiveTopMipSize = CubmapSize; + const int32 NumMips = FMath::CeilLogTwo(EffectiveTopMipSize) + 1; + + // necessary to resolve the clears which touched all the mips. scene rendering only resolves mip 0. + FullyResolveReflectionScratchCubes(RHICmdList); + + auto ShaderMap = GetGlobalShaderMap(FeatureLevel); + + FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); + + { + SCOPED_DRAW_EVENT(RHICmdList, DownsampleCubeMips); + + // Downsample all the mips, each one reads from the mip above it + for (int32 MipIndex = 1; MipIndex < NumMips; MipIndex++) + { + const int32 SourceMipIndex = FMath::Max(MipIndex - 1, 0); + const int32 MipSize = 1 << (NumMips - MipIndex - 1); + + FSceneRenderTargetItem& EffectiveRT = GetEffectiveRenderTarget(SceneContext, true, MipIndex); + FSceneRenderTargetItem& EffectiveSource = GetEffectiveSourceTexture(SceneContext, true, MipIndex); + check(EffectiveRT.TargetableTexture != EffectiveSource.ShaderResourceTexture); + + for (int32 CubeFace = 0; CubeFace < CubeFace_MAX; CubeFace++) + { + SetRenderTarget(RHICmdList, EffectiveRT.TargetableTexture, MipIndex, CubeFace, NULL, true); + FGraphicsPipelineStateInitializer GraphicsPSOInit; + RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit); + GraphicsPSOInit.RasterizerState = TStaticRasterizerState::GetRHI(); + GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState::GetRHI(); + GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI(); + + const FIntRect ViewRect(0, 0, MipSize, MipSize); + RHICmdList.SetViewport(0, 0, 0.0f, MipSize, MipSize, 1.0f); + + TShaderMapRef VertexShader(ShaderMap); + TShaderMapRef PixelShader(ShaderMap); + + GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI; + GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(*VertexShader); + GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(*PixelShader); + GraphicsPSOInit.PrimitiveType = PT_TriangleList; + SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit); + + PixelShader->SetParameters(RHICmdList, CubeFace, SourceMipIndex, EffectiveSource); + + DrawRectangle( + RHICmdList, + ViewRect.Min.X, ViewRect.Min.Y, + ViewRect.Width(), ViewRect.Height(), + ViewRect.Min.X, ViewRect.Min.Y, + ViewRect.Width(), ViewRect.Height(), + FIntPoint(ViewRect.Width(), ViewRect.Height()), + FIntPoint(MipSize, MipSize), + *VertexShader); + + RHICmdList.CopyToResolveTarget(EffectiveRT.TargetableTexture, EffectiveRT.ShaderResourceTexture, true, FResolveParams(FResolveRect(), (ECubeFace)CubeFace, MipIndex)); + } + } + } + + OutAverageBrightness = ComputeSingleAverageBrightnessFromCubemap(RHICmdList, FeatureLevel, CubmapSize, GetEffectiveRenderTarget(FSceneRenderTargets::Get(RHICmdList), true, NumMips - 1)); + } + + void CopyToSkyTexture(FRHICommandList& RHICmdList, FScene* Scene, FTexture* ProcessedTexture) + { + SCOPED_DRAW_EVENT(RHICmdList, CopyToSkyTexture); + if (ProcessedTexture->TextureRHI) + { + const int32 EffectiveTopMipSize = ProcessedTexture->GetSizeX(); + const int32 NumMips = FMath::CeilLogTwo(EffectiveTopMipSize) + 1; + FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); + + // GPU copy back to the skylight's texture, which is not a render target + for (int32 MipIndex = 0; MipIndex < NumMips; MipIndex++) + { + // The source for this copy is the dest from the filtering pass + FSceneRenderTargetItem& EffectiveSource = GetEffectiveRenderTarget(SceneContext, false, MipIndex); + + for (int32 CubeFace = 0; CubeFace < CubeFace_MAX; CubeFace++) + { + RHICmdList.CopyToResolveTarget(EffectiveSource.ShaderResourceTexture, ProcessedTexture->TextureRHI, true, FResolveParams(FResolveRect(), (ECubeFace)CubeFace, MipIndex, 0, 0)); + } + } + } + } + + /** Generates mips for glossiness and filters the cubemap for a given reflection. */ + void FilterReflectionEnvironment(FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, int32 CubmapSize, FSHVectorRGB3* OutIrradianceEnvironmentMap) + { + SCOPED_DRAW_EVENT(RHICmdList, FilterReflectionEnvironment); + + const int32 EffectiveTopMipSize = CubmapSize; + const int32 NumMips = FMath::CeilLogTwo(EffectiveTopMipSize) + 1; + + FSceneRenderTargetItem& EffectiveColorRT = FSceneRenderTargets::Get(RHICmdList).ReflectionColorScratchCubemap[0]->GetRenderTargetItem(); + // Premultiply alpha in-place using alpha blending + for (uint32 CubeFace = 0; CubeFace < CubeFace_MAX; CubeFace++) + { + SetRenderTarget(RHICmdList, EffectiveColorRT.TargetableTexture, 0, CubeFace, NULL, true); + FGraphicsPipelineStateInitializer GraphicsPSOInit; + RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit); + GraphicsPSOInit.RasterizerState = TStaticRasterizerState::GetRHI(); + GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState::GetRHI(); + GraphicsPSOInit.BlendState = TStaticBlendState::GetRHI(); + + const FIntPoint SourceDimensions(CubmapSize, CubmapSize); + const FIntRect ViewRect(0, 0, EffectiveTopMipSize, EffectiveTopMipSize); + RHICmdList.SetViewport(0, 0, 0.0f, EffectiveTopMipSize, EffectiveTopMipSize, 1.0f); + + TShaderMapRef VertexShader(GetGlobalShaderMap(FeatureLevel)); + TShaderMapRef PixelShader(GetGlobalShaderMap(FeatureLevel)); + + GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI; + GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(*VertexShader); + GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(*PixelShader); + GraphicsPSOInit.PrimitiveType = PT_TriangleList; + + SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit); + + FLinearColor UnusedColors[1] = { FLinearColor::Black }; + PixelShader->SetColors(RHICmdList, UnusedColors, ARRAY_COUNT(UnusedColors)); + + DrawRectangle( + RHICmdList, + ViewRect.Min.X, ViewRect.Min.Y, + ViewRect.Width(), ViewRect.Height(), + 0, 0, + SourceDimensions.X, SourceDimensions.Y, + FIntPoint(ViewRect.Width(), ViewRect.Height()), + SourceDimensions, + *VertexShader); + + RHICmdList.CopyToResolveTarget(EffectiveColorRT.TargetableTexture, EffectiveColorRT.ShaderResourceTexture, true, FResolveParams(FResolveRect(), (ECubeFace)CubeFace)); + } + + int32 DiffuseConvolutionSourceMip = INDEX_NONE; + FSceneRenderTargetItem* DiffuseConvolutionSource = NULL; + + auto ShaderMap = GetGlobalShaderMap(FeatureLevel); + FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); + + { + SCOPED_DRAW_EVENT(RHICmdList, DownsampleCubeMips); + // Downsample all the mips, each one reads from the mip above it + for (int32 MipIndex = 1; MipIndex < NumMips; MipIndex++) + { + SCOPED_DRAW_EVENT(RHICmdList, DownsampleCubeMip); + const int32 SourceMipIndex = FMath::Max(MipIndex - 1, 0); + const int32 MipSize = 1 << (NumMips - MipIndex - 1); + + FSceneRenderTargetItem& EffectiveRT = GetEffectiveRenderTarget(SceneContext, true, MipIndex); + FSceneRenderTargetItem& EffectiveSource = GetEffectiveSourceTexture(SceneContext, true, MipIndex); + check(EffectiveRT.TargetableTexture != EffectiveSource.ShaderResourceTexture); + + for (int32 CubeFace = 0; CubeFace < CubeFace_MAX; CubeFace++) + { + SetRenderTarget(RHICmdList, EffectiveRT.TargetableTexture, MipIndex, CubeFace, NULL, true); + + FGraphicsPipelineStateInitializer GraphicsPSOInit; + RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit); + GraphicsPSOInit.RasterizerState = TStaticRasterizerState::GetRHI(); + GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState::GetRHI(); + GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI(); + + const FIntRect ViewRect(0, 0, MipSize, MipSize); + RHICmdList.SetViewport(0, 0, 0.0f, MipSize, MipSize, 1.0f); + + TShaderMapRef VertexShader(ShaderMap); + TShaderMapRef PixelShader(ShaderMap); + + GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI; + GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(*VertexShader); + GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(*PixelShader); + GraphicsPSOInit.PrimitiveType = PT_TriangleList; + + SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit); + + PixelShader->SetParameters(RHICmdList, CubeFace, SourceMipIndex, EffectiveSource); + + DrawRectangle( + RHICmdList, + ViewRect.Min.X, ViewRect.Min.Y, + ViewRect.Width(), ViewRect.Height(), + ViewRect.Min.X, ViewRect.Min.Y, + ViewRect.Width(), ViewRect.Height(), + FIntPoint(ViewRect.Width(), ViewRect.Height()), + FIntPoint(MipSize, MipSize), + *VertexShader); + + RHICmdList.CopyToResolveTarget(EffectiveRT.TargetableTexture, EffectiveRT.ShaderResourceTexture, true, FResolveParams(FResolveRect(), (ECubeFace)CubeFace, MipIndex)); + } + + if (MipSize == GDiffuseIrradianceCubemapSize) + { + DiffuseConvolutionSourceMip = MipIndex; + DiffuseConvolutionSource = &EffectiveRT; + } + } + } + + if (OutIrradianceEnvironmentMap) + { + SCOPED_DRAW_EVENT(RHICmdList, ComputeDiffuseIrradiance); + check(DiffuseConvolutionSource != NULL); + ComputeDiffuseIrradiance(RHICmdList, FeatureLevel, DiffuseConvolutionSource->ShaderResourceTexture, DiffuseConvolutionSourceMip, OutIrradianceEnvironmentMap); + } + + { + SCOPED_DRAW_EVENT(RHICmdList, FilterCubeMap); + // Filter all the mips, each one reads from whichever scratch render target holds the downsampled contents, and writes to the destination cubemap + for (int32 MipIndex = 0; MipIndex < NumMips; MipIndex++) + { + SCOPED_DRAW_EVENT(RHICmdList, FilterCubeMip); + FSceneRenderTargetItem& EffectiveRT = GetEffectiveRenderTarget(SceneContext, false, MipIndex); + FSceneRenderTargetItem& EffectiveSource = GetEffectiveSourceTexture(SceneContext, false, MipIndex); + check(EffectiveRT.TargetableTexture != EffectiveSource.ShaderResourceTexture); + const int32 MipSize = 1 << (NumMips - MipIndex - 1); + + for (int32 CubeFace = 0; CubeFace < CubeFace_MAX; CubeFace++) + { + SetRenderTarget(RHICmdList, EffectiveRT.TargetableTexture, MipIndex, CubeFace, NULL, true); + + FGraphicsPipelineStateInitializer GraphicsPSOInit; + RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit); + GraphicsPSOInit.RasterizerState = TStaticRasterizerState::GetRHI(); + GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState::GetRHI(); + GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI(); + + const FIntRect ViewRect(0, 0, MipSize, MipSize); + RHICmdList.SetViewport(0, 0, 0.0f, MipSize, MipSize, 1.0f); + + TShaderMapRef VertexShader(GetGlobalShaderMap(FeatureLevel)); + TShaderMapRef< TCubeFilterPS<1> > CaptureCubemapArrayPixelShader(GetGlobalShaderMap(FeatureLevel)); + + FCubeFilterPS* PixelShader; + PixelShader = *TShaderMapRef< TCubeFilterPS<0> >(ShaderMap); + check(PixelShader); + + GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI; + GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(*VertexShader); + GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(PixelShader); + GraphicsPSOInit.PrimitiveType = PT_TriangleList; + + SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit); + { + const FPixelShaderRHIParamRef ShaderRHI = PixelShader->GetPixelShader(); + + SetShaderValue(RHICmdList, ShaderRHI, PixelShader->CubeFace, CubeFace); + SetShaderValue(RHICmdList, ShaderRHI, PixelShader->MipIndex, MipIndex); + + SetShaderValue(RHICmdList, ShaderRHI, PixelShader->NumMips, NumMips); + + SetTextureParameter( + RHICmdList, + ShaderRHI, + PixelShader->SourceTexture, + PixelShader->SourceTextureSampler, + TStaticSamplerState::GetRHI(), + EffectiveSource.ShaderResourceTexture); + } + //PixelShader->SetParameters(RHICmdList, NumMips, CubeFace, MipIndex, EffectiveSource); + + DrawRectangle( + RHICmdList, + ViewRect.Min.X, ViewRect.Min.Y, + ViewRect.Width(), ViewRect.Height(), + ViewRect.Min.X, ViewRect.Min.Y, + ViewRect.Width(), ViewRect.Height(), + FIntPoint(ViewRect.Width(), ViewRect.Height()), + FIntPoint(MipSize, MipSize), + *VertexShader); + + RHICmdList.CopyToResolveTarget(EffectiveRT.TargetableTexture, EffectiveRT.ShaderResourceTexture, true, FResolveParams(FResolveRect(), (ECubeFace)CubeFace, MipIndex)); + } + } + } + } +} diff --git a/Engine/Source/Runtime/Renderer/Private/MobileReflectionEnvironmentCapture.h b/Engine/Source/Runtime/Renderer/Private/MobileReflectionEnvironmentCapture.h new file mode 100644 index 000000000000..e27f0c9cf6be --- /dev/null +++ b/Engine/Source/Runtime/Renderer/Private/MobileReflectionEnvironmentCapture.h @@ -0,0 +1,19 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +/*============================================================================= + +=============================================================================*/ + +#pragma once + +#include "CoreMinimal.h" +#include "RHI.h" +#include "SHMath.h" +#include "ScenePrivate.h" + +namespace MobileReflectionEnvironmentCapture +{ + void ComputeAverageBrightness(FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, int32 CubmapSize, float& OutAverageBrightness); + void FilterReflectionEnvironment(FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, int32 CubmapSize, FSHVectorRGB3* OutIrradianceEnvironmentMap); + void CopyToSkyTexture(FRHICommandList& RHICmdList, FScene* Scene, FTexture* ProcessedTexture); +} \ No newline at end of file diff --git a/Engine/Source/Runtime/Renderer/Private/MobileSceneCaptureRendering.cpp b/Engine/Source/Runtime/Renderer/Private/MobileSceneCaptureRendering.cpp index 4153f2271036..1b0e6a8c6517 100644 --- a/Engine/Source/Runtime/Renderer/Private/MobileSceneCaptureRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/MobileSceneCaptureRendering.cpp @@ -393,7 +393,7 @@ void UpdateSceneCaptureContentMobile_RenderThread( { auto& RenderTargetRHI = Target->GetRenderTargetTexture(); SetRenderTarget(RHICmdList, RenderTargetRHI, NULL, true); - DrawClearQuad(RHICmdList, SceneRenderer->FeatureLevel, true, FLinearColor::Black, false, 0, false, 0, Target->GetSizeXY(), ViewRect); + DrawClearQuad(RHICmdList, true, FLinearColor::Black, false, 0, false, 0, Target->GetSizeXY(), ViewRect); } // Render the scene normally diff --git a/Engine/Source/Runtime/Renderer/Private/MobileShadingRenderer.cpp b/Engine/Source/Runtime/Renderer/Private/MobileShadingRenderer.cpp index bbc98ca308dd..caf15526e489 100644 --- a/Engine/Source/Runtime/Renderer/Private/MobileShadingRenderer.cpp +++ b/Engine/Source/Runtime/Renderer/Private/MobileShadingRenderer.cpp @@ -144,7 +144,7 @@ void FMobileSceneRenderer::Render(FRHICommandListImmediate& RHICmdList) } } - if (GRHIThread) + if (IsRunningRHIInSeparateThread()) { // we will probably stall on occlusion queries, so might as well have the RHI thread and GPU work while we wait. // Also when doing RHI thread this is the only spot that will process pending deletes @@ -208,7 +208,7 @@ void FMobileSceneRenderer::Render(FRHICommandListImmediate& RHICmdList) if (GIsEditor && !View.bIsSceneCapture) { - DrawClearQuad(RHICmdList, GMaxRHIFeatureLevel, Views[0].BackgroundColor); + DrawClearQuad(RHICmdList, Views[0].BackgroundColor); } RenderMobileBasePass(RHICmdList, ViewList); diff --git a/Engine/Source/Runtime/Renderer/Private/MobileTranslucentRendering.cpp b/Engine/Source/Runtime/Renderer/Private/MobileTranslucentRendering.cpp index 5779ba36a6e4..bc3540b19341 100644 --- a/Engine/Source/Runtime/Renderer/Private/MobileTranslucentRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/MobileTranslucentRendering.cpp @@ -276,9 +276,7 @@ template void FTranslucentPrimSet::DrawPrimitivesForMobile(FRHICommandListImmediate& RHICmdList, const FViewInfo& View, const FDrawingPolicyRenderState& DrawRenderState, typename TDrawingPolicyFactory::ContextType& DrawingContext) const { - ETranslucencyPass::Type TranslucencyPass = DrawingContext.ShouldRenderSeparateTranslucency() ? ETranslucencyPass::TPT_SeparateTranslucency : ETranslucencyPass::TPT_StandardTranslucency; - - FInt32Range PassRange = SortedPrimsNum.GetPassRange(TranslucencyPass); + FInt32Range PassRange = SortedPrimsNum.GetPassRange(ETranslucencyPass::TPT_AllTranslucency); // Draw sorted scene prims for (int32 PrimIdx = PassRange.GetLowerBoundValue(); PrimIdx < PassRange.GetUpperBoundValue(); PrimIdx++) @@ -327,7 +325,7 @@ void FTranslucentPrimSet::DrawPrimitivesForMobile(FRHICommandListImmediate& RHIC void FMobileSceneRenderer::RenderTranslucency(FRHICommandListImmediate& RHICmdList, const TArrayView PassViews) { - if (ShouldRenderTranslucency()) + if (ShouldRenderTranslucency(ETranslucencyPass::TPT_AllTranslucency)) { const bool bGammaSpace = !IsMobileHDR(); const bool bLinearHDR64 = !bGammaSpace && !IsMobileHDR32bpp(); @@ -352,7 +350,7 @@ void FMobileSceneRenderer::RenderTranslucency(FRHICommandListImmediate& RHICmdLi if (!bGammaSpace) { - FSceneRenderTargets::Get(RHICmdList).BeginRenderingTranslucency(RHICmdList, View); + FSceneRenderTargets::Get(RHICmdList).BeginRenderingTranslucency(RHICmdList, View, false); } else { @@ -670,7 +668,7 @@ bool FMobileSceneRenderer::RenderInverseOpacity(FRHICommandListImmediate& RHICmd { bool bDirty = false; - if (ShouldRenderTranslucency()) + if (ShouldRenderTranslucency(ETranslucencyPass::TPT_AllTranslucency)) { const bool bGammaSpace = !IsMobileHDR(); const bool bLinearHDR64 = !bGammaSpace && !IsMobileHDR32bpp(); diff --git a/Engine/Source/Runtime/Renderer/Private/PlanarReflectionRendering.cpp b/Engine/Source/Runtime/Renderer/Private/PlanarReflectionRendering.cpp index 0d16878466fc..4d6b54b7ef94 100644 --- a/Engine/Source/Runtime/Renderer/Private/PlanarReflectionRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PlanarReflectionRendering.cpp @@ -68,7 +68,7 @@ public: { const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader(); FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View.ViewUniformBuffer); - DeferredParameters.Set(RHICmdList, ShaderRHI, View, ESceneRenderTargetsMode::SetTextures); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_PostProcess, ESceneRenderTargetsMode::SetTextures); PlanarReflectionParameters.SetParameters(RHICmdList, ShaderRHI, View, ReflectionSceneProxy); int32 RenderTargetSizeY = ReflectionSceneProxy->RenderTarget->GetSizeXY().Y; @@ -272,7 +272,7 @@ static void UpdatePlanarReflectionContents_RenderThread( else { SetRenderTarget(RHICmdList, Target->GetRenderTargetTexture(), nullptr, true); - DrawClearQuad(RHICmdList, GMaxRHIFeatureLevel, FLinearColor::Black); + DrawClearQuad(RHICmdList, FLinearColor::Black); } // Reflection view late update @@ -364,7 +364,7 @@ void FScene::UpdatePlanarReflectionContents(UPlanarReflectionComponent* CaptureC }); } - const FMatrix ComponentTransform = CaptureComponent->ComponentToWorld.ToMatrixWithScale(); + const FMatrix ComponentTransform = CaptureComponent->GetComponentTransform().ToMatrixWithScale(); const FPlane MirrorPlane = FPlane(ComponentTransform.TransformPosition(FVector::ZeroVector), ComponentTransform.TransformVector(FVector(0, 0, 1))); TArray SceneCaptureViewInfo; @@ -499,7 +499,7 @@ void FScene::UpdatePlanarReflectionTransform(UPlanarReflectionComponent* Compone ENQUEUE_UNIQUE_RENDER_COMMAND_THREEPARAMETER( FUpdatePlanarReflectionCommand, FPlanarReflectionSceneProxy*,SceneProxy,Component->SceneProxy, - FMatrix,Transform,Component->ComponentToWorld.ToMatrixWithScale(), + FMatrix,Transform,Component->GetComponentTransform().ToMatrixWithScale(), FScene*,Scene,this, { Scene->ReflectionSceneData.bRegisteredReflectionCapturesHasChanged = true; @@ -537,7 +537,7 @@ public: { const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader(); FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View.ViewUniformBuffer); - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_PostProcess); PlanarReflectionParameters.SetParameters(RHICmdList, ShaderRHI, View, ReflectionSceneProxy); } @@ -601,7 +601,7 @@ bool FDeferredShadingSceneRenderer::RenderDeferredPlanarReflections(FRHICommandL if (!bSSRAsInput) { - DrawClearQuad(RHICmdList, GMaxRHIFeatureLevel, FLinearColor(0, 0, 0, 0)); + DrawClearQuad(RHICmdList, FLinearColor(0, 0, 0, 0)); } { diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessBloomSetup.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessBloomSetup.cpp index daed28e9b339..1c2d01f929ad 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessBloomSetup.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessBloomSetup.cpp @@ -287,7 +287,7 @@ void FRCPassPostProcessBloomSetup::Process(FRenderingCompositePassContext& Conte SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); // is optimized away if possible (RT size=view size, ) - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), true, FLinearColor::Black, false, 0, false, 0, DestSize, DestRect); + DrawClearQuad(Context.RHICmdList, true, FLinearColor::Black, false, 0, false, 0, DestSize, DestRect); Context.SetViewportAndCallRHI(0, 0, 0.0f, DestSize.X, DestSize.Y, 1.0f ); @@ -322,7 +322,7 @@ void FRCPassPostProcessBloomSetup::Process(FRenderingCompositePassContext& Conte SrcSize, *VertexShader, View.StereoPass, - Context.HasHmdMesh(), + false, // Disabled for correctness EDRF_UseTriangleOptimization); Context.RHICmdList.CopyToResolveTarget(DestRenderTarget.TargetableTexture, DestRenderTarget.ShaderResourceTexture, false, FResolveParams()); @@ -434,7 +434,7 @@ void FRCPassPostProcessVisualizeBloomSetup::Process(FRenderingCompositePassConte SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); // is optimized away if possible (RT size=view size, ) - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), true, FLinearColor(0, 0, 0, 0), false, 0, false, 0, DestSize, DestRect); + DrawClearQuad(Context.RHICmdList, true, FLinearColor(0, 0, 0, 0), false, 0, false, 0, DestSize, DestRect); Context.SetViewportAndCallRHI(0, 0, 0.0f, DestRect.Width(), DestRect.Height(), 1.0f ); @@ -578,7 +578,7 @@ void FRCPassPostProcessVisualizeBloomOverlay::Process(FRenderingCompositePassCon SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); // is optimized away if possible (RT size=view size, ) - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), true, FLinearColor(0, 0, 0 ,0), false, 0, false, 0, DestSize, DestRect); + DrawClearQuad(Context.RHICmdList, true, FLinearColor(0, 0, 0 ,0), false, 0, false, 0, DestSize, DestRect); Context.SetViewportAndCallRHI(0, 0, 0.0f, DestRect.Width(), DestRect.Height(), 1.0f ); diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessBokehDOF.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessBokehDOF.cpp index 1e436e619156..4f180b5301ac 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessBokehDOF.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessBokehDOF.cpp @@ -18,6 +18,7 @@ #include "PostProcess/PostProcessCircleDOF.h" #include "ClearQuad.h" #include "PipelineStateCache.h" +#include "SpriteIndexBuffer.h" const int32 GBokehDOFSetupTileSizeX = 8; const int32 GBokehDOFSetupTileSizeY = 8; @@ -50,7 +51,7 @@ public: }; /** Global Bokeh index buffer. */ -TGlobalResource< FBokehIndexBuffer > GBokehIndexBuffer; +TGlobalResource< FSpriteIndexBuffer<8> > GBokehIndexBuffer; /** Encapsulates the post processing depth of field setup pixel shader. */ class PostProcessVisualizeDOFPS : public FGlobalShader @@ -104,7 +105,7 @@ public: FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); @@ -194,7 +195,7 @@ void FRCPassPostProcessVisualizeDOF::Process(FRenderingCompositePassContext& Con // can be optimized (don't clear areas we overwrite, don't clear when full screen), // needed when a camera (matinee) has black borders or with multiple viewports // focal distance depth is stored in the alpha channel to avoid DOF artifacts - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), true, FLinearColor(0, 0, 0, View.FinalPostProcessSettings.DepthOfFieldFocalDistance), false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, DestRect); + DrawClearQuad(Context.RHICmdList, true, FLinearColor(0, 0, 0, View.FinalPostProcessSettings.DepthOfFieldFocalDistance), false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, DestRect); Context.SetViewportAndCallRHI(0, 0, 0.0f, DestSize.X, DestSize.Y, 1.0f ); @@ -401,7 +402,7 @@ public: FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); { @@ -479,7 +480,7 @@ public: const FComputeShaderRHIParamRef ShaderRHI = GetComputeShader(); FGlobalShader::SetParameters(RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); - DeferredParameters.Set(RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(RHICmdList, ShaderRHI, Context.View, MD_PostProcess); PostprocessParameter.SetCS(ShaderRHI, Context, RHICmdList, TStaticSamplerState::GetRHI()); RHICmdList.SetUAVParameter(ShaderRHI, OutComputeTex.GetBaseIndex(), DestUAV); @@ -545,7 +546,7 @@ void FRCPassPostProcessBokehDOFSetup::Process(FRenderingCompositePassContext& Co // can be optimized (don't clear areas we overwrite, don't clear when full screen), // needed when a camera (matinee) has black borders or with multiple viewports // focal distance depth is stored in the alpha channel to avoid DOF artifacts - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), true, FLinearColor(0, 0, 0, View.FinalPostProcessSettings.DepthOfFieldFocalDistance), false, 0, false, 0, DestSize, DestRect); + DrawClearQuad(Context.RHICmdList, true, FLinearColor(0, 0, 0, View.FinalPostProcessSettings.DepthOfFieldFocalDistance), false, 0, false, 0, DestSize, DestRect); Context.SetViewportAndCallRHI(0, 0, 0.0f, DestSize.X, DestSize.Y, 1.0f ); @@ -619,6 +620,8 @@ FPooledRenderTargetDesc FRCPassPostProcessBokehDOFSetup::ComputeOutputDesc(EPass Ret.DebugName = TEXT("BokehDOFSetup"); Ret.TargetableFlags &= ~(TexCreate_RenderTargetable | TexCreate_UAV); Ret.TargetableFlags |= bIsComputePass ? TexCreate_UAV : TexCreate_RenderTargetable; + Ret.Flags |= GetTextureFastVRamFlag_DynamicLayout(); + return Ret; } @@ -676,7 +679,7 @@ public: const FVertexShaderRHIParamRef ShaderRHI = GetVertexShader(); FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); PostprocessParameter.SetVS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); // PostprocessParameter.SetVS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); @@ -886,7 +889,7 @@ void FRCPassPostProcessBokehDOF::Process(FRenderingCompositePassContext& Context SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); // This clean is required to make the accumulation working - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), true, FLinearColor(0, 0, 0, 0), false, 0, false, 0, GetOutput(ePId_Output0)->RenderTargetDesc.Extent, FIntRect()); + DrawClearQuad(Context.RHICmdList, true, FLinearColor(0, 0, 0, 0), false, 0, false, 0, GetOutput(ePId_Output0)->RenderTargetDesc.Extent, FIntRect()); // we need to output to the whole rendertarget Context.SetViewportAndCallRHI(0, 0, 0.0f, PassOutputs[0].RenderTargetDesc.Extent.X, PassOutputs[0].RenderTargetDesc.Extent.Y, 1.0f); @@ -951,6 +954,7 @@ FPooledRenderTargetDesc FRCPassPostProcessBokehDOF::ComputeOutputDesc(EPassOutpu uint32 FullRes = FSceneRenderTargets::Get_FrameConstantsOnly().GetBufferSizeXY().Y; uint32 HalfRes = FMath::DivideAndRoundUp(FullRes, (uint32)2); + Ret.Flags |= GetTextureFastVRamFlag_DynamicLayout(); // we need space for the front part and the back part Ret.Extent.Y = HalfRes * 2 + SafetyBorder; Ret.DebugName = TEXT("BokehDOF"); diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessBokehDOFRecombine.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessBokehDOFRecombine.cpp index 58345fbab1e2..fb304d22339f 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessBokehDOFRecombine.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessBokehDOFRecombine.cpp @@ -14,13 +14,7 @@ #include "PostProcess/PostProcessBokehDOF.h" #include "ClearQuad.h" #include "PipelineStateCache.h" - -static TAutoConsoleVariable CVarSeparateTranslucencyUpsampleMode( - TEXT("r.SeparateTranslucencyUpsampleMode"), - 1, - TEXT("Upsample method to use on separate translucency. These are only used when r.SeparateTranslucencyScreenPercentage is less than 100.\n") - TEXT("0: bilinear 1: Nearest-Depth Neighbor (only when r.SeparateTranslucencyScreenPercentage is 50)"), - ECVF_Scalability | ECVF_Default); +#include "TranslucentRendering.h" const int32 GBokehDOFRecombineComputeTileSizeX = 8; const int32 GBokehDOFRecombineComputeTileSizeY = 8; @@ -101,7 +95,7 @@ public: const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader(); FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(Context.RHICmdList); @@ -121,20 +115,20 @@ public: if (UseNearestDepthNeighborUpsample()) { - check(SceneContext.IsSeparateTranslucencyDepthValid()); - FTextureRHIParamRef LowResDepth = SceneContext.GetSeparateTranslucencyDepthSurface(); + check(SceneContext.IsDownsampledTranslucencyDepthValid()); + FTextureRHIParamRef LowResDepth = SceneContext.GetDownsampledTranslucencyDepthSurface(); SetTextureParameter(Context.RHICmdList, ShaderRHI, LowResDepthTexture, LowResDepth); const auto& BuiltinSamplersUBParameter = GetUniformBufferParameter(); SetUniformBufferParameter(Context.RHICmdList, ShaderRHI, BuiltinSamplersUBParameter, GBuiltinSamplersUniformBuffer.GetUniformBufferRHI()); - - SetSamplerParameter(Context.RHICmdList, ShaderRHI, BilinearClampedSampler, TStaticSamplerState::GetRHI()); - SetSamplerParameter(Context.RHICmdList, ShaderRHI, PointClampedSampler, TStaticSamplerState::GetRHI()); } else { checkSlow(!LowResDepthTexture.IsBound()); } + + SetSamplerParameter(Context.RHICmdList, ShaderRHI, BilinearClampedSampler, TStaticSamplerState::GetRHI()); + SetSamplerParameter(Context.RHICmdList, ShaderRHI, PointClampedSampler, TStaticSamplerState::GetRHI()); } static const TCHAR* GetSourceFilename() @@ -248,7 +242,7 @@ public: // PS params PostprocessParameter.SetCS(ShaderRHI, Context, RHICmdList, TStaticSamplerState::GetRHI()); - DeferredParameters.Set(RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(RHICmdList, ShaderRHI, Context.View, MD_PostProcess); FIntPoint OutScaledSize; float OutScale; @@ -264,8 +258,8 @@ public: if (UseNearestDepthNeighborUpsample()) { - check(SceneContext.IsSeparateTranslucencyDepthValid()); - FTextureRHIParamRef LowResDepth = SceneContext.GetSeparateTranslucencyDepthSurface(); + check(SceneContext.IsDownsampledTranslucencyDepthValid()); + FTextureRHIParamRef LowResDepth = SceneContext.GetDownsampledTranslucencyDepthSurface(); SetTextureParameter(RHICmdList, ShaderRHI, LowResDepthTexture, LowResDepth); const auto& BuiltinSamplersUBParameter = GetUniformBufferParameter(); @@ -365,14 +359,7 @@ void FRCPassPostProcessBokehDOFRecombine::Process(FRenderingCompositePassContext check(GetInput(ePId_Input2)->GetPass()); } - FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(Context.RHICmdList); - FIntPoint OutScaledSize; - float OutScale; - SceneContext.GetSeparateTranslucencyDimensions(OutScaledSize, OutScale); - - const bool bUseNearestDepthNeighborUpsample = - CVarSeparateTranslucencyUpsampleMode.GetValueOnRenderThread() != 0 - && FMath::Abs(OutScale - .5f) < .001f; + const bool bUseNearestDepthNeighborUpsample = UseNearestDepthNeighborUpsampleForSeparateTranslucency(FSceneRenderTargets::Get(Context.RHICmdList)); if (Method != 1 && bUseNearestDepthNeighborUpsample) { @@ -441,7 +428,7 @@ void FRCPassPostProcessBokehDOFRecombine::Process(FRenderingCompositePassContext SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); // is optimized away if possible (RT size=view size, ) - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), true, FLinearColor::Black, false, 1.0f, false, 0, PassOutputs[0].RenderTargetDesc.Extent, View.ViewRect); + DrawClearQuad(Context.RHICmdList, true, FLinearColor::Black, false, 1.0f, false, 0, PassOutputs[0].RenderTargetDesc.Extent, View.ViewRect); Context.SetViewportAndCallRHI(View.ViewRect); @@ -468,7 +455,7 @@ void FRCPassPostProcessBokehDOFRecombine::Process(FRenderingCompositePassContext TexSize, *VertexShader, View.StereoPass, - Context.HasHmdMesh(), + false, // Disabled for correctness EDRF_UseTriangleOptimization); Context.RHICmdList.CopyToResolveTarget(DestRenderTarget.TargetableTexture, DestRenderTarget.ShaderResourceTexture, false, FResolveParams()); @@ -519,6 +506,7 @@ FPooledRenderTargetDesc FRCPassPostProcessBokehDOFRecombine::ComputeOutputDesc(E Ret.AutoWritable = false; Ret.DebugName = TEXT("BokehDOFRecombine"); + Ret.Flags |= GetTextureFastVRamFlag_DynamicLayout(); return Ret; } diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessCircleDOF.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessCircleDOF.cpp index 49b5fbf2e363..b75f1f81a24c 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessCircleDOF.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessCircleDOF.cpp @@ -148,7 +148,7 @@ public: PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); { FVector4 DepthOfFieldParamValues[2]; @@ -208,7 +208,7 @@ void FRCPassPostProcessCircleDOFSetup::Process(FRenderingCompositePassContext& C FLinearColor(0, 0, 0, 0) }; // is optimized away if possible (RT size=view size, ) - DrawClearQuadMRT(Context.RHICmdList, Context.GetFeatureLevel(), true, NumRenderTargets, ClearColors, false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, DestRect); + DrawClearQuadMRT(Context.RHICmdList, true, NumRenderTargets, ClearColors, false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, DestRect); Context.SetViewportAndCallRHI(0, 0, 0.0f, DestSize.X, DestSize.Y, 1.0f ); @@ -280,6 +280,8 @@ FPooledRenderTargetDesc FRCPassPostProcessCircleDOFSetup::ComputeOutputDesc(EPas Ret.TargetableFlags &= ~(uint32)TexCreate_UAV; Ret.TargetableFlags |= TexCreate_RenderTargetable; Ret.AutoWritable = false; + Ret.Flags |= GetTextureFastVRamFlag_DynamicLayout(); + if (FPostProcessing::HasAlphaChannelSupport()) { if (InPassOutputId == ePId_Output0) @@ -356,7 +358,7 @@ public: PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); { FVector4 DepthOfFieldParamValues[2]; @@ -417,7 +419,7 @@ void FRCPassPostProcessCircleDOFDilate::Process(FRenderingCompositePassContext& FLinearColor(0, 0, 0, 0) }; // is optimized away if possible (RT size=view size, ) - DrawClearQuadMRT(Context.RHICmdList, Context.GetFeatureLevel(), true, NumRenderTargets, ClearColors, false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, DestRect); + DrawClearQuadMRT(Context.RHICmdList, true, NumRenderTargets, ClearColors, false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, DestRect); Context.SetViewportAndCallRHI(0, 0, 0.0f, DestSize.X, DestSize.Y, 1.0f ); @@ -494,6 +496,7 @@ FPooledRenderTargetDesc FRCPassPostProcessCircleDOFDilate::ComputeOutputDesc(EPa // Ret.Format = PF_FloatRGBA; // we only use one channel, maybe using 4 channels would save memory as we reuse Ret.Format = PF_R16F; + Ret.Flags |= GetTextureFastVRamFlag_DynamicLayout(); return Ret; } @@ -590,7 +593,7 @@ public: } */ - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); { FVector4 DepthOfFieldParamValues[2]; @@ -698,7 +701,7 @@ void FRCPassPostProcessCircleDOF::Process(FRenderingCompositePassContext& Contex }; // is optimized away if possible (RT size=view size, ) - DrawClearQuadMRT(Context.RHICmdList, Context.GetFeatureLevel(), true, NumRenderTargets, ClearColors, false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, DestRect); + DrawClearQuadMRT(Context.RHICmdList, true, NumRenderTargets, ClearColors, false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, DestRect); Context.SetViewportAndCallRHI(0, 0, 0.0f, DestSize.X, DestSize.Y, 1.0f ); @@ -748,6 +751,7 @@ FPooledRenderTargetDesc FRCPassPostProcessCircleDOF::ComputeOutputDesc(EPassOutp Ret.Reset(); Ret.TargetableFlags &= ~(uint32)TexCreate_UAV; Ret.TargetableFlags |= TexCreate_RenderTargetable; + Ret.Flags |= GetTextureFastVRamFlag_DynamicLayout(); if (FPostProcessing::HasAlphaChannelSupport()) { @@ -824,7 +828,7 @@ public: FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); // Compute out of bounds UVs in the source texture. @@ -916,7 +920,7 @@ void FRCPassPostProcessCircleDOFRecombine::Process(FRenderingCompositePassContex SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); // is optimized away if possible (RT size=view size, ) - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), true, FLinearColor::Black, false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, View.ViewRect); + DrawClearQuad(Context.RHICmdList, true, FLinearColor::Black, false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, View.ViewRect); Context.SetViewportAndCallRHI(View.ViewRect); diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessCombineLUTs.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessCombineLUTs.cpp index 8ff99f26ffbf..d08426f0f23b 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessCombineLUTs.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessCombineLUTs.cpp @@ -1032,7 +1032,7 @@ FPooledRenderTargetDesc FRCPassPostProcessCombineLUTs::ComputeOutputDesc(EPassOu Ret.Extent = FIntPoint(GLUTSize, GLUTSize); Ret.Depth = GLUTSize; } - + Ret.Flags |= GetTextureFastVRamFlag_DynamicLayout(); Ret.DebugName = TEXT("CombineLUTs"); } diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessCompositeEditorPrimitives.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessCompositeEditorPrimitives.cpp index 54933c7892d3..88c333dd8965 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessCompositeEditorPrimitives.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessCompositeEditorPrimitives.cpp @@ -85,7 +85,7 @@ public: FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); FSamplerStateRHIRef SamplerStateRHIRef = TStaticSamplerState::GetRHI(); PostProcessParameters.SetPS(ShaderRHI, Context, SamplerStateRHIRef); @@ -243,7 +243,7 @@ void FRCPassPostProcessCompositeEditorPrimitives::Process(FRenderingCompositePas if (bClearIsNeeded) { SCOPED_DRAW_EVENT(Context.RHICmdList, ClearViewEditorPrimitives); - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), true, FLinearColor(0, 0, 0, 0), true, (float)ERHIZBuffer::FarPlane, false, 0, ColorTarget->GetSizeXY(), FIntRect()); + DrawClearQuad(Context.RHICmdList, true, FLinearColor(0, 0, 0, 0), true, (float)ERHIZBuffer::FarPlane, false, 0, ColorTarget->GetSizeXY(), FIntRect()); } SCOPED_DRAW_EVENT(Context.RHICmdList, RenderEditorPrimitives); diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessDOF.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessDOF.cpp index e4b856d70f19..f0dd8e6dc53b 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessDOF.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessDOF.cpp @@ -78,7 +78,7 @@ public: PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); } - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); { FVector4 DepthOfFieldParamValues[2]; @@ -193,7 +193,7 @@ void FRCPassPostProcessDOFSetup::Process(FRenderingCompositePassContext& Context FLinearColor(0, 0, 0, 0) }; // is optimized away if possible (RT size=view size, ) - DrawClearQuadMRT(Context.RHICmdList, Context.GetFeatureLevel(), true, NumRenderTargets, ClearColors, false, 0, false, 0, DestSize, DestRect); + DrawClearQuadMRT(Context.RHICmdList, true, NumRenderTargets, ClearColors, false, 0, false, 0, DestSize, DestRect); Context.SetViewportAndCallRHI(DestRect.Min.X, DestRect.Min.Y, 0.0f, DestRect.Max.X + 1, DestRect.Max.Y + 1, 1.0f ); @@ -337,7 +337,7 @@ public: FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState::GetRHI(), eFC_0001); // Compute out of bounds UVs in the source texture. @@ -447,7 +447,7 @@ void FRCPassPostProcessDOFRecombine::Process(FRenderingCompositePassContext& Con { SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); // is optimized away if possible (RT size=view size, ) - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), true, FLinearColor::Black, false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, View.ViewRect); + DrawClearQuad(Context.RHICmdList, true, FLinearColor::Black, false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, View.ViewRect); } Context.SetViewportAndCallRHI(View.ViewRect); diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessDownsample.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessDownsample.cpp index 6f02898078b0..7f31ab9da43a 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessDownsample.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessDownsample.cpp @@ -64,7 +64,7 @@ public: const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader(); FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); // filter only if needed for better performance FSamplerStateRHIParamRef Filter = (Method == 2) ? @@ -204,7 +204,7 @@ public: TStaticSamplerState::GetRHI(); PostprocessParameter.SetCS(ShaderRHI, Context, RHICmdList, Filter); - DeferredParameters.Set(RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(RHICmdList, ShaderRHI, Context.View, MD_PostProcess); RHICmdList.SetUAVParameter(ShaderRHI, OutComputeTex.GetBaseIndex(), DestUAV); const float PixelScale = (Method == 2) ? 0.5f : 1.0f; @@ -364,7 +364,7 @@ void FRCPassPostProcessDownsample::Process(FRenderingCompositePassContext& Conte // Set the view family's render target/viewport. SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef(), ESimpleRenderTargetMode::EExistingColorAndDepth); Context.SetViewportAndCallRHI(0, 0, 0.0f, DestSize.X, DestSize.Y, 1.0f); - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), true, FLinearColor(0, 0, 0, 0), false, 1.0f, false, 0, DestSize, DestRect); + DrawClearQuad(Context.RHICmdList, true, FLinearColor(0, 0, 0, 0), false, 1.0f, false, 0, DestSize, DestRect); } // InflateSize increases the size of the source/dest rectangle to compensate for bilinear reads and UIBlur pass requirements. @@ -443,6 +443,7 @@ FPooledRenderTargetDesc FRCPassPostProcessDownsample::ComputeOutputDesc(EPassOut Ret.TargetableFlags &= ~(TexCreate_RenderTargetable | TexCreate_UAV); Ret.TargetableFlags |= bIsComputePass ? TexCreate_UAV : TexCreate_RenderTargetable; + Ret.Flags |= GetTextureFastVRamFlag_DynamicLayout(); Ret.AutoWritable = false; Ret.DebugName = DebugName; diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessEyeAdaptation.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessEyeAdaptation.cpp index 30b555d4a313..58b3f9626d24 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessEyeAdaptation.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessEyeAdaptation.cpp @@ -461,7 +461,7 @@ void FRCPassPostProcessBasicEyeAdaptationSetUp::Process(FRenderingCompositePassC SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); // is optimized away if possible (RT size=view size, ) - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), true, FLinearColor::Black, false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, DestRect); + DrawClearQuad(Context.RHICmdList, true, FLinearColor::Black, false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, DestRect); Context.SetViewportAndCallRHI(0, 0, 0.0f, DestSize.X, DestSize.Y, 1.0f); @@ -507,6 +507,7 @@ FPooledRenderTargetDesc FRCPassPostProcessBasicEyeAdaptationSetUp::ComputeOutput Ret.DebugName = TEXT("EyeAdaptationBasicSetup"); // Require alpha channel for log2 information. Ret.Format = PF_FloatRGBA; + Ret.Flags |= GetTextureFastVRamFlag_DynamicLayout(); return Ret; } @@ -685,6 +686,6 @@ FPooledRenderTargetDesc FRCPassPostProcessBasicEyeAdaptation::ComputeOutputDesc( FPooledRenderTargetDesc Ret; Ret.DebugName = TEXT("EyeAdaptationBasic"); - + Ret.Flags |= GetTextureFastVRamFlag_DynamicLayout(); return Ret; } diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessFFTBloom.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessFFTBloom.cpp index ac889e7c38d1..dabdf5141293 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessFFTBloom.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessFFTBloom.cpp @@ -777,6 +777,12 @@ FSceneRenderTargetItem* FRCPassFFTBloom::InitDomainAndGetKernel(FRenderingCompos // The kernel parameters on the FinalPostProcess. UTexture2D* BloomConvolutionTexture = PPSettings.BloomConvolutionTexture; + + if (BloomConvolutionTexture == nullptr) + { + BloomConvolutionTexture = GEngine->DefaultBloomKernelTexture; + } + const float BloomConvolutionSize = PPSettings.BloomConvolutionSize; const FVector2D CenterUV = PPSettings.BloomConvolutionCenterUV; const float ClampedBloomConvolutionBufferScale = FMath::Clamp(PPSettings.BloomConvolutionBufferScale, 0.f, 1.f); @@ -1042,8 +1048,15 @@ FPooledRenderTargetDesc FRCPassFFTBloom::ComputeOutputDesc(EPassOutputId InPassO bool FRCPassFFTBloom::HasValidPhysicalKernel(FPostprocessContext& Context) { const FViewInfo& View = Context.View; + UTexture2D* BloomConvolutionTexture = View.FinalPostProcessSettings.BloomConvolutionTexture; + // Fall back to the default bloom texture if provided. + if (BloomConvolutionTexture == nullptr) + { + BloomConvolutionTexture = GEngine->DefaultBloomKernelTexture; + } + bool bValidSetup = (BloomConvolutionTexture != nullptr && BloomConvolutionTexture->Resource != nullptr); if (bValidSetup && BloomConvolutionTexture->IsFullyStreamedIn() == false) diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessGBufferHints.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessGBufferHints.cpp index 6563b42b607b..44804599485e 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessGBufferHints.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessGBufferHints.cpp @@ -59,7 +59,7 @@ public: FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); { FVector4 Temp[3]; diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessHMD.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessHMD.cpp index bd99ae2c48f1..217247ef8b10 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessHMD.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessHMD.cpp @@ -135,7 +135,7 @@ public: FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); } // FShader interface. @@ -181,7 +181,7 @@ void FRCPassPostProcessHMD::Process(FRenderingCompositePassContext& Context) { SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); Context.SetViewportAndCallRHI(DestRect); - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), FLinearColor::Black); + DrawClearQuad(Context.RHICmdList, FLinearColor::Black); } FGraphicsPipelineStateInitializer GraphicsPSOInit; diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessHistogram.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessHistogram.cpp index 9c148d1d31c5..31ef9c94dd16 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessHistogram.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessHistogram.cpp @@ -161,7 +161,7 @@ FPooledRenderTargetDesc FRCPassPostProcessHistogram::ComputeOutputDesc(EPassOutp // format can be optimized later FPooledRenderTargetDesc Ret(FPooledRenderTargetDesc::Create2DDesc(NewSize, PF_FloatRGBA, FClearValueBinding::None, TexCreate_None, TexCreate_RenderTargetable | TexCreate_UAV, false)); - + Ret.Flags |= GetTextureFastVRamFlag_DynamicLayout(); Ret.DebugName = TEXT("Histogram"); return Ret; diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessHistogramReduce.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessHistogramReduce.cpp index 2f0b72989813..821506cbe62b 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessHistogramReduce.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessHistogramReduce.cpp @@ -164,7 +164,7 @@ FPooledRenderTargetDesc FRCPassPostProcessHistogramReduce::ComputeOutputDesc(EPa // for quality float4 to get best quality for smooth eye adaptation transitions FPooledRenderTargetDesc Ret(FPooledRenderTargetDesc::Create2DDesc(NewSize, PF_A32B32G32R32F, FClearValueBinding::None, TexCreate_None, TexCreate_RenderTargetable, false)); - + Ret.Flags |= GetTextureFastVRamFlag_DynamicLayout(); Ret.DebugName = TEXT("HistogramReduce"); return Ret; diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessLensFlares.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessLensFlares.cpp index cf7c9a0c3d2d..0e70c20374b9 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessLensFlares.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessLensFlares.cpp @@ -166,8 +166,15 @@ void FRCPassPostProcessLensFlares::Process(FRenderingCompositePassContext& Conte // Set the view family's render target/viewport. SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); - // is optimized away if possible (RT size=view size, ) - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), true, FLinearColor::Black, false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, ViewRect1); + if (Context.HasHmdMesh() && View.StereoPass == eSSP_LEFT_EYE) + { + DrawClearQuad(Context.RHICmdList, true, FLinearColor::Black, false, 0, false, 0); + } + else + { + // is optimized away if possible (RT size=view size, ) + DrawClearQuad(Context.RHICmdList, true, FLinearColor::Black, false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, ViewRect1); + } Context.SetViewportAndCallRHI(ViewRect1); @@ -183,7 +190,7 @@ void FRCPassPostProcessLensFlares::Process(FRenderingCompositePassContext& Conte // setup background (bloom), can be implemented to use additive blending to avoid the read here if (bCompositeBloom) { - TShaderMapRef> PixelShader(Context.GetShaderMap()); + TShaderMapRef> PixelShader(Context.GetShaderMap()); GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI; GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(*VertexShader); @@ -209,7 +216,7 @@ void FRCPassPostProcessLensFlares::Process(FRenderingCompositePassContext& Conte } else { - TShaderMapRef> PixelShader(Context.GetShaderMap()); + TShaderMapRef> PixelShader(Context.GetShaderMap()); GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI; GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(*VertexShader); diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessMaterial.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessMaterial.cpp index 6e8aa888dc9a..f34c57df06c9 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessMaterial.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessMaterial.cpp @@ -239,11 +239,11 @@ void FRCPassPostProcessMaterial::Process(FRenderingCompositePassContext& Context if (Context.HasHmdMesh() && View.StereoPass == eSSP_LEFT_EYE) { // needed when using an hmd mesh instead of a full screen quad because we don't touch all of the pixels in the render target - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), FLinearColor::Black); + DrawClearQuad(Context.RHICmdList, FLinearColor::Black); } else if (ViewFamily.RenderTarget->GetRenderTargetTexture() != DestRenderTarget.TargetableTexture) { - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), true, FLinearColor::Black, false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, View.ViewRect); + DrawClearQuad(Context.RHICmdList, true, FLinearColor::Black, false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, View.ViewRect); } Context.SetViewportAndCallRHI(View.ViewRect); diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessMobile.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessMobile.cpp index 20e6d7238028..ab289c7f6c35 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessMobile.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessMobile.cpp @@ -239,7 +239,7 @@ void FRCPassPostProcessBloomSetupES2::Process(FRenderingCompositePassContext& Co else { SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), FLinearColor::Black); + DrawClearQuad(Context.RHICmdList, FLinearColor::Black); } Context.SetViewportAndCallRHI(0, 0, 0.0f, DstX, DstY, 1.0f ); @@ -454,7 +454,7 @@ void FRCPassPostProcessBloomSetupSmallES2::Process(FRenderingCompositePassContex else { SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), FLinearColor::Black); + DrawClearQuad(Context.RHICmdList, FLinearColor::Black); } Context.SetViewportAndCallRHI(0, 0, 0.0f, DstX, DstY, 1.0f ); @@ -613,7 +613,7 @@ void FRCPassPostProcessBloomDownES2::Process(FRenderingCompositePassContext& Con else { SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), FLinearColor::Black); + DrawClearQuad(Context.RHICmdList, FLinearColor::Black); } Context.SetViewportAndCallRHI(0, 0, 0.0f, DstX, DstY, 1.0f ); @@ -795,7 +795,7 @@ void FRCPassPostProcessBloomUpES2::Process(FRenderingCompositePassContext& Conte else { SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), FLinearColor::Black); + DrawClearQuad(Context.RHICmdList, FLinearColor::Black); } Context.SetViewportAndCallRHI(0, 0, 0.0f, DstX, DstY, 1.0f ); @@ -918,7 +918,7 @@ public: SunColorApertureDiv2.W = GetMobileDepthOfFieldScale(Context.View) * 0.5f; SetShaderValue(Context.RHICmdList, ShaderRHI, SunColorApertureDiv2Parameter, SunColorApertureDiv2); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); } virtual bool Serialize(FArchive& Ar) override @@ -1084,7 +1084,7 @@ void FRCPassPostProcessSunMaskES2::Process(FRenderingCompositePassContext& Conte } else { - SrcSize = InputDesc->Extent; + SrcSize = InputDesc->Extent; //-V595 // uint32 ScaleFactor = View.ViewRect.Width() / SrcSize.X; // SrcRect = View.ViewRect / ScaleFactor; // TODO: This won't work with scaled views. @@ -1102,7 +1102,7 @@ void FRCPassPostProcessSunMaskES2::Process(FRenderingCompositePassContext& Conte else { SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), FLinearColor::Black); + DrawClearQuad(Context.RHICmdList, FLinearColor::Black); } Context.SetViewportAndCallRHI(0, 0, 0.0f, DstX, DstY, 1.0f ); @@ -1305,7 +1305,7 @@ void FRCPassPostProcessSunAlphaES2::Process(FRenderingCompositePassContext& Cont else { SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), FLinearColor::Black); + DrawClearQuad(Context.RHICmdList, FLinearColor::Black); } Context.SetViewportAndCallRHI(0, 0, 0.0f, DstX, DstY, 1.0f ); @@ -1468,7 +1468,7 @@ void FRCPassPostProcessSunBlurES2::Process(FRenderingCompositePassContext& Conte else { SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), FLinearColor::Black); + DrawClearQuad(Context.RHICmdList, FLinearColor::Black); } Context.SetViewportAndCallRHI(0, 0, 0.0f, DstX, DstY, 1.0f ); @@ -1718,7 +1718,7 @@ void FRCPassPostProcessSunMergeES2::Process(FRenderingCompositePassContext& Cont else { SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), FLinearColor::Black); + DrawClearQuad(Context.RHICmdList, FLinearColor::Black); } Context.SetViewportAndCallRHI(0, 0, 0.0f, DstX, DstY, 1.0f ); @@ -1924,7 +1924,7 @@ void FRCPassPostProcessSunMergeSmallES2::Process(FRenderingCompositePassContext& else { SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), FLinearColor::Black); + DrawClearQuad(Context.RHICmdList, FLinearColor::Black); } Context.SetViewportAndCallRHI(0, 0, 0.0f, DstX, DstY, 1.0f ); @@ -2164,7 +2164,7 @@ void FRCPassPostProcessDofDownES2::Process(FRenderingCompositePassContext& Conte else { SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), FLinearColor::Black); + DrawClearQuad(Context.RHICmdList, FLinearColor::Black); } Context.SetViewportAndCallRHI(0, 0, 0.0f, DstX, DstY, 1.0f ); @@ -2367,7 +2367,7 @@ void FRCPassPostProcessDofNearES2::Process(FRenderingCompositePassContext& Conte else { SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), FLinearColor::Black); + DrawClearQuad(Context.RHICmdList, FLinearColor::Black); } Context.SetViewportAndCallRHI(0, 0, 0.0f, DstX, DstY, 1.0f ); @@ -2523,7 +2523,7 @@ void FRCPassPostProcessDofBlurES2::Process(FRenderingCompositePassContext& Conte else { SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), FLinearColor::Black); + DrawClearQuad(Context.RHICmdList, FLinearColor::Black); } Context.SetViewportAndCallRHI(0, 0, 0.0f, DstX, DstY, 1.0f ); @@ -2726,7 +2726,7 @@ void FRCPassPostProcessSunAvgES2::Process(FRenderingCompositePassContext& Contex else { SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), FLinearColor::Black); + DrawClearQuad(Context.RHICmdList, FLinearColor::Black); } Context.SetViewportAndCallRHI(0, 0, 0.0f, DstX, DstY, 1.0f ); @@ -2987,7 +2987,7 @@ void FRCPassPostProcessAaES2::Process(FRenderingCompositePassContext& Context) else { SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef(), ESimpleRenderTargetMode::EUninitializedColorAndDepth); - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), FLinearColor::Black); + DrawClearQuad(Context.RHICmdList, FLinearColor::Black); } } else diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessMorpheus.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessMorpheus.cpp index 67648301ef3e..a0cd14f7e18c 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessMorpheus.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessMorpheus.cpp @@ -94,7 +94,7 @@ public: FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); { check(GEngine->HMDDevice.IsValid()); diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessMotionBlur.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessMotionBlur.cpp index cb593e8908d2..2420aa8867ac 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessMotionBlur.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessMotionBlur.cpp @@ -18,6 +18,7 @@ #include "DeferredShadingRenderer.h" #include "ClearQuad.h" #include "PipelineStateCache.h" +#include "SpriteIndexBuffer.h" #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) static TAutoConsoleVariable CVarMotionBlurFiltering( @@ -190,6 +191,7 @@ FPooledRenderTargetDesc FRCPassPostProcessVelocityFlatten::ComputeOutputDesc(EPa Ret.Format = PF_FloatR11G11B10; Ret.TargetableFlags |= TexCreate_UAV; Ret.TargetableFlags |= TexCreate_RenderTargetable; + Ret.Flags |= GetTextureFastVRamFlag_DynamicLayout(); Ret.DebugName = TEXT("VelocityFlat"); return Ret; @@ -204,7 +206,7 @@ FPooledRenderTargetDesc FRCPassPostProcessVelocityFlatten::ComputeOutputDesc(EPa FIntPoint TileCount = GetNumTiles16x16(PixelExtent); FPooledRenderTargetDesc Ret(FPooledRenderTargetDesc::Create2DDesc(TileCount, PF_FloatRGBA, FClearValueBinding::None, TexCreate_None, TexCreate_RenderTargetable | TexCreate_UAV, false)); - + Ret.Flags |= GetTextureFastVRamFlag_DynamicLayout(); Ret.DebugName = TEXT("MaxVelocity"); return Ret; @@ -212,32 +214,7 @@ FPooledRenderTargetDesc FRCPassPostProcessVelocityFlatten::ComputeOutputDesc(EPa } -class FScatterQuadIndexBuffer : public FIndexBuffer -{ -public: - virtual void InitRHI() override - { - const uint32 Size = sizeof(uint16) * 6 * 8; - const uint32 Stride = sizeof(uint16); - FRHIResourceCreateInfo CreateInfo; - void* Buffer = nullptr; - IndexBufferRHI = RHICreateAndLockIndexBuffer( Stride, Size, BUF_Static, CreateInfo, Buffer ); - uint16* Indices = (uint16*)Buffer; - for (uint32 SpriteIndex = 0; SpriteIndex < 8; ++SpriteIndex) - { - Indices[SpriteIndex*6 + 0] = SpriteIndex*4 + 0; - Indices[SpriteIndex*6 + 1] = SpriteIndex*4 + 3; - Indices[SpriteIndex*6 + 2] = SpriteIndex*4 + 2; - Indices[SpriteIndex*6 + 3] = SpriteIndex*4 + 0; - Indices[SpriteIndex*6 + 4] = SpriteIndex*4 + 1; - Indices[SpriteIndex*6 + 5] = SpriteIndex*4 + 3; - } - RHIUnlockIndexBuffer( IndexBufferRHI ); - } -}; - -TGlobalResource< FScatterQuadIndexBuffer > GScatterQuadIndexBuffer; - +TGlobalResource< FSpriteIndexBuffer<8> > GScatterQuadIndexBuffer; class FPostProcessVelocityScatterVS : public FGlobalShader { @@ -517,6 +494,7 @@ FPooledRenderTargetDesc FRCPassPostProcessVelocityGather::ComputeOutputDesc(EPas Ret.TargetableFlags |= TexCreate_UAV; Ret.TargetableFlags |= TexCreate_RenderTargetable; + Ret.Flags |= GetTextureFastVRamFlag_DynamicLayout(); Ret.DebugName = TEXT("ScatteredMaxVelocity"); return Ret; @@ -573,7 +551,7 @@ public: FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); { bool bFiltered = false; @@ -687,7 +665,7 @@ public: SetShaderValue(RHICmdList, ShaderRHI, MotionBlurComputeParams, MotionBlurComputeValues); // PS params - DeferredParameters.Set(RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(RHICmdList, ShaderRHI, Context.View, MD_PostProcess); { bool bFiltered = false; @@ -862,7 +840,7 @@ void FRCPassPostProcessMotionBlur::Process(FRenderingCompositePassContext& Conte SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); // Is optimized away if possible (RT size=view size, ) - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), true, FLinearColor::Black, false, 0, false, 0, DestSize, SrcRect); + DrawClearQuad(Context.RHICmdList, true, FLinearColor::Black, false, 0, false, 0, DestSize, SrcRect); Context.SetViewportAndCallRHI(SrcRect); @@ -953,6 +931,7 @@ FPooledRenderTargetDesc FRCPassPostProcessMotionBlur::ComputeOutputDesc(EPassOut { Ret.Format = PF_FloatRGB; } + Ret.Flags |= GetTextureFastVRamFlag_DynamicLayout(); Ret.DebugName = TEXT("MotionBlur"); Ret.AutoWritable = false; @@ -1002,7 +981,7 @@ public: FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); SetUniformBufferParameter(Context.RHICmdList, ShaderRHI, GetUniformBufferParameter(), CreateCameraMotionParametersUniformBuffer(Context.View)); @@ -1084,7 +1063,7 @@ void FRCPassPostProcessVisualizeMotionBlur::Process(FRenderingCompositePassConte SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); // is optimized away if possible (RT size=view size, ) - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), true, FLinearColor::Black, false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, SrcRect); + DrawClearQuad(Context.RHICmdList, true, FLinearColor::Black, false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, SrcRect); Context.SetViewportAndCallRHI(SrcRect); diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessNoiseBlur.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessNoiseBlur.cpp index a7e5b6c6796c..9bc89f8d9dd5 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessNoiseBlur.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessNoiseBlur.cpp @@ -61,7 +61,7 @@ public: const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader(); FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); { @@ -151,7 +151,7 @@ void FRCPassPostProcessNoiseBlur::Process(FRenderingCompositePassContext& Contex SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); // is optimized away if possible (RT size=view size, ) - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), true, FLinearColor(0, 0, 0, 0), false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, DestRect); + DrawClearQuad(Context.RHICmdList, true, FLinearColor(0, 0, 0, 0), false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, DestRect); Context.SetViewportAndCallRHI(0, 0, 0.0f, DestSize.X, DestSize.Y, 1.0f ); diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessSelectionOutline.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessSelectionOutline.cpp index 47a6e82b0a39..0b48fac111cf 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessSelectionOutline.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessSelectionOutline.cpp @@ -111,16 +111,16 @@ void FRCPassPostProcessSelectionOutlineColor::Process(FRenderingCompositePassCon // top Context.RHICmdList.SetScissorRect(true, ViewRect.Min.X, ViewRect.Min.Y, ViewRect.Max.X, InnerRect.Min.Y); - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), false, FLinearColor(), true, (float)ERHIZBuffer::FarPlane, true, 0, PassOutputs[0].RenderTargetDesc.Extent, FIntRect()); + DrawClearQuad(Context.RHICmdList, false, FLinearColor(), true, (float)ERHIZBuffer::FarPlane, true, 0, PassOutputs[0].RenderTargetDesc.Extent, FIntRect()); // bottom Context.RHICmdList.SetScissorRect(true, ViewRect.Min.X, InnerRect.Max.Y, ViewRect.Max.X, ViewRect.Max.Y); - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), false, FLinearColor(), true, (float)ERHIZBuffer::FarPlane, true, 0, PassOutputs[0].RenderTargetDesc.Extent, FIntRect()); + DrawClearQuad(Context.RHICmdList, false, FLinearColor(), true, (float)ERHIZBuffer::FarPlane, true, 0, PassOutputs[0].RenderTargetDesc.Extent, FIntRect()); // left Context.RHICmdList.SetScissorRect(true, ViewRect.Min.X, ViewRect.Min.Y, InnerRect.Min.X, ViewRect.Max.Y); - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), false, FLinearColor(), true, (float)ERHIZBuffer::FarPlane, true, 0, PassOutputs[0].RenderTargetDesc.Extent, FIntRect()); + DrawClearQuad(Context.RHICmdList, false, FLinearColor(), true, (float)ERHIZBuffer::FarPlane, true, 0, PassOutputs[0].RenderTargetDesc.Extent, FIntRect()); // right Context.RHICmdList.SetScissorRect(true, InnerRect.Max.X, ViewRect.Min.Y, ViewRect.Max.X, ViewRect.Max.Y); - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), false, FLinearColor(), true, (float)ERHIZBuffer::FarPlane, true, 0, PassOutputs[0].RenderTargetDesc.Extent, FIntRect()); + DrawClearQuad(Context.RHICmdList, false, FLinearColor(), true, (float)ERHIZBuffer::FarPlane, true, 0, PassOutputs[0].RenderTargetDesc.Extent, FIntRect()); Context.RHICmdList.SetScissorRect(false, 0, 0, 0, 0); } @@ -217,7 +217,7 @@ public: FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); const FPostProcessSettings& Settings = Context.View.FinalPostProcessSettings; const FSceneViewFamily& ViewFamily = *(Context.View.Family); diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessSubsurface.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessSubsurface.cpp index 904d5c075a88..08399819aec2 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessSubsurface.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessSubsurface.cpp @@ -205,7 +205,7 @@ public: FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); SetTextureParameter(Context.RHICmdList, ShaderRHI, MiniFontTexture, GEngine->MiniFontTexture ? GEngine->MiniFontTexture->Resource->TextureRHI : GSystemTextures.WhiteDummy->GetRenderTargetItem().TargetableTexture); SubsurfaceParameters.SetParameters(Context.RHICmdList, ShaderRHI, Context); } @@ -290,7 +290,7 @@ void FRCPassPostProcessSubsurfaceVisualize::Process(FRenderingCompositePassConte SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); // is optimized away if possible (RT size=view size, ) - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), true, FLinearColor::Black, false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, DestRect); + DrawClearQuad(Context.RHICmdList, true, FLinearColor::Black, false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, DestRect); Context.SetViewportAndCallRHI(0, 0, 0.0f, DestSize.X, DestSize.Y, 1.0f ); @@ -342,7 +342,7 @@ void FRCPassPostProcessSubsurfaceVisualize::Process(FRenderingCompositePassConte FPooledRenderTargetDesc FRCPassPostProcessSubsurfaceVisualize::ComputeOutputDesc(EPassOutputId InPassOutputId) const { FPooledRenderTargetDesc Ret = FSceneRenderTargets::Get_FrameConstantsOnly().GetSceneColor()->GetDesc(); - + Ret.Flags &= ~(TexCreate_FastVRAM | TexCreate_Transient); Ret.Reset(); Ret.DebugName = TEXT("SubsurfaceVisualize"); // alpha is used to store depth and renormalize (alpha==0 means there is no subsurface scattering) @@ -402,7 +402,7 @@ public: FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); SubsurfaceParameters.SetParameters(Context.RHICmdList, ShaderRHI, Context); } @@ -546,7 +546,7 @@ void FRCPassPostProcessSubsurfaceSetup::Process(FRenderingCompositePassContext& FPooledRenderTargetDesc FRCPassPostProcessSubsurfaceSetup::ComputeOutputDesc(EPassOutputId InPassOutputId) const { FPooledRenderTargetDesc Ret = FSceneRenderTargets::Get_FrameConstantsOnly().GetSceneColor()->GetDesc(); - + Ret.Flags &= ~(TexCreate_FastVRAM | TexCreate_Transient); Ret.Reset(); Ret.DebugName = TEXT("SubsurfaceSetup"); // alpha is used to store depth and renormalize (alpha==0 means there is no subsurface scattering) @@ -617,7 +617,7 @@ public: const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader(); FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); if(CVarSSSFilter.GetValueOnRenderThread()) { @@ -838,7 +838,7 @@ public: const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader(); FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); SubsurfaceParameters.SetParameters(Context.RHICmdList, ShaderRHI, Context); } diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessTemporalAA.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessTemporalAA.cpp index ef328151f522..b47e7308ec4c 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessTemporalAA.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessTemporalAA.cpp @@ -117,7 +117,7 @@ public: PostprocessParameter.SetPS(ShaderRHI, Context, 0, eFC_0000, FilterTable); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); FSceneViewState* ViewState = (FSceneViewState*)Context.View.State; @@ -300,7 +300,7 @@ public: } PostprocessParameter.SetCS(ShaderRHI, Context, RHICmdList, 0, eFC_0000, FilterTable); - DeferredParameters.Set(RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(RHICmdList, ShaderRHI, Context.View, MD_PostProcess); RHICmdList.SetUAVParameter(ShaderRHI, OutComputeTex.GetBaseIndex(), DestUAV); const float ForceResponsiveFrame = Context.View.bCameraCut ? 1.f : 0.f; @@ -451,7 +451,7 @@ void FRCPassPostProcessSSRTemporalAA::Process(FRenderingCompositePassContext& Co SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); // is optimized away if possible (RT size=view size, ) - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), true, FLinearColor::Black, false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, SrcRect); + DrawClearQuad(Context.RHICmdList, true, FLinearColor::Black, false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, SrcRect); Context.SetViewportAndCallRHI(SrcRect); @@ -484,7 +484,7 @@ void FRCPassPostProcessSSRTemporalAA::Process(FRenderingCompositePassContext& Co SrcSize, *VertexShader, View.StereoPass, - Context.HasHmdMesh(), + false, // Disabled for correctness EDRF_UseTriangleOptimization); Context.RHICmdList.CopyToResolveTarget(DestRenderTarget.TargetableTexture, DestRenderTarget.ShaderResourceTexture, false, FResolveParams()); @@ -584,7 +584,7 @@ void FRCPassPostProcessDOFTemporalAA::Process(FRenderingCompositePassContext& Co SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); // is optimized away if possible (RT size=view size, ) - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), true, FLinearColor::Black, false, 0, false, 0, DestSize, SrcRect); + DrawClearQuad(Context.RHICmdList, true, FLinearColor::Black, false, 0, false, 0, DestSize, SrcRect); Context.SetViewportAndCallRHI(SrcRect); @@ -617,7 +617,7 @@ void FRCPassPostProcessDOFTemporalAA::Process(FRenderingCompositePassContext& Co SrcSize, *VertexShader, View.StereoPass, - Context.HasHmdMesh(), + false, // Disabled for correctness EDRF_UseTriangleOptimization); Context.RHICmdList.CopyToResolveTarget(DestRenderTarget.TargetableTexture, DestRenderTarget.ShaderResourceTexture, false, FResolveParams()); @@ -685,7 +685,7 @@ void FRCPassPostProcessDOFTemporalAANear::Process(FRenderingCompositePassContext SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); // is optimized away if possible (RT size=view size, ) - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), true, FLinearColor::Black, false, 0, false, 0, DestSize, SrcRect); + DrawClearQuad(Context.RHICmdList, true, FLinearColor::Black, false, 0, false, 0, DestSize, SrcRect); Context.SetViewportAndCallRHI(SrcRect); @@ -718,7 +718,7 @@ void FRCPassPostProcessDOFTemporalAANear::Process(FRenderingCompositePassContext SrcSize, *VertexShader, View.StereoPass, - Context.HasHmdMesh(), + false, // Disabled for correctness EDRF_UseTriangleOptimization); Context.RHICmdList.CopyToResolveTarget(DestRenderTarget.TargetableTexture, DestRenderTarget.ShaderResourceTexture, false, FResolveParams()); @@ -773,7 +773,7 @@ void FRCPassPostProcessLightShaftTemporalAA::Process(FRenderingCompositePassCont SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); // is optimized away if possible (RT size=view size, ) - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), true, FLinearColor::Black, false, 0, false, 0, DestSize, SrcRect); + DrawClearQuad(Context.RHICmdList, true, FLinearColor::Black, false, 0, false, 0, DestSize, SrcRect); Context.SetViewportAndCallRHI(SrcRect); @@ -806,7 +806,7 @@ void FRCPassPostProcessLightShaftTemporalAA::Process(FRenderingCompositePassCont SrcSize, *VertexShader, View.StereoPass, - Context.HasHmdMesh(), + false, // Disabled for correctness EDRF_UseTriangleOptimization); Context.RHICmdList.CopyToResolveTarget(DestRenderTarget.TargetableTexture, DestRenderTarget.ShaderResourceTexture, false, FResolveParams()); @@ -915,7 +915,7 @@ void FRCPassPostProcessTemporalAA::Process(FRenderingCompositePassContext& Conte SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, SceneContext.GetSceneDepthTexture(), ESimpleRenderTargetMode::EUninitializedColorExistingDepth, FExclusiveDepthStencil::DepthRead_StencilWrite); // is optimized away if possible (RT size=view size, ) - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), true, FLinearColor::Black, false, 0, false, 0, DestSize, SrcRect); + DrawClearQuad(Context.RHICmdList, true, FLinearColor::Black, false, 0, false, 0, DestSize, SrcRect); Context.SetViewportAndCallRHI(SrcRect); @@ -968,7 +968,7 @@ void FRCPassPostProcessTemporalAA::Process(FRenderingCompositePassContext& Conte SrcSize, *VertexShader, View.StereoPass, - Context.HasHmdMesh(), + false, // Disabled for correctness EDRF_UseTriangleOptimization); } else @@ -1021,7 +1021,7 @@ void FRCPassPostProcessTemporalAA::Process(FRenderingCompositePassContext& Conte SrcSize, *VertexShader, View.StereoPass, - Context.HasHmdMesh(), + false, // Disabled for correctness EDRF_UseTriangleOptimization); } @@ -1072,7 +1072,7 @@ void FRCPassPostProcessTemporalAA::Process(FRenderingCompositePassContext& Conte SrcSize, *VertexShader, View.StereoPass, - Context.HasHmdMesh(), + false, // Disabled for correctness EDRF_UseTriangleOptimization); } } @@ -1121,6 +1121,7 @@ void FRCPassPostProcessTemporalAA::DispatchCS(TRHICmdList& RHICmdList, FRenderin FPooledRenderTargetDesc FRCPassPostProcessTemporalAA::ComputeOutputDesc(EPassOutputId InPassOutputId) const { FPooledRenderTargetDesc Ret = GetInput(ePId_Input0)->GetOutput()->RenderTargetDesc; + Ret.Flags &= ~(TexCreate_FastVRAM | TexCreate_Transient); Ret.Reset(); //regardless of input type, PF_FloatRGBA is required to properly accumulate between frames for a good result. Ret.Format = PF_FloatRGBA; diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessTestImage.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessTestImage.cpp index edf3c279bd03..0d4365821eb7 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessTestImage.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessTestImage.cpp @@ -60,7 +60,7 @@ public: FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); { uint32 FrameNumberValue = Context.View.Family->FrameNumber; diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessTonemap.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessTonemap.cpp index f3c0f8168565..e0b753079951 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessTonemap.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessTonemap.cpp @@ -907,10 +907,12 @@ public: OutputDevice.Bind(ParameterMap, TEXT("OutputDevice")); OutputGamut.Bind(ParameterMap, TEXT("OutputGamut")); EncodeHDROutput.Bind(ParameterMap, TEXT("EncodeHDROutput")); + + EyeAdaptation.Bind(ParameterMap, TEXT("EyeAdaptation")); } template - void Set(TRHICmdList& RHICmdList, const TRHIShader ShaderRHI, const FRenderingCompositePassContext& Context, const TShaderUniformBufferParameter& BloomDirtMaskParam) + void Set(TRHICmdList& RHICmdList, const TRHIShader ShaderRHI, const FRenderingCompositePassContext& Context, const TShaderUniformBufferParameter& BloomDirtMaskParam, bool bDoEyeAdaptation = false) { const FPostProcessSettings& Settings = Context.View.FinalPostProcessSettings; const FSceneViewFamily& ViewFamily = *(Context.View.Family); @@ -1071,6 +1073,26 @@ public: SetShaderValue(RHICmdList, ShaderRHI, ColorShadow_Tint1, Constants[6]); SetShaderValue(RHICmdList, ShaderRHI, ColorShadow_Tint2, Constants[7]); } + + if(bDoEyeAdaptation) + { + // Fix for eye adaptation vertex texture read failing in Metal macOS 10.11 - If Mac should be Metal but also check lauguage version (Clone of Vertex Shader version implementation). + if (Context.View.HasValidEyeAdaptation()) + { + IPooledRenderTarget* EyeAdaptationRT = Context.View.GetEyeAdaptation(Context.RHICmdList); + FTextureRHIParamRef EyeAdaptationRTRef = EyeAdaptationRT->GetRenderTargetItem().TargetableTexture; + if (EyeAdaptationRTRef) + { + Context.RHICmdList.TransitionResources(EResourceTransitionAccess::EReadable, &EyeAdaptationRTRef, 1); + } + SetTextureParameter(RHICmdList, ShaderRHI, EyeAdaptation, EyeAdaptationRT->GetRenderTargetItem().TargetableTexture); + } + else + { + // some views don't have a state, thumbnail rendering? + SetTextureParameter(RHICmdList, ShaderRHI, EyeAdaptation, GWhiteTexture->TextureRHI); + } + } } friend FArchive& operator<<(FArchive& Ar,FPostProcessTonemapShaderParameters& P) @@ -1081,6 +1103,7 @@ public: Ar << P.ColorMatrixR_ColorCurveCd1 << P.ColorMatrixG_ColorCurveCd3Cm3 << P.ColorMatrixB_ColorCurveCm2 << P.ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3 << P.ColorCurve_Ch1_Ch2 << P.ColorShadow_Luma << P.ColorShadow_Tint1 << P.ColorShadow_Tint2; Ar << P.OverlayColor; Ar << P.OutputDevice << P.OutputGamut << P.EncodeHDROutput; + Ar << P.EyeAdaptation; return Ar; } @@ -1111,19 +1134,31 @@ public: FShaderParameter OutputDevice; FShaderParameter OutputGamut; FShaderParameter EncodeHDROutput; + + //Fix for eye adaptation vertex texture read failing in Metal macOS 10.11 + FShaderResourceParameter EyeAdaptation; +}; + +namespace PostProcessTonemapUtil +{ + // Function exists out side of the FPostProcessTonemapPS class - otherwise calling it would require template parameters + static inline bool PlatformRequiresEyeAdaptationPSSampling(EShaderPlatform ShaderPlatform) + { + return IsMetalPlatform(ShaderPlatform) && RHIGetShaderLanguageVersion(ShaderPlatform) < 2; + } }; /** * Encapsulates the post processing tonemapper pixel shader. */ -template +template class FPostProcessTonemapPS : public FGlobalShader { DECLARE_SHADER_TYPE(FPostProcessTonemapPS, Global); static bool ShouldCache(EShaderPlatform Platform) { - return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::ES2); + return (IsFeatureLevelSupported(Platform, ERHIFeatureLevel::ES2) && (!bDoEyeAdaptation || PostProcessTonemapUtil::PlatformRequiresEyeAdaptationPSSampling(Platform))); } static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment) @@ -1144,6 +1179,8 @@ class FPostProcessTonemapPS : public FGlobalShader OutEnvironment.SetDefine(TEXT("USE_COLOR_FRINGE"), TonemapperIsDefined(ConfigBitmask, TonemapperColorFringe)); OutEnvironment.SetDefine(TEXT("USE_SHARPEN"), TonemapperIsDefined(ConfigBitmask, TonemapperSharpen)); OutEnvironment.SetDefine(TEXT("USE_VOLUME_LUT"), UseVolumeTextureLUT(Platform)); + + OutEnvironment.SetDefine(TEXT("EYEADAPTATION_EXPOSURE_FIX"), bDoEyeAdaptation ? 1 : 0); } /** Default constructor. */ @@ -1189,7 +1226,7 @@ public: PostprocessParameter.SetPS(ShaderRHI, Context, 0, eFC_0000, Filters); } - PostProcessTonemapShaderParameters.Set(Context.RHICmdList, ShaderRHI, Context, GetUniformBufferParameter()); + PostProcessTonemapShaderParameters.Set(Context.RHICmdList, ShaderRHI, Context, GetUniformBufferParameter(), bDoEyeAdaptation); } static const TCHAR* GetSourceFilename() @@ -1203,9 +1240,11 @@ public: } }; -// #define avoids a lot of code duplication -#define VARIATION1(A) typedef FPostProcessTonemapPS FPostProcessTonemapPS##A; \ - IMPLEMENT_SHADER_TYPE2(FPostProcessTonemapPS##A, SF_Pixel); +#define VARIATION1(A) \ + typedef FPostProcessTonemapPS FPostProcessTonemapPS_EyeAdaptation##A; \ + IMPLEMENT_SHADER_TYPE2(FPostProcessTonemapPS_EyeAdaptation##A, SF_Pixel); \ + typedef FPostProcessTonemapPS FPostProcessTonemapPS_NoEyeAdaptation##A; \ + IMPLEMENT_SHADER_TYPE2(FPostProcessTonemapPS_NoEyeAdaptation##A, SF_Pixel); VARIATION1(0) VARIATION1(1) VARIATION1(2) VARIATION1(3) VARIATION1(4) VARIATION1(5) VARIATION1(6) VARIATION1(7) VARIATION1(8) VARIATION1(9) VARIATION1(10) VARIATION1(11) VARIATION1(12) VARIATION1(13) VARIATION1(14) @@ -1424,7 +1463,7 @@ FRCPassPostProcessTonemap::FRCPassPostProcessTonemap(const FViewInfo& InView, bo namespace PostProcessTonemapUtil { // Template implementation supports unique static BoundShaderState for each permutation of Vertex/Pixel Shaders - template + template static inline void SetShaderTempl(const FRenderingCompositePassContext& Context) { FGraphicsPipelineStateInitializer GraphicsPSOInit; @@ -1433,8 +1472,8 @@ namespace PostProcessTonemapUtil GraphicsPSOInit.RasterizerState = TStaticRasterizerState<>::GetRHI(); GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState::GetRHI(); - typedef TPostProcessTonemapVS VertexShaderType; - typedef FPostProcessTonemapPS PixelShaderType; + typedef TPostProcessTonemapVS VertexShaderType; + typedef FPostProcessTonemapPS PixelShaderType; TShaderMapRef PixelShader(Context.GetShaderMap()); TShaderMapRef VertexShader(Context.GetShaderMap()); @@ -1455,11 +1494,18 @@ namespace PostProcessTonemapUtil { if (bDoEyeAdaptation) { - SetShaderTempl(Context); + if (PlatformRequiresEyeAdaptationPSSampling(Context.GetShaderPlatform())) + { + SetShaderTempl(Context); + } + else + { + SetShaderTempl(Context); + } } else { - SetShaderTempl(Context); + SetShaderTempl(Context); } } @@ -1573,12 +1619,12 @@ void FRCPassPostProcessTonemap::Process(FRenderingCompositePassContext& Context) if (Context.HasHmdMesh() && View.StereoPass == eSSP_LEFT_EYE) { // needed when using an hmd mesh instead of a full screen quad because we don't touch all of the pixels in the render target - DrawClearQuad(Context.RHICmdList, GMaxRHIFeatureLevel, FLinearColor::Black); + DrawClearQuad(Context.RHICmdList, FLinearColor::Black); } else if (ViewFamily.RenderTarget->GetRenderTargetTexture() != DestRenderTarget.TargetableTexture) { // needed to not have PostProcessAA leaking in content (e.g. Matinee black borders), is optimized away if possible (RT size=view size, ) - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), true, FLinearColor::Black, false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, DestRect); + DrawClearQuad(Context.RHICmdList, true, FLinearColor::Black, false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, DestRect); } } @@ -1695,6 +1741,7 @@ FPooledRenderTargetDesc FRCPassPostProcessTonemap::ComputeOutputDesc(EPassOutput Ret.Format = bHDROutput ? GRHIHDRDisplayOutputFormat : Ret.Format; Ret.DebugName = TEXT("Tonemap"); Ret.ClearValue = FClearValueBinding(FLinearColor(0, 0, 0, 0)); + Ret.Flags |= GetTextureFastVRamFlag_DynamicLayout(); // Mobile needs to override the extent if (bDoScreenPercentageInTonemapper && View.GetFeatureLevel() <= ERHIFeatureLevel::ES3_1) @@ -2064,7 +2111,7 @@ void FRCPassPostProcessTonemapES2::Process(FRenderingCompositePassContext& Conte // Full clear to avoid restore if ((View.StereoPass == eSSP_FULL && bFirstView) || View.StereoPass == eSSP_LEFT_EYE) { - DrawClearQuad(Context.RHICmdList, GMaxRHIFeatureLevel, FLinearColor::Black); + DrawClearQuad(Context.RHICmdList, FLinearColor::Black); } } diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessTonemap.h b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessTonemap.h index 4d0a0061316d..60e4ca69e2d1 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessTonemap.h +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessTonemap.h @@ -94,6 +94,7 @@ public: virtual FPooledRenderTargetDesc ComputeOutputDesc(EPassOutputId InPassOutputId) const override; bool bDoScreenPercentageInTonemapper; + private: const FViewInfo& View; diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessUpscale.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessUpscale.cpp index 77bd55ca4c1c..aa8a2aaa13e8 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessUpscale.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessUpscale.cpp @@ -186,7 +186,7 @@ public: FilterTable[1] = TStaticSamplerState::GetRHI(); PostprocessParameter.SetPS(ShaderRHI, Context, 0, eFC_0000, FilterTable); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); { float UpscaleSoftnessValue = FMath::Clamp(CVarUpscaleSoftness.GetValueOnRenderThread(), 0.0f, 1.0f); @@ -327,7 +327,7 @@ void FRCPassPostProcessUpscale::Process(FRenderingCompositePassContext& Context) Context.SetViewportAndCallRHI(DestRect); if (View.StereoPass == eSSP_FULL || View.StereoPass == eSSP_LEFT_EYE) { - DrawClearQuad(Context.RHICmdList, Context.GetFeatureLevel(), true, FLinearColor::Black, false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, ExcludeRect); + DrawClearQuad(Context.RHICmdList, true, FLinearColor::Black, false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, ExcludeRect); } FShader* VertexShader = 0; @@ -385,6 +385,7 @@ FPooledRenderTargetDesc FRCPassPostProcessUpscale::ComputeOutputDesc(EPassOutput Ret.Reset(); Ret.DebugName = TEXT("Upscale"); Ret.Extent = OutputExtent; + Ret.Flags |= GetTextureFastVRamFlag_DynamicLayout(); return Ret; } diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessVisualizeBuffer.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessVisualizeBuffer.cpp index 4818bebfa32f..16a5e730c2ed 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessVisualizeBuffer.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessVisualizeBuffer.cpp @@ -61,7 +61,7 @@ public: FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); } void SetSourceTexture(FRHICommandList& RHICmdList, FTextureRHIRef Texture) diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessWeightedSampleSum.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessWeightedSampleSum.cpp index 05ceab0d979a..03a898685a5f 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessWeightedSampleSum.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessWeightedSampleSum.cpp @@ -791,7 +791,7 @@ void FRCPassPostProcessWeightedSampleSum::Process(FRenderingCompositePassContext } // in texel (input resolution), /2 as we use the diameter, 100 as we use percent - float EffectiveBlurRadius = SizeScale * SrcSizeForThisAxis / 2 / 100.0f; + float EffectiveBlurRadius = SizeScale * SrcSizeForThisAxis / 2 / 100.0f; // compute 1D filtered samples FVector2D BlurOffsets[MAX_FILTER_SAMPLES]; @@ -815,7 +815,7 @@ void FRCPassPostProcessWeightedSampleSum::Process(FRenderingCompositePassContext { float YOffset = bDoFastBlur ? (InvSrcSize.Y * 0.5f) : 0.0f; for (uint32 i = 0; i < NumSamples; ++i) - { + { BlurOffsets[i] = FVector2D(InvSrcSize.X * OffsetAndWeight[i].X, YOffset); } } @@ -825,7 +825,7 @@ void FRCPassPostProcessWeightedSampleSum::Process(FRenderingCompositePassContext for (uint32 i = 0; i < NumSamples; ++i) { BlurOffsets[i] = FVector2D(0, InvSrcSize.Y * OffsetAndWeight[i].X + YOffset); - } + } } uint32 CombineMethodInt = (CombineMethod == EFCM_MaxMagnitude) ? 2 : 0; @@ -862,7 +862,7 @@ void FRCPassPostProcessWeightedSampleSum::Process(FRenderingCompositePassContext { // Async path FRHIAsyncComputeCommandListImmediate& RHICmdListComputeImmediate = FRHICommandListExecutor::GetImmediateAsyncComputeCommandList(); - { + { SCOPED_COMPUTE_EVENT(RHICmdListComputeImmediate, AsyncWeightedSampleSum); WaitForInputPassComputeFences(RHICmdListComputeImmediate); @@ -899,7 +899,7 @@ void FRCPassPostProcessWeightedSampleSum::Process(FRenderingCompositePassContext else { SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef(), ESimpleRenderTargetMode::EExistingColorAndDepth); - } + } Context.SetViewportAndCallRHI(0, 0, 0.0f, DestSize.X, DestSize.Y, 1.0f); @@ -910,23 +910,23 @@ void FRCPassPostProcessWeightedSampleSum::Process(FRenderingCompositePassContext } - FShader* VertexShader = nullptr; - SetFilterShaders( - Context.RHICmdList, - FeatureLevel, - TStaticSamplerState::GetRHI(), - FilterTexture, - AdditiveTexture, - CombineMethodInt, - BlurOffsets, - BlurWeights, - NumSamples, - &VertexShader - ); + FShader* VertexShader = nullptr; + SetFilterShaders( + Context.RHICmdList, + FeatureLevel, + TStaticSamplerState::GetRHI(), + FilterTexture, + AdditiveTexture, + CombineMethodInt, + BlurOffsets, + BlurWeights, + NumSamples, + &VertexShader + ); - DrawQuad(Context.RHICmdList, FeatureLevel, bDoFastBlur, SrcRect, DestRect, DestSize, SrcSize, VertexShader); + DrawQuad(Context.RHICmdList, FeatureLevel, bDoFastBlur, SrcRect, DestRect, DestSize, SrcSize, VertexShader); - Context.RHICmdList.CopyToResolveTarget(DestRenderTarget.TargetableTexture, DestRenderTarget.ShaderResourceTexture, false, FResolveParams()); + Context.RHICmdList.CopyToResolveTarget(DestRenderTarget.TargetableTexture, DestRenderTarget.ShaderResourceTexture, false, FResolveParams()); } } @@ -1043,7 +1043,7 @@ FPooledRenderTargetDesc FRCPassPostProcessWeightedSampleSum::ComputeOutputDesc(E Ret.AutoWritable = false; Ret.TargetableFlags &= ~(TexCreate_RenderTargetable | TexCreate_UAV); Ret.TargetableFlags |= bIsComputePass ? TexCreate_UAV : TexCreate_RenderTargetable; - + Ret.Flags &= ~TexCreate_FastVRAM; Ret.ClearValue = FClearValueBinding(FLinearColor(0, 0, 0, 0)); return Ret; @@ -1129,7 +1129,7 @@ void FRCPassPostProcessWeightedSampleSum::DrawClear(FRHICommandListImmediate& RH AdjustRectsForFastBlur(SrcRect, DestRect); } - DrawClearQuad(RHICmdList, FeatureLevel, true, FLinearColor(0, 0, 0, 0), false, 1.0f, false, 0, DestSize, DestRect); + DrawClearQuad(RHICmdList, true, FLinearColor(0, 0, 0, 0), false, 1.0f, false, 0, DestSize, DestRect); } void FRCPassPostProcessWeightedSampleSum::DrawQuad(FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, bool bDoFastBlur, FIntRect SrcRect, FIntRect DestRect, FIntPoint DestSize, FIntPoint SrcSize, FShader* VertexShader) const diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessing.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessing.cpp index 13869c513e31..2b0c3df3cb41 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessing.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessing.cpp @@ -719,8 +719,7 @@ static FRenderingCompositeOutputRef AddBloom(FBloomDownSampleArray& BloomDownSam // Extract the Context FPostprocessContext& Context = BloomDownSampleArray.Context; - const bool bUseFFTBloom = (Context.View.FinalPostProcessSettings.BloomConvolutionTexture != nullptr - && Context.View.FinalPostProcessSettings.BloomMethod == EBloomMethod::BM_FFT + const bool bUseFFTBloom = (Context.View.FinalPostProcessSettings.BloomMethod == EBloomMethod::BM_FFT && Context.View.FeatureLevel >= ERHIFeatureLevel::SM5); // Extract the downsample array. @@ -805,6 +804,7 @@ static FRenderingCompositeOutputRef AddBloom(FBloomDownSampleArray& BloomDownSam // Only bloom this down-sampled input if the bloom size is non-zero if (Op.BloomSize > SMALL_NUMBER) { + BloomOutput = RenderBloom(Context, PostProcessDownsamples[SourceIndex], Op.BloomSize * Settings.BloomSizeScale, Tint, BloomOutput); } } @@ -814,7 +814,6 @@ static FRenderingCompositeOutputRef AddBloom(FBloomDownSampleArray& BloomDownSam // Bloom was disabled by setting bloom size to zero in the post process. // No bloom, provide substitute source for lens flare. BloomOutput = PostProcessDownsamples[0]; - } } @@ -2161,8 +2160,9 @@ void FPostProcessing::ProcessES2(FRHICommandListImmediate& RHICmdList, const FVi // add the passes we want to add to the graph (commenting a line means the pass is not inserted into the graph) --------- if( View.Family->EngineShowFlags.PostProcessing ) { - bool bUseMosaic = IsMobileHDRMosaic(); - bool bUseEncodedHDR = bMobileHDR32bpp && !bUseMosaic; + const EMobileHDRMode HDRMode = GetMobileHDRMode(); + bool bUseEncodedHDR = HDRMode == EMobileHDRMode::EnabledRGBE; + bool bHDRModeAllowsPost = bUseEncodedHDR || HDRMode == EMobileHDRMode::EnabledFloat16; bool bUseSun = !bUseEncodedHDR && View.bLightShaftUse; bool bUseDof = !bUseEncodedHDR && GetMobileDepthOfFieldScale(View) > 0.0f && !Context.View.Family->EngineShowFlags.VisualizeDOF; @@ -2181,7 +2181,7 @@ void FPostProcessing::ProcessES2(FRHICommandListImmediate& RHICmdList, const FVi bool bUsePost = bUseSun | bUseDof | bUseBloom | bUseVignette; // Post is not supported on ES2 devices using mosaic. - bUsePost &= !bUseMosaic; + bUsePost &= bHDRModeAllowsPost; bUsePost &= IsMobileHDR(); if(bUsePost) @@ -2434,6 +2434,7 @@ void FPostProcessing::ProcessES2(FRHICommandListImmediate& RHICmdList, const FVi static const auto VarTonemapperFilm = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.Mobile.TonemapperFilm")); const bool bUseTonemapperFilm = IsMobileHDR() && !bMobileHDR32bpp && GSupportsRenderTargetFormat_PF_FloatRGBA && (VarTonemapperFilm && VarTonemapperFilm->GetValueOnRenderThread()); + static const auto VarTonemapperUpscale = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.MobileTonemapperUpscale")); bool bDisableUpscaleInTonemapper = Context.View.Family->bUseSeparateRenderTarget || IsMobileHDRMosaic() || !VarTonemapperUpscale || VarTonemapperUpscale->GetValueOnRenderThread() == 0; @@ -2473,7 +2474,7 @@ void FPostProcessing::ProcessES2(FRHICommandListImmediate& RHICmdList, const FVi bDisableUpscaleInTonemapper = true; } } - + if (bUseAa) { // Double buffer post output. diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/RenderTargetPool.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/RenderTargetPool.cpp index 6d049dd468e1..f857bd46cffe 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/RenderTargetPool.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/RenderTargetPool.cpp @@ -71,6 +71,15 @@ static TAutoConsoleVariable CVarRenderTargetPoolTest( ECVF_Cheat | ECVF_RenderThreadSafe); #endif +static TAutoConsoleVariable CVarAllowMultipleAliasingDiscardsPerFrame( + TEXT("r.RenderTargetPool.AllowMultipleAliasingDiscardsPerFrame"), + 0, + TEXT("If enabled, allows rendertargets to be discarded and reacquired in the same frame.\n") + TEXT("This should give better aliasing efficiency, but carries some RHIthread/GPU performance overhead\n") + TEXT("with some RHIs (due to additional commandlist flushes)\n") + TEXT(" 0:off (default), 1:on"), + ECVF_Cheat | ECVF_RenderThreadSafe); + bool FRenderTargetPool::IsEventRecordingEnabled() const { #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) @@ -127,45 +136,6 @@ FRenderTargetPool::FRenderTargetPool() { } -static void LogVRamUsage(FPooledRenderTarget& Ref, FTextureRHIParamRef TexRef) -{ - if(FPlatformProperties::SupportsFastVRAMMemory() && TexRef) - { - FRHIResourceInfo Info; - - RHIGetResourceInfo(TexRef, Info); - - if(Info.VRamAllocation.AllocationSize) - { - // note we do KB for more readable numbers but this can cause quantization loss - UE_LOG(LogShaders, Log, TEXT(" VRamInKB(Start/Size):%d/%d %s '%s'"), - Info.VRamAllocation.AllocationStart / 1024, - (Info.VRamAllocation.AllocationSize + 1023) / 1024, - *Ref.GetDesc().GenerateInfoString(), - Ref.GetDesc().DebugName); - } - else - { - UE_LOG(LogShaders, Log, TEXT(" VRamInKB request failed %s '%s'"), - *Ref.GetDesc().GenerateInfoString(), - Ref.GetDesc().DebugName); - } - } -} - -static void LogVRamUsage(FPooledRenderTarget& Ref) -{ - if(Ref.GetDesc().Flags & TexCreate_FastVRAM) - { - LogVRamUsage(Ref, Ref.GetRenderTargetItem().TargetableTexture); - - if(Ref.GetRenderTargetItem().TargetableTexture != Ref.GetRenderTargetItem().ShaderResourceTexture) - { - LogVRamUsage(Ref, Ref.GetRenderTargetItem().ShaderResourceTexture); - } - } -} - void FRenderTargetPool::TransitionTargetsWritable(FRHICommandListImmediate& RHICmdList) { QUICK_SCOPE_CYCLE_COUNTER(STAT_RenderTargetPoolTransition); @@ -190,7 +160,7 @@ void FRenderTargetPool::TransitionTargetsWritable(FRHICommandListImmediate& RHIC if (TransitionTargets.Num() > 0) { RHICmdList.TransitionResourceArrayNoCopy(EResourceTransitionAccess::EWritable, TransitionTargets); - if (GRHIThread) + if (IsRunningRHIInSeparateThread()) { TransitionFence = RHICmdList.RHIThreadFence(false); } @@ -211,16 +181,47 @@ void FRenderTargetPool::WaitForTransitionFence() DeferredDeleteArray.Reset(); } -bool FRenderTargetPool::FindFreeElement(FRHICommandList& RHICmdList, const FPooledRenderTargetDesc& Desc, TRefCountPtr &Out, const TCHAR* InDebugName, bool bDoWritableBarrier) +bool FRenderTargetPool::FindFreeElement(FRHICommandList& RHICmdList, const FPooledRenderTargetDesc& InputDesc, TRefCountPtr &Out, const TCHAR* InDebugName, bool bDoWritableBarrier) { check(IsInRenderingThread()); - if(!Desc.IsValid()) + if(!InputDesc.IsValid()) { // no need to do anything return true; } + // If we're doing aliasing, we may need to override Transient flags, depending on the input format and mode + int32 AliasingMode = CVarTransientResourceAliasing_RenderTargets.GetValueOnRenderThread(); + FPooledRenderTargetDesc ModifiedDesc; + bool bModifyDesc = false; + if (GSupportsTransientResourceAliasing && AliasingMode > 0 ) + { + // Only override if the flags aren't already transient (this avoids a copy) + if ((InputDesc.Flags & TexCreate_Transient) == 0) + { + if (AliasingMode == 1) + { + // Mode 1: Make FastVRAM rendertargets transient + if (InputDesc.Flags & TexCreate_FastVRAM) + { + ModifiedDesc = InputDesc; + ModifiedDesc.Flags |= TexCreate_Transient; + bModifyDesc = true; + } + } + else if (AliasingMode == 2) + { + // Mode 2: Make all rendertargets transient + ModifiedDesc = InputDesc; + ModifiedDesc.Flags |= TexCreate_Transient; + bModifyDesc = true; + } + } + } + + const FPooledRenderTargetDesc& Desc = bModifyDesc ? ModifiedDesc : InputDesc; + // Make sure if requesting a depth format that the clear value is correct ensure(!IsDepthOrStencilFormat(Desc.Format) || (Desc.ClearValue.ColorBinding == EClearBinding::ENoneBound || Desc.ClearValue.ColorBinding == EClearBinding::EDepthStencilBound)); @@ -268,30 +269,37 @@ bool FRenderTargetPool::FindFreeElement(FRHICommandList& RHICmdList, const FPool // try to find a suitable element in the pool { //don't spend time doing 2 passes if the platform doesn't support fastvram - uint32 PassCount = ((Desc.Flags & TexCreate_FastVRAM) && FPlatformProperties::SupportsFastVRAMMemory()) ? 2 : 1; + uint32 PassCount = 1; + if (AliasingMode == 0) + { + if ((Desc.Flags & TexCreate_FastVRAM) && FPlatformMemory::SupportsFastVRAMMemory() ) + { + PassCount = 2; + } + } + bool bAllowMultipleDiscards = ( CVarAllowMultipleAliasingDiscardsPerFrame.GetValueOnRenderThread() != 0 ); // first we try exact, if that fails we try without TexCreate_FastVRAM // (easily we can run out of VRam, if this search becomes a performance problem we can optimize or we should use less TexCreate_FastVRAM) for(uint32 Pass = 0; Pass < PassCount; ++Pass) { bool bExactMatch = (Pass == 0); - + for(uint32 i = 0, Num = (uint32)PooledRenderTargets.Num(); i < Num; ++i) { FPooledRenderTarget* Element = PooledRenderTargets[i]; - + if(Element && Element->IsFree() && Element->GetDesc().Compare(Desc, bExactMatch)) { + if ( ( Desc.Flags & TexCreate_Transient ) && bAllowMultipleDiscards == false && Element->HasBeenDiscardedThisFrame() ) + { + // We can't re-use transient resources if they've already been discarded this frame + continue; + } check(!Element->IsSnapshot()); Found = Element; FoundIndex = i; bReusingExistingTarget = true; - if (Element->RenderTargetItem.TargetableTexture) - { - FRHICommandListImmediate& RHICmdListImmediate = FRHICommandListExecutor::GetImmediateCommandList(); - FTextureRHIParamRef Texture = Element->RenderTargetItem.TargetableTexture; - RHICmdListImmediate.SetResourceAliasability(EResourceAliasability::EUnaliasable, &Texture, 1); - } goto Done; } } @@ -304,14 +312,17 @@ Done: UE_LOG(LogRenderTargetPool, Display, TEXT("%d MB, NewRT %s %s"), (AllocationLevelInKB + 1023) / 1024, *Desc.GenerateInfoString(), InDebugName); // not found in the pool, create a new element - Found = new FPooledRenderTarget(Desc); + Found = new FPooledRenderTarget(Desc, this); PooledRenderTargets.Add(Found); // TexCreate_UAV should be used on Desc.TargetableFlags check(!(Desc.Flags & TexCreate_UAV)); + // TexCreate_FastVRAM should be used on Desc.Flags + ensure(!(Desc.TargetableFlags & TexCreate_FastVRAM)); FRHIResourceCreateInfo CreateInfo(Desc.ClearValue); + CreateInfo.DebugName = InDebugName; if(Desc.TargetableFlags & (TexCreate_RenderTargetable | TexCreate_DepthStencilTargetable | TexCreate_UAV)) { @@ -480,10 +491,7 @@ Done: FoundIndex = PooledRenderTargets.Num() - 1; - // done twice but it doesn't hurt an LogVRamUsage gets the new name this way Found->Desc.DebugName = InDebugName; - - LogVRamUsage(*Found); } #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) @@ -494,17 +502,17 @@ Done: if(Found->GetDesc().TargetableFlags & TexCreate_RenderTargetable) { SetRenderTarget(RHICmdList, Found->RenderTargetItem.TargetableTexture, FTextureRHIRef()); - DrawClearQuad(RHICmdList, GMaxRHIFeatureLevel, FLinearColor(1000, 1000, 1000, 1000)); + DrawClearQuad(RHICmdList, FLinearColor(1000, 1000, 1000, 1000)); } else if(Found->GetDesc().TargetableFlags & TexCreate_UAV) { - ClearUAV(RHICmdList, GMaxRHIFeatureLevel, Found->RenderTargetItem, FLinearColor(1000, 1000, 1000, 1000)); + ClearUAV(RHICmdList, Found->RenderTargetItem, FLinearColor(1000, 1000, 1000, 1000)); } if(Desc.TargetableFlags & TexCreate_DepthStencilTargetable) { SetRenderTarget(RHICmdList, FTextureRHIRef(), Found->RenderTargetItem.TargetableTexture); - DrawClearQuad(RHICmdList, GMaxRHIFeatureLevel, false, FLinearColor::Black, true, 0, false, 0); + DrawClearQuad(RHICmdList, false, FLinearColor::Black, true, 0.0f, true, 0); } } } @@ -518,15 +526,28 @@ Done: AddAllocEvent(FoundIndex, Found); + uint32 OriginalNumRefs = Found->GetRefCount(); + // assign to the reference counted variable Out = Found; check(!Found->IsFree()); - if (bReusingExistingTarget && bDoWritableBarrier) + // Only referenced by the pool, map the physical pages + if (OriginalNumRefs == 1 && Found->GetRenderTargetItem().TargetableTexture != nullptr) + { + RHIAcquireTransientResource(Found->GetRenderTargetItem().TargetableTexture); + } + + if (bReusingExistingTarget) + { + if (bDoWritableBarrier) { RHICmdList.TransitionResource(EResourceTransitionAccess::EWritable, Found->GetRenderTargetItem().TargetableTexture); } + + } + return false; } @@ -537,7 +558,7 @@ void FRenderTargetPool::CreateUntrackedElement(const FPooledRenderTargetDesc& De Out = 0; // not found in the pool, create a new element - FPooledRenderTarget* Found = new FPooledRenderTarget(Desc); + FPooledRenderTarget* Found = new FPooledRenderTarget(Desc, NULL); Found->RenderTargetItem = Item; check(!Found->IsSnapshot()); @@ -1329,7 +1350,7 @@ uint32 FPooledRenderTarget::AddRef() const return 1; } -uint32 FPooledRenderTarget::Release() const +uint32 FPooledRenderTarget::Release() { if (!bSnapshot) { @@ -1337,20 +1358,14 @@ uint32 FPooledRenderTarget::Release() const uint32 Refs = uint32(--NumRefs); if(Refs == 0) { - // better we remove const from Release() - FSceneRenderTargetItem& NonConstItem = (FSceneRenderTargetItem&)RenderTargetItem; - - NonConstItem.SafeRelease(); + RenderTargetItem.SafeRelease(); delete this; } - else if (IsFree() && GIsRHIInitialized) + else if (Refs == 1 && RenderTargetPool && IsTransient() ) { - FRHICommandListImmediate& RHICmdList = FRHICommandListExecutor::GetImmediateCommandList(); - if (RenderTargetItem.TargetableTexture) - { - FTextureRHIParamRef Texture = RenderTargetItem.TargetableTexture; - RHICmdList.SetResourceAliasability(EResourceAliasability::EAliasable, &Texture, 1); - } + // Discard the resource + RHIDiscardTransientResource( GetRenderTargetItem().TargetableTexture ); + FrameNumberLastDiscard = GFrameNumberRenderThread; } return Refs; } @@ -1398,7 +1413,6 @@ void FRenderTargetPool::DestructSnapshots() PooledRenderTargetSnapshots.Reset(); } - // for debugging purpose FPooledRenderTarget* FRenderTargetPool::GetElementById(uint32 Id) const { diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/RenderTargetPool.h b/Engine/Source/Runtime/Renderer/Private/PostProcess/RenderTargetPool.h index 029b1d70b6d3..2b79ac098b71 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/RenderTargetPool.h +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/RenderTargetPool.h @@ -17,11 +17,13 @@ class FViewInfo; /** The reference to a pooled render target, use like this: TRefCountPtr */ struct FPooledRenderTarget : public IPooledRenderTarget { - FPooledRenderTarget(const FPooledRenderTargetDesc& InDesc) + FPooledRenderTarget(const FPooledRenderTargetDesc& InDesc, class FRenderTargetPool* InRenderTargetPool) : NumRefs(0) , UnusedForNFrames(0) , Desc(InDesc) , bSnapshot(false) + , RenderTargetPool(InRenderTargetPool) + , FrameNumberLastDiscard(-1) { } /* Constructor that makes a snapshot */ @@ -30,6 +32,8 @@ struct FPooledRenderTarget : public IPooledRenderTarget , UnusedForNFrames(0) , Desc(SnaphotSource.Desc) , bSnapshot(true) + , RenderTargetPool(SnaphotSource.RenderTargetPool) + , FrameNumberLastDiscard(-1) { check(IsInRenderingThread()); RenderTargetItem = SnaphotSource.RenderTargetItem; @@ -55,9 +59,17 @@ struct FPooledRenderTarget : public IPooledRenderTarget // interface IPooledRenderTarget -------------- virtual uint32 AddRef() const override final; - virtual uint32 Release() const override final; + virtual uint32 Release() override final; virtual uint32 GetRefCount() const override final; virtual bool IsFree() const override final; + virtual uint32 HasBeenDiscardedThisFrame() const + { + return GFrameNumberRenderThread == FrameNumberLastDiscard; + } + bool IsTransient() const + { + return !!(Desc.Flags & TexCreate_Transient); + } virtual void SetDebugName(const TCHAR *InName); virtual const FPooledRenderTargetDesc& GetDesc() const; virtual uint32 ComputeMemorySize() const; @@ -76,6 +88,12 @@ private: /** Snapshots are sortof fake pooled render targets, they don't own anything and can outlive the things that created them. These are for threaded rendering. */ bool bSnapshot; + /** Pointer back to the pool for render targets which are actually pooled, otherwise NULL. */ + FRenderTargetPool* RenderTargetPool; + + /** Keeps track of the last frame we unmapped physical memory for this resource. We can't map again in the same frame if we did that */ + uint32 FrameNumberLastDiscard; + /** @return true:release this one, false otherwise */ bool OnFrameStart(); @@ -213,7 +231,7 @@ public: /** Destruct all snapshots, this must be done after all outstanding async tasks are done. It is important because they hold ref counted texture pointers etc **/ void DestructSnapshots(); - + void OnRenderTargetUnreferenced(IPooledRenderTarget* RenderTarget); /** Only to get statistics on usage and free elements. Normally only called in renderthread or if FlushRenderingCommands was called() */ void GetStats(uint32& OutWholeCount, uint32& OutWholePoolInKB, uint32& OutUsedInKB) const; diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.cpp index 0b118f22af37..c4a5984a6e9a 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.cpp @@ -92,31 +92,25 @@ static TAutoConsoleVariable CVarGBufferFormat( ECVF_RenderThreadSafe); // Fast VRam Settings. These should be tuned based on title requirements and resolution -// Note: Currently, changing these settings at runtime does not cause buffers to be reallocated -static TAutoConsoleVariable CVarFastVRamGBufferCount( - TEXT("r.FastVRamGBufferCount"), - 4, - TEXT("Number of fast VRAM GBuffers, in order A-E. May not be optimal on platforms with limited fast VRAM. Adjust based on resolution"), - ECVF_Scalability | ECVF_RenderThreadSafe); + +static TAutoConsoleVariable CVarFastVRamFillWithGBuffers( + TEXT("r.FastVRamStaticLayoutFillWithGBuffers"), + 1, + TEXT("Whether to fill ESRAM with GBuffers, all pass temporaries will fail to allocate. Games with mostly static lighting will benefit more from filling ESRAM with GBuffers instead of pass temporaries.\n") + TEXT("NOTE: Only applies if r.FastVRamDynamicAllocation is disabled."), + ECVF_RenderThreadSafe); static TAutoConsoleVariable CVarFastVRamSceneColor( TEXT("r.FastVRamSceneColor"), 1, TEXT("Whether to store scene color in fast VRAM"), - ECVF_Scalability | ECVF_RenderThreadSafe); + ECVF_RenderThreadSafe); static TAutoConsoleVariable CVarFastVRamSceneDepth( TEXT("r.FastVRamSceneDepth"), 1, TEXT("Whether to store scene depth in fast VRAM"), - ECVF_Scalability | ECVF_RenderThreadSafe); - -static TAutoConsoleVariable CVarFastVRamLightAttenuation( - TEXT("r.FastVRamLightAttenuation"), - 1, - TEXT("Whether to store light attenuation in fast VRAM"), - ECVF_Scalability | ECVF_RenderThreadSafe); - + ECVF_RenderThreadSafe); /** The global render targets used for scene rendering. */ static TGlobalResource SceneRenderTargetsSingleton; @@ -230,7 +224,7 @@ FSceneRenderTargets::FSceneRenderTargets(const FViewInfo& View, const FSceneRend , EditorPrimitivesColor(GRenderTargetPool.MakeSnapshot(SnapshotSource.EditorPrimitivesColor)) , EditorPrimitivesDepth(GRenderTargetPool.MakeSnapshot(SnapshotSource.EditorPrimitivesDepth)) , SeparateTranslucencyRT(SnapshotSource.SeparateTranslucencyRT) - , SeparateTranslucencyDepthRT(SnapshotSource.SeparateTranslucencyDepthRT) + , DownsampledTranslucencyDepthRT(SnapshotSource.DownsampledTranslucencyDepthRT) , bScreenSpaceAOIsValid(SnapshotSource.bScreenSpaceAOIsValid) , bCustomDepthIsValid(SnapshotSource.bCustomDepthIsValid) , GBufferRefCount(SnapshotSource.GBufferRefCount) @@ -249,6 +243,7 @@ FSceneRenderTargets::FSceneRenderTargets(const FViewInfo& View, const FSceneRend , bUseDownsizedOcclusionQueries(SnapshotSource.bUseDownsizedOcclusionQueries) , CurrentGBufferFormat(SnapshotSource.CurrentGBufferFormat) , CurrentSceneColorFormat(SnapshotSource.CurrentSceneColorFormat) + , CurrentMobileSceneColorFormat(SnapshotSource.CurrentMobileSceneColorFormat) , bAllowStaticLighting(SnapshotSource.bAllowStaticLighting) , CurrentMaxShadowResolution(SnapshotSource.CurrentMaxShadowResolution) , CurrentRSMResolution(SnapshotSource.CurrentRSMResolution) @@ -447,6 +442,8 @@ void FSceneRenderTargets::Allocate(FRHICommandList& RHICmdList, const FSceneView SceneColorFormat = CVar->GetValueOnRenderThread(); } + + EPixelFormat MobileSceneColorFormat = GetDesiredMobileSceneColorFormat(); bool bNewAllowStaticLighting; { @@ -491,6 +488,7 @@ void FSceneRenderTargets::Allocate(FRHICommandList& RHICmdList, const FSceneView (BufferSize.Y != DesiredBufferSize.Y) || (CurrentGBufferFormat != GBufferFormat) || (CurrentSceneColorFormat != SceneColorFormat) || + (CurrentMobileSceneColorFormat != MobileSceneColorFormat) || (bAllowStaticLighting != bNewAllowStaticLighting) || (bUseDownsizedOcclusionQueries != bDownsampledOcclusionQueries) || (CurrentMaxShadowResolution != MaxShadowResolution) || @@ -503,6 +501,7 @@ void FSceneRenderTargets::Allocate(FRHICommandList& RHICmdList, const FSceneView { CurrentGBufferFormat = GBufferFormat; CurrentSceneColorFormat = SceneColorFormat; + CurrentMobileSceneColorFormat = MobileSceneColorFormat; bAllowStaticLighting = bNewAllowStaticLighting; bUseDownsizedOcclusionQueries = bDownsampledOcclusionQueries; CurrentMaxShadowResolution = MaxShadowResolution; @@ -516,7 +515,7 @@ void FSceneRenderTargets::Allocate(FRHICommandList& RHICmdList, const FSceneView // Reinitialize the render targets for the given size. SetBufferSize(DesiredBufferSize.X, DesiredBufferSize.Y); - UE_LOG(LogRenderer, Log, TEXT("Reallocating scene render targets to support %ux%u NumSamples %u (Frame:%u)."), BufferSize.X, BufferSize.Y, CurrentMSAACount, ViewFamily.FrameNumber); + UE_LOG(LogRenderer, Log, TEXT("Reallocating scene render targets to support %ux%u Format %u NumSamples %u (Frame:%u)."), BufferSize.X, BufferSize.Y, (uint32)GetSceneColorFormat(), CurrentMSAACount, ViewFamily.FrameNumber); UpdateRHI(); } @@ -591,7 +590,7 @@ void FSceneRenderTargets::SetQuadOverdrawUAV(FRHICommandList& RHICmdList, bool b Info.UnorderedAccessView[Info.NumUAVs++] = QuadOverdrawBuffer->GetRenderTargetItem().UAV; // Clear to default value - ClearUAV(RHICmdList, GMaxRHIFeatureLevel, QuadOverdrawBuffer->GetRenderTargetItem(), FLinearColor::Transparent); + ClearUAV(RHICmdList, QuadOverdrawBuffer->GetRenderTargetItem(), FLinearColor::Transparent); RHICmdList.TransitionResource(EResourceTransitionAccess::ERWBarrier, EResourceTransitionPipeline::EGfxToGfx, QuadOverdrawBuffer->GetRenderTargetItem().UAV); } } @@ -669,7 +668,7 @@ void FSceneRenderTargets::BeginRenderingGBuffer(FRHICommandList& RHICmdList, ERe Textures[i] = RenderTargets[i].Texture; } //depth/stencil should have been handled by the fast clear. only color for RT0 can get changed. - DrawClearQuadMRT(RHICmdList, GMaxRHIFeatureLevel, true, MRTCount, ClearColors, false, 0, false, 0); + DrawClearQuadMRT(RHICmdList, true, MRTCount, ClearColors, false, 0, false, 0); } //bind any clear data that won't be bound automatically by the preceding SetRenderTargetsAndClear @@ -779,7 +778,6 @@ void FSceneRenderTargets::AllocMobileMultiViewSceneColor(FRHICommandList& RHICmd const FIntPoint MultiViewBufferSize(BufferSize.X / 2, BufferSize.Y); FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(MultiViewBufferSize, SceneColorBufferFormat, DefaultColorClear, TexCreate_None, TexCreate_RenderTargetable, false)); - Desc.Flags |= TexCreate_FastVRAM; Desc.NumSamples = GetNumSceneColorMSAASamples(CurrentFeatureLevel); Desc.ArraySize = 2; Desc.bIsArray = true; @@ -860,10 +858,6 @@ void FSceneRenderTargets::AllocLightAttenuation(FRHICommandList& RHICmdList) // Create a texture to store the resolved light attenuation values, and a render-targetable surface to hold the unresolved light attenuation values. { FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, PF_B8G8R8A8, FClearValueBinding::White, TexCreate_None, TexCreate_RenderTargetable, false)); - if (CVarFastVRamLightAttenuation.GetValueOnRenderThread() >= 1) - { - Desc.Flags |= TexCreate_FastVRAM; - } Desc.NumSamples = GetNumSceneColorMSAASamples(CurrentFeatureLevel); GRenderTargetPool.FindFreeElement(RHICmdList, Desc, LightAttenuation, TEXT("LightAttenuation")); } @@ -875,6 +869,7 @@ void FSceneRenderTargets::AllocLightAttenuation(FRHICommandList& RHICmdList) void FSceneRenderTargets::ReleaseGBufferTargets() { GBufferResourcesUniformBuffer.SafeRelease(); + GBufferDummyResourcesUniformBuffer.SafeRelease(); GBufferA.SafeRelease(); GBufferB.SafeRelease(); GBufferC.SafeRelease(); @@ -908,11 +903,6 @@ void FSceneRenderTargets::GetGBufferADesc(FPooledRenderTargetDesc& Desc) const NormalGBufferFormat = PF_FloatRGBA; } - if (CVarFastVRamGBufferCount.GetValueOnRenderThread() >= 1) - { - Desc.Flags |= TexCreate_FastVRAM; - } - Desc = FPooledRenderTargetDesc::Create2DDesc(BufferSize, NormalGBufferFormat, FClearValueBinding::Transparent, TexCreate_None, TexCreate_RenderTargetable, false); } } @@ -951,10 +941,7 @@ void FSceneRenderTargets::AllocGBufferTargets(FRHICommandList& RHICmdList) const EPixelFormat SpecularGBufferFormat = bHighPrecisionGBuffers ? PF_FloatRGBA : PF_B8G8R8A8; FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, SpecularGBufferFormat, FClearValueBinding::Transparent, TexCreate_None, TexCreate_RenderTargetable, false)); - if (CVarFastVRamGBufferCount.GetValueOnRenderThread() >= 2) - { Desc.Flags |= TexCreate_FastVRAM; - } GRenderTargetPool.FindFreeElement(RHICmdList, Desc, GBufferB, TEXT("GBufferB")); } @@ -962,9 +949,9 @@ void FSceneRenderTargets::AllocGBufferTargets(FRHICommandList& RHICmdList) { const EPixelFormat DiffuseGBufferFormat = bHighPrecisionGBuffers ? PF_FloatRGBA : PF_B8G8R8A8; FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, DiffuseGBufferFormat, FClearValueBinding::Transparent, TexCreate_SRGB, TexCreate_RenderTargetable, false)); - if (CVarFastVRamGBufferCount.GetValueOnRenderThread() >= 3) + if (CVarFastVRamFillWithGBuffers.GetValueOnRenderThread() >= 1) { - Desc.Flags |= TexCreate_FastVRAM; + Desc.Flags |= GetTextureFastVRamFlag_StaticLayout(); } GRenderTargetPool.FindFreeElement(RHICmdList, Desc, GBufferC, TEXT("GBufferC")); } @@ -972,9 +959,9 @@ void FSceneRenderTargets::AllocGBufferTargets(FRHICommandList& RHICmdList) // Create the mask g-buffer (e.g. SSAO, subsurface scattering, wet surface mask, skylight mask, ...). { FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, PF_B8G8R8A8, FClearValueBinding::Transparent, TexCreate_None, TexCreate_RenderTargetable, false)); - if (CVarFastVRamGBufferCount.GetValueOnRenderThread() >= 4) + if (CVarFastVRamFillWithGBuffers.GetValueOnRenderThread() >= 1) { - Desc.Flags |= TexCreate_FastVRAM; + Desc.Flags |= GetTextureFastVRamFlag_StaticLayout(); } GRenderTargetPool.FindFreeElement(RHICmdList, Desc, GBufferD, TEXT("GBufferD")); } @@ -982,10 +969,6 @@ void FSceneRenderTargets::AllocGBufferTargets(FRHICommandList& RHICmdList) if (bAllowStaticLighting) { FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, PF_B8G8R8A8, FClearValueBinding::Transparent, TexCreate_None, TexCreate_RenderTargetable, false)); - if (CVarFastVRamGBufferCount.GetValueOnRenderThread() >= 5) - { - Desc.Flags |= TexCreate_FastVRAM; - } GRenderTargetPool.FindFreeElement(RHICmdList, Desc, GBufferE, TEXT("GBufferE")); } @@ -1317,7 +1300,7 @@ void FSceneRenderTargets::BeginRenderingLightAttenuation(FRHICommandList& RHICmd TransitionSetRenderTargetsHelper(RHICmdList, GetLightAttenuationSurface(), GetSceneDepthSurface(), FExclusiveDepthStencil::DepthRead_StencilWrite); FRHIRenderTargetView View = FRHIRenderTargetView(GetLightAttenuationSurface(), ERenderTargetLoadAction::EClear); - FRHISetRenderTargetsInfo Info(1, &View, FRHIDepthRenderTargetView(GetSceneDepthSurface(), ERenderTargetLoadAction::ELoad, ERenderTargetStoreAction::ENoAction, ERenderTargetLoadAction::ELoad, ERenderTargetStoreAction::ENoAction)); + FRHISetRenderTargetsInfo Info(1, &View, FRHIDepthRenderTargetView(GetSceneDepthSurface(), ERenderTargetLoadAction::ELoad, ERenderTargetStoreAction::ENoAction, FExclusiveDepthStencil::DepthRead_StencilWrite)); RHICmdList.SetRenderTargetsAndClear(Info); } else @@ -1351,16 +1334,16 @@ TRefCountPtr& FSceneRenderTargets::GetSeparateTranslucency( return SeparateTranslucencyRT; } -TRefCountPtr& FSceneRenderTargets::GetSeparateTranslucencyDepth(FRHICommandList& RHICmdList, FIntPoint Size) +TRefCountPtr& FSceneRenderTargets::GetDownsampledTranslucencyDepth(FRHICommandList& RHICmdList, FIntPoint Size) { - if (!SeparateTranslucencyDepthRT || SeparateTranslucencyDepthRT->GetDesc().Extent != Size) + if (!DownsampledTranslucencyDepthRT || DownsampledTranslucencyDepthRT->GetDesc().Extent != Size) { // Create the SeparateTranslucency depth render target FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(Size, PF_DepthStencil, FClearValueBinding::None, TexCreate_None, TexCreate_DepthStencilTargetable, false)); Desc.NumSamples = GetNumSceneColorMSAASamples(CurrentFeatureLevel); - GRenderTargetPool.FindFreeElement(RHICmdList, Desc, SeparateTranslucencyDepthRT, TEXT("SeparateTranslucencyDepth")); + GRenderTargetPool.FindFreeElement(RHICmdList, Desc, DownsampledTranslucencyDepthRT, TEXT("SeparateTranslucencyDepth")); } - return SeparateTranslucencyDepthRT; + return DownsampledTranslucencyDepthRT; } void FSceneRenderTargets::BeginRenderingTranslucency(FRHICommandList& RHICmdList, const FViewInfo& View, bool bFirstTimeThisFrame) @@ -1372,7 +1355,7 @@ void FSceneRenderTargets::BeginRenderingTranslucency(FRHICommandList& RHICmdList { // Clear the stencil buffer for ResponsiveAA const FTexture2DRHIRef& DepthSurface = GetSceneDepthSurface(); - DrawClearQuad(RHICmdList, CurrentFeatureLevel, false, FLinearColor(), false, 0, true, 0, FIntPoint(DepthSurface->GetSizeX(), DepthSurface->GetSizeY()), View.ViewRect); + DrawClearQuad(RHICmdList, false, FLinearColor(), false, 0, true, 0, FIntPoint(DepthSurface->GetSizeX(), DepthSurface->GetSizeY()), View.ViewRect); } // viewport to match view size @@ -1381,14 +1364,8 @@ void FSceneRenderTargets::BeginRenderingTranslucency(FRHICommandList& RHICmdList void FSceneRenderTargets::BeginRenderingSeparateTranslucency(FRHICommandList& RHICmdList, const FViewInfo& View, bool bFirstTimeThisFrame) { - check(IsSeparateTranslucencyActive(View)); - bSeparateTranslucencyPass = true; - FIntPoint ScaledSize; - float Scale = 1.0f; - GetSeparateTranslucencyDimensions(ScaledSize, Scale); - SCOPED_DRAW_EVENT(RHICmdList, BeginSeparateTranslucency); TRefCountPtr* SeparateTranslucency; @@ -1399,9 +1376,9 @@ void FSceneRenderTargets::BeginRenderingSeparateTranslucency(FRHICommandList& RH } else { - SeparateTranslucency = &GetSeparateTranslucency(RHICmdList, ScaledSize); + SeparateTranslucency = &GetSeparateTranslucency(RHICmdList, SeparateTranslucencyBufferSize); } - const FTexture2DRHIRef &SeparateTranslucencyDepth = Scale < 1.0f ? (const FTexture2DRHIRef&)GetSeparateTranslucencyDepth(RHICmdList, ScaledSize)->GetRenderTargetItem().TargetableTexture : GetSceneDepthSurface(); + const FTexture2DRHIRef &SeparateTranslucencyDepth = SeparateTranslucencyScale < 1.0f ? (const FTexture2DRHIRef&)GetDownsampledTranslucencyDepth(RHICmdList, SeparateTranslucencyBufferSize)->GetRenderTargetItem().TargetableTexture : GetSceneDepthSurface(); check((*SeparateTranslucency)->GetRenderTargetItem().TargetableTexture->GetClearColor() == FLinearColor::Black); // clear the render target the first time, re-use afterwards @@ -1415,10 +1392,10 @@ void FSceneRenderTargets::BeginRenderingSeparateTranslucency(FRHICommandList& RH RHICmdList.BindClearMRTValues(true, false, true); } - RHICmdList.SetViewport(View.ViewRect.Min.X * Scale, View.ViewRect.Min.Y * Scale, 0.0f, View.ViewRect.Max.X * Scale, View.ViewRect.Max.Y * Scale, 1.0f); + RHICmdList.SetViewport(View.ViewRect.Min.X * SeparateTranslucencyScale, View.ViewRect.Min.Y * SeparateTranslucencyScale, 0.0f, View.ViewRect.Max.X * SeparateTranslucencyScale, View.ViewRect.Max.Y * SeparateTranslucencyScale, 1.0f); } -void FSceneRenderTargets::FinishRenderingSeparateTranslucency(FRHICommandList& RHICmdList) +void FSceneRenderTargets::FinishRenderingSeparateTranslucency(FRHICommandList& RHICmdList, const FViewInfo& View) { SCOPED_DRAW_EVENT(RHICmdList, FinishSeparateTranslucency); @@ -1428,19 +1405,23 @@ void FSceneRenderTargets::FinishRenderingSeparateTranslucency(FRHICommandList& R { check(SeparateTranslucencyRT.GetReference()); SeparateTranslucency = &SeparateTranslucencyRT; - SeparateTranslucencyDepth = &SeparateTranslucencyDepthRT; + SeparateTranslucencyDepth = SeparateTranslucencyScale < 1.f ? &DownsampledTranslucencyDepthRT : &SceneDepthZ; } else { - FIntPoint ScaledSize; - float Scale = 1.0f; - GetSeparateTranslucencyDimensions(ScaledSize, Scale); - SeparateTranslucency = &GetSeparateTranslucency(RHICmdList, ScaledSize); - SeparateTranslucencyDepth = &GetSeparateTranslucencyDepth(RHICmdList, ScaledSize); + SeparateTranslucency = &GetSeparateTranslucency(RHICmdList, SeparateTranslucencyBufferSize); + SeparateTranslucencyDepth = SeparateTranslucencyScale < 1.f ? &GetDownsampledTranslucencyDepth(RHICmdList, SeparateTranslucencyBufferSize) : &SceneDepthZ; } - RHICmdList.CopyToResolveTarget((*SeparateTranslucency)->GetRenderTargetItem().TargetableTexture, (*SeparateTranslucency)->GetRenderTargetItem().ShaderResourceTexture, true, FResolveParams()); - RHICmdList.CopyToResolveTarget((*SeparateTranslucencyDepth)->GetRenderTargetItem().TargetableTexture, (*SeparateTranslucencyDepth)->GetRenderTargetItem().ShaderResourceTexture, true, FResolveParams()); + const FResolveRect SeparateResolveRect( + View.ViewRect.Min.X * SeparateTranslucencyScale, + View.ViewRect.Min.Y * SeparateTranslucencyScale, + View.ViewRect.Max.X * SeparateTranslucencyScale, + View.ViewRect.Max.Y * SeparateTranslucencyScale + ); + + RHICmdList.CopyToResolveTarget((*SeparateTranslucency)->GetRenderTargetItem().TargetableTexture, (*SeparateTranslucency)->GetRenderTargetItem().ShaderResourceTexture, true, SeparateResolveRect); + RHICmdList.CopyToResolveTarget((*SeparateTranslucencyDepth)->GetRenderTargetItem().TargetableTexture, (*SeparateTranslucencyDepth)->GetRenderTargetItem().ShaderResourceTexture, true, SeparateResolveRect); bSeparateTranslucencyPass = false; } @@ -1539,24 +1520,6 @@ const FTexture2DRHIRef& FSceneRenderTargets::GetEditorPrimitivesDepth(FRHIComman return (const FTexture2DRHIRef&)EditorPrimitivesDepth->GetRenderTargetItem().TargetableTexture; } -TAutoConsoleVariable FSceneRenderTargets::CVarSetSeperateTranslucencyEnabled( - TEXT("r.SeparateTranslucency"), - 1, - TEXT("Allows to disable the separate translucency feature (all translucency is rendered in separate RT and composited\n") - TEXT("after DOF, if not specified otherwise in the material).\n") - TEXT(" 0: off (translucency is affected by depth of field)\n") - TEXT(" 1: on costs GPU performance and memory but keeps translucency unaffected by Depth of Field. (default)"), - ECVF_RenderThreadSafe); - -bool FSceneRenderTargets::IsSeparateTranslucencyActive(const FViewInfo& View) const -{ - int32 Value = FSceneRenderTargets::CVarSetSeperateTranslucencyEnabled.GetValueOnRenderThread(); - - return (Value != 0) && CurrentFeatureLevel >= ERHIFeatureLevel::SM4 - && (View.Family->EngineShowFlags.PostProcessing || View.Family->EngineShowFlags.ShaderComplexity) - && View.Family->EngineShowFlags.SeparateTranslucency; -} - void FSceneRenderTargets::InitEditorPrimitivesColor(FRHICommandList& RHICmdList) { FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(BufferSize, @@ -1932,18 +1895,41 @@ void FSceneRenderTargets::AllocateDeferredShadingPathRenderTargets(FRHICommandLi } } +EPixelFormat FSceneRenderTargets::GetDesiredMobileSceneColorFormat() const +{ + EPixelFormat DefaultColorFormat = (!IsMobileHDR() || IsMobileHDR32bpp() || !GSupportsRenderTargetFormat_PF_FloatRGBA) ? PF_B8G8R8A8 : PF_FloatRGBA; + check(GPixelFormats[DefaultColorFormat].Supported); + + EPixelFormat MobileSceneColorBufferFormat = DefaultColorFormat; + static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.Mobile.SceneColorFormat")); + int32 MobileSceneColor = CVar->GetValueOnRenderThread(); + switch (MobileSceneColor) + { + case 1: + MobileSceneColorBufferFormat = PF_FloatRGBA; break; + case 2: + MobileSceneColorBufferFormat = PF_FloatR11G11B10; break; + case 3: + MobileSceneColorBufferFormat = PF_B8G8R8A8; break; + default: + break; + } + + return GPixelFormats[MobileSceneColorBufferFormat].Supported ? MobileSceneColorBufferFormat : DefaultColorFormat; +} + +EPixelFormat FSceneRenderTargets::GetMobileSceneColorFormat() const +{ + return CurrentMobileSceneColorFormat; +} + EPixelFormat FSceneRenderTargets::GetSceneColorFormat() const { EPixelFormat SceneColorBufferFormat = PF_FloatRGBA; if (CurrentFeatureLevel < ERHIFeatureLevel::SM4) { - // Potentially allocate an alpha channel in th -fe scene color texture to store the resolved scene depth. - SceneColorBufferFormat = GSupportsRenderTargetFormat_PF_FloatRGBA ? PF_FloatRGBA : PF_B8G8R8A8; - if (!IsMobileHDR() || IsMobileHDR32bpp()) - { - SceneColorBufferFormat = PF_B8G8R8A8; - } + return GetMobileSceneColorFormat(); } else { @@ -2368,247 +2354,210 @@ void FSceneTextureShaderParameters::Set( TRHICmdList& RHICmdList, const ShaderRHIParamRef& ShaderRHI, const FSceneView& View, + const EDeferredParamStrictness ParamStrictness, ESceneRenderTargetsMode::Type TextureMode, ESamplerFilter ColorFilter ) const { + FTextureRHIParamRef BlackDefault2D = GSystemTextures.BlackDummy->GetRenderTargetItem().ShaderResourceTexture; + FTextureRHIParamRef DepthDefault = GSystemTextures.DepthDummy->GetRenderTargetItem().ShaderResourceTexture; + + FTextureRHIParamRef SceneColorTexture = BlackDefault2D; + FTextureRHIParamRef SceneAlphaCopyTexture = BlackDefault2D; + FTextureRHIParamRef SceneDepthTexture = DepthDefault; + FTextureRHIParamRef SceneColorSurfaceTexture = BlackDefault2D; + + FTextureRHIParamRef DepthSurface = DepthDefault; + FTextureRHIParamRef DepthTextureNonMS = DepthDefault; + FTextureRHIParamRef DepthAuxiliarySurface = DepthDefault; + + FShaderResourceViewRHIParamRef SceneStencilSRV = nullptr; + FTextureRHIParamRef MobileCustomStencil = BlackDefault2D; + + const auto FeatureLevel = View.GetFeatureLevel(); + if (TextureMode == ESceneRenderTargetsMode::SetTextures) { FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); + SceneColorTexture = SceneContext.GetSceneColorTexture(); + SceneAlphaCopyTexture = SceneContext.HasSceneAlphaCopyTexture() ? SceneContext.GetSceneAlphaCopyTexture() : nullptr; - // optimization possible: TShaderRHIParamRef is no param Ref - if (SceneColorTextureParameter.IsBound()) + const FTexture2DRHIRef* ActualDepthTexture = SceneContext.GetActualDepthTexture(); + SceneDepthTexture = ActualDepthTexture ? (*ActualDepthTexture).GetReference() : SceneDepthTexture; + if (SceneContext.IsSeparateTranslucencyPass() && SceneContext.IsDownsampledTranslucencyDepthValid()) { - FSamplerStateRHIRef Filter; - switch ( ColorFilter ) - { - case SF_Bilinear: - Filter = TStaticSamplerState::GetRHI(); - break; - case SF_Trilinear: - Filter = TStaticSamplerState::GetRHI(); - break; - case SF_AnisotropicPoint: - Filter = TStaticSamplerState::GetRHI(); - break; - case SF_AnisotropicLinear: - Filter = TStaticSamplerState::GetRHI(); - break; - case SF_Point: - default: - Filter = TStaticSamplerState::GetRHI(); - break; - } + FIntPoint OutScaledSize; + float OutScale; + SceneContext.GetSeparateTranslucencyDimensions(OutScaledSize, OutScale); - SetTextureParameter( - RHICmdList, - ShaderRHI, - SceneColorTextureParameter, - SceneColorTextureParameterSampler, - Filter, - SceneContext.GetSceneColorTexture() - ); + if (OutScale < 1.0f) + { + SceneDepthTexture = SceneContext.GetDownsampledTranslucencyDepthSurface(); + } } - if (SceneAlphaCopyTextureParameter.IsBound() && SceneContext.HasSceneAlphaCopyTexture()) + SceneColorSurfaceTexture = SceneContext.GetSceneColorSurface(); + + if (GSupportsDepthFetchDuringDepthTest) { - FSamplerStateRHIRef Filter; + DepthSurface = SceneContext.GetSceneDepthSurface(); + DepthTextureNonMS = SceneContext.GetSceneDepthTexture(); + } + else + { + DepthAuxiliarySurface = SceneContext.GetAuxiliarySceneDepthSurface(); + } + + SceneStencilSRV = SceneContext.SceneStencilSRV; + + if (FeatureLevel <= ERHIFeatureLevel::ES3_1) + { + if (SceneContext.MobileCustomStencil.IsValid()) + { + MobileCustomStencil = SceneContext.MobileCustomStencil->GetRenderTargetItem().ShaderResourceTexture; + } + } + } + else if (ParamStrictness == EDeferredParamStrictness::EStrict) + { + //otherwise start throwing failure warnings. + if (TextureMode == ESceneRenderTargetsMode::DontSet) + { + // Verify that none of these were bound if we were told not to set them + ensure(!SceneColorTextureParameter.IsBound() + && !SceneDepthTextureParameter.IsBound() + && !SceneColorSurfaceParameter.IsBound() + && !SceneDepthSurfaceParameter.IsBound() + && !SceneDepthTextureNonMS.IsBound() + && !SceneStencilTextureParameter.IsBound()); + } + else if (TextureMode == ESceneRenderTargetsMode::DontSetIgnoreBoundByEditorCompositing) + { + // Verify that none of these were bound if we were told not to set them + // ignore SceneDepthTextureNonMS + ensure(!SceneColorTextureParameter.IsBound() + && !SceneDepthTextureParameter.IsBound() + && !SceneColorSurfaceParameter.IsBound() + && !SceneDepthSurfaceParameter.IsBound() + && !SceneStencilTextureParameter.IsBound()); + } + } + + // optimization possible: TShaderRHIParamRef is no param Ref + if (SceneColorTextureParameter.IsBound()) + { + FSamplerStateRHIRef Filter; + switch ( ColorFilter ) + { + case SF_Bilinear: + Filter = TStaticSamplerState::GetRHI(); + break; + case SF_Trilinear: + Filter = TStaticSamplerState::GetRHI(); + break; + case SF_AnisotropicPoint: + Filter = TStaticSamplerState::GetRHI(); + break; + case SF_AnisotropicLinear: + Filter = TStaticSamplerState::GetRHI(); + break; + case SF_Point: + default: Filter = TStaticSamplerState::GetRHI(); - SetTextureParameter( - RHICmdList, - ShaderRHI, - SceneAlphaCopyTextureParameter, - SceneAlphaCopyTextureParameterSampler, - Filter, - SceneContext.GetSceneAlphaCopyTexture() - ); + break; } - if(SceneDepthTextureParameter.IsBound() || SceneDepthTextureParameterSampler.IsBound()) + SetTextureParameter( + RHICmdList, + ShaderRHI, + SceneColorTextureParameter, + SceneColorTextureParameterSampler, + Filter, + SceneColorTexture + ); + } + + if (SceneAlphaCopyTextureParameter.IsBound() && SceneAlphaCopyTexture) + { + FSamplerStateRHIRef Filter; + Filter = TStaticSamplerState::GetRHI(); + SetTextureParameter( + RHICmdList, + ShaderRHI, + SceneAlphaCopyTextureParameter, + SceneAlphaCopyTextureParameterSampler, + Filter, + SceneAlphaCopyTexture + ); + } + + if(SceneDepthTextureParameter.IsBound() || SceneDepthTextureParameterSampler.IsBound()) + { + SetTextureParameter( + RHICmdList, + ShaderRHI, + SceneDepthTextureParameter, + SceneDepthTextureParameterSampler, + TStaticSamplerState::GetRHI(), + SceneDepthTexture + ); + } + + if (FeatureLevel >= ERHIFeatureLevel::SM5) + { + SetTextureParameter(RHICmdList, ShaderRHI, SceneColorSurfaceParameter, SceneColorSurfaceTexture); + } + if (FeatureLevel >= ERHIFeatureLevel::SM4) + { + if(GSupportsDepthFetchDuringDepthTest) { - const FTexture2DRHIRef* DepthTexture = SceneContext.GetActualDepthTexture(); - - if (SceneContext.IsSeparateTranslucencyPass() && SceneContext.IsSeparateTranslucencyDepthValid()) + if(SceneDepthSurfaceParameter.IsBound()) { - FIntPoint OutScaledSize; - float OutScale; - SceneContext.GetSeparateTranslucencyDimensions(OutScaledSize, OutScale); - - if (OutScale < 1.0f) - { - DepthTexture = &SceneContext.GetSeparateTranslucencyDepthSurface(); - } + SetTextureParameter(RHICmdList, ShaderRHI, SceneDepthSurfaceParameter, DepthSurface); } - - SetTextureParameter( - RHICmdList, - ShaderRHI, - SceneDepthTextureParameter, - SceneDepthTextureParameterSampler, - TStaticSamplerState::GetRHI(), - *DepthTexture - ); - } - - const auto FeatureLevel = View.GetFeatureLevel(); - - if (FeatureLevel >= ERHIFeatureLevel::SM5) - { - SetTextureParameter(RHICmdList, ShaderRHI, SceneColorSurfaceParameter, SceneContext.GetSceneColorSurface()); - } - if (FeatureLevel >= ERHIFeatureLevel::SM4) - { - if(GSupportsDepthFetchDuringDepthTest) + if(SceneDepthTextureNonMS.IsBound()) { - if(SceneDepthSurfaceParameter.IsBound()) - { - SetTextureParameter(RHICmdList, ShaderRHI, SceneDepthSurfaceParameter, SceneContext.GetSceneDepthSurface()); - } - if(SceneDepthTextureNonMS.IsBound()) - { - SetTextureParameter(RHICmdList, ShaderRHI, SceneDepthTextureNonMS, SceneContext.GetSceneDepthTexture()); - } + SetTextureParameter(RHICmdList, ShaderRHI, SceneDepthTextureNonMS, DepthTextureNonMS); + } + } + else + { + if(SceneDepthSurfaceParameter.IsBound()) + { + SetTextureParameter(RHICmdList, ShaderRHI, SceneDepthSurfaceParameter, DepthAuxiliarySurface); + } + if(SceneDepthTextureNonMS.IsBound()) + { + SetTextureParameter(RHICmdList, ShaderRHI, SceneDepthTextureNonMS, DepthAuxiliarySurface); + } + } + + if (SceneStencilTextureParameter.IsBound()) + { + if (SceneStencilSRV) + { + SetSRVParameter(RHICmdList, ShaderRHI, SceneStencilTextureParameter, SceneStencilSRV); } else { - if(SceneDepthSurfaceParameter.IsBound()) - { - SetTextureParameter(RHICmdList, ShaderRHI, SceneDepthSurfaceParameter, SceneContext.GetAuxiliarySceneDepthSurface()); - } - if(SceneDepthTextureNonMS.IsBound()) - { - SetTextureParameter(RHICmdList, ShaderRHI, SceneDepthTextureNonMS, SceneContext.GetAuxiliarySceneDepthSurface()); - } - } - - if (SceneStencilTextureParameter.IsBound()) - { - if (SceneContext.SceneStencilSRV.GetReference()) - { - SetSRVParameter(RHICmdList, ShaderRHI, SceneStencilTextureParameter, SceneContext.SceneStencilSRV); - } - else - { - SetTextureParameter(RHICmdList, ShaderRHI, SceneStencilTextureParameter, GSystemTextures.BlackDummy->GetRenderTargetItem().ShaderResourceTexture); - } - } - } - - if (FeatureLevel <= ERHIFeatureLevel::ES3_1) - { - if (MobileCustomStencilTexture.IsBound() && SceneContext.MobileCustomStencil.IsValid()) - { - SetTextureParameter( - RHICmdList, - ShaderRHI, - MobileCustomStencilTexture, - MobileCustomStencilTextureSampler, - TStaticSamplerState::GetRHI(), - SceneContext.MobileCustomStencil->GetRenderTargetItem().ShaderResourceTexture - ); + SetTextureParameter(RHICmdList, ShaderRHI, SceneStencilTextureParameter, GSystemTextures.BlackDummy->GetRenderTargetItem().ShaderResourceTexture); } } } - else if (TextureMode == ESceneRenderTargetsMode::DontSet) - { - // Verify that none of these were bound if we were told not to set them - ensure(!SceneColorTextureParameter.IsBound() - && !SceneDepthTextureParameter.IsBound() - && !SceneColorSurfaceParameter.IsBound() - && !SceneDepthSurfaceParameter.IsBound() - && !SceneDepthTextureNonMS.IsBound() - && !SceneStencilTextureParameter.IsBound()); - } - else if (TextureMode == ESceneRenderTargetsMode::DontSetIgnoreBoundByEditorCompositing) - { - // Verify that none of these were bound if we were told not to set them - // ignore SceneDepthTextureNonMS - ensure(!SceneColorTextureParameter.IsBound() - && !SceneDepthTextureParameter.IsBound() - && !SceneColorSurfaceParameter.IsBound() - && !SceneDepthSurfaceParameter.IsBound() - && !SceneStencilTextureParameter.IsBound()); - } - else if (TextureMode == ESceneRenderTargetsMode::InvalidScene) - { - FTextureRHIParamRef BlackDefault2D = GSystemTextures.BlackDummy->GetRenderTargetItem().ShaderResourceTexture; - FTextureRHIParamRef DepthDefault = GSystemTextures.DepthDummy->GetRenderTargetItem().ShaderResourceTexture; - FSamplerStateRHIRef Filter = TStaticSamplerState::GetRHI(); - if (SceneColorTextureParameter.IsBound()) - { - - - SetTextureParameter( - RHICmdList, - ShaderRHI, - SceneColorTextureParameter, - SceneColorTextureParameterSampler, - Filter, - BlackDefault2D - ); - } - - if (SceneAlphaCopyTextureParameter.IsBound()) - { - SetTextureParameter( - RHICmdList, - ShaderRHI, - SceneAlphaCopyTextureParameter, - SceneAlphaCopyTextureParameterSampler, - Filter, - BlackDefault2D - ); - } - - if (SceneDepthTextureParameter.IsBound() || SceneDepthTextureParameterSampler.IsBound()) + if (FeatureLevel <= ERHIFeatureLevel::ES3_1) + { + if (MobileCustomStencilTexture.IsBound()) { SetTextureParameter( - RHICmdList, + RHICmdList, ShaderRHI, - SceneDepthTextureParameter, - SceneDepthTextureParameterSampler, - Filter, - DepthDefault + MobileCustomStencilTexture, + MobileCustomStencilTextureSampler, + TStaticSamplerState::GetRHI(), + MobileCustomStencil ); } - - const auto FeatureLevel = View.GetFeatureLevel(); - - if (FeatureLevel >= ERHIFeatureLevel::SM5) - { - SetTextureParameter(RHICmdList, ShaderRHI, SceneColorSurfaceParameter, BlackDefault2D); - } - if (FeatureLevel >= ERHIFeatureLevel::SM4) - { - if (SceneDepthSurfaceParameter.IsBound()) - { - SetTextureParameter(RHICmdList, ShaderRHI, SceneDepthSurfaceParameter, DepthDefault); - } - if (SceneDepthTextureNonMS.IsBound()) - { - SetTextureParameter(RHICmdList, ShaderRHI, SceneDepthTextureNonMS, DepthDefault); - } - if (SceneStencilTextureParameter.IsBound()) - { - SetTextureParameter(RHICmdList, ShaderRHI, SceneStencilTextureParameter, BlackDefault2D); - } - } - - if (FeatureLevel <= ERHIFeatureLevel::ES3_1) - { - if (MobileCustomStencilTexture.IsBound()) - { - SetTextureParameter( - RHICmdList, - ShaderRHI, - MobileCustomStencilTexture, - MobileCustomStencilTextureSampler, - Filter, - BlackDefault2D - ); - } - } - } + } if( DirectionalOcclusionSampler.IsBound() ) { @@ -2652,6 +2601,7 @@ void FSceneTextureShaderParameters::Set( FRHICommandList& RHICmdList, \ const ShaderRHIParamRef& ShaderRHI, \ const FSceneView& View, \ + EDeferredParamStrictness ParamStrictness, \ ESceneRenderTargetsMode::Type TextureMode, \ ESamplerFilter ColorFilter \ ) const; @@ -2714,17 +2664,23 @@ void FDeferredPixelShaderParameters::Bind(const FShaderParameterMap& ParameterMa bool IsDBufferEnabled(); template< typename ShaderRHIParamRef, typename TRHICmdList > -void FDeferredPixelShaderParameters::Set(TRHICmdList& RHICmdList, const ShaderRHIParamRef ShaderRHI, const FSceneView& View, ESceneRenderTargetsMode::Type TextureMode) const +void FDeferredPixelShaderParameters::Set(TRHICmdList& RHICmdList, const ShaderRHIParamRef ShaderRHI, const FSceneView& View, EMaterialDomain MaterialDomain, ESceneRenderTargetsMode::Type TextureMode) const { FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); + + //surface domain materials must not attempt to set scenetextures as they won't work. + //other domains we will allow to silently read from dummies for the purpose of thumbnails and editor preview for now. + const EDeferredParamStrictness ParamStrictness = (MaterialDomain == MD_Surface) ? EDeferredParamStrictness::EStrict : EDeferredParamStrictness::ELoose; + // This is needed on PC ES2 for SceneAlphaCopy, probably should be refactored for performance. - SceneTextureParameters.Set(RHICmdList, ShaderRHI, View, TextureMode, SF_Point); + SceneTextureParameters.Set(RHICmdList, ShaderRHI, View, ParamStrictness, TextureMode, SF_Point); // if() is purely an optimization and could be removed if (IsDBufferEnabled()) - { + { + IPooledRenderTarget* DBufferA = SceneContext.DBufferA ? SceneContext.DBufferA : GSystemTextures.BlackAlphaOneDummy; - IPooledRenderTarget* DBufferB = SceneContext.DBufferB ? SceneContext.DBufferB : GSystemTextures.MidGrayDummy; + IPooledRenderTarget* DBufferB = SceneContext.DBufferB ? SceneContext.DBufferB : GSystemTextures.DefaultNormal8Bit; IPooledRenderTarget* DBufferC = SceneContext.DBufferC ? SceneContext.DBufferC : GSystemTextures.GreenDummy; // todo: optimize out when not needed @@ -2754,77 +2710,81 @@ void FDeferredPixelShaderParameters::Set(TRHICmdList& RHICmdList, const ShaderRH const auto FeatureLevel = View.GetFeatureLevel(); + FTextureRHIParamRef BlackDefault2D = GSystemTextures.BlackDummy->GetRenderTargetItem().ShaderResourceTexture; + FTextureRHIParamRef WhiteDefault2D = GSystemTextures.WhiteDummy->GetRenderTargetItem().ShaderResourceTexture; + FTextureRHIParamRef DepthDefault = GSystemTextures.DepthDummy->GetRenderTargetItem().ShaderResourceTexture; + + FUniformBufferRHIParamRef GBufferResourcesUniformBuffer = nullptr; + FTextureRHIParamRef CustomDepth = DepthDefault; + FTextureRHIParamRef CustomStencil = BlackDefault2D; + FTextureRHIParamRef ScreenSpaceAOShaderResource = WhiteDefault2D; + FTextureRHIParamRef ScreenSpaceAOSTargetable = WhiteDefault2D; + FShaderResourceViewRHIParamRef CustomStencilSRV = nullptr; + + //dummies have the same lifetime as the actual gbuffers. + //avoid asserts grabbing them when we don't need them. + if (FeatureLevel >= ERHIFeatureLevel::SM4 && TextureMode != ESceneRenderTargetsMode::SetTextures) + { + if (GBufferResources.IsBound()) + { + GBufferResourcesUniformBuffer = SceneContext.GetDummyGBufferResourcesUniformBuffer(); + } + } + if (TextureMode == ESceneRenderTargetsMode::SetTextures) { - // if there is no ambient occlusion it's better to have white there - IPooledRenderTarget* ScreenSpaceAO = SceneContext.ScreenSpaceAO; - if(!SceneContext.bScreenSpaceAOIsValid) + if (SceneContext.bScreenSpaceAOIsValid) { - ScreenSpaceAO = GSystemTextures.WhiteDummy; + ScreenSpaceAOShaderResource = SceneContext.ScreenSpaceAO->GetRenderTargetItem().ShaderResourceTexture; + ScreenSpaceAOSTargetable = SceneContext.ScreenSpaceAO->GetRenderTargetItem().TargetableTexture; } // if there is no custom depth it's better to have the far distance there - IPooledRenderTarget* CustomDepth = SceneContext.bCustomDepthIsValid ? SceneContext.CustomDepth.GetReference() : 0; - if(!CustomDepth) + IPooledRenderTarget* CustomDepthTarget = SceneContext.bCustomDepthIsValid ? SceneContext.CustomDepth.GetReference() : 0; + if (CustomDepthTarget) { - CustomDepth = GSystemTextures.BlackDummy; + CustomDepth = CustomDepthTarget->GetRenderTargetItem().ShaderResourceTexture; } - SetTextureParameter(RHICmdList, ShaderRHI, CustomDepthTexture, CustomDepthTextureSampler, TStaticSamplerState<>::GetRHI(), CustomDepth->GetRenderTargetItem().ShaderResourceTexture); - if (FeatureLevel >= ERHIFeatureLevel::SM4) + if (SceneContext.bCustomDepthIsValid && SceneContext.CustomStencilSRV.GetReference()) { - if (GBufferResources.IsBound()) - { - SetUniformBufferParameter(RHICmdList, ShaderRHI, GBufferResources, SceneContext.GetGBufferResourcesUniformBuffer()); - } + CustomStencilSRV = SceneContext.CustomStencilSRV; + } - SetTextureParameter(RHICmdList, ShaderRHI, ScreenSpaceAOTexture, ScreenSpaceAOTextureSampler, TStaticSamplerState<>::GetRHI(), ScreenSpaceAO->GetRenderTargetItem().ShaderResourceTexture); - SetTextureParameter(RHICmdList, ShaderRHI, ScreenSpaceAOTextureMS, ScreenSpaceAO->GetRenderTargetItem().TargetableTexture); - SetTextureParameter(RHICmdList, ShaderRHI, ScreenSpaceAOTextureNonMS, ScreenSpaceAO->GetRenderTargetItem().ShaderResourceTexture); - - SetTextureParameter(RHICmdList, ShaderRHI, CustomDepthTextureNonMS, CustomDepth->GetRenderTargetItem().ShaderResourceTexture); - - if (CustomStencilTexture.IsBound()) - { - if (SceneContext.bCustomDepthIsValid && SceneContext.CustomStencilSRV.GetReference()) - { - SetSRVParameter(RHICmdList, ShaderRHI, CustomStencilTexture, SceneContext.CustomStencilSRV); - } - else - { - SetTextureParameter(RHICmdList, ShaderRHI, CustomStencilTexture, GSystemTextures.BlackDummy->GetRenderTargetItem().ShaderResourceTexture); - } - } + if (GBufferResources.IsBound()) + { + GBufferResourcesUniformBuffer = SceneContext.GetGBufferResourcesUniformBuffer(); } } - else if (TextureMode == ESceneRenderTargetsMode::DontSet || - TextureMode == ESceneRenderTargetsMode::DontSetIgnoreBoundByEditorCompositing) + else if (ParamStrictness == EDeferredParamStrictness::EStrict) { // Verify that none of these are actually bound - checkSlow(!GBufferResources.IsBound()); + ensureMsgf(!GBufferResources.IsBound(), TEXT("Incompatible Material bound")); } - else if (TextureMode == ESceneRenderTargetsMode::InvalidScene) + + SetTextureParameter(RHICmdList, ShaderRHI, CustomDepthTexture, CustomDepthTextureSampler, TStaticSamplerState<>::GetRHI(), CustomDepth); + + if (FeatureLevel >= ERHIFeatureLevel::SM4) { - FTextureRHIParamRef BlackDefault2D = GSystemTextures.BlackDummy->GetRenderTargetItem().ShaderResourceTexture; - FTextureRHIParamRef WhiteDefault2D = GSystemTextures.WhiteDummy->GetRenderTargetItem().ShaderResourceTexture; - FTextureRHIParamRef DepthDefault = GSystemTextures.DepthDummy->GetRenderTargetItem().ShaderResourceTexture; - - SetTextureParameter(RHICmdList, ShaderRHI, CustomDepthTexture, CustomDepthTextureSampler, TStaticSamplerState<>::GetRHI(), DepthDefault); - - if (FeatureLevel >= ERHIFeatureLevel::SM4) + if (GBufferResources.IsBound()) { - if (GBufferResources.IsBound()) + check(GBufferResourcesUniformBuffer); + SetUniformBufferParameter(RHICmdList, ShaderRHI, GBufferResources, GBufferResourcesUniformBuffer); + } + + SetTextureParameter(RHICmdList, ShaderRHI, ScreenSpaceAOTexture, ScreenSpaceAOTextureSampler, TStaticSamplerState<>::GetRHI(), ScreenSpaceAOShaderResource); + SetTextureParameter(RHICmdList, ShaderRHI, ScreenSpaceAOTextureMS, ScreenSpaceAOSTargetable); + SetTextureParameter(RHICmdList, ShaderRHI, ScreenSpaceAOTextureNonMS, ScreenSpaceAOShaderResource); + + SetTextureParameter(RHICmdList, ShaderRHI, CustomDepthTextureNonMS, CustomDepth); + + if (CustomStencilTexture.IsBound()) + { + if (CustomStencilSRV) { - SetUniformBufferParameter(RHICmdList, ShaderRHI, GBufferResources, SceneContext.GetDummyGBufferResourcesUniformBuffer()); + SetSRVParameter(RHICmdList, ShaderRHI, CustomStencilTexture, SceneContext.CustomStencilSRV); } - - SetTextureParameter(RHICmdList, ShaderRHI, ScreenSpaceAOTexture, ScreenSpaceAOTextureSampler, TStaticSamplerState<>::GetRHI(), WhiteDefault2D); - SetTextureParameter(RHICmdList, ShaderRHI, ScreenSpaceAOTextureMS, WhiteDefault2D); - SetTextureParameter(RHICmdList, ShaderRHI, ScreenSpaceAOTextureNonMS, WhiteDefault2D); - - SetTextureParameter(RHICmdList, ShaderRHI, CustomDepthTextureNonMS, DepthDefault); - - if (CustomStencilTexture.IsBound()) + else { SetTextureParameter(RHICmdList, ShaderRHI, CustomStencilTexture, BlackDefault2D); } @@ -2837,6 +2797,7 @@ void FDeferredPixelShaderParameters::Set(TRHICmdList& RHICmdList, const ShaderRH TRHICmdList& RHICmdList, \ const ShaderRHIParamRef ShaderRHI, \ const FSceneView& View, \ + EMaterialDomain MaterialDomain, \ ESceneRenderTargetsMode::Type TextureMode \ ) const; diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.h b/Engine/Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.h index 53eb6780e32d..0bd52d90b65a 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.h +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/SceneRenderTargets.h @@ -173,8 +173,6 @@ public: /** Destruct all snapshots */ void DestroyAllSnapshots(); - static TAutoConsoleVariable CVarSetSeperateTranslucencyEnabled; - protected: /** Constructor */ FSceneRenderTargets(): @@ -194,6 +192,7 @@ protected: bUseDownsizedOcclusionQueries(true), CurrentGBufferFormat(0), CurrentSceneColorFormat(0), + CurrentMobileSceneColorFormat(EPixelFormat::PF_Unknown), bAllowStaticLighting(true), CurrentMaxShadowResolution(0), CurrentRSMResolution(0), @@ -246,21 +245,23 @@ public: /** Binds the appropriate shadow depth cube map for rendering. */ void BeginRenderingCubeShadowDepth(FRHICommandList& RHICmdList, int32 ShadowResolution); + /** Begin rendering translucency in the scene color. */ void BeginRenderingTranslucency(FRHICommandList& RHICmdList, const class FViewInfo& View, bool bFirstTimeThisFrame = true); - + /** Begin rendering translucency in a separate (offscreen) buffer. This can be any translucency pass. */ void BeginRenderingSeparateTranslucency(FRHICommandList& RHICmdList, const FViewInfo& View, bool bFirstTimeThisFrame); - void FinishRenderingSeparateTranslucency(FRHICommandList& RHICmdList); + void FinishRenderingSeparateTranslucency(FRHICommandList& RHICmdList, const FViewInfo& View); + void FreeSeparateTranslucency() { SeparateTranslucencyRT.SafeRelease(); check(!SeparateTranslucencyRT); } - void FreeSeparateTranslucencyDepth() + void FreeDownsampledTranslucencyDepth() { - if (SeparateTranslucencyDepthRT.GetReference()) + if (DownsampledTranslucencyDepthRT.GetReference()) { - SeparateTranslucencyDepthRT.SafeRelease(); + DownsampledTranslucencyDepthRT.SafeRelease(); } } @@ -286,24 +287,25 @@ public: DefaultDepthClear = DepthClear; } - void GetSeparateTranslucencyDimensions(FIntPoint& OutScaledSize, float& OutScale) + FORCEINLINE void GetSeparateTranslucencyDimensions(FIntPoint& OutScaledSize, float& OutScale) const { OutScaledSize = SeparateTranslucencyBufferSize; OutScale = SeparateTranslucencyScale; } + /** Separate translucency buffer can be downsampled or not (as it is used to store the AfterDOF translucency) */ TRefCountPtr& GetSeparateTranslucency(FRHICommandList& RHICmdList, FIntPoint Size); - bool IsSeparateTranslucencyDepthValid() + bool IsDownsampledTranslucencyDepthValid() { - return SeparateTranslucencyDepthRT != nullptr; + return DownsampledTranslucencyDepthRT != nullptr; } - TRefCountPtr& GetSeparateTranslucencyDepth(FRHICommandList& RHICmdList, FIntPoint Size); + TRefCountPtr& GetDownsampledTranslucencyDepth(FRHICommandList& RHICmdList, FIntPoint Size); - const FTexture2DRHIRef& GetSeparateTranslucencyDepthSurface() + const FTexture2DRHIRef& GetDownsampledTranslucencyDepthSurface() { - return (const FTexture2DRHIRef&)SeparateTranslucencyDepthRT->GetRenderTargetItem().TargetableTexture; + return (const FTexture2DRHIRef&)DownsampledTranslucencyDepthRT->GetRenderTargetItem().TargetableTexture; } /** @@ -476,6 +478,9 @@ public: TRefCountPtr& GetSceneColor(); EPixelFormat GetSceneColorFormat() const; + EPixelFormat GetDesiredMobileSceneColorFormat() const; + EPixelFormat GetMobileSceneColorFormat() const; + // changes depending at which part of the frame this is called bool IsSceneColorAllocated() const; @@ -514,13 +519,7 @@ public: TRefCountPtr& GetReflectionBrightnessTarget(); - - bool IsSeparateTranslucencyActive(const FViewInfo& View) const; - - bool IsSeparateTranslucencyPass() - { - return bSeparateTranslucencyPass; - } + FORCEINLINE bool IsSeparateTranslucencyPass() const { return bSeparateTranslucencyPass; } // Can be called when the Scene Color content is no longer needed. As we create SceneColor on demand we can make sure it is created with the right format. // (as a call to SetSceneColor() can override it with a different format) @@ -608,7 +607,8 @@ public: /** ONLY for snapshots!!! this is a copy of the SeparateTranslucencyRT from the view state. */ TRefCountPtr SeparateTranslucencyRT; - TRefCountPtr SeparateTranslucencyDepthRT; + /** Downsampled depth used when rendering translucency in smaller resolution. */ + TRefCountPtr DownsampledTranslucencyDepthRT; // todo: free ScreenSpaceAO so pool can reuse bool bScreenSpaceAOIsValid; @@ -729,6 +729,8 @@ private: int32 CurrentGBufferFormat; /** To detect a change of the CVar r.SceneColorFormat */ int32 CurrentSceneColorFormat; + /** To detect a change of the mobile scene color format */ + EPixelFormat CurrentMobileSceneColorFormat; /** Whether render targets were allocated with static lighting allowed. */ bool bAllowStaticLighting; /** To detect a change of the CVar r.Shadow.MaxResolution */ diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/ScreenSpaceReflections.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/ScreenSpaceReflections.cpp index 8632a86540ad..e3d039ace967 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/ScreenSpaceReflections.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/ScreenSpaceReflections.cpp @@ -187,7 +187,7 @@ public: FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); { FLinearColor Value = ComputeSSRParams(Context, SSRQuality, EnableDiscard); @@ -257,7 +257,7 @@ public: FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View.ViewUniformBuffer); PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); { FLinearColor Value = ComputeSSRParams(Context, SSRQuality, false); @@ -376,7 +376,7 @@ void FRCPassPostProcessScreenSpaceReflections::Process(FRenderingCompositePassCo Context.SetViewportAndCallRHI(View.ViewRect); // Clear stencil to 0 - DrawClearQuad(RHICmdList, Context.GetFeatureLevel(), false, FLinearColor(), false, 0, true, 0, PassOutputs[0].RenderTargetDesc.Extent, View.ViewRect); + DrawClearQuad(RHICmdList, false, FLinearColor(), false, 0, true, 0, PassOutputs[0].RenderTargetDesc.Extent, View.ViewRect); FGraphicsPipelineStateInitializer GraphicsPSOInit; RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit); @@ -437,7 +437,7 @@ void FRCPassPostProcessScreenSpaceReflections::Process(FRenderingCompositePassCo RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit); // clear DestRenderTarget only outside of the view's rectangle - DrawClearQuad(RHICmdList, SceneContext.GetCurrentFeatureLevel(), true, FLinearColor::Black, false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, View.ViewRect); + DrawClearQuad(RHICmdList, true, FLinearColor::Black, false, 0, false, 0, PassOutputs[0].RenderTargetDesc.Extent, View.ViewRect); // set the state GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI(); @@ -549,7 +549,7 @@ void RenderScreenSpaceReflections(FRHICommandListImmediate& RHICmdList, FViewInf { { FRenderingCompositeOutputRef HistoryInput; - if( ViewState && ViewState->SSRHistoryRT && !Context.View.bCameraCut ) + if( ViewState->SSRHistoryRT && !Context.View.bCameraCut ) { HistoryInput = Context.Graph.RegisterPass( new FRCPassPostProcessInput( ViewState->SSRHistoryRT ) ); } @@ -568,13 +568,10 @@ void RenderScreenSpaceReflections(FRHICommandListImmediate& RHICmdList, FViewInf Context.FinalOutput = FRenderingCompositeOutputRef( TemporalAAPass ); } - if( ViewState ) - { - FRenderingCompositePass* HistoryOutput = Context.Graph.RegisterPass( new FRCPassPostProcessOutput( &ViewState->SSRHistoryRT ) ); - HistoryOutput->SetInput( ePId_Input0, Context.FinalOutput ); + FRenderingCompositePass* HistoryOutput = Context.Graph.RegisterPass( new FRCPassPostProcessOutput( &ViewState->SSRHistoryRT ) ); + HistoryOutput->SetInput( ePId_Input0, Context.FinalOutput ); - Context.FinalOutput = FRenderingCompositeOutputRef( HistoryOutput ); - } + Context.FinalOutput = FRenderingCompositeOutputRef( HistoryOutput ); } { diff --git a/Engine/Source/Runtime/Renderer/Private/PostProcess/VisualizeShadingModels.cpp b/Engine/Source/Runtime/Renderer/Private/PostProcess/VisualizeShadingModels.cpp index a718d0eef0d4..d0b53e12050e 100644 --- a/Engine/Source/Runtime/Renderer/Private/PostProcess/VisualizeShadingModels.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PostProcess/VisualizeShadingModels.cpp @@ -56,7 +56,7 @@ public: PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); - DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); + DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View, MD_PostProcess); static FLinearColor SoftBits[sizeof(InShadingModelMaskInView) * 8] = {}; // init with 0.0f diff --git a/Engine/Source/Runtime/Renderer/Private/PrimitiveSceneInfo.cpp b/Engine/Source/Runtime/Renderer/Private/PrimitiveSceneInfo.cpp index 843268de3a29..8991b4b43a06 100644 --- a/Engine/Source/Runtime/Renderer/Private/PrimitiveSceneInfo.cpp +++ b/Engine/Source/Runtime/Renderer/Private/PrimitiveSceneInfo.cpp @@ -64,7 +64,14 @@ private: TRefCountPtr CurrentHitProxy; }; -void FPrimitiveSceneInfoCompact::Init(FPrimitiveSceneInfo* InPrimitiveSceneInfo) +FPrimitiveFlagsCompact::FPrimitiveFlagsCompact(const FPrimitiveSceneProxy* Proxy) + : bCastDynamicShadow(Proxy->CastsDynamicShadow()) + , bStaticLighting(Proxy->HasStaticLighting()) + , bCastStaticShadow(Proxy->CastsStaticShadow()) +{} + +FPrimitiveSceneInfoCompact::FPrimitiveSceneInfoCompact(FPrimitiveSceneInfo* InPrimitiveSceneInfo) : + PrimitiveFlagsCompact(InPrimitiveSceneInfo->Proxy) { PrimitiveSceneInfo = InPrimitiveSceneInfo; Proxy = PrimitiveSceneInfo->Proxy; @@ -73,14 +80,6 @@ void FPrimitiveSceneInfoCompact::Init(FPrimitiveSceneInfo* InPrimitiveSceneInfo) MaxDrawDistance = PrimitiveSceneInfo->Proxy->GetMaxDrawDistance(); VisibilityId = PrimitiveSceneInfo->Proxy->GetVisibilityId(); - - bHasViewDependentDPG = Proxy->HasViewDependentDPG(); - bCastDynamicShadow = PrimitiveSceneInfo->Proxy->CastsDynamicShadow(); - - bAffectDynamicIndirectLighting = PrimitiveSceneInfo->Proxy->AffectsDynamicIndirectLighting(); - LpvBiasMultiplier = PrimitiveSceneInfo->Proxy->GetLpvBiasMultiplier(); - - StaticDepthPriorityGroup = bHasViewDependentDPG ? 0 : Proxy->GetStaticDepthPriorityGroup(); } FPrimitiveSceneInfo::FPrimitiveSceneInfo(UPrimitiveComponent* InComponent,FScene* InScene): @@ -158,6 +157,12 @@ void FPrimitiveSceneInfo::AddStaticMeshes(FRHICommandListImmediate& RHICmdList) Scene->StaticMeshes[SceneArrayAllocation.Index] = &Mesh; Mesh.Id = SceneArrayAllocation.Index; + if (Mesh.bRequiresPerElementVisibility) + { + // Use a separate index into StaticMeshBatchVisibility, since most meshes don't use it + Mesh.BatchVisibilityId = Scene->StaticMeshBatchVisibility.AddUninitialized().Index; + } + // By this point, the index buffer render resource must be initialized // Add the static mesh to the appropriate draw lists. Mesh.AddToDrawLists(RHICmdList, Scene); @@ -196,16 +201,11 @@ void FPrimitiveSceneInfo::AddToScene(FRHICommandListImmediate& RHICmdList, bool } // create potential storage for our compact info - FPrimitiveSceneInfoCompact LocalCompactPrimitiveSceneInfo; - FPrimitiveSceneInfoCompact* CompactPrimitiveSceneInfo = &LocalCompactPrimitiveSceneInfo; - - // if we are being added directly to the Octree, initialize the temp compact scene info, - // and let the Octree make a copy of it - LocalCompactPrimitiveSceneInfo.Init(this); + FPrimitiveSceneInfoCompact CompactPrimitiveSceneInfo(this); // Add the primitive to the octree. check(!OctreeId.IsValidId()); - Scene->PrimitiveOctree.AddElement(LocalCompactPrimitiveSceneInfo); + Scene->PrimitiveOctree.AddElement(CompactPrimitiveSceneInfo); check(OctreeId.IsValidId()); if (Proxy->CastsDynamicIndirectShadow()) @@ -213,15 +213,17 @@ void FPrimitiveSceneInfo::AddToScene(FRHICommandListImmediate& RHICmdList, bool Scene->DynamicIndirectCasterPrimitives.Add(this); } + Scene->PrimitiveSceneProxies[PackedIndex] = Proxy; + // Set bounds. FPrimitiveBounds& PrimitiveBounds = Scene->PrimitiveBounds[PackedIndex]; FBoxSphereBounds BoxSphereBounds = Proxy->GetBounds(); - PrimitiveBounds.Origin = BoxSphereBounds.Origin; - PrimitiveBounds.SphereRadius = BoxSphereBounds.SphereRadius; - PrimitiveBounds.BoxExtent = BoxSphereBounds.BoxExtent; + PrimitiveBounds.BoxSphereBounds = BoxSphereBounds; PrimitiveBounds.MinDrawDistanceSq = FMath::Square(Proxy->GetMinDrawDistance()); PrimitiveBounds.MaxDrawDistance = Proxy->GetMaxDrawDistance(); + Scene->PrimitiveFlagsCompact[PackedIndex] = FPrimitiveFlagsCompact(Proxy); + // Store precomputed visibility ID. int32 VisibilityBitIndex = Proxy->GetVisibilityId(); FPrimitiveVisibilityId& VisibilityId = Scene->PrimitiveVisibilityIds[PackedIndex]; @@ -276,7 +278,7 @@ void FPrimitiveSceneInfo::AddToScene(FRHICommandListImmediate& RHICmdList, bool LightIt.Advance()) { const FLightSceneInfoCompact& LightSceneInfoCompact = LightIt.GetCurrentElement(); - if (LightSceneInfoCompact.AffectsPrimitive(*CompactPrimitiveSceneInfo)) + if (LightSceneInfoCompact.AffectsPrimitive(CompactPrimitiveSceneInfo.Bounds, CompactPrimitiveSceneInfo.Proxy)) { FLightPrimitiveInteraction::Create(LightSceneInfoCompact.LightSceneInfo,this); } diff --git a/Engine/Source/Runtime/Renderer/Private/ReflectionEnvironment.cpp b/Engine/Source/Runtime/Renderer/Private/ReflectionEnvironment.cpp index b123b94c5b5d..24e79187e8d1 100644 --- a/Engine/Source/Runtime/Renderer/Private/ReflectionEnvironment.cpp +++ b/Engine/Source/Runtime/Renderer/Private/ReflectionEnvironment.cpp @@ -25,7 +25,7 @@ #include "PostProcess/PostProcessing.h" #include "PostProcess/ScreenSpaceReflections.h" #include "LightRendering.h" -#include "LightPropagationVolumeBlendable.h" +#include "LightPropagationVolumeSettings.h" #include "PipelineStateCache.h" DECLARE_FLOAT_COUNTER_STAT(TEXT("Reflection Environment"), Stat_GPU_ReflectionEnvironment, STATGROUP_GPU); @@ -209,7 +209,8 @@ void FReflectionEnvironmentSceneData::ResizeCubemapArrayGPU(uint32 InMaxCubemaps int32 Count = 0; for (int i = 0; i < CubemapArray.GetMaxCubemaps(); i++) { - if (CubemapArraySlotsUsed[i] ) + bool bUsed = i < CubemapArraySlotsUsed.Num() ? CubemapArraySlotsUsed[i] : false; + if (bUsed) { IndexRemapping.Add(Count); Count++; @@ -436,8 +437,9 @@ public: { } + template void SetParameters( - FRHIAsyncComputeCommandListImmediate& RHICmdList, + TRHICommandList& RHICmdList, const FViewInfo& View, FTextureRHIParamRef SSRTexture, FUnorderedAccessViewRHIParamRef OutSceneColorUAV, @@ -447,7 +449,7 @@ public: const FComputeShaderRHIParamRef ShaderRHI = GetComputeShader(); FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View.ViewUniformBuffer); - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_PostProcess); FScene* Scene = (FScene*)View.Family->Scene; @@ -487,7 +489,8 @@ public: ForwardLightingParameters.Set(RHICmdList, ShaderRHI, View); } - void UnsetParameters(FRHIAsyncComputeCommandListImmediate& RHICmdList, FUnorderedAccessViewRHIParamRef OutSceneColorUAV) + template + void UnsetParameters(TRHICommandList& RHICmdList, FUnorderedAccessViewRHIParamRef OutSceneColorUAV) { const FComputeShaderRHIParamRef ShaderRHI = GetComputeShader(); OutSceneColor.UnsetUAV(RHICmdList, ShaderRHI); @@ -640,7 +643,7 @@ public: const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader(); FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View.ViewUniformBuffer); - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_PostProcess); SkyLightParameters.SetParameters(RHICmdList, ShaderRHI, (FScene*)View.Family->Scene, true); SetTextureParameter(RHICmdList, ShaderRHI, ReflectionEnvTexture, ReflectionEnvSampler, TStaticSamplerState::GetRHI(), ReflectionEnv ); @@ -738,7 +741,7 @@ public: FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View.ViewUniformBuffer); - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_PostProcess); } // FShader interface. @@ -811,7 +814,7 @@ public: SetTextureParameter(RHICmdList, ShaderRHI, ReflectionEnvironmentColorTexture, ReflectionEnvironmentColorSampler, TStaticSamplerState::GetRHI(), SortData.SM4FullHDRCubemap->TextureRHI); } - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_PostProcess); SetShaderValue(RHICmdList, ShaderRHI, CapturePositionAndRadius, SortData.PositionAndRadius); SetShaderValue(RHICmdList, ShaderRHI, CaptureProperties, SortData.CaptureProperties); SetShaderValue(RHICmdList, ShaderRHI, CaptureBoxTransform, SortData.BoxTransform); @@ -1153,24 +1156,26 @@ void FDeferredShadingSceneRenderer::RenderTiledDeferredImageBasedReflections(FRH static const FName TiledReflBeginComputeName(TEXT("ReflectionEnvBeginComputeFence")); static const FName TiledReflEndComputeName(TEXT("ReflectionEnvEndComputeFence")); - FComputeFenceRHIRef ReflectionBeginFence = RHICmdList.CreateComputeFence(TiledReflBeginComputeName); - FComputeFenceRHIRef ReflectionEndFence = RHICmdList.CreateComputeFence(TiledReflEndComputeName); + //FComputeFenceRHIRef ReflectionBeginFence = RHICmdList.CreateComputeFence(TiledReflBeginComputeName); + //FComputeFenceRHIRef ReflectionEndFence = RHICmdList.CreateComputeFence(TiledReflEndComputeName); //Grab the async compute commandlist. - FRHIAsyncComputeCommandListImmediate& RHICmdListComputeImmediate = FRHICommandListExecutor::GetImmediateAsyncComputeCommandList(); + //FRHIAsyncComputeCommandListImmediate& RHICmdListComputeImmediate = FRHICommandListExecutor::GetImmediateAsyncComputeCommandList(); + auto& RHICmdListComputeImmediate = RHICmdList; { - SCOPED_COMPUTE_EVENTF(RHICmdListComputeImmediate, ReflectionEnvironment, TEXT("ReflectionEnvironment ComputeShader %dx%d Tile:%dx%d Box:%d Sphere:%d SkyLight:%d"), + /*SCOPED_COMPUTE_EVENTF(RHICmdListComputeImmediate, ReflectionEnvironment, TEXT("ReflectionEnvironment ComputeShader %dx%d Tile:%dx%d Box:%d Sphere:%d SkyLight:%d"), View.ViewRect.Width(), View.ViewRect.Height(), GReflectionEnvironmentTileSizeX, GReflectionEnvironmentTileSizeY, View.NumBoxReflectionCaptures, View.NumSphereReflectionCaptures, bHasSkyLight); + */ ComputeShader = SelectReflectionEnvironmentTiledDeferredCS(View.ShaderMap, bUseLightmaps, bHasSkyLight, bHasBoxCaptures, bHasSphereCaptures, DynamicBentNormalAO != NULL); //Really we should write this fence where we transition the final depedency for the reflections. We may add an RHI command just for writing fences if this //can't be done in the general case. In the meantime, hack this command a bit to write the fence. - RHICmdList.TransitionResources(EResourceTransitionAccess::EReadable, EResourceTransitionPipeline::EGfxToCompute, nullptr, 0, ReflectionBeginFence); + //RHICmdList.TransitionResources(EResourceTransitionAccess::EReadable, EResourceTransitionPipeline::EGfxToCompute, nullptr, 0, ReflectionBeginFence); //we must wait on the fence written from the Gfx pipe to let us know all our dependencies are ready. - RHICmdListComputeImmediate.WaitComputeFence(ReflectionBeginFence); + //RHICmdListComputeImmediate.WaitComputeFence(ReflectionBeginFence); //standard compute setup, but on the async commandlist. RHICmdListComputeImmediate.SetComputeShader(ComputeShader->GetComputeShader()); @@ -1185,15 +1190,15 @@ void FDeferredShadingSceneRenderer::RenderTiledDeferredImageBasedReflections(FRH ComputeShader->UnsetParameters(RHICmdListComputeImmediate, OutUAV); //transition the output to readable and write the fence to allow the Gfx pipe to carry on. - RHICmdListComputeImmediate.TransitionResources(EResourceTransitionAccess::EReadable, EResourceTransitionPipeline::EComputeToGfx, &OutUAV, 1, ReflectionEndFence); + RHICmdListComputeImmediate.TransitionResources(EResourceTransitionAccess::EReadable, EResourceTransitionPipeline::EComputeToGfx, &OutUAV, 1);// , ReflectionEndFence); } //immediately dispatch our async compute commands to the RHI thread to be submitted to the GPU as soon as possible. //dispatch after the scope so the drawevent pop is inside the dispatch - FRHIAsyncComputeCommandListImmediate::ImmediateDispatch(RHICmdListComputeImmediate); + //FRHIAsyncComputeCommandListImmediate::ImmediateDispatch(RHICmdListComputeImmediate); //Gfx pipe must wait for the async compute reflection job to complete. - RHICmdList.WaitComputeFence(ReflectionEndFence); + //RHICmdList.WaitComputeFence(ReflectionEndFence); } } diff --git a/Engine/Source/Runtime/Renderer/Private/ReflectionEnvironmentCapture.cpp b/Engine/Source/Runtime/Renderer/Private/ReflectionEnvironmentCapture.cpp index f52a53c83f86..290fd823f506 100644 --- a/Engine/Source/Runtime/Renderer/Private/ReflectionEnvironmentCapture.cpp +++ b/Engine/Source/Runtime/Renderer/Private/ReflectionEnvironmentCapture.cpp @@ -33,6 +33,7 @@ #include "ReflectionEnvironment.h" #include "OneColorShader.h" #include "PipelineStateCache.h" +#include "MobileReflectionEnvironmentCapture.h" /** Near plane to use when capturing the scene. */ float GReflectionCaptureNearPlane = 5; @@ -91,67 +92,8 @@ void FullyResolveReflectionScratchCubes(FRHICommandListImmediate& RHICmdList) RHICmdList.CopyToResolveTarget(Scratch1, Scratch1, true, ResolveParams); } -/** Pixel shader used for filtering a mip. */ -class FCubeFilterPS : public FGlobalShader -{ - DECLARE_SHADER_TYPE(FCubeFilterPS,Global); -public: - - static bool ShouldCache(EShaderPlatform Platform) - { - return true; - } - - FCubeFilterPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer): - FGlobalShader(Initializer) - { - CubeFace.Bind(Initializer.ParameterMap,TEXT("CubeFace")); - MipIndex.Bind(Initializer.ParameterMap,TEXT("MipIndex")); - NumMips.Bind(Initializer.ParameterMap,TEXT("NumMips")); - SourceTexture.Bind(Initializer.ParameterMap,TEXT("SourceTexture")); - SourceTextureSampler.Bind(Initializer.ParameterMap,TEXT("SourceTextureSampler")); - } - FCubeFilterPS() {} - - virtual bool Serialize(FArchive& Ar) override - { - bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar); - Ar << CubeFace; - Ar << MipIndex; - Ar << NumMips; - Ar << SourceTexture; - Ar << SourceTextureSampler; - return bShaderHasOutdatedParameters; - } - - FShaderParameter CubeFace; - FShaderParameter MipIndex; - FShaderParameter NumMips; - FShaderResourceParameter SourceTexture; - FShaderResourceParameter SourceTextureSampler; -}; - IMPLEMENT_SHADER_TYPE(,FCubeFilterPS,TEXT("ReflectionEnvironmentShaders"),TEXT("DownsamplePS"),SF_Pixel); -template< uint32 bNormalize > -class TCubeFilterPS : public FCubeFilterPS -{ - DECLARE_SHADER_TYPE(TCubeFilterPS,Global); - -public: - static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment) - { - FCubeFilterPS::ModifyCompilationEnvironment(Platform, OutEnvironment); - OutEnvironment.SetDefine(TEXT("NORMALIZE"), bNormalize); - } - - TCubeFilterPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) - : FCubeFilterPS(Initializer) - {} - - TCubeFilterPS() {} -}; - IMPLEMENT_SHADER_TYPE(template<>,TCubeFilterPS<0>,TEXT("ReflectionEnvironmentShaders"),TEXT("FilterPS"),SF_Pixel); IMPLEMENT_SHADER_TYPE(template<>,TCubeFilterPS<1>,TEXT("ReflectionEnvironmentShaders"),TEXT("FilterPS"),SF_Pixel); @@ -184,12 +126,11 @@ public: { } - void SetParameters(FRHICommandList& RHICmdList, int32 TargetSize) + void SetParameters(FRHICommandList& RHICmdList, int32 TargetSize, FSceneRenderTargetItem& Cubemap) { const int32 EffectiveTopMipSize = TargetSize; const int32 NumMips = FMath::CeilLogTwo(EffectiveTopMipSize) + 1; // Read from the smallest mip that was downsampled to - FSceneRenderTargetItem& Cubemap = FSceneRenderTargets::Get(RHICmdList).ReflectionColorScratchCubemap[0]->GetRenderTargetItem(); if (Cubemap.IsValid()) { @@ -246,6 +187,10 @@ void CreateCubeMips( FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Typ SetRenderTarget(RHICmdList, Cubemap.TargetableTexture, MipIndex, CubeFace, NULL, true); RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit); + //this is a weired place but at the end of the scope it will not be good enough as SetRendertarget sets it to writable + //Use ERWSubResBarrier since we don't transition individual subresources. Basically treat the whole texture as R/W as we walk down the mip chain. + RHICmdList.TransitionResources(EResourceTransitionAccess::ERWSubResBarrier, &CubeRef, 1); + const FIntRect ViewRect(0, 0, MipSize, MipSize); RHICmdList.SetViewport(0, 0, 0.0f, MipSize, MipSize, 1.0f); @@ -281,15 +226,13 @@ void CreateCubeMips( FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Typ FIntPoint(ViewRect.Width(), ViewRect.Height()), FIntPoint(MipSize, MipSize), *VertexShader); - - //Use ERWSubResBarrier since we don't transition individual subresources. Basically treat the whole texture as R/W as we walk down the mip chain. - RHICmdList.TransitionResources(EResourceTransitionAccess::ERWSubResBarrier, &CubeRef, 1); } } + RHICmdList.TransitionResources(EResourceTransitionAccess::EReadable, &CubeRef, 1); } /** Computes the average brightness of the given reflection capture and stores it in the scene. */ -float ComputeSingleAverageBrightnessFromCubemap(FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, int32 TargetSize) +float ComputeSingleAverageBrightnessFromCubemap(FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, int32 TargetSize, FSceneRenderTargetItem& Cubemap) { SCOPED_DRAW_EVENT(RHICmdList, ComputeSingleAverageBrightnessFromCubemap); @@ -317,7 +260,7 @@ float ComputeSingleAverageBrightnessFromCubemap(FRHICommandListImmediate& RHICmd SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit); - PixelShader->SetParameters(RHICmdList, TargetSize); + PixelShader->SetParameters(RHICmdList, TargetSize, Cubemap); DrawRectangle( RHICmdList, @@ -354,7 +297,7 @@ void ComputeAverageBrightness(FRHICommandListImmediate& RHICmdList, ERHIFeatureL FSceneRenderTargetItem& DownSampledCube = FSceneRenderTargets::Get(RHICmdList).ReflectionColorScratchCubemap[0]->GetRenderTargetItem(); CreateCubeMips( RHICmdList, FeatureLevel, NumMips, DownSampledCube ); - OutAverageBrightness = ComputeSingleAverageBrightnessFromCubemap(RHICmdList, FeatureLevel, CubmapSize); + OutAverageBrightness = ComputeSingleAverageBrightnessFromCubemap(RHICmdList, FeatureLevel, CubmapSize, DownSampledCube); } /** Generates mips for glossiness and filters the cubemap for a given reflection. */ @@ -558,7 +501,7 @@ public: const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader(); FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View.ViewUniformBuffer); - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_PostProcess); SetTextureParameter( RHICmdList, @@ -1522,7 +1465,7 @@ void FScene::UpdateReflectionCaptureContents(UReflectionCaptureComponent* Captur // Clean up the proxy now that the rendering thread is done with it delete ReflectionProxy; }); - } + } //-V773 } } @@ -1551,7 +1494,7 @@ void CopyToSkyTexture(FRHICommandList& RHICmdList, FScene* Scene, FTexture* Proc // Warning: returns before writes to OutIrradianceEnvironmentMap have completed, as they are queued on the rendering thread void FScene::UpdateSkyCaptureContents(const USkyLightComponent* CaptureComponent, bool bCaptureEmissiveOnly, UTextureCube* SourceCubemap, FTexture* OutProcessedTexture, float& OutAverageBrightness, FSHVectorRGB3& OutIrradianceEnvironmentMap) { - if (GetFeatureLevel() >= ERHIFeatureLevel::SM4) + if (GSupportsRenderTargetFormat_PF_FloatRGBA || GetFeatureLevel() >= ERHIFeatureLevel::SM4) { QUICK_SCOPE_CYCLE_COUNTER(STAT_UpdateSkyCaptureContents); { @@ -1600,19 +1543,35 @@ void FScene::UpdateSkyCaptureContents(const USkyLightComponent* CaptureComponent FSHVectorRGB3*, IrradianceEnvironmentMap, &OutIrradianceEnvironmentMap, ERHIFeatureLevel::Type, FeatureLevel, GetFeatureLevel(), { - ComputeAverageBrightness(RHICmdList, FeatureLevel, CubemapSize, AverageBrightness); - FilterReflectionEnvironment(RHICmdList, FeatureLevel, CubemapSize, IrradianceEnvironmentMap); + if (FeatureLevel <= ERHIFeatureLevel::ES3_1) + { + MobileReflectionEnvironmentCapture::ComputeAverageBrightness(RHICmdList, FeatureLevel, CubemapSize, AverageBrightness); + MobileReflectionEnvironmentCapture::FilterReflectionEnvironment(RHICmdList, FeatureLevel, CubemapSize, IrradianceEnvironmentMap); + } + else + { + ComputeAverageBrightness(RHICmdList, FeatureLevel, CubemapSize, AverageBrightness); + FilterReflectionEnvironment(RHICmdList, FeatureLevel, CubemapSize, IrradianceEnvironmentMap); + } }); // Optionally copy the filtered mip chain to the output texture if (OutProcessedTexture) { - ENQUEUE_UNIQUE_RENDER_COMMAND_TWOPARAMETER( + ENQUEUE_UNIQUE_RENDER_COMMAND_THREEPARAMETER( CopyCommand, FScene*, Scene, this, FTexture*, ProcessedTexture, OutProcessedTexture, + ERHIFeatureLevel::Type, FeatureLevel, GetFeatureLevel(), { - CopyToSkyTexture(RHICmdList, Scene, ProcessedTexture); + if (FeatureLevel <= ERHIFeatureLevel::ES3_1) + { + MobileReflectionEnvironmentCapture::CopyToSkyTexture(RHICmdList, Scene, ProcessedTexture); + } + else + { + CopyToSkyTexture(RHICmdList, Scene, ProcessedTexture); + } }); } } diff --git a/Engine/Source/Runtime/Renderer/Private/ReflectionEnvironmentCapture.h b/Engine/Source/Runtime/Renderer/Private/ReflectionEnvironmentCapture.h index 24989d92b8be..620ea152243a 100644 --- a/Engine/Source/Runtime/Renderer/Private/ReflectionEnvironmentCapture.h +++ b/Engine/Source/Runtime/Renderer/Private/ReflectionEnvironmentCapture.h @@ -9,5 +9,64 @@ #include "CoreMinimal.h" #include "Math/SHMath.h" #include "RHI.h" +#include "GlobalShader.h" extern void ComputeDiffuseIrradiance(FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, FTextureRHIRef LightingSource, int32 LightingSourceMipIndex, FSHVectorRGB3* OutIrradianceEnvironmentMap); + +/** Pixel shader used for filtering a mip. */ +class FCubeFilterPS : public FGlobalShader +{ + DECLARE_SHADER_TYPE(FCubeFilterPS, Global); +public: + + static bool ShouldCache(EShaderPlatform Platform) + { + return true; + } + + FCubeFilterPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) : + FGlobalShader(Initializer) + { + CubeFace.Bind(Initializer.ParameterMap, TEXT("CubeFace")); + MipIndex.Bind(Initializer.ParameterMap, TEXT("MipIndex")); + NumMips.Bind(Initializer.ParameterMap, TEXT("NumMips")); + SourceTexture.Bind(Initializer.ParameterMap, TEXT("SourceTexture")); + SourceTextureSampler.Bind(Initializer.ParameterMap, TEXT("SourceTextureSampler")); + } + FCubeFilterPS() {} + + virtual bool Serialize(FArchive& Ar) override + { + bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar); + Ar << CubeFace; + Ar << MipIndex; + Ar << NumMips; + Ar << SourceTexture; + Ar << SourceTextureSampler; + return bShaderHasOutdatedParameters; + } + + FShaderParameter CubeFace; + FShaderParameter MipIndex; + FShaderParameter NumMips; + FShaderResourceParameter SourceTexture; + FShaderResourceParameter SourceTextureSampler; +}; + +template< uint32 bNormalize > +class TCubeFilterPS : public FCubeFilterPS +{ + DECLARE_SHADER_TYPE(TCubeFilterPS, Global); +public: + static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment) + { + FCubeFilterPS::ModifyCompilationEnvironment(Platform, OutEnvironment); + OutEnvironment.SetDefine(TEXT("NORMALIZE"), bNormalize); + } + + TCubeFilterPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) + : FCubeFilterPS(Initializer) + {} + + TCubeFilterPS() {} +}; \ No newline at end of file diff --git a/Engine/Source/Runtime/Renderer/Private/Renderer.cpp b/Engine/Source/Runtime/Renderer/Private/Renderer.cpp index c0b0f38533fd..35aaf75a5254 100644 --- a/Engine/Source/Runtime/Renderer/Private/Renderer.cpp +++ b/Engine/Source/Runtime/Renderer/Private/Renderer.cpp @@ -101,6 +101,8 @@ void FRendererModule::DrawTileMesh(FRHICommandListImmediate& RHICmdList, FDrawin GMinimalDummyForwardLightingResources = new TGlobalResource(); } + FMaterialRenderProxy::UpdateDeferredCachedUniformExpressions(); + //Apply the minimal forward lighting resources View.ForwardLightingResources = &GMinimalDummyForwardLightingResources->ForwardLightingResources; diff --git a/Engine/Source/Runtime/Renderer/Private/RendererScene.cpp b/Engine/Source/Runtime/Renderer/Private/RendererScene.cpp index 768235b0e2fc..2b5370ce2c50 100644 --- a/Engine/Source/Runtime/Renderer/Private/RendererScene.cpp +++ b/Engine/Source/Runtime/Renderer/Private/RendererScene.cpp @@ -474,7 +474,9 @@ SIZE_T FScene::GetSizeBytes() const void FScene::CheckPrimitiveArrays() { + check(Primitives.Num() == PrimitiveSceneProxies.Num()); check(Primitives.Num() == PrimitiveBounds.Num()); + check(Primitives.Num() == PrimitiveFlagsCompact.Num()); check(Primitives.Num() == PrimitiveVisibilityIds.Num()); check(Primitives.Num() == PrimitiveOcclusionFlags.Num()); check(Primitives.Num() == PrimitiveComponentIds.Num()); @@ -490,7 +492,9 @@ void FScene::AddPrimitiveSceneInfo_RenderThread(FRHICommandListImmediate& RHICmd int32 PrimitiveIndex = Primitives.Add(PrimitiveSceneInfo); PrimitiveSceneInfo->PackedIndex = PrimitiveIndex; + PrimitiveSceneProxies.AddUninitialized(); PrimitiveBounds.AddUninitialized(); + PrimitiveFlagsCompact.AddUninitialized(); PrimitiveVisibilityIds.AddUninitialized(); PrimitiveOcclusionFlags.AddUninitialized(); PrimitiveComponentIds.AddUninitialized(); @@ -546,7 +550,7 @@ FReadOnlyCVARCache::FReadOnlyCVARCache() static const auto CVarSupportPointLightWholeSceneShadows = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.SupportPointLightWholeSceneShadows")); static const auto CVarSupportAllShaderPermutations = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.SupportAllShaderPermutations")); static const auto CVarVertexFoggingForOpaque = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.VertexFoggingForOpaque")); - static const auto CVarForwardShading = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.ForwardShading")); + static const auto CVarForwardShading = IConsoleManager::Get().FindConsoleVariable(TEXT("r.ForwardShading")); static const auto CVarAllowStaticLighting = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.AllowStaticLighting")); static const auto CVarMobileAllowMovableDirectionalLights = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.Mobile.AllowMovableDirectionalLights")); @@ -571,7 +575,7 @@ FReadOnlyCVARCache::FReadOnlyCVARCache() NumMobileMovablePointLights = CVarMobileNumDynamicPointLights->GetValueOnAnyThread(); // Only enable VertexFoggingForOpaque if ForwardShading is enabled - const bool bForwardShading = CVarForwardShading && CVarForwardShading->GetValueOnAnyThread() != 0; + const bool bForwardShading = CVarForwardShading && CVarForwardShading->GetInt() != 0; bEnableVertexFoggingForOpaque = bForwardShading && ( !CVarVertexFoggingForOpaque || CVarVertexFoggingForOpaque->GetValueOnAnyThread() != 0 ); const bool bShowMissmatchedLowQualityLightmapsWarning = (!bEnableLowQualityLightmaps) && (GEngine->bShouldGenerateLowQualityLightmaps_DEPRECATED); @@ -956,7 +960,9 @@ void FScene::RemovePrimitiveSceneInfo_RenderThread(FPrimitiveSceneInfo* Primitiv int32 PrimitiveIndex = PrimitiveSceneInfo->PackedIndex; Primitives.RemoveAtSwap(PrimitiveIndex); + PrimitiveSceneProxies.RemoveAtSwap(PrimitiveIndex); PrimitiveBounds.RemoveAtSwap(PrimitiveIndex); + PrimitiveFlagsCompact.RemoveAtSwap(PrimitiveIndex); PrimitiveVisibilityIds.RemoveAtSwap(PrimitiveIndex); PrimitiveOcclusionFlags.RemoveAtSwap(PrimitiveIndex); PrimitiveComponentIds.RemoveAtSwap(PrimitiveIndex); @@ -1182,7 +1188,7 @@ void FScene::AddLight(ULightComponent* Light) Light->SceneProxy = Proxy; // Update the light's transform and position. - Proxy->SetTransform(Light->ComponentToWorld.ToMatrixNoScale(),Light->GetLightPosition()); + Proxy->SetTransform(Light->GetComponentTransform().ToMatrixNoScale(),Light->GetLightPosition()); // Create the light scene info. Proxy->LightSceneInfo = new FLightSceneInfo(Proxy, true); @@ -1215,7 +1221,7 @@ void FScene::AddInvisibleLight(ULightComponent* Light) Light->SceneProxy = Proxy; // Update the light's transform and position. - Proxy->SetTransform(Light->ComponentToWorld.ToMatrixNoScale(),Light->GetLightPosition()); + Proxy->SetTransform(Light->GetComponentTransform().ToMatrixNoScale(),Light->GetLightPosition()); // Create the light scene info. Proxy->LightSceneInfo = new FLightSceneInfo(Proxy, false); @@ -1436,7 +1442,7 @@ void FScene::UpdateReflectionCaptureTransform(UReflectionCaptureComponent* Compo ENQUEUE_UNIQUE_RENDER_COMMAND_FOURPARAMETER( UpdateTransformCommand, FReflectionCaptureProxy*,Proxy,Component->SceneProxy, - FMatrix,Transform,Component->ComponentToWorld.ToMatrixWithScale(), + FMatrix,Transform,Component->GetComponentTransform().ToMatrixWithScale(), const float*,AverageBrightness,Component->GetAverageBrightnessPtr(), FScene*,Scene,this, { @@ -1503,7 +1509,7 @@ const FReflectionCaptureProxy* FScene::FindClosestReflectionCapture(FVector Posi return ClosestCaptureIndex != INDEX_NONE ? ReflectionSceneData.RegisteredReflectionCaptures[ClosestCaptureIndex] : NULL; } -const FPlanarReflectionSceneProxy* FScene::FindClosestPlanarReflection(const FPrimitiveBounds& Bounds) const +const FPlanarReflectionSceneProxy* FScene::FindClosestPlanarReflection(const FBoxSphereBounds& Bounds) const { checkSlow(IsInParallelRenderingThread()); const FPlanarReflectionSceneProxy* ClosestPlanarReflection = NULL; @@ -1696,7 +1702,7 @@ void FScene::UpdateLightTransform(ULightComponent* Light) if(Light->SceneProxy) { FUpdateLightTransformParameters Parameters; - Parameters.LightToWorld = Light->ComponentToWorld.ToMatrixNoScale(); + Parameters.LightToWorld = Light->GetComponentTransform().ToMatrixNoScale(); Parameters.Position = Light->GetLightPosition(); ENQUEUE_UNIQUE_RENDER_COMMAND_THREEPARAMETER( UpdateLightTransform, @@ -2711,7 +2717,7 @@ void FScene::ApplyWorldOffset_RenderThread(FVector InOffset) // Primitive bounds for (auto It = PrimitiveBounds.CreateIterator(); It; ++It) { - (*It).Origin+= InOffset; + (*It).BoxSphereBounds.Origin+= InOffset; } // Primitive occlusion bounds @@ -2785,7 +2791,7 @@ void FScene::OnLevelAddedToWorld(FName LevelAddedName, UWorld* InWorld, bool bIs { if (bIsLightingScenario) { - InWorld->PropagateLightingScenarioChange(); + InWorld->PropagateLightingScenarioChange(true); } ENQUEUE_UNIQUE_RENDER_COMMAND_TWOPARAMETER( @@ -2818,7 +2824,7 @@ void FScene::OnLevelRemovedFromWorld(UWorld* InWorld, bool bIsLightingScenario) { if (bIsLightingScenario) { - InWorld->PropagateLightingScenarioChange(); + InWorld->PropagateLightingScenarioChange(false); } } @@ -3236,7 +3242,7 @@ bool FLatentGPUTimer::Tick(FRHICommandListImmediate& RHICmdList) if (StartQueries[QueryIndex] && EndQueries[QueryIndex]) { - if (GRHIThread) + if (IsRunningRHIInSeparateThread()) { // Block until the RHI thread has processed the previous query commands, if necessary // Stat disabled since we buffer 2 frames minimum, it won't actually block @@ -3308,7 +3314,7 @@ void FLatentGPUTimer::End(FRHICommandListImmediate& RHICmdList) // for these query results on some platforms. RHICmdList.SubmitCommandsHint(); - if (GRHIThread) + if (IsRunningRHIInSeparateThread()) { int32 NumFrames = NumBufferedFrames; for (int32 Dest = 1; Dest < NumFrames; Dest++) diff --git a/Engine/Source/Runtime/Renderer/Private/SceneCaptureRendering.cpp b/Engine/Source/Runtime/Renderer/Private/SceneCaptureRendering.cpp index a1bff350261f..140bb7f11d6e 100644 --- a/Engine/Source/Runtime/Renderer/Private/SceneCaptureRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/SceneCaptureRendering.cpp @@ -83,7 +83,7 @@ public: void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View) { FGlobalShader::SetParameters(RHICmdList, GetPixelShader(), View.ViewUniformBuffer); - DeferredParameters.Set(RHICmdList, GetPixelShader(), View); + DeferredParameters.Set(RHICmdList, GetPixelShader(), View, MD_PostProcess); } virtual bool Serialize(FArchive& Ar) override @@ -254,7 +254,7 @@ static void UpdateSceneCaptureContentDeferred_RenderThread( FIntRect ViewRect = View.ViewRect; FIntRect UnconstrainedViewRect = View.UnconstrainedViewRect; SetRenderTarget(RHICmdList, Target->GetRenderTargetTexture(), nullptr, true); - DrawClearQuad(RHICmdList, SceneRenderer->FeatureLevel, true, FLinearColor::Black, false, 0, false, 0, Target->GetSizeXY(), ViewRect); + DrawClearQuad(RHICmdList, true, FLinearColor::Black, false, 0, false, 0, Target->GetSizeXY(), ViewRect); // Render the scene normally { @@ -278,8 +278,10 @@ static void UpdateSceneCaptureContent_RenderThread( const FName OwnerName, const FResolveParams& ResolveParams) { + FMaterialRenderProxy::UpdateDeferredCachedUniformExpressions(); + switch (SceneRenderer->Scene->GetShadingPath()) - { + { case EShadingPath::Mobile: { UpdateSceneCaptureContentMobile_RenderThread( @@ -391,7 +393,7 @@ FSceneRenderer* CreateSceneRendererForSceneCapture( Scene, SceneCaptureComponent->ShowFlags) .SetResolveScene(!bCaptureSceneColor) - .SetRealtimeUpdate(bIsPlanarReflection)); + .SetRealtimeUpdate(bIsPlanarReflection || SceneCaptureComponent->bCaptureEveryFrame)); for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex) { diff --git a/Engine/Source/Runtime/Renderer/Private/SceneCore.cpp b/Engine/Source/Runtime/Renderer/Private/SceneCore.cpp index 661e3bf8161f..f4bbf7a5eda4 100644 --- a/Engine/Source/Runtime/Renderer/Private/SceneCore.cpp +++ b/Engine/Source/Runtime/Renderer/Private/SceneCore.cpp @@ -130,7 +130,7 @@ void FLightPrimitiveInteraction::Create(FLightSceneInfo* LightSceneInfo,FPrimiti { // Create the light interaction. FLightPrimitiveInteraction* Interaction = new FLightPrimitiveInteraction(LightSceneInfo, PrimitiveSceneInfo, bDynamic, bIsLightMapped, bShadowMapped, bTranslucentObjectShadow, bInsetObjectShadow); - } + } //-V773 } } @@ -381,7 +381,7 @@ void FStaticMesh::RemoveFromDrawLists() // Remove the mesh from all draw lists. while(DrawListLinks.Num()) { - FStaticMesh::FDrawListElementLink* Link = DrawListLinks[0]; + TRefCountPtr Link = DrawListLinks[0]; const int32 OriginalNumLinks = DrawListLinks.Num(); // This will call UnlinkDrawList. Link->Remove(true); @@ -444,6 +444,13 @@ FExponentialHeightFogSceneInfo::FExponentialHeightFogSceneInfo(const UExponentia bEnableVolumetricFog = InComponent->bEnableVolumetricFog; VolumetricFogScatteringDistribution = FMath::Clamp(InComponent->VolumetricFogScatteringDistribution, -.99f, .99f); VolumetricFogAlbedo = FLinearColor(InComponent->VolumetricFogAlbedo); + VolumetricFogEmissive = InComponent->VolumetricFogEmissive; + + // Apply a scale so artists don't have to work with tiny numbers. + const float UnitScale = 1.0f / 10000.0f; + VolumetricFogEmissive.R = FMath::Max(VolumetricFogEmissive.R * UnitScale, 0.0f); + VolumetricFogEmissive.G = FMath::Max(VolumetricFogEmissive.G * UnitScale, 0.0f); + VolumetricFogEmissive.B = FMath::Max(VolumetricFogEmissive.B * UnitScale, 0.0f); VolumetricFogExtinctionScale = FMath::Max(InComponent->VolumetricFogExtinctionScale, 0.0f); VolumetricFogDistance = FMath::Max(InComponent->VolumetricFogDistance, 0.0f); bOverrideLightColorsWithFogInscatteringColors = InComponent->bOverrideLightColorsWithFogInscatteringColors; diff --git a/Engine/Source/Runtime/Renderer/Private/SceneCore.h b/Engine/Source/Runtime/Renderer/Private/SceneCore.h index 325bed91a4b7..78f4327e5efa 100644 --- a/Engine/Source/Runtime/Renderer/Private/SceneCore.h +++ b/Engine/Source/Runtime/Renderer/Private/SceneCore.h @@ -147,6 +147,9 @@ public: /** The index of the mesh in the scene's static meshes array. */ int32 Id; + /** Index of the mesh into the scene's StaticMeshBatchVisibility array. */ + int32 BatchVisibilityId; + // Constructor/destructor. FStaticMesh( FPrimitiveSceneInfo* InPrimitiveSceneInfo, @@ -157,7 +160,8 @@ public: FMeshBatch(InMesh), ScreenSize(InScreenSize), PrimitiveSceneInfo(InPrimitiveSceneInfo), - Id(INDEX_NONE) + Id(INDEX_NONE), + BatchVisibilityId(INDEX_NONE) { BatchHitProxyId = InHitProxyId; } @@ -188,7 +192,8 @@ private: FMeshBatch(InStaticMesh), ScreenSize(InStaticMesh.ScreenSize), PrimitiveSceneInfo(InStaticMesh.PrimitiveSceneInfo), - Id(InStaticMesh.Id) + Id(InStaticMesh.Id), + BatchVisibilityId(InStaticMesh.BatchVisibilityId) {} }; @@ -218,6 +223,7 @@ public: bool bEnableVolumetricFog; float VolumetricFogScatteringDistribution; FLinearColor VolumetricFogAlbedo; + FLinearColor VolumetricFogEmissive; float VolumetricFogExtinctionScale; float VolumetricFogDistance; bool bOverrideLightColorsWithFogInscatteringColors; diff --git a/Engine/Source/Runtime/Renderer/Private/SceneHitProxyRendering.cpp b/Engine/Source/Runtime/Renderer/Private/SceneHitProxyRendering.cpp index 95df021ec2c4..7b4c3e50125b 100644 --- a/Engine/Source/Runtime/Renderer/Private/SceneHitProxyRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/SceneHitProxyRendering.cpp @@ -444,7 +444,7 @@ void InitHitProxyRender(FRHICommandListImmediate& RHICmdList, const FSceneRender { const FViewInfo& View = Views[ViewIndex]; RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f); - DrawClearQuad(RHICmdList, SceneRenderer->FeatureLevel, true, FLinearColor::White, false, 0, false, 0, OutHitProxyRT->GetDesc().Extent, FIntRect()); + DrawClearQuad(RHICmdList, true, FLinearColor::White, false, 0, false, 0, OutHitProxyRT->GetDesc().Extent, FIntRect()); } } @@ -472,7 +472,7 @@ static void DoRenderHitProxies(FRHICommandListImmediate& RHICmdList, const FScen RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f); // Clear the depth buffer for each DPG. - DrawClearQuad(RHICmdList, SceneRenderer->FeatureLevel, false, FLinearColor(), true, (float)ERHIZBuffer::FarPlane, true, 0, HitProxyDepthRT->GetDesc().Extent, FIntRect()); + DrawClearQuad(RHICmdList, false, FLinearColor(), true, (float)ERHIZBuffer::FarPlane, true, 0, HitProxyDepthRT->GetDesc().Extent, FIntRect()); // Depth tests + writes, no alpha blending. DrawRenderState.SetDepthStencilState(TStaticDepthStencilState::GetRHI()); diff --git a/Engine/Source/Runtime/Renderer/Private/SceneOcclusion.cpp b/Engine/Source/Runtime/Renderer/Private/SceneOcclusion.cpp index 98bad05422bd..f2202e397a4c 100644 --- a/Engine/Source/Runtime/Renderer/Private/SceneOcclusion.cpp +++ b/Engine/Source/Runtime/Renderer/Private/SceneOcclusion.cpp @@ -44,12 +44,6 @@ static FAutoConsoleVariableRef CVarShowRelevantPrecomputedVisibilityCells( ECVF_RenderThreadSafe ); -static TAutoConsoleVariable CVarFastVRamHzb( - TEXT("r.FastVramHzb"), - 0, - TEXT("Whether to store HZB in fast VRAM"), - ECVF_Scalability | ECVF_RenderThreadSafe); - #define NUM_CUBE_VERTICES 36 /** Random table for occlusion **/ @@ -1088,10 +1082,6 @@ void BuildHZB( FRHICommandListImmediate& RHICmdList, FViewInfo& View ) View.HZBMipmap0Size = HZBSize; FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(HZBSize, PF_R16F, FClearValueBinding::None, TexCreate_None, TexCreate_RenderTargetable | TexCreate_ShaderResource | TexCreate_NoFastClear, false, NumMips)); - if (CVarFastVRamHzb.GetValueOnRenderThread() >= 1) - { - Desc.Flags |= TexCreate_FastVRAM; - } GRenderTargetPool.FindFreeElement(RHICmdList, Desc, View.HZB, TEXT("HZB") ); FSceneRenderTargetItem& HZBRenderTarget = View.HZB->GetRenderTargetItem(); diff --git a/Engine/Source/Runtime/Renderer/Private/ScenePrivate.h b/Engine/Source/Runtime/Renderer/Private/ScenePrivate.h index 3ce91c21fc9c..084951add0bd 100644 --- a/Engine/Source/Runtime/Renderer/Private/ScenePrivate.h +++ b/Engine/Source/Runtime/Renderer/Private/ScenePrivate.h @@ -431,8 +431,14 @@ public: return PrimitiveFadingOutLODMap[PrimIndex]; } + bool IsNodeHidden(const int32 PrimIndex) const + { + return HiddenChildPrimitiveMap.IsValidIndex(PrimIndex) && HiddenChildPrimitiveMap[PrimIndex]; + } + TBitArray<> PrimitiveFadingLODMap; TBitArray<> PrimitiveFadingOutLODMap; + TBitArray<> HiddenChildPrimitiveMap; float TemporalLODSyncTime; uint16 UpdateCount; }; @@ -692,7 +698,10 @@ public: // Pre-computed filter in spectral (i.e. FFT) domain along with data to determine if we need to up date it struct { + /// @cond DOXYGEN_WARNINGS void SafeRelease() { Spectral.SafeRelease(); CenterWeight.SafeRelease(); } + /// @endcond + // The 2d fourier transform of the physical space texture. TRefCountPtr Spectral; TRefCountPtr CenterWeight; // a 1-pixel buffer that holds blend weights for half-resolution fft. @@ -720,6 +729,8 @@ public: FForwardLightingViewResources ForwardLightingResources; + FForwardLightingCullingResources ForwardLightingCullingResources; + TRefCountPtr LightScatteringHistory; /** Distance field AO tile intersection GPU resources. Last frame's state is not used, but they must be sized exactly to the view so stored here. */ @@ -1042,6 +1053,7 @@ public: TranslucencyTimer.Release(); SeparateTranslucencyTimer.Release(); ForwardLightingResources.Release(); + ForwardLightingCullingResources.Release(); LightScatteringHistory.SafeRelease(); } @@ -1579,7 +1591,7 @@ private: /** Internal helper to determine if indirect lighting is enabled at all */ bool IndirectLightingAllowed(FScene* Scene, FSceneRenderer& Renderer) const; - void ProcessPrimitiveUpdate(FScene* Scene, FViewInfo& View, int32 PrimitiveIndex, bool bAllowUnbuiltPreview, TMap& OutBlocksToUpdate, TArray& OutTransitionsOverTimeToUpdate); + void ProcessPrimitiveUpdate(FScene* Scene, FViewInfo& View, int32 PrimitiveIndex, bool bAllowUnbuiltPreview, bool bAllowVolumeSample, TMap& OutBlocksToUpdate, TArray& OutTransitionsOverTimeToUpdate); /** Internal helper to perform the work of updating the cache primitives. Can be done on any thread as a task */ void UpdateCachePrimitivesInternal(FScene* Scene, FSceneRenderer& Renderer, bool bAllowUnbuiltPreview, TMap& OutBlocksToUpdate, TArray& OutTransitionsOverTimeToUpdate); @@ -1605,7 +1617,7 @@ private: const TMap& AttachmentGroups, FPrimitiveSceneInfo* PrimitiveSceneInfo, bool bAllowUnbuiltPreview, - bool bOpaqueRelevance, + bool bAllowVolumeSample, TMap& BlocksToUpdate, TArray& TransitionsOverTimeToUpdate); @@ -1697,12 +1709,7 @@ private: */ struct FPrimitiveBounds { - /** Origin of the primitive. */ - FVector Origin; - /** Radius of the bounding sphere. */ - float SphereRadius; - /** Extents of the axis-aligned bounding box. */ - FVector BoxExtent; + FBoxSphereBounds BoxSphereBounds; /** Square of the minimum draw distance for the primitive. */ float MinDrawDistanceSq; /** Maximum draw distance for the primitive. */ @@ -1920,8 +1927,12 @@ public: /** Packed array of primitives in the scene. */ TArray Primitives; + /** Packed array of primitive scene proxies in the scene. */ + TArray PrimitiveSceneProxies; /** Packed array of primitive bounds. */ TArray PrimitiveBounds; + /** Packed array of primitive flags. */ + TArray PrimitiveFlagsCompact; /** Packed array of precomputed primitive visibility IDs. */ TArray PrimitiveVisibilityIds; /** Packed array of primitive occlusion flags. See EOcclusionFlags. */ @@ -2009,6 +2020,9 @@ public: /** The static meshes in the scene. */ TSparseArray StaticMeshes; + /** This sparse array is used just to track free indices for FStaticMesh::BatchVisibilityId. */ + TSparseArray StaticMeshBatchVisibility; + /** The exponential fog components in the scene. */ TArray ExponentialFogs; @@ -2162,7 +2176,7 @@ public: /** Finds the closest reflection capture to a point in space. */ const FReflectionCaptureProxy* FindClosestReflectionCapture(FVector Position) const; - const class FPlanarReflectionSceneProxy* FindClosestPlanarReflection(const FPrimitiveBounds& Bounds) const; + const class FPlanarReflectionSceneProxy* FindClosestPlanarReflection(const FBoxSphereBounds& Bounds) const; void FindClosestReflectionCaptures(FVector Position, const FReflectionCaptureProxy* (&SortedByDistanceOUT)[FPrimitiveSceneInfo::MaxCachedReflectionCaptureProxies]) const; diff --git a/Engine/Source/Runtime/Renderer/Private/SceneRendering.cpp b/Engine/Source/Runtime/Renderer/Private/SceneRendering.cpp index 3941055c680a..de2ecdd98aa7 100644 --- a/Engine/Source/Runtime/Renderer/Private/SceneRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/SceneRendering.cpp @@ -160,14 +160,6 @@ static TAutoConsoleVariable CVarMaxMobileShadowCascades( ECVF_Scalability | ECVF_RenderThreadSafe ); -static TAutoConsoleVariable CVarForwardShading( - TEXT("r.ForwardShading"), - 0, - TEXT("Whether to use forward shading on desktop platforms - requires Shader Model 5 hardware.\n") - TEXT("Forward shading has lower constant cost, but fewer features supported. 0:off, 1:on\n") - TEXT("This rendering path is a work in progress with many unimplemented features, notably only a single reflection capture is applied per object and no translucency dynamic shadow receiving."), - ECVF_RenderThreadSafe | ECVF_ReadOnly); - static TAutoConsoleVariable CVarSupportSimpleForwardShading( TEXT("r.SupportSimpleForwardShading"), 0, @@ -241,6 +233,20 @@ static TAutoConsoleVariable CVarWideCustomResolve( ECVF_RenderThreadSafe | ECVF_Scalability ); +TAutoConsoleVariable CVarTransientResourceAliasing_RenderTargets( + TEXT("r.TransientResourceAliasing.RenderTargets"), + 1, + TEXT("0 : Disabled\n") + TEXT("1 : enable transient resource aliasing for fastVRam rendertargets\n") + TEXT("2 : enable transient resource aliasing for ALL rendertargets (experimental!)\n"), + ECVF_ReadOnly); + +TAutoConsoleVariable CVarTransientResourceAliasing_Buffers( + TEXT("r.TransientResourceAliasing.Buffers"), + 1, + TEXT("If true, enable transient resource aliasing for buffers"), + ECVF_ReadOnly); + static FParallelCommandListSet* GOutstandingParallelCommandListSet = nullptr; DECLARE_CYCLE_STAT(TEXT("DeferredShadingSceneRenderer MotionBlurStartFrame"), STAT_FDeferredShadingSceneRenderer_MotionBlurStartFrame, STATGROUP_SceneRendering); @@ -598,6 +604,13 @@ void UpdateNoiseTextureParameters(FViewUniformShaderParameters& ViewUniformShade } check(ViewUniformShaderParameters.PerlinNoise3DTexture); ViewUniformShaderParameters.PerlinNoise3DTextureSampler = TStaticSamplerState::GetRHI(); + + if (GSystemTextures.SobolSampling.GetReference()) + { + ViewUniformShaderParameters.SobolSamplingTexture = (FTexture2DRHIRef&)GSystemTextures.SobolSampling->GetRenderTargetItem().ShaderResourceTexture; + SetBlack2DIfNull(ViewUniformShaderParameters.SobolSamplingTexture); + } + check(ViewUniformShaderParameters.SobolSamplingTexture); } /** Creates the view's uniform buffers given a set of view transforms. */ @@ -816,10 +829,25 @@ void FViewInfo::SetupUniformBufferParameters( { // Enables HDR encoding mode selection without recompile of all PC shaders during ES2 emulation. - ViewUniformShaderParameters.HDR32bppEncodingMode = 0; + ViewUniformShaderParameters.HDR32bppEncodingMode = 0.0f; if (IsMobileHDR32bpp()) { - ViewUniformShaderParameters.HDR32bppEncodingMode = IsMobileHDRMosaic() ? 1.0f : 2.0f; + EMobileHDRMode MobileHDRMode = GetMobileHDRMode(); + switch (MobileHDRMode) + { + case EMobileHDRMode::EnabledMosaic: + ViewUniformShaderParameters.HDR32bppEncodingMode = 1.0f; + break; + case EMobileHDRMode::EnabledRGBE: + ViewUniformShaderParameters.HDR32bppEncodingMode = 2.0f; + break; + case EMobileHDRMode::EnabledRGBA8: + ViewUniformShaderParameters.HDR32bppEncodingMode = 3.0f; + break; + default: + checkNoEntry(); + break; + } } } @@ -936,7 +964,7 @@ FViewInfo* FViewInfo::CreateSnapshot() const } else { - Result = (FViewInfo*)FMemory::Malloc(sizeof(FViewInfo), ALIGNOF(FViewInfo)); + Result = (FViewInfo*)FMemory::Malloc(sizeof(FViewInfo), alignof(FViewInfo)); } FMemory::Memcpy(*Result, *this); @@ -1931,6 +1959,12 @@ void FRendererModule::BeginRenderingViewFamily(FCanvas* Canvas, FSceneViewFamily } } + ENQUEUE_RENDER_COMMAND(UpdateDeferredCachedUniformExpressions)( + [](FRHICommandList& RHICmdList) + { + FMaterialRenderProxy::UpdateDeferredCachedUniformExpressions(); + }); + // Flush the canvas first. Canvas->Flush_GameThread(); diff --git a/Engine/Source/Runtime/Renderer/Private/SceneRendering.h b/Engine/Source/Runtime/Renderer/Private/SceneRendering.h index cfeb15e6f137..78ddb7bf077a 100644 --- a/Engine/Source/Runtime/Renderer/Private/SceneRendering.h +++ b/Engine/Source/Runtime/Renderer/Private/SceneRendering.h @@ -152,7 +152,7 @@ namespace ETranslucencyPass enum Type { TPT_StandardTranslucency, - TPT_SeparateTranslucency, + TPT_TranslucencyAfterDOF, /** Drawing all translucency, regardless of separate or standard. Used when drawing translucency outside of the main renderer, eg FRendererModule::DrawTile. */ TPT_AllTranslucency, @@ -165,6 +165,8 @@ struct FTranslucenyPrimCount { private: uint32 Count[ETranslucencyPass::TPT_MAX]; + bool UseSceneColorCopyPerPass[ETranslucencyPass::TPT_MAX]; + bool DisableOffscreenRenderingPerPass[ETranslucencyPass::TPT_MAX]; public: // constructor @@ -173,6 +175,8 @@ public: for(uint32 i = 0; i < ETranslucencyPass::TPT_MAX; ++i) { Count[i] = 0; + UseSceneColorCopyPerPass[i] = false; + DisableOffscreenRenderingPerPass[i] = false; } } @@ -182,13 +186,17 @@ public: for(uint32 i = 0; i < ETranslucencyPass::TPT_MAX; ++i) { Count[i] += InSrc.Count[i]; + UseSceneColorCopyPerPass[i] |= InSrc.UseSceneColorCopyPerPass[i]; + DisableOffscreenRenderingPerPass[i] |= InSrc.DisableOffscreenRenderingPerPass[i]; } } // interface similar to TArray but here we only store the count of Prims per pass - void Add(ETranslucencyPass::Type InPass) + void Add(ETranslucencyPass::Type InPass, bool bUseSceneColorCopy, bool bDisableOffscreenRendering) { ++Count[InPass]; + UseSceneColorCopyPerPass[InPass] |= bUseSceneColorCopy; + DisableOffscreenRenderingPerPass[InPass] |= bDisableOffscreenRendering; } // @return range in SortedPrims[] after sorting @@ -218,6 +226,16 @@ public: { return Count[InPass]; } + + bool UseSceneColorCopy(ETranslucencyPass::Type InPass) const + { + return UseSceneColorCopyPerPass[InPass]; + } + + bool DisableOffscreenRendering(ETranslucencyPass::Type InPass) const + { + return DisableOffscreenRenderingPerPass[InPass]; + } }; @@ -278,9 +296,9 @@ class FMeshDecalPrimSet : public FSortedPrimSet public: typedef FSortedPrimSet::FSortedPrim KeyType; - static KeyType GenerateKey(FPrimitiveSceneInfo* PrimitiveSceneInfo) + static KeyType GenerateKey(FPrimitiveSceneInfo* PrimitiveSceneInfo, int16 InSortPriority) { - return KeyType(PrimitiveSceneInfo, 0); + return KeyType(PrimitiveSceneInfo, (uint32)(InSortPriority - SHRT_MIN)); } }; @@ -365,7 +383,7 @@ public: * Insert a primitive to the translucency rendering list[s] */ - static void PlaceScenePrimitive(FPrimitiveSceneInfo* PrimitiveSceneInfo, const FViewInfo& ViewInfo, bool bUseNormalTranslucency, bool bUseSeparateTranslucency, bool bUseMobileSeparateTranslucency, + static void PlaceScenePrimitive(FPrimitiveSceneInfo* PrimitiveSceneInfo, const FViewInfo& ViewInfo, const FPrimitiveViewRelevance& ViewRelevance, FTranslucentSortedPrim* InArrayStart, int32& InOutArrayNum, FTranslucenyPrimCount& OutCount); /** @@ -667,10 +685,6 @@ public: FDynamicReadBuffer ForwardLocalLightBuffer; FRWBuffer NumCulledLightsGrid; FRWBuffer CulledLightDataGrid; - FRWBuffer NextCulledLightLink; - FRWBuffer StartOffsetGrid; - FRWBuffer CulledLightLinks; - FRWBuffer NextCulledLightData; void Release() { @@ -678,6 +692,19 @@ public: ForwardLocalLightBuffer.Release(); NumCulledLightsGrid.Release(); CulledLightDataGrid.Release(); + } +}; + +class FForwardLightingCullingResources +{ +public: + FRWBuffer NextCulledLightLink; + FRWBuffer StartOffsetGrid; + FRWBuffer CulledLightLinks; + FRWBuffer NextCulledLightData; + + void Release() + { NextCulledLightLink.Release(); StartOffsetGrid.Release(); CulledLightLinks.Release(); @@ -1332,7 +1359,7 @@ protected: void InitDynamicShadows(FRHICommandListImmediate& RHICmdList); - bool RenderShadowProjections(FRHICommandListImmediate& RHICmdList, const FLightSceneInfo* LightSceneInfo, bool bProjectingForForwardShading, bool bMobileModulatedProjections); + bool RenderShadowProjections(FRHICommandListImmediate& RHICmdList, const FLightSceneInfo* LightSceneInfo, IPooledRenderTarget* ScreenShadowMaskTexture, bool bProjectingForForwardShading, bool bMobileModulatedProjections); /** Finds a matching cached preshadow, if one exists. */ TRefCountPtr GetCachedPreshadow( @@ -1389,28 +1416,12 @@ protected: */ bool CheckForProjectedShadows(const FLightSceneInfo* LightSceneInfo) const; - /** Returns whether a per object shadow should be created due to the light being a stationary light. */ - bool ShouldCreateObjectShadowForStationaryLight(const FLightSceneInfo* LightSceneInfo, const FPrimitiveSceneProxy* PrimitiveSceneProxy, bool bInteractionShadowMapped) const; - /** Gathers the list of primitives used to draw various shadow types */ void GatherShadowPrimitives( const TArray& PreShadows, const TArray& ViewDependentWholeSceneShadows, bool bReflectionCaptureScene); - /** - * Checks to see if this primitive is affected by various shadow types - * - * @param PrimitiveSceneInfoCompact The primitive to check for shadow interaction - * @param PreShadows The list of pre-shadows to check against - */ - void GatherShadowsForPrimitiveInner(const FPrimitiveSceneInfoCompact& PrimitiveSceneInfoCompact, - const TArray& PreShadows, - const TArray& ViewDependentWholeSceneShadows, - bool bReflectionCaptureScene); - - void BeginRenderRayTracedDistanceFieldProjections(FRHICommandListImmediate& RHICmdList); - void RenderShadowDepthMaps(FRHICommandListImmediate& RHICmdList); void RenderShadowDepthMapAtlases(FRHICommandListImmediate& RHICmdList); @@ -1456,7 +1467,7 @@ protected: void InitFogConstants(); /** Returns whether there are translucent primitives to be rendered. */ - bool ShouldRenderTranslucency() const; + bool ShouldRenderTranslucency(ETranslucencyPass::Type TranslucencyPass) const; /** TODO: REMOVE if no longer needed: Copies scene color to the viewport's render target after applying gamma correction. */ void GammaCorrectToViewportRenderTarget(FRHICommandList& RHICmdList, const FViewInfo* View, float OverrideGamma); @@ -1591,3 +1602,23 @@ inline void SetBlack3DIfNull(FTextureRHIParamRef& Tex) SetBlack2DIfNull(Tex); } } + +extern TAutoConsoleVariable CVarTransientResourceAliasing_RenderTargets; +extern TAutoConsoleVariable CVarTransientResourceAliasing_Buffers; + +FORCEINLINE bool IsTransientResourceBufferAliasingEnabled() +{ + return (GSupportsTransientResourceAliasing && CVarTransientResourceAliasing_Buffers.GetValueOnRenderThread() != 0); +} + +// Helper functions for fast vram to handle dynamic/static allocation +FORCEINLINE uint32 GetTextureFastVRamFlag_DynamicLayout() +{ + return (GSupportsTransientResourceAliasing && CVarTransientResourceAliasing_RenderTargets.GetValueOnRenderThread() > 0) ? ( TexCreate_FastVRAM | TexCreate_Transient ) : 0; +} + +FORCEINLINE uint32 GetTextureFastVRamFlag_StaticLayout() +{ + return (GSupportsTransientResourceAliasing == false && CVarTransientResourceAliasing_RenderTargets.GetValueOnRenderThread() == 0) ? TexCreate_FastVRAM : 0; +} + diff --git a/Engine/Source/Runtime/Renderer/Private/SceneVisibility.cpp b/Engine/Source/Runtime/Renderer/Private/SceneVisibility.cpp index a8db98359a57..d4a300666a34 100644 --- a/Engine/Source/Runtime/Renderer/Private/SceneVisibility.cpp +++ b/Engine/Source/Runtime/Renderer/Private/SceneVisibility.cpp @@ -339,7 +339,7 @@ static int32 FrustumCull(const FScene* Scene, FViewInfo& View) { int32 Index = WordIndex * NumBitsPerDWORD + BitSubIndex; const FPrimitiveBounds& Bounds = Scene->PrimitiveBounds[Index]; - float DistanceSquared = (Bounds.Origin - ViewOriginForDistanceCulling).SizeSquared(); + float DistanceSquared = (Bounds.BoxSphereBounds.Origin - ViewOriginForDistanceCulling).SizeSquared(); float MaxDrawDistance = Bounds.MaxDrawDistance * MaxDrawDistanceScale; int32 VisibilityId = INDEX_NONE; @@ -358,9 +358,9 @@ static int32 FrustumCull(const FScene* Scene, FViewInfo& View) if (DistanceSquared > FMath::Square(MaxDrawDistance + FadeRadius) || (DistanceSquared < Bounds.MinDrawDistanceSq) || - (UseCustomCulling && !View.CustomVisibilityQuery->IsVisible(VisibilityId, FBoxSphereBounds(Bounds.Origin, Bounds.BoxExtent, Bounds.SphereRadius))) || - (bAlsoUseSphereTest && View.ViewFrustum.IntersectSphere(Bounds.Origin, Bounds.SphereRadius) == false) || - View.ViewFrustum.IntersectBox(Bounds.Origin, Bounds.BoxExtent) == false || + (UseCustomCulling && !View.CustomVisibilityQuery->IsVisible(VisibilityId, FBoxSphereBounds(Bounds.BoxSphereBounds.Origin, Bounds.BoxSphereBounds.BoxExtent, Bounds.BoxSphereBounds.SphereRadius))) || + (bAlsoUseSphereTest && View.ViewFrustum.IntersectSphere(Bounds.BoxSphereBounds.Origin, Bounds.BoxSphereBounds.SphereRadius) == false) || + View.ViewFrustum.IntersectBox(Bounds.BoxSphereBounds.Origin, Bounds.BoxSphereBounds.BoxExtent) == false || (UseMonoCulling && Scene->Primitives[Index]->Proxy->RenderInMono())) { STAT(NumCulledPrimitives.Increment()); @@ -1512,7 +1512,7 @@ struct FRelevancePacket if (ViewRelevance.bDecal) { - MeshDecalPrimSet.AddPrim(FMeshDecalPrimSet::GenerateKey(PrimitiveSceneInfo)); + MeshDecalPrimSet.AddPrim(FMeshDecalPrimSet::GenerateKey(PrimitiveSceneInfo, PrimitiveSceneInfo->Proxy->GetTranslucencySortPriority())); } if (bEditorRelevance) @@ -1535,9 +1535,7 @@ struct FRelevancePacket if (bTranslucentRelevance && !bEditorRelevance && ViewRelevance.bRenderInMainPass) { // Add to set of dynamic translucent primitives - FTranslucentPrimSet::PlaceScenePrimitive(PrimitiveSceneInfo, View, - ViewRelevance.bNormalTranslucencyRelevance, ViewRelevance.bSeparateTranslucencyRelevance, ViewRelevance.bMobileSeparateTranslucencyRelevance, - &TranslucencyPrims.Prims[0], TranslucencyPrims.NumPrims, TranslucencyPrimCount); + FTranslucentPrimSet::PlaceScenePrimitive(PrimitiveSceneInfo, View, ViewRelevance, &TranslucencyPrims.Prims[0], TranslucencyPrims.NumPrims, TranslucencyPrimCount); if (ViewRelevance.bDistortionRelevance) { @@ -1590,13 +1588,13 @@ struct FRelevancePacket // For mobile, the per-object reflection is used for everything && (Scene->GetShadingPath() == EShadingPath::Mobile || bTranslucentRelevance || IsForwardShadingEnabled(Scene->GetFeatureLevel()))) { - PrimitiveSceneInfo->CachedReflectionCaptureProxy = Scene->FindClosestReflectionCapture(Scene->PrimitiveBounds[BitIndex].Origin); - PrimitiveSceneInfo->CachedPlanarReflectionProxy = Scene->FindClosestPlanarReflection(Scene->PrimitiveBounds[BitIndex]); + PrimitiveSceneInfo->CachedReflectionCaptureProxy = Scene->FindClosestReflectionCapture(Scene->PrimitiveBounds[BitIndex].BoxSphereBounds.Origin); + PrimitiveSceneInfo->CachedPlanarReflectionProxy = Scene->FindClosestPlanarReflection(Scene->PrimitiveBounds[BitIndex].BoxSphereBounds); if (Scene->GetShadingPath() == EShadingPath::Mobile) { // mobile HQ reflections - Scene->FindClosestReflectionCaptures(Scene->PrimitiveBounds[BitIndex].Origin, PrimitiveSceneInfo->CachedReflectionCaptureProxies); + Scene->FindClosestReflectionCaptures(Scene->PrimitiveBounds[BitIndex].BoxSphereBounds.Origin, PrimitiveSceneInfo->CachedReflectionCaptureProxies); } PrimitiveSceneInfo->bNeedsCachedReflectionCaptureUpdate = false; @@ -1630,15 +1628,15 @@ struct FRelevancePacket const FPrimitiveBounds& Bounds = Scene->PrimitiveBounds[PrimitiveIndex]; const FPrimitiveViewRelevance& ViewRelevance = View.PrimitiveViewRelevanceMap[PrimitiveIndex]; - FLODMask LODToRender = ComputeLODForMeshes( PrimitiveSceneInfo->StaticMeshes, View, Bounds.Origin, Bounds.SphereRadius, ViewData.ForcedLODLevel, ViewData.LODScale); + FLODMask LODToRender = ComputeLODForMeshes( PrimitiveSceneInfo->StaticMeshes, View, Bounds.BoxSphereBounds.Origin, Bounds.BoxSphereBounds.SphereRadius, ViewData.ForcedLODLevel, ViewData.LODScale); const bool bIsHLODFading = bHLODActive && ViewState && ViewState->HLODVisibilityState.IsNodeFading(PrimitiveIndex); const bool bIsHLODFadingOut = bHLODActive && ViewState && ViewState->HLODVisibilityState.IsNodeFadingOut(PrimitiveIndex); const bool bIsLODDithered = LODToRender.IsDithered(); - float DistanceSquared = (Bounds.Origin - ViewData.ViewOrigin).SizeSquared(); + float DistanceSquared = (Bounds.BoxSphereBounds.Origin - ViewData.ViewOrigin).SizeSquared(); const float LODFactorDistanceSquared = DistanceSquared * FMath::Square(View.LODDistanceFactor * ViewData.InvLODScale); - const bool bDrawShadowDepth = FMath::Square(Bounds.SphereRadius) > ViewData.MinScreenRadiusForCSMDepthSquared * LODFactorDistanceSquared; - const bool bDrawDepthOnly = ViewData.bFullEarlyZPass || FMath::Square(Bounds.SphereRadius) > GMinScreenRadiusForDepthPrepass * GMinScreenRadiusForDepthPrepass * LODFactorDistanceSquared; + const bool bDrawShadowDepth = FMath::Square(Bounds.BoxSphereBounds.SphereRadius) > ViewData.MinScreenRadiusForCSMDepthSquared * LODFactorDistanceSquared; + const bool bDrawDepthOnly = ViewData.bFullEarlyZPass || FMath::Square(Bounds.BoxSphereBounds.SphereRadius) > GMinScreenRadiusForDepthPrepass * GMinScreenRadiusForDepthPrepass * LODFactorDistanceSquared; const int32 NumStaticMeshes = PrimitiveSceneInfo->StaticMeshes.Num(); for(int32 MeshIndex = 0;MeshIndex < NumStaticMeshes;MeshIndex++) @@ -1729,7 +1727,7 @@ struct FRelevancePacket // Static meshes which don't need per-element visibility always draw all elements if (bNeedsBatchVisibility && StaticMesh.bRequiresPerElementVisibility) { - WriteView.StaticMeshBatchVisibility[StaticMesh.Id] = StaticMesh.VertexFactory->GetStaticBatchElementVisibility(View, &StaticMesh); + WriteView.StaticMeshBatchVisibility[StaticMesh.BatchVisibilityId] = StaticMesh.VertexFactory->GetStaticBatchElementVisibility(View, &StaticMesh); } } } @@ -2403,7 +2401,7 @@ void FSceneRenderer::ComputeViewVisibility(FRHICommandListImmediate& RHICmdList) View.StaticMeshFadeInDitheredLODMap.Init(false,Scene->StaticMeshes.GetMaxIndex()); View.StaticMeshVelocityMap.Init(false,Scene->StaticMeshes.GetMaxIndex()); View.StaticMeshShadowDepthMap.Init(false,Scene->StaticMeshes.GetMaxIndex()); - View.StaticMeshBatchVisibility.AddZeroed(Scene->StaticMeshes.GetMaxIndex()); + View.StaticMeshBatchVisibility.AddZeroed(Scene->StaticMeshBatchVisibility.GetMaxIndex()); View.VisibleLightInfos.Empty(Scene->Lights.GetMaxIndex()); @@ -2566,7 +2564,7 @@ void FSceneRenderer::ComputeViewVisibility(FRHICommandListImmediate& RHICmdList) float ScreenSizeScale = FMath::Max(View.ViewMatrices.GetProjectionMatrix().M[0][0] * View.ViewRect.Width(), View.ViewMatrices.GetProjectionMatrix().M[1][1] * View.ViewRect.Height()); for (FSceneSetBitIterator BitIt(View.PrimitiveVisibilityMap); BitIt; ++BitIt) { - if (ScreenSizeScale * Scene->PrimitiveBounds[BitIt.GetIndex()].SphereRadius <= GWireframeCullThreshold) + if (ScreenSizeScale * Scene->PrimitiveBounds[BitIt.GetIndex()].BoxSphereBounds.SphereRadius <= GWireframeCullThreshold) { View.PrimitiveVisibilityMap.AccessCorrespondingBit(BitIt) = false; } @@ -2807,8 +2805,7 @@ void FSceneRenderer::PostVisibilityFrameSetup(FILCUpdatePrimTaskData& OutILCTask FLinearColor Color( ColorAndFalloffExponent ); - // Scale by visible area - Color /= PI * FMath::Square( SourceRadius ); + Color /= PI * FMath::Square( SourceRadius ) + 0.5f * PI * SourceRadius * SourceLength; if( Proxy->IsInverseSquared() ) { @@ -2831,9 +2828,12 @@ void FSceneRenderer::PostVisibilityFrameSetup(FILCUpdatePrimTaskData& OutILCTask FVector L = ToLight.GetSafeNormal(); Color.A *= FMath::Square( FMath::Clamp( ( (L | Direction) - SpotAngles.X ) * SpotAngles.Y, 0.0f, 1.0f ) ); - FViewElementPDI LightPDI( &View, NULL ); FMaterialRenderProxy* const ColoredMeshInstance = new(FMemStack::Get()) FColoredMaterialRenderProxy( GEngine->DebugMeshMaterial->GetRenderProxy(false), Color ); - DrawSphere( &LightPDI, Origin, FVector( SourceRadius, SourceRadius, SourceRadius ), 36, 24, ColoredMeshInstance, SDPG_World ); + + FViewElementPDI LightPDI( &View, NULL ); + // Scaled sphere to handle SourceLength + const float ZScale = FMath::Max(SourceRadius, SourceLength); + DrawSphere(&LightPDI, Origin, FRotationMatrix::MakeFromZ(Direction).Rotator(), FVector(SourceRadius, SourceRadius, ZScale), 36, 24, ColoredMeshInstance, SDPG_World); } } } @@ -3040,6 +3040,7 @@ void FLODSceneTree::UpdateAndApplyVisibilityStates(FViewInfo& View) HLODState.PrimitiveFadingLODMap.Init(false, View.PrimitiveVisibilityMap.Num()); HLODState.PrimitiveFadingOutLODMap.Init(false, View.PrimitiveVisibilityMap.Num()); + HLODState.HiddenChildPrimitiveMap.Init(false, View.PrimitiveVisibilityMap.Num()); FSceneBitArray& VisibilityFlags = View.PrimitiveVisibilityMap; TArray& RelevanceMap = View.PrimitiveViewRelevanceMap; @@ -3087,7 +3088,7 @@ void FLODSceneTree::UpdateAndApplyVisibilityStates(FViewInfo& View) } } - const float DistanceSquared = (Bounds.Origin - View.ViewMatrices.GetViewOrigin()).SizeSquared(); + const float DistanceSquared = (Bounds.BoxSphereBounds.Origin - View.ViewMatrices.GetViewOrigin()).SizeSquared(); const bool bIsInDrawRange = DistanceSquared >= Bounds.MinDrawDistanceSq; const bool bWasFadingPreUpdate = !!NodeVisibility.bIsFading; @@ -3174,12 +3175,12 @@ void FLODSceneTree::UpdateAndApplyVisibilityStates(FViewInfo& View) void FLODSceneTree::ApplyNodeFadingToChildren(FSceneViewState* ViewState, FLODSceneNode& Node, FSceneBitArray& VisibilityFlags, const bool bIsFading, const bool bIsFadingOut) { checkSlow(ViewState); - FHLODVisibilityState& HLODState = ViewState->HLODVisibilityState; - TMap& VisibilityStates = ViewState->HLODSceneNodeVisibilityStates; - FHLODSceneNodeVisibilityState& NodeVisibility = VisibilityStates.FindOrAdd(Node.SceneInfo->PrimitiveComponentId); if (Node.SceneInfo) { + FHLODVisibilityState& HLODState = ViewState->HLODVisibilityState; + TMap& VisibilityStates = ViewState->HLODSceneNodeVisibilityStates; + FHLODSceneNodeVisibilityState& NodeVisibility = VisibilityStates.FindOrAdd(Node.SceneInfo->PrimitiveComponentId); NodeVisibility.UpdateCount = HLODState.UpdateCount; // Force visibility during fades @@ -3192,6 +3193,7 @@ void FLODSceneTree::ApplyNodeFadingToChildren(FSceneViewState* ViewState, FLODSc HLODState.PrimitiveFadingLODMap[ChildIndex] = bIsFading; HLODState.PrimitiveFadingOutLODMap[ChildIndex] = bIsFadingOut; + HLODState.HiddenChildPrimitiveMap[ChildIndex] = false; VisibilityFlags[ChildIndex] = true; // Fading only occurs at the adjacent hierarchy level, below should be hidden @@ -3217,6 +3219,7 @@ void FLODSceneTree::HideNodeChildren(FSceneViewState* ViewState, FLODSceneNode& for (const auto& Child : Node.ChildrenSceneInfos) { const int32 ChildIndex = Child->GetIndex(); + HLODState.HiddenChildPrimitiveMap[ChildIndex] = true; VisibilityFlags[ChildIndex] = false; if (FLODSceneNode* ChildNode = SceneNodes.Find(Child->PrimitiveComponentId)) diff --git a/Engine/Source/Runtime/Renderer/Private/ShaderBaseClasses.cpp b/Engine/Source/Runtime/Renderer/Private/ShaderBaseClasses.cpp index 1042ecf206ba..28123099b9bc 100644 --- a/Engine/Source/Runtime/Renderer/Private/ShaderBaseClasses.cpp +++ b/Engine/Source/Runtime/Renderer/Private/ShaderBaseClasses.cpp @@ -319,7 +319,7 @@ void FMaterialShader::SetParameters( } } - DeferredParameters.Set(RHICmdList, ShaderRHI, View, TextureMode); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, Material.GetMaterialDomain(), TextureMode); if (FeatureLevel >= ERHIFeatureLevel::SM4) { diff --git a/Engine/Source/Runtime/Renderer/Private/ShadowDepthRendering.cpp b/Engine/Source/Runtime/Renderer/Private/ShadowDepthRendering.cpp index 287978e6cdae..1837011aa9dd 100644 --- a/Engine/Source/Runtime/Renderer/Private/ShadowDepthRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/ShadowDepthRendering.cpp @@ -1319,7 +1319,7 @@ void FProjectedShadowInfo::ClearDepth(FRHICommandList& RHICmdList, class FSceneR ViewportMaxZ ); - DrawClearQuadMRT(RHICmdList, SceneRenderer->FeatureLevel, bClearColor, NumClearColors, Colors, true, 1.0f, false, 0); + DrawClearQuadMRT(RHICmdList, bClearColor, NumClearColors, Colors, true, 1.0f, false, 0); } else { @@ -1360,7 +1360,7 @@ void DrawMeshElements(FRHICommandList& RHICmdList, FShadowDepthDrawingPolicybRequiresPerElementVisibility ? View.StaticMeshBatchVisibility[Mesh->Id] : ((1ull << Mesh->Elements.Num()) - 1); + uint64 BatchElementMask = Mesh->bRequiresPerElementVisibility ? View.StaticMeshBatchVisibility[Mesh->BatchVisibilityId] : ((1ull << Mesh->Elements.Num()) - 1); int32 BatchElementIndex = 0; do { @@ -1580,7 +1580,7 @@ void FProjectedShadowInfo::SetStateForDepth(FRHICommandList& RHICmdList, EShadow static TAutoConsoleVariable CVarParallelShadows( TEXT("r.ParallelShadows"), - 0, + 1, TEXT("Toggles parallel shadow rendering. Parallel rendering must be enabled for this to have an effect."), ECVF_RenderThreadSafe ); @@ -2173,6 +2173,11 @@ void FSceneRenderer::RenderShadowDepthMapAtlases(FRHICommandListImmediate& RHICm } InRHICmdList.TransitionResource(EResourceTransitionAccess::EWritable, Info.DepthStencilRenderTarget.Texture); InRHICmdList.SetRenderTargetsAndClear(Info); + + if (!bPerformClear) + { + InRHICmdList.BindClearMRTValues(false, true, false); + } }; { @@ -2221,31 +2226,6 @@ void FSceneRenderer::RenderShadowDepthMapAtlases(FRHICommandListImmediate& RHICm } } -void FSceneRenderer::BeginRenderRayTracedDistanceFieldProjections(FRHICommandListImmediate& RHICmdList) -{ - for (TSparseArray::TConstIterator LightIt(Scene->Lights); LightIt; ++LightIt) - { - const FLightSceneInfoCompact& LightSceneInfoCompact = *LightIt; - const FLightSceneInfo* const LightSceneInfo = LightSceneInfoCompact.LightSceneInfo; - FVisibleLightInfo& VisibleLightInfo = VisibleLightInfos[LightSceneInfo->Id]; - - for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) - { - const FViewInfo& View = Views[ViewIndex]; - - for (int32 ShadowIndex = 0; ShadowIndex < VisibleLightInfo.ShadowsToProject.Num(); ShadowIndex++) - { - FProjectedShadowInfo* ProjectedShadowInfo = VisibleLightInfo.ShadowsToProject[ShadowIndex]; - - if (ProjectedShadowInfo->bRayTracedDistanceField) - { - ProjectedShadowInfo->BeginRenderRayTracedDistanceFieldProjection(RHICmdList, View); - } - } - } - } -} - void FSceneRenderer::RenderShadowDepthMaps(FRHICommandListImmediate& RHICmdList) { FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); @@ -2253,8 +2233,6 @@ void FSceneRenderer::RenderShadowDepthMaps(FRHICommandListImmediate& RHICmdList) SCOPED_DRAW_EVENT(RHICmdList, ShadowDepths); SCOPED_GPU_STAT(RHICmdList, Stat_GPU_ShadowDepths); - BeginRenderRayTracedDistanceFieldProjections(RHICmdList); - FSceneRenderer::RenderShadowDepthMapAtlases(RHICmdList); for (int32 CubemapIndex = 0; CubemapIndex < SortedShadowsForShadowDepthPass.ShadowMapCubemaps.Num(); CubemapIndex++) diff --git a/Engine/Source/Runtime/Renderer/Private/ShadowRendering.cpp b/Engine/Source/Runtime/Renderer/Private/ShadowRendering.cpp index 738afb7cc25a..21d5d06f071a 100644 --- a/Engine/Source/Runtime/Renderer/Private/ShadowRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/ShadowRendering.cpp @@ -78,6 +78,20 @@ static FAutoConsoleVariableRef CVarStencilOptimization( ECVF_RenderThreadSafe ); +static TAutoConsoleVariable CVarFilterMethod( + TEXT("r.Shadow.FilterMethod"), + 0, + TEXT("Chooses the shadow filtering method.\n") + TEXT(" 0: Uniform PCF (default)\n") + TEXT(" 1: PCSS (experimental)\n"), + ECVF_RenderThreadSafe); + +static TAutoConsoleVariable CVarMaxSoftKernelSize( + TEXT("r.Shadow.MaxSoftKernelSize"), + 40, + TEXT("Mazimum size of the softening kernels in pixels."), + ECVF_RenderThreadSafe); + DECLARE_FLOAT_COUNTER_STAT(TEXT("ShadowProjection"), Stat_GPU_ShadowProjection, STATGROUP_GPU); // 0:off, 1:low, 2:med, 3:high, 4:very high, 5:max @@ -144,15 +158,15 @@ TGlobalResource StencilingGeometry TGlobalResource StencilingGeometry::GStencilConeIndexBuffer; /*----------------------------------------------------------------------------- - FShadowProjectionVS + FShadowVolumeBoundProjectionVS -----------------------------------------------------------------------------*/ -bool FShadowProjectionVS::ShouldCache(EShaderPlatform Platform) +bool FShadowVolumeBoundProjectionVS::ShouldCache(EShaderPlatform Platform) { return true; } -void FShadowProjectionVS::SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, const FProjectedShadowInfo* ShadowInfo) +void FShadowVolumeBoundProjectionVS::SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, const FProjectedShadowInfo* ShadowInfo) { FGlobalShader::SetParameters(RHICmdList, GetVertexShader(),View.ViewUniformBuffer); @@ -176,7 +190,7 @@ void FShadowProjectionVS::SetParameters(FRHICommandList& RHICmdList, const FScen IMPLEMENT_SHADER_TYPE(,FShadowProjectionNoTransformVS,TEXT("ShadowProjectionVertexShader"),TEXT("Main"),SF_Vertex); -IMPLEMENT_SHADER_TYPE(,FShadowProjectionVS,TEXT("ShadowProjectionVertexShader"),TEXT("Main"),SF_Vertex); +IMPLEMENT_SHADER_TYPE(,FShadowVolumeBoundProjectionVS,TEXT("ShadowProjectionVertexShader"),TEXT("Main"),SF_Vertex); /** * Implementations for TShadowProjectionPS. @@ -199,6 +213,8 @@ IMPLEMENT_SHADOW_PROJECTION_PIXEL_SHADER(2,true); IMPLEMENT_SHADOW_PROJECTION_PIXEL_SHADER(3,true); IMPLEMENT_SHADOW_PROJECTION_PIXEL_SHADER(4,true); IMPLEMENT_SHADOW_PROJECTION_PIXEL_SHADER(5,true); + +#undef IMPLEMENT_SHADOW_PROJECTION_PIXEL_SHADER #endif // Implement a pixel shader for rendering modulated shadow projections. @@ -220,7 +236,15 @@ IMPLEMENT_SHADER_TYPE(template<>,TOnePassPointShadowProjectionPS<1>,TEXT("Shadow IMPLEMENT_SHADER_TYPE(template<>,TOnePassPointShadowProjectionPS<2>,TEXT("ShadowProjectionPixelShader"),TEXT("MainOnePassPointLightPS"),SF_Pixel); IMPLEMENT_SHADER_TYPE(template<>,TOnePassPointShadowProjectionPS<3>,TEXT("ShadowProjectionPixelShader"),TEXT("MainOnePassPointLightPS"),SF_Pixel); IMPLEMENT_SHADER_TYPE(template<>,TOnePassPointShadowProjectionPS<4>,TEXT("ShadowProjectionPixelShader"),TEXT("MainOnePassPointLightPS"),SF_Pixel); -IMPLEMENT_SHADER_TYPE(template<>,TOnePassPointShadowProjectionPS<5>,TEXT("ShadowProjectionPixelShader"),TEXT("MainOnePassPointLightPS"),SF_Pixel); +IMPLEMENT_SHADER_TYPE(template<>, TOnePassPointShadowProjectionPS<5>, TEXT("ShadowProjectionPixelShader"), TEXT("MainOnePassPointLightPS"), SF_Pixel); + +// Implements a pixel shader for directional light PCSS. +#define IMPLEMENT_SHADOW_PROJECTION_PIXEL_SHADER(Quality,UseFadePlane) \ + typedef TDirectionalPercentageCloserShadowProjectionPS TDirectionalPercentageCloserShadowProjectionPS##Quality##UseFadePlane; \ + IMPLEMENT_SHADER_TYPE(template<>,TDirectionalPercentageCloserShadowProjectionPS##Quality##UseFadePlane,TEXT("ShadowProjectionPixelShader"),TEXT("Main"),SF_Pixel); +IMPLEMENT_SHADOW_PROJECTION_PIXEL_SHADER(5,false); +IMPLEMENT_SHADOW_PROJECTION_PIXEL_SHADER(5,true); +#undef IMPLEMENT_SHADOW_PROJECTION_PIXEL_SHADER void StencilingGeometry::DrawSphere(FRHICommandList& RHICmdList) { @@ -247,88 +271,100 @@ void StencilingGeometry::DrawCone(FRHICommandList& RHICmdList) FStencilConeIndexBuffer::NumVerts, 0, StencilingGeometry::GStencilConeIndexBuffer.GetIndexCount() / 3, 1); } -template -static void SetShadowProjectionShaderTemplNew(FRHICommandList& RHICmdList, FGraphicsPipelineStateInitializer& GraphicsPSOInit, int32 ViewIndex, const FViewInfo& View, const FProjectedShadowInfo* ShadowInfo, bool bMobileModulatedProjections) +static void GetShadowProjectionShaders( + int32 Quality, const FViewInfo& View, const FProjectedShadowInfo* ShadowInfo, bool bMobileModulatedProjections, + FShadowProjectionVertexShaderInterface** OutShadowProjVS, FShadowProjectionPixelShaderInterface** OutShadowProjPS) { + check(!*OutShadowProjVS); + check(!*OutShadowProjPS); + if (ShadowInfo->bTranslucentShadow) { - // Get the Shadow Projection Vertex Shader (with transforms) - FShadowProjectionVS* ShadowProjVS = View.ShaderMap->GetShader(); + *OutShadowProjVS = View.ShaderMap->GetShader(); - // Get the translucency pixel shader - FShadowProjectionPixelShaderInterface* ShadowProjPS = View.ShaderMap->GetShader >(); - - GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GetVertexDeclarationFVector4(); - GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(ShadowProjVS); - GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(ShadowProjPS); - - SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit); - - // Set shader parameters - ShadowProjVS->SetParameters(RHICmdList, View, ShadowInfo); - ShadowProjPS->SetParameters(RHICmdList, ViewIndex, View, ShadowInfo); + switch (Quality) + { + case 1: *OutShadowProjPS = View.ShaderMap->GetShader >(); break; + case 2: *OutShadowProjPS = View.ShaderMap->GetShader >(); break; + case 3: *OutShadowProjPS = View.ShaderMap->GetShader >(); break; + case 4: *OutShadowProjPS = View.ShaderMap->GetShader >(); break; + case 5: *OutShadowProjPS = View.ShaderMap->GetShader >(); break; + default: + check(0); + } } else if (ShadowInfo->IsWholeSceneDirectionalShadow()) { - // Get the Shadow Projection Vertex Shader which does not use a transform - FShadowProjectionNoTransformVS* ShadowProjVS = View.ShaderMap->GetShader(); + *OutShadowProjVS = View.ShaderMap->GetShader(); - // Get the Shadow Projection Pixel Shader for PSSM - if (ShadowInfo->CascadeSettings.FadePlaneLength > 0) + if (CVarFilterMethod.GetValueOnRenderThread() == 1) { - // This shader fades the shadow towards the end of the split subfrustum. - FShadowProjectionPixelShaderInterface* ShadowProjPS = View.ShaderMap->GetShader >(); - - GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GetVertexDeclarationFVector4(); - GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(ShadowProjVS); - GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(ShadowProjPS); - - SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit); - - ShadowProjPS->SetParameters(RHICmdList, ViewIndex, View, ShadowInfo); + if (ShadowInfo->CascadeSettings.FadePlaneLength > 0) + *OutShadowProjPS = View.ShaderMap->GetShader >(); + else + *OutShadowProjPS = View.ShaderMap->GetShader >(); + } + else if (ShadowInfo->CascadeSettings.FadePlaneLength > 0) + { + switch (Quality) + { + case 1: *OutShadowProjPS = View.ShaderMap->GetShader >(); break; + case 2: *OutShadowProjPS = View.ShaderMap->GetShader >(); break; + case 3: *OutShadowProjPS = View.ShaderMap->GetShader >(); break; + case 4: *OutShadowProjPS = View.ShaderMap->GetShader >(); break; + case 5: *OutShadowProjPS = View.ShaderMap->GetShader >(); break; + default: + check(0); + } } else { - // Do not use the fade plane shader if the fade plane region length is 0 (avoids divide by 0). - FShadowProjectionPixelShaderInterface* ShadowProjPS = View.ShaderMap->GetShader >(); - - GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GetVertexDeclarationFVector4(); - GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(ShadowProjVS); - GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(ShadowProjPS); - - SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit); - - ShadowProjPS->SetParameters(RHICmdList, ViewIndex, View, ShadowInfo); + switch (Quality) + { + case 1: *OutShadowProjPS = View.ShaderMap->GetShader >(); break; + case 2: *OutShadowProjPS = View.ShaderMap->GetShader >(); break; + case 3: *OutShadowProjPS = View.ShaderMap->GetShader >(); break; + case 4: *OutShadowProjPS = View.ShaderMap->GetShader >(); break; + case 5: *OutShadowProjPS = View.ShaderMap->GetShader >(); break; + default: + check(0); + } } - - ShadowProjVS->SetParameters(RHICmdList, View.ViewUniformBuffer); } else { - // Get the Shadow Projection Vertex Shader - FShadowProjectionVS* ShadowProjVS = View.ShaderMap->GetShader(); + *OutShadowProjVS = View.ShaderMap->GetShader(); - // Get the Shadow Projection Pixel Shader - // This shader is the ordinary projection shader used by point/spot lights. - FShadowProjectionPixelShaderInterface* ShadowProjPS; if(bMobileModulatedProjections) { - ShadowProjPS = View.ShaderMap->GetShader >(); + switch (Quality) + { + case 1: *OutShadowProjPS = View.ShaderMap->GetShader >(); break; + case 2: *OutShadowProjPS = View.ShaderMap->GetShader >(); break; + case 3: *OutShadowProjPS = View.ShaderMap->GetShader >(); break; + case 4: *OutShadowProjPS = View.ShaderMap->GetShader >(); break; + case 5: *OutShadowProjPS = View.ShaderMap->GetShader >(); break; + default: + check(0); + } } else { - ShadowProjPS = View.ShaderMap->GetShader >(); + switch (Quality) + { + case 1: *OutShadowProjPS = View.ShaderMap->GetShader >(); break; + case 2: *OutShadowProjPS = View.ShaderMap->GetShader >(); break; + case 3: *OutShadowProjPS = View.ShaderMap->GetShader >(); break; + case 4: *OutShadowProjPS = View.ShaderMap->GetShader >(); break; + case 5: *OutShadowProjPS = View.ShaderMap->GetShader >(); break; + default: + check(0); + } } - - GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GetVertexDeclarationFVector4(); - GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(ShadowProjVS); - GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(ShadowProjPS); - - SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit); - - ShadowProjVS->SetParameters(RHICmdList, View, ShadowInfo); - ShadowProjPS->SetParameters(RHICmdList, ViewIndex, View, ShadowInfo); } + + check(*OutShadowProjVS); + check(*OutShadowProjPS); } void FProjectedShadowInfo::SetBlendStateForProjection( @@ -424,7 +460,7 @@ void FProjectedShadowInfo::SetBlendStateForProjection( { if (bMobileModulatedProjections) { - bool bEncodedHDR = IsMobileHDR32bpp() && !IsMobileHDRMosaic(); + bool bEncodedHDR = GetMobileHDRMode() == EMobileHDRMode::EnabledRGBE; if (bEncodedHDR) { GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI(); @@ -607,7 +643,7 @@ void FProjectedShadowInfo::SetupProjectionStencilMask( *View, FDepthDrawingPolicyFactory::ContextType(DDM_AllOccluders, false), StaticMesh, - StaticMesh.bRequiresPerElementVisibility ? View->StaticMeshBatchVisibility[StaticMesh.Id] : ((1ull << StaticMesh.Elements.Num() )- 1), + StaticMesh.bRequiresPerElementVisibility ? View->StaticMeshBatchVisibility[StaticMesh.BatchVisibilityId] : ((1ull << StaticMesh.Elements.Num() )- 1), true, DrawRenderState, ReceiverPrimitiveSceneInfo->Proxy, @@ -631,7 +667,7 @@ void FProjectedShadowInfo::SetupProjectionStencilMask( *View, FDepthDrawingPolicyFactory::ContextType(DDM_AllOccluders, false), StaticMesh, - StaticMesh.bRequiresPerElementVisibility ? View->StaticMeshBatchVisibility[StaticMesh.Id] : ((1ull << StaticMesh.Elements.Num() )- 1), + StaticMesh.bRequiresPerElementVisibility ? View->StaticMeshBatchVisibility[StaticMesh.BatchVisibilityId] : ((1ull << StaticMesh.Elements.Num() )- 1), true, DrawRenderState, StaticMesh.PrimitiveSceneInfo->Proxy, @@ -746,7 +782,7 @@ void FProjectedShadowInfo::SetupProjectionStencilMask( GraphicsPSOInit.RasterizerState = TStaticRasterizerState::GetRHI(); // Find the projection shaders. - TShaderMapRef VertexShader(View->ShaderMap); + TShaderMapRef VertexShader(View->ShaderMap); GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GetVertexDeclarationFVector4(); GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(*VertexShader); @@ -910,16 +946,19 @@ void FProjectedShadowInfo::RenderProjection(FRHICommandListImmediate& RHICmdList } } - switch(LocalQuality) - { - case 1: SetShadowProjectionShaderTemplNew<1>(RHICmdList, GraphicsPSOInit, ViewIndex, *View, this, bMobileModulatedProjections); break; - case 2: SetShadowProjectionShaderTemplNew<2>(RHICmdList, GraphicsPSOInit, ViewIndex, *View, this, bMobileModulatedProjections); break; - case 3: SetShadowProjectionShaderTemplNew<3>(RHICmdList, GraphicsPSOInit, ViewIndex, *View, this, bMobileModulatedProjections); break; - case 4: SetShadowProjectionShaderTemplNew<4>(RHICmdList, GraphicsPSOInit, ViewIndex, *View, this, bMobileModulatedProjections); break; - case 5: SetShadowProjectionShaderTemplNew<5>(RHICmdList, GraphicsPSOInit, ViewIndex, *View, this, bMobileModulatedProjections); break; - default: - check(0); - } + FShadowProjectionVertexShaderInterface* ShadowProjVS = nullptr; + FShadowProjectionPixelShaderInterface* ShadowProjPS = nullptr; + + GetShadowProjectionShaders(LocalQuality, *View, this, bMobileModulatedProjections, &ShadowProjVS, &ShadowProjPS); + + GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GetVertexDeclarationFVector4(); + GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(ShadowProjVS); + GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(ShadowProjPS); + + SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit); + + ShadowProjVS->SetParameters(RHICmdList, *View, this); + ShadowProjPS->SetParameters(RHICmdList, ViewIndex, *View, this); } if (IsWholeSceneDirectionalShadow()) @@ -949,7 +988,7 @@ void FProjectedShadowInfo::RenderProjection(FRHICommandListImmediate& RHICmdList // Clear the stencil buffer to 0. if (!GStencilOptimization) { - DrawClearQuad(RHICmdList, GMaxRHIFeatureLevel, false, FLinearColor::Transparent, false, 0, true, 1); + DrawClearQuad(RHICmdList, false, FLinearColor::Transparent, false, 0, true, 1); } } } @@ -958,7 +997,7 @@ void FProjectedShadowInfo::RenderProjection(FRHICommandListImmediate& RHICmdList template static void SetPointLightShaderTempl(FRHICommandList& RHICmdList, FGraphicsPipelineStateInitializer& GraphicsPSOInit, int32 ViewIndex, const FViewInfo& View, const FProjectedShadowInfo* ShadowInfo) { - TShaderMapRef VertexShader(View.ShaderMap); + TShaderMapRef VertexShader(View.ShaderMap); TShaderMapRef > PixelShader(View.ShaderMap); GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GetVertexDeclarationFVector4(); @@ -1333,7 +1372,7 @@ bool FDeferredShadingSceneRenderer::InjectReflectiveShadowMaps(FRHICommandListIm extern int32 GCapsuleShadows; -bool FSceneRenderer::RenderShadowProjections(FRHICommandListImmediate& RHICmdList, const FLightSceneInfo* LightSceneInfo, bool bProjectingForForwardShading, bool bMobileModulatedProjections) +bool FSceneRenderer::RenderShadowProjections(FRHICommandListImmediate& RHICmdList, const FLightSceneInfo* LightSceneInfo, IPooledRenderTarget* ScreenShadowMaskTexture, bool bProjectingForForwardShading, bool bMobileModulatedProjections) { FVisibleLightInfo& VisibleLightInfo = VisibleLightInfos[LightSceneInfo->Id]; FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); @@ -1344,8 +1383,8 @@ bool FSceneRenderer::RenderShadowProjections(FRHICommandListImmediate& RHICmdLis } else { - // Normal deferred shadows render to light attenuation - SceneContext.BeginRenderingLightAttenuation(RHICmdList); + // Normal deferred shadows render to the shadow mask + SetRenderTarget(RHICmdList, ScreenShadowMaskTexture->GetRenderTargetItem().TargetableTexture, SceneContext.GetSceneDepthSurface(), ESimpleRenderTargetMode::EExistingColorAndDepth, FExclusiveDepthStencil::DepthRead_StencilWrite, true); } for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) @@ -1367,7 +1406,7 @@ bool FSceneRenderer::RenderShadowProjections(FRHICommandListImmediate& RHICmdLis if (ProjectedShadowInfo->bRayTracedDistanceField) { - ProjectedShadowInfo->RenderRayTracedDistanceFieldProjection(RHICmdList, View, bProjectingForForwardShading); + ProjectedShadowInfo->RenderRayTracedDistanceFieldProjection(RHICmdList, View, ScreenShadowMaskTexture, bProjectingForForwardShading); } else if (ProjectedShadowInfo->bAllocated) { @@ -1382,11 +1421,6 @@ bool FSceneRenderer::RenderShadowProjections(FRHICommandListImmediate& RHICmdLis { ProjectedShadowInfo->RenderProjection(RHICmdList, ViewIndex, &View, bProjectingForForwardShading, bMobileModulatedProjections); } - - if (!bMobileModulatedProjections) - { - GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SceneContext.GetLightAttenuation()); - } } } } @@ -1398,7 +1432,7 @@ bool FSceneRenderer::RenderShadowProjections(FRHICommandListImmediate& RHICmdLis return true; } -bool FDeferredShadingSceneRenderer::RenderShadowProjections(FRHICommandListImmediate& RHICmdList, const FLightSceneInfo* LightSceneInfo, bool& bInjectedTranslucentVolume) +bool FDeferredShadingSceneRenderer::RenderShadowProjections(FRHICommandListImmediate& RHICmdList, const FLightSceneInfo* LightSceneInfo, IPooledRenderTarget* ScreenShadowMaskTexture, bool& bInjectedTranslucentVolume) { SCOPE_CYCLE_COUNTER(STAT_ProjectedShadowDrawTime); SCOPED_DRAW_EVENT(RHICmdList, ShadowProjectionOnOpaque); @@ -1406,7 +1440,7 @@ bool FDeferredShadingSceneRenderer::RenderShadowProjections(FRHICommandListImmed FVisibleLightInfo& VisibleLightInfo = VisibleLightInfos[LightSceneInfo->Id]; - FSceneRenderer::RenderShadowProjections(RHICmdList, LightSceneInfo, false, false); + FSceneRenderer::RenderShadowProjections(RHICmdList, LightSceneInfo, ScreenShadowMaskTexture, false, false); for (int32 ShadowIndex = 0; ShadowIndex < VisibleLightInfo.ShadowsToProject.Num(); ShadowIndex++) { @@ -1428,7 +1462,7 @@ bool FDeferredShadingSceneRenderer::RenderShadowProjections(FRHICommandListImmed } } - RenderCapsuleDirectShadows(*LightSceneInfo, RHICmdList, VisibleLightInfo.CapsuleShadowsToProject, false); + RenderCapsuleDirectShadows(RHICmdList, *LightSceneInfo, ScreenShadowMaskTexture, VisibleLightInfo.CapsuleShadowsToProject, false); for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) { @@ -1466,7 +1500,7 @@ void FMobileSceneRenderer::RenderModulatedShadowProjections(FRHICommandListImmed { TArray Shadows; SCOPE_CYCLE_COUNTER(STAT_ProjectedShadowDrawTime); - FSceneRenderer::RenderShadowProjections(RHICmdList, LightSceneInfo, false, true); + FSceneRenderer::RenderShadowProjections(RHICmdList, LightSceneInfo, NULL, false, true); } } } diff --git a/Engine/Source/Runtime/Renderer/Private/ShadowRendering.h b/Engine/Source/Runtime/Renderer/Private/ShadowRendering.h index 59c296cb38a9..866993205cc2 100644 --- a/Engine/Source/Runtime/Renderer/Private/ShadowRendering.h +++ b/Engine/Source/Runtime/Renderer/Private/ShadowRendering.h @@ -881,7 +881,7 @@ public: void BeginRenderRayTracedDistanceFieldProjection(FRHICommandListImmediate& RHICmdList, const FViewInfo& View); /** Renders ray traced distance field shadows. */ - void RenderRayTracedDistanceFieldProjection(FRHICommandListImmediate& RHICmdList, const class FViewInfo& View, bool bProjectingForForwardShading); + void RenderRayTracedDistanceFieldProjection(FRHICommandListImmediate& RHICmdList, const class FViewInfo& View, IPooledRenderTarget* ScreenShadowMaskTexture, bool bProjectingForForwardShading); /** Render one pass point light shadow projections. */ void RenderOnePassPointLightProjection(FRHICommandListImmediate& RHICmdList, int32 ViewIndex, const FViewInfo& View, bool bProjectingForForwardShading) const; @@ -894,7 +894,7 @@ public: /** * Adds a primitive to the shadow's subject list. */ - void AddSubjectPrimitive(FPrimitiveSceneInfo* PrimitiveSceneInfo, TArray* ViewArray, bool bRecordShadowSubjectForMobileShading); + void AddSubjectPrimitive(FPrimitiveSceneInfo* PrimitiveSceneInfo, TArray* ViewArray, ERHIFeatureLevel::Type FeatureLevel, bool bRecordShadowSubjectForMobileShading); /** * @return TRUE if this shadow info has any casting subject prims to render @@ -1068,7 +1068,7 @@ private: friend class FShadowDepthVS; template friend class TShadowDepthBasePS; - friend class FShadowProjectionVS; + friend class FShadowVolumeBoundProjectionVS; friend class FShadowProjectionPS; friend class FShadowDepthDrawingPolicyFactory; }; @@ -1190,16 +1190,31 @@ private: FShaderParameter StencilPreViewTranslation; }; +/** +* A generic vertex shader for projecting a shadow depth buffer onto the scene. +*/ +class FShadowProjectionVertexShaderInterface : public FGlobalShader +{ +public: + FShadowProjectionVertexShaderInterface() {} + FShadowProjectionVertexShaderInterface(const ShaderMetaType::CompiledShaderInitializerType& Initializer) + : FGlobalShader(Initializer) + { } + + virtual void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, const FProjectedShadowInfo* ShadowInfo) = 0; +}; + /** * A vertex shader for projecting a shadow depth buffer onto the scene. */ -class FShadowProjectionVS : public FGlobalShader +class FShadowVolumeBoundProjectionVS : public FShadowProjectionVertexShaderInterface { - DECLARE_SHADER_TYPE(FShadowProjectionVS,Global); + DECLARE_SHADER_TYPE(FShadowVolumeBoundProjectionVS,Global); public: - FShadowProjectionVS() {} - FShadowProjectionVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) : FGlobalShader(Initializer) + FShadowVolumeBoundProjectionVS() {} + FShadowVolumeBoundProjectionVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) + : FShadowProjectionVertexShaderInterface(Initializer) { StencilingGeometryParameters.Bind(Initializer.ParameterMap); } @@ -1208,11 +1223,11 @@ public: static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment) { - FGlobalShader::ModifyCompilationEnvironment(Platform, OutEnvironment); + FShadowProjectionVertexShaderInterface::ModifyCompilationEnvironment(Platform, OutEnvironment); OutEnvironment.SetDefine(TEXT("USE_TRANSFORM"), (uint32)1); } - void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, const FProjectedShadowInfo* ShadowInfo); + void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, const FProjectedShadowInfo* ShadowInfo) override; //~ Begin FShader Interface virtual bool Serialize(FArchive& Ar) override @@ -1227,13 +1242,13 @@ private: FStencilingGeometryShaderParameters StencilingGeometryParameters; }; -class FShadowProjectionNoTransformVS : public FGlobalShader +class FShadowProjectionNoTransformVS : public FShadowProjectionVertexShaderInterface { DECLARE_SHADER_TYPE(FShadowProjectionNoTransformVS,Global); public: FShadowProjectionNoTransformVS() {} FShadowProjectionNoTransformVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) - : FGlobalShader(Initializer) + : FShadowProjectionVertexShaderInterface(Initializer) { } @@ -1243,7 +1258,7 @@ public: */ static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment) { - FGlobalShader::ModifyCompilationEnvironment(Platform, OutEnvironment); + FShadowProjectionVertexShaderInterface::ModifyCompilationEnvironment(Platform, OutEnvironment); OutEnvironment.SetDefine(TEXT("USE_TRANSFORM"), (uint32)0); } @@ -1252,10 +1267,15 @@ public: return true; } - inline void SetParameters(FRHICommandList& RHICmdList, const FUniformBufferRHIParamRef ViewUniformBuffer) + void SetParameters(FRHICommandList& RHICmdList, const FUniformBufferRHIParamRef ViewUniformBuffer) { FGlobalShader::SetParameters(RHICmdList, GetVertexShader(), ViewUniformBuffer); } + + void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, const FProjectedShadowInfo*) override + { + FGlobalShader::SetParameters(RHICmdList, GetVertexShader(), View.ViewUniformBuffer); + } }; /** @@ -1323,25 +1343,27 @@ public: { const FPixelShaderRHIParamRef ShaderRHI = Shader->GetPixelShader(); - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_Surface); const FIntPoint ShadowBufferResolution = ShadowInfo->GetShadowBufferResolution(); + if (ShadowTileOffsetAndSizeParam.IsBound()) + { + FVector2D InverseShadowBufferResolution(1.0f / ShadowBufferResolution.X, 1.0f / ShadowBufferResolution.Y); + FVector4 ShadowTileOffsetAndSize( + (ShadowInfo->BorderSize + ShadowInfo->X) * InverseShadowBufferResolution.X, + (ShadowInfo->BorderSize + ShadowInfo->Y) * InverseShadowBufferResolution.Y, + ShadowInfo->ResolutionX * InverseShadowBufferResolution.X, + ShadowInfo->ResolutionY * InverseShadowBufferResolution.Y); + SetShaderValue(RHICmdList, ShaderRHI, ShadowTileOffsetAndSizeParam, ShadowTileOffsetAndSize); + } + // Set the transform from screen coordinates to shadow depth texture coordinates. if (bModulatedShadows) { // UE-29083 : work around precision issues with ScreenToShadowMatrix on low end devices. const FMatrix ScreenToShadow = ShadowInfo->GetScreenToShadowMatrix(View, 0, 0, ShadowBufferResolution.X, ShadowBufferResolution.Y); SetShaderValue(RHICmdList, ShaderRHI, ScreenToShadowMatrix, ScreenToShadow); - - FVector2D InverseShadowBufferResolution(1.0f/ShadowBufferResolution.X, 1.0f/ShadowBufferResolution.Y); - FVector4 ShadowTileOffsetAndSize( - (ShadowInfo->BorderSize + ShadowInfo->X) * InverseShadowBufferResolution.X, - (ShadowInfo->BorderSize + ShadowInfo->Y) * InverseShadowBufferResolution.Y, - ShadowInfo->ResolutionX * InverseShadowBufferResolution.X, - ShadowInfo->ResolutionY * InverseShadowBufferResolution.Y); - - SetShaderValue(RHICmdList, ShaderRHI, ShadowTileOffsetAndSizeParam, ShadowTileOffsetAndSize); } else { @@ -1828,7 +1850,7 @@ public: FGlobalShader::SetParameters(RHICmdList, ShaderRHI,View.ViewUniformBuffer); - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_Surface); OnePassShadowParameters.Set(RHICmdList, ShaderRHI, ShadowInfo); const FLightSceneProxy& LightProxy = *(ShadowInfo->GetLightSceneInfo().Proxy); @@ -1886,6 +1908,72 @@ struct FShadowProjectionMatrix: FMatrix {} }; + +/** Pixel shader to project directional PCSS onto the scene. */ +template +class TDirectionalPercentageCloserShadowProjectionPS : public TShadowProjectionPS +{ + DECLARE_SHADER_TYPE(TDirectionalPercentageCloserShadowProjectionPS, Global); +public: + + TDirectionalPercentageCloserShadowProjectionPS() {} + TDirectionalPercentageCloserShadowProjectionPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) : + TShadowProjectionPS(Initializer) + { + PCSSParameters.Bind(Initializer.ParameterMap, TEXT("PCSSParameters")); + } + + static bool ShouldCache(EShaderPlatform Platform) + { + return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5) && Platform == SP_PCD3D_SM5; + } + + static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment) + { + TShadowProjectionPS::ModifyCompilationEnvironment(Platform, OutEnvironment); + OutEnvironment.SetDefine(TEXT("USE_PCSS"), 1); + } + + virtual void SetParameters( + FRHICommandList& RHICmdList, + int32 ViewIndex, + const FSceneView& View, + const FProjectedShadowInfo* ShadowInfo) override + { + TShadowProjectionPS::SetParameters(RHICmdList, ViewIndex, View, ShadowInfo); + + const FPixelShaderRHIParamRef ShaderRHI = this->GetPixelShader(); + + // GetLightSourceAngle returns the full angle. + float TanLightSourceAngle = FMath::Tan(0.5 * FMath::DegreesToRadians(ShadowInfo->GetLightSceneInfo().Proxy->GetLightSourceAngle())); + + static IConsoleVariable* CVarMaxSoftShadowKernelSize = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Shadow.MaxSoftKernelSize")); + check(CVarMaxSoftShadowKernelSize); + int32 MaxKernelSize = CVarMaxSoftShadowKernelSize->GetInt(); + + float SW = 2.0 * ShadowInfo->ShadowBounds.W; + float SZ = ShadowInfo->MaxSubjectZ - ShadowInfo->MinSubjectZ; + + FVector4 PCSSParameterValues = FVector4(TanLightSourceAngle * SZ / SW, MaxKernelSize / float(ShadowInfo->ResolutionX), 0, 0); + SetShaderValue(RHICmdList, ShaderRHI, PCSSParameters, PCSSParameterValues); + } + + /** + * Serialize the parameters for this shader + * @param Ar - archive to serialize to + */ + virtual bool Serialize(FArchive& Ar) override + { + bool bShaderHasOutdatedParameters = TShadowProjectionPS::Serialize(Ar); + Ar << PCSSParameters; + return bShaderHasOutdatedParameters; + } + +protected: + FShaderParameter PCSSParameters; +}; + + // Sort by descending resolution struct FCompareFProjectedShadowInfoByResolution { diff --git a/Engine/Source/Runtime/Renderer/Private/ShadowSetup.cpp b/Engine/Source/Runtime/Renderer/Private/ShadowSetup.cpp index f68fb0dcf31e..1efd2117234a 100644 --- a/Engine/Source/Runtime/Renderer/Private/ShadowSetup.cpp +++ b/Engine/Source/Runtime/Renderer/Private/ShadowSetup.cpp @@ -28,7 +28,7 @@ #include "LightPropagationVolume.h" #include "ScenePrivate.h" #include "RendererModule.h" -#include "LightPropagationVolumeBlendable.h" +#include "LightPropagationVolumeSettings.h" #include "CapsuleShadowRendering.h" static float GMinScreenRadiusForShadowCaster = 0.03f; @@ -193,6 +193,28 @@ static TAutoConsoleVariable CVarEnableCsmShaderCulling( TEXT(""), ECVF_RenderThreadSafe); +static TAutoConsoleVariable CVarParallelGatherShadowPrimitives( + TEXT("r.ParallelGatherShadowPrimitives"), + 1, + TEXT("Toggles parallel Gather shadow primitives. 0 = off; 1 = on"), + ECVF_RenderThreadSafe + ); + +static TAutoConsoleVariable CVarParallelGatherNumPrimitivesPerPacket( + TEXT("r.ParallelGatherNumPrimitivesPerPacket"), + 256, + TEXT("Number of primitives per packet. Only used when r.Shadow.UseOctreeForCulling is disabled."), + ECVF_RenderThreadSafe + ); + +int32 GUseOctreeForShadowCulling = 1; +FAutoConsoleVariableRef CVarUseOctreeForShadowCulling( + TEXT("r.Shadow.UseOctreeForCulling"), + GUseOctreeForShadowCulling, + TEXT("Whether to use the primitive octree for shadow subject culling. The octree culls large groups of primitives at a time, but introduces cache misses walking the data structure."), + ECVF_Scalability | ECVF_RenderThreadSafe + ); + #if !UE_BUILD_SHIPPING // read and written on the render thread bool GDumpShadowSetup = false; @@ -739,7 +761,7 @@ void FProjectedShadowInfo::SetupWholeSceneProjection( UpdateShaderDepthBias(); } -void FProjectedShadowInfo::AddSubjectPrimitive(FPrimitiveSceneInfo* PrimitiveSceneInfo, TArray* ViewArray, bool bRecordShadowSubjectsForMobileShading) +void FProjectedShadowInfo::AddSubjectPrimitive(FPrimitiveSceneInfo* PrimitiveSceneInfo, TArray* ViewArray, ERHIFeatureLevel::Type FeatureLevel, bool bRecordShadowSubjectsForMobileShading) { QUICK_SCOPE_CYCLE_COUNTER(STAT_AddSubjectPrimitive); @@ -774,7 +796,6 @@ void FProjectedShadowInfo::AddSubjectPrimitive(FPrimitiveSceneInfo* PrimitiveSce bool bShadowRelevance = false; uint32 ViewMask = 0; int32 PrimitiveId = PrimitiveSceneInfo->GetIndex(); - const auto FeatureLevel = PrimitiveSceneInfo->Scene->GetFeatureLevel(); for (int32 ViewIndex = 0, Num = Views.Num(); ViewIndex < Num; ViewIndex++) { @@ -800,6 +821,12 @@ void FProjectedShadowInfo::AddSubjectPrimitive(FPrimitiveSceneInfo* PrimitiveSce } } + // Respect HLOD visibility which can hide child LOD primitives + if (CurrentView.ViewState && CurrentView.ViewState->HLODVisibilityState.IsNodeHidden(PrimitiveId)) + { + continue; + } + // Compute the subject primitive's view relevance since it wasn't cached // Update the main view's PrimitiveViewRelevanceMap ViewRelevance = PrimitiveSceneInfo->Proxy->GetViewRelevance(&CurrentView); @@ -877,9 +904,11 @@ void FProjectedShadowInfo::AddSubjectPrimitive(FPrimitiveSceneInfo* PrimitiveSce if (bMeshIsVisible && bWholeSceneDirectionalShadow) { StaticMeshWholeSceneShadowDepthMap[StaticMesh.Id] = true; - StaticMeshWholeSceneShadowBatchVisibility[StaticMesh.Id] = StaticMesh.bRequiresPerElementVisibility - ? StaticMesh.VertexFactory->GetStaticBatchElementShadowVisibility(CurrentView, LightSceneInfo->Proxy, &StaticMesh) - : ((1ull << StaticMesh.Elements.Num()) - 1); + + if (StaticMesh.bRequiresPerElementVisibility) + { + StaticMeshWholeSceneShadowBatchVisibility[StaticMesh.BatchVisibilityId] = StaticMesh.VertexFactory->GetStaticBatchElementVisibility(CurrentView, &StaticMesh); + } } } } @@ -894,7 +923,18 @@ void FProjectedShadowInfo::AddSubjectPrimitive(FPrimitiveSceneInfo* PrimitiveSce else { FLODMask LODToRender; - int32 ForcedLODLevel = (CurrentView.Family->EngineShowFlags.LOD) ? GetCVarForceLOD() : 0; + int32 ForcedLODLevel = 0; + + if (CurrentView.Family->EngineShowFlags.LOD) + { + // Shadow specific setting is highest priority + ForcedLODLevel = GetCVarForceLODShadow(); + + if (ForcedLODLevel == -1) + { + ForcedLODLevel = GetCVarForceLOD(); + } + } // Add the primitive's static mesh elements to the draw lists. if (bForceLowestDetailLevel) @@ -912,10 +952,7 @@ void FProjectedShadowInfo::AddSubjectPrimitive(FPrimitiveSceneInfo* PrimitiveSce } else { - FPrimitiveBounds PrimitiveBounds; - PrimitiveBounds.Origin = Bounds.Origin; - PrimitiveBounds.SphereRadius = Bounds.SphereRadius; - LODToRender = ComputeLODForMeshes(PrimitiveSceneInfo->StaticMeshes, CurrentView, PrimitiveBounds.Origin, PrimitiveBounds.SphereRadius, ForcedLODLevel); + LODToRender = ComputeLODForMeshes(PrimitiveSceneInfo->StaticMeshes, CurrentView, Bounds.Origin, Bounds.SphereRadius, ForcedLODLevel); } if (bWholeSceneDirectionalShadow) @@ -926,9 +963,11 @@ void FProjectedShadowInfo::AddSubjectPrimitive(FPrimitiveSceneInfo* PrimitiveSce if (StaticMesh.CastShadow && LODToRender.ContainsLOD(StaticMesh.LODIndex)) { StaticMeshWholeSceneShadowDepthMap[StaticMesh.Id] = true; - StaticMeshWholeSceneShadowBatchVisibility[StaticMesh.Id] = StaticMesh.bRequiresPerElementVisibility - ? StaticMesh.VertexFactory->GetStaticBatchElementShadowVisibility(CurrentView, LightSceneInfo->Proxy, &StaticMesh) - : ((1ull << StaticMesh.Elements.Num()) - 1); + + if (StaticMesh.bRequiresPerElementVisibility) + { + StaticMeshWholeSceneShadowBatchVisibility[StaticMesh.BatchVisibilityId] = StaticMesh.VertexFactory->GetStaticBatchElementVisibility(CurrentView, &StaticMesh); + } bDrawingStaticMeshes = true; } @@ -942,9 +981,11 @@ void FProjectedShadowInfo::AddSubjectPrimitive(FPrimitiveSceneInfo* PrimitiveSce if (StaticMesh.CastShadow && LODToRender.ContainsLOD(StaticMesh.LODIndex)) { CurrentView.StaticMeshShadowDepthMap[StaticMesh.Id] = true; - CurrentView.StaticMeshBatchVisibility[StaticMesh.Id] = StaticMesh.bRequiresPerElementVisibility - ? StaticMesh.VertexFactory->GetStaticBatchElementShadowVisibility(CurrentView, LightSceneInfo->Proxy, &StaticMesh) - : ((1ull << StaticMesh.Elements.Num()) - 1); + + if (StaticMesh.bRequiresPerElementVisibility) + { + CurrentView.StaticMeshBatchVisibility[StaticMesh.BatchVisibilityId] = StaticMesh.VertexFactory->GetStaticBatchElementVisibility(CurrentView, &StaticMesh); + } bDrawingStaticMeshes = true; } @@ -1309,7 +1350,7 @@ void FSceneRenderer::UpdatePreshadowCache(FSceneRenderTargets& SceneContext) } } -bool FSceneRenderer::ShouldCreateObjectShadowForStationaryLight(const FLightSceneInfo* LightSceneInfo, const FPrimitiveSceneProxy* PrimitiveSceneProxy, bool bInteractionShadowMapped) const +bool ShouldCreateObjectShadowForStationaryLight(const FLightSceneInfo* LightSceneInfo, const FPrimitiveSceneProxy* PrimitiveSceneProxy, bool bInteractionShadowMapped) { const bool bCreateObjectShadowForStationaryLight = LightSceneInfo->bCreatePerObjectShadowsForDynamicObjects @@ -1620,7 +1661,7 @@ void FSceneRenderer::CreatePerObjectProjectedShadow( for (int32 ChildIndex = 0, ChildCount = ShadowGroupPrimitives.Num(); ChildIndex < ChildCount; ChildIndex++) { FPrimitiveSceneInfo* ShadowChild = ShadowGroupPrimitives[ChildIndex]; - ProjectedShadowInfo->AddSubjectPrimitive(ShadowChild, &Views, false); + ProjectedShadowInfo->AddSubjectPrimitive(ShadowChild, &Views, FeatureLevel, false); } } else if (bShadowIsPotentiallyVisibleNextFrame) @@ -1660,7 +1701,7 @@ void FSceneRenderer::CreatePerObjectProjectedShadow( for (int32 ChildIndex = 0, ChildCount = ShadowGroupPrimitives.Num(); ChildIndex < ChildCount; ChildIndex++) { FPrimitiveSceneInfo* ShadowChild = ShadowGroupPrimitives[ChildIndex]; - ProjectedShadowInfo->AddSubjectPrimitive(ShadowChild, &Views, false); + ProjectedShadowInfo->AddSubjectPrimitive(ShadowChild, &Views, FeatureLevel, false); } } else if (bShadowIsPotentiallyVisibleNextFrame) @@ -2061,7 +2102,7 @@ void FSceneRenderer::CreateWholeSceneProjectedShadow(FLightSceneInfo* LightScene && !Interaction->CastsSelfShadowOnly() && (!bStaticSceneOnly || Interaction->GetPrimitiveSceneInfo()->Proxy->HasStaticLighting())) { - ProjectedShadowInfo->AddSubjectPrimitive(Interaction->GetPrimitiveSceneInfo(), &Views, false); + ProjectedShadowInfo->AddSubjectPrimitive(Interaction->GetPrimitiveSceneInfo(), &Views, FeatureLevel, false); } } } @@ -2078,7 +2119,7 @@ void FSceneRenderer::CreateWholeSceneProjectedShadow(FLightSceneInfo* LightScene && !Interaction->CastsSelfShadowOnly() && (!bStaticSceneOnly || Interaction->GetPrimitiveSceneInfo()->Proxy->HasStaticLighting())) { - ProjectedShadowInfo->AddSubjectPrimitive(Interaction->GetPrimitiveSceneInfo(), &Views, false); + ProjectedShadowInfo->AddSubjectPrimitive(Interaction->GetPrimitiveSceneInfo(), &Views, FeatureLevel, false); } } } @@ -2360,124 +2401,193 @@ void FSceneRenderer::GatherShadowDynamicMeshElements() } } -inline void FSceneRenderer::GatherShadowsForPrimitiveInner( - const FPrimitiveSceneInfoCompact& PrimitiveSceneInfoCompact, - const TArray& PreShadows, - const TArray& ViewDependentWholeSceneShadows, - bool bStaticSceneOnly) +typedef TArray FShadowSubjectPrimitives; + +struct FGatherShadowPrimitivesPacket { - if(PrimitiveSceneInfoCompact.bCastDynamicShadow) + // Inputs + const FScene* Scene; + TArray& Views; + const FScenePrimitiveOctree::FNode* Node; + int32 StartPrimitiveIndex; + int32 NumPrimitives; + const TArray& PreShadows; + const TArray& ViewDependentWholeSceneShadows; + ERHIFeatureLevel::Type FeatureLevel; + bool bStaticSceneOnly; + + // Outputs + TArray PreShadowSubjectPrimitives; + TArray ViewDependentWholeSceneShadowSubjectPrimitives; + + FGatherShadowPrimitivesPacket( + const FScene* InScene, + TArray& InViews, + const FScenePrimitiveOctree::FNode* InNode, + int32 InStartPrimitiveIndex, + int32 InNumPrimitives, + const TArray& InPreShadows, + const TArray& InViewDependentWholeSceneShadows, + ERHIFeatureLevel::Type InFeatureLevel, + bool bInStaticSceneOnly) + : Scene(InScene) + , Views(InViews) + , Node(InNode) + , StartPrimitiveIndex(InStartPrimitiveIndex) + , NumPrimitives(InNumPrimitives) + , PreShadows(InPreShadows) + , ViewDependentWholeSceneShadows(InViewDependentWholeSceneShadows) + , FeatureLevel(InFeatureLevel) + , bStaticSceneOnly(bInStaticSceneOnly) { - FPrimitiveSceneInfo* RESTRICT PrimitiveSceneInfo = PrimitiveSceneInfoCompact.PrimitiveSceneInfo; - FPrimitiveSceneProxy* RESTRICT PrimitiveProxy = PrimitiveSceneInfoCompact.Proxy; - const FBoxSphereBounds& PrimitiveBounds = PrimitiveSceneInfoCompact.Bounds; + PreShadowSubjectPrimitives.Empty(PreShadows.Num()); + PreShadowSubjectPrimitives.AddDefaulted(PreShadows.Num()); - // Check if the primitive is a subject for any of the preshadows. - // Only allow preshadows from lightmapped primitives that cast both dynamic and static shadows. - if (PreShadows.Num() && PrimitiveProxy->CastsStaticShadow() && PrimitiveProxy->HasStaticLighting()) + ViewDependentWholeSceneShadowSubjectPrimitives.Empty(ViewDependentWholeSceneShadows.Num()); + ViewDependentWholeSceneShadowSubjectPrimitives.AddDefaulted(ViewDependentWholeSceneShadows.Num()); + } + + void AnyThreadTask() + { + if (Node) { - for( int32 ShadowIndex = 0, Num = PreShadows.Num(); ShadowIndex < PreShadows.Num(); ShadowIndex++ ) + // Check all the primitives in this octree node. + for (FScenePrimitiveOctree::ElementConstIt NodePrimitiveIt(Node->GetElementIt()); NodePrimitiveIt; ++NodePrimitiveIt) { - FProjectedShadowInfo* RESTRICT ProjectedShadowInfo = PreShadows[ShadowIndex]; - - // Check if this primitive is in the shadow's frustum. - bool bInFrustum = ProjectedShadowInfo->CasterFrustum.IntersectBox( PrimitiveBounds.Origin, ProjectedShadowInfo->PreShadowTranslation, PrimitiveBounds.BoxExtent ); - - if( bInFrustum && ProjectedShadowInfo->GetLightSceneInfoCompact().AffectsPrimitive(PrimitiveSceneInfoCompact) ) + if (NodePrimitiveIt->PrimitiveFlagsCompact.bCastDynamicShadow) { - // Add this primitive to the shadow. - ProjectedShadowInfo->AddSubjectPrimitive(PrimitiveSceneInfo, &Views, false); + FilterPrimitiveForShadows(NodePrimitiveIt->Bounds, NodePrimitiveIt->PrimitiveFlagsCompact, NodePrimitiveIt->PrimitiveSceneInfo, NodePrimitiveIt->Proxy); } } } - - if(PrimitiveSceneInfoCompact.bCastDynamicShadow || PrimitiveSceneInfoCompact.bAffectDynamicIndirectLighting ) + else { - for(int32 ShadowIndex = 0, Num = ViewDependentWholeSceneShadows.Num();ShadowIndex < Num;ShadowIndex++) + check(NumPrimitives > 0); + + // Check primitives in this packet's range + for (int32 PrimitiveIndex = StartPrimitiveIndex; PrimitiveIndex < StartPrimitiveIndex + NumPrimitives; PrimitiveIndex++) { - FProjectedShadowInfo* RESTRICT ProjectedShadowInfo = ViewDependentWholeSceneShadows[ShadowIndex]; + FPrimitiveFlagsCompact PrimitiveFlagsCompact = Scene->PrimitiveFlagsCompact[PrimitiveIndex]; - if ( ProjectedShadowInfo->bReflectiveShadowmap && !PrimitiveSceneInfoCompact.bAffectDynamicIndirectLighting ) + if (PrimitiveFlagsCompact.bCastDynamicShadow) { - continue; - } - if ( !ProjectedShadowInfo->bReflectiveShadowmap && !PrimitiveSceneInfoCompact.bCastDynamicShadow ) - { - continue; - } - - FLightSceneProxy* RESTRICT LightProxy = ProjectedShadowInfo->GetLightSceneInfo().Proxy; - - const FVector LightDirection = LightProxy->GetDirection(); - const FVector PrimitiveToShadowCenter = ProjectedShadowInfo->ShadowBounds.Center - PrimitiveBounds.Origin; - // Project the primitive's bounds origin onto the light vector - const float ProjectedDistanceFromShadowOriginAlongLightDir = PrimitiveToShadowCenter | LightDirection; - // Calculate the primitive's squared distance to the cylinder's axis - const float PrimitiveDistanceFromCylinderAxisSq = (-LightDirection * ProjectedDistanceFromShadowOriginAlongLightDir + PrimitiveToShadowCenter).SizeSquared(); - const float CombinedRadiusSq = FMath::Square(ProjectedShadowInfo->ShadowBounds.W + PrimitiveBounds.SphereRadius); - - // Include all primitives for movable lights, but only statically shadowed primitives from a light with static shadowing, - // Since lights with static shadowing still create per-object shadows for primitives without static shadowing. - if( (!LightProxy->HasStaticLighting() || (!ProjectedShadowInfo->GetLightSceneInfo().IsPrecomputedLightingValid() || LightProxy->UseCSMForDynamicObjects())) - // Check if this primitive is in the shadow's cylinder - && PrimitiveDistanceFromCylinderAxisSq < CombinedRadiusSq - // Check if the primitive is closer than the cylinder cap toward the light - // next line is commented as it breaks large world shadows, if this was meant to be an optimization we should think about a better solution - //// && ProjectedDistanceFromShadowOriginAlongLightDir - PrimitiveBounds.SphereRadius < -ProjectedShadowInfo->MinPreSubjectZ - // If the primitive is further along the cone axis than the shadow bounds origin, - // Check if the primitive is inside the spherical cap of the cascade's bounds - && !(ProjectedDistanceFromShadowOriginAlongLightDir < 0 - && PrimitiveToShadowCenter.SizeSquared() > CombinedRadiusSq)) - { - const bool bInFrustum = ProjectedShadowInfo->CascadeSettings.ShadowBoundsAccurate.IntersectBox( PrimitiveBounds.Origin, PrimitiveBounds.BoxExtent ); - - if( bInFrustum ) - { - // Distance culling for RSMs - float MinScreenRadiusForShadowCaster = GMinScreenRadiusForShadowCaster; - if (ProjectedShadowInfo->bReflectiveShadowmap) - { - MinScreenRadiusForShadowCaster = GMinScreenRadiusForShadowCasterRSM; - } - - bool bScreenSpaceSizeCulled = false; - check( ProjectedShadowInfo->DependentView ); - if ( ProjectedShadowInfo->DependentView ) - { - const float DistanceSquared = ( PrimitiveBounds.Origin - ProjectedShadowInfo->DependentView->ShadowViewMatrices.GetViewOrigin() ).SizeSquared(); - bScreenSpaceSizeCulled = FMath::Square( PrimitiveBounds.SphereRadius ) < FMath::Square( MinScreenRadiusForShadowCaster ) * DistanceSquared * ProjectedShadowInfo->DependentView->LODDistanceFactorSquared; - } - - if (ProjectedShadowInfo->GetLightSceneInfoCompact().AffectsPrimitive(PrimitiveSceneInfoCompact) - // Exclude primitives that will create their own per-object shadow, except when rendering RSMs - && ( !PrimitiveProxy->CastsInsetShadow() || ProjectedShadowInfo->bReflectiveShadowmap ) - // Exclude primitives that will create a per-object shadow from a stationary light - && !ShouldCreateObjectShadowForStationaryLight(&ProjectedShadowInfo->GetLightSceneInfo(), PrimitiveSceneInfo->Proxy, true) - // Only render shadows from objects that use static lighting during a reflection capture, since the reflection capture doesn't update at runtime - && (!bStaticSceneOnly || PrimitiveProxy->HasStaticLighting()) - // Render dynamic lit objects if CSMForDynamicObjects is enabled. - && (!LightProxy->UseCSMForDynamicObjects() || !PrimitiveProxy->HasStaticLighting()) - && !bScreenSpaceSizeCulled ) - { - bool bRecordShadowSubjectsForMobile = false; - - if (Scene->GetShadingPath() == EShadingPath::Mobile) - { - static auto* CVarMobileEnableStaticAndCSMShadowReceivers = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.Mobile.EnableStaticAndCSMShadowReceivers")); - bRecordShadowSubjectsForMobile = CVarEnableCsmShaderCulling.GetValueOnRenderThread() - && CVarMobileEnableStaticAndCSMShadowReceivers->GetValueOnRenderThread() - && LightProxy->UseCSMForDynamicObjects(); - } - - // Add this primitive to the shadow. - ProjectedShadowInfo->AddSubjectPrimitive(PrimitiveSceneInfo, NULL, bRecordShadowSubjectsForMobile); - } - } + FilterPrimitiveForShadows(Scene->PrimitiveBounds[PrimitiveIndex].BoxSphereBounds, PrimitiveFlagsCompact, Scene->Primitives[PrimitiveIndex], Scene->PrimitiveSceneProxies[PrimitiveIndex]); } } } } -} + + void FilterPrimitiveForShadows(const FBoxSphereBounds& PrimitiveBounds, FPrimitiveFlagsCompact PrimitiveFlagsCompact, FPrimitiveSceneInfo* PrimitiveSceneInfo, FPrimitiveSceneProxy* PrimitiveProxy) + { + // Check if the primitive is a subject for any of the preshadows. + // Only allow preshadows from lightmapped primitives that cast both dynamic and static shadows. + if (PreShadows.Num() && PrimitiveFlagsCompact.bCastStaticShadow && PrimitiveFlagsCompact.bStaticLighting) + { + for (int32 ShadowIndex = 0, Num = PreShadows.Num(); ShadowIndex < Num; ShadowIndex++) + { + FProjectedShadowInfo* RESTRICT ProjectedShadowInfo = PreShadows[ShadowIndex]; + + // Note: Culling based on the primitive's bounds BEFORE dereferencing PrimitiveSceneInfo / PrimitiveProxy + // Check if this primitive is in the shadow's frustum. + bool bInFrustum = ProjectedShadowInfo->CasterFrustum.IntersectBox(PrimitiveBounds.Origin, ProjectedShadowInfo->PreShadowTranslation, PrimitiveBounds.BoxExtent); + + if (bInFrustum && ProjectedShadowInfo->GetLightSceneInfoCompact().AffectsPrimitive(PrimitiveBounds, PrimitiveProxy)) + { + PreShadowSubjectPrimitives[ShadowIndex].Add(PrimitiveSceneInfo); + } + } + } + + for (int32 ShadowIndex = 0, Num = ViewDependentWholeSceneShadows.Num();ShadowIndex < Num;ShadowIndex++) + { + const FProjectedShadowInfo* RESTRICT ProjectedShadowInfo = ViewDependentWholeSceneShadows[ShadowIndex]; + const FLightSceneInfo& RESTRICT LightSceneInfo = ProjectedShadowInfo->GetLightSceneInfo(); + const FLightSceneProxy& RESTRICT LightProxy = *LightSceneInfo.Proxy; + + const FVector LightDirection = LightProxy.GetDirection(); + const FVector PrimitiveToShadowCenter = ProjectedShadowInfo->ShadowBounds.Center - PrimitiveBounds.Origin; + // Project the primitive's bounds origin onto the light vector + const float ProjectedDistanceFromShadowOriginAlongLightDir = PrimitiveToShadowCenter | LightDirection; + // Calculate the primitive's squared distance to the cylinder's axis + const float PrimitiveDistanceFromCylinderAxisSq = (-LightDirection * ProjectedDistanceFromShadowOriginAlongLightDir + PrimitiveToShadowCenter).SizeSquared(); + const float CombinedRadiusSq = FMath::Square(ProjectedShadowInfo->ShadowBounds.W + PrimitiveBounds.SphereRadius); + + // Note: Culling based on the primitive's bounds BEFORE dereferencing PrimitiveSceneInfo / PrimitiveProxy + + // Check if this primitive is in the shadow's cylinder + if (PrimitiveDistanceFromCylinderAxisSq < CombinedRadiusSq + // If the primitive is further along the cone axis than the shadow bounds origin, + // Check if the primitive is inside the spherical cap of the cascade's bounds + && !(ProjectedDistanceFromShadowOriginAlongLightDir < 0 && PrimitiveToShadowCenter.SizeSquared() > CombinedRadiusSq) + // Test against the convex hull containing the extruded shadow bounds + && ProjectedShadowInfo->CascadeSettings.ShadowBoundsAccurate.IntersectBox(PrimitiveBounds.Origin, PrimitiveBounds.BoxExtent)) + { + // Distance culling for RSMs + const float MinScreenRadiusForShadowCaster = ProjectedShadowInfo->bReflectiveShadowmap ? GMinScreenRadiusForShadowCasterRSM : GMinScreenRadiusForShadowCaster; + + bool bScreenSpaceSizeCulled = false; + check(ProjectedShadowInfo->DependentView); + + { + const float DistanceSquared = (PrimitiveBounds.Origin - ProjectedShadowInfo->DependentView->ShadowViewMatrices.GetViewOrigin()).SizeSquared(); + bScreenSpaceSizeCulled = FMath::Square(PrimitiveBounds.SphereRadius) < FMath::Square(MinScreenRadiusForShadowCaster) * DistanceSquared * ProjectedShadowInfo->DependentView->LODDistanceFactorSquared; + } + + if (!bScreenSpaceSizeCulled + && ProjectedShadowInfo->GetLightSceneInfoCompact().AffectsPrimitive(PrimitiveBounds, PrimitiveProxy) + // Include all primitives for movable lights, but only statically shadowed primitives from a light with static shadowing, + // Since lights with static shadowing still create per-object shadows for primitives without static shadowing. + && (!LightProxy.HasStaticLighting() || (!LightSceneInfo.IsPrecomputedLightingValid() || LightProxy.UseCSMForDynamicObjects())) + // Only render primitives into a reflective shadowmap that are supposed to affect indirect lighting + && !(ProjectedShadowInfo->bReflectiveShadowmap && !PrimitiveProxy->AffectsDynamicIndirectLighting()) + // Exclude primitives that will create their own per-object shadow, except when rendering RSMs + && (!PrimitiveProxy->CastsInsetShadow() || ProjectedShadowInfo->bReflectiveShadowmap) + // Exclude primitives that will create a per-object shadow from a stationary light + && !ShouldCreateObjectShadowForStationaryLight(&LightSceneInfo, PrimitiveProxy, true) + // Only render shadows from objects that use static lighting during a reflection capture, since the reflection capture doesn't update at runtime + && (!bStaticSceneOnly || PrimitiveProxy->HasStaticLighting()) + // Render dynamic lit objects if CSMForDynamicObjects is enabled. + && (!LightProxy.UseCSMForDynamicObjects() || !PrimitiveProxy->HasStaticLighting())) + { + ViewDependentWholeSceneShadowSubjectPrimitives[ShadowIndex].Add(PrimitiveSceneInfo); + } + } + } + } + + void RenderThreadFinalize() + { + for (int32 ShadowIndex = 0; ShadowIndex < PreShadowSubjectPrimitives.Num(); ShadowIndex++) + { + FProjectedShadowInfo* ProjectedShadowInfo = PreShadows[ShadowIndex]; + + for (int32 PrimitiveIndex = 0; PrimitiveIndex < PreShadowSubjectPrimitives[ShadowIndex].Num(); PrimitiveIndex++) + { + ProjectedShadowInfo->AddSubjectPrimitive(PreShadowSubjectPrimitives[ShadowIndex][PrimitiveIndex], &Views, FeatureLevel, false); + } + } + + for (int32 ShadowIndex = 0; ShadowIndex < ViewDependentWholeSceneShadowSubjectPrimitives.Num(); ShadowIndex++) + { + FProjectedShadowInfo* ProjectedShadowInfo = ViewDependentWholeSceneShadows[ShadowIndex]; + + bool bRecordShadowSubjectsForMobile = false; + + if (FSceneInterface::GetShadingPath(FeatureLevel) == EShadingPath::Mobile) + { + static auto* CVarMobileEnableStaticAndCSMShadowReceivers = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.Mobile.EnableStaticAndCSMShadowReceivers")); + bRecordShadowSubjectsForMobile = CVarEnableCsmShaderCulling.GetValueOnRenderThread() + && CVarMobileEnableStaticAndCSMShadowReceivers->GetValueOnRenderThread() + && ProjectedShadowInfo->GetLightSceneInfo().Proxy->UseCSMForDynamicObjects(); + } + + for (int32 PrimitiveIndex = 0; PrimitiveIndex < ViewDependentWholeSceneShadowSubjectPrimitives[ShadowIndex].Num(); PrimitiveIndex++) + { + ProjectedShadowInfo->AddSubjectPrimitive(ViewDependentWholeSceneShadowSubjectPrimitives[ShadowIndex][PrimitiveIndex], NULL, FeatureLevel, bRecordShadowSubjectsForMobile); + } + } + } +}; void FSceneRenderer::GatherShadowPrimitives( const TArray& PreShadows, @@ -2487,94 +2597,140 @@ void FSceneRenderer::GatherShadowPrimitives( { SCOPE_CYCLE_COUNTER(STAT_GatherShadowPrimitivesTime); - if(PreShadows.Num() || ViewDependentWholeSceneShadows.Num()) + if (PreShadows.Num() || ViewDependentWholeSceneShadows.Num()) { - for(int32 ShadowIndex = 0, Num = ViewDependentWholeSceneShadows.Num(); ShadowIndex < Num;ShadowIndex++) + for (int32 ShadowIndex = 0, Num = ViewDependentWholeSceneShadows.Num(); ShadowIndex < Num;ShadowIndex++) { FProjectedShadowInfo* ProjectedShadowInfo = ViewDependentWholeSceneShadows[ShadowIndex]; checkSlow(ProjectedShadowInfo->DependentView); // Initialize the whole scene shadow's depth map with the shadow independent depth map from the view ProjectedShadowInfo->StaticMeshWholeSceneShadowDepthMap.Init(false,Scene->StaticMeshes.GetMaxIndex()); - ProjectedShadowInfo->StaticMeshWholeSceneShadowBatchVisibility.AddZeroed(Scene->StaticMeshes.GetMaxIndex()); + ProjectedShadowInfo->StaticMeshWholeSceneShadowBatchVisibility.AddZeroed(Scene->StaticMeshBatchVisibility.GetMaxIndex()); } - QUICK_SCOPE_CYCLE_COUNTER(STAT_ShadowOctreeTraversal); - // Find primitives that are in a shadow frustum in the octree. - for(FScenePrimitiveOctree::TConstIterator PrimitiveOctreeIt(Scene->PrimitiveOctree); - PrimitiveOctreeIt.HasPendingNodes(); - PrimitiveOctreeIt.Advance()) + TArray Packets; + + if (GUseOctreeForShadowCulling) { - const FScenePrimitiveOctree::FNode& PrimitiveOctreeNode = PrimitiveOctreeIt.GetCurrentNode(); - const FOctreeNodeContext& PrimitiveOctreeNodeContext = PrimitiveOctreeIt.GetCurrentContext(); + QUICK_SCOPE_CYCLE_COUNTER(STAT_ShadowSceneOctreeTraversal); + Packets.Reserve(100); + + // Find primitives that are in a shadow frustum in the octree. + for(FScenePrimitiveOctree::TConstIterator PrimitiveOctreeIt(Scene->PrimitiveOctree); + PrimitiveOctreeIt.HasPendingNodes(); + PrimitiveOctreeIt.Advance()) { - // Find children of this octree node that may contain relevant primitives. - FOREACH_OCTREE_CHILD_NODE(ChildRef) + const FScenePrimitiveOctree::FNode& PrimitiveOctreeNode = PrimitiveOctreeIt.GetCurrentNode(); + const FOctreeNodeContext& PrimitiveOctreeNodeContext = PrimitiveOctreeIt.GetCurrentContext(); + { - if(PrimitiveOctreeNode.HasChild(ChildRef)) + // Find children of this octree node that may contain relevant primitives. + FOREACH_OCTREE_CHILD_NODE(ChildRef) { - // Check that the child node is in the frustum for at least one shadow. - const FOctreeNodeContext ChildContext = PrimitiveOctreeNodeContext.GetChildContext(ChildRef); - bool bIsInFrustum = false; - - // Check for subjects of preshadows. - if(!bIsInFrustum) + if(PrimitiveOctreeNode.HasChild(ChildRef)) { - for(int32 ShadowIndex = 0, Num = PreShadows.Num(); ShadowIndex < Num; ShadowIndex++) - { - FProjectedShadowInfo* ProjectedShadowInfo = PreShadows[ShadowIndex]; + // Check that the child node is in the frustum for at least one shadow. + const FOctreeNodeContext ChildContext = PrimitiveOctreeNodeContext.GetChildContext(ChildRef); + bool bIsInFrustum = false; - check(ProjectedShadowInfo->CasterFrustum.PermutedPlanes.Num()); - // Check if this primitive is in the shadow's frustum. - if(ProjectedShadowInfo->CasterFrustum.IntersectBox( - ChildContext.Bounds.Center + ProjectedShadowInfo->PreShadowTranslation, - ChildContext.Bounds.Extent - )) + // Check for subjects of preshadows. + if(!bIsInFrustum) + { + for(int32 ShadowIndex = 0, Num = PreShadows.Num(); ShadowIndex < Num; ShadowIndex++) { - bIsInFrustum = true; - break; + FProjectedShadowInfo* ProjectedShadowInfo = PreShadows[ShadowIndex]; + + check(ProjectedShadowInfo->CasterFrustum.PermutedPlanes.Num()); + // Check if this primitive is in the shadow's frustum. + if(ProjectedShadowInfo->CasterFrustum.IntersectBox( + ChildContext.Bounds.Center + ProjectedShadowInfo->PreShadowTranslation, + ChildContext.Bounds.Extent + )) + { + bIsInFrustum = true; + break; + } } } - } - if (!bIsInFrustum) - { - for(int32 ShadowIndex = 0, Num = ViewDependentWholeSceneShadows.Num(); ShadowIndex < Num; ShadowIndex++) + if (!bIsInFrustum) { - FProjectedShadowInfo* ProjectedShadowInfo = ViewDependentWholeSceneShadows[ShadowIndex]; - - //check(ProjectedShadowInfo->CasterFrustum.PermutedPlanes.Num()); - // Check if this primitive is in the shadow's frustum. - if(ProjectedShadowInfo->CasterFrustum.IntersectBox( - ChildContext.Bounds.Center + ProjectedShadowInfo->PreShadowTranslation, - ChildContext.Bounds.Extent - )) + for(int32 ShadowIndex = 0, Num = ViewDependentWholeSceneShadows.Num(); ShadowIndex < Num; ShadowIndex++) { - bIsInFrustum = true; - break; + FProjectedShadowInfo* ProjectedShadowInfo = ViewDependentWholeSceneShadows[ShadowIndex]; + + //check(ProjectedShadowInfo->CasterFrustum.PermutedPlanes.Num()); + // Check if this primitive is in the shadow's frustum. + if(ProjectedShadowInfo->CasterFrustum.IntersectBox( + ChildContext.Bounds.Center + ProjectedShadowInfo->PreShadowTranslation, + ChildContext.Bounds.Extent + )) + { + bIsInFrustum = true; + break; + } } } - } - if(bIsInFrustum) - { - // If the child node was in the frustum of at least one preshadow, push it on - // the iterator's pending node stack. - PrimitiveOctreeIt.PushChild(ChildRef); + if(bIsInFrustum) + { + // If the child node was in the frustum of at least one preshadow, push it on + // the iterator's pending node stack. + PrimitiveOctreeIt.PushChild(ChildRef); + } } } } - } - // Check all the primitives in this octree node. - for(FScenePrimitiveOctree::ElementConstIt NodePrimitiveIt(PrimitiveOctreeNode.GetElementIt());NodePrimitiveIt;++NodePrimitiveIt) + if (PrimitiveOctreeNode.GetElementCount() > 0) + { + FGatherShadowPrimitivesPacket* Packet = new(FMemStack::Get()) FGatherShadowPrimitivesPacket(Scene, Views, &PrimitiveOctreeNode, 0, 0, PreShadows, ViewDependentWholeSceneShadows, FeatureLevel, bStaticSceneOnly); + Packets.Add(Packet); + } + } + } + else + { + const int32 PacketSize = CVarParallelGatherNumPrimitivesPerPacket.GetValueOnRenderThread(); + const int32 NumPackets = FMath::DivideAndRoundUp(Scene->Primitives.Num(), PacketSize); + + Packets.Reserve(NumPackets); + + for (int32 PacketIndex = 0; PacketIndex < NumPackets; PacketIndex++) { - // gather the shadows for this one primitive - GatherShadowsForPrimitiveInner(*NodePrimitiveIt, PreShadows, ViewDependentWholeSceneShadows, bStaticSceneOnly); + const int32 StartPrimitiveIndex = PacketIndex * PacketSize; + const int32 NumPrimitives = FMath::Min(PacketSize, Scene->Primitives.Num() - StartPrimitiveIndex); + FGatherShadowPrimitivesPacket* Packet = new(FMemStack::Get()) FGatherShadowPrimitivesPacket(Scene, Views, NULL, StartPrimitiveIndex, NumPrimitives, PreShadows, ViewDependentWholeSceneShadows, FeatureLevel, bStaticSceneOnly); + Packets.Add(Packet); + } + } + + { + QUICK_SCOPE_CYCLE_COUNTER(STAT_FilterPrimitivesForShadows); + + ParallelFor(Packets.Num(), + [&Packets](int32 Index) + { + Packets[Index]->AnyThreadTask(); + }, + !(FApp::ShouldUseThreadingForPerformance() && CVarParallelGatherShadowPrimitives.GetValueOnRenderThread() > 0) + ); + } + + { + QUICK_SCOPE_CYCLE_COUNTER(STAT_RenderThreadFinalize); + + for (int32 PacketIndex = 0; PacketIndex < Packets.Num(); PacketIndex++) + { + FGatherShadowPrimitivesPacket* Packet = Packets[PacketIndex]; + Packet->RenderThreadFinalize(); + // Class was allocated on the memstack which does not call destructors + Packet->~FGatherShadowPrimitivesPacket(); } } - for(int32 ShadowIndex = 0, Num = PreShadows.Num(); ShadowIndex < Num; ShadowIndex++) + for (int32 ShadowIndex = 0, Num = PreShadows.Num(); ShadowIndex < Num; ShadowIndex++) { FProjectedShadowInfo* ProjectedShadowInfo = PreShadows[ShadowIndex]; //@todo - sort other shadow types' subject mesh elements? diff --git a/Engine/Source/Runtime/Renderer/Private/ShadowSetupMobile.cpp b/Engine/Source/Runtime/Renderer/Private/ShadowSetupMobile.cpp index 7fb6fc48c351..6010f412f1f9 100644 --- a/Engine/Source/Runtime/Renderer/Private/ShadowSetupMobile.cpp +++ b/Engine/Source/Runtime/Renderer/Private/ShadowSetupMobile.cpp @@ -120,7 +120,7 @@ static bool MobileDetermineStaticMeshesCSMVisibilityStateInner( { FProjectedShadowInfo* RESTRICT ProjectedShadowInfo = WholeSceneShadow; - if (ProjectedShadowInfo->bReflectiveShadowmap && !PrimitiveSceneInfoCompact.bAffectDynamicIndirectLighting) + if (ProjectedShadowInfo->bReflectiveShadowmap && !PrimitiveProxy->AffectsDynamicIndirectLighting()) { return bFoundCSMReceiver; } diff --git a/Engine/Source/Runtime/Renderer/Private/SpriteIndexBuffer.h b/Engine/Source/Runtime/Renderer/Private/SpriteIndexBuffer.h new file mode 100644 index 000000000000..05ad1a2b505a --- /dev/null +++ b/Engine/Source/Runtime/Renderer/Private/SpriteIndexBuffer.h @@ -0,0 +1,28 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#pragma once + +template< uint32 NumSprites > +class FSpriteIndexBuffer : public FIndexBuffer +{ +public: + virtual void InitRHI() override + { + const uint32 Size = sizeof(uint16) * 6 * NumSprites; + const uint32 Stride = sizeof(uint16); + FRHIResourceCreateInfo CreateInfo; + void* Buffer = nullptr; + IndexBufferRHI = RHICreateAndLockIndexBuffer( Stride, Size, BUF_Static, CreateInfo, Buffer ); + uint16* Indices = (uint16*)Buffer; + for (uint32 SpriteIndex = 0; SpriteIndex < NumSprites; ++SpriteIndex) + { + Indices[SpriteIndex*6 + 0] = SpriteIndex*4 + 0; + Indices[SpriteIndex*6 + 1] = SpriteIndex*4 + 3; + Indices[SpriteIndex*6 + 2] = SpriteIndex*4 + 2; + Indices[SpriteIndex*6 + 3] = SpriteIndex*4 + 0; + Indices[SpriteIndex*6 + 4] = SpriteIndex*4 + 1; + Indices[SpriteIndex*6 + 5] = SpriteIndex*4 + 3; + } + RHIUnlockIndexBuffer( IndexBufferRHI ); + } +}; \ No newline at end of file diff --git a/Engine/Source/Runtime/Renderer/Private/StaticMeshDrawList.inl b/Engine/Source/Runtime/Renderer/Private/StaticMeshDrawList.inl index 79830d7c6a39..ed352eefb894 100644 --- a/Engine/Source/Runtime/Renderer/Private/StaticMeshDrawList.inl +++ b/Engine/Source/Runtime/Renderer/Private/StaticMeshDrawList.inl @@ -59,16 +59,17 @@ void TStaticMeshDrawList::FElementHandle::Remove(const bool b checkSlow(LocalDrawingPolicyLink->SetId == SetId); - check(LocalDrawingPolicyLink->Elements[ElementIndex].Mesh->MaterialRenderProxy); - LocalDrawingPolicyLink->Elements[ElementIndex].Mesh->MaterialRenderProxy->SetUnreferencedInDrawList(); + check(LocalDrawingPolicyLink->Elements[LocalElementIndex].Mesh->MaterialRenderProxy); + LocalDrawingPolicyLink->Elements[LocalElementIndex].Mesh->MaterialRenderProxy->SetUnreferencedInDrawList(); // Unlink the mesh from this draw list. Not necessary if the mesh is being destroyed if (bUnlinkMesh) { // Expensive (Order N). Spins through whole list - LocalDrawingPolicyLink->Elements[ElementIndex].Mesh->UnlinkDrawList(this); + LocalDrawingPolicyLink->Elements[LocalElementIndex].Mesh->UnlinkDrawList(this); } - LocalDrawingPolicyLink->Elements[ElementIndex].Mesh = NULL; + //from this point on the memory the this pointer point to might be gone (e.g. if we unlink ourselves) + LocalDrawingPolicyLink->Elements[LocalElementIndex].Mesh = NULL; checkSlow(LocalDrawingPolicyLink->Elements.Num() == LocalDrawingPolicyLink->CompactElements.Num()); @@ -355,7 +356,7 @@ bool TStaticMeshDrawList::DrawVisibleInner( STAT(StatInc += Element.Mesh->GetNumPrimitives();) int32 SubCount = Element.Mesh->Elements.Num(); // Avoid the cache miss looking up batch visibility if there is only one element. - uint64 BatchElementMask = Element.Mesh->bRequiresPerElementVisibility ? (*BatchVisibilityArray)[Element.Mesh->Id] : ((1ull << SubCount) - 1); + uint64 BatchElementMask = Element.Mesh->bRequiresPerElementVisibility ? (*BatchVisibilityArray)[Element.Mesh->BatchVisibilityId] : ((1ull << SubCount) - 1); Count += DrawElement(RHICmdList, View, PolicyContext, DrawRenderState, Element, BatchElementMask, DrawingPolicyLink, bDrawnShared); } } @@ -363,24 +364,24 @@ bool TStaticMeshDrawList::DrawVisibleInner( // Stereo pair, we need to test both eyes else { - const TArray* ResolvedVisiblityArray = nullptr; + const TArray* ResolvedBatchVisiblityArray = nullptr; if (StereoView->LeftViewVisibilityMap->AccessCorrespondingBit(FRelativeBitReference(CompactElementPtr->MeshId))) { - ResolvedVisiblityArray = StereoView->LeftViewBatchVisibilityArray; + ResolvedBatchVisiblityArray = StereoView->LeftViewBatchVisibilityArray; } else if (StereoView->RightViewVisibilityMap->AccessCorrespondingBit(FRelativeBitReference(CompactElementPtr->MeshId))) { - ResolvedVisiblityArray = StereoView->RightViewBatchVisibilityArray; + ResolvedBatchVisiblityArray = StereoView->RightViewBatchVisibilityArray; } - if (ResolvedVisiblityArray != nullptr) + if (ResolvedBatchVisiblityArray != nullptr) { const FElement& Element = DrawingPolicyLink->Elements[ElementIndex]; STAT(StatInc += Element.Mesh->GetNumPrimitives();) int32 SubCount = Element.Mesh->Elements.Num(); // Avoid the cache miss looking up batch visibility if there is only one element. - uint64 BatchElementMask = Element.Mesh->bRequiresPerElementVisibility ? (*ResolvedVisiblityArray)[Element.Mesh->Id] : ((1ull << SubCount) - 1); + uint64 BatchElementMask = Element.Mesh->bRequiresPerElementVisibility ? (*ResolvedBatchVisiblityArray)[Element.Mesh->BatchVisibilityId] : ((1ull << SubCount) - 1); Count += DrawElement(RHICmdList, View, PolicyContext, DrawRenderState, Element, BatchElementMask, DrawingPolicyLink, bDrawnShared); } } @@ -603,19 +604,19 @@ void TStaticMeshDrawList::DrawVisibleParallelInternal( const FElement& Element = DrawingPolicyLink->Elements[ElementIndex]; const int32 SubCount = Element.Mesh->Elements.Num(); - // Avoid the cache miss looking up batch visibility if there is only one element. - if (SubCount == 1) + // Avoid the cache miss looking up batch visibility if it's not needed + if (!Element.Mesh->bRequiresPerElementVisibility) { - ++Count; + Count += SubCount; } else if (!bIsInstancedStereo) { - Count += CountBits((*BatchVisibilityArray)[Element.Mesh->Id]); + Count += CountBits((*BatchVisibilityArray)[Element.Mesh->BatchVisibilityId]); } else { - const int32 LeftCount = CountBits((*StereoView->LeftViewBatchVisibilityArray)[Element.Mesh->Id]); - const int32 RightCount = CountBits((*StereoView->RightViewBatchVisibilityArray)[Element.Mesh->Id]); + const int32 LeftCount = CountBits((*StereoView->LeftViewBatchVisibilityArray)[Element.Mesh->BatchVisibilityId]); + const int32 RightCount = CountBits((*StereoView->RightViewBatchVisibilityArray)[Element.Mesh->BatchVisibilityId]); Count += (LeftCount > RightCount) ? LeftCount : RightCount; } } @@ -878,7 +879,7 @@ int32 TStaticMeshDrawList::DrawVisibleFrontToBackInner( const TArray* const ResolvedVisiblityArray = (InstancedStereo == InstancedStereoPolicy::Disabled) ? BatchVisibilityArray : ElementVisibility[SortedIndex]; // Avoid the cache miss looking up batch visibility if there is only one element. - uint64 BatchElementMask = Element.Mesh->bRequiresPerElementVisibility ? (*ResolvedVisiblityArray)[Element.Mesh->Id] : ((1ull << Element.Mesh->Elements.Num()) - 1); + uint64 BatchElementMask = Element.Mesh->bRequiresPerElementVisibility ? (*ResolvedVisiblityArray)[Element.Mesh->BatchVisibilityId] : ((1ull << Element.Mesh->Elements.Num()) - 1); DrawElement(RHICmdList, View, PolicyContext, DrawRenderState, Element, BatchElementMask, DrawingPolicyLink, bDrawnShared); NumDraws++; } diff --git a/Engine/Source/Runtime/Renderer/Private/SystemTextures.cpp b/Engine/Source/Runtime/Renderer/Private/SystemTextures.cpp index ee3933c22b0a..182329b4295c 100644 --- a/Engine/Source/Runtime/Renderer/Private/SystemTextures.cpp +++ b/Engine/Source/Runtime/Renderer/Private/SystemTextures.cpp @@ -62,14 +62,14 @@ void FSystemTextures::InternalInitializeTextures(FRHICommandListImmediate& RHICm RHICmdList.CopyToResolveTarget(GreenDummy->GetRenderTargetItem().TargetableTexture, GreenDummy->GetRenderTargetItem().ShaderResourceTexture, true, FResolveParams()); } - // Create a MidGrayDummy texture + // Create a DefaultNormal8Bit texture { - FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(FIntPoint(1, 1), PF_B8G8R8A8, FClearValueBinding::MidGray, TexCreate_HideInVisualizeTexture, TexCreate_RenderTargetable | TexCreate_NoFastClear, false)); + FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(FIntPoint(1, 1), PF_B8G8R8A8, FClearValueBinding::DefaultNormal8Bit, TexCreate_HideInVisualizeTexture, TexCreate_RenderTargetable | TexCreate_NoFastClear, false)); Desc.AutoWritable = false; - GRenderTargetPool.FindFreeElement(RHICmdList, Desc, MidGrayDummy, TEXT("MidGrayDummy")); + GRenderTargetPool.FindFreeElement(RHICmdList, Desc, DefaultNormal8Bit, TEXT("DefaultNormal8Bit")); - SetRenderTarget(RHICmdList, MidGrayDummy->GetRenderTargetItem().TargetableTexture, FTextureRHIRef(), ESimpleRenderTargetMode::EClearColorExistingDepth); - RHICmdList.CopyToResolveTarget(MidGrayDummy->GetRenderTargetItem().TargetableTexture, MidGrayDummy->GetRenderTargetItem().ShaderResourceTexture, true, FResolveParams()); + SetRenderTarget(RHICmdList, DefaultNormal8Bit->GetRenderTargetItem().TargetableTexture, FTextureRHIRef(), ESimpleRenderTargetMode::EClearColorExistingDepth); + RHICmdList.CopyToResolveTarget(DefaultNormal8Bit->GetRenderTargetItem().TargetableTexture, DefaultNormal8Bit->GetRenderTargetItem().ShaderResourceTexture, true, FResolveParams()); } // Create the PerlinNoiseGradient texture @@ -104,6 +104,63 @@ void FSystemTextures::InternalInitializeTextures(FRHICommandListImmediate& RHICm RHICmdList.UnlockTexture2D((FTexture2DRHIRef&)PerlinNoiseGradient->GetRenderTargetItem().ShaderResourceTexture, 0, false); } + // Create the SobolSampling texture + { + const size_t SobolBits = 8; + static const uint16 SobolXCell[SobolBits][4] = { + { 0x5880, 0x7780, 0x9400, 0xc400 }, + { 0x5400, 0xa400, 0x4a00, 0xc200 }, + { 0x3a80, 0x2980, 0xfb00, 0x5700 }, + { 0xe800, 0x8800, 0x0400, 0x5400 }, + { 0xea00, 0x3600, 0xa200, 0x8a00 }, + { 0x4c00, 0x1c00, 0x2600, 0x5e00 }, + { 0xa480, 0x9b80, 0xe600, 0x9e00 }, + { 0x6880, 0x0780, 0xae00, 0x7600 } + }; + static const uint16 SobolYCell[SobolBits][4] = { + { 0x8e80, 0xed80, 0xf600, 0x8e00 }, + { 0x6e00, 0x8200, 0x8e00, 0x5600 }, + { 0xf600, 0xba00, 0x1100, 0x3500 }, + { 0x6a80, 0xb980, 0x2200, 0x0a00 }, + { 0x2600, 0xaa00, 0x4400, 0x1400 }, + { 0xe880, 0x8780, 0x8800, 0x2800 }, + { 0xa480, 0x9b80, 0xe600, 0x9e00 }, + { 0x6880, 0x0780, 0xae00, 0x7600 } + }; + + FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(FIntPoint(1 << SobolBits, 1 << SobolBits), PF_R16G16B16A16_UINT, FClearValueBinding::None, TexCreate_HideInVisualizeTexture, TexCreate_NoFastClear, false)); + Desc.AutoWritable = false; + GRenderTargetPool.FindFreeElement(RHICmdList, Desc, SobolSampling, TEXT("SobolSampling")); + // Write the contents of the texture. + uint32 DestStride; + uint8* DestBuffer = (uint8*)RHICmdList.LockTexture2D((FTexture2DRHIRef&)SobolSampling->GetRenderTargetItem().ShaderResourceTexture, 0, RLM_WriteOnly, DestStride, false); + + for (int y = 0; y < Desc.Extent.Y; ++y) + { + for (int x = 0; x < Desc.Extent.X; ++x) + { + uint16 *Dest = (uint16*)(DestBuffer + x * 4 * sizeof(uint16) + y * DestStride); + Dest[0] = Dest[1] = Dest[2] = Dest[3] = 0; + + for (int bit = 0; bit < SobolBits; ++bit) + { + Dest[0] ^= (x & (1 << bit)) ? SobolXCell[bit][0] : 0; + Dest[0] ^= (y & (1 << bit)) ? SobolYCell[bit][0] : 0; + + Dest[1] ^= (x & (1 << bit)) ? SobolXCell[bit][1] : 0; + Dest[1] ^= (y & (1 << bit)) ? SobolYCell[bit][1] : 0; + + Dest[2] ^= (x & (1 << bit)) ? SobolXCell[bit][2] : 0; + Dest[2] ^= (y & (1 << bit)) ? SobolYCell[bit][2] : 0; + + Dest[3] ^= (x & (1 << bit)) ? SobolXCell[bit][3] : 0; + Dest[3] ^= (y & (1 << bit)) ? SobolYCell[bit][3] : 0; + } + } + } + RHICmdList.UnlockTexture2D((FTexture2DRHIRef&)SobolSampling->GetRenderTargetItem().ShaderResourceTexture, 0, false); + } + if (!GSupportsShaderFramebufferFetch && GPixelFormats[PF_FloatRGBA].Supported) { FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(FIntPoint(1, 1), PF_FloatRGBA, FClearValueBinding(FLinearColor(65000.0f, 65000.0f, 65000.0f, 65000.0f)), TexCreate_HideInVisualizeTexture, TexCreate_RenderTargetable | TexCreate_NoFastClear, false)); @@ -302,7 +359,7 @@ void FSystemTextures::InternalInitializeTextures(FRHICommandListImmediate& RHICm Format = PF_G16R16; } - FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(FIntPoint(128, 32), Format, FClearValueBinding::None, TexCreate_FastVRAM, TexCreate_None, false)); + FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(FIntPoint(128, 32), Format, FClearValueBinding::None, 0, TexCreate_None, false)); Desc.AutoWritable = false; if (bReference) { @@ -432,12 +489,13 @@ void FSystemTextures::ReleaseDynamicRHI() BlackAlphaOneDummy.SafeRelease(); PerlinNoiseGradient.SafeRelease(); PerlinNoise3D.SafeRelease(); + SobolSampling.SafeRelease(); SSAORandomization.SafeRelease(); PreintegratedGF.SafeRelease(); MaxFP16Depth.SafeRelease(); DepthDummy.SafeRelease(); GreenDummy.SafeRelease(); - MidGrayDummy.SafeRelease(); + DefaultNormal8Bit.SafeRelease(); GRenderTargetPool.FreeUnusedResources(); diff --git a/Engine/Source/Runtime/Renderer/Private/SystemTextures.h b/Engine/Source/Runtime/Renderer/Private/SystemTextures.h index 8931704814f7..46355176cd44 100644 --- a/Engine/Source/Runtime/Renderer/Private/SystemTextures.h +++ b/Engine/Source/Runtime/Renderer/Private/SystemTextures.h @@ -54,6 +54,8 @@ public: TRefCountPtr PerlinNoiseGradient; // used by the material expression Noise (faster version, should replace old version), todo: move out of SceneRenderTargets TRefCountPtr PerlinNoise3D; + // Sobol sampling texture, the first sample points for four sobol dimensions in RGBA + TRefCountPtr SobolSampling; /** SSAO randomization */ TRefCountPtr SSAORandomization; /** Preintegrated GF for single sample IBL */ @@ -65,7 +67,7 @@ public: // float4(0,1,0,1) TRefCountPtr GreenDummy; // float4(0.5,0.5,0.5,1) - TRefCountPtr MidGrayDummy; + TRefCountPtr DefaultNormal8Bit; protected: /** Maximum feature level that the textures have been initialized up to */ diff --git a/Engine/Source/Runtime/Renderer/Private/TiledDeferredLightRendering.cpp b/Engine/Source/Runtime/Renderer/Private/TiledDeferredLightRendering.cpp index e2f854e14c88..7e8977e8c666 100644 --- a/Engine/Source/Runtime/Renderer/Private/TiledDeferredLightRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/TiledDeferredLightRendering.cpp @@ -131,7 +131,7 @@ public: FComputeShaderRHIParamRef ShaderRHI = GetComputeShader(); FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View.ViewUniformBuffer); - DeferredParameters.Set(RHICmdList, ShaderRHI, View); + DeferredParameters.Set(RHICmdList, ShaderRHI, View, MD_PostProcess); SetTextureParameter(RHICmdList, ShaderRHI, InTexture, InTextureValue.GetRenderTargetItem().ShaderResourceTexture); FUnorderedAccessViewRHIParamRef OutUAV = OutTextureValue.GetRenderTargetItem().UAV; @@ -160,8 +160,7 @@ public: if (StartIndex + LightIndex < NumLightsToRenderInSortedLights) { const FSortedLightSceneInfo& SortedLightInfo = SortedLights[StartIndex + LightIndex]; - const FLightSceneInfoCompact& LightSceneInfoCompact = SortedLightInfo.SceneInfo; - const FLightSceneInfo* const LightSceneInfo = LightSceneInfoCompact.LightSceneInfo; + const FLightSceneInfo* const LightSceneInfo = SortedLightInfo.LightSceneInfo; FVector NormalizedLightDirection; FVector2D SpotAngles; diff --git a/Engine/Source/Runtime/Renderer/Private/TranslucentLighting.cpp b/Engine/Source/Runtime/Renderer/Private/TranslucentLighting.cpp index e9442aaa1901..2385571ef50f 100644 --- a/Engine/Source/Runtime/Renderer/Private/TranslucentLighting.cpp +++ b/Engine/Source/Runtime/Renderer/Private/TranslucentLighting.cpp @@ -549,7 +549,7 @@ void FProjectedShadowInfo::RenderTranslucencyDepths(FRHICommandList& RHICmdList, ); FLinearColor ClearColors[2] = {FLinearColor(0,0,0,0), FLinearColor(0,0,0,0)}; - DrawClearQuadMRT(RHICmdList, SceneRenderer->FeatureLevel, true, ARRAY_COUNT(ClearColors), ClearColors, false, 1.0f, false, 0); + DrawClearQuadMRT(RHICmdList, true, ARRAY_COUNT(ClearColors), ClearColors, false, 1.0f, false, 0); // Set the viewport for the shadow. RHICmdList.SetViewport( @@ -903,7 +903,7 @@ void ClearVolumeTextures(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type Fea if (false) #endif { - DrawClearQuadMRT(RHICmdList, GMaxRHIFeatureLevel, true, NumRenderTargets, ClearColors, false, 0, false, 0); + DrawClearQuadMRT(RHICmdList, true, NumRenderTargets, ClearColors, false, 0, false, 0); } else { @@ -1606,8 +1606,7 @@ void FDeferredShadingSceneRenderer::InjectTranslucentVolumeLightingArray(FRHICom for (int32 LightIndex = 0; LightIndex < NumLights; LightIndex++) { const FSortedLightSceneInfo& SortedLightInfo = SortedLights[LightIndex]; - const FLightSceneInfoCompact& LightSceneInfoCompact = SortedLightInfo.SceneInfo; - const FLightSceneInfo* const LightSceneInfo = LightSceneInfoCompact.LightSceneInfo; + const FLightSceneInfo* const LightSceneInfo = SortedLightInfo.LightSceneInfo; AddLightForInjection(*this, *LightSceneInfo, NULL, LightInjectionData); } diff --git a/Engine/Source/Runtime/Renderer/Private/TranslucentRendering.cpp b/Engine/Source/Runtime/Renderer/Private/TranslucentRendering.cpp index e4a374328aef..a3b71d7b8417 100644 --- a/Engine/Source/Runtime/Renderer/Private/TranslucentRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/TranslucentRendering.cpp @@ -49,11 +49,100 @@ static TAutoConsoleVariable CVarSeparateTranslucencyMinDownsampleChangeTi TEXT("Minimum time in seconds between changes to automatic downsampling state, used to prevent rapid swapping between half and full res."), ECVF_Scalability | ECVF_Default); -static TAutoConsoleVariable CVarCopySceneColorOncePerViewOnly( - TEXT("r.CopySceneColorOncePerViewOnly"), - 0, - TEXT("Copy the scene color for translucent materials that sample from it only once per-view rather than prior to each draw call. Currently adds a fixed overhead of one copy per-view even when it isn't used."), - ECVF_RenderThreadSafe); +static TAutoConsoleVariable CVarSeparateTranslucencyUpsampleMode( + TEXT("r.SeparateTranslucencyUpsampleMode"), + 1, + TEXT("Upsample method to use on separate translucency. These are only used when r.SeparateTranslucencyScreenPercentage is less than 100.\n") + TEXT("0: bilinear 1: Nearest-Depth Neighbor (only when r.SeparateTranslucencyScreenPercentage is 50)"), + ECVF_Scalability | ECVF_Default); + +int32 GAllowDownsampledStandardTranslucency = 0; + +static FAutoConsoleVariableRef CVarAllowDownsampledStandardTranslucency( + TEXT("r.AllowDownsampledStandardTranslucency"), + GAllowDownsampledStandardTranslucency, + TEXT("Allow standard translucency to be rendered in smaller resolution as an optimization\n") + TEXT("This is incompatible with materials using blend modulate. Use 2 to ignore those. \n") + TEXT(" <0: off\n") + TEXT(" 0: on unless a material using blend modulate is used (default)") + TEXT(" >0: on and ignores any material using blend modulate"), + ECVF_RenderThreadSafe + ); + +/** Mostly used to know if debug rendering should be drawn in this pass */ +FORCEINLINE bool IsMainTranslucencyPass(ETranslucencyPass::Type TranslucencyPass) +{ + return TranslucencyPass == ETranslucencyPass::TPT_AllTranslucency || TranslucencyPass == ETranslucencyPass::TPT_StandardTranslucency; +} + +static bool RenderInSeparateTranslucency(const FSceneRenderTargets& SceneContext, ETranslucencyPass::Type TranslucencyPass, bool bPrimitiveDisablesOffscreenBuffer) +{ + // Currently AfterDOF is rendered earlier in the frame and must be rendered in a separate (offscreen) buffer. + if (TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterDOF) + { + // If bPrimitiveDisablesOffscreenBuffer, that will trigger an ensure call + return true; + } + + // Otherwise it only gets rendered in the separate buffer if it is downsampled + if (bPrimitiveDisablesOffscreenBuffer ? (GAllowDownsampledStandardTranslucency > 0) : (GAllowDownsampledStandardTranslucency >= 0)) + { + FIntPoint ScaledSize; + float DownsamplingScale = 1.f; + SceneContext.GetSeparateTranslucencyDimensions(ScaledSize, DownsamplingScale); + + if (DownsamplingScale < 1.f) + { + return true; + } + } + + return false; +} + +bool FTranslucencyDrawingPolicyFactory::ContextType::ShouldDraw(const FViewInfo& View, const FMaterial* Material, bool bIsSeparateTranslucency) const +{ + bool bShouldDraw = false; + + if (Material) + { + // Only render translucent materials + const EBlendMode BlendMode = Material->GetBlendMode(); + if (IsTranslucentBlendMode(BlendMode) && ShouldIncludeDomainInMeshPass(Material->GetMaterialDomain())) + { + if (TranslucencyPass == ETranslucencyPass::TPT_AllTranslucency) + { + bShouldDraw = true; + } + // Only draw meshes in the relevant pass + const ETranslucencyPass::Type MaterialPass = Material->IsTranslucencyAfterDOFEnabled() ? ETranslucencyPass::TPT_TranslucencyAfterDOF : ETranslucencyPass::TPT_StandardTranslucency; + if (TranslucencyPass == MaterialPass || (!View.Family->EngineShowFlags.PostProcessing && MaterialPass == ETranslucencyPass::TPT_TranslucencyAfterDOF && TranslucencyPass == ETranslucencyPass::TPT_StandardTranslucency)) + { + bShouldDraw = true; + } + } + + if (bShouldDraw && BlendMode == BLEND_Modulate && bIsSeparateTranslucency) + { + // < 0 : never downsample, = 0 downsample only if no blend modulate, > 0 ignore + ensure(GAllowDownsampledStandardTranslucency > 0); + #if !UE_BUILD_SHIPPING + if (GAllowDownsampledStandardTranslucency > 0) + { + static bool bOnce = false; + if (!bOnce) + { + UE_LOG(LogRenderer, Warning, TEXT("Blend modulate materials (%s) are not supported when r.AllowDownsampledStandardTranslucency > 0."), *Material->GetFriendlyName()); + bOnce = true; + } + } + #endif + } + + } + + return bShouldDraw; +} void FDeferredShadingSceneRenderer::UpdateTranslucencyTimersAndSeparateTranslucencyBufferSize(FRHICommandListImmediate& RHICmdList) { @@ -138,9 +227,8 @@ void FDeferredShadingSceneRenderer::UpdateTranslucencyTimersAndSeparateTransluce } void FDeferredShadingSceneRenderer::BeginTimingSeparateTranslucencyPass(FRHICommandListImmediate& RHICmdList, const FViewInfo& View) -{ - if (View.ViewState - && GSupportsTimestampRenderQueries +{ + if (View.ViewState && GSupportsTimestampRenderQueries #if !STATS && (CVarSeparateTranslucencyAutoDownsample.GetValueOnRenderThread() != 0) #endif @@ -152,8 +240,7 @@ void FDeferredShadingSceneRenderer::BeginTimingSeparateTranslucencyPass(FRHIComm void FDeferredShadingSceneRenderer::EndTimingSeparateTranslucencyPass(FRHICommandListImmediate& RHICmdList, const FViewInfo& View) { - if (View.ViewState - && GSupportsTimestampRenderQueries + if (View.ViewState && GSupportsTimestampRenderQueries #if !STATS && (CVarSeparateTranslucencyAutoDownsample.GetValueOnRenderThread() != 0) #endif @@ -163,27 +250,6 @@ void FDeferredShadingSceneRenderer::EndTimingSeparateTranslucencyPass(FRHIComman } } -static void SetTranslucentRenderTarget(FRHICommandList& RHICmdList, const FViewInfo& View, ETranslucencyPass::Type TranslucencyPass, bool bFirstTimeThisFrame = false) -{ - FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); - bool bNeedsClear = (&View == View.Family->Views[0]) && bFirstTimeThisFrame; - - if ((TranslucencyPass == ETranslucencyPass::TPT_SeparateTranslucency) && SceneContext.IsSeparateTranslucencyActive(View)) - { - SceneContext.BeginRenderingSeparateTranslucency(RHICmdList, View, bNeedsClear); - } - else if (TranslucencyPass == ETranslucencyPass::TPT_StandardTranslucency) - { - SceneContext.BeginRenderingTranslucency(RHICmdList, View, bNeedsClear); - } -} - -static void SetTranslucentState(FRHICommandList& RHICmdList, FDrawingPolicyRenderState& DrawRenderState) -{ - // Enable depth test, disable depth writes. - DrawRenderState.SetDepthStencilState(TStaticDepthStencilState::GetRHI()); -} - const FProjectedShadowInfo* FDeferredShadingSceneRenderer::PrepareTranslucentShadowMap(FRHICommandList& RHICmdList, const FViewInfo& View, FPrimitiveSceneInfo* PrimitiveSceneInfo, ETranslucencyPass::Type TranslucencyPass) { QUICK_SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_PrepareTranslucentShadowMap); @@ -259,15 +325,16 @@ private: IMPLEMENT_SHADER_TYPE(,FCopySceneColorPS,TEXT("TranslucentLightingShaders"),TEXT("CopySceneColorMain"),SF_Pixel); -void FTranslucencyDrawingPolicyFactory::CopySceneColor(FRHICommandList& RHICmdList, const FViewInfo& View, const FPrimitiveSceneProxy* PrimitiveSceneProxy) +void FTranslucencyDrawingPolicyFactory::CopySceneColor(FRHICommandList& RHICmdList, const FViewInfo& View) { FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); - SCOPED_DRAW_EVENTF(RHICmdList, EventCopy, TEXT("CopySceneColor from SceneColor node for %s %s"), PrimitiveSceneProxy ? *PrimitiveSceneProxy->GetOwnerName().ToString() : TEXT("Scene"), PrimitiveSceneProxy ? *PrimitiveSceneProxy->GetResourceName().ToString() : TEXT("Scene")); + SCOPED_DRAW_EVENTF(RHICmdList, EventCopy, TEXT("CopySceneColor from SceneColor for translucency")); RHICmdList.CopyToResolveTarget(SceneContext.GetSceneColorSurface(), SceneContext.GetSceneColorTexture(), true, FResolveRect(View.ViewRect.Min.X, View.ViewRect.Min.Y, View.ViewRect.Max.X, View.ViewRect.Max.Y)); SceneContext.BeginRenderingLightAttenuation(RHICmdList); + RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f); FGraphicsPipelineStateInitializer GraphicsPSOInit; RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit); @@ -275,7 +342,6 @@ void FTranslucencyDrawingPolicyFactory::CopySceneColor(FRHICommandList& RHICmdLi GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState::GetRHI(); GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI(); - RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f); TShaderMapRef ScreenVertexShader(View.ShaderMap); TShaderMapRef PixelShader(View.ShaderMap); @@ -419,52 +485,6 @@ public: } }; -static void CopySceneColorAndRestore(FRHICommandList& RHICmdList, const FViewInfo& View, const FPrimitiveSceneProxy* PrimitiveSceneProxy) -{ - check(IsInRenderingThread()); - FTranslucencyDrawingPolicyFactory::CopySceneColor(RHICmdList, View, PrimitiveSceneProxy); - // Restore state - SetTranslucentRenderTarget(RHICmdList, View, ETranslucencyPass::TPT_StandardTranslucency); -} - -class FCopySceneColorAndRestoreRenderThreadTask -{ - FRHICommandList& RHICmdList; - const FViewInfo& View; - const FPrimitiveSceneProxy* PrimitiveSceneProxy; -public: - - FCopySceneColorAndRestoreRenderThreadTask(FRHICommandList& InRHICmdList, const FViewInfo& InView, const FPrimitiveSceneProxy* InPrimitiveSceneProxy) - : RHICmdList(InRHICmdList) - , View(InView) - , PrimitiveSceneProxy(InPrimitiveSceneProxy) - { - } - - FORCEINLINE TStatId GetStatId() const - { - RETURN_QUICK_DECLARE_CYCLE_STAT(FCopySceneColorAndRestoreRenderThreadTask, STATGROUP_TaskGraphTasks); - } - - ENamedThreads::Type GetDesiredThread() - { - return ENamedThreads::RenderThread_Local; - } - - static ESubsequentsMode::Type GetSubsequentsMode() { return ESubsequentsMode::TrackSubsequents; } - - void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent) - { - CopySceneColorAndRestore(RHICmdList, View, PrimitiveSceneProxy); - RHICmdList.HandleRTThreadTaskCompletion(MyCompletionGraphEvent); - } -}; - -bool IsSeparateTranslucencyPossible(const FViewInfo& View) -{ - return (FSceneRenderTargets::CVarSetSeperateTranslucencyEnabled.GetValueOnRenderThread() != 0) && View.Family->EngineShowFlags.SeparateTranslucency && View.Family->EngineShowFlags.PostProcessing; -} - /** * Render a dynamic or static mesh using a translucent draw policy * @return true if the mesh rendered @@ -484,113 +504,78 @@ bool FTranslucencyDrawingPolicyFactory::DrawMesh( bool bDirty = false; const auto FeatureLevel = View.GetFeatureLevel(); + const FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); + // Determine the mesh's material and blend mode. const FMaterial* Material = Mesh.MaterialRenderProxy->GetMaterial(FeatureLevel); - const EBlendMode BlendMode = Material->GetBlendMode(); - // Only render translucent materials - if (IsTranslucentBlendMode(BlendMode) && ShouldIncludeDomainInMeshPass(Material->GetMaterialDomain())) + // Only render relevant materials + if (DrawingContext.ShouldDraw(View, Material, SceneContext.IsSeparateTranslucencyPass())) { - // fix for materials on Canvas - // PrimitiveSceneProxy is NULL when rendering Canvas items - const bool bMeshUseSeparateTranslucency = Material->IsSeparateTranslucencyEnabled() && IsSeparateTranslucencyPossible(View) && PrimitiveSceneProxy != nullptr; + FDrawingPolicyRenderState DrawRenderStateLocal(DrawRenderState); - // Only draw meshes in the relevant pass - if (bMeshUseSeparateTranslucency == (DrawingContext.TranslucenyPassType == ETranslucencyPass::TPT_SeparateTranslucency) - || DrawingContext.TranslucenyPassType == ETranslucencyPass::TPT_AllTranslucency) + const bool bDisableDepthTest = Material->ShouldDisableDepthTest(); + const bool bEnableResponsiveAA = Material->ShouldEnableResponsiveAA(); + // editor compositing not supported on translucent materials currently + const bool bEditorCompositeDepthTest = false; + + // if this draw is coming postAA then there is probably no depth buffer (it's canvas) and bEnableResponsiveAA wont' do anything anyway. + if (bEnableResponsiveAA && !DrawingContext.bPostAA) { - FDrawingPolicyRenderState DrawRenderStateLocal(DrawRenderState); - - if (Material->RequiresSceneColorCopy_RenderThread()) + if( bDisableDepthTest ) { - if (DrawingContext.bSceneColorCopyIsUpToDate == false) - { - if (CVarCopySceneColorOncePerViewOnly.GetValueOnRenderThread() == 0) - { - if (!RHICmdList.Bypass() && !IsInActualRenderingThread() && !IsInGameThread()) - { - FRHICommandList* CmdList = new FRHICommandList; - CmdList->CopyRenderThreadContexts(RHICmdList); - FGraphEventRef RenderThreadCompletionEvent = TGraphTask::CreateTask().ConstructAndDispatchWhenReady(*CmdList, View, PrimitiveSceneProxy); - RHICmdList.QueueRenderThreadCommandListSubmit(RenderThreadCompletionEvent, CmdList); - } - else - { - // otherwise, just do it now. We don't want to defer in this case because that can interfere with render target visualization (a debugging tool). - CopySceneColorAndRestore(RHICmdList, View, PrimitiveSceneProxy); - } - } - - // todo: this optimization is currently broken - DrawingContext.bSceneColorCopyIsUpToDate = (DrawingContext.TranslucenyPassType == ETranslucencyPass::TPT_SeparateTranslucency); - SetTranslucentState(RHICmdList, DrawRenderStateLocal); - } + DrawRenderStateLocal.SetDepthStencilState(TStaticDepthStencilState< + false, CF_Always, + true, CF_Always, SO_Keep, SO_Keep, SO_Replace, + false, CF_Always, SO_Keep, SO_Keep, SO_Keep, + STENCIL_TEMPORAL_RESPONSIVE_AA_MASK, STENCIL_TEMPORAL_RESPONSIVE_AA_MASK + >::GetRHI()); + DrawRenderStateLocal.SetStencilRef(STENCIL_TEMPORAL_RESPONSIVE_AA_MASK); } - - const bool bDisableDepthTest = Material->ShouldDisableDepthTest(); - const bool bEnableResponsiveAA = Material->ShouldEnableResponsiveAA(); - // editor compositing not supported on translucent materials currently - const bool bEditorCompositeDepthTest = false; - - // if this draw is coming postAA then there is probably no depth buffer (it's canvas) and bEnableResponsiveAA wont' do anything anyway. - if (bEnableResponsiveAA && !DrawingContext.bPostAA) + else { - if( bDisableDepthTest ) - { - DrawRenderStateLocal.SetDepthStencilState(TStaticDepthStencilState< - false, CF_Always, - true, CF_Always, SO_Keep, SO_Keep, SO_Replace, - false, CF_Always, SO_Keep, SO_Keep, SO_Keep, - STENCIL_TEMPORAL_RESPONSIVE_AA_MASK, STENCIL_TEMPORAL_RESPONSIVE_AA_MASK - >::GetRHI()); - DrawRenderStateLocal.SetStencilRef(STENCIL_TEMPORAL_RESPONSIVE_AA_MASK); - } - else - { - DrawRenderStateLocal.SetDepthStencilState(TStaticDepthStencilState< - false, CF_DepthNearOrEqual, - true, CF_Always, SO_Keep, SO_Keep, SO_Replace, - false, CF_Always, SO_Keep, SO_Keep, SO_Keep, - STENCIL_TEMPORAL_RESPONSIVE_AA_MASK, STENCIL_TEMPORAL_RESPONSIVE_AA_MASK - >::GetRHI()); - DrawRenderStateLocal.SetStencilRef(STENCIL_TEMPORAL_RESPONSIVE_AA_MASK); - } + DrawRenderStateLocal.SetDepthStencilState(TStaticDepthStencilState< + false, CF_DepthNearOrEqual, + true, CF_Always, SO_Keep, SO_Keep, SO_Replace, + false, CF_Always, SO_Keep, SO_Keep, SO_Keep, + STENCIL_TEMPORAL_RESPONSIVE_AA_MASK, STENCIL_TEMPORAL_RESPONSIVE_AA_MASK + >::GetRHI()); + DrawRenderStateLocal.SetStencilRef(STENCIL_TEMPORAL_RESPONSIVE_AA_MASK); } - else if( bDisableDepthTest ) - { - DrawRenderStateLocal.SetDepthStencilState(TStaticDepthStencilState::GetRHI()); - } - - FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); - FIntPoint OutScaledSize; - float OutScale; - SceneContext.GetSeparateTranslucencyDimensions(OutScaledSize, OutScale); - - ProcessBasePassMesh( - RHICmdList, - FProcessBasePassMeshParameters( - Mesh, - BatchElementMask, - Material, - PrimitiveSceneProxy, - !bPreFog, - bEditorCompositeDepthTest, - DrawingContext.TextureMode, - FeatureLevel - ), - FDrawTranslucentMeshAction( - RHICmdList, - View, - DrawRenderStateLocal, - HitProxyId, - DrawingContext.TranslucentSelfShadow, - PrimitiveSceneProxy && PrimitiveSceneProxy->CastsVolumetricTranslucentShadow(), - DrawingContext.TranslucenyPassType == ETranslucencyPass::TPT_SeparateTranslucency && OutScale < 1.0f - ) - ); - - bDirty = true; } + else if( bDisableDepthTest ) + { + DrawRenderStateLocal.SetDepthStencilState(TStaticDepthStencilState::GetRHI()); + } + + FIntPoint OutScaledSize; + float OutScale; + SceneContext.GetSeparateTranslucencyDimensions(OutScaledSize, OutScale); + + ProcessBasePassMesh( + RHICmdList, + FProcessBasePassMeshParameters( + Mesh, + BatchElementMask, + Material, + PrimitiveSceneProxy, + !bPreFog, + bEditorCompositeDepthTest, + DrawingContext.TextureMode, + FeatureLevel + ), + FDrawTranslucentMeshAction( + RHICmdList, + View, + DrawRenderStateLocal, + HitProxyId, + DrawingContext.TranslucentSelfShadow, + PrimitiveSceneProxy && PrimitiveSceneProxy->CastsVolumetricTranslucentShadow(), + OutScale < 1.f && SceneContext.IsSeparateTranslucencyPass() + ) + ); + + bDirty = true; } return bDirty; } @@ -690,18 +675,18 @@ class FVolumetricTranslucentShadowRenderThreadTask const FViewInfo& View; FDrawingPolicyRenderState DrawRenderState; FDeferredShadingSceneRenderer& Renderer; - ETranslucencyPass::Type TranslucenyPassType; + ETranslucencyPass::Type TranslucencyPass; int32 Index; public: - FORCEINLINE_DEBUGGABLE FVolumetricTranslucentShadowRenderThreadTask(FRHICommandList& InRHICmdList, const FTranslucentPrimSet& InPrimSet, const FViewInfo& InView, const FDrawingPolicyRenderState& InDrawRenderState, FDeferredShadingSceneRenderer& InRenderer, ETranslucencyPass::Type InTranslucenyPassType, int32 InIndex) + FORCEINLINE_DEBUGGABLE FVolumetricTranslucentShadowRenderThreadTask(FRHICommandList& InRHICmdList, const FTranslucentPrimSet& InPrimSet, const FViewInfo& InView, const FDrawingPolicyRenderState& InDrawRenderState, FDeferredShadingSceneRenderer& InRenderer, ETranslucencyPass::Type InTranslucencyPass, int32 InIndex) : RHICmdList(InRHICmdList) , PrimSet(InPrimSet) , View(InView) , DrawRenderState(InDrawRenderState) , Renderer(InRenderer) - , TranslucenyPassType(InTranslucenyPassType) + , TranslucencyPass(InTranslucencyPass) , Index(InIndex) { } @@ -720,7 +705,7 @@ public: void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent) { - PrimSet.DrawAPrimitive(RHICmdList, View, DrawRenderState, Renderer, TranslucenyPassType, Index); + PrimSet.DrawAPrimitive(RHICmdList, View, DrawRenderState, Renderer, TranslucencyPass, Index); RHICmdList.HandleRTThreadTaskCompletion(MyCompletionGraphEvent); } }; @@ -730,7 +715,7 @@ void FTranslucentPrimSet::DrawPrimitivesParallel( const FViewInfo& View, const FDrawingPolicyRenderState& DrawRenderState, FDeferredShadingSceneRenderer& Renderer, - ETranslucencyPass::Type TranslucenyPassType, + ETranslucencyPass::Type TranslucencyPass, int32 FirstPrimIdx, int32 LastPrimIdx ) const { @@ -749,12 +734,12 @@ void FTranslucentPrimSet::DrawPrimitivesParallel( // can't do this in parallel, defer FRHICommandList* CmdList = new FRHICommandList; CmdList->CopyRenderThreadContexts(RHICmdList); - FGraphEventRef RenderThreadCompletionEvent = TGraphTask::CreateTask().ConstructAndDispatchWhenReady(*CmdList, *this, View, DrawRenderState, Renderer, TranslucenyPassType, PrimIdx); + FGraphEventRef RenderThreadCompletionEvent = TGraphTask::CreateTask().ConstructAndDispatchWhenReady(*CmdList, *this, View, DrawRenderState, Renderer, TranslucencyPass, PrimIdx); RHICmdList.QueueRenderThreadCommandListSubmit(RenderThreadCompletionEvent, CmdList); } else { - RenderPrimitive(RHICmdList, View, DrawRenderState, PrimitiveSceneInfo, ViewRelevance, nullptr, TranslucenyPassType); + RenderPrimitive(RHICmdList, View, DrawRenderState, PrimitiveSceneInfo, ViewRelevance, nullptr, TranslucencyPass); } } } @@ -764,10 +749,10 @@ void FTranslucentPrimSet::DrawPrimitives( const FViewInfo& View, const FDrawingPolicyRenderState& DrawRenderState, FDeferredShadingSceneRenderer& Renderer, - ETranslucencyPass::Type TranslucenyPassType + ETranslucencyPass::Type TranslucencyPass ) const { - FInt32Range PassRange = SortedPrimsNum.GetPassRange(TranslucenyPassType); + FInt32Range PassRange = SortedPrimsNum.GetPassRange(TranslucencyPass); // Draw sorted scene prims for( int32 PrimIdx = PassRange.GetLowerBoundValue(); PrimIdx < PassRange.GetUpperBoundValue(); PrimIdx++ ) @@ -778,9 +763,9 @@ void FTranslucentPrimSet::DrawPrimitives( checkSlow(ViewRelevance.HasTranslucency()); - const FProjectedShadowInfo* TranslucentSelfShadow = Renderer.PrepareTranslucentShadowMap(RHICmdList, View, PrimitiveSceneInfo, TranslucenyPassType); + const FProjectedShadowInfo* TranslucentSelfShadow = Renderer.PrepareTranslucentShadowMap(RHICmdList, View, PrimitiveSceneInfo, TranslucencyPass); - RenderPrimitive(RHICmdList, View, DrawRenderState, PrimitiveSceneInfo, ViewRelevance, TranslucentSelfShadow, TranslucenyPassType); + RenderPrimitive(RHICmdList, View, DrawRenderState, PrimitiveSceneInfo, ViewRelevance, TranslucentSelfShadow, TranslucencyPass); } View.SimpleElementCollector.DrawBatchedElements(RHICmdList, DrawRenderState, View, FTexture2DRHIRef(), EBlendModeFilter::Translucent); @@ -793,16 +778,14 @@ void FTranslucentPrimSet::RenderPrimitive( FPrimitiveSceneInfo* PrimitiveSceneInfo, const FPrimitiveViewRelevance& ViewRelevance, const FProjectedShadowInfo* TranslucentSelfShadow, - ETranslucencyPass::Type TranslucenyPassType) const + ETranslucencyPass::Type TranslucencyPass) const { checkSlow(ViewRelevance.HasTranslucency()); auto FeatureLevel = View.GetFeatureLevel(); if (ViewRelevance.bDrawRelevance) { - FTranslucencyDrawingPolicyFactory::ContextType Context(TranslucentSelfShadow, TranslucenyPassType); - - const bool bSeparateTranslucencyPossible = IsSeparateTranslucencyPossible(View); + FTranslucencyDrawingPolicyFactory::ContextType Context(TranslucentSelfShadow, TranslucencyPass); // Render dynamic scene prim { @@ -828,27 +811,20 @@ void FTranslucentPrimSet::RenderPrimitive( { FStaticMesh& StaticMesh = PrimitiveSceneInfo->StaticMeshes[StaticMeshIdx]; - if (View.StaticMeshVisibilityMap[StaticMesh.Id] - // Only render static mesh elements using translucent materials - && StaticMesh.IsTranslucent(FeatureLevel)) + // Only render visible elements with relevant materials + if (View.StaticMeshVisibilityMap[StaticMesh.Id] && Context.ShouldDraw(View, StaticMesh.MaterialRenderProxy->GetMaterial(FeatureLevel), FSceneRenderTargets::Get(RHICmdList).IsSeparateTranslucencyPass())) { - const bool bMeshUseSeparateTranslucency = StaticMesh.MaterialRenderProxy->GetMaterial(FeatureLevel)->IsSeparateTranslucencyEnabled() && bSeparateTranslucencyPossible; - - if (bMeshUseSeparateTranslucency == (TranslucenyPassType == ETranslucencyPass::TPT_SeparateTranslucency) - || TranslucenyPassType == ETranslucencyPass::TPT_AllTranslucency) - { - FTranslucencyDrawingPolicyFactory::DrawStaticMesh( - RHICmdList, - View, - FTranslucencyDrawingPolicyFactory::ContextType(TranslucentSelfShadow, TranslucenyPassType), - StaticMesh, - StaticMesh.bRequiresPerElementVisibility ? View.StaticMeshBatchVisibility[StaticMesh.Id] : ((1ull << StaticMesh.Elements.Num()) - 1), - false, - DrawRenderState, - PrimitiveSceneInfo->Proxy, - StaticMesh.BatchHitProxyId - ); - } + FTranslucencyDrawingPolicyFactory::DrawStaticMesh( + RHICmdList, + View, + Context, + StaticMesh, + StaticMesh.bRequiresPerElementVisibility ? View.StaticMeshBatchVisibility[StaticMesh.BatchVisibilityId] : ((1ull << StaticMesh.Elements.Num()) - 1), + false, + DrawRenderState, + PrimitiveSceneInfo->Proxy, + StaticMesh.BatchHitProxyId + ); } } } @@ -886,35 +862,31 @@ void FTranslucentPrimSet::AppendScenePrimitives(FTranslucentSortedPrim* Elements SortedPrimsNum.Append(TranslucentPrimitiveCountPerPass); } -void FTranslucentPrimSet::PlaceScenePrimitive(FPrimitiveSceneInfo* PrimitiveSceneInfo, const FViewInfo& ViewInfo, bool bUseNormalTranslucency, bool bUseSeparateTranslucency, bool bUseMobileSeparateTranslucency, +void FTranslucentPrimSet::PlaceScenePrimitive(FPrimitiveSceneInfo* PrimitiveSceneInfo, const FViewInfo& ViewInfo, const FPrimitiveViewRelevance& ViewRelevance, FTranslucentPrimSet::FTranslucentSortedPrim *InArrayStart, int32& InOutArrayNum, FTranslucenyPrimCount& OutCount) { const float SortKey = CalculateTranslucentSortKey(PrimitiveSceneInfo, ViewInfo); const auto FeatureLevel = ViewInfo.GetFeatureLevel(); - int32 CVarEnabled = FSceneRenderTargets::CVarSetSeperateTranslucencyEnabled.GetValueOnRenderThread(); - bool bCanBeSeparate = CVarEnabled - && FeatureLevel >= ERHIFeatureLevel::SM4 - && ViewInfo.Family->EngineShowFlags.PostProcessing - && !ViewInfo.Family->EngineShowFlags.ShaderComplexity - && ViewInfo.Family->EngineShowFlags.SeparateTranslucency; - - bool bIsSeparateTranslucency = bUseSeparateTranslucency && bCanBeSeparate; - bool bIsNonSeparateTranslucency = bUseNormalTranslucency || !bCanBeSeparate; - - if (bIsSeparateTranslucency) + if (ViewInfo.Family->AllowTranslucencyAfterDOF()) { - ETranslucencyPass::Type TranslucencyPass = ETranslucencyPass::TPT_SeparateTranslucency; + if (ViewRelevance.bNormalTranslucencyRelevance) + { + new(&InArrayStart[InOutArrayNum++]) FTranslucentSortedPrim(PrimitiveSceneInfo, ETranslucencyPass::TPT_StandardTranslucency, PrimitiveSceneInfo->Proxy->GetTranslucencySortPriority(), SortKey); + OutCount.Add(ETranslucencyPass::TPT_StandardTranslucency, ViewRelevance.bUsesSceneColorCopy, ViewRelevance.bDisableOffscreenRendering); + } - new(&InArrayStart[InOutArrayNum++]) FTranslucentSortedPrim(PrimitiveSceneInfo, TranslucencyPass, PrimitiveSceneInfo->Proxy->GetTranslucencySortPriority(), SortKey); - OutCount.Add(TranslucencyPass); + if (ViewRelevance.bSeparateTranslucencyRelevance) + { + new(&InArrayStart[InOutArrayNum++]) FTranslucentSortedPrim(PrimitiveSceneInfo, ETranslucencyPass::TPT_TranslucencyAfterDOF, PrimitiveSceneInfo->Proxy->GetTranslucencySortPriority(), SortKey); + OutCount.Add(ETranslucencyPass::TPT_TranslucencyAfterDOF, ViewRelevance.bUsesSceneColorCopy, ViewRelevance.bDisableOffscreenRendering); + } } - if (bIsNonSeparateTranslucency) + else // Otherwise, everything is rendered in a single bucket. This is not related to whether DOF is currently enabled or not. { - ETranslucencyPass::Type TranslucencyPass = ETranslucencyPass::TPT_StandardTranslucency; - - new(&InArrayStart[InOutArrayNum++]) FTranslucentSortedPrim(PrimitiveSceneInfo, TranslucencyPass, PrimitiveSceneInfo->Proxy->GetTranslucencySortPriority(), SortKey); - OutCount.Add(TranslucencyPass); + // When using all translucency, Standard and AfterDOF are sorted together instead of being rendered like 2 buckets. + new(&InArrayStart[InOutArrayNum++]) FTranslucentSortedPrim(PrimitiveSceneInfo, ETranslucencyPass::TPT_AllTranslucency, PrimitiveSceneInfo->Proxy->GetTranslucencySortPriority(), SortKey); + OutCount.Add(ETranslucencyPass::TPT_AllTranslucency, ViewRelevance.bUsesSceneColorCopy, ViewRelevance.bDisableOffscreenRendering); } } @@ -924,22 +896,42 @@ void FTranslucentPrimSet::SortPrimitives() SortedPrims.Sort( FCompareFTranslucentSortedPrim() ); } -bool FSceneRenderer::ShouldRenderTranslucency() const +extern int32 GLightShaftRenderAfterDOF; + +bool FSceneRenderer::ShouldRenderTranslucency(ETranslucencyPass::Type TranslucencyPass) const { - bool bRender = false; - - for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) + // Change this condition to control where simple elements should be rendered. + if (IsMainTranslucencyPass(TranslucencyPass)) { - const FViewInfo& View = Views[ViewIndex]; - - if (View.TranslucentPrimSet.NumPrims() || View.bHasTranslucentViewMeshElements) + if (ViewFamily.EngineShowFlags.VisualizeLPV) { - bRender = true; - break; + return true; + } + + for (const FViewInfo& View : Views) + { + if (View.bHasTranslucentViewMeshElements || View.SimpleElementCollector.BatchedElements.HasPrimsToDraw()) + { + return true; + } } } - return bRender; + // If lightshafts are rendered in low res, we must reset the offscreen buffer in case is was also used in TPT_StandardTranslucency. + if (GLightShaftRenderAfterDOF && TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterDOF) + { + return true; + } + + for (const FViewInfo& View : Views) + { + if (View.TranslucentPrimSet.SortedPrimsNum.Num(TranslucencyPass) > 0) + { + return true; + } + } + + return false; } class FDrawSortedTransAnyThreadTask : public FRenderTask @@ -948,7 +940,7 @@ class FDrawSortedTransAnyThreadTask : public FRenderTask FRHICommandList& RHICmdList; const FViewInfo& View; FDrawingPolicyRenderState DrawRenderState; - ETranslucencyPass::Type TranslucenyPassType; + ETranslucencyPass::Type TranslucencyPass; const int32 FirstIndex; const int32 LastIndex; @@ -960,7 +952,7 @@ public: FRHICommandList& InRHICmdList, const FViewInfo& InView, const FDrawingPolicyRenderState& InDrawRenderState, - ETranslucencyPass::Type InTranslucenyPassType, + ETranslucencyPass::Type InTranslucencyPass, int32 InFirstIndex, int32 InLastIndex ) @@ -968,7 +960,7 @@ public: , RHICmdList(InRHICmdList) , View(InView) , DrawRenderState(InDrawRenderState) - , TranslucenyPassType(InTranslucenyPassType) + , TranslucencyPass(InTranslucencyPass) , FirstIndex(InFirstIndex) , LastIndex(InLastIndex) { @@ -984,7 +976,7 @@ public: void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent) { FScopeCycleCounter ScopeOuter(RHICmdList.ExecuteStat); - View.TranslucentPrimSet.DrawPrimitivesParallel(RHICmdList, View, DrawRenderState, Renderer, TranslucenyPassType, FirstIndex, LastIndex); + View.TranslucentPrimSet.DrawPrimitivesParallel(RHICmdList, View, DrawRenderState, Renderer, TranslucencyPass, FirstIndex, LastIndex); RHICmdList.HandleRTThreadTaskCompletion(MyCompletionGraphEvent); } }; @@ -994,13 +986,14 @@ DECLARE_CYCLE_STAT(TEXT("Translucency"), STAT_CLP_Translucency, STATGROUP_Parall class FTranslucencyPassParallelCommandListSet : public FParallelCommandListSet { - ETranslucencyPass::Type TranslucenyPassType; - bool bFirstTimeThisFrame; + ETranslucencyPass::Type TranslucencyPass; + bool bRenderInSeparateTranslucency; + public: - FTranslucencyPassParallelCommandListSet(const FViewInfo& InView, FRHICommandListImmediate& InParentCmdList, bool bInParallelExecute, bool bInCreateSceneContext, ETranslucencyPass::Type InTranslucenyPassType) + FTranslucencyPassParallelCommandListSet(const FViewInfo& InView, FRHICommandListImmediate& InParentCmdList, bool bInParallelExecute, bool bInCreateSceneContext, ETranslucencyPass::Type InTranslucencyPass, bool InRenderInSeparateTranslucency) : FParallelCommandListSet(GET_STATID(STAT_CLP_Translucency), InView, InParentCmdList, bInParallelExecute, bInCreateSceneContext) - , TranslucenyPassType(InTranslucenyPassType) - , bFirstTimeThisFrame(true) + , TranslucencyPass(InTranslucencyPass) + , bRenderInSeparateTranslucency(InRenderInSeparateTranslucency) { SetStateOnCommandList(ParentCmdList); } @@ -1012,10 +1005,18 @@ public: virtual void SetStateOnCommandList(FRHICommandList& CmdList) override { + // Never needs clear here as it is already done in RenderTranslucency. FParallelCommandListSet::SetStateOnCommandList(CmdList); - SetTranslucentRenderTarget(CmdList, View, TranslucenyPassType, bFirstTimeThisFrame); - SetTranslucentState(CmdList, DrawRenderState); - bFirstTimeThisFrame = false; + FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(CmdList); + if (bRenderInSeparateTranslucency) + { + SceneContext.BeginRenderingSeparateTranslucency(CmdList, View, false); + } + else + { + SceneContext.BeginRenderingTranslucency(CmdList, View, false); + } + DrawRenderState.SetDepthStencilState(TStaticDepthStencilState::GetRHI()); } }; @@ -1029,74 +1030,96 @@ static TAutoConsoleVariable CVarRHICmdFlushRenderThreadTasksTranslucentPa 0, TEXT("Wait for completion of parallel render thread tasks at the end of the translucent pass. A more granular version of r.RHICmdFlushRenderThreadTasks. If either r.RHICmdFlushRenderThreadTasks or r.RHICmdFlushRenderThreadTasksTranslucentPass is > 0 we will flush.")); -// this is a static because we let the async tasks beyond the function -static FTranslucencyDrawingPolicyFactory::ContextType GParallelTranslucencyContext; -void FDeferredShadingSceneRenderer::RenderTranslucencyParallel(FRHICommandListImmediate& RHICmdList) +static TAutoConsoleVariable CVarParallelTranslucency( + TEXT("r.ParallelTranslucency"), + 1, + TEXT("Toggles parallel translucency rendering. Parallel rendering must be enabled for this to have an effect."), + ECVF_RenderThreadSafe + ); + +// this is a static because we let the async tasks beyond the function. Using all translucency as we want all materials to render +static FTranslucencyDrawingPolicyFactory::ContextType GParallelTranslucencyContext(nullptr, ETranslucencyPass::TPT_AllTranslucency); + + +void FDeferredShadingSceneRenderer::RenderViewTranslucency(FRHICommandListImmediate& RHICmdList, const FViewInfo& View, const FDrawingPolicyRenderState& DrawRenderState, ETranslucencyPass::Type TranslucencyPass) { - FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); - SceneContext.AllocLightAttenuation(RHICmdList); // materials will attempt to get this texture before the deferred command to set it up executes - check(IsInRenderingThread()); + // Draw translucent prims + View.TranslucentPrimSet.DrawPrimitives(RHICmdList, View, DrawRenderState, *this, TranslucencyPass); - GParallelTranslucencyContext.TranslucentSelfShadow = nullptr; - GParallelTranslucencyContext.TranslucenyPassType = ETranslucencyPass::TPT_StandardTranslucency; - GParallelTranslucencyContext.bSceneColorCopyIsUpToDate = false; - FScopedCommandListWaitForTasks Flusher(CVarRHICmdFlushRenderThreadTasksTranslucentPass.GetValueOnRenderThread() > 0 || CVarRHICmdFlushRenderThreadTasks.GetValueOnRenderThread() > 0, RHICmdList); - - bool bRequiresSeperateTranslucencyResolve = false; - - for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) + if (IsMainTranslucencyPass(TranslucencyPass)) { - SCOPED_CONDITIONAL_DRAW_EVENTF(RHICmdList, EventView, Views.Num() > 1, TEXT("View%d"), ViewIndex); - - FViewInfo& View = Views[ViewIndex]; + View.SimpleElementCollector.DrawBatchedElements(RHICmdList, DrawRenderState, View, FTexture2DRHIRef(), EBlendModeFilter::Translucent); + // editor and debug rendering + if (View.bHasTranslucentViewMeshElements) { + FTranslucencyDrawingPolicyFactory::ContextType Context(0, TranslucencyPass); + DrawViewElements(RHICmdList, View, DrawRenderState, Context, SDPG_World, false); + DrawViewElements(RHICmdList, View, DrawRenderState, Context, SDPG_Foreground, false); + } -#if STATS - if (View.ViewState) + const FSceneViewState* ViewState = (const FSceneViewState*)View.State; + if (ViewState && View.Family->EngineShowFlags.VisualizeLPV) + { + FLightPropagationVolume* LightPropagationVolume = ViewState->GetLightPropagationVolume(View.GetFeatureLevel()); + + if (LightPropagationVolume) { - View.ViewState->TranslucencyTimer.Begin(RHICmdList); + LightPropagationVolume->Visualise(RHICmdList, View); } -#endif - - ETranslucencyPass::Type TranslucenyPassType = ETranslucencyPass::TPT_StandardTranslucency; + } + } +} +void FDeferredShadingSceneRenderer::RenderViewTranslucencyParallel(FRHICommandListImmediate& RHICmdList, const FViewInfo& View, const FDrawingPolicyRenderState& DrawRenderState, ETranslucencyPass::Type TranslucencyPass) +{ + FTranslucencyPassParallelCommandListSet ParallelCommandListSet( + View, + RHICmdList, + CVarRHICmdTranslucencyPassDeferredContexts.GetValueOnRenderThread() > 0, + CVarRHICmdFlushRenderThreadTasksTranslucentPass.GetValueOnRenderThread() == 0 && CVarRHICmdFlushRenderThreadTasks.GetValueOnRenderThread() == 0, + TranslucencyPass, + FSceneRenderTargets::Get(RHICmdList).IsSeparateTranslucencyPass() + ); - FTranslucencyPassParallelCommandListSet ParallelCommandListSet(View, RHICmdList, - CVarRHICmdTranslucencyPassDeferredContexts.GetValueOnRenderThread() > 0, - CVarRHICmdFlushRenderThreadTasksTranslucentPass.GetValueOnRenderThread() == 0 && CVarRHICmdFlushRenderThreadTasks.GetValueOnRenderThread() == 0, - TranslucenyPassType); - - { - QUICK_SCOPE_CYCLE_COUNTER(RenderTranslucencyParallel_Start_FDrawSortedTransAnyThreadTask); + { + QUICK_SCOPE_CYCLE_COUNTER(RenderTranslucencyParallel_Start_FDrawSortedTransAnyThreadTask); - FInt32Range PassRange = View.TranslucentPrimSet.SortedPrimsNum.GetPassRange(TranslucenyPassType); - int32 NumPrims = PassRange.Size(); - int32 EffectiveThreads = FMath::Min(FMath::DivideAndRoundUp(NumPrims, ParallelCommandListSet.MinDrawsPerCommandList), ParallelCommandListSet.Width); + FInt32Range PassRange = View.TranslucentPrimSet.SortedPrimsNum.GetPassRange(TranslucencyPass); + int32 NumPrims = PassRange.Size(); + int32 EffectiveThreads = FMath::Min(FMath::DivideAndRoundUp(NumPrims, ParallelCommandListSet.MinDrawsPerCommandList), ParallelCommandListSet.Width); + + int32 Start = PassRange.GetLowerBoundValue(); + if (EffectiveThreads) + { + int32 NumPer = NumPrims / EffectiveThreads; + int32 Extra = NumPrims - NumPer * EffectiveThreads; + + for (int32 ThreadIndex = 0; ThreadIndex < EffectiveThreads; ThreadIndex++) + { + int32 Last = Start + (NumPer - 1) + (ThreadIndex < Extra); + check(Last >= Start); - int32 Start = PassRange.GetLowerBoundValue(); - if (EffectiveThreads) { - int32 NumPer = NumPrims / EffectiveThreads; - int32 Extra = NumPrims - NumPer * EffectiveThreads; - - for (int32 ThreadIndex = 0; ThreadIndex < EffectiveThreads; ThreadIndex++) - { - int32 Last = Start + (NumPer - 1) + (ThreadIndex < Extra); - check(Last >= Start); - - { - FRHICommandList* CmdList = ParallelCommandListSet.NewParallelCommandList(); + FRHICommandList* CmdList = ParallelCommandListSet.NewParallelCommandList(); - FGraphEventRef AnyThreadCompletionEvent = TGraphTask::CreateTask(ParallelCommandListSet.GetPrereqs(), ENamedThreads::RenderThread) - .ConstructAndDispatchWhenReady(*this, *CmdList, View, ParallelCommandListSet.DrawRenderState, TranslucenyPassType, Start, Last); + FGraphEventRef AnyThreadCompletionEvent = TGraphTask::CreateTask(ParallelCommandListSet.GetPrereqs(), ENamedThreads::RenderThread) + .ConstructAndDispatchWhenReady(*this, *CmdList, View, ParallelCommandListSet.DrawRenderState, TranslucencyPass, Start, Last); - ParallelCommandListSet.AddParallelCommandList(CmdList, AnyThreadCompletionEvent); - } - Start = Last + 1; - } + ParallelCommandListSet.AddParallelCommandList(CmdList, AnyThreadCompletionEvent); } + Start = Last + 1; } + } + } + + if (IsMainTranslucencyPass(TranslucencyPass)) + { + View.SimpleElementCollector.DrawBatchedElements(RHICmdList, DrawRenderState, View, FTexture2DRHIRef(), EBlendModeFilter::Translucent); + + // editor and debug rendering + if (View.bHasTranslucentViewMeshElements) + { // Draw the view's mesh elements with the translucent drawing policy. { QUICK_SCOPE_CYCLE_COUNTER(RenderTranslucencyParallel_SDPG_World); @@ -1108,240 +1131,331 @@ void FDeferredShadingSceneRenderer::RenderTranslucencyParallel(FRHICommandListIm DrawViewElementsParallel(GParallelTranslucencyContext, SDPG_Foreground, false, ParallelCommandListSet); } } -#if STATS - if (View.ViewState) + + const FSceneViewState* ViewState = (const FSceneViewState*)View.State; + if (ViewState && View.Family->EngineShowFlags.VisualizeLPV) { - View.ViewState->TranslucencyTimer.End(RHICmdList); + FLightPropagationVolume* LightPropagationVolume = ViewState->GetLightPropagationVolume(View.GetFeatureLevel()); + + if (LightPropagationVolume) + { + LightPropagationVolume->Visualise(RHICmdList, View); + } + } + } +} + +void FDeferredShadingSceneRenderer::SetupDownsampledTranslucencyViewUniformBuffer(FRHICommandListImmediate& RHICmdList, FViewInfo& View) +{ + if (!View.DownsampledTranslucencyViewUniformBuffer) + { + FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); + FIntPoint ScaledSize; + float DownsamplingScale = 1.f; + SceneContext.GetSeparateTranslucencyDimensions(ScaledSize, DownsamplingScale); + ensure(DownsamplingScale < 1.f); + + SceneContext.GetDownsampledTranslucencyDepth(RHICmdList, ScaledSize); + DownsampleDepthSurface(RHICmdList, SceneContext.GetDownsampledTranslucencyDepthSurface(), View, DownsamplingScale, false); + + FViewUniformShaderParameters DownsampledTranslucencyParameters = *View.CachedViewUniformShaderParameters; + + // Update the parts of DownsampledTranslucencyParameters which are dependent on the buffer size and view rect + View.SetupViewRectUniformBufferParameters( + DownsampledTranslucencyParameters, + ScaledSize, + FIntRect(View.ViewRect.Min.X * DownsamplingScale, View.ViewRect.Min.Y * DownsamplingScale, View.ViewRect.Max.X * DownsamplingScale, View.ViewRect.Max.Y * DownsamplingScale), + View.ViewMatrices, + View.PrevViewMatrices + ); + + View.DownsampledTranslucencyViewUniformBuffer = TUniformBufferRef::CreateUniformBufferImmediate(DownsampledTranslucencyParameters, UniformBuffer_SingleFrame); + } +} + +void FDeferredShadingSceneRenderer::ConditionalResolveSceneColorForTranslucentMaterials(FRHICommandListImmediate& RHICmdList) +{ + for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) + { + FViewInfo& View = Views[ViewIndex]; + + bool bNeedsResolve = false; + for (int32 TranslucencyPass = 0; TranslucencyPass < ETranslucencyPass::TPT_MAX && !bNeedsResolve; ++TranslucencyPass) + { + bNeedsResolve |= View.TranslucentPrimSet.SortedPrimsNum.UseSceneColorCopy((ETranslucencyPass::Type)TranslucencyPass); + } + + if (bNeedsResolve) + { + FTranslucencyDrawingPolicyFactory::CopySceneColor(RHICmdList, View); + } + } +} + +void FDeferredShadingSceneRenderer::RenderTranslucency(FRHICommandListImmediate& RHICmdList, ETranslucencyPass::Type TranslucencyPass) +{ + if (!ShouldRenderTranslucency(TranslucencyPass)) + { + return; // Early exit if nothing needs to be done. + } + + SCOPED_DRAW_EVENT(RHICmdList, Translucency); + SCOPED_GPU_STAT(RHICmdList, Stat_GPU_Translucency); + + FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); + + // Support for parallel rendering. + const bool bUseParallel = GRHICommandList.UseParallelAlgorithms() && CVarParallelTranslucency.GetValueOnRenderThread(); + if (bUseParallel) + { + SceneContext.AllocLightAttenuation(RHICmdList); // materials will attempt to get this texture before the deferred command to set it up executes + } + FScopedCommandListWaitForTasks Flusher(bUseParallel && (CVarRHICmdFlushRenderThreadTasksTranslucentPass.GetValueOnRenderThread() > 0 || CVarRHICmdFlushRenderThreadTasks.GetValueOnRenderThread() > 0), RHICmdList); + + for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) + { + SCOPED_CONDITIONAL_DRAW_EVENTF(RHICmdList, EventView, Views.Num() > 1, TEXT("View%d"), ViewIndex); + + FViewInfo& View = Views[ViewIndex]; + + // if (View.TranslucentPrimSet.SortedPrimsNum.UseSceneColorCopy(TranslucencyPass)) + // { + // FTranslucencyDrawingPolicyFactory::CopySceneColor(RHICmdList, View); + // } + +#if STATS + if (View.ViewState && IsMainTranslucencyPass(TranslucencyPass)) + { + View.ViewState->TranslucencyTimer.Begin(RHICmdList); } #endif - if (SceneContext.IsSeparateTranslucencyActive(View)) + + FDrawingPolicyRenderState DrawRenderState(View); + + // If downsampling we need to render in the separate buffer. Otherwise we also need to render offscreen to apply TPT_TranslucencyAfterDOF + if (RenderInSeparateTranslucency(SceneContext, TranslucencyPass, View.TranslucentPrimSet.SortedPrimsNum.DisableOffscreenRendering(TranslucencyPass))) { - QUICK_SCOPE_CYCLE_COUNTER(RenderTranslucencyParallel_Downsample); - // we need to allocate this now so it ends up in the snapshot FIntPoint ScaledSize; - float Scale = 1.0f; - SceneContext.GetSeparateTranslucencyDimensions(ScaledSize, Scale); - - if (Scale < 1.0f) + float DownsamplingScale = 1.f; + SceneContext.GetSeparateTranslucencyDimensions(ScaledSize, DownsamplingScale); + if (DownsamplingScale < 1.f) { - SceneContext.GetSeparateTranslucencyDepth(RHICmdList, ScaledSize); - DownsampleDepthSurface(RHICmdList, SceneContext.GetSeparateTranslucencyDepthSurface(), View, Scale, false); - - FViewUniformShaderParameters DownsampledTranslucencyParameters = *View.CachedViewUniformShaderParameters; - - // Update the parts of DownsampledTranslucencyParameters which are dependent on the buffer size and view rect - View.SetupViewRectUniformBufferParameters( - DownsampledTranslucencyParameters, - ScaledSize, - FIntRect(View.ViewRect.Min.X * Scale, View.ViewRect.Min.Y * Scale, View.ViewRect.Max.X * Scale, View.ViewRect.Max.Y * Scale), - View.ViewMatrices, - View.PrevViewMatrices - ); - - View.DownsampledTranslucencyViewUniformBuffer = TUniformBufferRef::CreateUniformBufferImmediate(DownsampledTranslucencyParameters, UniformBuffer_SingleFrame); + SetupDownsampledTranslucencyViewUniformBuffer(RHICmdList, View); } - } - { BeginTimingSeparateTranslucencyPass(RHICmdList, View); + SceneContext.BeginRenderingSeparateTranslucency(RHICmdList, View, ViewIndex == 0); + // Draw only translucent prims that are in the SeparateTranslucency pass + DrawRenderState.SetDepthStencilState(TStaticDepthStencilState::GetRHI()); + + if (bUseParallel) { - ETranslucencyPass::Type TranslucencyPass = ETranslucencyPass::TPT_SeparateTranslucency; - - if (CVarCopySceneColorOncePerViewOnly.GetValueOnRenderThread() != 0) - { - TGraphTask::CreateTask().ConstructAndDispatchWhenReady(RHICmdList, View, nullptr); - } - - // always call BeginRenderingSeparateTranslucency() even if there are no primitives to we keep the RT allocated - FTranslucencyPassParallelCommandListSet ParallelCommandListSet(View, - RHICmdList, - CVarRHICmdTranslucencyPassDeferredContexts.GetValueOnRenderThread() > 0, - CVarRHICmdFlushRenderThreadTasksTranslucentPass.GetValueOnRenderThread() == 0 && CVarRHICmdFlushRenderThreadTasks.GetValueOnRenderThread() == 0, - TranslucencyPass); - - // Draw only translucent prims that are in the SeparateTranslucency pass - if (View.TranslucentPrimSet.SortedPrimsNum.Num(TranslucencyPass) > 0) - { - bRequiresSeperateTranslucencyResolve = true; - - QUICK_SCOPE_CYCLE_COUNTER(RenderTranslucencyParallel_Start_FDrawSortedTransAnyThreadTask_SeparateTransluceny); - - FInt32Range PassRange = View.TranslucentPrimSet.SortedPrimsNum.GetPassRange(TranslucencyPass); - int32 NumPrims = PassRange.Size(); - int32 EffectiveThreads = FMath::Min(FMath::DivideAndRoundUp(NumPrims, ParallelCommandListSet.MinDrawsPerCommandList), ParallelCommandListSet.Width); - - int32 Start = PassRange.GetLowerBoundValue(); - check(EffectiveThreads); - { - int32 NumPer = NumPrims / EffectiveThreads; - int32 Extra = NumPrims - NumPer * EffectiveThreads; - - for (int32 ThreadIndex = 0; ThreadIndex < EffectiveThreads; ThreadIndex++) - { - int32 Last = Start + (NumPer - 1) + (ThreadIndex < Extra); - check(Last >= Start); - - { - FRHICommandList* CmdList = ParallelCommandListSet.NewParallelCommandList(); - - FGraphEventRef AnyThreadCompletionEvent = TGraphTask::CreateTask(ParallelCommandListSet.GetPrereqs(), ENamedThreads::RenderThread) - .ConstructAndDispatchWhenReady(*this, *CmdList, View, ParallelCommandListSet.DrawRenderState, TranslucencyPass, Start, Last); - - ParallelCommandListSet.AddParallelCommandList(CmdList, AnyThreadCompletionEvent); - } - Start = Last + 1; - } - } - } + RenderViewTranslucencyParallel(RHICmdList, View, DrawRenderState, TranslucencyPass); + } + else + { + RenderViewTranslucency(RHICmdList, View, DrawRenderState, TranslucencyPass); } + SceneContext.FinishRenderingSeparateTranslucency(RHICmdList, View); EndTimingSeparateTranslucencyPass(RHICmdList, View); + + if (TranslucencyPass != ETranslucencyPass::TPT_TranslucencyAfterDOF) + { + FTranslucencyDrawingPolicyFactory::UpsampleTranslucency(RHICmdList, View, false); + } } - } - - if (bRequiresSeperateTranslucencyResolve) - { - SceneContext.FinishRenderingSeparateTranslucency(RHICmdList); - } -} - -static TAutoConsoleVariable CVarParallelTranslucency( - TEXT("r.ParallelTranslucency"), - 1, - TEXT("Toggles parallel translucency rendering. Parallel rendering must be enabled for this to have an effect."), - ECVF_RenderThreadSafe - ); - -void FDeferredShadingSceneRenderer::DrawAllTranslucencyPasses(FRHICommandListImmediate& RHICmdList, const FViewInfo& View, const FDrawingPolicyRenderState& DrawRenderState, ETranslucencyPass::Type TranslucencyPass) -{ - // Draw translucent prims - View.TranslucentPrimSet.DrawPrimitives(RHICmdList, View, DrawRenderState, *this, TranslucencyPass); - - FTranslucencyDrawingPolicyFactory::ContextType Context(0, TranslucencyPass); - - // editor and debug rendering - DrawViewElements(RHICmdList, View, DrawRenderState, Context, SDPG_World, false); - DrawViewElements(RHICmdList, View, DrawRenderState, Context, SDPG_Foreground, false); -} - -void FDeferredShadingSceneRenderer::RenderTranslucency(FRHICommandListImmediate& RHICmdList) -{ - if (ShouldRenderTranslucency()) - { - SCOPED_DRAW_EVENT(RHICmdList, Translucency); - SCOPED_GPU_STAT(RHICmdList, Stat_GPU_Translucency); - - if (GRHICommandList.UseParallelAlgorithms() && CVarParallelTranslucency.GetValueOnRenderThread()) + else { - RenderTranslucencyParallel(RHICmdList); - return; + SceneContext.BeginRenderingTranslucency(RHICmdList, View, ViewIndex == 0); + DrawRenderState.SetDepthStencilState(TStaticDepthStencilState::GetRHI()); + + if (bUseParallel) + { + RenderViewTranslucencyParallel(RHICmdList, View, DrawRenderState, TranslucencyPass); + } + else + { + RenderViewTranslucency(RHICmdList, View, DrawRenderState, TranslucencyPass); + } + + // SceneContext.FinishRenderingTranslucency(RHICmdList, View); } +#if STATS + if (View.ViewState && IsMainTranslucencyPass(TranslucencyPass)) + { + STAT(View.ViewState->TranslucencyTimer.End(RHICmdList)); + } +#endif + } +} + +class FTranslucencyUpsamplingPS : public FGlobalShader +{ +protected: + + static bool ShouldCache(EShaderPlatform Platform) + { + return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4); + } + + /** Default constructor. */ + FTranslucencyUpsamplingPS(bool InbUseNearestDepthNeighborUpsample) + : bUseNearestDepthNeighborUpsample(InbUseNearestDepthNeighborUpsample) + { + } + + FShaderParameter LowResColorTexelSize; + FShaderResourceParameter SceneDepthTexture; + FShaderResourceParameter LowResDepthTexture; + FShaderResourceParameter LowResColorTexture; + FShaderResourceParameter BilinearClampedSampler; + FShaderResourceParameter PointClampedSampler; + +public: + + /** Initialization constructor. */ + FTranslucencyUpsamplingPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer, bool InbUseNearestDepthNeighborUpsample) + : FGlobalShader(Initializer) + , bUseNearestDepthNeighborUpsample(InbUseNearestDepthNeighborUpsample) + { + LowResColorTexelSize.Bind(Initializer.ParameterMap, TEXT("LowResColorTexelSize")); + SceneDepthTexture.Bind(Initializer.ParameterMap, TEXT("SceneDepthTexture")); + LowResDepthTexture.Bind(Initializer.ParameterMap, TEXT("LowResDepthTexture")); + LowResColorTexture.Bind(Initializer.ParameterMap, TEXT("LowResColorTexture")); + BilinearClampedSampler.Bind(Initializer.ParameterMap, TEXT("BilinearClampedSampler")); + PointClampedSampler.Bind(Initializer.ParameterMap, TEXT("PointClampedSampler")); + } + + + + + // FShader interface. + virtual bool Serialize(FArchive& Ar) override + { + bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar); + Ar << LowResColorTexelSize << SceneDepthTexture << LowResDepthTexture << LowResColorTexture << BilinearClampedSampler << PointClampedSampler; + return bShaderHasOutdatedParameters; + } + + void SetParameters(FRHICommandList& RHICmdList, const FViewInfo& View) + { + const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader(); + FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View.ViewUniformBuffer); + FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); - bool bRequiresSeperateTranslucencyResolve = false; + TRefCountPtr& DownsampledTranslucency = SceneContext.SeparateTranslucencyRT; - for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) - { - SCOPED_CONDITIONAL_DRAW_EVENTF(RHICmdList, EventView, Views.Num() > 1, TEXT("View%d"), ViewIndex); + float Width = DownsampledTranslucency->GetDesc().Extent.X; + float Height = DownsampledTranslucency->GetDesc().Extent.Y; + SetShaderValue(RHICmdList, ShaderRHI, LowResColorTexelSize, FVector4(Width, Height, 1.0f / Width, 1.0f / Height)); - FViewInfo& View = Views[ViewIndex]; - FDrawingPolicyRenderState DrawRenderState(View); + SetTextureParameter(RHICmdList, ShaderRHI, LowResColorTexture, DownsampledTranslucency->GetRenderTargetItem().ShaderResourceTexture); + SetTextureParameter(RHICmdList, ShaderRHI, LowResDepthTexture, SceneContext.GetDownsampledTranslucencyDepthSurface()); + SetTextureParameter(RHICmdList, ShaderRHI, SceneDepthTexture, SceneContext.GetSceneDepthSurface()); - // non separate translucency - { -#if STATS - if (View.ViewState) - { - View.ViewState->TranslucencyTimer.Begin(RHICmdList); - } -#endif - bool bFirstTimeThisFrame = (ViewIndex == 0); - SetTranslucentRenderTarget(RHICmdList, View, ETranslucencyPass::TPT_StandardTranslucency, bFirstTimeThisFrame); - SetTranslucentState(RHICmdList, DrawRenderState); - - DrawAllTranslucencyPasses(RHICmdList, View, DrawRenderState, ETranslucencyPass::TPT_StandardTranslucency); - - const FSceneViewState* ViewState = (const FSceneViewState*)View.State; - - if (ViewState && View.Family->EngineShowFlags.VisualizeLPV) - { - FLightPropagationVolume* LightPropagationVolume = ViewState->GetLightPropagationVolume(View.GetFeatureLevel()); - - if (LightPropagationVolume) - { - LightPropagationVolume->Visualise(RHICmdList, View); - } - } -#if STATS - if (View.ViewState) - { - View.ViewState->TranslucencyTimer.End(RHICmdList); - } -#endif - } - - // separate translucency - { - if (SceneContext.IsSeparateTranslucencyActive(View)) - { - bRequiresSeperateTranslucencyResolve = true; - - // always call BeginRenderingSeparateTranslucency() even if there are no primitives to we keep the RT allocated - FIntPoint ScaledSize; - float Scale = 1.0f; - SceneContext.GetSeparateTranslucencyDimensions(ScaledSize, Scale); - if (Scale < 1.0f) - { - SceneContext.GetSeparateTranslucencyDepth(RHICmdList, ScaledSize); - DownsampleDepthSurface(RHICmdList, SceneContext.GetSeparateTranslucencyDepthSurface(), View, Scale, false); - - FViewUniformShaderParameters DownsampledTranslucencyParameters = *View.CachedViewUniformShaderParameters; - - // Update the parts of DownsampledTranslucencyParameters which are dependent on the buffer size and view rect - View.SetupViewRectUniformBufferParameters( - DownsampledTranslucencyParameters, - ScaledSize, - FIntRect(View.ViewRect.Min.X * Scale, View.ViewRect.Min.Y * Scale, View.ViewRect.Max.X * Scale, View.ViewRect.Max.Y * Scale), - View.ViewMatrices, - View.PrevViewMatrices - ); - - View.DownsampledTranslucencyViewUniformBuffer = TUniformBufferRef::CreateUniformBufferImmediate(DownsampledTranslucencyParameters, UniformBuffer_SingleFrame); - } - - BeginTimingSeparateTranslucencyPass(RHICmdList, View); - - if (CVarCopySceneColorOncePerViewOnly.GetValueOnRenderThread() != 0) - { - FTranslucencyDrawingPolicyFactory::CopySceneColor(RHICmdList, View, nullptr); - } - - bool bFirstTimeThisFrame = (ViewIndex == 0); - SceneContext.BeginRenderingSeparateTranslucency(RHICmdList, View, bFirstTimeThisFrame); - - const TIndirectArray& WorldList = View.ViewMeshElements; - const TIndirectArray& ForegroundList = View.TopViewMeshElements; - - bool bRenderSeparateTranslucency = View.TranslucentPrimSet.SortedPrimsNum.Num(ETranslucencyPass::TPT_SeparateTranslucency) > 0 || WorldList.Num() || ForegroundList.Num(); - - // Draw only translucent prims that are in the SeparateTranslucency pass - if (bRenderSeparateTranslucency) - { - DrawRenderState.SetDepthStencilState(TStaticDepthStencilState::GetRHI()); - - DrawAllTranslucencyPasses(RHICmdList, View, DrawRenderState, ETranslucencyPass::TPT_SeparateTranslucency); - } - - - EndTimingSeparateTranslucencyPass(RHICmdList, View); - } - } - } - - if (bRequiresSeperateTranslucencyResolve) - { - SceneContext.FinishRenderingSeparateTranslucency(RHICmdList); - } + SetSamplerParameter(RHICmdList, ShaderRHI, BilinearClampedSampler, TStaticSamplerState::GetRHI()); + SetSamplerParameter(RHICmdList, ShaderRHI, PointClampedSampler, TStaticSamplerState::GetRHI()); } + + const bool bUseNearestDepthNeighborUpsample; +}; + +class FTranslucencySimpleUpsamplingPS : public FTranslucencyUpsamplingPS +{ +protected: + DECLARE_SHADER_TYPE(FTranslucencySimpleUpsamplingPS, Global); + FTranslucencySimpleUpsamplingPS() : FTranslucencyUpsamplingPS(false) {} +public: + FTranslucencySimpleUpsamplingPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) : FTranslucencyUpsamplingPS(Initializer, false) {} +}; + +IMPLEMENT_SHADER_TYPE(,FTranslucencySimpleUpsamplingPS,TEXT("TranslucencyUpsampling"),TEXT("SimpleUpsamplingPS"),SF_Pixel); + +class FTranslucencyNearestDepthNeighborUpsamplingPS : public FTranslucencyUpsamplingPS +{ +protected: + DECLARE_SHADER_TYPE(FTranslucencyNearestDepthNeighborUpsamplingPS, Global); + FTranslucencyNearestDepthNeighborUpsamplingPS() : FTranslucencyUpsamplingPS(true) {} +public: + FTranslucencyNearestDepthNeighborUpsamplingPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) : FTranslucencyUpsamplingPS(Initializer, true) {} +}; + +IMPLEMENT_SHADER_TYPE(,FTranslucencyNearestDepthNeighborUpsamplingPS,TEXT("TranslucencyUpsampling"),TEXT("NearestDepthNeighborUpsamplingPS"),SF_Pixel); + +bool UseNearestDepthNeighborUpsampleForSeparateTranslucency(const FSceneRenderTargets& SceneContext) +{ + FIntPoint OutScaledSize; + float OutScale; + SceneContext.GetSeparateTranslucencyDimensions(OutScaledSize, OutScale); + + return CVarSeparateTranslucencyUpsampleMode.GetValueOnRenderThread() != 0 && FMath::Abs(OutScale - .5f) < .001f; } + +void FTranslucencyDrawingPolicyFactory::UpsampleTranslucency(FRHICommandList& RHICmdList, const FViewInfo& View, bool bOverwrite) +{ + SCOPED_DRAW_EVENTF(RHICmdList, EventUpsampleCopy, TEXT("Upsample translucency")); + + FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); + SceneContext.BeginRenderingSceneColor(RHICmdList, ESimpleRenderTargetMode::EExistingColorAndDepth, FExclusiveDepthStencil::DepthRead_StencilWrite); + RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f); + + FGraphicsPipelineStateInitializer GraphicsPSOInit; + RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit); + + GraphicsPSOInit.RasterizerState = TStaticRasterizerState::GetRHI(); + GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState::GetRHI(); + if (bOverwrite) // When overwriting, we also need to set the alpha as other translucent primitive could accumulate into the buffer. + { + GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI(); + } + else + { + GraphicsPSOInit.BlendState = TStaticBlendState::GetRHI(); + } + + TShaderMapRef ScreenVertexShader(View.ShaderMap); + FTranslucencyUpsamplingPS* UpsamplingPixelShader = nullptr; + if (UseNearestDepthNeighborUpsampleForSeparateTranslucency(SceneContext)) + { + TShaderMapRef PixelShader(View.ShaderMap); + UpsamplingPixelShader = *PixelShader; + } + else + { + TShaderMapRef PixelShader(View.ShaderMap); + UpsamplingPixelShader = *PixelShader; + } + + GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI; + GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(*ScreenVertexShader); + GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(UpsamplingPixelShader); + GraphicsPSOInit.PrimitiveType = PT_TriangleList; + + SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit); + UpsamplingPixelShader->SetParameters(RHICmdList, View); + + FIntPoint OutScaledSize; + float OutScale; + SceneContext.GetSeparateTranslucencyDimensions(OutScaledSize, OutScale); + + TRefCountPtr& DownsampledTranslucency = SceneContext.SeparateTranslucencyRT; + int32 TextureWidth = DownsampledTranslucency->GetDesc().Extent.X; + int32 TextureHeight = DownsampledTranslucency->GetDesc().Extent.Y; + + DrawRectangle( + RHICmdList, + View.ViewRect.Min.X, View.ViewRect.Min.Y, + View.ViewRect.Width(), View.ViewRect.Height(), + View.ViewRect.Min.X * OutScale, View.ViewRect.Min.Y * OutScale, + View.ViewRect.Width() * OutScale, View.ViewRect.Height() * OutScale, + View.ViewRect.Size(), + FIntPoint(TextureWidth, TextureHeight), + *ScreenVertexShader, + EDRF_UseTriangleOptimization); +} + + + diff --git a/Engine/Source/Runtime/Renderer/Private/TranslucentRendering.h b/Engine/Source/Runtime/Renderer/Private/TranslucentRendering.h index 2e001e00e099..d7ffc6c90341 100644 --- a/Engine/Source/Runtime/Renderer/Private/TranslucentRendering.h +++ b/Engine/Source/Runtime/Renderer/Private/TranslucentRendering.h @@ -14,6 +14,9 @@ #include "SceneRendering.h" #include "VolumeRendering.h" + +bool UseNearestDepthNeighborUpsampleForSeparateTranslucency(const FSceneRenderTargets& SceneContext); + /** * Translucent draw policy factory. * Creates the policies needed for rendering a mesh based on its material @@ -25,18 +28,19 @@ public: struct ContextType { const FProjectedShadowInfo* TranslucentSelfShadow; - ETranslucencyPass::Type TranslucenyPassType; + ETranslucencyPass::Type TranslucencyPass; ESceneRenderTargetsMode::Type TextureMode; - bool bSceneColorCopyIsUpToDate; bool bPostAA; - ContextType(const FProjectedShadowInfo* InTranslucentSelfShadow = NULL, ETranslucencyPass::Type InTranslucenyPassType = ETranslucencyPass::TPT_StandardTranslucency, bool bPostAAIn = false, ESceneRenderTargetsMode::Type InTextureMode = ESceneRenderTargetsMode::SetTextures) + ContextType(const FProjectedShadowInfo* InTranslucentSelfShadow, ETranslucencyPass::Type InTranslucencyPass, bool bPostAAIn = false, ESceneRenderTargetsMode::Type InTextureMode = ESceneRenderTargetsMode::SetTextures) : TranslucentSelfShadow(InTranslucentSelfShadow) - , TranslucenyPassType(InTranslucenyPassType) + , TranslucencyPass(InTranslucencyPass) , TextureMode(InTextureMode) - , bSceneColorCopyIsUpToDate(false) , bPostAA(bPostAAIn) {} + + /** Whether this material should be processed now */ + bool ShouldDraw(const FViewInfo& View, const FMaterial* Material, bool bIsSeparateTranslucency) const; }; /** @@ -73,7 +77,8 @@ public: /** * Resolves the scene color target and copies it for use as a source texture. */ - static void CopySceneColor(FRHICommandList& RHICmdList, const FViewInfo& View, const FPrimitiveSceneProxy* PrimitiveSceneProxy); + static void CopySceneColor(FRHICommandList& RHICmdList, const FViewInfo& View); + static void UpsampleTranslucency(FRHICommandList& RHICmdList, const FViewInfo& View, bool bOverwrite); private: /** diff --git a/Engine/Source/Runtime/Renderer/Private/VT/TexturePagePool.cpp b/Engine/Source/Runtime/Renderer/Private/VT/TexturePagePool.cpp new file mode 100644 index 000000000000..ad5199e55a52 --- /dev/null +++ b/Engine/Source/Runtime/Renderer/Private/VT/TexturePagePool.cpp @@ -0,0 +1,708 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "TexturePagePool.h" + +#include "VirtualTextureSpace.h" +#include "VirtualTextureSystem.h" + +template< typename IndexType, typename CountType > +void RadixSort32( IndexType* RESTRICT Dst, IndexType* RESTRICT Src, CountType Num ) +{ + CountType Histograms[ 1024 + 2048 + 2048 ]; + CountType* RESTRICT Histogram0 = Histograms + 0; + CountType* RESTRICT Histogram1 = Histogram0 + 1024; + CountType* RESTRICT Histogram2 = Histogram1 + 2048; + + FMemory::Memzero( Histograms, sizeof( Histograms ) ); + + { + // Parallel histogram generation pass + const IndexType* RESTRICT s = (const IndexType* RESTRICT)Src; + for( CountType i = 0; i < Num; i++ ) + { + IndexType j = s[i]; + Histogram0[ ( j >> 0 ) & 1023 ]++; + Histogram1[ ( j >> 10 ) & 2047 ]++; + Histogram2[ ( j >> 21 ) & 2047 ]++; + } + } + { + // Set each histogram entry to the sum of entries preceding it + CountType Sum0 = 0; + CountType Sum1 = 0; + CountType Sum2 = 0; + for( CountType i = 0; i < 1024; i++ ) + { + CountType t; + t = Histogram0[i] + Sum0; Histogram0[i] = Sum0 - 1; Sum0 = t; + t = Histogram1[i] + Sum1; Histogram1[i] = Sum1 - 1; Sum1 = t; + t = Histogram2[i] + Sum2; Histogram2[i] = Sum2 - 1; Sum2 = t; + } + for( CountType i = 1024; i < 2048; i++ ) + { + CountType t; + t = Histogram1[i] + Sum1; Histogram1[i] = Sum1 - 1; Sum1 = t; + t = Histogram2[i] + Sum2; Histogram2[i] = Sum2 - 1; Sum2 = t; + } + } + { + // Sort pass 1 + const IndexType* RESTRICT s = (const IndexType* RESTRICT)Src; + IndexType* RESTRICT d = Dst; + for( CountType i = 0; i < Num; i++ ) + { + IndexType k = s[i]; + d[ ++Histogram0[ ( (k >> 0) & 1023 ) ] ] = k; + } + } + { + // Sort pass 2 + const IndexType* RESTRICT s = (const IndexType* RESTRICT)Dst; + IndexType* RESTRICT d = Src; + for( CountType i = 0; i < Num; i++ ) + { + IndexType k = s[i]; + d[ ++Histogram1[ ( (k >> 10) & 2047 ) ] ] = k; + } + } + { + // Sort pass 3 + const IndexType* RESTRICT s = (const IndexType* RESTRICT)Src; + IndexType* RESTRICT d = Dst; + for( CountType i = 0; i < Num; i++ ) + { + IndexType k = s[i]; + d[ ++Histogram2[ ( (k >> 21) & 2047 ) ] ] = k; + } + } +} + + +FORCEINLINE uint64 EncodeSortKey( uint8 ID, uint8 vLevel, uint32 vAddress, uint16 pAddress ) +{ +#if VT_RADIX_SORT + uint64 Key; + Key = (uint64)vAddress << 0; + Key |= (uint64)vLevel << 24; + Key |= (uint64)ID << 28; + Key |= (uint64)pAddress << 32; + return Key; +#else + uint64 Key; + Key = (uint64)pAddress << 0; + Key |= (uint64)vAddress << 16; + Key |= (uint64)vLevel << 48; + Key |= (uint64)ID << 56; + return Key; +#endif +} + +FORCEINLINE void DecodeSortKey( uint64 Key, uint8& ID, uint8& vLevel, uint32& vAddress, uint16& pAddress ) +{ +#if VT_RADIX_SORT + vAddress = ( Key >> 0 ) & 0xffffff; + vLevel = ( Key >> 24 ) & 0xf; + ID = ( Key >> 28 ) & 0xf; + pAddress = ( Key >> 32 ); +#else + pAddress = ( Key >> 0 ) & 0xffff; + vAddress = ( Key >> 16 ) & 0xffffffff; + vLevel = ( Key >> 48 ) & 0xf; + ID = ( Key >> 56 ); +#endif +} + + +FTexturePagePool::FTexturePagePool( uint32 Size, uint32 Dimensions ) + : vDimensions( Dimensions ) + , HashTable( 2048, Size ) + , FreeHeap( Size, Size ) +{ + Pages.SetNum( Size ); + SortedKeys.Reserve( Size ); + + for( int32 i = 0; i < Pages.Num(); i++ ) + { + FTexturePage& Page = Pages[i]; + + Page.pAddress = i; + Page.vAddress = 0; + Page.vLevel = 0; + Page.ID = 0xff; + + FreeHeap.Add( 0, i ); + } +} + +FTexturePagePool::~FTexturePagePool() +{} + +bool FTexturePagePool::AnyFreeAvailable( uint32 Frame ) const +{ + if( FreeHeap.Num() > 0 ) + { + // Keys include vLevel to help prevent parent before child ordering + uint32 PageIndex = FreeHeap.Top(); + uint32 PageFrame = FreeHeap.GetKey( PageIndex ) >> 4; + return PageFrame != Frame; + } + + return false; +} + +uint32 FTexturePagePool::Alloc( uint32 Frame ) +{ + check( AnyFreeAvailable( Frame ) ); + + uint32 PageIndex = FreeHeap.Top(); + FreeHeap.Pop(); + return PageIndex; +} + +void FTexturePagePool::Free( uint32 Frame, uint32 PageIndex ) +{ + FreeHeap.Add( (Frame << 4) + (Pages[ PageIndex ].vLevel & 0xf), PageIndex ); +} + +void FTexturePagePool::UpdateUsage( uint32 Frame, uint32 PageIndex ) +{ + FreeHeap.Update( (Frame << 4) + (Pages[ PageIndex ].vLevel & 0xf), PageIndex ); +} + + +uint32 FTexturePagePool::FindPage( uint8 ID, uint8 vLevel, uint32 vAddress ) const +{ + uint16 Hash = HashPage( vLevel, vAddress, vDimensions ); + for( uint32 PageIndex = HashTable.First( Hash ); HashTable.IsValid( PageIndex ); PageIndex = HashTable.Next( PageIndex ) ) + { + if( ID == Pages[ PageIndex ].ID && + vLevel == Pages[ PageIndex ].vLevel && + vAddress == Pages[ PageIndex ].vAddress ) + { + return PageIndex; + } + } + + return ~0u; +} + +uint32 FTexturePagePool::FindNearestPage( uint8 ID, uint8 vLevel, uint32 vAddress ) const +{ + while( vLevel < 16 ) + { + uint16 Hash = HashPage( vLevel, vAddress, vDimensions ); + for( uint32 PageIndex = HashTable.First( Hash ); HashTable.IsValid( PageIndex ); PageIndex = HashTable.Next( PageIndex ) ) + { + if( ID == Pages[ PageIndex ].ID && + vLevel == Pages[ PageIndex ].vLevel && + vAddress == Pages[ PageIndex ].vAddress ) + { + return PageIndex; + } + } + + vLevel++; + vAddress &= 0xffffffff << ( vDimensions * vLevel ); + } + + return ~0u; +} + +void FTexturePagePool::UnmapPage( uint16 pAddress ) +{ +#if VT_RADIX_SORT + const uint64 Mask = 0xffffffff; +#else + const uint64 Mask = 0xffffffffffff0000ull; +#endif + + FTexturePage& Page = Pages[ pAddress ]; + + if( Page.ID != 0xff ) + { + // Unmap old page + HashTable.Remove( HashPage( Page.vLevel, Page.vAddress, vDimensions ), Page.pAddress ); + + uint32 Ancestor_pAddress = FindNearestPage( Page.ID, Page.vLevel, Page.vAddress ); + uint8 Ancestor_vLevel = Ancestor_pAddress == ~0u ? 0xff : Pages[ Ancestor_pAddress ].vLevel; + GVirtualTextureSystem.GetSpace( Page.ID )->QueueUpdate( Page.vLevel, Page.vAddress, Ancestor_vLevel, Ancestor_pAddress ); + +#if VT_MERGE_RESORT + uint64 OldKey = EncodeSortKey( Page.ID, Page.vLevel, Page.vAddress, 0 ); + uint32 OldIndex = LowerBound( 0, SortedKeys.Num(), OldKey, Mask ); + SortedSubIndexes.Add( ( OldIndex << 16 ) | Page.pAddress ); +#endif + } + + Page.vLevel = 0; + Page.vAddress = 0; + Page.ID = 0xff; + + SortedKeysDirty = true; +} + +void FTexturePagePool::MapPage( uint8 ID, uint8 vLevel, uint32 vAddress, uint16 pAddress ) +{ +#if VT_RADIX_SORT + const uint64 Mask = 0xffffffff; +#else + const uint64 Mask = 0xffffffffffff0000ull; +#endif + + FTexturePage& Page = Pages[ pAddress ]; + + Page.vLevel = vLevel; + Page.vAddress = vAddress; + Page.ID = ID; + + { +#if VT_MERGE_RESORT + uint64 NewKey = EncodeSortKey( Page.ID, Page.vLevel, Page.vAddress, 0 ); + uint32 NewIndex = UpperBound( 0, SortedKeys.Num(), NewKey, Mask ); + SortedAddIndexes.Add( ( NewIndex << 16 ) | Page.pAddress ); +#endif + + // Map new page + HashTable.Add( HashPage( Page.vLevel, Page.vAddress, vDimensions ), Page.pAddress ); + GVirtualTextureSystem.GetSpace( Page.ID )->QueueUpdate( Page.vLevel, Page.vAddress, Page.vLevel, Page.pAddress ); + } + + SortedKeysDirty = true; +} + +// Must call this before the below functions so that SortedKeys is up to date. +inline void FTexturePagePool::BuildSortedKeys() +{ +#if VT_MERGE_RESORT + checkSlow( SortedSubIndexes.Num() || SortedAddIndexes.Num() ); + + SortedSubIndexes.Sort(); + SortedAddIndexes.Sort( + [this]( const uint32& A, const uint32& B ) + { + const FTexturePage& PageA = Pages[ A & 0xffff ]; + const FTexturePage& PageB = Pages[ B & 0xffff ]; + + uint64 KeyA = EncodeSortKey( PageA.ID, PageA.vLevel, PageA.vAddress, PageA.pAddress ); + uint64 KeyB = EncodeSortKey( PageB.ID, PageB.vLevel, PageB.vAddress, PageB.pAddress ); + + return KeyA < KeyB; + } ); + + // Copy version + Exchange( SortedKeys, UnsortedKeys ); + + uint32 NumUnsorted = UnsortedKeys.Num(); + SortedKeys.SetNum( NumUnsorted + SortedAddIndexes.Num() - SortedSubIndexes.Num(), false ); + + int32 SubI = 0; + int32 AddI = 0; + int32 UnsortedI = 0; + int32 SortedI = 0; + + while( SortedI < SortedKeys.Num() ) + { + const uint32 SubIndex = SubI < SortedSubIndexes.Num() ? ( SortedSubIndexes[ SubI ] >> 16 ) : NumUnsorted; + const uint32 AddIndex = AddI < SortedAddIndexes.Num() ? ( SortedAddIndexes[ AddI ] >> 16 ) : NumUnsorted; + + const uint32 Interval = FMath::Min( SubIndex, AddIndex ) - UnsortedI; + if( Interval ) + { + FMemory::Memcpy( &SortedKeys[ SortedI ], &UnsortedKeys[ UnsortedI ], Interval * sizeof( uint64 ) ); + + UnsortedI += Interval; + SortedI += Interval; + + if( SortedI >= SortedKeys.Num() ) + break; + } + + if( SubIndex < AddIndex ) + { + checkSlow( SubI < SortedSubIndexes.Num() ); + + // Skip hole + UnsortedI++; + SubI++; + } + else + { + checkSlow( AddI < SortedAddIndexes.Num() ); + + // Add new updated page + uint16 pAddress = SortedAddIndexes[ AddI ] & 0xffff; + + FTexturePage& Page = Pages[ pAddress ]; + SortedKeys[ SortedI ] = EncodeSortKey( Page.ID, Page.vLevel, Page.vAddress, Page.pAddress ); + + SortedI++; + AddI++; + } + } + + SortedSubIndexes.Reset(); + SortedAddIndexes.Reset(); + + SortedKeysDirty = false; +#elif VT_RADIX_SORT + UnsortedKeys.Reset(); + + for( auto Page : Pages ) + { + if( Page.ID != 0xff ) + { + UnsortedKeys.Add( EncodeSortKey( Page.ID, Page.vLevel, Page.vAddress, Page.pAddress ) ); + } + } + + SortedKeys.SetNum( UnsortedKeys.Num(), false ); + + RadixSort32( SortedKeys.GetData(), UnsortedKeys.GetData(), (uint16)SortedKeys.Num() ); + SortedKeysDirty = false; +#else + SortedKeys.Reset(); + + for( auto Page : Pages ) + { + if( Page.ID != 0xff ) + { + SortedKeys.Add( EncodeSortKey( Page.ID, Page.vLevel, Page.vAddress, Page.pAddress ) ); + } + } + + Sort( SortedKeys.GetData(), SortedKeys.Num() ); + SortedKeysDirty = false; +#endif +} + +// Binary search lower bound +// Similar to std::lower_bound +// Range [Min,Max) +uint32 FTexturePagePool::LowerBound( uint32 Min, uint32 Max, uint64 SearchKey, uint64 Mask ) const +{ + while( Min != Max ) + { + uint32 Mid = Min + (Max - Min) / 2; + uint64 Key = SortedKeys[ Mid ] & Mask; + + if( SearchKey <= Key ) + Max = Mid; + else + Min = Mid + 1; + } + + return Min; +} + +// Binary search upper bound +// Similar to std::upper_bound +// Range [Min,Max) +uint32 FTexturePagePool::UpperBound( uint32 Min, uint32 Max, uint64 SearchKey, uint64 Mask ) const +{ + while( Min != Max ) + { + uint32 Mid = Min + (Max - Min) / 2; + uint64 Key = SortedKeys[ Mid ] & Mask; + + if( SearchKey < Key ) + Max = Mid; + else + Min = Mid + 1; + } + + return Min; +} + +// Binary search equal range +// Similar to std::equal_range +// Range [Min,Max) +uint32 FTexturePagePool::EqualRange( uint32 Min, uint32 Max, uint64 SearchKey, uint64 Mask ) const +{ + while( Min != Max ) + { + uint32 Mid = Min + (Max - Min) / 2; + uint64 Key = SortedKeys[ Mid ] & Mask; + + if( SearchKey < Key ) + { + Max = Mid; + } + else if( SearchKey > Key ) + { + Min = Mid + 1; + } + else + { // Range straddles Mid. Search both sides and return. + Min = LowerBound( Min, Mid, SearchKey, Mask ); + Max = UpperBound( Mid + 1, Max, SearchKey, Mask ); + return Min | ( Max << 16 ); + } + } + + return 0; +} + +void FTexturePagePool::RefreshEntirePageTable( uint8 ID, TArray< FPageUpdate >* Output ) +{ + if( SortedKeysDirty ) + { + BuildSortedKeys(); + } + + // TODO match ID + + for( int i = SortedKeys.Num() - 1; i >= 0; i-- ) + { + FPageUpdate Update; + uint8 Update_ID; + DecodeSortKey( SortedKeys[i], Update_ID, Update.vLevel, Update.vAddress, Update.pAddress ); + Update.vLogSize = Update.vLevel; + + for( int Mip = Update.vLevel; Mip >= 0; Mip-- ) + { + Output[ Mip ].Add( Update ); + } + } +} + +/* +====================== +Update entry in page table for this page and entries for all of its unmapped descendants. + +If no mapped descendants then this is a single square per mip. +If there are mapped descendants then draw those on top using painters algorithm. +Outputs list of FPageTableUpdate which will be drawn on the GPU to the page table. +====================== +*/ +void FTexturePagePool::ExpandPageTableUpdatePainters( uint8 ID, FPageUpdate Update, TArray< FPageUpdate >* Output ) +{ + if( SortedKeysDirty ) + { + BuildSortedKeys(); + } + + static TArray< FPageUpdate > LoopOutput; + + LoopOutput.Reset(); + + uint8 vLogSize = Update.vLogSize; + uint32 vAddress = Update.vAddress; + + Output[ vLogSize ].Add( Update ); + + // Start with input quad + LoopOutput.Add( Update ); + + uint32 SearchRange = SortedKeys.Num(); + + for( uint32 Mip = vLogSize; Mip > 0; ) + { + Mip--; + uint64 SearchKey = EncodeSortKey( ID, Mip, vAddress, 0 ); +#if VT_RADIX_SORT + uint64 Mask = ( 0xffffffff << ( vDimensions * vLogSize ) ) & 0xffffffff; +#else + uint64 Mask = 0xffffffffffff0000ull << ( vDimensions * vLogSize ); +#endif + + uint32 DescendantRange = EqualRange( 0, SearchRange, SearchKey, Mask ); + if( DescendantRange != 0 ) + { + uint32 DescendantMin = DescendantRange & 0xffff; + uint32 DescendantMax = DescendantRange >> 16; + + // List is sorted by level so lower levels must be earlier in the list than what we found. + SearchRange = DescendantMin; + + for( uint32 DescendantIndex = DescendantMin; DescendantIndex < DescendantMax; DescendantIndex++ ) + { + checkSlow( SearchKey == ( SortedKeys[ DescendantIndex ] & Mask ) ); + + FPageUpdate Descendant; + uint8 Descendant_ID, Descendant_Level; + DecodeSortKey( SortedKeys[ DescendantIndex ], Descendant_ID, Descendant_Level, Descendant.vAddress, Descendant.pAddress ); + + Descendant.vLevel = Mip; + Descendant.vLogSize = Mip; + + checkSlow( Descendant_ID == ID ); + checkSlow( Descendant_Level == Mip ); + + // Mask out low bits + uint32 Ancestor_vAddress = Descendant.vAddress & ( 0xffffffff << ( vDimensions * vLogSize ) ); + checkSlow( Ancestor_vAddress == vAddress ); + + LoopOutput.Add( Descendant ); + } + } + + Output[ Mip ].Append( LoopOutput ); + } +} + +/* +====================== +Update entry in page table for this page and entries for all of its unmapped descendants. + +If no mapped descendants then this is a single square per mip. +If there are mapped descendants then break it up into many squares in quadtree order with holes for any already mapped pages. +Outputs list of FPageTableUpdate which will be drawn on the GPU to the page table. +====================== +*/ +void FTexturePagePool::ExpandPageTableUpdateMasked( uint8 ID, FPageUpdate Update, TArray< FPageUpdate >* Output ) +{ + if( SortedKeysDirty ) + { + BuildSortedKeys(); + } + + static TArray< FPageUpdate > LoopInput; + static TArray< FPageUpdate > LoopOutput; + static TArray< FPageUpdate > Stack; + + LoopInput.Reset(); + LoopOutput.Reset(); + checkSlow( Stack.Num() == 0 ); + + uint8 vLogSize = Update.vLogSize; + uint32 vAddress = Update.vAddress; + + Output[ vLogSize ].Add( Update ); + + // Start with input quad + LoopOutput.Add( Update ); + + uint32 SearchRange = SortedKeys.Num(); + + for( uint32 Mip = vLogSize; Mip > 0; ) + { + Mip--; + uint64 SearchKey = EncodeSortKey( ID, Mip, vAddress, 0 ); +#if VT_RADIX_SORT + uint64 Mask = ( 0xffffffff << ( vDimensions * vLogSize ) ) & 0xffffffff; +#else + uint64 Mask = 0xffffffffffff0000ull << ( vDimensions * vLogSize ); +#endif + + uint32 DescendantRange = EqualRange( 0, SearchRange, SearchKey, Mask ); + if( DescendantRange != 0 ) + { + uint32 DescendantMin = DescendantRange & 0xffff; + uint32 DescendantMax = DescendantRange >> 16; + + // List is sorted by level so lower levels must be earlier in the list than what we found. + SearchRange = DescendantMin; + + // Ping pong input and output + Exchange( LoopInput, LoopOutput ); + LoopOutput.Reset(); + int32 InputIndex = 0; + + Update = LoopInput[ InputIndex++ ]; + + for( uint32 DescendantIndex = DescendantMin; DescendantIndex < DescendantMax; ) + { + checkSlow( SearchKey == ( SortedKeys[ DescendantIndex ] & Mask ) ); + + FPageUpdate Descendant; + uint8 Descendant_ID, Descendant_Level; + DecodeSortKey( SortedKeys[ DescendantIndex ], Descendant_ID, Descendant_Level, Descendant.vAddress, Descendant.pAddress ); + + Descendant.vLevel = Mip; + Descendant.vLogSize = Mip; + + checkSlow( Descendant_ID == ID ); + checkSlow( Descendant_Level == Mip ); + + // Mask out low bits + uint32 Ancestor_vAddress = Descendant.vAddress & ( 0xffffffff << ( vDimensions * vLogSize ) ); + checkSlow( Ancestor_vAddress == vAddress ); + + uint32 UpdateSize = 1 << ( vDimensions * Update.vLogSize ); + uint32 DescendantSize = 1 << ( vDimensions * Descendant.vLogSize ); + + checkSlow( Update.vLogSize >= Mip ); + + Update.Check( vDimensions ); + Descendant.Check( vDimensions ); + + // Find if Update intersects with Descendant + + // Is update past descendant? + if( Update.vAddress > Descendant.vAddress ) + { + checkSlow( Update.vAddress >= Descendant.vAddress + DescendantSize ); + // Move to next descendant + DescendantIndex++; + continue; + } + // Is update quad before descendant quad and doesn't intersect? + else if( Update.vAddress + UpdateSize <= Descendant.vAddress ) + { + // Output this update and fetch next + LoopOutput.Add( Update ); + } + // Does update quad equal descendant quad? + else if( Update.vAddress == Descendant.vAddress && + Update.vLogSize == Descendant.vLogSize ) + { + // Move to next descendant + DescendantIndex++; + // Toss this update and fetch next + } + else + { + checkSlow( Update.vLogSize > Mip ); + + // Update intersects with Descendant but isn't the same size + // Split update into 4 for 2D, 8 for 3D + Update.vLogSize--; + for( uint32 Sibling = (1 << vDimensions) - 1; Sibling > 0; Sibling-- ) + { + Stack.Push( FPageUpdate( Update, Sibling, vDimensions ) ); + } + continue; + } + + // Fetch next update + if( Stack.Num() ) + { + Update = Stack.Pop( false ); + } + else if( InputIndex < LoopInput.Num() ) + { + Update = LoopInput[ InputIndex++ ]; + } + else + { + // No more input + Update.vLogSize = 0xff; + break; + } + } + + // If update was still being worked with add it + if( Update.vLogSize != 0xff ) + { + LoopOutput.Add( Update ); + } + // Add remaining stack to output + while( Stack.Num() ) + { + LoopOutput.Add( Stack.Pop( false ) ); + } + // Add remaining input to output + LoopOutput.Append( LoopInput.GetData() + InputIndex, LoopInput.Num() - InputIndex ); + } + + if( LoopOutput.Num() == 0 ) + { + // Completely masked out by descendants + break; + } + else + { + Output[ Mip ].Append( LoopOutput ); + } + } +} \ No newline at end of file diff --git a/Engine/Source/Runtime/Renderer/Private/VT/TexturePagePool.h b/Engine/Source/Runtime/Renderer/Private/VT/TexturePagePool.h new file mode 100644 index 000000000000..8728d3eeb258 --- /dev/null +++ b/Engine/Source/Runtime/Renderer/Private/VT/TexturePagePool.h @@ -0,0 +1,67 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "VirtualTextureShared.h" +#include "BinaryHeap.h" +#include "HashTable.h" + +#define VT_MERGE_RESORT 1 +#define VT_RADIX_SORT 0 + +// 64k x 64k virtual pages +// 256 x 256 physical pages +struct FTexturePage +{ + // Address is Morton order, relative to mip 0 + uint32 vAddress; + uint16 pAddress; + uint8 vLevel; + uint8 ID; +}; + +class FTexturePagePool +{ +public: + FTexturePagePool( uint32 Size, uint32 Dimensions ); + ~FTexturePagePool(); + + uint32 GetSize() const { return Pages.Num(); } + const FTexturePage& GetPage( uint16 pAddress ) const { return Pages[ pAddress ]; } + + bool AnyFreeAvailable( uint32 Frame ) const; + uint32 Alloc( uint32 Frame ); + void Free( uint32 Frame, uint32 PageIndex ); + void UpdateUsage( uint32 Frame, uint32 PageIndex ); + + uint32 FindPage( uint8 ID, uint8 vLevel, uint32 vAddress ) const; + uint32 FindNearestPage( uint8 ID, uint8 vLevel, uint32 vAddress ) const; + + void UnmapPage( uint16 pAddress ); + void MapPage( uint8 ID, uint8 vLevel, uint32 vAddress, uint16 pAddress ); + + void RefreshEntirePageTable( uint8 ID, TArray< FPageUpdate >* Output ); + void ExpandPageTableUpdatePainters( uint8 ID, FPageUpdate Update, TArray< FPageUpdate >* Output ); + void ExpandPageTableUpdateMasked( uint8 ID, FPageUpdate Update, TArray< FPageUpdate >* Output ); + +private: + void BuildSortedKeys(); + uint32 LowerBound( uint32 Min, uint32 Max, uint64 SearchKey, uint64 Mask ) const; + uint32 UpperBound( uint32 Min, uint32 Max, uint64 SearchKey, uint64 Mask ) const; + uint32 EqualRange( uint32 Min, uint32 Max, uint64 SearchKey, uint64 Mask ) const; + + uint32 vDimensions; + + TArray< FTexturePage > Pages; + + FHashTable HashTable; + FBinaryHeap< uint32, uint16 > FreeHeap; + + TArray< uint64 > UnsortedKeys; + TArray< uint64 > SortedKeys; + bool SortedKeysDirty; + + TArray< uint32 > SortedSubIndexes; + TArray< uint32 > SortedAddIndexes; +}; \ No newline at end of file diff --git a/Engine/Source/Runtime/Renderer/Private/VT/UniquePageList.h b/Engine/Source/Runtime/Renderer/Private/VT/UniquePageList.h new file mode 100644 index 000000000000..cf2356fb3c6c --- /dev/null +++ b/Engine/Source/Runtime/Renderer/Private/VT/UniquePageList.h @@ -0,0 +1,126 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "VirtualTextureShared.h" +#include "HashTable.h" + +// 4k x 4k virtual pages +// 16 IDs +FORCEINLINE uint32 EncodePage( uint32 ID, uint32 vLevel, uint32 vPosition ) +{ + uint32 Page; + Page = vPosition << 0; + Page |= vLevel << 24; + Page |= ID << 28; + return Page; +} + +FORCEINLINE void DecodePage( uint32 Page, uint32& ID, uint32& vLevel, uint32& vPosition ) +{ + vPosition = ( Page >> 0 ) & 0xffffff; + vLevel = ( Page >> 24 ) & 0xf; + ID = ( Page >> 28 ); +} + + +class FUniquePageList +{ +public: + FUniquePageList(); + + void Add( uint32 Page, uint32 Count ); + void ExpandByMips( uint32 NumMips ); + + uint32 GetNum() const { return NumPages; } + uint32 GetPage( uint32 Index ) const { return Pages[ Index ]; } + uint32 GetCount( uint32 Index ) const { return Counts[ Index ]; } + + uint8 NumLevels[16]; + uint8 Dimensions[16]; + +private: + enum + { + HashSize = 1024, + MaxUniquePages = 4096, + }; + + uint32 NumPages; + uint32 Pages[ MaxUniquePages ]; + uint16 Counts[ MaxUniquePages ]; + + TStaticHashTable< HashSize, MaxUniquePages > HashTable; +}; + +FUniquePageList::FUniquePageList() + : NumPages( 0 ) +{} + +void FUniquePageList::Add( uint32 Page, uint32 Count ) +{ + uint32 ID, vLevel, vPosition; + DecodePage( Page, ID, vLevel, vPosition ); + uint32 vDimensions = Dimensions[ ID ]; + + // Search hash table + uint16 Hash = HashPage( vLevel, vPosition, vDimensions ); + uint16 Index; + for( Index = HashTable.First( Hash ); HashTable.IsValid( Index ); Index = HashTable.Next( Index ) ) + { + if( Page == Pages[ Index ] ) + { + break; + } + } + if( !HashTable.IsValid( Index ) ) + { + if( NumPages == MaxUniquePages ) + { + // Ran out of space + return; + } + + // Add page + Index = NumPages++; + HashTable.Add( Hash, Index ); + + Pages[ Index ] = Page; + Counts[ Index ] = 0; + } + + // Add count + Counts[ Index ] += Count; +} + +// Expanding the list by mips gives look ahead and faster time to first data when many high res pages are requested. +void FUniquePageList::ExpandByMips( uint32 NumMips ) +{ + // TODO cache parent page chains + + for( uint32 i = 0, Num = NumPages; i < Num; i++ ) + { + uint64 Page = Pages[i]; + + uint32 ID, vLevel, vPosition; + DecodePage( Page, ID, vLevel, vPosition ); + uint32 vDimensions = Dimensions[ ID ]; + uint32 Count = Counts[i]; + + for( uint32 Mip = 0; Mip < NumMips; Mip++ ) + { + vLevel++; + + if( vLevel >= NumLevels[ ID ] ) + { + break; + } + + // Mask out low bits + vPosition &= 0xffffffff << ( vDimensions * vLevel ); + + Add( EncodePage( ID, vLevel, vPosition ), Count ); + } + } +} \ No newline at end of file diff --git a/Engine/Source/Runtime/Renderer/Private/VT/VirtualTexture.h b/Engine/Source/Runtime/Renderer/Private/VT/VirtualTexture.h new file mode 100644 index 000000000000..f765a5f4611f --- /dev/null +++ b/Engine/Source/Runtime/Renderer/Private/VT/VirtualTexture.h @@ -0,0 +1,29 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "RHI.h" + +class IVirtualTexture +{ +public: + IVirtualTexture( uint32 InSizeX, uint32 InSizeY, uint32 InSizeZ ) + : SizeX( InSizeX ) + , SizeY( InSizeY ) + , SizeZ( InSizeZ ) + {} + + virtual ~IVirtualTexture() = 0; + + // Locates page and returns if page data can be provided at this moment. + virtual bool LocatePageData( uint8 vLevel, uint32 vAddress, void* RESTRICT& Location ) const = 0; + + // Produces and fills in texture data for the page in the physical texture(s). + virtual void ProducePageData( FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, uint8 vLevel, uint32 vAddress, uint16 pAddress, void* RESTRICT Location ) const = 0; + + // Size in pages + uint32 SizeX; + uint32 SizeY; + uint32 SizeZ; +}; diff --git a/Engine/Source/Runtime/Renderer/Private/VT/VirtualTextureAllocator.cpp b/Engine/Source/Runtime/Renderer/Private/VT/VirtualTextureAllocator.cpp new file mode 100644 index 000000000000..de38c7f0f464 --- /dev/null +++ b/Engine/Source/Runtime/Renderer/Private/VT/VirtualTextureAllocator.cpp @@ -0,0 +1,167 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "VirtualTextureAllocator.h" + +#include "VirtualTexture.h" + +FVirtualTextureAllocator::FVirtualTextureAllocator( uint32 Size, uint32 Dimensions ) + : vDimensions( Dimensions ) +{ + uint8 LogSize = FMath::CeilLogTwo( Size ); + + // Start with one empty block + AddressBlocks.Add( FAddressBlock( LogSize ) ); + SortedBlocks.AddUninitialized(); + SortedBlocks[0].vAddress = 0; + SortedBlocks[0].Index = 0; + + // Init free list + FreeList.AddUninitialized( LogSize + 1 ); + for( uint8 i = 0; i < LogSize; i++ ) + { + FreeList[i] = 0xffff; + } + FreeList[ LogSize ] = 0; +} + +// returns SortedIndex +uint32 FVirtualTextureAllocator::Find( uint32 vAddress ) const +{ + uint32 Min = 0; + uint32 Max = SortedBlocks.Num(); + + // Binary search for upper bound + while( Min != Max ) + { + uint32 Mid = Min + (Max - Min) / 2; + uint32 Key = SortedBlocks[ Mid ].vAddress; + + if( vAddress < Key ) + Max = Mid; + else + Min = Mid + 1; + } + + return Min - 1; +} + +IVirtualTexture* FVirtualTextureAllocator::Find( uint32 vAddress, uint32& Local_vAddress ) const +{ + uint32 SortedIndex = Find( vAddress ); + + const FSortedBlock& SortedBlock = SortedBlocks[ SortedIndex ]; + const FAddressBlock& AddressBlock = AddressBlocks[ SortedBlock.Index ]; + checkSlow( SortedBlock.vAddress == AddressBlock.vAddress ); + + uint32 BlockSize = 1 << ( vDimensions * AddressBlock.vLogSize ); + if( vAddress >= AddressBlock.vAddress && + vAddress < AddressBlock.vAddress + BlockSize ) + { + Local_vAddress = vAddress - AddressBlock.vAddress; + // TODO mip bias + return AddressBlock.VT; + } + + return nullptr; +} + +uint32 FVirtualTextureAllocator::Alloc( IVirtualTexture* VT ) +{ + uint32 BlockSize = FMath::Max( VT->SizeX, VT->SizeY ); + uint8 vLogSize = FMath::CeilLogTwo( BlockSize ); + + // Find smallest free that fits + for( int i = vLogSize; i < FreeList.Num(); i++ ) + { + uint16 FreeIndex = FreeList[i]; + if( FreeIndex != 0xffff ) + { + // Found free + FAddressBlock& AllocBlock = AddressBlocks[ FreeIndex ]; + checkSlow( AllocBlock.VT == nullptr ); + checkSlow( AllocBlock.PrevFree == 0xffff ); + + // Remove from free list + FreeList[i] = AllocBlock.NextFree; + if( AllocBlock.NextFree != 0xffff ) + { + AddressBlocks[ AllocBlock.NextFree ].PrevFree = 0xffff; + AllocBlock.NextFree = 0xffff; + } + + AllocBlock.VT = VT; + + // Add to hash table + uint16 Key = reinterpret_cast< UPTRINT >( VT ) / 16; + HashTable.Add( Key, FreeIndex ); + + // Recursive subdivide until the right size + int NumNewBlocks = 0; + while( AllocBlock.vLogSize > vLogSize ) + { + AllocBlock.vLogSize--; + const uint32 NumSiblings = (1 << vDimensions) - 1; + for( uint32 Sibling = NumSiblings; Sibling > 0; Sibling-- ) + { + AddressBlocks.Add( FAddressBlock( AllocBlock, Sibling, vDimensions ) ); + } + NumNewBlocks += NumSiblings; + } + + uint32 SortedIndex = Find( AllocBlock.vAddress ) + 1; + checkSlow( AllocBlock.vAddress == SortedBlocks[ SortedIndex ].vAddress ); + + // Make room for newly added + SortedBlocks.InsertUninitialized( SortedIndex, NumNewBlocks ); + + for( int Block = 0; Block < NumNewBlocks; Block++ ) + { + uint32 Index = AddressBlocks.Num() - NumNewBlocks + Block; + FAddressBlock AddressBlock = AddressBlocks[ Index ]; + + // Place on free list + AddressBlock.NextFree = FreeList[ AddressBlock.vLogSize ]; + AddressBlocks[ AddressBlock.NextFree ].PrevFree = Index; + FreeList[ AddressBlock.vLogSize ] = Index; + + // Add to sorted list + SortedBlocks[ SortedIndex + Block ].vAddress = AddressBlock.vAddress; + SortedBlocks[ SortedIndex + Block ].Index = Index; + } + + return AllocBlock.vAddress; + } + } + + return ~0u; +} + +void FVirtualTextureAllocator::Free( IVirtualTexture* VT ) +{ + // Find block index + uint16 Key = reinterpret_cast< UPTRINT >( VT ) / 16; + uint32 Index; + for( Index = HashTable.First( Key ); HashTable.IsValid( Index ); Index = HashTable.Next( Index ) ) + { + if( AddressBlocks[ Index ].VT == VT ) + { + break; + } + } + if( HashTable.IsValid( Index ) ) + { + FAddressBlock& AddressBlock = AddressBlocks[ Index ]; + checkSlow( AddressBlock.VT == VT ); + checkSlow( AddressBlock.NextFree == 0xffff ); + checkSlow( AddressBlock.PrevFree == 0xffff ); + + AddressBlock.VT = nullptr; + + // TODO merge with sibling free blocks + + // Place on free list + AddressBlock.NextFree = FreeList[ AddressBlock.vLogSize ]; + AddressBlocks[ AddressBlock.NextFree ].PrevFree = Index; + FreeList[ AddressBlock.vLogSize ] = Index; + } +} \ No newline at end of file diff --git a/Engine/Source/Runtime/Renderer/Private/VT/VirtualTextureAllocator.h b/Engine/Source/Runtime/Renderer/Private/VT/VirtualTextureAllocator.h new file mode 100644 index 000000000000..3277fc612e9c --- /dev/null +++ b/Engine/Source/Runtime/Renderer/Private/VT/VirtualTextureAllocator.h @@ -0,0 +1,69 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "VirtualTextureShared.h" +#include "HashTable.h" + +class IVirtualTexture; + +// Allocates virtual memory address space +class FVirtualTextureAllocator +{ +public: + FVirtualTextureAllocator( uint32 Size, uint32 Dimensions ); + ~FVirtualTextureAllocator() {} + + IVirtualTexture* Find( uint32 vAddress, uint32& Local_vAddress ) const; + uint32 Alloc( IVirtualTexture* VT ); + void Free( IVirtualTexture* VT ); + // TODO Realloc + +private: + uint32 Find( uint32 vAddress ) const; + + struct FAddressBlock + { + IVirtualTexture* VT; + uint32 vAddress; + uint16 NextFree; + uint16 PrevFree; + uint8 vLogSize; + uint8 MipBias; + + FAddressBlock() + {} + + FAddressBlock( uint8 LogSize ) + : VT( nullptr ) + , vAddress( 0 ) + , NextFree( 0xffff ) + , PrevFree( 0xffff ) + , vLogSize( LogSize ) + , MipBias( 0 ) + {} + + FAddressBlock( const FAddressBlock& Block, uint32 Offset, uint32 Dimensions ) + : VT( nullptr ) + , vAddress( Block.vAddress + ( Offset << ( Dimensions * Block.vLogSize ) ) ) + , NextFree( 0xffff ) + , PrevFree( 0xffff ) + , vLogSize( Block.vLogSize ) + , MipBias( 0 ) + {} + }; + + struct FSortedBlock + { + uint32 vAddress; + uint16 Index; + }; + + uint32 vDimensions; + + TArray< FAddressBlock > AddressBlocks; + TArray< uint16 > FreeList; + TArray< FSortedBlock > SortedBlocks; + FHashTable HashTable; +}; \ No newline at end of file diff --git a/Engine/Source/Runtime/Renderer/Private/VT/VirtualTextureFeedback.cpp b/Engine/Source/Runtime/Renderer/Private/VT/VirtualTextureFeedback.cpp new file mode 100644 index 000000000000..0361d30ff9e4 --- /dev/null +++ b/Engine/Source/Runtime/Renderer/Private/VT/VirtualTextureFeedback.cpp @@ -0,0 +1,76 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "VirtualTextureFeedback.h" + +#include "ClearQuad.h" + +TGlobalResource< FVirtualTextureFeedback > GVirtualTextureFeedback; + +FVirtualTextureFeedback::FVirtualTextureFeedback() + : Size( 0, 0 ) +{} + +void FVirtualTextureFeedback::InitDynamicRHI() +{} + +void FVirtualTextureFeedback::ReleaseDynamicRHI() +{ + GRenderTargetPool.FreeUnusedResource( FeedbackTextureGPU ); + GRenderTargetPool.FreeUnusedResource( FeedbackTextureCPU ); +} + +void FVirtualTextureFeedback::CreateResourceGPU( FRHICommandListImmediate& RHICmdList, int32 SizeX, int32 SizeY ) +{ + Size = FIntPoint( SizeX, SizeY ); + + FPooledRenderTargetDesc Desc( FPooledRenderTargetDesc::Create2DDesc( Size, PF_R32_UINT, FClearValueBinding::None, TexCreate_None, TexCreate_UAV, false ) ); + GRenderTargetPool.FindFreeElement( RHICmdList, Desc, FeedbackTextureGPU, TEXT("VTFeedbackGPU") ); + + // Clear to default value + const uint32 ClearValue[4] = { ~0u, ~0u, ~0u, ~0u }; + ClearUAV( RHICmdList, FeedbackTextureGPU->GetRenderTargetItem(), ClearValue ); + RHICmdList.TransitionResource( EResourceTransitionAccess::ERWNoBarrier, EResourceTransitionPipeline::EGfxToGfx, FeedbackTextureGPU->GetRenderTargetItem().UAV ); +} + +void FVirtualTextureFeedback::TransferGPUToCPU( FRHICommandListImmediate& RHICmdList ) +{ + RHICmdList.TransitionResource( EResourceTransitionAccess::EReadable, EResourceTransitionPipeline::EGfxToGfx, FeedbackTextureGPU->GetRenderTargetItem().UAV ); + + GRenderTargetPool.VisualizeTexture.SetCheckPoint( RHICmdList, FeedbackTextureGPU ); + + FPooledRenderTargetDesc Desc( FPooledRenderTargetDesc::Create2DDesc( Size, PF_R32_UINT, FClearValueBinding::None, TexCreate_CPUReadback | TexCreate_HideInVisualizeTexture, TexCreate_None, false ) ); + GRenderTargetPool.FindFreeElement( RHICmdList, Desc, FeedbackTextureCPU, TEXT("VTFeedbackCPU") ); + + // Transfer memory GPU -> CPU + RHICmdList.CopyToResolveTarget( FeedbackTextureGPU->GetRenderTargetItem().TargetableTexture, FeedbackTextureCPU->GetRenderTargetItem().ShaderResourceTexture, false, FResolveParams() ); + + GRenderTargetPool.FreeUnusedResource( FeedbackTextureGPU ); +} + +uint32* FVirtualTextureFeedback::Map( FRHICommandListImmediate& RHICmdList, int32& Pitch ) +{ + uint32* FeedbackBuffer = nullptr; + + if( Size.X > 0 && Size.Y > 0 ) + { + uint32 IdleStart = FPlatformTime::Cycles(); + + int32 Temp; + RHICmdList.MapStagingSurface( FeedbackTextureCPU->GetRenderTargetItem().ShaderResourceTexture, *(void**)&FeedbackBuffer, Pitch, Temp ); + + // RHIMapStagingSurface will block until the results are ready (from the previous frame) so we need to consider this RT idle time + GRenderThreadIdle[ERenderThreadIdleTypes::WaitingForGPUQuery] += FPlatformTime::Cycles() - IdleStart; + GRenderThreadNumIdle[ERenderThreadIdleTypes::WaitingForGPUQuery]++; + } + + return FeedbackBuffer; +} + +void FVirtualTextureFeedback::Unmap( FRHICommandListImmediate& RHICmdList ) +{ + check( Size.X > 0 && Size.Y > 0 ); + RHICmdList.UnmapStagingSurface( FeedbackTextureCPU->GetRenderTargetItem().ShaderResourceTexture ); + + GRenderTargetPool.FreeUnusedResource( FeedbackTextureCPU ); + Size = FIntPoint::ZeroValue; +} \ No newline at end of file diff --git a/Engine/Source/Runtime/Renderer/Private/VT/VirtualTextureFeedback.h b/Engine/Source/Runtime/Renderer/Private/VT/VirtualTextureFeedback.h new file mode 100644 index 000000000000..7df7475d9398 --- /dev/null +++ b/Engine/Source/Runtime/Renderer/Private/VT/VirtualTextureFeedback.h @@ -0,0 +1,39 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "RenderTargetPool.h" + +/* +==================================== + Manages GPU and CPU buffers for VT feedback. + Shared for all views, not per view. + + Should use append buffer but that requires RHI ability to copy + a GPU structured buffer to a CPU read only version. +==================================== +*/ +class FVirtualTextureFeedback : public FRenderResource +{ +public: + FVirtualTextureFeedback(); + ~FVirtualTextureFeedback() {} + + // FRenderResource interface + virtual void InitDynamicRHI() override; + virtual void ReleaseDynamicRHI() override; + + void CreateResourceGPU( FRHICommandListImmediate& RHICmdList, int32 SizeX, int32 SizeY ); + void TransferGPUToCPU( FRHICommandListImmediate& RHICmdList ); + + uint32* Map( FRHICommandListImmediate& RHICmdList, int32& Pitch ); + void Unmap( FRHICommandListImmediate& RHICmdList ); + + FIntPoint Size; + + TRefCountPtr< IPooledRenderTarget > FeedbackTextureGPU; + TRefCountPtr< IPooledRenderTarget > FeedbackTextureCPU; +}; + +extern TGlobalResource< FVirtualTextureFeedback > GVirtualTextureFeedback; \ No newline at end of file diff --git a/Engine/Source/Runtime/Renderer/Private/VT/VirtualTextureShared.h b/Engine/Source/Runtime/Renderer/Private/VT/VirtualTextureShared.h new file mode 100644 index 000000000000..2b53fa552af7 --- /dev/null +++ b/Engine/Source/Runtime/Renderer/Private/VT/VirtualTextureShared.h @@ -0,0 +1,38 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" + +FORCEINLINE uint16 HashPage( uint32 vLevel, uint32 vIndex, uint8 vDimensions ) +{ + // Mix level into top 4 bits + return ( vLevel << 6 ) ^ ( vIndex >> ( vDimensions * vLevel ) ); +} + + +struct FPageUpdate +{ + uint32 vAddress; + uint16 pAddress; + uint8 vLevel; + uint8 vLogSize; + + FPageUpdate() + {} + + FPageUpdate( const FPageUpdate& Update, uint32 Offset, uint8 vDimensions ) + : vAddress( Update.vAddress + ( Offset << ( vDimensions * Update.vLogSize ) ) ) + , pAddress( Update.pAddress ) + , vLevel( Update.vLevel ) + , vLogSize( Update.vLogSize ) + {} + + inline void Check( uint8 vDimensions ) + { + uint32 LowBitMask = ( 1 << ( vDimensions * vLogSize ) ) - 1; + checkSlow( (vAddress & LowBitMask) == 0 ); + + checkSlow( vLogSize <= vLevel ); + } +}; \ No newline at end of file diff --git a/Engine/Source/Runtime/Renderer/Private/VT/VirtualTextureSpace.cpp b/Engine/Source/Runtime/Renderer/Private/VT/VirtualTextureSpace.cpp new file mode 100644 index 000000000000..c217c3c7f13f --- /dev/null +++ b/Engine/Source/Runtime/Renderer/Private/VT/VirtualTextureSpace.cpp @@ -0,0 +1,281 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "VirtualTextureSpace.h" + +#include "VirtualTextureSystem.h" +#include "SpriteIndexBuffer.h" +#include "SceneFilterRendering.h" +#include "RenderTargetPool.h" +#include "GlobalShader.h" +#include "PipelineStateCache.h" +#include "HAL/IConsoleManager.h" +#include "SceneUtils.h" + +static TAutoConsoleVariable CVarVTRefreshEntirePageTable( + TEXT("r.VT.RefreshEntirePageTable"), + 0, + TEXT("Refreshes the entire page table texture every frame"), + ECVF_RenderThreadSafe + ); + +static TAutoConsoleVariable CVarVTMaskedPageTableUpdates( + TEXT("r.VT.MaskedPageTableUpdates"), + 1, + TEXT("Masks the page table update quads to reduce pixel fill costs"), + ECVF_RenderThreadSafe + ); + + +FVirtualTextureSpace::FVirtualTextureSpace( uint32 InSize, uint32 InDimensions, FTexturePagePool* InPool ) + : ID( 0xff ) + , Dimensions( InDimensions ) + , Pool( InPool ) + , Allocator( InSize, InDimensions ) +{ + PageTableSize = InSize; + PageTableLevels = FMath::FloorLog2( PageTableSize ) + 1; + + GVirtualTextureSystem.RegisterSpace( this ); +} + +FVirtualTextureSpace::~FVirtualTextureSpace() +{ + GVirtualTextureSystem.UnregisterSpace( this ); +} + +void FVirtualTextureSpace::InitDynamicRHI() +{ + { + // Page Table + FRHICommandListImmediate& RHICmdList = FRHICommandListExecutor::GetImmediateCommandList(); + FPooledRenderTargetDesc Desc( FPooledRenderTargetDesc::Create2DDesc( FIntPoint( PageTableSize, PageTableSize ), PF_R8G8B8A8, FClearValueBinding::None, TexCreate_None, TexCreate_RenderTargetable | TexCreate_ShaderResource, false, PageTableLevels ) ); + GRenderTargetPool.FindFreeElement( RHICmdList, Desc, PageTable, TEXT("PageTable") ); + } + + { + // Worst case scenario of max mip page update when all other pages are perfectly sparse at mip 0. + const uint32 MaxSparseRegions = Pool->GetSize(); + const uint32 SparseRegionSize = PageTableSize / (uint32)FMath::Pow( (float)MaxSparseRegions, 1.0f / Dimensions ); + const uint32 PerRegionMaxExpansion = ( (1 << Dimensions) - 1 ) * FMath::FloorLog2( SparseRegionSize ); + const uint32 MaxExpansionMip0 = PerRegionMaxExpansion * MaxSparseRegions; + const uint32 Mip0Updates = 64; + const uint32 MaxUpdates = MaxExpansionMip0 + (PageTableLevels - 1) + Mip0Updates; + + // Update Buffer + FRHIResourceCreateInfo CreateInfo; + UpdateBuffer = RHICreateStructuredBuffer( sizeof( FPageUpdate ), MaxUpdates * sizeof( FPageUpdate ), BUF_ShaderResource | BUF_Volatile, CreateInfo ); + UpdateBufferSRV = RHICreateShaderResourceView( UpdateBuffer ); + } +} + +void FVirtualTextureSpace::ReleaseDynamicRHI() +{ + GRenderTargetPool.FreeUnusedResource( PageTable ); + + UpdateBuffer.SafeRelease(); + UpdateBufferSRV.SafeRelease(); +} + +void FVirtualTextureSpace::QueueUpdate( uint8 vLogSize, uint32 vAddress, uint8 vLevel, uint16 pAddress ) +{ + FPageUpdate Update; + Update.vAddress = vAddress; + Update.pAddress = pAddress; + Update.vLevel = vLevel; + Update.vLogSize = vLogSize; + Update.Check( Dimensions ); + + PageTableUpdates.Add( Update ); +} + + +TGlobalResource< FSpriteIndexBuffer<8> > GQuadIndexBuffer; + +class FPageTableUpdateVS : public FGlobalShader +{ + DECLARE_SHADER_TYPE(FPageTableUpdateVS,Global); + + FPageTableUpdateVS() {} + +public: + FShaderParameter PageTableSize; + FShaderParameter FirstUpdate; + FShaderParameter NumUpdates; + FShaderResourceParameter UpdateBuffer; + + FPageTableUpdateVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) + : FGlobalShader(Initializer) + { + PageTableSize.Bind( Initializer.ParameterMap, TEXT("PageTableSize") ); + FirstUpdate.Bind( Initializer.ParameterMap, TEXT("FirstUpdate") ); + NumUpdates.Bind( Initializer.ParameterMap, TEXT("NumUpdates") ); + UpdateBuffer.Bind( Initializer.ParameterMap, TEXT("UpdateBuffer") ); + } + + static bool ShouldCache(EShaderPlatform Platform) + { + return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5) && !IsHlslccShaderPlatform(Platform); + } + + virtual bool Serialize( FArchive& Ar ) override + { + bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar); + Ar << PageTableSize; + Ar << FirstUpdate; + Ar << NumUpdates; + Ar << UpdateBuffer; + return bShaderHasOutdatedParameters; + } +}; + +class FPageTableUpdatePS : public FGlobalShader +{ + DECLARE_SHADER_TYPE(FPageTableUpdatePS, Global); + + static bool ShouldCache( EShaderPlatform Platform ) + { + return IsFeatureLevelSupported( Platform, ERHIFeatureLevel::SM5 ) && !IsHlslccShaderPlatform(Platform); + } + + static void ModifyCompilationEnvironment( EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment ) + { + FGlobalShader::ModifyCompilationEnvironment( Platform, OutEnvironment ); + //OutEnvironment.SetRenderTargetOutputFormat( 0, PF_R16_UINT ); + } + + FPageTableUpdatePS() {} + +public: + FPageTableUpdatePS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) + : FGlobalShader(Initializer) + {} +}; + +IMPLEMENT_SHADER_TYPE(, FPageTableUpdateVS, TEXT("PageTableUpdate"), TEXT("PageTableUpdateVS"), SF_Vertex ); +IMPLEMENT_SHADER_TYPE(, FPageTableUpdatePS, TEXT("PageTableUpdate"), TEXT("PageTableUpdatePS"), SF_Pixel ); + + +void FVirtualTextureSpace::ApplyUpdates( FRHICommandList& RHICmdList ) +{ + static TArray< FPageUpdate > ExpandedUpdates[16]; + + if( CVarVTRefreshEntirePageTable.GetValueOnRenderThread() ) + { + Pool->RefreshEntirePageTable( ID, ExpandedUpdates ); + } + else + { + if( PageTableUpdates.Num() == 0 ) + { + GRenderTargetPool.VisualizeTexture.SetCheckPoint( RHICmdList, PageTable ); + return; + } + + for( auto& Update : PageTableUpdates ) + { + if( CVarVTMaskedPageTableUpdates.GetValueOnRenderThread() ) + { + Pool->ExpandPageTableUpdateMasked( ID, Update, ExpandedUpdates ); + } + else + { + Pool->ExpandPageTableUpdatePainters( ID, Update, ExpandedUpdates ); + } + } + } + + PageTableUpdates.Reset(); + + // TODO Expand 3D updates for slices of volume texture + + uint32 TotalNumUpdates = 0; + for( uint32 Mip = 0; Mip < PageTableLevels; Mip++ ) + { + TotalNumUpdates += ExpandedUpdates[ Mip ].Num(); + } + + if( TotalNumUpdates * sizeof( FPageUpdate ) > UpdateBuffer->GetSize() ) + { + // Resize Update Buffer + uint32 MaxUpdates = FMath::RoundUpToPowerOfTwo( TotalNumUpdates ); + + FRHIResourceCreateInfo CreateInfo; + UpdateBuffer = RHICreateStructuredBuffer( sizeof( FPageUpdate ), MaxUpdates * sizeof( FPageUpdate ), BUF_ShaderResource | BUF_Volatile, CreateInfo ); + UpdateBufferSRV = RHICreateShaderResourceView( UpdateBuffer ); + } + + // This flushes the RHI thread! + uint8* Buffer = (uint8*)RHILockStructuredBuffer( UpdateBuffer, 0, TotalNumUpdates * sizeof( FPageUpdate ), RLM_WriteOnly ); + + for( uint32 Mip = 0; Mip < PageTableLevels; Mip++ ) + { + uint32 NumUpdates = ExpandedUpdates[ Mip ].Num(); + if( NumUpdates ) + { + size_t UploadSize = NumUpdates * sizeof( FPageUpdate ); + FMemory::Memcpy( Buffer, ExpandedUpdates[ Mip ].GetData(), UploadSize ); + Buffer += UploadSize; + } + } + + RHIUnlockStructuredBuffer( UpdateBuffer ); + + // Draw + SCOPED_DRAW_EVENT( RHICmdList, PageTableUpdate ); + + auto ShaderMap = GetGlobalShaderMap( GetFeatureLevel() ); + + FSceneRenderTargetItem& PageTableTarget = PageTable->GetRenderTargetItem(); + + uint32 FirstUpdate = 0; + uint32 MipSize = PageTableSize; + for( uint32 Mip = 0; Mip < PageTableLevels; Mip++ ) + { + uint32 NumUpdates = ExpandedUpdates[ Mip ].Num(); + if( NumUpdates ) + { + SetRenderTarget( RHICmdList, PageTableTarget.TargetableTexture, Mip, NULL ); + RHICmdList.SetViewport( 0, 0, 0.0f, MipSize, MipSize, 1.0f ); + + FGraphicsPipelineStateInitializer GraphicsPSOInit; + RHICmdList.ApplyCachedRenderTargets( GraphicsPSOInit ); + + GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI(); + GraphicsPSOInit.RasterizerState = TStaticRasterizerState<>::GetRHI(); + GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState::GetRHI(); + GraphicsPSOInit.PrimitiveType = PT_TriangleList; + + TShaderMapRef< FPageTableUpdateVS > VertexShader( ShaderMap ); + TShaderMapRef< FPageTableUpdatePS > PixelShader( ShaderMap ); + + GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GEmptyVertexDeclaration.VertexDeclarationRHI; + GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(*VertexShader); + GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(*PixelShader); + SetGraphicsPipelineState( RHICmdList, GraphicsPSOInit ); + + { + const FVertexShaderRHIParamRef ShaderRHI = VertexShader->GetVertexShader(); + + SetShaderValue( RHICmdList, ShaderRHI, VertexShader->PageTableSize, PageTableSize ); + SetShaderValue( RHICmdList, ShaderRHI, VertexShader->FirstUpdate, FirstUpdate ); + SetShaderValue( RHICmdList, ShaderRHI, VertexShader->NumUpdates, NumUpdates ); + SetSRVParameter( RHICmdList, ShaderRHI, VertexShader->UpdateBuffer, UpdateBufferSRV ); + } + + // needs to be the same on shader side (faster on NVIDIA and AMD) + uint32 QuadsPerInstance = 8; + + RHICmdList.SetStreamSource( 0, NULL, 0, 0 ); + RHICmdList.DrawIndexedPrimitive( GQuadIndexBuffer.IndexBufferRHI, PT_TriangleList, 0, 0, 32, 0, 2 * QuadsPerInstance, FMath::DivideAndRoundUp( NumUpdates, QuadsPerInstance ) ); + + ExpandedUpdates[ Mip ].Reset(); + } + + FirstUpdate += NumUpdates; + MipSize >>= 1; + } + + RHICmdList.CopyToResolveTarget( PageTableTarget.TargetableTexture, PageTableTarget.ShaderResourceTexture, false, FResolveParams() ); + + GRenderTargetPool.VisualizeTexture.SetCheckPoint( RHICmdList, PageTable ); +} \ No newline at end of file diff --git a/Engine/Source/Runtime/Renderer/Private/VT/VirtualTextureSpace.h b/Engine/Source/Runtime/Renderer/Private/VT/VirtualTextureSpace.h new file mode 100644 index 000000000000..59ba5849e0f9 --- /dev/null +++ b/Engine/Source/Runtime/Renderer/Private/VT/VirtualTextureSpace.h @@ -0,0 +1,43 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "VirtualTextureShared.h" +#include "TexturePagePool.h" +#include "VirtualTextureAllocator.h" +#include "RenderTargetPool.h" + +// Virtual memory address space mapped by a page table texture +class FVirtualTextureSpace : public FRenderResource +{ +public: + FVirtualTextureSpace( uint32 InSize, uint32 InDimensions, FTexturePagePool* InPool ); + ~FVirtualTextureSpace(); + + // FRenderResource interface + virtual void InitDynamicRHI() override; + virtual void ReleaseDynamicRHI() override; + + FRHITexture* GetPageTableTexture() const { return PageTable->GetRenderTargetItem().ShaderResourceTexture; } + + void QueueUpdate( uint8 vLogSize, uint32 vAddress, uint8 vLevel, uint16 pAddress ); + void ApplyUpdates( FRHICommandList& RHICmdList ); + + uint32 ID; + uint32 PageTableSize; + uint32 PageTableLevels; + uint32 Dimensions; + + FTexturePagePool* Pool; + + FVirtualTextureAllocator Allocator; + +private: + TRefCountPtr< IPooledRenderTarget > PageTable; + + TArray< FPageUpdate > PageTableUpdates; + + FStructuredBufferRHIRef UpdateBuffer; + FShaderResourceViewRHIRef UpdateBufferSRV; +}; diff --git a/Engine/Source/Runtime/Renderer/Private/VT/VirtualTextureSystem.cpp b/Engine/Source/Runtime/Renderer/Private/VT/VirtualTextureSystem.cpp new file mode 100644 index 000000000000..009e761e64ce --- /dev/null +++ b/Engine/Source/Runtime/Renderer/Private/VT/VirtualTextureSystem.cpp @@ -0,0 +1,293 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "VirtualTextureSystem.h" + +#include "TexturePagePool.h" +#include "VirtualTextureSpace.h" +#include "VirtualTextureFeedback.h" +#include "VirtualTexture.h" +#include "UniquePageList.h" +#include "Stats/Stats.h" +#include "SceneUtils.h" +#include "HAL/IConsoleManager.h" + +DECLARE_STATS_GROUP( TEXT("Virtual Texturing"), STATGROUP_VirtualTexturing, STATCAT_Advanced ); + +DECLARE_CYCLE_STAT( TEXT("Feedback Analysis"), STAT_FeedbackAnalysis, STATGROUP_VirtualTexturing ); +DECLARE_CYCLE_STAT( TEXT("VirtualTextureSystem Update"), STAT_VirtualTextureSystem_Update, STATGROUP_VirtualTexturing ); +DECLARE_CYCLE_STAT( TEXT("Page Table Updates"), STAT_PageTableUpdates, STATGROUP_VirtualTexturing ); +DECLARE_CYCLE_STAT( TEXT("UniquePageList ExpandByMips"), STAT_UniquePageList_ExpandByMips, STATGROUP_VirtualTexturing ); +DECLARE_CYCLE_STAT( TEXT("UniquePageList Sort"), STAT_UniquePageList_Sort, STATGROUP_VirtualTexturing ); + +DECLARE_DWORD_COUNTER_STAT( TEXT("Num pages visible"), STAT_NumPagesVisible, STATGROUP_VirtualTexturing ); +DECLARE_DWORD_COUNTER_STAT( TEXT("Num page requests"), STAT_NumPageRequests, STATGROUP_VirtualTexturing ); +DECLARE_DWORD_COUNTER_STAT( TEXT("Num page requests resident"), STAT_NumPageRequestsResident, STATGROUP_VirtualTexturing ); +DECLARE_DWORD_COUNTER_STAT( TEXT("Num page requests not resident"), STAT_NumPageRequestsNotResident, STATGROUP_VirtualTexturing ); +DECLARE_DWORD_COUNTER_STAT( TEXT("Num page uploads"), STAT_NumPageUploads, STATGROUP_VirtualTexturing ); + +DECLARE_FLOAT_COUNTER_STAT( TEXT("VT"), STAT_GPU_VT, STATGROUP_GPU ); + + +static TAutoConsoleVariable CVarVTMaxUploadsPerFrame( + TEXT("r.VT.MaxUploadsPerFrame"), + 16, + TEXT("Max number of page uploads per frame"), + ECVF_RenderThreadSafe + ); + +static TAutoConsoleVariable CVarVTNumMipsToExpandRequests( + TEXT("r.VT.NumMipsToExpandRequests"), + 3, + TEXT("Number of mip levels to request in addition to the original request"), + ECVF_RenderThreadSafe + ); + + +IVirtualTexture::~IVirtualTexture() +{} + + +FVirtualTextureSystem GVirtualTextureSystem; + +FVirtualTextureSystem::FVirtualTextureSystem() + : Frame(0) +{ + for( int ID = 0; ID < 16; ID++ ) + { + Spaces[ ID ] = nullptr; + } +} + +FVirtualTextureSystem::~FVirtualTextureSystem() +{} + +void FVirtualTextureSystem::RegisterSpace( FVirtualTextureSpace* Space ) +{ + check( Space ); + + for( int ID = 0; ID < 16; ID++ ) + { + if( Spaces[ ID ] == nullptr ) + { + Spaces[ ID ] = Space; + Space->ID = ID; + return; + } + } + + check(0); +} + +void FVirtualTextureSystem::UnregisterSpace( FVirtualTextureSpace* Space ) +{ + check( Space ); + check( Spaces[ Space->ID ] == Space ); + + Spaces[ Space->ID ] = nullptr; + Space->ID = 0xff; +} + +void FVirtualTextureSystem::FeedbackAnalysis( FUniquePageList* RESTRICT RequestedPageList, const uint32* RESTRICT Buffer, uint32 Width, uint32 Height, uint32 Pitch ) +{ + SCOPE_CYCLE_COUNTER( STAT_FeedbackAnalysis ); + + // Combine simple runs of identical requests + uint32 LastPixel = 0xffffffff; + uint32 LastPage = 0xffffffff; + uint32 LastCount = 0; + + for( uint32 y = 0; y < Height; y++ ) + { + for( uint32 x = 0; x < Width; x++ ) + { + const uint32 Pixel = Buffer[ x + y * Pitch ]; + + if( Pixel == 0xffffffff ) + { + continue; + } + + if( Pixel == LastPixel ) + { + LastCount++; + continue; + } + + // Decode pixel encoding + const uint32 PageX = ( Pixel >> 0 ) & 0xfff; + const uint32 PageY = ( Pixel >> 12 ) & 0xfff; + const uint32 Level = ( Pixel >> 24 ) & 0xf; + const uint32 ID = ( Pixel >> 28 ); + + const uint32 MaxLevel = RequestedPageList->NumLevels[ ID ] - 1; + + uint32 vAddress = FMath::MortonCode2( PageX ) | ( FMath::MortonCode2( PageY ) << 1 ); + uint32 vLevel = FMath::Min( Level, MaxLevel ); + uint32 vDimensions = RequestedPageList->Dimensions[ ID ]; + + // Mask out low bits + vAddress &= 0xffffffff << ( vDimensions * vLevel ); + + uint32 Page = EncodePage( ID, vLevel, vAddress ); + if( Page == LastPage ) + { + LastCount++; + continue; + } + + if( LastPage != 0xffffffff ) + { + RequestedPageList->Add( LastPage, LastCount ); + } + + LastPixel = Pixel; + LastPage = Page; + LastCount = 1; + } + } + + if( LastPage != 0xffffffff ) + { + RequestedPageList->Add( LastPage, LastCount ); + } +} + +void FVirtualTextureSystem::Update( FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel ) +{ + SCOPE_CYCLE_COUNTER( STAT_VirtualTextureSystem_Update ); + SCOPED_GPU_STAT( RHICmdList, STAT_GPU_VT ); + + FMemMark Mark( FMemStack::Get() ); + FUniquePageList* RESTRICT RequestedPageList = new(FMemStack::Get()) FUniquePageList; + + // Cache to avoid indirection + for( uint32 ID = 0; ID < 16; ID++ ) + { + FVirtualTextureSpace* RESTRICT Space = Spaces[ ID ]; + + RequestedPageList->NumLevels[ ID ] = Space ? Space->PageTableLevels : 16; + RequestedPageList->Dimensions[ ID ] = Space ? Space->Dimensions : 2; + } + + int32 Pitch = 0; + const uint32* RESTRICT Buffer = GVirtualTextureFeedback.Map( RHICmdList, Pitch ); + if( Buffer ) + { + FeedbackAnalysis( RequestedPageList, Buffer, GVirtualTextureFeedback.Size.X, GVirtualTextureFeedback.Size.Y, Pitch ); + GVirtualTextureFeedback.Unmap( RHICmdList ); + } + + SET_DWORD_STAT( STAT_NumPagesVisible, RequestedPageList->GetNum() ); + + // Can add other sources of pages to RequestedPageList here + + { + SCOPE_CYCLE_COUNTER( STAT_UniquePageList_ExpandByMips ); + RequestedPageList->ExpandByMips( CVarVTNumMipsToExpandRequests.GetValueOnRenderThread() ); + } + + SET_DWORD_STAT( STAT_NumPageRequests, RequestedPageList->GetNum() ); + + // Static to avoid malloc cost + static FBinaryHeap< uint32, uint16 > RequestHeap; + RequestHeap.Clear(); + + { + // Find resident + + for( uint32 i = 0, Num = RequestedPageList->GetNum(); i < Num; i++ ) + { + const uint64 PageEncoded = RequestedPageList->GetPage(i); + + // Decode page + uint32 ID, vLevel, vAddress; + DecodePage( (uint32)PageEncoded, ID, vLevel, vAddress ); + + FVirtualTextureSpace* RESTRICT Space = Spaces[ ID ]; checkSlow( Space ); + FTexturePagePool* RESTRICT Pool = Space->Pool; + + // Is this page already resident? + uint32 pAddress = Pool->FindPage( ID, vLevel, vAddress ); + if( pAddress == ~0u ) + { + // Page isn't resident. Start searching at parent level for nearest ancestor. + uint32 Parent_vLevel = vLevel + 1; + uint32 Parent_vAddress = vAddress & ( 0xffffffff << ( Space->Dimensions * Parent_vLevel ) ); + + uint32 Ancestor_pAddress = Pool->FindNearestPage( ID, Parent_vLevel, Parent_vAddress ); + uint32 Ancestor_vLevel = Ancestor_pAddress != ~0u ? Pool->GetPage( Ancestor_pAddress ).vLevel : Space->PageTableLevels - 1; + + uint32 Count = RequestedPageList->GetCount(i); + uint32 Priority = Count * ( 1 << ( Ancestor_vLevel - vLevel ) ); + + RequestHeap.Add( ~Priority, i ); + } + else + { + Pool->UpdateUsage( Frame, pAddress ); + + //FileCache->Touch( VT->FileName, PageOffset, PageSize, priority ); + } + } + + SET_DWORD_STAT( STAT_NumPageRequestsResident, RequestedPageList->GetNum() - RequestHeap.Num() ); + SET_DWORD_STAT( STAT_NumPageRequestsNotResident, RequestHeap.Num() ); + } + + // Limit the number of uploads + // Are all pages equal? Should there be different limits on different types of pages? + int32 NumUploadsLeft = CVarVTMaxUploadsPerFrame.GetValueOnRenderThread(); + + while( RequestHeap.Num() > 0 && NumUploadsLeft > 0 ) + { + uint32 PageIndex = RequestHeap.Top(); + RequestHeap.Pop(); + + const uint64 PageEncoded = RequestedPageList->GetPage( PageIndex ); + + // Decode page + uint32 ID, vLevel, vAddress; + DecodePage( (uint32)PageEncoded, ID, vLevel, vAddress ); + + FVirtualTextureSpace* RESTRICT Space = Spaces[ ID ]; checkSlow( Space ); + FTexturePagePool* RESTRICT Pool = Space->Pool; + + // Find specific VT in Space + uint32 Local_vAddress = 0; + IVirtualTexture* RESTRICT VT = Space->Allocator.Find( vAddress, Local_vAddress ); + + void* RESTRICT Location = nullptr; + bool bPageDataAvailable = VT->LocatePageData( vLevel, Local_vAddress, Location ); + + // FIXME ExpandByMips might not provide a valid page for this to fall back on + + if( bPageDataAvailable && Pool->AnyFreeAvailable( Frame ) ) + { + uint32 pAddress = Pool->Alloc( Frame ); + check( pAddress != ~0u ); + + Pool->UnmapPage( pAddress ); + + VT->ProducePageData( RHICmdList, FeatureLevel, vLevel, Local_vAddress, pAddress, Location ); + + Pool->MapPage( ID, vLevel, vAddress, pAddress ); + Pool->Free( Frame, pAddress ); + + NumUploadsLeft--; + INC_DWORD_STAT( STAT_NumPageUploads ); + } + } + + SCOPE_CYCLE_COUNTER( STAT_PageTableUpdates ); + + // Update page tables + for( uint32 ID = 0; ID < 16; ID++ ) + { + if( Spaces[ ID ] ) + { + Spaces[ ID ]->ApplyUpdates( RHICmdList ); + } + } + + Frame++; +} \ No newline at end of file diff --git a/Engine/Source/Runtime/Renderer/Private/VT/VirtualTextureSystem.h b/Engine/Source/Runtime/Renderer/Private/VT/VirtualTextureSystem.h new file mode 100644 index 000000000000..78b286dc5fc0 --- /dev/null +++ b/Engine/Source/Runtime/Renderer/Private/VT/VirtualTextureSystem.h @@ -0,0 +1,32 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "RHI.h" + +class FVirtualTextureSpace; +class FUniquePageList; + +class FVirtualTextureSystem +{ +public: + FVirtualTextureSystem(); + ~FVirtualTextureSystem(); + + void Update( FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel ); + + void RegisterSpace( FVirtualTextureSpace* Space ); + void UnregisterSpace( FVirtualTextureSpace* Space ); + + FVirtualTextureSpace* GetSpace( uint8 ID ) { return Spaces[ ID ]; } + +private: + void FeedbackAnalysis( FUniquePageList* RESTRICT RequestedPageList, const uint32* RESTRICT Buffer, uint32 Width, uint32 Height, uint32 Pitch ); + + uint32 Frame; + + FVirtualTextureSpace* Spaces[16]; +}; + +extern FVirtualTextureSystem GVirtualTextureSystem; \ No newline at end of file diff --git a/Engine/Source/Runtime/Renderer/Private/VelocityRendering.cpp b/Engine/Source/Runtime/Renderer/Private/VelocityRendering.cpp index 5484bcafe422..7fcc5e282c3e 100644 --- a/Engine/Source/Runtime/Renderer/Private/VelocityRendering.cpp +++ b/Engine/Source/Runtime/Renderer/Private/VelocityRendering.cpp @@ -608,7 +608,6 @@ bool IsMotionBlurEnabled(const FViewInfo& View) && View.FinalPostProcessSettings.MotionBlurMax > 0.001f && View.Family->bRealtimeUpdate && MotionBlurQuality > 0 - && !View.bIsSceneCapture && (CVarAllowMotionBlurInVR->GetInt() != 0 || !(View.Family->Views.Num() > 1)); } diff --git a/Engine/Source/Runtime/Renderer/Private/VolumetricFog.cpp b/Engine/Source/Runtime/Renderer/Private/VolumetricFog.cpp index b319b9127f44..974d13b0640e 100644 --- a/Engine/Source/Runtime/Renderer/Private/VolumetricFog.cpp +++ b/Engine/Source/Runtime/Renderer/Private/VolumetricFog.cpp @@ -70,7 +70,7 @@ int32 GVolumetricFogJitter = 1; FAutoConsoleVariableRef CVarVolumetricFogJitter( TEXT("r.VolumetricFog.Jitter"), GVolumetricFogJitter, - TEXT(""), + TEXT("Whether to apply jitter to each frame's volumetric fog computation, achieving temporal super sampling."), ECVF_Scalability | ECVF_RenderThreadSafe ); @@ -78,7 +78,16 @@ float GVolumetricFogHistoryWeight = .9f; FAutoConsoleVariableRef CVarVolumetricFogHistoryWeight( TEXT("r.VolumetricFog.HistoryWeight"), GVolumetricFogHistoryWeight, - TEXT(""), + TEXT("How much the history value should be weighted each frame. This is a tradeoff between visible jittering and responsiveness."), + ECVF_Scalability | ECVF_RenderThreadSafe + ); + +int32 GVolumetricFogHistoryMissSupersampleCount = 4; +FAutoConsoleVariableRef CVarVolumetricFogHistoryMissSupersampleCount( + TEXT("r.VolumetricFog.HistoryMissSupersampleCount"), + GVolumetricFogHistoryMissSupersampleCount, + TEXT("Number of lighting samples to compute for voxels whose history value is not available.\n") + TEXT("This reduces noise when panning or on camera cuts, but introduces a variable cost to volumetric fog computation. Valid range [1, 16]."), ECVF_Scalability | ECVF_RenderThreadSafe ); @@ -147,6 +156,7 @@ public: VolumetricFogParameters.Bind(Initializer.ParameterMap); HeightFogParameters.Bind(Initializer.ParameterMap); GlobalAlbedo.Bind(Initializer.ParameterMap, TEXT("GlobalAlbedo")); + GlobalEmissive.Bind(Initializer.ParameterMap, TEXT("GlobalEmissive")); GlobalExtinctionScale.Bind(Initializer.ParameterMap, TEXT("GlobalExtinctionScale")); } @@ -157,15 +167,15 @@ public: void SetParameters( FRHICommandList& RHICmdList, const FViewInfo& View, - const FExponentialHeightFogSceneInfo& FogInfo, - IPooledRenderTarget* VBufferA, - IPooledRenderTarget* VBufferB) + const FVolumetricFogIntegrationParameterData& IntegrationData, + const FExponentialHeightFogSceneInfo& FogInfo) { FComputeShaderRHIParamRef ShaderRHI = GetComputeShader(); FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View.ViewUniformBuffer); - VolumetricFogParameters.Set(RHICmdList, ShaderRHI, View, VBufferA, VBufferB, NULL); + VolumetricFogParameters.Set(RHICmdList, ShaderRHI, View, IntegrationData); HeightFogParameters.Set(RHICmdList, ShaderRHI, &View); SetShaderValue(RHICmdList, ShaderRHI, GlobalAlbedo, FogInfo.VolumetricFogAlbedo); + SetShaderValue(RHICmdList, ShaderRHI, GlobalEmissive, FogInfo.VolumetricFogEmissive); SetShaderValue(RHICmdList, ShaderRHI, GlobalExtinctionScale, FogInfo.VolumetricFogExtinctionScale); } @@ -183,6 +193,7 @@ public: Ar << VolumetricFogParameters; Ar << HeightFogParameters; Ar << GlobalAlbedo; + Ar << GlobalEmissive; Ar << GlobalExtinctionScale; return bShaderHasOutdatedParameters; } @@ -192,6 +203,7 @@ private: FVolumetricFogIntegrationParameters VolumetricFogParameters; FExponentialHeightFogShaderParameters HeightFogParameters; FShaderParameter GlobalAlbedo; + FShaderParameter GlobalEmissive; FShaderParameter GlobalExtinctionScale; }; @@ -212,6 +224,7 @@ public: { FGlobalShader::ModifyCompilationEnvironment(Platform, OutEnvironment); OutEnvironment.CompilerFlags.Add(CFLAG_VertexToGeometryShader); + FVolumetricFogIntegrationParameters::ModifyCompilationEnvironment(Platform, OutEnvironment); } FWriteToBoundingSphereVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer): @@ -225,7 +238,7 @@ public: FWriteToBoundingSphereVS() {} - void SetParameters(FRHICommandList& RHICmdList, const FViewInfo& View, const FSphere& BoundingSphere, int32 MinZValue) + void SetParameters(FRHICommandList& RHICmdList, const FViewInfo& View, const FVolumetricFogIntegrationParameterData& IntegrationData, const FSphere& BoundingSphere, int32 MinZValue) { SetShaderValue(RHICmdList, GetVertexShader(), MinZ, MinZValue); @@ -235,7 +248,7 @@ public: const FMatrix ProjectionMatrix = View.ViewMatrices.ComputeProjectionNoAAMatrix(); SetShaderValue(RHICmdList, GetVertexShader(), ViewToVolumeClip, ProjectionMatrix); - VolumetricFogParameters.Set(RHICmdList, GetVertexShader(), View, NULL, NULL, NULL); + VolumetricFogParameters.Set(RHICmdList, GetVertexShader(), View, IntegrationData); } virtual bool Serialize(FArchive& Ar) override @@ -258,7 +271,7 @@ private: IMPLEMENT_SHADER_TYPE(,FWriteToBoundingSphereVS,TEXT("VolumetricFog"),TEXT("WriteToBoundingSphereVS"),SF_Vertex); /** Shader that adds direct lighting contribution from the given light to the current volume lighting cascade. */ -template +template class TInjectShadowedLocalLightPS : public FGlobalShader { DECLARE_SHADER_TYPE(TInjectShadowedLocalLightPS,Global); @@ -269,6 +282,8 @@ public: FGlobalShader::ModifyCompilationEnvironment(Platform, OutEnvironment); OutEnvironment.SetDefine(TEXT("DYNAMICALLY_SHADOWED"), (uint32)bDynamicallyShadowed); OutEnvironment.SetDefine(TEXT("INVERSE_SQUARED_FALLOFF"), (uint32)bInverseSquared); + OutEnvironment.SetDefine(TEXT("USE_TEMPORAL_REPROJECTION"), bTemporalReprojection); + FVolumetricFogIntegrationParameters::ModifyCompilationEnvironment(Platform, OutEnvironment); } static bool ShouldCache(EShaderPlatform Platform) @@ -292,6 +307,7 @@ public: void SetParameters( FRHICommandList& RHICmdList, const FViewInfo& View, + const FVolumetricFogIntegrationParameterData& IntegrationData, const FLightSceneInfo* LightSceneInfo, const FExponentialHeightFogSceneInfo& FogInfo, const FProjectedShadowInfo* ShadowMap) @@ -302,7 +318,7 @@ public: SetDeferredLightParameters(RHICmdList, ShaderRHI, GetUniformBufferParameter(), LightSceneInfo, View); - VolumetricFogParameters.Set(RHICmdList, ShaderRHI, View, NULL, NULL, NULL); + VolumetricFogParameters.Set(RHICmdList, ShaderRHI, View, IntegrationData); SetShaderValue(RHICmdList, ShaderRHI, PhaseG, FogInfo.VolumetricFogScatteringDistribution); SetShaderValue(RHICmdList, ShaderRHI, InverseSquaredLightDistanceBiasScale, GInverseSquaredLightDistanceBiasScale); @@ -327,14 +343,18 @@ private: FVolumeShadowingParameters VolumeShadowingParameters; }; -#define IMPLEMENT_LOCAL_LIGHT_INJECTION_PIXELSHADER_TYPE(bDynamicallyShadowed,bInverseSquared) \ - typedef TInjectShadowedLocalLightPS TInjectShadowedLocalLightPS##bDynamicallyShadowed##bInverseSquared; \ - IMPLEMENT_SHADER_TYPE(template<>,TInjectShadowedLocalLightPS##bDynamicallyShadowed##bInverseSquared,TEXT("VolumetricFog"),TEXT("InjectShadowedLocalLightPS"),SF_Pixel); +#define IMPLEMENT_LOCAL_LIGHT_INJECTION_PIXELSHADER_TYPE(bDynamicallyShadowed,bInverseSquared,bTemporalReprojection) \ + typedef TInjectShadowedLocalLightPS TInjectShadowedLocalLightPS##bDynamicallyShadowed##bInverseSquared##bTemporalReprojection; \ + IMPLEMENT_SHADER_TYPE(template<>,TInjectShadowedLocalLightPS##bDynamicallyShadowed##bInverseSquared##bTemporalReprojection,TEXT("VolumetricFog"),TEXT("InjectShadowedLocalLightPS"),SF_Pixel); -IMPLEMENT_LOCAL_LIGHT_INJECTION_PIXELSHADER_TYPE(true, true); -IMPLEMENT_LOCAL_LIGHT_INJECTION_PIXELSHADER_TYPE(true, false); -IMPLEMENT_LOCAL_LIGHT_INJECTION_PIXELSHADER_TYPE(false, true); -IMPLEMENT_LOCAL_LIGHT_INJECTION_PIXELSHADER_TYPE(false, false); +IMPLEMENT_LOCAL_LIGHT_INJECTION_PIXELSHADER_TYPE(true, true, true); +IMPLEMENT_LOCAL_LIGHT_INJECTION_PIXELSHADER_TYPE(true, false, true); +IMPLEMENT_LOCAL_LIGHT_INJECTION_PIXELSHADER_TYPE(false, true, true); +IMPLEMENT_LOCAL_LIGHT_INJECTION_PIXELSHADER_TYPE(false, false, true); +IMPLEMENT_LOCAL_LIGHT_INJECTION_PIXELSHADER_TYPE(true, true, false); +IMPLEMENT_LOCAL_LIGHT_INJECTION_PIXELSHADER_TYPE(true, false, false); +IMPLEMENT_LOCAL_LIGHT_INJECTION_PIXELSHADER_TYPE(false, true, false); +IMPLEMENT_LOCAL_LIGHT_INJECTION_PIXELSHADER_TYPE(false, false, false); FProjectedShadowInfo* GetShadowForInjectionIntoVolumetricFog(const FLightSceneProxy* LightProxy, FVisibleLightInfo& VisibleLightInfo) { @@ -387,10 +407,11 @@ FIntPoint CalculateVolumetricFogBoundsForLight(const FSphere& LightBounds, const return VolumeZBounds; } -template +template void SetInjectShadowedLocalLightShaders( FRHICommandList& RHICmdList, const FViewInfo& View, + const FVolumetricFogIntegrationParameterData& IntegrationData, const FLightSceneInfo* LightSceneInfo, const FSphere& LightBounds, const FExponentialHeightFogSceneInfo& FogInfo, @@ -400,7 +421,7 @@ void SetInjectShadowedLocalLightShaders( { TShaderMapRef VertexShader(View.ShaderMap); TOptionalShaderMapRef GeometryShader(View.ShaderMap); - TShaderMapRef> PixelShader(View.ShaderMap); + TShaderMapRef> PixelShader(View.ShaderMap); FGraphicsPipelineStateInitializer GraphicsPSOInit; RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit); @@ -413,12 +434,12 @@ void SetInjectShadowedLocalLightShaders( GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(*VertexShader); GraphicsPSOInit.BoundShaderState.GeometryShaderRHI = GETSAFERHISHADER_GEOMETRY(*GeometryShader); GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(*PixelShader); - GraphicsPSOInit.PrimitiveType = PT_TriangleStrip; + GraphicsPSOInit.PrimitiveType = PT_TriangleList; SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit); - PixelShader->SetParameters(RHICmdList, View, LightSceneInfo, FogInfo, ProjectedShadowInfo); - VertexShader->SetParameters(RHICmdList, View, LightBounds, MinZ); + PixelShader->SetParameters(RHICmdList, View, IntegrationData, LightSceneInfo, FogInfo, ProjectedShadowInfo); + VertexShader->SetParameters(RHICmdList, View, IntegrationData, LightBounds, MinZ); if (GeometryShader.IsValid()) { @@ -426,11 +447,81 @@ void SetInjectShadowedLocalLightShaders( } } +/** */ +class FCircleRasterizeVertexBuffer : public FVertexBuffer +{ +public: + + virtual void InitRHI() override + { + const int32 NumTriangles = NumVertices - 2; + const uint32 Size = NumVertices * sizeof(FScreenVertex); + FRHIResourceCreateInfo CreateInfo; + void* Buffer = nullptr; + VertexBufferRHI = RHICreateAndLockVertexBuffer(Size, BUF_Static, CreateInfo, Buffer); + FScreenVertex* DestVertex = (FScreenVertex*)Buffer; + + const int32 NumRings = NumVertices; + const float RadiansPerRingSegment = PI / (float)NumRings; + + // Boost the effective radius so that the edges of the circle approximation lie on the circle, instead of the vertices + const float RadiusScale = 1.0f / FMath::Cos(RadiansPerRingSegment); + + for (int32 VertexIndex = 0; VertexIndex < NumVertices; VertexIndex++) + { + float Angle = VertexIndex / (float)(NumVertices - 1) * 2 * PI; + // WriteToBoundingSphereVS only uses UV + DestVertex[VertexIndex].Position = FVector2D(0, 0); + DestVertex[VertexIndex].UV = FVector2D(RadiusScale * FMath::Cos(Angle) * .5f + .5f, RadiusScale * FMath::Sin(Angle) * .5f + .5f); + } + + RHIUnlockVertexBuffer(VertexBufferRHI); + } + + static int32 NumVertices; +}; + +int32 FCircleRasterizeVertexBuffer::NumVertices = 8; + +TGlobalResource GCircleRasterizeVertexBuffer; + +/** */ +class FCircleRasterizeIndexBuffer : public FIndexBuffer +{ +public: + + virtual void InitRHI() override + { + const int32 NumTriangles = FCircleRasterizeVertexBuffer::NumVertices - 2; + + TResourceArray Indices; + Indices.Empty(NumTriangles * 3); + + for (int32 TriangleIndex = 0; TriangleIndex < NumTriangles; TriangleIndex++) + { + int32 LeadingVertexIndex = TriangleIndex + 2; + Indices.Add(0); + Indices.Add(LeadingVertexIndex - 1); + Indices.Add(LeadingVertexIndex); + } + + const uint32 Size = Indices.GetResourceDataSize(); + const uint32 Stride = sizeof(uint16); + + // Create index buffer. Fill buffer with initial data upon creation + FRHIResourceCreateInfo CreateInfo(&Indices); + IndexBufferRHI = RHICreateIndexBuffer(Stride, Size, BUF_Static, CreateInfo); + } +}; + +TGlobalResource GCircleRasterizeIndexBuffer; + void FDeferredShadingSceneRenderer::RenderLocalLightsForVolumetricFog( FRHICommandListImmediate& RHICmdList, FViewInfo& View, + bool bUseTemporalReprojection, + const FVolumetricFogIntegrationParameterData& IntegrationData, const FExponentialHeightFogSceneInfo& FogInfo, - IPooledRenderTarget* VBufferA, FIntVector VolumetricFogGridSize, FVector GridZParams, const FPooledRenderTargetDesc& VolumeDesc, @@ -479,33 +570,61 @@ void FDeferredShadingSceneRenderer::RenderLocalLightsForVolumetricFog( if (VolumeZBounds.X < VolumeZBounds.Y) { + if (bUseTemporalReprojection) + { + if (bDynamicallyShadowed) + { + if (bInverseSquared) + { + SetInjectShadowedLocalLightShaders(RHICmdList, View, IntegrationData, LightSceneInfo, LightBounds, FogInfo, ProjectedShadowInfo, VolumetricFogGridSize, VolumeZBounds.X); + } + else + { + SetInjectShadowedLocalLightShaders(RHICmdList, View, IntegrationData, LightSceneInfo, LightBounds, FogInfo, ProjectedShadowInfo, VolumetricFogGridSize, VolumeZBounds.X); + } + } + else + { + if (bInverseSquared) + { + SetInjectShadowedLocalLightShaders(RHICmdList, View, IntegrationData, LightSceneInfo, LightBounds, FogInfo, ProjectedShadowInfo, VolumetricFogGridSize, VolumeZBounds.X); + } + else + { + SetInjectShadowedLocalLightShaders(RHICmdList, View, IntegrationData, LightSceneInfo, LightBounds, FogInfo, ProjectedShadowInfo, VolumetricFogGridSize, VolumeZBounds.X); + } + } + } + else + { if (bDynamicallyShadowed) { if (bInverseSquared) { - SetInjectShadowedLocalLightShaders(RHICmdList, View, LightSceneInfo, LightBounds, FogInfo, ProjectedShadowInfo, VolumetricFogGridSize, VolumeZBounds.X); + SetInjectShadowedLocalLightShaders(RHICmdList, View, IntegrationData, LightSceneInfo, LightBounds, FogInfo, ProjectedShadowInfo, VolumetricFogGridSize, VolumeZBounds.X); } else { - SetInjectShadowedLocalLightShaders(RHICmdList, View, LightSceneInfo, LightBounds, FogInfo, ProjectedShadowInfo, VolumetricFogGridSize, VolumeZBounds.X); + SetInjectShadowedLocalLightShaders(RHICmdList, View, IntegrationData, LightSceneInfo, LightBounds, FogInfo, ProjectedShadowInfo, VolumetricFogGridSize, VolumeZBounds.X); } } else { if (bInverseSquared) { - SetInjectShadowedLocalLightShaders(RHICmdList, View, LightSceneInfo, LightBounds, FogInfo, ProjectedShadowInfo, VolumetricFogGridSize, VolumeZBounds.X); + SetInjectShadowedLocalLightShaders(RHICmdList, View, IntegrationData, LightSceneInfo, LightBounds, FogInfo, ProjectedShadowInfo, VolumetricFogGridSize, VolumeZBounds.X); } else { - SetInjectShadowedLocalLightShaders(RHICmdList, View, LightSceneInfo, LightBounds, FogInfo, ProjectedShadowInfo, VolumetricFogGridSize, VolumeZBounds.X); + SetInjectShadowedLocalLightShaders(RHICmdList, View, IntegrationData, LightSceneInfo, LightBounds, FogInfo, ProjectedShadowInfo, VolumetricFogGridSize, VolumeZBounds.X); + } } } - RHICmdList.SetStreamSource(0, GVolumeRasterizeVertexBuffer.VertexBufferRHI, sizeof(FScreenVertex), 0); + RHICmdList.SetStreamSource(0, GCircleRasterizeVertexBuffer.VertexBufferRHI, sizeof(FScreenVertex), 0); const int32 NumInstances = VolumeZBounds.Y - VolumeZBounds.X; - // Render a quad per slice affected by the given bounds - RHICmdList.DrawPrimitive(PT_TriangleStrip, 0, 2, NumInstances); + const int32 NumTriangles = FCircleRasterizeVertexBuffer::NumVertices - 2; + RHICmdList.DrawIndexedPrimitive(GCircleRasterizeIndexBuffer.IndexBufferRHI, PT_TriangleList, 0, 0, FCircleRasterizeVertexBuffer::NumVertices, 0, NumTriangles, NumInstances); } } @@ -539,7 +658,6 @@ public: TVolumetricFogLightScatteringCS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) : FGlobalShader(Initializer) { - HistoryWeight.Bind(Initializer.ParameterMap, TEXT("HistoryWeight")); LocalShadowedLightScattering.Bind(Initializer.ParameterMap, TEXT("LocalShadowedLightScattering")); LightScatteringHistory.Bind(Initializer.ParameterMap, TEXT("LightScatteringHistory")); LightScatteringHistorySampler.Bind(Initializer.ParameterMap, TEXT("LightScatteringHistorySampler")); @@ -565,12 +683,10 @@ public: void SetParameters( FRHICommandList& RHICmdList, - const FViewInfo& View, + const FViewInfo& View, + const FVolumetricFogIntegrationParameterData& IntegrationData, const FExponentialHeightFogSceneInfo& FogInfo, - IPooledRenderTarget* VBufferA, - IPooledRenderTarget* VBufferB, IPooledRenderTarget* LocalShadowedLightScatteringTarget, - IPooledRenderTarget* LightScatteringRenderTarget, FTextureRHIParamRef LightScatteringHistoryTexture, bool bUseDirectionalLightShadowing, const FMatrix& DirectionalLightFunctionWorldToShadowValue, @@ -579,8 +695,6 @@ public: FComputeShaderRHIParamRef ShaderRHI = GetComputeShader(); FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View.ViewUniformBuffer); - SetShaderValue(RHICmdList, ShaderRHI, HistoryWeight, GVolumetricFogHistoryWeight); - FTextureRHIParamRef LocalShadowedLightScatteringTexture = GBlackVolumeTexture->TextureRHI; if (LocalShadowedLightScatteringTarget) @@ -603,7 +717,7 @@ public: TStaticSamplerState::GetRHI(), LightScatteringHistoryTexture); - VolumetricFogParameters.Set(RHICmdList, ShaderRHI, View, VBufferA, VBufferB, LightScatteringRenderTarget); + VolumetricFogParameters.Set(RHICmdList, ShaderRHI, View, IntegrationData); ForwardLightingParameters.Set(RHICmdList, ShaderRHI, View); SetShaderValue(RHICmdList, ShaderRHI, DirectionalLightFunctionWorldToShadow, DirectionalLightFunctionWorldToShadowValue); @@ -660,7 +774,6 @@ public: virtual bool Serialize(FArchive& Ar) { bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar); - Ar << HistoryWeight; Ar << LocalShadowedLightScattering; Ar << LightScatteringHistory; Ar << LightScatteringHistorySampler; @@ -683,7 +796,6 @@ public: private: - FShaderParameter HistoryWeight; FShaderResourceParameter LocalShadowedLightScattering; FShaderResourceParameter LightScatteringHistory; FShaderResourceParameter LightScatteringHistorySampler; @@ -741,11 +853,11 @@ public: { } - void SetParameters(FRHICommandList& RHICmdList, const FViewInfo& View, IPooledRenderTarget* LightScatteringRenderTarget) + void SetParameters(FRHICommandList& RHICmdList, const FViewInfo& View, const FVolumetricFogIntegrationParameterData& IntegrationData) { FComputeShaderRHIParamRef ShaderRHI = GetComputeShader(); FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View.ViewUniformBuffer); - VolumetricFogParameters.Set(RHICmdList, ShaderRHI, View, NULL, NULL, LightScatteringRenderTarget); + VolumetricFogParameters.Set(RHICmdList, ShaderRHI, View, IntegrationData); } void UnsetParameters(FRHICommandList& RHICmdList, const FViewInfo& View) @@ -923,6 +1035,30 @@ void FDeferredShadingSceneRenderer::ComputeVolumetricFog(FRHICommandListImmediat SCOPED_DRAW_EVENT(RHICmdList, VolumetricFog); + const FVector FrameJitterOffsetValue = VolumetricFogTemporalRandom(View.Family->FrameNumber); + + FVolumetricFogIntegrationParameterData IntegrationData; + IntegrationData.FrameJitterOffsetValues.Empty(16); + IntegrationData.FrameJitterOffsetValues.AddZeroed(16); + IntegrationData.FrameJitterOffsetValues[0] = VolumetricFogTemporalRandom(View.Family->FrameNumber); + + for (int32 FrameOffsetIndex = 1; FrameOffsetIndex < GVolumetricFogHistoryMissSupersampleCount; FrameOffsetIndex++) + { + IntegrationData.FrameJitterOffsetValues[FrameOffsetIndex] = VolumetricFogTemporalRandom(View.Family->FrameNumber - FrameOffsetIndex); + } + + const bool bUseTemporalReprojection = + GVolumetricFogTemporalReprojection + && View.ViewState; + + IntegrationData.bTemporalHistoryIsValid = + bUseTemporalReprojection + && !View.bCameraCut + && !View.bPrevTransformsReset + && ViewFamily.bRealtimeUpdate + && View.ViewState->LightScatteringHistory + && View.ViewState->LightScatteringHistory->GetDesc().GetSize() == VolumetricFogGridSize; + FMatrix LightFunctionWorldToShadow; TRefCountPtr LightFunctionTexture; bool bUseDirectionalLightShadowing; @@ -941,8 +1077,13 @@ void FDeferredShadingSceneRenderer::ComputeVolumetricFog(FRHICommandListImmediat const uint32 Flags = TexCreate_ShaderResource | TexCreate_RenderTargetable | TexCreate_UAV | TexCreate_ReduceMemoryWithTilingMode; FPooledRenderTargetDesc VolumeDesc(FPooledRenderTargetDesc::CreateVolumeDesc(VolumetricFogGridSize.X, VolumetricFogGridSize.Y, VolumetricFogGridSize.Z, PF_FloatRGBA, FClearValueBinding::Black, TexCreate_None, Flags, false)); - GRenderTargetPool.FindFreeElement(RHICmdList, VolumeDesc, VBufferA, TEXT("VBufferA")); - GRenderTargetPool.FindFreeElement(RHICmdList, VolumeDesc, VBufferB, TEXT("VBufferB")); + FPooledRenderTargetDesc VolumeDescFastVRAM = VolumeDesc; + VolumeDescFastVRAM.Flags |= GetTextureFastVRamFlag_DynamicLayout(); + GRenderTargetPool.FindFreeElement(RHICmdList, VolumeDescFastVRAM, VBufferA, TEXT("VBufferA")); + GRenderTargetPool.FindFreeElement(RHICmdList, VolumeDescFastVRAM, VBufferB, TEXT("VBufferB")); + + IntegrationData.VBufferARenderTarget = VBufferA.GetReference(); + IntegrationData.VBufferBRenderTarget = VBufferB.GetReference(); // Unbind render targets, the shadow depth target may still be bound SetRenderTarget(RHICmdList, NULL, NULL); @@ -954,7 +1095,7 @@ void FDeferredShadingSceneRenderer::ComputeVolumetricFog(FRHICommandListImmediat SCOPED_DRAW_EVENT(RHICmdList, InitializeVolumeAttributes); TShaderMapRef ComputeShader(View.ShaderMap); RHICmdList.SetComputeShader(ComputeShader->GetComputeShader()); - ComputeShader->SetParameters(RHICmdList, View, FogInfo, VBufferA.GetReference(), VBufferB.GetReference()); + ComputeShader->SetParameters(RHICmdList, View, IntegrationData, FogInfo); DispatchComputeShader(RHICmdList, *ComputeShader, NumGroups.X, NumGroups.Y, NumGroups.Z); ComputeShader->UnsetParameters(RHICmdList, View, VBufferA.GetReference(), VBufferB.GetReference()); } @@ -962,11 +1103,10 @@ void FDeferredShadingSceneRenderer::ComputeVolumetricFog(FRHICommandListImmediat VoxelizeFogVolumePrimitives( RHICmdList, View, + IntegrationData, VolumetricFogGridSize, GridZParams, - FogInfo.VolumetricFogDistance, - VBufferA.GetReference(), - VBufferB.GetReference()); + FogInfo.VolumetricFogDistance); FTextureRHIParamRef VoxelizeRenderTargets[2] = { @@ -981,22 +1121,18 @@ void FDeferredShadingSceneRenderer::ComputeVolumetricFog(FRHICommandListImmediat } TRefCountPtr LocalShadowedLightScattering = NULL; - RenderLocalLightsForVolumetricFog(RHICmdList, View, FogInfo, VBufferA.GetReference(), VolumetricFogGridSize, GridZParams, VolumeDesc, LocalShadowedLightScattering); + RenderLocalLightsForVolumetricFog(RHICmdList, View, bUseTemporalReprojection, IntegrationData, FogInfo, VolumetricFogGridSize, GridZParams, VolumeDescFastVRAM, LocalShadowedLightScattering); TRefCountPtr LightScattering; GRenderTargetPool.FindFreeElement(RHICmdList, VolumeDesc, LightScattering, TEXT("LightScattering")); + IntegrationData.LightScatteringRenderTarget = LightScattering.GetReference(); + SetRenderTarget(RHICmdList, NULL, NULL); { const FIntVector NumGroups = FIntVector::DivideAndRoundUp(VolumetricFogGridSize, VolumetricFogGridInjectionGroupSize); - const bool bUseTemporalReprojection = - GVolumetricFogTemporalReprojection - && View.ViewState - && !View.bCameraCut - && !View.bPrevTransformsReset; - const bool bUseGlobalDistanceField = UseGlobalDistanceField() && Scene->DistanceFieldSceneData.NumObjectsInBuffer > 0; const bool bUseDistanceFieldSkyOcclusion = @@ -1017,13 +1153,17 @@ void FDeferredShadingSceneRenderer::ComputeVolumetricFog(FRHICommandListImmediat bUseDistanceFieldSkyOcclusion ? TEXT("DFAO") : TEXT(""), LightFunctionTexture ? TEXT("LF") : TEXT("")); - if (bUseTemporalReprojection && View.ViewState->LightScatteringHistory) + if (bUseTemporalReprojection) { + FTextureRHIParamRef LightScatteringHistoryTexture = View.ViewState->LightScatteringHistory + ? View.ViewState->LightScatteringHistory->GetRenderTargetItem().ShaderResourceTexture + : GBlackVolumeTexture->TextureRHI; + if (bUseDistanceFieldSkyOcclusion) { TShaderMapRef > ComputeShader(View.ShaderMap); RHICmdList.SetComputeShader(ComputeShader->GetComputeShader()); - ComputeShader->SetParameters(RHICmdList, View, FogInfo, VBufferA.GetReference(), VBufferB.GetReference(), LocalShadowedLightScattering.GetReference(), LightScattering.GetReference(), View.ViewState->LightScatteringHistory->GetRenderTargetItem().ShaderResourceTexture, bUseDirectionalLightShadowing, LightFunctionWorldToShadow, LightFunctionTexture); + ComputeShader->SetParameters(RHICmdList, View, IntegrationData, FogInfo, LocalShadowedLightScattering.GetReference(), LightScatteringHistoryTexture, bUseDirectionalLightShadowing, LightFunctionWorldToShadow, LightFunctionTexture); DispatchComputeShader(RHICmdList, *ComputeShader, NumGroups.X, NumGroups.Y, NumGroups.Z); ComputeShader->UnsetParameters(RHICmdList, View, LightScattering.GetReference()); } @@ -1031,7 +1171,7 @@ void FDeferredShadingSceneRenderer::ComputeVolumetricFog(FRHICommandListImmediat { TShaderMapRef > ComputeShader(View.ShaderMap); RHICmdList.SetComputeShader(ComputeShader->GetComputeShader()); - ComputeShader->SetParameters(RHICmdList, View, FogInfo, VBufferA.GetReference(), VBufferB.GetReference(), LocalShadowedLightScattering.GetReference(), LightScattering.GetReference(), View.ViewState->LightScatteringHistory->GetRenderTargetItem().ShaderResourceTexture, bUseDirectionalLightShadowing, LightFunctionWorldToShadow, LightFunctionTexture); + ComputeShader->SetParameters(RHICmdList, View, IntegrationData, FogInfo, LocalShadowedLightScattering.GetReference(), LightScatteringHistoryTexture, bUseDirectionalLightShadowing, LightFunctionWorldToShadow, LightFunctionTexture); DispatchComputeShader(RHICmdList, *ComputeShader, NumGroups.X, NumGroups.Y, NumGroups.Z); ComputeShader->UnsetParameters(RHICmdList, View, LightScattering.GetReference()); } @@ -1042,7 +1182,7 @@ void FDeferredShadingSceneRenderer::ComputeVolumetricFog(FRHICommandListImmediat { TShaderMapRef > ComputeShader(View.ShaderMap); RHICmdList.SetComputeShader(ComputeShader->GetComputeShader()); - ComputeShader->SetParameters(RHICmdList, View, FogInfo, VBufferA.GetReference(), VBufferB.GetReference(), LocalShadowedLightScattering.GetReference(), LightScattering.GetReference(), NULL, bUseDirectionalLightShadowing, LightFunctionWorldToShadow, LightFunctionTexture); + ComputeShader->SetParameters(RHICmdList, View, IntegrationData, FogInfo, LocalShadowedLightScattering.GetReference(), NULL, bUseDirectionalLightShadowing, LightFunctionWorldToShadow, LightFunctionTexture); DispatchComputeShader(RHICmdList, *ComputeShader, NumGroups.X, NumGroups.Y, NumGroups.Z); ComputeShader->UnsetParameters(RHICmdList, View, LightScattering.GetReference()); } @@ -1050,7 +1190,7 @@ void FDeferredShadingSceneRenderer::ComputeVolumetricFog(FRHICommandListImmediat { TShaderMapRef > ComputeShader(View.ShaderMap); RHICmdList.SetComputeShader(ComputeShader->GetComputeShader()); - ComputeShader->SetParameters(RHICmdList, View, FogInfo, VBufferA.GetReference(), VBufferB.GetReference(), LocalShadowedLightScattering.GetReference(), LightScattering.GetReference(), NULL, bUseDirectionalLightShadowing, LightFunctionWorldToShadow, LightFunctionTexture); + ComputeShader->SetParameters(RHICmdList, View, IntegrationData, FogInfo, LocalShadowedLightScattering.GetReference(), NULL, bUseDirectionalLightShadowing, LightFunctionWorldToShadow, LightFunctionTexture); DispatchComputeShader(RHICmdList, *ComputeShader, NumGroups.X, NumGroups.Y, NumGroups.Z); ComputeShader->UnsetParameters(RHICmdList, View, LightScattering.GetReference()); } @@ -1070,6 +1210,7 @@ void FDeferredShadingSceneRenderer::ComputeVolumetricFog(FRHICommandListImmediat VBufferA = NULL; VBufferB = NULL; + LightFunctionTexture = NULL; GRenderTargetPool.FindFreeElement(RHICmdList, VolumeDesc, View.VolumetricFogResources.IntegratedLightScattering, TEXT("IntegratedLightScattering")); @@ -1079,7 +1220,7 @@ void FDeferredShadingSceneRenderer::ComputeVolumetricFog(FRHICommandListImmediat const FIntVector NumGroups = FIntVector::DivideAndRoundUp(VolumetricFogGridSize, VolumetricFogIntegrationGroupSize); TShaderMapRef ComputeShader(View.ShaderMap); RHICmdList.SetComputeShader(ComputeShader->GetComputeShader()); - ComputeShader->SetParameters(RHICmdList, View, LightScattering.GetReference()); + ComputeShader->SetParameters(RHICmdList, View, IntegrationData); DispatchComputeShader(RHICmdList, *ComputeShader, NumGroups.X, NumGroups.Y, 1); ComputeShader->UnsetParameters(RHICmdList, View); } diff --git a/Engine/Source/Runtime/Renderer/Private/VolumetricFog.h b/Engine/Source/Runtime/Renderer/Private/VolumetricFog.h index 1d2329724bce..e41326656329 100644 --- a/Engine/Source/Runtime/Renderer/Private/VolumetricFog.h +++ b/Engine/Source/Runtime/Renderer/Private/VolumetricFog.h @@ -12,12 +12,12 @@ inline bool DoesPlatformSupportVolumetricFog(EShaderPlatform Platform) { - return Platform == SP_PCD3D_SM5 || Platform == SP_PS4 || Platform == SP_XBOXONE || Platform == SP_METAL_SM5; + return Platform == SP_PCD3D_SM5 || Platform == SP_PS4 || Platform == SP_XBOXONE_D3D12 || Platform == SP_XBOXONE_D3D11 || Platform == SP_METAL_SM5; } inline bool DoesPlatformSupportVolumetricFogVoxelization(EShaderPlatform Platform) { - return Platform == SP_PCD3D_SM5 || Platform == SP_PS4 || Platform == SP_XBOXONE || Platform == SP_METAL_SM5; + return Platform == SP_PCD3D_SM5 || Platform == SP_PS4 || Platform == SP_XBOXONE_D3D12 || Platform == SP_XBOXONE_D3D11 || Platform == SP_METAL_SM5; } extern bool ShouldRenderVolumetricFog(const FScene* Scene, const FSceneViewFamily& ViewFamily); diff --git a/Engine/Source/Runtime/Renderer/Private/VolumetricFogLightFunction.cpp b/Engine/Source/Runtime/Renderer/Private/VolumetricFogLightFunction.cpp index 77ea6ed55858..602d7e933418 100644 --- a/Engine/Source/Runtime/Renderer/Private/VolumetricFogLightFunction.cpp +++ b/Engine/Source/Runtime/Renderer/Private/VolumetricFogLightFunction.cpp @@ -187,6 +187,7 @@ void FDeferredShadingSceneRenderer::RenderLightFunctionForVolumetricFog( if (MaterialProxy && MaterialProxy->GetMaterial(Scene->GetFeatureLevel())->IsLightFunction()) { FPooledRenderTargetDesc LightFunctionTextureDesc(FPooledRenderTargetDesc::Create2DDesc(LightFunctionResolution, PF_G8, FClearValueBinding::None, TexCreate_None, TexCreate_ShaderResource | TexCreate_RenderTargetable, false)); + LightFunctionTextureDesc.Flags |= GetTextureFastVRamFlag_DynamicLayout(); GRenderTargetPool.FindFreeElement(RHICmdList, LightFunctionTextureDesc, OutLightFunctionTexture, TEXT("VolumetricFogLightFunction")); const FMatrix WorldToShadowValue = FTranslationMatrix(ProjectedShadowInfo.PreShadowTranslation) * ProjectedShadowInfo.SubjectAndReceiverMatrix; diff --git a/Engine/Source/Runtime/Renderer/Private/VolumetricFogShared.h b/Engine/Source/Runtime/Renderer/Private/VolumetricFogShared.h index 6a213d23e642..3bc6d6be785b 100644 --- a/Engine/Source/Runtime/Renderer/Private/VolumetricFogShared.h +++ b/Engine/Source/Runtime/Renderer/Private/VolumetricFogShared.h @@ -12,6 +12,22 @@ extern FVector VolumetricFogTemporalRandom(uint32 FrameNumber); +struct FVolumetricFogIntegrationParameterData +{ + FVolumetricFogIntegrationParameterData() : + bTemporalHistoryIsValid(false), + VBufferARenderTarget(NULL), + VBufferBRenderTarget(NULL), + LightScatteringRenderTarget(NULL) + {} + + bool bTemporalHistoryIsValid; + TArray> FrameJitterOffsetValues; + IPooledRenderTarget* VBufferARenderTarget; + IPooledRenderTarget* VBufferBRenderTarget; + IPooledRenderTarget* LightScatteringRenderTarget; +}; + /** */ class FVolumetricFogIntegrationParameters { @@ -19,7 +35,6 @@ public: static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment) { - } void Bind(const FShaderParameterMap& ParameterMap) @@ -32,7 +47,9 @@ public: VolumetricFogData.Bind(ParameterMap, TEXT("VolumetricFog")); UnjitteredClipToTranslatedWorld.Bind(ParameterMap, TEXT("UnjitteredClipToTranslatedWorld")); UnjitteredPrevWorldToClip.Bind(ParameterMap, TEXT("UnjitteredPrevWorldToClip")); - FrameJitterOffset.Bind(ParameterMap, TEXT("FrameJitterOffset")); + FrameJitterOffsets.Bind(ParameterMap, TEXT("FrameJitterOffsets")); + HistoryWeight.Bind(ParameterMap, TEXT("HistoryWeight")); + HistoryMissSuperSampleCount.Bind(ParameterMap, TEXT("HistoryMissSuperSampleCount")); } template @@ -40,25 +57,23 @@ public: FRHICommandList& RHICmdList, const ShaderRHIParamRef& ShaderRHI, const FViewInfo& View, - IPooledRenderTarget* VBufferARenderTarget, - IPooledRenderTarget* VBufferBRenderTarget, - IPooledRenderTarget* LightScatteringRenderTarget) const + const FVolumetricFogIntegrationParameterData& IntegrationData) const { if (VBufferA.IsBound()) { - const FSceneRenderTargetItem& VBufferAItem = VBufferARenderTarget->GetRenderTargetItem(); + const FSceneRenderTargetItem& VBufferAItem = IntegrationData.VBufferARenderTarget->GetRenderTargetItem(); VBufferA.SetTexture(RHICmdList, ShaderRHI, VBufferAItem.ShaderResourceTexture, VBufferAItem.UAV); } if (VBufferB.IsBound()) { - const FSceneRenderTargetItem& VBufferBItem = VBufferBRenderTarget->GetRenderTargetItem(); + const FSceneRenderTargetItem& VBufferBItem = IntegrationData.VBufferBRenderTarget->GetRenderTargetItem(); VBufferB.SetTexture(RHICmdList, ShaderRHI, VBufferBItem.ShaderResourceTexture, VBufferBItem.UAV); } if (LightScattering.IsBound()) { - const FSceneRenderTargetItem& LightScatteringItem = LightScatteringRenderTarget->GetRenderTargetItem(); + const FSceneRenderTargetItem& LightScatteringItem = IntegrationData.LightScatteringRenderTarget->GetRenderTargetItem(); LightScattering.SetTexture(RHICmdList, ShaderRHI, LightScatteringItem.ShaderResourceTexture, LightScatteringItem.UAV); } @@ -88,11 +103,16 @@ public: SetShaderValue(RHICmdList, ShaderRHI, UnjitteredPrevWorldToClip, UnjitteredViewProjectionMatrix); } - if (FrameJitterOffset.IsBound()) + if (FrameJitterOffsets.IsBound()) { - const FVector FrameJitterOffsetValue = VolumetricFogTemporalRandom(View.Family->FrameNumber); - SetShaderValue(RHICmdList, ShaderRHI, FrameJitterOffset, FrameJitterOffsetValue); + SetShaderValueArray(RHICmdList, ShaderRHI, FrameJitterOffsets, IntegrationData.FrameJitterOffsetValues.GetData(), IntegrationData.FrameJitterOffsetValues.Num()); } + + extern float GVolumetricFogHistoryWeight; + SetShaderValue(RHICmdList, ShaderRHI, HistoryWeight, IntegrationData.bTemporalHistoryIsValid ? GVolumetricFogHistoryWeight : 0.0f); + + extern int32 GVolumetricFogHistoryMissSupersampleCount; + SetShaderValue(RHICmdList, ShaderRHI, HistoryMissSuperSampleCount, FMath::Clamp(GVolumetricFogHistoryMissSupersampleCount, 1, 16)); } template @@ -151,7 +171,9 @@ public: Ar << P.VolumetricFogData; Ar << P.UnjitteredClipToTranslatedWorld; Ar << P.UnjitteredPrevWorldToClip; - Ar << P.FrameJitterOffset; + Ar << P.FrameJitterOffsets; + Ar << P.HistoryWeight; + Ar << P.HistoryMissSuperSampleCount; return Ar; } @@ -165,7 +187,9 @@ private: FShaderUniformBufferParameter VolumetricFogData; FShaderParameter UnjitteredClipToTranslatedWorld; FShaderParameter UnjitteredPrevWorldToClip; - FShaderParameter FrameJitterOffset; + FShaderParameter FrameJitterOffsets; + FShaderParameter HistoryWeight; + FShaderParameter HistoryMissSuperSampleCount; }; inline int32 ComputeZSliceFromDepth(float SceneDepth, FVector GridZParams) diff --git a/Engine/Source/Runtime/Renderer/Private/VolumetricFogVoxelization.cpp b/Engine/Source/Runtime/Renderer/Private/VolumetricFogVoxelization.cpp index 54ac81aa6892..78015ce757ce 100644 --- a/Engine/Source/Runtime/Renderer/Private/VolumetricFogVoxelization.cpp +++ b/Engine/Source/Runtime/Renderer/Private/VolumetricFogVoxelization.cpp @@ -72,6 +72,7 @@ public: const FVertexFactory* VertexFactory, const FMaterialRenderProxy* MaterialRenderProxy, const FViewInfo& View, + const FVolumetricFogIntegrationParameterData& IntegrationData, const TUniformBufferRef& VoxelizeViewUniformBuffer, FVector2D Jitter) { @@ -79,7 +80,7 @@ public: if (!RHISupportsGeometryShaders(View.GetShaderPlatform())) { - VolumetricFogParameters.Set(RHICmdList, GetVertexShader(), View, NULL, NULL, NULL); + VolumetricFogParameters.Set(RHICmdList, GetVertexShader(), View, IntegrationData); FMatrix ProjectionMatrix = View.ViewMatrices.ComputeProjectionNoAAMatrix(); @@ -157,11 +158,12 @@ public: const FVertexFactory* VertexFactory, const FMaterialRenderProxy* MaterialRenderProxy, const FViewInfo& View, + const FVolumetricFogIntegrationParameterData& IntegrationData, const TUniformBufferRef& VoxelizeViewUniformBuffer, FVector2D Jitter) { FMeshMaterialShader::SetParameters(RHICmdList, (FGeometryShaderRHIParamRef)GetGeometryShader(), MaterialRenderProxy, *MaterialRenderProxy->GetMaterial(View.GetFeatureLevel()), View, VoxelizeViewUniformBuffer, ESceneRenderTargetsMode::SetTextures); - VolumetricFogParameters.Set(RHICmdList, GetGeometryShader(), View, NULL, NULL, NULL); + VolumetricFogParameters.Set(RHICmdList, GetGeometryShader(), View, IntegrationData); FMatrix ProjectionMatrix = View.ViewMatrices.ComputeProjectionNoAAMatrix(); @@ -221,10 +223,16 @@ protected: public: - void SetParameters(FRHICommandList& RHICmdList, const FVertexFactory* VertexFactory,const FMaterialRenderProxy* MaterialRenderProxy,const FViewInfo& View, const TUniformBufferRef& VoxelizeViewUniformBuffer) + void SetParameters( + FRHICommandList& RHICmdList, + const FVertexFactory* VertexFactory, + const FMaterialRenderProxy* MaterialRenderProxy, + const FViewInfo& View, + const FVolumetricFogIntegrationParameterData& IntegrationData, + const TUniformBufferRef& VoxelizeViewUniformBuffer) { FMeshMaterialShader::SetParameters(RHICmdList, GetPixelShader(), MaterialRenderProxy, *MaterialRenderProxy->GetMaterial(View.GetFeatureLevel()), View, VoxelizeViewUniformBuffer, ESceneRenderTargetsMode::SetTextures); - VolumetricFogParameters.Set(RHICmdList, GetPixelShader(), View, NULL, NULL, NULL); + VolumetricFogParameters.Set(RHICmdList, GetPixelShader(), View, IntegrationData); } void SetMesh(FRHICommandList& RHICmdList, const FVertexFactory* VertexFactory,const FSceneView& View,const FPrimitiveSceneProxy* Proxy,const FMeshBatchElement& BatchElement,const FDrawingPolicyRenderState& DrawRenderState) @@ -276,6 +284,7 @@ public: void SetSharedState( FRHICommandList& RHICmdList, const FViewInfo& View, + const FVolumetricFogIntegrationParameterData& IntegrationData, const TUniformBufferRef& VoxelizeViewUniformBuffer, FVector2D Jitter, const ContextDataType PolicyContext, @@ -334,6 +343,7 @@ FDrawingPolicyMatchResult FVoxelizeVolumeDrawingPolicy::Matches( void FVoxelizeVolumeDrawingPolicy::SetSharedState( FRHICommandList& RHICmdList, const FViewInfo& View, + const FVolumetricFogIntegrationParameterData& IntegrationData, const TUniformBufferRef& VoxelizeViewUniformBuffer, FVector2D Jitter, const ContextDataType PolicyContext, @@ -343,12 +353,12 @@ void FVoxelizeVolumeDrawingPolicy::SetSharedState( // Set shared mesh resources FMeshDrawingPolicy::SetSharedState(RHICmdList, DrawRenderState, &View, PolicyContext); - VertexShader->SetParameters(RHICmdList, VertexFactory, MaterialRenderProxy, View, VoxelizeViewUniformBuffer, Jitter); + VertexShader->SetParameters(RHICmdList, VertexFactory, MaterialRenderProxy, View, IntegrationData, VoxelizeViewUniformBuffer, Jitter); if (GeometryShader) { - GeometryShader->SetParameters(RHICmdList, VertexFactory, MaterialRenderProxy, View, VoxelizeViewUniformBuffer, Jitter); + GeometryShader->SetParameters(RHICmdList, VertexFactory, MaterialRenderProxy, View, IntegrationData, VoxelizeViewUniformBuffer, Jitter); } - PixelShader->SetParameters(RHICmdList, VertexFactory, MaterialRenderProxy, View, VoxelizeViewUniformBuffer); + PixelShader->SetParameters(RHICmdList, VertexFactory, MaterialRenderProxy, View, IntegrationData, VoxelizeViewUniformBuffer); } FBoundShaderStateInput FVoxelizeVolumeDrawingPolicy::GetBoundShaderStateInput(ERHIFeatureLevel::Type InFeatureLevel) @@ -387,6 +397,7 @@ void FVoxelizeVolumeDrawingPolicy::SetMeshRenderState( void VoxelizeVolumePrimitive( FRHICommandListImmediate& RHICmdList, const FViewInfo& View, + const FVolumetricFogIntegrationParameterData& IntegrationData, const TUniformBufferRef& VoxelizeViewUniformBuffer, FVector2D Jitter, FIntVector VolumetricFogGridSize, @@ -408,7 +419,7 @@ void VoxelizeVolumePrimitive( FDrawingPolicyRenderState DrawRenderState(View); DrawingPolicy.SetupPipelineState(DrawRenderState, View); CommitGraphicsPipelineState(RHICmdList, DrawingPolicy, DrawRenderState, DrawingPolicy.GetBoundShaderStateInput(View.GetFeatureLevel())); - DrawingPolicy.SetSharedState(RHICmdList, View, VoxelizeViewUniformBuffer, Jitter, FVoxelizeVolumeDrawingPolicy::ContextDataType(), DrawRenderState); + DrawingPolicy.SetSharedState(RHICmdList, View, IntegrationData, VoxelizeViewUniformBuffer, Jitter, FVoxelizeVolumeDrawingPolicy::ContextDataType(), DrawRenderState); FBoxSphereBounds Bounds = PrimitiveSceneProxy->GetBounds(); //@todo - compute NumSlices based on the largest particle size. Bounds is overly conservative in most cases. @@ -442,11 +453,10 @@ void VoxelizeVolumePrimitive( void FDeferredShadingSceneRenderer::VoxelizeFogVolumePrimitives( FRHICommandListImmediate& RHICmdList, const FViewInfo& View, + const FVolumetricFogIntegrationParameterData& IntegrationData, FIntVector VolumetricFogGridSize, FVector GridZParams, - float VolumetricFogDistance, - IPooledRenderTarget* VBufferA, - IPooledRenderTarget* VBufferB) + float VolumetricFogDistance) { if (View.VolumetricPrimSet.NumPrims() > 0 && DoesPlatformSupportVolumetricFogVoxelization(View.GetShaderPlatform())) @@ -466,13 +476,12 @@ void FDeferredShadingSceneRenderer::VoxelizeFogVolumePrimitives( TUniformBufferRef VoxelizeViewUniformBuffer = TUniformBufferRef::CreateUniformBufferImmediate(VoxelizeParameters, UniformBuffer_SingleFrame); - FVector JitterOffset = VolumetricFogTemporalRandom(View.Family->FrameNumber); - FVector2D Jitter(JitterOffset.X / VolumetricFogGridSize.X, JitterOffset.Y / VolumetricFogGridSize.Y); + FVector2D Jitter(IntegrationData.FrameJitterOffsetValues[0].X / VolumetricFogGridSize.X, IntegrationData.FrameJitterOffsetValues[0].Y / VolumetricFogGridSize.Y); FTextureRHIParamRef RenderTargets[2] = { - VBufferA->GetRenderTargetItem().TargetableTexture, - VBufferB->GetRenderTargetItem().TargetableTexture + IntegrationData.VBufferARenderTarget->GetRenderTargetItem().TargetableTexture, + IntegrationData.VBufferBRenderTarget->GetRenderTargetItem().TargetableTexture }; SetRenderTargets(RHICmdList, ARRAY_COUNT(RenderTargets), RenderTargets, FTextureRHIParamRef(), 0, NULL); @@ -499,7 +508,7 @@ void FDeferredShadingSceneRenderer::VoxelizeFogVolumePrimitives( checkSlow(MeshBatchAndRelevance.PrimitiveSceneProxy == PrimitiveSceneInfo->Proxy); const FMeshBatch& MeshBatch = *MeshBatchAndRelevance.Mesh; - VoxelizeVolumePrimitive(RHICmdList, View, VoxelizeViewUniformBuffer, Jitter, VolumetricFogGridSize, GridZParams, PrimitiveSceneProxy, MeshBatch); + VoxelizeVolumePrimitive(RHICmdList, View, IntegrationData, VoxelizeViewUniformBuffer, Jitter, VolumetricFogGridSize, GridZParams, PrimitiveSceneProxy, MeshBatch); } } @@ -511,7 +520,7 @@ void FDeferredShadingSceneRenderer::VoxelizeFogVolumePrimitives( if (View.StaticMeshVisibilityMap[StaticMesh.Id]) { - VoxelizeVolumePrimitive(RHICmdList, View, VoxelizeViewUniformBuffer, Jitter, VolumetricFogGridSize, GridZParams, PrimitiveSceneProxy, StaticMesh); + VoxelizeVolumePrimitive(RHICmdList, View, IntegrationData, VoxelizeViewUniformBuffer, Jitter, VolumetricFogGridSize, GridZParams, PrimitiveSceneProxy, StaticMesh); } } } diff --git a/Engine/Source/Runtime/Renderer/Public/LightPropagationVolumeSettings.h b/Engine/Source/Runtime/Renderer/Public/LightPropagationVolumeSettings.h new file mode 100644 index 000000000000..f8182e2204a5 --- /dev/null +++ b/Engine/Source/Runtime/Renderer/Public/LightPropagationVolumeSettings.h @@ -0,0 +1,154 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "UObject/Object.h" +#include "LightPropagationVolumeSettings.generated.h" + +USTRUCT(BlueprintType) +struct RENDERER_API FLightPropagationVolumeSettings +{ + GENERATED_USTRUCT_BODY() + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category=Overrides, meta=(PinHiddenByDefault, InlineEditConditionToggle)) + uint32 bOverride_LPVIntensity:1; + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle)) + uint32 bOverride_LPVDirectionalOcclusionIntensity:1; + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle)) + uint32 bOverride_LPVDirectionalOcclusionRadius:1; + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle)) + uint32 bOverride_LPVDiffuseOcclusionExponent:1; + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle)) + uint32 bOverride_LPVSpecularOcclusionExponent:1; + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle)) + uint32 bOverride_LPVDiffuseOcclusionIntensity:1; + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle)) + uint32 bOverride_LPVSpecularOcclusionIntensity:1; + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle)) + uint32 bOverride_LPVSize:1; + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle)) + uint32 bOverride_LPVSecondaryOcclusionIntensity:1; + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle)) + uint32 bOverride_LPVSecondaryBounceIntensity:1; + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle)) + uint32 bOverride_LPVGeometryVolumeBias:1; + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle)) + uint32 bOverride_LPVVplInjectionBias:1; + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Overrides, meta = (PinHiddenByDefault, InlineEditConditionToggle)) + uint32 bOverride_LPVEmissiveInjectionIntensity:1; + + /** How strong the dynamic GI from the LPV should be. 0.0 is off, 1.0 is the "normal" value, but higher values can be used to boost the effect*/ + UPROPERTY(interp, BlueprintReadWrite, Category=LightPropagationVolume, meta=(editcondition = "bOverride_LPVIntensity", UIMin = "0", UIMax = "20", DisplayName = "Intensity") ) + float LPVIntensity; + + /** Bias applied to light injected into the LPV in cell units. Increase to reduce bleeding through thin walls*/ + UPROPERTY(interp, BlueprintReadWrite, Category=LightPropagationVolume, AdvancedDisplay, meta=(editcondition = "bOverride_LPVVplInjectionBias", UIMin = "0", UIMax = "2", DisplayName = "Light Injection Bias") ) + float LPVVplInjectionBias; + + /** The size of the LPV volume, in Unreal units*/ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=LightPropagationVolume, meta=(editcondition = "bOverride_LPVSize", UIMin = "100", UIMax = "20000", DisplayName = "Size") ) + float LPVSize; + + /** Secondary occlusion strength (bounce light shadows). Set to 0 to disable*/ + UPROPERTY(interp, BlueprintReadWrite, Category=LightPropagationVolume, meta=(editcondition = "bOverride_LPVSecondaryOcclusionIntensity", UIMin = "0", UIMax = "1", DisplayName = "Secondary Occlusion Intensity") ) + float LPVSecondaryOcclusionIntensity; + + /** Secondary bounce light strength (bounce light shadows). Set to 0 to disable*/ + UPROPERTY(interp, BlueprintReadWrite, Category=LightPropagationVolume, AdvancedDisplay, meta=(editcondition = "bOverride_LPVSecondaryBounceIntensity", UIMin = "0", UIMax = "1", DisplayName = "Secondary Bounce Intensity") ) + float LPVSecondaryBounceIntensity; + + /** Bias applied to the geometry volume in cell units. Increase to reduce darkening due to secondary occlusion */ + UPROPERTY(interp, BlueprintReadWrite, Category=LightPropagationVolume, AdvancedDisplay, meta=(editcondition = "bOverride_LPVGeometryVolumeBias", UIMin = "0", UIMax = "2", DisplayName = "Geometry Volume Bias")) + float LPVGeometryVolumeBias; + + UPROPERTY(interp, BlueprintReadWrite, Category=LightPropagationVolume, AdvancedDisplay, meta=(editcondition = "bOverride_LPVEmissiveInjectionIntensity", UIMin = "0", UIMax = "20", DisplayName = "Emissive Injection Intensity") ) + float LPVEmissiveInjectionIntensity; + + /** Controls the amount of directional occlusion. Requires LPV. Values very close to 1.0 are recommended */ + UPROPERTY(interp, BlueprintReadWrite, Category=LightPropagationVolume, meta=(editcondition = "bOverride_LPVDirectionalOcclusionIntensity", UIMin = "0", UIMax = "1", DisplayName = "Occlusion Intensity") ) + float LPVDirectionalOcclusionIntensity; + + /** Occlusion Radius - 16 is recommended for most scenes */ + UPROPERTY(interp, BlueprintReadWrite, Category=LightPropagationVolume, AdvancedDisplay, meta=(editcondition = "bOverride_LPVDirectionalOcclusionRadius", UIMin = "1", UIMax = "16", DisplayName = "Occlusion Radius") ) + float LPVDirectionalOcclusionRadius; + + /** Diffuse occlusion exponent - increase for more contrast. 1 to 2 is recommended */ + UPROPERTY(interp, BlueprintReadWrite, Category=LightPropagationVolume, meta=(editcondition = "bOverride_LPVDiffuseOcclusionExponent", UIMin = "0.5", UIMax = "5", DisplayName = "Diffuse occlusion exponent") ) + float LPVDiffuseOcclusionExponent; + + /** Specular occlusion exponent - increase for more contrast. 6 to 9 is recommended */ + UPROPERTY(interp, BlueprintReadWrite, Category=LightPropagationVolume, meta=(editcondition = "bOverride_LPVSpecularOcclusionExponent", UIMin = "1", UIMax = "16", DisplayName = "Specular occlusion exponent") ) + float LPVSpecularOcclusionExponent; + + /** Diffuse occlusion intensity - higher values provide increased diffuse occlusion.*/ + UPROPERTY(interp, BlueprintReadWrite, Category=LightPropagationVolume, AdvancedDisplay, meta=(editcondition = "bOverride_LPVDiffuseOcclusionIntensity", UIMin = "0", UIMax = "4", DisplayName = "Diffuse occlusion intensity") ) + float LPVDiffuseOcclusionIntensity; + + /** Specular occlusion intensity - higher values provide increased specular occlusion.*/ + UPROPERTY(interp, BlueprintReadWrite, Category=LightPropagationVolume, AdvancedDisplay, meta=(editcondition = "bOverride_LPVSpecularOcclusionIntensity", UIMin = "0", UIMax = "4", DisplayName = "Specular occlusion intensity") ) + float LPVSpecularOcclusionIntensity; + + /** LPV Fade range - increase to fade more gradually towards the LPV edges.*/ + UPROPERTY(interp, BlueprintReadWrite, Category = LightPropagationVolume, AdvancedDisplay, meta = (editcondition = "bOverride_LPVFadeRange", UIMin = "0", UIMax = "9", DisplayName = "Fade range")) + float LPVFadeRange; + + /** LPV Directional Occlusion Fade range - increase to fade more gradually towards the LPV edges.*/ + UPROPERTY(interp, BlueprintReadWrite, Category = LightPropagationVolume, AdvancedDisplay, meta = (editcondition = "bOverride_LPVDirectionalOcclusionFadeRange", UIMin = "0", UIMax = "9", DisplayName = "DO Fade range")) + float LPVDirectionalOcclusionFadeRange; + + // good start values for a new volume + FLightPropagationVolumeSettings() + { + // to set all bOverride_.. by default to false + FMemory::Memzero(this, sizeof(*this)); + + // default values: + + LPVIntensity = 1.0f; + LPVSize = 5312.0f; + LPVSecondaryOcclusionIntensity = 0.0f; + LPVSecondaryBounceIntensity = 0.0f; + LPVVplInjectionBias = 0.64f; + LPVGeometryVolumeBias = 0.384f; + LPVEmissiveInjectionIntensity = 1.0f; + LPVDirectionalOcclusionIntensity = 0.0f; + LPVDirectionalOcclusionRadius = 8.0f; + LPVDiffuseOcclusionExponent = 1.0f; + LPVSpecularOcclusionExponent = 7.0f; + LPVDiffuseOcclusionIntensity = 1.0f; + LPVSpecularOcclusionIntensity = 1.0f; + LPVFadeRange = 0.0f; + LPVDirectionalOcclusionFadeRange = 0.0f; + } + + /** + * Used to define the values before any override happens. + * Should be as neutral as possible. + */ + void SetBaseValues() + { + *this = FLightPropagationVolumeSettings(); + } + + // for type safety in FBlendableManager + static const FName& GetFName() + { + static const FName Name = FName(TEXT("FLightPropagationVolumeSettings")); + + return Name; + } +}; diff --git a/Engine/Source/Runtime/Renderer/Public/PrimitiveSceneInfo.h b/Engine/Source/Runtime/Renderer/Public/PrimitiveSceneInfo.h index 1e9924f9c8ae..1e1203643c91 100644 --- a/Engine/Source/Runtime/Renderer/Public/PrimitiveSceneInfo.h +++ b/Engine/Source/Runtime/Renderer/Public/PrimitiveSceneInfo.h @@ -138,6 +138,19 @@ public: } }; +/** Flags needed for shadow culling. These are pulled out of the FPrimitiveSceneProxy so we can do rough culling before dereferencing the proxy. */ +struct FPrimitiveFlagsCompact +{ + /** True if the primitive casts dynamic shadows. */ + uint32 bCastDynamicShadow : 1; + /** True if the primitive will cache static lighting. */ + uint32 bStaticLighting : 1; + /** True if the primitive casts static shadows. */ + uint32 bCastStaticShadow : 1; + + FPrimitiveFlagsCompact(const FPrimitiveSceneProxy* Proxy); +}; + /** The information needed to determine whether a primitive is visible. */ class FPrimitiveSceneInfoCompact { @@ -147,28 +160,12 @@ public: FBoxSphereBounds Bounds; float MinDrawDistance; float MaxDrawDistance; - float LpvBiasMultiplier; /** Used for precomputed visibility */ int32 VisibilityId; - uint32 bHasViewDependentDPG : 1; - uint32 bCastDynamicShadow : 1; - uint32 bAffectDynamicIndirectLighting : 1; - uint32 StaticDepthPriorityGroup : SDPG_NumBits; - - /** Initializes the compact scene info from the primitive's full scene info. */ - void Init(FPrimitiveSceneInfo* InPrimitiveSceneInfo); - - /** Default constructor. */ - FPrimitiveSceneInfoCompact(): - PrimitiveSceneInfo(NULL), - Proxy(NULL) - {} + FPrimitiveFlagsCompact PrimitiveFlagsCompact; /** Initialization constructor. */ - FPrimitiveSceneInfoCompact(FPrimitiveSceneInfo* InPrimitiveSceneInfo) - { - Init(InPrimitiveSceneInfo); - } + FPrimitiveSceneInfoCompact(FPrimitiveSceneInfo* InPrimitiveSceneInfo); }; /** The type of the octree used by FScene to find primitives. */ @@ -447,7 +444,8 @@ private: /** Defines how the primitive is stored in the scene's primitive octree. */ struct FPrimitiveOctreeSemantics { - enum { MaxElementsPerLeaf = 16 }; + /** Note: this is coupled to shadow gather task granularity, see r.ParallelGatherShadowPrimitives. */ + enum { MaxElementsPerLeaf = 256 }; enum { MinInclusiveElementsPerNode = 7 }; enum { MaxNodeDepth = 12 }; diff --git a/Engine/Source/Runtime/Renderer/Public/SceneRenderTargetParameters.h b/Engine/Source/Runtime/Renderer/Public/SceneRenderTargetParameters.h index fa7e8511bcee..8c19cd90750b 100644 --- a/Engine/Source/Runtime/Renderer/Public/SceneRenderTargetParameters.h +++ b/Engine/Source/Runtime/Renderer/Public/SceneRenderTargetParameters.h @@ -8,6 +8,7 @@ #include "CoreMinimal.h" #include "ShaderParameters.h" +#include "MaterialShared.h" class FSceneView; class FShaderParameterMap; @@ -40,6 +41,7 @@ public: TRHICmdList& RHICmdList, const ShaderRHIParamRef& ShaderRHI, const FSceneView& View, + const EDeferredParamStrictness ParamStrictness = EDeferredParamStrictness::ELoose, ESceneRenderTargetsMode::Type TextureMode = ESceneRenderTargetsMode::SetTextures, ESamplerFilter ColorFilter = SF_Point ) const; @@ -84,6 +86,7 @@ public: TRHICmdList& RHICmdList, const ShaderRHIParamRef ShaderRHI, const FSceneView& View, + EMaterialDomain MaterialDomain, ESceneRenderTargetsMode::Type TextureMode = ESceneRenderTargetsMode::SetTextures ) const; diff --git a/Engine/Source/Runtime/Renderer/Renderer.Build.cs b/Engine/Source/Runtime/Renderer/Renderer.Build.cs index 6c4515cb9dd3..f16fb5bb4275 100644 --- a/Engine/Source/Runtime/Renderer/Renderer.Build.cs +++ b/Engine/Source/Runtime/Renderer/Renderer.Build.cs @@ -34,7 +34,7 @@ public class Renderer : ModuleRules } ); - PrivateIncludePathModuleNames.AddRange(new string[] { "HeadMountedDisplay", "LightPropagationVolumeRuntime" }); + PrivateIncludePathModuleNames.AddRange(new string[] { "HeadMountedDisplay" }); DynamicallyLoadedModuleNames.AddRange(new string[] { "HeadMountedDisplay" }); } } diff --git a/Engine/Source/Runtime/RuntimeAssetCache/Private/RuntimeAssetCache.h b/Engine/Source/Runtime/RuntimeAssetCache/Private/RuntimeAssetCache.h index 9c5f44eb97be..01e1724feb6c 100644 --- a/Engine/Source/Runtime/RuntimeAssetCache/Private/RuntimeAssetCache.h +++ b/Engine/Source/Runtime/RuntimeAssetCache/Private/RuntimeAssetCache.h @@ -24,7 +24,7 @@ class FRuntimeAssetCacheBucket; /** * Concrete class implementing FRuntimeAssetCacheInterface. */ -class FRuntimeAssetCache : public FRuntimeAssetCacheInterface +class FRuntimeAssetCache final : public FRuntimeAssetCacheInterface { /** FRuntimeAssetCacheInterface implementation */ public: diff --git a/Engine/Source/Runtime/RuntimeAssetCache/Private/RuntimeAssetCacheBackend.h b/Engine/Source/Runtime/RuntimeAssetCache/Private/RuntimeAssetCacheBackend.h index b03c582b6a6e..5653c559a57e 100644 --- a/Engine/Source/Runtime/RuntimeAssetCache/Private/RuntimeAssetCacheBackend.h +++ b/Engine/Source/Runtime/RuntimeAssetCache/Private/RuntimeAssetCacheBackend.h @@ -79,6 +79,11 @@ public: virtual FRuntimeAssetCacheBucket* PreLoadBucket(FName BucketName, int32 BucketSize) = 0; protected: + /* + * Virtual destructor. + */ + virtual ~FRuntimeAssetCacheBackend() { } + /* * Creates archive to read data from. * @param Bucket Bucket containing cache entry. diff --git a/Engine/Source/Runtime/RuntimeAssetCache/Public/RuntimeAssetCacheInterface.h b/Engine/Source/Runtime/RuntimeAssetCache/Public/RuntimeAssetCacheInterface.h index 6e54a863a996..c1e06c0184ab 100644 --- a/Engine/Source/Runtime/RuntimeAssetCache/Public/RuntimeAssetCacheInterface.h +++ b/Engine/Source/Runtime/RuntimeAssetCache/Public/RuntimeAssetCacheInterface.h @@ -18,7 +18,7 @@ class IRuntimeAssetCacheBuilder; /** * Useful for passing around void* data and size */ -USTRUCT() +USTRUCT(BlueprintType) struct FVoidPtrParam { GENERATED_BODY() @@ -66,6 +66,8 @@ DECLARE_DYNAMIC_DELEGATE_TwoParams(FOnRuntimeAssetCacheAsyncComplete, int32, Han class FRuntimeAssetCacheInterface { public: + virtual ~FRuntimeAssetCacheInterface() { } + /** * Synchronously gets value from cache. If value is not found, builds entry using CacheBuilder and updates cache. * @param CacheBuilder Builder to produce cache key and in the event of a miss. diff --git a/Engine/Source/Runtime/SandboxFile/Public/IPlatformFileSandboxWrapper.h b/Engine/Source/Runtime/SandboxFile/Public/IPlatformFileSandboxWrapper.h index 84af83cf5464..662ccb67fa77 100644 --- a/Engine/Source/Runtime/SandboxFile/Public/IPlatformFileSandboxWrapper.h +++ b/Engine/Source/Runtime/SandboxFile/Public/IPlatformFileSandboxWrapper.h @@ -475,7 +475,7 @@ public: // Now convert the sandbox path back to engine path because the sandbox folder should not be exposed // to the engine and remain transparent. LocalFilename = LocalFilename.Mid(SandboxFile.GetSandboxDirectory().Len()); - if (LocalFilename.StartsWith(TEXT("Engine/"))) + if (LocalFilename.StartsWith(TEXT("Engine/")) || (FCString::Stricmp( *LocalFilename, TEXT("Engine") ) == 0)) { LocalFilename = SandboxFile.GetAbsoluteRootDirectory() / LocalFilename; } diff --git a/Engine/Source/Runtime/ShaderCore/Private/Shader.cpp b/Engine/Source/Runtime/ShaderCore/Private/Shader.cpp index 372b352e318f..da0db6f42be5 100644 --- a/Engine/Source/Runtime/ShaderCore/Private/Shader.cpp +++ b/Engine/Source/Runtime/ShaderCore/Private/Shader.cpp @@ -488,9 +488,12 @@ void FShaderResource::Serialize(FArchive& Ar) { INC_DWORD_STAT_BY_FName(GetMemoryStatType((EShaderFrequency)Target.Frequency).GetName(), (int64)Code.Num()); INC_DWORD_STAT_BY(STAT_Shaders_ShaderResourceMemory, GetSizeBytes()); - - FShaderCache::LogShader((EShaderPlatform)Target.Platform, (EShaderFrequency)Target.Frequency, OutputHash, UncompressedCodeSize, Code); + if (FShaderCache::GetShaderCache()) + { + FShaderCache::LogShader((EShaderPlatform)Target.Platform, (EShaderFrequency)Target.Frequency, OutputHash, UncompressedCodeSize, Code); + } + // The shader resource has been serialized in, so this shader resource is now initialized. check(Canary != FShader::ShaderMagic_CleaningUp); Canary = FShader::ShaderMagic_Initialized; @@ -1864,8 +1867,8 @@ void ShaderMapAppendKeyString(EShaderPlatform Platform, FString& KeyString) } { - static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.ForwardShading")); - if (CVar && CVar->GetValueOnAnyThread() > 0) + static const auto CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.ForwardShading")); + if (CVar && CVar->GetInt() > 0) { KeyString += TEXT("_FS"); } diff --git a/Engine/Source/Runtime/ShaderCore/Private/ShaderCache.cpp b/Engine/Source/Runtime/ShaderCore/Private/ShaderCache.cpp index 2e23b9d558f4..42878d4469cc 100644 --- a/Engine/Source/Runtime/ShaderCore/Private/ShaderCache.cpp +++ b/Engine/Source/Runtime/ShaderCore/Private/ShaderCache.cpp @@ -15,6 +15,7 @@ #include "Shader.h" #include "Misc/EngineVersion.h" #include "PipelineStateCache.h" +#include "ScopeRWLock.h" DECLARE_STATS_GROUP(TEXT("Shader Cache"),STATGROUP_ShaderCache, STATCAT_Advanced); DECLARE_DWORD_ACCUMULATOR_STAT(TEXT("Num Shaders Cached"),STATGROUP_NumShadersCached,STATGROUP_ShaderCache); @@ -58,6 +59,14 @@ FAutoConsoleVariableRef FShaderCache::CVarUseShaderCaching( ECVF_ReadOnly|ECVF_RenderThreadSafe ); +int32 FShaderCache::bUseUserShaderCache = 1; +FAutoConsoleVariableRef FShaderCache::CVarUseUserShaderCache( + TEXT("r.UseUserShaderCache"), + bUseUserShaderCache, + TEXT("If true, shader caching will use (and store) draw-log from a user directory, otherwise only draw-log stored in game content directory"), + ECVF_RenderThreadSafe + ); + // Predrawing takes an existing shader cache with draw log & renders each shader + draw-state combination before use to avoid in-driver recompilation // This requires plenty of setup & is done in batches at frame-end. int32 FShaderCache::bUseShaderPredraw = SHADER_CACHE_ENABLED; @@ -625,7 +634,8 @@ static bool ShaderPlatformCanPrebindBoundShaderState(EShaderPlatform Platform) { case SP_PCD3D_SM5: case SP_PS4: - case SP_XBOXONE: + case SP_XBOXONE_D3D11: + case SP_XBOXONE_D3D12: case SP_PCD3D_SM4: case SP_PCD3D_ES2: case SP_METAL: @@ -635,19 +645,19 @@ static bool ShaderPlatformCanPrebindBoundShaderState(EShaderPlatform Platform) case SP_METAL_SM5: case SP_METAL_MACES3_1: case SP_METAL_MACES2: + case SP_OPENGL_PCES2: + case SP_OPENGL_ES2_ANDROID: + case SP_OPENGL_ES3_1_ANDROID: + case SP_OPENGL_ES31_EXT: + case SP_OPENGL_ES2_IOS: case SP_SWITCH: case SP_SWITCH_FORWARD: { return true; } case SP_OPENGL_SM4: - case SP_OPENGL_PCES2: case SP_OPENGL_SM5: - case SP_OPENGL_ES2_ANDROID: case SP_OPENGL_ES2_WEBGL: - case SP_OPENGL_ES2_IOS: - case SP_OPENGL_ES31_EXT: - case SP_OPENGL_ES3_1_ANDROID: default: { return false; @@ -704,7 +714,7 @@ void FShaderCache::InitShaderCache(uint32 Options) if(bUseShaderCaching) { Cache = new FShaderCache(Options); - } + } } void FShaderCache::LoadBinaryCache() @@ -736,13 +746,13 @@ void FShaderCache::LoadBinaryCache() bool bLoadedUserCache = LoadShaderCache(UserBinaryShaderFile, &Cache->Caches); // Fallback to game-content version. - if ( !bLoadedUserCache ) + if (!bLoadedUserCache) { LoadShaderCache(GameBinaryShaderFile, &Cache->Caches); } // Make sure relevant platform caches are already setup - for(size_t FeatureLevel = 0;FeatureLevel < ERHIFeatureLevel::Num;++FeatureLevel) + for (size_t FeatureLevel = 0; FeatureLevel < ERHIFeatureLevel::Num; ++FeatureLevel) { Cache->Caches.PlatformCaches.FindOrAdd(GShaderPlatformForFeatureLevel[FeatureLevel]); } @@ -841,11 +851,11 @@ void FShaderCache::LoadBinaryCache() // Regardless of the presence of the platform specific file we want an modifiable FShaderCacheLibrary to catch any outliers. FShaderCacheLibrary* ShaderCacheLib = new FShaderCacheLibrary(ShaderPlat,GShaderCodeCacheFileName); ShaderCacheLib->AddRef(); - + // Try to load user cache, making sure that if we fail version test we still try game-content version. bool bLoadedCache = ShaderCacheLib->Load(FPaths::GameSavedDir()); Cache->CodeCache.Add(ShaderPlat,ShaderCacheLib); - + Cache->CachedShaderLibraries.Add( ShaderPlat, ShaderCacheLib ); if (bLoadedCache) @@ -933,7 +943,7 @@ void FShaderCache::ShutdownShaderCache() { delete Cache; Cache = nullptr; - } + } } FShaderCache::FShaderCache(uint32 InOptions) @@ -943,12 +953,9 @@ FShaderCache::FShaderCache(uint32 InOptions) , OverridePrecompileTime(0) , OverridePredrawBatchTime(0) , bBatchingPaused(false) -, ShaderCacheGlobalStateMutex(0) -, PipelineStateMutex(1) -, DrawLogMutex(2) -, ContextCacheStatesMutex(3) , DefaultCacheState(nullptr) { + MaxTextureSamplers = FMath::Min(GetMaxTextureSamplers(), FShaderDrawKey::MaxNumSamplers); FShaderDrawKey::bTrackDrawResources = ShaderPlatformPrebindRequiresResource(GMaxRHIShaderPlatform); } @@ -2577,6 +2584,7 @@ FTextureRHIRef FShaderCache::InternalCreateTexture(FShaderTextureKey const& Text case SCTT_Buffer: case SCTT_Texture1D: case SCTT_Texture1DArray: + case SCTT_TextureExternal2D: default: { check(false); @@ -3201,6 +3209,8 @@ bool FShaderCache::LoadShaderCache(FString Path, FShaderCaches* InCache) bool FShaderCache::SaveShaderCache(FString Path, FShaderCaches* InCache) { + UE_LOG(LogRHI, Log, TEXT("Saving shader cache: %s"), *Path); + FArchive* BinaryShaderAr = IFileManager::Get().CreateFileWriter(*Path); if( BinaryShaderAr != NULL ) { diff --git a/Engine/Source/Runtime/ShaderCore/Private/ShaderCacheTypes.cpp b/Engine/Source/Runtime/ShaderCore/Private/ShaderCacheTypes.cpp index a5bf8532ad8f..46a583e7bbd2 100644 --- a/Engine/Source/Runtime/ShaderCore/Private/ShaderCacheTypes.cpp +++ b/Engine/Source/Runtime/ShaderCore/Private/ShaderCacheTypes.cpp @@ -8,10 +8,6 @@ #include "ShaderCache.h" #include "Serialization/MemoryWriter.h" -#if RWLOCK_DEBUG_CHECKS -thread_local TArray FRWMutex::LockLevels; -#endif - bool FShaderDrawKey::bTrackDrawResources = true; FArchive& operator<<( FArchive& Ar, FShaderCaches& Info ) diff --git a/Engine/Source/Runtime/ShaderCore/Private/ShaderCodeLibrary.cpp b/Engine/Source/Runtime/ShaderCore/Private/ShaderCodeLibrary.cpp index 758702ba1a15..1f3c8daadac7 100644 --- a/Engine/Source/Runtime/ShaderCore/Private/ShaderCodeLibrary.cpp +++ b/Engine/Source/Runtime/ShaderCore/Private/ShaderCodeLibrary.cpp @@ -522,7 +522,11 @@ struct FEditorShaderCodeArchive bool PackageNativeShaderLibrary(const FString& ShaderCodeDir, const FString& DebugShaderCodeDir) { bool bOK = false; - FString TempPath = GetShaderCodeFilename(FPaths::GameIntermediateDir(), FormatName) / TEXT("NativeLibrary"); + + FString IntermediateFormatPath = GetShaderCodeFilename(FPaths::GameIntermediateDir(), FormatName); + FString IntermediateCookedByteCodePath = IntermediateFormatPath / TEXT("NativeCookedByteCode"); + FString TempPath = IntermediateFormatPath / TEXT("NativeLibrary"); + EShaderPlatform Platform = ShaderFormatToLegacyShaderPlatform(FormatName); IShaderFormatArchive* Archive = Format->CreateShaderArchive(FormatName, TempPath); if (Archive) @@ -531,8 +535,23 @@ struct FEditorShaderCodeArchive FString DebugPath = GetShaderCodeFilename(DebugShaderCodeDir, FormatName); bOK = true; + //Collect previous native cooked bytecode files into this shader files processing directory - keep the rest of the code simpler, don't overwrite in case dest file is newer + { + TArray NativeShaderFiles; + IFileManager::Get().FindFiles(NativeShaderFiles, *IntermediateCookedByteCodePath, TEXT("*.ushaderbytecode")); + + for (FString const& FileName : NativeShaderFiles) + { + if (FileName.Len() > 2 && FileName[1] == TEXT('_')) + { + IFileManager::Get().Move(*(OutputPath / FileName), *(IntermediateCookedByteCodePath / FileName), false); + } + } + } + TArray ShaderFiles; IFileManager::Get().FindFiles(ShaderFiles, *OutputPath, TEXT("*.ushaderbytecode")); + for (FString const& FileName : ShaderFiles) { if (FileName.Len() > 2 && FileName[1] == TEXT('_')) @@ -580,9 +599,21 @@ struct FEditorShaderCodeArchive { bOK = Archive->Finalize(ShaderCodeDir, DebugPath, nullptr); + //Always delete debug directory + IFileManager::Get().DeleteDirectory(*DebugShaderCodeDir, true, true); + + //Move files to intermediate dir for next iterative cook with overwwrite Move mode if (bOK) { - IFileManager::Get().DeleteDirectory(*DebugPath, true, true); + for (FString const& FileName : ShaderFiles) + { + if (FileName.Len() > 2 && FileName[1] == TEXT('_')) + { + IFileManager::Get().Move(*(IntermediateCookedByteCodePath / FileName), *(OutputPath / FileName), true); + } + } + + //We don't want to keep the shader code library shader files for native cooked content IFileManager::Get().DeleteDirectory(*OutputPath, true, true); } } @@ -655,6 +686,8 @@ public: if(ShaderCodeArchive.IsValid()) { bNativeFormat = true; + + UE_LOG(LogTemp, Display, TEXT("Cooked Context: Loaded Native Format Shared Shader Library")); } else { @@ -663,6 +696,8 @@ public: { ShaderCodeArchive = new FShaderCodeArchive(ShaderPlatform, Filename); bSupportsPipelines = (ShaderCodeArchive != nullptr); + + UE_LOG(LogTemp, Display, TEXT("Cooked Context: Using Shared Shader Library")); } } return IsValidRef(ShaderCodeArchive); diff --git a/Engine/Source/Runtime/ShaderCore/Private/ShaderCore.cpp b/Engine/Source/Runtime/ShaderCore/Private/ShaderCore.cpp index a4d0a3623ee7..9773489ebf09 100644 --- a/Engine/Source/Runtime/ShaderCore/Private/ShaderCore.cpp +++ b/Engine/Source/Runtime/ShaderCore/Private/ShaderCore.cpp @@ -207,15 +207,15 @@ void FShaderCompilerOutput::GenerateOutputHash() */ static void AddShaderSourceFileEntry( TArray& ShaderSourceFiles, const FString& ShaderFilename) { - FString ShaderFilenameBase( FPaths::GetBaseFilename(ShaderFilename) ); + FString ShaderRelativeFilename = FindShaderRelativePath(ShaderFilename); // get the filename for the the vertex factory type - if( !ShaderSourceFiles.Contains(ShaderFilenameBase) ) + if( !ShaderSourceFiles.Contains(ShaderRelativeFilename) ) { - ShaderSourceFiles.Add(ShaderFilenameBase); + ShaderSourceFiles.Add(ShaderRelativeFilename); TArray ShaderIncludes; - GetShaderIncludes(*ShaderFilenameBase,ShaderIncludes); + GetShaderIncludes(*ShaderRelativeFilename,ShaderIncludes); for( int32 IncludeIdx=0; IncludeIdx < ShaderIncludes.Num(); IncludeIdx++ ) { ShaderSourceFiles.AddUnique(ShaderIncludes[IncludeIdx]); @@ -448,8 +448,10 @@ void GetShaderIncludes(const TCHAR* Filename, TArray& IncludeFilenames, // ignore the header if it's optional and doesn't exist if (bIsOptionalInclude) { - FString ShaderFilename = FPaths::Combine(FPlatformProcess::BaseDir(), FPlatformProcess::ShaderDir(), *ExtractedIncludeFilename); - if (!FPaths::FileExists(ShaderFilename)) + // Search in the default engine shader folder and in the same folder as the shader (in case its a project or plugin shader) + FString EngineShaderFilename = FPaths::Combine(FPlatformProcess::BaseDir(), FPlatformProcess::ShaderDir(), *ExtractedIncludeFilename); + FString LocalShaderFilename = FPaths::Combine(FPaths::GetPath(Filename), *ExtractedIncludeFilename); + if (!FPaths::FileExists(EngineShaderFilename) && !FPaths::FileExists(LocalShaderFilename)) { bIgnoreInclude = true; } @@ -458,10 +460,9 @@ void GetShaderIncludes(const TCHAR* Filename, TArray& IncludeFilenames, //vertex factories need to be handled separately if (!bIgnoreInclude) { - GetShaderIncludes(*ExtractedIncludeFilename, IncludeFilenames, DepthLimit - 1); - // maintain subdirectory info, but strip the extension - ExtractedIncludeFilename = FPaths::GetBaseFilename(ExtractedIncludeFilename, false); - IncludeFilenames.AddUnique(ExtractedIncludeFilename); + FString RelativeFilename = FindShaderRelativePath(ExtractedIncludeFilename); + GetShaderIncludes(*RelativeFilename, IncludeFilenames, DepthLimit - 1); + IncludeFilenames.AddUnique(RelativeFilename); } } } @@ -483,7 +484,8 @@ static void UpdateSingleShaderFilehash(FSHA1& InOutHashState, const TCHAR* Filen { // Get the list of includes this file contains TArray IncludeFilenames; - GetShaderIncludes(Filename, IncludeFilenames); + FString RelativeFilename = FindShaderRelativePath(Filename); + GetShaderIncludes(*RelativeFilename, IncludeFilenames); for (int32 IncludeIndex = 0; IncludeIndex < IncludeFilenames.Num(); IncludeIndex++) { @@ -495,7 +497,7 @@ static void UpdateSingleShaderFilehash(FSHA1& InOutHashState, const TCHAR* Filen // Load the source file and hash it FString FileContents; - LoadShaderSourceFileChecked(Filename, FileContents); + LoadShaderSourceFileChecked(*RelativeFilename, FileContents); InOutHashState.UpdateWithString(*FileContents, FileContents.Len()); } @@ -573,6 +575,49 @@ const FSHAHash& GetShaderFilesHash(const TArray& Filenames) } } +extern SHADERCORE_API FString FindShaderRelativePath(const FString Filename) +{ + bool bHadExtension = true; + FString ShaderFilename = Filename; + if (FPaths::GetExtension(ShaderFilename) == TEXT("")) + { + bHadExtension = false; + ShaderFilename += TEXT(".usf"); + } + + bool bFound = false; + FString ShaderPath; + for (FString ShaderDir : FPlatformProcess::AllShaderDirs()) + { + FString Path = FPaths::Combine(FPlatformProcess::BaseDir(), ShaderDir, ShaderFilename); + if (FPaths::FileExists(Path)) + { + ShaderPath = Path; + FPaths::MakePathRelativeTo(ShaderPath, *FPaths::Combine(FPlatformProcess::ShaderDir(), TEXT("/"))); + bFound = true; + break; + } + } + if (!bFound) + { + UE_LOG(LogShaders, Fatal, TEXT("Couldn't find shader file \'%s\'"), *Filename); + UE_LOG(LogShaders, Fatal, TEXT("Known shader dirs:")); + for (FString ShaderDir : FPlatformProcess::AllShaderDirs()) + { + UE_LOG(LogShaders, Fatal, TEXT(" %s"), *ShaderDir); + } + } + + // If the filename didn't provide an extension, remove extension in returned path + // Extension are added in many places, don't want to end up with double extensions + if (!bHadExtension) + { + ShaderPath = FPaths::SetExtension(ShaderPath, TEXT("")); + } + + return ShaderPath; +} + void BuildShaderFileToUniformBufferMap(TMap >& ShaderFileToUniformBufferVariables) { if (!FPlatformProperties::RequiresCookedData()) @@ -685,8 +730,9 @@ void GenerateReferencedUniformBuffers( TMap& UniformBufferEntries) { TArray FilesToSearch; - GetShaderIncludes(SourceFilename, FilesToSearch); - FilesToSearch.Add(SourceFilename); + FString ShaderRelativeFilename = FindShaderRelativePath(SourceFilename); + GetShaderIncludes(*ShaderRelativeFilename, FilesToSearch); + FilesToSearch.Add(ShaderRelativeFilename); for (int32 FileIndex = 0; FileIndex < FilesToSearch.Num(); FileIndex++) { diff --git a/Engine/Source/Runtime/ShaderCore/Public/Shader.h b/Engine/Source/Runtime/ShaderCore/Public/Shader.h index 61021fda85b5..f0f1c051d26b 100644 --- a/Engine/Source/Runtime/ShaderCore/Public/Shader.h +++ b/Engine/Source/Runtime/ShaderCore/Public/Shader.h @@ -1417,13 +1417,18 @@ class TShaderMap TArray SerializedShaders; /** List of serialzied shader pipeline stages to be processed and registered on the game thread */ TArray SerializedShaderPipelines; +protected: + /** The platform this shader map was compiled with */ + EShaderPlatform Platform; +private: /** Flag that makes sure this shader map isn't used until all shaders have been registerd */ bool bHasBeenRegistered; public: /** Default constructor. */ - TShaderMap() - : bHasBeenRegistered(true) + TShaderMap(EShaderPlatform InPlatform) + : Platform(InPlatform) + , bHasBeenRegistered(true) {} /** Destructor ensures pipelines cleared up. */ @@ -1432,13 +1437,15 @@ public: EmptyShaderPipelines(); } + EShaderPlatform GetShaderPlatform() const { return Platform; } + /** Finds the shader with the given type. Asserts on failure. */ template ShaderType* GetShader() const { check(bHasBeenRegistered); const TRefCountPtr* ShaderRef = Shaders.Find(&ShaderType::StaticType); - checkf(ShaderRef != NULL && *ShaderRef != nullptr, TEXT("Failed to find shader type %s"), ShaderType::StaticType.GetName()); + checkf(ShaderRef != NULL && *ShaderRef != nullptr, TEXT("Failed to find shader type %s in Platform %s"), ShaderType::StaticType.GetName(), *LegacyShaderPlatformToShaderFormat(Platform).ToString()); return (ShaderType*)((*ShaderRef)->GetShaderChecked()); } diff --git a/Engine/Source/Runtime/ShaderCore/Public/ShaderCache.h b/Engine/Source/Runtime/ShaderCore/Public/ShaderCache.h index 6c7ce3d258d6..45f098f99cbf 100644 --- a/Engine/Source/Runtime/ShaderCore/Public/ShaderCache.h +++ b/Engine/Source/Runtime/ShaderCore/Public/ShaderCache.h @@ -709,10 +709,10 @@ private: bool bBatchingPaused; //Thread access mutual exclusion - mutable FRWMutex ShaderCacheGlobalStateMutex; - mutable FRWMutex PipelineStateMutex; - mutable FRWMutex DrawLogMutex; - mutable FRWMutex ContextCacheStatesMutex; + mutable FRWLock ShaderCacheGlobalStateMutex; + mutable FRWLock PipelineStateMutex; + mutable FRWLock DrawLogMutex; + mutable FRWLock ContextCacheStatesMutex; //List of states per RHI context with a default state FShaderCacheState* DefaultCacheState; @@ -721,6 +721,7 @@ private: static FShaderCache* Cache; static int32 GameVersion; static int32 bUseShaderCaching; + static int32 bUseUserShaderCache; static int32 bUseShaderPredraw; static int32 bUseShaderDrawLog; static int32 PredrawBatchTime; @@ -733,6 +734,7 @@ private: static uint32 MaxTextureSamplers; static uint8 MaxResources; static FAutoConsoleVariableRef CVarUseShaderCaching; + static FAutoConsoleVariableRef CVarUseUserShaderCache; static FAutoConsoleVariableRef CVarUseShaderPredraw; static FAutoConsoleVariableRef CVarUseShaderDrawLog; static FAutoConsoleVariableRef CVarPredrawBatchTime; diff --git a/Engine/Source/Runtime/ShaderCore/Public/ShaderCacheTypes.h b/Engine/Source/Runtime/ShaderCore/Public/ShaderCacheTypes.h index 5332875941c9..03c63e38604e 100644 --- a/Engine/Source/Runtime/ShaderCore/Public/ShaderCacheTypes.h +++ b/Engine/Source/Runtime/ShaderCore/Public/ShaderCacheTypes.h @@ -10,187 +10,6 @@ ShaderCacheTypes.h: Shader Cache Types #include "RHI.h" #include "RHIDefinitions.h" -/** - * FRWMutex - Read/Write Mutex - * - Provides Read/Write (or shared-exclusive) access. - * - As a fallback default for non implemented platforms, using a single FCriticalSection to provide complete single mutual exclusion - no seperate Read/Write access. - * - * TODOs: - * - Add Xbox and Windows specific lock structures/calls Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/aa904937(v=vs.85).aspx - * Notes: - * - pThreads and Win32 API's don't provide a mechanism for upgrading a ownership of a read lock to a write lock - to get round that this system unlocks then acquires a write lock. - * - If trying to use system described here (https://en.wikipedia.org/wiki/Readers–writer_lock) to implement a read-write lock: - * - The two mutex solution relies on a seperate thread being able to unlock a mutex locked on a different thread (Needs more work than described to implement if this is not the case). - * - Doesn't seem to be a generic 'engine' conditional variable for the mutex+conditional solution. - * - Currently has an experimental thread_local lock level implementation (set DEVELOPER_TEST_RWLOCK_LEVELS to 1) for potential deadlock detection (see: http://www.drdobbs.com/parallel/use-lock-hierarchies-to-avoid-deadlock/204801163?pgno=4) - * - Define the locking order by passing an integer in the Mutex constructor - * - To avoid deadlocks lock in increasing sequence order (can miss ones out but can't go lower) - * - Asserts if trying to get a same or lower level lock as this could result in deadlock depending on situation/timing etc. - */ - -#define DEVELOPER_TEST_RWLOCK_LEVELS 0 -#define RWLOCK_DEBUG_CHECKS (DO_CHECK && PLATFORM_DESKTOP && !UE_BUILD_SHIPPING && !UE_BUILD_SHIPPING_WITH_EDITOR && DEVELOPER_TEST_RWLOCK_LEVELS) - -class FRWMutex -{ - friend class FRWScopeLock; - -public: - - // Default to level zero, we are not allowed to take another at the same level or lower - so no more than one 'default' mutex at once - FRWMutex(uint32 Level = 0) -#if RWLOCK_DEBUG_CHECKS - : MutexLevel(Level) -#endif - { -#if PLATFORM_USE_PTHREADS - int Err = pthread_rwlock_init(&Mutex, nullptr); - checkf(Err == 0, TEXT("pthread_rwlock_init failed with error: %d"), Err); -#endif - } - - ~FRWMutex() - { -#if PLATFORM_USE_PTHREADS - int Err = pthread_rwlock_destroy(&Mutex); - checkf(Err == 0, TEXT("pthread_rwlock_destroy failed with error: %d"), Err); -#endif - } - -private: - -#if RWLOCK_DEBUG_CHECKS - void CheckAndAddLockLevel() - { - if(LockLevels.Num()) - { - uint32 Last = LockLevels.Last(); - check(MutexLevel > Last && "Trying to lock on an object with the same or lower level, options: [change lock order|change lock level values|disable this]"); - } - - LockLevels.Add(MutexLevel); - } -#endif - - void ReadLock() - { -#if RWLOCK_DEBUG_CHECKS - CheckAndAddLockLevel(); -#endif - -#if PLATFORM_USE_PTHREADS - int Err = pthread_rwlock_rdlock(&Mutex); - checkf(Err == 0, TEXT("pthread_rwlock_rdlock failed with error: %d"), Err); -#else - Mutex.Lock(); -#endif - } - - void WriteLock() - { -#if RWLOCK_DEBUG_CHECKS - CheckAndAddLockLevel(); -#endif - -#if PLATFORM_USE_PTHREADS - int Err = pthread_rwlock_wrlock(&Mutex); - checkf(Err == 0, TEXT("pthread_rwlock_wrlock failed with error: %d"), Err); -#else - Mutex.Lock(); -#endif - } - - void Unlock() - { -#if PLATFORM_USE_PTHREADS - int Err = pthread_rwlock_unlock(&Mutex); - checkf(Err == 0, TEXT("pthread_rwlock_unlock failed with error: %d"), Err); -#else - Mutex.Unlock(); -#endif - -#if RWLOCK_DEBUG_CHECKS - LockLevels.Pop(); -#endif - } - - void RaiseLockToWrite() - { -#if PLATFORM_USE_PTHREADS - int Err = pthread_rwlock_unlock(&Mutex); - checkf(Err == 0, TEXT("pthread_rwlock_unlock failed with error: %d"), Err); - Err = pthread_rwlock_wrlock(&Mutex); - checkf(Err == 0, TEXT("pthread_rwlock_wrlock failed with error: %d"), Err); -#else - //NOP -#endif - } - -private: -#if PLATFORM_USE_PTHREADS - pthread_rwlock_t Mutex; -#else - FCriticalSection Mutex; -#endif - -#if RWLOCK_DEBUG_CHECKS - uint32 MutexLevel; - static thread_local TArray LockLevels; -#endif -}; - -// -// A scope lifetime controlled Read or Write lock of referenced mutex object -// -enum FRWScopeLockType -{ - SLT_ReadOnly = 0, - SLT_Write, -}; - -class FRWScopeLock -{ -public: - FRWScopeLock(FRWMutex& InLockObject,FRWScopeLockType InLockType) - : LockObject(InLockObject) - , LockType(InLockType) - { - if(LockType != SLT_ReadOnly) - { - LockObject.WriteLock(); - } - else - { - LockObject.ReadLock(); - } - } - - void RaiseLockToWrite() - { - if(LockType == SLT_ReadOnly) - { - LockObject.RaiseLockToWrite(); - LockType = SLT_Write; - } - } - - ~FRWScopeLock() - { - LockObject.Unlock(); - } - -private: - - FRWScopeLock(); - FRWScopeLock(const FRWScopeLock&); - FRWScopeLock& operator=(const FRWScopeLock&); - -private: - FRWMutex& LockObject; - FRWScopeLockType LockType; -}; - - /** Texture type enum for shader cache draw keys */ enum EShaderCacheTextureType { @@ -202,7 +21,8 @@ enum EShaderCacheTextureType SCTT_Texture1DArray, SCTT_Texture2DArray, SCTT_TextureCubeArray, - SCTT_Buffer + SCTT_Buffer, + SCTT_TextureExternal2D }; /** The minimum texture state required for logging shader draw states */ diff --git a/Engine/Source/Runtime/ShaderCore/Public/ShaderCore.h b/Engine/Source/Runtime/ShaderCore/Public/ShaderCore.h index 6dd656eac8b1..caa1aa93224f 100644 --- a/Engine/Source/Runtime/ShaderCore/Public/ShaderCore.h +++ b/Engine/Source/Runtime/ShaderCore/Public/ShaderCore.h @@ -897,6 +897,11 @@ extern SHADERCORE_API const class FSHAHash& GetShaderFileHash(const TCHAR* Filen */ extern SHADERCORE_API const class FSHAHash& GetShaderFilesHash(const TArray& Filenames); +/** +* Find the shader in the potential shader directories (engine, project, plugins) relative to the engine shader folder +*/ +extern SHADERCORE_API FString FindShaderRelativePath(const FString Filename); + extern void BuildShaderFileToUniformBufferMap(TMap >& ShaderFileToUniformBufferVariables); /** diff --git a/Engine/Source/Runtime/ShaderCore/Public/ShaderParameterUtils.h b/Engine/Source/Runtime/ShaderCore/Public/ShaderParameterUtils.h index 18b460b36c72..f6bdb884546f 100644 --- a/Engine/Source/Runtime/ShaderCore/Public/ShaderParameterUtils.h +++ b/Engine/Source/Runtime/ShaderCore/Public/ShaderParameterUtils.h @@ -350,60 +350,70 @@ TRHICmdList& RHICmdList, } } -template -inline void SetUAVParameterIfCS(TRHICmdList& RHICmdList, TShaderRHIRef, const FShaderResourceParameter& UAVParameter, FUnorderedAccessViewRHIParamRef UAV) + +template +inline bool SetUAVParameterIfCS(TRHICmdList& RHICmdList, const FVertexShaderRHIParamRef Shader, const FShaderResourceParameter& UAVParameter, FUnorderedAccessViewRHIParamRef UAV) { + return false; } -template<> inline void SetUAVParameterIfCS(FRHICommandList& RHICmdList, FComputeShaderRHIParamRef ComputeShader,const FShaderResourceParameter& UAVParameter,FUnorderedAccessViewRHIParamRef UAV) +template +inline bool SetUAVParameterIfCS(TRHICmdList& RHICmdList, const FPixelShaderRHIParamRef Shader, const FShaderResourceParameter& UAVParameter, FUnorderedAccessViewRHIParamRef UAV) { - SetUAVParameter(RHICmdList, ComputeShader,UAVParameter,UAV); + return false; } -template<> inline void SetUAVParameterIfCS(FRHICommandList& RHICmdList, FComputeShaderRHIRef ComputeShader, const FShaderResourceParameter& UAVParameter, FUnorderedAccessViewRHIParamRef UAV) +template +inline bool SetUAVParameterIfCS(TRHICmdList& RHICmdList, const FHullShaderRHIParamRef Shader, const FShaderResourceParameter& UAVParameter, FUnorderedAccessViewRHIParamRef UAV) { - SetUAVParameter(RHICmdList, ComputeShader,UAVParameter,UAV); + return false; } -template<> inline void SetUAVParameterIfCS(FRHICommandListImmediate& RHICmdList, FComputeShaderRHIParamRef ComputeShader,const FShaderResourceParameter& UAVParameter,FUnorderedAccessViewRHIParamRef UAV) +template +inline bool SetUAVParameterIfCS(TRHICmdList& RHICmdList, const FDomainShaderRHIParamRef Shader, const FShaderResourceParameter& UAVParameter, FUnorderedAccessViewRHIParamRef UAV) { - SetUAVParameter(RHICmdList, ComputeShader,UAVParameter,UAV); + return false; } -template<> inline void SetUAVParameterIfCS(FRHICommandListImmediate& RHICmdList, FComputeShaderRHIRef ComputeShader, const FShaderResourceParameter& UAVParameter, FUnorderedAccessViewRHIParamRef UAV) +template +inline bool SetUAVParameterIfCS(TRHICmdList& RHICmdList, const FGeometryShaderRHIParamRef Shader, const FShaderResourceParameter& UAVParameter, FUnorderedAccessViewRHIParamRef UAV) { - SetUAVParameter(RHICmdList, ComputeShader,UAVParameter,UAV); + return false; } -template<> inline void SetUAVParameterIfCS(FRHIAsyncComputeCommandListImmediate& RHICmdList, FComputeShaderRHIParamRef ComputeShader, const FShaderResourceParameter& UAVParameter, FUnorderedAccessViewRHIParamRef UAV) +template +inline bool SetUAVParameterIfCS(TRHICmdList& RHICmdList, const FComputeShaderRHIParamRef Shader, const FShaderResourceParameter& UAVParameter, FUnorderedAccessViewRHIParamRef UAV) { - SetUAVParameter(RHICmdList, ComputeShader, UAVParameter, UAV); + SetUAVParameter(RHICmdList, Shader, UAVParameter, UAV); + return UAVParameter.IsBound(); } -template<> inline void SetUAVParameterIfCS(FRHIAsyncComputeCommandListImmediate& RHICmdList, FComputeShaderRHIRef ComputeShader, const FShaderResourceParameter& UAVParameter, FUnorderedAccessViewRHIParamRef UAV) -{ - SetUAVParameter(RHICmdList, ComputeShader, UAVParameter, UAV); -} template inline void FRWShaderParameter::SetBuffer(TRHICmdList& RHICmdList, TShaderRHIRef Shader, const FRWBuffer& RWBuffer) const { - SetSRVParameter(RHICmdList, Shader,SRVParameter,RWBuffer.SRV); - SetUAVParameterIfCS(RHICmdList, Shader,UAVParameter,RWBuffer.UAV); + if (!SetUAVParameterIfCS(RHICmdList, Shader, UAVParameter, RWBuffer.UAV)) + { + SetSRVParameter(RHICmdList, Shader, SRVParameter, RWBuffer.SRV); + } } template inline void FRWShaderParameter::SetBuffer(TRHICmdList& RHICmdList, TShaderRHIRef Shader, const FRWBufferStructured& RWBuffer) const { - SetSRVParameter(RHICmdList, Shader,SRVParameter,RWBuffer.SRV); - SetUAVParameterIfCS(RHICmdList, Shader,UAVParameter,RWBuffer.UAV); + if (!SetUAVParameterIfCS(RHICmdList, Shader, UAVParameter, RWBuffer.UAV)) + { + SetSRVParameter(RHICmdList, Shader, SRVParameter, RWBuffer.SRV); + } } template inline void FRWShaderParameter::SetTexture(TRHICmdList& RHICmdList, TShaderRHIRef Shader, const FTextureRHIParamRef Texture, FUnorderedAccessViewRHIParamRef UAV) const { - SetTextureParameter(RHICmdList, Shader,SRVParameter,Texture); - SetUAVParameterIfCS(RHICmdList, Shader,UAVParameter,UAV); + if (!SetUAVParameterIfCS(RHICmdList, Shader, UAVParameter, UAV)) + { + SetTextureParameter(RHICmdList, Shader, SRVParameter, Texture); + } } template diff --git a/Engine/Source/Runtime/ShaderCore/Public/VertexFactory.h b/Engine/Source/Runtime/ShaderCore/Public/VertexFactory.h index 10aa4c9e02ac..ba29ab76dbdf 100644 --- a/Engine/Source/Runtime/ShaderCore/Public/VertexFactory.h +++ b/Engine/Source/Runtime/ShaderCore/Public/VertexFactory.h @@ -413,12 +413,6 @@ public: */ virtual uint64 GetStaticBatchElementVisibility(const class FSceneView& View, const struct FMeshBatch* Batch) const { return 1; } - /** - * Get a bitmask representing the visibility of each FMeshBatch element for the shadow depths of a given light. - * FMeshBatch.bRequiresPerElementVisibility must be set for this to be called. - */ - virtual uint64 GetStaticBatchElementShadowVisibility(const class FSceneView& View, const class FLightSceneProxy* LightSceneProxy, const struct FMeshBatch* Batch) const { return GetStaticBatchElementVisibility(View, Batch); } - protected: /** diff --git a/Engine/Source/Runtime/Slate/Private/Framework/Application/GestureDetector.cpp b/Engine/Source/Runtime/Slate/Private/Framework/Application/GestureDetector.cpp new file mode 100644 index 000000000000..f23930a04fc1 --- /dev/null +++ b/Engine/Source/Runtime/Slate/Private/Framework/Application/GestureDetector.cpp @@ -0,0 +1,68 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#include "Framework/Application/GestureDetector.h" + +double FGestureDetector::LongPressSeconds = 0.800f; +float FGestureDetector::LongPressAllowedMovement = 0; + +bool FGestureDetector::IsGestureSupported(EGestureEvent::Type Gesture) +{ + switch ( Gesture ) + { + case EGestureEvent::LongPress: + return true; + default: + return false; + } +} + +void FGestureDetector::OnTouchStarted(int32 TouchIndex, const FVector2D& Location) +{ + if ( TouchIndex < EKeys::NUM_TOUCH_KEYS ) + { + LongPressTrack[TouchIndex].Reset(); + LongPressTrack[TouchIndex].Time = FPlatformTime::Seconds(); + LongPressTrack[TouchIndex].Location = Location; + } +} + +void FGestureDetector::OnTouchEnded(int32 TouchIndex, const FVector2D& Location) +{ + if ( TouchIndex < EKeys::NUM_TOUCH_KEYS ) + { + LongPressTrack[TouchIndex].Reset(); + } +} + +void FGestureDetector::OnTouchMoved(int32 TouchIndex, const FVector2D& Location) +{ + if ( TouchIndex < EKeys::NUM_TOUCH_KEYS ) + { + FVector2D Delta = ( Location - LongPressTrack[TouchIndex].Location ); + if ( Delta.Size() >= FGestureDetector::LongPressAllowedMovement ) + { + LongPressTrack[TouchIndex].Reset(); + } + } +} + +void FGestureDetector::GenerateGestures(FGenericApplicationMessageHandler& MessageHandler, const TBitArray& EnabledGestures) +{ + if ( EnabledGestures[EGestureEvent::LongPress] ) + { + const double CurrentTime = FPlatformTime::Seconds(); + + for ( int32 TouchIndex = 0; TouchIndex < EKeys::NUM_TOUCH_KEYS; TouchIndex++ ) + { + if ( LongPressTrack[TouchIndex].Time.IsSet() ) + { + const double DeltaTime = CurrentTime - LongPressTrack[TouchIndex].Time.GetValue(); + if ( DeltaTime >= FGestureDetector::LongPressSeconds ) + { + MessageHandler.OnTouchGesture(EGestureEvent::LongPress, FVector2D(0, 0), 0, false); + LongPressTrack[TouchIndex].Reset(); + } + } + } + } +} \ No newline at end of file diff --git a/Engine/Source/Runtime/Slate/Private/Framework/Application/MenuStack.cpp b/Engine/Source/Runtime/Slate/Private/Framework/Application/MenuStack.cpp index 0aa8e6905e0e..98a521fc831d 100644 --- a/Engine/Source/Runtime/Slate/Private/Framework/Application/MenuStack.cpp +++ b/Engine/Source/Runtime/Slate/Private/Framework/Application/MenuStack.cpp @@ -166,7 +166,7 @@ TSharedRef FMenuStack::PushMenu( const TSharedRef& ParentWindo FSlateRect Anchor(SummonLocation, SummonLocation + SummonLocationSize); FVector2D ExpectedSize(300, 200); - FVector2D AdjustedSummonLocation = FSlateApplication::Get().CalculatePopupWindowPosition(Anchor, ExpectedSize, Orient_Vertical); + FVector2D AdjustedSummonLocation = FSlateApplication::Get().CalculatePopupWindowPosition(Anchor, ExpectedSize, FVector2D::ZeroVector, Orient_Vertical); TSharedRef NewMenuWindow = SNew(SWindow) @@ -357,7 +357,7 @@ FMenuStack::FPrePushResults FMenuStack::PrePush(const FPrePushArgs& InArgs) if (ActiveMethod.GetPopupMethod() == EPopupMethod::CreateNewWindow) { // Places the menu's window in the work area - OutResults.AnimStartLocation = OutResults.AnimFinalLocation = FSlateApplication::Get().CalculatePopupWindowPosition(InArgs.Anchor, OutResults.ExpectedSize, Orientation); + OutResults.AnimStartLocation = OutResults.AnimFinalLocation = FSlateApplication::Get().CalculatePopupWindowPosition(InArgs.Anchor, OutResults.ExpectedSize, FVector2D::ZeroVector, Orientation); } else { diff --git a/Engine/Source/Runtime/Slate/Private/Framework/Application/SlateApplication.cpp b/Engine/Source/Runtime/Slate/Private/Framework/Application/SlateApplication.cpp index 780e3749bd14..d8b3e7cfb5b6 100644 --- a/Engine/Source/Runtime/Slate/Private/Framework/Application/SlateApplication.cpp +++ b/Engine/Source/Runtime/Slate/Private/Framework/Application/SlateApplication.cpp @@ -33,6 +33,7 @@ #include "GenericPlatform/ITextInputMethodSystem.h" #include "ToolboxModule.h" #include "Framework/Docking/TabCommands.h" +#include "Math/UnitConversion.h" #define SLATE_HAS_WIDGET_REFLECTOR !UE_BUILD_SHIPPING || PLATFORM_DESKTOP @@ -159,7 +160,6 @@ public: return RoutingPath; } - private: int32 WidgetIndex; const FWidgetPath& RoutingPath; @@ -298,9 +298,9 @@ FSlateUser::FSlateUser(int32 InUserIndex, bool InVirtualUser) : UserIndex(InUserIndex) , bVirtualUser(InVirtualUser) { - Focus.WidgetPath = FWidgetPath(); - Focus.FocusCause = EFocusCause::Cleared; - Focus.ShowFocus = false; + FocusWidgetPathWeak = FWidgetPath(); + FocusCause = EFocusCause::Cleared; + ShowFocus = false; } FSlateUser::~FSlateUser() @@ -309,14 +309,26 @@ FSlateUser::~FSlateUser() TSharedPtr FSlateUser::GetFocusedWidget() const { - if ( Focus.WidgetPath.IsValid() ) + if ( FocusWidgetPathWeak.IsValid() ) { - return Focus.WidgetPath.GetLastWidget().Pin(); + return FocusWidgetPathWeak.GetLastWidget().Pin(); } return TSharedPtr(); } +void FSlateUser::SetFocusPath(const FWidgetPath& InWidgetPath, EFocusCause InCause, bool InShowFocus) +{ + FocusWidgetPathStrong.Reset(); + FocusWidgetPathWeak = InWidgetPath; + FocusCause = InCause; + ShowFocus = InShowFocus; +} + +void FSlateUser::FinishFrame() +{ + FocusWidgetPathStrong.Reset(); +} FSlateVirtualUser::FSlateVirtualUser(int32 InUserIndex, int32 InVirtualUserIndex) : UserIndex(InUserIndex) @@ -479,7 +491,7 @@ bool FSlateApplication::MouseCaptorHelper::HasCaptureForUser(uint32 UserIndex) c bool FSlateApplication::MouseCaptorHelper::HasCaptureForPointerIndex(uint32 UserIndex, uint32 PointerIndex) const { - const FWeakWidgetPath* MouseCaptorWeakPath = PointerIndexToMouseCaptorWeakPathMap.Find( FUserAndPointer(UserIndex,PointerIndex) ); + const FWeakWidgetPath* MouseCaptorWeakPath = PointerIndexToMouseCaptorWeakPathMap.Find(FUserAndPointer(UserIndex, PointerIndex)); return MouseCaptorWeakPath && MouseCaptorWeakPath->IsValid(); } @@ -566,7 +578,7 @@ TSharedPtr< SWidget > FSlateApplication::MouseCaptorHelper::ToSharedWindow(uint3 return TSharedPtr< SWidget >(); } -void FSlateApplication::MouseCaptorHelper::SetMouseCaptor(uint32 UserIndex, uint32 PointerIndex, const FWidgetPath& EventPath, TSharedPtr< SWidget > Widget) +bool FSlateApplication::MouseCaptorHelper::SetMouseCaptor(uint32 UserIndex, uint32 PointerIndex, const FWidgetPath& EventPath, TSharedPtr< SWidget > Widget) { // Caller is trying to set a new mouse captor, so invalidate the current one - when the function finishes // it still may not have a valid captor widget, this is ok @@ -605,8 +617,11 @@ void FSlateApplication::MouseCaptorHelper::SetMouseCaptor(uint32 UserIndex, uint if (MouseCaptorWeakPath.IsValid()) { PointerIndexToMouseCaptorWeakPathMap.Add(FUserAndPointer(UserIndex,PointerIndex), MouseCaptorWeakPath); + return true; } } + + return false; } void FSlateApplication::MouseCaptorHelper::InvalidateCaptureForAllPointers() @@ -635,7 +650,7 @@ void FSlateApplication::MouseCaptorHelper::InvalidateCaptureForUser(uint32 UserI FWidgetPath FSlateApplication::MouseCaptorHelper::ToWidgetPath( FWeakWidgetPath::EInterruptedPathHandling::Type InterruptedPathHandling, const FPointerEvent* PointerEvent ) { FWidgetPath WidgetPath; - const FWeakWidgetPath* MouseCaptorWeakPath = PointerIndexToMouseCaptorWeakPathMap.Find(FUserAndPointer(PointerEvent->GetUserIndex(),PointerEvent->GetPointerIndex())); + const FWeakWidgetPath* MouseCaptorWeakPath = PointerIndexToMouseCaptorWeakPathMap.Find(FUserAndPointer(PointerEvent->GetUserIndex(), PointerEvent->GetPointerIndex())); if ( MouseCaptorWeakPath->IsValid() ) { if ( MouseCaptorWeakPath->ToWidgetPath( WidgetPath, InterruptedPathHandling, PointerEvent ) == FWeakWidgetPath::EPathResolutionResult::Truncated ) @@ -652,14 +667,14 @@ FWidgetPath FSlateApplication::MouseCaptorHelper::ToWidgetPath( FWeakWidgetPath: FWidgetPath FSlateApplication::MouseCaptorHelper::ToWidgetPath(uint32 UserIndex, uint32 PointerIndex, FWeakWidgetPath::EInterruptedPathHandling::Type InterruptedPathHandling) { FWidgetPath WidgetPath; - const FWeakWidgetPath* MouseCaptorWeakPath = PointerIndexToMouseCaptorWeakPathMap.Find(FUserAndPointer(UserIndex,PointerIndex)); + const FWeakWidgetPath* MouseCaptorWeakPath = PointerIndexToMouseCaptorWeakPathMap.Find(FUserAndPointer(UserIndex, PointerIndex)); if (MouseCaptorWeakPath && MouseCaptorWeakPath->IsValid() ) { if ( MouseCaptorWeakPath->ToWidgetPath( WidgetPath, InterruptedPathHandling ) == FWeakWidgetPath::EPathResolutionResult::Truncated ) { // If the path was truncated then it means this widget is no longer part of the active set, // so we make sure to invalidate its capture - InvalidateCaptureForPointer(UserIndex,PointerIndex); + InvalidateCaptureForPointer(UserIndex, PointerIndex); } } @@ -924,7 +939,7 @@ FSlateApplication::FSlateApplication() , bAppIsActive(true) , bSlateWindowActive(true) , Scale( 1.0f ) - , DragTriggerDistance( 5.0f ) + , DragTriggerDistance( 0 ) , CursorRadius( 0.0f ) , LastUserInteractionTime( 0.0 ) , LastUserInteractionTimeForThrottling( 0.0 ) @@ -937,7 +952,11 @@ FSlateApplication::FSlateApplication() , OnExitRequested() , EventLogger( TSharedPtr() ) , NumExternalModalWindowsActive( 0 ) +#if PLATFORM_UI_NEEDS_TOOLTIPS , bAllowToolTips( true ) +#else + , bAllowToolTips( false ) +#endif , ToolTipDelay( 0.15f ) , ToolTipFadeInDuration( 0.1f ) , ToolTipSummonTime( 0.0 ) @@ -969,19 +988,21 @@ FSlateApplication::FSlateApplication() , AppIcon( FCoreStyle::Get().GetBrush("DefaultAppIcon") ) , VirtualDesktopRect( 0,0,0,0 ) , NavigationConfig(MakeShareable(new FNavigationConfig())) + , SimulateGestures(false, EGestureEvent::Count) , ProcessingInput(0) { #if WITH_UNREAL_DEVELOPER_TOOLS FModuleManager::Get().LoadModule(TEXT("Settings")); #endif + SetupPhysicalSensitivities(); + if (GConfig) { - GConfig->GetBool(TEXT("MobileSlateUI"),TEXT("bTouchFallbackToMouse"),bTouchFallbackToMouse,GEngineIni); + GConfig->GetBool(TEXT("MobileSlateUI"), TEXT("bTouchFallbackToMouse"), bTouchFallbackToMouse, GEngineIni); GConfig->GetBool(TEXT("CursorControl"), TEXT("bAllowSoftwareCursor"), bSoftwareCursorAvailable, GEngineIni); } - // causes InputCore to initialize, even if statically linked FInputCoreModule& InputCore = FModuleManager::LoadModuleChecked(TEXT("InputCore")); @@ -989,10 +1010,14 @@ FSlateApplication::FSlateApplication() FTabCommands::Register(); NormalExecutionGetter.BindRaw( this, &FSlateApplication::IsNormalExecution ); - PointerIndexLastPositionMap.Add(CursorPointerIndex, FVector2D::ZeroVector); + + PointerIndexPositionMap.Add(FUserAndPointer(0, CursorPointerIndex), FVector2D::ZeroVector); + PointerIndexLastPositionMap.Add(FUserAndPointer(0, CursorPointerIndex), FVector2D::ZeroVector); // Add the standard 'default' user because there's always 1 user. RegisterUser(MakeShareable(new FSlateUser(0, false))); + + SimulateGestures[EGestureEvent::LongPress] = true; } FSlateApplication::~FSlateApplication() @@ -1007,6 +1032,24 @@ FSlateApplication::~FSlateApplication() } } +void FSlateApplication::SetupPhysicalSensitivities() +{ + const float DragTriggerDistanceInInches = FUnitConversion::Convert(1.0f, EUnit::Millimeters, EUnit::Inches); + FPlatformMisc::ConvertInchesToPixels(DragTriggerDistanceInInches, DragTriggerDistance); + + // TODO Rather than allow people to request the DragTriggerDistance directly, we should + // probably store a drag trigger distance for touch and mouse, and force users to pass + // the pointer event they're checking for, and if that pointer event is touch, use touch + // and if not touch, return mouse. +#if PLATFORM_DESKTOP + DragTriggerDistance = FMath::Max(DragTriggerDistance, 5.0f); +#else + DragTriggerDistance = FMath::Max(DragTriggerDistance, 10.0f); +#endif + + FGestureDetector::LongPressAllowedMovement = DragTriggerDistance; +} + const FStyleNode* FSlateApplication::GetRootStyle() const { return RootStyleNode; @@ -1062,12 +1105,14 @@ FVector2D FSlateApplication::GetCursorPos() const return Cursor->GetPosition(); } - return FVector2D( 0, 0 ); + const int32 UserIndex = 0; + return PointerIndexPositionMap.FindRef(FUserAndPointer(UserIndex, CursorPointerIndex)); } FVector2D FSlateApplication::GetLastCursorPos() const { - return PointerIndexLastPositionMap[CursorPointerIndex]; + const int32 UserIndex = 0; + return PointerIndexLastPositionMap.FindRef(FUserAndPointer(UserIndex, CursorPointerIndex)); } void FSlateApplication::SetCursorPos( const FVector2D& MouseCoordinate ) @@ -1467,9 +1512,9 @@ void FSlateApplication::FinishedInputThisFrame() { const float DeltaTime = GetDeltaTime(); - if (InputPreProcessor.IsValid() && PlatformApplication->Cursor.IsValid()) + if (PlatformApplication->Cursor.IsValid()) { - InputPreProcessor->Tick(DeltaTime, *this, PlatformApplication->Cursor.ToSharedRef()); + InputPreProcessors.Tick(DeltaTime, *this, PlatformApplication->Cursor.ToSharedRef()); } // All the input events have been processed. @@ -1505,11 +1550,11 @@ void FSlateApplication::FinishedInputThisFrame() } } - // Any widgets that may have recieved key events + // Any widgets that may have received key events // are given a chance to process accumulated values. ForEachUser([&] (FSlateUser* User) { - const FSlateUser::FUserFocusEntry& UserFocusEntry = User->Focus; - for ( const TWeakPtr& WidgetPtr : UserFocusEntry.WidgetPath.Widgets ) + const FWeakWidgetPath& WidgetPath = User->GetWeakFocusPath(); + for ( const TWeakPtr& WidgetPtr : WidgetPath.Widgets ) { const TSharedPtr& Widget = WidgetPtr.Pin(); if ( Widget.IsValid() ) @@ -1522,6 +1567,10 @@ void FSlateApplication::FinishedInputThisFrame() } } }); + + ForEachUser([&] (FSlateUser* User) { + User->FinishFrame(); + }); } void FSlateApplication::Tick(ESlateTickType TickType) @@ -1688,6 +1737,10 @@ void FSlateApplication::TickApplication(ESlateTickType TickType, float DeltaTime // as if the cursor moved over it. QueueSynthesizedMouseMove(); } + // Generate any simulated gestures that we've detected. + ForEachUser([&] (FSlateUser* User) { + User->GestureDetector.GenerateGestures(*this, SimulateGestures); + }); // Check if any element lists used for caching need to be released { @@ -1733,7 +1786,6 @@ void FSlateApplication::PumpMessages() PlatformApplication->PumpMessages( GetDeltaTime() ); } - void FSlateApplication::ThrottleApplicationBasedOnMouseMovement() { bool bShouldThrottle = false; @@ -1818,8 +1870,8 @@ FWidgetPath FSlateApplication::LocateWidgetInWindow(FVector2D ScreenspaceMouseCo const bool bAcceptsInput = Window->IsVisible() && (Window->AcceptsInput() || IsWindowHousingInteractiveTooltip(Window)); if (bAcceptsInput && Window->IsScreenspaceMouseWithin(ScreenspaceMouseCoordinate)) { - const TArray WidgetsAndCursors = Window->GetHittestGrid()->GetBubblePath(ScreenspaceMouseCoordinate, GetCursorRadius(), bIgnoreEnabledStatus); - return FWidgetPath(WidgetsAndCursors); + TArray WidgetsAndCursors = Window->GetHittestGrid()->GetBubblePath(ScreenspaceMouseCoordinate, GetCursorRadius(), bIgnoreEnabledStatus); + return FWidgetPath(MoveTemp(WidgetsAndCursors)); } else { @@ -2518,7 +2570,8 @@ void FSlateApplication::ResetToDefaultInputSettings() void FSlateApplication::ResetToDefaultPointerInputSettings() { - for (auto MouseCaptorPath : MouseCaptor.ToWidgetPaths()) + TArray CaptorPaths = MouseCaptor.ToWidgetPaths(); + for (const FWidgetPath& MouseCaptorPath : CaptorPaths ) { ProcessReply(MouseCaptorPath, FReply::Handled().ReleaseMouseCapture(), nullptr, nullptr); } @@ -2546,7 +2599,6 @@ void FSlateApplication::ReleaseMouseCaptureForUser(int32 UserIndex) MouseCaptor.InvalidateCaptureForUser(UserIndex); } - FDelegateHandle FSlateApplication::RegisterOnWindowActionNotification(const FOnWindowAction& Notification) { OnWindowActionNotifications.Add(Notification); @@ -2637,14 +2689,12 @@ bool FSlateApplication::SetUserFocus(FSlateUser* User, const FWidgetPath& InFocu { return false; } - - FUserFocusEntry& UserFocusEntry = User->Focus; - + TSharedPtr WidgetReflector = WidgetReflectorPtr.Pin(); const bool bReflectorShowingFocus = WidgetReflector.IsValid() && WidgetReflector->IsShowingFocus(); // Get the old Widget information - const FWeakWidgetPath OldFocusedWidgetPath = UserFocusEntry.WidgetPath; + const FWeakWidgetPath OldFocusedWidgetPath = User->GetWeakFocusPath(); TSharedPtr OldFocusedWidget = OldFocusedWidgetPath.IsValid() ? OldFocusedWidgetPath.GetLastWidget().Pin() : TSharedPtr< SWidget >(); // Get the new widget information by finding the first widget in the path that supports focus @@ -2707,28 +2757,25 @@ bool FSlateApplication::SetUserFocus(FSlateUser* User, const FWidgetPath& InFocu //UE_LOG(LogSlate, Warning, TEXT("Focus for user %i set to %s."), User->GetUserIndex(), NewFocusedWidget.IsValid() ? *NewFocusedWidget->ToString() : TEXT("Invalid")); - // Store a weak widget path to the widget that's taking focus - UserFocusEntry.WidgetPath = FWeakWidgetPath(NewFocusedWidgetPath); - - // Store the cause of the focus - UserFocusEntry.FocusCause = InCause; - // Figure out if we should show focus for this focus entry - UserFocusEntry.ShowFocus = false; + bool ShowFocus = false; if (NewFocusedWidgetPath.IsValid()) { - UserFocusEntry.ShowFocus = InCause == EFocusCause::Navigation; + ShowFocus = InCause == EFocusCause::Navigation; for (int32 WidgetIndex = NewFocusedWidgetPath.Widgets.Num() - 1; WidgetIndex >= 0; --WidgetIndex) { - TOptional ShowFocus = NewFocusedWidgetPath.Widgets[WidgetIndex].Widget->OnQueryShowFocus(InCause); - if (ShowFocus.IsSet()) + TOptional QueryShowFocus = NewFocusedWidgetPath.Widgets[WidgetIndex].Widget->OnQueryShowFocus(InCause); + if ( QueryShowFocus.IsSet()) { - UserFocusEntry.ShowFocus = ShowFocus.GetValue(); + ShowFocus = QueryShowFocus.GetValue(); break; } } } + // Store a weak widget path to the widget that's taking focus + User->SetFocusPath(NewFocusedWidgetPath, InCause, ShowFocus); + // Let the old widget know that it lost keyboard focus if(OldFocusedWidget.IsValid()) { @@ -2780,8 +2827,8 @@ void FSlateApplication::SetAllUserFocusAllowingDescendantFocus(const FWidgetPath TSharedRef FocusWidget = InFocusPath.Widgets.Last().Widget; ForEachUser([&] (FSlateUser* User) { - const FUserFocusEntry& UserFocusEntry = User->Focus; - if (!UserFocusEntry.WidgetPath.ContainsWidget(FocusWidget)) + const FWeakWidgetPath& WidgetPath = User->GetWeakFocusPath(); + if (!WidgetPath.ContainsWidget(FocusWidget)) { SetUserFocus(User, InFocusPath, InCause); } @@ -2985,8 +3032,28 @@ void FSlateApplication::ProcessReply( const FWidgetPath& CurrentEventPath, const // Do not capture the mouse if we are also starting a drag and drop. if (RequestedMouseCaptor.IsValid() && !bStartingDragDrop) { - MouseCaptor.SetMouseCaptor(UserIndex, PointerIndex, CurrentEventPath, RequestedMouseCaptor); + if ( MouseCaptor.SetMouseCaptor(UserIndex, PointerIndex, CurrentEventPath, RequestedMouseCaptor) ) + { + if ( WidgetsUnderMouse ) + { + // In the event that we've set a new mouse captor, we need to take every widget in-between the captor and the widget under the + // mouse and let them know that the mouse has left their bounds. + bool DoneRoutingLeave = false; + FEventRouter::Route(this, FEventRouter::FBubblePolicy(*WidgetsUnderMouse), *InMouseEvent, [&DoneRoutingLeave, &RequestedMouseCaptor] (const FArrangedWidget& SomeWidget, const FPointerEvent& PointerEvent) + { + if ( SomeWidget.Widget == RequestedMouseCaptor ) + { + DoneRoutingLeave = true; + } + else if(!DoneRoutingLeave) + { + SomeWidget.Widget->OnMouseLeave(PointerEvent); + } + return FNoReply(); + }); + } + } // When the cursor capture state changes we need to refresh cursor state. bQueryCursorRequested = true; } @@ -3010,7 +3077,8 @@ void FSlateApplication::ProcessReply( const FWidgetPath& CurrentEventPath, const if (RequestedMousePos.IsSet()) { const FVector2D Position = RequestedMousePos.GetValue(); - PointerIndexLastPositionMap.Add(CursorPointerIndex, Position); + PointerIndexPositionMap.Add(FUserAndPointer(UserIndex, PointerIndex), Position); + PointerIndexLastPositionMap.Add(FUserAndPointer(UserIndex, PointerIndex), Position); SetCursorPos(Position); } @@ -3055,8 +3123,8 @@ void FSlateApplication::ProcessReply( const FWidgetPath& CurrentEventPath, const } else if(const FSlateUser* User = GetOrCreateUser(UserIndex)) { - const FUserFocusEntry& UserFocusEntry = User->Focus; - NavigationSource = UserFocusEntry.WidgetPath.ToWidgetPath(); + TSharedRef EventPathRef = User->GetFocusPath(); + NavigationSource = EventPathRef.Get(); } if (NavigationSource.IsValid()) @@ -3398,9 +3466,24 @@ void FSlateApplication::CloseToolTip() void FSlateApplication::UpdateToolTip( bool AllowSpawningOfNewToolTips ) { + // Don't do anything if tooltips are not enabled. + if ( !bAllowToolTips ) + { + // The user may have disabled this while a tooltip was visible, like during a menu to game transition, if this + // happens we need to close the tool tip if it's still visible. + if ( ActiveToolTip.IsValid() ) + { + CloseToolTip(); + } + + return; + } + + SCOPE_CYCLE_COUNTER(STAT_SlateUpdateTooltip); + SLATE_CYCLE_COUNTER_SCOPE(GUpdateTooltipTime); + const bool bCheckForToolTipChanges = IsInGameThread() && // We should never allow the slate loading thread to create new windows or interact with the hittest grid - bAllowToolTips && // Tool-tips must be enabled !IsUsingHighPrecisionMouseMovment() && // If we are using HighPrecision movement then we can't rely on the OS cursor to be accurate !IsDragDropping(); // We must not currwently be in the middle of a drag-drop action @@ -3858,23 +3941,61 @@ float FSlateApplication::GetDragTriggerDistance() const return DragTriggerDistance; } +float FSlateApplication::GetDragTriggerDistanceSquared() const +{ + return DragTriggerDistance * DragTriggerDistance; +} + +bool FSlateApplication::HasTraveledFarEnoughToTriggerDrag(const FPointerEvent& PointerEvent, const FVector2D ScreenSpaceOrigin) const +{ + return ( PointerEvent.GetScreenSpacePosition() - ScreenSpaceOrigin ).SizeSquared() >= ( DragTriggerDistance * DragTriggerDistance ); +} + void FSlateApplication::SetDragTriggerDistance( float ScreenPixels ) { DragTriggerDistance = ScreenPixels; } -void FSlateApplication::SetInputPreProcessor(bool bEnable, TSharedPtr NewInputProcessor) +void FSlateApplication::SetInputPreProcessor(bool bEnable, TSharedPtr NewInputProcessor /*= nullptr*/) { - if (bEnable && NewInputProcessor.IsValid()) + if (bEnable) { - InputPreProcessor = NewInputProcessor; + RegisterInputPreProcessor(NewInputProcessor); } else { - InputPreProcessor.Reset(); + if ( NewInputProcessor.IsValid() ) + { + UnregisterInputPreProcessor(NewInputProcessor); + } + else + { + UnregisterAllInputPreProcessors(); + } } } +bool FSlateApplication::RegisterInputPreProcessor(TSharedPtr InputProcessor, const int32 Index /*= INDEX_NONE*/) +{ + bool bResult = false; + if ( InputProcessor.IsValid() ) + { + bResult = InputPreProcessors.Add(InputProcessor, Index); + } + + return bResult; +} + +void FSlateApplication::UnregisterInputPreProcessor(TSharedPtr InputProcessor) +{ + InputPreProcessors.Remove(InputProcessor); +} + +void FSlateApplication::UnregisterAllInputPreProcessors() +{ + InputPreProcessors.RemoveAll(); +} + void FSlateApplication::SetCursorRadius(float NewRadius) { CursorRadius = FMath::Max(0.0f, NewRadius); @@ -3885,7 +4006,17 @@ float FSlateApplication::GetCursorRadius() const return CursorRadius; } -FVector2D FSlateApplication::CalculatePopupWindowPosition( const FSlateRect& InAnchor, const FVector2D& InSize, const EOrientation Orientation ) const +void FSlateApplication::SetAllowTooltips(bool bCanShow) +{ + bAllowToolTips = bCanShow ? 1 : 0; +} + +bool FSlateApplication::GetAllowTooltips() const +{ + return bAllowToolTips != 0; +} + +FVector2D FSlateApplication::CalculatePopupWindowPosition( const FSlateRect& InAnchor, const FVector2D& InSize, const FVector2D& InProposedPlacement, const EOrientation Orientation) const { FVector2D CalculatedPopUpWindowPosition( 0, 0 ); @@ -3902,7 +4033,7 @@ FVector2D FSlateApplication::CalculatePopupWindowPosition( const FSlateRect& InA PopUpOrientation = EPopUpOrientation::Vertical; } - if ( PlatformApplication->TryCalculatePopupWindowPosition( AnchorRect, InSize, PopUpOrientation, /*OUT*/&CalculatedPopUpWindowPosition ) ) + if ( PlatformApplication->TryCalculatePopupWindowPosition( AnchorRect, InSize, InProposedPlacement, PopUpOrientation, /*OUT*/&CalculatedPopUpWindowPosition ) ) { return CalculatedPopUpWindowPosition; } @@ -3922,10 +4053,15 @@ FVector2D FSlateApplication::CalculatePopupWindowPosition( const FSlateRect& InA PlatformWorkArea.Left+(PlatformWorkArea.Right - PlatformWorkArea.Left), PlatformWorkArea.Top+(PlatformWorkArea.Bottom - PlatformWorkArea.Top) ); - // Assume natural left-to-right, top-to-bottom flow; position popup below and to the right. - const FVector2D ProposedPlacement( - Orientation == Orient_Horizontal ? AnchorRect.Right : AnchorRect.Left, - Orientation == Orient_Horizontal ? AnchorRect.Top : AnchorRect.Bottom); + FVector2D ProposedPlacement = InProposedPlacement; + + if (ProposedPlacement.IsZero()) + { + // Assume natural left-to-right, top-to-bottom flow; position popup below and to the right. + ProposedPlacement = FVector2D( + Orientation == Orient_Horizontal ? AnchorRect.Right : AnchorRect.Left, + Orientation == Orient_Horizontal ? AnchorRect.Top : AnchorRect.Bottom); + } return ComputePopupFitInRect(InAnchor, FSlateRect(ProposedPlacement, ProposedPlacement+InSize), Orientation, WorkAreaRect); } @@ -3979,7 +4115,7 @@ FSlateRect FSlateApplication::GetPreferredWorkArea() const { if ( const FSlateUser* User = GetUser(GetUserIndexForKeyboard()) ) { - const FWeakWidgetPath & FocusedWidgetPath = User->Focus.WidgetPath; + const FWeakWidgetPath& FocusedWidgetPath = User->GetWeakFocusPath(); // First see if we have a focused widget if ( FocusedWidgetPath.IsValid() && FocusedWidgetPath.Window.IsValid() ) @@ -4238,7 +4374,9 @@ void FSlateApplication::RegisterUser(TSharedRef NewUser) { // Migrate any state we know about that needs to be maintained if the // user is replaced. - NewUser->Focus = ExistingUser->Focus; + NewUser->FocusWidgetPathWeak = ExistingUser->FocusWidgetPathWeak; + NewUser->FocusCause = ExistingUser->FocusCause; + NewUser->ShowFocus = ExistingUser->ShowFocus; } // Replace the user that's at this index with the new user. @@ -4303,11 +4441,7 @@ TSharedPtr< SWidget > FSlateApplication::GetKeyboardFocusedWidget() const { if ( const FSlateUser* User = GetUser(GetUserIndexForKeyboard()) ) { - const FUserFocusEntry& UserFocusEntry = User->Focus; - if ( UserFocusEntry.WidgetPath.IsValid() ) - { - return UserFocusEntry.WidgetPath.GetLastWidget().Pin(); - } + return User->GetFocusedWidget(); } return TSharedPtr< SWidget >(); @@ -4315,7 +4449,7 @@ TSharedPtr< SWidget > FSlateApplication::GetKeyboardFocusedWidget() const TSharedPtr FSlateApplication::GetMouseCaptorImpl() const { - return MouseCaptor.ToSharedWidget(CursorUserIndex,CursorPointerIndex); + return MouseCaptor.ToSharedWidget(CursorUserIndex, CursorPointerIndex); } bool FSlateApplication::HasAnyMouseCaptor() const @@ -4344,8 +4478,7 @@ TOptional FSlateApplication::HasUserFocus(const TSharedPtrGetFocusedWidget() == Widget ) { - TOptional FocusReason(User->Focus.FocusCause); - return FocusReason; + return User->FocusCause; } } @@ -4360,8 +4493,7 @@ TOptional FSlateApplication::HasAnyUserFocus(const TSharedPtrGetFocusedWidget() == Widget ) { - TOptional FocusReason(User->Focus.FocusCause); - return FocusReason; + return User->FocusCause; } } } @@ -4388,11 +4520,10 @@ bool FSlateApplication::ShowUserFocus(const TSharedPtr Widget) co { if ( const FSlateUser* User = Users[UserIndex].Get() ) { - const FUserFocusEntry& UserFocusEntry = User->Focus; - const FWeakWidgetPath & FocusedWidgetPath = UserFocusEntry.WidgetPath; - if ( FocusedWidgetPath.IsValid() && FocusedWidgetPath.GetLastWidget().Pin() == Widget ) + TSharedPtr FocusedWidget = User->GetFocusedWidget(); + if ( FocusedWidget == Widget ) { - return UserFocusEntry.ShowFocus; + return User->ShowFocus; } } } @@ -4404,11 +4535,14 @@ bool FSlateApplication::HasUserFocusedDescendants(const TSharedRef< const SWidge { if ( const FSlateUser* User = GetUser(UserIndex) ) { - const FUserFocusEntry& UserFocusEntry = User->Focus; - const FWeakWidgetPath & FocusedWidgetPath = UserFocusEntry.WidgetPath; - if ( FocusedWidgetPath.IsValid() && FocusedWidgetPath.GetLastWidget().Pin() != Widget && FocusedWidgetPath.ContainsWidget(Widget) ) + TSharedPtr FocusedWidget = User->GetFocusedWidget(); + if ( FocusedWidget != Widget ) { - return true; + const FWeakWidgetPath& FocusedWidgetPath = User->GetWeakFocusPath(); + if ( FocusedWidgetPath.ContainsWidget(Widget) ) + { + return true; + } } } @@ -4421,11 +4555,14 @@ bool FSlateApplication::HasFocusedDescendants( const TSharedRef< const SWidget > { if ( const FSlateUser* User = Users[UserIndex].Get() ) { - const FUserFocusEntry& UserFocusEntry = User->Focus; - const FWeakWidgetPath & FocusedWidgetPath = UserFocusEntry.WidgetPath; - if ( FocusedWidgetPath.IsValid() && FocusedWidgetPath.GetLastWidget().Pin() != Widget && FocusedWidgetPath.ContainsWidget(Widget) ) + TSharedPtr FocusedWidget = User->GetFocusedWidget(); + if ( FocusedWidget != Widget ) { - return true; + const FWeakWidgetPath& FocusedWidgetPath = User->GetWeakFocusPath(); + if ( FocusedWidgetPath.ContainsWidget(Widget) ) + { + return true; + } } } } @@ -4511,7 +4648,8 @@ bool FSlateApplication::ProcessKeyCharEvent( FCharacterEvent& InCharacterEvent ) // Bubble the key event if ( FSlateUser* User = GetOrCreateUser(InCharacterEvent.GetUserIndex()) ) { - FWidgetPath EventPath = User->Focus.WidgetPath.ToWidgetPath(); + TSharedRef EventPathRef = User->GetFocusPath(); + const FWidgetPath& EventPath = EventPathRef.Get(); // Switch worlds for widgets in the current path FScopedSwitchWorldHack SwitchWorld(EventPath); @@ -4558,7 +4696,7 @@ bool FSlateApplication::ProcessKeyDownEvent( FKeyEvent& InKeyEvent ) QueueSynthesizedMouseMove(); // Analog cursor gets first chance at the input - if (InputPreProcessor.IsValid() && InputPreProcessor->HandleKeyDownEvent(*this, InKeyEvent)) + if (InputPreProcessors.HandleKeyDownEvent(*this, InKeyEvent)) { return true; } @@ -4609,7 +4747,8 @@ bool FSlateApplication::ProcessKeyDownEvent( FKeyEvent& InKeyEvent ) // Bubble the keyboard event if ( FSlateUser* User = GetOrCreateUser(InKeyEvent.GetUserIndex()) ) { - FWidgetPath EventPath = User->Focus.WidgetPath.ToWidgetPath(); + TSharedRef EventPathRef = User->GetFocusPath(); + const FWidgetPath& EventPath = EventPathRef.Get(); // Switch worlds for widgets inOnPreviewMouseButtonDown the current path FScopedSwitchWorldHack SwitchWorld(EventPath); @@ -4663,7 +4802,7 @@ bool FSlateApplication::ProcessKeyUpEvent( FKeyEvent& InKeyEvent ) QueueSynthesizedMouseMove(); // Analog cursor gets first chance at the input - if (InputPreProcessor.IsValid() && InputPreProcessor->HandleKeyUpEvent(*this, InKeyEvent)) + if (InputPreProcessors.HandleKeyUpEvent(*this, InKeyEvent)) { return true; } @@ -4677,7 +4816,8 @@ bool FSlateApplication::ProcessKeyUpEvent( FKeyEvent& InKeyEvent ) // Bubble the key event if ( FSlateUser* User = GetOrCreateUser(InKeyEvent.GetUserIndex()) ) { - FWidgetPath EventPath = User->Focus.WidgetPath.ToWidgetPath(); + TSharedRef EventPathRef = User->GetFocusPath(); + const FWidgetPath& EventPath = EventPathRef.Get(); // Switch worlds for widgets in the current path FScopedSwitchWorldHack SwitchWorld(EventPath); @@ -4706,16 +4846,18 @@ bool FSlateApplication::ProcessAnalogInputEvent(FAnalogInputEvent& InAnalogInput FReply Reply = FReply::Unhandled(); // Analog cursor gets first chance at the input - if (InputPreProcessor.IsValid() && InputPreProcessor->HandleAnalogInputEvent(*this, InAnalogInputEvent)) + if (InputPreProcessors.HandleAnalogInputEvent(*this, InAnalogInputEvent)) { Reply = FReply::Handled(); } - else + + if (!Reply.IsEventHandled()) { - // Bubble the key event - if ( FSlateUser* User = GetOrCreateUser(InAnalogInputEvent.GetUserIndex()) ) + if (FSlateUser* User = GetOrCreateUser(InAnalogInputEvent.GetUserIndex())) { - FWidgetPath EventPath = User->Focus.WidgetPath.ToWidgetPath(); + TSharedRef EventPathRef = User->GetFocusPath(); + const FWidgetPath& EventPath = EventPathRef.Get(); + InAnalogInputEvent.SetEventPath(EventPath); // Switch worlds for widgets in the current path @@ -4728,7 +4870,7 @@ bool FSlateApplication::ProcessAnalogInputEvent(FAnalogInputEvent& InAnalogInput : FReply::Unhandled(); }); - LOG_EVENT_CONTENT(EEventLog::AnalogInput, InAnalogInputEvent.GetKey().ToString(), Reply); + LOG_EVENT_CONTENT(EEventLog::AnalogInput, InAnalogInputEvent.GetKey().ToString(), Reply); QueueSynthesizedMouseMove(); } @@ -4773,15 +4915,23 @@ FKey TranslateMouseButtonToKey( const EMouseButtons::Type Button ) return Key; } +#if PLATFORM_DESKTOP + void FSlateApplication::SetGameIsFakingTouchEvents(const bool bIsFaking, FVector2D* CursorLocation) { - if (bIsFakingTouched && !bIsFaking && bIsGameFakingTouch && !bIsFakingTouch) + if ( bIsGameFakingTouch != bIsFaking ) { - OnTouchEnded((CursorLocation ? *CursorLocation : PlatformApplication->Cursor->GetPosition()), 0, 0); + if (bIsFakingTouched && !bIsFaking && bIsGameFakingTouch && !bIsFakingTouch) + { + OnTouchEnded((CursorLocation ? *CursorLocation : PlatformApplication->Cursor->GetPosition()), 0, 0); + } + + bIsGameFakingTouch = bIsFaking; } - bIsGameFakingTouch = bIsFaking; } +#endif + bool FSlateApplication::IsFakingTouchEvents() const { return bIsFakingTouch || bIsGameFakingTouch; @@ -4840,8 +4990,8 @@ bool FSlateApplication::ProcessMouseButtonDownEvent( const TSharedPtr< FGenericW } PressedMouseButtons.Add( MouseEvent.GetEffectingButton() ); - // Input preprocessor gets first chance at the input - if( InputPreProcessor.IsValid() && InputPreProcessor->HandleMouseButtonDownEvent( *this, MouseEvent ) ) + // Input preprocessors get the first chance at the input + if (InputPreProcessors.HandleMouseButtonDownEvent(*this, MouseEvent)) { return true; } @@ -4915,7 +5065,6 @@ bool FSlateApplication::ProcessMouseButtonDownEvent( const TSharedPtr< FGenericW } } - PointerIndexLastPositionMap.Add(MouseEvent.GetPointerIndex(), MouseEvent.GetScreenSpacePosition()); return true; } @@ -5028,7 +5177,6 @@ FReply FSlateApplication::RoutePointerUpEvent(FWidgetPath& WidgetsUnderPointer, if (MouseCaptor.HasCaptureForPointerIndex(PointerEvent.GetUserIndex(), PointerEvent.GetPointerIndex())) { - //FWidgetPath MouseCaptorPath = MouseCaptor.ToWidgetPath(PointerEvent.GetPointerIndex()); FWidgetPath MouseCaptorPath = MouseCaptor.ToWidgetPath( FWeakWidgetPath::EInterruptedPathHandling::Truncate, &PointerEvent ); if ( ensureMsgf(MouseCaptorPath.Widgets.Num() > 0, TEXT("A window had a widget with mouse capture. That entire window has been dismissed before the mouse up could be processed.")) ) { @@ -5041,16 +5189,30 @@ FReply FSlateApplication::RoutePointerUpEvent(FWidgetPath& WidgetsUnderPointer, FReply TempReply = FReply::Unhandled(); if (Event.IsTouchEvent()) { - TempReply = TargetWidget.Widget->OnTouchEnded( TargetWidget.Geometry, Event ); + TempReply = TargetWidget.Widget->OnTouchEnded(TargetWidget.Geometry, Event); } if (!Event.IsTouchEvent() || (!TempReply.IsEventHandled() && this->bTouchFallbackToMouse)) { TempReply = TargetWidget.Widget->OnMouseButtonUp( TargetWidget.Geometry, Event ); } + + if ( Event.IsTouchEvent() && !IsFakingTouchEvents() ) + { + // Generate a Leave event when a touch ends as well, since a touch can enter a widget and then end inside it + TargetWidget.Widget->OnMouseLeave(Event); + } + return TempReply; }); + // For touch events, we always invalidate capture for the pointer. There's no reason to ever maintain capture for + // fingers no longer in contact with the screen. + if ( PointerEvent.IsTouchEvent() ) + { + MouseCaptor.InvalidateCaptureForPointer(PointerEvent.GetUserIndex(), PointerEvent.GetPointerIndex()); + } + #if PLATFORM_MAC TopLevelWindow = MouseCaptorPath.TopLevelWindow; #endif @@ -5069,22 +5231,32 @@ FReply FSlateApplication::RoutePointerUpEvent(FWidgetPath& WidgetsUnderPointer, TSharedPtr< FDragDropOperation > LocalDragDropContent = DragDropContent; DragDropContent.Reset(); - Reply = FEventRouter::Route( this, FEventRouter::FBubblePolicy(LocalWidgetsUnderCursor), PointerEvent, [&](const FArrangedWidget& CurWidget, const FPointerEvent& Event) + Reply = FEventRouter::Route(this, FEventRouter::FBubblePolicy(LocalWidgetsUnderCursor), PointerEvent, [&] (const FArrangedWidget& CurWidget, const FPointerEvent& Event) { - if (bIsDragDropping) + if ( bIsDragDropping ) { return CurWidget.Widget->OnDrop(CurWidget.Geometry, FDragDropEvent(Event, LocalDragDropContent)); } + FReply TempReply = FReply::Unhandled(); - if (Event.IsTouchEvent()) + + if ( Event.IsTouchEvent() ) { - TempReply = CurWidget.Widget->OnTouchEnded( CurWidget.Geometry, Event ); + TempReply = CurWidget.Widget->OnTouchEnded(CurWidget.Geometry, Event); } - if (!Event.IsTouchEvent() || (!TempReply.IsEventHandled() && bTouchFallbackToMouse)) + + if ( !Event.IsTouchEvent() || ( !TempReply.IsEventHandled() && bTouchFallbackToMouse ) ) { - TempReply = CurWidget.Widget->OnMouseButtonUp( CurWidget.Geometry, Event ); + TempReply = CurWidget.Widget->OnMouseButtonUp(CurWidget.Geometry, Event); } - return TempReply; + + if ( Event.IsTouchEvent() && !IsFakingTouchEvents() ) + { + // Generate a Leave event when a touch ends as well, since a touch can enter a widget and then end inside it + CurWidget.Widget->OnMouseLeave(Event); + } + + return TempReply; }); LOG_EVENT( bIsDragDropping ? EEventLog::DragDrop : EEventLog::MouseButtonUp, Reply ); @@ -5128,6 +5300,8 @@ bool FSlateApplication::RoutePointerMoveEvent(const FWidgetPath& WidgetsUnderPoi { TScopeCounter BeginInput(ProcessingInput); + PointerIndexPositionMap.Add(FUserAndPointer(PointerEvent.GetUserIndex(), PointerEvent.GetPointerIndex()), PointerEvent.GetScreenSpacePosition()); + bool bHandled = false; FWeakWidgetPath LastWidgetsUnderCursor; @@ -5136,11 +5310,13 @@ bool FSlateApplication::RoutePointerMoveEvent(const FWidgetPath& WidgetsUnderPoi bool bDragDetected = false; bool bShouldStartDetectingDrag = true; +#if WITH_EDITOR //@TODO VREDITOR - Remove and move to interaction component if (OnDragDropCheckOverride.IsBound()) { bShouldStartDetectingDrag = OnDragDropCheckOverride.Execute(); } +#endif if ( !bIsSynthetic && bShouldStartDetectingDrag ) { @@ -5193,7 +5369,6 @@ bool FSlateApplication::RoutePointerMoveEvent(const FWidgetPath& WidgetsUnderPoi FWidgetPath MouseCaptorPath; if ( MouseCaptor.HasCaptureForPointerIndex(PointerEvent.GetUserIndex(), PointerEvent.GetPointerIndex()) ) { - //MouseCaptorPath = MouseCaptor.ToWidgetPath(MouseEvent.GetPointerIndex(), FWeakWidgetPath::EInterruptedPathHandling::ReturnInvalid); MouseCaptorPath = MouseCaptor.ToWidgetPath(FWeakWidgetPath::EInterruptedPathHandling::ReturnInvalid, &PointerEvent); } @@ -5250,8 +5425,6 @@ bool FSlateApplication::RoutePointerMoveEvent(const FWidgetPath& WidgetsUnderPoi } - - if (MouseCaptorPath.IsValid()) { if ( !bIsSynthetic ) @@ -5271,19 +5444,19 @@ bool FSlateApplication::RoutePointerMoveEvent(const FWidgetPath& WidgetsUnderPoi return FNoReply(); }); - FReply Reply = FEventRouter::Route( this, FEventRouter::FToLeafmostPolicy(MouseCaptorPath), PointerEvent, [this]( const FArrangedWidget& MouseCaptorWidget, const FPointerEvent& Event ) + FReply Reply = FEventRouter::Route(this, FEventRouter::FToLeafmostPolicy(MouseCaptorPath), PointerEvent, [this] (const FArrangedWidget& MouseCaptorWidget, const FPointerEvent& Event) { FReply TempReply = FReply::Unhandled(); - if (Event.IsTouchEvent()) + if ( Event.IsTouchEvent() ) { - TempReply = MouseCaptorWidget.Widget->OnTouchMoved( MouseCaptorWidget.Geometry, Event ); + TempReply = MouseCaptorWidget.Widget->OnTouchMoved(MouseCaptorWidget.Geometry, Event); } - if (!Event.IsTouchEvent() || (!TempReply.IsEventHandled() && this->bTouchFallbackToMouse)) + if ( !Event.IsTouchEvent() || ( !TempReply.IsEventHandled() && this->bTouchFallbackToMouse ) ) { - TempReply = MouseCaptorWidget.Widget->OnMouseMove( MouseCaptorWidget.Geometry, Event ); + TempReply = MouseCaptorWidget.Widget->OnMouseMove(MouseCaptorWidget.Geometry, Event); } return TempReply; - } ); + }); bHandled = Reply.IsEventHandled(); } } @@ -5338,7 +5511,7 @@ bool FSlateApplication::RoutePointerMoveEvent(const FWidgetPath& WidgetsUnderPoi LOG_EVENT( IsDragDropping() ? EEventLog::DragOver : EEventLog::MouseMove, Reply ) - bHandled = Reply.IsEventHandled(); + bHandled = Reply.IsEventHandled(); } // Give the current drag drop operation a chance to do something @@ -5347,12 +5520,14 @@ bool FSlateApplication::RoutePointerMoveEvent(const FWidgetPath& WidgetsUnderPoi { FDragDropEvent DragDropEvent( PointerEvent, DragDropContent ); //@TODO VREDITOR - Remove and move to interaction component +#if WITH_EDITOR if (OnDragDropCheckOverride.IsBound() && DragDropEvent.GetOperation().IsValid()) { DragDropEvent.GetOperation()->SetDecoratorVisibility(false); DragDropEvent.GetOperation()->SetCursorOverride(EMouseCursor::None); DragDropContent->SetCursorOverride(EMouseCursor::None); } +#endif FScopedSwitchWorldHack SwitchWorld( WidgetsUnderPointer ); DragDropContent->OnDragged( DragDropEvent ); @@ -5385,9 +5560,9 @@ bool FSlateApplication::RoutePointerMoveEvent(const FWidgetPath& WidgetsUnderPoi DragDropWindowPtr = nullptr; } - WidgetsUnderCursorLastEvent.Add( FUserAndPointer( PointerEvent.GetUserIndex(), PointerEvent.GetPointerIndex() ), FWeakWidgetPath( WidgetsUnderPointer ) ); + WidgetsUnderCursorLastEvent.Add(FUserAndPointer(PointerEvent.GetUserIndex(), PointerEvent.GetPointerIndex()), FWeakWidgetPath(WidgetsUnderPointer)); + PointerIndexLastPositionMap.Add(FUserAndPointer(PointerEvent.GetUserIndex(), PointerEvent.GetPointerIndex()), PointerEvent.GetScreenSpacePosition()); - PointerIndexLastPositionMap.Add(PointerEvent.GetPointerIndex(), PointerEvent.GetScreenSpacePosition()); return bHandled; } @@ -5440,8 +5615,6 @@ bool FSlateApplication::ProcessMouseButtonDoubleClickEvent( const TSharedPtr< FG FReply Reply = RoutePointerDoubleClickEvent( WidgetsUnderCursor, InMouseEvent ); - PointerIndexLastPositionMap.Add(InMouseEvent.GetPointerIndex(), InMouseEvent.GetScreenSpacePosition()); - return Reply.IsEventHandled(); } @@ -5504,8 +5677,8 @@ bool FSlateApplication::ProcessMouseButtonUpEvent( FPointerEvent& MouseEvent ) LastUserInteractionTimeForThrottling = LastUserInteractionTime; PressedMouseButtons.Remove( MouseEvent.GetEffectingButton() ); - // Input preprocessor gets first chance at the input - if( InputPreProcessor.IsValid() && InputPreProcessor->HandleMouseButtonUpEvent( *this, MouseEvent ) ) + // Input preprocessors get the first chance at the input + if (InputPreProcessors.HandleMouseButtonUpEvent(*this, MouseEvent)) { return true; } @@ -5524,6 +5697,7 @@ bool FSlateApplication::ProcessMouseButtonUpEvent( FPointerEvent& MouseEvent ) { // Release Capture PlatformApplication->SetCapture( nullptr ); +// MouseCaptor.InvalidateCaptureForPointer(MouseEvent.GetUserIndex(), MouseEvent.GetPointerIndex()); } return bHandled; @@ -5555,9 +5729,25 @@ bool FSlateApplication::ProcessMouseWheelOrGestureEvent( FPointerEvent& InWheelE QueueSynthesizedMouseMove(); - const bool bShouldProcessEvent = InWheelEvent.GetWheelDelta() != 0 || - (InGestureEvent != nullptr && InGestureEvent->GetGestureDelta() != FVector2D::ZeroVector); - + bool bShouldProcessEvent = false; + + if ( InGestureEvent ) + { + switch ( InGestureEvent->GetGestureType() ) + { + case EGestureEvent::LongPress: + bShouldProcessEvent = true; + break; + default: + bShouldProcessEvent = InGestureEvent->GetGestureDelta() != FVector2D::ZeroVector; + break; + } + } + else + { + bShouldProcessEvent = InWheelEvent.GetWheelDelta() != 0; + } + if ( !bShouldProcessEvent ) { return false; @@ -5591,7 +5781,7 @@ FReply FSlateApplication::RouteMouseWheelOrGestureEvent(const FWidgetPath& Widge { FReply TempReply = FReply::Unhandled(); // Gesture event gets first shot, if slate doesn't respond to it, we'll try the wheel event. - if ( InGestureEvent != nullptr && InGestureEvent->GetGestureDelta() != FVector2D::ZeroVector ) + if ( InGestureEvent != nullptr ) { TempReply = CurWidget.Widget->OnTouchGesture(CurWidget.Geometry, *InGestureEvent); } @@ -5638,8 +5828,8 @@ bool FSlateApplication::OnMouseMove() 0, PlatformApplication->GetModifierKeys() ); - - if (InputPreProcessor.IsValid() && InputPreProcessor->HandleMouseMoveEvent(*this, MouseEvent)) + + if (InputPreProcessors.HandleMouseMoveEvent(*this, MouseEvent)) { return true; } @@ -5668,7 +5858,7 @@ bool FSlateApplication::OnRawMouseMove( const int32 X, const int32 Y ) PlatformApplication->GetModifierKeys() ); - if (InputPreProcessor.IsValid() && InputPreProcessor->HandleMouseMoveEvent(*this, MouseEvent)) + if (InputPreProcessors.HandleMouseMoveEvent(*this, MouseEvent)) { return true; } @@ -5733,8 +5923,7 @@ void FSlateApplication::NavigateToWidget(const uint32 UserIndex, const TSharedPt } else if (const FSlateUser* User = GetOrCreateUser(UserIndex)) { - const FUserFocusEntry& UserFocusEntry = User->Focus; - NavigationSourceWP = UserFocusEntry.WidgetPath.ToWidgetPath(); + NavigationSourceWP = User->FocusWidgetPathWeak.ToWidgetPath(); } if (NavigationSourceWP.IsValid()) @@ -5895,6 +6084,11 @@ bool FSlateApplication::OnTouchStarted( const TSharedPtr< FGenericWindow >& Plat true); ProcessTouchStartedEvent( PlatformWindow, PointerEvent ); + if ( FSlateUser* User = GetUser(ControllerId) ) + { + User->GestureDetector.OnTouchStarted(TouchIndex, Location); + } + return true; } @@ -5905,8 +6099,9 @@ void FSlateApplication::ProcessTouchStartedEvent( const TSharedPtr< FGenericWind bool FSlateApplication::OnTouchMoved( const FVector2D& Location, int32 TouchIndex, int32 ControllerId ) { - FVector2D LastLocation = PointerIndexLastPositionMap.Contains(TouchIndex) ? - PointerIndexLastPositionMap[TouchIndex] : Location; + const FVector2D* LastLocationPtr = PointerIndexLastPositionMap.Find(FUserAndPointer(ControllerId, TouchIndex)); + const FVector2D LastLocation = LastLocationPtr ? *LastLocationPtr : Location; + FPointerEvent PointerEvent( ControllerId, TouchIndex, @@ -5915,6 +6110,11 @@ bool FSlateApplication::OnTouchMoved( const FVector2D& Location, int32 TouchInde true); ProcessTouchMovedEvent(PointerEvent); + if ( FSlateUser* User = GetUser(ControllerId) ) + { + User->GestureDetector.OnTouchMoved(TouchIndex, Location); + } + return true; } @@ -5933,9 +6133,21 @@ bool FSlateApplication::OnTouchEnded( const FVector2D& Location, int32 TouchInde true); ProcessTouchEndedEvent(PointerEvent); + if ( FSlateUser* User = GetUser(ControllerId) ) + { + User->GestureDetector.OnTouchEnded(TouchIndex, Location); + } + return true; } +void FSlateApplication::ShouldSimulateGesture(EGestureEvent::Type Gesture, bool bEnable) +{ + check(FGestureDetector::IsGestureSupported(Gesture)); + + SimulateGestures[Gesture] = bEnable; +} + void FSlateApplication::ProcessTouchEndedEvent( FPointerEvent& PointerEvent ) { ProcessMouseButtonUpEvent(PointerEvent); @@ -5962,19 +6174,20 @@ void FSlateApplication::ProcessMotionDetectedEvent( FMotionEvent& MotionEvent ) if ( FSlateUser* User = GetOrCreateUser(MotionEvent.GetUserIndex()) ) { - if (InputPreProcessor.IsValid() && InputPreProcessor->HandleMotionDetectedEvent(*this, MotionEvent)) + if (InputPreProcessors.HandleMotionDetectedEvent(*this, MotionEvent)) { return; } - if ( User->Focus.WidgetPath.IsValid() ) + if ( User->HasValidFocusPath() ) { /* Get the controller focus target for this user */ - const FWidgetPath PathToWidget = User->Focus.WidgetPath.ToWidgetPath(); + TSharedRef EventPathRef = User->GetFocusPath(); + const FWidgetPath& EventPath = EventPathRef.Get(); - FScopedSwitchWorldHack SwitchWorld(PathToWidget); + FScopedSwitchWorldHack SwitchWorld(EventPath); - FReply Reply = FEventRouter::Route(this, FEventRouter::FBubblePolicy(PathToWidget), MotionEvent, [] (const FArrangedWidget& SomeWidget, const FMotionEvent& InMotionEvent) + FReply Reply = FEventRouter::Route(this, FEventRouter::FBubblePolicy(EventPath), MotionEvent, [] (const FArrangedWidget& SomeWidget, const FMotionEvent& InMotionEvent) { return SomeWidget.Widget->OnMotionDetected(SomeWidget.Geometry, InMotionEvent); }); @@ -6116,6 +6329,8 @@ bool FSlateApplication::ProcessWindowActivatedEvent( const FWindowActivateEvent& if ( ActivateEvent.GetActivationType() != FWindowActivateEvent::EA_Deactivate ) { + ReleaseMouseCapture(); + const bool bActivatedByMouse = ActivateEvent.GetActivationType() == FWindowActivateEvent::EA_ActivateByMouse; // Only window activate by mouse is considered a user interaction @@ -6458,7 +6673,8 @@ bool FSlateApplication::ProcessDragEnterEvent( TSharedRef WindowEntered FReply TriggerDragDropReply = FReply::Handled().BeginDragDrop( DragDropEvent.GetOperation().ToSharedRef() ); ProcessReply( WidgetsUnderCursor, TriggerDragDropReply, &WidgetsUnderCursor, &DragDropEvent ); - PointerIndexLastPositionMap.Add(DragDropEvent.GetPointerIndex(), DragDropEvent.GetScreenSpacePosition()); + PointerIndexLastPositionMap.Add(FUserAndPointer(DragDropEvent.GetUserIndex(), DragDropEvent.GetPointerIndex()), DragDropEvent.GetScreenSpacePosition()); + return true; } @@ -6529,7 +6745,7 @@ EDropEffect::Type FSlateApplication::OnDragDrop( const TSharedPtr< FGenericWindo // User dropped into a Slate window. Slate is already in drag and drop mode. // It knows what to do based on a mouse up. if ( ProcessMouseButtonUpEvent( MouseEvent ) ) -{ + { Result = EDropEffect::Copy; } } @@ -6629,4 +6845,133 @@ void FSlateApplication::NavigateFromWidgetUnderCursor(const uint32 InUserIndex, } } +void FSlateApplication::InputPreProcessorsHelper::Tick(const float DeltaTime, FSlateApplication& SlateApp, TSharedRef Cursor) +{ + for (TSharedPtr InputPreProcessor : InputPreProcessorList) + { + InputPreProcessor->Tick(DeltaTime, SlateApp, Cursor); + } +} + +bool FSlateApplication::InputPreProcessorsHelper::HandleKeyDownEvent(FSlateApplication& SlateApp, const FKeyEvent& InKeyEvent) +{ + for (TSharedPtr InputPreProcessor : InputPreProcessorList) + { + if (InputPreProcessor->HandleKeyDownEvent(SlateApp, InKeyEvent)) + { + return true; + } + } + + return false; +} + +bool FSlateApplication::InputPreProcessorsHelper::HandleKeyUpEvent(FSlateApplication& SlateApp, const FKeyEvent& InKeyEvent) +{ + for (TSharedPtr InputPreProcessor : InputPreProcessorList) + { + if (InputPreProcessor.IsValid()) + { + if (InputPreProcessor->HandleKeyUpEvent(SlateApp, InKeyEvent)) + { + return true; + } + } + } + + return false; +} + +bool FSlateApplication::InputPreProcessorsHelper::HandleAnalogInputEvent(FSlateApplication& SlateApp, const FAnalogInputEvent& InAnalogInputEvent) +{ + for (TSharedPtr InputPreProcessor : InputPreProcessorList) + { + if (InputPreProcessor->HandleAnalogInputEvent(SlateApp, InAnalogInputEvent)) + { + return true; + } + } + + return false; +} + +bool FSlateApplication::InputPreProcessorsHelper::HandleMouseMoveEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent) +{ + for (TSharedPtr InputPreProcessor : InputPreProcessorList) + { + if (InputPreProcessor->HandleMouseMoveEvent(SlateApp, MouseEvent)) + { + return true; + } + } + + return false; +} + +bool FSlateApplication::InputPreProcessorsHelper::HandleMouseButtonDownEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent) +{ + for (TSharedPtr InputPreProcessor : InputPreProcessorList) + { + if (InputPreProcessor->HandleMouseButtonDownEvent(SlateApp, MouseEvent)) + { + return true; + } + } + + return false; +} + +bool FSlateApplication::InputPreProcessorsHelper::HandleMouseButtonUpEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent) +{ + for (TSharedPtr InputPreProcessor : InputPreProcessorList) + { + if (InputPreProcessor->HandleMouseButtonUpEvent(SlateApp, MouseEvent)) + { + return true; + } + } + + return false; +} + +bool FSlateApplication::InputPreProcessorsHelper::HandleMotionDetectedEvent(FSlateApplication& SlateApp, const FMotionEvent& MotionEvent) +{ + for (TSharedPtr InputPreProcessor : InputPreProcessorList) + { + if (InputPreProcessor->HandleMotionDetectedEvent(SlateApp, MotionEvent)) + { + return true; + } + } + + return false; +} + +bool FSlateApplication::InputPreProcessorsHelper::Add(TSharedPtr InputProcessor, const int32 Index /*= INDEX_NONE*/) +{ + bool bResult = false; + if (Index == INDEX_NONE) + { + InputPreProcessorList.AddUnique(InputProcessor); + bResult = true; + } + else if (!InputPreProcessorList.Find(InputProcessor)) + { + InputPreProcessorList.Insert(InputProcessor, Index); + bResult = true; + } + + return bResult; +} + +void FSlateApplication::InputPreProcessorsHelper::Remove(TSharedPtr InputProcessor) +{ + InputPreProcessorList.Remove(InputProcessor); +} + +void FSlateApplication::InputPreProcessorsHelper::RemoveAll() +{ + InputPreProcessorList.Reset(); +} + #undef SLATE_HAS_WIDGET_REFLECTOR diff --git a/Engine/Source/Runtime/Slate/Private/Framework/Docking/SDockingTabWell.cpp b/Engine/Source/Runtime/Slate/Private/Framework/Docking/SDockingTabWell.cpp index 4da673e47b78..8bad8f51b4a5 100644 --- a/Engine/Source/Runtime/Slate/Private/Framework/Docking/SDockingTabWell.cpp +++ b/Engine/Source/Runtime/Slate/Private/Framework/Docking/SDockingTabWell.cpp @@ -129,10 +129,11 @@ int32 SDockingTabWell::OnPaint( const FPaintArgs& Args, const FGeometry& Allotte int32 MaxLayerId = LayerId; TSharedPtr ForegroundTab = GetForegroundTab(); - FArrangedWidget* ForegroundTabGeometry = NULL; + FArrangedWidget* ForegroundTabGeometry = nullptr; - // Draw all inactive tabs first - for (int32 ChildIndex = 0; ChildIndex < ArrangedChildren.Num(); ++ChildIndex) + // Draw all inactive tabs first, from last, to first, so that the inactive tabs + // that come later, are drawn behind tabs that come before it. + for (int32 ChildIndex = ArrangedChildren.Num() - 1; ChildIndex >= 0; --ChildIndex) { FArrangedWidget& CurWidget = ArrangedChildren[ChildIndex]; if (CurWidget.Widget == ForegroundTab) diff --git a/Engine/Source/Runtime/Slate/Private/Framework/Layout/InertialScrollManager.cpp b/Engine/Source/Runtime/Slate/Private/Framework/Layout/InertialScrollManager.cpp index e3556bdaa4b5..69b34c91b3b2 100644 --- a/Engine/Source/Runtime/Slate/Private/Framework/Layout/InertialScrollManager.cpp +++ b/Engine/Source/Runtime/Slate/Private/Framework/Layout/InertialScrollManager.cpp @@ -2,27 +2,28 @@ #include "Framework/Layout/InertialScrollManager.h" +float FInertialScrollManager::FrictionCoefficient = 2.0f; +float FInertialScrollManager::StaticVelocityDrag = 100; -FInertialScrollManager::FInertialScrollManager(float InScrollDecceleration, double InSampleTimeout) +FInertialScrollManager::FInertialScrollManager(double InSampleTimeout) : ScrollVelocity(0.f) - , ScrollDecceleration(InScrollDecceleration) , SampleTimeout(InSampleTimeout) { } void FInertialScrollManager::AddScrollSample(float Delta, double CurrentTime) { - new( this->ScrollSamples ) FScrollSample(Delta, CurrentTime); + new( ScrollSamples ) FScrollSample(Delta, CurrentTime); float Total = 0; double OldestTime = 0; - for ( int32 VelIdx = this->ScrollSamples.Num() - 1; VelIdx >= 0; --VelIdx ) + for ( int32 VelIdx = ScrollSamples.Num() - 1; VelIdx >= 0; --VelIdx ) { - const double SampleTime = this->ScrollSamples[VelIdx].Time; - const float SampleDelta = this->ScrollSamples[VelIdx].Delta; + const double SampleTime = ScrollSamples[VelIdx].Time; + const float SampleDelta = ScrollSamples[VelIdx].Delta; if ( CurrentTime - SampleTime > SampleTimeout ) { - this->ScrollSamples.RemoveAt(VelIdx); + ScrollSamples.RemoveAt(VelIdx); } else { @@ -39,29 +40,30 @@ void FInertialScrollManager::AddScrollSample(float Delta, double CurrentTime) const double Duration = (OldestTime > 0) ? (CurrentTime - OldestTime) : 0; if ( Duration > 0 ) { - this->ScrollVelocity = Total / Duration; + ScrollVelocity = Total / Duration; } else { - this->ScrollVelocity = 0; + ScrollVelocity = 0; } } void FInertialScrollManager::UpdateScrollVelocity(const float InDeltaTime) { - if ( this->ScrollVelocity > 0 ) + const float VelocityLostPerSecond = ScrollVelocity > 0 ? StaticVelocityDrag : -StaticVelocityDrag; + const float DeltaVelocity = FrictionCoefficient * ScrollVelocity * InDeltaTime + VelocityLostPerSecond * InDeltaTime; + + if ( ScrollVelocity > 0 ) { - this->ScrollVelocity -= ScrollDecceleration * InDeltaTime; - this->ScrollVelocity = FMath::Max(0.f, this->ScrollVelocity); + ScrollVelocity = FMath::Max(0.f, ScrollVelocity - DeltaVelocity); } - else if ( this->ScrollVelocity < 0 ) + else if ( ScrollVelocity < 0 ) { - this->ScrollVelocity += ScrollDecceleration * InDeltaTime; - this->ScrollVelocity = FMath::Min(0.f, this->ScrollVelocity); + ScrollVelocity = FMath::Min(0.f, ScrollVelocity - DeltaVelocity); } } void FInertialScrollManager::ClearScrollVelocity() { - this->ScrollVelocity = 0; + ScrollVelocity = 0; } diff --git a/Engine/Source/Runtime/Slate/Private/Framework/Text/Android/AndroidPlatformTextField.cpp b/Engine/Source/Runtime/Slate/Private/Framework/Text/Android/AndroidPlatformTextField.cpp index 656ce68e0520..d74c4c49da2a 100644 --- a/Engine/Source/Runtime/Slate/Private/Framework/Text/Android/AndroidPlatformTextField.cpp +++ b/Engine/Source/Runtime/Slate/Private/Framework/Text/Android/AndroidPlatformTextField.cpp @@ -3,6 +3,7 @@ #include "Framework/Text/Android/AndroidPlatformTextField.h" #include "Widgets/Input/IVirtualKeyboardEntry.h" #include "Misc/ConfigCacheIni.h" +#include "IConsoleManager.h" // Java InputType class #define TYPE_CLASS_TEXT 0x00000001 @@ -25,7 +26,7 @@ int32 GAndroidNewKeyboard = 0; static FAutoConsoleVariableRef CVarAndroidNewKeyboard( TEXT("Android.NewKeyboard"), GAndroidNewKeyboard, - TEXT("If set, input will trigger virtual keyboard instead of dialog. (Default: False)"), + TEXT("Controls usage of experimental new keyboard input. 0 uses the checkbox setting, 1 forces new keyboard, 2 forces dialog. (Default: 0)"), ECVF_Default ); void FAndroidPlatformTextField::ShowVirtualKeyboard(bool bShow, int32 UserIndex, TSharedPtr TextEntryWidget) @@ -63,10 +64,22 @@ void FAndroidPlatformTextField::ShowVirtualKeyboard(bool bShow, int32 UserIndex, // read the value from the config file static bool bEnableNewKeyboardConfig = false; GConfig->GetBool( TEXT("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings"), TEXT("bEnableNewKeyboard"), bEnableNewKeyboardConfig, GEngineIni ); - - // use integrated keyboard if the runtime setting is set or the console variable is set - bool bIsUsingIntegratedKeyboard = bEnableNewKeyboardConfig || GAndroidNewKeyboard; - + // use integrated keyboard if the runtime setting is set or the console variable is set to 1 + bool bIsUsingIntegratedKeyboard = bEnableNewKeyboardConfig; + switch (GAndroidNewKeyboard) + { + case 1: + bIsUsingIntegratedKeyboard = true; + break; + + case 2: + bIsUsingIntegratedKeyboard = false; + break; + + default: + break; + } + if (bIsUsingIntegratedKeyboard) { if (bShow) diff --git a/Engine/Source/Runtime/Slate/Private/Framework/Text/IOS/IOSPlatformTextField.cpp b/Engine/Source/Runtime/Slate/Private/Framework/Text/IOS/IOSPlatformTextField.cpp index f84e42462421..f80d038b8e8d 100644 --- a/Engine/Source/Runtime/Slate/Private/Framework/Text/IOS/IOSPlatformTextField.cpp +++ b/Engine/Source/Runtime/Slate/Private/Framework/Text/IOS/IOSPlatformTextField.cpp @@ -6,6 +6,36 @@ #include "Widgets/Input/IVirtualKeyboardEntry.h" #include "IOS/IOSAsyncTask.h" +namespace +{ + void GetKeyboardConfig(EKeyboardType TargetKeyboardType, FKeyboardConfig& KeyboardConfig) + { + KeyboardConfig.KeyboardType = UIKeyboardTypeDefault; + KeyboardConfig.bSecureTextEntry = NO; + + switch (TargetKeyboardType) + { + case EKeyboardType::Keyboard_Email: + KeyboardConfig.KeyboardType = UIKeyboardTypeEmailAddress; + break; + case EKeyboardType::Keyboard_Number: + KeyboardConfig.KeyboardType = UIKeyboardTypeDecimalPad; + break; + case EKeyboardType::Keyboard_Web: + KeyboardConfig.KeyboardType = UIKeyboardTypeURL; + break; + case EKeyboardType::Keyboard_AlphaNumeric: + KeyboardConfig.KeyboardType = UIKeyboardTypeASCIICapable; + break; + case EKeyboardType::Keyboard_Password: + KeyboardConfig.bSecureTextEntry = YES; + case EKeyboardType::Keyboard_Default: + default: + KeyboardConfig.KeyboardType = UIKeyboardTypeDefault; + break; + } + } +} FIOSPlatformTextField::FIOSPlatformTextField() : TextField( nullptr ) @@ -30,9 +60,16 @@ void FIOSPlatformTextField::ShowVirtualKeyboard(bool bShow, int32 UserIndex, TSh { if (bShow) { - dispatch_async(dispatch_get_main_queue(),^ { - [View ActivateKeyboard:false]; - }); + EKeyboardType TargetKeyboardType = (TextEntryWidget.IsValid()) ? TextEntryWidget->GetVirtualKeyboardType() : Keyboard_Default; + + FKeyboardConfig KeyboardConfig; + GetKeyboardConfig(TargetKeyboardType, KeyboardConfig); + + [View ActivateKeyboard:false keyboardConfig:KeyboardConfig]; + } + else + { + [View DeactivateKeyboard]; } } else @@ -76,10 +113,12 @@ void FIOSPlatformTextField::ShowVirtualKeyboard(bool bShow, int32 UserIndex, TSh else #endif { - if(AlertView != nil) +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0 + if (AlertView != nil) { [AlertView dismissWithClickedButtonIndex: 0 animated: YES]; //0 is the cancel button } +#endif } TextWidget = nullptr; @@ -144,33 +183,17 @@ void FIOSPlatformTextField::ShowVirtualKeyboard(bool bShow, int32 UserIndex, TSh { AlertTextField.clearsOnBeginEditing = NO; AlertTextField.clearsOnInsertion = NO; - AlertTextField.autocorrectionType = UITextAutocorrectionTypeNo; - AlertTextField.autocapitalizationType = UITextAutocapitalizationTypeNone; AlertTextField.text = [NSString stringWithFString : TextWidget->GetText().ToString()]; AlertTextField.placeholder = [NSString stringWithFString : TextWidget->GetHintText().ToString()]; + + EKeyboardType TargetKeyboardType = (TextWidget.IsValid()) ? TextWidget->GetVirtualKeyboardType() : Keyboard_Default; + FKeyboardConfig KeyboardConfig; + GetKeyboardConfig(TargetKeyboardType, KeyboardConfig); - // set up the keyboard styles not supported in the AlertViewStyle styles - switch (TextWidget->GetVirtualKeyboardType()) - { - case EKeyboardType::Keyboard_Email: - AlertTextField.keyboardType = UIKeyboardTypeEmailAddress; - break; - case EKeyboardType::Keyboard_Number: - AlertTextField.keyboardType = UIKeyboardTypeDecimalPad; - break; - case EKeyboardType::Keyboard_Web: - AlertTextField.keyboardType = UIKeyboardTypeURL; - break; - case EKeyboardType::Keyboard_AlphaNumeric: - AlertTextField.keyboardType = UIKeyboardTypeASCIICapable; - break; - case EKeyboardType::Keyboard_Password: - AlertTextField.secureTextEntry = YES; - case EKeyboardType::Keyboard_Default: - default: - AlertTextField.keyboardType = UIKeyboardTypeDefault; - break; - } + AlertTextField.keyboardType = KeyboardConfig.KeyboardType; + AlertTextField.autocorrectionType = KeyboardConfig.AutocorrectionType; + AlertTextField.autocapitalizationType = KeyboardConfig.AutocapitalizationType; + AlertTextField.secureTextEntry = KeyboardConfig.bSecureTextEntry; } ]; [[IOSAppDelegate GetDelegate].IOSController presentViewController : AlertController animated : YES completion : nil]; @@ -178,6 +201,7 @@ void FIOSPlatformTextField::ShowVirtualKeyboard(bool bShow, int32 UserIndex, TSh else #endif { +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0 AlertView = [[UIAlertView alloc] initWithTitle:@"" message:@"" delegate:self @@ -233,9 +257,11 @@ void FIOSPlatformTextField::ShowVirtualKeyboard(bool bShow, int32 UserIndex, TSh [AlertView show]; [AlertView release]; +#endif } } +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0 - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { UITextField* AlertTextField = [alertView textFieldAtIndex : 0]; @@ -256,6 +282,7 @@ void FIOSPlatformTextField::ShowVirtualKeyboard(bool bShow, int32 UserIndex, TSh }; [AsyncTask FinishedTask]; } +#endif @end diff --git a/Engine/Source/Runtime/Slate/Private/Framework/Text/SlateTextLayout.cpp b/Engine/Source/Runtime/Slate/Private/Framework/Text/SlateTextLayout.cpp index ff636360ee82..8bc4209e4598 100644 --- a/Engine/Source/Runtime/Slate/Private/Framework/Text/SlateTextLayout.cpp +++ b/Engine/Source/Runtime/Slate/Private/Framework/Text/SlateTextLayout.cpp @@ -11,6 +11,15 @@ #include "Framework/Text/SlateTextRun.h" #include "Framework/Text/SlatePasswordRun.h" +#if !UE_BUILD_SHIPPING + +TAutoConsoleVariable ShowDebugTextLayout( + TEXT("Slate.ShowDebugTextLayout"), + false, + TEXT("Whether to show debuging visulization for text layout in Slate.")); + +#endif + TSharedRef< FSlateTextLayout > FSlateTextLayout::Create(FTextBlockStyle InDefaultTextStyle) { TSharedRef< FSlateTextLayout > Layout = MakeShareable( new FSlateTextLayout(MoveTemp(InDefaultTextStyle)) ); @@ -53,7 +62,12 @@ int32 FSlateTextLayout::OnPaint( const FPaintArgs& Args, const FGeometry& Allott const FSlateRect ClippingRect = AllottedGeometry.GetClippingRect().IntersectionWith(MyClippingRect); const ESlateDrawEffect DrawEffects = bParentEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect; - static bool ShowDebug = false; +#if UE_BUILD_SHIPPING + const bool bShowDebug = false; +#else + const bool bShowDebug = ShowDebugTextLayout.GetValueOnAnyThread() != 0; +#endif + FLinearColor BlockHue( 0, 1.0f, 1.0f, 0.5 ); int32 HighestLayerId = LayerId; @@ -77,7 +91,7 @@ int32 FSlateTextLayout::OnPaint( const FPaintArgs& Args, const FGeometry& Allott // Render every block for this line for (const TSharedRef< ILayoutBlock >& Block : LineView.Blocks) { - if ( ShowDebug ) + if ( bShowDebug ) { BlockHue.R += 50.0f; diff --git a/Engine/Source/Runtime/Slate/Private/Framework/Text/TextLayout.cpp b/Engine/Source/Runtime/Slate/Private/Framework/Text/TextLayout.cpp index 28df3314fbd7..8a1787ccdb2b 100644 --- a/Engine/Source/Runtime/Slate/Private/Framework/Text/TextLayout.cpp +++ b/Engine/Source/Runtime/Slate/Private/Framework/Text/TextLayout.cpp @@ -9,6 +9,7 @@ #include "Internationalization/BreakIterator.h" #include "Framework/Text/ShapedTextCache.h" +DECLARE_CYCLE_STAT(TEXT("Text Layout"), STAT_SlateTextLayout, STATGROUP_Slate); static TAutoConsoleVariable CVarDefaultTextFlowDirection( TEXT("Slate.DefaultTextFlowDirection"), @@ -1115,6 +1116,8 @@ void FTextLayout::UpdateIfNeeded() void FTextLayout::UpdateLayout() { + SCOPE_CYCLE_COUNTER(STAT_SlateTextLayout); + ClearView(); BeginLayout(); @@ -2405,17 +2408,20 @@ void FTextLayout::SetMargin( const FMargin& InMargin ) void FTextLayout::SetScale( float Value ) { - if ( Scale == Value ) + if (FMath::IsNaN(Value)) { - return; + Value = 0.0; } - Scale = Value; - DirtyFlags |= ETextLayoutDirtyState::Layout; + if (Scale != Value) + { + Scale = Value; + DirtyFlags |= ETextLayoutDirtyState::Layout; - // Changing the scale will affect the wrapping information for *all lines* - // Clear out the entire cache so it gets regenerated on the text call to FlowLayout - DirtyAllLineModels(ELineModelDirtyState::WrappingInformation | ELineModelDirtyState::ShapingCache); + // Changing the scale will affect the wrapping information for *all lines* + // Clear out the entire cache so it gets regenerated on the text call to FlowLayout + DirtyAllLineModels(ELineModelDirtyState::WrappingInformation | ELineModelDirtyState::ShapingCache); + } } void FTextLayout::SetTextShapingMethod( const ETextShapingMethod InTextShapingMethod ) diff --git a/Engine/Source/Runtime/Slate/Private/Widgets/Docking/SDockTab.cpp b/Engine/Source/Runtime/Slate/Private/Widgets/Docking/SDockTab.cpp index ac668c5cfb25..444dccdc1bb3 100644 --- a/Engine/Source/Runtime/Slate/Private/Widgets/Docking/SDockTab.cpp +++ b/Engine/Source/Runtime/Slate/Private/Widgets/Docking/SDockTab.cpp @@ -22,6 +22,9 @@ namespace SDockTabDefs /** The amount of time to pass before we switch tabs due to drag event */ static const float DragTimerActivate = 0.75f; + + /** Overrides the tab padding if color overlays are enabled */ + static const float TabVerticalPaddingScaleOverride = 0.85f; } @@ -356,7 +359,7 @@ SDockTab::SDockTab() , OnCanCloseTab() , ContentAreaPadding( 2 ) , bShouldAutosize(false) - , TabColorScale(FLinearColor(0,0,0,0)) + , TabColorScale(FLinearColor::Transparent) , LastActivationTime(0.0) { } @@ -501,18 +504,6 @@ void SDockTab::Construct( const FArguments& InArgs ) SNew(SImage) .Image( this, &SDockTab::GetImageBrush ) ] - // Overlay for color-coded tab effect - + SOverlay::Slot() - [ - SNew(SBorder) - // Don't allow color overlay to absorb mouse clicks - .Visibility( EVisibility::HitTestInvisible ) - - // @todo toolkit major: Replace temp color overlay art with something prettier before enabling it! - .Padding( this, &SDockTab::GetTabPadding ) - .BorderImage( this, &SDockTab::GetColorOverlayImageBrush ) - .BorderBackgroundColor( this, &SDockTab::GetTabColor ) - ] // Overlay for active tab indication. + SOverlay::Slot() @@ -536,24 +527,32 @@ void SDockTab::Construct( const FArguments& InArgs ) ] + SOverlay::Slot() - .Padding( TAttribute::Create( TAttribute::FGetter::CreateSP( this, &SDockTab::GetTabPadding ) ) ) + .Padding(TAttribute::Create(TAttribute::FGetter::CreateSP(this, &SDockTab::GetTabPadding))) .VAlign(VAlign_Center) [ SNew(SHorizontalBox) .Visibility(EVisibility::Visible) - .ToolTip( InArgs._ToolTip ) - .ToolTipText( InArgs._ToolTipText.IsSet() ? InArgs._ToolTipText : TAttribute( this, &SDockTab::GetTabLabel ) ) + .ToolTip(InArgs._ToolTip) + .ToolTipText(InArgs._ToolTipText.IsSet() ? InArgs._ToolTipText : TAttribute(this, &SDockTab::GetTabLabel)) // Tab Icon + SHorizontalBox::Slot() .AutoWidth() .VAlign(VAlign_Center) - .Padding(0,0,5,0) + .Padding(0, 0, 5, 0) [ - SAssignNew( IconWidget, SImage ) - .Image( this, &SDockTab::GetTabIcon ) + SNew(SBorder) + // Don't allow active tab overlay to absorb mouse clicks + .Padding(1.0f) + .Visibility(EVisibility::HitTestInvisible) + // Overlay for color-coded tab effect + .BorderImage(this, &SDockTab::GetColorOverlayImageBrush) + .BorderBackgroundColor(this, &SDockTab::GetTabColor) + [ + SAssignNew(IconWidget, SImage) + .Image(this, &SDockTab::GetTabIcon) + ] ] - // Tab Label + SHorizontalBox::Slot() .FillWidth(1) @@ -623,13 +622,18 @@ const FSlateBrush* SDockTab::GetImageBrush() const FMargin SDockTab::GetTabPadding() const { - return GetCurrentStyle().TabPadding; + FMargin NewPadding = GetCurrentStyle().TabPadding; + if (TabIcon.Get() != FStyleDefaults::GetNoBrush()) + { + NewPadding.Top *= SDockTabDefs::TabVerticalPaddingScaleOverride; + NewPadding.Bottom *= SDockTabDefs::TabVerticalPaddingScaleOverride; + } + return NewPadding; } - const FSlateBrush* SDockTab::GetColorOverlayImageBrush() const { - if (this->TabColorScale.A > 0.0f) + if (this->TabColorScale.Get().A > 0.0f) { return &GetCurrentStyle().ColorOverlayBrush; } @@ -649,7 +653,7 @@ const FSlateBrush* SDockTab::GetActiveTabOverlayImageBrush() const FSlateColor SDockTab::GetTabColor() const { - return TabColorScale; + return TabColorScale.Get(); } diff --git a/Engine/Source/Runtime/Slate/Private/Widgets/Input/SButton.cpp b/Engine/Source/Runtime/Slate/Private/Widgets/Input/SButton.cpp index eff853cad392..aabc452876ba 100644 --- a/Engine/Source/Runtime/Slate/Private/Widgets/Input/SButton.cpp +++ b/Engine/Source/Runtime/Slate/Private/Widgets/Input/SButton.cpp @@ -208,6 +208,7 @@ FReply SButton::OnMouseButtonDown( const FGeometry& MyGeometry, const FPointerEv if (IsEnabled() && (MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton || MouseEvent.IsTouchEvent())) { Press(); + PressedScreenSpacePosition = MouseEvent.GetScreenSpacePosition(); if( ClickMethod == EButtonClickMethod::MouseDown ) { @@ -221,11 +222,12 @@ FReply SButton::OnMouseButtonDown( const FGeometry& MyGeometry, const FPointerEv { // do not capture the pointer for precise taps or clicks // + Reply = FReply::Handled(); } else { //we need to capture the mouse for MouseUp events - Reply = FReply::Handled().CaptureMouse( AsShared() ); + Reply = FReply::Handled().CaptureMouse( AsShared() ); } } @@ -235,7 +237,6 @@ FReply SButton::OnMouseButtonDown( const FGeometry& MyGeometry, const FPointerEv return Reply; } - FReply SButton::OnMouseButtonDoubleClick( const FGeometry& InMyGeometry, const FPointerEvent& InMouseEvent ) { return OnMouseButtonDown( InMyGeometry, InMouseEvent ); @@ -247,35 +248,40 @@ FReply SButton::OnMouseButtonUp( const FGeometry& MyGeometry, const FPointerEven const bool bMustBePressed = ClickMethod == EButtonClickMethod::DownAndUp || IsPreciseTapOrClick(MouseEvent); const bool bMeetsPressedRequirements = (!bMustBePressed || (bIsPressed && bMustBePressed)); - if (bMeetsPressedRequirements && IsEnabled() && ( MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton || MouseEvent.IsTouchEvent() ) ) + if (bMeetsPressedRequirements && ( ( MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton || MouseEvent.IsTouchEvent()))) { Release(); - if( ClickMethod == EButtonClickMethod::MouseDown ) + if ( IsEnabled() ) { - // NOTE: If we're configured to click on mouse-down/precise-tap, then we never capture the mouse thus - // may never receive an OnMouseButtonUp() call. We make sure that our bIsPressed - // state is reset by overriding OnMouseLeave(). - } - else - { - bool bEventOverButton = IsHovered(); - if (!bEventOverButton && MouseEvent.IsTouchEvent()) + if ( ClickMethod == EButtonClickMethod::MouseDown ) { - bEventOverButton = MyGeometry.IsUnderLocation(MouseEvent.GetScreenSpacePosition()); + // NOTE: If we're configured to click on mouse-down/precise-tap, then we never capture the mouse thus + // may never receive an OnMouseButtonUp() call. We make sure that our bIsPressed + // state is reset by overriding OnMouseLeave(). } - if (bEventOverButton) + else { - // If we asked for a precise tap, all we need is for the user to have not moved their pointer very far. - const bool bTriggerForTouchEvent = IsPreciseTapOrClick(MouseEvent); + bool bEventOverButton = IsHovered(); - // If we were asked to allow the button to be clicked on mouse up, regardless of whether the user - // pressed the button down first, then we'll allow the click to proceed without an active capture - const bool bTriggerForMouseEvent = ( ClickMethod == EButtonClickMethod::MouseUp || HasMouseCapture() ); - - if( (bTriggerForTouchEvent || bTriggerForMouseEvent) && OnClicked.IsBound() == true ) + if ( !bEventOverButton && MouseEvent.IsTouchEvent() ) { - Reply = OnClicked.Execute(); + bEventOverButton = MyGeometry.IsUnderLocation(MouseEvent.GetScreenSpacePosition()); + } + + if ( bEventOverButton ) + { + // If we asked for a precise tap, all we need is for the user to have not moved their pointer very far. + const bool bTriggerForTouchEvent = IsPreciseTapOrClick(MouseEvent); + + // If we were asked to allow the button to be clicked on mouse up, regardless of whether the user + // pressed the button down first, then we'll allow the click to proceed without an active capture + const bool bTriggerForMouseEvent = ( ClickMethod == EButtonClickMethod::MouseUp || HasMouseCapture() ); + + if ( ( bTriggerForTouchEvent || bTriggerForMouseEvent ) && OnClicked.IsBound() == true ) + { + Reply = OnClicked.Execute(); + } } } } @@ -302,11 +308,11 @@ FReply SButton::OnMouseButtonUp( const FGeometry& MyGeometry, const FPointerEven FReply SButton::OnMouseMove( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) { - const float SlateDragStartDistance = FSlateApplication::Get().GetDragTriggerDistance(); - if ( IsPreciseTapOrClick(MouseEvent) && MouseEvent.GetCursorDelta().SizeSquared() > ( SlateDragStartDistance*SlateDragStartDistance ) ) + if ( IsPressed() && IsPreciseTapOrClick(MouseEvent) && FSlateApplication::Get().HasTraveledFarEnoughToTriggerDrag(MouseEvent, PressedScreenSpacePosition) ) { Release(); } + return FReply::Unhandled(); } @@ -341,14 +347,17 @@ void SButton::OnMouseLeave( const FPointerEvent& MouseEvent ) Invalidate(EInvalidateWidget::Layout); } +void SButton::OnMouseCaptureLost() +{ + Release(); +} + void SButton::Press() { if ( !bIsPressed ) { bIsPressed = true; - PlayPressedSound(); - OnPressed.ExecuteIfBound(); } } @@ -443,3 +452,18 @@ void SButton::SetButtonStyle(const FButtonStyle* ButtonStyle) HoveredSound = Style->HoveredSlateSound; PressedSound = Style->PressedSlateSound; } + +void SButton::SetClickMethod(EButtonClickMethod::Type InClickMethod) +{ + ClickMethod = InClickMethod; +} + +void SButton::SetTouchMethod(EButtonTouchMethod::Type InTouchMethod) +{ + TouchMethod = InTouchMethod; +} + +void SButton::SetPressMethod(EButtonPressMethod::Type InPressMethod) +{ + PressMethod = InPressMethod; +} \ No newline at end of file diff --git a/Engine/Source/Runtime/Slate/Private/Widgets/Input/SInputKeySelector.cpp b/Engine/Source/Runtime/Slate/Private/Widgets/Input/SInputKeySelector.cpp index 249c304005df..0d897e7e793b 100644 --- a/Engine/Source/Runtime/Slate/Private/Widgets/Input/SInputKeySelector.cpp +++ b/Engine/Source/Runtime/Slate/Private/Widgets/Input/SInputKeySelector.cpp @@ -8,14 +8,15 @@ void SInputKeySelector::Construct( const FArguments& InArgs ) { SelectedKey = InArgs._SelectedKey; + KeySelectionText = InArgs._KeySelectionText; + NoKeySpecifiedText = InArgs._NoKeySpecifiedText; OnKeySelected = InArgs._OnKeySelected; - Font = InArgs._Font; - ColorAndOpacity = InArgs._ColorAndOpacity; OnIsSelectingKeyChanged = InArgs._OnIsSelectingKeyChanged; bAllowModifierKeys = InArgs._AllowModifierKeys; + bAllowGamepadKeys = InArgs._AllowGamepadKeys; bEscapeCancelsSelection = InArgs._EscapeCancelsSelection; - - DefaultFont = FCoreStyle::Get().GetWidgetStyle( "NormalText" ).Font; + EscapeKeys = InArgs._EscapeKeys; + bIsFocusable = InArgs._IsFocusable; bIsSelectingKey = false; @@ -23,13 +24,13 @@ void SInputKeySelector::Construct( const FArguments& InArgs ) [ SAssignNew(Button, SButton) .ButtonStyle(InArgs._ButtonStyle) + .IsFocusable(bIsFocusable) .OnClicked(this, &SInputKeySelector::OnClicked) [ - SNew(STextBlock) + SAssignNew(TextBlock, STextBlock) .Text(this, &SInputKeySelector::GetSelectedKeyText) - .Font(this, &SInputKeySelector::GetFont) + .TextStyle(InArgs._TextStyle) .Margin(Margin) - .ColorAndOpacity(this, &SInputKeySelector::GetSlateColorAndOpacity) .Justification(ETextJustify::Center) ] ]; @@ -51,9 +52,8 @@ FText SInputKeySelector::GetSelectedKeyText() const ? SelectedKey.Get().Key.GetDisplayName() : SelectedKey.Get().GetInputText(); } - return FText(); } - return FText(); + return NoKeySpecifiedText; } FInputChord SInputKeySelector::GetSelectedKey() const @@ -70,16 +70,6 @@ void SInputKeySelector::SetSelectedKey( TAttribute InSelectedKey ) } } -FSlateFontInfo SInputKeySelector::GetFont() const -{ - return Font.IsSet() ? Font.Get() : DefaultFont; -} - -void SInputKeySelector::SetFont( TAttribute InFont ) -{ - Font = InFont; -} - FMargin SInputKeySelector::GetMargin() const { return Margin.Get(); @@ -90,34 +80,20 @@ void SInputKeySelector::SetMargin( TAttribute InMargin ) Margin = InMargin; } -FSlateColor SInputKeySelector::GetSlateColorAndOpacity() const -{ - return FSlateColor(GetColorAndOpacity()); -} - -void SInputKeySelector::SetColorAndOpacity( TAttribute InColorAndOpacity ) -{ - ColorAndOpacity = InColorAndOpacity; -} - void SInputKeySelector::SetButtonStyle(const FButtonStyle* ButtonStyle ) { - Button->SetButtonStyle(ButtonStyle); + if (Button.IsValid()) + { + Button->SetButtonStyle(ButtonStyle); + } } -void SInputKeySelector::SetKeySelectionText( FText InKeySelectionText ) +void SInputKeySelector::SetTextStyle(const FTextBlockStyle* InTextStyle) { - KeySelectionText = InKeySelectionText; -} - -void SInputKeySelector::SetAllowModifierKeys( bool bInAllowModifierKeys ) -{ - bAllowModifierKeys = bInAllowModifierKeys; -} - -bool SInputKeySelector::GetIsSelectingKey() const -{ - return bIsSelectingKey; + if (TextBlock.IsValid()) + { + TextBlock->SetTextStyle(InTextStyle); + } } FReply SInputKeySelector::OnClicked() @@ -152,21 +128,34 @@ void SInputKeySelector::SetIsSelectingKey( bool bInIsSelectingKey ) } } +bool SInputKeySelector::IsEscapeKey(const FKey& InKey) const +{ + return EscapeKeys.Contains(InKey); +} + FReply SInputKeySelector::OnPreviewKeyDown( const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent ) { - // TODO: Add an argument to allow gamepad key selection. - if ( bIsSelectingKey && InKeyEvent.GetKey().IsGamepadKey() == false) + if ( bIsSelectingKey && (bAllowGamepadKeys || InKeyEvent.GetKey().IsGamepadKey() == false) ) { // While selecting keys handle all key downs to prevent contained controls from // interfering with key selection. return FReply::Handled(); } - return SWidget::OnPreviewKeyDown( MyGeometry, InKeyEvent ); + return SCompoundWidget::OnPreviewKeyDown( MyGeometry, InKeyEvent ); +} + +FReply SInputKeySelector::OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) +{ + if (!bIsSelectingKey && SelectedKey.IsSet() && SelectedKey.Get().Key.IsValid() && (bAllowGamepadKeys && InKeyEvent.GetKey() == EKeys::Gamepad_FaceButton_Left)) + { + SelectedKey = FInputChord(); + return FReply::Handled(); + } + return SCompoundWidget::OnKeyDown(MyGeometry, InKeyEvent); } FReply SInputKeySelector::OnKeyUp( const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent ) { - // TODO: Add an argument to allow gamepad key selection. FKey KeyUp = InKeyEvent.GetKey(); EModifierKey::Type ModifierKey = EModifierKey::FromBools( InKeyEvent.IsControlDown() && KeyUp != EKeys::LeftControl && KeyUp != EKeys::RightControl, @@ -175,11 +164,12 @@ FReply SInputKeySelector::OnKeyUp( const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent.IsCommandDown() && KeyUp != EKeys::LeftCommand && KeyUp != EKeys::RightCommand ); // Don't allow chords consisting of just modifier keys. - if ( bIsSelectingKey && KeyUp.IsGamepadKey() == false && ( KeyUp.IsModifierKey() == false || ModifierKey == EModifierKey::None ) ) + if ( bIsSelectingKey && (bAllowGamepadKeys || KeyUp.IsGamepadKey() == false) && ( KeyUp.IsModifierKey() == false || ModifierKey == EModifierKey::None ) ) { SetIsSelectingKey( false ); - if ( KeyUp == EKeys::Escape && bEscapeCancelsSelection ) + if ((InKeyEvent.GetKey() == EKeys::PS4_Special) || // Required? + (bEscapeCancelsSelection && (KeyUp == EKeys::Escape || IsEscapeKey(KeyUp)))) { return FReply::Handled(); } @@ -192,7 +182,8 @@ FReply SInputKeySelector::OnKeyUp( const FGeometry& MyGeometry, const FKeyEvent& ModifierKey == EModifierKey::Command); return FReply::Handled(); } - return SWidget::OnPreviewKeyDown( MyGeometry, InKeyEvent ); + + return SCompoundWidget::OnKeyUp( MyGeometry, InKeyEvent ); } FReply SInputKeySelector::OnPreviewMouseButtonDown( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) @@ -204,7 +195,27 @@ FReply SInputKeySelector::OnPreviewMouseButtonDown( const FGeometry& MyGeometry, SelectKey(MouseEvent.GetEffectingButton(), false, false, false, false); return FReply::Handled(); } - return SWidget::OnPreviewMouseButtonDown( MyGeometry, MouseEvent ); + return SCompoundWidget::OnPreviewMouseButtonDown( MyGeometry, MouseEvent ); +} + +FReply SInputKeySelector::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) +{ + if (!bIsSelectingKey && SelectedKey.IsSet() && SelectedKey.Get().Key.IsValid() && MouseEvent.IsMouseButtonDown(EKeys::RightMouseButton)) + { + SelectedKey = FInputChord(); + return FReply::Handled(); + } + return SCompoundWidget::OnMouseButtonDown(MyGeometry, MouseEvent); +} + +FNavigationReply SInputKeySelector::OnNavigation(const FGeometry& MyGeometry, const FNavigationEvent& InNavigationEvent) +{ + if (Button.IsValid()) + { + return Button->OnNavigation(MyGeometry, InNavigationEvent); + } + + return SCompoundWidget::OnNavigation(MyGeometry, InNavigationEvent); } void SInputKeySelector::OnFocusLost( const FFocusEvent& InFocusEvent ) diff --git a/Engine/Source/Runtime/Slate/Private/Widgets/Input/SMenuAnchor.cpp b/Engine/Source/Runtime/Slate/Private/Widgets/Input/SMenuAnchor.cpp index c6ab1cb33411..66f8a74882d2 100644 --- a/Engine/Source/Runtime/Slate/Private/Widgets/Input/SMenuAnchor.cpp +++ b/Engine/Source/Runtime/Slate/Private/Widgets/Input/SMenuAnchor.cpp @@ -85,6 +85,7 @@ FGeometry ComputeMenuPlacement(const FGeometry& AllottedGeometry, const FVector2 const FVector2D NewPositionDesktopSpace = FSlateApplication::Get().CalculatePopupWindowPosition( TransformRect(AllottedGeometry.GetAccumulatedLayoutTransform(), Placement.AnchorLocalSpace), TransformVector(AllottedGeometry.GetAccumulatedLayoutTransform(), Placement.LocalPopupSize), + TransformPoint(AllottedGeometry.GetAccumulatedLayoutTransform(), Placement.LocalPopupOffset), Placement.Orientation); // transform the desktop offset into local space and use that as the layout transform for the child content. @@ -430,7 +431,7 @@ void SMenuAnchor::SetIsOpen( bool InIsOpen, const bool bFocusMenu, const int32 F MenuContentRef->SlatePrepass(FSlateApplication::Get().GetApplicationScale()); // @todo slate: Doesn't take into account potential window border size FVector2D ExpectedSize = MenuContentRef->GetDesiredSize(); - const FVector2D ScreenPosition = FSlateApplication::Get().CalculatePopupWindowPosition(Anchor, ExpectedSize, Orientation); + const FVector2D ScreenPosition = FSlateApplication::Get().CalculatePopupWindowPosition(Anchor, ExpectedSize, FVector2D::ZeroVector, Orientation); // Release the mouse so that context can be properly restored upon closing menus. See CL 1411833 before changing this. if (bFocusMenu) diff --git a/Engine/Source/Runtime/Slate/Private/Widgets/Input/SSubMenuHandler.cpp b/Engine/Source/Runtime/Slate/Private/Widgets/Input/SSubMenuHandler.cpp index 0265c7e1449c..46504e596ea1 100644 --- a/Engine/Source/Runtime/Slate/Private/Widgets/Input/SSubMenuHandler.cpp +++ b/Engine/Source/Runtime/Slate/Private/Widgets/Input/SSubMenuHandler.cpp @@ -20,7 +20,7 @@ void SSubMenuHandler::Construct(const FArguments& InArgs, TWeakPtr I if (InArgs._OnGetMenuContent.IsBound() || InArgs._MenuContent.IsValid()) { ChildSlotWidget = SAssignNew(MenuAnchor, SMenuAnchor) - .Placement(EMenuPlacement::MenuPlacement_MenuRight) + .Placement(InArgs._Placement) .OnGetMenuContent(InArgs._OnGetMenuContent) .MenuContent(InArgs._MenuContent) [ diff --git a/Engine/Source/Runtime/Slate/Private/Widgets/Layout/SConstraintCanvas.cpp b/Engine/Source/Runtime/Slate/Private/Widgets/Layout/SConstraintCanvas.cpp index dc45e8f74e34..5f140957fbbc 100644 --- a/Engine/Source/Runtime/Slate/Private/Widgets/Layout/SConstraintCanvas.cpp +++ b/Engine/Source/Runtime/Slate/Private/Widgets/Layout/SConstraintCanvas.cpp @@ -131,9 +131,8 @@ void SConstraintCanvas::ArrangeLayeredChildren(const FGeometry& AllottedGeometry const bool bIsVerticalStretch = Anchors.Minimum.Y != Anchors.Maximum.Y; const FVector2D SlotSize = FVector2D(Offset.Right, Offset.Bottom); - const FVector2D WidgetDesiredSize = CurWidget->GetDesiredSize(); - const FVector2D Size = AutoSize ? WidgetDesiredSize : SlotSize; + const FVector2D Size = AutoSize ? CurWidget->GetDesiredSize() : SlotSize; // Calculate the offset based on the pivot position. FVector2D AlignmentOffset = Size * Alignment; @@ -252,11 +251,10 @@ FVector2D SConstraintCanvas::ComputeDesiredSize( float ) const const FAnchors Anchors = CurChild.AnchorsAttr.Get(); const FVector2D SlotSize = FVector2D(Offset.Right, Offset.Bottom); - const FVector2D WidgetDesiredSize = Widget->GetDesiredSize(); const bool AutoSize = CurChild.AutoSizeAttr.Get(); - const FVector2D Size = AutoSize ? WidgetDesiredSize : SlotSize; + const FVector2D Size = AutoSize ? Widget->GetDesiredSize() : SlotSize; const bool bIsDockedHorizontally = ( Anchors.Minimum.X == Anchors.Maximum.X ) && ( Anchors.Minimum.X == 0 || Anchors.Minimum.X == 1 ); const bool bIsDockedVertically = ( Anchors.Minimum.Y == Anchors.Maximum.Y ) && ( Anchors.Minimum.Y == 0 || Anchors.Minimum.Y == 1 ); diff --git a/Engine/Source/Runtime/Slate/Private/Widgets/Layout/SSafeZone.cpp b/Engine/Source/Runtime/Slate/Private/Widgets/Layout/SSafeZone.cpp index 16e2e108d274..a1a118c02ec3 100644 --- a/Engine/Source/Runtime/Slate/Private/Widgets/Layout/SSafeZone.cpp +++ b/Engine/Source/Runtime/Slate/Private/Widgets/Layout/SSafeZone.cpp @@ -30,9 +30,15 @@ void SSafeZone::Construct( const FArguments& InArgs ) SetTitleSafe(bIsTitleSafe); - FCoreDelegates::OnSafeFrameChangedEvent.AddSP(this, &SSafeZone::SafeAreaUpdated); + OnSafeFrameChangedHandle = FCoreDelegates::OnSafeFrameChangedEvent.AddSP(this, &SSafeZone::SafeAreaUpdated); } +SSafeZone::~SSafeZone() +{ + FCoreDelegates::OnSafeFrameChangedEvent.Remove(OnSafeFrameChangedHandle); +} + + void SSafeZone::SafeAreaUpdated() { SetTitleSafe(bIsTitleSafe); diff --git a/Engine/Source/Runtime/Slate/Private/Widgets/Layout/SScaleBox.cpp b/Engine/Source/Runtime/Slate/Private/Widgets/Layout/SScaleBox.cpp index c8cdeb58786a..28856988aea0 100644 --- a/Engine/Source/Runtime/Slate/Private/Widgets/Layout/SScaleBox.cpp +++ b/Engine/Source/Runtime/Slate/Private/Widgets/Layout/SScaleBox.cpp @@ -18,6 +18,11 @@ void SScaleBox::Construct( const SScaleBox::FArguments& InArgs ) StretchDirection = InArgs._StretchDirection; UserSpecifiedScale = InArgs._UserSpecifiedScale; IgnoreInheritedScale = InArgs._IgnoreInheritedScale; + bSingleLayoutPass = InArgs._SingleLayoutPass; + + LastIncomingScale = 1.0f; + LastAreaSize = FVector2D(0, 0); + LastFinalOffset = FVector2D(0, 0); ChildSlot .HAlign(InArgs._HAlign) @@ -26,7 +31,12 @@ void SScaleBox::Construct( const SScaleBox::FArguments& InArgs ) InArgs._Content.Widget ]; - FCoreDelegates::OnSafeFrameChangedEvent.AddSP(this, &SScaleBox::RefreshSafeZoneScale); + OnSafeFrameChangedHandle = FCoreDelegates::OnSafeFrameChangedEvent.AddSP(this, &SScaleBox::RefreshSafeZoneScale); +} + +SScaleBox::~SScaleBox() +{ + FCoreDelegates::OnSafeFrameChangedEvent.Remove(OnSafeFrameChangedHandle); } /* SWidget overrides @@ -42,93 +52,132 @@ void SScaleBox::OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedC float FinalScale = 1; - const EStretch::Type CurrentStretch = Stretch.Get(); - const EStretchDirection::Type CurrentStretchDirection = StretchDirection.Get(); + bool bAllowFullLayout = true; - if (SlotWidgetDesiredSize.X != 0 && SlotWidgetDesiredSize.Y != 0 ) + if ( bSingleLayoutPass && LastContentDesiredSize.IsSet() && LastFinalScale.IsSet() && LastAreaSize.Equals(AreaSize) && FMath::IsNearlyEqual(LastIncomingScale, AllottedGeometry.Scale) ) { - switch ( CurrentStretch ) + if ( SlotWidgetDesiredSize.Equals(LastContentDesiredSize.GetValue()) ) { - case EStretch::None: - break; - case EStretch::Fill: - SlotWidgetDesiredSize = AreaSize; - break; - case EStretch::ScaleToFit: - FinalScale = FMath::Min(AreaSize.X / SlotWidgetDesiredSize.X, AreaSize.Y / SlotWidgetDesiredSize.Y); - break; - case EStretch::ScaleToFitX: - FinalScale = AreaSize.X / SlotWidgetDesiredSize.X; - break; - case EStretch::ScaleToFitY: - FinalScale = AreaSize.Y / SlotWidgetDesiredSize.Y; - break; - case EStretch::ScaleToFill: - FinalScale = FMath::Max(AreaSize.X / SlotWidgetDesiredSize.X, AreaSize.Y / SlotWidgetDesiredSize.Y); - break; - case EStretch::ScaleBySafeZone: - FinalScale = SafeZoneScale; - break; - case EStretch::UserSpecified: - FinalScale = UserSpecifiedScale.Get(1.0f); - break; - } - - switch ( CurrentStretchDirection ) - { - case EStretchDirection::DownOnly: - FinalScale = FMath::Min(FinalScale, 1.0f); - break; - case EStretchDirection::UpOnly: - FinalScale = FMath::Max(FinalScale, 1.0f); - break; - case EStretchDirection::Both: - break; + bAllowFullLayout = false; + FinalScale = LastFinalScale.GetValue(); } } - if (IgnoreInheritedScale.Get(false) && AllottedGeometry.Scale != 0) + if ( bAllowFullLayout ) { - FinalScale /= AllottedGeometry.Scale; - } + const EStretch::Type CurrentStretch = Stretch.Get(); + const EStretchDirection::Type CurrentStretchDirection = StretchDirection.Get(); - FVector2D FinalOffset(0, 0); + bool bRequiresAnotherPrepass = CurrentStretch != EStretch::UserSpecified && CurrentStretch != EStretch::ScaleBySafeZone; - // If we're just filling, there's no scale applied, we're just filling the area. - if ( CurrentStretch != EStretch::Fill ) - { - const FMargin SlotPadding(ChildSlot.SlotPadding.Get()); - AlignmentArrangeResult XResult = AlignChild(AreaSize.X, ChildSlot, SlotPadding, FinalScale, false); - AlignmentArrangeResult YResult = AlignChild(AreaSize.Y, ChildSlot, SlotPadding, FinalScale, false); - - FinalOffset = FVector2D(XResult.Offset, YResult.Offset) / FinalScale; - - // If the layout horizontally is fill, then we need the desired size to be the whole size of the widget, - // but scale the inverse of the scale we're applying. - if ( ChildSlot.HAlignment == HAlign_Fill ) + if ( SlotWidgetDesiredSize.X != 0 && SlotWidgetDesiredSize.Y != 0 ) { - SlotWidgetDesiredSize.X = AreaSize.X / FinalScale; + switch ( CurrentStretch ) + { + case EStretch::None: + bRequiresAnotherPrepass = false; + break; + case EStretch::Fill: + SlotWidgetDesiredSize = AreaSize; + bRequiresAnotherPrepass = false; + break; + case EStretch::ScaleToFit: + FinalScale = FMath::Min(AreaSize.X / SlotWidgetDesiredSize.X, AreaSize.Y / SlotWidgetDesiredSize.Y); + break; + case EStretch::ScaleToFitX: + FinalScale = AreaSize.X / SlotWidgetDesiredSize.X; + break; + case EStretch::ScaleToFitY: + FinalScale = AreaSize.Y / SlotWidgetDesiredSize.Y; + break; + case EStretch::ScaleToFill: + FinalScale = FMath::Max(AreaSize.X / SlotWidgetDesiredSize.X, AreaSize.Y / SlotWidgetDesiredSize.Y); + break; + case EStretch::ScaleBySafeZone: + FinalScale = SafeZoneScale; + bRequiresAnotherPrepass = false; + break; + case EStretch::UserSpecified: + FinalScale = UserSpecifiedScale.Get(1.0f); + bRequiresAnotherPrepass = false; + break; + } + + switch ( CurrentStretchDirection ) + { + case EStretchDirection::DownOnly: + FinalScale = FMath::Min(FinalScale, 1.0f); + break; + case EStretchDirection::UpOnly: + FinalScale = FMath::Max(FinalScale, 1.0f); + break; + case EStretchDirection::Both: + break; + } + + LastFinalScale = FinalScale; + } + else + { + LastFinalScale.Reset(); } - // If the layout vertically is fill, then we need the desired size to be the whole size of the widget, - // but scale the inverse of the scale we're applying. - if ( ChildSlot.VAlignment == VAlign_Fill ) + if ( IgnoreInheritedScale.Get(false) && AllottedGeometry.Scale != 0 ) { - SlotWidgetDesiredSize.Y = AreaSize.Y / FinalScale; + FinalScale /= AllottedGeometry.Scale; } - } - if ( CurrentStretch != EStretch::UserSpecified && CurrentStretch != EStretch::ScaleBySafeZone ) - { - // We need to run another pre-pass now that we know the final scale. - // This will allow things that don't scale linearly (such as text) to update their size and layout correctly. - ChildSlot.GetWidget()->SlatePrepass(AllottedGeometry.GetAccumulatedLayoutTransform().GetScale() * FinalScale); + LastFinalOffset = FVector2D(0, 0); + + // If we're just filling, there's no scale applied, we're just filling the area. + if ( CurrentStretch != EStretch::Fill ) + { + const FMargin SlotPadding(ChildSlot.SlotPadding.Get()); + AlignmentArrangeResult XResult = AlignChild(AreaSize.X, ChildSlot, SlotPadding, FinalScale, false); + AlignmentArrangeResult YResult = AlignChild(AreaSize.Y, ChildSlot, SlotPadding, FinalScale, false); + + LastFinalOffset = FVector2D(XResult.Offset, YResult.Offset) / FinalScale; + + // If the layout horizontally is fill, then we need the desired size to be the whole size of the widget, + // but scale the inverse of the scale we're applying. + if ( ChildSlot.HAlignment == HAlign_Fill ) + { + SlotWidgetDesiredSize.X = AreaSize.X / FinalScale; + } + + // If the layout vertically is fill, then we need the desired size to be the whole size of the widget, + // but scale the inverse of the scale we're applying. + if ( ChildSlot.VAlignment == VAlign_Fill ) + { + SlotWidgetDesiredSize.Y = AreaSize.Y / FinalScale; + } + } + + LastAreaSize = AreaSize; + LastIncomingScale = AllottedGeometry.Scale; + LastSlotWidgetDesiredSize = SlotWidgetDesiredSize; + + if ( bRequiresAnotherPrepass ) + { + // We need to run another pre-pass now that we know the final scale. + // This will allow things that don't scale linearly (such as text) to update their size and layout correctly. + // + // NOTE: This step is pretty expensive especially if you're nesting scale boxes. + ChildSlot.GetWidget()->SlatePrepass(AllottedGeometry.GetAccumulatedLayoutTransform().GetScale() * FinalScale); + + LastContentDesiredSize = ChildSlot.GetWidget()->GetDesiredSize(); + } + else + { + LastContentDesiredSize.Reset(); + LastFinalScale.Reset(); + } } ArrangedChildren.AddWidget(ChildVisibility, AllottedGeometry.MakeChild( ChildSlot.GetWidget(), - FinalOffset, - SlotWidgetDesiredSize, + LastFinalOffset, + LastSlotWidgetDesiredSize, FinalScale ) ); } @@ -201,7 +250,7 @@ float SScaleBox::GetRelativeLayoutScale(const FSlotBase& Child, float LayoutScal float SScaleBox::GetLayoutScale() const { const EStretch::Type CurrentStretch = Stretch.Get(); - + switch (CurrentStretch) { case EStretch::ScaleBySafeZone: @@ -209,6 +258,14 @@ float SScaleBox::GetLayoutScale() const case EStretch::UserSpecified: return UserSpecifiedScale.Get(1.0f); default: + if ( bSingleLayoutPass ) + { + if ( LastFinalScale.IsSet() ) + { + return LastFinalScale.GetValue(); + } + } + // Because our scale is determined by our size, we always report a scale of 1.0 here, // as reporting our actual scale can cause a feedback loop whereby the calculated size changes each frame. // We workaround this by forcibly pre-passing our child content a second time once we know its final scale in OnArrangeChildren. @@ -237,7 +294,6 @@ void SScaleBox::RefreshSafeZoneScale() ScaleDownBy = (Metrics.TitleSafePaddingSize.X * 2.f) / (float)ViewportSize.X; } } - } SafeZoneScale = 1.f - ScaleDownBy; diff --git a/Engine/Source/Runtime/Slate/Private/Widgets/Layout/SScrollBar.cpp b/Engine/Source/Runtime/Slate/Private/Widgets/Layout/SScrollBar.cpp index cd27f01f9b2b..bdf5f7297fd8 100644 --- a/Engine/Source/Runtime/Slate/Private/Widgets/Layout/SScrollBar.cpp +++ b/Engine/Source/Runtime/Slate/Private/Widgets/Layout/SScrollBar.cpp @@ -6,6 +6,7 @@ #include "Widgets/Layout/SSpacer.h" #include "Widgets/Images/SImage.h" #include "Widgets/Layout/SBox.h" +#include "Framework/Application/SlateApplication.h" /** * Construct this widget @@ -24,6 +25,10 @@ void SScrollBar::Construct(const FArguments& InArgs) EHorizontalAlignment HorizontalAlignment = Orientation == Orient_Vertical ? HAlign_Center : HAlign_Fill; EVerticalAlignment VerticalAlignment = Orientation == Orient_Vertical ? VAlign_Fill : VAlign_Center; + bHideWhenNotInUse = InArgs._HideWhenNotInUse; + bIsScrolling = false; + LastInteractionTime = 0; + SBorder::Construct( SBorder::FArguments() .BorderImage(FCoreStyle::Get().GetBrush("NoBorder")) .BorderBackgroundColor( this, &SScrollBar::GetTrackOpacity ) @@ -89,19 +94,16 @@ void SScrollBar::SetOnUserScrolled( const FOnUserScrolled& InHandler ) void SScrollBar::SetState( float InOffsetFraction, float InThumbSizeFraction ) { - // Note that the maximum offset depends on how many items fit per screen - // It is 1.0f-InThumbSizeFraction. - Track->SetSizes( InOffsetFraction, InThumbSizeFraction ); + if ( Track->DistanceFromTop() != InOffsetFraction || Track->GetThumbSizeFraction() != InThumbSizeFraction ) + { + // Note that the maximum offset depends on how many items fit per screen + // It is 1.0f-InThumbSizeFraction. + Track->SetSizes(InOffsetFraction, InThumbSizeFraction); + + LastInteractionTime = FSlateApplication::Get().GetCurrentTime(); + } } -/** - * The system calls this method to notify the widget that a mouse button was pressed within it. This event is bubbled. - * - * @param MyGeometry The Geometry of the widget receiving the event - * @param MouseEvent Information about the input event - * - * @return Whether the event was handled along with possible requests for the system to take action. - */ FReply SScrollBar::OnMouseButtonDown( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) { if ( MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton ) @@ -142,14 +144,6 @@ FReply SScrollBar::OnMouseButtonDown( const FGeometry& MyGeometry, const FPointe } } -/** - * The system calls this method to notify the widget that a mouse button was release within it. This event is bubbled. - * - * @param MyGeometry The Geometry of the widget receiving the event - * @param MouseEvent Information about the input event - * - * @return Whether the event was handled along with possible requests for the system to take action. - */ FReply SScrollBar::OnMouseButtonUp( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) { if ( MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton ) @@ -163,14 +157,6 @@ FReply SScrollBar::OnMouseButtonUp( const FGeometry& MyGeometry, const FPointerE } } -/** - * The system calls this method to notify the widget that a mouse moved within it. This event is bubbled. - * - * @param MyGeometry The Geometry of the widget receiving the event - * @param MouseEvent Information about the input event - * - * @return Whether the event was handled along with possible requests for the system to take action. - */ FReply SScrollBar::OnMouseMove( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) { if ( this->HasMouseCapture() && !MouseEvent.GetCursorDelta().IsZero() ) @@ -187,6 +173,18 @@ FReply SScrollBar::OnMouseMove( const FGeometry& MyGeometry, const FPointerEvent } } +void SScrollBar::OnMouseEnter(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) +{ + SBorder::OnMouseEnter(MyGeometry, MouseEvent); + LastInteractionTime = FSlateApplication::Get().GetCurrentTime(); +} + +void SScrollBar::OnMouseLeave(const FPointerEvent& MouseEvent) +{ + SBorder::OnMouseLeave(MouseEvent); + LastInteractionTime = FSlateApplication::Get().GetCurrentTime(); +} + void SScrollBar::ExecuteOnUserScrolled( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) { const int32 AxisId = (Orientation == Orient_Horizontal) ? 0 : 1; @@ -223,7 +221,7 @@ SScrollBar::SScrollBar() FSlateColor SScrollBar::GetTrackOpacity() const { - if ( bDraggingThumb || this->IsHovered() ) + if ( bDraggingThumb || IsHovered() ) { return FLinearColor(1,1,1,1); } @@ -233,19 +231,38 @@ FSlateColor SScrollBar::GetTrackOpacity() const } } - FLinearColor SScrollBar::GetThumbOpacity() const { - if ( bDraggingThumb || this->IsHovered() ) + if ( bDraggingThumb || IsHovered() ) { return FLinearColor(1,1,1,1); } else { - return FLinearColor(1,1,1,0.75f); + if ( bHideWhenNotInUse ) + { + const double LastInteractionDelta = bIsScrolling ? 0 : ( FSlateApplication::Get().GetCurrentTime() - LastInteractionTime ); + + float Opacity = FMath::Lerp(1.0f, 0.0f, FMath::Clamp((float)( ( LastInteractionDelta - 0.2 ) / 0.2 ), 0.0f, 1.0f)); + return FLinearColor(1, 1, 1, Opacity); + } + else + { + return FLinearColor(1, 1, 1, 0.75f); + } } } +void SScrollBar::BeginScrolling() +{ + bIsScrolling = true; +} + +void SScrollBar::EndScrolling() +{ + bIsScrolling = false; + LastInteractionTime = FSlateApplication::Get().GetCurrentTime(); +} const FSlateBrush* SScrollBar::GetDragThumbImage() const { diff --git a/Engine/Source/Runtime/Slate/Private/Widgets/Layout/SScrollBox.cpp b/Engine/Source/Runtime/Slate/Private/Widgets/Layout/SScrollBox.cpp index c86a782949e3..e3bbf15896c9 100644 --- a/Engine/Source/Runtime/Slate/Private/Widgets/Layout/SScrollBox.cpp +++ b/Engine/Source/Runtime/Slate/Private/Widgets/Layout/SScrollBox.cpp @@ -81,17 +81,25 @@ public: } } + virtual FChildren* GetChildren() override + { + return &Children; + } + float PhysicalOffset; + TPanelChildren Children; + +protected: virtual FVector2D ComputeDesiredSize(float) const override { FVector2D ThisDesiredSize = FVector2D::ZeroVector; - for(int32 SlotIndex=0; SlotIndex < Children.Num(); ++SlotIndex ) + for ( int32 SlotIndex=0; SlotIndex < Children.Num(); ++SlotIndex ) { const SScrollBox::FSlot& ThisSlot = Children[SlotIndex]; - if (ThisSlot.GetWidget()->GetVisibility() != EVisibility::Collapsed) + if ( ThisSlot.GetWidget()->GetVisibility() != EVisibility::Collapsed ) { const FVector2D ChildDesiredSize = ThisSlot.GetWidget()->GetDesiredSize(); - if (Orientation == Orient_Vertical) + if ( Orientation == Orient_Vertical ) { ThisDesiredSize.X = FMath::Max(ChildDesiredSize.X, ThisDesiredSize.X); ThisDesiredSize.Y += ChildDesiredSize.Y + ThisSlot.SlotPadding.Get().GetTotalSpaceAlong(); @@ -107,14 +115,6 @@ public: return ThisDesiredSize; } - virtual FChildren* GetChildren() override - { - return &Children; - } - - float PhysicalOffset; - TPanelChildren Children; - private: float ArrangeChildVerticalAndReturnOffset(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren, const SScrollBox::FSlot& ThisSlot, float CurChildOffset) const @@ -161,8 +161,8 @@ void SScrollBox::Construct( const FArguments& InArgs ) DesiredScrollOffset = 0; bIsScrolling = false; bAnimateScroll = false; - bStartedTouchInteraction = false; AmountScrolledWhileRightMouseDown = 0; + PendingScrollTriggerAmount = 0; bShowSoftwareCursor = false; SoftwareCursorPosition = FVector2D::ZeroVector; OnUserScrolled = InArgs._OnUserScrolled; @@ -174,6 +174,7 @@ void SScrollBox::Construct( const FArguments& InArgs ) AllowOverscroll = InArgs._AllowOverscroll; DestinationScrollingWidgetIntoView = EDescendantScrollDestination::IntoView; bAnimateScrollingWidgetIntoView = false; + bTouchPanningCapture = false; if (InArgs._ExternalScrollbar.IsValid()) { @@ -384,12 +385,7 @@ void SScrollBox::ScrollDescendantIntoView(const TSharedPtr& WidgetToFin DestinationScrollingWidgetIntoView = InDestination; bAnimateScrollingWidgetIntoView = InAnimateScroll; - // This will force the active timer system to wakeup for a frame to ensure we tick at least once. - bIsScrolling = true; - bIsScrollingActiveTimerRegistered = true; - RegisterActiveTimer(0.f, FWidgetActiveTimerDelegate::CreateSP(this, &SScrollBox::UpdateInertialScroll)); - - Invalidate(EInvalidateWidget::Layout); + BeginInertialScrolling(); } bool SScrollBox::ScrollDescendantIntoView(const FGeometry& MyGeometry, const TSharedPtr& WidgetToFind, bool InAnimateScroll, EDescendantScrollDestination InDestination) @@ -501,63 +497,46 @@ EActiveTimerReturnType SScrollBox::UpdateInertialScroll(double InCurrentTime, fl { bool bKeepTicking = bIsScrolling; - //if (bIsScrolling) - //{ - // const float ScrollVelocity = InertialScrollManager.GetScrollVelocity(); - // // Do not apply inertial scrolling while the user is actively scrolling via RMB. - // if (ScrollVelocity != 0.f && !IsRightClickScrolling()) - // { - // ScrollBy(CachedGeometry, ScrollVelocity * InDeltaTime, AllowOverscroll, true); - // } - - // bKeepTicking = true; - //} - - if ( IsRightClickScrolling() ) - { - bKeepTicking = true; - - // We sample for the inertial scroll on tick rather than on mouse/touch move so - // that we still get samples even if the mouse has not moved. - if ( CanUseInertialScroll(TickScrollDelta) ) - { - InertialScrollManager.AddScrollSample(TickScrollDelta, InCurrentTime); - } - } - else + if ( bIsScrolling ) { InertialScrollManager.UpdateScrollVelocity(InDeltaTime); - const float ScrollVelocity = InertialScrollManager.GetScrollVelocity(); + const float ScrollVelocity = InertialScrollManager.GetScrollVelocity() / CachedGeometry.Scale; if ( ScrollVelocity != 0.f ) { if ( CanUseInertialScroll(ScrollVelocity) ) { bKeepTicking = true; - ScrollBy(CachedGeometry, ScrollVelocity * InDeltaTime, AllowOverscroll); + ScrollBy(CachedGeometry, ScrollVelocity * InDeltaTime, AllowOverscroll, false); } else { InertialScrollManager.ClearScrollVelocity(); } } + } - if ( AllowOverscroll == EAllowOverscroll::Yes ) + if ( AllowOverscroll == EAllowOverscroll::Yes ) + { + // If we are currently in overscroll, the list will need refreshing. + // Do this before UpdateOverscroll, as that could cause GetOverscroll() to be 0 + if ( Overscroll.GetOverscroll() != 0.0f ) { - // If we are currently in overscroll, the list will need refreshing. - // Do this before UpdateOverscroll, as that could cause GetOverscroll() to be 0 - if ( Overscroll.GetOverscroll() != 0.0f ) - { - bKeepTicking = true; - } - - Overscroll.UpdateOverscroll(InDeltaTime); + bKeepTicking = true; } + + Overscroll.UpdateOverscroll(InDeltaTime); } TickScrollDelta = 0.f; - bIsScrollingActiveTimerRegistered = bKeepTicking; + if ( !bKeepTicking ) + { + bIsScrolling = false; + bIsScrollingActiveTimerRegistered = false; + UpdateInertialScrollHandle.Reset(); + } + return bKeepTicking ? EActiveTimerReturnType::Continue : EActiveTimerReturnType::Stop; } @@ -565,6 +544,11 @@ void SScrollBox::Tick( const FGeometry& AllottedGeometry, const double InCurrent { CachedGeometry = AllottedGeometry; + if ( bTouchPanningCapture && (FSlateApplication::Get().GetCurrentTime() - LastScrollTime) > 0.10 ) + { + InertialScrollManager.ClearScrollVelocity(); + } + // If we needed a widget to be scrolled into view, make that happen. if ( WidgetToScrollIntoView.IsValid() ) { @@ -600,7 +584,7 @@ void SScrollBox::Tick( const FGeometry& AllottedGeometry, const double InCurrent if (bWasScrolling && !bIsScrolling) { - Invalidate(EInvalidateWidget::LayoutAndVolatility); + Invalidate(EInvalidateWidget::Layout); } ScrollBar->SetState(ViewOffset, ViewFraction); @@ -618,47 +602,47 @@ bool SScrollBox::ComputeVolatility() const FReply SScrollBox::OnPreviewMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { - if ( MouseEvent.IsTouchEvent() ) + if (MouseEvent.IsTouchEvent() && !bFingerOwningTouchInteraction.IsSet()) { // Clear any inertia - this->InertialScrollManager.ClearScrollVelocity(); + InertialScrollManager.ClearScrollVelocity(); // We have started a new interaction; track how far the user has moved since they put their finger down. AmountScrolledWhileRightMouseDown = 0; + PendingScrollTriggerAmount = 0; // Someone put their finger down in this list, so they probably want to drag the list. - bStartedTouchInteraction = true; + bFingerOwningTouchInteraction = MouseEvent.GetPointerIndex(); - Invalidate(EInvalidateWidget::LayoutAndVolatility); - - return FReply::Unhandled(); - } - else - { - return FReply::Unhandled(); + Invalidate(EInvalidateWidget::Layout); } + return FReply::Unhandled(); } FReply SScrollBox::OnMouseButtonDown( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) { - // Zero the scroll velocity so the panel stops immediately on mouse down, even if the user does not drag - this->InertialScrollManager.ClearScrollVelocity(); - - if ( MouseEvent.GetEffectingButton() == EKeys::RightMouseButton && ScrollBar->IsNeeded() ) + if ( !bFingerOwningTouchInteraction.IsSet() ) { - AmountScrolledWhileRightMouseDown = 0; + EndInertialScrolling(); + } - Invalidate(EInvalidateWidget::LayoutAndVolatility); - - // NOTE: We don't bother capturing the mouse, unless the user starts dragging a few pixels (see the - // mouse move handling here.) This is important so that the item row has a chance to select - // items when the right mouse button is released. Just keep in mind that you might not get - // an OnMouseButtonUp event for the right mouse button if the user moves off of the table before - // they reach our scroll threshold + if ( MouseEvent.IsTouchEvent() ) + { return FReply::Handled(); } + else + { + if ( MouseEvent.GetEffectingButton() == EKeys::RightMouseButton && ScrollBar->IsNeeded() ) + { + AmountScrolledWhileRightMouseDown = 0; + + Invalidate(EInvalidateWidget::Layout); + + return FReply::Handled(); + } + } + return FReply::Unhandled(); } - FReply SScrollBox::OnMouseButtonUp( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) { if ( MouseEvent.GetEffectingButton() == EKeys::RightMouseButton ) @@ -667,14 +651,12 @@ FReply SScrollBox::OnMouseButtonUp( const FGeometry& MyGeometry, const FPointerE { // Register the active timer to handle the inertial scrolling CachedGeometry = MyGeometry; - bIsScrolling = true; - bIsScrollingActiveTimerRegistered = true; - RegisterActiveTimer(0.f, FWidgetActiveTimerDelegate::CreateSP(this, &SScrollBox::UpdateInertialScroll)); + BeginInertialScrolling(); } AmountScrolledWhileRightMouseDown = 0; - Invalidate(EInvalidateWidget::LayoutAndVolatility); + Invalidate(EInvalidateWidget::Layout); FReply Reply = FReply::Handled().ReleaseMouseCapture(); bShowSoftwareCursor = false; @@ -695,46 +677,88 @@ FReply SScrollBox::OnMouseButtonUp( const FGeometry& MyGeometry, const FPointerE return Reply; } + return FReply::Unhandled(); } FReply SScrollBox::OnMouseMove( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) -{ - if( MouseEvent.IsMouseButtonDown( EKeys::RightMouseButton ) ) +{ + const float ScrollByAmountScreen = GetScrollComponentFromVector(MouseEvent.GetCursorDelta()); + const float ScrollByAmountLocal = ScrollByAmountScreen / MyGeometry.Scale; + + if ( MouseEvent.IsTouchEvent() ) { - const float ScrollByAmount = GetScrollComponentFromVector(MouseEvent.GetCursorDelta()); - // If scrolling with the right mouse button, we need to remember how much we scrolled. - // If we did not scroll at all, we will bring up the context menu when the mouse is released. - AmountScrolledWhileRightMouseDown += FMath::Abs( ScrollByAmount ); + FReply Reply = FReply::Unhandled(); - Invalidate(EInvalidateWidget::LayoutAndVolatility); - - // Has the mouse moved far enough with the right mouse button held down to start capturing - // the mouse and dragging the view? - if( IsRightClickScrolling() ) + if ( !bTouchPanningCapture ) { - this->InertialScrollManager.AddScrollSample(-ScrollByAmount, FPlatformTime::Seconds()); - const bool bDidScroll = this->ScrollBy( MyGeometry, -ScrollByAmount, AllowOverscroll ); - - FReply Reply = FReply::Handled(); - - // Capture the mouse if we need to - if(this->HasMouseCapture() == false) + if ( bFingerOwningTouchInteraction.IsSet() && MouseEvent.IsTouchEvent() && !HasMouseCapture() ) { - Reply.CaptureMouse( AsShared() ).UseHighPrecisionMouseMovement( AsShared() ); - SoftwareCursorPosition = MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() ); - bShowSoftwareCursor = true; - } + PendingScrollTriggerAmount += ScrollByAmountScreen; - // Check if the mouse has moved. - if( bDidScroll ) + if ( FMath::Abs(PendingScrollTriggerAmount) > FSlateApplication::Get().GetDragTriggerDistance() ) + { + bTouchPanningCapture = true; + ScrollBar->BeginScrolling(); + + // The user has moved the list some amount; they are probably + // trying to scroll. From now on, the list assumes the user is scrolling + // until they lift their finger. + Reply = FReply::Handled().CaptureMouse(AsShared()); + } + else + { + Reply = FReply::Handled(); + } + } + } + else + { + if ( bFingerOwningTouchInteraction.IsSet() && HasMouseCaptureByUser(MouseEvent.GetUserIndex(), MouseEvent.GetPointerIndex()) ) { - SetScrollComponentOnVector(SoftwareCursorPosition, GetScrollComponentFromVector(SoftwareCursorPosition) + GetScrollComponentFromVector(MouseEvent.GetCursorDelta())); + LastScrollTime = FSlateApplication::Get().GetCurrentTime(); + InertialScrollManager.AddScrollSample(-ScrollByAmountScreen, FSlateApplication::Get().GetCurrentTime()); + ScrollBy(MyGeometry, -ScrollByAmountLocal, EAllowOverscroll::Yes, false); + + Reply = FReply::Handled(); } + } - TickScrollDelta -= ScrollByAmount; + return Reply; + } + else + { + if ( MouseEvent.IsMouseButtonDown(EKeys::RightMouseButton) ) + { + // If scrolling with the right mouse button, we need to remember how much we scrolled. + // If we did not scroll at all, we will bring up the context menu when the mouse is released. + AmountScrolledWhileRightMouseDown += FMath::Abs(ScrollByAmountScreen); - return Reply; + // Has the mouse moved far enough with the right mouse button held down to start capturing + // the mouse and dragging the view? + if ( IsRightClickScrolling() ) + { + InertialScrollManager.AddScrollSample(-ScrollByAmountScreen, FPlatformTime::Seconds()); + const bool bDidScroll = ScrollBy(MyGeometry, -ScrollByAmountLocal, AllowOverscroll, false); + + FReply Reply = FReply::Handled(); + + // Capture the mouse if we need to + if ( HasMouseCapture() == false ) + { + Reply.CaptureMouse(AsShared()).UseHighPrecisionMouseMovement(AsShared()); + SoftwareCursorPosition = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition()); + bShowSoftwareCursor = true; + } + + // Check if the mouse has moved. + if ( bDidScroll ) + { + SetScrollComponentOnVector(SoftwareCursorPosition, GetScrollComponentFromVector(SoftwareCursorPosition) + GetScrollComponentFromVector(MouseEvent.GetCursorDelta())); + } + + return Reply; + } } } @@ -743,15 +767,19 @@ FReply SScrollBox::OnMouseMove( const FGeometry& MyGeometry, const FPointerEvent void SScrollBox::OnMouseLeave( const FPointerEvent& MouseEvent ) { - if (HasMouseCapture() == false) + if ( HasMouseCapture() == false ) { // No longer scrolling (unless we have mouse capture) - if (AmountScrolledWhileRightMouseDown != 0) + if ( AmountScrolledWhileRightMouseDown != 0 ) { AmountScrolledWhileRightMouseDown = 0; - Invalidate(EInvalidateWidget::LayoutAndVolatility); + Invalidate(EInvalidateWidget::Layout); + } + + if ( MouseEvent.IsTouchEvent() ) + { + bFingerOwningTouchInteraction.Reset(); } - bStartedTouchInteraction = false; } } @@ -762,16 +790,13 @@ FReply SScrollBox::OnMouseWheel( const FGeometry& MyGeometry, const FPointerEven // Make sure scroll velocity is cleared so it doesn't fight with the mouse wheel input InertialScrollManager.ClearScrollVelocity(); - const bool bScrollWasHandled = this->ScrollBy(MyGeometry, -MouseEvent.GetWheelDelta() * GetGlobalScrollAmount(), EAllowOverscroll::No); + const bool bScrollWasHandled = ScrollBy(MyGeometry, -MouseEvent.GetWheelDelta() * GetGlobalScrollAmount(), EAllowOverscroll::No, false); if ( bScrollWasHandled && !bIsScrollingActiveTimerRegistered ) { // Register the active timer to handle the inertial scrolling CachedGeometry = MyGeometry; - bIsScrolling = true; - bIsScrollingActiveTimerRegistered = true; - RegisterActiveTimer(0.f, FWidgetActiveTimerDelegate::CreateSP(this, &SScrollBox::UpdateInertialScroll)); - Invalidate(EInvalidateWidget::LayoutAndVolatility); + BeginInertialScrolling(); } return bScrollWasHandled ? FReply::Handled() : FReply::Unhandled(); @@ -784,6 +809,8 @@ FReply SScrollBox::OnMouseWheel( const FGeometry& MyGeometry, const FPointerEven bool SScrollBox::ScrollBy(const FGeometry& AllottedGeometry, float ScrollAmount, EAllowOverscroll Overscrolling, bool InAnimateScroll) { + Invalidate(EInvalidateWidget::LayoutAndVolatility); + bAnimateScroll = InAnimateScroll; const float ContentSize = GetScrollComponentFromVector(ScrollPanel->GetDesiredSize()); @@ -811,11 +838,6 @@ bool SScrollBox::ScrollBy(const FGeometry& AllottedGeometry, float ScrollAmount, return ConsumeMouseWheel == EConsumeMouseWheel::Always || DesiredScrollOffset != PreviousScrollOffset; } -FReply SScrollBox::OnDragDetected( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) -{ - return FReply::Handled().CaptureMouse( SharedThis(this) ); -} - FCursorReply SScrollBox::OnCursorQuery( const FGeometry& MyGeometry, const FPointerEvent& CursorEvent ) const { if ( IsRightClickScrolling() ) @@ -829,61 +851,32 @@ FCursorReply SScrollBox::OnCursorQuery( const FGeometry& MyGeometry, const FPoin } } -FReply SScrollBox::OnTouchStarted(const FGeometry& MyGeometry, const FPointerEvent& InTouchEvent) -{ - // See OnPreviewMouseButtonDown() - // if (MouseEvent.IsTouchEvent()) - - return FReply::Unhandled(); -} - -FReply SScrollBox::OnTouchMoved(const FGeometry& MyGeometry, const FPointerEvent& InTouchEvent) -{ - if ( bStartedTouchInteraction ) - { - const float ScrollByAmount = GetScrollComponentFromVector(InTouchEvent.GetCursorDelta()) / MyGeometry.Scale; - AmountScrolledWhileRightMouseDown += FMath::Abs(ScrollByAmount); - TickScrollDelta -= ScrollByAmount; - - Invalidate(EInvalidateWidget::LayoutAndVolatility); - - if ( AmountScrolledWhileRightMouseDown > FSlateApplication::Get().GetDragTriggerDistance() ) - { - const float AmountScrolled = this->ScrollBy(MyGeometry, -ScrollByAmount, EAllowOverscroll::Yes, true); - - // The user has moved the list some amount; they are probably - // trying to scroll. From now on, the list assumes the user is scrolling - // until they lift their finger. - return FReply::Handled().CaptureMouse(AsShared()); - } - return FReply::Handled(); - } - else - { - return FReply::Handled(); - } -} - FReply SScrollBox::OnTouchEnded(const FGeometry& MyGeometry, const FPointerEvent& InTouchEvent) { CachedGeometry = MyGeometry; - AmountScrolledWhileRightMouseDown = 0; - bStartedTouchInteraction = false; - - Invalidate(EInvalidateWidget::LayoutAndVolatility); - - bIsScrollingActiveTimerRegistered = true; - RegisterActiveTimer(0.f, FWidgetActiveTimerDelegate::CreateSP(this, &SScrollBox::UpdateInertialScroll)); - - if ( HasMouseCapture() ) + if ( HasMouseCaptureByUser(InTouchEvent.GetUserIndex(), InTouchEvent.GetPointerIndex()) ) { + AmountScrolledWhileRightMouseDown = 0; + PendingScrollTriggerAmount = 0; + bFingerOwningTouchInteraction.Reset(); + bTouchPanningCapture = false; + + ScrollBar->EndScrolling(); + + Invalidate(EInvalidateWidget::Layout); + + BeginInertialScrolling(); + return FReply::Handled().ReleaseMouseCapture(); } - else - { - return FReply::Handled(); - } + + return FReply::Unhandled(); +} + +void SScrollBox::OnMouseCaptureLost() +{ + SCompoundWidget::OnMouseCaptureLost(); } FNavigationReply SScrollBox::OnNavigation(const FGeometry& MyGeometry, const FNavigationEvent& InNavigationEvent) @@ -970,7 +963,7 @@ int32 SScrollBox::OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeom AllottedGeometry.ToPaintGeometry( SoftwareCursorPosition - ( Brush->ImageSize / 2 ), Brush->ImageSize ), Brush, MyClippingRect - ); + ); return NewLayerId; } @@ -983,6 +976,8 @@ void SScrollBox::ScrollBar_OnUserScrolled( float InScrollOffsetFraction ) // Clamp to max scroll offset DesiredScrollOffset = FMath::Min(InScrollOffsetFraction * ContentSize, ContentSize - GetScrollComponentFromVector(ScrollPanelGeometry.Size)); OnUserScrolled.ExecuteIfBound(DesiredScrollOffset); + + Invalidate(EInvalidateWidget::Layout); } const float ShadowFadeDistance = 32.0f; @@ -1011,3 +1006,29 @@ bool SScrollBox::CanUseInertialScroll(float ScrollAmount) const // Or if we are scrolling outwards of the overscroll region return CurrentOverscroll == 0.f || FMath::Sign(CurrentOverscroll) != FMath::Sign(ScrollAmount); } + +void SScrollBox::BeginInertialScrolling() +{ + if ( !UpdateInertialScrollHandle.IsValid() ) + { + bIsScrolling = true; + bIsScrollingActiveTimerRegistered = true; + UpdateInertialScrollHandle = RegisterActiveTimer(0.f, FWidgetActiveTimerDelegate::CreateSP(this, &SScrollBox::UpdateInertialScroll)); + Invalidate(EInvalidateWidget::LayoutAndVolatility); + } +} + +void SScrollBox::EndInertialScrolling() +{ + bIsScrolling = false; + bIsScrollingActiveTimerRegistered = false; + + if ( UpdateInertialScrollHandle.IsValid() ) + { + UnRegisterActiveTimer(UpdateInertialScrollHandle.ToSharedRef()); + UpdateInertialScrollHandle.Reset(); + } + + // Zero the scroll velocity so the panel stops immediately on mouse down, even if the user does not drag + InertialScrollManager.ClearScrollVelocity(); +} \ No newline at end of file diff --git a/Engine/Source/Runtime/Slate/Private/Widgets/SInvalidationPanel.cpp b/Engine/Source/Runtime/Slate/Private/Widgets/SInvalidationPanel.cpp index 0d71410da12e..ab99ad41f061 100644 --- a/Engine/Source/Runtime/Slate/Private/Widgets/SInvalidationPanel.cpp +++ b/Engine/Source/Runtime/Slate/Private/Widgets/SInvalidationPanel.cpp @@ -330,6 +330,7 @@ int32 SInvalidationPanel::OnPaint( const FPaintArgs& Args, const FGeometry& Allo } //FPlatformMisc::BeginNamedEvent(FColor::Yellow, "Slate::RecordHitTestGeometry"); + // The hit test grid is actually populated during the initial cache phase, so don't bother @@ -338,7 +339,7 @@ int32 SInvalidationPanel::OnPaint( const FPaintArgs& Args, const FGeometry& Allo { INC_DWORD_STAT_BY(STAT_SlateNumCachedElements, CachedWindowElements->GetDrawElements().Num()); - RootCacheNode->RecordHittestGeometry(Args.GetGrid(), Args.GetLastHitTestIndex(), LayerId); + RootCacheNode->RecordHittestGeometry(Args.GetGrid(), Args.GetLastHitTestIndex(), LayerId, AbsoluteDeltaPosition); } else { @@ -350,7 +351,7 @@ int32 SInvalidationPanel::OnPaint( const FPaintArgs& Args, const FGeometry& Allo if (bCacheRenderData) { - FSlateDrawElement::MakeCachedBuffer(OutDrawElements, LayerId, CachedRenderData, AbsoluteDeltaPosition * AllottedGeometry.Scale); + FSlateDrawElement::MakeCachedBuffer(OutDrawElements, LayerId, CachedRenderData, AbsoluteDeltaPosition); } else { @@ -380,7 +381,7 @@ int32 SInvalidationPanel::OnPaint( const FPaintArgs& Args, const FGeometry& Allo const TArray>& VolatileElements = CachedWindowElements->GetVolatileElements(); INC_DWORD_STAT_BY(STAT_SlateNumVolatileWidgets, VolatileElements.Num()); - int32 VolatileLayerId = CachedWindowElements->PaintVolatile(OutDrawElements, Args.GetCurrentTime(), Args.GetDeltaTime(), AbsoluteDeltaPosition); + int32 VolatileLayerId = CachedWindowElements->PaintVolatile(OutDrawElements, Args.GetCurrentTime(), Args.GetDeltaTime(), AbsoluteDeltaPosition * AllottedGeometry.Scale); OutMaxChildLayer = FMath::Max(OutMaxChildLayer, VolatileLayerId); //FPlatformMisc::EndNamedEvent(); diff --git a/Engine/Source/Runtime/Slate/Private/Widgets/Text/SInlineEditableTextBlock.cpp b/Engine/Source/Runtime/Slate/Private/Widgets/Text/SInlineEditableTextBlock.cpp index f97ec759c935..a8e2be9bac67 100644 --- a/Engine/Source/Runtime/Slate/Private/Widgets/Text/SInlineEditableTextBlock.cpp +++ b/Engine/Source/Runtime/Slate/Private/Widgets/Text/SInlineEditableTextBlock.cpp @@ -188,11 +188,11 @@ FReply SInlineEditableTextBlock::OnMouseButtonDown( const FGeometry& MyGeometry, else { // The widget is not managed by another widget, so handle the mouse input and enter edit mode if ready. - if(HasKeyboardFocus()) + if(HasKeyboardFocus() && !bIsReadOnly.Get()) { EnterEditingMode(); + return FReply::Handled(); } - return FReply::Handled(); } // Do not handle the mouse input, this will allow for drag and dropping events to trigger. diff --git a/Engine/Source/Runtime/Slate/Private/Widgets/Text/SlateEditableTextLayout.cpp b/Engine/Source/Runtime/Slate/Private/Widgets/Text/SlateEditableTextLayout.cpp index 10d46c633927..f071fa94fc81 100644 --- a/Engine/Source/Runtime/Slate/Private/Widgets/Text/SlateEditableTextLayout.cpp +++ b/Engine/Source/Runtime/Slate/Private/Widgets/Text/SlateEditableTextLayout.cpp @@ -201,11 +201,12 @@ FSlateEditableTextLayout::~FSlateEditableTextLayout() if (TextInputMethodSystem) { TSharedRef TextInputMethodContextRef = TextInputMethodContext.ToSharedRef(); + + // Make sure that the composition is aborted to avoid any IME calls to EndComposition from trying to mutate our dying owner widget + TextInputMethodContextRef->AbortComposition(); + if (TextInputMethodSystem->IsActiveContext(TextInputMethodContextRef)) { - // Make sure that the composition is aborted to avoid any IME calls to EndComposition from trying to mutate our dying owner widget - TextInputMethodContextRef->AbortComposition(); - // This can happen if an entire tree of widgets is culled, as Slate isn't notified of the focus loss, the widget is just deleted TextInputMethodSystem->DeactivateContext(TextInputMethodContextRef); } @@ -3541,12 +3542,13 @@ void FSlateEditableTextLayout::FTextInputMethodContext::BeginComposition() void FSlateEditableTextLayout::FTextInputMethodContext::UpdateCompositionRange(const int32 InBeginIndex, const uint32 InLength) { - check(bIsComposing); + if (bIsComposing) + { + CompositionBeginIndex = InBeginIndex; + CompositionLength = InLength; - CompositionBeginIndex = InBeginIndex; - CompositionLength = InLength; - - OwnerLayout->UpdateCursorHighlight(); + OwnerLayout->UpdateCursorHighlight(); + } } void FSlateEditableTextLayout::FTextInputMethodContext::EndComposition() diff --git a/Engine/Source/Runtime/Slate/Private/Widgets/Views/STableViewBase.cpp b/Engine/Source/Runtime/Slate/Private/Widgets/Views/STableViewBase.cpp index 947ed5ca37d3..bca5ef0008c9 100644 --- a/Engine/Source/Runtime/Slate/Private/Widgets/Views/STableViewBase.cpp +++ b/Engine/Source/Runtime/Slate/Private/Widgets/Views/STableViewBase.cpp @@ -556,6 +556,8 @@ FReply STableViewBase::OnTouchMoved( const FGeometry& MyGeometry, const FPointer const float AmountScrolled = this->ScrollBy( MyGeometry, -ScrollByAmount, EAllowOverscroll::Yes ); + ScrollBar->BeginScrolling(); + // The user has moved the list some amount; they are probably // trying to scroll. From now on, the list assumes the user is scrolling // until they lift their finger. @@ -571,10 +573,11 @@ FReply STableViewBase::OnTouchMoved( const FGeometry& MyGeometry, const FPointer FReply STableViewBase::OnTouchEnded( const FGeometry& MyGeometry, const FPointerEvent& InTouchEvent ) { - AmountScrolledWhileRightMouseDown = 0; bStartedTouchInteraction = false; + ScrollBar->EndScrolling(); + if (HasMouseCapture()) { return FReply::Handled().ReleaseMouseCapture(); diff --git a/Engine/Source/Runtime/Slate/Public/Framework/Application/GestureDetector.h b/Engine/Source/Runtime/Slate/Public/Framework/Application/GestureDetector.h new file mode 100644 index 000000000000..34534585f99d --- /dev/null +++ b/Engine/Source/Runtime/Slate/Public/Framework/Application/GestureDetector.h @@ -0,0 +1,59 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. +#pragma once + +#include "InputCoreTypes.h" +#include "Containers/BitArray.h" +#include "GenericApplicationMessageHandler.h" + +/** + * The gesture detector can simulate the detection of certain kinds of gestures that may or may not + * be available to be detected at the platform level. + */ +class FGestureDetector +{ +public: + /** The amount of time in seconds you hold a finger down before it's detected as a long press. */ + static double LongPressSeconds; + + /** + * The amount of movement allowed before the finger is no longer considered valid for a long press, + * until it's removed and re-pressed. + */ + static float LongPressAllowedMovement; + +public: + /** + * Call to determine if the gesture is supported by the gesture detector. + */ + static bool IsGestureSupported(EGestureEvent::Type Gesture); + + void OnTouchStarted(int32 TouchIndex, const FVector2D& Location); + void OnTouchEnded(int32 TouchIndex, const FVector2D& Location); + void OnTouchMoved(int32 TouchIndex, const FVector2D& Location); + + /** + * Generates gesture messages for all enabled gestures. + */ + void GenerateGestures(FGenericApplicationMessageHandler& MessageHandler, const TBitArray& EnabledGestures); + +private: + struct FLongPressData + { + TOptional Time; + FVector2D Location; + + FLongPressData() + : Time() + , Location(0, 0) + { + } + + void Reset() + { + Time.Reset(); + Location = FVector2D(0, 0); + } + }; + + FLongPressData LongPressTrack[EKeys::NUM_TOUCH_KEYS]; +}; \ No newline at end of file diff --git a/Engine/Source/Runtime/Slate/Public/Framework/Application/IMenu.h b/Engine/Source/Runtime/Slate/Public/Framework/Application/IMenu.h index 927c23f4c4ed..0c645d158552 100644 --- a/Engine/Source/Runtime/Slate/Public/Framework/Application/IMenu.h +++ b/Engine/Source/Runtime/Slate/Public/Framework/Application/IMenu.h @@ -16,6 +16,7 @@ class IMenu public: DECLARE_MULTICAST_DELEGATE_OneParam(FOnMenuDismissed, TSharedRef /*DismissedMenu*/); + virtual ~IMenu() { } virtual EPopupMethod GetPopupMethod() const = 0; virtual TSharedPtr GetParentWindow() const = 0; virtual TSharedPtr GetOwnedWindow() const = 0; diff --git a/Engine/Source/Runtime/Slate/Public/Framework/Application/SlateApplication.h b/Engine/Source/Runtime/Slate/Public/Framework/Application/SlateApplication.h index 62e942905554..48ad230b2a36 100644 --- a/Engine/Source/Runtime/Slate/Public/Framework/Application/SlateApplication.h +++ b/Engine/Source/Runtime/Slate/Public/Framework/Application/SlateApplication.h @@ -28,6 +28,8 @@ #include "Framework/Application/MenuStack.h" #include "Framework/SlateDelegates.h" +#include "GestureDetector.h" + class FNavigationConfig; class IInputInterface; class IInputProcessor; @@ -122,6 +124,33 @@ public: TSharedPtr GetFocusedWidget() const; + FGestureDetector GestureDetector; + +private: + FORCEINLINE bool HasValidFocusPath() const + { + return FocusWidgetPathWeak.IsValid(); + } + + FORCEINLINE const FWeakWidgetPath& GetWeakFocusPath() const + { + return FocusWidgetPathWeak; + } + + FORCEINLINE TSharedRef GetFocusPath() const + { + if ( !FocusWidgetPathStrong.IsValid() ) + { + FocusWidgetPathStrong = FocusWidgetPathWeak.ToWidgetPathRef(); + } + + return FocusWidgetPathStrong.ToSharedRef(); + } + + void SetFocusPath(const FWidgetPath& InWidgetPath, EFocusCause InCause, bool InShowFocus); + + void FinishFrame(); + private: /** The index the user was assigned. */ int32 UserIndex; @@ -129,17 +158,17 @@ private: /** Is this a virtual user? Virtual users are generally ignored in most operations that affect all users. */ bool bVirtualUser; - struct FUserFocusEntry - { - /** A weak path to the widget currently focused by a user, if any. */ - FWeakWidgetPath WidgetPath; - /** Reason a widget was focused by a user, if any. */ - EFocusCause FocusCause; - /** If we should show this focus */ - bool ShowFocus; - }; + /** A weak path to the widget currently focused by a user, if any. */ + FWeakWidgetPath FocusWidgetPathWeak; - FUserFocusEntry Focus; + /** A strong widget path to a widget, this is cleared after the end of pumping messages. */ + mutable TSharedPtr FocusWidgetPathStrong; + + /** Reason a widget was focused by a user, if any. */ + EFocusCause FocusCause; + + /** If we should show this focus */ + bool ShowFocus; friend class FSlateApplication; }; @@ -755,15 +784,15 @@ public: * Calculates the popup window position from the passed in window position and size. * Adjusts position for popup windows which are outside of the work area of the monitor where they reside * - * @param InAnchor The current(suggseted) window position and size of an area which may not be covered by the popup. - * @param InSize The size of the window - * @param Orientation The direction of the popup. - * If vertical it will attempt to open below the anchor but will open above if there is no room. - * If horizontal it will attempt to open below the anchor but will open above if there is no room. + * @param InAnchor The current(suggseted) window position and size of an area which may not be covered by the popup. + * @param InSize The size of the window + * @param InProposedPlacement The location on screen where the popup should go if allowed. If zero this will be determined from Orientation and Anchor + * @param Orientation The direction of the popup. + * If vertical it will attempt to open below the anchor but will open above if there is no room. + * If horizontal it will attempt to open below the anchor but will open above if there is no room. * @return The adjusted position */ - virtual FVector2D CalculatePopupWindowPosition( const FSlateRect& InAnchor, const FVector2D& InSize, const EOrientation Orientation = Orient_Vertical ) const; - + virtual FVector2D CalculatePopupWindowPosition( const FSlateRect& InAnchor, const FVector2D& InSize, const FVector2D& InProposedPlacement = FVector2D::ZeroVector, const EOrientation Orientation = Orient_Vertical) const; /** * Is the window in the app's destroy queue? If so it will be destroyed next tick. @@ -966,12 +995,17 @@ protected: */ void GetAllVisibleChildWindows(TArray< TSharedRef >& OutWindows, TSharedRef CurrentWindow); - /** Engages or disengages application throttling based on user behavior */ void ThrottleApplicationBasedOnMouseMovement(); virtual FWidgetPath LocateWidgetInWindow(FVector2D ScreenspaceMouseCoordinate, const TSharedRef& Window, bool bIgnoreEnabledStatus) const override; + /** + * Sets up any values that need to be based on the physical dimensions of the device. + * Such as dead zones associated with precise tapping...etc + */ + void SetupPhysicalSensitivities(); + public: /** @@ -1179,9 +1213,13 @@ public: /** @return true if mouse events are being turned into touch events, and touch UI should be forced on */ bool IsFakingTouchEvents() const; +#if PLATFORM_DESKTOP + /** Sets whether the application is treating mouse events as imitating touch events. Optional CursorLocation can be supplied to override the platform's belief of where the cursor is */ void SetGameIsFakingTouchEvents(const bool bIsFaking, FVector2D* CursorLocation = nullptr); +#endif + /** Sets the handler for otherwise unhandled key down events. This is used by the editor to provide a global action list, if the key was not consumed by any widget. */ void SetUnhandledKeyDownEventHandler( const FOnKeyEvent& NewHandler ); @@ -1195,17 +1233,46 @@ public: /** @return the deadzone size for dragging in screen pixels (aka virtual desktop pixels) */ float GetDragTriggerDistance() const; + /** @return the deadzone size squared for dragging in screen pixels (aka virtual desktop pixels) */ + float GetDragTriggerDistanceSquared() const; + + /** @return true if the difference between the ScreenSpaceOrigin and the ScreenSpacePosition is larger than the trigger distance for dragging in Slate. */ + bool HasTraveledFarEnoughToTriggerDrag(const FPointerEvent& PointerEvent, const FVector2D ScreenSpaceOrigin) const; + /** Set the size of the deadzone for dragging in screen pixels */ void SetDragTriggerDistance( float ScreenPixels ); - /** Set the analog cursor to be enabled or disabled. */ - void SetInputPreProcessor(bool bEnable, TSharedPtr NewInputProcessor = nullptr); + /** [Deprecated] Adds or removes input pre-processor. */ + DEPRECATED(4.17, "SetInputPreProcessor(...) is deprecated. Use RegisterInputPreProcessor(...) and/or UnregisterInputPreProcessor(...) / UnregisterAllInputPreProcessors(...) instead.") + void SetInputPreProcessor(bool bEnable, TSharedPtr InputProcessor = nullptr); + + /** + * Adds input pre-processor if unique. + * @param InputProcessor The input pre-processor to add. + * @param Index Where to insert the InputProcessor, when sorting is needed. Default index will add at the end. + * @return True if added to list of input pre-processors, false if not + */ + bool RegisterInputPreProcessor(TSharedPtr InputProcessor, const int32 Index = INDEX_NONE); + + /** + * Removes an input pre-processor. + * @param InputProcessor The input pre-processor to Remove. + */ + void UnregisterInputPreProcessor(TSharedPtr InputProcessor); + + /** + * Removes all input pre-processor from list of input pre-processors. + */ + void UnregisterAllInputPreProcessors(); /** Sets the hit detection radius of the cursor */ void SetCursorRadius(float NewRadius); /** Getter for the cursor radius */ float GetCursorRadius() const; + + void SetAllowTooltips(bool bCanShow); + bool GetAllowTooltips() const; public: @@ -1248,7 +1315,7 @@ public: virtual FVector2D GetCursorPos() const override; virtual FVector2D GetLastCursorPos() const override; - virtual FVector2D GetCursorSize() const override; + virtual FVector2D GetCursorSize() const override; virtual bool GetSoftwareCursorAvailable() const override { @@ -1319,6 +1386,7 @@ public: virtual bool OnTouchStarted( const TSharedPtr< FGenericWindow >& PlatformWindow, const FVector2D& Location, int32 TouchIndex, int32 ControllerId ) override; virtual bool OnTouchMoved( const FVector2D& Location, int32 TouchIndex, int32 ControllerId ) override; virtual bool OnTouchEnded( const FVector2D& Location, int32 TouchIndex, int32 ControllerId ) override; + virtual void ShouldSimulateGesture(EGestureEvent::Type Gesture, bool bEnable) override; virtual bool OnMotionDetected(const FVector& Tilt, const FVector& RotationRate, const FVector& Gravity, const FVector& Acceleration, int32 ControllerId) override; virtual bool OnSizeChanged( const TSharedRef< FGenericWindow >& PlatformWindow, const int32 Width, const int32 Height, bool bWasMinimized = false ) override; virtual void OnOSPaint( const TSharedRef< FGenericWindow >& PlatformWindow ) override; @@ -1459,7 +1527,9 @@ public: const void* FindBestParentWindowHandleForDialogs(const TSharedPtr& InWidget); public: +#if WITH_EDITORONLY_DATA FDragDropCheckingOverride OnDragDropCheckOverride; +#endif private: @@ -1606,6 +1676,12 @@ private: /** A vertical slice through the tree of widgets on screen; it represents widgets that were under the cursor last time an event was processed */ TMap WidgetsUnderCursorLastEvent; + /** Stores the position for the pointer position. */ + TMap PointerIndexPositionMap; + + /** Stores the position for the last pointer position. */ + TMap PointerIndexLastPositionMap; + /** * A helper class to wrap the weak path functionality. The advantage of using this * class is that the path can be validated and the current mouse captor (if any) can @@ -1641,7 +1717,7 @@ private: * @param EventPath The path to the event. * @param Widget The widget that wants to capture the mouse. */ - void SetMouseCaptor(uint32 UserIndex, uint32 PointerIndex, const FWidgetPath& EventPath, TSharedPtr< SWidget > Widget ); + bool SetMouseCaptor(uint32 UserIndex, uint32 PointerIndex, const FWidgetPath& EventPath, TSharedPtr< SWidget > Widget ); /** Invalidates all current mouse captors. Calls OnMouseCaptureLost() on the current mouse captor if one exists */ void InvalidateCaptureForAllPointers(); @@ -1694,9 +1770,6 @@ private: /** The current mouse captor for the application, if any. */ MouseCaptorHelper MouseCaptor; - /** An input preprocessor, gets an opportunity to parse input before anything else. */ - TSharedPtr InputPreProcessor; - /** The cursor widget and window to render that cursor for the current software cursor.*/ TWeakPtr CursorWindowPtr; TWeakPtr CursorWidgetPtr; @@ -1716,8 +1789,6 @@ private: */ TArray> VirtualUsers; - typedef FSlateUser::FUserFocusEntry FUserFocusEntry; - /** * Application throttling */ @@ -1875,14 +1946,13 @@ private: /** Direction that tool-tip is being repelled from a force field in. We cache this to avoid tool-tips teleporting between different offset directions as the user moves the mouse cursor around. */ - struct EToolTipOffsetDirection + enum class EToolTipOffsetDirection : uint8 { - enum Type - { - Undetermined, Down, Right - }; + Undetermined, + Down, + Right }; - EToolTipOffsetDirection::Type ToolTipOffsetDirection; + EToolTipOffsetDirection ToolTipOffsetDirection; /** The top of the Style tree. */ const class FStyleNode* RootStyleNode; @@ -1931,8 +2001,6 @@ private: /** When an drag and drop is happening, we keep track of whether slate knew what to do with the payload on last mouse move */ bool DragIsHandled; - TMap PointerIndexLastPositionMap; - /** * Virtual keyboard text field */ @@ -2001,6 +2069,9 @@ private: /** Configured fkeys to control navigation */ TSharedRef NavigationConfig; + /** */ + TBitArray SimulateGestures; + /** Delegate for pre slate tick */ FSlateTickEvent PreTickEvent; @@ -2016,6 +2087,51 @@ private: /** Are we currently processing input in slate? If so this value will be greater than 0. */ int32 ProcessingInput; + + /** + * A helper class to wrap the list of input pre-processors. + */ + class InputPreProcessorsHelper + { + public: + + // Wrapper functions that call the corresponding function of IInputProcessor for each InputProcessor in the list. + void Tick(const float DeltaTime, FSlateApplication& SlateApp, TSharedRef Cursor); + bool HandleKeyDownEvent(FSlateApplication& SlateApp, const FKeyEvent& InKeyEvent); + bool HandleKeyUpEvent(FSlateApplication& SlateApp, const FKeyEvent& InKeyEvent); + bool HandleAnalogInputEvent(FSlateApplication& SlateApp, const FAnalogInputEvent& InAnalogInputEvent); + bool HandleMouseMoveEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent); + bool HandleMouseButtonDownEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent); + bool HandleMouseButtonUpEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent); + bool HandleMotionDetectedEvent(FSlateApplication& SlateApp, const FMotionEvent& MotionEvent); + + /** + * Adds or inserts an unique input pre-processor. + * @param InputProcessor The InputProcessor to add. + * @param Index When this is set the index will be used to insert the InputProcessor. Defaults to INDEX_NONE, resulting in AddUnique. + */ + bool Add(TSharedPtr InputProcessor, const int32 Index = INDEX_NONE); + + /** + * Remove an input pre-processor. + * @param InputProcessor The InputProcessor to remove. + */ + void Remove(TSharedPtr InputProcessor); + + /** + * Remove all registered input pre-processors. + */ + void RemoveAll(); + + private: + + /** The list of input pre-processors. */ + TArray> InputPreProcessorList; + }; + + /** A list of input pre-processors, gets an opportunity to parse input before anything else. */ + InputPreProcessorsHelper InputPreProcessors; + #if WITH_EDITOR /** * Delegate that is invoked before the input key get process by slate widgets bubble system. diff --git a/Engine/Source/Runtime/Slate/Public/Framework/Commands/InputBindingManager.h b/Engine/Source/Runtime/Slate/Public/Framework/Commands/InputBindingManager.h index 0bb1967be0b3..f912bf837cdf 100644 --- a/Engine/Source/Runtime/Slate/Public/Framework/Commands/InputBindingManager.h +++ b/Engine/Source/Runtime/Slate/Public/Framework/Commands/InputBindingManager.h @@ -32,6 +32,11 @@ public: */ static FInputBindingManager& Get(); + /** + * Virtual destructor + */ + virtual ~FInputBindingManager() { } + /** * Returns a list of all known input contexts * diff --git a/Engine/Source/Runtime/Slate/Public/Framework/Commands/InputChord.h b/Engine/Source/Runtime/Slate/Public/Framework/Commands/InputChord.h index 3adfa6ad30c7..2c7fc1c1b01d 100644 --- a/Engine/Source/Runtime/Slate/Public/Framework/Commands/InputChord.h +++ b/Engine/Source/Runtime/Slate/Public/Framework/Commands/InputChord.h @@ -18,23 +18,23 @@ struct SLATE_API FInputChord GENERATED_USTRUCT_BODY() /** The Key is the core of the chord. */ - UPROPERTY(EditAnywhere, Category = Key) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Key) FKey Key; /** Whether the shift key is part of the chord. */ - UPROPERTY(EditAnywhere, Category = Modifier) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Modifier) uint32 bShift:1; /** Whether the control key is part of the chord. */ - UPROPERTY(EditAnywhere, Category = Modifier) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Modifier) uint32 bCtrl:1; /** Whether the alt key is part of the chord. */ - UPROPERTY(EditAnywhere, Category = Modifier) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Modifier) uint32 bAlt:1; /** Whether the command key is part of the chord. */ - UPROPERTY(EditAnywhere, Category = Modifier) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Modifier) uint32 bCmd:1; /** diff --git a/Engine/Source/Runtime/Slate/Public/Framework/Docking/TabManager.h b/Engine/Source/Runtime/Slate/Public/Framework/Docking/TabManager.h index ad1bc0ba3c26..01ba4e42e29b 100644 --- a/Engine/Source/Runtime/Slate/Public/Framework/Docking/TabManager.h +++ b/Engine/Source/Runtime/Slate/Public/Framework/Docking/TabManager.h @@ -237,6 +237,8 @@ class SLATE_API FTabManager : public TSharedFromThis friend class FTabManager; public: + + virtual ~FLayoutNode() { } virtual TSharedPtr AsStack(); @@ -661,6 +663,14 @@ class SLATE_API FTabManager : public TSharedFromThis */ virtual TSharedRef InvokeTab( const FTabId& TabId ); + /** + * Finds the first instance of an existing tab with the given tab id. + * + * @param TabId The tab identifier. + * @return The existing tab instance if found, otherwise null. + */ + TSharedPtr FindExistingLiveTab(const FTabId& TabId) const; + virtual ~FTabManager() { } @@ -722,9 +732,6 @@ class SLATE_API FTabManager : public TSharedFromThis TSharedRef InvokeTab_Internal( const FTabId& TabId ); - /** Finds the first instance of an existing tab with the given tab id. */ - TSharedPtr FindExistingLiveTab(const FTabId& TabId) const; - /** Finds the last major or nomad tab in a particular window. */ TSharedPtr FindLastTabInWindow(TSharedPtr Window) const; diff --git a/Engine/Source/Runtime/Slate/Public/Framework/Layout/InertialScrollManager.h b/Engine/Source/Runtime/Slate/Public/Framework/Layout/InertialScrollManager.h index 33cdc9d39d65..4476008a8464 100644 --- a/Engine/Source/Runtime/Slate/Public/Framework/Layout/InertialScrollManager.h +++ b/Engine/Source/Runtime/Slate/Public/Framework/Layout/InertialScrollManager.h @@ -5,17 +5,30 @@ #include "CoreMinimal.h" /** - * A helper class to calculate inertial scrolling + * A helper class to calculate inertial scrolling. This class combines a percentage of velocity lost + * per second coupled with a static amount of velocity lost per second in order to achieve a quick decay + * when the velocity grows small enough, and the percentage of friction lost prevents large velocities + * from scrolling forever. */ class SLATE_API FInertialScrollManager { + /** + * This is the percentage of velocity loss per second. + */ + static float FrictionCoefficient; + + /** + * This is a constant amount of velocity lost per second. + */ + static float StaticVelocityDrag; + public: /** * Constructor * @param ScrollDecceleration The acceleration against the velocity causing it to decay. * @param SampleTimeout Samples older than this amount of time will be discarded. */ - FInertialScrollManager(float ScrollDecceleration = 2048.f, double SampleTimeout = 0.1f); + FInertialScrollManager(double SampleTimeout = 0.1f); /** Adds a scroll velocity sample to help calculate a smooth velocity */ void AddScrollSample(float Delta, double CurrentTime); @@ -47,9 +60,6 @@ private: /** The current velocity of the scroll */ float ScrollVelocity; - /** The acceleration against the velocity causing it to decay. */ - float ScrollDecceleration; - /** Samples older than this amount of time will be discarded. */ double SampleTimeout; }; diff --git a/Engine/Source/Runtime/Slate/Public/Framework/MultiBox/MultiBoxBuilder.h b/Engine/Source/Runtime/Slate/Public/Framework/MultiBox/MultiBoxBuilder.h index 4754f077d55b..b6961827a6a4 100644 --- a/Engine/Source/Runtime/Slate/Public/Framework/MultiBox/MultiBoxBuilder.h +++ b/Engine/Source/Runtime/Slate/Public/Framework/MultiBox/MultiBoxBuilder.h @@ -44,6 +44,7 @@ public: */ FMultiBoxBuilder( const EMultiBoxType::Type InType, FMultiBoxCustomization InCustomization, const bool bInShouldCloseWindowAfterMenuSelection, const TSharedPtr< const FUICommandList >& InCommandList, TSharedPtr InExtender = TSharedPtr(), FName InTutorialHighlightName = NAME_None ); + virtual ~FMultiBoxBuilder() {} /** * Adds an editable text entry diff --git a/Engine/Source/Runtime/Slate/Public/Framework/Text/IOS/IOSPlatformTextField.h b/Engine/Source/Runtime/Slate/Public/Framework/Text/IOS/IOSPlatformTextField.h index eeb8d0001a89..fb54cd626d23 100644 --- a/Engine/Source/Runtime/Slate/Public/Framework/Text/IOS/IOSPlatformTextField.h +++ b/Engine/Source/Runtime/Slate/Public/Framework/Text/IOS/IOSPlatformTextField.h @@ -35,7 +35,9 @@ typedef FIOSPlatformTextField FPlatformTextField; #ifdef __IPHONE_8_0 UIAlertController* AlertController; #endif +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0 UIAlertView* AlertView; +#endif } -(void)show:(TSharedPtr)InTextWidget; diff --git a/Engine/Source/Runtime/Slate/Public/Slate.h b/Engine/Source/Runtime/Slate/Public/Slate.h index e9d0c58c3f47..e65769a49d4e 100644 --- a/Engine/Source/Runtime/Slate/Public/Slate.h +++ b/Engine/Source/Runtime/Slate/Public/Slate.h @@ -5,7 +5,6 @@ #include "Misc/MonolithicHeaderBoilerplate.h" MONOLITHIC_HEADER_BOILERPLATE() -EMIT_DEPRECATED_WARNING_MESSAGE("including Slate.h is deprecated. Please include SlateBasics.h and then individual widget headers instead."); #include "SlateBasics.h" #include "SlateExtras.h" diff --git a/Engine/Source/Runtime/Slate/Public/SlateSharedPCH.h b/Engine/Source/Runtime/Slate/Public/SlateSharedPCH.h index 14ac2dfb9f73..9b79815cf258 100644 --- a/Engine/Source/Runtime/Slate/Public/SlateSharedPCH.h +++ b/Engine/Source/Runtime/Slate/Public/SlateSharedPCH.h @@ -34,7 +34,6 @@ #include "Templates/EnableIf.h" #include "Templates/RemoveReference.h" #include "Templates/TypeCompatibleBytes.h" -#include "Templates/AlignOf.h" #include "Templates/ChooseClass.h" #include "Templates/IntegralConstant.h" #include "Templates/IsClass.h" @@ -362,7 +361,6 @@ #include "Widgets/Images/SImage.h" #include "Framework/Application/SlateApplication.h" #include "Framework/Application/MenuStack.h" -#include "Runtime/Slate/Private/Framework/Application/Menu.h" #include "SlateOptMacros.h" #include "Widgets/Input/SButton.h" #include "SlateFwd.h" @@ -385,9 +383,6 @@ #include "Widgets/Layout/SSplitter.h" #include "Framework/Commands/InputBindingManager.h" #include "Widgets/Docking/SDockTab.h" -#include "Runtime/Slate/Private/Framework/Docking/SDockingArea.h" -#include "Runtime/Slate/Private/Framework/Docking/SDockingNode.h" -#include "Runtime/Slate/Private/Framework/Docking/SDockingSplitter.h" #include "Widgets/Layout/SGridPanel.h" #include "Framework/Commands/Commands.h" #include "Widgets/Views/STreeView.h" diff --git a/Engine/Source/Runtime/Slate/Public/Widgets/Docking/SDockTab.h b/Engine/Source/Runtime/Slate/Public/Widgets/Docking/SDockTab.h index d40f66be787c..25962d24be8c 100644 --- a/Engine/Source/Runtime/Slate/Public/Widgets/Docking/SDockTab.h +++ b/Engine/Source/Runtime/Slate/Public/Widgets/Docking/SDockTab.h @@ -75,7 +75,7 @@ public: , _ShouldAutosize(false) , _OnCanCloseTab() , _OnPersistVisualState() - , _TabColorScale(0,0,0,0) + , _TabColorScale(FLinearColor::Transparent) {} SLATE_DEFAULT_SLOT( FArguments, Content ) @@ -91,7 +91,7 @@ public: SLATE_ARGUMENT( bool, ShouldAutosize ) SLATE_EVENT( FCanCloseTab, OnCanCloseTab ) SLATE_EVENT( FOnPersistVisualState, OnPersistVisualState ) - SLATE_ARGUMENT( FLinearColor, TabColorScale ) + SLATE_ATTRIBUTE( FLinearColor, TabColorScale ) SLATE_END_ARGS() /** Construct the widget from the declaration. */ @@ -371,7 +371,7 @@ protected: bool bShouldAutosize; /** Color of this tab */ - FLinearColor TabColorScale; + TAttribute TabColorScale; /** @return the scaling of the tab based on the opening/closing animation */ FVector2D GetAnimatedScale() const; diff --git a/Engine/Source/Runtime/Slate/Public/Widgets/Docking/SDockableTab.h b/Engine/Source/Runtime/Slate/Public/Widgets/Docking/SDockableTab.h index a687b999bfe8..08a1985d6089 100644 --- a/Engine/Source/Runtime/Slate/Public/Widgets/Docking/SDockableTab.h +++ b/Engine/Source/Runtime/Slate/Public/Widgets/Docking/SDockableTab.h @@ -98,14 +98,6 @@ protected: /** Delegate to execute to determine if we can close this tab */ SDockTab::FCanCloseTab OnCanCloseTab; - /** The brushes used to draw the tab in its various states */ - const FSlateBrush* NoBrush; - const FSlateBrush* NormalBrush; - const FSlateBrush* ActiveBrush; - const FSlateBrush* ColorOverlayBrush; - const FSlateBrush* ForegroundBrush; - const FSlateBrush* HoveredBrush; - /** * The brush that the SDockTabStack should use to draw the content associated with this tab * Documents, Apps, and Tool Panels have different backgrounds diff --git a/Engine/Source/Runtime/Slate/Public/Widgets/Images/SImage.h b/Engine/Source/Runtime/Slate/Public/Widgets/Images/SImage.h index 15c9e796d33e..919e27f86973 100644 --- a/Engine/Source/Runtime/Slate/Public/Widgets/Images/SImage.h +++ b/Engine/Source/Runtime/Slate/Public/Widgets/Images/SImage.h @@ -68,10 +68,13 @@ public: public: // SWidget overrides - virtual int32 OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const override; virtual FReply OnMouseButtonDown( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override; + +protected: + // Begin SWidget overrides. virtual FVector2D ComputeDesiredSize(float) const override; + // End SWidget overrides. protected: diff --git a/Engine/Source/Runtime/Slate/Public/Widgets/Input/SButton.h b/Engine/Source/Runtime/Slate/Public/Widgets/Input/SButton.h index f16542a43491..4c7318636825 100644 --- a/Engine/Source/Runtime/Slate/Public/Widgets/Input/SButton.h +++ b/Engine/Source/Runtime/Slate/Public/Widgets/Input/SButton.h @@ -156,33 +156,27 @@ public: /** See ButtonStyle attribute */ void SetButtonStyle(const FButtonStyle* ButtonStyle); + void SetClickMethod(EButtonClickMethod::Type InClickMethod); + void SetTouchMethod(EButtonTouchMethod::Type InTouchMethod); + void SetPressMethod(EButtonPressMethod::Type InPressMethod); + public: // SWidget overrides - virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override; - virtual bool SupportsKeyboardFocus() const override; - virtual void OnFocusLost( const FFocusEvent& InFocusEvent ) override; - virtual FReply OnKeyDown( const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent ) override; - virtual FReply OnKeyUp( const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent ) override; - virtual FReply OnMouseButtonDown( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override; - virtual FReply OnMouseButtonDoubleClick( const FGeometry& InMyGeometry, const FPointerEvent& InMouseEvent ) override; - virtual FReply OnMouseButtonUp( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override; - virtual FReply OnMouseMove( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override; - virtual void OnMouseEnter( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override; - virtual void OnMouseLeave( const FPointerEvent& MouseEvent ) override; - + virtual void OnMouseCaptureLost() override; virtual bool IsInteractable() const override; + // SWidget protected: @@ -204,6 +198,9 @@ protected: /** True if this button is currently in a pressed state */ bool bIsPressed; + /** The location in screenspace the button was pressed */ + FVector2D PressedScreenSpacePosition; + /** The delegate to execute when the button is clicked */ FOnClicked OnClicked; diff --git a/Engine/Source/Runtime/Slate/Public/Widgets/Input/SComboBox.h b/Engine/Source/Runtime/Slate/Public/Widgets/Input/SComboBox.h index 812b65d79ce9..fe36329522d8 100644 --- a/Engine/Source/Runtime/Slate/Public/Widgets/Input/SComboBox.h +++ b/Engine/Source/Runtime/Slate/Public/Widgets/Input/SComboBox.h @@ -234,8 +234,8 @@ public: // Need to establish the selected item at point of construction so its available for querying // NB: If you need a selection to fire use SetItemSelection rather than setting an IntiallySelectedItem - this->SelectedItem = InArgs._InitiallySelectedItem; - if( TListTypeTraits::IsPtrValid( InArgs._InitiallySelectedItem ) ) + SelectedItem = InArgs._InitiallySelectedItem; + if( TListTypeTraits::IsPtrValid( SelectedItem ) ) { ComboListView->Private_SetItemSelection( SelectedItem, true); } @@ -249,7 +249,14 @@ public: void SetSelectedItem( OptionType InSelectedItem ) { - ComboListView->SetSelection( InSelectedItem ); + if (TListTypeTraits::IsPtrValid(InSelectedItem)) + { + ComboListView->SetSelection(InSelectedItem); + } + else + { + ComboListView->ClearSelection(); + } } /** @return the item currently selected by the combo box. */ @@ -410,11 +417,14 @@ private: { if (bOpen == false) { - bControllerInputCaptured = false; - //Ensure the ListView selection is set back to the last committed selection - ComboListView->SetSelection(SelectedItem, ESelectInfo::OnNavigation); - ComboListView->RequestScrollIntoView(SelectedItem, 0); + + if (TListTypeTraits::IsPtrValid(SelectedItem)) + { + // Ensure the ListView selection is set back to the last committed selection + ComboListView->SetSelection(SelectedItem, ESelectInfo::OnNavigation); + ComboListView->RequestScrollIntoView(SelectedItem, 0); + } // Set focus back to ComboBox for users focusing the ListView that just closed FSlateApplication::Get().ForEachUser([&](FSlateUser* User) { diff --git a/Engine/Source/Runtime/Slate/Public/Widgets/Input/SInputKeySelector.h b/Engine/Source/Runtime/Slate/Public/Widgets/Input/SInputKeySelector.h index 8da28c8c5172..3a4ae477448e 100644 --- a/Engine/Source/Runtime/Slate/Public/Widgets/Input/SInputKeySelector.h +++ b/Engine/Source/Runtime/Slate/Public/Widgets/Input/SInputKeySelector.h @@ -17,6 +17,7 @@ #include "Framework/Commands/InputChord.h" class SButton; +class STextBlock; /** * A widget for selecting keys or input chords. @@ -30,10 +31,15 @@ public: SLATE_BEGIN_ARGS( SInputKeySelector ) : _SelectedKey( FInputChord(EKeys::Invalid) ) , _ButtonStyle( &FCoreStyle::Get().GetWidgetStyle( "Button" ) ) - , _KeySelectionText( NSLOCTEXT("DefaultKeySelectionText", "InputKeySelector", "...") ) + , _TextStyle( &FCoreStyle::Get().GetWidgetStyle< FTextBlockStyle >("NormalText") ) + , _KeySelectionText( NSLOCTEXT("InputKeySelector", "DefaultKeySelectionText", "...") ) + , _NoKeySpecifiedText(NSLOCTEXT("InputKeySelector", "DefaultEmptyText", "Empty")) , _AllowModifierKeys( true ) + , _AllowGamepadKeys( false ) , _EscapeCancelsSelection( true ) - {} + , _IsFocusable(true) + {} + /** The currently selected key */ SLATE_ATTRIBUTE( FInputChord, SelectedKey ) @@ -43,27 +49,38 @@ public: /** The margin around the selected key text. */ SLATE_ATTRIBUTE( FMargin, Margin ) - /** The color of the selected key text. */ - SLATE_ATTRIBUTE( FLinearColor, ColorAndOpacity ) - /** The style of the button used to enable key selection. */ SLATE_STYLE_ARGUMENT( FButtonStyle, ButtonStyle ) + /** The text style of the button text */ + SLATE_STYLE_ARGUMENT( FTextBlockStyle, TextStyle) + /** The text to display while selecting a new key. */ SLATE_ARGUMENT( FText, KeySelectionText ) + /** The text to display while no key text is available or not selecting a key. */ + SLATE_ARGUMENT(FText, NoKeySpecifiedText) + /** When true modifier keys are captured in the selected key chord, otherwise they are ignored. */ SLATE_ARGUMENT( bool, AllowModifierKeys ) + /** When true gamepad keys are captured in the selected key chord, otherwise they are ignored. */ + SLATE_ARGUMENT( bool, AllowGamepadKeys ) + /** When true, pressing escape will cancel the key selection, when false, pressing escape will select the escape key. */ SLATE_ARGUMENT( bool, EscapeCancelsSelection ) + /** When EscapeCancelsSelection is true, escape on specific keys that are unbind able by the user. */ + SLATE_ARGUMENT( TArray, EscapeKeys ) + /** Occurs whenever a new key is selected. */ SLATE_EVENT( FOnKeySelected, OnKeySelected ) /** Occurs whenever key selection mode starts and stops. */ SLATE_EVENT( FOnIsSelectingKeyChanged, OnIsSelectingKeyChanged ) + /** Sometimes a button should only be mouse-clickable and never keyboard focusable. */ + SLATE_ARGUMENT(bool, IsFocusable) SLATE_END_ARGS() void Construct( const FArguments& InArgs ); @@ -76,50 +93,52 @@ public: /** Sets the currently selected key chord. */ void SetSelectedKey( TAttribute InSelectedKey ); - /** Sets the font which is used to display the currently selected key. */ - void SetFont( TAttribute InFont ); - /** Sets the margin around the text used to display the currently selected key */ void SetMargin( TAttribute InMargin ); - /** Sets the color of the text used to display the currently selected key. */ - void SetColorAndOpacity( TAttribute InColorAndOpacity ); - /** Sets the style of the button which is used enter key selection mode. */ void SetButtonStyle( const FButtonStyle* ButtonStyle ); + /** Sets the style of the text on the button which is used enter key selection mode. */ + void SetTextStyle(const FTextBlockStyle* InTextStyle); + /** Sets the text which is displayed when selecting a key. */ - void SetKeySelectionText( FText InKeySelectionText ); + void SetKeySelectionText( FText InKeySelectionText ) { KeySelectionText = MoveTemp(InKeySelectionText); } + + /** Sets the text to display when no key text is available or not selecting a key. */ + void SetNoKeySpecifiedText(FText InNoKeySpecifiedText) { NoKeySpecifiedText = MoveTemp(InNoKeySpecifiedText); } /** When true modifier keys are captured in the selected key chord, otherwise they are ignored. */ - void SetAllowModifierKeys( bool bInAllowModifierKeys ); + void SetAllowModifierKeys(const bool bInAllowModifierKeys) { bAllowModifierKeys = bInAllowModifierKeys; } + + /** When true gamepad keys are captured in the selected key chord, otherwise they are ignored. */ + void SetAllowGamepadKeys(const bool bInAllowGamepadKeys) { bAllowGamepadKeys = bInAllowGamepadKeys; } + + /** Sets the escape keys to check against. */ + void SetEscapeKeys(TArray InEscapeKeys) { EscapeKeys = MoveTemp(InEscapeKeys); } /** Returns true whenever key selection mode is active, otherwise returns false. */ - bool GetIsSelectingKey() const; + bool GetIsSelectingKey() const { return bIsSelectingKey; } public: virtual FReply OnPreviewKeyDown( const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent ) override; + virtual FReply OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) override; virtual FReply OnKeyUp( const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent ) override; virtual FReply OnPreviewMouseButtonDown( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override; - + virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; virtual void OnFocusLost( const FFocusEvent& InFocusEvent ) override; - virtual bool SupportsKeyboardFocus() const { return true; } + virtual FNavigationReply OnNavigation(const FGeometry& MyGeometry, const FNavigationEvent& InNavigationEvent) override; + virtual bool SupportsKeyboardFocus() const override { return true; } private: /** Gets the display text for the currently selected key. */ FText GetSelectedKeyText() const; - /** Gets the font used to display the currently selected key. */ - FSlateFontInfo GetFont() const; - /** Gets the margin around the text used to display the currently selected key. */ FMargin GetMargin() const; - /** Gets the color of the text used to display the currently selected key. */ - FSlateColor GetSlateColorAndOpacity() const; - /** Handles the OnClicked event from the button which enables key selection mode. */ FReply OnClicked(); @@ -129,6 +148,9 @@ private: /** Sets bIsSelectingKey and invokes the associated events. */ void SetIsSelectingKey(bool bInIsSelectingKey); + /** Returns true, if the key has been specified as an escape key, else false. */ + bool IsEscapeKey(const FKey& InKey) const; + private: /** True when key selection mode is active. */ @@ -137,23 +159,26 @@ private: /** The currently selected key chord. */ TAttribute SelectedKey; - /** The font for the text used to display the currently selected key. */ - TAttribute Font; - /** The margin around the text used to display the currently selected key. */ TAttribute Margin; /** The text to display when selecting keys. */ FText KeySelectionText; + /** The text to display while no key text is available or not selecting a key. */ + FText NoKeySpecifiedText; + /** When true modifier keys are recorded on the selected key chord, otherwise they are ignored. */ bool bAllowModifierKeys; + /** When true gamepad keys are recorded on the selected key chord, otherwise they are ignored. */ + bool bAllowGamepadKeys; + /** When true, pressing escape will cancel the key selection, when false, pressing escape will select the escape key. */ bool bEscapeCancelsSelection; - /** The default font used for the text which displays the currently selected key. */ - FSlateFontInfo DefaultFont; + /** When EscapeCancelsSelection is true, escape on specific keys that are unbind able by the user. */ + TArray EscapeKeys; /** Delegate which is run any time a new key is selected. */ FOnKeySelected OnKeySelected; @@ -161,6 +186,12 @@ private: /** Delegate which is run when key selection mode starts and stops. */ FOnIsSelectingKeyChanged OnIsSelectingKeyChanged; - /** The button which starts key key selection mode. */ + /** The button which starts the key selection mode. */ TSharedPtr Button; + + /** The text which is rendered on the button. */ + TSharedPtr TextBlock; + + /** Can this button be focused? */ + bool bIsFocusable; }; diff --git a/Engine/Source/Runtime/Slate/Public/Widgets/Input/SSubMenuHandler.h b/Engine/Source/Runtime/Slate/Public/Widgets/Input/SSubMenuHandler.h index 32a82ab19b44..494dd0ae6189 100644 --- a/Engine/Source/Runtime/Slate/Public/Widgets/Input/SSubMenuHandler.h +++ b/Engine/Source/Runtime/Slate/Public/Widgets/Input/SSubMenuHandler.h @@ -16,10 +16,12 @@ class SLATE_API SSubMenuHandler : public SCompoundWidget { public: SLATE_BEGIN_ARGS( SSubMenuHandler ) + : _Placement( EMenuPlacement::MenuPlacement_MenuRight ) {} SLATE_DEFAULT_SLOT( FArguments, Content ) SLATE_ARGUMENT( TSharedPtr, MenuAnchor ) SLATE_ARGUMENT( TSharedPtr, MenuContent ) + SLATE_ATTRIBUTE( EMenuPlacement, Placement ) SLATE_EVENT( FOnGetContent, OnGetMenuContent ) SLATE_END_ARGS() diff --git a/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SBorder.h b/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SBorder.h index dce7d594a2e4..401dcfff456f 100644 --- a/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SBorder.h +++ b/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SBorder.h @@ -122,9 +122,13 @@ public: public: // SWidget interface virtual int32 OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const override; - virtual FVector2D ComputeDesiredSize(float) const override; // End of SWidget interface +protected: + // Begin SWidget overrides. + virtual FVector2D ComputeDesiredSize(float) const override; + // End SWidget overrides. + protected: TAttribute BorderImage; diff --git a/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SBox.h b/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SBox.h index 9d6fa8d0598e..08cc1fc5b8d0 100644 --- a/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SBox.h +++ b/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SBox.h @@ -85,8 +85,6 @@ class SLATE_API SBox : public SPanel void Construct( const FArguments& InArgs ); - - virtual FVector2D ComputeDesiredSize(float) const override; virtual void OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const override; virtual FChildren* GetChildren() override; virtual int32 OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const override; @@ -125,6 +123,11 @@ class SLATE_API SBox : public SPanel void SetMaxAspectRatio(TAttribute InMaxAspectRatio); +protected: + // Begin SWidget overrides. + virtual FVector2D ComputeDesiredSize(float) const override; + // End SWidget overrides. + protected: FBoxSlot ChildSlot; diff --git a/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SConstraintCanvas.h b/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SConstraintCanvas.h index 385e4ff1f381..280c6ff23b27 100644 --- a/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SConstraintCanvas.h +++ b/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SConstraintCanvas.h @@ -149,17 +149,16 @@ public: public: // Begin SWidget overrides - virtual void OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const override; - virtual int32 OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const override; - - virtual FVector2D ComputeDesiredSize(float) const override; - virtual FChildren* GetChildren() override; - // End SWidget overrides +protected: + // Begin SWidget overrides. + virtual FVector2D ComputeDesiredSize(float) const override; + // End SWidget overrides. + private: /** An array matching the length and order of ArrangedChildren. True means the child must be placed in a layer in front of all previous children. */ diff --git a/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SResponsiveGridPanel.h b/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SResponsiveGridPanel.h index 159365f06d6b..5354c7f49864 100644 --- a/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SResponsiveGridPanel.h +++ b/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SResponsiveGridPanel.h @@ -156,9 +156,13 @@ public: virtual int32 OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const override; virtual void OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const override; virtual void CacheDesiredSize(float) override; - virtual FVector2D ComputeDesiredSize(float) const override; virtual FChildren* GetChildren() override; +protected: + // Begin SWidget overrides. + virtual FVector2D ComputeDesiredSize(float) const override; + // End SWidget overrides. + private: /** diff --git a/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SSafeZone.h b/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SSafeZone.h index 9e26b85aee14..fc1527b3740c 100644 --- a/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SSafeZone.h +++ b/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SSafeZone.h @@ -90,6 +90,13 @@ class SLATE_API SSafeZone : public SBox public: + SSafeZone() + { + bCanTick = false; + bCanSupportFocus = false; + } + virtual ~SSafeZone(); + void Construct( const FArguments& InArgs ); void SafeAreaUpdated(); @@ -125,5 +132,7 @@ private: /** Screen space margin */ FMargin SafeMargin; + + FDelegateHandle OnSafeFrameChangedHandle; }; diff --git a/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SScaleBox.h b/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SScaleBox.h index adf5d5e9d5c6..a69e56b4f9c8 100644 --- a/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SScaleBox.h +++ b/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SScaleBox.h @@ -82,6 +82,7 @@ public: , _Stretch(EStretch::None) , _UserSpecifiedScale(1.0f) , _IgnoreInheritedScale(false) + , _SingleLayoutPass(false) {} /** Slot for this designers content (optional) */ SLATE_DEFAULT_SLOT(FArguments, Content) @@ -104,6 +105,15 @@ public: /** Undo any inherited scale factor before applying this scale box's scale */ SLATE_ATTRIBUTE(bool, IgnoreInheritedScale) + /** + * Only perform a single layout pass, if you do this, it can save a considerable + * amount of time, however, some things like text may not look correct. You may also + * see the UI judder between frames. This generally is caused by not explicitly + * sizing the widget, and instead allowing it to layout based on desired size along + * which won't work in Single Layout Pass mode. + */ + SLATE_ARGUMENT(bool, SingleLayoutPass) + SLATE_END_ARGS() /** Constructor */ @@ -113,11 +123,12 @@ public: bCanSupportFocus = false; } + virtual ~SScaleBox(); + void Construct(const FArguments& InArgs); // SWidget interface virtual void OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const override; - virtual FVector2D ComputeDesiredSize(float InScale) const override; virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override; // End SWidget of interface @@ -143,11 +154,15 @@ public: void SetIgnoreInheritedScale(bool InIgnoreInheritedScale); protected: + // Begin SWidget overrides. + virtual FVector2D ComputeDesiredSize(float InScale) const override; virtual float GetRelativeLayoutScale(const FSlotBase& Child, float LayoutScaleMultiplier) const override; + // End SWidget overrides. float GetLayoutScale() const; void RefreshSafeZoneScale(); -private: + +protected: /** The allowed direction of stretching of the content */ TAttribute StretchDirection; @@ -162,4 +177,33 @@ private: /** Computed scale when scaled by safe zone padding */ float SafeZoneScale; + + /** Delegate handle to unhook the safe frame changed. */ + FDelegateHandle OnSafeFrameChangedHandle; + + /** + * Determines if this scale box should attempt to layout everything using only a + * single pass each frame. This is a MUCH more efficient mode, since invalidating + * text during prepass is expensive, however for that very reason this mode may not + * work always, but for large pieces of UI with a restricted size you should try it. + */ + bool bSingleLayoutPass; + + /** */ + mutable TOptional LastContentDesiredSize; + + /** */ + mutable FVector2D LastAreaSize; + + /** */ + mutable float LastIncomingScale; + + /** */ + mutable TOptional LastFinalScale; + + /** */ + mutable FVector2D LastFinalOffset; + + /** */ + mutable FVector2D LastSlotWidgetDesiredSize; }; diff --git a/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SScrollBar.h b/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SScrollBar.h index 40fc6954762b..d1b5392fd6f6 100644 --- a/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SScrollBar.h +++ b/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SScrollBar.h @@ -31,6 +31,11 @@ public: : _Style( &FCoreStyle::Get().GetWidgetStyle("Scrollbar") ) , _OnUserScrolled() , _AlwaysShowScrollbar(false) +#if PLATFORM_UI_HAS_MOBILE_SCROLLBARS + , _HideWhenNotInUse(true) +#else + , _HideWhenNotInUse(false) +#endif , _Orientation( Orient_Vertical ) , _Thickness( FVector2D(12.0f, 12.0f) ) {} @@ -39,6 +44,7 @@ public: SLATE_STYLE_ARGUMENT( FScrollBarStyle, Style ) SLATE_EVENT( FOnUserScrolled, OnUserScrolled ) SLATE_ARGUMENT( bool, AlwaysShowScrollbar ) + SLATE_ARGUMENT( bool, HideWhenNotInUse ) SLATE_ARGUMENT( EOrientation, Orientation ) /** The thickness of the scrollbar thumb */ SLATE_ATTRIBUTE( FVector2D, Thickness ) @@ -68,35 +74,13 @@ public: */ void SetState( float InOffsetFraction, float InThumbSizeFraction ); - /** - * The system calls this method to notify the widget that a mouse button was pressed within it. This event is bubbled. - * - * @param MyGeometry The Geometry of the widget receiving the event - * @param MouseEvent Information about the input event - * - * @return Whether the event was handled along with possible requests for the system to take action. - */ - virtual FReply OnMouseButtonDown( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ); - - /** - * The system calls this method to notify the widget that a mouse button was release within it. This event is bubbled. - * - * @param MyGeometry The Geometry of the widget receiving the event - * @param MouseEvent Information about the input event - * - * @return Whether the event was handled along with possible requests for the system to take action. - */ - virtual FReply OnMouseButtonUp( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ); - - /** - * The system calls this method to notify the widget that a mouse moved within it. This event is bubbled. - * - * @param MyGeometry The Geometry of the widget receiving the event - * @param MouseEvent Information about the input event - * - * @return Whether the event was handled along with possible requests for the system to take action. - */ - virtual FReply OnMouseMove( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ); + // SWidget + virtual FReply OnMouseButtonDown( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override; + virtual FReply OnMouseButtonUp( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override; + virtual FReply OnMouseMove( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override; + virtual void OnMouseEnter(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; + virtual void OnMouseLeave(const FPointerEvent& MouseEvent) override; + // SWidget /** @return true if scrolling is possible; false if the view is big enough to fit all the content */ bool IsNeeded() const; @@ -128,6 +112,12 @@ public: /** See ScrollBarAlwaysVisible attribute */ void SetScrollBarAlwaysVisible(bool InAlwaysVisible); + /** Allows external scrolling panels to notify the scrollbar when scrolling begins. */ + virtual void BeginScrolling(); + + /** Allows external scrolling panels to notify the scrollbar when scrolling ends. */ + virtual void EndScrolling(); + SScrollBar(); protected: @@ -154,6 +144,9 @@ protected: FOnUserScrolled OnUserScrolled; float DragGrabOffset; EOrientation Orientation; + bool bHideWhenNotInUse; + bool bIsScrolling; + double LastInteractionTime; /** Image to use when the scrollbar thumb is in its normal state */ const FSlateBrush* NormalThumbImage; diff --git a/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SScrollBox.h b/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SScrollBox.h index cf7487c25fde..21fbcf891d91 100644 --- a/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SScrollBox.h +++ b/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SScrollBox.h @@ -169,13 +169,11 @@ public: virtual FReply OnMouseMove( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override; virtual void OnMouseLeave( const FPointerEvent& MouseEvent ) override; virtual FReply OnMouseWheel( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override; - virtual FReply OnDragDetected( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override; virtual FCursorReply OnCursorQuery( const FGeometry& MyGeometry, const FPointerEvent& CursorEvent ) const override; virtual int32 OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const override; - virtual FReply OnTouchStarted(const FGeometry& MyGeometry, const FPointerEvent& InTouchEvent) override; - virtual FReply OnTouchMoved(const FGeometry& MyGeometry, const FPointerEvent& InTouchEvent) override; virtual FReply OnTouchEnded(const FGeometry& MyGeometry, const FPointerEvent& InTouchEvent) override; - virtual FNavigationReply OnNavigation(const FGeometry& MyGeometry, const FNavigationEvent& InNavigationEvent); + virtual void OnMouseCaptureLost() override; + virtual FNavigationReply OnNavigation(const FGeometry& MyGeometry, const FNavigationEvent& InNavigationEvent) override; // End of SWidget interface private: @@ -222,7 +220,7 @@ private: * @param InAnimateScroll Whether or not to animate the scroll * @return Whether or not the scroll was fully handled */ - bool ScrollBy(const FGeometry& AllottedGeometry, float ScrollAmount, EAllowOverscroll Overscroll, bool InAnimateScroll = true); + bool ScrollBy(const FGeometry& AllottedGeometry, float ScrollAmount, EAllowOverscroll Overscroll, bool InAnimateScroll); /** Invoked when the user scroll via the scrollbar */ void ScrollBar_OnUserScrolled( float InScrollOffsetFraction ); @@ -239,6 +237,10 @@ private: /** Check whether the current state of the table warrants inertial scroll by the specified amount */ bool CanUseInertialScroll(float ScrollAmount) const; + void BeginInertialScrolling(); + + void EndInertialScrolling(); + private: /** The panel which stacks the child slots */ @@ -251,11 +253,14 @@ private: float TickScrollDelta; /** Did the user start an interaction in this list? */ - bool bStartedTouchInteraction; + TOptional bFingerOwningTouchInteraction; /** How much we scrolled while the rmb has been held */ float AmountScrolledWhileRightMouseDown; + /** The current deviation we've accumulated on scrol, once it passes the trigger amount, we're going to begin scrolling. */ + float PendingScrollTriggerAmount; + /** Helper object to manage inertial scrolling */ FInertialScrollManager InertialScrollManager; @@ -292,6 +297,10 @@ private: /** Where we should scroll the descendant to */ EDescendantScrollDestination DestinationScrollingWidgetIntoView; + TSharedPtr UpdateInertialScrollHandle; + + double LastScrollTime; + /** Whether we should scroll the widget into view over time. */ bool bAnimateScrollingWidgetIntoView : 1; @@ -312,4 +321,7 @@ private: /** Whether the active timer to update the inertial scroll is registered */ bool bIsScrollingActiveTimerRegistered : 1; + + /** */ + bool bTouchPanningCapture : 1; }; diff --git a/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SSpacer.h b/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SSpacer.h index a05cb8779765..1ddb7d83dde2 100644 --- a/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SSpacer.h +++ b/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SSpacer.h @@ -39,7 +39,6 @@ public: // SWidget interface virtual int32 OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const override; - virtual FVector2D ComputeDesiredSize(float) const override; // End of SWidget interface FVector2D GetSize() const @@ -52,6 +51,10 @@ public: SpacerSize = InSpacerSize; } +protected: + // Begin SWidget overrides. + virtual FVector2D ComputeDesiredSize(float) const override; + // End SWidget overrides. private: TAttribute SpacerSize; diff --git a/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SUniformGridPanel.h b/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SUniformGridPanel.h index 5821894aa33d..8c6f1cff1dfb 100644 --- a/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SUniformGridPanel.h +++ b/Engine/Source/Runtime/Slate/Public/Widgets/Layout/SUniformGridPanel.h @@ -69,7 +69,6 @@ public: //~ Begin SPanel Interface virtual void OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const override; - virtual FVector2D ComputeDesiredSize(float) const override; virtual FChildren* GetChildren() override; //~ End SPanel Interface @@ -100,6 +99,11 @@ public: /** Removes all slots from the panel */ void ClearChildren(); +protected: + // Begin SWidget overrides. + virtual FVector2D ComputeDesiredSize(float) const override; + // End SWidget overrides. + private: TPanelChildren Children; TAttribute SlotPadding; diff --git a/Engine/Source/Runtime/Slate/Public/Widgets/SCanvas.h b/Engine/Source/Runtime/Slate/Public/Widgets/SCanvas.h index 1ea3863a7932..0b8d23525276 100644 --- a/Engine/Source/Runtime/Slate/Public/Widgets/SCanvas.h +++ b/Engine/Source/Runtime/Slate/Public/Widgets/SCanvas.h @@ -150,9 +150,13 @@ public: virtual void OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const override; virtual int32 OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const override; - virtual FVector2D ComputeDesiredSize(float) const override; virtual FChildren* GetChildren() override; +protected: + // Begin SWidget overrides. + virtual FVector2D ComputeDesiredSize(float) const override; + // End SWidget overrides. + protected: /** The canvas widget's children. */ diff --git a/Engine/Source/Runtime/Slate/Public/Widgets/SInvalidationPanel.h b/Engine/Source/Runtime/Slate/Public/Widgets/SInvalidationPanel.h index 7cd47ee12359..bcdf0b7a7e12 100644 --- a/Engine/Source/Runtime/Slate/Public/Widgets/SInvalidationPanel.h +++ b/Engine/Source/Runtime/Slate/Public/Widgets/SInvalidationPanel.h @@ -83,6 +83,7 @@ private: #else FORCEINLINE bool IsCachingNeeded() const { return bNeedsCaching; } #endif + bool IsCachingNeeded(const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect) const; diff --git a/Engine/Source/Runtime/Slate/Public/Widgets/SWeakWidget.h b/Engine/Source/Runtime/Slate/Public/Widgets/SWeakWidget.h index 263e77f14e45..2b36993b397f 100644 --- a/Engine/Source/Runtime/Slate/Public/Widgets/SWeakWidget.h +++ b/Engine/Source/Runtime/Slate/Public/Widgets/SWeakWidget.h @@ -46,12 +46,15 @@ public: public: // SWidget interface - - virtual FVector2D ComputeDesiredSize(float) const override; virtual void OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const override; virtual FChildren* GetChildren() override; virtual int32 OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const override; +protected: + // Begin SWidget overrides. + virtual FVector2D ComputeDesiredSize(float) const override; + // End SWidget overrides. + private: TWeakChild WeakChild; diff --git a/Engine/Source/Runtime/Slate/Public/Widgets/Text/SRichTextBlock.h b/Engine/Source/Runtime/Slate/Public/Widgets/Text/SRichTextBlock.h index f45b7be160f8..a3546354e8f6 100644 --- a/Engine/Source/Runtime/Slate/Public/Widgets/Text/SRichTextBlock.h +++ b/Engine/Source/Runtime/Slate/Public/Widgets/Text/SRichTextBlock.h @@ -156,7 +156,6 @@ public: //~ Begin SWidget Interface void Construct( const FArguments& InArgs ); virtual int32 OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const override; - virtual FVector2D ComputeDesiredSize(float) const override; virtual FChildren* GetChildren() override; virtual void OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const override; //~ End SWidget Interface @@ -214,6 +213,7 @@ public: protected: //~ SWidget interface + virtual FVector2D ComputeDesiredSize(float) const override; virtual bool ComputeVolatility() const override; //~ End of SWidget interface diff --git a/Engine/Source/Runtime/Slate/Public/Widgets/Text/STextBlock.h b/Engine/Source/Runtime/Slate/Public/Widgets/Text/STextBlock.h index 6a870ae93baf..018b7608fc3e 100644 --- a/Engine/Source/Runtime/Slate/Public/Widgets/Text/STextBlock.h +++ b/Engine/Source/Runtime/Slate/Public/Widgets/Text/STextBlock.h @@ -223,7 +223,7 @@ public: // End of SWidget interface protected: - // SWidget interface + // Begin SWidget overrides. virtual bool ComputeVolatility() const override; // End of SWidget interface diff --git a/Engine/Source/Runtime/Slate/Public/Widgets/Views/STileView.h b/Engine/Source/Runtime/Slate/Public/Widgets/Views/STileView.h index 12a7a511ba55..6261f11b32d3 100644 --- a/Engine/Source/Runtime/Slate/Public/Widgets/Views/STileView.h +++ b/Engine/Source/Runtime/Slate/Public/Widgets/Views/STileView.h @@ -327,14 +327,8 @@ public: WidthUsedSoFar = 0; bNewRow = true; - // Hack: Added "+ ItemHeight". This unfixes a previous bug which caused TileViews to - // work when placed in a SScrollBox. - // !!!!!! THIS IS A PORTAL ONLY CHANGE !!!!!! - // If found outside of portal repositories please - // Contact: Barnabas.McManners or Justin.Sargent. - // Stop when we've generated a widget that's partially clipped by the bottom of the list. - if ( HeightUsedSoFar >= MyGeometry.Size.Y /**/+ ItemHeight /**/) + if ( HeightUsedSoFar >= MyGeometry.Size.Y ) { bKeepGenerating = false; } diff --git a/Engine/Source/Runtime/SlateCore/Private/Fonts/FontCache.cpp b/Engine/Source/Runtime/SlateCore/Private/Fonts/FontCache.cpp index fa1d8e4211db..c374aade2d21 100644 --- a/Engine/Source/Runtime/SlateCore/Private/Fonts/FontCache.cpp +++ b/Engine/Source/Runtime/SlateCore/Private/Fonts/FontCache.cpp @@ -47,13 +47,15 @@ FShapedGlyphEntryKey::FShapedGlyphEntryKey(const FShapedGlyphFaceData& InFontFac : FontFace(InFontFaceData.FontFace) , FontSize(InFontFaceData.FontSize) , OutlineSize(InOutlineSettings.OutlineSize) + , OutlineSizeSeparateFillAlpha(InOutlineSettings.bSeparateFillAlpha) , FontScale(InFontFaceData.FontScale) , GlyphIndex(InGlyphIndex) , KeyHash(0) { KeyHash = HashCombine(KeyHash, GetTypeHash(FontFace)); KeyHash = HashCombine(KeyHash, GetTypeHash(FontSize)); - KeyHash = HashCombine(KeyHash, GetTypeHash(InOutlineSettings)); + KeyHash = HashCombine(KeyHash, GetTypeHash(OutlineSize)); + KeyHash = HashCombine(KeyHash, GetTypeHash(OutlineSizeSeparateFillAlpha)); KeyHash = HashCombine(KeyHash, GetTypeHash(FontScale)); KeyHash = HashCombine(KeyHash, GetTypeHash(GlyphIndex)); } diff --git a/Engine/Source/Runtime/SlateCore/Private/Fonts/FontCacheFreeType.cpp b/Engine/Source/Runtime/SlateCore/Private/Fonts/FontCacheFreeType.cpp index 44ece8e01f16..a6cd3185e8d0 100644 --- a/Engine/Source/Runtime/SlateCore/Private/Fonts/FontCacheFreeType.cpp +++ b/Engine/Source/Runtime/SlateCore/Private/Fonts/FontCacheFreeType.cpp @@ -369,12 +369,16 @@ bool FFreeTypeAdvanceCache::FindOrCache(FT_Face InFace, const uint32 InGlyphInde } } - FreeTypeUtils::ApplySizeAndScale(InFace, InFontSize, InFontScale); + FreeTypeUtils::ApplySizeAndScale(InFace, InFontSize, 1.0f); // No cached data, go ahead and add an entry for it... FT_Error Error = FT_Get_Advance(InFace, InGlyphIndex, InLoadFlags, &OutCachedAdvance); if (Error == 0) { + // We apply our own scaling as FreeType doesn't always produce the correct results for all fonts when applying the scale via the transform matrix + const FT_Long FixedFontScale = FreeTypeUtils::ConvertPixelTo16Dot16(InFontScale); + OutCachedAdvance = FT_MulFix(OutCachedAdvance, FixedFontScale); + CachedAdvanceMap.Add(CachedAdvanceKey, OutCachedAdvance); return true; } diff --git a/Engine/Source/Runtime/SlateCore/Private/Fonts/SlateFontRenderer.cpp b/Engine/Source/Runtime/SlateCore/Private/Fonts/SlateFontRenderer.cpp index 1be41fdc72ab..4e76a2317c16 100644 --- a/Engine/Source/Runtime/SlateCore/Private/Fonts/SlateFontRenderer.cpp +++ b/Engine/Source/Runtime/SlateCore/Private/Fonts/SlateFontRenderer.cpp @@ -199,7 +199,7 @@ FFreeTypeFaceGlyphData FSlateFontRenderer::GetFontFaceForCharacter(const FFontDa } // If the requested glyph doesn't exist, use the localization fallback font - if (Char != 0 && ReturnVal.GlyphIndex == 0) + if (!ReturnVal.FaceAndMemory.IsValid() || (Char != 0 && ReturnVal.GlyphIndex == 0)) { const bool bCanFallback = bOverrideFallback || MaxFallbackLevel >= EFontFallback::FF_LocalizedFallback; @@ -221,7 +221,7 @@ FFreeTypeFaceGlyphData FSlateFontRenderer::GetFontFaceForCharacter(const FFontDa } // If the requested glyph doesn't exist, use the last resort fallback font - if (Char != 0 && ReturnVal.GlyphIndex == 0) + if (!ReturnVal.FaceAndMemory.IsValid() || (Char != 0 && ReturnVal.GlyphIndex == 0)) { const bool bCanFallback = bOverrideFallback || MaxFallbackLevel >= EFontFallback::FF_LastResortFallback; diff --git a/Engine/Source/Runtime/SlateCore/Private/Fonts/UnicodeBlockRange.cpp b/Engine/Source/Runtime/SlateCore/Private/Fonts/UnicodeBlockRange.cpp new file mode 100644 index 000000000000..e171775ab9a4 --- /dev/null +++ b/Engine/Source/Runtime/SlateCore/Private/Fonts/UnicodeBlockRange.cpp @@ -0,0 +1,20 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#include "Fonts/UnicodeBlockRange.h" + +TArrayView FUnicodeBlockRange::GetUnicodeBlockRanges() +{ + static const FUnicodeBlockRange UnicodeBlockRanges[] = { + #define REGISTER_UNICODE_BLOCK_RANGE(LOWERBOUND, UPPERBOUND, SYMBOLNAME, DISPLAYNAME) { EUnicodeBlockRange::SYMBOLNAME, DISPLAYNAME, FInt32Range(FInt32Range::BoundsType::Inclusive(LOWERBOUND), FInt32Range::BoundsType::Inclusive(UPPERBOUND)) }, + #include "UnicodeBlockRange.inl" + #undef REGISTER_UNICODE_BLOCK_RANGE + }; + + return UnicodeBlockRanges; +} + +FUnicodeBlockRange FUnicodeBlockRange::GetUnicodeBlockRange(const EUnicodeBlockRange InBlockIndex) +{ + TArrayView UnicodeBlockRanges = GetUnicodeBlockRanges(); + return UnicodeBlockRanges[(int32)InBlockIndex]; +} diff --git a/Engine/Source/Runtime/SlateCore/Private/Input/Events.cpp b/Engine/Source/Runtime/SlateCore/Private/Input/Events.cpp index 9fad89debc17..9a81d390ba03 100644 --- a/Engine/Source/Runtime/SlateCore/Private/Input/Events.cpp +++ b/Engine/Source/Runtime/SlateCore/Private/Input/Events.cpp @@ -62,4 +62,3 @@ bool FPointerEvent::IsPointerEvent() const { return true; } - diff --git a/Engine/Source/Runtime/SlateCore/Private/Layout/SlateRotatedRect.cpp b/Engine/Source/Runtime/SlateCore/Private/Layout/SlateRotatedRect.cpp index 4fb7b477de25..f04b1c347af7 100644 --- a/Engine/Source/Runtime/SlateCore/Private/Layout/SlateRotatedRect.cpp +++ b/Engine/Source/Runtime/SlateCore/Private/Layout/SlateRotatedRect.cpp @@ -68,4 +68,3 @@ FSlateRotatedRect FSlateRotatedRect::MakeSnappedRotatedRect(const FSlateRect& Cl SnappedTopRight - SnappedTopLeft, SnappedBottomLeft - SnappedTopLeft); } - diff --git a/Engine/Source/Runtime/SlateCore/Private/Layout/WidgetCaching.cpp b/Engine/Source/Runtime/SlateCore/Private/Layout/WidgetCaching.cpp index 69b7e6a62860..9d84cd268b5a 100644 --- a/Engine/Source/Runtime/SlateCore/Private/Layout/WidgetCaching.cpp +++ b/Engine/Source/Runtime/SlateCore/Private/Layout/WidgetCaching.cpp @@ -24,7 +24,7 @@ void FCachedWidgetNode::Initialize(const FPaintArgs& Args, TSharedRef I Children.Reset(); } -void FCachedWidgetNode::RecordHittestGeometry(FHittestGrid& Grid, int32 LastHittestIndex, int32 LayerId) +void FCachedWidgetNode::RecordHittestGeometry(FHittestGrid& Grid, int32 LastHittestIndex, int32 LayerId, FVector2D DynamicOffset) { if ( RecordedVisibility.AreChildrenHitTestVisible() ) { @@ -36,25 +36,25 @@ void FCachedWidgetNode::RecordHittestGeometry(FHittestGrid& Grid, int32 LastHitt const int32 ChildCount = Children.Num(); for ( int32 i = 0; i < ChildCount; i++ ) { - Children[i]->RecordHittestGeometryInternal(Grid, LastHittestIndex, LayerId); + Children[i]->RecordHittestGeometryInternal(Grid, LastHittestIndex, LayerId, DynamicOffset); } } } } -void FCachedWidgetNode::RecordHittestGeometryInternal(FHittestGrid& Grid, int32 LastHittestIndex, int32 LayerId) +void FCachedWidgetNode::RecordHittestGeometryInternal(FHittestGrid& Grid, int32 LastHittestIndex, int32 LayerId, FVector2D DynamicOffset) { if ( RecordedVisibility.AreChildrenHitTestVisible() ) { TSharedPtr SafeWidget = Widget.Pin(); if ( SafeWidget.IsValid() ) { - LastRecordedHittestIndex = Grid.InsertWidget(LastHittestIndex, RecordedVisibility, FArrangedWidget(SafeWidget.ToSharedRef(), Geometry), WindowOffset, ClippingRect, LayerId); + LastRecordedHittestIndex = Grid.InsertWidget(LastHittestIndex, RecordedVisibility, FArrangedWidget(SafeWidget.ToSharedRef(), Geometry), WindowOffset + DynamicOffset, ClippingRect, LayerId); const int32 ChildCount = Children.Num(); for ( int32 i = 0; i < ChildCount; i++ ) { - Children[i]->RecordHittestGeometryInternal(Grid, LastRecordedHittestIndex, LayerId); + Children[i]->RecordHittestGeometryInternal(Grid, LastRecordedHittestIndex, LayerId, DynamicOffset); } } } diff --git a/Engine/Source/Runtime/SlateCore/Private/Layout/WidgetPath.cpp b/Engine/Source/Runtime/SlateCore/Private/Layout/WidgetPath.cpp index a9a87595133d..876739371682 100644 --- a/Engine/Source/Runtime/SlateCore/Private/Layout/WidgetPath.cpp +++ b/Engine/Source/Runtime/SlateCore/Private/Layout/WidgetPath.cpp @@ -243,6 +243,13 @@ FWidgetPath FWeakWidgetPath::ToWidgetPath(EInterruptedPathHandling::Type Interru return WidgetPath; } +TSharedRef FWeakWidgetPath::ToWidgetPathRef(EInterruptedPathHandling::Type InterruptedPathHandling, const FPointerEvent* PointerEvent) const +{ + TSharedRef WidgetPath = MakeShareable(new FWidgetPath()); + ToWidgetPath(WidgetPath.Get(), InterruptedPathHandling, PointerEvent); + return WidgetPath; +} + FWeakWidgetPath::EPathResolutionResult::Result FWeakWidgetPath::ToWidgetPath( FWidgetPath& WidgetPath, EInterruptedPathHandling::Type InterruptedPathHandling, const FPointerEvent* PointerEvent ) const { SCOPE_CYCLE_COUNTER(STAT_ToWidgetPath); @@ -291,7 +298,7 @@ FWeakWidgetPath::EPathResolutionResult::Result FWeakWidgetPath::ToWidgetPath( FW { FArrangedWidget& ArrangedWidget = ArrangedChildren[SearchIndex]; - if ( ArrangedWidget.Widget == WidgetPtrs[WidgetIndex+1] ) + if ( ArrangedWidget.Widget == WidgetPtrs[WidgetIndex + 1] ) { if( PointerEvent && !VirtualPointerPos.IsValid() ) { @@ -332,12 +339,12 @@ bool FWeakWidgetPath::ContainsWidget( const TSharedRef< const SWidget >& SomeWid return false; } -FWidgetPath FWeakWidgetPath::ToNextFocusedPath(EUINavigation NavigationType) +FWidgetPath FWeakWidgetPath::ToNextFocusedPath(EUINavigation NavigationType) const { return ToNextFocusedPath(NavigationType, FNavigationReply::Escape(), FArrangedWidget::NullWidget); } -FWidgetPath FWeakWidgetPath::ToNextFocusedPath(EUINavigation NavigationType, const FNavigationReply& NavigationReply, const FArrangedWidget& RuleWidget) +FWidgetPath FWeakWidgetPath::ToNextFocusedPath(EUINavigation NavigationType, const FNavigationReply& NavigationReply, const FArrangedWidget& RuleWidget) const { check(NavigationType == EUINavigation::Next || NavigationType == EUINavigation::Previous); diff --git a/Engine/Source/Runtime/SlateCore/Private/Rendering/DrawElements.cpp b/Engine/Source/Runtime/SlateCore/Private/Rendering/DrawElements.cpp index bd94a909e4c0..6fc0a2d0c23c 100644 --- a/Engine/Source/Runtime/SlateCore/Private/Rendering/DrawElements.cpp +++ b/Engine/Source/Runtime/SlateCore/Private/Rendering/DrawElements.cpp @@ -21,7 +21,7 @@ void FSlateDataPayload::SetTextPayloadProperties( FSlateWindowElementList& Eleme int32 StartIndex = FMath::Min(InStartIndex, Count - 1); int32 EndIndex = FMath::Min(InEndIndex, Count - 1); Count = 1 + ((EndIndex > StartIndex) ? EndIndex - StartIndex : 0); - ImmutableText = (TCHAR*)ElementList.Alloc(sizeof(TCHAR) * Count, ALIGNOF(TCHAR)); + ImmutableText = (TCHAR*)ElementList.Alloc(sizeof(TCHAR) * Count, alignof(TCHAR)); if (Count > 1) { FCString::Strncpy(ImmutableText, InText.GetCharArray().GetData() + StartIndex, Count); diff --git a/Engine/Source/Runtime/SlateCore/Private/Rendering/ElementBatcher.cpp b/Engine/Source/Runtime/SlateCore/Private/Rendering/ElementBatcher.cpp index 9c8949eb3362..2966415fa39d 100644 --- a/Engine/Source/Runtime/SlateCore/Private/Rendering/ElementBatcher.cpp +++ b/Engine/Source/Runtime/SlateCore/Private/Rendering/ElementBatcher.cpp @@ -58,6 +58,7 @@ void FSlateElementBatcher::AddElements(FSlateWindowElementList& WindowElementLis TMap < TSharedPtr, TSharedPtr >& DrawLayers = WindowElementList.GetChildDrawLayers(); for ( auto& Entry : DrawLayers ) { + DrawLayer = Entry.Value.Get(); AddElements(Entry.Value.Get()->DrawElements, ViewportSize); } diff --git a/Engine/Source/Runtime/SlateCore/Private/Styling/CoreStyle.cpp b/Engine/Source/Runtime/SlateCore/Private/Styling/CoreStyle.cpp index a02594b2cab6..043888697a72 100644 --- a/Engine/Source/Runtime/SlateCore/Private/Styling/CoreStyle.cpp +++ b/Engine/Source/Runtime/SlateCore/Private/Styling/CoreStyle.cpp @@ -1065,7 +1065,7 @@ TSharedRef FCoreStyle::Create( const FName& InStyleSetName ) .SetCloseButtonStyle( CloseButton ) .SetNormalBrush( BOX_BRUSH( "/Docking/Tab_Inactive", 4/16.0f ) ) .SetActiveBrush( BOX_BRUSH( "/Docking/Tab_Active", 4/16.0f ) ) - .SetColorOverlayBrush( BOX_BRUSH( "/Docking/Tab_ColorOverlay", 4/16.0f ) ) + .SetColorOverlayBrush( BOX_BRUSH( "/Docking/Tab_ColorOverlayIcon", 4/16.0f ) ) .SetForegroundBrush( BOX_BRUSH( "/Docking/Tab_Foreground", 4/16.0f ) ) .SetHoveredBrush( BOX_BRUSH( "/Docking/Tab_Hovered", 4/16.0f ) ) .SetContentAreaBrush( BOX_BRUSH( "/Docking/TabContentArea", FMargin(4/16.0f) ) ) @@ -1080,7 +1080,7 @@ TSharedRef FCoreStyle::Create( const FName& InStyleSetName ) .SetCloseButtonStyle( CloseButton ) .SetNormalBrush( BOX_BRUSH( "/Docking/AppTab_Inactive", FMargin(24.0f/64.0f, 4/32.0f) ) ) .SetActiveBrush( BOX_BRUSH( "/Docking/AppTab_Active", FMargin(24.0f/64.0f, 4/32.0f) ) ) - .SetColorOverlayBrush( BOX_BRUSH( "/Docking/AppTab_ColorOverlay", FMargin(24.0f/64.0f, 4/32.0f) ) ) + .SetColorOverlayBrush( BOX_BRUSH( "/Docking/AppTab_ColorOverlayIcon", FMargin(24.0f/64.0f, 4/32.0f) ) ) .SetForegroundBrush( BOX_BRUSH( "/Docking/AppTab_Foreground", FMargin(24.0f/64.0f, 4/32.0f) ) ) .SetHoveredBrush( BOX_BRUSH( "/Docking/AppTab_Hovered", FMargin(24.0f/64.0f, 4/32.0f) ) ) .SetContentAreaBrush( BOX_BRUSH( "/Docking/AppTabContentArea", FMargin(4/16.0f) ) ) @@ -1198,6 +1198,8 @@ TSharedRef FCoreStyle::Create( const FName& InStyleSetName ) // Widget Reflector Window { Style->Set("WidgetReflector.TabIcon", new IMAGE_BRUSH("Icons/icon_tab_WidgetReflector_16x", Icon16x16)); + Style->Set("WidgetReflector.Icon", new IMAGE_BRUSH("Icons/icon_tab_WidgetReflector_40x", Icon40x40)); + Style->Set("WidgetReflector.Icon.Small", new IMAGE_BRUSH("Icons/icon_tab_WidgetReflector_40x", Icon20x20)); } // Message Log @@ -1211,16 +1213,6 @@ TSharedRef FCoreStyle::Create( const FName& InStyleSetName ) Style->Set("MessageLog.Note", new IMAGE_BRUSH("MessageLog/Log_Note", Icon16x16)); } - // Slate RHI Renderer - Crash Tracker - { - Style->Set( "CrashTracker", FTextBlockStyle(NormalText) - .SetFont(TTF_FONT("Fonts/Roboto-Bold", 18)) - .SetShadowOffset(FVector2D::ZeroVector)); - - Style->Set("CrashTracker.Cursor", new IMAGE_BRUSH("CrashTracker/MouseCursor", Icon32x32, FLinearColor(1.0f, 1.0f, 1.0f, 1.0f), ESlateBrushTileType::Both)); - Style->Set("CrashTracker.Record", new IMAGE_BRUSH("CrashTracker/Record", Icon20x20)); - } - // Wizard icons { Style->Set("Wizard.BackIcon", new IMAGE_BRUSH("Icons/BackIcon", Icon8x8)); diff --git a/Engine/Source/Runtime/SlateCore/Private/Textures/TextureAtlas.cpp b/Engine/Source/Runtime/SlateCore/Private/Textures/TextureAtlas.cpp index a3b191143236..1e990fa208e6 100644 --- a/Engine/Source/Runtime/SlateCore/Private/Textures/TextureAtlas.cpp +++ b/Engine/Source/Runtime/SlateCore/Private/Textures/TextureAtlas.cpp @@ -121,7 +121,7 @@ void FSlateTextureAtlas::InitAtlasData() check(AtlasOwnerThread != ESlateTextureAtlasThreadId::Unknown); INC_MEMORY_STAT_BY(STAT_SlateTextureAtlasMemory, AtlasData.GetAllocatedSize()); -} +} //-V773 void FSlateTextureAtlas::CopyRow( const FCopyRowData& CopyRowData ) diff --git a/Engine/Source/Runtime/SlateCore/Private/Widgets/SBoxPanel.cpp b/Engine/Source/Runtime/SlateCore/Private/Widgets/SBoxPanel.cpp index 2c7eb59538c6..c338a854a9d3 100644 --- a/Engine/Source/Runtime/SlateCore/Private/Widgets/SBoxPanel.cpp +++ b/Engine/Source/Runtime/SlateCore/Private/Widgets/SBoxPanel.cpp @@ -63,17 +63,18 @@ static void ArrangeChildrenAlong( const TPanelChildren& Childr } else { + FVector2D ChildDesiredSize = CurChild.GetWidget()->GetDesiredSize(); + // Auto-sized children contribute their desired size to the fixed space requirement - float ChildSize = (Orientation == Orient_Vertical) - ? CurChild.GetWidget()->GetDesiredSize().Y - : CurChild.GetWidget()->GetDesiredSize().X; + const float ChildSize = (Orientation == Orient_Vertical) + ? ChildDesiredSize.Y + : ChildDesiredSize.X; // Clamp to the max size if it was specified float MaxSize = CurChild.MaxSize.Get(); FixedTotal += MaxSize > 0 ? FMath::Min( MaxSize, ChildSize ) : ChildSize ; } } - } // The space available for SizeRule_Stretch widgets is any space that wasn't taken up by fixed-sized widgets. @@ -89,9 +90,7 @@ static void ArrangeChildrenAlong( const TPanelChildren& Childr { const SBoxPanel::FSlot& CurChild = Children[ChildIndex]; const EVisibility ChildVisibility = CurChild.GetWidget()->GetVisibility(); - - FVector2D ChildDesiredSize = CurChild.GetWidget()->GetDesiredSize(); - + // Figure out the area allocated to the child in the direction of BoxPanel // The area allocated to the slot is ChildSize + the associated margin. float ChildSize = 0; @@ -105,6 +104,8 @@ static void ArrangeChildrenAlong( const TPanelChildren& Childr } else { + FVector2D ChildDesiredSize = CurChild.GetWidget()->GetDesiredSize(); + // Auto-sized widgets get their desired-size value ChildSize = (Orientation == Orient_Vertical) ? ChildDesiredSize.Y diff --git a/Engine/Source/Runtime/SlateCore/Private/Widgets/SNullWidget.cpp b/Engine/Source/Runtime/SlateCore/Private/Widgets/SNullWidget.cpp index e63fe0c22f34..fdc6e5883b94 100644 --- a/Engine/Source/Runtime/SlateCore/Private/Widgets/SNullWidget.cpp +++ b/Engine/Source/Runtime/SlateCore/Private/Widgets/SNullWidget.cpp @@ -57,11 +57,6 @@ public: return LayerId; } - virtual FVector2D ComputeDesiredSize(float) const override final - { - return FVector2D(0.0f, 0.0f); - } - virtual FChildren* GetChildren( ) override final { return &NullWidgetNoChildren; @@ -73,6 +68,12 @@ public: // Nothing to arrange; Null Widgets do not have children. } +protected: + virtual FVector2D ComputeDesiredSize(float) const override final + { + return FVector2D(0.0f, 0.0f); + } + // End of SWidget interface }; diff --git a/Engine/Source/Runtime/SlateCore/Private/Widgets/SOverlay.cpp b/Engine/Source/Runtime/SlateCore/Private/Widgets/SOverlay.cpp index 79c511893c2b..766e7ee06dbb 100644 --- a/Engine/Source/Runtime/SlateCore/Private/Widgets/SOverlay.cpp +++ b/Engine/Source/Runtime/SlateCore/Private/Widgets/SOverlay.cpp @@ -36,7 +36,7 @@ void SOverlay::OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedCh ArrangedChildren.AddWidget( ChildVisibility, AllottedGeometry.MakeChild( CurChild.GetWidget(), - FVector2D(XResult.Offset,YResult.Offset), + FVector2D(XResult.Offset, YResult.Offset), FVector2D(XResult.Size, YResult.Size) ) ); } diff --git a/Engine/Source/Runtime/SlateCore/Private/Widgets/SWidget.cpp b/Engine/Source/Runtime/SlateCore/Private/Widgets/SWidget.cpp index 0dbdd0a385fa..db14aba373e1 100644 --- a/Engine/Source/Runtime/SlateCore/Private/Widgets/SWidget.cpp +++ b/Engine/Source/Runtime/SlateCore/Private/Widgets/SWidget.cpp @@ -92,13 +92,20 @@ SWidget::SWidget() , bCachedVolatile(false) , bInheritedVolatility(false) , DesiredSize(FVector2D::ZeroVector) - , EnabledState( true ) - , Visibility( EVisibility::Visible ) - , RenderTransform( ) - , RenderTransformPivot( FVector2D::ZeroVector ) +#if SLATE_DEFERRED_DESIRED_SIZE + , DesiredSizeScaleMultiplier(0.0f) +#endif + , EnabledState(true) + , Visibility(EVisibility::Visible) + , RenderTransform() + , RenderTransformPivot(FVector2D::ZeroVector) +#if SLATE_DEFERRED_DESIRED_SIZE + , bCachedDesiredSize(false) + , bUpdatingDesiredSize(false) +#endif , Cursor( TOptional() ) , ToolTip() - , LayoutCache(nullptr) + , LayoutCache(nullptr) { if (GIsRunning) { @@ -447,7 +454,7 @@ void SWidget::SlatePrepass(float LayoutScaleMultiplier) //SLATE_CYCLE_COUNTER_SCOPE_CUSTOM_DETAILED(SLATE_STATS_DETAIL_LEVEL_MED, GSlatePrepass, GetType()); // TODO Figure out a better way than to just reset the pointer. This causes problems when we prepass - // volatile widgets, who still need to know about their invalidation panel incase they vanish themselves. + // volatile widgets, who still need to know about their invalidation panel in case they vanish themselves. // Reset the layout cache object each pre-pass to ensure we never access a stale layout cache object // as this widget could have been moved in and out of a panel that was invalidated between frames. @@ -458,7 +465,7 @@ void SWidget::SlatePrepass(float LayoutScaleMultiplier) // Cache child desired sizes first. This widget's desired size is // a function of its children's sizes. FChildren* MyChildren = this->GetChildren(); - int32 NumChildren = MyChildren->Num(); + const int32 NumChildren = MyChildren->Num(); for ( int32 ChildIndex=0; ChildIndex < NumChildren; ++ChildIndex ) { const TSharedRef& Child = MyChildren->GetChildAt(ChildIndex); @@ -472,14 +479,19 @@ void SWidget::SlatePrepass(float LayoutScaleMultiplier) } } +#if SLATE_DEFERRED_DESIRED_SIZE + // Invalidate this widget's desired size. + InvalidateDesiredSize(LayoutScaleMultiplier); +#else // Cache this widget's desired size. CacheDesiredSize(LayoutScaleMultiplier); +#endif } void SWidget::CacheDesiredSize(float LayoutScaleMultiplier) { // Cache this widget's desired size. - this->Advanced_SetDesiredSize(this->ComputeDesiredSize(LayoutScaleMultiplier)); + Advanced_SetDesiredSize(ComputeDesiredSize(LayoutScaleMultiplier)); } void SWidget::CachePrepass(const TWeakPtr& InLayoutCache) @@ -487,7 +499,7 @@ void SWidget::CachePrepass(const TWeakPtr& InLayoutCache) if ( bCanHaveChildren ) { FChildren* MyChildren = this->GetChildren(); - int32 NumChildren = MyChildren->Num(); + const int32 NumChildren = MyChildren->Num(); for ( int32 ChildIndex=0; ChildIndex < NumChildren; ++ChildIndex ) { const TSharedRef& Child = MyChildren->GetChildAt(ChildIndex); @@ -775,6 +787,7 @@ int32 SWidget::Paint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, // Paint the geometry of this widget. int32 NewLayerID = OnPaint(UpdatedArgs, AllottedGeometry, MyClippingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled); +#if PLATFORM_UI_NEEDS_FOCUS_OUTLINES // Check if we need to show the keyboard focus ring, this is only necessary if the widget could be focused. if ( bCanSupportFocus && SupportsKeyboardFocus() ) { @@ -797,6 +810,7 @@ int32 SWidget::Paint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, } } } +#endif if ( OutDrawElements.ShouldResolveDeferred() ) { diff --git a/Engine/Source/Runtime/SlateCore/Private/Widgets/SWindow.cpp b/Engine/Source/Runtime/SlateCore/Private/Widgets/SWindow.cpp index 5a0ca9bed7d5..afffd2af4fdf 100644 --- a/Engine/Source/Runtime/SlateCore/Private/Widgets/SWindow.cpp +++ b/Engine/Source/Runtime/SlateCore/Private/Widgets/SWindow.cpp @@ -796,6 +796,13 @@ FMargin SWindow::GetWindowBorderSize( bool bIncTitleBar ) const return BorderSize; } + + return GetNonMaximizedWindowBorderSize(); +} + + +FMargin SWindow::GetNonMaximizedWindowBorderSize() const +{ #if PLATFORM_WINDOWS || PLATFORM_LINUX return LayoutBorder; #else diff --git a/Engine/Source/Runtime/SlateCore/Public/Application/SlateApplicationBase.h b/Engine/Source/Runtime/SlateCore/Public/Application/SlateApplicationBase.h index 3cc71b58ac96..f967019ae16d 100644 --- a/Engine/Source/Runtime/SlateCore/Public/Application/SlateApplicationBase.h +++ b/Engine/Source/Runtime/SlateCore/Public/Application/SlateApplicationBase.h @@ -73,6 +73,7 @@ class SLATECORE_API FSlateApplicationBase public: FSlateApplicationBase(); + virtual ~FSlateApplicationBase() { } /** * Whether the application is active. diff --git a/Engine/Source/Runtime/SlateCore/Public/Fonts/FontCache.h b/Engine/Source/Runtime/SlateCore/Public/Fonts/FontCache.h index 8d4279337088..96d32d89d6f2 100644 --- a/Engine/Source/Runtime/SlateCore/Public/Fonts/FontCache.h +++ b/Engine/Source/Runtime/SlateCore/Public/Fonts/FontCache.h @@ -180,6 +180,7 @@ public: return FontFace == Other.FontFace && FontSize == Other.FontSize && OutlineSize == Other.OutlineSize + && OutlineSizeSeparateFillAlpha == Other.OutlineSizeSeparateFillAlpha && FontScale == Other.FontScale && GlyphIndex == Other.GlyphIndex; } @@ -201,6 +202,8 @@ private: int32 FontSize; /** The size in pixels of the outline to render for the font */ float OutlineSize; + /** If checked, the outline will be completely translucent where the filled area will be. @see FFontOutlineSettings */ + bool OutlineSizeSeparateFillAlpha; /** Provides the final scale used to render to the font */ float FontScale; /** The index of this glyph in the FreeType face */ @@ -225,7 +228,7 @@ public: int32 TextLen; }; - FShapedGlyphSequence(TArray InGlyphsToRender, const int16 InTextBaseline, const uint16 InMaxTextHeight, const UObject* InFontMaterial, const struct FFontOutlineSettings& InOutlineSettings, const FSourceTextRange& InSourceTextRange); + FShapedGlyphSequence(TArray InGlyphsToRender, const int16 InTextBaseline, const uint16 InMaxTextHeight, const UObject* InFontMaterial, const FFontOutlineSettings& InOutlineSettings, const FSourceTextRange& InSourceTextRange); ~FShapedGlyphSequence(); /** Get the amount of memory allocated to this sequence */ diff --git a/Engine/Source/Runtime/SlateCore/Public/Fonts/FontTypes.h b/Engine/Source/Runtime/SlateCore/Public/Fonts/FontTypes.h index 7a005c49bb2b..01fd53064dea 100644 --- a/Engine/Source/Runtime/SlateCore/Public/Fonts/FontTypes.h +++ b/Engine/Source/Runtime/SlateCore/Public/Fonts/FontTypes.h @@ -15,7 +15,8 @@ public: , KeyHash( 0 ) { KeyHash = HashCombine(KeyHash, GetTypeHash(FontInfo)); - KeyHash = HashCombine(KeyHash, GetTypeHash(OutlineSettings)); + KeyHash = HashCombine(KeyHash, GetTypeHash(OutlineSettings.OutlineSize)); + KeyHash = HashCombine(KeyHash, GetTypeHash(OutlineSettings.bSeparateFillAlpha)); KeyHash = HashCombine(KeyHash, GetTypeHash(Scale)); } @@ -36,7 +37,10 @@ public: FORCEINLINE bool operator==(const FSlateFontKey& Other ) const { - return FontInfo == Other.FontInfo && OutlineSettings == Other.OutlineSettings && Scale == Other.Scale; + return FontInfo == Other.FontInfo + && OutlineSettings.OutlineSize == Other.OutlineSettings.OutlineSize + && OutlineSettings.bSeparateFillAlpha == Other.OutlineSettings.bSeparateFillAlpha + && Scale == Other.Scale; } FORCEINLINE bool operator!=(const FSlateFontKey& Other ) const diff --git a/Engine/Source/Runtime/SlateCore/Public/Fonts/SlateFontInfo.h b/Engine/Source/Runtime/SlateCore/Public/Fonts/SlateFontInfo.h index 5daf33891130..d47646ce7f3e 100644 --- a/Engine/Source/Runtime/SlateCore/Public/Fonts/SlateFontInfo.h +++ b/Engine/Source/Runtime/SlateCore/Public/Fonts/SlateFontInfo.h @@ -30,7 +30,7 @@ enum class EFontFallback : uint8 /** * Settings for applying an outline to a font */ -USTRUCT() +USTRUCT(BlueprintType) struct SLATECORE_API FFontOutlineSettings { GENERATED_USTRUCT_BODY() @@ -71,6 +71,8 @@ struct SLATECORE_API FFontOutlineSettings bool operator==(const FFontOutlineSettings& Other) const { return OutlineSize == Other.OutlineSize + && OutlineMaterial == Other.OutlineMaterial + && OutlineColor == Other.OutlineColor && bSeparateFillAlpha == Other.bSeparateFillAlpha; } @@ -78,6 +80,8 @@ struct SLATECORE_API FFontOutlineSettings { uint32 Hash = 0; Hash = HashCombine(Hash, GetTypeHash(OutlineSettings.OutlineSize)); + Hash = HashCombine(Hash, GetTypeHash(OutlineSettings.OutlineMaterial)); + Hash = HashCombine(Hash, GetTypeHash(OutlineSettings.OutlineColor)); Hash = HashCombine(Hash, GetTypeHash(OutlineSettings.bSeparateFillAlpha)); return Hash; } diff --git a/Engine/Source/Runtime/SlateCore/Public/Fonts/UnicodeBlockRange.h b/Engine/Source/Runtime/SlateCore/Public/Fonts/UnicodeBlockRange.h new file mode 100644 index 000000000000..d5b6bf7866e7 --- /dev/null +++ b/Engine/Source/Runtime/SlateCore/Public/Fonts/UnicodeBlockRange.h @@ -0,0 +1,33 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "ArrayView.h" + +/** Enumeration of pre-defined Unicode block ranges that can be used to access entries from FUnicodeBlockRange */ +enum class EUnicodeBlockRange : uint8 +{ +#define REGISTER_UNICODE_BLOCK_RANGE(LOWERBOUND, UPPERBOUND, SYMBOLNAME, DISPLAYNAME) SYMBOLNAME, +#include "UnicodeBlockRange.inl" +#undef REGISTER_UNICODE_BLOCK_RANGE +}; + +/** Pre-defined Unicode block ranges that can be used with the character ranges in sub-fonts */ +struct SLATECORE_API FUnicodeBlockRange +{ + /** Index enum of this block */ + EUnicodeBlockRange Index; + + /** Display name of this block */ + FText DisplayName; + + /** Range of this block */ + FInt32Range Range; + + /** Returns an array containing all of the pre-defined block ranges */ + static TArrayView GetUnicodeBlockRanges(); + + /** Returns the block corresponding to the given enum */ + static FUnicodeBlockRange GetUnicodeBlockRange(const EUnicodeBlockRange InBlockIndex); +}; diff --git a/Engine/Source/Runtime/SlateCore/Public/Fonts/UnicodeBlockRange.inl b/Engine/Source/Runtime/SlateCore/Public/Fonts/UnicodeBlockRange.inl new file mode 100644 index 000000000000..9e7ac8333692 --- /dev/null +++ b/Engine/Source/Runtime/SlateCore/Public/Fonts/UnicodeBlockRange.inl @@ -0,0 +1,129 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +// XMacro header +// #define REGISTER_UNICODE_BLOCK_RANGE(LOWERBOUND, UPPERBOUND, SYMBOLNAME, DISPLAYNAME) before including this header + +REGISTER_UNICODE_BLOCK_RANGE(0x0020, 0x007f, BasicLatin, NSLOCTEXT("UnicodeBlock", "BasicLatin", "Basic Latin")) +REGISTER_UNICODE_BLOCK_RANGE(0x00a0, 0x00ff, Latin1Supplement, NSLOCTEXT("UnicodeBlock", "Latin1Supplement", "Latin - 1 Supplement")) +REGISTER_UNICODE_BLOCK_RANGE(0x0100, 0x017f, LatinExtendedA, NSLOCTEXT("UnicodeBlock", "LatinExtendedA", "Latin Extended - A")) +REGISTER_UNICODE_BLOCK_RANGE(0x0180, 0x024f, LatinExtendedB, NSLOCTEXT("UnicodeBlock", "LatinExtendedB", "Latin Extended - B")) +REGISTER_UNICODE_BLOCK_RANGE(0x0250, 0x02af, IPAExtensions, NSLOCTEXT("UnicodeBlock", "IPAExtensions", "IPA Extensions")) +REGISTER_UNICODE_BLOCK_RANGE(0x02b0, 0x02ff, SpacingModifierLetters, NSLOCTEXT("UnicodeBlock", "SpacingModifierLetters", "Spacing Modifier Letters")) +REGISTER_UNICODE_BLOCK_RANGE(0x0300, 0x036f, CombiningDiacriticalMarks, NSLOCTEXT("UnicodeBlock", "CombiningDiacriticalMarks", "Combining Diacritical Marks")) +REGISTER_UNICODE_BLOCK_RANGE(0x0370, 0x03ff, GreekAndCoptic, NSLOCTEXT("UnicodeBlock", "GreekAndCoptic", "Greek and Coptic")) +REGISTER_UNICODE_BLOCK_RANGE(0x0400, 0x04ff, Cyrillic, NSLOCTEXT("UnicodeBlock", "Cyrillic", "Cyrillic")) +REGISTER_UNICODE_BLOCK_RANGE(0x0500, 0x052f, CyrillicSupplementary, NSLOCTEXT("UnicodeBlock", "CyrillicSupplementary", "Cyrillic Supplementary")) +REGISTER_UNICODE_BLOCK_RANGE(0x0530, 0x058f, Armenian, NSLOCTEXT("UnicodeBlock", "Armenian", "Armenian")) +REGISTER_UNICODE_BLOCK_RANGE(0x0590, 0x05ff, Hebrew, NSLOCTEXT("UnicodeBlock", "Hebrew", "Hebrew")) +REGISTER_UNICODE_BLOCK_RANGE(0x0600, 0x06ff, Arabic, NSLOCTEXT("UnicodeBlock", "Arabic", "Arabic")) +REGISTER_UNICODE_BLOCK_RANGE(0x0700, 0x074f, Syriac, NSLOCTEXT("UnicodeBlock", "Syriac", "Syriac")) +REGISTER_UNICODE_BLOCK_RANGE(0x0780, 0x07bf, Thaana, NSLOCTEXT("UnicodeBlock", "Thaana", "Thaana")) +REGISTER_UNICODE_BLOCK_RANGE(0x0900, 0x097f, Devanagari, NSLOCTEXT("UnicodeBlock", "Devanagari", "Devanagari")) +REGISTER_UNICODE_BLOCK_RANGE(0x0980, 0x09ff, Bengali, NSLOCTEXT("UnicodeBlock", "Bengali", "Bengali")) +REGISTER_UNICODE_BLOCK_RANGE(0x0a00, 0x0a7f, Gurmukhi, NSLOCTEXT("UnicodeBlock", "Gurmukhi", "Gurmukhi")) +REGISTER_UNICODE_BLOCK_RANGE(0x0a80, 0x0aff, Gujarati, NSLOCTEXT("UnicodeBlock", "Gujarati", "Gujarati")) +REGISTER_UNICODE_BLOCK_RANGE(0x0b00, 0x0b7f, Oriya, NSLOCTEXT("UnicodeBlock", "Oriya", "Oriya")) +REGISTER_UNICODE_BLOCK_RANGE(0x0b80, 0x0bff, Tamil, NSLOCTEXT("UnicodeBlock", "Tamil", "Tamil")) +REGISTER_UNICODE_BLOCK_RANGE(0x0c00, 0x0c7f, Telugu, NSLOCTEXT("UnicodeBlock", "Telugu", "Telugu")) +REGISTER_UNICODE_BLOCK_RANGE(0x0c80, 0x0cff, Kannada, NSLOCTEXT("UnicodeBlock", "Kannada", "Kannada")) +REGISTER_UNICODE_BLOCK_RANGE(0x0d00, 0x0d7f, Malayalam, NSLOCTEXT("UnicodeBlock", "Malayalam", "Malayalam")) +REGISTER_UNICODE_BLOCK_RANGE(0x0d80, 0x0dff, Sinhala, NSLOCTEXT("UnicodeBlock", "Sinhala", "Sinhala")) +REGISTER_UNICODE_BLOCK_RANGE(0x0e00, 0x0e7f, Thai, NSLOCTEXT("UnicodeBlock", "Thai", "Thai")) +REGISTER_UNICODE_BLOCK_RANGE(0x0e80, 0x0eff, Lao, NSLOCTEXT("UnicodeBlock", "Lao", "Lao")) +REGISTER_UNICODE_BLOCK_RANGE(0x0f00, 0x0fff, Tibetan, NSLOCTEXT("UnicodeBlock", "Tibetan", "Tibetan")) +REGISTER_UNICODE_BLOCK_RANGE(0x1000, 0x109f, Myanmar, NSLOCTEXT("UnicodeBlock", "Myanmar", "Myanmar")) +REGISTER_UNICODE_BLOCK_RANGE(0x10a0, 0x10ff, Georgian, NSLOCTEXT("UnicodeBlock", "Georgian", "Georgian")) +REGISTER_UNICODE_BLOCK_RANGE(0x1100, 0x11ff, HangulJamo, NSLOCTEXT("UnicodeBlock", "HangulJamo", "Hangul Jamo")) +REGISTER_UNICODE_BLOCK_RANGE(0x1200, 0x137f, Ethiopic, NSLOCTEXT("UnicodeBlock", "Ethiopic", "Ethiopic")) +REGISTER_UNICODE_BLOCK_RANGE(0x13a0, 0x13ff, Cherokee, NSLOCTEXT("UnicodeBlock", "Cherokee", "Cherokee")) +REGISTER_UNICODE_BLOCK_RANGE(0x1400, 0x167f, UnifiedCanadianAboriginalSyllabics, NSLOCTEXT("UnicodeBlock", "UnifiedCanadianAboriginalSyllabics", "Unified Canadian Aboriginal Syllabics")) +REGISTER_UNICODE_BLOCK_RANGE(0x1680, 0x169f, Ogham, NSLOCTEXT("UnicodeBlock", "Ogham", "Ogham")) +REGISTER_UNICODE_BLOCK_RANGE(0x16a0, 0x16ff, Runic, NSLOCTEXT("UnicodeBlock", "Runic", "Runic")) +REGISTER_UNICODE_BLOCK_RANGE(0x1700, 0x171f, Tagalog, NSLOCTEXT("UnicodeBlock", "Tagalog", "Tagalog")) +REGISTER_UNICODE_BLOCK_RANGE(0x1720, 0x173f, Hanunoo, NSLOCTEXT("UnicodeBlock", "Hanunoo", "Hanunoo")) +REGISTER_UNICODE_BLOCK_RANGE(0x1740, 0x175f, Buhid, NSLOCTEXT("UnicodeBlock", "Buhid", "Buhid")) +REGISTER_UNICODE_BLOCK_RANGE(0x1760, 0x177f, Tagbanwa, NSLOCTEXT("UnicodeBlock", "Tagbanwa", "Tagbanwa")) +REGISTER_UNICODE_BLOCK_RANGE(0x1780, 0x17ff, Khmer, NSLOCTEXT("UnicodeBlock", "Khmer", "Khmer")) +REGISTER_UNICODE_BLOCK_RANGE(0x1800, 0x18af, Mongolian, NSLOCTEXT("UnicodeBlock", "Mongolian", "Mongolian")) +REGISTER_UNICODE_BLOCK_RANGE(0x1900, 0x194f, Limbu, NSLOCTEXT("UnicodeBlock", "Limbu", "Limbu")) +REGISTER_UNICODE_BLOCK_RANGE(0x1950, 0x197f, TaiLe, NSLOCTEXT("UnicodeBlock", "TaiLe", "Tai Le")) +REGISTER_UNICODE_BLOCK_RANGE(0x19e0, 0x19ff, KhmerSymbols, NSLOCTEXT("UnicodeBlock", "KhmerSymbols", "Khmer Symbols")) +REGISTER_UNICODE_BLOCK_RANGE(0x1d00, 0x1d7f, PhoneticExtensions, NSLOCTEXT("UnicodeBlock", "PhoneticExtensions", "Phonetic Extensions")) +REGISTER_UNICODE_BLOCK_RANGE(0x1e00, 0x1eff, LatinExtendedAdditional, NSLOCTEXT("UnicodeBlock", "LatinExtendedAdditional", "Latin Extended Additional")) +REGISTER_UNICODE_BLOCK_RANGE(0x1f00, 0x1fff, GreekExtended, NSLOCTEXT("UnicodeBlock", "GreekExtended", "Greek Extended")) +REGISTER_UNICODE_BLOCK_RANGE(0x2000, 0x206f, GeneralPunctuation, NSLOCTEXT("UnicodeBlock", "GeneralPunctuation", "General Punctuation")) +REGISTER_UNICODE_BLOCK_RANGE(0x2070, 0x209f, SuperscriptsAndSubscripts, NSLOCTEXT("UnicodeBlock", "SuperscriptsAndSubscripts", "Superscripts and Subscripts")) +REGISTER_UNICODE_BLOCK_RANGE(0x20a0, 0x20cf, CurrencySymbols, NSLOCTEXT("UnicodeBlock", "CurrencySymbols", "Currency Symbols")) +REGISTER_UNICODE_BLOCK_RANGE(0x20d0, 0x20ff, CombiningDiacriticalMarksForSymbols, NSLOCTEXT("UnicodeBlock", "CombiningDiacriticalMarksForSymbols", "Combining Diacritical Marks for Symbols")) +REGISTER_UNICODE_BLOCK_RANGE(0x2100, 0x214f, LetterlikeSymbols, NSLOCTEXT("UnicodeBlock", "LetterlikeSymbols", "Letterlike Symbols")) +REGISTER_UNICODE_BLOCK_RANGE(0x2150, 0x218f, NumberForms, NSLOCTEXT("UnicodeBlock", "NumberForms", "Number Forms")) +REGISTER_UNICODE_BLOCK_RANGE(0x2190, 0x21ff, Arrows, NSLOCTEXT("UnicodeBlock", "Arrows", "Arrows")) +REGISTER_UNICODE_BLOCK_RANGE(0x2200, 0x22ff, MathematicalOperators, NSLOCTEXT("UnicodeBlock", "MathematicalOperators", "Mathematical Operators")) +REGISTER_UNICODE_BLOCK_RANGE(0x2300, 0x23ff, MiscellaneousTechnical, NSLOCTEXT("UnicodeBlock", "MiscellaneousTechnical", "Miscellaneous Technical")) +REGISTER_UNICODE_BLOCK_RANGE(0x2400, 0x243f, ControlPictures, NSLOCTEXT("UnicodeBlock", "ControlPictures", "Control Pictures")) +REGISTER_UNICODE_BLOCK_RANGE(0x2440, 0x245f, OpticalCharacterRecognition, NSLOCTEXT("UnicodeBlock", "OpticalCharacterRecognition", "Optical Character Recognition")) +REGISTER_UNICODE_BLOCK_RANGE(0x2460, 0x24ff, EnclosedAlphanumerics, NSLOCTEXT("UnicodeBlock", "EnclosedAlphanumerics", "Enclosed Alphanumerics")) +REGISTER_UNICODE_BLOCK_RANGE(0x2500, 0x257f, BoxDrawing, NSLOCTEXT("UnicodeBlock", "BoxDrawing", "Box Drawing")) +REGISTER_UNICODE_BLOCK_RANGE(0x2580, 0x259f, BlockElements, NSLOCTEXT("UnicodeBlock", "BlockElements", "Block Elements")) +REGISTER_UNICODE_BLOCK_RANGE(0x25a0, 0x25ff, GeometricShapes, NSLOCTEXT("UnicodeBlock", "GeometricShapes", "Geometric Shapes")) +REGISTER_UNICODE_BLOCK_RANGE(0x2600, 0x26ff, MiscellaneousSymbols, NSLOCTEXT("UnicodeBlock", "MiscellaneousSymbols", "Miscellaneous Symbols")) +REGISTER_UNICODE_BLOCK_RANGE(0x2700, 0x27bf, Dingbats, NSLOCTEXT("UnicodeBlock", "Dingbats", "Dingbats")) +REGISTER_UNICODE_BLOCK_RANGE(0x27c0, 0x27ef, MiscellaneousMathematicalSymbolsA, NSLOCTEXT("UnicodeBlock", "MiscellaneousMathematicalSymbolsA", "Miscellaneous Mathematical Symbols - A")) +REGISTER_UNICODE_BLOCK_RANGE(0x27f0, 0x27ff, SupplementalArrowsA, NSLOCTEXT("UnicodeBlock", "SupplementalArrowsA", "Supplemental Arrows - A")) +REGISTER_UNICODE_BLOCK_RANGE(0x2800, 0x28ff, BraillePatterns, NSLOCTEXT("UnicodeBlock", "BraillePatterns", "Braille Patterns")) +REGISTER_UNICODE_BLOCK_RANGE(0x2900, 0x297f, SupplementalArrowsB, NSLOCTEXT("UnicodeBlock", "SupplementalArrowsB", "Supplemental Arrows - B")) +REGISTER_UNICODE_BLOCK_RANGE(0x2980, 0x29ff, MiscellaneousMathematicalSymbolsB, NSLOCTEXT("UnicodeBlock", "MiscellaneousMathematicalSymbolsB", "Miscellaneous Mathematical Symbols - B")) +REGISTER_UNICODE_BLOCK_RANGE(0x2a00, 0x2aff, SupplementalMathematicalOperators, NSLOCTEXT("UnicodeBlock", "SupplementalMathematicalOperators", "Supplemental Mathematical Operators")) +REGISTER_UNICODE_BLOCK_RANGE(0x2b00, 0x2bff, MiscellaneousSymbolsAndArrows, NSLOCTEXT("UnicodeBlock", "MiscellaneousSymbolsAndArrows", "Miscellaneous Symbols and Arrows")) +REGISTER_UNICODE_BLOCK_RANGE(0x2e80, 0x2eff, CJKRadicalsSupplement, NSLOCTEXT("UnicodeBlock", "CJKRadicalsSupplement", "CJK Radicals Supplement")) +REGISTER_UNICODE_BLOCK_RANGE(0x2f00, 0x2fdf, KangxiRadicals, NSLOCTEXT("UnicodeBlock", "KangxiRadicals", "Kangxi Radicals")) +REGISTER_UNICODE_BLOCK_RANGE(0x2ff0, 0x2fff, IdeographicDescriptionCharacters, NSLOCTEXT("UnicodeBlock", "IdeographicDescriptionCharacters", "Ideographic Description Characters")) +REGISTER_UNICODE_BLOCK_RANGE(0x3000, 0x303f, CJKSymbolsAndPunctuation, NSLOCTEXT("UnicodeBlock", "CJKSymbolsAndPunctuation", "CJK Symbols and Punctuation")) +REGISTER_UNICODE_BLOCK_RANGE(0x3040, 0x309f, Hiragana, NSLOCTEXT("UnicodeBlock", "Hiragana", "Hiragana")) +REGISTER_UNICODE_BLOCK_RANGE(0x30a0, 0x30ff, Katakana, NSLOCTEXT("UnicodeBlock", "Katakana", "Katakana")) +REGISTER_UNICODE_BLOCK_RANGE(0x3100, 0x312f, Bopomofo, NSLOCTEXT("UnicodeBlock", "Bopomofo", "Bopomofo")) +REGISTER_UNICODE_BLOCK_RANGE(0x3130, 0x318f, HangulCompatibilityJamo, NSLOCTEXT("UnicodeBlock", "HangulCompatibilityJamo", "Hangul Compatibility Jamo")) +REGISTER_UNICODE_BLOCK_RANGE(0x3190, 0x319f, Kanbun, NSLOCTEXT("UnicodeBlock", "Kanbun", "Kanbun")) +REGISTER_UNICODE_BLOCK_RANGE(0x31a0, 0x31bf, BopomofoExtended, NSLOCTEXT("UnicodeBlock", "BopomofoExtended", "Bopomofo Extended")) +REGISTER_UNICODE_BLOCK_RANGE(0x31f0, 0x31ff, KatakanaPhoneticExtensions, NSLOCTEXT("UnicodeBlock", "KatakanaPhoneticExtensions", "Katakana Phonetic Extensions")) +REGISTER_UNICODE_BLOCK_RANGE(0x3200, 0x32ff, EnclosedCJKLettersAndMonths, NSLOCTEXT("UnicodeBlock", "EnclosedCJKLettersAndMonths", "Enclosed CJK Letters and Months")) +REGISTER_UNICODE_BLOCK_RANGE(0x3300, 0x33ff, CJKCompatibility, NSLOCTEXT("UnicodeBlock", "CJKCompatibility", "CJK Compatibility")) +REGISTER_UNICODE_BLOCK_RANGE(0x3400, 0x4dbf, CJKUnifiedIdeographsExtensionA, NSLOCTEXT("UnicodeBlock", "CJKUnifiedIdeographsExtensionA", "CJK Unified Ideographs Extension A")) +REGISTER_UNICODE_BLOCK_RANGE(0x4dc0, 0x4dff, YijingHexagramSymbols, NSLOCTEXT("UnicodeBlock", "YijingHexagramSymbols", "Yijing Hexagram Symbols")) +REGISTER_UNICODE_BLOCK_RANGE(0x4e00, 0x9fff, CJKUnifiedIdeographs, NSLOCTEXT("UnicodeBlock", "CJKUnifiedIdeographs", "CJK Unified Ideographs")) +REGISTER_UNICODE_BLOCK_RANGE(0xa000, 0xa48f, YiSyllables, NSLOCTEXT("UnicodeBlock", "YiSyllables", "Yi Syllables")) +REGISTER_UNICODE_BLOCK_RANGE(0xa490, 0xa4cf, YiRadicals, NSLOCTEXT("UnicodeBlock", "YiRadicals", "Yi Radicals")) +REGISTER_UNICODE_BLOCK_RANGE(0xac00, 0xd7af, HangulSyllables, NSLOCTEXT("UnicodeBlock", "HangulSyllables", "Hangul Syllables")) +REGISTER_UNICODE_BLOCK_RANGE(0xd800, 0xdb7f, HighSurrogates, NSLOCTEXT("UnicodeBlock", "HighSurrogates", "High Surrogates")) +REGISTER_UNICODE_BLOCK_RANGE(0xdb80, 0xdbff, HighPrivateUseSurrogates, NSLOCTEXT("UnicodeBlock", "HighPrivateUseSurrogates", "High Private Use Surrogates")) +REGISTER_UNICODE_BLOCK_RANGE(0xdc00, 0xdfff, LowSurrogates, NSLOCTEXT("UnicodeBlock", "LowSurrogates", "Low Surrogates")) +REGISTER_UNICODE_BLOCK_RANGE(0xe000, 0xf8ff, PrivateUseArea, NSLOCTEXT("UnicodeBlock", "PrivateUseArea", "Private Use Area")) +REGISTER_UNICODE_BLOCK_RANGE(0xf900, 0xfaff, CJKCompatibilityIdeographs, NSLOCTEXT("UnicodeBlock", "CJKCompatibilityIdeographs", "CJK Compatibility Ideographs")) +REGISTER_UNICODE_BLOCK_RANGE(0xfb00, 0xfb4f, AlphabeticPresentationForms, NSLOCTEXT("UnicodeBlock", "AlphabeticPresentationForms", "Alphabetic Presentation Forms")) +REGISTER_UNICODE_BLOCK_RANGE(0xfb50, 0xfdff, ArabicPresentationFormsA, NSLOCTEXT("UnicodeBlock", "ArabicPresentationFormsA", "Arabic Presentation Forms - A")) +REGISTER_UNICODE_BLOCK_RANGE(0xfe00, 0xfe0f, VariationSelectors, NSLOCTEXT("UnicodeBlock", "VariationSelectors", "Variation Selectors")) +REGISTER_UNICODE_BLOCK_RANGE(0xfe20, 0xfe2f, CombiningHalfMarks, NSLOCTEXT("UnicodeBlock", "CombiningHalfMarks", "Combining Half Marks")) +REGISTER_UNICODE_BLOCK_RANGE(0xfe30, 0xfe4f, CJKCompatibilityForms, NSLOCTEXT("UnicodeBlock", "CJKCompatibilityForms", "CJK Compatibility Forms")) +REGISTER_UNICODE_BLOCK_RANGE(0xfe50, 0xfe6f, SmallFormVariants, NSLOCTEXT("UnicodeBlock", "SmallFormVariants", "Small Form Variants")) +REGISTER_UNICODE_BLOCK_RANGE(0xfe70, 0xfeff, ArabicPresentationFormsB, NSLOCTEXT("UnicodeBlock", "ArabicPresentationFormsB", "Arabic Presentation Forms - B")) +REGISTER_UNICODE_BLOCK_RANGE(0xff00, 0xffef, HalfwidthAndFullwidthForms, NSLOCTEXT("UnicodeBlock", "HalfwidthAndFullwidthForms", "Halfwidth and Fullwidth Forms")) +REGISTER_UNICODE_BLOCK_RANGE(0xfff0, 0xffff, Specials, NSLOCTEXT("UnicodeBlock", "Specials", "Specials")) + +// The following are outside the Basic Multilingual Plane, and cannot currently be supported by UE4 on all platforms +//REGISTER_UNICODE_BLOCK_RANGE(0x10000, 0x1007f, LinearBSyllabary, NSLOCTEXT("UnicodeBlock", "LinearBSyllabary", "Linear B Syllabary")) +//REGISTER_UNICODE_BLOCK_RANGE(0x10080, 0x100ff, LinearBIdeograms, NSLOCTEXT("UnicodeBlock", "LinearBIdeograms", "Linear B Ideograms")) +//REGISTER_UNICODE_BLOCK_RANGE(0x10100, 0x1013f, AegeanNumbers, NSLOCTEXT("UnicodeBlock", "AegeanNumbers", "Aegean Numbers")) +//REGISTER_UNICODE_BLOCK_RANGE(0x10300, 0x1032f, OldItalic, NSLOCTEXT("UnicodeBlock", "OldItalic", "Old Italic")) +//REGISTER_UNICODE_BLOCK_RANGE(0x10330, 0x1034f, Gothic, NSLOCTEXT("UnicodeBlock", "Gothic", "Gothic")) +//REGISTER_UNICODE_BLOCK_RANGE(0x10380, 0x1039f, Ugaritic, NSLOCTEXT("UnicodeBlock", "Ugaritic", "Ugaritic")) +//REGISTER_UNICODE_BLOCK_RANGE(0x10400, 0x1044f, Deseret, NSLOCTEXT("UnicodeBlock", "Deseret", "Deseret")) +//REGISTER_UNICODE_BLOCK_RANGE(0x10450, 0x1047f, Shavian, NSLOCTEXT("UnicodeBlock", "Shavian", "Shavian")) +//REGISTER_UNICODE_BLOCK_RANGE(0x10480, 0x104af, Osmanya, NSLOCTEXT("UnicodeBlock", "Osmanya", "Osmanya")) +//REGISTER_UNICODE_BLOCK_RANGE(0x10800, 0x1083f, CypriotSyllabary, NSLOCTEXT("UnicodeBlock", "CypriotSyllabary", "Cypriot Syllabary")) +//REGISTER_UNICODE_BLOCK_RANGE(0x1d000, 0x1d0ff, ByzantineMusicalSymbols, NSLOCTEXT("UnicodeBlock", "ByzantineMusicalSymbols", "Byzantine Musical Symbols")) +//REGISTER_UNICODE_BLOCK_RANGE(0x1d100, 0x1d1ff, MusicalSymbols, NSLOCTEXT("UnicodeBlock", "MusicalSymbols", "Musical Symbols")) +//REGISTER_UNICODE_BLOCK_RANGE(0x1d300, 0x1d35f, TaiXuanJingSymbols, NSLOCTEXT("UnicodeBlock", "TaiXuanJingSymbols", "Tai Xuan Jing Symbols")) +//REGISTER_UNICODE_BLOCK_RANGE(0x1d400, 0x1d7ff, MathematicalAlphanumericSymbols, NSLOCTEXT("UnicodeBlock", "MathematicalAlphanumericSymbols", "Mathematical Alphanumeric Symbols")) +//REGISTER_UNICODE_BLOCK_RANGE(0x20000, 0x2a6df, CJKUnifiedIdeographsExtensionB, NSLOCTEXT("UnicodeBlock", "CJKUnifiedIdeographsExtensionB", "CJK Unified Ideographs Extension B")) +//REGISTER_UNICODE_BLOCK_RANGE(0x2f800, 0x2fa1f, CJKCompatibilityIdeographsSupplement, NSLOCTEXT("UnicodeBlock", "CJKCompatibilityIdeographsSupplement", "CJK Compatibility Ideographs Supplement")) +//REGISTER_UNICODE_BLOCK_RANGE(0xe0000, 0xe007f, Tags, NSLOCTEXT("UnicodeBlock", "Tags", "Tags")) diff --git a/Engine/Source/Runtime/SlateCore/Public/Input/Events.h b/Engine/Source/Runtime/SlateCore/Public/Input/Events.h index 23e0acb41fcb..277523350e5d 100644 --- a/Engine/Source/Runtime/SlateCore/Public/Input/Events.h +++ b/Engine/Source/Runtime/SlateCore/Public/Input/Events.h @@ -59,7 +59,7 @@ namespace EKeyboardFocusCause * FFocusEvent is used when notifying widgets about keyboard focus changes * It is passed to event handlers dealing with keyboard focus */ -USTRUCT() +USTRUCT(BlueprintType) struct FFocusEvent { GENERATED_USTRUCT_BODY() @@ -461,23 +461,6 @@ struct TStructOpsTypeTraits : public TStructOpsTypeTraitsBase2 : public TStructOpsTypeTraitsBase /** * FCharacterEvent describes a keyboard action where the utf-16 code is given. Used for OnKeyChar messages */ -USTRUCT() +USTRUCT(BlueprintType) struct FCharacterEvent : public FInputEvent { diff --git a/Engine/Source/Runtime/SlateCore/Public/Layout/ArrangedChildren.h b/Engine/Source/Runtime/SlateCore/Public/Layout/ArrangedChildren.h index f4d6ee06a1b1..19377f81311f 100644 --- a/Engine/Source/Runtime/SlateCore/Public/Layout/ArrangedChildren.h +++ b/Engine/Source/Runtime/SlateCore/Public/Layout/ArrangedChildren.h @@ -19,7 +19,7 @@ class SLATECORE_API FArrangedChildren public: - typedef TArray> FArrangedWidgetArray; + typedef TArray> FArrangedWidgetArray; /** * Construct a new container for arranged children that only accepts children that match the VisibilityFilter. @@ -162,7 +162,7 @@ public: FORCEINLINE void Empty() { - Array.Empty(); + Array.Reset(); } FORCEINLINE bool IsValidIndex(int32 Index) diff --git a/Engine/Source/Runtime/SlateCore/Public/Layout/LayoutUtils.h b/Engine/Source/Runtime/SlateCore/Public/Layout/LayoutUtils.h index 5790b7e90f81..48912ddd09db 100644 --- a/Engine/Source/Runtime/SlateCore/Public/Layout/LayoutUtils.h +++ b/Engine/Source/Runtime/SlateCore/Public/Layout/LayoutUtils.h @@ -74,37 +74,62 @@ static AlignmentArrangeResult AlignChild(float AllottedSize, float ChildDesiredS const int32 Alignment = ArrangeUtils::GetChildAlignment::AsInt(ChildToArrange); - const float ChildSize = bClampToParent ? FMath::Min(ChildDesiredSize, AllottedSize - TotalMargin) : ChildDesiredSize; - switch ( Alignment ) { - default: case HAlign_Fill: - return AlignmentArrangeResult(MarginPre, ( AllottedSize - TotalMargin )*ContentScale); - break; + return AlignmentArrangeResult(MarginPre, ( AllottedSize - TotalMargin ) * ContentScale); + } + const float ChildSize = bClampToParent ? FMath::Min(ChildDesiredSize, AllottedSize - TotalMargin) : ChildDesiredSize; + + switch( Alignment ) + { case HAlign_Left: // same as Align_Top return AlignmentArrangeResult(MarginPre, ChildSize); - break; - case HAlign_Center: return AlignmentArrangeResult(( AllottedSize - ChildSize ) / 2.0f + MarginPre - MarginPost, ChildSize); - break; - case HAlign_Right: // same as Align_Bottom return AlignmentArrangeResult(AllottedSize - ChildSize - MarginPost, ChildSize); - break; } + + // Same as Fill + return AlignmentArrangeResult(MarginPre, ( AllottedSize - TotalMargin ) * ContentScale); } template static AlignmentArrangeResult AlignChild(float AllottedSize, const SlotType& ChildToArrange, const FMargin& SlotPadding, const float& ContentScale = 1.0f, bool bClampToParent = true) { - float ChildDesiredSize = ( Orientation == Orient_Horizontal ) + const FMargin& Margin = SlotPadding; + const float TotalMargin = Margin.GetTotalSpaceAlong(); + const float MarginPre = ( Orientation == Orient_Horizontal ) ? Margin.Left : Margin.Top; + const float MarginPost = ( Orientation == Orient_Horizontal ) ? Margin.Right : Margin.Bottom; + + const int32 Alignment = ArrangeUtils::GetChildAlignment::AsInt(ChildToArrange); + + switch ( Alignment ) + { + case HAlign_Fill: + return AlignmentArrangeResult(MarginPre, ( AllottedSize - TotalMargin ) * ContentScale); + } + + const float ChildDesiredSize = ( Orientation == Orient_Horizontal ) ? ( ChildToArrange.GetWidget()->GetDesiredSize().X * ContentScale ) : ( ChildToArrange.GetWidget()->GetDesiredSize().Y * ContentScale ); - return AlignChild(AllottedSize, ChildDesiredSize, ChildToArrange, SlotPadding, ContentScale, bClampToParent); + const float ChildSize = bClampToParent ? FMath::Min(ChildDesiredSize, AllottedSize - TotalMargin) : ChildDesiredSize; + + switch ( Alignment ) + { + case HAlign_Left: // same as Align_Top + return AlignmentArrangeResult(MarginPre, ChildSize); + case HAlign_Center: + return AlignmentArrangeResult(( AllottedSize - ChildSize ) / 2.0f + MarginPre - MarginPost, ChildSize); + case HAlign_Right: // same as Align_Bottom + return AlignmentArrangeResult(AllottedSize - ChildSize - MarginPost, ChildSize); + } + + // Same as Fill + return AlignmentArrangeResult(MarginPre, ( AllottedSize - TotalMargin ) * ContentScale); } diff --git a/Engine/Source/Runtime/SlateCore/Public/Layout/Margin.h b/Engine/Source/Runtime/SlateCore/Public/Layout/Margin.h index 797c32dd0dd2..affca176a547 100644 --- a/Engine/Source/Runtime/SlateCore/Public/Layout/Margin.h +++ b/Engine/Source/Runtime/SlateCore/Public/Layout/Margin.h @@ -47,11 +47,11 @@ public: { } /** Construct a Margin with uniform space on all sides */ - FMargin( float UnifromMargin ) - : Left(UnifromMargin) - , Top(UnifromMargin) - , Right(UnifromMargin) - , Bottom(UnifromMargin) + FMargin( float UniformMargin ) + : Left(UniformMargin) + , Top(UniformMargin) + , Right(UniformMargin) + , Bottom(UniformMargin) { } /** Construct a Margin where Horizontal describes Left and Right spacing while Vertical describes Top and Bottom spacing */ diff --git a/Engine/Source/Runtime/SlateCore/Public/Layout/SlateRect.h b/Engine/Source/Runtime/SlateCore/Public/Layout/SlateRect.h index 9e532e144f0b..edf533a2fa0a 100644 --- a/Engine/Source/Runtime/SlateCore/Public/Layout/SlateRect.h +++ b/Engine/Source/Runtime/SlateCore/Public/Layout/SlateRect.h @@ -172,6 +172,17 @@ public: return FSlateRect( FMath::Min( Left, Other.Left ), FMath::Min( Top, Other.Top ), FMath::Max( Right, Other.Right ), FMath::Max( Bottom, Other.Bottom ) ); } + /** + * Rounds the Left, Top, Right and Bottom fields and returns a new FSlateRect with rounded components. + */ + FSlateRect Round() const + { + return FSlateRect( + FMath::RoundToFloat(Left), + FMath::RoundToFloat(Top), + FMath::RoundToFloat(Right), + FMath::RoundToFloat(Bottom)); + } /** * Returns the rectangle that is the intersection of this rectangle and Other. diff --git a/Engine/Source/Runtime/SlateCore/Public/Layout/WidgetCaching.h b/Engine/Source/Runtime/SlateCore/Public/Layout/WidgetCaching.h index 90ba9f0f384a..3c39322a0e25 100644 --- a/Engine/Source/Runtime/SlateCore/Public/Layout/WidgetCaching.h +++ b/Engine/Source/Runtime/SlateCore/Public/Layout/WidgetCaching.h @@ -21,11 +21,11 @@ class SLATECORE_API FCachedWidgetNode public: void Initialize(const FPaintArgs& Args, TSharedRef InWidget, const FGeometry& InGeometry, const FSlateRect& InClippingRect); - void RecordHittestGeometry(FHittestGrid& Grid, int32 LastHittestIndex, int32 LayerId); + void RecordHittestGeometry(FHittestGrid& Grid, int32 LastHittestIndex, int32 LayerId, FVector2D DynamicOffset); public: - void RecordHittestGeometryInternal(FHittestGrid& Grid, int32 LastHittestIndex, int32 LayerId); + void RecordHittestGeometryInternal(FHittestGrid& Grid, int32 LastHittestIndex, int32 LayerId, FVector2D DynamicOffset); TArray< FCachedWidgetNode*, TInlineAllocator<4> > Children; diff --git a/Engine/Source/Runtime/SlateCore/Public/Layout/WidgetPath.h b/Engine/Source/Runtime/SlateCore/Public/Layout/WidgetPath.h index 0ad7fc9b0670..b45ce32ea45d 100644 --- a/Engine/Source/Runtime/SlateCore/Public/Layout/WidgetPath.h +++ b/Engine/Source/Runtime/SlateCore/Public/Layout/WidgetPath.h @@ -174,7 +174,6 @@ private: /** Identical to SearchForWidgetRecursively, but iterates in reverse order */ template static bool SearchForWidgetRecursively_Reverse( const MatchRuleType& MatchRule, const FArrangedWidget& InCandidate, FArrangedChildren& OutReversedPath, EVisibility VisibilityFilter = EVisibility::Visible ); - }; @@ -204,6 +203,13 @@ public: */ FWidgetPath ToWidgetPath( EInterruptedPathHandling::Type InterruptedPathHandling = EInterruptedPathHandling::Truncate, const FPointerEvent* PointerEvent = nullptr ) const; + /** + * Make a non-weak WidgetPath out of this WeakWidgetPath. Do this by computing all the relevant geometries and converting the weak pointers to TSharedPtr. + * + * @param InterruptedPathHandling Should interrupted paths result in a truncated path or an invalid path + */ + TSharedRef ToWidgetPathRef( EInterruptedPathHandling::Type InterruptedPathHandling = EInterruptedPathHandling::Truncate, const FPointerEvent* PointerEvent = nullptr ) const; + struct EPathResolutionResult { enum Result @@ -228,7 +234,7 @@ public: * * @return The widget path to the resulting widget */ - FWidgetPath ToNextFocusedPath(EUINavigation NavigationType); + FWidgetPath ToNextFocusedPath(EUINavigation NavigationType) const; /** * @param NavigationType Direction in which to move the focus (only for use with EUINavigation::Next and EUINavigation::Previous). @@ -237,7 +243,7 @@ public: * * @return The widget path to the resulting widget */ - FWidgetPath ToNextFocusedPath(EUINavigation NavigationType, const FNavigationReply& NavigationReply, const FArrangedWidget& RuleWidget); + FWidgetPath ToNextFocusedPath(EUINavigation NavigationType, const FNavigationReply& NavigationReply, const FArrangedWidget& RuleWidget) const; /** Get the last (leaf-most) widget in this path; assumes path is valid */ TWeakPtr< SWidget > GetLastWidget() const diff --git a/Engine/Source/Runtime/SlateCore/Public/Layout/WidgetPath.inl b/Engine/Source/Runtime/SlateCore/Public/Layout/WidgetPath.inl index 549d7208081f..b98e0766a137 100644 --- a/Engine/Source/Runtime/SlateCore/Public/Layout/WidgetPath.inl +++ b/Engine/Source/Runtime/SlateCore/Public/Layout/WidgetPath.inl @@ -7,7 +7,6 @@ class FArrangedWidget; class FWidgetPath; struct EVisibility; -// FWidgetPath functions that depend on classes defined after WidgetPath.h is included in Slate.h /** * Utility function to search recursively through a widget hierarchy for a specific widget diff --git a/Engine/Source/Runtime/SlateCore/Public/Rendering/DrawElements.h b/Engine/Source/Runtime/SlateCore/Public/Rendering/DrawElements.h index 47e1c17357d1..92119db11943 100644 --- a/Engine/Source/Runtime/SlateCore/Public/Rendering/DrawElements.h +++ b/Engine/Source/Runtime/SlateCore/Public/Rendering/DrawElements.h @@ -500,6 +500,7 @@ public: { return Inverse(FSlateLayoutTransform(Scale, Position)); } + /** * Update element cached position with an arbitrary offset @@ -1333,7 +1334,7 @@ public: template FORCEINLINE_DEBUGGABLE void* Alloc() { - return MemManager.Alloc(sizeof(T), ALIGNOF(T)); + return MemManager.Alloc(sizeof(T), alignof(T)); } FSlateBatchData& GetBatchData() { return BatchData; } diff --git a/Engine/Source/Runtime/SlateCore/Public/Rendering/RenderingCommon.h b/Engine/Source/Runtime/SlateCore/Public/Rendering/RenderingCommon.h index 93f2a8c92edb..c46108647016 100644 --- a/Engine/Source/Runtime/SlateCore/Public/Rendering/RenderingCommon.h +++ b/Engine/Source/Runtime/SlateCore/Public/Rendering/RenderingCommon.h @@ -358,6 +358,11 @@ struct FShortRect uint16 Bottom; }; +static FVector2D RoundToInt(const FVector2D& Vec) +{ + return FVector2D(FMath::RoundToInt(Vec.X), FMath::RoundToInt(Vec.Y)); +} + /** * Viewport implementation interface that is used by SViewport when it needs to draw and processes input. */ diff --git a/Engine/Source/Runtime/SlateCore/Public/Rendering/SlateRenderer.h b/Engine/Source/Runtime/SlateCore/Public/Rendering/SlateRenderer.h index 26eaa2a0aea2..e369cb5a8f16 100644 --- a/Engine/Source/Runtime/SlateCore/Public/Rendering/SlateRenderer.h +++ b/Engine/Source/Runtime/SlateCore/Public/Rendering/SlateRenderer.h @@ -412,16 +412,6 @@ public: */ virtual void ReleaseCachingResourcesFor(const ILayoutCache* Cacher); - /** - * You must call this before calling CopyWindowsToVirtualScreenBuffer(), to setup the render targets first. - * - * @param bPrimaryWorkAreaOnly True if we should capture only the primary monitor's work area, or false to capture the entire desktop spanning all monitors - * @param ScreenScaling How much to downscale the desktop size - * @param LiveStreamingService Optional pointer to a live streaming service this buffer needs to work with - * @return The virtual screen rectangle. The size of this rectangle will be the size of the render target buffer. - */ - virtual FIntRect SetupVirtualScreenBuffer( const bool bPrimaryWorkAreaOnly, const float ScreenScaling, class ILiveStreamingService* LiveStreamingService) { return FIntRect(); } - /** * Copies all slate windows out to a buffer at half resolution with debug information * like the mouse cursor and any keypresses. diff --git a/Engine/Source/Runtime/SlateCore/Public/SlateGlobals.h b/Engine/Source/Runtime/SlateCore/Public/SlateGlobals.h index 9f32cfbb337c..f96648ec4ff0 100644 --- a/Engine/Source/Runtime/SlateCore/Public/SlateGlobals.h +++ b/Engine/Source/Runtime/SlateCore/Public/SlateGlobals.h @@ -36,6 +36,10 @@ DECLARE_STATS_GROUP(TEXT("Slate"), STATGROUP_Slate, STATCAT_Advanced); DECLARE_STATS_GROUP_VERBOSE(TEXT("SlateVerbose"), STATGROUP_SlateVerbose, STATCAT_Advanced); DECLARE_STATS_GROUP_MAYBE_COMPILED_OUT(TEXT("SlateVeryVerbose"), STATGROUP_SlateVeryVerbose, STATCAT_Advanced, WITH_VERY_VERBOSE_SLATE_STATS); +// Compile slate with a deferred desired size calculation, rather than immediately calculating +// all desired sizes during prepass, only invalidate and wait for it to be requested. +//#define SLATE_DEFERRED_DESIRED_SIZE 0 + /* Forward declarations *****************************************************************************/ class FActiveTimerHandle; diff --git a/Engine/Source/Runtime/SlateCore/Public/Sound/SlateSound.h b/Engine/Source/Runtime/SlateCore/Public/Sound/SlateSound.h index cccc6856b57f..843c008bf9f6 100644 --- a/Engine/Source/Runtime/SlateCore/Public/Sound/SlateSound.h +++ b/Engine/Source/Runtime/SlateCore/Public/Sound/SlateSound.h @@ -11,7 +11,7 @@ /** * An intermediary to make UBaseSound available for Slate to play sounds */ -USTRUCT() +USTRUCT(BlueprintType) struct SLATECORE_API FSlateSound { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/SlateCore/Public/Styling/SlateColor.h b/Engine/Source/Runtime/SlateCore/Public/Styling/SlateColor.h index a3da7b80d6be..762d969f2386 100644 --- a/Engine/Source/Runtime/SlateCore/Public/Styling/SlateColor.h +++ b/Engine/Source/Runtime/SlateCore/Public/Styling/SlateColor.h @@ -74,6 +74,9 @@ public: , LinkedSpecifiedColor(InColor) { } + ~FSlateColor() + { } + public: /** diff --git a/Engine/Source/Runtime/SlateCore/Public/Types/ReflectionMetadata.h b/Engine/Source/Runtime/SlateCore/Public/Types/ReflectionMetadata.h index 128a8867e2c2..6f66fe7f6684 100644 --- a/Engine/Source/Runtime/SlateCore/Public/Types/ReflectionMetadata.h +++ b/Engine/Source/Runtime/SlateCore/Public/Types/ReflectionMetadata.h @@ -18,9 +18,10 @@ class FReflectionMetaData : public ISlateMetaData public: SLATE_METADATA_TYPE(FReflectionMetaData, ISlateMetaData) - FReflectionMetaData(FName InName, UClass* InClass, const UObject* InAsset) + FReflectionMetaData(FName InName, UClass* InClass, UObject* InSourceObject, const UObject* InAsset) : Name(InName) , Class(InClass) + , SourceObject(InSourceObject) , Asset(InAsset) { } @@ -31,6 +32,9 @@ public: /** The class the constructed the slate widget. */ TWeakObjectPtr Class; + /** The UObject wrapper that creates the widget, this is expected to be a UWidget. */ + TWeakObjectPtr SourceObject; + /** The asset that owns the widget and is responsible for its specific existence. */ TWeakObjectPtr Asset; diff --git a/Engine/Source/Runtime/SlateCore/Public/Widgets/SBoxPanel.h b/Engine/Source/Runtime/SlateCore/Public/Widgets/SBoxPanel.h index 955abdb73a67..1ae4d0684943 100644 --- a/Engine/Source/Runtime/SlateCore/Public/Widgets/SBoxPanel.h +++ b/Engine/Source/Runtime/SlateCore/Public/Widgets/SBoxPanel.h @@ -85,16 +85,15 @@ public: public: // Begin SWidget overrides. - - virtual void OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const; - - virtual FVector2D ComputeDesiredSize(float) const; - - virtual FChildren* GetChildren(); - + virtual void OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const override; + virtual FChildren* GetChildren() override; // End SWidget overrides. protected: + // Begin SWidget overrides. + virtual FVector2D ComputeDesiredSize(float) const override; + // End SWidget overrides. + /** * A Box Panel's orientation cannot be changed once it is constructed.. * @@ -138,12 +137,6 @@ public: SizeParam = FStretch( StretchCoefficient ); return *this; } - - DEPRECATED( 4.5, "AspectRatio() property is no longer supported; it did not behave correctly to begin with and was rarely used." ) - FSlot& AspectRatio() - { - return *this; - } FSlot& Padding( float Uniform ) { diff --git a/Engine/Source/Runtime/SlateCore/Public/Widgets/SCompoundWidget.h b/Engine/Source/Runtime/SlateCore/Public/Widgets/SCompoundWidget.h index 37f40ff6bce7..e54ef607ccef 100644 --- a/Engine/Source/Runtime/SlateCore/Public/Widgets/SCompoundWidget.h +++ b/Engine/Source/Runtime/SlateCore/Public/Widgets/SCompoundWidget.h @@ -72,16 +72,19 @@ public: public: // SWidgetOverrides - virtual int32 OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const override; virtual FChildren* GetChildren() override; - virtual FVector2D ComputeDesiredSize(float) const override; virtual void OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const override; virtual FSlateColor GetForegroundColor() const override; public: virtual void SetVisibility( TAttribute InVisibility ) override final; +protected: + // Begin SWidget overrides. + virtual FVector2D ComputeDesiredSize(float) const override; + // End SWidget overrides. + protected: /** Disallow public construction */ diff --git a/Engine/Source/Runtime/SlateCore/Public/Widgets/SOverlay.h b/Engine/Source/Runtime/SlateCore/Public/Widgets/SOverlay.h index 31447ea526df..06b7e26418cd 100644 --- a/Engine/Source/Runtime/SlateCore/Public/Widgets/SOverlay.h +++ b/Engine/Source/Runtime/SlateCore/Public/Widgets/SOverlay.h @@ -142,11 +142,15 @@ public: // SWidget interface virtual void OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const override; - virtual FVector2D ComputeDesiredSize(float) const override; virtual FChildren* GetChildren() override; virtual int32 OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const override; // End of SWidget interface +protected: + // Begin SWidget overrides. + virtual FVector2D ComputeDesiredSize(float) const override; + // End SWidget overrides. + protected: /** The SOverlay's slots; each slot contains a child widget. */ TPanelChildren Children; diff --git a/Engine/Source/Runtime/SlateCore/Public/Widgets/SWidget.h b/Engine/Source/Runtime/SlateCore/Public/Widgets/SWidget.h index 87985ab8cb7e..ed01a9822ede 100644 --- a/Engine/Source/Runtime/SlateCore/Public/Widgets/SWidget.h +++ b/Engine/Source/Runtime/SlateCore/Public/Widgets/SWidget.h @@ -622,9 +622,34 @@ public: */ void SlatePrepass(float LayoutScaleMultiplier); +#if SLATE_DEFERRED_DESIRED_SIZE + private: + FORCEINLINE void InvalidateDesiredSize(float LayoutScaleMultiplier) + { + bCachedDesiredSize = false; + DesiredSizeScaleMultiplier = LayoutScaleMultiplier; + } + public: /** @return the DesiredSize that was computed the last time CacheDesiredSize() was called. */ + FORCEINLINE const FVector2D& GetDesiredSize() const + { + if ( !bCachedDesiredSize && ensureMsgf(!bUpdatingDesiredSize, TEXT("The layout is cyclically dependent. A child widget can not ask the desired size of a parent while the parent is asking the desired size of its children.")) ) + { + bUpdatingDesiredSize = true; + + // Cache this widget's desired size. + const_cast(this)->CacheDesiredSize(DesiredSizeScaleMultiplier); + + bUpdatingDesiredSize = false; + } + + return DesiredSize; + } +#else + public: FORCEINLINE const FVector2D& GetDesiredSize() const { return DesiredSize; } +#endif /** * The system calls this method. It performs a breadth-first traversal of every visible widget and asks @@ -636,7 +661,13 @@ public: * Explicitly set the desired size. This is highly advanced functionality that is meant * to be used in conjunction with overriding CacheDesiredSize. Use ComputeDesiredSize() instead. */ - protected: void Advanced_SetDesiredSize(const FVector2D& InDesiredSize) { DesiredSize = InDesiredSize; } + protected: void Advanced_SetDesiredSize(const FVector2D& InDesiredSize) + { + DesiredSize = InDesiredSize; +#if SLATE_DEFERRED_DESIRED_SIZE + bCachedDesiredSize = true; +#endif + } /** * Compute the ideal size necessary to display this widget. For aggregate widgets (e.g. panels) this size should include the @@ -1276,6 +1307,10 @@ private: /** The list of active timer handles for this widget. */ TArray> ActiveTimers; +#if SLATE_DEFERRED_DESIRED_SIZE + float DesiredSizeScaleMultiplier; +#endif + protected: /** Whether or not this widget is enabled */ @@ -1291,6 +1326,13 @@ protected: TAttribute< FVector2D > RenderTransformPivot; protected: +#if SLATE_DEFERRED_DESIRED_SIZE + /** Has the desired size of the widget been cached? */ + bool bCachedDesiredSize : 1; + + /** Are we currently updating the desired size? */ + mutable bool bUpdatingDesiredSize : 1; +#endif /** Debugging information on the type of widget we're creating for the Widget Reflector. */ FName TypeOfWidget; diff --git a/Engine/Source/Runtime/SlateCore/Public/Widgets/SWindow.h b/Engine/Source/Runtime/SlateCore/Public/Widgets/SWindow.h index ccc75ee3da51..da5538236da9 100644 --- a/Engine/Source/Runtime/SlateCore/Public/Widgets/SWindow.h +++ b/Engine/Source/Runtime/SlateCore/Public/Widgets/SWindow.h @@ -376,6 +376,9 @@ public: /** Returns the margins used for the window border. This varies based on whether it's maximized or not. */ FMargin GetWindowBorderSize( bool bIncTitleBar = false ) const; + /** Returns the margins used for the window border if it's not maximized */ + FMargin GetNonMaximizedWindowBorderSize() const; + /** Relocate the window to a screenspace position specified by NewPosition */ void MoveWindowTo( FVector2D NewPosition ); /** Relocate the window to a screenspace position specified by NewPosition and resize it to NewSize */ diff --git a/Engine/Source/Runtime/SlateCore/SlateCore.Build.cs b/Engine/Source/Runtime/SlateCore/SlateCore.Build.cs index 3b0b99e5b547..edc2152fbbba 100644 --- a/Engine/Source/Runtime/SlateCore/SlateCore.Build.cs +++ b/Engine/Source/Runtime/SlateCore/SlateCore.Build.cs @@ -35,7 +35,9 @@ public class SlateCore : ModuleRules } ); - if (Target.Type != TargetType.Server) + Definitions.Add("SLATE_DEFERRED_DESIRED_SIZE=0"); + + if (Target.Type != TargetType.Server) { if (UEBuildConfiguration.bCompileFreeType) { diff --git a/Engine/Source/Runtime/SlateRHIRenderer/Private/Slate3DRenderer.h b/Engine/Source/Runtime/SlateRHIRenderer/Private/Slate3DRenderer.h index 984cc7072865..36d54150eff6 100644 --- a/Engine/Source/Runtime/SlateRHIRenderer/Private/Slate3DRenderer.h +++ b/Engine/Source/Runtime/SlateRHIRenderer/Private/Slate3DRenderer.h @@ -28,7 +28,7 @@ public: private: /** Double buffered draw buffers so that the rendering thread can be rendering windows while the game thread is setting up for next frame */ - static const int32 NUM_DRAW_BUFFERS = 3; + static const int32 NUM_DRAW_BUFFERS = 4; FSlateDrawBuffer DrawBuffers[NUM_DRAW_BUFFERS]; /** The font services to use for rendering text */ diff --git a/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateRHIRenderer.cpp b/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateRHIRenderer.cpp index fe98301d2100..a93d3d0acb05 100644 --- a/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateRHIRenderer.cpp +++ b/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateRHIRenderer.cpp @@ -19,16 +19,12 @@ #include "SlateShaders.h" #include "Rendering/ElementBatcher.h" #include "StereoRendering.h" -#include "Features/ILiveStreamingService.h" #include "SlateNativeTextureResource.h" #include "SceneUtils.h" #include "Runtime/Renderer/Public/VolumeRendering.h" #include "ShaderCompiler.h" #include "PipelineStateCache.h" -DECLARE_CYCLE_STAT(TEXT("Map Staging Buffer"),STAT_MapStagingBuffer,STATGROUP_CrashTracker); -DECLARE_CYCLE_STAT(TEXT("Generate Capture Buffer"),STAT_GenerateCaptureBuffer,STATGROUP_CrashTracker); -DECLARE_CYCLE_STAT(TEXT("Unmap Staging Buffer"),STAT_UnmapStagingBuffer,STATGROUP_CrashTracker); DECLARE_CYCLE_STAT(TEXT("Slate RT: Rendering"), STAT_SlateRenderingRTTime, STATGROUP_Slate); DECLARE_CYCLE_STAT(TEXT("Slate RT: Create Batches"), STAT_SlateRTCreateBatches, STATGROUP_Slate); @@ -60,53 +56,22 @@ static TAutoConsoleVariable CVarDrawToVRRenderTarget( TEXT("If enabled while in VR. Slate UI will be drawn into the render target texture where the VR imagery for either eye was rendered, allow the viewer of the HMD to see the UI (for better or worse.) This render target will then be cropped/scaled into the back buffer, if mirroring is enabled. When disabled, Slate UI will be drawn on top of the backbuffer (not to the HMD) after the mirror texture has been cropped/scaled into the backbuffer."), ECVF_RenderThreadSafe); +#if WITH_SLATE_VISUALIZERS -void FSlateCrashReportResource::InitDynamicRHI() -{ - int32 Width = VirtualScreen.Width(); - int32 Height = VirtualScreen.Height(); - - // @todo livestream: Ideally this "desktop background color" should be configurable in the editor's preferences - FRHIResourceCreateInfo CreateInfo = { FClearValueBinding(FLinearColor(0.8f, 0.00f, 0.0f)) }; - CrashReportBuffer = RHICreateTexture2D( - Width, - Height, - PF_R8G8B8A8, - 1, - 1, - TexCreate_RenderTargetable, - CreateInfo - ); - - for (int32 i = 0; i < 2; ++i) - { - ReadbackBuffer[i] = RHICreateTexture2D( - Width, - Height, - PF_R8G8B8A8, - 1, - 1, - TexCreate_CPUReadback, - CreateInfo - ); - } - - ReadbackBufferIndex = 0; -} - -void FSlateCrashReportResource::ReleaseDynamicRHI() -{ - ReadbackBuffer[0].SafeRelease(); - ReadbackBuffer[1].SafeRelease(); - CrashReportBuffer.SafeRelease(); -} - -FSlateWindowElementList* FSlateCrashReportResource::GetNextElementList() -{ - ElementListIndex = (ElementListIndex + 1) % 2; - return &ElementList[ElementListIndex]; -} +TAutoConsoleVariable CVarShowSlateOverdraw( + TEXT("Slate.ShowOverdraw"), + 0, + TEXT("0: Don't show overdraw, 1: Show Overdraw"), + ECVF_Default +); +TAutoConsoleVariable CVarShowSlateBatching( + TEXT("Slate.ShowBatching"), + 0, + TEXT("0: Don't show batching, 1: Show Batching"), + ECVF_Default +); +#endif void FSlateRHIRenderer::FViewportInfo::InitRHI() { @@ -160,7 +125,6 @@ FSlateRHIRenderer::FSlateRHIRenderer( TSharedRef InSlateFont { ResourceManager = InResourceManager; - CrashTrackerResource = NULL; ViewMatrix = FMatrix( FPlane(1, 0, 0, 0), FPlane(0, 1, 0, 0), FPlane(0, 0, 1, 0), @@ -216,13 +180,7 @@ void FSlateRHIRenderer::Destroy() { BeginReleaseResource( It.Value() ); } - -#if PLATFORM_WINDOWS || PLATFORM_MAC || PLATFORM_LINUX - if (CrashTrackerResource != nullptr) - { - BeginReleaseResource(CrashTrackerResource); - } -#endif + FlushRenderingCommands(); @@ -238,12 +196,6 @@ void FSlateRHIRenderer::Destroy() delete ViewportInfo; } - if (CrashTrackerResource != nullptr) - { - delete CrashTrackerResource; - CrashTrackerResource = nullptr; - } - WindowToViewportInfo.Empty(); CurrentSceneIndex = -1; ActiveScenes.Empty(); @@ -640,6 +592,8 @@ void FSlateRHIRenderer::DrawWindow_RenderThread(FRHICommandListImmediate& RHICmd // Should only be called by the rendering thread check(IsInRenderingThread()); + FMaterialRenderProxy::UpdateDeferredCachedUniformExpressions(); + // Optional off-screen UI composition during HDR rendering static const auto CVarCompositeMode = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.HDR.UI.CompositeMode")); static const auto CVarHDROutputEnabled = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.HDR.EnableHDROutput")); @@ -754,9 +708,23 @@ void FSlateRHIRenderer::DrawWindow_RenderThread(FRHICommandListImmediate& RHICmd SetRenderTarget(RHICmdList, BackBuffer, FTextureRHIRef(), bClear ? ESimpleRenderTargetMode::EClearColorAndDepth : ESimpleRenderTargetMode::EExistingColorAndDepth); } -#if DEBUG_OVERDRAW - DrawClearQuad(RHICmdList, GMaxRHIFeatureLevel, FLinearColor::Black); +#if WITH_SLATE_VISUALIZERS + if ( CVarShowSlateBatching.GetValueOnRenderThread() != 0 || CVarShowSlateOverdraw.GetValueOnRenderThread() != 0 ) + { + if (ViewportInfo.bRequiresStencilTest) + { + // Reset the backbuffer as our color render target and also set a depth stencil buffer + FRHIRenderTargetView ColorView(BackBuffer, 0, -1, ERenderTargetLoadAction::EClear, ERenderTargetStoreAction::EStore); + FRHISetRenderTargetsInfo Info(1, &ColorView, FRHIDepthRenderTargetView(ViewportInfo.DepthStencil, ERenderTargetLoadAction::ELoad, ERenderTargetStoreAction::EStore, ERenderTargetLoadAction::EClear, ERenderTargetStoreAction::EStore)); + RHICmdList.SetRenderTargetsAndClear(Info); + } + else + { + SetRenderTarget(RHICmdList, BackBuffer, FTextureRHIRef(), ESimpleRenderTargetMode::EClearColorAndDepth); + } + } #endif + if( BatchData.GetRenderBatches().Num() > 0 ) { SCOPE_CYCLE_COUNTER(STAT_SlateRTDrawBatches); @@ -1094,351 +1062,6 @@ void FSlateRHIRenderer::DrawWindows_Private( FSlateDrawBuffer& WindowDrawBuffer } -FIntRect FSlateRHIRenderer::SetupVirtualScreenBuffer(const bool bPrimaryWorkAreaOnly, const float ScreenScaling, ILiveStreamingService* LiveStreamingService ) -{ - // Figure out how big we need our render targets to be, based on the size of the entire desktop and the configured scaling amount - FDisplayMetrics DisplayMetrics; - FSlateApplication::Get().GetDisplayMetrics(DisplayMetrics); - -#if !PLATFORM_WINDOWS && !PLATFORM_MAC && !PLATFORM_LINUX - ensureMsgf(0, TEXT("This functionality is not valid for this platform")); - return FIntRect(FIntPoint(0, 0), FIntPoint(DisplayMetrics.PrimaryDisplayWidth, DisplayMetrics.PrimaryDisplayHeight)); -#endif - - FIntPoint UnscaledVirtualScreenOrigin; - FIntPoint UnscaledVirtualScreenLowerRight; - - if( bPrimaryWorkAreaOnly ) - { - UnscaledVirtualScreenOrigin = FIntPoint(DisplayMetrics.PrimaryDisplayWorkAreaRect.Left, DisplayMetrics.PrimaryDisplayWorkAreaRect.Top); - UnscaledVirtualScreenLowerRight = FIntPoint(DisplayMetrics.PrimaryDisplayWorkAreaRect.Right, DisplayMetrics.PrimaryDisplayWorkAreaRect.Bottom); - } - else - { - UnscaledVirtualScreenOrigin = FIntPoint(DisplayMetrics.VirtualDisplayRect.Left, DisplayMetrics.VirtualDisplayRect.Top); - UnscaledVirtualScreenLowerRight = FIntPoint(DisplayMetrics.VirtualDisplayRect.Right, DisplayMetrics.VirtualDisplayRect.Bottom); - } - const FIntRect UnscaledVirtualScreen = FIntRect(UnscaledVirtualScreenOrigin, UnscaledVirtualScreenLowerRight); - FIntRect ScaledVirtualScreen; - { - int BufferWidth = FMath::FloorToInt( (float)UnscaledVirtualScreen.Width() * ScreenScaling ); - int BufferHeight = FMath::FloorToInt( (float)UnscaledVirtualScreen.Height() * ScreenScaling ); - - // If we're preparing a buffer for live streaming, then go ahead and make sure the resolution will be valid for that - if( LiveStreamingService != nullptr ) - { - // @todo livestream: This could cause the aspect ratio to be changed and the buffer to be stretched non-uniformly, but usually the aspect only changes slightly - LiveStreamingService->MakeValidVideoBufferResolution( BufferWidth, BufferHeight ); - } - - const float XScaling = (float)BufferWidth / (float)UnscaledVirtualScreen.Width(); - const float YScaling = (float)BufferHeight / (float)UnscaledVirtualScreen.Height(); - - ScaledVirtualScreen.Min.X = FMath::FloorToInt(( float)UnscaledVirtualScreen.Min.X * XScaling ); - ScaledVirtualScreen.Max.X = FMath::FloorToInt(( float)UnscaledVirtualScreen.Max.X * XScaling ); - ScaledVirtualScreen.Min.Y = FMath::FloorToInt(( float)UnscaledVirtualScreen.Min.Y * YScaling ); - ScaledVirtualScreen.Max.Y = FMath::FloorToInt(( float)UnscaledVirtualScreen.Max.Y * YScaling ); - } - - // @todo livestream: This CrashTrackerResource is now also used for editor live streaming, so we should consider renaming it and cleaning - // up the API a little bit more - if( CrashTrackerResource == nullptr || - ScaledVirtualScreen != CrashTrackerResource->GetVirtualScreen() ) - { - if( CrashTrackerResource != nullptr ) - { - // Size has changed, so clear out our old resource and create a new one - BeginReleaseResource(CrashTrackerResource); - - FlushRenderingCommands(); - - if (CrashTrackerResource != nullptr) - { - delete CrashTrackerResource; - CrashTrackerResource = NULL; - } - } - - CrashTrackerResource = new FSlateCrashReportResource(ScaledVirtualScreen, UnscaledVirtualScreen); - BeginInitResource(CrashTrackerResource); - } - - return CrashTrackerResource->GetVirtualScreen(); -} - - -void FSlateRHIRenderer::CopyWindowsToVirtualScreenBuffer(const TArray& KeypressBuffer) -{ -#if !PLATFORM_WINDOWS && !PLATFORM_MAC && !PLATFORM_LINUX - ensureMsgf(0, TEXT("This functionality is not valid for this platform")); - return; -#endif - - SCOPE_CYCLE_COUNTER(STAT_GenerateCaptureBuffer); - - // Make sure to call SetupDrawBuffer() before calling this function! - check( CrashTrackerResource != nullptr ); - - const FIntRect VirtualScreen = CrashTrackerResource->GetVirtualScreen(); - const FIntPoint VirtualScreenPos = VirtualScreen.Min; - const FIntPoint VirtualScreenSize = VirtualScreen.Size(); - const FIntRect UnscaledVirtualScreen = CrashTrackerResource->GetUnscaledVirtualScreen(); - const float XScaling = (float)VirtualScreen.Width() / (float)UnscaledVirtualScreen.Width(); - const float YScaling = (float)VirtualScreen.Height() / (float)UnscaledVirtualScreen.Height(); - - // setup state - struct FSetupWindowStateContext - { - FSlateCrashReportResource* CrashReportResource; - FIntRect IntermediateBufferSize; - }; - FSetupWindowStateContext SetupWindowStateContext = - { - CrashTrackerResource, - VirtualScreen - }; - - ENQUEUE_RENDER_COMMAND(SetupWindowState)( - [SetupWindowStateContext](FRHICommandListImmediate& RHICmdList) - { - FRHIRenderTargetView RtView = FRHIRenderTargetView(SetupWindowStateContext.CrashReportResource->GetBuffer(), ERenderTargetLoadAction::EClear); - FRHISetRenderTargetsInfo Info(1, &RtView, FRHIDepthRenderTargetView()); - RHICmdList.SetRenderTargetsAndClear(Info); - RHICmdList.SetViewport(0, 0, 0.0f, SetupWindowStateContext.IntermediateBufferSize.Width(), SetupWindowStateContext.IntermediateBufferSize.Height(), 1.0f); - } - ); - - // draw windows to buffer - TArray< TSharedRef > OutWindows; - FSlateApplication::Get().GetAllVisibleWindowsOrdered(OutWindows); - - static const FName RendererModuleName( "Renderer" ); - IRendererModule& RendererModule = FModuleManager::GetModuleChecked( RendererModuleName ); - - //if ( false ) - { - for (int32 i = 0; i < OutWindows.Num(); ++i) - { - TSharedPtr WindowPtr = OutWindows[i]; - SWindow* Window = WindowPtr.Get(); - FViewportInfo* ViewportInfo = WindowToViewportInfo.FindChecked(Window); - - const FSlateRect SlateWindowRect = Window->GetRectInScreen(); - const FVector2D WindowSize = SlateWindowRect.GetSize(); - if ( WindowSize.X > 0 && WindowSize.Y > 0 ) - { - FIntRect ScaledWindowRect; - ScaledWindowRect.Min.X = SlateWindowRect.Left * XScaling - VirtualScreenPos.X; - ScaledWindowRect.Max.X = SlateWindowRect.Right * XScaling - VirtualScreenPos.X; - ScaledWindowRect.Min.Y = SlateWindowRect.Top * YScaling - VirtualScreenPos.Y; - ScaledWindowRect.Max.Y = SlateWindowRect.Bottom * YScaling - VirtualScreenPos.Y; - - struct FDrawWindowToBufferContext - { - FViewportInfo* InViewportInfo; - FIntRect WindowRect; - FIntRect IntermediateBufferSize; - IRendererModule* RendererModule; - }; - FDrawWindowToBufferContext DrawWindowToBufferContext = - { - ViewportInfo, - ScaledWindowRect, - VirtualScreen, - &RendererModule - }; - - // Draw a quad mapping scene color to the view's render target - ENQUEUE_RENDER_COMMAND(DrawWindowToBuffer)( - [DrawWindowToBufferContext](FRHICommandListImmediate& RHICmdList) - { - FGraphicsPipelineStateInitializer GraphicsPSOInit; - RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit); - GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI(); - GraphicsPSOInit.RasterizerState = TStaticRasterizerState<>::GetRHI(); - GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState::GetRHI(); - - const auto FeatureLevel = GMaxRHIFeatureLevel; - auto ShaderMap = GetGlobalShaderMap(FeatureLevel); - - TShaderMapRef VertexShader(ShaderMap); - TShaderMapRef PixelShader(ShaderMap); - - GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = DrawWindowToBufferContext.RendererModule->GetFilterVertexDeclaration().VertexDeclarationRHI; - GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(*VertexShader); - GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(*PixelShader); - GraphicsPSOInit.PrimitiveType = PT_TriangleList; - - SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit); - - if(DrawWindowToBufferContext.WindowRect.Width() != DrawWindowToBufferContext.InViewportInfo->Width || DrawWindowToBufferContext.WindowRect.Height() != DrawWindowToBufferContext.InViewportInfo->Height ) - { - // We're scaling down the window, so use bilinear filtering - PixelShader->SetParameters(RHICmdList, TStaticSamplerState::GetRHI(), RHICmdList.GetViewportBackBuffer(DrawWindowToBufferContext.InViewportInfo->ViewportRHI)); - } - else - { - // Drawing 1:1, so no filtering needed - PixelShader->SetParameters(RHICmdList, TStaticSamplerState::GetRHI(), RHICmdList.GetViewportBackBuffer(DrawWindowToBufferContext.InViewportInfo->ViewportRHI)); - } - - DrawWindowToBufferContext.RendererModule->DrawRectangle( - RHICmdList, - DrawWindowToBufferContext.WindowRect.Min.X, DrawWindowToBufferContext.WindowRect.Min.Y, - DrawWindowToBufferContext.WindowRect.Width(), DrawWindowToBufferContext.WindowRect.Height(), - 0, 0, - 1, 1, - FIntPoint(DrawWindowToBufferContext.IntermediateBufferSize.Width(), DrawWindowToBufferContext.IntermediateBufferSize.Height()), - FIntPoint(1, 1), - *VertexShader, - EDRF_Default); - } - ); - } - } - } - - // draw mouse cursor and keypresses - const FVector2D MouseCursorLocation = FSlateApplication::Get().GetCursorPos(); - const FIntPoint ScaledCursorLocation = FIntPoint(MouseCursorLocation.X * XScaling, MouseCursorLocation.Y * YScaling) - VirtualScreenPos; - - FSlateWindowElementList* WindowElementList = CrashTrackerResource->GetNextElementList(); - WindowElementList->ResetBuffers(); - - // Don't draw cursor when it is hidden (mouse looking, scrolling, etc.) - // @todo livestream: The cursor is probably still hidden when dragging with the mouse captured (grabby hand) - if( FSlateApplication::Get().GetMouseCaptureWindow() == nullptr ) - { - FSlateDrawElement::MakeBox( - *WindowElementList, - 0, - FPaintGeometry(ScaledCursorLocation, FVector2D(32, 32) * XScaling, XScaling), - FCoreStyle::Get().GetBrush("CrashTracker.Cursor"), - FSlateRect(0, 0, VirtualScreenSize.X, VirtualScreenSize.Y)); - } - - for (int32 i = 0; i < KeypressBuffer.Num(); ++i) - { - FSlateDrawElement::MakeText( - *WindowElementList, - 0, - FPaintGeometry(FVector2D(10, 10 + i * 30), FVector2D(300, 30), 1.f), - KeypressBuffer[i], - FCoreStyle::Get().GetFontStyle(TEXT("CrashTracker.Font")), - FSlateRect(0, 0, VirtualScreenSize.X, VirtualScreenSize.Y)); - } - - ElementBatcher->AddElements(*WindowElementList); - ElementBatcher->ResetBatches(); - - struct FWriteMouseCursorAndKeyPressesContext - { - FSlateCrashReportResource* CrashReportResource; - FIntRect IntermediateBufferSize; - FSlateRHIRenderingPolicy* RenderPolicy; - FSlateWindowElementList* SlateElementList; - FIntPoint ViewportSize; - }; - FWriteMouseCursorAndKeyPressesContext WriteMouseCursorAndKeyPressesContext = - { - CrashTrackerResource, - VirtualScreen, - RenderingPolicy.Get(), - WindowElementList, - VirtualScreenSize - }; - ENQUEUE_RENDER_COMMAND(WriteMouseCursorAndKeyPresses)( - [WriteMouseCursorAndKeyPressesContext](FRHICommandListImmediate& RHICmdList) - { - //TODO Where does this State go? - //GraphicsPSOInit.BlendState = TStaticBlendState::GetRHI(); - - FSlateBatchData& BatchData = WriteMouseCursorAndKeyPressesContext.SlateElementList->GetBatchData(); - FElementBatchMap& RootBatchMap = WriteMouseCursorAndKeyPressesContext.SlateElementList->GetRootDrawLayer().GetElementBatchMap(); - - BatchData.CreateRenderBatches(RootBatchMap); - - WriteMouseCursorAndKeyPressesContext.RenderPolicy->UpdateVertexAndIndexBuffers(RHICmdList, BatchData); - if( BatchData.GetRenderBatches().Num() > 0 ) - { - FTexture2DRHIRef UnusedTargetTexture; - FSlateBackBuffer UnusedTarget( UnusedTargetTexture, FIntPoint::ZeroValue ); - - WriteMouseCursorAndKeyPressesContext.RenderPolicy->DrawElements(RHICmdList, UnusedTarget, CreateProjectionMatrix(WriteMouseCursorAndKeyPressesContext.ViewportSize.X, WriteMouseCursorAndKeyPressesContext.ViewportSize.Y), BatchData.GetRenderBatches()); - } - } - ); - - // copy back to the cpu - struct FReadbackFromIntermediateBufferContext - { - FSlateCrashReportResource* CrashReportResource; - FIntRect IntermediateBufferSize; - }; - FReadbackFromIntermediateBufferContext ReadbackFromIntermediateBufferContext = - { - CrashTrackerResource, - VirtualScreen - }; - ENQUEUE_RENDER_COMMAND(ReadbackFromIntermediateBuffer)( - [ReadbackFromIntermediateBufferContext](FRHICommandListImmediate& RHICmdList) - { - RHICmdList.CopyToResolveTarget( - ReadbackFromIntermediateBufferContext.CrashReportResource->GetBuffer(), - ReadbackFromIntermediateBufferContext.CrashReportResource->GetReadbackBuffer(), - false, - FResolveParams()); - } - ); -} - - -void FSlateRHIRenderer::MapVirtualScreenBuffer(FMappedTextureBuffer* OutTextureData) -{ - const FIntRect VirtualScreen = CrashTrackerResource->GetVirtualScreen(); - - struct FReadbackFromStagingBufferContext - { - FSlateCrashReportResource* CrashReportResource; - FMappedTextureBuffer* TextureData; - FIntRect ExpectedBufferSize; - }; - FReadbackFromStagingBufferContext ReadbackFromStagingBufferContext = - { - CrashTrackerResource, - OutTextureData, - VirtualScreen, - }; - ENQUEUE_RENDER_COMMAND(ReadbackFromStagingBuffer)( - [ReadbackFromStagingBufferContext](FRHICommandListImmediate& RHICmdList) - { - SCOPE_CYCLE_COUNTER(STAT_MapStagingBuffer); - RHICmdList.MapStagingSurface(ReadbackFromStagingBufferContext.CrashReportResource->GetReadbackBuffer(), ReadbackFromStagingBufferContext.TextureData->Data, ReadbackFromStagingBufferContext.TextureData->Width, ReadbackFromStagingBufferContext.TextureData->Height); - - ReadbackFromStagingBufferContext.CrashReportResource->SwapTargetReadbackBuffer(); - } - ); -} - -void FSlateRHIRenderer::UnmapVirtualScreenBuffer() -{ - struct FReadbackFromStagingBufferContext - { - FSlateCrashReportResource* CrashReportResource; - }; - FReadbackFromStagingBufferContext ReadbackFromStagingBufferContext = - { - CrashTrackerResource - }; - ENQUEUE_RENDER_COMMAND(ReadbackFromStagingBuffer)( - [ReadbackFromStagingBufferContext](FRHICommandListImmediate& RHICmdList) - { - SCOPE_CYCLE_COUNTER(STAT_UnmapStagingBuffer); - RHICmdList.UnmapStagingSurface(ReadbackFromStagingBufferContext.CrashReportResource->GetReadbackBuffer()); - } - ); -} - FIntPoint FSlateRHIRenderer::GenerateDynamicImageResource(const FName InTextureName) { check( IsInGameThread() ); diff --git a/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateRHIRenderer.h b/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateRHIRenderer.h index fcbcfea17fea..2314fe69df29 100644 --- a/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateRHIRenderer.h +++ b/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateRHIRenderer.h @@ -25,7 +25,12 @@ template struct FRHICommand; const uint32 NumDrawBuffers = 3; // Enable to visualize overdraw in Slate -#define DEBUG_OVERDRAW 0 +#define WITH_SLATE_VISUALIZERS 0 //!(UE_BUILD_SHIPPING || UE_BUILD_TEST) + +#if WITH_SLATE_VISUALIZERS +extern TAutoConsoleVariable CVarShowSlateOverdraw; +extern TAutoConsoleVariable CVarShowSlateBatching; +#endif class FSlateBackBuffer : public FRenderTarget { @@ -40,56 +45,6 @@ private: FIntPoint SizeXY; }; -/** Resource for crash buffer editor capturing */ -class FSlateCrashReportResource : public FRenderResource -{ -public: - FSlateCrashReportResource(FIntRect InVirtualScreen, FIntRect InUnscaledVirtualScreen) - : ReadbackBufferIndex(0) - , ElementListIndex(0) - , VirtualScreen(InVirtualScreen) - , UnscaledVirtualScreen(InUnscaledVirtualScreen) {} - - /** FRenderResource Interface. Called when render resources need to be initialized */ - virtual void InitDynamicRHI() override; - - /** FRenderResource Interface. Called when render resources need to be released */ - virtual void ReleaseDynamicRHI() override; - - /** Changes the target readback buffer */ - void SwapTargetReadbackBuffer() {ReadbackBufferIndex = (ReadbackBufferIndex + 1) % 2;} - - /** Gets the next element list, ping ponging between the element lists */ - FSlateWindowElementList* GetNextElementList(); - - /** Accessors */ - FIntRect GetVirtualScreen() const {return VirtualScreen;} - FIntRect GetUnscaledVirtualScreen() const {return UnscaledVirtualScreen;} - FTexture2DRHIRef GetBuffer() const {return CrashReportBuffer;} - FTexture2DRHIRef GetReadbackBuffer() const {return ReadbackBuffer[ReadbackBufferIndex];} - -private: - /** The crash report buffer we push out to a movie capture */ - FTexture2DRHIRef CrashReportBuffer; - - /** The readback buffers for copying back to the CPU from the GPU */ - FTexture2DRHIRef ReadbackBuffer[2]; - /** We ping pong between the buffers in case the GPU is a frame behind (GSystemSettings.bAllowOneFrameThreadLag) */ - int32 ReadbackBufferIndex; - - /** Window Element Lists for keypress buffer drawing */ - FSlateWindowElementList ElementList[2]; - /** We ping pong between the element lists, which is on the main thread, so it needs a different index than ReadbackBufferIndex */ - int32 ElementListIndex; - - /** The size of the virtual screen, used to calculate the buffer size */ - FIntRect VirtualScreen; - - /** Size of the virtual screen before we applied any scaling */ - FIntRect UnscaledVirtualScreen; -}; - - /** A Slate rendering implementation for Unreal engine */ class FSlateRHIRenderer : public FSlateRenderer { @@ -245,27 +200,6 @@ public: /** Draws windows from a FSlateDrawBuffer on the render thread */ void DrawWindow_RenderThread(FRHICommandListImmediate& RHICmdList, FSlateRHIRenderer::FViewportInfo& ViewportInfo, FSlateWindowElementList& WindowElementList, bool bLockToVsync, bool bClear); - /** - * You must call this before calling CopyWindowsToVirtualScreenBuffer(), to setup the render targets first. - * - * @param ScreenScaling How much to downscale the desktop size - * @param LiveStreamingService Optional pointer to a live streaming service this buffer needs to work with - * @param bPrimaryWorkAreaOnly True if we should capture only the primary monitor's work area, or false to capture the entire desktop spanning all monitors - * - * @return The virtual screen rectangle. The size of this rectangle will be the size of the render target buffer. - */ - virtual FIntRect SetupVirtualScreenBuffer(const bool bPrimaryWorkAreaOnly, const float ScreenScaling, class ILiveStreamingService* LiveStreamingService) override; - - /** - * Copies all slate windows out to a buffer at half resolution with debug information - * like the mouse cursor and any keypresses. - */ - virtual void CopyWindowsToVirtualScreenBuffer(const TArray& KeypressBuffer) override; - - /** Allows and disallows access to the crash tracker buffer data on the CPU */ - virtual void MapVirtualScreenBuffer(FMappedTextureBuffer* OutTextureData) override; - virtual void UnmapVirtualScreenBuffer() override; - /** * Reloads texture resources from disk */ @@ -341,9 +275,6 @@ private: TArray< TSharedPtr > DynamicBrushesToRemove[NumDrawBuffers]; - /** The resource which allows us to capture the editor to a buffer */ - FSlateCrashReportResource* CrashTrackerResource; - bool bTakingAScreenShot; FIntRect ScreenshotRect; TArray* OutScreenshotData; diff --git a/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateRHIRenderingPolicy.cpp b/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateRHIRenderingPolicy.cpp index fc80565d4edd..836dffb6bad6 100644 --- a/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateRHIRenderingPolicy.cpp +++ b/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateRHIRenderingPolicy.cpp @@ -19,6 +19,7 @@ #include "SlateUpdatableBuffer.h" #include "SlatePostProcessor.h" #include "Modules/ModuleManager.h" +#include "Math/RandomStream.h" extern void UpdateNoiseTextureParameters(FViewUniformShaderParameters& ViewUniformShaderParameters); @@ -28,6 +29,9 @@ DECLARE_DWORD_COUNTER_STAT(TEXT("Num Layers"), STAT_SlateNumLayers, STATGROUP_Sl DECLARE_DWORD_COUNTER_STAT(TEXT("Num Batches"), STAT_SlateNumBatches, STATGROUP_Slate); DECLARE_DWORD_COUNTER_STAT(TEXT("Num Vertices"), STAT_SlateVertexCount, STATGROUP_Slate); +DECLARE_CYCLE_STAT(TEXT("Slate RT: Draw Call"), STAT_SlateRTDrawCall, STATGROUP_Slate); +DECLARE_CYCLE_STAT(TEXT("Slate RT: Custom Draw"), STAT_SlateRTCustomDraw, STATGROUP_Slate); + TAutoConsoleVariable CVarSlateAbsoluteIndices( TEXT("Slate.AbsoluteIndices"), 0, @@ -165,7 +169,7 @@ void FSlateRHIRenderingPolicy::UpdateVertexAndIndexBuffers(FRHICommandListImmedi VertexBuffer.PreFillBuffer(NumVertices, bShouldShrinkResources); IndexBuffer.PreFillBuffer(NumIndices, bShouldShrinkResources); - if(!GRHIThread || RHICmdList.Bypass()) + if(!IsRunningRHIInSeparateThread() || RHICmdList.Bypass()) { uint8* VertexBufferData = (uint8*)VertexBuffer.LockBuffer_RenderThread(NumVertices); uint8* IndexBufferData = (uint8*)IndexBuffer.LockBuffer_RenderThread(NumIndices); @@ -227,6 +231,7 @@ static FSceneView* CreateSceneView( FSceneViewFamilyContext* ViewFamilyContext, ); ViewUniformShaderParameters.WorldViewOrigin = View->ViewMatrices.GetViewOrigin(); + ERHIFeatureLevel::Type RHIFeatureLevel = View->GetFeatureLevel(); @@ -312,11 +317,22 @@ void FSlateRHIRenderingPolicy::DrawElements(FRHICommandListImmediate& RHICmdList const FSlateRenderDataHandle* LastHandle = nullptr; + const ERHIFeatureLevel::Type FeatureLevel = GMaxRHIFeatureLevel; + TShaderMap* ShaderMap = GetGlobalShaderMap(FeatureLevel); + +#if WITH_SLATE_VISUALIZERS + FRandomStream BatchColors(1337); +#endif + const bool bAbsoluteIndices = CVarSlateAbsoluteIndices.GetValueOnRenderThread() != 0; // Draw each element for( int32 BatchIndex = 0; BatchIndex < RenderBatches.Num(); ++BatchIndex ) { +#if WITH_SLATE_VISUALIZERS + FLinearColor BatchColor = FLinearColor(BatchColors.GetUnitVector()); +#endif + const FSlateRenderBatch& RenderBatch = RenderBatches[BatchIndex]; const FSlateRenderDataHandle* RenderHandle = RenderBatch.CachedRenderHandle.Get(); @@ -384,12 +400,38 @@ void FSlateRHIRenderingPolicy::DrawElements(FRHICommandListImmediate& RHICmdList if( ResourceType != ESlateShaderResource::Material && ShaderType != ESlateShader::PostProcess ) { check(RenderBatch.NumIndices > 0); - FSlateElementPS* PixelShader = GetTexturePixelShader(ShaderType, DrawEffects); + FSlateElementPS* PixelShader = nullptr; const bool bUseInstancing = RenderBatch.InstanceCount > 1 && RenderBatch.InstanceData != nullptr; check(bUseInstancing == false); - -#if !DEBUG_OVERDRAW + +#if WITH_SLATE_VISUALIZERS + FSlateDebugBatchingPS* BatchingPixelShader = nullptr; + if ( CVarShowSlateBatching.GetValueOnRenderThread() != 0 ) + { + BatchingPixelShader = *TShaderMapRef(ShaderMap); + PixelShader = BatchingPixelShader; + } + else +#endif + { + PixelShader = GetTexturePixelShader(ShaderMap, ShaderType, DrawEffects); + } + +#if WITH_SLATE_VISUALIZERS + if ( CVarShowSlateBatching.GetValueOnRenderThread() != 0 ) + { + BatchingPixelShader->SetBatchColor(RHICmdList, BatchColor); + + GraphicsPSOInit.BlendState = TStaticBlendState::GetRHI(); + } + else if ( CVarShowSlateOverdraw.GetValueOnRenderThread() != 0 ) + { + GraphicsPSOInit.BlendState = TStaticBlendState::GetRHI(); + } + else +#endif + { GraphicsPSOInit.BlendState = EnumHasAllFlags( DrawFlags, ESlateBatchDrawFlag::NoBlending ) ? TStaticBlendState<>::GetRHI() @@ -397,9 +439,7 @@ void FSlateRHIRenderingPolicy::DrawElements(FRHICommandListImmediate& RHICmdList ? TStaticBlendState::GetRHI() : TStaticBlendState::GetRHI() ) ; -#else - GraphicsPSOInit.BlendState = TStaticBlendState::GetRHI(); -#endif + } if ( EnumHasAllFlags(DrawFlags, ESlateBatchDrawFlag::Wireframe) ) { @@ -511,6 +551,8 @@ void FSlateRHIRenderingPolicy::DrawElements(FRHICommandListImmediate& RHICmdList PixelShader->SetInvertAlpha(RHICmdList, EnumHasAllFlags(DrawEffects, ESlateDrawEffect::InvertAlpha ) ? true : false ); + SCOPE_CYCLE_COUNTER(STAT_SlateRTDrawCall); + // for RHIs that can't handle VertexOffset, we need to offset the stream source each time if (!GRHISupportsBaseVertexIndex && !bAbsoluteIndices) { @@ -560,7 +602,7 @@ void FSlateRHIRenderingPolicy::DrawElements(FRHICommandListImmediate& RHICmdList const FSceneView& ActiveSceneView = *SceneViews[ActiveSceneIndex]; FSlateMaterialResource* MaterialShaderResource = (FSlateMaterialResource*)ShaderResource; - if( MaterialShaderResource->GetMaterialObject() != nullptr ) + if (MaterialShaderResource->GetMaterialObject() != nullptr) { #if !UE_BUILD_SHIPPING // pending kill objects may still be rendered for a frame so it is valid for the check to pass @@ -580,94 +622,132 @@ void FSlateRHIRenderingPolicy::DrawElements(FRHICommandListImmediate& RHICmdList if (VertexShader && PixelShader) { - PixelShader->SetBlendState(GraphicsPSOInit, Material); - FSlateShaderResource* MaskResource = MaterialShaderResource->GetTextureMaskResource(); - if (MaskResource) +#if WITH_SLATE_VISUALIZERS + if (CVarShowSlateBatching.GetValueOnRenderThread() != 0) { - GraphicsPSOInit.BlendState = TStaticBlendState::GetRHI(); + FSlateDebugBatchingPS* BatchingPixelShader = *TShaderMapRef(ShaderMap); + + RHICmdList.SetLocalBoundShaderState(RHICmdList.BuildLocalBoundShaderState( + GSlateVertexDeclaration.VertexDeclarationRHI, + GlobalVertexShader->GetVertexShader(), + nullptr, + nullptr, + BatchingPixelShader->GetPixelShader(), + FGeometryShaderRHIRef())); + + BatchingPixelShader->SetBatchColor(RHICmdList, BatchColor); + GraphicsPSOInit.BlendState = TStaticBlendState::GetRHI(); } - - GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = bUseInstancing ? GSlateInstancedVertexDeclaration.VertexDeclarationRHI : GSlateVertexDeclaration.VertexDeclarationRHI; - GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(VertexShader); - GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(PixelShader); - GraphicsPSOInit.PrimitiveType = GetRHIPrimitiveType(RenderBatch.DrawPrimitiveType); - - FLocalGraphicsPipelineState BaseGraphicsPSO = RHICmdList.BuildLocalGraphicsPipelineState(GraphicsPSOInit); - RHICmdList.SetLocalGraphicsPipelineState(BaseGraphicsPSO); - - VertexShader->SetViewProjection(RHICmdList, ViewProjection); - VertexShader->SetVerticalAxisMultiplier(RHICmdList, bAllowSwitchVerticalAxis && RHINeedsToSwitchVerticalAxis(GShaderPlatformForFeatureLevel[GMaxRHIFeatureLevel]) ? -1.0f : 1.0f); - VertexShader->SetMaterialShaderParameters(RHICmdList, ActiveSceneView, MaterialRenderProxy, Material); - - PixelShader->SetParameters(RHICmdList, ActiveSceneView, MaterialRenderProxy, Material, ShaderParams.PixelParams); - PixelShader->SetDisplayGamma(RHICmdList, EnumHasAllFlags(DrawFlags, ESlateBatchDrawFlag::NoGamma) ? 1.0f : DisplayGamma); - - if (MaskResource) + else if (CVarShowSlateOverdraw.GetValueOnRenderThread() != 0) { - FTexture2DRHIRef TextureRHI; - TextureRHI = ((TSlateTexture*)MaskResource)->GetTypedResource(); + FSlateElementPS* OverdrawPixelShader = *TShaderMapRef(ShaderMap); - PixelShader->SetAdditionalTexture(RHICmdList, TextureRHI, BilinearClamp); + RHICmdList.SetLocalBoundShaderState(RHICmdList.BuildLocalBoundShaderState( + GSlateVertexDeclaration.VertexDeclarationRHI, + GlobalVertexShader->GetVertexShader(), + nullptr, + nullptr, + OverdrawPixelShader->GetPixelShader(), + FGeometryShaderRHIRef())); + + GraphicsPSOInit.BlendState = TStaticBlendState::GetRHI(); } - - if ( bUseInstancing ) + else { - uint32 InstanceCount = RenderBatch.InstanceCount; - - if ( GRHISupportsInstancing ) + GraphicsPSOInit.RasterizerState = TStaticRasterizerState::GetRHI(); + } + +#endif + { + PixelShader->SetBlendState(GraphicsPSOInit, Material); + FSlateShaderResource* MaskResource = MaterialShaderResource->GetTextureMaskResource(); + if (MaskResource) { - FSlateUpdatableInstanceBuffer* InstanceBuffer = (FSlateUpdatableInstanceBuffer*)RenderBatch.InstanceData; - InstanceBuffer->BindStreamSource(RHICmdList, 1, RenderBatch.InstanceOffset); + GraphicsPSOInit.BlendState = TStaticBlendState::GetRHI(); + } + + GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = bUseInstancing ? GSlateInstancedVertexDeclaration.VertexDeclarationRHI : GSlateVertexDeclaration.VertexDeclarationRHI; + GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(VertexShader); + GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(PixelShader); + GraphicsPSOInit.PrimitiveType = GetRHIPrimitiveType(RenderBatch.DrawPrimitiveType); + + FLocalGraphicsPipelineState BaseGraphicsPSO = RHICmdList.BuildLocalGraphicsPipelineState(GraphicsPSOInit); + RHICmdList.SetLocalGraphicsPipelineState(BaseGraphicsPSO); + + VertexShader->SetViewProjection(RHICmdList, ViewProjection); + VertexShader->SetVerticalAxisMultiplier(RHICmdList, bAllowSwitchVerticalAxis && RHINeedsToSwitchVerticalAxis(GShaderPlatformForFeatureLevel[GMaxRHIFeatureLevel]) ? -1.0f : 1.0f); + VertexShader->SetMaterialShaderParameters(RHICmdList, ActiveSceneView, MaterialRenderProxy, Material); + + PixelShader->SetParameters(RHICmdList, ActiveSceneView, MaterialRenderProxy, Material, ShaderParams.PixelParams); + PixelShader->SetDisplayGamma(RHICmdList, EnumHasAllFlags(DrawFlags, ESlateBatchDrawFlag::NoGamma) ? 1.0f : DisplayGamma); + + if (MaskResource) + { + FTexture2DRHIRef TextureRHI; + TextureRHI = ((TSlateTexture*)MaskResource)->GetTypedResource(); + + PixelShader->SetAdditionalTexture(RHICmdList, TextureRHI, BilinearClamp); + } + + if (bUseInstancing) + { + uint32 InstanceCount = RenderBatch.InstanceCount; + + if (GRHISupportsInstancing) + { + FSlateUpdatableInstanceBuffer* InstanceBuffer = (FSlateUpdatableInstanceBuffer*)RenderBatch.InstanceData; + InstanceBuffer->BindStreamSource(RHICmdList, 1, RenderBatch.InstanceOffset); + + // for RHIs that can't handle VertexOffset, we need to offset the stream source each time + if (!GRHISupportsBaseVertexIndex && !bAbsoluteIndices) + { + RHICmdList.SetStreamSource(0, VertexBuffer->VertexBufferRHI, sizeof(FSlateVertex), RenderBatch.VertexOffset * sizeof(FSlateVertex)); + RHICmdList.DrawIndexedPrimitive(IndexBuffer->IndexBufferRHI, GetRHIPrimitiveType(RenderBatch.DrawPrimitiveType), 0, 0, RenderBatch.NumVertices, RenderBatch.IndexOffset, PrimitiveCount, InstanceCount); + } + else + { + uint32 VertexOffset = bAbsoluteIndices ? 0 : RenderBatch.VertexOffset; + RHICmdList.SetStreamSource(0, VertexBuffer->VertexBufferRHI, sizeof(FSlateVertex), 0); + RHICmdList.DrawIndexedPrimitive(IndexBuffer->IndexBufferRHI, GetRHIPrimitiveType(RenderBatch.DrawPrimitiveType), VertexOffset, 0, RenderBatch.NumVertices, RenderBatch.IndexOffset, PrimitiveCount, InstanceCount); + } + } + //else + //{ + // for ( uint32 InstanceIndex = 0; InstanceIndex < InstanceCount; InstanceIndex++ ) + // { + // FSlateUpdatableInstanceBuffer* InstanceBuffer = (FSlateUpdatableInstanceBuffer*)RenderBatch.InstanceData; + // InstanceBuffer->BindStreamSource(RHICmdList, 1, RenderBatch.InstanceOffset + InstanceIndex); + + // // for RHIs that can't handle VertexOffset, we need to offset the stream source each time + // if ( !GRHISupportsBaseVertexIndex ) + // { + // RHICmdList.SetStreamSource(0, VertexBuffer->VertexBufferRHI, sizeof(FSlateVertex), RenderBatch.VertexOffset * sizeof(FSlateVertex)); + // RHICmdList.DrawIndexedPrimitive(IndexBuffer->IndexBufferRHI, GetRHIPrimitiveType(RenderBatch.DrawPrimitiveType), 0, 0, RenderBatch.NumVertices, RenderBatch.IndexOffset, PrimitiveCount, 1); + // } + // else + // { + // RHICmdList.DrawIndexedPrimitive(IndexBuffer->IndexBufferRHI, GetRHIPrimitiveType(RenderBatch.DrawPrimitiveType), RenderBatch.VertexOffset, 0, RenderBatch.NumVertices, RenderBatch.IndexOffset, PrimitiveCount, 1); + // } + // } + //} + } + else + { + RHICmdList.SetStreamSource(1, nullptr, 0, 0); // for RHIs that can't handle VertexOffset, we need to offset the stream source each time if ( !GRHISupportsBaseVertexIndex && !bAbsoluteIndices) { RHICmdList.SetStreamSource(0, VertexBuffer->VertexBufferRHI, sizeof(FSlateVertex), RenderBatch.VertexOffset * sizeof(FSlateVertex)); - RHICmdList.DrawIndexedPrimitive(IndexBuffer->IndexBufferRHI, GetRHIPrimitiveType(RenderBatch.DrawPrimitiveType), 0, 0, RenderBatch.NumVertices, RenderBatch.IndexOffset, PrimitiveCount, InstanceCount); + RHICmdList.DrawIndexedPrimitive(IndexBuffer->IndexBufferRHI, GetRHIPrimitiveType(RenderBatch.DrawPrimitiveType), 0, 0, RenderBatch.NumVertices, RenderBatch.IndexOffset, PrimitiveCount, 1); } else { uint32 VertexOffset = bAbsoluteIndices ? 0 : RenderBatch.VertexOffset; RHICmdList.SetStreamSource(0, VertexBuffer->VertexBufferRHI, sizeof(FSlateVertex), 0); - RHICmdList.DrawIndexedPrimitive(IndexBuffer->IndexBufferRHI, GetRHIPrimitiveType(RenderBatch.DrawPrimitiveType), VertexOffset, 0, RenderBatch.NumVertices, RenderBatch.IndexOffset, PrimitiveCount, InstanceCount); + RHICmdList.DrawIndexedPrimitive(IndexBuffer->IndexBufferRHI, GetRHIPrimitiveType(RenderBatch.DrawPrimitiveType), VertexOffset, 0, RenderBatch.NumVertices, RenderBatch.IndexOffset, PrimitiveCount, 1); } } - //else - //{ - // for ( uint32 InstanceIndex = 0; InstanceIndex < InstanceCount; InstanceIndex++ ) - // { - // FSlateUpdatableInstanceBuffer* InstanceBuffer = (FSlateUpdatableInstanceBuffer*)RenderBatch.InstanceData; - // InstanceBuffer->BindStreamSource(RHICmdList, 1, RenderBatch.InstanceOffset + InstanceIndex); - - // // for RHIs that can't handle VertexOffset, we need to offset the stream source each time - // if ( !GRHISupportsBaseVertexIndex ) - // { - // RHICmdList.SetStreamSource(0, VertexBuffer->VertexBufferRHI, sizeof(FSlateVertex), RenderBatch.VertexOffset * sizeof(FSlateVertex)); - // RHICmdList.DrawIndexedPrimitive(IndexBuffer->IndexBufferRHI, GetRHIPrimitiveType(RenderBatch.DrawPrimitiveType), 0, 0, RenderBatch.NumVertices, RenderBatch.IndexOffset, PrimitiveCount, 1); - // } - // else - // { - // RHICmdList.DrawIndexedPrimitive(IndexBuffer->IndexBufferRHI, GetRHIPrimitiveType(RenderBatch.DrawPrimitiveType), RenderBatch.VertexOffset, 0, RenderBatch.NumVertices, RenderBatch.IndexOffset, PrimitiveCount, 1); - // } - // } - //} - } - else - { - RHICmdList.SetStreamSource(1, nullptr, 0, 0); - - // for RHIs that can't handle VertexOffset, we need to offset the stream source each time - if ( !GRHISupportsBaseVertexIndex && !bAbsoluteIndices) - { - RHICmdList.SetStreamSource(0, VertexBuffer->VertexBufferRHI, sizeof(FSlateVertex), RenderBatch.VertexOffset * sizeof(FSlateVertex)); - RHICmdList.DrawIndexedPrimitive(IndexBuffer->IndexBufferRHI, GetRHIPrimitiveType(RenderBatch.DrawPrimitiveType), 0, 0, RenderBatch.NumVertices, RenderBatch.IndexOffset, PrimitiveCount, 1); - } - else - { - uint32 VertexOffset = bAbsoluteIndices ? 0 : RenderBatch.VertexOffset; - RHICmdList.SetStreamSource(0, VertexBuffer->VertexBufferRHI, sizeof(FSlateVertex), 0); - RHICmdList.DrawIndexedPrimitive(IndexBuffer->IndexBufferRHI, GetRHIPrimitiveType(RenderBatch.DrawPrimitiveType), VertexOffset, 0, RenderBatch.NumVertices, RenderBatch.IndexOffset, PrimitiveCount, 1); - } } } } @@ -704,11 +784,10 @@ void FSlateRHIRenderingPolicy::DrawElements(FRHICommandListImmediate& RHICmdList CustomDrawer->DrawRenderThread(RHICmdList, &BackBuffer.GetRenderTargetTexture()); // Something may have messed with the viewport size so set it back to the full target. - RHICmdList.SetViewport( 0,0,0,BackBuffer.GetSizeXY().X, BackBuffer.GetSizeXY().Y, 0.0f ); + RHICmdList.SetViewport(0, 0, 0, BackBuffer.GetSizeXY().X, BackBuffer.GetSizeXY().Y, 0.0f); RHICmdList.SetStreamSource(0, VertexBuffer->VertexBufferRHI, sizeof(FSlateVertex), 0); } } - } for (int i = 0; i < NumScenes; i++) @@ -721,14 +800,18 @@ void FSlateRHIRenderingPolicy::DrawElements(FRHICommandListImmediate& RHICmdList } -FSlateElementPS* FSlateRHIRenderingPolicy::GetTexturePixelShader( ESlateShader::Type ShaderType, ESlateDrawEffect DrawEffects ) +FSlateElementPS* FSlateRHIRenderingPolicy::GetTexturePixelShader( TShaderMap* ShaderMap, ESlateShader::Type ShaderType, ESlateDrawEffect DrawEffects ) { FSlateElementPS* PixelShader = nullptr; - const auto FeatureLevel = GMaxRHIFeatureLevel; - auto ShaderMap = GetGlobalShaderMap(FeatureLevel); -#if !DEBUG_OVERDRAW - +#if WITH_SLATE_VISUALIZERS + if ( CVarShowSlateOverdraw.GetValueOnRenderThread() != 0 ) + { + PixelShader = *TShaderMapRef(ShaderMap); + } + else +#endif + { const bool bDrawDisabled = EnumHasAllFlags( DrawEffects, ESlateDrawEffect::DisabledEffect ); const bool bUseTextureAlpha = !EnumHasAllFlags( DrawEffects, ESlateDrawEffect::IgnoreTextureAlpha ); @@ -798,9 +881,7 @@ FSlateElementPS* FSlateRHIRenderingPolicy::GetTexturePixelShader( ESlateShader:: break; } } -#else - PixelShader = *TShaderMapRef(ShaderMap); -#endif + } #undef PixelShaderLookupTable diff --git a/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateRHIRenderingPolicy.h b/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateRHIRenderingPolicy.h index 562b547c3ddf..3f6fe488440f 100644 --- a/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateRHIRenderingPolicy.h +++ b/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateRHIRenderingPolicy.h @@ -11,6 +11,7 @@ #include "SlateElementIndexBuffer.h" #include "SlateElementVertexBuffer.h" #include "SlateRHIResourceManager.h" +#include "Shader.h" class FSlateFontServices; class FSlateRHIResourceManager; @@ -56,7 +57,7 @@ private: * @param DrawEffects Draw effects being used * @return The pixel shader for use with the shader type and draw effects */ - class FSlateElementPS* GetTexturePixelShader( ESlateShader::Type ShaderType, ESlateDrawEffect DrawEffects ); + class FSlateElementPS* GetTexturePixelShader( TShaderMap* ShaderMap, ESlateShader::Type ShaderType, ESlateDrawEffect DrawEffects ); class FSlateMaterialShaderPS* GetMaterialPixelShader( const class FMaterial* Material, ESlateShader::Type ShaderType, ESlateDrawEffect DrawEffects ); class FSlateMaterialShaderVS* GetMaterialVertexShader( const class FMaterial* Material, bool bUseInstancing ); diff --git a/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateRHIResourceManager.cpp b/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateRHIResourceManager.cpp index ba8f8392ed76..210ec123bc20 100644 --- a/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateRHIResourceManager.cpp +++ b/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateRHIResourceManager.cpp @@ -267,7 +267,7 @@ bool FSlateRHIResourceManager::IsAtlasPageResourceAlphaOnly() const void FSlateRHIResourceManager::Tick(float DeltaSeconds) { // Don't need to do this if there's no RHI thread. - if ( GRHIThread ) + if (IsRunningRHIInSeparateThread()) { struct FDeleteCachedRenderDataContext { @@ -1058,17 +1058,17 @@ void FSlateRHIResourceManager::ReleaseCachedBuffer(FRHICommandListImmediate& RHI { check(IsInRenderingThread()); - if ( GRHIThread ) + if (IsRunningRHIInSeparateThread()) { PooledBuffersPendingRelease.Add(PooledBuffer); PooledBuffer->ReleaseResourcesFence = RHICmdList.RHIThreadFence(); } else { - PooledBuffer->VertexBuffer.Destroy(); - PooledBuffer->IndexBuffer.Destroy(); - delete PooledBuffer; - } + PooledBuffer->VertexBuffer.Destroy(); + PooledBuffer->IndexBuffer.Destroy(); + delete PooledBuffer; + } } void FSlateRHIResourceManager::ReleaseResources() diff --git a/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateShaders.cpp b/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateShaders.cpp index 017412d8a0c4..e1e0ac6f3c3d 100644 --- a/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateShaders.cpp +++ b/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateShaders.cpp @@ -14,6 +14,7 @@ IMPLEMENT_SHADER_TYPE(, FSlatePostProcessBlurPS, TEXT("SlatePostProcessPixelShad IMPLEMENT_SHADER_TYPE(, FSlatePostProcessDownsamplePS, TEXT("SlatePostProcessPixelShader"), TEXT("DownsampleMain"), SF_Pixel); +IMPLEMENT_SHADER_TYPE(, FSlateDebugBatchingPS, TEXT("SlateElementPixelShader"), TEXT("DebugBatchingMain"), SF_Pixel ); #define IMPLEMENT_SLATE_PIXELSHADER_TYPE(ShaderType, bDrawDisabledEffect, bUseTextureAlpha) \ typedef TSlateElementPS TSlateElementPS##ShaderType##bDrawDisabledEffect##bUseTextureAlpha##A; \ diff --git a/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateShaders.h b/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateShaders.h index 6f2970bb5bf2..aafb582b8106 100644 --- a/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateShaders.h +++ b/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateShaders.h @@ -254,6 +254,53 @@ public: private: }; +/** + * Pixel shader for debugging Slate overdraw + */ +class FSlateDebugBatchingPS : public FSlateElementPS +{ + DECLARE_SHADER_TYPE(FSlateDebugBatchingPS, Global ); +public: + /** Indicates that this shader should be cached */ + static bool ShouldCache( EShaderPlatform Platform ) + { + return true; + } + + FSlateDebugBatchingPS() + { + } + + /** Constructor. Binds all parameters used by the shader */ + FSlateDebugBatchingPS( const ShaderMetaType::CompiledShaderInitializerType& Initializer ) + : FSlateElementPS( Initializer ) + { + BatchColor.Bind(Initializer.ParameterMap, TEXT("BatchColor")); + } + + /** + * Sets shader params used by the shader + * + * @param InShaderParams Shader params to use + */ + void SetBatchColor(FRHICommandList& RHICmdList, const FLinearColor& InBatchColor) + { + SetShaderValue(RHICmdList, GetPixelShader(), BatchColor, InBatchColor); + } + + virtual bool Serialize( FArchive& Ar ) override + { + bool bShaderHasOutdatedParameters = FSlateElementPS::Serialize( Ar ); + + Ar << BatchColor; + + return bShaderHasOutdatedParameters; + } + +private: + FShaderParameter BatchColor; +}; + const int32 MAX_BLUR_SAMPLES = 127; class FSlatePostProcessBlurPS : public FSlateElementPS diff --git a/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateUpdatableBuffer.cpp b/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateUpdatableBuffer.cpp index 7b3beabe3a76..7725e7cc84f4 100644 --- a/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateUpdatableBuffer.cpp +++ b/Engine/Source/Runtime/SlateRHIRenderer/Private/SlateUpdatableBuffer.cpp @@ -90,7 +90,7 @@ void FSlateUpdatableInstanceBuffer::UpdateRenderingData_RenderThread(FRHICommand const TArray& RenderThreadBufferData = BufferData[BufferIndex]; InstanceBufferResource.PreFillBuffer( RenderThreadBufferData.Num(), false ); - if(!GRHIThread || RHICmdList.Bypass()) + if(!IsRunningRHIInSeparateThread() || RHICmdList.Bypass()) { uint8* InstanceBufferData = (uint8*)InstanceBufferResource.LockBuffer_RenderThread(RenderThreadBufferData.Num()); diff --git a/Engine/Source/Runtime/Sockets/Private/BSDIPv6Sockets/SocketSubsystemBSDIPv6.cpp b/Engine/Source/Runtime/Sockets/Private/BSDIPv6Sockets/SocketSubsystemBSDIPv6.cpp index 91fbb08cdad7..3fd2624a8190 100644 --- a/Engine/Source/Runtime/Sockets/Private/BSDIPv6Sockets/SocketSubsystemBSDIPv6.cpp +++ b/Engine/Source/Runtime/Sockets/Private/BSDIPv6Sockets/SocketSubsystemBSDIPv6.cpp @@ -72,10 +72,12 @@ ESocketErrors FSocketSubsystemBSDIPv6::GetHostByName(const ANSICHAR* HostName, F if (IPv6SockAddr != nullptr) { static_cast(OutAddr).SetIp(IPv6SockAddr->sin6_addr); + freeaddrinfo(AddrInfo); return SE_NO_ERROR; } } } + freeaddrinfo(AddrInfo); return SE_HOST_NOT_FOUND; } return SocketError; diff --git a/Engine/Source/Runtime/Sockets/Private/BSDSockets/SocketSubsystemBSD.cpp b/Engine/Source/Runtime/Sockets/Private/BSDSockets/SocketSubsystemBSD.cpp index 2e512f6b3bc6..4668e9feb732 100644 --- a/Engine/Source/Runtime/Sockets/Private/BSDSockets/SocketSubsystemBSD.cpp +++ b/Engine/Source/Runtime/Sockets/Private/BSDSockets/SocketSubsystemBSD.cpp @@ -84,10 +84,12 @@ ESocketErrors FSocketSubsystemBSD::GetHostByName(const ANSICHAR* HostName, FInte { uint32 HostIP = ntohl(IPv4SockAddr->sin_addr.s_addr); static_cast(OutAddr).SetIp(HostIP); + freeaddrinfo(AddrInfo); return SE_NO_ERROR; } } } + freeaddrinfo(AddrInfo); return SE_HOST_NOT_FOUND; } return SocketError; diff --git a/Engine/Source/Runtime/Sockets/Private/ServerTOC.cpp b/Engine/Source/Runtime/Sockets/Private/ServerTOC.cpp index 5df710a4e6ee..69ff84eb91e3 100644 --- a/Engine/Source/Runtime/Sockets/Private/ServerTOC.cpp +++ b/Engine/Source/Runtime/Sockets/Private/ServerTOC.cpp @@ -34,22 +34,34 @@ void FServerTOC::AddFileOrDirectory(const FString& Filename, const FDateTime& Ti ServerPathDirectory->Add(Filename, Timestamp); } -FDateTime* FServerTOC::FindFile(const FString& Filename) +int32 FServerTOC::RemoveFileOrDirectory(const FString& Filename ) { - FDateTime* Result = NULL; + const FString Path = FPaths::GetPath( Filename ); + FDirectory* ServerPathDirectory = FindDirectory(Path); + if ( ServerPathDirectory != NULL ) + { + return ServerPathDirectory->Remove(Filename); + } + return 0; +} + + +const FDateTime* FServerTOC::FindFile(const FString& Filename) const +{ + const FDateTime* Result = NULL; // Find a directory first. const FString Path = FPaths::GetPath(Filename); - FDirectory** FoundDirectory = Directories.Find(Path); + const FDirectory*const* FoundDirectory = Directories.Find(Path); if (FoundDirectory != NULL) { // Find a file inside this directory. - FDirectory* Directory = *FoundDirectory; + const FDirectory* Directory = *FoundDirectory; Result = Directory->Find(Filename); } return Result; } -FServerTOC::FDirectory* FServerTOC::FindDirectory(const FString& Directory) +FServerTOC::FDirectory* FServerTOC::FindDirectory(const FString& Directory) { FDirectory** FoundDirectory = Directories.Find(Directory); if (FoundDirectory != NULL) @@ -60,4 +72,17 @@ FServerTOC::FDirectory* FServerTOC::FindDirectory(const FString& Directory) { return NULL; } +} + +const FServerTOC::FDirectory* FServerTOC::FindDirectory(const FString& Directory) const +{ + const FDirectory*const* FoundDirectory = Directories.Find(Directory); + if (FoundDirectory != NULL) + { + return *FoundDirectory; + } + else + { + return NULL; + } } diff --git a/Engine/Source/Runtime/Sockets/Public/NetworkMessage.h b/Engine/Source/Runtime/Sockets/Public/NetworkMessage.h index bac6ac2f42fa..c411f45267e6 100644 --- a/Engine/Source/Runtime/Sockets/Public/NetworkMessage.h +++ b/Engine/Source/Runtime/Sockets/Public/NetworkMessage.h @@ -5,6 +5,7 @@ #include "CoreMinimal.h" #include "Serialization/BufferArchive.h" #include "Serialization/ArrayReader.h" +#include "Misc/EnumClassFlags.h" enum { @@ -59,6 +60,18 @@ namespace NFS_Channels }; } + + +enum class EConnectionFlags : uint8 +{ + None = 0x00000000, + Streaming = 0x00000001, + PreCookedIterative = 0x00000002, +}; +ENUM_CLASS_FLAGS(EConnectionFlags); + + + /** * Simple abstraction for sockets that allows FNFSMessageHeader to use either an ordinary socket or a mutichannel socket **/ diff --git a/Engine/Source/Runtime/Sockets/Public/ServerTOC.h b/Engine/Source/Runtime/Sockets/Public/ServerTOC.h index 5c53c85b70e4..e8e2d99cc880 100644 --- a/Engine/Source/Runtime/Sockets/Public/ServerTOC.h +++ b/Engine/Source/Runtime/Sockets/Public/ServerTOC.h @@ -32,13 +32,25 @@ struct SOCKETS_API FServerTOC * @param Filename File name to find. * @return Pointer to a timestamp if the file was found, NULL otherwise. */ - FDateTime* FindFile(const FString& Filename); + const FDateTime* FindFile(const FString& Filename) const; /** * Finds a directory in TOC. * * @param Directory Directory to find. - * @return Pointer to a timestamp if the directory was found, NULL otherwise. + * @return Pointer to a FDirectory if the directory was found, NULL otherwise. + */ + const FDirectory* FindDirectory(const FString& Directory) const; + + /** + * Finds a directory in TOC non const version used internally + * see FindDirectory + * + * @param Directory Directory to find + * @return pointer to a FDirectory if the directory was found, null otherwise */ FDirectory* FindDirectory(const FString& Directory); + + + int32 RemoveFileOrDirectory(const FString& Filename); }; diff --git a/Engine/Source/Runtime/Sockets/Public/SocketSubsystem.h b/Engine/Source/Runtime/Sockets/Public/SocketSubsystem.h index 06cf75e5b53e..9902a6ade50e 100644 --- a/Engine/Source/Runtime/Sockets/Public/SocketSubsystem.h +++ b/Engine/Source/Runtime/Sockets/Public/SocketSubsystem.h @@ -57,6 +57,9 @@ public: */ static void ShutdownAllSystems(); + + virtual ~ISocketSubsystem() { } + /** * Does per platform initialization of the sockets library * diff --git a/Engine/Source/Runtime/StreamingFile/Private/StreamingNetworkPlatformFile.cpp b/Engine/Source/Runtime/StreamingFile/Private/StreamingNetworkPlatformFile.cpp index 870bff02253e..f9e4742feae9 100644 --- a/Engine/Source/Runtime/StreamingFile/Private/StreamingNetworkPlatformFile.cpp +++ b/Engine/Source/Runtime/StreamingFile/Private/StreamingNetworkPlatformFile.cpp @@ -325,7 +325,7 @@ bool FStreamingNetworkPlatformFile::InitializeInternal(IPlatformFile* Inner, con // Send the filenames and timestamps to the server. FNetworkFileArchive Payload(NFS_Messages::GetFileList); - FillGetFileList(Payload, true); + FillGetFileList(Payload); // Send the directories over, and wait for a response. FArrayReader Response; diff --git a/Engine/Source/Runtime/StreamingFile/Public/StreamingNetworkPlatformFile.h b/Engine/Source/Runtime/StreamingFile/Public/StreamingNetworkPlatformFile.h index 56747395ace1..224cbe5ac1a4 100644 --- a/Engine/Source/Runtime/StreamingFile/Public/StreamingNetworkPlatformFile.h +++ b/Engine/Source/Runtime/StreamingFile/Public/StreamingNetworkPlatformFile.h @@ -131,7 +131,11 @@ class STREAMINGFILE_API FStreamingNetworkPlatformFile public: /** Default Constructor */ - FStreamingNetworkPlatformFile() { }; + FStreamingNetworkPlatformFile() + { + HeartbeatFrequency = -1.0f; + ConnectionFlags |= EConnectionFlags::Streaming; + } /** Virtual destructor */ virtual ~FStreamingNetworkPlatformFile(); diff --git a/Engine/Source/Runtime/SynthBenchmark/Private/SynthBenchmarkPrivate.cpp b/Engine/Source/Runtime/SynthBenchmark/Private/SynthBenchmarkPrivate.cpp index d531a8f1b258..b5da040f5d8b 100644 --- a/Engine/Source/Runtime/SynthBenchmark/Private/SynthBenchmarkPrivate.cpp +++ b/Engine/Source/Runtime/SynthBenchmark/Private/SynthBenchmarkPrivate.cpp @@ -10,9 +10,6 @@ float RayIntersectBenchmark(); float FractalBenchmark(); - -DEFINE_LOG_CATEGORY_STATIC(LogSynthBenchmark, Log, All); - // to prevent compiler optimizations static float GGlobalStateObject = 0.0f; diff --git a/Engine/Source/Runtime/UMG/Private/Components/Border.cpp b/Engine/Source/Runtime/UMG/Private/Components/Border.cpp index 49753472ee68..2a0566b13be9 100644 --- a/Engine/Source/Runtime/UMG/Private/Components/Border.cpp +++ b/Engine/Source/Runtime/UMG/Private/Components/Border.cpp @@ -57,7 +57,7 @@ void UBorder::SynchronizeProperties() { Super::SynchronizeProperties(); - TAttribute ContentColorAndOpacityBinding = OPTIONAL_BINDING(FLinearColor, ContentColorAndOpacity); + TAttribute ContentColorAndOpacityBinding = PROPERTY_BINDING(FLinearColor, ContentColorAndOpacity); TAttribute BrushColorBinding = OPTIONAL_BINDING_CONVERT(FLinearColor, BrushColor, FSlateColor, ConvertLinearColorToSlateColor); TAttribute ImageBinding = OPTIONAL_BINDING_CONVERT(FSlateBrush, Background, const FSlateBrush*, ConvertImage); diff --git a/Engine/Source/Runtime/UMG/Private/Components/Button.cpp b/Engine/Source/Runtime/UMG/Private/Components/Button.cpp index 4a85661df2c6..3a750bfab0b1 100644 --- a/Engine/Source/Runtime/UMG/Private/Components/Button.cpp +++ b/Engine/Source/Runtime/UMG/Private/Components/Button.cpp @@ -123,6 +123,33 @@ bool UButton::IsPressed() const return false; } +void UButton::SetClickMethod(EButtonClickMethod::Type InClickMethod) +{ + ClickMethod = InClickMethod; + if ( MyButton.IsValid() ) + { + MyButton->SetClickMethod(ClickMethod); + } +} + +void UButton::SetTouchMethod(EButtonTouchMethod::Type InTouchMethod) +{ + TouchMethod = InTouchMethod; + if ( MyButton.IsValid() ) + { + MyButton->SetTouchMethod(TouchMethod); + } +} + +//void UButton::SetPressMethod(EButtonPressMethod::Type InPressMethod) +//{ +// PressMethod = InPressMethod; +// if ( MyButton.IsValid() ) +// { +// MyButton->SetPressMethod(PressMethod); +// } +//} + void UButton::PostLoad() { Super::PostLoad(); diff --git a/Engine/Source/Runtime/UMG/Private/Components/CheckBox.cpp b/Engine/Source/Runtime/UMG/Private/Components/CheckBox.cpp index a7b36bafb8fe..f6ca021ed85d 100644 --- a/Engine/Source/Runtime/UMG/Private/Components/CheckBox.cpp +++ b/Engine/Source/Runtime/UMG/Private/Components/CheckBox.cpp @@ -57,7 +57,7 @@ void UCheckBox::SynchronizeProperties() Super::SynchronizeProperties(); MyCheckbox->SetStyle(&WidgetStyle); - MyCheckbox->SetIsChecked( OPTIONAL_BINDING(ECheckBoxState, CheckedState) ); + MyCheckbox->SetIsChecked( PROPERTY_BINDING(ECheckBoxState, CheckedState) ); } void UCheckBox::OnSlotAdded(UPanelSlot* InSlot) @@ -113,7 +113,7 @@ void UCheckBox::SetIsChecked(bool InIsChecked) CheckedState = InIsChecked ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; if ( MyCheckbox.IsValid() ) { - MyCheckbox->SetIsChecked(OPTIONAL_BINDING(ECheckBoxState, CheckedState)); + MyCheckbox->SetIsChecked(PROPERTY_BINDING(ECheckBoxState, CheckedState)); } } @@ -122,7 +122,7 @@ void UCheckBox::SetCheckedState(ECheckBoxState InCheckedState) CheckedState = InCheckedState; if ( MyCheckbox.IsValid() ) { - MyCheckbox->SetIsChecked(OPTIONAL_BINDING(ECheckBoxState, CheckedState)); + MyCheckbox->SetIsChecked(PROPERTY_BINDING(ECheckBoxState, CheckedState)); } } diff --git a/Engine/Source/Runtime/UMG/Private/Components/ComboBoxString.cpp b/Engine/Source/Runtime/UMG/Private/Components/ComboBoxString.cpp index 2b9ba7b40b12..53588dbcf980 100644 --- a/Engine/Source/Runtime/UMG/Private/Components/ComboBoxString.cpp +++ b/Engine/Source/Runtime/UMG/Private/Components/ComboBoxString.cpp @@ -46,6 +46,17 @@ UComboBoxString::UComboBoxString(const FObjectInitializer& ObjectInitializer) } } +void UComboBoxString::PostInitProperties() +{ + Super::PostInitProperties(); + + // Initialize the set of options from the default set only once. + for (const FString& DefaultOption : DefaultOptions) + { + AddOption(DefaultOption); + } +} + void UComboBoxString::ReleaseSlateResources(bool bReleaseChildren) { Super::ReleaseSlateResources(bReleaseChildren); @@ -59,7 +70,7 @@ void UComboBoxString::PostLoad() Super::PostLoad(); // Initialize the set of options from the default set only once. - for ( const FString& DefaultOption : DefaultOptions ) + for (const FString& DefaultOption : DefaultOptions) { AddOption(DefaultOption); } @@ -68,8 +79,6 @@ void UComboBoxString::PostLoad() { EnableGamepadNavigationMode = false; } - - } TSharedRef UComboBoxString::RebuildWidget() diff --git a/Engine/Source/Runtime/UMG/Private/Components/EditableText.cpp b/Engine/Source/Runtime/UMG/Private/Components/EditableText.cpp index 73a1df56b8bb..ff5853c334fd 100644 --- a/Engine/Source/Runtime/UMG/Private/Components/EditableText.cpp +++ b/Engine/Source/Runtime/UMG/Private/Components/EditableText.cpp @@ -66,8 +66,8 @@ void UEditableText::SynchronizeProperties() { Super::SynchronizeProperties(); - TAttribute TextBinding = OPTIONAL_BINDING(FText, Text); - TAttribute HintTextBinding = OPTIONAL_BINDING(FText, HintText); + TAttribute TextBinding = PROPERTY_BINDING(FText, Text); + TAttribute HintTextBinding = PROPERTY_BINDING(FText, HintText); MyEditableText->SetText(TextBinding); MyEditableText->SetHintText(HintTextBinding); diff --git a/Engine/Source/Runtime/UMG/Private/Components/EditableTextBox.cpp b/Engine/Source/Runtime/UMG/Private/Components/EditableTextBox.cpp index 1f0d01094950..e48b949011a2 100644 --- a/Engine/Source/Runtime/UMG/Private/Components/EditableTextBox.cpp +++ b/Engine/Source/Runtime/UMG/Private/Components/EditableTextBox.cpp @@ -69,8 +69,8 @@ void UEditableTextBox::SynchronizeProperties() { Super::SynchronizeProperties(); - TAttribute TextBinding = OPTIONAL_BINDING(FText, Text); - TAttribute HintTextBinding = OPTIONAL_BINDING(FText, HintText); + TAttribute TextBinding = PROPERTY_BINDING(FText, Text); + TAttribute HintTextBinding = PROPERTY_BINDING(FText, HintText); MyEditableTextBlock->SetStyle(&WidgetStyle); MyEditableTextBlock->SetText(TextBinding); diff --git a/Engine/Source/Runtime/UMG/Private/Components/Image.cpp b/Engine/Source/Runtime/UMG/Private/Components/Image.cpp index ee6cf5870722..9ed40bc7743a 100644 --- a/Engine/Source/Runtime/UMG/Private/Components/Image.cpp +++ b/Engine/Source/Runtime/UMG/Private/Components/Image.cpp @@ -48,7 +48,7 @@ void UImage::SynchronizeProperties() { Super::SynchronizeProperties(); - TAttribute ColorAndOpacityBinding = OPTIONAL_BINDING(FSlateColor, ColorAndOpacity); + TAttribute ColorAndOpacityBinding = PROPERTY_BINDING(FSlateColor, ColorAndOpacity); TAttribute ImageBinding = OPTIONAL_BINDING_CONVERT(FSlateBrush, Brush, const FSlateBrush*, ConvertImage); if (MyImage.IsValid()) diff --git a/Engine/Source/Runtime/UMG/Private/Components/InputKeySelector.cpp b/Engine/Source/Runtime/UMG/Private/Components/InputKeySelector.cpp index 66198b114947..0491416c2a90 100644 --- a/Engine/Source/Runtime/UMG/Private/Components/InputKeySelector.cpp +++ b/Engine/Source/Runtime/UMG/Private/Components/InputKeySelector.cpp @@ -1,18 +1,52 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "Components/InputKeySelector.h" +#include "Engine/Font.h" +#include "UObject/ConstructorHelpers.h" +#include "UObject/FrameworkObjectVersion.h" #include "Widgets/DeclarativeSyntaxSupport.h" #include "Widgets/Input/SInputKeySelector.h" UInputKeySelector::UInputKeySelector( const FObjectInitializer& ObjectInitializer ) + : Super(ObjectInitializer) { SInputKeySelector::FArguments InputKeySelectorDefaults; + WidgetStyle = *InputKeySelectorDefaults._ButtonStyle; + TextStyle = *InputKeySelectorDefaults._TextStyle; + KeySelectionText = InputKeySelectorDefaults._KeySelectionText; + NoKeySpecifiedText = InputKeySelectorDefaults._NoKeySpecifiedText; SelectedKey = InputKeySelectorDefaults._SelectedKey.Get(); - ButtonStyle = InputKeySelectorDefaults._ButtonStyle; bAllowModifierKeys = InputKeySelectorDefaults._AllowModifierKeys; + bAllowGamepadKeys = InputKeySelectorDefaults._AllowGamepadKeys; + + EscapeKeys.AddUnique(EKeys::Gamepad_Special_Right); // In most (if not all) cases this is going to be the menu button + + if (!IsRunningDedicatedServer()) + { + static ConstructorHelpers::FObjectFinder RobotoFontObj(TEXT("/Engine/EngineFonts/Roboto")); + TextStyle.Font = FSlateFontInfo(RobotoFontObj.Object, 24, FName("Bold")); + } } -void UInputKeySelector::SetSelectedKey( FInputChord InSelectedKey ) +void UInputKeySelector::Serialize(FArchive& Ar) +{ + Super::Serialize(Ar); + + Ar.UsingCustomVersion(FFrameworkObjectVersion::GUID); +} + +void UInputKeySelector::PostLoad() +{ + Super::PostLoad(); + + if (GetLinkerCustomVersion(FFrameworkObjectVersion::GUID) < FFrameworkObjectVersion::InputKeySelectorTextStyle) + { + TextStyle.Font = Font_DEPRECATED; + TextStyle.ColorAndOpacity = ColorAndOpacity_DEPRECATED; + } +} + +void UInputKeySelector::SetSelectedKey( const FInputChord& InSelectedKey ) { if ( MyInputKeySelector.IsValid() ) { @@ -27,10 +61,19 @@ void UInputKeySelector::SetKeySelectionText( FText InKeySelectionText ) { MyInputKeySelector->SetKeySelectionText( InKeySelectionText ); } - KeySelectionText = InKeySelectionText; + KeySelectionText = MoveTemp(InKeySelectionText); } -void UInputKeySelector::SetAllowModifierKeys( bool bInAllowModifierKeys ) +void UInputKeySelector::SetNoKeySpecifiedText(FText InNoKeySpecifiedText) +{ + if (MyInputKeySelector.IsValid()) + { + MyInputKeySelector->SetNoKeySpecifiedText(InNoKeySpecifiedText); + } + NoKeySpecifiedText = MoveTemp(InNoKeySpecifiedText); +} + +void UInputKeySelector::SetAllowModifierKeys( const bool bInAllowModifierKeys ) { if ( MyInputKeySelector.IsValid() ) { @@ -39,6 +82,15 @@ void UInputKeySelector::SetAllowModifierKeys( bool bInAllowModifierKeys ) bAllowModifierKeys = bInAllowModifierKeys; } +void UInputKeySelector::SetAllowGamepadKeys(const bool bInAllowGamepadKeys) +{ + if (MyInputKeySelector.IsValid()) + { + MyInputKeySelector->SetAllowGamepadKeys(bInAllowGamepadKeys); + } + bAllowGamepadKeys = bInAllowGamepadKeys; +} + bool UInputKeySelector::GetIsSelectingKey() const { return MyInputKeySelector.IsValid() ? MyInputKeySelector->GetIsSelectingKey() : false; @@ -48,9 +100,9 @@ void UInputKeySelector::SetButtonStyle( const FButtonStyle* InButtonStyle ) { if ( MyInputKeySelector.IsValid() ) { - MyInputKeySelector->SetButtonStyle( ButtonStyle ); + MyInputKeySelector->SetButtonStyle(InButtonStyle); } - ButtonStyle = InButtonStyle; + WidgetStyle = *InButtonStyle; } void UInputKeySelector::SynchronizeProperties() @@ -58,24 +110,33 @@ void UInputKeySelector::SynchronizeProperties() Super::SynchronizeProperties(); MyInputKeySelector->SetSelectedKey( SelectedKey ); - MyInputKeySelector->SetFont( Font ); MyInputKeySelector->SetMargin( Margin ); - MyInputKeySelector->SetColorAndOpacity( ColorAndOpacity ); - MyInputKeySelector->SetButtonStyle( ButtonStyle ); + MyInputKeySelector->SetButtonStyle( &WidgetStyle ); + MyInputKeySelector->SetTextStyle( &TextStyle ); MyInputKeySelector->SetKeySelectionText( KeySelectionText ); MyInputKeySelector->SetAllowModifierKeys( bAllowModifierKeys ); + MyInputKeySelector->SetAllowGamepadKeys(bAllowGamepadKeys); + MyInputKeySelector->SetEscapeKeys(EscapeKeys); +} + +void UInputKeySelector::ReleaseSlateResources(bool bReleaseChildren) +{ + Super::ReleaseSlateResources(bReleaseChildren); + + MyInputKeySelector.Reset(); } TSharedRef UInputKeySelector::RebuildWidget() { MyInputKeySelector = SNew(SInputKeySelector) .SelectedKey(SelectedKey) - .Font(Font) .Margin(Margin) - .ColorAndOpacity(ColorAndOpacity) - .ButtonStyle(ButtonStyle) + .ButtonStyle(&WidgetStyle) + .TextStyle(&TextStyle) .KeySelectionText(KeySelectionText) .AllowModifierKeys(bAllowModifierKeys) + .AllowGamepadKeys(bAllowGamepadKeys) + .EscapeKeys(EscapeKeys) .OnKeySelected( BIND_UOBJECT_DELEGATE( SInputKeySelector::FOnKeySelected, HandleKeySelected ) ) .OnIsSelectingKeyChanged( BIND_UOBJECT_DELEGATE( SInputKeySelector::FOnIsSelectingKeyChanged, HandleIsSelectingKeyChanged ) ); return MyInputKeySelector.ToSharedRef(); diff --git a/Engine/Source/Runtime/UMG/Private/Components/ListView.cpp b/Engine/Source/Runtime/UMG/Private/Components/ListView.cpp index 82d372326b4b..f7f024cc52cb 100644 --- a/Engine/Source/Runtime/UMG/Private/Components/ListView.cpp +++ b/Engine/Source/Runtime/UMG/Private/Components/ListView.cpp @@ -61,6 +61,7 @@ TSharedRef UListView::HandleOnGenerateRow(UObject* Item, const TShare ]; } + #if WITH_EDITOR const FText UListView::GetPaletteCategory() diff --git a/Engine/Source/Runtime/UMG/Private/Components/MultiLineEditableText.cpp b/Engine/Source/Runtime/UMG/Private/Components/MultiLineEditableText.cpp index 80ff205d77cd..bb7aa8394118 100644 --- a/Engine/Source/Runtime/UMG/Private/Components/MultiLineEditableText.cpp +++ b/Engine/Source/Runtime/UMG/Private/Components/MultiLineEditableText.cpp @@ -63,7 +63,7 @@ void UMultiLineEditableText::SynchronizeProperties() { Super::SynchronizeProperties(); - TAttribute HintTextBinding = OPTIONAL_BINDING(FText, HintText); + TAttribute HintTextBinding = PROPERTY_BINDING(FText, HintText); MyMultiLineEditableText->SetTextStyle(&WidgetStyle); MyMultiLineEditableText->SetText(Text); diff --git a/Engine/Source/Runtime/UMG/Private/Components/MultiLineEditableTextBox.cpp b/Engine/Source/Runtime/UMG/Private/Components/MultiLineEditableTextBox.cpp index cb2218ced0f9..3cfb03104b7d 100644 --- a/Engine/Source/Runtime/UMG/Private/Components/MultiLineEditableTextBox.cpp +++ b/Engine/Source/Runtime/UMG/Private/Components/MultiLineEditableTextBox.cpp @@ -69,7 +69,7 @@ void UMultiLineEditableTextBox::SynchronizeProperties() { Super::SynchronizeProperties(); - TAttribute HintTextBinding = OPTIONAL_BINDING(FText, HintText); + TAttribute HintTextBinding = PROPERTY_BINDING(FText, HintText); MyEditableTextBlock->SetStyle(&WidgetStyle); MyEditableTextBlock->SetText(Text); diff --git a/Engine/Source/Runtime/UMG/Private/Components/PanelWidget.cpp b/Engine/Source/Runtime/UMG/Private/Components/PanelWidget.cpp index 302ae70c1e19..3660681516d8 100644 --- a/Engine/Source/Runtime/UMG/Private/Components/PanelWidget.cpp +++ b/Engine/Source/Runtime/UMG/Private/Components/PanelWidget.cpp @@ -123,10 +123,7 @@ UPanelSlot* UPanelWidget::AddChild(UWidget* Content) PanelSlot->Content = Content; PanelSlot->Parent = this; - if ( Content ) - { - Content->Slot = PanelSlot; - } + Content->Slot = PanelSlot; Slots.Add(PanelSlot); diff --git a/Engine/Source/Runtime/UMG/Private/Components/ProgressBar.cpp b/Engine/Source/Runtime/UMG/Private/Components/ProgressBar.cpp index 3bfc68e5253b..2520c97fc768 100644 --- a/Engine/Source/Runtime/UMG/Private/Components/ProgressBar.cpp +++ b/Engine/Source/Runtime/UMG/Private/Components/ProgressBar.cpp @@ -41,7 +41,7 @@ void UProgressBar::SynchronizeProperties() Super::SynchronizeProperties(); TAttribute< TOptional > PercentBinding = OPTIONAL_BINDING_CONVERT(float, Percent, TOptional, ConvertFloatToOptionalFloat); - TAttribute FillColorAndOpacityBinding = OPTIONAL_BINDING(FSlateColor, FillColorAndOpacity); + TAttribute FillColorAndOpacityBinding = PROPERTY_BINDING(FSlateColor, FillColorAndOpacity); MyProgressBar->SetStyle(&WidgetStyle); diff --git a/Engine/Source/Runtime/UMG/Private/Components/RichTextBlock.cpp b/Engine/Source/Runtime/UMG/Private/Components/RichTextBlock.cpp index 7c39b58c7ac0..9d742eeb6c59 100644 --- a/Engine/Source/Runtime/UMG/Private/Components/RichTextBlock.cpp +++ b/Engine/Source/Runtime/UMG/Private/Components/RichTextBlock.cpp @@ -5,7 +5,6 @@ #include "Engine/Font.h" #include "Widgets/DeclarativeSyntaxSupport.h" #include "Widgets/Text/SRichTextBlock.h" - #include "Components/RichTextBlockDecorator.h" #define LOCTEXT_NAMESPACE "UMG" @@ -22,8 +21,6 @@ URichTextBlock::URichTextBlock(const FObjectInitializer& ObjectInitializer) Font = FSlateFontInfo(RobotoFontObj.Object, 12, FName("Regular")); } Color = FLinearColor::White; - - Decorators.Add(ObjectInitializer.CreateOptionalDefaultSubobject(this, FName("DefaultDecorator"))); } void URichTextBlock::ReleaseSlateResources(bool bReleaseChildren) @@ -64,7 +61,7 @@ void URichTextBlock::SynchronizeProperties() { Super::SynchronizeProperties(); - TAttribute TextBinding = OPTIONAL_BINDING(FText, Text); + TAttribute TextBinding = PROPERTY_BINDING(FText, Text); MyRichTextBlock->SetText(TextBinding); @@ -78,6 +75,11 @@ const FText URichTextBlock::GetPaletteCategory() return LOCTEXT("Common", "Common"); } +void URichTextBlock::OnCreationFromPalette() +{ + Decorators.Add(NewObject(this, NAME_None, RF_Transactional)); +} + #endif ///////////////////////////////////////////////////// diff --git a/Engine/Source/Runtime/UMG/Private/Components/RichTextBlockDecorator.cpp b/Engine/Source/Runtime/UMG/Private/Components/RichTextBlockDecorator.cpp index b56270347773..0f6ac51646cf 100644 --- a/Engine/Source/Runtime/UMG/Private/Components/RichTextBlockDecorator.cpp +++ b/Engine/Source/Runtime/UMG/Private/Components/RichTextBlockDecorator.cpp @@ -34,7 +34,7 @@ public: { const TArray< FTextLayout::FLineView >& Views = TextLayout->GetLineViews(); - int32 AbsoluteBeginIndex = Line.Range.BeginIndex; + int32 AbsoluteBeginIndex = 0; for ( int32 i = 0; i < Views.Num(); i++ ) { if ( Views[i].ModelIndex == Line.ModelIndex ) @@ -42,7 +42,7 @@ public: break; } - AbsoluteBeginIndex = Views[i].Range.Len(); + AbsoluteBeginIndex += Views[i].Range.Len(); } if ( AbsoluteBeginIndex < RichBlock->RevealedIndex ) diff --git a/Engine/Source/Runtime/UMG/Private/Components/ScaleBox.cpp b/Engine/Source/Runtime/UMG/Private/Components/ScaleBox.cpp index 9458e2a02095..14e9db9d8498 100644 --- a/Engine/Source/Runtime/UMG/Private/Components/ScaleBox.cpp +++ b/Engine/Source/Runtime/UMG/Private/Components/ScaleBox.cpp @@ -18,6 +18,7 @@ UScaleBox::UScaleBox(const FObjectInitializer& ObjectInitializer) Stretch = EStretch::ScaleToFit; UserSpecifiedScale = 1.0f; IgnoreInheritedScale = false; + bSingleLayoutPass = false; } void UScaleBox::ReleaseSlateResources(bool bReleaseChildren) @@ -29,11 +30,12 @@ void UScaleBox::ReleaseSlateResources(bool bReleaseChildren) TSharedRef UScaleBox::RebuildWidget() { - MyScaleBox = SNew(SScaleBox); + MyScaleBox = SNew(SScaleBox) + .SingleLayoutPass(bSingleLayoutPass); if ( GetChildrenCount() > 0 ) { - Cast(GetContentSlot())->BuildSlot(MyScaleBox.ToSharedRef()); + CastChecked(GetContentSlot())->BuildSlot(MyScaleBox.ToSharedRef()); } return BuildDesignTimeWidget( MyScaleBox.ToSharedRef() ); diff --git a/Engine/Source/Runtime/UMG/Private/Components/Slider.cpp b/Engine/Source/Runtime/UMG/Private/Components/Slider.cpp index 41a889518ab5..a86a4dc6673e 100644 --- a/Engine/Source/Runtime/UMG/Private/Components/Slider.cpp +++ b/Engine/Source/Runtime/UMG/Private/Components/Slider.cpp @@ -39,7 +39,7 @@ void USlider::SynchronizeProperties() { Super::SynchronizeProperties(); - TAttribute ValueBinding = OPTIONAL_BINDING(float, Value); + TAttribute ValueBinding = PROPERTY_BINDING(float, Value); MySlider->SetOrientation(Orientation); MySlider->SetSliderBarColor(SliderBarColor); diff --git a/Engine/Source/Runtime/UMG/Private/Components/SpinBox.cpp b/Engine/Source/Runtime/UMG/Private/Components/SpinBox.cpp index 88896aec68d5..2e75c27c01f2 100644 --- a/Engine/Source/Runtime/UMG/Private/Components/SpinBox.cpp +++ b/Engine/Source/Runtime/UMG/Private/Components/SpinBox.cpp @@ -76,7 +76,7 @@ void USpinBox::SynchronizeProperties() bOverride_MaxSliderValue ? SetMaxSliderValue(MaxSliderValue) : ClearMaxSliderValue(); // Always set the value last so that the max/min values are taken into account. - TAttribute ValueBinding = OPTIONAL_BINDING(float, Value); + TAttribute ValueBinding = PROPERTY_BINDING(float, Value); MySpinBox->SetValue(ValueBinding); } diff --git a/Engine/Source/Runtime/UMG/Private/Components/TextBlock.cpp b/Engine/Source/Runtime/UMG/Private/Components/TextBlock.cpp index 9cbb967d17b9..e79f312705a0 100644 --- a/Engine/Source/Runtime/UMG/Private/Components/TextBlock.cpp +++ b/Engine/Source/Runtime/UMG/Private/Components/TextBlock.cpp @@ -131,12 +131,12 @@ void UTextBlock::OnBindingChanged(const FName& Property) } else if ( Property == ColorAndOpacityProperty ) { - TAttribute ColorAndOpacityBinding = OPTIONAL_BINDING(FSlateColor, ColorAndOpacity); + TAttribute ColorAndOpacityBinding = PROPERTY_BINDING(FSlateColor, ColorAndOpacity); MyTextBlock->SetColorAndOpacity(ColorAndOpacityBinding); } else if ( Property == ShadowColorAndOpacityProperty ) { - TAttribute ShadowColorAndOpacityBinding = OPTIONAL_BINDING(FLinearColor, ShadowColorAndOpacity); + TAttribute ShadowColorAndOpacityBinding = PROPERTY_BINDING(FLinearColor, ShadowColorAndOpacity); MyTextBlock->SetShadowColorAndOpacity(ShadowColorAndOpacityBinding); } } @@ -147,8 +147,8 @@ void UTextBlock::SynchronizeProperties() Super::SynchronizeProperties(); TAttribute TextBinding = GetDisplayText(); - TAttribute ColorAndOpacityBinding = OPTIONAL_BINDING(FSlateColor, ColorAndOpacity); - TAttribute ShadowColorAndOpacityBinding = OPTIONAL_BINDING(FLinearColor, ShadowColorAndOpacity); + TAttribute ColorAndOpacityBinding = PROPERTY_BINDING(FSlateColor, ColorAndOpacity); + TAttribute ShadowColorAndOpacityBinding = PROPERTY_BINDING(FLinearColor, ShadowColorAndOpacity); if ( MyTextBlock.IsValid() ) { @@ -163,6 +163,8 @@ void UTextBlock::SynchronizeProperties() } } +/// @cond DOXYGEN_WARNINGS + FText UTextBlock::GetText() const { if (MyTextBlock.IsValid()) @@ -173,6 +175,8 @@ FText UTextBlock::GetText() const return Text; } +/// @endcond + void UTextBlock::SetText(FText InText) { Text = InText; @@ -186,7 +190,7 @@ void UTextBlock::SetText(FText InText) TAttribute UTextBlock::GetDisplayText() { - return OPTIONAL_BINDING(FText, Text); + return PROPERTY_BINDING(FText, Text); } #if WITH_EDITOR diff --git a/Engine/Source/Runtime/UMG/Private/Components/Widget.cpp b/Engine/Source/Runtime/UMG/Private/Components/Widget.cpp index 3a5cff36949f..ce975255f204 100644 --- a/Engine/Source/Runtime/UMG/Private/Components/Widget.cpp +++ b/Engine/Source/Runtime/UMG/Private/Components/Widget.cpp @@ -600,6 +600,17 @@ void UWidget::RemoveFromParent() { CurrentParent->RemoveChild(this); } + else + { +#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) + if ( GetCachedWidget().IsValid() ) + { + FText WarningMessage = FText::Format(LOCTEXT("RemoveFromParentWithNoParent", "UWidget::RemoveFromParent() called on '{0}' which has no UMG parent (if it was added directly to a native Slate widget via TakeWidget() then it must be removed explicitly rather than via RemoveFromParent())"), FText::AsCultureInvariant(GetPathName())); + // @todo: nickd - we need to switch this back to a warning in engine, but info for games + FMessageLog("PIE").Info(WarningMessage); + } +#endif + } } const FGeometry& UWidget::GetCachedGeometry() const @@ -936,10 +947,10 @@ void UWidget::SynchronizeProperties() { if ( bOverride_Cursor /*|| CursorDelegate.IsBound()*/ ) { - SafeWidget->SetCursor(Cursor);// GAME_SAFE_OPTIONAL_BINDING(EMouseCursor::Type, Cursor)); + SafeWidget->SetCursor(Cursor);// PROPERTY_BINDING(EMouseCursor::Type, Cursor)); } - SafeWidget->SetEnabled(GAME_SAFE_OPTIONAL_BINDING( bool, bIsEnabled )); + SafeWidget->SetEnabled(PROPERTY_BINDING( bool, bIsEnabled )); SafeWidget->SetVisibility(OPTIONAL_BINDING_CONVERT(ESlateVisibility, Visibility, EVisibility, ConvertVisibility)); } @@ -967,17 +978,17 @@ void UWidget::SynchronizeProperties() } else if ( !ToolTipText.IsEmpty() || ToolTipTextDelegate.IsBound() ) { - SafeWidget->SetToolTipText(GAME_SAFE_OPTIONAL_BINDING(FText, ToolTipText)); + SafeWidget->SetToolTipText(PROPERTY_BINDING(FText, ToolTipText)); } -#if WITH_EDITORONLY_DATA +#if WITH_EDITOR // In editor builds we add metadata to the widget so that once hit with the widget reflector it can report // where it comes from, what blueprint, what the name of the widget was...etc. - SafeWidget->AddMetadata(MakeShared(GetFName(), GetClass(), WidgetGeneratedBy.Get())); + SafeWidget->AddMetadata(MakeShared(GetFName(), GetClass(), this, WidgetGeneratedBy.Get())); #else #if !UE_BUILD_SHIPPING - SafeWidget->AddMetadata(MakeShared(GetFName(), GetClass(), WidgetGeneratedByClass.Get())); + SafeWidget->AddMetadata(MakeShared(GetFName(), GetClass(), this, WidgetGeneratedByClass.Get())); #endif #endif diff --git a/Engine/Source/Runtime/UMG/Private/Components/WidgetComponent.cpp b/Engine/Source/Runtime/UMG/Private/Components/WidgetComponent.cpp index 69602ef6780a..dcafef8a4b50 100644 --- a/Engine/Source/Runtime/UMG/Private/Components/WidgetComponent.cpp +++ b/Engine/Source/Runtime/UMG/Private/Components/WidgetComponent.cpp @@ -612,7 +612,7 @@ FPrimitiveSceneProxy* UWidgetComponent::CreateSceneProxy() MaterialInstance = nullptr; } - if ( Space != EWidgetSpace::Screen && WidgetRenderer.IsValid() ) + if ( Space != EWidgetSpace::Screen && WidgetRenderer.IsValid() && WidgetClass.Get() != nullptr ) { // Create a new MID for the current base material { @@ -628,8 +628,60 @@ FPrimitiveSceneProxy* UWidgetComponent::CreateSceneProxy() return new FWidget3DSceneProxy(this, *WidgetRenderer->GetSlateRenderer()); } - - return nullptr; + + // make something so we can see this component in the editor + class FWidgetBoxProxy : public FPrimitiveSceneProxy + { + public: + FWidgetBoxProxy(const UWidgetComponent* InComponent) + : FPrimitiveSceneProxy(InComponent) + , BoxExtents(1.f, InComponent->GetDrawSize().X / 2.0f, InComponent->GetDrawSize().Y / 2.0f) + { + bWillEverBeLit = false; + } + + virtual void GetDynamicMeshElements(const TArray& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const override + { + QUICK_SCOPE_CYCLE_COUNTER(STAT_BoxSceneProxy_GetDynamicMeshElements); + + const FMatrix& LocalToWorld = GetLocalToWorld(); + + for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) + { + if (VisibilityMap & (1 << ViewIndex)) + { + const FSceneView* View = Views[ViewIndex]; + + const FLinearColor DrawColor = GetViewSelectionColor(FColor::White, *View, IsSelected(), IsHovered(), false, IsIndividuallySelected()); + + FPrimitiveDrawInterface* PDI = Collector.GetPDI(ViewIndex); + DrawOrientedWireBox(PDI, LocalToWorld.GetOrigin(), LocalToWorld.GetScaledAxis(EAxis::X), LocalToWorld.GetScaledAxis(EAxis::Y), LocalToWorld.GetScaledAxis(EAxis::Z), BoxExtents, DrawColor, SDPG_World); + } + } + } + + virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView* View) const override + { + FPrimitiveViewRelevance Result; + if (!View->bIsGameView) + { + // Should we draw this because collision drawing is enabled, and we have collision + const bool bShowForCollision = View->Family->EngineShowFlags.Collision && IsCollisionEnabled(); + Result.bDrawRelevance = IsShown(View) || bShowForCollision; + Result.bDynamicRelevance = true; + Result.bShadowRelevance = IsShadowCast(View); + Result.bEditorPrimitiveRelevance = UseEditorCompositing(View); + } + return Result; + } + virtual uint32 GetMemoryFootprint(void) const override { return(sizeof(*this) + GetAllocatedSize()); } + uint32 GetAllocatedSize(void) const { return(FPrimitiveSceneProxy::GetAllocatedSize()); } + + private: + const FVector BoxExtents; + }; + + return new FWidgetBoxProxy(this); } FBoxSphereBounds UWidgetComponent::CalcBounds(const FTransform & LocalToWorld) const @@ -666,7 +718,7 @@ FCollisionShape UWidgetComponent::GetCollisionShape(float Inflation) const { if ( Space != EWidgetSpace::Screen ) { - FVector BoxHalfExtent = ( FVector(0.01f, DrawSize.X * 0.5f, DrawSize.Y * 0.5f) * ComponentToWorld.GetScale3D() ) + Inflation; + FVector BoxHalfExtent = ( FVector(0.01f, DrawSize.X * 0.5f, DrawSize.Y * 0.5f) * GetComponentTransform().GetScale3D() ) + Inflation; if ( Inflation < 0.0f ) { @@ -1103,9 +1155,24 @@ bool UWidgetComponent::CanEditChange(const UProperty* InProperty) const { FString PropertyName = InProperty->GetName(); + if ( PropertyName == GET_MEMBER_NAME_STRING_CHECKED(UWidgetComponent, GeometryMode) || + PropertyName == GET_MEMBER_NAME_STRING_CHECKED(UWidgetComponent, TimingPolicy) || + PropertyName == GET_MEMBER_NAME_STRING_CHECKED(UWidgetComponent, bWindowFocusable) || + PropertyName == GET_MEMBER_NAME_STRING_CHECKED(UWidgetComponent, bManuallyRedraw) || + PropertyName == GET_MEMBER_NAME_STRING_CHECKED(UWidgetComponent, RedrawTime) || + PropertyName == GET_MEMBER_NAME_STRING_CHECKED(UWidgetComponent, BackgroundColor) || + PropertyName == GET_MEMBER_NAME_STRING_CHECKED(UWidgetComponent, TintColorAndOpacity) || + PropertyName == GET_MEMBER_NAME_STRING_CHECKED(UWidgetComponent, OpacityFromTexture) || + PropertyName == GET_MEMBER_NAME_STRING_CHECKED(UWidgetComponent, BlendMode) || + PropertyName == GET_MEMBER_NAME_STRING_CHECKED(UWidgetComponent, bIsTwoSided) || + PropertyName == GET_MEMBER_NAME_STRING_CHECKED(UWidgetComponent, TickWhenOffscreen) ) + { + return Space != EWidgetSpace::Screen; + } + if ( PropertyName == GET_MEMBER_NAME_STRING_CHECKED(UWidgetComponent, bReceiveHardwareInput) ) { - return GeometryMode == EWidgetGeometryMode::Plane; + return Space != EWidgetSpace::Screen && GeometryMode == EWidgetGeometryMode::Plane; } if ( PropertyName == GET_MEMBER_NAME_STRING_CHECKED(UWidgetComponent, CylinderArcAngle) ) @@ -1306,8 +1373,10 @@ void UWidgetComponent::UpdateRenderTarget(FIntPoint DesiredRenderTargetSize) { case EWidgetBlendMode::Opaque: ActualBackgroundColor.A = 1.0f; + break; case EWidgetBlendMode::Masked: ActualBackgroundColor.A = 0.0f; + break; } if ( DesiredRenderTargetSize.X != 0 && DesiredRenderTargetSize.Y != 0 ) @@ -1403,7 +1472,7 @@ void UWidgetComponent::GetLocalHitLocation(FVector WorldHitLocation, FVector2D& ensureMsgf(GeometryMode == EWidgetGeometryMode::Plane, TEXT("Method does not support non-planar widgets.")); // Find the hit location on the component - FVector ComponentHitLocation = ComponentToWorld.InverseTransformPosition(WorldHitLocation); + FVector ComponentHitLocation = GetComponentTransform().InverseTransformPosition(WorldHitLocation); // Convert the 3D position of component space, into the 2D equivalent OutLocalWidgetHitLocation = FVector2D(-ComponentHitLocation.Y, -ComponentHitLocation.Z); @@ -1455,8 +1524,8 @@ TTuple UWidgetComponent::GetCylinderHitLocation(FVector Worl FTransform ToWorld = GetComponentToWorld(); - const FVector HitLocation_ComponentSpace = ComponentToWorld.InverseTransformPosition(WorldHitLocation); - const FVector HitDirection_ComponentSpace = ComponentToWorld.InverseTransformVector(WorldHitDirection); + const FVector HitLocation_ComponentSpace = GetComponentTransform().InverseTransformPosition(WorldHitLocation); + const FVector HitDirection_ComponentSpace = GetComponentTransform().InverseTransformVector(WorldHitDirection); const float ArcAngleRadians = FMath::DegreesToRadians(GetCylinderArcAngle()); @@ -1525,7 +1594,7 @@ TTuple UWidgetComponent::GetCylinderHitLocation(FVector Worl const FVector2D WidgetSpaceHitCoord = FVector2D(HitAngleZeroToOne * CurrentDrawSize.X, YHitLocation); - return MakeTuple(ComponentToWorld.TransformPosition(CylinderHitLocation_ComponentSpace), WidgetSpaceHitCoord); + return MakeTuple(GetComponentTransform().TransformPosition(CylinderHitLocation_ComponentSpace), WidgetSpaceHitCoord); } else { diff --git a/Engine/Source/Runtime/UMG/Private/Components/WidgetInteractionComponent.cpp b/Engine/Source/Runtime/UMG/Private/Components/WidgetInteractionComponent.cpp index 70a6f8d8f4fb..d9d8460d107b 100644 --- a/Engine/Source/Runtime/UMG/Private/Components/WidgetInteractionComponent.cpp +++ b/Engine/Source/Runtime/UMG/Private/Components/WidgetInteractionComponent.cpp @@ -475,17 +475,14 @@ bool UWidgetInteractionComponent::PressKey(FKey Key, bool bRepeat) return false; } - const uint32* KeyCodePtr; - const uint32* CharCodePtr; - FInputKeyManager::Get().GetCodesFromKey(Key, KeyCodePtr, CharCodePtr); - - uint32 KeyCode = KeyCodePtr ? *KeyCodePtr : 0; - uint32 CharCode = CharCodePtr ? *CharCodePtr : 0; + bool bHasKeyCode, bHasCharCode; + uint32 KeyCode, CharCode; + GetKeyAndCharCodes(Key, bHasKeyCode, KeyCode, bHasCharCode, CharCode); FKeyEvent KeyEvent(Key, ModifierKeys, VirtualUser->GetUserIndex(), bRepeat, KeyCode, CharCode); bool DownResult = FSlateApplication::Get().ProcessKeyDownEvent(KeyEvent); - if ( CharCodePtr ) + if (bHasCharCode) { FCharacterEvent CharacterEvent(CharCode, ModifierKeys, VirtualUser->GetUserIndex(), bRepeat); return FSlateApplication::Get().ProcessKeyCharEvent(CharacterEvent); @@ -501,15 +498,46 @@ bool UWidgetInteractionComponent::ReleaseKey(FKey Key) return false; } + bool bHasKeyCode, bHasCharCode; + uint32 KeyCode, CharCode; + GetKeyAndCharCodes(Key, bHasKeyCode, KeyCode, bHasCharCode, CharCode); + + FKeyEvent KeyEvent(Key, ModifierKeys, VirtualUser->GetUserIndex(), false, KeyCode, CharCode); + return FSlateApplication::Get().ProcessKeyUpEvent(KeyEvent); +} + +void UWidgetInteractionComponent::GetKeyAndCharCodes(const FKey& Key, bool& bHasKeyCode, uint32& KeyCode, bool& bHasCharCode, uint32& CharCode) +{ const uint32* KeyCodePtr; const uint32* CharCodePtr; FInputKeyManager::Get().GetCodesFromKey(Key, KeyCodePtr, CharCodePtr); - uint32 KeyCode = KeyCodePtr ? *KeyCodePtr : 0; - uint32 CharCode = CharCodePtr ? *CharCodePtr : 0; + bHasKeyCode = KeyCodePtr ? true : false; + bHasCharCode = CharCodePtr ? true : false; - FKeyEvent KeyEvent(Key, ModifierKeys, VirtualUser->GetUserIndex(), false, KeyCode, CharCode); - return FSlateApplication::Get().ProcessKeyUpEvent(KeyEvent); + KeyCode = KeyCodePtr ? *KeyCodePtr : 0; + CharCode = CharCodePtr ? *CharCodePtr : 0; + + // These special keys are not handled by the platform layer, and while not printable + // have character mappings that several widgets look for, since the hardware sends them. + if (CharCodePtr == nullptr) + { + if (Key == EKeys::Tab) + { + CharCode = '\t'; + bHasCharCode = true; + } + else if (Key == EKeys::BackSpace) + { + CharCode = '\b'; + bHasCharCode = true; + } + else if (Key == EKeys::Enter) + { + CharCode = '\n'; + bHasCharCode = true; + } + } } bool UWidgetInteractionComponent::PressAndReleaseKey(FKey Key) diff --git a/Engine/Source/Runtime/UMG/Private/DragDropOperation.cpp b/Engine/Source/Runtime/UMG/Private/DragDropOperation.cpp index 3ef806cd4c10..1c2c192c5e5c 100644 --- a/Engine/Source/Runtime/UMG/Private/DragDropOperation.cpp +++ b/Engine/Source/Runtime/UMG/Private/DragDropOperation.cpp @@ -11,6 +11,8 @@ UDragDropOperation::UDragDropOperation(const FObjectInitializer& ObjectInitializ Pivot = EDragPivot::CenterCenter; } +/// @cond DOXYGEN_WARNINGS + void UDragDropOperation::Drop_Implementation(const FPointerEvent& PointerEvent) { OnDrop.Broadcast(this); @@ -25,3 +27,5 @@ void UDragDropOperation::Dragged_Implementation(const FPointerEvent& PointerEven { OnDragged.Broadcast(this); } + +/// @endcond diff --git a/Engine/Source/Runtime/UMG/Private/Slate/SObjectWidget.cpp b/Engine/Source/Runtime/UMG/Private/Slate/SObjectWidget.cpp index 963912642002..2676124819bb 100644 --- a/Engine/Source/Runtime/UMG/Private/Slate/SObjectWidget.cpp +++ b/Engine/Source/Runtime/UMG/Private/Slate/SObjectWidget.cpp @@ -462,3 +462,13 @@ FNavigationReply SObjectWidget::OnNavigation(const FGeometry& MyGeometry, const return Reply; } + +void SObjectWidget::OnMouseCaptureLost() +{ + SCompoundWidget::OnMouseCaptureLost(); + + if ( CanRouteEvent() ) + { + return WidgetObject->NativeOnMouseCaptureLost(); + } +} \ No newline at end of file diff --git a/Engine/Source/Runtime/UMG/Private/Slate/SRetainerWidget.cpp b/Engine/Source/Runtime/UMG/Private/Slate/SRetainerWidget.cpp index a02c43385a10..e5451cac56bc 100644 --- a/Engine/Source/Runtime/UMG/Private/Slate/SRetainerWidget.cpp +++ b/Engine/Source/Runtime/UMG/Private/Slate/SRetainerWidget.cpp @@ -40,8 +40,6 @@ static bool IsRetainedRenderingEnabled() SRetainerWidget::SRetainerWidget() : CachedWindowToDesktopTransform(0, 0) - // Use slate's gamma correction for mobile, as HW sRGB writes are not supported. - , WidgetRenderer( GMaxRHIFeatureLevel <= ERHIFeatureLevel::ES3_1 ) , DynamicEffect(nullptr) { } @@ -54,7 +52,18 @@ SRetainerWidget::~SRetainerWidget() OnRetainerModeChangedDelegate.RemoveAll( this ); #endif } - +} + +void SRetainerWidget::InitWidgetRenderer() +{ + // Use slate's gamma correction for dynamic materials on mobile, as HW sRGB writes are not supported. + bool bUseGammaCorrection = (DynamicEffect != nullptr) ? GMaxRHIFeatureLevel <= ERHIFeatureLevel::ES3_1 : true; + + if (!WidgetRenderer.IsValid() || WidgetRenderer->GetUseGammaCorrection() != bUseGammaCorrection) + { + WidgetRenderer = MakeShareable(new FWidgetRenderer(bUseGammaCorrection)); + WidgetRenderer->SetIsPrepassNeeded(false); + } } void SRetainerWidget::Construct(const FArguments& InArgs) @@ -65,8 +74,8 @@ void SRetainerWidget::Construct(const FArguments& InArgs) // Use HW sRGB correction for RT, ensuring it is linearised on read by material shaders // since SRetainerWidget::OnPaint renders the RT with gamma correction. - RenderTarget->SRGB = true; - RenderTarget->TargetGamma = 2.2f; + RenderTarget->SRGB = false; + RenderTarget->TargetGamma = 1.0f; RenderTarget->ClearColor = FLinearColor::Transparent; SurfaceBrush.SetResourceObject(RenderTarget); @@ -74,8 +83,7 @@ void SRetainerWidget::Construct(const FArguments& InArgs) Window = SNew(SVirtualWindow); Window->SetShouldResolveDeferred(false); HitTestGrid = MakeShareable(new FHittestGrid()); - - WidgetRenderer.SetIsPrepassNeeded(false); + InitWidgetRenderer(); MyWidget = InArgs._Content.Widget; Phase = InArgs._Phase; @@ -180,6 +188,7 @@ void SRetainerWidget::SetEffectMaterial(UMaterialInterface* EffectMaterial) DynamicEffect = nullptr; SurfaceBrush.SetResourceObject(RenderTarget); } + InitWidgetRenderer(); } void SRetainerWidget::SetTextureParameter(FName TextureParameter) @@ -269,10 +278,15 @@ void SRetainerWidget::PaintRetainedContent(float DeltaTime) { if ( MyWidget->GetVisibility().IsVisible() ) { + bool bDynamicMaterialInUse = (DynamicEffect != nullptr); if ( RenderTarget->GetSurfaceWidth() != RenderTargetWidth || - RenderTarget->GetSurfaceHeight() != RenderTargetHeight ) + RenderTarget->GetSurfaceHeight() != RenderTargetHeight || + RenderTarget->SRGB != bDynamicMaterialInUse + ) { const bool bForceLinearGamma = false; + RenderTarget->TargetGamma = bDynamicMaterialInUse ? 2.2f : 1.0f; + RenderTarget->SRGB = bDynamicMaterialInUse; RenderTarget->InitCustomFormat(RenderTargetWidth, RenderTargetHeight, PF_B8G8R8A8, bForceLinearGamma); RenderTarget->UpdateResourceImmediate(); } @@ -285,9 +299,9 @@ void SRetainerWidget::PaintRetainedContent(float DeltaTime) // Update the surface brush to match the latest size. SurfaceBrush.ImageSize = DrawSize; - WidgetRenderer.ViewOffset = -ViewOffset; + WidgetRenderer->ViewOffset = -ViewOffset; - WidgetRenderer.DrawWindow( + WidgetRenderer->DrawWindow( RenderTarget, HitTestGrid.ToSharedRef(), Window.ToSharedRef(), @@ -332,7 +346,8 @@ int32 SRetainerWidget::OnPaint(const FPaintArgs& Args, const FGeometry& Allotted // Retainer widget uses premultiplied alpha, so premultiply the color by the alpha to respect opacity. const FLinearColor PremultipliedColorAndOpacity(ComputedColorAndOpacity*ComputedColorAndOpacity.A); - if ( DynamicEffect ) + const bool bDynamicMaterialInUse = (DynamicEffect != nullptr); + if (bDynamicMaterialInUse) { DynamicEffect->SetTextureParameterValue(DynamicEffectTextureParameter, RenderTarget); } @@ -343,7 +358,7 @@ int32 SRetainerWidget::OnPaint(const FPaintArgs& Args, const FGeometry& Allotted AllottedGeometry.ToPaintGeometry(), &SurfaceBrush, MyClippingRect, - ESlateDrawEffect::PreMultipliedAlpha, + bDynamicMaterialInUse ? ESlateDrawEffect::PreMultipliedAlpha : ESlateDrawEffect::PreMultipliedAlpha | ESlateDrawEffect::NoGamma, FLinearColor(PremultipliedColorAndOpacity.R, PremultipliedColorAndOpacity.G, PremultipliedColorAndOpacity.B, PremultipliedColorAndOpacity.A) ); @@ -352,7 +367,7 @@ int32 SRetainerWidget::OnPaint(const FPaintArgs& Args, const FGeometry& Allotted // Any deferred painted elements of the retainer should be drawn directly by the main renderer, not rendered into the render target, // as most of those sorts of things will break the rendering rect, things like tooltips, and popup menus. - for ( auto& DeferredPaint : WidgetRenderer.DeferredPaints ) + for ( auto& DeferredPaint :WidgetRenderer->DeferredPaints ) { OutDrawElements.QueueDeferredPainting(DeferredPaint->Copy(Args)); } diff --git a/Engine/Source/Runtime/UMG/Private/Slate/SWorldWidgetScreenLayer.cpp b/Engine/Source/Runtime/UMG/Private/Slate/SWorldWidgetScreenLayer.cpp index eec769d9d2a8..550a9af1cdf9 100644 --- a/Engine/Source/Runtime/UMG/Private/Slate/SWorldWidgetScreenLayer.cpp +++ b/Engine/Source/Runtime/UMG/Private/Slate/SWorldWidgetScreenLayer.cpp @@ -133,7 +133,7 @@ void SWorldWidgetScreenLayer::Tick(const FGeometry& AllottedGeometry, const doub } // Normally components should be removed by someone calling remove component, but just in case it was - // deleted in a way where they didn't happen, this is our backup solution to enure we remove stale widgets. + // deleted in a way where they didn't happen, this is our backup solution to ensure we remove stale widgets. for ( int32 Index = 0; Index < DeadComponents.Num(); Index++ ) { RemoveComponent(DeadComponents[Index]); diff --git a/Engine/Source/Runtime/UMG/Private/SlateBlueprintLibrary.cpp b/Engine/Source/Runtime/UMG/Private/SlateBlueprintLibrary.cpp index 211e3d7e4d66..5dde4b1f6499 100644 --- a/Engine/Source/Runtime/UMG/Private/SlateBlueprintLibrary.cpp +++ b/Engine/Source/Runtime/UMG/Private/SlateBlueprintLibrary.cpp @@ -42,6 +42,11 @@ FVector2D USlateBlueprintLibrary::GetLocalSize(const FGeometry& Geometry) return Geometry.GetLocalSize(); } +FVector2D USlateBlueprintLibrary::GetAbsoluteSize(const FGeometry& Geometry) +{ + return TransformVector(Geometry.GetAccumulatedRenderTransform(), Geometry.GetLocalSize()); +} + bool USlateBlueprintLibrary::EqualEqual_SlateBrush(const FSlateBrush& A, const FSlateBrush& B) { return A == B; diff --git a/Engine/Source/Runtime/UMG/Private/UserWidget.cpp b/Engine/Source/Runtime/UMG/Private/UserWidget.cpp index 87d79fc3af31..97559aceb1c7 100644 --- a/Engine/Source/Runtime/UMG/Private/UserWidget.cpp +++ b/Engine/Source/Runtime/UMG/Private/UserWidget.cpp @@ -22,6 +22,7 @@ #include "UObject/EditorObjectVersion.h" #include "UMGPrivate.h" #include "UObject/UObjectHash.h" +#include "PropertyPortFlags.h" DECLARE_CYCLE_STAT(TEXT("UserWidget Create"), STAT_CreateWidget, STATGROUP_Slate); @@ -124,6 +125,7 @@ void UUserWidget::TemplateInitInner() FObjectDuplicationParameters Parameters(WidgetClass->WidgetTree, this); Parameters.FlagMask = RF_Transactional; + Parameters.PortFlags = PPF_DuplicateVerbatim; WidgetTree = (UWidgetTree*)StaticDuplicateObjectEx(Parameters); bCookedWidgetTree = true; @@ -452,8 +454,8 @@ void UUserWidget::SynchronizeProperties() TSharedPtr SafeGCWidget = MyGCWidget.Pin(); if ( SafeGCWidget.IsValid() ) { - TAttribute ColorBinding = OPTIONAL_BINDING(FLinearColor, ColorAndOpacity); - TAttribute ForegroundColorBinding = OPTIONAL_BINDING(FSlateColor, ForegroundColor); + TAttribute ColorBinding = PROPERTY_BINDING(FLinearColor, ColorAndOpacity); + TAttribute ForegroundColorBinding = PROPERTY_BINDING(FSlateColor, ForegroundColor); SafeGCWidget->SetColorAndOpacity(ColorBinding); SafeGCWidget->SetForegroundColor(ForegroundColorBinding); @@ -1591,6 +1593,11 @@ FCursorReply UUserWidget::NativeOnCursorQuery( const FGeometry& InGeometry, cons return FCursorReply::Unhandled(); } +void UUserWidget::NativeOnMouseCaptureLost() +{ + OnMouseCaptureLost(); +} + bool UUserWidget::ShouldSerializeWidgetTree(const ITargetPlatform* TargetPlatform) const { if ( UWidgetBlueprintGeneratedClass* BGClass = Cast(GetClass()) ) diff --git a/Engine/Source/Runtime/UMG/Private/WidgetLayoutLibrary.cpp b/Engine/Source/Runtime/UMG/Private/WidgetLayoutLibrary.cpp index ee1f79c78680..c4d2bb83da08 100644 --- a/Engine/Source/Runtime/UMG/Private/WidgetLayoutLibrary.cpp +++ b/Engine/Source/Runtime/UMG/Private/WidgetLayoutLibrary.cpp @@ -20,6 +20,9 @@ #include "Runtime/Engine/Classes/Engine/RendererSettings.h" #include "Blueprint/SlateBlueprintLibrary.h" #include "Slate/SceneViewport.h" +#include "Slate/SGameLayerManager.h" +#include "Framework/Application/SlateApplication.h" +#include "FrameValue.h" #define LOCTEXT_NAMESPACE "UMG" @@ -72,16 +75,27 @@ bool UWidgetLayoutLibrary::ProjectWorldLocationToWidgetPositionWithDistance(APla float UWidgetLayoutLibrary::GetViewportScale(UObject* WorldContextObject) { - UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject); - if ( World && World->IsGameWorld() ) + static TFrameValue ViewportScaleCache; + + if ( !ViewportScaleCache.IsSet() || WITH_EDITOR ) { - if ( UGameViewportClient* ViewportClient = World->GetGameViewport() ) + float ViewportScale = 1.0f; + + UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject); + if ( World && World->IsGameWorld() ) { - return GetViewportScale(ViewportClient); + if ( UGameViewportClient* ViewportClient = World->GetGameViewport() ) + { + FVector2D ViewportSize; + ViewportClient->GetViewportSize(ViewportSize); + ViewportScale = GetDefault()->GetDPIScaleBasedOnSize(FIntPoint(ViewportSize.X, ViewportSize.Y)); + } } + + ViewportScaleCache = ViewportScale; } - return 1; + return ViewportScaleCache.GetValue(); } float UWidgetLayoutLibrary::GetViewportScale(UGameViewportClient* ViewportClient) @@ -101,10 +115,30 @@ float UWidgetLayoutLibrary::GetViewportScale(UGameViewportClient* ViewportClient return UserResolutionScale; } +FVector2D UWidgetLayoutLibrary::GetMousePositionOnPlatform() +{ + if ( FSlateApplication::IsInitialized() ) + { + return FSlateApplication::Get().GetCursorPos(); + } + + return FVector2D(0, 0); +} + +FVector2D UWidgetLayoutLibrary::GetMousePositionOnViewport(UObject* WorldContextObject) +{ + if ( FSlateApplication::IsInitialized() ) + { + FVector2D MousePosition = FSlateApplication::Get().GetCursorPos(); + FGeometry ViewportGeometry = GetViewportWidgetGeometry(WorldContextObject); + return ViewportGeometry.AbsoluteToLocal(MousePosition); + } + + return FVector2D(0, 0); +} + bool UWidgetLayoutLibrary::GetMousePositionScaledByDPI(APlayerController* Player, float& LocationX, float& LocationY) { - // TODO NDarnell We should deprecate this function, it's not super useful. - if ( Player && Player->GetMousePosition(LocationX, LocationY) ) { float Scale = UWidgetLayoutLibrary::GetViewportScale(Player); @@ -118,19 +152,62 @@ bool UWidgetLayoutLibrary::GetMousePositionScaledByDPI(APlayerController* Player } FVector2D UWidgetLayoutLibrary::GetViewportSize(UObject* WorldContextObject) +{ + static TFrameValue ViewportSizeCache; + + if ( !ViewportSizeCache.IsSet() || WITH_EDITOR ) + { + FVector2D ViewportSize(1, 1); + + UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject); + if ( World && World->IsGameWorld() ) + { + if ( UGameViewportClient* ViewportClient = World->GetGameViewport() ) + { + ViewportClient->GetViewportSize(ViewportSize); + } + } + + ViewportSizeCache = ViewportSize; + } + + return ViewportSizeCache.GetValue(); +} + +FGeometry UWidgetLayoutLibrary::GetViewportWidgetGeometry(UObject* WorldContextObject) { UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject); if ( World && World->IsGameWorld() ) { if ( UGameViewportClient* ViewportClient = World->GetGameViewport() ) { - FVector2D ViewportSize; - ViewportClient->GetViewportSize(ViewportSize); - return ViewportSize; + TSharedPtr LayerManager = ViewportClient->GetGameLayerManager(); + if ( LayerManager.IsValid() ) + { + return LayerManager->GetViewportWidgetHostGeometry(); + } } } - return FVector2D(1, 1); + return FGeometry(); +} + +FGeometry UWidgetLayoutLibrary::GetPlayerScreenWidgetGeometry(APlayerController* PlayerController) +{ + UWorld* World = GEngine->GetWorldFromContextObject(PlayerController); + if ( World && World->IsGameWorld() ) + { + if ( UGameViewportClient* ViewportClient = World->GetGameViewport() ) + { + TSharedPtr LayerManager = ViewportClient->GetGameLayerManager(); + if ( LayerManager.IsValid() ) + { + return LayerManager->GetPlayerWidgetHostGeometry(PlayerController->GetLocalPlayer()); + } + } + } + + return FGeometry(); } UBorderSlot* UWidgetLayoutLibrary::SlotAsBorderSlot(UWidget* Widget) diff --git a/Engine/Source/Runtime/UMG/Public/Blueprint/SlateBlueprintLibrary.h b/Engine/Source/Runtime/UMG/Public/Blueprint/SlateBlueprintLibrary.h index 778779eefcda..602bfb6a4ba1 100644 --- a/Engine/Source/Runtime/UMG/Public/Blueprint/SlateBlueprintLibrary.h +++ b/Engine/Source/Runtime/UMG/Public/Blueprint/SlateBlueprintLibrary.h @@ -47,6 +47,10 @@ public: UFUNCTION(BlueprintPure, Category="User Interface|Geometry") static FVector2D GetLocalSize(const FGeometry& Geometry); + /** @return the size of the geometry in absolute space. */ + UFUNCTION(BlueprintPure, Category="User Interface|Geometry") + static FVector2D GetAbsoluteSize(const FGeometry& Geometry); + /** @return Whether brushes A and B are identical. */ UFUNCTION(BlueprintPure, meta = (DisplayName = "Equal (SlateBrush)", CompactNodeTitle = "=="), Category = "SlateBrush") static bool EqualEqual_SlateBrush(const FSlateBrush& A, const FSlateBrush& B); diff --git a/Engine/Source/Runtime/UMG/Public/Blueprint/UserWidget.h b/Engine/Source/Runtime/UMG/Public/Blueprint/UserWidget.h index 02f06fe32dfc..bd39c0d3daf5 100644 --- a/Engine/Source/Runtime/UMG/Public/Blueprint/UserWidget.h +++ b/Engine/Source/Runtime/UMG/Public/Blueprint/UserWidget.h @@ -631,6 +631,12 @@ public: UFUNCTION(BlueprintImplementableEvent, BlueprintCosmetic, Category="Touch Input") FEventReply OnMotionDetected(FGeometry MyGeometry, FMotionEvent InMotionEvent); + /** + * Called when mouse capture is lost if it was owned by this widget. + */ + UFUNCTION(BlueprintImplementableEvent, BlueprintCosmetic, Category="Touch Input") + void OnMouseCaptureLost(); + public: /** @@ -971,6 +977,7 @@ protected: virtual FReply NativeOnTouchEnded( const FGeometry& InGeometry, const FPointerEvent& InGestureEvent ); virtual FReply NativeOnMotionDetected( const FGeometry& InGeometry, const FMotionEvent& InMotionEvent ); virtual FCursorReply NativeOnCursorQuery( const FGeometry& InGeometry, const FPointerEvent& InCursorEvent ); + virtual void NativeOnMouseCaptureLost(); protected: bool ShouldSerializeWidgetTree(const class ITargetPlatform* TargetPlatform) const; @@ -1053,6 +1060,11 @@ private: static bool bTemplateInitializing; static uint32 bInitializingFromWidgetTree; + +protected: + + PROPERTY_BINDING_IMPLEMENTATION(FLinearColor, ColorAndOpacity); + PROPERTY_BINDING_IMPLEMENTATION(FSlateColor, ForegroundColor); }; #define LOCTEXT_NAMESPACE "UMG" diff --git a/Engine/Source/Runtime/UMG/Public/Blueprint/WidgetLayoutLibrary.h b/Engine/Source/Runtime/UMG/Public/Blueprint/WidgetLayoutLibrary.h index 24c01f5e3132..de00a7cd983b 100644 --- a/Engine/Source/Runtime/UMG/Public/Blueprint/WidgetLayoutLibrary.h +++ b/Engine/Source/Runtime/UMG/Public/Blueprint/WidgetLayoutLibrary.h @@ -5,6 +5,7 @@ #include "CoreMinimal.h" #include "UObject/ObjectMacros.h" #include "Kismet/BlueprintFunctionLibrary.h" +#include "Layout/Geometry.h" #include "WidgetLayoutLibrary.generated.h" class APlayerController; @@ -59,12 +60,41 @@ public: UFUNCTION(BlueprintPure, BlueprintCosmetic, Category="Viewport", meta=( WorldContext="WorldContextObject" )) static FVector2D GetViewportSize(UObject* WorldContextObject); + /** + * Gets the geometry of the widget holding all widgets added to the "Viewport". You + * can use this geometry to convert between absolute and local space of widgets held on this + * widget. + */ + UFUNCTION(BlueprintCallable, Category="Viewport", meta=( WorldContext="WorldContextObject" )) + static FGeometry GetViewportWidgetGeometry(UObject* WorldContextObject); + + /** + * Gets the geometry of the widget holding all widgets added to the "Player Screen". You + * can use this geometry to convert between absolute and local space of widgets held on this + * widget. + */ + UFUNCTION(BlueprintCallable, Category="Viewport") + static FGeometry GetPlayerScreenWidgetGeometry(APlayerController* PlayerController); + + /** + * Gets the platform's mouse cursor position. This is the 'absolute' desktop location of the mouse. + */ + UFUNCTION(BlueprintCallable, Category="Viewport") + static FVector2D GetMousePositionOnPlatform(); + + /** + * Gets the platform's mouse cursor position in the local space of the viewport widget. + */ + UFUNCTION(BlueprintCallable, Category="Viewport", meta=( WorldContext="WorldContextObject" )) + static FVector2D GetMousePositionOnViewport(UObject* WorldContextObject); + /** * Gets the mouse position of the player controller, scaled by the DPI. If you're trying to go from raw mouse screenspace coordinates * to fullscreen widget space, you'll need to transform the mouse into DPI Scaled space. This function performs that scaling. * * MousePositionScaledByDPI = MousePosition * (1 / ViewportScale). */ + //DEPRECATED(4.17, "Use GetMousePositionOnViewport() instead. Optionally and for more options, you can use GetViewportWidgetGeometry and GetPlayerScreenWidgetGeometry are newly introduced to give you the geometry of the viewport and the player screen for widgets to help convert between spaces.") UFUNCTION(BlueprintPure, BlueprintCosmetic, Category="Viewport") static bool GetMousePositionScaledByDPI(APlayerController* Player, float& LocationX, float& LocationY); diff --git a/Engine/Source/Runtime/UMG/Public/Blueprint/WidgetNavigation.h b/Engine/Source/Runtime/UMG/Public/Blueprint/WidgetNavigation.h index 6c5946192221..ec1fa8345296 100644 --- a/Engine/Source/Runtime/UMG/Public/Blueprint/WidgetNavigation.h +++ b/Engine/Source/Runtime/UMG/Public/Blueprint/WidgetNavigation.h @@ -15,7 +15,7 @@ class UWidget; /** * */ -USTRUCT() +USTRUCT(BlueprintType) struct UMG_API FWidgetNavigationData { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/UMG/Public/Components/Border.h b/Engine/Source/Runtime/UMG/Public/Components/Border.h index 82b542272756..55164db33fe7 100644 --- a/Engine/Source/Runtime/UMG/Public/Components/Border.h +++ b/Engine/Source/Runtime/UMG/Public/Components/Border.h @@ -193,4 +193,6 @@ protected: /** Image to use for the border */ UPROPERTY() USlateBrushAsset* Brush_DEPRECATED; + + PROPERTY_BINDING_IMPLEMENTATION(FLinearColor, ContentColorAndOpacity) }; diff --git a/Engine/Source/Runtime/UMG/Public/Components/Button.h b/Engine/Source/Runtime/UMG/Public/Components/Button.h index adcc5ce6421a..025a43bf8b12 100644 --- a/Engine/Source/Runtime/UMG/Public/Components/Button.h +++ b/Engine/Source/Runtime/UMG/Public/Components/Button.h @@ -103,6 +103,15 @@ public: UFUNCTION(BlueprintCallable, Category="Button") bool IsPressed() const; + UFUNCTION(BlueprintCallable, Category="Button") + void SetClickMethod(EButtonClickMethod::Type InClickMethod); + + UFUNCTION(BlueprintCallable, Category="Button") + void SetTouchMethod(EButtonTouchMethod::Type InTouchMethod); + + //UFUNCTION(BlueprintCallable, Category="Button") + //void SetPressMethod(EButtonPressMethod::Type InPressMethod); + public: //~ Begin UWidget Interface diff --git a/Engine/Source/Runtime/UMG/Public/Components/CheckBox.h b/Engine/Source/Runtime/UMG/Public/Components/CheckBox.h index 43a7a07dd162..147a9e68a74e 100644 --- a/Engine/Source/Runtime/UMG/Public/Components/CheckBox.h +++ b/Engine/Source/Runtime/UMG/Public/Components/CheckBox.h @@ -163,4 +163,6 @@ protected: protected: TSharedPtr MyCheckbox; + + PROPERTY_BINDING_IMPLEMENTATION(ECheckBoxState, CheckedState) }; diff --git a/Engine/Source/Runtime/UMG/Public/Components/ComboBoxString.h b/Engine/Source/Runtime/UMG/Public/Components/ComboBoxString.h index 8050f421fcdb..c0bb3a7d310d 100644 --- a/Engine/Source/Runtime/UMG/Public/Components/ComboBoxString.h +++ b/Engine/Source/Runtime/UMG/Public/Components/ComboBoxString.h @@ -136,6 +136,7 @@ public: //~ End UVisual Interface //~ Begin UObject Interface + virtual void PostInitProperties() override; virtual void PostLoad() override; //~ End UObject Interface diff --git a/Engine/Source/Runtime/UMG/Public/Components/EditableText.h b/Engine/Source/Runtime/UMG/Public/Components/EditableText.h index 5347971a5e11..44578cb9d944 100644 --- a/Engine/Source/Runtime/UMG/Public/Components/EditableText.h +++ b/Engine/Source/Runtime/UMG/Public/Components/EditableText.h @@ -183,4 +183,7 @@ protected: protected: TSharedPtr MyEditableText; + + PROPERTY_BINDING_IMPLEMENTATION(FText, Text); + PROPERTY_BINDING_IMPLEMENTATION(FText, HintText); }; diff --git a/Engine/Source/Runtime/UMG/Public/Components/EditableTextBox.h b/Engine/Source/Runtime/UMG/Public/Components/EditableTextBox.h index b34525934eab..e8a7a0acadd6 100644 --- a/Engine/Source/Runtime/UMG/Public/Components/EditableTextBox.h +++ b/Engine/Source/Runtime/UMG/Public/Components/EditableTextBox.h @@ -186,4 +186,7 @@ protected: protected: TSharedPtr MyEditableTextBlock; + + PROPERTY_BINDING_IMPLEMENTATION(FText, Text); + PROPERTY_BINDING_IMPLEMENTATION(FText, HintText); }; diff --git a/Engine/Source/Runtime/UMG/Public/Components/ExpandableArea.h b/Engine/Source/Runtime/UMG/Public/Components/ExpandableArea.h index da323d620554..d2f8cf5db02b 100644 --- a/Engine/Source/Runtime/UMG/Public/Components/ExpandableArea.h +++ b/Engine/Source/Runtime/UMG/Public/Components/ExpandableArea.h @@ -28,7 +28,7 @@ class UMG_API UExpandableArea : public UWidget, public INamedSlotInterface public: - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Style") + UPROPERTY(EditAnywhere, Category = "Style") FExpandableAreaStyle Style; UPROPERTY( EditAnywhere, BlueprintReadOnly, Category = "Style" ) diff --git a/Engine/Source/Runtime/UMG/Public/Components/Image.h b/Engine/Source/Runtime/UMG/Public/Components/Image.h index 0ac5efd18461..168c4801b9d4 100644 --- a/Engine/Source/Runtime/UMG/Public/Components/Image.h +++ b/Engine/Source/Runtime/UMG/Public/Components/Image.h @@ -118,4 +118,8 @@ protected: protected: TSharedPtr MyImage; + +protected: + + PROPERTY_BINDING_IMPLEMENTATION(FSlateColor, ColorAndOpacity); }; diff --git a/Engine/Source/Runtime/UMG/Public/Components/InputKeySelector.h b/Engine/Source/Runtime/UMG/Public/Components/InputKeySelector.h index 048eabbe2447..d072f9760099 100644 --- a/Engine/Source/Runtime/UMG/Public/Components/InputKeySelector.h +++ b/Engine/Source/Runtime/UMG/Public/Components/InputKeySelector.h @@ -9,6 +9,7 @@ #include "Layout/Margin.h" #include "Widgets/SWidget.h" #include "Components/Widget.h" +#include "Styling/SlateTypes.h" #include "InputKeySelector.generated.h" class SInputKeySelector; @@ -25,31 +26,49 @@ public: DECLARE_DYNAMIC_MULTICAST_DELEGATE( FOnIsSelectingKeyChanged ); public: + /** The button style used at runtime */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Appearance, meta = (DisplayName = "Style")) + FButtonStyle WidgetStyle; + + /** The button style used at runtime */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Appearance, meta = (DisplayName = "Text Style")) + FTextBlockStyle TextStyle; + /** The currently selected key chord. */ UPROPERTY( BlueprintReadOnly, Category = "Key Selection" ) FInputChord SelectedKey; - /** The font used to display the currently selected key. */ - UPROPERTY( EditAnywhere, BlueprintReadOnly, Category = Appearance ) - FSlateFontInfo Font; + UPROPERTY() + FSlateFontInfo Font_DEPRECATED; /** The amount of blank space around the text used to display the currently selected key. */ UPROPERTY( EditAnywhere, BlueprintReadOnly, Category = Appearance ) FMargin Margin; - /** The color of the text used to display the currently selected key. */ - UPROPERTY( EditAnywhere, BlueprintReadOnly, Category = Appearance ) - FLinearColor ColorAndOpacity; + UPROPERTY() + FLinearColor ColorAndOpacity_DEPRECATED; /** Sets the text which is displayed while selecting keys. */ UPROPERTY( EditAnywhere, BlueprintReadOnly, Category = Appearance ) FText KeySelectionText; + /** Sets the text to display when no key text is available or not selecting a key. */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Appearance) + FText NoKeySpecifiedText; + /** When true modifier keys such as control and alt are allowed in the */ /** input chord representing the selected key, if false modifier keys are ignored. */ UPROPERTY( EditAnywhere, BlueprintReadOnly, Category = "Key Selection" ) bool bAllowModifierKeys; + /** When true gamepad keys are allowed in the input chord representing the selected key, otherwise they are ignored. */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Key Selection") + bool bAllowGamepadKeys; + + /** When true gamepad keys are allowed in the input chord representing the selected key, otherwise they are ignored. */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Key Selection") + TArray EscapeKeys; + public: /** Called whenever a new key is selected by the user. */ UPROPERTY( BlueprintAssignable, Category = "Widget Event" ) @@ -61,16 +80,24 @@ public: /** Sets the currently selected key. */ UFUNCTION( BlueprintCallable, Category = "Widget" ) - void SetSelectedKey(FInputChord InSelectedKey); + void SetSelectedKey(const FInputChord& InSelectedKey); /** Sets the text which is displayed while selecting keys. */ UFUNCTION( BlueprintCallable, Category = "Widget" ) void SetKeySelectionText( FText InKeySelectionText ); + /** Sets the text to display when no key text is available or not selecting a key. */ + UFUNCTION(BlueprintCallable, Category = "Widget") + void SetNoKeySpecifiedText(FText InNoKeySpecifiedText); + /** Sets whether or not modifier keys are allowed in the selected key. */ UFUNCTION(BlueprintCallable, Category = "Widget" ) void SetAllowModifierKeys(bool bInAllowModifierKeys ); + /** Sets whether or not gamepad keys are allowed in the selected key. */ + UFUNCTION(BlueprintCallable, Category = "Widget") + void SetAllowGamepadKeys(bool bInAllowGamepadKeys); + /** Returns true if the widget is currently selecting a key, otherwise returns false. */ UFUNCTION( BlueprintCallable, Category = "Widget" ) bool GetIsSelectingKey() const; @@ -83,18 +110,24 @@ public: //~ End UWidget Interface protected: + //~ Begin UObject Interface + virtual void PostLoad() override; + virtual void Serialize(FArchive& Ar) override; + //~ End UObject Interface + //~ Begin UWidget Interface virtual TSharedRef RebuildWidget() override; //~ End UWidget Interface + //~ Begin UVisual Interface + virtual void ReleaseSlateResources(bool bReleaseChildren) override; + //~ End UVisual Interface + private: virtual void HandleKeySelected(const FInputChord& InSelectedKey); void HandleIsSelectingKeyChanged(); private: - /** The style for the button used to start key selection mode. */ - const FButtonStyle* ButtonStyle; - /** The input key selector widget managed by this object. */ TSharedPtr MyInputKeySelector; }; diff --git a/Engine/Source/Runtime/UMG/Public/Components/MultiLineEditableText.h b/Engine/Source/Runtime/UMG/Public/Components/MultiLineEditableText.h index d01712229d34..a11e34131497 100644 --- a/Engine/Source/Runtime/UMG/Public/Components/MultiLineEditableText.h +++ b/Engine/Source/Runtime/UMG/Public/Components/MultiLineEditableText.h @@ -102,4 +102,6 @@ protected: protected: TSharedPtr MyMultiLineEditableText; + + PROPERTY_BINDING_IMPLEMENTATION(FText, HintText); }; diff --git a/Engine/Source/Runtime/UMG/Public/Components/MultiLineEditableTextBox.h b/Engine/Source/Runtime/UMG/Public/Components/MultiLineEditableTextBox.h index dfa78366c441..b85629dc028b 100644 --- a/Engine/Source/Runtime/UMG/Public/Components/MultiLineEditableTextBox.h +++ b/Engine/Source/Runtime/UMG/Public/Components/MultiLineEditableTextBox.h @@ -137,4 +137,6 @@ protected: protected: TSharedPtr MyEditableTextBlock; + + PROPERTY_BINDING_IMPLEMENTATION(FText, HintText); }; diff --git a/Engine/Source/Runtime/UMG/Public/Components/ProgressBar.h b/Engine/Source/Runtime/UMG/Public/Components/ProgressBar.h index e869c928ba9f..e026194cca9e 100644 --- a/Engine/Source/Runtime/UMG/Public/Components/ProgressBar.h +++ b/Engine/Source/Runtime/UMG/Public/Components/ProgressBar.h @@ -111,4 +111,6 @@ protected: //~ Begin UWidget Interface virtual TSharedRef RebuildWidget() override; //~ End UWidget Interface + + PROPERTY_BINDING_IMPLEMENTATION(FSlateColor, FillColorAndOpacity); }; diff --git a/Engine/Source/Runtime/UMG/Public/Components/RichTextBlock.h b/Engine/Source/Runtime/UMG/Public/Components/RichTextBlock.h index 8dc6ed5a11f8..c45e21e9fc61 100644 --- a/Engine/Source/Runtime/UMG/Public/Components/RichTextBlock.h +++ b/Engine/Source/Runtime/UMG/Public/Components/RichTextBlock.h @@ -11,6 +11,7 @@ #include "RichTextBlock.generated.h" class SRichTextBlock; +class URichTextBlockDecorator; /** * The rich text block @@ -37,6 +38,7 @@ public: #if WITH_EDITOR // UWidget interface virtual const FText GetPaletteCategory() override; + virtual void OnCreationFromPalette() override; // End UWidget interface #endif @@ -58,7 +60,7 @@ protected: FLinearColor Color; UPROPERTY(EditAnywhere, Instanced, Category=Decorators) - TArray Decorators; + TArray Decorators; protected: FTextBlockStyle DefaultStyle; @@ -69,4 +71,7 @@ protected: // UWidget interface virtual TSharedRef RebuildWidget() override; // End of UWidget interface + +protected: + PROPERTY_BINDING_IMPLEMENTATION(FText, Text); }; diff --git a/Engine/Source/Runtime/UMG/Public/Components/ScaleBox.h b/Engine/Source/Runtime/UMG/Public/Components/ScaleBox.h index 21393229071c..74440236b37f 100644 --- a/Engine/Source/Runtime/UMG/Public/Components/ScaleBox.h +++ b/Engine/Source/Runtime/UMG/Public/Components/ScaleBox.h @@ -17,7 +17,7 @@ * * Single Child * * Aspect Ratio */ -UCLASS() +UCLASS(config=Engine) class UMG_API UScaleBox : public UContentWidget { GENERATED_UCLASS_BODY() @@ -40,6 +40,16 @@ public: UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Stretching") bool IgnoreInheritedScale; + /** + * Only perform a single layout pass, if you do this, it can save a considerable + * amount of time, however, some things like text may not look correct. You may also + * see the UI judder between frames. This generally is caused by not explicitly + * sizing the widget, and instead allowing it to layout based on desired size along + * which won't work in Single Layout Pass mode. + */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, config, Category = "Performance") + bool bSingleLayoutPass; + public: UFUNCTION(BlueprintCallable, Category = "Appearance") void SetStretch(EStretch::Type InStretch); diff --git a/Engine/Source/Runtime/UMG/Public/Components/Slider.h b/Engine/Source/Runtime/UMG/Public/Components/Slider.h index 480abb94524c..89b8df38ebfe 100644 --- a/Engine/Source/Runtime/UMG/Public/Components/Slider.h +++ b/Engine/Source/Runtime/UMG/Public/Components/Slider.h @@ -145,4 +145,6 @@ protected: void HandleOnMouseCaptureEnd(); void HandleOnControllerCaptureBegin(); void HandleOnControllerCaptureEnd(); + + PROPERTY_BINDING_IMPLEMENTATION(float, Value); }; diff --git a/Engine/Source/Runtime/UMG/Public/Components/SpinBox.h b/Engine/Source/Runtime/UMG/Public/Components/SpinBox.h index 3c85e4642599..5fd60bf2004f 100644 --- a/Engine/Source/Runtime/UMG/Public/Components/SpinBox.h +++ b/Engine/Source/Runtime/UMG/Public/Components/SpinBox.h @@ -215,4 +215,6 @@ protected: protected: TSharedPtr> MySpinBox; + + PROPERTY_BINDING_IMPLEMENTATION(float, Value); }; diff --git a/Engine/Source/Runtime/UMG/Public/Components/TextBlock.h b/Engine/Source/Runtime/UMG/Public/Components/TextBlock.h index 28777ec2e3b0..b6682ee86ac1 100644 --- a/Engine/Source/Runtime/UMG/Public/Components/TextBlock.h +++ b/Engine/Source/Runtime/UMG/Public/Components/TextBlock.h @@ -171,4 +171,8 @@ protected: protected: TSharedPtr MyTextBlock; + + PROPERTY_BINDING_IMPLEMENTATION(FText, Text); + PROPERTY_BINDING_IMPLEMENTATION(FSlateColor, ColorAndOpacity); + PROPERTY_BINDING_IMPLEMENTATION(FLinearColor, ShadowColorAndOpacity); }; diff --git a/Engine/Source/Runtime/UMG/Public/Components/Widget.h b/Engine/Source/Runtime/UMG/Public/Components/Widget.h index 73ca00bd3c22..e4a0f50acd80 100644 --- a/Engine/Source/Runtime/UMG/Public/Components/Widget.h +++ b/Engine/Source/Runtime/UMG/Public/Components/Widget.h @@ -57,6 +57,7 @@ namespace UMWidget * Helper macro for binding to a delegate or using the constant value when constructing the underlying SWidget */ #define OPTIONAL_BINDING(ReturnType, MemberName) \ + DEPRECATED_MACRO(4.17, "OPTIONAL_BINDING macro is deprecated. Please use PROPERTY_BINDING in place and you'll need to define a PROPERTY_BINDING_IMPLEMENTATION in your header instead.") \ ( MemberName ## Delegate.IsBound() && !IsDesignTime() ) \ ? \ TAttribute< ReturnType >::Create(MemberName ## Delegate.GetUObject(), MemberName ## Delegate.GetFunctionName()) \ @@ -65,14 +66,18 @@ namespace UMWidget #if WITH_EDITOR -#define GAME_SAFE_OPTIONAL_BINDING(ReturnType, MemberName) \ +/** + * Helper macro for binding to a delegate or using the constant value when constructing the underlying SWidget. + * These macros create a binding that has a layer of indirection that allows blueprint debugging to work more effectively. + */ +#define PROPERTY_BINDING(ReturnType, MemberName) \ ( MemberName ## Delegate.IsBound() && !IsDesignTime() ) \ ? \ BIND_UOBJECT_ATTRIBUTE(ReturnType, K2_Gate_ ## MemberName) \ : \ TAttribute< ReturnType >(MemberName) -#define GAME_SAFE_BINDING_IMPLEMENTATION(ReturnType, MemberName) \ +#define PROPERTY_BINDING_IMPLEMENTATION(ReturnType, MemberName) \ ReturnType K2_Cache_ ## MemberName; \ ReturnType K2_Gate_ ## MemberName() \ { \ @@ -86,17 +91,20 @@ namespace UMWidget #else -#define GAME_SAFE_OPTIONAL_BINDING(ReturnType, MemberName) \ +#define PROPERTY_BINDING(ReturnType, MemberName) \ ( MemberName ## Delegate.IsBound() && !IsDesignTime() ) \ ? \ TAttribute< ReturnType >::Create(MemberName ## Delegate.GetUObject(), MemberName ## Delegate.GetFunctionName()) \ : \ TAttribute< ReturnType >(MemberName) -#define GAME_SAFE_BINDING_IMPLEMENTATION(Type, MemberName) +#define PROPERTY_BINDING_IMPLEMENTATION(Type, MemberName) #endif +#define GAME_SAFE_OPTIONAL_BINDING(ReturnType, MemberName) PROPERTY_BINDING(ReturnType, MemberName) +#define GAME_SAFE_BINDING_IMPLEMENTATION(ReturnType, MemberName) PROPERTY_BINDING_IMPLEMENTATION(ReturnType, MemberName) + /** * Helper macro for binding to a delegate or using the constant value when constructing the underlying SWidget, * also allows a conversion function to be provided to convert between the SWidget value and the value exposed to UMG. @@ -294,8 +302,30 @@ public: UPROPERTY() bool bExpandedInDesigner; + /** Stores the design time flag setting if the widget is locked inside the designer */ + UPROPERTY() + bool bLockedInDesigner; + /** Stores a reference to the asset responsible for this widgets construction. */ TWeakObjectPtr WidgetGeneratedBy; + +#endif + +public: + +#if WITH_EDITOR + + /** @return is this widget locked */ + bool IsLockedInDesigner() const + { + return bLockedInDesigner; + } + + /** @param bLockedInDesigner should this widget be locked */ + virtual void SetLockedInDesigner(bool NewLockedInDesigner) + { + bLockedInDesigner = NewLockedInDesigner; + } #endif @@ -744,7 +774,7 @@ private: #endif private: - GAME_SAFE_BINDING_IMPLEMENTATION(FText, ToolTipText) - GAME_SAFE_BINDING_IMPLEMENTATION(bool, bIsEnabled) - //GAME_SAFE_BINDING_IMPLEMENTATION(EMouseCursor::Type, Cursor) + PROPERTY_BINDING_IMPLEMENTATION(FText, ToolTipText); + PROPERTY_BINDING_IMPLEMENTATION(bool, bIsEnabled); + //PROPERTY_BINDING_IMPLEMENTATION(EMouseCursor::Type, Cursor); }; diff --git a/Engine/Source/Runtime/UMG/Public/Components/WidgetComponent.h b/Engine/Source/Runtime/UMG/Public/Components/WidgetComponent.h index 6e44f767012d..f00d3c6e0a76 100644 --- a/Engine/Source/Runtime/UMG/Public/Components/WidgetComponent.h +++ b/Engine/Source/Runtime/UMG/Public/Components/WidgetComponent.h @@ -140,7 +140,7 @@ public: TSubclassOf GetWidgetClass() const { return WidgetClass; } /** @return The user widget object displayed by this component */ - UFUNCTION(BlueprintCallable, Category=UserInterface) + UFUNCTION(BlueprintCallable, Category=UserInterface, meta=(UnsafeDuringActorConstruction=true)) UUserWidget* GetUserWidgetObject() const; /** @return Returns the Slate widget that was assigned to this component, if any */ diff --git a/Engine/Source/Runtime/UMG/Public/Components/WidgetInteractionComponent.h b/Engine/Source/Runtime/UMG/Public/Components/WidgetInteractionComponent.h index 0d008c8899ee..2dfe0376cc0d 100644 --- a/Engine/Source/Runtime/UMG/Public/Components/WidgetInteractionComponent.h +++ b/Engine/Source/Runtime/UMG/Public/Components/WidgetInteractionComponent.h @@ -248,6 +248,9 @@ public: protected: + // Gets the key and char codes for sending keys for the platform. + void GetKeyAndCharCodes(const FKey& Key, bool& bHasKeyCode, uint32& KeyCode, bool& bHasCharCode, uint32& CharCode); + /** Is it safe for this interaction component to run? Might not be in a server situation with no slate application. */ bool CanSendInput(); @@ -335,7 +338,7 @@ private: /** Returns the path to the widget that is currently beneath the pointer */ FWidgetPath DetermineWidgetUnderPointer(); -private_subobject: +private: #if WITH_EDITORONLY_DATA /** The arrow component we show at editor time. */ diff --git a/Engine/Source/Runtime/UMG/Public/Slate/SObjectWidget.h b/Engine/Source/Runtime/UMG/Public/Slate/SObjectWidget.h index e9e7823cf133..d747cde48438 100644 --- a/Engine/Source/Runtime/UMG/Public/Slate/SObjectWidget.h +++ b/Engine/Source/Runtime/UMG/Public/Slate/SObjectWidget.h @@ -95,6 +95,8 @@ class UMG_API SObjectWidget : public SCompoundWidget, public FGCObject virtual FNavigationReply OnNavigation(const FGeometry& MyGeometry, const FNavigationEvent& InNavigationEvent) override; + virtual void OnMouseCaptureLost() override; + protected: /** The UWidget that created this SObjectWidget who needs to be kept alive. */ diff --git a/Engine/Source/Runtime/UMG/Public/Slate/SRetainerWidget.h b/Engine/Source/Runtime/UMG/Public/Slate/SRetainerWidget.h index 1820ed9c424e..cc567082f2df 100644 --- a/Engine/Source/Runtime/UMG/Public/Slate/SRetainerWidget.h +++ b/Engine/Source/Runtime/UMG/Public/Slate/SRetainerWidget.h @@ -109,7 +109,8 @@ private: mutable FSlateBrush SurfaceBrush; - mutable FWidgetRenderer WidgetRenderer; + void InitWidgetRenderer(); + mutable TSharedPtr WidgetRenderer; mutable class UTextureRenderTarget2D* RenderTarget; mutable TSharedPtr MyWidget; diff --git a/Engine/Source/Runtime/UMG/Public/Slate/WidgetRenderer.h b/Engine/Source/Runtime/UMG/Public/Slate/WidgetRenderer.h index 830b9906da9f..589156ca5e47 100644 --- a/Engine/Source/Runtime/UMG/Public/Slate/WidgetRenderer.h +++ b/Engine/Source/Runtime/UMG/Public/Slate/WidgetRenderer.h @@ -32,6 +32,7 @@ public: bool GetIsPrepassNeeded() const { return bPrepassNeeded; } void SetIsPrepassNeeded(bool bInPrepassNeeded) { bPrepassNeeded = bInPrepassNeeded; } void SetShouldClearTarget(bool bShouldClear) { bClearTarget = bShouldClear; } + bool GetUseGammaCorrection() const { return bUseGammaSpace; } ISlate3DRenderer* GetSlateRenderer(); diff --git a/Engine/Source/Runtime/UnrealAudio/Private/Tests/UnrealAudioSystemTests.cpp b/Engine/Source/Runtime/UnrealAudio/Private/Tests/UnrealAudioSystemTests.cpp index 3857e28244d7..0af3e71779e9 100644 --- a/Engine/Source/Runtime/UnrealAudio/Private/Tests/UnrealAudioSystemTests.cpp +++ b/Engine/Source/Runtime/UnrealAudio/Private/Tests/UnrealAudioSystemTests.cpp @@ -137,7 +137,7 @@ namespace UAudio Emitter->SetPosition(GetRandomPosition()); TLinkedList>* EmitterLink = new TLinkedList>(Emitter); EmitterLink->LinkHead(EmittersHead); - } + } //-V773 } FPlatformProcess::Sleep(0.033f); diff --git a/Engine/Source/Runtime/UnrealAudio/Private/UnrealAudioSoundFileConvert.cpp b/Engine/Source/Runtime/UnrealAudio/Private/UnrealAudioSoundFileConvert.cpp index cb1bb520b266..907a0e0d7ed5 100644 --- a/Engine/Source/Runtime/UnrealAudio/Private/UnrealAudioSoundFileConvert.cpp +++ b/Engine/Source/Runtime/UnrealAudio/Private/UnrealAudioSoundFileConvert.cpp @@ -66,6 +66,7 @@ namespace UAudio TArray ChannelMap; Error = InputSoundFileInternal->GetChannelMap(ChannelMap); + check(Error == ESoundFileError::NONE); FSoundFileDescription NewSoundFileDescription; NewSoundFileDescription.NumChannels = InputDescription.NumChannels; @@ -203,14 +204,14 @@ namespace UAudio // Make an auto-deleting task to perform the sound file loading work in the background task thread pool FAutoDeleteAsyncTask* Task = new FAutoDeleteAsyncTask(this, &InputFilePath, &OutputFilePath, &ConvertFormat); Task->StartBackgroundTask(); - } + } //-V773 void FUnrealAudioModule::ConvertSound(const FString& InputFilePath, const FString& OutputFilePath) { // Make an auto-deleting task to perform the sound file loading work in the background task thread pool FAutoDeleteAsyncTask* Task = new FAutoDeleteAsyncTask(this, &InputFilePath, &OutputFilePath, &DefaultConvertFormat); Task->StartBackgroundTask(); - } + } //-V773 } diff --git a/Engine/Source/Runtime/UnrealAudio/Private/UnrealAudioSoundFileManager.cpp b/Engine/Source/Runtime/UnrealAudio/Private/UnrealAudioSoundFileManager.cpp index 333fe338dfef..e0ed312e388b 100644 --- a/Engine/Source/Runtime/UnrealAudio/Private/UnrealAudioSoundFileManager.cpp +++ b/Engine/Source/Runtime/UnrealAudio/Private/UnrealAudioSoundFileManager.cpp @@ -196,7 +196,7 @@ namespace UAudio // Create a task to load the sound file. Note this task will delete itself when it finishes loading the sound file FAsyncTask* Task = new FAsyncTask(AudioModule, NewHandle, Path.GetPlainNameString()); Task->StartBackgroundTask(FileLoadingThreadPool); - } + } //-V773 else { // Immediately load the data entry if this is a synchronous load call diff --git a/Engine/Source/Runtime/UtilityShaders/Private/ClearQuad.cpp b/Engine/Source/Runtime/UtilityShaders/Private/ClearQuad.cpp index 15f988a33dde..c154c24553c0 100644 --- a/Engine/Source/Runtime/UtilityShaders/Private/ClearQuad.cpp +++ b/Engine/Source/Runtime/UtilityShaders/Private/ClearQuad.cpp @@ -8,8 +8,13 @@ #include "ClearReplacementShaders.h" #include "RendererInterface.h" -static void ClearQuadSetup( FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, bool bClearColor, int32 NumClearColors, const FLinearColor* ClearColorArray, bool bClearDepth, float Depth, bool bClearStencil, uint32 Stencil ) +static void ClearQuadSetup( FRHICommandList& RHICmdList, bool bClearColor, int32 NumClearColors, const FLinearColor* ClearColorArray, bool bClearDepth, float Depth, bool bClearStencil, uint32 Stencil ) { + if (UNLIKELY(!FApp::CanEverRender())) + { + return; + } + // Set new states FBlendStateRHIParamRef BlendStateRHI; @@ -43,7 +48,7 @@ static void ClearQuadSetup( FRHICommandList& RHICmdList, ERHIFeatureLevel::Type GraphicsPSOInit.BlendState = BlendStateRHI; GraphicsPSOInit.DepthStencilState = DepthStencilStateRHI; - auto ShaderMap = GetGlobalShaderMap(FeatureLevel); + auto ShaderMap = GetGlobalShaderMap(GMaxRHIFeatureLevel); // Set the new shaders @@ -106,9 +111,9 @@ static void ClearQuadSetup( FRHICommandList& RHICmdList, ERHIFeatureLevel::Type } const uint32 GMaxSizeUAVDMA = 1024; -static void ClearUAVShader(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, FUnorderedAccessViewRHIParamRef UnorderedAccessViewRHI, uint32 Size, uint32 Value) +static void ClearUAVShader(FRHICommandList& RHICmdList, FUnorderedAccessViewRHIParamRef UnorderedAccessViewRHI, uint32 Size, uint32 Value) { - TShaderMapRef ComputeShader(GetGlobalShaderMap(FeatureLevel)); + TShaderMapRef ComputeShader(GetGlobalShaderMap(GMaxRHIFeatureLevel)); FComputeShaderRHIParamRef ShaderRHI = ComputeShader->GetComputeShader(); RHICmdList.SetComputeShader(ShaderRHI); ComputeShader->SetParameters(RHICmdList, UnorderedAccessViewRHI, Value); @@ -118,7 +123,7 @@ static void ClearUAVShader(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type F ComputeShader->FinalizeParameters(RHICmdList, UnorderedAccessViewRHI); } -void ClearUAV(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, const FRWBufferStructured& StructuredBuffer, uint32 Value) +void ClearUAV(FRHICommandList& RHICmdList, const FRWBufferStructured& StructuredBuffer, uint32 Value) { if (StructuredBuffer.NumBytes <= GMaxSizeUAVDMA) { @@ -127,11 +132,11 @@ void ClearUAV(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, } else { - ClearUAVShader(RHICmdList, FeatureLevel, StructuredBuffer.UAV, StructuredBuffer.NumBytes, Value); + ClearUAVShader(RHICmdList, StructuredBuffer.UAV, StructuredBuffer.NumBytes, Value); } } -void ClearUAV(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, const FRWBuffer& Buffer, uint32 Value) +void ClearUAV(FRHICommandList& RHICmdList, const FRWBuffer& Buffer, uint32 Value) { if (Buffer.NumBytes <= GMaxSizeUAVDMA) { @@ -140,16 +145,29 @@ void ClearUAV(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, } else { - ClearUAVShader(RHICmdList, FeatureLevel, Buffer.UAV, Buffer.NumBytes, Value); + ClearUAVShader(RHICmdList, Buffer.UAV, Buffer.NumBytes, Value); + } +} + +void ClearUAV(FRHICommandList& RHICmdList, FRHIUnorderedAccessView* Buffer, uint32 NumBytes, uint32 Value) +{ + if (NumBytes <= GMaxSizeUAVDMA) + { + uint32 Values[4] = { Value, Value, Value, Value }; + RHICmdList.ClearTinyUAV(Buffer, Values); + } + else + { + ClearUAVShader(RHICmdList, Buffer, NumBytes, Value); } } template< typename T > -inline void ClearUAV_T(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, const FSceneRenderTargetItem& RenderTargetItem, const T(&ClearValues)[4]) +inline void ClearUAV_T(FRHICommandList& RHICmdList, const FSceneRenderTargetItem& RenderTargetItem, const T(&ClearValues)[4]) { if (auto Texture2d = RenderTargetItem.TargetableTexture->GetTexture2D()) { - TShaderMapRef< FClearTexture2DReplacementCS > ComputeShader(GetGlobalShaderMap(FeatureLevel)); + TShaderMapRef< FClearTexture2DReplacementCS > ComputeShader(GetGlobalShaderMap(GMaxRHIFeatureLevel)); FComputeShaderRHIParamRef ShaderRHI = ComputeShader->GetComputeShader(); RHICmdList.SetComputeShader(ShaderRHI); ComputeShader->SetParameters(RHICmdList, RenderTargetItem.UAV, ClearValues); @@ -160,7 +178,7 @@ inline void ClearUAV_T(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type Featu } else if (auto Texture2dArray = RenderTargetItem.TargetableTexture->GetTexture2DArray()) { - TShaderMapRef< FClearTexture2DArrayReplacementCS > ComputeShader(GetGlobalShaderMap(FeatureLevel)); + TShaderMapRef< FClearTexture2DArrayReplacementCS > ComputeShader(GetGlobalShaderMap(GMaxRHIFeatureLevel)); FComputeShaderRHIParamRef ShaderRHI = ComputeShader->GetComputeShader(); RHICmdList.SetComputeShader(ShaderRHI); ComputeShader->SetParameters(RHICmdList, RenderTargetItem.UAV, ClearValues); @@ -172,7 +190,7 @@ inline void ClearUAV_T(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type Featu } else if (auto TextureCube = RenderTargetItem.TargetableTexture->GetTextureCube()) { - TShaderMapRef< FClearTexture2DArrayReplacementCS > ComputeShader(GetGlobalShaderMap(FeatureLevel)); + TShaderMapRef< FClearTexture2DArrayReplacementCS > ComputeShader(GetGlobalShaderMap(GMaxRHIFeatureLevel)); FComputeShaderRHIParamRef ShaderRHI = ComputeShader->GetComputeShader(); RHICmdList.SetComputeShader(ShaderRHI); ComputeShader->SetParameters(RHICmdList, RenderTargetItem.UAV, ClearValues); @@ -183,7 +201,7 @@ inline void ClearUAV_T(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type Featu } else if (auto Texture3d = RenderTargetItem.TargetableTexture->GetTexture3D()) { - TShaderMapRef< FClearVolumeReplacementCS > ComputeShader(GetGlobalShaderMap(FeatureLevel)); + TShaderMapRef< FClearVolumeReplacementCS > ComputeShader(GetGlobalShaderMap(GMaxRHIFeatureLevel)); FComputeShaderRHIParamRef ShaderRHI = ComputeShader->GetComputeShader(); RHICmdList.SetComputeShader(ShaderRHI); ComputeShader->SetParameters(RHICmdList, RenderTargetItem.UAV, ClearValues); @@ -199,9 +217,9 @@ inline void ClearUAV_T(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type Featu } } -void ClearTexture2DUAV(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, FUnorderedAccessViewRHIParamRef UAV, int32 Width, int32 Height, const FLinearColor& ClearColor) +void ClearTexture2DUAV(FRHICommandList& RHICmdList, FUnorderedAccessViewRHIParamRef UAV, int32 Width, int32 Height, const FLinearColor& ClearColor) { - TShaderMapRef< FClearTexture2DReplacementCS > ComputeShader(GetGlobalShaderMap(FeatureLevel)); + TShaderMapRef< FClearTexture2DReplacementCS > ComputeShader(GetGlobalShaderMap(GMaxRHIFeatureLevel)); FComputeShaderRHIParamRef ShaderRHI = ComputeShader->GetComputeShader(); RHICmdList.SetComputeShader(ShaderRHI); ComputeShader->SetParameters(RHICmdList, UAV, reinterpret_cast(ClearColor)); @@ -211,24 +229,24 @@ void ClearTexture2DUAV(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type Featu ComputeShader->FinalizeParameters(RHICmdList, UAV); } -void ClearUAV(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, const FSceneRenderTargetItem& RenderTargetItem, const float(&ClearValues)[4]) +void ClearUAV(FRHICommandList& RHICmdList, const FSceneRenderTargetItem& RenderTargetItem, const float(&ClearValues)[4]) { - ClearUAV_T(RHICmdList, FeatureLevel, RenderTargetItem, ClearValues); + ClearUAV_T(RHICmdList, RenderTargetItem, ClearValues); } -void ClearUAV(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, const FSceneRenderTargetItem& RenderTargetItem, const uint32(&ClearValues)[4]) +void ClearUAV(FRHICommandList& RHICmdList, const FSceneRenderTargetItem& RenderTargetItem, const uint32(&ClearValues)[4]) { - ClearUAV_T(RHICmdList, FeatureLevel, RenderTargetItem, ClearValues); + ClearUAV_T(RHICmdList, RenderTargetItem, ClearValues); } -void ClearUAV(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, const FSceneRenderTargetItem& RenderTargetItem, const FLinearColor& ClearColor) +void ClearUAV(FRHICommandList& RHICmdList, const FSceneRenderTargetItem& RenderTargetItem, const FLinearColor& ClearColor) { - ClearUAV_T(RHICmdList, FeatureLevel, RenderTargetItem, reinterpret_cast(ClearColor)); + ClearUAV_T(RHICmdList, RenderTargetItem, reinterpret_cast(ClearColor)); } -void DrawClearQuadMRT(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, bool bClearColor, int32 NumClearColors, const FLinearColor* ClearColorArray, bool bClearDepth, float Depth, bool bClearStencil, uint32 Stencil) +void DrawClearQuadMRT(FRHICommandList& RHICmdList, bool bClearColor, int32 NumClearColors, const FLinearColor* ClearColorArray, bool bClearDepth, float Depth, bool bClearStencil, uint32 Stencil) { - ClearQuadSetup(RHICmdList, FeatureLevel, bClearColor, NumClearColors, ClearColorArray, bClearDepth, Depth, bClearStencil, Stencil); + ClearQuadSetup(RHICmdList, bClearColor, NumClearColors, ClearColorArray, bClearDepth, Depth, bClearStencil, Stencil); // without a hole FVector4 Vertices[4]; @@ -239,7 +257,7 @@ void DrawClearQuadMRT(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type Featur DrawPrimitiveUP(RHICmdList, PT_TriangleStrip, 2, Vertices, sizeof(Vertices[0])); } -void DrawClearQuadMRT(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, bool bClearColor, int32 NumClearColors, const FLinearColor* ClearColorArray, bool bClearDepth, float Depth, bool bClearStencil, uint32 Stencil, FIntPoint ViewSize, FIntRect ExcludeRect) +void DrawClearQuadMRT(FRHICommandList& RHICmdList, bool bClearColor, int32 NumClearColors, const FLinearColor* ClearColorArray, bool bClearDepth, float Depth, bool bClearStencil, uint32 Stencil, FIntPoint ViewSize, FIntRect ExcludeRect) { if (ExcludeRect.Min == FIntPoint::ZeroValue && ExcludeRect.Max == ViewSize) { @@ -247,7 +265,7 @@ void DrawClearQuadMRT(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type Featur return; } - ClearQuadSetup(RHICmdList, FeatureLevel, bClearColor, NumClearColors, ClearColorArray, bClearDepth, Depth, bClearStencil, Stencil); + ClearQuadSetup(RHICmdList, bClearColor, NumClearColors, ClearColorArray, bClearDepth, Depth, bClearStencil, Stencil); // Draw a fullscreen quad if (ExcludeRect.Width() > 0 && ExcludeRect.Height() > 0) @@ -294,4 +312,4 @@ void DrawClearQuadMRT(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type Featur DrawPrimitiveUP(RHICmdList, PT_TriangleStrip, 2, Vertices, sizeof(Vertices[0])); } -} \ No newline at end of file +} diff --git a/Engine/Source/Runtime/UtilityShaders/Private/ClearReplacementShaders.cpp b/Engine/Source/Runtime/UtilityShaders/Private/ClearReplacementShaders.cpp index 09d696c54d34..8d754185694e 100644 --- a/Engine/Source/Runtime/UtilityShaders/Private/ClearReplacementShaders.cpp +++ b/Engine/Source/Runtime/UtilityShaders/Private/ClearReplacementShaders.cpp @@ -18,7 +18,7 @@ void FClearTexture2DReplacementCS::SetParameters( FRHICommandList& RHICmdList template< typename T > void FClearTexture2DReplacementCS::FinalizeParameters(FRHICommandList& RHICmdList, FUnorderedAccessViewRHIParamRef TextureRW) { - RHICmdList.TransitionResource(EResourceTransitionAccess::EReadable, EResourceTransitionPipeline::EComputeToGfx, TextureRW); + RHICmdList.TransitionResource(EResourceTransitionAccess::ERWBarrier, EResourceTransitionPipeline::EComputeToCompute, TextureRW); } template< typename T > @@ -34,7 +34,7 @@ void FClearTexture2DArrayReplacementCS::SetParameters(FRHICommandList& RHICmd template< typename T > void FClearTexture2DArrayReplacementCS::FinalizeParameters(FRHICommandList& RHICmdList, FUnorderedAccessViewRHIParamRef TextureRW) { - RHICmdList.TransitionResource(EResourceTransitionAccess::EReadable, EResourceTransitionPipeline::EComputeToGfx, TextureRW); + RHICmdList.TransitionResource(EResourceTransitionAccess::ERWBarrier, EResourceTransitionPipeline::EComputeToCompute, TextureRW); } template< typename T > @@ -50,7 +50,7 @@ void FClearVolumeReplacementCS::SetParameters(FRHICommandList& RHICmdList, FU template< typename T > void FClearVolumeReplacementCS::FinalizeParameters(FRHICommandList& RHICmdList, FUnorderedAccessViewRHIParamRef TextureRW) { - RHICmdList.TransitionResource(EResourceTransitionAccess::EReadable, EResourceTransitionPipeline::EComputeToGfx, TextureRW); + RHICmdList.TransitionResource(EResourceTransitionAccess::ERWBarrier, EResourceTransitionPipeline::EComputeToCompute, TextureRW); } void FClearTexture2DReplacementScissorCS::SetParameters(FRHICommandList& RHICmdList, FUnorderedAccessViewRHIParamRef TextureRW, FLinearColor InClearColor, const FVector4& InTargetBounds) @@ -64,7 +64,7 @@ void FClearTexture2DReplacementScissorCS::SetParameters(FRHICommandList& RHICmdL void FClearTexture2DReplacementScissorCS::FinalizeParameters(FRHICommandList& RHICmdList, FUnorderedAccessViewRHIParamRef TextureRW) { - RHICmdList.TransitionResource(EResourceTransitionAccess::EReadable, EResourceTransitionPipeline::EComputeToGfx, TextureRW); + RHICmdList.TransitionResource(EResourceTransitionAccess::ERWBarrier, EResourceTransitionPipeline::EComputeToCompute, TextureRW); } void FClearBufferReplacementCS::SetParameters( FRHICommandList& RHICmdList, FUnorderedAccessViewRHIParamRef BufferRW, uint32 Dword ) @@ -77,7 +77,7 @@ void FClearBufferReplacementCS::SetParameters( FRHICommandList& RHICmdList, FUno void FClearBufferReplacementCS::FinalizeParameters(FRHICommandList& RHICmdList, FUnorderedAccessViewRHIParamRef BufferRW) { - RHICmdList.TransitionResource(EResourceTransitionAccess::EReadable, EResourceTransitionPipeline::EComputeToGfx, BufferRW); + RHICmdList.TransitionResource(EResourceTransitionAccess::ERWBarrier, EResourceTransitionPipeline::EComputeToCompute, BufferRW); } template class FClearTexture2DReplacementCS; diff --git a/Engine/Source/Runtime/UtilityShaders/Public/ClearQuad.h b/Engine/Source/Runtime/UtilityShaders/Public/ClearQuad.h index c27e1651d747..ecec72038c41 100644 --- a/Engine/Source/Runtime/UtilityShaders/Public/ClearQuad.h +++ b/Engine/Source/Runtime/UtilityShaders/Public/ClearQuad.h @@ -12,30 +12,31 @@ struct FSceneRenderTargetItem; class FRHIUnorderedAccessView; extern UTILITYSHADERS_API const uint32 GMaxSizeUAVDMA; -extern UTILITYSHADERS_API void ClearUAV(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, const FRWBufferStructured& StructuredBuffer, uint32 Value); -extern UTILITYSHADERS_API void ClearUAV(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, const FRWBuffer& Buffer, uint32 Value); +extern UTILITYSHADERS_API void ClearUAV(FRHICommandList& RHICmdList, const FRWBufferStructured& StructuredBuffer, uint32 Value); +extern UTILITYSHADERS_API void ClearUAV(FRHICommandList& RHICmdList, const FRWBuffer& Buffer, uint32 Value); +extern UTILITYSHADERS_API void ClearUAV(FRHICommandList& RHICmdList, FRHIUnorderedAccessView* Buffer, uint32 NumBytes, uint32 Value); -extern UTILITYSHADERS_API void ClearUAV(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, const FSceneRenderTargetItem& RenderTargetItem, const float(&ClearValues)[4]); -extern UTILITYSHADERS_API void ClearUAV(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, const FSceneRenderTargetItem& RenderTargetItem, const uint32(&ClearValues)[4]); -extern UTILITYSHADERS_API void ClearUAV(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, const FSceneRenderTargetItem& RenderTargetItem, const FLinearColor& ClearColor); +extern UTILITYSHADERS_API void ClearUAV(FRHICommandList& RHICmdList, const FSceneRenderTargetItem& RenderTargetItem, const float(&ClearValues)[4]); +extern UTILITYSHADERS_API void ClearUAV(FRHICommandList& RHICmdList, const FSceneRenderTargetItem& RenderTargetItem, const uint32(&ClearValues)[4]); +extern UTILITYSHADERS_API void ClearUAV(FRHICommandList& RHICmdList, const FSceneRenderTargetItem& RenderTargetItem, const FLinearColor& ClearColor); -extern UTILITYSHADERS_API void ClearTexture2DUAV(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, FRHIUnorderedAccessView* UAV, int32 Width, int32 Height, const FLinearColor& ClearColor); +extern UTILITYSHADERS_API void ClearTexture2DUAV(FRHICommandList& RHICmdList, FRHIUnorderedAccessView* UAV, int32 Width, int32 Height, const FLinearColor& ClearColor); -extern UTILITYSHADERS_API void DrawClearQuadMRT( FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, bool bClearColor, int32 NumClearColors, const FLinearColor* ClearColorArray, bool bClearDepth, float Depth, bool bClearStencil, uint32 Stencil ); -extern UTILITYSHADERS_API void DrawClearQuadMRT( FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, bool bClearColor, int32 NumClearColors, const FLinearColor* ClearColorArray, bool bClearDepth, float Depth, bool bClearStencil, uint32 Stencil, FIntPoint ViewSize, FIntRect ExcludeRect ); +extern UTILITYSHADERS_API void DrawClearQuadMRT( FRHICommandList& RHICmdList, bool bClearColor, int32 NumClearColors, const FLinearColor* ClearColorArray, bool bClearDepth, float Depth, bool bClearStencil, uint32 Stencil ); +extern UTILITYSHADERS_API void DrawClearQuadMRT( FRHICommandList& RHICmdList, bool bClearColor, int32 NumClearColors, const FLinearColor* ClearColorArray, bool bClearDepth, float Depth, bool bClearStencil, uint32 Stencil, FIntPoint ViewSize, FIntRect ExcludeRect ); -inline void DrawClearQuad(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, bool bClearColor, const FLinearColor& Color, bool bClearDepth, float Depth, bool bClearStencil, uint32 Stencil) +inline void DrawClearQuad(FRHICommandList& RHICmdList, bool bClearColor, const FLinearColor& Color, bool bClearDepth, float Depth, bool bClearStencil, uint32 Stencil) { - DrawClearQuadMRT(RHICmdList, FeatureLevel, bClearColor, 1, &Color, bClearDepth, Depth, bClearStencil, Stencil); + DrawClearQuadMRT(RHICmdList, bClearColor, 1, &Color, bClearDepth, Depth, bClearStencil, Stencil); } -inline void DrawClearQuad(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, bool bClearColor, const FLinearColor& Color, bool bClearDepth, float Depth, bool bClearStencil, uint32 Stencil, FIntPoint ViewSize, FIntRect ExcludeRect) +inline void DrawClearQuad(FRHICommandList& RHICmdList, bool bClearColor, const FLinearColor& Color, bool bClearDepth, float Depth, bool bClearStencil, uint32 Stencil, FIntPoint ViewSize, FIntRect ExcludeRect) { - DrawClearQuadMRT(RHICmdList, FeatureLevel, bClearColor, 1, &Color, bClearDepth, Depth, bClearStencil, Stencil, ViewSize, ExcludeRect); + DrawClearQuadMRT(RHICmdList, bClearColor, 1, &Color, bClearDepth, Depth, bClearStencil, Stencil, ViewSize, ExcludeRect); } -inline void DrawClearQuad(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, const FLinearColor& Color) +inline void DrawClearQuad(FRHICommandList& RHICmdList, const FLinearColor& Color) { - DrawClearQuadMRT(RHICmdList, FeatureLevel, true, 1, &Color, false, 0, false, 0); + DrawClearQuadMRT(RHICmdList, true, 1, &Color, false, 0, false, 0); } \ No newline at end of file diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanCommands.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanCommands.cpp index 24536d345502..c12563e998c3 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanCommands.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanCommands.cpp @@ -836,10 +836,9 @@ void FVulkanCommandListContext::RHIClearMRT(bool bClearColor, int32 NumClearColo void FVulkanCommandListContext::InternalClearMRT(FVulkanCmdBuffer* CmdBuffer, bool bClearColor, int32 NumClearColors, const FLinearColor* ClearColorArray, bool bClearDepth, float Depth, bool bClearStencil, uint32 Stencil) { - const VkExtent2D& Extents = TransitionState.CurrentRenderPass->GetLayout().GetExtent2D(); - if (TransitionState.CurrentRenderPass) { + const VkExtent2D& Extents = TransitionState.CurrentRenderPass->GetLayout().GetExtent2D(); VkClearRect Rect; FMemory::Memzero(Rect); Rect.rect.offset.x = 0; diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanMemory.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanMemory.cpp index 11b78714bb5d..acb5d601e94f 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanMemory.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanMemory.cpp @@ -1450,7 +1450,7 @@ namespace VulkanRHI VKSWITCH(Sampler); VKSWITCH(Semaphore); VKSWITCH(ShaderModule); -#undef VKSWTICH +#undef VKSWITCH default: check(0); break; diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanRHI.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanRHI.cpp index 3cd9c438ae26..d98f213ab8a7 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanRHI.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanRHI.cpp @@ -16,6 +16,8 @@ #include "Modules/ModuleManager.h" #include "VulkanPipelineState.h" +#define LOCTEXT_NAMESPACE "VulkanRHI" + #ifdef VK_API_VERSION // Check the SDK is least the API version we want to use static_assert(VK_API_VERSION >= UE_VK_API_VERSION, "Vulkan SDK is older than the version we want to support (UE_VK_API_VERSION). Please update your SDK."); @@ -358,6 +360,11 @@ void FVulkanDynamicRHI::Init() { if (!LoadVulkanLibrary()) { +#if PLATFORM_LINUX + // be more verbose on Linux + FPlatformMisc::MessageBoxExt(EAppMsgType::Ok, *LOCTEXT("UnableToInitializeVulkanLinux", "Unable to load Vulkan library and/or acquire the necessary function pointers. Make sure an up-to-date libvulkan.so.1 is installed.").ToString(), + *LOCTEXT("UnableToInitializeVulkanLinuxTitle", "Unable to initialize Vulkan.").ToString()); +#endif // PLATFORM_LINUX UE_LOG(LogVulkanRHI, Fatal, TEXT("Failed to find all required Vulkan entry points; make sure your driver supports Vulkan!")); } @@ -1333,3 +1340,5 @@ void FVulkanDynamicRHI::RecreateSwapChain(void* NewNativeWindow) FlushRenderingCommands(); } } + +#undef LOCTEXT_NAMESPACE diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanShaders.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanShaders.cpp index 5df68569f9d5..4110ab4172d7 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanShaders.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanShaders.cpp @@ -278,7 +278,7 @@ inline void FVulkanDescriptorSetWriter::SetupDescriptorWrites(const FNEWVulkanSh } } -inline void FVulkanLayout::AddBindingsForStage(VkShaderStageFlagBits StageFlags, EDescriptorSetStage DescSet, const FVulkanCodeHeader& CodeHeader) +void FVulkanLayout::AddBindingsForStage(VkShaderStageFlagBits StageFlags, EDescriptorSetStage DescSet, const FVulkanCodeHeader& CodeHeader) { //#todo-rco: Mobile assumption! int32 DescriptorSetIndex = (int32)DescSet; diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanState.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanState.cpp index ee4070b0a593..2929c975d19b 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanState.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanState.cpp @@ -115,8 +115,8 @@ namespace VulkanRHI { // get the unique key uint64 StencilBitMask = - (State.failOp << 0) | (State.passOp << 3) | (State.depthFailOp << 6) | - (State.compareOp << 9) | (State.compareMask << 12) | (State.writeMask << 20); + (((uint64)State.failOp) << 0) | (((uint64)State.passOp) << 3) | (((uint64)State.depthFailOp) << 6) | + (((uint64)State.compareOp) << 9) | (((uint64)State.compareMask) << 12) | (((uint64)State.writeMask) << 20); uint8* Key = SettingsToUniqueKeyMap.Find(StencilBitMask); if (Key == NULL) diff --git a/Engine/Source/Runtime/VulkanRHI/Private/VulkanViewport.cpp b/Engine/Source/Runtime/VulkanRHI/Private/VulkanViewport.cpp index a23fa57c16ac..61e82605aaa1 100644 --- a/Engine/Source/Runtime/VulkanRHI/Private/VulkanViewport.cpp +++ b/Engine/Source/Runtime/VulkanRHI/Private/VulkanViewport.cpp @@ -122,7 +122,7 @@ FVulkanTexture2D* FVulkanViewport::GetBackBuffer(FRHICommandList& RHICmdList) RenderingBackBuffer = new FVulkanBackBuffer(*Device, PixelFormat, SizeX, SizeY, VK_NULL_HANDLE, TexCreate_Presentable | TexCreate_RenderTargetable); check(RHICmdList.IsImmediate()); - if (RHICmdList.Bypass() || !GRHIThread) + if (RHICmdList.Bypass() || !IsRunningRHIInSeparateThread()) { FRHICommandAcquireBackBuffer Cmd(this, RenderingBackBuffer); Cmd.Execute(RHICmdList); @@ -707,7 +707,7 @@ void FVulkanDynamicRHI::RHIAdvanceFrameForGetViewportBackBuffer() { FRHICommandList& RHICmdList = FRHICommandListExecutor::GetImmediateCommandList(); - if (RHICmdList.Bypass() || !GRHIThread) + if (RHICmdList.Bypass() || !IsRunningRHIInSeparateThread()) { FRHICommandProcessDeferredDeletionQueue Cmd(Device); Cmd.Execute(RHICmdList); diff --git a/Engine/Source/Runtime/VulkanRHI/Public/VulkanDynamicRHI.h b/Engine/Source/Runtime/VulkanRHI/Public/VulkanDynamicRHI.h index 2e17e5ea46ee..434d8cddfe03 100644 --- a/Engine/Source/Runtime/VulkanRHI/Public/VulkanDynamicRHI.h +++ b/Engine/Source/Runtime/VulkanRHI/Public/VulkanDynamicRHI.h @@ -252,7 +252,7 @@ protected: return false; } - if (RHICmdList->Bypass() || !GRHIThread) + if (RHICmdList->Bypass() || !IsRunningRHIInSeparateThread()) { return false; } diff --git a/Engine/Source/Runtime/VulkanRHI/Public/VulkanMemory.h b/Engine/Source/Runtime/VulkanRHI/Public/VulkanMemory.h index c996f2d826e8..adebfd27e99f 100644 --- a/Engine/Source/Runtime/VulkanRHI/Public/VulkanMemory.h +++ b/Engine/Source/Runtime/VulkanRHI/Public/VulkanMemory.h @@ -772,7 +772,7 @@ namespace VulkanRHI MemoryPropertyFlags = MemoryPropertyFlags & ~VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT; } - FOldResourceAllocation* Allocation = ResourceTypeHeaps[TypeIndex]->AllocateResource(MemoryReqs.size, MemoryReqs.alignment, false, bMapped, File, Line); + FOldResourceAllocation* Allocation = ResourceTypeHeaps[TypeIndex]->AllocateResource(MemoryReqs.size, MemoryReqs.alignment, false, bMapped, File, Line); //-V595 if (!Allocation) { // Try another memory type if the allocation failed diff --git a/Engine/Source/Runtime/WebBrowser/Private/Android/AndroidWebBrowserWidget.cpp b/Engine/Source/Runtime/WebBrowser/Private/Android/AndroidWebBrowserWidget.cpp index f96d25810b88..6b024783d8f6 100644 --- a/Engine/Source/Runtime/WebBrowser/Private/Android/AndroidWebBrowserWidget.cpp +++ b/Engine/Source/Runtime/WebBrowser/Private/Android/AndroidWebBrowserWidget.cpp @@ -8,21 +8,48 @@ #include "AndroidWindow.h" #include "AndroidJava.h" #include "Async.h" +#include "ScopeLock.h" // For UrlDecode #include "Http.h" #include +FCriticalSection SAndroidWebBrowserWidget::WebControlsCS; +TMap> SAndroidWebBrowserWidget::AllWebControls; + +TSharedPtr SAndroidWebBrowserWidget::GetWidgetPtr(JNIEnv* JEnv, jobject Jobj) +{ + FScopeLock L(&WebControlsCS); + + jclass Class = JEnv->GetObjectClass(Jobj); + jmethodID JMethod = JEnv->GetMethodID(Class, "GetNativePtr", "()J"); + check(JMethod != nullptr); + + int64 ObjAddr = JEnv->CallLongMethod(Jobj, JMethod); + + TWeakPtr WebControl = AllWebControls.FindRef(ObjAddr); + return (WebControl.IsValid()) ? WebControl.Pin() : TSharedPtr(); +} + +SAndroidWebBrowserWidget::~SAndroidWebBrowserWidget() +{ + FScopeLock L(&WebControlsCS); + AllWebControls.Remove(reinterpret_cast(this)); +} void SAndroidWebBrowserWidget::Construct(const FArguments& Args) { + { + FScopeLock L(&WebControlsCS); + AllWebControls.Add(reinterpret_cast(this), StaticCastSharedRef(AsShared())); + } + WebBrowserWindowPtr = Args._WebBrowserWindow; HistorySize = 0; HistoryPosition = 0; - JWebView.Emplace("com/epicgames/ue4/WebViewControl", "(JZ)V", reinterpret_cast(this), !(UE_BUILD_SHIPPING || UE_BUILD_TEST) ); - + JWebView.Emplace("com/epicgames/ue4/WebViewControl", "(JZZ)V", reinterpret_cast(this), !(UE_BUILD_SHIPPING || UE_BUILD_TEST), Args._UseTransparency); JWebView_Update = JWebView->GetClassMethod("Update", "(IIII)V"); JWebView_ExecuteJavascript = JWebView->GetClassMethod("ExecuteJavascript", "(Ljava/lang/String;)V"); JWebView_LoadURL = JWebView->GetClassMethod("LoadURL", "(Ljava/lang/String;)V"); @@ -97,6 +124,7 @@ void SAndroidWebBrowserWidget::Reload() void SAndroidWebBrowserWidget::Close() { JWebView->CallMethod(JWebView_Close.GetValue()); + WebBrowserWindowPtr.Reset(); } void SAndroidWebBrowserWidget::GoBack() @@ -134,28 +162,31 @@ jbyteArray SAndroidWebBrowserWidget::HandleShouldInterceptRequest(jstring JUrl) { AsyncTask(ENamedThreads::GameThread, [Url, Position, this]() { - TSharedPtr BrowserWindow = WebBrowserWindowPtr.Pin(); - if (BrowserWindow.IsValid()) + if (WebBrowserWindowPtr.IsValid()) { - FString Origin = Url.Left(Position); - FString Message = Url.RightChop(Position + FAndroidJSScripting::JSMessageTag.Len()); - - TArray Params; - Message.ParseIntoArray(Params, TEXT("/"), false); - if (Params.Num() > 0) + TSharedPtr BrowserWindow = WebBrowserWindowPtr.Pin(); + if (BrowserWindow.IsValid()) { - for(int I=0; I Params; + Message.ParseIntoArray(Params, TEXT("/"), false); + if (Params.Num() > 0) { - Params[I] = FPlatformHttp::UrlDecode(Params[I]); - } + for (int I = 0; I < Params.Num(); I++) + { + Params[I] = FPlatformHttp::UrlDecode(Params[I]); + } - FString Command = Params[0]; - Params.RemoveAt(0,1); - BrowserWindow->OnJsMessageReceived(Command, Params, Origin); - } - else - { - GLog->Logf(ELogVerbosity::Error,TEXT("Invalid message from browser view: %s"), *Message); + FString Command = Params[0]; + Params.RemoveAt(0, 1); + BrowserWindow->OnJsMessageReceived(Command, Params, Origin); + } + else + { + GLog->Logf(ELogVerbosity::Error, TEXT("Invalid message from browser view: %s"), *Message); + } } } }); @@ -163,11 +194,14 @@ jbyteArray SAndroidWebBrowserWidget::HandleShouldInterceptRequest(jstring JUrl) } else { - TSharedPtr BrowserWindow = WebBrowserWindowPtr.Pin(); - if (BrowserWindow.IsValid() && BrowserWindow->OnLoadUrl().IsBound()) + if (WebBrowserWindowPtr.IsValid()) { - FString Method = TEXT(""); // We don't support passing anything but the requested URL - bOverrideResponse = BrowserWindow->OnLoadUrl().Execute(Method, Url, Response); + TSharedPtr BrowserWindow = WebBrowserWindowPtr.Pin(); + if (BrowserWindow.IsValid() && BrowserWindow->OnLoadUrl().IsBound()) + { + FString Method = TEXT(""); // We don't support passing anything but the requested URL + bOverrideResponse = BrowserWindow->OnLoadUrl().Execute(Method, Url, Response); + } } } @@ -190,16 +224,19 @@ bool SAndroidWebBrowserWidget::HandleShouldOverrideUrlLoading(jstring JUrl) JEnv->ReleaseStringUTFChars(JUrl, JUrlChars); bool Retval = false; - TSharedPtr BrowserWindow = WebBrowserWindowPtr.Pin(); - if (BrowserWindow.IsValid()) + if (WebBrowserWindowPtr.IsValid()) { - if (BrowserWindow->OnBeforeBrowse().IsBound() ) + TSharedPtr BrowserWindow = WebBrowserWindowPtr.Pin(); + if (BrowserWindow.IsValid()) { - FWebNavigationRequest RequestDetails; - RequestDetails.bIsRedirect = false; - RequestDetails.bIsMainFrame = true; // shouldOverrideUrlLoading is only called on the main frame + if (BrowserWindow->OnBeforeBrowse().IsBound()) + { + FWebNavigationRequest RequestDetails; + RequestDetails.bIsRedirect = false; + RequestDetails.bIsMainFrame = true; // shouldOverrideUrlLoading is only called on the main frame - Retval = BrowserWindow->OnBeforeBrowse().Execute(Url, RequestDetails); + Retval = BrowserWindow->OnBeforeBrowse().Execute(Url, RequestDetails); + } } } return Retval; @@ -208,27 +245,30 @@ bool SAndroidWebBrowserWidget::HandleShouldOverrideUrlLoading(jstring JUrl) bool SAndroidWebBrowserWidget::HandleJsDialog(TSharedPtr& Dialog) { bool Retval = false; - TSharedPtr BrowserWindow = WebBrowserWindowPtr.Pin(); - if (BrowserWindow.IsValid() && BrowserWindow->OnShowDialog().IsBound() ) + if (WebBrowserWindowPtr.IsValid()) { - EWebBrowserDialogEventResponse EventResponse = BrowserWindow->OnShowDialog().Execute(TWeakPtr(Dialog)); - switch (EventResponse) + TSharedPtr BrowserWindow = WebBrowserWindowPtr.Pin(); + if (BrowserWindow.IsValid() && BrowserWindow->OnShowDialog().IsBound()) { - case EWebBrowserDialogEventResponse::Handled: - Retval = true; - break; - case EWebBrowserDialogEventResponse::Continue: - Dialog->Continue(true, (Dialog->GetType() == EWebBrowserDialogType::Prompt)?Dialog->GetDefaultPrompt():FText::GetEmpty()); - Retval = true; - break; - case EWebBrowserDialogEventResponse::Ignore: - Dialog->Continue(false); - Retval = true; - break; - case EWebBrowserDialogEventResponse::Unhandled: - default: - Retval = false; - break; + EWebBrowserDialogEventResponse EventResponse = BrowserWindow->OnShowDialog().Execute(TWeakPtr(Dialog)); + switch (EventResponse) + { + case EWebBrowserDialogEventResponse::Handled: + Retval = true; + break; + case EWebBrowserDialogEventResponse::Continue: + Dialog->Continue(true, (Dialog->GetType() == EWebBrowserDialogType::Prompt) ? Dialog->GetDefaultPrompt() : FText::GetEmpty()); + Retval = true; + break; + case EWebBrowserDialogEventResponse::Ignore: + Dialog->Continue(false); + Retval = true; + break; + case EWebBrowserDialogEventResponse::Unhandled: + default: + Retval = false; + break; + } } } return Retval; @@ -242,10 +282,13 @@ void SAndroidWebBrowserWidget::HandleReceivedTitle(jstring JTitle) FString Title = UTF8_TO_TCHAR(JTitleChars); JEnv->ReleaseStringUTFChars(JTitle, JTitleChars); - TSharedPtr BrowserWindow = WebBrowserWindowPtr.Pin(); - if (BrowserWindow.IsValid()) + if (WebBrowserWindowPtr.IsValid()) { - BrowserWindow->SetTitle(Title); + TSharedPtr BrowserWindow = WebBrowserWindowPtr.Pin(); + if (BrowserWindow.IsValid()) + { + BrowserWindow->SetTitle(Title); + } } } @@ -260,10 +303,13 @@ void SAndroidWebBrowserWidget::HandlePageLoad(jstring JUrl, bool bIsLoading, int FString Url = UTF8_TO_TCHAR(JUrlChars); JEnv->ReleaseStringUTFChars(JUrl, JUrlChars); - TSharedPtr BrowserWindow = WebBrowserWindowPtr.Pin(); - if (BrowserWindow.IsValid()) + if (WebBrowserWindowPtr.IsValid()) { - BrowserWindow->NotifyDocumentLoadingStateChange(Url, bIsLoading); + TSharedPtr BrowserWindow = WebBrowserWindowPtr.Pin(); + if (BrowserWindow.IsValid()) + { + BrowserWindow->NotifyDocumentLoadingStateChange(Url, bIsLoading); + } } } @@ -275,10 +321,13 @@ void SAndroidWebBrowserWidget::HandleReceivedError(jint ErrorCode, jstring /* ig FString Url = UTF8_TO_TCHAR(JUrlChars); JEnv->ReleaseStringUTFChars(JUrl, JUrlChars); - TSharedPtr BrowserWindow = WebBrowserWindowPtr.Pin(); - if (BrowserWindow.IsValid()) + if (WebBrowserWindowPtr.IsValid()) { - BrowserWindow->NotifyDocumentError(Url, ErrorCode); + TSharedPtr BrowserWindow = WebBrowserWindowPtr.Pin(); + if (BrowserWindow.IsValid()) + { + BrowserWindow->NotifyDocumentError(Url, ErrorCode); + } } } @@ -286,58 +335,105 @@ void SAndroidWebBrowserWidget::HandleReceivedError(jint ErrorCode, jstring /* ig JNI_METHOD jbyteArray Java_com_epicgames_ue4_WebViewControl_00024ViewClient_shouldInterceptRequestImpl(JNIEnv* JEnv, jobject Client, jstring JUrl) { - SAndroidWebBrowserWidget* Widget=SAndroidWebBrowserWidget::GetWidgetPtr(JEnv, Client); - check(Widget != nullptr); - return Widget->HandleShouldInterceptRequest(JUrl); + TSharedPtr Widget = SAndroidWebBrowserWidget::GetWidgetPtr(JEnv, Client); + if (Widget.IsValid()) + { + return Widget->HandleShouldInterceptRequest(JUrl); + } + else + { + return nullptr; + } } JNI_METHOD jboolean Java_com_epicgames_ue4_WebViewControl_00024ViewClient_shouldOverrideUrlLoading(JNIEnv* JEnv, jobject Client, jobject /* ignore */, jstring JUrl) { - SAndroidWebBrowserWidget* Widget=SAndroidWebBrowserWidget::GetWidgetPtr(JEnv, Client); - check(Widget != nullptr); - return Widget->HandleShouldOverrideUrlLoading(JUrl); + TSharedPtr Widget = SAndroidWebBrowserWidget::GetWidgetPtr(JEnv, Client); + if (Widget.IsValid()) + { + return Widget->HandleShouldOverrideUrlLoading(JUrl); + } + else + { + return false; + } } JNI_METHOD void Java_com_epicgames_ue4_WebViewControl_00024ViewClient_onPageLoad(JNIEnv* JEnv, jobject Client, jstring JUrl, jboolean bIsLoading, jint HistorySize, jint HistoryPosition) { - SAndroidWebBrowserWidget* Widget=SAndroidWebBrowserWidget::GetWidgetPtr(JEnv, Client); - check(Widget != nullptr); - Widget->HandlePageLoad(JUrl, bIsLoading, HistorySize, HistoryPosition); + TSharedPtr Widget = SAndroidWebBrowserWidget::GetWidgetPtr(JEnv, Client); + if (Widget.IsValid()) + { + Widget->HandlePageLoad(JUrl, bIsLoading, HistorySize, HistoryPosition); + } } JNI_METHOD void Java_com_epicgames_ue4_WebViewControl_00024ViewClient_onReceivedError(JNIEnv* JEnv, jobject Client, jobject /* ignore */, jint ErrorCode, jstring Description, jstring JUrl) { - SAndroidWebBrowserWidget* Widget=SAndroidWebBrowserWidget::GetWidgetPtr(JEnv, Client); - check(Widget != nullptr); - Widget->HandleReceivedError(ErrorCode, Description, JUrl); + TSharedPtr Widget = SAndroidWebBrowserWidget::GetWidgetPtr(JEnv, Client); + if (Widget.IsValid()) + { + Widget->HandleReceivedError(ErrorCode, Description, JUrl); + } } JNI_METHOD jboolean Java_com_epicgames_ue4_WebViewControl_00024ChromeClient_onJsAlert(JNIEnv* JEnv, jobject Client, jobject /* ignore */, jstring JUrl, jstring Message, jobject Result) { - SAndroidWebBrowserWidget* Widget=SAndroidWebBrowserWidget::GetWidgetPtr(JEnv, Client); - return Widget->HandleJsDialog(EWebBrowserDialogType::Alert, JUrl, Message, Result); + TSharedPtr Widget = SAndroidWebBrowserWidget::GetWidgetPtr(JEnv, Client); + if (Widget.IsValid()) + { + return Widget->HandleJsDialog(EWebBrowserDialogType::Alert, JUrl, Message, Result); + } + else + { + return false; + } } JNI_METHOD jboolean Java_com_epicgames_ue4_WebViewControl_00024ChromeClient_onJsBeforeUnload(JNIEnv* JEnv, jobject Client, jobject /* ignore */, jstring JUrl, jstring Message, jobject Result) { - SAndroidWebBrowserWidget* Widget=SAndroidWebBrowserWidget::GetWidgetPtr(JEnv, Client); - return Widget->HandleJsDialog(EWebBrowserDialogType::Unload, JUrl, Message, Result); + TSharedPtr Widget = SAndroidWebBrowserWidget::GetWidgetPtr(JEnv, Client); + if (Widget.IsValid()) + { + return Widget->HandleJsDialog(EWebBrowserDialogType::Unload, JUrl, Message, Result); + } + else + { + return false; + } } JNI_METHOD jboolean Java_com_epicgames_ue4_WebViewControl_00024ChromeClient_onJsConfirm(JNIEnv* JEnv, jobject Client, jobject /* ignore */, jstring JUrl, jstring Message, jobject Result) { - SAndroidWebBrowserWidget* Widget=SAndroidWebBrowserWidget::GetWidgetPtr(JEnv, Client); - return Widget->HandleJsDialog(EWebBrowserDialogType::Confirm, JUrl, Message, Result); + TSharedPtr Widget = SAndroidWebBrowserWidget::GetWidgetPtr(JEnv, Client); + if (Widget.IsValid()) + { + return Widget->HandleJsDialog(EWebBrowserDialogType::Confirm, JUrl, Message, Result); + } + else + { + return false; + } } JNI_METHOD jboolean Java_com_epicgames_ue4_WebViewControl_00024ChromeClient_onJsPrompt(JNIEnv* JEnv, jobject Client, jobject /* ignore */, jstring JUrl, jstring Message, jstring DefaultValue, jobject Result) { - SAndroidWebBrowserWidget* Widget=SAndroidWebBrowserWidget::GetWidgetPtr(JEnv, Client); - return Widget->HandleJsPrompt(JUrl, Message, DefaultValue, Result); + TSharedPtr Widget = SAndroidWebBrowserWidget::GetWidgetPtr(JEnv, Client); + if (Widget.IsValid()) + { + return Widget->HandleJsPrompt(JUrl, Message, DefaultValue, Result); + } + else + { + return false; + } } JNI_METHOD void Java_com_epicgames_ue4_WebViewControl_00024ChromeClient_onReceivedTitle(JNIEnv* JEnv, jobject Client, jobject /* ignore */, jstring Title) { - SAndroidWebBrowserWidget* Widget=SAndroidWebBrowserWidget::GetWidgetPtr(JEnv, Client); - Widget->HandleReceivedTitle(Title); + TSharedPtr Widget = SAndroidWebBrowserWidget::GetWidgetPtr(JEnv, Client); + if (Widget.IsValid()) + { + Widget->HandleReceivedTitle(Title); + } } diff --git a/Engine/Source/Runtime/WebBrowser/Private/Android/AndroidWebBrowserWidget.h b/Engine/Source/Runtime/WebBrowser/Private/Android/AndroidWebBrowserWidget.h index fa84714a70e3..b8f82c84fb43 100644 --- a/Engine/Source/Runtime/WebBrowser/Private/Android/AndroidWebBrowserWidget.h +++ b/Engine/Source/Runtime/WebBrowser/Private/Android/AndroidWebBrowserWidget.h @@ -14,13 +14,18 @@ class SAndroidWebBrowserWidget : public SLeafWidget { SLATE_BEGIN_ARGS(SAndroidWebBrowserWidget) : _InitialURL("about:blank") + , _UseTransparency(false) { } SLATE_ARGUMENT(FString, InitialURL); + SLATE_ARGUMENT(bool, UseTransparency); SLATE_ARGUMENT(TSharedPtr, WebBrowserWindow); + SLATE_END_ARGS() public: + virtual ~SAndroidWebBrowserWidget(); + void Construct(const FArguments& Args); virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override; @@ -62,15 +67,12 @@ public: // Helper to get the native widget pointer from a Java callback. // Jobj can either be a WebViewControl, a WebViewControl.ViewClient or WebViewControl.ChromeClient instance - static SAndroidWebBrowserWidget* GetWidgetPtr(JNIEnv* JEnv, jobject Jobj) - { - jclass Class = JEnv->GetObjectClass(Jobj); - jmethodID JMethod = JEnv->GetMethodID(Class, "GetNativePtr", "()J"); - check(JMethod != nullptr); - return reinterpret_cast(JEnv->CallLongMethod(Jobj, JMethod)); - } + static TSharedPtr GetWidgetPtr(JNIEnv* JEnv, jobject Jobj); protected: + static FCriticalSection WebControlsCS; + static TMap> AllWebControls; + bool HandleJsDialog(TSharedPtr& Dialog); int HistorySize; int HistoryPosition; diff --git a/Engine/Source/Runtime/WebBrowser/Private/Android/AndroidWebBrowserWindow.cpp b/Engine/Source/Runtime/WebBrowser/Private/Android/AndroidWebBrowserWindow.cpp index d34ca58e2ce0..03235bc6c312 100644 --- a/Engine/Source/Runtime/WebBrowser/Private/Android/AndroidWebBrowserWindow.cpp +++ b/Engine/Source/Runtime/WebBrowser/Private/Android/AndroidWebBrowserWindow.cpp @@ -22,6 +22,7 @@ namespace { FAndroidWebBrowserWindow::FAndroidWebBrowserWindow(FString InUrl, TOptional InContentsToLoad, bool InShowErrorMessage, bool InThumbMouseButtonNavigation, bool InUseTransparency, bool bInJSBindingToLoweringEnabled) : CurrentUrl(MoveTemp(InUrl)) , ContentsToLoad(MoveTemp(InContentsToLoad)) + , bUseTransparency(InUseTransparency) , DocumentState(EWebBrowserDocumentState::NoDocument) , ErrorCode(0) , Scripting(new FAndroidJSScripting(bInJSBindingToLoweringEnabled)) @@ -47,6 +48,7 @@ TSharedRef FAndroidWebBrowserWindow::CreateWidget() { TSharedRef BrowserWidgetRef = SNew(SAndroidWebBrowserWidget) + .UseTransparency(bUseTransparency) .InitialURL(CurrentUrl) .WebBrowserWindow(SharedThis(this)); diff --git a/Engine/Source/Runtime/WebBrowser/Private/Android/AndroidWebBrowserWindow.h b/Engine/Source/Runtime/WebBrowser/Private/Android/AndroidWebBrowserWindow.h index e449c60ff065..e687ae61daaf 100644 --- a/Engine/Source/Runtime/WebBrowser/Private/Android/AndroidWebBrowserWindow.h +++ b/Engine/Source/Runtime/WebBrowser/Private/Android/AndroidWebBrowserWindow.h @@ -204,6 +204,9 @@ private: /** Optional text to load as a web page. */ TOptional ContentsToLoad; + /** Whether to enable background transparency */ + bool bUseTransparency; + /** Delegate for broadcasting load state changes. */ FOnDocumentStateChanged DocumentStateChangedEvent; diff --git a/Engine/Source/Runtime/WebBrowser/Private/CEF/CEFBrowserByteResource.cpp b/Engine/Source/Runtime/WebBrowser/Private/CEF/CEFBrowserByteResource.cpp index d2b7f41e4476..62063e92d425 100644 --- a/Engine/Source/Runtime/WebBrowser/Private/CEF/CEFBrowserByteResource.cpp +++ b/Engine/Source/Runtime/WebBrowser/Private/CEF/CEFBrowserByteResource.cpp @@ -4,6 +4,24 @@ #if WITH_CEF3 +FCEFBrowserByteResource::FCEFBrowserByteResource(const CefRefPtr& PostData, const FString& InMimeType) + : Position(0) + , Buffer(nullptr) + , MimeType(InMimeType) +{ + Size = PostData->GetBytesCount(); + if (Size > 0) + { + Buffer = new unsigned char[Size]; + PostData->GetBytes(Size, Buffer); + } +} + +FCEFBrowserByteResource::~FCEFBrowserByteResource() +{ + delete[] Buffer; +} + void FCEFBrowserByteResource::Cancel() { @@ -11,7 +29,7 @@ void FCEFBrowserByteResource::Cancel() void FCEFBrowserByteResource::GetResponseHeaders(CefRefPtr Response, int64& ResponseLength, CefString& RedirectUrl) { - Response->SetMimeType("text/html"); + Response->SetMimeType(*MimeType); Response->SetStatus(200); Response->SetStatusText("OK"); ResponseLength = Size; diff --git a/Engine/Source/Runtime/WebBrowser/Private/CEF/CEFBrowserByteResource.h b/Engine/Source/Runtime/WebBrowser/Private/CEF/CEFBrowserByteResource.h index 9d3172b8f1ed..5f03047997b3 100644 --- a/Engine/Source/Runtime/WebBrowser/Private/CEF/CEFBrowserByteResource.h +++ b/Engine/Source/Runtime/WebBrowser/Private/CEF/CEFBrowserByteResource.h @@ -34,16 +34,8 @@ class FCEFBrowserByteResource public: /** */ - FCEFBrowserByteResource(const void* InBuffer, int32 InSize) : Position(0), Size(InSize) - { - Buffer = new unsigned char[Size]; - FMemory::Memcpy(Buffer, InBuffer, Size); - } - - ~FCEFBrowserByteResource() - { - delete[] Buffer; - } + FCEFBrowserByteResource(const CefRefPtr& PostData, const FString& InMimeType); + ~FCEFBrowserByteResource(); // CefResourceHandler interface virtual void Cancel() override; @@ -55,6 +47,7 @@ private: int32 Position; int32 Size; unsigned char* Buffer; + FString MimeType; // Include the default reference counting implementation. IMPLEMENT_REFCOUNTING(FCEFBrowserByteResource); diff --git a/Engine/Source/Runtime/WebBrowser/Private/CEF/CEFBrowserHandler.cpp b/Engine/Source/Runtime/WebBrowser/Private/CEF/CEFBrowserHandler.cpp index 4a11d428a0bf..d5e7edc3abb8 100644 --- a/Engine/Source/Runtime/WebBrowser/Private/CEF/CEFBrowserHandler.cpp +++ b/Engine/Source/Runtime/WebBrowser/Private/CEF/CEFBrowserHandler.cpp @@ -19,7 +19,6 @@ // Used to force returning custom content instead of performing a request. -const FString CustomContentHeader(TEXT("X-UE-Content")); const FString CustomContentMethod(TEXT("X-GET-CUSTOM-CONTENT")); FCEFBrowserHandler::FCEFBrowserHandler(bool InUseTransparency) @@ -361,8 +360,23 @@ CefRequestHandler::ReturnValue FCEFBrowserHandler::OnBeforeResourceLoad(CefRefPt TOptional Contents = BrowserWindow->GetResourceContent(Frame, Request); if(Contents.IsSet()) { - // Set a custom request header, so that we can return it wrapped in a custom resource handler in GetResourceHandler later on - HeaderMap.insert(std::pair(*CustomContentHeader, *Contents.GetValue())); + // pass the text we'd like to come back as a response to the request post data + CefRefPtr PostData = CefPostData::Create(); + CefRefPtr Element = CefPostDataElement::Create(); + FTCHARToUTF8 UTF8String(*Contents.GetValue()); + Element->SetToBytes(UTF8String.Length(), UTF8String.Get()); + PostData->AddElement(Element); + Request->SetPostData(PostData); + + // Set a custom request header, so we know the mime type if it was specified as a hash on the dummy URL + std::string Url = Request->GetURL().ToString(); + std::string::size_type HashPos = Url.find_last_of('#'); + if (HashPos != std::string::npos) + { + std::string MimeType = Url.substr(HashPos + 1); + HeaderMap.insert(std::pair(TEXT("Content-Type"), MimeType)); + } + // Change http method to tell GetResourceHandler to return the content Request->SetMethod(*CustomContentMethod); } @@ -410,13 +424,22 @@ CefRefPtr FCEFBrowserHandler::GetResourceHandler( CefRefPtr< if (Request->GetMethod() == *CustomContentMethod) { // Content override header will be set by OnBeforeResourceLoad before passing the request on to this. - CefRequest::HeaderMap HeaderMap; - Request->GetHeaderMap(HeaderMap); - auto ContentOverride = HeaderMap.find(*CustomContentHeader); - if (ContentOverride != HeaderMap.end()) + if (Request->GetPostData() && Request->GetPostData()->GetElementCount() > 0) { - std::string Convert = ContentOverride->second.ToString(); - return new FCEFBrowserByteResource(Convert.c_str(), Convert.length()); + // get the mime type from Content-Type header (default to text/html to support old behavior) + FString MimeType = TEXT("text/html"); // default if not specified + CefRequest::HeaderMap HeaderMap; + Request->GetHeaderMap(HeaderMap); + auto ContentOverride = HeaderMap.find(TEXT("Content-Type")); + if (ContentOverride != HeaderMap.end()) + { + MimeType = ContentOverride->second.ToWString().c_str(); + } + + // reply with the post data + CefPostData::ElementVector Elements; + Request->GetPostData()->GetElements(Elements); + return new FCEFBrowserByteResource(Elements[0], MimeType); } } return nullptr; diff --git a/Engine/Source/Runtime/WebBrowser/Private/IOS/IOSPlatformWebBrowser.cpp b/Engine/Source/Runtime/WebBrowser/Private/IOS/IOSPlatformWebBrowser.cpp index 0cf31a9499e8..b4ba7612e7d6 100644 --- a/Engine/Source/Runtime/WebBrowser/Private/IOS/IOSPlatformWebBrowser.cpp +++ b/Engine/Source/Runtime/WebBrowser/Private/IOS/IOSPlatformWebBrowser.cpp @@ -17,7 +17,7 @@ @synthesize NextURL; @synthesize NextContent; --(void)create:(TSharedPtr)InWebBrowserWidget; +-(void)create:(TSharedPtr)InWebBrowserWidget useTransparency:(bool)InUseTransparency; { WebBrowserWidget = InWebBrowserWidget; NextURL = nil; @@ -29,6 +29,16 @@ { WebView = [[UIWebView alloc]initWithFrame:CGRectMake(1, 1, 100, 100)]; WebView.delegate = self; + + if (InUseTransparency) + { + [self.WebView setOpaque:NO]; + [self.WebView setBackgroundColor:[UIColor clearColor]]; + } + else + { + [self.WebView setOpaque:YES]; + } }); #endif } @@ -97,7 +107,7 @@ { dispatch_async(dispatch_get_main_queue(), ^ { - NextURL = InURL; + self.NextURL = InURL; }); } @@ -105,8 +115,8 @@ { dispatch_async(dispatch_get_main_queue(), ^ { - NextContent = InString; - NextURL = InURL; + self.NextContent = InString; + self.NextURL = InURL; }); } @@ -116,8 +126,12 @@ class SIOSWebBrowserWidget : public SLeafWidget { SLATE_BEGIN_ARGS(SIOSWebBrowserWidget) : _InitialURL("about:blank") + , _UseTransparency(false) { } + SLATE_ARGUMENT(FString, InitialURL); + SLATE_ARGUMENT(bool, UseTransparency); + SLATE_END_ARGS() SIOSWebBrowserWidget() @@ -127,7 +141,7 @@ class SIOSWebBrowserWidget : public SLeafWidget void Construct(const FArguments& Args) { WebViewWrapper = [IOSWebViewWrapper alloc]; - [WebViewWrapper create: TSharedPtr(this)]; + [WebViewWrapper create: TSharedPtr(this) useTransparency:Args._UseTransparency]; LoadURL(Args._InitialURL); } @@ -202,6 +216,7 @@ protected: FWebBrowserWindow::FWebBrowserWindow(FString InUrl, TOptional InContentsToLoad, bool InShowErrorMessage, bool InThumbMouseButtonNavigation, bool InUseTransparency) : CurrentUrl(MoveTemp(InUrl)) , ContentsToLoad(MoveTemp(InContentsToLoad)) + , bUseTransparency(InUseTransparency) { } @@ -224,6 +239,7 @@ TSharedRef FWebBrowserWindow::CreateWidget() { TSharedRef BrowserWidgetRef = SNew(SIOSWebBrowserWidget) + .UseTransparency(bUseTransparency) .InitialURL(CurrentUrl); BrowserWidget = BrowserWidgetRef; diff --git a/Engine/Source/Runtime/WebBrowser/Private/IOS/IOSPlatformWebBrowser.h b/Engine/Source/Runtime/WebBrowser/Private/IOS/IOSPlatformWebBrowser.h index 7b2c553fde79..80c8ef6c74fb 100644 --- a/Engine/Source/Runtime/WebBrowser/Private/IOS/IOSPlatformWebBrowser.h +++ b/Engine/Source/Runtime/WebBrowser/Private/IOS/IOSPlatformWebBrowser.h @@ -33,7 +33,7 @@ class SWebBrowserView; @property(copy) NSString* NextContent; @property CGRect DesiredFrame; --(void)create:(TSharedPtr)InWebBrowserWidget; +-(void)create:(TSharedPtr)InWebBrowserWidget useTransparency:(bool)InUseTransparency; -(void)close; -(void)updateframe:(CGRect)InFrame; -(void)loadstring:(NSString*)InString dummyurl:(NSURL*)InURL; @@ -223,6 +223,9 @@ private: /** Optional text to load as a web page. */ TOptional ContentsToLoad; + + /** Whether to enable background transparency */ + bool bUseTransparency; // TODO: None of these events are actually called diff --git a/Engine/Source/Runtime/WebBrowser/WebBrowser.Build.cs b/Engine/Source/Runtime/WebBrowser/WebBrowser.Build.cs index 2d73cb2e3217..daadac37cea9 100644 --- a/Engine/Source/Runtime/WebBrowser/WebBrowser.Build.cs +++ b/Engine/Source/Runtime/WebBrowser/WebBrowser.Build.cs @@ -39,21 +39,24 @@ public class WebBrowser : ModuleRules "CEF3" ); - if (Target.Platform == UnrealTargetPlatform.Mac) + if (Target.Type != TargetType.Server) { - // Add contents of UnrealCefSubProcess.app directory as runtime dependencies - foreach (string FilePath in Directory.EnumerateFiles(BuildConfiguration.RelativeEnginePath + "/Binaries/Mac/UnrealCEFSubProcess.app", "*", SearchOption.AllDirectories)) + if (Target.Platform == UnrealTargetPlatform.Mac) { - RuntimeDependencies.Add(new RuntimeDependency(FilePath)); + // Add contents of UnrealCefSubProcess.app directory as runtime dependencies + foreach (string FilePath in Directory.EnumerateFiles(BuildConfiguration.RelativeEnginePath + "/Binaries/Mac/UnrealCEFSubProcess.app", "*", SearchOption.AllDirectories)) + { + RuntimeDependencies.Add(new RuntimeDependency(FilePath)); + } + } + else if (Target.Platform == UnrealTargetPlatform.Linux) + { + RuntimeDependencies.Add(new RuntimeDependency("$(EngineDir)/Binaries/" + Target.Platform.ToString() + "/UnrealCEFSubProcess")); + } + else + { + RuntimeDependencies.Add(new RuntimeDependency("$(EngineDir)/Binaries/" + Target.Platform.ToString() + "/UnrealCEFSubProcess.exe")); } - } - else if (Target.Platform == UnrealTargetPlatform.Linux) - { - RuntimeDependencies.Add(new RuntimeDependency("$(EngineDir)/Binaries/" + Target.Platform.ToString() + "/UnrealCEFSubProcess")); - } - else - { - RuntimeDependencies.Add(new RuntimeDependency("$(EngineDir)/Binaries/" + Target.Platform.ToString() + "/UnrealCEFSubProcess.exe")); } } diff --git a/Engine/Source/Runtime/WidgetCarousel/Public/WidgetCarouselStyle.h b/Engine/Source/Runtime/WidgetCarousel/Public/WidgetCarouselStyle.h index f40bd327a9d2..209dd6ad7787 100644 --- a/Engine/Source/Runtime/WidgetCarousel/Public/WidgetCarouselStyle.h +++ b/Engine/Source/Runtime/WidgetCarousel/Public/WidgetCarouselStyle.h @@ -39,7 +39,7 @@ struct WIDGETCAROUSEL_API FWidgetCarouselNavigationButtonStyle : public FSlateWi FWidgetCarouselNavigationButtonStyle& SetNavigationButtonRightImage(const FSlateBrush& InNavigationButtonRightImage) { NavigationButtonRightImage = InNavigationButtonRightImage; return *this; } }; -USTRUCT() +USTRUCT(BlueprintType) struct WIDGETCAROUSEL_API FWidgetCarouselNavigationBarStyle : public FSlateWidgetStyle { GENERATED_USTRUCT_BODY() diff --git a/Engine/Source/Runtime/Windows/AudioMixerXAudio2/Private/AudioMixerPlatformWindows.cpp b/Engine/Source/Runtime/Windows/AudioMixerXAudio2/Private/AudioMixerPlatformWindows.cpp index 502721b4bbad..c19fc18e9119 100644 --- a/Engine/Source/Runtime/Windows/AudioMixerXAudio2/Private/AudioMixerPlatformWindows.cpp +++ b/Engine/Source/Runtime/Windows/AudioMixerXAudio2/Private/AudioMixerPlatformWindows.cpp @@ -18,7 +18,7 @@ #include #include -class FWindowsMMNotificationClient : public IMMNotificationClient +class FWindowsMMNotificationClient final : public IMMNotificationClient { public: FWindowsMMNotificationClient() @@ -33,7 +33,7 @@ public: } } - ~FWindowsMMNotificationClient() + virtual ~FWindowsMMNotificationClient() { if (DeviceEnumerator) { diff --git a/Engine/Source/Runtime/Windows/AudioMixerXAudio2/Private/AudioMixerPlatformXAudio2.cpp b/Engine/Source/Runtime/Windows/AudioMixerXAudio2/Private/AudioMixerPlatformXAudio2.cpp index 664c1478b832..f51f263786c0 100644 --- a/Engine/Source/Runtime/Windows/AudioMixerXAudio2/Private/AudioMixerPlatformXAudio2.cpp +++ b/Engine/Source/Runtime/Windows/AudioMixerXAudio2/Private/AudioMixerPlatformXAudio2.cpp @@ -33,6 +33,7 @@ return false; \ } + namespace Audio { void FXAudio2VoiceCallback::OnBufferEnd(void* BufferContext) @@ -89,12 +90,14 @@ namespace Audio case HRESULT(XAUDIO2_E_XMA_DECODER_ERROR): return TEXT("XAUDIO2_E_XMA_DECODER_ERROR"); case HRESULT(XAUDIO2_E_XAPO_CREATION_FAILED): return TEXT("XAUDIO2_E_XAPO_CREATION_FAILED"); case HRESULT(XAUDIO2_E_DEVICE_INVALIDATED): return TEXT("XAUDIO2_E_DEVICE_INVALIDATED"); +#if PLATFORM_WINDOWS case REGDB_E_CLASSNOTREG: return TEXT("REGDB_E_CLASSNOTREG"); case CLASS_E_NOAGGREGATION: return TEXT("CLASS_E_NOAGGREGATION"); case E_NOINTERFACE: return TEXT("E_NOINTERFACE"); case E_POINTER: return TEXT("E_POINTER"); case E_INVALIDARG: return TEXT("E_INVALIDARG"); case E_OUTOFMEMORY: return TEXT("E_OUTOFMEMORY"); +#endif default: return TEXT("UKNOWN"); } } @@ -111,7 +114,9 @@ namespace Audio // Load ogg and vorbis dlls if they haven't been loaded yet LoadVorbisLibraries(); +#if PLATFORM_WINDOWS bIsComInitialized = FWindowsPlatformMisc::CoInitialize(); +#endif XAUDIO2_RETURN_ON_FAIL(XAudio2Create(&XAudio2System, 0, (XAUDIO2_PROCESSOR)FPlatformAffinity::GetAudioThreadMask())); @@ -130,10 +135,13 @@ namespace Audio SAFE_RELEASE(XAudio2System); +#if PLATFORM_WINDOWS if (bIsComInitialized) { FWindowsPlatformMisc::CoUninitialize(); } +#endif + bIsInitialized = false; return true; @@ -152,8 +160,12 @@ namespace Audio return false; } +#if PLATFORM_WINDOWS check(XAudio2System); XAUDIO2_RETURN_ON_FAIL(XAudio2System->GetDeviceCount(&OutNumOutputDevices)); +#else + OutNumOutputDevices = 1; +#endif return true; } @@ -165,6 +177,8 @@ namespace Audio return false; } +#if PLATFORM_WINDOWS + check(XAudio2System); XAUDIO2_DEVICE_DETAILS DeviceDetails; @@ -238,6 +252,25 @@ namespace Audio UE_LOG(LogAudioMixerDebug, Log, TEXT("%d: %s"), i, EAudioMixerChannel::ToString(OutInfo.OutputChannelArray[i])); } } +#else // #if PLATFORM_WINDOWS + + OutInfo.bIsSystemDefault = true; + OutInfo.SampleRate = 44100; + OutInfo.DeviceId = 0; + OutInfo.Format = EAudioMixerStreamDataFormat::Float; + OutInfo.Latency = 0; + OutInfo.Name = TEXT("XBoxOne Audio Device."); + OutInfo.NumChannels = 8; + + OutInfo.OutputChannelArray.Add(EAudioMixerChannel::FrontLeft); + OutInfo.OutputChannelArray.Add(EAudioMixerChannel::FrontRight); + OutInfo.OutputChannelArray.Add(EAudioMixerChannel::FrontCenter); + OutInfo.OutputChannelArray.Add(EAudioMixerChannel::LowFrequency); + OutInfo.OutputChannelArray.Add(EAudioMixerChannel::BackLeft); + OutInfo.OutputChannelArray.Add(EAudioMixerChannel::BackRight); + OutInfo.OutputChannelArray.Add(EAudioMixerChannel::SideLeft); + OutInfo.OutputChannelArray.Add(EAudioMixerChannel::SideRight); +#endif // #else // #if PLATFORM_WINDOWS return true; } @@ -268,11 +301,14 @@ namespace Audio WAVEFORMATEX Format = { 0 }; + OpenStreamParams = Params; + AudioStreamInfo.Reset(); - AudioStreamInfo.OutputDeviceIndex = Params.OutputDeviceIndex; - AudioStreamInfo.NumOutputFrames = Params.NumFrames; - AudioStreamInfo.AudioMixer = Params.AudioMixer; + AudioStreamInfo.OutputDeviceIndex = OpenStreamParams.OutputDeviceIndex; + AudioStreamInfo.NumOutputFrames = OpenStreamParams.NumFrames; + AudioStreamInfo.NumBuffers = OpenStreamParams.NumBuffers; + AudioStreamInfo.AudioMixer = OpenStreamParams.AudioMixer; if (!GetOutputDeviceInfo(AudioStreamInfo.OutputDeviceIndex, AudioStreamInfo.DeviceInfo)) { @@ -285,21 +321,15 @@ namespace Audio OriginalAudioDeviceId = AudioStreamInfo.DeviceInfo.DeviceId; } - AudioStreamInfo.DeviceInfo.NumFrames = Params.NumFrames; - AudioStreamInfo.DeviceInfo.NumSamples = AudioStreamInfo.DeviceInfo.NumFrames * AudioStreamInfo.DeviceInfo.NumChannels; - HRESULT Result = XAudio2System->CreateMasteringVoice(&OutputAudioStreamMasteringVoice, AudioStreamInfo.DeviceInfo.NumChannels, AudioStreamInfo.DeviceInfo.SampleRate, 0, AudioStreamInfo.OutputDeviceIndex, nullptr); XAUDIO2_CLEANUP_ON_FAIL(Result); - // Xaudio2 on windows, no need for byte swap - AudioStreamInfo.bPerformByteSwap = false; - // Start the xaudio2 engine running, which will now allow us to start feeding audio to it XAudio2System->StartEngine(); // Setup the format of the output source voice Format.nChannels = AudioStreamInfo.DeviceInfo.NumChannels; - Format.nSamplesPerSec = AUDIO_SAMPLE_RATE; + Format.nSamplesPerSec = Params.SampleRate; Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; Format.nAvgBytesPerSec = Format.nSamplesPerSec * sizeof(float) * Format.nChannels; Format.nBlockAlign = sizeof(float) * Format.nChannels; @@ -389,6 +419,11 @@ namespace Audio if (AudioStreamInfo.StreamState != EAudioOutputStreamState::Stopped) { + if (AudioStreamInfo.StreamState == EAudioOutputStreamState::Running) + { + StopGeneratingAudio(); + } + // Signal that the thread that is running the update that we're stopping if (OutputAudioStreamSourceVoice) { @@ -396,11 +431,6 @@ namespace Audio OutputAudioStreamSourceVoice = nullptr; } - if (AudioStreamInfo.StreamState == EAudioOutputStreamState::Running) - { - StopGeneratingAudio(); - } - check(AudioStreamInfo.StreamState == EAudioOutputStreamState::Stopped); } @@ -485,16 +515,13 @@ namespace Audio // Get the output device info at this new index GetOutputDeviceInfo(AudioStreamInfo.OutputDeviceIndex, AudioStreamInfo.DeviceInfo); - // Update the num samples param based on results - AudioStreamInfo.DeviceInfo.NumSamples = AudioStreamInfo.DeviceInfo.NumFrames * AudioStreamInfo.DeviceInfo.NumChannels; - // Create a new master voice XAUDIO2_RETURN_ON_FAIL(XAudio2System->CreateMasteringVoice(&OutputAudioStreamMasteringVoice, AudioStreamInfo.DeviceInfo.NumChannels, AudioStreamInfo.DeviceInfo.SampleRate, 0, AudioStreamInfo.OutputDeviceIndex, nullptr)); // Setup the format of the output source voice WAVEFORMATEX Format = { 0 }; Format.nChannels = AudioStreamInfo.DeviceInfo.NumChannels; - Format.nSamplesPerSec = AUDIO_SAMPLE_RATE; + Format.nSamplesPerSec = OpenStreamParams.SampleRate; Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; Format.nAvgBytesPerSec = Format.nSamplesPerSec * sizeof(float) * Format.nChannels; Format.nBlockAlign = sizeof(float) * Format.nChannels; @@ -506,30 +533,41 @@ namespace Audio // Start the xaudio2 system back up XAudio2System->StartEngine(); - // Clear the output buffers with zero's and submit one - for (int32 Index = 0; Index < NumMixerBuffers; ++Index) - { - OutputBuffers[Index].Reset(); - OutputBuffers[Index].AddZeroed(AudioStreamInfo.DeviceInfo.NumSamples); - } + const int32 NewNumSamples = OpenStreamParams.NumFrames * AudioStreamInfo.DeviceInfo.NumChannels; - CurrentBufferIndex = 0; - SubmitBuffer(OutputBuffers[CurrentBufferIndex]); - - // Start the voice streaming - OutputAudioStreamSourceVoice->Start(); + // Clear the output buffers with zero's and submit one + for (int32 Index = 0; Index < OutputBuffers.Num(); ++Index) + { + OutputBuffers[Index].Reset(NewNumSamples); + } bAudioDeviceChanging = false; return true; } - void FMixerPlatformXAudio2::SubmitBuffer(const TArray& Buffer) + void FMixerPlatformXAudio2::ResumePlaybackOnNewDevice() + { + if (OutputAudioStreamSourceVoice) + { + CurrentBufferReadIndex = 0; + CurrentBufferWriteIndex = 1; + + SubmitBuffer(OutputBuffers[CurrentBufferReadIndex].GetBufferData()); + + AudioRenderEvent->Trigger(); + + // Start the voice streaming + OutputAudioStreamSourceVoice->Start(); + } + } + + void FMixerPlatformXAudio2::SubmitBuffer(const uint8* Buffer) { // Create a new xaudio2 buffer submission XAUDIO2_BUFFER XAudio2Buffer = { 0 }; - XAudio2Buffer.AudioBytes = AudioStreamInfo.DeviceInfo.NumSamples * sizeof(float); - XAudio2Buffer.pAudioData = (const BYTE*)Buffer.GetData(); + XAudio2Buffer.AudioBytes = OpenStreamParams.NumFrames * AudioStreamInfo.DeviceInfo.NumChannels * sizeof(float); + XAudio2Buffer.pAudioData = (const BYTE*)Buffer; XAudio2Buffer.pContext = this; // Submit buffer to the output streaming voice @@ -580,4 +618,9 @@ namespace Audio return FString(); } + FAudioPlatformSettings FMixerPlatformXAudio2::GetPlatformSettings() const + { + return FAudioPlatformSettings::GetPlatformSettings(TEXT("/Script/WindowsTargetPlatform.WindowsTargetSettings")); + } + } \ No newline at end of file diff --git a/Engine/Source/Runtime/Windows/AudioMixerXAudio2/Private/AudioMixerPlatformXAudio2.h b/Engine/Source/Runtime/Windows/AudioMixerXAudio2/Private/AudioMixerPlatformXAudio2.h index fd0102194fe8..37ca87b8a966 100644 --- a/Engine/Source/Runtime/Windows/AudioMixerXAudio2/Private/AudioMixerPlatformXAudio2.h +++ b/Engine/Source/Runtime/Windows/AudioMixerXAudio2/Private/AudioMixerPlatformXAudio2.h @@ -19,11 +19,11 @@ namespace Audio * This callback class is used to get event notifications on buffer end (when a buffer has finished processing). * This is used to signal the I/O thread that it can request another buffer from the user callback. */ - class FXAudio2VoiceCallback : public IXAudio2VoiceCallback + class FXAudio2VoiceCallback final : public IXAudio2VoiceCallback { public: FXAudio2VoiceCallback() {} - ~FXAudio2VoiceCallback() {} + virtual ~FXAudio2VoiceCallback() {} private: void STDCALL OnVoiceProcessingPassStart(UINT32 BytesRequired) {} @@ -59,12 +59,14 @@ namespace Audio virtual bool StartAudioStream() override; virtual bool StopAudioStream() override; virtual bool MoveAudioStreamToNewAudioDevice(const FString& InNewDeviceId) override; + virtual void ResumePlaybackOnNewDevice() override; virtual FAudioPlatformDeviceInfo GetPlatformDeviceInfo() const override; - virtual void SubmitBuffer(const TArray& Buffer) override; + virtual void SubmitBuffer(const uint8* Buffer) override; virtual FName GetRuntimeFormat(USoundWave* InSoundWave) override; virtual bool HasCompressedAudioInfoClass(USoundWave* InSoundWave) override; virtual ICompressedAudioInfo* CreateCompressedAudioInfo(USoundWave* InSoundWave) override; virtual FString GetDefaultDeviceName() override; + virtual FAudioPlatformSettings GetPlatformSettings() const override; //~ End IAudioMixerPlatformInterface //~ Begin IAudioMixerDeviceChangedLister diff --git a/Engine/Source/Runtime/Windows/AudioMixerXAudio2/Private/AudioMixerXAudio2.cpp b/Engine/Source/Runtime/Windows/AudioMixerXAudio2/Private/AudioMixerXAudio2.cpp index 2ab340f3585b..505cad87e2ba 100644 --- a/Engine/Source/Runtime/Windows/AudioMixerXAudio2/Private/AudioMixerXAudio2.cpp +++ b/Engine/Source/Runtime/Windows/AudioMixerXAudio2/Private/AudioMixerXAudio2.cpp @@ -14,6 +14,8 @@ class FAudioMixerModuleXAudio2 : public IAudioDeviceModule { public: + virtual bool IsAudioMixerModule() const override { return true; } + virtual FAudioDevice* CreateAudioDevice() override { return new Audio::FMixerDevice(new Audio::FMixerPlatformXAudio2()); diff --git a/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11RHI.cpp b/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11RHI.cpp index da60a3f5cb70..c27e120e351b 100644 --- a/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11RHI.cpp +++ b/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11RHI.cpp @@ -132,7 +132,7 @@ void GetMipAndSliceInfoFromSRV(ID3D11ShaderResourceView* SRV, int32& MipLevel, i void FD3D11DynamicRHI::CheckIfSRVIsResolved(ID3D11ShaderResourceView* SRV) { #if CHECK_SRV_TRANSITIONS - if (GRHIThread || !SRV) + if (IsRunningRHIInSeparateThread() || !SRV) { return; } diff --git a/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11RenderTarget.cpp b/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11RenderTarget.cpp index a52c578de15d..3e32e2068378 100644 --- a/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11RenderTarget.cpp +++ b/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11RenderTarget.cpp @@ -480,6 +480,7 @@ static uint32 ComputeBytesPerPixel(DXGI_FORMAT Format) case DXGI_FORMAT_R10G10B10A2_UNORM: case DXGI_FORMAT_R11G11B10_FLOAT: case DXGI_FORMAT_R16G16_UNORM: + case DXGI_FORMAT_R32_UINT: BytesPerPixel = 4; break; case DXGI_FORMAT_R16G16B16A16_FLOAT: @@ -1272,44 +1273,62 @@ static void ConvertRAWSurfaceDataToFLinearColor(EPixelFormat Format, uint32 Widt } else if (Format == PF_FloatRGBA) { - FPlane MinValue(0.0f, 0.0f, 0.0f, 0.0f), - MaxValue(1.0f, 1.0f, 1.0f, 1.0f); - - check(sizeof(FD3DFloat16) == sizeof(uint16)); - - for (uint32 Y = 0; Y < Height; Y++) + if (InFlags.GetCompressionMode() == RCM_MinMax) { - FD3DFloat16* SrcPtr = (FD3DFloat16*)(In + Y * SrcPitch); - - for (uint32 X = 0; X < Width; X++) + for (uint32 Y = 0; Y < Height; Y++) { - MinValue.X = FMath::Min(SrcPtr[0], MinValue.X); - MinValue.Y = FMath::Min(SrcPtr[1], MinValue.Y); - MinValue.Z = FMath::Min(SrcPtr[2], MinValue.Z); - MinValue.W = FMath::Min(SrcPtr[3], MinValue.W); - MaxValue.X = FMath::Max(SrcPtr[0], MaxValue.X); - MaxValue.Y = FMath::Max(SrcPtr[1], MaxValue.Y); - MaxValue.Z = FMath::Max(SrcPtr[2], MaxValue.Z); - MaxValue.W = FMath::Max(SrcPtr[3], MaxValue.W); - SrcPtr += 4; + FD3DFloat16* SrcPtr = (FD3DFloat16*)(In + Y * SrcPitch); + FLinearColor* DestPtr = Out + Y * Width; + + for (uint32 X = 0; X < Width; X++) + { + *DestPtr = FLinearColor((float)SrcPtr[0], (float)SrcPtr[1], (float)SrcPtr[2], (float)SrcPtr[3]); + ++DestPtr; + SrcPtr += 4; + } } } - - for (uint32 Y = 0; Y < Height; Y++) + else { - FD3DFloat16* SrcPtr = (FD3DFloat16*)(In + Y * SrcPitch); - FLinearColor* DestPtr = Out + Y * Width; + FPlane MinValue(0.0f, 0.0f, 0.0f, 0.0f); + FPlane MaxValue(1.0f, 1.0f, 1.0f, 1.0f); - for (uint32 X = 0; X < Width; X++) + check(sizeof(FD3DFloat16) == sizeof(uint16)); + + for (uint32 Y = 0; Y < Height; Y++) { - *DestPtr = FLinearColor( - (SrcPtr[0] - MinValue.X) / (MaxValue.X - MinValue.X), - (SrcPtr[1] - MinValue.Y) / (MaxValue.Y - MinValue.Y), - (SrcPtr[2] - MinValue.Z) / (MaxValue.Z - MinValue.Z), - (SrcPtr[3] - MinValue.W) / (MaxValue.W - MinValue.W) - ); - ++DestPtr; - SrcPtr += 4; + FD3DFloat16* SrcPtr = (FD3DFloat16*)(In + Y * SrcPitch); + + for (uint32 X = 0; X < Width; X++) + { + MinValue.X = FMath::Min(SrcPtr[0], MinValue.X); + MinValue.Y = FMath::Min(SrcPtr[1], MinValue.Y); + MinValue.Z = FMath::Min(SrcPtr[2], MinValue.Z); + MinValue.W = FMath::Min(SrcPtr[3], MinValue.W); + MaxValue.X = FMath::Max(SrcPtr[0], MaxValue.X); + MaxValue.Y = FMath::Max(SrcPtr[1], MaxValue.Y); + MaxValue.Z = FMath::Max(SrcPtr[2], MaxValue.Z); + MaxValue.W = FMath::Max(SrcPtr[3], MaxValue.W); + SrcPtr += 4; + } + } + + for (uint32 Y = 0; Y < Height; Y++) + { + FD3DFloat16* SrcPtr = (FD3DFloat16*)(In + Y * SrcPitch); + FLinearColor* DestPtr = Out + Y * Width; + + for (uint32 X = 0; X < Width; X++) + { + *DestPtr = FLinearColor( + (SrcPtr[0] - MinValue.X) / (MaxValue.X - MinValue.X), + (SrcPtr[1] - MinValue.Y) / (MaxValue.Y - MinValue.Y), + (SrcPtr[2] - MinValue.Z) / (MaxValue.Z - MinValue.Z), + (SrcPtr[3] - MinValue.W) / (MaxValue.W - MinValue.W) + ); + ++DestPtr; + SrcPtr += 4; + } } } } diff --git a/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11StateCachePrivate.h b/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11StateCachePrivate.h index 897d755c44fe..da1d79a8adc0 100644 --- a/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11StateCachePrivate.h +++ b/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11StateCachePrivate.h @@ -904,7 +904,7 @@ public: #endif } - ~FD3D11StateCacheBase() + virtual ~FD3D11StateCacheBase() { } diff --git a/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11StructuredBuffer.cpp b/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11StructuredBuffer.cpp index ea904a7e71b8..986583ca233e 100644 --- a/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11StructuredBuffer.cpp +++ b/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11StructuredBuffer.cpp @@ -53,7 +53,7 @@ FStructuredBufferRHIRef FD3D11DynamicRHI::RHICreateStructuredBuffer(uint32 Strid Desc.StructureByteStride = Stride; - if (FPlatformProperties::SupportsFastVRAMMemory()) + if (FPlatformMemory::SupportsFastVRAMMemory()) { if (InUsage & BUF_FastVRAM) { diff --git a/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11Texture.cpp b/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11Texture.cpp index 635a0791d5bb..9a87351fed4e 100644 --- a/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11Texture.cpp +++ b/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11Texture.cpp @@ -201,7 +201,7 @@ TD3D11Texture2D::~TD3D11Texture2D() D3D11TextureDeleted(*this); if (bPooled) { - ReturnPooledTexture2D(GetNumMips(), GetFormat(), GetResource()); + ReturnPooledTexture2D(this->GetNumMips(), this->GetFormat(), this->GetResource()); } #if PLATFORM_SUPPORTS_VIRTUAL_TEXTURES @@ -622,7 +622,7 @@ TD3D11Texture2D* FD3D11DynamicRHI::CreateD3D11Texture2D(uint32 FVRamAllocation VRamAllocation; - if (FPlatformProperties::SupportsFastVRAMMemory()) + if (FPlatformMemory::SupportsFastVRAMMemory()) { if (Flags & TexCreate_FastVRAM) { @@ -939,7 +939,7 @@ FD3D11Texture3D* FD3D11DynamicRHI::CreateD3D11Texture3D(uint32 SizeX,uint32 Size FVRamAllocation VRamAllocation; - if (FPlatformProperties::SupportsFastVRAMMemory()) + if (FPlatformMemory::SupportsFastVRAMMemory()) { if (Flags & TexCreate_FastVRAM) { @@ -1423,14 +1423,14 @@ void* TD3D11Texture2D::Lock(uint32 MipIndex,uint32 ArrayIndex,E SCOPE_CYCLE_COUNTER(STAT_D3D11LockTextureTime); // Calculate the subresource index corresponding to the specified mip-map. - const uint32 Subresource = D3D11CalcSubresource(MipIndex,ArrayIndex,GetNumMips()); + const uint32 Subresource = D3D11CalcSubresource(MipIndex,ArrayIndex,this->GetNumMips()); // Calculate the dimensions of the mip-map. - const uint32 BlockSizeX = GPixelFormats[GetFormat()].BlockSizeX; - const uint32 BlockSizeY = GPixelFormats[GetFormat()].BlockSizeY; - const uint32 BlockBytes = GPixelFormats[GetFormat()].BlockBytes; - const uint32 MipSizeX = FMath::Max(GetSizeX() >> MipIndex,BlockSizeX); - const uint32 MipSizeY = FMath::Max(GetSizeY() >> MipIndex,BlockSizeY); + const uint32 BlockSizeX = GPixelFormats[this->GetFormat()].BlockSizeX; + const uint32 BlockSizeY = GPixelFormats[this->GetFormat()].BlockSizeY; + const uint32 BlockBytes = GPixelFormats[this->GetFormat()].BlockBytes; + const uint32 MipSizeX = FMath::Max(this->GetSizeX() >> MipIndex,BlockSizeX); + const uint32 MipSizeY = FMath::Max(this->GetSizeY() >> MipIndex,BlockSizeY); const uint32 NumBlocksX = (MipSizeX + BlockSizeX - 1) / BlockSizeX; const uint32 NumBlocksY = (MipSizeY + BlockSizeY - 1) / BlockSizeY; const uint32 MipBytes = NumBlocksX * NumBlocksY * BlockBytes; @@ -1467,9 +1467,9 @@ void* TD3D11Texture2D::Lock(uint32 MipIndex,uint32 ArrayIndex,E TRefCountPtr StagingTexture; VERIFYD3D11CREATETEXTURERESULT( D3DRHI->GetDevice()->CreateTexture2D(&StagingTextureDesc,NULL,StagingTexture.GetInitReference()), - GetSizeX(), - GetSizeY(), - GetSizeZ(), + this->GetSizeX(), + this->GetSizeY(), + this->GetSizeZ(), StagingTextureDesc.Format, 1, 0, @@ -1499,7 +1499,7 @@ void TD3D11Texture2D::Unlock(uint32 MipIndex,uint32 ArrayIndex) SCOPE_CYCLE_COUNTER(STAT_D3D11UnlockTextureTime); // Calculate the subresource index corresponding to the specified mip-map. - const uint32 Subresource = D3D11CalcSubresource(MipIndex,ArrayIndex,GetNumMips()); + const uint32 Subresource = D3D11CalcSubresource(MipIndex,ArrayIndex,this->GetNumMips()); // Find the object that is tracking this lock const FD3D11LockedKey LockedKey(GetResource(),Subresource); diff --git a/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11UniformBuffer.cpp b/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11UniformBuffer.cpp index 9d9d280b96dc..970f47a4de92 100644 --- a/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11UniformBuffer.cpp +++ b/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11UniformBuffer.cpp @@ -95,7 +95,7 @@ void UniformBufferBeginFrame() static bool IsPoolingEnabled() { - if (GRHIThread && IsInRenderingThread() && GRHICommandList.IsRHIThreadActive()) + if (IsRunningRHIInSeparateThread() && IsInRenderingThread() && GRHICommandList.IsRHIThreadActive()) { return false; // we can't currently use pooling if the RHI thread is active. } diff --git a/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11Util.cpp b/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11Util.cpp index 21d911a48c24..fc5542486883 100644 --- a/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11Util.cpp +++ b/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11Util.cpp @@ -293,6 +293,39 @@ void VerifyD3D11CreateTextureResult(HRESULT D3DResult,const ANSICHAR* Code,const *GetD3D11TextureFlagString(Flags)); } +void VerifyD3D11ResizeViewportResult(HRESULT D3DResult, const ANSICHAR* Code, const ANSICHAR* Filename, uint32 Line, uint32 SizeX, uint32 SizeY, uint8 Format, ID3D11Device* Device) +{ + check(FAILED(D3DResult)); + + const FString ErrorString = GetD3D11ErrorString(D3DResult, 0); + const TCHAR* D3DFormatString = GetD3D11TextureFormatString((DXGI_FORMAT)Format); + + UE_LOG(LogD3D11RHI, Error, + TEXT("%s failed \n at %s:%u \n with error %s, \n Size=%ix%i Format=%s(0x%08X)"), + ANSI_TO_TCHAR(Code), + ANSI_TO_TCHAR(Filename), + Line, + *ErrorString, + SizeX, + SizeY, + D3DFormatString, + Format); + + TerminateOnDeviceRemoved(D3DResult, Device); + TerminateOnOutOfMemory(D3DResult, true); + + UE_LOG(LogD3D11RHI, Fatal, + TEXT("%s failed \n at %s:%u \n with error %s, \n Size=%ix%i Format=%s(0x%08X)"), + ANSI_TO_TCHAR(Code), + ANSI_TO_TCHAR(Filename), + Line, + *ErrorString, + SizeX, + SizeY, + D3DFormatString, + Format); +} + void VerifyComRefCount(IUnknown* Object,int32 ExpectedRefs,const TCHAR* Code,const TCHAR* Filename,int32 Line) { int32 NumRefs; diff --git a/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11VertexBuffer.cpp b/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11VertexBuffer.cpp index 861c511821bb..83f4c579f9a4 100644 --- a/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11VertexBuffer.cpp +++ b/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11VertexBuffer.cpp @@ -51,7 +51,7 @@ FVertexBufferRHIRef FD3D11DynamicRHI::RHICreateVertexBuffer(uint32 Size,uint32 I Desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE; } - if (FPlatformProperties::SupportsFastVRAMMemory()) + if (FPlatformMemory::SupportsFastVRAMMemory()) { if (InUsage & BUF_FastVRAM) { diff --git a/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11Viewport.cpp b/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11Viewport.cpp index f4a56d271745..9028ffdb66e6 100644 --- a/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11Viewport.cpp +++ b/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11Viewport.cpp @@ -216,7 +216,8 @@ void FD3D11Viewport::Resize(uint32 InSizeX, uint32 InSizeY, bool bInIsFullscreen check(SizeY > 0); // Resize the swap chain. - VERIFYD3D11RESULT_EX(SwapChain->ResizeBuffers(1,SizeX,SizeY,GetRenderTargetFormat(PixelFormat),DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH), D3DRHI->GetDevice()); + DXGI_FORMAT RenderTargetFormat = GetRenderTargetFormat(PixelFormat); + VERIFYD3D11RESIZEVIEWPORTRESULT(SwapChain->ResizeBuffers(1,SizeX,SizeY,RenderTargetFormat,DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH),SizeX,SizeY,RenderTargetFormat, D3DRHI->GetDevice()); if(bInIsFullscreen) { diff --git a/Engine/Source/Runtime/Windows/D3D11RHI/Private/Windows/WindowsD3D11Device.cpp b/Engine/Source/Runtime/Windows/D3D11RHI/Private/Windows/WindowsD3D11Device.cpp index 2949e1cd8299..1f89322c5ef9 100644 --- a/Engine/Source/Runtime/Windows/D3D11RHI/Private/Windows/WindowsD3D11Device.cpp +++ b/Engine/Source/Runtime/Windows/D3D11RHI/Private/Windows/WindowsD3D11Device.cpp @@ -18,18 +18,32 @@ #include "GenericPlatformDriver.h" // FGPUDriverInfo #if NV_AFTERMATH -int32 GDX11NVAfterMathEnabled = 1; -static FAutoConsoleVariableRef CVarDX11NVAfterMathBufferSize( - TEXT("r.DX11NVAfterMathEnabled"), - GDX11NVAfterMathEnabled, - TEXT("Use NV Aftermath for GPU crash analysis"), - ECVF_ReadOnly -); +int32 GDX11NVAfterMathEnabled = 0; #endif extern bool D3D11RHI_ShouldCreateWithD3DDebug(); extern bool D3D11RHI_ShouldAllowAsyncResourceCreation(); +int D3D11RHI_PreferAdaperVendor() +{ + if (FParse::Param(FCommandLine::Get(), TEXT("preferAMD"))) + { + return 0x1002; + } + + if (FParse::Param(FCommandLine::Get(), TEXT("preferIntel"))) + { + return 0x8086; + } + + if (FParse::Param(FCommandLine::Get(), TEXT("preferNvidia"))) + { + return 0x10DE; + } + + return -1; +} + // Filled in during InitD3DDevice if IsRHIDeviceAMD struct AmdAgsInfo { @@ -547,13 +561,21 @@ static bool SupportsHDROutput(FD3D11DynamicRHI* D3DRHI) void FD3D11DynamicRHIModule::StartupModule() { #if NV_AFTERMATH - FString AftermathBinariesRoot = FPaths::EngineDir() / TEXT("Binaries/ThirdParty/NVIDIA/NVaftermath/Win64/"); - if (LoadLibraryW(*(AftermathBinariesRoot + "GFSDK_Aftermath_Lib.dll")) == nullptr) - { - UE_LOG(LogD3D11RHI, Log, TEXT("Failed to load GFSDK_Aftermath_Lib.dll")); - GDX11NVAfterMathEnabled = 0; - return; - } + // Note - can't check device type here, we'll check for that before actually initializing Aftermath + + FString AftermathBinariesRoot = FPaths::EngineDir() / TEXT("Binaries/ThirdParty/NVIDIA/NVaftermath/Win64/"); + if (LoadLibraryW(*(AftermathBinariesRoot + "GFSDK_Aftermath_Lib.dll")) == nullptr) + { + UE_LOG(LogD3D11RHI, Warning, TEXT("Failed to load GFSDK_Aftermath_Lib.dll")); + GDX11NVAfterMathEnabled = 0; + return; + } + else + { + UE_LOG(LogD3D11RHI, Log, TEXT("Aftermath initialized")); + GDX11NVAfterMathEnabled = 1; + } + #endif } @@ -644,6 +666,7 @@ void FD3D11DynamicRHIModule::FindAdapter() UE_LOG(LogD3D11RHI, Log, TEXT("D3D11 adapters:")); + int PreferredVendor = D3D11RHI_PreferAdaperVendor(); // Enumerate the DXGIFactory's adapters. for(uint32 AdapterIndex = 0; DXGIFactory1->EnumAdapters(AdapterIndex,TempAdapter.GetInitReference()) != DXGI_ERROR_NOT_FOUND; ++AdapterIndex) { @@ -711,11 +734,19 @@ void FD3D11DynamicRHIModule::FindAdapter() { FirstWithoutIntegratedAdapter = CurrentAdapter; } + else if (PreferredVendor == AdapterDesc.VendorId && FirstWithoutIntegratedAdapter.IsValid()) + { + FirstWithoutIntegratedAdapter = CurrentAdapter; + } if (!FirstAdapter.IsValid()) { FirstAdapter = CurrentAdapter; } + else if (PreferredVendor == AdapterDesc.VendorId && FirstAdapter.IsValid()) + { + FirstAdapter = CurrentAdapter; + } } } } @@ -1057,16 +1088,9 @@ void FD3D11DynamicRHI::InitD3DDevice() GSupportsTimestampRenderQueries = false; } } - -#if NV_AFTERMATH - if (!IsRHIDeviceNVIDIA()) - { - GDX11NVAfterMathEnabled = 0; - } -#endif #if PLATFORM_DESKTOP - if( IsRHIDeviceNVIDIA() ) + if (IsRHIDeviceNVIDIA()) { GSupportsDepthBoundsTest = true; NV_GET_CURRENT_SLI_STATE SLICaps; @@ -1085,23 +1109,6 @@ void FD3D11DynamicRHI::InitD3DDevice() { UE_LOG(LogD3D11RHI, Log, TEXT("NvAPI_D3D_GetCurrentSLIState failed: 0x%x"), (int32)SLIStatus); } - -#if NV_AFTERMATH - if (GDX11NVAfterMathEnabled) - { - auto Result = GFSDK_Aftermath_DX11_Initialize(GFSDK_Aftermath_Version_API, Direct3DDevice); - if (Result == GFSDK_Aftermath_Result_Success) - { - UE_LOG(LogD3D11RHI, Log, TEXT("[Aftermath] Aftermath enabled and primed")); - GEmitDrawEvents = true; - } - else - { - UE_LOG(LogD3D11RHI, Log, TEXT("[Aftermath] Aftermath enabled but failed to initialize")); - GDX11NVAfterMathEnabled = 0; - } - } -#endif } else if( IsRHIDeviceAMD() ) { @@ -1118,12 +1125,56 @@ void FD3D11DynamicRHI::InitD3DDevice() } } +#if NV_AFTERMATH + // Two ways to enable aftermath, command line or the r.GPUCrashDebugging variable + // Note: If intending to change this please alert game teams who use this for user support. + if (FParse::Param(FCommandLine::Get(), TEXT("gpucrashdebugging"))) + { + GDX11NVAfterMathEnabled = true; + } + else + { + static IConsoleVariable* GPUCrashDebugging = IConsoleManager::Get().FindConsoleVariable(TEXT("r.GPUCrashDebugging")); + if (GPUCrashDebugging) + { + GDX11NVAfterMathEnabled = GPUCrashDebugging->GetInt(); + } + } + + if (GDX11NVAfterMathEnabled) + { + if (IsRHIDeviceNVIDIA()) + { + auto Result = GFSDK_Aftermath_DX11_Initialize(GFSDK_Aftermath_Version_API, Direct3DDevice); + if (Result == GFSDK_Aftermath_Result_Success) + { + UE_LOG(LogD3D11RHI, Log, TEXT("[Aftermath] Aftermath enabled and primed")); + GEmitDrawEvents = true; + } + else + { + unsigned Index = (unsigned)Result & (~((unsigned)GFSDK_Aftermath_Result_Fail)); + const TCHAR* Reason[13] = { TEXT("Fail"), TEXT("VersionMismatch"), TEXT("NotInitialized"), TEXT("InvalidAdapter"), TEXT("InvalidParameter"), TEXT("Unknown"), TEXT("ApiError"), TEXT("NvApiIncompatible"), TEXT("GettingContextDataWithNewCommandList"), TEXT("AlreadyInitialized"), TEXT("D3DDebugLayerNotCompatible"),TEXT("NotEnabledInDriver"), TEXT("DriverVersionNotSupported") }; + Index = Index > 12 ? 0 : Index; + + UE_LOG(LogD3D11RHI, Log, TEXT("[Aftermath] Aftermath enabled but failed to initialize due to reason: %s"), Reason[Index]); + GDX11NVAfterMathEnabled = 0; + } + } + else + { + GDX11NVAfterMathEnabled = 0; + UE_LOG(LogD3D11RHI, Warning, TEXT("[Aftermath] Skipping aftermath initialization on non-Nvidia device")); + } + } +#endif // NV_AFTERMATH + if (GDX11ForcedGPUs > 0) { GNumActiveGPUsForRendering = GDX11ForcedGPUs; UE_LOG(LogD3D11RHI, Log, TEXT("r.DX11NumForcedGPUs forcing GNumActiveGPUsForRendering to: %i "), GDX11ForcedGPUs); } -#endif +#endif // PLATFORM_DESKTOP SetupAfterDeviceCreation(); diff --git a/Engine/Source/Runtime/Windows/D3D11RHI/Public/D3D11Util.h b/Engine/Source/Runtime/Windows/D3D11RHI/Public/D3D11Util.h index 10d36745d450..1503314a2b43 100644 --- a/Engine/Source/Runtime/Windows/D3D11RHI/Public/D3D11Util.h +++ b/Engine/Source/Runtime/Windows/D3D11RHI/Public/D3D11Util.h @@ -57,6 +57,10 @@ extern D3D11RHI_API void VerifyD3D11ShaderResult(class FRHIShader* Shader, HRESU extern D3D11RHI_API void VerifyD3D11CreateTextureResult(HRESULT D3DResult,const ANSICHAR* Code,const ANSICHAR* Filename,uint32 Line, uint32 SizeX,uint32 SizeY,uint32 SizeZ,uint8 D3DFormat,uint32 NumMips,uint32 Flags, ID3D11Device* Device); + +extern D3D11RHI_API void VerifyD3D11ResizeViewportResult(HRESULT D3DResult, const ANSICHAR* Code, const ANSICHAR* Filename, uint32 Line, + uint32 SizeX, uint32 SizeY, uint8 D3DFormat, ID3D11Device* Device); + /** * A macro for using VERIFYD3D11RESULT that automatically passes in the code and filename/line. */ @@ -64,7 +68,7 @@ extern D3D11RHI_API void VerifyD3D11CreateTextureResult(HRESULT D3DResult,const #define VERIFYD3D11RESULT(x) {HRESULT hr = x; if (FAILED(hr)) { VerifyD3D11Result(hr,#x,__FILE__,__LINE__, 0); }} #define VERIFYD3D11SHADERRESULT(Result, Shader, Device) {HRESULT hr = (Result); if (FAILED(hr)) { VerifyD3D11ShaderResult(Shader, hr, #Result,__FILE__,__LINE__, Device); }} #define VERIFYD3D11CREATETEXTURERESULT(x,SizeX,SizeY,SizeZ,Format,NumMips,Flags, Device) {HRESULT hr = x; if (FAILED(hr)) { VerifyD3D11CreateTextureResult(hr,#x,__FILE__,__LINE__,SizeX,SizeY,SizeZ,Format,NumMips,Flags, Device); }} - +#define VERIFYD3D11RESIZEVIEWPORTRESULT(x,SizeX,SizeY,Format, Device) {HRESULT hr = x; if (FAILED(hr)) { VerifyD3D11ResizeViewportResult(hr,#x,__FILE__,__LINE__,SizeX,SizeY,Format, Device); }} /** * Checks that a COM object has the expected number of references. */ diff --git a/Engine/Source/Runtime/Windows/UnrealAudioXAudio2/Private/UnrealAudioDeviceXAudio2.cpp b/Engine/Source/Runtime/Windows/UnrealAudioXAudio2/Private/UnrealAudioDeviceXAudio2.cpp index 41e152060cb5..68a58304ba78 100644 --- a/Engine/Source/Runtime/Windows/UnrealAudioXAudio2/Private/UnrealAudioDeviceXAudio2.cpp +++ b/Engine/Source/Runtime/Windows/UnrealAudioXAudio2/Private/UnrealAudioDeviceXAudio2.cpp @@ -99,7 +99,7 @@ namespace UAudio * This callback class is used to get event notifications on buffer end (when a buffer has finished processing). * This is used to signal the I/O thread that it can request another buffer from the user callback. */ - class FXAudio2VoiceCallback : public IXAudio2VoiceCallback + class FXAudio2VoiceCallback final : public IXAudio2VoiceCallback { public: FXAudio2VoiceCallback() @@ -107,7 +107,7 @@ namespace UAudio { } - ~FXAudio2VoiceCallback() + virtual ~FXAudio2VoiceCallback() { } @@ -386,18 +386,20 @@ namespace UAudio Result = XAudio2Info.XAudio2System->CreateMasteringVoice(&XAudio2Info.MasteringVoice, DeviceInfo.NumChannels, StreamInfo.FrameRate, 0, CreateStreamParams.OutputDeviceIndex, nullptr); CLEANUP_ON_FAIL(Result); - FStreamDeviceInfo& StreamDeviceInfo = StreamInfo.DeviceInfo; - StreamDeviceInfo.DeviceIndex = CreateStreamParams.OutputDeviceIndex; - StreamDeviceInfo.bPerformByteSwap = false; - StreamDeviceInfo.NumChannels = DeviceInfo.NumChannels; - StreamDeviceInfo.DeviceDataFormat = DeviceInfo.StreamFormat; - StreamDeviceInfo.FrameRate = DeviceInfo.FrameRate; - StreamDeviceInfo.Speakers = DeviceInfo.Speakers; + { + FStreamDeviceInfo& StreamDeviceInfo = StreamInfo.DeviceInfo; + StreamDeviceInfo.DeviceIndex = CreateStreamParams.OutputDeviceIndex; + StreamDeviceInfo.bPerformByteSwap = false; + StreamDeviceInfo.NumChannels = DeviceInfo.NumChannels; + StreamDeviceInfo.DeviceDataFormat = DeviceInfo.StreamFormat; + StreamDeviceInfo.FrameRate = DeviceInfo.FrameRate; + StreamDeviceInfo.Speakers = DeviceInfo.Speakers; - uint32 BufferSize = StreamDeviceInfo.NumChannels * StreamInfo.BlockSize * GetNumBytesForFormat(EStreamFormat::FLT); - StreamDeviceInfo.UserBuffer.Init(0, BufferSize); - XAudio2Info.bDeviceOpen = true; - XAudio2Info.XAudio2System->StartEngine(); + uint32 BufferSize = StreamDeviceInfo.NumChannels * StreamInfo.BlockSize * GetNumBytesForFormat(EStreamFormat::FLT); + StreamDeviceInfo.UserBuffer.Init(0, BufferSize); + XAudio2Info.bDeviceOpen = true; + XAudio2Info.XAudio2System->StartEngine(); + } Cleanup: if (FAILED(Result)) diff --git a/Engine/Source/Runtime/Windows/XAudio2/Private/XAudio2Buffer.cpp b/Engine/Source/Runtime/Windows/XAudio2/Private/XAudio2Buffer.cpp index 3db2bf78f8d3..900d05a0d065 100644 --- a/Engine/Source/Runtime/Windows/XAudio2/Private/XAudio2Buffer.cpp +++ b/Engine/Source/Runtime/Windows/XAudio2/Private/XAudio2Buffer.cpp @@ -194,12 +194,20 @@ int32 FXAudio2SoundBuffer::GetSize( void ) int32 FXAudio2SoundBuffer::GetCurrentChunkIndex() const { - return DecompressionState->GetCurrentChunkIndex(); + if (DecompressionState) + { + return DecompressionState->GetCurrentChunkIndex(); + } + return INDEX_NONE; } int32 FXAudio2SoundBuffer::GetCurrentChunkOffset() const { - return DecompressionState->GetCurrentChunkOffset(); + if (DecompressionState) + { + return DecompressionState->GetCurrentChunkOffset(); + } + return INDEX_NONE; } bool FXAudio2SoundBuffer::IsRealTimeSourceReady() @@ -497,21 +505,21 @@ FXAudio2SoundBuffer* FXAudio2SoundBuffer::CreateStreamingBuffer( FXAudio2Device* Wave->RawPCMDataSize = QualityInfo.SampleDataSize; Wave->Duration = QualityInfo.Duration; + Buffer->InitWaveFormatEx(WAVE_FORMAT_PCM, Wave, false); + // Clear out any dangling pointers Buffer->PCM.PCMData = NULL; Buffer->PCM.PCMDataSize = 0; - Buffer->InitWaveFormatEx(WAVE_FORMAT_PCM, Wave, false); + return Buffer; } else { - Wave->DecompressionType = DTYPE_Invalid; - Wave->NumChannels = 0; + delete Buffer; + Buffer = nullptr; - Wave->RemoveAudioResource(); + return nullptr; } - - return(Buffer); } FXAudio2SoundBuffer* FXAudio2SoundBuffer::Init( FAudioDevice* AudioDevice, USoundWave* Wave, bool bForceRealTime ) diff --git a/Engine/Source/Runtime/Windows/XAudio2/Private/XAudio2Device.cpp b/Engine/Source/Runtime/Windows/XAudio2/Private/XAudio2Device.cpp index 2ccec115bb1c..7f708db05a79 100644 --- a/Engine/Source/Runtime/Windows/XAudio2/Private/XAudio2Device.cpp +++ b/Engine/Source/Runtime/Windows/XAudio2/Private/XAudio2Device.cpp @@ -31,6 +31,10 @@ THIRD_PARTY_INCLUDES_END #include "XAudio2Support.h" #include "Runtime/HeadMountedDisplay/Public/IHeadMountedDisplayModule.h" +#if WITH_XMA2 +#include "XMAAudioInfo.h" +#endif + DEFINE_LOG_CATEGORY(LogXAudio2); class FXAudio2DeviceModule : public IAudioDeviceModule @@ -90,8 +94,10 @@ bool FXAudio2Device::InitializeHardware() DeviceProperties->XAudio2 = nullptr; DeviceProperties->MasteringVoice = nullptr; +#if WITH_OGGVORBIS // Load ogg and vorbis dlls if they haven't been loaded yet LoadVorbisLibraries(); +#endif SampleRate = UE4_XAUDIO2_SAMPLERATE; @@ -121,11 +127,16 @@ bool FXAudio2Device::InitializeHardware() uint32 Flags = 0; #endif +#if WITH_XMA2 + // We don't use all of the SHAPE processor, so this flag prevents wasted resources + Flags |= XAUDIO2_DO_NOT_USE_SHAPE; +#endif + // Create a new XAudio2 device object instance if (XAudio2Create(&DeviceProperties->XAudio2, Flags, (XAUDIO2_PROCESSOR)FPlatformAffinity::GetAudioThreadMask()) != S_OK) { - UE_LOG(LogInit, Log, TEXT( "Failed to create XAudio2 interface" ) ); - return( false ); + UE_LOG(LogInit, Log, TEXT("Failed to create XAudio2 interface")); + return(false); } check(DeviceProperties->XAudio2 != nullptr); @@ -257,6 +268,10 @@ bool FXAudio2Device::InitializeHardware() // Now initialize the audio clock voice after xaudio2 is initialized DeviceProperties->InitAudioClockVoice(); +#if WITH_XMA2 + FXMAAudioInfo::Initialize(); +#endif + return true; } @@ -310,7 +325,7 @@ FSoundSource* FXAudio2Device::CreateSoundSource() bool FXAudio2Device::HasCompressedAudioInfoClass(USoundWave* SoundWave) { -#if WITH_OGGVORBIS +#if WITH_OGGVORBIS || WITH_XMA2 return true; #else return false; @@ -338,14 +353,23 @@ class ICompressedAudioInfo* FXAudio2Device::CreateCompressedAudioInfo(USoundWave } return CompressedInfo; } - else - { - return nullptr; - } -#else - return nullptr; #endif - + +#if WITH_XMA2 + static const FName NAME_XMA(TEXT("XMA")); + if (FPlatformProperties::RequiresCookedData() ? SoundWave->HasCompressedData(NAME_XMA) : (SoundWave->GetCompressedData(NAME_XMA) != nullptr)) + { + ICompressedAudioInfo* CompressedInfo = new FXMAAudioInfo(); + if (!CompressedInfo) + { + UE_LOG(LogAudio, Error, TEXT("Failed to create new FXMAAudioInfo for SoundWave %s: out of memory."), *SoundWave->GetName()); + return nullptr; + } + return CompressedInfo; + } +#endif + + return nullptr; } /** @@ -532,6 +556,7 @@ bool FXAudio2Device::GetOutputMatrix( uint32 ChannelMask, uint32 NumChannels ) /** Test decompress a vorbis file */ void FXAudio2Device::TestDecompressOggVorbis( USoundWave* Wave ) { +#if WITH_OGGVORBIS FVorbisAudioInfo OggInfo; FSoundQualityInfo QualityInfo = { 0 }; @@ -551,6 +576,7 @@ void FXAudio2Device::TestDecompressOggVorbis( USoundWave* Wave ) FMemory::Free( Wave->RawPCMData ); } +#endif } #if !UE_BUILD_SHIPPING diff --git a/Engine/Source/Runtime/Windows/XAudio2/Private/XAudio2Source.cpp b/Engine/Source/Runtime/Windows/XAudio2/Private/XAudio2Source.cpp index 0070d5d6d394..357c3255bf03 100644 --- a/Engine/Source/Runtime/Windows/XAudio2/Private/XAudio2Source.cpp +++ b/Engine/Source/Runtime/Windows/XAudio2/Private/XAudio2Source.cpp @@ -97,7 +97,7 @@ void FXAudio2SoundSource::FreeResources( void ) // Release voice. Note that this will stop calling OnBufferEnd if (Source) { - AudioDevice->DeviceProperties->ReleaseSourceVoice(Source, XAudio2Buffer->PCM, MaxEffectChainChannels); + AudioDevice->DeviceProperties->ReleaseSourceVoice(Source, XAudio2Buffer->PCM, MaxEffectChainChannels); //-V595 Source = nullptr; } @@ -236,13 +236,12 @@ void FXAudio2SoundSource::SubmitPCMRTBuffers( void ) const uint32 BufferSize = MONO_PCM_BUFFER_SIZE * Buffer->NumChannels; // Set up buffer areas to decompress to - XAudio2Buffers[0].pAudioData = GetRealtimeBufferData(0, BufferSize); - XAudio2Buffers[0].AudioBytes = BufferSize; - XAudio2Buffers[0].pContext = this; - - XAudio2Buffers[1].pAudioData = GetRealtimeBufferData(1, BufferSize); - XAudio2Buffers[1].AudioBytes = BufferSize; - XAudio2Buffers[1].pContext = this; + for (int32 i = 0; i < 3; ++i) + { + XAudio2Buffers[i].pAudioData = GetRealtimeBufferData(i, BufferSize); + XAudio2Buffers[i].AudioBytes = BufferSize; + XAudio2Buffers[i].pContext = this; + } // Only use the cached data if we're starting from the beginning, otherwise we'll have to take a synchronous hit bPlayedCachedBuffer = false; @@ -252,29 +251,33 @@ void FXAudio2SoundSource::SubmitPCMRTBuffers( void ) bPlayedCachedBuffer = true; FMemory::Memcpy((uint8*)XAudio2Buffers[0].pAudioData, WaveInstance->WaveData->CachedRealtimeFirstBuffer, BufferSize); FMemory::Memcpy((uint8*)XAudio2Buffers[1].pAudioData, WaveInstance->WaveData->CachedRealtimeFirstBuffer + BufferSize, BufferSize); + + // Immediately submit the first two buffers that were either cached or synchronously read + // The first buffer will start the voice processing buffers and trigger an OnBufferEnd callback, which will then + // trigger async tasks to generate more PCMRT buffers. + AudioDevice->ValidateAPICall(TEXT("SubmitSourceBuffer - PCMRT"), + Source->SubmitSourceBuffer(&XAudio2Buffers[0])); + + AudioDevice->ValidateAPICall(TEXT("SubmitSourceBuffer - PCMRT"), + Source->SubmitSourceBuffer(&XAudio2Buffers[1])); + + // Prepare the third buffer for the OnBufferEnd callback to write to in the OnBufferEnd callback + CurrentBuffer = 2; } else { + // Read the first buffer now ReadMorePCMData(0, EDataReadMode::Synchronous); - ReadMorePCMData(1, EDataReadMode::Synchronous); + + // Submit it + AudioDevice->ValidateAPICall(TEXT("SubmitSourceBuffer - PCMRT"), + Source->SubmitSourceBuffer(&XAudio2Buffers[0])); + + // Kick off an async decode of the next buffer so when first buffer finishes, it'll be ready + CurrentBuffer = 1; + ReadMorePCMData(CurrentBuffer, EDataReadMode::Asynchronous); } - // Immediately submit the first two buffers that were either cached or synchronously read - // The first buffer will start the voice processing buffers and trigger an OnBufferEnd callback, which will then - // trigger async tasks to generate more PCMRT buffers. - AudioDevice->ValidateAPICall(TEXT("SubmitSourceBuffer - PCMRT"), - Source->SubmitSourceBuffer(&XAudio2Buffers[0])); - - AudioDevice->ValidateAPICall(TEXT("SubmitSourceBuffer - PCMRT"), - Source->SubmitSourceBuffer(&XAudio2Buffers[1])); - - // Prepare the third buffer for the OnBufferEnd callback to write to in the OnBufferEnd callback - CurrentBuffer = 2; - - XAudio2Buffers[2].pAudioData = GetRealtimeBufferData(2, BufferSize); - XAudio2Buffers[2].AudioBytes = BufferSize; - XAudio2Buffers[2].pContext = this; - bResourcesNeedFreeing = true; } @@ -466,10 +469,12 @@ bool FXAudio2SoundSource::PrepareForInitialization(FWaveInstance* InWaveInstance bIsVirtual = true; } + // We need to set the wave instance regardless of what happens below so that the wave instance can be stopped if this sound source fails to init + WaveInstance = InWaveInstance; + // If virtual only need wave instance data and no need to load source data if (bIsVirtual) { - WaveInstance = InWaveInstance; bIsFinished = false; return true; } @@ -509,11 +514,6 @@ bool FXAudio2SoundSource::PrepareForInitialization(FWaveInstance* InWaveInstance LPFFrequency = MAX_FILTER_FREQUENCY; LastLPFFrequency = FLT_MAX; - WaveInstance = InWaveInstance; - - // Reset the LPFFrequency values - LPFFrequency = MAX_FILTER_FREQUENCY; - LastLPFFrequency = FLT_MAX; bIsFinished = false; // We succeeded in preparing our xaudio2 buffer for initialization. We are technically not initialized yet. @@ -556,9 +556,16 @@ bool FXAudio2SoundSource::Init(FWaveInstance* InWaveInstance) if (CreateSource()) { check(WaveInstance); - if (WaveInstance->StartTime) + if (WaveInstance->StartTime > 0.0f) { - XAudio2Buffer->Seek(WaveInstance->StartTime); + if (WaveInstance->WaveData->bStreaming) + { + UE_LOG(LogXAudio2, Verbose, TEXT("Seeking (aka start time) is not supported for streaming sound waves ('%s')."), *InWaveInstance->GetName()); + } + else + { + XAudio2Buffer->Seek(WaveInstance->StartTime); + } } // Submit audio buffers @@ -1578,7 +1585,7 @@ void FXAudio2SoundSource::HandleRealTimeSource(bool bBlockForData) } else { - DataReadMode = (XAudio2Buffer->SoundFormat == ESoundFormat::SoundFormat_Streaming ? EDataReadMode::Synchronous : EDataReadMode::Asynchronous); + DataReadMode = EDataReadMode::Asynchronous; } const bool bLooped = ReadMorePCMData(CurrentBuffer, DataReadMode); diff --git a/Engine/Source/Runtime/Windows/XAudio2/Private/XAudio2Support.h b/Engine/Source/Runtime/Windows/XAudio2/Private/XAudio2Support.h index 931cf53607c6..ce4152a40087 100644 --- a/Engine/Source/Runtime/Windows/XAudio2/Private/XAudio2Support.h +++ b/Engine/Source/Runtime/Windows/XAudio2/Private/XAudio2Support.h @@ -39,7 +39,7 @@ #include #include -class FMMNotificationClient : public IMMNotificationClient +class FMMNotificationClient final : public IMMNotificationClient { public: FMMNotificationClient() @@ -54,7 +54,7 @@ public: } } - ~FMMNotificationClient() + virtual ~FMMNotificationClient() { if (DeviceEnumerator) { @@ -733,7 +733,7 @@ FORCEINLINE bool operator==(const WAVEFORMATEX& FormatA, const WAVEFORMATEX& For /** This structure holds any singleton XAudio2 resources which need to be used, not just "properties" of the device. */ -struct FXAudioDeviceProperties : public IDeviceChangedListener +struct FXAudioDeviceProperties final : public IDeviceChangedListener { // These variables are non-static to support multiple audio device instances struct IXAudio2* XAudio2; @@ -794,7 +794,7 @@ struct FXAudioDeviceProperties : public IDeviceChangedListener #endif } - ~FXAudioDeviceProperties() + virtual ~FXAudioDeviceProperties() { #if PLATFORM_WINDOWS NotificationClient->UnRegisterDeviceDeviceChangedListener(this); diff --git a/Engine/Source/Runtime/Windows/XAudio2/Public/XAudio2Device.h b/Engine/Source/Runtime/Windows/XAudio2/Public/XAudio2Device.h index 27453617b539..05f7a1c77410 100644 --- a/Engine/Source/Runtime/Windows/XAudio2/Public/XAudio2Device.h +++ b/Engine/Source/Runtime/Windows/XAudio2/Public/XAudio2Device.h @@ -6,6 +6,10 @@ #pragma once +#ifndef WITH_XMA2 +#define WITH_XMA2 0 +#endif + /*------------------------------------------------------------------------------------ XAudio2 system headers ------------------------------------------------------------------------------------*/ @@ -83,6 +87,15 @@ class FSpatializationHelper; */ class FXAudio2Device : public FAudioDevice { +public: + FXAudio2Device() : FAudioDevice() + { +#if WITH_XMA2 + bDisableAudioCaching = true; // Do not allow DTYPE_Native buffers, only DTYPE_RealTime or DTYPE_Streaming since on the fly decompression is so cheap, it saves memory, and requires fewer code paths +#endif + } + +private: virtual void GetAudioDeviceList(TArray& OutAudioDeviceNames) const override; /** Starts up any platform specific hardware/APIs */ @@ -113,7 +126,22 @@ class FXAudio2Device : public FAudioDevice } #if WITH_OGGVORBIS static FName NAME_OGG(TEXT("OGG")); + static FName NAME_XMA(TEXT("XMA")); + +#if WITH_XMA2 + if (SoundWave->NumChannels > 2) + { + // Use OGG for surround wave sources, until we can sort out the channel assignments properly + return NAME_OGG; + } + else + { + return NAME_XMA; + } +#else return NAME_OGG; +#endif + #else //WITH_OGGVORBIS static FName NAME_XMA(TEXT("XMA")); return NAME_XMA; diff --git a/Engine/Source/Runtime/XmlParser/Private/FastXml.cpp b/Engine/Source/Runtime/XmlParser/Private/FastXml.cpp index e3530cd2af44..d12d7f347531 100644 --- a/Engine/Source/Runtime/XmlParser/Private/FastXml.cpp +++ b/Engine/Source/Runtime/XmlParser/Private/FastXml.cpp @@ -443,17 +443,17 @@ protected: if( *Buffer ) // if not eof... { Buffer = SkipNextData( Buffer ); - if( *Buffer == L'"' ) + if( *Buffer == L'"' || *Buffer == L'\'' ) { Buffer++; AttributeCount++; Attributes[ AttributeCount ] = Buffer; AttributeCount++; - while( *Buffer && *Buffer != 34 ) + while( *Buffer && *Buffer != L'"' && *Buffer != L'\'' ) { Buffer++; } - if( *Buffer == L'"' ) + if( *Buffer == L'"' || *Buffer == L'\'' ) { *Buffer = 0; Buffer++; diff --git a/Engine/Source/ThirdParty/Android/extras/google/m2repository/com/google/android/gms/play-services-places/maven-metadata.xml b/Engine/Source/ThirdParty/Android/extras/google/m2repository/com/google/android/gms/play-services-places/maven-metadata.xml deleted file mode 100644 index ec03ed481337..000000000000 --- a/Engine/Source/ThirdParty/Android/extras/google/m2repository/com/google/android/gms/play-services-places/maven-metadata.xml +++ /dev/null @@ -1,11 +0,0 @@ - - com.google.android.gms - play-services-places - - 9.2.0 - - 9.2.0 - - 20160612215637 - - diff --git a/Engine/Source/ThirdParty/FBX/FBX.Build.cs b/Engine/Source/ThirdParty/FBX/FBX.Build.cs index 0670bdcd75b1..1cf0b706e382 100644 --- a/Engine/Source/ThirdParty/FBX/FBX.Build.cs +++ b/Engine/Source/ThirdParty/FBX/FBX.Build.cs @@ -25,12 +25,26 @@ public class FBX : ModuleRules FBxLibPath += "x64/release/"; PublicLibraryPaths.Add(FBxLibPath); - PublicAdditionalLibraries.Add("libfbxsdk.lib"); + if (Target.LinkType != TargetLinkType.Monolithic) + { + PublicAdditionalLibraries.Add("libfbxsdk.lib"); - // We are using DLL versions of the FBX libraries - Definitions.Add("FBXSDK_SHARED"); + // We are using DLL versions of the FBX libraries + Definitions.Add("FBXSDK_SHARED"); - RuntimeDependencies.Add(new RuntimeDependency("$(EngineDir)/Binaries/Win64/libfbxsdk.dll")); + RuntimeDependencies.Add(new RuntimeDependency("$(EngineDir)/Binaries/Win64/libfbxsdk.dll")); + } + else + { + if (Target.bUseStaticCRT) + { + PublicAdditionalLibraries.Add("libfbxsdk-mt.lib"); + } + else + { + PublicAdditionalLibraries.Add("libfbxsdk-md.lib"); + } + } } else if (Target.Platform == UnrealTargetPlatform.Mac) { diff --git a/Engine/Source/ThirdParty/Facebook/Bolts.tps b/Engine/Source/ThirdParty/Facebook/Bolts.tps new file mode 100644 index 000000000000..cb0eb959858a --- /dev/null +++ b/Engine/Source/ThirdParty/Facebook/Bolts.tps @@ -0,0 +1,9 @@ + + + + /Engine/Source/ThirdParty/Facebook/IOS/FacebookSDK/Bolts.embeddedframework.zip + +Redirect: ../IOS/Bolts/Bolts.tps + + + \ No newline at end of file diff --git a/Engine/Source/ThirdParty/Facebook/FBNotifications.tps b/Engine/Source/ThirdParty/Facebook/FBNotifications.tps new file mode 100644 index 000000000000..b4b39d4ede1a --- /dev/null +++ b/Engine/Source/ThirdParty/Facebook/FBNotifications.tps @@ -0,0 +1,14 @@ + + + Facebook In-App Notifications (FBNotifications) + /Engine/Source/ThirdParty/Facebook/IOS/FacebookSDK/FBNotifications.embeddedframework.zip + 2016-06-10T14:10:42.9950458-04:00 + Included as part of the Facebook SDK for iOS to give developers access to FB social features. + https://github.com/facebook/FBNotifications/blob/0666010b261558495fa0c614f7bffb59b7c3a01f/LICENSE + + Licensees + Git + P4 + + /Engine/Source/ThirdParty/Licenses/FBNotifications_License.txt + \ No newline at end of file diff --git a/Engine/Source/ThirdParty/Facebook/Facebook.Build.cs b/Engine/Source/ThirdParty/Facebook/Facebook.Build.cs index 90037a670dd9..a498b9d95dcb 100644 --- a/Engine/Source/ThirdParty/Facebook/Facebook.Build.cs +++ b/Engine/Source/ThirdParty/Facebook/Facebook.Build.cs @@ -9,12 +9,11 @@ public class Facebook : ModuleRules { Type = ModuleType.External; - Definitions.Add("WITH_FACEBOOK=1"); - // Additional Frameworks and Libraries for Android found in OnlineSubsystemFacebook_UPL.xml if (Target.Platform == UnrealTargetPlatform.IOS) { - Definitions.Add("UE4_FACEBOOK_VER=4.18"); + Definitions.Add("WITH_FACEBOOK=1"); + Definitions.Add("UE4_FACEBOOK_VER=4.18"); // These are iOS system libraries that Facebook depends on (FBAudienceNetwork, FBNotifications) PublicFrameworks.AddRange( diff --git a/Engine/Source/ThirdParty/Facebook/FacebookiOS.tps b/Engine/Source/ThirdParty/Facebook/FacebookiOS.tps deleted file mode 100644 index 4248031c5455..000000000000 --- a/Engine/Source/ThirdParty/Facebook/FacebookiOS.tps +++ /dev/null @@ -1,26 +0,0 @@ - - - Facebook SDK for iOS 4.19 - Engine/Source/ThirdParty/Facebook/IOS/FacebookSDK - 2017-02-20T15:20:53.4785436-05:00 - Access to the Facebook SDK for iOS - External provider authentication of users and access to social features provided by Facebook - - iOS - - - UE4 - - lib - https://github.com/facebook/facebook-ios-sdk/blob/master/LICENSE - - Licensees - Git - P4 - - false - true - None - http://developers.facebook.com/policy/ - FacebookiOS.tps - \ No newline at end of file diff --git a/Engine/Source/ThirdParty/Facebook/facebook-ios-sdk.tps b/Engine/Source/ThirdParty/Facebook/facebook-ios-sdk.tps index 5d73975ea289..928088df62b8 100644 --- a/Engine/Source/ThirdParty/Facebook/facebook-ios-sdk.tps +++ b/Engine/Source/ThirdParty/Facebook/facebook-ios-sdk.tps @@ -1,15 +1,15 @@  - Facebook SDK 4.01 + Facebook SDK for iOS v4.18.0 /Engine/Source/ThirdParty/Facebook/ 2016-06-09T17:05:24.8627086-04:00 Allows users to integrate Facebook Login, Sharing etc into their game/app - UE has supported this in earlier versions and it is due an upgrade. - https://github.com/facebook/facebook-ios-sdk/blob/sdk-version-4.0.1/LICENSE + External provider authentication of users and access to social features provided by Facebook + 1 Licensees Git P4 - /Engine/Source/ThirdParty/Licenses/Facebook_SDK4.01_LICENSE.txt + /Engine/Source/ThirdParty/Licenses/FacebookSDKiOS_License.txt \ No newline at end of file diff --git a/Engine/Source/ThirdParty/GoogleVR/include/vr/gvr/capi/include/gvr.h b/Engine/Source/ThirdParty/GoogleVR/include/vr/gvr/capi/include/gvr.h index bdc8c07fda5a..7d3fc86b9299 100644 --- a/Engine/Source/ThirdParty/GoogleVR/include/vr/gvr/capi/include/gvr.h +++ b/Engine/Source/ThirdParty/GoogleVR/include/vr/gvr/capi/include/gvr.h @@ -253,6 +253,9 @@ bool gvr_get_async_reprojection_enabled(const gvr_context* gvr); /// will ensure that the populated viewports reflect the currently paired /// viewer. /// +/// This function assumes that the client is *not* using multiview to render to +/// multiple layers simultaneously. +/// /// @param gvr Pointer to the gvr instance from which to get the viewports. /// @param viewport_list Pointer to a previously allocated viewport list. This /// will be populated with the recommended buffer viewports and resized if @@ -340,7 +343,7 @@ void gvr_distort_to_screen(gvr_context* gvr, int32_t texture_id, gvr_clock_time_point target_presentation_time); /// Queries whether a particular GVR feature is supported by the underlying -/// platform. +/// platform. This should be called after gvr_initialize_gl(). /// /// @param gvr The context to query against. /// @param feature The gvr_feature type being queried. @@ -491,6 +494,13 @@ int32_t gvr_buffer_viewport_get_reprojection( void gvr_buffer_viewport_set_reprojection(gvr_buffer_viewport* viewport, int32_t reprojection); +/// Sets the layer in a multiview buffer from which the viewport should sample. +/// +/// @param layer_index The layer in the array texture that distortion samples +/// from. Must be non-negative. Defaults to 0. +void gvr_buffer_viewport_set_source_layer(gvr_buffer_viewport* viewport, + int32_t layer_index); + /// Compares two gvr_buffer_viewport instances and returns true if they specify /// the same view mapping. /// @@ -617,6 +627,17 @@ void gvr_buffer_spec_set_color_format(gvr_buffer_spec* spec, void gvr_buffer_spec_set_depth_stencil_format(gvr_buffer_spec* spec, int32_t depth_stencil_format); +/// Sets the number of layers in a framebuffer backed by an array texture. +/// +/// Default is 1, which means a non-layered texture will be created. +/// Not all platforms support multiple layers, so clients can call +/// gvr_is_feature_supported(GVR_FEATURE_MULTIVIEW) to check. +/// +/// @param spec Buffer specification. +/// @param num_layers The number of layers in the array texture. +void gvr_buffer_spec_set_multiview_layers(gvr_buffer_spec* spec, + int32_t num_layers); + /// Creates a swap chain from the given buffer specifications. /// This is a potentially time-consuming operation. All frames within the /// swapchain will be allocated. Once rendering is stopped, call @@ -971,6 +992,10 @@ class BufferViewport { if (viewport_) gvr_buffer_viewport_destroy(&viewport_); } + explicit operator bool() const { + return viewport_ != nullptr; + } + /// For more information, see gvr_buffer_viewport_get_source_fov(). Rectf GetSourceFov() const { return gvr_buffer_viewport_get_source_fov(viewport_); @@ -1041,6 +1066,11 @@ class BufferViewport { gvr_buffer_viewport_set_reprojection(viewport_, reprojection); } + /// For more information, see gvr_buffer_viewport_set_source_layer(). + void SetSourceLayer(int32_t layer_index) { + gvr_buffer_viewport_set_source_layer(viewport_, layer_index); + } + /// For more information, see gvr_buffer_viewport_equal(). bool operator==(const BufferViewport& other) const { return gvr_buffer_viewport_equal(viewport_, other.viewport_) ? true : false; @@ -1052,7 +1082,7 @@ class BufferViewport { /// @name Wrapper manipulation /// @{ /// Creates a C++ wrapper for a C object and takes ownership. - explicit BufferViewport(gvr_buffer_viewport* viewport) + explicit BufferViewport(gvr_buffer_viewport* viewport = nullptr) : viewport_(viewport) {} /// Returns the wrapped C object. Does not affect ownership. @@ -1084,6 +1114,11 @@ class BufferViewport { /// validity is tied to the lifetime of that instance. class BufferViewportList { public: + BufferViewportList() + : context_(nullptr), + viewport_list_(nullptr) + {} + BufferViewportList(BufferViewportList&& other) : context_(nullptr), viewport_list_(nullptr) { std::swap(context_, other.context_); @@ -1102,6 +1137,10 @@ class BufferViewportList { } } + explicit operator bool() const { + return viewport_list_ != nullptr; + } + /// For more information, see gvr_get_recommended_buffer_viewports(). void SetToRecommendedBufferViewports() { gvr_get_recommended_buffer_viewports(context_, viewport_list_); @@ -1185,6 +1224,10 @@ class BufferSpec { if (spec_) gvr_buffer_spec_destroy(&spec_); } + explicit operator bool() const { + return spec_ != nullptr; + } + /// Gets the buffer's size. The default value is the recommended render /// target size. For more information, see gvr_buffer_spec_get_size(). Sizei GetSize() const { @@ -1229,10 +1272,15 @@ class BufferSpec { gvr_buffer_spec_set_depth_stencil_format(spec_, depth_stencil_format); } + /// For more information, see gvr_buffer_spec_set_multiview_layers(). + void SetMultiviewLayers(int32_t num_layers) { + gvr_buffer_spec_set_multiview_layers(spec_, num_layers); + } + /// @name Wrapper manipulation /// @{ /// Creates a C++ wrapper for a C object and takes ownership. - explicit BufferSpec(gvr_buffer_spec* spec) : spec_(spec) {} + explicit BufferSpec(gvr_buffer_spec* spec = nullptr) : spec_(spec) {} /// Returns the wrapped C object. Does not affect ownership. gvr_buffer_spec* cobj() { return spec_; } @@ -1275,6 +1323,10 @@ class Frame { // The swap chain owns the frame, so no clean-up is required. } + explicit operator bool() const { + return frame_ != nullptr; + } + /// For more information, see gvr_frame_get_buffer_size(). Sizei GetBufferSize(int32_t index) const { return gvr_frame_get_buffer_size(frame_, index); @@ -1305,7 +1357,7 @@ class Frame { /// @name Wrapper manipulation /// @{ /// Creates a C++ wrapper for a C object and takes ownership. - explicit Frame(gvr_frame* frame) : frame_(frame) {} + explicit Frame(gvr_frame* frame = nullptr) : frame_(frame) {} /// Returns the wrapped C object. Does not affect ownership. gvr_frame* cobj() { return frame_; } @@ -1349,6 +1401,10 @@ class SwapChain { if (swap_chain_) gvr_swap_chain_destroy(&swap_chain_); } + explicit operator bool() const { + return swap_chain_ != nullptr; + } + /// For more information, see gvr_swap_chain_get_buffer_count(). int32_t GetBufferCount() const { return gvr_swap_chain_get_buffer_count(swap_chain_); @@ -1376,7 +1432,8 @@ class SwapChain { /// @name Wrapper manipulation /// @{ /// Creates a C++ wrapper for a C object and takes ownership. - explicit SwapChain(gvr_swap_chain* swap_chain) : swap_chain_(swap_chain) {} + explicit SwapChain(gvr_swap_chain* swap_chain = nullptr) + : swap_chain_(swap_chain) {} /// Returns the wrapped C object. Does not affect ownership. gvr_swap_chain* cobj() { return swap_chain_; } diff --git a/Engine/Source/ThirdParty/GoogleVR/include/vr/gvr/capi/include/gvr_gesture.h b/Engine/Source/ThirdParty/GoogleVR/include/vr/gvr/capi/include/gvr_gesture.h index 2df27fa21695..0860e00bda7d 100644 --- a/Engine/Source/ThirdParty/GoogleVR/include/vr/gvr/capi/include/gvr_gesture.h +++ b/Engine/Source/ThirdParty/GoogleVR/include/vr/gvr/capi/include/gvr_gesture.h @@ -111,7 +111,7 @@ typedef enum { /// Opaque handle to gesture context. typedef struct gvr_gesture_context_ gvr_gesture_context; -/// Opaque handle to gesture detector. +/// Opaque handle to gesture. typedef struct gvr_gesture_ gvr_gesture; /// Creates and initializes a gesture context instance which can be used to diff --git a/Engine/Source/ThirdParty/GoogleVR/include/vr/gvr/capi/include/gvr_types.h b/Engine/Source/ThirdParty/GoogleVR/include/vr/gvr/capi/include/gvr_types.h index cf81b51c8a92..39329d95094e 100644 --- a/Engine/Source/ThirdParty/GoogleVR/include/vr/gvr/capi/include/gvr_types.h +++ b/Engine/Source/ThirdParty/GoogleVR/include/vr/gvr/capi/include/gvr_types.h @@ -56,6 +56,9 @@ typedef enum { // Asynchronous reprojection warps the app's rendered frame using the most // recent head pose just before pushing the frame to the display. GVR_FEATURE_ASYNC_REPROJECTION = 0, + // Support for framebuffers suitable for rendering with the GL_OVR_multiview2 + // and GL_OVR_multiview_multisampled_render_to_texture extensions. + GVR_FEATURE_MULTIVIEW = 1, } gvr_feature; /// @} diff --git a/Engine/Source/ThirdParty/GoogleVR/include/vr/gvr/capi/include/gvr_version.h b/Engine/Source/ThirdParty/GoogleVR/include/vr/gvr/capi/include/gvr_version.h index ebb3c761c532..5383a308cb4d 100644 --- a/Engine/Source/ThirdParty/GoogleVR/include/vr/gvr/capi/include/gvr_version.h +++ b/Engine/Source/ThirdParty/GoogleVR/include/vr/gvr/capi/include/gvr_version.h @@ -23,14 +23,14 @@ extern "C" { /// A string representation of the current GVR build version. This is of /// the form "MAJOR.MINOR.PATCH". Note that this may differ from the runtime /// GVR version as reported by gvr_get_version_string(). -#define GVR_SDK_VERSION_STRING "1.30.0" +#define GVR_SDK_VERSION_STRING "1.40.0" /// Semantic components for the current GVR build version. Note that these /// values may differ from the runtime GVR version as reported by /// gvr_get_version(). enum { GVR_SDK_MAJOR_VERSION = 1, - GVR_SDK_MINOR_VERSION = 30, + GVR_SDK_MINOR_VERSION = 40, GVR_SDK_PATCH_VERSION = 0, }; diff --git a/Engine/Source/ThirdParty/GoogleVR/lib/common_library/res/values-da/values.xml b/Engine/Source/ThirdParty/GoogleVR/lib/common_library/res/values-da/values.xml index e3d6a6f7770f..3f5522d22ac5 100644 --- a/Engine/Source/ThirdParty/GoogleVR/lib/common_library/res/values-da/values.xml +++ b/Engine/Source/ThirdParty/GoogleVR/lib/common_library/res/values-da/values.xml @@ -7,7 +7,7 @@ "OK" "ÅBN HJÆLP" "En Daydream-kompatibel telefon er påkrævet. Gå til Hjælp til Daydream for at få flere oplysninger." -"Hent Cardboard-appen, så du kan konfigurere fremviseren." +"Hent Cardboard-appen, så du kan konfigurere brillen." "Konfigurer" "Telefonen er ikke kompatibel" "Konfiguration er påkrævet" @@ -18,10 +18,10 @@ "Gå til Play Butik" "Gå til Indstillinger" "Der er ingen browser til at åbne websitet" -"Placer din telefon i Cardboard-fremviseren" -"Placer din telefon i din %s-fremviser" +"Placer din telefon i Cardboard-brillen" +"Placer din telefon i din %s-brille" "indstillinger" "Konfigurer" "Skift" -"Vil du skifte fremviser?" +"Vil du skifte brille?" \ No newline at end of file diff --git a/Engine/Source/ThirdParty/GoogleVR/lib/common_library/res/values-id/values.xml b/Engine/Source/ThirdParty/GoogleVR/lib/common_library/res/values-id/values.xml index 0e544ce66d9f..4050ec3ef066 100644 --- a/Engine/Source/ThirdParty/GoogleVR/lib/common_library/res/values-id/values.xml +++ b/Engine/Source/ThirdParty/GoogleVR/lib/common_library/res/values-id/values.xml @@ -4,7 +4,7 @@ "kembali" "Batal" -"MENGERTI" +"OK" "BUKA PUSAT BANTUAN" "Ponsel yang kompatibel dengan Daydream diperlukan. Kunjungi Pusat Bantuan Daydream untuk informasi lebih lanjut." "Dapatkan aplikasi Cardboard untuk mengonfigurasikan penampil Anda." diff --git a/Engine/Source/ThirdParty/GoogleVR/lib/common_library/res/values-zh-rCN/values.xml b/Engine/Source/ThirdParty/GoogleVR/lib/common_library/res/values-zh-rCN/values.xml index 2a5dfdbf6a4b..45af8fa98a67 100644 --- a/Engine/Source/ThirdParty/GoogleVR/lib/common_library/res/values-zh-rCN/values.xml +++ b/Engine/Source/ThirdParty/GoogleVR/lib/common_library/res/values-zh-rCN/values.xml @@ -7,7 +7,7 @@ "知道了" "打开帮助中心" "手机必须与 Daydream 兼容。请访问 Daydream 帮助中心了解详情。" -"获取 Cardboard 应用以配置眼镜。" +"获取 Cardboard 应用以配置观看器。" "配置" "手机不兼容" "需要设置" @@ -18,10 +18,10 @@ "转到 Play 商店" "转到“设置”" "找不到可以打开网站的浏览器" -"将手机放入 Cardboard 眼镜" -"将手机放入 %s 眼镜" +"将手机放入 Cardboard 观看器" +"将手机放入 %s 观看器" "设置" "设置" "切换" -"要使用其他眼镜吗?" +"要使用其他观看器吗?" \ No newline at end of file diff --git a/Engine/Source/ThirdParty/ICU/icu4c-53_1/Android/Config for Android.bat b/Engine/Source/ThirdParty/ICU/icu4c-53_1/Android/Config for Android.bat deleted file mode 100644 index 0aa48a332b0b..000000000000 --- a/Engine/Source/ThirdParty/ICU/icu4c-53_1/Android/Config for Android.bat +++ /dev/null @@ -1,35 +0,0 @@ -@echo off -REM Batch file for configuring Android platforms of ICU -REM Run this from the ICU directory - -setlocal -set CYGWIN=winsymlinks:native - -REM Android Configs -if not exist ./Android mkdir Android -cd ./Android - - REM ARMv7 Config - if not exist ./ARMv7 mkdir ARMv7 - cd ./ARMv7 - set PATH=%NDKROOT%\toolchains\llvm-3.3\prebuilt\windows-x86_64\bin\;%NDKROOT%\toolchains\arm-linux-androideabi-4.8\prebuilt\windows-x86_64\bin\;%NDKROOT%\toolchains\arm-linux-androideabi-4.8\prebuilt\windows-x86_64\arm-linux-androideabi\bin\;%PATH% - bash -c '../../ConfigForAndroid-armv7.sh' - cd ../ - - REM x86 Config - if not exist ./x86 mkdir x86 - cd ./x86 - set PATH=%NDKROOT%\toolchains\llvm-3.3\prebuilt\windows-x86_64\bin\;%NDKROOT%\toolchains\x86-4.8\prebuilt\windows-x86_64\bin\;%NDKROOT%\toolchains\x86-4.8\prebuilt\windows-x86_64\i686-linux-android\bin\;%PATH% - bash -c '../../ConfigForAndroid-x86.sh' - cd ../ - - REM x64 Config -REM if not exist ./x64 mkdir x64 -REM cd ./x64 -REM set PATH=%NDKROOT%\toolchains\llvm-3.4\prebuilt\windows-x86_64\bin\;%NDKROOT%\toolchains\x86_64-4.9\prebuilt\windows-x86_64\bin\;%NDKROOT%\toolchains\x86_64-4.9\prebuilt\windows-x86_64\x86_64-linux-android\bin\;%PATH% -REM bash -c '../../ConfigForAndroid-x64.sh' -REM cd ../ - -REM Back to root -cd ../ -endlocal \ No newline at end of file diff --git a/Engine/Source/ThirdParty/ICU/icu4c-53_1/Android/ConfigForAndroid-arm64.sh b/Engine/Source/ThirdParty/ICU/icu4c-53_1/Android/ConfigForAndroid-arm64.sh new file mode 100755 index 000000000000..9a1133ea155f --- /dev/null +++ b/Engine/Source/ThirdParty/ICU/icu4c-53_1/Android/ConfigForAndroid-arm64.sh @@ -0,0 +1,13 @@ +SYSROOT=$NDKROOT/platforms/android-21/arch-arm64 +GCCTOOLCHAIN=$NDKROOT/toolchains/aarch64-linux-android-4.9/prebuilt/windows-x86_64 +GNUSTL=$NDKROOT/sources/cxx-stl/gnu-libstdc++/4.9 +COMMONTOOLCHAINFLAGS="-target aarch64-none-linux-android --sysroot=$SYSROOT -gcc-toolchain $GCCTOOLCHAIN" +COMMONCOMPILERFLAGS="-fdiagnostics-format=msvc -fPIC -fno-exceptions -frtti -fno-short-enums -march=armv8-a -fsigned-char" +COMMONINCLUDES="-I$GNUSTL/include -I$GNUSTL/libs/arm64-v8a/include -I$SYSROOT/usr/include" +export CFLAGS="$COMMONTOOLCHAINFLAGS $COMMONCOMPILERFLAGS -DANDROID -fdata-sections -ffunction-sections $COMMONINCLUDES -x c" +export CXXFLAGS="$COMMONTOOLCHAINFLAGS $COMMONCOMPILERFLAGS $COMMONINCLUDES -x c++ -std=c++11" +export CPPFLAGS="$COMMONTOOLCHAINFLAGS $COMMONINCLUDES -DANDROID -frtti -fno-exceptions -fdata-sections -ffunction-sections -DUCONFIG_NO_TRANSLITERATION=1 -DPIC -DU_HAVE_NL_LANGINFO_CODESET=0" +export LDFLAGS="$COMMONTOOLCHAINFLAGS -nostdlib -Wl,-shared,-Bsymbolic -Wl,--no-undefined -lgnustl_shared -lc -lgcc -L$GNUSTL/libs/arm64-v8a -march=armv8-a -Wl" + +echo "Running Release Config" +../../Source/configure --prefix=$PWD --build=x86_64-unknown-cygwin --with-cross-build=$PWD/../../Win64/VS2015 --host=aarch64-none-linux-android --disable-debug --enable-release --enable-static --disable-shared --with-data-packaging=files diff --git a/Engine/Source/ThirdParty/ICU/icu4c-53_1/Android/ConfigForAndroid-armv7.sh b/Engine/Source/ThirdParty/ICU/icu4c-53_1/Android/ConfigForAndroid-armv7.sh index e09db25fbb66..48622c704342 100755 --- a/Engine/Source/ThirdParty/ICU/icu4c-53_1/Android/ConfigForAndroid-armv7.sh +++ b/Engine/Source/ThirdParty/ICU/icu4c-53_1/Android/ConfigForAndroid-armv7.sh @@ -1,11 +1,18 @@ SYSROOT=$NDKROOT/platforms/android-19/arch-arm -GCCTOOLCHAIN=$NDKROOT/toolchains/arm-linux-androideabi-4.8/prebuilt/windows-x86_64 -GNUSTL=$NDKROOT/sources/cxx-stl/gnu-libstdc++/4.8 +GCCTOOLCHAIN=$NDKROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/windows-x86_64 +GNUSTL=$NDKROOT/sources/cxx-stl/gnu-libstdc++/4.9 COMMONTOOLCHAINFLAGS="-target armv7a-none-linux-androideabi --sysroot=$SYSROOT -gcc-toolchain $GCCTOOLCHAIN" COMMONCOMPILERFLAGS="-fdiagnostics-format=msvc -fPIC -fno-exceptions -frtti -fno-short-enums -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -fsigned-char" COMMONINCLUDES="-I$GNUSTL/include -I$GNUSTL/libs/armeabi-v7a/include -I$SYSROOT/usr/include" export CFLAGS="$COMMONTOOLCHAINFLAGS $COMMONCOMPILERFLAGS -DANDROID -fdata-sections -ffunction-sections $COMMONINCLUDES -x c" export CXXFLAGS="$COMMONTOOLCHAINFLAGS $COMMONCOMPILERFLAGS $COMMONINCLUDES -x c++ -std=c++11" -export CPPFLAGS="$COMMONTOOLCHAINFLAGS $COMMONINCLUDES -DANDROID -frtti -fno-exceptions -fdata-sections -ffunction-sections -DUCONFIG_NO_TRANSLITERATION=1 -DPIC -DU_HAVE_NL_LANGINFO_CODESET=0 -DU_TIMEZONE=0" +export CPPFLAGS="$COMMONTOOLCHAINFLAGS $COMMONINCLUDES -DANDROID -frtti -fno-exceptions -fdata-sections -ffunction-sections -DUCONFIG_NO_TRANSLITERATION=1 -DPIC -DU_HAVE_NL_LANGINFO_CODESET=0" export LDFLAGS="$COMMONTOOLCHAINFLAGS -nostdlib -Wl,-shared,-Bsymbolic -Wl,--no-undefined -lgnustl_shared -lc -lgcc -L$GNUSTL/libs/armeabi-v7a -march=armv7-a -Wl,--fix-cortex-a8" -../../Source/configure --prefix=$PWD --build=x86_64-unknown-cygwin --with-cross-build=$PWD/../../Win64/VS2013 --host=armv7a-none-linux-androideabi --enable-debug --disable-release --enable-static --disable-shared --with-data-packaging=files \ No newline at end of file +if [ $1 -eq 1 ] +then + echo "Running Debug Config" + ../../Source/configure --prefix=$PWD --build=x86_64-unknown-cygwin --with-cross-build=$PWD/../../Win64/VS2015 --host=armv7a-none-linux-androideabi --enable-debug --disable-release --enable-static --disable-shared --with-data-packaging=files +else + echo "Running Release Config" + ../../Source/configure --prefix=$PWD --build=x86_64-unknown-cygwin --with-cross-build=$PWD/../../Win64/VS2015 --host=armv7a-none-linux-androideabi --disable-debug --enable-release --enable-static --disable-shared --with-data-packaging=files +fi diff --git a/Engine/Source/ThirdParty/ICU/icu4c-53_1/Android/ConfigForAndroid-x64.sh b/Engine/Source/ThirdParty/ICU/icu4c-53_1/Android/ConfigForAndroid-x64.sh index 0e3a79c9338b..15578a63c400 100755 --- a/Engine/Source/ThirdParty/ICU/icu4c-53_1/Android/ConfigForAndroid-x64.sh +++ b/Engine/Source/ThirdParty/ICU/icu4c-53_1/Android/ConfigForAndroid-x64.sh @@ -1,4 +1,4 @@ -SYSROOT=$NDKROOT/platforms/android-20/arch-x86_64 +SYSROOT=$NDKROOT/platforms/android-21/arch-x86_64 GCCTOOLCHAIN=$NDKROOT/toolchains/x86_64-4.9/prebuilt/windows-x86_64 GNUSTL=$NDKROOT/sources/cxx-stl/gnu-libstdc++/4.9 COMMONTOOLCHAINFLAGS="-target x86_64-none-linux-android --sysroot=$SYSROOT -gcc-toolchain $GCCTOOLCHAIN" @@ -6,6 +6,6 @@ COMMONCOMPILERFLAGS="-fdiagnostics-format=msvc -fPIC -fno-exceptions -frtti -fno COMMONINCLUDES="-I$GNUSTL/include -I$GNUSTL/libs/x86_64/include -I$SYSROOT/usr/include" export CFLAGS="$COMMONTOOLCHAINFLAGS $COMMONCOMPILERFLAGS -MD -MF /dev/null -DANDROID -fdata-sections -ffunction-sections $COMMONINCLUDES -x c" export CXXFLAGS="$COMMONTOOLCHAINFLAGS $COMMONCOMPILERFLAGS -MD -MF /dev/null $COMMONINCLUDES -x c++ -std=c++11" -export CPPFLAGS="$COMMONTOOLCHAINFLAGS $COMMONINCLUDES -MD -MF /dev/null -DANDROID -frtti -fno-exceptions -fdata-sections -ffunction-sections -DUCONFIG_NO_TRANSLITERATION=1 -DPIC -DU_HAVE_NL_LANGINFO_CODESET=0 -DU_TIMEZONE=0" +export CPPFLAGS="$COMMONTOOLCHAINFLAGS $COMMONINCLUDES -MD -MF /dev/null -DANDROID -frtti -fno-exceptions -fdata-sections -ffunction-sections -DUCONFIG_NO_TRANSLITERATION=1 -DPIC -DU_HAVE_NL_LANGINFO_CODESET=0" export LDFLAGS="$COMMONTOOLCHAINFLAGS -nostdlib -Wl,-shared,-Bsymbolic -Wl,--no-undefined -lgnustl_shared -lc -lgcc -L$GNUSTL/libs/x86_64 -march=atom" -../../Source/configure --prefix=$PWD --build=x86_64-unknown-cygwin --with-cross-build=$PWD/../../Win64/VS2013 --host=x86_64-none-linux-android --enable-debug --disable-release --enable-static --disable-shared --with-data-packaging=files \ No newline at end of file +../../Source/configure --prefix=$PWD --build=x86_64-unknown-cygwin --with-cross-build=$PWD/../../Win64/VS2015 --host=x86_64-none-linux-android --enable-debug --disable-release --enable-static --disable-shared --with-data-packaging=files \ No newline at end of file diff --git a/Engine/Source/ThirdParty/ICU/icu4c-53_1/Android/ConfigForAndroid-x86.sh b/Engine/Source/ThirdParty/ICU/icu4c-53_1/Android/ConfigForAndroid-x86.sh index 073e42bb4c4e..f95291e2a068 100755 --- a/Engine/Source/ThirdParty/ICU/icu4c-53_1/Android/ConfigForAndroid-x86.sh +++ b/Engine/Source/ThirdParty/ICU/icu4c-53_1/Android/ConfigForAndroid-x86.sh @@ -1,11 +1,11 @@ SYSROOT=$NDKROOT/platforms/android-19/arch-x86 -GCCTOOLCHAIN=$NDKROOT/toolchains/x86-4.8/prebuilt/windows-x86_64 -GNUSTL=$NDKROOT/sources/cxx-stl/gnu-libstdc++/4.8 +GCCTOOLCHAIN=$NDKROOT/toolchains/x86-4.9/prebuilt/windows-x86_64 +GNUSTL=$NDKROOT/sources/cxx-stl/gnu-libstdc++/4.9 COMMONTOOLCHAINFLAGS="-target i686-none-linux-android --sysroot=$SYSROOT -gcc-toolchain $GCCTOOLCHAIN" COMMONCOMPILERFLAGS="-fdiagnostics-format=msvc -fPIC -fno-exceptions -frtti -fno-short-enums -march=atom -fsigned-char" COMMONINCLUDES="-I$GNUSTL/include -I$GNUSTL/libs/x86/include -I$SYSROOT/usr/include" export CFLAGS="$COMMONTOOLCHAINFLAGS $COMMONCOMPILERFLAGS -MD -MF /dev/null -DANDROID -fdata-sections -ffunction-sections $COMMONINCLUDES -x c" export CXXFLAGS="$COMMONTOOLCHAINFLAGS $COMMONCOMPILERFLAGS -MD -MF /dev/null $COMMONINCLUDES -x c++ -std=c++11" -export CPPFLAGS="$COMMONTOOLCHAINFLAGS $COMMONINCLUDES -MD -MF /dev/null -DANDROID -frtti -fno-exceptions -fdata-sections -ffunction-sections -DUCONFIG_NO_TRANSLITERATION=1 -DPIC -DU_HAVE_NL_LANGINFO_CODESET=0 -DU_TIMEZONE=0" +export CPPFLAGS="$COMMONTOOLCHAINFLAGS $COMMONINCLUDES -MD -MF /dev/null -DANDROID -frtti -fno-exceptions -fdata-sections -ffunction-sections -DUCONFIG_NO_TRANSLITERATION=1 -DPIC -DU_HAVE_NL_LANGINFO_CODESET=0" export LDFLAGS="$COMMONTOOLCHAINFLAGS -nostdlib -Wl,-shared,-Bsymbolic -Wl,--no-undefined -lgnustl_shared -lc -lgcc -L$GNUSTL/libs/x86 -march=atom" -../../Source/configure --prefix=$PWD --build=x86_64-unknown-cygwin --with-cross-build=$PWD/../../Win64/VS2013 --host=i686-none-linux-android --enable-debug --disable-release --enable-static --disable-shared --with-data-packaging=files \ No newline at end of file +../../Source/configure --prefix=$PWD --build=x86_64-unknown-cygwin --with-cross-build=$PWD/../../Win64/VS2015 --host=i686-none-linux-android --enable-debug --disable-release --enable-static --disable-shared --with-data-packaging=files \ No newline at end of file diff --git a/Engine/Source/ThirdParty/ICU/icu4c-53_1/Android/Make for Android.bat b/Engine/Source/ThirdParty/ICU/icu4c-53_1/Android/Make for Android.bat deleted file mode 100644 index 0b2edd26eeef..000000000000 --- a/Engine/Source/ThirdParty/ICU/icu4c-53_1/Android/Make for Android.bat +++ /dev/null @@ -1,52 +0,0 @@ -@echo off -REM Batch file for configuring Android platforms of ICU -REM Run this from the ICU directory - -setlocal -set CYGWIN=winsymlinks:native - -REM Android Configs -if not exist ./Android ( - echo Error: Android directory does not exist. Did you forget to run configuration? - goto:eof) -cd ./Android - - REM ARMv7 Make - if not exist ./ARMv7 ( - echo Error: ARMv7 directory does not exist. Did you forget to run configuration? - goto:eof) - cd ./ARMv7 - set PATH=%NDKROOT%\toolchains\llvm-3.3\prebuilt\windows-x86_64\bin\;%NDKROOT%\toolchains\arm-linux-androideabi-4.8\prebuilt\windows-x86_64\bin\;%NDKROOT%\toolchains\arm-linux-androideabi-4.8\prebuilt\windows-x86_64\arm-linux-androideabi\bin\;%PATH% - bash -c 'make clean' - bash -c 'make all' - cd ./data - bash -c 'make' - cd ../../ - - REM x86 Make - if not exist ./x86 ( - echo Error: x86 directory does not exist. Did you forget to run configuration? - goto:eof) - cd ./x86 - set PATH=%NDKROOT%\toolchains\llvm-3.3\prebuilt\windows-x86_64\bin\;%NDKROOT%\toolchains\x86-4.8\prebuilt\windows-x86_64\bin\;%NDKROOT%\toolchains\x86-4.8\prebuilt\windows-x86_64\i686-linux-android\bin\;%PATH% - bash -c 'make clean' - bash -c 'make all' - cd ./data - bash -c 'make' - cd ../../ - - REM x64 Make -REM if not exist ./x64 ( -REM echo Error: x64 directory does not exist. Did you forget to run configuration? -REM goto:eof) -REM cd ./x64 -REM set PATH=%NDKROOT%\toolchains\llvm-3.4\prebuilt\windows-x86_64\bin\;%NDKROOT%\toolchains\x86_64-4.9\prebuilt\windows-x86_64\bin\;%NDKROOT%\toolchains\x86_64-4.9\prebuilt\windows-x86_64\x86_64-linux-android\bin\;%PATH% -REM bash -c 'make clean' -REM bash -c 'make all' -REM cd ./data -REM bash -c 'make' -REM cd ../../ - -REM Back to root -cd ../ -endlocal \ No newline at end of file diff --git a/Engine/Source/ThirdParty/ICU/icu4c-53_1/Android/README_AndroidCompile.txt b/Engine/Source/ThirdParty/ICU/icu4c-53_1/Android/README_AndroidCompile.txt index e3b32355284f..a43abbe9101d 100644 --- a/Engine/Source/ThirdParty/ICU/icu4c-53_1/Android/README_AndroidCompile.txt +++ b/Engine/Source/ThirdParty/ICU/icu4c-53_1/Android/README_AndroidCompile.txt @@ -1,3 +1,15 @@ -The batch files in this directory are meant to be run from one directory up. +Before running these Android scripts you will have to run Config and Make for Windows. -Either copy them one directory up to use, or fix them up to be run from this directory. +Make sure your NDKROOT path only has forward slashes (/) as the backward slashes (\) will cause issues. + +If you have to change any of the files, make sure before trying to run any of them to run 'dos2unix' on the file eg 'dos2unix Make\ for\ Android.bat' in cygwin. + + +This is the order to run the scripts in from the Engine\Source\ThirdParty\ICU\icu4c-53_1 directory in cygwin... + +1. Config for Windows - Release.bat +2. Make on Windows.bat +3. Run Config for Android.bat with Usage options. like "Config for Android.bat ARMv7 d" or "Config for Android.bat ARM64" +4. Run Make for Android.bat with Usage options. like "Make for Android.bat ARMv7 d" + +You'd need to follow these steps for each arch you want to rebuild. \ No newline at end of file diff --git a/Engine/Source/ThirdParty/ICU/icu4c-53_1/Config for Android - Debug.bat b/Engine/Source/ThirdParty/ICU/icu4c-53_1/Config for Android - Debug.bat deleted file mode 100644 index 71d2966e78d6..000000000000 --- a/Engine/Source/ThirdParty/ICU/icu4c-53_1/Config for Android - Debug.bat +++ /dev/null @@ -1,21 +0,0 @@ -@echo off -REM Batch file for configuring Android platforms of ICU -REM Run this from the ICU directory - -setlocal -set CYGWIN=winsymlinks:native - -REM Android Configs -if not exist ./Android mkdir Android -cd ./Android - - REM ARMv7 Config - if not exist ./ARMv7 mkdir ARMv7 - cd ./ARMv7 - set PATH=%PATH%;%NDKROOT%\toolchains\llvm-3.3\prebuilt\windows-x86_64\bin\;%NDKROOT%\toolchains\arm-linux-androideabi-4.8\prebuilt\windows-x86_64\bin\;%NDKROOT%\toolchains\arm-linux-androideabi-4.8\prebuilt\windows-x86_64\arm-linux-androideabi\bin\ - bash -c '../../ConfigForAndroid-Debug.sh' - cd ../ - -REM Back to root -cd ../ -endlocal \ No newline at end of file diff --git a/Engine/Source/ThirdParty/ICU/icu4c-53_1/Config for Android - Release.bat b/Engine/Source/ThirdParty/ICU/icu4c-53_1/Config for Android - Release.bat deleted file mode 100644 index 554caedaebbb..000000000000 --- a/Engine/Source/ThirdParty/ICU/icu4c-53_1/Config for Android - Release.bat +++ /dev/null @@ -1,21 +0,0 @@ -@echo off -REM Batch file for configuring Android platforms of ICU -REM Run this from the ICU directory - -setlocal -set CYGWIN=winsymlinks:native - -REM Android Configs -if not exist ./Android mkdir Android -cd ./Android - - REM ARMv7 Config - if not exist ./ARMv7 mkdir ARMv7 - cd ./ARMv7 - set PATH=%PATH%;%NDKROOT%\toolchains\llvm-3.3\prebuilt\windows-x86_64\bin\;%NDKROOT%\toolchains\arm-linux-androideabi-4.8\prebuilt\windows-x86_64\bin\;%NDKROOT%\toolchains\arm-linux-androideabi-4.8\prebuilt\windows-x86_64\arm-linux-androideabi\bin\ - bash -c '../../ConfigForAndroid-Release.sh' - cd ../ - -REM Back to root -cd ../ -endlocal \ No newline at end of file diff --git a/Engine/Source/ThirdParty/ICU/icu4c-53_1/Config for Android.bat b/Engine/Source/ThirdParty/ICU/icu4c-53_1/Config for Android.bat new file mode 100644 index 000000000000..810c4037e56d --- /dev/null +++ b/Engine/Source/ThirdParty/ICU/icu4c-53_1/Config for Android.bat @@ -0,0 +1,66 @@ +@echo off +REM Batch file for configuring Android platforms of ICU +REM Run this from the ICU directory + +setlocal +set CYGWIN=winsymlinks:native + +:SETARCH +set ARCH="" +if "%1"=="" goto USAGE + +set Array=ARMv7 ARM64 x64 x86 +for %%i in (%Array%) do ( + if %%i==%1 set ARCH="%1" +) + +if %ARCH%=="" goto USAGE + +:SETDEBUG +set DEBUG=0 +if "%2"=="d" set DEBUG=1 + +@echo flags %ARCH% %DEBUG% + +REM Android Configs +if not exist ./Android mkdir Android +cd ./Android + + +REM ARMv7 Config +REM Set path out here bc for unknown reason it errors inside if statement +if %ARCH%=="ARMv7" set PATH=%NDKROOT%\toolchains\llvm\prebuilt\windows-x86_64\bin\;%NDKROOT%\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64\bin\;%NDKROOT%\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64\arm-linux-androideabi\bin\;%PATH% +if %ARCH%=="ARMv7" ( + @echo Config For ARMv7 being run + if not exist ./ARMv7 mkdir ARMv7 + cd ./ARMv7 + bash -c '../ConfigForAndroid-armv7.sh %DEBUG%' + cd ../ +) + + +REM ARM64 Config +REM Set path out here bc for unknown reason it errors inside if statement +if %ARCH%=="ARM64" set PATH=%NDKROOT%\toolchains\llvm\prebuilt\windows-x86_64\bin\;%NDKROOT%\toolchains\aarch64-linux-android-4.9\prebuilt\windows-x86_64\bin\;%NDKROOT%\toolchains\aarch64-linux-android-4.9\prebuilt\windows-x86_64\aarch64-linux-android\bin\;%PATH% +if %ARCH%=="ARM64" ( + @echo Config For ARM64 being run + if not exist ./ARM64 mkdir ARM64 + cd ./ARM64 + bash -c '../ConfigForAndroid-arm64.sh' + cd ../ +) + +REM Back to root +cd ../ + + + +goto END + +:USAGE +@echo Usage: %0 ARCH d +@echo ***Acceptable ARCH values are ARMv7 ARM64. Not supported: x64 x86. +@echo ***The debug flag (d) is not necessary and only used on ARMv7. + +:END +endlocal \ No newline at end of file diff --git a/Engine/Source/ThirdParty/ICU/icu4c-53_1/ConfigForAndroid-Debug.sh b/Engine/Source/ThirdParty/ICU/icu4c-53_1/ConfigForAndroid-Debug.sh deleted file mode 100755 index 7273f82a1718..000000000000 --- a/Engine/Source/ThirdParty/ICU/icu4c-53_1/ConfigForAndroid-Debug.sh +++ /dev/null @@ -1,10 +0,0 @@ -SYSROOT=$NDKROOT/platforms/android-19/arch-arm -GCCTOOLCHAIN=$NDKROOT/toolchains/arm-linux-androideabi-4.8/prebuilt/windows-x86_64 -GNUSTL=$NDKROOT/sources/cxx-stl/gnu-libstdc++/4.8 -COMMONTOOLCHAINFLAGS="-target armv7a-none-linux-androideabi --sysroot=$SYSROOT -gcc-toolchain $GCCTOOLCHAIN" -COMMONCOMPILERFLAGS="-fdiagnostics-format=msvc -fPIC -fno-exceptions -frtti -fno-short-enums -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -fsigned-char" -export CFLAGS="$COMMONTOOLCHAINFLAGS $COMMONCOMPILERFLAGS -x c" -export CXXFLAGS="$COMMONTOOLCHAINFLAGS $COMMONCOMPILERFLAGS -x c++ -std=c++11" -export CPPFLAGS="$COMMONTOOLCHAINFLAGS -DUCONFIG_NO_TRANSLITERATION=1 -DPIC -DU_HAVE_NL_LANGINFO_CODESET=0 -DU_TIMEZONE=0 -I$GNUSTL/include -I$GNUSTL/libs/armeabi-v7a/include" -export LDFLAGS="$COMMONTOOLCHAINFLAGS -nostdlib -Wl,-shared,-Bsymbolic -Wl,--no-undefined -lgnustl_shared -lc -lgcc -L$GNUSTL/libs/armeabi-v7a -march=armv7-a -Wl,--fix-cortex-a8" -../../Source/configure --prefix=$PWD --build=x86_64-unknown-cygwin --with-cross-build=$PWD/../../Win64/VS2013 --host=armv7a-none-linux-androideabi --enable-debug --disable-release --enable-static --disable-shared --disable-extras --disable-samples --disable-tools --with-data-packaging=files \ No newline at end of file diff --git a/Engine/Source/ThirdParty/ICU/icu4c-53_1/ConfigForAndroid-Release.sh b/Engine/Source/ThirdParty/ICU/icu4c-53_1/ConfigForAndroid-Release.sh deleted file mode 100755 index 790c31fc4b49..000000000000 --- a/Engine/Source/ThirdParty/ICU/icu4c-53_1/ConfigForAndroid-Release.sh +++ /dev/null @@ -1,10 +0,0 @@ -SYSROOT=$NDKROOT/platforms/android-19/arch-arm -GCCTOOLCHAIN=$NDKROOT/toolchains/arm-linux-androideabi-4.8/prebuilt/windows-x86_64 -GNUSTL=$NDKROOT/sources/cxx-stl/gnu-libstdc++/4.8 -COMMONTOOLCHAINFLAGS="-target armv7a-none-linux-androideabi --sysroot=$SYSROOT -gcc-toolchain $GCCTOOLCHAIN" -COMMONCOMPILERFLAGS="-fdiagnostics-format=msvc -fPIC -fno-exceptions -frtti -fno-short-enums -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -fsigned-char" -export CFLAGS="$COMMONTOOLCHAINFLAGS $COMMONCOMPILERFLAGS -x c" -export CXXFLAGS="$COMMONTOOLCHAINFLAGS $COMMONCOMPILERFLAGS -x c++ -std=c++11" -export CPPFLAGS="$COMMONTOOLCHAINFLAGS -DUCONFIG_NO_TRANSLITERATION=1 -DPIC -DU_HAVE_NL_LANGINFO_CODESET=0 -DU_TIMEZONE=0 -I$GNUSTL/include -I$GNUSTL/libs/armeabi-v7a/include" -export LDFLAGS="$COMMONTOOLCHAINFLAGS -nostdlib -Wl,-shared,-Bsymbolic -Wl,--no-undefined -lgnustl_shared -lc -lgcc -L$GNUSTL/libs/armeabi-v7a -march=armv7-a -Wl,--fix-cortex-a8" -../../Source/configure --prefix=$PWD --build=x86_64-unknown-cygwin --with-cross-build=$PWD/../../Win64/VS2013 --host=armv7a-none-linux-androideabi --disable-debug --enable-release --enable-static --disable-shared --disable-extras --disable-samples --disable-tools --with-data-packaging=files \ No newline at end of file diff --git a/Engine/Source/ThirdParty/ICU/icu4c-53_1/Make for Android.bat b/Engine/Source/ThirdParty/ICU/icu4c-53_1/Make for Android.bat index 057a8bd0bc36..0a6f1831eca2 100644 --- a/Engine/Source/ThirdParty/ICU/icu4c-53_1/Make for Android.bat +++ b/Engine/Source/ThirdParty/ICU/icu4c-53_1/Make for Android.bat @@ -5,6 +5,24 @@ REM Run this from the ICU directory setlocal set CYGWIN=winsymlinks:native +:SETARCH +set ARCH="" +if "%1"=="" goto USAGE + +set Array=ARMv7 ARM64 +for %%i in (%Array%) do ( + if %%i==%1 set ARCH="%1" +) + +if %ARCH%=="" goto USAGE + +:SETDEBUG +set DEBUG=0 +if "%2"=="d" set DEBUG=1 + +@echo flags %ARCH% %DEBUG% + + REM Android Configs if not exist ./Android ( echo Error: Android directory does not exist. Did you forget to run configuration? @@ -12,15 +30,66 @@ if not exist ./Android ( cd ./Android REM ARMv7 Make + +if %ARCH%=="ARMv7" set PATH=%NDKROOT%\toolchains\llvm\prebuilt\windows-x86_64\bin\;%NDKROOT%\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64\bin\;%NDKROOT%\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64\arm-linux-androideabi\bin\;%PATH% +if %ARCH%=="ARMv7" ( + if not exist ./ARMv7 ( echo Error: ARMv7 directory does not exist. Did you forget to run configuration? goto:eof) - cd ./ARMv7 - set PATH=%PATH%;%NDKROOT%\toolchains\llvm-3.3\prebuilt\windows-x86_64\bin\;%NDKROOT%\toolchains\arm-linux-androideabi-4.8\prebuilt\windows-x86_64\bin\;%NDKROOT%\toolchains\arm-linux-androideabi-4.8\prebuilt\windows-x86_64\arm-linux-androideabi\bin\ - bash -c 'make clean' - bash -c 'make all' - cd ../ + cd ./ARMv7 + + bash -c 'make clean' + bash -c 'make all' + cd ./data + bash -c 'make' + + cd .. + + REM Copying libicudata.a to the lib directory for consistency + copy /y stubdata\libicudata.a lib\libicudata.a + + if %DEBUG%==1 ( + @echo WARNING - Renaming libs for debug. You will need to rebuild release since you just over wrote the release libs. + cd lib + del "*d.a" 2>NUL + for %%A in (*.a) do ren "%%~fA" "%%~nAd.*" + cd .. + ) + + cd ../../ +) + +if %ARCH%=="ARM64" set PATH=%NDKROOT%\toolchains\llvm\prebuilt\windows-x86_64\bin\;%NDKROOT%\toolchains\aarch64-linux-android-4.9\prebuilt\windows-x86_64\bin\;%NDKROOT%\toolchains\aarch64-linux-android-4.9\prebuilt\windows-x86_64\aarch64-linux-android\bin\;%PATH% +if %ARCH%=="ARM64" ( + + if not exist ./ARM64 ( + echo Error: ARM64 directory does not exist. Did you forget to run configuration? + goto:eof) + cd ./ARM64 + + bash -c 'make clean' + bash -c 'make all' + cd ./data + bash -c 'make' + cd .. + + REM Copying libicudata.a to the lib directory for consistency + copy /y stubdata\libicudata.a lib\libicudata.a + + cd ../../ +) + REM Back to root cd ../ + +goto END + +:USAGE +@echo Usage: %0 ARCH d +@echo ***Acceptable ARCH values are ARMv7 ARM64. Not supported: x64 x86. +@echo ***The debug flag (d) is not necessary and only used on ARMv7. + +:END endlocal \ No newline at end of file diff --git a/Engine/Source/ThirdParty/ICU/icu4c-53_1/Make on Windows.bat b/Engine/Source/ThirdParty/ICU/icu4c-53_1/Make on Windows.bat index 20c1a1d72b35..75c4f53ff85a 100644 --- a/Engine/Source/ThirdParty/ICU/icu4c-53_1/Make on Windows.bat +++ b/Engine/Source/ThirdParty/ICU/icu4c-53_1/Make on Windows.bat @@ -28,7 +28,7 @@ if not exist ./Win64 ( cd ./Win64 REM VS2015 Make - if not exist ./VS2013 ( + if not exist ./VS2015 ( echo Error: VS2015 directory does not exist. Did you forget to run configuration? goto:eof) cd ./VS2015 diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/CMakeLists.txt deleted file mode 100644 index aba747c407ed..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/CMakeLists.txt +++ /dev/null @@ -1,46 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2017 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -ADD_SUBDIRECTORY(common) - -ADD_SUBDIRECTORY(verify) -ADD_SUBDIRECTORY(triangle_geometry) -ADD_SUBDIRECTORY(dynamic_scene) -ADD_SUBDIRECTORY(user_geometry) -ADD_SUBDIRECTORY(viewer) -ADD_SUBDIRECTORY(instanced_geometry) -ADD_SUBDIRECTORY(intersection_filter) -ADD_SUBDIRECTORY(pathtracer) -ADD_SUBDIRECTORY(hair_geometry) -ADD_SUBDIRECTORY(subdivision_geometry) -ADD_SUBDIRECTORY(displacement_geometry) -ADD_SUBDIRECTORY(bvh_builder) -ADD_SUBDIRECTORY(lazy_geometry) -ADD_SUBDIRECTORY(bvh_access) -ADD_SUBDIRECTORY(motion_blur_geometry) -ADD_SUBDIRECTORY(interpolation) -ADD_SUBDIRECTORY(convert) -ADD_SUBDIRECTORY(curve_geometry) -ADD_SUBDIRECTORY(buildbench) - -IF (EMBREE_RAY_PACKETS) -ADD_SUBDIRECTORY(viewer_stream) -ADD_SUBDIRECTORY(viewer_anim) -ENDIF() - -# propagate menu links up -SET(CPACK_NSIS_MENU_LINKS ${CPACK_NSIS_MENU_LINKS} PARENT_SCOPE) - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/Makefile b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/Makefile deleted file mode 100644 index 3a483e18626a..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/Makefile +++ /dev/null @@ -1,52 +0,0 @@ - -ispc2cpp: - @./ispc2cpp.sh common/tutorial/tutorial_device.isph common/tutorial/tutorial_device.h - @./ispc2cpp.sh common/tutorial/tutorial_device.ispc common/tutorial/tutorial_device.cpp - @./ispc2cpp.sh common/core/differential_geometry.isph common/core/differential_geometry.h - #@./ispc2cpp.sh common/math/random_sampler.isph common/math/random_sampler.h # manual optimizations - @./ispc2cpp.sh common/math/sampling.isph common/math/sampling.h - @./ispc2cpp.sh common/tutorial/optics.isph common/tutorial/optics.h - @./ispc2cpp.sh common/lights/light.isph common/lights/light.h - @./ispc2cpp.sh common/lights/light.ispc common/lights/light.cpp - @./ispc2cpp.sh common/lights/ambient_light.ispc common/lights/ambient_light.cpp - @./ispc2cpp.sh common/lights/directional_light.ispc common/lights/directional_light.cpp - @./ispc2cpp.sh common/lights/point_light.ispc common/lights/point_light.cpp - @./ispc2cpp.sh common/lights/quad_light.ispc common/lights/quad_light.cpp - @./ispc2cpp.sh common/lights/spot_light.ispc common/lights/spot_light.cpp - @./ispc2cpp.sh common/texture/texture2d.isph common/texture/texture2d.h - @./ispc2cpp.sh common/texture/texture2d.ispc common/texture/texture2d.cpp - @./ispc2cpp.sh common/texture/texture_param.isph common/texture/texture_param.h - @./ispc2cpp.sh triangle_geometry/triangle_geometry_device.ispc triangle_geometry/triangle_geometry_device.cpp - @./ispc2cpp.sh dynamic_scene/dynamic_scene_device.ispc dynamic_scene/dynamic_scene_device.cpp - @./ispc2cpp.sh user_geometry/user_geometry_device.ispc user_geometry/user_geometry_device.cpp - @./ispc2cpp.sh viewer/viewer_device.ispc viewer/viewer_device.cpp - @./ispc2cpp.sh viewer_stream/viewer_stream_device.ispc viewer_stream/viewer_stream_device.cpp - @./ispc2cpp.sh instanced_geometry/instanced_geometry_device.ispc instanced_geometry/instanced_geometry_device.cpp - @./ispc2cpp.sh intersection_filter/intersection_filter_device.ispc intersection_filter/intersection_filter_device.cpp - @./ispc2cpp.sh pathtracer/pathtracer_device.ispc pathtracer/pathtracer_device.cpp - @./ispc2cpp.sh hair_geometry/hair_geometry_device.ispc hair_geometry/hair_geometry_device.cpp - @./ispc2cpp.sh subdivision_geometry/subdivision_geometry_device.ispc subdivision_geometry/subdivision_geometry_device.cpp - @./ispc2cpp.sh displacement_geometry/displacement_geometry_device.ispc displacement_geometry/displacement_geometry_device.cpp - @./ispc2cpp.sh lazy_geometry/lazy_geometry_device.ispc lazy_geometry/lazy_geometry_device.cpp - @./ispc2cpp.sh motion_blur_geometry/motion_blur_geometry_device.ispc motion_blur_geometry/motion_blur_geometry_device.cpp - @./ispc2cpp.sh interpolation/interpolation_device.ispc interpolation/interpolation_device.cpp - @./ispc2cpp.sh curve_geometry/curve_geometry_device.ispc curve_geometry/curve_geometry_device.cpp - -osp2emb: - @./osp2emb.sh ../../ospray/ospray/math/math.ih common/math/math.isph - #@./osp2emb.sh ../../ospray/ospray/math/vec.ih common/math/vec.isph # requires manual changes - @./osp2emb.sh ../../ospray/ospray/math/sampling.ih common/math/sampling.isph - @./osp2emb.sh ../../ospray/ospray/lights/Light.ih common/lights/light.isph - @./osp2emb.sh ../../ospray/ospray/lights/Light.ispc common/lights/light.ispc - @./osp2emb.sh ../../ospray/ospray/lights/AmbientLight.ispc common/lights/ambient_light.ispc - @./osp2emb.sh ../../ospray/ospray/lights/DirectionalLight.ispc common/lights/directional_light.ispc - @./osp2emb.sh ../../ospray/ospray/lights/PointLight.ispc common/lights/point_light.ispc - @./osp2emb.sh ../../ospray/ospray/lights/QuadLight.ispc common/lights/quad_light.ispc - @./osp2emb.sh ../../ospray/ospray/lights/SpotLight.ispc common/lights/spot_light.ispc - @./osp2emb.sh ../../ospray/ospray/include/ospray/OSPTexture.h common/texture/texture.h - @./osp2emb.sh ../../ospray/ospray/texture/Texture2D.ih common/texture/texture2d.isph - @./osp2emb.sh ../../ospray/ospray/texture/Texture2D.ispc common/texture/texture2d.ispc - @./osp2emb.sh ../../ospray/ospray/texture/TextureParam.ih common/texture/texture_param.isph - @echo "export void dummy() {} // just to avoid linker warning under MacOSX" >> common/lights/light.ispc - -all: osp2emb ispc2cpp diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/buildbench/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/buildbench/CMakeLists.txt deleted file mode 100644 index 2d7d311d7c2d..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/buildbench/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2017 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -SET(EMBREE_ISPC_SUPPORT OFF) -INCLUDE(tutorial) -ADD_TUTORIAL(buildbench) diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/buildbench/buildbench.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/buildbench/buildbench.cpp deleted file mode 100644 index f253f12778ff..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/buildbench/buildbench.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial.h" - -namespace embree -{ - extern "C" { int g_instancing_mode = 0; } - - struct Tutorial : public SceneLoadingTutorialApplication - { - Tutorial() - : SceneLoadingTutorialApplication("build_bench",FEATURE_RTCORE) - { - interactive = false; - } - - void postParseCommandLine() - { - /* load default scene if none specified */ - if (sceneFilename.ext() == "") { - FileName file = FileName::executableFolder() + FileName("models/cornell_box.ecs"); - parseCommandLine(new ParseStream(new LineCommentFilter(file, "#")), file.path()); - } - - g_instancing_mode = instancing_mode; - } - }; - -} - -int main(int argc, char** argv) { - return embree::Tutorial().main(argc,argv); -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/buildbench/buildbench_device.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/buildbench/buildbench_device.cpp deleted file mode 100644 index 7df98266c0be..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/buildbench/buildbench_device.cpp +++ /dev/null @@ -1,437 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial_device.h" -#include "../common/tutorial/scene_device.h" - -namespace embree { - - static const MAYBE_UNUSED size_t skip_iterations = 5; - static const MAYBE_UNUSED size_t iterations_dynamic_deformable = 200; - static const MAYBE_UNUSED size_t iterations_dynamic_dynamic = 200; - static const MAYBE_UNUSED size_t iterations_dynamic_static = 50; - static const MAYBE_UNUSED size_t iterations_static_static = 30; - - extern "C" ISPCScene* g_ispc_scene; - - /* scene data */ - RTCDevice g_device = nullptr; - RTCScene g_scene = nullptr; - - unsigned int convertTriangleMesh(ISPCTriangleMesh* mesh, RTCScene scene_out, RTCGeometryFlags flags) - { - unsigned int geomID = rtcNewTriangleMesh (scene_out, flags, mesh->numTriangles, mesh->numVertices, mesh->numTimeSteps); - for (size_t t=0; tnumTimeSteps; t++) { - rtcSetBuffer(scene_out, geomID, (RTCBufferType)(RTC_VERTEX_BUFFER+t),mesh->positions+t*mesh->numVertices, 0, sizeof(Vec3fa )); - } - rtcSetBuffer(scene_out, geomID, RTC_INDEX_BUFFER, mesh->triangles, 0, sizeof(ISPCTriangle)); - mesh->geomID = geomID; - return geomID; - } - - unsigned int convertQuadMesh(ISPCQuadMesh* mesh, RTCScene scene_out, RTCGeometryFlags flags) - { - unsigned int geomID = rtcNewQuadMesh (scene_out, flags, mesh->numQuads, mesh->numVertices, mesh->numTimeSteps); - for (size_t t=0; tnumTimeSteps; t++) { - rtcSetBuffer(scene_out, geomID, (RTCBufferType)(RTC_VERTEX_BUFFER+t),mesh->positions+t*mesh->numVertices, 0, sizeof(Vec3fa )); - } - rtcSetBuffer(scene_out, geomID, RTC_INDEX_BUFFER, mesh->quads, 0, sizeof(ISPCQuad)); - mesh->geomID = geomID; - return geomID; - } - - unsigned int convertSubdivMesh(ISPCSubdivMesh* mesh, RTCScene scene_out, RTCGeometryFlags flags) - { - unsigned int geomID = rtcNewSubdivisionMesh(scene_out,flags, mesh->numFaces, mesh->numEdges, mesh->numVertices, - mesh->numEdgeCreases, mesh->numVertexCreases, mesh->numHoles, mesh->numTimeSteps); - mesh->geomID = geomID; - for (size_t i=0; inumEdges; i++) mesh->subdivlevel[i] = 16.0f; - for (size_t t=0; tnumTimeSteps; t++) { - rtcSetBuffer(scene_out, geomID, (RTCBufferType)(RTC_VERTEX_BUFFER+t),mesh->positions+t*mesh->numVertices, 0, sizeof(Vec3fa )); - } - rtcSetBuffer(scene_out, geomID, RTC_LEVEL_BUFFER, mesh->subdivlevel, 0, sizeof(float)); - rtcSetBuffer(scene_out, geomID, RTC_INDEX_BUFFER, mesh->position_indices , 0, sizeof(unsigned int)); - rtcSetBuffer(scene_out, geomID, RTC_FACE_BUFFER, mesh->verticesPerFace, 0, sizeof(unsigned int)); - rtcSetBuffer(scene_out, geomID, RTC_HOLE_BUFFER, mesh->holes, 0, sizeof(unsigned int)); - rtcSetBuffer(scene_out, geomID, RTC_EDGE_CREASE_INDEX_BUFFER, mesh->edge_creases, 0, 2*sizeof(unsigned int)); - rtcSetBuffer(scene_out, geomID, RTC_EDGE_CREASE_WEIGHT_BUFFER, mesh->edge_crease_weights, 0, sizeof(float)); - rtcSetBuffer(scene_out, geomID, RTC_VERTEX_CREASE_INDEX_BUFFER, mesh->vertex_creases, 0, sizeof(unsigned int)); - rtcSetBuffer(scene_out, geomID, RTC_VERTEX_CREASE_WEIGHT_BUFFER, mesh->vertex_crease_weights, 0, sizeof(float)); - rtcSetSubdivisionMode(scene_out, geomID, 0, mesh->position_subdiv_mode); - return geomID; - } - - unsigned int convertLineSegments(ISPCLineSegments* mesh, RTCScene scene_out, RTCGeometryFlags flags) - { - unsigned int geomID = rtcNewLineSegments (scene_out, flags, mesh->numSegments, mesh->numVertices, mesh->numTimeSteps); - for (size_t t=0; tnumTimeSteps; t++) { - rtcSetBuffer(scene_out,geomID,(RTCBufferType)(RTC_VERTEX_BUFFER+t),mesh->positions+t*mesh->numVertices,0,sizeof(Vertex)); - } - rtcSetBuffer(scene_out,geomID,RTC_INDEX_BUFFER,mesh->indices,0,sizeof(int)); - return geomID; - } - - unsigned int convertHairSet(ISPCHairSet* hair, RTCScene scene_out, RTCGeometryFlags flags) - { - unsigned int geomID = rtcNewHairGeometry (scene_out, flags, hair->numHairs, hair->numVertices, hair->numTimeSteps); - for (size_t t=0; tnumTimeSteps; t++) { - rtcSetBuffer(scene_out,geomID,(RTCBufferType)(RTC_VERTEX_BUFFER+t),hair->positions+t*hair->numVertices,0,sizeof(Vertex)); - } - rtcSetBuffer(scene_out,geomID,RTC_INDEX_BUFFER,hair->hairs,0,sizeof(ISPCHair)); - rtcSetTessellationRate(scene_out,geomID,(float)hair->tessellation_rate); - return geomID; - } - - unsigned int convertCurveGeometry(ISPCHairSet* hair, RTCScene scene_out, RTCGeometryFlags flags) - { - unsigned int geomID = rtcNewCurveGeometry (scene_out, flags, hair->numHairs, hair->numVertices, hair->numTimeSteps); - for (size_t t=0; tnumTimeSteps; t++) { - rtcSetBuffer(scene_out,geomID,(RTCBufferType)(RTC_VERTEX_BUFFER+t),hair->positions+t*hair->numVertices,0,sizeof(Vertex)); - } - rtcSetBuffer(scene_out,geomID,RTC_INDEX_BUFFER,hair->hairs,0,sizeof(ISPCHair)); - return geomID; - } - - RTCScene createScene(RTCSceneFlags sflags) - { - RTCSceneFlags scene_flags = sflags | RTC_SCENE_INCOHERENT; - int scene_aflags = RTC_INTERSECT1 | RTC_INTERSECT_STREAM | RTC_INTERPOLATE; - RTCScene scene_out = rtcDeviceNewScene(g_device, (RTCSceneFlags)scene_flags,(RTCAlgorithmFlags) scene_aflags); - return scene_out; - } - - void convertScene(RTCScene scene_out, ISPCScene* scene_in, RTCGeometryFlags gflags) - { - size_t numGeometries = scene_in->numGeometries; - //PRINT(numGeometries); - - for (size_t i=0; igeometries[i]; - if (geometry->type == SUBDIV_MESH) { - unsigned int geomID MAYBE_UNUSED = convertSubdivMesh((ISPCSubdivMesh*) geometry, scene_out, gflags); - ((ISPCSubdivMesh*)geometry)->geomID = geomID; - } - else if (geometry->type == TRIANGLE_MESH) { - unsigned int geomID MAYBE_UNUSED = convertTriangleMesh((ISPCTriangleMesh*) geometry, scene_out, gflags); - ((ISPCTriangleMesh*)geometry)->geomID = geomID; - } - else if (geometry->type == QUAD_MESH) { - unsigned int geomID MAYBE_UNUSED = convertQuadMesh((ISPCQuadMesh*) geometry, scene_out, gflags); - ((ISPCQuadMesh*)geometry)->geomID = geomID; - } - else if (geometry->type == LINE_SEGMENTS) { - unsigned int geomID MAYBE_UNUSED = convertLineSegments((ISPCLineSegments*) geometry, scene_out, gflags); - ((ISPCLineSegments*)geometry)->geomID = geomID; - } - else if (geometry->type == HAIR_SET) { - unsigned int geomID MAYBE_UNUSED = convertHairSet((ISPCHairSet*) geometry, scene_out, gflags); - ((ISPCHairSet*)geometry)->geomID = geomID; - } - else if (geometry->type == CURVES) { - unsigned int geomID MAYBE_UNUSED = convertCurveGeometry((ISPCHairSet*) geometry, scene_out, gflags); - ((ISPCHairSet*)geometry)->geomID = geomID; - } - else - assert(false); - } - } - - size_t getNumPrimitives(ISPCScene* scene_in) - { - size_t numPrimitives = 0; - size_t numGeometries = scene_in->numGeometries; - for (size_t i=0; igeometries[i]; - if (geometry->type == SUBDIV_MESH) { - numPrimitives += ((ISPCSubdivMesh*)geometry)->numFaces; - } - else if (geometry->type == TRIANGLE_MESH) { - numPrimitives += ((ISPCTriangleMesh*)geometry)->numTriangles; - } - else if (geometry->type == QUAD_MESH) { - numPrimitives += ((ISPCQuadMesh*)geometry)->numQuads; - } - else if (geometry->type == LINE_SEGMENTS) { - numPrimitives += ((ISPCLineSegments*)geometry)->numSegments; - } - else if (geometry->type == HAIR_SET) { - numPrimitives += ((ISPCHairSet*)geometry)->numHairs; - } - else if (geometry->type == CURVES) { - numPrimitives += ((ISPCHairSet*)geometry)->numHairs; - } - else - assert(false); - } - return numPrimitives; - } - - size_t getNumObjects(ISPCScene* scene_in) - { - return scene_in->numGeometries; - } - - void updateObjects(ISPCScene* scene_in, RTCScene scene_out) - { - size_t numGeometries = scene_in->numGeometries; - for (size_t i=0; igeometries[i]; - if (geometry->type == SUBDIV_MESH) { - rtcUpdate(scene_out,((ISPCSubdivMesh*)geometry)->geomID); - } - else if (geometry->type == TRIANGLE_MESH) { - rtcUpdate(scene_out,((ISPCTriangleMesh*)geometry)->geomID); - } - else if (geometry->type == QUAD_MESH) { - rtcUpdate(scene_out,((ISPCQuadMesh*)geometry)->geomID); - } - else if (geometry->type == LINE_SEGMENTS) { - rtcUpdate(scene_out,((ISPCLineSegments*)geometry)->geomID); - } - else if (geometry->type == HAIR_SET) { - rtcUpdate(scene_out,((ISPCHairSet*)geometry)->geomID); - } - else if (geometry->type == CURVES) { - rtcUpdate(scene_out,((ISPCHairSet*)geometry)->geomID); - } - else - assert(false); - } - } - - void deleteObjects(ISPCScene* scene_in, RTCScene scene_out) - { - size_t numGeometries = scene_in->numGeometries; - for (size_t i=0; igeometries[i]; - if (geometry->type == SUBDIV_MESH) { - rtcDeleteGeometry(scene_out,((ISPCSubdivMesh*)geometry)->geomID); - } - else if (geometry->type == TRIANGLE_MESH) { - rtcDeleteGeometry(scene_out,((ISPCTriangleMesh*)geometry)->geomID); - } - else if (geometry->type == QUAD_MESH) { - rtcDeleteGeometry(scene_out,((ISPCQuadMesh*)geometry)->geomID); - } - else if (geometry->type == LINE_SEGMENTS) { - rtcDeleteGeometry(scene_out,((ISPCLineSegments*)geometry)->geomID); - } - else if (geometry->type == HAIR_SET) { - rtcDeleteGeometry(scene_out,((ISPCHairSet*)geometry)->geomID); - } - else if (geometry->type == CURVES) { - rtcDeleteGeometry(scene_out,((ISPCHairSet*)geometry)->geomID); - } - else - assert(false); - } - } - - void Benchmark_Dynamic_Update(ISPCScene* scene_in, size_t benchmark_iterations, RTCGeometryFlags gflags = RTC_GEOMETRY_DYNAMIC) - { - assert(g_scene == nullptr); - g_scene = createScene(RTC_SCENE_DYNAMIC); - convertScene(g_scene, scene_in, gflags); - size_t primitives = getNumPrimitives(scene_in); - size_t objects = getNumObjects(scene_in); - size_t iterations = 0; - double time = 0.0; - for(size_t i=0;i= skip_iterations) - { - time += t1 - t0; - iterations++; - } - } - - if (gflags == RTC_GEOMETRY_DYNAMIC) - std::cout << "Update dynamic scene, dynamic geometry "; - else if (gflags == RTC_GEOMETRY_STATIC) - std::cout << "Update dynamic scene, static geometry "; - else if (gflags == RTC_GEOMETRY_DEFORMABLE) - std::cout << "Update dynamic scene, deformable geometry "; - else - FATAL("unknown flags"); - - std::cout << "(" << primitives << " primitives, " << objects << " objects) : " - << " avg. time = " << time/iterations - << " , avg. build perf " << 1.0 / (time/iterations) * primitives / 1000000.0 << " Mprims/s" << std::endl; - - rtcDeleteScene (g_scene); - g_scene = nullptr; - } - - void Benchmark_Dynamic_Create(ISPCScene* scene_in, size_t benchmark_iterations, RTCGeometryFlags gflags = RTC_GEOMETRY_STATIC) - { - assert(g_scene == nullptr); - g_scene = createScene(RTC_SCENE_DYNAMIC); - convertScene(g_scene, scene_in,gflags); - size_t primitives = getNumPrimitives(scene_in); - size_t objects = getNumObjects(scene_in); - size_t iterations = 0; - double time = 0.0; - for(size_t i=0;i= skip_iterations) - { - time += t1 - t0; - iterations++; - } - } - if (gflags == RTC_GEOMETRY_STATIC) - std::cout << "Create dynamic scene, static geometry "; - else if (gflags == RTC_GEOMETRY_DYNAMIC) - std::cout << "Create dynamic scene, dynamic geometry "; - else if (gflags == RTC_GEOMETRY_DEFORMABLE) - std::cout << "Create dynamic scene, deformable geometry "; - else - FATAL("unknown flags"); - - std::cout << "(" << primitives << " primitives, " << objects << " objects) : " - << " avg. time = " << time/iterations - << " , avg. build perf " << 1.0 / (time/iterations) * primitives / 1000000.0 << " Mprims/s" << std::endl; - - rtcDeleteScene (g_scene); - g_scene = nullptr; - } - - void Benchmark_Static_Create(ISPCScene* scene_in, size_t benchmark_iterations, RTCGeometryFlags gflags = RTC_GEOMETRY_STATIC, RTCSceneFlags sflags = RTC_SCENE_STATIC) - { - assert(g_scene == nullptr); - size_t primitives = getNumPrimitives(scene_in); - size_t objects = getNumObjects(scene_in); - size_t iterations = 0; - double time = 0.0; - for(size_t i=0;i= skip_iterations) - { - time += t1 - t0; - iterations++; - } - rtcDeleteScene (g_scene); - } - - if (sflags & RTC_SCENE_HIGH_QUALITY) - std::cout << "Create static (HQ) scene, "; - else - std::cout << "Create static scene, "; - - if (gflags == RTC_GEOMETRY_STATIC) - std::cout << "static geometry "; - else if (gflags == RTC_GEOMETRY_DYNAMIC) - std::cout << "dynamic geometry "; - else if (gflags == RTC_GEOMETRY_DEFORMABLE) - std::cout << "deformable geometry "; - else - FATAL("unknown flags"); - - std::cout << "(" << primitives << " primitives, " << objects << " objects) : " - << " avg. time = " << time/iterations - << " , avg. build perf " << 1.0 / (time/iterations) * primitives / 1000000.0 << " Mprims/s" << std::endl; - - g_scene = nullptr; - } - - void Pause() - { - std::cout << "sleeping..." << std::flush; - sleepSeconds(3); - std::cout << "done" << std::endl; - } - - - /* called by the C++ code for initialization */ - extern "C" void device_init (char* cfg) - { - std::string init("start_threads=1,affinity=1"); - if (cfg) - { - init += ","; - init += cfg; - } - /* create new Embree device */ - g_device = rtcNewDevice(init.c_str()); - error_handler(rtcDeviceGetError(g_device)); - - /* set error handler */ - rtcDeviceSetErrorFunction(g_device,error_handler); - Benchmark_Dynamic_Update(g_ispc_scene,iterations_dynamic_dynamic,RTC_GEOMETRY_DEFORMABLE); - Pause(); - Benchmark_Dynamic_Update(g_ispc_scene,iterations_dynamic_dynamic,RTC_GEOMETRY_DYNAMIC); - Pause(); - Benchmark_Dynamic_Update(g_ispc_scene,iterations_dynamic_static ,RTC_GEOMETRY_STATIC); - Pause(); - Benchmark_Dynamic_Create(g_ispc_scene,iterations_dynamic_dynamic,RTC_GEOMETRY_DEFORMABLE); - Pause(); - Benchmark_Dynamic_Create(g_ispc_scene,iterations_dynamic_dynamic,RTC_GEOMETRY_DYNAMIC); - Pause(); - Benchmark_Dynamic_Create(g_ispc_scene,iterations_dynamic_static ,RTC_GEOMETRY_STATIC); - Pause(); - Benchmark_Static_Create(g_ispc_scene,iterations_static_static,RTC_GEOMETRY_STATIC,RTC_SCENE_STATIC); - Pause(); - Benchmark_Static_Create(g_ispc_scene,iterations_static_static,RTC_GEOMETRY_STATIC,RTC_SCENE_HIGH_QUALITY); - - rtcDeleteDevice(g_device); g_device = nullptr; - } - -/* called by the C++ code to render */ - extern "C" void device_render (int* pixels, - const unsigned int width, - const unsigned int height, - const float time, - const ISPCCamera& camera) - { - } - -/* renders a single screen tile */ - void renderTileStandard(int taskIndex, - int* pixels, - const unsigned int width, - const unsigned int height, - const float time, - const ISPCCamera& camera, - const int numTilesX, - const int numTilesY) - { - } - -/* called by the C++ code for cleanup */ - extern "C" void device_cleanup () - { - } - -} // namespace embree diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/bvh_access/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/bvh_access/CMakeLists.txt deleted file mode 100644 index b299f64fb274..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/bvh_access/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2017 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -ADD_EXECUTABLE(bvh_access bvh_access.cpp) -TARGET_LINK_LIBRARIES(bvh_access embree) -SET_PROPERTY(TARGET bvh_access PROPERTY FOLDER tutorials/single) -INSTALL(TARGETS bvh_access DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT examples) -ADD_TEST(NAME bvh_access COMMAND bvh_access) diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/bvh_access/bvh_access.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/bvh_access/bvh_access.cpp deleted file mode 100644 index 5c0c420a1066..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/bvh_access/bvh_access.cpp +++ /dev/null @@ -1,263 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial.h" -#include "../common/tutorial/tutorial_device.h" -#include "../../include/embree2/rtcore.h" -#include "../../kernels/bvh/bvh.h" -#include "../../kernels/geometry/trianglev.h" - -namespace embree -{ - /* error reporting function */ - void error_handler(const RTCError code, const char* str) - { - if (code == RTC_NO_ERROR) - return; - - printf("Embree: "); - switch (code) { - case RTC_UNKNOWN_ERROR : printf("RTC_UNKNOWN_ERROR"); break; - case RTC_INVALID_ARGUMENT : printf("RTC_INVALID_ARGUMENT"); break; - case RTC_INVALID_OPERATION: printf("RTC_INVALID_OPERATION"); break; - case RTC_OUT_OF_MEMORY : printf("RTC_OUT_OF_MEMORY"); break; - case RTC_UNSUPPORTED_CPU : printf("RTC_UNSUPPORTED_CPU"); break; - case RTC_CANCELLED : printf("RTC_CANCELLED"); break; - default : printf("invalid error code"); break; - } - if (str) { - printf(" ("); - while (*str) putchar(*str++); - printf(")\n"); - } - exit(1); - } - - /* adds a cube to the scene */ - unsigned int addCube (RTCScene scene_i, const Vec3fa& pos) - { - /* create a triangulated cube with 12 triangles and 8 vertices */ - unsigned int mesh = rtcNewTriangleMesh (scene_i, RTC_GEOMETRY_STATIC, 12, 8); - - /* set vertices */ - Vec3fa* vertices = (Vec3fa*) rtcMapBuffer(scene_i,mesh,RTC_VERTEX_BUFFER); - vertices[0].x = pos.x + -1; vertices[0].y = pos.y + -1; vertices[0].z = pos.z + -1; - vertices[1].x = pos.x + -1; vertices[1].y = pos.y + -1; vertices[1].z = pos.z + +1; - vertices[2].x = pos.x + -1; vertices[2].y = pos.y + +1; vertices[2].z = pos.z + -1; - vertices[3].x = pos.x + -1; vertices[3].y = pos.y + +1; vertices[3].z = pos.z + +1; - vertices[4].x = pos.x + +1; vertices[4].y = pos.y + -1; vertices[4].z = pos.z + -1; - vertices[5].x = pos.x + +1; vertices[5].y = pos.y + -1; vertices[5].z = pos.z + +1; - vertices[6].x = pos.x + +1; vertices[6].y = pos.y + +1; vertices[6].z = pos.z + -1; - vertices[7].x = pos.x + +1; vertices[7].y = pos.y + +1; vertices[7].z = pos.z + +1; - rtcUnmapBuffer(scene_i,mesh,RTC_VERTEX_BUFFER); - - /* set triangles */ - int tri = 0; - Triangle* triangles = (Triangle*) rtcMapBuffer(scene_i,mesh,RTC_INDEX_BUFFER); - - // left side - triangles[tri].v0 = 0; triangles[tri].v1 = 2; triangles[tri].v2 = 1; tri++; - triangles[tri].v0 = 1; triangles[tri].v1 = 2; triangles[tri].v2 = 3; tri++; - - // right side - triangles[tri].v0 = 4; triangles[tri].v1 = 5; triangles[tri].v2 = 6; tri++; - triangles[tri].v0 = 5; triangles[tri].v1 = 7; triangles[tri].v2 = 6; tri++; - - // bottom side - triangles[tri].v0 = 0; triangles[tri].v1 = 1; triangles[tri].v2 = 4; tri++; - triangles[tri].v0 = 1; triangles[tri].v1 = 5; triangles[tri].v2 = 4; tri++; - - // top side - triangles[tri].v0 = 2; triangles[tri].v1 = 6; triangles[tri].v2 = 3; tri++; - triangles[tri].v0 = 3; triangles[tri].v1 = 6; triangles[tri].v2 = 7; tri++; - - // front side - triangles[tri].v0 = 0; triangles[tri].v1 = 4; triangles[tri].v2 = 2; tri++; - triangles[tri].v0 = 2; triangles[tri].v1 = 4; triangles[tri].v2 = 6; tri++; - - // back side - triangles[tri].v0 = 1; triangles[tri].v1 = 3; triangles[tri].v2 = 5; tri++; - triangles[tri].v0 = 3; triangles[tri].v1 = 7; triangles[tri].v2 = 5; tri++; - - rtcUnmapBuffer(scene_i,mesh,RTC_INDEX_BUFFER); - - return mesh; - } - - /* adds a ground plane to the scene */ - unsigned int addGroundPlane (RTCScene scene_i) - { - /* create a triangulated plane with 2 triangles and 4 vertices */ - unsigned int mesh = rtcNewTriangleMesh (scene_i, RTC_GEOMETRY_STATIC, 2, 4); - - /* set vertices */ - Vec3fa* vertices = (Vec3fa*) rtcMapBuffer(scene_i,mesh,RTC_VERTEX_BUFFER); - vertices[0].x = -10; vertices[0].y = -2; vertices[0].z = -10; - vertices[1].x = -10; vertices[1].y = -2; vertices[1].z = +10; - vertices[2].x = +10; vertices[2].y = -2; vertices[2].z = -10; - vertices[3].x = +10; vertices[3].y = -2; vertices[3].z = +10; - rtcUnmapBuffer(scene_i,mesh,RTC_VERTEX_BUFFER); - - /* set triangles */ - Triangle* triangles = (Triangle*) rtcMapBuffer(scene_i,mesh,RTC_INDEX_BUFFER); - triangles[0].v0 = 0; triangles[0].v1 = 2; triangles[0].v2 = 1; - triangles[1].v0 = 1; triangles[1].v1 = 2; triangles[1].v2 = 3; - rtcUnmapBuffer(scene_i,mesh,RTC_INDEX_BUFFER); - - return mesh; - } - - /* adds a hair to the scene */ - unsigned int addHair(RTCScene scene_i) - { - unsigned int geomID = rtcNewHairGeometry (scene_i, RTC_GEOMETRY_STATIC, 1, 4, 1); - - vfloat4* pos = (vfloat4*) rtcMapBuffer(scene_i,geomID,RTC_VERTEX_BUFFER); - pos[0] = vfloat4(0.0f,0.0f,0.0f,0.1f); - pos[1] = vfloat4(0.0f,1.0f,0.0f,0.1f); - pos[2] = vfloat4(0.0f,2.0f,0.0f,0.1f); - pos[3] = vfloat4(0.0f,3.0f,0.0f,0.1f); - rtcUnmapBuffer(scene_i,geomID,RTC_VERTEX_BUFFER); - - int* index = (int*) rtcMapBuffer(scene_i,geomID,RTC_INDEX_BUFFER); - index[0] = 0; - rtcUnmapBuffer(scene_i,geomID,RTC_INDEX_BUFFER); - - return geomID; - } - - /* prints the bvh4.triangle4v data structure */ - void print_bvh4_triangle4v(BVH4::NodeRef node, size_t depth) - { - if (node.isAlignedNode()) - { - BVH4::AlignedNode* n = node.alignedNode(); - - std::cout << "AlignedNode {" << std::endl; - for (size_t i=0; i<4; i++) - { - for (size_t k=0; kintersectors.ptr; - if (accel->type == AccelData::TY_BVH4) - bvh4 = (BVH4*)accel; - - /* if there are also other geometry types, one has to iterate over the toplevel AccelN structure */ - else if (accel->type == AccelData::TY_ACCELN) - { - AccelN* accelN = (AccelN*)(accel); - for (size_t i=0; iaccels.size(); i++) { - if (accelN->accels[i]->intersectors.ptr->type == AccelData::TY_BVH4) { - bvh4 = (BVH4*)accelN->accels[i]->intersectors.ptr; - if (bvh4->primTy.name == "triangle4v") break; - bvh4 = nullptr; - } - } - } - if (bvh4 == nullptr) - throw std::runtime_error("cannot access BVH4 acceleration structure"); // will not happen if you use this Embree version - - /* now lets print the entire hierarchy */ - print_bvh4_triangle4v(bvh4->root,0); - } - - /* main function in embree namespace */ - int main(int argc, char** argv) - { - /* for best performance set FTZ and DAZ flags in MXCSR control and status register */ - _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); - _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); - - /* create new Embree device and force bvh4.triangle4v hierarchy for triangles */ - RTCDevice device = rtcNewDevice("tri_accel=bvh4.triangle4v"); - error_handler(rtcDeviceGetError(device)); - - /* set error handler */ - rtcDeviceSetErrorFunction(device,error_handler); - - /* create scene */ - RTCScene scene = rtcDeviceNewScene(device,RTC_SCENE_STATIC,RTC_INTERSECT1); - addCube(scene,Vec3fa(-1,0,0)); - addCube(scene,Vec3fa(1,0,0)); - addCube(scene,Vec3fa(0,0,-1)); - addCube(scene,Vec3fa(0,0,1)); - addHair(scene); - addGroundPlane(scene); - rtcCommit (scene); - /* print triangle BVH */ - print_bvh(scene); - - /* cleanup */ - rtcDeleteScene (scene); - rtcDeleteDevice(device); - return 0; - } -} - -int main(int argc, char** argv) -{ - try { - return embree::main(argc, argv); - } - catch (const std::exception& e) { - std::cout << "Error: " << e.what() << std::endl; - return 1; - } - catch (...) { - std::cout << "Error: unknown exception caught." << std::endl; - return 1; - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/bvh_builder/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/bvh_builder/CMakeLists.txt deleted file mode 100644 index 61f61bf8192a..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/bvh_builder/CMakeLists.txt +++ /dev/null @@ -1,25 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2017 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -SET(EMBREE_ISPC_SUPPORT OFF) - -IF (TASKING_TBB) - SET(ADDITIONAL_LIBRARIES ${TBB_LIBRARIES}) -ENDIF() - -INCLUDE(tutorial) -ADD_TUTORIAL(bvh_builder) -ADD_TEST(NAME bvh_builder COMMAND bvh_builder) diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/bvh_builder/bvh_builder.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/bvh_builder/bvh_builder.cpp deleted file mode 100644 index 294144abb906..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/bvh_builder/bvh_builder.cpp +++ /dev/null @@ -1,34 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial.h" - -namespace embree -{ - struct Tutorial : public TutorialApplication - { - Tutorial() - : TutorialApplication("bvh_builder",FEATURE_RTCORE) - { - interactive = false; - } - }; - -} - -int main(int argc, char** argv) { - return embree::Tutorial().main(argc,argv); -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/bvh_builder/bvh_builder_device.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/bvh_builder/bvh_builder_device.cpp deleted file mode 100644 index d370ddcc2c85..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/bvh_builder/bvh_builder_device.cpp +++ /dev/null @@ -1,276 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial_device.h" -#include "../../kernels/common/alloc.h" -#include "../../kernels/builders/bvh_builder_sah.h" -#include "../../kernels/builders/bvh_builder_morton.h" - -namespace embree -{ - RTCDevice g_device = nullptr; - RTCScene g_scene = nullptr; - - /* This function is called by the builder to signal progress and to - * report memory consumption. */ - void memoryMonitor(ssize_t bytes, bool post) - { - // throw an exception here when nprims>0 to cancel the build operation - } - - struct Node - { - virtual float sah() = 0; - }; - - struct InnerNode : public Node - { - BBox3fa bounds[2]; - Node* children[2]; - - InnerNode() { - bounds[0] = bounds[1] = empty; - children[0] = children[1] = nullptr; - } - - float sah() { - return 1.0f + (area(bounds[0])*children[0]->sah() + area(bounds[1])*children[1]->sah())/area(merge(bounds[0],bounds[1])); - } - }; - - struct LeafNode : public Node - { - size_t id; - BBox3fa bounds; - - LeafNode (size_t id, const BBox3fa& bounds) - : id(id), bounds(bounds) {} - - float sah() { - return 1.0f; - } - }; - - void build_sah(avector& prims, isa::PrimInfo& pinfo) - { - size_t N = pinfo.size(); - - /* fast allocator that supports thread local operation */ - FastAllocator allocator(nullptr,false); - - for (size_t i=0; i<2; i++) - { - std::cout << "iteration " << i << ": building BVH over " << N << " primitives, " << std::flush; - double t0 = getSeconds(); - - allocator.reset(); - allocator.init(N); - - Node* root; - isa::BVHBuilderBinnedSAH::build( - root, - /* thread local allocator for fast allocations */ - [&] () -> FastAllocator::ThreadLocal* { - return allocator.threadLocal(); - }, - - /* lambda function that creates BVH nodes */ - [&](const isa::BVHBuilderBinnedSAH::BuildRecord& current, isa::BVHBuilderBinnedSAH::BuildRecord* children, const size_t N, FastAllocator::ThreadLocal* alloc) -> int - { - assert(N <= 2); - InnerNode* node = new (alloc->malloc(sizeof(InnerNode))) InnerNode; - for (size_t i=0; ibounds[i] = children[i].pinfo.geomBounds; - children[i].parent = (size_t*) &node->children[i]; - } - *current.parent = (size_t) node; - return 0; - }, - - /* lambda function that creates BVH leaves */ - [&](const isa::BVHBuilderBinnedSAH::BuildRecord& current, FastAllocator::ThreadLocal* alloc) -> int - { - assert(current.prims.size() == 1); - Node* node = new (alloc->malloc(sizeof(LeafNode))) LeafNode(prims[current.prims.begin()].ID(),prims[current.prims.begin()].bounds()); - *current.parent = (size_t) node; - return 0; - }, - - /* progress monitor function */ - [&] (size_t dn) { - // throw an exception here to cancel the build operation - }, - - prims.data(),pinfo,2,1024,1,1,1,1.0f,1.0f,Builder::DEFAULT_SINGLE_THREAD_THRESHOLD); - - double t1 = getSeconds(); - - std::cout << 1000.0f*(t1-t0) << "ms, " << 1E-6*double(N)/(t1-t0) << " Mprims/s, sah = " << root->sah() << " [DONE]" << std::endl; - } - } - - void build_morton(avector& prims, isa::PrimInfo& pinfo) - { - unsigned N = unsigned(pinfo.size()); - /* array for morton builder */ - avector morton_src(N); - avector morton_tmp(N); - for (unsigned i=0; i node_bounds = isa::bvh_builder_morton( - - /* thread local allocator for fast allocations */ - [&] () -> FastAllocator::ThreadLocal* { - return allocator.threadLocal(); - }, - - BBox3fa(empty), - - /* lambda function that allocates BVH nodes */ - [&] ( isa::MortonBuildRecord& current, isa::MortonBuildRecord* children, size_t N, FastAllocator::ThreadLocal* alloc ) -> InnerNode* - { - assert(N <= 2); - InnerNode* node = new (alloc->malloc(sizeof(InnerNode))) InnerNode; - *current.parent = node; - for (size_t i=0; ichildren[i]; - return node; - }, - - /* lambda function that sets bounds */ - [&] (InnerNode* node, const BBox3fa* bounds, size_t N) -> BBox3fa - { - BBox3fa res = empty; - for (size_t i=0; ibounds[i] = b; - } - return res; - }, - - /* lambda function that creates BVH leaves */ - [&]( isa::MortonBuildRecord& current, FastAllocator::ThreadLocal* alloc, BBox3fa& box_o) -> Node* - { - assert(current.size() == 1); - const size_t id = morton_src[current.begin].index; - const BBox3fa bounds = prims[id].bounds(); - Node* node = new (alloc->malloc(sizeof(LeafNode))) LeafNode(id,bounds); - *current.parent = node; - box_o = bounds; - return node; - }, - - /* lambda that calculates the bounds for some primitive */ - [&] (const isa::MortonID32Bit& morton) -> BBox3fa { - return prims[morton.index].bounds(); - }, - - /* progress monitor function */ - [&] (size_t dn) { - // throw an exception here to cancel the build operation - }, - - morton_src.data(),morton_tmp.data(),prims.size(),2,1024,1,1,Builder::DEFAULT_SINGLE_THREAD_THRESHOLD); - - Node* root = node_bounds.first; - - double t1 = getSeconds(); - - std::cout << 1000.0f*(t1-t0) << "ms, " << 1E-6*double(N)/(t1-t0) << " Mprims/s, sah = " << root->sah() << " [DONE]" << std::endl; - } - } - - /* called by the C++ code for initialization */ - extern "C" void device_init (char* cfg) - { - /* create new Embree device */ - g_device = rtcNewDevice(cfg); - error_handler(rtcDeviceGetError(g_device)); - - /* set error handler */ - rtcDeviceSetErrorFunction(g_device,error_handler); - - /* set start render mode */ - renderTile = renderTileStandard; - - /* create random bounding boxes */ - const size_t N = 2300000; - isa::PrimInfo pinfo(empty); - avector prims; - for (size_t i=0; i -#include -#include -#include -#include - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/freeglut/LICENSE.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/freeglut/LICENSE.txt deleted file mode 100644 index fc36ad99039d..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/freeglut/LICENSE.txt +++ /dev/null @@ -1,27 +0,0 @@ - - Freeglut Copyright - ------------------ - - Freeglut code without an explicit copyright is covered by the following - copyright: - - Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies or substantial portions of the Software. - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Pawel W. Olszta shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Pawel W. Olszta. diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/freeglut/include/GL/freeglut.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/freeglut/include/GL/freeglut.h deleted file mode 100644 index 0e6f8c6ad86d..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/freeglut/include/GL/freeglut.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef __FREEGLUT_H__ -#define __FREEGLUT_H__ - -/* - * freeglut.h - * - * The freeglut library include file - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "freeglut_std.h" -#include "freeglut_ext.h" - -/*** END OF FILE ***/ - -#endif /* __FREEGLUT_H__ */ diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/freeglut/include/GL/freeglut_ext.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/freeglut/include/GL/freeglut_ext.h deleted file mode 100644 index e547c56d8484..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/freeglut/include/GL/freeglut_ext.h +++ /dev/null @@ -1,239 +0,0 @@ -#ifndef __FREEGLUT_EXT_H__ -#define __FREEGLUT_EXT_H__ - -/* - * freeglut_ext.h - * - * The non-GLUT-compatible extensions to the freeglut library include file - * - * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. - * Written by Pawel W. Olszta, - * Creation date: Thu Dec 2 1999 - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifdef __cplusplus - extern "C" { -#endif - -/* - * Additional GLUT Key definitions for the Special key function - */ -#define GLUT_KEY_NUM_LOCK 0x006D -#define GLUT_KEY_BEGIN 0x006E -#define GLUT_KEY_DELETE 0x006F -#define GLUT_KEY_SHIFT_L 0x0070 -#define GLUT_KEY_SHIFT_R 0x0071 -#define GLUT_KEY_CTRL_L 0x0072 -#define GLUT_KEY_CTRL_R 0x0073 -#define GLUT_KEY_ALT_L 0x0074 -#define GLUT_KEY_ALT_R 0x0075 - -/* - * GLUT API Extension macro definitions -- behaviour when the user clicks on an "x" to close a window - */ -#define GLUT_ACTION_EXIT 0 -#define GLUT_ACTION_GLUTMAINLOOP_RETURNS 1 -#define GLUT_ACTION_CONTINUE_EXECUTION 2 - -/* - * Create a new rendering context when the user opens a new window? - */ -#define GLUT_CREATE_NEW_CONTEXT 0 -#define GLUT_USE_CURRENT_CONTEXT 1 - -/* - * Direct/Indirect rendering context options (has meaning only in Unix/X11) - */ -#define GLUT_FORCE_INDIRECT_CONTEXT 0 -#define GLUT_ALLOW_DIRECT_CONTEXT 1 -#define GLUT_TRY_DIRECT_CONTEXT 2 -#define GLUT_FORCE_DIRECT_CONTEXT 3 - -/* - * GLUT API Extension macro definitions -- the glutGet parameters - */ -#define GLUT_INIT_STATE 0x007C - -#define GLUT_ACTION_ON_WINDOW_CLOSE 0x01F9 - -#define GLUT_WINDOW_BORDER_WIDTH 0x01FA -#define GLUT_WINDOW_BORDER_HEIGHT 0x01FB -#define GLUT_WINDOW_HEADER_HEIGHT 0x01FB /* Docs say it should always have been GLUT_WINDOW_BORDER_HEIGHT, keep this for backward compatibility */ - -#define GLUT_VERSION 0x01FC - -#define GLUT_RENDERING_CONTEXT 0x01FD -#define GLUT_DIRECT_RENDERING 0x01FE - -#define GLUT_FULL_SCREEN 0x01FF - -#define GLUT_SKIP_STALE_MOTION_EVENTS 0x0204 - -/* - * New tokens for glutInitDisplayMode. - * Only one GLUT_AUXn bit may be used at a time. - * Value 0x0400 is defined in OpenGLUT. - */ -#define GLUT_AUX 0x1000 - -#define GLUT_AUX1 0x1000 -#define GLUT_AUX2 0x2000 -#define GLUT_AUX3 0x4000 -#define GLUT_AUX4 0x8000 - -/* - * Context-related flags, see freeglut_state.c - */ -#define GLUT_INIT_MAJOR_VERSION 0x0200 -#define GLUT_INIT_MINOR_VERSION 0x0201 -#define GLUT_INIT_FLAGS 0x0202 -#define GLUT_INIT_PROFILE 0x0203 - -/* - * Flags for glutInitContextFlags, see freeglut_init.c - */ -#define GLUT_DEBUG 0x0001 -#define GLUT_FORWARD_COMPATIBLE 0x0002 - - -/* - * Flags for glutInitContextProfile, see freeglut_init.c - */ -#define GLUT_CORE_PROFILE 0x0001 -#define GLUT_COMPATIBILITY_PROFILE 0x0002 - -/* - * Process loop function, see freeglut_main.c - */ -FGAPI void FGAPIENTRY glutMainLoopEvent( void ); -FGAPI void FGAPIENTRY glutLeaveMainLoop( void ); -FGAPI void FGAPIENTRY glutExit ( void ); - -/* - * Window management functions, see freeglut_window.c - */ -FGAPI void FGAPIENTRY glutFullScreenToggle( void ); -FGAPI void FGAPIENTRY glutLeaveFullScreen( void ); - -/* - * Window-specific callback functions, see freeglut_callbacks.c - */ -FGAPI void FGAPIENTRY glutMouseWheelFunc( void (* callback)( int, int, int, int ) ); -FGAPI void FGAPIENTRY glutCloseFunc( void (* callback)( void ) ); -FGAPI void FGAPIENTRY glutWMCloseFunc( void (* callback)( void ) ); -/* A. Donev: Also a destruction callback for menus */ -FGAPI void FGAPIENTRY glutMenuDestroyFunc( void (* callback)( void ) ); - -/* - * State setting and retrieval functions, see freeglut_state.c - */ -FGAPI void FGAPIENTRY glutSetOption ( GLenum option_flag, int value ); -FGAPI int * FGAPIENTRY glutGetModeValues(GLenum mode, int * size); -/* A.Donev: User-data manipulation */ -FGAPI void* FGAPIENTRY glutGetWindowData( void ); -FGAPI void FGAPIENTRY glutSetWindowData(void* data); -FGAPI void* FGAPIENTRY glutGetMenuData( void ); -FGAPI void FGAPIENTRY glutSetMenuData(void* data); - -/* - * Font stuff, see freeglut_font.c - */ -FGAPI int FGAPIENTRY glutBitmapHeight( void* font ); -FGAPI GLfloat FGAPIENTRY glutStrokeHeight( void* font ); -FGAPI void FGAPIENTRY glutBitmapString( void* font, const unsigned char *string ); -FGAPI void FGAPIENTRY glutStrokeString( void* font, const unsigned char *string ); - -/* - * Geometry functions, see freeglut_geometry.c - */ -FGAPI void FGAPIENTRY glutWireRhombicDodecahedron( void ); -FGAPI void FGAPIENTRY glutSolidRhombicDodecahedron( void ); -FGAPI void FGAPIENTRY glutWireSierpinskiSponge ( int num_levels, GLdouble offset[3], GLdouble scale ); -FGAPI void FGAPIENTRY glutSolidSierpinskiSponge ( int num_levels, GLdouble offset[3], GLdouble scale ); -FGAPI void FGAPIENTRY glutWireCylinder( GLdouble radius, GLdouble height, GLint slices, GLint stacks); -FGAPI void FGAPIENTRY glutSolidCylinder( GLdouble radius, GLdouble height, GLint slices, GLint stacks); - -/* - * Extension functions, see freeglut_ext.c - */ -typedef void (*GLUTproc)(); -FGAPI GLUTproc FGAPIENTRY glutGetProcAddress( const char *procName ); - -/* - * Multi-touch/multi-pointer extensions - */ - -#define GLUT_HAS_MULTI 1 - -FGAPI void FGAPIENTRY glutMultiEntryFunc( void (* callback)( int, int ) ); -FGAPI void FGAPIENTRY glutMultiButtonFunc( void (* callback)( int, int, int, int, int ) ); -FGAPI void FGAPIENTRY glutMultiMotionFunc( void (* callback)( int, int, int ) ); -FGAPI void FGAPIENTRY glutMultiPassiveFunc( void (* callback)( int, int, int ) ); - -/* - * Joystick functions, see freeglut_joystick.c - */ -/* USE OF THESE FUNCTIONS IS DEPRECATED !!!!! */ -/* If you have a serious need for these functions in your application, please either - * contact the "freeglut" developer community at freeglut-developer@lists.sourceforge.net, - * switch to the OpenGLUT library, or else port your joystick functionality over to PLIB's - * "js" library. - */ -int glutJoystickGetNumAxes( int ident ); -int glutJoystickGetNumButtons( int ident ); -int glutJoystickNotWorking( int ident ); -float glutJoystickGetDeadBand( int ident, int axis ); -void glutJoystickSetDeadBand( int ident, int axis, float db ); -float glutJoystickGetSaturation( int ident, int axis ); -void glutJoystickSetSaturation( int ident, int axis, float st ); -void glutJoystickSetMinRange( int ident, float *axes ); -void glutJoystickSetMaxRange( int ident, float *axes ); -void glutJoystickSetCenter( int ident, float *axes ); -void glutJoystickGetMinRange( int ident, float *axes ); -void glutJoystickGetMaxRange( int ident, float *axes ); -void glutJoystickGetCenter( int ident, float *axes ); - -/* - * Initialization functions, see freeglut_init.c - */ -FGAPI void FGAPIENTRY glutInitContextVersion( int majorVersion, int minorVersion ); -FGAPI void FGAPIENTRY glutInitContextFlags( int flags ); -FGAPI void FGAPIENTRY glutInitContextProfile( int profile ); - -/* to get the typedef for va_list */ -#include - -FGAPI void FGAPIENTRY glutInitErrorFunc( void (* vError)( const char *fmt, va_list ap ) ); -FGAPI void FGAPIENTRY glutInitWarningFunc( void (* vWarning)( const char *fmt, va_list ap ) ); - -/* - * GLUT API macro definitions -- the display mode definitions - */ -#define GLUT_CAPTIONLESS 0x0400 -#define GLUT_BORDERLESS 0x0800 -#define GLUT_SRGB 0x1000 - -#ifdef __cplusplus - } -#endif - -/*** END OF FILE ***/ - -#endif /* __FREEGLUT_EXT_H__ */ diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/freeglut/include/GL/freeglut_std.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/freeglut/include/GL/freeglut_std.h deleted file mode 100644 index 2e41efd7c5e5..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/freeglut/include/GL/freeglut_std.h +++ /dev/null @@ -1,630 +0,0 @@ -#ifndef __FREEGLUT_STD_H__ -#define __FREEGLUT_STD_H__ - -/* - * freeglut_std.h - * - * The GLUT-compatible part of the freeglut library include file - * - * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. - * Written by Pawel W. Olszta, - * Creation date: Thu Dec 2 1999 - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifdef __cplusplus - extern "C" { -#endif - -/* - * Under windows, we have to differentiate between static and dynamic libraries - */ -#ifdef _WIN32 -/* #pragma may not be supported by some compilers. - * Discussion by FreeGLUT developers suggests that - * Visual C++ specific code involving pragmas may - * need to move to a separate header. 24th Dec 2003 - */ - -/* Define FREEGLUT_LIB_PRAGMAS to 1 to include library - * pragmas or to 0 to exclude library pragmas. - * The default behavior depends on the compiler/platform. - */ -# ifndef FREEGLUT_LIB_PRAGMAS -# if ( defined(_MSC_VER) || defined(__WATCOMC__) ) && !defined(_WIN32_WCE) -# define FREEGLUT_LIB_PRAGMAS 1 -# else -# define FREEGLUT_LIB_PRAGMAS 0 -# endif -# endif - -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN 1 -# endif -# ifndef NOMINMAX -# define NOMINMAX -# endif -# include - -/* Windows static library */ -# ifdef FREEGLUT_STATIC - -#error Static linking is not supported with this build. Please remove the FREEGLUT_STATIC preprocessor directive, or download the source code from http://freeglut.sf.net/ and build against that. - -/* Windows shared library (DLL) */ -# else - -# define FGAPIENTRY __stdcall -# if defined(FREEGLUT_EXPORTS) -# define FGAPI __declspec(dllexport) -# else -# define FGAPI __declspec(dllimport) - - /* Link with Win32 shared freeglut lib */ -# if FREEGLUT_LIB_PRAGMAS -# pragma comment (lib, "freeglut.lib") -# endif - -# endif - -# endif - -/* Drag in other Windows libraries as required by FreeGLUT */ -# if FREEGLUT_LIB_PRAGMAS -# pragma comment (lib, "glu32.lib") /* link OpenGL Utility lib */ -# pragma comment (lib, "opengl32.lib") /* link Microsoft OpenGL lib */ -# pragma comment (lib, "gdi32.lib") /* link Windows GDI lib */ -# pragma comment (lib, "winmm.lib") /* link Windows MultiMedia lib */ -# pragma comment (lib, "user32.lib") /* link Windows user lib */ -# endif - -#else - -/* Non-Windows definition of FGAPI and FGAPIENTRY */ -# define FGAPI -# define FGAPIENTRY - -#endif - -/* - * The freeglut and GLUT API versions - */ -#define FREEGLUT 1 -#define GLUT_API_VERSION 4 -#define GLUT_XLIB_IMPLEMENTATION 13 -/* Deprecated: - cf. http://sourceforge.net/mailarchive/forum.php?thread_name=CABcAi1hw7cr4xtigckaGXB5X8wddLfMcbA_rZ3NAuwMrX_zmsw%40mail.gmail.com&forum_name=freeglut-developer */ -#define FREEGLUT_VERSION_2_0 1 - -/* - * Always include OpenGL and GLU headers - */ -#if __APPLE__ -# include -# include -#else -# include -# include -#endif - -/* - * GLUT API macro definitions -- the special key codes: - */ -#define GLUT_KEY_F1 0x0001 -#define GLUT_KEY_F2 0x0002 -#define GLUT_KEY_F3 0x0003 -#define GLUT_KEY_F4 0x0004 -#define GLUT_KEY_F5 0x0005 -#define GLUT_KEY_F6 0x0006 -#define GLUT_KEY_F7 0x0007 -#define GLUT_KEY_F8 0x0008 -#define GLUT_KEY_F9 0x0009 -#define GLUT_KEY_F10 0x000A -#define GLUT_KEY_F11 0x000B -#define GLUT_KEY_F12 0x000C -#define GLUT_KEY_LEFT 0x0064 -#define GLUT_KEY_UP 0x0065 -#define GLUT_KEY_RIGHT 0x0066 -#define GLUT_KEY_DOWN 0x0067 -#define GLUT_KEY_PAGE_UP 0x0068 -#define GLUT_KEY_PAGE_DOWN 0x0069 -#define GLUT_KEY_HOME 0x006A -#define GLUT_KEY_END 0x006B -#define GLUT_KEY_INSERT 0x006C - -/* - * GLUT API macro definitions -- mouse state definitions - */ -#define GLUT_LEFT_BUTTON 0x0000 -#define GLUT_MIDDLE_BUTTON 0x0001 -#define GLUT_RIGHT_BUTTON 0x0002 -#define GLUT_DOWN 0x0000 -#define GLUT_UP 0x0001 -#define GLUT_LEFT 0x0000 -#define GLUT_ENTERED 0x0001 - -/* - * GLUT API macro definitions -- the display mode definitions - */ -#define GLUT_RGB 0x0000 -#define GLUT_RGBA 0x0000 -#define GLUT_INDEX 0x0001 -#define GLUT_SINGLE 0x0000 -#define GLUT_DOUBLE 0x0002 -#define GLUT_ACCUM 0x0004 -#define GLUT_ALPHA 0x0008 -#define GLUT_DEPTH 0x0010 -#define GLUT_STENCIL 0x0020 -#define GLUT_MULTISAMPLE 0x0080 -#define GLUT_STEREO 0x0100 -#define GLUT_LUMINANCE 0x0200 - -/* - * GLUT API macro definitions -- windows and menu related definitions - */ -#define GLUT_MENU_NOT_IN_USE 0x0000 -#define GLUT_MENU_IN_USE 0x0001 -#define GLUT_NOT_VISIBLE 0x0000 -#define GLUT_VISIBLE 0x0001 -#define GLUT_HIDDEN 0x0000 -#define GLUT_FULLY_RETAINED 0x0001 -#define GLUT_PARTIALLY_RETAINED 0x0002 -#define GLUT_FULLY_COVERED 0x0003 - -/* - * GLUT API macro definitions -- fonts definitions - * - * Steve Baker suggested to make it binary compatible with GLUT: - */ -#if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__WATCOMC__) -# define GLUT_STROKE_ROMAN ((void *)0x0000) -# define GLUT_STROKE_MONO_ROMAN ((void *)0x0001) -# define GLUT_BITMAP_9_BY_15 ((void *)0x0002) -# define GLUT_BITMAP_8_BY_13 ((void *)0x0003) -# define GLUT_BITMAP_TIMES_ROMAN_10 ((void *)0x0004) -# define GLUT_BITMAP_TIMES_ROMAN_24 ((void *)0x0005) -# define GLUT_BITMAP_HELVETICA_10 ((void *)0x0006) -# define GLUT_BITMAP_HELVETICA_12 ((void *)0x0007) -# define GLUT_BITMAP_HELVETICA_18 ((void *)0x0008) -#else - /* - * I don't really know if it's a good idea... But here it goes: - */ - extern void* glutStrokeRoman; - extern void* glutStrokeMonoRoman; - extern void* glutBitmap9By15; - extern void* glutBitmap8By13; - extern void* glutBitmapTimesRoman10; - extern void* glutBitmapTimesRoman24; - extern void* glutBitmapHelvetica10; - extern void* glutBitmapHelvetica12; - extern void* glutBitmapHelvetica18; - - /* - * Those pointers will be used by following definitions: - */ -# define GLUT_STROKE_ROMAN ((void *) &glutStrokeRoman) -# define GLUT_STROKE_MONO_ROMAN ((void *) &glutStrokeMonoRoman) -# define GLUT_BITMAP_9_BY_15 ((void *) &glutBitmap9By15) -# define GLUT_BITMAP_8_BY_13 ((void *) &glutBitmap8By13) -# define GLUT_BITMAP_TIMES_ROMAN_10 ((void *) &glutBitmapTimesRoman10) -# define GLUT_BITMAP_TIMES_ROMAN_24 ((void *) &glutBitmapTimesRoman24) -# define GLUT_BITMAP_HELVETICA_10 ((void *) &glutBitmapHelvetica10) -# define GLUT_BITMAP_HELVETICA_12 ((void *) &glutBitmapHelvetica12) -# define GLUT_BITMAP_HELVETICA_18 ((void *) &glutBitmapHelvetica18) -#endif - -/* - * GLUT API macro definitions -- the glutGet parameters - */ -#define GLUT_WINDOW_X 0x0064 -#define GLUT_WINDOW_Y 0x0065 -#define GLUT_WINDOW_WIDTH 0x0066 -#define GLUT_WINDOW_HEIGHT 0x0067 -#define GLUT_WINDOW_BUFFER_SIZE 0x0068 -#define GLUT_WINDOW_STENCIL_SIZE 0x0069 -#define GLUT_WINDOW_DEPTH_SIZE 0x006A -#define GLUT_WINDOW_RED_SIZE 0x006B -#define GLUT_WINDOW_GREEN_SIZE 0x006C -#define GLUT_WINDOW_BLUE_SIZE 0x006D -#define GLUT_WINDOW_ALPHA_SIZE 0x006E -#define GLUT_WINDOW_ACCUM_RED_SIZE 0x006F -#define GLUT_WINDOW_ACCUM_GREEN_SIZE 0x0070 -#define GLUT_WINDOW_ACCUM_BLUE_SIZE 0x0071 -#define GLUT_WINDOW_ACCUM_ALPHA_SIZE 0x0072 -#define GLUT_WINDOW_DOUBLEBUFFER 0x0073 -#define GLUT_WINDOW_RGBA 0x0074 -#define GLUT_WINDOW_PARENT 0x0075 -#define GLUT_WINDOW_NUM_CHILDREN 0x0076 -#define GLUT_WINDOW_COLORMAP_SIZE 0x0077 -#define GLUT_WINDOW_NUM_SAMPLES 0x0078 -#define GLUT_WINDOW_STEREO 0x0079 -#define GLUT_WINDOW_CURSOR 0x007A - -#define GLUT_SCREEN_WIDTH 0x00C8 -#define GLUT_SCREEN_HEIGHT 0x00C9 -#define GLUT_SCREEN_WIDTH_MM 0x00CA -#define GLUT_SCREEN_HEIGHT_MM 0x00CB -#define GLUT_MENU_NUM_ITEMS 0x012C -#define GLUT_DISPLAY_MODE_POSSIBLE 0x0190 -#define GLUT_INIT_WINDOW_X 0x01F4 -#define GLUT_INIT_WINDOW_Y 0x01F5 -#define GLUT_INIT_WINDOW_WIDTH 0x01F6 -#define GLUT_INIT_WINDOW_HEIGHT 0x01F7 -#define GLUT_INIT_DISPLAY_MODE 0x01F8 -#define GLUT_ELAPSED_TIME 0x02BC -#define GLUT_WINDOW_FORMAT_ID 0x007B - -/* - * GLUT API macro definitions -- the glutDeviceGet parameters - */ -#define GLUT_HAS_KEYBOARD 0x0258 -#define GLUT_HAS_MOUSE 0x0259 -#define GLUT_HAS_SPACEBALL 0x025A -#define GLUT_HAS_DIAL_AND_BUTTON_BOX 0x025B -#define GLUT_HAS_TABLET 0x025C -#define GLUT_NUM_MOUSE_BUTTONS 0x025D -#define GLUT_NUM_SPACEBALL_BUTTONS 0x025E -#define GLUT_NUM_BUTTON_BOX_BUTTONS 0x025F -#define GLUT_NUM_DIALS 0x0260 -#define GLUT_NUM_TABLET_BUTTONS 0x0261 -#define GLUT_DEVICE_IGNORE_KEY_REPEAT 0x0262 -#define GLUT_DEVICE_KEY_REPEAT 0x0263 -#define GLUT_HAS_JOYSTICK 0x0264 -#define GLUT_OWNS_JOYSTICK 0x0265 -#define GLUT_JOYSTICK_BUTTONS 0x0266 -#define GLUT_JOYSTICK_AXES 0x0267 -#define GLUT_JOYSTICK_POLL_RATE 0x0268 - -/* - * GLUT API macro definitions -- the glutLayerGet parameters - */ -#define GLUT_OVERLAY_POSSIBLE 0x0320 -#define GLUT_LAYER_IN_USE 0x0321 -#define GLUT_HAS_OVERLAY 0x0322 -#define GLUT_TRANSPARENT_INDEX 0x0323 -#define GLUT_NORMAL_DAMAGED 0x0324 -#define GLUT_OVERLAY_DAMAGED 0x0325 - -/* - * GLUT API macro definitions -- the glutVideoResizeGet parameters - */ -#define GLUT_VIDEO_RESIZE_POSSIBLE 0x0384 -#define GLUT_VIDEO_RESIZE_IN_USE 0x0385 -#define GLUT_VIDEO_RESIZE_X_DELTA 0x0386 -#define GLUT_VIDEO_RESIZE_Y_DELTA 0x0387 -#define GLUT_VIDEO_RESIZE_WIDTH_DELTA 0x0388 -#define GLUT_VIDEO_RESIZE_HEIGHT_DELTA 0x0389 -#define GLUT_VIDEO_RESIZE_X 0x038A -#define GLUT_VIDEO_RESIZE_Y 0x038B -#define GLUT_VIDEO_RESIZE_WIDTH 0x038C -#define GLUT_VIDEO_RESIZE_HEIGHT 0x038D - -/* - * GLUT API macro definitions -- the glutUseLayer parameters - */ -#define GLUT_NORMAL 0x0000 -#define GLUT_OVERLAY 0x0001 - -/* - * GLUT API macro definitions -- the glutGetModifiers parameters - */ -#define GLUT_ACTIVE_SHIFT 0x0001 -#define GLUT_ACTIVE_CTRL 0x0002 -#define GLUT_ACTIVE_ALT 0x0004 - -/* - * GLUT API macro definitions -- the glutSetCursor parameters - */ -#define GLUT_CURSOR_RIGHT_ARROW 0x0000 -#define GLUT_CURSOR_LEFT_ARROW 0x0001 -#define GLUT_CURSOR_INFO 0x0002 -#define GLUT_CURSOR_DESTROY 0x0003 -#define GLUT_CURSOR_HELP 0x0004 -#define GLUT_CURSOR_CYCLE 0x0005 -#define GLUT_CURSOR_SPRAY 0x0006 -#define GLUT_CURSOR_WAIT 0x0007 -#define GLUT_CURSOR_TEXT 0x0008 -#define GLUT_CURSOR_CROSSHAIR 0x0009 -#define GLUT_CURSOR_UP_DOWN 0x000A -#define GLUT_CURSOR_LEFT_RIGHT 0x000B -#define GLUT_CURSOR_TOP_SIDE 0x000C -#define GLUT_CURSOR_BOTTOM_SIDE 0x000D -#define GLUT_CURSOR_LEFT_SIDE 0x000E -#define GLUT_CURSOR_RIGHT_SIDE 0x000F -#define GLUT_CURSOR_TOP_LEFT_CORNER 0x0010 -#define GLUT_CURSOR_TOP_RIGHT_CORNER 0x0011 -#define GLUT_CURSOR_BOTTOM_RIGHT_CORNER 0x0012 -#define GLUT_CURSOR_BOTTOM_LEFT_CORNER 0x0013 -#define GLUT_CURSOR_INHERIT 0x0064 -#define GLUT_CURSOR_NONE 0x0065 -#define GLUT_CURSOR_FULL_CROSSHAIR 0x0066 - -/* - * GLUT API macro definitions -- RGB color component specification definitions - */ -#define GLUT_RED 0x0000 -#define GLUT_GREEN 0x0001 -#define GLUT_BLUE 0x0002 - -/* - * GLUT API macro definitions -- additional keyboard and joystick definitions - */ -#define GLUT_KEY_REPEAT_OFF 0x0000 -#define GLUT_KEY_REPEAT_ON 0x0001 -#define GLUT_KEY_REPEAT_DEFAULT 0x0002 - -#define GLUT_JOYSTICK_BUTTON_A 0x0001 -#define GLUT_JOYSTICK_BUTTON_B 0x0002 -#define GLUT_JOYSTICK_BUTTON_C 0x0004 -#define GLUT_JOYSTICK_BUTTON_D 0x0008 - -/* - * GLUT API macro definitions -- game mode definitions - */ -#define GLUT_GAME_MODE_ACTIVE 0x0000 -#define GLUT_GAME_MODE_POSSIBLE 0x0001 -#define GLUT_GAME_MODE_WIDTH 0x0002 -#define GLUT_GAME_MODE_HEIGHT 0x0003 -#define GLUT_GAME_MODE_PIXEL_DEPTH 0x0004 -#define GLUT_GAME_MODE_REFRESH_RATE 0x0005 -#define GLUT_GAME_MODE_DISPLAY_CHANGED 0x0006 - -/* - * Initialization functions, see fglut_init.c - */ -FGAPI void FGAPIENTRY glutInit( int* pargc, char** argv ); -FGAPI void FGAPIENTRY glutInitWindowPosition( int x, int y ); -FGAPI void FGAPIENTRY glutInitWindowSize( int width, int height ); -FGAPI void FGAPIENTRY glutInitDisplayMode( unsigned int displayMode ); -FGAPI void FGAPIENTRY glutInitDisplayString( const char* displayMode ); - -/* - * Process loop function, see freeglut_main.c - */ -FGAPI void FGAPIENTRY glutMainLoop( void ); - -/* - * Window management functions, see freeglut_window.c - */ -FGAPI int FGAPIENTRY glutCreateWindow( const char* title ); -FGAPI int FGAPIENTRY glutCreateSubWindow( int window, int x, int y, int width, int height ); -FGAPI void FGAPIENTRY glutDestroyWindow( int window ); -FGAPI void FGAPIENTRY glutSetWindow( int window ); -FGAPI int FGAPIENTRY glutGetWindow( void ); -FGAPI void FGAPIENTRY glutSetWindowTitle( const char* title ); -FGAPI void FGAPIENTRY glutSetIconTitle( const char* title ); -FGAPI void FGAPIENTRY glutReshapeWindow( int width, int height ); -FGAPI void FGAPIENTRY glutPositionWindow( int x, int y ); -FGAPI void FGAPIENTRY glutShowWindow( void ); -FGAPI void FGAPIENTRY glutHideWindow( void ); -FGAPI void FGAPIENTRY glutIconifyWindow( void ); -FGAPI void FGAPIENTRY glutPushWindow( void ); -FGAPI void FGAPIENTRY glutPopWindow( void ); -FGAPI void FGAPIENTRY glutFullScreen( void ); - -/* - * Display-connected functions, see freeglut_display.c - */ -FGAPI void FGAPIENTRY glutPostWindowRedisplay( int window ); -FGAPI void FGAPIENTRY glutPostRedisplay( void ); -FGAPI void FGAPIENTRY glutSwapBuffers( void ); - -/* - * Mouse cursor functions, see freeglut_cursor.c - */ -FGAPI void FGAPIENTRY glutWarpPointer( int x, int y ); -FGAPI void FGAPIENTRY glutSetCursor( int cursor ); - -/* - * Overlay stuff, see freeglut_overlay.c - */ -FGAPI void FGAPIENTRY glutEstablishOverlay( void ); -FGAPI void FGAPIENTRY glutRemoveOverlay( void ); -FGAPI void FGAPIENTRY glutUseLayer( GLenum layer ); -FGAPI void FGAPIENTRY glutPostOverlayRedisplay( void ); -FGAPI void FGAPIENTRY glutPostWindowOverlayRedisplay( int window ); -FGAPI void FGAPIENTRY glutShowOverlay( void ); -FGAPI void FGAPIENTRY glutHideOverlay( void ); - -/* - * Menu stuff, see freeglut_menu.c - */ -FGAPI int FGAPIENTRY glutCreateMenu( void (* callback)( int menu ) ); -FGAPI void FGAPIENTRY glutDestroyMenu( int menu ); -FGAPI int FGAPIENTRY glutGetMenu( void ); -FGAPI void FGAPIENTRY glutSetMenu( int menu ); -FGAPI void FGAPIENTRY glutAddMenuEntry( const char* label, int value ); -FGAPI void FGAPIENTRY glutAddSubMenu( const char* label, int subMenu ); -FGAPI void FGAPIENTRY glutChangeToMenuEntry( int item, const char* label, int value ); -FGAPI void FGAPIENTRY glutChangeToSubMenu( int item, const char* label, int value ); -FGAPI void FGAPIENTRY glutRemoveMenuItem( int item ); -FGAPI void FGAPIENTRY glutAttachMenu( int button ); -FGAPI void FGAPIENTRY glutDetachMenu( int button ); - -/* - * Global callback functions, see freeglut_callbacks.c - */ -FGAPI void FGAPIENTRY glutTimerFunc( unsigned int time, void (* callback)( int ), int value ); -FGAPI void FGAPIENTRY glutIdleFunc( void (* callback)( void ) ); - -/* - * Window-specific callback functions, see freeglut_callbacks.c - */ -FGAPI void FGAPIENTRY glutKeyboardFunc( void (* callback)( unsigned char, int, int ) ); -FGAPI void FGAPIENTRY glutSpecialFunc( void (* callback)( int, int, int ) ); -FGAPI void FGAPIENTRY glutReshapeFunc( void (* callback)( int, int ) ); -FGAPI void FGAPIENTRY glutVisibilityFunc( void (* callback)( int ) ); -FGAPI void FGAPIENTRY glutDisplayFunc( void (* callback)( void ) ); -FGAPI void FGAPIENTRY glutMouseFunc( void (* callback)( int, int, int, int ) ); -FGAPI void FGAPIENTRY glutMotionFunc( void (* callback)( int, int ) ); -FGAPI void FGAPIENTRY glutPassiveMotionFunc( void (* callback)( int, int ) ); -FGAPI void FGAPIENTRY glutEntryFunc( void (* callback)( int ) ); - -FGAPI void FGAPIENTRY glutKeyboardUpFunc( void (* callback)( unsigned char, int, int ) ); -FGAPI void FGAPIENTRY glutSpecialUpFunc( void (* callback)( int, int, int ) ); -FGAPI void FGAPIENTRY glutJoystickFunc( void (* callback)( unsigned int, int, int, int ), int pollInterval ); -FGAPI void FGAPIENTRY glutMenuStateFunc( void (* callback)( int ) ); -FGAPI void FGAPIENTRY glutMenuStatusFunc( void (* callback)( int, int, int ) ); -FGAPI void FGAPIENTRY glutOverlayDisplayFunc( void (* callback)( void ) ); -FGAPI void FGAPIENTRY glutWindowStatusFunc( void (* callback)( int ) ); - -FGAPI void FGAPIENTRY glutSpaceballMotionFunc( void (* callback)( int, int, int ) ); -FGAPI void FGAPIENTRY glutSpaceballRotateFunc( void (* callback)( int, int, int ) ); -FGAPI void FGAPIENTRY glutSpaceballButtonFunc( void (* callback)( int, int ) ); -FGAPI void FGAPIENTRY glutButtonBoxFunc( void (* callback)( int, int ) ); -FGAPI void FGAPIENTRY glutDialsFunc( void (* callback)( int, int ) ); -FGAPI void FGAPIENTRY glutTabletMotionFunc( void (* callback)( int, int ) ); -FGAPI void FGAPIENTRY glutTabletButtonFunc( void (* callback)( int, int, int, int ) ); - -/* - * State setting and retrieval functions, see freeglut_state.c - */ -FGAPI int FGAPIENTRY glutGet( GLenum query ); -FGAPI int FGAPIENTRY glutDeviceGet( GLenum query ); -FGAPI int FGAPIENTRY glutGetModifiers( void ); -FGAPI int FGAPIENTRY glutLayerGet( GLenum query ); - -/* - * Font stuff, see freeglut_font.c - */ -FGAPI void FGAPIENTRY glutBitmapCharacter( void* font, int character ); -FGAPI int FGAPIENTRY glutBitmapWidth( void* font, int character ); -FGAPI void FGAPIENTRY glutStrokeCharacter( void* font, int character ); -FGAPI int FGAPIENTRY glutStrokeWidth( void* font, int character ); -FGAPI int FGAPIENTRY glutBitmapLength( void* font, const unsigned char* string ); -FGAPI int FGAPIENTRY glutStrokeLength( void* font, const unsigned char* string ); - -/* - * Geometry functions, see freeglut_geometry.c - */ -FGAPI void FGAPIENTRY glutWireCube( GLdouble size ); -FGAPI void FGAPIENTRY glutSolidCube( GLdouble size ); -FGAPI void FGAPIENTRY glutWireSphere( GLdouble radius, GLint slices, GLint stacks ); -FGAPI void FGAPIENTRY glutSolidSphere( GLdouble radius, GLint slices, GLint stacks ); -FGAPI void FGAPIENTRY glutWireCone( GLdouble base, GLdouble height, GLint slices, GLint stacks ); -FGAPI void FGAPIENTRY glutSolidCone( GLdouble base, GLdouble height, GLint slices, GLint stacks ); - -FGAPI void FGAPIENTRY glutWireTorus( GLdouble innerRadius, GLdouble outerRadius, GLint sides, GLint rings ); -FGAPI void FGAPIENTRY glutSolidTorus( GLdouble innerRadius, GLdouble outerRadius, GLint sides, GLint rings ); -FGAPI void FGAPIENTRY glutWireDodecahedron( void ); -FGAPI void FGAPIENTRY glutSolidDodecahedron( void ); -FGAPI void FGAPIENTRY glutWireOctahedron( void ); -FGAPI void FGAPIENTRY glutSolidOctahedron( void ); -FGAPI void FGAPIENTRY glutWireTetrahedron( void ); -FGAPI void FGAPIENTRY glutSolidTetrahedron( void ); -FGAPI void FGAPIENTRY glutWireIcosahedron( void ); -FGAPI void FGAPIENTRY glutSolidIcosahedron( void ); - -/* - * Teapot rendering functions, found in freeglut_teapot.c - * NB: front facing polygons have clockwise winding, not counter clockwise - */ -FGAPI void FGAPIENTRY glutWireTeapot( GLdouble size ); -FGAPI void FGAPIENTRY glutSolidTeapot( GLdouble size ); - -/* - * Game mode functions, see freeglut_gamemode.c - */ -FGAPI void FGAPIENTRY glutGameModeString( const char* string ); -FGAPI int FGAPIENTRY glutEnterGameMode( void ); -FGAPI void FGAPIENTRY glutLeaveGameMode( void ); -FGAPI int FGAPIENTRY glutGameModeGet( GLenum query ); - -/* - * Video resize functions, see freeglut_videoresize.c - */ -FGAPI int FGAPIENTRY glutVideoResizeGet( GLenum query ); -FGAPI void FGAPIENTRY glutSetupVideoResizing( void ); -FGAPI void FGAPIENTRY glutStopVideoResizing( void ); -FGAPI void FGAPIENTRY glutVideoResize( int x, int y, int width, int height ); -FGAPI void FGAPIENTRY glutVideoPan( int x, int y, int width, int height ); - -/* - * Colormap functions, see freeglut_misc.c - */ -FGAPI void FGAPIENTRY glutSetColor( int color, GLfloat red, GLfloat green, GLfloat blue ); -FGAPI GLfloat FGAPIENTRY glutGetColor( int color, int component ); -FGAPI void FGAPIENTRY glutCopyColormap( int window ); - -/* - * Misc keyboard and joystick functions, see freeglut_misc.c - */ -FGAPI void FGAPIENTRY glutIgnoreKeyRepeat( int ignore ); -FGAPI void FGAPIENTRY glutSetKeyRepeat( int repeatMode ); -FGAPI void FGAPIENTRY glutForceJoystickFunc( void ); - -/* - * Misc functions, see freeglut_misc.c - */ -FGAPI int FGAPIENTRY glutExtensionSupported( const char* extension ); -FGAPI void FGAPIENTRY glutReportErrors( void ); - -/* Comment from glut.h of classic GLUT: - - Win32 has an annoying issue where there are multiple C run-time - libraries (CRTs). If the executable is linked with a different CRT - from the GLUT DLL, the GLUT DLL will not share the same CRT static - data seen by the executable. In particular, atexit callbacks registered - in the executable will not be called if GLUT calls its (different) - exit routine). GLUT is typically built with the - "/MD" option (the CRT with multithreading DLL support), but the Visual - C++ linker default is "/ML" (the single threaded CRT). - - One workaround to this issue is requiring users to always link with - the same CRT as GLUT is compiled with. That requires users supply a - non-standard option. GLUT 3.7 has its own built-in workaround where - the executable's "exit" function pointer is covertly passed to GLUT. - GLUT then calls the executable's exit function pointer to ensure that - any "atexit" calls registered by the application are called if GLUT - needs to exit. - - Note that the __glut*WithExit routines should NEVER be called directly. - To avoid the atexit workaround, #define GLUT_DISABLE_ATEXIT_HACK. */ - -/* to get the prototype for exit() */ -#include - -#if defined(_WIN32) && !defined(GLUT_DISABLE_ATEXIT_HACK) && !defined(__WATCOMC__) -FGAPI void FGAPIENTRY __glutInitWithExit(int *argcp, char **argv, void (__cdecl *exitfunc)(int)); -FGAPI int FGAPIENTRY __glutCreateWindowWithExit(const char *title, void (__cdecl *exitfunc)(int)); -FGAPI int FGAPIENTRY __glutCreateMenuWithExit(void (* func)(int), void (__cdecl *exitfunc)(int)); -#ifndef FREEGLUT_BUILDING_LIB -#if defined(__GNUC__) -#define FGUNUSED __attribute__((unused)) -#else -#define FGUNUSED -#endif -static void FGAPIENTRY FGUNUSED glutInit_ATEXIT_HACK(int *argcp, char **argv) { __glutInitWithExit(argcp, argv, exit); } -#define glutInit glutInit_ATEXIT_HACK -static int FGAPIENTRY FGUNUSED glutCreateWindow_ATEXIT_HACK(const char *title) { return __glutCreateWindowWithExit(title, exit); } -#define glutCreateWindow glutCreateWindow_ATEXIT_HACK -static int FGAPIENTRY FGUNUSED glutCreateMenu_ATEXIT_HACK(void (* func)(int)) { return __glutCreateMenuWithExit(func, exit); } -#define glutCreateMenu glutCreateMenu_ATEXIT_HACK -#endif -#endif - -#ifdef __cplusplus - } -#endif - -/*** END OF FILE ***/ - -#endif /* __FREEGLUT_STD_H__ */ - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/freeglut/include/GL/glext.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/freeglut/include/GL/glext.h deleted file mode 100644 index 99a4b4bdb295..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/freeglut/include/GL/glext.h +++ /dev/null @@ -1,11751 +0,0 @@ -#ifndef __glext_h_ -#define __glext_h_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** Copyright (c) 2007-2012 The Khronos Group Inc. -** -** Permission is hereby granted, free of charge, to any person obtaining a -** copy of this software and/or associated documentation files (the -** "Materials"), to deal in the Materials without restriction, including -** without limitation the rights to use, copy, modify, merge, publish, -** distribute, sublicense, and/or sell copies of the Materials, and to -** permit persons to whom the Materials are furnished to do so, subject to -** the following conditions: -** -** The above copyright notice and this permission notice shall be included -** in all copies or substantial portions of the Materials. -** -** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. -*/ - -/* Header file version number, required by OpenGL ABI for Linux */ -/* glext.h last updated $Date: 2012-03-05 02:52:51 -0800 (Mon, 05 Mar 2012) $ */ -/* Current version at http://www.opengl.org/registry/ */ -#define GL_GLEXT_VERSION 76 -/* Function declaration macros - to move into glplatform.h */ - -#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) -#define WIN32_LEAN_AND_MEAN 1 -#include -#endif - -#ifndef APIENTRY -#define APIENTRY -#endif -#ifndef APIENTRYP -#define APIENTRYP APIENTRY * -#endif -#ifndef GLAPI -#define GLAPI extern -#endif - -/*************************************************************/ - -#ifndef GL_VERSION_1_2 -#define GL_UNSIGNED_BYTE_3_3_2 0x8032 -#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 -#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 -#define GL_UNSIGNED_INT_8_8_8_8 0x8035 -#define GL_UNSIGNED_INT_10_10_10_2 0x8036 -#define GL_TEXTURE_BINDING_3D 0x806A -#define GL_PACK_SKIP_IMAGES 0x806B -#define GL_PACK_IMAGE_HEIGHT 0x806C -#define GL_UNPACK_SKIP_IMAGES 0x806D -#define GL_UNPACK_IMAGE_HEIGHT 0x806E -#define GL_TEXTURE_3D 0x806F -#define GL_PROXY_TEXTURE_3D 0x8070 -#define GL_TEXTURE_DEPTH 0x8071 -#define GL_TEXTURE_WRAP_R 0x8072 -#define GL_MAX_3D_TEXTURE_SIZE 0x8073 -#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 -#define GL_UNSIGNED_SHORT_5_6_5 0x8363 -#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 -#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 -#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 -#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 -#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 -#define GL_BGR 0x80E0 -#define GL_BGRA 0x80E1 -#define GL_MAX_ELEMENTS_VERTICES 0x80E8 -#define GL_MAX_ELEMENTS_INDICES 0x80E9 -#define GL_CLAMP_TO_EDGE 0x812F -#define GL_TEXTURE_MIN_LOD 0x813A -#define GL_TEXTURE_MAX_LOD 0x813B -#define GL_TEXTURE_BASE_LEVEL 0x813C -#define GL_TEXTURE_MAX_LEVEL 0x813D -#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 -#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 -#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 -#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 -#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E -#endif - -#ifndef GL_VERSION_1_2_DEPRECATED -#define GL_RESCALE_NORMAL 0x803A -#define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8 -#define GL_SINGLE_COLOR 0x81F9 -#define GL_SEPARATE_SPECULAR_COLOR 0x81FA -#define GL_ALIASED_POINT_SIZE_RANGE 0x846D -#endif - -#ifndef GL_ARB_imaging -#define GL_CONSTANT_COLOR 0x8001 -#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 -#define GL_CONSTANT_ALPHA 0x8003 -#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 -#define GL_BLEND_COLOR 0x8005 -#define GL_FUNC_ADD 0x8006 -#define GL_MIN 0x8007 -#define GL_MAX 0x8008 -#define GL_BLEND_EQUATION 0x8009 -#define GL_FUNC_SUBTRACT 0x800A -#define GL_FUNC_REVERSE_SUBTRACT 0x800B -#endif - -#ifndef GL_ARB_imaging_DEPRECATED -#define GL_CONVOLUTION_1D 0x8010 -#define GL_CONVOLUTION_2D 0x8011 -#define GL_SEPARABLE_2D 0x8012 -#define GL_CONVOLUTION_BORDER_MODE 0x8013 -#define GL_CONVOLUTION_FILTER_SCALE 0x8014 -#define GL_CONVOLUTION_FILTER_BIAS 0x8015 -#define GL_REDUCE 0x8016 -#define GL_CONVOLUTION_FORMAT 0x8017 -#define GL_CONVOLUTION_WIDTH 0x8018 -#define GL_CONVOLUTION_HEIGHT 0x8019 -#define GL_MAX_CONVOLUTION_WIDTH 0x801A -#define GL_MAX_CONVOLUTION_HEIGHT 0x801B -#define GL_POST_CONVOLUTION_RED_SCALE 0x801C -#define GL_POST_CONVOLUTION_GREEN_SCALE 0x801D -#define GL_POST_CONVOLUTION_BLUE_SCALE 0x801E -#define GL_POST_CONVOLUTION_ALPHA_SCALE 0x801F -#define GL_POST_CONVOLUTION_RED_BIAS 0x8020 -#define GL_POST_CONVOLUTION_GREEN_BIAS 0x8021 -#define GL_POST_CONVOLUTION_BLUE_BIAS 0x8022 -#define GL_POST_CONVOLUTION_ALPHA_BIAS 0x8023 -#define GL_HISTOGRAM 0x8024 -#define GL_PROXY_HISTOGRAM 0x8025 -#define GL_HISTOGRAM_WIDTH 0x8026 -#define GL_HISTOGRAM_FORMAT 0x8027 -#define GL_HISTOGRAM_RED_SIZE 0x8028 -#define GL_HISTOGRAM_GREEN_SIZE 0x8029 -#define GL_HISTOGRAM_BLUE_SIZE 0x802A -#define GL_HISTOGRAM_ALPHA_SIZE 0x802B -#define GL_HISTOGRAM_LUMINANCE_SIZE 0x802C -#define GL_HISTOGRAM_SINK 0x802D -#define GL_MINMAX 0x802E -#define GL_MINMAX_FORMAT 0x802F -#define GL_MINMAX_SINK 0x8030 -#define GL_TABLE_TOO_LARGE 0x8031 -#define GL_COLOR_MATRIX 0x80B1 -#define GL_COLOR_MATRIX_STACK_DEPTH 0x80B2 -#define GL_MAX_COLOR_MATRIX_STACK_DEPTH 0x80B3 -#define GL_POST_COLOR_MATRIX_RED_SCALE 0x80B4 -#define GL_POST_COLOR_MATRIX_GREEN_SCALE 0x80B5 -#define GL_POST_COLOR_MATRIX_BLUE_SCALE 0x80B6 -#define GL_POST_COLOR_MATRIX_ALPHA_SCALE 0x80B7 -#define GL_POST_COLOR_MATRIX_RED_BIAS 0x80B8 -#define GL_POST_COLOR_MATRIX_GREEN_BIAS 0x80B9 -#define GL_POST_COLOR_MATRIX_BLUE_BIAS 0x80BA -#define GL_POST_COLOR_MATRIX_ALPHA_BIAS 0x80BB -#define GL_COLOR_TABLE 0x80D0 -#define GL_POST_CONVOLUTION_COLOR_TABLE 0x80D1 -#define GL_POST_COLOR_MATRIX_COLOR_TABLE 0x80D2 -#define GL_PROXY_COLOR_TABLE 0x80D3 -#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE 0x80D4 -#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE 0x80D5 -#define GL_COLOR_TABLE_SCALE 0x80D6 -#define GL_COLOR_TABLE_BIAS 0x80D7 -#define GL_COLOR_TABLE_FORMAT 0x80D8 -#define GL_COLOR_TABLE_WIDTH 0x80D9 -#define GL_COLOR_TABLE_RED_SIZE 0x80DA -#define GL_COLOR_TABLE_GREEN_SIZE 0x80DB -#define GL_COLOR_TABLE_BLUE_SIZE 0x80DC -#define GL_COLOR_TABLE_ALPHA_SIZE 0x80DD -#define GL_COLOR_TABLE_LUMINANCE_SIZE 0x80DE -#define GL_COLOR_TABLE_INTENSITY_SIZE 0x80DF -#define GL_CONSTANT_BORDER 0x8151 -#define GL_REPLICATE_BORDER 0x8153 -#define GL_CONVOLUTION_BORDER_COLOR 0x8154 -#endif - -#ifndef GL_VERSION_1_3 -#define GL_TEXTURE0 0x84C0 -#define GL_TEXTURE1 0x84C1 -#define GL_TEXTURE2 0x84C2 -#define GL_TEXTURE3 0x84C3 -#define GL_TEXTURE4 0x84C4 -#define GL_TEXTURE5 0x84C5 -#define GL_TEXTURE6 0x84C6 -#define GL_TEXTURE7 0x84C7 -#define GL_TEXTURE8 0x84C8 -#define GL_TEXTURE9 0x84C9 -#define GL_TEXTURE10 0x84CA -#define GL_TEXTURE11 0x84CB -#define GL_TEXTURE12 0x84CC -#define GL_TEXTURE13 0x84CD -#define GL_TEXTURE14 0x84CE -#define GL_TEXTURE15 0x84CF -#define GL_TEXTURE16 0x84D0 -#define GL_TEXTURE17 0x84D1 -#define GL_TEXTURE18 0x84D2 -#define GL_TEXTURE19 0x84D3 -#define GL_TEXTURE20 0x84D4 -#define GL_TEXTURE21 0x84D5 -#define GL_TEXTURE22 0x84D6 -#define GL_TEXTURE23 0x84D7 -#define GL_TEXTURE24 0x84D8 -#define GL_TEXTURE25 0x84D9 -#define GL_TEXTURE26 0x84DA -#define GL_TEXTURE27 0x84DB -#define GL_TEXTURE28 0x84DC -#define GL_TEXTURE29 0x84DD -#define GL_TEXTURE30 0x84DE -#define GL_TEXTURE31 0x84DF -#define GL_ACTIVE_TEXTURE 0x84E0 -#define GL_MULTISAMPLE 0x809D -#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E -#define GL_SAMPLE_ALPHA_TO_ONE 0x809F -#define GL_SAMPLE_COVERAGE 0x80A0 -#define GL_SAMPLE_BUFFERS 0x80A8 -#define GL_SAMPLES 0x80A9 -#define GL_SAMPLE_COVERAGE_VALUE 0x80AA -#define GL_SAMPLE_COVERAGE_INVERT 0x80AB -#define GL_TEXTURE_CUBE_MAP 0x8513 -#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A -#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B -#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C -#define GL_COMPRESSED_RGB 0x84ED -#define GL_COMPRESSED_RGBA 0x84EE -#define GL_TEXTURE_COMPRESSION_HINT 0x84EF -#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 -#define GL_TEXTURE_COMPRESSED 0x86A1 -#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 -#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 -#define GL_CLAMP_TO_BORDER 0x812D -#endif - -#ifndef GL_VERSION_1_3_DEPRECATED -#define GL_CLIENT_ACTIVE_TEXTURE 0x84E1 -#define GL_MAX_TEXTURE_UNITS 0x84E2 -#define GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3 -#define GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4 -#define GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5 -#define GL_TRANSPOSE_COLOR_MATRIX 0x84E6 -#define GL_MULTISAMPLE_BIT 0x20000000 -#define GL_NORMAL_MAP 0x8511 -#define GL_REFLECTION_MAP 0x8512 -#define GL_COMPRESSED_ALPHA 0x84E9 -#define GL_COMPRESSED_LUMINANCE 0x84EA -#define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB -#define GL_COMPRESSED_INTENSITY 0x84EC -#define GL_COMBINE 0x8570 -#define GL_COMBINE_RGB 0x8571 -#define GL_COMBINE_ALPHA 0x8572 -#define GL_SOURCE0_RGB 0x8580 -#define GL_SOURCE1_RGB 0x8581 -#define GL_SOURCE2_RGB 0x8582 -#define GL_SOURCE0_ALPHA 0x8588 -#define GL_SOURCE1_ALPHA 0x8589 -#define GL_SOURCE2_ALPHA 0x858A -#define GL_OPERAND0_RGB 0x8590 -#define GL_OPERAND1_RGB 0x8591 -#define GL_OPERAND2_RGB 0x8592 -#define GL_OPERAND0_ALPHA 0x8598 -#define GL_OPERAND1_ALPHA 0x8599 -#define GL_OPERAND2_ALPHA 0x859A -#define GL_RGB_SCALE 0x8573 -#define GL_ADD_SIGNED 0x8574 -#define GL_INTERPOLATE 0x8575 -#define GL_SUBTRACT 0x84E7 -#define GL_CONSTANT 0x8576 -#define GL_PRIMARY_COLOR 0x8577 -#define GL_PREVIOUS 0x8578 -#define GL_DOT3_RGB 0x86AE -#define GL_DOT3_RGBA 0x86AF -#endif - -#ifndef GL_VERSION_1_4 -#define GL_BLEND_DST_RGB 0x80C8 -#define GL_BLEND_SRC_RGB 0x80C9 -#define GL_BLEND_DST_ALPHA 0x80CA -#define GL_BLEND_SRC_ALPHA 0x80CB -#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 -#define GL_DEPTH_COMPONENT16 0x81A5 -#define GL_DEPTH_COMPONENT24 0x81A6 -#define GL_DEPTH_COMPONENT32 0x81A7 -#define GL_MIRRORED_REPEAT 0x8370 -#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD -#define GL_TEXTURE_LOD_BIAS 0x8501 -#define GL_INCR_WRAP 0x8507 -#define GL_DECR_WRAP 0x8508 -#define GL_TEXTURE_DEPTH_SIZE 0x884A -#define GL_TEXTURE_COMPARE_MODE 0x884C -#define GL_TEXTURE_COMPARE_FUNC 0x884D -#endif - -#ifndef GL_VERSION_1_4_DEPRECATED -#define GL_POINT_SIZE_MIN 0x8126 -#define GL_POINT_SIZE_MAX 0x8127 -#define GL_POINT_DISTANCE_ATTENUATION 0x8129 -#define GL_GENERATE_MIPMAP 0x8191 -#define GL_GENERATE_MIPMAP_HINT 0x8192 -#define GL_FOG_COORDINATE_SOURCE 0x8450 -#define GL_FOG_COORDINATE 0x8451 -#define GL_FRAGMENT_DEPTH 0x8452 -#define GL_CURRENT_FOG_COORDINATE 0x8453 -#define GL_FOG_COORDINATE_ARRAY_TYPE 0x8454 -#define GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455 -#define GL_FOG_COORDINATE_ARRAY_POINTER 0x8456 -#define GL_FOG_COORDINATE_ARRAY 0x8457 -#define GL_COLOR_SUM 0x8458 -#define GL_CURRENT_SECONDARY_COLOR 0x8459 -#define GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A -#define GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B -#define GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C -#define GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D -#define GL_SECONDARY_COLOR_ARRAY 0x845E -#define GL_TEXTURE_FILTER_CONTROL 0x8500 -#define GL_DEPTH_TEXTURE_MODE 0x884B -#define GL_COMPARE_R_TO_TEXTURE 0x884E -#endif - -#ifndef GL_VERSION_1_5 -#define GL_BUFFER_SIZE 0x8764 -#define GL_BUFFER_USAGE 0x8765 -#define GL_QUERY_COUNTER_BITS 0x8864 -#define GL_CURRENT_QUERY 0x8865 -#define GL_QUERY_RESULT 0x8866 -#define GL_QUERY_RESULT_AVAILABLE 0x8867 -#define GL_ARRAY_BUFFER 0x8892 -#define GL_ELEMENT_ARRAY_BUFFER 0x8893 -#define GL_ARRAY_BUFFER_BINDING 0x8894 -#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 -#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F -#define GL_READ_ONLY 0x88B8 -#define GL_WRITE_ONLY 0x88B9 -#define GL_READ_WRITE 0x88BA -#define GL_BUFFER_ACCESS 0x88BB -#define GL_BUFFER_MAPPED 0x88BC -#define GL_BUFFER_MAP_POINTER 0x88BD -#define GL_STREAM_DRAW 0x88E0 -#define GL_STREAM_READ 0x88E1 -#define GL_STREAM_COPY 0x88E2 -#define GL_STATIC_DRAW 0x88E4 -#define GL_STATIC_READ 0x88E5 -#define GL_STATIC_COPY 0x88E6 -#define GL_DYNAMIC_DRAW 0x88E8 -#define GL_DYNAMIC_READ 0x88E9 -#define GL_DYNAMIC_COPY 0x88EA -#define GL_SAMPLES_PASSED 0x8914 -#endif - -#ifndef GL_VERSION_1_5_DEPRECATED -#define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896 -#define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897 -#define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898 -#define GL_INDEX_ARRAY_BUFFER_BINDING 0x8899 -#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A -#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B -#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C -#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D -#define GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E -#define GL_FOG_COORD_SRC 0x8450 -#define GL_FOG_COORD 0x8451 -#define GL_CURRENT_FOG_COORD 0x8453 -#define GL_FOG_COORD_ARRAY_TYPE 0x8454 -#define GL_FOG_COORD_ARRAY_STRIDE 0x8455 -#define GL_FOG_COORD_ARRAY_POINTER 0x8456 -#define GL_FOG_COORD_ARRAY 0x8457 -#define GL_FOG_COORD_ARRAY_BUFFER_BINDING 0x889D -#define GL_SRC0_RGB 0x8580 -#define GL_SRC1_RGB 0x8581 -#define GL_SRC2_RGB 0x8582 -#define GL_SRC0_ALPHA 0x8588 -#define GL_SRC1_ALPHA 0x8589 -#define GL_SRC2_ALPHA 0x858A -#endif - -#ifndef GL_VERSION_2_0 -#define GL_BLEND_EQUATION_RGB 0x8009 -#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 -#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 -#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 -#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 -#define GL_CURRENT_VERTEX_ATTRIB 0x8626 -#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 -#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 -#define GL_STENCIL_BACK_FUNC 0x8800 -#define GL_STENCIL_BACK_FAIL 0x8801 -#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 -#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 -#define GL_MAX_DRAW_BUFFERS 0x8824 -#define GL_DRAW_BUFFER0 0x8825 -#define GL_DRAW_BUFFER1 0x8826 -#define GL_DRAW_BUFFER2 0x8827 -#define GL_DRAW_BUFFER3 0x8828 -#define GL_DRAW_BUFFER4 0x8829 -#define GL_DRAW_BUFFER5 0x882A -#define GL_DRAW_BUFFER6 0x882B -#define GL_DRAW_BUFFER7 0x882C -#define GL_DRAW_BUFFER8 0x882D -#define GL_DRAW_BUFFER9 0x882E -#define GL_DRAW_BUFFER10 0x882F -#define GL_DRAW_BUFFER11 0x8830 -#define GL_DRAW_BUFFER12 0x8831 -#define GL_DRAW_BUFFER13 0x8832 -#define GL_DRAW_BUFFER14 0x8833 -#define GL_DRAW_BUFFER15 0x8834 -#define GL_BLEND_EQUATION_ALPHA 0x883D -#define GL_MAX_VERTEX_ATTRIBS 0x8869 -#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A -#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 -#define GL_FRAGMENT_SHADER 0x8B30 -#define GL_VERTEX_SHADER 0x8B31 -#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 -#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A -#define GL_MAX_VARYING_FLOATS 0x8B4B -#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C -#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D -#define GL_SHADER_TYPE 0x8B4F -#define GL_FLOAT_VEC2 0x8B50 -#define GL_FLOAT_VEC3 0x8B51 -#define GL_FLOAT_VEC4 0x8B52 -#define GL_INT_VEC2 0x8B53 -#define GL_INT_VEC3 0x8B54 -#define GL_INT_VEC4 0x8B55 -#define GL_BOOL 0x8B56 -#define GL_BOOL_VEC2 0x8B57 -#define GL_BOOL_VEC3 0x8B58 -#define GL_BOOL_VEC4 0x8B59 -#define GL_FLOAT_MAT2 0x8B5A -#define GL_FLOAT_MAT3 0x8B5B -#define GL_FLOAT_MAT4 0x8B5C -#define GL_SAMPLER_1D 0x8B5D -#define GL_SAMPLER_2D 0x8B5E -#define GL_SAMPLER_3D 0x8B5F -#define GL_SAMPLER_CUBE 0x8B60 -#define GL_SAMPLER_1D_SHADOW 0x8B61 -#define GL_SAMPLER_2D_SHADOW 0x8B62 -#define GL_DELETE_STATUS 0x8B80 -#define GL_COMPILE_STATUS 0x8B81 -#define GL_LINK_STATUS 0x8B82 -#define GL_VALIDATE_STATUS 0x8B83 -#define GL_INFO_LOG_LENGTH 0x8B84 -#define GL_ATTACHED_SHADERS 0x8B85 -#define GL_ACTIVE_UNIFORMS 0x8B86 -#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 -#define GL_SHADER_SOURCE_LENGTH 0x8B88 -#define GL_ACTIVE_ATTRIBUTES 0x8B89 -#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A -#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B -#define GL_SHADING_LANGUAGE_VERSION 0x8B8C -#define GL_CURRENT_PROGRAM 0x8B8D -#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 -#define GL_LOWER_LEFT 0x8CA1 -#define GL_UPPER_LEFT 0x8CA2 -#define GL_STENCIL_BACK_REF 0x8CA3 -#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 -#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 -#endif - -#ifndef GL_VERSION_2_0_DEPRECATED -#define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643 -#define GL_POINT_SPRITE 0x8861 -#define GL_COORD_REPLACE 0x8862 -#define GL_MAX_TEXTURE_COORDS 0x8871 -#endif - -#ifndef GL_VERSION_2_1 -#define GL_PIXEL_PACK_BUFFER 0x88EB -#define GL_PIXEL_UNPACK_BUFFER 0x88EC -#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED -#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF -#define GL_FLOAT_MAT2x3 0x8B65 -#define GL_FLOAT_MAT2x4 0x8B66 -#define GL_FLOAT_MAT3x2 0x8B67 -#define GL_FLOAT_MAT3x4 0x8B68 -#define GL_FLOAT_MAT4x2 0x8B69 -#define GL_FLOAT_MAT4x3 0x8B6A -#define GL_SRGB 0x8C40 -#define GL_SRGB8 0x8C41 -#define GL_SRGB_ALPHA 0x8C42 -#define GL_SRGB8_ALPHA8 0x8C43 -#define GL_COMPRESSED_SRGB 0x8C48 -#define GL_COMPRESSED_SRGB_ALPHA 0x8C49 -#endif - -#ifndef GL_VERSION_2_1_DEPRECATED -#define GL_CURRENT_RASTER_SECONDARY_COLOR 0x845F -#define GL_SLUMINANCE_ALPHA 0x8C44 -#define GL_SLUMINANCE8_ALPHA8 0x8C45 -#define GL_SLUMINANCE 0x8C46 -#define GL_SLUMINANCE8 0x8C47 -#define GL_COMPRESSED_SLUMINANCE 0x8C4A -#define GL_COMPRESSED_SLUMINANCE_ALPHA 0x8C4B -#endif - -#ifndef GL_VERSION_3_0 -#define GL_COMPARE_REF_TO_TEXTURE 0x884E -#define GL_CLIP_DISTANCE0 0x3000 -#define GL_CLIP_DISTANCE1 0x3001 -#define GL_CLIP_DISTANCE2 0x3002 -#define GL_CLIP_DISTANCE3 0x3003 -#define GL_CLIP_DISTANCE4 0x3004 -#define GL_CLIP_DISTANCE5 0x3005 -#define GL_CLIP_DISTANCE6 0x3006 -#define GL_CLIP_DISTANCE7 0x3007 -#define GL_MAX_CLIP_DISTANCES 0x0D32 -#define GL_MAJOR_VERSION 0x821B -#define GL_MINOR_VERSION 0x821C -#define GL_NUM_EXTENSIONS 0x821D -#define GL_CONTEXT_FLAGS 0x821E -#define GL_COMPRESSED_RED 0x8225 -#define GL_COMPRESSED_RG 0x8226 -#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x0001 -#define GL_RGBA32F 0x8814 -#define GL_RGB32F 0x8815 -#define GL_RGBA16F 0x881A -#define GL_RGB16F 0x881B -#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD -#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF -#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 -#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 -#define GL_CLAMP_READ_COLOR 0x891C -#define GL_FIXED_ONLY 0x891D -#define GL_MAX_VARYING_COMPONENTS 0x8B4B -#define GL_TEXTURE_1D_ARRAY 0x8C18 -#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 -#define GL_TEXTURE_2D_ARRAY 0x8C1A -#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B -#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C -#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D -#define GL_R11F_G11F_B10F 0x8C3A -#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B -#define GL_RGB9_E5 0x8C3D -#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E -#define GL_TEXTURE_SHARED_SIZE 0x8C3F -#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 -#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F -#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 -#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 -#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 -#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 -#define GL_PRIMITIVES_GENERATED 0x8C87 -#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 -#define GL_RASTERIZER_DISCARD 0x8C89 -#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A -#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B -#define GL_INTERLEAVED_ATTRIBS 0x8C8C -#define GL_SEPARATE_ATTRIBS 0x8C8D -#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E -#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F -#define GL_RGBA32UI 0x8D70 -#define GL_RGB32UI 0x8D71 -#define GL_RGBA16UI 0x8D76 -#define GL_RGB16UI 0x8D77 -#define GL_RGBA8UI 0x8D7C -#define GL_RGB8UI 0x8D7D -#define GL_RGBA32I 0x8D82 -#define GL_RGB32I 0x8D83 -#define GL_RGBA16I 0x8D88 -#define GL_RGB16I 0x8D89 -#define GL_RGBA8I 0x8D8E -#define GL_RGB8I 0x8D8F -#define GL_RED_INTEGER 0x8D94 -#define GL_GREEN_INTEGER 0x8D95 -#define GL_BLUE_INTEGER 0x8D96 -#define GL_RGB_INTEGER 0x8D98 -#define GL_RGBA_INTEGER 0x8D99 -#define GL_BGR_INTEGER 0x8D9A -#define GL_BGRA_INTEGER 0x8D9B -#define GL_SAMPLER_1D_ARRAY 0x8DC0 -#define GL_SAMPLER_2D_ARRAY 0x8DC1 -#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 -#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 -#define GL_SAMPLER_CUBE_SHADOW 0x8DC5 -#define GL_UNSIGNED_INT_VEC2 0x8DC6 -#define GL_UNSIGNED_INT_VEC3 0x8DC7 -#define GL_UNSIGNED_INT_VEC4 0x8DC8 -#define GL_INT_SAMPLER_1D 0x8DC9 -#define GL_INT_SAMPLER_2D 0x8DCA -#define GL_INT_SAMPLER_3D 0x8DCB -#define GL_INT_SAMPLER_CUBE 0x8DCC -#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE -#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF -#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 -#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 -#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 -#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 -#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 -#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 -#define GL_QUERY_WAIT 0x8E13 -#define GL_QUERY_NO_WAIT 0x8E14 -#define GL_QUERY_BY_REGION_WAIT 0x8E15 -#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 -#define GL_BUFFER_ACCESS_FLAGS 0x911F -#define GL_BUFFER_MAP_LENGTH 0x9120 -#define GL_BUFFER_MAP_OFFSET 0x9121 -/* Reuse tokens from ARB_depth_buffer_float */ -/* reuse GL_DEPTH_COMPONENT32F */ -/* reuse GL_DEPTH32F_STENCIL8 */ -/* reuse GL_FLOAT_32_UNSIGNED_INT_24_8_REV */ -/* Reuse tokens from ARB_framebuffer_object */ -/* reuse GL_INVALID_FRAMEBUFFER_OPERATION */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE */ -/* reuse GL_FRAMEBUFFER_DEFAULT */ -/* reuse GL_FRAMEBUFFER_UNDEFINED */ -/* reuse GL_DEPTH_STENCIL_ATTACHMENT */ -/* reuse GL_INDEX */ -/* reuse GL_MAX_RENDERBUFFER_SIZE */ -/* reuse GL_DEPTH_STENCIL */ -/* reuse GL_UNSIGNED_INT_24_8 */ -/* reuse GL_DEPTH24_STENCIL8 */ -/* reuse GL_TEXTURE_STENCIL_SIZE */ -/* reuse GL_TEXTURE_RED_TYPE */ -/* reuse GL_TEXTURE_GREEN_TYPE */ -/* reuse GL_TEXTURE_BLUE_TYPE */ -/* reuse GL_TEXTURE_ALPHA_TYPE */ -/* reuse GL_TEXTURE_DEPTH_TYPE */ -/* reuse GL_UNSIGNED_NORMALIZED */ -/* reuse GL_FRAMEBUFFER_BINDING */ -/* reuse GL_DRAW_FRAMEBUFFER_BINDING */ -/* reuse GL_RENDERBUFFER_BINDING */ -/* reuse GL_READ_FRAMEBUFFER */ -/* reuse GL_DRAW_FRAMEBUFFER */ -/* reuse GL_READ_FRAMEBUFFER_BINDING */ -/* reuse GL_RENDERBUFFER_SAMPLES */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER */ -/* reuse GL_FRAMEBUFFER_COMPLETE */ -/* reuse GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT */ -/* reuse GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT */ -/* reuse GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER */ -/* reuse GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER */ -/* reuse GL_FRAMEBUFFER_UNSUPPORTED */ -/* reuse GL_MAX_COLOR_ATTACHMENTS */ -/* reuse GL_COLOR_ATTACHMENT0 */ -/* reuse GL_COLOR_ATTACHMENT1 */ -/* reuse GL_COLOR_ATTACHMENT2 */ -/* reuse GL_COLOR_ATTACHMENT3 */ -/* reuse GL_COLOR_ATTACHMENT4 */ -/* reuse GL_COLOR_ATTACHMENT5 */ -/* reuse GL_COLOR_ATTACHMENT6 */ -/* reuse GL_COLOR_ATTACHMENT7 */ -/* reuse GL_COLOR_ATTACHMENT8 */ -/* reuse GL_COLOR_ATTACHMENT9 */ -/* reuse GL_COLOR_ATTACHMENT10 */ -/* reuse GL_COLOR_ATTACHMENT11 */ -/* reuse GL_COLOR_ATTACHMENT12 */ -/* reuse GL_COLOR_ATTACHMENT13 */ -/* reuse GL_COLOR_ATTACHMENT14 */ -/* reuse GL_COLOR_ATTACHMENT15 */ -/* reuse GL_DEPTH_ATTACHMENT */ -/* reuse GL_STENCIL_ATTACHMENT */ -/* reuse GL_FRAMEBUFFER */ -/* reuse GL_RENDERBUFFER */ -/* reuse GL_RENDERBUFFER_WIDTH */ -/* reuse GL_RENDERBUFFER_HEIGHT */ -/* reuse GL_RENDERBUFFER_INTERNAL_FORMAT */ -/* reuse GL_STENCIL_INDEX1 */ -/* reuse GL_STENCIL_INDEX4 */ -/* reuse GL_STENCIL_INDEX8 */ -/* reuse GL_STENCIL_INDEX16 */ -/* reuse GL_RENDERBUFFER_RED_SIZE */ -/* reuse GL_RENDERBUFFER_GREEN_SIZE */ -/* reuse GL_RENDERBUFFER_BLUE_SIZE */ -/* reuse GL_RENDERBUFFER_ALPHA_SIZE */ -/* reuse GL_RENDERBUFFER_DEPTH_SIZE */ -/* reuse GL_RENDERBUFFER_STENCIL_SIZE */ -/* reuse GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE */ -/* reuse GL_MAX_SAMPLES */ -/* Reuse tokens from ARB_framebuffer_sRGB */ -/* reuse GL_FRAMEBUFFER_SRGB */ -/* Reuse tokens from ARB_half_float_vertex */ -/* reuse GL_HALF_FLOAT */ -/* Reuse tokens from ARB_map_buffer_range */ -/* reuse GL_MAP_READ_BIT */ -/* reuse GL_MAP_WRITE_BIT */ -/* reuse GL_MAP_INVALIDATE_RANGE_BIT */ -/* reuse GL_MAP_INVALIDATE_BUFFER_BIT */ -/* reuse GL_MAP_FLUSH_EXPLICIT_BIT */ -/* reuse GL_MAP_UNSYNCHRONIZED_BIT */ -/* Reuse tokens from ARB_texture_compression_rgtc */ -/* reuse GL_COMPRESSED_RED_RGTC1 */ -/* reuse GL_COMPRESSED_SIGNED_RED_RGTC1 */ -/* reuse GL_COMPRESSED_RG_RGTC2 */ -/* reuse GL_COMPRESSED_SIGNED_RG_RGTC2 */ -/* Reuse tokens from ARB_texture_rg */ -/* reuse GL_RG */ -/* reuse GL_RG_INTEGER */ -/* reuse GL_R8 */ -/* reuse GL_R16 */ -/* reuse GL_RG8 */ -/* reuse GL_RG16 */ -/* reuse GL_R16F */ -/* reuse GL_R32F */ -/* reuse GL_RG16F */ -/* reuse GL_RG32F */ -/* reuse GL_R8I */ -/* reuse GL_R8UI */ -/* reuse GL_R16I */ -/* reuse GL_R16UI */ -/* reuse GL_R32I */ -/* reuse GL_R32UI */ -/* reuse GL_RG8I */ -/* reuse GL_RG8UI */ -/* reuse GL_RG16I */ -/* reuse GL_RG16UI */ -/* reuse GL_RG32I */ -/* reuse GL_RG32UI */ -/* Reuse tokens from ARB_vertex_array_object */ -/* reuse GL_VERTEX_ARRAY_BINDING */ -#endif - -#ifndef GL_VERSION_3_0_DEPRECATED -#define GL_CLAMP_VERTEX_COLOR 0x891A -#define GL_CLAMP_FRAGMENT_COLOR 0x891B -#define GL_ALPHA_INTEGER 0x8D97 -/* Reuse tokens from ARB_framebuffer_object */ -/* reuse GL_TEXTURE_LUMINANCE_TYPE */ -/* reuse GL_TEXTURE_INTENSITY_TYPE */ -#endif - -#ifndef GL_VERSION_3_1 -#define GL_SAMPLER_2D_RECT 0x8B63 -#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 -#define GL_SAMPLER_BUFFER 0x8DC2 -#define GL_INT_SAMPLER_2D_RECT 0x8DCD -#define GL_INT_SAMPLER_BUFFER 0x8DD0 -#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 -#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 -#define GL_TEXTURE_BUFFER 0x8C2A -#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B -#define GL_TEXTURE_BINDING_BUFFER 0x8C2C -#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D -#define GL_TEXTURE_BUFFER_FORMAT 0x8C2E -#define GL_TEXTURE_RECTANGLE 0x84F5 -#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 -#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 -#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 -#define GL_RED_SNORM 0x8F90 -#define GL_RG_SNORM 0x8F91 -#define GL_RGB_SNORM 0x8F92 -#define GL_RGBA_SNORM 0x8F93 -#define GL_R8_SNORM 0x8F94 -#define GL_RG8_SNORM 0x8F95 -#define GL_RGB8_SNORM 0x8F96 -#define GL_RGBA8_SNORM 0x8F97 -#define GL_R16_SNORM 0x8F98 -#define GL_RG16_SNORM 0x8F99 -#define GL_RGB16_SNORM 0x8F9A -#define GL_RGBA16_SNORM 0x8F9B -#define GL_SIGNED_NORMALIZED 0x8F9C -#define GL_PRIMITIVE_RESTART 0x8F9D -#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E -/* Reuse tokens from ARB_copy_buffer */ -/* reuse GL_COPY_READ_BUFFER */ -/* reuse GL_COPY_WRITE_BUFFER */ -/* Reuse tokens from ARB_draw_instanced (none) */ -/* Reuse tokens from ARB_uniform_buffer_object */ -/* reuse GL_UNIFORM_BUFFER */ -/* reuse GL_UNIFORM_BUFFER_BINDING */ -/* reuse GL_UNIFORM_BUFFER_START */ -/* reuse GL_UNIFORM_BUFFER_SIZE */ -/* reuse GL_MAX_VERTEX_UNIFORM_BLOCKS */ -/* reuse GL_MAX_FRAGMENT_UNIFORM_BLOCKS */ -/* reuse GL_MAX_COMBINED_UNIFORM_BLOCKS */ -/* reuse GL_MAX_UNIFORM_BUFFER_BINDINGS */ -/* reuse GL_MAX_UNIFORM_BLOCK_SIZE */ -/* reuse GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS */ -/* reuse GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS */ -/* reuse GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT */ -/* reuse GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH */ -/* reuse GL_ACTIVE_UNIFORM_BLOCKS */ -/* reuse GL_UNIFORM_TYPE */ -/* reuse GL_UNIFORM_SIZE */ -/* reuse GL_UNIFORM_NAME_LENGTH */ -/* reuse GL_UNIFORM_BLOCK_INDEX */ -/* reuse GL_UNIFORM_OFFSET */ -/* reuse GL_UNIFORM_ARRAY_STRIDE */ -/* reuse GL_UNIFORM_MATRIX_STRIDE */ -/* reuse GL_UNIFORM_IS_ROW_MAJOR */ -/* reuse GL_UNIFORM_BLOCK_BINDING */ -/* reuse GL_UNIFORM_BLOCK_DATA_SIZE */ -/* reuse GL_UNIFORM_BLOCK_NAME_LENGTH */ -/* reuse GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS */ -/* reuse GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES */ -/* reuse GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER */ -/* reuse GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER */ -/* reuse GL_INVALID_INDEX */ -#endif - -#ifndef GL_VERSION_3_2 -#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 -#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 -#define GL_LINES_ADJACENCY 0x000A -#define GL_LINE_STRIP_ADJACENCY 0x000B -#define GL_TRIANGLES_ADJACENCY 0x000C -#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D -#define GL_PROGRAM_POINT_SIZE 0x8642 -#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 -#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 -#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 -#define GL_GEOMETRY_SHADER 0x8DD9 -#define GL_GEOMETRY_VERTICES_OUT 0x8916 -#define GL_GEOMETRY_INPUT_TYPE 0x8917 -#define GL_GEOMETRY_OUTPUT_TYPE 0x8918 -#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF -#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 -#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 -#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 -#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 -#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 -#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 -#define GL_CONTEXT_PROFILE_MASK 0x9126 -/* reuse GL_MAX_VARYING_COMPONENTS */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER */ -/* Reuse tokens from ARB_depth_clamp */ -/* reuse GL_DEPTH_CLAMP */ -/* Reuse tokens from ARB_draw_elements_base_vertex (none) */ -/* Reuse tokens from ARB_fragment_coord_conventions (none) */ -/* Reuse tokens from ARB_provoking_vertex */ -/* reuse GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION */ -/* reuse GL_FIRST_VERTEX_CONVENTION */ -/* reuse GL_LAST_VERTEX_CONVENTION */ -/* reuse GL_PROVOKING_VERTEX */ -/* Reuse tokens from ARB_seamless_cube_map */ -/* reuse GL_TEXTURE_CUBE_MAP_SEAMLESS */ -/* Reuse tokens from ARB_sync */ -/* reuse GL_MAX_SERVER_WAIT_TIMEOUT */ -/* reuse GL_OBJECT_TYPE */ -/* reuse GL_SYNC_CONDITION */ -/* reuse GL_SYNC_STATUS */ -/* reuse GL_SYNC_FLAGS */ -/* reuse GL_SYNC_FENCE */ -/* reuse GL_SYNC_GPU_COMMANDS_COMPLETE */ -/* reuse GL_UNSIGNALED */ -/* reuse GL_SIGNALED */ -/* reuse GL_ALREADY_SIGNALED */ -/* reuse GL_TIMEOUT_EXPIRED */ -/* reuse GL_CONDITION_SATISFIED */ -/* reuse GL_WAIT_FAILED */ -/* reuse GL_TIMEOUT_IGNORED */ -/* reuse GL_SYNC_FLUSH_COMMANDS_BIT */ -/* reuse GL_TIMEOUT_IGNORED */ -/* Reuse tokens from ARB_texture_multisample */ -/* reuse GL_SAMPLE_POSITION */ -/* reuse GL_SAMPLE_MASK */ -/* reuse GL_SAMPLE_MASK_VALUE */ -/* reuse GL_MAX_SAMPLE_MASK_WORDS */ -/* reuse GL_TEXTURE_2D_MULTISAMPLE */ -/* reuse GL_PROXY_TEXTURE_2D_MULTISAMPLE */ -/* reuse GL_TEXTURE_2D_MULTISAMPLE_ARRAY */ -/* reuse GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY */ -/* reuse GL_TEXTURE_BINDING_2D_MULTISAMPLE */ -/* reuse GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY */ -/* reuse GL_TEXTURE_SAMPLES */ -/* reuse GL_TEXTURE_FIXED_SAMPLE_LOCATIONS */ -/* reuse GL_SAMPLER_2D_MULTISAMPLE */ -/* reuse GL_INT_SAMPLER_2D_MULTISAMPLE */ -/* reuse GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE */ -/* reuse GL_SAMPLER_2D_MULTISAMPLE_ARRAY */ -/* reuse GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY */ -/* reuse GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY */ -/* reuse GL_MAX_COLOR_TEXTURE_SAMPLES */ -/* reuse GL_MAX_DEPTH_TEXTURE_SAMPLES */ -/* reuse GL_MAX_INTEGER_SAMPLES */ -/* Don't need to reuse tokens from ARB_vertex_array_bgra since they're already in 1.2 core */ -#endif - -#ifndef GL_VERSION_3_3 -#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE -/* Reuse tokens from ARB_blend_func_extended */ -/* reuse GL_SRC1_COLOR */ -/* reuse GL_ONE_MINUS_SRC1_COLOR */ -/* reuse GL_ONE_MINUS_SRC1_ALPHA */ -/* reuse GL_MAX_DUAL_SOURCE_DRAW_BUFFERS */ -/* Reuse tokens from ARB_explicit_attrib_location (none) */ -/* Reuse tokens from ARB_occlusion_query2 */ -/* reuse GL_ANY_SAMPLES_PASSED */ -/* Reuse tokens from ARB_sampler_objects */ -/* reuse GL_SAMPLER_BINDING */ -/* Reuse tokens from ARB_shader_bit_encoding (none) */ -/* Reuse tokens from ARB_texture_rgb10_a2ui */ -/* reuse GL_RGB10_A2UI */ -/* Reuse tokens from ARB_texture_swizzle */ -/* reuse GL_TEXTURE_SWIZZLE_R */ -/* reuse GL_TEXTURE_SWIZZLE_G */ -/* reuse GL_TEXTURE_SWIZZLE_B */ -/* reuse GL_TEXTURE_SWIZZLE_A */ -/* reuse GL_TEXTURE_SWIZZLE_RGBA */ -/* Reuse tokens from ARB_timer_query */ -/* reuse GL_TIME_ELAPSED */ -/* reuse GL_TIMESTAMP */ -/* Reuse tokens from ARB_vertex_type_2_10_10_10_rev */ -/* reuse GL_INT_2_10_10_10_REV */ -#endif - -#ifndef GL_VERSION_4_0 -#define GL_SAMPLE_SHADING 0x8C36 -#define GL_MIN_SAMPLE_SHADING_VALUE 0x8C37 -#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E -#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F -#define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009 -#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A -#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY 0x900B -#define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C -#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D -#define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E -#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F -/* Reuse tokens from ARB_texture_query_lod (none) */ -/* Reuse tokens from ARB_draw_buffers_blend (none) */ -/* Reuse tokens from ARB_draw_indirect */ -/* reuse GL_DRAW_INDIRECT_BUFFER */ -/* reuse GL_DRAW_INDIRECT_BUFFER_BINDING */ -/* Reuse tokens from ARB_gpu_shader5 */ -/* reuse GL_GEOMETRY_SHADER_INVOCATIONS */ -/* reuse GL_MAX_GEOMETRY_SHADER_INVOCATIONS */ -/* reuse GL_MIN_FRAGMENT_INTERPOLATION_OFFSET */ -/* reuse GL_MAX_FRAGMENT_INTERPOLATION_OFFSET */ -/* reuse GL_FRAGMENT_INTERPOLATION_OFFSET_BITS */ -/* reuse GL_MAX_VERTEX_STREAMS */ -/* Reuse tokens from ARB_gpu_shader_fp64 */ -/* reuse GL_DOUBLE_VEC2 */ -/* reuse GL_DOUBLE_VEC3 */ -/* reuse GL_DOUBLE_VEC4 */ -/* reuse GL_DOUBLE_MAT2 */ -/* reuse GL_DOUBLE_MAT3 */ -/* reuse GL_DOUBLE_MAT4 */ -/* reuse GL_DOUBLE_MAT2x3 */ -/* reuse GL_DOUBLE_MAT2x4 */ -/* reuse GL_DOUBLE_MAT3x2 */ -/* reuse GL_DOUBLE_MAT3x4 */ -/* reuse GL_DOUBLE_MAT4x2 */ -/* reuse GL_DOUBLE_MAT4x3 */ -/* Reuse tokens from ARB_shader_subroutine */ -/* reuse GL_ACTIVE_SUBROUTINES */ -/* reuse GL_ACTIVE_SUBROUTINE_UNIFORMS */ -/* reuse GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS */ -/* reuse GL_ACTIVE_SUBROUTINE_MAX_LENGTH */ -/* reuse GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH */ -/* reuse GL_MAX_SUBROUTINES */ -/* reuse GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS */ -/* reuse GL_NUM_COMPATIBLE_SUBROUTINES */ -/* reuse GL_COMPATIBLE_SUBROUTINES */ -/* Reuse tokens from ARB_tessellation_shader */ -/* reuse GL_PATCHES */ -/* reuse GL_PATCH_VERTICES */ -/* reuse GL_PATCH_DEFAULT_INNER_LEVEL */ -/* reuse GL_PATCH_DEFAULT_OUTER_LEVEL */ -/* reuse GL_TESS_CONTROL_OUTPUT_VERTICES */ -/* reuse GL_TESS_GEN_MODE */ -/* reuse GL_TESS_GEN_SPACING */ -/* reuse GL_TESS_GEN_VERTEX_ORDER */ -/* reuse GL_TESS_GEN_POINT_MODE */ -/* reuse GL_ISOLINES */ -/* reuse GL_FRACTIONAL_ODD */ -/* reuse GL_FRACTIONAL_EVEN */ -/* reuse GL_MAX_PATCH_VERTICES */ -/* reuse GL_MAX_TESS_GEN_LEVEL */ -/* reuse GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS */ -/* reuse GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS */ -/* reuse GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS */ -/* reuse GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS */ -/* reuse GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS */ -/* reuse GL_MAX_TESS_PATCH_COMPONENTS */ -/* reuse GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS */ -/* reuse GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS */ -/* reuse GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS */ -/* reuse GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS */ -/* reuse GL_MAX_TESS_CONTROL_INPUT_COMPONENTS */ -/* reuse GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS */ -/* reuse GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS */ -/* reuse GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS */ -/* reuse GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER */ -/* reuse GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER */ -/* reuse GL_TESS_EVALUATION_SHADER */ -/* reuse GL_TESS_CONTROL_SHADER */ -/* Reuse tokens from ARB_texture_buffer_object_rgb32 (none) */ -/* Reuse tokens from ARB_transform_feedback2 */ -/* reuse GL_TRANSFORM_FEEDBACK */ -/* reuse GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED */ -/* reuse GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE */ -/* reuse GL_TRANSFORM_FEEDBACK_BINDING */ -/* Reuse tokens from ARB_transform_feedback3 */ -/* reuse GL_MAX_TRANSFORM_FEEDBACK_BUFFERS */ -/* reuse GL_MAX_VERTEX_STREAMS */ -#endif - -#ifndef GL_VERSION_4_1 -/* Reuse tokens from ARB_ES2_compatibility */ -/* reuse GL_FIXED */ -/* reuse GL_IMPLEMENTATION_COLOR_READ_TYPE */ -/* reuse GL_IMPLEMENTATION_COLOR_READ_FORMAT */ -/* reuse GL_LOW_FLOAT */ -/* reuse GL_MEDIUM_FLOAT */ -/* reuse GL_HIGH_FLOAT */ -/* reuse GL_LOW_INT */ -/* reuse GL_MEDIUM_INT */ -/* reuse GL_HIGH_INT */ -/* reuse GL_SHADER_COMPILER */ -/* reuse GL_NUM_SHADER_BINARY_FORMATS */ -/* reuse GL_MAX_VERTEX_UNIFORM_VECTORS */ -/* reuse GL_MAX_VARYING_VECTORS */ -/* reuse GL_MAX_FRAGMENT_UNIFORM_VECTORS */ -/* Reuse tokens from ARB_get_program_binary */ -/* reuse GL_PROGRAM_BINARY_RETRIEVABLE_HINT */ -/* reuse GL_PROGRAM_BINARY_LENGTH */ -/* reuse GL_NUM_PROGRAM_BINARY_FORMATS */ -/* reuse GL_PROGRAM_BINARY_FORMATS */ -/* Reuse tokens from ARB_separate_shader_objects */ -/* reuse GL_VERTEX_SHADER_BIT */ -/* reuse GL_FRAGMENT_SHADER_BIT */ -/* reuse GL_GEOMETRY_SHADER_BIT */ -/* reuse GL_TESS_CONTROL_SHADER_BIT */ -/* reuse GL_TESS_EVALUATION_SHADER_BIT */ -/* reuse GL_ALL_SHADER_BITS */ -/* reuse GL_PROGRAM_SEPARABLE */ -/* reuse GL_ACTIVE_PROGRAM */ -/* reuse GL_PROGRAM_PIPELINE_BINDING */ -/* Reuse tokens from ARB_shader_precision (none) */ -/* Reuse tokens from ARB_vertex_attrib_64bit - all are in GL 3.0 and 4.0 already */ -/* Reuse tokens from ARB_viewport_array - some are in GL 1.1 and ARB_provoking_vertex already */ -/* reuse GL_MAX_VIEWPORTS */ -/* reuse GL_VIEWPORT_SUBPIXEL_BITS */ -/* reuse GL_VIEWPORT_BOUNDS_RANGE */ -/* reuse GL_LAYER_PROVOKING_VERTEX */ -/* reuse GL_VIEWPORT_INDEX_PROVOKING_VERTEX */ -/* reuse GL_UNDEFINED_VERTEX */ -#endif - -#ifndef GL_VERSION_4_2 -/* Reuse tokens from ARB_base_instance (none) */ -/* Reuse tokens from ARB_shading_language_420pack (none) */ -/* Reuse tokens from ARB_transform_feedback_instanced (none) */ -/* Reuse tokens from ARB_compressed_texture_pixel_storage */ -/* reuse GL_UNPACK_COMPRESSED_BLOCK_WIDTH */ -/* reuse GL_UNPACK_COMPRESSED_BLOCK_HEIGHT */ -/* reuse GL_UNPACK_COMPRESSED_BLOCK_DEPTH */ -/* reuse GL_UNPACK_COMPRESSED_BLOCK_SIZE */ -/* reuse GL_PACK_COMPRESSED_BLOCK_WIDTH */ -/* reuse GL_PACK_COMPRESSED_BLOCK_HEIGHT */ -/* reuse GL_PACK_COMPRESSED_BLOCK_DEPTH */ -/* reuse GL_PACK_COMPRESSED_BLOCK_SIZE */ -/* Reuse tokens from ARB_conservative_depth (none) */ -/* Reuse tokens from ARB_internalformat_query */ -/* reuse GL_NUM_SAMPLE_COUNTS */ -/* Reuse tokens from ARB_map_buffer_alignment */ -/* reuse GL_MIN_MAP_BUFFER_ALIGNMENT */ -/* Reuse tokens from ARB_shader_atomic_counters */ -/* reuse GL_ATOMIC_COUNTER_BUFFER */ -/* reuse GL_ATOMIC_COUNTER_BUFFER_BINDING */ -/* reuse GL_ATOMIC_COUNTER_BUFFER_START */ -/* reuse GL_ATOMIC_COUNTER_BUFFER_SIZE */ -/* reuse GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE */ -/* reuse GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS */ -/* reuse GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES */ -/* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER */ -/* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER */ -/* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER */ -/* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER */ -/* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER */ -/* reuse GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS */ -/* reuse GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS */ -/* reuse GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS */ -/* reuse GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS */ -/* reuse GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS */ -/* reuse GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS */ -/* reuse GL_MAX_VERTEX_ATOMIC_COUNTERS */ -/* reuse GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS */ -/* reuse GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS */ -/* reuse GL_MAX_GEOMETRY_ATOMIC_COUNTERS */ -/* reuse GL_MAX_FRAGMENT_ATOMIC_COUNTERS */ -/* reuse GL_MAX_COMBINED_ATOMIC_COUNTERS */ -/* reuse GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE */ -/* reuse GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS */ -/* reuse GL_ACTIVE_ATOMIC_COUNTER_BUFFERS */ -/* reuse GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX */ -/* reuse GL_UNSIGNED_INT_ATOMIC_COUNTER */ -/* Reuse tokens from ARB_shader_image_load_store */ -/* reuse GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT */ -/* reuse GL_ELEMENT_ARRAY_BARRIER_BIT */ -/* reuse GL_UNIFORM_BARRIER_BIT */ -/* reuse GL_TEXTURE_FETCH_BARRIER_BIT */ -/* reuse GL_SHADER_IMAGE_ACCESS_BARRIER_BIT */ -/* reuse GL_COMMAND_BARRIER_BIT */ -/* reuse GL_PIXEL_BUFFER_BARRIER_BIT */ -/* reuse GL_TEXTURE_UPDATE_BARRIER_BIT */ -/* reuse GL_BUFFER_UPDATE_BARRIER_BIT */ -/* reuse GL_FRAMEBUFFER_BARRIER_BIT */ -/* reuse GL_TRANSFORM_FEEDBACK_BARRIER_BIT */ -/* reuse GL_ATOMIC_COUNTER_BARRIER_BIT */ -/* reuse GL_ALL_BARRIER_BITS */ -/* reuse GL_MAX_IMAGE_UNITS */ -/* reuse GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS */ -/* reuse GL_IMAGE_BINDING_NAME */ -/* reuse GL_IMAGE_BINDING_LEVEL */ -/* reuse GL_IMAGE_BINDING_LAYERED */ -/* reuse GL_IMAGE_BINDING_LAYER */ -/* reuse GL_IMAGE_BINDING_ACCESS */ -/* reuse GL_IMAGE_1D */ -/* reuse GL_IMAGE_2D */ -/* reuse GL_IMAGE_3D */ -/* reuse GL_IMAGE_2D_RECT */ -/* reuse GL_IMAGE_CUBE */ -/* reuse GL_IMAGE_BUFFER */ -/* reuse GL_IMAGE_1D_ARRAY */ -/* reuse GL_IMAGE_2D_ARRAY */ -/* reuse GL_IMAGE_CUBE_MAP_ARRAY */ -/* reuse GL_IMAGE_2D_MULTISAMPLE */ -/* reuse GL_IMAGE_2D_MULTISAMPLE_ARRAY */ -/* reuse GL_INT_IMAGE_1D */ -/* reuse GL_INT_IMAGE_2D */ -/* reuse GL_INT_IMAGE_3D */ -/* reuse GL_INT_IMAGE_2D_RECT */ -/* reuse GL_INT_IMAGE_CUBE */ -/* reuse GL_INT_IMAGE_BUFFER */ -/* reuse GL_INT_IMAGE_1D_ARRAY */ -/* reuse GL_INT_IMAGE_2D_ARRAY */ -/* reuse GL_INT_IMAGE_CUBE_MAP_ARRAY */ -/* reuse GL_INT_IMAGE_2D_MULTISAMPLE */ -/* reuse GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY */ -/* reuse GL_UNSIGNED_INT_IMAGE_1D */ -/* reuse GL_UNSIGNED_INT_IMAGE_2D */ -/* reuse GL_UNSIGNED_INT_IMAGE_3D */ -/* reuse GL_UNSIGNED_INT_IMAGE_2D_RECT */ -/* reuse GL_UNSIGNED_INT_IMAGE_CUBE */ -/* reuse GL_UNSIGNED_INT_IMAGE_BUFFER */ -/* reuse GL_UNSIGNED_INT_IMAGE_1D_ARRAY */ -/* reuse GL_UNSIGNED_INT_IMAGE_2D_ARRAY */ -/* reuse GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY */ -/* reuse GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE */ -/* reuse GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY */ -/* reuse GL_MAX_IMAGE_SAMPLES */ -/* reuse GL_IMAGE_BINDING_FORMAT */ -/* reuse GL_IMAGE_FORMAT_COMPATIBILITY_TYPE */ -/* reuse GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE */ -/* reuse GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS */ -/* reuse GL_MAX_VERTEX_IMAGE_UNIFORMS */ -/* reuse GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS */ -/* reuse GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS */ -/* reuse GL_MAX_GEOMETRY_IMAGE_UNIFORMS */ -/* reuse GL_MAX_FRAGMENT_IMAGE_UNIFORMS */ -/* reuse GL_MAX_COMBINED_IMAGE_UNIFORMS */ -/* Reuse tokens from ARB_shading_language_packing (none) */ -/* Reuse tokens from ARB_texture_storage */ -/* reuse GL_TEXTURE_IMMUTABLE_FORMAT */ -#endif - -#ifndef GL_ARB_multitexture -#define GL_TEXTURE0_ARB 0x84C0 -#define GL_TEXTURE1_ARB 0x84C1 -#define GL_TEXTURE2_ARB 0x84C2 -#define GL_TEXTURE3_ARB 0x84C3 -#define GL_TEXTURE4_ARB 0x84C4 -#define GL_TEXTURE5_ARB 0x84C5 -#define GL_TEXTURE6_ARB 0x84C6 -#define GL_TEXTURE7_ARB 0x84C7 -#define GL_TEXTURE8_ARB 0x84C8 -#define GL_TEXTURE9_ARB 0x84C9 -#define GL_TEXTURE10_ARB 0x84CA -#define GL_TEXTURE11_ARB 0x84CB -#define GL_TEXTURE12_ARB 0x84CC -#define GL_TEXTURE13_ARB 0x84CD -#define GL_TEXTURE14_ARB 0x84CE -#define GL_TEXTURE15_ARB 0x84CF -#define GL_TEXTURE16_ARB 0x84D0 -#define GL_TEXTURE17_ARB 0x84D1 -#define GL_TEXTURE18_ARB 0x84D2 -#define GL_TEXTURE19_ARB 0x84D3 -#define GL_TEXTURE20_ARB 0x84D4 -#define GL_TEXTURE21_ARB 0x84D5 -#define GL_TEXTURE22_ARB 0x84D6 -#define GL_TEXTURE23_ARB 0x84D7 -#define GL_TEXTURE24_ARB 0x84D8 -#define GL_TEXTURE25_ARB 0x84D9 -#define GL_TEXTURE26_ARB 0x84DA -#define GL_TEXTURE27_ARB 0x84DB -#define GL_TEXTURE28_ARB 0x84DC -#define GL_TEXTURE29_ARB 0x84DD -#define GL_TEXTURE30_ARB 0x84DE -#define GL_TEXTURE31_ARB 0x84DF -#define GL_ACTIVE_TEXTURE_ARB 0x84E0 -#define GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1 -#define GL_MAX_TEXTURE_UNITS_ARB 0x84E2 -#endif - -#ifndef GL_ARB_transpose_matrix -#define GL_TRANSPOSE_MODELVIEW_MATRIX_ARB 0x84E3 -#define GL_TRANSPOSE_PROJECTION_MATRIX_ARB 0x84E4 -#define GL_TRANSPOSE_TEXTURE_MATRIX_ARB 0x84E5 -#define GL_TRANSPOSE_COLOR_MATRIX_ARB 0x84E6 -#endif - -#ifndef GL_ARB_multisample -#define GL_MULTISAMPLE_ARB 0x809D -#define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E -#define GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F -#define GL_SAMPLE_COVERAGE_ARB 0x80A0 -#define GL_SAMPLE_BUFFERS_ARB 0x80A8 -#define GL_SAMPLES_ARB 0x80A9 -#define GL_SAMPLE_COVERAGE_VALUE_ARB 0x80AA -#define GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB -#define GL_MULTISAMPLE_BIT_ARB 0x20000000 -#endif - -#ifndef GL_ARB_texture_env_add -#endif - -#ifndef GL_ARB_texture_cube_map -#define GL_NORMAL_MAP_ARB 0x8511 -#define GL_REFLECTION_MAP_ARB 0x8512 -#define GL_TEXTURE_CUBE_MAP_ARB 0x8513 -#define GL_TEXTURE_BINDING_CUBE_MAP_ARB 0x8514 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x8515 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x8516 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x8517 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x8518 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x8519 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x851A -#define GL_PROXY_TEXTURE_CUBE_MAP_ARB 0x851B -#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB 0x851C -#endif - -#ifndef GL_ARB_texture_compression -#define GL_COMPRESSED_ALPHA_ARB 0x84E9 -#define GL_COMPRESSED_LUMINANCE_ARB 0x84EA -#define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB -#define GL_COMPRESSED_INTENSITY_ARB 0x84EC -#define GL_COMPRESSED_RGB_ARB 0x84ED -#define GL_COMPRESSED_RGBA_ARB 0x84EE -#define GL_TEXTURE_COMPRESSION_HINT_ARB 0x84EF -#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0 -#define GL_TEXTURE_COMPRESSED_ARB 0x86A1 -#define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2 -#define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3 -#endif - -#ifndef GL_ARB_texture_border_clamp -#define GL_CLAMP_TO_BORDER_ARB 0x812D -#endif - -#ifndef GL_ARB_point_parameters -#define GL_POINT_SIZE_MIN_ARB 0x8126 -#define GL_POINT_SIZE_MAX_ARB 0x8127 -#define GL_POINT_FADE_THRESHOLD_SIZE_ARB 0x8128 -#define GL_POINT_DISTANCE_ATTENUATION_ARB 0x8129 -#endif - -#ifndef GL_ARB_vertex_blend -#define GL_MAX_VERTEX_UNITS_ARB 0x86A4 -#define GL_ACTIVE_VERTEX_UNITS_ARB 0x86A5 -#define GL_WEIGHT_SUM_UNITY_ARB 0x86A6 -#define GL_VERTEX_BLEND_ARB 0x86A7 -#define GL_CURRENT_WEIGHT_ARB 0x86A8 -#define GL_WEIGHT_ARRAY_TYPE_ARB 0x86A9 -#define GL_WEIGHT_ARRAY_STRIDE_ARB 0x86AA -#define GL_WEIGHT_ARRAY_SIZE_ARB 0x86AB -#define GL_WEIGHT_ARRAY_POINTER_ARB 0x86AC -#define GL_WEIGHT_ARRAY_ARB 0x86AD -#define GL_MODELVIEW0_ARB 0x1700 -#define GL_MODELVIEW1_ARB 0x850A -#define GL_MODELVIEW2_ARB 0x8722 -#define GL_MODELVIEW3_ARB 0x8723 -#define GL_MODELVIEW4_ARB 0x8724 -#define GL_MODELVIEW5_ARB 0x8725 -#define GL_MODELVIEW6_ARB 0x8726 -#define GL_MODELVIEW7_ARB 0x8727 -#define GL_MODELVIEW8_ARB 0x8728 -#define GL_MODELVIEW9_ARB 0x8729 -#define GL_MODELVIEW10_ARB 0x872A -#define GL_MODELVIEW11_ARB 0x872B -#define GL_MODELVIEW12_ARB 0x872C -#define GL_MODELVIEW13_ARB 0x872D -#define GL_MODELVIEW14_ARB 0x872E -#define GL_MODELVIEW15_ARB 0x872F -#define GL_MODELVIEW16_ARB 0x8730 -#define GL_MODELVIEW17_ARB 0x8731 -#define GL_MODELVIEW18_ARB 0x8732 -#define GL_MODELVIEW19_ARB 0x8733 -#define GL_MODELVIEW20_ARB 0x8734 -#define GL_MODELVIEW21_ARB 0x8735 -#define GL_MODELVIEW22_ARB 0x8736 -#define GL_MODELVIEW23_ARB 0x8737 -#define GL_MODELVIEW24_ARB 0x8738 -#define GL_MODELVIEW25_ARB 0x8739 -#define GL_MODELVIEW26_ARB 0x873A -#define GL_MODELVIEW27_ARB 0x873B -#define GL_MODELVIEW28_ARB 0x873C -#define GL_MODELVIEW29_ARB 0x873D -#define GL_MODELVIEW30_ARB 0x873E -#define GL_MODELVIEW31_ARB 0x873F -#endif - -#ifndef GL_ARB_matrix_palette -#define GL_MATRIX_PALETTE_ARB 0x8840 -#define GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB 0x8841 -#define GL_MAX_PALETTE_MATRICES_ARB 0x8842 -#define GL_CURRENT_PALETTE_MATRIX_ARB 0x8843 -#define GL_MATRIX_INDEX_ARRAY_ARB 0x8844 -#define GL_CURRENT_MATRIX_INDEX_ARB 0x8845 -#define GL_MATRIX_INDEX_ARRAY_SIZE_ARB 0x8846 -#define GL_MATRIX_INDEX_ARRAY_TYPE_ARB 0x8847 -#define GL_MATRIX_INDEX_ARRAY_STRIDE_ARB 0x8848 -#define GL_MATRIX_INDEX_ARRAY_POINTER_ARB 0x8849 -#endif - -#ifndef GL_ARB_texture_env_combine -#define GL_COMBINE_ARB 0x8570 -#define GL_COMBINE_RGB_ARB 0x8571 -#define GL_COMBINE_ALPHA_ARB 0x8572 -#define GL_SOURCE0_RGB_ARB 0x8580 -#define GL_SOURCE1_RGB_ARB 0x8581 -#define GL_SOURCE2_RGB_ARB 0x8582 -#define GL_SOURCE0_ALPHA_ARB 0x8588 -#define GL_SOURCE1_ALPHA_ARB 0x8589 -#define GL_SOURCE2_ALPHA_ARB 0x858A -#define GL_OPERAND0_RGB_ARB 0x8590 -#define GL_OPERAND1_RGB_ARB 0x8591 -#define GL_OPERAND2_RGB_ARB 0x8592 -#define GL_OPERAND0_ALPHA_ARB 0x8598 -#define GL_OPERAND1_ALPHA_ARB 0x8599 -#define GL_OPERAND2_ALPHA_ARB 0x859A -#define GL_RGB_SCALE_ARB 0x8573 -#define GL_ADD_SIGNED_ARB 0x8574 -#define GL_INTERPOLATE_ARB 0x8575 -#define GL_SUBTRACT_ARB 0x84E7 -#define GL_CONSTANT_ARB 0x8576 -#define GL_PRIMARY_COLOR_ARB 0x8577 -#define GL_PREVIOUS_ARB 0x8578 -#endif - -#ifndef GL_ARB_texture_env_crossbar -#endif - -#ifndef GL_ARB_texture_env_dot3 -#define GL_DOT3_RGB_ARB 0x86AE -#define GL_DOT3_RGBA_ARB 0x86AF -#endif - -#ifndef GL_ARB_texture_mirrored_repeat -#define GL_MIRRORED_REPEAT_ARB 0x8370 -#endif - -#ifndef GL_ARB_depth_texture -#define GL_DEPTH_COMPONENT16_ARB 0x81A5 -#define GL_DEPTH_COMPONENT24_ARB 0x81A6 -#define GL_DEPTH_COMPONENT32_ARB 0x81A7 -#define GL_TEXTURE_DEPTH_SIZE_ARB 0x884A -#define GL_DEPTH_TEXTURE_MODE_ARB 0x884B -#endif - -#ifndef GL_ARB_shadow -#define GL_TEXTURE_COMPARE_MODE_ARB 0x884C -#define GL_TEXTURE_COMPARE_FUNC_ARB 0x884D -#define GL_COMPARE_R_TO_TEXTURE_ARB 0x884E -#endif - -#ifndef GL_ARB_shadow_ambient -#define GL_TEXTURE_COMPARE_FAIL_VALUE_ARB 0x80BF -#endif - -#ifndef GL_ARB_window_pos -#endif - -#ifndef GL_ARB_vertex_program -#define GL_COLOR_SUM_ARB 0x8458 -#define GL_VERTEX_PROGRAM_ARB 0x8620 -#define GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622 -#define GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB 0x8623 -#define GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624 -#define GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB 0x8625 -#define GL_CURRENT_VERTEX_ATTRIB_ARB 0x8626 -#define GL_PROGRAM_LENGTH_ARB 0x8627 -#define GL_PROGRAM_STRING_ARB 0x8628 -#define GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB 0x862E -#define GL_MAX_PROGRAM_MATRICES_ARB 0x862F -#define GL_CURRENT_MATRIX_STACK_DEPTH_ARB 0x8640 -#define GL_CURRENT_MATRIX_ARB 0x8641 -#define GL_VERTEX_PROGRAM_POINT_SIZE_ARB 0x8642 -#define GL_VERTEX_PROGRAM_TWO_SIDE_ARB 0x8643 -#define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645 -#define GL_PROGRAM_ERROR_POSITION_ARB 0x864B -#define GL_PROGRAM_BINDING_ARB 0x8677 -#define GL_MAX_VERTEX_ATTRIBS_ARB 0x8869 -#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A -#define GL_PROGRAM_ERROR_STRING_ARB 0x8874 -#define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875 -#define GL_PROGRAM_FORMAT_ARB 0x8876 -#define GL_PROGRAM_INSTRUCTIONS_ARB 0x88A0 -#define GL_MAX_PROGRAM_INSTRUCTIONS_ARB 0x88A1 -#define GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A2 -#define GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A3 -#define GL_PROGRAM_TEMPORARIES_ARB 0x88A4 -#define GL_MAX_PROGRAM_TEMPORARIES_ARB 0x88A5 -#define GL_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A6 -#define GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A7 -#define GL_PROGRAM_PARAMETERS_ARB 0x88A8 -#define GL_MAX_PROGRAM_PARAMETERS_ARB 0x88A9 -#define GL_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AA -#define GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AB -#define GL_PROGRAM_ATTRIBS_ARB 0x88AC -#define GL_MAX_PROGRAM_ATTRIBS_ARB 0x88AD -#define GL_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AE -#define GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AF -#define GL_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B0 -#define GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B1 -#define GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B2 -#define GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B3 -#define GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB 0x88B4 -#define GL_MAX_PROGRAM_ENV_PARAMETERS_ARB 0x88B5 -#define GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB 0x88B6 -#define GL_TRANSPOSE_CURRENT_MATRIX_ARB 0x88B7 -#define GL_MATRIX0_ARB 0x88C0 -#define GL_MATRIX1_ARB 0x88C1 -#define GL_MATRIX2_ARB 0x88C2 -#define GL_MATRIX3_ARB 0x88C3 -#define GL_MATRIX4_ARB 0x88C4 -#define GL_MATRIX5_ARB 0x88C5 -#define GL_MATRIX6_ARB 0x88C6 -#define GL_MATRIX7_ARB 0x88C7 -#define GL_MATRIX8_ARB 0x88C8 -#define GL_MATRIX9_ARB 0x88C9 -#define GL_MATRIX10_ARB 0x88CA -#define GL_MATRIX11_ARB 0x88CB -#define GL_MATRIX12_ARB 0x88CC -#define GL_MATRIX13_ARB 0x88CD -#define GL_MATRIX14_ARB 0x88CE -#define GL_MATRIX15_ARB 0x88CF -#define GL_MATRIX16_ARB 0x88D0 -#define GL_MATRIX17_ARB 0x88D1 -#define GL_MATRIX18_ARB 0x88D2 -#define GL_MATRIX19_ARB 0x88D3 -#define GL_MATRIX20_ARB 0x88D4 -#define GL_MATRIX21_ARB 0x88D5 -#define GL_MATRIX22_ARB 0x88D6 -#define GL_MATRIX23_ARB 0x88D7 -#define GL_MATRIX24_ARB 0x88D8 -#define GL_MATRIX25_ARB 0x88D9 -#define GL_MATRIX26_ARB 0x88DA -#define GL_MATRIX27_ARB 0x88DB -#define GL_MATRIX28_ARB 0x88DC -#define GL_MATRIX29_ARB 0x88DD -#define GL_MATRIX30_ARB 0x88DE -#define GL_MATRIX31_ARB 0x88DF -#endif - -#ifndef GL_ARB_fragment_program -#define GL_FRAGMENT_PROGRAM_ARB 0x8804 -#define GL_PROGRAM_ALU_INSTRUCTIONS_ARB 0x8805 -#define GL_PROGRAM_TEX_INSTRUCTIONS_ARB 0x8806 -#define GL_PROGRAM_TEX_INDIRECTIONS_ARB 0x8807 -#define GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808 -#define GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809 -#define GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A -#define GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B -#define GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C -#define GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D -#define GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E -#define GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F -#define GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810 -#define GL_MAX_TEXTURE_COORDS_ARB 0x8871 -#define GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872 -#endif - -#ifndef GL_ARB_vertex_buffer_object -#define GL_BUFFER_SIZE_ARB 0x8764 -#define GL_BUFFER_USAGE_ARB 0x8765 -#define GL_ARRAY_BUFFER_ARB 0x8892 -#define GL_ELEMENT_ARRAY_BUFFER_ARB 0x8893 -#define GL_ARRAY_BUFFER_BINDING_ARB 0x8894 -#define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895 -#define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896 -#define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897 -#define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898 -#define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899 -#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A -#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B -#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C -#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D -#define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E -#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F -#define GL_READ_ONLY_ARB 0x88B8 -#define GL_WRITE_ONLY_ARB 0x88B9 -#define GL_READ_WRITE_ARB 0x88BA -#define GL_BUFFER_ACCESS_ARB 0x88BB -#define GL_BUFFER_MAPPED_ARB 0x88BC -#define GL_BUFFER_MAP_POINTER_ARB 0x88BD -#define GL_STREAM_DRAW_ARB 0x88E0 -#define GL_STREAM_READ_ARB 0x88E1 -#define GL_STREAM_COPY_ARB 0x88E2 -#define GL_STATIC_DRAW_ARB 0x88E4 -#define GL_STATIC_READ_ARB 0x88E5 -#define GL_STATIC_COPY_ARB 0x88E6 -#define GL_DYNAMIC_DRAW_ARB 0x88E8 -#define GL_DYNAMIC_READ_ARB 0x88E9 -#define GL_DYNAMIC_COPY_ARB 0x88EA -#endif - -#ifndef GL_ARB_occlusion_query -#define GL_QUERY_COUNTER_BITS_ARB 0x8864 -#define GL_CURRENT_QUERY_ARB 0x8865 -#define GL_QUERY_RESULT_ARB 0x8866 -#define GL_QUERY_RESULT_AVAILABLE_ARB 0x8867 -#define GL_SAMPLES_PASSED_ARB 0x8914 -#endif - -#ifndef GL_ARB_shader_objects -#define GL_PROGRAM_OBJECT_ARB 0x8B40 -#define GL_SHADER_OBJECT_ARB 0x8B48 -#define GL_OBJECT_TYPE_ARB 0x8B4E -#define GL_OBJECT_SUBTYPE_ARB 0x8B4F -#define GL_FLOAT_VEC2_ARB 0x8B50 -#define GL_FLOAT_VEC3_ARB 0x8B51 -#define GL_FLOAT_VEC4_ARB 0x8B52 -#define GL_INT_VEC2_ARB 0x8B53 -#define GL_INT_VEC3_ARB 0x8B54 -#define GL_INT_VEC4_ARB 0x8B55 -#define GL_BOOL_ARB 0x8B56 -#define GL_BOOL_VEC2_ARB 0x8B57 -#define GL_BOOL_VEC3_ARB 0x8B58 -#define GL_BOOL_VEC4_ARB 0x8B59 -#define GL_FLOAT_MAT2_ARB 0x8B5A -#define GL_FLOAT_MAT3_ARB 0x8B5B -#define GL_FLOAT_MAT4_ARB 0x8B5C -#define GL_SAMPLER_1D_ARB 0x8B5D -#define GL_SAMPLER_2D_ARB 0x8B5E -#define GL_SAMPLER_3D_ARB 0x8B5F -#define GL_SAMPLER_CUBE_ARB 0x8B60 -#define GL_SAMPLER_1D_SHADOW_ARB 0x8B61 -#define GL_SAMPLER_2D_SHADOW_ARB 0x8B62 -#define GL_SAMPLER_2D_RECT_ARB 0x8B63 -#define GL_SAMPLER_2D_RECT_SHADOW_ARB 0x8B64 -#define GL_OBJECT_DELETE_STATUS_ARB 0x8B80 -#define GL_OBJECT_COMPILE_STATUS_ARB 0x8B81 -#define GL_OBJECT_LINK_STATUS_ARB 0x8B82 -#define GL_OBJECT_VALIDATE_STATUS_ARB 0x8B83 -#define GL_OBJECT_INFO_LOG_LENGTH_ARB 0x8B84 -#define GL_OBJECT_ATTACHED_OBJECTS_ARB 0x8B85 -#define GL_OBJECT_ACTIVE_UNIFORMS_ARB 0x8B86 -#define GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87 -#define GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88 -#endif - -#ifndef GL_ARB_vertex_shader -#define GL_VERTEX_SHADER_ARB 0x8B31 -#define GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A -#define GL_MAX_VARYING_FLOATS_ARB 0x8B4B -#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C -#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D -#define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB 0x8B89 -#define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A -#endif - -#ifndef GL_ARB_fragment_shader -#define GL_FRAGMENT_SHADER_ARB 0x8B30 -#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49 -#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B -#endif - -#ifndef GL_ARB_shading_language_100 -#define GL_SHADING_LANGUAGE_VERSION_ARB 0x8B8C -#endif - -#ifndef GL_ARB_texture_non_power_of_two -#endif - -#ifndef GL_ARB_point_sprite -#define GL_POINT_SPRITE_ARB 0x8861 -#define GL_COORD_REPLACE_ARB 0x8862 -#endif - -#ifndef GL_ARB_fragment_program_shadow -#endif - -#ifndef GL_ARB_draw_buffers -#define GL_MAX_DRAW_BUFFERS_ARB 0x8824 -#define GL_DRAW_BUFFER0_ARB 0x8825 -#define GL_DRAW_BUFFER1_ARB 0x8826 -#define GL_DRAW_BUFFER2_ARB 0x8827 -#define GL_DRAW_BUFFER3_ARB 0x8828 -#define GL_DRAW_BUFFER4_ARB 0x8829 -#define GL_DRAW_BUFFER5_ARB 0x882A -#define GL_DRAW_BUFFER6_ARB 0x882B -#define GL_DRAW_BUFFER7_ARB 0x882C -#define GL_DRAW_BUFFER8_ARB 0x882D -#define GL_DRAW_BUFFER9_ARB 0x882E -#define GL_DRAW_BUFFER10_ARB 0x882F -#define GL_DRAW_BUFFER11_ARB 0x8830 -#define GL_DRAW_BUFFER12_ARB 0x8831 -#define GL_DRAW_BUFFER13_ARB 0x8832 -#define GL_DRAW_BUFFER14_ARB 0x8833 -#define GL_DRAW_BUFFER15_ARB 0x8834 -#endif - -#ifndef GL_ARB_texture_rectangle -#define GL_TEXTURE_RECTANGLE_ARB 0x84F5 -#define GL_TEXTURE_BINDING_RECTANGLE_ARB 0x84F6 -#define GL_PROXY_TEXTURE_RECTANGLE_ARB 0x84F7 -#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8 -#endif - -#ifndef GL_ARB_color_buffer_float -#define GL_RGBA_FLOAT_MODE_ARB 0x8820 -#define GL_CLAMP_VERTEX_COLOR_ARB 0x891A -#define GL_CLAMP_FRAGMENT_COLOR_ARB 0x891B -#define GL_CLAMP_READ_COLOR_ARB 0x891C -#define GL_FIXED_ONLY_ARB 0x891D -#endif - -#ifndef GL_ARB_half_float_pixel -#define GL_HALF_FLOAT_ARB 0x140B -#endif - -#ifndef GL_ARB_texture_float -#define GL_TEXTURE_RED_TYPE_ARB 0x8C10 -#define GL_TEXTURE_GREEN_TYPE_ARB 0x8C11 -#define GL_TEXTURE_BLUE_TYPE_ARB 0x8C12 -#define GL_TEXTURE_ALPHA_TYPE_ARB 0x8C13 -#define GL_TEXTURE_LUMINANCE_TYPE_ARB 0x8C14 -#define GL_TEXTURE_INTENSITY_TYPE_ARB 0x8C15 -#define GL_TEXTURE_DEPTH_TYPE_ARB 0x8C16 -#define GL_UNSIGNED_NORMALIZED_ARB 0x8C17 -#define GL_RGBA32F_ARB 0x8814 -#define GL_RGB32F_ARB 0x8815 -#define GL_ALPHA32F_ARB 0x8816 -#define GL_INTENSITY32F_ARB 0x8817 -#define GL_LUMINANCE32F_ARB 0x8818 -#define GL_LUMINANCE_ALPHA32F_ARB 0x8819 -#define GL_RGBA16F_ARB 0x881A -#define GL_RGB16F_ARB 0x881B -#define GL_ALPHA16F_ARB 0x881C -#define GL_INTENSITY16F_ARB 0x881D -#define GL_LUMINANCE16F_ARB 0x881E -#define GL_LUMINANCE_ALPHA16F_ARB 0x881F -#endif - -#ifndef GL_ARB_pixel_buffer_object -#define GL_PIXEL_PACK_BUFFER_ARB 0x88EB -#define GL_PIXEL_UNPACK_BUFFER_ARB 0x88EC -#define GL_PIXEL_PACK_BUFFER_BINDING_ARB 0x88ED -#define GL_PIXEL_UNPACK_BUFFER_BINDING_ARB 0x88EF -#endif - -#ifndef GL_ARB_depth_buffer_float -#define GL_DEPTH_COMPONENT32F 0x8CAC -#define GL_DEPTH32F_STENCIL8 0x8CAD -#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD -#endif - -#ifndef GL_ARB_draw_instanced -#endif - -#ifndef GL_ARB_framebuffer_object -#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 -#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 -#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 -#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 -#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 -#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 -#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 -#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 -#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 -#define GL_FRAMEBUFFER_DEFAULT 0x8218 -#define GL_FRAMEBUFFER_UNDEFINED 0x8219 -#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A -#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 -#define GL_DEPTH_STENCIL 0x84F9 -#define GL_UNSIGNED_INT_24_8 0x84FA -#define GL_DEPTH24_STENCIL8 0x88F0 -#define GL_TEXTURE_STENCIL_SIZE 0x88F1 -#define GL_TEXTURE_RED_TYPE 0x8C10 -#define GL_TEXTURE_GREEN_TYPE 0x8C11 -#define GL_TEXTURE_BLUE_TYPE 0x8C12 -#define GL_TEXTURE_ALPHA_TYPE 0x8C13 -#define GL_TEXTURE_DEPTH_TYPE 0x8C16 -#define GL_UNSIGNED_NORMALIZED 0x8C17 -#define GL_FRAMEBUFFER_BINDING 0x8CA6 -#define GL_DRAW_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING -#define GL_RENDERBUFFER_BINDING 0x8CA7 -#define GL_READ_FRAMEBUFFER 0x8CA8 -#define GL_DRAW_FRAMEBUFFER 0x8CA9 -#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA -#define GL_RENDERBUFFER_SAMPLES 0x8CAB -#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 -#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 -#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 -#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 -#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 -#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB -#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC -#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD -#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF -#define GL_COLOR_ATTACHMENT0 0x8CE0 -#define GL_COLOR_ATTACHMENT1 0x8CE1 -#define GL_COLOR_ATTACHMENT2 0x8CE2 -#define GL_COLOR_ATTACHMENT3 0x8CE3 -#define GL_COLOR_ATTACHMENT4 0x8CE4 -#define GL_COLOR_ATTACHMENT5 0x8CE5 -#define GL_COLOR_ATTACHMENT6 0x8CE6 -#define GL_COLOR_ATTACHMENT7 0x8CE7 -#define GL_COLOR_ATTACHMENT8 0x8CE8 -#define GL_COLOR_ATTACHMENT9 0x8CE9 -#define GL_COLOR_ATTACHMENT10 0x8CEA -#define GL_COLOR_ATTACHMENT11 0x8CEB -#define GL_COLOR_ATTACHMENT12 0x8CEC -#define GL_COLOR_ATTACHMENT13 0x8CED -#define GL_COLOR_ATTACHMENT14 0x8CEE -#define GL_COLOR_ATTACHMENT15 0x8CEF -#define GL_DEPTH_ATTACHMENT 0x8D00 -#define GL_STENCIL_ATTACHMENT 0x8D20 -#define GL_FRAMEBUFFER 0x8D40 -#define GL_RENDERBUFFER 0x8D41 -#define GL_RENDERBUFFER_WIDTH 0x8D42 -#define GL_RENDERBUFFER_HEIGHT 0x8D43 -#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 -#define GL_STENCIL_INDEX1 0x8D46 -#define GL_STENCIL_INDEX4 0x8D47 -#define GL_STENCIL_INDEX8 0x8D48 -#define GL_STENCIL_INDEX16 0x8D49 -#define GL_RENDERBUFFER_RED_SIZE 0x8D50 -#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 -#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 -#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 -#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 -#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 -#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 -#define GL_MAX_SAMPLES 0x8D57 -#endif - -#ifndef GL_ARB_framebuffer_object_DEPRECATED -#define GL_INDEX 0x8222 -#define GL_TEXTURE_LUMINANCE_TYPE 0x8C14 -#define GL_TEXTURE_INTENSITY_TYPE 0x8C15 -#endif - -#ifndef GL_ARB_framebuffer_sRGB -#define GL_FRAMEBUFFER_SRGB 0x8DB9 -#endif - -#ifndef GL_ARB_geometry_shader4 -#define GL_LINES_ADJACENCY_ARB 0x000A -#define GL_LINE_STRIP_ADJACENCY_ARB 0x000B -#define GL_TRIANGLES_ADJACENCY_ARB 0x000C -#define GL_TRIANGLE_STRIP_ADJACENCY_ARB 0x000D -#define GL_PROGRAM_POINT_SIZE_ARB 0x8642 -#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB 0x8C29 -#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB 0x8DA7 -#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB 0x8DA8 -#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB 0x8DA9 -#define GL_GEOMETRY_SHADER_ARB 0x8DD9 -#define GL_GEOMETRY_VERTICES_OUT_ARB 0x8DDA -#define GL_GEOMETRY_INPUT_TYPE_ARB 0x8DDB -#define GL_GEOMETRY_OUTPUT_TYPE_ARB 0x8DDC -#define GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB 0x8DDD -#define GL_MAX_VERTEX_VARYING_COMPONENTS_ARB 0x8DDE -#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB 0x8DDF -#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB 0x8DE0 -#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB 0x8DE1 -/* reuse GL_MAX_VARYING_COMPONENTS */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER */ -#endif - -#ifndef GL_ARB_half_float_vertex -#define GL_HALF_FLOAT 0x140B -#endif - -#ifndef GL_ARB_instanced_arrays -#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB 0x88FE -#endif - -#ifndef GL_ARB_map_buffer_range -#define GL_MAP_READ_BIT 0x0001 -#define GL_MAP_WRITE_BIT 0x0002 -#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 -#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 -#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 -#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 -#endif - -#ifndef GL_ARB_texture_buffer_object -#define GL_TEXTURE_BUFFER_ARB 0x8C2A -#define GL_MAX_TEXTURE_BUFFER_SIZE_ARB 0x8C2B -#define GL_TEXTURE_BINDING_BUFFER_ARB 0x8C2C -#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_ARB 0x8C2D -#define GL_TEXTURE_BUFFER_FORMAT_ARB 0x8C2E -#endif - -#ifndef GL_ARB_texture_compression_rgtc -#define GL_COMPRESSED_RED_RGTC1 0x8DBB -#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC -#define GL_COMPRESSED_RG_RGTC2 0x8DBD -#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE -#endif - -#ifndef GL_ARB_texture_rg -#define GL_RG 0x8227 -#define GL_RG_INTEGER 0x8228 -#define GL_R8 0x8229 -#define GL_R16 0x822A -#define GL_RG8 0x822B -#define GL_RG16 0x822C -#define GL_R16F 0x822D -#define GL_R32F 0x822E -#define GL_RG16F 0x822F -#define GL_RG32F 0x8230 -#define GL_R8I 0x8231 -#define GL_R8UI 0x8232 -#define GL_R16I 0x8233 -#define GL_R16UI 0x8234 -#define GL_R32I 0x8235 -#define GL_R32UI 0x8236 -#define GL_RG8I 0x8237 -#define GL_RG8UI 0x8238 -#define GL_RG16I 0x8239 -#define GL_RG16UI 0x823A -#define GL_RG32I 0x823B -#define GL_RG32UI 0x823C -#endif - -#ifndef GL_ARB_vertex_array_object -#define GL_VERTEX_ARRAY_BINDING 0x85B5 -#endif - -#ifndef GL_ARB_uniform_buffer_object -#define GL_UNIFORM_BUFFER 0x8A11 -#define GL_UNIFORM_BUFFER_BINDING 0x8A28 -#define GL_UNIFORM_BUFFER_START 0x8A29 -#define GL_UNIFORM_BUFFER_SIZE 0x8A2A -#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B -#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C -#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D -#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E -#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F -#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 -#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 -#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 -#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 -#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 -#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 -#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 -#define GL_UNIFORM_TYPE 0x8A37 -#define GL_UNIFORM_SIZE 0x8A38 -#define GL_UNIFORM_NAME_LENGTH 0x8A39 -#define GL_UNIFORM_BLOCK_INDEX 0x8A3A -#define GL_UNIFORM_OFFSET 0x8A3B -#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C -#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D -#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E -#define GL_UNIFORM_BLOCK_BINDING 0x8A3F -#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 -#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 -#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 -#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 -#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 -#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 -#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 -#define GL_INVALID_INDEX 0xFFFFFFFFu -#endif - -#ifndef GL_ARB_compatibility -/* ARB_compatibility just defines tokens from core 3.0 */ -#endif - -#ifndef GL_ARB_copy_buffer -#define GL_COPY_READ_BUFFER 0x8F36 -#define GL_COPY_WRITE_BUFFER 0x8F37 -#endif - -#ifndef GL_ARB_shader_texture_lod -#endif - -#ifndef GL_ARB_depth_clamp -#define GL_DEPTH_CLAMP 0x864F -#endif - -#ifndef GL_ARB_draw_elements_base_vertex -#endif - -#ifndef GL_ARB_fragment_coord_conventions -#endif - -#ifndef GL_ARB_provoking_vertex -#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C -#define GL_FIRST_VERTEX_CONVENTION 0x8E4D -#define GL_LAST_VERTEX_CONVENTION 0x8E4E -#define GL_PROVOKING_VERTEX 0x8E4F -#endif - -#ifndef GL_ARB_seamless_cube_map -#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F -#endif - -#ifndef GL_ARB_sync -#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 -#define GL_OBJECT_TYPE 0x9112 -#define GL_SYNC_CONDITION 0x9113 -#define GL_SYNC_STATUS 0x9114 -#define GL_SYNC_FLAGS 0x9115 -#define GL_SYNC_FENCE 0x9116 -#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 -#define GL_UNSIGNALED 0x9118 -#define GL_SIGNALED 0x9119 -#define GL_ALREADY_SIGNALED 0x911A -#define GL_TIMEOUT_EXPIRED 0x911B -#define GL_CONDITION_SATISFIED 0x911C -#define GL_WAIT_FAILED 0x911D -#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 -#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull -#endif - -#ifndef GL_ARB_texture_multisample -#define GL_SAMPLE_POSITION 0x8E50 -#define GL_SAMPLE_MASK 0x8E51 -#define GL_SAMPLE_MASK_VALUE 0x8E52 -#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 -#define GL_TEXTURE_2D_MULTISAMPLE 0x9100 -#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 -#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 -#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 -#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 -#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 -#define GL_TEXTURE_SAMPLES 0x9106 -#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 -#define GL_SAMPLER_2D_MULTISAMPLE 0x9108 -#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 -#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A -#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B -#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C -#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D -#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E -#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F -#define GL_MAX_INTEGER_SAMPLES 0x9110 -#endif - -#ifndef GL_ARB_vertex_array_bgra -/* reuse GL_BGRA */ -#endif - -#ifndef GL_ARB_draw_buffers_blend -#endif - -#ifndef GL_ARB_sample_shading -#define GL_SAMPLE_SHADING_ARB 0x8C36 -#define GL_MIN_SAMPLE_SHADING_VALUE_ARB 0x8C37 -#endif - -#ifndef GL_ARB_texture_cube_map_array -#define GL_TEXTURE_CUBE_MAP_ARRAY_ARB 0x9009 -#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_ARB 0x900A -#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY_ARB 0x900B -#define GL_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900C -#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_ARB 0x900D -#define GL_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900E -#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900F -#endif - -#ifndef GL_ARB_texture_gather -#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5E -#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5F -#endif - -#ifndef GL_ARB_texture_query_lod -#endif - -#ifndef GL_ARB_shading_language_include -#define GL_SHADER_INCLUDE_ARB 0x8DAE -#define GL_NAMED_STRING_LENGTH_ARB 0x8DE9 -#define GL_NAMED_STRING_TYPE_ARB 0x8DEA -#endif - -#ifndef GL_ARB_texture_compression_bptc -#define GL_COMPRESSED_RGBA_BPTC_UNORM_ARB 0x8E8C -#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB 0x8E8D -#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB 0x8E8E -#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB 0x8E8F -#endif - -#ifndef GL_ARB_blend_func_extended -#define GL_SRC1_COLOR 0x88F9 -/* reuse GL_SRC1_ALPHA */ -#define GL_ONE_MINUS_SRC1_COLOR 0x88FA -#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB -#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC -#endif - -#ifndef GL_ARB_explicit_attrib_location -#endif - -#ifndef GL_ARB_occlusion_query2 -#define GL_ANY_SAMPLES_PASSED 0x8C2F -#endif - -#ifndef GL_ARB_sampler_objects -#define GL_SAMPLER_BINDING 0x8919 -#endif - -#ifndef GL_ARB_shader_bit_encoding -#endif - -#ifndef GL_ARB_texture_rgb10_a2ui -#define GL_RGB10_A2UI 0x906F -#endif - -#ifndef GL_ARB_texture_swizzle -#define GL_TEXTURE_SWIZZLE_R 0x8E42 -#define GL_TEXTURE_SWIZZLE_G 0x8E43 -#define GL_TEXTURE_SWIZZLE_B 0x8E44 -#define GL_TEXTURE_SWIZZLE_A 0x8E45 -#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 -#endif - -#ifndef GL_ARB_timer_query -#define GL_TIME_ELAPSED 0x88BF -#define GL_TIMESTAMP 0x8E28 -#endif - -#ifndef GL_ARB_vertex_type_2_10_10_10_rev -/* reuse GL_UNSIGNED_INT_2_10_10_10_REV */ -#define GL_INT_2_10_10_10_REV 0x8D9F -#endif - -#ifndef GL_ARB_draw_indirect -#define GL_DRAW_INDIRECT_BUFFER 0x8F3F -#define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43 -#endif - -#ifndef GL_ARB_gpu_shader5 -#define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F -#define GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A -#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B -#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C -#define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D -/* reuse GL_MAX_VERTEX_STREAMS */ -#endif - -#ifndef GL_ARB_gpu_shader_fp64 -/* reuse GL_DOUBLE */ -#define GL_DOUBLE_VEC2 0x8FFC -#define GL_DOUBLE_VEC3 0x8FFD -#define GL_DOUBLE_VEC4 0x8FFE -#define GL_DOUBLE_MAT2 0x8F46 -#define GL_DOUBLE_MAT3 0x8F47 -#define GL_DOUBLE_MAT4 0x8F48 -#define GL_DOUBLE_MAT2x3 0x8F49 -#define GL_DOUBLE_MAT2x4 0x8F4A -#define GL_DOUBLE_MAT3x2 0x8F4B -#define GL_DOUBLE_MAT3x4 0x8F4C -#define GL_DOUBLE_MAT4x2 0x8F4D -#define GL_DOUBLE_MAT4x3 0x8F4E -#endif - -#ifndef GL_ARB_shader_subroutine -#define GL_ACTIVE_SUBROUTINES 0x8DE5 -#define GL_ACTIVE_SUBROUTINE_UNIFORMS 0x8DE6 -#define GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS 0x8E47 -#define GL_ACTIVE_SUBROUTINE_MAX_LENGTH 0x8E48 -#define GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH 0x8E49 -#define GL_MAX_SUBROUTINES 0x8DE7 -#define GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS 0x8DE8 -#define GL_NUM_COMPATIBLE_SUBROUTINES 0x8E4A -#define GL_COMPATIBLE_SUBROUTINES 0x8E4B -/* reuse GL_UNIFORM_SIZE */ -/* reuse GL_UNIFORM_NAME_LENGTH */ -#endif - -#ifndef GL_ARB_tessellation_shader -#define GL_PATCHES 0x000E -#define GL_PATCH_VERTICES 0x8E72 -#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73 -#define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74 -#define GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75 -#define GL_TESS_GEN_MODE 0x8E76 -#define GL_TESS_GEN_SPACING 0x8E77 -#define GL_TESS_GEN_VERTEX_ORDER 0x8E78 -#define GL_TESS_GEN_POINT_MODE 0x8E79 -/* reuse GL_TRIANGLES */ -/* reuse GL_QUADS */ -#define GL_ISOLINES 0x8E7A -/* reuse GL_EQUAL */ -#define GL_FRACTIONAL_ODD 0x8E7B -#define GL_FRACTIONAL_EVEN 0x8E7C -/* reuse GL_CCW */ -/* reuse GL_CW */ -#define GL_MAX_PATCH_VERTICES 0x8E7D -#define GL_MAX_TESS_GEN_LEVEL 0x8E7E -#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F -#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80 -#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81 -#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82 -#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83 -#define GL_MAX_TESS_PATCH_COMPONENTS 0x8E84 -#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85 -#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86 -#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89 -#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A -#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C -#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D -#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E -#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F -#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0 -#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1 -#define GL_TESS_EVALUATION_SHADER 0x8E87 -#define GL_TESS_CONTROL_SHADER 0x8E88 -#endif - -#ifndef GL_ARB_texture_buffer_object_rgb32 -/* reuse GL_RGB32F */ -/* reuse GL_RGB32UI */ -/* reuse GL_RGB32I */ -#endif - -#ifndef GL_ARB_transform_feedback2 -#define GL_TRANSFORM_FEEDBACK 0x8E22 -#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED 0x8E23 -#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE 0x8E24 -#define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25 -#endif - -#ifndef GL_ARB_transform_feedback3 -#define GL_MAX_TRANSFORM_FEEDBACK_BUFFERS 0x8E70 -#define GL_MAX_VERTEX_STREAMS 0x8E71 -#endif - -#ifndef GL_ARB_ES2_compatibility -#define GL_FIXED 0x140C -#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A -#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B -#define GL_LOW_FLOAT 0x8DF0 -#define GL_MEDIUM_FLOAT 0x8DF1 -#define GL_HIGH_FLOAT 0x8DF2 -#define GL_LOW_INT 0x8DF3 -#define GL_MEDIUM_INT 0x8DF4 -#define GL_HIGH_INT 0x8DF5 -#define GL_SHADER_COMPILER 0x8DFA -#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 -#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB -#define GL_MAX_VARYING_VECTORS 0x8DFC -#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD -#endif - -#ifndef GL_ARB_get_program_binary -#define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257 -#define GL_PROGRAM_BINARY_LENGTH 0x8741 -#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE -#define GL_PROGRAM_BINARY_FORMATS 0x87FF -#endif - -#ifndef GL_ARB_separate_shader_objects -#define GL_VERTEX_SHADER_BIT 0x00000001 -#define GL_FRAGMENT_SHADER_BIT 0x00000002 -#define GL_GEOMETRY_SHADER_BIT 0x00000004 -#define GL_TESS_CONTROL_SHADER_BIT 0x00000008 -#define GL_TESS_EVALUATION_SHADER_BIT 0x00000010 -#define GL_ALL_SHADER_BITS 0xFFFFFFFF -#define GL_PROGRAM_SEPARABLE 0x8258 -#define GL_ACTIVE_PROGRAM 0x8259 -#define GL_PROGRAM_PIPELINE_BINDING 0x825A -#endif - -#ifndef GL_ARB_shader_precision -#endif - -#ifndef GL_ARB_vertex_attrib_64bit -/* reuse GL_RGB32I */ -/* reuse GL_DOUBLE_VEC2 */ -/* reuse GL_DOUBLE_VEC3 */ -/* reuse GL_DOUBLE_VEC4 */ -/* reuse GL_DOUBLE_MAT2 */ -/* reuse GL_DOUBLE_MAT3 */ -/* reuse GL_DOUBLE_MAT4 */ -/* reuse GL_DOUBLE_MAT2x3 */ -/* reuse GL_DOUBLE_MAT2x4 */ -/* reuse GL_DOUBLE_MAT3x2 */ -/* reuse GL_DOUBLE_MAT3x4 */ -/* reuse GL_DOUBLE_MAT4x2 */ -/* reuse GL_DOUBLE_MAT4x3 */ -#endif - -#ifndef GL_ARB_viewport_array -/* reuse GL_SCISSOR_BOX */ -/* reuse GL_VIEWPORT */ -/* reuse GL_DEPTH_RANGE */ -/* reuse GL_SCISSOR_TEST */ -#define GL_MAX_VIEWPORTS 0x825B -#define GL_VIEWPORT_SUBPIXEL_BITS 0x825C -#define GL_VIEWPORT_BOUNDS_RANGE 0x825D -#define GL_LAYER_PROVOKING_VERTEX 0x825E -#define GL_VIEWPORT_INDEX_PROVOKING_VERTEX 0x825F -#define GL_UNDEFINED_VERTEX 0x8260 -/* reuse GL_FIRST_VERTEX_CONVENTION */ -/* reuse GL_LAST_VERTEX_CONVENTION */ -/* reuse GL_PROVOKING_VERTEX */ -#endif - -#ifndef GL_ARB_cl_event -#define GL_SYNC_CL_EVENT_ARB 0x8240 -#define GL_SYNC_CL_EVENT_COMPLETE_ARB 0x8241 -#endif - -#ifndef GL_ARB_debug_output -#define GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242 -#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243 -#define GL_DEBUG_CALLBACK_FUNCTION_ARB 0x8244 -#define GL_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245 -#define GL_DEBUG_SOURCE_API_ARB 0x8246 -#define GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247 -#define GL_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248 -#define GL_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249 -#define GL_DEBUG_SOURCE_APPLICATION_ARB 0x824A -#define GL_DEBUG_SOURCE_OTHER_ARB 0x824B -#define GL_DEBUG_TYPE_ERROR_ARB 0x824C -#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D -#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E -#define GL_DEBUG_TYPE_PORTABILITY_ARB 0x824F -#define GL_DEBUG_TYPE_PERFORMANCE_ARB 0x8250 -#define GL_DEBUG_TYPE_OTHER_ARB 0x8251 -#define GL_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143 -#define GL_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144 -#define GL_DEBUG_LOGGED_MESSAGES_ARB 0x9145 -#define GL_DEBUG_SEVERITY_HIGH_ARB 0x9146 -#define GL_DEBUG_SEVERITY_MEDIUM_ARB 0x9147 -#define GL_DEBUG_SEVERITY_LOW_ARB 0x9148 -#endif - -#ifndef GL_ARB_robustness -/* reuse GL_NO_ERROR */ -#define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB 0x00000004 -#define GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 -#define GL_GUILTY_CONTEXT_RESET_ARB 0x8253 -#define GL_INNOCENT_CONTEXT_RESET_ARB 0x8254 -#define GL_UNKNOWN_CONTEXT_RESET_ARB 0x8255 -#define GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 -#define GL_NO_RESET_NOTIFICATION_ARB 0x8261 -#endif - -#ifndef GL_ARB_shader_stencil_export -#endif - -#ifndef GL_ARB_base_instance -#endif - -#ifndef GL_ARB_shading_language_420pack -#endif - -#ifndef GL_ARB_transform_feedback_instanced -#endif - -#ifndef GL_ARB_compressed_texture_pixel_storage -#define GL_UNPACK_COMPRESSED_BLOCK_WIDTH 0x9127 -#define GL_UNPACK_COMPRESSED_BLOCK_HEIGHT 0x9128 -#define GL_UNPACK_COMPRESSED_BLOCK_DEPTH 0x9129 -#define GL_UNPACK_COMPRESSED_BLOCK_SIZE 0x912A -#define GL_PACK_COMPRESSED_BLOCK_WIDTH 0x912B -#define GL_PACK_COMPRESSED_BLOCK_HEIGHT 0x912C -#define GL_PACK_COMPRESSED_BLOCK_DEPTH 0x912D -#define GL_PACK_COMPRESSED_BLOCK_SIZE 0x912E -#endif - -#ifndef GL_ARB_conservative_depth -#endif - -#ifndef GL_ARB_internalformat_query -#define GL_NUM_SAMPLE_COUNTS 0x9380 -#endif - -#ifndef GL_ARB_map_buffer_alignment -#define GL_MIN_MAP_BUFFER_ALIGNMENT 0x90BC -#endif - -#ifndef GL_ARB_shader_atomic_counters -#define GL_ATOMIC_COUNTER_BUFFER 0x92C0 -#define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1 -#define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2 -#define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3 -#define GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE 0x92C4 -#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS 0x92C5 -#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES 0x92C6 -#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER 0x92C7 -#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER 0x92C8 -#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER 0x92C9 -#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER 0x92CA -#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER 0x92CB -#define GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC -#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS 0x92CD -#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS 0x92CE -#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF -#define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0 -#define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1 -#define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2 -#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3 -#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4 -#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5 -#define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6 -#define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7 -#define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8 -#define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC -#define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9 -#define GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX 0x92DA -#define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB -#endif - -#ifndef GL_ARB_shader_image_load_store -#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001 -#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002 -#define GL_UNIFORM_BARRIER_BIT 0x00000004 -#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008 -#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020 -#define GL_COMMAND_BARRIER_BIT 0x00000040 -#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080 -#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100 -#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200 -#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400 -#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800 -#define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000 -#define GL_ALL_BARRIER_BITS 0xFFFFFFFF -#define GL_MAX_IMAGE_UNITS 0x8F38 -#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39 -#define GL_IMAGE_BINDING_NAME 0x8F3A -#define GL_IMAGE_BINDING_LEVEL 0x8F3B -#define GL_IMAGE_BINDING_LAYERED 0x8F3C -#define GL_IMAGE_BINDING_LAYER 0x8F3D -#define GL_IMAGE_BINDING_ACCESS 0x8F3E -#define GL_IMAGE_1D 0x904C -#define GL_IMAGE_2D 0x904D -#define GL_IMAGE_3D 0x904E -#define GL_IMAGE_2D_RECT 0x904F -#define GL_IMAGE_CUBE 0x9050 -#define GL_IMAGE_BUFFER 0x9051 -#define GL_IMAGE_1D_ARRAY 0x9052 -#define GL_IMAGE_2D_ARRAY 0x9053 -#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054 -#define GL_IMAGE_2D_MULTISAMPLE 0x9055 -#define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056 -#define GL_INT_IMAGE_1D 0x9057 -#define GL_INT_IMAGE_2D 0x9058 -#define GL_INT_IMAGE_3D 0x9059 -#define GL_INT_IMAGE_2D_RECT 0x905A -#define GL_INT_IMAGE_CUBE 0x905B -#define GL_INT_IMAGE_BUFFER 0x905C -#define GL_INT_IMAGE_1D_ARRAY 0x905D -#define GL_INT_IMAGE_2D_ARRAY 0x905E -#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F -#define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060 -#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061 -#define GL_UNSIGNED_INT_IMAGE_1D 0x9062 -#define GL_UNSIGNED_INT_IMAGE_2D 0x9063 -#define GL_UNSIGNED_INT_IMAGE_3D 0x9064 -#define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065 -#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066 -#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067 -#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068 -#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069 -#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A -#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B -#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C -#define GL_MAX_IMAGE_SAMPLES 0x906D -#define GL_IMAGE_BINDING_FORMAT 0x906E -#define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7 -#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8 -#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9 -#define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA -#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB -#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC -#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD -#define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE -#define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF -#endif - -#ifndef GL_ARB_shading_language_packing -#endif - -#ifndef GL_ARB_texture_storage -#define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F -#endif - -#ifndef GL_EXT_abgr -#define GL_ABGR_EXT 0x8000 -#endif - -#ifndef GL_EXT_blend_color -#define GL_CONSTANT_COLOR_EXT 0x8001 -#define GL_ONE_MINUS_CONSTANT_COLOR_EXT 0x8002 -#define GL_CONSTANT_ALPHA_EXT 0x8003 -#define GL_ONE_MINUS_CONSTANT_ALPHA_EXT 0x8004 -#define GL_BLEND_COLOR_EXT 0x8005 -#endif - -#ifndef GL_EXT_polygon_offset -#define GL_POLYGON_OFFSET_EXT 0x8037 -#define GL_POLYGON_OFFSET_FACTOR_EXT 0x8038 -#define GL_POLYGON_OFFSET_BIAS_EXT 0x8039 -#endif - -#ifndef GL_EXT_texture -#define GL_ALPHA4_EXT 0x803B -#define GL_ALPHA8_EXT 0x803C -#define GL_ALPHA12_EXT 0x803D -#define GL_ALPHA16_EXT 0x803E -#define GL_LUMINANCE4_EXT 0x803F -#define GL_LUMINANCE8_EXT 0x8040 -#define GL_LUMINANCE12_EXT 0x8041 -#define GL_LUMINANCE16_EXT 0x8042 -#define GL_LUMINANCE4_ALPHA4_EXT 0x8043 -#define GL_LUMINANCE6_ALPHA2_EXT 0x8044 -#define GL_LUMINANCE8_ALPHA8_EXT 0x8045 -#define GL_LUMINANCE12_ALPHA4_EXT 0x8046 -#define GL_LUMINANCE12_ALPHA12_EXT 0x8047 -#define GL_LUMINANCE16_ALPHA16_EXT 0x8048 -#define GL_INTENSITY_EXT 0x8049 -#define GL_INTENSITY4_EXT 0x804A -#define GL_INTENSITY8_EXT 0x804B -#define GL_INTENSITY12_EXT 0x804C -#define GL_INTENSITY16_EXT 0x804D -#define GL_RGB2_EXT 0x804E -#define GL_RGB4_EXT 0x804F -#define GL_RGB5_EXT 0x8050 -#define GL_RGB8_EXT 0x8051 -#define GL_RGB10_EXT 0x8052 -#define GL_RGB12_EXT 0x8053 -#define GL_RGB16_EXT 0x8054 -#define GL_RGBA2_EXT 0x8055 -#define GL_RGBA4_EXT 0x8056 -#define GL_RGB5_A1_EXT 0x8057 -#define GL_RGBA8_EXT 0x8058 -#define GL_RGB10_A2_EXT 0x8059 -#define GL_RGBA12_EXT 0x805A -#define GL_RGBA16_EXT 0x805B -#define GL_TEXTURE_RED_SIZE_EXT 0x805C -#define GL_TEXTURE_GREEN_SIZE_EXT 0x805D -#define GL_TEXTURE_BLUE_SIZE_EXT 0x805E -#define GL_TEXTURE_ALPHA_SIZE_EXT 0x805F -#define GL_TEXTURE_LUMINANCE_SIZE_EXT 0x8060 -#define GL_TEXTURE_INTENSITY_SIZE_EXT 0x8061 -#define GL_REPLACE_EXT 0x8062 -#define GL_PROXY_TEXTURE_1D_EXT 0x8063 -#define GL_PROXY_TEXTURE_2D_EXT 0x8064 -#define GL_TEXTURE_TOO_LARGE_EXT 0x8065 -#endif - -#ifndef GL_EXT_texture3D -#define GL_PACK_SKIP_IMAGES_EXT 0x806B -#define GL_PACK_IMAGE_HEIGHT_EXT 0x806C -#define GL_UNPACK_SKIP_IMAGES_EXT 0x806D -#define GL_UNPACK_IMAGE_HEIGHT_EXT 0x806E -#define GL_TEXTURE_3D_EXT 0x806F -#define GL_PROXY_TEXTURE_3D_EXT 0x8070 -#define GL_TEXTURE_DEPTH_EXT 0x8071 -#define GL_TEXTURE_WRAP_R_EXT 0x8072 -#define GL_MAX_3D_TEXTURE_SIZE_EXT 0x8073 -#endif - -#ifndef GL_SGIS_texture_filter4 -#define GL_FILTER4_SGIS 0x8146 -#define GL_TEXTURE_FILTER4_SIZE_SGIS 0x8147 -#endif - -#ifndef GL_EXT_subtexture -#endif - -#ifndef GL_EXT_copy_texture -#endif - -#ifndef GL_EXT_histogram -#define GL_HISTOGRAM_EXT 0x8024 -#define GL_PROXY_HISTOGRAM_EXT 0x8025 -#define GL_HISTOGRAM_WIDTH_EXT 0x8026 -#define GL_HISTOGRAM_FORMAT_EXT 0x8027 -#define GL_HISTOGRAM_RED_SIZE_EXT 0x8028 -#define GL_HISTOGRAM_GREEN_SIZE_EXT 0x8029 -#define GL_HISTOGRAM_BLUE_SIZE_EXT 0x802A -#define GL_HISTOGRAM_ALPHA_SIZE_EXT 0x802B -#define GL_HISTOGRAM_LUMINANCE_SIZE_EXT 0x802C -#define GL_HISTOGRAM_SINK_EXT 0x802D -#define GL_MINMAX_EXT 0x802E -#define GL_MINMAX_FORMAT_EXT 0x802F -#define GL_MINMAX_SINK_EXT 0x8030 -#define GL_TABLE_TOO_LARGE_EXT 0x8031 -#endif - -#ifndef GL_EXT_convolution -#define GL_CONVOLUTION_1D_EXT 0x8010 -#define GL_CONVOLUTION_2D_EXT 0x8011 -#define GL_SEPARABLE_2D_EXT 0x8012 -#define GL_CONVOLUTION_BORDER_MODE_EXT 0x8013 -#define GL_CONVOLUTION_FILTER_SCALE_EXT 0x8014 -#define GL_CONVOLUTION_FILTER_BIAS_EXT 0x8015 -#define GL_REDUCE_EXT 0x8016 -#define GL_CONVOLUTION_FORMAT_EXT 0x8017 -#define GL_CONVOLUTION_WIDTH_EXT 0x8018 -#define GL_CONVOLUTION_HEIGHT_EXT 0x8019 -#define GL_MAX_CONVOLUTION_WIDTH_EXT 0x801A -#define GL_MAX_CONVOLUTION_HEIGHT_EXT 0x801B -#define GL_POST_CONVOLUTION_RED_SCALE_EXT 0x801C -#define GL_POST_CONVOLUTION_GREEN_SCALE_EXT 0x801D -#define GL_POST_CONVOLUTION_BLUE_SCALE_EXT 0x801E -#define GL_POST_CONVOLUTION_ALPHA_SCALE_EXT 0x801F -#define GL_POST_CONVOLUTION_RED_BIAS_EXT 0x8020 -#define GL_POST_CONVOLUTION_GREEN_BIAS_EXT 0x8021 -#define GL_POST_CONVOLUTION_BLUE_BIAS_EXT 0x8022 -#define GL_POST_CONVOLUTION_ALPHA_BIAS_EXT 0x8023 -#endif - -#ifndef GL_SGI_color_matrix -#define GL_COLOR_MATRIX_SGI 0x80B1 -#define GL_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B2 -#define GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B3 -#define GL_POST_COLOR_MATRIX_RED_SCALE_SGI 0x80B4 -#define GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI 0x80B5 -#define GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI 0x80B6 -#define GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI 0x80B7 -#define GL_POST_COLOR_MATRIX_RED_BIAS_SGI 0x80B8 -#define GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI 0x80B9 -#define GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI 0x80BA -#define GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI 0x80BB -#endif - -#ifndef GL_SGI_color_table -#define GL_COLOR_TABLE_SGI 0x80D0 -#define GL_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D1 -#define GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D2 -#define GL_PROXY_COLOR_TABLE_SGI 0x80D3 -#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D4 -#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D5 -#define GL_COLOR_TABLE_SCALE_SGI 0x80D6 -#define GL_COLOR_TABLE_BIAS_SGI 0x80D7 -#define GL_COLOR_TABLE_FORMAT_SGI 0x80D8 -#define GL_COLOR_TABLE_WIDTH_SGI 0x80D9 -#define GL_COLOR_TABLE_RED_SIZE_SGI 0x80DA -#define GL_COLOR_TABLE_GREEN_SIZE_SGI 0x80DB -#define GL_COLOR_TABLE_BLUE_SIZE_SGI 0x80DC -#define GL_COLOR_TABLE_ALPHA_SIZE_SGI 0x80DD -#define GL_COLOR_TABLE_LUMINANCE_SIZE_SGI 0x80DE -#define GL_COLOR_TABLE_INTENSITY_SIZE_SGI 0x80DF -#endif - -#ifndef GL_SGIS_pixel_texture -#define GL_PIXEL_TEXTURE_SGIS 0x8353 -#define GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS 0x8354 -#define GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS 0x8355 -#define GL_PIXEL_GROUP_COLOR_SGIS 0x8356 -#endif - -#ifndef GL_SGIX_pixel_texture -#define GL_PIXEL_TEX_GEN_SGIX 0x8139 -#define GL_PIXEL_TEX_GEN_MODE_SGIX 0x832B -#endif - -#ifndef GL_SGIS_texture4D -#define GL_PACK_SKIP_VOLUMES_SGIS 0x8130 -#define GL_PACK_IMAGE_DEPTH_SGIS 0x8131 -#define GL_UNPACK_SKIP_VOLUMES_SGIS 0x8132 -#define GL_UNPACK_IMAGE_DEPTH_SGIS 0x8133 -#define GL_TEXTURE_4D_SGIS 0x8134 -#define GL_PROXY_TEXTURE_4D_SGIS 0x8135 -#define GL_TEXTURE_4DSIZE_SGIS 0x8136 -#define GL_TEXTURE_WRAP_Q_SGIS 0x8137 -#define GL_MAX_4D_TEXTURE_SIZE_SGIS 0x8138 -#define GL_TEXTURE_4D_BINDING_SGIS 0x814F -#endif - -#ifndef GL_SGI_texture_color_table -#define GL_TEXTURE_COLOR_TABLE_SGI 0x80BC -#define GL_PROXY_TEXTURE_COLOR_TABLE_SGI 0x80BD -#endif - -#ifndef GL_EXT_cmyka -#define GL_CMYK_EXT 0x800C -#define GL_CMYKA_EXT 0x800D -#define GL_PACK_CMYK_HINT_EXT 0x800E -#define GL_UNPACK_CMYK_HINT_EXT 0x800F -#endif - -#ifndef GL_EXT_texture_object -#define GL_TEXTURE_PRIORITY_EXT 0x8066 -#define GL_TEXTURE_RESIDENT_EXT 0x8067 -#define GL_TEXTURE_1D_BINDING_EXT 0x8068 -#define GL_TEXTURE_2D_BINDING_EXT 0x8069 -#define GL_TEXTURE_3D_BINDING_EXT 0x806A -#endif - -#ifndef GL_SGIS_detail_texture -#define GL_DETAIL_TEXTURE_2D_SGIS 0x8095 -#define GL_DETAIL_TEXTURE_2D_BINDING_SGIS 0x8096 -#define GL_LINEAR_DETAIL_SGIS 0x8097 -#define GL_LINEAR_DETAIL_ALPHA_SGIS 0x8098 -#define GL_LINEAR_DETAIL_COLOR_SGIS 0x8099 -#define GL_DETAIL_TEXTURE_LEVEL_SGIS 0x809A -#define GL_DETAIL_TEXTURE_MODE_SGIS 0x809B -#define GL_DETAIL_TEXTURE_FUNC_POINTS_SGIS 0x809C -#endif - -#ifndef GL_SGIS_sharpen_texture -#define GL_LINEAR_SHARPEN_SGIS 0x80AD -#define GL_LINEAR_SHARPEN_ALPHA_SGIS 0x80AE -#define GL_LINEAR_SHARPEN_COLOR_SGIS 0x80AF -#define GL_SHARPEN_TEXTURE_FUNC_POINTS_SGIS 0x80B0 -#endif - -#ifndef GL_EXT_packed_pixels -#define GL_UNSIGNED_BYTE_3_3_2_EXT 0x8032 -#define GL_UNSIGNED_SHORT_4_4_4_4_EXT 0x8033 -#define GL_UNSIGNED_SHORT_5_5_5_1_EXT 0x8034 -#define GL_UNSIGNED_INT_8_8_8_8_EXT 0x8035 -#define GL_UNSIGNED_INT_10_10_10_2_EXT 0x8036 -#endif - -#ifndef GL_SGIS_texture_lod -#define GL_TEXTURE_MIN_LOD_SGIS 0x813A -#define GL_TEXTURE_MAX_LOD_SGIS 0x813B -#define GL_TEXTURE_BASE_LEVEL_SGIS 0x813C -#define GL_TEXTURE_MAX_LEVEL_SGIS 0x813D -#endif - -#ifndef GL_SGIS_multisample -#define GL_MULTISAMPLE_SGIS 0x809D -#define GL_SAMPLE_ALPHA_TO_MASK_SGIS 0x809E -#define GL_SAMPLE_ALPHA_TO_ONE_SGIS 0x809F -#define GL_SAMPLE_MASK_SGIS 0x80A0 -#define GL_1PASS_SGIS 0x80A1 -#define GL_2PASS_0_SGIS 0x80A2 -#define GL_2PASS_1_SGIS 0x80A3 -#define GL_4PASS_0_SGIS 0x80A4 -#define GL_4PASS_1_SGIS 0x80A5 -#define GL_4PASS_2_SGIS 0x80A6 -#define GL_4PASS_3_SGIS 0x80A7 -#define GL_SAMPLE_BUFFERS_SGIS 0x80A8 -#define GL_SAMPLES_SGIS 0x80A9 -#define GL_SAMPLE_MASK_VALUE_SGIS 0x80AA -#define GL_SAMPLE_MASK_INVERT_SGIS 0x80AB -#define GL_SAMPLE_PATTERN_SGIS 0x80AC -#endif - -#ifndef GL_EXT_rescale_normal -#define GL_RESCALE_NORMAL_EXT 0x803A -#endif - -#ifndef GL_EXT_vertex_array -#define GL_VERTEX_ARRAY_EXT 0x8074 -#define GL_NORMAL_ARRAY_EXT 0x8075 -#define GL_COLOR_ARRAY_EXT 0x8076 -#define GL_INDEX_ARRAY_EXT 0x8077 -#define GL_TEXTURE_COORD_ARRAY_EXT 0x8078 -#define GL_EDGE_FLAG_ARRAY_EXT 0x8079 -#define GL_VERTEX_ARRAY_SIZE_EXT 0x807A -#define GL_VERTEX_ARRAY_TYPE_EXT 0x807B -#define GL_VERTEX_ARRAY_STRIDE_EXT 0x807C -#define GL_VERTEX_ARRAY_COUNT_EXT 0x807D -#define GL_NORMAL_ARRAY_TYPE_EXT 0x807E -#define GL_NORMAL_ARRAY_STRIDE_EXT 0x807F -#define GL_NORMAL_ARRAY_COUNT_EXT 0x8080 -#define GL_COLOR_ARRAY_SIZE_EXT 0x8081 -#define GL_COLOR_ARRAY_TYPE_EXT 0x8082 -#define GL_COLOR_ARRAY_STRIDE_EXT 0x8083 -#define GL_COLOR_ARRAY_COUNT_EXT 0x8084 -#define GL_INDEX_ARRAY_TYPE_EXT 0x8085 -#define GL_INDEX_ARRAY_STRIDE_EXT 0x8086 -#define GL_INDEX_ARRAY_COUNT_EXT 0x8087 -#define GL_TEXTURE_COORD_ARRAY_SIZE_EXT 0x8088 -#define GL_TEXTURE_COORD_ARRAY_TYPE_EXT 0x8089 -#define GL_TEXTURE_COORD_ARRAY_STRIDE_EXT 0x808A -#define GL_TEXTURE_COORD_ARRAY_COUNT_EXT 0x808B -#define GL_EDGE_FLAG_ARRAY_STRIDE_EXT 0x808C -#define GL_EDGE_FLAG_ARRAY_COUNT_EXT 0x808D -#define GL_VERTEX_ARRAY_POINTER_EXT 0x808E -#define GL_NORMAL_ARRAY_POINTER_EXT 0x808F -#define GL_COLOR_ARRAY_POINTER_EXT 0x8090 -#define GL_INDEX_ARRAY_POINTER_EXT 0x8091 -#define GL_TEXTURE_COORD_ARRAY_POINTER_EXT 0x8092 -#define GL_EDGE_FLAG_ARRAY_POINTER_EXT 0x8093 -#endif - -#ifndef GL_EXT_misc_attribute -#endif - -#ifndef GL_SGIS_generate_mipmap -#define GL_GENERATE_MIPMAP_SGIS 0x8191 -#define GL_GENERATE_MIPMAP_HINT_SGIS 0x8192 -#endif - -#ifndef GL_SGIX_clipmap -#define GL_LINEAR_CLIPMAP_LINEAR_SGIX 0x8170 -#define GL_TEXTURE_CLIPMAP_CENTER_SGIX 0x8171 -#define GL_TEXTURE_CLIPMAP_FRAME_SGIX 0x8172 -#define GL_TEXTURE_CLIPMAP_OFFSET_SGIX 0x8173 -#define GL_TEXTURE_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8174 -#define GL_TEXTURE_CLIPMAP_LOD_OFFSET_SGIX 0x8175 -#define GL_TEXTURE_CLIPMAP_DEPTH_SGIX 0x8176 -#define GL_MAX_CLIPMAP_DEPTH_SGIX 0x8177 -#define GL_MAX_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8178 -#define GL_NEAREST_CLIPMAP_NEAREST_SGIX 0x844D -#define GL_NEAREST_CLIPMAP_LINEAR_SGIX 0x844E -#define GL_LINEAR_CLIPMAP_NEAREST_SGIX 0x844F -#endif - -#ifndef GL_SGIX_shadow -#define GL_TEXTURE_COMPARE_SGIX 0x819A -#define GL_TEXTURE_COMPARE_OPERATOR_SGIX 0x819B -#define GL_TEXTURE_LEQUAL_R_SGIX 0x819C -#define GL_TEXTURE_GEQUAL_R_SGIX 0x819D -#endif - -#ifndef GL_SGIS_texture_edge_clamp -#define GL_CLAMP_TO_EDGE_SGIS 0x812F -#endif - -#ifndef GL_SGIS_texture_border_clamp -#define GL_CLAMP_TO_BORDER_SGIS 0x812D -#endif - -#ifndef GL_EXT_blend_minmax -#define GL_FUNC_ADD_EXT 0x8006 -#define GL_MIN_EXT 0x8007 -#define GL_MAX_EXT 0x8008 -#define GL_BLEND_EQUATION_EXT 0x8009 -#endif - -#ifndef GL_EXT_blend_subtract -#define GL_FUNC_SUBTRACT_EXT 0x800A -#define GL_FUNC_REVERSE_SUBTRACT_EXT 0x800B -#endif - -#ifndef GL_EXT_blend_logic_op -#endif - -#ifndef GL_SGIX_interlace -#define GL_INTERLACE_SGIX 0x8094 -#endif - -#ifndef GL_SGIX_pixel_tiles -#define GL_PIXEL_TILE_BEST_ALIGNMENT_SGIX 0x813E -#define GL_PIXEL_TILE_CACHE_INCREMENT_SGIX 0x813F -#define GL_PIXEL_TILE_WIDTH_SGIX 0x8140 -#define GL_PIXEL_TILE_HEIGHT_SGIX 0x8141 -#define GL_PIXEL_TILE_GRID_WIDTH_SGIX 0x8142 -#define GL_PIXEL_TILE_GRID_HEIGHT_SGIX 0x8143 -#define GL_PIXEL_TILE_GRID_DEPTH_SGIX 0x8144 -#define GL_PIXEL_TILE_CACHE_SIZE_SGIX 0x8145 -#endif - -#ifndef GL_SGIS_texture_select -#define GL_DUAL_ALPHA4_SGIS 0x8110 -#define GL_DUAL_ALPHA8_SGIS 0x8111 -#define GL_DUAL_ALPHA12_SGIS 0x8112 -#define GL_DUAL_ALPHA16_SGIS 0x8113 -#define GL_DUAL_LUMINANCE4_SGIS 0x8114 -#define GL_DUAL_LUMINANCE8_SGIS 0x8115 -#define GL_DUAL_LUMINANCE12_SGIS 0x8116 -#define GL_DUAL_LUMINANCE16_SGIS 0x8117 -#define GL_DUAL_INTENSITY4_SGIS 0x8118 -#define GL_DUAL_INTENSITY8_SGIS 0x8119 -#define GL_DUAL_INTENSITY12_SGIS 0x811A -#define GL_DUAL_INTENSITY16_SGIS 0x811B -#define GL_DUAL_LUMINANCE_ALPHA4_SGIS 0x811C -#define GL_DUAL_LUMINANCE_ALPHA8_SGIS 0x811D -#define GL_QUAD_ALPHA4_SGIS 0x811E -#define GL_QUAD_ALPHA8_SGIS 0x811F -#define GL_QUAD_LUMINANCE4_SGIS 0x8120 -#define GL_QUAD_LUMINANCE8_SGIS 0x8121 -#define GL_QUAD_INTENSITY4_SGIS 0x8122 -#define GL_QUAD_INTENSITY8_SGIS 0x8123 -#define GL_DUAL_TEXTURE_SELECT_SGIS 0x8124 -#define GL_QUAD_TEXTURE_SELECT_SGIS 0x8125 -#endif - -#ifndef GL_SGIX_sprite -#define GL_SPRITE_SGIX 0x8148 -#define GL_SPRITE_MODE_SGIX 0x8149 -#define GL_SPRITE_AXIS_SGIX 0x814A -#define GL_SPRITE_TRANSLATION_SGIX 0x814B -#define GL_SPRITE_AXIAL_SGIX 0x814C -#define GL_SPRITE_OBJECT_ALIGNED_SGIX 0x814D -#define GL_SPRITE_EYE_ALIGNED_SGIX 0x814E -#endif - -#ifndef GL_SGIX_texture_multi_buffer -#define GL_TEXTURE_MULTI_BUFFER_HINT_SGIX 0x812E -#endif - -#ifndef GL_EXT_point_parameters -#define GL_POINT_SIZE_MIN_EXT 0x8126 -#define GL_POINT_SIZE_MAX_EXT 0x8127 -#define GL_POINT_FADE_THRESHOLD_SIZE_EXT 0x8128 -#define GL_DISTANCE_ATTENUATION_EXT 0x8129 -#endif - -#ifndef GL_SGIS_point_parameters -#define GL_POINT_SIZE_MIN_SGIS 0x8126 -#define GL_POINT_SIZE_MAX_SGIS 0x8127 -#define GL_POINT_FADE_THRESHOLD_SIZE_SGIS 0x8128 -#define GL_DISTANCE_ATTENUATION_SGIS 0x8129 -#endif - -#ifndef GL_SGIX_instruments -#define GL_INSTRUMENT_BUFFER_POINTER_SGIX 0x8180 -#define GL_INSTRUMENT_MEASUREMENTS_SGIX 0x8181 -#endif - -#ifndef GL_SGIX_texture_scale_bias -#define GL_POST_TEXTURE_FILTER_BIAS_SGIX 0x8179 -#define GL_POST_TEXTURE_FILTER_SCALE_SGIX 0x817A -#define GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX 0x817B -#define GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX 0x817C -#endif - -#ifndef GL_SGIX_framezoom -#define GL_FRAMEZOOM_SGIX 0x818B -#define GL_FRAMEZOOM_FACTOR_SGIX 0x818C -#define GL_MAX_FRAMEZOOM_FACTOR_SGIX 0x818D -#endif - -#ifndef GL_SGIX_tag_sample_buffer -#endif - -#ifndef GL_FfdMaskSGIX -#define GL_TEXTURE_DEFORMATION_BIT_SGIX 0x00000001 -#define GL_GEOMETRY_DEFORMATION_BIT_SGIX 0x00000002 -#endif - -#ifndef GL_SGIX_polynomial_ffd -#define GL_GEOMETRY_DEFORMATION_SGIX 0x8194 -#define GL_TEXTURE_DEFORMATION_SGIX 0x8195 -#define GL_DEFORMATIONS_MASK_SGIX 0x8196 -#define GL_MAX_DEFORMATION_ORDER_SGIX 0x8197 -#endif - -#ifndef GL_SGIX_reference_plane -#define GL_REFERENCE_PLANE_SGIX 0x817D -#define GL_REFERENCE_PLANE_EQUATION_SGIX 0x817E -#endif - -#ifndef GL_SGIX_flush_raster -#endif - -#ifndef GL_SGIX_depth_texture -#define GL_DEPTH_COMPONENT16_SGIX 0x81A5 -#define GL_DEPTH_COMPONENT24_SGIX 0x81A6 -#define GL_DEPTH_COMPONENT32_SGIX 0x81A7 -#endif - -#ifndef GL_SGIS_fog_function -#define GL_FOG_FUNC_SGIS 0x812A -#define GL_FOG_FUNC_POINTS_SGIS 0x812B -#define GL_MAX_FOG_FUNC_POINTS_SGIS 0x812C -#endif - -#ifndef GL_SGIX_fog_offset -#define GL_FOG_OFFSET_SGIX 0x8198 -#define GL_FOG_OFFSET_VALUE_SGIX 0x8199 -#endif - -#ifndef GL_HP_image_transform -#define GL_IMAGE_SCALE_X_HP 0x8155 -#define GL_IMAGE_SCALE_Y_HP 0x8156 -#define GL_IMAGE_TRANSLATE_X_HP 0x8157 -#define GL_IMAGE_TRANSLATE_Y_HP 0x8158 -#define GL_IMAGE_ROTATE_ANGLE_HP 0x8159 -#define GL_IMAGE_ROTATE_ORIGIN_X_HP 0x815A -#define GL_IMAGE_ROTATE_ORIGIN_Y_HP 0x815B -#define GL_IMAGE_MAG_FILTER_HP 0x815C -#define GL_IMAGE_MIN_FILTER_HP 0x815D -#define GL_IMAGE_CUBIC_WEIGHT_HP 0x815E -#define GL_CUBIC_HP 0x815F -#define GL_AVERAGE_HP 0x8160 -#define GL_IMAGE_TRANSFORM_2D_HP 0x8161 -#define GL_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8162 -#define GL_PROXY_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8163 -#endif - -#ifndef GL_HP_convolution_border_modes -#define GL_IGNORE_BORDER_HP 0x8150 -#define GL_CONSTANT_BORDER_HP 0x8151 -#define GL_REPLICATE_BORDER_HP 0x8153 -#define GL_CONVOLUTION_BORDER_COLOR_HP 0x8154 -#endif - -#ifndef GL_INGR_palette_buffer -#endif - -#ifndef GL_SGIX_texture_add_env -#define GL_TEXTURE_ENV_BIAS_SGIX 0x80BE -#endif - -#ifndef GL_EXT_color_subtable -#endif - -#ifndef GL_PGI_vertex_hints -#define GL_VERTEX_DATA_HINT_PGI 0x1A22A -#define GL_VERTEX_CONSISTENT_HINT_PGI 0x1A22B -#define GL_MATERIAL_SIDE_HINT_PGI 0x1A22C -#define GL_MAX_VERTEX_HINT_PGI 0x1A22D -#define GL_COLOR3_BIT_PGI 0x00010000 -#define GL_COLOR4_BIT_PGI 0x00020000 -#define GL_EDGEFLAG_BIT_PGI 0x00040000 -#define GL_INDEX_BIT_PGI 0x00080000 -#define GL_MAT_AMBIENT_BIT_PGI 0x00100000 -#define GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI 0x00200000 -#define GL_MAT_DIFFUSE_BIT_PGI 0x00400000 -#define GL_MAT_EMISSION_BIT_PGI 0x00800000 -#define GL_MAT_COLOR_INDEXES_BIT_PGI 0x01000000 -#define GL_MAT_SHININESS_BIT_PGI 0x02000000 -#define GL_MAT_SPECULAR_BIT_PGI 0x04000000 -#define GL_NORMAL_BIT_PGI 0x08000000 -#define GL_TEXCOORD1_BIT_PGI 0x10000000 -#define GL_TEXCOORD2_BIT_PGI 0x20000000 -#define GL_TEXCOORD3_BIT_PGI 0x40000000 -#define GL_TEXCOORD4_BIT_PGI 0x80000000 -#define GL_VERTEX23_BIT_PGI 0x00000004 -#define GL_VERTEX4_BIT_PGI 0x00000008 -#endif - -#ifndef GL_PGI_misc_hints -#define GL_PREFER_DOUBLEBUFFER_HINT_PGI 0x1A1F8 -#define GL_CONSERVE_MEMORY_HINT_PGI 0x1A1FD -#define GL_RECLAIM_MEMORY_HINT_PGI 0x1A1FE -#define GL_NATIVE_GRAPHICS_HANDLE_PGI 0x1A202 -#define GL_NATIVE_GRAPHICS_BEGIN_HINT_PGI 0x1A203 -#define GL_NATIVE_GRAPHICS_END_HINT_PGI 0x1A204 -#define GL_ALWAYS_FAST_HINT_PGI 0x1A20C -#define GL_ALWAYS_SOFT_HINT_PGI 0x1A20D -#define GL_ALLOW_DRAW_OBJ_HINT_PGI 0x1A20E -#define GL_ALLOW_DRAW_WIN_HINT_PGI 0x1A20F -#define GL_ALLOW_DRAW_FRG_HINT_PGI 0x1A210 -#define GL_ALLOW_DRAW_MEM_HINT_PGI 0x1A211 -#define GL_STRICT_DEPTHFUNC_HINT_PGI 0x1A216 -#define GL_STRICT_LIGHTING_HINT_PGI 0x1A217 -#define GL_STRICT_SCISSOR_HINT_PGI 0x1A218 -#define GL_FULL_STIPPLE_HINT_PGI 0x1A219 -#define GL_CLIP_NEAR_HINT_PGI 0x1A220 -#define GL_CLIP_FAR_HINT_PGI 0x1A221 -#define GL_WIDE_LINE_HINT_PGI 0x1A222 -#define GL_BACK_NORMALS_HINT_PGI 0x1A223 -#endif - -#ifndef GL_EXT_paletted_texture -#define GL_COLOR_INDEX1_EXT 0x80E2 -#define GL_COLOR_INDEX2_EXT 0x80E3 -#define GL_COLOR_INDEX4_EXT 0x80E4 -#define GL_COLOR_INDEX8_EXT 0x80E5 -#define GL_COLOR_INDEX12_EXT 0x80E6 -#define GL_COLOR_INDEX16_EXT 0x80E7 -#define GL_TEXTURE_INDEX_SIZE_EXT 0x80ED -#endif - -#ifndef GL_EXT_clip_volume_hint -#define GL_CLIP_VOLUME_CLIPPING_HINT_EXT 0x80F0 -#endif - -#ifndef GL_SGIX_list_priority -#define GL_LIST_PRIORITY_SGIX 0x8182 -#endif - -#ifndef GL_SGIX_ir_instrument1 -#define GL_IR_INSTRUMENT1_SGIX 0x817F -#endif - -#ifndef GL_SGIX_calligraphic_fragment -#define GL_CALLIGRAPHIC_FRAGMENT_SGIX 0x8183 -#endif - -#ifndef GL_SGIX_texture_lod_bias -#define GL_TEXTURE_LOD_BIAS_S_SGIX 0x818E -#define GL_TEXTURE_LOD_BIAS_T_SGIX 0x818F -#define GL_TEXTURE_LOD_BIAS_R_SGIX 0x8190 -#endif - -#ifndef GL_SGIX_shadow_ambient -#define GL_SHADOW_AMBIENT_SGIX 0x80BF -#endif - -#ifndef GL_EXT_index_texture -#endif - -#ifndef GL_EXT_index_material -#define GL_INDEX_MATERIAL_EXT 0x81B8 -#define GL_INDEX_MATERIAL_PARAMETER_EXT 0x81B9 -#define GL_INDEX_MATERIAL_FACE_EXT 0x81BA -#endif - -#ifndef GL_EXT_index_func -#define GL_INDEX_TEST_EXT 0x81B5 -#define GL_INDEX_TEST_FUNC_EXT 0x81B6 -#define GL_INDEX_TEST_REF_EXT 0x81B7 -#endif - -#ifndef GL_EXT_index_array_formats -#define GL_IUI_V2F_EXT 0x81AD -#define GL_IUI_V3F_EXT 0x81AE -#define GL_IUI_N3F_V2F_EXT 0x81AF -#define GL_IUI_N3F_V3F_EXT 0x81B0 -#define GL_T2F_IUI_V2F_EXT 0x81B1 -#define GL_T2F_IUI_V3F_EXT 0x81B2 -#define GL_T2F_IUI_N3F_V2F_EXT 0x81B3 -#define GL_T2F_IUI_N3F_V3F_EXT 0x81B4 -#endif - -#ifndef GL_EXT_compiled_vertex_array -#define GL_ARRAY_ELEMENT_LOCK_FIRST_EXT 0x81A8 -#define GL_ARRAY_ELEMENT_LOCK_COUNT_EXT 0x81A9 -#endif - -#ifndef GL_EXT_cull_vertex -#define GL_CULL_VERTEX_EXT 0x81AA -#define GL_CULL_VERTEX_EYE_POSITION_EXT 0x81AB -#define GL_CULL_VERTEX_OBJECT_POSITION_EXT 0x81AC -#endif - -#ifndef GL_SGIX_ycrcb -#define GL_YCRCB_422_SGIX 0x81BB -#define GL_YCRCB_444_SGIX 0x81BC -#endif - -#ifndef GL_SGIX_fragment_lighting -#define GL_FRAGMENT_LIGHTING_SGIX 0x8400 -#define GL_FRAGMENT_COLOR_MATERIAL_SGIX 0x8401 -#define GL_FRAGMENT_COLOR_MATERIAL_FACE_SGIX 0x8402 -#define GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_SGIX 0x8403 -#define GL_MAX_FRAGMENT_LIGHTS_SGIX 0x8404 -#define GL_MAX_ACTIVE_LIGHTS_SGIX 0x8405 -#define GL_CURRENT_RASTER_NORMAL_SGIX 0x8406 -#define GL_LIGHT_ENV_MODE_SGIX 0x8407 -#define GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_SGIX 0x8408 -#define GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_SGIX 0x8409 -#define GL_FRAGMENT_LIGHT_MODEL_AMBIENT_SGIX 0x840A -#define GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_SGIX 0x840B -#define GL_FRAGMENT_LIGHT0_SGIX 0x840C -#define GL_FRAGMENT_LIGHT1_SGIX 0x840D -#define GL_FRAGMENT_LIGHT2_SGIX 0x840E -#define GL_FRAGMENT_LIGHT3_SGIX 0x840F -#define GL_FRAGMENT_LIGHT4_SGIX 0x8410 -#define GL_FRAGMENT_LIGHT5_SGIX 0x8411 -#define GL_FRAGMENT_LIGHT6_SGIX 0x8412 -#define GL_FRAGMENT_LIGHT7_SGIX 0x8413 -#endif - -#ifndef GL_IBM_rasterpos_clip -#define GL_RASTER_POSITION_UNCLIPPED_IBM 0x19262 -#endif - -#ifndef GL_HP_texture_lighting -#define GL_TEXTURE_LIGHTING_MODE_HP 0x8167 -#define GL_TEXTURE_POST_SPECULAR_HP 0x8168 -#define GL_TEXTURE_PRE_SPECULAR_HP 0x8169 -#endif - -#ifndef GL_EXT_draw_range_elements -#define GL_MAX_ELEMENTS_VERTICES_EXT 0x80E8 -#define GL_MAX_ELEMENTS_INDICES_EXT 0x80E9 -#endif - -#ifndef GL_WIN_phong_shading -#define GL_PHONG_WIN 0x80EA -#define GL_PHONG_HINT_WIN 0x80EB -#endif - -#ifndef GL_WIN_specular_fog -#define GL_FOG_SPECULAR_TEXTURE_WIN 0x80EC -#endif - -#ifndef GL_EXT_light_texture -#define GL_FRAGMENT_MATERIAL_EXT 0x8349 -#define GL_FRAGMENT_NORMAL_EXT 0x834A -#define GL_FRAGMENT_COLOR_EXT 0x834C -#define GL_ATTENUATION_EXT 0x834D -#define GL_SHADOW_ATTENUATION_EXT 0x834E -#define GL_TEXTURE_APPLICATION_MODE_EXT 0x834F -#define GL_TEXTURE_LIGHT_EXT 0x8350 -#define GL_TEXTURE_MATERIAL_FACE_EXT 0x8351 -#define GL_TEXTURE_MATERIAL_PARAMETER_EXT 0x8352 -/* reuse GL_FRAGMENT_DEPTH_EXT */ -#endif - -#ifndef GL_SGIX_blend_alpha_minmax -#define GL_ALPHA_MIN_SGIX 0x8320 -#define GL_ALPHA_MAX_SGIX 0x8321 -#endif - -#ifndef GL_SGIX_impact_pixel_texture -#define GL_PIXEL_TEX_GEN_Q_CEILING_SGIX 0x8184 -#define GL_PIXEL_TEX_GEN_Q_ROUND_SGIX 0x8185 -#define GL_PIXEL_TEX_GEN_Q_FLOOR_SGIX 0x8186 -#define GL_PIXEL_TEX_GEN_ALPHA_REPLACE_SGIX 0x8187 -#define GL_PIXEL_TEX_GEN_ALPHA_NO_REPLACE_SGIX 0x8188 -#define GL_PIXEL_TEX_GEN_ALPHA_LS_SGIX 0x8189 -#define GL_PIXEL_TEX_GEN_ALPHA_MS_SGIX 0x818A -#endif - -#ifndef GL_EXT_bgra -#define GL_BGR_EXT 0x80E0 -#define GL_BGRA_EXT 0x80E1 -#endif - -#ifndef GL_SGIX_async -#define GL_ASYNC_MARKER_SGIX 0x8329 -#endif - -#ifndef GL_SGIX_async_pixel -#define GL_ASYNC_TEX_IMAGE_SGIX 0x835C -#define GL_ASYNC_DRAW_PIXELS_SGIX 0x835D -#define GL_ASYNC_READ_PIXELS_SGIX 0x835E -#define GL_MAX_ASYNC_TEX_IMAGE_SGIX 0x835F -#define GL_MAX_ASYNC_DRAW_PIXELS_SGIX 0x8360 -#define GL_MAX_ASYNC_READ_PIXELS_SGIX 0x8361 -#endif - -#ifndef GL_SGIX_async_histogram -#define GL_ASYNC_HISTOGRAM_SGIX 0x832C -#define GL_MAX_ASYNC_HISTOGRAM_SGIX 0x832D -#endif - -#ifndef GL_INTEL_texture_scissor -#endif - -#ifndef GL_INTEL_parallel_arrays -#define GL_PARALLEL_ARRAYS_INTEL 0x83F4 -#define GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL 0x83F5 -#define GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL 0x83F6 -#define GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL 0x83F7 -#define GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL 0x83F8 -#endif - -#ifndef GL_HP_occlusion_test -#define GL_OCCLUSION_TEST_HP 0x8165 -#define GL_OCCLUSION_TEST_RESULT_HP 0x8166 -#endif - -#ifndef GL_EXT_pixel_transform -#define GL_PIXEL_TRANSFORM_2D_EXT 0x8330 -#define GL_PIXEL_MAG_FILTER_EXT 0x8331 -#define GL_PIXEL_MIN_FILTER_EXT 0x8332 -#define GL_PIXEL_CUBIC_WEIGHT_EXT 0x8333 -#define GL_CUBIC_EXT 0x8334 -#define GL_AVERAGE_EXT 0x8335 -#define GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8336 -#define GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8337 -#define GL_PIXEL_TRANSFORM_2D_MATRIX_EXT 0x8338 -#endif - -#ifndef GL_EXT_pixel_transform_color_table -#endif - -#ifndef GL_EXT_shared_texture_palette -#define GL_SHARED_TEXTURE_PALETTE_EXT 0x81FB -#endif - -#ifndef GL_EXT_separate_specular_color -#define GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8 -#define GL_SINGLE_COLOR_EXT 0x81F9 -#define GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA -#endif - -#ifndef GL_EXT_secondary_color -#define GL_COLOR_SUM_EXT 0x8458 -#define GL_CURRENT_SECONDARY_COLOR_EXT 0x8459 -#define GL_SECONDARY_COLOR_ARRAY_SIZE_EXT 0x845A -#define GL_SECONDARY_COLOR_ARRAY_TYPE_EXT 0x845B -#define GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT 0x845C -#define GL_SECONDARY_COLOR_ARRAY_POINTER_EXT 0x845D -#define GL_SECONDARY_COLOR_ARRAY_EXT 0x845E -#endif - -#ifndef GL_EXT_texture_perturb_normal -#define GL_PERTURB_EXT 0x85AE -#define GL_TEXTURE_NORMAL_EXT 0x85AF -#endif - -#ifndef GL_EXT_multi_draw_arrays -#endif - -#ifndef GL_EXT_fog_coord -#define GL_FOG_COORDINATE_SOURCE_EXT 0x8450 -#define GL_FOG_COORDINATE_EXT 0x8451 -#define GL_FRAGMENT_DEPTH_EXT 0x8452 -#define GL_CURRENT_FOG_COORDINATE_EXT 0x8453 -#define GL_FOG_COORDINATE_ARRAY_TYPE_EXT 0x8454 -#define GL_FOG_COORDINATE_ARRAY_STRIDE_EXT 0x8455 -#define GL_FOG_COORDINATE_ARRAY_POINTER_EXT 0x8456 -#define GL_FOG_COORDINATE_ARRAY_EXT 0x8457 -#endif - -#ifndef GL_REND_screen_coordinates -#define GL_SCREEN_COORDINATES_REND 0x8490 -#define GL_INVERTED_SCREEN_W_REND 0x8491 -#endif - -#ifndef GL_EXT_coordinate_frame -#define GL_TANGENT_ARRAY_EXT 0x8439 -#define GL_BINORMAL_ARRAY_EXT 0x843A -#define GL_CURRENT_TANGENT_EXT 0x843B -#define GL_CURRENT_BINORMAL_EXT 0x843C -#define GL_TANGENT_ARRAY_TYPE_EXT 0x843E -#define GL_TANGENT_ARRAY_STRIDE_EXT 0x843F -#define GL_BINORMAL_ARRAY_TYPE_EXT 0x8440 -#define GL_BINORMAL_ARRAY_STRIDE_EXT 0x8441 -#define GL_TANGENT_ARRAY_POINTER_EXT 0x8442 -#define GL_BINORMAL_ARRAY_POINTER_EXT 0x8443 -#define GL_MAP1_TANGENT_EXT 0x8444 -#define GL_MAP2_TANGENT_EXT 0x8445 -#define GL_MAP1_BINORMAL_EXT 0x8446 -#define GL_MAP2_BINORMAL_EXT 0x8447 -#endif - -#ifndef GL_EXT_texture_env_combine -#define GL_COMBINE_EXT 0x8570 -#define GL_COMBINE_RGB_EXT 0x8571 -#define GL_COMBINE_ALPHA_EXT 0x8572 -#define GL_RGB_SCALE_EXT 0x8573 -#define GL_ADD_SIGNED_EXT 0x8574 -#define GL_INTERPOLATE_EXT 0x8575 -#define GL_CONSTANT_EXT 0x8576 -#define GL_PRIMARY_COLOR_EXT 0x8577 -#define GL_PREVIOUS_EXT 0x8578 -#define GL_SOURCE0_RGB_EXT 0x8580 -#define GL_SOURCE1_RGB_EXT 0x8581 -#define GL_SOURCE2_RGB_EXT 0x8582 -#define GL_SOURCE0_ALPHA_EXT 0x8588 -#define GL_SOURCE1_ALPHA_EXT 0x8589 -#define GL_SOURCE2_ALPHA_EXT 0x858A -#define GL_OPERAND0_RGB_EXT 0x8590 -#define GL_OPERAND1_RGB_EXT 0x8591 -#define GL_OPERAND2_RGB_EXT 0x8592 -#define GL_OPERAND0_ALPHA_EXT 0x8598 -#define GL_OPERAND1_ALPHA_EXT 0x8599 -#define GL_OPERAND2_ALPHA_EXT 0x859A -#endif - -#ifndef GL_APPLE_specular_vector -#define GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE 0x85B0 -#endif - -#ifndef GL_APPLE_transform_hint -#define GL_TRANSFORM_HINT_APPLE 0x85B1 -#endif - -#ifndef GL_SGIX_fog_scale -#define GL_FOG_SCALE_SGIX 0x81FC -#define GL_FOG_SCALE_VALUE_SGIX 0x81FD -#endif - -#ifndef GL_SUNX_constant_data -#define GL_UNPACK_CONSTANT_DATA_SUNX 0x81D5 -#define GL_TEXTURE_CONSTANT_DATA_SUNX 0x81D6 -#endif - -#ifndef GL_SUN_global_alpha -#define GL_GLOBAL_ALPHA_SUN 0x81D9 -#define GL_GLOBAL_ALPHA_FACTOR_SUN 0x81DA -#endif - -#ifndef GL_SUN_triangle_list -#define GL_RESTART_SUN 0x0001 -#define GL_REPLACE_MIDDLE_SUN 0x0002 -#define GL_REPLACE_OLDEST_SUN 0x0003 -#define GL_TRIANGLE_LIST_SUN 0x81D7 -#define GL_REPLACEMENT_CODE_SUN 0x81D8 -#define GL_REPLACEMENT_CODE_ARRAY_SUN 0x85C0 -#define GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN 0x85C1 -#define GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN 0x85C2 -#define GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN 0x85C3 -#define GL_R1UI_V3F_SUN 0x85C4 -#define GL_R1UI_C4UB_V3F_SUN 0x85C5 -#define GL_R1UI_C3F_V3F_SUN 0x85C6 -#define GL_R1UI_N3F_V3F_SUN 0x85C7 -#define GL_R1UI_C4F_N3F_V3F_SUN 0x85C8 -#define GL_R1UI_T2F_V3F_SUN 0x85C9 -#define GL_R1UI_T2F_N3F_V3F_SUN 0x85CA -#define GL_R1UI_T2F_C4F_N3F_V3F_SUN 0x85CB -#endif - -#ifndef GL_SUN_vertex -#endif - -#ifndef GL_EXT_blend_func_separate -#define GL_BLEND_DST_RGB_EXT 0x80C8 -#define GL_BLEND_SRC_RGB_EXT 0x80C9 -#define GL_BLEND_DST_ALPHA_EXT 0x80CA -#define GL_BLEND_SRC_ALPHA_EXT 0x80CB -#endif - -#ifndef GL_INGR_color_clamp -#define GL_RED_MIN_CLAMP_INGR 0x8560 -#define GL_GREEN_MIN_CLAMP_INGR 0x8561 -#define GL_BLUE_MIN_CLAMP_INGR 0x8562 -#define GL_ALPHA_MIN_CLAMP_INGR 0x8563 -#define GL_RED_MAX_CLAMP_INGR 0x8564 -#define GL_GREEN_MAX_CLAMP_INGR 0x8565 -#define GL_BLUE_MAX_CLAMP_INGR 0x8566 -#define GL_ALPHA_MAX_CLAMP_INGR 0x8567 -#endif - -#ifndef GL_INGR_interlace_read -#define GL_INTERLACE_READ_INGR 0x8568 -#endif - -#ifndef GL_EXT_stencil_wrap -#define GL_INCR_WRAP_EXT 0x8507 -#define GL_DECR_WRAP_EXT 0x8508 -#endif - -#ifndef GL_EXT_422_pixels -#define GL_422_EXT 0x80CC -#define GL_422_REV_EXT 0x80CD -#define GL_422_AVERAGE_EXT 0x80CE -#define GL_422_REV_AVERAGE_EXT 0x80CF -#endif - -#ifndef GL_NV_texgen_reflection -#define GL_NORMAL_MAP_NV 0x8511 -#define GL_REFLECTION_MAP_NV 0x8512 -#endif - -#ifndef GL_EXT_texture_cube_map -#define GL_NORMAL_MAP_EXT 0x8511 -#define GL_REFLECTION_MAP_EXT 0x8512 -#define GL_TEXTURE_CUBE_MAP_EXT 0x8513 -#define GL_TEXTURE_BINDING_CUBE_MAP_EXT 0x8514 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT 0x8515 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT 0x8516 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT 0x8517 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT 0x8518 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT 0x8519 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT 0x851A -#define GL_PROXY_TEXTURE_CUBE_MAP_EXT 0x851B -#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT 0x851C -#endif - -#ifndef GL_SUN_convolution_border_modes -#define GL_WRAP_BORDER_SUN 0x81D4 -#endif - -#ifndef GL_EXT_texture_env_add -#endif - -#ifndef GL_EXT_texture_lod_bias -#define GL_MAX_TEXTURE_LOD_BIAS_EXT 0x84FD -#define GL_TEXTURE_FILTER_CONTROL_EXT 0x8500 -#define GL_TEXTURE_LOD_BIAS_EXT 0x8501 -#endif - -#ifndef GL_EXT_texture_filter_anisotropic -#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE -#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF -#endif - -#ifndef GL_EXT_vertex_weighting -#define GL_MODELVIEW0_STACK_DEPTH_EXT GL_MODELVIEW_STACK_DEPTH -#define GL_MODELVIEW1_STACK_DEPTH_EXT 0x8502 -#define GL_MODELVIEW0_MATRIX_EXT GL_MODELVIEW_MATRIX -#define GL_MODELVIEW1_MATRIX_EXT 0x8506 -#define GL_VERTEX_WEIGHTING_EXT 0x8509 -#define GL_MODELVIEW0_EXT GL_MODELVIEW -#define GL_MODELVIEW1_EXT 0x850A -#define GL_CURRENT_VERTEX_WEIGHT_EXT 0x850B -#define GL_VERTEX_WEIGHT_ARRAY_EXT 0x850C -#define GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT 0x850D -#define GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT 0x850E -#define GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT 0x850F -#define GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT 0x8510 -#endif - -#ifndef GL_NV_light_max_exponent -#define GL_MAX_SHININESS_NV 0x8504 -#define GL_MAX_SPOT_EXPONENT_NV 0x8505 -#endif - -#ifndef GL_NV_vertex_array_range -#define GL_VERTEX_ARRAY_RANGE_NV 0x851D -#define GL_VERTEX_ARRAY_RANGE_LENGTH_NV 0x851E -#define GL_VERTEX_ARRAY_RANGE_VALID_NV 0x851F -#define GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV 0x8520 -#define GL_VERTEX_ARRAY_RANGE_POINTER_NV 0x8521 -#endif - -#ifndef GL_NV_register_combiners -#define GL_REGISTER_COMBINERS_NV 0x8522 -#define GL_VARIABLE_A_NV 0x8523 -#define GL_VARIABLE_B_NV 0x8524 -#define GL_VARIABLE_C_NV 0x8525 -#define GL_VARIABLE_D_NV 0x8526 -#define GL_VARIABLE_E_NV 0x8527 -#define GL_VARIABLE_F_NV 0x8528 -#define GL_VARIABLE_G_NV 0x8529 -#define GL_CONSTANT_COLOR0_NV 0x852A -#define GL_CONSTANT_COLOR1_NV 0x852B -#define GL_PRIMARY_COLOR_NV 0x852C -#define GL_SECONDARY_COLOR_NV 0x852D -#define GL_SPARE0_NV 0x852E -#define GL_SPARE1_NV 0x852F -#define GL_DISCARD_NV 0x8530 -#define GL_E_TIMES_F_NV 0x8531 -#define GL_SPARE0_PLUS_SECONDARY_COLOR_NV 0x8532 -#define GL_UNSIGNED_IDENTITY_NV 0x8536 -#define GL_UNSIGNED_INVERT_NV 0x8537 -#define GL_EXPAND_NORMAL_NV 0x8538 -#define GL_EXPAND_NEGATE_NV 0x8539 -#define GL_HALF_BIAS_NORMAL_NV 0x853A -#define GL_HALF_BIAS_NEGATE_NV 0x853B -#define GL_SIGNED_IDENTITY_NV 0x853C -#define GL_SIGNED_NEGATE_NV 0x853D -#define GL_SCALE_BY_TWO_NV 0x853E -#define GL_SCALE_BY_FOUR_NV 0x853F -#define GL_SCALE_BY_ONE_HALF_NV 0x8540 -#define GL_BIAS_BY_NEGATIVE_ONE_HALF_NV 0x8541 -#define GL_COMBINER_INPUT_NV 0x8542 -#define GL_COMBINER_MAPPING_NV 0x8543 -#define GL_COMBINER_COMPONENT_USAGE_NV 0x8544 -#define GL_COMBINER_AB_DOT_PRODUCT_NV 0x8545 -#define GL_COMBINER_CD_DOT_PRODUCT_NV 0x8546 -#define GL_COMBINER_MUX_SUM_NV 0x8547 -#define GL_COMBINER_SCALE_NV 0x8548 -#define GL_COMBINER_BIAS_NV 0x8549 -#define GL_COMBINER_AB_OUTPUT_NV 0x854A -#define GL_COMBINER_CD_OUTPUT_NV 0x854B -#define GL_COMBINER_SUM_OUTPUT_NV 0x854C -#define GL_MAX_GENERAL_COMBINERS_NV 0x854D -#define GL_NUM_GENERAL_COMBINERS_NV 0x854E -#define GL_COLOR_SUM_CLAMP_NV 0x854F -#define GL_COMBINER0_NV 0x8550 -#define GL_COMBINER1_NV 0x8551 -#define GL_COMBINER2_NV 0x8552 -#define GL_COMBINER3_NV 0x8553 -#define GL_COMBINER4_NV 0x8554 -#define GL_COMBINER5_NV 0x8555 -#define GL_COMBINER6_NV 0x8556 -#define GL_COMBINER7_NV 0x8557 -/* reuse GL_TEXTURE0_ARB */ -/* reuse GL_TEXTURE1_ARB */ -/* reuse GL_ZERO */ -/* reuse GL_NONE */ -/* reuse GL_FOG */ -#endif - -#ifndef GL_NV_fog_distance -#define GL_FOG_DISTANCE_MODE_NV 0x855A -#define GL_EYE_RADIAL_NV 0x855B -#define GL_EYE_PLANE_ABSOLUTE_NV 0x855C -/* reuse GL_EYE_PLANE */ -#endif - -#ifndef GL_NV_texgen_emboss -#define GL_EMBOSS_LIGHT_NV 0x855D -#define GL_EMBOSS_CONSTANT_NV 0x855E -#define GL_EMBOSS_MAP_NV 0x855F -#endif - -#ifndef GL_NV_blend_square -#endif - -#ifndef GL_NV_texture_env_combine4 -#define GL_COMBINE4_NV 0x8503 -#define GL_SOURCE3_RGB_NV 0x8583 -#define GL_SOURCE3_ALPHA_NV 0x858B -#define GL_OPERAND3_RGB_NV 0x8593 -#define GL_OPERAND3_ALPHA_NV 0x859B -#endif - -#ifndef GL_MESA_resize_buffers -#endif - -#ifndef GL_MESA_window_pos -#endif - -#ifndef GL_EXT_texture_compression_s3tc -#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 -#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 -#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 -#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 -#endif - -#ifndef GL_IBM_cull_vertex -#define GL_CULL_VERTEX_IBM 103050 -#endif - -#ifndef GL_IBM_multimode_draw_arrays -#endif - -#ifndef GL_IBM_vertex_array_lists -#define GL_VERTEX_ARRAY_LIST_IBM 103070 -#define GL_NORMAL_ARRAY_LIST_IBM 103071 -#define GL_COLOR_ARRAY_LIST_IBM 103072 -#define GL_INDEX_ARRAY_LIST_IBM 103073 -#define GL_TEXTURE_COORD_ARRAY_LIST_IBM 103074 -#define GL_EDGE_FLAG_ARRAY_LIST_IBM 103075 -#define GL_FOG_COORDINATE_ARRAY_LIST_IBM 103076 -#define GL_SECONDARY_COLOR_ARRAY_LIST_IBM 103077 -#define GL_VERTEX_ARRAY_LIST_STRIDE_IBM 103080 -#define GL_NORMAL_ARRAY_LIST_STRIDE_IBM 103081 -#define GL_COLOR_ARRAY_LIST_STRIDE_IBM 103082 -#define GL_INDEX_ARRAY_LIST_STRIDE_IBM 103083 -#define GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM 103084 -#define GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM 103085 -#define GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM 103086 -#define GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM 103087 -#endif - -#ifndef GL_SGIX_subsample -#define GL_PACK_SUBSAMPLE_RATE_SGIX 0x85A0 -#define GL_UNPACK_SUBSAMPLE_RATE_SGIX 0x85A1 -#define GL_PIXEL_SUBSAMPLE_4444_SGIX 0x85A2 -#define GL_PIXEL_SUBSAMPLE_2424_SGIX 0x85A3 -#define GL_PIXEL_SUBSAMPLE_4242_SGIX 0x85A4 -#endif - -#ifndef GL_SGIX_ycrcb_subsample -#endif - -#ifndef GL_SGIX_ycrcba -#define GL_YCRCB_SGIX 0x8318 -#define GL_YCRCBA_SGIX 0x8319 -#endif - -#ifndef GL_SGI_depth_pass_instrument -#define GL_DEPTH_PASS_INSTRUMENT_SGIX 0x8310 -#define GL_DEPTH_PASS_INSTRUMENT_COUNTERS_SGIX 0x8311 -#define GL_DEPTH_PASS_INSTRUMENT_MAX_SGIX 0x8312 -#endif - -#ifndef GL_3DFX_texture_compression_FXT1 -#define GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0 -#define GL_COMPRESSED_RGBA_FXT1_3DFX 0x86B1 -#endif - -#ifndef GL_3DFX_multisample -#define GL_MULTISAMPLE_3DFX 0x86B2 -#define GL_SAMPLE_BUFFERS_3DFX 0x86B3 -#define GL_SAMPLES_3DFX 0x86B4 -#define GL_MULTISAMPLE_BIT_3DFX 0x20000000 -#endif - -#ifndef GL_3DFX_tbuffer -#endif - -#ifndef GL_EXT_multisample -#define GL_MULTISAMPLE_EXT 0x809D -#define GL_SAMPLE_ALPHA_TO_MASK_EXT 0x809E -#define GL_SAMPLE_ALPHA_TO_ONE_EXT 0x809F -#define GL_SAMPLE_MASK_EXT 0x80A0 -#define GL_1PASS_EXT 0x80A1 -#define GL_2PASS_0_EXT 0x80A2 -#define GL_2PASS_1_EXT 0x80A3 -#define GL_4PASS_0_EXT 0x80A4 -#define GL_4PASS_1_EXT 0x80A5 -#define GL_4PASS_2_EXT 0x80A6 -#define GL_4PASS_3_EXT 0x80A7 -#define GL_SAMPLE_BUFFERS_EXT 0x80A8 -#define GL_SAMPLES_EXT 0x80A9 -#define GL_SAMPLE_MASK_VALUE_EXT 0x80AA -#define GL_SAMPLE_MASK_INVERT_EXT 0x80AB -#define GL_SAMPLE_PATTERN_EXT 0x80AC -#define GL_MULTISAMPLE_BIT_EXT 0x20000000 -#endif - -#ifndef GL_SGIX_vertex_preclip -#define GL_VERTEX_PRECLIP_SGIX 0x83EE -#define GL_VERTEX_PRECLIP_HINT_SGIX 0x83EF -#endif - -#ifndef GL_SGIX_convolution_accuracy -#define GL_CONVOLUTION_HINT_SGIX 0x8316 -#endif - -#ifndef GL_SGIX_resample -#define GL_PACK_RESAMPLE_SGIX 0x842C -#define GL_UNPACK_RESAMPLE_SGIX 0x842D -#define GL_RESAMPLE_REPLICATE_SGIX 0x842E -#define GL_RESAMPLE_ZERO_FILL_SGIX 0x842F -#define GL_RESAMPLE_DECIMATE_SGIX 0x8430 -#endif - -#ifndef GL_SGIS_point_line_texgen -#define GL_EYE_DISTANCE_TO_POINT_SGIS 0x81F0 -#define GL_OBJECT_DISTANCE_TO_POINT_SGIS 0x81F1 -#define GL_EYE_DISTANCE_TO_LINE_SGIS 0x81F2 -#define GL_OBJECT_DISTANCE_TO_LINE_SGIS 0x81F3 -#define GL_EYE_POINT_SGIS 0x81F4 -#define GL_OBJECT_POINT_SGIS 0x81F5 -#define GL_EYE_LINE_SGIS 0x81F6 -#define GL_OBJECT_LINE_SGIS 0x81F7 -#endif - -#ifndef GL_SGIS_texture_color_mask -#define GL_TEXTURE_COLOR_WRITEMASK_SGIS 0x81EF -#endif - -#ifndef GL_EXT_texture_env_dot3 -#define GL_DOT3_RGB_EXT 0x8740 -#define GL_DOT3_RGBA_EXT 0x8741 -#endif - -#ifndef GL_ATI_texture_mirror_once -#define GL_MIRROR_CLAMP_ATI 0x8742 -#define GL_MIRROR_CLAMP_TO_EDGE_ATI 0x8743 -#endif - -#ifndef GL_NV_fence -#define GL_ALL_COMPLETED_NV 0x84F2 -#define GL_FENCE_STATUS_NV 0x84F3 -#define GL_FENCE_CONDITION_NV 0x84F4 -#endif - -#ifndef GL_IBM_texture_mirrored_repeat -#define GL_MIRRORED_REPEAT_IBM 0x8370 -#endif - -#ifndef GL_NV_evaluators -#define GL_EVAL_2D_NV 0x86C0 -#define GL_EVAL_TRIANGULAR_2D_NV 0x86C1 -#define GL_MAP_TESSELLATION_NV 0x86C2 -#define GL_MAP_ATTRIB_U_ORDER_NV 0x86C3 -#define GL_MAP_ATTRIB_V_ORDER_NV 0x86C4 -#define GL_EVAL_FRACTIONAL_TESSELLATION_NV 0x86C5 -#define GL_EVAL_VERTEX_ATTRIB0_NV 0x86C6 -#define GL_EVAL_VERTEX_ATTRIB1_NV 0x86C7 -#define GL_EVAL_VERTEX_ATTRIB2_NV 0x86C8 -#define GL_EVAL_VERTEX_ATTRIB3_NV 0x86C9 -#define GL_EVAL_VERTEX_ATTRIB4_NV 0x86CA -#define GL_EVAL_VERTEX_ATTRIB5_NV 0x86CB -#define GL_EVAL_VERTEX_ATTRIB6_NV 0x86CC -#define GL_EVAL_VERTEX_ATTRIB7_NV 0x86CD -#define GL_EVAL_VERTEX_ATTRIB8_NV 0x86CE -#define GL_EVAL_VERTEX_ATTRIB9_NV 0x86CF -#define GL_EVAL_VERTEX_ATTRIB10_NV 0x86D0 -#define GL_EVAL_VERTEX_ATTRIB11_NV 0x86D1 -#define GL_EVAL_VERTEX_ATTRIB12_NV 0x86D2 -#define GL_EVAL_VERTEX_ATTRIB13_NV 0x86D3 -#define GL_EVAL_VERTEX_ATTRIB14_NV 0x86D4 -#define GL_EVAL_VERTEX_ATTRIB15_NV 0x86D5 -#define GL_MAX_MAP_TESSELLATION_NV 0x86D6 -#define GL_MAX_RATIONAL_EVAL_ORDER_NV 0x86D7 -#endif - -#ifndef GL_NV_packed_depth_stencil -#define GL_DEPTH_STENCIL_NV 0x84F9 -#define GL_UNSIGNED_INT_24_8_NV 0x84FA -#endif - -#ifndef GL_NV_register_combiners2 -#define GL_PER_STAGE_CONSTANTS_NV 0x8535 -#endif - -#ifndef GL_NV_texture_compression_vtc -#endif - -#ifndef GL_NV_texture_rectangle -#define GL_TEXTURE_RECTANGLE_NV 0x84F5 -#define GL_TEXTURE_BINDING_RECTANGLE_NV 0x84F6 -#define GL_PROXY_TEXTURE_RECTANGLE_NV 0x84F7 -#define GL_MAX_RECTANGLE_TEXTURE_SIZE_NV 0x84F8 -#endif - -#ifndef GL_NV_texture_shader -#define GL_OFFSET_TEXTURE_RECTANGLE_NV 0x864C -#define GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV 0x864D -#define GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV 0x864E -#define GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV 0x86D9 -#define GL_UNSIGNED_INT_S8_S8_8_8_NV 0x86DA -#define GL_UNSIGNED_INT_8_8_S8_S8_REV_NV 0x86DB -#define GL_DSDT_MAG_INTENSITY_NV 0x86DC -#define GL_SHADER_CONSISTENT_NV 0x86DD -#define GL_TEXTURE_SHADER_NV 0x86DE -#define GL_SHADER_OPERATION_NV 0x86DF -#define GL_CULL_MODES_NV 0x86E0 -#define GL_OFFSET_TEXTURE_MATRIX_NV 0x86E1 -#define GL_OFFSET_TEXTURE_SCALE_NV 0x86E2 -#define GL_OFFSET_TEXTURE_BIAS_NV 0x86E3 -#define GL_OFFSET_TEXTURE_2D_MATRIX_NV GL_OFFSET_TEXTURE_MATRIX_NV -#define GL_OFFSET_TEXTURE_2D_SCALE_NV GL_OFFSET_TEXTURE_SCALE_NV -#define GL_OFFSET_TEXTURE_2D_BIAS_NV GL_OFFSET_TEXTURE_BIAS_NV -#define GL_PREVIOUS_TEXTURE_INPUT_NV 0x86E4 -#define GL_CONST_EYE_NV 0x86E5 -#define GL_PASS_THROUGH_NV 0x86E6 -#define GL_CULL_FRAGMENT_NV 0x86E7 -#define GL_OFFSET_TEXTURE_2D_NV 0x86E8 -#define GL_DEPENDENT_AR_TEXTURE_2D_NV 0x86E9 -#define GL_DEPENDENT_GB_TEXTURE_2D_NV 0x86EA -#define GL_DOT_PRODUCT_NV 0x86EC -#define GL_DOT_PRODUCT_DEPTH_REPLACE_NV 0x86ED -#define GL_DOT_PRODUCT_TEXTURE_2D_NV 0x86EE -#define GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV 0x86F0 -#define GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV 0x86F1 -#define GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV 0x86F2 -#define GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV 0x86F3 -#define GL_HILO_NV 0x86F4 -#define GL_DSDT_NV 0x86F5 -#define GL_DSDT_MAG_NV 0x86F6 -#define GL_DSDT_MAG_VIB_NV 0x86F7 -#define GL_HILO16_NV 0x86F8 -#define GL_SIGNED_HILO_NV 0x86F9 -#define GL_SIGNED_HILO16_NV 0x86FA -#define GL_SIGNED_RGBA_NV 0x86FB -#define GL_SIGNED_RGBA8_NV 0x86FC -#define GL_SIGNED_RGB_NV 0x86FE -#define GL_SIGNED_RGB8_NV 0x86FF -#define GL_SIGNED_LUMINANCE_NV 0x8701 -#define GL_SIGNED_LUMINANCE8_NV 0x8702 -#define GL_SIGNED_LUMINANCE_ALPHA_NV 0x8703 -#define GL_SIGNED_LUMINANCE8_ALPHA8_NV 0x8704 -#define GL_SIGNED_ALPHA_NV 0x8705 -#define GL_SIGNED_ALPHA8_NV 0x8706 -#define GL_SIGNED_INTENSITY_NV 0x8707 -#define GL_SIGNED_INTENSITY8_NV 0x8708 -#define GL_DSDT8_NV 0x8709 -#define GL_DSDT8_MAG8_NV 0x870A -#define GL_DSDT8_MAG8_INTENSITY8_NV 0x870B -#define GL_SIGNED_RGB_UNSIGNED_ALPHA_NV 0x870C -#define GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV 0x870D -#define GL_HI_SCALE_NV 0x870E -#define GL_LO_SCALE_NV 0x870F -#define GL_DS_SCALE_NV 0x8710 -#define GL_DT_SCALE_NV 0x8711 -#define GL_MAGNITUDE_SCALE_NV 0x8712 -#define GL_VIBRANCE_SCALE_NV 0x8713 -#define GL_HI_BIAS_NV 0x8714 -#define GL_LO_BIAS_NV 0x8715 -#define GL_DS_BIAS_NV 0x8716 -#define GL_DT_BIAS_NV 0x8717 -#define GL_MAGNITUDE_BIAS_NV 0x8718 -#define GL_VIBRANCE_BIAS_NV 0x8719 -#define GL_TEXTURE_BORDER_VALUES_NV 0x871A -#define GL_TEXTURE_HI_SIZE_NV 0x871B -#define GL_TEXTURE_LO_SIZE_NV 0x871C -#define GL_TEXTURE_DS_SIZE_NV 0x871D -#define GL_TEXTURE_DT_SIZE_NV 0x871E -#define GL_TEXTURE_MAG_SIZE_NV 0x871F -#endif - -#ifndef GL_NV_texture_shader2 -#define GL_DOT_PRODUCT_TEXTURE_3D_NV 0x86EF -#endif - -#ifndef GL_NV_vertex_array_range2 -#define GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV 0x8533 -#endif - -#ifndef GL_NV_vertex_program -#define GL_VERTEX_PROGRAM_NV 0x8620 -#define GL_VERTEX_STATE_PROGRAM_NV 0x8621 -#define GL_ATTRIB_ARRAY_SIZE_NV 0x8623 -#define GL_ATTRIB_ARRAY_STRIDE_NV 0x8624 -#define GL_ATTRIB_ARRAY_TYPE_NV 0x8625 -#define GL_CURRENT_ATTRIB_NV 0x8626 -#define GL_PROGRAM_LENGTH_NV 0x8627 -#define GL_PROGRAM_STRING_NV 0x8628 -#define GL_MODELVIEW_PROJECTION_NV 0x8629 -#define GL_IDENTITY_NV 0x862A -#define GL_INVERSE_NV 0x862B -#define GL_TRANSPOSE_NV 0x862C -#define GL_INVERSE_TRANSPOSE_NV 0x862D -#define GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV 0x862E -#define GL_MAX_TRACK_MATRICES_NV 0x862F -#define GL_MATRIX0_NV 0x8630 -#define GL_MATRIX1_NV 0x8631 -#define GL_MATRIX2_NV 0x8632 -#define GL_MATRIX3_NV 0x8633 -#define GL_MATRIX4_NV 0x8634 -#define GL_MATRIX5_NV 0x8635 -#define GL_MATRIX6_NV 0x8636 -#define GL_MATRIX7_NV 0x8637 -#define GL_CURRENT_MATRIX_STACK_DEPTH_NV 0x8640 -#define GL_CURRENT_MATRIX_NV 0x8641 -#define GL_VERTEX_PROGRAM_POINT_SIZE_NV 0x8642 -#define GL_VERTEX_PROGRAM_TWO_SIDE_NV 0x8643 -#define GL_PROGRAM_PARAMETER_NV 0x8644 -#define GL_ATTRIB_ARRAY_POINTER_NV 0x8645 -#define GL_PROGRAM_TARGET_NV 0x8646 -#define GL_PROGRAM_RESIDENT_NV 0x8647 -#define GL_TRACK_MATRIX_NV 0x8648 -#define GL_TRACK_MATRIX_TRANSFORM_NV 0x8649 -#define GL_VERTEX_PROGRAM_BINDING_NV 0x864A -#define GL_PROGRAM_ERROR_POSITION_NV 0x864B -#define GL_VERTEX_ATTRIB_ARRAY0_NV 0x8650 -#define GL_VERTEX_ATTRIB_ARRAY1_NV 0x8651 -#define GL_VERTEX_ATTRIB_ARRAY2_NV 0x8652 -#define GL_VERTEX_ATTRIB_ARRAY3_NV 0x8653 -#define GL_VERTEX_ATTRIB_ARRAY4_NV 0x8654 -#define GL_VERTEX_ATTRIB_ARRAY5_NV 0x8655 -#define GL_VERTEX_ATTRIB_ARRAY6_NV 0x8656 -#define GL_VERTEX_ATTRIB_ARRAY7_NV 0x8657 -#define GL_VERTEX_ATTRIB_ARRAY8_NV 0x8658 -#define GL_VERTEX_ATTRIB_ARRAY9_NV 0x8659 -#define GL_VERTEX_ATTRIB_ARRAY10_NV 0x865A -#define GL_VERTEX_ATTRIB_ARRAY11_NV 0x865B -#define GL_VERTEX_ATTRIB_ARRAY12_NV 0x865C -#define GL_VERTEX_ATTRIB_ARRAY13_NV 0x865D -#define GL_VERTEX_ATTRIB_ARRAY14_NV 0x865E -#define GL_VERTEX_ATTRIB_ARRAY15_NV 0x865F -#define GL_MAP1_VERTEX_ATTRIB0_4_NV 0x8660 -#define GL_MAP1_VERTEX_ATTRIB1_4_NV 0x8661 -#define GL_MAP1_VERTEX_ATTRIB2_4_NV 0x8662 -#define GL_MAP1_VERTEX_ATTRIB3_4_NV 0x8663 -#define GL_MAP1_VERTEX_ATTRIB4_4_NV 0x8664 -#define GL_MAP1_VERTEX_ATTRIB5_4_NV 0x8665 -#define GL_MAP1_VERTEX_ATTRIB6_4_NV 0x8666 -#define GL_MAP1_VERTEX_ATTRIB7_4_NV 0x8667 -#define GL_MAP1_VERTEX_ATTRIB8_4_NV 0x8668 -#define GL_MAP1_VERTEX_ATTRIB9_4_NV 0x8669 -#define GL_MAP1_VERTEX_ATTRIB10_4_NV 0x866A -#define GL_MAP1_VERTEX_ATTRIB11_4_NV 0x866B -#define GL_MAP1_VERTEX_ATTRIB12_4_NV 0x866C -#define GL_MAP1_VERTEX_ATTRIB13_4_NV 0x866D -#define GL_MAP1_VERTEX_ATTRIB14_4_NV 0x866E -#define GL_MAP1_VERTEX_ATTRIB15_4_NV 0x866F -#define GL_MAP2_VERTEX_ATTRIB0_4_NV 0x8670 -#define GL_MAP2_VERTEX_ATTRIB1_4_NV 0x8671 -#define GL_MAP2_VERTEX_ATTRIB2_4_NV 0x8672 -#define GL_MAP2_VERTEX_ATTRIB3_4_NV 0x8673 -#define GL_MAP2_VERTEX_ATTRIB4_4_NV 0x8674 -#define GL_MAP2_VERTEX_ATTRIB5_4_NV 0x8675 -#define GL_MAP2_VERTEX_ATTRIB6_4_NV 0x8676 -#define GL_MAP2_VERTEX_ATTRIB7_4_NV 0x8677 -#define GL_MAP2_VERTEX_ATTRIB8_4_NV 0x8678 -#define GL_MAP2_VERTEX_ATTRIB9_4_NV 0x8679 -#define GL_MAP2_VERTEX_ATTRIB10_4_NV 0x867A -#define GL_MAP2_VERTEX_ATTRIB11_4_NV 0x867B -#define GL_MAP2_VERTEX_ATTRIB12_4_NV 0x867C -#define GL_MAP2_VERTEX_ATTRIB13_4_NV 0x867D -#define GL_MAP2_VERTEX_ATTRIB14_4_NV 0x867E -#define GL_MAP2_VERTEX_ATTRIB15_4_NV 0x867F -#endif - -#ifndef GL_SGIX_texture_coordinate_clamp -#define GL_TEXTURE_MAX_CLAMP_S_SGIX 0x8369 -#define GL_TEXTURE_MAX_CLAMP_T_SGIX 0x836A -#define GL_TEXTURE_MAX_CLAMP_R_SGIX 0x836B -#endif - -#ifndef GL_SGIX_scalebias_hint -#define GL_SCALEBIAS_HINT_SGIX 0x8322 -#endif - -#ifndef GL_OML_interlace -#define GL_INTERLACE_OML 0x8980 -#define GL_INTERLACE_READ_OML 0x8981 -#endif - -#ifndef GL_OML_subsample -#define GL_FORMAT_SUBSAMPLE_24_24_OML 0x8982 -#define GL_FORMAT_SUBSAMPLE_244_244_OML 0x8983 -#endif - -#ifndef GL_OML_resample -#define GL_PACK_RESAMPLE_OML 0x8984 -#define GL_UNPACK_RESAMPLE_OML 0x8985 -#define GL_RESAMPLE_REPLICATE_OML 0x8986 -#define GL_RESAMPLE_ZERO_FILL_OML 0x8987 -#define GL_RESAMPLE_AVERAGE_OML 0x8988 -#define GL_RESAMPLE_DECIMATE_OML 0x8989 -#endif - -#ifndef GL_NV_copy_depth_to_color -#define GL_DEPTH_STENCIL_TO_RGBA_NV 0x886E -#define GL_DEPTH_STENCIL_TO_BGRA_NV 0x886F -#endif - -#ifndef GL_ATI_envmap_bumpmap -#define GL_BUMP_ROT_MATRIX_ATI 0x8775 -#define GL_BUMP_ROT_MATRIX_SIZE_ATI 0x8776 -#define GL_BUMP_NUM_TEX_UNITS_ATI 0x8777 -#define GL_BUMP_TEX_UNITS_ATI 0x8778 -#define GL_DUDV_ATI 0x8779 -#define GL_DU8DV8_ATI 0x877A -#define GL_BUMP_ENVMAP_ATI 0x877B -#define GL_BUMP_TARGET_ATI 0x877C -#endif - -#ifndef GL_ATI_fragment_shader -#define GL_FRAGMENT_SHADER_ATI 0x8920 -#define GL_REG_0_ATI 0x8921 -#define GL_REG_1_ATI 0x8922 -#define GL_REG_2_ATI 0x8923 -#define GL_REG_3_ATI 0x8924 -#define GL_REG_4_ATI 0x8925 -#define GL_REG_5_ATI 0x8926 -#define GL_REG_6_ATI 0x8927 -#define GL_REG_7_ATI 0x8928 -#define GL_REG_8_ATI 0x8929 -#define GL_REG_9_ATI 0x892A -#define GL_REG_10_ATI 0x892B -#define GL_REG_11_ATI 0x892C -#define GL_REG_12_ATI 0x892D -#define GL_REG_13_ATI 0x892E -#define GL_REG_14_ATI 0x892F -#define GL_REG_15_ATI 0x8930 -#define GL_REG_16_ATI 0x8931 -#define GL_REG_17_ATI 0x8932 -#define GL_REG_18_ATI 0x8933 -#define GL_REG_19_ATI 0x8934 -#define GL_REG_20_ATI 0x8935 -#define GL_REG_21_ATI 0x8936 -#define GL_REG_22_ATI 0x8937 -#define GL_REG_23_ATI 0x8938 -#define GL_REG_24_ATI 0x8939 -#define GL_REG_25_ATI 0x893A -#define GL_REG_26_ATI 0x893B -#define GL_REG_27_ATI 0x893C -#define GL_REG_28_ATI 0x893D -#define GL_REG_29_ATI 0x893E -#define GL_REG_30_ATI 0x893F -#define GL_REG_31_ATI 0x8940 -#define GL_CON_0_ATI 0x8941 -#define GL_CON_1_ATI 0x8942 -#define GL_CON_2_ATI 0x8943 -#define GL_CON_3_ATI 0x8944 -#define GL_CON_4_ATI 0x8945 -#define GL_CON_5_ATI 0x8946 -#define GL_CON_6_ATI 0x8947 -#define GL_CON_7_ATI 0x8948 -#define GL_CON_8_ATI 0x8949 -#define GL_CON_9_ATI 0x894A -#define GL_CON_10_ATI 0x894B -#define GL_CON_11_ATI 0x894C -#define GL_CON_12_ATI 0x894D -#define GL_CON_13_ATI 0x894E -#define GL_CON_14_ATI 0x894F -#define GL_CON_15_ATI 0x8950 -#define GL_CON_16_ATI 0x8951 -#define GL_CON_17_ATI 0x8952 -#define GL_CON_18_ATI 0x8953 -#define GL_CON_19_ATI 0x8954 -#define GL_CON_20_ATI 0x8955 -#define GL_CON_21_ATI 0x8956 -#define GL_CON_22_ATI 0x8957 -#define GL_CON_23_ATI 0x8958 -#define GL_CON_24_ATI 0x8959 -#define GL_CON_25_ATI 0x895A -#define GL_CON_26_ATI 0x895B -#define GL_CON_27_ATI 0x895C -#define GL_CON_28_ATI 0x895D -#define GL_CON_29_ATI 0x895E -#define GL_CON_30_ATI 0x895F -#define GL_CON_31_ATI 0x8960 -#define GL_MOV_ATI 0x8961 -#define GL_ADD_ATI 0x8963 -#define GL_MUL_ATI 0x8964 -#define GL_SUB_ATI 0x8965 -#define GL_DOT3_ATI 0x8966 -#define GL_DOT4_ATI 0x8967 -#define GL_MAD_ATI 0x8968 -#define GL_LERP_ATI 0x8969 -#define GL_CND_ATI 0x896A -#define GL_CND0_ATI 0x896B -#define GL_DOT2_ADD_ATI 0x896C -#define GL_SECONDARY_INTERPOLATOR_ATI 0x896D -#define GL_NUM_FRAGMENT_REGISTERS_ATI 0x896E -#define GL_NUM_FRAGMENT_CONSTANTS_ATI 0x896F -#define GL_NUM_PASSES_ATI 0x8970 -#define GL_NUM_INSTRUCTIONS_PER_PASS_ATI 0x8971 -#define GL_NUM_INSTRUCTIONS_TOTAL_ATI 0x8972 -#define GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI 0x8973 -#define GL_NUM_LOOPBACK_COMPONENTS_ATI 0x8974 -#define GL_COLOR_ALPHA_PAIRING_ATI 0x8975 -#define GL_SWIZZLE_STR_ATI 0x8976 -#define GL_SWIZZLE_STQ_ATI 0x8977 -#define GL_SWIZZLE_STR_DR_ATI 0x8978 -#define GL_SWIZZLE_STQ_DQ_ATI 0x8979 -#define GL_SWIZZLE_STRQ_ATI 0x897A -#define GL_SWIZZLE_STRQ_DQ_ATI 0x897B -#define GL_RED_BIT_ATI 0x00000001 -#define GL_GREEN_BIT_ATI 0x00000002 -#define GL_BLUE_BIT_ATI 0x00000004 -#define GL_2X_BIT_ATI 0x00000001 -#define GL_4X_BIT_ATI 0x00000002 -#define GL_8X_BIT_ATI 0x00000004 -#define GL_HALF_BIT_ATI 0x00000008 -#define GL_QUARTER_BIT_ATI 0x00000010 -#define GL_EIGHTH_BIT_ATI 0x00000020 -#define GL_SATURATE_BIT_ATI 0x00000040 -#define GL_COMP_BIT_ATI 0x00000002 -#define GL_NEGATE_BIT_ATI 0x00000004 -#define GL_BIAS_BIT_ATI 0x00000008 -#endif - -#ifndef GL_ATI_pn_triangles -#define GL_PN_TRIANGLES_ATI 0x87F0 -#define GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F1 -#define GL_PN_TRIANGLES_POINT_MODE_ATI 0x87F2 -#define GL_PN_TRIANGLES_NORMAL_MODE_ATI 0x87F3 -#define GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F4 -#define GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI 0x87F5 -#define GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI 0x87F6 -#define GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI 0x87F7 -#define GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI 0x87F8 -#endif - -#ifndef GL_ATI_vertex_array_object -#define GL_STATIC_ATI 0x8760 -#define GL_DYNAMIC_ATI 0x8761 -#define GL_PRESERVE_ATI 0x8762 -#define GL_DISCARD_ATI 0x8763 -#define GL_OBJECT_BUFFER_SIZE_ATI 0x8764 -#define GL_OBJECT_BUFFER_USAGE_ATI 0x8765 -#define GL_ARRAY_OBJECT_BUFFER_ATI 0x8766 -#define GL_ARRAY_OBJECT_OFFSET_ATI 0x8767 -#endif - -#ifndef GL_EXT_vertex_shader -#define GL_VERTEX_SHADER_EXT 0x8780 -#define GL_VERTEX_SHADER_BINDING_EXT 0x8781 -#define GL_OP_INDEX_EXT 0x8782 -#define GL_OP_NEGATE_EXT 0x8783 -#define GL_OP_DOT3_EXT 0x8784 -#define GL_OP_DOT4_EXT 0x8785 -#define GL_OP_MUL_EXT 0x8786 -#define GL_OP_ADD_EXT 0x8787 -#define GL_OP_MADD_EXT 0x8788 -#define GL_OP_FRAC_EXT 0x8789 -#define GL_OP_MAX_EXT 0x878A -#define GL_OP_MIN_EXT 0x878B -#define GL_OP_SET_GE_EXT 0x878C -#define GL_OP_SET_LT_EXT 0x878D -#define GL_OP_CLAMP_EXT 0x878E -#define GL_OP_FLOOR_EXT 0x878F -#define GL_OP_ROUND_EXT 0x8790 -#define GL_OP_EXP_BASE_2_EXT 0x8791 -#define GL_OP_LOG_BASE_2_EXT 0x8792 -#define GL_OP_POWER_EXT 0x8793 -#define GL_OP_RECIP_EXT 0x8794 -#define GL_OP_RECIP_SQRT_EXT 0x8795 -#define GL_OP_SUB_EXT 0x8796 -#define GL_OP_CROSS_PRODUCT_EXT 0x8797 -#define GL_OP_MULTIPLY_MATRIX_EXT 0x8798 -#define GL_OP_MOV_EXT 0x8799 -#define GL_OUTPUT_VERTEX_EXT 0x879A -#define GL_OUTPUT_COLOR0_EXT 0x879B -#define GL_OUTPUT_COLOR1_EXT 0x879C -#define GL_OUTPUT_TEXTURE_COORD0_EXT 0x879D -#define GL_OUTPUT_TEXTURE_COORD1_EXT 0x879E -#define GL_OUTPUT_TEXTURE_COORD2_EXT 0x879F -#define GL_OUTPUT_TEXTURE_COORD3_EXT 0x87A0 -#define GL_OUTPUT_TEXTURE_COORD4_EXT 0x87A1 -#define GL_OUTPUT_TEXTURE_COORD5_EXT 0x87A2 -#define GL_OUTPUT_TEXTURE_COORD6_EXT 0x87A3 -#define GL_OUTPUT_TEXTURE_COORD7_EXT 0x87A4 -#define GL_OUTPUT_TEXTURE_COORD8_EXT 0x87A5 -#define GL_OUTPUT_TEXTURE_COORD9_EXT 0x87A6 -#define GL_OUTPUT_TEXTURE_COORD10_EXT 0x87A7 -#define GL_OUTPUT_TEXTURE_COORD11_EXT 0x87A8 -#define GL_OUTPUT_TEXTURE_COORD12_EXT 0x87A9 -#define GL_OUTPUT_TEXTURE_COORD13_EXT 0x87AA -#define GL_OUTPUT_TEXTURE_COORD14_EXT 0x87AB -#define GL_OUTPUT_TEXTURE_COORD15_EXT 0x87AC -#define GL_OUTPUT_TEXTURE_COORD16_EXT 0x87AD -#define GL_OUTPUT_TEXTURE_COORD17_EXT 0x87AE -#define GL_OUTPUT_TEXTURE_COORD18_EXT 0x87AF -#define GL_OUTPUT_TEXTURE_COORD19_EXT 0x87B0 -#define GL_OUTPUT_TEXTURE_COORD20_EXT 0x87B1 -#define GL_OUTPUT_TEXTURE_COORD21_EXT 0x87B2 -#define GL_OUTPUT_TEXTURE_COORD22_EXT 0x87B3 -#define GL_OUTPUT_TEXTURE_COORD23_EXT 0x87B4 -#define GL_OUTPUT_TEXTURE_COORD24_EXT 0x87B5 -#define GL_OUTPUT_TEXTURE_COORD25_EXT 0x87B6 -#define GL_OUTPUT_TEXTURE_COORD26_EXT 0x87B7 -#define GL_OUTPUT_TEXTURE_COORD27_EXT 0x87B8 -#define GL_OUTPUT_TEXTURE_COORD28_EXT 0x87B9 -#define GL_OUTPUT_TEXTURE_COORD29_EXT 0x87BA -#define GL_OUTPUT_TEXTURE_COORD30_EXT 0x87BB -#define GL_OUTPUT_TEXTURE_COORD31_EXT 0x87BC -#define GL_OUTPUT_FOG_EXT 0x87BD -#define GL_SCALAR_EXT 0x87BE -#define GL_VECTOR_EXT 0x87BF -#define GL_MATRIX_EXT 0x87C0 -#define GL_VARIANT_EXT 0x87C1 -#define GL_INVARIANT_EXT 0x87C2 -#define GL_LOCAL_CONSTANT_EXT 0x87C3 -#define GL_LOCAL_EXT 0x87C4 -#define GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87C5 -#define GL_MAX_VERTEX_SHADER_VARIANTS_EXT 0x87C6 -#define GL_MAX_VERTEX_SHADER_INVARIANTS_EXT 0x87C7 -#define GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87C8 -#define GL_MAX_VERTEX_SHADER_LOCALS_EXT 0x87C9 -#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CA -#define GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT 0x87CB -#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87CC -#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT 0x87CD -#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT 0x87CE -#define GL_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CF -#define GL_VERTEX_SHADER_VARIANTS_EXT 0x87D0 -#define GL_VERTEX_SHADER_INVARIANTS_EXT 0x87D1 -#define GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87D2 -#define GL_VERTEX_SHADER_LOCALS_EXT 0x87D3 -#define GL_VERTEX_SHADER_OPTIMIZED_EXT 0x87D4 -#define GL_X_EXT 0x87D5 -#define GL_Y_EXT 0x87D6 -#define GL_Z_EXT 0x87D7 -#define GL_W_EXT 0x87D8 -#define GL_NEGATIVE_X_EXT 0x87D9 -#define GL_NEGATIVE_Y_EXT 0x87DA -#define GL_NEGATIVE_Z_EXT 0x87DB -#define GL_NEGATIVE_W_EXT 0x87DC -#define GL_ZERO_EXT 0x87DD -#define GL_ONE_EXT 0x87DE -#define GL_NEGATIVE_ONE_EXT 0x87DF -#define GL_NORMALIZED_RANGE_EXT 0x87E0 -#define GL_FULL_RANGE_EXT 0x87E1 -#define GL_CURRENT_VERTEX_EXT 0x87E2 -#define GL_MVP_MATRIX_EXT 0x87E3 -#define GL_VARIANT_VALUE_EXT 0x87E4 -#define GL_VARIANT_DATATYPE_EXT 0x87E5 -#define GL_VARIANT_ARRAY_STRIDE_EXT 0x87E6 -#define GL_VARIANT_ARRAY_TYPE_EXT 0x87E7 -#define GL_VARIANT_ARRAY_EXT 0x87E8 -#define GL_VARIANT_ARRAY_POINTER_EXT 0x87E9 -#define GL_INVARIANT_VALUE_EXT 0x87EA -#define GL_INVARIANT_DATATYPE_EXT 0x87EB -#define GL_LOCAL_CONSTANT_VALUE_EXT 0x87EC -#define GL_LOCAL_CONSTANT_DATATYPE_EXT 0x87ED -#endif - -#ifndef GL_ATI_vertex_streams -#define GL_MAX_VERTEX_STREAMS_ATI 0x876B -#define GL_VERTEX_STREAM0_ATI 0x876C -#define GL_VERTEX_STREAM1_ATI 0x876D -#define GL_VERTEX_STREAM2_ATI 0x876E -#define GL_VERTEX_STREAM3_ATI 0x876F -#define GL_VERTEX_STREAM4_ATI 0x8770 -#define GL_VERTEX_STREAM5_ATI 0x8771 -#define GL_VERTEX_STREAM6_ATI 0x8772 -#define GL_VERTEX_STREAM7_ATI 0x8773 -#define GL_VERTEX_SOURCE_ATI 0x8774 -#endif - -#ifndef GL_ATI_element_array -#define GL_ELEMENT_ARRAY_ATI 0x8768 -#define GL_ELEMENT_ARRAY_TYPE_ATI 0x8769 -#define GL_ELEMENT_ARRAY_POINTER_ATI 0x876A -#endif - -#ifndef GL_SUN_mesh_array -#define GL_QUAD_MESH_SUN 0x8614 -#define GL_TRIANGLE_MESH_SUN 0x8615 -#endif - -#ifndef GL_SUN_slice_accum -#define GL_SLICE_ACCUM_SUN 0x85CC -#endif - -#ifndef GL_NV_multisample_filter_hint -#define GL_MULTISAMPLE_FILTER_HINT_NV 0x8534 -#endif - -#ifndef GL_NV_depth_clamp -#define GL_DEPTH_CLAMP_NV 0x864F -#endif - -#ifndef GL_NV_occlusion_query -#define GL_PIXEL_COUNTER_BITS_NV 0x8864 -#define GL_CURRENT_OCCLUSION_QUERY_ID_NV 0x8865 -#define GL_PIXEL_COUNT_NV 0x8866 -#define GL_PIXEL_COUNT_AVAILABLE_NV 0x8867 -#endif - -#ifndef GL_NV_point_sprite -#define GL_POINT_SPRITE_NV 0x8861 -#define GL_COORD_REPLACE_NV 0x8862 -#define GL_POINT_SPRITE_R_MODE_NV 0x8863 -#endif - -#ifndef GL_NV_texture_shader3 -#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV 0x8850 -#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV 0x8851 -#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8852 -#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV 0x8853 -#define GL_OFFSET_HILO_TEXTURE_2D_NV 0x8854 -#define GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV 0x8855 -#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV 0x8856 -#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8857 -#define GL_DEPENDENT_HILO_TEXTURE_2D_NV 0x8858 -#define GL_DEPENDENT_RGB_TEXTURE_3D_NV 0x8859 -#define GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV 0x885A -#define GL_DOT_PRODUCT_PASS_THROUGH_NV 0x885B -#define GL_DOT_PRODUCT_TEXTURE_1D_NV 0x885C -#define GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV 0x885D -#define GL_HILO8_NV 0x885E -#define GL_SIGNED_HILO8_NV 0x885F -#define GL_FORCE_BLUE_TO_ONE_NV 0x8860 -#endif - -#ifndef GL_NV_vertex_program1_1 -#endif - -#ifndef GL_EXT_shadow_funcs -#endif - -#ifndef GL_EXT_stencil_two_side -#define GL_STENCIL_TEST_TWO_SIDE_EXT 0x8910 -#define GL_ACTIVE_STENCIL_FACE_EXT 0x8911 -#endif - -#ifndef GL_ATI_text_fragment_shader -#define GL_TEXT_FRAGMENT_SHADER_ATI 0x8200 -#endif - -#ifndef GL_APPLE_client_storage -#define GL_UNPACK_CLIENT_STORAGE_APPLE 0x85B2 -#endif - -#ifndef GL_APPLE_element_array -#define GL_ELEMENT_ARRAY_APPLE 0x8A0C -#define GL_ELEMENT_ARRAY_TYPE_APPLE 0x8A0D -#define GL_ELEMENT_ARRAY_POINTER_APPLE 0x8A0E -#endif - -#ifndef GL_APPLE_fence -#define GL_DRAW_PIXELS_APPLE 0x8A0A -#define GL_FENCE_APPLE 0x8A0B -#endif - -#ifndef GL_APPLE_vertex_array_object -#define GL_VERTEX_ARRAY_BINDING_APPLE 0x85B5 -#endif - -#ifndef GL_APPLE_vertex_array_range -#define GL_VERTEX_ARRAY_RANGE_APPLE 0x851D -#define GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE 0x851E -#define GL_VERTEX_ARRAY_STORAGE_HINT_APPLE 0x851F -#define GL_VERTEX_ARRAY_RANGE_POINTER_APPLE 0x8521 -#define GL_STORAGE_CLIENT_APPLE 0x85B4 -#define GL_STORAGE_CACHED_APPLE 0x85BE -#define GL_STORAGE_SHARED_APPLE 0x85BF -#endif - -#ifndef GL_APPLE_ycbcr_422 -#define GL_YCBCR_422_APPLE 0x85B9 -#define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA -#define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB -#endif - -#ifndef GL_S3_s3tc -#define GL_RGB_S3TC 0x83A0 -#define GL_RGB4_S3TC 0x83A1 -#define GL_RGBA_S3TC 0x83A2 -#define GL_RGBA4_S3TC 0x83A3 -#endif - -#ifndef GL_ATI_draw_buffers -#define GL_MAX_DRAW_BUFFERS_ATI 0x8824 -#define GL_DRAW_BUFFER0_ATI 0x8825 -#define GL_DRAW_BUFFER1_ATI 0x8826 -#define GL_DRAW_BUFFER2_ATI 0x8827 -#define GL_DRAW_BUFFER3_ATI 0x8828 -#define GL_DRAW_BUFFER4_ATI 0x8829 -#define GL_DRAW_BUFFER5_ATI 0x882A -#define GL_DRAW_BUFFER6_ATI 0x882B -#define GL_DRAW_BUFFER7_ATI 0x882C -#define GL_DRAW_BUFFER8_ATI 0x882D -#define GL_DRAW_BUFFER9_ATI 0x882E -#define GL_DRAW_BUFFER10_ATI 0x882F -#define GL_DRAW_BUFFER11_ATI 0x8830 -#define GL_DRAW_BUFFER12_ATI 0x8831 -#define GL_DRAW_BUFFER13_ATI 0x8832 -#define GL_DRAW_BUFFER14_ATI 0x8833 -#define GL_DRAW_BUFFER15_ATI 0x8834 -#endif - -#ifndef GL_ATI_pixel_format_float -#define GL_TYPE_RGBA_FLOAT_ATI 0x8820 -#define GL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI 0x8835 -#endif - -#ifndef GL_ATI_texture_env_combine3 -#define GL_MODULATE_ADD_ATI 0x8744 -#define GL_MODULATE_SIGNED_ADD_ATI 0x8745 -#define GL_MODULATE_SUBTRACT_ATI 0x8746 -#endif - -#ifndef GL_ATI_texture_float -#define GL_RGBA_FLOAT32_ATI 0x8814 -#define GL_RGB_FLOAT32_ATI 0x8815 -#define GL_ALPHA_FLOAT32_ATI 0x8816 -#define GL_INTENSITY_FLOAT32_ATI 0x8817 -#define GL_LUMINANCE_FLOAT32_ATI 0x8818 -#define GL_LUMINANCE_ALPHA_FLOAT32_ATI 0x8819 -#define GL_RGBA_FLOAT16_ATI 0x881A -#define GL_RGB_FLOAT16_ATI 0x881B -#define GL_ALPHA_FLOAT16_ATI 0x881C -#define GL_INTENSITY_FLOAT16_ATI 0x881D -#define GL_LUMINANCE_FLOAT16_ATI 0x881E -#define GL_LUMINANCE_ALPHA_FLOAT16_ATI 0x881F -#endif - -#ifndef GL_NV_float_buffer -#define GL_FLOAT_R_NV 0x8880 -#define GL_FLOAT_RG_NV 0x8881 -#define GL_FLOAT_RGB_NV 0x8882 -#define GL_FLOAT_RGBA_NV 0x8883 -#define GL_FLOAT_R16_NV 0x8884 -#define GL_FLOAT_R32_NV 0x8885 -#define GL_FLOAT_RG16_NV 0x8886 -#define GL_FLOAT_RG32_NV 0x8887 -#define GL_FLOAT_RGB16_NV 0x8888 -#define GL_FLOAT_RGB32_NV 0x8889 -#define GL_FLOAT_RGBA16_NV 0x888A -#define GL_FLOAT_RGBA32_NV 0x888B -#define GL_TEXTURE_FLOAT_COMPONENTS_NV 0x888C -#define GL_FLOAT_CLEAR_COLOR_VALUE_NV 0x888D -#define GL_FLOAT_RGBA_MODE_NV 0x888E -#endif - -#ifndef GL_NV_fragment_program -#define GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV 0x8868 -#define GL_FRAGMENT_PROGRAM_NV 0x8870 -#define GL_MAX_TEXTURE_COORDS_NV 0x8871 -#define GL_MAX_TEXTURE_IMAGE_UNITS_NV 0x8872 -#define GL_FRAGMENT_PROGRAM_BINDING_NV 0x8873 -#define GL_PROGRAM_ERROR_STRING_NV 0x8874 -#endif - -#ifndef GL_NV_half_float -#define GL_HALF_FLOAT_NV 0x140B -#endif - -#ifndef GL_NV_pixel_data_range -#define GL_WRITE_PIXEL_DATA_RANGE_NV 0x8878 -#define GL_READ_PIXEL_DATA_RANGE_NV 0x8879 -#define GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV 0x887A -#define GL_READ_PIXEL_DATA_RANGE_LENGTH_NV 0x887B -#define GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV 0x887C -#define GL_READ_PIXEL_DATA_RANGE_POINTER_NV 0x887D -#endif - -#ifndef GL_NV_primitive_restart -#define GL_PRIMITIVE_RESTART_NV 0x8558 -#define GL_PRIMITIVE_RESTART_INDEX_NV 0x8559 -#endif - -#ifndef GL_NV_texture_expand_normal -#define GL_TEXTURE_UNSIGNED_REMAP_MODE_NV 0x888F -#endif - -#ifndef GL_NV_vertex_program2 -#endif - -#ifndef GL_ATI_map_object_buffer -#endif - -#ifndef GL_ATI_separate_stencil -#define GL_STENCIL_BACK_FUNC_ATI 0x8800 -#define GL_STENCIL_BACK_FAIL_ATI 0x8801 -#define GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI 0x8802 -#define GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI 0x8803 -#endif - -#ifndef GL_ATI_vertex_attrib_array_object -#endif - -#ifndef GL_OES_read_format -#define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A -#define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B -#endif - -#ifndef GL_EXT_depth_bounds_test -#define GL_DEPTH_BOUNDS_TEST_EXT 0x8890 -#define GL_DEPTH_BOUNDS_EXT 0x8891 -#endif - -#ifndef GL_EXT_texture_mirror_clamp -#define GL_MIRROR_CLAMP_EXT 0x8742 -#define GL_MIRROR_CLAMP_TO_EDGE_EXT 0x8743 -#define GL_MIRROR_CLAMP_TO_BORDER_EXT 0x8912 -#endif - -#ifndef GL_EXT_blend_equation_separate -#define GL_BLEND_EQUATION_RGB_EXT 0x8009 -#define GL_BLEND_EQUATION_ALPHA_EXT 0x883D -#endif - -#ifndef GL_MESA_pack_invert -#define GL_PACK_INVERT_MESA 0x8758 -#endif - -#ifndef GL_MESA_ycbcr_texture -#define GL_UNSIGNED_SHORT_8_8_MESA 0x85BA -#define GL_UNSIGNED_SHORT_8_8_REV_MESA 0x85BB -#define GL_YCBCR_MESA 0x8757 -#endif - -#ifndef GL_EXT_pixel_buffer_object -#define GL_PIXEL_PACK_BUFFER_EXT 0x88EB -#define GL_PIXEL_UNPACK_BUFFER_EXT 0x88EC -#define GL_PIXEL_PACK_BUFFER_BINDING_EXT 0x88ED -#define GL_PIXEL_UNPACK_BUFFER_BINDING_EXT 0x88EF -#endif - -#ifndef GL_NV_fragment_program_option -#endif - -#ifndef GL_NV_fragment_program2 -#define GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV 0x88F4 -#define GL_MAX_PROGRAM_CALL_DEPTH_NV 0x88F5 -#define GL_MAX_PROGRAM_IF_DEPTH_NV 0x88F6 -#define GL_MAX_PROGRAM_LOOP_DEPTH_NV 0x88F7 -#define GL_MAX_PROGRAM_LOOP_COUNT_NV 0x88F8 -#endif - -#ifndef GL_NV_vertex_program2_option -/* reuse GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV */ -/* reuse GL_MAX_PROGRAM_CALL_DEPTH_NV */ -#endif - -#ifndef GL_NV_vertex_program3 -/* reuse GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB */ -#endif - -#ifndef GL_EXT_framebuffer_object -#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506 -#define GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8 -#define GL_FRAMEBUFFER_BINDING_EXT 0x8CA6 -#define GL_RENDERBUFFER_BINDING_EXT 0x8CA7 -#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0 -#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4 -#define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5 -#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6 -#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7 -#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9 -#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA -#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB -#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC -#define GL_FRAMEBUFFER_UNSUPPORTED_EXT 0x8CDD -#define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF -#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0 -#define GL_COLOR_ATTACHMENT1_EXT 0x8CE1 -#define GL_COLOR_ATTACHMENT2_EXT 0x8CE2 -#define GL_COLOR_ATTACHMENT3_EXT 0x8CE3 -#define GL_COLOR_ATTACHMENT4_EXT 0x8CE4 -#define GL_COLOR_ATTACHMENT5_EXT 0x8CE5 -#define GL_COLOR_ATTACHMENT6_EXT 0x8CE6 -#define GL_COLOR_ATTACHMENT7_EXT 0x8CE7 -#define GL_COLOR_ATTACHMENT8_EXT 0x8CE8 -#define GL_COLOR_ATTACHMENT9_EXT 0x8CE9 -#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA -#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB -#define GL_COLOR_ATTACHMENT12_EXT 0x8CEC -#define GL_COLOR_ATTACHMENT13_EXT 0x8CED -#define GL_COLOR_ATTACHMENT14_EXT 0x8CEE -#define GL_COLOR_ATTACHMENT15_EXT 0x8CEF -#define GL_DEPTH_ATTACHMENT_EXT 0x8D00 -#define GL_STENCIL_ATTACHMENT_EXT 0x8D20 -#define GL_FRAMEBUFFER_EXT 0x8D40 -#define GL_RENDERBUFFER_EXT 0x8D41 -#define GL_RENDERBUFFER_WIDTH_EXT 0x8D42 -#define GL_RENDERBUFFER_HEIGHT_EXT 0x8D43 -#define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44 -#define GL_STENCIL_INDEX1_EXT 0x8D46 -#define GL_STENCIL_INDEX4_EXT 0x8D47 -#define GL_STENCIL_INDEX8_EXT 0x8D48 -#define GL_STENCIL_INDEX16_EXT 0x8D49 -#define GL_RENDERBUFFER_RED_SIZE_EXT 0x8D50 -#define GL_RENDERBUFFER_GREEN_SIZE_EXT 0x8D51 -#define GL_RENDERBUFFER_BLUE_SIZE_EXT 0x8D52 -#define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53 -#define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54 -#define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55 -#endif - -#ifndef GL_GREMEDY_string_marker -#endif - -#ifndef GL_EXT_packed_depth_stencil -#define GL_DEPTH_STENCIL_EXT 0x84F9 -#define GL_UNSIGNED_INT_24_8_EXT 0x84FA -#define GL_DEPTH24_STENCIL8_EXT 0x88F0 -#define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1 -#endif - -#ifndef GL_EXT_stencil_clear_tag -#define GL_STENCIL_TAG_BITS_EXT 0x88F2 -#define GL_STENCIL_CLEAR_TAG_VALUE_EXT 0x88F3 -#endif - -#ifndef GL_EXT_texture_sRGB -#define GL_SRGB_EXT 0x8C40 -#define GL_SRGB8_EXT 0x8C41 -#define GL_SRGB_ALPHA_EXT 0x8C42 -#define GL_SRGB8_ALPHA8_EXT 0x8C43 -#define GL_SLUMINANCE_ALPHA_EXT 0x8C44 -#define GL_SLUMINANCE8_ALPHA8_EXT 0x8C45 -#define GL_SLUMINANCE_EXT 0x8C46 -#define GL_SLUMINANCE8_EXT 0x8C47 -#define GL_COMPRESSED_SRGB_EXT 0x8C48 -#define GL_COMPRESSED_SRGB_ALPHA_EXT 0x8C49 -#define GL_COMPRESSED_SLUMINANCE_EXT 0x8C4A -#define GL_COMPRESSED_SLUMINANCE_ALPHA_EXT 0x8C4B -#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C -#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D -#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E -#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F -#endif - -#ifndef GL_EXT_framebuffer_blit -#define GL_READ_FRAMEBUFFER_EXT 0x8CA8 -#define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9 -#define GL_DRAW_FRAMEBUFFER_BINDING_EXT GL_FRAMEBUFFER_BINDING_EXT -#define GL_READ_FRAMEBUFFER_BINDING_EXT 0x8CAA -#endif - -#ifndef GL_EXT_framebuffer_multisample -#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB -#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56 -#define GL_MAX_SAMPLES_EXT 0x8D57 -#endif - -#ifndef GL_MESAX_texture_stack -#define GL_TEXTURE_1D_STACK_MESAX 0x8759 -#define GL_TEXTURE_2D_STACK_MESAX 0x875A -#define GL_PROXY_TEXTURE_1D_STACK_MESAX 0x875B -#define GL_PROXY_TEXTURE_2D_STACK_MESAX 0x875C -#define GL_TEXTURE_1D_STACK_BINDING_MESAX 0x875D -#define GL_TEXTURE_2D_STACK_BINDING_MESAX 0x875E -#endif - -#ifndef GL_EXT_timer_query -#define GL_TIME_ELAPSED_EXT 0x88BF -#endif - -#ifndef GL_EXT_gpu_program_parameters -#endif - -#ifndef GL_APPLE_flush_buffer_range -#define GL_BUFFER_SERIALIZED_MODIFY_APPLE 0x8A12 -#define GL_BUFFER_FLUSHING_UNMAP_APPLE 0x8A13 -#endif - -#ifndef GL_NV_gpu_program4 -#define GL_MIN_PROGRAM_TEXEL_OFFSET_NV 0x8904 -#define GL_MAX_PROGRAM_TEXEL_OFFSET_NV 0x8905 -#define GL_PROGRAM_ATTRIB_COMPONENTS_NV 0x8906 -#define GL_PROGRAM_RESULT_COMPONENTS_NV 0x8907 -#define GL_MAX_PROGRAM_ATTRIB_COMPONENTS_NV 0x8908 -#define GL_MAX_PROGRAM_RESULT_COMPONENTS_NV 0x8909 -#define GL_MAX_PROGRAM_GENERIC_ATTRIBS_NV 0x8DA5 -#define GL_MAX_PROGRAM_GENERIC_RESULTS_NV 0x8DA6 -#endif - -#ifndef GL_NV_geometry_program4 -#define GL_LINES_ADJACENCY_EXT 0x000A -#define GL_LINE_STRIP_ADJACENCY_EXT 0x000B -#define GL_TRIANGLES_ADJACENCY_EXT 0x000C -#define GL_TRIANGLE_STRIP_ADJACENCY_EXT 0x000D -#define GL_GEOMETRY_PROGRAM_NV 0x8C26 -#define GL_MAX_PROGRAM_OUTPUT_VERTICES_NV 0x8C27 -#define GL_MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV 0x8C28 -#define GL_GEOMETRY_VERTICES_OUT_EXT 0x8DDA -#define GL_GEOMETRY_INPUT_TYPE_EXT 0x8DDB -#define GL_GEOMETRY_OUTPUT_TYPE_EXT 0x8DDC -#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT 0x8C29 -#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT 0x8DA7 -#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT 0x8DA8 -#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT 0x8DA9 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT 0x8CD4 -#define GL_PROGRAM_POINT_SIZE_EXT 0x8642 -#endif - -#ifndef GL_EXT_geometry_shader4 -#define GL_GEOMETRY_SHADER_EXT 0x8DD9 -/* reuse GL_GEOMETRY_VERTICES_OUT_EXT */ -/* reuse GL_GEOMETRY_INPUT_TYPE_EXT */ -/* reuse GL_GEOMETRY_OUTPUT_TYPE_EXT */ -/* reuse GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT */ -#define GL_MAX_GEOMETRY_VARYING_COMPONENTS_EXT 0x8DDD -#define GL_MAX_VERTEX_VARYING_COMPONENTS_EXT 0x8DDE -#define GL_MAX_VARYING_COMPONENTS_EXT 0x8B4B -#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT 0x8DDF -#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT 0x8DE0 -#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT 0x8DE1 -/* reuse GL_LINES_ADJACENCY_EXT */ -/* reuse GL_LINE_STRIP_ADJACENCY_EXT */ -/* reuse GL_TRIANGLES_ADJACENCY_EXT */ -/* reuse GL_TRIANGLE_STRIP_ADJACENCY_EXT */ -/* reuse GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT */ -/* reuse GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT */ -/* reuse GL_PROGRAM_POINT_SIZE_EXT */ -#endif - -#ifndef GL_NV_vertex_program4 -#define GL_VERTEX_ATTRIB_ARRAY_INTEGER_NV 0x88FD -#endif - -#ifndef GL_EXT_gpu_shader4 -#define GL_SAMPLER_1D_ARRAY_EXT 0x8DC0 -#define GL_SAMPLER_2D_ARRAY_EXT 0x8DC1 -#define GL_SAMPLER_BUFFER_EXT 0x8DC2 -#define GL_SAMPLER_1D_ARRAY_SHADOW_EXT 0x8DC3 -#define GL_SAMPLER_2D_ARRAY_SHADOW_EXT 0x8DC4 -#define GL_SAMPLER_CUBE_SHADOW_EXT 0x8DC5 -#define GL_UNSIGNED_INT_VEC2_EXT 0x8DC6 -#define GL_UNSIGNED_INT_VEC3_EXT 0x8DC7 -#define GL_UNSIGNED_INT_VEC4_EXT 0x8DC8 -#define GL_INT_SAMPLER_1D_EXT 0x8DC9 -#define GL_INT_SAMPLER_2D_EXT 0x8DCA -#define GL_INT_SAMPLER_3D_EXT 0x8DCB -#define GL_INT_SAMPLER_CUBE_EXT 0x8DCC -#define GL_INT_SAMPLER_2D_RECT_EXT 0x8DCD -#define GL_INT_SAMPLER_1D_ARRAY_EXT 0x8DCE -#define GL_INT_SAMPLER_2D_ARRAY_EXT 0x8DCF -#define GL_INT_SAMPLER_BUFFER_EXT 0x8DD0 -#define GL_UNSIGNED_INT_SAMPLER_1D_EXT 0x8DD1 -#define GL_UNSIGNED_INT_SAMPLER_2D_EXT 0x8DD2 -#define GL_UNSIGNED_INT_SAMPLER_3D_EXT 0x8DD3 -#define GL_UNSIGNED_INT_SAMPLER_CUBE_EXT 0x8DD4 -#define GL_UNSIGNED_INT_SAMPLER_2D_RECT_EXT 0x8DD5 -#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT 0x8DD6 -#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT 0x8DD7 -#define GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT 0x8DD8 -#endif - -#ifndef GL_EXT_draw_instanced -#endif - -#ifndef GL_EXT_packed_float -#define GL_R11F_G11F_B10F_EXT 0x8C3A -#define GL_UNSIGNED_INT_10F_11F_11F_REV_EXT 0x8C3B -#define GL_RGBA_SIGNED_COMPONENTS_EXT 0x8C3C -#endif - -#ifndef GL_EXT_texture_array -#define GL_TEXTURE_1D_ARRAY_EXT 0x8C18 -#define GL_PROXY_TEXTURE_1D_ARRAY_EXT 0x8C19 -#define GL_TEXTURE_2D_ARRAY_EXT 0x8C1A -#define GL_PROXY_TEXTURE_2D_ARRAY_EXT 0x8C1B -#define GL_TEXTURE_BINDING_1D_ARRAY_EXT 0x8C1C -#define GL_TEXTURE_BINDING_2D_ARRAY_EXT 0x8C1D -#define GL_MAX_ARRAY_TEXTURE_LAYERS_EXT 0x88FF -#define GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT 0x884E -/* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT */ -#endif - -#ifndef GL_EXT_texture_buffer_object -#define GL_TEXTURE_BUFFER_EXT 0x8C2A -#define GL_MAX_TEXTURE_BUFFER_SIZE_EXT 0x8C2B -#define GL_TEXTURE_BINDING_BUFFER_EXT 0x8C2C -#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_EXT 0x8C2D -#define GL_TEXTURE_BUFFER_FORMAT_EXT 0x8C2E -#endif - -#ifndef GL_EXT_texture_compression_latc -#define GL_COMPRESSED_LUMINANCE_LATC1_EXT 0x8C70 -#define GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT 0x8C71 -#define GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT 0x8C72 -#define GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT 0x8C73 -#endif - -#ifndef GL_EXT_texture_compression_rgtc -#define GL_COMPRESSED_RED_RGTC1_EXT 0x8DBB -#define GL_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC -#define GL_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD -#define GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE -#endif - -#ifndef GL_EXT_texture_shared_exponent -#define GL_RGB9_E5_EXT 0x8C3D -#define GL_UNSIGNED_INT_5_9_9_9_REV_EXT 0x8C3E -#define GL_TEXTURE_SHARED_SIZE_EXT 0x8C3F -#endif - -#ifndef GL_NV_depth_buffer_float -#define GL_DEPTH_COMPONENT32F_NV 0x8DAB -#define GL_DEPTH32F_STENCIL8_NV 0x8DAC -#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV_NV 0x8DAD -#define GL_DEPTH_BUFFER_FLOAT_MODE_NV 0x8DAF -#endif - -#ifndef GL_NV_fragment_program4 -#endif - -#ifndef GL_NV_framebuffer_multisample_coverage -#define GL_RENDERBUFFER_COVERAGE_SAMPLES_NV 0x8CAB -#define GL_RENDERBUFFER_COLOR_SAMPLES_NV 0x8E10 -#define GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV 0x8E11 -#define GL_MULTISAMPLE_COVERAGE_MODES_NV 0x8E12 -#endif - -#ifndef GL_EXT_framebuffer_sRGB -#define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9 -#define GL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x8DBA -#endif - -#ifndef GL_NV_geometry_shader4 -#endif - -#ifndef GL_NV_parameter_buffer_object -#define GL_MAX_PROGRAM_PARAMETER_BUFFER_BINDINGS_NV 0x8DA0 -#define GL_MAX_PROGRAM_PARAMETER_BUFFER_SIZE_NV 0x8DA1 -#define GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV 0x8DA2 -#define GL_GEOMETRY_PROGRAM_PARAMETER_BUFFER_NV 0x8DA3 -#define GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV 0x8DA4 -#endif - -#ifndef GL_EXT_draw_buffers2 -#endif - -#ifndef GL_NV_transform_feedback -#define GL_BACK_PRIMARY_COLOR_NV 0x8C77 -#define GL_BACK_SECONDARY_COLOR_NV 0x8C78 -#define GL_TEXTURE_COORD_NV 0x8C79 -#define GL_CLIP_DISTANCE_NV 0x8C7A -#define GL_VERTEX_ID_NV 0x8C7B -#define GL_PRIMITIVE_ID_NV 0x8C7C -#define GL_GENERIC_ATTRIB_NV 0x8C7D -#define GL_TRANSFORM_FEEDBACK_ATTRIBS_NV 0x8C7E -#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_NV 0x8C7F -#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_NV 0x8C80 -#define GL_ACTIVE_VARYINGS_NV 0x8C81 -#define GL_ACTIVE_VARYING_MAX_LENGTH_NV 0x8C82 -#define GL_TRANSFORM_FEEDBACK_VARYINGS_NV 0x8C83 -#define GL_TRANSFORM_FEEDBACK_BUFFER_START_NV 0x8C84 -#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_NV 0x8C85 -#define GL_TRANSFORM_FEEDBACK_RECORD_NV 0x8C86 -#define GL_PRIMITIVES_GENERATED_NV 0x8C87 -#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_NV 0x8C88 -#define GL_RASTERIZER_DISCARD_NV 0x8C89 -#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_ATTRIBS_NV 0x8C8A -#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_NV 0x8C8B -#define GL_INTERLEAVED_ATTRIBS_NV 0x8C8C -#define GL_SEPARATE_ATTRIBS_NV 0x8C8D -#define GL_TRANSFORM_FEEDBACK_BUFFER_NV 0x8C8E -#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_NV 0x8C8F -#define GL_LAYER_NV 0x8DAA -#define GL_NEXT_BUFFER_NV -2 -#define GL_SKIP_COMPONENTS4_NV -3 -#define GL_SKIP_COMPONENTS3_NV -4 -#define GL_SKIP_COMPONENTS2_NV -5 -#define GL_SKIP_COMPONENTS1_NV -6 -#endif - -#ifndef GL_EXT_bindable_uniform -#define GL_MAX_VERTEX_BINDABLE_UNIFORMS_EXT 0x8DE2 -#define GL_MAX_FRAGMENT_BINDABLE_UNIFORMS_EXT 0x8DE3 -#define GL_MAX_GEOMETRY_BINDABLE_UNIFORMS_EXT 0x8DE4 -#define GL_MAX_BINDABLE_UNIFORM_SIZE_EXT 0x8DED -#define GL_UNIFORM_BUFFER_EXT 0x8DEE -#define GL_UNIFORM_BUFFER_BINDING_EXT 0x8DEF -#endif - -#ifndef GL_EXT_texture_integer -#define GL_RGBA32UI_EXT 0x8D70 -#define GL_RGB32UI_EXT 0x8D71 -#define GL_ALPHA32UI_EXT 0x8D72 -#define GL_INTENSITY32UI_EXT 0x8D73 -#define GL_LUMINANCE32UI_EXT 0x8D74 -#define GL_LUMINANCE_ALPHA32UI_EXT 0x8D75 -#define GL_RGBA16UI_EXT 0x8D76 -#define GL_RGB16UI_EXT 0x8D77 -#define GL_ALPHA16UI_EXT 0x8D78 -#define GL_INTENSITY16UI_EXT 0x8D79 -#define GL_LUMINANCE16UI_EXT 0x8D7A -#define GL_LUMINANCE_ALPHA16UI_EXT 0x8D7B -#define GL_RGBA8UI_EXT 0x8D7C -#define GL_RGB8UI_EXT 0x8D7D -#define GL_ALPHA8UI_EXT 0x8D7E -#define GL_INTENSITY8UI_EXT 0x8D7F -#define GL_LUMINANCE8UI_EXT 0x8D80 -#define GL_LUMINANCE_ALPHA8UI_EXT 0x8D81 -#define GL_RGBA32I_EXT 0x8D82 -#define GL_RGB32I_EXT 0x8D83 -#define GL_ALPHA32I_EXT 0x8D84 -#define GL_INTENSITY32I_EXT 0x8D85 -#define GL_LUMINANCE32I_EXT 0x8D86 -#define GL_LUMINANCE_ALPHA32I_EXT 0x8D87 -#define GL_RGBA16I_EXT 0x8D88 -#define GL_RGB16I_EXT 0x8D89 -#define GL_ALPHA16I_EXT 0x8D8A -#define GL_INTENSITY16I_EXT 0x8D8B -#define GL_LUMINANCE16I_EXT 0x8D8C -#define GL_LUMINANCE_ALPHA16I_EXT 0x8D8D -#define GL_RGBA8I_EXT 0x8D8E -#define GL_RGB8I_EXT 0x8D8F -#define GL_ALPHA8I_EXT 0x8D90 -#define GL_INTENSITY8I_EXT 0x8D91 -#define GL_LUMINANCE8I_EXT 0x8D92 -#define GL_LUMINANCE_ALPHA8I_EXT 0x8D93 -#define GL_RED_INTEGER_EXT 0x8D94 -#define GL_GREEN_INTEGER_EXT 0x8D95 -#define GL_BLUE_INTEGER_EXT 0x8D96 -#define GL_ALPHA_INTEGER_EXT 0x8D97 -#define GL_RGB_INTEGER_EXT 0x8D98 -#define GL_RGBA_INTEGER_EXT 0x8D99 -#define GL_BGR_INTEGER_EXT 0x8D9A -#define GL_BGRA_INTEGER_EXT 0x8D9B -#define GL_LUMINANCE_INTEGER_EXT 0x8D9C -#define GL_LUMINANCE_ALPHA_INTEGER_EXT 0x8D9D -#define GL_RGBA_INTEGER_MODE_EXT 0x8D9E -#endif - -#ifndef GL_GREMEDY_frame_terminator -#endif - -#ifndef GL_NV_conditional_render -#define GL_QUERY_WAIT_NV 0x8E13 -#define GL_QUERY_NO_WAIT_NV 0x8E14 -#define GL_QUERY_BY_REGION_WAIT_NV 0x8E15 -#define GL_QUERY_BY_REGION_NO_WAIT_NV 0x8E16 -#endif - -#ifndef GL_NV_present_video -#define GL_FRAME_NV 0x8E26 -#define GL_FIELDS_NV 0x8E27 -#define GL_CURRENT_TIME_NV 0x8E28 -#define GL_NUM_FILL_STREAMS_NV 0x8E29 -#define GL_PRESENT_TIME_NV 0x8E2A -#define GL_PRESENT_DURATION_NV 0x8E2B -#endif - -#ifndef GL_EXT_transform_feedback -#define GL_TRANSFORM_FEEDBACK_BUFFER_EXT 0x8C8E -#define GL_TRANSFORM_FEEDBACK_BUFFER_START_EXT 0x8C84 -#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_EXT 0x8C85 -#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_EXT 0x8C8F -#define GL_INTERLEAVED_ATTRIBS_EXT 0x8C8C -#define GL_SEPARATE_ATTRIBS_EXT 0x8C8D -#define GL_PRIMITIVES_GENERATED_EXT 0x8C87 -#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT 0x8C88 -#define GL_RASTERIZER_DISCARD_EXT 0x8C89 -#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT 0x8C8A -#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT 0x8C8B -#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT 0x8C80 -#define GL_TRANSFORM_FEEDBACK_VARYINGS_EXT 0x8C83 -#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_EXT 0x8C7F -#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH_EXT 0x8C76 -#endif - -#ifndef GL_EXT_direct_state_access -#define GL_PROGRAM_MATRIX_EXT 0x8E2D -#define GL_TRANSPOSE_PROGRAM_MATRIX_EXT 0x8E2E -#define GL_PROGRAM_MATRIX_STACK_DEPTH_EXT 0x8E2F -#endif - -#ifndef GL_EXT_vertex_array_bgra -/* reuse GL_BGRA */ -#endif - -#ifndef GL_EXT_texture_swizzle -#define GL_TEXTURE_SWIZZLE_R_EXT 0x8E42 -#define GL_TEXTURE_SWIZZLE_G_EXT 0x8E43 -#define GL_TEXTURE_SWIZZLE_B_EXT 0x8E44 -#define GL_TEXTURE_SWIZZLE_A_EXT 0x8E45 -#define GL_TEXTURE_SWIZZLE_RGBA_EXT 0x8E46 -#endif - -#ifndef GL_NV_explicit_multisample -#define GL_SAMPLE_POSITION_NV 0x8E50 -#define GL_SAMPLE_MASK_NV 0x8E51 -#define GL_SAMPLE_MASK_VALUE_NV 0x8E52 -#define GL_TEXTURE_BINDING_RENDERBUFFER_NV 0x8E53 -#define GL_TEXTURE_RENDERBUFFER_DATA_STORE_BINDING_NV 0x8E54 -#define GL_TEXTURE_RENDERBUFFER_NV 0x8E55 -#define GL_SAMPLER_RENDERBUFFER_NV 0x8E56 -#define GL_INT_SAMPLER_RENDERBUFFER_NV 0x8E57 -#define GL_UNSIGNED_INT_SAMPLER_RENDERBUFFER_NV 0x8E58 -#define GL_MAX_SAMPLE_MASK_WORDS_NV 0x8E59 -#endif - -#ifndef GL_NV_transform_feedback2 -#define GL_TRANSFORM_FEEDBACK_NV 0x8E22 -#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED_NV 0x8E23 -#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE_NV 0x8E24 -#define GL_TRANSFORM_FEEDBACK_BINDING_NV 0x8E25 -#endif - -#ifndef GL_ATI_meminfo -#define GL_VBO_FREE_MEMORY_ATI 0x87FB -#define GL_TEXTURE_FREE_MEMORY_ATI 0x87FC -#define GL_RENDERBUFFER_FREE_MEMORY_ATI 0x87FD -#endif - -#ifndef GL_AMD_performance_monitor -#define GL_COUNTER_TYPE_AMD 0x8BC0 -#define GL_COUNTER_RANGE_AMD 0x8BC1 -#define GL_UNSIGNED_INT64_AMD 0x8BC2 -#define GL_PERCENTAGE_AMD 0x8BC3 -#define GL_PERFMON_RESULT_AVAILABLE_AMD 0x8BC4 -#define GL_PERFMON_RESULT_SIZE_AMD 0x8BC5 -#define GL_PERFMON_RESULT_AMD 0x8BC6 -#endif - -#ifndef GL_AMD_texture_texture4 -#endif - -#ifndef GL_AMD_vertex_shader_tesselator -#define GL_SAMPLER_BUFFER_AMD 0x9001 -#define GL_INT_SAMPLER_BUFFER_AMD 0x9002 -#define GL_UNSIGNED_INT_SAMPLER_BUFFER_AMD 0x9003 -#define GL_TESSELLATION_MODE_AMD 0x9004 -#define GL_TESSELLATION_FACTOR_AMD 0x9005 -#define GL_DISCRETE_AMD 0x9006 -#define GL_CONTINUOUS_AMD 0x9007 -#endif - -#ifndef GL_EXT_provoking_vertex -#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT 0x8E4C -#define GL_FIRST_VERTEX_CONVENTION_EXT 0x8E4D -#define GL_LAST_VERTEX_CONVENTION_EXT 0x8E4E -#define GL_PROVOKING_VERTEX_EXT 0x8E4F -#endif - -#ifndef GL_EXT_texture_snorm -#define GL_ALPHA_SNORM 0x9010 -#define GL_LUMINANCE_SNORM 0x9011 -#define GL_LUMINANCE_ALPHA_SNORM 0x9012 -#define GL_INTENSITY_SNORM 0x9013 -#define GL_ALPHA8_SNORM 0x9014 -#define GL_LUMINANCE8_SNORM 0x9015 -#define GL_LUMINANCE8_ALPHA8_SNORM 0x9016 -#define GL_INTENSITY8_SNORM 0x9017 -#define GL_ALPHA16_SNORM 0x9018 -#define GL_LUMINANCE16_SNORM 0x9019 -#define GL_LUMINANCE16_ALPHA16_SNORM 0x901A -#define GL_INTENSITY16_SNORM 0x901B -/* reuse GL_RED_SNORM */ -/* reuse GL_RG_SNORM */ -/* reuse GL_RGB_SNORM */ -/* reuse GL_RGBA_SNORM */ -/* reuse GL_R8_SNORM */ -/* reuse GL_RG8_SNORM */ -/* reuse GL_RGB8_SNORM */ -/* reuse GL_RGBA8_SNORM */ -/* reuse GL_R16_SNORM */ -/* reuse GL_RG16_SNORM */ -/* reuse GL_RGB16_SNORM */ -/* reuse GL_RGBA16_SNORM */ -/* reuse GL_SIGNED_NORMALIZED */ -#endif - -#ifndef GL_AMD_draw_buffers_blend -#endif - -#ifndef GL_APPLE_texture_range -#define GL_TEXTURE_RANGE_LENGTH_APPLE 0x85B7 -#define GL_TEXTURE_RANGE_POINTER_APPLE 0x85B8 -#define GL_TEXTURE_STORAGE_HINT_APPLE 0x85BC -#define GL_STORAGE_PRIVATE_APPLE 0x85BD -/* reuse GL_STORAGE_CACHED_APPLE */ -/* reuse GL_STORAGE_SHARED_APPLE */ -#endif - -#ifndef GL_APPLE_float_pixels -#define GL_HALF_APPLE 0x140B -#define GL_RGBA_FLOAT32_APPLE 0x8814 -#define GL_RGB_FLOAT32_APPLE 0x8815 -#define GL_ALPHA_FLOAT32_APPLE 0x8816 -#define GL_INTENSITY_FLOAT32_APPLE 0x8817 -#define GL_LUMINANCE_FLOAT32_APPLE 0x8818 -#define GL_LUMINANCE_ALPHA_FLOAT32_APPLE 0x8819 -#define GL_RGBA_FLOAT16_APPLE 0x881A -#define GL_RGB_FLOAT16_APPLE 0x881B -#define GL_ALPHA_FLOAT16_APPLE 0x881C -#define GL_INTENSITY_FLOAT16_APPLE 0x881D -#define GL_LUMINANCE_FLOAT16_APPLE 0x881E -#define GL_LUMINANCE_ALPHA_FLOAT16_APPLE 0x881F -#define GL_COLOR_FLOAT_APPLE 0x8A0F -#endif - -#ifndef GL_APPLE_vertex_program_evaluators -#define GL_VERTEX_ATTRIB_MAP1_APPLE 0x8A00 -#define GL_VERTEX_ATTRIB_MAP2_APPLE 0x8A01 -#define GL_VERTEX_ATTRIB_MAP1_SIZE_APPLE 0x8A02 -#define GL_VERTEX_ATTRIB_MAP1_COEFF_APPLE 0x8A03 -#define GL_VERTEX_ATTRIB_MAP1_ORDER_APPLE 0x8A04 -#define GL_VERTEX_ATTRIB_MAP1_DOMAIN_APPLE 0x8A05 -#define GL_VERTEX_ATTRIB_MAP2_SIZE_APPLE 0x8A06 -#define GL_VERTEX_ATTRIB_MAP2_COEFF_APPLE 0x8A07 -#define GL_VERTEX_ATTRIB_MAP2_ORDER_APPLE 0x8A08 -#define GL_VERTEX_ATTRIB_MAP2_DOMAIN_APPLE 0x8A09 -#endif - -#ifndef GL_APPLE_aux_depth_stencil -#define GL_AUX_DEPTH_STENCIL_APPLE 0x8A14 -#endif - -#ifndef GL_APPLE_object_purgeable -#define GL_BUFFER_OBJECT_APPLE 0x85B3 -#define GL_RELEASED_APPLE 0x8A19 -#define GL_VOLATILE_APPLE 0x8A1A -#define GL_RETAINED_APPLE 0x8A1B -#define GL_UNDEFINED_APPLE 0x8A1C -#define GL_PURGEABLE_APPLE 0x8A1D -#endif - -#ifndef GL_APPLE_row_bytes -#define GL_PACK_ROW_BYTES_APPLE 0x8A15 -#define GL_UNPACK_ROW_BYTES_APPLE 0x8A16 -#endif - -#ifndef GL_APPLE_rgb_422 -#define GL_RGB_422_APPLE 0x8A1F -/* reuse GL_UNSIGNED_SHORT_8_8_APPLE */ -/* reuse GL_UNSIGNED_SHORT_8_8_REV_APPLE */ -#endif - -#ifndef GL_NV_video_capture -#define GL_VIDEO_BUFFER_NV 0x9020 -#define GL_VIDEO_BUFFER_BINDING_NV 0x9021 -#define GL_FIELD_UPPER_NV 0x9022 -#define GL_FIELD_LOWER_NV 0x9023 -#define GL_NUM_VIDEO_CAPTURE_STREAMS_NV 0x9024 -#define GL_NEXT_VIDEO_CAPTURE_BUFFER_STATUS_NV 0x9025 -#define GL_VIDEO_CAPTURE_TO_422_SUPPORTED_NV 0x9026 -#define GL_LAST_VIDEO_CAPTURE_STATUS_NV 0x9027 -#define GL_VIDEO_BUFFER_PITCH_NV 0x9028 -#define GL_VIDEO_COLOR_CONVERSION_MATRIX_NV 0x9029 -#define GL_VIDEO_COLOR_CONVERSION_MAX_NV 0x902A -#define GL_VIDEO_COLOR_CONVERSION_MIN_NV 0x902B -#define GL_VIDEO_COLOR_CONVERSION_OFFSET_NV 0x902C -#define GL_VIDEO_BUFFER_INTERNAL_FORMAT_NV 0x902D -#define GL_PARTIAL_SUCCESS_NV 0x902E -#define GL_SUCCESS_NV 0x902F -#define GL_FAILURE_NV 0x9030 -#define GL_YCBYCR8_422_NV 0x9031 -#define GL_YCBAYCR8A_4224_NV 0x9032 -#define GL_Z6Y10Z6CB10Z6Y10Z6CR10_422_NV 0x9033 -#define GL_Z6Y10Z6CB10Z6A10Z6Y10Z6CR10Z6A10_4224_NV 0x9034 -#define GL_Z4Y12Z4CB12Z4Y12Z4CR12_422_NV 0x9035 -#define GL_Z4Y12Z4CB12Z4A12Z4Y12Z4CR12Z4A12_4224_NV 0x9036 -#define GL_Z4Y12Z4CB12Z4CR12_444_NV 0x9037 -#define GL_VIDEO_CAPTURE_FRAME_WIDTH_NV 0x9038 -#define GL_VIDEO_CAPTURE_FRAME_HEIGHT_NV 0x9039 -#define GL_VIDEO_CAPTURE_FIELD_UPPER_HEIGHT_NV 0x903A -#define GL_VIDEO_CAPTURE_FIELD_LOWER_HEIGHT_NV 0x903B -#define GL_VIDEO_CAPTURE_SURFACE_ORIGIN_NV 0x903C -#endif - -#ifndef GL_NV_copy_image -#endif - -#ifndef GL_EXT_separate_shader_objects -#define GL_ACTIVE_PROGRAM_EXT 0x8B8D -#endif - -#ifndef GL_NV_parameter_buffer_object2 -#endif - -#ifndef GL_NV_shader_buffer_load -#define GL_BUFFER_GPU_ADDRESS_NV 0x8F1D -#define GL_GPU_ADDRESS_NV 0x8F34 -#define GL_MAX_SHADER_BUFFER_ADDRESS_NV 0x8F35 -#endif - -#ifndef GL_NV_vertex_buffer_unified_memory -#define GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV 0x8F1E -#define GL_ELEMENT_ARRAY_UNIFIED_NV 0x8F1F -#define GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV 0x8F20 -#define GL_VERTEX_ARRAY_ADDRESS_NV 0x8F21 -#define GL_NORMAL_ARRAY_ADDRESS_NV 0x8F22 -#define GL_COLOR_ARRAY_ADDRESS_NV 0x8F23 -#define GL_INDEX_ARRAY_ADDRESS_NV 0x8F24 -#define GL_TEXTURE_COORD_ARRAY_ADDRESS_NV 0x8F25 -#define GL_EDGE_FLAG_ARRAY_ADDRESS_NV 0x8F26 -#define GL_SECONDARY_COLOR_ARRAY_ADDRESS_NV 0x8F27 -#define GL_FOG_COORD_ARRAY_ADDRESS_NV 0x8F28 -#define GL_ELEMENT_ARRAY_ADDRESS_NV 0x8F29 -#define GL_VERTEX_ATTRIB_ARRAY_LENGTH_NV 0x8F2A -#define GL_VERTEX_ARRAY_LENGTH_NV 0x8F2B -#define GL_NORMAL_ARRAY_LENGTH_NV 0x8F2C -#define GL_COLOR_ARRAY_LENGTH_NV 0x8F2D -#define GL_INDEX_ARRAY_LENGTH_NV 0x8F2E -#define GL_TEXTURE_COORD_ARRAY_LENGTH_NV 0x8F2F -#define GL_EDGE_FLAG_ARRAY_LENGTH_NV 0x8F30 -#define GL_SECONDARY_COLOR_ARRAY_LENGTH_NV 0x8F31 -#define GL_FOG_COORD_ARRAY_LENGTH_NV 0x8F32 -#define GL_ELEMENT_ARRAY_LENGTH_NV 0x8F33 -#define GL_DRAW_INDIRECT_UNIFIED_NV 0x8F40 -#define GL_DRAW_INDIRECT_ADDRESS_NV 0x8F41 -#define GL_DRAW_INDIRECT_LENGTH_NV 0x8F42 -#endif - -#ifndef GL_NV_texture_barrier -#endif - -#ifndef GL_AMD_shader_stencil_export -#endif - -#ifndef GL_AMD_seamless_cubemap_per_texture -/* reuse GL_TEXTURE_CUBE_MAP_SEAMLESS */ -#endif - -#ifndef GL_AMD_conservative_depth -#endif - -#ifndef GL_EXT_shader_image_load_store -#define GL_MAX_IMAGE_UNITS_EXT 0x8F38 -#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS_EXT 0x8F39 -#define GL_IMAGE_BINDING_NAME_EXT 0x8F3A -#define GL_IMAGE_BINDING_LEVEL_EXT 0x8F3B -#define GL_IMAGE_BINDING_LAYERED_EXT 0x8F3C -#define GL_IMAGE_BINDING_LAYER_EXT 0x8F3D -#define GL_IMAGE_BINDING_ACCESS_EXT 0x8F3E -#define GL_IMAGE_1D_EXT 0x904C -#define GL_IMAGE_2D_EXT 0x904D -#define GL_IMAGE_3D_EXT 0x904E -#define GL_IMAGE_2D_RECT_EXT 0x904F -#define GL_IMAGE_CUBE_EXT 0x9050 -#define GL_IMAGE_BUFFER_EXT 0x9051 -#define GL_IMAGE_1D_ARRAY_EXT 0x9052 -#define GL_IMAGE_2D_ARRAY_EXT 0x9053 -#define GL_IMAGE_CUBE_MAP_ARRAY_EXT 0x9054 -#define GL_IMAGE_2D_MULTISAMPLE_EXT 0x9055 -#define GL_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x9056 -#define GL_INT_IMAGE_1D_EXT 0x9057 -#define GL_INT_IMAGE_2D_EXT 0x9058 -#define GL_INT_IMAGE_3D_EXT 0x9059 -#define GL_INT_IMAGE_2D_RECT_EXT 0x905A -#define GL_INT_IMAGE_CUBE_EXT 0x905B -#define GL_INT_IMAGE_BUFFER_EXT 0x905C -#define GL_INT_IMAGE_1D_ARRAY_EXT 0x905D -#define GL_INT_IMAGE_2D_ARRAY_EXT 0x905E -#define GL_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x905F -#define GL_INT_IMAGE_2D_MULTISAMPLE_EXT 0x9060 -#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x9061 -#define GL_UNSIGNED_INT_IMAGE_1D_EXT 0x9062 -#define GL_UNSIGNED_INT_IMAGE_2D_EXT 0x9063 -#define GL_UNSIGNED_INT_IMAGE_3D_EXT 0x9064 -#define GL_UNSIGNED_INT_IMAGE_2D_RECT_EXT 0x9065 -#define GL_UNSIGNED_INT_IMAGE_CUBE_EXT 0x9066 -#define GL_UNSIGNED_INT_IMAGE_BUFFER_EXT 0x9067 -#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY_EXT 0x9068 -#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY_EXT 0x9069 -#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x906A -#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_EXT 0x906B -#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x906C -#define GL_MAX_IMAGE_SAMPLES_EXT 0x906D -#define GL_IMAGE_BINDING_FORMAT_EXT 0x906E -#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT_EXT 0x00000001 -#define GL_ELEMENT_ARRAY_BARRIER_BIT_EXT 0x00000002 -#define GL_UNIFORM_BARRIER_BIT_EXT 0x00000004 -#define GL_TEXTURE_FETCH_BARRIER_BIT_EXT 0x00000008 -#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT_EXT 0x00000020 -#define GL_COMMAND_BARRIER_BIT_EXT 0x00000040 -#define GL_PIXEL_BUFFER_BARRIER_BIT_EXT 0x00000080 -#define GL_TEXTURE_UPDATE_BARRIER_BIT_EXT 0x00000100 -#define GL_BUFFER_UPDATE_BARRIER_BIT_EXT 0x00000200 -#define GL_FRAMEBUFFER_BARRIER_BIT_EXT 0x00000400 -#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT_EXT 0x00000800 -#define GL_ATOMIC_COUNTER_BARRIER_BIT_EXT 0x00001000 -#define GL_ALL_BARRIER_BITS_EXT 0xFFFFFFFF -#endif - -#ifndef GL_EXT_vertex_attrib_64bit -/* reuse GL_DOUBLE */ -#define GL_DOUBLE_VEC2_EXT 0x8FFC -#define GL_DOUBLE_VEC3_EXT 0x8FFD -#define GL_DOUBLE_VEC4_EXT 0x8FFE -#define GL_DOUBLE_MAT2_EXT 0x8F46 -#define GL_DOUBLE_MAT3_EXT 0x8F47 -#define GL_DOUBLE_MAT4_EXT 0x8F48 -#define GL_DOUBLE_MAT2x3_EXT 0x8F49 -#define GL_DOUBLE_MAT2x4_EXT 0x8F4A -#define GL_DOUBLE_MAT3x2_EXT 0x8F4B -#define GL_DOUBLE_MAT3x4_EXT 0x8F4C -#define GL_DOUBLE_MAT4x2_EXT 0x8F4D -#define GL_DOUBLE_MAT4x3_EXT 0x8F4E -#endif - -#ifndef GL_NV_gpu_program5 -#define GL_MAX_GEOMETRY_PROGRAM_INVOCATIONS_NV 0x8E5A -#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_NV 0x8E5B -#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_NV 0x8E5C -#define GL_FRAGMENT_PROGRAM_INTERPOLATION_OFFSET_BITS_NV 0x8E5D -#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_NV 0x8E5E -#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_NV 0x8E5F -#define GL_MAX_PROGRAM_SUBROUTINE_PARAMETERS_NV 0x8F44 -#define GL_MAX_PROGRAM_SUBROUTINE_NUM_NV 0x8F45 -#endif - -#ifndef GL_NV_gpu_shader5 -#define GL_INT64_NV 0x140E -#define GL_UNSIGNED_INT64_NV 0x140F -#define GL_INT8_NV 0x8FE0 -#define GL_INT8_VEC2_NV 0x8FE1 -#define GL_INT8_VEC3_NV 0x8FE2 -#define GL_INT8_VEC4_NV 0x8FE3 -#define GL_INT16_NV 0x8FE4 -#define GL_INT16_VEC2_NV 0x8FE5 -#define GL_INT16_VEC3_NV 0x8FE6 -#define GL_INT16_VEC4_NV 0x8FE7 -#define GL_INT64_VEC2_NV 0x8FE9 -#define GL_INT64_VEC3_NV 0x8FEA -#define GL_INT64_VEC4_NV 0x8FEB -#define GL_UNSIGNED_INT8_NV 0x8FEC -#define GL_UNSIGNED_INT8_VEC2_NV 0x8FED -#define GL_UNSIGNED_INT8_VEC3_NV 0x8FEE -#define GL_UNSIGNED_INT8_VEC4_NV 0x8FEF -#define GL_UNSIGNED_INT16_NV 0x8FF0 -#define GL_UNSIGNED_INT16_VEC2_NV 0x8FF1 -#define GL_UNSIGNED_INT16_VEC3_NV 0x8FF2 -#define GL_UNSIGNED_INT16_VEC4_NV 0x8FF3 -#define GL_UNSIGNED_INT64_VEC2_NV 0x8FF5 -#define GL_UNSIGNED_INT64_VEC3_NV 0x8FF6 -#define GL_UNSIGNED_INT64_VEC4_NV 0x8FF7 -#define GL_FLOAT16_NV 0x8FF8 -#define GL_FLOAT16_VEC2_NV 0x8FF9 -#define GL_FLOAT16_VEC3_NV 0x8FFA -#define GL_FLOAT16_VEC4_NV 0x8FFB -/* reuse GL_PATCHES */ -#endif - -#ifndef GL_NV_shader_buffer_store -#define GL_SHADER_GLOBAL_ACCESS_BARRIER_BIT_NV 0x00000010 -/* reuse GL_READ_WRITE */ -/* reuse GL_WRITE_ONLY */ -#endif - -#ifndef GL_NV_tessellation_program5 -#define GL_MAX_PROGRAM_PATCH_ATTRIBS_NV 0x86D8 -#define GL_TESS_CONTROL_PROGRAM_NV 0x891E -#define GL_TESS_EVALUATION_PROGRAM_NV 0x891F -#define GL_TESS_CONTROL_PROGRAM_PARAMETER_BUFFER_NV 0x8C74 -#define GL_TESS_EVALUATION_PROGRAM_PARAMETER_BUFFER_NV 0x8C75 -#endif - -#ifndef GL_NV_vertex_attrib_integer_64bit -/* reuse GL_INT64_NV */ -/* reuse GL_UNSIGNED_INT64_NV */ -#endif - -#ifndef GL_NV_multisample_coverage -#define GL_COVERAGE_SAMPLES_NV 0x80A9 -#define GL_COLOR_SAMPLES_NV 0x8E20 -#endif - -#ifndef GL_AMD_name_gen_delete -#define GL_DATA_BUFFER_AMD 0x9151 -#define GL_PERFORMANCE_MONITOR_AMD 0x9152 -#define GL_QUERY_OBJECT_AMD 0x9153 -#define GL_VERTEX_ARRAY_OBJECT_AMD 0x9154 -#define GL_SAMPLER_OBJECT_AMD 0x9155 -#endif - -#ifndef GL_AMD_debug_output -#define GL_MAX_DEBUG_LOGGED_MESSAGES_AMD 0x9144 -#define GL_DEBUG_LOGGED_MESSAGES_AMD 0x9145 -#define GL_DEBUG_SEVERITY_HIGH_AMD 0x9146 -#define GL_DEBUG_SEVERITY_MEDIUM_AMD 0x9147 -#define GL_DEBUG_SEVERITY_LOW_AMD 0x9148 -#define GL_DEBUG_CATEGORY_API_ERROR_AMD 0x9149 -#define GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD 0x914A -#define GL_DEBUG_CATEGORY_DEPRECATION_AMD 0x914B -#define GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD 0x914C -#define GL_DEBUG_CATEGORY_PERFORMANCE_AMD 0x914D -#define GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD 0x914E -#define GL_DEBUG_CATEGORY_APPLICATION_AMD 0x914F -#define GL_DEBUG_CATEGORY_OTHER_AMD 0x9150 -#endif - -#ifndef GL_NV_vdpau_interop -#define GL_SURFACE_STATE_NV 0x86EB -#define GL_SURFACE_REGISTERED_NV 0x86FD -#define GL_SURFACE_MAPPED_NV 0x8700 -#define GL_WRITE_DISCARD_NV 0x88BE -#endif - -#ifndef GL_AMD_transform_feedback3_lines_triangles -#endif - -#ifndef GL_AMD_depth_clamp_separate -#define GL_DEPTH_CLAMP_NEAR_AMD 0x901E -#define GL_DEPTH_CLAMP_FAR_AMD 0x901F -#endif - -#ifndef GL_EXT_texture_sRGB_decode -#define GL_TEXTURE_SRGB_DECODE_EXT 0x8A48 -#define GL_DECODE_EXT 0x8A49 -#define GL_SKIP_DECODE_EXT 0x8A4A -#endif - -#ifndef GL_NV_texture_multisample -#define GL_TEXTURE_COVERAGE_SAMPLES_NV 0x9045 -#define GL_TEXTURE_COLOR_SAMPLES_NV 0x9046 -#endif - -#ifndef GL_AMD_blend_minmax_factor -#define GL_FACTOR_MIN_AMD 0x901C -#define GL_FACTOR_MAX_AMD 0x901D -#endif - -#ifndef GL_AMD_sample_positions -#define GL_SUBSAMPLE_DISTANCE_AMD 0x883F -#endif - -#ifndef GL_EXT_x11_sync_object -#define GL_SYNC_X11_FENCE_EXT 0x90E1 -#endif - -#ifndef GL_AMD_multi_draw_indirect -#endif - -#ifndef GL_EXT_framebuffer_multisample_blit_scaled -#define GL_SCALED_RESOLVE_FASTEST_EXT 0x90BA -#define GL_SCALED_RESOLVE_NICEST_EXT 0x90BB -#endif - -#ifndef GL_NV_path_rendering -#define GL_PATH_FORMAT_SVG_NV 0x9070 -#define GL_PATH_FORMAT_PS_NV 0x9071 -#define GL_STANDARD_FONT_NAME_NV 0x9072 -#define GL_SYSTEM_FONT_NAME_NV 0x9073 -#define GL_FILE_NAME_NV 0x9074 -#define GL_PATH_STROKE_WIDTH_NV 0x9075 -#define GL_PATH_END_CAPS_NV 0x9076 -#define GL_PATH_INITIAL_END_CAP_NV 0x9077 -#define GL_PATH_TERMINAL_END_CAP_NV 0x9078 -#define GL_PATH_JOIN_STYLE_NV 0x9079 -#define GL_PATH_MITER_LIMIT_NV 0x907A -#define GL_PATH_DASH_CAPS_NV 0x907B -#define GL_PATH_INITIAL_DASH_CAP_NV 0x907C -#define GL_PATH_TERMINAL_DASH_CAP_NV 0x907D -#define GL_PATH_DASH_OFFSET_NV 0x907E -#define GL_PATH_CLIENT_LENGTH_NV 0x907F -#define GL_PATH_FILL_MODE_NV 0x9080 -#define GL_PATH_FILL_MASK_NV 0x9081 -#define GL_PATH_FILL_COVER_MODE_NV 0x9082 -#define GL_PATH_STROKE_COVER_MODE_NV 0x9083 -#define GL_PATH_STROKE_MASK_NV 0x9084 -#define GL_PATH_SAMPLE_QUALITY_NV 0x9085 -#define GL_PATH_STROKE_BOUND_NV 0x9086 -#define GL_PATH_STROKE_OVERSAMPLE_COUNT_NV 0x9087 -#define GL_COUNT_UP_NV 0x9088 -#define GL_COUNT_DOWN_NV 0x9089 -#define GL_PATH_OBJECT_BOUNDING_BOX_NV 0x908A -#define GL_CONVEX_HULL_NV 0x908B -#define GL_MULTI_HULLS_NV 0x908C -#define GL_BOUNDING_BOX_NV 0x908D -#define GL_TRANSLATE_X_NV 0x908E -#define GL_TRANSLATE_Y_NV 0x908F -#define GL_TRANSLATE_2D_NV 0x9090 -#define GL_TRANSLATE_3D_NV 0x9091 -#define GL_AFFINE_2D_NV 0x9092 -#define GL_PROJECTIVE_2D_NV 0x9093 -#define GL_AFFINE_3D_NV 0x9094 -#define GL_PROJECTIVE_3D_NV 0x9095 -#define GL_TRANSPOSE_AFFINE_2D_NV 0x9096 -#define GL_TRANSPOSE_PROJECTIVE_2D_NV 0x9097 -#define GL_TRANSPOSE_AFFINE_3D_NV 0x9098 -#define GL_TRANSPOSE_PROJECTIVE_3D_NV 0x9099 -#define GL_UTF8_NV 0x909A -#define GL_UTF16_NV 0x909B -#define GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV 0x909C -#define GL_PATH_COMMAND_COUNT_NV 0x909D -#define GL_PATH_COORD_COUNT_NV 0x909E -#define GL_PATH_DASH_ARRAY_COUNT_NV 0x909F -#define GL_PATH_COMPUTED_LENGTH_NV 0x90A0 -#define GL_PATH_FILL_BOUNDING_BOX_NV 0x90A1 -#define GL_PATH_STROKE_BOUNDING_BOX_NV 0x90A2 -#define GL_SQUARE_NV 0x90A3 -#define GL_ROUND_NV 0x90A4 -#define GL_TRIANGULAR_NV 0x90A5 -#define GL_BEVEL_NV 0x90A6 -#define GL_MITER_REVERT_NV 0x90A7 -#define GL_MITER_TRUNCATE_NV 0x90A8 -#define GL_SKIP_MISSING_GLYPH_NV 0x90A9 -#define GL_USE_MISSING_GLYPH_NV 0x90AA -#define GL_PATH_ERROR_POSITION_NV 0x90AB -#define GL_PATH_FOG_GEN_MODE_NV 0x90AC -#define GL_ACCUM_ADJACENT_PAIRS_NV 0x90AD -#define GL_ADJACENT_PAIRS_NV 0x90AE -#define GL_FIRST_TO_REST_NV 0x90AF -#define GL_PATH_GEN_MODE_NV 0x90B0 -#define GL_PATH_GEN_COEFF_NV 0x90B1 -#define GL_PATH_GEN_COLOR_FORMAT_NV 0x90B2 -#define GL_PATH_GEN_COMPONENTS_NV 0x90B3 -#define GL_PATH_STENCIL_FUNC_NV 0x90B7 -#define GL_PATH_STENCIL_REF_NV 0x90B8 -#define GL_PATH_STENCIL_VALUE_MASK_NV 0x90B9 -#define GL_PATH_STENCIL_DEPTH_OFFSET_FACTOR_NV 0x90BD -#define GL_PATH_STENCIL_DEPTH_OFFSET_UNITS_NV 0x90BE -#define GL_PATH_COVER_DEPTH_FUNC_NV 0x90BF -#define GL_PATH_DASH_OFFSET_RESET_NV 0x90B4 -#define GL_MOVE_TO_RESETS_NV 0x90B5 -#define GL_MOVE_TO_CONTINUES_NV 0x90B6 -#define GL_CLOSE_PATH_NV 0x00 -#define GL_MOVE_TO_NV 0x02 -#define GL_RELATIVE_MOVE_TO_NV 0x03 -#define GL_LINE_TO_NV 0x04 -#define GL_RELATIVE_LINE_TO_NV 0x05 -#define GL_HORIZONTAL_LINE_TO_NV 0x06 -#define GL_RELATIVE_HORIZONTAL_LINE_TO_NV 0x07 -#define GL_VERTICAL_LINE_TO_NV 0x08 -#define GL_RELATIVE_VERTICAL_LINE_TO_NV 0x09 -#define GL_QUADRATIC_CURVE_TO_NV 0x0A -#define GL_RELATIVE_QUADRATIC_CURVE_TO_NV 0x0B -#define GL_CUBIC_CURVE_TO_NV 0x0C -#define GL_RELATIVE_CUBIC_CURVE_TO_NV 0x0D -#define GL_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0E -#define GL_RELATIVE_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0F -#define GL_SMOOTH_CUBIC_CURVE_TO_NV 0x10 -#define GL_RELATIVE_SMOOTH_CUBIC_CURVE_TO_NV 0x11 -#define GL_SMALL_CCW_ARC_TO_NV 0x12 -#define GL_RELATIVE_SMALL_CCW_ARC_TO_NV 0x13 -#define GL_SMALL_CW_ARC_TO_NV 0x14 -#define GL_RELATIVE_SMALL_CW_ARC_TO_NV 0x15 -#define GL_LARGE_CCW_ARC_TO_NV 0x16 -#define GL_RELATIVE_LARGE_CCW_ARC_TO_NV 0x17 -#define GL_LARGE_CW_ARC_TO_NV 0x18 -#define GL_RELATIVE_LARGE_CW_ARC_TO_NV 0x19 -#define GL_RESTART_PATH_NV 0xF0 -#define GL_DUP_FIRST_CUBIC_CURVE_TO_NV 0xF2 -#define GL_DUP_LAST_CUBIC_CURVE_TO_NV 0xF4 -#define GL_RECT_NV 0xF6 -#define GL_CIRCULAR_CCW_ARC_TO_NV 0xF8 -#define GL_CIRCULAR_CW_ARC_TO_NV 0xFA -#define GL_CIRCULAR_TANGENT_ARC_TO_NV 0xFC -#define GL_ARC_TO_NV 0xFE -#define GL_RELATIVE_ARC_TO_NV 0xFF -#define GL_BOLD_BIT_NV 0x01 -#define GL_ITALIC_BIT_NV 0x02 -#define GL_GLYPH_WIDTH_BIT_NV 0x01 -#define GL_GLYPH_HEIGHT_BIT_NV 0x02 -#define GL_GLYPH_HORIZONTAL_BEARING_X_BIT_NV 0x04 -#define GL_GLYPH_HORIZONTAL_BEARING_Y_BIT_NV 0x08 -#define GL_GLYPH_HORIZONTAL_BEARING_ADVANCE_BIT_NV 0x10 -#define GL_GLYPH_VERTICAL_BEARING_X_BIT_NV 0x20 -#define GL_GLYPH_VERTICAL_BEARING_Y_BIT_NV 0x40 -#define GL_GLYPH_VERTICAL_BEARING_ADVANCE_BIT_NV 0x80 -#define GL_GLYPH_HAS_KERNING_NV 0x100 -#define GL_FONT_X_MIN_BOUNDS_NV 0x00010000 -#define GL_FONT_Y_MIN_BOUNDS_NV 0x00020000 -#define GL_FONT_X_MAX_BOUNDS_NV 0x00040000 -#define GL_FONT_Y_MAX_BOUNDS_NV 0x00080000 -#define GL_FONT_UNITS_PER_EM_NV 0x00100000 -#define GL_FONT_ASCENDER_NV 0x00200000 -#define GL_FONT_DESCENDER_NV 0x00400000 -#define GL_FONT_HEIGHT_NV 0x00800000 -#define GL_FONT_MAX_ADVANCE_WIDTH_NV 0x01000000 -#define GL_FONT_MAX_ADVANCE_HEIGHT_NV 0x02000000 -#define GL_FONT_UNDERLINE_POSITION_NV 0x04000000 -#define GL_FONT_UNDERLINE_THICKNESS_NV 0x08000000 -#define GL_FONT_HAS_KERNING_NV 0x10000000 -#endif - -#ifndef GL_AMD_pinned_memory -#define GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD 0x9160 -#endif - -#ifndef GL_AMD_stencil_operation_extended -#define GL_SET_AMD 0x874A -#define GL_REPLACE_VALUE_AMD 0x874B -#define GL_STENCIL_OP_VALUE_AMD 0x874C -#define GL_STENCIL_BACK_OP_VALUE_AMD 0x874D -#endif - - -/*************************************************************/ - -#include -#ifndef GL_VERSION_2_0 -/* GL type for program/shader text */ -typedef char GLchar; -#endif - -#ifndef GL_VERSION_1_5 -/* GL types for handling large vertex buffer objects */ -typedef ptrdiff_t GLintptr; -typedef ptrdiff_t GLsizeiptr; -#endif - -#ifndef GL_ARB_vertex_buffer_object -/* GL types for handling large vertex buffer objects */ -typedef ptrdiff_t GLintptrARB; -typedef ptrdiff_t GLsizeiptrARB; -#endif - -#ifndef GL_ARB_shader_objects -/* GL types for program/shader text and shader object handles */ -typedef char GLcharARB; -typedef unsigned int GLhandleARB; -#endif - -/* GL type for "half" precision (s10e5) float data in host memory */ -#ifndef GL_ARB_half_float_pixel -typedef unsigned short GLhalfARB; -#endif - -#ifndef GL_NV_half_float -typedef unsigned short GLhalfNV; -#endif - -#ifndef GLEXT_64_TYPES_DEFINED -/* This code block is duplicated in glxext.h, so must be protected */ -#define GLEXT_64_TYPES_DEFINED -/* Define int32_t, int64_t, and uint64_t types for UST/MSC */ -/* (as used in the GL_EXT_timer_query extension). */ -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L -#include -#elif defined(__sun__) || defined(__digital__) -#include -#if defined(__STDC__) -#if defined(__arch64__) || defined(_LP64) -typedef long int int64_t; -typedef unsigned long int uint64_t; -#else -typedef long long int int64_t; -typedef unsigned long long int uint64_t; -#endif /* __arch64__ */ -#endif /* __STDC__ */ -#elif defined( __VMS ) || defined(__sgi) -#include -#elif defined(__SCO__) || defined(__USLC__) -#include -#elif defined(__UNIXOS2__) || defined(__SOL64__) -typedef long int int32_t; -typedef long long int int64_t; -typedef unsigned long long int uint64_t; -#elif defined(_WIN32) && defined(__GNUC__) -#include -#elif defined(_WIN32) -typedef __int32 int32_t; -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -#else -/* Fallback if nothing above works */ -#include -#endif -#endif - -#ifndef GL_EXT_timer_query -typedef int64_t GLint64EXT; -typedef uint64_t GLuint64EXT; -#endif - -#ifndef GL_ARB_sync -typedef int64_t GLint64; -typedef uint64_t GLuint64; -typedef struct __GLsync *GLsync; -#endif - -#ifndef GL_ARB_cl_event -/* These incomplete types let us declare types compatible with OpenCL's cl_context and cl_event */ -struct _cl_context; -struct _cl_event; -#endif - -#ifndef GL_ARB_debug_output -typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,GLvoid *userParam); -#endif - -#ifndef GL_AMD_debug_output -typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,GLvoid *userParam); -#endif - -#ifndef GL_NV_vdpau_interop -typedef GLintptr GLvdpauSurfaceNV; -#endif - -#ifndef GL_VERSION_1_2 -#define GL_VERSION_1_2 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); -GLAPI void APIENTRY glBlendEquation (GLenum mode); -GLAPI void APIENTRY glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); -GLAPI void APIENTRY glTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBLENDCOLORPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); -typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode); -typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); -typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -#endif - -#ifndef GL_VERSION_1_2_DEPRECATED -#define GL_VERSION_1_2_DEPRECATED 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColorTable (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); -GLAPI void APIENTRY glColorTableParameterfv (GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glColorTableParameteriv (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glCopyColorTable (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glGetColorTable (GLenum target, GLenum format, GLenum type, GLvoid *table); -GLAPI void APIENTRY glGetColorTableParameterfv (GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetColorTableParameteriv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glColorSubTable (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); -GLAPI void APIENTRY glCopyColorSubTable (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glConvolutionFilter1D (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); -GLAPI void APIENTRY glConvolutionFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); -GLAPI void APIENTRY glConvolutionParameterf (GLenum target, GLenum pname, GLfloat params); -GLAPI void APIENTRY glConvolutionParameterfv (GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glConvolutionParameteri (GLenum target, GLenum pname, GLint params); -GLAPI void APIENTRY glConvolutionParameteriv (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glCopyConvolutionFilter1D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glCopyConvolutionFilter2D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetConvolutionFilter (GLenum target, GLenum format, GLenum type, GLvoid *image); -GLAPI void APIENTRY glGetConvolutionParameterfv (GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetConvolutionParameteriv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetSeparableFilter (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); -GLAPI void APIENTRY glSeparableFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); -GLAPI void APIENTRY glGetHistogram (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); -GLAPI void APIENTRY glGetHistogramParameterfv (GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetHistogramParameteriv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetMinmax (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); -GLAPI void APIENTRY glGetMinmaxParameterfv (GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetMinmaxParameteriv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glHistogram (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); -GLAPI void APIENTRY glMinmax (GLenum target, GLenum internalformat, GLboolean sink); -GLAPI void APIENTRY glResetHistogram (GLenum target); -GLAPI void APIENTRY glResetMinmax (GLenum target); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); -typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLCOPYCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table); -typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); -typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); -typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat params); -typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIPROC) (GLenum target, GLenum pname, GLint params); -typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image); -typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); -typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); -typedef void (APIENTRYP PFNGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); -typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); -typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLHISTOGRAMPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); -typedef void (APIENTRYP PFNGLMINMAXPROC) (GLenum target, GLenum internalformat, GLboolean sink); -typedef void (APIENTRYP PFNGLRESETHISTOGRAMPROC) (GLenum target); -typedef void (APIENTRYP PFNGLRESETMINMAXPROC) (GLenum target); -#endif - -#ifndef GL_VERSION_1_3 -#define GL_VERSION_1_3 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glActiveTexture (GLenum texture); -GLAPI void APIENTRY glSampleCoverage (GLclampf value, GLboolean invert); -GLAPI void APIENTRY glCompressedTexImage3D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexImage1D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glGetCompressedTexImage (GLenum target, GLint level, GLvoid *img); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture); -typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLclampf value, GLboolean invert); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, GLvoid *img); -#endif - -#ifndef GL_VERSION_1_3_DEPRECATED -#define GL_VERSION_1_3_DEPRECATED 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glClientActiveTexture (GLenum texture); -GLAPI void APIENTRY glMultiTexCoord1d (GLenum target, GLdouble s); -GLAPI void APIENTRY glMultiTexCoord1dv (GLenum target, const GLdouble *v); -GLAPI void APIENTRY glMultiTexCoord1f (GLenum target, GLfloat s); -GLAPI void APIENTRY glMultiTexCoord1fv (GLenum target, const GLfloat *v); -GLAPI void APIENTRY glMultiTexCoord1i (GLenum target, GLint s); -GLAPI void APIENTRY glMultiTexCoord1iv (GLenum target, const GLint *v); -GLAPI void APIENTRY glMultiTexCoord1s (GLenum target, GLshort s); -GLAPI void APIENTRY glMultiTexCoord1sv (GLenum target, const GLshort *v); -GLAPI void APIENTRY glMultiTexCoord2d (GLenum target, GLdouble s, GLdouble t); -GLAPI void APIENTRY glMultiTexCoord2dv (GLenum target, const GLdouble *v); -GLAPI void APIENTRY glMultiTexCoord2f (GLenum target, GLfloat s, GLfloat t); -GLAPI void APIENTRY glMultiTexCoord2fv (GLenum target, const GLfloat *v); -GLAPI void APIENTRY glMultiTexCoord2i (GLenum target, GLint s, GLint t); -GLAPI void APIENTRY glMultiTexCoord2iv (GLenum target, const GLint *v); -GLAPI void APIENTRY glMultiTexCoord2s (GLenum target, GLshort s, GLshort t); -GLAPI void APIENTRY glMultiTexCoord2sv (GLenum target, const GLshort *v); -GLAPI void APIENTRY glMultiTexCoord3d (GLenum target, GLdouble s, GLdouble t, GLdouble r); -GLAPI void APIENTRY glMultiTexCoord3dv (GLenum target, const GLdouble *v); -GLAPI void APIENTRY glMultiTexCoord3f (GLenum target, GLfloat s, GLfloat t, GLfloat r); -GLAPI void APIENTRY glMultiTexCoord3fv (GLenum target, const GLfloat *v); -GLAPI void APIENTRY glMultiTexCoord3i (GLenum target, GLint s, GLint t, GLint r); -GLAPI void APIENTRY glMultiTexCoord3iv (GLenum target, const GLint *v); -GLAPI void APIENTRY glMultiTexCoord3s (GLenum target, GLshort s, GLshort t, GLshort r); -GLAPI void APIENTRY glMultiTexCoord3sv (GLenum target, const GLshort *v); -GLAPI void APIENTRY glMultiTexCoord4d (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); -GLAPI void APIENTRY glMultiTexCoord4dv (GLenum target, const GLdouble *v); -GLAPI void APIENTRY glMultiTexCoord4f (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); -GLAPI void APIENTRY glMultiTexCoord4fv (GLenum target, const GLfloat *v); -GLAPI void APIENTRY glMultiTexCoord4i (GLenum target, GLint s, GLint t, GLint r, GLint q); -GLAPI void APIENTRY glMultiTexCoord4iv (GLenum target, const GLint *v); -GLAPI void APIENTRY glMultiTexCoord4s (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); -GLAPI void APIENTRY glMultiTexCoord4sv (GLenum target, const GLshort *v); -GLAPI void APIENTRY glLoadTransposeMatrixf (const GLfloat *m); -GLAPI void APIENTRY glLoadTransposeMatrixd (const GLdouble *m); -GLAPI void APIENTRY glMultTransposeMatrixf (const GLfloat *m); -GLAPI void APIENTRY glMultTransposeMatrixd (const GLdouble *m); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1DPROC) (GLenum target, GLdouble s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVPROC) (GLenum target, const GLdouble *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1FPROC) (GLenum target, GLfloat s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVPROC) (GLenum target, const GLfloat *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1IPROC) (GLenum target, GLint s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVPROC) (GLenum target, const GLint *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1SPROC) (GLenum target, GLshort s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVPROC) (GLenum target, const GLshort *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2DPROC) (GLenum target, GLdouble s, GLdouble t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVPROC) (GLenum target, const GLdouble *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC) (GLenum target, GLfloat s, GLfloat t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVPROC) (GLenum target, const GLfloat *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2IPROC) (GLenum target, GLint s, GLint t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVPROC) (GLenum target, const GLint *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2SPROC) (GLenum target, GLshort s, GLshort t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVPROC) (GLenum target, const GLshort *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVPROC) (GLenum target, const GLdouble *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVPROC) (GLenum target, const GLfloat *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3IPROC) (GLenum target, GLint s, GLint t, GLint r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVPROC) (GLenum target, const GLint *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3SPROC) (GLenum target, GLshort s, GLshort t, GLshort r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVPROC) (GLenum target, const GLshort *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVPROC) (GLenum target, const GLdouble *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVPROC) (GLenum target, const GLfloat *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4IPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVPROC) (GLenum target, const GLint *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4SPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVPROC) (GLenum target, const GLshort *v); -typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFPROC) (const GLfloat *m); -typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDPROC) (const GLdouble *m); -typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFPROC) (const GLfloat *m); -typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDPROC) (const GLdouble *m); -#endif - -#ifndef GL_VERSION_1_4 -#define GL_VERSION_1_4 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); -GLAPI void APIENTRY glMultiDrawArrays (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); -GLAPI void APIENTRY glMultiDrawElements (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); -GLAPI void APIENTRY glPointParameterf (GLenum pname, GLfloat param); -GLAPI void APIENTRY glPointParameterfv (GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glPointParameteri (GLenum pname, GLint param); -GLAPI void APIENTRY glPointParameteriv (GLenum pname, const GLint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); -typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); -typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC) (GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC) (GLenum pname, const GLint *params); -#endif - -#ifndef GL_VERSION_1_4_DEPRECATED -#define GL_VERSION_1_4_DEPRECATED 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFogCoordf (GLfloat coord); -GLAPI void APIENTRY glFogCoordfv (const GLfloat *coord); -GLAPI void APIENTRY glFogCoordd (GLdouble coord); -GLAPI void APIENTRY glFogCoorddv (const GLdouble *coord); -GLAPI void APIENTRY glFogCoordPointer (GLenum type, GLsizei stride, const GLvoid *pointer); -GLAPI void APIENTRY glSecondaryColor3b (GLbyte red, GLbyte green, GLbyte blue); -GLAPI void APIENTRY glSecondaryColor3bv (const GLbyte *v); -GLAPI void APIENTRY glSecondaryColor3d (GLdouble red, GLdouble green, GLdouble blue); -GLAPI void APIENTRY glSecondaryColor3dv (const GLdouble *v); -GLAPI void APIENTRY glSecondaryColor3f (GLfloat red, GLfloat green, GLfloat blue); -GLAPI void APIENTRY glSecondaryColor3fv (const GLfloat *v); -GLAPI void APIENTRY glSecondaryColor3i (GLint red, GLint green, GLint blue); -GLAPI void APIENTRY glSecondaryColor3iv (const GLint *v); -GLAPI void APIENTRY glSecondaryColor3s (GLshort red, GLshort green, GLshort blue); -GLAPI void APIENTRY glSecondaryColor3sv (const GLshort *v); -GLAPI void APIENTRY glSecondaryColor3ub (GLubyte red, GLubyte green, GLubyte blue); -GLAPI void APIENTRY glSecondaryColor3ubv (const GLubyte *v); -GLAPI void APIENTRY glSecondaryColor3ui (GLuint red, GLuint green, GLuint blue); -GLAPI void APIENTRY glSecondaryColor3uiv (const GLuint *v); -GLAPI void APIENTRY glSecondaryColor3us (GLushort red, GLushort green, GLushort blue); -GLAPI void APIENTRY glSecondaryColor3usv (const GLushort *v); -GLAPI void APIENTRY glSecondaryColorPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -GLAPI void APIENTRY glWindowPos2d (GLdouble x, GLdouble y); -GLAPI void APIENTRY glWindowPos2dv (const GLdouble *v); -GLAPI void APIENTRY glWindowPos2f (GLfloat x, GLfloat y); -GLAPI void APIENTRY glWindowPos2fv (const GLfloat *v); -GLAPI void APIENTRY glWindowPos2i (GLint x, GLint y); -GLAPI void APIENTRY glWindowPos2iv (const GLint *v); -GLAPI void APIENTRY glWindowPos2s (GLshort x, GLshort y); -GLAPI void APIENTRY glWindowPos2sv (const GLshort *v); -GLAPI void APIENTRY glWindowPos3d (GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glWindowPos3dv (const GLdouble *v); -GLAPI void APIENTRY glWindowPos3f (GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glWindowPos3fv (const GLfloat *v); -GLAPI void APIENTRY glWindowPos3i (GLint x, GLint y, GLint z); -GLAPI void APIENTRY glWindowPos3iv (const GLint *v); -GLAPI void APIENTRY glWindowPos3s (GLshort x, GLshort y, GLshort z); -GLAPI void APIENTRY glWindowPos3sv (const GLshort *v); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLFOGCOORDFPROC) (GLfloat coord); -typedef void (APIENTRYP PFNGLFOGCOORDFVPROC) (const GLfloat *coord); -typedef void (APIENTRYP PFNGLFOGCOORDDPROC) (GLdouble coord); -typedef void (APIENTRYP PFNGLFOGCOORDDVPROC) (const GLdouble *coord); -typedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BPROC) (GLbyte red, GLbyte green, GLbyte blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVPROC) (const GLbyte *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DPROC) (GLdouble red, GLdouble green, GLdouble blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FPROC) (GLfloat red, GLfloat green, GLfloat blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IPROC) (GLint red, GLint green, GLint blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SPROC) (GLshort red, GLshort green, GLshort blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVPROC) (const GLshort *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBPROC) (GLubyte red, GLubyte green, GLubyte blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVPROC) (const GLubyte *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIPROC) (GLuint red, GLuint green, GLuint blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVPROC) (const GLuint *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USPROC) (GLushort red, GLushort green, GLushort blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVPROC) (const GLushort *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLWINDOWPOS2DPROC) (GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLWINDOWPOS2DVPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLWINDOWPOS2FPROC) (GLfloat x, GLfloat y); -typedef void (APIENTRYP PFNGLWINDOWPOS2FVPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLWINDOWPOS2IPROC) (GLint x, GLint y); -typedef void (APIENTRYP PFNGLWINDOWPOS2IVPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLWINDOWPOS2SPROC) (GLshort x, GLshort y); -typedef void (APIENTRYP PFNGLWINDOWPOS2SVPROC) (const GLshort *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3DPROC) (GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLWINDOWPOS3DVPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3FPROC) (GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLWINDOWPOS3FVPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3IPROC) (GLint x, GLint y, GLint z); -typedef void (APIENTRYP PFNGLWINDOWPOS3IVPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3SPROC) (GLshort x, GLshort y, GLshort z); -typedef void (APIENTRYP PFNGLWINDOWPOS3SVPROC) (const GLshort *v); -#endif - -#ifndef GL_VERSION_1_5 -#define GL_VERSION_1_5 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGenQueries (GLsizei n, GLuint *ids); -GLAPI void APIENTRY glDeleteQueries (GLsizei n, const GLuint *ids); -GLAPI GLboolean APIENTRY glIsQuery (GLuint id); -GLAPI void APIENTRY glBeginQuery (GLenum target, GLuint id); -GLAPI void APIENTRY glEndQuery (GLenum target); -GLAPI void APIENTRY glGetQueryiv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetQueryObjectiv (GLuint id, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetQueryObjectuiv (GLuint id, GLenum pname, GLuint *params); -GLAPI void APIENTRY glBindBuffer (GLenum target, GLuint buffer); -GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers); -GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers); -GLAPI GLboolean APIENTRY glIsBuffer (GLuint buffer); -GLAPI void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); -GLAPI void APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); -GLAPI void APIENTRY glGetBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data); -GLAPI GLvoid* APIENTRY glMapBuffer (GLenum target, GLenum access); -GLAPI GLboolean APIENTRY glUnmapBuffer (GLenum target); -GLAPI void APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetBufferPointerv (GLenum target, GLenum pname, GLvoid* *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids); -typedef void (APIENTRYP PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids); -typedef GLboolean (APIENTRYP PFNGLISQUERYPROC) (GLuint id); -typedef void (APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id); -typedef void (APIENTRYP PFNGLENDQUERYPROC) (GLenum target); -typedef void (APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); -typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers); -typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers); -typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer); -typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); -typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); -typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data); -typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERPROC) (GLenum target, GLenum access); -typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target); -typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, GLvoid* *params); -#endif - -#ifndef GL_VERSION_2_0 -#define GL_VERSION_2_0 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha); -GLAPI void APIENTRY glDrawBuffers (GLsizei n, const GLenum *bufs); -GLAPI void APIENTRY glStencilOpSeparate (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); -GLAPI void APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask); -GLAPI void APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask); -GLAPI void APIENTRY glAttachShader (GLuint program, GLuint shader); -GLAPI void APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar *name); -GLAPI void APIENTRY glCompileShader (GLuint shader); -GLAPI GLuint APIENTRY glCreateProgram (void); -GLAPI GLuint APIENTRY glCreateShader (GLenum type); -GLAPI void APIENTRY glDeleteProgram (GLuint program); -GLAPI void APIENTRY glDeleteShader (GLuint shader); -GLAPI void APIENTRY glDetachShader (GLuint program, GLuint shader); -GLAPI void APIENTRY glDisableVertexAttribArray (GLuint index); -GLAPI void APIENTRY glEnableVertexAttribArray (GLuint index); -GLAPI void APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); -GLAPI void APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); -GLAPI void APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *obj); -GLAPI GLint APIENTRY glGetAttribLocation (GLuint program, const GLchar *name); -GLAPI void APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -GLAPI void APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -GLAPI void APIENTRY glGetShaderSource (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); -GLAPI GLint APIENTRY glGetUniformLocation (GLuint program, const GLchar *name); -GLAPI void APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat *params); -GLAPI void APIENTRY glGetUniformiv (GLuint program, GLint location, GLint *params); -GLAPI void APIENTRY glGetVertexAttribdv (GLuint index, GLenum pname, GLdouble *params); -GLAPI void APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, GLvoid* *pointer); -GLAPI GLboolean APIENTRY glIsProgram (GLuint program); -GLAPI GLboolean APIENTRY glIsShader (GLuint shader); -GLAPI void APIENTRY glLinkProgram (GLuint program); -GLAPI void APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar* *string, const GLint *length); -GLAPI void APIENTRY glUseProgram (GLuint program); -GLAPI void APIENTRY glUniform1f (GLint location, GLfloat v0); -GLAPI void APIENTRY glUniform2f (GLint location, GLfloat v0, GLfloat v1); -GLAPI void APIENTRY glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -GLAPI void APIENTRY glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -GLAPI void APIENTRY glUniform1i (GLint location, GLint v0); -GLAPI void APIENTRY glUniform2i (GLint location, GLint v0, GLint v1); -GLAPI void APIENTRY glUniform3i (GLint location, GLint v0, GLint v1, GLint v2); -GLAPI void APIENTRY glUniform4i (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -GLAPI void APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glValidateProgram (GLuint program); -GLAPI void APIENTRY glVertexAttrib1d (GLuint index, GLdouble x); -GLAPI void APIENTRY glVertexAttrib1dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib1f (GLuint index, GLfloat x); -GLAPI void APIENTRY glVertexAttrib1fv (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib1s (GLuint index, GLshort x); -GLAPI void APIENTRY glVertexAttrib1sv (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib2d (GLuint index, GLdouble x, GLdouble y); -GLAPI void APIENTRY glVertexAttrib2dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib2f (GLuint index, GLfloat x, GLfloat y); -GLAPI void APIENTRY glVertexAttrib2fv (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib2s (GLuint index, GLshort x, GLshort y); -GLAPI void APIENTRY glVertexAttrib2sv (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib3d (GLuint index, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glVertexAttrib3dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib3f (GLuint index, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glVertexAttrib3fv (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib3s (GLuint index, GLshort x, GLshort y, GLshort z); -GLAPI void APIENTRY glVertexAttrib3sv (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib4Nbv (GLuint index, const GLbyte *v); -GLAPI void APIENTRY glVertexAttrib4Niv (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttrib4Nsv (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib4Nub (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); -GLAPI void APIENTRY glVertexAttrib4Nubv (GLuint index, const GLubyte *v); -GLAPI void APIENTRY glVertexAttrib4Nuiv (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttrib4Nusv (GLuint index, const GLushort *v); -GLAPI void APIENTRY glVertexAttrib4bv (GLuint index, const GLbyte *v); -GLAPI void APIENTRY glVertexAttrib4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glVertexAttrib4dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib4f (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glVertexAttrib4fv (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib4iv (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttrib4s (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); -GLAPI void APIENTRY glVertexAttrib4sv (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib4ubv (GLuint index, const GLubyte *v); -GLAPI void APIENTRY glVertexAttrib4uiv (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttrib4usv (GLuint index, const GLushort *v); -GLAPI void APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha); -typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs); -typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); -typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC) (GLenum face, GLenum func, GLint ref, GLuint mask); -typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask); -typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); -typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name); -typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader); -typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void); -typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type); -typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program); -typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader); -typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader); -typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index); -typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index); -typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); -typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *obj); -typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name); -typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); -typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name); -typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params); -typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, GLvoid* *pointer); -typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC) (GLuint program); -typedef GLboolean (APIENTRYP PFNGLISSHADERPROC) (GLuint shader); -typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program); -typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar* *string, const GLint *length); -typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program); -typedef void (APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0); -typedef void (APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1); -typedef void (APIENTRYP PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -typedef void (APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0); -typedef void (APIENTRYP PFNGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1); -typedef void (APIENTRYP PFNGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2); -typedef void (APIENTRYP PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -typedef void (APIENTRYP PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC) (GLuint index, GLdouble x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC) (GLuint index, GLshort x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC) (GLuint index, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC) (GLuint index, GLshort x, GLshort y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC) (GLuint index, GLshort x, GLshort y, GLshort z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC) (GLuint index, const GLbyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC) (GLuint index, const GLubyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC) (GLuint index, const GLushort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC) (GLuint index, const GLbyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); -#endif - -#ifndef GL_VERSION_2_1 -#define GL_VERSION_2_1 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glUniformMatrix2x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix3x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix2x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix4x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix3x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix4x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -#endif - -#ifndef GL_VERSION_3_0 -#define GL_VERSION_3_0 1 -/* OpenGL 3.0 also reuses entry points from these extensions: */ -/* ARB_framebuffer_object */ -/* ARB_map_buffer_range */ -/* ARB_vertex_array_object */ -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColorMaski (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); -GLAPI void APIENTRY glGetBooleani_v (GLenum target, GLuint index, GLboolean *data); -GLAPI void APIENTRY glGetIntegeri_v (GLenum target, GLuint index, GLint *data); -GLAPI void APIENTRY glEnablei (GLenum target, GLuint index); -GLAPI void APIENTRY glDisablei (GLenum target, GLuint index); -GLAPI GLboolean APIENTRY glIsEnabledi (GLenum target, GLuint index); -GLAPI void APIENTRY glBeginTransformFeedback (GLenum primitiveMode); -GLAPI void APIENTRY glEndTransformFeedback (void); -GLAPI void APIENTRY glBindBufferRange (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -GLAPI void APIENTRY glBindBufferBase (GLenum target, GLuint index, GLuint buffer); -GLAPI void APIENTRY glTransformFeedbackVaryings (GLuint program, GLsizei count, const GLchar* *varyings, GLenum bufferMode); -GLAPI void APIENTRY glGetTransformFeedbackVarying (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); -GLAPI void APIENTRY glClampColor (GLenum target, GLenum clamp); -GLAPI void APIENTRY glBeginConditionalRender (GLuint id, GLenum mode); -GLAPI void APIENTRY glEndConditionalRender (void); -GLAPI void APIENTRY glVertexAttribIPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -GLAPI void APIENTRY glGetVertexAttribIiv (GLuint index, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVertexAttribIuiv (GLuint index, GLenum pname, GLuint *params); -GLAPI void APIENTRY glVertexAttribI1i (GLuint index, GLint x); -GLAPI void APIENTRY glVertexAttribI2i (GLuint index, GLint x, GLint y); -GLAPI void APIENTRY glVertexAttribI3i (GLuint index, GLint x, GLint y, GLint z); -GLAPI void APIENTRY glVertexAttribI4i (GLuint index, GLint x, GLint y, GLint z, GLint w); -GLAPI void APIENTRY glVertexAttribI1ui (GLuint index, GLuint x); -GLAPI void APIENTRY glVertexAttribI2ui (GLuint index, GLuint x, GLuint y); -GLAPI void APIENTRY glVertexAttribI3ui (GLuint index, GLuint x, GLuint y, GLuint z); -GLAPI void APIENTRY glVertexAttribI4ui (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -GLAPI void APIENTRY glVertexAttribI1iv (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttribI2iv (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttribI3iv (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttribI4iv (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttribI1uiv (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttribI2uiv (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttribI3uiv (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttribI4uiv (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttribI4bv (GLuint index, const GLbyte *v); -GLAPI void APIENTRY glVertexAttribI4sv (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttribI4ubv (GLuint index, const GLubyte *v); -GLAPI void APIENTRY glVertexAttribI4usv (GLuint index, const GLushort *v); -GLAPI void APIENTRY glGetUniformuiv (GLuint program, GLint location, GLuint *params); -GLAPI void APIENTRY glBindFragDataLocation (GLuint program, GLuint color, const GLchar *name); -GLAPI GLint APIENTRY glGetFragDataLocation (GLuint program, const GLchar *name); -GLAPI void APIENTRY glUniform1ui (GLint location, GLuint v0); -GLAPI void APIENTRY glUniform2ui (GLint location, GLuint v0, GLuint v1); -GLAPI void APIENTRY glUniform3ui (GLint location, GLuint v0, GLuint v1, GLuint v2); -GLAPI void APIENTRY glUniform4ui (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -GLAPI void APIENTRY glUniform1uiv (GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glUniform2uiv (GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glUniform3uiv (GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glUniform4uiv (GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glTexParameterIiv (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glTexParameterIuiv (GLenum target, GLenum pname, const GLuint *params); -GLAPI void APIENTRY glGetTexParameterIiv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetTexParameterIuiv (GLenum target, GLenum pname, GLuint *params); -GLAPI void APIENTRY glClearBufferiv (GLenum buffer, GLint drawbuffer, const GLint *value); -GLAPI void APIENTRY glClearBufferuiv (GLenum buffer, GLint drawbuffer, const GLuint *value); -GLAPI void APIENTRY glClearBufferfv (GLenum buffer, GLint drawbuffer, const GLfloat *value); -GLAPI void APIENTRY glClearBufferfi (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); -GLAPI const GLubyte * APIENTRY glGetStringi (GLenum name, GLuint index); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCOLORMASKIPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); -typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data); -typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data); -typedef void (APIENTRYP PFNGLENABLEIPROC) (GLenum target, GLuint index); -typedef void (APIENTRYP PFNGLDISABLEIPROC) (GLenum target, GLuint index); -typedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC) (GLenum target, GLuint index); -typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC) (GLenum primitiveMode); -typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC) (void); -typedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -typedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC) (GLenum target, GLuint index, GLuint buffer); -typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC) (GLuint program, GLsizei count, const GLchar* *varyings, GLenum bufferMode); -typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); -typedef void (APIENTRYP PFNGLCLAMPCOLORPROC) (GLenum target, GLenum clamp); -typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC) (GLuint id, GLenum mode); -typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC) (void); -typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC) (GLuint index, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC) (GLuint index, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC) (GLuint index, GLint x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC) (GLuint index, GLint x, GLint y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC) (GLuint index, GLint x, GLint y, GLint z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC) (GLuint index, GLuint x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC) (GLuint index, GLuint x, GLuint y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC) (GLuint index, const GLbyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC) (GLuint index, const GLubyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC) (GLuint index, const GLushort *v); -typedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC) (GLuint program, GLint location, GLuint *params); -typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC) (GLuint program, GLuint color, const GLchar *name); -typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC) (GLuint program, const GLchar *name); -typedef void (APIENTRYP PFNGLUNIFORM1UIPROC) (GLint location, GLuint v0); -typedef void (APIENTRYP PFNGLUNIFORM2UIPROC) (GLint location, GLuint v0, GLuint v1); -typedef void (APIENTRYP PFNGLUNIFORM3UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2); -typedef void (APIENTRYP PFNGLUNIFORM4UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, const GLuint *params); -typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC) (GLenum buffer, GLint drawbuffer, const GLint *value); -typedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint *value); -typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value); -typedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); -typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGIPROC) (GLenum name, GLuint index); -#endif - -#ifndef GL_VERSION_3_1 -#define GL_VERSION_3_1 1 -/* OpenGL 3.1 also reuses entry points from these extensions: */ -/* ARB_copy_buffer */ -/* ARB_uniform_buffer_object */ -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawArraysInstanced (GLenum mode, GLint first, GLsizei count, GLsizei primcount); -GLAPI void APIENTRY glDrawElementsInstanced (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); -GLAPI void APIENTRY glTexBuffer (GLenum target, GLenum internalformat, GLuint buffer); -GLAPI void APIENTRY glPrimitiveRestartIndex (GLuint index); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); -typedef void (APIENTRYP PFNGLTEXBUFFERPROC) (GLenum target, GLenum internalformat, GLuint buffer); -typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC) (GLuint index); -#endif - -#ifndef GL_VERSION_3_2 -#define GL_VERSION_3_2 1 -/* OpenGL 3.2 also reuses entry points from these extensions: */ -/* ARB_draw_elements_base_vertex */ -/* ARB_provoking_vertex */ -/* ARB_sync */ -/* ARB_texture_multisample */ -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetInteger64i_v (GLenum target, GLuint index, GLint64 *data); -GLAPI void APIENTRY glGetBufferParameteri64v (GLenum target, GLenum pname, GLint64 *params); -GLAPI void APIENTRY glFramebufferTexture (GLenum target, GLenum attachment, GLuint texture, GLint level); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data); -typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC) (GLenum target, GLenum pname, GLint64 *params); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); -#endif - -#ifndef GL_VERSION_3_3 -#define GL_VERSION_3_3 1 -/* OpenGL 3.3 also reuses entry points from these extensions: */ -/* ARB_blend_func_extended */ -/* ARB_sampler_objects */ -/* ARB_explicit_attrib_location, but it has none */ -/* ARB_occlusion_query2 (no entry points) */ -/* ARB_shader_bit_encoding (no entry points) */ -/* ARB_texture_rgb10_a2ui (no entry points) */ -/* ARB_texture_swizzle (no entry points) */ -/* ARB_timer_query */ -/* ARB_vertex_type_2_10_10_10_rev */ -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexAttribDivisor (GLuint index, GLuint divisor); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint divisor); -#endif - -#ifndef GL_VERSION_4_0 -#define GL_VERSION_4_0 1 -/* OpenGL 4.0 also reuses entry points from these extensions: */ -/* ARB_texture_query_lod (no entry points) */ -/* ARB_draw_indirect */ -/* ARB_gpu_shader5 (no entry points) */ -/* ARB_gpu_shader_fp64 */ -/* ARB_shader_subroutine */ -/* ARB_tessellation_shader */ -/* ARB_texture_buffer_object_rgb32 (no entry points) */ -/* ARB_texture_cube_map_array (no entry points) */ -/* ARB_texture_gather (no entry points) */ -/* ARB_transform_feedback2 */ -/* ARB_transform_feedback3 */ -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMinSampleShading (GLclampf value); -GLAPI void APIENTRY glBlendEquationi (GLuint buf, GLenum mode); -GLAPI void APIENTRY glBlendEquationSeparatei (GLuint buf, GLenum modeRGB, GLenum modeAlpha); -GLAPI void APIENTRY glBlendFunci (GLuint buf, GLenum src, GLenum dst); -GLAPI void APIENTRY glBlendFuncSeparatei (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLMINSAMPLESHADINGPROC) (GLclampf value); -typedef void (APIENTRYP PFNGLBLENDEQUATIONIPROC) (GLuint buf, GLenum mode); -typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); -typedef void (APIENTRYP PFNGLBLENDFUNCIPROC) (GLuint buf, GLenum src, GLenum dst); -typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); -#endif - -#ifndef GL_VERSION_4_1 -#define GL_VERSION_4_1 1 -/* OpenGL 4.1 reuses entry points from these extensions: */ -/* ARB_ES2_compatibility */ -/* ARB_get_program_binary */ -/* ARB_separate_shader_objects */ -/* ARB_shader_precision (no entry points) */ -/* ARB_vertex_attrib_64bit */ -/* ARB_viewport_array */ -#endif - -#ifndef GL_VERSION_4_2 -#define GL_VERSION_4_2 1 -/* OpenGL 4.2 reuses entry points from these extensions: */ -/* ARB_base_instance */ -/* ARB_shading_language_420pack (no entry points) */ -/* ARB_transform_feedback_instanced */ -/* ARB_compressed_texture_pixel_storage (no entry points) */ -/* ARB_conservative_depth (no entry points) */ -/* ARB_internalformat_query */ -/* ARB_map_buffer_alignment (no entry points) */ -/* ARB_shader_atomic_counters */ -/* ARB_shader_image_load_store */ -/* ARB_shading_language_packing (no entry points) */ -/* ARB_texture_storage */ -#endif - -#ifndef GL_ARB_multitexture -#define GL_ARB_multitexture 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glActiveTextureARB (GLenum texture); -GLAPI void APIENTRY glClientActiveTextureARB (GLenum texture); -GLAPI void APIENTRY glMultiTexCoord1dARB (GLenum target, GLdouble s); -GLAPI void APIENTRY glMultiTexCoord1dvARB (GLenum target, const GLdouble *v); -GLAPI void APIENTRY glMultiTexCoord1fARB (GLenum target, GLfloat s); -GLAPI void APIENTRY glMultiTexCoord1fvARB (GLenum target, const GLfloat *v); -GLAPI void APIENTRY glMultiTexCoord1iARB (GLenum target, GLint s); -GLAPI void APIENTRY glMultiTexCoord1ivARB (GLenum target, const GLint *v); -GLAPI void APIENTRY glMultiTexCoord1sARB (GLenum target, GLshort s); -GLAPI void APIENTRY glMultiTexCoord1svARB (GLenum target, const GLshort *v); -GLAPI void APIENTRY glMultiTexCoord2dARB (GLenum target, GLdouble s, GLdouble t); -GLAPI void APIENTRY glMultiTexCoord2dvARB (GLenum target, const GLdouble *v); -GLAPI void APIENTRY glMultiTexCoord2fARB (GLenum target, GLfloat s, GLfloat t); -GLAPI void APIENTRY glMultiTexCoord2fvARB (GLenum target, const GLfloat *v); -GLAPI void APIENTRY glMultiTexCoord2iARB (GLenum target, GLint s, GLint t); -GLAPI void APIENTRY glMultiTexCoord2ivARB (GLenum target, const GLint *v); -GLAPI void APIENTRY glMultiTexCoord2sARB (GLenum target, GLshort s, GLshort t); -GLAPI void APIENTRY glMultiTexCoord2svARB (GLenum target, const GLshort *v); -GLAPI void APIENTRY glMultiTexCoord3dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r); -GLAPI void APIENTRY glMultiTexCoord3dvARB (GLenum target, const GLdouble *v); -GLAPI void APIENTRY glMultiTexCoord3fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r); -GLAPI void APIENTRY glMultiTexCoord3fvARB (GLenum target, const GLfloat *v); -GLAPI void APIENTRY glMultiTexCoord3iARB (GLenum target, GLint s, GLint t, GLint r); -GLAPI void APIENTRY glMultiTexCoord3ivARB (GLenum target, const GLint *v); -GLAPI void APIENTRY glMultiTexCoord3sARB (GLenum target, GLshort s, GLshort t, GLshort r); -GLAPI void APIENTRY glMultiTexCoord3svARB (GLenum target, const GLshort *v); -GLAPI void APIENTRY glMultiTexCoord4dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); -GLAPI void APIENTRY glMultiTexCoord4dvARB (GLenum target, const GLdouble *v); -GLAPI void APIENTRY glMultiTexCoord4fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); -GLAPI void APIENTRY glMultiTexCoord4fvARB (GLenum target, const GLfloat *v); -GLAPI void APIENTRY glMultiTexCoord4iARB (GLenum target, GLint s, GLint t, GLint r, GLint q); -GLAPI void APIENTRY glMultiTexCoord4ivARB (GLenum target, const GLint *v); -GLAPI void APIENTRY glMultiTexCoord4sARB (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); -GLAPI void APIENTRY glMultiTexCoord4svARB (GLenum target, const GLshort *v); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLACTIVETEXTUREARBPROC) (GLenum texture); -typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v); -#endif - -#ifndef GL_ARB_transpose_matrix -#define GL_ARB_transpose_matrix 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glLoadTransposeMatrixfARB (const GLfloat *m); -GLAPI void APIENTRY glLoadTransposeMatrixdARB (const GLdouble *m); -GLAPI void APIENTRY glMultTransposeMatrixfARB (const GLfloat *m); -GLAPI void APIENTRY glMultTransposeMatrixdARB (const GLdouble *m); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFARBPROC) (const GLfloat *m); -typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDARBPROC) (const GLdouble *m); -typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFARBPROC) (const GLfloat *m); -typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDARBPROC) (const GLdouble *m); -#endif - -#ifndef GL_ARB_multisample -#define GL_ARB_multisample 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glSampleCoverageARB (GLclampf value, GLboolean invert); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLSAMPLECOVERAGEARBPROC) (GLclampf value, GLboolean invert); -#endif - -#ifndef GL_ARB_texture_env_add -#define GL_ARB_texture_env_add 1 -#endif - -#ifndef GL_ARB_texture_cube_map -#define GL_ARB_texture_cube_map 1 -#endif - -#ifndef GL_ARB_texture_compression -#define GL_ARB_texture_compression 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glCompressedTexImage3DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexImage2DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexImage1DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexSubImage3DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexSubImage2DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexSubImage1DARB (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glGetCompressedTexImageARB (GLenum target, GLint level, GLvoid *img); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint level, GLvoid *img); -#endif - -#ifndef GL_ARB_texture_border_clamp -#define GL_ARB_texture_border_clamp 1 -#endif - -#ifndef GL_ARB_point_parameters -#define GL_ARB_point_parameters 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPointParameterfARB (GLenum pname, GLfloat param); -GLAPI void APIENTRY glPointParameterfvARB (GLenum pname, const GLfloat *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPOINTPARAMETERFARBPROC) (GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLPOINTPARAMETERFVARBPROC) (GLenum pname, const GLfloat *params); -#endif - -#ifndef GL_ARB_vertex_blend -#define GL_ARB_vertex_blend 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glWeightbvARB (GLint size, const GLbyte *weights); -GLAPI void APIENTRY glWeightsvARB (GLint size, const GLshort *weights); -GLAPI void APIENTRY glWeightivARB (GLint size, const GLint *weights); -GLAPI void APIENTRY glWeightfvARB (GLint size, const GLfloat *weights); -GLAPI void APIENTRY glWeightdvARB (GLint size, const GLdouble *weights); -GLAPI void APIENTRY glWeightubvARB (GLint size, const GLubyte *weights); -GLAPI void APIENTRY glWeightusvARB (GLint size, const GLushort *weights); -GLAPI void APIENTRY glWeightuivARB (GLint size, const GLuint *weights); -GLAPI void APIENTRY glWeightPointerARB (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -GLAPI void APIENTRY glVertexBlendARB (GLint count); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLWEIGHTBVARBPROC) (GLint size, const GLbyte *weights); -typedef void (APIENTRYP PFNGLWEIGHTSVARBPROC) (GLint size, const GLshort *weights); -typedef void (APIENTRYP PFNGLWEIGHTIVARBPROC) (GLint size, const GLint *weights); -typedef void (APIENTRYP PFNGLWEIGHTFVARBPROC) (GLint size, const GLfloat *weights); -typedef void (APIENTRYP PFNGLWEIGHTDVARBPROC) (GLint size, const GLdouble *weights); -typedef void (APIENTRYP PFNGLWEIGHTUBVARBPROC) (GLint size, const GLubyte *weights); -typedef void (APIENTRYP PFNGLWEIGHTUSVARBPROC) (GLint size, const GLushort *weights); -typedef void (APIENTRYP PFNGLWEIGHTUIVARBPROC) (GLint size, const GLuint *weights); -typedef void (APIENTRYP PFNGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLVERTEXBLENDARBPROC) (GLint count); -#endif - -#ifndef GL_ARB_matrix_palette -#define GL_ARB_matrix_palette 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glCurrentPaletteMatrixARB (GLint index); -GLAPI void APIENTRY glMatrixIndexubvARB (GLint size, const GLubyte *indices); -GLAPI void APIENTRY glMatrixIndexusvARB (GLint size, const GLushort *indices); -GLAPI void APIENTRY glMatrixIndexuivARB (GLint size, const GLuint *indices); -GLAPI void APIENTRY glMatrixIndexPointerARB (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCURRENTPALETTEMATRIXARBPROC) (GLint index); -typedef void (APIENTRYP PFNGLMATRIXINDEXUBVARBPROC) (GLint size, const GLubyte *indices); -typedef void (APIENTRYP PFNGLMATRIXINDEXUSVARBPROC) (GLint size, const GLushort *indices); -typedef void (APIENTRYP PFNGLMATRIXINDEXUIVARBPROC) (GLint size, const GLuint *indices); -typedef void (APIENTRYP PFNGLMATRIXINDEXPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -#endif - -#ifndef GL_ARB_texture_env_combine -#define GL_ARB_texture_env_combine 1 -#endif - -#ifndef GL_ARB_texture_env_crossbar -#define GL_ARB_texture_env_crossbar 1 -#endif - -#ifndef GL_ARB_texture_env_dot3 -#define GL_ARB_texture_env_dot3 1 -#endif - -#ifndef GL_ARB_texture_mirrored_repeat -#define GL_ARB_texture_mirrored_repeat 1 -#endif - -#ifndef GL_ARB_depth_texture -#define GL_ARB_depth_texture 1 -#endif - -#ifndef GL_ARB_shadow -#define GL_ARB_shadow 1 -#endif - -#ifndef GL_ARB_shadow_ambient -#define GL_ARB_shadow_ambient 1 -#endif - -#ifndef GL_ARB_window_pos -#define GL_ARB_window_pos 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glWindowPos2dARB (GLdouble x, GLdouble y); -GLAPI void APIENTRY glWindowPos2dvARB (const GLdouble *v); -GLAPI void APIENTRY glWindowPos2fARB (GLfloat x, GLfloat y); -GLAPI void APIENTRY glWindowPos2fvARB (const GLfloat *v); -GLAPI void APIENTRY glWindowPos2iARB (GLint x, GLint y); -GLAPI void APIENTRY glWindowPos2ivARB (const GLint *v); -GLAPI void APIENTRY glWindowPos2sARB (GLshort x, GLshort y); -GLAPI void APIENTRY glWindowPos2svARB (const GLshort *v); -GLAPI void APIENTRY glWindowPos3dARB (GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glWindowPos3dvARB (const GLdouble *v); -GLAPI void APIENTRY glWindowPos3fARB (GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glWindowPos3fvARB (const GLfloat *v); -GLAPI void APIENTRY glWindowPos3iARB (GLint x, GLint y, GLint z); -GLAPI void APIENTRY glWindowPos3ivARB (const GLint *v); -GLAPI void APIENTRY glWindowPos3sARB (GLshort x, GLshort y, GLshort z); -GLAPI void APIENTRY glWindowPos3svARB (const GLshort *v); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLWINDOWPOS2DARBPROC) (GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLWINDOWPOS2DVARBPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLWINDOWPOS2FARBPROC) (GLfloat x, GLfloat y); -typedef void (APIENTRYP PFNGLWINDOWPOS2FVARBPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLWINDOWPOS2IARBPROC) (GLint x, GLint y); -typedef void (APIENTRYP PFNGLWINDOWPOS2IVARBPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLWINDOWPOS2SARBPROC) (GLshort x, GLshort y); -typedef void (APIENTRYP PFNGLWINDOWPOS2SVARBPROC) (const GLshort *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3DARBPROC) (GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLWINDOWPOS3DVARBPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3FARBPROC) (GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLWINDOWPOS3FVARBPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3IARBPROC) (GLint x, GLint y, GLint z); -typedef void (APIENTRYP PFNGLWINDOWPOS3IVARBPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3SARBPROC) (GLshort x, GLshort y, GLshort z); -typedef void (APIENTRYP PFNGLWINDOWPOS3SVARBPROC) (const GLshort *v); -#endif - -#ifndef GL_ARB_vertex_program -#define GL_ARB_vertex_program 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexAttrib1dARB (GLuint index, GLdouble x); -GLAPI void APIENTRY glVertexAttrib1dvARB (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib1fARB (GLuint index, GLfloat x); -GLAPI void APIENTRY glVertexAttrib1fvARB (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib1sARB (GLuint index, GLshort x); -GLAPI void APIENTRY glVertexAttrib1svARB (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib2dARB (GLuint index, GLdouble x, GLdouble y); -GLAPI void APIENTRY glVertexAttrib2dvARB (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib2fARB (GLuint index, GLfloat x, GLfloat y); -GLAPI void APIENTRY glVertexAttrib2fvARB (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib2sARB (GLuint index, GLshort x, GLshort y); -GLAPI void APIENTRY glVertexAttrib2svARB (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib3dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glVertexAttrib3dvARB (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib3fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glVertexAttrib3fvARB (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib3sARB (GLuint index, GLshort x, GLshort y, GLshort z); -GLAPI void APIENTRY glVertexAttrib3svARB (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib4NbvARB (GLuint index, const GLbyte *v); -GLAPI void APIENTRY glVertexAttrib4NivARB (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttrib4NsvARB (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib4NubARB (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); -GLAPI void APIENTRY glVertexAttrib4NubvARB (GLuint index, const GLubyte *v); -GLAPI void APIENTRY glVertexAttrib4NuivARB (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttrib4NusvARB (GLuint index, const GLushort *v); -GLAPI void APIENTRY glVertexAttrib4bvARB (GLuint index, const GLbyte *v); -GLAPI void APIENTRY glVertexAttrib4dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glVertexAttrib4dvARB (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib4fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glVertexAttrib4fvARB (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib4ivARB (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttrib4sARB (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); -GLAPI void APIENTRY glVertexAttrib4svARB (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib4ubvARB (GLuint index, const GLubyte *v); -GLAPI void APIENTRY glVertexAttrib4uivARB (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttrib4usvARB (GLuint index, const GLushort *v); -GLAPI void APIENTRY glVertexAttribPointerARB (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); -GLAPI void APIENTRY glEnableVertexAttribArrayARB (GLuint index); -GLAPI void APIENTRY glDisableVertexAttribArrayARB (GLuint index); -GLAPI void APIENTRY glProgramStringARB (GLenum target, GLenum format, GLsizei len, const GLvoid *string); -GLAPI void APIENTRY glBindProgramARB (GLenum target, GLuint program); -GLAPI void APIENTRY glDeleteProgramsARB (GLsizei n, const GLuint *programs); -GLAPI void APIENTRY glGenProgramsARB (GLsizei n, GLuint *programs); -GLAPI void APIENTRY glProgramEnvParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glProgramEnvParameter4dvARB (GLenum target, GLuint index, const GLdouble *params); -GLAPI void APIENTRY glProgramEnvParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glProgramEnvParameter4fvARB (GLenum target, GLuint index, const GLfloat *params); -GLAPI void APIENTRY glProgramLocalParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glProgramLocalParameter4dvARB (GLenum target, GLuint index, const GLdouble *params); -GLAPI void APIENTRY glProgramLocalParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glProgramLocalParameter4fvARB (GLenum target, GLuint index, const GLfloat *params); -GLAPI void APIENTRY glGetProgramEnvParameterdvARB (GLenum target, GLuint index, GLdouble *params); -GLAPI void APIENTRY glGetProgramEnvParameterfvARB (GLenum target, GLuint index, GLfloat *params); -GLAPI void APIENTRY glGetProgramLocalParameterdvARB (GLenum target, GLuint index, GLdouble *params); -GLAPI void APIENTRY glGetProgramLocalParameterfvARB (GLenum target, GLuint index, GLfloat *params); -GLAPI void APIENTRY glGetProgramivARB (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetProgramStringARB (GLenum target, GLenum pname, GLvoid *string); -GLAPI void APIENTRY glGetVertexAttribdvARB (GLuint index, GLenum pname, GLdouble *params); -GLAPI void APIENTRY glGetVertexAttribfvARB (GLuint index, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetVertexAttribivARB (GLuint index, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVertexAttribPointervARB (GLuint index, GLenum pname, GLvoid* *pointer); -GLAPI GLboolean APIENTRY glIsProgramARB (GLuint program); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVERTEXATTRIB1DARBPROC) (GLuint index, GLdouble x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVARBPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1FARBPROC) (GLuint index, GLfloat x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVARBPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1SARBPROC) (GLuint index, GLshort x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVARBPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2DARBPROC) (GLuint index, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVARBPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2FARBPROC) (GLuint index, GLfloat x, GLfloat y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVARBPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2SARBPROC) (GLuint index, GLshort x, GLshort y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVARBPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVARBPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVARBPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVARBPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVARBPROC) (GLuint index, const GLbyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVARBPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVARBPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBARBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVARBPROC) (GLuint index, const GLubyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVARBPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVARBPROC) (GLuint index, const GLushort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVARBPROC) (GLuint index, const GLbyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVARBPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVARBPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVARBPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVARBPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVARBPROC) (GLuint index, const GLubyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVARBPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVARBPROC) (GLuint index, const GLushort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYARBPROC) (GLuint index); -typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) (GLuint index); -typedef void (APIENTRYP PFNGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const GLvoid *string); -typedef void (APIENTRYP PFNGLBINDPROGRAMARBPROC) (GLenum target, GLuint program); -typedef void (APIENTRYP PFNGLDELETEPROGRAMSARBPROC) (GLsizei n, const GLuint *programs); -typedef void (APIENTRYP PFNGLGENPROGRAMSARBPROC) (GLsizei n, GLuint *programs); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params); -typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params); -typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params); -typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params); -typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params); -typedef void (APIENTRYP PFNGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, GLvoid *string); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVARBPROC) (GLuint index, GLenum pname, GLdouble *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVARBPROC) (GLuint index, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVARBPROC) (GLuint index, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, GLvoid* *pointer); -typedef GLboolean (APIENTRYP PFNGLISPROGRAMARBPROC) (GLuint program); -#endif - -#ifndef GL_ARB_fragment_program -#define GL_ARB_fragment_program 1 -/* All ARB_fragment_program entry points are shared with ARB_vertex_program. */ -#endif - -#ifndef GL_ARB_vertex_buffer_object -#define GL_ARB_vertex_buffer_object 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBindBufferARB (GLenum target, GLuint buffer); -GLAPI void APIENTRY glDeleteBuffersARB (GLsizei n, const GLuint *buffers); -GLAPI void APIENTRY glGenBuffersARB (GLsizei n, GLuint *buffers); -GLAPI GLboolean APIENTRY glIsBufferARB (GLuint buffer); -GLAPI void APIENTRY glBufferDataARB (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage); -GLAPI void APIENTRY glBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data); -GLAPI void APIENTRY glGetBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data); -GLAPI GLvoid* APIENTRY glMapBufferARB (GLenum target, GLenum access); -GLAPI GLboolean APIENTRY glUnmapBufferARB (GLenum target); -GLAPI void APIENTRY glGetBufferParameterivARB (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetBufferPointervARB (GLenum target, GLenum pname, GLvoid* *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer); -typedef void (APIENTRYP PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers); -typedef void (APIENTRYP PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers); -typedef GLboolean (APIENTRYP PFNGLISBUFFERARBPROC) (GLuint buffer); -typedef void (APIENTRYP PFNGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage); -typedef void (APIENTRYP PFNGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data); -typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data); -typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERARBPROC) (GLenum target, GLenum access); -typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERARBPROC) (GLenum target); -typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVARBPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, GLvoid* *params); -#endif - -#ifndef GL_ARB_occlusion_query -#define GL_ARB_occlusion_query 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGenQueriesARB (GLsizei n, GLuint *ids); -GLAPI void APIENTRY glDeleteQueriesARB (GLsizei n, const GLuint *ids); -GLAPI GLboolean APIENTRY glIsQueryARB (GLuint id); -GLAPI void APIENTRY glBeginQueryARB (GLenum target, GLuint id); -GLAPI void APIENTRY glEndQueryARB (GLenum target); -GLAPI void APIENTRY glGetQueryivARB (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetQueryObjectivARB (GLuint id, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetQueryObjectuivARB (GLuint id, GLenum pname, GLuint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGENQUERIESARBPROC) (GLsizei n, GLuint *ids); -typedef void (APIENTRYP PFNGLDELETEQUERIESARBPROC) (GLsizei n, const GLuint *ids); -typedef GLboolean (APIENTRYP PFNGLISQUERYARBPROC) (GLuint id); -typedef void (APIENTRYP PFNGLBEGINQUERYARBPROC) (GLenum target, GLuint id); -typedef void (APIENTRYP PFNGLENDQUERYARBPROC) (GLenum target); -typedef void (APIENTRYP PFNGLGETQUERYIVARBPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVARBPROC) (GLuint id, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVARBPROC) (GLuint id, GLenum pname, GLuint *params); -#endif - -#ifndef GL_ARB_shader_objects -#define GL_ARB_shader_objects 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDeleteObjectARB (GLhandleARB obj); -GLAPI GLhandleARB APIENTRY glGetHandleARB (GLenum pname); -GLAPI void APIENTRY glDetachObjectARB (GLhandleARB containerObj, GLhandleARB attachedObj); -GLAPI GLhandleARB APIENTRY glCreateShaderObjectARB (GLenum shaderType); -GLAPI void APIENTRY glShaderSourceARB (GLhandleARB shaderObj, GLsizei count, const GLcharARB* *string, const GLint *length); -GLAPI void APIENTRY glCompileShaderARB (GLhandleARB shaderObj); -GLAPI GLhandleARB APIENTRY glCreateProgramObjectARB (void); -GLAPI void APIENTRY glAttachObjectARB (GLhandleARB containerObj, GLhandleARB obj); -GLAPI void APIENTRY glLinkProgramARB (GLhandleARB programObj); -GLAPI void APIENTRY glUseProgramObjectARB (GLhandleARB programObj); -GLAPI void APIENTRY glValidateProgramARB (GLhandleARB programObj); -GLAPI void APIENTRY glUniform1fARB (GLint location, GLfloat v0); -GLAPI void APIENTRY glUniform2fARB (GLint location, GLfloat v0, GLfloat v1); -GLAPI void APIENTRY glUniform3fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -GLAPI void APIENTRY glUniform4fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -GLAPI void APIENTRY glUniform1iARB (GLint location, GLint v0); -GLAPI void APIENTRY glUniform2iARB (GLint location, GLint v0, GLint v1); -GLAPI void APIENTRY glUniform3iARB (GLint location, GLint v0, GLint v1, GLint v2); -GLAPI void APIENTRY glUniform4iARB (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -GLAPI void APIENTRY glUniform1fvARB (GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glUniform2fvARB (GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glUniform3fvARB (GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glUniform4fvARB (GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glUniform1ivARB (GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glUniform2ivARB (GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glUniform3ivARB (GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glUniform4ivARB (GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glUniformMatrix2fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix3fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix4fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glGetObjectParameterfvARB (GLhandleARB obj, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetObjectParameterivARB (GLhandleARB obj, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetInfoLogARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); -GLAPI void APIENTRY glGetAttachedObjectsARB (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj); -GLAPI GLint APIENTRY glGetUniformLocationARB (GLhandleARB programObj, const GLcharARB *name); -GLAPI void APIENTRY glGetActiveUniformARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); -GLAPI void APIENTRY glGetUniformfvARB (GLhandleARB programObj, GLint location, GLfloat *params); -GLAPI void APIENTRY glGetUniformivARB (GLhandleARB programObj, GLint location, GLint *params); -GLAPI void APIENTRY glGetShaderSourceARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDELETEOBJECTARBPROC) (GLhandleARB obj); -typedef GLhandleARB (APIENTRYP PFNGLGETHANDLEARBPROC) (GLenum pname); -typedef void (APIENTRYP PFNGLDETACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB attachedObj); -typedef GLhandleARB (APIENTRYP PFNGLCREATESHADEROBJECTARBPROC) (GLenum shaderType); -typedef void (APIENTRYP PFNGLSHADERSOURCEARBPROC) (GLhandleARB shaderObj, GLsizei count, const GLcharARB* *string, const GLint *length); -typedef void (APIENTRYP PFNGLCOMPILESHADERARBPROC) (GLhandleARB shaderObj); -typedef GLhandleARB (APIENTRYP PFNGLCREATEPROGRAMOBJECTARBPROC) (void); -typedef void (APIENTRYP PFNGLATTACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB obj); -typedef void (APIENTRYP PFNGLLINKPROGRAMARBPROC) (GLhandleARB programObj); -typedef void (APIENTRYP PFNGLUSEPROGRAMOBJECTARBPROC) (GLhandleARB programObj); -typedef void (APIENTRYP PFNGLVALIDATEPROGRAMARBPROC) (GLhandleARB programObj); -typedef void (APIENTRYP PFNGLUNIFORM1FARBPROC) (GLint location, GLfloat v0); -typedef void (APIENTRYP PFNGLUNIFORM2FARBPROC) (GLint location, GLfloat v0, GLfloat v1); -typedef void (APIENTRYP PFNGLUNIFORM3FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -typedef void (APIENTRYP PFNGLUNIFORM4FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -typedef void (APIENTRYP PFNGLUNIFORM1IARBPROC) (GLint location, GLint v0); -typedef void (APIENTRYP PFNGLUNIFORM2IARBPROC) (GLint location, GLint v0, GLint v1); -typedef void (APIENTRYP PFNGLUNIFORM3IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2); -typedef void (APIENTRYP PFNGLUNIFORM4IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -typedef void (APIENTRYP PFNGLUNIFORM1FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORM2FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORM3FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORM4FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORM1IVARBPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLUNIFORM2IVARBPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLUNIFORM3IVARBPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLUNIFORM4IVARBPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERFVARBPROC) (GLhandleARB obj, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVARBPROC) (GLhandleARB obj, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETINFOLOGARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); -typedef void (APIENTRYP PFNGLGETATTACHEDOBJECTSARBPROC) (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj); -typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name); -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); -typedef void (APIENTRYP PFNGLGETUNIFORMFVARBPROC) (GLhandleARB programObj, GLint location, GLfloat *params); -typedef void (APIENTRYP PFNGLGETUNIFORMIVARBPROC) (GLhandleARB programObj, GLint location, GLint *params); -typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); -#endif - -#ifndef GL_ARB_vertex_shader -#define GL_ARB_vertex_shader 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBindAttribLocationARB (GLhandleARB programObj, GLuint index, const GLcharARB *name); -GLAPI void APIENTRY glGetActiveAttribARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); -GLAPI GLint APIENTRY glGetAttribLocationARB (GLhandleARB programObj, const GLcharARB *name); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONARBPROC) (GLhandleARB programObj, GLuint index, const GLcharARB *name); -typedef void (APIENTRYP PFNGLGETACTIVEATTRIBARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); -typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name); -#endif - -#ifndef GL_ARB_fragment_shader -#define GL_ARB_fragment_shader 1 -#endif - -#ifndef GL_ARB_shading_language_100 -#define GL_ARB_shading_language_100 1 -#endif - -#ifndef GL_ARB_texture_non_power_of_two -#define GL_ARB_texture_non_power_of_two 1 -#endif - -#ifndef GL_ARB_point_sprite -#define GL_ARB_point_sprite 1 -#endif - -#ifndef GL_ARB_fragment_program_shadow -#define GL_ARB_fragment_program_shadow 1 -#endif - -#ifndef GL_ARB_draw_buffers -#define GL_ARB_draw_buffers 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawBuffersARB (GLsizei n, const GLenum *bufs); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDRAWBUFFERSARBPROC) (GLsizei n, const GLenum *bufs); -#endif - -#ifndef GL_ARB_texture_rectangle -#define GL_ARB_texture_rectangle 1 -#endif - -#ifndef GL_ARB_color_buffer_float -#define GL_ARB_color_buffer_float 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glClampColorARB (GLenum target, GLenum clamp); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCLAMPCOLORARBPROC) (GLenum target, GLenum clamp); -#endif - -#ifndef GL_ARB_half_float_pixel -#define GL_ARB_half_float_pixel 1 -#endif - -#ifndef GL_ARB_texture_float -#define GL_ARB_texture_float 1 -#endif - -#ifndef GL_ARB_pixel_buffer_object -#define GL_ARB_pixel_buffer_object 1 -#endif - -#ifndef GL_ARB_depth_buffer_float -#define GL_ARB_depth_buffer_float 1 -#endif - -#ifndef GL_ARB_draw_instanced -#define GL_ARB_draw_instanced 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawArraysInstancedARB (GLenum mode, GLint first, GLsizei count, GLsizei primcount); -GLAPI void APIENTRY glDrawElementsInstancedARB (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDARBPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDARBPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); -#endif - -#ifndef GL_ARB_framebuffer_object -#define GL_ARB_framebuffer_object 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLboolean APIENTRY glIsRenderbuffer (GLuint renderbuffer); -GLAPI void APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer); -GLAPI void APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint *renderbuffers); -GLAPI void APIENTRY glGenRenderbuffers (GLsizei n, GLuint *renderbuffers); -GLAPI void APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint *params); -GLAPI GLboolean APIENTRY glIsFramebuffer (GLuint framebuffer); -GLAPI void APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer); -GLAPI void APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint *framebuffers); -GLAPI void APIENTRY glGenFramebuffers (GLsizei n, GLuint *framebuffers); -GLAPI GLenum APIENTRY glCheckFramebufferStatus (GLenum target); -GLAPI void APIENTRY glFramebufferTexture1D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLAPI void APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLAPI void APIENTRY glFramebufferTexture3D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -GLAPI void APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -GLAPI void APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint *params); -GLAPI void APIENTRY glGenerateMipmap (GLenum target); -GLAPI void APIENTRY glBlitFramebuffer (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -GLAPI void APIENTRY glRenderbufferStorageMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glFramebufferTextureLayer (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC) (GLuint renderbuffer); -typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC) (GLenum target, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC) (GLsizei n, const GLuint *renderbuffers); -typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers); -typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC) (GLuint framebuffer); -typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer); -typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint *framebuffers); -typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers); -typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC) (GLenum target); -typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -#endif - -#ifndef GL_ARB_framebuffer_sRGB -#define GL_ARB_framebuffer_sRGB 1 -#endif - -#ifndef GL_ARB_geometry_shader4 -#define GL_ARB_geometry_shader4 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProgramParameteriARB (GLuint program, GLenum pname, GLint value); -GLAPI void APIENTRY glFramebufferTextureARB (GLenum target, GLenum attachment, GLuint texture, GLint level); -GLAPI void APIENTRY glFramebufferTextureLayerARB (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -GLAPI void APIENTRY glFramebufferTextureFaceARB (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIARBPROC) (GLuint program, GLenum pname, GLint value); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); -#endif - -#ifndef GL_ARB_half_float_vertex -#define GL_ARB_half_float_vertex 1 -#endif - -#ifndef GL_ARB_instanced_arrays -#define GL_ARB_instanced_arrays 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexAttribDivisorARB (GLuint index, GLuint divisor); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORARBPROC) (GLuint index, GLuint divisor); -#endif - -#ifndef GL_ARB_map_buffer_range -#define GL_ARB_map_buffer_range 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLvoid* APIENTRY glMapBufferRange (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); -GLAPI void APIENTRY glFlushMappedBufferRange (GLenum target, GLintptr offset, GLsizeiptr length); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); -typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length); -#endif - -#ifndef GL_ARB_texture_buffer_object -#define GL_ARB_texture_buffer_object 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexBufferARB (GLenum target, GLenum internalformat, GLuint buffer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTEXBUFFERARBPROC) (GLenum target, GLenum internalformat, GLuint buffer); -#endif - -#ifndef GL_ARB_texture_compression_rgtc -#define GL_ARB_texture_compression_rgtc 1 -#endif - -#ifndef GL_ARB_texture_rg -#define GL_ARB_texture_rg 1 -#endif - -#ifndef GL_ARB_vertex_array_object -#define GL_ARB_vertex_array_object 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBindVertexArray (GLuint array); -GLAPI void APIENTRY glDeleteVertexArrays (GLsizei n, const GLuint *arrays); -GLAPI void APIENTRY glGenVertexArrays (GLsizei n, GLuint *arrays); -GLAPI GLboolean APIENTRY glIsVertexArray (GLuint array); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array); -typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays); -typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays); -typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC) (GLuint array); -#endif - -#ifndef GL_ARB_uniform_buffer_object -#define GL_ARB_uniform_buffer_object 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetUniformIndices (GLuint program, GLsizei uniformCount, const GLchar* *uniformNames, GLuint *uniformIndices); -GLAPI void APIENTRY glGetActiveUniformsiv (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetActiveUniformName (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); -GLAPI GLuint APIENTRY glGetUniformBlockIndex (GLuint program, const GLchar *uniformBlockName); -GLAPI void APIENTRY glGetActiveUniformBlockiv (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetActiveUniformBlockName (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); -GLAPI void APIENTRY glUniformBlockBinding (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGETUNIFORMINDICESPROC) (GLuint program, GLsizei uniformCount, const GLchar* *uniformNames, GLuint *uniformIndices); -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC) (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC) (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); -typedef GLuint (APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC) (GLuint program, const GLchar *uniformBlockName); -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); -typedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); -#endif - -#ifndef GL_ARB_compatibility -#define GL_ARB_compatibility 1 -#endif - -#ifndef GL_ARB_copy_buffer -#define GL_ARB_copy_buffer 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glCopyBufferSubData (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); -#endif - -#ifndef GL_ARB_shader_texture_lod -#define GL_ARB_shader_texture_lod 1 -#endif - -#ifndef GL_ARB_depth_clamp -#define GL_ARB_depth_clamp 1 -#endif - -#ifndef GL_ARB_draw_elements_base_vertex -#define GL_ARB_draw_elements_base_vertex 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawElementsBaseVertex (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); -GLAPI void APIENTRY glDrawRangeElementsBaseVertex (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); -GLAPI void APIENTRY glDrawElementsInstancedBaseVertex (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount, GLint basevertex); -GLAPI void APIENTRY glMultiDrawElementsBaseVertex (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount, const GLint *basevertex); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); -typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount, GLint basevertex); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount, const GLint *basevertex); -#endif - -#ifndef GL_ARB_fragment_coord_conventions -#define GL_ARB_fragment_coord_conventions 1 -#endif - -#ifndef GL_ARB_provoking_vertex -#define GL_ARB_provoking_vertex 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProvokingVertex (GLenum mode); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC) (GLenum mode); -#endif - -#ifndef GL_ARB_seamless_cube_map -#define GL_ARB_seamless_cube_map 1 -#endif - -#ifndef GL_ARB_sync -#define GL_ARB_sync 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLsync APIENTRY glFenceSync (GLenum condition, GLbitfield flags); -GLAPI GLboolean APIENTRY glIsSync (GLsync sync); -GLAPI void APIENTRY glDeleteSync (GLsync sync); -GLAPI GLenum APIENTRY glClientWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); -GLAPI void APIENTRY glWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); -GLAPI void APIENTRY glGetInteger64v (GLenum pname, GLint64 *params); -GLAPI void APIENTRY glGetSynciv (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLsync (APIENTRYP PFNGLFENCESYNCPROC) (GLenum condition, GLbitfield flags); -typedef GLboolean (APIENTRYP PFNGLISSYNCPROC) (GLsync sync); -typedef void (APIENTRYP PFNGLDELETESYNCPROC) (GLsync sync); -typedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); -typedef void (APIENTRYP PFNGLWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); -typedef void (APIENTRYP PFNGLGETINTEGER64VPROC) (GLenum pname, GLint64 *params); -typedef void (APIENTRYP PFNGLGETSYNCIVPROC) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); -#endif - -#ifndef GL_ARB_texture_multisample -#define GL_ARB_texture_multisample 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexImage2DMultisample (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -GLAPI void APIENTRY glTexImage3DMultisample (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); -GLAPI void APIENTRY glGetMultisamplefv (GLenum pname, GLuint index, GLfloat *val); -GLAPI void APIENTRY glSampleMaski (GLuint index, GLbitfield mask); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); -typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC) (GLenum pname, GLuint index, GLfloat *val); -typedef void (APIENTRYP PFNGLSAMPLEMASKIPROC) (GLuint index, GLbitfield mask); -#endif - -#ifndef GL_ARB_vertex_array_bgra -#define GL_ARB_vertex_array_bgra 1 -#endif - -#ifndef GL_ARB_draw_buffers_blend -#define GL_ARB_draw_buffers_blend 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendEquationiARB (GLuint buf, GLenum mode); -GLAPI void APIENTRY glBlendEquationSeparateiARB (GLuint buf, GLenum modeRGB, GLenum modeAlpha); -GLAPI void APIENTRY glBlendFunciARB (GLuint buf, GLenum src, GLenum dst); -GLAPI void APIENTRY glBlendFuncSeparateiARB (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBLENDEQUATIONIARBPROC) (GLuint buf, GLenum mode); -typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIARBPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); -typedef void (APIENTRYP PFNGLBLENDFUNCIARBPROC) (GLuint buf, GLenum src, GLenum dst); -typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIARBPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); -#endif - -#ifndef GL_ARB_sample_shading -#define GL_ARB_sample_shading 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMinSampleShadingARB (GLclampf value); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLMINSAMPLESHADINGARBPROC) (GLclampf value); -#endif - -#ifndef GL_ARB_texture_cube_map_array -#define GL_ARB_texture_cube_map_array 1 -#endif - -#ifndef GL_ARB_texture_gather -#define GL_ARB_texture_gather 1 -#endif - -#ifndef GL_ARB_texture_query_lod -#define GL_ARB_texture_query_lod 1 -#endif - -#ifndef GL_ARB_shading_language_include -#define GL_ARB_shading_language_include 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glNamedStringARB (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string); -GLAPI void APIENTRY glDeleteNamedStringARB (GLint namelen, const GLchar *name); -GLAPI void APIENTRY glCompileShaderIncludeARB (GLuint shader, GLsizei count, const GLchar* *path, const GLint *length); -GLAPI GLboolean APIENTRY glIsNamedStringARB (GLint namelen, const GLchar *name); -GLAPI void APIENTRY glGetNamedStringARB (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string); -GLAPI void APIENTRY glGetNamedStringivARB (GLint namelen, const GLchar *name, GLenum pname, GLint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLNAMEDSTRINGARBPROC) (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string); -typedef void (APIENTRYP PFNGLDELETENAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name); -typedef void (APIENTRYP PFNGLCOMPILESHADERINCLUDEARBPROC) (GLuint shader, GLsizei count, const GLchar* *path, const GLint *length); -typedef GLboolean (APIENTRYP PFNGLISNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name); -typedef void (APIENTRYP PFNGLGETNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string); -typedef void (APIENTRYP PFNGLGETNAMEDSTRINGIVARBPROC) (GLint namelen, const GLchar *name, GLenum pname, GLint *params); -#endif - -#ifndef GL_ARB_texture_compression_bptc -#define GL_ARB_texture_compression_bptc 1 -#endif - -#ifndef GL_ARB_blend_func_extended -#define GL_ARB_blend_func_extended 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBindFragDataLocationIndexed (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); -GLAPI GLint APIENTRY glGetFragDataIndex (GLuint program, const GLchar *name); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONINDEXEDPROC) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); -typedef GLint (APIENTRYP PFNGLGETFRAGDATAINDEXPROC) (GLuint program, const GLchar *name); -#endif - -#ifndef GL_ARB_explicit_attrib_location -#define GL_ARB_explicit_attrib_location 1 -#endif - -#ifndef GL_ARB_occlusion_query2 -#define GL_ARB_occlusion_query2 1 -#endif - -#ifndef GL_ARB_sampler_objects -#define GL_ARB_sampler_objects 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGenSamplers (GLsizei count, GLuint *samplers); -GLAPI void APIENTRY glDeleteSamplers (GLsizei count, const GLuint *samplers); -GLAPI GLboolean APIENTRY glIsSampler (GLuint sampler); -GLAPI void APIENTRY glBindSampler (GLuint unit, GLuint sampler); -GLAPI void APIENTRY glSamplerParameteri (GLuint sampler, GLenum pname, GLint param); -GLAPI void APIENTRY glSamplerParameteriv (GLuint sampler, GLenum pname, const GLint *param); -GLAPI void APIENTRY glSamplerParameterf (GLuint sampler, GLenum pname, GLfloat param); -GLAPI void APIENTRY glSamplerParameterfv (GLuint sampler, GLenum pname, const GLfloat *param); -GLAPI void APIENTRY glSamplerParameterIiv (GLuint sampler, GLenum pname, const GLint *param); -GLAPI void APIENTRY glSamplerParameterIuiv (GLuint sampler, GLenum pname, const GLuint *param); -GLAPI void APIENTRY glGetSamplerParameteriv (GLuint sampler, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetSamplerParameterIiv (GLuint sampler, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetSamplerParameterfv (GLuint sampler, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetSamplerParameterIuiv (GLuint sampler, GLenum pname, GLuint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers); -typedef void (APIENTRYP PFNGLDELETESAMPLERSPROC) (GLsizei count, const GLuint *samplers); -typedef GLboolean (APIENTRYP PFNGLISSAMPLERPROC) (GLuint sampler); -typedef void (APIENTRYP PFNGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler); -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIPROC) (GLuint sampler, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, const GLint *param); -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFPROC) (GLuint sampler, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, const GLfloat *param); -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, const GLint *param); -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, const GLuint *param); -typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, GLuint *params); -#endif - -#ifndef GL_ARB_shader_bit_encoding -#define GL_ARB_shader_bit_encoding 1 -#endif - -#ifndef GL_ARB_texture_rgb10_a2ui -#define GL_ARB_texture_rgb10_a2ui 1 -#endif - -#ifndef GL_ARB_texture_swizzle -#define GL_ARB_texture_swizzle 1 -#endif - -#ifndef GL_ARB_timer_query -#define GL_ARB_timer_query 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glQueryCounter (GLuint id, GLenum target); -GLAPI void APIENTRY glGetQueryObjecti64v (GLuint id, GLenum pname, GLint64 *params); -GLAPI void APIENTRY glGetQueryObjectui64v (GLuint id, GLenum pname, GLuint64 *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLQUERYCOUNTERPROC) (GLuint id, GLenum target); -typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VPROC) (GLuint id, GLenum pname, GLint64 *params); -typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VPROC) (GLuint id, GLenum pname, GLuint64 *params); -#endif - -#ifndef GL_ARB_vertex_type_2_10_10_10_rev -#define GL_ARB_vertex_type_2_10_10_10_rev 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexP2ui (GLenum type, GLuint value); -GLAPI void APIENTRY glVertexP2uiv (GLenum type, const GLuint *value); -GLAPI void APIENTRY glVertexP3ui (GLenum type, GLuint value); -GLAPI void APIENTRY glVertexP3uiv (GLenum type, const GLuint *value); -GLAPI void APIENTRY glVertexP4ui (GLenum type, GLuint value); -GLAPI void APIENTRY glVertexP4uiv (GLenum type, const GLuint *value); -GLAPI void APIENTRY glTexCoordP1ui (GLenum type, GLuint coords); -GLAPI void APIENTRY glTexCoordP1uiv (GLenum type, const GLuint *coords); -GLAPI void APIENTRY glTexCoordP2ui (GLenum type, GLuint coords); -GLAPI void APIENTRY glTexCoordP2uiv (GLenum type, const GLuint *coords); -GLAPI void APIENTRY glTexCoordP3ui (GLenum type, GLuint coords); -GLAPI void APIENTRY glTexCoordP3uiv (GLenum type, const GLuint *coords); -GLAPI void APIENTRY glTexCoordP4ui (GLenum type, GLuint coords); -GLAPI void APIENTRY glTexCoordP4uiv (GLenum type, const GLuint *coords); -GLAPI void APIENTRY glMultiTexCoordP1ui (GLenum texture, GLenum type, GLuint coords); -GLAPI void APIENTRY glMultiTexCoordP1uiv (GLenum texture, GLenum type, const GLuint *coords); -GLAPI void APIENTRY glMultiTexCoordP2ui (GLenum texture, GLenum type, GLuint coords); -GLAPI void APIENTRY glMultiTexCoordP2uiv (GLenum texture, GLenum type, const GLuint *coords); -GLAPI void APIENTRY glMultiTexCoordP3ui (GLenum texture, GLenum type, GLuint coords); -GLAPI void APIENTRY glMultiTexCoordP3uiv (GLenum texture, GLenum type, const GLuint *coords); -GLAPI void APIENTRY glMultiTexCoordP4ui (GLenum texture, GLenum type, GLuint coords); -GLAPI void APIENTRY glMultiTexCoordP4uiv (GLenum texture, GLenum type, const GLuint *coords); -GLAPI void APIENTRY glNormalP3ui (GLenum type, GLuint coords); -GLAPI void APIENTRY glNormalP3uiv (GLenum type, const GLuint *coords); -GLAPI void APIENTRY glColorP3ui (GLenum type, GLuint color); -GLAPI void APIENTRY glColorP3uiv (GLenum type, const GLuint *color); -GLAPI void APIENTRY glColorP4ui (GLenum type, GLuint color); -GLAPI void APIENTRY glColorP4uiv (GLenum type, const GLuint *color); -GLAPI void APIENTRY glSecondaryColorP3ui (GLenum type, GLuint color); -GLAPI void APIENTRY glSecondaryColorP3uiv (GLenum type, const GLuint *color); -GLAPI void APIENTRY glVertexAttribP1ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); -GLAPI void APIENTRY glVertexAttribP1uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -GLAPI void APIENTRY glVertexAttribP2ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); -GLAPI void APIENTRY glVertexAttribP2uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -GLAPI void APIENTRY glVertexAttribP3ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); -GLAPI void APIENTRY glVertexAttribP3uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -GLAPI void APIENTRY glVertexAttribP4ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); -GLAPI void APIENTRY glVertexAttribP4uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVERTEXP2UIPROC) (GLenum type, GLuint value); -typedef void (APIENTRYP PFNGLVERTEXP2UIVPROC) (GLenum type, const GLuint *value); -typedef void (APIENTRYP PFNGLVERTEXP3UIPROC) (GLenum type, GLuint value); -typedef void (APIENTRYP PFNGLVERTEXP3UIVPROC) (GLenum type, const GLuint *value); -typedef void (APIENTRYP PFNGLVERTEXP4UIPROC) (GLenum type, GLuint value); -typedef void (APIENTRYP PFNGLVERTEXP4UIVPROC) (GLenum type, const GLuint *value); -typedef void (APIENTRYP PFNGLTEXCOORDP1UIPROC) (GLenum type, GLuint coords); -typedef void (APIENTRYP PFNGLTEXCOORDP1UIVPROC) (GLenum type, const GLuint *coords); -typedef void (APIENTRYP PFNGLTEXCOORDP2UIPROC) (GLenum type, GLuint coords); -typedef void (APIENTRYP PFNGLTEXCOORDP2UIVPROC) (GLenum type, const GLuint *coords); -typedef void (APIENTRYP PFNGLTEXCOORDP3UIPROC) (GLenum type, GLuint coords); -typedef void (APIENTRYP PFNGLTEXCOORDP3UIVPROC) (GLenum type, const GLuint *coords); -typedef void (APIENTRYP PFNGLTEXCOORDP4UIPROC) (GLenum type, GLuint coords); -typedef void (APIENTRYP PFNGLTEXCOORDP4UIVPROC) (GLenum type, const GLuint *coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIPROC) (GLenum texture, GLenum type, GLuint coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIPROC) (GLenum texture, GLenum type, GLuint coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIPROC) (GLenum texture, GLenum type, GLuint coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIPROC) (GLenum texture, GLenum type, GLuint coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); -typedef void (APIENTRYP PFNGLNORMALP3UIPROC) (GLenum type, GLuint coords); -typedef void (APIENTRYP PFNGLNORMALP3UIVPROC) (GLenum type, const GLuint *coords); -typedef void (APIENTRYP PFNGLCOLORP3UIPROC) (GLenum type, GLuint color); -typedef void (APIENTRYP PFNGLCOLORP3UIVPROC) (GLenum type, const GLuint *color); -typedef void (APIENTRYP PFNGLCOLORP4UIPROC) (GLenum type, GLuint color); -typedef void (APIENTRYP PFNGLCOLORP4UIVPROC) (GLenum type, const GLuint *color); -typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIPROC) (GLenum type, GLuint color); -typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIVPROC) (GLenum type, const GLuint *color); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -#endif - -#ifndef GL_ARB_draw_indirect -#define GL_ARB_draw_indirect 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawArraysIndirect (GLenum mode, const GLvoid *indirect); -GLAPI void APIENTRY glDrawElementsIndirect (GLenum mode, GLenum type, const GLvoid *indirect); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDRAWARRAYSINDIRECTPROC) (GLenum mode, const GLvoid *indirect); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const GLvoid *indirect); -#endif - -#ifndef GL_ARB_gpu_shader5 -#define GL_ARB_gpu_shader5 1 -#endif - -#ifndef GL_ARB_gpu_shader_fp64 -#define GL_ARB_gpu_shader_fp64 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glUniform1d (GLint location, GLdouble x); -GLAPI void APIENTRY glUniform2d (GLint location, GLdouble x, GLdouble y); -GLAPI void APIENTRY glUniform3d (GLint location, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glUniform4d (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glUniform1dv (GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glUniform2dv (GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glUniform3dv (GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glUniform4dv (GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix2x3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix2x4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix3x2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix3x4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix4x2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix4x3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glGetUniformdv (GLuint program, GLint location, GLdouble *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLUNIFORM1DPROC) (GLint location, GLdouble x); -typedef void (APIENTRYP PFNGLUNIFORM2DPROC) (GLint location, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLUNIFORM3DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLUNIFORM4DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLUNIFORM1DVPROC) (GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORM2DVPROC) (GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORM3DVPROC) (GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORM4DVPROC) (GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLGETUNIFORMDVPROC) (GLuint program, GLint location, GLdouble *params); -#endif - -#ifndef GL_ARB_shader_subroutine -#define GL_ARB_shader_subroutine 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLint APIENTRY glGetSubroutineUniformLocation (GLuint program, GLenum shadertype, const GLchar *name); -GLAPI GLuint APIENTRY glGetSubroutineIndex (GLuint program, GLenum shadertype, const GLchar *name); -GLAPI void APIENTRY glGetActiveSubroutineUniformiv (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values); -GLAPI void APIENTRY glGetActiveSubroutineUniformName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); -GLAPI void APIENTRY glGetActiveSubroutineName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); -GLAPI void APIENTRY glUniformSubroutinesuiv (GLenum shadertype, GLsizei count, const GLuint *indices); -GLAPI void APIENTRY glGetUniformSubroutineuiv (GLenum shadertype, GLint location, GLuint *params); -GLAPI void APIENTRY glGetProgramStageiv (GLuint program, GLenum shadertype, GLenum pname, GLint *values); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLint (APIENTRYP PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC) (GLuint program, GLenum shadertype, const GLchar *name); -typedef GLuint (APIENTRYP PFNGLGETSUBROUTINEINDEXPROC) (GLuint program, GLenum shadertype, const GLchar *name); -typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC) (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values); -typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); -typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINENAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); -typedef void (APIENTRYP PFNGLUNIFORMSUBROUTINESUIVPROC) (GLenum shadertype, GLsizei count, const GLuint *indices); -typedef void (APIENTRYP PFNGLGETUNIFORMSUBROUTINEUIVPROC) (GLenum shadertype, GLint location, GLuint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMSTAGEIVPROC) (GLuint program, GLenum shadertype, GLenum pname, GLint *values); -#endif - -#ifndef GL_ARB_tessellation_shader -#define GL_ARB_tessellation_shader 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPatchParameteri (GLenum pname, GLint value); -GLAPI void APIENTRY glPatchParameterfv (GLenum pname, const GLfloat *values); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPATCHPARAMETERIPROC) (GLenum pname, GLint value); -typedef void (APIENTRYP PFNGLPATCHPARAMETERFVPROC) (GLenum pname, const GLfloat *values); -#endif - -#ifndef GL_ARB_texture_buffer_object_rgb32 -#define GL_ARB_texture_buffer_object_rgb32 1 -#endif - -#ifndef GL_ARB_transform_feedback2 -#define GL_ARB_transform_feedback2 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBindTransformFeedback (GLenum target, GLuint id); -GLAPI void APIENTRY glDeleteTransformFeedbacks (GLsizei n, const GLuint *ids); -GLAPI void APIENTRY glGenTransformFeedbacks (GLsizei n, GLuint *ids); -GLAPI GLboolean APIENTRY glIsTransformFeedback (GLuint id); -GLAPI void APIENTRY glPauseTransformFeedback (void); -GLAPI void APIENTRY glResumeTransformFeedback (void); -GLAPI void APIENTRY glDrawTransformFeedback (GLenum mode, GLuint id); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKPROC) (GLenum target, GLuint id); -typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSPROC) (GLsizei n, const GLuint *ids); -typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids); -typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKPROC) (GLuint id); -typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKPROC) (void); -typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKPROC) (void); -typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKPROC) (GLenum mode, GLuint id); -#endif - -#ifndef GL_ARB_transform_feedback3 -#define GL_ARB_transform_feedback3 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawTransformFeedbackStream (GLenum mode, GLuint id, GLuint stream); -GLAPI void APIENTRY glBeginQueryIndexed (GLenum target, GLuint index, GLuint id); -GLAPI void APIENTRY glEndQueryIndexed (GLenum target, GLuint index); -GLAPI void APIENTRY glGetQueryIndexediv (GLenum target, GLuint index, GLenum pname, GLint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC) (GLenum mode, GLuint id, GLuint stream); -typedef void (APIENTRYP PFNGLBEGINQUERYINDEXEDPROC) (GLenum target, GLuint index, GLuint id); -typedef void (APIENTRYP PFNGLENDQUERYINDEXEDPROC) (GLenum target, GLuint index); -typedef void (APIENTRYP PFNGLGETQUERYINDEXEDIVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params); -#endif - -#ifndef GL_ARB_ES2_compatibility -#define GL_ARB_ES2_compatibility 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glReleaseShaderCompiler (void); -GLAPI void APIENTRY glShaderBinary (GLsizei count, const GLuint *shaders, GLenum binaryformat, const GLvoid *binary, GLsizei length); -GLAPI void APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); -GLAPI void APIENTRY glDepthRangef (GLclampf n, GLclampf f); -GLAPI void APIENTRY glClearDepthf (GLclampf d); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLRELEASESHADERCOMPILERPROC) (void); -typedef void (APIENTRYP PFNGLSHADERBINARYPROC) (GLsizei count, const GLuint *shaders, GLenum binaryformat, const GLvoid *binary, GLsizei length); -typedef void (APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC) (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); -typedef void (APIENTRYP PFNGLDEPTHRANGEFPROC) (GLclampf n, GLclampf f); -typedef void (APIENTRYP PFNGLCLEARDEPTHFPROC) (GLclampf d); -#endif - -#ifndef GL_ARB_get_program_binary -#define GL_ARB_get_program_binary 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetProgramBinary (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary); -GLAPI void APIENTRY glProgramBinary (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLsizei length); -GLAPI void APIENTRY glProgramParameteri (GLuint program, GLenum pname, GLint value); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary); -typedef void (APIENTRYP PFNGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLsizei length); -typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value); -#endif - -#ifndef GL_ARB_separate_shader_objects -#define GL_ARB_separate_shader_objects 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glUseProgramStages (GLuint pipeline, GLbitfield stages, GLuint program); -GLAPI void APIENTRY glActiveShaderProgram (GLuint pipeline, GLuint program); -GLAPI GLuint APIENTRY glCreateShaderProgramv (GLenum type, GLsizei count, const GLchar* *strings); -GLAPI void APIENTRY glBindProgramPipeline (GLuint pipeline); -GLAPI void APIENTRY glDeleteProgramPipelines (GLsizei n, const GLuint *pipelines); -GLAPI void APIENTRY glGenProgramPipelines (GLsizei n, GLuint *pipelines); -GLAPI GLboolean APIENTRY glIsProgramPipeline (GLuint pipeline); -GLAPI void APIENTRY glGetProgramPipelineiv (GLuint pipeline, GLenum pname, GLint *params); -GLAPI void APIENTRY glProgramUniform1i (GLuint program, GLint location, GLint v0); -GLAPI void APIENTRY glProgramUniform1iv (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniform1f (GLuint program, GLint location, GLfloat v0); -GLAPI void APIENTRY glProgramUniform1fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform1d (GLuint program, GLint location, GLdouble v0); -GLAPI void APIENTRY glProgramUniform1dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniform1ui (GLuint program, GLint location, GLuint v0); -GLAPI void APIENTRY glProgramUniform1uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glProgramUniform2i (GLuint program, GLint location, GLint v0, GLint v1); -GLAPI void APIENTRY glProgramUniform2iv (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniform2f (GLuint program, GLint location, GLfloat v0, GLfloat v1); -GLAPI void APIENTRY glProgramUniform2fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform2d (GLuint program, GLint location, GLdouble v0, GLdouble v1); -GLAPI void APIENTRY glProgramUniform2dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniform2ui (GLuint program, GLint location, GLuint v0, GLuint v1); -GLAPI void APIENTRY glProgramUniform2uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glProgramUniform3i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); -GLAPI void APIENTRY glProgramUniform3iv (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniform3f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -GLAPI void APIENTRY glProgramUniform3fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform3d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); -GLAPI void APIENTRY glProgramUniform3dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniform3ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); -GLAPI void APIENTRY glProgramUniform3uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glProgramUniform4i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -GLAPI void APIENTRY glProgramUniform4iv (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniform4f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -GLAPI void APIENTRY glProgramUniform4fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform4d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); -GLAPI void APIENTRY glProgramUniform4dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniform4ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -GLAPI void APIENTRY glProgramUniform4uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glProgramUniformMatrix2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix2x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix3x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix2x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix4x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix3x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix4x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix2x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix3x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix2x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix4x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix3x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix4x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glValidateProgramPipeline (GLuint pipeline); -GLAPI void APIENTRY glGetProgramPipelineInfoLog (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLUSEPROGRAMSTAGESPROC) (GLuint pipeline, GLbitfield stages, GLuint program); -typedef void (APIENTRYP PFNGLACTIVESHADERPROGRAMPROC) (GLuint pipeline, GLuint program); -typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMVPROC) (GLenum type, GLsizei count, const GLchar* *strings); -typedef void (APIENTRYP PFNGLBINDPROGRAMPIPELINEPROC) (GLuint pipeline); -typedef void (APIENTRYP PFNGLDELETEPROGRAMPIPELINESPROC) (GLsizei n, const GLuint *pipelines); -typedef void (APIENTRYP PFNGLGENPROGRAMPIPELINESPROC) (GLsizei n, GLuint *pipelines); -typedef GLboolean (APIENTRYP PFNGLISPROGRAMPIPELINEPROC) (GLuint pipeline); -typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEIVPROC) (GLuint pipeline, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IPROC) (GLuint program, GLint location, GLint v0); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FPROC) (GLuint program, GLint location, GLfloat v0); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DPROC) (GLuint program, GLint location, GLdouble v0); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIPROC) (GLuint program, GLint location, GLuint v0); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IPROC) (GLuint program, GLint location, GLint v0, GLint v1); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEPROC) (GLuint pipeline); -typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -#endif - -#ifndef GL_ARB_vertex_attrib_64bit -#define GL_ARB_vertex_attrib_64bit 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexAttribL1d (GLuint index, GLdouble x); -GLAPI void APIENTRY glVertexAttribL2d (GLuint index, GLdouble x, GLdouble y); -GLAPI void APIENTRY glVertexAttribL3d (GLuint index, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glVertexAttribL4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glVertexAttribL1dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribL2dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribL3dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribL4dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribLPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -GLAPI void APIENTRY glGetVertexAttribLdv (GLuint index, GLenum pname, GLdouble *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DPROC) (GLuint index, GLdouble x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DPROC) (GLuint index, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVPROC) (GLuint index, GLenum pname, GLdouble *params); -#endif - -#ifndef GL_ARB_viewport_array -#define GL_ARB_viewport_array 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glViewportArrayv (GLuint first, GLsizei count, const GLfloat *v); -GLAPI void APIENTRY glViewportIndexedf (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); -GLAPI void APIENTRY glViewportIndexedfv (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glScissorArrayv (GLuint first, GLsizei count, const GLint *v); -GLAPI void APIENTRY glScissorIndexed (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); -GLAPI void APIENTRY glScissorIndexedv (GLuint index, const GLint *v); -GLAPI void APIENTRY glDepthRangeArrayv (GLuint first, GLsizei count, const GLclampd *v); -GLAPI void APIENTRY glDepthRangeIndexed (GLuint index, GLclampd n, GLclampd f); -GLAPI void APIENTRY glGetFloati_v (GLenum target, GLuint index, GLfloat *data); -GLAPI void APIENTRY glGetDoublei_v (GLenum target, GLuint index, GLdouble *data); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVIEWPORTARRAYVPROC) (GLuint first, GLsizei count, const GLfloat *v); -typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); -typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLSCISSORARRAYVPROC) (GLuint first, GLsizei count, const GLint *v); -typedef void (APIENTRYP PFNGLSCISSORINDEXEDPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLSCISSORINDEXEDVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLDEPTHRANGEARRAYVPROC) (GLuint first, GLsizei count, const GLclampd *v); -typedef void (APIENTRYP PFNGLDEPTHRANGEINDEXEDPROC) (GLuint index, GLclampd n, GLclampd f); -typedef void (APIENTRYP PFNGLGETFLOATI_VPROC) (GLenum target, GLuint index, GLfloat *data); -typedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC) (GLenum target, GLuint index, GLdouble *data); -#endif - -#ifndef GL_ARB_cl_event -#define GL_ARB_cl_event 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLsync APIENTRY glCreateSyncFromCLeventARB (struct _cl_context * context, struct _cl_event * event, GLbitfield flags); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLsync (APIENTRYP PFNGLCREATESYNCFROMCLEVENTARBPROC) (struct _cl_context * context, struct _cl_event * event, GLbitfield flags); -#endif - -#ifndef GL_ARB_debug_output -#define GL_ARB_debug_output 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDebugMessageControlARB (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); -GLAPI void APIENTRY glDebugMessageInsertARB (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); -GLAPI void APIENTRY glDebugMessageCallbackARB (GLDEBUGPROCARB callback, const GLvoid *userParam); -GLAPI GLuint APIENTRY glGetDebugMessageLogARB (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLARBPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); -typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTARBPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); -typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKARBPROC) (GLDEBUGPROCARB callback, const GLvoid *userParam); -typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGARBPROC) (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); -#endif - -#ifndef GL_ARB_robustness -#define GL_ARB_robustness 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLenum APIENTRY glGetGraphicsResetStatusARB (void); -GLAPI void APIENTRY glGetnMapdvARB (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v); -GLAPI void APIENTRY glGetnMapfvARB (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v); -GLAPI void APIENTRY glGetnMapivARB (GLenum target, GLenum query, GLsizei bufSize, GLint *v); -GLAPI void APIENTRY glGetnPixelMapfvARB (GLenum map, GLsizei bufSize, GLfloat *values); -GLAPI void APIENTRY glGetnPixelMapuivARB (GLenum map, GLsizei bufSize, GLuint *values); -GLAPI void APIENTRY glGetnPixelMapusvARB (GLenum map, GLsizei bufSize, GLushort *values); -GLAPI void APIENTRY glGetnPolygonStippleARB (GLsizei bufSize, GLubyte *pattern); -GLAPI void APIENTRY glGetnColorTableARB (GLenum target, GLenum format, GLenum type, GLsizei bufSize, GLvoid *table); -GLAPI void APIENTRY glGetnConvolutionFilterARB (GLenum target, GLenum format, GLenum type, GLsizei bufSize, GLvoid *image); -GLAPI void APIENTRY glGetnSeparableFilterARB (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, GLvoid *row, GLsizei columnBufSize, GLvoid *column, GLvoid *span); -GLAPI void APIENTRY glGetnHistogramARB (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, GLvoid *values); -GLAPI void APIENTRY glGetnMinmaxARB (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, GLvoid *values); -GLAPI void APIENTRY glGetnTexImageARB (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, GLvoid *img); -GLAPI void APIENTRY glReadnPixelsARB (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLvoid *data); -GLAPI void APIENTRY glGetnCompressedTexImageARB (GLenum target, GLint lod, GLsizei bufSize, GLvoid *img); -GLAPI void APIENTRY glGetnUniformfvARB (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); -GLAPI void APIENTRY glGetnUniformivARB (GLuint program, GLint location, GLsizei bufSize, GLint *params); -GLAPI void APIENTRY glGetnUniformuivARB (GLuint program, GLint location, GLsizei bufSize, GLuint *params); -GLAPI void APIENTRY glGetnUniformdvARB (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSARBPROC) (void); -typedef void (APIENTRYP PFNGLGETNMAPDVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v); -typedef void (APIENTRYP PFNGLGETNMAPFVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v); -typedef void (APIENTRYP PFNGLGETNMAPIVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLint *v); -typedef void (APIENTRYP PFNGLGETNPIXELMAPFVARBPROC) (GLenum map, GLsizei bufSize, GLfloat *values); -typedef void (APIENTRYP PFNGLGETNPIXELMAPUIVARBPROC) (GLenum map, GLsizei bufSize, GLuint *values); -typedef void (APIENTRYP PFNGLGETNPIXELMAPUSVARBPROC) (GLenum map, GLsizei bufSize, GLushort *values); -typedef void (APIENTRYP PFNGLGETNPOLYGONSTIPPLEARBPROC) (GLsizei bufSize, GLubyte *pattern); -typedef void (APIENTRYP PFNGLGETNCOLORTABLEARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, GLvoid *table); -typedef void (APIENTRYP PFNGLGETNCONVOLUTIONFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, GLvoid *image); -typedef void (APIENTRYP PFNGLGETNSEPARABLEFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, GLvoid *row, GLsizei columnBufSize, GLvoid *column, GLvoid *span); -typedef void (APIENTRYP PFNGLGETNHISTOGRAMARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, GLvoid *values); -typedef void (APIENTRYP PFNGLGETNMINMAXARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, GLvoid *values); -typedef void (APIENTRYP PFNGLGETNTEXIMAGEARBPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, GLvoid *img); -typedef void (APIENTRYP PFNGLREADNPIXELSARBPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLvoid *data); -typedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint lod, GLsizei bufSize, GLvoid *img); -typedef void (APIENTRYP PFNGLGETNUNIFORMFVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); -typedef void (APIENTRYP PFNGLGETNUNIFORMIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params); -typedef void (APIENTRYP PFNGLGETNUNIFORMUIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params); -typedef void (APIENTRYP PFNGLGETNUNIFORMDVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); -#endif - -#ifndef GL_ARB_shader_stencil_export -#define GL_ARB_shader_stencil_export 1 -#endif - -#ifndef GL_ARB_base_instance -#define GL_ARB_base_instance 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawArraysInstancedBaseInstance (GLenum mode, GLint first, GLsizei count, GLsizei primcount, GLuint baseinstance); -GLAPI void APIENTRY glDrawElementsInstancedBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount, GLuint baseinstance); -GLAPI void APIENTRY glDrawElementsInstancedBaseVertexBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount, GLint basevertex, GLuint baseinstance); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount, GLuint baseinstance); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount, GLuint baseinstance); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount, GLint basevertex, GLuint baseinstance); -#endif - -#ifndef GL_ARB_shading_language_420pack -#define GL_ARB_shading_language_420pack 1 -#endif - -#ifndef GL_ARB_transform_feedback_instanced -#define GL_ARB_transform_feedback_instanced 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawTransformFeedbackInstanced (GLenum mode, GLuint id, GLsizei primcount); -GLAPI void APIENTRY glDrawTransformFeedbackStreamInstanced (GLenum mode, GLuint id, GLuint stream, GLsizei primcount); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC) (GLenum mode, GLuint id, GLsizei primcount); -typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC) (GLenum mode, GLuint id, GLuint stream, GLsizei primcount); -#endif - -#ifndef GL_ARB_compressed_texture_pixel_storage -#define GL_ARB_compressed_texture_pixel_storage 1 -#endif - -#ifndef GL_ARB_conservative_depth -#define GL_ARB_conservative_depth 1 -#endif - -#ifndef GL_ARB_internalformat_query -#define GL_ARB_internalformat_query 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetInternalformativ (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); -#endif - -#ifndef GL_ARB_map_buffer_alignment -#define GL_ARB_map_buffer_alignment 1 -#endif - -#ifndef GL_ARB_shader_atomic_counters -#define GL_ARB_shader_atomic_counters 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetActiveAtomicCounterBufferiv (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC) (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params); -#endif - -#ifndef GL_ARB_shader_image_load_store -#define GL_ARB_shader_image_load_store 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBindImageTexture (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); -GLAPI void APIENTRY glMemoryBarrier (GLbitfield barriers); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); -typedef void (APIENTRYP PFNGLMEMORYBARRIERPROC) (GLbitfield barriers); -#endif - -#ifndef GL_ARB_shading_language_packing -#define GL_ARB_shading_language_packing 1 -#endif - -#ifndef GL_ARB_texture_storage -#define GL_ARB_texture_storage 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexStorage1D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); -GLAPI void APIENTRY glTexStorage2D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glTexStorage3D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); -GLAPI void APIENTRY glTextureStorage1DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); -GLAPI void APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTEXSTORAGE1DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); -typedef void (APIENTRYP PFNGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); -typedef void (APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); -typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); -#endif - -#ifndef GL_EXT_abgr -#define GL_EXT_abgr 1 -#endif - -#ifndef GL_EXT_blend_color -#define GL_EXT_blend_color 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendColorEXT (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBLENDCOLOREXTPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); -#endif - -#ifndef GL_EXT_polygon_offset -#define GL_EXT_polygon_offset 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPolygonOffsetEXT (GLfloat factor, GLfloat bias); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPOLYGONOFFSETEXTPROC) (GLfloat factor, GLfloat bias); -#endif - -#ifndef GL_EXT_texture -#define GL_EXT_texture 1 -#endif - -#ifndef GL_EXT_texture3D -#define GL_EXT_texture3D 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexImage3DEXT (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTEXIMAGE3DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); -#endif - -#ifndef GL_SGIS_texture_filter4 -#define GL_SGIS_texture_filter4 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetTexFilterFuncSGIS (GLenum target, GLenum filter, GLfloat *weights); -GLAPI void APIENTRY glTexFilterFuncSGIS (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGETTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLfloat *weights); -typedef void (APIENTRYP PFNGLTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights); -#endif - -#ifndef GL_EXT_subtexture -#define GL_EXT_subtexture 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); -#endif - -#ifndef GL_EXT_copy_texture -#define GL_EXT_copy_texture 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glCopyTexImage1DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); -GLAPI void APIENTRY glCopyTexImage2DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -GLAPI void APIENTRY glCopyTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glCopyTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glCopyTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); -typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -#endif - -#ifndef GL_EXT_histogram -#define GL_EXT_histogram 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetHistogramEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); -GLAPI void APIENTRY glGetHistogramParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetHistogramParameterivEXT (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetMinmaxEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); -GLAPI void APIENTRY glGetMinmaxParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetMinmaxParameterivEXT (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glHistogramEXT (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); -GLAPI void APIENTRY glMinmaxEXT (GLenum target, GLenum internalformat, GLboolean sink); -GLAPI void APIENTRY glResetHistogramEXT (GLenum target); -GLAPI void APIENTRY glResetMinmaxEXT (GLenum target); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGETHISTOGRAMEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); -typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETMINMAXEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); -typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLHISTOGRAMEXTPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); -typedef void (APIENTRYP PFNGLMINMAXEXTPROC) (GLenum target, GLenum internalformat, GLboolean sink); -typedef void (APIENTRYP PFNGLRESETHISTOGRAMEXTPROC) (GLenum target); -typedef void (APIENTRYP PFNGLRESETMINMAXEXTPROC) (GLenum target); -#endif - -#ifndef GL_EXT_convolution -#define GL_EXT_convolution 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); -GLAPI void APIENTRY glConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); -GLAPI void APIENTRY glConvolutionParameterfEXT (GLenum target, GLenum pname, GLfloat params); -GLAPI void APIENTRY glConvolutionParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glConvolutionParameteriEXT (GLenum target, GLenum pname, GLint params); -GLAPI void APIENTRY glConvolutionParameterivEXT (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glCopyConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glCopyConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetConvolutionFilterEXT (GLenum target, GLenum format, GLenum type, GLvoid *image); -GLAPI void APIENTRY glGetConvolutionParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetConvolutionParameterivEXT (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetSeparableFilterEXT (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); -GLAPI void APIENTRY glSeparableFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); -typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); -typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat params); -typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint params); -typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image); -typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETSEPARABLEFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); -typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); -#endif - -#ifndef GL_SGI_color_matrix -#define GL_SGI_color_matrix 1 -#endif - -#ifndef GL_SGI_color_table -#define GL_SGI_color_table 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColorTableSGI (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); -GLAPI void APIENTRY glColorTableParameterfvSGI (GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glColorTableParameterivSGI (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glCopyColorTableSGI (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glGetColorTableSGI (GLenum target, GLenum format, GLenum type, GLvoid *table); -GLAPI void APIENTRY glGetColorTableParameterfvSGI (GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetColorTableParameterivSGI (GLenum target, GLenum pname, GLint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); -typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLCOPYCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLGETCOLORTABLESGIPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table); -typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, GLint *params); -#endif - -#ifndef GL_SGIX_pixel_texture -#define GL_SGIX_pixel_texture 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPixelTexGenSGIX (GLenum mode); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPIXELTEXGENSGIXPROC) (GLenum mode); -#endif - -#ifndef GL_SGIS_pixel_texture -#define GL_SGIS_pixel_texture 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPixelTexGenParameteriSGIS (GLenum pname, GLint param); -GLAPI void APIENTRY glPixelTexGenParameterivSGIS (GLenum pname, const GLint *params); -GLAPI void APIENTRY glPixelTexGenParameterfSGIS (GLenum pname, GLfloat param); -GLAPI void APIENTRY glPixelTexGenParameterfvSGIS (GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glGetPixelTexGenParameterivSGIS (GLenum pname, GLint *params); -GLAPI void APIENTRY glGetPixelTexGenParameterfvSGIS (GLenum pname, GLfloat *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERISGISPROC) (GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFSGISPROC) (GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, GLfloat *params); -#endif - -#ifndef GL_SGIS_texture4D -#define GL_SGIS_texture4D 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexImage4DSGIS (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glTexSubImage4DSGIS (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const GLvoid *pixels); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTEXIMAGE4DSGISPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLTEXSUBIMAGE4DSGISPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const GLvoid *pixels); -#endif - -#ifndef GL_SGI_texture_color_table -#define GL_SGI_texture_color_table 1 -#endif - -#ifndef GL_EXT_cmyka -#define GL_EXT_cmyka 1 -#endif - -#ifndef GL_EXT_texture_object -#define GL_EXT_texture_object 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLboolean APIENTRY glAreTexturesResidentEXT (GLsizei n, const GLuint *textures, GLboolean *residences); -GLAPI void APIENTRY glBindTextureEXT (GLenum target, GLuint texture); -GLAPI void APIENTRY glDeleteTexturesEXT (GLsizei n, const GLuint *textures); -GLAPI void APIENTRY glGenTexturesEXT (GLsizei n, GLuint *textures); -GLAPI GLboolean APIENTRY glIsTextureEXT (GLuint texture); -GLAPI void APIENTRY glPrioritizeTexturesEXT (GLsizei n, const GLuint *textures, const GLclampf *priorities); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLboolean (APIENTRYP PFNGLARETEXTURESRESIDENTEXTPROC) (GLsizei n, const GLuint *textures, GLboolean *residences); -typedef void (APIENTRYP PFNGLBINDTEXTUREEXTPROC) (GLenum target, GLuint texture); -typedef void (APIENTRYP PFNGLDELETETEXTURESEXTPROC) (GLsizei n, const GLuint *textures); -typedef void (APIENTRYP PFNGLGENTEXTURESEXTPROC) (GLsizei n, GLuint *textures); -typedef GLboolean (APIENTRYP PFNGLISTEXTUREEXTPROC) (GLuint texture); -typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESEXTPROC) (GLsizei n, const GLuint *textures, const GLclampf *priorities); -#endif - -#ifndef GL_SGIS_detail_texture -#define GL_SGIS_detail_texture 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDetailTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points); -GLAPI void APIENTRY glGetDetailTexFuncSGIS (GLenum target, GLfloat *points); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDETAILTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points); -typedef void (APIENTRYP PFNGLGETDETAILTEXFUNCSGISPROC) (GLenum target, GLfloat *points); -#endif - -#ifndef GL_SGIS_sharpen_texture -#define GL_SGIS_sharpen_texture 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glSharpenTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points); -GLAPI void APIENTRY glGetSharpenTexFuncSGIS (GLenum target, GLfloat *points); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLSHARPENTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points); -typedef void (APIENTRYP PFNGLGETSHARPENTEXFUNCSGISPROC) (GLenum target, GLfloat *points); -#endif - -#ifndef GL_EXT_packed_pixels -#define GL_EXT_packed_pixels 1 -#endif - -#ifndef GL_SGIS_texture_lod -#define GL_SGIS_texture_lod 1 -#endif - -#ifndef GL_SGIS_multisample -#define GL_SGIS_multisample 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glSampleMaskSGIS (GLclampf value, GLboolean invert); -GLAPI void APIENTRY glSamplePatternSGIS (GLenum pattern); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLSAMPLEMASKSGISPROC) (GLclampf value, GLboolean invert); -typedef void (APIENTRYP PFNGLSAMPLEPATTERNSGISPROC) (GLenum pattern); -#endif - -#ifndef GL_EXT_rescale_normal -#define GL_EXT_rescale_normal 1 -#endif - -#ifndef GL_EXT_vertex_array -#define GL_EXT_vertex_array 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glArrayElementEXT (GLint i); -GLAPI void APIENTRY glColorPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); -GLAPI void APIENTRY glDrawArraysEXT (GLenum mode, GLint first, GLsizei count); -GLAPI void APIENTRY glEdgeFlagPointerEXT (GLsizei stride, GLsizei count, const GLboolean *pointer); -GLAPI void APIENTRY glGetPointervEXT (GLenum pname, GLvoid* *params); -GLAPI void APIENTRY glIndexPointerEXT (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); -GLAPI void APIENTRY glNormalPointerEXT (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); -GLAPI void APIENTRY glTexCoordPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); -GLAPI void APIENTRY glVertexPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLARRAYELEMENTEXTPROC) (GLint i); -typedef void (APIENTRYP PFNGLCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLDRAWARRAYSEXTPROC) (GLenum mode, GLint first, GLsizei count); -typedef void (APIENTRYP PFNGLEDGEFLAGPOINTEREXTPROC) (GLsizei stride, GLsizei count, const GLboolean *pointer); -typedef void (APIENTRYP PFNGLGETPOINTERVEXTPROC) (GLenum pname, GLvoid* *params); -typedef void (APIENTRYP PFNGLINDEXPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLNORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLTEXCOORDPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLVERTEXPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); -#endif - -#ifndef GL_EXT_misc_attribute -#define GL_EXT_misc_attribute 1 -#endif - -#ifndef GL_SGIS_generate_mipmap -#define GL_SGIS_generate_mipmap 1 -#endif - -#ifndef GL_SGIX_clipmap -#define GL_SGIX_clipmap 1 -#endif - -#ifndef GL_SGIX_shadow -#define GL_SGIX_shadow 1 -#endif - -#ifndef GL_SGIS_texture_edge_clamp -#define GL_SGIS_texture_edge_clamp 1 -#endif - -#ifndef GL_SGIS_texture_border_clamp -#define GL_SGIS_texture_border_clamp 1 -#endif - -#ifndef GL_EXT_blend_minmax -#define GL_EXT_blend_minmax 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendEquationEXT (GLenum mode); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBLENDEQUATIONEXTPROC) (GLenum mode); -#endif - -#ifndef GL_EXT_blend_subtract -#define GL_EXT_blend_subtract 1 -#endif - -#ifndef GL_EXT_blend_logic_op -#define GL_EXT_blend_logic_op 1 -#endif - -#ifndef GL_SGIX_interlace -#define GL_SGIX_interlace 1 -#endif - -#ifndef GL_SGIX_pixel_tiles -#define GL_SGIX_pixel_tiles 1 -#endif - -#ifndef GL_SGIX_texture_select -#define GL_SGIX_texture_select 1 -#endif - -#ifndef GL_SGIX_sprite -#define GL_SGIX_sprite 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glSpriteParameterfSGIX (GLenum pname, GLfloat param); -GLAPI void APIENTRY glSpriteParameterfvSGIX (GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glSpriteParameteriSGIX (GLenum pname, GLint param); -GLAPI void APIENTRY glSpriteParameterivSGIX (GLenum pname, const GLint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLSPRITEPARAMETERFSGIXPROC) (GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLSPRITEPARAMETERFVSGIXPROC) (GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLSPRITEPARAMETERISGIXPROC) (GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLSPRITEPARAMETERIVSGIXPROC) (GLenum pname, const GLint *params); -#endif - -#ifndef GL_SGIX_texture_multi_buffer -#define GL_SGIX_texture_multi_buffer 1 -#endif - -#ifndef GL_EXT_point_parameters -#define GL_EXT_point_parameters 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPointParameterfEXT (GLenum pname, GLfloat param); -GLAPI void APIENTRY glPointParameterfvEXT (GLenum pname, const GLfloat *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPOINTPARAMETERFEXTPROC) (GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLPOINTPARAMETERFVEXTPROC) (GLenum pname, const GLfloat *params); -#endif - -#ifndef GL_SGIS_point_parameters -#define GL_SGIS_point_parameters 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPointParameterfSGIS (GLenum pname, GLfloat param); -GLAPI void APIENTRY glPointParameterfvSGIS (GLenum pname, const GLfloat *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPOINTPARAMETERFSGISPROC) (GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLPOINTPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params); -#endif - -#ifndef GL_SGIX_instruments -#define GL_SGIX_instruments 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLint APIENTRY glGetInstrumentsSGIX (void); -GLAPI void APIENTRY glInstrumentsBufferSGIX (GLsizei size, GLint *buffer); -GLAPI GLint APIENTRY glPollInstrumentsSGIX (GLint *marker_p); -GLAPI void APIENTRY glReadInstrumentsSGIX (GLint marker); -GLAPI void APIENTRY glStartInstrumentsSGIX (void); -GLAPI void APIENTRY glStopInstrumentsSGIX (GLint marker); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLint (APIENTRYP PFNGLGETINSTRUMENTSSGIXPROC) (void); -typedef void (APIENTRYP PFNGLINSTRUMENTSBUFFERSGIXPROC) (GLsizei size, GLint *buffer); -typedef GLint (APIENTRYP PFNGLPOLLINSTRUMENTSSGIXPROC) (GLint *marker_p); -typedef void (APIENTRYP PFNGLREADINSTRUMENTSSGIXPROC) (GLint marker); -typedef void (APIENTRYP PFNGLSTARTINSTRUMENTSSGIXPROC) (void); -typedef void (APIENTRYP PFNGLSTOPINSTRUMENTSSGIXPROC) (GLint marker); -#endif - -#ifndef GL_SGIX_texture_scale_bias -#define GL_SGIX_texture_scale_bias 1 -#endif - -#ifndef GL_SGIX_framezoom -#define GL_SGIX_framezoom 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFrameZoomSGIX (GLint factor); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLFRAMEZOOMSGIXPROC) (GLint factor); -#endif - -#ifndef GL_SGIX_tag_sample_buffer -#define GL_SGIX_tag_sample_buffer 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTagSampleBufferSGIX (void); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTAGSAMPLEBUFFERSGIXPROC) (void); -#endif - -#ifndef GL_SGIX_polynomial_ffd -#define GL_SGIX_polynomial_ffd 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDeformationMap3dSGIX (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points); -GLAPI void APIENTRY glDeformationMap3fSGIX (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points); -GLAPI void APIENTRY glDeformSGIX (GLbitfield mask); -GLAPI void APIENTRY glLoadIdentityDeformationMapSGIX (GLbitfield mask); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDEFORMATIONMAP3DSGIXPROC) (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points); -typedef void (APIENTRYP PFNGLDEFORMATIONMAP3FSGIXPROC) (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points); -typedef void (APIENTRYP PFNGLDEFORMSGIXPROC) (GLbitfield mask); -typedef void (APIENTRYP PFNGLLOADIDENTITYDEFORMATIONMAPSGIXPROC) (GLbitfield mask); -#endif - -#ifndef GL_SGIX_reference_plane -#define GL_SGIX_reference_plane 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glReferencePlaneSGIX (const GLdouble *equation); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLREFERENCEPLANESGIXPROC) (const GLdouble *equation); -#endif - -#ifndef GL_SGIX_flush_raster -#define GL_SGIX_flush_raster 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFlushRasterSGIX (void); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLFLUSHRASTERSGIXPROC) (void); -#endif - -#ifndef GL_SGIX_depth_texture -#define GL_SGIX_depth_texture 1 -#endif - -#ifndef GL_SGIS_fog_function -#define GL_SGIS_fog_function 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFogFuncSGIS (GLsizei n, const GLfloat *points); -GLAPI void APIENTRY glGetFogFuncSGIS (GLfloat *points); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLFOGFUNCSGISPROC) (GLsizei n, const GLfloat *points); -typedef void (APIENTRYP PFNGLGETFOGFUNCSGISPROC) (GLfloat *points); -#endif - -#ifndef GL_SGIX_fog_offset -#define GL_SGIX_fog_offset 1 -#endif - -#ifndef GL_HP_image_transform -#define GL_HP_image_transform 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glImageTransformParameteriHP (GLenum target, GLenum pname, GLint param); -GLAPI void APIENTRY glImageTransformParameterfHP (GLenum target, GLenum pname, GLfloat param); -GLAPI void APIENTRY glImageTransformParameterivHP (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glImageTransformParameterfvHP (GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glGetImageTransformParameterivHP (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetImageTransformParameterfvHP (GLenum target, GLenum pname, GLfloat *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIHPPROC) (GLenum target, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFHPPROC) (GLenum target, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, GLfloat *params); -#endif - -#ifndef GL_HP_convolution_border_modes -#define GL_HP_convolution_border_modes 1 -#endif - -#ifndef GL_SGIX_texture_add_env -#define GL_SGIX_texture_add_env 1 -#endif - -#ifndef GL_EXT_color_subtable -#define GL_EXT_color_subtable 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColorSubTableEXT (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); -GLAPI void APIENTRY glCopyColorSubTableEXT (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); -#endif - -#ifndef GL_PGI_vertex_hints -#define GL_PGI_vertex_hints 1 -#endif - -#ifndef GL_PGI_misc_hints -#define GL_PGI_misc_hints 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glHintPGI (GLenum target, GLint mode); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLHINTPGIPROC) (GLenum target, GLint mode); -#endif - -#ifndef GL_EXT_paletted_texture -#define GL_EXT_paletted_texture 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColorTableEXT (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); -GLAPI void APIENTRY glGetColorTableEXT (GLenum target, GLenum format, GLenum type, GLvoid *data); -GLAPI void APIENTRY glGetColorTableParameterivEXT (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetColorTableParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); -typedef void (APIENTRYP PFNGLGETCOLORTABLEEXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *data); -typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); -#endif - -#ifndef GL_EXT_clip_volume_hint -#define GL_EXT_clip_volume_hint 1 -#endif - -#ifndef GL_SGIX_list_priority -#define GL_SGIX_list_priority 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetListParameterfvSGIX (GLuint list, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetListParameterivSGIX (GLuint list, GLenum pname, GLint *params); -GLAPI void APIENTRY glListParameterfSGIX (GLuint list, GLenum pname, GLfloat param); -GLAPI void APIENTRY glListParameterfvSGIX (GLuint list, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glListParameteriSGIX (GLuint list, GLenum pname, GLint param); -GLAPI void APIENTRY glListParameterivSGIX (GLuint list, GLenum pname, const GLint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGETLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLLISTPARAMETERFSGIXPROC) (GLuint list, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLLISTPARAMETERISGIXPROC) (GLuint list, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, const GLint *params); -#endif - -#ifndef GL_SGIX_ir_instrument1 -#define GL_SGIX_ir_instrument1 1 -#endif - -#ifndef GL_SGIX_calligraphic_fragment -#define GL_SGIX_calligraphic_fragment 1 -#endif - -#ifndef GL_SGIX_texture_lod_bias -#define GL_SGIX_texture_lod_bias 1 -#endif - -#ifndef GL_SGIX_shadow_ambient -#define GL_SGIX_shadow_ambient 1 -#endif - -#ifndef GL_EXT_index_texture -#define GL_EXT_index_texture 1 -#endif - -#ifndef GL_EXT_index_material -#define GL_EXT_index_material 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glIndexMaterialEXT (GLenum face, GLenum mode); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLINDEXMATERIALEXTPROC) (GLenum face, GLenum mode); -#endif - -#ifndef GL_EXT_index_func -#define GL_EXT_index_func 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glIndexFuncEXT (GLenum func, GLclampf ref); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLINDEXFUNCEXTPROC) (GLenum func, GLclampf ref); -#endif - -#ifndef GL_EXT_index_array_formats -#define GL_EXT_index_array_formats 1 -#endif - -#ifndef GL_EXT_compiled_vertex_array -#define GL_EXT_compiled_vertex_array 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glLockArraysEXT (GLint first, GLsizei count); -GLAPI void APIENTRY glUnlockArraysEXT (void); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLLOCKARRAYSEXTPROC) (GLint first, GLsizei count); -typedef void (APIENTRYP PFNGLUNLOCKARRAYSEXTPROC) (void); -#endif - -#ifndef GL_EXT_cull_vertex -#define GL_EXT_cull_vertex 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glCullParameterdvEXT (GLenum pname, GLdouble *params); -GLAPI void APIENTRY glCullParameterfvEXT (GLenum pname, GLfloat *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCULLPARAMETERDVEXTPROC) (GLenum pname, GLdouble *params); -typedef void (APIENTRYP PFNGLCULLPARAMETERFVEXTPROC) (GLenum pname, GLfloat *params); -#endif - -#ifndef GL_SGIX_ycrcb -#define GL_SGIX_ycrcb 1 -#endif - -#ifndef GL_SGIX_fragment_lighting -#define GL_SGIX_fragment_lighting 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFragmentColorMaterialSGIX (GLenum face, GLenum mode); -GLAPI void APIENTRY glFragmentLightfSGIX (GLenum light, GLenum pname, GLfloat param); -GLAPI void APIENTRY glFragmentLightfvSGIX (GLenum light, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glFragmentLightiSGIX (GLenum light, GLenum pname, GLint param); -GLAPI void APIENTRY glFragmentLightivSGIX (GLenum light, GLenum pname, const GLint *params); -GLAPI void APIENTRY glFragmentLightModelfSGIX (GLenum pname, GLfloat param); -GLAPI void APIENTRY glFragmentLightModelfvSGIX (GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glFragmentLightModeliSGIX (GLenum pname, GLint param); -GLAPI void APIENTRY glFragmentLightModelivSGIX (GLenum pname, const GLint *params); -GLAPI void APIENTRY glFragmentMaterialfSGIX (GLenum face, GLenum pname, GLfloat param); -GLAPI void APIENTRY glFragmentMaterialfvSGIX (GLenum face, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glFragmentMaterialiSGIX (GLenum face, GLenum pname, GLint param); -GLAPI void APIENTRY glFragmentMaterialivSGIX (GLenum face, GLenum pname, const GLint *params); -GLAPI void APIENTRY glGetFragmentLightfvSGIX (GLenum light, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetFragmentLightivSGIX (GLenum light, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetFragmentMaterialfvSGIX (GLenum face, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetFragmentMaterialivSGIX (GLenum face, GLenum pname, GLint *params); -GLAPI void APIENTRY glLightEnviSGIX (GLenum pname, GLint param); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLFRAGMENTCOLORMATERIALSGIXPROC) (GLenum face, GLenum mode); -typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFSGIXPROC) (GLenum light, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLFRAGMENTLIGHTISGIXPROC) (GLenum light, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFSGIXPROC) (GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFVSGIXPROC) (GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELISGIXPROC) (GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELIVSGIXPROC) (GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFSGIXPROC) (GLenum face, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLFRAGMENTMATERIALISGIXPROC) (GLenum face, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLLIGHTENVISGIXPROC) (GLenum pname, GLint param); -#endif - -#ifndef GL_IBM_rasterpos_clip -#define GL_IBM_rasterpos_clip 1 -#endif - -#ifndef GL_HP_texture_lighting -#define GL_HP_texture_lighting 1 -#endif - -#ifndef GL_EXT_draw_range_elements -#define GL_EXT_draw_range_elements 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawRangeElementsEXT (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); -#endif - -#ifndef GL_WIN_phong_shading -#define GL_WIN_phong_shading 1 -#endif - -#ifndef GL_WIN_specular_fog -#define GL_WIN_specular_fog 1 -#endif - -#ifndef GL_EXT_light_texture -#define GL_EXT_light_texture 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glApplyTextureEXT (GLenum mode); -GLAPI void APIENTRY glTextureLightEXT (GLenum pname); -GLAPI void APIENTRY glTextureMaterialEXT (GLenum face, GLenum mode); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLAPPLYTEXTUREEXTPROC) (GLenum mode); -typedef void (APIENTRYP PFNGLTEXTURELIGHTEXTPROC) (GLenum pname); -typedef void (APIENTRYP PFNGLTEXTUREMATERIALEXTPROC) (GLenum face, GLenum mode); -#endif - -#ifndef GL_SGIX_blend_alpha_minmax -#define GL_SGIX_blend_alpha_minmax 1 -#endif - -#ifndef GL_EXT_bgra -#define GL_EXT_bgra 1 -#endif - -#ifndef GL_SGIX_async -#define GL_SGIX_async 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glAsyncMarkerSGIX (GLuint marker); -GLAPI GLint APIENTRY glFinishAsyncSGIX (GLuint *markerp); -GLAPI GLint APIENTRY glPollAsyncSGIX (GLuint *markerp); -GLAPI GLuint APIENTRY glGenAsyncMarkersSGIX (GLsizei range); -GLAPI void APIENTRY glDeleteAsyncMarkersSGIX (GLuint marker, GLsizei range); -GLAPI GLboolean APIENTRY glIsAsyncMarkerSGIX (GLuint marker); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLASYNCMARKERSGIXPROC) (GLuint marker); -typedef GLint (APIENTRYP PFNGLFINISHASYNCSGIXPROC) (GLuint *markerp); -typedef GLint (APIENTRYP PFNGLPOLLASYNCSGIXPROC) (GLuint *markerp); -typedef GLuint (APIENTRYP PFNGLGENASYNCMARKERSSGIXPROC) (GLsizei range); -typedef void (APIENTRYP PFNGLDELETEASYNCMARKERSSGIXPROC) (GLuint marker, GLsizei range); -typedef GLboolean (APIENTRYP PFNGLISASYNCMARKERSGIXPROC) (GLuint marker); -#endif - -#ifndef GL_SGIX_async_pixel -#define GL_SGIX_async_pixel 1 -#endif - -#ifndef GL_SGIX_async_histogram -#define GL_SGIX_async_histogram 1 -#endif - -#ifndef GL_INTEL_parallel_arrays -#define GL_INTEL_parallel_arrays 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexPointervINTEL (GLint size, GLenum type, const GLvoid* *pointer); -GLAPI void APIENTRY glNormalPointervINTEL (GLenum type, const GLvoid* *pointer); -GLAPI void APIENTRY glColorPointervINTEL (GLint size, GLenum type, const GLvoid* *pointer); -GLAPI void APIENTRY glTexCoordPointervINTEL (GLint size, GLenum type, const GLvoid* *pointer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVERTEXPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer); -typedef void (APIENTRYP PFNGLNORMALPOINTERVINTELPROC) (GLenum type, const GLvoid* *pointer); -typedef void (APIENTRYP PFNGLCOLORPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer); -typedef void (APIENTRYP PFNGLTEXCOORDPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer); -#endif - -#ifndef GL_HP_occlusion_test -#define GL_HP_occlusion_test 1 -#endif - -#ifndef GL_EXT_pixel_transform -#define GL_EXT_pixel_transform 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPixelTransformParameteriEXT (GLenum target, GLenum pname, GLint param); -GLAPI void APIENTRY glPixelTransformParameterfEXT (GLenum target, GLenum pname, GLfloat param); -GLAPI void APIENTRY glPixelTransformParameterivEXT (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glPixelTransformParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params); -#endif - -#ifndef GL_EXT_pixel_transform_color_table -#define GL_EXT_pixel_transform_color_table 1 -#endif - -#ifndef GL_EXT_shared_texture_palette -#define GL_EXT_shared_texture_palette 1 -#endif - -#ifndef GL_EXT_separate_specular_color -#define GL_EXT_separate_specular_color 1 -#endif - -#ifndef GL_EXT_secondary_color -#define GL_EXT_secondary_color 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glSecondaryColor3bEXT (GLbyte red, GLbyte green, GLbyte blue); -GLAPI void APIENTRY glSecondaryColor3bvEXT (const GLbyte *v); -GLAPI void APIENTRY glSecondaryColor3dEXT (GLdouble red, GLdouble green, GLdouble blue); -GLAPI void APIENTRY glSecondaryColor3dvEXT (const GLdouble *v); -GLAPI void APIENTRY glSecondaryColor3fEXT (GLfloat red, GLfloat green, GLfloat blue); -GLAPI void APIENTRY glSecondaryColor3fvEXT (const GLfloat *v); -GLAPI void APIENTRY glSecondaryColor3iEXT (GLint red, GLint green, GLint blue); -GLAPI void APIENTRY glSecondaryColor3ivEXT (const GLint *v); -GLAPI void APIENTRY glSecondaryColor3sEXT (GLshort red, GLshort green, GLshort blue); -GLAPI void APIENTRY glSecondaryColor3svEXT (const GLshort *v); -GLAPI void APIENTRY glSecondaryColor3ubEXT (GLubyte red, GLubyte green, GLubyte blue); -GLAPI void APIENTRY glSecondaryColor3ubvEXT (const GLubyte *v); -GLAPI void APIENTRY glSecondaryColor3uiEXT (GLuint red, GLuint green, GLuint blue); -GLAPI void APIENTRY glSecondaryColor3uivEXT (const GLuint *v); -GLAPI void APIENTRY glSecondaryColor3usEXT (GLushort red, GLushort green, GLushort blue); -GLAPI void APIENTRY glSecondaryColor3usvEXT (const GLushort *v); -GLAPI void APIENTRY glSecondaryColorPointerEXT (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BEXTPROC) (GLbyte red, GLbyte green, GLbyte blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVEXTPROC) (const GLbyte *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DEXTPROC) (GLdouble red, GLdouble green, GLdouble blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVEXTPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FEXTPROC) (GLfloat red, GLfloat green, GLfloat blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVEXTPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IEXTPROC) (GLint red, GLint green, GLint blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVEXTPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SEXTPROC) (GLshort red, GLshort green, GLshort blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVEXTPROC) (const GLshort *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBEXTPROC) (GLubyte red, GLubyte green, GLubyte blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVEXTPROC) (const GLubyte *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIEXTPROC) (GLuint red, GLuint green, GLuint blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVEXTPROC) (const GLuint *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USEXTPROC) (GLushort red, GLushort green, GLushort blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVEXTPROC) (const GLushort *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -#endif - -#ifndef GL_EXT_texture_perturb_normal -#define GL_EXT_texture_perturb_normal 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTextureNormalEXT (GLenum mode); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTEXTURENORMALEXTPROC) (GLenum mode); -#endif - -#ifndef GL_EXT_multi_draw_arrays -#define GL_EXT_multi_draw_arrays 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMultiDrawArraysEXT (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); -GLAPI void APIENTRY glMultiDrawElementsEXT (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); -#endif - -#ifndef GL_EXT_fog_coord -#define GL_EXT_fog_coord 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFogCoordfEXT (GLfloat coord); -GLAPI void APIENTRY glFogCoordfvEXT (const GLfloat *coord); -GLAPI void APIENTRY glFogCoorddEXT (GLdouble coord); -GLAPI void APIENTRY glFogCoorddvEXT (const GLdouble *coord); -GLAPI void APIENTRY glFogCoordPointerEXT (GLenum type, GLsizei stride, const GLvoid *pointer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLFOGCOORDFEXTPROC) (GLfloat coord); -typedef void (APIENTRYP PFNGLFOGCOORDFVEXTPROC) (const GLfloat *coord); -typedef void (APIENTRYP PFNGLFOGCOORDDEXTPROC) (GLdouble coord); -typedef void (APIENTRYP PFNGLFOGCOORDDVEXTPROC) (const GLdouble *coord); -typedef void (APIENTRYP PFNGLFOGCOORDPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); -#endif - -#ifndef GL_REND_screen_coordinates -#define GL_REND_screen_coordinates 1 -#endif - -#ifndef GL_EXT_coordinate_frame -#define GL_EXT_coordinate_frame 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTangent3bEXT (GLbyte tx, GLbyte ty, GLbyte tz); -GLAPI void APIENTRY glTangent3bvEXT (const GLbyte *v); -GLAPI void APIENTRY glTangent3dEXT (GLdouble tx, GLdouble ty, GLdouble tz); -GLAPI void APIENTRY glTangent3dvEXT (const GLdouble *v); -GLAPI void APIENTRY glTangent3fEXT (GLfloat tx, GLfloat ty, GLfloat tz); -GLAPI void APIENTRY glTangent3fvEXT (const GLfloat *v); -GLAPI void APIENTRY glTangent3iEXT (GLint tx, GLint ty, GLint tz); -GLAPI void APIENTRY glTangent3ivEXT (const GLint *v); -GLAPI void APIENTRY glTangent3sEXT (GLshort tx, GLshort ty, GLshort tz); -GLAPI void APIENTRY glTangent3svEXT (const GLshort *v); -GLAPI void APIENTRY glBinormal3bEXT (GLbyte bx, GLbyte by, GLbyte bz); -GLAPI void APIENTRY glBinormal3bvEXT (const GLbyte *v); -GLAPI void APIENTRY glBinormal3dEXT (GLdouble bx, GLdouble by, GLdouble bz); -GLAPI void APIENTRY glBinormal3dvEXT (const GLdouble *v); -GLAPI void APIENTRY glBinormal3fEXT (GLfloat bx, GLfloat by, GLfloat bz); -GLAPI void APIENTRY glBinormal3fvEXT (const GLfloat *v); -GLAPI void APIENTRY glBinormal3iEXT (GLint bx, GLint by, GLint bz); -GLAPI void APIENTRY glBinormal3ivEXT (const GLint *v); -GLAPI void APIENTRY glBinormal3sEXT (GLshort bx, GLshort by, GLshort bz); -GLAPI void APIENTRY glBinormal3svEXT (const GLshort *v); -GLAPI void APIENTRY glTangentPointerEXT (GLenum type, GLsizei stride, const GLvoid *pointer); -GLAPI void APIENTRY glBinormalPointerEXT (GLenum type, GLsizei stride, const GLvoid *pointer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTANGENT3BEXTPROC) (GLbyte tx, GLbyte ty, GLbyte tz); -typedef void (APIENTRYP PFNGLTANGENT3BVEXTPROC) (const GLbyte *v); -typedef void (APIENTRYP PFNGLTANGENT3DEXTPROC) (GLdouble tx, GLdouble ty, GLdouble tz); -typedef void (APIENTRYP PFNGLTANGENT3DVEXTPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLTANGENT3FEXTPROC) (GLfloat tx, GLfloat ty, GLfloat tz); -typedef void (APIENTRYP PFNGLTANGENT3FVEXTPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLTANGENT3IEXTPROC) (GLint tx, GLint ty, GLint tz); -typedef void (APIENTRYP PFNGLTANGENT3IVEXTPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLTANGENT3SEXTPROC) (GLshort tx, GLshort ty, GLshort tz); -typedef void (APIENTRYP PFNGLTANGENT3SVEXTPROC) (const GLshort *v); -typedef void (APIENTRYP PFNGLBINORMAL3BEXTPROC) (GLbyte bx, GLbyte by, GLbyte bz); -typedef void (APIENTRYP PFNGLBINORMAL3BVEXTPROC) (const GLbyte *v); -typedef void (APIENTRYP PFNGLBINORMAL3DEXTPROC) (GLdouble bx, GLdouble by, GLdouble bz); -typedef void (APIENTRYP PFNGLBINORMAL3DVEXTPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLBINORMAL3FEXTPROC) (GLfloat bx, GLfloat by, GLfloat bz); -typedef void (APIENTRYP PFNGLBINORMAL3FVEXTPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLBINORMAL3IEXTPROC) (GLint bx, GLint by, GLint bz); -typedef void (APIENTRYP PFNGLBINORMAL3IVEXTPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLBINORMAL3SEXTPROC) (GLshort bx, GLshort by, GLshort bz); -typedef void (APIENTRYP PFNGLBINORMAL3SVEXTPROC) (const GLshort *v); -typedef void (APIENTRYP PFNGLTANGENTPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLBINORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); -#endif - -#ifndef GL_EXT_texture_env_combine -#define GL_EXT_texture_env_combine 1 -#endif - -#ifndef GL_APPLE_specular_vector -#define GL_APPLE_specular_vector 1 -#endif - -#ifndef GL_APPLE_transform_hint -#define GL_APPLE_transform_hint 1 -#endif - -#ifndef GL_SGIX_fog_scale -#define GL_SGIX_fog_scale 1 -#endif - -#ifndef GL_SUNX_constant_data -#define GL_SUNX_constant_data 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFinishTextureSUNX (void); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLFINISHTEXTURESUNXPROC) (void); -#endif - -#ifndef GL_SUN_global_alpha -#define GL_SUN_global_alpha 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGlobalAlphaFactorbSUN (GLbyte factor); -GLAPI void APIENTRY glGlobalAlphaFactorsSUN (GLshort factor); -GLAPI void APIENTRY glGlobalAlphaFactoriSUN (GLint factor); -GLAPI void APIENTRY glGlobalAlphaFactorfSUN (GLfloat factor); -GLAPI void APIENTRY glGlobalAlphaFactordSUN (GLdouble factor); -GLAPI void APIENTRY glGlobalAlphaFactorubSUN (GLubyte factor); -GLAPI void APIENTRY glGlobalAlphaFactorusSUN (GLushort factor); -GLAPI void APIENTRY glGlobalAlphaFactoruiSUN (GLuint factor); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORBSUNPROC) (GLbyte factor); -typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORSSUNPROC) (GLshort factor); -typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORISUNPROC) (GLint factor); -typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORFSUNPROC) (GLfloat factor); -typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORDSUNPROC) (GLdouble factor); -typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUBSUNPROC) (GLubyte factor); -typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUSSUNPROC) (GLushort factor); -typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUISUNPROC) (GLuint factor); -#endif - -#ifndef GL_SUN_triangle_list -#define GL_SUN_triangle_list 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glReplacementCodeuiSUN (GLuint code); -GLAPI void APIENTRY glReplacementCodeusSUN (GLushort code); -GLAPI void APIENTRY glReplacementCodeubSUN (GLubyte code); -GLAPI void APIENTRY glReplacementCodeuivSUN (const GLuint *code); -GLAPI void APIENTRY glReplacementCodeusvSUN (const GLushort *code); -GLAPI void APIENTRY glReplacementCodeubvSUN (const GLubyte *code); -GLAPI void APIENTRY glReplacementCodePointerSUN (GLenum type, GLsizei stride, const GLvoid* *pointer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUISUNPROC) (GLuint code); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSSUNPROC) (GLushort code); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBSUNPROC) (GLubyte code); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVSUNPROC) (const GLuint *code); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSVSUNPROC) (const GLushort *code); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBVSUNPROC) (const GLubyte *code); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEPOINTERSUNPROC) (GLenum type, GLsizei stride, const GLvoid* *pointer); -#endif - -#ifndef GL_SUN_vertex -#define GL_SUN_vertex 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColor4ubVertex2fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y); -GLAPI void APIENTRY glColor4ubVertex2fvSUN (const GLubyte *c, const GLfloat *v); -GLAPI void APIENTRY glColor4ubVertex3fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glColor4ubVertex3fvSUN (const GLubyte *c, const GLfloat *v); -GLAPI void APIENTRY glColor3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glColor3fVertex3fvSUN (const GLfloat *c, const GLfloat *v); -GLAPI void APIENTRY glNormal3fVertex3fSUN (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glNormal3fVertex3fvSUN (const GLfloat *n, const GLfloat *v); -GLAPI void APIENTRY glColor4fNormal3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glColor4fNormal3fVertex3fvSUN (const GLfloat *c, const GLfloat *n, const GLfloat *v); -GLAPI void APIENTRY glTexCoord2fVertex3fSUN (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glTexCoord2fVertex3fvSUN (const GLfloat *tc, const GLfloat *v); -GLAPI void APIENTRY glTexCoord4fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glTexCoord4fVertex4fvSUN (const GLfloat *tc, const GLfloat *v); -GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fSUN (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fvSUN (const GLfloat *tc, const GLubyte *c, const GLfloat *v); -GLAPI void APIENTRY glTexCoord2fColor3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glTexCoord2fColor3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *v); -GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *n, const GLfloat *v); -GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); -GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); -GLAPI void APIENTRY glReplacementCodeuiVertex3fSUN (GLuint rc, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glReplacementCodeuiVertex3fvSUN (const GLuint *rc, const GLfloat *v); -GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fSUN (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fvSUN (const GLuint *rc, const GLubyte *c, const GLfloat *v); -GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *v); -GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fSUN (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *n, const GLfloat *v); -GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v); -GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *v); -GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v); -GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y); -typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FVSUNPROC) (const GLubyte *c, const GLfloat *v); -typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FVSUNPROC) (const GLubyte *c, const GLfloat *v); -typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *v); -typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FSUNPROC) (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *n, const GLfloat *v); -typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *n, const GLfloat *v); -typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *v); -typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *v); -typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FVSUNPROC) (const GLfloat *tc, const GLubyte *c, const GLfloat *v); -typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *v); -typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *n, const GLfloat *v); -typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); -typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FSUNPROC) (GLuint rc, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *v); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FSUNPROC) (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FVSUNPROC) (const GLuint *rc, const GLubyte *c, const GLfloat *v); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *v); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *n, const GLfloat *v); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *v); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); -#endif - -#ifndef GL_EXT_blend_func_separate -#define GL_EXT_blend_func_separate 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendFuncSeparateEXT (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEEXTPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); -#endif - -#ifndef GL_INGR_blend_func_separate -#define GL_INGR_blend_func_separate 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendFuncSeparateINGR (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINGRPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); -#endif - -#ifndef GL_INGR_color_clamp -#define GL_INGR_color_clamp 1 -#endif - -#ifndef GL_INGR_interlace_read -#define GL_INGR_interlace_read 1 -#endif - -#ifndef GL_EXT_stencil_wrap -#define GL_EXT_stencil_wrap 1 -#endif - -#ifndef GL_EXT_422_pixels -#define GL_EXT_422_pixels 1 -#endif - -#ifndef GL_NV_texgen_reflection -#define GL_NV_texgen_reflection 1 -#endif - -#ifndef GL_SUN_convolution_border_modes -#define GL_SUN_convolution_border_modes 1 -#endif - -#ifndef GL_EXT_texture_env_add -#define GL_EXT_texture_env_add 1 -#endif - -#ifndef GL_EXT_texture_lod_bias -#define GL_EXT_texture_lod_bias 1 -#endif - -#ifndef GL_EXT_texture_filter_anisotropic -#define GL_EXT_texture_filter_anisotropic 1 -#endif - -#ifndef GL_EXT_vertex_weighting -#define GL_EXT_vertex_weighting 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexWeightfEXT (GLfloat weight); -GLAPI void APIENTRY glVertexWeightfvEXT (const GLfloat *weight); -GLAPI void APIENTRY glVertexWeightPointerEXT (GLsizei size, GLenum type, GLsizei stride, const GLvoid *pointer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVERTEXWEIGHTFEXTPROC) (GLfloat weight); -typedef void (APIENTRYP PFNGLVERTEXWEIGHTFVEXTPROC) (const GLfloat *weight); -typedef void (APIENTRYP PFNGLVERTEXWEIGHTPOINTEREXTPROC) (GLsizei size, GLenum type, GLsizei stride, const GLvoid *pointer); -#endif - -#ifndef GL_NV_light_max_exponent -#define GL_NV_light_max_exponent 1 -#endif - -#ifndef GL_NV_vertex_array_range -#define GL_NV_vertex_array_range 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFlushVertexArrayRangeNV (void); -GLAPI void APIENTRY glVertexArrayRangeNV (GLsizei length, const GLvoid *pointer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGENVPROC) (void); -typedef void (APIENTRYP PFNGLVERTEXARRAYRANGENVPROC) (GLsizei length, const GLvoid *pointer); -#endif - -#ifndef GL_NV_register_combiners -#define GL_NV_register_combiners 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glCombinerParameterfvNV (GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glCombinerParameterfNV (GLenum pname, GLfloat param); -GLAPI void APIENTRY glCombinerParameterivNV (GLenum pname, const GLint *params); -GLAPI void APIENTRY glCombinerParameteriNV (GLenum pname, GLint param); -GLAPI void APIENTRY glCombinerInputNV (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); -GLAPI void APIENTRY glCombinerOutputNV (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum); -GLAPI void APIENTRY glFinalCombinerInputNV (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); -GLAPI void APIENTRY glGetCombinerInputParameterfvNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetCombinerInputParameterivNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetCombinerOutputParameterfvNV (GLenum stage, GLenum portion, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetCombinerOutputParameterivNV (GLenum stage, GLenum portion, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetFinalCombinerInputParameterfvNV (GLenum variable, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetFinalCombinerInputParameterivNV (GLenum variable, GLenum pname, GLint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFVNVPROC) (GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFNVPROC) (GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLCOMBINERPARAMETERIVNVPROC) (GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLCOMBINERPARAMETERINVPROC) (GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLCOMBINERINPUTNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); -typedef void (APIENTRYP PFNGLCOMBINEROUTPUTNVPROC) (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum); -typedef void (APIENTRYP PFNGLFINALCOMBINERINPUTNVPROC) (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); -typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC) (GLenum variable, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC) (GLenum variable, GLenum pname, GLint *params); -#endif - -#ifndef GL_NV_fog_distance -#define GL_NV_fog_distance 1 -#endif - -#ifndef GL_NV_texgen_emboss -#define GL_NV_texgen_emboss 1 -#endif - -#ifndef GL_NV_blend_square -#define GL_NV_blend_square 1 -#endif - -#ifndef GL_NV_texture_env_combine4 -#define GL_NV_texture_env_combine4 1 -#endif - -#ifndef GL_MESA_resize_buffers -#define GL_MESA_resize_buffers 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glResizeBuffersMESA (void); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLRESIZEBUFFERSMESAPROC) (void); -#endif - -#ifndef GL_MESA_window_pos -#define GL_MESA_window_pos 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glWindowPos2dMESA (GLdouble x, GLdouble y); -GLAPI void APIENTRY glWindowPos2dvMESA (const GLdouble *v); -GLAPI void APIENTRY glWindowPos2fMESA (GLfloat x, GLfloat y); -GLAPI void APIENTRY glWindowPos2fvMESA (const GLfloat *v); -GLAPI void APIENTRY glWindowPos2iMESA (GLint x, GLint y); -GLAPI void APIENTRY glWindowPos2ivMESA (const GLint *v); -GLAPI void APIENTRY glWindowPos2sMESA (GLshort x, GLshort y); -GLAPI void APIENTRY glWindowPos2svMESA (const GLshort *v); -GLAPI void APIENTRY glWindowPos3dMESA (GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glWindowPos3dvMESA (const GLdouble *v); -GLAPI void APIENTRY glWindowPos3fMESA (GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glWindowPos3fvMESA (const GLfloat *v); -GLAPI void APIENTRY glWindowPos3iMESA (GLint x, GLint y, GLint z); -GLAPI void APIENTRY glWindowPos3ivMESA (const GLint *v); -GLAPI void APIENTRY glWindowPos3sMESA (GLshort x, GLshort y, GLshort z); -GLAPI void APIENTRY glWindowPos3svMESA (const GLshort *v); -GLAPI void APIENTRY glWindowPos4dMESA (GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glWindowPos4dvMESA (const GLdouble *v); -GLAPI void APIENTRY glWindowPos4fMESA (GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glWindowPos4fvMESA (const GLfloat *v); -GLAPI void APIENTRY glWindowPos4iMESA (GLint x, GLint y, GLint z, GLint w); -GLAPI void APIENTRY glWindowPos4ivMESA (const GLint *v); -GLAPI void APIENTRY glWindowPos4sMESA (GLshort x, GLshort y, GLshort z, GLshort w); -GLAPI void APIENTRY glWindowPos4svMESA (const GLshort *v); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLWINDOWPOS2DMESAPROC) (GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLWINDOWPOS2DVMESAPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLWINDOWPOS2FMESAPROC) (GLfloat x, GLfloat y); -typedef void (APIENTRYP PFNGLWINDOWPOS2FVMESAPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLWINDOWPOS2IMESAPROC) (GLint x, GLint y); -typedef void (APIENTRYP PFNGLWINDOWPOS2IVMESAPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLWINDOWPOS2SMESAPROC) (GLshort x, GLshort y); -typedef void (APIENTRYP PFNGLWINDOWPOS2SVMESAPROC) (const GLshort *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3DMESAPROC) (GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLWINDOWPOS3DVMESAPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3FMESAPROC) (GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLWINDOWPOS3FVMESAPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3IMESAPROC) (GLint x, GLint y, GLint z); -typedef void (APIENTRYP PFNGLWINDOWPOS3IVMESAPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3SMESAPROC) (GLshort x, GLshort y, GLshort z); -typedef void (APIENTRYP PFNGLWINDOWPOS3SVMESAPROC) (const GLshort *v); -typedef void (APIENTRYP PFNGLWINDOWPOS4DMESAPROC) (GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLWINDOWPOS4DVMESAPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLWINDOWPOS4FMESAPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLWINDOWPOS4FVMESAPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLWINDOWPOS4IMESAPROC) (GLint x, GLint y, GLint z, GLint w); -typedef void (APIENTRYP PFNGLWINDOWPOS4IVMESAPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLWINDOWPOS4SMESAPROC) (GLshort x, GLshort y, GLshort z, GLshort w); -typedef void (APIENTRYP PFNGLWINDOWPOS4SVMESAPROC) (const GLshort *v); -#endif - -#ifndef GL_IBM_cull_vertex -#define GL_IBM_cull_vertex 1 -#endif - -#ifndef GL_IBM_multimode_draw_arrays -#define GL_IBM_multimode_draw_arrays 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMultiModeDrawArraysIBM (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride); -GLAPI void APIENTRY glMultiModeDrawElementsIBM (const GLenum *mode, const GLsizei *count, GLenum type, const GLvoid* const *indices, GLsizei primcount, GLint modestride); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLMULTIMODEDRAWARRAYSIBMPROC) (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride); -typedef void (APIENTRYP PFNGLMULTIMODEDRAWELEMENTSIBMPROC) (const GLenum *mode, const GLsizei *count, GLenum type, const GLvoid* const *indices, GLsizei primcount, GLint modestride); -#endif - -#ifndef GL_IBM_vertex_array_lists -#define GL_IBM_vertex_array_lists 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColorPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); -GLAPI void APIENTRY glSecondaryColorPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); -GLAPI void APIENTRY glEdgeFlagPointerListIBM (GLint stride, const GLboolean* *pointer, GLint ptrstride); -GLAPI void APIENTRY glFogCoordPointerListIBM (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); -GLAPI void APIENTRY glIndexPointerListIBM (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); -GLAPI void APIENTRY glNormalPointerListIBM (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); -GLAPI void APIENTRY glTexCoordPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); -GLAPI void APIENTRY glVertexPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); -typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); -typedef void (APIENTRYP PFNGLEDGEFLAGPOINTERLISTIBMPROC) (GLint stride, const GLboolean* *pointer, GLint ptrstride); -typedef void (APIENTRYP PFNGLFOGCOORDPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); -typedef void (APIENTRYP PFNGLINDEXPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); -typedef void (APIENTRYP PFNGLNORMALPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); -typedef void (APIENTRYP PFNGLTEXCOORDPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); -typedef void (APIENTRYP PFNGLVERTEXPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); -#endif - -#ifndef GL_SGIX_subsample -#define GL_SGIX_subsample 1 -#endif - -#ifndef GL_SGIX_ycrcba -#define GL_SGIX_ycrcba 1 -#endif - -#ifndef GL_SGIX_ycrcb_subsample -#define GL_SGIX_ycrcb_subsample 1 -#endif - -#ifndef GL_SGIX_depth_pass_instrument -#define GL_SGIX_depth_pass_instrument 1 -#endif - -#ifndef GL_3DFX_texture_compression_FXT1 -#define GL_3DFX_texture_compression_FXT1 1 -#endif - -#ifndef GL_3DFX_multisample -#define GL_3DFX_multisample 1 -#endif - -#ifndef GL_3DFX_tbuffer -#define GL_3DFX_tbuffer 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTbufferMask3DFX (GLuint mask); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTBUFFERMASK3DFXPROC) (GLuint mask); -#endif - -#ifndef GL_EXT_multisample -#define GL_EXT_multisample 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glSampleMaskEXT (GLclampf value, GLboolean invert); -GLAPI void APIENTRY glSamplePatternEXT (GLenum pattern); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLSAMPLEMASKEXTPROC) (GLclampf value, GLboolean invert); -typedef void (APIENTRYP PFNGLSAMPLEPATTERNEXTPROC) (GLenum pattern); -#endif - -#ifndef GL_SGIX_vertex_preclip -#define GL_SGIX_vertex_preclip 1 -#endif - -#ifndef GL_SGIX_convolution_accuracy -#define GL_SGIX_convolution_accuracy 1 -#endif - -#ifndef GL_SGIX_resample -#define GL_SGIX_resample 1 -#endif - -#ifndef GL_SGIS_point_line_texgen -#define GL_SGIS_point_line_texgen 1 -#endif - -#ifndef GL_SGIS_texture_color_mask -#define GL_SGIS_texture_color_mask 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTextureColorMaskSGIS (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTEXTURECOLORMASKSGISPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); -#endif - -#ifndef GL_SGIX_igloo_interface -#define GL_SGIX_igloo_interface 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glIglooInterfaceSGIX (GLenum pname, const GLvoid *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLIGLOOINTERFACESGIXPROC) (GLenum pname, const GLvoid *params); -#endif - -#ifndef GL_EXT_texture_env_dot3 -#define GL_EXT_texture_env_dot3 1 -#endif - -#ifndef GL_ATI_texture_mirror_once -#define GL_ATI_texture_mirror_once 1 -#endif - -#ifndef GL_NV_fence -#define GL_NV_fence 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDeleteFencesNV (GLsizei n, const GLuint *fences); -GLAPI void APIENTRY glGenFencesNV (GLsizei n, GLuint *fences); -GLAPI GLboolean APIENTRY glIsFenceNV (GLuint fence); -GLAPI GLboolean APIENTRY glTestFenceNV (GLuint fence); -GLAPI void APIENTRY glGetFenceivNV (GLuint fence, GLenum pname, GLint *params); -GLAPI void APIENTRY glFinishFenceNV (GLuint fence); -GLAPI void APIENTRY glSetFenceNV (GLuint fence, GLenum condition); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences); -typedef void (APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences); -typedef GLboolean (APIENTRYP PFNGLISFENCENVPROC) (GLuint fence); -typedef GLboolean (APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence); -typedef void (APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence); -typedef void (APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition); -#endif - -#ifndef GL_NV_evaluators -#define GL_NV_evaluators 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const GLvoid *points); -GLAPI void APIENTRY glMapParameterivNV (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glMapParameterfvNV (GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glGetMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, GLvoid *points); -GLAPI void APIENTRY glGetMapParameterivNV (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetMapParameterfvNV (GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetMapAttribParameterivNV (GLenum target, GLuint index, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetMapAttribParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glEvalMapsNV (GLenum target, GLenum mode); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const GLvoid *points); -typedef void (APIENTRYP PFNGLMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLGETMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, GLvoid *points); -typedef void (APIENTRYP PFNGLGETMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERIVNVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLEVALMAPSNVPROC) (GLenum target, GLenum mode); -#endif - -#ifndef GL_NV_packed_depth_stencil -#define GL_NV_packed_depth_stencil 1 -#endif - -#ifndef GL_NV_register_combiners2 -#define GL_NV_register_combiners2 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glCombinerStageParameterfvNV (GLenum stage, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glGetCombinerStageParameterfvNV (GLenum stage, GLenum pname, GLfloat *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, GLfloat *params); -#endif - -#ifndef GL_NV_texture_compression_vtc -#define GL_NV_texture_compression_vtc 1 -#endif - -#ifndef GL_NV_texture_rectangle -#define GL_NV_texture_rectangle 1 -#endif - -#ifndef GL_NV_texture_shader -#define GL_NV_texture_shader 1 -#endif - -#ifndef GL_NV_texture_shader2 -#define GL_NV_texture_shader2 1 -#endif - -#ifndef GL_NV_vertex_array_range2 -#define GL_NV_vertex_array_range2 1 -#endif - -#ifndef GL_NV_vertex_program -#define GL_NV_vertex_program 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLboolean APIENTRY glAreProgramsResidentNV (GLsizei n, const GLuint *programs, GLboolean *residences); -GLAPI void APIENTRY glBindProgramNV (GLenum target, GLuint id); -GLAPI void APIENTRY glDeleteProgramsNV (GLsizei n, const GLuint *programs); -GLAPI void APIENTRY glExecuteProgramNV (GLenum target, GLuint id, const GLfloat *params); -GLAPI void APIENTRY glGenProgramsNV (GLsizei n, GLuint *programs); -GLAPI void APIENTRY glGetProgramParameterdvNV (GLenum target, GLuint index, GLenum pname, GLdouble *params); -GLAPI void APIENTRY glGetProgramParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetProgramivNV (GLuint id, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetProgramStringNV (GLuint id, GLenum pname, GLubyte *program); -GLAPI void APIENTRY glGetTrackMatrixivNV (GLenum target, GLuint address, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVertexAttribdvNV (GLuint index, GLenum pname, GLdouble *params); -GLAPI void APIENTRY glGetVertexAttribfvNV (GLuint index, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetVertexAttribivNV (GLuint index, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVertexAttribPointervNV (GLuint index, GLenum pname, GLvoid* *pointer); -GLAPI GLboolean APIENTRY glIsProgramNV (GLuint id); -GLAPI void APIENTRY glLoadProgramNV (GLenum target, GLuint id, GLsizei len, const GLubyte *program); -GLAPI void APIENTRY glProgramParameter4dNV (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glProgramParameter4dvNV (GLenum target, GLuint index, const GLdouble *v); -GLAPI void APIENTRY glProgramParameter4fNV (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glProgramParameter4fvNV (GLenum target, GLuint index, const GLfloat *v); -GLAPI void APIENTRY glProgramParameters4dvNV (GLenum target, GLuint index, GLsizei count, const GLdouble *v); -GLAPI void APIENTRY glProgramParameters4fvNV (GLenum target, GLuint index, GLsizei count, const GLfloat *v); -GLAPI void APIENTRY glRequestResidentProgramsNV (GLsizei n, const GLuint *programs); -GLAPI void APIENTRY glTrackMatrixNV (GLenum target, GLuint address, GLenum matrix, GLenum transform); -GLAPI void APIENTRY glVertexAttribPointerNV (GLuint index, GLint fsize, GLenum type, GLsizei stride, const GLvoid *pointer); -GLAPI void APIENTRY glVertexAttrib1dNV (GLuint index, GLdouble x); -GLAPI void APIENTRY glVertexAttrib1dvNV (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib1fNV (GLuint index, GLfloat x); -GLAPI void APIENTRY glVertexAttrib1fvNV (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib1sNV (GLuint index, GLshort x); -GLAPI void APIENTRY glVertexAttrib1svNV (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib2dNV (GLuint index, GLdouble x, GLdouble y); -GLAPI void APIENTRY glVertexAttrib2dvNV (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib2fNV (GLuint index, GLfloat x, GLfloat y); -GLAPI void APIENTRY glVertexAttrib2fvNV (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib2sNV (GLuint index, GLshort x, GLshort y); -GLAPI void APIENTRY glVertexAttrib2svNV (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib3dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glVertexAttrib3dvNV (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib3fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glVertexAttrib3fvNV (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib3sNV (GLuint index, GLshort x, GLshort y, GLshort z); -GLAPI void APIENTRY glVertexAttrib3svNV (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib4dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glVertexAttrib4dvNV (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib4fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glVertexAttrib4fvNV (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib4sNV (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); -GLAPI void APIENTRY glVertexAttrib4svNV (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib4ubNV (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); -GLAPI void APIENTRY glVertexAttrib4ubvNV (GLuint index, const GLubyte *v); -GLAPI void APIENTRY glVertexAttribs1dvNV (GLuint index, GLsizei count, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribs1fvNV (GLuint index, GLsizei count, const GLfloat *v); -GLAPI void APIENTRY glVertexAttribs1svNV (GLuint index, GLsizei count, const GLshort *v); -GLAPI void APIENTRY glVertexAttribs2dvNV (GLuint index, GLsizei count, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribs2fvNV (GLuint index, GLsizei count, const GLfloat *v); -GLAPI void APIENTRY glVertexAttribs2svNV (GLuint index, GLsizei count, const GLshort *v); -GLAPI void APIENTRY glVertexAttribs3dvNV (GLuint index, GLsizei count, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribs3fvNV (GLuint index, GLsizei count, const GLfloat *v); -GLAPI void APIENTRY glVertexAttribs3svNV (GLuint index, GLsizei count, const GLshort *v); -GLAPI void APIENTRY glVertexAttribs4dvNV (GLuint index, GLsizei count, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribs4fvNV (GLuint index, GLsizei count, const GLfloat *v); -GLAPI void APIENTRY glVertexAttribs4svNV (GLuint index, GLsizei count, const GLshort *v); -GLAPI void APIENTRY glVertexAttribs4ubvNV (GLuint index, GLsizei count, const GLubyte *v); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLboolean (APIENTRYP PFNGLAREPROGRAMSRESIDENTNVPROC) (GLsizei n, const GLuint *programs, GLboolean *residences); -typedef void (APIENTRYP PFNGLBINDPROGRAMNVPROC) (GLenum target, GLuint id); -typedef void (APIENTRYP PFNGLDELETEPROGRAMSNVPROC) (GLsizei n, const GLuint *programs); -typedef void (APIENTRYP PFNGLEXECUTEPROGRAMNVPROC) (GLenum target, GLuint id, const GLfloat *params); -typedef void (APIENTRYP PFNGLGENPROGRAMSNVPROC) (GLsizei n, GLuint *programs); -typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERDVNVPROC) (GLenum target, GLuint index, GLenum pname, GLdouble *params); -typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETPROGRAMIVNVPROC) (GLuint id, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGNVPROC) (GLuint id, GLenum pname, GLubyte *program); -typedef void (APIENTRYP PFNGLGETTRACKMATRIXIVNVPROC) (GLenum target, GLuint address, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVNVPROC) (GLuint index, GLenum pname, GLdouble *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVNVPROC) (GLuint index, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVNVPROC) (GLuint index, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVNVPROC) (GLuint index, GLenum pname, GLvoid* *pointer); -typedef GLboolean (APIENTRYP PFNGLISPROGRAMNVPROC) (GLuint id); -typedef void (APIENTRYP PFNGLLOADPROGRAMNVPROC) (GLenum target, GLuint id, GLsizei len, const GLubyte *program); -typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DNVPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DVNVPROC) (GLenum target, GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FNVPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FVNVPROC) (GLenum target, GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4DVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLdouble *v); -typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4FVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *v); -typedef void (APIENTRYP PFNGLREQUESTRESIDENTPROGRAMSNVPROC) (GLsizei n, const GLuint *programs); -typedef void (APIENTRYP PFNGLTRACKMATRIXNVPROC) (GLenum target, GLuint address, GLenum matrix, GLenum transform); -typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERNVPROC) (GLuint index, GLint fsize, GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1DNVPROC) (GLuint index, GLdouble x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVNVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1FNVPROC) (GLuint index, GLfloat x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVNVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1SNVPROC) (GLuint index, GLshort x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVNVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2DNVPROC) (GLuint index, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVNVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2FNVPROC) (GLuint index, GLfloat x, GLfloat y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVNVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2SNVPROC) (GLuint index, GLshort x, GLshort y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVNVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVNVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVNVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVNVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVNVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVNVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVNVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBNVPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVNVPROC) (GLuint index, const GLubyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS1DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS1FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS1SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS2DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS2FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS2SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS3DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS3FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS3SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS4DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS4FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS4SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS4UBVNVPROC) (GLuint index, GLsizei count, const GLubyte *v); -#endif - -#ifndef GL_SGIX_texture_coordinate_clamp -#define GL_SGIX_texture_coordinate_clamp 1 -#endif - -#ifndef GL_SGIX_scalebias_hint -#define GL_SGIX_scalebias_hint 1 -#endif - -#ifndef GL_OML_interlace -#define GL_OML_interlace 1 -#endif - -#ifndef GL_OML_subsample -#define GL_OML_subsample 1 -#endif - -#ifndef GL_OML_resample -#define GL_OML_resample 1 -#endif - -#ifndef GL_NV_copy_depth_to_color -#define GL_NV_copy_depth_to_color 1 -#endif - -#ifndef GL_ATI_envmap_bumpmap -#define GL_ATI_envmap_bumpmap 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexBumpParameterivATI (GLenum pname, const GLint *param); -GLAPI void APIENTRY glTexBumpParameterfvATI (GLenum pname, const GLfloat *param); -GLAPI void APIENTRY glGetTexBumpParameterivATI (GLenum pname, GLint *param); -GLAPI void APIENTRY glGetTexBumpParameterfvATI (GLenum pname, GLfloat *param); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERIVATIPROC) (GLenum pname, const GLint *param); -typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERFVATIPROC) (GLenum pname, const GLfloat *param); -typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERIVATIPROC) (GLenum pname, GLint *param); -typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERFVATIPROC) (GLenum pname, GLfloat *param); -#endif - -#ifndef GL_ATI_fragment_shader -#define GL_ATI_fragment_shader 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLuint APIENTRY glGenFragmentShadersATI (GLuint range); -GLAPI void APIENTRY glBindFragmentShaderATI (GLuint id); -GLAPI void APIENTRY glDeleteFragmentShaderATI (GLuint id); -GLAPI void APIENTRY glBeginFragmentShaderATI (void); -GLAPI void APIENTRY glEndFragmentShaderATI (void); -GLAPI void APIENTRY glPassTexCoordATI (GLuint dst, GLuint coord, GLenum swizzle); -GLAPI void APIENTRY glSampleMapATI (GLuint dst, GLuint interp, GLenum swizzle); -GLAPI void APIENTRY glColorFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); -GLAPI void APIENTRY glColorFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); -GLAPI void APIENTRY glColorFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); -GLAPI void APIENTRY glAlphaFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); -GLAPI void APIENTRY glAlphaFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); -GLAPI void APIENTRY glAlphaFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); -GLAPI void APIENTRY glSetFragmentShaderConstantATI (GLuint dst, const GLfloat *value); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLuint (APIENTRYP PFNGLGENFRAGMENTSHADERSATIPROC) (GLuint range); -typedef void (APIENTRYP PFNGLBINDFRAGMENTSHADERATIPROC) (GLuint id); -typedef void (APIENTRYP PFNGLDELETEFRAGMENTSHADERATIPROC) (GLuint id); -typedef void (APIENTRYP PFNGLBEGINFRAGMENTSHADERATIPROC) (void); -typedef void (APIENTRYP PFNGLENDFRAGMENTSHADERATIPROC) (void); -typedef void (APIENTRYP PFNGLPASSTEXCOORDATIPROC) (GLuint dst, GLuint coord, GLenum swizzle); -typedef void (APIENTRYP PFNGLSAMPLEMAPATIPROC) (GLuint dst, GLuint interp, GLenum swizzle); -typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); -typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); -typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); -typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); -typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); -typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); -typedef void (APIENTRYP PFNGLSETFRAGMENTSHADERCONSTANTATIPROC) (GLuint dst, const GLfloat *value); -#endif - -#ifndef GL_ATI_pn_triangles -#define GL_ATI_pn_triangles 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPNTrianglesiATI (GLenum pname, GLint param); -GLAPI void APIENTRY glPNTrianglesfATI (GLenum pname, GLfloat param); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPNTRIANGLESIATIPROC) (GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLPNTRIANGLESFATIPROC) (GLenum pname, GLfloat param); -#endif - -#ifndef GL_ATI_vertex_array_object -#define GL_ATI_vertex_array_object 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLuint APIENTRY glNewObjectBufferATI (GLsizei size, const GLvoid *pointer, GLenum usage); -GLAPI GLboolean APIENTRY glIsObjectBufferATI (GLuint buffer); -GLAPI void APIENTRY glUpdateObjectBufferATI (GLuint buffer, GLuint offset, GLsizei size, const GLvoid *pointer, GLenum preserve); -GLAPI void APIENTRY glGetObjectBufferfvATI (GLuint buffer, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetObjectBufferivATI (GLuint buffer, GLenum pname, GLint *params); -GLAPI void APIENTRY glFreeObjectBufferATI (GLuint buffer); -GLAPI void APIENTRY glArrayObjectATI (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); -GLAPI void APIENTRY glGetArrayObjectfvATI (GLenum array, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetArrayObjectivATI (GLenum array, GLenum pname, GLint *params); -GLAPI void APIENTRY glVariantArrayObjectATI (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); -GLAPI void APIENTRY glGetVariantArrayObjectfvATI (GLuint id, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetVariantArrayObjectivATI (GLuint id, GLenum pname, GLint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLuint (APIENTRYP PFNGLNEWOBJECTBUFFERATIPROC) (GLsizei size, const GLvoid *pointer, GLenum usage); -typedef GLboolean (APIENTRYP PFNGLISOBJECTBUFFERATIPROC) (GLuint buffer); -typedef void (APIENTRYP PFNGLUPDATEOBJECTBUFFERATIPROC) (GLuint buffer, GLuint offset, GLsizei size, const GLvoid *pointer, GLenum preserve); -typedef void (APIENTRYP PFNGLGETOBJECTBUFFERFVATIPROC) (GLuint buffer, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETOBJECTBUFFERIVATIPROC) (GLuint buffer, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLFREEOBJECTBUFFERATIPROC) (GLuint buffer); -typedef void (APIENTRYP PFNGLARRAYOBJECTATIPROC) (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); -typedef void (APIENTRYP PFNGLGETARRAYOBJECTFVATIPROC) (GLenum array, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETARRAYOBJECTIVATIPROC) (GLenum array, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLVARIANTARRAYOBJECTATIPROC) (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); -typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTFVATIPROC) (GLuint id, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTIVATIPROC) (GLuint id, GLenum pname, GLint *params); -#endif - -#ifndef GL_EXT_vertex_shader -#define GL_EXT_vertex_shader 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBeginVertexShaderEXT (void); -GLAPI void APIENTRY glEndVertexShaderEXT (void); -GLAPI void APIENTRY glBindVertexShaderEXT (GLuint id); -GLAPI GLuint APIENTRY glGenVertexShadersEXT (GLuint range); -GLAPI void APIENTRY glDeleteVertexShaderEXT (GLuint id); -GLAPI void APIENTRY glShaderOp1EXT (GLenum op, GLuint res, GLuint arg1); -GLAPI void APIENTRY glShaderOp2EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2); -GLAPI void APIENTRY glShaderOp3EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3); -GLAPI void APIENTRY glSwizzleEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); -GLAPI void APIENTRY glWriteMaskEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); -GLAPI void APIENTRY glInsertComponentEXT (GLuint res, GLuint src, GLuint num); -GLAPI void APIENTRY glExtractComponentEXT (GLuint res, GLuint src, GLuint num); -GLAPI GLuint APIENTRY glGenSymbolsEXT (GLenum datatype, GLenum storagetype, GLenum range, GLuint components); -GLAPI void APIENTRY glSetInvariantEXT (GLuint id, GLenum type, const GLvoid *addr); -GLAPI void APIENTRY glSetLocalConstantEXT (GLuint id, GLenum type, const GLvoid *addr); -GLAPI void APIENTRY glVariantbvEXT (GLuint id, const GLbyte *addr); -GLAPI void APIENTRY glVariantsvEXT (GLuint id, const GLshort *addr); -GLAPI void APIENTRY glVariantivEXT (GLuint id, const GLint *addr); -GLAPI void APIENTRY glVariantfvEXT (GLuint id, const GLfloat *addr); -GLAPI void APIENTRY glVariantdvEXT (GLuint id, const GLdouble *addr); -GLAPI void APIENTRY glVariantubvEXT (GLuint id, const GLubyte *addr); -GLAPI void APIENTRY glVariantusvEXT (GLuint id, const GLushort *addr); -GLAPI void APIENTRY glVariantuivEXT (GLuint id, const GLuint *addr); -GLAPI void APIENTRY glVariantPointerEXT (GLuint id, GLenum type, GLuint stride, const GLvoid *addr); -GLAPI void APIENTRY glEnableVariantClientStateEXT (GLuint id); -GLAPI void APIENTRY glDisableVariantClientStateEXT (GLuint id); -GLAPI GLuint APIENTRY glBindLightParameterEXT (GLenum light, GLenum value); -GLAPI GLuint APIENTRY glBindMaterialParameterEXT (GLenum face, GLenum value); -GLAPI GLuint APIENTRY glBindTexGenParameterEXT (GLenum unit, GLenum coord, GLenum value); -GLAPI GLuint APIENTRY glBindTextureUnitParameterEXT (GLenum unit, GLenum value); -GLAPI GLuint APIENTRY glBindParameterEXT (GLenum value); -GLAPI GLboolean APIENTRY glIsVariantEnabledEXT (GLuint id, GLenum cap); -GLAPI void APIENTRY glGetVariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data); -GLAPI void APIENTRY glGetVariantIntegervEXT (GLuint id, GLenum value, GLint *data); -GLAPI void APIENTRY glGetVariantFloatvEXT (GLuint id, GLenum value, GLfloat *data); -GLAPI void APIENTRY glGetVariantPointervEXT (GLuint id, GLenum value, GLvoid* *data); -GLAPI void APIENTRY glGetInvariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data); -GLAPI void APIENTRY glGetInvariantIntegervEXT (GLuint id, GLenum value, GLint *data); -GLAPI void APIENTRY glGetInvariantFloatvEXT (GLuint id, GLenum value, GLfloat *data); -GLAPI void APIENTRY glGetLocalConstantBooleanvEXT (GLuint id, GLenum value, GLboolean *data); -GLAPI void APIENTRY glGetLocalConstantIntegervEXT (GLuint id, GLenum value, GLint *data); -GLAPI void APIENTRY glGetLocalConstantFloatvEXT (GLuint id, GLenum value, GLfloat *data); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBEGINVERTEXSHADEREXTPROC) (void); -typedef void (APIENTRYP PFNGLENDVERTEXSHADEREXTPROC) (void); -typedef void (APIENTRYP PFNGLBINDVERTEXSHADEREXTPROC) (GLuint id); -typedef GLuint (APIENTRYP PFNGLGENVERTEXSHADERSEXTPROC) (GLuint range); -typedef void (APIENTRYP PFNGLDELETEVERTEXSHADEREXTPROC) (GLuint id); -typedef void (APIENTRYP PFNGLSHADEROP1EXTPROC) (GLenum op, GLuint res, GLuint arg1); -typedef void (APIENTRYP PFNGLSHADEROP2EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2); -typedef void (APIENTRYP PFNGLSHADEROP3EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3); -typedef void (APIENTRYP PFNGLSWIZZLEEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); -typedef void (APIENTRYP PFNGLWRITEMASKEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); -typedef void (APIENTRYP PFNGLINSERTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num); -typedef void (APIENTRYP PFNGLEXTRACTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num); -typedef GLuint (APIENTRYP PFNGLGENSYMBOLSEXTPROC) (GLenum datatype, GLenum storagetype, GLenum range, GLuint components); -typedef void (APIENTRYP PFNGLSETINVARIANTEXTPROC) (GLuint id, GLenum type, const GLvoid *addr); -typedef void (APIENTRYP PFNGLSETLOCALCONSTANTEXTPROC) (GLuint id, GLenum type, const GLvoid *addr); -typedef void (APIENTRYP PFNGLVARIANTBVEXTPROC) (GLuint id, const GLbyte *addr); -typedef void (APIENTRYP PFNGLVARIANTSVEXTPROC) (GLuint id, const GLshort *addr); -typedef void (APIENTRYP PFNGLVARIANTIVEXTPROC) (GLuint id, const GLint *addr); -typedef void (APIENTRYP PFNGLVARIANTFVEXTPROC) (GLuint id, const GLfloat *addr); -typedef void (APIENTRYP PFNGLVARIANTDVEXTPROC) (GLuint id, const GLdouble *addr); -typedef void (APIENTRYP PFNGLVARIANTUBVEXTPROC) (GLuint id, const GLubyte *addr); -typedef void (APIENTRYP PFNGLVARIANTUSVEXTPROC) (GLuint id, const GLushort *addr); -typedef void (APIENTRYP PFNGLVARIANTUIVEXTPROC) (GLuint id, const GLuint *addr); -typedef void (APIENTRYP PFNGLVARIANTPOINTEREXTPROC) (GLuint id, GLenum type, GLuint stride, const GLvoid *addr); -typedef void (APIENTRYP PFNGLENABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id); -typedef void (APIENTRYP PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id); -typedef GLuint (APIENTRYP PFNGLBINDLIGHTPARAMETEREXTPROC) (GLenum light, GLenum value); -typedef GLuint (APIENTRYP PFNGLBINDMATERIALPARAMETEREXTPROC) (GLenum face, GLenum value); -typedef GLuint (APIENTRYP PFNGLBINDTEXGENPARAMETEREXTPROC) (GLenum unit, GLenum coord, GLenum value); -typedef GLuint (APIENTRYP PFNGLBINDTEXTUREUNITPARAMETEREXTPROC) (GLenum unit, GLenum value); -typedef GLuint (APIENTRYP PFNGLBINDPARAMETEREXTPROC) (GLenum value); -typedef GLboolean (APIENTRYP PFNGLISVARIANTENABLEDEXTPROC) (GLuint id, GLenum cap); -typedef void (APIENTRYP PFNGLGETVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); -typedef void (APIENTRYP PFNGLGETVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); -typedef void (APIENTRYP PFNGLGETVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); -typedef void (APIENTRYP PFNGLGETVARIANTPOINTERVEXTPROC) (GLuint id, GLenum value, GLvoid* *data); -typedef void (APIENTRYP PFNGLGETINVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); -typedef void (APIENTRYP PFNGLGETINVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); -typedef void (APIENTRYP PFNGLGETINVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); -typedef void (APIENTRYP PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); -typedef void (APIENTRYP PFNGLGETLOCALCONSTANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); -typedef void (APIENTRYP PFNGLGETLOCALCONSTANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); -#endif - -#ifndef GL_ATI_vertex_streams -#define GL_ATI_vertex_streams 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexStream1sATI (GLenum stream, GLshort x); -GLAPI void APIENTRY glVertexStream1svATI (GLenum stream, const GLshort *coords); -GLAPI void APIENTRY glVertexStream1iATI (GLenum stream, GLint x); -GLAPI void APIENTRY glVertexStream1ivATI (GLenum stream, const GLint *coords); -GLAPI void APIENTRY glVertexStream1fATI (GLenum stream, GLfloat x); -GLAPI void APIENTRY glVertexStream1fvATI (GLenum stream, const GLfloat *coords); -GLAPI void APIENTRY glVertexStream1dATI (GLenum stream, GLdouble x); -GLAPI void APIENTRY glVertexStream1dvATI (GLenum stream, const GLdouble *coords); -GLAPI void APIENTRY glVertexStream2sATI (GLenum stream, GLshort x, GLshort y); -GLAPI void APIENTRY glVertexStream2svATI (GLenum stream, const GLshort *coords); -GLAPI void APIENTRY glVertexStream2iATI (GLenum stream, GLint x, GLint y); -GLAPI void APIENTRY glVertexStream2ivATI (GLenum stream, const GLint *coords); -GLAPI void APIENTRY glVertexStream2fATI (GLenum stream, GLfloat x, GLfloat y); -GLAPI void APIENTRY glVertexStream2fvATI (GLenum stream, const GLfloat *coords); -GLAPI void APIENTRY glVertexStream2dATI (GLenum stream, GLdouble x, GLdouble y); -GLAPI void APIENTRY glVertexStream2dvATI (GLenum stream, const GLdouble *coords); -GLAPI void APIENTRY glVertexStream3sATI (GLenum stream, GLshort x, GLshort y, GLshort z); -GLAPI void APIENTRY glVertexStream3svATI (GLenum stream, const GLshort *coords); -GLAPI void APIENTRY glVertexStream3iATI (GLenum stream, GLint x, GLint y, GLint z); -GLAPI void APIENTRY glVertexStream3ivATI (GLenum stream, const GLint *coords); -GLAPI void APIENTRY glVertexStream3fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glVertexStream3fvATI (GLenum stream, const GLfloat *coords); -GLAPI void APIENTRY glVertexStream3dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glVertexStream3dvATI (GLenum stream, const GLdouble *coords); -GLAPI void APIENTRY glVertexStream4sATI (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w); -GLAPI void APIENTRY glVertexStream4svATI (GLenum stream, const GLshort *coords); -GLAPI void APIENTRY glVertexStream4iATI (GLenum stream, GLint x, GLint y, GLint z, GLint w); -GLAPI void APIENTRY glVertexStream4ivATI (GLenum stream, const GLint *coords); -GLAPI void APIENTRY glVertexStream4fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glVertexStream4fvATI (GLenum stream, const GLfloat *coords); -GLAPI void APIENTRY glVertexStream4dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glVertexStream4dvATI (GLenum stream, const GLdouble *coords); -GLAPI void APIENTRY glNormalStream3bATI (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz); -GLAPI void APIENTRY glNormalStream3bvATI (GLenum stream, const GLbyte *coords); -GLAPI void APIENTRY glNormalStream3sATI (GLenum stream, GLshort nx, GLshort ny, GLshort nz); -GLAPI void APIENTRY glNormalStream3svATI (GLenum stream, const GLshort *coords); -GLAPI void APIENTRY glNormalStream3iATI (GLenum stream, GLint nx, GLint ny, GLint nz); -GLAPI void APIENTRY glNormalStream3ivATI (GLenum stream, const GLint *coords); -GLAPI void APIENTRY glNormalStream3fATI (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz); -GLAPI void APIENTRY glNormalStream3fvATI (GLenum stream, const GLfloat *coords); -GLAPI void APIENTRY glNormalStream3dATI (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz); -GLAPI void APIENTRY glNormalStream3dvATI (GLenum stream, const GLdouble *coords); -GLAPI void APIENTRY glClientActiveVertexStreamATI (GLenum stream); -GLAPI void APIENTRY glVertexBlendEnviATI (GLenum pname, GLint param); -GLAPI void APIENTRY glVertexBlendEnvfATI (GLenum pname, GLfloat param); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVERTEXSTREAM1SATIPROC) (GLenum stream, GLshort x); -typedef void (APIENTRYP PFNGLVERTEXSTREAM1SVATIPROC) (GLenum stream, const GLshort *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM1IATIPROC) (GLenum stream, GLint x); -typedef void (APIENTRYP PFNGLVERTEXSTREAM1IVATIPROC) (GLenum stream, const GLint *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM1FATIPROC) (GLenum stream, GLfloat x); -typedef void (APIENTRYP PFNGLVERTEXSTREAM1FVATIPROC) (GLenum stream, const GLfloat *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM1DATIPROC) (GLenum stream, GLdouble x); -typedef void (APIENTRYP PFNGLVERTEXSTREAM1DVATIPROC) (GLenum stream, const GLdouble *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM2SATIPROC) (GLenum stream, GLshort x, GLshort y); -typedef void (APIENTRYP PFNGLVERTEXSTREAM2SVATIPROC) (GLenum stream, const GLshort *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM2IATIPROC) (GLenum stream, GLint x, GLint y); -typedef void (APIENTRYP PFNGLVERTEXSTREAM2IVATIPROC) (GLenum stream, const GLint *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM2FATIPROC) (GLenum stream, GLfloat x, GLfloat y); -typedef void (APIENTRYP PFNGLVERTEXSTREAM2FVATIPROC) (GLenum stream, const GLfloat *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM2DATIPROC) (GLenum stream, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLVERTEXSTREAM2DVATIPROC) (GLenum stream, const GLdouble *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM3SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z); -typedef void (APIENTRYP PFNGLVERTEXSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM3IATIPROC) (GLenum stream, GLint x, GLint y, GLint z); -typedef void (APIENTRYP PFNGLVERTEXSTREAM3IVATIPROC) (GLenum stream, const GLint *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM3FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLVERTEXSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM3DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLVERTEXSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM4SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w); -typedef void (APIENTRYP PFNGLVERTEXSTREAM4SVATIPROC) (GLenum stream, const GLshort *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM4IATIPROC) (GLenum stream, GLint x, GLint y, GLint z, GLint w); -typedef void (APIENTRYP PFNGLVERTEXSTREAM4IVATIPROC) (GLenum stream, const GLint *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM4FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLVERTEXSTREAM4FVATIPROC) (GLenum stream, const GLfloat *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM4DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLVERTEXSTREAM4DVATIPROC) (GLenum stream, const GLdouble *coords); -typedef void (APIENTRYP PFNGLNORMALSTREAM3BATIPROC) (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz); -typedef void (APIENTRYP PFNGLNORMALSTREAM3BVATIPROC) (GLenum stream, const GLbyte *coords); -typedef void (APIENTRYP PFNGLNORMALSTREAM3SATIPROC) (GLenum stream, GLshort nx, GLshort ny, GLshort nz); -typedef void (APIENTRYP PFNGLNORMALSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords); -typedef void (APIENTRYP PFNGLNORMALSTREAM3IATIPROC) (GLenum stream, GLint nx, GLint ny, GLint nz); -typedef void (APIENTRYP PFNGLNORMALSTREAM3IVATIPROC) (GLenum stream, const GLint *coords); -typedef void (APIENTRYP PFNGLNORMALSTREAM3FATIPROC) (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz); -typedef void (APIENTRYP PFNGLNORMALSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords); -typedef void (APIENTRYP PFNGLNORMALSTREAM3DATIPROC) (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz); -typedef void (APIENTRYP PFNGLNORMALSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords); -typedef void (APIENTRYP PFNGLCLIENTACTIVEVERTEXSTREAMATIPROC) (GLenum stream); -typedef void (APIENTRYP PFNGLVERTEXBLENDENVIATIPROC) (GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLVERTEXBLENDENVFATIPROC) (GLenum pname, GLfloat param); -#endif - -#ifndef GL_ATI_element_array -#define GL_ATI_element_array 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glElementPointerATI (GLenum type, const GLvoid *pointer); -GLAPI void APIENTRY glDrawElementArrayATI (GLenum mode, GLsizei count); -GLAPI void APIENTRY glDrawRangeElementArrayATI (GLenum mode, GLuint start, GLuint end, GLsizei count); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLELEMENTPOINTERATIPROC) (GLenum type, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYATIPROC) (GLenum mode, GLsizei count); -typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYATIPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count); -#endif - -#ifndef GL_SUN_mesh_array -#define GL_SUN_mesh_array 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawMeshArraysSUN (GLenum mode, GLint first, GLsizei count, GLsizei width); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDRAWMESHARRAYSSUNPROC) (GLenum mode, GLint first, GLsizei count, GLsizei width); -#endif - -#ifndef GL_SUN_slice_accum -#define GL_SUN_slice_accum 1 -#endif - -#ifndef GL_NV_multisample_filter_hint -#define GL_NV_multisample_filter_hint 1 -#endif - -#ifndef GL_NV_depth_clamp -#define GL_NV_depth_clamp 1 -#endif - -#ifndef GL_NV_occlusion_query -#define GL_NV_occlusion_query 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGenOcclusionQueriesNV (GLsizei n, GLuint *ids); -GLAPI void APIENTRY glDeleteOcclusionQueriesNV (GLsizei n, const GLuint *ids); -GLAPI GLboolean APIENTRY glIsOcclusionQueryNV (GLuint id); -GLAPI void APIENTRY glBeginOcclusionQueryNV (GLuint id); -GLAPI void APIENTRY glEndOcclusionQueryNV (void); -GLAPI void APIENTRY glGetOcclusionQueryivNV (GLuint id, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetOcclusionQueryuivNV (GLuint id, GLenum pname, GLuint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGENOCCLUSIONQUERIESNVPROC) (GLsizei n, GLuint *ids); -typedef void (APIENTRYP PFNGLDELETEOCCLUSIONQUERIESNVPROC) (GLsizei n, const GLuint *ids); -typedef GLboolean (APIENTRYP PFNGLISOCCLUSIONQUERYNVPROC) (GLuint id); -typedef void (APIENTRYP PFNGLBEGINOCCLUSIONQUERYNVPROC) (GLuint id); -typedef void (APIENTRYP PFNGLENDOCCLUSIONQUERYNVPROC) (void); -typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYIVNVPROC) (GLuint id, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYUIVNVPROC) (GLuint id, GLenum pname, GLuint *params); -#endif - -#ifndef GL_NV_point_sprite -#define GL_NV_point_sprite 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPointParameteriNV (GLenum pname, GLint param); -GLAPI void APIENTRY glPointParameterivNV (GLenum pname, const GLint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPOINTPARAMETERINVPROC) (GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLPOINTPARAMETERIVNVPROC) (GLenum pname, const GLint *params); -#endif - -#ifndef GL_NV_texture_shader3 -#define GL_NV_texture_shader3 1 -#endif - -#ifndef GL_NV_vertex_program1_1 -#define GL_NV_vertex_program1_1 1 -#endif - -#ifndef GL_EXT_shadow_funcs -#define GL_EXT_shadow_funcs 1 -#endif - -#ifndef GL_EXT_stencil_two_side -#define GL_EXT_stencil_two_side 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glActiveStencilFaceEXT (GLenum face); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face); -#endif - -#ifndef GL_ATI_text_fragment_shader -#define GL_ATI_text_fragment_shader 1 -#endif - -#ifndef GL_APPLE_client_storage -#define GL_APPLE_client_storage 1 -#endif - -#ifndef GL_APPLE_element_array -#define GL_APPLE_element_array 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glElementPointerAPPLE (GLenum type, const GLvoid *pointer); -GLAPI void APIENTRY glDrawElementArrayAPPLE (GLenum mode, GLint first, GLsizei count); -GLAPI void APIENTRY glDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count); -GLAPI void APIENTRY glMultiDrawElementArrayAPPLE (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); -GLAPI void APIENTRY glMultiDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLELEMENTPOINTERAPPLEPROC) (GLenum type, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, GLint first, GLsizei count); -typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); -typedef void (APIENTRYP PFNGLMULTIDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount); -#endif - -#ifndef GL_APPLE_fence -#define GL_APPLE_fence 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGenFencesAPPLE (GLsizei n, GLuint *fences); -GLAPI void APIENTRY glDeleteFencesAPPLE (GLsizei n, const GLuint *fences); -GLAPI void APIENTRY glSetFenceAPPLE (GLuint fence); -GLAPI GLboolean APIENTRY glIsFenceAPPLE (GLuint fence); -GLAPI GLboolean APIENTRY glTestFenceAPPLE (GLuint fence); -GLAPI void APIENTRY glFinishFenceAPPLE (GLuint fence); -GLAPI GLboolean APIENTRY glTestObjectAPPLE (GLenum object, GLuint name); -GLAPI void APIENTRY glFinishObjectAPPLE (GLenum object, GLint name); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGENFENCESAPPLEPROC) (GLsizei n, GLuint *fences); -typedef void (APIENTRYP PFNGLDELETEFENCESAPPLEPROC) (GLsizei n, const GLuint *fences); -typedef void (APIENTRYP PFNGLSETFENCEAPPLEPROC) (GLuint fence); -typedef GLboolean (APIENTRYP PFNGLISFENCEAPPLEPROC) (GLuint fence); -typedef GLboolean (APIENTRYP PFNGLTESTFENCEAPPLEPROC) (GLuint fence); -typedef void (APIENTRYP PFNGLFINISHFENCEAPPLEPROC) (GLuint fence); -typedef GLboolean (APIENTRYP PFNGLTESTOBJECTAPPLEPROC) (GLenum object, GLuint name); -typedef void (APIENTRYP PFNGLFINISHOBJECTAPPLEPROC) (GLenum object, GLint name); -#endif - -#ifndef GL_APPLE_vertex_array_object -#define GL_APPLE_vertex_array_object 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBindVertexArrayAPPLE (GLuint array); -GLAPI void APIENTRY glDeleteVertexArraysAPPLE (GLsizei n, const GLuint *arrays); -GLAPI void APIENTRY glGenVertexArraysAPPLE (GLsizei n, GLuint *arrays); -GLAPI GLboolean APIENTRY glIsVertexArrayAPPLE (GLuint array); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBINDVERTEXARRAYAPPLEPROC) (GLuint array); -typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSAPPLEPROC) (GLsizei n, const GLuint *arrays); -typedef void (APIENTRYP PFNGLGENVERTEXARRAYSAPPLEPROC) (GLsizei n, GLuint *arrays); -typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYAPPLEPROC) (GLuint array); -#endif - -#ifndef GL_APPLE_vertex_array_range -#define GL_APPLE_vertex_array_range 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexArrayRangeAPPLE (GLsizei length, GLvoid *pointer); -GLAPI void APIENTRY glFlushVertexArrayRangeAPPLE (GLsizei length, GLvoid *pointer); -GLAPI void APIENTRY glVertexArrayParameteriAPPLE (GLenum pname, GLint param); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer); -typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer); -typedef void (APIENTRYP PFNGLVERTEXARRAYPARAMETERIAPPLEPROC) (GLenum pname, GLint param); -#endif - -#ifndef GL_APPLE_ycbcr_422 -#define GL_APPLE_ycbcr_422 1 -#endif - -#ifndef GL_S3_s3tc -#define GL_S3_s3tc 1 -#endif - -#ifndef GL_ATI_draw_buffers -#define GL_ATI_draw_buffers 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawBuffersATI (GLsizei n, const GLenum *bufs); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDRAWBUFFERSATIPROC) (GLsizei n, const GLenum *bufs); -#endif - -#ifndef GL_ATI_pixel_format_float -#define GL_ATI_pixel_format_float 1 -/* This is really a WGL extension, but defines some associated GL enums. - * ATI does not export "GL_ATI_pixel_format_float" in the GL_EXTENSIONS string. - */ -#endif - -#ifndef GL_ATI_texture_env_combine3 -#define GL_ATI_texture_env_combine3 1 -#endif - -#ifndef GL_ATI_texture_float -#define GL_ATI_texture_float 1 -#endif - -#ifndef GL_NV_float_buffer -#define GL_NV_float_buffer 1 -#endif - -#ifndef GL_NV_fragment_program -#define GL_NV_fragment_program 1 -/* Some NV_fragment_program entry points are shared with ARB_vertex_program. */ -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProgramNamedParameter4fNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glProgramNamedParameter4dNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glProgramNamedParameter4fvNV (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v); -GLAPI void APIENTRY glProgramNamedParameter4dvNV (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v); -GLAPI void APIENTRY glGetProgramNamedParameterfvNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params); -GLAPI void APIENTRY glGetProgramNamedParameterdvNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v); -typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v); -typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERFVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params); -typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERDVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params); -#endif - -#ifndef GL_NV_half_float -#define GL_NV_half_float 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertex2hNV (GLhalfNV x, GLhalfNV y); -GLAPI void APIENTRY glVertex2hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glVertex3hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z); -GLAPI void APIENTRY glVertex3hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glVertex4hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); -GLAPI void APIENTRY glVertex4hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glNormal3hNV (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz); -GLAPI void APIENTRY glNormal3hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue); -GLAPI void APIENTRY glColor3hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glColor4hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha); -GLAPI void APIENTRY glColor4hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glTexCoord1hNV (GLhalfNV s); -GLAPI void APIENTRY glTexCoord1hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glTexCoord2hNV (GLhalfNV s, GLhalfNV t); -GLAPI void APIENTRY glTexCoord2hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glTexCoord3hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r); -GLAPI void APIENTRY glTexCoord3hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glTexCoord4hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); -GLAPI void APIENTRY glTexCoord4hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glMultiTexCoord1hNV (GLenum target, GLhalfNV s); -GLAPI void APIENTRY glMultiTexCoord1hvNV (GLenum target, const GLhalfNV *v); -GLAPI void APIENTRY glMultiTexCoord2hNV (GLenum target, GLhalfNV s, GLhalfNV t); -GLAPI void APIENTRY glMultiTexCoord2hvNV (GLenum target, const GLhalfNV *v); -GLAPI void APIENTRY glMultiTexCoord3hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r); -GLAPI void APIENTRY glMultiTexCoord3hvNV (GLenum target, const GLhalfNV *v); -GLAPI void APIENTRY glMultiTexCoord4hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); -GLAPI void APIENTRY glMultiTexCoord4hvNV (GLenum target, const GLhalfNV *v); -GLAPI void APIENTRY glFogCoordhNV (GLhalfNV fog); -GLAPI void APIENTRY glFogCoordhvNV (const GLhalfNV *fog); -GLAPI void APIENTRY glSecondaryColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue); -GLAPI void APIENTRY glSecondaryColor3hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glVertexWeighthNV (GLhalfNV weight); -GLAPI void APIENTRY glVertexWeighthvNV (const GLhalfNV *weight); -GLAPI void APIENTRY glVertexAttrib1hNV (GLuint index, GLhalfNV x); -GLAPI void APIENTRY glVertexAttrib1hvNV (GLuint index, const GLhalfNV *v); -GLAPI void APIENTRY glVertexAttrib2hNV (GLuint index, GLhalfNV x, GLhalfNV y); -GLAPI void APIENTRY glVertexAttrib2hvNV (GLuint index, const GLhalfNV *v); -GLAPI void APIENTRY glVertexAttrib3hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z); -GLAPI void APIENTRY glVertexAttrib3hvNV (GLuint index, const GLhalfNV *v); -GLAPI void APIENTRY glVertexAttrib4hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); -GLAPI void APIENTRY glVertexAttrib4hvNV (GLuint index, const GLhalfNV *v); -GLAPI void APIENTRY glVertexAttribs1hvNV (GLuint index, GLsizei n, const GLhalfNV *v); -GLAPI void APIENTRY glVertexAttribs2hvNV (GLuint index, GLsizei n, const GLhalfNV *v); -GLAPI void APIENTRY glVertexAttribs3hvNV (GLuint index, GLsizei n, const GLhalfNV *v); -GLAPI void APIENTRY glVertexAttribs4hvNV (GLuint index, GLsizei n, const GLhalfNV *v); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVERTEX2HNVPROC) (GLhalfNV x, GLhalfNV y); -typedef void (APIENTRYP PFNGLVERTEX2HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEX3HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z); -typedef void (APIENTRYP PFNGLVERTEX3HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEX4HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); -typedef void (APIENTRYP PFNGLVERTEX4HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLNORMAL3HNVPROC) (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz); -typedef void (APIENTRYP PFNGLNORMAL3HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); -typedef void (APIENTRYP PFNGLCOLOR3HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLCOLOR4HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha); -typedef void (APIENTRYP PFNGLCOLOR4HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLTEXCOORD1HNVPROC) (GLhalfNV s); -typedef void (APIENTRYP PFNGLTEXCOORD1HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLTEXCOORD2HNVPROC) (GLhalfNV s, GLhalfNV t); -typedef void (APIENTRYP PFNGLTEXCOORD2HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLTEXCOORD3HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r); -typedef void (APIENTRYP PFNGLTEXCOORD3HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLTEXCOORD4HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); -typedef void (APIENTRYP PFNGLTEXCOORD4HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1HNVPROC) (GLenum target, GLhalfNV s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1HVNVPROC) (GLenum target, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2HVNVPROC) (GLenum target, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3HVNVPROC) (GLenum target, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4HVNVPROC) (GLenum target, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLFOGCOORDHNVPROC) (GLhalfNV fog); -typedef void (APIENTRYP PFNGLFOGCOORDHVNVPROC) (const GLhalfNV *fog); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEXWEIGHTHNVPROC) (GLhalfNV weight); -typedef void (APIENTRYP PFNGLVERTEXWEIGHTHVNVPROC) (const GLhalfNV *weight); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1HNVPROC) (GLuint index, GLhalfNV x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1HVNVPROC) (GLuint index, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2HVNVPROC) (GLuint index, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3HVNVPROC) (GLuint index, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4HVNVPROC) (GLuint index, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS1HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS2HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS3HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS4HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); -#endif - -#ifndef GL_NV_pixel_data_range -#define GL_NV_pixel_data_range 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPixelDataRangeNV (GLenum target, GLsizei length, GLvoid *pointer); -GLAPI void APIENTRY glFlushPixelDataRangeNV (GLenum target); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPIXELDATARANGENVPROC) (GLenum target, GLsizei length, GLvoid *pointer); -typedef void (APIENTRYP PFNGLFLUSHPIXELDATARANGENVPROC) (GLenum target); -#endif - -#ifndef GL_NV_primitive_restart -#define GL_NV_primitive_restart 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPrimitiveRestartNV (void); -GLAPI void APIENTRY glPrimitiveRestartIndexNV (GLuint index); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPRIMITIVERESTARTNVPROC) (void); -typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXNVPROC) (GLuint index); -#endif - -#ifndef GL_NV_texture_expand_normal -#define GL_NV_texture_expand_normal 1 -#endif - -#ifndef GL_NV_vertex_program2 -#define GL_NV_vertex_program2 1 -#endif - -#ifndef GL_ATI_map_object_buffer -#define GL_ATI_map_object_buffer 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLvoid* APIENTRY glMapObjectBufferATI (GLuint buffer); -GLAPI void APIENTRY glUnmapObjectBufferATI (GLuint buffer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLvoid* (APIENTRYP PFNGLMAPOBJECTBUFFERATIPROC) (GLuint buffer); -typedef void (APIENTRYP PFNGLUNMAPOBJECTBUFFERATIPROC) (GLuint buffer); -#endif - -#ifndef GL_ATI_separate_stencil -#define GL_ATI_separate_stencil 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glStencilOpSeparateATI (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); -GLAPI void APIENTRY glStencilFuncSeparateATI (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEATIPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); -typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEATIPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); -#endif - -#ifndef GL_ATI_vertex_attrib_array_object -#define GL_ATI_vertex_attrib_array_object 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexAttribArrayObjectATI (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset); -GLAPI void APIENTRY glGetVertexAttribArrayObjectfvATI (GLuint index, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetVertexAttribArrayObjectivATI (GLuint index, GLenum pname, GLint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVERTEXATTRIBARRAYOBJECTATIPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTFVATIPROC) (GLuint index, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTIVATIPROC) (GLuint index, GLenum pname, GLint *params); -#endif - -#ifndef GL_OES_read_format -#define GL_OES_read_format 1 -#endif - -#ifndef GL_EXT_depth_bounds_test -#define GL_EXT_depth_bounds_test 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDepthBoundsEXT (GLclampd zmin, GLclampd zmax); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDEPTHBOUNDSEXTPROC) (GLclampd zmin, GLclampd zmax); -#endif - -#ifndef GL_EXT_texture_mirror_clamp -#define GL_EXT_texture_mirror_clamp 1 -#endif - -#ifndef GL_EXT_blend_equation_separate -#define GL_EXT_blend_equation_separate 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendEquationSeparateEXT (GLenum modeRGB, GLenum modeAlpha); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEEXTPROC) (GLenum modeRGB, GLenum modeAlpha); -#endif - -#ifndef GL_MESA_pack_invert -#define GL_MESA_pack_invert 1 -#endif - -#ifndef GL_MESA_ycbcr_texture -#define GL_MESA_ycbcr_texture 1 -#endif - -#ifndef GL_EXT_pixel_buffer_object -#define GL_EXT_pixel_buffer_object 1 -#endif - -#ifndef GL_NV_fragment_program_option -#define GL_NV_fragment_program_option 1 -#endif - -#ifndef GL_NV_fragment_program2 -#define GL_NV_fragment_program2 1 -#endif - -#ifndef GL_NV_vertex_program2_option -#define GL_NV_vertex_program2_option 1 -#endif - -#ifndef GL_NV_vertex_program3 -#define GL_NV_vertex_program3 1 -#endif - -#ifndef GL_EXT_framebuffer_object -#define GL_EXT_framebuffer_object 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLboolean APIENTRY glIsRenderbufferEXT (GLuint renderbuffer); -GLAPI void APIENTRY glBindRenderbufferEXT (GLenum target, GLuint renderbuffer); -GLAPI void APIENTRY glDeleteRenderbuffersEXT (GLsizei n, const GLuint *renderbuffers); -GLAPI void APIENTRY glGenRenderbuffersEXT (GLsizei n, GLuint *renderbuffers); -GLAPI void APIENTRY glRenderbufferStorageEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetRenderbufferParameterivEXT (GLenum target, GLenum pname, GLint *params); -GLAPI GLboolean APIENTRY glIsFramebufferEXT (GLuint framebuffer); -GLAPI void APIENTRY glBindFramebufferEXT (GLenum target, GLuint framebuffer); -GLAPI void APIENTRY glDeleteFramebuffersEXT (GLsizei n, const GLuint *framebuffers); -GLAPI void APIENTRY glGenFramebuffersEXT (GLsizei n, GLuint *framebuffers); -GLAPI GLenum APIENTRY glCheckFramebufferStatusEXT (GLenum target); -GLAPI void APIENTRY glFramebufferTexture1DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLAPI void APIENTRY glFramebufferTexture2DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLAPI void APIENTRY glFramebufferTexture3DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -GLAPI void APIENTRY glFramebufferRenderbufferEXT (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -GLAPI void APIENTRY glGetFramebufferAttachmentParameterivEXT (GLenum target, GLenum attachment, GLenum pname, GLint *params); -GLAPI void APIENTRY glGenerateMipmapEXT (GLenum target); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFEREXTPROC) (GLuint renderbuffer); -typedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC) (GLenum target, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers); -typedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC) (GLsizei n, GLuint *renderbuffers); -typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); -typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFEREXTPROC) (GLuint framebuffer); -typedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint framebuffer); -typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint *framebuffers); -typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers); -typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum target); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC) (GLenum target); -#endif - -#ifndef GL_GREMEDY_string_marker -#define GL_GREMEDY_string_marker 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glStringMarkerGREMEDY (GLsizei len, const GLvoid *string); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLSTRINGMARKERGREMEDYPROC) (GLsizei len, const GLvoid *string); -#endif - -#ifndef GL_EXT_packed_depth_stencil -#define GL_EXT_packed_depth_stencil 1 -#endif - -#ifndef GL_EXT_stencil_clear_tag -#define GL_EXT_stencil_clear_tag 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glStencilClearTagEXT (GLsizei stencilTagBits, GLuint stencilClearTag); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLSTENCILCLEARTAGEXTPROC) (GLsizei stencilTagBits, GLuint stencilClearTag); -#endif - -#ifndef GL_EXT_texture_sRGB -#define GL_EXT_texture_sRGB 1 -#endif - -#ifndef GL_EXT_framebuffer_blit -#define GL_EXT_framebuffer_blit 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlitFramebufferEXT (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBLITFRAMEBUFFEREXTPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -#endif - -#ifndef GL_EXT_framebuffer_multisample -#define GL_EXT_framebuffer_multisample 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glRenderbufferStorageMultisampleEXT (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -#endif - -#ifndef GL_MESAX_texture_stack -#define GL_MESAX_texture_stack 1 -#endif - -#ifndef GL_EXT_timer_query -#define GL_EXT_timer_query 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetQueryObjecti64vEXT (GLuint id, GLenum pname, GLint64EXT *params); -GLAPI void APIENTRY glGetQueryObjectui64vEXT (GLuint id, GLenum pname, GLuint64EXT *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VEXTPROC) (GLuint id, GLenum pname, GLint64EXT *params); -typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VEXTPROC) (GLuint id, GLenum pname, GLuint64EXT *params); -#endif - -#ifndef GL_EXT_gpu_program_parameters -#define GL_EXT_gpu_program_parameters 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProgramEnvParameters4fvEXT (GLenum target, GLuint index, GLsizei count, const GLfloat *params); -GLAPI void APIENTRY glProgramLocalParameters4fvEXT (GLenum target, GLuint index, GLsizei count, const GLfloat *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERS4FVEXTPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *params); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *params); -#endif - -#ifndef GL_APPLE_flush_buffer_range -#define GL_APPLE_flush_buffer_range 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBufferParameteriAPPLE (GLenum target, GLenum pname, GLint param); -GLAPI void APIENTRY glFlushMappedBufferRangeAPPLE (GLenum target, GLintptr offset, GLsizeiptr size); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBUFFERPARAMETERIAPPLEPROC) (GLenum target, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC) (GLenum target, GLintptr offset, GLsizeiptr size); -#endif - -#ifndef GL_NV_gpu_program4 -#define GL_NV_gpu_program4 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProgramLocalParameterI4iNV (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); -GLAPI void APIENTRY glProgramLocalParameterI4ivNV (GLenum target, GLuint index, const GLint *params); -GLAPI void APIENTRY glProgramLocalParametersI4ivNV (GLenum target, GLuint index, GLsizei count, const GLint *params); -GLAPI void APIENTRY glProgramLocalParameterI4uiNV (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -GLAPI void APIENTRY glProgramLocalParameterI4uivNV (GLenum target, GLuint index, const GLuint *params); -GLAPI void APIENTRY glProgramLocalParametersI4uivNV (GLenum target, GLuint index, GLsizei count, const GLuint *params); -GLAPI void APIENTRY glProgramEnvParameterI4iNV (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); -GLAPI void APIENTRY glProgramEnvParameterI4ivNV (GLenum target, GLuint index, const GLint *params); -GLAPI void APIENTRY glProgramEnvParametersI4ivNV (GLenum target, GLuint index, GLsizei count, const GLint *params); -GLAPI void APIENTRY glProgramEnvParameterI4uiNV (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -GLAPI void APIENTRY glProgramEnvParameterI4uivNV (GLenum target, GLuint index, const GLuint *params); -GLAPI void APIENTRY glProgramEnvParametersI4uivNV (GLenum target, GLuint index, GLsizei count, const GLuint *params); -GLAPI void APIENTRY glGetProgramLocalParameterIivNV (GLenum target, GLuint index, GLint *params); -GLAPI void APIENTRY glGetProgramLocalParameterIuivNV (GLenum target, GLuint index, GLuint *params); -GLAPI void APIENTRY glGetProgramEnvParameterIivNV (GLenum target, GLuint index, GLint *params); -GLAPI void APIENTRY glGetProgramEnvParameterIuivNV (GLenum target, GLuint index, GLuint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4INVPROC) (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4IVNVPROC) (GLenum target, GLuint index, const GLint *params); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERSI4IVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLint *params); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4UINVPROC) (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4UIVNVPROC) (GLenum target, GLuint index, const GLuint *params); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERSI4UIVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLuint *params); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4INVPROC) (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4IVNVPROC) (GLenum target, GLuint index, const GLint *params); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERSI4IVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLint *params); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4UINVPROC) (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4UIVNVPROC) (GLenum target, GLuint index, const GLuint *params); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERSI4UIVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLuint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERIIVNVPROC) (GLenum target, GLuint index, GLint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERIUIVNVPROC) (GLenum target, GLuint index, GLuint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERIIVNVPROC) (GLenum target, GLuint index, GLint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERIUIVNVPROC) (GLenum target, GLuint index, GLuint *params); -#endif - -#ifndef GL_NV_geometry_program4 -#define GL_NV_geometry_program4 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProgramVertexLimitNV (GLenum target, GLint limit); -GLAPI void APIENTRY glFramebufferTextureEXT (GLenum target, GLenum attachment, GLuint texture, GLint level); -GLAPI void APIENTRY glFramebufferTextureLayerEXT (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -GLAPI void APIENTRY glFramebufferTextureFaceEXT (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPROGRAMVERTEXLIMITNVPROC) (GLenum target, GLint limit); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); -#endif - -#ifndef GL_EXT_geometry_shader4 -#define GL_EXT_geometry_shader4 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProgramParameteriEXT (GLuint program, GLenum pname, GLint value); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value); -#endif - -#ifndef GL_NV_vertex_program4 -#define GL_NV_vertex_program4 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexAttribI1iEXT (GLuint index, GLint x); -GLAPI void APIENTRY glVertexAttribI2iEXT (GLuint index, GLint x, GLint y); -GLAPI void APIENTRY glVertexAttribI3iEXT (GLuint index, GLint x, GLint y, GLint z); -GLAPI void APIENTRY glVertexAttribI4iEXT (GLuint index, GLint x, GLint y, GLint z, GLint w); -GLAPI void APIENTRY glVertexAttribI1uiEXT (GLuint index, GLuint x); -GLAPI void APIENTRY glVertexAttribI2uiEXT (GLuint index, GLuint x, GLuint y); -GLAPI void APIENTRY glVertexAttribI3uiEXT (GLuint index, GLuint x, GLuint y, GLuint z); -GLAPI void APIENTRY glVertexAttribI4uiEXT (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -GLAPI void APIENTRY glVertexAttribI1ivEXT (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttribI2ivEXT (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttribI3ivEXT (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttribI4ivEXT (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttribI1uivEXT (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttribI2uivEXT (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttribI3uivEXT (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttribI4uivEXT (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttribI4bvEXT (GLuint index, const GLbyte *v); -GLAPI void APIENTRY glVertexAttribI4svEXT (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttribI4ubvEXT (GLuint index, const GLubyte *v); -GLAPI void APIENTRY glVertexAttribI4usvEXT (GLuint index, const GLushort *v); -GLAPI void APIENTRY glVertexAttribIPointerEXT (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -GLAPI void APIENTRY glGetVertexAttribIivEXT (GLuint index, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVertexAttribIuivEXT (GLuint index, GLenum pname, GLuint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IEXTPROC) (GLuint index, GLint x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IEXTPROC) (GLuint index, GLint x, GLint y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IEXTPROC) (GLuint index, GLint x, GLint y, GLint z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IEXTPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIEXTPROC) (GLuint index, GLuint x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIEXTPROC) (GLuint index, GLuint x, GLuint y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVEXTPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVEXTPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVEXTPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVEXTPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVEXTPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVEXTPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVEXTPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVEXTPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVEXTPROC) (GLuint index, const GLbyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVEXTPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVEXTPROC) (GLuint index, const GLubyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVEXTPROC) (GLuint index, const GLushort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVEXTPROC) (GLuint index, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVEXTPROC) (GLuint index, GLenum pname, GLuint *params); -#endif - -#ifndef GL_EXT_gpu_shader4 -#define GL_EXT_gpu_shader4 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetUniformuivEXT (GLuint program, GLint location, GLuint *params); -GLAPI void APIENTRY glBindFragDataLocationEXT (GLuint program, GLuint color, const GLchar *name); -GLAPI GLint APIENTRY glGetFragDataLocationEXT (GLuint program, const GLchar *name); -GLAPI void APIENTRY glUniform1uiEXT (GLint location, GLuint v0); -GLAPI void APIENTRY glUniform2uiEXT (GLint location, GLuint v0, GLuint v1); -GLAPI void APIENTRY glUniform3uiEXT (GLint location, GLuint v0, GLuint v1, GLuint v2); -GLAPI void APIENTRY glUniform4uiEXT (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -GLAPI void APIENTRY glUniform1uivEXT (GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glUniform2uivEXT (GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glUniform3uivEXT (GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glUniform4uivEXT (GLint location, GLsizei count, const GLuint *value); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGETUNIFORMUIVEXTPROC) (GLuint program, GLint location, GLuint *params); -typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONEXTPROC) (GLuint program, GLuint color, const GLchar *name); -typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONEXTPROC) (GLuint program, const GLchar *name); -typedef void (APIENTRYP PFNGLUNIFORM1UIEXTPROC) (GLint location, GLuint v0); -typedef void (APIENTRYP PFNGLUNIFORM2UIEXTPROC) (GLint location, GLuint v0, GLuint v1); -typedef void (APIENTRYP PFNGLUNIFORM3UIEXTPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2); -typedef void (APIENTRYP PFNGLUNIFORM4UIEXTPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -typedef void (APIENTRYP PFNGLUNIFORM1UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLUNIFORM2UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLUNIFORM3UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLUNIFORM4UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); -#endif - -#ifndef GL_EXT_draw_instanced -#define GL_EXT_draw_instanced 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawArraysInstancedEXT (GLenum mode, GLint start, GLsizei count, GLsizei primcount); -GLAPI void APIENTRY glDrawElementsInstancedEXT (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); -#endif - -#ifndef GL_EXT_packed_float -#define GL_EXT_packed_float 1 -#endif - -#ifndef GL_EXT_texture_array -#define GL_EXT_texture_array 1 -#endif - -#ifndef GL_EXT_texture_buffer_object -#define GL_EXT_texture_buffer_object 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexBufferEXT (GLenum target, GLenum internalformat, GLuint buffer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTEXBUFFEREXTPROC) (GLenum target, GLenum internalformat, GLuint buffer); -#endif - -#ifndef GL_EXT_texture_compression_latc -#define GL_EXT_texture_compression_latc 1 -#endif - -#ifndef GL_EXT_texture_compression_rgtc -#define GL_EXT_texture_compression_rgtc 1 -#endif - -#ifndef GL_EXT_texture_shared_exponent -#define GL_EXT_texture_shared_exponent 1 -#endif - -#ifndef GL_NV_depth_buffer_float -#define GL_NV_depth_buffer_float 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDepthRangedNV (GLdouble zNear, GLdouble zFar); -GLAPI void APIENTRY glClearDepthdNV (GLdouble depth); -GLAPI void APIENTRY glDepthBoundsdNV (GLdouble zmin, GLdouble zmax); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDEPTHRANGEDNVPROC) (GLdouble zNear, GLdouble zFar); -typedef void (APIENTRYP PFNGLCLEARDEPTHDNVPROC) (GLdouble depth); -typedef void (APIENTRYP PFNGLDEPTHBOUNDSDNVPROC) (GLdouble zmin, GLdouble zmax); -#endif - -#ifndef GL_NV_fragment_program4 -#define GL_NV_fragment_program4 1 -#endif - -#ifndef GL_NV_framebuffer_multisample_coverage -#define GL_NV_framebuffer_multisample_coverage 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glRenderbufferStorageMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); -#endif - -#ifndef GL_EXT_framebuffer_sRGB -#define GL_EXT_framebuffer_sRGB 1 -#endif - -#ifndef GL_NV_geometry_shader4 -#define GL_NV_geometry_shader4 1 -#endif - -#ifndef GL_NV_parameter_buffer_object -#define GL_NV_parameter_buffer_object 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProgramBufferParametersfvNV (GLenum target, GLuint buffer, GLuint index, GLsizei count, const GLfloat *params); -GLAPI void APIENTRY glProgramBufferParametersIivNV (GLenum target, GLuint buffer, GLuint index, GLsizei count, const GLint *params); -GLAPI void APIENTRY glProgramBufferParametersIuivNV (GLenum target, GLuint buffer, GLuint index, GLsizei count, const GLuint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSFVNVPROC) (GLenum target, GLuint buffer, GLuint index, GLsizei count, const GLfloat *params); -typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSIIVNVPROC) (GLenum target, GLuint buffer, GLuint index, GLsizei count, const GLint *params); -typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSIUIVNVPROC) (GLenum target, GLuint buffer, GLuint index, GLsizei count, const GLuint *params); -#endif - -#ifndef GL_EXT_draw_buffers2 -#define GL_EXT_draw_buffers2 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColorMaskIndexedEXT (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); -GLAPI void APIENTRY glGetBooleanIndexedvEXT (GLenum target, GLuint index, GLboolean *data); -GLAPI void APIENTRY glGetIntegerIndexedvEXT (GLenum target, GLuint index, GLint *data); -GLAPI void APIENTRY glEnableIndexedEXT (GLenum target, GLuint index); -GLAPI void APIENTRY glDisableIndexedEXT (GLenum target, GLuint index); -GLAPI GLboolean APIENTRY glIsEnabledIndexedEXT (GLenum target, GLuint index); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCOLORMASKINDEXEDEXTPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); -typedef void (APIENTRYP PFNGLGETBOOLEANINDEXEDVEXTPROC) (GLenum target, GLuint index, GLboolean *data); -typedef void (APIENTRYP PFNGLGETINTEGERINDEXEDVEXTPROC) (GLenum target, GLuint index, GLint *data); -typedef void (APIENTRYP PFNGLENABLEINDEXEDEXTPROC) (GLenum target, GLuint index); -typedef void (APIENTRYP PFNGLDISABLEINDEXEDEXTPROC) (GLenum target, GLuint index); -typedef GLboolean (APIENTRYP PFNGLISENABLEDINDEXEDEXTPROC) (GLenum target, GLuint index); -#endif - -#ifndef GL_NV_transform_feedback -#define GL_NV_transform_feedback 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBeginTransformFeedbackNV (GLenum primitiveMode); -GLAPI void APIENTRY glEndTransformFeedbackNV (void); -GLAPI void APIENTRY glTransformFeedbackAttribsNV (GLuint count, const GLint *attribs, GLenum bufferMode); -GLAPI void APIENTRY glBindBufferRangeNV (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -GLAPI void APIENTRY glBindBufferOffsetNV (GLenum target, GLuint index, GLuint buffer, GLintptr offset); -GLAPI void APIENTRY glBindBufferBaseNV (GLenum target, GLuint index, GLuint buffer); -GLAPI void APIENTRY glTransformFeedbackVaryingsNV (GLuint program, GLsizei count, const GLint *locations, GLenum bufferMode); -GLAPI void APIENTRY glActiveVaryingNV (GLuint program, const GLchar *name); -GLAPI GLint APIENTRY glGetVaryingLocationNV (GLuint program, const GLchar *name); -GLAPI void APIENTRY glGetActiveVaryingNV (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); -GLAPI void APIENTRY glGetTransformFeedbackVaryingNV (GLuint program, GLuint index, GLint *location); -GLAPI void APIENTRY glTransformFeedbackStreamAttribsNV (GLsizei count, const GLint *attribs, GLsizei nbuffers, const GLint *bufstreams, GLenum bufferMode); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKNVPROC) (GLenum primitiveMode); -typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKNVPROC) (void); -typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKATTRIBSNVPROC) (GLuint count, const GLint *attribs, GLenum bufferMode); -typedef void (APIENTRYP PFNGLBINDBUFFERRANGENVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -typedef void (APIENTRYP PFNGLBINDBUFFEROFFSETNVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset); -typedef void (APIENTRYP PFNGLBINDBUFFERBASENVPROC) (GLenum target, GLuint index, GLuint buffer); -typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSNVPROC) (GLuint program, GLsizei count, const GLint *locations, GLenum bufferMode); -typedef void (APIENTRYP PFNGLACTIVEVARYINGNVPROC) (GLuint program, const GLchar *name); -typedef GLint (APIENTRYP PFNGLGETVARYINGLOCATIONNVPROC) (GLuint program, const GLchar *name); -typedef void (APIENTRYP PFNGLGETACTIVEVARYINGNVPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); -typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGNVPROC) (GLuint program, GLuint index, GLint *location); -typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKSTREAMATTRIBSNVPROC) (GLsizei count, const GLint *attribs, GLsizei nbuffers, const GLint *bufstreams, GLenum bufferMode); -#endif - -#ifndef GL_EXT_bindable_uniform -#define GL_EXT_bindable_uniform 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glUniformBufferEXT (GLuint program, GLint location, GLuint buffer); -GLAPI GLint APIENTRY glGetUniformBufferSizeEXT (GLuint program, GLint location); -GLAPI GLintptr APIENTRY glGetUniformOffsetEXT (GLuint program, GLint location); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLUNIFORMBUFFEREXTPROC) (GLuint program, GLint location, GLuint buffer); -typedef GLint (APIENTRYP PFNGLGETUNIFORMBUFFERSIZEEXTPROC) (GLuint program, GLint location); -typedef GLintptr (APIENTRYP PFNGLGETUNIFORMOFFSETEXTPROC) (GLuint program, GLint location); -#endif - -#ifndef GL_EXT_texture_integer -#define GL_EXT_texture_integer 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexParameterIivEXT (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glTexParameterIuivEXT (GLenum target, GLenum pname, const GLuint *params); -GLAPI void APIENTRY glGetTexParameterIivEXT (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetTexParameterIuivEXT (GLenum target, GLenum pname, GLuint *params); -GLAPI void APIENTRY glClearColorIiEXT (GLint red, GLint green, GLint blue, GLint alpha); -GLAPI void APIENTRY glClearColorIuiEXT (GLuint red, GLuint green, GLuint blue, GLuint alpha); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, const GLuint *params); -typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLCLEARCOLORIIEXTPROC) (GLint red, GLint green, GLint blue, GLint alpha); -typedef void (APIENTRYP PFNGLCLEARCOLORIUIEXTPROC) (GLuint red, GLuint green, GLuint blue, GLuint alpha); -#endif - -#ifndef GL_GREMEDY_frame_terminator -#define GL_GREMEDY_frame_terminator 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFrameTerminatorGREMEDY (void); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLFRAMETERMINATORGREMEDYPROC) (void); -#endif - -#ifndef GL_NV_conditional_render -#define GL_NV_conditional_render 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBeginConditionalRenderNV (GLuint id, GLenum mode); -GLAPI void APIENTRY glEndConditionalRenderNV (void); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERNVPROC) (GLuint id, GLenum mode); -typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERNVPROC) (void); -#endif - -#ifndef GL_NV_present_video -#define GL_NV_present_video 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPresentFrameKeyedNV (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLuint key0, GLenum target1, GLuint fill1, GLuint key1); -GLAPI void APIENTRY glPresentFrameDualFillNV (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLenum target1, GLuint fill1, GLenum target2, GLuint fill2, GLenum target3, GLuint fill3); -GLAPI void APIENTRY glGetVideoivNV (GLuint video_slot, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVideouivNV (GLuint video_slot, GLenum pname, GLuint *params); -GLAPI void APIENTRY glGetVideoi64vNV (GLuint video_slot, GLenum pname, GLint64EXT *params); -GLAPI void APIENTRY glGetVideoui64vNV (GLuint video_slot, GLenum pname, GLuint64EXT *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPRESENTFRAMEKEYEDNVPROC) (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLuint key0, GLenum target1, GLuint fill1, GLuint key1); -typedef void (APIENTRYP PFNGLPRESENTFRAMEDUALFILLNVPROC) (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLenum target1, GLuint fill1, GLenum target2, GLuint fill2, GLenum target3, GLuint fill3); -typedef void (APIENTRYP PFNGLGETVIDEOIVNVPROC) (GLuint video_slot, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVIDEOUIVNVPROC) (GLuint video_slot, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLGETVIDEOI64VNVPROC) (GLuint video_slot, GLenum pname, GLint64EXT *params); -typedef void (APIENTRYP PFNGLGETVIDEOUI64VNVPROC) (GLuint video_slot, GLenum pname, GLuint64EXT *params); -#endif - -#ifndef GL_EXT_transform_feedback -#define GL_EXT_transform_feedback 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBeginTransformFeedbackEXT (GLenum primitiveMode); -GLAPI void APIENTRY glEndTransformFeedbackEXT (void); -GLAPI void APIENTRY glBindBufferRangeEXT (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -GLAPI void APIENTRY glBindBufferOffsetEXT (GLenum target, GLuint index, GLuint buffer, GLintptr offset); -GLAPI void APIENTRY glBindBufferBaseEXT (GLenum target, GLuint index, GLuint buffer); -GLAPI void APIENTRY glTransformFeedbackVaryingsEXT (GLuint program, GLsizei count, const GLchar* *varyings, GLenum bufferMode); -GLAPI void APIENTRY glGetTransformFeedbackVaryingEXT (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKEXTPROC) (GLenum primitiveMode); -typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKEXTPROC) (void); -typedef void (APIENTRYP PFNGLBINDBUFFERRANGEEXTPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -typedef void (APIENTRYP PFNGLBINDBUFFEROFFSETEXTPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset); -typedef void (APIENTRYP PFNGLBINDBUFFERBASEEXTPROC) (GLenum target, GLuint index, GLuint buffer); -typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSEXTPROC) (GLuint program, GLsizei count, const GLchar* *varyings, GLenum bufferMode); -typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGEXTPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); -#endif - -#ifndef GL_EXT_direct_state_access -#define GL_EXT_direct_state_access 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glClientAttribDefaultEXT (GLbitfield mask); -GLAPI void APIENTRY glPushClientAttribDefaultEXT (GLbitfield mask); -GLAPI void APIENTRY glMatrixLoadfEXT (GLenum mode, const GLfloat *m); -GLAPI void APIENTRY glMatrixLoaddEXT (GLenum mode, const GLdouble *m); -GLAPI void APIENTRY glMatrixMultfEXT (GLenum mode, const GLfloat *m); -GLAPI void APIENTRY glMatrixMultdEXT (GLenum mode, const GLdouble *m); -GLAPI void APIENTRY glMatrixLoadIdentityEXT (GLenum mode); -GLAPI void APIENTRY glMatrixRotatefEXT (GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glMatrixRotatedEXT (GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glMatrixScalefEXT (GLenum mode, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glMatrixScaledEXT (GLenum mode, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glMatrixTranslatefEXT (GLenum mode, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glMatrixTranslatedEXT (GLenum mode, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glMatrixFrustumEXT (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); -GLAPI void APIENTRY glMatrixOrthoEXT (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); -GLAPI void APIENTRY glMatrixPopEXT (GLenum mode); -GLAPI void APIENTRY glMatrixPushEXT (GLenum mode); -GLAPI void APIENTRY glMatrixLoadTransposefEXT (GLenum mode, const GLfloat *m); -GLAPI void APIENTRY glMatrixLoadTransposedEXT (GLenum mode, const GLdouble *m); -GLAPI void APIENTRY glMatrixMultTransposefEXT (GLenum mode, const GLfloat *m); -GLAPI void APIENTRY glMatrixMultTransposedEXT (GLenum mode, const GLdouble *m); -GLAPI void APIENTRY glTextureParameterfEXT (GLuint texture, GLenum target, GLenum pname, GLfloat param); -GLAPI void APIENTRY glTextureParameterfvEXT (GLuint texture, GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glTextureParameteriEXT (GLuint texture, GLenum target, GLenum pname, GLint param); -GLAPI void APIENTRY glTextureParameterivEXT (GLuint texture, GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glCopyTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); -GLAPI void APIENTRY glCopyTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -GLAPI void APIENTRY glCopyTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glCopyTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetTextureImageEXT (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); -GLAPI void APIENTRY glGetTextureParameterfvEXT (GLuint texture, GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetTextureParameterivEXT (GLuint texture, GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetTextureLevelParameterfvEXT (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetTextureLevelParameterivEXT (GLuint texture, GLenum target, GLint level, GLenum pname, GLint *params); -GLAPI void APIENTRY glTextureImage3DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glCopyTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glMultiTexParameterfEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat param); -GLAPI void APIENTRY glMultiTexParameterfvEXT (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glMultiTexParameteriEXT (GLenum texunit, GLenum target, GLenum pname, GLint param); -GLAPI void APIENTRY glMultiTexParameterivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glCopyMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); -GLAPI void APIENTRY glCopyMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -GLAPI void APIENTRY glCopyMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glCopyMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetMultiTexImageEXT (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); -GLAPI void APIENTRY glGetMultiTexParameterfvEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetMultiTexParameterivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetMultiTexLevelParameterfvEXT (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetMultiTexLevelParameterivEXT (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint *params); -GLAPI void APIENTRY glMultiTexImage3DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glCopyMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glBindMultiTextureEXT (GLenum texunit, GLenum target, GLuint texture); -GLAPI void APIENTRY glEnableClientStateIndexedEXT (GLenum array, GLuint index); -GLAPI void APIENTRY glDisableClientStateIndexedEXT (GLenum array, GLuint index); -GLAPI void APIENTRY glMultiTexCoordPointerEXT (GLenum texunit, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -GLAPI void APIENTRY glMultiTexEnvfEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat param); -GLAPI void APIENTRY glMultiTexEnvfvEXT (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glMultiTexEnviEXT (GLenum texunit, GLenum target, GLenum pname, GLint param); -GLAPI void APIENTRY glMultiTexEnvivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glMultiTexGendEXT (GLenum texunit, GLenum coord, GLenum pname, GLdouble param); -GLAPI void APIENTRY glMultiTexGendvEXT (GLenum texunit, GLenum coord, GLenum pname, const GLdouble *params); -GLAPI void APIENTRY glMultiTexGenfEXT (GLenum texunit, GLenum coord, GLenum pname, GLfloat param); -GLAPI void APIENTRY glMultiTexGenfvEXT (GLenum texunit, GLenum coord, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glMultiTexGeniEXT (GLenum texunit, GLenum coord, GLenum pname, GLint param); -GLAPI void APIENTRY glMultiTexGenivEXT (GLenum texunit, GLenum coord, GLenum pname, const GLint *params); -GLAPI void APIENTRY glGetMultiTexEnvfvEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetMultiTexEnvivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetMultiTexGendvEXT (GLenum texunit, GLenum coord, GLenum pname, GLdouble *params); -GLAPI void APIENTRY glGetMultiTexGenfvEXT (GLenum texunit, GLenum coord, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetMultiTexGenivEXT (GLenum texunit, GLenum coord, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetFloatIndexedvEXT (GLenum target, GLuint index, GLfloat *data); -GLAPI void APIENTRY glGetDoubleIndexedvEXT (GLenum target, GLuint index, GLdouble *data); -GLAPI void APIENTRY glGetPointerIndexedvEXT (GLenum target, GLuint index, GLvoid* *data); -GLAPI void APIENTRY glCompressedTextureImage3DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glGetCompressedTextureImageEXT (GLuint texture, GLenum target, GLint lod, GLvoid *img); -GLAPI void APIENTRY glCompressedMultiTexImage3DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glGetCompressedMultiTexImageEXT (GLenum texunit, GLenum target, GLint lod, GLvoid *img); -GLAPI void APIENTRY glNamedProgramStringEXT (GLuint program, GLenum target, GLenum format, GLsizei len, const GLvoid *string); -GLAPI void APIENTRY glNamedProgramLocalParameter4dEXT (GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glNamedProgramLocalParameter4dvEXT (GLuint program, GLenum target, GLuint index, const GLdouble *params); -GLAPI void APIENTRY glNamedProgramLocalParameter4fEXT (GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glNamedProgramLocalParameter4fvEXT (GLuint program, GLenum target, GLuint index, const GLfloat *params); -GLAPI void APIENTRY glGetNamedProgramLocalParameterdvEXT (GLuint program, GLenum target, GLuint index, GLdouble *params); -GLAPI void APIENTRY glGetNamedProgramLocalParameterfvEXT (GLuint program, GLenum target, GLuint index, GLfloat *params); -GLAPI void APIENTRY glGetNamedProgramivEXT (GLuint program, GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetNamedProgramStringEXT (GLuint program, GLenum target, GLenum pname, GLvoid *string); -GLAPI void APIENTRY glNamedProgramLocalParameters4fvEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat *params); -GLAPI void APIENTRY glNamedProgramLocalParameterI4iEXT (GLuint program, GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); -GLAPI void APIENTRY glNamedProgramLocalParameterI4ivEXT (GLuint program, GLenum target, GLuint index, const GLint *params); -GLAPI void APIENTRY glNamedProgramLocalParametersI4ivEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLint *params); -GLAPI void APIENTRY glNamedProgramLocalParameterI4uiEXT (GLuint program, GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -GLAPI void APIENTRY glNamedProgramLocalParameterI4uivEXT (GLuint program, GLenum target, GLuint index, const GLuint *params); -GLAPI void APIENTRY glNamedProgramLocalParametersI4uivEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint *params); -GLAPI void APIENTRY glGetNamedProgramLocalParameterIivEXT (GLuint program, GLenum target, GLuint index, GLint *params); -GLAPI void APIENTRY glGetNamedProgramLocalParameterIuivEXT (GLuint program, GLenum target, GLuint index, GLuint *params); -GLAPI void APIENTRY glTextureParameterIivEXT (GLuint texture, GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glTextureParameterIuivEXT (GLuint texture, GLenum target, GLenum pname, const GLuint *params); -GLAPI void APIENTRY glGetTextureParameterIivEXT (GLuint texture, GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetTextureParameterIuivEXT (GLuint texture, GLenum target, GLenum pname, GLuint *params); -GLAPI void APIENTRY glMultiTexParameterIivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glMultiTexParameterIuivEXT (GLenum texunit, GLenum target, GLenum pname, const GLuint *params); -GLAPI void APIENTRY glGetMultiTexParameterIivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetMultiTexParameterIuivEXT (GLenum texunit, GLenum target, GLenum pname, GLuint *params); -GLAPI void APIENTRY glProgramUniform1fEXT (GLuint program, GLint location, GLfloat v0); -GLAPI void APIENTRY glProgramUniform2fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1); -GLAPI void APIENTRY glProgramUniform3fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -GLAPI void APIENTRY glProgramUniform4fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -GLAPI void APIENTRY glProgramUniform1iEXT (GLuint program, GLint location, GLint v0); -GLAPI void APIENTRY glProgramUniform2iEXT (GLuint program, GLint location, GLint v0, GLint v1); -GLAPI void APIENTRY glProgramUniform3iEXT (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); -GLAPI void APIENTRY glProgramUniform4iEXT (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -GLAPI void APIENTRY glProgramUniform1fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform2fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform3fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform4fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform1ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniform2ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniform3ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniform4ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniformMatrix2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix2x3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix3x2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix2x4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix4x2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix3x4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix4x3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform1uiEXT (GLuint program, GLint location, GLuint v0); -GLAPI void APIENTRY glProgramUniform2uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1); -GLAPI void APIENTRY glProgramUniform3uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); -GLAPI void APIENTRY glProgramUniform4uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -GLAPI void APIENTRY glProgramUniform1uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glProgramUniform2uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glProgramUniform3uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glProgramUniform4uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glNamedBufferDataEXT (GLuint buffer, GLsizeiptr size, const GLvoid *data, GLenum usage); -GLAPI void APIENTRY glNamedBufferSubDataEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, const GLvoid *data); -GLAPI GLvoid* APIENTRY glMapNamedBufferEXT (GLuint buffer, GLenum access); -GLAPI GLboolean APIENTRY glUnmapNamedBufferEXT (GLuint buffer); -GLAPI GLvoid* APIENTRY glMapNamedBufferRangeEXT (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); -GLAPI void APIENTRY glFlushMappedNamedBufferRangeEXT (GLuint buffer, GLintptr offset, GLsizeiptr length); -GLAPI void APIENTRY glNamedCopyBufferSubDataEXT (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); -GLAPI void APIENTRY glGetNamedBufferParameterivEXT (GLuint buffer, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetNamedBufferPointervEXT (GLuint buffer, GLenum pname, GLvoid* *params); -GLAPI void APIENTRY glGetNamedBufferSubDataEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, GLvoid *data); -GLAPI void APIENTRY glTextureBufferEXT (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer); -GLAPI void APIENTRY glMultiTexBufferEXT (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer); -GLAPI void APIENTRY glNamedRenderbufferStorageEXT (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetNamedRenderbufferParameterivEXT (GLuint renderbuffer, GLenum pname, GLint *params); -GLAPI GLenum APIENTRY glCheckNamedFramebufferStatusEXT (GLuint framebuffer, GLenum target); -GLAPI void APIENTRY glNamedFramebufferTexture1DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLAPI void APIENTRY glNamedFramebufferTexture2DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLAPI void APIENTRY glNamedFramebufferTexture3DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -GLAPI void APIENTRY glNamedFramebufferRenderbufferEXT (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -GLAPI void APIENTRY glGetNamedFramebufferAttachmentParameterivEXT (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); -GLAPI void APIENTRY glGenerateTextureMipmapEXT (GLuint texture, GLenum target); -GLAPI void APIENTRY glGenerateMultiTexMipmapEXT (GLenum texunit, GLenum target); -GLAPI void APIENTRY glFramebufferDrawBufferEXT (GLuint framebuffer, GLenum mode); -GLAPI void APIENTRY glFramebufferDrawBuffersEXT (GLuint framebuffer, GLsizei n, const GLenum *bufs); -GLAPI void APIENTRY glFramebufferReadBufferEXT (GLuint framebuffer, GLenum mode); -GLAPI void APIENTRY glGetFramebufferParameterivEXT (GLuint framebuffer, GLenum pname, GLint *params); -GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleEXT (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleCoverageEXT (GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glNamedFramebufferTextureEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); -GLAPI void APIENTRY glNamedFramebufferTextureLayerEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); -GLAPI void APIENTRY glNamedFramebufferTextureFaceEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLenum face); -GLAPI void APIENTRY glTextureRenderbufferEXT (GLuint texture, GLenum target, GLuint renderbuffer); -GLAPI void APIENTRY glMultiTexRenderbufferEXT (GLenum texunit, GLenum target, GLuint renderbuffer); -GLAPI void APIENTRY glProgramUniform1dEXT (GLuint program, GLint location, GLdouble x); -GLAPI void APIENTRY glProgramUniform2dEXT (GLuint program, GLint location, GLdouble x, GLdouble y); -GLAPI void APIENTRY glProgramUniform3dEXT (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glProgramUniform4dEXT (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glProgramUniform1dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniform2dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniform3dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniform4dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix2x3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix2x4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix3x2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix3x4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix4x2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix4x3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask); -typedef void (APIENTRYP PFNGLPUSHCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask); -typedef void (APIENTRYP PFNGLMATRIXLOADFEXTPROC) (GLenum mode, const GLfloat *m); -typedef void (APIENTRYP PFNGLMATRIXLOADDEXTPROC) (GLenum mode, const GLdouble *m); -typedef void (APIENTRYP PFNGLMATRIXMULTFEXTPROC) (GLenum mode, const GLfloat *m); -typedef void (APIENTRYP PFNGLMATRIXMULTDEXTPROC) (GLenum mode, const GLdouble *m); -typedef void (APIENTRYP PFNGLMATRIXLOADIDENTITYEXTPROC) (GLenum mode); -typedef void (APIENTRYP PFNGLMATRIXROTATEFEXTPROC) (GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLMATRIXROTATEDEXTPROC) (GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLMATRIXSCALEFEXTPROC) (GLenum mode, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLMATRIXSCALEDEXTPROC) (GLenum mode, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLMATRIXTRANSLATEFEXTPROC) (GLenum mode, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLMATRIXTRANSLATEDEXTPROC) (GLenum mode, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLMATRIXFRUSTUMEXTPROC) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); -typedef void (APIENTRYP PFNGLMATRIXORTHOEXTPROC) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); -typedef void (APIENTRYP PFNGLMATRIXPOPEXTPROC) (GLenum mode); -typedef void (APIENTRYP PFNGLMATRIXPUSHEXTPROC) (GLenum mode); -typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m); -typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m); -typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m); -typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLCOPYTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); -typedef void (APIENTRYP PFNGLCOPYTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); -typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLMULTITEXPARAMETERFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLCOPYMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); -typedef void (APIENTRYP PFNGLCOPYMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); -typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLBINDMULTITEXTUREEXTPROC) (GLenum texunit, GLenum target, GLuint texture); -typedef void (APIENTRYP PFNGLENABLECLIENTSTATEINDEXEDEXTPROC) (GLenum array, GLuint index); -typedef void (APIENTRYP PFNGLDISABLECLIENTSTATEINDEXEDEXTPROC) (GLenum array, GLuint index); -typedef void (APIENTRYP PFNGLMULTITEXCOORDPOINTEREXTPROC) (GLenum texunit, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLMULTITEXENVFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLMULTITEXENVIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLMULTITEXENVIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLMULTITEXGENDEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLdouble param); -typedef void (APIENTRYP PFNGLMULTITEXGENDVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLdouble *params); -typedef void (APIENTRYP PFNGLMULTITEXGENFEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLMULTITEXGENIEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLGETMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETMULTITEXENVIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETMULTITEXGENDVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLdouble *params); -typedef void (APIENTRYP PFNGLGETMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETFLOATINDEXEDVEXTPROC) (GLenum target, GLuint index, GLfloat *data); -typedef void (APIENTRYP PFNGLGETDOUBLEINDEXEDVEXTPROC) (GLenum target, GLuint index, GLdouble *data); -typedef void (APIENTRYP PFNGLGETPOINTERINDEXEDVEXTPROC) (GLenum target, GLuint index, GLvoid* *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint lod, GLvoid *img); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLGETCOMPRESSEDMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint lod, GLvoid *img); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum format, GLsizei len, const GLvoid *string); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLdouble *params); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLfloat *params); -typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERDVEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble *params); -typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERFVEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat *params); -typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMIVEXTPROC) (GLuint program, GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum pname, GLvoid *string); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat *params); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4IEXTPROC) (GLuint program, GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4IVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLint *params); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERSI4IVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLint *params); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIEXTPROC) (GLuint program, GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLuint *params); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERSI4UIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint *params); -typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERIIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLint *params); -typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERIUIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLuint *params); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIUIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLuint *params); -typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIUIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIUIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLuint *params); -typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIUIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat v0); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint v0); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIEXTPROC) (GLuint program, GLint location, GLuint v0); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLsizeiptr size, const GLvoid *data, GLenum usage); -typedef void (APIENTRYP PFNGLNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, const GLvoid *data); -typedef GLvoid* (APIENTRYP PFNGLMAPNAMEDBUFFEREXTPROC) (GLuint buffer, GLenum access); -typedef GLboolean (APIENTRYP PFNGLUNMAPNAMEDBUFFEREXTPROC) (GLuint buffer); -typedef GLvoid* (APIENTRYP PFNGLMAPNAMEDBUFFERRANGEEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); -typedef void (APIENTRYP PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length); -typedef void (APIENTRYP PFNGLNAMEDCOPYBUFFERSUBDATAEXTPROC) (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); -typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERIVEXTPROC) (GLuint buffer, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPOINTERVEXTPROC) (GLuint buffer, GLenum pname, GLvoid* *params); -typedef void (APIENTRYP PFNGLGETNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, GLvoid *data); -typedef void (APIENTRYP PFNGLTEXTUREBUFFEREXTPROC) (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer); -typedef void (APIENTRYP PFNGLMULTITEXBUFFEREXTPROC) (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer); -typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEEXTPROC) (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETNAMEDRENDERBUFFERPARAMETERIVEXTPROC) (GLuint renderbuffer, GLenum pname, GLint *params); -typedef GLenum (APIENTRYP PFNGLCHECKNAMEDFRAMEBUFFERSTATUSEXTPROC) (GLuint framebuffer, GLenum target); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE1DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE2DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE3DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERRENDERBUFFEREXTPROC) (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGENERATETEXTUREMIPMAPEXTPROC) (GLuint texture, GLenum target); -typedef void (APIENTRYP PFNGLGENERATEMULTITEXMIPMAPEXTPROC) (GLenum texunit, GLenum target); -typedef void (APIENTRYP PFNGLFRAMEBUFFERDRAWBUFFEREXTPROC) (GLuint framebuffer, GLenum mode); -typedef void (APIENTRYP PFNGLFRAMEBUFFERDRAWBUFFERSEXTPROC) (GLuint framebuffer, GLsizei n, const GLenum *bufs); -typedef void (APIENTRYP PFNGLFRAMEBUFFERREADBUFFEREXTPROC) (GLuint framebuffer, GLenum mode); -typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLECOVERAGEEXTPROC) (GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREEXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURELAYEREXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREFACEEXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLenum face); -typedef void (APIENTRYP PFNGLTEXTURERENDERBUFFEREXTPROC) (GLuint texture, GLenum target, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLMULTITEXRENDERBUFFEREXTPROC) (GLenum texunit, GLenum target, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DEXTPROC) (GLuint program, GLint location, GLdouble x); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -#endif - -#ifndef GL_EXT_vertex_array_bgra -#define GL_EXT_vertex_array_bgra 1 -#endif - -#ifndef GL_EXT_texture_swizzle -#define GL_EXT_texture_swizzle 1 -#endif - -#ifndef GL_NV_explicit_multisample -#define GL_NV_explicit_multisample 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetMultisamplefvNV (GLenum pname, GLuint index, GLfloat *val); -GLAPI void APIENTRY glSampleMaskIndexedNV (GLuint index, GLbitfield mask); -GLAPI void APIENTRY glTexRenderbufferNV (GLenum target, GLuint renderbuffer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVNVPROC) (GLenum pname, GLuint index, GLfloat *val); -typedef void (APIENTRYP PFNGLSAMPLEMASKINDEXEDNVPROC) (GLuint index, GLbitfield mask); -typedef void (APIENTRYP PFNGLTEXRENDERBUFFERNVPROC) (GLenum target, GLuint renderbuffer); -#endif - -#ifndef GL_NV_transform_feedback2 -#define GL_NV_transform_feedback2 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBindTransformFeedbackNV (GLenum target, GLuint id); -GLAPI void APIENTRY glDeleteTransformFeedbacksNV (GLsizei n, const GLuint *ids); -GLAPI void APIENTRY glGenTransformFeedbacksNV (GLsizei n, GLuint *ids); -GLAPI GLboolean APIENTRY glIsTransformFeedbackNV (GLuint id); -GLAPI void APIENTRY glPauseTransformFeedbackNV (void); -GLAPI void APIENTRY glResumeTransformFeedbackNV (void); -GLAPI void APIENTRY glDrawTransformFeedbackNV (GLenum mode, GLuint id); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKNVPROC) (GLenum target, GLuint id); -typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSNVPROC) (GLsizei n, const GLuint *ids); -typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSNVPROC) (GLsizei n, GLuint *ids); -typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKNVPROC) (GLuint id); -typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKNVPROC) (void); -typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKNVPROC) (void); -typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKNVPROC) (GLenum mode, GLuint id); -#endif - -#ifndef GL_ATI_meminfo -#define GL_ATI_meminfo 1 -#endif - -#ifndef GL_AMD_performance_monitor -#define GL_AMD_performance_monitor 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetPerfMonitorGroupsAMD (GLint *numGroups, GLsizei groupsSize, GLuint *groups); -GLAPI void APIENTRY glGetPerfMonitorCountersAMD (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); -GLAPI void APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString); -GLAPI void APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString); -GLAPI void APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, GLvoid *data); -GLAPI void APIENTRY glGenPerfMonitorsAMD (GLsizei n, GLuint *monitors); -GLAPI void APIENTRY glDeletePerfMonitorsAMD (GLsizei n, GLuint *monitors); -GLAPI void APIENTRY glSelectPerfMonitorCountersAMD (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList); -GLAPI void APIENTRY glBeginPerfMonitorAMD (GLuint monitor); -GLAPI void APIENTRY glEndPerfMonitorAMD (GLuint monitor); -GLAPI void APIENTRY glGetPerfMonitorCounterDataAMD (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC) (GLint *numGroups, GLsizei groupsSize, GLuint *groups); -typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); -typedef void (APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString); -typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString); -typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, GLvoid *data); -typedef void (APIENTRYP PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors); -typedef void (APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors); -typedef void (APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC) (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList); -typedef void (APIENTRYP PFNGLBEGINPERFMONITORAMDPROC) (GLuint monitor); -typedef void (APIENTRYP PFNGLENDPERFMONITORAMDPROC) (GLuint monitor); -typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten); -#endif - -#ifndef GL_AMD_texture_texture4 -#define GL_AMD_texture_texture4 1 -#endif - -#ifndef GL_AMD_vertex_shader_tesselator -#define GL_AMD_vertex_shader_tesselator 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTessellationFactorAMD (GLfloat factor); -GLAPI void APIENTRY glTessellationModeAMD (GLenum mode); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTESSELLATIONFACTORAMDPROC) (GLfloat factor); -typedef void (APIENTRYP PFNGLTESSELLATIONMODEAMDPROC) (GLenum mode); -#endif - -#ifndef GL_EXT_provoking_vertex -#define GL_EXT_provoking_vertex 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProvokingVertexEXT (GLenum mode); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPROVOKINGVERTEXEXTPROC) (GLenum mode); -#endif - -#ifndef GL_EXT_texture_snorm -#define GL_EXT_texture_snorm 1 -#endif - -#ifndef GL_AMD_draw_buffers_blend -#define GL_AMD_draw_buffers_blend 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendFuncIndexedAMD (GLuint buf, GLenum src, GLenum dst); -GLAPI void APIENTRY glBlendFuncSeparateIndexedAMD (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); -GLAPI void APIENTRY glBlendEquationIndexedAMD (GLuint buf, GLenum mode); -GLAPI void APIENTRY glBlendEquationSeparateIndexedAMD (GLuint buf, GLenum modeRGB, GLenum modeAlpha); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBLENDFUNCINDEXEDAMDPROC) (GLuint buf, GLenum src, GLenum dst); -typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINDEXEDAMDPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); -typedef void (APIENTRYP PFNGLBLENDEQUATIONINDEXEDAMDPROC) (GLuint buf, GLenum mode); -typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEINDEXEDAMDPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); -#endif - -#ifndef GL_APPLE_texture_range -#define GL_APPLE_texture_range 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTextureRangeAPPLE (GLenum target, GLsizei length, const GLvoid *pointer); -GLAPI void APIENTRY glGetTexParameterPointervAPPLE (GLenum target, GLenum pname, GLvoid* *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTEXTURERANGEAPPLEPROC) (GLenum target, GLsizei length, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLGETTEXPARAMETERPOINTERVAPPLEPROC) (GLenum target, GLenum pname, GLvoid* *params); -#endif - -#ifndef GL_APPLE_float_pixels -#define GL_APPLE_float_pixels 1 -#endif - -#ifndef GL_APPLE_vertex_program_evaluators -#define GL_APPLE_vertex_program_evaluators 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glEnableVertexAttribAPPLE (GLuint index, GLenum pname); -GLAPI void APIENTRY glDisableVertexAttribAPPLE (GLuint index, GLenum pname); -GLAPI GLboolean APIENTRY glIsVertexAttribEnabledAPPLE (GLuint index, GLenum pname); -GLAPI void APIENTRY glMapVertexAttrib1dAPPLE (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); -GLAPI void APIENTRY glMapVertexAttrib1fAPPLE (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); -GLAPI void APIENTRY glMapVertexAttrib2dAPPLE (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); -GLAPI void APIENTRY glMapVertexAttrib2fAPPLE (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBAPPLEPROC) (GLuint index, GLenum pname); -typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBAPPLEPROC) (GLuint index, GLenum pname); -typedef GLboolean (APIENTRYP PFNGLISVERTEXATTRIBENABLEDAPPLEPROC) (GLuint index, GLenum pname); -typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB1DAPPLEPROC) (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); -typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB1FAPPLEPROC) (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); -typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB2DAPPLEPROC) (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); -typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB2FAPPLEPROC) (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); -#endif - -#ifndef GL_APPLE_aux_depth_stencil -#define GL_APPLE_aux_depth_stencil 1 -#endif - -#ifndef GL_APPLE_object_purgeable -#define GL_APPLE_object_purgeable 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLenum APIENTRY glObjectPurgeableAPPLE (GLenum objectType, GLuint name, GLenum option); -GLAPI GLenum APIENTRY glObjectUnpurgeableAPPLE (GLenum objectType, GLuint name, GLenum option); -GLAPI void APIENTRY glGetObjectParameterivAPPLE (GLenum objectType, GLuint name, GLenum pname, GLint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLenum (APIENTRYP PFNGLOBJECTPURGEABLEAPPLEPROC) (GLenum objectType, GLuint name, GLenum option); -typedef GLenum (APIENTRYP PFNGLOBJECTUNPURGEABLEAPPLEPROC) (GLenum objectType, GLuint name, GLenum option); -typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVAPPLEPROC) (GLenum objectType, GLuint name, GLenum pname, GLint *params); -#endif - -#ifndef GL_APPLE_row_bytes -#define GL_APPLE_row_bytes 1 -#endif - -#ifndef GL_APPLE_rgb_422 -#define GL_APPLE_rgb_422 1 -#endif - -#ifndef GL_NV_video_capture -#define GL_NV_video_capture 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBeginVideoCaptureNV (GLuint video_capture_slot); -GLAPI void APIENTRY glBindVideoCaptureStreamBufferNV (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLintptrARB offset); -GLAPI void APIENTRY glBindVideoCaptureStreamTextureNV (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLenum target, GLuint texture); -GLAPI void APIENTRY glEndVideoCaptureNV (GLuint video_capture_slot); -GLAPI void APIENTRY glGetVideoCaptureivNV (GLuint video_capture_slot, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVideoCaptureStreamivNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVideoCaptureStreamfvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetVideoCaptureStreamdvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLdouble *params); -GLAPI GLenum APIENTRY glVideoCaptureNV (GLuint video_capture_slot, GLuint *sequence_num, GLuint64EXT *capture_time); -GLAPI void APIENTRY glVideoCaptureStreamParameterivNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLint *params); -GLAPI void APIENTRY glVideoCaptureStreamParameterfvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glVideoCaptureStreamParameterdvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLdouble *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBEGINVIDEOCAPTURENVPROC) (GLuint video_capture_slot); -typedef void (APIENTRYP PFNGLBINDVIDEOCAPTURESTREAMBUFFERNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLintptrARB offset); -typedef void (APIENTRYP PFNGLBINDVIDEOCAPTURESTREAMTEXTURENVPROC) (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLenum target, GLuint texture); -typedef void (APIENTRYP PFNGLENDVIDEOCAPTURENVPROC) (GLuint video_capture_slot); -typedef void (APIENTRYP PFNGLGETVIDEOCAPTUREIVNVPROC) (GLuint video_capture_slot, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMIVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMFVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMDVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLdouble *params); -typedef GLenum (APIENTRYP PFNGLVIDEOCAPTURENVPROC) (GLuint video_capture_slot, GLuint *sequence_num, GLuint64EXT *capture_time); -typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERIVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERFVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERDVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLdouble *params); -#endif - -#ifndef GL_NV_copy_image -#define GL_NV_copy_image 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glCopyImageSubDataNV (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCOPYIMAGESUBDATANVPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); -#endif - -#ifndef GL_EXT_separate_shader_objects -#define GL_EXT_separate_shader_objects 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glUseShaderProgramEXT (GLenum type, GLuint program); -GLAPI void APIENTRY glActiveProgramEXT (GLuint program); -GLAPI GLuint APIENTRY glCreateShaderProgramEXT (GLenum type, const GLchar *string); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLUSESHADERPROGRAMEXTPROC) (GLenum type, GLuint program); -typedef void (APIENTRYP PFNGLACTIVEPROGRAMEXTPROC) (GLuint program); -typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMEXTPROC) (GLenum type, const GLchar *string); -#endif - -#ifndef GL_NV_parameter_buffer_object2 -#define GL_NV_parameter_buffer_object2 1 -#endif - -#ifndef GL_NV_shader_buffer_load -#define GL_NV_shader_buffer_load 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMakeBufferResidentNV (GLenum target, GLenum access); -GLAPI void APIENTRY glMakeBufferNonResidentNV (GLenum target); -GLAPI GLboolean APIENTRY glIsBufferResidentNV (GLenum target); -GLAPI void APIENTRY glMakeNamedBufferResidentNV (GLuint buffer, GLenum access); -GLAPI void APIENTRY glMakeNamedBufferNonResidentNV (GLuint buffer); -GLAPI GLboolean APIENTRY glIsNamedBufferResidentNV (GLuint buffer); -GLAPI void APIENTRY glGetBufferParameterui64vNV (GLenum target, GLenum pname, GLuint64EXT *params); -GLAPI void APIENTRY glGetNamedBufferParameterui64vNV (GLuint buffer, GLenum pname, GLuint64EXT *params); -GLAPI void APIENTRY glGetIntegerui64vNV (GLenum value, GLuint64EXT *result); -GLAPI void APIENTRY glUniformui64NV (GLint location, GLuint64EXT value); -GLAPI void APIENTRY glUniformui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glGetUniformui64vNV (GLuint program, GLint location, GLuint64EXT *params); -GLAPI void APIENTRY glProgramUniformui64NV (GLuint program, GLint location, GLuint64EXT value); -GLAPI void APIENTRY glProgramUniformui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLMAKEBUFFERRESIDENTNVPROC) (GLenum target, GLenum access); -typedef void (APIENTRYP PFNGLMAKEBUFFERNONRESIDENTNVPROC) (GLenum target); -typedef GLboolean (APIENTRYP PFNGLISBUFFERRESIDENTNVPROC) (GLenum target); -typedef void (APIENTRYP PFNGLMAKENAMEDBUFFERRESIDENTNVPROC) (GLuint buffer, GLenum access); -typedef void (APIENTRYP PFNGLMAKENAMEDBUFFERNONRESIDENTNVPROC) (GLuint buffer); -typedef GLboolean (APIENTRYP PFNGLISNAMEDBUFFERRESIDENTNVPROC) (GLuint buffer); -typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERUI64VNVPROC) (GLenum target, GLenum pname, GLuint64EXT *params); -typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERUI64VNVPROC) (GLuint buffer, GLenum pname, GLuint64EXT *params); -typedef void (APIENTRYP PFNGLGETINTEGERUI64VNVPROC) (GLenum value, GLuint64EXT *result); -typedef void (APIENTRYP PFNGLUNIFORMUI64NVPROC) (GLint location, GLuint64EXT value); -typedef void (APIENTRYP PFNGLUNIFORMUI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLGETUNIFORMUI64VNVPROC) (GLuint program, GLint location, GLuint64EXT *params); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMUI64NVPROC) (GLuint program, GLint location, GLuint64EXT value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMUI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -#endif - -#ifndef GL_NV_vertex_buffer_unified_memory -#define GL_NV_vertex_buffer_unified_memory 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBufferAddressRangeNV (GLenum pname, GLuint index, GLuint64EXT address, GLsizeiptr length); -GLAPI void APIENTRY glVertexFormatNV (GLint size, GLenum type, GLsizei stride); -GLAPI void APIENTRY glNormalFormatNV (GLenum type, GLsizei stride); -GLAPI void APIENTRY glColorFormatNV (GLint size, GLenum type, GLsizei stride); -GLAPI void APIENTRY glIndexFormatNV (GLenum type, GLsizei stride); -GLAPI void APIENTRY glTexCoordFormatNV (GLint size, GLenum type, GLsizei stride); -GLAPI void APIENTRY glEdgeFlagFormatNV (GLsizei stride); -GLAPI void APIENTRY glSecondaryColorFormatNV (GLint size, GLenum type, GLsizei stride); -GLAPI void APIENTRY glFogCoordFormatNV (GLenum type, GLsizei stride); -GLAPI void APIENTRY glVertexAttribFormatNV (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride); -GLAPI void APIENTRY glVertexAttribIFormatNV (GLuint index, GLint size, GLenum type, GLsizei stride); -GLAPI void APIENTRY glGetIntegerui64i_vNV (GLenum value, GLuint index, GLuint64EXT *result); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBUFFERADDRESSRANGENVPROC) (GLenum pname, GLuint index, GLuint64EXT address, GLsizeiptr length); -typedef void (APIENTRYP PFNGLVERTEXFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLNORMALFORMATNVPROC) (GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLCOLORFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLINDEXFORMATNVPROC) (GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLTEXCOORDFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLEDGEFLAGFORMATNVPROC) (GLsizei stride); -typedef void (APIENTRYP PFNGLSECONDARYCOLORFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLFOGCOORDFORMATNVPROC) (GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride); -typedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLGETINTEGERUI64I_VNVPROC) (GLenum value, GLuint index, GLuint64EXT *result); -#endif - -#ifndef GL_NV_texture_barrier -#define GL_NV_texture_barrier 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTextureBarrierNV (void); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTEXTUREBARRIERNVPROC) (void); -#endif - -#ifndef GL_AMD_shader_stencil_export -#define GL_AMD_shader_stencil_export 1 -#endif - -#ifndef GL_AMD_seamless_cubemap_per_texture -#define GL_AMD_seamless_cubemap_per_texture 1 -#endif - -#ifndef GL_AMD_conservative_depth -#define GL_AMD_conservative_depth 1 -#endif - -#ifndef GL_EXT_shader_image_load_store -#define GL_EXT_shader_image_load_store 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBindImageTextureEXT (GLuint index, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLint format); -GLAPI void APIENTRY glMemoryBarrierEXT (GLbitfield barriers); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREEXTPROC) (GLuint index, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLint format); -typedef void (APIENTRYP PFNGLMEMORYBARRIEREXTPROC) (GLbitfield barriers); -#endif - -#ifndef GL_EXT_vertex_attrib_64bit -#define GL_EXT_vertex_attrib_64bit 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexAttribL1dEXT (GLuint index, GLdouble x); -GLAPI void APIENTRY glVertexAttribL2dEXT (GLuint index, GLdouble x, GLdouble y); -GLAPI void APIENTRY glVertexAttribL3dEXT (GLuint index, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glVertexAttribL4dEXT (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glVertexAttribL1dvEXT (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribL2dvEXT (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribL3dvEXT (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribL4dvEXT (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribLPointerEXT (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -GLAPI void APIENTRY glGetVertexAttribLdvEXT (GLuint index, GLenum pname, GLdouble *params); -GLAPI void APIENTRY glVertexArrayVertexAttribLOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DEXTPROC) (GLuint index, GLdouble x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DEXTPROC) (GLuint index, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DEXTPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DEXTPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVEXTPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVEXTPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVEXTPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVEXTPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVEXTPROC) (GLuint index, GLenum pname, GLdouble *params); -typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBLOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); -#endif - -#ifndef GL_NV_gpu_program5 -#define GL_NV_gpu_program5 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProgramSubroutineParametersuivNV (GLenum target, GLsizei count, const GLuint *params); -GLAPI void APIENTRY glGetProgramSubroutineParameteruivNV (GLenum target, GLuint index, GLuint *param); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPROGRAMSUBROUTINEPARAMETERSUIVNVPROC) (GLenum target, GLsizei count, const GLuint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMSUBROUTINEPARAMETERUIVNVPROC) (GLenum target, GLuint index, GLuint *param); -#endif - -#ifndef GL_NV_gpu_shader5 -#define GL_NV_gpu_shader5 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glUniform1i64NV (GLint location, GLint64EXT x); -GLAPI void APIENTRY glUniform2i64NV (GLint location, GLint64EXT x, GLint64EXT y); -GLAPI void APIENTRY glUniform3i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); -GLAPI void APIENTRY glUniform4i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); -GLAPI void APIENTRY glUniform1i64vNV (GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glUniform2i64vNV (GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glUniform3i64vNV (GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glUniform4i64vNV (GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glUniform1ui64NV (GLint location, GLuint64EXT x); -GLAPI void APIENTRY glUniform2ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y); -GLAPI void APIENTRY glUniform3ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); -GLAPI void APIENTRY glUniform4ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); -GLAPI void APIENTRY glUniform1ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glUniform2ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glUniform3ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glUniform4ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glGetUniformi64vNV (GLuint program, GLint location, GLint64EXT *params); -GLAPI void APIENTRY glProgramUniform1i64NV (GLuint program, GLint location, GLint64EXT x); -GLAPI void APIENTRY glProgramUniform2i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y); -GLAPI void APIENTRY glProgramUniform3i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); -GLAPI void APIENTRY glProgramUniform4i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); -GLAPI void APIENTRY glProgramUniform1i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glProgramUniform2i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glProgramUniform3i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glProgramUniform4i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glProgramUniform1ui64NV (GLuint program, GLint location, GLuint64EXT x); -GLAPI void APIENTRY glProgramUniform2ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y); -GLAPI void APIENTRY glProgramUniform3ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); -GLAPI void APIENTRY glProgramUniform4ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); -GLAPI void APIENTRY glProgramUniform1ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glProgramUniform2ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glProgramUniform3ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glProgramUniform4ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLUNIFORM1I64NVPROC) (GLint location, GLint64EXT x); -typedef void (APIENTRYP PFNGLUNIFORM2I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y); -typedef void (APIENTRYP PFNGLUNIFORM3I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); -typedef void (APIENTRYP PFNGLUNIFORM4I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); -typedef void (APIENTRYP PFNGLUNIFORM1I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM2I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM3I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM4I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM1UI64NVPROC) (GLint location, GLuint64EXT x); -typedef void (APIENTRYP PFNGLUNIFORM2UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y); -typedef void (APIENTRYP PFNGLUNIFORM3UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); -typedef void (APIENTRYP PFNGLUNIFORM4UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); -typedef void (APIENTRYP PFNGLUNIFORM1UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM2UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM3UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM4UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLGETUNIFORMI64VNVPROC) (GLuint program, GLint location, GLint64EXT *params); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64NVPROC) (GLuint program, GLint location, GLint64EXT x); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -#endif - -#ifndef GL_NV_shader_buffer_store -#define GL_NV_shader_buffer_store 1 -#endif - -#ifndef GL_NV_tessellation_program5 -#define GL_NV_tessellation_program5 1 -#endif - -#ifndef GL_NV_vertex_attrib_integer_64bit -#define GL_NV_vertex_attrib_integer_64bit 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexAttribL1i64NV (GLuint index, GLint64EXT x); -GLAPI void APIENTRY glVertexAttribL2i64NV (GLuint index, GLint64EXT x, GLint64EXT y); -GLAPI void APIENTRY glVertexAttribL3i64NV (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z); -GLAPI void APIENTRY glVertexAttribL4i64NV (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); -GLAPI void APIENTRY glVertexAttribL1i64vNV (GLuint index, const GLint64EXT *v); -GLAPI void APIENTRY glVertexAttribL2i64vNV (GLuint index, const GLint64EXT *v); -GLAPI void APIENTRY glVertexAttribL3i64vNV (GLuint index, const GLint64EXT *v); -GLAPI void APIENTRY glVertexAttribL4i64vNV (GLuint index, const GLint64EXT *v); -GLAPI void APIENTRY glVertexAttribL1ui64NV (GLuint index, GLuint64EXT x); -GLAPI void APIENTRY glVertexAttribL2ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y); -GLAPI void APIENTRY glVertexAttribL3ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); -GLAPI void APIENTRY glVertexAttribL4ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); -GLAPI void APIENTRY glVertexAttribL1ui64vNV (GLuint index, const GLuint64EXT *v); -GLAPI void APIENTRY glVertexAttribL2ui64vNV (GLuint index, const GLuint64EXT *v); -GLAPI void APIENTRY glVertexAttribL3ui64vNV (GLuint index, const GLuint64EXT *v); -GLAPI void APIENTRY glVertexAttribL4ui64vNV (GLuint index, const GLuint64EXT *v); -GLAPI void APIENTRY glGetVertexAttribLi64vNV (GLuint index, GLenum pname, GLint64EXT *params); -GLAPI void APIENTRY glGetVertexAttribLui64vNV (GLuint index, GLenum pname, GLuint64EXT *params); -GLAPI void APIENTRY glVertexAttribLFormatNV (GLuint index, GLint size, GLenum type, GLsizei stride); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1I64NVPROC) (GLuint index, GLint64EXT x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1I64VNVPROC) (GLuint index, const GLint64EXT *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2I64VNVPROC) (GLuint index, const GLint64EXT *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3I64VNVPROC) (GLuint index, const GLint64EXT *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4I64VNVPROC) (GLuint index, const GLint64EXT *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64NVPROC) (GLuint index, GLuint64EXT x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64VNVPROC) (GLuint index, const GLuint64EXT *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2UI64VNVPROC) (GLuint index, const GLuint64EXT *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3UI64VNVPROC) (GLuint index, const GLuint64EXT *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4UI64VNVPROC) (GLuint index, const GLuint64EXT *v); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLI64VNVPROC) (GLuint index, GLenum pname, GLint64EXT *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLUI64VNVPROC) (GLuint index, GLenum pname, GLuint64EXT *params); -typedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLsizei stride); -#endif - -#ifndef GL_NV_multisample_coverage -#define GL_NV_multisample_coverage 1 -#endif - -#ifndef GL_AMD_name_gen_delete -#define GL_AMD_name_gen_delete 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGenNamesAMD (GLenum identifier, GLuint num, GLuint *names); -GLAPI void APIENTRY glDeleteNamesAMD (GLenum identifier, GLuint num, const GLuint *names); -GLAPI GLboolean APIENTRY glIsNameAMD (GLenum identifier, GLuint name); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGENNAMESAMDPROC) (GLenum identifier, GLuint num, GLuint *names); -typedef void (APIENTRYP PFNGLDELETENAMESAMDPROC) (GLenum identifier, GLuint num, const GLuint *names); -typedef GLboolean (APIENTRYP PFNGLISNAMEAMDPROC) (GLenum identifier, GLuint name); -#endif - -#ifndef GL_AMD_debug_output -#define GL_AMD_debug_output 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDebugMessageEnableAMD (GLenum category, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); -GLAPI void APIENTRY glDebugMessageInsertAMD (GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar *buf); -GLAPI void APIENTRY glDebugMessageCallbackAMD (GLDEBUGPROCAMD callback, GLvoid *userParam); -GLAPI GLuint APIENTRY glGetDebugMessageLogAMD (GLuint count, GLsizei bufsize, GLenum *categories, GLuint *severities, GLuint *ids, GLsizei *lengths, GLchar *message); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDEBUGMESSAGEENABLEAMDPROC) (GLenum category, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); -typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTAMDPROC) (GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar *buf); -typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKAMDPROC) (GLDEBUGPROCAMD callback, GLvoid *userParam); -typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGAMDPROC) (GLuint count, GLsizei bufsize, GLenum *categories, GLuint *severities, GLuint *ids, GLsizei *lengths, GLchar *message); -#endif - -#ifndef GL_NV_vdpau_interop -#define GL_NV_vdpau_interop 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVDPAUInitNV (const GLvoid *vdpDevice, const GLvoid *getProcAddress); -GLAPI void APIENTRY glVDPAUFiniNV (void); -GLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterVideoSurfaceNV (GLvoid *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); -GLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterOutputSurfaceNV (GLvoid *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); -GLAPI void APIENTRY glVDPAUIsSurfaceNV (GLvdpauSurfaceNV surface); -GLAPI void APIENTRY glVDPAUUnregisterSurfaceNV (GLvdpauSurfaceNV surface); -GLAPI void APIENTRY glVDPAUGetSurfaceivNV (GLvdpauSurfaceNV surface, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); -GLAPI void APIENTRY glVDPAUSurfaceAccessNV (GLvdpauSurfaceNV surface, GLenum access); -GLAPI void APIENTRY glVDPAUMapSurfacesNV (GLsizei numSurfaces, const GLvdpauSurfaceNV *surfaces); -GLAPI void APIENTRY glVDPAUUnmapSurfacesNV (GLsizei numSurface, const GLvdpauSurfaceNV *surfaces); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVDPAUINITNVPROC) (const GLvoid *vdpDevice, const GLvoid *getProcAddress); -typedef void (APIENTRYP PFNGLVDPAUFININVPROC) (void); -typedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTERVIDEOSURFACENVPROC) (GLvoid *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); -typedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC) (GLvoid *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); -typedef void (APIENTRYP PFNGLVDPAUISSURFACENVPROC) (GLvdpauSurfaceNV surface); -typedef void (APIENTRYP PFNGLVDPAUUNREGISTERSURFACENVPROC) (GLvdpauSurfaceNV surface); -typedef void (APIENTRYP PFNGLVDPAUGETSURFACEIVNVPROC) (GLvdpauSurfaceNV surface, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); -typedef void (APIENTRYP PFNGLVDPAUSURFACEACCESSNVPROC) (GLvdpauSurfaceNV surface, GLenum access); -typedef void (APIENTRYP PFNGLVDPAUMAPSURFACESNVPROC) (GLsizei numSurfaces, const GLvdpauSurfaceNV *surfaces); -typedef void (APIENTRYP PFNGLVDPAUUNMAPSURFACESNVPROC) (GLsizei numSurface, const GLvdpauSurfaceNV *surfaces); -#endif - -#ifndef GL_AMD_transform_feedback3_lines_triangles -#define GL_AMD_transform_feedback3_lines_triangles 1 -#endif - -#ifndef GL_AMD_depth_clamp_separate -#define GL_AMD_depth_clamp_separate 1 -#endif - -#ifndef GL_EXT_texture_sRGB_decode -#define GL_EXT_texture_sRGB_decode 1 -#endif - -#ifndef GL_NV_texture_multisample -#define GL_NV_texture_multisample 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexImage2DMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); -GLAPI void APIENTRY glTexImage3DMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); -GLAPI void APIENTRY glTextureImage2DMultisampleNV (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); -GLAPI void APIENTRY glTextureImage3DMultisampleNV (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); -GLAPI void APIENTRY glTextureImage2DMultisampleCoverageNV (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); -GLAPI void APIENTRY glTextureImage3DMultisampleCoverageNV (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); -typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); -typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DMULTISAMPLENVPROC) (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); -typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DMULTISAMPLENVPROC) (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); -typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DMULTISAMPLECOVERAGENVPROC) (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); -typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DMULTISAMPLECOVERAGENVPROC) (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); -#endif - -#ifndef GL_AMD_blend_minmax_factor -#define GL_AMD_blend_minmax_factor 1 -#endif - -#ifndef GL_AMD_sample_positions -#define GL_AMD_sample_positions 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glSetMultisamplefvAMD (GLenum pname, GLuint index, const GLfloat *val); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLSETMULTISAMPLEFVAMDPROC) (GLenum pname, GLuint index, const GLfloat *val); -#endif - -#ifndef GL_EXT_x11_sync_object -#define GL_EXT_x11_sync_object 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLsync APIENTRY glImportSyncEXT (GLenum external_sync_type, GLintptr external_sync, GLbitfield flags); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLsync (APIENTRYP PFNGLIMPORTSYNCEXTPROC) (GLenum external_sync_type, GLintptr external_sync, GLbitfield flags); -#endif - -#ifndef GL_AMD_multi_draw_indirect -#define GL_AMD_multi_draw_indirect 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMultiDrawArraysIndirectAMD (GLenum mode, const GLvoid *indirect, GLsizei primcount, GLsizei stride); -GLAPI void APIENTRY glMultiDrawElementsIndirectAMD (GLenum mode, GLenum type, const GLvoid *indirect, GLsizei primcount, GLsizei stride); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTAMDPROC) (GLenum mode, const GLvoid *indirect, GLsizei primcount, GLsizei stride); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTAMDPROC) (GLenum mode, GLenum type, const GLvoid *indirect, GLsizei primcount, GLsizei stride); -#endif - -#ifndef GL_EXT_framebuffer_multisample_blit_scaled -#define GL_EXT_framebuffer_multisample_blit_scaled 1 -#endif - -#ifndef GL_NV_path_rendering -#define GL_NV_path_rendering 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLuint APIENTRY glGenPathsNV (GLsizei range); -GLAPI void APIENTRY glDeletePathsNV (GLuint path, GLsizei range); -GLAPI GLboolean APIENTRY glIsPathNV (GLuint path); -GLAPI void APIENTRY glPathCommandsNV (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const GLvoid *coords); -GLAPI void APIENTRY glPathCoordsNV (GLuint path, GLsizei numCoords, GLenum coordType, const GLvoid *coords); -GLAPI void APIENTRY glPathSubCommandsNV (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const GLvoid *coords); -GLAPI void APIENTRY glPathSubCoordsNV (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const GLvoid *coords); -GLAPI void APIENTRY glPathStringNV (GLuint path, GLenum format, GLsizei length, const GLvoid *pathString); -GLAPI void APIENTRY glPathGlyphsNV (GLuint firstPathName, GLenum fontTarget, const GLvoid *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const GLvoid *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); -GLAPI void APIENTRY glPathGlyphRangeNV (GLuint firstPathName, GLenum fontTarget, const GLvoid *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); -GLAPI void APIENTRY glWeightPathsNV (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights); -GLAPI void APIENTRY glCopyPathNV (GLuint resultPath, GLuint srcPath); -GLAPI void APIENTRY glInterpolatePathsNV (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight); -GLAPI void APIENTRY glTransformPathNV (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues); -GLAPI void APIENTRY glPathParameterivNV (GLuint path, GLenum pname, const GLint *value); -GLAPI void APIENTRY glPathParameteriNV (GLuint path, GLenum pname, GLint value); -GLAPI void APIENTRY glPathParameterfvNV (GLuint path, GLenum pname, const GLfloat *value); -GLAPI void APIENTRY glPathParameterfNV (GLuint path, GLenum pname, GLfloat value); -GLAPI void APIENTRY glPathDashArrayNV (GLuint path, GLsizei dashCount, const GLfloat *dashArray); -GLAPI void APIENTRY glPathStencilFuncNV (GLenum func, GLint ref, GLuint mask); -GLAPI void APIENTRY glPathStencilDepthOffsetNV (GLfloat factor, GLfloat units); -GLAPI void APIENTRY glStencilFillPathNV (GLuint path, GLenum fillMode, GLuint mask); -GLAPI void APIENTRY glStencilStrokePathNV (GLuint path, GLint reference, GLuint mask); -GLAPI void APIENTRY glStencilFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues); -GLAPI void APIENTRY glStencilStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues); -GLAPI void APIENTRY glPathCoverDepthFuncNV (GLenum func); -GLAPI void APIENTRY glPathColorGenNV (GLenum color, GLenum genMode, GLenum colorFormat, const GLfloat *coeffs); -GLAPI void APIENTRY glPathTexGenNV (GLenum texCoordSet, GLenum genMode, GLint components, const GLfloat *coeffs); -GLAPI void APIENTRY glPathFogGenNV (GLenum genMode); -GLAPI void APIENTRY glCoverFillPathNV (GLuint path, GLenum coverMode); -GLAPI void APIENTRY glCoverStrokePathNV (GLuint path, GLenum coverMode); -GLAPI void APIENTRY glCoverFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); -GLAPI void APIENTRY glCoverStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); -GLAPI void APIENTRY glGetPathParameterivNV (GLuint path, GLenum pname, GLint *value); -GLAPI void APIENTRY glGetPathParameterfvNV (GLuint path, GLenum pname, GLfloat *value); -GLAPI void APIENTRY glGetPathCommandsNV (GLuint path, GLubyte *commands); -GLAPI void APIENTRY glGetPathCoordsNV (GLuint path, GLfloat *coords); -GLAPI void APIENTRY glGetPathDashArrayNV (GLuint path, GLfloat *dashArray); -GLAPI void APIENTRY glGetPathMetricsNV (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics); -GLAPI void APIENTRY glGetPathMetricRangeNV (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics); -GLAPI void APIENTRY glGetPathSpacingNV (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing); -GLAPI void APIENTRY glGetPathColorGenivNV (GLenum color, GLenum pname, GLint *value); -GLAPI void APIENTRY glGetPathColorGenfvNV (GLenum color, GLenum pname, GLfloat *value); -GLAPI void APIENTRY glGetPathTexGenivNV (GLenum texCoordSet, GLenum pname, GLint *value); -GLAPI void APIENTRY glGetPathTexGenfvNV (GLenum texCoordSet, GLenum pname, GLfloat *value); -GLAPI GLboolean APIENTRY glIsPointInFillPathNV (GLuint path, GLuint mask, GLfloat x, GLfloat y); -GLAPI GLboolean APIENTRY glIsPointInStrokePathNV (GLuint path, GLfloat x, GLfloat y); -GLAPI GLfloat APIENTRY glGetPathLengthNV (GLuint path, GLsizei startSegment, GLsizei numSegments); -GLAPI GLboolean APIENTRY glPointAlongPathNV (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLuint (APIENTRYP PFNGLGENPATHSNVPROC) (GLsizei range); -typedef void (APIENTRYP PFNGLDELETEPATHSNVPROC) (GLuint path, GLsizei range); -typedef GLboolean (APIENTRYP PFNGLISPATHNVPROC) (GLuint path); -typedef void (APIENTRYP PFNGLPATHCOMMANDSNVPROC) (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const GLvoid *coords); -typedef void (APIENTRYP PFNGLPATHCOORDSNVPROC) (GLuint path, GLsizei numCoords, GLenum coordType, const GLvoid *coords); -typedef void (APIENTRYP PFNGLPATHSUBCOMMANDSNVPROC) (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const GLvoid *coords); -typedef void (APIENTRYP PFNGLPATHSUBCOORDSNVPROC) (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const GLvoid *coords); -typedef void (APIENTRYP PFNGLPATHSTRINGNVPROC) (GLuint path, GLenum format, GLsizei length, const GLvoid *pathString); -typedef void (APIENTRYP PFNGLPATHGLYPHSNVPROC) (GLuint firstPathName, GLenum fontTarget, const GLvoid *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const GLvoid *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); -typedef void (APIENTRYP PFNGLPATHGLYPHRANGENVPROC) (GLuint firstPathName, GLenum fontTarget, const GLvoid *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); -typedef void (APIENTRYP PFNGLWEIGHTPATHSNVPROC) (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights); -typedef void (APIENTRYP PFNGLCOPYPATHNVPROC) (GLuint resultPath, GLuint srcPath); -typedef void (APIENTRYP PFNGLINTERPOLATEPATHSNVPROC) (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight); -typedef void (APIENTRYP PFNGLTRANSFORMPATHNVPROC) (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues); -typedef void (APIENTRYP PFNGLPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, const GLint *value); -typedef void (APIENTRYP PFNGLPATHPARAMETERINVPROC) (GLuint path, GLenum pname, GLint value); -typedef void (APIENTRYP PFNGLPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, const GLfloat *value); -typedef void (APIENTRYP PFNGLPATHPARAMETERFNVPROC) (GLuint path, GLenum pname, GLfloat value); -typedef void (APIENTRYP PFNGLPATHDASHARRAYNVPROC) (GLuint path, GLsizei dashCount, const GLfloat *dashArray); -typedef void (APIENTRYP PFNGLPATHSTENCILFUNCNVPROC) (GLenum func, GLint ref, GLuint mask); -typedef void (APIENTRYP PFNGLPATHSTENCILDEPTHOFFSETNVPROC) (GLfloat factor, GLfloat units); -typedef void (APIENTRYP PFNGLSTENCILFILLPATHNVPROC) (GLuint path, GLenum fillMode, GLuint mask); -typedef void (APIENTRYP PFNGLSTENCILSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask); -typedef void (APIENTRYP PFNGLSTENCILFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues); -typedef void (APIENTRYP PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues); -typedef void (APIENTRYP PFNGLPATHCOVERDEPTHFUNCNVPROC) (GLenum func); -typedef void (APIENTRYP PFNGLPATHCOLORGENNVPROC) (GLenum color, GLenum genMode, GLenum colorFormat, const GLfloat *coeffs); -typedef void (APIENTRYP PFNGLPATHTEXGENNVPROC) (GLenum texCoordSet, GLenum genMode, GLint components, const GLfloat *coeffs); -typedef void (APIENTRYP PFNGLPATHFOGGENNVPROC) (GLenum genMode); -typedef void (APIENTRYP PFNGLCOVERFILLPATHNVPROC) (GLuint path, GLenum coverMode); -typedef void (APIENTRYP PFNGLCOVERSTROKEPATHNVPROC) (GLuint path, GLenum coverMode); -typedef void (APIENTRYP PFNGLCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); -typedef void (APIENTRYP PFNGLCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); -typedef void (APIENTRYP PFNGLGETPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, GLint *value); -typedef void (APIENTRYP PFNGLGETPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, GLfloat *value); -typedef void (APIENTRYP PFNGLGETPATHCOMMANDSNVPROC) (GLuint path, GLubyte *commands); -typedef void (APIENTRYP PFNGLGETPATHCOORDSNVPROC) (GLuint path, GLfloat *coords); -typedef void (APIENTRYP PFNGLGETPATHDASHARRAYNVPROC) (GLuint path, GLfloat *dashArray); -typedef void (APIENTRYP PFNGLGETPATHMETRICSNVPROC) (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics); -typedef void (APIENTRYP PFNGLGETPATHMETRICRANGENVPROC) (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics); -typedef void (APIENTRYP PFNGLGETPATHSPACINGNVPROC) (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing); -typedef void (APIENTRYP PFNGLGETPATHCOLORGENIVNVPROC) (GLenum color, GLenum pname, GLint *value); -typedef void (APIENTRYP PFNGLGETPATHCOLORGENFVNVPROC) (GLenum color, GLenum pname, GLfloat *value); -typedef void (APIENTRYP PFNGLGETPATHTEXGENIVNVPROC) (GLenum texCoordSet, GLenum pname, GLint *value); -typedef void (APIENTRYP PFNGLGETPATHTEXGENFVNVPROC) (GLenum texCoordSet, GLenum pname, GLfloat *value); -typedef GLboolean (APIENTRYP PFNGLISPOINTINFILLPATHNVPROC) (GLuint path, GLuint mask, GLfloat x, GLfloat y); -typedef GLboolean (APIENTRYP PFNGLISPOINTINSTROKEPATHNVPROC) (GLuint path, GLfloat x, GLfloat y); -typedef GLfloat (APIENTRYP PFNGLGETPATHLENGTHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments); -typedef GLboolean (APIENTRYP PFNGLPOINTALONGPATHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY); -#endif - -#ifndef GL_AMD_pinned_memory -#define GL_AMD_pinned_memory 1 -#endif - -#ifndef GL_AMD_stencil_operation_extended -#define GL_AMD_stencil_operation_extended 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glStencilOpValueAMD (GLenum face, GLuint value); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLSTENCILOPVALUEAMDPROC) (GLenum face, GLuint value); -#endif - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/freeglut/include/GL/glut.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/freeglut/include/GL/glut.h deleted file mode 100644 index 6191f77b75d7..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/freeglut/include/GL/glut.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __GLUT_H__ -#define __GLUT_H__ - -/* - * glut.h - * - * The freeglut library include file - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "freeglut_std.h" - -/*** END OF FILE ***/ - -#endif /* __GLUT_H__ */ diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/freeglut/include/GL/glxext.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/freeglut/include/GL/glxext.h deleted file mode 100644 index e640ff7e3977..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/freeglut/include/GL/glxext.h +++ /dev/null @@ -1,1001 +0,0 @@ -#ifndef __glxext_h_ -#define __glxext_h_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** Copyright (c) 2007-2012 The Khronos Group Inc. -** -** Permission is hereby granted, free of charge, to any person obtaining a -** copy of this software and/or associated documentation files (the -** "Materials"), to deal in the Materials without restriction, including -** without limitation the rights to use, copy, modify, merge, publish, -** distribute, sublicense, and/or sell copies of the Materials, and to -** permit persons to whom the Materials are furnished to do so, subject to -** the following conditions: -** -** The above copyright notice and this permission notice shall be included -** in all copies or substantial portions of the Materials. -** -** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. -*/ - -/* Function declaration macros - to move into glplatform.h */ - -#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) -#define WIN32_LEAN_AND_MEAN 1 -#include -#endif - -#ifndef APIENTRY -#define APIENTRY -#endif -#ifndef APIENTRYP -#define APIENTRYP APIENTRY * -#endif -#ifndef GLAPI -#define GLAPI extern -#endif - -/*************************************************************/ - -/* Header file version number, required by OpenGL ABI for Linux */ -/* glxext.h last updated 2012/02/29 */ -/* Current version at http://www.opengl.org/registry/ */ -#define GLX_GLXEXT_VERSION 33 - -#ifndef GLX_VERSION_1_3 -#define GLX_WINDOW_BIT 0x00000001 -#define GLX_PIXMAP_BIT 0x00000002 -#define GLX_PBUFFER_BIT 0x00000004 -#define GLX_RGBA_BIT 0x00000001 -#define GLX_COLOR_INDEX_BIT 0x00000002 -#define GLX_PBUFFER_CLOBBER_MASK 0x08000000 -#define GLX_FRONT_LEFT_BUFFER_BIT 0x00000001 -#define GLX_FRONT_RIGHT_BUFFER_BIT 0x00000002 -#define GLX_BACK_LEFT_BUFFER_BIT 0x00000004 -#define GLX_BACK_RIGHT_BUFFER_BIT 0x00000008 -#define GLX_AUX_BUFFERS_BIT 0x00000010 -#define GLX_DEPTH_BUFFER_BIT 0x00000020 -#define GLX_STENCIL_BUFFER_BIT 0x00000040 -#define GLX_ACCUM_BUFFER_BIT 0x00000080 -#define GLX_CONFIG_CAVEAT 0x20 -#define GLX_X_VISUAL_TYPE 0x22 -#define GLX_TRANSPARENT_TYPE 0x23 -#define GLX_TRANSPARENT_INDEX_VALUE 0x24 -#define GLX_TRANSPARENT_RED_VALUE 0x25 -#define GLX_TRANSPARENT_GREEN_VALUE 0x26 -#define GLX_TRANSPARENT_BLUE_VALUE 0x27 -#define GLX_TRANSPARENT_ALPHA_VALUE 0x28 -#define GLX_DONT_CARE 0xFFFFFFFF -#define GLX_NONE 0x8000 -#define GLX_SLOW_CONFIG 0x8001 -#define GLX_TRUE_COLOR 0x8002 -#define GLX_DIRECT_COLOR 0x8003 -#define GLX_PSEUDO_COLOR 0x8004 -#define GLX_STATIC_COLOR 0x8005 -#define GLX_GRAY_SCALE 0x8006 -#define GLX_STATIC_GRAY 0x8007 -#define GLX_TRANSPARENT_RGB 0x8008 -#define GLX_TRANSPARENT_INDEX 0x8009 -#define GLX_VISUAL_ID 0x800B -#define GLX_SCREEN 0x800C -#define GLX_NON_CONFORMANT_CONFIG 0x800D -#define GLX_DRAWABLE_TYPE 0x8010 -#define GLX_RENDER_TYPE 0x8011 -#define GLX_X_RENDERABLE 0x8012 -#define GLX_FBCONFIG_ID 0x8013 -#define GLX_RGBA_TYPE 0x8014 -#define GLX_COLOR_INDEX_TYPE 0x8015 -#define GLX_MAX_PBUFFER_WIDTH 0x8016 -#define GLX_MAX_PBUFFER_HEIGHT 0x8017 -#define GLX_MAX_PBUFFER_PIXELS 0x8018 -#define GLX_PRESERVED_CONTENTS 0x801B -#define GLX_LARGEST_PBUFFER 0x801C -#define GLX_WIDTH 0x801D -#define GLX_HEIGHT 0x801E -#define GLX_EVENT_MASK 0x801F -#define GLX_DAMAGED 0x8020 -#define GLX_SAVED 0x8021 -#define GLX_WINDOW 0x8022 -#define GLX_PBUFFER 0x8023 -#define GLX_PBUFFER_HEIGHT 0x8040 -#define GLX_PBUFFER_WIDTH 0x8041 -#endif - -#ifndef GLX_VERSION_1_4 -#define GLX_SAMPLE_BUFFERS 100000 -#define GLX_SAMPLES 100001 -#endif - -#ifndef GLX_ARB_get_proc_address -#endif - -#ifndef GLX_ARB_multisample -#define GLX_SAMPLE_BUFFERS_ARB 100000 -#define GLX_SAMPLES_ARB 100001 -#endif - -#ifndef GLX_ARB_vertex_buffer_object -#define GLX_CONTEXT_ALLOW_BUFFER_BYTE_ORDER_MISMATCH_ARB 0x2095 -#endif - -#ifndef GLX_ARB_fbconfig_float -#define GLX_RGBA_FLOAT_TYPE_ARB 0x20B9 -#define GLX_RGBA_FLOAT_BIT_ARB 0x00000004 -#endif - -#ifndef GLX_ARB_framebuffer_sRGB -#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2 -#endif - -#ifndef GLX_ARB_create_context -#define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001 -#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 -#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 -#define GLX_CONTEXT_FLAGS_ARB 0x2094 -#endif - -#ifndef GLX_ARB_create_context_profile -#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 -#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 -#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 -#endif - -#ifndef GLX_ARB_create_context_robustness -#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 -#define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252 -#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 -#define GLX_NO_RESET_NOTIFICATION_ARB 0x8261 -#endif - -#ifndef GLX_SGIS_multisample -#define GLX_SAMPLE_BUFFERS_SGIS 100000 -#define GLX_SAMPLES_SGIS 100001 -#endif - -#ifndef GLX_EXT_visual_info -#define GLX_X_VISUAL_TYPE_EXT 0x22 -#define GLX_TRANSPARENT_TYPE_EXT 0x23 -#define GLX_TRANSPARENT_INDEX_VALUE_EXT 0x24 -#define GLX_TRANSPARENT_RED_VALUE_EXT 0x25 -#define GLX_TRANSPARENT_GREEN_VALUE_EXT 0x26 -#define GLX_TRANSPARENT_BLUE_VALUE_EXT 0x27 -#define GLX_TRANSPARENT_ALPHA_VALUE_EXT 0x28 -#define GLX_NONE_EXT 0x8000 -#define GLX_TRUE_COLOR_EXT 0x8002 -#define GLX_DIRECT_COLOR_EXT 0x8003 -#define GLX_PSEUDO_COLOR_EXT 0x8004 -#define GLX_STATIC_COLOR_EXT 0x8005 -#define GLX_GRAY_SCALE_EXT 0x8006 -#define GLX_STATIC_GRAY_EXT 0x8007 -#define GLX_TRANSPARENT_RGB_EXT 0x8008 -#define GLX_TRANSPARENT_INDEX_EXT 0x8009 -#endif - -#ifndef GLX_SGI_swap_control -#endif - -#ifndef GLX_SGI_video_sync -#endif - -#ifndef GLX_SGI_make_current_read -#endif - -#ifndef GLX_SGIX_video_source -#endif - -#ifndef GLX_EXT_visual_rating -#define GLX_VISUAL_CAVEAT_EXT 0x20 -#define GLX_SLOW_VISUAL_EXT 0x8001 -#define GLX_NON_CONFORMANT_VISUAL_EXT 0x800D -/* reuse GLX_NONE_EXT */ -#endif - -#ifndef GLX_EXT_import_context -#define GLX_SHARE_CONTEXT_EXT 0x800A -#define GLX_VISUAL_ID_EXT 0x800B -#define GLX_SCREEN_EXT 0x800C -#endif - -#ifndef GLX_SGIX_fbconfig -#define GLX_WINDOW_BIT_SGIX 0x00000001 -#define GLX_PIXMAP_BIT_SGIX 0x00000002 -#define GLX_RGBA_BIT_SGIX 0x00000001 -#define GLX_COLOR_INDEX_BIT_SGIX 0x00000002 -#define GLX_DRAWABLE_TYPE_SGIX 0x8010 -#define GLX_RENDER_TYPE_SGIX 0x8011 -#define GLX_X_RENDERABLE_SGIX 0x8012 -#define GLX_FBCONFIG_ID_SGIX 0x8013 -#define GLX_RGBA_TYPE_SGIX 0x8014 -#define GLX_COLOR_INDEX_TYPE_SGIX 0x8015 -/* reuse GLX_SCREEN_EXT */ -#endif - -#ifndef GLX_SGIX_pbuffer -#define GLX_PBUFFER_BIT_SGIX 0x00000004 -#define GLX_BUFFER_CLOBBER_MASK_SGIX 0x08000000 -#define GLX_FRONT_LEFT_BUFFER_BIT_SGIX 0x00000001 -#define GLX_FRONT_RIGHT_BUFFER_BIT_SGIX 0x00000002 -#define GLX_BACK_LEFT_BUFFER_BIT_SGIX 0x00000004 -#define GLX_BACK_RIGHT_BUFFER_BIT_SGIX 0x00000008 -#define GLX_AUX_BUFFERS_BIT_SGIX 0x00000010 -#define GLX_DEPTH_BUFFER_BIT_SGIX 0x00000020 -#define GLX_STENCIL_BUFFER_BIT_SGIX 0x00000040 -#define GLX_ACCUM_BUFFER_BIT_SGIX 0x00000080 -#define GLX_SAMPLE_BUFFERS_BIT_SGIX 0x00000100 -#define GLX_MAX_PBUFFER_WIDTH_SGIX 0x8016 -#define GLX_MAX_PBUFFER_HEIGHT_SGIX 0x8017 -#define GLX_MAX_PBUFFER_PIXELS_SGIX 0x8018 -#define GLX_OPTIMAL_PBUFFER_WIDTH_SGIX 0x8019 -#define GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX 0x801A -#define GLX_PRESERVED_CONTENTS_SGIX 0x801B -#define GLX_LARGEST_PBUFFER_SGIX 0x801C -#define GLX_WIDTH_SGIX 0x801D -#define GLX_HEIGHT_SGIX 0x801E -#define GLX_EVENT_MASK_SGIX 0x801F -#define GLX_DAMAGED_SGIX 0x8020 -#define GLX_SAVED_SGIX 0x8021 -#define GLX_WINDOW_SGIX 0x8022 -#define GLX_PBUFFER_SGIX 0x8023 -#endif - -#ifndef GLX_SGI_cushion -#endif - -#ifndef GLX_SGIX_video_resize -#define GLX_SYNC_FRAME_SGIX 0x00000000 -#define GLX_SYNC_SWAP_SGIX 0x00000001 -#endif - -#ifndef GLX_SGIX_dmbuffer -#define GLX_DIGITAL_MEDIA_PBUFFER_SGIX 0x8024 -#endif - -#ifndef GLX_SGIX_swap_group -#endif - -#ifndef GLX_SGIX_swap_barrier -#endif - -#ifndef GLX_SGIS_blended_overlay -#define GLX_BLENDED_RGBA_SGIS 0x8025 -#endif - -#ifndef GLX_SGIS_shared_multisample -#define GLX_MULTISAMPLE_SUB_RECT_WIDTH_SGIS 0x8026 -#define GLX_MULTISAMPLE_SUB_RECT_HEIGHT_SGIS 0x8027 -#endif - -#ifndef GLX_SUN_get_transparent_index -#endif - -#ifndef GLX_3DFX_multisample -#define GLX_SAMPLE_BUFFERS_3DFX 0x8050 -#define GLX_SAMPLES_3DFX 0x8051 -#endif - -#ifndef GLX_MESA_copy_sub_buffer -#endif - -#ifndef GLX_MESA_pixmap_colormap -#endif - -#ifndef GLX_MESA_release_buffers -#endif - -#ifndef GLX_MESA_set_3dfx_mode -#define GLX_3DFX_WINDOW_MODE_MESA 0x1 -#define GLX_3DFX_FULLSCREEN_MODE_MESA 0x2 -#endif - -#ifndef GLX_SGIX_visual_select_group -#define GLX_VISUAL_SELECT_GROUP_SGIX 0x8028 -#endif - -#ifndef GLX_OML_swap_method -#define GLX_SWAP_METHOD_OML 0x8060 -#define GLX_SWAP_EXCHANGE_OML 0x8061 -#define GLX_SWAP_COPY_OML 0x8062 -#define GLX_SWAP_UNDEFINED_OML 0x8063 -#endif - -#ifndef GLX_OML_sync_control -#endif - -#ifndef GLX_NV_float_buffer -#define GLX_FLOAT_COMPONENTS_NV 0x20B0 -#endif - -#ifndef GLX_SGIX_hyperpipe -#define GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX 80 -#define GLX_BAD_HYPERPIPE_CONFIG_SGIX 91 -#define GLX_BAD_HYPERPIPE_SGIX 92 -#define GLX_HYPERPIPE_DISPLAY_PIPE_SGIX 0x00000001 -#define GLX_HYPERPIPE_RENDER_PIPE_SGIX 0x00000002 -#define GLX_PIPE_RECT_SGIX 0x00000001 -#define GLX_PIPE_RECT_LIMITS_SGIX 0x00000002 -#define GLX_HYPERPIPE_STEREO_SGIX 0x00000003 -#define GLX_HYPERPIPE_PIXEL_AVERAGE_SGIX 0x00000004 -#define GLX_HYPERPIPE_ID_SGIX 0x8030 -#endif - -#ifndef GLX_MESA_agp_offset -#endif - -#ifndef GLX_EXT_fbconfig_packed_float -#define GLX_RGBA_UNSIGNED_FLOAT_TYPE_EXT 0x20B1 -#define GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT 0x00000008 -#endif - -#ifndef GLX_EXT_framebuffer_sRGB -#define GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20B2 -#endif - -#ifndef GLX_EXT_texture_from_pixmap -#define GLX_TEXTURE_1D_BIT_EXT 0x00000001 -#define GLX_TEXTURE_2D_BIT_EXT 0x00000002 -#define GLX_TEXTURE_RECTANGLE_BIT_EXT 0x00000004 -#define GLX_BIND_TO_TEXTURE_RGB_EXT 0x20D0 -#define GLX_BIND_TO_TEXTURE_RGBA_EXT 0x20D1 -#define GLX_BIND_TO_MIPMAP_TEXTURE_EXT 0x20D2 -#define GLX_BIND_TO_TEXTURE_TARGETS_EXT 0x20D3 -#define GLX_Y_INVERTED_EXT 0x20D4 -#define GLX_TEXTURE_FORMAT_EXT 0x20D5 -#define GLX_TEXTURE_TARGET_EXT 0x20D6 -#define GLX_MIPMAP_TEXTURE_EXT 0x20D7 -#define GLX_TEXTURE_FORMAT_NONE_EXT 0x20D8 -#define GLX_TEXTURE_FORMAT_RGB_EXT 0x20D9 -#define GLX_TEXTURE_FORMAT_RGBA_EXT 0x20DA -#define GLX_TEXTURE_1D_EXT 0x20DB -#define GLX_TEXTURE_2D_EXT 0x20DC -#define GLX_TEXTURE_RECTANGLE_EXT 0x20DD -#define GLX_FRONT_LEFT_EXT 0x20DE -#define GLX_FRONT_RIGHT_EXT 0x20DF -#define GLX_BACK_LEFT_EXT 0x20E0 -#define GLX_BACK_RIGHT_EXT 0x20E1 -#define GLX_FRONT_EXT GLX_FRONT_LEFT_EXT -#define GLX_BACK_EXT GLX_BACK_LEFT_EXT -#define GLX_AUX0_EXT 0x20E2 -#define GLX_AUX1_EXT 0x20E3 -#define GLX_AUX2_EXT 0x20E4 -#define GLX_AUX3_EXT 0x20E5 -#define GLX_AUX4_EXT 0x20E6 -#define GLX_AUX5_EXT 0x20E7 -#define GLX_AUX6_EXT 0x20E8 -#define GLX_AUX7_EXT 0x20E9 -#define GLX_AUX8_EXT 0x20EA -#define GLX_AUX9_EXT 0x20EB -#endif - -#ifndef GLX_NV_present_video -#define GLX_NUM_VIDEO_SLOTS_NV 0x20F0 -#endif - -#ifndef GLX_NV_video_out -#define GLX_VIDEO_OUT_COLOR_NV 0x20C3 -#define GLX_VIDEO_OUT_ALPHA_NV 0x20C4 -#define GLX_VIDEO_OUT_DEPTH_NV 0x20C5 -#define GLX_VIDEO_OUT_COLOR_AND_ALPHA_NV 0x20C6 -#define GLX_VIDEO_OUT_COLOR_AND_DEPTH_NV 0x20C7 -#define GLX_VIDEO_OUT_FRAME_NV 0x20C8 -#define GLX_VIDEO_OUT_FIELD_1_NV 0x20C9 -#define GLX_VIDEO_OUT_FIELD_2_NV 0x20CA -#define GLX_VIDEO_OUT_STACKED_FIELDS_1_2_NV 0x20CB -#define GLX_VIDEO_OUT_STACKED_FIELDS_2_1_NV 0x20CC -#endif - -#ifndef GLX_NV_swap_group -#endif - -#ifndef GLX_NV_video_capture -#define GLX_DEVICE_ID_NV 0x20CD -#define GLX_UNIQUE_ID_NV 0x20CE -#define GLX_NUM_VIDEO_CAPTURE_SLOTS_NV 0x20CF -#endif - -#ifndef GLX_EXT_swap_control -#define GLX_SWAP_INTERVAL_EXT 0x20F1 -#define GLX_MAX_SWAP_INTERVAL_EXT 0x20F2 -#endif - -#ifndef GLX_NV_copy_image -#endif - -#ifndef GLX_INTEL_swap_event -#define GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK 0x04000000 -#define GLX_EXCHANGE_COMPLETE_INTEL 0x8180 -#define GLX_COPY_COMPLETE_INTEL 0x8181 -#define GLX_FLIP_COMPLETE_INTEL 0x8182 -#endif - -#ifndef GLX_NV_multisample_coverage -#define GLX_COVERAGE_SAMPLES_NV 100001 -#define GLX_COLOR_SAMPLES_NV 0x20B3 -#endif - -#ifndef GLX_AMD_gpu_association -#define GLX_GPU_VENDOR_AMD 0x1F00 -#define GLX_GPU_RENDERER_STRING_AMD 0x1F01 -#define GLX_GPU_OPENGL_VERSION_STRING_AMD 0x1F02 -#define GLX_GPU_FASTEST_TARGET_GPUS_AMD 0x21A2 -#define GLX_GPU_RAM_AMD 0x21A3 -#define GLX_GPU_CLOCK_AMD 0x21A4 -#define GLX_GPU_NUM_PIPES_AMD 0x21A5 -#define GLX_GPU_NUM_SIMD_AMD 0x21A6 -#define GLX_GPU_NUM_RB_AMD 0x21A7 -#define GLX_GPU_NUM_SPI_AMD 0x21A8 -#endif - -#ifndef GLX_EXT_create_context_es2_profile -#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 -#endif - -#ifndef GLX_EXT_swap_control_tear -#define GLX_LATE_SWAPS_TEAR_EXT 0x20F3 -#endif - - -/*************************************************************/ - -#ifndef GLX_ARB_get_proc_address -typedef void (*__GLXextFuncPtr)(void); -#endif - -#ifndef GLX_SGIX_video_source -typedef XID GLXVideoSourceSGIX; -#endif - -#ifndef GLX_SGIX_fbconfig -typedef XID GLXFBConfigIDSGIX; -typedef struct __GLXFBConfigRec *GLXFBConfigSGIX; -#endif - -#ifndef GLX_SGIX_pbuffer -typedef XID GLXPbufferSGIX; -typedef struct { - int type; - unsigned long serial; /* # of last request processed by server */ - Bool send_event; /* true if this came for SendEvent request */ - Display *display; /* display the event was read from */ - GLXDrawable drawable; /* i.d. of Drawable */ - int event_type; /* GLX_DAMAGED_SGIX or GLX_SAVED_SGIX */ - int draw_type; /* GLX_WINDOW_SGIX or GLX_PBUFFER_SGIX */ - unsigned int mask; /* mask indicating which buffers are affected*/ - int x, y; - int width, height; - int count; /* if nonzero, at least this many more */ -} GLXBufferClobberEventSGIX; -#endif - -#ifndef GLX_NV_video_output -typedef unsigned int GLXVideoDeviceNV; -#endif - -#ifndef GLX_NV_video_capture -typedef XID GLXVideoCaptureDeviceNV; -#endif - -#ifndef GLEXT_64_TYPES_DEFINED -/* This code block is duplicated in glext.h, so must be protected */ -#define GLEXT_64_TYPES_DEFINED -/* Define int32_t, int64_t, and uint64_t types for UST/MSC */ -/* (as used in the GLX_OML_sync_control extension). */ -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L -#include -#elif defined(__sun__) || defined(__digital__) -#include -#if defined(__STDC__) -#if defined(__arch64__) || defined(_LP64) -typedef long int int64_t; -typedef unsigned long int uint64_t; -#else -typedef long long int int64_t; -typedef unsigned long long int uint64_t; -#endif /* __arch64__ */ -#endif /* __STDC__ */ -#elif defined( __VMS ) || defined(__sgi) -#include -#elif defined(__SCO__) || defined(__USLC__) -#include -#elif defined(__UNIXOS2__) || defined(__SOL64__) -typedef long int int32_t; -typedef long long int int64_t; -typedef unsigned long long int uint64_t; -#elif defined(_WIN32) && defined(__GNUC__) -#include -#elif defined(_WIN32) -typedef __int32 int32_t; -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -#else -#include /* Fallback option */ -#endif -#endif - -#ifndef GLX_VERSION_1_3 -#define GLX_VERSION_1_3 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern GLXFBConfig * glXGetFBConfigs (Display *dpy, int screen, int *nelements); -extern GLXFBConfig * glXChooseFBConfig (Display *dpy, int screen, const int *attrib_list, int *nelements); -extern int glXGetFBConfigAttrib (Display *dpy, GLXFBConfig config, int attribute, int *value); -extern XVisualInfo * glXGetVisualFromFBConfig (Display *dpy, GLXFBConfig config); -extern GLXWindow glXCreateWindow (Display *dpy, GLXFBConfig config, Window win, const int *attrib_list); -extern void glXDestroyWindow (Display *dpy, GLXWindow win); -extern GLXPixmap glXCreatePixmap (Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attrib_list); -extern void glXDestroyPixmap (Display *dpy, GLXPixmap pixmap); -extern GLXPbuffer glXCreatePbuffer (Display *dpy, GLXFBConfig config, const int *attrib_list); -extern void glXDestroyPbuffer (Display *dpy, GLXPbuffer pbuf); -extern void glXQueryDrawable (Display *dpy, GLXDrawable draw, int attribute, unsigned int *value); -extern GLXContext glXCreateNewContext (Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct); -extern Bool glXMakeContextCurrent (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx); -extern GLXDrawable glXGetCurrentReadDrawable (void); -extern Display * glXGetCurrentDisplay (void); -extern int glXQueryContext (Display *dpy, GLXContext ctx, int attribute, int *value); -extern void glXSelectEvent (Display *dpy, GLXDrawable draw, unsigned long event_mask); -extern void glXGetSelectedEvent (Display *dpy, GLXDrawable draw, unsigned long *event_mask); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef GLXFBConfig * ( * PFNGLXGETFBCONFIGSPROC) (Display *dpy, int screen, int *nelements); -typedef GLXFBConfig * ( * PFNGLXCHOOSEFBCONFIGPROC) (Display *dpy, int screen, const int *attrib_list, int *nelements); -typedef int ( * PFNGLXGETFBCONFIGATTRIBPROC) (Display *dpy, GLXFBConfig config, int attribute, int *value); -typedef XVisualInfo * ( * PFNGLXGETVISUALFROMFBCONFIGPROC) (Display *dpy, GLXFBConfig config); -typedef GLXWindow ( * PFNGLXCREATEWINDOWPROC) (Display *dpy, GLXFBConfig config, Window win, const int *attrib_list); -typedef void ( * PFNGLXDESTROYWINDOWPROC) (Display *dpy, GLXWindow win); -typedef GLXPixmap ( * PFNGLXCREATEPIXMAPPROC) (Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attrib_list); -typedef void ( * PFNGLXDESTROYPIXMAPPROC) (Display *dpy, GLXPixmap pixmap); -typedef GLXPbuffer ( * PFNGLXCREATEPBUFFERPROC) (Display *dpy, GLXFBConfig config, const int *attrib_list); -typedef void ( * PFNGLXDESTROYPBUFFERPROC) (Display *dpy, GLXPbuffer pbuf); -typedef void ( * PFNGLXQUERYDRAWABLEPROC) (Display *dpy, GLXDrawable draw, int attribute, unsigned int *value); -typedef GLXContext ( * PFNGLXCREATENEWCONTEXTPROC) (Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct); -typedef Bool ( * PFNGLXMAKECONTEXTCURRENTPROC) (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx); -typedef GLXDrawable ( * PFNGLXGETCURRENTREADDRAWABLEPROC) (void); -typedef Display * ( * PFNGLXGETCURRENTDISPLAYPROC) (void); -typedef int ( * PFNGLXQUERYCONTEXTPROC) (Display *dpy, GLXContext ctx, int attribute, int *value); -typedef void ( * PFNGLXSELECTEVENTPROC) (Display *dpy, GLXDrawable draw, unsigned long event_mask); -typedef void ( * PFNGLXGETSELECTEDEVENTPROC) (Display *dpy, GLXDrawable draw, unsigned long *event_mask); -#endif - -#ifndef GLX_VERSION_1_4 -#define GLX_VERSION_1_4 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern __GLXextFuncPtr glXGetProcAddress (const GLubyte *procName); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef __GLXextFuncPtr ( * PFNGLXGETPROCADDRESSPROC) (const GLubyte *procName); -#endif - -#ifndef GLX_ARB_get_proc_address -#define GLX_ARB_get_proc_address 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern __GLXextFuncPtr glXGetProcAddressARB (const GLubyte *procName); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef __GLXextFuncPtr ( * PFNGLXGETPROCADDRESSARBPROC) (const GLubyte *procName); -#endif - -#ifndef GLX_ARB_multisample -#define GLX_ARB_multisample 1 -#endif - -#ifndef GLX_ARB_fbconfig_float -#define GLX_ARB_fbconfig_float 1 -#endif - -#ifndef GLX_ARB_framebuffer_sRGB -#define GLX_ARB_framebuffer_sRGB 1 -#endif - -#ifndef GLX_ARB_create_context -#define GLX_ARB_create_context 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern GLXContext glXCreateContextAttribsARB (Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef GLXContext ( * PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list); -#endif - -#ifndef GLX_ARB_create_context_profile -#define GLX_ARB_create_context_profile 1 -#endif - -#ifndef GLX_ARB_create_context_robustness -#define GLX_ARB_create_context_robustness 1 -#endif - -#ifndef GLX_SGIS_multisample -#define GLX_SGIS_multisample 1 -#endif - -#ifndef GLX_EXT_visual_info -#define GLX_EXT_visual_info 1 -#endif - -#ifndef GLX_SGI_swap_control -#define GLX_SGI_swap_control 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern int glXSwapIntervalSGI (int interval); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef int ( * PFNGLXSWAPINTERVALSGIPROC) (int interval); -#endif - -#ifndef GLX_SGI_video_sync -#define GLX_SGI_video_sync 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern int glXGetVideoSyncSGI (unsigned int *count); -extern int glXWaitVideoSyncSGI (int divisor, int remainder, unsigned int *count); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef int ( * PFNGLXGETVIDEOSYNCSGIPROC) (unsigned int *count); -typedef int ( * PFNGLXWAITVIDEOSYNCSGIPROC) (int divisor, int remainder, unsigned int *count); -#endif - -#ifndef GLX_SGI_make_current_read -#define GLX_SGI_make_current_read 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern Bool glXMakeCurrentReadSGI (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx); -extern GLXDrawable glXGetCurrentReadDrawableSGI (void); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef Bool ( * PFNGLXMAKECURRENTREADSGIPROC) (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx); -typedef GLXDrawable ( * PFNGLXGETCURRENTREADDRAWABLESGIPROC) (void); -#endif - -#ifndef GLX_SGIX_video_source -#define GLX_SGIX_video_source 1 -#ifdef _VL_H -#ifdef GLX_GLXEXT_PROTOTYPES -extern GLXVideoSourceSGIX glXCreateGLXVideoSourceSGIX (Display *display, int screen, VLServer server, VLPath path, int nodeClass, VLNode drainNode); -extern void glXDestroyGLXVideoSourceSGIX (Display *dpy, GLXVideoSourceSGIX glxvideosource); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef GLXVideoSourceSGIX ( * PFNGLXCREATEGLXVIDEOSOURCESGIXPROC) (Display *display, int screen, VLServer server, VLPath path, int nodeClass, VLNode drainNode); -typedef void ( * PFNGLXDESTROYGLXVIDEOSOURCESGIXPROC) (Display *dpy, GLXVideoSourceSGIX glxvideosource); -#endif /* _VL_H */ -#endif - -#ifndef GLX_EXT_visual_rating -#define GLX_EXT_visual_rating 1 -#endif - -#ifndef GLX_EXT_import_context -#define GLX_EXT_import_context 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern Display * glXGetCurrentDisplayEXT (void); -extern int glXQueryContextInfoEXT (Display *dpy, GLXContext context, int attribute, int *value); -extern GLXContextID glXGetContextIDEXT (const GLXContext context); -extern GLXContext glXImportContextEXT (Display *dpy, GLXContextID contextID); -extern void glXFreeContextEXT (Display *dpy, GLXContext context); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef Display * ( * PFNGLXGETCURRENTDISPLAYEXTPROC) (void); -typedef int ( * PFNGLXQUERYCONTEXTINFOEXTPROC) (Display *dpy, GLXContext context, int attribute, int *value); -typedef GLXContextID ( * PFNGLXGETCONTEXTIDEXTPROC) (const GLXContext context); -typedef GLXContext ( * PFNGLXIMPORTCONTEXTEXTPROC) (Display *dpy, GLXContextID contextID); -typedef void ( * PFNGLXFREECONTEXTEXTPROC) (Display *dpy, GLXContext context); -#endif - -#ifndef GLX_SGIX_fbconfig -#define GLX_SGIX_fbconfig 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern int glXGetFBConfigAttribSGIX (Display *dpy, GLXFBConfigSGIX config, int attribute, int *value); -extern GLXFBConfigSGIX * glXChooseFBConfigSGIX (Display *dpy, int screen, int *attrib_list, int *nelements); -extern GLXPixmap glXCreateGLXPixmapWithConfigSGIX (Display *dpy, GLXFBConfigSGIX config, Pixmap pixmap); -extern GLXContext glXCreateContextWithConfigSGIX (Display *dpy, GLXFBConfigSGIX config, int render_type, GLXContext share_list, Bool direct); -extern XVisualInfo * glXGetVisualFromFBConfigSGIX (Display *dpy, GLXFBConfigSGIX config); -extern GLXFBConfigSGIX glXGetFBConfigFromVisualSGIX (Display *dpy, XVisualInfo *vis); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef int ( * PFNGLXGETFBCONFIGATTRIBSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, int attribute, int *value); -typedef GLXFBConfigSGIX * ( * PFNGLXCHOOSEFBCONFIGSGIXPROC) (Display *dpy, int screen, int *attrib_list, int *nelements); -typedef GLXPixmap ( * PFNGLXCREATEGLXPIXMAPWITHCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, Pixmap pixmap); -typedef GLXContext ( * PFNGLXCREATECONTEXTWITHCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, int render_type, GLXContext share_list, Bool direct); -typedef XVisualInfo * ( * PFNGLXGETVISUALFROMFBCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config); -typedef GLXFBConfigSGIX ( * PFNGLXGETFBCONFIGFROMVISUALSGIXPROC) (Display *dpy, XVisualInfo *vis); -#endif - -#ifndef GLX_SGIX_pbuffer -#define GLX_SGIX_pbuffer 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern GLXPbufferSGIX glXCreateGLXPbufferSGIX (Display *dpy, GLXFBConfigSGIX config, unsigned int width, unsigned int height, int *attrib_list); -extern void glXDestroyGLXPbufferSGIX (Display *dpy, GLXPbufferSGIX pbuf); -extern int glXQueryGLXPbufferSGIX (Display *dpy, GLXPbufferSGIX pbuf, int attribute, unsigned int *value); -extern void glXSelectEventSGIX (Display *dpy, GLXDrawable drawable, unsigned long mask); -extern void glXGetSelectedEventSGIX (Display *dpy, GLXDrawable drawable, unsigned long *mask); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef GLXPbufferSGIX ( * PFNGLXCREATEGLXPBUFFERSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, unsigned int width, unsigned int height, int *attrib_list); -typedef void ( * PFNGLXDESTROYGLXPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuf); -typedef int ( * PFNGLXQUERYGLXPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuf, int attribute, unsigned int *value); -typedef void ( * PFNGLXSELECTEVENTSGIXPROC) (Display *dpy, GLXDrawable drawable, unsigned long mask); -typedef void ( * PFNGLXGETSELECTEDEVENTSGIXPROC) (Display *dpy, GLXDrawable drawable, unsigned long *mask); -#endif - -#ifndef GLX_SGI_cushion -#define GLX_SGI_cushion 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern void glXCushionSGI (Display *dpy, Window window, float cushion); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef void ( * PFNGLXCUSHIONSGIPROC) (Display *dpy, Window window, float cushion); -#endif - -#ifndef GLX_SGIX_video_resize -#define GLX_SGIX_video_resize 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern int glXBindChannelToWindowSGIX (Display *display, int screen, int channel, Window window); -extern int glXChannelRectSGIX (Display *display, int screen, int channel, int x, int y, int w, int h); -extern int glXQueryChannelRectSGIX (Display *display, int screen, int channel, int *dx, int *dy, int *dw, int *dh); -extern int glXQueryChannelDeltasSGIX (Display *display, int screen, int channel, int *x, int *y, int *w, int *h); -extern int glXChannelRectSyncSGIX (Display *display, int screen, int channel, GLenum synctype); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef int ( * PFNGLXBINDCHANNELTOWINDOWSGIXPROC) (Display *display, int screen, int channel, Window window); -typedef int ( * PFNGLXCHANNELRECTSGIXPROC) (Display *display, int screen, int channel, int x, int y, int w, int h); -typedef int ( * PFNGLXQUERYCHANNELRECTSGIXPROC) (Display *display, int screen, int channel, int *dx, int *dy, int *dw, int *dh); -typedef int ( * PFNGLXQUERYCHANNELDELTASSGIXPROC) (Display *display, int screen, int channel, int *x, int *y, int *w, int *h); -typedef int ( * PFNGLXCHANNELRECTSYNCSGIXPROC) (Display *display, int screen, int channel, GLenum synctype); -#endif - -#ifndef GLX_SGIX_dmbuffer -#define GLX_SGIX_dmbuffer 1 -#ifdef _DM_BUFFER_H_ -#ifdef GLX_GLXEXT_PROTOTYPES -extern Bool glXAssociateDMPbufferSGIX (Display *dpy, GLXPbufferSGIX pbuffer, DMparams *params, DMbuffer dmbuffer); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef Bool ( * PFNGLXASSOCIATEDMPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuffer, DMparams *params, DMbuffer dmbuffer); -#endif /* _DM_BUFFER_H_ */ -#endif - -#ifndef GLX_SGIX_swap_group -#define GLX_SGIX_swap_group 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern void glXJoinSwapGroupSGIX (Display *dpy, GLXDrawable drawable, GLXDrawable member); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef void ( * PFNGLXJOINSWAPGROUPSGIXPROC) (Display *dpy, GLXDrawable drawable, GLXDrawable member); -#endif - -#ifndef GLX_SGIX_swap_barrier -#define GLX_SGIX_swap_barrier 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern void glXBindSwapBarrierSGIX (Display *dpy, GLXDrawable drawable, int barrier); -extern Bool glXQueryMaxSwapBarriersSGIX (Display *dpy, int screen, int *max); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef void ( * PFNGLXBINDSWAPBARRIERSGIXPROC) (Display *dpy, GLXDrawable drawable, int barrier); -typedef Bool ( * PFNGLXQUERYMAXSWAPBARRIERSSGIXPROC) (Display *dpy, int screen, int *max); -#endif - -#ifndef GLX_SUN_get_transparent_index -#define GLX_SUN_get_transparent_index 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern Status glXGetTransparentIndexSUN (Display *dpy, Window overlay, Window underlay, long *pTransparentIndex); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef Status ( * PFNGLXGETTRANSPARENTINDEXSUNPROC) (Display *dpy, Window overlay, Window underlay, long *pTransparentIndex); -#endif - -#ifndef GLX_MESA_copy_sub_buffer -#define GLX_MESA_copy_sub_buffer 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern void glXCopySubBufferMESA (Display *dpy, GLXDrawable drawable, int x, int y, int width, int height); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef void ( * PFNGLXCOPYSUBBUFFERMESAPROC) (Display *dpy, GLXDrawable drawable, int x, int y, int width, int height); -#endif - -#ifndef GLX_MESA_pixmap_colormap -#define GLX_MESA_pixmap_colormap 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern GLXPixmap glXCreateGLXPixmapMESA (Display *dpy, XVisualInfo *visual, Pixmap pixmap, Colormap cmap); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef GLXPixmap ( * PFNGLXCREATEGLXPIXMAPMESAPROC) (Display *dpy, XVisualInfo *visual, Pixmap pixmap, Colormap cmap); -#endif - -#ifndef GLX_MESA_release_buffers -#define GLX_MESA_release_buffers 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern Bool glXReleaseBuffersMESA (Display *dpy, GLXDrawable drawable); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef Bool ( * PFNGLXRELEASEBUFFERSMESAPROC) (Display *dpy, GLXDrawable drawable); -#endif - -#ifndef GLX_MESA_set_3dfx_mode -#define GLX_MESA_set_3dfx_mode 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern Bool glXSet3DfxModeMESA (int mode); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef Bool ( * PFNGLXSET3DFXMODEMESAPROC) (int mode); -#endif - -#ifndef GLX_SGIX_visual_select_group -#define GLX_SGIX_visual_select_group 1 -#endif - -#ifndef GLX_OML_swap_method -#define GLX_OML_swap_method 1 -#endif - -#ifndef GLX_OML_sync_control -#define GLX_OML_sync_control 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern Bool glXGetSyncValuesOML (Display *dpy, GLXDrawable drawable, int64_t *ust, int64_t *msc, int64_t *sbc); -extern Bool glXGetMscRateOML (Display *dpy, GLXDrawable drawable, int32_t *numerator, int32_t *denominator); -extern int64_t glXSwapBuffersMscOML (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder); -extern Bool glXWaitForMscOML (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc); -extern Bool glXWaitForSbcOML (Display *dpy, GLXDrawable drawable, int64_t target_sbc, int64_t *ust, int64_t *msc, int64_t *sbc); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef Bool ( * PFNGLXGETSYNCVALUESOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t *ust, int64_t *msc, int64_t *sbc); -typedef Bool ( * PFNGLXGETMSCRATEOMLPROC) (Display *dpy, GLXDrawable drawable, int32_t *numerator, int32_t *denominator); -typedef int64_t ( * PFNGLXSWAPBUFFERSMSCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder); -typedef Bool ( * PFNGLXWAITFORMSCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc); -typedef Bool ( * PFNGLXWAITFORSBCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_sbc, int64_t *ust, int64_t *msc, int64_t *sbc); -#endif - -#ifndef GLX_NV_float_buffer -#define GLX_NV_float_buffer 1 -#endif - -#ifndef GLX_SGIX_hyperpipe -#define GLX_SGIX_hyperpipe 1 - -typedef struct { - char pipeName[GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX]; - int networkId; -} GLXHyperpipeNetworkSGIX; - -typedef struct { - char pipeName[GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX]; - int channel; - unsigned int - participationType; - int timeSlice; -} GLXHyperpipeConfigSGIX; - -typedef struct { - char pipeName[GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX]; - int srcXOrigin, srcYOrigin, srcWidth, srcHeight; - int destXOrigin, destYOrigin, destWidth, destHeight; -} GLXPipeRect; - -typedef struct { - char pipeName[GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX]; - int XOrigin, YOrigin, maxHeight, maxWidth; -} GLXPipeRectLimits; - -#ifdef GLX_GLXEXT_PROTOTYPES -extern GLXHyperpipeNetworkSGIX * glXQueryHyperpipeNetworkSGIX (Display *dpy, int *npipes); -extern int glXHyperpipeConfigSGIX (Display *dpy, int networkId, int npipes, GLXHyperpipeConfigSGIX *cfg, int *hpId); -extern GLXHyperpipeConfigSGIX * glXQueryHyperpipeConfigSGIX (Display *dpy, int hpId, int *npipes); -extern int glXDestroyHyperpipeConfigSGIX (Display *dpy, int hpId); -extern int glXBindHyperpipeSGIX (Display *dpy, int hpId); -extern int glXQueryHyperpipeBestAttribSGIX (Display *dpy, int timeSlice, int attrib, int size, void *attribList, void *returnAttribList); -extern int glXHyperpipeAttribSGIX (Display *dpy, int timeSlice, int attrib, int size, void *attribList); -extern int glXQueryHyperpipeAttribSGIX (Display *dpy, int timeSlice, int attrib, int size, void *returnAttribList); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef GLXHyperpipeNetworkSGIX * ( * PFNGLXQUERYHYPERPIPENETWORKSGIXPROC) (Display *dpy, int *npipes); -typedef int ( * PFNGLXHYPERPIPECONFIGSGIXPROC) (Display *dpy, int networkId, int npipes, GLXHyperpipeConfigSGIX *cfg, int *hpId); -typedef GLXHyperpipeConfigSGIX * ( * PFNGLXQUERYHYPERPIPECONFIGSGIXPROC) (Display *dpy, int hpId, int *npipes); -typedef int ( * PFNGLXDESTROYHYPERPIPECONFIGSGIXPROC) (Display *dpy, int hpId); -typedef int ( * PFNGLXBINDHYPERPIPESGIXPROC) (Display *dpy, int hpId); -typedef int ( * PFNGLXQUERYHYPERPIPEBESTATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *attribList, void *returnAttribList); -typedef int ( * PFNGLXHYPERPIPEATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *attribList); -typedef int ( * PFNGLXQUERYHYPERPIPEATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *returnAttribList); -#endif - -#ifndef GLX_MESA_agp_offset -#define GLX_MESA_agp_offset 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern unsigned int glXGetAGPOffsetMESA (const void *pointer); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef unsigned int ( * PFNGLXGETAGPOFFSETMESAPROC) (const void *pointer); -#endif - -#ifndef GLX_EXT_fbconfig_packed_float -#define GLX_EXT_fbconfig_packed_float 1 -#endif - -#ifndef GLX_EXT_framebuffer_sRGB -#define GLX_EXT_framebuffer_sRGB 1 -#endif - -#ifndef GLX_EXT_texture_from_pixmap -#define GLX_EXT_texture_from_pixmap 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern void glXBindTexImageEXT (Display *dpy, GLXDrawable drawable, int buffer, const int *attrib_list); -extern void glXReleaseTexImageEXT (Display *dpy, GLXDrawable drawable, int buffer); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef void ( * PFNGLXBINDTEXIMAGEEXTPROC) (Display *dpy, GLXDrawable drawable, int buffer, const int *attrib_list); -typedef void ( * PFNGLXRELEASETEXIMAGEEXTPROC) (Display *dpy, GLXDrawable drawable, int buffer); -#endif - -#ifndef GLX_NV_present_video -#define GLX_NV_present_video 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern unsigned int * glXEnumerateVideoDevicesNV (Display *dpy, int screen, int *nelements); -extern int glXBindVideoDeviceNV (Display *dpy, unsigned int video_slot, unsigned int video_device, const int *attrib_list); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef unsigned int * ( * PFNGLXENUMERATEVIDEODEVICESNVPROC) (Display *dpy, int screen, int *nelements); -typedef int ( * PFNGLXBINDVIDEODEVICENVPROC) (Display *dpy, unsigned int video_slot, unsigned int video_device, const int *attrib_list); -#endif - -#ifndef GLX_NV_video_output -#define GLX_NV_video_output 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern int glXGetVideoDeviceNV (Display *dpy, int screen, int numVideoDevices, GLXVideoDeviceNV *pVideoDevice); -extern int glXReleaseVideoDeviceNV (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice); -extern int glXBindVideoImageNV (Display *dpy, GLXVideoDeviceNV VideoDevice, GLXPbuffer pbuf, int iVideoBuffer); -extern int glXReleaseVideoImageNV (Display *dpy, GLXPbuffer pbuf); -extern int glXSendPbufferToVideoNV (Display *dpy, GLXPbuffer pbuf, int iBufferType, unsigned long *pulCounterPbuffer, GLboolean bBlock); -extern int glXGetVideoInfoNV (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef int ( * PFNGLXGETVIDEODEVICENVPROC) (Display *dpy, int screen, int numVideoDevices, GLXVideoDeviceNV *pVideoDevice); -typedef int ( * PFNGLXRELEASEVIDEODEVICENVPROC) (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice); -typedef int ( * PFNGLXBINDVIDEOIMAGENVPROC) (Display *dpy, GLXVideoDeviceNV VideoDevice, GLXPbuffer pbuf, int iVideoBuffer); -typedef int ( * PFNGLXRELEASEVIDEOIMAGENVPROC) (Display *dpy, GLXPbuffer pbuf); -typedef int ( * PFNGLXSENDPBUFFERTOVIDEONVPROC) (Display *dpy, GLXPbuffer pbuf, int iBufferType, unsigned long *pulCounterPbuffer, GLboolean bBlock); -typedef int ( * PFNGLXGETVIDEOINFONVPROC) (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo); -#endif - -#ifndef GLX_NV_swap_group -#define GLX_NV_swap_group 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern Bool glXJoinSwapGroupNV (Display *dpy, GLXDrawable drawable, GLuint group); -extern Bool glXBindSwapBarrierNV (Display *dpy, GLuint group, GLuint barrier); -extern Bool glXQuerySwapGroupNV (Display *dpy, GLXDrawable drawable, GLuint *group, GLuint *barrier); -extern Bool glXQueryMaxSwapGroupsNV (Display *dpy, int screen, GLuint *maxGroups, GLuint *maxBarriers); -extern Bool glXQueryFrameCountNV (Display *dpy, int screen, GLuint *count); -extern Bool glXResetFrameCountNV (Display *dpy, int screen); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef Bool ( * PFNGLXJOINSWAPGROUPNVPROC) (Display *dpy, GLXDrawable drawable, GLuint group); -typedef Bool ( * PFNGLXBINDSWAPBARRIERNVPROC) (Display *dpy, GLuint group, GLuint barrier); -typedef Bool ( * PFNGLXQUERYSWAPGROUPNVPROC) (Display *dpy, GLXDrawable drawable, GLuint *group, GLuint *barrier); -typedef Bool ( * PFNGLXQUERYMAXSWAPGROUPSNVPROC) (Display *dpy, int screen, GLuint *maxGroups, GLuint *maxBarriers); -typedef Bool ( * PFNGLXQUERYFRAMECOUNTNVPROC) (Display *dpy, int screen, GLuint *count); -typedef Bool ( * PFNGLXRESETFRAMECOUNTNVPROC) (Display *dpy, int screen); -#endif - -#ifndef GLX_NV_video_capture -#define GLX_NV_video_capture 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern int glXBindVideoCaptureDeviceNV (Display *dpy, unsigned int video_capture_slot, GLXVideoCaptureDeviceNV device); -extern GLXVideoCaptureDeviceNV * glXEnumerateVideoCaptureDevicesNV (Display *dpy, int screen, int *nelements); -extern void glXLockVideoCaptureDeviceNV (Display *dpy, GLXVideoCaptureDeviceNV device); -extern int glXQueryVideoCaptureDeviceNV (Display *dpy, GLXVideoCaptureDeviceNV device, int attribute, int *value); -extern void glXReleaseVideoCaptureDeviceNV (Display *dpy, GLXVideoCaptureDeviceNV device); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef int ( * PFNGLXBINDVIDEOCAPTUREDEVICENVPROC) (Display *dpy, unsigned int video_capture_slot, GLXVideoCaptureDeviceNV device); -typedef GLXVideoCaptureDeviceNV * ( * PFNGLXENUMERATEVIDEOCAPTUREDEVICESNVPROC) (Display *dpy, int screen, int *nelements); -typedef void ( * PFNGLXLOCKVIDEOCAPTUREDEVICENVPROC) (Display *dpy, GLXVideoCaptureDeviceNV device); -typedef int ( * PFNGLXQUERYVIDEOCAPTUREDEVICENVPROC) (Display *dpy, GLXVideoCaptureDeviceNV device, int attribute, int *value); -typedef void ( * PFNGLXRELEASEVIDEOCAPTUREDEVICENVPROC) (Display *dpy, GLXVideoCaptureDeviceNV device); -#endif - -#ifndef GLX_EXT_swap_control -#define GLX_EXT_swap_control 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern void glXSwapIntervalEXT (Display *dpy, GLXDrawable drawable, int interval); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef void ( * PFNGLXSWAPINTERVALEXTPROC) (Display *dpy, GLXDrawable drawable, int interval); -#endif - -#ifndef GLX_NV_copy_image -#define GLX_NV_copy_image 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern void glXCopyImageSubDataNV (Display *dpy, GLXContext srcCtx, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLXContext dstCtx, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef void ( * PFNGLXCOPYIMAGESUBDATANVPROC) (Display *dpy, GLXContext srcCtx, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLXContext dstCtx, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); -#endif - -#ifndef GLX_INTEL_swap_event -#define GLX_INTEL_swap_event 1 -#endif - -#ifndef GLX_NV_multisample_coverage -#define GLX_NV_multisample_coverage 1 -#endif - -#ifndef GLX_EXT_swap_control_tear -#define GLX_EXT_swap_control_tear 1 -#endif - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/freeglut/include/GL/wglext.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/freeglut/include/GL/wglext.h deleted file mode 100644 index b5dc7bf7f132..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/freeglut/include/GL/wglext.h +++ /dev/null @@ -1,943 +0,0 @@ -#ifndef __wglext_h_ -#define __wglext_h_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** Copyright (c) 2007-2012 The Khronos Group Inc. -** -** Permission is hereby granted, free of charge, to any person obtaining a -** copy of this software and/or associated documentation files (the -** "Materials"), to deal in the Materials without restriction, including -** without limitation the rights to use, copy, modify, merge, publish, -** distribute, sublicense, and/or sell copies of the Materials, and to -** permit persons to whom the Materials are furnished to do so, subject to -** the following conditions: -** -** The above copyright notice and this permission notice shall be included -** in all copies or substantial portions of the Materials. -** -** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. -*/ - -/* Function declaration macros - to move into glplatform.h */ - -#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) -#define WIN32_LEAN_AND_MEAN 1 -#include -#endif - -#ifndef APIENTRY -#define APIENTRY -#endif -#ifndef APIENTRYP -#define APIENTRYP APIENTRY * -#endif -#ifndef GLAPI -#define GLAPI extern -#endif - -/*************************************************************/ - -/* Header file version number */ -/* wglext.h last updated 2012/01/04 */ -/* Current version at http://www.opengl.org/registry/ */ -#define WGL_WGLEXT_VERSION 24 - -#ifndef WGL_ARB_buffer_region -#define WGL_FRONT_COLOR_BUFFER_BIT_ARB 0x00000001 -#define WGL_BACK_COLOR_BUFFER_BIT_ARB 0x00000002 -#define WGL_DEPTH_BUFFER_BIT_ARB 0x00000004 -#define WGL_STENCIL_BUFFER_BIT_ARB 0x00000008 -#endif - -#ifndef WGL_ARB_multisample -#define WGL_SAMPLE_BUFFERS_ARB 0x2041 -#define WGL_SAMPLES_ARB 0x2042 -#endif - -#ifndef WGL_ARB_extensions_string -#endif - -#ifndef WGL_ARB_pixel_format -#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 -#define WGL_DRAW_TO_WINDOW_ARB 0x2001 -#define WGL_DRAW_TO_BITMAP_ARB 0x2002 -#define WGL_ACCELERATION_ARB 0x2003 -#define WGL_NEED_PALETTE_ARB 0x2004 -#define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005 -#define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006 -#define WGL_SWAP_METHOD_ARB 0x2007 -#define WGL_NUMBER_OVERLAYS_ARB 0x2008 -#define WGL_NUMBER_UNDERLAYS_ARB 0x2009 -#define WGL_TRANSPARENT_ARB 0x200A -#define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037 -#define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038 -#define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039 -#define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A -#define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B -#define WGL_SHARE_DEPTH_ARB 0x200C -#define WGL_SHARE_STENCIL_ARB 0x200D -#define WGL_SHARE_ACCUM_ARB 0x200E -#define WGL_SUPPORT_GDI_ARB 0x200F -#define WGL_SUPPORT_OPENGL_ARB 0x2010 -#define WGL_DOUBLE_BUFFER_ARB 0x2011 -#define WGL_STEREO_ARB 0x2012 -#define WGL_PIXEL_TYPE_ARB 0x2013 -#define WGL_COLOR_BITS_ARB 0x2014 -#define WGL_RED_BITS_ARB 0x2015 -#define WGL_RED_SHIFT_ARB 0x2016 -#define WGL_GREEN_BITS_ARB 0x2017 -#define WGL_GREEN_SHIFT_ARB 0x2018 -#define WGL_BLUE_BITS_ARB 0x2019 -#define WGL_BLUE_SHIFT_ARB 0x201A -#define WGL_ALPHA_BITS_ARB 0x201B -#define WGL_ALPHA_SHIFT_ARB 0x201C -#define WGL_ACCUM_BITS_ARB 0x201D -#define WGL_ACCUM_RED_BITS_ARB 0x201E -#define WGL_ACCUM_GREEN_BITS_ARB 0x201F -#define WGL_ACCUM_BLUE_BITS_ARB 0x2020 -#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 -#define WGL_DEPTH_BITS_ARB 0x2022 -#define WGL_STENCIL_BITS_ARB 0x2023 -#define WGL_AUX_BUFFERS_ARB 0x2024 -#define WGL_NO_ACCELERATION_ARB 0x2025 -#define WGL_GENERIC_ACCELERATION_ARB 0x2026 -#define WGL_FULL_ACCELERATION_ARB 0x2027 -#define WGL_SWAP_EXCHANGE_ARB 0x2028 -#define WGL_SWAP_COPY_ARB 0x2029 -#define WGL_SWAP_UNDEFINED_ARB 0x202A -#define WGL_TYPE_RGBA_ARB 0x202B -#define WGL_TYPE_COLORINDEX_ARB 0x202C -#endif - -#ifndef WGL_ARB_make_current_read -#define ERROR_INVALID_PIXEL_TYPE_ARB 0x2043 -#define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054 -#endif - -#ifndef WGL_ARB_pbuffer -#define WGL_DRAW_TO_PBUFFER_ARB 0x202D -#define WGL_MAX_PBUFFER_PIXELS_ARB 0x202E -#define WGL_MAX_PBUFFER_WIDTH_ARB 0x202F -#define WGL_MAX_PBUFFER_HEIGHT_ARB 0x2030 -#define WGL_PBUFFER_LARGEST_ARB 0x2033 -#define WGL_PBUFFER_WIDTH_ARB 0x2034 -#define WGL_PBUFFER_HEIGHT_ARB 0x2035 -#define WGL_PBUFFER_LOST_ARB 0x2036 -#endif - -#ifndef WGL_ARB_render_texture -#define WGL_BIND_TO_TEXTURE_RGB_ARB 0x2070 -#define WGL_BIND_TO_TEXTURE_RGBA_ARB 0x2071 -#define WGL_TEXTURE_FORMAT_ARB 0x2072 -#define WGL_TEXTURE_TARGET_ARB 0x2073 -#define WGL_MIPMAP_TEXTURE_ARB 0x2074 -#define WGL_TEXTURE_RGB_ARB 0x2075 -#define WGL_TEXTURE_RGBA_ARB 0x2076 -#define WGL_NO_TEXTURE_ARB 0x2077 -#define WGL_TEXTURE_CUBE_MAP_ARB 0x2078 -#define WGL_TEXTURE_1D_ARB 0x2079 -#define WGL_TEXTURE_2D_ARB 0x207A -#define WGL_MIPMAP_LEVEL_ARB 0x207B -#define WGL_CUBE_MAP_FACE_ARB 0x207C -#define WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x207D -#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x207E -#define WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x207F -#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x2080 -#define WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x2081 -#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x2082 -#define WGL_FRONT_LEFT_ARB 0x2083 -#define WGL_FRONT_RIGHT_ARB 0x2084 -#define WGL_BACK_LEFT_ARB 0x2085 -#define WGL_BACK_RIGHT_ARB 0x2086 -#define WGL_AUX0_ARB 0x2087 -#define WGL_AUX1_ARB 0x2088 -#define WGL_AUX2_ARB 0x2089 -#define WGL_AUX3_ARB 0x208A -#define WGL_AUX4_ARB 0x208B -#define WGL_AUX5_ARB 0x208C -#define WGL_AUX6_ARB 0x208D -#define WGL_AUX7_ARB 0x208E -#define WGL_AUX8_ARB 0x208F -#define WGL_AUX9_ARB 0x2090 -#endif - -#ifndef WGL_ARB_pixel_format_float -#define WGL_TYPE_RGBA_FLOAT_ARB 0x21A0 -#endif - -#ifndef WGL_ARB_framebuffer_sRGB -#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9 -#endif - -#ifndef WGL_ARB_create_context -#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 -#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 -#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 -#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 -#define WGL_CONTEXT_FLAGS_ARB 0x2094 -#define ERROR_INVALID_VERSION_ARB 0x2095 -#endif - -#ifndef WGL_ARB_create_context_profile -#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 -#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 -#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 -#define ERROR_INVALID_PROFILE_ARB 0x2096 -#endif - -#ifndef WGL_ARB_create_context_robustness -#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 -#define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 -#define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 -#define WGL_NO_RESET_NOTIFICATION_ARB 0x8261 -#endif - -#ifndef WGL_EXT_make_current_read -#define ERROR_INVALID_PIXEL_TYPE_EXT 0x2043 -#endif - -#ifndef WGL_EXT_pixel_format -#define WGL_NUMBER_PIXEL_FORMATS_EXT 0x2000 -#define WGL_DRAW_TO_WINDOW_EXT 0x2001 -#define WGL_DRAW_TO_BITMAP_EXT 0x2002 -#define WGL_ACCELERATION_EXT 0x2003 -#define WGL_NEED_PALETTE_EXT 0x2004 -#define WGL_NEED_SYSTEM_PALETTE_EXT 0x2005 -#define WGL_SWAP_LAYER_BUFFERS_EXT 0x2006 -#define WGL_SWAP_METHOD_EXT 0x2007 -#define WGL_NUMBER_OVERLAYS_EXT 0x2008 -#define WGL_NUMBER_UNDERLAYS_EXT 0x2009 -#define WGL_TRANSPARENT_EXT 0x200A -#define WGL_TRANSPARENT_VALUE_EXT 0x200B -#define WGL_SHARE_DEPTH_EXT 0x200C -#define WGL_SHARE_STENCIL_EXT 0x200D -#define WGL_SHARE_ACCUM_EXT 0x200E -#define WGL_SUPPORT_GDI_EXT 0x200F -#define WGL_SUPPORT_OPENGL_EXT 0x2010 -#define WGL_DOUBLE_BUFFER_EXT 0x2011 -#define WGL_STEREO_EXT 0x2012 -#define WGL_PIXEL_TYPE_EXT 0x2013 -#define WGL_COLOR_BITS_EXT 0x2014 -#define WGL_RED_BITS_EXT 0x2015 -#define WGL_RED_SHIFT_EXT 0x2016 -#define WGL_GREEN_BITS_EXT 0x2017 -#define WGL_GREEN_SHIFT_EXT 0x2018 -#define WGL_BLUE_BITS_EXT 0x2019 -#define WGL_BLUE_SHIFT_EXT 0x201A -#define WGL_ALPHA_BITS_EXT 0x201B -#define WGL_ALPHA_SHIFT_EXT 0x201C -#define WGL_ACCUM_BITS_EXT 0x201D -#define WGL_ACCUM_RED_BITS_EXT 0x201E -#define WGL_ACCUM_GREEN_BITS_EXT 0x201F -#define WGL_ACCUM_BLUE_BITS_EXT 0x2020 -#define WGL_ACCUM_ALPHA_BITS_EXT 0x2021 -#define WGL_DEPTH_BITS_EXT 0x2022 -#define WGL_STENCIL_BITS_EXT 0x2023 -#define WGL_AUX_BUFFERS_EXT 0x2024 -#define WGL_NO_ACCELERATION_EXT 0x2025 -#define WGL_GENERIC_ACCELERATION_EXT 0x2026 -#define WGL_FULL_ACCELERATION_EXT 0x2027 -#define WGL_SWAP_EXCHANGE_EXT 0x2028 -#define WGL_SWAP_COPY_EXT 0x2029 -#define WGL_SWAP_UNDEFINED_EXT 0x202A -#define WGL_TYPE_RGBA_EXT 0x202B -#define WGL_TYPE_COLORINDEX_EXT 0x202C -#endif - -#ifndef WGL_EXT_pbuffer -#define WGL_DRAW_TO_PBUFFER_EXT 0x202D -#define WGL_MAX_PBUFFER_PIXELS_EXT 0x202E -#define WGL_MAX_PBUFFER_WIDTH_EXT 0x202F -#define WGL_MAX_PBUFFER_HEIGHT_EXT 0x2030 -#define WGL_OPTIMAL_PBUFFER_WIDTH_EXT 0x2031 -#define WGL_OPTIMAL_PBUFFER_HEIGHT_EXT 0x2032 -#define WGL_PBUFFER_LARGEST_EXT 0x2033 -#define WGL_PBUFFER_WIDTH_EXT 0x2034 -#define WGL_PBUFFER_HEIGHT_EXT 0x2035 -#endif - -#ifndef WGL_EXT_depth_float -#define WGL_DEPTH_FLOAT_EXT 0x2040 -#endif - -#ifndef WGL_3DFX_multisample -#define WGL_SAMPLE_BUFFERS_3DFX 0x2060 -#define WGL_SAMPLES_3DFX 0x2061 -#endif - -#ifndef WGL_EXT_multisample -#define WGL_SAMPLE_BUFFERS_EXT 0x2041 -#define WGL_SAMPLES_EXT 0x2042 -#endif - -#ifndef WGL_I3D_digital_video_control -#define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_FRAMEBUFFER_I3D 0x2050 -#define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_VALUE_I3D 0x2051 -#define WGL_DIGITAL_VIDEO_CURSOR_INCLUDED_I3D 0x2052 -#define WGL_DIGITAL_VIDEO_GAMMA_CORRECTED_I3D 0x2053 -#endif - -#ifndef WGL_I3D_gamma -#define WGL_GAMMA_TABLE_SIZE_I3D 0x204E -#define WGL_GAMMA_EXCLUDE_DESKTOP_I3D 0x204F -#endif - -#ifndef WGL_I3D_genlock -#define WGL_GENLOCK_SOURCE_MULTIVIEW_I3D 0x2044 -#define WGL_GENLOCK_SOURCE_EXTENAL_SYNC_I3D 0x2045 -#define WGL_GENLOCK_SOURCE_EXTENAL_FIELD_I3D 0x2046 -#define WGL_GENLOCK_SOURCE_EXTENAL_TTL_I3D 0x2047 -#define WGL_GENLOCK_SOURCE_DIGITAL_SYNC_I3D 0x2048 -#define WGL_GENLOCK_SOURCE_DIGITAL_FIELD_I3D 0x2049 -#define WGL_GENLOCK_SOURCE_EDGE_FALLING_I3D 0x204A -#define WGL_GENLOCK_SOURCE_EDGE_RISING_I3D 0x204B -#define WGL_GENLOCK_SOURCE_EDGE_BOTH_I3D 0x204C -#endif - -#ifndef WGL_I3D_image_buffer -#define WGL_IMAGE_BUFFER_MIN_ACCESS_I3D 0x00000001 -#define WGL_IMAGE_BUFFER_LOCK_I3D 0x00000002 -#endif - -#ifndef WGL_I3D_swap_frame_lock -#endif - -#ifndef WGL_NV_render_depth_texture -#define WGL_BIND_TO_TEXTURE_DEPTH_NV 0x20A3 -#define WGL_BIND_TO_TEXTURE_RECTANGLE_DEPTH_NV 0x20A4 -#define WGL_DEPTH_TEXTURE_FORMAT_NV 0x20A5 -#define WGL_TEXTURE_DEPTH_COMPONENT_NV 0x20A6 -#define WGL_DEPTH_COMPONENT_NV 0x20A7 -#endif - -#ifndef WGL_NV_render_texture_rectangle -#define WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV 0x20A0 -#define WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV 0x20A1 -#define WGL_TEXTURE_RECTANGLE_NV 0x20A2 -#endif - -#ifndef WGL_ATI_pixel_format_float -#define WGL_TYPE_RGBA_FLOAT_ATI 0x21A0 -#endif - -#ifndef WGL_NV_float_buffer -#define WGL_FLOAT_COMPONENTS_NV 0x20B0 -#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV 0x20B1 -#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV 0x20B2 -#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV 0x20B3 -#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV 0x20B4 -#define WGL_TEXTURE_FLOAT_R_NV 0x20B5 -#define WGL_TEXTURE_FLOAT_RG_NV 0x20B6 -#define WGL_TEXTURE_FLOAT_RGB_NV 0x20B7 -#define WGL_TEXTURE_FLOAT_RGBA_NV 0x20B8 -#endif - -#ifndef WGL_3DL_stereo_control -#define WGL_STEREO_EMITTER_ENABLE_3DL 0x2055 -#define WGL_STEREO_EMITTER_DISABLE_3DL 0x2056 -#define WGL_STEREO_POLARITY_NORMAL_3DL 0x2057 -#define WGL_STEREO_POLARITY_INVERT_3DL 0x2058 -#endif - -#ifndef WGL_EXT_pixel_format_packed_float -#define WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT 0x20A8 -#endif - -#ifndef WGL_EXT_framebuffer_sRGB -#define WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20A9 -#endif - -#ifndef WGL_NV_present_video -#define WGL_NUM_VIDEO_SLOTS_NV 0x20F0 -#endif - -#ifndef WGL_NV_video_out -#define WGL_BIND_TO_VIDEO_RGB_NV 0x20C0 -#define WGL_BIND_TO_VIDEO_RGBA_NV 0x20C1 -#define WGL_BIND_TO_VIDEO_RGB_AND_DEPTH_NV 0x20C2 -#define WGL_VIDEO_OUT_COLOR_NV 0x20C3 -#define WGL_VIDEO_OUT_ALPHA_NV 0x20C4 -#define WGL_VIDEO_OUT_DEPTH_NV 0x20C5 -#define WGL_VIDEO_OUT_COLOR_AND_ALPHA_NV 0x20C6 -#define WGL_VIDEO_OUT_COLOR_AND_DEPTH_NV 0x20C7 -#define WGL_VIDEO_OUT_FRAME 0x20C8 -#define WGL_VIDEO_OUT_FIELD_1 0x20C9 -#define WGL_VIDEO_OUT_FIELD_2 0x20CA -#define WGL_VIDEO_OUT_STACKED_FIELDS_1_2 0x20CB -#define WGL_VIDEO_OUT_STACKED_FIELDS_2_1 0x20CC -#endif - -#ifndef WGL_NV_swap_group -#endif - -#ifndef WGL_NV_gpu_affinity -#define WGL_ERROR_INCOMPATIBLE_AFFINITY_MASKS_NV 0x20D0 -#define WGL_ERROR_MISSING_AFFINITY_MASK_NV 0x20D1 -#endif - -#ifndef WGL_AMD_gpu_association -#define WGL_GPU_VENDOR_AMD 0x1F00 -#define WGL_GPU_RENDERER_STRING_AMD 0x1F01 -#define WGL_GPU_OPENGL_VERSION_STRING_AMD 0x1F02 -#define WGL_GPU_FASTEST_TARGET_GPUS_AMD 0x21A2 -#define WGL_GPU_RAM_AMD 0x21A3 -#define WGL_GPU_CLOCK_AMD 0x21A4 -#define WGL_GPU_NUM_PIPES_AMD 0x21A5 -#define WGL_GPU_NUM_SIMD_AMD 0x21A6 -#define WGL_GPU_NUM_RB_AMD 0x21A7 -#define WGL_GPU_NUM_SPI_AMD 0x21A8 -#endif - -#ifndef WGL_NV_video_capture -#define WGL_UNIQUE_ID_NV 0x20CE -#define WGL_NUM_VIDEO_CAPTURE_SLOTS_NV 0x20CF -#endif - -#ifndef WGL_NV_copy_image -#endif - -#ifndef WGL_NV_multisample_coverage -#define WGL_COVERAGE_SAMPLES_NV 0x2042 -#define WGL_COLOR_SAMPLES_NV 0x20B9 -#endif - -#ifndef WGL_EXT_create_context_es2_profile -#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 -#endif - -#ifndef WGL_NV_DX_interop -#define WGL_ACCESS_READ_ONLY_NV 0x00000000 -#define WGL_ACCESS_READ_WRITE_NV 0x00000001 -#define WGL_ACCESS_WRITE_DISCARD_NV 0x00000002 -#endif - -#ifndef WGL_NV_DX_interop2 -#endif - -#ifndef WGL_EXT_swap_control_tear -#endif - - -/*************************************************************/ - -#ifndef WGL_ARB_pbuffer -DECLARE_HANDLE(HPBUFFERARB); -#endif -#ifndef WGL_EXT_pbuffer -DECLARE_HANDLE(HPBUFFEREXT); -#endif -#ifndef WGL_NV_present_video -DECLARE_HANDLE(HVIDEOOUTPUTDEVICENV); -#endif -#ifndef WGL_NV_video_output -DECLARE_HANDLE(HPVIDEODEV); -#endif -#ifndef WGL_NV_gpu_affinity -DECLARE_HANDLE(HPGPUNV); -DECLARE_HANDLE(HGPUNV); - -typedef struct _GPU_DEVICE { - DWORD cb; - CHAR DeviceName[32]; - CHAR DeviceString[128]; - DWORD Flags; - RECT rcVirtualScreen; -} GPU_DEVICE, *PGPU_DEVICE; -#endif -#ifndef WGL_NV_video_capture -DECLARE_HANDLE(HVIDEOINPUTDEVICENV); -#endif - -#ifndef WGL_ARB_buffer_region -#define WGL_ARB_buffer_region 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern HANDLE WINAPI wglCreateBufferRegionARB (HDC hDC, int iLayerPlane, UINT uType); -extern VOID WINAPI wglDeleteBufferRegionARB (HANDLE hRegion); -extern BOOL WINAPI wglSaveBufferRegionARB (HANDLE hRegion, int x, int y, int width, int height); -extern BOOL WINAPI wglRestoreBufferRegionARB (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef HANDLE (WINAPI * PFNWGLCREATEBUFFERREGIONARBPROC) (HDC hDC, int iLayerPlane, UINT uType); -typedef VOID (WINAPI * PFNWGLDELETEBUFFERREGIONARBPROC) (HANDLE hRegion); -typedef BOOL (WINAPI * PFNWGLSAVEBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height); -typedef BOOL (WINAPI * PFNWGLRESTOREBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc); -#endif - -#ifndef WGL_ARB_multisample -#define WGL_ARB_multisample 1 -#endif - -#ifndef WGL_ARB_extensions_string -#define WGL_ARB_extensions_string 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern const char * WINAPI wglGetExtensionsStringARB (HDC hdc); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc); -#endif - -#ifndef WGL_ARB_pixel_format -#define WGL_ARB_pixel_format 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglGetPixelFormatAttribivARB (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues); -extern BOOL WINAPI wglGetPixelFormatAttribfvARB (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues); -extern BOOL WINAPI wglChoosePixelFormatARB (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues); -typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues); -typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); -#endif - -#ifndef WGL_ARB_make_current_read -#define WGL_ARB_make_current_read 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglMakeContextCurrentARB (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); -extern HDC WINAPI wglGetCurrentReadDCARB (void); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTARBPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); -typedef HDC (WINAPI * PFNWGLGETCURRENTREADDCARBPROC) (void); -#endif - -#ifndef WGL_ARB_pbuffer -#define WGL_ARB_pbuffer 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern HPBUFFERARB WINAPI wglCreatePbufferARB (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); -extern HDC WINAPI wglGetPbufferDCARB (HPBUFFERARB hPbuffer); -extern int WINAPI wglReleasePbufferDCARB (HPBUFFERARB hPbuffer, HDC hDC); -extern BOOL WINAPI wglDestroyPbufferARB (HPBUFFERARB hPbuffer); -extern BOOL WINAPI wglQueryPbufferARB (HPBUFFERARB hPbuffer, int iAttribute, int *piValue); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef HPBUFFERARB (WINAPI * PFNWGLCREATEPBUFFERARBPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); -typedef HDC (WINAPI * PFNWGLGETPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer); -typedef int (WINAPI * PFNWGLRELEASEPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer, HDC hDC); -typedef BOOL (WINAPI * PFNWGLDESTROYPBUFFERARBPROC) (HPBUFFERARB hPbuffer); -typedef BOOL (WINAPI * PFNWGLQUERYPBUFFERARBPROC) (HPBUFFERARB hPbuffer, int iAttribute, int *piValue); -#endif - -#ifndef WGL_ARB_render_texture -#define WGL_ARB_render_texture 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglBindTexImageARB (HPBUFFERARB hPbuffer, int iBuffer); -extern BOOL WINAPI wglReleaseTexImageARB (HPBUFFERARB hPbuffer, int iBuffer); -extern BOOL WINAPI wglSetPbufferAttribARB (HPBUFFERARB hPbuffer, const int *piAttribList); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLBINDTEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer); -typedef BOOL (WINAPI * PFNWGLRELEASETEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer); -typedef BOOL (WINAPI * PFNWGLSETPBUFFERATTRIBARBPROC) (HPBUFFERARB hPbuffer, const int *piAttribList); -#endif - -#ifndef WGL_ARB_pixel_format_float -#define WGL_ARB_pixel_format_float 1 -#endif - -#ifndef WGL_ARB_framebuffer_sRGB -#define WGL_ARB_framebuffer_sRGB 1 -#endif - -#ifndef WGL_ARB_create_context -#define WGL_ARB_create_context 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern HGLRC WINAPI wglCreateContextAttribsARB (HDC hDC, HGLRC hShareContext, const int *attribList); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList); -#endif - -#ifndef WGL_ARB_create_context_profile -#define WGL_ARB_create_context_profile 1 -#endif - -#ifndef WGL_ARB_create_context_robustness -#define WGL_ARB_create_context_robustness 1 -#endif - -#ifndef WGL_EXT_display_color_table -#define WGL_EXT_display_color_table 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern GLboolean WINAPI wglCreateDisplayColorTableEXT (GLushort id); -extern GLboolean WINAPI wglLoadDisplayColorTableEXT (const GLushort *table, GLuint length); -extern GLboolean WINAPI wglBindDisplayColorTableEXT (GLushort id); -extern VOID WINAPI wglDestroyDisplayColorTableEXT (GLushort id); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef GLboolean (WINAPI * PFNWGLCREATEDISPLAYCOLORTABLEEXTPROC) (GLushort id); -typedef GLboolean (WINAPI * PFNWGLLOADDISPLAYCOLORTABLEEXTPROC) (const GLushort *table, GLuint length); -typedef GLboolean (WINAPI * PFNWGLBINDDISPLAYCOLORTABLEEXTPROC) (GLushort id); -typedef VOID (WINAPI * PFNWGLDESTROYDISPLAYCOLORTABLEEXTPROC) (GLushort id); -#endif - -#ifndef WGL_EXT_extensions_string -#define WGL_EXT_extensions_string 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern const char * WINAPI wglGetExtensionsStringEXT (void); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC) (void); -#endif - -#ifndef WGL_EXT_make_current_read -#define WGL_EXT_make_current_read 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglMakeContextCurrentEXT (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); -extern HDC WINAPI wglGetCurrentReadDCEXT (void); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTEXTPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); -typedef HDC (WINAPI * PFNWGLGETCURRENTREADDCEXTPROC) (void); -#endif - -#ifndef WGL_EXT_pbuffer -#define WGL_EXT_pbuffer 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern HPBUFFEREXT WINAPI wglCreatePbufferEXT (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); -extern HDC WINAPI wglGetPbufferDCEXT (HPBUFFEREXT hPbuffer); -extern int WINAPI wglReleasePbufferDCEXT (HPBUFFEREXT hPbuffer, HDC hDC); -extern BOOL WINAPI wglDestroyPbufferEXT (HPBUFFEREXT hPbuffer); -extern BOOL WINAPI wglQueryPbufferEXT (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef HPBUFFEREXT (WINAPI * PFNWGLCREATEPBUFFEREXTPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); -typedef HDC (WINAPI * PFNWGLGETPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer); -typedef int (WINAPI * PFNWGLRELEASEPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer, HDC hDC); -typedef BOOL (WINAPI * PFNWGLDESTROYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer); -typedef BOOL (WINAPI * PFNWGLQUERYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue); -#endif - -#ifndef WGL_EXT_pixel_format -#define WGL_EXT_pixel_format 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglGetPixelFormatAttribivEXT (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues); -extern BOOL WINAPI wglGetPixelFormatAttribfvEXT (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues); -extern BOOL WINAPI wglChoosePixelFormatEXT (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues); -typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues); -typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATEXTPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); -#endif - -#ifndef WGL_EXT_swap_control -#define WGL_EXT_swap_control 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglSwapIntervalEXT (int interval); -extern int WINAPI wglGetSwapIntervalEXT (void); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval); -typedef int (WINAPI * PFNWGLGETSWAPINTERVALEXTPROC) (void); -#endif - -#ifndef WGL_EXT_depth_float -#define WGL_EXT_depth_float 1 -#endif - -#ifndef WGL_NV_vertex_array_range -#define WGL_NV_vertex_array_range 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern void* WINAPI wglAllocateMemoryNV (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority); -extern void WINAPI wglFreeMemoryNV (void *pointer); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef void* (WINAPI * PFNWGLALLOCATEMEMORYNVPROC) (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority); -typedef void (WINAPI * PFNWGLFREEMEMORYNVPROC) (void *pointer); -#endif - -#ifndef WGL_3DFX_multisample -#define WGL_3DFX_multisample 1 -#endif - -#ifndef WGL_EXT_multisample -#define WGL_EXT_multisample 1 -#endif - -#ifndef WGL_OML_sync_control -#define WGL_OML_sync_control 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglGetSyncValuesOML (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc); -extern BOOL WINAPI wglGetMscRateOML (HDC hdc, INT32 *numerator, INT32 *denominator); -extern INT64 WINAPI wglSwapBuffersMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder); -extern INT64 WINAPI wglSwapLayerBuffersMscOML (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder); -extern BOOL WINAPI wglWaitForMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc); -extern BOOL WINAPI wglWaitForSbcOML (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLGETSYNCVALUESOMLPROC) (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc); -typedef BOOL (WINAPI * PFNWGLGETMSCRATEOMLPROC) (HDC hdc, INT32 *numerator, INT32 *denominator); -typedef INT64 (WINAPI * PFNWGLSWAPBUFFERSMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder); -typedef INT64 (WINAPI * PFNWGLSWAPLAYERBUFFERSMSCOMLPROC) (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder); -typedef BOOL (WINAPI * PFNWGLWAITFORMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc); -typedef BOOL (WINAPI * PFNWGLWAITFORSBCOMLPROC) (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc); -#endif - -#ifndef WGL_I3D_digital_video_control -#define WGL_I3D_digital_video_control 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglGetDigitalVideoParametersI3D (HDC hDC, int iAttribute, int *piValue); -extern BOOL WINAPI wglSetDigitalVideoParametersI3D (HDC hDC, int iAttribute, const int *piValue); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLGETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue); -typedef BOOL (WINAPI * PFNWGLSETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue); -#endif - -#ifndef WGL_I3D_gamma -#define WGL_I3D_gamma 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglGetGammaTableParametersI3D (HDC hDC, int iAttribute, int *piValue); -extern BOOL WINAPI wglSetGammaTableParametersI3D (HDC hDC, int iAttribute, const int *piValue); -extern BOOL WINAPI wglGetGammaTableI3D (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue); -extern BOOL WINAPI wglSetGammaTableI3D (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLGETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue); -typedef BOOL (WINAPI * PFNWGLSETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue); -typedef BOOL (WINAPI * PFNWGLGETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue); -typedef BOOL (WINAPI * PFNWGLSETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue); -#endif - -#ifndef WGL_I3D_genlock -#define WGL_I3D_genlock 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglEnableGenlockI3D (HDC hDC); -extern BOOL WINAPI wglDisableGenlockI3D (HDC hDC); -extern BOOL WINAPI wglIsEnabledGenlockI3D (HDC hDC, BOOL *pFlag); -extern BOOL WINAPI wglGenlockSourceI3D (HDC hDC, UINT uSource); -extern BOOL WINAPI wglGetGenlockSourceI3D (HDC hDC, UINT *uSource); -extern BOOL WINAPI wglGenlockSourceEdgeI3D (HDC hDC, UINT uEdge); -extern BOOL WINAPI wglGetGenlockSourceEdgeI3D (HDC hDC, UINT *uEdge); -extern BOOL WINAPI wglGenlockSampleRateI3D (HDC hDC, UINT uRate); -extern BOOL WINAPI wglGetGenlockSampleRateI3D (HDC hDC, UINT *uRate); -extern BOOL WINAPI wglGenlockSourceDelayI3D (HDC hDC, UINT uDelay); -extern BOOL WINAPI wglGetGenlockSourceDelayI3D (HDC hDC, UINT *uDelay); -extern BOOL WINAPI wglQueryGenlockMaxSourceDelayI3D (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLENABLEGENLOCKI3DPROC) (HDC hDC); -typedef BOOL (WINAPI * PFNWGLDISABLEGENLOCKI3DPROC) (HDC hDC); -typedef BOOL (WINAPI * PFNWGLISENABLEDGENLOCKI3DPROC) (HDC hDC, BOOL *pFlag); -typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEI3DPROC) (HDC hDC, UINT uSource); -typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEI3DPROC) (HDC hDC, UINT *uSource); -typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT uEdge); -typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT *uEdge); -typedef BOOL (WINAPI * PFNWGLGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT uRate); -typedef BOOL (WINAPI * PFNWGLGETGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT *uRate); -typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT uDelay); -typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT *uDelay); -typedef BOOL (WINAPI * PFNWGLQUERYGENLOCKMAXSOURCEDELAYI3DPROC) (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay); -#endif - -#ifndef WGL_I3D_image_buffer -#define WGL_I3D_image_buffer 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern LPVOID WINAPI wglCreateImageBufferI3D (HDC hDC, DWORD dwSize, UINT uFlags); -extern BOOL WINAPI wglDestroyImageBufferI3D (HDC hDC, LPVOID pAddress); -extern BOOL WINAPI wglAssociateImageBufferEventsI3D (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count); -extern BOOL WINAPI wglReleaseImageBufferEventsI3D (HDC hDC, const LPVOID *pAddress, UINT count); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef LPVOID (WINAPI * PFNWGLCREATEIMAGEBUFFERI3DPROC) (HDC hDC, DWORD dwSize, UINT uFlags); -typedef BOOL (WINAPI * PFNWGLDESTROYIMAGEBUFFERI3DPROC) (HDC hDC, LPVOID pAddress); -typedef BOOL (WINAPI * PFNWGLASSOCIATEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count); -typedef BOOL (WINAPI * PFNWGLRELEASEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const LPVOID *pAddress, UINT count); -#endif - -#ifndef WGL_I3D_swap_frame_lock -#define WGL_I3D_swap_frame_lock 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglEnableFrameLockI3D (void); -extern BOOL WINAPI wglDisableFrameLockI3D (void); -extern BOOL WINAPI wglIsEnabledFrameLockI3D (BOOL *pFlag); -extern BOOL WINAPI wglQueryFrameLockMasterI3D (BOOL *pFlag); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLENABLEFRAMELOCKI3DPROC) (void); -typedef BOOL (WINAPI * PFNWGLDISABLEFRAMELOCKI3DPROC) (void); -typedef BOOL (WINAPI * PFNWGLISENABLEDFRAMELOCKI3DPROC) (BOOL *pFlag); -typedef BOOL (WINAPI * PFNWGLQUERYFRAMELOCKMASTERI3DPROC) (BOOL *pFlag); -#endif - -#ifndef WGL_I3D_swap_frame_usage -#define WGL_I3D_swap_frame_usage 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglGetFrameUsageI3D (float *pUsage); -extern BOOL WINAPI wglBeginFrameTrackingI3D (void); -extern BOOL WINAPI wglEndFrameTrackingI3D (void); -extern BOOL WINAPI wglQueryFrameTrackingI3D (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLGETFRAMEUSAGEI3DPROC) (float *pUsage); -typedef BOOL (WINAPI * PFNWGLBEGINFRAMETRACKINGI3DPROC) (void); -typedef BOOL (WINAPI * PFNWGLENDFRAMETRACKINGI3DPROC) (void); -typedef BOOL (WINAPI * PFNWGLQUERYFRAMETRACKINGI3DPROC) (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage); -#endif - -#ifndef WGL_ATI_pixel_format_float -#define WGL_ATI_pixel_format_float 1 -#endif - -#ifndef WGL_NV_float_buffer -#define WGL_NV_float_buffer 1 -#endif - -#ifndef WGL_3DL_stereo_control -#define WGL_3DL_stereo_control 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglSetStereoEmitterState3DL (HDC hDC, UINT uState); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLSETSTEREOEMITTERSTATE3DLPROC) (HDC hDC, UINT uState); -#endif - -#ifndef WGL_EXT_pixel_format_packed_float -#define WGL_EXT_pixel_format_packed_float 1 -#endif - -#ifndef WGL_EXT_framebuffer_sRGB -#define WGL_EXT_framebuffer_sRGB 1 -#endif - -#ifndef WGL_NV_present_video -#define WGL_NV_present_video 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern int WINAPI wglEnumerateVideoDevicesNV (HDC hDC, HVIDEOOUTPUTDEVICENV *phDeviceList); -extern BOOL WINAPI wglBindVideoDeviceNV (HDC hDC, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList); -extern BOOL WINAPI wglQueryCurrentContextNV (int iAttribute, int *piValue); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef int (WINAPI * PFNWGLENUMERATEVIDEODEVICESNVPROC) (HDC hDC, HVIDEOOUTPUTDEVICENV *phDeviceList); -typedef BOOL (WINAPI * PFNWGLBINDVIDEODEVICENVPROC) (HDC hDC, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList); -typedef BOOL (WINAPI * PFNWGLQUERYCURRENTCONTEXTNVPROC) (int iAttribute, int *piValue); -#endif - -#ifndef WGL_NV_video_output -#define WGL_NV_video_output 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglGetVideoDeviceNV (HDC hDC, int numDevices, HPVIDEODEV *hVideoDevice); -extern BOOL WINAPI wglReleaseVideoDeviceNV (HPVIDEODEV hVideoDevice); -extern BOOL WINAPI wglBindVideoImageNV (HPVIDEODEV hVideoDevice, HPBUFFERARB hPbuffer, int iVideoBuffer); -extern BOOL WINAPI wglReleaseVideoImageNV (HPBUFFERARB hPbuffer, int iVideoBuffer); -extern BOOL WINAPI wglSendPbufferToVideoNV (HPBUFFERARB hPbuffer, int iBufferType, unsigned long *pulCounterPbuffer, BOOL bBlock); -extern BOOL WINAPI wglGetVideoInfoNV (HPVIDEODEV hpVideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLGETVIDEODEVICENVPROC) (HDC hDC, int numDevices, HPVIDEODEV *hVideoDevice); -typedef BOOL (WINAPI * PFNWGLRELEASEVIDEODEVICENVPROC) (HPVIDEODEV hVideoDevice); -typedef BOOL (WINAPI * PFNWGLBINDVIDEOIMAGENVPROC) (HPVIDEODEV hVideoDevice, HPBUFFERARB hPbuffer, int iVideoBuffer); -typedef BOOL (WINAPI * PFNWGLRELEASEVIDEOIMAGENVPROC) (HPBUFFERARB hPbuffer, int iVideoBuffer); -typedef BOOL (WINAPI * PFNWGLSENDPBUFFERTOVIDEONVPROC) (HPBUFFERARB hPbuffer, int iBufferType, unsigned long *pulCounterPbuffer, BOOL bBlock); -typedef BOOL (WINAPI * PFNWGLGETVIDEOINFONVPROC) (HPVIDEODEV hpVideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo); -#endif - -#ifndef WGL_NV_swap_group -#define WGL_NV_swap_group 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglJoinSwapGroupNV (HDC hDC, GLuint group); -extern BOOL WINAPI wglBindSwapBarrierNV (GLuint group, GLuint barrier); -extern BOOL WINAPI wglQuerySwapGroupNV (HDC hDC, GLuint *group, GLuint *barrier); -extern BOOL WINAPI wglQueryMaxSwapGroupsNV (HDC hDC, GLuint *maxGroups, GLuint *maxBarriers); -extern BOOL WINAPI wglQueryFrameCountNV (HDC hDC, GLuint *count); -extern BOOL WINAPI wglResetFrameCountNV (HDC hDC); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLJOINSWAPGROUPNVPROC) (HDC hDC, GLuint group); -typedef BOOL (WINAPI * PFNWGLBINDSWAPBARRIERNVPROC) (GLuint group, GLuint barrier); -typedef BOOL (WINAPI * PFNWGLQUERYSWAPGROUPNVPROC) (HDC hDC, GLuint *group, GLuint *barrier); -typedef BOOL (WINAPI * PFNWGLQUERYMAXSWAPGROUPSNVPROC) (HDC hDC, GLuint *maxGroups, GLuint *maxBarriers); -typedef BOOL (WINAPI * PFNWGLQUERYFRAMECOUNTNVPROC) (HDC hDC, GLuint *count); -typedef BOOL (WINAPI * PFNWGLRESETFRAMECOUNTNVPROC) (HDC hDC); -#endif - -#ifndef WGL_NV_gpu_affinity -#define WGL_NV_gpu_affinity 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglEnumGpusNV (UINT iGpuIndex, HGPUNV *phGpu); -extern BOOL WINAPI wglEnumGpuDevicesNV (HGPUNV hGpu, UINT iDeviceIndex, PGPU_DEVICE lpGpuDevice); -extern HDC WINAPI wglCreateAffinityDCNV (const HGPUNV *phGpuList); -extern BOOL WINAPI wglEnumGpusFromAffinityDCNV (HDC hAffinityDC, UINT iGpuIndex, HGPUNV *hGpu); -extern BOOL WINAPI wglDeleteDCNV (HDC hdc); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLENUMGPUSNVPROC) (UINT iGpuIndex, HGPUNV *phGpu); -typedef BOOL (WINAPI * PFNWGLENUMGPUDEVICESNVPROC) (HGPUNV hGpu, UINT iDeviceIndex, PGPU_DEVICE lpGpuDevice); -typedef HDC (WINAPI * PFNWGLCREATEAFFINITYDCNVPROC) (const HGPUNV *phGpuList); -typedef BOOL (WINAPI * PFNWGLENUMGPUSFROMAFFINITYDCNVPROC) (HDC hAffinityDC, UINT iGpuIndex, HGPUNV *hGpu); -typedef BOOL (WINAPI * PFNWGLDELETEDCNVPROC) (HDC hdc); -#endif - -#ifndef WGL_AMD_gpu_association -#define WGL_AMD_gpu_association 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern UINT WINAPI wglGetGPUIDsAMD (UINT maxCount, UINT *ids); -extern INT WINAPI wglGetGPUInfoAMD (UINT id, int property, GLenum dataType, UINT size, void *data); -extern UINT WINAPI wglGetContextGPUIDAMD (HGLRC hglrc); -extern HGLRC WINAPI wglCreateAssociatedContextAMD (UINT id); -extern HGLRC WINAPI wglCreateAssociatedContextAttribsAMD (UINT id, HGLRC hShareContext, const int *attribList); -extern BOOL WINAPI wglDeleteAssociatedContextAMD (HGLRC hglrc); -extern BOOL WINAPI wglMakeAssociatedContextCurrentAMD (HGLRC hglrc); -extern HGLRC WINAPI wglGetCurrentAssociatedContextAMD (void); -extern VOID WINAPI wglBlitContextFramebufferAMD (HGLRC dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef UINT (WINAPI * PFNWGLGETGPUIDSAMDPROC) (UINT maxCount, UINT *ids); -typedef INT (WINAPI * PFNWGLGETGPUINFOAMDPROC) (UINT id, int property, GLenum dataType, UINT size, void *data); -typedef UINT (WINAPI * PFNWGLGETCONTEXTGPUIDAMDPROC) (HGLRC hglrc); -typedef HGLRC (WINAPI * PFNWGLCREATEASSOCIATEDCONTEXTAMDPROC) (UINT id); -typedef HGLRC (WINAPI * PFNWGLCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC) (UINT id, HGLRC hShareContext, const int *attribList); -typedef BOOL (WINAPI * PFNWGLDELETEASSOCIATEDCONTEXTAMDPROC) (HGLRC hglrc); -typedef BOOL (WINAPI * PFNWGLMAKEASSOCIATEDCONTEXTCURRENTAMDPROC) (HGLRC hglrc); -typedef HGLRC (WINAPI * PFNWGLGETCURRENTASSOCIATEDCONTEXTAMDPROC) (void); -typedef VOID (WINAPI * PFNWGLBLITCONTEXTFRAMEBUFFERAMDPROC) (HGLRC dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -#endif - -#ifndef WGL_NV_video_capture -#define WGL_NV_video_capture 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglBindVideoCaptureDeviceNV (UINT uVideoSlot, HVIDEOINPUTDEVICENV hDevice); -extern UINT WINAPI wglEnumerateVideoCaptureDevicesNV (HDC hDc, HVIDEOINPUTDEVICENV *phDeviceList); -extern BOOL WINAPI wglLockVideoCaptureDeviceNV (HDC hDc, HVIDEOINPUTDEVICENV hDevice); -extern BOOL WINAPI wglQueryVideoCaptureDeviceNV (HDC hDc, HVIDEOINPUTDEVICENV hDevice, int iAttribute, int *piValue); -extern BOOL WINAPI wglReleaseVideoCaptureDeviceNV (HDC hDc, HVIDEOINPUTDEVICENV hDevice); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLBINDVIDEOCAPTUREDEVICENVPROC) (UINT uVideoSlot, HVIDEOINPUTDEVICENV hDevice); -typedef UINT (WINAPI * PFNWGLENUMERATEVIDEOCAPTUREDEVICESNVPROC) (HDC hDc, HVIDEOINPUTDEVICENV *phDeviceList); -typedef BOOL (WINAPI * PFNWGLLOCKVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice); -typedef BOOL (WINAPI * PFNWGLQUERYVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice, int iAttribute, int *piValue); -typedef BOOL (WINAPI * PFNWGLRELEASEVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice); -#endif - -#ifndef WGL_NV_copy_image -#define WGL_NV_copy_image 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglCopyImageSubDataNV (HGLRC hSrcRC, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, HGLRC hDstRC, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLCOPYIMAGESUBDATANVPROC) (HGLRC hSrcRC, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, HGLRC hDstRC, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); -#endif - -#ifndef WGL_NV_multisample_coverage -#define WGL_NV_multisample_coverage 1 -#endif - -#ifndef WGL_NV_DX_interop -#define WGL_NV_DX_interop 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglDXSetResourceShareHandleNV (void *dxObject, HANDLE shareHandle); -extern HANDLE WINAPI wglDXOpenDeviceNV (void *dxDevice); -extern BOOL WINAPI wglDXCloseDeviceNV (HANDLE hDevice); -extern HANDLE WINAPI wglDXRegisterObjectNV (HANDLE hDevice, void *dxObject, GLuint name, GLenum type, GLenum access); -extern BOOL WINAPI wglDXUnregisterObjectNV (HANDLE hDevice, HANDLE hObject); -extern BOOL WINAPI wglDXObjectAccessNV (HANDLE hObject, GLenum access); -extern BOOL WINAPI wglDXLockObjectsNV (HANDLE hDevice, GLint count, HANDLE *hObjects); -extern BOOL WINAPI wglDXUnlockObjectsNV (HANDLE hDevice, GLint count, HANDLE *hObjects); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLDXSETRESOURCESHAREHANDLENVPROC) (void *dxObject, HANDLE shareHandle); -typedef HANDLE (WINAPI * PFNWGLDXOPENDEVICENVPROC) (void *dxDevice); -typedef BOOL (WINAPI * PFNWGLDXCLOSEDEVICENVPROC) (HANDLE hDevice); -typedef HANDLE (WINAPI * PFNWGLDXREGISTEROBJECTNVPROC) (HANDLE hDevice, void *dxObject, GLuint name, GLenum type, GLenum access); -typedef BOOL (WINAPI * PFNWGLDXUNREGISTEROBJECTNVPROC) (HANDLE hDevice, HANDLE hObject); -typedef BOOL (WINAPI * PFNWGLDXOBJECTACCESSNVPROC) (HANDLE hObject, GLenum access); -typedef BOOL (WINAPI * PFNWGLDXLOCKOBJECTSNVPROC) (HANDLE hDevice, GLint count, HANDLE *hObjects); -typedef BOOL (WINAPI * PFNWGLDXUNLOCKOBJECTSNVPROC) (HANDLE hDevice, GLint count, HANDLE *hObjects); -#endif - -#ifndef WGL_NV_DX_interop2 -#define WGL_NV_DX_interop2 1 -#endif - -#ifndef WGL_EXT_swap_control_tear -#define WGL_EXT_swap_control_tear 1 -#endif - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/CMakeLists.txt deleted file mode 100644 index f3b8e0ead524..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/CMakeLists.txt +++ /dev/null @@ -1,64 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2017 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -SET(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_MODULE_PATH}) -INCLUDE(CMakeDependentOption) - -SET(ADDITIONAL_SOURCES) - -FIND_PACKAGE(ImageMagick COMPONENTS Magick++) -MARK_AS_ADVANCED( - ImageMagick_EXECUTABLE_DIR - ImageMagick_Magick++_INCLUDE_DIR - ImageMagick_Magick++_ARCH_INCLUDE_DIR - ImageMagick_Magick++_LIBRARY -) -CMAKE_DEPENDENT_OPTION(EMBREE_TUTORIALS_IMAGE_MAGICK "Enables BMP, GIF, PNG, TGA, TIFF image codecs." OFF "IMAGEMAGICK_FOUND" OFF) -IF (EMBREE_TUTORIALS_IMAGE_MAGICK) - ADD_DEFINITIONS(-DUSE_IMAGEMAGICK) - INCLUDE_DIRECTORIES(${ImageMagick_Magick++_INCLUDE_DIR}) - SET(ADDITIONAL_LIBRARIES ${ADDITIONAL_LIBRARIES} ${ImageMagick_Magick++_LIBRARY}) - SET(ADDITIONAL_SOURCES ${ADDITIONAL_SOURCES} magick.cpp) -ENDIF (EMBREE_TUTORIALS_IMAGE_MAGICK) - -FIND_PACKAGE(JPEG) -CMAKE_DEPENDENT_OPTION(EMBREE_TUTORIALS_LIBJPEG "Enables JPEG image codec." ON "JPEG_FOUND" OFF) -IF (EMBREE_TUTORIALS_LIBJPEG) - ADD_DEFINITIONS(-DEMBREE_TUTORIALS_LIBJPEG) - INCLUDE_DIRECTORIES(${JPEG_INCLUDE_DIR}) - SET(ADDITIONAL_LIBRARIES ${ADDITIONAL_LIBRARIES} ${JPEG_LIBRARIES}) - SET(ADDITIONAL_SOURCES ${ADDITIONAL_SOURCES} jpeg.cpp) -ENDIF (EMBREE_TUTORIALS_LIBJPEG) - -FIND_PACKAGE(PNG) -CMAKE_DEPENDENT_OPTION(EMBREE_TUTORIALS_LIBPNG "Enables PNG image codecs." ON "PNG_FOUND" OFF) -IF (EMBREE_TUTORIALS_LIBPNG) - ADD_DEFINITIONS(-DEMBREE_TUTORIALS_LIBPNG) - INCLUDE_DIRECTORIES(${PNG_INCLUDE_DIR}) - SET(ADDITIONAL_LIBRARIES ${ADDITIONAL_LIBRARIES} ${PNG_LIBRARIES}) -ENDIF (EMBREE_TUTORIALS_LIBPNG) - -ADD_LIBRARY(image STATIC - image.cpp - pfm.cpp - ppm.cpp - tga.cpp - png.cpp - ${ADDITIONAL_SOURCES} - ) - -TARGET_LINK_LIBRARIES(image sys ${ADDITIONAL_LIBRARIES}) -SET_PROPERTY(TARGET image PROPERTY FOLDER tutorials/common) diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/LICENSE-ImageMagick.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/LICENSE-ImageMagick.txt deleted file mode 100644 index c7a343c08b99..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/LICENSE-ImageMagick.txt +++ /dev/null @@ -1,103 +0,0 @@ -Before we get to the text of the license, lets just review what the license says in simple terms: - -It allows you to: - - * freely download and use ImageMagick software, in whole or in part, for personal, company internal, or commercial purposes; - * use ImageMagick software in packages or distributions that you create; - * link against a library under a different license; - * link code under a different license against a library under this license; - * merge code into a work under a different license; - * extend patent grants to any code using code under this license; - * and extend patent protection. - -It forbids you to: - - * redistribute any piece of ImageMagick-originated software without proper attribution; - * use any marks owned by ImageMagick Studio LLC in any way that might state or imply that ImageMagick Studio LLC endorses your distribution; - * use any marks owned by ImageMagick Studio LLC in any way that might state or imply that you created the ImageMagick software in question. - -It requires you to: - - * include a copy of the license in any redistribution you may make that includes ImageMagick software; - * provide clear attribution to ImageMagick Studio LLC for any distributions that include ImageMagick software. - -It does not require you to: - - * include the source of the ImageMagick software itself, or of any modifications you may have made to it, in any redistribution you may assemble that includes it; - * submit changes that you make to the software back to the ImageMagick Studio LLC (though such feedback is encouraged). - -A few other clarifications include: - - * ImageMagick is freely available without charge; - * you may include ImageMagick on a DVD as long as you comply with the terms of the license; - * you can give modified code away for free or sell it under the terms of the ImageMagick license or distribute the result under a different license, but you need to acknowledge the use of the ImageMagick software; - * the license is compatible with the GPL V3. - * when exporting the ImageMagick software, review its export classification. - -Terms and Conditions for Use, Reproduction, and Distribution - -The legally binding and authoritative terms and conditions for use, reproduction, and distribution of ImageMagick follow: - -Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization dedicated to making software imaging solutions freely available. - -1. Definitions. - -License shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. - -Licensor shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. - -Legal Entity shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, control means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - -You (or Your) shall mean an individual or Legal Entity exercising permissions granted by this License. - -Source form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. - -Object form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. - -Work shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). - -Derivative Works shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. - -Contribution shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as Not a Contribution. - -Contributor shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - - * You must give any other recipients of the Work or Derivative Works a copy of this License; and - * You must cause any modified files to carry prominent notices stating that You changed the files; and - * You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and - * If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. -You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an AS IS BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. - -How to Apply the License to your Work - -To apply the ImageMagick License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information (don't include the brackets). The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the ImageMagick License (the "License"); you may not use - this file except in compliance with the License. You may obtain a copy - of the License at - - https://www.imagemagick.org/script/license.php - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - License for the specific language governing permissions and limitations - under the License. diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/LICENSE-libjpeg.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/LICENSE-libjpeg.txt deleted file mode 100644 index 86cc20669d61..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/LICENSE-libjpeg.txt +++ /dev/null @@ -1,385 +0,0 @@ -The Independent JPEG Group's JPEG software -========================================== - -README for release 6b of 27-Mar-1998 -==================================== - -This distribution contains the sixth public release of the Independent JPEG -Group's free JPEG software. You are welcome to redistribute this software and -to use it for any purpose, subject to the conditions under LEGAL ISSUES, below. - -Serious users of this software (particularly those incorporating it into -larger programs) should contact IJG at jpeg-info@uunet.uu.net to be added to -our electronic mailing list. Mailing list members are notified of updates -and have a chance to participate in technical discussions, etc. - -This software is the work of Tom Lane, Philip Gladstone, Jim Boucher, -Lee Crocker, Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi, -Guido Vollbeding, Ge' Weijers, and other members of the Independent JPEG -Group. - -IJG is not affiliated with the official ISO JPEG standards committee. - - -DOCUMENTATION ROADMAP -===================== - -This file contains the following sections: - -OVERVIEW General description of JPEG and the IJG software. -LEGAL ISSUES Copyright, lack of warranty, terms of distribution. -REFERENCES Where to learn more about JPEG. -ARCHIVE LOCATIONS Where to find newer versions of this software. -RELATED SOFTWARE Other stuff you should get. -FILE FORMAT WARS Software *not* to get. -TO DO Plans for future IJG releases. - -Other documentation files in the distribution are: - -User documentation: - install.doc How to configure and install the IJG software. - usage.doc Usage instructions for cjpeg, djpeg, jpegtran, - rdjpgcom, and wrjpgcom. - *.1 Unix-style man pages for programs (same info as usage.doc). - wizard.doc Advanced usage instructions for JPEG wizards only. - change.log Version-to-version change highlights. -Programmer and internal documentation: - libjpeg.doc How to use the JPEG library in your own programs. - example.c Sample code for calling the JPEG library. - structure.doc Overview of the JPEG library's internal structure. - filelist.doc Road map of IJG files. - coderules.doc Coding style rules --- please read if you contribute code. - -Please read at least the files install.doc and usage.doc. Useful information -can also be found in the JPEG FAQ (Frequently Asked Questions) article. See -ARCHIVE LOCATIONS below to find out where to obtain the FAQ article. - -If you want to understand how the JPEG code works, we suggest reading one or -more of the REFERENCES, then looking at the documentation files (in roughly -the order listed) before diving into the code. - - -OVERVIEW -======== - -This package contains C software to implement JPEG image compression and -decompression. JPEG (pronounced "jay-peg") is a standardized compression -method for full-color and gray-scale images. JPEG is intended for compressing -"real-world" scenes; line drawings, cartoons and other non-realistic images -are not its strong suit. JPEG is lossy, meaning that the output image is not -exactly identical to the input image. Hence you must not use JPEG if you -have to have identical output bits. However, on typical photographic images, -very good compression levels can be obtained with no visible change, and -remarkably high compression levels are possible if you can tolerate a -low-quality image. For more details, see the references, or just experiment -with various compression settings. - -This software implements JPEG baseline, extended-sequential, and progressive -compression processes. Provision is made for supporting all variants of these -processes, although some uncommon parameter settings aren't implemented yet. -For legal reasons, we are not distributing code for the arithmetic-coding -variants of JPEG; see LEGAL ISSUES. We have made no provision for supporting -the hierarchical or lossless processes defined in the standard. - -We provide a set of library routines for reading and writing JPEG image files, -plus two sample applications "cjpeg" and "djpeg", which use the library to -perform conversion between JPEG and some other popular image file formats. -The library is intended to be reused in other applications. - -In order to support file conversion and viewing software, we have included -considerable functionality beyond the bare JPEG coding/decoding capability; -for example, the color quantization modules are not strictly part of JPEG -decoding, but they are essential for output to colormapped file formats or -colormapped displays. These extra functions can be compiled out of the -library if not required for a particular application. We have also included -"jpegtran", a utility for lossless transcoding between different JPEG -processes, and "rdjpgcom" and "wrjpgcom", two simple applications for -inserting and extracting textual comments in JFIF files. - -The emphasis in designing this software has been on achieving portability and -flexibility, while also making it fast enough to be useful. In particular, -the software is not intended to be read as a tutorial on JPEG. (See the -REFERENCES section for introductory material.) Rather, it is intended to -be reliable, portable, industrial-strength code. We do not claim to have -achieved that goal in every aspect of the software, but we strive for it. - -We welcome the use of this software as a component of commercial products. -No royalty is required, but we do ask for an acknowledgement in product -documentation, as described under LEGAL ISSUES. - - -LEGAL ISSUES -============ - -In plain English: - -1. We don't promise that this software works. (But if you find any bugs, - please let us know!) -2. You can use this software for whatever you want. You don't have to pay us. -3. You may not pretend that you wrote this software. If you use it in a - program, you must acknowledge somewhere in your documentation that - you've used the IJG code. - -In legalese: - -The authors make NO WARRANTY or representation, either express or implied, -with respect to this software, its quality, accuracy, merchantability, or -fitness for a particular purpose. This software is provided "AS IS", and you, -its user, assume the entire risk as to its quality and accuracy. - -This software is copyright (C) 1991-1998, Thomas G. Lane. -All Rights Reserved except as specified below. - -Permission is hereby granted to use, copy, modify, and distribute this -software (or portions thereof) for any purpose, without fee, subject to these -conditions: -(1) If any part of the source code for this software is distributed, then this -README file must be included, with this copyright and no-warranty notice -unaltered; and any additions, deletions, or changes to the original files -must be clearly indicated in accompanying documentation. -(2) If only executable code is distributed, then the accompanying -documentation must state that "this software is based in part on the work of -the Independent JPEG Group". -(3) Permission for use of this software is granted only if the user accepts -full responsibility for any undesirable consequences; the authors accept -NO LIABILITY for damages of any kind. - -These conditions apply to any software derived from or based on the IJG code, -not just to the unmodified library. If you use our work, you ought to -acknowledge us. - -Permission is NOT granted for the use of any IJG author's name or company name -in advertising or publicity relating to this software or products derived from -it. This software may be referred to only as "the Independent JPEG Group's -software". - -We specifically permit and encourage the use of this software as the basis of -commercial products, provided that all warranty or liability claims are -assumed by the product vendor. - - -ansi2knr.c is included in this distribution by permission of L. Peter Deutsch, -sole proprietor of its copyright holder, Aladdin Enterprises of Menlo Park, CA. -ansi2knr.c is NOT covered by the above copyright and conditions, but instead -by the usual distribution terms of the Free Software Foundation; principally, -that you must include source code if you redistribute it. (See the file -ansi2knr.c for full details.) However, since ansi2knr.c is not needed as part -of any program generated from the IJG code, this does not limit you more than -the foregoing paragraphs do. - -The Unix configuration script "configure" was produced with GNU Autoconf. -It is copyright by the Free Software Foundation but is freely distributable. -The same holds for its supporting scripts (config.guess, config.sub, -ltconfig, ltmain.sh). Another support script, install-sh, is copyright -by M.I.T. but is also freely distributable. - -It appears that the arithmetic coding option of the JPEG spec is covered by -patents owned by IBM, AT&T, and Mitsubishi. Hence arithmetic coding cannot -legally be used without obtaining one or more licenses. For this reason, -support for arithmetic coding has been removed from the free JPEG software. -(Since arithmetic coding provides only a marginal gain over the unpatented -Huffman mode, it is unlikely that very many implementations will support it.) -So far as we are aware, there are no patent restrictions on the remaining -code. - -The IJG distribution formerly included code to read and write GIF files. -To avoid entanglement with the Unisys LZW patent, GIF reading support has -been removed altogether, and the GIF writer has been simplified to produce -"uncompressed GIFs". This technique does not use the LZW algorithm; the -resulting GIF files are larger than usual, but are readable by all standard -GIF decoders. - -We are required to state that - "The Graphics Interchange Format(c) is the Copyright property of - CompuServe Incorporated. GIF(sm) is a Service Mark property of - CompuServe Incorporated." - - -REFERENCES -========== - -We highly recommend reading one or more of these references before trying to -understand the innards of the JPEG software. - -The best short technical introduction to the JPEG compression algorithm is - Wallace, Gregory K. "The JPEG Still Picture Compression Standard", - Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44. -(Adjacent articles in that issue discuss MPEG motion picture compression, -applications of JPEG, and related topics.) If you don't have the CACM issue -handy, a PostScript file containing a revised version of Wallace's article is -available at ftp://ftp.uu.net/graphics/jpeg/wallace.ps.gz. The file (actually -a preprint for an article that appeared in IEEE Trans. Consumer Electronics) -omits the sample images that appeared in CACM, but it includes corrections -and some added material. Note: the Wallace article is copyright ACM and IEEE, -and it may not be used for commercial purposes. - -A somewhat less technical, more leisurely introduction to JPEG can be found in -"The Data Compression Book" by Mark Nelson and Jean-loup Gailly, published by -M&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1. This book provides -good explanations and example C code for a multitude of compression methods -including JPEG. It is an excellent source if you are comfortable reading C -code but don't know much about data compression in general. The book's JPEG -sample code is far from industrial-strength, but when you are ready to look -at a full implementation, you've got one here... - -The best full description of JPEG is the textbook "JPEG Still Image Data -Compression Standard" by William B. Pennebaker and Joan L. Mitchell, published -by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1. Price US$59.95, 638 pp. -The book includes the complete text of the ISO JPEG standards (DIS 10918-1 -and draft DIS 10918-2). This is by far the most complete exposition of JPEG -in existence, and we highly recommend it. - -The JPEG standard itself is not available electronically; you must order a -paper copy through ISO or ITU. (Unless you feel a need to own a certified -official copy, we recommend buying the Pennebaker and Mitchell book instead; -it's much cheaper and includes a great deal of useful explanatory material.) -In the USA, copies of the standard may be ordered from ANSI Sales at (212) -642-4900, or from Global Engineering Documents at (800) 854-7179. (ANSI -doesn't take credit card orders, but Global does.) It's not cheap: as of -1992, ANSI was charging $95 for Part 1 and $47 for Part 2, plus 7% -shipping/handling. The standard is divided into two parts, Part 1 being the -actual specification, while Part 2 covers compliance testing methods. Part 1 -is titled "Digital Compression and Coding of Continuous-tone Still Images, -Part 1: Requirements and guidelines" and has document numbers ISO/IEC IS -10918-1, ITU-T T.81. Part 2 is titled "Digital Compression and Coding of -Continuous-tone Still Images, Part 2: Compliance testing" and has document -numbers ISO/IEC IS 10918-2, ITU-T T.83. - -Some extensions to the original JPEG standard are defined in JPEG Part 3, -a newer ISO standard numbered ISO/IEC IS 10918-3 and ITU-T T.84. IJG -currently does not support any Part 3 extensions. - -The JPEG standard does not specify all details of an interchangeable file -format. For the omitted details we follow the "JFIF" conventions, revision -1.02. A copy of the JFIF spec is available from: - Literature Department - C-Cube Microsystems, Inc. - 1778 McCarthy Blvd. - Milpitas, CA 95035 - phone (408) 944-6300, fax (408) 944-6314 -A PostScript version of this document is available by FTP at -ftp://ftp.uu.net/graphics/jpeg/jfif.ps.gz. There is also a plain text -version at ftp://ftp.uu.net/graphics/jpeg/jfif.txt.gz, but it is missing -the figures. - -The TIFF 6.0 file format specification can be obtained by FTP from -ftp://ftp.sgi.com/graphics/tiff/TIFF6.ps.gz. The JPEG incorporation scheme -found in the TIFF 6.0 spec of 3-June-92 has a number of serious problems. -IJG does not recommend use of the TIFF 6.0 design (TIFF Compression tag 6). -Instead, we recommend the JPEG design proposed by TIFF Technical Note #2 -(Compression tag 7). Copies of this Note can be obtained from ftp.sgi.com or -from ftp://ftp.uu.net/graphics/jpeg/. It is expected that the next revision -of the TIFF spec will replace the 6.0 JPEG design with the Note's design. -Although IJG's own code does not support TIFF/JPEG, the free libtiff library -uses our library to implement TIFF/JPEG per the Note. libtiff is available -from ftp://ftp.sgi.com/graphics/tiff/. - - -ARCHIVE LOCATIONS -================= - -The "official" archive site for this software is ftp.uu.net (Internet -address 192.48.96.9). The most recent released version can always be found -there in directory graphics/jpeg. This particular version will be archived -as ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz. If you don't have -direct Internet access, UUNET's archives are also available via UUCP; contact -help@uunet.uu.net for information on retrieving files that way. - -Numerous Internet sites maintain copies of the UUNET files. However, only -ftp.uu.net is guaranteed to have the latest official version. - -You can also obtain this software in DOS-compatible "zip" archive format from -the SimTel archives (ftp://ftp.simtel.net/pub/simtelnet/msdos/graphics/), or -on CompuServe in the Graphics Support forum (GO CIS:GRAPHSUP), library 12 -"JPEG Tools". Again, these versions may sometimes lag behind the ftp.uu.net -release. - -The JPEG FAQ (Frequently Asked Questions) article is a useful source of -general information about JPEG. It is updated constantly and therefore is -not included in this distribution. The FAQ is posted every two weeks to -Usenet newsgroups comp.graphics.misc, news.answers, and other groups. -It is available on the World Wide Web at http://www.faqs.org/faqs/jpeg-faq/ -and other news.answers archive sites, including the official news.answers -archive at rtfm.mit.edu: ftp://rtfm.mit.edu/pub/usenet/news.answers/jpeg-faq/. -If you don't have Web or FTP access, send e-mail to mail-server@rtfm.mit.edu -with body - send usenet/news.answers/jpeg-faq/part1 - send usenet/news.answers/jpeg-faq/part2 - - -RELATED SOFTWARE -================ - -Numerous viewing and image manipulation programs now support JPEG. (Quite a -few of them use this library to do so.) The JPEG FAQ described above lists -some of the more popular free and shareware viewers, and tells where to -obtain them on Internet. - -If you are on a Unix machine, we highly recommend Jef Poskanzer's free -PBMPLUS software, which provides many useful operations on PPM-format image -files. In particular, it can convert PPM images to and from a wide range of -other formats, thus making cjpeg/djpeg considerably more useful. The latest -version is distributed by the NetPBM group, and is available from numerous -sites, notably ftp://wuarchive.wustl.edu/graphics/graphics/packages/NetPBM/. -Unfortunately PBMPLUS/NETPBM is not nearly as portable as the IJG software is; -you are likely to have difficulty making it work on any non-Unix machine. - -A different free JPEG implementation, written by the PVRG group at Stanford, -is available from ftp://havefun.stanford.edu/pub/jpeg/. This program -is designed for research and experimentation rather than production use; -it is slower, harder to use, and less portable than the IJG code, but it -is easier to read and modify. Also, the PVRG code supports lossless JPEG, -which we do not. (On the other hand, it doesn't do progressive JPEG.) - - -FILE FORMAT WARS -================ - -Some JPEG programs produce files that are not compatible with our library. -The root of the problem is that the ISO JPEG committee failed to specify a -concrete file format. Some vendors "filled in the blanks" on their own, -creating proprietary formats that no one else could read. (For example, none -of the early commercial JPEG implementations for the Macintosh were able to -exchange compressed files.) - -The file format we have adopted is called JFIF (see REFERENCES). This format -has been agreed to by a number of major commercial JPEG vendors, and it has -become the de facto standard. JFIF is a minimal or "low end" representation. -We recommend the use of TIFF/JPEG (TIFF revision 6.0 as modified by TIFF -Technical Note #2) for "high end" applications that need to record a lot of -additional data about an image. TIFF/JPEG is fairly new and not yet widely -supported, unfortunately. - -The upcoming JPEG Part 3 standard defines a file format called SPIFF. -SPIFF is interoperable with JFIF, in the sense that most JFIF decoders should -be able to read the most common variant of SPIFF. SPIFF has some technical -advantages over JFIF, but its major claim to fame is simply that it is an -official standard rather than an informal one. At this point it is unclear -whether SPIFF will supersede JFIF or whether JFIF will remain the de-facto -standard. IJG intends to support SPIFF once the standard is frozen, but we -have not decided whether it should become our default output format or not. -(In any case, our decoder will remain capable of reading JFIF indefinitely.) - -Various proprietary file formats incorporating JPEG compression also exist. -We have little or no sympathy for the existence of these formats. Indeed, -one of the original reasons for developing this free software was to help -force convergence on common, open format standards for JPEG files. Don't -use a proprietary file format! - - -TO DO -===== - -The major thrust for v7 will probably be improvement of visual quality. -The current method for scaling the quantization tables is known not to be -very good at low Q values. We also intend to investigate block boundary -smoothing, "poor man's variable quantization", and other means of improving -quality-vs-file-size performance without sacrificing compatibility. - -In future versions, we are considering supporting some of the upcoming JPEG -Part 3 extensions --- principally, variable quantization and the SPIFF file -format. - -As always, speeding things up is of great interest. - -Please send bug reports, offers of help, etc. to jpeg-info@uunet.uu.net. diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/LICENSE-libpng.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/LICENSE-libpng.txt deleted file mode 100644 index 08e31294ae3e..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/LICENSE-libpng.txt +++ /dev/null @@ -1,130 +0,0 @@ - -This copy of the libpng notices is provided for your convenience. In case of -any discrepancy between this copy and the notices in the file png.h that is -included in the libpng distribution, the latter shall prevail. - -COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: - -If you modify libpng you may insert additional notices immediately following -this sentence. - -This code is released under the libpng license. - -libpng versions 1.0.7, July 1, 2000 through 1.6.26, October 20, 2016 are -Copyright (c) 2000-2002, 2004, 2006-2016 Glenn Randers-Pehrson, are -derived from libpng-1.0.6, and are distributed according to the same -disclaimer and license as libpng-1.0.6 with the following individuals -added to the list of Contributing Authors: - - Simon-Pierre Cadieux - Eric S. Raymond - Mans Rullgard - Cosmin Truta - Gilles Vollant - James Yu - -and with the following additions to the disclaimer: - - There is no warranty against interference with your enjoyment of the - library or against infringement. There is no warranty that our - efforts or the library will fulfill any of your particular purposes - or needs. This library is provided with all faults, and the entire - risk of satisfactory quality, performance, accuracy, and effort is with - the user. - -Some files in the "contrib" directory and some configure-generated -files that are distributed with libpng have other copyright owners and -are released under other open source licenses. - -libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are -Copyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from -libpng-0.96, and are distributed according to the same disclaimer and -license as libpng-0.96, with the following individuals added to the list -of Contributing Authors: - - Tom Lane - Glenn Randers-Pehrson - Willem van Schaik - -libpng versions 0.89, June 1996, through 0.96, May 1997, are -Copyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88, -and are distributed according to the same disclaimer and license as -libpng-0.88, with the following individuals added to the list of -Contributing Authors: - - John Bowler - Kevin Bracey - Sam Bushell - Magnus Holmgren - Greg Roelofs - Tom Tanner - -Some files in the "scripts" directory have other copyright owners -but are released under this license. - -libpng versions 0.5, May 1995, through 0.88, January 1996, are -Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. - -For the purposes of this copyright and license, "Contributing Authors" -is defined as the following set of individuals: - - Andreas Dilger - Dave Martindale - Guy Eric Schalnat - Paul Schmidt - Tim Wegner - -The PNG Reference Library is supplied "AS IS". The Contributing Authors -and Group 42, Inc. disclaim all warranties, expressed or implied, -including, without limitation, the warranties of merchantability and of -fitness for any purpose. The Contributing Authors and Group 42, Inc. -assume no liability for direct, indirect, incidental, special, exemplary, -or consequential damages, which may result from the use of the PNG -Reference Library, even if advised of the possibility of such damage. - -Permission is hereby granted to use, copy, modify, and distribute this -source code, or portions hereof, for any purpose, without fee, subject -to the following restrictions: - - 1. The origin of this source code must not be misrepresented. - - 2. Altered versions must be plainly marked as such and must not - be misrepresented as being the original source. - - 3. This Copyright notice may not be removed or altered from any - source or altered source distribution. - -The Contributing Authors and Group 42, Inc. specifically permit, without -fee, and encourage the use of this source code as a component to -supporting the PNG file format in commercial products. If you use this -source code in a product, acknowledgment is not required but would be -appreciated. - -END OF COPYRIGHT NOTICE, DISCLAIMER, and LICENSE. - -TRADEMARK: - -The name "libpng" has not been registered by the Copyright owner -as a trademark in any jurisdiction. However, because libpng has -been distributed and maintained world-wide, continually since 1995, -the Copyright owner claims "common-law trademark protection" in any -jurisdiction where common-law trademark is recognized. - -OSI CERTIFICATION: - -Libpng is OSI Certified Open Source Software. OSI Certified Open Source is -a certification mark of the Open Source Initiative. OSI has not addressed -the additional disclaimers inserted at version 1.0.7. - -EXPORT CONTROL: - -The Copyright owner believes that the Export Control Classification -Number (ECCN) for libpng is EAR99, which means not subject to export -controls or International Traffic in Arms Regulations (ITAR) because -it is open source, publicly available software, that does not contain -any encryption software. See the EAR, paragraphs 734.3(b)(3) and -734.7(b). - -Glenn Randers-Pehrson -glennrp at users.sourceforge.net -October 20, 2016 diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/image.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/image.cpp deleted file mode 100644 index 38bb379ce592..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/image.cpp +++ /dev/null @@ -1,96 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "image.h" -#include "../../../common/sys/string.h" - -#include -#include - -namespace embree -{ - /*! loads an image from a file with auto-detection of format */ - Ref loadImageFromDisk(const FileName& fileName) - { - std::string ext = toLowerCase(fileName.ext()); - -#ifdef EMBREE_TUTORIALS_LIBPNG - if (ext == "png" ) return loadPNG(fileName); -#endif - -#ifdef EMBREE_TUTORIALS_LIBJPEG - if (ext == "jpg" ) return loadJPEG(fileName); -#endif - -#ifdef USE_IMAGEMAGICK - if (ext == "bmp" ) return loadMagick(fileName); - if (ext == "gif" ) return loadMagick(fileName); - if (ext == "tga" ) return loadMagick(fileName); - if (ext == "tif" ) return loadMagick(fileName); - if (ext == "tiff") return loadMagick(fileName); - if (ext == "png" ) return loadMagick(fileName); - if (ext == "jpg" ) return loadMagick(fileName); -#endif - - if (ext == "pfm" ) return loadPFM(fileName); - if (ext == "ppm" ) return loadPPM(fileName); - THROW_RUNTIME_ERROR("image format " + ext + " not supported"); - } - - /*! loads an image from a file with auto-detection of format */ - Ref loadImage(const FileName& fileName, bool cache) - { - static std::map > image_cache; - - if (!cache) - return loadImageFromDisk(fileName); - - if (image_cache.find(fileName) == image_cache.end()) - image_cache[fileName] = loadImageFromDisk(fileName); - - return image_cache[fileName]; - } - - /*! stores an image to file with auto-detection of format */ - void storeImage(const Ref& img, const FileName& fileName) - { - std::string ext = toLowerCase(fileName.ext()); - -#ifdef EMBREE_TUTORIALS_LIBJPEG - if (ext == "jpg" ) { storeJPEG(img, fileName); return; } -#endif - -#ifdef USE_IMAGEMAGICK - if (ext == "bmp" ) { storeMagick(img, fileName); return; } - if (ext == "gif" ) { storeMagick(img, fileName); return; } - if (ext == "tga" ) { storeMagick(img, fileName); return; } - if (ext == "tif" ) { storeMagick(img, fileName); return; } - if (ext == "tiff") { storeMagick(img, fileName); return; } - if (ext == "png" ) { storeMagick(img, fileName); return; } - if (ext == "jpg" ) { storeMagick(img, fileName); return; } -#endif - - if (ext == "pfm" ) { storePFM(img, fileName); return; } - if (ext == "ppm" ) { storePPM(img, fileName); return; } - if (ext == "tga" ) { storeTga(img, fileName); return; } - THROW_RUNTIME_ERROR("image format " + ext + " not supported"); - } - - /*! template instantiations */ - template class ImageT; - template class ImageT; - -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/image.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/image.h deleted file mode 100644 index 2551934e479b..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/image.h +++ /dev/null @@ -1,200 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../../../common/sys/platform.h" -#include "../../../common/sys/ref.h" -#include "../../../common/sys/filename.h" -#include "../../../common/math/color.h" - -#include -#include - -namespace embree -{ - /* virtual interface to image */ - class Image : public RefCount { - public: - Image (size_t width, size_t height, const std::string& name) : width(width), height(height), name(name) {} - virtual ~Image() {} - virtual Color4 get(size_t x, size_t y) const = 0; - virtual void set(size_t x, size_t y, const Color4& c) = 0; - void set(size_t x, size_t y, const Color& c) { set(x,y,Color4(c.r,c.g,c.b,1.0f)); } - void convertToRGBA8(unsigned char *dest) - { - for (size_t y=0;y - class ImageT : public Image { - public: - - /*! create empty image */ - ImageT (size_t width = 0, size_t height = 0, const std::string& name = "") - : Image(width,height,name) - { - data = new T[width*height]; - memset(data,0,width*height*sizeof(T)); - } - - /*! create image of constant color */ - ImageT (size_t width, size_t height, const T& color, const std::string& name = "") - : Image(width,height,name) - { - data = new T[width*height]; - for (size_t i=0; i Image3uc; - typedef ImageT Image3f; - typedef ImageT Image4uc; - typedef ImageT Image4f; - - /*! Generate a JPEG encoded image from a RGB8 buffer in memory. */ - void encodeRGB8_to_JPEG(unsigned char *image, size_t width, size_t height, unsigned char **encoded, unsigned long *capacity); - - /*! Loads image from file. Format is auto detected. */ - Ref loadImage(const FileName& filename, bool cache = false); - - /*! Loads image from JPEG file. */ - Ref loadJPEG(const FileName& fileName); - - /*! Loads image using ImageMagick. */ - Ref loadMagick(const FileName& fileName); - - /*! Loads image from PFM file. */ - Ref loadPFM(const FileName& fileName); - - /*! Loads image from PNG file. */ - Ref loadPNG(const FileName& fileName); - - /*! Loads image from PPM file. */ - Ref loadPPM(const FileName& fileName); - - /*! Loads image from TIFF file. */ -//Ref loadTIFF(const FileName& fileName); - - /*! Store image to file. Format is auto detected. */ - void storeImage(const Ref& image, const FileName& filename); - - /*! Store image to JPEG file. */ - void storeJPEG(const Ref& img, const FileName& fileName); - - /*! Store image to file using ImageMagick. */ - void storeMagick(const Ref& img, const FileName& fileName); - - /*! Store image to PFM file. */ - void storePFM(const Ref& img, const FileName& fileName); - - /*! Store image to PNG file. */ -//void storePNG(const Ref& img, const FileName& fileName); - - /*! Store image to PPM file. */ - void storePPM(const Ref& img, const FileName& fileName); - - /*! Store image to TGA file. */ - void storeTga(const Ref& img, const FileName& fileName); - - /*! Store image to TIFF file. */ -//void storeTIFF(const Ref& img, const FileName& fileName); - -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/jpeg.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/jpeg.cpp deleted file mode 100644 index 387081e962f8..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/jpeg.cpp +++ /dev/null @@ -1,200 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#ifdef EMBREE_TUTORIALS_LIBJPEG - -#include "image.h" -#include "jpeglib.h" - -namespace embree -{ - void compress(struct jpeg_compress_struct *cinfo, unsigned char *image) - { - - /*! Start compression. */ - jpeg_start_compress(cinfo, TRUE); - - /*! Pointer to and size of a scanline in the image. */ - JSAMPROW scanline[1]; size_t bytes = cinfo->image_width * cinfo->input_components; - - /*! Here we use the library state variable 'next_scanline' as the loop index. */ - while (cinfo->next_scanline < cinfo->image_height) scanline[0] = &image[cinfo->next_scanline * bytes], jpeg_write_scanlines(cinfo, scanline, 1); - - /*! Finish compression. */ - jpeg_finish_compress(cinfo); - - } - - unsigned char *decompress(struct jpeg_decompress_struct *cinfo) - { - - /*! Start decompression. */ - jpeg_start_decompress(cinfo); - - /*! Bytes per row in the scanline buffer. */ - size_t bytes = cinfo->output_width * cinfo->output_components; - - /*! Allocate scratch space for a single scanline. */ - JSAMPARRAY scanline = (*cinfo->mem->alloc_sarray)((j_common_ptr) cinfo, JPOOL_IMAGE, bytes, 1); - - /*! Allocate storage for the decompressed image. */ - unsigned char* image = new unsigned char[cinfo->output_height * bytes]; - - /*! Here we use the library state variable 'output_scanline' as the loop index. */ - while (cinfo->output_scanline < cinfo->output_height) - jpeg_read_scanlines(cinfo, scanline, 1), memcpy(&image[(cinfo->output_scanline - 1) * bytes], scanline[0], bytes); - - /*! Finish decompression. */ - jpeg_finish_decompress(cinfo); - return(image); - } - - void encodeRGB8_to_JPEG(unsigned char *image, size_t width, size_t height, unsigned char **encoded, unsigned long *capacity) - { - -#if JPEG_LIB_VERSION >= 80 - - /*! Compression parameters and scratch space pointers (allocated by the library). */ - struct jpeg_compress_struct cinfo; - - /*! The library error handler. */ - struct jpeg_error_mgr jerror; cinfo.err = jpeg_std_error(&jerror); - - /*! Initialize the JPEG compression object. */ - jpeg_create_compress(&cinfo); - - /*! Specify the incoming image resolution, color space, and color space components. */ - cinfo.image_width = width; cinfo.image_height = height; cinfo.in_color_space = JCS_RGB; cinfo.input_components = 3; - - /*! Fill in a sensible set of defaults. */ - jpeg_set_defaults(&cinfo); - - /*! Set the image quality. */ - jpeg_set_quality(&cinfo, 90, TRUE); - - /*! Specify the data source. */ - jpeg_mem_dest(&cinfo, encoded, capacity); - - /*! Compress and write the image into the target buffer. */ - compress(&cinfo, image); - - /*! At this point 'jerror.num_warnings' could be checked for corrupt-data warnings. */ - jpeg_destroy_compress(&cinfo); - -#else // JPEG_LIB_VERSION - - THROW_RUNTIME_ERROR("JPEG encoding into a memory buffer requires LibJPEG 8a or higher"); - -#endif // JPEG_LIB_VERSION - - } - - Ref loadJPEG(const FileName &filename) - { - - /*! Open the source JPEG file. */ - FILE *file = fopen(filename.c_str(), "rb"); if (!file) THROW_RUNTIME_ERROR("Unable to open \"" + filename.str() + "\"."); - - /*! Decompression parameters and scratch space pointers allocated by the library. */ - struct jpeg_decompress_struct cinfo; - - /*! The library error handler. */ - struct jpeg_error_mgr jerror; cinfo.err = jpeg_std_error(&jerror); - - /*! Initialize the JPEG decompression object. */ - jpeg_create_decompress(&cinfo); - - /*! Specify the data source. */ - jpeg_stdio_src(&cinfo, file); - - /*! Read file parameters with jpeg_read_header(). */ - jpeg_read_header(&cinfo, TRUE); - - /*! Specify the color space and color space components of the decompressed image. */ - cinfo.out_color_space = JCS_RGB; cinfo.output_components = 3; - - /*! Decompress the image into an output buffer and get the image dimensions. */ - unsigned char *rgb = decompress(&cinfo); size_t width = cinfo.output_width; size_t height = cinfo.output_height; - - /*! Allocate the Embree image. */ - Ref image = new Image4uc(width, height, filename); - - /*! Convert the image from unsigned char RGB to unsigned char RGBA. */ - for (size_t y=0, i=0 ; y < height ; y++) { - for (size_t x=0 ; x < width ; x++) { - const float r = (float) rgb[i++] / 255.0f; - const float g = (float) rgb[i++] / 255.0f; - const float b = (float) rgb[i++] / 255.0f; - image->set(x, y, Color4(r,g,b,1.0f)); - } - } - - /*! Clean up. */ - jpeg_destroy_decompress(&cinfo); - delete[] rgb; - fclose(file); - return(image); - } - - void storeJPEG(const Ref &image, const FileName &filename) - { - - /*! Open the target JPEG file. */ - FILE *file = fopen(filename.c_str(), "wb"); if (!file) THROW_RUNTIME_ERROR("Unable to open \"" + filename.str() + "\"."); - - /*! Compression parameters and scratch space pointers (allocated by the library). */ - struct jpeg_compress_struct cinfo; - - /*! The library error handler. */ - struct jpeg_error_mgr jerror; cinfo.err = jpeg_std_error(&jerror); - - /*! Initialize the JPEG compression object. */ - jpeg_create_compress(&cinfo); - - /*! Specify the incoming image resolution, color space, and color space components. */ - cinfo.image_width = image->width; cinfo.image_height = image->height; cinfo.in_color_space = JCS_RGB; cinfo.input_components = 3; - - /*! Fill in a sensible set of defaults. */ - jpeg_set_defaults(&cinfo); - - /*! Specify the data source. */ - jpeg_stdio_dest(&cinfo, file); - - /*! Allocate storage for the uncompressed packed image. */ - unsigned char* rgb = new unsigned char [3 * image->height * image->width]; - - /*! Convert the image to unsigned char RGB. */ - for (size_t y=0, i=0 ; y < image->height ; y++) { - for (size_t x=0 ; x < image->width ; x++) { - const Color4 pixel = image->get(x, y); - rgb[i++] = (unsigned char)(clamp(pixel.r) * 255.0f); - rgb[i++] = (unsigned char)(clamp(pixel.g) * 255.0f); - rgb[i++] = (unsigned char)(clamp(pixel.b) * 255.0f); - } - } - - /*! Compress and write the image into the target file. */ - compress(&cinfo, rgb); - - /*! At this point 'jerror.num_warnings' could be checked for corrupt-data warnings. */ - jpeg_destroy_compress(&cinfo); - delete [] rgb; - fclose(file); - } -} - -#endif // EMBREE_TUTORIALS_LIBJPEG - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/magick.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/magick.cpp deleted file mode 100644 index 19483b873972..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/magick.cpp +++ /dev/null @@ -1,96 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#ifdef USE_IMAGEMAGICK - -#include "image.h" -#include - -/*! include Image Magick headers */ -#include -using namespace Magick; - -namespace embree -{ - Ref loadMagick(const FileName& fileName) - { - Magick::Image image(fileName.c_str()); - Image* out = new Image4uc(image.columns(),image.rows(),fileName); - float rcpMaxRGB = 1.0f/float(MaxRGB); - Magick::Pixels pixel_cache(image); - Magick::PixelPacket* pixels = pixel_cache.get(0,0,out->width,out->height); - - switch (image.orientation()) - { - case UndefinedOrientation: - case TopLeftOrientation: { - for (size_t y=0; yheight; y++) { - for (size_t x=0; xwidth; x++) { - Color4 c; - c.r = float(pixels[y*out->width+x].red)*rcpMaxRGB; - c.g = float(pixels[y*out->width+x].green)*rcpMaxRGB; - c.b = float(pixels[y*out->width+x].blue)*rcpMaxRGB; - c.a = float(pixels[y*out->width+x].opacity)*rcpMaxRGB; - out->set(x,out->height-y-1,c); - } - } - break; - } - case BottomLeftOrientation: { - for (size_t y=0; yheight; y++) { - for (size_t x=0; xwidth; x++) { - Color4 c; - c.r = float(pixels[y*out->width+x].red)*rcpMaxRGB; - c.g = float(pixels[y*out->width+x].green)*rcpMaxRGB; - c.b = float(pixels[y*out->width+x].blue)*rcpMaxRGB; - c.a = float(pixels[y*out->width+x].opacity)*rcpMaxRGB; - out->set(x,y,c); - } - } - break; - } - default: { - throw std::runtime_error("not supported image orientation"); - } - } - - return out; - } - - void storeMagick(const Ref& img, const FileName& fileName) - { - Magick::Image image(Magick::Geometry(img->width,img->height), - Magick::ColorRGB(0,0,0)); - image.modifyImage(); - - Magick::Pixels pixel_cache(image); - Magick::PixelPacket* pixels = pixel_cache.get(0,0,img->width,img->height); - for (size_t y=0; yheight; y++) { - for (size_t x=0; xwidth; x++) { - Color4 c = img->get(x,y); - pixels[y*img->width+x].red = Magick::Quantum(clamp(c.r)*MaxRGB); - pixels[y*img->width+x].green = Magick::Quantum(clamp(c.g)*MaxRGB); - pixels[y*img->width+x].blue = Magick::Quantum(clamp(c.b)*MaxRGB); - pixels[y*img->width+x].opacity = Magick::Quantum(clamp(c.a)*MaxRGB); - } - } - pixel_cache.sync(); - image.write(fileName.c_str()); - } -} - -#endif // USE_IMAGEMAGICK - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/pfm.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/pfm.cpp deleted file mode 100644 index 066c9f515cf2..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/pfm.cpp +++ /dev/null @@ -1,103 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "image.h" - -#include -#include -#include - -namespace embree -{ - static void skipSpacesAndComments(std::fstream& file) - { - while (true) - { - if (isspace(file.peek())) { - file.ignore(); - } else if (file.peek() == '#') { - std::string line; std::getline(file,line); - } else break; - } - } - - /*! read PFM file from disk */ - Ref loadPFM(const FileName& fileName) - { - /* open file for reading */ - std::fstream file; - file.exceptions (std::fstream::failbit | std::fstream::badbit); - file.open (fileName.c_str(), std::fstream::in | std::fstream::binary); - - /* read file type */ - char cty[2]; file.read(cty,2); - skipSpacesAndComments(file); - std::string type(cty,2); - - /* read width, height, and maximal color value */ - int width; file >> width; - skipSpacesAndComments(file); - int height; file >> height; - skipSpacesAndComments(file); - float maxColor; file >> maxColor; - if (maxColor > 0) THROW_RUNTIME_ERROR("Big endian PFM files not supported"); - float rcpMaxColor = -1.0f/float(maxColor); - file.ignore(); // skip space or return - - /* create image and fill with data */ - Ref img = new Image4f(width,height,fileName); - - /* image in binary format 16 bit */ - if (type == "PF") - { - float rgb[3]; - for (ssize_t y=height-1; y>=0; y--) { - for (ssize_t x=0; xset(x,y,Color4(rgb[0]*rcpMaxColor,rgb[1]*rcpMaxColor,rgb[2]*rcpMaxColor,1.0f)); - } - } - } - - /* invalid magic value */ - else { - THROW_RUNTIME_ERROR("Invalid magic value in PFM file"); - } - return img; - } - - /*! store PFM file to disk */ - void storePFM(const Ref& img, const FileName& fileName) - { - /* open file for writing */ - std::fstream file; - file.exceptions (std::fstream::failbit | std::fstream::badbit); - file.open (fileName.c_str(), std::fstream::out | std::fstream::binary); - - /* write file header */ - file << "PF" << std::endl; - file << img->width << " " << img->height << std::endl; - file << -1.0f << std::endl; - - /* write image */ - for (ssize_t y=img->height-1; y>=0; y--) { - for (ssize_t x=0; x<(ssize_t)img->width; x++) { - const Color4 c = img->get(x,y); - file.write((char*)&c,3*sizeof(float)); - } - } - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/png.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/png.cpp deleted file mode 100644 index e4ddf12f69ed..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/png.cpp +++ /dev/null @@ -1,148 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#ifdef EMBREE_TUTORIALS_LIBPNG - -#include "image.h" - -#include -#include -#include -#include - -namespace embree -{ - struct AutoCloseFile - { - FILE* file; - AutoCloseFile (FILE* file) : file(file) {} - ~AutoCloseFile () { if (file) fclose(file); } - }; - - /*! read PNG file from disk */ - Ref loadPNG(const FileName& fileName) - { - size_t width, height; - - //header for testing if it is a png - png_byte header[8]; - - //open file as binary - FILE* fp = fopen(fileName.c_str(), "rb"); - if (!fp) THROW_RUNTIME_ERROR("cannot open file "+fileName.str()); - //ON_SCOPE_EXIT(fclose(fp)); - AutoCloseFile close_file(fp); - - //read the header - if (fread(header, 1, 8, fp) != 8) - THROW_RUNTIME_ERROR("invalid PNG file "+fileName.str()); - - //test if png - int is_png = !png_sig_cmp(header, 0, 8); - if (!is_png) - THROW_RUNTIME_ERROR("invalid PNG file "+fileName.str()); - - //create png struct - png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); - if (!png_ptr) THROW_RUNTIME_ERROR("invalid PNG file "+fileName.str()); - ON_SCOPE_EXIT(png_destroy_read_struct(&png_ptr, (png_infopp) nullptr, (png_infopp) nullptr)); - - //create png info struct - png_infop info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) - THROW_RUNTIME_ERROR("invalid PNG file "+fileName.str()); - - //create png info struct - png_infop end_info = png_create_info_struct(png_ptr); - if (!end_info) - THROW_RUNTIME_ERROR("invalid PNG file "+fileName.str()); - - //png error stuff, not sure libpng man suggests this. - //if (setjmp(png_jmpbuf(png_ptr))) { - /// return (TEXTURE_LOAD_ERROR); - //} - - //init png reading - png_init_io(png_ptr, fp); - - //let libpng know you already read the first 8 bytes - png_set_sig_bytes(png_ptr, 8); - - // read all the info up to the image data - png_read_info(png_ptr, info_ptr); - - //variables to pass to get info - int bit_depth, color_type; - png_uint_32 twidth, theight; - - // get info about png - png_get_IHDR(png_ptr, info_ptr, &twidth, &theight, &bit_depth, &color_type, - nullptr, nullptr, nullptr); - - //update width and height based on png info - width = twidth; - height = theight; - - Ref img = new Image4uc(width,height,fileName); - - // Update the png info struct. - png_read_update_info(png_ptr, info_ptr); - - // Row size in bytes. - int rowbytes = png_get_rowbytes(png_ptr, info_ptr); - - // Allocate the image_data as a big block, to be given to opengl - std::vector data(rowbytes * height); - - // row_pointers is for pointing to image_data for reading the png with libpng - std::vector row_pointers(height); - - // set the individual row_pointers to point at the correct offsets of image_data - for (size_t i = 0; i < height; ++i) - row_pointers[i] = (unsigned char*) &data[i * rowbytes]; - - // read the png into image_data through row_pointers - png_read_image(png_ptr, row_pointers.data()); - - if (color_type == PNG_COLOR_TYPE_RGB && bit_depth == 8) - { - for (size_t y=0;yset(x,y,c); - } - } - else if (color_type == PNG_COLOR_TYPE_RGBA && bit_depth == 8) - { - for (size_t y=0;yset(x,y,c); - } - } - else - THROW_RUNTIME_ERROR("invalid color type in PNG file "+fileName.str()); - - return img; - } -} - -#endif - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/ppm.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/ppm.cpp deleted file mode 100644 index 0d120407f8cb..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/ppm.cpp +++ /dev/null @@ -1,130 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "image.h" - -#include -#include -#include -#include - -namespace embree -{ - static void skipSpacesAndComments(std::fstream& file) - { - while (true) - { - if (isspace(file.peek())) { - file.ignore(); - } else if (file.peek() == '#') { - std::string line; std::getline(file,line); - } else break; - } - } - - /*! read PPM file from disk */ - Ref loadPPM(const FileName& fileName) - { - /* open file for reading */ - std::fstream file; - file.exceptions (std::fstream::failbit | std::fstream::badbit); - file.open (fileName.c_str(), std::fstream::in | std::fstream::binary); - - /* read file type */ - char cty[2]; file.read(cty,2); - skipSpacesAndComments(file); - std::string type(cty,2); - - /* read width, height, and maximal color value */ - int width; file >> width; - skipSpacesAndComments(file); - int height; file >> height; - skipSpacesAndComments(file); - int maxColor; file >> maxColor; - if (maxColor <= 0) THROW_RUNTIME_ERROR("Invalid maxColor value in PPM file"); - float rcpMaxColor = 1.0f/float(maxColor); - file.ignore(); // skip space or return - - /* create image and fill with data */ - Ref img = new Image4uc(width,height,fileName); - - /* image in text format */ - if (type == "P3") - { - int r, g, b; - for (ssize_t y=0; y> r; file >> g; file >> b; - img->set(x,y,Color4(float(r)*rcpMaxColor,float(g)*rcpMaxColor,float(b)*rcpMaxColor,1.0f)); - } - } - } - - /* image in binary format 8 bit */ - else if (type == "P6" && maxColor <= 255) - { - unsigned char rgb[3]; - for (ssize_t y=0; yset(x,y,Color4(float(rgb[0])*rcpMaxColor,float(rgb[1])*rcpMaxColor,float(rgb[2])*rcpMaxColor,1.0f)); - } - } - } - - /* image in binary format 16 bit */ - else if (type == "P6" && maxColor <= 65535) - { - unsigned short rgb[3]; - for (ssize_t y=0; yset(x,y,Color4(float(rgb[0])*rcpMaxColor,float(rgb[1])*rcpMaxColor,float(rgb[2])*rcpMaxColor,1.0f)); - } - } - } - - /* invalid magic value */ - else { - THROW_RUNTIME_ERROR("Invalid magic value in PPM file"); - } - return img; - } - - /*! store PPM file to disk */ - void storePPM(const Ref& img, const FileName& fileName) - { - /* open file for writing */ - std::fstream file; - file.exceptions (std::fstream::failbit | std::fstream::badbit); - file.open (fileName.c_str(), std::fstream::out | std::fstream::binary); - - /* write file header */ - file << "P6" << std::endl; - file << img->width << " " << img->height << std::endl; - file << 255 << std::endl; - - /* write image */ - for (size_t y=0; yheight; y++) { - for (size_t x=0; xwidth; x++) { - const Color4 c = img->get(x,y); - file << (unsigned char)(clamp(c.r)*255.0f); - file << (unsigned char)(clamp(c.g)*255.0f); - file << (unsigned char)(clamp(c.b)*255.0f); - } - } - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/tga.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/tga.cpp deleted file mode 100644 index 949acf7d2674..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/image/tga.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "image.h" - -#include - -namespace embree -{ - inline void fwrite_uchar (unsigned char v, FILE* file) { fwrite(&v, sizeof(v), 1, file); } - inline void fwrite_ushort(unsigned short v, FILE* file) { fwrite(&v, sizeof(v), 1, file); } - - void storeTga(const Ref& img, const FileName& fileName) - { - FILE* file = fopen(fileName.c_str(), "wb"); - if (!file) THROW_RUNTIME_ERROR("error opening file " + fileName.str()); - - fwrite_uchar(0x00, file); - fwrite_uchar(0x00, file); - fwrite_uchar(0x02, file); - fwrite_ushort(0x0000, file); - fwrite_ushort(0x0000, file); - fwrite_ushort(0x0000, file); - fwrite_ushort(0x0000, file); - fwrite_uchar(0x00, file); - fwrite_ushort((unsigned short)img->width , file); - fwrite_ushort((unsigned short)img->height, file); - fwrite_uchar(0x18, file); - fwrite_uchar(0x20, file); - - for (size_t y=0; yheight; y++) { - for (size_t x=0; xwidth; x++) { - Color c = img->get(x,y); - fwrite_uchar((unsigned char)(clamp(c.b)*255.0f), file); - fwrite_uchar((unsigned char)(clamp(c.g)*255.0f), file); - fwrite_uchar((unsigned char)(clamp(c.r)*255.0f), file); - } - } - fclose(file); - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/CMakeLists.txt deleted file mode 100644 index 23f5af9598eb..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/CMakeLists.txt +++ /dev/null @@ -1,40 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2017 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -ADD_LIBRARY(lights STATIC - light.cpp - ambient_light.cpp - directional_light.cpp - point_light.cpp - quad_light.cpp - spot_light.cpp -) -TARGET_LINK_LIBRARIES(lights sys) -SET_PROPERTY(TARGET lights PROPERTY FOLDER tutorials/common) - -IF (EMBREE_ISPC_SUPPORT) - ADD_ISPC_LIBRARY(lights_ispc STATIC - light.ispc - ambient_light.ispc - directional_light.ispc - point_light.ispc - quad_light.ispc - spot_light.ispc - ) - TARGET_LINK_LIBRARIES(lights_ispc sys) - SET_TARGET_PROPERTIES(lights_ispc PROPERTIES LINKER_LANGUAGE C) - SET_PROPERTY(TARGET lights_ispc PROPERTY FOLDER tutorials/common) -ENDIF() diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/ambient_light.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/ambient_light.cpp deleted file mode 100644 index eb72e7d16a9e..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/ambient_light.cpp +++ /dev/null @@ -1,96 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "light.h" -#include "../math/sampling.h" -#include "../math/linearspace.h" - -namespace embree { - -struct AmbientLight -{ - Light super; //!< inherited light fields - - Vec3fa radiance; //!< RGB color and intensity of light -}; - - -// Implementation -////////////////////////////////////////////////////////////////////////////// - -// XXX importance sampling is only done into the positive hemisphere -// ==> poor support for translucent materials -Light_SampleRes AmbientLight_sample(const Light* super, - const DifferentialGeometry& dg, - const Vec2f& s) -{ - AmbientLight* self = (AmbientLight*)super; - Light_SampleRes res; - - const Vec3fa localDir = cosineSampleHemisphere(s); - res.dir = frame(dg.Ns) * localDir; - res.pdf = cosineSampleHemispherePDF(localDir); - res.dist = inf; - res.weight = self->radiance * rcp(res.pdf); - - return res; -} - -Light_EvalRes AmbientLight_eval(const Light* super, - const DifferentialGeometry& dg, - const Vec3fa& dir) -{ - AmbientLight* self = (AmbientLight*)super; - Light_EvalRes res; - - res.value = self->radiance; - res.dist = inf; - res.pdf = cosineSampleHemispherePDF(max(dot(dg.Ns, dir), 0.f)); - - return res; -} - - -void AmbientLight_Constructor(AmbientLight* self, - const Vec3fa& radiance) -{ - Light_Constructor(&self->super); - self->radiance = radiance; - self->super.sample = AmbientLight_sample; - self->super.eval = AmbientLight_eval; -} - - -// Exports (called from C++) -////////////////////////////////////////////////////////////////////////////// - -//! Create an ispc-side AmbientLight object -extern "C" void *AmbientLight_create() -{ - AmbientLight* self = (AmbientLight*) alignedMalloc(sizeof(AmbientLight)); - AmbientLight_Constructor(self, Vec3fa(1.f)); - return self; -} - -//! Set the parameters of an ispc-side AmbientLight object -extern "C" void AmbientLight_set(void* super, - const Vec3fa& radiance) -{ - AmbientLight* self = (AmbientLight*)super; - self->radiance = radiance; -} - -} // namespace embree diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/ambient_light.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/ambient_light.h deleted file mode 100644 index dc02ae1af6e8..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/ambient_light.h +++ /dev/null @@ -1,27 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../math/vec.h" - -namespace embree -{ - extern "C" void* AmbientLight_create(); - - extern "C" void AmbientLight_set(void* super, - const Vec3fa& radiance); -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/directional_light.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/directional_light.cpp deleted file mode 100644 index 9de225e49c6c..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/directional_light.cpp +++ /dev/null @@ -1,107 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "light.h" -#include "../math/sampling.h" -#include "../math/linearspace.h" - -namespace embree { - -struct DirectionalLight -{ - Light super; //!< inherited light fields - - LinearSpace3fa frame; //!< coordinate frame, with vz == direction *towards* the light source - Vec3fa radiance; //!< RGB color and intensity of light - float cosAngle; //!< Angular limit of the cone light in an easier to use form: cosine of the half angle in radians - float pdf; //!< Probability to sample a direction to the light -}; - -// for very small cones treat as singular light, because float precision is not good enough -#define COS_ANGLE_MAX 0.99999988f - - -// Implementation -////////////////////////////////////////////////////////////////////////////// - -Light_SampleRes DirectionalLight_sample(const Light* super, - const DifferentialGeometry& dg, - const Vec2f& s) -{ - const DirectionalLight* self = (DirectionalLight*)super; - Light_SampleRes res; - - res.dir = self->frame.vz; - res.dist = inf; - res.pdf = self->pdf; - - if (self->cosAngle < COS_ANGLE_MAX) - res.dir = self->frame * uniformSampleCone(self->cosAngle, s); - - res.weight = self->radiance; // *pdf/pdf cancel - - return res; -} - -Light_EvalRes DirectionalLight_eval(const Light* super, - const DifferentialGeometry&, - const Vec3fa& dir) -{ - DirectionalLight* self = (DirectionalLight*)super; - Light_EvalRes res; - res.dist = inf; - - if (self->cosAngle < COS_ANGLE_MAX && dot(self->frame.vz, dir) > self->cosAngle) { - res.value = self->radiance * self->pdf; - res.pdf = self->pdf; - } else { - res.value = Vec3fa(0.f); - res.pdf = 0.f; - } - - return res; -} - - -// Exports (called from C++) -////////////////////////////////////////////////////////////////////////////// - -//! Set the parameters of an ispc-side DirectionalLight object -extern "C" void DirectionalLight_set(void* super, - const Vec3fa& direction, - const Vec3fa& radiance, - float cosAngle) -{ - DirectionalLight* self = (DirectionalLight*)super; - self->frame = frame(direction); - self->radiance = radiance; - self->cosAngle = cosAngle; - self->pdf = cosAngle < COS_ANGLE_MAX ? uniformSampleConePDF(cosAngle) : inf; -} - -//! Create an ispc-side DirectionalLight object -extern "C" void* DirectionalLight_create() -{ - DirectionalLight* self = (DirectionalLight*) alignedMalloc(sizeof(DirectionalLight)); - Light_Constructor(&self->super); - self->super.sample = DirectionalLight_sample; - self->super.eval = DirectionalLight_eval; - - DirectionalLight_set(self, Vec3fa(0.f, 0.f, 1.f), Vec3fa(1.f), 1.f); - return self; -} - -} // namespace embree diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/directional_light.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/directional_light.h deleted file mode 100644 index 42705833b185..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/directional_light.h +++ /dev/null @@ -1,29 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../math/vec.h" - -namespace embree -{ - extern "C" void* DirectionalLight_create(); - - extern "C" void DirectionalLight_set(void* super, - const Vec3fa& direction, - const Vec3fa& radiance, - float cosAngle); -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/light.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/light.cpp deleted file mode 100644 index ab2a321d20a8..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/light.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "light.h" - -namespace embree { - -Light_EvalRes Light_eval(const Light* uniform, - const DifferentialGeometry&, - const Vec3fa&) -{ - Light_EvalRes res; - res.value = Vec3fa(0.f); - res.dist = inf; - res.pdf = 0.f; - return res; -} -extern "C" void dummy() {} // just to avoid linker warning under MacOSX - -} // namespace embree diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/light.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/light.h deleted file mode 100644 index bfccd2b67a87..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/light.h +++ /dev/null @@ -1,67 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../core/differential_geometry.h" - -namespace embree { - -struct Light; - -struct Light_SampleRes -{ - Vec3fa weight; //!< radiance that arrives at the given point divided by pdf - Vec3fa dir; //!< direction towards the light source - float dist; //!< largest valid t_far value for a shadow ray - float pdf; //!< probability density that this sample was taken -}; - -//! compute the weighted radiance at a point caused by a sample on the light source -// by convention, giving (0, 0) as "random" numbers should sample the "center" -// of the light source (used by the raytracing renderers such as the OBJ renderer) -typedef Light_SampleRes (*Light_SampleFunc)(const Light* self, - const DifferentialGeometry& dg, /*! point to generate the sample for >*/ - const Vec2f& s); /*! random numbers to generate the sample >*/ - - -struct Light_EvalRes -{ - Vec3fa value; //!< radiance that arrives at the given point (not weighted by pdf) - float dist; - float pdf; //!< probability density that the direction would have been sampled -}; - -//! compute the radiance, distance and pdf caused by the light source (pointed to by the given direction) -typedef Light_EvalRes (*Light_EvalFunc)(const Light* self, - const DifferentialGeometry& dg, /*! point to evaluate illumination for >*/ - const Vec3fa& dir); /*! direction towards the light source >*/ - - -struct Light -{ - Light_SampleFunc sample; - Light_EvalFunc eval; -}; - -Light_EvalRes Light_eval(const Light* self, const DifferentialGeometry& dg, const Vec3fa& dir); - -inline void Light_Constructor(Light* self) -{ - self->eval = Light_eval; -} - -} // namespace embree diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/point_light.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/point_light.cpp deleted file mode 100644 index 29e5769908a6..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/point_light.cpp +++ /dev/null @@ -1,146 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "light.h" -#include "../math/sampling.h" -#include "../math/linearspace.h" - -namespace embree { - -struct PointLight -{ - Light super; //!< inherited light fields - - Vec3fa position; //!< light position - Vec3fa power; //!< RGB color and intensity of light - float radius; //!< defines the size of the SphereLight -}; - - -// Implementation -////////////////////////////////////////////////////////////////////////////// - -Light_SampleRes PointLight_sample(const Light* super, - const DifferentialGeometry& dg, - const Vec2f& s) -{ - const PointLight* self = (PointLight*)super; - Light_SampleRes res; - - // extant light vector from the hit point - const Vec3fa dir = self->position - dg.P; - const float dist2 = dot(dir, dir); - const float invdist = rsqrt(dist2); - - // normalized light vector - res.dir = dir * invdist; - res.dist = dist2 * invdist; - - res.pdf = inf; // per default we always take this res - - // convert from power to radiance by attenuating by distance^2 - res.weight = self->power * sqr(invdist); - const float sinTheta = self->radius * invdist; - - if ((self->radius > 0.f) & (sinTheta > 0.005f)) { - // res surface of sphere as seen by hit point -> cone of directions - // for very small cones treat as point light, because float precision is not good enough - if (sinTheta < 1.f) { - const float cosTheta = sqrt(1.f - sinTheta * sinTheta); - const Vec3fa localDir = uniformSampleCone(cosTheta, s); - res.dir = frame(res.dir) * localDir; - res.pdf = uniformSampleConePDF(cosTheta); - const float c = localDir.z; - res.dist = c*res.dist - sqrt(sqr(self->radius) - (1.f - c*c) * dist2); - // TODO scale radiance by actual distance - } else { // inside sphere - const Vec3fa localDir = cosineSampleHemisphere(s); - res.dir = frame(dg.Ns) * localDir; - res.pdf = cosineSampleHemispherePDF(localDir); - // TODO: - res.weight = self->power * rcp(sqr(self->radius)); - res.dist = self->radius; - } - } - - return res; -} - -Light_EvalRes PointLight_eval(const Light* super, - const DifferentialGeometry& dg, - const Vec3fa& dir) -{ - const PointLight* self = (PointLight*)super; - Light_EvalRes res; - res.value = Vec3fa(0.f); - res.dist = inf; - res.pdf = 0.f; - - if (self->radius > 0.f) { - const Vec3fa A = self->position - dg.P; - const float a = dot(dir, dir); - const float b = 2.f * dot(dir, A); - const float centerDist2 = dot(A, A); - const float c = centerDist2 - sqr(self->radius); - const float radical = sqr(b) - 4.f*a*c; - - if (radical > 0.f) { - const float t_near = (b - sqrt(radical)) / (2.f*a); - const float t_far = (b + sqrt(radical)) / (2.f*a); - - if (t_far > 0.0f) { - // TODO: handle interior case - res.dist = t_near; - const float sinTheta2 = sqr(self->radius) * rcp(centerDist2); - const float cosTheta = sqrt(1.f - sinTheta2); - res.pdf = uniformSampleConePDF(cosTheta); - const float invdist = rcp(t_near); - res.value = self->power * res.pdf * sqr(invdist); - } - } - } - - return res; -} - -// Exports (called from C++) -////////////////////////////////////////////////////////////////////////////// - -//! Set the parameters of an ispc-side PointLight object -extern "C" void PointLight_set(void* super, - const Vec3fa& position, - const Vec3fa& power, - float radius) -{ - PointLight* self = (PointLight*)super; - self->position = position; - self->power = power; - self->radius = radius; -} - -//! Create an ispc-side PointLight object -extern "C" void* PointLight_create() -{ - PointLight* self = (PointLight*) alignedMalloc(sizeof(PointLight)); - Light_Constructor(&self->super); - self->super.sample = PointLight_sample; - self->super.eval = PointLight_eval; - - PointLight_set(self, Vec3fa(0.f), Vec3fa(1.f), 0.f); - return self; -} - -} // namespace embree diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/point_light.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/point_light.h deleted file mode 100644 index 37d907a4b6ac..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/point_light.h +++ /dev/null @@ -1,29 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../math/vec.h" - -namespace embree -{ - extern "C" void* PointLight_create(); - - extern "C" void PointLight_set(void* super, - const Vec3fa& position, - const Vec3fa& power, - float radius); -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/quad_light.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/quad_light.cpp deleted file mode 100644 index 87cb06c51eb6..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/quad_light.cpp +++ /dev/null @@ -1,106 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "light.h" - -namespace embree { - -struct QuadLight -{ - Light super; //!< inherited light fields - - Vec3fa position; //!< world-space corner position of the light - Vec3fa edge1; //!< vectors to adjacent corners - Vec3fa edge2; //!< vectors to adjacent corners - Vec3fa radiance; //!< RGB color and intensity of the QuadLight - - Vec3fa nnormal; //!< negated normal, the direction that the QuadLight is not emitting; normalized - float ppdf; // probability to sample point on light = 1/area -}; - - -// Implementation -////////////////////////////////////////////////////////////////////////////// - -Light_SampleRes QuadLight_sample(const Light* super, - const DifferentialGeometry& dg, - const Vec2f& s) -{ - const QuadLight* self = (QuadLight*)super; - Light_SampleRes res; - - // res position on light with density ppdf = 1/area - // TODO: use solid angle sampling - const Vec3fa pos = self->position + self->edge1 * s.x + self->edge2 * s.y; - - // extant light vector from the hit point - const Vec3fa dir = pos - dg.P; - const float dist = length(dir); - - // normalized light vector - res.dir = dir / dist; - res.dist = dist; - - // convert to pdf wrt. solid angle - const float cosd = dot(self->nnormal, res.dir); - res.pdf = self->ppdf * (dist * dist) / abs(cosd); - - // emit only to one side - res.weight = cosd > 0.f ? self->radiance * rcp(res.pdf) : Vec3fa(0.f); - - return res; -} - - -// Exports (called from C++) -////////////////////////////////////////////////////////////////////////////// - -//! Set the parameters of an ispc-side QuadLight object -extern "C" void QuadLight_set(void* super, - const Vec3fa& position, - const Vec3fa& edge2, - const Vec3fa& edge1, - const Vec3fa& radiance) -{ - QuadLight* self = (QuadLight*)super; - self->position = position; - self->edge1 = edge1; - self->edge2 = edge2; - self->radiance = radiance; - - const Vec3fa ndirection = cross(edge2, edge1); - self->ppdf = rcp(length(ndirection)); - self->nnormal = ndirection * self->ppdf; -} - -//! Create an ispc-side QuadLight object -extern "C" void* QuadLight_create() -{ - QuadLight* self = (QuadLight*) alignedMalloc(sizeof(QuadLight)); - - Light_Constructor(&self->super); - self->super.sample = QuadLight_sample; - - QuadLight_set(self, - Vec3fa(0.f), - Vec3fa(1.f, 0.f, 0.f), - Vec3fa(0.f, 1.f, 0.f), - Vec3fa(1.f)); - - return self; -} - -} // namespace embree diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/quad_light.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/quad_light.h deleted file mode 100644 index de483b198edc..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/quad_light.h +++ /dev/null @@ -1,31 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../math/vec.h" - -namespace embree -{ - extern "C" void* QuadLight_create(); - - extern "C" void QuadLight_set(void* super, - const Vec3fa& position, - const Vec3fa& edge2, - const Vec3fa& edge1, - const Vec3fa& radiance); -} - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/spot_light.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/spot_light.cpp deleted file mode 100644 index 8dc1d07d4e70..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/spot_light.cpp +++ /dev/null @@ -1,151 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "light.h" -#include "../math/sampling.h" -#include "../math/linearspace.h" - -namespace embree { - -struct SpotLight -{ - Light super; //!< inherited light fields - - Vec3fa position; //!< Position of the SpotLight - LinearSpace3fa frame; //!< coordinate frame, with vz == direction that the SpotLight is emitting - Vec3fa power; //!< RGB color and intensity of the SpotLight - float cosAngleMax; //!< Angular limit of the spot in an easier to use form: cosine of the half angle in radians - float cosAngleScale; //!< 1/(cos(border of the penumbra area) - cosAngleMax); positive - float radius; //!< defines the size of the (extended) SpotLight - float diskPdf; //!< pdf of disk with radius -}; - - -// Implementation -////////////////////////////////////////////////////////////////////////////// - -Light_SampleRes SpotLight_sample(const Light* super, - const DifferentialGeometry& dg, - const Vec2f& s) -{ - const SpotLight* self = (SpotLight*)super; - Light_SampleRes res; - - // extant light vector from the hit point - res.dir = self->position - dg.P; - - if (self->radius > 0.) - res.dir = self->frame * uniformSampleDisk(self->radius, s) + res.dir; - - const float dist2 = dot(res.dir, res.dir); - const float invdist = rsqrt(dist2); - - // normalized light vector - res.dir = res.dir * invdist; - res.dist = dist2 * invdist; - - // cosine of the negated light direction and light vector. - const float cosAngle = -dot(self->frame.vz, res.dir); - const float angularAttenuation = clamp((cosAngle - self->cosAngleMax) * self->cosAngleScale); - - if (self->radius > 0.) - res.pdf = self->diskPdf * dist2 * abs(cosAngle); - else - res.pdf = inf; // we always take this res - - // convert from power to radiance by attenuating by distance^2; attenuate by angle - res.weight = self->power * (sqr(invdist) * angularAttenuation); - - return res; -} - -Light_EvalRes SpotLight_eval(const Light* super, - const DifferentialGeometry& dg, - const Vec3fa& dir) -{ - const SpotLight* self = (SpotLight*)super; - Light_EvalRes res; - res.value = Vec3fa(0.f); - res.dist = inf; - res.pdf = 0.f; - - if (self->radius > 0.f) { - // intersect disk - const float cosAngle = -dot(dir, self->frame.vz); - if (cosAngle > self->cosAngleMax) { // inside illuminated cone? - const Vec3fa vp = dg.P - self->position; - const float dp = dot(vp, self->frame.vz); - if (dp > 0.f) { // in front of light? - const float t = dp*rcp(cosAngle); - const Vec3fa vd = vp + t * dir; - if (dot(vd, vd) < sqr(self->radius)) { // inside disk? - const float angularAttenuation = min((cosAngle - self->cosAngleMax) * self->cosAngleScale, 1.f); - const float pdf = self->diskPdf * cosAngle; - res.value = self->power * (angularAttenuation * pdf); // *sqr(t)/sqr(t) cancels - res.dist = t; - res.pdf = pdf * sqr(t); - } - } - } - } - - return res; -} - - -// Exports (called from C++) -////////////////////////////////////////////////////////////////////////////// - -//! Set the parameters of an ispc-side SpotLight object -extern "C" void SpotLight_set(void* super, - const Vec3fa& position, - const Vec3fa& direction, - const Vec3fa& power, - float cosAngleMax, - float cosAngleScale, - float radius) -{ - SpotLight* self = (SpotLight*)super; - self->position = position; - self->frame = frame(direction); - self->power = power; - self->cosAngleMax = cosAngleMax; - self->cosAngleScale = cosAngleScale; - self->radius = radius; - self->diskPdf = uniformSampleDiskPDF(radius); -} - -//! Create an ispc-side SpotLight object -extern "C" void* SpotLight_create() -{ - SpotLight* self = (SpotLight*) alignedMalloc(sizeof(SpotLight)); - - Light_Constructor(&self->super); - self->super.sample = SpotLight_sample; - self->super.eval = SpotLight_eval; - - SpotLight_set(self, - Vec3fa(0.f), - Vec3fa(0.f, 0.f, 1.f), - Vec3fa(1.f), - 0.f, - 100.f, - 0.f); - - return self; -} - -} // namespace embree diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/spot_light.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/spot_light.h deleted file mode 100644 index eaea6fc155c0..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/lights/spot_light.h +++ /dev/null @@ -1,32 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../math/vec.h" - -namespace embree -{ - extern "C" void* SpotLight_create(); - - extern "C" void SpotLight_set(void* super, - const Vec3fa& position, - const Vec3fa& direction, - const Vec3fa& power, - float cosAngleMax, - float cosAngleScale, - float radius); -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/math/affinespace.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/math/affinespace.h deleted file mode 100644 index 4f64c5661bb8..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/math/affinespace.h +++ /dev/null @@ -1,25 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../../../common/math/affinespace.h" - -namespace embree -{ - __forceinline bool eq (const AffineSpace3fa& a, const AffineSpace3fa& b) { return a == b; } -} - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/math/linearspace.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/math/linearspace.h deleted file mode 100644 index 98d6e854ecdb..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/math/linearspace.h +++ /dev/null @@ -1,20 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../../../common/math/linearspace3.h" - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/math/math.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/math/math.h deleted file mode 100644 index 8c61149eac5a..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/math/math.h +++ /dev/null @@ -1,19 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../../../common/math/math.h" diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/math/random_sampler.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/math/random_sampler.h deleted file mode 100644 index d2a3f2d50575..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/math/random_sampler.h +++ /dev/null @@ -1,127 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../math/vec.h" - -namespace embree { - -struct RandomSampler -{ - unsigned int s; -}; - -__forceinline unsigned int MurmurHash3_mix(unsigned int hash, unsigned int k) -{ - const unsigned int c1 = 0xcc9e2d51; - const unsigned int c2 = 0x1b873593; - const unsigned int r1 = 15; - const unsigned int r2 = 13; - const unsigned int m = 5; - const unsigned int n = 0xe6546b64; - - k *= c1; - k = (k << r1) | (k >> (32 - r1)); - k *= c2; - - hash ^= k; - hash = ((hash << r2) | (hash >> (32 - r2))) * m + n; - - return hash; -} - -__forceinline unsigned int MurmurHash3_finalize(unsigned int hash) -{ - hash ^= hash >> 16; - hash *= 0x85ebca6b; - hash ^= hash >> 13; - hash *= 0xc2b2ae35; - hash ^= hash >> 16; - - return hash; -} - -__forceinline unsigned int LCG_next(unsigned int value) -{ - const unsigned int m = 1664525; - const unsigned int n = 1013904223; - - return value * m + n; -} - -__forceinline void RandomSampler_init(RandomSampler& self, int id) -{ - unsigned int hash = 0; - hash = MurmurHash3_mix(hash, id); - hash = MurmurHash3_finalize(hash); - - self.s = hash; -} - -__forceinline void RandomSampler_init(RandomSampler& self, int pixelId, int sampleId) -{ - unsigned int hash = 0; - hash = MurmurHash3_mix(hash, pixelId); - hash = MurmurHash3_mix(hash, sampleId); - hash = MurmurHash3_finalize(hash); - - self.s = hash; -} - -__forceinline void RandomSampler_init(RandomSampler& self, int x, int y, int sampleId) -{ - RandomSampler_init(self, x | (y << 16), sampleId); -} - -__forceinline int RandomSampler_getInt(RandomSampler& self) { - self.s = LCG_next(self.s); return self.s >> 1; -} - -__forceinline unsigned int RandomSampler_getUInt(RandomSampler& self) { - self.s = LCG_next(self.s); return self.s; -} - -__forceinline float RandomSampler_getFloat(RandomSampler& self) { - return (float)RandomSampler_getInt(self) * 4.656612873077392578125e-10f; -} - -__forceinline float RandomSampler_get1D(RandomSampler& self) { - return RandomSampler_getFloat(self); -} - -__forceinline Vec2f RandomSampler_get2D(RandomSampler& self) -{ - const float u = RandomSampler_get1D(self); - const float v = RandomSampler_get1D(self); - return Vec2f(u,v); -} - -__forceinline Vec3fa RandomSampler_get3D(RandomSampler& self) -{ - /* - const float u = RandomSampler_get1D(self); - const float v = RandomSampler_get1D(self); - const float w = RandomSampler_get1D(self); - return Vec3fa(u,v,w); - */ - const int u = RandomSampler_getUInt(self); - const int v = RandomSampler_getUInt(self); - const int w = RandomSampler_getUInt(self); - return Vec3fa(srl(Vec3ia(u,v,w), 1)) * 4.656612873077392578125e-10f; -} - -} // namespace embree diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/math/sampling.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/math/sampling.h deleted file mode 100644 index d9a03e4a4b9c..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/math/sampling.h +++ /dev/null @@ -1,145 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -/*! \brief utility library containing sampling functions */ - -// convention is to return the sample (Vec3fa) generated from given Vec2f 's'ample as last parameter -// sampling functions often come in pairs: sample and pdf (needed later for MIS) -// good reference is "Total Compendium" by Philip Dutre http://people.cs.kuleuven.be/~philip.dutre/GI/ - -#include "../math/vec.h" - -namespace embree { - - -inline Vec3fa cartesian(const float phi, const float sinTheta, const float cosTheta) -{ - float sinPhi, cosPhi; - sincosf(phi, &sinPhi, &cosPhi); - return Vec3fa(cosPhi * sinTheta, - sinPhi * sinTheta, - cosTheta); -} - -inline Vec3fa cartesian(const float phi, const float cosTheta) -{ - return cartesian(phi, cos2sin(cosTheta), cosTheta); -} - - -/// cosine-weighted sampling of hemisphere oriented along the +z-axis -//////////////////////////////////////////////////////////////////////////////// - -inline Vec3fa cosineSampleHemisphere(const Vec2f s) -{ - const float phi =float(two_pi) * s.x; - const float cosTheta = sqrt(s.y); - const float sinTheta = sqrt(1.0f - s.y); - return cartesian(phi, sinTheta, cosTheta); -} - -inline float cosineSampleHemispherePDF(const Vec3fa &dir) -{ - return dir.z / float(pi); -} - -inline float cosineSampleHemispherePDF(float cosTheta) -{ - return cosTheta / float(pi); -} - - -/// power cosine-weighted sampling of hemisphere oriented along the +z-axis -//////////////////////////////////////////////////////////////////////////////// - -inline Vec3fa powerCosineSampleHemisphere(const float n, const Vec2f &s) -{ - const float phi =float(two_pi) * s.x; - const float cosTheta = pow(s.y, 1.0f / (n + 1.0f)); - return cartesian(phi, cosTheta); -} - -inline float powerCosineSampleHemispherePDF(const float cosTheta, const float n) // TODO: order of arguments -{ - return (n + 1.0f) * (0.5f / float(pi)) * pow(cosTheta, n); -} - -inline float powerCosineSampleHemispherePDF(const Vec3fa& dir, const float n) // TODO: order of arguments -{ - return (n + 1.0f) * (0.5f / float(pi)) * pow(dir.z, n); -} - -/// sampling of cone of directions oriented along the +z-axis -//////////////////////////////////////////////////////////////////////////////// - -inline Vec3fa uniformSampleCone(const float cosAngle, const Vec2f &s) -{ - const float phi =float(two_pi) * s.x; - const float cosTheta = 1.0f - s.y * (1.0f - cosAngle); - return cartesian(phi, cosTheta); -} - -inline float uniformSampleConePDF(const float cosAngle) -{ - return rcp(float(two_pi)*(1.0f - cosAngle)); -} - -inline float _uniformSampleConePDF(const float cosAngle) -{ - return rcp(float(two_pi)*(1.0f - cosAngle)); -} - - -/// sampling of disk -//////////////////////////////////////////////////////////////////////////////// - -inline Vec3fa uniformSampleDisk(const float radius, const Vec2f &s) -{ - const float r = sqrtf(s.x) * radius; - const float phi =float(two_pi) * s.y; - float sinPhi, cosPhi; - sincosf(phi, &sinPhi, &cosPhi); - return Vec3fa(r * cosPhi, r * sinPhi, 0.f); -} - -inline float uniformSampleDiskPDF(const float radius) -{ - return rcp(float(pi) * sqr(radius)); -} - -inline float _uniformSampleDiskPDF(const float radius) -{ - return rcp(float(pi) * sqr(radius)); -} - - -/// sampling of triangle abc -//////////////////////////////////////////////////////////////////////////////// - -inline Vec3fa uniformSampleTriangle(const Vec3fa &a, const Vec3fa &b, const Vec3fa &c, const Vec2f &s) -{ - const float su = sqrtf(s.x); - return c + (1.0f - su) * (a-c) + (s.y*su) * (b-c); -} - -inline float uniformSampleTrianglePDF(const Vec3fa &a, const Vec3fa &b, const Vec3fa &c) -{ - return 2.0f * rcp(abs(length(cross(a-c, b-c)))); -} - -} // namespace embree diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/math/vec.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/math/vec.h deleted file mode 100644 index fad6458d5d35..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/math/vec.h +++ /dev/null @@ -1,100 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../../../common/math/vec2.h" -#include "../../../common/math/vec3.h" -#include "../../../common/math/vec4.h" - -namespace embree { - -__forceinline Vec3f neg(const Vec3f& a ) { return -a; } -__forceinline Vec3fa neg(const Vec3fa& a) { return -a; } -__forceinline bool eq (const Vec3fa& a, const Vec3fa& b) { return a == b; } -__forceinline bool ne (const Vec3fa& a, const Vec3fa& b) { return a != b; } - -// FIXME: change order of lerp arguments, then remove this function -template -__forceinline V lerpr(float t, const V& v0, const V& v1) { - return (1.0f-t)*v0 + t*v1; -} - -// ------------------------------------------------------- -// sRGB conversion functions -// ------------------------------------------------------- -#define APPROXIMATE_SRGB - -inline float linear_to_srgb(const float f) -{ - const float c = max(f, 0.f); -#ifdef APPROXIMATE_SRGB - return pow(c, 1.f/2.2f); -#else - return c <= 0.0031308f ? 12.92f*c : pow(c, 1.f/2.4f)*1.055f - 0.055f; -#endif -} - -inline Vec4f linear_to_srgba(const Vec4f c) -{ - return Vec4f(linear_to_srgb(c.x), - linear_to_srgb(c.y), - linear_to_srgb(c.z), - max(c.w, 0.f)); // alpha is never gamma-corrected -} - -inline uint32_t linear_to_srgba8(const Vec4f c) -{ -#if 1 - Vec4f l = 255.f * min(linear_to_srgba(c), Vec4f(1.f)); - return - ((uint32_t)l.x << 0) | - ((uint32_t)l.y << 8) | - ((uint32_t)l.z << 16) | - ((uint32_t)l.w << 24); -#else -// TODO use ISPC's float_to_srgb8 once it is fixed (issue #1198) - return - (float_to_srgb8(c.x) << 0) | - (float_to_srgb8(c.y) << 8) | - (float_to_srgb8(c.z) << 16) | - ((uint32_t)clamp(c.w, 0.f, 1.f) << 24); // alpha is never gamma-corrected -#endif -} - -inline float srgb_to_linear(const float f) -{ - const float c = max(f, 0.f); -#ifdef APPROXIMATE_SRGB - return pow(c, 2.2f); -#else - return c <= 0.04045f ? c/12.92f : pow((c + 0.055f)/1.055f, 2.4f); -#endif -} - -inline Vec4f srgba_to_linear(const Vec4f c) -{ - return Vec4f(srgb_to_linear(c.x), - srgb_to_linear(c.y), - srgb_to_linear(c.z), - max(c.w, 0.f)); // alpha is never gamma-corrected -} - -// TODO implement srgba8_to_linear with a 256 entry LUT - -#undef APPROXIMATE_SRGB - -} // namespace embree diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/CMakeLists.txt deleted file mode 100644 index 2e262c472376..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2017 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -ADD_LIBRARY(scenegraph STATIC - xml_parser.cpp - xml_loader.cpp - xml_writer.cpp - obj_loader.cpp - ply_loader.cpp - corona_loader.cpp - texture.cpp - scenegraph.cpp) - -TARGET_LINK_LIBRARIES(scenegraph sys lexers image) -SET_PROPERTY(TARGET scenegraph PROPERTY FOLDER tutorials/common) diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/corona_loader.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/corona_loader.cpp deleted file mode 100644 index 3404e7ef9824..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/corona_loader.cpp +++ /dev/null @@ -1,318 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "corona_loader.h" -#include "xml_parser.h" -#include "obj_loader.h" - -namespace embree -{ - class CoronaLoader - { - public: - - static Ref load(const FileName& fileName, const AffineSpace3fa& space); - CoronaLoader(const FileName& fileName, const AffineSpace3fa& space); - - private: - template T load(const Ref& xml) { assert(false); return T(zero); } - Ref loadMaterial(const Ref& xml); - void loadMaterialDefinition(const Ref& xml); - Texture* loadMap(const Ref& xml); - void loadMapDefinition(const Ref& xml); - Ref loadMaterialLibrary(const FileName& fileName); - Ref loadObject(const Ref& xml); - std::pair, avector > loadInstances(const Ref& xml); - Ref loadGroupNode(const Ref& xml); - Ref loadNode(const Ref& xml); - - private: - FileName path; - std::map > materialMap; - std::map textureMap; - std::map textureFileMap; - public: - Ref root; - }; - - template<> FileName CoronaLoader::load(const Ref& xml) - { - if (xml->body.size() != 1) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong FileName body"); - return xml->body[0].Identifier(); - } - - template<> std::string CoronaLoader::load(const Ref& xml) - { - if (xml->body.size() != 1) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong string body"); - return xml->body[0].Identifier(); - } - - template<> int CoronaLoader::load(const Ref& xml) { - if (xml->body.size() < 1) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong int body"); - return xml->body[0].Int(); - } - - template<> float CoronaLoader::load(const Ref& xml) { - if (xml->body.size() < 1) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong float body"); - return xml->body[0].Float(); - } - - template<> Vec3f CoronaLoader::load(const Ref& xml) { - if (xml->body.size() < 3) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong float3 body"); - return Vec3f(xml->body[0].Float(),xml->body[1].Float(),xml->body[2].Float()); - } - - template<> Vec3fa CoronaLoader::load(const Ref& xml) { - if (xml->body.size() < 3) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong float3 body"); - return Vec3fa(xml->body[0].Float(),xml->body[1].Float(),xml->body[2].Float()); - } - - template<> AffineSpace3fa CoronaLoader::load(const Ref& xml) - { - if (xml->body.size() != 12) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong AffineSpace body"); - return AffineSpace3fa(LinearSpace3fa(xml->body[0].Float(),xml->body[1].Float(),xml->body[ 2].Float(), - xml->body[4].Float(),xml->body[5].Float(),xml->body[ 6].Float(), - xml->body[8].Float(),xml->body[9].Float(),xml->body[10].Float()), - Vec3fa(xml->body[3].Float(),xml->body[7].Float(),xml->body[11].Float())); - } - - Ref CoronaLoader::loadMaterial(const Ref& xml) - { - if (xml->name != "material") - THROW_RUNTIME_ERROR(xml->loc.str()+": invalid material: "+xml->name); - - /* native material */ - if (xml->parm("class") == "Native") - { - /* we convert into an OBJ material */ - OBJMaterial objmaterial; - for (auto child : xml->children) - { - if (child->name == "diffuse") { - objmaterial.Kd = load(child); - if (child->children.size() && child->children[0]->name == "map") - objmaterial.map_Kd = loadMap(child->children[0]); - } - else if (child->name == "reflect") { - objmaterial.Ks = load(child->child("color")); - objmaterial.Ni = load(child->child("ior")); - objmaterial.Ns = load(child->child("glossiness")); - } - else if (child->name == "translucency") { - objmaterial.Kt = load(child->child("color")); - } - else if (child->name == "opacity") { - objmaterial.d = load(child).x; - if (child->children.size() && child->children[0]->name == "map") - objmaterial.map_d = loadMap(child->children[0]); - } - } - - /* return material */ - Material material; new (&material) OBJMaterial(objmaterial); - return new SceneGraph::MaterialNode(material); - } - - /* reference by name */ - else if (xml->parm("class") == "Reference") - { - const std::string name = load(xml); - return materialMap[name]; - } - - /* else return default material */ - else - { - Material objmtl; new (&objmtl) OBJMaterial; - return new SceneGraph::MaterialNode(objmtl); - } - } - - void CoronaLoader::loadMaterialDefinition(const Ref& xml) - { - if (xml->name != "materialDefinition") - THROW_RUNTIME_ERROR(xml->loc.str()+": invalid material definition: "+xml->name); - if (xml->children.size() != 1) - THROW_RUNTIME_ERROR(xml->loc.str()+": invalid material definition"); - - const std::string name = xml->parm("name"); - materialMap[name] = loadMaterial(xml->children[0]); - } - - Texture* CoronaLoader::loadMap(const Ref& xml) - { - /* process map node */ - if (xml->name == "map") - { - std::string mapClass = xml->parm("class"); - - /* load textures */ - if (mapClass == "Texture") - { - const FileName src = load(xml->child("image")); - - /* load images only once */ - if (textureFileMap.find(src) != textureFileMap.end()) - return textureFileMap[src]; - - try { - return Texture::load(path+src); - } catch (std::runtime_error e) { - std::cerr << "failed to load " << path+src << ": " << e.what() << std::endl; - } - } - else if (mapClass == "Reference") { - const std::string name = load(xml); - return textureMap[name]; - } - } - - /* recurse into every unknown node to find some texture */ - for (auto child : xml->children) { - Texture* texture = loadMap(child); - if (texture) return texture; - } - return nullptr; - } - - void CoronaLoader::loadMapDefinition(const Ref& xml) - { - if (xml->name != "mapDefinition") - THROW_RUNTIME_ERROR(xml->loc.str()+": invalid map definition: "+xml->name); - if (xml->children.size() != 1) - THROW_RUNTIME_ERROR(xml->loc.str()+": invalid map definition"); - - const std::string name = xml->parm("name"); - Texture* texture = loadMap(xml->children[0]); - if (texture) textureMap[name] = texture; - } - - Ref CoronaLoader::loadMaterialLibrary(const FileName& fileName) - { - Ref xml = parseXML(path+fileName,"/.-",false); - if (xml->name != "mtlLib") - THROW_RUNTIME_ERROR(xml->loc.str()+": invalid material library"); - - for (auto child : xml->children) - { - if (child->name == "materialDefinition") { - loadMaterialDefinition(child); - } - else if (child->name == "mapDefinition") - loadMapDefinition(child); - } - - return nullptr; - } - - Ref CoronaLoader::loadObject(const Ref& xml) - { - if (xml->name != "object") - THROW_RUNTIME_ERROR(xml->loc.str()+": invalid object node"); - if (xml->parm("class") != "file") - THROW_RUNTIME_ERROR(xml->loc.str()+": invalid object class"); - const FileName fileName = load(xml); - return SceneGraph::load(path+fileName); - } - - std::pair, avector > CoronaLoader::loadInstances(const Ref& xml) - { - if (xml->name != "instance") - THROW_RUNTIME_ERROR(xml->loc.str()+": invalid instance node"); - - /* create default material */ - Material objmtl; new (&objmtl) OBJMaterial; - Ref material = new SceneGraph::MaterialNode(objmtl); - - avector xfms; - for (size_t i=0; ichildren.size(); i++) - { - Ref child = xml->children[i]; - if (child->name == "material" ) material = loadMaterial(child); - else if (child->name == "transform") xfms.push_back(load(child)); - else THROW_RUNTIME_ERROR(child->loc.str()+": unknown node: "+child->name); - } - - return std::make_pair(material,xfms); - } - - Ref CoronaLoader::loadGroupNode(const Ref& xml) - { - if (xml->children.size() < 1) - THROW_RUNTIME_ERROR(xml->loc.str()+": invalid group node"); - - /* load instances */ - auto p = loadInstances(xml->children[0]); - Ref material = p.first; - avector& xfms = p.second; - - /* load meshes */ - Ref objects = new SceneGraph::GroupNode; - for (size_t i=1; ichildren.size(); i++) - objects->add(loadObject(xml->children[i])); - - /* force material */ - objects->setMaterial(material); - - /* create instances */ - Ref instances = new SceneGraph::GroupNode; - for (size_t i=0; iadd(new SceneGraph::TransformNode(xfms[i],objects.cast())); - - return instances.cast(); - } - - Ref CoronaLoader::loadNode(const Ref& xml) - { - if (xml->name == "conffile" ) return nullptr; - else if (xml->name == "mtllib" ) return loadMaterialLibrary(load(xml)); - else if (xml->name == "camera" ) return nullptr; - else if (xml->name == "environment" ) return nullptr; - else if (xml->name == "geometryGroup") return loadGroupNode(xml); - else THROW_RUNTIME_ERROR(xml->loc.str()+": unknown tag: "+xml->name); - return nullptr; - } - - Ref CoronaLoader::load(const FileName& fileName, const AffineSpace3fa& space) { - CoronaLoader loader(fileName,space); return loader.root; - } - - CoronaLoader::CoronaLoader(const FileName& fileName, const AffineSpace3fa& space) - { - path = fileName.path(); - Ref xml = parseXML(fileName,"/.-",false); - if (xml->name == "scene") - { - Ref group = new SceneGraph::GroupNode; - for (size_t i=0; ichildren.size(); i++) { - group->add(loadNode(xml->children[i])); - } - root = group.cast(); - } - else - THROW_RUNTIME_ERROR(xml->loc.str()+": invalid scene tag"); - - if (space == AffineSpace3fa(one)) - return; - - root = new SceneGraph::TransformNode(space,root); - } - - /*! read from disk */ - Ref SceneGraph::loadCorona(const FileName& fileName, const AffineSpace3fa& space) { - return CoronaLoader::load(fileName,space); - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/corona_loader.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/corona_loader.h deleted file mode 100644 index 5c24ccec2848..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/corona_loader.h +++ /dev/null @@ -1,27 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "scenegraph.h" - -namespace embree -{ - namespace SceneGraph - { - Ref loadCorona(const FileName& fileName, const AffineSpace3fa& space = one); - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/lights.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/lights.h deleted file mode 100644 index 0b8b588f9f1c..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/lights.h +++ /dev/null @@ -1,164 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../default.h" - -namespace embree -{ - namespace SceneGraph - { - enum LightType - { - LIGHT_AMBIENT, - LIGHT_POINT, - LIGHT_DIRECTIONAL, - LIGHT_SPOT, - LIGHT_DISTANT, - LIGHT_TRIANGLE, - LIGHT_QUAD, - }; - - class Light : public RefCount - { - ALIGNED_CLASS - - public: - Light(LightType type) : type(type) {} - - LightType getType() const { return type; } - virtual Ref transform(const AffineSpace3fa& space) const = 0; - - private: - LightType type; - }; - - class AmbientLight : public Light - { - public: - AmbientLight (const Vec3fa& L) - : Light(LIGHT_AMBIENT), L(L) {} - - Ref transform(const AffineSpace3fa& space) const { - return new AmbientLight(L); - } - - public: - Vec3fa L; //!< radiance of ambient light - }; - - class PointLight : public Light - { - public: - PointLight (const Vec3fa& P, const Vec3fa& I) - : Light(LIGHT_POINT), P(P), I(I) {} - - Ref transform(const AffineSpace3fa& space) const { - return new PointLight(xfmPoint(space,P),I); - } - - public: - Vec3fa P; //!< position of point light - Vec3fa I; //!< radiant intensity of point light - }; - - class DirectionalLight : public Light - { - public: - DirectionalLight (const Vec3fa& D, const Vec3fa& E) - : Light(LIGHT_DIRECTIONAL), D(D), E(E) {} - - Ref transform(const AffineSpace3fa& space) const { - return new DirectionalLight(xfmVector(space,D),E); - } - - public: - Vec3fa D; //!< Light direction - Vec3fa E; //!< Irradiance (W/m^2) - }; - - class SpotLight : public Light - { - public: - SpotLight (const Vec3fa& P, const Vec3fa& D, const Vec3fa& I, float angleMin, float angleMax) - : Light(LIGHT_SPOT), P(P), D(D), I(I), angleMin(angleMin), angleMax(angleMax) {} - - Ref transform(const AffineSpace3fa& space) const { - return new SpotLight(xfmPoint(space,P),xfmVector(space,D),I,angleMin,angleMax); - } - - public: - Vec3fa P; //!< Position of the spot light - Vec3fa D; //!< Light direction of the spot light - Vec3fa I; //!< Radiant intensity (W/sr) - float angleMin, angleMax; //!< Linear falloff region - }; - - class DistantLight : public Light - { - public: - DistantLight (const Vec3fa& D, const Vec3fa& L, const float halfAngle) - : Light(LIGHT_DISTANT), D(D), L(L), halfAngle(halfAngle), radHalfAngle(deg2rad(halfAngle)), cosHalfAngle(cos(deg2rad(halfAngle))) {} - - Ref transform(const AffineSpace3fa& space) const { - return new DistantLight(xfmVector(space,D),L,halfAngle); - } - - public: - Vec3fa D; //!< Light direction - Vec3fa L; //!< Radiance (W/(m^2*sr)) - float halfAngle; //!< Half illumination angle - float radHalfAngle; //!< Half illumination angle in radians - float cosHalfAngle; //!< Cosine of half illumination angle - }; - - class TriangleLight : public Light - { - public: - TriangleLight (const Vec3fa& v0, const Vec3fa& v1, const Vec3fa& v2, const Vec3fa& L) - : Light(LIGHT_TRIANGLE), v0(v0), v1(v1), v2(v2), L(L) {} - - Ref transform(const AffineSpace3fa& space) const { - return new TriangleLight(xfmPoint(space,v0),xfmPoint(space,v1),xfmPoint(space,v2),L); - } - - public: - Vec3fa v0; - Vec3fa v1; - Vec3fa v2; - Vec3fa L; - }; - - class QuadLight : public Light - { - public: - QuadLight (const Vec3fa& v0, const Vec3fa& v1, const Vec3fa& v2, const Vec3fa& v3, const Vec3fa& L) - : Light(LIGHT_QUAD), v0(v0), v1(v1), v2(v2), v3(v3), L(L) {} - - Ref transform(const AffineSpace3fa& space) const { - return new QuadLight(xfmPoint(space,v0),xfmPoint(space,v1),xfmPoint(space,v2),xfmPoint(space,v3),L); - } - - public: - Vec3fa v0; - Vec3fa v1; - Vec3fa v2; - Vec3fa v3; - Vec3fa L; - }; - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/materials.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/materials.h deleted file mode 100644 index 22a2721d153d..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/materials.h +++ /dev/null @@ -1,194 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../default.h" -#include "texture.h" - -namespace embree -{ - enum MaterialType - { - MATERIAL_OBJ, - MATERIAL_THIN_DIELECTRIC, - MATERIAL_METAL, - MATERIAL_VELVET, - MATERIAL_DIELECTRIC, - MATERIAL_METALLIC_PAINT, - MATERIAL_MATTE, - MATERIAL_MIRROR, - MATERIAL_REFLECTIVE_METAL, - MATERIAL_HAIR - }; - - class MaterialBase - { - public: - MaterialBase() {} - MaterialBase(MaterialType type) : type(type) {} - - public: - int type; - private: - int align[3]; - }; - - class MatteMaterial : public MaterialBase - { - public: - MatteMaterial (const Vec3fa& reflectance) - : MaterialBase(MATERIAL_MATTE), reflectance(reflectance) {} - - public: - Vec3fa reflectance; - }; - - class MirrorMaterial : public MaterialBase - { - public: - MirrorMaterial (const Vec3fa& reflectance) - : MaterialBase(MATERIAL_MIRROR), reflectance(reflectance) {} - - public: - Vec3fa reflectance; - }; - - class ThinDielectricMaterial : public MaterialBase - { - public: - ThinDielectricMaterial (const Vec3fa& transmission, const float eta, const float thickness) - : MaterialBase(MATERIAL_THIN_DIELECTRIC), transmission(transmission), transmissionFactor(log(transmission)*thickness), eta(eta), thickness(thickness) {} - - public: - Vec3fa transmission; - Vec3fa transmissionFactor; - float eta; - float thickness; - }; - - class OBJMaterial : public MaterialBase - { - public: - OBJMaterial () - : MaterialBase(MATERIAL_OBJ), illum(0), d(1.f), Ns(1.f), Ni(1.f), Ka(0.f), Kd(1.f), Ks(0.f), Kt(1.0f), map_d(nullptr), map_Kd(nullptr), map_Displ(nullptr) {} - - OBJMaterial (float d, const Vec3fa& Kd, const Vec3fa& Ks, const float Ns) - : MaterialBase(MATERIAL_OBJ), illum(0), d(d), Ns(Ns), Ni(1.f), Ka(0.f), Kd(Kd), Ks(Ks), Kt(1.0f), map_d(nullptr), map_Kd(nullptr), map_Displ(nullptr) {} - - OBJMaterial (float d, const Texture* map_d, const Vec3fa& Kd, const Texture* map_Kd, const Vec3fa& Ks, const Texture* map_Ks, const float Ns, const Texture* map_Ns, const Texture* map_Bump) - : MaterialBase(MATERIAL_OBJ), illum(0), d(d), Ns(Ns), Ni(1.f), Ka(0.f), Kd(Kd), Ks(Ks), Kt(1.0f), map_d(map_d), map_Kd(map_Kd), map_Displ(nullptr) {} - - ~OBJMaterial() { // FIXME: destructor never called! - } - - public: - int illum; /*< illumination model */ - float d; /*< dissolve factor, 1=opaque, 0=transparent */ - float Ns; /*< specular exponent */ - float Ni; /*< optical density for the surface (index of refraction) */ - - Vec3fa Ka; /*< ambient reflectivity */ - Vec3fa Kd; /*< diffuse reflectivity */ - Vec3fa Ks; /*< specular reflectivity */ - Vec3fa Kt; /*< transmission filter */ - - const Texture* map_d; /*< d texture */ - const Texture* map_Kd; /*< Kd texture */ - const Texture* map_Displ; /*< Displ texture */ - }; - - class MetalMaterial : public MaterialBase - { - public: - MetalMaterial (const Vec3fa& reflectance, const Vec3fa& eta, const Vec3fa& k) - : MaterialBase(MATERIAL_REFLECTIVE_METAL), reflectance(reflectance), eta(eta), k(k), roughness(0.0f) {} - - MetalMaterial (const Vec3fa& reflectance, const Vec3fa& eta, const Vec3fa& k, const float roughness) - : MaterialBase(MATERIAL_METAL), reflectance(reflectance), eta(eta), k(k), roughness(roughness) {} - - public: - Vec3fa reflectance; - Vec3fa eta; - Vec3fa k; - float roughness; - }; - - typedef MetalMaterial ReflectiveMetalMaterial; - - class VelvetMaterial : public MaterialBase - { - public: - VelvetMaterial (const Vec3fa& reflectance, const float backScattering, const Vec3fa& horizonScatteringColor, const float horizonScatteringFallOff) - : MaterialBase(MATERIAL_VELVET), reflectance(reflectance), horizonScatteringColor(horizonScatteringColor), backScattering(backScattering), horizonScatteringFallOff(horizonScatteringFallOff) {} - - public: - Vec3fa reflectance; - Vec3fa horizonScatteringColor; - float backScattering; - float horizonScatteringFallOff; - }; - - class DielectricMaterial : public MaterialBase - { - public: - DielectricMaterial (const Vec3fa& transmissionOutside, const Vec3fa& transmissionInside, const float etaOutside, const float etaInside) - : MaterialBase(MATERIAL_DIELECTRIC), transmissionOutside(transmissionOutside), transmissionInside(transmissionInside), etaOutside(etaOutside), etaInside(etaInside) {} - - public: - Vec3fa transmissionOutside; - Vec3fa transmissionInside; - float etaOutside; - float etaInside; - }; - - class MetallicPaintMaterial : public MaterialBase - { - public: - MetallicPaintMaterial (const Vec3fa& shadeColor, const Vec3fa& glitterColor, float glitterSpread, float eta) - : MaterialBase(MATERIAL_METALLIC_PAINT), shadeColor(shadeColor), glitterColor(glitterColor), glitterSpread(glitterSpread), eta(eta) {} - - public: - Vec3fa shadeColor; - Vec3fa glitterColor; - float glitterSpread; - float eta; - }; - - class HairMaterial : public MaterialBase - { - public: - HairMaterial (const Vec3fa& Kr, const Vec3fa& Kt, float nx, float ny) - : MaterialBase(MATERIAL_HAIR), Kr(Kr), Kt(Kt), nx(nx), ny(ny) {} - - public: - Vec3fa Kr; - Vec3fa Kt; - float nx; - float ny; - }; - - class Material : public MaterialBase - { - public: - Material () { for (auto& x : v) x = Vec3fa(zero); } - Material (const OBJMaterial& in) { *((OBJMaterial*)this) = in; } - OBJMaterial& obj() { return *(OBJMaterial*)this; } - - private: - Vec3fa v[7]; - }; -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/obj_loader.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/obj_loader.cpp deleted file mode 100644 index 89446a7e8c80..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/obj_loader.cpp +++ /dev/null @@ -1,524 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "obj_loader.h" -#include "texture.h" - -namespace embree -{ - /*! Three-index vertex, indexing start at 0, -1 means invalid vertex. */ - struct Vertex { - int v, vt, vn; - Vertex() {}; - Vertex(int v) : v(v), vt(v), vn(v) {}; - Vertex(int v, int vt, int vn) : v(v), vt(vt), vn(vn) {}; - }; - - struct Crease { - float w; - int a, b; - Crease() : w(0), a(-1), b(-1) {}; - Crease(float w, int a, int b) : w(w), a(a), b(b) {}; - }; - - static inline bool operator < ( const Vertex& a, const Vertex& b ) { - if (a.v != b.v) return a.v < b.v; - if (a.vn != b.vn) return a.vn < b.vn; - if (a.vt != b.vt) return a.vt < b.vt; - return false; - } - - /*! Fill space at the end of the token with 0s. */ - static inline const char* trimEnd(const char* token) { - size_t len = strlen(token); - if (len == 0) return token; - char* pe = (char*)(token + len - 1); - while ((*pe == ' ' || *pe == '\t' || *pe == '\r') && pe >= token) *pe-- = 0; - return token; - } - - /*! Determine if character is a separator. */ - static inline bool isSep(const char c) { - return (c == ' ') || (c == '\t'); - } - - /*! Parse separator. */ - static inline const char* parseSep(const char*& token) { - size_t sep = strspn(token, " \t"); - if (!sep) THROW_RUNTIME_ERROR("separator expected"); - return token+=sep; - } - - /*! Parse optional separator. */ - static inline const char* parseSepOpt(const char*& token) { - return token+=strspn(token, " \t"); - } - - /*! Read float from a string. */ - static inline float getFloat(const char*& token) { - token += strspn(token, " \t"); - float n = (float)atof(token); - token += strcspn(token, " \t\r"); - return n; - } - - /*! Read int from a string. */ - static inline int getInt(const char*& token) { - token += strspn(token, " \t"); - int n = atoi(token); - token += strcspn(token, " \t\r"); - return n; - } - - /*! Read Vec2f from a string. */ - static inline Vec2f getVec2f(const char*& token) { - float x = getFloat(token); - float y = getFloat(token); - return Vec2f(x,y); - } - - /*! Read Vec3f from a string. */ - static inline Vec3f getVec3f(const char*& token) { - float x = getFloat(token); - token += strspn(token, " \t"); - if (*token == 0) return Vec3f(x); - float y = getFloat(token); - float z = getFloat(token); - return Vec3f(x,y,z); - } - - class OBJLoader - { - public: - - /*! Constructor. */ - OBJLoader(const FileName& fileName, const bool subdivMode, const bool combineIntoSingleObject); - - /*! output model */ - Ref group; - - private: - - /*! file to load */ - FileName path; - - /*! load only quads and ignore triangles */ - bool subdivMode; - - /*! Geometry buffer. */ - avector v; - avector vn; - std::vector vt; - std::vector ec; - - std::vector > curGroup; - - /*! Material handling. */ - std::string curMaterialName; - Ref curMaterial; - std::map > material; - - private: - void loadMTL(const FileName& fileName); - int fix_v (int index); - int fix_vt(int index); - int fix_vn(int index); - void flushFaceGroup(); - Vertex getInt3(const char*& token); - uint32_t getVertex(std::map& vertexMap, Ref mesh, const Vertex& i); - }; - - OBJLoader::OBJLoader(const FileName &fileName, const bool subdivMode, const bool combineIntoSingleObject) - : group(new SceneGraph::GroupNode), path(fileName.path()), subdivMode(subdivMode) - { - /* open file */ - std::ifstream cin; - cin.open(fileName.c_str()); - if (!cin.is_open()) { - THROW_RUNTIME_ERROR("cannot open " + fileName.str()); - return; - } - - /* generate default material */ - Material objmtl; new (&objmtl) OBJMaterial; - Ref defaultMaterial = new SceneGraph::MaterialNode(objmtl); - curMaterialName = "default"; - curMaterial = defaultMaterial; - - char line[10000]; - memset(line, 0, sizeof(line)); - - while (cin.peek() != -1) - { - /* load next multiline */ - char* pline = line; - while (true) { - cin.getline(pline, sizeof(line) - (pline - line) - 16, '\n'); - ssize_t last = strlen(pline) - 1; - if (last < 0 || pline[last] != '\\') break; - pline += last; - *pline++ = ' '; - } - - const char* token = trimEnd(line + strspn(line, " \t")); - if (token[0] == 0) continue; - - /*! parse position */ - if (token[0] == 'v' && isSep(token[1])) { - v.push_back(getVec3f(token += 2)); continue; - } - - /* parse normal */ - if (token[0] == 'v' && token[1] == 'n' && isSep(token[2])) { - vn.push_back(getVec3f(token += 3)); - continue; - } - - /* parse texcoord */ - if (token[0] == 'v' && token[1] == 't' && isSep(token[2])) { vt.push_back(getVec2f(token += 3)); continue; } - - /*! parse face */ - if (token[0] == 'f' && isSep(token[1])) - { - parseSep(token += 1); - - std::vector face; - while (token[0]) { - Vertex vtx = getInt3(token); - face.push_back(vtx); - parseSepOpt(token); - } - curGroup.push_back(face); - continue; - } - - /*! parse edge crease */ - if (token[0] == 'e' && token[1] == 'c' && isSep(token[2])) - { - parseSep(token += 2); - float w = getFloat(token); - parseSepOpt(token); - int a = fix_v(getInt(token)); - parseSepOpt(token); - int b = fix_v(getInt(token)); - parseSepOpt(token); - ec.push_back(Crease(w, a, b)); - continue; - } - - /*! use material */ - if (!strncmp(token, "usemtl", 6) && isSep(token[6])) - { - if (!combineIntoSingleObject) flushFaceGroup(); - std::string name(parseSep(token += 6)); - if (material.find(name) == material.end()) { - curMaterial = defaultMaterial; - curMaterialName = "default"; - } - else { - curMaterial = material[name]; - curMaterialName = name; - } - continue; - } - - /* load material library */ - if (!strncmp(token, "mtllib", 6) && isSep(token[6])) { - loadMTL(path + std::string(parseSep(token += 6))); - continue; - } - - // ignore unknown stuff - } - flushFaceGroup(); - - cin.close(); - } - - struct ExtObjMaterial : public OBJMaterial - { - public: - - enum Type { NONE, MATTE, GLASS, METAL, METALLIC_PAINT }; - - ExtObjMaterial () - : type(NONE), roughness(0.0f), roughnessMap(nullptr), coat_eta(1.0f), coat_roughness(0.0f), coat_roughnessMap(nullptr), bump(0.0f), eta(1.4f), k(3.0f) {} - - Material select() const - { - Material material; - if (type == NONE) { - new (&material) OBJMaterial(*this); - } else if (type == MATTE) { - if (coat_eta != 1.0f) new (&material) MetallicPaintMaterial (Kd,zero,0.0f,eta.x); - else new (&material) OBJMaterial(1.0f,nullptr,Kd,map_Kd,Ks,nullptr,1.0f/(1E-6f+roughness),nullptr,nullptr); - } else if (type == GLASS) { - new (&material) ThinDielectricMaterial(Vec3fa(1.0f),eta.x,0.1f); - } else if (type == METAL) { - if (roughness == 0.0f) { - if (eta == Vec3fa(1.0f) && k == Vec3fa(0.0f)) new (&material) MirrorMaterial(Kd); - else new (&material) MetalMaterial(Kd,eta,k); - } - else new (&material) MetalMaterial(Kd,eta,k,roughness); - } else if (type == METALLIC_PAINT) { - new (&material) MetallicPaintMaterial (Kd,Ks,0.0f,coat_eta); - } - return material; - } - - public: - Type type; - float roughness; - Texture* roughnessMap; - float coat_eta; - float coat_roughness; - Texture* coat_roughnessMap; - float bump; - Vec3f eta; - Vec3f k; - }; - - /* load material file */ - void OBJLoader::loadMTL(const FileName &fileName) - { - std::ifstream cin; - cin.open(fileName.c_str()); - if (!cin.is_open()) { - std::cerr << "cannot open " << fileName.str() << std::endl; - return; - } - - char line[10000]; - memset(line, 0, sizeof(line)); - - //OBJMaterial* cur = nullptr; - std::string name; - ExtObjMaterial cur; - - while (cin.peek() != -1) - { - /* load next multiline */ - char* pline = line; - while (true) { - cin.getline(pline, sizeof(line) - (pline - line) - 16, '\n'); - ssize_t last = strlen(pline) - 1; - if (last < 0 || pline[last] != '\\') break; - pline += last; - *pline++ = ' '; - } - const char* token = trimEnd(line + strspn(line, " \t")); - - if (token[0] == 0 ) continue; // ignore empty lines - if (token[0] == '#') continue; // ignore comments - - if (!strncmp(token, "newmtl", 6)) - { - if (name != "") - material[name] = new SceneGraph::MaterialNode(cur.select()); - - parseSep(token+=6); - name = token; - new (&cur) ExtObjMaterial; - continue; - } - if (name == "") THROW_RUNTIME_ERROR("invalid material file: newmtl expected first"); - - try - { - if (!strncmp(token, "illum", 5)) { parseSep(token += 5); continue; } - - if (!strncmp(token, "d", 1)) { parseSep(token += 1); cur.d = getFloat(token); continue; } - if (!strncmp(token, "Ns", 2)) { parseSep(token += 2); cur.Ns = getFloat(token); continue; } - if (!strncmp(token, "Ni", 2)) { parseSep(token += 2); cur.Ni = getFloat(token); continue; } - - if (!strncmp(token, "map_d", 5) || !strncmp(token, "d_map", 5)) { - parseSep(token += 5); - cur.map_d = Texture::load(path + FileName(token)); - continue; - } - if (!strncmp(token, "map_Ka", 6) || !strncmp(token, "Ka_map", 6)) { continue; } - if (!strncmp(token, "map_Kd", 6) || !strncmp(token, "Kd_map", 6)) { - parseSep(token += 6); - cur.map_Kd = Texture::load(path + FileName(token)); - continue; - } - - if (!strncmp(token, "map_Ks", 6) || !strncmp(token, "Ks_map", 6)) { continue; } - if (!strncmp(token, "map_Tf", 6) || !strncmp(token, "Tf_map", 6)) { continue; } - if (!strncmp(token, "map_Displ", 9) || !strncmp(token, "Displ_map", 9)) { - parseSep(token += 9); - cur.map_Displ = Texture::load(path + FileName(token)); - continue; - } - - if (!strncmp(token, "Ka", 2)) { parseSep(token += 2); cur.Ka = getVec3f(token); continue; } - if (!strncmp(token, "Kd", 2)) { parseSep(token += 2); cur.Kd = getVec3f(token); continue; } - if (!strncmp(token, "Ks", 2)) { parseSep(token += 2); cur.Ks = getVec3f(token); continue; } - if (!strncmp(token, "Tf", 2)) { parseSep(token += 2); cur.Kt = getVec3f(token); continue; } - - /* extended OBJ */ - if (!strncmp(token, "type", 4)) { - parseSep(token += 4); std::string type = token; - if (type == "matte") cur.type = ExtObjMaterial::MATTE; - else if (type == "glass") cur.type = ExtObjMaterial::GLASS; - else if (type == "metal") cur.type = ExtObjMaterial::METAL; - else if (type == "metallicPaint") cur.type = ExtObjMaterial::METALLIC_PAINT; - } - if (!strncmp(token, "roughnessMap", 12)) { parseSep(token += 12); cur.roughnessMap = Texture::load(path + FileName(token)); } - if (!strncmp(token, "roughness", 9)) { parseSep(token += 9); cur.roughness = getFloat(token); } - if (!strncmp(token, "colorMap", 8)) { parseSep(token += 8); cur.map_Kd = Texture::load(path + FileName(token)); } - if (!strncmp(token, "color", 5)) { parseSep(token += 5); cur.Kd = getVec3f(token); } - if (!strncmp(token, "coat.color", 10)) { parseSep(token += 10); cur.Kd = getVec3f(token); } - if (!strncmp(token, "coat.eta", 8)) { parseSep(token += 8); cur.coat_eta = getFloat(token); } - if (!strncmp(token, "coat.roughnessMap",17)) { parseSep(token += 17); cur.coat_roughnessMap = Texture::load(path + FileName(token)); } - if (!strncmp(token, "coat.roughness", 14)) { parseSep(token += 14); cur.coat_roughness = getFloat(token); } - if (!strncmp(token, "bumpMap", 7)) { parseSep(token += 7); cur.map_Displ = Texture::load(path + FileName(token)); } - if (!strncmp(token, "bump", 4)) { parseSep(token += 4); cur.bump = getFloat(token); } - if (!strncmp(token, "eta", 3)) { parseSep(token += 3); cur.eta = getVec3f(token); } - if (!strncmp(token, "k", 1)) { parseSep(token += 1); cur.k = getVec3f(token); } - } - catch (const std::runtime_error e) { - std::cerr << "Error: " << e.what() << std::endl; - } - } - - if (name != "") - material[name] = new SceneGraph::MaterialNode(cur.select()); - - cin.close(); - } - - /*! handles relative indices and starts indexing from 0 */ - int OBJLoader::fix_v (int index) { return (index > 0 ? index - 1 : (index == 0 ? 0 : (int) v .size() + index)); } - int OBJLoader::fix_vt(int index) { return (index > 0 ? index - 1 : (index == 0 ? 0 : (int) vt.size() + index)); } - int OBJLoader::fix_vn(int index) { return (index > 0 ? index - 1 : (index == 0 ? 0 : (int) vn.size() + index)); } - - /*! Parse differently formated triplets like: n0, n0/n1/n2, n0//n2, n0/n1. */ - /*! All indices are converted to C-style (from 0). Missing entries are assigned -1. */ - Vertex OBJLoader::getInt3(const char*& token) - { - Vertex v(-1); - v.v = fix_v(atoi(token)); - token += strcspn(token, "/ \t\r"); - if (token[0] != '/') return(v); - token++; - - // it is i//n - if (token[0] == '/') { - token++; - v.vn = fix_vn(atoi(token)); - token += strcspn(token, " \t\r"); - return(v); - } - - // it is i/t/n or i/t - v.vt = fix_vt(atoi(token)); - token += strcspn(token, "/ \t\r"); - if (token[0] != '/') return(v); - token++; - - // it is i/t/n - v.vn = fix_vn(atoi(token)); - token += strcspn(token, " \t\r"); - return(v); - } - - uint32_t OBJLoader::getVertex(std::map& vertexMap, Ref mesh, const Vertex& i) - { - const std::map::iterator& entry = vertexMap.find(i); - if (entry != vertexMap.end()) return(entry->second); - mesh->positions[0].push_back(Vec3fa(v[i.v].x,v[i.v].y,v[i.v].z)); - if (i.vn >= 0) { - while (mesh->normals.size() < mesh->positions[0].size()) mesh->normals.push_back(zero); // some vertices might not had a normal - mesh->normals[mesh->positions[0].size()-1] = vn[i.vn]; - } - if (i.vt >= 0) { - while (mesh->texcoords.size() < mesh->positions[0].size()) mesh->texcoords.push_back(zero); // some vertices might not had a texture coordinate - mesh->texcoords[mesh->positions[0].size()-1] = vt[i.vt]; - } - return(vertexMap[i] = int(mesh->positions[0].size()) - 1); - } - - /*! end current facegroup and append to mesh */ - void OBJLoader::flushFaceGroup() - { - if (curGroup.empty()) return; - - if (subdivMode) - { - Ref mesh = new SceneGraph::SubdivMeshNode(curMaterial,1); - group->add(mesh.cast()); - - for (size_t i=0; ipositions[0].push_back(v[i]); - for (size_t i=0; inormals .push_back(vn[i]); - for (size_t i=0; itexcoords.push_back(vt[i]); - - for (size_t i=0; iedge_creases.push_back(Vec2i(ec[i].a, ec[i].b)); - mesh->edge_crease_weights.push_back(ec[i].w); - } - - for (size_t j=0; j& face = curGroup[j]; - mesh->verticesPerFace.push_back(int(face.size())); - for (size_t i=0; iposition_indices.push_back(face[i].v); - } - mesh->verify(); - } - else - { - Ref mesh = new SceneGraph::TriangleMeshNode(curMaterial,1); - group->add(mesh.cast()); - // merge three indices into one - std::map vertexMap; - for (size_t j=0; j& face = curGroup[j]; - - /* triangulate the face with a triangle fan */ - Vertex i0 = face[0], i1 = Vertex(-1), i2 = face[1]; - for (size_t k=2; k < face.size(); k++) - { - i1 = i2; i2 = face[k]; - uint32_t v0,v1,v2; - v0 = getVertex(vertexMap, mesh, i0); - v1 = getVertex(vertexMap, mesh, i1); - v2 = getVertex(vertexMap, mesh, i2); - assert(v0 < mesh->numVertices()); - assert(v1 < mesh->numVertices()); - assert(v2 < mesh->numVertices()); - mesh->triangles.push_back(SceneGraph::TriangleMeshNode::Triangle(v0,v1,v2)); - } - } - /* there may be vertices without normals or texture coordinates, thus we have to make these arrays the same size here */ - if (mesh->normals .size()) while (mesh->normals .size() < mesh->numVertices()) mesh->normals .push_back(zero); - if (mesh->texcoords.size()) while (mesh->texcoords.size() < mesh->numVertices()) mesh->texcoords.push_back(zero); - mesh->verify(); - } - curGroup.clear(); - ec.clear(); - } - - Ref loadOBJ(const FileName& fileName, const bool subdivMode, const bool combineIntoSingleObject) { - OBJLoader loader(fileName,subdivMode,combineIntoSingleObject); - return loader.group.cast(); - } -} - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/obj_loader.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/obj_loader.h deleted file mode 100644 index 0d7169780d9c..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/obj_loader.h +++ /dev/null @@ -1,26 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "scenegraph.h" - -namespace embree -{ - Ref loadOBJ(const FileName& fileName, - const bool subdivMode = false, - const bool combineIntoSingleObject = false); -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/ply_loader.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/ply_loader.cpp deleted file mode 100644 index 0f152b40eb6e..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/ply_loader.cpp +++ /dev/null @@ -1,346 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "ply_loader.h" -#include - -namespace embree -{ - namespace SceneGraph - { - /*! PLY type */ - struct Type { - enum Tag { PTY_CHAR, PTY_UCHAR, PTY_SHORT, PTY_USHORT, PTY_INT, PTY_UINT, PTY_FLOAT, PTY_DOUBLE, PTY_LIST, PTY_NONE } ty, index, data; - Type() : ty(PTY_NONE), index(PTY_NONE), data(PTY_NONE) {} - Type(Tag ty) : ty(ty), index(PTY_NONE), data(PTY_NONE) {} - Type(Tag ty, Tag index, Tag data) : ty(ty), index(index), data(data) {} - }; - - /*! an element stored in the PLY file, such as vertex, face, etc. */ - struct Element { - std::string name; - size_t size; /// number of data items of the element - std::vector properties; /// list of all properties of the element (e.g. x, y, z) (not strictly necessary) - std::map type; /// mapping of property name to type - std::map > data; /// data array properties (all represented as floats) - std::map > > list; /// list properties (integer lists supported only) - }; - - /*! mesh structure that reflects the PLY file format */ - struct Mesh { - std::vector order; /// order of all elements in file (not strictly necessary) - std::map elements; /// all elements of the file, e.g. vertex, face, ... - }; - - /* returns the size of a type in bytes */ - size_t sizeOfType(Type::Tag ty) - { - switch (ty) { - case Type::PTY_CHAR : return 1; - case Type::PTY_UCHAR : return 1; - case Type::PTY_SHORT : return 2; - case Type::PTY_USHORT : return 2; - case Type::PTY_INT : return 4; - case Type::PTY_UINT : return 4; - case Type::PTY_FLOAT : return 4; - case Type::PTY_DOUBLE : return 8; - default : throw std::runtime_error("invalid type"); - } - } - - /* compute the type of a string */ - Type::Tag typeTagOfString(const std::string& ty) { - if (ty == "char") return Type::PTY_CHAR; - if (ty == "int8") return Type::PTY_CHAR; - if (ty == "uchar") return Type::PTY_UCHAR; - if (ty == "uint8") return Type::PTY_UCHAR; - if (ty == "short") return Type::PTY_SHORT; - if (ty == "int16") return Type::PTY_SHORT; - if (ty == "ushort") return Type::PTY_USHORT; - if (ty == "uint16") return Type::PTY_USHORT; - if (ty == "int") return Type::PTY_INT; - if (ty == "int32") return Type::PTY_INT; - if (ty == "uint") return Type::PTY_UINT; - if (ty == "uint32") return Type::PTY_UINT; - if (ty == "float") return Type::PTY_FLOAT; - if (ty == "float32") return Type::PTY_FLOAT; - if (ty == "double") return Type::PTY_DOUBLE; - throw std::runtime_error("invalid type " + ty); - return Type::PTY_NONE; - } - - /* compute the type of a string */ - std::string stringOfTypeTag(Type::Tag ty) { - if (ty == Type::PTY_CHAR) return "char"; - if (ty == Type::PTY_UCHAR) return "uchar"; - if (ty == Type::PTY_SHORT) return "short"; - if (ty == Type::PTY_USHORT) return "ushort"; - if (ty == Type::PTY_INT) return "int"; - if (ty == Type::PTY_UINT) return "uint"; - if (ty == Type::PTY_FLOAT) return "float"; - if (ty == Type::PTY_DOUBLE) return "double"; - if (ty == Type::PTY_LIST) return "list"; - throw std::runtime_error("invalid type"); - return ""; - } - - /* compute the type of a string */ - std::string stringOfType(Type ty) { - if (ty.ty == Type::PTY_LIST) return "list " + stringOfTypeTag(ty.index) + " " + stringOfTypeTag(ty.data); - else return stringOfTypeTag(ty.ty); - } - - /* PLY parser class */ - struct PlyParser - { - std::fstream fs; - Mesh mesh; - Ref scene; - - /* storage format of data in file */ - enum Format { ASCII, BINARY_BIG_ENDIAN, BINARY_LITTLE_ENDIAN } format; - - /* constructor parses the input stream */ - PlyParser(const FileName& fileName) : format(ASCII) - { - /* open file */ - fs.open (fileName.c_str(), std::fstream::in | std::fstream::binary); - if (!fs.is_open()) throw std::runtime_error("cannot open file : " + fileName.str()); - - /* check for file signature */ - std::string signature; getline(fs,signature); - if (signature != "ply") throw std::runtime_error("invalid PLY file signature: " + signature); - - /* read header */ - std::list header; - while (true) { - std::string line; getline(fs,line); - if (line == "end_header") break; - if (line.find_first_of('#') == 0) continue; - if (line == "") continue; - header.push_back(line); - } - - /* parse header */ - parseHeader(header); - - /* now parse all elements */ - for (std::vector::iterator i = mesh.order.begin(); i!=mesh.order.end(); i++) - parseElementData(mesh.elements[*i]); - - /* create triangle mesh */ - scene = import(); - } - - /* parse the PLY header */ - void parseHeader(std::list& header) - { - while (!header.empty()) - { - std::stringstream line(header.front()); - header.pop_front(); - - std::string tag; line >> tag; - - /* ignore comments */ - if (tag == "comment") { - } - - /* parse format */ - else if (tag == "format") - { - std::string fmt; line >> fmt; - if (fmt == "ascii") format = ASCII; - else if (fmt == "binary_big_endian") format = BINARY_BIG_ENDIAN; - else if (fmt == "binary_little_endian") format = BINARY_LITTLE_ENDIAN; - else throw std::runtime_error("invalid PLY file format: " + fmt); - std::string version; line >> version; - if (version != "1.0") throw std::runtime_error("invalid PLY file version: " + version); - } - - /* parse end of header tag */ - else if (tag == "end_header") - break; - - /* parse elements */ - else if (tag == "element") parseElementDescr(line,header); - - /* report unknown tags */ - else throw std::runtime_error("unknown tag in PLY file: " + tag); - } - } - - /* parses a PLY element description */ - void parseElementDescr(std::stringstream& cin, std::list& header) - { - Element elt; - std::string name; cin >> name; - size_t num; cin >> num; - mesh.order.push_back(name); - elt.name = name; - elt.size = num; - - /* parse all properties */ - while (!header.empty()) - { - std::stringstream line(header.front()); - std::string tag; line >> tag; - if (tag != "property") break; - header.pop_front(); - - Type ty = parseType(line); - std::string name; line >> name; - elt.type[name] = ty; - elt.properties.push_back(name); - } - - mesh.elements[name] = elt; - } - - /* parses a PLY type */ - Type parseType(std::stringstream& cin) - { - std::string ty; cin >> ty; - if (ty == "list") { - std::string ty0; cin >> ty0; - std::string ty1; cin >> ty1; - return Type(Type::PTY_LIST,typeTagOfString(ty0),typeTagOfString(ty1)); - } else return Type(typeTagOfString(ty)); - } - - /* parses data of a PLY element */ - void parseElementData(Element& elt) - { - /* allocate data for all properties */ - for (std::vector::iterator i=elt.properties.begin(); i!=elt.properties.end(); i++) { - if (elt.type[*i].ty == Type::PTY_LIST) elt.list[*i] = std::vector >(); - else elt.data[*i] = std::vector(); - } - - /* parse all elements */ - for (size_t e=0; e::iterator i=elt.properties.begin(); i!=elt.properties.end(); i++) { - Type ty = elt.type[*i]; - if (ty.ty == Type::PTY_LIST) loadPropertyList(elt.list[*i],ty.index,ty.data); - else loadPropertyData(elt.data[*i],ty.ty); - } - } - } - - /* load bytes from file and take care of little and big endian encoding */ - void readBytes(void* dst, int num) { - if (format == BINARY_LITTLE_ENDIAN) fs.read((char*)dst,num); - else if (format == BINARY_BIG_ENDIAN) for (int i=0; i> i; return i; } - float read_ascii_float() { float f; fs >> f; return f; } - signed char read_char () { if (format == ASCII) return read_ascii_int(); signed char r = 0; readBytes(&r,1); return r; } - unsigned char read_uchar () { if (format == ASCII) return read_ascii_int(); unsigned char r = 0; readBytes(&r,1); return r; } - signed short read_short () { if (format == ASCII) return read_ascii_int(); signed short r = 0; readBytes(&r,2); return r; } - unsigned short read_ushort() { if (format == ASCII) return read_ascii_int(); unsigned short r = 0; readBytes(&r,2); return r; } - signed int read_int () { if (format == ASCII) return read_ascii_int(); signed int r = 0; readBytes(&r,4); return r; } - unsigned int read_uint () { if (format == ASCII) return read_ascii_int(); unsigned int r = 0; readBytes(&r,4); return r; } - float read_float () { if (format == ASCII) return read_ascii_float(); float r = 0; readBytes(&r,4); return r; } - double read_double() { if (format == ASCII) return read_ascii_float(); double r = 0; readBytes(&r,8); return r; } - - /* load an integer type */ - size_t loadInteger(Type::Tag ty) - { - switch (ty) { - case Type::PTY_CHAR : return read_char(); break; - case Type::PTY_UCHAR : return read_uchar(); break; - case Type::PTY_SHORT : return read_short(); break; - case Type::PTY_USHORT : return read_ushort(); break; - case Type::PTY_INT : return read_int(); break; - case Type::PTY_UINT : return read_uint(); break; - default : throw std::runtime_error("invalid type"); return 0; - } - } - - /* load a list */ - void loadPropertyList(std::vector >& vec,Type::Tag index_ty,Type::Tag data_ty) - { - std::vector lst; - size_t num = loadInteger(index_ty); - for (size_t i=0; i& vec, Type::Tag ty) - { - switch (ty) { - case Type::PTY_CHAR : vec.push_back(float(read_char())); break; - case Type::PTY_UCHAR : vec.push_back(float(read_uchar())); break; - case Type::PTY_SHORT : vec.push_back(float(read_short())); break; - case Type::PTY_USHORT : vec.push_back(float(read_ushort())); break; - case Type::PTY_INT : vec.push_back(float(read_int())); break; - case Type::PTY_UINT : vec.push_back(float(read_uint())); break; - case Type::PTY_FLOAT : vec.push_back(float(read_float())); break; - case Type::PTY_DOUBLE : vec.push_back(float(read_double())); break; - default : throw std::runtime_error("invalid type"); - } - } - - Ref import() - { - Material objmtl; new (&objmtl) OBJMaterial; - Ref material = new SceneGraph::MaterialNode(objmtl); - Ref mesh_o = new SceneGraph::TriangleMeshNode(material,1); - - /* convert all vertices */ - const Element& vertices = mesh.elements.at("vertex"); - const std::vector& posx = vertices.data.at("x"); - const std::vector& posy = vertices.data.at("y"); - const std::vector& posz = vertices.data.at("z"); - - mesh_o->positions[0].resize(vertices.size); - for (size_t i=0; ipositions[0][i].x = posx[i]; - mesh_o->positions[0][i].y = posy[i]; - mesh_o->positions[0][i].z = posz[i]; - } - - /* convert all faces */ - const Element& faces = mesh.elements.at("face"); - const std::vector >& polygons = faces.list.at("vertex_indices"); - - for (size_t j=0; j& face = polygons[j]; - if (face.size() < 3) continue; - - /* triangulate the face with a triangle fan */ - size_t i0 = face[0], i1 = 0, i2 = face[1]; - for (size_t k=2; ktriangles.push_back(SceneGraph::TriangleMeshNode::Triangle((unsigned int)i0, (unsigned int)i1, (unsigned int)i2)); - } - } - return mesh_o.dynamicCast(); - } - }; - - Ref loadPLY(const FileName& fileName) { - return PlyParser(fileName).scene; - } - } -} - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/ply_loader.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/ply_loader.h deleted file mode 100644 index d475d640cdca..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/ply_loader.h +++ /dev/null @@ -1,27 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "scenegraph.h" - -namespace embree -{ - namespace SceneGraph - { - Ref loadPLY(const FileName& fileName); - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/scenegraph.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/scenegraph.cpp deleted file mode 100644 index 4731e1adad32..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/scenegraph.cpp +++ /dev/null @@ -1,1162 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "scenegraph.h" -#include "xml_loader.h" -#include "xml_writer.h" -#include "obj_loader.h" -#include "ply_loader.h" -#include "corona_loader.h" - -namespace embree -{ - Ref SceneGraph::load(const FileName& filename, const bool singleObject) - { - if (toLowerCase(filename.ext()) == std::string("obj" )) return loadOBJ(filename, false, singleObject); - else if (toLowerCase(filename.ext()) == std::string("ply" )) return loadPLY(filename); - else if (toLowerCase(filename.ext()) == std::string("xml" )) return loadXML(filename); - else if (toLowerCase(filename.ext()) == std::string("scn" )) return loadCorona(filename); - else throw std::runtime_error("unknown scene format: " + filename.ext()); - } - - void SceneGraph::store(Ref root, const FileName& filename, bool embedTextures) - { - if (toLowerCase(filename.ext()) == std::string("xml")) { - storeXML(root,filename,embedTextures); - } - else - throw std::runtime_error("unknown scene format: " + filename.ext()); - } - - void SceneGraph::Node::resetNode(std::set>& done) - { - indegree = 0; - closed = true; - } - - void SceneGraph::TransformNode::resetNode(std::set>& done) - { - if (done.find(this) != done.end()) return; - else done.insert(this); - indegree = 0; - closed = false; - child->resetNode(done); - } - - void SceneGraph::GroupNode::resetNode(std::set>& done) - { - if (done.find(this) != done.end()) return; - else done.insert(this); - indegree = 0; - closed = false; - for (auto& c : children) - c->resetNode(done); - } - - void SceneGraph::Node::calculateInDegree() { - indegree++; - } - - void SceneGraph::TransformNode::calculateInDegree() - { - indegree++; - if (indegree == 1) { - child->calculateInDegree(); - if (spaces.size() > 1) child->calculateInDegree(); // break instance up when motion blur is used - } - } - - void SceneGraph::GroupNode::calculateInDegree() - { - indegree++; - if (indegree == 1) { - for (auto& c : children) - c->calculateInDegree(); - } - } - - bool SceneGraph::Node::calculateClosed() - { - assert(indegree); - closed = true; - return closed && (indegree == 1); - } - - bool SceneGraph::TransformNode::calculateClosed() - { - assert(indegree); - closed = child->calculateClosed(); - return closed && (indegree == 1); - } - - bool SceneGraph::GroupNode::calculateClosed() - { - assert(indegree); - closed = true; - for (auto c : children) - closed &= c->calculateClosed(); - return closed && (indegree == 1); - } - - void SceneGraph::TriangleMeshNode::verify() const - { - const size_t N = numVertices(); - for (const auto& p : positions) - if (p.size() != N) - THROW_RUNTIME_ERROR("incompatible vertex array sizes"); - if (normals.size() && normals.size() != N) THROW_RUNTIME_ERROR("incompatible vertex array sizes"); - if (texcoords.size() && texcoords.size() != N) THROW_RUNTIME_ERROR("incompatible vertex array sizes"); - for (auto tri : triangles) { - if (size_t(tri.v0) >= N || size_t(tri.v1) >= N || size_t(tri.v2) >= N) - THROW_RUNTIME_ERROR("invalid triangle"); - } - } - - void SceneGraph::QuadMeshNode::verify() const - { - const size_t N = numVertices(); - for (const auto& p : positions) - if (p.size() != N) - THROW_RUNTIME_ERROR("incompatible vertex array sizes"); - if (normals.size() && normals.size() != N) THROW_RUNTIME_ERROR("incompatible vertex array sizes"); - if (texcoords.size() && texcoords.size() != N) THROW_RUNTIME_ERROR("incompatible vertex array sizes"); - for (auto quad : quads) { - if (size_t(quad.v0) >= N || size_t(quad.v1) >= N || size_t(quad.v2) >= N || size_t(quad.v3) >= N) - THROW_RUNTIME_ERROR("invalid quad"); - } - } - - void SceneGraph::SubdivMeshNode::verify() const - { - const size_t N = numPositions(); - for (const auto& p : positions) - if (p.size() != N) - THROW_RUNTIME_ERROR("incompatible position array sizes"); - for (auto i : position_indices) - if (size_t(i) >= N) THROW_RUNTIME_ERROR("invalid position index array"); - for (auto i : normal_indices) - if (size_t(i) >= normals.size()) THROW_RUNTIME_ERROR("invalid normal index array"); - for (auto i : texcoord_indices) - if (size_t(i) >= texcoords.size()) THROW_RUNTIME_ERROR("invalid texcoord index array"); - for (auto i : holes) - if (size_t(i) >= verticesPerFace.size()) THROW_RUNTIME_ERROR("invalid hole index array"); - for (auto crease : edge_creases) - if (max(size_t(crease.x),size_t(crease.y)) >= N) THROW_RUNTIME_ERROR("invalid edge crease array"); - if (edge_crease_weights.size() != edge_creases.size()) - THROW_RUNTIME_ERROR("invalid edge crease weight array"); - for (auto crease : vertex_creases) - if (size_t(crease) >= N) THROW_RUNTIME_ERROR("invalid vertex crease array"); - if (vertex_crease_weights.size() != vertex_creases.size()) - THROW_RUNTIME_ERROR("invalid vertex crease weight array"); - } - - void SceneGraph::LineSegmentsNode::verify() const - { - const size_t N = numVertices(); - for (const auto& p : positions) - if (p.size() != N) - THROW_RUNTIME_ERROR("incompatible vertex array sizes"); - for (auto i : indices) - if (size_t(i) >= N) - THROW_RUNTIME_ERROR("invalid line segment"); - } - - void SceneGraph::HairSetNode::verify() const - { - const size_t N = numVertices(); - for (const auto& p : positions) - if (p.size() != N) - THROW_RUNTIME_ERROR("incompatible vertex array sizes"); - for (auto hair : hairs) - if (size_t(hair.vertex) >= N) - THROW_RUNTIME_ERROR("invalid hair"); - } - - void SceneGraph::extend_animation(Ref node0, Ref node1) - { - if (Ref xfmNode0 = node0.dynamicCast()) - { - if (Ref xfmNode1 = node1.dynamicCast()) - { - xfmNode0->spaces.add(xfmNode1->spaces); - extend_animation(xfmNode0->child, xfmNode1->child); - } - else THROW_RUNTIME_ERROR("incompatible scene graph"); - } - else if (Ref groupNode0 = node0.dynamicCast()) - { - if (Ref groupNode1 = node1.dynamicCast()) - { - if (groupNode0->children.size() != groupNode1->children.size()) - THROW_RUNTIME_ERROR("incompatible scene graph"); - - for (size_t i=0; ichildren.size(); i++) - extend_animation(groupNode0->children[i],groupNode1->children[i]); - } - else THROW_RUNTIME_ERROR("incompatible scene graph"); - } - else if (Ref mesh0 = node0.dynamicCast()) - { - if (Ref mesh1 = node1.dynamicCast()) - { - if (mesh0->numVertices() != mesh1->numVertices()) - THROW_RUNTIME_ERROR("incompatible scene graph"); - - for (auto& p : mesh1->positions) - mesh0->positions.push_back(std::move(p)); - } - else THROW_RUNTIME_ERROR("incompatible scene graph"); - } - else if (Ref mesh0 = node0.dynamicCast()) - { - if (Ref mesh1 = node1.dynamicCast()) - { - if (mesh0->numVertices() != mesh1->numVertices()) - THROW_RUNTIME_ERROR("incompatible scene graph"); - - for (auto& p : mesh1->positions) - mesh0->positions.push_back(std::move(p)); - } - else THROW_RUNTIME_ERROR("incompatible scene graph"); - } - else if (Ref mesh0 = node0.dynamicCast()) - { - if (Ref mesh1 = node1.dynamicCast()) - { - if (mesh0->numVertices() != mesh1->numVertices()) - THROW_RUNTIME_ERROR("incompatible scene graph"); - - for (auto& p : mesh1->positions) - mesh0->positions.push_back(std::move(p)); - } - else THROW_RUNTIME_ERROR("incompatible scene graph"); - } - else if (Ref mesh0 = node0.dynamicCast()) - { - if (Ref mesh1 = node1.dynamicCast()) - { - if (mesh0->numPositions() != mesh1->numPositions()) - THROW_RUNTIME_ERROR("incompatible scene graph"); - if (mesh0->verticesPerFace != mesh1->verticesPerFace) - THROW_RUNTIME_ERROR("incompatible scene graph"); - - for (auto& p : mesh1->positions) - mesh0->positions.push_back(std::move(p)); - } - else THROW_RUNTIME_ERROR("incompatible scene graph"); - } - } - - void SceneGraph::optimize_animation(Ref node) - { - if (Ref xfmNode = node.dynamicCast()) - optimize_animation(xfmNode->child); - - else if (Ref groupNode = node.dynamicCast()) - { - for (const auto& child : groupNode->children) - optimize_animation(child); - } - else if (Ref mesh = node.dynamicCast()) - { - bool equal = true; - for (size_t i=1; inumTimeSteps(); i++) - equal &= mesh->positions[0] == mesh->positions[i]; - - if (equal) - mesh->positions.resize(1); - } - else if (Ref mesh = node.dynamicCast()) - { - bool equal = true; - for (size_t i=1; inumTimeSteps(); i++) - equal &= mesh->positions[0] == mesh->positions[i]; - - if (equal) - mesh->positions.resize(1); - } - else if (Ref mesh = node.dynamicCast()) - { - bool equal = true; - for (size_t i=1; inumTimeSteps(); i++) - equal &= mesh->positions[0] == mesh->positions[i]; - - if (equal) - mesh->positions.resize(1); - } - else if (Ref mesh = node.dynamicCast()) - { - bool equal = true; - for (size_t i=1; inumTimeSteps(); i++) - equal &= mesh->positions[0] == mesh->positions[i]; - - if (equal) - mesh->positions.resize(1); - } - } - - void SceneGraph::set_motion_vector(Ref node, const Vec3fa& dP) - { - if (Ref xfmNode = node.dynamicCast()) { - set_motion_vector(xfmNode->child, dP); - } - else if (Ref groupNode = node.dynamicCast()) - { - for (size_t i=0; ichildren.size(); i++) - set_motion_vector(groupNode->children[i],dP); - } - else if (Ref mesh = node.dynamicCast()) - { - avector positions1; - for (auto P : mesh->positions.back()) - positions1.push_back(P+dP); - mesh->positions.push_back(std::move(positions1)); - } - else if (Ref mesh = node.dynamicCast()) - { - avector positions1; - for (auto P : mesh->positions.back()) - positions1.push_back(P+dP); - mesh->positions.push_back(std::move(positions1)); - } - else if (Ref mesh = node.dynamicCast()) - { - avector positions1; - for (auto P : mesh->positions.back()) - positions1.push_back(P+dP); - mesh->positions.push_back(std::move(positions1)); - } - else if (Ref mesh = node.dynamicCast()) - { - avector positions1; - for (auto P : mesh->positions.back()) - positions1.push_back(P+dP); - mesh->positions.push_back(std::move(positions1)); - } - else if (Ref mesh = node.dynamicCast()) - { - avector positions1; - for (auto P : mesh->positions.back()) - positions1.push_back(P+dP); - mesh->positions.push_back(std::move(positions1)); - } - } - - void SceneGraph::set_motion_vector(Ref node, const avector& motion_vector) - { - if (Ref xfmNode = node.dynamicCast()) { - set_motion_vector(xfmNode->child,motion_vector); - } - else if (Ref groupNode = node.dynamicCast()) - { - for (size_t i=0; ichildren.size(); i++) - set_motion_vector(groupNode->children[i],motion_vector); - } - else if (Ref mesh = node.dynamicCast()) - { - avector positions = std::move(mesh->positions[0]); - mesh->positions.clear(); - for (size_t t=0; t tpositions(positions.size()); - for (size_t i=0; ipositions.push_back(std::move(tpositions)); - } - } - else if (Ref mesh = node.dynamicCast()) - { - avector positions = std::move(mesh->positions[0]); - mesh->positions.clear(); - for (size_t t=0; t tpositions(positions.size()); - for (size_t i=0; ipositions.push_back(std::move(tpositions)); - } - } - else if (Ref mesh = node.dynamicCast()) - { - avector positions = std::move(mesh->positions[0]); - mesh->positions.clear(); - for (size_t t=0; t tpositions(positions.size()); - for (size_t i=0; ipositions.push_back(std::move(tpositions)); - } - } - else if (Ref mesh = node.dynamicCast()) - { - avector positions = std::move(mesh->positions[0]); - mesh->positions.clear(); - for (size_t t=0; t tpositions(positions.size()); - for (size_t i=0; ipositions.push_back(std::move(tpositions)); - } - } - else if (Ref mesh = node.dynamicCast()) - { - avector positions = std::move(mesh->positions[0]); - mesh->positions.clear(); - for (size_t t=0; t tpositions(positions.size()); - for (size_t i=0; ipositions.push_back(std::move(tpositions)); - } - } - } - - void SceneGraph::resize_randomly(RandomSampler& sampler, Ref node, const size_t N) - { - if (Ref xfmNode = node.dynamicCast()) { - resize_randomly(sampler,xfmNode->child, N); - } - else if (Ref groupNode = node.dynamicCast()) - { - for (size_t i=0; ichildren.size(); i++) - resize_randomly(sampler,groupNode->children[i],N); - } - else if (Ref mesh = node.dynamicCast()) - { - if (!mesh->triangles.size()) return; - for (size_t i=0; itriangles.size(),N)); - if (i < mesh->triangles.size()) std::swap(mesh->triangles[i],mesh->triangles[j]); - else mesh->triangles.push_back(mesh->triangles[j]); - } - } - else if (Ref mesh = node.dynamicCast()) - { - if (!mesh->quads.size()) return; - for (size_t i=0; iquads.size(),N)); - if (i < mesh->quads.size()) std::swap(mesh->quads[i],mesh->quads[j]); - else mesh->quads.push_back(mesh->quads[j]); - } - } - else if (Ref mesh = node.dynamicCast()) - { - if (!mesh->hairs.size()) return; - for (size_t i=0; ihairs.size(),N)); - if (i < mesh->hairs.size()) std::swap(mesh->hairs[i],mesh->hairs[j]); - else mesh->hairs.push_back(mesh->hairs[j]); - } - } - else if (Ref mesh = node.dynamicCast()) - { - if (mesh->verticesPerFace.size() <= N) return; - mesh->verticesPerFace.resize(N); - } - } - - std::pair quad_index2(int p, int a0, int a1, int b0, int b1) - { - if (b0 == a0) return std::make_pair(p-1,b1); - else if (b0 == a1) return std::make_pair(p+0,b1); - else if (b1 == a0) return std::make_pair(p-1,b0); - else if (b1 == a1) return std::make_pair(p+0,b0); - else return std::make_pair(0,-1); - } - - std::pair quad_index3(int a0, int a1, int a2, int b0, int b1, int b2) - { - if (b0 == a0) return quad_index2(0,a2,a1,b1,b2); - else if (b0 == a1) return quad_index2(1,a0,a2,b1,b2); - else if (b0 == a2) return quad_index2(2,a1,a0,b1,b2); - else if (b1 == a0) return quad_index2(0,a2,a1,b0,b2); - else if (b1 == a1) return quad_index2(1,a0,a2,b0,b2); - else if (b1 == a2) return quad_index2(2,a1,a0,b0,b2); - else if (b2 == a0) return quad_index2(0,a2,a1,b0,b1); - else if (b2 == a1) return quad_index2(1,a0,a2,b0,b1); - else if (b2 == a2) return quad_index2(2,a1,a0,b0,b1); - else return std::make_pair(0,-1); - } - - Ref SceneGraph::convert_triangles_to_quads(Ref node) - { - if (Ref xfmNode = node.dynamicCast()) { - xfmNode->child = convert_triangles_to_quads(xfmNode->child); - } - else if (Ref groupNode = node.dynamicCast()) - { - for (size_t i=0; ichildren.size(); i++) - groupNode->children[i] = convert_triangles_to_quads(groupNode->children[i]); - } - else if (Ref tmesh = node.dynamicCast()) - { - SceneGraph::QuadMeshNode* qmesh = new SceneGraph::QuadMeshNode(tmesh->material); - - for (auto& p : tmesh->positions) - qmesh->positions.push_back(p); - - qmesh->normals = tmesh->normals; - qmesh->texcoords = tmesh->texcoords; - - for (size_t i=0; itriangles.size(); i++) - { - const int a0 = tmesh->triangles[i+0].v0; - const int a1 = tmesh->triangles[i+0].v1; - const int a2 = tmesh->triangles[i+0].v2; - if (i+1 == tmesh->triangles.size()) { - qmesh->quads.push_back(SceneGraph::QuadMeshNode::Quad(a0,a1,a2,a2)); - continue; - } - - const int b0 = tmesh->triangles[i+1].v0; - const int b1 = tmesh->triangles[i+1].v1; - const int b2 = tmesh->triangles[i+1].v2; - const std::pair q = quad_index3(a0,a1,a2,b0,b1,b2); - const int a3 = q.second; - if (a3 == -1) { - qmesh->quads.push_back(SceneGraph::QuadMeshNode::Quad(a0,a1,a2,a2)); - continue; - } - - if (q.first == -1) qmesh->quads.push_back(SceneGraph::QuadMeshNode::Quad(a1,a2,a3,a0)); - else if (q.first == 0) qmesh->quads.push_back(SceneGraph::QuadMeshNode::Quad(a3,a1,a2,a0)); - else if (q.first == 1) qmesh->quads.push_back(SceneGraph::QuadMeshNode::Quad(a0,a1,a3,a2)); - else if (q.first == 2) qmesh->quads.push_back(SceneGraph::QuadMeshNode::Quad(a1,a2,a3,a0)); - i++; - } - return qmesh; - } - return node; - } - - Ref SceneGraph::convert_quads_to_subdivs(Ref node) - { - if (Ref xfmNode = node.dynamicCast()) { - xfmNode->child = convert_quads_to_subdivs(xfmNode->child); - } - else if (Ref groupNode = node.dynamicCast()) - { - for (size_t i=0; ichildren.size(); i++) - groupNode->children[i] = convert_quads_to_subdivs(groupNode->children[i]); - } - else if (Ref tmesh = node.dynamicCast()) - { - SceneGraph::SubdivMeshNode* smesh = new SceneGraph::SubdivMeshNode(tmesh->material); - - for (auto& p : tmesh->positions) - smesh->positions.push_back(p); - - for (size_t i=0; iquads.size(); i++) { - smesh->position_indices.push_back(tmesh->quads[i].v0); - smesh->position_indices.push_back(tmesh->quads[i].v1); - smesh->position_indices.push_back(tmesh->quads[i].v2); - if (tmesh->quads[i].v2 != tmesh->quads[i].v3) - smesh->position_indices.push_back(tmesh->quads[i].v3); - } - - smesh->normals = tmesh->normals; - if (smesh->normals.size()) - smesh->normal_indices = smesh->position_indices; - - smesh->texcoords = tmesh->texcoords; - if (smesh->texcoords.size()) - smesh->texcoord_indices = smesh->position_indices; - - for (size_t i=0; iquads.size(); i++) - smesh->verticesPerFace.push_back(3 + (int)(tmesh->quads[i].v2 != tmesh->quads[i].v3)); - - return smesh; - } - return node; - } - - Ref SceneGraph::convert_bezier_to_lines(Ref node) - { - if (Ref xfmNode = node.dynamicCast()) { - xfmNode->child = convert_bezier_to_lines(xfmNode->child); - } - else if (Ref groupNode = node.dynamicCast()) - { - for (size_t i=0; ichildren.size(); i++) - groupNode->children[i] = convert_bezier_to_lines(groupNode->children[i]); - } - else if (Ref hmesh = node.dynamicCast()) - { - SceneGraph::LineSegmentsNode* lmesh = new SceneGraph::LineSegmentsNode(hmesh->material); - - for (auto& p : hmesh->positions) - lmesh->positions.push_back(p); - - for (auto hair : hmesh->hairs) { - lmesh->indices.push_back(hair.vertex+0); - lmesh->indices.push_back(hair.vertex+1); - lmesh->indices.push_back(hair.vertex+2); - } - return lmesh; - } - return node; - } - - Ref SceneGraph::convert_hair_to_curves(Ref node) - { - if (Ref xfmNode = node.dynamicCast()) { - xfmNode->child = convert_hair_to_curves(xfmNode->child); - } - else if (Ref groupNode = node.dynamicCast()) - { - for (size_t i=0; ichildren.size(); i++) - groupNode->children[i] = convert_hair_to_curves(groupNode->children[i]); - } - else if (Ref hmesh = node.dynamicCast()) - { - hmesh->hair = false; - return hmesh.dynamicCast(); - } - return node; - } - - Ref SceneGraph::flatten(Ref node, const Transformations& spaces) - { - if (Ref xfmNode = node.dynamicCast()) { - return flatten(xfmNode->child, spaces*xfmNode->spaces); - } - else if (Ref groupNode = node.dynamicCast()) { - for (auto& child : groupNode->children) child = flatten(child,spaces); - } - else if (Ref mesh = node.dynamicCast()) { - return new SceneGraph::TriangleMeshNode(mesh,spaces); - } - else if (Ref mesh = node.dynamicCast()) { - return new SceneGraph::QuadMeshNode(mesh,spaces); - } - else if (Ref mesh = node.dynamicCast()) { - return new SceneGraph::SubdivMeshNode(mesh,spaces); - } - else if (Ref mesh = node.dynamicCast()) { - return new SceneGraph::LineSegmentsNode(mesh,spaces); - } - else if (Ref mesh = node.dynamicCast()) { - return new SceneGraph::HairSetNode(mesh,spaces); - } - else { - throw std::runtime_error("unsupported node type in SceneGraph::flatten"); - } - return node; - } - - Ref SceneGraph::createTrianglePlane (const Vec3fa& p0, const Vec3fa& dx, const Vec3fa& dy, size_t width, size_t height, Ref material) - { - SceneGraph::TriangleMeshNode* mesh = new SceneGraph::TriangleMeshNode(material,1); - mesh->positions[0].resize((width+1)*(height+1)); - mesh->triangles.resize(2*width*height); - - for (size_t y=0; y<=height; y++) { - for (size_t x=0; x<=width; x++) { - Vec3fa p = p0+float(x)/float(width)*dx+float(y)/float(height)*dy; - size_t i = y*(width+1)+x; - mesh->positions[0][i].x = p.x; - mesh->positions[0][i].y = p.y; - mesh->positions[0][i].z = p.z; - } - } - for (size_t y=0; ytriangles[i+0].v0 = unsigned(p00); mesh->triangles[i+0].v1 = unsigned(p01); mesh->triangles[i+0].v2 = unsigned(p10); - mesh->triangles[i+1].v0 = unsigned(p11); mesh->triangles[i+1].v1 = unsigned(p10); mesh->triangles[i+1].v2 = unsigned(p01); - } - } - return mesh; - } - - Ref SceneGraph::createQuadPlane (const Vec3fa& p0, const Vec3fa& dx, const Vec3fa& dy, size_t width, size_t height, Ref material) - { - SceneGraph::QuadMeshNode* mesh = new SceneGraph::QuadMeshNode(material,1); - mesh->positions[0].resize((width+1)*(height+1)); - mesh->quads.resize(width*height); - - for (size_t y=0; y<=height; y++) { - for (size_t x=0; x<=width; x++) { - Vec3fa p = p0+float(x)/float(width)*dx+float(y)/float(height)*dy; - size_t i = y*(width+1)+x; - mesh->positions[0][i].x = p.x; - mesh->positions[0][i].y = p.y; - mesh->positions[0][i].z = p.z; - } - } - for (size_t y=0; yquads[i].v0 = unsigned(p00); - mesh->quads[i].v1 = unsigned(p01); - mesh->quads[i].v2 = unsigned(p11); - mesh->quads[i].v3 = unsigned(p10); - } - } - return mesh; - } - - Ref SceneGraph::createSubdivPlane (const Vec3fa& p0, const Vec3fa& dx, const Vec3fa& dy, size_t width, size_t height, float tessellationRate, Ref material) - { - SceneGraph::SubdivMeshNode* mesh = new SceneGraph::SubdivMeshNode(material,1); - mesh->tessellationRate = tessellationRate; - mesh->positions[0].resize((width+1)*(height+1)); - mesh->position_indices.resize(4*width*height); - mesh->verticesPerFace.resize(width*height); - - for (size_t y=0; y<=height; y++) { - for (size_t x=0; x<=width; x++) { - Vec3fa p = p0+float(x)/float(width)*dx+float(y)/float(height)*dy; - size_t i = y*(width+1)+x; - mesh->positions[0][i].x = p.x; - mesh->positions[0][i].y = p.y; - mesh->positions[0][i].z = p.z; - } - } - for (size_t y=0; yposition_indices[4*i+0] = unsigned(p00); - mesh->position_indices[4*i+1] = unsigned(p01); - mesh->position_indices[4*i+2] = unsigned(p11); - mesh->position_indices[4*i+3] = unsigned(p10); - mesh->verticesPerFace[i] = 4; - } - } - mesh->position_subdiv_mode = RTC_SUBDIV_PIN_CORNERS; - return mesh; - } - - Ref SceneGraph::createTriangleSphere (const Vec3fa& center, const float radius, size_t N, Ref material) - { - unsigned numPhi = unsigned(N); - unsigned numTheta = 2*numPhi; - unsigned numVertices = numTheta*(numPhi+1); - SceneGraph::TriangleMeshNode* mesh = new SceneGraph::TriangleMeshNode(material,1); - mesh->positions[0].resize(numVertices); - - /* create sphere geometry */ - const float rcpNumTheta = rcp(float(numTheta)); - const float rcpNumPhi = rcp(float(numPhi)); - for (unsigned int phi=0; phi<=numPhi; phi++) - { - for (unsigned int theta=0; thetapositions[0][phi*numTheta+theta].x = center.x + radius*sin(phif)*sin(thetaf); - mesh->positions[0][phi*numTheta+theta].y = center.y + radius*cos(phif); - mesh->positions[0][phi*numTheta+theta].z = center.z + radius*sin(phif)*cos(thetaf); - } - if (phi == 0) continue; - - if (phi == 1) - { - for (unsigned int theta=1; theta<=numTheta; theta++) - { - unsigned int p00 = numTheta-1; - unsigned int p10 = phi*numTheta+theta-1; - unsigned int p11 = phi*numTheta+theta%numTheta; - mesh->triangles.push_back(TriangleMeshNode::Triangle(p10,p00,p11)); - } - } - else if (phi == numPhi) - { - for (unsigned int theta=1; theta<=numTheta; theta++) - { - unsigned int p00 = (phi-1)*numTheta+theta-1; - unsigned int p01 = (phi-1)*numTheta+theta%numTheta; - unsigned int p10 = numPhi*numTheta; - mesh->triangles.push_back(TriangleMeshNode::Triangle(p10,p00,p01)); - } - } - else - { - for (unsigned int theta=1; theta<=numTheta; theta++) - { - unsigned int p00 = (phi-1)*numTheta+theta-1; - unsigned int p01 = (phi-1)*numTheta+theta%numTheta; - unsigned int p10 = phi*numTheta+theta-1; - unsigned int p11 = phi*numTheta+theta%numTheta; - mesh->triangles.push_back(TriangleMeshNode::Triangle(p10,p00,p11)); - mesh->triangles.push_back(TriangleMeshNode::Triangle(p01,p11,p00)); - } - } - } - return mesh; - } - - Ref SceneGraph::createQuadSphere (const Vec3fa& center, const float radius, size_t N, Ref material) - { - unsigned numPhi = unsigned(N); - unsigned numTheta = 2*numPhi; - unsigned numVertices = numTheta*(numPhi+1); - SceneGraph::QuadMeshNode* mesh = new SceneGraph::QuadMeshNode(material,1); - mesh->positions[0].resize(numVertices); - - /* create sphere geometry */ - const float rcpNumTheta = rcp(float(numTheta)); - const float rcpNumPhi = rcp(float(numPhi)); - for (unsigned int phi=0; phi<=numPhi; phi++) - { - for (unsigned int theta=0; thetapositions[0][phi*numTheta+theta].x = center.x + radius*sin(phif)*sin(thetaf); - mesh->positions[0][phi*numTheta+theta].y = center.y + radius*cos(phif); - mesh->positions[0][phi*numTheta+theta].z = center.z + radius*sin(phif)*cos(thetaf); - } - if (phi == 0) continue; - - if (phi == 1) - { - for (unsigned int theta=1; theta<=numTheta; theta++) - { - unsigned int p00 = numTheta-1; - unsigned int p10 = phi*numTheta+theta-1; - unsigned int p11 = phi*numTheta+theta%numTheta; - mesh->quads.push_back(QuadMeshNode::Quad(p10,p00,p11,p11)); - } - } - else if (phi == numPhi) - { - for (unsigned int theta=1; theta<=numTheta; theta++) - { - unsigned int p00 = (phi-1)*numTheta+theta-1; - unsigned int p01 = (phi-1)*numTheta+theta%numTheta; - unsigned int p10 = numPhi*numTheta; - mesh->quads.push_back(QuadMeshNode::Quad(p10,p00,p01,p01)); - } - } - else - { - for (unsigned int theta=1; theta<=numTheta; theta++) - { - unsigned int p00 = (phi-1)*numTheta+theta-1; - unsigned int p01 = (phi-1)*numTheta+theta%numTheta; - unsigned int p10 = phi*numTheta+theta-1; - unsigned int p11 = phi*numTheta+theta%numTheta; - mesh->quads.push_back(QuadMeshNode::Quad(p10,p00,p01,p11)); - } - } - } - return mesh; - } - - Ref SceneGraph::createSubdivSphere (const Vec3fa& center, const float radius, size_t N, float tessellationRate, Ref material) - { - unsigned numPhi = unsigned(N); - unsigned numTheta = 2*numPhi; - unsigned numVertices = numTheta*(numPhi+1); - SceneGraph::SubdivMeshNode* mesh = new SceneGraph::SubdivMeshNode(material,1); - mesh->tessellationRate = tessellationRate; - mesh->positions[0].resize(numVertices); - - /* create sphere geometry */ - const float rcpNumTheta = rcp((float)numTheta); - const float rcpNumPhi = rcp((float)numPhi); - for (unsigned int phi=0; phi<=numPhi; phi++) - { - for (unsigned int theta=0; thetapositions[0][phi*numTheta+theta].x = center.x + radius*sin(phif)*sin(thetaf); - mesh->positions[0][phi*numTheta+theta].y = center.y + radius*cos(phif); - mesh->positions[0][phi*numTheta+theta].z = center.z + radius*sin(phif)*cos(thetaf); - } - if (phi == 0) continue; - - if (phi == 1) - { - for (unsigned int theta=1; theta<=numTheta; theta++) - { - unsigned int p00 = numTheta-1; - unsigned int p10 = phi*numTheta+theta-1; - unsigned int p11 = phi*numTheta+theta%numTheta; - mesh->verticesPerFace.push_back(3); - mesh->position_indices.push_back(p10); - mesh->position_indices.push_back(p00); - mesh->position_indices.push_back(p11); - } - } - else if (phi == numPhi) - { - for (unsigned int theta=1; theta<=numTheta; theta++) - { - unsigned int p00 = (phi-1)*numTheta+theta-1; - unsigned int p01 = (phi-1)*numTheta+theta%numTheta; - unsigned int p10 = numPhi*numTheta; - mesh->verticesPerFace.push_back(3); - mesh->position_indices.push_back(p10); - mesh->position_indices.push_back(p00); - mesh->position_indices.push_back(p01); - } - } - else - { - for (unsigned int theta=1; theta<=numTheta; theta++) - { - unsigned int p00 = (phi-1)*numTheta+theta-1; - unsigned int p01 = (phi-1)*numTheta+theta%numTheta; - unsigned int p10 = phi*numTheta+theta-1; - unsigned int p11 = phi*numTheta+theta%numTheta; - mesh->verticesPerFace.push_back(4); - mesh->position_indices.push_back(p10); - mesh->position_indices.push_back(p00); - mesh->position_indices.push_back(p01); - mesh->position_indices.push_back(p11); - } - } - } - return mesh; - } - - Ref SceneGraph::createSphereShapedHair(const Vec3fa& center, const float radius, Ref material) - { - SceneGraph::HairSetNode* mesh = new SceneGraph::HairSetNode(true,material,1); - mesh->hairs.push_back(SceneGraph::HairSetNode::Hair(0,0)); - mesh->positions[0].push_back(Vec3fa(center+Vec3fa(-radius,0,0),radius)); - mesh->positions[0].push_back(Vec3fa(center+Vec3fa(0,radius,0),radius)); - mesh->positions[0].push_back(Vec3fa(center+Vec3fa(0,0,radius),radius)); - mesh->positions[0].push_back(Vec3fa(center+Vec3fa(0,+radius,0),radius)); - return mesh; - } - - Ref SceneGraph::createHairyPlane (int hash, const Vec3fa& pos, const Vec3fa& dx, const Vec3fa& dy, const float len, const float r, size_t numHairs, bool hair, Ref material) - { - RandomSampler sampler; - RandomSampler_init(sampler,hash); - - SceneGraph::HairSetNode* mesh = new SceneGraph::HairSetNode(hair,material,1); - - if (numHairs == 1) { - const Vec3fa p0 = pos; - const Vec3fa p1 = p0 + len*Vec3fa(1,0,0); - const Vec3fa p2 = p0 + len*Vec3fa(0,1,1); - const Vec3fa p3 = p0 + len*Vec3fa(0,1,0); - mesh->hairs.push_back(HairSetNode::Hair(0,0)); - mesh->positions[0].push_back(Vec3fa(p0,r)); - mesh->positions[0].push_back(Vec3fa(p1,r)); - mesh->positions[0].push_back(Vec3fa(p2,r)); - mesh->positions[0].push_back(Vec3fa(p3,r)); - return mesh; - } - - Vec3fa dz = cross(dx,dy); - for (size_t i=0; ihairs.push_back(HairSetNode::Hair(unsigned(4*i),unsigned(i))); - mesh->positions[0].push_back(Vec3fa(p0,r)); - mesh->positions[0].push_back(Vec3fa(p1,r)); - mesh->positions[0].push_back(Vec3fa(p2,r)); - mesh->positions[0].push_back(Vec3fa(p3,r)); - } - return mesh; - } - - Ref SceneGraph::createGarbageTriangleMesh (int hash, size_t numTriangles, bool mblur, Ref material) - { - RandomSampler sampler; - RandomSampler_init(sampler,hash); - SceneGraph::TriangleMeshNode* mesh = new SceneGraph::TriangleMeshNode(material,mblur?2:1); - - mesh->triangles.resize(numTriangles); - for (size_t i=0; itriangles[i] = TriangleMeshNode::Triangle(v0,v1,v2); - } - - mesh->positions[0].resize(3*numTriangles); - for (size_t i=0; i<3*numTriangles; i++) { - const float x = cast_i2f(RandomSampler_getUInt(sampler)); - const float y = cast_i2f(RandomSampler_getUInt(sampler)); - const float z = cast_i2f(RandomSampler_getUInt(sampler)); - const float w = cast_i2f(RandomSampler_getUInt(sampler)); - mesh->positions[0][i] = Vec3fa(x,y,z,w); - } - - if (mblur) - { - mesh->positions[1].resize(3*numTriangles); - for (size_t i=0; i<3*numTriangles; i++) { - const float x = cast_i2f(RandomSampler_getUInt(sampler)); - const float y = cast_i2f(RandomSampler_getUInt(sampler)); - const float z = cast_i2f(RandomSampler_getUInt(sampler)); - const float w = cast_i2f(RandomSampler_getUInt(sampler)); - mesh->positions[1][i] = Vec3fa(x,y,z,w); - } - } - - return mesh; - } - - Ref SceneGraph::createGarbageQuadMesh (int hash, size_t numQuads, bool mblur, Ref material) - { - RandomSampler sampler; - RandomSampler_init(sampler,hash); - SceneGraph::QuadMeshNode* mesh = new SceneGraph::QuadMeshNode(material,mblur?2:1); - - mesh->quads.resize(numQuads); - for (size_t i=0; iquads[i] = QuadMeshNode::Quad(v0,v1,v2,v3); - } - - mesh->positions[0].resize(4*numQuads); - for (size_t i=0; i<4*numQuads; i++) { - const float x = cast_i2f(RandomSampler_getUInt(sampler)); - const float y = cast_i2f(RandomSampler_getUInt(sampler)); - const float z = cast_i2f(RandomSampler_getUInt(sampler)); - const float w = cast_i2f(RandomSampler_getUInt(sampler)); - mesh->positions[0][i] = Vec3fa(x,y,z,w); - } - - if (mblur) - { - mesh->positions[1].resize(4*numQuads); - for (size_t i=0; i<4*numQuads; i++) { - const float x = cast_i2f(RandomSampler_getUInt(sampler)); - const float y = cast_i2f(RandomSampler_getUInt(sampler)); - const float z = cast_i2f(RandomSampler_getUInt(sampler)); - const float w = cast_i2f(RandomSampler_getUInt(sampler)); - mesh->positions[1][i] = Vec3fa(x,y,z,w); - } - } - - return mesh; - } - - Ref SceneGraph::createGarbageLineSegments (int hash, size_t numLineSegments, bool mblur, Ref material) - { - RandomSampler sampler; - RandomSampler_init(sampler,hash); - SceneGraph::LineSegmentsNode* mesh = new SceneGraph::LineSegmentsNode(material,mblur?2:1); - - mesh->indices.resize(numLineSegments); - for (size_t i=0; iindices[i] = (RandomSampler_getInt(sampler) % 32 == 0) ? RandomSampler_getUInt(sampler) : unsigned(2*i); - } - - mesh->positions[0].resize(2*numLineSegments); - for (size_t i=0; i<2*numLineSegments; i++) { - const float x = cast_i2f(RandomSampler_getUInt(sampler)); - const float y = cast_i2f(RandomSampler_getUInt(sampler)); - const float z = cast_i2f(RandomSampler_getUInt(sampler)); - const float r = cast_i2f(RandomSampler_getUInt(sampler)); - mesh->positions[0][i] = Vec3fa(x,y,z,r); - } - - if (mblur) - { - mesh->positions[1].resize(2*numLineSegments); - for (size_t i=0; i<2*numLineSegments; i++) { - const float x = cast_i2f(RandomSampler_getUInt(sampler)); - const float y = cast_i2f(RandomSampler_getUInt(sampler)); - const float z = cast_i2f(RandomSampler_getUInt(sampler)); - const float r = cast_i2f(RandomSampler_getUInt(sampler)); - mesh->positions[1][i] = Vec3fa(x,y,z,r); - } - } - - return mesh; - } - - Ref SceneGraph::createGarbageHair (int hash, size_t numHairs, bool mblur, Ref material) - { - RandomSampler sampler; - RandomSampler_init(sampler,hash); - SceneGraph::HairSetNode* mesh = new SceneGraph::HairSetNode(true,material,mblur?2:1); - - mesh->hairs.resize(numHairs); - for (size_t i=0; ihairs[i] = HairSetNode::Hair(v0,0); - } - - mesh->positions[0].resize(4*numHairs); - for (size_t i=0; i<4*numHairs; i++) { - const float x = cast_i2f(RandomSampler_getUInt(sampler)); - const float y = cast_i2f(RandomSampler_getUInt(sampler)); - const float z = cast_i2f(RandomSampler_getUInt(sampler)); - const float r = cast_i2f(RandomSampler_getUInt(sampler)); - mesh->positions[0][i] = Vec3fa(x,y,z,r); - } - - if (mblur) - { - mesh->positions[1].resize(4*numHairs); - for (size_t i=0; i<4*numHairs; i++) { - const float x = cast_i2f(RandomSampler_getUInt(sampler)); - const float y = cast_i2f(RandomSampler_getUInt(sampler)); - const float z = cast_i2f(RandomSampler_getUInt(sampler)); - const float r = cast_i2f(RandomSampler_getUInt(sampler)); - mesh->positions[1][i] = Vec3fa(x,y,z,r); - } - } - - return mesh; - } - - Ref SceneGraph::createGarbageSubdivMesh (int hash, size_t numFaces, bool mblur, Ref material) - { - RandomSampler sampler; - RandomSampler_init(sampler,hash); - SceneGraph::SubdivMeshNode* mesh = new SceneGraph::SubdivMeshNode(material,mblur?2:1); - - for (size_t i=0; iverticesPerFace.push_back(f); - for (size_t j=0; jposition_indices.push_back((RandomSampler_getInt(sampler) % 32 == 0) ? RandomSampler_getUInt(sampler) : unsigned(mesh->numPositions())); - - const float x = cast_i2f(RandomSampler_getUInt(sampler)); - const float y = cast_i2f(RandomSampler_getUInt(sampler)); - const float z = cast_i2f(RandomSampler_getUInt(sampler)); - const float w = cast_i2f(RandomSampler_getUInt(sampler)); - mesh->positions[0].push_back(Vec3fa(x,y,z,w)); - - if (mblur) - { - const float x = cast_i2f(RandomSampler_getUInt(sampler)); - const float y = cast_i2f(RandomSampler_getUInt(sampler)); - const float z = cast_i2f(RandomSampler_getUInt(sampler)); - const float w = cast_i2f(RandomSampler_getUInt(sampler)); - mesh->positions[1].push_back(Vec3fa(x,y,z,w)); - } - } - } - - return mesh; - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/scenegraph.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/scenegraph.h deleted file mode 100644 index 6a89df902aab..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/scenegraph.h +++ /dev/null @@ -1,770 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "materials.h" -#include "lights.h" -#include "../../../include/embree2/rtcore.h" -#include "../math/random_sampler.h" - -namespace embree -{ - namespace SceneGraph - { - struct Node; - struct MaterialNode; - struct Transformations; - - Ref load(const FileName& fname, bool singleObject = false); - void store(Ref root, const FileName& fname, bool embedTextures); - void extend_animation(Ref node0, Ref node1); - void optimize_animation(Ref node0); - void set_motion_vector(Ref node, const Vec3fa& dP); - void set_motion_vector(Ref node, const avector& motion_vector); - void resize_randomly(RandomSampler& sampler, Ref node, const size_t N); - Ref convert_triangles_to_quads(Ref node); - Ref convert_quads_to_subdivs(Ref node); - Ref convert_bezier_to_lines(Ref node); - Ref convert_hair_to_curves(Ref node); - - Ref createTrianglePlane (const Vec3fa& p0, const Vec3fa& dx, const Vec3fa& dy, size_t width, size_t height, Ref material = nullptr); - Ref createQuadPlane (const Vec3fa& p0, const Vec3fa& dx, const Vec3fa& dy, size_t width, size_t height, Ref material = nullptr); - Ref createSubdivPlane (const Vec3fa& p0, const Vec3fa& dx, const Vec3fa& dy, size_t width, size_t height, float tessellationRate, Ref material = nullptr); - Ref createTriangleSphere(const Vec3fa& center, const float radius, size_t numPhi, Ref material = nullptr); - Ref createQuadSphere (const Vec3fa& center, const float radius, size_t numPhi, Ref material = nullptr); - Ref createSubdivSphere (const Vec3fa& center, const float radius, size_t numPhi, float tessellationRate, Ref material = nullptr); - Ref createSphereShapedHair(const Vec3fa& center, const float radius, Ref material = nullptr); - - Ref createHairyPlane (int hash, const Vec3fa& pos, const Vec3fa& dx, const Vec3fa& dy, const float len, const float r, size_t numHairs, bool hair, Ref material = nullptr); - - Ref createGarbageTriangleMesh (int hash, size_t numTriangles, bool mblur, Ref material = nullptr); - Ref createGarbageQuadMesh (int hash, size_t numQuads, bool mblur, Ref material = nullptr); - Ref createGarbageHair (int hash, size_t numHairs, bool mblur, Ref material = nullptr); - Ref createGarbageLineSegments (int hash, size_t numLineSegments, bool mblur, Ref material = nullptr); - Ref createGarbageSubdivMesh (int hash, size_t numFaces, bool mblur, Ref material = nullptr); - - struct Node : public RefCount - { - Node (bool closed = false) - : indegree(0), closed(closed) {} - - /* resets indegree and closed parameters */ - void reset() - { - std::set> done; - resetNode(done); - } - - /* sets material */ - virtual void setMaterial(Ref material) {}; - - /* resets indegree and closed parameters */ - virtual void resetNode(std::set>& done); - - /* calculates the number of parent nodes pointing to this node */ - virtual void calculateInDegree(); - - /* calculates for each node if its subtree is closed, indegrees have to be calculated first */ - virtual bool calculateClosed(); - - /* checks if the node is closed */ - __forceinline bool isClosed() const { return closed; } - - /* calculates bounding box of node */ - virtual BBox3fa bounds() const { - return empty; - } - - /* calculates linear bounding box of node */ - virtual LBBox3fa lbounds() const { - return empty; - } - - /* calculates number of primitives */ - virtual size_t numPrimitives() const = 0; - - Ref set_motion_vector(const Vec3fa& dP) { - SceneGraph::set_motion_vector(this,dP); return this; - } - - Ref set_motion_vector(const avector& motion_vector) { - SceneGraph::set_motion_vector(this,motion_vector); return this; - } - - protected: - size_t indegree; // number of nodes pointing to us - bool closed; // determines if the subtree may represent an instance - }; - - struct Transformations - { - __forceinline Transformations() {} - - __forceinline Transformations(OneTy) { - spaces.push_back(one); - } - - __forceinline Transformations( size_t N ) - : spaces(N) {} - - __forceinline Transformations(const AffineSpace3fa& space) { - spaces.push_back(space); - } - - __forceinline Transformations(const AffineSpace3fa& space0, const AffineSpace3fa& space1) { - spaces.push_back(space0); - spaces.push_back(space1); - } - - __forceinline Transformations(const avector& spaces) - : spaces(spaces) { assert(spaces.size()); } - - __forceinline size_t size() const { - return spaces.size(); - } - - __forceinline AffineSpace3fa& operator[] ( const size_t i ) { return spaces[i]; } - __forceinline const AffineSpace3fa& operator[] ( const size_t i ) const { return spaces[i]; } - - BBox3fa bounds ( const BBox3fa& cbounds ) const - { - BBox3fa r = empty; - for (size_t i=0; i bounds(spaces.size()); - for (size_t i=0; i spaces; - }; - - struct TransformNode : public Node - { - ALIGNED_STRUCT; - - TransformNode (const AffineSpace3fa& xfm, const Ref& child) - : spaces(xfm), child(child) {} - - TransformNode (const AffineSpace3fa& xfm0, const AffineSpace3fa& xfm1, const Ref& child) - : spaces(xfm0,xfm1), child(child) {} - - TransformNode (const avector& spaces, const Ref& child) - : spaces(spaces), child(child) {} - - virtual void setMaterial(Ref material) { - child->setMaterial(material); - } - - virtual void resetNode(std::set>& done); - virtual void calculateInDegree(); - virtual bool calculateClosed(); - - virtual BBox3fa bounds() const { - return spaces.bounds(child->bounds()); - } - - virtual LBBox3fa lbounds() const { - return spaces.lbounds(child->lbounds()); - } - - virtual size_t numPrimitives() const { - return child->numPrimitives(); - } - - public: - Transformations spaces; - Ref child; - }; - - struct GroupNode : public Node - { - GroupNode (const size_t N = 0) { - children.resize(N); - } - - size_t size() const { - return children.size(); - } - - void add(const Ref& node) { - if (node) children.push_back(node); - } - - void set(const size_t i, const Ref& node) { - children[i] = node; - } - - virtual BBox3fa bounds() const - { - BBox3fa b = empty; - for (auto c : children) b.extend(c->bounds()); - return b; - } - - virtual LBBox3fa lbounds() const - { - LBBox3fa b = empty; - for (auto c : children) b.extend(c->lbounds()); - return b; - } - - virtual size_t numPrimitives() const - { - size_t n = 0; - for (auto child : children) n += child->numPrimitives(); - return n; - } - - void triangles_to_quads() - { - for (size_t i=0; i material) { - for (auto& child : children) child->setMaterial(material); - } - - virtual void resetNode(std::set>& done); - virtual void calculateInDegree(); - virtual bool calculateClosed(); - - public: - std::vector > children; - }; - - struct LightNode : public Node - { - LightNode (Ref light) - : light(light) {} - - virtual size_t numPrimitives() const { - return 0; - } - - Ref light; - }; - - struct MaterialNode : public Node - { - ALIGNED_STRUCT; - - MaterialNode(const Material& material) - : material(material) {} - - virtual size_t numPrimitives() const { - return 0; - } - - Material material; - }; - - /*! Mesh. */ - struct TriangleMeshNode : public Node - { - typedef Vec3fa Vertex; - - struct Triangle - { - public: - Triangle() {} - Triangle (unsigned v0, unsigned v1, unsigned v2) - : v0(v0), v1(v1), v2(v2) {} - public: - unsigned v0, v1, v2; - }; - - public: - TriangleMeshNode (Ref material, size_t numTimeSteps = 0) - : Node(true), material(material) - { - for (size_t i=0; i()); - } - - TriangleMeshNode (Ref imesh, const Transformations& spaces) - : Node(true), normals(imesh->normals), texcoords(imesh->texcoords), triangles(imesh->triangles), material(imesh->material) - { - for (size_t i=0; i verts(imesh->numVertices()); - for (size_t j=0; jnumVertices(); j++) - verts[j] = xfmPoint(spaces[i],imesh->positions[0][j]); - positions.push_back(std::move(verts)); - } - } - - virtual void setMaterial(Ref material) { - this->material = material; - } - - virtual BBox3fa bounds() const - { - BBox3fa b = empty; - for (const auto& p : positions) - for (auto x : p) - b.extend(x); - return b; - } - - virtual LBBox3fa lbounds() const - { - avector bboxes(positions.size()); - for (size_t t=0; t> positions; - avector normals; - std::vector texcoords; - std::vector triangles; - Ref material; - }; - - /*! Mesh. */ - struct QuadMeshNode : public Node - { - typedef Vec3fa Vertex; - - struct Quad - { - public: - Quad() {} - Quad (unsigned v0, unsigned v1, unsigned v2, unsigned v3) - : v0(v0), v1(v1), v2(v2), v3(v3) {} - public: - unsigned v0, v1, v2, v3; - }; - - public: - QuadMeshNode (Ref material, size_t numTimeSteps = 0) - : Node(true), material(material) - { - for (size_t i=0; i()); - } - - QuadMeshNode (Ref imesh, const Transformations& spaces) - : Node(true), normals(imesh->normals), texcoords(imesh->texcoords), quads(imesh->quads), material(imesh->material) - { - for (size_t i=0; i verts(imesh->numVertices()); - for (size_t j=0; jnumVertices(); j++) - verts[j] = xfmPoint(spaces[i],imesh->positions[0][j]); - positions.push_back(std::move(verts)); - } - } - - virtual void setMaterial(Ref material) { - this->material = material; - } - - virtual BBox3fa bounds() const - { - BBox3fa b = empty; - for (const auto& p : positions) - for (auto x : p) - b.extend(x); - return b; - } - - virtual LBBox3fa lbounds() const - { - avector bboxes(positions.size()); - for (size_t t=0; t> positions; - avector normals; - std::vector texcoords; - std::vector quads; - Ref material; - }; - - /*! Subdivision Mesh. */ - struct SubdivMeshNode : public Node - { - typedef Vec3fa Vertex; - - SubdivMeshNode (Ref material, size_t numTimeSteps = 0) - : Node(true), - position_subdiv_mode(RTC_SUBDIV_SMOOTH_BOUNDARY), - normal_subdiv_mode(RTC_SUBDIV_SMOOTH_BOUNDARY), - texcoord_subdiv_mode(RTC_SUBDIV_SMOOTH_BOUNDARY), - material(material), tessellationRate(2.0f) - { - for (size_t i=0; i()); - } - - SubdivMeshNode (Ref imesh, const Transformations& spaces) - : Node(true), - normals(imesh->normals), - texcoords(imesh->texcoords), - position_indices(imesh->position_indices), - normal_indices(imesh->normal_indices), - texcoord_indices(imesh->texcoord_indices), - position_subdiv_mode(imesh->position_subdiv_mode), - normal_subdiv_mode(imesh->normal_subdiv_mode), - texcoord_subdiv_mode(imesh->texcoord_subdiv_mode), - verticesPerFace(imesh->verticesPerFace), - holes(imesh->holes), - edge_creases(imesh->edge_creases), - edge_crease_weights(imesh->edge_crease_weights), - vertex_creases(imesh->vertex_creases), - vertex_crease_weights(imesh->vertex_crease_weights), - material(imesh->material), - tessellationRate(imesh->tessellationRate) - { - for (size_t i=0; i verts(imesh->numPositions()); - for (size_t j=0; jnumPositions(); j++) - verts[j] = xfmPoint(spaces[i],imesh->positions[0][j]); - positions.push_back(std::move(verts)); - } - } - - virtual void setMaterial(Ref material) { - this->material = material; - } - - virtual BBox3fa bounds() const - { - BBox3fa b = empty; - for (const auto& p : positions) - for (auto x : p) - b.extend(x); - return b; - } - - virtual LBBox3fa lbounds() const - { - avector bboxes(positions.size()); - for (size_t t=0; t> positions; //!< vertex positions for multiple timesteps - avector normals; //!< face vertex normals - std::vector texcoords; //!< face texture coordinates - std::vector position_indices; //!< position indices for all faces - std::vector normal_indices; //!< normal indices for all faces - std::vector texcoord_indices; //!< texcoord indices for all faces - RTCSubdivisionMode position_subdiv_mode; - RTCSubdivisionMode normal_subdiv_mode; - RTCSubdivisionMode texcoord_subdiv_mode; - std::vector verticesPerFace; //!< number of indices of each face - std::vector holes; //!< face ID of holes - std::vector edge_creases; //!< index pairs for edge crease - std::vector edge_crease_weights; //!< weight for each edge crease - std::vector vertex_creases; //!< indices of vertex creases - std::vector vertex_crease_weights; //!< weight for each vertex crease - Ref material; - float tessellationRate; - }; - - /*! Line Segments */ - struct LineSegmentsNode : public Node - { - typedef Vec3fa Vertex; - - public: - LineSegmentsNode (Ref material, size_t numTimeSteps = 0) - : Node(true), material(material) - { - for (size_t i=0; i()); - } - - LineSegmentsNode (Ref imesh, const Transformations& spaces) - : Node(true), indices(imesh->indices), material(imesh->material) - { - for (size_t i=0; i verts(imesh->numVertices()); - for (size_t j=0; jnumVertices(); j++) - verts[j] = xfmPoint(spaces[i],imesh->positions[0][j]); - positions.push_back(std::move(verts)); - } - } - - virtual void setMaterial(Ref material) { - this->material = material; - } - - virtual BBox3fa bounds() const - { - BBox3fa b = empty; - for (const auto& p : positions) - for (auto x : p) - b.extend(x); - return b; - } - - virtual LBBox3fa lbounds() const - { - avector bboxes(positions.size()); - for (size_t t=0; t> positions; //!< line control points (x,y,z,r) for multiple timesteps - std::vector indices; //!< list of line segments - Ref material; - }; - - /*! Hair Set. */ - struct HairSetNode : public Node - { - typedef Vec3fa Vertex; - - struct Hair - { - public: - Hair () {} - Hair (unsigned vertex, unsigned id) - : vertex(vertex), id(id) {} - - public: - unsigned vertex,id; //!< index of first control point and hair ID - }; - - public: - HairSetNode (bool hair, Ref material, size_t numTimeSteps = 0) - : Node(true), hair(hair), material(material), tessellation_rate(4) - { - for (size_t i=0; i()); - } - - HairSetNode (Ref imesh, const Transformations& spaces) - : Node(true), hair(imesh->hair), hairs(imesh->hairs), material(imesh->material), tessellation_rate(imesh->tessellation_rate) - { - for (size_t i=0; i verts(imesh->numVertices()); - for (size_t j=0; jnumVertices(); j++) - verts[j] = xfmPoint(spaces[i],imesh->positions[0][j]); - positions.push_back(std::move(verts)); - } - } - - virtual void setMaterial(Ref material) { - this->material = material; - } - - virtual BBox3fa bounds() const - { - BBox3fa b = empty; - for (const auto& p : positions) - for (auto x : p) - b.extend(x); - return b; - } - - virtual LBBox3fa lbounds() const - { - avector bboxes(positions.size()); - for (size_t t=0; t> positions; //!< hair control points (x,y,z,r) for multiple timesteps - std::vector hairs; //!< list of hairs - Ref material; - unsigned tessellation_rate; - }; - - Ref flatten(Ref node, const Transformations& spaces = Transformations(one)); - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/texture.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/texture.cpp deleted file mode 100644 index ee404f10f5d9..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/texture.cpp +++ /dev/null @@ -1,94 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "texture.h" - -namespace embree -{ - bool isPowerOf2 (unsigned int x) - { - while (((x % 2) == 0) && x > 1) - x /= 2; - return (x == 1); - } - - std::map texture_cache; - - Texture::Texture () - : width(-1), height(-1), format(INVALID), bytesPerTexel(0), width_mask(0), height_mask(0), data(nullptr) {} - - Texture::Texture(Ref img, const std::string fileName) - : width(unsigned(img->width)), height(unsigned(img->height)), format(RGBA8), bytesPerTexel(4), width_mask(0), height_mask(0), data(nullptr), fileName(fileName) - { - width_mask = isPowerOf2(width) ? width-1 : 0; - height_mask = isPowerOf2(height) ? height-1 : 0; - - data = alignedMalloc(4*width*height,64); - img->convertToRGBA8((unsigned char*)data); - } - - Texture::Texture (unsigned width, unsigned height, const Format format, const char* in) - : width(width), height(height), format(format), bytesPerTexel(getFormatBytesPerTexel(format)), width_mask(0), height_mask(0), data(nullptr) - { - width_mask = isPowerOf2(width) ? width-1 : 0; - height_mask = isPowerOf2(height) ? height-1 : 0; - - data = alignedMalloc(bytesPerTexel*width*height,64); - if (in) memcpy(data,in,bytesPerTexel*width*height); - else memset(data,0 ,bytesPerTexel*width*height); - } - - Texture::~Texture () { - alignedFree(data); - } - - const char* Texture::format_to_string(const Format format) - { - switch (format) { - case RGBA8 : return "RGBA8"; - case RGB8 : return "RGB8"; - case FLOAT32: return "FLOAT32"; - default : THROW_RUNTIME_ERROR("invalid texture format"); - } - } - - Texture::Format Texture::string_to_format(const std::string& str) - { - if (str == "RGBA8") return RGBA8; - else if (str == "RGB8") return RGB8; - else if (str == "FLOAT32") return FLOAT32; - else THROW_RUNTIME_ERROR("invalid texture format string"); - } - - unsigned Texture::getFormatBytesPerTexel(const Format format) - { - switch (format) { - case RGBA8 : return 4; - case RGB8 : return 3; - case FLOAT32: return 4; - default : THROW_RUNTIME_ERROR("invalid texture format"); - } - } - - /*! read png texture from disk */ - Texture* Texture::load(const FileName& fileName) - { - if (texture_cache.find(fileName.str()) != texture_cache.end()) - return texture_cache[fileName.str()]; - - return texture_cache[fileName.str()] = new Texture(loadImage(fileName),fileName); - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/texture.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/texture.h deleted file mode 100644 index 1ce93ea29c33..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/texture.h +++ /dev/null @@ -1,55 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../default.h" -#include "../image/image.h" - -namespace embree -{ - struct Texture // FIXME: should be derived from SceneGraph::Node - { - enum Format { - INVALID = 0, - RGBA8 = 1, - RGB8 = 2, - FLOAT32 = 3, - }; - - public: - Texture (); - Texture (Ref image, const std::string fileName); - Texture (unsigned width, unsigned height, const Format format, const char* in = nullptr); - ~Texture (); - - static const char* format_to_string(const Format format); - static Format string_to_format(const std::string& str); - static unsigned getFormatBytesPerTexel(const Format format); - - static Texture* load(const FileName& fileName); // FIXME: return reference - - public: - unsigned width; - unsigned height; - Format format; - unsigned bytesPerTexel; - unsigned width_mask; - unsigned height_mask; - void* data; - std::string fileName; - }; -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/xml_loader.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/xml_loader.cpp deleted file mode 100644 index f250aa3c3d81..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/xml_loader.cpp +++ /dev/null @@ -1,1298 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "xml_loader.h" -#include "xml_parser.h" -#include "obj_loader.h" - -namespace embree -{ - struct Variant - { - ALIGNED_CLASS - public: - - /*! Determines which kind of value is stored in the variant. */ - enum Type { - EMPTY, /*!< variant is empty */ - BOOL1, /*!< variant stores bool value */ - BOOL2, /*!< variant stores bool2 value */ - BOOL3, /*!< variant stores bool3 value */ - BOOL4, /*!< variant stores bool4 value */ - INT1, /*!< variant stores int value */ - INT2, /*!< variant stores int2 value */ - INT3, /*!< variant stores int3 value */ - INT4, /*!< variant stores int4 value */ - FLOAT1, /*!< variant stores float value */ - FLOAT2, /*!< variant stores float2 value */ - FLOAT3, /*!< variant stores float3 value */ - FLOAT4, /*!< variant stores float4 value */ - STRING, /*!< variant stores string value */ - TEXTURE, /*!< variant stores texture value */ - }; - - /*! Constructs an empty variant object. */ - Variant ( ) : type(EMPTY) { } - - /*! Constructs a variant object holding a bool value. */ - Variant (bool b0 ) : type(BOOL1) { b[0] = b0; } - - /*! Constructs a variant object holding a bool2 value. */ - Variant (bool b0, bool b1 ) : type(BOOL2) { b[0] = b0; b[1] = b1; } - - /*! Constructs a variant object holding a bool3 value. */ - Variant (bool b0, bool b1, bool b2 ) : type(BOOL3) { b[0] = b0; b[1] = b1; b[2] = b2; } - - /*! Constructs a variant object holding a bool4 value. */ - Variant (bool b0, bool b1, bool b2, bool b3) : type(BOOL4) { b[0] = b0; b[1] = b1; b[2] = b2; b[3] = b3; } - - /*! Constructs a variant object holding an int value. */ - Variant (int i0) : type(INT1) { i[0] = i0; } - - /*! Constructs a variant object holding an int2 value. */ - Variant (Vec2i v) : type(INT2) { i[0] = v.x; i[1] = v.y; } - - /*! Constructs a variant object holding an int3 value. */ - Variant (Vec3i v) : type(INT3) { i[0] = v.x; i[1] = v.y; i[2] = v.z; } - - /*! Constructs a variant object holding an int4 value. */ - Variant (Vec4i v) : type(INT4) { i[0] = v.x; i[1] = v.y; i[2] = v.z; i[3] = v.w; } - - /*! Constructs a variant object holding a float value. */ - Variant (float f0) : type(FLOAT1) { f[0] = f0; } - - /*! Constructs a variant object holding a float2 value. */ - Variant (Vec2f v) : type(FLOAT2) { f[0] = v.x; f[1] = v.y; } - - /*! Constructs a variant object holding a float3 value. */ - Variant (Vec3f v) : type(FLOAT3) { f[0] = v.x; f[1] = v.y; f[2] = v.z; } - - /*! Constructs a variant object holding a float4 value. */ - Variant (Vec4f v) : type(FLOAT4) { f[0] = v.x; f[1] = v.y; f[2] = v.z; f[3] = v.w; } - - /*! Constructs a variant object holding a string value. */ - Variant (const char* str) : type(STRING), str(str) {} - - /*! Constructs a variant object holding a string value. */ - Variant (const std::string& str) : type(STRING), str(str) {} - - /*! Constructs a variant object holding a texture value. */ - Variant (const Texture* tex) : type(TEXTURE) { texture = tex; } - - /*! Extracts a boolean from the variant type. */ - bool getBool () const { return b[0]; } - - /*! Extracts an integer from the variant type. */ - int getInt () const { return i[0]; } - - /*! Extracts a float from the variant type. */ - float getFloat() const { return f[0]; } - - /*! Extracts a Vec2f from the variant type. */ - Vec2f getVec2f() const { return Vec2f(f[0],f[1]); } - - /*! Extracts a Vec3f from the variant type. */ - Vec3f getVec3f() const { return Vec3f(f[0],f[1],f[2]); } - - /*! Extracts a Vec3fa from the variant type. */ - Vec3f getVec3fa() const { return Vec3fa(f[0],f[1],f[2]); } - - /*! Extracts a string from the variant type. */ - std::string getString() const { return str; } - - /*! Extracts a texture from the variant type. */ - const Texture* getTexture() const { return texture; } - - operator bool() const { - return type != EMPTY; - } - - public: - Type type; //!< Type of the data contained in the variant. - union { - bool b[4]; //!< Storage for single bool,bool2,bool3, and bool4 values. - int i[4]; //!< Storage for single int,int2,int3, and int4 values. - float f[12]; //!< Storage for single float,float2,float3, float4, and AffineSpace3f values. - const Texture* texture; - }; - std::string str; //!< Storage for string values. - }; - - /*! Parameter container. Implements parameter container as a mapping - * from a string to variant values. This container is used to pass - * parameters for constructing objects from the API to the - * constructors of that objects. All the extraction functions - * return a default values in case the parameter is not found. */ - class Parms - { - public: - - /*! clears the parameter container */ - void clear() { - m.clear(); - } - - /*! Extracts a named boolean out of the container. */ - bool getBool(const char* name, bool def = false) const { - std::map::const_iterator i = m.find(name); - if (i == m.end() || (*i).second.type != Variant::BOOL1) return def; - return (*i).second.getBool(); - } - - /*! Extracts a named integer out of the container. */ - int getInt(const char* name, int def = zero) const { - std::map::const_iterator i = m.find(name); - if (i == m.end() || (*i).second.type != Variant::INT1) return def; - return (*i).second.getInt(); - } - - /*! Extracts a named float out of the container. */ - float getFloat(const char* name, float def = zero) const { - std::map::const_iterator i = m.find(name); - if (i == m.end() || (*i).second.type != Variant::FLOAT1) return def; - return (*i).second.getFloat(); - } - - /*! Extracts a named Vec2f out of the container. */ - Vec2f getVec2f(const char* name, const Vec2f& def = zero) const { - std::map::const_iterator i = m.find(name); - if (i == m.end() || (*i).second.type != Variant::FLOAT2) return def; - return (*i).second.getVec2f(); - } - - /*! Extracts a named Vec3f out of the container. */ - Vec3f getVec3f(const char* name, const Vec3f& def = zero) const { - std::map::const_iterator i = m.find(name); - if (i == m.end() || (*i).second.type != Variant::FLOAT3) return def; - return (*i).second.getVec3f(); - } - - /*! Extracts a named Vec3f out of the container. */ - Vec3fa getVec3fa(const char* name, const Vec3fa& def = zero) const { - std::map::const_iterator i = m.find(name); - if (i == m.end() || (*i).second.type != Variant::FLOAT3) return def; - return (*i).second.getVec3fa(); - } - - /*! Extracts a named string out of the container. */ - std::string getString(const char* name, std::string def = "") const { - std::map::const_iterator i = m.find(name); - if (i == m.end() || (*i).second.type != Variant::STRING) return def; - return (*i).second.getString(); - } - - /*! Extracts a named texture out of the container. */ - const Texture* getTexture(const char* name) const { - std::map::const_iterator i = m.find(name); - if (i == m.end() || (*i).second.type != Variant::TEXTURE) return nullptr; - return (*i).second.getTexture(); - } - - /*! Adds a new named element to the container. */ - void add(const std::string& name, Variant data) { - m[name] = data; - } - - private: - - /*! Implementation of the container as an STL map. */ - std::map m; - }; - - class XMLLoader - { - public: - - static Ref load(const FileName& fileName, const AffineSpace3fa& space); - XMLLoader(const FileName& fileName, const AffineSpace3fa& space); - ~XMLLoader(); - - public: - std::shared_ptr loadTextureParm(const Ref& xml); - Parms loadMaterialParms(const Ref& parms); - Ref addMaterial(const std::string& type, const Parms& parms); - - public: - Ref loadPointLight(const Ref& xml); - Ref loadSpotLight(const Ref& xml); - Ref loadDirectionalLight(const Ref& xml); - Ref loadDistantLight(const Ref& xml); - Ref loadAmbientLight(const Ref& xml); - Ref loadTriangleLight(const Ref& xml); - Ref loadQuadLight(const Ref& xml); - Ref loadHDRILight(const Ref& xml); - - Ref loadTriangleMesh(const Ref& xml); - Ref loadQuadMesh(const Ref& xml); - Ref loadSubdivMesh(const Ref& xml); - Ref loadLineSegments(const Ref& xml); - Ref loadBezierCurves(const Ref& xml, bool hair); - Ref loadBSplineCurves(const Ref& xml, bool hair); - - private: - Ref loadMaterial(const Ref& xml); - Ref loadTransformNode(const Ref& xml); - Ref loadTransform2Node(const Ref& xml); - Ref loadTransformAnimationNode(const Ref& xml); - Ref loadAnimation2Node(const Ref& xml); - Ref loadAnimationNode(const Ref& xml); - Ref loadGroupNode(const Ref& xml); - Ref loadNode(const Ref& xml); - - private: - Ref loadBGFMaterial(const Ref& xml); - Ref loadBGFMesh(const Ref& xml); - Ref loadBGFTransformNode(const Ref& xml); - Ref loadBGFGroupNode(const Ref& xml); - Ref loadBGFNode(const Ref& xml); - - private: - template T load(const Ref& xml) { assert(false); return T(zero); } - template T load(const Ref& xml, const T& opt) { assert(false); return T(zero); } - template Vector loadBinary(const Ref& xml); - - std::vector loadFloatArray(const Ref& xml); - std::vector loadVec2fArray(const Ref& xml); - std::vector loadVec3fArray(const Ref& xml); - avector loadVec3faArray(const Ref& xml); - avector loadVec4fArray(const Ref& xml); - std::vector loadUIntArray(const Ref& xml); - std::vector loadVec2iArray(const Ref& xml); - std::vector loadVec3iArray(const Ref& xml); - std::vector loadVec4iArray(const Ref& xml); - - private: - FileName path; //!< path to XML file - FILE* binFile; //!< .bin file for reading binary data - FileName binFileName; //!< name of the .bin file - size_t binFileSize; - - private: - std::map > materialMap; //!< named materials - std::map, Ref > materialCache; //!< map for detecting repeated materials - std::map > sceneMap; - std::map> textureMap; - - private: - size_t currentNodeID; - std::map > id2node; - std::map > id2material; - - public: - Ref root; - }; - - ////////////////////////////////////////////////////////////////////////////// - //// Loading standard types from an XML node - ////////////////////////////////////////////////////////////////////////////// - - template<> std::string XMLLoader::load(const Ref& xml) { - if (xml->body.size() < 1) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong string body"); - return xml->body[0].String(); - } - - template<> bool XMLLoader::load(const Ref& xml, const bool& opt) { - if (xml == null) return opt; - if (xml->body.size() != 1) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong bool body"); - return xml->body[0].Int() != 0; - } - - template<> int XMLLoader::load(const Ref& xml) { - if (xml->body.size() != 1) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong int body"); - return xml->body[0].Int(); - } - - template<> Vec2i XMLLoader::load(const Ref& xml) { - if (xml->body.size() != 2) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong int2 body"); - return Vec2i(xml->body[0].Int(),xml->body[1].Int()); - } - - template<> Vec3i XMLLoader::load(const Ref& xml) { - if (xml->body.size() != 3) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong int3 body"); - return Vec3i(xml->body[0].Int(),xml->body[1].Int(),xml->body[2].Int()); - } - - template<> Vec4i XMLLoader::load(const Ref& xml) { - if (xml->body.size() != 4) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong int4 body"); - return Vec4i(xml->body[0].Int(),xml->body[1].Int(),xml->body[2].Int(),xml->body[3].Int()); - } - - template<> float XMLLoader::load(const Ref& xml) { - if (xml->body.size() != 1) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong float body"); - return xml->body[0].Float(); - } - - template<> float XMLLoader::load(const Ref& xml, const float& opt) { - if (xml == null) return opt; - if (xml->body.size() != 1) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong float body"); - return xml->body[0].Float(); - } - - template<> Vec2f XMLLoader::load(const Ref& xml) { - if (xml->body.size() != 2) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong float2 body"); - return Vec2f(xml->body[0].Float(),xml->body[1].Float()); - } - - template<> Vec3f XMLLoader::load(const Ref& xml) { - if (xml->body.size() != 3) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong float3 body"); - return Vec3f(xml->body[0].Float(),xml->body[1].Float(),xml->body[2].Float()); - } - - template<> Vec3fa XMLLoader::load(const Ref& xml) { - if (xml->body.size() != 3) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong float3 body"); - return Vec3fa(xml->body[0].Float(),xml->body[1].Float(),xml->body[2].Float()); - } - - template<> Vec3fa XMLLoader::load(const Ref& xml, const Vec3fa& opt) { - if (xml == null) return opt; - if (xml->body.size() != 3) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong float3 body"); - return Vec3fa(xml->body[0].Float(),xml->body[1].Float(),xml->body[2].Float()); - } - - template<> Vec4f XMLLoader::load(const Ref& xml) { - if (xml->body.size() != 4) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong float4 body"); - return Vec4f(xml->body[0].Float(),xml->body[1].Float(),xml->body[2].Float(),xml->body[3].Float()); - } - - template<> AffineSpace3fa XMLLoader::load(const Ref& xml) - { - if (xml->parm("translate") != "") { - float x,y,z; sscanf(xml->parm("translate").c_str(),"%f %f %f",&x,&y,&z); - return AffineSpace3fa::translate(Vec3f(x,y,z)); - } else if (xml->parm("scale") != "") { - float x,y,z; sscanf(xml->parm("scale").c_str(),"%f %f %f",&x,&y,&z); - return AffineSpace3fa::scale(Vec3f(x,y,z)); - } else if (xml->parm("rotate_x") != "") { - float degrees; sscanf(xml->parm("rotate_x").c_str(),"%f",°rees); - return AffineSpace3fa::rotate(Vec3f(1,0,0),deg2rad(degrees)); - } else if (xml->parm("rotate_y") != "") { - float degrees; sscanf(xml->parm("rotate_y").c_str(),"%f",°rees); - return AffineSpace3fa::rotate(Vec3f(0,1,0),deg2rad(degrees)); - } else if (xml->parm("rotate_z") != "") { - float degrees; sscanf(xml->parm("rotate_z").c_str(),"%f",°rees); - return AffineSpace3fa::rotate(Vec3f(0,0,1),deg2rad(degrees)); - } else if (xml->parm("angle") != "" && xml->parm("axis") != "" && xml->parm("point") != "") { - float degrees; sscanf(xml->parm("angle").c_str(),"%f",°rees); - float vx,vy,vz; sscanf(xml->parm("axis" ).c_str(),"%f %f %f",&vx,&vy,&vz); - float px,py,pz; sscanf(xml->parm("point").c_str(),"%f %f %f",&px,&py,&pz); - return AffineSpace3fa::rotate(Vec3f(px,py,pz),Vec3f(vx,vy,vz),deg2rad(degrees)); - } else if (xml->parm("angle") != "" && xml->parm("axis") != "") { - float degrees; sscanf(xml->parm("angle").c_str(),"%f",°rees); - float x,y,z; sscanf(xml->parm("axis").c_str(),"%f %f %f",&x,&y,&z); - return AffineSpace3fa::rotate(Vec3f(x,y,z),deg2rad(degrees)); - } else { - if (xml->body.size() != 12) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong AffineSpace body"); - return AffineSpace3fa(LinearSpace3fa(xml->body[0].Float(),xml->body[1].Float(),xml->body[ 2].Float(), - xml->body[4].Float(),xml->body[5].Float(),xml->body[ 6].Float(), - xml->body[8].Float(),xml->body[9].Float(),xml->body[10].Float()), - Vec3fa(xml->body[3].Float(),xml->body[7].Float(),xml->body[11].Float())); - } - } - - template - Vector XMLLoader::loadBinary(const Ref& xml) - { - if (!binFile) - THROW_RUNTIME_ERROR("cannot open file "+binFileName.str()+" for reading"); - - size_t ofs = atol(xml->parm("ofs").c_str()); - fseek(binFile,long(ofs),SEEK_SET); - - /* read size of array */ - size_t size = atol(xml->parm("size").c_str()); - if (size == 0) size = atol(xml->parm("num").c_str()); // version for BGF format - - /* perform security check that we stay in the file */ - if (ofs + size*sizeof(typename Vector::value_type) > binFileSize) - THROW_RUNTIME_ERROR("error reading from binary file: "+binFileName.str()); - - /* read data from file */ - Vector data(size); - if (size != fread(data.data(), sizeof(typename Vector::value_type), data.size(), binFile)) - THROW_RUNTIME_ERROR("error reading from binary file: "+binFileName.str()); - - return data; - } - - std::vector XMLLoader::loadFloatArray(const Ref& xml) - { - if (!xml) return std::vector(); - - if (xml->parm("ofs") != "") { - return loadBinary>(xml); - } - else - { - std::vector data; - data.resize(xml->body.size()); - for (size_t i=0; ibody[i].Float(); - return data; - } - } - - std::vector XMLLoader::loadVec2fArray(const Ref& xml) - { - if (!xml) return std::vector(); - - if (xml->parm("ofs") != "") { - return loadBinary>(xml); - } - else - { - std::vector data; - if (xml->body.size() % 2 != 0) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong vector body"); - data.resize(xml->body.size()/2); - for (size_t i=0; ibody[2*i+0].Float(),xml->body[2*i+1].Float()); - return data; - } - } - - std::vector XMLLoader::loadVec3fArray(const Ref& xml) - { - if (!xml) return std::vector(); - - if (xml->parm("ofs") != "") { - return loadBinary>(xml); - } - else - { - std::vector data; - if (xml->body.size() % 3 != 0) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong vector body"); - data.resize(xml->body.size()/3); - for (size_t i=0; ibody[3*i+0].Float(),xml->body[3*i+1].Float(),xml->body[3*i+2].Float()); - return data; - } - } - - avector XMLLoader::loadVec3faArray(const Ref& xml) - { - if (!xml) return avector(); - - if (xml->parm("ofs") != "") { - std::vector temp = loadBinary>(xml); - avector data; data.resize(temp.size()); - for (size_t i=0; i data; - if (xml->body.size() % 3 != 0) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong vector body"); - data.resize(xml->body.size()/3); - for (size_t i=0; ibody[3*i+0].Float(),xml->body[3*i+1].Float(),xml->body[3*i+2].Float()); - return data; - } - } - - avector XMLLoader::loadVec4fArray(const Ref& xml) - { - if (!xml) return avector(); - - if (xml->parm("ofs") != "") { - return loadBinary>(xml); - } - else - { - avector data; - if (xml->body.size() % 4 != 0) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong vector body"); - data.resize(xml->body.size()/4); - for (size_t i=0; ibody[4*i+0].Float(),xml->body[4*i+1].Float(),xml->body[4*i+2].Float(),xml->body[4*i+3].Float()); - return data; - } - } - - std::vector XMLLoader::loadUIntArray(const Ref& xml) - { - if (!xml) return std::vector(); - - if (xml->parm("ofs") != "") { - return loadBinary>(xml); - } - else - { - std::vector data; - data.resize(xml->body.size()); - for (size_t i=0; ibody[i].Int(); - return data; - } - } - - std::vector XMLLoader::loadVec2iArray(const Ref& xml) - { - if (!xml) return std::vector(); - - if (xml->parm("ofs") != "") { - return loadBinary>(xml); - } - else - { - std::vector data; - if (xml->body.size() % 2 != 0) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong vector body"); - data.resize(xml->body.size()/2); - for (size_t i=0; ibody[2*i+0].Int(),xml->body[2*i+1].Int()); - return data; - } - } - - std::vector XMLLoader::loadVec3iArray(const Ref& xml) - { - if (!xml) return std::vector(); - - if (xml->parm("ofs") != "") { - return loadBinary>(xml); - } - else - { - std::vector data; - if (xml->body.size() % 3 != 0) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong vector body"); - data.resize(xml->body.size()/3); - for (size_t i=0; ibody[3*i+0].Int(),xml->body[3*i+1].Int(),xml->body[3*i+2].Int()); - return data; - } - } - - std::vector XMLLoader::loadVec4iArray(const Ref& xml) - { - if (!xml) return std::vector(); - - if (xml->parm("ofs") != "") { - return loadBinary>(xml); - } - else - { - std::vector data; - if (xml->body.size() % 4 != 0) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong vector body"); - data.resize(xml->body.size()/4); - for (size_t i=0; ibody[4*i+0].Int(),xml->body[4*i+1].Int(),xml->body[4*i+2].Int(),xml->body[4*i+3].Int()); - return data; - } - } - - ////////////////////////////////////////////////////////////////////////////// - //// Loading of objects from XML file - ////////////////////////////////////////////////////////////////////////////// - - Ref XMLLoader::loadPointLight(const Ref& xml) - { - const AffineSpace3fa space = load(xml->child("AffineSpace")); - const Vec3fa I = load(xml->child("I")); - const Vec3fa P = Vec3fa(zero); - return new SceneGraph::TransformNode(space, new SceneGraph::LightNode(new SceneGraph::PointLight(P,I))); - } - - Ref XMLLoader::loadSpotLight(const Ref& xml) - { - const AffineSpace3fa space = load(xml->child("AffineSpace")); - const Vec3fa I = load(xml->child("I")); - const Vec3fa P = Vec3fa(zero); - const Vec3fa D = Vec3fa(0,0,1); - const float angleMin = load(xml->child("angleMin")); - const float angleMax = load(xml->child("angleMax")); - return new SceneGraph::TransformNode(space, new SceneGraph::LightNode(new SceneGraph::SpotLight(P,D,I,angleMin,angleMax))); - } - - Ref XMLLoader::loadDirectionalLight(const Ref& xml) - { - const AffineSpace3fa space = load(xml->child("AffineSpace")); - const Vec3fa E = load(xml->child("E")); - const Vec3fa D = Vec3fa(0,0,1); - return new SceneGraph::TransformNode(space, new SceneGraph::LightNode(new SceneGraph::DirectionalLight(D,E))); - } - - Ref XMLLoader::loadDistantLight(const Ref& xml) - { - const AffineSpace3fa space = load(xml->child("AffineSpace")); - const Vec3fa L = load(xml->child("L")); - const Vec3fa D = Vec3fa(0,0,1); - const float halfAngle = load(xml->child("halfAngle")); - return new SceneGraph::TransformNode(space, new SceneGraph::LightNode(new SceneGraph::DistantLight(D,L,halfAngle))); - } - - Ref XMLLoader::loadAmbientLight(const Ref& xml) - { - const Vec3fa L = load(xml->child("L")); - return new SceneGraph::LightNode(new SceneGraph::AmbientLight(L)); - } - - Ref XMLLoader::loadTriangleLight(const Ref& xml) - { - const AffineSpace3fa space = load(xml->child("AffineSpace")); - const Vec3fa L = load(xml->child("L")); - const Vec3fa v0 = xfmPoint(space, Vec3fa(1, 0, 0)); - const Vec3fa v1 = xfmPoint(space, Vec3fa(0, 1, 0)); - const Vec3fa v2 = xfmPoint(space, Vec3fa(0, 0, 0)); - return new SceneGraph::LightNode(new SceneGraph::TriangleLight(v0,v1,v2,L)); - } - - Ref XMLLoader::loadQuadLight(const Ref& xml) - { - const AffineSpace3fa space = load(xml->child("AffineSpace")); - const Vec3fa L = load(xml->child("L")); - const Vec3fa v0 = xfmPoint(space, Vec3fa(0, 0, 0)); - const Vec3fa v1 = xfmPoint(space, Vec3fa(0, 1, 0)); - const Vec3fa v2 = xfmPoint(space, Vec3fa(1, 1, 0)); - const Vec3fa v3 = xfmPoint(space, Vec3fa(1, 0, 0)); - return new SceneGraph::LightNode(new SceneGraph::QuadLight(v0,v1,v2,v3,L)); - } - - std::shared_ptr XMLLoader::loadTextureParm(const Ref& xml) - { - static std::vector> g_textures; - - const std::string id = xml->parm("id"); - if (id != "" && textureMap.find(id) != textureMap.end()) - return textureMap[id]; - - std::shared_ptr texture; - const FileName src = xml->parm("src"); - - /*! load texture from file */ - if (src.str() != "") { - texture = std::shared_ptr(Texture::load(path+src)); - } - - /*! load texture from binary file */ - else { - const unsigned width = stoi(xml->parm("width")); - const unsigned height = stoi(xml->parm("height")); - const Texture::Format format = Texture::string_to_format(xml->parm("format")); - const unsigned bytesPerTexel = Texture::getFormatBytesPerTexel(format); - if (ftell(binFile) + width*height*bytesPerTexel > (unsigned)binFileSize) - THROW_RUNTIME_ERROR("error reading from binary file: "+binFileName.str()); - - texture = std::make_shared(width,height,format); - if (width*height != fread(texture->data, bytesPerTexel, width*height, binFile)) - THROW_RUNTIME_ERROR("error reading from binary file: "+binFileName.str()); - g_textures.push_back(texture); // FIXME: we can only free textures at application exit currently - } - - if (id != "") textureMap[id] = texture; - return texture; - } - - Parms XMLLoader::loadMaterialParms(const Ref& parms) - { - Parms material; - for (size_t i=0; isize(); i++) - { - Ref entry = parms->children[i]; - std::string name = entry->parm("name"); - if (entry->name == "int" ) { material.add(name, load (entry)); } - else if (entry->name == "int2" ) { material.add(name, load(entry)); } - else if (entry->name == "int3" ) { material.add(name, load(entry)); } - else if (entry->name == "int4" ) { material.add(name, load(entry)); } - else if (entry->name == "float" ) { material.add(name, load(entry)); } - else if (entry->name == "float2" ) { material.add(name, load(entry)); } - else if (entry->name == "float3" ) { material.add(name, load(entry)); } - else if (entry->name == "float4" ) { material.add(name, load(entry)); } - else if (entry->name == "texture3d") { material.add(name, loadTextureParm(entry).get()); } - else if (entry->name == "param") { - const std::string type = entry->parm("type"); - if (type == "int" ) { material.add(name, load (entry)); } - else if (type == "int2" ) { material.add(name, load(entry)); } - else if (type == "int3" ) { material.add(name, load(entry)); } - else if (type == "int4" ) { material.add(name, load(entry)); } - else if (type == "float" ) { material.add(name, load(entry)); } - else if (type == "float2" ) { material.add(name, load(entry)); } - else if (type == "float3" ) { material.add(name, load(entry)); } - else if (type == "float4" ) { material.add(name, load(entry)); } - else THROW_RUNTIME_ERROR(entry->loc.str()+": invalid param type: "+type); - } - } - return material; - } - - Ref XMLLoader::loadMaterial(const Ref& xml) - { - const std::string id = xml->parm("id"); - if (id != "" && materialMap.find(id) != materialMap.end()) - return materialMap[id]; - - Ref parameters = xml->child("parameters"); - if (materialCache.find(parameters) != materialCache.end()) { - return materialMap[id] = materialCache[parameters]; - } - - std::string type = load(xml->child("code")).c_str(); - Parms parms = loadMaterialParms(parameters); - Ref material = addMaterial(type,parms); - materialCache[parameters] = material; - return materialMap[id] = material; - } - - Ref XMLLoader::addMaterial(const std::string& type, const Parms& parms) - { - Material material; - if (type == "Matte") - { - const Vec3fa reflectance = parms.getVec3fa("reflectance",one); - new (&material) MatteMaterial(reflectance); - } - else if (type == "Mirror") - { - const Vec3fa reflectance = parms.getVec3fa("reflectance",one); - new (&material) MirrorMaterial(reflectance); - } - else if (type == "OBJ") - { - const Texture* map_d = parms.getTexture("map_d"); - const float d = parms.getFloat("d", 1.0f); - const Texture* map_Kd = parms.getTexture("map_Kd"); - const Vec3fa Kd = parms.getVec3fa("Kd", one); - const Texture* map_Ks = parms.getTexture("map_Ks"); - const Vec3fa Ks = parms.getVec3fa("Ks", zero); - const Texture* map_Ns = parms.getTexture("map_Ns"); - const float Ns = parms.getFloat("Ns", 10.0f); - const Texture* map_Bump = parms.getTexture("map_Bump"); - new (&material) OBJMaterial(d,map_d,Kd,map_Kd,Ks,map_Ks,Ns,map_Ns,map_Bump); - } - else if (type == "OBJMaterial") // for BGF file format - { - //map_d = parms.getTexture("map_d"); - const float d = parms.getFloat("d", 1.0f); - //map_Kd = parms.getTexture("map_kd"); - const Vec3fa Kd = parms.getVec3fa("kd", one); - //map_Ks = parms.getTexture("map_ks"); - const Vec3fa Ks = parms.getVec3fa("ks", zero); - //map_Ns = parms.getTexture("map_ns"); - const float Ns = parms.getFloat("ns", 10.0f); - //map_Bump = parms.getTexture("map_Bump"); - new (&material) OBJMaterial(d,Kd,Ks,Ns); - } - else if (type == "ThinDielectric" || type == "ThinGlass") - { - const Vec3fa transmission = parms.getVec3fa("transmission",one); - const float eta = parms.getFloat("eta",1.4f); - const float thickness = parms.getFloat("thickness",0.1f); - new (&material) ThinDielectricMaterial(transmission,eta,thickness); - } - else if (type == "Plastic") - { - const Vec3fa pigmentColor = parms.getVec3fa("pigmentColor",one); - const float eta = parms.getFloat("eta",1.4f); - const float roughness = parms.getFloat("roughness",0.01f); - new (&material) MetallicPaintMaterial(pigmentColor,pigmentColor,roughness,eta); - } - else if (type == "Metal") - { - const Vec3fa reflectance = parms.getVec3fa("reflectance",one); - const Vec3fa eta = parms.getVec3fa("eta",Vec3fa(1.4f)); - const Vec3fa k = parms.getVec3fa("k",Vec3fa(0.0f)); - const float roughness = parms.getFloat("roughness",0.01f); - if (roughness == 0.0f) - new (&material) MetalMaterial(reflectance,eta,k); - else - new (&material) MetalMaterial(reflectance,eta,k,roughness); - } - else if (type == "Velvet") - { - const Vec3fa reflectance = parms.getVec3fa("reflectance",one); - const float backScattering = parms.getFloat("backScattering",zero); - const Vec3fa horizonScatteringColor = parms.getVec3fa("horizonScatteringColor",one); - const float horizonScatteringFallOff = parms.getFloat("horizonScatteringFallOff",zero); - new (&material) VelvetMaterial(reflectance,backScattering,horizonScatteringColor,horizonScatteringFallOff); - } - else if (type == "Dielectric") - { - const Vec3fa transmissionOutside = parms.getVec3fa("transmissionOutside",one); - const Vec3fa transmissionInside = parms.getVec3fa("transmission",one); - const float etaOutside = parms.getFloat("etaOutside",1.0f); - const float etaInside = parms.getFloat("etaInside",1.4f); - new (&material) DielectricMaterial(transmissionOutside,transmissionInside,etaOutside,etaInside); - } - else if (type == "MetallicPaint") - { - const Vec3fa shadeColor = parms.getVec3fa("shadeColor",one); - const Vec3fa glitterColor = parms.getVec3fa("glitterColor",zero); - const float glitterSpread = parms.getFloat("glitterSpread",1.0f); - const float eta = parms.getFloat("eta",1.4f); - new (&material) MetallicPaintMaterial(shadeColor,glitterColor,glitterSpread,eta); - } - else if (type == "Hair") - { - const Vec3fa Kr = parms.getVec3fa("Kr",one); - const Vec3fa Kt = parms.getVec3fa("Kt",zero); - const float nx = parms.getFloat("nx",20.0f); - const float ny = parms.getFloat("ny",2.0f); - new (&material) HairMaterial(Kr,Kt,nx,ny); - } - else { - std::cout << "Warning: unsupported material " << type << std::endl; - new (&material) OBJMaterial(1.0f,Vec3fa(0.5f),Vec3fa(0.0f),0.0f); - } - return new SceneGraph::MaterialNode(material); - } - - Ref XMLLoader::loadTriangleMesh(const Ref& xml) - { - Ref material = loadMaterial(xml->child("material")); - SceneGraph::TriangleMeshNode* mesh = new SceneGraph::TriangleMeshNode(material); - - if (Ref animation = xml->childOpt("animated_positions")) { - for (size_t i=0; isize(); i++) - mesh->positions.push_back(loadVec3faArray(animation->child(i))); - } else { - mesh->positions.push_back(loadVec3faArray(xml->childOpt("positions"))); - if (xml->hasChild("positions2")) - mesh->positions.push_back(loadVec3faArray(xml->childOpt("positions2"))); - } - - mesh->normals = loadVec3faArray(xml->childOpt("normals")); - mesh->texcoords = loadVec2fArray(xml->childOpt("texcoords")); - - std::vector triangles = loadVec3iArray(xml->childOpt("triangles")); - for (size_t i=0; itriangles.push_back(SceneGraph::TriangleMeshNode::Triangle(triangles[i].x,triangles[i].y,triangles[i].z)); - - mesh->verify(); - return mesh; - } - - Ref XMLLoader::loadQuadMesh(const Ref& xml) - { - Ref material = loadMaterial(xml->child("material")); - SceneGraph::QuadMeshNode* mesh = new SceneGraph::QuadMeshNode(material); - - if (Ref animation = xml->childOpt("animated_positions")) { - for (size_t i=0; isize(); i++) - mesh->positions.push_back(loadVec3faArray(animation->child(i))); - } else { - mesh->positions.push_back(loadVec3faArray(xml->childOpt("positions"))); - if (xml->hasChild("positions2")) - mesh->positions.push_back(loadVec3faArray(xml->childOpt("positions2"))); - } - - mesh->normals = loadVec3faArray(xml->childOpt("normals")); - mesh->texcoords = loadVec2fArray(xml->childOpt("texcoords")); - - std::vector indices = loadVec4iArray(xml->childOpt("indices")); - for (size_t i=0; iquads.push_back(SceneGraph::QuadMeshNode::Quad(indices[i].x,indices[i].y,indices[i].z,indices[i].w)); - mesh->verify(); - return mesh; - } - - RTCSubdivisionMode parseSubdivMode(const Ref& xml) - { - std::string subdiv_mode = xml->parm("subdiv_mode"); - if (subdiv_mode == "no_boundary" ) return RTC_SUBDIV_NO_BOUNDARY; - else if (subdiv_mode == "smooth" ) return RTC_SUBDIV_SMOOTH_BOUNDARY; - else if (subdiv_mode == "pin_corners" ) return RTC_SUBDIV_PIN_CORNERS; - else if (subdiv_mode == "pin_boundary") return RTC_SUBDIV_PIN_BOUNDARY; - else if (subdiv_mode == "pin_all" ) return RTC_SUBDIV_PIN_ALL; - else if (subdiv_mode != "" ) THROW_RUNTIME_ERROR("invalid subdivision mode: "+subdiv_mode); - return RTC_SUBDIV_SMOOTH_BOUNDARY; - } - - Ref XMLLoader::loadSubdivMesh(const Ref& xml) - { - Ref material = loadMaterial(xml->child("material")); - SceneGraph::SubdivMeshNode* mesh = new SceneGraph::SubdivMeshNode(material); - - if (Ref animation = xml->childOpt("animated_positions")) { - for (size_t i=0; isize(); i++) - mesh->positions.push_back(loadVec3faArray(animation->child(i))); - } else { - mesh->positions.push_back(loadVec3faArray(xml->childOpt("positions"))); - if (xml->hasChild("positions2")) - mesh->positions.push_back(loadVec3faArray(xml->childOpt("positions2"))); - } - mesh->normals = loadVec3faArray(xml->childOpt("normals")); - mesh->texcoords = loadVec2fArray(xml->childOpt("texcoords")); - - if (Ref child = xml->childOpt("position_indices")) { - mesh->position_indices = loadUIntArray(child); - mesh->position_subdiv_mode = parseSubdivMode(child); - } - if (Ref child = xml->childOpt("normal_indices")) { - mesh->normal_indices = loadUIntArray(child); - mesh->normal_subdiv_mode = parseSubdivMode(child); - } - if (Ref child = xml->childOpt("texcoord_indices")) { - mesh->texcoord_indices = loadUIntArray(child); - mesh->texcoord_subdiv_mode = parseSubdivMode(child); - } - - mesh->verticesPerFace = loadUIntArray(xml->childOpt("faces")); - mesh->holes = loadUIntArray(xml->childOpt("holes")); - mesh->edge_creases = loadVec2iArray(xml->childOpt("edge_creases")); - mesh->edge_crease_weights = loadFloatArray(xml->childOpt("edge_crease_weights")); - mesh->vertex_creases = loadUIntArray(xml->childOpt("vertex_creases")); - mesh->vertex_crease_weights = loadFloatArray(xml->childOpt("vertex_crease_weights")); - mesh->verify(); - return mesh; - } - - Ref XMLLoader::loadLineSegments(const Ref& xml) - { - Ref material = loadMaterial(xml->child("material")); - SceneGraph::LineSegmentsNode* mesh = new SceneGraph::LineSegmentsNode(material); - - if (Ref animation = xml->childOpt("animated_positions")) { - for (size_t i=0; isize(); i++) - mesh->positions.push_back(loadVec4fArray(animation->child(i))); - } else { - mesh->positions.push_back(loadVec4fArray(xml->childOpt("positions"))); - if (xml->hasChild("positions2")) - mesh->positions.push_back(loadVec4fArray(xml->childOpt("positions2"))); - } - - mesh->indices = loadUIntArray(xml->childOpt("indices")); - mesh->verify(); - return mesh; - } - - avector convert_bspline_to_bezier(const std::vector& indices, const avector& positions) - { - avector positions_o; - positions_o.resize(4*indices.size()); - for (size_t i=0; i XMLLoader::loadBezierCurves(const Ref& xml, bool hair) - { - Ref material = loadMaterial(xml->child("material")); - SceneGraph::HairSetNode* mesh = new SceneGraph::HairSetNode(hair,material); - - if (Ref animation = xml->childOpt("animated_positions")) { - for (size_t i=0; isize(); i++) - mesh->positions.push_back(loadVec4fArray(animation->child(i))); - } else { - mesh->positions.push_back(loadVec4fArray(xml->childOpt("positions"))); - if (xml->hasChild("positions2")) - mesh->positions.push_back(loadVec4fArray(xml->childOpt("positions2"))); - } - - std::vector indices = loadVec2iArray(xml->childOpt("indices")); - mesh->hairs.resize(indices.size()); - for (size_t i=0; ihairs[i] = SceneGraph::HairSetNode::Hair(indices[i].x,indices[i].y); - - std::string tessellation_rate = xml->parm("tessellation_rate"); - if (tessellation_rate != "") - mesh->tessellation_rate = atoi(tessellation_rate.c_str()); - - mesh->verify(); - return mesh; - } - - Ref XMLLoader::loadBSplineCurves(const Ref& xml, bool hair) - { - Ref material = loadMaterial(xml->child("material")); - SceneGraph::HairSetNode* mesh = new SceneGraph::HairSetNode(hair,material); - - std::vector indices = loadUIntArray(xml->childOpt("indices")); - mesh->hairs.resize(indices.size()); - for (size_t i=0; ihairs[i] = SceneGraph::HairSetNode::Hair(unsigned(4*i),0); - } - - if (Ref animation = xml->childOpt("animated_positions")) { - for (size_t i=0; isize(); i++) - mesh->positions.push_back(convert_bspline_to_bezier(indices,loadVec4fArray(animation->child(i)))); - } else { - mesh->positions.push_back(convert_bspline_to_bezier(indices,loadVec4fArray(xml->childOpt("positions")))); - if (xml->hasChild("positions2")) - mesh->positions.push_back(convert_bspline_to_bezier(indices,loadVec4fArray(xml->childOpt("positions2")))); - } - - mesh->verify(); - return mesh; - } - - Ref XMLLoader::loadTransformNode(const Ref& xml) - { - AffineSpace3fa space = load(xml->children[0]); - - Ref group = new SceneGraph::GroupNode; - for (size_t i=1; isize(); i++) - group->add(loadNode(xml->children[i])); - - return new SceneGraph::TransformNode(space,group.cast()); - } - - Ref XMLLoader::loadTransform2Node(const Ref& xml) - { - AffineSpace3fa space0 = load(xml->children[0]); - AffineSpace3fa space1 = load(xml->children[1]); - - Ref group = new SceneGraph::GroupNode; - for (size_t i=2; isize(); i++) - group->add(loadNode(xml->children[i])); - - return new SceneGraph::TransformNode(space0,space1,group.cast()); - } - - Ref XMLLoader::loadTransformAnimationNode(const Ref& xml) - { - if (xml->size() < 2) THROW_RUNTIME_ERROR(xml->loc.str()+": invalid TransformAnimation node"); - - avector spaces(xml->size()-1); - for (size_t i=0; isize()-1; i++) - spaces[i] = load(xml->children[i]); - - Ref child = loadNode(xml->children[xml->size()-1]); - return new SceneGraph::TransformNode(spaces,child); - } - - Ref XMLLoader::loadAnimation2Node(const Ref& xml) - { - if (xml->size() != 2) THROW_RUNTIME_ERROR(xml->loc.str()+": invalid Animation2 node"); - Ref node0 = loadNode(xml->children[0]); - Ref node1 = loadNode(xml->children[1]); - SceneGraph::extend_animation(node0,node1); - SceneGraph::optimize_animation(node0); - return node0; - } - - Ref XMLLoader::loadAnimationNode(const Ref& xml) - { - if (xml->size() == 0) THROW_RUNTIME_ERROR(xml->loc.str()+": invalid Animation node"); - Ref node = loadNode(xml->children[0]); - for (size_t i=1; isize(); i++) { - Ref nodei = loadNode(xml->children[i]); - SceneGraph::extend_animation(node,nodei); - } - SceneGraph::optimize_animation(node); - return node; - } - - Ref XMLLoader::loadGroupNode(const Ref& xml) - { - Ref group = new SceneGraph::GroupNode; - for (size_t i=0; isize(); i++) - group->add(loadNode(xml->children[i])); - return group.cast(); - } - - Ref XMLLoader::loadNode(const Ref& xml) - { - if (xml->name == "assign") - { - if (xml->parm("type") == "material") - { - Ref material = loadMaterial(xml->child(0)); - materialMap[xml->parm("id")] = material; - return nullptr; - } - else if (xml->parm("type") == "scene") - { - sceneMap[xml->parm("id")] = loadNode(xml->child(0)); - return nullptr; - } - else - THROW_RUNTIME_ERROR(xml->loc.str()+": unknown type: "+xml->parm("type")); - } - else - { - const std::string id = xml->parm("id"); - if (xml->name == "extern" ) - return sceneMap[id] = SceneGraph::load(path + xml->parm("src")); - else if (xml->name == "extern_combine" ) - return sceneMap[id] = SceneGraph::load(path + xml->parm("src"),true); - else if (xml->name == "obj" ) { - const bool subdiv_mode = xml->parm("subdiv") == "1"; - return sceneMap[id] = loadOBJ(path + xml->parm("src"),subdiv_mode); - } - else if (xml->name == "ref" ) return sceneMap[id] = sceneMap[xml->parm("id")]; - else if (xml->name == "PointLight" ) return sceneMap[id] = loadPointLight (xml); - else if (xml->name == "SpotLight" ) return sceneMap[id] = loadSpotLight (xml); - else if (xml->name == "DirectionalLight") return sceneMap[id] = loadDirectionalLight(xml); - else if (xml->name == "DistantLight" ) return sceneMap[id] = loadDistantLight (xml); - else if (xml->name == "AmbientLight" ) return sceneMap[id] = loadAmbientLight (xml); - else if (xml->name == "TriangleLight" ) return sceneMap[id] = loadTriangleLight (xml); - else if (xml->name == "QuadLight" ) return sceneMap[id] = loadQuadLight (xml); - else if (xml->name == "TriangleMesh" ) return sceneMap[id] = loadTriangleMesh (xml); - else if (xml->name == "QuadMesh" ) return sceneMap[id] = loadQuadMesh (xml); - else if (xml->name == "SubdivisionMesh" ) return sceneMap[id] = loadSubdivMesh (xml); - else if (xml->name == "LineSegments" ) return sceneMap[id] = loadLineSegments (xml); - else if (xml->name == "Hair" ) return sceneMap[id] = loadBezierCurves (xml,true); - else if (xml->name == "BezierHair" ) return sceneMap[id] = loadBezierCurves (xml,true); - else if (xml->name == "BSplineHair" ) return sceneMap[id] = loadBSplineCurves (xml,true); - else if (xml->name == "BezierCurves" ) return sceneMap[id] = loadBezierCurves (xml,false); - else if (xml->name == "BSplineCurves" ) return sceneMap[id] = loadBSplineCurves (xml,false); - else if (xml->name == "Group" ) return sceneMap[id] = loadGroupNode (xml); - else if (xml->name == "Transform" ) return sceneMap[id] = loadTransformNode (xml); - else if (xml->name == "Transform2" ) return sceneMap[id] = loadTransform2Node (xml); - else if (xml->name == "TransformAnimation") return sceneMap[id] = loadTransformAnimationNode(xml); - else if (xml->name == "Animation2" ) return sceneMap[id] = loadAnimation2Node (xml); - else if (xml->name == "Animation" ) return sceneMap[id] = loadAnimationNode (xml); - - else if (xml->name == "ConvertTrianglesToQuads") return convert_triangles_to_quads(sceneMap[id] = loadNode(xml->child(0))); - else if (xml->name == "ConvertQuadsToSubdivs" ) return convert_quads_to_subdivs (sceneMap[id] = loadNode(xml->child(0))); - else if (xml->name == "ConvertBezierToLines" ) return convert_bezier_to_lines (sceneMap[id] = loadNode(xml->child(0))); - else if (xml->name == "ConvertHairToCurves" ) return convert_hair_to_curves (sceneMap[id] = loadNode(xml->child(0))); - else if (xml->name == "Flatten" ) return flatten (sceneMap[id] = loadNode(xml->child(0))); - - else THROW_RUNTIME_ERROR(xml->loc.str()+": unknown tag: "+xml->name); - } - - return nullptr; - } - - /*******************************************************************************************/ - - Ref XMLLoader::loadBGFMaterial(const Ref& xml) - { - std::string type = xml->parm("type"); - std::string name = xml->parm("name"); - Parms parms = loadMaterialParms(xml); - return addMaterial(type,parms); - } - - Ref XMLLoader::loadBGFMesh(const Ref& xml) - { - size_t matid = xml->child("materiallist")->body[0].Int(); - Ref material = id2material.at(matid); - SceneGraph::TriangleMeshNode* mesh = new SceneGraph::TriangleMeshNode(material); - - mesh->positions.push_back(loadVec3faArray(xml->childOpt("vertex"))); - mesh->normals = loadVec3faArray(xml->childOpt("normal")); - mesh->texcoords = loadVec2fArray(xml->childOpt("texcoord")); - - std::vector triangles = loadVec4iArray(xml->childOpt("prim")); - for (size_t i=0; itriangles.push_back(SceneGraph::TriangleMeshNode::Triangle(triangles[i].x,triangles[i].y,triangles[i].z)); - - return mesh; - } - - Ref XMLLoader::loadBGFTransformNode(const Ref& xml) - { - const size_t child = atoi(xml->parm("child").c_str()); - if (xml->body.size() != 12) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong AffineSpace body"); - const AffineSpace3fa space(LinearSpace3fa(Vec3fa(xml->body[0].Float(),xml->body[1].Float(),xml->body[2].Float()), - Vec3fa(xml->body[3].Float(),xml->body[4].Float(),xml->body[5].Float()), - Vec3fa(xml->body[6].Float(),xml->body[7].Float(),xml->body[8].Float())), - Vec3fa(xml->body[9].Float(),xml->body[10].Float(),xml->body[11].Float())); - return new SceneGraph::TransformNode(space,id2node.at(child)); - } - - Ref XMLLoader::loadBGFGroupNode(const Ref& xml) - { - const size_t N = atoi(xml->parm("numChildren").c_str()); - if (xml->body.size() != N) - THROW_RUNTIME_ERROR(xml->loc.str()+": invalid group node"); - - Ref group = new SceneGraph::GroupNode(N); - for (size_t i=0; ibody[i].Int(); - group->set(i,id2node.at(id)); - } - return group.cast(); - } - - Ref XMLLoader::loadBGFNode(const Ref& xml) - { - //const size_t id = atoi(xml->parm("id").c_str()); - const size_t id = currentNodeID++; - - if (xml->name == "Mesh" ) return id2node[id] = loadBGFMesh(xml); - else if (xml->name == "Group" ) return id2node[id] = loadBGFGroupNode(xml); - else if (xml->name == "Transform") return id2node[id] = loadBGFTransformNode(xml); - else if (xml->name == "Material" ) - { - Ref material = loadBGFMaterial(xml); - id2material[id] = material; - return material.cast(); - } - else if (xml->name == "Texture2D") { - // textures not implemented yet - return new SceneGraph::GroupNode(); - } - else THROW_RUNTIME_ERROR(xml->loc.str()+": unknown tag: "+xml->name); - } - - /*******************************************************************************************/ - - - Ref XMLLoader::load(const FileName& fileName, const AffineSpace3fa& space) { - XMLLoader loader(fileName,space); return loader.root; - } - - XMLLoader::XMLLoader(const FileName& fileName, const AffineSpace3fa& space) : binFile(nullptr), binFileSize(0), currentNodeID(0) - { - path = fileName.path(); - binFileName = fileName.setExt(".bin"); - binFile = fopen(binFileName.c_str(),"rb"); - if (!binFile) { - binFileName = fileName.addExt(".bin"); - binFile = fopen(binFileName.c_str(),"rb"); - } - if (binFile) { - fseek(binFile, 0L, SEEK_END); - binFileSize = ftell(binFile); - fseek(binFile, 0L, SEEK_SET); - } - - Ref xml = parseXML(fileName); - if (xml->name == "scene") - { - Ref group = new SceneGraph::GroupNode; - for (size_t i=0; isize(); i++) { - group->add(loadNode(xml->children[i])); - } - root = group.cast(); - } - else if (xml->name == "BGFscene") - { - Ref last = nullptr; - for (size_t i=0; isize(); i++) { - root = loadBGFNode(xml->children[i]); - } - } - else - THROW_RUNTIME_ERROR(xml->loc.str()+": invalid scene tag"); - - if (space == AffineSpace3fa(one)) - return; - - root = new SceneGraph::TransformNode(space,root); - } - - XMLLoader::~XMLLoader() { - if (binFile) fclose(binFile); - } - - /*! read from disk */ - Ref SceneGraph::loadXML(const FileName& fileName, const AffineSpace3fa& space) { - return XMLLoader::load(fileName,space); - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/xml_loader.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/xml_loader.h deleted file mode 100644 index 55c8f3d71c57..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/xml_loader.h +++ /dev/null @@ -1,28 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "scenegraph.h" - -namespace embree -{ - namespace SceneGraph - { - Ref loadXML(const FileName& fileName, const AffineSpace3fa& space = one); - } -} - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/xml_parser.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/xml_parser.cpp deleted file mode 100644 index 94bb151a63fe..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/xml_parser.cpp +++ /dev/null @@ -1,202 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "xml_parser.h" - -#include - -namespace embree -{ - ////////////////////////////////////////////////////////////////////////////// - /// XML Input - ////////////////////////////////////////////////////////////////////////////// - - /*! parse a list of XML comments */ - void parseComments(Ref >& cin) - { - while (cin->peek() == Token::Sym("")) cin->drop(); - cin->drop(); - } - } - - /*! parse XML parameter */ - void parseParm(Ref >& cin, std::map& parms) - { - std::string name = cin->get().Identifier(); - if (cin->get() != Token::Sym("=")) THROW_RUNTIME_ERROR(cin->unget().Location().str()+": symbol \"=\" expected"); - parms[name] = cin->get().String(); - } - - /*! parse XML header */ - Ref parseHeader(Ref >& cin) - { - Ref xml = new XML; - if (cin->get() != Token::Sym("unget().Location().str()+": wrong XML header"); - xml->name = cin->get().Identifier(); - parseComments(cin); - while (cin->peek() != Token::Sym("?>")) { - parseParm(cin,xml->parms); - parseComments(cin); - } - cin->drop(); - return xml; - } - - /*! parse XML tag */ - Ref parseXML(Ref >& cin) - { - Ref xml = new XML; - xml->loc = cin->peek().Location(); - - /* parse tag opening */ - if (cin->get() != Token::Sym("<")) THROW_RUNTIME_ERROR(cin->unget().Location().str()+": tag expected"); - - xml->name = cin->get().Identifier(); - parseComments(cin); - while (cin->peek() != Token::Sym("/>") && cin->peek() != Token::Sym(">")) { - parseParm(cin,xml->parms); - parseComments(cin); - } - if (cin->peek() == Token::Sym("/>")) { - cin->drop(); - return xml; - } - cin->drop(); - - /* parse body token list */ - parseComments(cin); - while (cin->peek() != Token::Sym("<") && cin->peek() != Token::Sym("body.push_back(cin->get()); - parseComments(cin); - } - - /* the body also contains children */ - if (cin->peek() == Token::Sym("<")) { - while (cin->peek() != Token::Sym("children.push_back(parseXML(cin)); - parseComments(cin); - } - } - - /* parse tag closing */ - if (cin->get() != Token::Sym("unget().Location().str()+": symbol \"get() != Token::Id(xml->name)) THROW_RUNTIME_ERROR(cin->unget().Location().str()+": closing "+xml->name+" expected"); - if (cin->get() != Token::Sym(">") ) THROW_RUNTIME_ERROR(cin->unget().Location().str()+": symbol \">\" expected"); - - return xml; - } - - /* load XML from token stream */ - Ref parseXML(Ref > chars, std::string id, bool hasHeader = true, bool hasTail = false) - { - /* create lexer for XML file */ - std::vector symbols; - symbols.push_back(""); - symbols.push_back(""); - symbols.push_back(""); - symbols.push_back("<"); - symbols.push_back(">"); - symbols.push_back("="); - Ref > cin = new TokenStream(chars,TokenStream::alpha + TokenStream::ALPHA + "_" + id, TokenStream::separators, symbols); - - if (hasHeader) parseHeader(cin); - parseComments(cin); - Ref xml = parseXML(cin); - parseComments(cin); - - if (!hasTail) - if (cin->peek() != Token::Eof()) THROW_RUNTIME_ERROR(cin->peek().Location().str()+": end of file expected"); - - return xml; - } - - /*! load XML file from stream */ - std::istream& operator>>(std::istream& cin, Ref& xml) { - xml = parseXML(new StdStream(cin),"",false,true); - return cin; - } - - /*! load XML file from disk */ - Ref parseXML(const FileName& fileName, std::string id, bool hasHeader) { - return parseXML(new FileStream(fileName),id,hasHeader,false); - } - - - ////////////////////////////////////////////////////////////////////////////// - /// XML Output - ////////////////////////////////////////////////////////////////////////////// - - - /* indent to some hierarchy level using spaces */ - void indent(std::ostream& cout, size_t depth) { - for (size_t i=0; i<2*depth; i++) cout << " "; - } - - /* store XML to a stream */ - std::ostream& emitXML(std::ostream& cout, const Ref& xml, size_t depth = 0) - { - /* print header */ - if (depth == 0) cout << "" << std::endl << std::endl; - - /* print tag opening */ - indent(cout,depth); cout << "<" << xml->name; - for (std::map::const_iterator i=xml->parms.begin(); i!=xml->parms.end(); i++) - cout << " " << i->first << "=" << "\"" << i->second << "\""; - if (xml->children.size() == 0 && xml->body.size() == 0) { - cout << "/>" << std::endl; - return cout; - } - cout << ">"; - - bool compact = xml->body.size() < 16 && xml->children.size() == 0; - if (!compact) cout << std::endl; - - /* print token list */ - if (xml->body.size()) { - if (!compact) indent(cout,depth+1); - for (size_t i=0; ibody.size(); i++) - cout << xml->body[i] << (i!=xml->body.size()-1?" ":""); - if (!compact) cout << std::endl; - } - - /* print children */ - for (size_t i=0; ichildren.size(); i++) - emitXML(cout,xml->children[i],depth+1); - - /* print tag closing */ - if (!compact) indent(cout,depth); - return cout << "name << ">" << std::endl; - } - - /* store XML to stream */ - std::ostream& operator<<(std::ostream& cout, const Ref& xml) { - return emitXML(cout,xml); - } - - /*! store XML to disk */ - void emitXML(const FileName& fileName, const Ref& xml) - { - std::ofstream cout(fileName.c_str()); - if (!cout.is_open()) THROW_RUNTIME_ERROR("cannot open file " + fileName.str() + " for writing"); - emitXML(cout,xml); - cout.close(); - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/xml_parser.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/xml_parser.h deleted file mode 100644 index 7864cb2535b6..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/xml_parser.h +++ /dev/null @@ -1,122 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../default.h" - -namespace embree -{ - /* an XML node */ - class XML : public RefCount - { - public: - XML (const std::string& name = "") : name(name) {} - - /*! returns number of children of XML node */ - size_t size() const { return children.size(); } - - /*! checks if child with specified node tag exists */ - bool hasChild(const std::string& childID) const - { - for (size_t i=0; iname == childID) return true; - return false; - } - - /*! returns a parameter of the XML node */ - std::string parm(const std::string& parmID) const { - std::map::const_iterator i = parms.find(parmID); - if (i == parms.end()) return ""; else return i->second; - } - - /*! returns the nth child */ - const Ref child(const size_t id) const - { - if (id >= children.size()) - THROW_RUNTIME_ERROR (loc.str()+": XML node has no child \"" + toString(id) + "\""); - return children[id]; - } - - /*! returns child by node tag */ - const Ref child(const std::string& childID) const - { - for (size_t i=0; iname == childID) return children[i]; - THROW_RUNTIME_ERROR (loc.str()+": XML node has no child \"" + childID + "\""); - } - - /*! returns child by node tag without failing */ - const Ref childOpt(const std::string& childID) const - { - for (size_t i=0; iname == childID) return children[i]; - return null; - } - - /*! adds a new parameter to the node */ - Ref add(const std::string& name, const std::string& val) { - parms[name] = val; - return this; - } - - /*! adds a new child */ - Ref add(const Ref& xml) { - children.push_back(xml); - return this; - } - - /*! adds new data tokens to the body of the node */ - Ref add(const Token& tok) { - body.push_back(tok); - return this; - } - - /*! compares two XML nodes */ - friend bool operator ==( const Ref& a, const Ref& b ) { - return a->name == b->name && a->parms == b->parms && a->children == b->children && a->body == b->body; - } - - /*! orders two XML nodes */ - friend bool operator <( const Ref& a, const Ref& b ) { - if (a->name != b->name ) return a->name < b->name; - if (a->parms != b->parms ) return a->parms < b->parms; - if (a->children != b->children) return a->children < b->children; - if (a->body != b->body ) return a->body < b->body; - return false; - } - - public: - ParseLocation loc; - std::string name; - std::map parms; - std::vector > children; - std::vector body; - }; - - /*! load XML file from stream */ - std::istream& operator>>(std::istream& cin, Ref& xml); - - /*! load XML file from disk */ - Ref parseXML(const FileName& fileName, std::string id = "", bool hasHeader = true); - - /* store XML to stream */ - std::ostream& operator<<(std::ostream& cout, const Ref& xml); - - /*! store XML to disk */ - void emitXML(const FileName& fileName, const Ref& xml); -} - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/xml_writer.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/xml_writer.cpp deleted file mode 100644 index 4e3c9dae5492..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/xml_writer.cpp +++ /dev/null @@ -1,539 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "xml_writer.h" - -namespace embree -{ - class XMLWriter - { - public: - - XMLWriter(Ref root, const FileName& fileName, bool embedTextures); - - public: - void tab(); - void open(const char* str); - void open(const char* str, size_t id); - void close(const char* str); - - void store(const char* name, const char* str); - void store(const char* name, const float& v); - void store(const char* name, const Vec3fa& v); - template void store(const char* name, const std::vector& vec); - void store(const char* name, const avector& vec); - void store4f(const char* name, const avector& vec); - void store_parm(const char* name, const float& v); - void store_parm(const char* name, const Vec3fa& v); - void store_parm(const char* name, const Texture* tex); - void store(const char* name, const AffineSpace3fa& space); - - void store(const SceneGraph::PointLight& light, ssize_t id); - void store(const SceneGraph::SpotLight& light, ssize_t id); - void store(const SceneGraph::DirectionalLight& light, ssize_t id); - void store(const SceneGraph::DistantLight& light, ssize_t id); - void store(const SceneGraph::AmbientLight& light, ssize_t id); - void store(const SceneGraph::TriangleLight& light, ssize_t id); - void store(const SceneGraph::QuadLight& light, ssize_t id); - void store(Ref light, ssize_t id); - - void store(const MatteMaterial& material, ssize_t id); - void store(const MirrorMaterial& material, ssize_t id); - void store(const ThinDielectricMaterial& material, ssize_t id); - void store(const OBJMaterial& material, ssize_t id); - void store(const MetalMaterial& material, ssize_t id); - void store(const VelvetMaterial& material, ssize_t id); - void store(const DielectricMaterial& material, ssize_t id); - void store(const MetallicPaintMaterial& material, ssize_t id); - void store(const HairMaterial& material, ssize_t id); - void store(Ref material); - - void store(Ref mesh, ssize_t id); - void store(Ref mesh, ssize_t id); - void store(Ref mesh, ssize_t id); - void store(Ref mesh, ssize_t id); - void store(Ref hair, ssize_t id); - - void store(Ref node, ssize_t id); - void store(Ref group, ssize_t id); - void store(Ref node); - - private: - std::fstream xml; //!< .xml file for writing XML data - std::fstream bin; //!< .bin file for writing binary data - - private: - size_t ident; - size_t currentNodeID; - std::map, size_t> nodeMap; - std::map textureMap; // FIXME: use Ref - bool embedTextures; - }; - - ////////////////////////////////////////////////////////////////////////////// - //// Storing of objects to XML file - ////////////////////////////////////////////////////////////////////////////// - - void XMLWriter::tab() - { - for (size_t i=0; i" << std::endl; - ident+=2; - } - - void XMLWriter::open(const char* str, size_t id) - { - tab(); xml << "<" << str << " id=\"" << id << "\">" << std::endl; - ident+=2; - } - - void XMLWriter::close(const char* str) - { - assert(ident>=2); - ident-=2; - tab(); xml << "" << std::endl; - } - - void XMLWriter::store(const char* name, const char* str) { - tab(); xml << "<" << name << ">\"" << str << "\"" << std::endl; - } - - void XMLWriter::store(const char* name, const float& v) { - tab(); xml << "<" << name << ">" << v << "" << std::endl; - } - - void XMLWriter::store(const char* name, const Vec3fa& v) { - tab(); xml << "<" << name << ">" << v.x << " " << v.y << " " << v.z << "" << std::endl; - } - - template - void XMLWriter::store(const char* name, const std::vector& vec) - { - std::streampos offset = bin.tellg(); - tab(); xml << "<" << name << " ofs=\"" << offset << "\" size=\"" << vec.size() << "\"/>" << std::endl; - if (vec.size()) bin.write((char*)vec.data(),vec.size()*sizeof(T)); - } - - void XMLWriter::store(const char* name, const avector& vec) - { - std::streampos offset = bin.tellg(); - tab(); xml << "<" << name << " ofs=\"" << offset << "\" size=\"" << vec.size() << "\"/>" << std::endl; - for (size_t i=0; i& vec) - { - std::streampos offset = bin.tellg(); - tab(); xml << "<" << name << " ofs=\"" << offset << "\" size=\"" << vec.size() << "\"/>" << std::endl; - for (size_t i=0; i" << v << "" << std::endl; - } - - void XMLWriter::store_parm(const char* name, const Vec3fa& v) { - tab(); xml << "" << v.x << " " << v.y << " " << v.z << "" << std::endl; - } - - void XMLWriter::store_parm(const char* name, const Texture* tex) - { - if (tex == nullptr) return; - - if (textureMap.find(tex) != textureMap.end()) { - tab(); xml << "" << std::endl; - } else if (embedTextures) { - std::streampos offset = bin.tellg(); - bin.write((char*)tex->data,tex->width*tex->height*tex->bytesPerTexel); - const size_t id = textureMap[tex] = currentNodeID++; - tab(); xml << "width << "\" height=\"" << tex->height - << "\" format=\"" << Texture::format_to_string(tex->format) << "\"/>" << std::endl; - } - else { - const size_t id = textureMap[tex] = currentNodeID++; - tab(); xml << "fileName << "\"/>" << std::endl; - } - } - - void XMLWriter::store(const char* name, const AffineSpace3fa& space) - { - tab(); xml << "<" << name << ">" << std::endl; - tab(); xml << " " << space.l.vx.x << " " << space.l.vy.x << " " << space.l.vz.x << " " << space.p.x << std::endl; - tab(); xml << " " << space.l.vx.y << " " << space.l.vy.y << " " << space.l.vz.y << " " << space.p.y << std::endl; - tab(); xml << " " << space.l.vx.z << " " << space.l.vy.z << " " << space.l.vz.z << " " << space.p.z << std::endl; - tab(); xml << "" << std::endl; - } - - void XMLWriter::store(const SceneGraph::PointLight& light, ssize_t id) - { - open("PointLight",id); - store("AffineSpace",AffineSpace3fa::translate(light.P)); - store("I",light.I); - close("PointLight"); - } - - void XMLWriter::store(const SceneGraph::SpotLight& light, ssize_t id) - { - open("SpotLight",id); - store("AffineSpace",AffineSpace3fa(frame(light.D),light.P)); - store("I",light.I); - store("angleMin",light.angleMin); - store("angleMax",light.angleMax); - close("SpotLight"); - } - - void XMLWriter::store(const SceneGraph::DirectionalLight& light, ssize_t id) - { - open("DirectionalLight",id); - store("AffineSpace",frame(light.D)); - store("E",light.E); - close("DirectionalLight"); - } - - void XMLWriter::store(const SceneGraph::DistantLight& light, ssize_t id) - { - open("DistantLight",id); - store("AffineSpace",frame(light.D)); - store("L",light.L); - store("halfAngle",light.halfAngle); - close("DistantLight"); - } - - void XMLWriter::store(const SceneGraph::AmbientLight& light, ssize_t id) - { - open("AmbientLight"); - store("L",light.L); - close("AmbientLight"); - } - - void XMLWriter::store(const SceneGraph::TriangleLight& light, ssize_t id) - { - open("TriangleLight",id); - const Vec3fa dx = light.v0-light.v2; - const Vec3fa dy = light.v1-light.v2; - const Vec3fa dz = cross(dx,dy); - const Vec3fa p = light.v2; - store("AffineSpace",AffineSpace3fa(dx,dy,dz,p)); - store("L",light.L); - close("TriangleLight"); - } - - void XMLWriter::store(const SceneGraph::QuadLight& light, ssize_t id) - { - open("QuadLight",id); - const Vec3fa dx = light.v3-light.v0; - const Vec3fa dy = light.v1-light.v0; - const Vec3fa dz = cross(dx,dy); - const Vec3fa p = light.v2; - store("AffineSpace",AffineSpace3fa(dx,dy,dz,p)); - store("L",light.L); - close("QuadLight"); - } - - void XMLWriter::store(Ref node, ssize_t id) - { - switch (node->light->getType()) - { - case SceneGraph::LIGHT_AMBIENT : store(*node->light.dynamicCast(),id); break; - case SceneGraph::LIGHT_POINT : store(*node->light.dynamicCast(),id); break; - case SceneGraph::LIGHT_DIRECTIONAL : store(*node->light.dynamicCast(),id); break; - case SceneGraph::LIGHT_SPOT : store(*node->light.dynamicCast(),id); break; - case SceneGraph::LIGHT_DISTANT : store(*node->light.dynamicCast(),id); break; - case SceneGraph::LIGHT_TRIANGLE : store(*node->light.dynamicCast(),id); break; - case SceneGraph::LIGHT_QUAD : store(*node->light.dynamicCast(),id); break; - - default: throw std::runtime_error("unsupported light"); - } - } - - void XMLWriter::store(const MatteMaterial& material, ssize_t id) - { - open("material",id); - store("code","Matte"); - open("parameters"); - store_parm("reflectance",material.reflectance); - close("parameters"); - close("material"); - } - - void XMLWriter::store(const MirrorMaterial& material, ssize_t id) - { - open("material",id); - store("code","Mirror"); - open("parameters"); - store_parm("reflectance",material.reflectance); - close("parameters"); - close("material"); - } - - void XMLWriter::store(const ThinDielectricMaterial& material, ssize_t id) - { - open("material",id); - store("code","ThinDielectric"); - open("parameters"); - store_parm("transmission",material.transmission); - store_parm("eta",material.eta); - store_parm("thickness",material.thickness); - close("parameters"); - close("material"); - } - - void XMLWriter::store(const OBJMaterial& material, ssize_t id) - { - open("material",id); - store("code","OBJ"); - open("parameters"); - store_parm("d",material.d); - store_parm("Kd",material.Kd); - store_parm("Ks",material.Ks); - store_parm("Ns",material.Ns); - store_parm("map_d",material.map_d); - store_parm("map_Kd",material.map_Kd); - close("parameters"); - close("material"); - } - - void XMLWriter::store(const MetalMaterial& material, ssize_t id) - { - open("material",id); - store("code","Metal"); - open("parameters"); - store_parm("reflectance",material.reflectance); - store_parm("eta",material.eta); - store_parm("k",material.k); - store_parm("roughness",material.roughness); - close("parameters"); - close("material"); - } - - void XMLWriter::store(const VelvetMaterial& material, ssize_t id) - { - open("material",id); - store("code","Velvet"); - open("parameters"); - store_parm("reflectance",material.reflectance); - store_parm("backScattering",material.backScattering); - store_parm("horizonScatteringColor",material.horizonScatteringColor); - store_parm("horizonScatteringFallOff",material.horizonScatteringFallOff); - close("parameters"); - close("material"); - } - - void XMLWriter::store(const DielectricMaterial& material, ssize_t id) - { - open("material",id); - store("code","Dielectric"); - open("parameters"); - store_parm("transmissionOutside",material.transmissionOutside); - store_parm("transmission",material.transmissionInside); - store_parm("etaOutside",material.etaOutside); - store_parm("etaInside",material.etaInside); - close("parameters"); - close("material"); - } - - void XMLWriter::store(const MetallicPaintMaterial& material, ssize_t id) - { - open("material",id); - store("code","MetallicPaint"); - open("parameters"); - store_parm("shadeColor",material.shadeColor); - store_parm("glitterColor",material.glitterColor); - store_parm("glitterSpread",material.glitterSpread); - store_parm("eta",material.eta); - close("parameters"); - close("material"); - } - - void XMLWriter::store(const HairMaterial& material, ssize_t id) - { - open("material",id); - store("code","Hair"); - open("parameters"); - store_parm("Kr",material.Kr); - store_parm("Kt",material.Kt); - store_parm("nx",material.nx); - store_parm("ny",material.ny); - close("parameters"); - close("material"); - } - - void XMLWriter::store(Ref mnode) - { - Ref node = mnode.dynamicCast(); - if (nodeMap.find(node) != nodeMap.end()) { - tab(); xml << "" << std::endl; - return; - } - const ssize_t id = nodeMap[node] = currentNodeID++; - - switch (mnode->material.type) - { - case MATERIAL_OBJ : store((OBJMaterial&)mnode->material,id); break; - case MATERIAL_THIN_DIELECTRIC : store((ThinDielectricMaterial&)mnode->material,id); break; - case MATERIAL_METAL : store((MetalMaterial&)mnode->material,id); break; - case MATERIAL_VELVET : store((VelvetMaterial&)mnode->material,id); break; - case MATERIAL_DIELECTRIC : store((DielectricMaterial&)mnode->material,id); break; - case MATERIAL_METALLIC_PAINT : store((MetallicPaintMaterial&)mnode->material,id); break; - case MATERIAL_MATTE : store((MatteMaterial&)mnode->material,id); break; - case MATERIAL_MIRROR : store((MirrorMaterial&)mnode->material,id); break; - case MATERIAL_REFLECTIVE_METAL: store((ReflectiveMetalMaterial&)mnode->material,id); break; - case MATERIAL_HAIR : store((HairMaterial&)mnode->material,id); break; - default: throw std::runtime_error("unsupported material"); - } - } - - void XMLWriter::store(Ref mesh, ssize_t id) - { - open("TriangleMesh",id); - store(mesh->material); - if (mesh->numTimeSteps() != 1) open("animated_positions"); - for (const auto& p : mesh->positions) store("positions",p); - if (mesh->numTimeSteps() != 1) close("animated_positions"); - store("normals",mesh->normals); - store("texcoords",mesh->texcoords); - store("triangles",mesh->triangles); - close("TriangleMesh"); - } - - void XMLWriter::store(Ref mesh, ssize_t id) - { - open("QuadMesh",id); - store(mesh->material); - if (mesh->numTimeSteps() != 1) open("animated_positions"); - for (const auto& p : mesh->positions) store("positions",p); - if (mesh->numTimeSteps() != 1) close("animated_positions"); - store("normals",mesh->normals); - store("texcoords",mesh->texcoords); - store("indices",mesh->quads); - close("QuadMesh"); - } - - void XMLWriter::store(Ref mesh, ssize_t id) - { - open("SubdivisionMesh",id); - store(mesh->material); - if (mesh->numTimeSteps() != 1) open("animated_positions"); - for (const auto& p : mesh->positions) store("positions",p); - if (mesh->numTimeSteps() != 1) close("animated_positions"); - store("normals",mesh->normals); - store("texcoords",mesh->texcoords); - store("position_indices",mesh->position_indices); - store("normal_indices",mesh->normal_indices); - store("texcoord_indices",mesh->texcoord_indices); - store("faces",mesh->verticesPerFace); - store("holes",mesh->holes); - store("edge_creases",mesh->edge_creases); - store("edge_crease_weights",mesh->edge_crease_weights); - store("vertex_creases",mesh->vertex_creases); - store("vertex_crease_weights",mesh->vertex_crease_weights); - close("SubdivisionMesh"); - } - - void XMLWriter::store(Ref mesh, ssize_t id) - { - open("LineSegments",id); - store(mesh->material); - if (mesh->numTimeSteps() != 1) open("animated_positions"); - for (const auto& p : mesh->positions) store4f("positions",p); - if (mesh->numTimeSteps() != 1) close("animated_positions"); - store("indices",mesh->indices); - close("LineSegments"); - } - - void XMLWriter::store(Ref mesh, ssize_t id) - { - open("Hair",id); - store(mesh->material); - if (mesh->numTimeSteps() != 1) open("animated_positions"); - for (const auto& p : mesh->positions) store4f("positions",p); - if (mesh->numTimeSteps() != 1) close("animated_positions"); - store("indices",mesh->hairs); - close("Hair"); - } - - void XMLWriter::store(Ref node, ssize_t id) - { - if (node->spaces.size() == 1) - { - open("Transform",id); - store("AffineSpace",node->spaces[0]); - store(node->child); - close("Transform"); - } - else - { - open("TransformAnimation",id); - for (size_t i=0; ispaces.size(); i++) - store("AffineSpace",node->spaces[i]); - store(node->child); - close("TransformAnimation"); - } - } - - void XMLWriter::store(Ref group, ssize_t id) - { - open("Group",id); - for (size_t i=0; ichildren.size(); i++) - store(group->children[i]); - close("Group"); - } - - void XMLWriter::store(Ref node) - { - if (nodeMap.find(node) != nodeMap.end()) { - tab(); xml << "" << std::endl; return; - } - const ssize_t id = nodeMap[node] = currentNodeID++; - - if (Ref cnode = node.dynamicCast()) store(cnode,id); - //else if (Ref cnode = node.dynamicCast()) store(cnode,id); - else if (Ref cnode = node.dynamicCast()) store(cnode,id); - else if (Ref cnode = node.dynamicCast()) store(cnode,id); - else if (Ref cnode = node.dynamicCast()) store(cnode,id); - else if (Ref cnode = node.dynamicCast()) store(cnode,id); - else if (Ref cnode = node.dynamicCast()) store(cnode,id); - else if (Ref cnode = node.dynamicCast()) store(cnode,id); - else if (Ref cnode = node.dynamicCast()) store(cnode,id); - else throw std::runtime_error("unknown node type"); - } - - XMLWriter::XMLWriter(Ref root, const FileName& fileName, bool embedTextures) - : ident(0), currentNodeID(0), embedTextures(embedTextures) - { - FileName binFileName = fileName.addExt(".bin"); - - xml.exceptions (std::fstream::failbit | std::fstream::badbit); - xml.open (fileName, std::fstream::out); - bin.exceptions (std::fstream::failbit | std::fstream::badbit); - bin.open (binFileName, std::fstream::out | std::fstream::binary); - - xml << "" << std::endl; - open("scene"); - store(root); - close("scene"); - } - - void SceneGraph::storeXML(Ref root, const FileName& fileName, bool embedTextures) { - XMLWriter(root,fileName,embedTextures); - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/xml_writer.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/xml_writer.h deleted file mode 100644 index 347973d21461..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/scenegraph/xml_writer.h +++ /dev/null @@ -1,28 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "scenegraph.h" - -namespace embree -{ - namespace SceneGraph - { - void storeXML(Ref root, const FileName& fileName, bool embedTextures); - } -} - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/texture/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/texture/CMakeLists.txt deleted file mode 100644 index f1d66a029e19..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/texture/CMakeLists.txt +++ /dev/null @@ -1,30 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2017 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -ADD_LIBRARY(texture STATIC - texture2d.cpp -) -TARGET_LINK_LIBRARIES(texture sys) -SET_PROPERTY(TARGET texture PROPERTY FOLDER tutorials/common) - -IF (EMBREE_ISPC_SUPPORT) - ADD_ISPC_LIBRARY(texture_ispc STATIC - texture2d.ispc - ) - TARGET_LINK_LIBRARIES(texture_ispc sys) - SET_TARGET_PROPERTIES(texture_ispc PROPERTIES LINKER_LANGUAGE C) - SET_PROPERTY(TARGET texture_ispc PROPERTY FOLDER tutorials/common) -ENDIF() diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/texture/texture.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/texture/texture.h deleted file mode 100644 index 41cee2fb68c0..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/texture/texture.h +++ /dev/null @@ -1,44 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -/*! This header is shared with ISPC. */ -#pragma once - -/*! Embree format constants for Texture creation */ -typedef enum { - TEXTURE_RGBA8, - TEXTURE_SRGBA, - TEXTURE_RGBA32F, - TEXTURE_RGB8, - TEXTURE_SRGB, - TEXTURE_RGB32F, - TEXTURE_R8, - TEXTURE_R32F, -/* TODO - LogLuv, - RGBA16F - RGB16F - RGBE, // radiance hdr - compressed (RGTC, BPTC, ETC, ...) -*/ -} TextureFormat; - -/*! flags that can be passed to ospNewTexture2D(); can be OR'ed together */ -typedef enum { - TEXTURE_SHARED_BUFFER = (1<<0), - TEXTURE_FILTER_NEAREST = (1<<1) /*!< use nearest-neighbor interpolation rather than the default bilinear interpolation */ -} TextureCreationFlags; - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/texture/texture2d.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/texture/texture2d.cpp deleted file mode 100644 index 3d38c805b7c4..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/texture/texture2d.cpp +++ /dev/null @@ -1,216 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "texture2d.h" - -namespace embree { - - -// Low-level texel accessors -////////////////////////////////////////////////////////////////////////////// - -// TODO blocking - -inline Vec4f getTexel_RGBA8(const Texture2D *self, const Vec2i i) -{ - assert(self); - const uint32_t c = ((const uint32_t *)self->data)[i.y*self->size.x + i.x]; - const uint32_t r = c & 0xff; - const uint32_t g = (c >> 8) & 0xff; - const uint32_t b = (c >> 16) & 0xff; - const uint32_t a = c >> 24; - return Vec4f((float)r, (float)g, (float)b, (float)a)*(1.f/255.f); -} - -inline Vec4f getTexel_RGB8(const Texture2D *self, const Vec2i i) -{ - assert(self); - const uint8_t *texel = (const uint8_t *)self->data; - const uint32_t texelOfs = 3*(i.y*self->size.x + i.x); - const uint32_t r = texel[texelOfs]; - const uint32_t g = texel[texelOfs+1]; - const uint32_t b = texel[texelOfs+2]; - return Vec4f(Vec3fa((float)r, (float)g, (float)b)*(1.f/255.f), 1.f); -} - -inline Vec4f getTexel_R8(const Texture2D *self, const Vec2i i) -{ - assert(self); - const uint8_t c = ((const uint8_t *)self->data)[i.y*self->size.x + i.x]; - return Vec4f(c*(1.f/255.f), 0.0f, 0.0f, 1.f); -} - -inline Vec4f getTexel_SRGBA(const Texture2D *self, const Vec2i i) -{ - return srgba_to_linear(getTexel_RGBA8(self, i)); -} - -inline Vec4f getTexel_SRGB(const Texture2D *self, const Vec2i i) -{ - return srgba_to_linear(getTexel_RGB8(self, i)); -} - -inline Vec4f getTexel_RGBA32F(const Texture2D *self, const Vec2i i) -{ - assert(self); - return ((const Vec4f *)self->data)[i.y*self->size.x + i.x]; -} - -inline Vec4f getTexel_RGB32F(const Texture2D *self, const Vec2i i) -{ - assert(self); - Vec3fa v = ((const Vec3fa*)self->data)[i.y*self->size.x + i.x]; - return Vec4f(v, 1.f); -} - -inline Vec4f getTexel_R32F(const Texture2D *self, const Vec2i i) -{ - assert(self); - float v = ((const float*)self->data)[i.y*self->size.x + i.x]; - return Vec4f(v, 0.f, 0.f, 1.f); -} - - -// Texture coordinate utilities -////////////////////////////////////////////////////////////////////////////// - -inline Vec2i nearest_coords(const Texture2D *self, const Vec2f p) -{ - // repeat: get remainder within [0..1] parameter space - Vec2f tc = frac(p); - tc = max(tc, Vec2f(0.0f)); // filter out inf/NaN - - // scale by texture size - tc = tc * self->sizef; - - // nearest - return Vec2i(tc); -} - -struct BilinCoords { - Vec2i st0; - Vec2i st1; - Vec2f frac; -}; - -inline BilinCoords bilinear_coords(const Texture2D *self, const Vec2f p) -{ - BilinCoords coords; - - // repeat: get remainder within [0..1] parameter space - // lower sample shifted by half a texel - Vec2f tc = frac(p - self->halfTexel); - tc = max(tc, Vec2f(0.0f)); // filter out inf/NaN - - // scale by texture size - tc = tc * self->sizef; - coords.frac = frac(tc); - - coords.st0 = Vec2i(tc); - coords.st1 = coords.st0 + 1; - // handle border cases - if (coords.st1.x >= self->size.x) - coords.st1.x = 0; - if (coords.st1.y >= self->size.y) - coords.st1.y = 0; - - return coords; -} - -inline Vec4f bilerp(const Vec2f frac, const Vec4f c00, const Vec4f c01, const Vec4f c10, const Vec4f c11) -{ - return lerpr(frac.y, - lerpr(frac.x, c00, c01), - lerpr(frac.x, c10, c11)); -} - - -// Implementations of Texture2D_get for different formats and filter modi -////////////////////////////////////////////////////////////////////////////// - -#define __define_tex_get(FMT) \ - \ -static Vec4f Texture2D_nearest_##FMT(const Texture2D *self, \ - const Vec2f &p) \ -{ \ - return getTexel_##FMT(self, nearest_coords(self, p)); \ -} \ - \ -static Vec4f Texture2D_bilinear_##FMT(const Texture2D *self, \ - const Vec2f &p) \ -{ \ - BilinCoords cs = bilinear_coords(self, p); \ - \ - const Vec4f c00 = getTexel_##FMT(self, Vec2i(cs.st0.x, cs.st0.y)); \ - const Vec4f c01 = getTexel_##FMT(self, Vec2i(cs.st1.x, cs.st0.y)); \ - const Vec4f c10 = getTexel_##FMT(self, Vec2i(cs.st0.x, cs.st1.y)); \ - const Vec4f c11 = getTexel_##FMT(self, Vec2i(cs.st1.x, cs.st1.y)); \ - \ - return bilerp(cs.frac, c00, c01, c10, c11); \ -} - -#define __define_tex_get_case(FMT) \ - case TEXTURE_##FMT: return filter_nearest ? &Texture2D_nearest_##FMT : \ - &Texture2D_bilinear_##FMT; - -#define __foreach_fetcher(FCT) \ - FCT(RGBA8) \ - FCT(SRGBA) \ - FCT(RGBA32F) \ - FCT(RGB8) \ - FCT(SRGB) \ - FCT(RGB32F) \ - FCT(R8) \ - FCT(R32F) - -__foreach_fetcher(__define_tex_get) - -static Texture2D_get Texture2D_get_addr(const uint32_t type, - const bool filter_nearest) -{ - switch (type) { - __foreach_fetcher(__define_tex_get_case) - } - return 0; -}; - -#undef __define_tex_get -#undef __define_tex_get_addr -#undef __foreach_fetcher - - -// Exports (called from C++) -////////////////////////////////////////////////////////////////////////////// - -extern "C" void *Texture2D_create(Vec2i &size, void *data, - uint32_t type, uint32_t flags) -{ - Texture2D *self = (Texture2D*) alignedMalloc(sizeof(Texture2D)); - self->size = size; - - // Due to float rounding frac(x) can be exactly 1.0f (e.g. for very small - // negative x), although it should be strictly smaller than 1.0f. We handle - // this case by having sizef slightly smaller than size, such that - // frac(x)*sizef is always < size. - self->sizef = Vec2f(nextafter((float)size.x, -1.0f), nextafter((float)size.y, -1.0f)); - self->halfTexel = Vec2f(0.5f/size.x, 0.5f/size.y); - self->data = data; - self->get = Texture2D_get_addr(type, flags & TEXTURE_FILTER_NEAREST); - - return self; -} - -} // namespace embree diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/texture/texture2d.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/texture/texture2d.h deleted file mode 100644 index 0bd486cbfa29..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/texture/texture2d.h +++ /dev/null @@ -1,117 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "texture.h" -#include "../math/vec.h" - -namespace embree { - -struct Texture2D; - -typedef Vec4f (*Texture2D_get)(const Texture2D *self, - const Vec2f &p); - -struct Texture2D { - Vec2i size; - Vec2f sizef; // size, as floats; slightly smaller than 'size' to avoid range checks - Vec2f halfTexel; // 0.5/size, needed for bilinear filtering and clamp-to-edge - Texture2D_get get; - void *data; -}; - -// XXX won't work with MIPmapping: clean implementation with clamping on integer coords needed then -inline Vec2f clamp2edge(const Texture2D *self, const Vec2f p) -{ - return clamp(p, self->halfTexel, 1.0f - self->halfTexel); -} - -/*! helper function that returns the sampled value for the first - channel of the given texture - - Right now, this function always asks the texture for all four - channels, and then discards all but one; later implementations may - have specialized 'get1f' methods with the texture - - \note self may NOT be nullptr! -*/ -inline float get1f(const Texture2D *self, - const Vec2f where) -{ - Vec4f ret = self->get(self, where); - return ret.x; -} - -/*! helper function that returns the sampled value for the first three - channels of the given texture - - Right now, this function always asks the texture for all four - channels, and then discards all but one; later implementations may - have specialized 'get3f' methods with the texture - - \note self may NOT be nullptr! -*/ -inline Vec3fa get3f(const Texture2D *self, - const Vec2f where) -{ - Vec4f ret = self->get(self, where); - return Vec3fa(ret); -} - -/*! helper function that returns the sampled value of the four - channels of the given texture. - - Note that it's up to the texture to define clearly what happens if - we ask for four channels even if the texture has less physical - channels. - - \note self may NOT be nullptr! -*/ -inline Vec4f get4f(const Texture2D *self, - const Vec2f where) -{ - return self->get(self, where); -} - -/*! helper function: get1f() with a default value if the texture is nullptr */ -inline float get1f(const Texture2D *self, - const Vec2f where, - const float defaultValue) -{ - if (self == nullptr) return defaultValue; - else return get1f(self,where); -} - -/*! helper function: get3f() with a default value if the texture is nullptr */ -inline Vec3fa get3f(const Texture2D *self, - const Vec2f where, - const Vec3fa& defaultValue) -{ - if (self == nullptr) return defaultValue; - else return get3f(self,where); -} - -/*! helper function: get4f() with a default value if the texture is nullptr */ -inline Vec4f get4f(const Texture2D *self, - const Vec2f where, - const Vec4f defaultValue) -{ - if (self == nullptr) return defaultValue; - else return get4f(self,where); -} - -} // namespace embree diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/texture/texture_param.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/texture/texture_param.h deleted file mode 100644 index ec870123acc4..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/texture/texture_param.h +++ /dev/null @@ -1,92 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "texture2d.h" -#include "ospray/math/AffineSpace.ih" - -namespace embree { - - -//! Texture2D including coordinate transformation, plus helpers - -struct TextureParam -{ - Texture2D* map; - affine2f xform; -}; - -inline TextureParam make_TextureParam(Texture2D * tex, const affine2f &xform) -{ - TextureParam t; - t.map = tex; - t.xform = xform; - return t; -} - -inline bool valid(const TextureParam &tex) -{ - return tex.map; -} - -inline float get1f(const TextureParam &tex, - const Vec2f uv) -{ - return get1f(tex.map, tex.xform * uv); -} - -inline float get1f(const TextureParam &tex, - const Vec2f uv, - const float defaultValue) -{ - if (tex.map == nullptr) - return defaultValue; - return get1f(tex.map, tex.xform * uv); -} - -inline Vec3fa get3f(const TextureParam &tex, - const Vec2f uv) -{ - return get3f(tex.map, tex.xform * uv); -} - -inline Vec3fa get3f(const TextureParam &tex, - const Vec2f uv, - const Vec3fa& defaultValue) -{ - if (tex.map == nullptr) - return defaultValue; - return get3f(tex.map, tex.xform * uv); -} - -inline Vec4f get4f(const TextureParam &tex, - const Vec2f uv) -{ - return get4f(tex.map, tex.xform * uv); -} - -inline Vec4f get4f(const TextureParam &tex, - const Vec2f uv, - const Vec4f defaultValue) -{ - if (tex.map == nullptr) - return defaultValue; - return get4f(tex.map, tex.xform * uv); -} - - -} // namespace embree diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/CMakeLists.txt deleted file mode 100644 index 8697ece5d144..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/CMakeLists.txt +++ /dev/null @@ -1,68 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2017 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -IF (WIN32) -# FindGLUT.cmake is broken for Windows in CMake until 3.0: does not support PATH - FIND_PATH(GLUT_INCLUDE_DIR NAMES GL/glut.h PATHS ../freeglut/include) - # detect and select Win32 or x64 - IF (CMAKE_SIZEOF_VOID_P EQUAL 8) - SET(ARCH x64) - ELSE() - SET(ARCH Win32) - ENDIF() - FIND_LIBRARY(GLUT_glut_LIBRARY freeglut ../freeglut/${ARCH}) - SET(GLUT_LIBRARIES ${GLUT_glut_LIBRARY}) - MARK_AS_ADVANCED( - GLUT_INCLUDE_DIR - GLUT_glut_LIBRARY - ) -ELSE (WIN32) - FIND_PACKAGE(GLUT REQUIRED) -ENDIF (WIN32) - -FIND_PACKAGE(OpenGL REQUIRED) - -INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR} ${GLUT_INCLUDE_DIR}) -ADD_LIBRARY(tutorial STATIC tutorial.cpp application.cpp scene.cpp) -TARGET_LINK_LIBRARIES(tutorial sys lexers scenegraph ${OPENGL_LIBRARIES} ${GLUT_LIBRARIES}) -SET_PROPERTY(TARGET tutorial PROPERTY FOLDER tutorials/common) - -IF (WIN32) - GET_FILENAME_COMPONENT(GLUT_DIR ${GLUT_glut_LIBRARY} PATH) - ADD_CUSTOM_COMMAND(TARGET tutorial POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${GLUT_DIR}/freeglut.dll $ - COMMENT "Copy FreeGlut DLL" VERBATIM - ) - INSTALL(PROGRAMS ${GLUT_DIR}/freeglut.dll DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT examples) -ENDIF (WIN32) - -ADD_LIBRARY(tutorial_device STATIC tutorial_device.cpp scene_device.cpp) -TARGET_LINK_LIBRARIES(tutorial_device tutorial lights embree) -SET_PROPERTY(TARGET tutorial_device PROPERTY FOLDER tutorials/common) - -ADD_LIBRARY(noise STATIC noise.cpp) -SET_PROPERTY(TARGET noise PROPERTY FOLDER tutorials/common) - -IF (EMBREE_ISPC_SUPPORT) - ADD_ISPC_LIBRARY(tutorial_device_ispc STATIC tutorial_device.ispc) - TARGET_LINK_LIBRARIES(tutorial_device_ispc tutorial lights_ispc tutorial_device embree) - SET_TARGET_PROPERTIES(tutorial_device_ispc PROPERTIES LINKER_LANGUAGE C) - SET_PROPERTY(TARGET tutorial_device_ispc PROPERTY FOLDER tutorials/common) - - ADD_ISPC_LIBRARY(noise_ispc STATIC noise.ispc) - SET_TARGET_PROPERTIES(noise_ispc PROPERTIES LINKER_LANGUAGE C) - SET_PROPERTY(TARGET noise_ispc PROPERTY FOLDER tutorials/common) -ENDIF() diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/application.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/application.cpp deleted file mode 100644 index b9b39f493582..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/application.cpp +++ /dev/null @@ -1,122 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "application.h" - -namespace embree -{ - Application::Application(int features) - : rtcore("start_threads=1,set_affinity=1") - { - registerOption("help", [this] (Ref cin, const FileName& path) { - printCommandLineHelp(); - exit(1); - }, "--help: prints help for all supported command line options"); - - if (features & FEATURE_RTCORE) - { - registerOption("rtcore", [this] (Ref cin, const FileName& path) { - rtcore += "," + cin->getString(); - }, "--rtcore : uses to configure Embree device"); - - registerOption("threads", [this] (Ref cin, const FileName& path) { - rtcore += ",threads=" + toString(cin->getInt()); - }, "--threads : number of threads to use"); - - registerOption("affinity", [this] (Ref cin, const FileName& path) { - rtcore += ",set_affinity=1"; - }, "--affinity: affinitize threads"); - - registerOption("set_affinity", [this] (Ref cin, const FileName& path) { - rtcore += ",set_affinity=" + cin->getString(); - }, "--set_affinity <0/1>: enables or disables affinitizing of threads"); - registerOptionAlias("set_affinity","set-affinity"); - - registerOption("start_threads", [this] (Ref cin, const FileName& path) { - rtcore += ",start_threads=" + cin->getString(); - }, "--start_threads <0/1>: starts threads at device creation time if set to 1"); - registerOptionAlias("start_threads","start-threads"); - - registerOption("verbose", [this] (Ref cin, const FileName& path) { - rtcore += ",verbose=" + toString(cin->getInt()); - }, "--verbose : sets verbosity level"); - - registerOption("isa", [this] (Ref cin, const FileName& path) { - rtcore += ",isa=" + cin->getString(); - }, "--isa : selects instruction set to use:\n" - " sse: select SSE codepath\n" - " sse2: select SSE2 codepath\n" - " sse3: select SSE3 codepath\n" - " ssse3: select SSSE3 codepath\n" - " sse4.1: select SSE4.1 codepath\n" - " sse4.2: select SSE4.2 codepath\n" - " avx: select AVX codepath\n" - " avxi: select AVXI codepath\n" - " avx2: select AVX2 codepath\n" - " avx512knl: select AVX512 codepath for KNL\n" - " avx512skx: select AVX512 codepath for SKX\n"); - } - } - - void Application::registerOptionAlias(const std::string& name, const std::string& alternativeName) { - commandLineOptionMap[alternativeName] = commandLineOptionMap[name]; - } - - void Application::parseCommandLine(int argc, char** argv) - { - /* create stream for parsing */ - Ref stream = new ParseStream(new CommandLineStream(argc, argv)); - - /* parse command line */ - parseCommandLine(stream, FileName()); - } - - void Application::parseCommandLine(Ref cin, const FileName& path) - { - while (true) - { - std::string tag = cin->getString(); - if (tag == "") return; - std::string tag0 = tag; - - /* remove - or -- and lookup command line option */ - if (tag.find("-") == 0) - { - tag = tag.substr(1); - if (tag.find("-") == 0) tag = tag.substr(1); - auto option = commandLineOptionMap.find(tag); - - /* process command line option */ - if (option != commandLineOptionMap.end()) { - option->second->parse(cin,path); - continue; - } - } - - /* handle unknown command line options */ - std::cerr << "unknown command line parameter: " << tag0 << " "; - while (cin->peek() != "" && cin->peek()[0] != '-') std::cerr << cin->getString() << " "; - std::cerr << std::endl; - } - } - - void Application::printCommandLineHelp() - { - for (auto& c : commandLineOptionList) { - std::cout << c->description << std::endl; - } - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/application.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/application.h deleted file mode 100644 index b63c3f8c010a..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/application.h +++ /dev/null @@ -1,91 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../default.h" - -namespace embree -{ - class Application - { - public: - enum Features { FEATURE_RTCORE = 1, FEATURE_STREAM = 2 }; - - Application (int features); - - /* virtual interface for command line option processing */ - struct CommandLineOption : public RefCount - { - public: - CommandLineOption (const std::string& description) - : description(description) {} - - virtual void parse(Ref cin, const FileName& path) = 0; - - public: - std::string description; - }; - - /* helper class to provide parsing function via lambda function */ - template - struct CommandLineOptionClosure : public CommandLineOption - { - CommandLineOptionClosure (std::string description, const F& f) - : CommandLineOption(description), f(f) {} - - virtual void parse(Ref cin, const FileName& path) { - f(cin,path); - } - - public: - F f; - }; - - /* registers a command line option */ - template - void registerOption(const std::string& name, const F& f, const std::string& description) - { - Ref closure = new CommandLineOptionClosure(description,f); - commandLineOptionList.push_back(closure); - commandLineOptionMap[name] = closure; - } - - /* registers an alias for a command line option */ - void registerOptionAlias(const std::string& name, const std::string& alternativeName); - - /* command line parsing */ - void parseCommandLine(int argc, char** argv); - void parseCommandLine(Ref cin, const FileName& path); - - /* prints help for all supported command line options */ - void printCommandLineHelp(); - - /* command line options database */ - public: - std::vector< Ref > commandLineOptionList; - std::map > commandLineOptionMap; - - public: - - /* virtual main function, contains all tutorial logic */ - virtual int main(int argc, char** argv) = 0; - - public: - /* embree configuration */ - std::string rtcore; - }; -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/camera.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/camera.h deleted file mode 100644 index 59350b6abd90..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/camera.h +++ /dev/null @@ -1,126 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../../../common/sys/platform.h" -#include "../../../common/sys/ref.h" -#include "../../../common/math/math.h" -#include "../../../common/math/vec3.h" -#include "../../../common/math/affinespace.h" - -namespace embree -{ - /* camera settings */ - struct Camera - { - struct ISPCCamera - { - public: - ISPCCamera (const AffineSpace3fa& xfm) - : xfm(xfm) {} - - public: - AffineSpace3fa xfm; - }; - - public: - - Camera () - : from(0.0001f,0.0001f,-3.0f), to(0,0,0), up(0,1,0), fov(90) {} - - Camera (Vec3fa& from, Vec3fa& to, Vec3fa& up, float fov) - : from(from), to(to), up(up), fov(fov) {} - - AffineSpace3fa camera2world () { return AffineSpace3fa::lookat(from, to, up); } - AffineSpace3fa world2camera () { return rcp(AffineSpace3fa::lookat(from, to, up)); } - Vec3fa world2camera(const Vec3fa& p) { return xfmPoint(world2camera(),p); } - Vec3fa camera2world(const Vec3fa& p) { return xfmPoint(camera2world(),p); } - - /*AffineSpace3fa pixel2world (size_t width, size_t height) - { - const float fovScale = 1.0f/tanf(deg2rad(0.5f*fov)); - const AffineSpace3fa local2world = AffineSpace3fa::lookat(from, to, up); - return AffineSpace3fa(local2world.l.vx, - -local2world.l.vy, - -0.5f*width*local2world.l.vx + 0.5f*height*local2world.l.vy + 0.5f*height*fovScale*local2world.l.vz, - local2world.p); - }*/ - - ISPCCamera getISPCCamera (size_t width, size_t height, bool flip_y = false) - { - const float fovScale = 1.0f/tanf(deg2rad(0.5f*fov)); - const AffineSpace3fa local2world = AffineSpace3fa::lookat(from, to, up); - Vec3fa vx = local2world.l.vx; - Vec3fa vy = -local2world.l.vy; - Vec3fa vz = -0.5f*width*local2world.l.vx + 0.5f*height*local2world.l.vy + 0.5f*height*fovScale*local2world.l.vz; - Vec3fa p = local2world.p; - if (flip_y) { - vz = vz+float(height)*vy; - vy = -vy; - } - return ISPCCamera(AffineSpace3fa(vx,vy,vz,p)); - } - - void move (float dx, float dy, float dz) - { - AffineSpace3fa xfm = camera2world(); - Vec3fa ds = xfmVector(xfm,Vec3fa(dx,dy,dz)); - from += ds; - to += ds; - } - - void rotate (float dtheta, float dphi) - { - Vec3fa view = xfmPoint(world2camera(),to); - float theta = atan2f(view.x, view.z); theta += dtheta; - float phi = asinf (view.y); phi += dphi; - float x = cosf(phi)*sinf(theta); - float y = sinf(phi); - float z = cosf(phi)*cosf(theta); - to = xfmPoint(camera2world(),length(view)*Vec3fa(x,y,z)); - } - - void rotateOrbit (float dtheta, float dphi) - { - Vec3fa view = normalize(xfmVector(world2camera(),to - from)); - float theta = atan2f(view.x, view.z); theta += dtheta; - float phi = asinf (view.y); phi += dphi; - assert(std::isfinite(theta)); - assert(std::isfinite(phi)); - float x = cosf(phi)*sinf(theta); - float y = sinf(phi); - float z = cosf(phi)*cosf(theta); - Vec3fa view1 = xfmVector(camera2world(),Vec3fa(x,y,z)); - from = to - length(to - from) * view1; - } - - void dolly (float ds) - { - float dollySpeed = 0.01f; - float k = powf((1.0f-dollySpeed), ds); - from += length(to-from) * (1-k) * normalize(to-from); - } - - public: - Vec3fa from; //!< position of camera - Vec3fa to; //!< look at point - Vec3fa up; //!< up vector - float fov; //!< field of view - }; - - typedef Camera::ISPCCamera ISPCCamera; -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/noise.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/noise.cpp deleted file mode 100644 index 9b3b6b2b3c00..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/noise.cpp +++ /dev/null @@ -1,179 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "noise.h" - -namespace embree -{ - static int p[513] = { - 151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23, - 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33, - 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166, - 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244, - 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196, - 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123, - 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42, - 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9, - 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228, - 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107, - 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, - 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180, - 151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23, - 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33, - 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166, - 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244, - 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196, - 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123, - 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42, - 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9, - 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228, - 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107, - 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, - 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180, - 151 - }; - - static float g1[128] = { - -0.20707f, 0.680971f, -0.293328f, -0.106833f, -0.362614f, 0.772857f, -0.968834f, 0.16818f, -0.681263f, -0.232568f, 0.382009f, -0.882282f, 0.799709f, -0.672908f, -0.681857f, 0.0661294f, 0.208288f, 0.165398f, -0.460058f, -0.219044f, -0.413199f, 0.484755f, -0.402949f, -0.848924f, -0.190035f, 0.714756f, 0.883937f, 0.325661f, 0.692952f, -0.99449f, -0.0752415f, 0.065192f, 0.575753f, -0.468776f, 0.965505f, -0.38643f, 0.20171f, 0.217431f, -0.575122f, 0.77179f, -0.390686f, -0.69628f, -0.324676f, -0.225046f, 0.28722f, 0.507107f, 0.207232f, 0.0632565f, -0.0812794f, 0.304977f, -0.345638f, 0.892741f, -0.26392f, 0.887781f, -0.985143f, 0.0331999f, -0.454458f, -0.951402f, 0.183909f, -0.590073f, 0.755387f, -0.881263f, -0.478315f, -0.394342f, 0.78299f, -0.00360388f, 0.420051f, -0.427172f, 0.729847f, 0.351081f, -0.0830201f, 0.919271f, 0.549351f, -0.246897f, -0.542722f, -0.290932f, -0.399364f, 0.339532f, 0.437933f, 0.131909f, 0.648931f, -0.218776f, 0.637533f, 0.688017f, -0.639064f, 0.886792f, -0.150226f, 0.0413316f, -0.868712f, 0.827016f, 0.765169f, 0.522728f, -0.202155f, 0.376514f, 0.523097f, -0.189982f, -0.749498f, -0.0307322f, -0.555075f, 0.746242f, 0.0576438f, -0.997172f, 0.721028f, -0.962605f, 0.629784f, -0.514232f, -0.370856f, 0.931465f, 0.87112f, 0.618863f, -0.0157817f, -0.559729f, 0.152707f, -0.421942f, -0.357866f, -0.477353f, -0.652024f, -0.996365f, -0.910432f, -0.517651f, -0.169098f, 0.403249f, -0.556309f, 0.00782069f, -0.86594f, -0.213873f, -0.0410469f, -0.563716f - }; - - static float g2[128*2] = { - 0.605609f, 0.538399f, 0.796519f, -0.944204f, 0.908294f, 0.756016f, 0.0977536f, -0.863638f, 0.842196f, -0.744751f, -0.932081f, 0.932392f, -0.588525f, 0.516884f, 0.841188f, -0.978497f, -0.608649f, -0.868011f, 0.992137f, -0.772425f, 0.963049f, -0.0478757f, 0.953878f, 0.889467f, 0.562174f, 0.624644f, -0.356598f, -0.520726f, -0.821833f, 0.99985f, 0.234183f, -0.9791f, -0.971815f, -0.0979374f, -0.108159f, -0.34927f, -0.592124f, -0.775632f, 0.97228f, 0.753819f, 0.941608f, 0.578291f, 0.852108f, -0.760312f, -0.784772f, 0.0223242f, -0.606013f, -0.980319f, 0.252581f, -0.575064f, 0.884701f, 0.943763f, 0.737344f, 0.938496f, 0.0466562f, -0.994566f, 0.989782f, 0.988368f, -0.546155f, 0.279211f, -0.69504f, 0.931229f, 0.99768f, -0.325874f, -0.630157f, -0.999936f, -0.968623f, -0.226805f, -0.750428f, -0.450961f, 0.257868f, 0.968011f, -0.988005f, -0.713965f, 0.991007f, -0.61059f, 0.950437f, -0.483042f, -0.98105f, -0.915356f, -0.892527f, -0.772958f, -0.9081f, 0.55692f, 0.906075f, 0.937419f, 0.454624f, -0.991582f, 0.400857f, 0.855933f, -0.672619f, 0.0713424f, 0.593249f, -0.378286f, -0.997369f, -0.827112f, 0.708222f, -0.995343f, 0.985069f, 0.698711f, -0.180105f, 0.999961f, -0.768451f, 0.993107f, -0.918024f, 0.0446961f, 0.91882f, 0.97691f, -0.393915f, 0.364803f, 0.0495592f, 0.186545f, -0.461553f, -0.242776f, 0.901952f, -0.0710866f, 0.888101f, 0.999935f, 0.277688f, 0.0554235f, 0.506599f, -0.299293f, 0.984394f, -0.999698f, 0.408822f, -0.782639f, 0.128596f, 0.198834f, 0.981707f, 0.864566f, 0.808197f, 0.352335f, 0.970484f, -0.667503f, 0.330243f, 0.208392f, 0.191539f, -0.938943f, 0.895002f, 0.910575f, -0.537691f, -0.98548f, -0.721635f, -0.335382f, -0.424701f, -0.960452f, 0.595047f, 0.783579f, -0.937749f, 0.529096f, -0.997906f, -0.581313f, -0.899828f, -0.88461f, 0.989469f, 0.91872f, -0.850793f, 0.955954f, 0.715768f, -0.736686f, 0.80392f, -0.717276f, -0.788579f, 0.987003f, -0.839648f, 0.885176f, -0.998929f, -0.0376033f, -0.578371f, -0.718771f, 0.906081f, 0.239947f, -0.803563f, -0.00826282f, 0.991011f, -0.0057943f, -0.349232f, 0.65319f, 0.992067f, -0.953535f, 0.893781f, 0.661689f, 0.957253f, -0.425442f, -0.866609f, 0.712892f, -0.807777f, 0.89632f, -0.595147f, -0.0224999f, -0.643786f, 0.545815f, -0.870124f, -0.696306f, -0.99902f, 0.773648f, -0.806008f, -0.931319f, -0.780114f, -0.552154f, -0.933812f, -0.563108f, -0.619909f, 0.966532f, 0.692454f, 0.993284f, 0.338885f, -0.75104f, 0.237272f, -0.713619f, -0.160187f, -0.199242f, -0.371265f, -0.781439f, -0.914125f, -0.944104f, 0.169525f, -0.984403f, 0.976056f, -0.265228f, 0.94232f, 0.993906f, -0.877517f, -0.89618f, 0.611817f, -0.106758f, 0.680403f, 0.163329f, -0.325386f, -0.0687362f, -0.901164f, 0.460314f, 0.999981f, -0.0408026f, 0.850356f, -0.763343f, -0.170806f, -0.102919f, 0.581564f, 0.688634f, 0.284368f, -0.276419f, 0.616641f, -0.929771f, 0.927865f, 0.440373f, 0.153446f, 0.840456f, 0.996966f, 0.867209f, -0.135077f, -0.493238f, -0.577193f, 0.0588088f, 0.715215f, 0.0143633f - }; - - static float g3[128*4] = { - -0.582745f, 0.443494f, -0.680971f, 0.0f, -0.601153f, 0.791961f, 0.106833f, 0.0f, -0.265466f, 0.576385f, -0.772857f, 0.0f, 0.981035f, 0.0963612f, -0.16818f, 0.0f, 0.524388f, 0.819103f, 0.232568f, 0.0f, -0.170518f, -0.43875f, 0.882282f, 0.0f, 0.598053f, -0.435348f, 0.672908f, 0.0f, 0.53956f, 0.839346f, -0.0661294f, 0.0f, -0.782511f, -0.600267f, -0.165398f, 0.0f, -0.122114f, 0.968043f, 0.219044f, 0.0f, -0.235567f, 0.842331f, -0.484755f, 0.0f, -0.158657f, 0.504139f, 0.848924f, 0.0f, -0.578396f, 0.39317f, -0.714756f, 0.0f, 0.883328f, -0.337159f, -0.325661f, 0.0f, 0.0597264f, -0.0861552f, 0.99449f, 0.0f, -0.970124f, 0.233685f, -0.0651921f, 0.0f, 0.208238f, -0.858421f, 0.468776f, 0.0f, 0.916908f, -0.0997567f, 0.38643f, 0.0f, -0.786568f, -0.577957f, -0.217431f, 0.0f, 0.14868f, 0.618251f, -0.77179f, 0.0f, -0.24168f, 0.675858f, 0.69628f, 0.0f, -0.50994f, 0.83025f, 0.225046f, 0.0f, -0.534183f, -0.676382f, -0.507107f, 0.0f, -0.793861f, -0.6048f, -0.0632565f, 0.0f, -0.92148f, 0.240548f, -0.304977f, 0.0f, -0.210037f, 0.39862f, -0.892741f, 0.0f, -0.310918f, 0.339375f, -0.887781f, 0.0f, 0.99836f, 0.0466305f, -0.0331999f, 0.0f, -0.0439099f, 0.304806f, 0.951402f, 0.0f, -0.676304f, -0.440938f, 0.590073f, 0.0f, 0.339805f, -0.328495f, 0.881263f, 0.0f, -0.0625568f, 0.916832f, 0.394342f, 0.0f, 0.776463f, -0.630153f, 0.00360388f, 0.0f, -0.224717f, -0.8758f, 0.427172f, 0.0f, 0.618879f, -0.70266f, -0.351081f, 0.0f, -0.380313f, 0.101503f, -0.919271f, 0.0f, 0.149639f, -0.957418f, 0.246897f, 0.0f, 0.128024f, 0.948139f, 0.290932f, 0.0f, -0.292448f, 0.893976f, -0.339532f, 0.0f, -0.192062f, -0.972477f, -0.131909f, 0.0f, 0.44007f, -0.870905f, 0.218776f, 0.0f, 0.303887f, -0.659003f, -0.688017f, 0.0f, 0.195552f, 0.41876f, -0.886792f, 0.0f, -0.889922f, 0.454236f, -0.0413315f, 0.0f, 0.515034f, 0.225353f, -0.827016f, 0.0f, 0.63084f, -0.573408f, -0.522728f, 0.0f, -0.745779f, 0.549592f, -0.376514f, 0.0f, 0.0711763f, -0.979204f, 0.189982f, 0.0f, 0.705657f, 0.707887f, 0.0307322f, 0.0f, 0.114603f, 0.655735f, -0.746242f, 0.0f, -0.0739232f, -0.0135353f, 0.997172f, 0.0f, 0.173356f, -0.20818f, 0.962605f, 0.0f, 0.34008f, -0.787344f, 0.514232f, 0.0f, -0.143596f, 0.334295f, -0.931465f, 0.0f, 0.721989f, -0.30942f, -0.618863f, 0.0f, -0.827657f, 0.0410685f, 0.559729f, 0.0f, -0.804277f, -0.418454f, 0.421942f, 0.0f, -0.379459f, 0.792556f, 0.477353f, 0.0f, 0.0391537f, 0.0756503f, 0.996365f, 0.0f, 0.821943f, 0.237588f, 0.517651f, 0.0f, -0.788974f, 0.463584f, -0.403249f, 0.0f, 0.175972f, 0.984364f, -0.00782073f, 0.0f, 0.891497f, 0.399363f, 0.213873f, 0.0f, -0.819111f, 0.106216f, 0.563716f, 0.0f, 0.105511f, 0.544028f, -0.832406f, 0.0f, -0.464551f, 0.63753f, 0.614612f, 0.0f, 0.232387f, 0.935154f, -0.267363f, 0.0f, 0.777619f, 0.272068f, -0.566823f, 0.0f, 0.975331f, 0.190338f, 0.111807f, 0.0f, 0.224313f, 0.450072f, -0.86436f, 0.0f, 0.841897f, -0.536898f, 0.0543103f, 0.0f, 0.637123f, -0.664145f, -0.391135f, 0.0f, 0.901675f, -0.422984f, 0.0898189f, 0.0f, -0.496241f, 0.367413f, -0.786608f, 0.0f, -0.255468f, -0.689763f, -0.677469f, 0.0f, -0.0616459f, -0.951141f, -0.302539f, 0.0f, -0.431011f, -0.889035f, -0.154425f, 0.0f, -0.0711688f, 0.486502f, -0.870776f, 0.0f, -0.223359f, -0.36162f, 0.905175f, 0.0f, -0.678546f, 0.695482f, -0.23639f, 0.0f, 0.576553f, 0.77934f, 0.245389f, 0.0f, -0.194568f, -0.24951f, 0.948624f, 0.0f, 0.28962f, -0.447736f, 0.845962f, 0.0f, -0.0403821f, -0.871893f, 0.488028f, 0.0f, 0.790972f, -0.560788f, 0.244705f, 0.0f, -0.34553f, 0.739953f, 0.57713f, 0.0f, -0.516376f, -0.697122f, 0.49737f, 0.0f, 0.115998f, 0.859293f, 0.498156f, 0.0f, 0.643831f, -0.239955f, 0.72657f, 0.0f, -0.125114f, 0.987348f, -0.0974144f, 0.0f, -0.306452f, 0.610699f, -0.73016f, 0.0f, -0.269845f, 0.893027f, -0.360119f, 0.0f, 0.328563f, -0.570628f, -0.752615f, 0.0f, -0.306918f, -0.42057f, 0.853769f, 0.0f, 0.699245f, -0.51785f, 0.492837f, 0.0f, -0.558362f, -0.469763f, -0.68378f, 0.0f, 0.476563f, -0.841398f, 0.254826f, 0.0f, 0.0276172f, -0.623206f, 0.78157f, 0.0f, 0.587723f, -0.800313f, -0.118659f, 0.0f, 0.594035f, -0.740708f, 0.313806f, 0.0f, -0.340185f, -0.887929f, 0.309605f, 0.0f, 0.312245f, -0.246681f, -0.917416f, 0.0f, 0.194206f, 0.186398f, -0.963089f, 0.0f, 0.915704f, 0.329835f, -0.229553f, 0.0f, 0.94133f, 0.229917f, 0.247055f, 0.0f, -0.888253f, -0.144148f, 0.436152f, 0.0f, -0.906917f, -0.362625f, -0.214486f, 0.0f, 0.403108f, -0.908884f, 0.10693f, 0.0f, 0.983963f, 0.169256f, 0.056292f, 0.0f, -0.197949f, 0.888236f, 0.414553f, 0.0f, 0.0879741f, 0.247673f, 0.964841f, 0.0f, 0.474384f, -0.868071f, -0.146331f, 0.0f, 0.699884f, 0.541342f, -0.465953f, 0.0f, 0.610965f, 0.567249f, 0.552223f, 0.0f, 0.830508f, -0.285788f, -0.478103f, 0.0f, 0.328573f, -0.683076f, -0.652263f, 0.0f, -0.00537775f, 0.873381f, 0.487009f, 0.0f, -0.51289f, 0.828835f, 0.223557f, 0.0f, -0.871168f, -0.15102f, 0.467182f, 0.0f, -0.545561f, 0.390016f, -0.741789f, 0.0f, 0.874063f, 0.259258f, 0.410852f, 0.0f, -0.781555f, 0.612184f, -0.120005f, 0.0f, -0.284928f, 0.708938f, -0.645154f, 0.0f, -0.568809f, 0.0883274f, 0.817713f, 0.0f, -0.0429388f, 0.549957f, -0.834088f, 0.0f, 0.933296f, -0.127233f, 0.335813f, 0.0f, 0.698149f, -0.493464f, 0.51873f, 0.0f, -0.603413f, 0.617495f, -0.504572f, 0.0f - }; - - __forceinline float fade(float t) { - return (t * t * t) * (t * (t * 6 - 15) + 10); - } - -/*__forceinline float fade(float t) { - return t * t * (3 - t * 2); - }*/ - - __forceinline float lerp(float t, float a, float b) { - return a + t * (b - a); - } - - __forceinline float grad(int hash, float x) { - return x*g1[hash&127]; - } - - __forceinline float grad(int hash, float x, float y) { - int h = hash&127; - return x*g2[2*h+0]+y*g2[2*h+1]; - } - - __forceinline float grad(int hash, float x, float y, float z) { - int h = hash&127; - return x*g3[4*h+0]+y*g3[4*h+1]+z*g3[4*h+2]; - } - - float noise(float x) - { - float fx = floorf(x); - int X = (int)fx & 255; - x -= fx; - float u = fade(x); - float g00 = grad(p[X ],x ); - float g10 = grad(p[X+1],x-1); - return lerp(u,g00,g10); - } - - float noise(float x, float y) - { - float fx = floorf(x); - float fy = floorf(y); - - int X = (int)fx & 255; - int Y = (int)fy & 255; - - x -= fx; - y -= fy; - - float u = fade(x); - float v = fade(y); - - int p00 = p[X ]+Y; - int p10 = p[X+1]+Y; - int p01 = p[X ]+Y+1; - int p11 = p[X+1]+Y+1; - - float g00 = grad(p[p00],x ,y ); - float g10 = grad(p[p10],x-1,y ); - float g01 = grad(p[p01],x ,y-1); - float g11 = grad(p[p11],x-1,y-1); - - return lerp(v,lerp(u,g00,g10),lerp(u,g01,g11)); - } - - float noise(const Vec3fa& pos) - { - float x = pos.x; - float y = pos.y; - float z = pos.z; - - float fx = floorf(x); - float fy = floorf(y); - float fz = floorf(z); - - int X = (int)fx & 255; - int Y = (int)fy & 255; - int Z = (int)fz & 255; - - x -= fx; - y -= fy; - z -= fz; - - float u = fade(x); - float v = fade(y); - float w = fade(z); - - int p00 = p[X]+Y; - int p000 = p[p00]+Z; - int p010 = p[p00+1]+Z; - int p001 = p000+1; - int p011 = p010+1; - int p10 = p[X+1]+Y; - int p100 = p[p10]+Z; - int p110 = p[p10+1]+Z; - int p101 = p100+1; - int p111 = p110+1; - - float g000 = grad(p[p000],x ,y ,z ); - float g100 = grad(p[p100],x-1,y ,z ); - float g010 = grad(p[p010],x ,y-1,z ); - float g110 = grad(p[p110],x-1,y-1,z ); - float g001 = grad(p[p001],x ,y ,z-1); - float g101 = grad(p[p101],x-1,y ,z-1); - float g011 = grad(p[p011],x ,y-1,z-1); - float g111 = grad(p[p111],x-1,y-1,z-1); - - return lerp(w, - lerp(v,lerp(u,g000,g100),lerp(u,g010,g110)), - lerp(v,lerp(u,g001,g101),lerp(u,g011,g111))); - } - - Vec3fa noise3D(const Vec3fa& p) - { - float x = noise(p.x+128.0f); - float y = noise(p.y+64.0f); - float z = noise(p.z+192.0f); - return Vec3fa(x,y,z); - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/noise.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/noise.h deleted file mode 100644 index 70504f4efb3c..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/noise.h +++ /dev/null @@ -1,26 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../math/vec.h" - -namespace embree -{ - /* noise functions */ - float noise(const Vec3fa& p); - Vec3fa noise3D(const Vec3fa& p); -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/optics.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/optics.h deleted file mode 100644 index ac170fd03314..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/optics.h +++ /dev/null @@ -1,186 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../math/sampling.h" - -namespace embree { - -/*! \addtogroup rivl_render_embree_ivl */ -/*! @{ */ - -/*! Reflects a viewing vector V at a normal N. */ -inline Vec3fa reflect(const Vec3fa& V, const Vec3fa& N) { return 2.0f*dot(V,N)*N-V; } -#ifdef ISPC -inline Vec3fa reflect(const Vec3fa& V, const Vec3fa& N) { return 2.0f*dot(V,N)*N-V; } -inline Vec3fa reflect(const Vec3fa& V, const Vec3fa& N) { return 2.0f*dot(V,N)*N-V; } -inline Vec3fa reflect(const Vec3fa& V, const Vec3fa& N) { return 2.0f*dot(V,N)*N-V; } -#endif - -/*! Reflects a viewing vector V at a normal N. Cosine between V - * and N is given as input. */ -inline Vec3fa reflect(const Vec3fa &V, const Vec3fa &N, const float cosi) { - return 2.0f*cosi*N-V; -} - -// ======================================================= -/*!Refracts a viewing vector V at a normal N using the relative - * refraction index eta. Eta is refraction index of outside medium - * (where N points into) divided by refraction index of the inside - * medium. The vectors V and N have to point towards the same side - * of the surface. The cosine between V and N is given as input and - * the cosine of -N and transmission ray is computed as output. */ -inline Sample3f refract(const Vec3fa& V, const Vec3fa& N, const float eta, - const float cosi, float &cost) -{ - const float k = 1.0f-eta*eta*(1.0f-cosi*cosi); - if (k < 0.0f) { cost = 0.0f; return make_Sample3f(Vec3fa(0.f),0.0f); } - cost = sqrt(k); - return make_Sample3f(eta*(cosi*N-V)-cost*N, sqr(eta)); -} - -/*! Computes fresnel coefficient for media interface with relative - * refraction index eta. Eta is the outside refraction index - * divided by the inside refraction index. Both cosines have to be - * positive. */ -inline float fresnelDielectric(const float cosi, const float cost, const float eta) -{ - const float Rper = (eta*cosi - cost) * rcp(eta*cosi + cost); - const float Rpar = ( cosi - eta*cost) * rcp( cosi + eta*cost); - return 0.5f*(Rpar*Rpar + Rper*Rper); -} - - /*! Computes fresnel coefficient for media interface with relative - * refraction index eta. Eta is the outside refraction index - * divided by the inside refraction index. The cosine has to be - * positive. */ -inline float fresnelDielectric(const float cosi, const float eta) -{ - const float k = 1.0f-eta*eta*(1.0f-cosi*cosi); - if (k < 0.0f) return 1.0f; - const float cost = sqrt(k); - return fresnelDielectric(cosi, cost, eta); -} - -/*! Computes fresnel coefficient for conductor medium with complex - * refraction index (eta,k). The cosine has to be positive. */ -inline Vec3fa fresnelConductor(const float cosi, const Vec3fa& eta, const Vec3fa& k) -{ - const Vec3fa tmp = eta*eta + k*k; - const Vec3fa Rpar = (tmp * (cosi*cosi) - 2.0f*eta*cosi + Vec3fa(1.0f)) * - rcp(tmp * (cosi*cosi) + 2.0f*eta*cosi + Vec3fa(1.0f)); - const Vec3fa Rper = (tmp - 2.0f*eta*cosi + Vec3fa(cosi*cosi)) * - rcp(tmp + 2.0f*eta*cosi + Vec3fa(cosi*cosi)); - return 0.5f * (Rpar + Rper); -} - -// ======================================================= -struct FresnelConductor { - Vec3fa eta; //!< Real part of refraction index - Vec3fa k; //!< Imaginary part of refraction index -}; - -inline Vec3fa eval(const FresnelConductor& This, const float cosTheta) { - return fresnelConductor(cosTheta,This.eta,This.k); -} - -inline FresnelConductor make_FresnelConductor(const Vec3fa& eta, const Vec3fa& k) { - FresnelConductor m; m.eta = eta; m.k = k; return m; -} - -#if defined(ISPC) -inline FresnelConductor make_FresnelConductor(const Vec3fa& eta, const Vec3fa& k) { - FresnelConductor m; m.eta = eta; m.k = k; return m; -} -#endif - -// ======================================================= -struct FresnelDielectric -{ - /*! refraction index of the medium the incident ray travels in */ - float etai; - - /*! refraction index of the medium the outgoing transmission rays - * travels in */ - float etat; -}; - -inline Vec3fa eval(const FresnelDielectric& This, const float cosTheta) { - return Vec3fa(fresnelDielectric(cosTheta,This.etai/This.etat)); -} - -inline FresnelDielectric make_FresnelDielectric(const float etai, const float etat) { - FresnelDielectric m; m.etai = etai; m.etat = etat; return m; -} - -#if defined(ISPC) -inline FresnelDielectric make_FresnelDielectric(const float etai, const float etat) { - FresnelDielectric m; m.etai = etai; m.etat = etat; return m; -} -#endif - -// ======================================================= -struct PowerCosineDistribution { - float exp; -}; - -inline float eval(const PowerCosineDistribution &This, const float cosThetaH) { - return (This.exp+2) * (1.0f/(2.0f*(float(pi)))) * pow(abs(cosThetaH), This.exp); -} - -#if defined(ISPC) - -inline float eval(const PowerCosineDistribution &This, const float cosThetaH) { - return (This.exp+2) * (1.0f/(2.0f*(float(pi)))) * pow(abs(cosThetaH), This.exp); -} -#endif - -/*! Samples the power cosine distribution. */ -inline void sample(const PowerCosineDistribution& This, const Vec3fa& wo, const Vec3fa& N, Sample3f &wi, const Vec2f s) -{ - Vec3fa dir = powerCosineSampleHemisphere(This.exp,s); - Sample3f wh; - wh.v = frame(N) * dir; - wh.pdf = powerCosineSampleHemispherePDF(dir,This.exp); - Sample3f r = make_Sample3f(reflect(wo,wh.v),1.0f); - wi = make_Sample3f(r.v,wh.pdf/(4.0f*abs(dot(wo,wh.v)))); -} - -/*! Samples the power cosine distribution. */ -#if defined(ISPC) -inline void sample(const PowerCosineDistribution& This, const Vec3fa& wo, const Vec3fa& N, Sample3f &wi, const Vec2f s) -{ - Vec3fa dir = powerCosineSampleHemisphere(This.exp,s); - Sample3f wh; - wh.v = frame(N) * dir; - wh.pdf = powerCosineSampleHemispherePDF(dir,This.exp); - Sample3f r = make_Sample3f(reflect(wo,wh.v),1.0f); - wi = make_Sample3f(r.v,wh.pdf/(4.0f*abs(dot(wo,wh.v)))); -} -#endif - -inline PowerCosineDistribution make_PowerCosineDistribution(const float _exp) { - PowerCosineDistribution m; m.exp = _exp; return m; -} - -#if defined(ISPC) -inline PowerCosineDistribution make_PowerCosineDistribution(const float _exp) { - PowerCosineDistribution m; m.exp = _exp; return m; -} -#endif - -} // namespace embree diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/scene.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/scene.cpp deleted file mode 100644 index 9909a5b81833..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/scene.cpp +++ /dev/null @@ -1,147 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "scene.h" - -namespace embree -{ - struct SceneGraphConverter - { - TutorialScene* scene; - std::map, unsigned> material2id; - std::map, unsigned> geometry2id; - - SceneGraphConverter (Ref in, TutorialScene* scene, TutorialScene::InstancingMode instancing) - : scene(scene) - { - convertLights(in,one); - - if (instancing != TutorialScene::INSTANCING_NONE) - { - if (instancing == TutorialScene::INSTANCING_SCENE_GROUP) - { - in->reset(); - in->calculateInDegree(); - in->calculateClosed(); - } - convertInstances(in,one); - } - else - convertGeometries(scene->geometries,in,one); - } - - unsigned convert(Ref node) - { - if (material2id.find(node) == material2id.end()) { - scene->materials.push_back(node->material); - material2id[node] = unsigned(scene->materials.size()-1); - } - return material2id[node]; - } - - Ref convertTriangleMesh(Ref mesh, const SceneGraph::Transformations& spaces) { - return new TutorialScene::TriangleMesh(mesh,spaces,convert(mesh->material)); - } - - Ref convertQuadMesh(Ref mesh, const SceneGraph::Transformations& spaces) { - return new TutorialScene::QuadMesh(mesh,spaces,convert(mesh->material)); - } - - Ref convertSubdivMesh(Ref mesh, const SceneGraph::Transformations& spaces) { - return new TutorialScene::SubdivMesh(mesh,spaces,convert(mesh->material)); - } - - Ref convertLineSegments(Ref mesh, const SceneGraph::Transformations& spaces) { - return new TutorialScene::LineSegments(mesh,spaces,convert(mesh->material)); - } - - Ref convertHairSet(Ref mesh, const SceneGraph::Transformations& spaces) { - return new TutorialScene::HairSet(mesh,spaces,convert(mesh->material)); - } - - void convertLights(Ref node, const SceneGraph::Transformations& spaces) - { - if (Ref xfmNode = node.dynamicCast()) { - convertLights(xfmNode->child, spaces*xfmNode->spaces); - } - else if (Ref groupNode = node.dynamicCast()) { - for (const auto& child : groupNode->children) convertLights(child,spaces); - } - else if (Ref lightNode = node.dynamicCast()) { - scene->lights.push_back(lightNode->light->transform(spaces[0])); - } - } - - void convertGeometries(std::vector>& group, Ref node, const SceneGraph::Transformations& spaces) - { - if (Ref xfmNode = node.dynamicCast()) { - convertGeometries(group,xfmNode->child, spaces*xfmNode->spaces); - } - else if (Ref groupNode = node.dynamicCast()) { - for (const auto& child : groupNode->children) convertGeometries(group,child,spaces); - } - else if (Ref mesh = node.dynamicCast()) { - group.push_back(convertTriangleMesh(mesh,spaces)); - } - else if (Ref mesh = node.dynamicCast()) { - group.push_back(convertQuadMesh(mesh,spaces)); - } - else if (Ref mesh = node.dynamicCast()) { - group.push_back(convertSubdivMesh(mesh,spaces)); - } - else if (Ref mesh = node.dynamicCast()) { - group.push_back(convertLineSegments(mesh,spaces)); - } - else if (Ref mesh = node.dynamicCast()) { - group.push_back(convertHairSet(mesh,spaces)); - } - } - - unsigned lookupGeometries(Ref node) - { - if (geometry2id.find(node) == geometry2id.end()) - { - std::vector> geometries; - convertGeometries(geometries,node,one); - - if (geometries.size() == 1) - scene->geometries.push_back(geometries[0]); - else - scene->geometries.push_back(new TutorialScene::Group(geometries)); - - geometry2id[node] = unsigned(scene->geometries.size()-1); - } - return geometry2id[node]; - } - - void convertInstances(Ref node, const SceneGraph::Transformations& spaces) - { - if (node->isClosed()) { - scene->geometries.push_back(new TutorialScene::Instance(spaces,lookupGeometries(node))); - } - else if (Ref xfmNode = node.dynamicCast()) { - convertInstances(xfmNode->child, spaces*xfmNode->spaces); - } - else if (Ref groupNode = node.dynamicCast()) { - for (const auto& child : groupNode->children) convertInstances(child,spaces); - } - } - }; - - void TutorialScene::add(Ref node, TutorialScene::InstancingMode instancing) { - SceneGraphConverter(node,this,instancing); - } -}; diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/scene.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/scene.h deleted file mode 100644 index a7befc8aaf95..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/scene.h +++ /dev/null @@ -1,330 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../default.h" -#include "../scenegraph/scenegraph.h" - -namespace embree -{ - enum Shader { - SHADER_DEFAULT, - SHADER_EYELIGHT, - SHADER_UV, - SHADER_TEXCOORDS, - SHADER_TEXCOORDS_GRID, - SHADER_NG, - SHADER_GEOMID, - SHADER_GEOMID_PRIMID, - SHADER_AMBIENT_OCCLUSION - }; - - /*! Scene representing the OBJ file */ - struct TutorialScene - { - TutorialScene () {} - - enum InstancingMode { INSTANCING_NONE, INSTANCING_GEOMETRY, INSTANCING_SCENE_GEOMETRY, INSTANCING_SCENE_GROUP }; - void add (Ref node, InstancingMode instancing); - - /*! OBJ Triangle */ - struct Triangle - { - public: - Triangle () {} - - Triangle (const Triangle& other) - : v0(other.v0), v1(other.v1), v2(other.v2), materialID(other.materialID) {} - - Triangle (unsigned v0, unsigned v1, unsigned v2, unsigned materialID) - : v0(v0), v1(v1), v2(v2), materialID(materialID) {} - - public: - unsigned v0, v1, v2, materialID; - }; - - /*! OBJ Quad */ - struct Quad - { - public: - Quad () {} - - Quad (unsigned v0, unsigned v1, unsigned v2, unsigned v3) - : v0(v0), v1(v1), v2(v2), v3(v3) {} - - public: - unsigned v0, v1, v2, v3; - }; - - struct Hair - { - public: - Hair () {} - Hair (unsigned vertex, unsigned id) - : vertex(vertex), id(id) {} - public: - unsigned vertex,id; //!< index of first control point and hair ID - }; - - struct Geometry : public RefCount - { - enum Type { TRIANGLE_MESH, SUBDIV_MESH, HAIR_SET, INSTANCE, GROUP, QUAD_MESH, LINE_SEGMENTS, CURVES }; - Type type; - - Geometry (Type type) : type(type) {} - }; - - /*! Triangle Mesh. */ - struct TriangleMesh : public Geometry - { - TriangleMesh (avector& positions, avector& normals, std::vector& texcoords, std::vector& triangles, unsigned materialID) - : Geometry(TRIANGLE_MESH), positions(positions), normals(normals), texcoords(texcoords), triangles(triangles), numTimeSteps(1), numVertices((unsigned int)positions.size()), materialID(materialID) {} - - TriangleMesh (Ref mesh, const SceneGraph::Transformations& spaces, unsigned materialID) - : Geometry(TRIANGLE_MESH), numTimeSteps((unsigned int)mesh->numTimeSteps()), numVertices((unsigned int)mesh->numVertices()), materialID(materialID) - { - positions.resize(numTimeSteps*numVertices); - for (size_t t=0; t 1 ? float(t)/float(numTimeSteps-1) : 0.0f; - const AffineSpace3fa space = spaces.interpolate(time); - for (size_t i=0; ipositions[t][i]); - } - - const LinearSpace3fa nspace0 = rcp(spaces[0].l).transposed(); - normals.resize(mesh->normals.size()); - for (size_t i=0; inormals.size(); i++) - normals[i] = xfmVector(nspace0,mesh->normals[i]); - - texcoords = mesh->texcoords; - - triangles.resize(mesh->triangles.size()); - for (size_t i=0; itriangles.size(); i++) { - SceneGraph::TriangleMeshNode::Triangle& tri = mesh->triangles[i]; - triangles[i] = TutorialScene::Triangle(tri.v0,tri.v1,tri.v2,materialID); - } - } - - public: - avector positions; //!< vertex positions for all time steps - avector normals; //!< vertex normals - std::vector texcoords; //!< texture coordinates - std::vector triangles; //!< triangle indices - - unsigned numTimeSteps; - unsigned numVertices; - unsigned materialID; - }; - - /*! Quad Mesh. */ - struct QuadMesh : public Geometry - { - QuadMesh (Ref mesh, const SceneGraph::Transformations& spaces, unsigned materialID) - : Geometry(QUAD_MESH), numTimeSteps((unsigned int)mesh->numTimeSteps()), numVertices((unsigned int)mesh->numVertices()), materialID(materialID) - { - positions.resize(numTimeSteps*numVertices); - for (size_t t=0; t 1 ? float(t)/float(numTimeSteps-1) : 0.0f; - const AffineSpace3fa space = spaces.interpolate(time); - for (size_t i=0; ipositions[t][i]); - } - - const LinearSpace3fa nspace0 = rcp(spaces[0].l).transposed(); - normals.resize(mesh->normals.size()); - for (size_t i=0; inormals.size(); i++) - normals[i] = xfmVector(nspace0,mesh->normals[i]); - - texcoords = mesh->texcoords; - - quads.resize(mesh->quads.size()); - for (size_t i=0; iquads.size(); i++) { - SceneGraph::QuadMeshNode::Quad& quad = mesh->quads[i]; - quads[i] = TutorialScene::Quad(quad.v0,quad.v1,quad.v2,quad.v3); - } - } - - public: - avector positions; //!< vertex positions for all time steps - avector normals; //!< vertex normals - std::vector texcoords; //!< texture coordinates - std::vector quads; //!< quad indices - - unsigned numTimeSteps; - unsigned numVertices; - unsigned materialID; - }; - - /*! Subdivision Mesh. */ - struct SubdivMesh : public Geometry - { - SubdivMesh (Ref mesh, const SceneGraph::Transformations& spaces, unsigned materialID) - : Geometry(SUBDIV_MESH), - position_subdiv_mode(mesh->position_subdiv_mode), - normal_subdiv_mode(mesh->normal_subdiv_mode), - texcoord_subdiv_mode(mesh->texcoord_subdiv_mode), - numTimeSteps((unsigned int)mesh->numTimeSteps()), numPositions((unsigned int)mesh->numPositions()), materialID(materialID) - { - positions.resize(numTimeSteps*numPositions); - for (size_t t=0; t 1 ? float(t)/float(numTimeSteps-1) : 0.0f; - const AffineSpace3fa space = spaces.interpolate(time); - for (size_t i=0; ipositions[t][i]); - } - - const LinearSpace3fa nspace0 = rcp(spaces[0].l).transposed(); - normals.resize(mesh->normals.size()); - for (size_t i=0; inormals.size(); i++) - normals[i] = xfmVector(nspace0,mesh->normals[i]); - - texcoords = mesh->texcoords; - if (texcoords.size()) { // zero pad to 16 bytes - texcoords.reserve(texcoords.size()+1); - texcoords.data()[texcoords.size()] = zero; - } - position_indices = mesh->position_indices; - normal_indices = mesh->normal_indices; - texcoord_indices = mesh->texcoord_indices; - verticesPerFace = mesh->verticesPerFace; - holes = mesh->holes; - edge_creases = mesh->edge_creases; - edge_crease_weights = mesh->edge_crease_weights; - vertex_creases = mesh->vertex_creases; - vertex_crease_weights = mesh->vertex_crease_weights; - } - - public: - avector positions; //!< vertex positions for all timesteps - avector normals; //!< face vertex normals - std::vector texcoords; //!< face texture coordinates - std::vector position_indices; //!< position indices for all faces - std::vector normal_indices; //!< normal indices for all faces - std::vector texcoord_indices; //!< texcoord indices for all faces - RTCSubdivisionMode position_subdiv_mode; - RTCSubdivisionMode normal_subdiv_mode; - RTCSubdivisionMode texcoord_subdiv_mode; - std::vector verticesPerFace; //!< number of indices of each face - std::vector holes; //!< face ID of holes - std::vector edge_creases; //!< index pairs for edge crease - std::vector edge_crease_weights; //!< weight for each edge crease - std::vector vertex_creases; //!< indices of vertex creases - std::vector vertex_crease_weights; //!< weight for each vertex crease - - unsigned numTimeSteps; - unsigned numPositions; - unsigned materialID; - }; - - /*! Line segments. */ - struct LineSegments : public Geometry - { - LineSegments (Ref mesh, const SceneGraph::Transformations& spaces, unsigned materialID) - : Geometry(LINE_SEGMENTS), numTimeSteps((unsigned int)mesh->numTimeSteps()), numVertices((unsigned int)mesh->numVertices()), materialID(materialID) - { - positions.resize(numTimeSteps*numVertices); - for (size_t t=0; t 1 ? float(t)/float(numTimeSteps-1) : 0.0f; - const AffineSpace3fa space = spaces.interpolate(time); - for (size_t i=0; ipositions[t][i]); - positions[t*numVertices+i].w = mesh->positions[t][i].w; - } - } - - indices.resize(mesh->indices.size()); - for (size_t i=0; iindices.size(); i++) - indices[i] = mesh->indices[i]; - } - - public: - avector positions; //!< control points (x,y,z,r) for all timesteps - std::vector indices; //!< index buffer - - unsigned numTimeSteps; - unsigned numVertices; - unsigned materialID; - }; - - /*! Hair Set. */ - struct HairSet : public Geometry - { - HairSet (avector& positions, std::vector& hairs, unsigned materialID, bool hair) - : Geometry(hair ? HAIR_SET : CURVES), positions(positions), hairs(hairs), numTimeSteps(1), numVertices((unsigned int)positions.size()), materialID(materialID), tessellation_rate(4) {} - - HairSet (Ref mesh, const SceneGraph::Transformations& spaces, unsigned materialID) - : Geometry(mesh->hair ? HAIR_SET : CURVES), numTimeSteps((unsigned int)mesh->numTimeSteps()), numVertices((unsigned int)mesh->numVertices()), materialID(materialID), tessellation_rate(mesh->tessellation_rate) - { - positions.resize(numTimeSteps*numVertices); - for (size_t t=0; t 1 ? float(t)/float(numTimeSteps-1) : 0.0f; - const AffineSpace3fa space = spaces.interpolate(time); - for (size_t i=0; ipositions[t][i]); - positions[t*numVertices+i].w = mesh->positions[t][i].w; - } - } - - hairs.resize(mesh->hairs.size()); - for (size_t i=0; ihairs.size(); i++) - hairs[i] = TutorialScene::Hair(mesh->hairs[i].vertex,mesh->hairs[i].id); - } - - public: - avector positions; //!< hair control points (x,y,z,r) - std::vector hairs; //!< list of hairs - - unsigned numTimeSteps; - unsigned numVertices; - unsigned materialID; - unsigned tessellation_rate; - }; - - struct Instance : public Geometry - { - ALIGNED_STRUCT; - - Instance (const SceneGraph::Transformations& spaces, unsigned geomID) - : Geometry(INSTANCE), spaces(spaces), geomID(geomID) {} - - public: - SceneGraph::Transformations spaces; - unsigned geomID; - }; - - struct Group : public Geometry - { - Group (std::vector> children) - : Geometry(GROUP), children(children) {} - - size_t size() const { return children.size(); } - Ref at(size_t i) { return children[i]; } - - public: - std::vector> children; - }; - - bool empty() const { - return geometries.size() == 0; - } - - public: - avector materials; //!< material list - std::vector > geometries; //!< list of geometries - std::vector> lights; //!< list of lights - }; -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/scene_device.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/scene_device.cpp deleted file mode 100644 index 210ce37bcb88..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/scene_device.cpp +++ /dev/null @@ -1,327 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "scene_device.h" - -#define FIXED_EDGE_TESSELLATION_VALUE 4 - -namespace embree -{ - extern "C" RTCScene* geomID_to_scene = nullptr; - extern "C" ISPCInstance** geomID_to_inst = nullptr; - extern "C" int g_instancing_mode; - - unsigned int ConvertTriangleMesh(ISPCTriangleMesh* mesh, RTCGeometryFlags gflags, RTCScene scene_out) - { - unsigned int geomID = rtcNewTriangleMesh (scene_out, gflags, mesh->numTriangles, mesh->numVertices, mesh->numTimeSteps); - for (size_t t=0; tnumTimeSteps; t++) { - rtcSetBuffer(scene_out, geomID, (RTCBufferType)(RTC_VERTEX_BUFFER+t), mesh->positions+t*mesh->numVertices, 0, sizeof(Vec3fa )); - } - rtcSetBuffer(scene_out, geomID, RTC_INDEX_BUFFER, mesh->triangles, 0, sizeof(ISPCTriangle)); - mesh->scene = scene_out; - mesh->geomID = geomID; - return geomID; - } - - unsigned int ConvertQuadMesh(ISPCQuadMesh* mesh, RTCGeometryFlags gflags, RTCScene scene_out) - { - unsigned int geomID = rtcNewQuadMesh (scene_out, gflags, mesh->numQuads, mesh->numVertices, mesh->numTimeSteps); - for (size_t t=0; tnumTimeSteps; t++) { - rtcSetBuffer(scene_out, geomID, (RTCBufferType)(RTC_VERTEX_BUFFER+t), mesh->positions+t*mesh->numVertices, 0, sizeof(Vec3fa )); - } - rtcSetBuffer(scene_out, geomID, RTC_INDEX_BUFFER, mesh->quads, 0, sizeof(ISPCQuad)); - mesh->scene = scene_out; - mesh->geomID = geomID; - return geomID; - } - - unsigned int ConvertSubdivMesh(ISPCSubdivMesh* mesh, RTCGeometryFlags gflags, RTCScene scene_out) - { - unsigned int geomID = rtcNewSubdivisionMesh(scene_out, gflags, mesh->numFaces, mesh->numEdges, mesh->numVertices, - mesh->numEdgeCreases, mesh->numVertexCreases, mesh->numHoles, mesh->numTimeSteps); - for (size_t i=0; inumEdges; i++) mesh->subdivlevel[i] = FIXED_EDGE_TESSELLATION_VALUE; - for (size_t t=0; tnumTimeSteps; t++) { - rtcSetBuffer(scene_out, geomID, (RTCBufferType)(RTC_VERTEX_BUFFER+t), mesh->positions+t*mesh->numVertices, 0, sizeof(Vec3fa )); - } - rtcSetBuffer(scene_out, geomID, RTC_LEVEL_BUFFER, mesh->subdivlevel, 0, sizeof(float)); - - /* create geometry topology */ - rtcSetBuffer(scene_out, geomID, RTC_INDEX_BUFFER, mesh->position_indices , 0, sizeof(unsigned int)); - rtcSetSubdivisionMode(scene_out, geomID, 0, mesh->position_subdiv_mode); - - /* set normal buffers and optionally normal topology */ - if (mesh->normals) { - rtcSetBuffer2(scene_out, geomID, (RTCBufferType)(RTC_USER_VERTEX_BUFFER+1), mesh->normals, 0, sizeof(Vec3fa ), mesh->numNormals); - if (mesh->normal_indices) { - rtcSetBuffer(scene_out, geomID, (RTCBufferType)(RTC_INDEX_BUFFER+1), mesh->normal_indices , 0, sizeof(unsigned int)); - rtcSetIndexBuffer(scene_out, geomID, (RTCBufferType)(RTC_USER_VERTEX_BUFFER+1), (RTCBufferType)(RTC_INDEX_BUFFER+1)); - rtcSetSubdivisionMode(scene_out, geomID, 1, mesh->normal_subdiv_mode); - } - } - - /* set texcoord buffer and optionally texcoord topology */ - if (mesh->texcoords) { - rtcSetBuffer2(scene_out, geomID, (RTCBufferType)(RTC_USER_VERTEX_BUFFER+2), mesh->texcoords, 0, sizeof(Vec2f), mesh->numTexCoords); - if (mesh->texcoord_indices) { - rtcSetBuffer(scene_out, geomID, (RTCBufferType)(RTC_INDEX_BUFFER+2), mesh->texcoord_indices , 0, sizeof(unsigned int)); - rtcSetIndexBuffer(scene_out, geomID, (RTCBufferType)(RTC_USER_VERTEX_BUFFER+2), (RTCBufferType)(RTC_INDEX_BUFFER+2)); - rtcSetSubdivisionMode(scene_out, geomID, 2, mesh->texcoord_subdiv_mode); - } - } - - rtcSetBuffer(scene_out, geomID, RTC_FACE_BUFFER, mesh->verticesPerFace, 0, sizeof(unsigned int)); - rtcSetBuffer(scene_out, geomID, RTC_HOLE_BUFFER, mesh->holes, 0, sizeof(unsigned int)); - rtcSetBuffer(scene_out, geomID, RTC_EDGE_CREASE_INDEX_BUFFER, mesh->edge_creases, 0, 2*sizeof(unsigned int)); - rtcSetBuffer(scene_out, geomID, RTC_EDGE_CREASE_WEIGHT_BUFFER, mesh->edge_crease_weights, 0, sizeof(float)); - rtcSetBuffer(scene_out, geomID, RTC_VERTEX_CREASE_INDEX_BUFFER, mesh->vertex_creases, 0, sizeof(unsigned int)); - rtcSetBuffer(scene_out, geomID, RTC_VERTEX_CREASE_WEIGHT_BUFFER, mesh->vertex_crease_weights, 0, sizeof(float)); - mesh->scene = scene_out; - mesh->geomID = geomID; - return geomID; - } - - unsigned int ConvertLineSegments(ISPCLineSegments* mesh, RTCGeometryFlags gflags, RTCScene scene_out) - { - unsigned int geomID = rtcNewLineSegments (scene_out, gflags, mesh->numSegments, mesh->numVertices, mesh->numTimeSteps); - for (size_t t=0; tnumTimeSteps; t++) { - rtcSetBuffer(scene_out,geomID,(RTCBufferType)(RTC_VERTEX_BUFFER+t), mesh->positions+t*mesh->numVertices,0,sizeof(Vec3fa)); - } - rtcSetBuffer(scene_out,geomID,RTC_INDEX_BUFFER,mesh->indices,0,sizeof(int)); - mesh->scene = scene_out; - mesh->geomID = geomID; - return geomID; - } - - unsigned int ConvertHairSet(ISPCHairSet* mesh, RTCGeometryFlags gflags, RTCScene scene_out) - { - unsigned int geomID = rtcNewHairGeometry (scene_out, gflags, mesh->numHairs, mesh->numVertices, mesh->numTimeSteps); - for (size_t t=0; tnumTimeSteps; t++) { - rtcSetBuffer(scene_out,geomID,(RTCBufferType)(RTC_VERTEX_BUFFER+t), mesh->positions+t*mesh->numVertices,0,sizeof(Vec3fa)); - } - rtcSetBuffer(scene_out,geomID,RTC_INDEX_BUFFER,mesh->hairs,0,sizeof(ISPCHair)); - rtcSetTessellationRate(scene_out,geomID,(float)mesh->tessellation_rate); - mesh->scene = scene_out; - mesh->geomID = geomID; - return geomID; - } - - unsigned int ConvertCurveGeometry(ISPCHairSet* mesh, RTCGeometryFlags gflags, RTCScene scene_out) - { - unsigned int geomID = rtcNewCurveGeometry (scene_out, gflags, mesh->numHairs, mesh->numVertices, mesh->numTimeSteps); - for (size_t t=0; tnumTimeSteps; t++) { - rtcSetBuffer(scene_out,geomID,(RTCBufferType)(RTC_VERTEX_BUFFER+t), mesh->positions+t*mesh->numVertices,0,sizeof(Vec3fa)); - } - rtcSetBuffer(scene_out,geomID,RTC_INDEX_BUFFER,mesh->hairs,0,sizeof(ISPCHair)); - mesh->scene = scene_out; - mesh->geomID = geomID; - return geomID; - } - - void ConvertGroup(ISPCGroup* group, RTCGeometryFlags gflags, RTCScene scene_out) - { - for (size_t i=0; inumGeometries; i++) - { - ISPCGeometry* geometry = group->geometries[i]; - if (geometry->type == SUBDIV_MESH) - ConvertSubdivMesh((ISPCSubdivMesh*) geometry, gflags, scene_out); - else if (geometry->type == TRIANGLE_MESH) - ConvertTriangleMesh((ISPCTriangleMesh*) geometry, gflags, scene_out); - else if (geometry->type == QUAD_MESH) - ConvertQuadMesh((ISPCQuadMesh*) geometry, gflags, scene_out); - else if (geometry->type == LINE_SEGMENTS) - ConvertLineSegments((ISPCLineSegments*) geometry, gflags, scene_out); - else if (geometry->type == HAIR_SET) - ConvertHairSet((ISPCHairSet*) geometry, gflags, scene_out); - else if (geometry->type == CURVES) - ConvertCurveGeometry((ISPCHairSet*) geometry, gflags, scene_out); - else - assert(false); - } - } - - unsigned int ConvertInstance(ISPCInstance* instance, int meshID, RTCScene scene_out) - { - /*if (g_instancing_mode == 1) { - unsigned int geom_inst = instance->geomID; - unsigned int geomID = rtcNewGeometryInstance(scene_out, geom_inst); - rtcSetTransform(scene_out,geomID,RTC_MATRIX_COLUMN_MAJOR_ALIGNED16,&instance->space.l.vx.x); - return geomID; - } else */ - { - RTCScene scene_inst = geomID_to_scene[instance->geomID]; - if (instance->numTimeSteps == 1) { - unsigned int geomID = rtcNewInstance(scene_out, scene_inst); - rtcSetTransform(scene_out,geomID,RTC_MATRIX_COLUMN_MAJOR_ALIGNED16,&instance->spaces[0].l.vx.x); - return geomID; - } - else { - unsigned int geomID = rtcNewInstance2(scene_out, scene_inst, instance->numTimeSteps); - for (size_t t=0; tnumTimeSteps; t++) - rtcSetTransform2(scene_out,geomID,RTC_MATRIX_COLUMN_MAJOR_ALIGNED16,&instance->spaces[t].l.vx.x,t); - return geomID; - } - } - } - - typedef ISPCInstance* ISPCInstance_ptr; - typedef ISPCGeometry* ISPCGeometry_ptr; - - extern "C" RTCScene ConvertScene(RTCDevice g_device, ISPCScene* scene_in, RTCSceneFlags sflags, RTCAlgorithmFlags aflags, RTCGeometryFlags gflags) - { - size_t numGeometries = scene_in->numGeometries; - geomID_to_scene = (RTCScene*) alignedMalloc(numGeometries*sizeof(RTCScene)); - geomID_to_inst = (ISPCInstance_ptr*) alignedMalloc(numGeometries*sizeof(ISPCInstance_ptr)); - RTCScene scene_out = rtcDeviceNewScene(g_device,sflags,aflags); - - /* use geometry instancing feature */ - if (g_instancing_mode == 1) - { - for (unsigned int i=0; inumGeometries; i++) - { - ISPCGeometry* geometry = scene_in->geometries[i]; - if (geometry->type == SUBDIV_MESH) { - unsigned int geomID = ConvertSubdivMesh((ISPCSubdivMesh*) geometry, gflags, scene_out); - assert(geomID == i); - rtcDisable(scene_out,geomID); - } - else if (geometry->type == TRIANGLE_MESH) { - unsigned int geomID = ConvertTriangleMesh((ISPCTriangleMesh*) geometry, gflags, scene_out); - assert(geomID == i); - rtcDisable(scene_out,geomID); - } - else if (geometry->type == QUAD_MESH) { - unsigned int geomID = ConvertQuadMesh((ISPCQuadMesh*) geometry, gflags, scene_out); - assert(geomID == i); - rtcDisable(scene_out,geomID); - } - else if (geometry->type == LINE_SEGMENTS) { - unsigned int geomID = ConvertLineSegments((ISPCLineSegments*) geometry, gflags, scene_out); - assert(geomID == i); - rtcDisable(scene_out,geomID); - } - else if (geometry->type == HAIR_SET) { - unsigned int geomID = ConvertHairSet((ISPCHairSet*) geometry, gflags, scene_out); - assert(geomID == i); - rtcDisable(scene_out,geomID); - } - else if (geometry->type == CURVES) { - unsigned int geomID = ConvertCurveGeometry((ISPCHairSet*) geometry, gflags, scene_out); - assert(geomID == i); - rtcDisable(scene_out,geomID); - } - else if (geometry->type == INSTANCE) { - unsigned int geomID = ConvertInstance((ISPCInstance*) geometry, i, scene_out); - assert(geomID == i); geomID_to_inst[geomID] = (ISPCInstance*) geometry; - } - else - assert(false); - } - } - - /* use scene instancing feature */ - else if (g_instancing_mode == 2 || g_instancing_mode == 3) - { - for (unsigned int i=0; inumGeometries; i++) - { - ISPCGeometry* geometry = scene_in->geometries[i]; - if (geometry->type == SUBDIV_MESH) { - RTCScene objscene = rtcDeviceNewScene(g_device,sflags,aflags); - ConvertSubdivMesh((ISPCSubdivMesh*) geometry,gflags,objscene); - geomID_to_scene[i] = objscene; - //rtcCommit(objscene); - } - else if (geometry->type == TRIANGLE_MESH) { - RTCScene objscene = rtcDeviceNewScene(g_device,sflags,aflags); - ConvertTriangleMesh((ISPCTriangleMesh*) geometry,gflags,objscene); - geomID_to_scene[i] = objscene; - //rtcCommit(objscene); - } - else if (geometry->type == QUAD_MESH) { - RTCScene objscene = rtcDeviceNewScene(g_device,sflags,aflags); - ConvertQuadMesh((ISPCQuadMesh*) geometry,gflags,objscene); - geomID_to_scene[i] = objscene; - //rtcCommit(objscene); - } - else if (geometry->type == LINE_SEGMENTS) { - RTCScene objscene = rtcDeviceNewScene(g_device,sflags,aflags); - ConvertLineSegments((ISPCLineSegments*) geometry,gflags,objscene); - geomID_to_scene[i] = objscene; - //rtcCommit(objscene); - } - else if (geometry->type == HAIR_SET) { - RTCScene objscene = rtcDeviceNewScene(g_device,sflags,aflags); - ConvertHairSet((ISPCHairSet*) geometry,gflags,objscene); - geomID_to_scene[i] = objscene; - //rtcCommit(objscene); - } - else if (geometry->type == CURVES) { - RTCScene objscene = rtcDeviceNewScene(g_device,sflags,aflags); - ConvertCurveGeometry((ISPCHairSet*) geometry,gflags,objscene); - geomID_to_scene[i] = objscene; - //rtcCommit(objscene); - } - else if (geometry->type == GROUP) { - RTCScene objscene = rtcDeviceNewScene(g_device,sflags,aflags); - ConvertGroup((ISPCGroup*) geometry,gflags,objscene); - geomID_to_scene[i] = objscene; - //rtcCommit(objscene); - } - else if (geometry->type == INSTANCE) { - unsigned int geomID = ConvertInstance((ISPCInstance*) geometry, i, scene_out); - geomID_to_scene[i] = nullptr; geomID_to_inst[geomID] = (ISPCInstance*) geometry; - } - else - assert(false); - } - } - - /* no instancing */ - else - { - for (unsigned int i=0; inumGeometries; i++) - { - ISPCGeometry* geometry = scene_in->geometries[i]; - if (geometry->type == SUBDIV_MESH) { - unsigned int geomID MAYBE_UNUSED = ConvertSubdivMesh((ISPCSubdivMesh*) geometry, gflags, scene_out); - assert(geomID == i); - } - else if (geometry->type == TRIANGLE_MESH) { - unsigned int geomID MAYBE_UNUSED = ConvertTriangleMesh((ISPCTriangleMesh*) geometry, gflags, scene_out); - assert(geomID == i); - } - else if (geometry->type == QUAD_MESH) { - unsigned int geomID MAYBE_UNUSED = ConvertQuadMesh((ISPCQuadMesh*) geometry, gflags, scene_out); - assert(geomID == i); - } - else if (geometry->type == LINE_SEGMENTS) { - unsigned int geomID MAYBE_UNUSED = ConvertLineSegments((ISPCLineSegments*) geometry, gflags, scene_out); - assert(geomID == i); - } - else if (geometry->type == HAIR_SET) { - unsigned int geomID MAYBE_UNUSED = ConvertHairSet((ISPCHairSet*) geometry, gflags, scene_out); - assert(geomID == i); - } - else if (geometry->type == CURVES) { - unsigned int geomID MAYBE_UNUSED = ConvertCurveGeometry((ISPCHairSet*) geometry, gflags, scene_out); - assert(geomID == i); - } - else - assert(false); - } - } - return scene_out; - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/scene_device.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/scene_device.h deleted file mode 100644 index f21abcaca61e..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/scene_device.h +++ /dev/null @@ -1,479 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../math/sampling.h" -#include "../lights/light.h" -#include "../lights/ambient_light.h" -#include "../lights/directional_light.h" -#include "../lights/point_light.h" -#include "../lights/quad_light.h" -#include "../lights/spot_light.h" -#include "scene.h" - -namespace embree -{ - struct ISPCTriangle - { - unsigned v0; /*< first triangle vertex */ - unsigned v1; /*< second triangle vertex */ - unsigned v2; /*< third triangle vertex */ - unsigned materialID; /*< material of triangle */ - }; - - struct ISPCQuad - { - unsigned v0; /*< first triangle vertex */ - unsigned v1; /*< second triangle vertex */ - unsigned v2; /*< third triangle vertex */ - unsigned v3; /*< fourth triangle vertex */ - }; - - struct ISPCHair - { - unsigned vertex; - unsigned id; - }; - - enum ISPCType { TRIANGLE_MESH, SUBDIV_MESH, HAIR_SET, INSTANCE, GROUP, QUAD_MESH, LINE_SEGMENTS, CURVES }; - - struct ISPCMaterial - { - int ty; - int align0,align1,align2; - Vec3fa v[7]; - }; - - enum TEXTURE_FORMAT { - Texture_RGBA8 = 1, - Texture_RGB8 = 2, - Texture_FLOAT32 = 3, - }; - - struct ISPCScene - { - struct ISPCGeometry - { - ISPCGeometry (ISPCType type) : type(type) {} - - ISPCType type; - }; - - struct ISPCTriangleMesh - { - ISPCTriangleMesh (Ref in) : geom(TRIANGLE_MESH) - { - positions = in->positions.data(); - normals = in->normals.data(); - texcoords = in->texcoords.data(); - triangles = (ISPCTriangle*) in->triangles.data(); - numTimeSteps = in->numTimeSteps; - numVertices = in->numVertices; - numTriangles = unsigned(in->triangles.size()); - scene = nullptr; - geomID = -1; - materialID = in->materialID; - } - - public: - ISPCGeometry geom; - Vec3fa* positions; //!< vertex position array with all timesteps - Vec3fa* normals; //!< vertex normal array - Vec2f* texcoords; //!< vertex texcoord array - ISPCTriangle* triangles; //!< list of triangles - - unsigned int numTimeSteps; - unsigned int numVertices; - unsigned int numTriangles; - RTCScene scene; - unsigned int geomID; - unsigned int materialID; - }; - - struct ISPCQuadMesh - { - ISPCQuadMesh (Ref in) : geom(QUAD_MESH) - { - positions = in->positions.data(); - normals = in->normals.data(); - texcoords = in->texcoords.data(); - quads = (ISPCQuad*) in->quads.data(); - numTimeSteps = in->numTimeSteps; - numVertices = in->numVertices; - numQuads = unsigned(in->quads.size()); - scene = nullptr; - geomID = -1; - materialID = in->materialID; - } - - public: - ISPCGeometry geom; - Vec3fa* positions; //!< vertex position array - Vec3fa* normals; //!< vertex normal array - Vec2f* texcoords; //!< vertex texcoord array - ISPCQuad* quads; //!< list of quads - - unsigned int numTimeSteps; - unsigned int numVertices; - unsigned int numQuads; - RTCScene scene; - unsigned int geomID; - unsigned int materialID; - }; - - struct ISPCSubdivMesh - { - ISPCSubdivMesh (Ref in) - : geom(SUBDIV_MESH) - { - positions = in->positions.data(); - normals = in->normals.data(); - texcoords = in->texcoords.data(); - position_indices = in->position_indices.data(); - normal_indices = in->normal_indices.data(); - texcoord_indices = in->texcoord_indices.data(); - position_subdiv_mode = in->position_subdiv_mode; - normal_subdiv_mode = in->normal_subdiv_mode; - texcoord_subdiv_mode = in->texcoord_subdiv_mode; - verticesPerFace = in->verticesPerFace.data(); - holes = in->holes.data(); - edge_creases = in->edge_creases.data(); - edge_crease_weights = in->edge_crease_weights.data(); - vertex_creases = in->vertex_creases.data(); - vertex_crease_weights = in->vertex_crease_weights.data(); - numTimeSteps = in->numTimeSteps; - numVertices = in->numPositions; - numFaces = unsigned(in->verticesPerFace.size()); - numEdges = unsigned(in->position_indices.size()); - numEdgeCreases = unsigned(in->edge_creases.size()); - numVertexCreases = unsigned(in->vertex_creases.size()); - numHoles = unsigned(in->holes.size()); - numNormals = unsigned(in->normals.size()); - numTexCoords = unsigned(in->texcoords.size()); - materialID = in->materialID; - scene = nullptr; - geomID = -1; - - size_t numEdges = in->position_indices.size(); - size_t numFaces = in->verticesPerFace.size(); - subdivlevel = new float[numEdges]; - face_offsets = new unsigned[numFaces]; - for (size_t i=0; i in) : geom(LINE_SEGMENTS) - { - positions = in->positions.data(); - indices = in->indices.data(); - numTimeSteps = in->numTimeSteps; - numVertices = in->numVertices; - numSegments = unsigned(in->indices.size()); - materialID = in->materialID; - scene = nullptr; - geomID = -1; - } - - public: - ISPCGeometry geom; - Vec3fa* positions; //!< control points (x,y,z,r) - unsigned* indices; //!< for each segment, index to first control point - - unsigned int numTimeSteps; - unsigned int numVertices; - unsigned int numSegments; - unsigned int materialID; - RTCScene scene; - unsigned int geomID; - }; - - struct ISPCHairSet - { - ISPCHairSet (bool hair, Ref in) : geom(hair ? HAIR_SET : CURVES) - { - positions = in->positions.data(); - hairs = (ISPCHair*) in->hairs.data(); - numTimeSteps = in->numTimeSteps; - numVertices = in->numVertices; - numHairs = unsigned(in->hairs.size()); - materialID = in->materialID; - scene = nullptr; - geomID = -1; - tessellation_rate = in->tessellation_rate; - } - - public: - ISPCGeometry geom; - Vec3fa* positions; //!< hair control points (x,y,z,r) - ISPCHair* hairs; //!< for each hair, index to first control point - - unsigned int numTimeSteps; - unsigned int numVertices; - unsigned int numHairs; - unsigned int materialID; - RTCScene scene; - unsigned int geomID; - unsigned int tessellation_rate; - }; - - struct ISPCInstance - { - ALIGNED_STRUCT; - - static ISPCInstance* create (Ref in) { - return ::new (alignedMalloc(sizeof(ISPCInstance)+(in->spaces.size()-1)*sizeof(AffineSpace3fa))) ISPCInstance(in); - } - - private: - ISPCInstance (Ref in) - : geom(INSTANCE), geomID(in->geomID), numTimeSteps(unsigned(in->spaces.size())) - { - for (size_t i=0; ispaces[i]; - } - - public: - ISPCGeometry geom; - unsigned int geomID; - unsigned int numTimeSteps; - AffineSpace3fa spaces[1]; - }; - - struct ISPCGroup - { - ISPCGroup (Ref in) - : geom(GROUP) - { - numGeometries = in->size(); - geometries = new ISPCGeometry*[numGeometries]; - for (size_t i=0; iat(i)); - } - - ~ISPCGroup() - { - for (size_t i=0; igeometries.size()]; - for (size_t i=0; igeometries.size(); i++) - geometries[i] = convertGeometry(in->geometries[i]); - numGeometries = unsigned(in->geometries.size()); - - materials = (ISPCMaterial*) in->materials.data(); - numMaterials = unsigned(in->materials.size()); - - lights = new Light*[in->lights.size()]; - numLights = 0; - for (size_t i=0; ilights.size(); i++) - { - Light* light = convertLight(in->lights[i]); - if (light) lights[numLights++] = light; - } - } - - ~ISPCScene() - { - /* delete all geometries */ - for (size_t i=0; itype) { - case TRIANGLE_MESH: delete (ISPCTriangleMesh*) geometries[i]; break; - case SUBDIV_MESH : delete (ISPCSubdivMesh*) geometries[i]; break; - case HAIR_SET: delete (ISPCHairSet*) geometries[i]; break; - case INSTANCE: delete (ISPCInstance*) geometries[i]; break; - case GROUP: delete (ISPCGroup*) geometries[i]; break; - case QUAD_MESH: delete (ISPCQuadMesh*) geometries[i]; break; - case LINE_SEGMENTS: delete (ISPCLineSegments*) geometries[i]; break; - case CURVES: delete (ISPCHairSet*) geometries[i]; break; - default: assert(false); break; - } - } - delete[] geometries; - - /* delete all lights */ - //for (size_t i=0; i in) - { - if (in->type == TutorialScene::Geometry::TRIANGLE_MESH) - return (ISPCGeometry*) new ISPCTriangleMesh(in.dynamicCast()); - else if (in->type == TutorialScene::Geometry::QUAD_MESH) - return (ISPCGeometry*) new ISPCQuadMesh(in.dynamicCast()); - else if (in->type == TutorialScene::Geometry::SUBDIV_MESH) - return (ISPCGeometry*) new ISPCSubdivMesh(in.dynamicCast()); - else if (in->type == TutorialScene::Geometry::LINE_SEGMENTS) - return (ISPCGeometry*) new ISPCLineSegments(in.dynamicCast()); - else if (in->type == TutorialScene::Geometry::HAIR_SET) - return (ISPCGeometry*) new ISPCHairSet(true,in.dynamicCast()); - else if (in->type == TutorialScene::Geometry::CURVES) - return (ISPCGeometry*) new ISPCHairSet(false,in.dynamicCast()); - else if (in->type == TutorialScene::Geometry::INSTANCE) - return (ISPCGeometry*) ISPCInstance::create(in.dynamicCast()); - else if (in->type == TutorialScene::Geometry::GROUP) - return (ISPCGeometry*) new ISPCGroup(in.dynamicCast()); - else - THROW_RUNTIME_ERROR("unknown geometry type"); - } - - static Light* convertLight(Ref in) - { - void* out = 0; - - switch (in->getType()) - { - case SceneGraph::LIGHT_AMBIENT: - { - Ref inAmbient = in.dynamicCast(); - out = AmbientLight_create(); - AmbientLight_set(out, inAmbient->L); - break; - } - case SceneGraph::LIGHT_DIRECTIONAL: - { - Ref inDirectional = in.dynamicCast(); - out = DirectionalLight_create(); - DirectionalLight_set(out, -normalize(inDirectional->D), inDirectional->E, 1.0f); - break; - } - case SceneGraph::LIGHT_DISTANT: - { - Ref inDistant = in.dynamicCast(); - out = DirectionalLight_create(); - DirectionalLight_set(out, - -normalize(inDistant->D), - inDistant->L * rcp(uniformSampleConePDF(inDistant->cosHalfAngle)), - inDistant->cosHalfAngle); - break; - } - case SceneGraph::LIGHT_POINT: - { - Ref inPoint = in.dynamicCast(); - out = PointLight_create(); - PointLight_set(out, inPoint->P, inPoint->I, 0.f); - break; - } - case SceneGraph::LIGHT_SPOT: - case SceneGraph::LIGHT_TRIANGLE: - case SceneGraph::LIGHT_QUAD: - { - // FIXME: not implemented yet - break; - } - - default: - THROW_RUNTIME_ERROR("unknown light type"); - } - - return (Light*)out; - } - - private: - ISPCScene (const ISPCScene& other) DELETED; // do not implement - ISPCScene& operator= (const ISPCScene& other) DELETED; // do not implement - - public: - ISPCGeometry** geometries; //!< list of geometries - ISPCMaterial* materials; //!< material list - unsigned int numGeometries; //!< number of geometries - unsigned int numMaterials; //!< number of materials - - Light** lights; //!< list of lights - unsigned int numLights; //!< number of lights - }; - - typedef ISPCScene::ISPCGeometry ISPCGeometry; - typedef ISPCScene::ISPCTriangleMesh ISPCTriangleMesh; - typedef ISPCScene::ISPCQuadMesh ISPCQuadMesh; - typedef ISPCScene::ISPCSubdivMesh ISPCSubdivMesh; - typedef ISPCScene::ISPCLineSegments ISPCLineSegments; - typedef ISPCScene::ISPCHairSet ISPCHairSet; - typedef ISPCScene::ISPCInstance ISPCInstance; - typedef ISPCScene::ISPCGroup ISPCGroup; - - extern "C" RTCScene ConvertScene(RTCDevice g_device, ISPCScene* scene_in, RTCSceneFlags sflags, RTCAlgorithmFlags aflags, RTCGeometryFlags gflags); -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/statistics.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/statistics.h deleted file mode 100644 index a43d229f442f..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/statistics.h +++ /dev/null @@ -1,96 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../default.h" -#include - -namespace embree -{ - /* calculates min/avg/max and sigma */ - struct Statistics - { - public: - Statistics() - : v(0.0f), v2(0.0f), vmin(pos_inf), vmax(neg_inf), N(0) {} - - void add(float a) - { - v += a; - v2 += a*a; - vmin = min(vmin,a); - vmax = max(vmax,a); - N++; - } - - float getSigma() const - { - if (N == 0) return 0.0f; - else return (float) sqrt(max(0.0,v2/N - sqr(v/N))); - } - - float getAvgSigma() const // standard deviation of average - { - if (N == 0) return 0.0f; - else return getSigma()/sqrt(float(N)); - } - - float getMin() const { return vmin; } - float getMax() const { return vmax; } - float getAvg() const { return float(v/N); } - - private: - double v; // sum of all values - double v2; // sum of squares of all values - float vmin; // min of all values - float vmax; // max of all values - size_t N; // number of values - }; - - /* filters outlyers out */ - struct FilteredStatistics - { - public: - FilteredStatistics(float fskip_small, float fskip_large) - : fskip_small(fskip_small), fskip_large(fskip_large) {} - - void add(float a) - { - v.push_back(a); - std::sort(v.begin(),v.end(),std::less()); - size_t skip_small = (size_t) floor(0.5*fskip_small*double(v.size())); - size_t skip_large = (size_t) floor(0.5*fskip_large*double(v.size())); - - new (&stat) Statistics; - for (size_t i=skip_small; i v; - Statistics stat; - }; -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/tutorial.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/tutorial.cpp deleted file mode 100644 index bb14e31fcd33..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/tutorial.cpp +++ /dev/null @@ -1,851 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "tutorial.h" -#include "scene.h" -#include "statistics.h" - -/* include GLUT for display */ -#if defined(__MACOSX__) -# include -# include -#elif defined(__WIN32__) -# include -# include -# include -#else -# include -# include -#endif - -/* include tutorial_device.h after GLUT, as otherwise we may get - * warnings of redefined GLUT_KEY_F1, etc. */ -#include "tutorial_device.h" -#include "../scenegraph/scenegraph.h" -#include "../scenegraph/obj_loader.h" -#include "../scenegraph/xml_loader.h" -#include "../image/image.h" - -namespace embree -{ - extern "C" - { - float g_debug = 0.0f; - Mode g_mode = MODE_NORMAL; - ISPCScene* g_ispc_scene = nullptr; - - /* intensity scaling for traversal cost visualization */ - float scale = 1.0f / 1000000.0f; - bool g_changed = false; - - int64_t get_tsc() { return read_tsc(); } - - unsigned int g_numThreads = 0; - } - - TutorialApplication* TutorialApplication::instance = nullptr; - - TutorialApplication::TutorialApplication (const std::string& tutorialName, int features) - - : Application(features), - tutorialName(tutorialName), - - shader(SHADER_DEFAULT), - - width(512), - height(512), - pixels(nullptr), - - outputImageFilename(""), - - skipBenchmarkFrames(0), - numBenchmarkFrames(0), - numBenchmarkRepetitions(1), - - interactive(true), - fullscreen(false), - consoleOutput(true), - - window_width(512), - window_height(512), - windowID(0), - - time0(getSeconds()), - debug_int0(0), - debug_int1(0), - - mouseMode(0), - clickX(0), clickY(0), - speed(1.0f) - - { - /* only a single instance of this class is supported */ - assert(instance == nullptr); - instance = this; - - /* for best performance set FTZ and DAZ flags in MXCSR control and status register */ - _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); - _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); - - registerOption("c", [this] (Ref cin, const FileName& path) { - FileName file = path + cin->getFileName(); - parseCommandLine(new ParseStream(new LineCommentFilter(file, "#")), file.path()); - }, "-c : parses command line option from "); - - registerOption("o", [this] (Ref cin, const FileName& path) { - outputImageFilename = cin->getFileName(); - interactive = false; - }, "-o : output image filename"); - - /* camera settings */ - registerOption("vp", [this] (Ref cin, const FileName& path) { - camera.from = cin->getVec3fa(); - }, "--vp : camera position"); - - registerOption("vi", [this] (Ref cin, const FileName& path) { - camera.to = cin->getVec3fa(); - }, "--vi : camera lookat position"); - - registerOption("vd", [this] (Ref cin, const FileName& path) { - camera.to = camera.from + cin->getVec3fa(); - }, "--vd : camera direction vector"); - - registerOption("vu", [this] (Ref cin, const FileName& path) { - camera.up = cin->getVec3fa(); - }, "--vu : camera up vector"); - - registerOption("fov", [this] (Ref cin, const FileName& path) { - camera.fov = cin->getFloat(); - }, "--fov : vertical field of view"); - - /* framebuffer settings */ - registerOption("size", [this] (Ref cin, const FileName& path) { - width = cin->getInt(); - height = cin->getInt(); - }, "--size : sets image size"); - - registerOption("fullscreen", [this] (Ref cin, const FileName& path) { - fullscreen = true; - }, "--fullscreen: starts in fullscreen mode"); - - registerOption("benchmark", [this] (Ref cin, const FileName& path) { - skipBenchmarkFrames = cin->getInt(); - numBenchmarkFrames = cin->getInt(); - if (cin->peek() != "" && cin->peek()[0] != '-') - numBenchmarkRepetitions = cin->getInt(); - interactive = false; - rtcore += ",benchmark=1,start_threads=1"; - }, "--benchmark : enabled benchmark mode, builds scene, skips N frames, renders M frames, and repeats this R times"); - - registerOption("nodisplay", [this] (Ref cin, const FileName& path) { - skipBenchmarkFrames = 0; - numBenchmarkFrames = 2048; - interactive = false; - }, "--nodisplay: enabled benchmark mode, continously renders frames"); - - /* output filename */ - registerOption("shader", [this] (Ref cin, const FileName& path) { - std::string mode = cin->getString(); - if (mode == "default" ) shader = SHADER_DEFAULT; - else if (mode == "eyelight") shader = SHADER_EYELIGHT; - else if (mode == "uv" ) shader = SHADER_UV; - else if (mode == "texcoords") shader = SHADER_TEXCOORDS; - else if (mode == "texcoords-grid") shader = SHADER_TEXCOORDS_GRID; - else if (mode == "Ng" ) shader = SHADER_NG; - else if (mode == "geomID" ) shader = SHADER_GEOMID; - else if (mode == "primID" ) shader = SHADER_GEOMID_PRIMID; - else if (mode == "ao" ) shader = SHADER_AMBIENT_OCCLUSION; - else throw std::runtime_error("invalid shader:" +mode); - }, - "--shader : sets shader to use at startup\n" - " default: default tutorial shader\n" - " eyelight: eyelight shading\n" - " uv: uv debug shader\n" - " texcoords: texture coordinate debug shader\n" - " texcoords-grid: grid texture debug shader\n" - " Ng: visualization of shading normal\n" - " geomID: visualization of geometry ID\n" - " primID: visualization of geometry and primitive ID\n" - " ao: ambient occlusion shader"); - - if (features & FEATURE_STREAM) - { - /* register parsing of stream mode */ - registerOption("mode", [this] (Ref cin, const FileName& path) { - std::string mode = cin->getString(); - if (mode == "normal" ) g_mode = MODE_NORMAL; - else if (mode == "stream-coherent" ) g_mode = MODE_STREAM_COHERENT; - else if (mode == "stream-incoherent") g_mode = MODE_STREAM_INCOHERENT; - else throw std::runtime_error("invalid mode:" +mode); - }, - "--mode: sets rendering mode\n" - " normal : normal mode\n" - " stream-coherent : coherent stream mode\n" - " stream-incoherent: incoherent stream mode\n"); - } - } - - TutorialApplication::~TutorialApplication() - { - if (g_ispc_scene) delete g_ispc_scene; - device_cleanup(); - alignedFree(pixels); - pixels = nullptr; - width = 0; - height = 0; - } - - SceneLoadingTutorialApplication::SceneLoadingTutorialApplication (const std::string& tutorialName, int features) - - : TutorialApplication(tutorialName, features), - scene(new SceneGraph::GroupNode), - convert_tris_to_quads(false), - convert_bezier_to_lines(false), - convert_hair_to_curves(false), - sceneFilename(""), - instancing_mode(0), - subdiv_mode("") - { - registerOption("i", [this] (Ref cin, const FileName& path) { - sceneFilename = path + cin->getFileName(); - }, "-i : parses scene from "); - - registerOption("animlist", [this] (Ref cin, const FileName& path) { - FileName listFilename = path + cin->getFileName(); - - std::ifstream listFile; - listFile.open(listFilename.c_str()); - if (!listFile.is_open()) { - THROW_RUNTIME_ERROR("cannot open " + listFilename.str()); - } - else - { - while (!listFile.eof()) - { - std::string line; - listFile >> line; - if (line != "") - keyFramesFilenames.push_back(listFilename.path() + line); - } - } - }, "-animlist : parses a sequence of .obj/.xml files listed in and adds them to the scene"); - - registerOption("convert-triangles-to-quads", [this] (Ref cin, const FileName& path) { - convert_tris_to_quads = true; - }, "--convert-triangles-to-quads: converts all triangles to quads when loading"); - - registerOption("convert-bezier-to-lines", [this] (Ref cin, const FileName& path) { - convert_bezier_to_lines = true; - }, "--convert-bezier-to-lines: converts all bezier curves to line segments when loading"); - - registerOption("convert-hair-to-curves", [this] (Ref cin, const FileName& path) { - convert_hair_to_curves = true; - }, "--convert-hair-to-curves: converts all hair geometry to curves when loading"); - - registerOption("instancing", [this] (Ref cin, const FileName& path) { - std::string mode = cin->getString(); - if (mode == "none" ) instancing_mode = TutorialScene::INSTANCING_NONE; - //else if (mode == "geometry") instancing_mode = TutorialScene::INSTANCING_GEOMETRY; - else if (mode == "scene_geometry") instancing_mode = TutorialScene::INSTANCING_SCENE_GEOMETRY; - else if (mode == "scene_group" ) instancing_mode = TutorialScene::INSTANCING_SCENE_GROUP; - else throw std::runtime_error("unknown instancing mode: "+mode); - }, "--instancing: set instancing mode\n" - " none: no instancing\n" - " geometry: instance individual geometries\n" - " scene_geometry: instance individual geometries as scenes\n" - " scene_group: instance geometry groups as scenes"); - - registerOption("ambientlight", [this] (Ref cin, const FileName& path) { - const Vec3fa L = cin->getVec3fa(); - scene->add(new SceneGraph::LightNode(new SceneGraph::AmbientLight(L))); - }, "--ambientlight r g b: adds an ambient light with intensity rgb"); - registerOptionAlias("ambientlight","ambient"); - - registerOption("pointlight", [this] (Ref cin, const FileName& path) { - const Vec3fa P = cin->getVec3fa(); - const Vec3fa I = cin->getVec3fa(); - scene->add(new SceneGraph::LightNode(new SceneGraph::PointLight(P,I))); - }, "--pointlight x y z r g b: adds a point light at position xyz with intensity rgb"); - - registerOption("directionallight", [this] (Ref cin, const FileName& path) { - const Vec3fa D = cin->getVec3fa(); - const Vec3fa E = cin->getVec3fa(); - scene->add(new SceneGraph::LightNode(new SceneGraph::DirectionalLight(D,E))); - }, "--directionallight x y z r g b: adds a directional light with direction xyz and intensity rgb"); - registerOptionAlias("directionallight","dirlight"); - - registerOption("distantlight", [this] (Ref cin, const FileName& path) { - const Vec3fa D = cin->getVec3fa(); - const Vec3fa L = cin->getVec3fa(); - const float halfAngle = cin->getFloat(); - scene->add(new SceneGraph::LightNode(new SceneGraph::DistantLight(D,L,halfAngle))); - }, "--distantlight x y z r g b a: adds a distant light with direction xyz, intensity rgb, and opening angle a"); - - registerOption("triangle-plane", [this] (Ref cin, const FileName& path) { - const Vec3fa p0 = cin->getVec3fa(); - const Vec3fa dx = cin->getVec3fa(); - const Vec3fa dy = cin->getVec3fa(); - const size_t width = cin->getInt(); - const size_t height = cin->getInt(); - Material obj; new (&obj) OBJMaterial(); - scene->add(SceneGraph::createTrianglePlane(p0,dx,dy,width,height,new SceneGraph::MaterialNode(obj))); - }, "--triangle-plane p.x p.y p.z dx.x dx.y dx.z dy.x dy.y dy.z width height: adds a plane build of triangles originated at p0 and spanned by the vectors dx and dy with a tesselation width/height."); - - registerOption("quad-plane", [this] (Ref cin, const FileName& path) { - const Vec3fa p0 = cin->getVec3fa(); - const Vec3fa dx = cin->getVec3fa(); - const Vec3fa dy = cin->getVec3fa(); - const size_t width = cin->getInt(); - const size_t height = cin->getInt(); - Material obj; new (&obj) OBJMaterial(); - scene->add(SceneGraph::createQuadPlane(p0,dx,dy,width,height,new SceneGraph::MaterialNode(obj))); - }, "--quad-plane p.x p.y p.z dx.x dx.y dx.z dy.x dy.y dy.z width height: adds a plane build of quadrilaterals originated at p0 and spanned by the vectors dx and dy with a tesselation width/height."); - - registerOption("subdiv-plane", [this] (Ref cin, const FileName& path) { - const Vec3fa p0 = cin->getVec3fa(); - const Vec3fa dx = cin->getVec3fa(); - const Vec3fa dy = cin->getVec3fa(); - const size_t width = cin->getInt(); - const size_t height = cin->getInt(); - const float tessellationRate = cin->getFloat(); - Material obj; new (&obj) OBJMaterial(); - scene->add(SceneGraph::createSubdivPlane(p0,dx,dy,width,height,tessellationRate,new SceneGraph::MaterialNode(obj))); - }, "--subdiv-plane p.x p.y p.z dx.x dx.y dx.z dy.x dy.y dy.z width height tessellationRate: adds a plane build as a Catmull Clark subdivision surface originated at p0 and spanned by the vectors dx and dy. The plane consists of widt x height many patches, and each patch has the specified tesselation rate."); - - registerOption("hair-plane", [this] (Ref cin, const FileName& path) { - const Vec3fa p0 = cin->getVec3fa(); - const Vec3fa dx = cin->getVec3fa(); - const Vec3fa dy = cin->getVec3fa(); - const float len = cin->getFloat(); - const float r = cin->getFloat(); - const size_t N = cin->getInt(); - Material obj; new (&obj) OBJMaterial(); - scene->add(SceneGraph::createHairyPlane(0,p0,dx,dy,len,r,N,true,new SceneGraph::MaterialNode(obj))); - }, "--hair-plane p.x p.y p.z dx.x dx.y dx.z dy.x dy.y dy.z length radius num: adds a hair plane originated at p0 and spanned by the vectors dx and dy. num hairs are generated with speficied length and radius."); - - registerOption("curve-plane", [this] (Ref cin, const FileName& path) { - const Vec3fa p0 = cin->getVec3fa(); - const Vec3fa dx = cin->getVec3fa(); - const Vec3fa dy = cin->getVec3fa(); - const float len = cin->getFloat(); - const float r = cin->getFloat(); - const size_t N = cin->getInt(); - Material obj; new (&obj) OBJMaterial(); - scene->add(SceneGraph::createHairyPlane(0,p0,dx,dy,len,r,N,false,new SceneGraph::MaterialNode(obj))); - }, "--curve-plane p.x p.y p.z dx.x dx.y dx.z dy.x dy.y dy.z length radius: adds a plane build of bezier curves originated at p0 and spanned by the vectors dx and dy. num curves are generated with speficied length and radius."); - - registerOption("triangle-sphere", [this] (Ref cin, const FileName& path) { - const Vec3fa p = cin->getVec3fa(); - const float r = cin->getFloat(); - const size_t numPhi = cin->getInt(); - Material obj; new (&obj) OBJMaterial(); - scene->add(SceneGraph::createTriangleSphere(p,r,numPhi,new SceneGraph::MaterialNode(obj))); - }, "--triangle-sphere p.x p.y p.z r numPhi: adds a sphere at position p with radius r and tesselation numPhi build of triangles."); - - registerOption("quad-sphere", [this] (Ref cin, const FileName& path) { - const Vec3fa p = cin->getVec3fa(); - const float r = cin->getFloat(); - const size_t numPhi = cin->getInt(); - Material obj; new (&obj) OBJMaterial(); - scene->add(SceneGraph::createQuadSphere(p,r,numPhi,new SceneGraph::MaterialNode(obj))); - }, "--quad-sphere p.x p.y p.z r numPhi: adds a sphere at position p with radius r and tesselation numPhi build of quadrilaterals."); - - registerOption("subdiv-sphere", [this] (Ref cin, const FileName& path) { - const Vec3fa p = cin->getVec3fa(); - const float r = cin->getFloat(); - const size_t numPhi = cin->getInt(); - const float tessellationRate = cin->getFloat(); - Material obj; new (&obj) OBJMaterial(); - scene->add(SceneGraph::createSubdivSphere(p,r,numPhi,tessellationRate,new SceneGraph::MaterialNode(obj))); - }, "--subdiv-sphere p.x p.y p.z r numPhi: adds a sphere at position p with radius r build of Catmull Clark subdivision surfaces. The sphere consists of numPhi x numPhi many patches and each path has the specified tessellation rate."); - - registerOption("cache", [this] (Ref cin, const FileName& path) { - subdiv_mode = ",subdiv_accel=bvh4.subdivpatch1cached"; - rtcore += subdiv_mode; - }, "--cache: enabled cached subdiv mode"); - - registerOption("pregenerate", [this] (Ref cin, const FileName& path) { - subdiv_mode = ",subdiv_accel=bvh4.grid.eager"; - rtcore += subdiv_mode; - }, "--pregenerate: enabled pregenerate subdiv mode"); - } - - void TutorialApplication::renderBenchmark() - { - IOStreamStateRestorer cout_state(std::cout); - std::cout.setf(std::ios::fixed, std::ios::floatfield); - std::cout.precision(4); - - resize(width,height); - ISPCCamera ispccamera = camera.getISPCCamera(width,height); - - //Statistics stat; - FilteredStatistics stat(0.5f,0.0f); - for (size_t j=0; j= 1024 && (i % 64 == 0)) - { - std::cout << "frame [" << std::setw(3) << i << " / " << std::setw(3) << numTotalFrames << "]: " - << std::setw(8) << fr << " fps, " - << "min = " << std::setw(8) << stat.getMin() << " fps, " - << "avg = " << std::setw(8) << stat.getAvg() << " fps, " - << "max = " << std::setw(8) << stat.getMax() << " fps, " - << "sigma = " << std::setw(6) << stat.getSigma() << " (" << 100.0f*stat.getSigma()/stat.getAvg() << "%)" << std::endl << std::flush; - } - } - - /* rebuild scene between repetitions */ - if (numBenchmarkRepetitions) - { - device_cleanup(); - device_init(rtcore.c_str()); - resize(width,height); - } - - std::cout << "frame [" << std::setw(3) << skipBenchmarkFrames << " - " << std::setw(3) << numTotalFrames << "]: " - << " " - << "min = " << std::setw(8) << stat.getMin() << " fps, " - << "avg = " << std::setw(8) << stat.getAvg() << " fps, " - << "max = " << std::setw(8) << stat.getMax() << " fps, " - << "sigma = " << std::setw(6) << stat.getAvgSigma() << " (" << 100.0f*stat.getAvgSigma()/stat.getAvg() << "%)" << std::endl; - } - - std::cout << "BENCHMARK_RENDER_MIN " << stat.getMin() << std::endl; - std::cout << "BENCHMARK_RENDER_AVG " << stat.getAvg() << std::endl; - std::cout << "BENCHMARK_RENDER_MAX " << stat.getMax() << std::endl; - std::cout << "BENCHMARK_RENDER_SIGMA " << stat.getSigma() << std::endl; - std::cout << "BENCHMARK_RENDER_AVG_SIGMA " << stat.getAvgSigma() << std::endl << std::flush; - } - - void TutorialApplication::renderToFile(const FileName& fileName) - { - resize(width,height); - ISPCCamera ispccamera = camera.getISPCCamera(width,height); - device_render(pixels,width,height,0.0f,ispccamera); - Ref image = new Image4uc(width, height, (Col4uc*)pixels); - storeImage(image, fileName); - } - - void TutorialApplication::set_parameter(size_t parm, ssize_t val) { - rtcDeviceSetParameter1i(nullptr,(RTCParameter)parm,val); - } - - void TutorialApplication::resize(unsigned width, unsigned height) - { - if (width == this->width && height == this->height && pixels) - return; - - if (pixels) alignedFree(pixels); - this->width = width; - this->height = height; - pixels = (unsigned*) alignedMalloc(width*height*sizeof(unsigned),64); - } - - void TutorialApplication::set_scene (TutorialScene* in) { - g_ispc_scene = new ISPCScene(in); - } - - void TutorialApplication::keyboardFunc(unsigned char key, int x, int y) - { - /* call tutorial keyboard handler */ - device_key_pressed(key); - - switch (key) - { - case 'f' : - if (fullscreen) { - fullscreen = false; - glutReshapeWindow(window_width,window_height); - } else { - fullscreen = true; - window_width = width; - window_height = height; - glutFullScreen(); - } - break; - case 'c' : { - std::cout.precision(10); - std::cout << "-vp " << camera.from.x << " " << camera.from.y << " " << camera.from.z << " " - << "-vi " << camera.to.x << " " << camera.to.y << " " << camera.to.z << " " - << "-vu " << camera.up.x << " " << camera.up.y << " " << camera.up.z << " " - << "-fov " << camera.fov << std::endl; - break; - } - case '+' : g_debug=clamp(g_debug+0.01f); PRINT(g_debug); break; - case '-' : g_debug=clamp(g_debug-0.01f); PRINT(g_debug); break; - - case ' ' : { - Ref image = new Image4uc(width, height, (Col4uc*)pixels, true, "", true); - storeImage(image, "screenshot.tga"); - break; - } - - case '\033': case 'q': case 'Q': - glutDestroyWindow(windowID); -#if defined(__MACOSX__) - exit(1); -#endif - break; - } - } - - void TutorialApplication::specialFunc(int key, int x, int y) - { - device_key_pressed(key); - - if (glutGetModifiers() == GLUT_ACTIVE_CTRL) - { - switch (key) { - case GLUT_KEY_UP : debug_int0++; set_parameter(1000000,debug_int0); PRINT(debug_int0); break; - case GLUT_KEY_DOWN : debug_int0--; set_parameter(1000000,debug_int0); PRINT(debug_int0); break; - case GLUT_KEY_LEFT : debug_int1--; set_parameter(1000001,debug_int1); PRINT(debug_int1); break; - case GLUT_KEY_RIGHT : debug_int1++; set_parameter(1000001,debug_int1); PRINT(debug_int1); break; - } - } - else - { - switch (key) { - case GLUT_KEY_LEFT : camera.rotate(-0.02f,0.0f); break; - case GLUT_KEY_RIGHT : camera.rotate(+0.02f,0.0f); break; - case GLUT_KEY_UP : camera.move(0.0f,0.0f,+speed); break; - case GLUT_KEY_DOWN : camera.move(0.0f,0.0f,-speed); break; - case GLUT_KEY_PAGE_UP : speed *= 1.2f; break; - case GLUT_KEY_PAGE_DOWN : speed /= 1.2f; break; - } - } - } - - void TutorialApplication::clickFunc(int button, int state, int x, int y) - { - if (state == GLUT_UP) - { - mouseMode = 0; - if (button == GLUT_LEFT_BUTTON && glutGetModifiers() == GLUT_ACTIVE_SHIFT) - { - ISPCCamera ispccamera = camera.getISPCCamera(width,height); - Vec3fa p; bool hit = device_pick(float(x),float(y),ispccamera,p); - - if (hit) { - Vec3fa delta = p - camera.to; - Vec3fa right = normalize(ispccamera.xfm.l.vx); - Vec3fa up = normalize(ispccamera.xfm.l.vy); - camera.to = p; - camera.from += dot(delta,right)*right + dot(delta,up)*up; - } - } - else if (button == GLUT_LEFT_BUTTON && glutGetModifiers() == (GLUT_ACTIVE_CTRL | GLUT_ACTIVE_SHIFT)) - { - ISPCCamera ispccamera = camera.getISPCCamera(width,height); - Vec3fa p; bool hit = device_pick(float(x),float(y),ispccamera,p); - if (hit) camera.to = p; - } - - } else { - clickX = x; clickY = y; - int modifiers = glutGetModifiers(); - if (button == GLUT_LEFT_BUTTON && modifiers == GLUT_ACTIVE_SHIFT) mouseMode = 1; - else if (button == GLUT_MIDDLE_BUTTON) mouseMode = 2; - else if (button == GLUT_RIGHT_BUTTON ) mouseMode = 3; - else if (button == GLUT_LEFT_BUTTON && modifiers == GLUT_ACTIVE_CTRL ) mouseMode = 3; - else if (button == GLUT_LEFT_BUTTON ) mouseMode = 4; - } - } - - void TutorialApplication::motionFunc(int x, int y) - { - float dClickX = float(clickX - x), dClickY = float(clickY - y); - clickX = x; clickY = y; - - switch (mouseMode) { - case 1: camera.rotateOrbit(-0.005f*dClickX,0.005f*dClickY); break; - case 2: break; - case 3: camera.dolly(-dClickY); break; - case 4: camera.rotate(-0.005f*dClickX,0.005f*dClickY); break; - } - } - - void TutorialApplication::displayFunc(void) - { - ISPCCamera ispccamera = camera.getISPCCamera(width,height,true); - - /* render image using ISPC */ - double t0 = getSeconds(); - device_render(pixels,width,height,float(time0-t0),ispccamera); - double dt0 = getSeconds()-t0; - - /* draw pixels to screen */ - glDrawPixels(width,height,GL_RGBA,GL_UNSIGNED_BYTE,pixels); - - if (fullscreen || !consoleOutput) - { - glMatrixMode( GL_PROJECTION ); - glPushMatrix(); - glLoadIdentity(); - gluOrtho2D( 0, width, 0, height ); - glMatrixMode( GL_MODELVIEW ); - glPushMatrix(); - glLoadIdentity(); - - /* print frame rate */ - std::ostringstream stream; - stream.setf(std::ios::fixed, std::ios::floatfield); - stream.precision(2); - stream << 1.0f/dt0 << " fps"; - std::string str = stream.str(); - - glRasterPos2i( width-GLint(str.size())*12, height - 24); - for (size_t i=0; iwidth = width; this->height = height; - } - - void TutorialApplication::idleFunc() { - glutPostRedisplay(); - } - - void keyboardFunc(unsigned char key, int x, int y) { - TutorialApplication::instance->keyboardFunc(key,x,y); - } - void specialFunc(int key, int x, int y) { - TutorialApplication::instance->specialFunc(key,x,y); - } - void clickFunc(int button, int state, int x, int y) { - TutorialApplication::instance->clickFunc(button,state,x,y); - } - void motionFunc(int x, int y) { - TutorialApplication::instance->motionFunc(x,y); - } - void displayFunc() { - TutorialApplication::instance->displayFunc(); - } - void reshapeFunc(int width, int height) { - TutorialApplication::instance->reshapeFunc(width,height); - } - void idleFunc() { - TutorialApplication::instance->idleFunc(); - } - - void TutorialApplication::run(int argc, char** argv) - { - /* initialize ray tracing core */ - device_init(rtcore.c_str()); - - /* set shader mode */ - switch (shader) { - case SHADER_DEFAULT : break; - case SHADER_EYELIGHT : device_key_pressed(GLUT_KEY_F2); break; - case SHADER_UV : device_key_pressed(GLUT_KEY_F4); break; - case SHADER_TEXCOORDS: device_key_pressed(GLUT_KEY_F8); break; - case SHADER_TEXCOORDS_GRID: device_key_pressed(GLUT_KEY_F8); device_key_pressed(GLUT_KEY_F8); break; - case SHADER_NG : device_key_pressed(GLUT_KEY_F5); break; - case SHADER_GEOMID : device_key_pressed(GLUT_KEY_F6); break; - case SHADER_GEOMID_PRIMID: device_key_pressed(GLUT_KEY_F7); break; - case SHADER_AMBIENT_OCCLUSION: device_key_pressed(GLUT_KEY_F11); break; - }; - - /* benchmark mode */ - if (numBenchmarkFrames) - { - renderBenchmark(); - } - - /* render to disk */ - if (outputImageFilename.str() != "") - renderToFile(outputImageFilename); - - /* interactive mode */ - if (interactive) - { - resize(width,height); - - glutInit(&argc, argv); - glutInitWindowSize((GLsizei)width, (GLsizei)height); - glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); - glutInitWindowPosition(0, 0); - windowID = glutCreateWindow(tutorialName.c_str()); - if (fullscreen) glutFullScreen(); - glutDisplayFunc(embree::displayFunc); - glutIdleFunc(embree::idleFunc); - glutKeyboardFunc(embree::keyboardFunc); - glutSpecialFunc(embree::specialFunc); - glutMouseFunc(embree::clickFunc); - glutMotionFunc(embree::motionFunc); - glutReshapeFunc(embree::reshapeFunc); - glutMainLoop(); - } - } - - int TutorialApplication::main(int argc, char** argv) try - { - /* parse command line options */ - parseCommandLine(argc,argv); - - /* callback */ - postParseCommandLine(); - - /* start tutorial */ - run(argc,argv); - return 0; - } - catch (const std::exception& e) { - std::cout << "Error: " << e.what() << std::endl; - return 1; - } - catch (...) { - std::cout << "Error: unknown exception caught." << std::endl; - return 1; - } - - int SceneLoadingTutorialApplication::main(int argc, char** argv) try - { - /* parse command line options */ - parseCommandLine(argc,argv); - - /* callback */ - try { - postParseCommandLine(); - } - catch (const std::exception& e) { - std::cout << "Error: " << e.what() << std::endl; - } - - /* load scene */ - if (sceneFilename != "") - { - if (toLowerCase(sceneFilename.ext()) == std::string("obj")) - scene->add(loadOBJ(sceneFilename,subdiv_mode != "")); - else if (sceneFilename.ext() != "") - scene->add(SceneGraph::load(sceneFilename)); - } - - /* load key frames for animation */ - for (size_t i=0;iadd(loadOBJ(keyFramesFilenames[i],subdiv_mode != "",true)); - else if (keyFramesFilenames[i].ext() != "") - scene->add(SceneGraph::load(keyFramesFilenames[i])); - std::cout << "done" << std::endl << std::flush; - } - /* convert triangles to quads */ - if (convert_tris_to_quads) - scene->triangles_to_quads(); - - /* convert bezier to lines */ - if (convert_bezier_to_lines) - scene->bezier_to_lines(); - - /* convert hair to curves */ - if (convert_hair_to_curves) - scene->hair_to_curves(); - - /* convert model */ - obj_scene.add(scene.dynamicCast(),(TutorialScene::InstancingMode)instancing_mode); - scene = nullptr; - - /* send model */ - set_scene(&obj_scene); - - /* start tutorial */ - run(argc,argv); - - return 0; - } - catch (const std::exception& e) { - std::cout << "Error: " << e.what() << std::endl; - return 1; - } - catch (...) { - std::cout << "Error: unknown exception caught." << std::endl; - return 1; - } - - /* draws progress bar */ - static int progressWidth = 0; - static std::atomic progressDots(0); - - extern "C" void progressStart() - { - progressDots = 0; - progressWidth = max(3,getTerminalWidth()); - std::cout << "[" << std::flush; - } - - extern "C" bool progressMonitor(void* ptr, const double n) - { - size_t olddots = progressDots; - size_t maxdots = progressWidth-2; - size_t newdots = max(olddots,min(size_t(maxdots),size_t(n*double(maxdots)))); - if (progressDots.compare_exchange_strong(olddots,newdots)) - for (size_t i=olddots; i scene; - bool convert_tris_to_quads; - bool convert_bezier_to_lines; - bool convert_hair_to_curves; - FileName sceneFilename; - std::vector keyFramesFilenames; - int instancing_mode; - std::string subdiv_mode; - }; -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/tutorial_device.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/tutorial_device.cpp deleted file mode 100644 index 6c7c90513144..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/tutorial_device.cpp +++ /dev/null @@ -1,894 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "tutorial_device.h" -#include "scene_device.h" - -namespace embree { - -/* the scene to render */ -extern RTCScene g_scene; -extern "C" ISPCScene* g_ispc_scene; - -/* intensity scaling for traversal cost visualization */ -extern "C" float scale; -extern "C" bool g_changed; - -extern "C" float g_debug; - -/* stores pointer to currently used rendePixel function */ -renderTileFunc renderTile; - -/* error reporting function */ -void error_handler(const RTCError code, const char* str) -{ - if (code == RTC_NO_ERROR) - return; - - printf("Embree: "); - switch (code) { - case RTC_UNKNOWN_ERROR : printf("RTC_UNKNOWN_ERROR"); break; - case RTC_INVALID_ARGUMENT : printf("RTC_INVALID_ARGUMENT"); break; - case RTC_INVALID_OPERATION: printf("RTC_INVALID_OPERATION"); break; - case RTC_OUT_OF_MEMORY : printf("RTC_OUT_OF_MEMORY"); break; - case RTC_UNSUPPORTED_CPU : printf("RTC_UNSUPPORTED_CPU"); break; - case RTC_CANCELLED : printf("RTC_CANCELLED"); break; - default : printf("invalid error code"); break; - } - if (str) { - printf(" ("); - while (*str) putchar(*str++); - printf(")\n"); - } - exit(1); -} - -/* renders a single pixel with eyelight shading */ -Vec3fa renderPixelEyeLight(float x, float y, const ISPCCamera& camera) -{ - /* initialize ray */ - RTCRay ray; - ray.org = Vec3fa(camera.xfm.p); - ray.dir = Vec3fa(normalize(x*camera.xfm.l.vx + y*camera.xfm.l.vy + camera.xfm.l.vz)); - ray.tnear = 0.0f; - ray.tfar = inf; - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.primID = RTC_INVALID_GEOMETRY_ID; - ray.mask = -1; - ray.time = g_debug; - - /* intersect ray with scene */ - rtcIntersect(g_scene,ray); - - /* shade pixel */ - if (ray.geomID == RTC_INVALID_GEOMETRY_ID) return Vec3fa(0.0f); - else return Vec3fa(abs(dot(ray.dir,normalize(ray.Ng)))); -} - -void renderTileEyeLight(int taskIndex, - int* pixels, - const unsigned int width, - const unsigned int height, - const float time, - const ISPCCamera& camera, - const int numTilesX, - const int numTilesY) -{ - const int t = taskIndex; - const unsigned int tileY = t / numTilesX; - const unsigned int tileX = t - tileY * numTilesX; - const unsigned int x0 = tileX * TILE_SIZE_X; - const unsigned int x1 = min(x0+TILE_SIZE_X,width); - const unsigned int y0 = tileY * TILE_SIZE_Y; - const unsigned int y1 = min(y0+TILE_SIZE_Y,height); - - for (unsigned int y=y0; ytexcoord_indices) - { - assert(primID < mesh->numFaces); - const size_t face_offset = mesh->face_offsets[primID]; - if (mesh->verticesPerFace[primID] == 3) - { - const size_t t0 = mesh->texcoord_indices[face_offset+0]; - const size_t t1 = mesh->texcoord_indices[face_offset+1]; - const size_t t2 = mesh->texcoord_indices[face_offset+2]; - const Vec2f txt0 = mesh->texcoords[t0]; - const Vec2f txt1 = mesh->texcoords[t1]; - const Vec2f txt2 = mesh->texcoords[t2]; - const float w = 1.0f - u - v; - st = w * txt0 + u * txt1 + v * txt2; - } - else if (mesh->verticesPerFace[primID] == 4) - { - const size_t t0 = mesh->texcoord_indices[face_offset+0]; - const size_t t1 = mesh->texcoord_indices[face_offset+1]; - const size_t t2 = mesh->texcoord_indices[face_offset+2]; - const size_t t3 = mesh->texcoord_indices[face_offset+3]; - const Vec2f txt0 = mesh->texcoords[t0]; - const Vec2f txt1 = mesh->texcoords[t1]; - const Vec2f txt2 = mesh->texcoords[t2]; - const Vec2f txt3 = mesh->texcoords[t3]; - const float u0 = u; - const float v0 = v; - const float u1 = 1.0f - u; - const float v1 = 1.0f - v; - st = u1*v1 * txt0 + u0*v1* txt1 + u0*v0 * txt2 + u1*v0* txt3; - } -#if defined(_DEBUG) - else - PRINT("not supported"); -#endif - } - return st; -} - -float getTextureTexel1f(const Texture* texture, float s, float t) -{ - if (!texture) return 0.0f; - - int iu = (int)floor(s * (float)(texture->width)); - iu = iu % texture->width; if (iu < 0) iu += texture->width; - int iv = (int)floor(t * (float)(texture->height)); - iv = iv % texture->height; if (iv < 0) iv += texture->height; - - if (texture->format == Texture::FLOAT32) - { - float *data = (float *)texture->data; - return data[iv*texture->width + iu]; - } - else if (texture->format == Texture::RGBA8) - { - const int offset = (iv * texture->width + iu) * 4; - unsigned char * t = (unsigned char*)texture->data; - return t[offset+0]*(1.0f/255.0f); - } - return 0.0f; -} - -Vec3fa getTextureTexel3f(const Texture* texture, float s, float t) -{ - if (!texture) return Vec3fa(0.0f,0.0f,0.0f); - - int iu = (int)floor(s * (float)(texture->width)); - iu = iu % texture->width; if (iu < 0) iu += texture->width; - int iv = (int)floor(t * (float)(texture->height)); - iv = iv % texture->height; if (iv < 0) iv += texture->height; - - if (texture->format == Texture::RGBA8) - { - const int offset = (iv * texture->width + iu) * 4; - unsigned char * t = (unsigned char*)texture->data; - const unsigned char r = t[offset+0]; - const unsigned char g = t[offset+1]; - const unsigned char b = t[offset+2]; - return Vec3fa( (float)r * 1.0f/255.0f, (float)g * 1.0f/255.0f, (float)b * 1.0f/255.0f ); - } - return Vec3fa(0.0f,0.0f,0.0f); -} - -} // namespace embree diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/tutorial_device.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/tutorial_device.h deleted file mode 100644 index df6f003b5426..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/common/tutorial/tutorial_device.h +++ /dev/null @@ -1,146 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#define _CRT_SECURE_NO_WARNINGS - -#include "config.h" - -/* size of screen tiles */ -#define TILE_SIZE_X 8 -#define TILE_SIZE_Y 8 - -/* vertex and triangle layout */ -struct Vertex { float x,y,z,r; }; // FIXME: rename to Vertex4f -struct Triangle { int v0, v1, v2; }; - -/* include embree API */ -#include "../../../include/embree2/rtcore.h" - -/* include optional vector library */ -#include "../math/math.h" -#include "../math/vec.h" -#include "../math/affinespace.h" -#include "../core/ray.h" -#include "camera.h" -#include "scene_device.h" -#include "noise.h" -#if !defined(ISPC) -#include "../../../common/algorithms/parallel_for.h" - -namespace embree { -#endif - -enum Mode { - MODE_NORMAL = 0, - MODE_STREAM_COHERENT = 1, - MODE_STREAM_INCOHERENT = 2 -}; - -extern "C" Mode g_mode; - -/* error reporting function */ -void error_handler(const RTCError code, const char* str = nullptr); - -/* returns time stamp counter */ -extern "C" int64_t get_tsc(); - -/* declare some standard library functions */ -extern "C" void abort (); -extern "C" void exit(int); -extern "C" int puts ( const char* str ); -extern "C" int putchar ( int character ); - -/* face forward for shading normals */ -inline Vec3fa faceforward( const Vec3fa& N, const Vec3fa& I, const Vec3fa& Ng ) { - Vec3fa NN = N; return dot(I, Ng) < 0 ? NN : neg(NN); -} - -/* glut keys codes */ -#if !defined(GLUT_KEY_F1) -#define GLUT_KEY_F1 1 -#define GLUT_KEY_F2 2 -#define GLUT_KEY_F3 3 -#define GLUT_KEY_F4 4 -#define GLUT_KEY_F5 5 -#define GLUT_KEY_F6 6 -#define GLUT_KEY_F7 7 -#define GLUT_KEY_F8 8 -#define GLUT_KEY_F9 9 -#define GLUT_KEY_F10 10 -#define GLUT_KEY_F11 11 -#define GLUT_KEY_F12 12 -#endif - -/* standard shading function */ -typedef void (* renderTileFunc)(int taskIndex, - int* pixels, - const unsigned int width, - const unsigned int height, - const float time, - const ISPCCamera& camera, - const int numTilesX, - const int numTilesY); -extern "C" renderTileFunc renderTile; - -extern "C" void device_key_pressed_default(int key); -extern "C" void (* key_pressed_handler)(int key); - -void renderTileStandard(int taskIndex, - int* pixels, - const unsigned int width, - const unsigned int height, - const float time, - const ISPCCamera& camera, - const int numTilesX, - const int numTilesY); - -unsigned int getNumHWThreads(); - -#if defined(ISPC) -#define ALIGNED_STRUCT -#define __aligned(x) -#define MAYBE_UNUSED -#endif - -struct Sample3f -{ - Vec3fa v; - float pdf; -}; - -inline Sample3f make_Sample3f(const Vec3fa& v, const float pdf) { - Sample3f s; s.v = v; s.pdf = pdf; return s; -} - -#if defined(ISPC) -inline Sample3f make_Sample3f(const Vec3fa& v, const float pdf) { - Sample3f s; s.v = v; s.pdf = pdf; return s; -} -#endif - -/* draws progress bar */ -extern "C" void progressStart(); -extern "C" bool progressMonitor(void* ptr, const double n); -extern "C" void progressEnd(); - -Vec2f getTextureCoordinatesSubdivMesh(void* mesh, const unsigned int primID, const float u, const float v); - -float getTextureTexel1f(const Texture* texture, float u, float v); -Vec3fa getTextureTexel3f(const Texture* texture, float u, float v); - -} // namespace embree diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/convert/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/convert/CMakeLists.txt deleted file mode 100644 index 05bd79d4794b..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/convert/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2017 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -ADD_EXECUTABLE(convert convert.cpp distribution1d.cpp distribution2d.cpp) -TARGET_LINK_LIBRARIES(convert scenegraph image) -SET_PROPERTY(TARGET convert PROPERTY FOLDER tutorials/single) -INSTALL(TARGETS convert DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT examples) diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/convert/convert.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/convert/convert.cpp deleted file mode 100644 index 33a86870b9b0..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/convert/convert.cpp +++ /dev/null @@ -1,268 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "default.h" -#include "distribution2d.h" -#include "../common/scenegraph/scenegraph.h" -#include "../common/image/image.h" - -namespace embree -{ - /* name of the tutorial */ - bool embedTextures = true; - float centerScale = 0.0f; - Vec3fa centerTranslate(0.0f,0.0f,0.0f); - - struct HeightField : public RefCount - { - ALIGNED_STRUCT; - - HeightField (Ref texture, const BBox3fa& bounds) - : texture(texture), bounds(bounds) {} - - const Vec3fa at(const size_t x, const size_t y) - { - const size_t width = texture->width; - const size_t height = texture->height; - const Color4 c = texture->get(x,y); - const Vec2f p(x/float(width-1),y/float(height-1)); - const float px = p.x*(bounds.upper.x-bounds.lower.x) + bounds.lower.x; - const float py = c.r*(bounds.upper.y-bounds.lower.y) + bounds.lower.y; - const float pz = p.y*(bounds.upper.z-bounds.lower.z) + bounds.lower.z; - return Vec3fa(px,py,pz); - } - - const AffineSpace3fa get(Vec2f p) - { - const size_t width = texture->width; - const size_t height = texture->height; - const size_t x = clamp((size_t)(p.x*(width-1)),(size_t)0,width-1); - const size_t y = clamp((size_t)(p.y*(height-1)),(size_t)0,height-1); - const Color4 c = texture->get(x,y); - const float px = p.x*(bounds.upper.x-bounds.lower.x) + bounds.lower.x; - const float py = c.r*(bounds.upper.y-bounds.lower.y) + bounds.lower.y; - const float pz = p.y*(bounds.upper.z-bounds.lower.z) + bounds.lower.z; - return AffineSpace3fa::translate(Vec3fa(px,py,pz)); - } - - Ref geometry() - { - OBJMaterial material(1.0f,Vec3fa(1.0f),Vec3fa(0.0f),1.0f); - Ref mnode = new SceneGraph::MaterialNode((Material&)material); - Ref mesh = new SceneGraph::TriangleMeshNode(mnode,1); - - const size_t width = texture->width; - const size_t height = texture->height; - - mesh->positions[0].resize(height*width); - for (size_t y=0; ypositions[0][y*width+x] = at(x,y); - - mesh->triangles.resize(2*(height-1)*(width-1)); - for (size_t y=0; ytriangles[2*tri+0] = SceneGraph::TriangleMeshNode::Triangle(unsigned(p00),unsigned(p01),unsigned(p10)); - mesh->triangles[2*tri+1] = SceneGraph::TriangleMeshNode::Triangle(unsigned(p01),unsigned(p11),unsigned(p10)); - } - } - return mesh.dynamicCast(); - } - - private: - Ref texture; - BBox3fa bounds; - }; - - struct Instantiator : public RefCount - { - Instantiator(const Ref& heightField, - const Ref& object, const Ref& distribution, float minDistance, size_t N) - : heightField(heightField), object(object), /*minDistance(minDistance),*/ N(N) - { - /* create distribution */ - size_t width = distribution->width; - size_t height = distribution->height; - float* values = new float[width*height]; - for (size_t y=0; yget(x,y)); - dist = std::make_shared(values,width,height); - delete[] values; - } - - void instantiate(Ref& group) - { - for (size_t i=0; i(),random()); - Vec2f p = dist->sample(r); - p.x *= rcp(float(dist->width)); p.y *= rcp(float(dist->height)); - float angle = 2.0f*float(pi)*random(); - const AffineSpace3fa space = heightField->get(p)*AffineSpace3fa::rotate(Vec3fa(0,1,0),angle); - group->add(new SceneGraph::TransformNode(space,object)); - } - } - - private: - Ref heightField; - Ref object; - std::shared_ptr dist; - //float MAYBE_UNUSED minDistance; - size_t N; - }; - - /* scene */ - Ref g_scene = new SceneGraph::GroupNode; - Ref g_height_field = nullptr; - - static void parseCommandLine(Ref cin, const FileName& path) - { - while (true) - { - std::string tag = cin->getString(); - if (tag == "") return; - - /* parse command line parameters from a file */ - else if (tag == "-c") { - FileName file = path + cin->getFileName(); - parseCommandLine(new ParseStream(new LineCommentFilter(file, "#")), file.path()); - } - - /* load model */ - else if (tag == "-i") { - Ref object = SceneGraph::load(path + cin->getFileName()); - if (centerScale != 0.0f) - { - BBox3fa bb = object->bounds(); - Vec3fa center = bb.center(); - const AffineSpace3fa space = AffineSpace3fa::translate(centerTranslate)*AffineSpace3fa::scale(Vec3fa(centerScale))*AffineSpace3fa::translate(-center); - g_scene->add(new SceneGraph::TransformNode(space,object)); - } - else - g_scene->add(object); - } - - /* convert triangles to quads */ - else if (tag == "-convert-triangles-to-quads") { - g_scene->triangles_to_quads(); - } - - /* convert to subdivs */ - else if (tag == "-convert-to-subdivs") { - g_scene->triangles_to_quads(); - g_scene->quads_to_subdivs(); - } - - /* convert bezier to lines */ - else if (tag == "-convert-bezier-to-lines") { - g_scene->bezier_to_lines(); - } - - /* load terrain */ - else if (tag == "-terrain") - { - Ref tex = loadImage(path + cin->getFileName()); - const Vec3fa lower = cin->getVec3fa(); - const Vec3fa upper = cin->getVec3fa(); - g_height_field = new HeightField(tex,BBox3fa(lower,upper)); - g_scene->add(g_height_field->geometry()); - } - - /* distribute model */ - else if (tag == "-distribute") { - Ref object = SceneGraph::load(path + cin->getFileName()); - Ref distribution = loadImage(path + cin->getFileName()); - const float minDistance = cin->getFloat(); - const size_t N = cin->getInt(); - Ref instantiator = new Instantiator(g_height_field,object,distribution,minDistance,N); - instantiator->instantiate(g_scene); - } - - /* instantiate model a single time */ - else if (tag == "-instantiate") { - Ref object = SceneGraph::load(path + cin->getFileName()); - const float px = cin->getFloat(); - const float py = cin->getFloat(); - const Vec2f p(px,py); - const float angle = cin->getFloat()/180.0f*float(pi); - const AffineSpace3fa space = g_height_field->get(p)*AffineSpace3fa::rotate(Vec3fa(0,1,0),angle); - g_scene->add(new SceneGraph::TransformNode(space,object)); - } - - /* enable texture embedding */ - else if (tag == "-embed-textures") { - embedTextures = true; - } - - /* enable texture referencing */ - else if (tag == "-reference-textures") { - embedTextures = false; - } - - else if (tag == "-centerScaleTranslate") { - centerScale = cin->getFloat(); - centerTranslate.x = cin->getFloat(); - centerTranslate.y = cin->getFloat(); - centerTranslate.z = cin->getFloat(); - } - - /* output filename */ - else if (tag == "-o") { - SceneGraph::store(g_scene.dynamicCast(),path + cin->getFileName(),embedTextures); - } - - /* skip unknown command line parameter */ - else { - std::cerr << "unknown command line parameter: " << tag << " "; - while (cin->peek() != "" && cin->peek()[0] != '-') std::cerr << cin->getString() << " "; - std::cerr << std::endl; - } - } - } - - /* main function in embree namespace */ - int main(int argc, char** argv) - { - /* create stream for parsing */ - Ref stream = new ParseStream(new CommandLineStream(argc, argv)); - - /* parse command line */ - parseCommandLine(stream, FileName()); - - return 0; - } -} - -int main(int argc, char** argv) -{ - try { - return embree::main(argc, argv); - } - catch (const std::exception& e) { - std::cout << "Error: " << e.what() << std::endl; - return 1; - } - catch (...) { - std::cout << "Error: unknown exception caught." << std::endl; - return 1; - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/convert/default.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/convert/default.h deleted file mode 100644 index 5f80a47594d3..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/convert/default.h +++ /dev/null @@ -1,27 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../../common/sys/platform.h" -#include "../../common/sys/ref.h" -#include "../../common/sys/vector.h" -#include "../../common/math/vec2.h" -#include "../../common/math/vec3.h" -#include "../../common/math/affinespace.h" -#include "../../common/sys/filename.h" -#include "../../common/sys/string.h" -#include "../common/tutorial/tutorial.h" diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/convert/distribution1d.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/convert/distribution1d.cpp deleted file mode 100644 index ebd813cb8840..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/convert/distribution1d.cpp +++ /dev/null @@ -1,69 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "distribution1d.h" -#include - -namespace embree -{ - Distribution1D::Distribution1D() - : size(0) {} - - Distribution1D::Distribution1D(const float* f, const size_t size_in) { - init(f, size_in); - } - - void Distribution1D::init(const float* f, const size_t size_in) - { - /*! create arrays */ - size = size_in; - PDF.resize(size); - CDF.resize(size+1); - - /*! accumulate the function f */ - CDF[0] = 0.0f; - for (size_t i=1; i PDF; //!< Probability distribution function - std::vector CDF; //!< Cumulative distribution function (required for sampling) - }; -} - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/convert/distribution2d.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/convert/distribution2d.cpp deleted file mode 100644 index a1b54d5de66b..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/convert/distribution2d.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "distribution2d.h" - -namespace embree -{ - Distribution2D::Distribution2D() - : width(0), height(0) {} - - Distribution2D::Distribution2D(const float* f, const size_t width, const size_t height) - : width(width), height(height) - { - init(f, width, height); - } - - void Distribution2D::init(const float* f, const size_t w, const size_t h) - { - /*! create arrays */ - width = w; height = h; - xDists.resize(height); - std::vector fy(height); - - /*! compute y distribution and initialize row distributions */ - for (size_t y=0; y xDists; //!< One 1D Distribution per row - }; -} - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/curve_geometry/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/curve_geometry/CMakeLists.txt deleted file mode 100644 index a5b40ba7de69..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/curve_geometry/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2017 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -INCLUDE(tutorial) -ADD_TUTORIAL(curve_geometry) -ADD_EMBREE_TEST(curve_geometry) diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/curve_geometry/curve_geometry.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/curve_geometry/curve_geometry.cpp deleted file mode 100644 index 38f8d5282190..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/curve_geometry/curve_geometry.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial.h" - -namespace embree -{ - struct Tutorial : public TutorialApplication - { - Tutorial() - : TutorialApplication("curve_geometry",FEATURE_RTCORE) - { - /* set default camera */ - camera.from = Vec3fa(2.244145155f, 1.310973883f, 0.09447964281f); - camera.to = Vec3fa(0.0f,0.0f,0.0f); - } - }; - -} - -int main(int argc, char** argv) { - return embree::Tutorial().main(argc,argv); -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/curve_geometry/curve_geometry_device.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/curve_geometry/curve_geometry_device.cpp deleted file mode 100644 index 27518f475fab..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/curve_geometry/curve_geometry_device.cpp +++ /dev/null @@ -1,284 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial_device.h" -#include "../common/tutorial/optics.h" - -namespace embree { - -/* scene data */ -RTCDevice g_device = nullptr; -RTCScene g_scene = nullptr; - -#define NUM_VERTICES 9 -#define NUM_CURVES 6 - -#define W 2.0f - -float hair_vertices[9][4] = -{ - { -1.0f, 0.0f, - W, 0.2f }, - - { +0.0f,-1.0f, +0.0f, 0.2f }, - { +1.0f, 0.0f, + W, 0.2f }, - { -1.0f, 0.0f, + W, 0.2f }, - { +0.0f,+1.0f, +0.0f, 0.6f }, - { +1.0f, 0.0f, - W, 0.2f }, - { -1.0f, 0.0f, - W, 0.2f }, - - { +0.0f,-1.0f, +0.0f, 0.2f }, - { +1.0f, 0.0f, + W, 0.2f }, -}; - -float hair_vertex_colors[9][4] = -{ - { 1.0f, 1.0f, 0.0f, 0.0f }, - - { 1.0f, 0.0f, 0.0f, 0.0f }, - { 1.0f, 1.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 1.0f, 0.0f }, - { 1.0f, 1.0f, 1.0f, 0.0f }, - { 1.0f, 0.0f, 0.0f, 0.0f }, - { 1.0f, 1.0f, 0.0f, 0.0f }, - - { 1.0f, 0.0f, 0.0f, 0.0f }, - { 1.0f, 1.0f, 0.0f, 0.0f }, -}; - -unsigned int hair_indices[6] = { - 0, 1, 2, 3, 4, 5 -}; - -/* add hair geometry */ -unsigned int addCurve (RTCScene scene, const Vec3fa& pos) -{ - unsigned int geomID = rtcNewCurveGeometry (scene, RTC_GEOMETRY_STATIC, NUM_CURVES, 4*NUM_CURVES); - - /* converts b-spline to bezier basis */ - Vec3fa* vtx = (Vec3fa*) rtcMapBuffer(scene, geomID, RTC_VERTEX_BUFFER); - for (size_t i=0; i 0) - { - unsigned int geomID = ray.geomID; { - rtcInterpolate(g_scene,geomID,ray.primID,ray.u,ray.v,RTC_USER_VERTEX_BUFFER0,&diffuse.x,nullptr,nullptr,3); - } - diffuse = 0.5f*diffuse; - } - - /* calculate smooth shading normal */ - Vec3fa Ng = normalize(ray.Ng); - color = color + diffuse*0.5f; - Vec3fa lightDir = normalize(Vec3fa(-1,-1,-1)); - - /* initialize shadow ray */ - RTCRay shadow; - shadow.org = ray.org + ray.tfar*ray.dir; - shadow.dir = neg(lightDir); - shadow.tnear = 0.001f; - shadow.tfar = inf; - shadow.geomID = 1; - shadow.primID = 0; - shadow.mask = -1; - shadow.time = 0; - - /* trace shadow ray */ - rtcOccluded(g_scene,shadow); - - /* add light contribution */ - if (shadow.geomID) { - Vec3fa r = normalize(reflect(ray.dir,Ng)); - float s = pow(clamp(dot(r,lightDir),0.0f,1.0f),10.0f); - float d = clamp(-dot(lightDir,Ng),0.0f,1.0f); - color = color + diffuse*d + 0.5f*Vec3fa(s); - } - } - return color; -} - -/* renders a single screen tile */ -void renderTileStandard(int taskIndex, - int* pixels, - const unsigned int width, - const unsigned int height, - const float time, - const ISPCCamera& camera, - const int numTilesX, - const int numTilesY) -{ - const unsigned int tileY = taskIndex / numTilesX; - const unsigned int tileX = taskIndex - tileY * numTilesX; - const unsigned int x0 = tileX * TILE_SIZE_X; - const unsigned int x1 = min(x0+TILE_SIZE_X,width); - const unsigned int y0 = tileY * TILE_SIZE_Y; - const unsigned int y1 = min(y0+TILE_SIZE_Y,height); - - for (unsigned int y=y0; y& range) { - for (size_t i=range.begin(); i 0) { - Vec3fa dPdu,dPdv; - unsigned int geomID = ray.geomID; { - rtcInterpolate(g_scene,geomID,ray.primID,ray.u,ray.v,RTC_VERTEX_BUFFER,nullptr,&dPdu.x,&dPdv.x,3); - } - Ng = normalize(cross(dPdv,dPdu)); - dPdu = dPdu + Ng*displacement_du(P,dPdu); - dPdv = dPdv + Ng*displacement_dv(P,dPdv); - Ng = normalize(cross(dPdv,dPdu)); - } -#endif - - /* initialize shadow ray */ - RTCRay shadow; - shadow.org = ray.org + ray.tfar*ray.dir; - shadow.dir = neg(lightDir); - shadow.tnear = 0.001f; - shadow.tfar = inf; - shadow.geomID = RTC_INVALID_GEOMETRY_ID; - shadow.primID = RTC_INVALID_GEOMETRY_ID; - shadow.mask = -1; - shadow.time = 0; - - /* trace shadow ray */ - rtcOccluded(g_scene,shadow); - - /* add light contribution */ - if (shadow.geomID == RTC_INVALID_GEOMETRY_ID) - color = color + diffuse*clamp(-(dot(lightDir,Ng)),0.0f,1.0f); - } - return color; -} - -/* renders a single screen tile */ -void renderTileStandard(int taskIndex, - int* pixels, - const unsigned int width, - const unsigned int height, - const float time, - const ISPCCamera& camera, - const int numTilesX, - const int numTilesY) -{ - const unsigned int tileY = taskIndex / numTilesX; - const unsigned int tileX = taskIndex - tileY * numTilesX; - const unsigned int x0 = tileX * TILE_SIZE_X; - const unsigned int x1 = min(x0+TILE_SIZE_X,width); - const unsigned int y0 = tileY * TILE_SIZE_Y; - const unsigned int y1 = min(y0+TILE_SIZE_Y,height); - - for (unsigned int y=y0; y& range) { - for (size_t i=range.begin(); i 1) { - triangles[tri].v0 = p10; - triangles[tri].v1 = p00; - triangles[tri].v2 = p01; - tri++; - } - - if (phi < numPhi) { - triangles[tri].v0 = p11; - triangles[tri].v1 = p10; - triangles[tri].v2 = p01; - tri++; - } - } - } - rtcUnmapBuffer(g_scene,mesh,RTC_VERTEX_BUFFER); - rtcUnmapBuffer(g_scene,mesh,RTC_INDEX_BUFFER); - - return mesh; -} - -/* adds a ground plane to the scene */ -unsigned int addGroundPlane (RTCScene scene_i) -{ - /* create a triangulated plane with 2 triangles and 4 vertices */ - unsigned int mesh = rtcNewTriangleMesh (scene_i, RTC_GEOMETRY_STATIC, 2, 4); - - /* set vertices */ - Vertex* vertices = (Vertex*) rtcMapBuffer(scene_i,mesh,RTC_VERTEX_BUFFER); - vertices[0].x = -10; vertices[0].y = -2; vertices[0].z = -10; - vertices[1].x = -10; vertices[1].y = -2; vertices[1].z = +10; - vertices[2].x = +10; vertices[2].y = -2; vertices[2].z = -10; - vertices[3].x = +10; vertices[3].y = -2; vertices[3].z = +10; - rtcUnmapBuffer(scene_i,mesh,RTC_VERTEX_BUFFER); - - /* set triangles */ - Triangle* triangles = (Triangle*) rtcMapBuffer(scene_i,mesh,RTC_INDEX_BUFFER); - triangles[0].v0 = 0; triangles[0].v1 = 2; triangles[0].v2 = 1; - triangles[1].v0 = 1; triangles[1].v1 = 2; triangles[1].v2 = 3; - rtcUnmapBuffer(scene_i,mesh,RTC_INDEX_BUFFER); - - return mesh; -} - -/* called by the C++ code for initialization */ -extern "C" void device_init (char* cfg) -{ - /* create new Embree device */ - g_device = rtcNewDevice(cfg); - error_handler(rtcDeviceGetError(g_device)); - - /* set error handler */ - rtcDeviceSetErrorFunction(g_device,error_handler); - - /* create scene */ - g_scene = rtcDeviceNewScene(g_device,RTC_SCENE_DYNAMIC | RTC_SCENE_ROBUST, RTC_INTERSECT1); - - /* create some triangulated spheres */ - for (int i=0; ix = pos.x + r*sin(f*phif)*sin(thetaf); - v->y = pos.y + r*cos(phif); - v->z = pos.z + r*sin(f*phif)*cos(thetaf); - } -} - -/* task that renders a single screen tile */ -Vec3fa renderPixelStandard(float x, float y, const ISPCCamera& camera) -{ - /* initialize ray */ - RTCRay ray; - ray.org = Vec3fa(camera.xfm.p); - ray.dir = Vec3fa(normalize(x*camera.xfm.l.vx + y*camera.xfm.l.vy + camera.xfm.l.vz)); - ray.tnear = 0.0f; - ray.tfar = inf; - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.primID = RTC_INVALID_GEOMETRY_ID; - ray.mask = -1; - ray.time = 0; - - /* intersect ray with scene */ - rtcIntersect(g_scene,ray); - - /* shade pixels */ - Vec3fa color = Vec3fa(0.0f); - if (ray.geomID != RTC_INVALID_GEOMETRY_ID) - { - Vec3fa diffuse = colors[ray.geomID]; - color = color + diffuse*0.1f; - Vec3fa lightDir = normalize(Vec3fa(-1,-1,-1)); - - /* initialize shadow ray */ - RTCRay shadow; - shadow.org = ray.org + ray.tfar*ray.dir; - shadow.dir = neg(lightDir); - shadow.tnear = 0.001f; - shadow.tfar = inf; - shadow.geomID = 1; - shadow.primID = 0; - shadow.mask = -1; - shadow.time = 0; - - /* trace shadow ray */ - rtcOccluded(g_scene,shadow); - - /* add light contribution */ - if (shadow.geomID) - color = color + diffuse*clamp(-dot(lightDir,normalize(ray.Ng)),0.0f,1.0f); - } - return color; -} - -/* renders a single screen tile */ -void renderTileStandard(int taskIndex, - int* pixels, - const unsigned int width, - const unsigned int height, - const float time, - const ISPCCamera& camera, - const int numTilesX, - const int numTilesY) -{ - const unsigned int tileY = taskIndex / numTilesX; - const unsigned int tileX = taskIndex - tileY * numTilesX; - const unsigned int x0 = tileX * TILE_SIZE_X; - const unsigned int x1 = min(x0+TILE_SIZE_X,width); - const unsigned int y0 = tileY * TILE_SIZE_Y; - const unsigned int y1 = min(y0+TILE_SIZE_Y,height); - - for (unsigned int y=y0; y& range) { - for (size_t i=range.begin(); ix = pos.x+r*sin(f*phif)*sin(thetaf); - v->y = pos.y+r*cos(phif); - v->z = pos.z+r*sin(f*phif)*cos(thetaf); - } -#endif - - rtcUnmapBuffer(g_scene,id,RTC_VERTEX_BUFFER); - - /* update mesh */ - rtcUpdate (g_scene,id); -} - -/* called by the C++ code to render */ -extern "C" void device_render (int* pixels, - const unsigned int width, - const unsigned int height, - const float time, - const ISPCCamera& camera) -{ - /* animate sphere */ - for (int i=0; i& range) { - for (size_t i=range.begin(); i - -#include -//#include // use this to get _MM_SET_DENORMALS_ZERO_MODE when compiling for SSE3 or higher - -#if !defined(_MM_SET_DENORMALS_ZERO_MODE) -#define _MM_DENORMALS_ZERO_ON (0x0040) -#define _MM_DENORMALS_ZERO_OFF (0x0000) -#define _MM_DENORMALS_ZERO_MASK (0x0040) -#define _MM_SET_DENORMALS_ZERO_MODE(x) (_mm_setcsr((_mm_getcsr() & ~_MM_DENORMALS_ZERO_MASK) | (x))) -#endif - -int main(int argc, char* argv[]) -{ - /* for best performance set FTZ and DAZ flags in MXCSR control and status register */ - _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); - _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); - - /* create new Embree device */ - RTCDevice device = rtcNewDevice("verbose=1"); - - /* ddelete device again */ - rtcDeleteDevice(device); - - return 0; -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/find_embree/find_embree_ispc.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/find_embree/find_embree_ispc.cpp deleted file mode 100644 index 59297f023957..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/find_embree/find_embree_ispc.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include - -#include -//#include // use this to get _MM_SET_DENORMALS_ZERO_MODE when compiling for SSE3 or higher - -#if !defined(_MM_SET_DENORMALS_ZERO_MODE) -#define _MM_DENORMALS_ZERO_ON (0x0040) -#define _MM_DENORMALS_ZERO_OFF (0x0000) -#define _MM_DENORMALS_ZERO_MASK (0x0040) -#define _MM_SET_DENORMALS_ZERO_MODE(x) (_mm_setcsr((_mm_getcsr() & ~_MM_DENORMALS_ZERO_MASK) | (x))) -#endif - -extern "C" void ispcEntry(); - -int main(int argc, char* argv[]) -{ - /* for best performance set FTZ and DAZ flags in MXCSR control and status register */ - _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); - _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); - - ispcEntry(); - - return 0; -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/hair_geometry/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/hair_geometry/CMakeLists.txt deleted file mode 100644 index 2f9e648d3a02..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/hair_geometry/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2017 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -INCLUDE(tutorial) -ADD_TUTORIAL(hair_geometry) -ADD_EMBREE_TEST(hair_geometry) diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/hair_geometry/hair_geometry.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/hair_geometry/hair_geometry.cpp deleted file mode 100644 index 427ff264eb52..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/hair_geometry/hair_geometry.cpp +++ /dev/null @@ -1,332 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial.h" - -namespace embree -{ - extern "C" { - embree::Vec3fa g_dirlight_direction = embree::normalize(embree::Vec3fa(1,-1,1)); - embree::Vec3fa g_dirlight_intensity = embree::Vec3fa(4.0f); - embree::Vec3fa g_ambient_intensity = embree::Vec3fa(1.0f); - } - - Vec3fa uniformSampleSphere(const float& u, const float& v) - { - const float phi = float(two_pi) * u; - const float cosTheta = 1.0f - 2.0f * v, sinTheta = 2.0f * sqrt(v * (1.0f - v)); - return Vec3fa(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta); - } - -static int p[513] = { - 151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23, - 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33, - 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166, - 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244, - 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196, - 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123, - 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42, - 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9, - 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228, - 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107, - 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, - 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180, - 151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23, - 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33, - 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166, - 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244, - 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196, - 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123, - 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42, - 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9, - 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228, - 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107, - 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, - 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180, - 151 -}; - -static float g1[128] = { - -0.20707f, 0.680971f, -0.293328f, -0.106833f, -0.362614f, 0.772857f, -0.968834f, 0.16818f, -0.681263f, -0.232568f, 0.382009f, -0.882282f, 0.799709f, -0.672908f, -0.681857f, 0.0661294f, 0.208288f, 0.165398f, -0.460058f, -0.219044f, -0.413199f, 0.484755f, -0.402949f, -0.848924f, -0.190035f, 0.714756f, 0.883937f, 0.325661f, 0.692952f, -0.99449f, -0.0752415f, 0.065192f, 0.575753f, -0.468776f, 0.965505f, -0.38643f, 0.20171f, 0.217431f, -0.575122f, 0.77179f, -0.390686f, -0.69628f, -0.324676f, -0.225046f, 0.28722f, 0.507107f, 0.207232f, 0.0632565f, -0.0812794f, 0.304977f, -0.345638f, 0.892741f, -0.26392f, 0.887781f, -0.985143f, 0.0331999f, -0.454458f, -0.951402f, 0.183909f, -0.590073f, 0.755387f, -0.881263f, -0.478315f, -0.394342f, 0.78299f, -0.00360388f, 0.420051f, -0.427172f, 0.729847f, 0.351081f, -0.0830201f, 0.919271f, 0.549351f, -0.246897f, -0.542722f, -0.290932f, -0.399364f, 0.339532f, 0.437933f, 0.131909f, 0.648931f, -0.218776f, 0.637533f, 0.688017f, -0.639064f, 0.886792f, -0.150226f, 0.0413316f, -0.868712f, 0.827016f, 0.765169f, 0.522728f, -0.202155f, 0.376514f, 0.523097f, -0.189982f, -0.749498f, -0.0307322f, -0.555075f, 0.746242f, 0.0576438f, -0.997172f, 0.721028f, -0.962605f, 0.629784f, -0.514232f, -0.370856f, 0.931465f, 0.87112f, 0.618863f, -0.0157817f, -0.559729f, 0.152707f, -0.421942f, -0.357866f, -0.477353f, -0.652024f, -0.996365f, -0.910432f, -0.517651f, -0.169098f, 0.403249f, -0.556309f, 0.00782069f, -0.86594f, -0.213873f, -0.0410469f, -0.563716f -}; - -static float g2[128*2] = { -0.605609f, 0.538399f, 0.796519f, -0.944204f, 0.908294f, 0.756016f, 0.0977536f, -0.863638f, 0.842196f, -0.744751f, -0.932081f, 0.932392f, -0.588525f, 0.516884f, 0.841188f, -0.978497f, -0.608649f, -0.868011f, 0.992137f, -0.772425f, 0.963049f, -0.0478757f, 0.953878f, 0.889467f, 0.562174f, 0.624644f, -0.356598f, -0.520726f, -0.821833f, 0.99985f, 0.234183f, -0.9791f, -0.971815f, -0.0979374f, -0.108159f, -0.34927f, -0.592124f, -0.775632f, 0.97228f, 0.753819f, 0.941608f, 0.578291f, 0.852108f, -0.760312f, -0.784772f, 0.0223242f, -0.606013f, -0.980319f, 0.252581f, -0.575064f, 0.884701f, 0.943763f, 0.737344f, 0.938496f, 0.0466562f, -0.994566f, 0.989782f, 0.988368f, -0.546155f, 0.279211f, -0.69504f, 0.931229f, 0.99768f, -0.325874f, -0.630157f, -0.999936f, -0.968623f, -0.226805f, -0.750428f, -0.450961f, 0.257868f, 0.968011f, -0.988005f, -0.713965f, 0.991007f, -0.61059f, 0.950437f, -0.483042f, -0.98105f, -0.915356f, -0.892527f, -0.772958f, -0.9081f, 0.55692f, 0.906075f, 0.937419f, 0.454624f, -0.991582f, 0.400857f, 0.855933f, -0.672619f, 0.0713424f, 0.593249f, -0.378286f, -0.997369f, -0.827112f, 0.708222f, -0.995343f, 0.985069f, 0.698711f, -0.180105f, 0.999961f, -0.768451f, 0.993107f, -0.918024f, 0.0446961f, 0.91882f, 0.97691f, -0.393915f, 0.364803f, 0.0495592f, 0.186545f, -0.461553f, -0.242776f, 0.901952f, -0.0710866f, 0.888101f, 0.999935f, 0.277688f, 0.0554235f, 0.506599f, -0.299293f, 0.984394f, -0.999698f, 0.408822f, -0.782639f, 0.128596f, 0.198834f, 0.981707f, 0.864566f, 0.808197f, 0.352335f, 0.970484f, -0.667503f, 0.330243f, 0.208392f, 0.191539f, -0.938943f, 0.895002f, 0.910575f, -0.537691f, -0.98548f, -0.721635f, -0.335382f, -0.424701f, -0.960452f, 0.595047f, 0.783579f, -0.937749f, 0.529096f, -0.997906f, -0.581313f, -0.899828f, -0.88461f, 0.989469f, 0.91872f, -0.850793f, 0.955954f, 0.715768f, -0.736686f, 0.80392f, -0.717276f, -0.788579f, 0.987003f, -0.839648f, 0.885176f, -0.998929f, -0.0376033f, -0.578371f, -0.718771f, 0.906081f, 0.239947f, -0.803563f, -0.00826282f, 0.991011f, -0.0057943f, -0.349232f, 0.65319f, 0.992067f, -0.953535f, 0.893781f, 0.661689f, 0.957253f, -0.425442f, -0.866609f, 0.712892f, -0.807777f, 0.89632f, -0.595147f, -0.0224999f, -0.643786f, 0.545815f, -0.870124f, -0.696306f, -0.99902f, 0.773648f, -0.806008f, -0.931319f, -0.780114f, -0.552154f, -0.933812f, -0.563108f, -0.619909f, 0.966532f, 0.692454f, 0.993284f, 0.338885f, -0.75104f, 0.237272f, -0.713619f, -0.160187f, -0.199242f, -0.371265f, -0.781439f, -0.914125f, -0.944104f, 0.169525f, -0.984403f, 0.976056f, -0.265228f, 0.94232f, 0.993906f, -0.877517f, -0.89618f, 0.611817f, -0.106758f, 0.680403f, 0.163329f, -0.325386f, -0.0687362f, -0.901164f, 0.460314f, 0.999981f, -0.0408026f, 0.850356f, -0.763343f, -0.170806f, -0.102919f, 0.581564f, 0.688634f, 0.284368f, -0.276419f, 0.616641f, -0.929771f, 0.927865f, 0.440373f, 0.153446f, 0.840456f, 0.996966f, 0.867209f, -0.135077f, -0.493238f, -0.577193f, 0.0588088f, 0.715215f, 0.0143633f -}; - -static float g3[128*4] = { - -0.582745f, 0.443494f, -0.680971f, 0.0f, -0.601153f, 0.791961f, 0.106833f, 0.0f, -0.265466f, 0.576385f, -0.772857f, 0.0f, 0.981035f, 0.0963612f, -0.16818f, 0.0f, 0.524388f, 0.819103f, 0.232568f, 0.0f, -0.170518f, -0.43875f, 0.882282f, 0.0f, 0.598053f, -0.435348f, 0.672908f, 0.0f, 0.53956f, 0.839346f, -0.0661294f, 0.0f, -0.782511f, -0.600267f, -0.165398f, 0.0f, -0.122114f, 0.968043f, 0.219044f, 0.0f, -0.235567f, 0.842331f, -0.484755f, 0.0f, -0.158657f, 0.504139f, 0.848924f, 0.0f, -0.578396f, 0.39317f, -0.714756f, 0.0f, 0.883328f, -0.337159f, -0.325661f, 0.0f, 0.0597264f, -0.0861552f, 0.99449f, 0.0f, -0.970124f, 0.233685f, -0.0651921f, 0.0f, 0.208238f, -0.858421f, 0.468776f, 0.0f, 0.916908f, -0.0997567f, 0.38643f, 0.0f, -0.786568f, -0.577957f, -0.217431f, 0.0f, 0.14868f, 0.618251f, -0.77179f, 0.0f, -0.24168f, 0.675858f, 0.69628f, 0.0f, -0.50994f, 0.83025f, 0.225046f, 0.0f, -0.534183f, -0.676382f, -0.507107f, 0.0f, -0.793861f, -0.6048f, -0.0632565f, 0.0f, -0.92148f, 0.240548f, -0.304977f, 0.0f, -0.210037f, 0.39862f, -0.892741f, 0.0f, -0.310918f, 0.339375f, -0.887781f, 0.0f, 0.99836f, 0.0466305f, -0.0331999f, 0.0f, -0.0439099f, 0.304806f, 0.951402f, 0.0f, -0.676304f, -0.440938f, 0.590073f, 0.0f, 0.339805f, -0.328495f, 0.881263f, 0.0f, -0.0625568f, 0.916832f, 0.394342f, 0.0f, 0.776463f, -0.630153f, 0.00360388f, 0.0f, -0.224717f, -0.8758f, 0.427172f, 0.0f, 0.618879f, -0.70266f, -0.351081f, 0.0f, -0.380313f, 0.101503f, -0.919271f, 0.0f, 0.149639f, -0.957418f, 0.246897f, 0.0f, 0.128024f, 0.948139f, 0.290932f, 0.0f, -0.292448f, 0.893976f, -0.339532f, 0.0f, -0.192062f, -0.972477f, -0.131909f, 0.0f, 0.44007f, -0.870905f, 0.218776f, 0.0f, 0.303887f, -0.659003f, -0.688017f, 0.0f, 0.195552f, 0.41876f, -0.886792f, 0.0f, -0.889922f, 0.454236f, -0.0413315f, 0.0f, 0.515034f, 0.225353f, -0.827016f, 0.0f, 0.63084f, -0.573408f, -0.522728f, 0.0f, -0.745779f, 0.549592f, -0.376514f, 0.0f, 0.0711763f, -0.979204f, 0.189982f, 0.0f, 0.705657f, 0.707887f, 0.0307322f, 0.0f, 0.114603f, 0.655735f, -0.746242f, 0.0f, -0.0739232f, -0.0135353f, 0.997172f, 0.0f, 0.173356f, -0.20818f, 0.962605f, 0.0f, 0.34008f, -0.787344f, 0.514232f, 0.0f, -0.143596f, 0.334295f, -0.931465f, 0.0f, 0.721989f, -0.30942f, -0.618863f, 0.0f, -0.827657f, 0.0410685f, 0.559729f, 0.0f, -0.804277f, -0.418454f, 0.421942f, 0.0f, -0.379459f, 0.792556f, 0.477353f, 0.0f, 0.0391537f, 0.0756503f, 0.996365f, 0.0f, 0.821943f, 0.237588f, 0.517651f, 0.0f, -0.788974f, 0.463584f, -0.403249f, 0.0f, 0.175972f, 0.984364f, -0.00782073f, 0.0f, 0.891497f, 0.399363f, 0.213873f, 0.0f, -0.819111f, 0.106216f, 0.563716f, 0.0f, 0.105511f, 0.544028f, -0.832406f, 0.0f, -0.464551f, 0.63753f, 0.614612f, 0.0f, 0.232387f, 0.935154f, -0.267363f, 0.0f, 0.777619f, 0.272068f, -0.566823f, 0.0f, 0.975331f, 0.190338f, 0.111807f, 0.0f, 0.224313f, 0.450072f, -0.86436f, 0.0f, 0.841897f, -0.536898f, 0.0543103f, 0.0f, 0.637123f, -0.664145f, -0.391135f, 0.0f, 0.901675f, -0.422984f, 0.0898189f, 0.0f, -0.496241f, 0.367413f, -0.786608f, 0.0f, -0.255468f, -0.689763f, -0.677469f, 0.0f, -0.0616459f, -0.951141f, -0.302539f, 0.0f, -0.431011f, -0.889035f, -0.154425f, 0.0f, -0.0711688f, 0.486502f, -0.870776f, 0.0f, -0.223359f, -0.36162f, 0.905175f, 0.0f, -0.678546f, 0.695482f, -0.23639f, 0.0f, 0.576553f, 0.77934f, 0.245389f, 0.0f, -0.194568f, -0.24951f, 0.948624f, 0.0f, 0.28962f, -0.447736f, 0.845962f, 0.0f, -0.0403821f, -0.871893f, 0.488028f, 0.0f, 0.790972f, -0.560788f, 0.244705f, 0.0f, -0.34553f, 0.739953f, 0.57713f, 0.0f, -0.516376f, -0.697122f, 0.49737f, 0.0f, 0.115998f, 0.859293f, 0.498156f, 0.0f, 0.643831f, -0.239955f, 0.72657f, 0.0f, -0.125114f, 0.987348f, -0.0974144f, 0.0f, -0.306452f, 0.610699f, -0.73016f, 0.0f, -0.269845f, 0.893027f, -0.360119f, 0.0f, 0.328563f, -0.570628f, -0.752615f, 0.0f, -0.306918f, -0.42057f, 0.853769f, 0.0f, 0.699245f, -0.51785f, 0.492837f, 0.0f, -0.558362f, -0.469763f, -0.68378f, 0.0f, 0.476563f, -0.841398f, 0.254826f, 0.0f, 0.0276172f, -0.623206f, 0.78157f, 0.0f, 0.587723f, -0.800313f, -0.118659f, 0.0f, 0.594035f, -0.740708f, 0.313806f, 0.0f, -0.340185f, -0.887929f, 0.309605f, 0.0f, 0.312245f, -0.246681f, -0.917416f, 0.0f, 0.194206f, 0.186398f, -0.963089f, 0.0f, 0.915704f, 0.329835f, -0.229553f, 0.0f, 0.94133f, 0.229917f, 0.247055f, 0.0f, -0.888253f, -0.144148f, 0.436152f, 0.0f, -0.906917f, -0.362625f, -0.214486f, 0.0f, 0.403108f, -0.908884f, 0.10693f, 0.0f, 0.983963f, 0.169256f, 0.056292f, 0.0f, -0.197949f, 0.888236f, 0.414553f, 0.0f, 0.0879741f, 0.247673f, 0.964841f, 0.0f, 0.474384f, -0.868071f, -0.146331f, 0.0f, 0.699884f, 0.541342f, -0.465953f, 0.0f, 0.610965f, 0.567249f, 0.552223f, 0.0f, 0.830508f, -0.285788f, -0.478103f, 0.0f, 0.328573f, -0.683076f, -0.652263f, 0.0f, -0.00537775f, 0.873381f, 0.487009f, 0.0f, -0.51289f, 0.828835f, 0.223557f, 0.0f, -0.871168f, -0.15102f, 0.467182f, 0.0f, -0.545561f, 0.390016f, -0.741789f, 0.0f, 0.874063f, 0.259258f, 0.410852f, 0.0f, -0.781555f, 0.612184f, -0.120005f, 0.0f, -0.284928f, 0.708938f, -0.645154f, 0.0f, -0.568809f, 0.0883274f, 0.817713f, 0.0f, -0.0429388f, 0.549957f, -0.834088f, 0.0f, 0.933296f, -0.127233f, 0.335813f, 0.0f, 0.698149f, -0.493464f, 0.51873f, 0.0f, -0.603413f, 0.617495f, -0.504572f, 0 -}; - -__forceinline float fade(float t) { - return (t * t * t) * (t * (t * 6 - 15) + 10); -} - -/*__forceinline float fade(float t) { - return t * t * (3 - t * 2); - }*/ - -__forceinline float lerp(float t, float a, float b) { - return a + t * (b - a); -} - -__forceinline float grad(int hash, float x) { - return x*g1[hash&127]; -} - -__forceinline float grad(int hash, float x, float y) { - int h = hash&127; - return x*g2[2*h+0]+y*g2[2*h+1]; -} - -__forceinline float grad(int hash, float x, float y, float z) { - int h = hash&127; - return x*g3[4*h+0]+y*g3[4*h+1]+z*g3[4*h+2]; -} - -float Noise(float x) -{ - float fx = floorf(x); - int X = (int)fx & 255; - x -= fx; - float u = fade(x); - float g00 = grad(p[X ],x ); - float g10 = grad(p[X+1],x-1); - return lerp(u,g00,g10); -} - -float Noise(float x, float y) -{ - float fx = floorf(x); - float fy = floorf(y); - - int X = (int)fx & 255; - int Y = (int)fy & 255; - - x -= fx; - y -= fy; - - float u = fade(x); - float v = fade(y); - - int p00 = p[X ]+Y; - int p10 = p[X+1]+Y; - int p01 = p[X ]+Y+1; - int p11 = p[X+1]+Y+1; - - float g00 = grad(p[p00],x ,y ); - float g10 = grad(p[p10],x-1,y ); - float g01 = grad(p[p01],x ,y-1); - float g11 = grad(p[p11],x-1,y-1); - - return lerp(v,lerp(u,g00,g10),lerp(u,g01,g11)); -} - -float Noise(float x, float y, float z) -{ - float fx = floorf(x); - float fy = floorf(y); - float fz = floorf(z); - - int X = (int)fx & 255; - int Y = (int)fy & 255; - int Z = (int)fz & 255; - - x -= fx; - y -= fy; - z -= fz; - - float u = fade(x); - float v = fade(y); - float w = fade(z); - - int p00 = p[X]+Y; - int p000 = p[p00]+Z; - int p010 = p[p00+1]+Z; - int p001 = p000+1; - int p011 = p010+1; - int p10 = p[X+1]+Y; - int p100 = p[p10]+Z; - int p110 = p[p10+1]+Z; - int p101 = p100+1; - int p111 = p110+1; - - float g000 = grad(p[p000],x ,y ,z ); - float g100 = grad(p[p100],x-1,y ,z ); - float g010 = grad(p[p010],x ,y-1,z ); - float g110 = grad(p[p110],x-1,y-1,z ); - float g001 = grad(p[p001],x ,y ,z-1); - float g101 = grad(p[p101],x-1,y ,z-1); - float g011 = grad(p[p011],x ,y-1,z-1); - float g111 = grad(p[p111],x-1,y-1,z-1); - - return lerp(w, - lerp(v,lerp(u,g000,g100),lerp(u,g010,g110)), - lerp(v,lerp(u,g001,g101),lerp(u,g011,g111))); -} - - Vec3fa Noise3D(const Vec3fa& p) - { - float x = Noise(4.0f*p.x); - float y = Noise(4.0f*p.y); - float z = Noise(4.0f*p.z); - return p+0.2f*Vec3fa(x,y,z); - } - - void addHairySphere (TutorialScene& scene, const Vec3fa& p, float r) - { - Material material; - unsigned materialID = unsigned(scene.materials.size()); - scene.materials.push_back(material); - - { - const size_t numPhi = 20; - const size_t numTheta = 2*numPhi; - - avector positions; - avector normals; - std::vector texcoords; - std::vector triangles; - - const float rcpNumTheta = rcp((float)numTheta); - const float rcpNumPhi = rcp((float)numPhi); - for (unsigned int phi=0; phi<=numPhi; phi++) - { - for (unsigned int theta=0; theta 1) - triangles.push_back(TutorialScene::Triangle(p10,p00,p01,materialID)); - - if (phi < numPhi) - triangles.push_back(TutorialScene::Triangle(p11,p10,p01,materialID)); - } - } - - scene.geometries.push_back(new TutorialScene::TriangleMesh(positions,normals,texcoords,triangles,materialID)); - } - - { - const float thickness = 0.001f*r; - avector positions; - std::vector hairs; - - unsigned int s = 0; - for (size_t iy=0; iy<300; iy++) - { - for (size_t ix=0; ix<300; ix++) - { - float fx = (float(ix)+2.0f*g2[s])/300.0f; s=(s+1)%255; - float fy = (float(iy)+2.0f*g2[s])/300.0f; s=(s+1)%255; - Vec3fa dp = uniformSampleSphere(fx,fy); - - Vec3fa l0 = p + r* (dp + 0.00f*dp); l0.w = thickness; - Vec3fa l1 = p + r* (dp + 0.25f*dp); l1.w = thickness; - Vec3fa l2 = p + r*Noise3D(dp + 0.50f*dp); l2.w = thickness; - Vec3fa l3 = p + r*Noise3D(dp + 0.75f*dp); l3.w = thickness; - - const size_t v_index = positions.size(); - positions.push_back(l0); - positions.push_back(l1); - positions.push_back(l2); - positions.push_back(l3); - hairs.push_back( TutorialScene::Hair(unsigned(v_index),0) ); - } - } - scene.geometries.push_back(new TutorialScene::HairSet(positions,hairs,materialID,true)); - } - } - - void addGroundPlane (TutorialScene& scene, const Vec3fa& p00, const Vec3fa& p01, const Vec3fa& p10, const Vec3fa& p11) - { - avector positions; - avector normals; - std::vector texcoords; - std::vector triangles; - - Material material; - unsigned materialID = unsigned(scene.materials.size()); - scene.materials.push_back(material); - - positions.push_back(p00); - positions.push_back(p01); - positions.push_back(p10); - positions.push_back(p11); - - triangles.push_back(TutorialScene::Triangle(0,1,2,materialID)); - triangles.push_back(TutorialScene::Triangle(2,1,3,materialID)); - - scene.geometries.push_back(new TutorialScene::TriangleMesh(positions,normals,texcoords,triangles,materialID)); - } - - struct Tutorial : public TutorialApplication - { - Tutorial() - : TutorialApplication("hair_geometry",FEATURE_RTCORE) - { - registerOption("ambientlight", [this] (Ref cin, const FileName& path) { - g_ambient_intensity = cin->getVec3fa(); - }, "--ambientlight r g b: adds an ambient light with intensity rgb"); - registerOptionAlias("ambientlight","ambient"); - - registerOption("directionallight", [this] (Ref cin, const FileName& path) { - g_dirlight_direction = normalize(cin->getVec3fa()); - g_dirlight_intensity = cin->getVec3fa(); - }, "--directionallight x y z r g b: adds a directional light with direction xyz and intensity rgb"); - registerOptionAlias("directionallight","dirlight"); - - /* set default camera */ - camera.from = Vec3fa(-3,3,3); - camera.to = Vec3fa(0,1,0); - camera.up = Vec3fa(0,1,0); - } - - void postParseCommandLine() - { - addHairySphere(obj_scene,Vec3fa(0,1.5f,0),1.5f); - addGroundPlane(obj_scene,Vec3fa(-10,0,-10),Vec3fa(-10,0,+10),Vec3fa(+10,0,-10),Vec3fa(+10,0,+10)); - - /* convert model */ - obj_scene.add(scene.dynamicCast(),(TutorialScene::InstancingMode)0); - scene = nullptr; - - /* send model */ - set_scene(&obj_scene); - } - - TutorialScene obj_scene; - Ref scene; - }; - -} - -int main(int argc, char** argv) { - return embree::Tutorial().main(argc,argv); -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/hair_geometry/hair_geometry_device.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/hair_geometry/hair_geometry_device.cpp deleted file mode 100644 index 9a465e3423d8..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/hair_geometry/hair_geometry_device.cpp +++ /dev/null @@ -1,537 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/math/random_sampler.h" -#include "../common/tutorial/tutorial_device.h" -#include "../common/tutorial/scene_device.h" -#include "../common/tutorial/optics.h" - -namespace embree { - -/* accumulation buffer */ -Vec3fa* g_accu = nullptr; -unsigned int g_accu_width = 0; -unsigned int g_accu_height = 0; -unsigned int g_accu_count = 0; -Vec3fa g_accu_vx; -Vec3fa g_accu_vy; -Vec3fa g_accu_vz; -Vec3fa g_accu_p; -extern "C" bool g_changed; -bool g_subdiv_mode = false; - -/* light settings */ -extern "C" Vec3fa g_dirlight_direction; -extern "C" Vec3fa g_dirlight_intensity; -extern "C" Vec3fa g_ambient_intensity; - -/* hair material */ -Vec3fa hair_K; -Vec3fa hair_dK; -Vec3fa hair_Kr; //!< reflectivity of hair -Vec3fa hair_Kt; //!< transparency of hair - -void filterDispatch(void* ptr, struct RTCRay2& ray); - -/* scene data */ -extern "C" ISPCScene* g_ispc_scene; -RTCDevice g_device = nullptr; -RTCScene g_scene = nullptr; - -/*! Uniform hemisphere sampling. Up direction is the z direction. */ -Vec3fa sampleSphere(const float u, const float v) -{ - const float phi = 2.0f*(float)pi * u; - const float cosTheta = 1.0f - 2.0f * v, sinTheta = 2.0f * sqrt(v * (1.0f - v)); - return Vec3fa(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta, float(one_over_four_pi)); -} - -void convertTriangleMesh(ISPCTriangleMesh* mesh, RTCScene scene_out) -{ - unsigned int geomID = rtcNewTriangleMesh (scene_out, RTC_GEOMETRY_STATIC, mesh->numTriangles, mesh->numVertices, mesh->numTimeSteps); - for (size_t t=0; tnumTimeSteps; t++) { - rtcSetBuffer(scene_out,geomID,(RTCBufferType)(RTC_VERTEX_BUFFER+t),mesh->positions+t*mesh->numVertices,0,sizeof(Vertex)); - } - rtcSetBuffer(scene_out,geomID,RTC_INDEX_BUFFER,mesh->triangles,0,sizeof(ISPCTriangle)); - rtcSetOcclusionFilterFunction(scene_out,geomID,(RTCFilterFunc)&filterDispatch); -} - -void convertHairSet(ISPCHairSet* hair, RTCScene scene_out) -{ - unsigned int geomID = rtcNewHairGeometry (scene_out, RTC_GEOMETRY_STATIC, hair->numHairs, hair->numVertices, hair->numTimeSteps); - for (size_t t=0; tnumTimeSteps; t++) { - rtcSetBuffer(scene_out,geomID,(RTCBufferType)(RTC_VERTEX_BUFFER+t),hair->positions+t*hair->numVertices,0,sizeof(Vertex)); - } - rtcSetBuffer(scene_out,geomID,RTC_INDEX_BUFFER,hair->hairs,0,sizeof(ISPCHair)); - rtcSetOcclusionFilterFunction(scene_out,geomID,(RTCFilterFunc)&filterDispatch); - rtcSetTessellationRate(scene_out,geomID,(float)hair->tessellation_rate); -} - -RTCScene convertScene(ISPCScene* scene_in) -{ - /* create scene */ - RTCScene scene_out = rtcDeviceNewScene(g_device, RTC_SCENE_STATIC | RTC_SCENE_INCOHERENT, RTC_INTERSECT1); - - for (size_t i=0; inumGeometries; i++) - { - ISPCGeometry* geometry = scene_in->geometries[i]; - if (geometry->type == TRIANGLE_MESH) - convertTriangleMesh((ISPCTriangleMesh*) geometry, scene_out); - else if (geometry->type == HAIR_SET) - convertHairSet((ISPCHairSet*) geometry, scene_out); - } - - /* commit changes to scene */ - rtcCommit (scene_out); - - return scene_out; -} - -////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////// - -/*! Anisotropic power cosine microfacet distribution. */ -struct AnisotropicBlinn { - Vec3fa dx; //!< x-direction of the distribution. - float nx; //!< Glossiness in x direction with range [0,infinity[ where 0 is a diffuse surface. - Vec3fa dy; //!< y-direction of the distribution. - float ny; //!< Exponent that determines the glossiness in y direction. - Vec3fa dz; //!< z-direction of the distribution. - float norm1; //!< Normalization constant for calculating the pdf for sampling. - float norm2; //!< Normalization constant for calculating the distribution. - Vec3fa Kr,Kt; - float side; -}; - - /*! Anisotropic power cosine distribution constructor. */ -inline void AnisotropicBlinn__Constructor(AnisotropicBlinn* This, const Vec3fa& Kr, const Vec3fa& Kt, - const Vec3fa& dx, float nx, const Vec3fa& dy, float ny, const Vec3fa& dz) -{ - This->Kr = Kr; - This->Kt = Kt; - This->dx = dx; - This->nx = nx; - This->dy = dy; - This->ny = ny; - This->dz = dz; - This->norm1 = sqrtf((nx+1)*(ny+1)) * float(one_over_two_pi); - This->norm2 = sqrtf((nx+2)*(ny+2)) * float(one_over_two_pi); - This->side = reduce_max(Kr)/(reduce_max(Kr)+reduce_max(Kt)); -} - -/*! Evaluates the power cosine distribution. \param wh is the half - * vector */ -inline float AnisotropicBlinn__eval(const AnisotropicBlinn* This, const Vec3fa& wh) -{ - const float cosPhiH = dot(wh, This->dx); - const float sinPhiH = dot(wh, This->dy); - const float cosThetaH = dot(wh, This->dz); - const float R = sqr(cosPhiH)+sqr(sinPhiH); - if (R == 0.0f) return This->norm2; - const float n = (This->nx*sqr(cosPhiH)+This->ny*sqr(sinPhiH))*rcp(R); - return This->norm2 * pow(abs(cosThetaH), n); -} - -/*! Samples the distribution. \param s is the sample location - * provided by the caller. */ -inline Vec3fa AnisotropicBlinn__sample(const AnisotropicBlinn* This, const float sx, const float sy) -{ - const float phi =float(two_pi)*sx; - const float sinPhi0 = sqrtf(This->nx+1)*sinf(phi); - const float cosPhi0 = sqrtf(This->ny+1)*cosf(phi); - const float norm = rsqrt(sqr(sinPhi0)+sqr(cosPhi0)); - const float sinPhi = sinPhi0*norm; - const float cosPhi = cosPhi0*norm; - const float n = This->nx*sqr(cosPhi)+This->ny*sqr(sinPhi); - const float cosTheta = powf(sy,rcp(n+1)); - const float sinTheta = cos2sin(cosTheta); - const float pdf = This->norm1*powf(cosTheta,n); - const Vec3fa h = Vec3fa(cosPhi * sinTheta, sinPhi * sinTheta, cosTheta); - const Vec3fa wh = h.x*This->dx + h.y*This->dy + h.z*This->dz; - return Vec3fa(wh,pdf); -} - -inline Vec3fa AnisotropicBlinn__eval(const AnisotropicBlinn* This, const Vec3fa& wo, const Vec3fa& wi) -{ - const float cosThetaI = dot(wi,This->dz); - - /* reflection */ - if (cosThetaI > 0.0f) { - const Vec3fa wh = normalize(wi + wo); - return This->Kr * AnisotropicBlinn__eval(This,wh) * abs(cosThetaI); - } - - /* transmission */ - else { - const Vec3fa wh = normalize(reflect(wi,This->dz) + wo); - return This->Kt * AnisotropicBlinn__eval(This,wh) * abs(cosThetaI); - } -} - -inline Vec3fa AnisotropicBlinn__sample(const AnisotropicBlinn* This, const Vec3fa& wo, Vec3fa& wi, const float sx, const float sy, const float sz) -{ - //wi = Vec3fa(reflect(normalize(wo),normalize(dz)),1.0f); return Kr; - //wi = Vec3fa(neg(wo),1.0f); return Kt; - const Vec3fa wh = AnisotropicBlinn__sample(This,sx,sy); - //if (dot(wo,wh) < 0.0f) return Vec3fa(0.0f,0.0f); - - /* reflection */ - if (sz < This->side) { - wi = Vec3fa(reflect(wo,Vec3fa(wh)),wh.w*This->side); - const float cosThetaI = dot(Vec3fa(wi),This->dz); - return This->Kr * AnisotropicBlinn__eval(This,Vec3fa(wh)) * abs(cosThetaI); - } - - /* transmission */ - else { - wi = Vec3fa(reflect(reflect(wo,Vec3fa(wh)),This->dz),wh.w*(1-This->side)); - const float cosThetaI = dot(Vec3fa(wi),This->dz); - return This->Kt * AnisotropicBlinn__eval(This,Vec3fa(wh)) * abs(cosThetaI); - } -} - -typedef Vec3fa* uniform_Vec3fa_ptr; - -inline Vec3fa evalBezier(const int geomID, const int primID, const float t) -{ - const float t0 = 1.0f - t, t1 = t; - const ISPCHairSet* hair = (const ISPCHairSet*) g_ispc_scene->geometries[geomID]; - const Vec3fa* vertices = hair->positions; - const ISPCHair* hairs = hair->hairs; - - const int i = hairs[primID].vertex; - const Vec3fa p00 = vertices[i+0]; - const Vec3fa p01 = vertices[i+1]; - const Vec3fa p02 = vertices[i+2]; - const Vec3fa p03 = vertices[i+3]; - - const Vec3fa p10 = p00 * t0 + p01 * t1; - const Vec3fa p11 = p01 * t0 + p02 * t1; - const Vec3fa p12 = p02 * t0 + p03 * t1; - const Vec3fa p20 = p10 * t0 + p11 * t1; - const Vec3fa p21 = p11 * t0 + p12 * t1; - const Vec3fa p30 = p20 * t0 + p21 * t1; - - return p30; - //tangent = p21-p20; -} - -/* extended ray structure that includes total transparency along the ray */ -struct RTCRay2 -{ - Vec3fa org; //!< Ray origin - Vec3fa dir; //!< Ray direction - float tnear; //!< Start of ray segment - float tfar; //!< End of ray segment - float time; //!< Time of this ray for motion blur. - int mask; //!< used to mask out objects during traversal - Vec3fa Ng; //!< Geometric normal. - float u; //!< Barycentric u coordinate of hit - float v; //!< Barycentric v coordinate of hit - unsigned int geomID; //!< geometry ID - unsigned int primID; //!< primitive ID - unsigned int instID; //!< instance ID - - // ray extensions - RTCFilterFunc filter; - Vec3fa transparency; //!< accumulated transparency value -}; - -bool enableFilterDispatch = false; - -/* filter dispatch function */ -void filterDispatch(void* ptr, RTCRay2& ray) { - if (!enableFilterDispatch) return; - if (ray.filter) ray.filter(ptr,*((RTCRay*)&ray)); -} - -/* occlusion filter function */ -void occlusionFilter(void* ptr, RTCRay2& ray) -{ - /* make all surfaces opaque */ - ISPCGeometry* geometry = g_ispc_scene->geometries[ray.geomID]; - if (geometry->type == TRIANGLE_MESH) { - ray.transparency = Vec3fa(0.0f); - return; - } - Vec3fa T = hair_Kt; - T = T * ray.transparency; - ray.transparency = T; - if (ne(T,Vec3fa(0.0f))) ray.geomID = RTC_INVALID_GEOMETRY_ID; -} - -Vec3fa occluded(RTCScene scene, RTCRay2& ray) -{ - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.primID = RTC_INVALID_GEOMETRY_ID; - ray.mask = -1; - ray.filter = (RTCFilterFunc) &occlusionFilter; - ray.transparency = Vec3fa(1.0f); - rtcOccluded(scene,*((RTCRay*)&ray)); - - return ray.transparency; -} - -/* task that renders a single screen tile */ -Vec3fa renderPixelStandard(float x, float y, const ISPCCamera& camera) -{ - RandomSampler sampler; - RandomSampler_init(sampler, (int)x, (int)y, g_accu_count); - x += RandomSampler_get1D(sampler); - y += RandomSampler_get1D(sampler); - float time = RandomSampler_get1D(sampler); - - /* initialize ray */ - RTCRay2 ray; - ray.org = Vec3fa(camera.xfm.p); - ray.dir = Vec3fa(normalize(x*camera.xfm.l.vx + y*camera.xfm.l.vy + camera.xfm.l.vz)); - ray.tnear = 0.0f; - ray.tfar = inf; - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.primID = RTC_INVALID_GEOMETRY_ID; - ray.mask = -1; - ray.time = time; - ray.filter = nullptr; - - Vec3fa color = Vec3fa(0.0f); - Vec3fa weight = Vec3fa(1.0f); - size_t depth = 0; - - while (true) - { - /* terminate ray path */ - if (reduce_max(weight) < 0.01 || depth > 20) - return color; - - /* intersect ray with scene and gather all hits */ - rtcIntersect(g_scene,*((RTCRay*)&ray)); - - /* exit if we hit environment */ - if (ray.geomID == RTC_INVALID_GEOMETRY_ID) - return color + weight*Vec3fa(g_ambient_intensity); - - /* calculate transmissivity of hair */ - AnisotropicBlinn brdf; - float tnear_eps = 0.0001f; - - ISPCGeometry* geometry = g_ispc_scene->geometries[ray.geomID]; - if (geometry->type == HAIR_SET) - { - /* calculate tangent space */ - const Vec3fa dx = normalize(ray.Ng); - const Vec3fa dy = normalize(cross(ray.dir,dx)); - const Vec3fa dz = normalize(cross(dy,dx)); - - /* generate anisotropic BRDF */ - AnisotropicBlinn__Constructor(&brdf,hair_Kr,hair_Kt,dx,20.0f,dy,2.0f,dz); - brdf.Kr = hair_Kr; - Vec3fa p = evalBezier(ray.geomID,ray.primID,ray.u); - tnear_eps = 1.1f*p.w; - } - else if (geometry->type == TRIANGLE_MESH) - { - if (dot(ray.dir,ray.Ng) > 0) ray.Ng = neg(ray.Ng); - - /* calculate tangent space */ - const Vec3fa dz = normalize(ray.Ng); - const Vec3fa dx = normalize(cross(dz,ray.dir)); - const Vec3fa dy = normalize(cross(dz,dx)); - - /* generate isotropic BRDF */ - AnisotropicBlinn__Constructor(&brdf,Vec3fa(1.0f),Vec3fa(0.0f),dx,1.0f,dy,1.0f,dz); - } - else - return color; - - /* sample directional light */ - RTCRay2 shadow; - shadow.org = ray.org + ray.tfar*ray.dir; - shadow.dir = neg(Vec3fa(g_dirlight_direction)); - shadow.tnear = tnear_eps; - shadow.tfar = inf; - shadow.time = time; - Vec3fa T = occluded(g_scene,shadow); - Vec3fa c = AnisotropicBlinn__eval(&brdf,neg(ray.dir),neg(Vec3fa(g_dirlight_direction))); - color = color + weight*c*T*Vec3fa(g_dirlight_intensity); - -#if 1 - /* sample BRDF */ - Vec3fa wi; - float ru = RandomSampler_get1D(sampler); - float rv = RandomSampler_get1D(sampler); - float rw = RandomSampler_get1D(sampler); - c = AnisotropicBlinn__sample(&brdf,neg(ray.dir),wi,ru,rv,rw); - if (wi.w <= 0.0f) return color; - - /* calculate secondary ray and offset it out of the hair */ - float sign = dot(Vec3fa(wi),brdf.dz) < 0.0f ? -1.0f : 1.0f; - ray.org = ray.org + ray.tfar*ray.dir + sign*tnear_eps*brdf.dz; - ray.dir = Vec3fa(wi); - ray.tnear = 0.001f; - ray.tfar = inf; - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.primID = RTC_INVALID_GEOMETRY_ID; - ray.mask = -1; - ray.time = time; - ray.filter = nullptr; - weight = weight * c/wi.w; - -#else - - /* continue with transparency ray */ - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.tnear = 1.001f*ray.tfar; - ray.tfar = inf; - weight *= brdf.Kt; - -#endif - - depth++; - } - return color; -} - -/* renders a single screen tile */ -void renderTileStandard(int taskIndex, - int* pixels, - const unsigned int width, - const unsigned int height, - const float time, - const ISPCCamera& camera, - const int numTilesX, - const int numTilesY) -{ - const unsigned int tileY = taskIndex / numTilesX; - const unsigned int tileX = taskIndex - tileY * numTilesX; - const unsigned int x0 = tileX * TILE_SIZE_X; - const unsigned int x1 = min(x0+TILE_SIZE_X,width); - const unsigned int y0 = tileY * TILE_SIZE_Y; - const unsigned int y1 = min(y0+TILE_SIZE_Y,height); - - for (unsigned int y=y0; y& range) { - for (size_t i=range.begin(); i 1) { - triangles[tri].v0 = p10; - triangles[tri].v1 = p00; - triangles[tri].v2 = p01; - tri++; - } - - if (phi < numPhi) { - triangles[tri].v0 = p11; - triangles[tri].v1 = p10; - triangles[tri].v2 = p01; - tri++; - } - } - } - rtcUnmapBuffer(scene,mesh,RTC_VERTEX_BUFFER); - rtcUnmapBuffer(scene,mesh,RTC_INDEX_BUFFER); - return mesh; -} - -/* creates a ground plane */ -unsigned int createGroundPlane (RTCScene scene) -{ - /* create a triangulated plane with 2 triangles and 4 vertices */ - unsigned int mesh = rtcNewTriangleMesh (scene, RTC_GEOMETRY_STATIC, 2, 4); - - /* set vertices */ - Vertex* vertices = (Vertex*) rtcMapBuffer(scene,mesh,RTC_VERTEX_BUFFER); - vertices[0].x = -10; vertices[0].y = -2; vertices[0].z = -10; - vertices[1].x = -10; vertices[1].y = -2; vertices[1].z = +10; - vertices[2].x = +10; vertices[2].y = -2; vertices[2].z = -10; - vertices[3].x = +10; vertices[3].y = -2; vertices[3].z = +10; - rtcUnmapBuffer(scene,mesh,RTC_VERTEX_BUFFER); - - /* set triangles */ - Triangle* triangles = (Triangle*) rtcMapBuffer(scene,mesh,RTC_INDEX_BUFFER); - triangles[0].v0 = 0; triangles[0].v1 = 2; triangles[0].v2 = 1; - triangles[1].v0 = 1; triangles[1].v1 = 2; triangles[1].v2 = 3; - rtcUnmapBuffer(scene,mesh,RTC_INDEX_BUFFER); - - return mesh; -} - -/* scene data */ -RTCDevice g_device = nullptr; -RTCScene g_scene = nullptr; -RTCScene g_scene1 = nullptr; - -unsigned int g_instance0 = -1; -unsigned int g_instance1 = -1; -unsigned int g_instance2 = -1; -unsigned int g_instance3 = -1; -AffineSpace3fa instance_xfm[4]; -LinearSpace3fa normal_xfm[4]; - -Vec3fa colors[4][4]; - -/* called by the C++ code for initialization */ -extern "C" void device_init (char* cfg) -{ - /* create new Embree device */ - g_device = rtcNewDevice(cfg); - error_handler(rtcDeviceGetError(g_device)); - - /* set error handler */ - rtcDeviceSetErrorFunction(g_device,error_handler); - - RTCAlgorithmFlags aflags; - if (g_mode == MODE_NORMAL) aflags = RTC_INTERSECT1; - else aflags = RTC_INTERSECT1 | RTC_INTERSECT_STREAM; - - /* create scene */ - g_scene = rtcDeviceNewScene(g_device, RTC_SCENE_DYNAMIC,aflags); - - /* create scene with 4 triangulated spheres */ - g_scene1 = rtcDeviceNewScene(g_device, RTC_SCENE_STATIC,aflags); - createTriangulatedSphere(g_scene1,Vec3fa( 0, 0,+1),0.5f); - createTriangulatedSphere(g_scene1,Vec3fa(+1, 0, 0),0.5f); - createTriangulatedSphere(g_scene1,Vec3fa( 0, 0,-1),0.5f); - createTriangulatedSphere(g_scene1,Vec3fa(-1, 0, 0),0.5f); - rtcCommit (g_scene1); - - /* instantiate geometry */ - g_instance0 = rtcNewInstance(g_scene,g_scene1); - g_instance1 = rtcNewInstance(g_scene,g_scene1); - g_instance2 = rtcNewInstance(g_scene,g_scene1); - g_instance3 = rtcNewInstance(g_scene,g_scene1); - createGroundPlane(g_scene); - - /* set all colors */ - colors[0][0] = Vec3fa(0.25f, 0.f, 0.f); - colors[0][1] = Vec3fa(0.50f, 0.f, 0.f); - colors[0][2] = Vec3fa(0.75f, 0.f, 0.f); - colors[0][3] = Vec3fa(1.00f, 0.f, 0.f); - - colors[1][0] = Vec3fa(0.f, 0.25f, 0.f); - colors[1][1] = Vec3fa(0.f, 0.50f, 0.f); - colors[1][2] = Vec3fa(0.f, 0.75f, 0.f); - colors[1][3] = Vec3fa(0.f, 1.00f, 0.f); - - colors[2][0] = Vec3fa(0.f, 0.f, 0.25f); - colors[2][1] = Vec3fa(0.f, 0.f, 0.50f); - colors[2][2] = Vec3fa(0.f, 0.f, 0.75f); - colors[2][3] = Vec3fa(0.f, 0.f, 1.00f); - - colors[3][0] = Vec3fa(0.25f, 0.25f, 0.f); - colors[3][1] = Vec3fa(0.50f, 0.50f, 0.f); - colors[3][2] = Vec3fa(0.75f, 0.75f, 0.f); - colors[3][3] = Vec3fa(1.00f, 1.00f, 0.f); - - /* set start render mode */ - if (g_mode == MODE_NORMAL) renderTile = renderTileStandard; - else renderTile = renderTileStandardStream; - key_pressed_handler = device_key_pressed_default; -} - -/* task that renders a single screen tile */ -Vec3fa renderPixelStandard(float x, float y, const ISPCCamera& camera) -{ - /* initialize ray */ - RTCRay ray; - ray.org = Vec3fa(camera.xfm.p); - ray.dir = Vec3fa(normalize(x*camera.xfm.l.vx + y*camera.xfm.l.vy + camera.xfm.l.vz)); - ray.tnear = 0.0f; - ray.tfar = (float)(inf); - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.primID = RTC_INVALID_GEOMETRY_ID; - ray.instID = -1; - ray.mask = -1; - ray.time = 0; - - /* intersect ray with scene */ - rtcIntersect(g_scene,ray); - - /* shade pixels */ - Vec3fa color = Vec3fa(0.0f); - if (ray.geomID != RTC_INVALID_GEOMETRY_ID) - { - /* calculate shading normal in world space */ - Vec3fa Ns = ray.Ng; - if (ray.instID != RTC_INVALID_GEOMETRY_ID) - Ns = xfmVector(normal_xfm[ray.instID],Ns); - Ns = normalize(Ns); - - /* calculate diffuse color of geometries */ - Vec3fa diffuse = Vec3fa(1,1,1); - if (ray.instID != RTC_INVALID_GEOMETRY_ID) - diffuse = colors[ray.instID][ray.geomID]; - color = color + diffuse*0.5; - - /* initialize shadow ray */ - Vec3fa lightDir = normalize(Vec3fa(-1,-1,-1)); - RTCRay shadow; - shadow.org = ray.org + ray.tfar*ray.dir; - shadow.dir = neg(lightDir); - shadow.tnear = 0.001f; - shadow.tfar = (float)(inf); - shadow.geomID = 1; - shadow.primID = 0; - shadow.mask = -1; - shadow.time = 0; - - /* trace shadow ray */ - rtcOccluded(g_scene,shadow); - - /* add light contribution */ - if (shadow.geomID) - color = color + diffuse*clamp(-dot(lightDir,Ns),0.0f,1.0f); - } - return color; -} - -/* renders a single screen tile */ -void renderTileStandard(int taskIndex, - int* pixels, - const unsigned int width, - const unsigned int height, - const float time, - const ISPCCamera& camera, - const int numTilesX, - const int numTilesY) -{ - const unsigned int tileY = taskIndex / numTilesX; - const unsigned int tileX = taskIndex - tileY * numTilesX; - const unsigned int x0 = tileX * TILE_SIZE_X; - const unsigned int x1 = min(x0+TILE_SIZE_X,width); - const unsigned int y0 = tileY * TILE_SIZE_Y; - const unsigned int y1 = min(y0+TILE_SIZE_Y,height); - - for (unsigned int y=y0; y& range) { - for (size_t i=range.begin(); i 0) - { - unsigned int geomID = ray.geomID; { - int geom = geomID == quadCubeID ? quadCubeID2 : geomID; // use special interpolation mesh - rtcInterpolate(g_scene,geom,ray.primID,ray.u,ray.v,RTC_USER_VERTEX_BUFFER0,&diffuse.x,nullptr,nullptr,3); - } - //return diffuse; - diffuse = 0.5f*diffuse; - } - - /* calculate smooth shading normal */ - Vec3fa Ng = ray.Ng; - if (ray.geomID >= 3) { - Vec3fa dPdu,dPdv; - unsigned int geomID = ray.geomID; { - rtcInterpolate(g_scene,geomID,ray.primID,ray.u,ray.v,RTC_VERTEX_BUFFER0,nullptr,&dPdu.x,&dPdv.x,3); - } - //return dPdu; - Ng = cross(dPdv,dPdu); - } - Ng = normalize(Ng); - color = color + diffuse*0.5f; - Vec3fa lightDir = normalize(Vec3fa(-1,-1,-1)); - - /* initialize shadow ray */ - RTCRay shadow; - shadow.org = ray.org + ray.tfar*ray.dir; - shadow.dir = neg(lightDir); - shadow.tnear = 0.001f; - shadow.tfar = inf; - shadow.geomID = 1; - shadow.primID = 0; - shadow.mask = -1; - shadow.time = 0; - - /* trace shadow ray */ - rtcOccluded(g_scene,shadow); - - /* add light contribution */ - if (shadow.geomID) { - Vec3fa r = normalize(reflect(ray.dir,Ng)); - float s = pow(clamp(dot(r,lightDir),0.0f,1.0f),10.0f); - float d = clamp(-dot(lightDir,Ng),0.0f,1.0f); - color = color + diffuse*d + 0.5f*Vec3fa(s); - } - } - return color; -} - -/* renders a single screen tile */ -void renderTileStandard(int taskIndex, - int* pixels, - const unsigned int width, - const unsigned int height, - const float time, - const ISPCCamera& camera, - const int numTilesX, - const int numTilesY) -{ - const unsigned int tileY = taskIndex / numTilesX; - const unsigned int tileX = taskIndex - tileY * numTilesX; - const unsigned int x0 = tileX * TILE_SIZE_X; - const unsigned int x1 = min(x0+TILE_SIZE_X,width); - const unsigned int y0 = tileY * TILE_SIZE_Y; - const unsigned int y1 = min(y0+TILE_SIZE_Y,height); - - for (unsigned int y=y0; y& range) { - for (size_t i=range.begin(); i= 1.0f) ray.geomID = RTC_INVALID_GEOMETRY_ID; - else ray.transparency = T; -} - -/* occlusion filter function */ -void occlusionFilter(void* ptr, RTCRay2& ray) -{ - Vec3fa h = ray.org + ray.dir*ray.tfar; - float T = transparencyFunction(h); - T *= ray.transparency; - ray.transparency = T; - if (T != 0.0f) ray.geomID = RTC_INVALID_GEOMETRY_ID; -} - -/* task that renders a single screen tile */ -Vec3fa renderPixelStandard(float x, float y, const ISPCCamera& camera) -{ - float weight = 1.0f; - Vec3fa color = Vec3fa(0.0f); - - /* initialize ray */ - RTCRay2 primary; - primary.org = Vec3fa(camera.xfm.p); - primary.dir = Vec3fa(normalize(x*camera.xfm.l.vx + y*camera.xfm.l.vy + camera.xfm.l.vz)); - primary.tnear = 0.0f; - primary.tfar = (float)(inf); - primary.geomID = RTC_INVALID_GEOMETRY_ID; - primary.primID = RTC_INVALID_GEOMETRY_ID; - primary.mask = -1; - primary.time = 0; - primary.transparency = 0.0f; - - while (true) - { - /* intersect ray with scene */ - rtcIntersect(g_scene,*((RTCRay*)&primary)); - - /* shade pixels */ - if (primary.geomID == RTC_INVALID_GEOMETRY_ID) - break; - - float opacity = 1.0f-primary.transparency; - Vec3fa diffuse = colors[primary.primID]; - Vec3fa La = diffuse*0.5f; - color = color + weight*opacity*La; - Vec3fa lightDir = normalize(Vec3fa(-1,-1,-1)); - - /* initialize shadow ray */ - RTCRay2 shadow; - shadow.org = primary.org + primary.tfar*primary.dir; - shadow.dir = neg(lightDir); - shadow.tnear = 0.001f; - shadow.tfar = (float)(inf); - shadow.geomID = RTC_INVALID_GEOMETRY_ID; - shadow.primID = RTC_INVALID_GEOMETRY_ID; - shadow.mask = -1; - shadow.time = 0; - shadow.transparency = 1.0f; - - /* trace shadow ray */ - rtcOccluded(g_scene,*((RTCRay*)&shadow)); - - /* add light contribution */ - if (shadow.geomID) { - Vec3fa Ll = diffuse*shadow.transparency*clamp(-dot(lightDir,normalize(primary.Ng)),0.0f,1.0f); - color = color + weight*opacity*Ll; - } - - /* shoot transmission ray */ - weight *= primary.transparency; - primary.tnear = 1.001f*primary.tfar; - primary.tfar = (float)(inf); - primary.geomID = RTC_INVALID_GEOMETRY_ID; - primary.primID = RTC_INVALID_GEOMETRY_ID; - primary.transparency = 0.0f; - } - return color; -} - -/* renders a single screen tile */ -void renderTileStandard(int taskIndex, - int* pixels, - const unsigned int width, - const unsigned int height, - const float time, - const ISPCCamera& camera, - const int numTilesX, - const int numTilesY) -{ - const unsigned int tileY = taskIndex / numTilesX; - const unsigned int tileX = taskIndex - tileY * numTilesX; - const unsigned int x0 = tileX * TILE_SIZE_X; - const unsigned int x1 = min(x0+TILE_SIZE_X,width); - const unsigned int y0 = tileY * TILE_SIZE_Y; - const unsigned int y1 = min(y0+TILE_SIZE_Y,height); - - for (unsigned int y=y0; y=N) continue; - - /* ignore inactive rays */ - if (valid[vi] != -1) continue; - - /* read ray from ray structure */ - Vec3fa ray_org = Vec3fa(RTCRayN_org_x(ray,N,ui),RTCRayN_org_y(ray,N,ui),RTCRayN_org_z(ray,N,ui)); - Vec3fa ray_dir = Vec3fa(RTCRayN_dir_x(ray,N,ui),RTCRayN_dir_y(ray,N,ui),RTCRayN_dir_z(ray,N,ui)); - unsigned ray_mask= RTCRayN_mask(ray,N,ui); - float hit_t = RTCHitN_t(potentialHit,N,ui); - - /* decode ray IDs */ - int pid = (ray_mask & 0xFFFF) / 1; - int rid = (ray_mask & 0xFFFF) % 1; - - /* calculate transparency */ - Vec3fa h = ray_org + ray_dir*hit_t; - float T = transparencyFunction(h); - - /* ignore hit if completely transparent */ - if (T >= 1.0f) valid[vi] = 0; - - /* otherwise accept hit and remember transparency */ - else - { - RTCRayN_instID(ray,N,ui) = RTCHitN_instID(potentialHit,N,ui); - RTCRayN_geomID(ray,N,ui) = RTCHitN_geomID(potentialHit,N,ui); - RTCRayN_primID(ray,N,ui) = RTCHitN_primID(potentialHit,N,ui); - - RTCRayN_u(ray,N,ui) = RTCHitN_u(potentialHit,N,ui); - RTCRayN_v(ray,N,ui) = RTCHitN_v(potentialHit,N,ui); - RTCRayN_tfar(ray,N,ui) = RTCHitN_t(potentialHit,N,ui); - - RTCRayN_Ng_x(ray,N,ui) = RTCHitN_Ng_x(potentialHit,N,ui); - RTCRayN_Ng_y(ray,N,ui) = RTCHitN_Ng_y(potentialHit,N,ui); - RTCRayN_Ng_z(ray,N,ui) = RTCHitN_Ng_z(potentialHit,N,ui); - - if (context) { - RTCRay2* eray = (RTCRay2*) context->userRayExt; - scatter(eray->transparency,sizeof(RTCRay2),pid,rid,T); - } - } - } -} - -/* occlusion filter function */ -void occlusionFilterN(int* valid, - void* ptr, - const RTCIntersectContext* context, - struct RTCRayN* ray, - const struct RTCHitN* potentialHit, - const size_t N) -{ - /* avoid crashing when debug visualizations are used */ - if (context == nullptr) - return; - - /* iterate over all rays in ray packet */ - for (unsigned int ui=0; ui=N) continue; - - /* ignore inactive rays */ - if (valid[vi] != -1) continue; - - /* read ray from ray structure */ - Vec3fa ray_org = Vec3fa(RTCRayN_org_x(ray,N,ui),RTCRayN_org_y(ray,N,ui),RTCRayN_org_z(ray,N,ui)); - Vec3fa ray_dir = Vec3fa(RTCRayN_dir_x(ray,N,ui),RTCRayN_dir_y(ray,N,ui),RTCRayN_dir_z(ray,N,ui)); - unsigned ray_mask= RTCRayN_mask(ray,N,ui); - float hit_t = RTCHitN_t(potentialHit,N,ui); - - /* decode ray IDs */ - int pid = (ray_mask & 0xFFFF) / 1; - int rid = (ray_mask & 0xFFFF) % 1; - RTCRay2* eray = (RTCRay2*) context->userRayExt; - - /* calculate transparency */ - Vec3fa h = ray_org + ray_dir*hit_t; - float T = transparencyFunction(h); - - /* accumulate transparency and store inside ray extensions */ - T *= gather(eray->transparency,sizeof(RTCRay2),pid,rid); - scatter(eray->transparency,sizeof(RTCRay2),pid,rid,T); - - /* reject a hit if not fully opqaue */ - if (T != 0.0f) valid[vi] = 0; - - /* otherwise accept the hit */ - else RTCRayN_geomID(ray,N,ui) = 0; - } -} - -/* renders a single screen tile */ -void renderTileStandardStream(int taskIndex, - int* pixels, - const unsigned int width, - const unsigned int height, - const float time, - const ISPCCamera& camera, - const int numTilesX, - const int numTilesY) -{ - const unsigned int tileY = taskIndex / numTilesX; - const unsigned int tileX = taskIndex - tileY * numTilesX; - const unsigned int x0 = tileX * TILE_SIZE_X; - const unsigned int x1 = min(x0+TILE_SIZE_X,width); - const unsigned int y0 = tileY * TILE_SIZE_Y; - const unsigned int y1 = min(y0+TILE_SIZE_Y,height); - - RTCRay2 primary_stream[TILE_SIZE_X*TILE_SIZE_Y]; - RTCRay2 shadow_stream[TILE_SIZE_X*TILE_SIZE_Y]; - Vec3fa color_stream[TILE_SIZE_X*TILE_SIZE_Y]; - float weight_stream[TILE_SIZE_X*TILE_SIZE_Y]; - bool valid_stream[TILE_SIZE_X*TILE_SIZE_Y]; - - /* select stream mode */ - RTCIntersectFlags iflags = g_mode == MODE_STREAM_COHERENT ? RTC_INTERSECT_COHERENT : RTC_INTERSECT_INCOHERENT; - - /* generate stream of primary rays */ - int N = 0; - int numActive = 0; - for (unsigned int y=y0; y& range) { - for (size_t i=range.begin(); i\& range) \{\ - for (size_t i=range.begin(); i $2 -echo >> $2 -echo 'namespace embree {' >> $2 -tail -n +$(($ln+1)) $2.backup >> $2 -echo >> $2 -echo '} // namespace embree' >> $2 diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/lazy_geometry/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/lazy_geometry/CMakeLists.txt deleted file mode 100644 index ec8f13966c05..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/lazy_geometry/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2017 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -INCLUDE(tutorial) -ADD_TUTORIAL(lazy_geometry) -ADD_EMBREE_TEST(lazy_geometry) diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/lazy_geometry/lazy_geometry.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/lazy_geometry/lazy_geometry.cpp deleted file mode 100644 index 4bab9864ed57..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/lazy_geometry/lazy_geometry.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial.h" - -namespace embree -{ - struct Tutorial : public TutorialApplication - { - Tutorial() - : TutorialApplication("intersection_filter",FEATURE_RTCORE) - { - /* set default camera */ - camera.from = Vec3fa(2.5f,2.5f,2.5f); - camera.to = Vec3fa(0.0f,0.0f,0.0f); - } - }; - -} - -int main(int argc, char** argv) { - return embree::Tutorial().main(argc,argv); -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/lazy_geometry/lazy_geometry_device.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/lazy_geometry/lazy_geometry_device.cpp deleted file mode 100644 index c06b1233e491..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/lazy_geometry/lazy_geometry_device.cpp +++ /dev/null @@ -1,353 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial_device.h" - -namespace embree { - -RTCDevice g_device = nullptr; - -const int numPhi = 20; -const int numTheta = 2*numPhi; -const int numSpheres = 64; - -/* state of the lazy geometry */ -enum LazyState -{ - LAZY_INVALID = 0, // the geometry is not yet created - LAZY_CREATE = 1, // one thread is creating the geometry - LAZY_COMMIT = 2, // possible multiple threads are committing the geometry - LAZY_VALID = 3 // the geometry is created -}; - -/* representation for our lazy geometry */ -struct LazyGeometry -{ - ALIGNED_STRUCT - unsigned int geometry; - LazyState state; - RTCScene object; - int userID; - Vec3fa center; - float radius; -}; - -void instanceBoundsFunc(const LazyGeometry* instance, size_t item, RTCBounds* bounds_o) -{ - Vec3fa lower = instance->center-Vec3fa(instance->radius); - Vec3fa upper = instance->center+Vec3fa(instance->radius); - bounds_o->lower_x = lower.x; - bounds_o->lower_y = lower.y; - bounds_o->lower_z = lower.z; - bounds_o->upper_x = upper.x; - bounds_o->upper_y = upper.y; - bounds_o->upper_z = upper.z; -} - -unsigned int createTriangulatedSphere (RTCScene scene, const Vec3fa& p, float r) -{ - /* create triangle mesh */ - unsigned int mesh = rtcNewTriangleMesh (scene, RTC_GEOMETRY_STATIC, 2*numTheta*(numPhi-1), numTheta*(numPhi+1)); - - /* map triangle and vertex buffers */ - Vertex* vertices = (Vertex*) rtcMapBuffer(scene,mesh,RTC_VERTEX_BUFFER); - Triangle* triangles = (Triangle*) rtcMapBuffer(scene,mesh,RTC_INDEX_BUFFER); - - /* create sphere */ - int tri = 0; - const float rcpNumTheta = rcp((float)numTheta); - const float rcpNumPhi = rcp((float)numPhi); - for (int phi=0; phi<=numPhi; phi++) - { - for (int theta=0; theta 1) { - triangles[tri].v0 = p10; - triangles[tri].v1 = p00; - triangles[tri].v2 = p01; - tri++; - } - - if (phi < numPhi) { - triangles[tri].v0 = p11; - triangles[tri].v1 = p10; - triangles[tri].v2 = p01; - tri++; - } - } - } - rtcUnmapBuffer(scene,mesh,RTC_VERTEX_BUFFER); - rtcUnmapBuffer(scene,mesh,RTC_INDEX_BUFFER); - return mesh; -} - -void lazyCreate(LazyGeometry* instance) -{ - /* one thread will switch the object from the LAZY_INVALID state to the LAZY_CREATE state */ - if (atomic_cmpxchg((int32_t*)&instance->state,LAZY_INVALID,LAZY_CREATE) == 0) - { - /* create the geometry */ - printf("creating sphere %i\n",instance->userID); - instance->object = rtcDeviceNewScene(g_device,RTC_SCENE_STATIC,RTC_INTERSECT1); - createTriangulatedSphere(instance->object,instance->center,instance->radius); - - /* when join mode is not supported we let only a single thread build */ - if (!rtcDeviceGetParameter1i(g_device,RTC_CONFIG_COMMIT_JOIN)) - rtcCommit(instance->object); - - /* now switch to the LAZY_COMMIT state */ - __memory_barrier(); - instance->state = LAZY_COMMIT; - } - else - { - /* wait until the geometry got created */ - while (atomic_cmpxchg((int32_t*)&instance->state,10,11) < LAZY_COMMIT) { - // instead of actively spinning here, best use a condition to let the thread sleep, or let it help in the creation stage - } - } - - /* multiple threads might enter the rtcCommit function to jointly - * build the internal data structures */ - if (rtcDeviceGetParameter1i(g_device,RTC_CONFIG_COMMIT_JOIN)) - rtcCommit(instance->object); - - /* switch to LAZY_VALID state */ - atomic_cmpxchg((int32_t*)&instance->state,LAZY_COMMIT,LAZY_VALID); -} - -void instanceIntersectFunc(LazyGeometry* instance, RTCRay& ray, size_t item) -{ - /* create the object if it is not yet created */ - if (instance->state != LAZY_VALID) - lazyCreate(instance); - - /* trace ray inside object */ - const int geomID = ray.geomID; - ray.geomID = RTC_INVALID_GEOMETRY_ID; - rtcIntersect(instance->object,ray); - if (ray.geomID == RTC_INVALID_GEOMETRY_ID) ray.geomID = geomID; - else ray.instID = instance->userID; -} - -void instanceOccludedFunc(LazyGeometry* instance, RTCRay& ray, size_t item) -{ - /* create the object if it is not yet created */ - if (instance->state != LAZY_VALID) - lazyCreate(instance); - - /* trace ray inside object */ - rtcOccluded(instance->object,ray); -} - -LazyGeometry* createLazyObject (RTCScene scene, int userID, const Vec3fa& center, const float radius) -{ - LazyGeometry* instance = (LazyGeometry*) alignedMalloc(sizeof(LazyGeometry)); - instance->state = LAZY_INVALID; - instance->object = nullptr; - instance->userID = userID; - instance->center = center; - instance->radius = radius; - instance->geometry = rtcNewUserGeometry(scene,1); - rtcSetUserData(scene,instance->geometry,instance); - rtcSetBoundsFunction(scene,instance->geometry,(RTCBoundsFunc)&instanceBoundsFunc); - rtcSetIntersectFunction(scene,instance->geometry,(RTCIntersectFunc)&instanceIntersectFunc); - rtcSetOccludedFunction (scene,instance->geometry,(RTCOccludedFunc )&instanceOccludedFunc); - return instance; -} - -/* creates a ground plane */ -unsigned int createGroundPlane (RTCScene scene) -{ - /* create a triangulated plane with 2 triangles and 4 vertices */ - unsigned int mesh = rtcNewTriangleMesh (scene, RTC_GEOMETRY_STATIC, 2, 4); - - /* set vertices */ - Vertex* vertices = (Vertex*) rtcMapBuffer(scene,mesh,RTC_VERTEX_BUFFER); - vertices[0].x = -10; vertices[0].y = -2; vertices[0].z = -10; - vertices[1].x = -10; vertices[1].y = -2; vertices[1].z = +10; - vertices[2].x = +10; vertices[2].y = -2; vertices[2].z = -10; - vertices[3].x = +10; vertices[3].y = -2; vertices[3].z = +10; - rtcUnmapBuffer(scene,mesh,RTC_VERTEX_BUFFER); - - /* set triangles */ - Triangle* triangles = (Triangle*) rtcMapBuffer(scene,mesh,RTC_INDEX_BUFFER); - triangles[0].v0 = 0; triangles[0].v1 = 2; triangles[0].v2 = 1; - triangles[1].v0 = 1; triangles[1].v1 = 2; triangles[1].v2 = 3; - rtcUnmapBuffer(scene,mesh,RTC_INDEX_BUFFER); - - return mesh; -} - -/* scene data */ -RTCScene g_scene = nullptr; - -/* called by the C++ code for initialization */ -extern "C" void device_init (char* cfg) -{ - /* create new Embree device */ - g_device = rtcNewDevice(cfg); - error_handler(rtcDeviceGetError(g_device)); - - /* set error handler */ - rtcDeviceSetErrorFunction(g_device,error_handler); - - /* create scene */ - g_scene = rtcDeviceNewScene(g_device,RTC_SCENE_STATIC,RTC_INTERSECT1); - - /* instantiate geometry */ - createGroundPlane(g_scene); - for (int i=0; i& range) { - for (size_t i=range.begin(); i - - - - - - -20 0 -20 - -20 0 +20 - +20 0 +20 - +20 0 -20 - - - 0 2 1 - 0 3 2 - - - "OBJ" - - 1 1 1 - - - - - - - - 0 0 0 0.3 - 0 1 0 0.3 - 0 1 1 0.3 - 1 1 1 0.3 - 2 1 1 0.3 - 2 3 1 0.3 - 4 3 1 0.1 - 4 0 1 0.1 - 2 1 2 0.5 - 2 2 5 0.7 - - 5 0 0 0.3 - 5 1 0 0.3 - 5 2 0 0.0 - nan nan nan nan - - 5 0 -2 3.0 - 5 1 -2 0.3 - 5 2 -2 0.0 - nan nan nan nan - - - - 1 2 3 4 5 6 7 - 11 - 15 - - - - "OBJ" - - 1 1 1 - - - - - - - - - 0 0 -2 0.2 - 8 4 -2 0.2 - -4 4 -2 0.2 - 4 0 -3 0.2 - - - - 0 0 - - - - "OBJ" - - 1 0 0 - - - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/curve1.xml b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/curve1.xml deleted file mode 100644 index eb5a2f2efdfc..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/curve1.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - -20 0 -20 - -20 0 +20 - +20 0 +20 - +20 0 -20 - - - 0 2 1 - 0 3 2 - - - "OBJ" - - 1 1 1 - - - - - - - - -2.0 1.0 -1.0 0.2 - +0.0 0.0 +0.0 0.2 - +2.0 1.0 +1.0 0.2 - +2.0 1.0 -1.0 0.6 - +0.0 +2.0 +0.0 0.2 - -2.0 1.0 +1.0 0.2 - -2.0 1.0 -1.0 0.2 - +0.0 0.0 +0.0 0.2 - +2.0 1.0 +1.0 0.2 - - - - 1 2 3 4 5 6 - - - - "OBJ" - - 1 1 1 - - - - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/cylinder.xml b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/cylinder.xml deleted file mode 100644 index dfde2123fb64..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/cylinder.xml +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - -1.0 -1.0 -1.0 - 1.0 -1.0 -1.0 - 1.0 -1.0 1.0 - -1.0 -1.0 1.0 - -1.0 1.0 -1.0 - 1.0 1.0 -1.0 - 1.0 1.0 1.0 - -1.0 1.0 1.0 - - - - 0 1 5 4 - 1 2 6 5 - 2 3 7 6 - 3 0 4 7 - - 4 5 6 7 - 0 3 2 1 - - - - 0.0 0.0 - 0.25 0.0 - 0.5 0.0 - 0.75 0.0 - 1.0 0.0 - - 0.0 1.0 - 0.25 1.0 - 0.5 1.0 - 0.75 1.0 - 1.0 1.0 - - 0 0 - 0 1 - 1 1 - 1 0 - - - - 0 1 6 5 - 1 2 7 6 - 2 3 8 7 - 3 4 9 8 - - 10 11 12 13 - 10 13 12 11 - - - - 4 4 4 4 4 4 - - - - 0 1 1 2 2 3 3 0 - 4 5 5 6 6 7 7 4 - - - - 4 4 4 4 - 4 4 4 4 - - - - "OBJ" - - 1 1 1 - - - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/hair0.xml b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/hair0.xml deleted file mode 100644 index 2b201c84904e..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/hair0.xml +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - - -20 0 -20 - -20 0 +20 - +20 0 +20 - +20 0 -20 - - - 0 2 1 - 0 3 2 - - - "OBJ" - - 1 1 1 - - - - - - - - 0 0 0 0.3 - 0 1 0 0.3 - 0 1 1 0.3 - 1 1 1 0.3 - 2 1 1 0.3 - 2 3 1 0.3 - 4 3 1 0.1 - 4 0 1 0.1 - 2 1 2 0.5 - 2 2 5 0.7 - - 5 0 0 0.3 - 5 1 0 0.3 - 5 2 0 0.0 - nan nan nan nan - - 5 0 -2 3.0 - 5 1 -2 0.3 - 5 2 -2 0.0 - nan nan nan nan - - - - 1 2 3 4 5 6 7 - 11 - 15 - - - - "OBJ" - - 1 1 1 - - - - - - - - - 0 0 -2 0.2 - 8 4 -2 0.2 - -4 4 -2 0.2 - 4 0 -3 0.2 - - - - 0 0 - - - - "OBJ" - - 1 0 0 - - - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/linesegments.xml b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/linesegments.xml deleted file mode 100644 index 12f19baaaa81..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/linesegments.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - -20 0 -20 - -20 0 +20 - +20 0 +20 - +20 0 -20 - - - 0 2 1 - 0 3 2 - - - "OBJ" - - 1 1 1 - - - - - - - - - - - - 0 -4 0 0.02 - 0 0 0 0.02 - 0 5 0 1 - 5 5 0 1 - 5 5 5 1 - 5 10 5 2 - 5 10 3 0 - - - - - 0 1 2 3 4 5 - - - - "OBJ" - - 1 1 1 - - - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv0.xml b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv0.xml deleted file mode 100644 index b22ab65a6a1c..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv0.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - -1.0 0.0 -1.0 - 0.0 0.0 -1.0 - +1.0 0.0 -1.0 - -1.0 1.0 0.0 - 0.0 1.0 0.0 - +1.0 1.0 0.0 - -1.0 0.0 +1.0 - 0.0 0.0 +1.0 - +1.0 0.0 +1.0 - - - - 0 1 4 3 - 1 2 5 4 - 3 4 7 6 - 4 5 8 7 - - - - 4 4 4 4 - - - - 3 4 4 5 - - - - 1 10 - - - - 0 2 6 8 - - - - 0 +inf 0 +inf - - - - "OBJ" - - 1 1 1 - - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv1.xml b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv1.xml deleted file mode 100644 index 10dccf1ca885..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv1.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - -1.0 -1.0 -1.0 - 1.0 -1.0 -1.0 - 1.0 -1.0 1.0 - -1.0 -1.0 1.0 - -1.0 1.0 -1.0 - 1.0 1.0 -1.0 - 1.0 1.0 1.0 - -1.0 1.0 1.0 - - - - 0 1 5 4 - 1 2 6 5 - 2 3 7 6 - 0 4 7 3 - 4 5 6 7 - 0 3 2 1 - - - - 4 4 4 4 4 4 - - - - "OBJ" - - 1 1 1 - - - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv3.xml b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv3.xml deleted file mode 100644 index 2634306402fe..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv3.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - -1.0 -1.0 -1.0 - 1.0 -1.0 -1.0 - 1.0 -1.0 1.0 - -1.0 -1.0 1.0 - -1.0 1.0 -1.0 - 1.0 1.0 -1.0 - 1.0 1.0 1.0 - -1.0 1.0 1.0 - - - - 0 1 4 5 - 1 2 6 5 - 2 3 7 6 - 0 4 7 3 - 4 5 6 7 - 0 3 2 1 - - - - 4 4 4 4 4 4 - - - - 0 - - - - "OBJ" - - 1 1 1 - - - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv4.xml b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv4.xml deleted file mode 100644 index 417c4a9a7bea..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv4.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - 0.0 0.0 +1.0 - 0.0 0.0 -1.0 - - +1.0 0.0 +1.0 - +1.0 0.0 -1.0 - - -1.0 0.0 +1.0 - -1.0 0.0 -1.0 - - 0.0 +1.0 +1.0 - 0.0 +1.0 -1.0 - - 0.0 -1.0 +1.0 - 0.0 -1.0 -1.0 - - - - - 2 3 1 0 - 4 5 1 0 - 6 7 1 0 - 8 9 1 0 - - - - 4 4 4 4 - - - - "OBJ" - - 1 1 1 - - - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv5.xml b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv5.xml deleted file mode 100644 index 433f6169aa4d..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv5.xml +++ /dev/null @@ -1,173 +0,0 @@ - - - - - "OBJ" - - 0.0000 0.0000 0.0000 - 1.0000 1.0000 1.0000 - 0.0000 0.0000 0.0000 - 0.0000 0.0000 0.0000 - 0.0000 - - - - - - - - 5 - 4 - 4 - 4 - 4 - 4 - 3 - 3 - 3 - 3 - 3 - - - -6.161304 3.084484 2.848330 - -2.643319 2.844333 3.752810 - -6.362397 2.310006 -1.083433 - -0.425384 2.985474 0.748454 - -2.414260 2.862669 -2.040039 - -7.162443 0.000000 -3.766171 - -3.198509 0.000000 -4.628065 - 1.854593 0.000000 -0.350175 - -0.334927 0.000000 -3.630392 - -0.294475 0.000000 5.092125 - 1.997062 0.000000 2.211453 - -6.599835 0.000000 5.503421 - -3.358078 0.000000 6.251306 - -9.117918 0.000000 -0.733933 - -8.480494 0.000000 3.151634 - - - 2 4 3 1 0 - 4 2 5 6 - 8 7 3 4 - 10 9 1 3 - 12 11 0 1 - 14 13 2 0 - 2 13 5 - 4 6 8 - 3 7 10 - 9 12 1 - 0 11 14 - - - 0.000000 0.000000 - 1.000000 0.000000 - 0.000000 0.963555 - 1.000000 0.670366 - 0.755295 0.963555 - 0.000000 0.000000 - 1.000000 0.000000 - 1.000000 1.000000 - 0.000000 1.000000 - 0.000000 0.000000 - 1.000000 0.000000 - 1.000000 1.000000 - 0.000000 1.000000 - 0.000000 0.000000 - 1.000000 0.000000 - 1.000000 1.000000 - 0.000000 1.000000 - 0.000000 0.000000 - 1.000000 0.000000 - 1.000000 1.000000 - 0.000000 1.000000 - 0.000000 0.000000 - 1.000000 0.000000 - 1.000000 1.000000 - 0.000000 1.000000 - 1.000000 0.000000 - 1.000000 1.000000 - 0.000000 1.000000 - 0.000000 0.000000 - 1.000000 1.000000 - 0.000000 1.000000 - 1.000000 0.000000 - 1.000000 1.000000 - 0.000000 1.000000 - 0.000000 0.000000 - 1.000000 0.000000 - 0.000000 1.000000 - 0.000000 0.000000 - 1.000000 1.000000 - 0.000000 1.000000 - - - 0 1 3 4 2 - 5 6 7 8 - 9 10 11 12 - 13 14 15 16 - 17 18 19 20 - 21 22 23 24 - 27 25 26 - 28 29 30 - 33 31 32 - 34 35 36 - 37 38 39 - - - -0.047363 0.997192 -0.058001 - -0.047363 0.997192 -0.058001 - -0.047363 0.997192 -0.058001 - -0.047363 0.997192 -0.058001 - -0.047363 0.997192 -0.058001 - -0.201349 0.728675 -0.654592 - -0.201349 0.728675 -0.654592 - -0.201349 0.728675 -0.654592 - -0.201349 0.728675 -0.654592 - 0.613888 0.658071 -0.435987 - 0.613888 0.658070 -0.435987 - 0.613888 0.658071 -0.435987 - 0.613888 0.658070 -0.435987 - 0.570399 0.684823 0.453499 - 0.570399 0.684823 0.453499 - 0.570399 0.684823 0.453499 - 0.570399 0.684823 0.453499 - -0.154934 0.665114 0.730492 - -0.154934 0.665114 0.730492 - -0.154934 0.665114 0.730492 - -0.154934 0.665114 0.730492 - -0.727717 0.685803 0.010114 - -0.727717 0.685803 0.010114 - -0.727717 0.685803 0.010114 - -0.727717 0.685803 0.010114 - -0.618327 0.677248 -0.398756 - -0.618327 0.677248 -0.398756 - -0.618327 0.677248 -0.398756 - 0.261487 0.606894 -0.750536 - 0.261487 0.606894 -0.750536 - 0.261487 0.606894 -0.750536 - 0.786161 0.616473 -0.043724 - 0.786161 0.616473 -0.043724 - 0.786161 0.616473 -0.043724 - 0.285470 0.591000 0.754471 - 0.285470 0.591000 0.754471 - 0.285470 0.591000 0.754471 - -0.655228 0.544182 0.523968 - -0.655228 0.544182 0.523968 - -0.655228 0.544182 0.523968 - - - 0 1 2 3 4 - 5 6 7 8 - 9 10 11 12 - 13 14 15 16 - 17 18 19 20 - 21 22 23 24 - 25 26 27 - 28 29 30 - 31 32 33 - 34 35 36 - 37 38 39 - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv6.xml b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv6.xml deleted file mode 100644 index 61f89a297fb9..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv6.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - -1.0 -1.0 0.0 - 0.0 -1.0 0.0 - +1.0 -1.0 0.0 - +2.0 -1.0 0.0 - - -1.0 0.0 0.0 - 0.0 0.0 0.0 - +1.0 0.0 0.0 - +2.0 0.0 0.0 - - -1.0 +1.0 0.0 - 0.0 +1.0 0.0 - +1.0 +1.0 0.0 - +2.0 +1.0 0.0 - - -1.0 +2.0 0.0 - 0.0 +2.0 0.0 - +1.0 +2.0 0.0 - +2.0 +2.0 0.0 - - - - - 0 1 5 4 - 1 2 6 5 - 2 3 7 6 - 4 5 9 8 - 5 6 10 9 - 6 7 11 10 - 8 9 13 12 - 9 10 14 13 - 10 11 15 14 - - - - 4 4 4 4 4 4 4 4 4 - - - - "OBJ" - - 1 1 1 - - - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv7.xml b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv7.xml deleted file mode 100644 index f577f346a4ee..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv7.xml +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - -1.0 -1.0 0.0 - 0.0 -1.0 0.0 - +1.0 -1.0 0.0 - +2.0 -1.0 0.0 - - -1.0 0.0 0.0 - 0.0 0.0 0.0 - +1.0 0.0 0.0 - +2.0 0.0 0.0 - - -1.0 +1.0 0.0 - 0.0 +1.0 0.0 - +1.0 +1.0 0.0 - +2.0 +1.0 0.0 - - -1.0 +2.0 0.0 - 0.0 +2.0 0.0 - +1.0 +2.0 0.0 - +2.0 +2.0 0.0 - - - - - 0 1 5 4 - 1 2 6 5 - 2 3 7 6 - 4 5 9 8 - 6 7 11 10 - 8 9 13 12 - 9 10 14 13 - 10 11 15 14 - - - - 4 4 4 4 4 4 4 4 - - - - 0 3 12 15 - 5 6 9 10 - - - - +inf +inf +inf +inf - +inf +inf +inf +inf - - - - "OBJ" - - 1 1 1 - - - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv8.xml b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv8.xml deleted file mode 100644 index 7fbbf80e20cd..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv8.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - -1.0 -1.0 0.0 - 0.0 -1.0 0.0 - +1.0 -1.0 0.0 - +2.0 -1.0 0.0 - - -1.0 0.0 0.0 - 0.0 0.0 0.0 - +1.0 0.0 0.0 - +2.0 0.0 0.0 - - -1.0 +1.0 0.0 - 0.0 +1.0 0.0 - +1.0 +1.0 0.0 - +2.0 +1.0 0.0 - - -1.0 +2.0 0.0 - 0.0 +2.0 0.0 - +1.0 +2.0 0.0 - +2.0 +2.0 0.0 - - - - - 1 2 6 5 - 4 5 9 8 - 5 6 10 9 - 6 7 11 10 - 9 10 14 13 - - - - 4 4 4 4 4 - - - - "OBJ" - - 1 1 1 - - - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv9.xml b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv9.xml deleted file mode 100644 index 6865837fbd3e..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv9.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - -1.0 -1.0 0.0 - 0.0 -1.0 0.0 - +1.0 -1.0 0.0 - +2.0 -1.0 0.0 - - -1.0 0.0 0.0 - 0.0 0.0 0.0 - +1.0 0.0 0.0 - +2.0 0.0 0.0 - - -1.0 +1.0 0.0 - 0.0 +1.0 0.0 - +1.0 +1.0 0.0 - +2.0 +1.0 0.0 - - -1.0 +2.0 0.0 - 0.0 +2.0 0.0 - +1.0 +2.0 0.0 - +2.0 +2.0 0.0 - - - - - 0 1 5 4 - - - - 4 - - - - "OBJ" - - 1 1 1 - - - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv_no_boundary.xml b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv_no_boundary.xml deleted file mode 100644 index 53346930fb3f..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv_no_boundary.xml +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - -3.5 -3.5 0.0 - -0.5 -1.5 0.0 - +0.5 -1.5 0.0 - +1.5 -1.5 0.0 - - -1.5 -0.5 0.0 - -0.5 -0.5 0.0 - +0.5 -0.5 0.0 - +1.5 -0.5 0.0 - - -1.5 +0.5 0.0 - -0.5 +0.5 0.0 - +0.5 +0.5 0.0 - +1.5 +0.5 0.0 - - -1.5 +1.5 0.0 - -0.5 +1.5 0.0 - +0.5 +1.5 0.0 - +3.5 +3.5 0.0 - - - - - 0 1 5 4 - 1 2 6 5 - 2 3 7 6 - 4 5 9 8 - 5 6 10 9 - 6 7 11 10 - 8 9 13 12 - 9 10 14 13 - 10 11 15 14 - - - - 0 0 - 0 0 - 0 1 - 1 1 - 1 0 - - - - 0 0 0 0 - 0 0 0 0 - 0 0 0 0 - 0 0 0 0 - - 1 2 3 4 - - 0 0 0 0 - 0 0 0 0 - 0 0 0 0 - 0 0 0 0 - - - - 4 4 4 4 4 4 4 4 4 - - - - "OBJ" - - 1 1 1 - - - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv_pin_all.xml b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv_pin_all.xml deleted file mode 100644 index 0fb7bcb06b3d..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv_pin_all.xml +++ /dev/null @@ -1,151 +0,0 @@ - - - - - - - - -2.0 +2.5 0.0 - -1.0 +2.5 0.0 - -0.5 +2.5 0.0 - +0.5 +2.5 0.0 - +1.0 +2.5 0.0 - +2.0 +2.5 0.0 - - -2.0 +1.5 0.0 - -1.0 +1.5 0.0 - +0.0 +1.5 0.0 - +1.0 +1.5 0.0 - +2.0 +1.5 0.0 - - -2.0 0.5 0.0 - -1.0 0.5 0.0 - +0.0 -0.5 0.0 - +1.0 0.5 0.0 - +2.0 0.5 0.0 - - -2.0 -0.5 0.0 - -1.25 -0.5 0.0 - -0.5 -1.5 0.0 - +0.5 -1.5 0.0 - +1.25 -0.5 0.0 - +2.0 -0.5 0.0 - - -2.0 -1.5 0.0 - -1.25 -1.5 0.0 - -0.5 -2.0 0.0 - +0.5 -2.0 0.0 - +1.25 -1.5 0.0 - +2.0 -1.5 0.0 - - -2.0 -2.5 0.0 - -1.25 -2.5 0.0 - -0.5 -2.5 0.0 - +0.5 -2.5 0.0 - +1.25 -2.5 0.0 - +2.0 -2.5 0.0 - - - - 0 1 7 6 - 1 2 8 7 - 3 4 9 8 - 4 5 10 9 - - 6 7 12 11 - 7 8 13 12 - 8 9 14 13 - 9 10 15 14 - - 16 17 23 22 - 17 18 24 23 - 19 20 26 25 - 20 21 27 26 - - 22 23 29 28 - 23 24 30 29 - 25 26 32 31 - 26 27 33 32 - - - - 0 0 - 0.25 0 - 0.375 0 - 0.625 0 - 0.75 0 - 1.0 0 - - 0.0 0.5 - 0.25 0.5 - 0.5 0.0 - 0.75 0.5 - 1.0 0.5 - - 0.0 1.0 - 0.25 1.0 - 0.5 1.0 - 0.75 1.0 - 1.0 1.0 - - 0.0 0.0 - 0.5 0.0 - 1.0 0.0 - 0.0 0.0 - 0.5 0.0 - 1.0 0.0 - - 0.0 0.5 - 0.5 0.5 - 1.0 0.5 - 0.0 0.5 - 0.5 0.5 - 1.0 0.5 - - 0.0 1.0 - 0.5 1.0 - 1.0 1.0 - 0.0 1.0 - 0.5 1.0 - 1.0 1.0 - - - - 0 1 7 6 - 1 2 8 7 - 3 4 9 8 - 4 5 10 9 - - 6 7 12 11 - 7 8 13 12 - 8 9 14 13 - 9 10 15 14 - - 16 17 23 22 - 17 18 24 23 - 19 20 26 25 - 20 21 27 26 - - 22 23 29 28 - 23 24 30 29 - 25 26 32 31 - 26 27 33 32 - - - - 4 4 4 4 - 4 4 4 4 - 4 4 4 4 - 4 4 4 4 - - - - "OBJ" - - 1 1 1 - - - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv_pin_boundary.xml b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv_pin_boundary.xml deleted file mode 100644 index b0e0efb8bf8e..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv_pin_boundary.xml +++ /dev/null @@ -1,152 +0,0 @@ - - - - - - - - -2.0 +2.5 0.0 - -1.0 +2.5 0.0 - -0.5 +2.5 0.0 - +0.5 +2.5 0.0 - +1.0 +2.5 0.0 - +2.0 +2.5 0.0 - - -2.0 +1.5 0.0 - -1.0 +1.5 0.0 - +0.0 +1.5 0.0 - +1.0 +1.5 0.0 - +2.0 +1.5 0.0 - - -2.0 0.5 0.0 - -1.0 0.5 0.0 - +0.0 -0.5 0.0 - +1.0 0.5 0.0 - +2.0 0.5 0.0 - - -2.0 -0.5 0.0 - -1.25 -0.5 0.0 - -0.5 -1.5 0.0 - +0.5 -1.5 0.0 - +1.25 -0.5 0.0 - +2.0 -0.5 0.0 - - -2.0 -1.5 0.0 - -1.25 -1.5 0.0 - -0.5 -2.0 0.0 - +0.5 -2.0 0.0 - +1.25 -1.5 0.0 - +2.0 -1.5 0.0 - - -2.0 -2.5 0.0 - -1.25 -2.5 0.0 - -0.5 -2.5 0.0 - +0.5 -2.5 0.0 - +1.25 -2.5 0.0 - +2.0 -2.5 0.0 - - - - 0 1 7 6 - 1 2 8 7 - 3 4 9 8 - 4 5 10 9 - - 6 7 12 11 - 7 8 13 12 - 8 9 14 13 - 9 10 15 14 - - 16 17 23 22 - 17 18 24 23 - 19 20 26 25 - 20 21 27 26 - - 22 23 29 28 - 23 24 30 29 - 25 26 32 31 - 26 27 33 32 - - - - - 0 0 - 0.25 0 - 0.375 0 - 0.625 0 - 0.75 0 - 1.0 0 - - 0.0 0.5 - 0.25 0.5 - 0.5 0.0 - 0.75 0.5 - 1.0 0.5 - - 0.0 1.0 - 0.25 1.0 - 0.5 1.0 - 0.75 1.0 - 1.0 1.0 - - 0.0 0.0 - 0.5 0.0 - 1.0 0.0 - 0.0 0.0 - 0.5 0.0 - 1.0 0.0 - - 0.0 0.5 - 0.5 0.5 - 1.0 0.5 - 0.0 0.5 - 0.5 0.5 - 1.0 0.5 - - 0.0 1.0 - 0.5 1.0 - 1.0 1.0 - 0.0 1.0 - 0.5 1.0 - 1.0 1.0 - - - - 0 1 7 6 - 1 2 8 7 - 3 4 9 8 - 4 5 10 9 - - 6 7 12 11 - 7 8 13 12 - 8 9 14 13 - 9 10 15 14 - - 16 17 23 22 - 17 18 24 23 - 19 20 26 25 - 20 21 27 26 - - 22 23 29 28 - 23 24 30 29 - 25 26 32 31 - 26 27 33 32 - - - - 4 4 4 4 - 4 4 4 4 - 4 4 4 4 - 4 4 4 4 - - - - "OBJ" - - 1 1 1 - - - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv_pin_corners.xml b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv_pin_corners.xml deleted file mode 100644 index 16156a6d2000..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv_pin_corners.xml +++ /dev/null @@ -1,151 +0,0 @@ - - - - - - - - -2.0 +2.5 0.0 - -1.0 +2.5 0.0 - -0.5 +2.5 0.0 - +0.5 +2.5 0.0 - +1.0 +2.5 0.0 - +2.0 +2.5 0.0 - - -2.0 +1.5 0.0 - -1.0 +1.5 0.0 - +0.0 +1.5 0.0 - +1.0 +1.5 0.0 - +2.0 +1.5 0.0 - - -2.0 0.5 0.0 - -1.0 0.5 0.0 - +0.0 -0.5 0.0 - +1.0 0.5 0.0 - +2.0 0.5 0.0 - - -2.0 -0.5 0.0 - -1.25 -0.5 0.0 - -0.5 -1.5 0.0 - +0.5 -1.5 0.0 - +1.25 -0.5 0.0 - +2.0 -0.5 0.0 - - -2.0 -1.5 0.0 - -1.25 -1.5 0.0 - -0.5 -2.0 0.0 - +0.5 -2.0 0.0 - +1.25 -1.5 0.0 - +2.0 -1.5 0.0 - - -2.0 -2.5 0.0 - -1.25 -2.5 0.0 - -0.5 -2.5 0.0 - +0.5 -2.5 0.0 - +1.25 -2.5 0.0 - +2.0 -2.5 0.0 - - - - 0 1 7 6 - 1 2 8 7 - 3 4 9 8 - 4 5 10 9 - - 6 7 12 11 - 7 8 13 12 - 8 9 14 13 - 9 10 15 14 - - 16 17 23 22 - 17 18 24 23 - 19 20 26 25 - 20 21 27 26 - - 22 23 29 28 - 23 24 30 29 - 25 26 32 31 - 26 27 33 32 - - - - 0 0 - 0.25 0 - 0.375 0 - 0.625 0 - 0.75 0 - 1.0 0 - - 0.0 0.5 - 0.25 0.5 - 0.5 0.0 - 0.75 0.5 - 1.0 0.5 - - 0.0 1.0 - 0.25 1.0 - 0.5 1.0 - 0.75 1.0 - 1.0 1.0 - - 0.0 0.0 - 0.5 0.0 - 1.0 0.0 - 0.0 0.0 - 0.5 0.0 - 1.0 0.0 - - 0.0 0.5 - 0.5 0.5 - 1.0 0.5 - 0.0 0.5 - 0.5 0.5 - 1.0 0.5 - - 0.0 1.0 - 0.5 1.0 - 1.0 1.0 - 0.0 1.0 - 0.5 1.0 - 1.0 1.0 - - - - 0 1 7 6 - 1 2 8 7 - 3 4 9 8 - 4 5 10 9 - - 6 7 12 11 - 7 8 13 12 - 8 9 14 13 - 9 10 15 14 - - 16 17 23 22 - 17 18 24 23 - 19 20 26 25 - 20 21 27 26 - - 22 23 29 28 - 23 24 30 29 - 25 26 32 31 - 26 27 33 32 - - - - 4 4 4 4 - 4 4 4 4 - 4 4 4 4 - 4 4 4 4 - - - - "OBJ" - - 1 1 1 - - - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv_smooth_boundary.xml b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv_smooth_boundary.xml deleted file mode 100644 index 93c9adc5e443..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/models/subdiv_smooth_boundary.xml +++ /dev/null @@ -1,151 +0,0 @@ - - - - - - - - -2.0 +2.5 0.0 - -1.0 +2.5 0.0 - -0.5 +2.5 0.0 - +0.5 +2.5 0.0 - +1.0 +2.5 0.0 - +2.0 +2.5 0.0 - - -2.0 +1.5 0.0 - -1.0 +1.5 0.0 - +0.0 +1.5 0.0 - +1.0 +1.5 0.0 - +2.0 +1.5 0.0 - - -2.0 0.5 0.0 - -1.0 0.5 0.0 - +0.0 -0.5 0.0 - +1.0 0.5 0.0 - +2.0 0.5 0.0 - - -2.0 -0.5 0.0 - -1.25 -0.5 0.0 - -0.5 -1.5 0.0 - +0.5 -1.5 0.0 - +1.25 -0.5 0.0 - +2.0 -0.5 0.0 - - -2.0 -1.5 0.0 - -1.25 -1.5 0.0 - -0.5 -2.0 0.0 - +0.5 -2.0 0.0 - +1.25 -1.5 0.0 - +2.0 -1.5 0.0 - - -2.0 -2.5 0.0 - -1.25 -2.5 0.0 - -0.5 -2.5 0.0 - +0.5 -2.5 0.0 - +1.25 -2.5 0.0 - +2.0 -2.5 0.0 - - - - 0 1 7 6 - 1 2 8 7 - 3 4 9 8 - 4 5 10 9 - - 6 7 12 11 - 7 8 13 12 - 8 9 14 13 - 9 10 15 14 - - 16 17 23 22 - 17 18 24 23 - 19 20 26 25 - 20 21 27 26 - - 22 23 29 28 - 23 24 30 29 - 25 26 32 31 - 26 27 33 32 - - - - 0 0 - 0.25 0 - 0.375 0 - 0.625 0 - 0.75 0 - 1.0 0 - - 0.0 0.5 - 0.25 0.5 - 0.5 0.0 - 0.75 0.5 - 1.0 0.5 - - 0.0 1.0 - 0.25 1.0 - 0.5 1.0 - 0.75 1.0 - 1.0 1.0 - - 0.0 0.0 - 0.5 0.0 - 1.0 0.0 - 0.0 0.0 - 0.5 0.0 - 1.0 0.0 - - 0.0 0.5 - 0.5 0.5 - 1.0 0.5 - 0.0 0.5 - 0.5 0.5 - 1.0 0.5 - - 0.0 1.0 - 0.5 1.0 - 1.0 1.0 - 0.0 1.0 - 0.5 1.0 - 1.0 1.0 - - - - 0 1 7 6 - 1 2 8 7 - 3 4 9 8 - 4 5 10 9 - - 6 7 12 11 - 7 8 13 12 - 8 9 14 13 - 9 10 15 14 - - 16 17 23 22 - 17 18 24 23 - 19 20 26 25 - 20 21 27 26 - - 22 23 29 28 - 23 24 30 29 - 25 26 32 31 - 26 27 33 32 - - - - 4 4 4 4 - 4 4 4 4 - 4 4 4 4 - 4 4 4 4 - - - - "OBJ" - - 1 1 1 - - - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/motion_blur_geometry/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/motion_blur_geometry/CMakeLists.txt deleted file mode 100644 index 1bf496386c09..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/motion_blur_geometry/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2017 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -INCLUDE(tutorial) -ADD_TUTORIAL(motion_blur_geometry) -ADD_EMBREE_TEST2(motion_blur_geometry motion_blur_geometry "--time 0.5") diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/motion_blur_geometry/motion_blur_geometry.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/motion_blur_geometry/motion_blur_geometry.cpp deleted file mode 100644 index 72b09f1318a0..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/motion_blur_geometry/motion_blur_geometry.cpp +++ /dev/null @@ -1,53 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial.h" - -namespace embree -{ - extern "C" float g_time = -1.0f; - extern "C" unsigned g_num_time_steps = 8; - extern "C" unsigned g_num_time_steps2 = 30; - - struct Tutorial : public TutorialApplication - { - Tutorial() - : TutorialApplication("motion_blur_geometry",FEATURE_RTCORE) - { - registerOption("time", [this] (Ref cin, const FileName& path) { - g_time = cin->getFloat(); - }, "--time : time to render image at"); - - registerOption("time-steps", [this] (Ref cin, const FileName& path) { - g_num_time_steps = cin->getInt(); - if (g_num_time_steps < 2) throw std::runtime_error("at least 2 time steps have to be used"); - }, "--time-steps : number of time steps to use"); - - registerOption("time-steps2", [this] (Ref cin, const FileName& path) { - g_num_time_steps2 = cin->getInt(); - if (g_num_time_steps2 < 2) throw std::runtime_error("at least 2 time steps have to be used"); - }, "--time-steps2 : number of time steps to use"); - - /* set default camera */ - camera.from = Vec3fa(6,11,0); - camera.to = Vec3fa(0,0,0); - } - }; -} - -int main(int argc, char** argv) { - return embree::Tutorial().main(argc,argv); -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/motion_blur_geometry/motion_blur_geometry_device.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/motion_blur_geometry/motion_blur_geometry_device.cpp deleted file mode 100644 index 712b9a5a3320..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/motion_blur_geometry/motion_blur_geometry_device.cpp +++ /dev/null @@ -1,702 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial_device.h" - -namespace embree { - -/* scene data */ -RTCDevice g_device = nullptr; -RTCScene g_scene = nullptr; -Vec3fa* face_colors = nullptr; - -/* accumulation buffer */ -Vec3fa* g_accu = nullptr; -unsigned int g_accu_width = 0; -unsigned int g_accu_height = 0; -unsigned int g_accu_count = 0; -Vec3fa g_accu_vx; -Vec3fa g_accu_vy; -Vec3fa g_accu_vz; -Vec3fa g_accu_p; -extern "C" bool g_changed; -extern "C" float g_time; -extern "C" unsigned int g_num_time_steps; -extern "C" unsigned int g_num_time_steps2; - - -__aligned(16) float cube_vertices[8][4] = -{ - { -1.0f, -1.0f, -1.0f, 0.0f }, - { 1.0f, -1.0f, -1.0f, 0.0f }, - { 1.0f, -1.0f, 1.0f, 0.0f }, - { -1.0f, -1.0f, 1.0f, 0.0f }, - { -1.0f, 1.0f, -1.0f, 0.0f }, - { 1.0f, 1.0f, -1.0f, 0.0f }, - { 1.0f, 1.0f, 1.0f, 0.0f }, - { -1.0f, 1.0f, 1.0f, 0.0f } -}; - -unsigned int cube_triangle_indices[36] = { - 1, 5, 4, 0, 1, 4, - 2, 6, 5, 1, 2, 5, - 3, 7, 6, 2, 3, 6, - 4, 7, 3, 0, 4, 3, - 5, 6, 7, 4, 5, 7, - 3, 2, 1, 0, 3, 1 -}; - -unsigned int cube_quad_indices[24] = { - 0, 1, 5, 4, - 1, 2, 6, 5, - 2, 3, 7, 6, - 0, 4, 7, 3, - 4, 5, 6, 7, - 0, 3, 2, 1, -}; - -__aligned(16) float cube_vertex_crease_weights[8] = { - inf, inf,inf, inf, inf, inf, inf, inf -}; - -__aligned(16) unsigned int cube_vertex_crease_indices[8] = { - 0,1,2,3,4,5,6,7 -}; - -__aligned(16) float cube_edge_crease_weights[12] = { - inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf -}; - -__aligned(16) unsigned int cube_edge_crease_indices[24] = -{ - 0,1, 1,2, 2,3, 3,0, - 4,5, 5,6, 6,7, 7,4, - 0,4, 1,5, 2,6, 3,7, -}; - -#define NUM_INDICES 24 -#define NUM_FACES 6 -#define FACE_SIZE 4 - -unsigned int cube_quad_faces[6] = { - 4, 4, 4, 4, 4, 4 -}; - -/* adds a cube to the scene */ -unsigned int addTriangleCube (RTCScene scene, const Vec3fa& pos, unsigned int num_time_steps) -{ - /* create a triangulated cube with 12 triangles and 8 vertices */ - unsigned int geomID = rtcNewTriangleMesh (scene, RTC_GEOMETRY_STATIC, 12, 8, num_time_steps); - rtcSetBuffer(scene, geomID, RTC_INDEX_BUFFER, cube_triangle_indices , 0, 3*sizeof(unsigned int)); - - for (size_t t=0; tp = p; - sphere->r = r; - sphere->geomID = geomID; - sphere->num_time_steps = num_time_steps; - rtcSetUserData(scene,geomID,sphere); - rtcSetBoundsFunction3(scene,geomID,(RTCBoundsFunc3)&sphereBoundsFunc,nullptr); - rtcSetIntersectFunction(scene,geomID,(RTCIntersectFunc)&sphereIntersectFunc); - rtcSetOccludedFunction (scene,geomID,(RTCOccludedFunc )&sphereOccludedFunc); - return sphere; -} - -/* adds a ground plane to the scene */ -unsigned int addGroundPlane (RTCScene scene) -{ - /* create a triangulated plane with 2 triangles and 4 vertices */ - unsigned int mesh = rtcNewTriangleMesh (scene, RTC_GEOMETRY_STATIC, 2, 4); - - /* set vertices */ - Vertex* vertices = (Vertex*) rtcMapBuffer(scene,mesh,RTC_VERTEX_BUFFER); - vertices[0].x = -10; vertices[0].y = -2; vertices[0].z = -10; - vertices[1].x = -10; vertices[1].y = -2; vertices[1].z = +10; - vertices[2].x = +10; vertices[2].y = -2; vertices[2].z = -10; - vertices[3].x = +10; vertices[3].y = -2; vertices[3].z = +10; - rtcUnmapBuffer(scene,mesh,RTC_VERTEX_BUFFER); - - /* set triangles */ - Triangle* triangles = (Triangle*) rtcMapBuffer(scene,mesh,RTC_INDEX_BUFFER); - triangles[0].v0 = 0; triangles[0].v1 = 2; triangles[0].v2 = 1; - triangles[1].v0 = 1; triangles[1].v1 = 2; triangles[1].v2 = 3; - rtcUnmapBuffer(scene,mesh,RTC_INDEX_BUFFER); - - return mesh; -} - -/* called by the C++ code for initialization */ -extern "C" void device_init (char* cfg) -{ - /* initialize last seen camera */ - g_accu_vx = Vec3fa(0.0f); - g_accu_vy = Vec3fa(0.0f); - g_accu_vz = Vec3fa(0.0f); - g_accu_p = Vec3fa(0.0f); - - /* create new Embree device */ - g_device = rtcNewDevice(cfg); - error_handler(rtcDeviceGetError(g_device)); - - /* set error handler */ - rtcDeviceSetErrorFunction(g_device,error_handler); - - /* create scene */ - g_scene = rtcDeviceNewScene(g_device, RTC_SCENE_STATIC,RTC_INTERSECT1); - - /* add geometry to the scene */ - addTriangleCube(g_scene,Vec3fa(-5,1,-5),g_num_time_steps); - addTriangleCube(g_scene,Vec3fa(-5,5,-5),g_num_time_steps2); - - addQuadCube (g_scene,Vec3fa( 0,1,-5),g_num_time_steps); - addQuadCube (g_scene,Vec3fa( 0,5,-5),g_num_time_steps2); - - addSubdivCube (g_scene,Vec3fa(+5,1,-5),g_num_time_steps); - addSubdivCube (g_scene,Vec3fa(+5,5,-5),g_num_time_steps2); - - addLines (g_scene,Vec3fa(-5,1, 0),g_num_time_steps); - addLines (g_scene,Vec3fa(-5,5, 0),g_num_time_steps2); - - addCurveOrHair (g_scene,Vec3fa( 0,1, 0),false,g_num_time_steps); - addCurveOrHair (g_scene,Vec3fa( 0,5, 0),false,g_num_time_steps2); - - addCurveOrHair (g_scene,Vec3fa(+5,1, 0),true,g_num_time_steps); - addCurveOrHair (g_scene,Vec3fa(+5,5, 0),true,g_num_time_steps2); - - addInstancedTriangleCube(g_scene,Vec3fa(-5,1,+5),g_num_time_steps); - addInstancedTriangleCube(g_scene,Vec3fa(-5,5,+5),g_num_time_steps2); - - addInstancedQuadCube (g_scene,Vec3fa( 0,1,+5),g_num_time_steps); - addInstancedQuadCube (g_scene,Vec3fa( 0,5,+5),g_num_time_steps2); - - addUserGeometrySphere (g_scene,Vec3fa(+5,1,+5),1.0f,g_num_time_steps); - addUserGeometrySphere (g_scene,Vec3fa(+5,5,+5),1.0f,g_num_time_steps2); - - addGroundPlane(g_scene); - - /* commit changes to scene */ - rtcCommit (g_scene); - - /* set start render mode */ - renderTile = renderTileStandard; - key_pressed_handler = device_key_pressed_default; -} - -int frameID = 50; - -/* task that renders a single screen tile */ -Vec3fa renderPixelStandard(float x, float y, const ISPCCamera& camera) -{ - float time = abs((int)(0.01f*frameID) - 0.01f*frameID); - if (g_time != -1) time = g_time; - - /* initialize ray */ - RTCRay ray; - ray.org = Vec3fa(camera.xfm.p); - ray.dir = Vec3fa(normalize(x*camera.xfm.l.vx + y*camera.xfm.l.vy + camera.xfm.l.vz)); - ray.tnear = 0.0f; - ray.tfar = inf; - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.primID = RTC_INVALID_GEOMETRY_ID; - ray.instID = RTC_INVALID_GEOMETRY_ID; - ray.mask = -1; - ray.time = time; - - /* intersect ray with scene */ - rtcIntersect(g_scene,ray); - - /* shade pixels */ - Vec3fa color = Vec3fa(0.0f); - if (ray.geomID != RTC_INVALID_GEOMETRY_ID) - { - Vec3fa diffuse = Vec3fa(0.5f,0.5f,0.5f); - if (ray.instID == RTC_INVALID_GEOMETRY_ID) - ray.instID = ray.geomID; - switch (ray.instID / 2) { - case 0: diffuse = face_colors[ray.primID]; break; - case 1: diffuse = face_colors[2*ray.primID]; break; - case 2: diffuse = face_colors[2*ray.primID]; break; - - case 3: diffuse = Vec3fa(0.5f,0.0f,0.0f); break; - case 4: diffuse = Vec3fa(0.0f,0.5f,0.0f); break; - case 5: diffuse = Vec3fa(0.0f,0.0f,0.5f); break; - - case 6: diffuse = face_colors[ray.primID]; break; - case 7: diffuse = face_colors[2*ray.primID]; break; - case 8: diffuse = Vec3fa(0.5f,0.5f,0.0f); break; - default: diffuse = Vec3fa(0.5f,0.5f,0.5f); break; - } - color = color + diffuse*0.5f; - Vec3fa lightDir = normalize(Vec3fa(-1,-4,-1)); - - /* initialize shadow ray */ - RTCRay shadow; - shadow.org = ray.org + ray.tfar*ray.dir; - shadow.dir = neg(lightDir); - shadow.tnear = 0.001f; - shadow.tfar = inf; - shadow.geomID = 1; - shadow.primID = 0; - shadow.instID = RTC_INVALID_GEOMETRY_ID; - shadow.mask = -1; - shadow.time = time; - - /* trace shadow ray */ - rtcOccluded(g_scene,shadow); - - /* add light contribution */ - if (shadow.geomID) - color = color + diffuse*clamp(-dot(lightDir,normalize(ray.Ng)),0.0f,1.0f); - } - return color; -} - -/* renders a single screen tile */ -void renderTileStandard(int taskIndex, - int* pixels, - const unsigned int width, - const unsigned int height, - const float time, - const ISPCCamera& camera, - const int numTilesX, - const int numTilesY) -{ - const unsigned int tileY = taskIndex / numTilesX; - const unsigned int tileX = taskIndex - tileY * numTilesX; - const unsigned int x0 = tileX * TILE_SIZE_X; - const unsigned int x1 = min(x0+TILE_SIZE_X,width); - const unsigned int y0 = tileY * TILE_SIZE_Y; - const unsigned int y1 = min(y0+TILE_SIZE_Y,height); - - for (unsigned int y=y0; y& range) { - for (size_t i=range.begin(); isize() == 0 && sceneFilename.ext() == "") { - FileName file = FileName::executableFolder() + FileName("models/cornell_box.ecs"); - parseCommandLine(new ParseStream(new LineCommentFilter(file, "#")), file.path()); - } - - g_instancing_mode = instancing_mode; - } - }; - -} - -int main(int argc, char** argv) { - return embree::Tutorial().main(argc,argv); -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/pathtracer/pathtracer_device.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/pathtracer/pathtracer_device.cpp deleted file mode 100644 index 21cf9e7d5180..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/pathtracer/pathtracer_device.cpp +++ /dev/null @@ -1,1627 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/math/random_sampler.h" -#include "../common/math/sampling.h" -#include "../common/core/differential_geometry.h" -#include "../common/tutorial/tutorial_device.h" -#include "../common/tutorial/scene_device.h" -#include "../common/tutorial/optics.h" - -namespace embree { - -#undef TILE_SIZE_X -#undef TILE_SIZE_Y - -#define TILE_SIZE_X 4 -#define TILE_SIZE_Y 4 - -#define FIXED_SAMPLING 0 -#define SAMPLES_PER_PIXEL 1 - -#define FIXED_EDGE_TESSELLATION_VALUE 4 - -#define ENABLE_FILTER_FUNCTION 1 - -#define MAX_EDGE_LEVEL 128.0f -#define MIN_EDGE_LEVEL 4.0f -#define LEVEL_FACTOR 64.0f -#define MAX_PATH_LENGTH 8 - -bool g_subdiv_mode = false; -unsigned int keyframeID = 0; - -struct BRDF -{ - float Ns; /*< specular exponent */ - float Ni; /*< optical density for the surface (index of refraction) */ - Vec3fa Ka; /*< ambient reflectivity */ - Vec3fa Kd; /*< diffuse reflectivity */ - Vec3fa Ks; /*< specular reflectivity */ - Vec3fa Kt; /*< transmission filter */ - float dummy[30]; -}; - -struct Medium -{ - Vec3fa transmission; //!< Transmissivity of medium. - float eta; //!< Refraction index of medium. -}; - -inline Medium make_Medium(const Vec3fa& transmission, const float eta) -{ - Medium m; - m.transmission = transmission; - m.eta = eta; - return m; -} - -inline Medium make_Medium_Vacuum() { - return make_Medium(Vec3fa((float)1.0f),1.0f); -} - -inline bool eq(const Medium& a, const Medium& b) { - return (a.eta == b.eta) && eq(a.transmission, b.transmission); -} - -inline Vec3fa sample_component2(const Vec3fa& c0, const Sample3f& wi0, const Medium& medium0, - const Vec3fa& c1, const Sample3f& wi1, const Medium& medium1, - const Vec3fa& Lw, Sample3f& wi_o, Medium& medium_o, const float s) -{ - const Vec3fa m0 = Lw*c0/wi0.pdf; - const Vec3fa m1 = Lw*c1/wi1.pdf; - - const float C0 = wi0.pdf == 0.0f ? 0.0f : max(max(m0.x,m0.y),m0.z); - const float C1 = wi1.pdf == 0.0f ? 0.0f : max(max(m1.x,m1.y),m1.z); - const float C = C0 + C1; - - if (C == 0.0f) { - wi_o = make_Sample3f(Vec3fa(0,0,0),0); - return Vec3fa(0,0,0); - } - - const float CP0 = C0/C; - const float CP1 = C1/C; - if (s < CP0) { - wi_o = make_Sample3f(wi0.v,wi0.pdf*CP0); - medium_o = medium0; return c0; - } - else { - wi_o = make_Sample3f(wi1.v,wi1.pdf*CP1); - medium_o = medium1; return c1; - } -} - -/*! Cosine weighted hemisphere sampling. Up direction is provided as argument. */ -inline Sample3f cosineSampleHemisphere(const float u, const float v, const Vec3fa& N) -{ - Vec3fa localDir = cosineSampleHemisphere(Vec2f(u,v)); - Sample3f s; - s.v = frame(N) * localDir; - s.pdf = cosineSampleHemispherePDF(localDir); - return s; -} - -//////////////////////////////////////////////////////////////////////////////// -// Minneart BRDF // -//////////////////////////////////////////////////////////////////////////////// - -struct Minneart -{ - /*! The reflectance parameter. The vale 0 means no reflection, - * and 1 means full reflection. */ - Vec3fa R; - - /*! The amount of backscattering. A value of 0 means lambertian - * diffuse, and inf means maximum backscattering. */ - float b; -}; - -inline Vec3fa Minneart__eval(const Minneart* This, - const Vec3fa &wo, const DifferentialGeometry &dg, const Vec3fa &wi) -{ - const float cosThetaI = clamp(dot(wi,dg.Ns)); - const float backScatter = powf(clamp(dot(wo,wi)), This->b); - return (backScatter * cosThetaI * float(one_over_pi)) * This->R; -} - -inline Vec3fa Minneart__sample(const Minneart* This, - const Vec3fa &wo, - const DifferentialGeometry &dg, - Sample3f &wi, - const Vec2f &s) -{ - wi = cosineSampleHemisphere(s.x,s.y,dg.Ns); - return Minneart__eval(This, wo, dg, wi.v); -} - -inline void Minneart__Constructor(Minneart* This, const Vec3fa& R, const float b) -{ - This->R = R; - This->b = b; -} - -inline Minneart make_Minneart(const Vec3fa& R, const float f) { - Minneart m; Minneart__Constructor(&m,R,f); return m; -} - -//////////////////////////////////////////////////////////////////////////////// -// Velvet BRDF // -//////////////////////////////////////////////////////////////////////////////// - -struct Velvety -{ - BRDF base; - - /*! The reflectance parameter. The vale 0 means no reflection, - * and 1 means full reflection. */ - Vec3fa R; - - /*! The falloff of horizon scattering. 0 no falloff, - * and inf means maximum falloff. */ - float f; -}; - -inline Vec3fa Velvety__eval(const Velvety* This, - const Vec3fa &wo, const DifferentialGeometry &dg, const Vec3fa &wi) -{ - const float cosThetaO = clamp(dot(wo,dg.Ns)); - const float cosThetaI = clamp(dot(wi,dg.Ns)); - const float sinThetaO = sqrt(1.0f - cosThetaO * cosThetaO); - const float horizonScatter = powf(sinThetaO, This->f); - return (horizonScatter * cosThetaI * float(one_over_pi)) * This->R; -} - -inline Vec3fa Velvety__sample(const Velvety* This, - const Vec3fa &wo, - const DifferentialGeometry &dg, - Sample3f &wi, - const Vec2f &s) -{ - wi = cosineSampleHemisphere(s.x,s.y,dg.Ns); - return Velvety__eval(This, wo, dg, wi.v); -} - -inline void Velvety__Constructor(Velvety* This, const Vec3fa& R, const float f) -{ - This->R = R; - This->f = f; -} - -inline Velvety make_Velvety(const Vec3fa& R, const float f) { - Velvety m; Velvety__Constructor(&m,R,f); return m; -} - -//////////////////////////////////////////////////////////////////////////////// -// Dielectric Reflection BRDF // -//////////////////////////////////////////////////////////////////////////////// - -struct DielectricReflection -{ - float eta; -}; - -inline Vec3fa DielectricReflection__eval(const DielectricReflection* This, const Vec3fa &wo, const DifferentialGeometry &dg, const Vec3fa &wi) { - return Vec3fa(0.f); -} - -inline Vec3fa DielectricReflection__sample(const DielectricReflection* This, const Vec3fa &wo, const DifferentialGeometry &dg, Sample3f &wi, const Vec2f &s) -{ - const float cosThetaO = clamp(dot(wo,dg.Ns)); - wi = make_Sample3f(reflect(wo,dg.Ns,cosThetaO),1.0f); - return Vec3fa(fresnelDielectric(cosThetaO,This->eta)); -} - -inline void DielectricReflection__Constructor(DielectricReflection* This, - const float etai, - const float etat) -{ - This->eta = etai*rcp(etat); -} - -inline DielectricReflection make_DielectricReflection(const float etai, const float etat) { - DielectricReflection v; DielectricReflection__Constructor(&v,etai,etat); return v; -} - -//////////////////////////////////////////////////////////////////////////////// -// Lambertian BRDF // -//////////////////////////////////////////////////////////////////////////////// - -struct Lambertian -{ - Vec3fa R; -}; - -inline Vec3fa Lambertian__eval(const Lambertian* This, - const Vec3fa &wo, const DifferentialGeometry &dg, const Vec3fa &wi) -{ - return This->R * (1.0f/(float)(float(pi))) * clamp(dot(wi,dg.Ns)); -} - -inline Vec3fa Lambertian__sample(const Lambertian* This, - const Vec3fa &wo, - const DifferentialGeometry &dg, - Sample3f &wi, - const Vec2f &s) -{ - wi = cosineSampleHemisphere(s.x,s.y,dg.Ns); - return Lambertian__eval(This, wo, dg, wi.v); -} - -inline void Lambertian__Constructor(Lambertian* This, const Vec3fa& R) -{ - This->R = R; -} - -inline Lambertian make_Lambertian(const Vec3fa& R) { - Lambertian v; Lambertian__Constructor(&v,R); return v; -} - - -//////////////////////////////////////////////////////////////////////////////// -// Lambertian BRDF with Dielectric Layer on top // -//////////////////////////////////////////////////////////////////////////////// - -struct DielectricLayerLambertian -{ - Vec3fa T; //!< Transmission coefficient of dielectricum - float etait; //!< Relative refraction index etai/etat of both media - float etati; //!< relative refraction index etat/etai of both media - Lambertian ground; //!< the BRDF of the ground layer -}; - -inline Vec3fa DielectricLayerLambertian__eval(const DielectricLayerLambertian* This, - const Vec3fa &wo, const DifferentialGeometry &dg, const Vec3fa &wi) -{ - const float cosThetaO = dot(wo,dg.Ns); - const float cosThetaI = dot(wi,dg.Ns); - if (cosThetaI <= 0.0f || cosThetaO <= 0.0f) return Vec3fa(0.f); - - float cosThetaO1; - const Sample3f wo1 = refract(wo,dg.Ns,This->etait,cosThetaO,cosThetaO1); - float cosThetaI1; - const Sample3f wi1 = refract(wi,dg.Ns,This->etait,cosThetaI,cosThetaI1); - const float Fi = 1.0f - fresnelDielectric(cosThetaI,cosThetaI1,This->etait); - const Vec3fa Fg = Lambertian__eval(&This->ground,neg(wo1.v),dg,neg(wi1.v)); - const float Fo = 1.0f - fresnelDielectric(cosThetaO,cosThetaO1,This->etait); - return Fo * This->T * Fg * This->T * Fi; -} - -inline Vec3fa DielectricLayerLambertian__sample(const DielectricLayerLambertian* This, - const Vec3fa &wo, - const DifferentialGeometry &dg, - Sample3f &wi, - const Vec2f &s) -{ - /*! refract ray into medium */ - float cosThetaO = dot(wo,dg.Ns); - if (cosThetaO <= 0.0f) { wi = make_Sample3f(Vec3fa(0.0f),0.0f); return Vec3fa(0.f); } - float cosThetaO1; Sample3f wo1 = refract(wo,dg.Ns,This->etait,cosThetaO,cosThetaO1); - - /*! sample ground BRDF */ - Sample3f wi1 = make_Sample3f(Vec3fa(0.f),1.f); - Vec3fa Fg = Lambertian__sample(&This->ground,neg(wo1.v),dg,wi1,s); - - /*! refract ray out of medium */ - float cosThetaI1 = dot(wi1.v,dg.Ns); - if (cosThetaI1 <= 0.0f) { wi = make_Sample3f(Vec3fa(0.0f),0.0f); return Vec3fa(0.f); } - - float cosThetaI; - Sample3f wi0 = refract(neg(wi1.v),neg(dg.Ns),This->etati,cosThetaI1,cosThetaI); - if (wi0.pdf == 0.0f) { wi = make_Sample3f(Vec3fa(0.0f),0.0f); return Vec3fa(0.f); } - - /*! accumulate contribution of path */ - wi = make_Sample3f(wi0.v,wi1.pdf); - float Fi = 1.0f - fresnelDielectric(cosThetaI,cosThetaI1,This->etait); - float Fo = 1.0f - fresnelDielectric(cosThetaO,cosThetaO1,This->etait); - return Fo * This->T * Fg * This->T * Fi; -} - -inline void DielectricLayerLambertian__Constructor(DielectricLayerLambertian* This, - const Vec3fa& T, - const float etai, - const float etat, - const Lambertian& ground) -{ - This->T = T; - This->etait = etai*rcp(etat); - This->etati = etat*rcp(etai); - This->ground = ground; -} - -inline DielectricLayerLambertian make_DielectricLayerLambertian(const Vec3fa& T, - const float etai, - const float etat, - const Lambertian& ground) -{ - DielectricLayerLambertian m; - DielectricLayerLambertian__Constructor(&m,T,etai,etat,ground); - return m; -} - -/*! Anisotropic power cosine microfacet distribution. */ -struct AnisotropicBlinn { - Vec3fa dx; //!< x-direction of the distribution. - Vec3fa dy; //!< y-direction of the distribution. - Vec3fa dz; //!< z-direction of the distribution. - Vec3fa Kr,Kt; - float nx; //!< Glossiness in x direction with range [0,infinity[ where 0 is a diffuse surface. - float ny; //!< Exponent that determines the glossiness in y direction. - float norm1; //!< Normalization constant for calculating the pdf for sampling. - float norm2; //!< Normalization constant for calculating the distribution. - float side; -}; - - /*! Anisotropic power cosine distribution constructor. */ -inline void AnisotropicBlinn__Constructor(AnisotropicBlinn* This, const Vec3fa& Kr, const Vec3fa& Kt, - const Vec3fa& dx, float nx, const Vec3fa& dy, float ny, const Vec3fa& dz) -{ - This->Kr = Kr; - This->Kt = Kt; - This->dx = dx; - This->nx = nx; - This->dy = dy; - This->ny = ny; - This->dz = dz; - This->norm1 = sqrtf((nx+1)*(ny+1)) * float(one_over_two_pi); - This->norm2 = sqrtf((nx+2)*(ny+2)) * float(one_over_two_pi); - This->side = reduce_max(Kr)/(reduce_max(Kr)+reduce_max(Kt)); -} - -/*! Evaluates the power cosine distribution. \param wh is the half - * vector */ -inline float AnisotropicBlinn__eval(const AnisotropicBlinn* This, const Vec3fa& wh) -{ - const float cosPhiH = dot(wh, This->dx); - const float sinPhiH = dot(wh, This->dy); - const float cosThetaH = dot(wh, This->dz); - const float R = sqr(cosPhiH)+sqr(sinPhiH); - if (R == 0.0f) return This->norm2; - const float n = (This->nx*sqr(cosPhiH)+This->ny*sqr(sinPhiH))*rcp(R); - return This->norm2 * powf(abs(cosThetaH), n); -} - -/*! Samples the distribution. \param s is the sample location - * provided by the caller. */ -inline Vec3fa AnisotropicBlinn__sample(const AnisotropicBlinn* This, const float sx, const float sy) -{ - const float phi =float(two_pi)*sx; - const float sinPhi0 = sqrtf(This->nx+1)*sinf(phi); - const float cosPhi0 = sqrtf(This->ny+1)*cosf(phi); - const float norm = rsqrt(sqr(sinPhi0)+sqr(cosPhi0)); - const float sinPhi = sinPhi0*norm; - const float cosPhi = cosPhi0*norm; - const float n = This->nx*sqr(cosPhi)+This->ny*sqr(sinPhi); - const float cosTheta = powf(sy,rcp(n+1)); - const float sinTheta = cos2sin(cosTheta); - const float pdf = This->norm1*powf(cosTheta,n); - const Vec3fa h = Vec3fa(cosPhi * sinTheta, sinPhi * sinTheta, cosTheta); - const Vec3fa wh = h.x*This->dx + h.y*This->dy + h.z*This->dz; - return Vec3fa(wh,pdf); -} - -inline Vec3fa AnisotropicBlinn__eval(const AnisotropicBlinn* This, const Vec3fa& wo, const Vec3fa& wi) -{ - const float cosThetaI = dot(wi,This->dz); - - /* reflection */ - if (cosThetaI > 0.0f) { - const Vec3fa wh = normalize(wi + wo); - return This->Kr * AnisotropicBlinn__eval(This,wh) * abs(cosThetaI); - } - - /* transmission */ - else { - const Vec3fa wh = normalize(reflect(wi,This->dz) + wo); - return This->Kt * AnisotropicBlinn__eval(This,wh) * abs(cosThetaI); - } -} - -inline Vec3fa AnisotropicBlinn__sample(const AnisotropicBlinn* This, const Vec3fa& wo, Sample3f& wi_o, const float sx, const float sy, const float sz) -{ - //wi = Vec3fa(reflect(normalize(wo),normalize(dz)),1.0f); return Kr; - //wi = Vec3fa(neg(wo),1.0f); return Kt; - const Vec3fa wh = AnisotropicBlinn__sample(This,sx,sy); - //if (dot(wo,wh) < 0.0f) return Vec3fa(0.0f,0.0f); - - /* reflection */ - if (sz < This->side) { - wi_o = make_Sample3f(reflect(wo,Vec3fa(wh)),wh.w*This->side); - const float cosThetaI = dot(wi_o.v,This->dz); - return This->Kr * AnisotropicBlinn__eval(This,Vec3fa(wh)) * abs(cosThetaI); - } - - /* transmission */ - else { - wi_o = make_Sample3f(reflect(reflect(wo,Vec3fa(wh)),This->dz),wh.w*(1-This->side)); - const float cosThetaI = dot(wi_o.v,This->dz); - return This->Kt * AnisotropicBlinn__eval(This,Vec3fa(wh)) * abs(cosThetaI); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Matte Material // -//////////////////////////////////////////////////////////////////////////////// - -void MatteMaterial__preprocess(MatteMaterial* material, BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Medium& medium) -{ -} - -Vec3fa MatteMaterial__eval(MatteMaterial* This, const BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Vec3fa& wi) -{ - Lambertian lambertian = make_Lambertian(Vec3fa((Vec3fa)This->reflectance)); - return Lambertian__eval(&lambertian,wo,dg,wi); -} - -Vec3fa MatteMaterial__sample(MatteMaterial* This, const BRDF& brdf, const Vec3fa& Lw, const Vec3fa& wo, const DifferentialGeometry& dg, Sample3f& wi_o, Medium& medium, const Vec2f& s) -{ - Lambertian lambertian = make_Lambertian(Vec3fa((Vec3fa)This->reflectance)); - return Lambertian__sample(&lambertian,wo,dg,wi_o,s); -} - -//////////////////////////////////////////////////////////////////////////////// -// Mirror Material // -//////////////////////////////////////////////////////////////////////////////// - -void MirrorMaterial__preprocess(MirrorMaterial* material, BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Medium& medium) -{ -} - -Vec3fa MirrorMaterial__eval(MirrorMaterial* This, const BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Vec3fa& wi) { - return Vec3fa(0.0f); -} - -Vec3fa MirrorMaterial__sample(MirrorMaterial* This, const BRDF& brdf, const Vec3fa& Lw, const Vec3fa& wo, const DifferentialGeometry& dg, Sample3f& wi_o, Medium& medium, const Vec2f& s) -{ - wi_o = make_Sample3f(reflect(wo,dg.Ns),1.0f); - return Vec3fa(This->reflectance); -} - -//////////////////////////////////////////////////////////////////////////////// -// OBJ Material // -//////////////////////////////////////////////////////////////////////////////// - -void OBJMaterial__preprocess(OBJMaterial* material, BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Medium& medium) -{ - float d = material->d; - if (material->map_d) d *= getTextureTexel1f(material->map_d,dg.u,dg.v); - brdf.Ka = Vec3fa(material->Ka); - //if (material->map_Ka) { brdf.Ka *= material->map_Ka->get(dg.st); } - brdf.Kd = d * Vec3fa(material->Kd); - if (material->map_Kd) brdf.Kd = brdf.Kd * getTextureTexel3f(material->map_Kd,dg.u,dg.v); - brdf.Ks = d * Vec3fa(material->Ks); - //if (material->map_Ks) brdf.Ks *= material->map_Ks->get(dg.st); - brdf.Ns = material->Ns; - //if (material->map_Ns) { brdf.Ns *= material->map_Ns.get(dg.st); } - brdf.Kt = (1.0f-d)*Vec3fa(material->Kt); - brdf.Ni = material->Ni; -} - -Vec3fa OBJMaterial__eval(OBJMaterial* material, const BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Vec3fa& wi) -{ - Vec3fa R = Vec3fa(0.0f); - const float Md = max(max(brdf.Kd.x,brdf.Kd.y),brdf.Kd.z); - const float Ms = max(max(brdf.Ks.x,brdf.Ks.y),brdf.Ks.z); - const float Mt = max(max(brdf.Kt.x,brdf.Kt.y),brdf.Kt.z); - if (Md > 0.0f) { - R = R + (1.0f/float(pi)) * clamp(dot(wi,dg.Ns)) * brdf.Kd; - } - if (Ms > 0.0f) { - const Sample3f refl = make_Sample3f(reflect(wo,dg.Ns),1.0f); - if (dot(refl.v,wi) > 0.0f) - R = R + (brdf.Ns+2) * float(one_over_two_pi) * powf(max(1e-10f,dot(refl.v,wi)),brdf.Ns) * clamp(dot(wi,dg.Ns)) * brdf.Ks; - } - if (Mt > 0.0f) { - } - return R; -} - -Vec3fa OBJMaterial__sample(OBJMaterial* material, const BRDF& brdf, const Vec3fa& Lw, const Vec3fa& wo, const DifferentialGeometry& dg, Sample3f& wi_o, Medium& medium, const Vec2f& s) -{ - Vec3fa cd = Vec3fa(0.0f); - Sample3f wid = make_Sample3f(Vec3fa(0.0f),0.0f); - if (max(max(brdf.Kd.x,brdf.Kd.y),brdf.Kd.z) > 0.0f) { - wid = cosineSampleHemisphere(s.x,s.y,dg.Ns); - cd = float(one_over_pi) * clamp(dot(wid.v,dg.Ns)) * brdf.Kd; - } - - Vec3fa cs = Vec3fa(0.0f); - Sample3f wis = make_Sample3f(Vec3fa(0.0f),0.0f); - if (max(max(brdf.Ks.x,brdf.Ks.y),brdf.Ks.z) > 0.0f) - { - const Sample3f refl = make_Sample3f(reflect(wo,dg.Ns),1.0f); - wis.v = powerCosineSampleHemisphere(brdf.Ns,s); - wis.pdf = powerCosineSampleHemispherePDF(wis.v,brdf.Ns); - wis.v = frame(refl.v) * wis.v; - cs = (brdf.Ns+2) * float(one_over_two_pi) * powf(max(dot(refl.v,wis.v),1e-10f),brdf.Ns) * clamp(dot(wis.v,dg.Ns)) * brdf.Ks; - } - - Vec3fa ct = Vec3fa(0.0f); - Sample3f wit = make_Sample3f(Vec3fa(0.0f),0.0f); - if (max(max(brdf.Kt.x,brdf.Kt.y),brdf.Kt.z) > 0.0f) - { - wit = make_Sample3f(neg(wo),1.0f); - ct = brdf.Kt; - } - - const Vec3fa md = Lw*cd/wid.pdf; - const Vec3fa ms = Lw*cs/wis.pdf; - const Vec3fa mt = Lw*ct/wit.pdf; - - const float Cd = wid.pdf == 0.0f ? 0.0f : max(max(md.x,md.y),md.z); - const float Cs = wis.pdf == 0.0f ? 0.0f : max(max(ms.x,ms.y),ms.z); - const float Ct = wit.pdf == 0.0f ? 0.0f : max(max(mt.x,mt.y),mt.z); - const float C = Cd + Cs + Ct; - - if (C == 0.0f) { - wi_o = make_Sample3f(Vec3fa(0,0,0),0); - return Vec3fa(0,0,0); - } - - const float CPd = Cd/C; - const float CPs = Cs/C; - const float CPt = Ct/C; - - if (s.x < CPd) { - wi_o = make_Sample3f(wid.v,wid.pdf*CPd); - return cd; - } - else if (s.x < CPd + CPs) - { - wi_o = make_Sample3f(wis.v,wis.pdf*CPs); - return cs; - } - else - { - wi_o = make_Sample3f(wit.v,wit.pdf*CPt); - return ct; - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Metal Material // -//////////////////////////////////////////////////////////////////////////////// - -void MetalMaterial__preprocess(MetalMaterial* material, BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Medium& medium) -{ -} - -Vec3fa MetalMaterial__eval(MetalMaterial* This, const BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Vec3fa& wi) -{ - const FresnelConductor fresnel = make_FresnelConductor(Vec3fa(This->eta),Vec3fa(This->k)); - const PowerCosineDistribution distribution = make_PowerCosineDistribution(rcp(This->roughness)); - - const float cosThetaO = dot(wo,dg.Ns); - const float cosThetaI = dot(wi,dg.Ns); - if (cosThetaI <= 0.0f || cosThetaO <= 0.0f) return Vec3fa(0.f); - const Vec3fa wh = normalize(wi+wo); - const float cosThetaH = dot(wh, dg.Ns); - const float cosTheta = dot(wi, wh); // = dot(wo, wh); - const Vec3fa F = eval(fresnel,cosTheta); - const float D = eval(distribution,cosThetaH); - const float G = min(1.0f, min(2.0f * cosThetaH * cosThetaO / cosTheta, - 2.0f * cosThetaH * cosThetaI / cosTheta)); - return (Vec3fa(This->reflectance)*F) * D * G * rcp(4.0f*cosThetaO); -} - -Vec3fa MetalMaterial__sample(MetalMaterial* This, const BRDF& brdf, const Vec3fa& Lw, const Vec3fa& wo, const DifferentialGeometry& dg, Sample3f& wi_o, Medium& medium, const Vec2f& s) -{ - const PowerCosineDistribution distribution = make_PowerCosineDistribution(rcp(This->roughness)); - - if (dot(wo,dg.Ns) <= 0.0f) { wi_o = make_Sample3f(Vec3fa(0.0f),0.0f); return Vec3fa(0.f); } - sample(distribution,wo,dg.Ns,wi_o,s); - if (dot(wi_o.v,dg.Ns) <= 0.0f) { wi_o = make_Sample3f(Vec3fa(0.0f),0.0f); return Vec3fa(0.f); } - return MetalMaterial__eval(This,brdf,wo,dg,wi_o.v); -} - -//////////////////////////////////////////////////////////////////////////////// -// ReflectiveMetal Material // -//////////////////////////////////////////////////////////////////////////////// - -void ReflectiveMetalMaterial__preprocess(ReflectiveMetalMaterial* material, BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Medium& medium) { -} - -Vec3fa ReflectiveMetalMaterial__eval(ReflectiveMetalMaterial* This, const BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Vec3fa& wi) { - return Vec3fa(0.0f); -} - -Vec3fa ReflectiveMetalMaterial__sample(ReflectiveMetalMaterial* This, const BRDF& brdf, const Vec3fa& Lw, const Vec3fa& wo, const DifferentialGeometry& dg, Sample3f& wi_o, Medium& medium, const Vec2f& s) -{ - wi_o = make_Sample3f(reflect(wo,dg.Ns),1.0f); - return Vec3fa(This->reflectance) * fresnelConductor(dot(wo,dg.Ns),Vec3fa((Vec3fa)This->eta),Vec3fa((Vec3fa)This->k)); -} - -//////////////////////////////////////////////////////////////////////////////// -// Velvet Material // -//////////////////////////////////////////////////////////////////////////////// - -void VelvetMaterial__preprocess(VelvetMaterial* material, BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Medium& medium) -{ -} - -Vec3fa VelvetMaterial__eval(VelvetMaterial* This, const BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Vec3fa& wi) -{ - Minneart minneart; Minneart__Constructor(&minneart,(Vec3fa)Vec3fa(This->reflectance),This->backScattering); - Velvety velvety; Velvety__Constructor (&velvety,Vec3fa((Vec3fa)This->horizonScatteringColor),This->horizonScatteringFallOff); - return Minneart__eval(&minneart,wo,dg,wi) + Velvety__eval(&velvety,wo,dg,wi); -} - -Vec3fa VelvetMaterial__sample(VelvetMaterial* This, const BRDF& brdf, const Vec3fa& Lw, const Vec3fa& wo, const DifferentialGeometry& dg, Sample3f& wi_o, Medium& medium, const Vec2f& s) -{ - Minneart minneart; Minneart__Constructor(&minneart,Vec3fa((Vec3fa)This->reflectance),This->backScattering); - Velvety velvety; Velvety__Constructor (&velvety,Vec3fa((Vec3fa)This->horizonScatteringColor),This->horizonScatteringFallOff); - - Sample3f wi0; Vec3fa c0 = Minneart__sample(&minneart,wo,dg,wi0,s); - Sample3f wi1; Vec3fa c1 = Velvety__sample(&velvety,wo,dg,wi1,s); - return sample_component2(c0,wi0,medium,c1,wi1,medium,Lw,wi_o,medium,s.x); -} - -//////////////////////////////////////////////////////////////////////////////// -// Dielectric Material // -//////////////////////////////////////////////////////////////////////////////// - -void DielectricMaterial__preprocess(DielectricMaterial* material, BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Medium& medium) -{ -} - -Vec3fa DielectricMaterial__eval(DielectricMaterial* material, const BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Vec3fa& wi) { - return Vec3fa(0.0f); -} - -Vec3fa DielectricMaterial__sample(DielectricMaterial* material, const BRDF& brdf, const Vec3fa& Lw, const Vec3fa& wo, const DifferentialGeometry& dg, Sample3f& wi_o, Medium& medium, const Vec2f& s) -{ - float eta = 0.0f; - Medium mediumOutside = make_Medium(Vec3fa((Vec3fa)material->transmissionOutside),material->etaOutside); - Medium mediumInside = make_Medium(Vec3fa((Vec3fa)material->transmissionInside ),material->etaInside ); - Medium mediumFront, mediumBack; - if (eq(medium,mediumInside)) { - eta = material->etaInside/material->etaOutside; - mediumFront = mediumInside; - mediumBack = mediumOutside; - } - else { - eta = material->etaOutside/material->etaInside; - mediumFront = mediumOutside; - mediumBack = mediumInside; - } - - float cosThetaO = clamp(dot(wo,dg.Ns)); - float cosThetaI; Sample3f wit = refract(wo,dg.Ns,eta,cosThetaO,cosThetaI); - Sample3f wis = make_Sample3f(reflect(wo,dg.Ns),1.0f); - float R = fresnelDielectric(cosThetaO,cosThetaI,eta); - Vec3fa cs = Vec3fa(R); - Vec3fa ct = Vec3fa(1.0f-R); - return sample_component2(cs,wis,mediumFront,ct,wit,mediumBack,Lw,wi_o,medium,s.x); -} - -//////////////////////////////////////////////////////////////////////////////// -// ThinDielectric Material // -//////////////////////////////////////////////////////////////////////////////// - -void ThinDielectricMaterial__preprocess(ThinDielectricMaterial* This, BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Medium& medium) -{ -} - -Vec3fa ThinDielectricMaterial__eval(ThinDielectricMaterial* This, const BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Vec3fa& wi) { - return Vec3fa(0.0f); -} - -Vec3fa ThinDielectricMaterial__sample(ThinDielectricMaterial* This, const BRDF& brdf, const Vec3fa& Lw, const Vec3fa& wo, const DifferentialGeometry& dg, Sample3f& wi_o, Medium& medium, const Vec2f& s) -{ - float cosThetaO = clamp(dot(wo,dg.Ns)); - if (cosThetaO <= 0.0f) return Vec3fa(0.0f); - float R = fresnelDielectric(cosThetaO,rcp(This->eta)); - Sample3f wit = make_Sample3f(neg(wo),1.0f); - Sample3f wis = make_Sample3f(reflect(wo,dg.Ns),1.0f); - Vec3fa ct = exp(Vec3fa(This->transmissionFactor)*rcp(cosThetaO))*Vec3fa(1.0f-R); - Vec3fa cs = Vec3fa(R); - return sample_component2(cs,wis,medium,ct,wit,medium,Lw,wi_o,medium,s.x); -} - -//////////////////////////////////////////////////////////////////////////////// -// MetallicPaint Material // -//////////////////////////////////////////////////////////////////////////////// - -void MetallicPaintMaterial__preprocess(MetallicPaintMaterial* material, BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Medium& medium) -{ -} - -Vec3fa MetallicPaintMaterial__eval(MetallicPaintMaterial* This, const BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Vec3fa& wi) -{ - DielectricReflection reflection; DielectricReflection__Constructor(&reflection, 1.0f, This->eta); - DielectricLayerLambertian lambertian; DielectricLayerLambertian__Constructor(&lambertian, Vec3fa((float)1.0f), 1.0f, This->eta, make_Lambertian(Vec3fa((Vec3fa)This->shadeColor))); - return DielectricReflection__eval(&reflection,wo,dg,wi) + DielectricLayerLambertian__eval(&lambertian,wo,dg,wi); -} - -Vec3fa MetallicPaintMaterial__sample(MetallicPaintMaterial* This, const BRDF& brdf, const Vec3fa& Lw, const Vec3fa& wo, const DifferentialGeometry& dg, Sample3f& wi_o, Medium& medium, const Vec2f& s) -{ - DielectricReflection reflection; DielectricReflection__Constructor(&reflection, 1.0f, This->eta); - DielectricLayerLambertian lambertian; DielectricLayerLambertian__Constructor(&lambertian, Vec3fa((float)1.0f), 1.0f, This->eta, make_Lambertian(Vec3fa((Vec3fa)This->shadeColor))); - Sample3f wi0; Vec3fa c0 = DielectricReflection__sample(&reflection,wo,dg,wi0,s); - Sample3f wi1; Vec3fa c1 = DielectricLayerLambertian__sample(&lambertian,wo,dg,wi1,s); - return sample_component2(c0,wi0,medium,c1,wi1,medium,Lw,wi_o,medium,s.x); -} - -//////////////////////////////////////////////////////////////////////////////// -// Hair Material // -//////////////////////////////////////////////////////////////////////////////// - -void HairMaterial__preprocess(HairMaterial* This, BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Medium& medium) -{ - AnisotropicBlinn__Constructor((AnisotropicBlinn*)&brdf,Vec3fa(This->Kr),Vec3fa(This->Kt),dg.Tx,(float)This->nx,dg.Ty,(float)This->ny,dg.Ng); -} - -Vec3fa HairMaterial__eval(HairMaterial* This, const BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Vec3fa& wi) -{ - return AnisotropicBlinn__eval((AnisotropicBlinn*)&brdf,wo,wi); -} - -Vec3fa HairMaterial__sample(HairMaterial* This, const BRDF& brdf, const Vec3fa& Lw, const Vec3fa& wo, const DifferentialGeometry& dg, Sample3f& wi_o, Medium& medium, const Vec2f& s) -{ - return AnisotropicBlinn__sample((AnisotropicBlinn*)&brdf,wo,wi_o,s.x,s.y,s.x); -} - -//////////////////////////////////////////////////////////////////////////////// -// Material // -//////////////////////////////////////////////////////////////////////////////// - -inline void Material__preprocess(ISPCMaterial* materials, unsigned int materialID, unsigned int numMaterials, BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Medium& medium) -{ - unsigned int id = materialID; - { - if (id < numMaterials) // FIXME: workaround for ISPC bug, location reached with empty execution mask - { - ISPCMaterial* material = &materials[id]; - - switch (material->ty) { - case MATERIAL_OBJ : OBJMaterial__preprocess ((OBJMaterial*) material,brdf,wo,dg,medium); break; - case MATERIAL_METAL: MetalMaterial__preprocess((MetalMaterial*)material,brdf,wo,dg,medium); break; - case MATERIAL_REFLECTIVE_METAL: ReflectiveMetalMaterial__preprocess((ReflectiveMetalMaterial*)material,brdf,wo,dg,medium); break; - case MATERIAL_VELVET: VelvetMaterial__preprocess((VelvetMaterial*)material,brdf,wo,dg,medium); break; - case MATERIAL_DIELECTRIC: DielectricMaterial__preprocess((DielectricMaterial*)material,brdf,wo,dg,medium); break; - case MATERIAL_METALLIC_PAINT: MetallicPaintMaterial__preprocess((MetallicPaintMaterial*)material,brdf,wo,dg,medium); break; - case MATERIAL_MATTE: MatteMaterial__preprocess((MatteMaterial*)material,brdf,wo,dg,medium); break; - case MATERIAL_MIRROR: MirrorMaterial__preprocess((MirrorMaterial*)material,brdf,wo,dg,medium); break; - case MATERIAL_THIN_DIELECTRIC: ThinDielectricMaterial__preprocess((ThinDielectricMaterial*)material,brdf,wo,dg,medium); break; - case MATERIAL_HAIR: HairMaterial__preprocess((HairMaterial*)material,brdf,wo,dg,medium); break; - default: break; - } - } - } -} - -inline Vec3fa Material__eval(ISPCMaterial* materials, unsigned int materialID, unsigned int numMaterials, const BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Vec3fa& wi) -{ - Vec3fa c = Vec3fa(0.0f); - unsigned int id = materialID; - { - if (id < numMaterials) // FIXME: workaround for ISPC bug, location reached with empty execution mask - { - ISPCMaterial* material = &materials[id]; - switch (material->ty) { - case MATERIAL_OBJ : c = OBJMaterial__eval ((OBJMaterial*) material, brdf, wo, dg, wi); break; - case MATERIAL_METAL: c = MetalMaterial__eval((MetalMaterial*)material, brdf, wo, dg, wi); break; - case MATERIAL_REFLECTIVE_METAL: c = ReflectiveMetalMaterial__eval((ReflectiveMetalMaterial*)material, brdf, wo, dg, wi); break; - case MATERIAL_VELVET: c = VelvetMaterial__eval((VelvetMaterial*)material, brdf, wo, dg, wi); break; - case MATERIAL_DIELECTRIC: c = DielectricMaterial__eval((DielectricMaterial*)material, brdf, wo, dg, wi); break; - case MATERIAL_METALLIC_PAINT: c = MetallicPaintMaterial__eval((MetallicPaintMaterial*)material, brdf, wo, dg, wi); break; - case MATERIAL_MATTE: c = MatteMaterial__eval((MatteMaterial*)material, brdf, wo, dg, wi); break; - case MATERIAL_MIRROR: c = MirrorMaterial__eval((MirrorMaterial*)material, brdf, wo, dg, wi); break; - case MATERIAL_THIN_DIELECTRIC: c = ThinDielectricMaterial__eval((ThinDielectricMaterial*)material, brdf, wo, dg, wi); break; - case MATERIAL_HAIR: c = HairMaterial__eval((HairMaterial*)material, brdf, wo, dg, wi); break; - default: c = Vec3fa(0.0f); - } - } - } - return c; -} - -inline Vec3fa Material__sample(ISPCMaterial* materials, unsigned int materialID, unsigned int numMaterials, const BRDF& brdf, const Vec3fa& Lw, const Vec3fa& wo, const DifferentialGeometry& dg, Sample3f& wi_o, Medium& medium, const Vec2f& s) -{ - Vec3fa c = Vec3fa(0.0f); - unsigned int id = materialID; - { - if (id < numMaterials) // FIXME: workaround for ISPC bug, location reached with empty execution mask - { - ISPCMaterial* material = &materials[id]; - switch (material->ty) { - case MATERIAL_OBJ : c = OBJMaterial__sample ((OBJMaterial*) material, brdf, Lw, wo, dg, wi_o, medium, s); break; - case MATERIAL_METAL: c = MetalMaterial__sample((MetalMaterial*)material, brdf, Lw, wo, dg, wi_o, medium, s); break; - case MATERIAL_REFLECTIVE_METAL: c = ReflectiveMetalMaterial__sample((ReflectiveMetalMaterial*)material, brdf, Lw, wo, dg, wi_o, medium, s); break; - case MATERIAL_VELVET: c = VelvetMaterial__sample((VelvetMaterial*)material, brdf, Lw, wo, dg, wi_o, medium, s); break; - case MATERIAL_DIELECTRIC: c = DielectricMaterial__sample((DielectricMaterial*)material, brdf, Lw, wo, dg, wi_o, medium, s); break; - case MATERIAL_METALLIC_PAINT: c = MetallicPaintMaterial__sample((MetallicPaintMaterial*)material, brdf, Lw, wo, dg, wi_o, medium, s); break; - case MATERIAL_MATTE: c = MatteMaterial__sample((MatteMaterial*)material, brdf, Lw, wo, dg, wi_o, medium, s); break; - case MATERIAL_MIRROR: c = MirrorMaterial__sample((MirrorMaterial*)material, brdf, Lw, wo, dg, wi_o, medium, s); break; - case MATERIAL_THIN_DIELECTRIC: c = ThinDielectricMaterial__sample((ThinDielectricMaterial*)material, brdf, Lw, wo, dg, wi_o, medium, s); break; - case MATERIAL_HAIR: c = HairMaterial__sample((HairMaterial*)material, brdf, Lw, wo, dg, wi_o, medium, s); break; - default: wi_o = make_Sample3f(Vec3fa(0.0f),0.0f); c = Vec3fa(0.0f); break; - } - } - } - return c; -} - - -//////////////////////////////////////////////////////////////////////////////// -// Scene // -//////////////////////////////////////////////////////////////////////////////// - -/* scene data */ -extern "C" ISPCScene* g_ispc_scene; -RTCDevice g_device = nullptr; -RTCScene g_scene = nullptr; -extern "C" RTCScene* geomID_to_scene; -extern "C" ISPCInstance** geomID_to_inst; - -/* occlusion filter function */ -void intersectionFilterReject(void* ptr, RTCRay& ray); -void intersectionFilterOBJ(void* ptr, RTCRay& ray); -void occlusionFilterOpaque(void* ptr, RTCRay& ray); -void occlusionFilterOBJ(void* ptr, RTCRay& ray); -void occlusionFilterHair(void* ptr, RTCRay& ray); - -/* accumulation buffer */ -Vec3fa* g_accu = nullptr; -unsigned int g_accu_width = 0; -unsigned int g_accu_height = 0; -unsigned int g_accu_count = 0; -Vec3fa g_accu_vx; -Vec3fa g_accu_vy; -Vec3fa g_accu_vz; -Vec3fa g_accu_p; -extern "C" bool g_changed; -extern "C" int g_instancing_mode; - - -bool g_animation = true; -bool g_use_smooth_normals = false; -void device_key_pressed_handler(int key) -{ - if (key == 32 /* */) g_animation = !g_animation; - if (key == 115 /*s*/) { g_use_smooth_normals = !g_use_smooth_normals; g_changed = true; } - else device_key_pressed_default(key); -} - -void assignShaders(ISPCGeometry* geometry) -{ - if (geometry->type == SUBDIV_MESH) { - ISPCSubdivMesh* mesh = (ISPCSubdivMesh* ) geometry; -#if ENABLE_FILTER_FUNCTION == 1 - rtcSetOcclusionFilterFunction(mesh->scene,mesh->geomID,(RTCFilterFunc)&occlusionFilterOpaque); -#endif - } - else if (geometry->type == TRIANGLE_MESH) { - ISPCTriangleMesh* mesh = (ISPCTriangleMesh* ) geometry; -#if ENABLE_FILTER_FUNCTION == 1 - rtcSetOcclusionFilterFunction(mesh->scene,mesh->geomID,(RTCFilterFunc)&occlusionFilterOpaque); - - ISPCMaterial& material = g_ispc_scene->materials[mesh->materialID]; - //if (material.ty == MATERIAL_DIELECTRIC || material.ty == MATERIAL_THIN_DIELECTRIC) - // rtcSetOcclusionFilterFunction(mesh->scene,mesh->geomID,(RTCFilterFunc)&intersectionFilterReject); - //else - if (material.ty == MATERIAL_OBJ) - { - OBJMaterial& obj = (OBJMaterial&) material; - if (obj.d != 1.0f || obj.map_d) { - rtcSetIntersectionFilterFunction(mesh->scene,mesh->geomID,(RTCFilterFunc)&intersectionFilterOBJ); - rtcSetOcclusionFilterFunction (mesh->scene,mesh->geomID,(RTCFilterFunc)&occlusionFilterOBJ); - } - } -#endif - } - else if (geometry->type == QUAD_MESH) { - ISPCQuadMesh* mesh = (ISPCQuadMesh*) geometry; -#if ENABLE_FILTER_FUNCTION == 1 - rtcSetOcclusionFilterFunction(mesh->scene,mesh->geomID,(RTCFilterFunc)&occlusionFilterOpaque); - - ISPCMaterial& material = g_ispc_scene->materials[mesh->materialID]; - //if (material.ty == MATERIAL_DIELECTRIC || material.ty == MATERIAL_THIN_DIELECTRIC) - // rtcSetOcclusionFilterFunction(mesh->scene,mesh->geomID,(RTCFilterFunc)&intersectionFilterReject); - //else - if (material.ty == MATERIAL_OBJ) - { - OBJMaterial& obj = (OBJMaterial&) material; - if (obj.d != 1.0f || obj.map_d) { - rtcSetIntersectionFilterFunction(mesh->scene,mesh->geomID,(RTCFilterFunc)&intersectionFilterOBJ); - rtcSetOcclusionFilterFunction (mesh->scene,mesh->geomID,(RTCFilterFunc)&occlusionFilterOBJ); - } - } -#endif - } - else if (geometry->type == LINE_SEGMENTS) { - ISPCLineSegments* mesh = (ISPCLineSegments*) geometry; - rtcSetOcclusionFilterFunction(mesh->scene,mesh->geomID,(RTCFilterFunc)&occlusionFilterHair); - } - else if (geometry->type == HAIR_SET) { - ISPCHairSet* mesh = (ISPCHairSet*) geometry; - rtcSetOcclusionFilterFunction(mesh->scene,mesh->geomID,(RTCFilterFunc)&occlusionFilterHair); - } - else if (geometry->type == CURVES) { - ISPCHairSet* mesh = (ISPCHairSet*) geometry; - rtcSetOcclusionFilterFunction(mesh->scene,mesh->geomID,(RTCFilterFunc)&occlusionFilterHair); - } - else if (geometry->type == GROUP) { - ISPCGroup* group = (ISPCGroup*) geometry; - for (size_t i=0; inumGeometries; i++) - assignShaders(group->geometries[i]); - } -} - -typedef ISPCInstance* ISPCInstance_ptr; -typedef ISPCGeometry* ISPCGeometry_ptr; - -RTCScene convertScene(ISPCScene* scene_in) -{ - for (size_t i=0; inumGeometries; i++) - { - ISPCGeometry* geometry = scene_in->geometries[i]; - if (geometry->type == SUBDIV_MESH) { - g_subdiv_mode = true; break; - } - } - - /* create scene */ - int scene_flags = RTC_SCENE_STATIC | RTC_SCENE_INCOHERENT; - int scene_aflags = RTC_INTERSECT1; - - if (g_subdiv_mode) - scene_flags = RTC_SCENE_DYNAMIC | RTC_SCENE_INCOHERENT | RTC_SCENE_ROBUST; - - scene_aflags |= RTC_INTERPOLATE; - - RTCScene scene_out = ConvertScene(g_device, g_ispc_scene,(RTCSceneFlags)scene_flags, (RTCAlgorithmFlags) scene_aflags, RTC_GEOMETRY_STATIC); - - /* assign shaders */ - for (unsigned int i=0; inumGeometries; i++) { - assignShaders(scene_in->geometries[i]); - } - - /* commit individual objects in case of instancing */ - if (g_instancing_mode == 2 || g_instancing_mode == 3) - { - for (unsigned int i=0; inumGeometries; i++) { - if (geomID_to_scene[i]) rtcCommit(geomID_to_scene[i]); - } - } - - /* commit changes to scene */ - progressStart(); - rtcSetProgressMonitorFunction(scene_out,(RTCProgressMonitorFunc)&progressMonitor,nullptr); - rtcCommit (scene_out); - rtcSetProgressMonitorFunction(scene_out,nullptr,nullptr); - progressEnd(); - - return scene_out; -} // convertScene - -inline Vec3fa face_forward(const Vec3fa& dir, const Vec3fa& _Ng) { - const Vec3fa Ng = _Ng; - return dot(dir,Ng) < 0.0f ? Ng : neg(Ng); -} - -inline void evalBezier(const ISPCHairSet* hair, const int primID, const float t, Vec3fa& p, Vec3fa& dp) -{ - const float t0 = 1.0f - t, t1 = t; - const Vec3fa* vertices = hair->positions; - const ISPCHair* hairs = hair->hairs; - - const int i = hairs[primID].vertex; - const Vec3fa p00 = vertices[i+0]; - const Vec3fa p01 = vertices[i+1]; - const Vec3fa p02 = vertices[i+2]; - const Vec3fa p03 = vertices[i+3]; - - const Vec3fa p10 = p00 * t0 + p01 * t1; - const Vec3fa p11 = p01 * t0 + p02 * t1; - const Vec3fa p12 = p02 * t0 + p03 * t1; - const Vec3fa p20 = p10 * t0 + p11 * t1; - const Vec3fa p21 = p11 * t0 + p12 * t1; - const Vec3fa p30 = p20 * t0 + p21 * t1; - - p = p30; - dp = 3.0f*(p21-p20); -} - -void postIntersectGeometry(const RTCRay& ray, DifferentialGeometry& dg, ISPCGeometry* geometry, int& materialID) -{ - if (geometry->type == TRIANGLE_MESH) - { - ISPCTriangleMesh* mesh = (ISPCTriangleMesh*) geometry; - materialID = mesh->triangles[ray.primID].materialID; - if (mesh->texcoords) { - ISPCTriangle* tri = &mesh->triangles[ray.primID]; - const Vec2f st0 = mesh->texcoords[tri->v0]; - const Vec2f st1 = mesh->texcoords[tri->v1]; - const Vec2f st2 = mesh->texcoords[tri->v2]; - const float u = ray.u, v = ray.v, w = 1.0f-ray.u-ray.v; - const Vec2f st = w*st0 + u*st1 + v*st2; - dg.u = st.x; - dg.v = st.y; - /* - const Vec3fa n0 = mesh->normals[tri->v0]; - const Vec3fa n1 = mesh->normals[tri->v1]; - const Vec3fa n2 = mesh->normals[tri->v2]; - dg.Ns = w*n0 + u*n1 + v*n2; - */ - } - } - else if (geometry->type == QUAD_MESH) - { - ISPCQuadMesh* mesh = (ISPCQuadMesh*) geometry; - materialID = mesh->materialID; - if (mesh->texcoords) { - ISPCQuad* quad = &mesh->quads[ray.primID]; - const Vec2f st0 = mesh->texcoords[quad->v0]; - const Vec2f st1 = mesh->texcoords[quad->v1]; - const Vec2f st2 = mesh->texcoords[quad->v2]; - const Vec2f st3 = mesh->texcoords[quad->v3]; - if (ray.u+ray.v < 1.0f) { - const float u = ray.u, v = ray.v; const float w = 1.0f-u-v; - const Vec2f st = w*st0 + u*st1 + v*st3; - dg.u = st.x; - dg.v = st.y; - } else { - const float u = 1.0f-ray.u, v = 1.0f-ray.v; const float w = 1.0f-u-v; - const Vec2f st = w*st2 + u*st3 + v*st1; - dg.u = st.x; - dg.v = st.y; - } - } - } - else if (geometry->type == SUBDIV_MESH) - { - ISPCSubdivMesh* mesh = (ISPCSubdivMesh*) geometry; - materialID = mesh->materialID; - const Vec2f st = getTextureCoordinatesSubdivMesh(mesh,ray.primID,ray.u,ray.v); - dg.u = st.x; - dg.v = st.y; - } - else if (geometry->type == LINE_SEGMENTS) - { - ISPCLineSegments* mesh = (ISPCLineSegments*) geometry; - materialID = mesh->materialID; - const Vec3fa dx = normalize(dg.Ng); - const Vec3fa dy = normalize(cross(neg(ray.dir),dx)); - const Vec3fa dz = normalize(cross(dy,dx)); - dg.Tx = dx; - dg.Ty = dy; - dg.Ng = dg.Ns = dz; - int vtx = mesh->indices[ray.primID]; - dg.tnear_eps = 1.1f*mesh->positions[vtx].w; - } - else if (geometry->type == HAIR_SET) - { - ISPCHairSet* mesh = (ISPCHairSet*) geometry; - materialID = mesh->materialID; - Vec3fa p,dp; evalBezier(mesh,ray.primID,ray.u,p,dp); - const Vec3fa dx = normalize(dg.Ng); - const Vec3fa dy = normalize(cross(neg(ray.dir),dx)); - const Vec3fa dz = normalize(cross(dy,dx)); - dg.Tx = dx; - dg.Ty = dy; - dg.Ng = dg.Ns = dz; - dg.tnear_eps = 1.1f*p.w; - } - else if (geometry->type == CURVES) - { - ISPCHairSet* mesh = (ISPCHairSet*) geometry; - materialID = mesh->materialID; - Vec3fa p,dp; evalBezier(mesh,ray.primID,ray.u,p,dp); - if (length(dp) < 1E-6f) { // some hair are just points - dg.Tx = Vec3fa(1,0,0); - dg.Ty = Vec3fa(0,1,0); - dg.Ng = dg.Ns = Vec3fa(0,0,1); - } - else - { - const Vec3fa dx = normalize(Vec3fa(dp)); - const Vec3fa dy = normalize(cross(Vec3fa(dp),dg.Ng)); - const Vec3fa dz = normalize(dg.Ng); - dg.Tx = dx; - dg.Ty = dy; - dg.Ng = dg.Ns = dz; - } - dg.tnear_eps = 1024.0f*1.19209e-07f*max(max(abs(dg.P.x),abs(dg.P.y)),max(abs(dg.P.z),ray.tfar)); - } - else if (geometry->type == GROUP) { - unsigned int geomID = ray.geomID; { - postIntersectGeometry(ray,dg,((ISPCGroup*) geometry)->geometries[geomID],materialID); - } - } - else - assert(false); -} - -AffineSpace3fa calculate_interpolated_space (ISPCInstance* instance, float gtime) -{ - if (instance->numTimeSteps == 1) - return AffineSpace3fa(instance->spaces[0]); - - /* calculate time segment itime and fractional time ftime */ - const int time_segments = instance->numTimeSteps-1; - const float time = gtime*(float)(time_segments); - const int itime = clamp((int)(floor(time)),(int)0,time_segments-1); - const float ftime = time - (float)(itime); - return (1.0f-ftime)*AffineSpace3fa(instance->spaces[itime+0]) + ftime*AffineSpace3fa(instance->spaces[itime+1]); -} - -inline int postIntersect(const RTCRay& ray, DifferentialGeometry& dg) -{ - int materialID = 0; - unsigned ray_geomID = g_instancing_mode >= 2 ? ray.instID : ray.geomID; - dg.tnear_eps = 32.0f*1.19209e-07f*max(max(abs(dg.P.x),abs(dg.P.y)),max(abs(dg.P.z),ray.tfar)); - unsigned int geomID = ray_geomID; - { - /* get instance and geometry pointers */ - ISPCInstance* instance; - ISPCGeometry* geometry; - if (g_instancing_mode) { - instance = geomID_to_inst[geomID]; - geometry = g_ispc_scene->geometries[instance->geomID]; - } else { - instance = nullptr; - geometry = g_ispc_scene->geometries[geomID]; - } - - postIntersectGeometry(ray,dg,geometry,materialID); - - /* convert normals */ - if (instance) { - //AffineSpace3fa space = (1.0f-ray.time)*AffineSpace3fa(instance->space0) + ray.time*AffineSpace3fa(instance->space1); - AffineSpace3fa space = calculate_interpolated_space(instance,ray.time); - dg.Ng = xfmVector(space,dg.Ng); - dg.Ns = xfmVector(space,dg.Ns); - } - } - - return materialID; -} - -void intersectionFilterReject(void* ptr, RTCRay& ray) { - ray.geomID = RTC_INVALID_GEOMETRY_ID; -} - -void intersectionFilterOBJ(void* ptr, RTCRay& ray) -{ - /* compute differential geometry */ - DifferentialGeometry dg; - dg.geomID = ray.geomID; - dg.primID = ray.primID; - dg.u = ray.u; - dg.v = ray.v; - dg.P = ray.org+ray.tfar*ray.dir; - dg.Ng = ray.Ng; - dg.Ns = ray.Ng; - int materialID = postIntersect(ray,dg); - dg.Ng = face_forward(ray.dir,normalize(dg.Ng)); - dg.Ns = face_forward(ray.dir,normalize(dg.Ns)); - const Vec3fa wo = neg(ray.dir); - - /* calculate BRDF */ - BRDF brdf; brdf.Kt = Vec3fa(0,0,0); - int numMaterials = g_ispc_scene->numMaterials; - ISPCMaterial* material_array = &g_ispc_scene->materials[0]; - Medium medium = make_Medium_Vacuum(); - Material__preprocess(material_array,materialID,numMaterials,brdf,wo,dg,medium); - if (min(min(brdf.Kt.x,brdf.Kt.y),brdf.Kt.z) >= 1.0f) - ray.geomID = RTC_INVALID_GEOMETRY_ID; -} - -void occlusionFilterOpaque(void* ptr, RTCRay& ray) { - ray.transparency = Vec3fa(0.0f); -} - -void occlusionFilterOBJ(void* ptr, RTCRay& ray) -{ - /* compute differential geometry */ - DifferentialGeometry dg; - dg.geomID = ray.geomID; - dg.primID = ray.primID; - dg.u = ray.u; - dg.v = ray.v; - dg.P = ray.org+ray.tfar*ray.dir; - dg.Ng = ray.Ng; - dg.Ns = ray.Ng; - int materialID = postIntersect(ray,dg); - dg.Ng = face_forward(ray.dir,normalize(dg.Ng)); - dg.Ns = face_forward(ray.dir,normalize(dg.Ns)); - const Vec3fa wo = neg(ray.dir); - - /* calculate BRDF */ - BRDF brdf; brdf.Kt = Vec3fa(0,0,0); - int numMaterials = g_ispc_scene->numMaterials; - ISPCMaterial* material_array = &g_ispc_scene->materials[0]; - Medium medium = make_Medium_Vacuum(); - Material__preprocess(material_array,materialID,numMaterials,brdf,wo,dg,medium); - - ray.transparency = ray.transparency * brdf.Kt; - if (max(max(ray.transparency.x,ray.transparency.y),ray.transparency.z) > 0.0f) - ray.geomID = RTC_INVALID_GEOMETRY_ID; -} - -/* occlusion filter function */ -void occlusionFilterHair(void* ptr, RTCRay& ray) -{ - Vec3fa Kt = Vec3fa(0.0f); - unsigned int geomID = ray.geomID; - { - ISPCGeometry* geometry = g_ispc_scene->geometries[geomID]; - if (geometry->type == LINE_SEGMENTS) - { - int materialID = ((ISPCLineSegments*)geometry)->materialID; - ISPCMaterial* material = &g_ispc_scene->materials[materialID]; - switch (material->ty) { - case MATERIAL_HAIR: Kt = Vec3fa(((HairMaterial*)material)->Kt); break; - default: break; - } - } - else if (geometry->type == HAIR_SET) - { - int materialID = ((ISPCHairSet*)geometry)->materialID; - ISPCMaterial* material = &g_ispc_scene->materials[materialID]; - switch (material->ty) { - case MATERIAL_HAIR: Kt = Vec3fa(((HairMaterial*)material)->Kt); break; - default: break; - } - } - else if (geometry->type == CURVES) - { - /*if (dot(ray.dir,ray.Ng) > 0.0f) { - Kt = Vec3fa(1.0f); - } - else*/ - { - int materialID = ((ISPCHairSet*)geometry)->materialID; - ISPCMaterial* material = &g_ispc_scene->materials[materialID]; - switch (material->ty) { - case MATERIAL_HAIR: Kt = Vec3fa(((HairMaterial*)material)->Kt); break; - default: break; - } - } - } - } - - Kt = Kt * ray.transparency; - ray.transparency = Kt; - if (max(max(ray.transparency.x,ray.transparency.y),ray.transparency.z) > 0.0f) - ray.geomID = RTC_INVALID_GEOMETRY_ID; -} - -Vec3fa renderPixelFunction(float x, float y, RandomSampler& sampler, const ISPCCamera& camera) -{ - /* radiance accumulator and weight */ - Vec3fa L = Vec3fa(0.0f); - Vec3fa Lw = Vec3fa(1.0f); - Medium medium = make_Medium_Vacuum(); - float time = RandomSampler_get1D(sampler); - - /* initialize ray */ - RTCRay ray = RTCRay(Vec3fa(camera.xfm.p), - Vec3fa(normalize(x*camera.xfm.l.vx + y*camera.xfm.l.vy + camera.xfm.l.vz)),0.0f,inf,time); - - DifferentialGeometry dg; - - /* iterative path tracer loop */ - for (int i=0; inumLights; i++) - { - const Light* l = g_ispc_scene->lights[i]; - Light_EvalRes le = l->eval(l,dg,ray.dir); - L = L + Lw*le.value; - } - - break; - } - Vec3fa Ns = normalize(ray.Ng); - - if (g_use_smooth_normals) - if (ray.geomID != RTC_INVALID_GEOMETRY_ID) // FIXME: workaround for ISPC bug, location reached with empty execution mask - { - Vec3fa dPdu,dPdv; - unsigned int geomID = ray.geomID; { - rtcInterpolate(g_scene,geomID,ray.primID,ray.u,ray.v,RTC_VERTEX_BUFFER0,nullptr,&dPdu.x,&dPdv.x,3); - } - Ns = normalize(cross(dPdv,dPdu)); - } - - /* compute differential geometry */ - dg.geomID = ray.geomID; - dg.primID = ray.primID; - dg.u = ray.u; - dg.v = ray.v; - dg.P = ray.org+ray.tfar*ray.dir; - dg.Ng = ray.Ng; - dg.Ns = Ns; - int materialID = postIntersect(ray,dg); - dg.Ng = face_forward(ray.dir,normalize(dg.Ng)); - dg.Ns = face_forward(ray.dir,normalize(dg.Ns)); - - /*! Compute simple volumetric effect. */ - Vec3fa c = Vec3fa(1.0f); - const Vec3fa transmission = medium.transmission; - if (ne(transmission,Vec3fa(1.0f))) - c = c * pow(transmission,ray.tfar); - - /* calculate BRDF */ - BRDF brdf; - int numMaterials = g_ispc_scene->numMaterials; - ISPCMaterial* material_array = &g_ispc_scene->materials[0]; - Material__preprocess(material_array,materialID,numMaterials,brdf,wo,dg,medium); - - /* sample BRDF at hit point */ - Sample3f wi1; - c = c * Material__sample(material_array,materialID,numMaterials,brdf,Lw, wo, dg, wi1, medium, RandomSampler_get2D(sampler)); - - /* iterate over lights */ - for (size_t i=0; inumLights; i++) - { - const Light* l = g_ispc_scene->lights[i]; - Light_SampleRes ls = l->sample(l,dg,RandomSampler_get2D(sampler)); - if (ls.pdf <= 0.0f) continue; - RTCRay shadow = RTCRay(dg.P,ls.dir,dg.tnear_eps,ls.dist,time); shadow.transparency = Vec3fa(1.0f); - rtcOccluded(g_scene,shadow); - //if (shadow.geomID != RTC_INVALID_GEOMETRY_ID) continue; - if (max(max(shadow.transparency.x,shadow.transparency.y),shadow.transparency.z) > 0.0f) - L = L + Lw*ls.weight*shadow.transparency*Material__eval(material_array,materialID,numMaterials,brdf,wo,dg,ls.dir); - } - - if (wi1.pdf <= 1E-4f /* 0.0f */) break; - Lw = Lw*c/wi1.pdf; - - /* setup secondary ray */ - float sign = dot(wi1.v,dg.Ng) < 0.0f ? -1.0f : 1.0f; - dg.P = dg.P + sign*dg.tnear_eps*dg.Ng; - ray = RTCRay(dg.P,normalize(wi1.v),dg.tnear_eps,inf,time); - } - return L; -} - -/* task that renders a single screen tile */ -Vec3fa renderPixelStandard(float x, float y, const ISPCCamera& camera) -{ - RandomSampler sampler; - - Vec3fa L = Vec3fa(0.0f); - - for (int i=0; ipositions[mesh->position_indices[e0]]; - const Vec3fa v1 = mesh->positions[mesh->position_indices[e1]]; - const Vec3fa edge = v1-v0; - const Vec3fa P = 0.5f*(v1+v0); - const Vec3fa dist = cam_pos - P; - return max(min(LEVEL_FACTOR*(0.5f*length(edge)/length(dist)),MAX_EDGE_LEVEL),MIN_EDGE_LEVEL); -} - -void updateEdgeLevelBuffer( ISPCSubdivMesh* mesh, const Vec3fa& cam_pos, size_t startID, size_t endID ) -{ - for (size_t f=startID; fface_offsets[f]; - unsigned int N = mesh->verticesPerFace[f]; - if (N == 4) /* fast path for quads */ - for (size_t i=0; i<4; i++) - mesh->subdivlevel[e+i] = updateEdgeLevel(mesh,cam_pos,e+(i+0),e+(i+1)%4); - else if (N == 3) /* fast path for triangles */ - for (size_t i=0; i<3; i++) - mesh->subdivlevel[e+i] = updateEdgeLevel(mesh,cam_pos,e+(i+0),e+(i+1)%3); - else /* fast path for general polygons */ - for (size_t i=0; isubdivlevel[e+i] = updateEdgeLevel(mesh,cam_pos,e+(i+0),e+(i+1)%N); - } -} - -#if defined(ISPC) -void updateEdgeLevelBufferTask (int taskIndex, ISPCSubdivMesh* mesh, const Vec3fa& cam_pos ) -{ - const size_t size = mesh->numFaces; - const size_t startID = ((taskIndex+0)*size)/taskCount; - const size_t endID = ((taskIndex+1)*size)/taskCount; - updateEdgeLevelBuffer(mesh,cam_pos,startID,endID); -} -#endif - -void updateEdgeLevels(ISPCScene* scene_in, const Vec3fa& cam_pos) -{ - for (size_t g=0; gnumGeometries; g++) - { - ISPCGeometry* geometry = g_ispc_scene->geometries[g]; - if (geometry->type != SUBDIV_MESH) continue; - ISPCSubdivMesh* mesh = (ISPCSubdivMesh*) geometry; - unsigned int geomID = mesh->geomID; -#if defined(ISPC) - parallel_for(size_t(0),size_t( (mesh->numFaces+4095)/4096 ),[&](const range& range) { - for (size_t i=range.begin(); inumFaces); -#endif - rtcUpdateBuffer(g_scene,geomID,RTC_LEVEL_BUFFER); - } -} - -/* called by the C++ code for initialization */ -extern "C" void device_init (char* cfg) -{ - /* initialize last seen camera */ - g_accu_vx = Vec3fa(0.0f); - g_accu_vy = Vec3fa(0.0f); - g_accu_vz = Vec3fa(0.0f); - g_accu_p = Vec3fa(0.0f); - - /* create new Embree device */ - g_device = rtcNewDevice(cfg); - error_handler(rtcDeviceGetError(g_device)); - - /* set error handler */ - rtcDeviceSetErrorFunction(g_device,error_handler); - - /* set start render mode */ - renderTile = renderTileStandard; - key_pressed_handler = device_key_pressed_handler; - -#if ENABLE_FILTER_FUNCTION == 0 - printf("Warning: filter functions disabled\n"); -#endif - -} // device_init - -/* called by the C++ code to render */ -extern "C" void device_render (int* pixels, - const unsigned int width, - const unsigned int height, - const float time, - const ISPCCamera& camera) -{ - /* create scene */ - if (g_scene == nullptr) { - g_scene = convertScene(g_ispc_scene); - if (g_subdiv_mode) updateEdgeLevels(g_ispc_scene,camera.xfm.p); - rtcCommit (g_scene); - } - - /* create accumulator */ - if (g_accu_width != width || g_accu_height != height) { - alignedFree(g_accu); - g_accu = (Vec3fa*) alignedMalloc(width*height*sizeof(Vec3fa)); - g_accu_width = width; - g_accu_height = height; - for (size_t i=0; i& range) { - for (size_t i=range.begin(); i 0) { - Vec3fa dPdu,dPdv; - unsigned int geomID = ray.geomID; { - rtcInterpolate(g_scene,geomID,ray.primID,ray.u,ray.v,RTC_VERTEX_BUFFER,nullptr,&dPdu.x,&dPdv.x,3); - } - Ng = cross(dPdv,dPdu); - } - - color = color + diffuse*0.5f; - Vec3fa lightDir = normalize(Vec3fa(-1,-1,-1)); - - /* initialize shadow ray */ - RTCRay shadow; - shadow.org = ray.org + ray.tfar*ray.dir; - shadow.dir = neg(lightDir); - shadow.tnear = 0.001f; - shadow.tfar = inf; - shadow.geomID = RTC_INVALID_GEOMETRY_ID; - shadow.primID = RTC_INVALID_GEOMETRY_ID; - shadow.mask = -1; - shadow.time = 0; - - /* trace shadow ray */ - rtcOccluded(g_scene,shadow); - - /* add light contribution */ - if (shadow.geomID == RTC_INVALID_GEOMETRY_ID) - color = color + diffuse*clamp(-dot(lightDir,normalize(Ng)),0.0f,1.0f); - } - return color; -} - -/* renders a single screen tile */ -void renderTileStandard(int taskIndex, - int* pixels, - const unsigned int width, - const unsigned int height, - const float time, - const ISPCCamera& camera, - const int numTilesX, - const int numTilesY) -{ - const unsigned int tileY = taskIndex / numTilesX; - const unsigned int tileX = taskIndex - tileY * numTilesX; - const unsigned int x0 = tileX * TILE_SIZE_X; - const unsigned int x1 = min(x0+TILE_SIZE_X,width); - const unsigned int y0 = tileY * TILE_SIZE_Y; - const unsigned int y1 = min(y0+TILE_SIZE_Y,height); - - for (unsigned int y=y0; y& range) { - for (size_t i=range.begin(); i& range) { - for (size_t i=range.begin(); ilower; - Vec3fa u = instance->upper; - Vec3fa p000 = xfmPoint(instance->local2world,Vec3fa(l.x,l.y,l.z)); - Vec3fa p001 = xfmPoint(instance->local2world,Vec3fa(l.x,l.y,u.z)); - Vec3fa p010 = xfmPoint(instance->local2world,Vec3fa(l.x,u.y,l.z)); - Vec3fa p011 = xfmPoint(instance->local2world,Vec3fa(l.x,u.y,u.z)); - Vec3fa p100 = xfmPoint(instance->local2world,Vec3fa(u.x,l.y,l.z)); - Vec3fa p101 = xfmPoint(instance->local2world,Vec3fa(u.x,l.y,u.z)); - Vec3fa p110 = xfmPoint(instance->local2world,Vec3fa(u.x,u.y,l.z)); - Vec3fa p111 = xfmPoint(instance->local2world,Vec3fa(u.x,u.y,u.z)); - Vec3fa lower = min(min(min(p000,p001),min(p010,p011)),min(min(p100,p101),min(p110,p111))); - Vec3fa upper = max(max(max(p000,p001),max(p010,p011)),max(max(p100,p101),max(p110,p111))); - bounds_o->lower_x = lower.x; - bounds_o->lower_y = lower.y; - bounds_o->lower_z = lower.z; - bounds_o->upper_x = upper.x; - bounds_o->upper_y = upper.y; - bounds_o->upper_z = upper.z; -} - -void instanceIntersectFunc(const Instance* instance, RTCRay& ray, size_t item) -{ - const Vec3fa ray_org = ray.org; - const Vec3fa ray_dir = ray.dir; - const int geomID = ray.geomID; - ray.org = xfmPoint (instance->world2local,ray_org); - ray.dir = xfmVector(instance->world2local,ray_dir); - ray.geomID = RTC_INVALID_GEOMETRY_ID; - rtcIntersect(instance->object,ray); - ray.org = ray_org; - ray.dir = ray_dir; - if (ray.geomID == RTC_INVALID_GEOMETRY_ID) ray.geomID = geomID; - else { - ray.instID = instance->userID; - ray.Ng = xfmVector(instance->normal2world,ray.Ng); - } -} - -void instanceOccludedFunc(const Instance* instance, RTCRay& ray, size_t item) -{ - const Vec3fa ray_org = ray.org; - const Vec3fa ray_dir = ray.dir; - ray.org = xfmPoint (instance->world2local,ray_org); - ray.dir = xfmVector(instance->world2local,ray_dir); - rtcOccluded(instance->object,ray); - ray.org = ray_org; - ray.dir = ray_dir; -} - -void instanceIntersectFuncN(const int* valid, - void* ptr, - const RTCIntersectContext* context, - RTCRayN* rays, - size_t N, - size_t item) -{ - /* avoid crashing when debug visualizations are used */ - if (context == nullptr) - return; - - const Instance* instance = (const Instance*) ptr; - - /* iterate over all rays in ray packet */ - for (unsigned int ui=0; ui=N) continue; - - /* ignore inactive rays */ - if (valid[vi] != -1) continue; - - /* create transformed ray */ - RTCRay ray; - const Vec3fa ray_org = Vec3fa(RTCRayN_org_x(rays,N,ui),RTCRayN_org_y(rays,N,ui),RTCRayN_org_z(rays,N,ui)); - const Vec3fa ray_dir = Vec3fa(RTCRayN_dir_x(rays,N,ui),RTCRayN_dir_y(rays,N,ui),RTCRayN_dir_z(rays,N,ui)); - ray.org = xfmPoint (instance->world2local,ray_org); - ray.dir = xfmVector(instance->world2local,ray_dir); - bool mask = 1; { - ray.tnear = mask ? RTCRayN_tnear(rays,N,ui) : (float)(pos_inf); - ray.tfar = mask ? RTCRayN_tfar(rays,N,ui ) : (float)(neg_inf); - } - ray.time = RTCRayN_time(rays,N,ui); - ray.mask = RTCRayN_mask(rays,N,ui); - ray.geomID = RTC_INVALID_GEOMETRY_ID; - - /* trace ray through object */ - rtcIntersect1M(instance->object,context,&ray,1,sizeof(RTCRay)); - if (ray.geomID == RTC_INVALID_GEOMETRY_ID) continue; - - /* update hit */ - RTCRayN_u(rays,N,ui) = ray.u; - RTCRayN_v(rays,N,ui) = ray.v; - RTCRayN_tfar(rays,N,ui) = ray.tfar; - RTCRayN_instID(rays,N,ui) = instance->userID; - RTCRayN_geomID(rays,N,ui) = ray.geomID; - RTCRayN_primID(rays,N,ui) = ray.primID; - Vec3fa Ng = xfmVector(instance->normal2world,ray.Ng); - RTCRayN_Ng_x(rays,N,ui) = Ng.x; - RTCRayN_Ng_y(rays,N,ui) = Ng.y; - RTCRayN_Ng_z(rays,N,ui) = Ng.z; - } -} - -void instanceOccludedFuncN(const int* valid, - void* ptr, - const RTCIntersectContext* context, - RTCRayN* rays, - size_t N, - size_t item) -{ - /* avoid crashing when debug visualizations are used */ - if (context == nullptr) - return; - - const Instance* instance = (const Instance*) ptr; - - /* iterate over all rays in ray packet */ - for (unsigned int ui=0; ui=N) continue; - - /* ignore inactive rays */ - if (valid[vi] != -1) continue; - - /* create transformed ray */ - RTCRay ray; - const Vec3fa ray_org = Vec3fa(RTCRayN_org_x(rays,N,ui),RTCRayN_org_y(rays,N,ui),RTCRayN_org_z(rays,N,ui)); - const Vec3fa ray_dir = Vec3fa(RTCRayN_dir_x(rays,N,ui),RTCRayN_dir_y(rays,N,ui),RTCRayN_dir_z(rays,N,ui)); - ray.org = xfmPoint (instance->world2local,ray_org); - ray.dir = xfmVector(instance->world2local,ray_dir); - bool mask = 1; { - ray.tnear = mask ? RTCRayN_tnear(rays,N,ui) : (float)(pos_inf); - ray.tfar = mask ? RTCRayN_tfar(rays,N,ui) : (float)(neg_inf); - } - ray.time = RTCRayN_time(rays,N,ui); - ray.mask = RTCRayN_mask(rays,N,ui); - ray.geomID = RTC_INVALID_GEOMETRY_ID; - - /* trace ray through object */ - rtcOccluded1M(instance->object,context,&ray,1,sizeof(RTCRay)); - if (ray.geomID == RTC_INVALID_GEOMETRY_ID) continue; - - /* update hit */ - RTCRayN_geomID(rays,N,ui) = ray.geomID; - } -} - -Instance* createInstance (RTCScene scene, RTCScene object, int userID, const Vec3fa& lower, const Vec3fa& upper) -{ - Instance* instance = (Instance*) alignedMalloc(sizeof(Instance)); - instance->object = object; - instance->userID = userID; - instance->lower = lower; - instance->upper = upper; - instance->local2world.l.vx = Vec3fa(1,0,0); - instance->local2world.l.vy = Vec3fa(0,1,0); - instance->local2world.l.vz = Vec3fa(0,0,1); - instance->local2world.p = Vec3fa(0,0,0); - instance->geometry = rtcNewUserGeometry(scene,1); - rtcSetUserData(scene,instance->geometry,instance); - rtcSetBoundsFunction(scene,instance->geometry,(RTCBoundsFunc)&instanceBoundsFunc); - if (g_mode == MODE_NORMAL) { - rtcSetIntersectFunction(scene,instance->geometry,(RTCIntersectFunc)&instanceIntersectFunc); - rtcSetOccludedFunction (scene,instance->geometry,(RTCOccludedFunc )&instanceOccludedFunc); - } else { - rtcSetIntersectFunctionN(scene,instance->geometry,&instanceIntersectFuncN); - rtcSetOccludedFunctionN (scene,instance->geometry,&instanceOccludedFuncN); - } - return instance; -} - -void updateInstance (RTCScene scene, Instance* instance) -{ - instance->world2local = rcp(instance->local2world); - instance->normal2world = transposed(rcp(instance->local2world.l)); - rtcUpdate(scene,instance->geometry); -} - -// ======================================================================== // -// User defined sphere geometry // -// ======================================================================== // - -struct Sphere -{ - ALIGNED_STRUCT - Vec3fa p; //!< position of the sphere - float r; //!< radius of the sphere - unsigned int geomID; -}; - -void sphereBoundsFunc(const Sphere* spheres, size_t item, RTCBounds* bounds_o) -{ - const Sphere& sphere = spheres[item]; - bounds_o->lower_x = sphere.p.x-sphere.r; - bounds_o->lower_y = sphere.p.y-sphere.r; - bounds_o->lower_z = sphere.p.z-sphere.r; - bounds_o->upper_x = sphere.p.x+sphere.r; - bounds_o->upper_y = sphere.p.y+sphere.r; - bounds_o->upper_z = sphere.p.z+sphere.r; -} - -void sphereIntersectFunc(const Sphere* spheres, RTCRay& ray, size_t item) -{ - const Sphere& sphere = spheres[item]; - const Vec3fa v = ray.org-sphere.p; - const float A = dot(ray.dir,ray.dir); - const float B = 2.0f*dot(v,ray.dir); - const float C = dot(v,v) - sqr(sphere.r); - const float D = B*B - 4.0f*A*C; - if (D < 0.0f) return; - const float Q = sqrt(D); - const float rcpA = rcp(A); - const float t0 = 0.5f*rcpA*(-B-Q); - const float t1 = 0.5f*rcpA*(-B+Q); - if ((ray.tnear < t0) & (t0 < ray.tfar)) { - ray.u = 0.0f; - ray.v = 0.0f; - ray.tfar = t0; - ray.geomID = sphere.geomID; - ray.primID = (unsigned int) item; - ray.Ng = ray.org+t0*ray.dir-sphere.p; - } - if ((ray.tnear < t1) & (t1 < ray.tfar)) { - ray.u = 0.0f; - ray.v = 0.0f; - ray.tfar = t1; - ray.geomID = sphere.geomID; - ray.primID = (unsigned int) item; - ray.Ng = ray.org+t1*ray.dir-sphere.p; - } -} - -void sphereOccludedFunc(const Sphere* spheres, RTCRay& ray, size_t item) -{ - const Sphere& sphere = spheres[item]; - const Vec3fa v = ray.org-sphere.p; - const float A = dot(ray.dir,ray.dir); - const float B = 2.0f*dot(v,ray.dir); - const float C = dot(v,v) - sqr(sphere.r); - const float D = B*B - 4.0f*A*C; - if (D < 0.0f) return; - const float Q = sqrt(D); - const float rcpA = rcp(A); - const float t0 = 0.5f*rcpA*(-B-Q); - const float t1 = 0.5f*rcpA*(-B+Q); - if ((ray.tnear < t0) & (t0 < ray.tfar)) { - ray.geomID = 0; - } - if ((ray.tnear < t1) & (t1 < ray.tfar)) { - ray.geomID = 0; - } -} - -void sphereIntersectFuncN(const int* valid, - void* ptr, - const RTCIntersectContext* context, - RTCRayN* rays, - size_t N, - size_t item) -{ - const Sphere* spheres = (const Sphere*) ptr; - - /* iterate over all rays in ray packet */ - for (unsigned int ui=0; ui=N) continue; - - /* ignore inactive rays */ - if (valid[vi] != -1) continue; - - const Vec3fa ray_org = Vec3fa(RTCRayN_org_x(rays,N,ui),RTCRayN_org_y(rays,N,ui),RTCRayN_org_z(rays,N,ui)); - const Vec3fa ray_dir = Vec3fa(RTCRayN_dir_x(rays,N,ui),RTCRayN_dir_y(rays,N,ui),RTCRayN_dir_z(rays,N,ui)); - float& ray_tnear = RTCRayN_tnear(rays,N,ui); - float& ray_tfar = RTCRayN_tfar(rays,N,ui); - - const Sphere& sphere = spheres[item]; - const Vec3fa v = ray_org-sphere.p; - const float A = dot(ray_dir,ray_dir); - const float B = 2.0f*dot(v,ray_dir); - const float C = dot(v,v) - sqr(sphere.r); - const float D = B*B - 4.0f*A*C; - if (D < 0.0f) continue; - const float Q = sqrt(D); - const float rcpA = rcp(A); - const float t0 = 0.5f*rcpA*(-B-Q); - const float t1 = 0.5f*rcpA*(-B+Q); - - if ((ray_tnear < t0) & (t0 < ray_tfar)) - { - RTCRayN_u(rays,N,ui) = 0.0f; - RTCRayN_v(rays,N,ui) = 0.0f; - RTCRayN_tfar(rays,N,ui) = t0; - RTCRayN_geomID(rays,N,ui) = sphere.geomID; - RTCRayN_primID(rays,N,ui) = (unsigned int)item; - const Vec3fa Ng = ray_org+t0*ray_dir-sphere.p; - RTCRayN_Ng_x(rays,N,ui) = Ng.x; - RTCRayN_Ng_y(rays,N,ui) = Ng.y; - RTCRayN_Ng_z(rays,N,ui) = Ng.z; - } - if ((ray_tnear < t1) & (t1 < ray_tfar)) - { - RTCRayN_u(rays,N,ui) = 0.0f; - RTCRayN_v(rays,N,ui) = 0.0f; - RTCRayN_tfar(rays,N,ui) = t1; - RTCRayN_geomID(rays,N,ui) = sphere.geomID; - RTCRayN_primID(rays,N,ui) = (unsigned int)item; - const Vec3fa Ng = ray_org+t1*ray_dir-sphere.p; - RTCRayN_Ng_x(rays,N,ui) = Ng.x; - RTCRayN_Ng_y(rays,N,ui) = Ng.y; - RTCRayN_Ng_z(rays,N,ui) = Ng.z; - } - } -} - -void sphereOccludedFuncN(const int* valid, - void* ptr, - const RTCIntersectContext* context, - RTCRayN* rays, - size_t N, - size_t item) -{ - const Sphere* spheres = (const Sphere*) ptr; - - /* iterate over all rays in ray packet */ - for (unsigned int ui=0; ui=N) continue; - - /* ignore inactive rays */ - if (valid[vi] != -1) continue; - - const Vec3fa ray_org = Vec3fa(RTCRayN_org_x(rays,N,ui),RTCRayN_org_y(rays,N,ui),RTCRayN_org_z(rays,N,ui)); - const Vec3fa ray_dir = Vec3fa(RTCRayN_dir_x(rays,N,ui),RTCRayN_dir_y(rays,N,ui),RTCRayN_dir_z(rays,N,ui)); - float& ray_tnear = RTCRayN_tnear(rays,N,ui); - float& ray_tfar = RTCRayN_tfar(rays,N,ui); - - const Sphere& sphere = spheres[item]; - const Vec3fa v = ray_org-sphere.p; - const float A = dot(ray_dir,ray_dir); - const float B = 2.0f*dot(v,ray_dir); - const float C = dot(v,v) - sqr(sphere.r); - const float D = B*B - 4.0f*A*C; - if (D < 0.0f) continue; - const float Q = sqrt(D); - const float rcpA = rcp(A); - const float t0 = 0.5f*rcpA*(-B-Q); - const float t1 = 0.5f*rcpA*(-B+Q); - if ((ray_tnear < t0) & (t0 < ray_tfar)) { - RTCRayN_geomID(rays,N,ui) = 0; - } - if ((ray_tnear < t1) & (t1 < ray_tfar)) { - RTCRayN_geomID(rays,N,ui) = 0; - } - } -} - -Sphere* createAnalyticalSphere (RTCScene scene, const Vec3fa& p, float r) -{ - unsigned int geomID = rtcNewUserGeometry(scene,1); - Sphere* sphere = (Sphere*) alignedMalloc(sizeof(Sphere)); - sphere->p = p; - sphere->r = r; - sphere->geomID = geomID; - rtcSetUserData(scene,geomID,sphere); - rtcSetBoundsFunction(scene,geomID,(RTCBoundsFunc)&sphereBoundsFunc); - if (g_mode == MODE_NORMAL) { - rtcSetIntersectFunction(scene,geomID,(RTCIntersectFunc)&sphereIntersectFunc); - rtcSetOccludedFunction (scene,geomID,(RTCOccludedFunc )&sphereOccludedFunc); - } else { - rtcSetIntersectFunctionN(scene,geomID,&sphereIntersectFuncN); - rtcSetOccludedFunctionN (scene,geomID,&sphereOccludedFuncN); - } - return sphere; -} - -Sphere* createAnalyticalSpheres (RTCScene scene, size_t N) -{ - unsigned int geomID = rtcNewUserGeometry(scene,N); - Sphere* spheres = (Sphere*) alignedMalloc(N*sizeof(Sphere)); - for (size_t i=0; i 1) { - triangles[tri].v0 = p10; - triangles[tri].v1 = p00; - triangles[tri].v2 = p01; - tri++; - } - - if (phi < numPhi) { - triangles[tri].v0 = p11; - triangles[tri].v1 = p10; - triangles[tri].v2 = p01; - tri++; - } - } - } - rtcUnmapBuffer(scene,mesh,RTC_VERTEX_BUFFER); - rtcUnmapBuffer(scene,mesh,RTC_INDEX_BUFFER); - return mesh; -} - -/* creates a ground plane */ -unsigned int createGroundPlane (RTCScene scene) -{ - /* create a triangulated plane with 2 triangles and 4 vertices */ - unsigned int mesh = rtcNewTriangleMesh (scene, RTC_GEOMETRY_STATIC, 2, 4); - - /* set vertices */ - Vertex* vertices = (Vertex*) rtcMapBuffer(scene,mesh,RTC_VERTEX_BUFFER); - vertices[0].x = -10; vertices[0].y = -2; vertices[0].z = -10; - vertices[1].x = -10; vertices[1].y = -2; vertices[1].z = +10; - vertices[2].x = +10; vertices[2].y = -2; vertices[2].z = -10; - vertices[3].x = +10; vertices[3].y = -2; vertices[3].z = +10; - rtcUnmapBuffer(scene,mesh,RTC_VERTEX_BUFFER); - - /* set triangles */ - Triangle* triangles = (Triangle*) rtcMapBuffer(scene,mesh,RTC_INDEX_BUFFER); - triangles[0].v0 = 0; triangles[0].v1 = 2; triangles[0].v2 = 1; - triangles[1].v0 = 1; triangles[1].v1 = 2; triangles[1].v2 = 3; - rtcUnmapBuffer(scene,mesh,RTC_INDEX_BUFFER); - - return mesh; -} - -/* scene data */ -RTCDevice g_device = nullptr; -RTCScene g_scene = nullptr; -RTCScene g_scene0 = nullptr; -RTCScene g_scene1 = nullptr; -RTCScene g_scene2 = nullptr; - -Instance* g_instance[4] = { nullptr, nullptr, nullptr, nullptr }; - -Vec3fa colors[5][4]; - -/* called by the C++ code for initialization */ -extern "C" void device_init (char* cfg) -{ - /* create new Embree device */ - g_device = rtcNewDevice(cfg); - error_handler(rtcDeviceGetError(g_device)); - - /* set error handler */ - rtcDeviceSetErrorFunction(g_device,error_handler); - - RTCAlgorithmFlags aflags; - if (g_mode == MODE_NORMAL) aflags = RTC_INTERSECT1; - else aflags = RTC_INTERSECT1 | RTC_INTERSECT_STREAM; - - /* create scene */ - g_scene = rtcDeviceNewScene(g_device, RTC_SCENE_DYNAMIC,aflags); - - /* create scene with 4 analytical spheres */ - g_scene0 = rtcDeviceNewScene(g_device, RTC_SCENE_STATIC,aflags); - Sphere* spheres = createAnalyticalSpheres(g_scene0,4); - spheres[0].p = Vec3fa( 0, 0,+1); spheres[0].r = 0.5f; - spheres[1].p = Vec3fa(+1, 0, 0); spheres[1].r = 0.5f; - spheres[2].p = Vec3fa( 0, 0,-1); spheres[2].r = 0.5f; - spheres[3].p = Vec3fa(-1, 0, 0); spheres[3].r = 0.5f; - rtcCommit(g_scene0); - - /* create scene with 4 triangulated spheres */ - g_scene1 = rtcDeviceNewScene(g_device, RTC_SCENE_STATIC,aflags); - createTriangulatedSphere(g_scene1,Vec3fa( 0, 0,+1),0.5f); - createTriangulatedSphere(g_scene1,Vec3fa(+1, 0, 0),0.5f); - createTriangulatedSphere(g_scene1,Vec3fa( 0, 0,-1),0.5f); - createTriangulatedSphere(g_scene1,Vec3fa(-1, 0, 0),0.5f); - rtcCommit(g_scene1); - - /* create scene with 2 triangulated and 2 analytical spheres */ - g_scene2 = rtcDeviceNewScene(g_device, RTC_SCENE_STATIC,aflags); - createTriangulatedSphere(g_scene2,Vec3fa( 0, 0,+1),0.5f); - createAnalyticalSphere (g_scene2,Vec3fa(+1, 0, 0),0.5f); - createTriangulatedSphere(g_scene2,Vec3fa( 0, 0,-1),0.5f); - createAnalyticalSphere (g_scene2,Vec3fa(-1, 0, 0),0.5f); - rtcCommit(g_scene2); - - /* instantiate geometry */ - createGroundPlane(g_scene); - g_instance[0] = createInstance(g_scene,g_scene0,0,Vec3fa(-2,-2,-2),Vec3fa(+2,+2,+2)); - g_instance[1] = createInstance(g_scene,g_scene1,1,Vec3fa(-2,-2,-2),Vec3fa(+2,+2,+2)); - g_instance[2] = createInstance(g_scene,g_scene2,2,Vec3fa(-2,-2,-2),Vec3fa(+2,+2,+2)); - g_instance[3] = createInstance(g_scene,g_scene2,3,Vec3fa(-2,-2,-2),Vec3fa(+2,+2,+2)); - rtcCommit(g_scene); - - /* set all colors */ - colors[0][0] = Vec3fa(0.25f, 0.00f, 0.00f); - colors[0][1] = Vec3fa(0.50f, 0.00f, 0.00f); - colors[0][2] = Vec3fa(0.75f, 0.00f, 0.00f); - colors[0][3] = Vec3fa(1.00f, 0.00f, 0.00f); - - colors[1][0] = Vec3fa(0.00f, 0.25f, 0.00f); - colors[1][1] = Vec3fa(0.00f, 0.50f, 0.00f); - colors[1][2] = Vec3fa(0.00f, 0.75f, 0.00f); - colors[1][3] = Vec3fa(0.00f, 1.00f, 0.00f); - - colors[2][0] = Vec3fa(0.00f, 0.00f, 0.25f); - colors[2][1] = Vec3fa(0.00f, 0.00f, 0.50f); - colors[2][2] = Vec3fa(0.00f, 0.00f, 0.75f); - colors[2][3] = Vec3fa(0.00f, 0.00f, 1.00f); - - colors[3][0] = Vec3fa(0.25f, 0.25f, 0.00f); - colors[3][1] = Vec3fa(0.50f, 0.50f, 0.00f); - colors[3][2] = Vec3fa(0.75f, 0.75f, 0.00f); - colors[3][3] = Vec3fa(1.00f, 1.00f, 0.00f); - - colors[4][0] = Vec3fa(1.0f, 1.0f, 1.0f); - colors[4][1] = Vec3fa(1.0f, 1.0f, 1.0f); - colors[4][2] = Vec3fa(1.0f, 1.0f, 1.0f); - colors[4][3] = Vec3fa(1.0f, 1.0f, 1.0f); - - /* set start render mode */ - if (g_mode == MODE_NORMAL) renderTile = renderTileStandard; - else renderTile = renderTileStandardStream; - key_pressed_handler = device_key_pressed_default; -} - -/* task that renders a single screen tile */ -Vec3fa renderPixelStandard(float x, float y, const ISPCCamera& camera) -{ - /* initialize ray */ - RTCRay ray; - ray.org = Vec3fa(camera.xfm.p); - ray.dir = Vec3fa(normalize(x*camera.xfm.l.vx + y*camera.xfm.l.vy + camera.xfm.l.vz)); - ray.tnear = 0.0f; - ray.tfar = (float)(inf); - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.primID = RTC_INVALID_GEOMETRY_ID; - ray.instID = 4; // set default instance ID - ray.mask = -1; - ray.time = 0; - - /* intersect ray with scene */ - rtcIntersect(g_scene,ray); - - /* shade pixels */ - Vec3fa color = Vec3fa(0.0f); - if (ray.geomID != RTC_INVALID_GEOMETRY_ID) - { - /* calculate shading normal */ - Vec3fa Ns = normalize(ray.Ng); - - /* calculate diffuse color of geometries */ - Vec3fa diffuse = Vec3fa(0.0f); - if (ray.instID == 0) diffuse = colors[ray.instID][ray.primID]; - else diffuse = colors[ray.instID][ray.geomID]; - color = color + diffuse*0.5; - - /* initialize shadow ray */ - Vec3fa lightDir = normalize(Vec3fa(-1,-1,-1)); - RTCRay shadow; - shadow.org = ray.org + ray.tfar*ray.dir; - shadow.dir = neg(lightDir); - shadow.tnear = 0.001f; - shadow.tfar = (float)(inf); - shadow.geomID = 1; - shadow.primID = 0; - shadow.mask = -1; - shadow.time = 0; - - /* trace shadow ray */ - rtcOccluded(g_scene,shadow); - - /* add light contribution */ - if (shadow.geomID) - color = color + diffuse*clamp(-dot(lightDir,Ns),0.0f,1.0f); - } - return color; -} - -/* renders a single screen tile */ -void renderTileStandard(int taskIndex, - int* pixels, - const unsigned int width, - const unsigned int height, - const float time, - const ISPCCamera& camera, - const int numTilesX, - const int numTilesY) -{ - const unsigned int tileY = taskIndex / numTilesX; - const unsigned int tileX = taskIndex - tileY * numTilesX; - const unsigned int x0 = tileX * TILE_SIZE_X; - const unsigned int x1 = min(x0+TILE_SIZE_X,width); - const unsigned int y0 = tileY * TILE_SIZE_Y; - const unsigned int y1 = min(y0+TILE_SIZE_Y,height); - - for (unsigned int y=y0; ylocal2world = AffineSpace3fa(xfm,2.2f*Vec3fa(+cos(t0),0.0f,+sin(t0))); - g_instance[1]->local2world = AffineSpace3fa(xfm,2.2f*Vec3fa(-cos(t0),0.0f,-sin(t0))); - g_instance[2]->local2world = AffineSpace3fa(xfm,2.2f*Vec3fa(-sin(t0),0.0f,+cos(t0))); - g_instance[3]->local2world = AffineSpace3fa(xfm,2.2f*Vec3fa(+sin(t0),0.0f,-cos(t0))); - - /* update scene */ - updateInstance(g_scene,g_instance[0]); - updateInstance(g_scene,g_instance[1]); - updateInstance(g_scene,g_instance[2]); - updateInstance(g_scene,g_instance[3]); - rtcCommit (g_scene); - - /* render all pixels */ - const int numTilesX = (width +TILE_SIZE_X-1)/TILE_SIZE_X; - const int numTilesY = (height+TILE_SIZE_Y-1)/TILE_SIZE_Y; - parallel_for(size_t(0),size_t(numTilesX*numTilesY),[&](const range& range) { - for (size_t i=range.begin(); i - inline void IntersectWithNMMode(IntersectVariant ivariant, RTCScene scene, RTCIntersectContext* context, RTCRay* rays, size_t Nrays) - { - assert(Nrays<1024); - const size_t alignment = size_t(rays) % 64; - __aligned(64) char data[1024*sizeof(RTCRay)+64]; - assert((size_t)data % 64 == 0); - for (size_t i=0; i(ivariant,scene,&context,rays,N); - break; - } - case MODE_INTERSECTNM3: { - IntersectWithNMMode<3>(ivariant,scene,&context,rays,N); - break; - } - case MODE_INTERSECTNM4: { - IntersectWithNMMode<4>(ivariant,scene,&context,rays,N); - break; - } - case MODE_INTERSECTNM8: { - IntersectWithNMMode<8>(ivariant,scene,&context,rays,N); - break; - } - case MODE_INTERSECTNM16: { - IntersectWithNMMode<16>(ivariant,scene,&context,rays,N); - break; - } - case MODE_INTERSECTNp: - { - assert(N<1024); - const size_t alignment = size_t(rays) % 64; - __aligned(64) char data[1024*sizeof(RTCRay)+64]; - RTCRayN* ray = (RTCRayN*) &data[alignment]; - for (size_t j=0; j> rays2(N); - for (size_t i=0; i -#include - -#define random use_random_function_of_test // do use random_int() and random_float() from Test class -#define drand48 use_random_function_of_test // do use random_int() and random_float() from Test class - -#define DEFAULT_STACK_SIZE 4*1024*1024 -#define TEXT_ALIGN 85 - -#if defined(__INTEL_COMPILER) -#pragma warning (disable: 1478) // warning: function was declared deprecated -#elif defined(_MSC_VER) -#pragma warning (disable: 4996) // warning: function was declared deprecated -#elif defined(__clang__) -#pragma clang diagnostic ignored "-Wdeprecated-declarations" // warning: xxx is deprecated -#elif defined(__GNUC__) -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" // warning: xxx is deprecated -#endif - -namespace embree -{ - /* error reporting function */ - void errorHandler(const RTCError code, const char* str = nullptr) - { - if (code == RTC_NO_ERROR) - return; - - std::string descr = str ? ": " + std::string(str) : ""; - switch (code) { - case RTC_UNKNOWN_ERROR : throw std::runtime_error("RTC_UNKNOWN_ERROR"+descr); - case RTC_INVALID_ARGUMENT : throw std::runtime_error("RTC_INVALID_ARGUMENT"+descr); break; - case RTC_INVALID_OPERATION: throw std::runtime_error("RTC_INVALID_OPERATION"+descr); break; - case RTC_OUT_OF_MEMORY : throw std::runtime_error("RTC_OUT_OF_MEMORY"+descr); break; - case RTC_UNSUPPORTED_CPU : throw std::runtime_error("RTC_UNSUPPORTED_CPU"+descr); break; - case RTC_CANCELLED : throw std::runtime_error("RTC_CANCELLED"+descr); break; - default : throw std::runtime_error("invalid error code"+descr); break; - } - } - - bool hasISA(const int isa) - { - int cpu_features = getCPUFeatures(); - return (cpu_features & isa) == isa; - } - - bool regex_match(std::string str, std::string regex) - { -#if (defined(__INTEL_COMPILER) && (__INTEL_COMPILER < 1600)) // works around __ZTVNSt3__123__match_any_but_newlineIcEE link error - return str == regex; -#elif defined(__GNUC__) && !defined(__clang__) && (__GNUC__ <= 4) && (__GNUC_MINOR__ < 8) // workaround for older gcc version - return str == regex; -#else - std::smatch match; std::regex regexpr(regex); - return std::regex_match(str, match, regexpr); -#endif - } - - void AssertNoError(RTCDevice device) - { - RTCError error = rtcDeviceGetError(device); - if (error != RTC_NO_ERROR) - throw std::runtime_error("Error occured: "+string_of(error)); - } - - void AssertAnyError(RTCDevice device) - { - RTCError error = rtcDeviceGetError(device); - if (error == RTC_NO_ERROR) - throw std::runtime_error("Any error expected"); - } - - void AssertError(RTCDevice device, RTCError expectedError) - { - RTCError error = rtcDeviceGetError(device); - if (error != expectedError) - throw std::runtime_error("Error "+string_of(expectedError)+" expected"); - } - - typedef SceneGraph::TriangleMeshNode::Triangle Triangle; - - void addRandomSubdivFeatures(RandomSampler& sampler, Ref mesh, size_t numEdgeCreases, size_t numVertexCreases, size_t numHoles) - { - std::vector offsets; - std::vector& faces = mesh->verticesPerFace; - std::vector& indices = mesh->position_indices; - for (size_t i=0, j=0; iverticesPerFace.size(); i++) { - offsets.push_back(unsigned(j)); j+=mesh->verticesPerFace[i]; - } - - for (size_t i=0; iedge_creases.push_back(Vec2i(indices[offsets[f]+(e+0)%n],indices[offsets[f]+(e+1)%n])); - } else { - mesh->edge_creases.push_back(Vec2i(0,0)); - } - mesh->edge_crease_weights.push_back(10.0f*RandomSampler_getFloat(sampler)); - } - - for (size_t i=0; ivertex_creases.push_back(indices[offsets[f] + e]); - mesh->vertex_crease_weights.push_back(10.0f*RandomSampler_getFloat(sampler)); - } - } - - for (size_t i=0; iholes.push_back(RandomSampler_getInt(sampler) % faces.size()); - } - } - - struct Sphere - { - ALIGNED_CLASS; - public: - Sphere () : pos(zero), r(zero) {} - Sphere (const Vec3fa& pos, float r) : pos(pos), r(r) {} - __forceinline BBox3fa bounds() const { return BBox3fa(pos-Vec3fa(r),pos+Vec3fa(r)); } - public: - Vec3fa pos; - float r; - }; - - void BoundsFunc(Sphere* sphere, size_t index, BBox3fa* bounds_o) - { - bounds_o->lower.x = sphere->pos.x-sphere->r; - bounds_o->lower.y = sphere->pos.y-sphere->r; - bounds_o->lower.z = sphere->pos.z-sphere->r; - bounds_o->upper.x = sphere->pos.x+sphere->r; - bounds_o->upper.y = sphere->pos.y+sphere->r; - bounds_o->upper.z = sphere->pos.z+sphere->r; - } - - void IntersectFuncN(const int* valid, - void* ptr, - const RTCIntersectContext* context, - RTCRayN* rays, - size_t N, - size_t item) - { - } - - struct VerifyScene : public RefCount - { - VerifyScene (const RTCDeviceRef& device, RTCSceneFlags sflags, RTCAlgorithmFlags aflags) - : device(device), scene(rtcDeviceNewScene(device,sflags,aflags)) {} - - operator RTCScene() const { - return scene; - } - - unsigned addGeometry(const RTCGeometryFlags gflag, const Ref& node) - { - nodes.push_back(node); - - if (Ref mesh = node.dynamicCast()) - { - unsigned geomID = rtcNewTriangleMesh (scene, gflag, mesh->triangles.size(), mesh->numVertices(), mesh->numTimeSteps()); - rtcSetBuffer(scene,geomID,RTC_INDEX_BUFFER ,mesh->triangles.data(),0,sizeof(SceneGraph::TriangleMeshNode::Triangle)); - for (size_t t=0; tnumTimeSteps(); t++) - rtcSetBuffer(scene,geomID,RTCBufferType(RTC_VERTEX_BUFFER0+t),mesh->positions[t].data(),0,sizeof(SceneGraph::TriangleMeshNode::Vertex)); - AssertNoError(device); - return geomID; - } - else if (Ref mesh = node.dynamicCast()) - { - unsigned geomID = rtcNewQuadMesh (scene, gflag, mesh->quads.size(), mesh->numVertices(), mesh->numTimeSteps()); - rtcSetBuffer(scene,geomID,RTC_INDEX_BUFFER ,mesh->quads.data(),0,sizeof(SceneGraph::QuadMeshNode::Quad )); - for (size_t t=0; tnumTimeSteps(); t++) - rtcSetBuffer(scene,geomID,RTCBufferType(RTC_VERTEX_BUFFER0+t),mesh->positions[t].data(),0,sizeof(SceneGraph::QuadMeshNode::Vertex)); - AssertNoError(device); - return geomID; - } - else if (Ref mesh = node.dynamicCast()) - { - unsigned geomID = rtcNewSubdivisionMesh (scene, gflag, - mesh->verticesPerFace.size(), mesh->position_indices.size(), mesh->numPositions(), - mesh->edge_creases.size(), mesh->vertex_creases.size(), mesh->holes.size(), mesh->numTimeSteps()); - rtcSetBuffer(scene,geomID,RTC_FACE_BUFFER ,mesh->verticesPerFace.data(), 0,sizeof(int)); - rtcSetBuffer(scene,geomID,RTC_INDEX_BUFFER ,mesh->position_indices.data(),0,sizeof(int)); - for (size_t t=0; tnumTimeSteps(); t++) - rtcSetBuffer(scene,geomID,RTCBufferType(RTC_VERTEX_BUFFER0+t),mesh->positions[t].data(),0,sizeof(SceneGraph::SubdivMeshNode::Vertex)); - if (mesh->edge_creases.size()) rtcSetBuffer(scene,geomID,RTC_EDGE_CREASE_INDEX_BUFFER,mesh->edge_creases.data(),0,2*sizeof(int)); - if (mesh->edge_crease_weights.size()) rtcSetBuffer(scene,geomID,RTC_EDGE_CREASE_WEIGHT_BUFFER,mesh->edge_crease_weights.data(),0,sizeof(float)); - if (mesh->vertex_creases.size()) rtcSetBuffer(scene,geomID,RTC_VERTEX_CREASE_INDEX_BUFFER,mesh->vertex_creases.data(),0,sizeof(int)); - if (mesh->vertex_crease_weights.size()) rtcSetBuffer(scene,geomID,RTC_VERTEX_CREASE_WEIGHT_BUFFER,mesh->vertex_crease_weights.data(),0,sizeof(float)); - if (mesh->holes.size()) rtcSetBuffer(scene,geomID,RTC_HOLE_BUFFER,mesh->holes.data(),0,sizeof(int)); - rtcSetTessellationRate(scene,geomID,mesh->tessellationRate); - rtcSetSubdivisionMode(scene,geomID,0,mesh->position_subdiv_mode); - AssertNoError(device); - return geomID; - } - else if (Ref mesh = node.dynamicCast()) - { - unsigned int geomID = rtcNewHairGeometry (scene, gflag, mesh->hairs.size(), mesh->numVertices(), mesh->numTimeSteps()); - for (size_t t=0; tnumTimeSteps(); t++) - rtcSetBuffer(scene,geomID,RTCBufferType(RTC_VERTEX_BUFFER0+t),mesh->positions[t].data(),0,sizeof(SceneGraph::HairSetNode::Vertex)); - rtcSetBuffer(scene,geomID,RTC_INDEX_BUFFER,mesh->hairs.data(),0,sizeof(SceneGraph::HairSetNode::Hair)); - AssertNoError(device); - return geomID; - } - else if (Ref mesh = node.dynamicCast()) - { - unsigned int geomID = rtcNewLineSegments (scene, gflag, mesh->indices.size(), mesh->numVertices(), mesh->numTimeSteps()); - for (size_t t=0; tnumTimeSteps(); t++) - rtcSetBuffer(scene,geomID,RTCBufferType(RTC_VERTEX_BUFFER0+t),mesh->positions[t].data(),0,sizeof(SceneGraph::LineSegmentsNode::Vertex)); - rtcSetBuffer(scene,geomID,RTC_INDEX_BUFFER,mesh->indices.data(),0,sizeof(int)); - AssertNoError(device); - return geomID; - } - else { - THROW_RUNTIME_ERROR("unknown node type"); - } - return 0; - } - - std::pair> addGeometry2(const RTCGeometryFlags gflag, const Ref& node) { - return std::make_pair(addGeometry(gflag,node),node); - } - - std::pair> addPlane (RandomSampler& sampler, const RTCGeometryFlags gflag, size_t num, const Vec3fa& p0, const Vec3fa& dx, const Vec3fa& dy) { - return addGeometry2(gflag,SceneGraph::createTrianglePlane(p0,dx,dy,num,num)); - } - - std::pair> addSubdivPlane (RandomSampler& sampler, RTCGeometryFlags gflag, size_t num, const Vec3fa& p0, const Vec3fa& dx, const Vec3fa& dy) { - return addGeometry2(gflag,SceneGraph::createSubdivPlane(p0,dx,dy,num,num,2.0f)); - } - - std::pair> addSphere (RandomSampler& sampler, RTCGeometryFlags gflag, const Vec3fa& pos, const float r, size_t numPhi, size_t maxTriangles = -1, const avector& motion_vector = avector()) - { - Ref node = SceneGraph::createTriangleSphere(pos,r,numPhi); - if (motion_vector.size()) SceneGraph::set_motion_vector(node,motion_vector); - if (maxTriangles != size_t(-1)) SceneGraph::resize_randomly(sampler,node,maxTriangles); - return addGeometry2(gflag,node); - } - - std::pair> addQuadSphere (RandomSampler& sampler, RTCGeometryFlags gflag, const Vec3fa& pos, const float r, size_t numPhi, size_t maxQuads = -1, const avector& motion_vector = avector()) - { - Ref node = SceneGraph::createQuadSphere(pos,r,numPhi); - if (motion_vector.size()) SceneGraph::set_motion_vector(node,motion_vector); - if (maxQuads != size_t(-1)) SceneGraph::resize_randomly(sampler,node,maxQuads); - return addGeometry2(gflag,node); - } - - std::pair> addSubdivSphere (RandomSampler& sampler, RTCGeometryFlags gflag, const Vec3fa& pos, const float r, size_t numPhi, float level, size_t maxFaces = -1, const avector& motion_vector = avector()) - { - Ref node = SceneGraph::createSubdivSphere(pos,r,numPhi,level); - if (motion_vector.size()) SceneGraph::set_motion_vector(node,motion_vector); - if (maxFaces != size_t(-1)) SceneGraph::resize_randomly(sampler,node,maxFaces); - addRandomSubdivFeatures(sampler,node.dynamicCast(),10,10,0); - return addGeometry2(gflag,node); - } - - std::pair> addSphereHair (RandomSampler& sampler, RTCGeometryFlags gflag, const Vec3fa& center, const float radius, const avector& motion_vector = avector()) - { - Ref node = SceneGraph::createSphereShapedHair(center,radius); - if (motion_vector.size()) SceneGraph::set_motion_vector(node,motion_vector); - return addGeometry2(gflag,node); - } - - std::pair> addHair (RandomSampler& sampler, RTCGeometryFlags gflag, const Vec3fa& pos, const float scale, const float r, size_t numHairs = 1, const avector& motion_vector = avector()) - { - Ref node = SceneGraph::createHairyPlane(RandomSampler_getInt(sampler),pos,Vec3fa(1,0,0),Vec3fa(0,0,1),scale,r,numHairs,true); - if (motion_vector.size()) SceneGraph::set_motion_vector(node,motion_vector); - return addGeometry2(gflag,node); - } - - std::pair> addUserGeometryEmpty (RandomSampler& sampler, RTCGeometryFlags gflag, Sphere* sphere) - { - unsigned geom = rtcNewUserGeometry3 (scene,gflag,1,1); - rtcSetBoundsFunction(scene,geom,(RTCBoundsFunc)BoundsFunc); - rtcSetUserData(scene,geom,sphere); - rtcSetIntersectFunctionN(scene,geom,IntersectFuncN); - rtcSetOccludedFunctionN(scene,geom,IntersectFuncN); - return std::make_pair(geom,Ref(nullptr)); - } - - void resizeRandomly (std::pair> geom, RandomSampler& sampler) - { - if (Ref mesh = geom.second.dynamicCast()) - { - rtcSetBuffer2(scene,geom.first,RTC_INDEX_BUFFER ,mesh->triangles.data(),0,sizeof(SceneGraph::TriangleMeshNode::Triangle), RandomSampler_getInt(sampler) % (mesh->triangles.size()+1)); - } - else if (Ref mesh = geom.second.dynamicCast()) - { - rtcSetBuffer2(scene,geom.first,RTC_INDEX_BUFFER ,mesh->quads.data(),0,sizeof(SceneGraph::QuadMeshNode::Quad), RandomSampler_getInt(sampler) % (mesh->quads.size()+1)); - } - else if (Ref mesh = geom.second.dynamicCast()) - { - rtcSetBuffer2(scene,geom.first,RTC_FACE_BUFFER ,mesh->verticesPerFace.data(), 0,sizeof(int), RandomSampler_getInt(sampler) % (mesh->verticesPerFace.size()+1)); - } - else if (Ref mesh = geom.second.dynamicCast()) - { - rtcSetBuffer2(scene,geom.first,RTC_INDEX_BUFFER,mesh->hairs.data(),0,sizeof(SceneGraph::HairSetNode::Hair), RandomSampler_getInt(sampler) % (mesh->hairs.size()+1)); - } - else if (Ref mesh = geom.second.dynamicCast()) - { - rtcSetBuffer2(scene,geom.first,RTC_INDEX_BUFFER,mesh->indices.data(),0,sizeof(int), RandomSampler_getInt(sampler) % (mesh->indices.size()+1)); - } - } - - public: - const RTCDeviceRef& device; - RTCSceneRef scene; - std::vector> nodes; - }; - - VerifyApplication::TestReturnValue VerifyApplication::Test::execute(VerifyApplication* state, bool silent) - { - if (!isEnabled()) - return SKIPPED; - - if (!silent) - std::cout << std::setw(TEXT_ALIGN) << name << " ..." << std::flush; - - TestReturnValue v = SKIPPED; - try { - v = run(state,silent); - } catch (...) { - v = FAILED; - } - TestReturnValue ev = ty != TEST_SHOULD_FAIL ? PASSED : FAILED; - bool passed = v == ev || v == SKIPPED; - - if (silent) - { - Lock lock(state->mutex); - if (v != SKIPPED) { - if (passed ) std::cout << state->green ("+") << std::flush; - else if (ignoreFailure) std::cout << state->yellow("!") << std::flush; - else std::cout << state->red ("-") << std::flush; - } - } - else - { - if (v == SKIPPED ) std::cout << state->green (" [SKIPPED]") << std::endl << std::flush; - else if (passed ) std::cout << state->green (" [PASSED]" ) << std::endl << std::flush; - else if (ignoreFailure) std::cout << state->yellow(" [FAILED] (ignored)") << std::endl << std::flush; - else std::cout << state->red (" [FAILED]" ) << std::endl << std::flush; - } - - /* update passed/failed counters */ - state->numPassedTests += passed; - if (ignoreFailure) state->numFailedAndIgnoredTests += !passed; - else state->numFailedTests += !passed; - - /* do ignore failures for some specific tests */ - if (ignoreFailure) - passed = true; - - return passed ? PASSED : FAILED; - } - - double VerifyApplication::Benchmark::readDatabase(VerifyApplication* state) - { - std::fstream db; - FileName base = state->database+FileName(name); - db.open(base.addExt(".txt"), std::fstream::in); - double start_value = higher_is_better ? double(neg_inf) : double(pos_inf); - if (!db.is_open()) return start_value; - - double bestAvg = start_value; - while (true) - { - std::string line; std::getline(db,line); - if (db.eof()) break; - if (line == "") { bestAvg = start_value; continue; } - std::stringstream linestream(line); - std::string hash; linestream >> hash; - double avg; linestream >> avg; - if (higher_is_better) { - if (avg > bestAvg) bestAvg = avg; - } else { - if (avg < bestAvg) bestAvg = avg; - } - } - db.close(); - return bestAvg; - } - - void VerifyApplication::Benchmark::updateDatabase(VerifyApplication* state, Statistics stat, double bestAvg) - { - /* load git hash from file */ - std::fstream hashFile; - std::string hash = "unknown"; - hashFile.open(FileName::executableFolder()+FileName("hash"), std::fstream::in); - if (hashFile.is_open()) { - hashFile >> hash; - hashFile.close(); - } - - /* update database */ - std::fstream db; - FileName base = state->database+FileName(name); - db.open(base.addExt(".txt"), std::fstream::out | std::fstream::app); - db << hash << " " << stat.getAvg() << " " << bestAvg << std::endl; - db.close(); - } - - void VerifyApplication::Benchmark::plotDatabase(VerifyApplication* state) - { - std::fstream plot; - FileName base = state->database+FileName(name); - plot.open(base.addExt(".plot"), std::fstream::out | std::fstream::trunc); - plot << "set terminal png size 2048,600 enhanced" << std::endl; - plot << "set output \"" << base.addExt(".png") << "\"" << std::endl; - plot << "set key inside right top vertical Right noreverse enhanced autotitles box linetype -1 linewidth 1.000" << std::endl; - plot << "set samples 50, 50" << std::endl; - //plot << "set title \"" << name << "\"" << std::endl; - //plot << "set xlabel \"" << name << "\""<< std::endl; - plot << "set xtics axis rotate by 90" << std::endl; - plot << "set ylabel \"" << unit << "\"" << std::endl; - plot << "set yrange [0:]" << std::endl; - plot << "plot \"" << FileName(name).addExt(".txt") << "\" using :2:xtic(1) title \"" << name << "\" with lines, \\" << std::endl; - plot << " \"" << FileName(name).addExt(".txt") << "\" using :3 title \"best\" with lines" << std::endl; - plot << std::endl; - plot.close(); - } - - Statistics VerifyApplication::Benchmark::benchmark_loop(VerifyApplication* state) - { - //sleepSeconds(0.1); - const size_t skipBenchmarkFrames = 1; - const size_t numBenchmarkFrames = 8; - FilteredStatistics stat(0.5f,0.0f); - size_t numTotalFrames = skipBenchmarkFrames + numBenchmarkFrames; - for (size_t i=0; idatabase != "") - avgdb = readDatabase(state); - - /* execute benchmark */ - Statistics curStat; - Statistics bestStat; - bool passed = false; - - /* retry if benchmark failed */ - //static size_t numRetries = 0; - size_t i=0; - for (; i 1000) break; - //std::cout << state->yellow(" [RETRY]" ) << " (" << 100.0f*(curStat.getAvg()-avgdb)/avgdb << "%)" << std::flush; - setup(state); - } - - try { - curStat = benchmark_loop(state); - if (i == 0) bestStat = curStat; - if (higher_is_better) { - if (curStat.getAvg() > bestStat.getAvg()) bestStat = curStat; - } else { - if (curStat.getAvg() < bestStat.getAvg()) bestStat = curStat; - } - } catch (TestReturnValue v) { - return v; - } - - /* check against database to see if test passed */ - if (state->database != "") { - if (higher_is_better) - passed = !(curStat.getAvg()-avgdb < -state->benchmark_tolerance*avgdb); // !(a < b) on purpose for nan case - else - passed = !(curStat.getAvg()-avgdb > +state->benchmark_tolerance*avgdb); // !(a > b) on purpose for nan case - } - else - passed = true; - } - - if (state->database == "" || avgdb == double(neg_inf)) - avgdb = bestStat.getAvg(); - - /* update database */ - if (state->database != "" && state->update_database) - updateDatabase(state,bestStat,avgdb); - - /* print test result */ - std::cout << std::setw(8) << std::setprecision(3) << std::fixed << bestStat.getAvg() << " " << unit << " (+/-" << 100.0f*bestStat.getAvgSigma()/bestStat.getAvg() << "%)"; - if (passed) std::cout << state->green(" [PASSED]" ) << " (" << 100.0f*(bestStat.getAvg()-avgdb)/avgdb << "%) (" << i << " attempts)" << std::endl << std::flush; - else std::cout << state->red (" [FAILED]" ) << " (" << 100.0f*(bestStat.getAvg()-avgdb)/avgdb << "%) (" << i << " attempts)" << std::endl << std::flush; - if (state->database != "") - plotDatabase(state); - - /* print dart measurement */ - if (state->cdash) - { - //std::cout << "" << bestStat.getAvg() << "" << std::endl; - //std::cout << "" << bestStat.getAvgSigma() << "" << std::endl; - - /* send plot only when test failed */ - if (!passed) - { - FileName base = state->database+FileName(name); - std::string command = std::string("cd ")+state->database.str()+std::string(" && gnuplot ") + FileName(name).addExt(".plot").str(); - if (system(command.c_str()) == 0) - std::cout << "" << base.addExt(".png") << "" << std::endl; - } - } - - sleepSeconds(0.1); - cleanup(state); - - /* update passed/failed counters */ - state->numPassedTests += passed; - state->numFailedTests += !passed; - return passed ? PASSED : FAILED; - } - catch (const std::exception& e) - { - std::cout << std::setw(TEXT_ALIGN) << name << ": " << std::flush; - std::cout << state->red(" [FAILED] ") << "(" << e.what() << ")" << std::endl << std::flush; - state->numFailedTests++; - return VerifyApplication::FAILED; - } - catch (...) - { - std::cout << std::setw(TEXT_ALIGN) << name << ": " << std::flush; - std::cout << state->red(" [FAILED] ") << " (unknown error)" << std::endl << std::flush; - state->numFailedTests++; - return VerifyApplication::FAILED; - } - - VerifyApplication::TestReturnValue VerifyApplication::TestGroup::execute(VerifyApplication* state, bool silent_in) - { - if (!isEnabled()) - return SKIPPED; - - bool leaftest = state->flatten && !silent_in && silent; - bool nextsilent = silent_in || (state->flatten && silent); - if (leaftest) - std::cout << std::setw(TEXT_ALIGN) << name << " ..." << std::flush; - - std::atomic passed(true); - - if (state->parallel && parallel && leaftest) - { - parallel_for(tests.size(),[&] (size_t i) { - passed.fetch_and(tests[i]->execute(state,nextsilent) != FAILED); - }); - } - else { - for (auto& test : tests) - passed.fetch_and(test->execute(state,nextsilent) != FAILED); - } - - if (leaftest) { - if (passed) std::cout << state->green(" [PASSED]") << std::endl << std::flush; - else std::cout << state->red (" [FAILED]") << std::endl << std::flush; - } - - return passed ? PASSED : FAILED; - } - - RTCAlgorithmFlags aflags = (RTCAlgorithmFlags) (RTC_INTERSECT1 | RTC_INTERSECT4 | RTC_INTERSECT8 | RTC_INTERSECT16); - RTCAlgorithmFlags aflags_all = (RTCAlgorithmFlags) (RTC_INTERSECT1 | RTC_INTERSECT4 | RTC_INTERSECT8 | RTC_INTERSECT16 | RTC_INTERSECT_STREAM); - - ///////////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////// - - struct InitExitTest : public VerifyApplication::Test - { - InitExitTest (std::string name) - : VerifyApplication::Test(name,0,VerifyApplication::TEST_SHOULD_PASS) {} - - VerifyApplication::TestReturnValue run(VerifyApplication* state, bool silent) - { - rtcInit("verbose=1"); - errorHandler(rtcGetError()); - rtcExit(); - return VerifyApplication::PASSED; - } - }; - - struct EmbreeInternalTest : public VerifyApplication::Test - { - EmbreeInternalTest (std::string name, size_t testID) - : VerifyApplication::Test(name,0,VerifyApplication::TEST_SHOULD_PASS), testID(testID) {} - - VerifyApplication::TestReturnValue run(VerifyApplication* state, bool silent) - { - RTCDeviceRef device = rtcNewDevice(state->rtcore.c_str()); - AssertNoError(device); - return (VerifyApplication::TestReturnValue)rtcDeviceGetParameter1i(device,(RTCParameter)(3000000+testID)); - } - - size_t testID; - }; - - struct MultipleDevicesTest : public VerifyApplication::Test - { - MultipleDevicesTest (std::string name, int isa) - : VerifyApplication::Test(name,isa,VerifyApplication::TEST_SHOULD_PASS) {} - - VerifyApplication::TestReturnValue run(VerifyApplication* state, bool silent) - { - std::string cfg = state->rtcore + ",isa="+stringOfISA(isa); - RTCDevice device1 = rtcNewDevice(cfg.c_str()); - AssertNoError(device1); - RTCDevice device2 = rtcNewDevice(cfg.c_str()); - AssertNoError(device2); - RTCDevice device3 = rtcNewDevice(cfg.c_str()); - AssertNoError(device3); - rtcDeleteDevice(device1); - rtcDeleteDevice(device3); - rtcDeleteDevice(device2); - return VerifyApplication::PASSED; - } - }; - - struct FlagsTest : public VerifyApplication::Test - { - RTCSceneFlags sceneFlags; - RTCGeometryFlags geomFlags; - - FlagsTest (std::string name, int isa, VerifyApplication::TestType type, RTCSceneFlags sceneFlags, RTCGeometryFlags geomFlags) - : VerifyApplication::Test(name,isa,type), sceneFlags(sceneFlags), geomFlags(geomFlags) {} - - VerifyApplication::TestReturnValue run(VerifyApplication* state, bool silent) - { - std::string cfg = state->rtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - RTCSceneRef scene = rtcDeviceNewScene(device,sceneFlags,aflags); - AssertNoError(device); - rtcNewTriangleMesh (scene, geomFlags, 0, 0); - AssertNoError(device); - rtcNewHairGeometry (scene, geomFlags, 0, 0); - AssertNoError(device); - rtcCommit (scene); - AssertNoError(device); - return VerifyApplication::PASSED; - } - }; - - struct UnmappedBeforeCommitTest : public VerifyApplication::Test - { - UnmappedBeforeCommitTest (std::string name, int isa) - : VerifyApplication::Test(name,isa,VerifyApplication::TEST_SHOULD_PASS) {} - - VerifyApplication::TestReturnValue run(VerifyApplication* state, bool silent) - { - std::string cfg = state->rtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - VerifyScene scene(device,RTC_SCENE_STATIC,aflags); - AssertNoError(device); - unsigned geom0 = scene.addSphere(sampler,RTC_GEOMETRY_STATIC,zero,1.0f,50).first; - unsigned geom1 = scene.addSphere(sampler,RTC_GEOMETRY_STATIC,zero,1.0f,50).first; - AssertNoError(device); - rtcMapBuffer(scene,geom0,RTC_INDEX_BUFFER); - rtcMapBuffer(scene,geom1,RTC_VERTEX_BUFFER); - AssertNoError(device); - rtcCommit (scene); - AssertError(device,RTC_INVALID_OPERATION); // error, buffers still mapped - return VerifyApplication::PASSED; - } - }; - - struct GetBoundsTest : public VerifyApplication::Test - { - GeometryType gtype; - - GetBoundsTest (std::string name, int isa, GeometryType gtype) - : VerifyApplication::Test(name,isa,VerifyApplication::TEST_SHOULD_PASS), gtype(gtype) {} - - VerifyApplication::TestReturnValue run(VerifyApplication* state, bool silent) - { - std::string cfg = state->rtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - VerifyScene scene(device,RTC_SCENE_STATIC,RTC_INTERSECT1); - AssertNoError(device); - - Ref node = nullptr; - switch (gtype) { - case TRIANGLE_MESH : node = SceneGraph::createTriangleSphere(zero,1.0f,50); break; - case TRIANGLE_MESH_MB: node = SceneGraph::createTriangleSphere(zero,1.0f,5)->set_motion_vector(Vec3fa(1.0f)); break; - case QUAD_MESH : node = SceneGraph::createQuadSphere(zero,1.0f,50); break; - case QUAD_MESH_MB : node = SceneGraph::createQuadSphere(zero,1.0f,50)->set_motion_vector(Vec3fa(1.0f)); break; - //case SUBDIV_MESH: - //case SUBDIV_MESH_MB: - default: return VerifyApplication::SKIPPED; - } - - BBox3fa bounds0 = node->bounds(); - scene.addGeometry(RTC_GEOMETRY_STATIC,node); - AssertNoError(device); - rtcCommit (scene); - AssertNoError(device); - BBox3fa bounds1; - rtcGetBounds(scene,(RTCBounds&)bounds1); - AssertNoError(device); - return (VerifyApplication::TestReturnValue)(bounds0 == bounds1); - } - }; - - struct GetLinearBoundsTest : public VerifyApplication::Test - { - GeometryType gtype; - - GetLinearBoundsTest (std::string name, int isa, GeometryType gtype) - : VerifyApplication::Test(name,isa,VerifyApplication::TEST_SHOULD_PASS), gtype(gtype) {} - - VerifyApplication::TestReturnValue run(VerifyApplication* state, bool silent) - { - std::string cfg = state->rtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - error_handler(rtcDeviceGetError(device)); - VerifyScene scene(device,RTC_SCENE_STATIC,RTC_INTERSECT1); - AssertNoError(device); - - Ref node = nullptr; - switch (gtype) { - case TRIANGLE_MESH : node = SceneGraph::createTriangleSphere(zero,1.0f,50); break; - case TRIANGLE_MESH_MB: node = SceneGraph::createTriangleSphere(zero,1.0f,50)->set_motion_vector(Vec3fa(1.0f)); break; - case QUAD_MESH : node = SceneGraph::createQuadSphere(zero,1.0f,50); break; - case QUAD_MESH_MB : node = SceneGraph::createQuadSphere(zero,1.0f,50)->set_motion_vector(Vec3fa(1.0f)); break; - //case SUBDIV_MESH: - //case SUBDIV_MESH_MB: - default: return VerifyApplication::SKIPPED; - } - - LBBox3fa bounds0 = node->lbounds(); - scene.addGeometry(RTC_GEOMETRY_STATIC,node); - AssertNoError(device); - rtcCommit (scene); - AssertNoError(device); - BBox3fa bbox[2]; - rtcGetLinearBounds(scene,(RTCBounds*)bbox); - LBBox3fa bounds1(bbox[0],bbox[1]); - AssertNoError(device); - return (VerifyApplication::TestReturnValue)(bounds0 == bounds1); - } - }; - - struct GetUserDataTest : public VerifyApplication::Test - { - GetUserDataTest (std::string name, int isa) - : VerifyApplication::Test(name,isa,VerifyApplication::TEST_SHOULD_PASS) {} - - VerifyApplication::TestReturnValue run(VerifyApplication* state, bool silent) - { - std::string cfg = state->rtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - RTCSceneRef scene = rtcDeviceNewScene(device,RTC_SCENE_STATIC,RTC_INTERSECT1); - AssertNoError(device); - - unsigned geom0 = rtcNewTriangleMesh (scene, RTC_GEOMETRY_STATIC, 0, 0, 1); - rtcSetUserData(scene,geom0,(void*)1); - unsigned geom1 = rtcNewTriangleMesh (scene, RTC_GEOMETRY_STATIC, 0, 0, 2); - rtcSetUserData(scene,geom1,(void*)2); - unsigned geom2 = rtcNewQuadMesh (scene, RTC_GEOMETRY_STATIC, 0, 0, 1); - rtcSetUserData(scene,geom2,(void*)3); - unsigned geom3 = rtcNewQuadMesh (scene, RTC_GEOMETRY_STATIC, 0, 0, 2); - rtcSetUserData(scene,geom3,(void*)4); - unsigned geom4 = rtcNewSubdivisionMesh(scene, RTC_GEOMETRY_STATIC, 0, 0, 0, 0, 0, 0, 1); - rtcSetUserData(scene,geom4,(void*)5); - unsigned geom5 = rtcNewSubdivisionMesh(scene, RTC_GEOMETRY_STATIC, 0, 0, 0, 0, 0, 0, 2); - rtcSetUserData(scene,geom5,(void*)6); - unsigned geom6 = rtcNewHairGeometry (scene, RTC_GEOMETRY_STATIC, 0, 0, 1); - rtcSetUserData(scene,geom6,(void*)7); - unsigned geom7 = rtcNewHairGeometry (scene, RTC_GEOMETRY_STATIC, 0, 0, 2); - rtcSetUserData(scene,geom7,(void*)8); - unsigned geom8 = rtcNewCurveGeometry (scene, RTC_GEOMETRY_STATIC, 0, 0, 1); - rtcSetUserData(scene,geom8,(void*)9); - unsigned geom9 = rtcNewCurveGeometry (scene, RTC_GEOMETRY_STATIC, 0, 0, 2); - rtcSetUserData(scene,geom9,(void*)10); - unsigned geom10 = rtcNewLineSegments (scene, RTC_GEOMETRY_STATIC, 0, 0, 1); - rtcSetUserData(scene,geom10,(void*)11); - unsigned geom11 = rtcNewLineSegments (scene, RTC_GEOMETRY_STATIC, 0, 0, 2); - rtcSetUserData(scene,geom11,(void*)12); - unsigned geom12 = rtcNewUserGeometry2(scene,0,1); - rtcSetUserData(scene,geom12,(void*)13); - unsigned geom13 = rtcNewUserGeometry2(scene,0,2); - rtcSetUserData(scene,geom13,(void*)14); - rtcCommit (scene); - AssertNoError(device); - - if ((size_t)rtcGetUserData(scene,geom0 ) != 1) return VerifyApplication::FAILED; - if ((size_t)rtcGetUserData(scene,geom1 ) != 2) return VerifyApplication::FAILED; - if ((size_t)rtcGetUserData(scene,geom2 ) != 3) return VerifyApplication::FAILED; - if ((size_t)rtcGetUserData(scene,geom3 ) != 4) return VerifyApplication::FAILED; - if ((size_t)rtcGetUserData(scene,geom4 ) != 5) return VerifyApplication::FAILED; - if ((size_t)rtcGetUserData(scene,geom5 ) != 6) return VerifyApplication::FAILED; - if ((size_t)rtcGetUserData(scene,geom6 ) != 7) return VerifyApplication::FAILED; - if ((size_t)rtcGetUserData(scene,geom7 ) != 8) return VerifyApplication::FAILED; - if ((size_t)rtcGetUserData(scene,geom8 ) != 9) return VerifyApplication::FAILED; - if ((size_t)rtcGetUserData(scene,geom9 ) != 10) return VerifyApplication::FAILED; - if ((size_t)rtcGetUserData(scene,geom10) != 11) return VerifyApplication::FAILED; - if ((size_t)rtcGetUserData(scene,geom11) != 12) return VerifyApplication::FAILED; - if ((size_t)rtcGetUserData(scene,geom12) != 13) return VerifyApplication::FAILED; - if ((size_t)rtcGetUserData(scene,geom13) != 14) return VerifyApplication::FAILED; - AssertNoError(device); - - return VerifyApplication::PASSED; - } - }; - - struct BufferStrideTest : public VerifyApplication::Test - { - GeometryType gtype; - - BufferStrideTest (std::string name, int isa, GeometryType gtype) - : VerifyApplication::Test(name,isa,VerifyApplication::TEST_SHOULD_PASS), gtype(gtype) {} - - VerifyApplication::TestReturnValue run(VerifyApplication* state, bool silent) - { - std::string cfg = state->rtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - RTCSceneRef scene = rtcDeviceNewScene(device,RTC_SCENE_STATIC,aflags); - AssertNoError(device); - - unsigned geomID = RTC_INVALID_GEOMETRY_ID; - switch (gtype) { - case TRIANGLE_MESH : geomID = rtcNewTriangleMesh (scene, RTC_GEOMETRY_STATIC, 16, 16, 1); break; - case TRIANGLE_MESH_MB : geomID = rtcNewTriangleMesh (scene, RTC_GEOMETRY_STATIC, 16, 16, 2); break; - case QUAD_MESH : geomID = rtcNewQuadMesh (scene, RTC_GEOMETRY_STATIC, 16, 16, 1); break; - case QUAD_MESH_MB : geomID = rtcNewQuadMesh (scene, RTC_GEOMETRY_STATIC, 16, 16, 2); break; - case SUBDIV_MESH : geomID = rtcNewSubdivisionMesh(scene, RTC_GEOMETRY_STATIC, 0, 16, 16, 0,0,0, 1); break; - case SUBDIV_MESH_MB : geomID = rtcNewSubdivisionMesh(scene, RTC_GEOMETRY_STATIC, 0, 16, 16, 0,0,0, 2); break; - case HAIR_GEOMETRY : geomID = rtcNewHairGeometry (scene, RTC_GEOMETRY_STATIC, 16, 16, 1); break; - case HAIR_GEOMETRY_MB : geomID = rtcNewHairGeometry (scene, RTC_GEOMETRY_STATIC, 16, 16, 2); break; - case CURVE_GEOMETRY : geomID = rtcNewCurveGeometry (scene, RTC_GEOMETRY_STATIC, 16, 16, 1); break; - case CURVE_GEOMETRY_MB: geomID = rtcNewCurveGeometry (scene, RTC_GEOMETRY_STATIC, 16, 16, 2); break; - default : throw std::runtime_error("unknown geometry type: "+to_string(gtype)); - } - AssertNoError(device); - - avector indexBuffer(8+16*6*sizeof(int)); - avector vertexBuffer(12+16*9*sizeof(float)+4); - - rtcSetBuffer(scene,geomID,RTC_INDEX_BUFFER,indexBuffer.data(),1,3*sizeof(int)); - AssertError(device,RTC_INVALID_OPERATION); - rtcSetBuffer(scene,geomID,RTC_VERTEX_BUFFER,vertexBuffer.data(),1,3*sizeof(float)); - AssertError(device,RTC_INVALID_OPERATION); - - rtcSetBuffer(scene,geomID,RTC_INDEX_BUFFER,indexBuffer.data(),0,3*sizeof(int)+3); - AssertError(device,RTC_INVALID_OPERATION); - rtcSetBuffer(scene,geomID,RTC_VERTEX_BUFFER,vertexBuffer.data(),0,3*sizeof(float)+3); - AssertError(device,RTC_INVALID_OPERATION); - - rtcSetBuffer(scene,geomID,RTC_INDEX_BUFFER,indexBuffer.data(),0,3*sizeof(int)); - AssertNoError(device); - rtcSetBuffer(scene,geomID,RTC_VERTEX_BUFFER,vertexBuffer.data(),0,3*sizeof(float)); - AssertNoError(device); - - rtcSetBuffer(scene,geomID,RTC_INDEX_BUFFER,indexBuffer.data(),8,6*sizeof(int)); - AssertNoError(device); - rtcSetBuffer(scene,geomID,RTC_VERTEX_BUFFER,vertexBuffer.data(),12,9*sizeof(float)); - AssertNoError(device); - - rtcSetBuffer(scene,geomID,RTC_INDEX_BUFFER,indexBuffer.data(),0,3*sizeof(int)); - AssertNoError(device); - - rtcSetBuffer(scene,geomID,RTC_VERTEX_BUFFER,vertexBuffer.data(),0,4*sizeof(float)); - AssertNoError(device); - - return VerifyApplication::PASSED; - } - }; - - ///////////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////// - - struct EmptySceneTest : public VerifyApplication::Test - { - EmptySceneTest (std::string name, int isa, RTCSceneFlags sflags) - : VerifyApplication::Test(name,isa,VerifyApplication::TEST_SHOULD_PASS), sflags(sflags) {} - - VerifyApplication::TestReturnValue run(VerifyApplication* state, bool silent) - { - std::string cfg = state->rtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - RTCSceneRef scene = rtcDeviceNewScene(device,sflags,aflags); - AssertNoError(device); - rtcCommit (scene); - AssertNoError(device); - return VerifyApplication::PASSED; - } - - public: - RTCSceneFlags sflags; - }; - - struct EmptyGeometryTest : public VerifyApplication::Test - { - RTCSceneFlags sflags; - RTCGeometryFlags gflags; - - EmptyGeometryTest (std::string name, int isa, RTCSceneFlags sflags, RTCGeometryFlags gflags) - : VerifyApplication::Test(name,isa,VerifyApplication::TEST_SHOULD_PASS), sflags(sflags), gflags(gflags) {} - - VerifyApplication::TestReturnValue run(VerifyApplication* state, bool silent) - { - std::string cfg = state->rtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - RTCSceneRef scene = rtcDeviceNewScene(device,sflags,aflags); - rtcNewTriangleMesh (scene,gflags,0,0,1); - rtcNewTriangleMesh (scene,gflags,0,0,2); - rtcNewQuadMesh (scene,gflags,0,0,1); - rtcNewQuadMesh (scene,gflags,0,0,2); - rtcNewSubdivisionMesh (scene,gflags,0,0,0,0,0,0,1); - rtcNewSubdivisionMesh (scene,gflags,0,0,0,0,0,0,2); - rtcNewHairGeometry (scene,gflags,0,0,1); - rtcNewHairGeometry (scene,gflags,0,0,2); - rtcNewCurveGeometry (scene,gflags,0,0,1); - rtcNewCurveGeometry (scene,gflags,0,0,2); - rtcNewUserGeometry2 (scene,0,1); - rtcNewUserGeometry2 (scene,0,2); - rtcCommit (scene); - AssertNoError(device); - return VerifyApplication::PASSED; - } - }; - - struct BuildTest : public VerifyApplication::Test - { - RTCSceneFlags sflags; - RTCGeometryFlags gflags; - - BuildTest (std::string name, int isa, RTCSceneFlags sflags, RTCGeometryFlags gflags) - : VerifyApplication::Test(name,isa,VerifyApplication::TEST_SHOULD_PASS), sflags(sflags), gflags(gflags) {} - - VerifyApplication::TestReturnValue run (VerifyApplication* state, bool silent) - { - std::string cfg = state->rtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - VerifyScene scene(device,sflags,aflags); - - const Vec3fa center = zero; - const float radius = 1.0f; - const Vec3fa dx(1,0,0); - const Vec3fa dy(0,1,0); - scene.addGeometry(gflags,SceneGraph::createTriangleSphere(center,radius,50)); - scene.addGeometry(gflags,SceneGraph::createTriangleSphere(center,radius,50)->set_motion_vector(random_motion_vector(1.0f))); - scene.addGeometry(gflags,SceneGraph::createQuadSphere(center,radius,50)); - scene.addGeometry(gflags,SceneGraph::createQuadSphere(center,radius,50)->set_motion_vector(random_motion_vector(1.0f))); - scene.addGeometry(gflags,SceneGraph::createSubdivSphere(center,radius,8,20)); - scene.addGeometry(gflags,SceneGraph::createSubdivSphere(center,radius,8,20)->set_motion_vector(random_motion_vector(1.0f))); - scene.addGeometry(gflags,SceneGraph::createHairyPlane(RandomSampler_getInt(sampler),center,dx,dy,0.1f,0.01f,100,true)); - scene.addGeometry(gflags,SceneGraph::createHairyPlane(RandomSampler_getInt(sampler),center,dx,dy,0.1f,0.01f,100,true)->set_motion_vector(random_motion_vector(1.0f))); - rtcCommit (scene); - AssertNoError(device); - - if ((sflags & RTC_SCENE_DYNAMIC) == 0) - { - for (unsigned int i=0; i<8; i++) { - rtcDisable(scene,i); - AssertAnyError(device); - } - } - AssertNoError(device); - - return VerifyApplication::PASSED; - } - }; - - struct OverlappingGeometryTest : public VerifyApplication::Test - { - RTCSceneFlags sflags; - RTCGeometryFlags gflags; - size_t N; - - OverlappingGeometryTest (std::string name, int isa, RTCSceneFlags sflags, RTCGeometryFlags gflags, size_t N) - : VerifyApplication::Test(name,isa,VerifyApplication::TEST_SHOULD_PASS), sflags(sflags), gflags(gflags), N(N) {} - - VerifyApplication::TestReturnValue run(VerifyApplication* state, bool silent) - { - std::string cfg = state->rtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - VerifyScene scene(device,sflags,aflags); - AssertNoError(device); - - const Vec3fa p (0,0,0); - const Vec3fa dx(1,0,0); - const Vec3fa dy(0,1,0); - - Ref trimesh = SceneGraph::createTrianglePlane(p,dx,dy,1,1).dynamicCast(); - for (size_t i=0; itriangles.push_back(trimesh->triangles.back()); - scene.addGeometry(gflags,trimesh.dynamicCast()); - - Ref trimesh2 = SceneGraph::createTrianglePlane(p,dx,dy,1,1)->set_motion_vector(random_motion_vector(1.0f)).dynamicCast(); - for (size_t i=0; itriangles.push_back(trimesh2->triangles.back()); - scene.addGeometry(gflags,trimesh2.dynamicCast()); - - Ref quadmesh = SceneGraph::createQuadPlane(p,dx,dy,1,1).dynamicCast(); - for (size_t i=0; iquads.push_back(quadmesh->quads.back()); - scene.addGeometry(gflags,quadmesh.dynamicCast()); - - Ref quadmesh2 = SceneGraph::createQuadPlane(p,dx,dy,1,1)->set_motion_vector(random_motion_vector(1.0f)).dynamicCast(); - for (size_t i=0; iquads.push_back(quadmesh2->quads.back()); - scene.addGeometry(gflags,quadmesh2.dynamicCast()); - - Ref subdivmesh = new SceneGraph::SubdivMeshNode(nullptr,1); - for (unsigned i=0; iverticesPerFace.push_back(4); - subdivmesh->position_indices.push_back(4*i+0); - subdivmesh->position_indices.push_back(4*i+1); - subdivmesh->position_indices.push_back(4*i+2); - subdivmesh->position_indices.push_back(4*i+3); - subdivmesh->positions[0].push_back(Vec3fa(0,0,0)); - subdivmesh->positions[0].push_back(Vec3fa(0,1,0)); - subdivmesh->positions[0].push_back(Vec3fa(1,1,0)); - subdivmesh->positions[0].push_back(Vec3fa(1,0,0)); - } - scene.addGeometry(gflags,subdivmesh.dynamicCast()); - - Ref subdivmesh2 = new SceneGraph::SubdivMeshNode(nullptr,1); - for (unsigned i=0; iverticesPerFace.push_back(4); - subdivmesh2->position_indices.push_back(4*i+0); - subdivmesh2->position_indices.push_back(4*i+1); - subdivmesh2->position_indices.push_back(4*i+2); - subdivmesh2->position_indices.push_back(4*i+3); - subdivmesh2->positions[0].push_back(Vec3fa(0,0,0)); - subdivmesh2->positions[0].push_back(Vec3fa(0,1,0)); - subdivmesh2->positions[0].push_back(Vec3fa(1,1,0)); - subdivmesh2->positions[0].push_back(Vec3fa(1,0,0)); - } - subdivmesh2->set_motion_vector(random_motion_vector(1.0f)); - scene.addGeometry(gflags,subdivmesh2.dynamicCast()); - - Ref hairgeom = SceneGraph::createHairyPlane(RandomSampler_getInt(sampler),p,dx,dy,0.2f,0.01f,1,true).dynamicCast(); - for (size_t i=0; ihairs.push_back(hairgeom->hairs.back()); - scene.addGeometry(gflags,hairgeom.dynamicCast()); - - Ref hairgeom2 = SceneGraph::createHairyPlane(RandomSampler_getInt(sampler),p,dx,dy,0.2f,0.01f,1,true)->set_motion_vector(random_motion_vector(1.0f)).dynamicCast(); - for (size_t i=0; ihairs.push_back(hairgeom2->hairs.back()); - scene.addGeometry(gflags,hairgeom2.dynamicCast()); - - Ref curvegeom = SceneGraph::convert_hair_to_curves(hairgeom.dynamicCast()); - scene.addGeometry(gflags,curvegeom); - - Ref curvegeom2 = SceneGraph::convert_hair_to_curves(hairgeom2.dynamicCast()); - scene.addGeometry(gflags,curvegeom2); - - Ref linegeom = SceneGraph::convert_bezier_to_lines(hairgeom.dynamicCast()); - scene.addGeometry(gflags,linegeom); - - Ref linegeom2 = SceneGraph::convert_bezier_to_lines(hairgeom2.dynamicCast()); - scene.addGeometry(gflags,linegeom2); - - rtcCommit (scene); - AssertNoError(device); - return VerifyApplication::PASSED; - } - }; - - static std::atomic memory_consumption_bytes_used(0); - - struct MemoryConsumptionTest : public VerifyApplication::Test - { - GeometryType gtype; - RTCSceneFlags sflags; - RTCGeometryFlags gflags; - - MemoryConsumptionTest (std::string name, int isa, GeometryType gtype, RTCSceneFlags sflags, RTCGeometryFlags gflags) - : VerifyApplication::Test(name,isa,VerifyApplication::TEST_SHOULD_PASS), gtype(gtype), sflags(sflags), gflags(gflags) {} - - static bool memoryMonitor(const ssize_t bytes, const bool /*post*/) - { - memory_consumption_bytes_used += bytes; - return true; - } - - std::pair run_build(VerifyApplication* state, size_t N, unsigned numThreads) - { - //if (numThreads != 1) numThreads = 2; - std::string cfg = state->rtcore + ",isa="+stringOfISA(isa) + ",threads="+std::to_string((long long)numThreads); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - memory_consumption_bytes_used = 0; - rtcDeviceSetMemoryMonitorFunction(device,memoryMonitor); - VerifyScene scene(device,sflags,aflags); - AssertNoError(device); - - int numPhi = (size_t) ceilf(sqrtf(N/4.0f)); - ssize_t NN = 0; - - Ref mesh; - int i = 0; - switch (gtype) { - case TRIANGLE_MESH: - case TRIANGLE_MESH_MB: mesh = SceneGraph::createTriangleSphere(zero,float(i+1),numPhi); - NN = 4*numPhi*numPhi; break; - case QUAD_MESH: - case QUAD_MESH_MB: mesh = SceneGraph::createQuadSphere(zero,float(i+1),numPhi); - NN = 2*numPhi*numPhi; break; - case SUBDIV_MESH: - case SUBDIV_MESH_MB: mesh = SceneGraph::createSubdivSphere(zero,float(i+1),8,float(numPhi)/8.0f); - NN = 2*8*8; break; - case HAIR_GEOMETRY: - case HAIR_GEOMETRY_MB: mesh = SceneGraph::createHairyPlane(i,Vec3fa(float(i)),Vec3fa(1,0,0),Vec3fa(0,1,0),0.01f,0.00001f,4*numPhi*numPhi,true); - NN = 4*numPhi*numPhi; break; - case LINE_GEOMETRY: - case LINE_GEOMETRY_MB: mesh = SceneGraph::createHairyPlane(i,Vec3fa(float(i)),Vec3fa(1,0,0),Vec3fa(0,1,0),0.01f,0.00001f,4*numPhi*numPhi/3,true); - NN = (4*numPhi*numPhi/3)*3; break; - default: throw std::runtime_error("invalid geometry for benchmark"); - } - - switch (gtype) { - case LINE_GEOMETRY: - case LINE_GEOMETRY_MB: mesh = SceneGraph::convert_bezier_to_lines(mesh); break; - default: break; - } - - switch (gtype) { - case TRIANGLE_MESH_MB: - case QUAD_MESH_MB: - case SUBDIV_MESH_MB: - case HAIR_GEOMETRY_MB: - case LINE_GEOMETRY_MB: mesh = mesh->set_motion_vector(random_motion_vector2(0.0001f)); break; - default: break; - } - - scene.addGeometry(gflags,mesh); - rtcCommit (scene); - AssertNoError(device); - - return std::make_pair(NN,memory_consumption_bytes_used.load()); - } - - VerifyApplication::TestReturnValue run(VerifyApplication* state, bool silent) - { - for (size_t N=128; N<100000; N = (size_t)((float)N * 1.2f)) - { - auto bytes_one_thread = run_build(state,N,1); - auto bytes_all_threads = run_build(state,N,0); - double overhead = double(bytes_all_threads.second)/double(bytes_one_thread.second); - //std::cout << "N = " << bytes_one_thread.first << ", 1 thread = " << 1E-6*bytes_one_thread.second << " MB, all_threads = " << 1E-6*bytes_all_threads.second << " MB (" << 100.0f*overhead << " %)" << std::endl; - - /* right now we use a 38% overhead threshold, FIXME: investigate growSize for quads/line builders */ - if (overhead > 1.38f) { - return VerifyApplication::FAILED; } - } - return VerifyApplication::PASSED; - } - }; - - struct NewDeleteGeometryTest : public VerifyApplication::Test - { - RTCSceneFlags sflags; - - NewDeleteGeometryTest (std::string name, int isa, RTCSceneFlags sflags) - : VerifyApplication::Test(name,isa,VerifyApplication::TEST_SHOULD_PASS), sflags(sflags) {} - - VerifyApplication::TestReturnValue run(VerifyApplication* state, bool silent) - { - std::string cfg = state->rtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - VerifyScene scene(device,sflags,aflags_all); - AssertNoError(device); - int geom[128]; - for (size_t i=0; i<128; i++) geom[i] = -1; - Sphere spheres[128]; - memset(spheres,0,sizeof(spheres)); - - for (size_t i=0; iintensity); i++) - { - for (size_t j=0; j<10; j++) { - int index = random_int()%128; - Vec3fa pos = 100.0f*random_Vec3fa(); - if (geom[index] == -1) { - switch (random_int()%9) { - case 0: geom[index] = scene.addSphere(sampler,RTC_GEOMETRY_STATIC,pos,2.0f,10).first; break; - case 1: geom[index] = scene.addSphere(sampler,RTC_GEOMETRY_STATIC,pos,2.0f,10,-1,random_motion_vector(1.0f)).first; break; - case 2: geom[index] = scene.addQuadSphere(sampler,RTC_GEOMETRY_STATIC,pos,2.0f,10).first; break; - case 3: geom[index] = scene.addQuadSphere(sampler,RTC_GEOMETRY_STATIC,pos,2.0f,10,-1,random_motion_vector(1.0f)).first; break; - case 4: geom[index] = scene.addHair (sampler,RTC_GEOMETRY_STATIC,pos,1.0f,2.0f,10).first; break; - case 5: geom[index] = scene.addHair (sampler,RTC_GEOMETRY_STATIC,pos,1.0f,2.0f,10,random_motion_vector(1.0f)).first; break; - case 6: geom[index] = scene.addSubdivSphere(sampler,RTC_GEOMETRY_STATIC,pos,2.0f,4,4).first; break; - case 7: geom[index] = scene.addSubdivSphere(sampler,RTC_GEOMETRY_STATIC,pos,2.0f,4,4,-1,random_motion_vector(1.0f)).first; break; - case 8: - spheres[index] = Sphere(pos,2.0f); - geom[index] = scene.addUserGeometryEmpty(sampler,RTC_GEOMETRY_STATIC,&spheres[index]).first; break; - } - AssertNoError(device); - } - else { - rtcDeleteGeometry(scene,geom[index]); - AssertNoError(device); - geom[index] = -1; - } - } - rtcCommit(scene); - AssertNoError(device); - rtcCommit(scene); - AssertNoError(device); - if (i%2 == 0) std::cout << "." << std::flush; - } - - /* now delete all geometries */ - for (size_t i=0; i<128; i++) - if (geom[i] != -1) rtcDeleteGeometry(scene,geom[i]); - rtcCommit(scene); - AssertNoError(device); - - rtcCommit (scene); - AssertNoError(device); - - return VerifyApplication::PASSED; - } - }; - - struct EnableDisableGeometryTest : public VerifyApplication::Test - { - RTCSceneFlags sflags; - - EnableDisableGeometryTest (std::string name, int isa, RTCSceneFlags sflags) - : VerifyApplication::Test(name,isa,VerifyApplication::TEST_SHOULD_PASS), sflags(sflags) {} - - VerifyApplication::TestReturnValue run(VerifyApplication* state, bool silent) - { - std::string cfg = state->rtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - VerifyScene scene(device,sflags,aflags); - AssertNoError(device); - unsigned geom0 = scene.addSphere (sampler,RTC_GEOMETRY_STATIC,Vec3fa(-1,0,-1),1.0f,50).first; - unsigned geom1 = scene.addQuadSphere (sampler,RTC_GEOMETRY_STATIC,Vec3fa(-1,0,+1),1.0f,50).first; - unsigned geom2 = scene.addSubdivSphere(sampler,RTC_GEOMETRY_STATIC,Vec3fa(+1,0,-1),1.0f,5,4).first; - unsigned geom3 = scene.addHair (sampler,RTC_GEOMETRY_STATIC,Vec3fa(+1,0,+1),1.0f,1.0f,1).first; - AssertNoError(device); - - for (size_t i=0; i<16; i++) - { - bool enabled0 = i & 1, enabled1 = i & 2, enabled2 = i & 4, enabled3 = i & 8; - if (enabled0) rtcEnable(scene,geom0); else rtcDisable(scene,geom0); AssertNoError(device); - if (enabled1) rtcEnable(scene,geom1); else rtcDisable(scene,geom1); AssertNoError(device); - if (enabled2) rtcEnable(scene,geom2); else rtcDisable(scene,geom2); AssertNoError(device); - if (enabled3) rtcEnable(scene,geom3); else rtcDisable(scene,geom3); AssertNoError(device); - rtcCommit (scene); - AssertNoError(device); - { - RTCRay ray0 = makeRay(Vec3fa(-1,10,-1),Vec3fa(0,-1,0)); - RTCRay ray1 = makeRay(Vec3fa(-1,10,+1),Vec3fa(0,-1,0)); - RTCRay ray2 = makeRay(Vec3fa(+1,10,-1),Vec3fa(0,-1,0)); - RTCRay ray3 = makeRay(Vec3fa(+1,10,+1),Vec3fa(0,-1,0)); - rtcIntersect(scene,ray0); - rtcIntersect(scene,ray1); - rtcIntersect(scene,ray2); - rtcIntersect(scene,ray3); - bool ok0 = enabled0 ? ray0.geomID == 0 : ray0.geomID == RTC_INVALID_GEOMETRY_ID; - bool ok1 = enabled1 ? ray1.geomID == 1 : ray1.geomID == RTC_INVALID_GEOMETRY_ID; - bool ok2 = enabled2 ? ray2.geomID == 2 : ray2.geomID == RTC_INVALID_GEOMETRY_ID; - bool ok3 = enabled3 ? ray3.geomID == 3 : ray3.geomID == RTC_INVALID_GEOMETRY_ID; - if (!ok0 || !ok1 || !ok2 || !ok3) return VerifyApplication::FAILED; - } - } - AssertNoError(device); - - return VerifyApplication::PASSED; - } - }; - - struct UpdateTest : public VerifyApplication::IntersectTest - { - RTCSceneFlags sflags; - RTCGeometryFlags gflags; - - UpdateTest (std::string name, int isa, RTCSceneFlags sflags, RTCGeometryFlags gflags, IntersectMode imode, IntersectVariant ivariant) - : VerifyApplication::IntersectTest(name,isa,imode,ivariant,VerifyApplication::TEST_SHOULD_PASS), sflags(sflags), gflags(gflags) {} - - static void move_mesh(const VerifyScene& scene, unsigned mesh, size_t numVertices, Vec3fa& pos) - { - Vec3fa* vertices = (Vec3fa*) rtcMapBuffer(scene,mesh,RTC_VERTEX_BUFFER); - for (size_t i=0; irtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - if (!supportsIntersectMode(device,imode)) - return VerifyApplication::SKIPPED; - - VerifyScene scene(device,sflags,to_aflags(imode)); - AssertNoError(device); - size_t numPhi = 10; - size_t numVertices = 2*numPhi*(numPhi+1); - Vec3fa pos0 = Vec3fa(-10,0,-10); - Vec3fa pos1 = Vec3fa(-10,0,+10); - Vec3fa pos2 = Vec3fa(+10,0,-10); - Vec3fa pos3 = Vec3fa(+10,0,+10); - unsigned geom0 = scene.addSphere (sampler,gflags,pos0,1.0f,numPhi).first; - unsigned geom1 = scene.addQuadSphere (sampler,gflags,pos1,1.0f,numPhi).first; - unsigned geom2 = scene.addSubdivSphere(sampler,gflags,pos2,1.0f,numPhi,4).first; - unsigned geom3 = scene.addSphereHair (sampler,gflags,pos3,1.0f).first; - AssertNoError(device); - - for (size_t i=0; i<16; i++) - { - bool move0 = i & 1, move1 = i & 2, move2 = i & 4, move3 = i & 8; - Vec3fa ds(2,0.1f,2); - if (move0) { move_mesh(scene,geom0,numVertices,ds); pos0 += ds; } - if (move1) { move_mesh(scene,geom1,numVertices,ds); pos1 += ds; } - if (move2) { move_mesh(scene,geom2,numVertices,ds); pos2 += ds; } - if (move3) { move_mesh(scene,geom3,4,ds); pos3 += ds; } - rtcCommit (scene); - AssertNoError(device); - - RTCRay ray0 = makeRay(pos0+Vec3fa(0,10,0),Vec3fa(0,-1,0)); // hits geomID == 0 - RTCRay ray1 = makeRay(pos1+Vec3fa(0,10,0),Vec3fa(0,-1,0)); // hits geomID == 1 - RTCRay ray2 = makeRay(pos2+Vec3fa(0,10,0),Vec3fa(0,-1,0)); // hits geomID == 2 - RTCRay ray3 = makeRay(pos3+Vec3fa(0,10,0),Vec3fa(0,-1,0)); // hits geomID == 3 - RTCRay testRays[4] = { ray0, ray1, ray2, ray3 }; - - const size_t maxRays = 100; - RTCRay rays[maxRays]; - for (size_t numRays=1; numRaysrtcore + "isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - - for (size_t i=0; iintensity); i++) - { - RandomSampler_init(sampler,int(i*23565)); - if (i%20 == 0) std::cout << "." << std::flush; - - RTCSceneFlags sflag = getSceneFlag(i); - VerifyScene scene(device,sflag,aflags); - AssertNoError(device); - - for (size_t j=0; j<20; j++) - { - size_t numPrimitives = random_int()%256; - switch (random_int()%8) { - case 0: scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createGarbageTriangleMesh(random_int(),numPrimitives,false)); break; - case 1: scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createGarbageTriangleMesh(random_int(),numPrimitives,true )); break; - case 2: scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createGarbageQuadMesh(random_int(),numPrimitives,false)); break; - case 3: scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createGarbageQuadMesh(random_int(),numPrimitives,true )); break; - case 4: scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createGarbageHair(random_int(),numPrimitives,false)); break; - case 5: scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createGarbageHair(random_int(),numPrimitives,true )); break; - case 6: scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createGarbageLineSegments(random_int(),numPrimitives,false)); break; - case 7: scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createGarbageLineSegments(random_int(),numPrimitives,true )); break; - //case 8: scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createGarbageSubdivMesh(random_int(),numPrimitives,false)); break; // FIXME: not working yet - //case 9: scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createGarbageSubdivMesh(random_int(),numPrimitives,true )); break; - } - AssertNoError(device); - } - - rtcCommit(scene); - AssertNoError(device); - } - AssertNoError(device); - - return VerifyApplication::PASSED; - } - }; - - ///////////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////// - - const size_t num_interpolation_vertices = 16; - const size_t num_interpolation_quad_faces = 9; - const size_t num_interpolation_triangle_faces = 18; - - __aligned(16) float interpolation_vertices[num_interpolation_vertices*3] = { - -1.0f, -1.0f, 0.0f, - 0.0f, -1.0f, 0.0f, - +1.0f, -1.0f, 0.0f, - +2.0f, -1.0f, 0.0f, - - -1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, - +1.0f, 0.0f, 0.0f, - +2.0f, 0.0f, 0.0f, - - -1.0f, +1.0f, 0.0f, - 0.0f, +1.0f, 0.0f, - +1.0f, +1.0f, 0.0f, - +2.0f, +1.0f, 0.0f, - - -1.0f, +2.0f, 0.0f, - 0.0f, +2.0f, 0.0f, - +1.0f, +2.0f, 0.0f, - +2.0f, +2.0f, 0.0f, - }; - - __aligned(16) int interpolation_quad_indices[num_interpolation_quad_faces*4] = { - 0, 1, 5, 4, - 1, 2, 6, 5, - 2, 3, 7, 6, - 4, 5, 9, 8, - 5, 6, 10, 9, - 6, 7, 11, 10, - 8, 9, 13, 12, - 9, 10, 14, 13, - 10, 11, 15, 14 - }; - - __aligned(16) int interpolation_triangle_indices[num_interpolation_triangle_faces*3] = { - 0, 1, 5, 0, 5, 4, - 1, 2, 6, 1, 6, 5, - 2, 3, 7, 2, 7, 6, - 4, 5, 9, 4, 9, 8, - 5, 6, 10, 5, 10, 9, - 6, 7, 11, 6, 11, 10, - 8, 9, 13, 8, 13, 12, - 9, 10, 14, 9, 14, 13, - 10, 11, 15, 10, 15, 14 - }; - - __aligned(16) int interpolation_quad_faces[num_interpolation_quad_faces] = { - 4, 4, 4, 4, 4, 4, 4, 4, 4 - }; - - __aligned(16) float interpolation_vertex_crease_weights[2] = { - inf, inf - }; - - __aligned(16) unsigned int interpolation_vertex_crease_indices[2] = { - 12, 15 - }; - - __aligned(16) float interpolation_edge_crease_weights[3] = { - inf, inf, inf - }; - - __aligned(16) unsigned int interpolation_edge_crease_indices[6] = - { - 8,9, 9,10, 10,11 - }; - - struct InterpolateSubdivTest : public VerifyApplication::Test - { - size_t N; - - InterpolateSubdivTest (std::string name, int isa, size_t N) - : VerifyApplication::Test(name,isa,VerifyApplication::TEST_SHOULD_PASS), N(N) {} - - bool checkInterpolation2D(const RTCSceneRef& scene, int geomID, int primID, float u, float v, int v0, RTCBufferType buffer, float* data, size_t N, size_t N_total) - { - bool passed = true; - float P[256], dPdu[256], dPdv[256]; - rtcInterpolate(scene,geomID,primID,u,v,buffer,P,dPdu,dPdv,N); - - for (size_t i=0; irtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - size_t M = num_interpolation_vertices*N+16; // padds the arrays with some valid data - - RTCSceneRef scene = rtcDeviceNewScene(device,RTC_SCENE_DYNAMIC,RTC_INTERPOLATE); - AssertNoError(device); - unsigned int geomID = rtcNewSubdivisionMesh(scene, RTC_GEOMETRY_STATIC, num_interpolation_quad_faces, num_interpolation_quad_faces*4, num_interpolation_vertices, 3, 2, 0, 1); - AssertNoError(device); - - rtcSetBuffer(scene, geomID, RTC_INDEX_BUFFER, interpolation_quad_indices , 0, sizeof(unsigned int)); - rtcSetBuffer(scene, geomID, RTC_FACE_BUFFER, interpolation_quad_faces, 0, sizeof(unsigned int)); - rtcSetBuffer(scene, geomID, RTC_EDGE_CREASE_INDEX_BUFFER, interpolation_edge_crease_indices, 0, 2*sizeof(unsigned int)); - rtcSetBuffer(scene, geomID, RTC_EDGE_CREASE_WEIGHT_BUFFER, interpolation_edge_crease_weights, 0, sizeof(float)); - rtcSetBuffer(scene, geomID, RTC_VERTEX_CREASE_INDEX_BUFFER, interpolation_vertex_crease_indices,0, sizeof(unsigned int)); - rtcSetBuffer(scene, geomID, RTC_VERTEX_CREASE_WEIGHT_BUFFER,interpolation_vertex_crease_weights,0, sizeof(float)); - AssertNoError(device); - - float* vertices0 = new float[M]; - for (size_t i=0; irtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - - size_t M = num_interpolation_vertices*N+16; // padds the arrays with some valid data - - RTCSceneRef scene = rtcDeviceNewScene(device,RTC_SCENE_DYNAMIC,RTC_INTERPOLATE); - AssertNoError(device); - unsigned int geomID = rtcNewTriangleMesh(scene, RTC_GEOMETRY_STATIC, num_interpolation_triangle_faces, num_interpolation_vertices, 1); - AssertNoError(device); - - rtcSetBuffer(scene, geomID, RTC_INDEX_BUFFER, interpolation_triangle_indices , 0, 3*sizeof(unsigned int)); - AssertNoError(device); - - float* vertices0 = new float[M]; - for (size_t i=0; irtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - - size_t M = num_interpolation_vertices*N+16; // padds the arrays with some valid data - - RTCSceneRef scene = rtcDeviceNewScene(device,RTC_SCENE_DYNAMIC,RTC_INTERPOLATE); - AssertNoError(device); - unsigned int geomID = rtcNewHairGeometry(scene, RTC_GEOMETRY_STATIC, num_interpolation_hairs, num_interpolation_hair_vertices, 1); - AssertNoError(device); - - rtcSetBuffer(scene, geomID, RTC_INDEX_BUFFER, interpolation_hair_indices , 0, sizeof(unsigned int)); - AssertNoError(device); - - float* vertices0 = new float[M]; - for (size_t i=0; i 0.999f) { u = 0.333f; v = 0.333f; } // avoid hitting edges - return c + u * (a-c) + v * (b-c); - } - - VerifyApplication::TestReturnValue run(VerifyApplication* state, bool silent) - { - std::string cfg = state->rtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - if (!supportsIntersectMode(device,imode)) - return VerifyApplication::SKIPPED; - - Vec3f vertices[3] = { - Vec3f(0.0f,0.0f,0.0f), - Vec3f(1.0f,0.0f,0.0f), - Vec3f(0.0f,1.0f,0.0f) - }; - Triangle triangles[1] = { - Triangle(0,1,2) - }; - RTCSceneRef scene = rtcDeviceNewScene(device,sflags,to_aflags(imode)); - int geomID = rtcNewTriangleMesh (scene, gflags, 1, 3); - rtcSetBuffer(scene, geomID, RTC_VERTEX_BUFFER, vertices , 0, sizeof(Vec3f)); - rtcSetBuffer(scene, geomID, RTC_INDEX_BUFFER , triangles, 0, sizeof(Triangle)); - rtcCommit (scene); - AssertNoError(device); - - float u[256], v[256]; - RTCRay rays[256]; - for (size_t i=0; i<256; i++) - { - u[i] = random_float(); - v[i] = random_float(); - Vec3fa from(0.0f,0.0f,-1.0f); - Vec3fa to = uniformSampleTriangle(vertices[1],vertices[2],vertices[0],u[i],v[i]); - rays[i] = makeRay(from,to-from); - } - IntersectWithMode(imode,ivariant,scene,rays,256); - - for (size_t i=0; i<256; i++) - { - if (rays[i].geomID != 0) return VerifyApplication::FAILED; - - if (ivariant & VARIANT_OCCLUDED) continue; - - if (rays[i].primID != 0) return VerifyApplication::FAILED; - if (abs(rays[i].u - u[i]) > 16.0f*float(ulp)) return VerifyApplication::FAILED; - if (abs(rays[i].v - v[i]) > 16.0f*float(ulp)) return VerifyApplication::FAILED; - if (abs(rays[i].tfar - 1.0f) > 16.0f*float(ulp)) return VerifyApplication::FAILED; - const Vec3fa org(rays[i].org[0],rays[i].org[1],rays[i].org[2]); - const Vec3fa dir(rays[i].dir[0],rays[i].dir[1],rays[i].dir[2]); - const Vec3fa ht = org + rays[i].tfar*dir; - const Vec3fa huv = vertices[0] + rays[i].u*(vertices[1]-vertices[0]) + rays[i].v*(vertices[2]-vertices[0]); - if (reduce_max(abs(ht-huv)) > 16.0f*float(ulp)) return VerifyApplication::FAILED; - const Vec3fa Ng = Vec3fa(rays[i].Ng[0],rays[i].Ng[1],rays[i].Ng[2]); - if (reduce_max(abs(Ng - Vec3fa(0.0f,0.0f,-1.0f))) > 16.0f*float(ulp)) return VerifyApplication::FAILED; - } - AssertNoError(device); - - return VerifyApplication::PASSED; - } - }; - - struct QuadHitTest : public VerifyApplication::IntersectTest - { - RTCSceneFlags sflags; - RTCGeometryFlags gflags; - - QuadHitTest (std::string name, int isa, RTCSceneFlags sflags, RTCGeometryFlags gflags, IntersectMode imode, IntersectVariant ivariant) - : VerifyApplication::IntersectTest(name,isa,imode,ivariant,VerifyApplication::TEST_SHOULD_PASS), sflags(sflags), gflags(gflags) {} - - VerifyApplication::TestReturnValue run(VerifyApplication* state, bool silent) - { - std::string cfg = state->rtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - if (!supportsIntersectMode(device,imode)) - return VerifyApplication::SKIPPED; - - Vec3f vertices[4] = { - Vec3f(0.0f,0.0f,0.0f), - Vec3f(1.0f,0.0f,0.0f), - Vec3f(1.0f,1.0f,0.0f), - Vec3f(0.0f,1.0f,0.0f) - }; - int quads[4] = { - 0,1,2,3 - }; - RTCSceneRef scene = rtcDeviceNewScene(device,sflags,to_aflags(imode)); - int geomID = rtcNewQuadMesh (scene, gflags, 1, 4); - rtcSetBuffer(scene, geomID, RTC_VERTEX_BUFFER, vertices , 0, sizeof(Vec3f)); - rtcSetBuffer(scene, geomID, RTC_INDEX_BUFFER , quads, 0, 4*sizeof(int)); - rtcCommit (scene); - AssertNoError(device); - - float u[256], v[256]; - RTCRay rays[256]; - for (size_t i=0; i<256; i++) - { - u[i] = random_float(); - v[i] = random_float(); - if (u[i] < 0.001f || v[i] < 0.001f || u[i] > 0.999f || v[i] > 0.999f) { u[i] = 0.333f; v[i] = 0.333f; } // avoid hitting edges - Vec3fa from(0.0f,0.0f,-1.0f); - Vec3fa to = vertices[0] + u[i]*(vertices[1]-vertices[0]) + v[i]*(vertices[3]-vertices[0]); - rays[i] = makeRay(from,to-from); - } - IntersectWithMode(imode,ivariant,scene,rays,256); - - for (size_t i=0; i<256; i++) - { - if (rays[i].geomID != 0) return VerifyApplication::FAILED; - if (ivariant & VARIANT_OCCLUDED) continue; - if (rays[i].primID != 0) return VerifyApplication::FAILED; - if (abs(rays[i].u - u[i]) > 16.0f*float(ulp)) return VerifyApplication::FAILED; - if (abs(rays[i].v - v[i]) > 16.0f*float(ulp)) return VerifyApplication::FAILED; - if (abs(rays[i].tfar - 1.0f) > 16.0f*float(ulp)) return VerifyApplication::FAILED; - - const Vec3fa org(rays[i].org[0],rays[i].org[1],rays[i].org[2]); - const Vec3fa dir(rays[i].dir[0],rays[i].dir[1],rays[i].dir[2]); - const Vec3fa ht = org + rays[i].tfar*dir; - const Vec3fa huv = vertices[0] + rays[i].u*(vertices[1]-vertices[0]) + rays[i].v*(vertices[3]-vertices[0]); - if (reduce_max(abs(ht-huv)) > 16.0f*float(ulp)) return VerifyApplication::FAILED; - const Vec3fa Ng = Vec3fa(rays[i].Ng[0],rays[i].Ng[1],rays[i].Ng[2]); - if (reduce_max(abs(Ng - Vec3fa(0.0f,0.0f,-1.0f))) > 16.0f*float(ulp)) return VerifyApplication::FAILED; - } - AssertNoError(device); - - return VerifyApplication::PASSED; - } - }; - - struct RayMasksTest : public VerifyApplication::IntersectTest - { - RTCSceneFlags sflags; - RTCGeometryFlags gflags; - - RayMasksTest (std::string name, int isa, RTCSceneFlags sflags, RTCGeometryFlags gflags, IntersectMode imode, IntersectVariant ivariant) - : VerifyApplication::IntersectTest(name,isa,imode,ivariant,VerifyApplication::TEST_SHOULD_PASS), sflags(sflags), gflags(gflags) {} - - VerifyApplication::TestReturnValue run(VerifyApplication* state, bool silent) - { - std::string cfg = state->rtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - if (!supportsIntersectMode(device,imode)) - return VerifyApplication::SKIPPED; - - bool passed = true; - Vec3fa pos0 = Vec3fa(-10,0,-10); - Vec3fa pos1 = Vec3fa(-10,0,+10); - Vec3fa pos2 = Vec3fa(+10,0,-10); - Vec3fa pos3 = Vec3fa(+10,0,+10); - - VerifyScene scene(device,sflags,to_aflags(imode)); - unsigned int geom0 = scene.addSphere (sampler,gflags,pos0,1.0f,50).first; - unsigned int geom1 = scene.addQuadSphere (sampler,gflags,pos1,1.0f,50).first; - unsigned int geom2 = scene.addSubdivSphere(sampler,gflags,pos2,1.0f,5,4).first; - unsigned int geom3 = scene.addHair (sampler,gflags,pos3,1.0f,1.0f,1).first; - rtcSetMask(scene,geom0,1); - rtcSetMask(scene,geom1,2); - rtcSetMask(scene,geom2,4); - rtcSetMask(scene,geom3,8); - rtcCommit (scene); - AssertNoError(device); - - for (unsigned i=0; i<16; i++) - { - unsigned mask0 = i; - unsigned mask1 = i+1; - unsigned mask2 = i+2; - unsigned mask3 = i+3; - unsigned masks[4] = { mask0, mask1, mask2, mask3 }; - RTCRay ray0 = makeRay(pos0+Vec3fa(0,10,0),Vec3fa(0,-1,0)); ray0.mask = mask0; - RTCRay ray1 = makeRay(pos1+Vec3fa(0,10,0),Vec3fa(0,-1,0)); ray1.mask = mask1; - RTCRay ray2 = makeRay(pos2+Vec3fa(0,10,0),Vec3fa(0,-1,0)); ray2.mask = mask2; - RTCRay ray3 = makeRay(pos3+Vec3fa(0,10,0),Vec3fa(0,-1,0)); ray3.mask = mask3; - RTCRay rays[4] = { ray0, ray1, ray2, ray3 }; - IntersectWithMode(imode,ivariant,scene,rays,4); - for (size_t j=0; j<4; j++) - passed &= masks[j] & (1<rtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - if (!supportsIntersectMode(device,imode)) - return VerifyApplication::SKIPPED; - - /* create triangle that is front facing for a right handed - coordinate system if looking along the z direction */ - VerifyScene scene(device,sflags,to_aflags(imode)); - AssertNoError(device); - const Vec3fa p0 = Vec3fa(0.0f); - const Vec3fa dx = Vec3fa(1.0f,0.0f,0.0f); - const Vec3fa dy = Vec3fa(0.0f,1.0f,0.0f); - switch (gtype) { - case TRIANGLE_MESH: scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createTrianglePlane(p0,dx,dy,1,1)); break; - case TRIANGLE_MESH_MB: scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createTrianglePlane(p0,dx,dy,1,1)->set_motion_vector(random_motion_vector(1.0f))); break; - case QUAD_MESH: scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createQuadPlane(p0,dx,dy,1,1)); break; - case QUAD_MESH_MB: scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createQuadPlane(p0,dx,dy,1,1)->set_motion_vector(random_motion_vector(1.0f))); break; - case SUBDIV_MESH: scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createSubdivPlane(p0,dx,dy,1,1,4.0f)); break; - case SUBDIV_MESH_MB: scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createSubdivPlane(p0,dx,dy,1,1,4.0f)->set_motion_vector(random_motion_vector(1.0f))); break; - default: throw std::runtime_error("unsupported geometry type: "+to_string(gtype)); - } - - AssertNoError(device); - rtcCommit (scene); - AssertNoError(device); - - const size_t numRays = 1000; - RTCRay rays[numRays]; - bool passed = true; - - for (size_t i=0; irtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - if (!supportsIntersectMode(device,imode)) - return VerifyApplication::SKIPPED; - - VerifyScene scene(device,sflags,to_aflags(imode)); - Vec3fa p0(-0.75f,-0.25f,-10.0f), dx(4,0,0), dy(0,4,0); - int geom0 = 0; - if (subdiv) geom0 = scene.addSubdivPlane (sampler,gflags, 4, p0, dx, dy).first; - else geom0 = scene.addPlane (sampler,gflags, 4, p0, dx, dy).first; - rtcSetUserData(scene,geom0,(void*)123); - - if (imode == MODE_INTERSECT1 ) { - rtcSetIntersectionFilterFunction(scene,geom0,intersectionFilter1); - rtcSetOcclusionFilterFunction (scene,geom0,intersectionFilter1); - } - else if (imode == MODE_INTERSECT4 ) { - rtcSetIntersectionFilterFunction4(scene,geom0,intersectionFilter4); - rtcSetOcclusionFilterFunction4 (scene,geom0,intersectionFilter4); - } - else if (imode == MODE_INTERSECT8 ) { - rtcSetIntersectionFilterFunction8(scene,geom0,intersectionFilter8); - rtcSetOcclusionFilterFunction8 (scene,geom0,intersectionFilter8); - } - else if (imode == MODE_INTERSECT16) { - rtcSetIntersectionFilterFunction16(scene,geom0,intersectionFilter16); - rtcSetOcclusionFilterFunction16 (scene,geom0,intersectionFilter16); - } - else { - rtcSetIntersectionFilterFunctionN (scene,geom0,intersectionFilterN); - rtcSetOcclusionFilterFunctionN (scene,geom0,intersectionFilterN); - } - rtcCommit (scene); - AssertNoError(device); - - RTCRay rays[16]; - for (unsigned int iy=0; iy<4; iy++) - { - for (unsigned int ix=0; ix<4; ix++) - { - unsigned int primID = iy*4+ix; - if (!subdiv) primID *= 2; - rays[iy*4+ix] = makeRay(Vec3fa(float(ix),float(iy),0.0f),Vec3fa(0,0,-1)); - } - } - IntersectWithMode(imode,ivariant,scene,rays,16); - - bool passed = true; - for (unsigned int iy=0; iy<4; iy++) - { - for (unsigned int ix=0; ix<4; ix++) - { - unsigned int primID = iy*4+ix; - if (!subdiv) primID *= 2; - RTCRay& ray = rays[iy*4+ix]; - bool ok = (primID & 2) ? (ray.geomID == RTC_INVALID_GEOMETRY_ID) : (ray.geomID == 0); - if (!ok) passed = false; - } - } - AssertNoError(device); - - return (VerifyApplication::TestReturnValue) passed; - } - }; - - struct InactiveRaysTest : public VerifyApplication::IntersectTest - { - RTCSceneFlags sflags; - RTCGeometryFlags gflags; - - static const size_t N = 10; - static const size_t maxStreamSize = 100; - - InactiveRaysTest (std::string name, int isa, RTCSceneFlags sflags, RTCGeometryFlags gflags, IntersectMode imode, IntersectVariant ivariant) - : VerifyApplication::IntersectTest(name,isa,imode,ivariant,VerifyApplication::TEST_SHOULD_PASS), sflags(sflags), gflags(gflags) {} - - VerifyApplication::TestReturnValue run(VerifyApplication* state, bool silent) - { - std::string cfg = state->rtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - if (!supportsIntersectMode(device,imode)) - return VerifyApplication::SKIPPED; - - Vec3fa pos = zero; - VerifyScene scene(device,sflags,to_aflags(imode)); - scene.addSphere(sampler,RTC_GEOMETRY_STATIC,pos,2.0f,50); // FIXME: use different geometries too - rtcCommit (scene); - AssertNoError(device); - - RTCRay invalid_ray; clearRay(invalid_ray); - invalid_ray.tnear = pos_inf; - invalid_ray.tfar = neg_inf; - invalid_ray = invalid_ray; - - size_t numFailures = 0; - for (size_t i=0; iintensity); i++) - { - for (size_t M=1; Mrtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - if (!supportsIntersectMode(device,imode)) - return VerifyApplication::SKIPPED; - - avector motion_vector; - motion_vector.push_back(Vec3fa(0.0f)); - motion_vector.push_back(Vec3fa(0.0f)); - - VerifyScene scene(device,sflags,to_aflags(imode)); - size_t size = state->intensity < 1.0f ? 50 : 500; - if (model == "sphere.triangles") scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createTriangleSphere(pos,2.0f,size)); - else if (model == "sphere.quads" ) scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createQuadSphere (pos,2.0f,size)); - else if (model == "sphere.subdiv" ) scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createSubdivSphere (pos,2.0f,4,64)); - else if (model == "plane.triangles" ) scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createTrianglePlane (Vec3fa(pos.x,-6.0f,-6.0f),Vec3fa(0.0f,0.0f,12.0f),Vec3fa(0.0f,12.0f,0.0f),size,size)); - else if (model == "plane.quads" ) scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createQuadPlane (Vec3fa(pos.x,-6.0f,-6.0f),Vec3fa(0.0f,0.0f,12.0f),Vec3fa(0.0f,12.0f,0.0f),size,size)); - else if (model == "plane.subdiv" ) scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createSubdivPlane (Vec3fa(pos.x,-6.0f,-6.0f),Vec3fa(0.0f,0.0f,12.0f),Vec3fa(0.0f,12.0f,0.0f),size,size,2)); - else if (model == "sphere.triangles_mb") scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createTriangleSphere(pos,2.0f,size)->set_motion_vector(motion_vector)); - else if (model == "sphere.quads_mb" ) scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createQuadSphere (pos,2.0f,size)->set_motion_vector(motion_vector)); - else if (model == "plane.triangles_mb" ) scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createTrianglePlane (Vec3fa(pos.x,-6.0f,-6.0f),Vec3fa(0.0f,0.0f,12.0f),Vec3fa(0.0f,12.0f,0.0f),size,size)->set_motion_vector(motion_vector)); - else if (model == "plane.quads_mb" ) scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createQuadPlane (Vec3fa(pos.x,-6.0f,-6.0f),Vec3fa(0.0f,0.0f,12.0f),Vec3fa(0.0f,12.0f,0.0f),size,size)->set_motion_vector(motion_vector)); - bool plane = model.compare(0,5,"plane") == 0; - rtcCommit (scene); - AssertNoError(device); - - size_t numTests = 0; - size_t numFailures = 0; - for (auto ivariant : state->intersectVariants) - for (size_t i=0; iintensity); i++) - { - for (size_t M=1; M 0.00002; - if (!silent) { printf(" (%f%%)", 100.0f*failRate); fflush(stdout); } - return (VerifyApplication::TestReturnValue)(!failed); - } - }; - - struct SmallTriangleHitTest : public VerifyApplication::IntersectTest - { - ALIGNED_STRUCT; - RTCSceneFlags sflags; - Vec3fa pos; - float radius; - static const size_t N = 10000; - static const size_t maxStreamSize = 100; - - SmallTriangleHitTest (std::string name, int isa, RTCSceneFlags sflags, IntersectMode imode, const Vec3fa& pos, const float radius) - : VerifyApplication::IntersectTest(name,isa,imode,VARIANT_INTERSECT,VerifyApplication::TEST_SHOULD_PASS), sflags(sflags), pos(pos), radius(radius) {} - - VerifyApplication::TestReturnValue run(VerifyApplication* state, bool silent) - { - std::string cfg = state->rtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - if (!supportsIntersectMode(device,imode)) - return VerifyApplication::SKIPPED; - - VerifyScene scene(device,sflags,to_aflags(imode)); - LinearSpace3fa space(Vec3fa(1.0f,0.0f,0.0f),Vec3fa(0.0f,1.0f,0.0f),Vec3fa(0.0f,0.0f,1.0f)); - space *= LinearSpace3fa::rotate(Vec3fa(4.0f,7.0f,-1.0f),4.34f); - const Vec3fa dx = 100.0f*normalize(space.vx); - const Vec3fa dy = 100.0f*normalize(space.vy); - const Vec3fa p = pos-0.5f*(dx+dy); - Ref plane = SceneGraph::createTrianglePlane (p,dx,dy,100,100).dynamicCast(); - scene.addGeometry(RTC_GEOMETRY_STATIC,plane.dynamicCast()); - rtcCommit (scene); - AssertNoError(device); - - size_t numTests = 0; - size_t numFailures = 0; - //for (auto ivariant : state->intersectVariants) - IntersectVariant ivariant = VARIANT_INTERSECT_INCOHERENT; - size_t numRays = size_t(N*state->intensity); - for (size_t i=0; itriangles.size(); - Vec3fa v0 = plane->positions[0][plane->triangles[primID].v0]; - Vec3fa v1 = plane->positions[0][plane->triangles[primID].v1]; - Vec3fa v2 = plane->positions[0][plane->triangles[primID].v2]; - Vec3fa c = (v0+v1+v2)/3.0f; - primIDs[j] = primID; - rays[j] = makeRay(org,c-org); - } - IntersectWithMode(imode,ivariant,scene,rays,M); - for (size_t j=0; j 0.00002; - if (!silent) { printf(" (%f%%)", 100.0f*failRate); fflush(stdout); } - return (VerifyApplication::TestReturnValue)(!failed); - } - }; - - struct RayAlignmentTest : public VerifyApplication::IntersectTest - { - ALIGNED_STRUCT; - RTCSceneFlags sflags; - std::string model; - static const size_t N = 10; - static const size_t maxStreamSize = 100; - - RayAlignmentTest (std::string name, int isa, RTCSceneFlags sflags, IntersectMode imode, std::string model) - : VerifyApplication::IntersectTest(name,isa,imode,VARIANT_INTERSECT,VerifyApplication::TEST_SHOULD_PASS), sflags(sflags), model(model) {} - - VerifyApplication::TestReturnValue run(VerifyApplication* state, bool silent) - { - std::string cfg = state->rtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - if (!supportsIntersectMode(device,imode)) - return VerifyApplication::SKIPPED; - - VerifyScene scene(device,sflags,to_aflags(imode)); - if (model == "sphere.triangles") scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createTriangleSphere(zero,2.0f,50)); - else if (model == "sphere.quads" ) scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createQuadSphere (zero,2.0f,50)); - else if (model == "sphere.subdiv" ) scene.addGeometry(RTC_GEOMETRY_STATIC,SceneGraph::createSubdivSphere (zero,2.0f,4,4)); - // FIXME: test more geometry types - rtcCommit (scene); - AssertNoError(device); - - for (auto ivariant : state->intersectVariants) - for (size_t i=0; iintensity); i++) - { - for (size_t M=1; Mrtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - if (!supportsIntersectMode(device,imode)) - return VerifyApplication::SKIPPED; - - const size_t numRays = 1000; - RTCRay rays[numRays]; - VerifyScene scene(device,sflags,to_aflags(imode)); - scene.addSphere(sampler,gflags,zero,2.0f,100); - scene.addHair (sampler,gflags,zero,1.0f,1.0f,100); - rtcCommit (scene); - - double c0 = getSeconds(); - for (size_t i=0; irtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - if (!supportsIntersectMode(device,imode)) - return VerifyApplication::SKIPPED; - - const size_t numRays = 1000; - RTCRay rays[numRays]; - VerifyScene scene(device,sflags,to_aflags(imode)); - scene.addSphere(sampler,gflags,zero,2.0f,100); - scene.addHair (sampler,gflags,zero,1.0f,1.0f,100); - rtcCommit (scene); - AssertNoError(device); - - double c0 = getSeconds(); - for (size_t i=0; i& intersectModes, std::vector& intersectVariants, const VerifyScene& scene) - { - RandomSampler sampler; - RandomSampler_init(sampler,hash); - - const size_t numRays = 100; - for (auto imode : intersectModes) - { - for (auto ivariant : intersectVariants) - { - if (!has_variant(imode,ivariant)) continue; - - RTCRay rays[numRays]; - for (size_t i=0; i scene; - BarrierSys barrier; - volatile unsigned int numActiveThreads; - bool cancelBuild; - std::atomic errorCounter; - RandomSampler sampler; - }; - - struct ThreadRegressionTask - { - ThreadRegressionTask (unsigned int threadIndex, unsigned int threadCount, - VerifyApplication* state, RTCDeviceRef& device, std::vector& intersectModes, RegressionTask* task) - : threadIndex(threadIndex), threadCount(threadCount), state(state), device(device), intersectModes(intersectModes), task(task) {} - - unsigned int threadIndex; - unsigned int threadCount; - VerifyApplication* state; - RTCDeviceRef& device; - std::vector& intersectModes; - RegressionTask* task; - }; - - size_t monitorProgressBreak = 0; - std::atomic monitorProgressInvokations(0); - std::atomic monitorProgressBreakExecuted(0); - - bool monitorProgressFunction(void* ptr, double dn) - { - size_t n = monitorProgressInvokations++; - if (n == monitorProgressBreak) { - monitorProgressBreakExecuted++; - return false; - } - return true; - } - - void rtcore_regression_static_thread(void* ptr) - { - ThreadRegressionTask* thread = (ThreadRegressionTask*) ptr; - RegressionTask* task = thread->task; - if (thread->threadIndex > 0) - { - for (unsigned int i=0; isceneCount; i++) - { - task->barrier.wait(); - if (thread->threadIndex < task->numActiveThreads) - { - if (build_join_test) rtcCommit(*task->scene); - else { - rtcCommitThread(*task->scene,thread->threadIndex,task->numActiveThreads); - rtcCommitThread(*task->scene,thread->threadIndex,task->numActiveThreads); - } - //if (rtcDeviceGetError(thread->device) != RTC_NO_ERROR) task->errorCounter++;; - if (rtcDeviceGetError(thread->device) != RTC_NO_ERROR) { - task->errorCounter++; - } - else { - shootRandomRays(i,thread->intersectModes,thread->state->intersectVariants,*task->scene); - } - } - task->barrier.wait(); - } - delete thread; thread = nullptr; - return; - } - - if (rtcDeviceGetError(thread->device) != RTC_NO_ERROR) task->errorCounter++;; - bool hasError = false; - - for (unsigned int i=0; isceneCount; i++) - { - RandomSampler_init(task->sampler,task->sceneIndex*13565+i*3242); - if (i%5 == 0) std::cout << "." << std::flush; - - RTCSceneFlags sflag = getSceneFlag(i); - task->scene = new VerifyScene(thread->device,sflag,aflags_all); - if (rtcDeviceGetError(thread->device) != RTC_NO_ERROR) task->errorCounter++;; - if (task->cancelBuild) rtcSetProgressMonitorFunction(*task->scene,monitorProgressFunction,nullptr); - avector spheres; - - for (unsigned int j=0; j<10; j++) - { - Vec3fa pos = 100.0f*RandomSampler_get3D(task->sampler); - int type = RandomSampler_getInt(task->sampler)%9; - switch (RandomSampler_getInt(task->sampler)%16) { - case 0: pos = Vec3fa(nan); break; - case 1: pos = Vec3fa(inf); break; - case 2: pos = Vec3fa(1E30f); break; - default: break; - }; - size_t numPhi = RandomSampler_getInt(task->sampler)%50; - if (type == 2) numPhi = RandomSampler_getInt(task->sampler)%10; - size_t numTriangles = 2*2*numPhi*(numPhi-1); - numTriangles = RandomSampler_getInt(task->sampler)%(numTriangles+1); - switch (type) { - case 0: task->scene->addSphere(task->sampler,RTC_GEOMETRY_STATIC,pos,2.0f,numPhi,numTriangles); break; - case 1: task->scene->addSphere(task->sampler,RTC_GEOMETRY_STATIC,pos,2.0f,numPhi,numTriangles,task->test->random_motion_vector(1.0f)); break; - case 2: task->scene->addQuadSphere(task->sampler,RTC_GEOMETRY_STATIC,pos,2.0f,numPhi,numTriangles); break; - case 3: task->scene->addQuadSphere(task->sampler,RTC_GEOMETRY_STATIC,pos,2.0f,numPhi,numTriangles,task->test->random_motion_vector(1.0f)); break; - case 4: task->scene->addSubdivSphere(task->sampler,RTC_GEOMETRY_STATIC,pos,2.0f,numPhi,4,numTriangles); break; - case 5: task->scene->addSubdivSphere(task->sampler,RTC_GEOMETRY_STATIC,pos,2.0f,numPhi,4,numTriangles,task->test->random_motion_vector(1.0f)); break; - case 6: task->scene->addHair (task->sampler,RTC_GEOMETRY_STATIC,pos,1.0f,2.0f,numTriangles); break; - case 7: task->scene->addHair (task->sampler,RTC_GEOMETRY_STATIC,pos,1.0f,2.0f,numTriangles,task->test->random_motion_vector(1.0f)); break; - - case 8: { - Sphere* sphere = new Sphere(pos,2.0f); spheres.push_back(sphere); - task->scene->addUserGeometryEmpty(task->sampler,RTC_GEOMETRY_STATIC,sphere); break; - } - } - //if (rtcDeviceGetError(thread->device) != RTC_NO_ERROR) task->errorCounter++;; - if (rtcDeviceGetError(thread->device) != RTC_NO_ERROR) { - task->errorCounter++; - hasError = true; - break; - } - } - - if (thread->threadCount) { - task->numActiveThreads = max(unsigned(1),RandomSampler_getInt(task->sampler) % thread->threadCount); - task->barrier.wait(); - if (build_join_test) rtcCommit(*task->scene); - else { - rtcCommitThread(*task->scene,thread->threadIndex,task->numActiveThreads); - rtcCommitThread(*task->scene,thread->threadIndex,task->numActiveThreads); - } - } else { - if (!hasError) { - rtcCommit(*task->scene); - } - } - //if (rtcDeviceGetError(thread->device) != RTC_NO_ERROR) task->errorCounter++;; - - if (rtcDeviceGetError(thread->device) != RTC_NO_ERROR) { - task->errorCounter++; - } - else { - if (!hasError) { - shootRandomRays(i,thread->intersectModes,thread->state->intersectVariants,*task->scene); - } - } - - if (thread->threadCount) - task->barrier.wait(); - - task->scene = nullptr; - if (rtcDeviceGetError(thread->device) != RTC_NO_ERROR) task->errorCounter++;; - - for (size_t i=0; itask; - if (thread->threadIndex > 0) - { - for (unsigned int i=0; isceneCount; i++) - { - task->barrier.wait(); - if (thread->threadIndex < task->numActiveThreads) - { - if (build_join_test) rtcCommit(*task->scene); - else rtcCommitThread(*task->scene,thread->threadIndex,task->numActiveThreads); - //if (rtcDeviceGetError(thread->device) != RTC_NO_ERROR) task->errorCounter++;; - if (rtcDeviceGetError(thread->device) != RTC_NO_ERROR) { - task->errorCounter++; - } - else { - shootRandomRays(i,thread->intersectModes,thread->state->intersectVariants,*task->scene); - } - } - task->barrier.wait(); - } - delete thread; thread = nullptr; - return; - } - task->scene = new VerifyScene(thread->device,RTC_SCENE_DYNAMIC,aflags_all); - if (rtcDeviceGetError(thread->device) != RTC_NO_ERROR) task->errorCounter++;; - if (task->cancelBuild) rtcSetProgressMonitorFunction(*task->scene,monitorProgressFunction,nullptr); - const size_t numSlots = 20; - const size_t numIterations = 2*numSlots; - std::pair> geom[numSlots]; - int types[numSlots]; - Sphere spheres[numSlots]; - size_t numVertices[numSlots]; - for (size_t i=0; isceneCount; i++) - { - srand(task->sceneIndex*23565+i*2242); - if (i%20 == 0) std::cout << "." << std::flush; - - for (unsigned int j=0; jsampler)%numSlots; - if (geom[index].first == -1) - { - int type = RandomSampler_getInt(task->sampler)%21; - Vec3fa pos = 100.0f*RandomSampler_get3D(task->sampler); - switch (RandomSampler_getInt(task->sampler)%16) { - case 0: pos = Vec3fa(nan); break; - case 1: pos = Vec3fa(inf); break; - case 2: pos = Vec3fa(1E30f); break; - default: break; - }; - size_t numPhi = RandomSampler_getInt(task->sampler)%100; - if (type >= 12 || type <= 17) numPhi = RandomSampler_getInt(task->sampler)%10; -#if defined(__WIN32__) - numPhi = RandomSampler_getInt(task->sampler) % 4; -#endif - - size_t numTriangles = 2*2*numPhi*(numPhi-1); - numTriangles = RandomSampler_getInt(task->sampler)%(numTriangles+1); - types[index] = type; - numVertices[index] = 2*numPhi*(numPhi+1); - switch (type) { - case 0: geom[index] = task->scene->addSphere(task->sampler,RTC_GEOMETRY_STATIC,pos,2.0f,numPhi,numTriangles); break; - case 1: geom[index] = task->scene->addSphere(task->sampler,RTC_GEOMETRY_DEFORMABLE,pos,2.0f,numPhi,numTriangles); break; - case 2: geom[index] = task->scene->addSphere(task->sampler,RTC_GEOMETRY_DYNAMIC,pos,2.0f,numPhi,numTriangles); break; - - case 3: geom[index] = task->scene->addSphere(task->sampler,RTC_GEOMETRY_STATIC,pos,2.0f,numPhi,numTriangles,task->test->random_motion_vector(1.0f)); break; - case 4: geom[index] = task->scene->addSphere(task->sampler,RTC_GEOMETRY_DEFORMABLE,pos,2.0f,numPhi,numTriangles,task->test->random_motion_vector(1.0f)); break; - case 5: geom[index] = task->scene->addSphere(task->sampler,RTC_GEOMETRY_DYNAMIC,pos,2.0f,numPhi,numTriangles,task->test->random_motion_vector(1.0f)); break; - - case 6: geom[index] = task->scene->addQuadSphere(task->sampler,RTC_GEOMETRY_STATIC,pos,2.0f,numPhi,numTriangles); break; - case 7: geom[index] = task->scene->addQuadSphere(task->sampler,RTC_GEOMETRY_DEFORMABLE,pos,2.0f,numPhi,numTriangles); break; - case 8: geom[index] = task->scene->addQuadSphere(task->sampler,RTC_GEOMETRY_DYNAMIC,pos,2.0f,numPhi,numTriangles); break; - - case 9: geom[index] = task->scene->addQuadSphere(task->sampler,RTC_GEOMETRY_STATIC,pos,2.0f,numPhi,numTriangles,task->test->random_motion_vector(1.0f)); break; - case 10: geom[index] = task->scene->addQuadSphere(task->sampler,RTC_GEOMETRY_DEFORMABLE,pos,2.0f,numPhi,numTriangles,task->test->random_motion_vector(1.0f)); break; - case 11: geom[index] = task->scene->addQuadSphere(task->sampler,RTC_GEOMETRY_DYNAMIC,pos,2.0f,numPhi,numTriangles,task->test->random_motion_vector(1.0f)); break; - - case 12: geom[index] = task->scene->addSubdivSphere(task->sampler,RTC_GEOMETRY_STATIC,pos,2.0f,numPhi,4,numTriangles); break; - case 13: geom[index] = task->scene->addSubdivSphere(task->sampler,RTC_GEOMETRY_DEFORMABLE,pos,2.0f,numPhi,4,numTriangles); break; - case 14: geom[index] = task->scene->addSubdivSphere(task->sampler,RTC_GEOMETRY_DYNAMIC,pos,2.0f,numPhi,4,numTriangles); break; - - case 15: geom[index] = task->scene->addSubdivSphere(task->sampler,RTC_GEOMETRY_STATIC,pos,2.0f,numPhi,4,numTriangles,task->test->random_motion_vector(1.0f)); break; - case 16: geom[index] = task->scene->addSubdivSphere(task->sampler,RTC_GEOMETRY_DEFORMABLE,pos,2.0f,numPhi,4,numTriangles,task->test->random_motion_vector(1.0f)); break; - case 17: geom[index] = task->scene->addSubdivSphere(task->sampler,RTC_GEOMETRY_DYNAMIC,pos,2.0f,numPhi,4,numTriangles,task->test->random_motion_vector(1.0f)); break; - - case 18: spheres[index] = Sphere(pos,2.0f); geom[index] = task->scene->addUserGeometryEmpty(task->sampler,RTC_GEOMETRY_STATIC,&spheres[index]); break; - case 19: spheres[index] = Sphere(pos,2.0f); geom[index] = task->scene->addUserGeometryEmpty(task->sampler,RTC_GEOMETRY_DEFORMABLE,&spheres[index]); break; - case 20: spheres[index] = Sphere(pos,2.0f); geom[index] = task->scene->addUserGeometryEmpty(task->sampler,RTC_GEOMETRY_DYNAMIC,&spheres[index]); break; - }; - //if (rtcDeviceGetError(thread->device) != RTC_NO_ERROR) task->errorCounter++;; - if (rtcDeviceGetError(thread->device) != RTC_NO_ERROR) { - task->errorCounter++; - hasError = true; - break; - } - } - else - { - switch (types[index]) { - case 18: - case 19: - case 20: - { - rtcDeleteGeometry(*task->scene,geom[index].first); - if (rtcDeviceGetError(thread->device) != RTC_NO_ERROR) task->errorCounter++;; - geom[index].first = -1; - geom[index].second = nullptr; - break; - } - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - case 9: - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: - case 16: - case 17: - { - int op = RandomSampler_getInt(task->sampler)%3; - switch (op) { - case 0: { - rtcDeleteGeometry(*task->scene,geom[index].first); - if (rtcDeviceGetError(thread->device) != RTC_NO_ERROR) task->errorCounter++;; - geom[index].first = -1; - geom[index].second = nullptr; - break; - } - case 1: { - Vec3fa* vertices = (Vec3fa*) rtcMapBuffer(*task->scene,geom[index].first,RTC_VERTEX_BUFFER); - if (vertices) { - for (size_t i=0; iscene,geom[index].first,RTC_VERTEX_BUFFER); - switch (types[index]) - { - case 4: case 5: case 10: case 11: - Vec3fa* vertices = (Vec3fa*)rtcMapBuffer(*task->scene, geom[index].first, RTC_VERTEX_BUFFER1); - if (vertices) { - for (size_t i = 0; i < numVertices[index]; i++) vertices[i] += Vec3fa(0.1f); - } - rtcUnmapBuffer(*task->scene, geom[index].first, RTC_VERTEX_BUFFER1); - } - break; - } - case 2: { - switch (types[index]) - { - case 2: - case 5: - case 8: - case 11: - case 14: - task->scene->resizeRandomly(geom[index],task->sampler); - break; - } - } - } - break; - } - } - } - - /* entirely delete all objects at the end */ - if (j == numIterations-1) { - for (size_t i=0; iscene,geom[i].first); - if (rtcDeviceGetError(thread->device) != RTC_NO_ERROR) task->errorCounter++;; - geom[i].first = -1; - geom[i].second = nullptr; - } - } - } - } - - if (thread->threadCount) { - task->numActiveThreads = max(unsigned(1),RandomSampler_getInt(task->sampler) % thread->threadCount); - task->barrier.wait(); - if (build_join_test) rtcCommit(*task->scene); - else rtcCommitThread(*task->scene,thread->threadIndex,task->numActiveThreads); - } else { - if (!hasError) - rtcCommit(*task->scene); - } - //if (rtcDeviceGetError(thread->device) != RTC_NO_ERROR) task->errorCounter++;; - - if (rtcDeviceGetError(thread->device) != RTC_NO_ERROR) - task->errorCounter++; - else - if (!hasError) - shootRandomRays(i,thread->intersectModes,thread->state->intersectVariants,*task->scene); - - if (thread->threadCount) - task->barrier.wait(); - } - - task->scene = nullptr; - if (rtcDeviceGetError(thread->device) != RTC_NO_ERROR) task->errorCounter++;; - - delete thread; thread = nullptr; - return; - } - - struct IntensiveRegressionTest : public VerifyApplication::Test - { - thread_func func; - int mode; - float intensity; - std::vector intersectModes; - std::vector threads; - - IntensiveRegressionTest (std::string name, int isa, thread_func func, int mode, float intensity) - : VerifyApplication::Test(name,isa,VerifyApplication::TEST_SHOULD_PASS), func(func), mode(mode), intensity(intensity) {} - - VerifyApplication::TestReturnValue run(VerifyApplication* state, bool silent) - { - std::string cfg = state->rtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - - /* only test supported intersect modes */ - if (rtcDeviceGetParameter1i(device,RTC_CONFIG_INTERSECT1)) intersectModes.push_back(MODE_INTERSECT1); - if (rtcDeviceGetParameter1i(device,RTC_CONFIG_INTERSECT4)) intersectModes.push_back(MODE_INTERSECT4); - if (rtcDeviceGetParameter1i(device,RTC_CONFIG_INTERSECT8)) intersectModes.push_back(MODE_INTERSECT8); - if (rtcDeviceGetParameter1i(device,RTC_CONFIG_INTERSECT16)) intersectModes.push_back(MODE_INTERSECT16); - if (rtcDeviceGetParameter1i(device,RTC_CONFIG_INTERSECT_STREAM)) { - intersectModes.push_back(MODE_INTERSECT1M); - intersectModes.push_back(MODE_INTERSECT1Mp); - intersectModes.push_back(MODE_INTERSECTNM1); - intersectModes.push_back(MODE_INTERSECTNM3); - intersectModes.push_back(MODE_INTERSECTNM4); - intersectModes.push_back(MODE_INTERSECTNM8); - intersectModes.push_back(MODE_INTERSECTNM16); - intersectModes.push_back(MODE_INTERSECTNp); - } - - size_t errorCounter = 0; - unsigned int sceneIndex = 0; - while (sceneIndex < size_t(intensity*state->intensity)) - { - if (mode) - { - build_join_test = (mode == 2); - unsigned numThreads = getNumberOfLogicalThreads(); - - std::vector tasks; - while (numThreads) - { - unsigned int N = max(unsigned(1),random_int()%numThreads); numThreads -= N; - RegressionTask* task = new RegressionTask(this,sceneIndex++,5,N,false); - tasks.push_back(task); - - for (unsigned int i=0; ierrorCounter; - delete tasks[i]; - } - - threads.clear(); - } - else - { - RegressionTask task(this,sceneIndex++,5,0,false); - func(new ThreadRegressionTask(0,0,state,device,intersectModes,&task)); - } - } - return (VerifyApplication::TestReturnValue) (errorCounter == 0); - } - }; - - size_t monitorMemoryBreak = 0; - std::atomic monitorMemoryBytesUsed(0); - std::atomic monitorMemoryInvokations(0); - std::atomic monitorMemoryBreakExecuted(0); - - bool monitorMemoryFunction(ssize_t bytes, bool post) - { - monitorMemoryBytesUsed += bytes; - if (bytes > 0) { - size_t n = monitorMemoryInvokations++; - if (n == monitorMemoryBreak) { - monitorMemoryBreakExecuted++; - if (!post) monitorMemoryBytesUsed -= bytes; - return false; - } - } - return true; - } - - struct MemoryMonitorTest : public VerifyApplication::Test - { - thread_func func; - float intensity; - std::vector intersectModes; - - MemoryMonitorTest (std::string name, int isa, thread_func func, float intensity) - : VerifyApplication::Test(name,isa,VerifyApplication::TEST_SHOULD_PASS), func(func), intensity(intensity) {} - - VerifyApplication::TestReturnValue run(VerifyApplication* state, bool silent) - { - std::string cfg = state->rtcore + ",isa="+stringOfISA(isa); - RTCDeviceRef device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - - /* only test supported intersect modes */ - if (rtcDeviceGetParameter1i(device,RTC_CONFIG_INTERSECT1)) intersectModes.push_back(MODE_INTERSECT1); - if (rtcDeviceGetParameter1i(device,RTC_CONFIG_INTERSECT4)) intersectModes.push_back(MODE_INTERSECT4); - if (rtcDeviceGetParameter1i(device,RTC_CONFIG_INTERSECT8)) intersectModes.push_back(MODE_INTERSECT8); - if (rtcDeviceGetParameter1i(device,RTC_CONFIG_INTERSECT16)) intersectModes.push_back(MODE_INTERSECT16); - if (rtcDeviceGetParameter1i(device,RTC_CONFIG_INTERSECT_STREAM)) { - intersectModes.push_back(MODE_INTERSECT1M); - intersectModes.push_back(MODE_INTERSECT1Mp); - intersectModes.push_back(MODE_INTERSECTNM1); - intersectModes.push_back(MODE_INTERSECTNM3); - intersectModes.push_back(MODE_INTERSECTNM4); - intersectModes.push_back(MODE_INTERSECTNM8); - intersectModes.push_back(MODE_INTERSECTNM16); - intersectModes.push_back(MODE_INTERSECTNp); - } - - rtcDeviceSetMemoryMonitorFunction(device,monitorMemoryFunction); - - unsigned int sceneIndex = 0; - while (sceneIndex < size_t(intensity*state->intensity)) - { - monitorMemoryBreak = std::numeric_limits::max(); - monitorMemoryBytesUsed = 0; - monitorMemoryInvokations = 0; - monitorMemoryBreakExecuted = 0; - monitorProgressBreak = std::numeric_limits::max(); - monitorProgressInvokations = 0; - monitorProgressBreakExecuted = 0; - RegressionTask task1(this,sceneIndex,1,0,true); - func(new ThreadRegressionTask(0,0,state,device,intersectModes,&task1)); - if (monitorMemoryBytesUsed) - return VerifyApplication::FAILED; - - monitorMemoryBreak = size_t(float(monitorMemoryInvokations) * random_float()); - monitorMemoryBytesUsed = 0; - monitorMemoryInvokations = 0; - monitorMemoryBreakExecuted = 0; - monitorProgressBreak = size_t(float(monitorProgressInvokations) * 2.0f * random_float()); - monitorProgressInvokations = 0; - monitorProgressBreakExecuted = 0; - RegressionTask task2(this,sceneIndex,1,0,true); - func(new ThreadRegressionTask(0,0,state,device,intersectModes,&task2)); - if (monitorMemoryBytesUsed) - return VerifyApplication::FAILED; - if (monitorMemoryBreakExecuted && task2.errorCounter != 1) - return VerifyApplication::FAILED; - if (monitorProgressBreakExecuted && task2.errorCounter != 1) - return VerifyApplication::FAILED; - if (!monitorMemoryBreakExecuted && !monitorProgressBreakExecuted && task2.errorCounter != 0) - return VerifyApplication::FAILED; - sceneIndex++; - } - rtcDeviceSetMemoryMonitorFunction(device,nullptr); - AssertNoError(device); - return VerifyApplication::PASSED; - } - }; - - ///////////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////// - - struct SimpleBenchmark : public VerifyApplication::Benchmark - { - SimpleBenchmark (std::string name, int isa) - : VerifyApplication::Benchmark(name,isa,"1/s",true,10) {} - - float benchmark(VerifyApplication* state) - { - double t0 = getSeconds(); - for (volatile size_t i=0; i<10000000; i++); - double t1 = getSeconds(); - return 1.0f/float(t1-t0); - } - }; - - struct ParallelIntersectBenchmark : public VerifyApplication::Benchmark - { - unsigned int N, dN; - - ParallelIntersectBenchmark (std::string name, int isa, unsigned int N, unsigned int dN) - : VerifyApplication::Benchmark(name,isa,"Mrps",true,10), N(N), dN(dN) {} - - bool setup(VerifyApplication* state) - { - return true; - } - - virtual void render_block(size_t i, size_t n) = 0; - - float benchmark(VerifyApplication* state) - { - double t0 = getSeconds(); - parallel_for((size_t)N/dN, [&](size_t i) { - render_block(i*dN, dN); - }); - double t1 = getSeconds(); - return 1E-6f * (float)(N)/float(t1-t0); - } - - virtual void cleanup(VerifyApplication* state) - { - } - }; - - struct CoherentRaysBenchmark : public ParallelIntersectBenchmark - { - GeometryType gtype; - RTCSceneFlags sflags; - RTCGeometryFlags gflags; - IntersectMode imode; - IntersectVariant ivariant; - size_t numPhi; - RTCDeviceRef device; - Ref scene; - static const size_t tileSizeX = 32; - static const size_t tileSizeY = 32; - static const size_t width = 4096; - static const size_t height = 4096; - static const size_t numTilesX = width / tileSizeX; - static const size_t numTilesY = height / tileSizeY; - - CoherentRaysBenchmark (std::string name, int isa, GeometryType gtype, RTCSceneFlags sflags, RTCGeometryFlags gflags, IntersectMode imode, IntersectVariant ivariant, size_t numPhi) - : ParallelIntersectBenchmark(name,isa,numTilesX*numTilesY,1), gtype(gtype), sflags(sflags), gflags(gflags), imode(imode), ivariant(ivariant), numPhi(numPhi) {} - - size_t setNumPrimitives(size_t N) - { - numPhi = size_t(ceilf(sqrtf(N/4.0f))); - return 4*numPhi*numPhi; - } - - bool setup(VerifyApplication* state) - { - if (!ParallelIntersectBenchmark::setup(state)) - return false; - - std::string cfg = state->rtcore + ",start_threads=1,set_affinity=1,isa="+stringOfISA(isa); - device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - rtcDeviceSetErrorFunction(device,errorHandler); - if (!supportsIntersectMode(device,imode)) - return false; - - scene = new VerifyScene(device,sflags,aflags_all); - switch (gtype) { - case TRIANGLE_MESH: scene->addGeometry(gflags,SceneGraph::createTriangleSphere(zero,one,numPhi)); break; - case TRIANGLE_MESH_MB: scene->addGeometry(gflags,SceneGraph::createTriangleSphere(zero,one,numPhi)->set_motion_vector(random_motion_vector2(0.01f))); break; - case QUAD_MESH: scene->addGeometry(gflags,SceneGraph::createQuadSphere(zero,one,numPhi)); break; - case QUAD_MESH_MB: scene->addGeometry(gflags,SceneGraph::createQuadSphere(zero,one,numPhi)->set_motion_vector(random_motion_vector2(0.01f))); break; - case SUBDIV_MESH: scene->addGeometry(gflags,SceneGraph::createSubdivSphere(zero,one,8,float(numPhi)/8.0f)); break; - case SUBDIV_MESH_MB: scene->addGeometry(gflags,SceneGraph::createSubdivSphere(zero,one,8,float(numPhi)/8.0f)->set_motion_vector(random_motion_vector2(0.01f))); break; - default: throw std::runtime_error("invalid geometry for benchmark"); - } - rtcCommit (*scene); - AssertNoError(device); - - return true; - } - - void render_block(size_t i, size_t) - { - float rcpWidth = 1.0f/width; - float rcpHeight = 1.0/height; - const size_t tileY = i / numTilesX; - const size_t tileX = i - tileY * numTilesX; - const size_t x0 = tileX * tileSizeX; - const size_t x1 = min(x0 + tileSizeX, width); - const size_t y0 = tileY * tileSizeY; - const size_t y1 = min(y0 + tileSizeY, height); - - RTCIntersectContext context; - context.flags = ((ivariant & VARIANT_COHERENT_INCOHERENT_MASK) == VARIANT_COHERENT) ? RTC_INTERSECT_COHERENT : RTC_INTERSECT_INCOHERENT; - context.userRayExt = nullptr; - - switch (imode) - { - case MODE_INTERSECT1: - { - for (size_t y=y0; y scene; - static const size_t numRays = 16*1024*1024; - static const size_t deltaRays = 1024; - - IncoherentRaysBenchmark (std::string name, int isa, GeometryType gtype, RTCSceneFlags sflags, RTCGeometryFlags gflags, IntersectMode imode, IntersectVariant ivariant, size_t numPhi) - : ParallelIntersectBenchmark(name,isa,numRays,deltaRays), gtype(gtype), sflags(sflags), gflags(gflags), imode(imode), ivariant(ivariant), numPhi(numPhi), device(nullptr) {} - - size_t setNumPrimitives(size_t N) - { - numPhi = size_t(ceilf(sqrtf(N/4.0f))); - return 4*numPhi*numPhi; - } - - bool setup(VerifyApplication* state) - { - if (!ParallelIntersectBenchmark::setup(state)) - return false; - - std::string cfg = state->rtcore + ",start_threads=1,set_affinity=1,isa="+stringOfISA(isa); - device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - rtcDeviceSetErrorFunction(device,errorHandler); - if (!supportsIntersectMode(device,imode)) - return false; - - scene = new VerifyScene(device,sflags,aflags_all); - switch (gtype) { - case TRIANGLE_MESH: scene->addGeometry(gflags,SceneGraph::createTriangleSphere(zero,one,numPhi)); break; - case TRIANGLE_MESH_MB: scene->addGeometry(gflags,SceneGraph::createTriangleSphere(zero,one,numPhi)->set_motion_vector(random_motion_vector2(0.01f))); break; - case QUAD_MESH: scene->addGeometry(gflags,SceneGraph::createQuadSphere(zero,one,numPhi)); break; - case QUAD_MESH_MB: scene->addGeometry(gflags,SceneGraph::createQuadSphere(zero,one,numPhi)->set_motion_vector(random_motion_vector2(0.01f))); break; - case SUBDIV_MESH: scene->addGeometry(gflags,SceneGraph::createSubdivSphere(zero,one,8,float(numPhi)/8.0f)); break; - case SUBDIV_MESH_MB: scene->addGeometry(gflags,SceneGraph::createSubdivSphere(zero,one,8,float(numPhi)/8.0f)->set_motion_vector(random_motion_vector2(0.01f))); break; - default: throw std::runtime_error("invalid geometry for benchmark"); - } - rtcCommit (*scene); - AssertNoError(device); - - return true; - } - - void render_block(size_t i, size_t dn) - { - RTCIntersectContext context; - context.flags = ((ivariant & VARIANT_COHERENT_INCOHERENT_MASK) == VARIANT_COHERENT) ? RTC_INTERSECT_COHERENT : RTC_INTERSECT_INCOHERENT; - context.userRayExt = nullptr; - - RandomSampler sampler; - RandomSampler_init(sampler, (int)i); - - switch (imode) - { - case MODE_INTERSECT1: - { - for (size_t j=0; j create_geometry_bytes_used(0); - - struct CreateGeometryBenchmark : public VerifyApplication::Benchmark - { - GeometryType gtype; - RTCSceneFlags sflags; - RTCGeometryFlags gflags; - size_t numPhi; - size_t numMeshes; - bool update; - bool dobenchmark; // true = measure build performance, false = measure memory consumption - size_t numPrimitives; - RTCDeviceRef device; - Ref scene; - std::vector> geometries; - - CreateGeometryBenchmark (std::string name, int isa, GeometryType gtype, RTCSceneFlags sflags, RTCGeometryFlags gflags, size_t numPhi, size_t numMeshes, bool update, bool dobenchmark) - : VerifyApplication::Benchmark(name,isa,dobenchmark ? "Mprims/s" : "MB",dobenchmark,dobenchmark?10:1), gtype(gtype), sflags(sflags), gflags(gflags), - numPhi(numPhi), numMeshes(numMeshes), update(update), dobenchmark(dobenchmark), - numPrimitives(0), device(nullptr), scene(nullptr) {} - - size_t setNumPrimitives(size_t N) - { - numPhi = (size_t) ceilf(sqrtf(N/4.0f)); - return 4*numPhi*numPhi; - } - - void create_scene() - { - scene = new VerifyScene(device,sflags,aflags_all); - - numPrimitives = 0; - for (size_t i=0; inumPrimitives(); - - switch (gtype) { - case TRIANGLE_MESH: - case QUAD_MESH: - case SUBDIV_MESH: - case HAIR_GEOMETRY: - case LINE_GEOMETRY: - case TRIANGLE_MESH_MB: - case QUAD_MESH_MB: - case SUBDIV_MESH_MB: - case HAIR_GEOMETRY_MB: - case LINE_GEOMETRY_MB: - scene->addGeometry(gflags,geometries[i]); - break; - default: - throw std::runtime_error("invalid geometry for benchmark"); - } - } - } - - static bool memoryMonitor(const ssize_t bytes, const bool /*post*/) - { - create_geometry_bytes_used += bytes; - return true; - } - - bool setup(VerifyApplication* state) - { - std::string cfg = "start_threads=1,set_affinity=1,isa="+stringOfISA(isa) + ",threads=" + std::to_string((long long)numThreads)+","+state->rtcore; - device = rtcNewDevice(cfg.c_str()); - errorHandler(rtcDeviceGetError(device)); - rtcDeviceSetErrorFunction(device,errorHandler); - if (!dobenchmark) rtcDeviceSetMemoryMonitorFunction(device,memoryMonitor); - - for (unsigned int i=0; iset_motion_vector(random_motion_vector2(0.0001f)); break; - default: break; - } - } - - if (update) - create_scene(); - - return true; - } - - float benchmark(VerifyApplication* state) - { - if (!update) create_scene(); - - double t0 = getSeconds(); - - if (update) - for (unsigned int i=0; i> groups; - groups.push(tests.dynamicCast()); - auto push = [&] (Ref group) { - groups.top()->add(group.dynamicCast()); - groups.push(group); - }; - - groups.top()->add(new InitExitTest("init_exit")); - - /* add Embree internal tests */ - for (size_t i=2000000; i<3000000; i++) { - const char* testName = (const char*) rtcDeviceGetParameter1i(device,(RTCParameter)i); - if (testName == nullptr) break; - groups.top()->add(new EmbreeInternalTest(testName,i-2000000)); - } - - for (auto isa : isas) - { - push(new TestGroup(stringOfISA(isa),false,false)); - - groups.top()->add(new MultipleDevicesTest("multiple_devices",isa)); - - push(new TestGroup("flags",true,true)); - groups.top()->add(new FlagsTest("static_static" ,isa,VerifyApplication::TEST_SHOULD_PASS, RTC_SCENE_STATIC, RTC_GEOMETRY_STATIC)); - groups.top()->add(new FlagsTest("static_deformable" ,isa,VerifyApplication::TEST_SHOULD_FAIL, RTC_SCENE_STATIC, RTC_GEOMETRY_DEFORMABLE)); - groups.top()->add(new FlagsTest("static_dynamic" ,isa,VerifyApplication::TEST_SHOULD_FAIL, RTC_SCENE_STATIC, RTC_GEOMETRY_DYNAMIC)); - groups.top()->add(new FlagsTest("dynamic_static" ,isa,VerifyApplication::TEST_SHOULD_PASS, RTC_SCENE_DYNAMIC,RTC_GEOMETRY_STATIC)); - groups.top()->add(new FlagsTest("dynamic_deformable",isa,VerifyApplication::TEST_SHOULD_PASS, RTC_SCENE_DYNAMIC,RTC_GEOMETRY_DEFORMABLE)); - groups.top()->add(new FlagsTest("dynamic_dynamic" ,isa,VerifyApplication::TEST_SHOULD_PASS, RTC_SCENE_DYNAMIC,RTC_GEOMETRY_DYNAMIC)); - groups.pop(); - - groups.top()->add(new UnmappedBeforeCommitTest("unmapped_before_commit",isa)); - - push(new TestGroup("get_bounds",true,true)); - for (auto gtype : gtypes_all) - groups.top()->add(new GetBoundsTest(to_string(gtype),isa,gtype)); - groups.pop(); - - push(new TestGroup("get_linear_bounds",true,true)); - for (auto gtype : gtypes_all) - groups.top()->add(new GetLinearBoundsTest(to_string(gtype),isa,gtype)); - groups.pop(); - - groups.top()->add(new GetUserDataTest("get_user_data",isa)); - - push(new TestGroup("buffer_stride",true,true)); - for (auto gtype : gtypes) - groups.top()->add(new BufferStrideTest(to_string(gtype),isa,gtype)); - groups.pop(); - - /**************************************************************************/ - /* Builder Tests */ - /**************************************************************************/ - - push(new TestGroup("empty_scene",true,true)); - for (auto sflags : sceneFlags) - groups.top()->add(new EmptySceneTest(to_string(sflags),isa,sflags)); - groups.pop(); - - push(new TestGroup("empty_geometry",true,true)); - for (auto sflags : sceneFlags) - groups.top()->add(new EmptyGeometryTest(to_string(sflags),isa,sflags,RTC_GEOMETRY_STATIC)); - groups.pop(); - - push(new TestGroup("build",true,true)); - for (auto sflags : sceneFlags) - groups.top()->add(new BuildTest(to_string(sflags),isa,sflags,RTC_GEOMETRY_STATIC)); - groups.pop(); - - push(new TestGroup("overlapping_primitives",true,true)); - for (auto sflags : sceneFlags) - groups.top()->add(new OverlappingGeometryTest(to_string(sflags),isa,sflags,RTC_GEOMETRY_STATIC,clamp(int(intensity*10000),1000,100000))); - groups.pop(); - - push(new TestGroup("new_delete_geometry",true,true)); - for (auto sflags : sceneFlagsDynamic) - groups.top()->add(new NewDeleteGeometryTest(to_string(sflags),isa,sflags)); - groups.pop(); - - push(new TestGroup("enable_disable_geometry",true,true)); - for (auto sflags : sceneFlagsDynamic) - groups.top()->add(new EnableDisableGeometryTest(to_string(sflags),isa,sflags)); - groups.pop(); - - push(new TestGroup("update",true,true)); - for (auto sflags : sceneFlagsDynamic) { - for (auto imode : intersectModes) { - for (auto ivariant : intersectVariants) { - if (has_variant(imode,ivariant)) { - groups.top()->add(new UpdateTest("deformable."+to_string(sflags,imode,ivariant),isa,sflags,RTC_GEOMETRY_DEFORMABLE,imode,ivariant)); - groups.top()->add(new UpdateTest("dynamic."+to_string(sflags,imode,ivariant),isa,sflags,RTC_GEOMETRY_DYNAMIC,imode,ivariant)); - } - } - } - } - groups.pop(); - - groups.top()->add(new GarbageGeometryTest("build_garbage_geom",isa)); - - GeometryType gtypes_memory[] = { TRIANGLE_MESH, TRIANGLE_MESH_MB, QUAD_MESH, QUAD_MESH_MB, HAIR_GEOMETRY, HAIR_GEOMETRY_MB, LINE_GEOMETRY, LINE_GEOMETRY_MB }; - std::vector> sflags_gflags_memory; - sflags_gflags_memory.push_back(std::make_pair(RTC_SCENE_STATIC,RTC_GEOMETRY_STATIC)); - sflags_gflags_memory.push_back(std::make_pair(RTC_SCENE_DYNAMIC,RTC_GEOMETRY_DYNAMIC)); - - push(new TestGroup("memory_consumption",false,false)); - - for (auto gtype : gtypes_memory) - for (auto sflags : sflags_gflags_memory) - groups.top()->add(new MemoryConsumptionTest(to_string(gtype)+"."+to_string(sflags.first,sflags.second),isa,gtype,sflags.first,sflags.second)); - - groups.pop(); - - /**************************************************************************/ - /* Interpolation Tests */ - /**************************************************************************/ - - push(new TestGroup("interpolate",false,false)); - int interpolateTests[] = { 4,5,8,11,12,15 }; - - push(new TestGroup("triangles",true,true)); - for (auto s : interpolateTests) - groups.top()->add(new InterpolateTrianglesTest(std::to_string((long long)(s)),isa,s)); - groups.pop(); - - push(new TestGroup("subdiv",true,true)); - for (auto s : interpolateTests) - groups.top()->add(new InterpolateSubdivTest(std::to_string((long long)(s)),isa,s)); - groups.pop(); - - push(new TestGroup("hair",true,true)); - for (auto s : interpolateTests) - groups.top()->add(new InterpolateHairTest(std::to_string((long long)(s)),isa,s)); - groups.pop(); - - groups.pop(); - - /**************************************************************************/ - /* Intersection Tests */ - /**************************************************************************/ - - push(new TestGroup("triangle_hit",true,true)); - for (auto sflags : sceneFlags) - for (auto imode : intersectModes) - for (auto ivariant : intersectVariants) - if (has_variant(imode,ivariant)) - groups.top()->add(new TriangleHitTest(to_string(sflags,imode,ivariant),isa,sflags,RTC_GEOMETRY_STATIC,imode,ivariant)); - groups.pop(); - - push(new TestGroup("quad_hit",true,true)); - for (auto sflags : sceneFlags) - for (auto imode : intersectModes) - for (auto ivariant : intersectVariants) - if (has_variant(imode,ivariant)) - groups.top()->add(new QuadHitTest(to_string(sflags,imode,ivariant),isa,sflags,RTC_GEOMETRY_STATIC,imode,ivariant)); - groups.pop(); - - if (rtcDeviceGetParameter1i(device,RTC_CONFIG_RAY_MASK)) - { - push(new TestGroup("ray_masks",true,true)); - for (auto sflags : sceneFlags) - for (auto imode : intersectModes) - for (auto ivariant : intersectVariants) - if (has_variant(imode,ivariant)) - groups.top()->add(new RayMasksTest(to_string(sflags,imode,ivariant),isa,sflags,RTC_GEOMETRY_STATIC,imode,ivariant)); - groups.pop(); - } - - if (rtcDeviceGetParameter1i(device,RTC_CONFIG_BACKFACE_CULLING)) - { - push(new TestGroup("backface_culling",true,true)); - for (auto gtype : gtypes) - for (auto sflags : sceneFlags) - for (auto imode : intersectModes) - for (auto ivariant : intersectVariants) - if (has_variant(imode,ivariant)) - groups.top()->add(new BackfaceCullingTest(to_string(gtype,sflags,imode,ivariant),isa,sflags,RTC_GEOMETRY_STATIC,gtype,imode,ivariant)); - groups.pop(); - } - - push(new TestGroup("intersection_filter",true,true)); - if (rtcDeviceGetParameter1i(device,RTC_CONFIG_INTERSECTION_FILTER)) - { - for (auto sflags : sceneFlags) - for (auto imode : intersectModes) - for (auto ivariant : intersectVariants) - if (has_variant(imode,ivariant)) - groups.top()->add(new IntersectionFilterTest("triangles."+to_string(sflags,imode,ivariant),isa,sflags,RTC_GEOMETRY_STATIC,false,imode,ivariant)); - - for (auto sflags : sceneFlags) - for (auto imode : intersectModes) - for (auto ivariant : intersectVariants) - if (has_variant(imode,ivariant)) - groups.top()->add(new IntersectionFilterTest("subdiv."+to_string(sflags,imode,ivariant),isa,sflags,RTC_GEOMETRY_STATIC,true,imode,ivariant)); - } - groups.pop(); - - push(new TestGroup("inactive_rays",true,true)); - for (auto sflags : sceneFlags) - for (auto imode : intersectModes) - for (auto ivariant : intersectVariants) - if (has_variant(imode,ivariant)) - if (imode != MODE_INTERSECT1) // INTERSECT1 does not support disabled rays - groups.top()->add(new InactiveRaysTest(to_string(sflags,imode,ivariant),isa,sflags,RTC_GEOMETRY_STATIC,imode,ivariant)); - groups.pop(); - - push(new TestGroup("watertight_triangles",true,true)); { - std::string watertightModels [] = {"sphere.triangles", "plane.triangles"}; - const Vec3fa watertight_pos = Vec3fa(148376.0f,1234.0f,-223423.0f); - for (auto sflags : sceneFlagsRobust) - for (auto imode : intersectModes) - for (std::string model : watertightModels) - groups.top()->add(new WatertightTest(to_string(sflags,imode)+"."+model,isa,sflags,imode,model,watertight_pos)); - groups.pop(); - } - - push(new TestGroup("watertight_triangles_mb",true,true)); { - std::string watertightModels [] = {"sphere.triangles_mb", "plane.triangles_mb"}; - const Vec3fa watertight_pos = Vec3fa(148376.0f,1234.0f,-223423.0f); - for (auto sflags : sceneFlagsRobust) - for (auto imode : intersectModes) - for (std::string model : watertightModels) - groups.top()->add(new WatertightTest(to_string(sflags,imode)+"."+model,isa,sflags,imode,model,watertight_pos)); - groups.pop(); - } - - push(new TestGroup("watertight_quads",true,true)); { - std::string watertightModels [] = {"sphere.quads", "plane.quads"}; - const Vec3fa watertight_pos = Vec3fa(148376.0f,1234.0f,-223423.0f); - for (auto sflags : sceneFlagsRobust) - for (auto imode : intersectModes) - for (std::string model : watertightModels) - groups.top()->add(new WatertightTest(to_string(sflags,imode)+"."+model,isa,sflags,imode,model,watertight_pos)); - groups.pop(); - } - - push(new TestGroup("watertight_quads_mb",true,true)); { - std::string watertightModels [] = {"sphere.quads_mb", "plane.quads_mb"}; - const Vec3fa watertight_pos = Vec3fa(148376.0f,1234.0f,-223423.0f); - for (auto sflags : sceneFlagsRobust) - for (auto imode : intersectModes) - for (std::string model : watertightModels) - groups.top()->add(new WatertightTest(to_string(sflags,imode)+"."+model,isa,sflags,imode,model,watertight_pos)); - groups.pop(); - } - - push(new TestGroup("watertight_subdiv",true,true)); { - std::string watertightModels [] = { "sphere.subdiv", "plane.subdiv"}; - const Vec3fa watertight_pos = Vec3fa(148376.0f,1234.0f,-223423.0f); - for (auto sflags : sceneFlagsRobust) - for (auto imode : intersectModes) - for (std::string model : watertightModels) - groups.top()->add(new WatertightTest(to_string(sflags,imode)+"."+model,isa,sflags,imode,model,watertight_pos)); - groups.pop(); - } - - /*push(new TestGroup("small_triangle_hit_test",true,true)); { - const Vec3fa pos = Vec3fa(0.0f,0.0f,0.0f); - const float radius = 1000000.0f; - for (auto sflags : sceneFlags) - for (auto imode : intersectModes) - groups.top()->add(new SmallTriangleHitTest(to_string(sflags,imode),isa,sflags,imode,pos,radius)); - groups.pop(); - }*/ - - push(new TestGroup("ray_alignment_test",true,true)); { - std::string watertightModels [] = {"sphere.triangles", "sphere.quads", "sphere.subdiv" }; - for (auto sflags : sceneFlagsRobust) - for (auto imode : intersectModes) - for (std::string model : watertightModels) - groups.top()->add(new RayAlignmentTest(to_string(sflags,imode)+"."+model,isa,sflags,imode,model)); - groups.pop(); - } - - if (rtcDeviceGetParameter1i(device,RTC_CONFIG_IGNORE_INVALID_RAYS)) - { - push(new TestGroup("nan_test",true,false)); - for (auto sflags : sceneFlags) - for (auto imode : intersectModes) - for (auto ivariant : intersectVariants) - if (has_variant(imode,ivariant)) - groups.top()->add(new NaNTest(to_string(sflags,imode,ivariant),isa,sflags,RTC_GEOMETRY_STATIC,imode,ivariant)); - groups.pop(); - - push(new TestGroup("inf_test",true,false)); - for (auto sflags : sceneFlags) - for (auto imode : intersectModes) - for (auto ivariant : intersectVariants) - if (has_variant(imode,ivariant)) - groups.top()->add(new InfTest(to_string(sflags,imode,ivariant),isa,sflags,RTC_GEOMETRY_STATIC,imode,ivariant)); - groups.pop(); - } - - /**************************************************************************/ - /* Randomized Stress Testing */ - /**************************************************************************/ - - groups.top()->add(new IntensiveRegressionTest("regression_static",isa,rtcore_regression_static_thread,0,30)); - groups.top()->add(new IntensiveRegressionTest("regression_dynamic",isa,rtcore_regression_dynamic_thread,0,300)); - - if (rtcDeviceGetParameter1i(device,RTC_CONFIG_COMMIT_THREAD)) { - groups.top()->add(new IntensiveRegressionTest("regression_static_user_threads", isa,rtcore_regression_static_thread,1,30)); - groups.top()->add(new IntensiveRegressionTest("regression_dynamic_user_threads",isa,rtcore_regression_dynamic_thread,1,300)); - } - - if (rtcDeviceGetParameter1i(device,RTC_CONFIG_COMMIT_JOIN)) { - groups.top()->add(new IntensiveRegressionTest("regression_static_build_join", isa,rtcore_regression_static_thread,2,30)); - groups.top()->add(new IntensiveRegressionTest("regression_dynamic_build_join",isa,rtcore_regression_dynamic_thread,2,300)); - } - - groups.top()->add(new MemoryMonitorTest("regression_static_memory_monitor", isa,rtcore_regression_static_thread,30)); - groups.top()->add(new MemoryMonitorTest("regression_dynamic_memory_monitor",isa,rtcore_regression_dynamic_thread,300)); - - /**************************************************************************/ - /* Benchmarks */ - /**************************************************************************/ - - push(new TestGroup("benchmarks",false,false)); - - std::vector> benchmark_sflags_gflags; - benchmark_sflags_gflags.push_back(std::make_pair(RTC_SCENE_STATIC,RTC_GEOMETRY_STATIC)); - benchmark_sflags_gflags.push_back(std::make_pair(RTC_SCENE_STATIC | RTC_SCENE_ROBUST,RTC_GEOMETRY_STATIC)); - benchmark_sflags_gflags.push_back(std::make_pair(RTC_SCENE_STATIC | RTC_SCENE_COMPACT,RTC_GEOMETRY_STATIC)); - benchmark_sflags_gflags.push_back(std::make_pair(RTC_SCENE_STATIC | RTC_SCENE_COMPACT | RTC_SCENE_ROBUST,RTC_GEOMETRY_STATIC)); - benchmark_sflags_gflags.push_back(std::make_pair(RTC_SCENE_DYNAMIC,RTC_GEOMETRY_DYNAMIC)); - - std::vector> benchmark_imodes_ivariants; - benchmark_imodes_ivariants.push_back(std::make_pair(MODE_INTERSECT1,VARIANT_INTERSECT)); - benchmark_imodes_ivariants.push_back(std::make_pair(MODE_INTERSECT1,VARIANT_OCCLUDED)); - benchmark_imodes_ivariants.push_back(std::make_pair(MODE_INTERSECT4,VARIANT_INTERSECT)); - benchmark_imodes_ivariants.push_back(std::make_pair(MODE_INTERSECT4,VARIANT_OCCLUDED)); - benchmark_imodes_ivariants.push_back(std::make_pair(MODE_INTERSECT8,VARIANT_INTERSECT)); - benchmark_imodes_ivariants.push_back(std::make_pair(MODE_INTERSECT8,VARIANT_OCCLUDED)); - benchmark_imodes_ivariants.push_back(std::make_pair(MODE_INTERSECT16,VARIANT_INTERSECT)); - benchmark_imodes_ivariants.push_back(std::make_pair(MODE_INTERSECT16,VARIANT_OCCLUDED)); - benchmark_imodes_ivariants.push_back(std::make_pair(MODE_INTERSECT1M,VARIANT_INTERSECT_INCOHERENT)); - benchmark_imodes_ivariants.push_back(std::make_pair(MODE_INTERSECT1M,VARIANT_OCCLUDED_INCOHERENT)); - - GeometryType benchmark_gtypes[] = { - TRIANGLE_MESH, - TRIANGLE_MESH_MB, - QUAD_MESH, - QUAD_MESH_MB, - SUBDIV_MESH, - //SUBDIV_MESH_MB // FIXME: not supported yet - // FIXME: use more geometry types - }; - - groups.top()->add(new SimpleBenchmark("simple",isa)); - - for (auto gtype : benchmark_gtypes) - for (auto sflags : benchmark_sflags_gflags) - for (auto imode : benchmark_imodes_ivariants) - groups.top()->add(new CoherentRaysBenchmark("coherent."+to_string(gtype)+"_1000k."+to_string(sflags.first,imode.first,imode.second), - isa,gtype,sflags.first,sflags.second,imode.first,imode.second,501)); - - for (auto gtype : benchmark_gtypes) - for (auto sflags : benchmark_sflags_gflags) - for (auto imode : benchmark_imodes_ivariants) - groups.top()->add(new IncoherentRaysBenchmark("incoherent."+to_string(gtype)+"_1000k."+to_string(sflags.first,imode.first,imode.second), - isa,gtype,sflags.first,sflags.second,imode.first,imode.second,501)); - - std::vector> benchmark_create_sflags_gflags; - benchmark_create_sflags_gflags.push_back(std::make_pair(RTC_SCENE_STATIC,RTC_GEOMETRY_STATIC)); - //benchmark_create_sflags_gflags.push_back(std::make_pair(RTC_SCENE_DYNAMIC,RTC_GEOMETRY_STATIC)); - //benchmark_create_sflags_gflags.push_back(std::make_pair(RTC_SCENE_DYNAMIC,RTC_GEOMETRY_DEFORMABLE)); - benchmark_create_sflags_gflags.push_back(std::make_pair(RTC_SCENE_DYNAMIC,RTC_GEOMETRY_DYNAMIC)); - - GeometryType benchmark_create_gtypes[] = { - TRIANGLE_MESH, - TRIANGLE_MESH_MB, - QUAD_MESH, - QUAD_MESH_MB, - HAIR_GEOMETRY, - HAIR_GEOMETRY_MB, - LINE_GEOMETRY, - LINE_GEOMETRY_MB - }; - - std::vector> num_primitives; - num_primitives.push_back(std::make_tuple("120",6,1)); - num_primitives.push_back(std::make_tuple("1k" ,17,1)); - num_primitives.push_back(std::make_tuple("10k",51,1)); - num_primitives.push_back(std::make_tuple("100k",159,1)); - num_primitives.push_back(std::make_tuple("10000k_1",801,1)); - num_primitives.push_back(std::make_tuple("1000k_1",501,1)); - num_primitives.push_back(std::make_tuple("100k_10",159,10)); - num_primitives.push_back(std::make_tuple("10k_100",51,100)); - num_primitives.push_back(std::make_tuple("1k_1000",17,1000)); - - for (auto gtype : benchmark_create_gtypes) - for (auto sflags : benchmark_create_sflags_gflags) - for (auto num_prims : num_primitives) - groups.top()->add(new CreateGeometryBenchmark("create."+to_string(gtype)+"_"+std::get<0>(num_prims)+"."+to_string(sflags.first,sflags.second), - isa,gtype,sflags.first,sflags.second,std::get<1>(num_prims),std::get<2>(num_prims),false,true)); - - std::vector> benchmark_update_sflags_gflags; - benchmark_update_sflags_gflags.push_back(std::make_pair(RTC_SCENE_DYNAMIC,RTC_GEOMETRY_STATIC)); - benchmark_update_sflags_gflags.push_back(std::make_pair(RTC_SCENE_DYNAMIC,RTC_GEOMETRY_DEFORMABLE)); - benchmark_update_sflags_gflags.push_back(std::make_pair(RTC_SCENE_DYNAMIC,RTC_GEOMETRY_DYNAMIC)); - - for (auto gtype : benchmark_create_gtypes) - for (auto sflags : benchmark_update_sflags_gflags) - for (auto num_prims : num_primitives) - groups.top()->add(new CreateGeometryBenchmark("update."+to_string(gtype)+"_"+std::get<0>(num_prims)+"."+to_string(sflags.first,sflags.second), - isa,gtype,sflags.first,sflags.second,std::get<1>(num_prims),std::get<2>(num_prims),true,true)); - - groups.pop(); // benchmarks - - /**************************************************************************/ - /* Memory Consumption */ - /**************************************************************************/ - - push(new TestGroup("embree_reported_memory",false,false)); - - for (auto gtype : benchmark_create_gtypes) - for (auto sflags : benchmark_create_sflags_gflags) - for (auto num_prims : num_primitives) - groups.top()->add(new CreateGeometryBenchmark(to_string(gtype)+"_"+std::get<0>(num_prims)+"."+to_string(sflags.first,sflags.second), - isa,gtype,sflags.first,sflags.second,std::get<1>(num_prims),std::get<2>(num_prims),false,false)); - - groups.pop(); // embree_reported_memory - - groups.pop(); // isa - } - - prefix_test_names(tests); - - /* ignore failure of some tests that are known to fail */ - map_tests(tests, [&] (Ref test) { - if (test->name.find("watertight_subdiv") != std::string::npos) test->ignoreFailure = true; - if (test->name.find("memory_consumption") != std::string::npos) test->ignoreFailure = true; - - }); - - /**************************************************************************/ - /* Command Line Parsing */ - /**************************************************************************/ - - registerOption("run", [this] (Ref cin, const FileName& path) { - if (!user_specified_tests) enable_disable_all_tests(tests,false); - user_specified_tests = true; - std::string regex = cin->getString(); - if (!enable_disable_some_tests(tests,regex,true)) { - std::cout << "no tests matched regular expression " << regex << std::endl; - exit(1); - } - }, "--run : Runs all tests whose name match the regular expression. If no test matches the application fails."); - - registerOption("enable", [this] (Ref cin, const FileName& path) { - if (!user_specified_tests) enable_disable_all_tests(tests,false); - user_specified_tests = true; - std::string regex = cin->getString(); - enable_disable_some_tests(tests,regex,true); - }, "--enable : Enables all tests whose name matches the regular expression."); - - registerOption("skip", [this] (Ref cin, const FileName& path) { - user_specified_tests = true; - std::string regex = cin->getString(); - enable_disable_some_tests(tests,regex,false); - }, "--skip : Skips all tests whose name matches the regular expression."); - registerOptionAlias("skip","disable"); - - registerOption("skip-before", [this] (Ref cin, const FileName& path) { - user_specified_tests = true; - bool found = false; - std::string regex = cin->getString(); - map_tests(tests, [&] (Ref test) { - if (regex_match(test->name,regex)) found = true; - test->enabled &= found; - }); - }, "--skip-before : Skips all tests before the first test matching the regular expression."); - registerOptionAlias("skip-before","disable-before"); - - registerOption("flatten", [this] (Ref cin, const FileName& path) { - flatten = false; - }, "--flatten: shows all leaf test names when executing tests"); - - registerOption("sequential", [this] (Ref cin, const FileName& path) { - parallel = false; - }, "--sequential: execute all tests sequentially"); - - registerOption("parallel", [this] (Ref cin, const FileName& path) { - parallel = true; - }, "--parallel: parallelized test execution (default)"); - - registerOption("colors", [this] (Ref cin, const FileName& path) { - usecolors = true; - }, "--colors: do use shell colors"); - - registerOption("no-colors", [this] (Ref cin, const FileName& path) { - usecolors = false; - }, "--no-colors: do not use shell colors"); - - registerOption("cdash", [this] (Ref cin, const FileName& path) { - cdash = true; - }, "--cdash: prints cdash measurements"); - - registerOption("database", [this] (Ref cin, const FileName& path) { - database = cin->getString(); - update_database = true; - }, "--database: location to folder containing the measurement database"); - - registerOption("compare", [this] (Ref cin, const FileName& path) { - database = cin->getString(); - update_database = false; - }, "--compare: compares with database, but does not update database"); - - registerOption("benchmark-tolerance", [this] (Ref cin, const FileName& path) { - benchmark_tolerance = cin->getFloat(); - }, "--benchmark-tolerance: maximal relative slowdown to let a test pass"); - registerOptionAlias("benchmark-tolerance","tolerance"); - - registerOption("print-tests", [this] (Ref cin, const FileName& path) { - print_tests(tests,0); - exit(1); - }, "--print-tests: prints all enabled test names"); - registerOptionAlias("print-tests","print-names"); - - registerOption("print-ctests", [this] (Ref cin, const FileName& path) { - print_ctests(tests,0); - exit(1); - }, "--print-ctests: prints all test in a form to add to CMakeLists.txt"); - - registerOption("intensity", [this] (Ref cin, const FileName& path) { - intensity = cin->getFloat(); - }, "--intensity : intensity of testing to perform"); - - registerOption("plot-over-primitives", [this] (Ref cin, const FileName& path) { - std::vector> benchmarks; - FileName outFileName = parse_benchmark_list(cin,benchmarks); - plot(benchmarks,outFileName,"#primitives",1000,1100000,1.2f,0,[&] (Ref benchmark, size_t& N) { - N = benchmark->setNumPrimitives(N); - benchmark->setup(this); - Statistics stat = benchmark->benchmark_loop(this); - benchmark->cleanup(this); - return stat; - }); - exit(1); - }, "--plot-over-primitives ... : Plots performance over number of primitives to outfile for the specified benchmarks."); - - registerOption("plot-over-threads", [this] (Ref cin, const FileName& path) { - std::vector> benchmarks; - FileName outFileName = parse_benchmark_list(cin,benchmarks); - plot(benchmarks,outFileName,"#threads",2,getNumberOfLogicalThreads(),1.0f,2,[&] (Ref benchmark, size_t N) { - benchmark->setNumThreads(N); - benchmark->setup(this); - Statistics stat = benchmark->benchmark_loop(this); - benchmark->cleanup(this); - return stat; - }); - exit(1); - }, "--plot-over-primitives ... : Plots performance over number of primitives to outfile for the specified benchmarks."); - - /* the internal tasking system need the device to be present to allow parallel test execution */ -#if !defined(TASKING_INTERNAL) - device = nullptr; -#endif - } - - void VerifyApplication::prefix_test_names(Ref test, std::string prefix) - { - if (Ref group = test.dynamicCast()) - for (auto& t : group->tests) - prefix_test_names(t,group->extend_prefix(prefix)); - - test->name = prefix + test->name; - name2test[test->name] = test; - } - - FileName VerifyApplication::parse_benchmark_list(Ref cin, std::vector>& benchmarks) - { - std::vector regexpr; - while (cin->peek() != "" && cin->peek()[0] != '-') - regexpr.push_back(cin->getString()); - - if (regexpr.size() == 0) throw std::runtime_error("no output file specified"); - FileName outFileName = regexpr.back(); - regexpr.pop_back(); - - for (size_t i=0; i test) { - if (!regex_match(test->name,regexpr[i])) return; - Ref benchmark = test.dynamicCast(); - if (!benchmark) return; - benchmarks.push_back(benchmark); - }); - } - return outFileName; - } - - bool VerifyApplication::update_tests(Ref test) - { - if (Ref group = test.dynamicCast()) - { - bool any_enabled = false; - for (auto t : group->tests) any_enabled |= update_tests(t); - return test->enabled = any_enabled; - } - else - return test->enabled; - } - - void VerifyApplication::print_tests(Ref test, size_t depth) - { - if (!test->isEnabled()) return; - - if (Ref group = test.dynamicCast()) - { - std::cout << std::string(2*depth,' ') << group->name << (group->name != "" ? " " : "") << "{" << std::endl; - for (auto& t : group->tests) print_tests(t,depth+1); - std::cout << std::string(2*depth,' ') << "}" << std::endl; - } else { - std::cout << std::string(2*depth,' ') << test->name << std::endl; - } - } - - void VerifyApplication::print_ctests(Ref test, size_t depth) - { - if (!test->isEnabled()) return; - - if (Ref group = test.dynamicCast()) - { - for (auto& t : group->tests) print_ctests(t,depth+1); - } else { - std::cout << "ADD_TEST(NAME " << test->name << " COMMAND verify --no-colors --cdash-measurements --run " << test->name << std::endl; - } - } - - template - void VerifyApplication::map_tests(Ref test, const Function& f) - { - if (Ref group = test.dynamicCast()) { - for (auto& t : group->tests) map_tests(t,f); - } else { - f(test); - } - } - - void VerifyApplication::enable_disable_all_tests(Ref test, bool enabled) - { - map_tests(test, [&] (Ref test) { test->enabled = enabled; }); - update_tests(test); - } - - size_t VerifyApplication::enable_disable_some_tests(Ref test, std::string regex, bool enabled) - { - size_t N = 0; - map_tests(test, [&] (Ref test) { - if (regex_match(test->name,regex)) { - test->enabled = enabled; - N++; - } - }); - update_tests(test); - return N; - } - - template - void VerifyApplication::plot(std::vector> benchmarks, const FileName outFileName, std::string xlabel, size_t startN, size_t endN, float f, size_t dn, const Closure& test) - { - std::fstream plot; - plot.open(outFileName, std::fstream::out | std::fstream::trunc); - plot << "set key inside right top vertical Right noreverse enhanced autotitles box linetype -1 linewidth 1.000" << std::endl; - plot << "set samples 50, 50" << std::endl; - plot << "set title \"" << outFileName.name() << "\"" << std::endl; - plot << "set xlabel \"" + xlabel + "\"" << std::endl; - if (f != 1.0f) plot << "set logscale x" << std::endl; - if (benchmarks.size()) - plot << "set ylabel \"" << benchmarks[0]->unit << "\"" << std::endl; - plot << "set yrange [0:]" << std::endl; - - plot << "plot \\" << std::endl; - for (size_t i=0; iname << ".txt\" using 1:2 title \"" << benchmarks[i]->name << "\" with lines"; - if (i != benchmarks.size()-1) plot << ",\\"; - plot << std::endl; - } - plot << std::endl; - plot.close(); - - for (auto benchmark : benchmarks) - { - std::fstream data; - data.open(outFileName.name()+"."+benchmark->name+".txt", std::fstream::out | std::fstream::trunc); - std::cout << benchmark->name << std::endl; - for (size_t i=startN; i<=endN; i=size_t(i*f)+dn) - { - size_t N = i; - Statistics stat = test(benchmark,N); - data << " " << N << " " << stat.getAvg() << std::endl; - std::cout<< " " << N << " " << stat.getAvg() << std::endl; - } - data.close(); - } - } - - int VerifyApplication::main(int argc, char** argv) try - { - /* for best performance set FTZ and DAZ flags in MXCSR control and status register */ - _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); - _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); - - /* parse command line options */ - parseCommandLine(argc,argv); - - /* run all enabled tests */ - tests->execute(this,false); - - /* print result */ - std::cout << std::endl; - std::cout << std::setw(TEXT_ALIGN) << "Tests passed" << ": " << numPassedTests << std::endl; - std::cout << std::setw(TEXT_ALIGN) << "Tests failed" << ": " << numFailedTests << std::endl; - std::cout << std::setw(TEXT_ALIGN) << "Tests failed and ignored" << ": " << numFailedAndIgnoredTests << std::endl; - std::cout << std::endl; - - return (int)numFailedTests; - } - catch (const std::exception& e) { - std::cout << "Error: " << e.what() << std::endl; - return 1; - } - catch (...) { - std::cout << "Error: unknown exception caught." << std::endl; - return 1; - } -} - -int main(int argc, char** argv) -{ - embree::VerifyApplication app; - return app.main(argc,argv); -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/verify/verify.h b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/verify/verify.h deleted file mode 100644 index a1a2e46982b3..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/verify/verify.h +++ /dev/null @@ -1,202 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -/* we include the Embree headers the very first to make sure they - * always compile without any internal Embree specific stuff. */ -#include "../include/embree2/rtcore.h" -#include "../include/embree2/rtcore_ray.h" - -/* now we include all Embree internal files we need for testing */ -#include "../kernels/common/default.h" -#include "../kernels/common/ray.h" -#include "rtcore_helpers.h" -#include "../tutorials/common/tutorial/application.h" -#include "../tutorials/common/math/random_sampler.h" -#include "../tutorials/common/tutorial/statistics.h" - -namespace embree -{ - class VerifyApplication : public Application - { - public: - enum TestType { TEST_SHOULD_PASS, TEST_SHOULD_FAIL, TEST_GROUP, BENCHMARK }; - enum TestReturnValue { FAILED, PASSED, SKIPPED }; - - struct Test : public RefCount - { - Test (std::string name, int isa, TestType ty, bool enabled = true) - : name(name), isa(isa), ty(ty), enabled(enabled), ignoreFailure(false) - { - RandomSampler_init(sampler,0x23F67E21); - } - - float random_float () { return RandomSampler_getFloat(sampler); } - int random_int () { return RandomSampler_getInt (sampler); } - Vec3fa random_Vec3fa() { return RandomSampler_get3D (sampler); } - - avector random_motion_vector2(float f = 1.0f) - { - avector motion_vector(2); - motion_vector[0] = f*random_Vec3fa(); - motion_vector[1] = f*random_Vec3fa(); - return motion_vector; - } - - avector random_motion_vector(float f = 1.0f) - { - float v = random_float(); - size_t numTimeSteps = clamp(int(v*v*9),2,8); // samples small number of time steps more frequently - - avector motion_vector(numTimeSteps); - for (size_t i=0; i test) { - tests.push_back(test); - } - - std::string extend_prefix(std::string prefix) const { - return (name != "") ? prefix + name + "." : prefix; - } - - bool isEnabled() { return enabled; } - TestReturnValue execute(VerifyApplication* state, bool silent); - - public: - bool silent; - bool parallel; - std::vector> tests; - }; - - struct IntersectTest : public Test - { - IntersectTest (std::string name, int isa, IntersectMode imode, IntersectVariant ivariant, TestType ty = TEST_SHOULD_PASS) - : Test(name,isa,ty), imode(imode), ivariant(ivariant) {} - - public: - IntersectMode imode; - IntersectVariant ivariant; - }; - - public: - - VerifyApplication (); - void prefix_test_names(Ref test, std::string prefix = ""); - bool update_tests(Ref test); - void print_tests(Ref test, size_t depth); - void print_ctests(Ref test, size_t depth); - template - void map_tests(Ref test, const Function& f); - void enable_disable_all_tests(Ref test, bool enabled); - size_t enable_disable_some_tests(Ref test, std::string regex, bool enabled); - template - void plot(std::vector> benchmarks, const FileName outFileName, std::string xlabel, size_t startN, size_t endN, float f, size_t dn, const Closure& test); - FileName parse_benchmark_list(Ref cin, std::vector>& benchmarks); - int main(int argc, char** argv); - - public: - float intensity; - std::atomic numPassedTests; - std::atomic numFailedTests; - std::atomic numFailedAndIgnoredTests; - - public: - MutexSys mutex; - std::vector isas; - Ref tests; - std::map> name2test; - - public: - RTCDeviceRef device; - std::vector sceneFlags; - std::vector sceneFlagsRobust; - std::vector sceneFlagsDynamic; - std::vector intersectModes; - std::vector intersectVariants; - bool user_specified_tests; - bool flatten; - bool parallel; - bool cdash; - FileName database; - bool update_database; - float benchmark_tolerance; - - /* sets terminal colors */ - public: - std::string green(std::string str) { - if (usecolors) return "\033[32m" + str + "\033[0m"; - else return str; - } - std::string yellow(std::string str) { - if (usecolors) return "\033[33m" + str + "\033[0m"; - else return str; - } - std::string red(std::string str) { - if (usecolors) return "\033[31m" + str + "\033[0m"; - else return str; - } - bool usecolors; - }; -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/viewer/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/viewer/CMakeLists.txt deleted file mode 100644 index 4de77b63bd60..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/viewer/CMakeLists.txt +++ /dev/null @@ -1,30 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2017 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -INCLUDE(tutorial) -ADD_TUTORIAL(viewer) -ADD_EMBREE_MODELS_TEST(viewer viewer viewer) -ADD_EMBREE_MODELS_TEST(viewer_quad viewer viewer -convert-triangles-to-quads) -ADD_EMBREE_SUBDIV_MODELS_TEST(viewer viewer viewer viewer) - -IF (EMBREE_TESTING_INTENSIVE) - ADD_EMBREE_MODELS_TEST(viewer_static_scene viewer viewer viewer -rtcore flags=static) - ADD_EMBREE_MODELS_TEST(viewer_dynamic_scene viewer viewer viewer -rtcore flags=dynamic) - ADD_EMBREE_MODELS_TEST(viewer_high_quality_scene viewer viewer viewer -rtcore flags=high_quality) - ADD_EMBREE_MODELS_TEST(viewer_robust_scene viewer viewer viewer -rtcore flags=robust) - ADD_EMBREE_MODELS_TEST(viewer_compact_scene viewer viewer viewer -rtcore flags=compact) -ENDIF() - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/viewer/viewer.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/viewer/viewer.cpp deleted file mode 100644 index 700393abb51e..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/viewer/viewer.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial.h" - -namespace embree -{ - extern "C" { int g_instancing_mode = 0; } - - struct Tutorial : public SceneLoadingTutorialApplication - { - Tutorial() - : SceneLoadingTutorialApplication("viewer",FEATURE_RTCORE) {} - - void postParseCommandLine() - { - /* load default scene if none specified */ - if (scene->size() == 0 && sceneFilename.ext() == "") { - FileName file = FileName::executableFolder() + FileName("models/cornell_box.ecs"); - parseCommandLine(new ParseStream(new LineCommentFilter(file, "#")), file.path()); - } - - g_instancing_mode = instancing_mode; - } - }; - -} - -int main(int argc, char** argv) { - return embree::Tutorial().main(argc,argv); -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/viewer/viewer_device.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/viewer/viewer_device.cpp deleted file mode 100644 index 8e63f2f0f694..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree2140/src/tutorials/viewer/viewer_device.cpp +++ /dev/null @@ -1,419 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2017 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/math/random_sampler.h" -#include "../common/core/differential_geometry.h" -#include "../common/tutorial/tutorial_device.h" -#include "../common/tutorial/scene_device.h" - -namespace embree { - -extern "C" ISPCScene* g_ispc_scene; -extern "C" bool g_changed; -extern "C" int g_instancing_mode; - -/* scene data */ -RTCDevice g_device = nullptr; -RTCScene g_scene = nullptr; -extern "C" RTCScene* geomID_to_scene; -extern "C" ISPCInstance** geomID_to_inst; -bool g_subdiv_mode = false; - -#define SPP 1 - -#define FIXED_EDGE_TESSELLATION_VALUE 3 - -#define MAX_EDGE_LEVEL 64.0f -#define MIN_EDGE_LEVEL 4.0f -#define LEVEL_FACTOR 64.0f - -inline float updateEdgeLevel( ISPCSubdivMesh* mesh, const Vec3fa& cam_pos, const size_t e0, const size_t e1) -{ - const Vec3fa v0 = mesh->positions[mesh->position_indices[e0]]; - const Vec3fa v1 = mesh->positions[mesh->position_indices[e1]]; - const Vec3fa edge = v1-v0; - const Vec3fa P = 0.5f*(v1+v0); - const Vec3fa dist = cam_pos - P; - return max(min(LEVEL_FACTOR*(0.5f*length(edge)/length(dist)),MAX_EDGE_LEVEL),MIN_EDGE_LEVEL); -} - - -void updateEdgeLevelBuffer( ISPCSubdivMesh* mesh, const Vec3fa& cam_pos, size_t startID, size_t endID ) -{ - for (size_t f=startID; fface_offsets[f]; - unsigned int N = mesh->verticesPerFace[f]; - if (N == 4) /* fast path for quads */ - for (size_t i=0; i<4; i++) - mesh->subdivlevel[e+i] = updateEdgeLevel(mesh,cam_pos,e+(i+0),e+(i+1)%4); - else if (N == 3) /* fast path for triangles */ - for (size_t i=0; i<3; i++) - mesh->subdivlevel[e+i] = updateEdgeLevel(mesh,cam_pos,e+(i+0),e+(i+1)%3); - else /* fast path for general polygons */ - for (size_t i=0; isubdivlevel[e+i] = updateEdgeLevel(mesh,cam_pos,e+(i+0),e+(i+1)%N); - } -} - -#if defined(ISPC) -void updateSubMeshEdgeLevelBufferTask (int taskIndex, ISPCSubdivMesh* mesh, const Vec3fa& cam_pos ) -{ - const size_t size = mesh->numFaces; - const size_t startID = ((taskIndex+0)*size)/taskCount; - const size_t endID = ((taskIndex+1)*size)/taskCount; - updateEdgeLevelBuffer(mesh,cam_pos,startID,endID); -} -void updateMeshEdgeLevelBufferTask (int taskIndex, ISPCScene* scene_in, const Vec3fa& cam_pos ) -{ - ISPCGeometry* geometry = g_ispc_scene->geometries[taskIndex]; - if (geometry->type != SUBDIV_MESH) return; - ISPCSubdivMesh* mesh = (ISPCSubdivMesh*) geometry; - unsigned int geomID = mesh->geomID; - if (mesh->numFaces < 10000) { - updateEdgeLevelBuffer(mesh,cam_pos,0,mesh->numFaces); - rtcUpdateBuffer(g_scene,mesh->geomID,RTC_LEVEL_BUFFER); - } -} -#endif - -void updateEdgeLevels(ISPCScene* scene_in, const Vec3fa& cam_pos) -{ - /* first update small meshes */ -#if defined(ISPC) - parallel_for(size_t(0),size_t( scene_in->numGeometries ),[&](const range& range) { - for (size_t i=range.begin(); inumGeometries; g++) - { - ISPCGeometry* geometry = g_ispc_scene->geometries[g]; - if (geometry->type != SUBDIV_MESH) continue; - ISPCSubdivMesh* mesh = (ISPCSubdivMesh*) geometry; -#if defined(ISPC) - if (mesh->numFaces < 10000) continue; - parallel_for(size_t(0),size_t( (mesh->numFaces+4095)/4096 ),[&](const range& range) { - for (size_t i=range.begin(); inumFaces); -#endif - rtcUpdateBuffer(g_scene,mesh->geomID,RTC_LEVEL_BUFFER); - } -} - -bool g_use_smooth_normals = false; -void device_key_pressed_handler(int key) -{ - if (key == 115 /*c*/) g_use_smooth_normals = !g_use_smooth_normals; - else device_key_pressed_default(key); -} - -RTCScene convertScene(ISPCScene* scene_in) -{ - for (size_t i=0; inumGeometries; i++) - { - ISPCGeometry* geometry = scene_in->geometries[i]; - if (geometry->type == SUBDIV_MESH) { - g_subdiv_mode = true; break; - } - } - - int scene_flags = RTC_SCENE_STATIC | RTC_SCENE_INCOHERENT; - int scene_aflags = RTC_INTERSECT1 | RTC_INTERPOLATE; - if (g_subdiv_mode) - scene_flags = RTC_SCENE_DYNAMIC | RTC_SCENE_INCOHERENT | RTC_SCENE_ROBUST; - - RTCScene scene_out = ConvertScene(g_device, g_ispc_scene,(RTCSceneFlags)scene_flags, (RTCAlgorithmFlags) scene_aflags, RTC_GEOMETRY_STATIC); - - /* commit individual objects in case of instancing */ - if (g_instancing_mode == 2 || g_instancing_mode == 3) - { - for (unsigned int i=0; inumGeometries; i++) { - if (geomID_to_scene[i]) rtcCommit(geomID_to_scene[i]); - } - } - - /* commit changes to scene */ - return scene_out; -} - - -void postIntersectGeometry(const RTCRay& ray, DifferentialGeometry& dg, ISPCGeometry* geometry, int& materialID) -{ - if (geometry->type == TRIANGLE_MESH) - { - ISPCTriangleMesh* mesh = (ISPCTriangleMesh*) geometry; - materialID = mesh->triangles[ray.primID].materialID; - } - else if (geometry->type == QUAD_MESH) - { - ISPCQuadMesh* mesh = (ISPCQuadMesh*) geometry; - materialID = mesh->materialID; - } - else if (geometry->type == SUBDIV_MESH) - { - ISPCSubdivMesh* mesh = (ISPCSubdivMesh*) geometry; - materialID = mesh->materialID; - } - else if (geometry->type == LINE_SEGMENTS) - { - ISPCLineSegments* mesh = (ISPCLineSegments*) geometry; - materialID = mesh->materialID; - } - else if (geometry->type == HAIR_SET) - { - ISPCHairSet* mesh = (ISPCHairSet*) geometry; - materialID = mesh->materialID; - } - else if (geometry->type == CURVES) - { - ISPCHairSet* mesh = (ISPCHairSet*) geometry; - materialID = mesh->materialID; - } - else if (geometry->type == GROUP) { - unsigned int geomID = ray.geomID; { - postIntersectGeometry(ray,dg,((ISPCGroup*) geometry)->geometries[geomID],materialID); - } - } - else - assert(false); -} - -AffineSpace3fa calculate_interpolated_space (ISPCInstance* instance, float gtime) -{ - if (instance->numTimeSteps == 1) - return AffineSpace3fa(instance->spaces[0]); - - /* calculate time segment itime and fractional time ftime */ - const int time_segments = instance->numTimeSteps-1; - const float time = gtime*(float)(time_segments); - const int itime = clamp((int)(floor(time)),(int)0,time_segments-1); - const float ftime = time - (float)(itime); - return (1.0f-ftime)*AffineSpace3fa(instance->spaces[itime+0]) + ftime*AffineSpace3fa(instance->spaces[itime+1]); -} - -inline int postIntersect(const RTCRay& ray, DifferentialGeometry& dg) -{ - int materialID = 0; - unsigned ray_geomID = g_instancing_mode >= 2 ? ray.instID : ray.geomID; - unsigned int geomID = ray_geomID; - { - /* get instance and geometry pointers */ - ISPCInstance* instance; - ISPCGeometry* geometry; - if (g_instancing_mode) { - instance = geomID_to_inst[geomID]; - geometry = g_ispc_scene->geometries[instance->geomID]; - } else { - instance = nullptr; - geometry = g_ispc_scene->geometries[geomID]; - } - - postIntersectGeometry(ray,dg,geometry,materialID); - - /* convert normals */ - if (instance) { - //AffineSpace3fa space = (1.0f-ray.time)*AffineSpace3fa(instance->space0) + ray.time*AffineSpace3fa(instance->space1); - AffineSpace3fa space = calculate_interpolated_space(instance,ray.time); - dg.Ng = xfmVector(space,dg.Ng); - dg.Ns = xfmVector(space,dg.Ns); - } - } - - return materialID; -} - -inline Vec3fa face_forward(const Vec3fa& dir, const Vec3fa& _Ng) { - const Vec3fa Ng = _Ng; - return dot(dir,Ng) < 0.0f ? Ng : neg(Ng); -} - -/* task that renders a single screen tile */ -Vec3fa renderPixelStandard(float x, float y, const ISPCCamera& camera) -{ - /* initialize sampler */ - RandomSampler sampler; - RandomSampler_init(sampler, (int)x, (int)y, 0); - - /* initialize ray */ - RTCRay ray; - ray.org = Vec3fa(camera.xfm.p); - ray.dir = Vec3fa(normalize(x*camera.xfm.l.vx + y*camera.xfm.l.vy + camera.xfm.l.vz)); - ray.tnear = 0.0f; - ray.tfar = inf; - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.primID = RTC_INVALID_GEOMETRY_ID; - ray.mask = -1; - ray.time = RandomSampler_get1D(sampler); - - /* intersect ray with scene */ - rtcIntersect(g_scene,ray); - - /* shade background black */ - if (ray.geomID == RTC_INVALID_GEOMETRY_ID) { - return Vec3fa(0.0f); - } - - /* shade all rays that hit something */ - Vec3fa color = Vec3fa(0.5f); - - /* compute differential geometry */ - DifferentialGeometry dg; - dg.geomID = ray.geomID; - dg.primID = ray.primID; - dg.u = ray.u; - dg.v = ray.v; - dg.P = ray.org+ray.tfar*ray.dir; - dg.Ng = ray.Ng; - dg.Ns = ray.Ng; - - if (g_use_smooth_normals) - if (ray.geomID != RTC_INVALID_GEOMETRY_ID) // FIXME: workaround for ISPC bug, location reached with empty execution mask - { - Vec3fa dPdu,dPdv; - unsigned int geomID = ray.geomID; { - rtcInterpolate(g_scene,geomID,ray.primID,ray.u,ray.v,RTC_VERTEX_BUFFER0,nullptr,&dPdu.x,&dPdv.x,3); - } - dg.Ns = cross(dPdv,dPdu); - } - - int materialID = postIntersect(ray,dg); - dg.Ng = face_forward(ray.dir,normalize(dg.Ng)); - dg.Ns = face_forward(ray.dir,normalize(dg.Ns)); - - /* shade */ - if (g_ispc_scene->materials[materialID].ty == MATERIAL_OBJ) { - OBJMaterial* material = (OBJMaterial*) &g_ispc_scene->materials[materialID]; - color = Vec3fa(material->Kd); - } - - return color*dot(neg(ray.dir),dg.Ns); -} - -/* renders a single screen tile */ -void renderTileStandard(int taskIndex, - int* pixels, - const unsigned int width, - const unsigned int height, - const float time, - const ISPCCamera& camera, - const int numTilesX, - const int numTilesY) -{ - const int t = taskIndex; - const unsigned int tileY = t / numTilesX; - const unsigned int tileX = t - tileY * numTilesX; - const unsigned int x0 = tileX * TILE_SIZE_X; - const unsigned int x1 = min(x0+TILE_SIZE_X,width); - const unsigned int y0 = tileY * TILE_SIZE_Y; - const unsigned int y1 = min(y0+TILE_SIZE_Y,height); - - for (unsigned int y=y0; y& range) { - for (size_t i=range.begin(); i buildTime; - std::vector vertexUpdateTime; - std::vector renderTime; - bool printStats = false; - bool timeInitialized = false; - - static const size_t numProfileFrames = 200; - - /* shadow distance map */ - -#if DUMP_PROFILE_DATA == 1 - void dumpBuildAndRenderTimes(); -#endif - - void device_key_pressed_handler(int key) - { - if (key == 100 /*d*/) { -#if DUMP_PROFILE_DATA == 1 - std::cout << "dumping build and render times per frame [" << buildTime.size() << " frames]..." << std::flush; - dumpBuildAndRenderTimes(); - std::cout << "done" << std::endl; -#endif - } - else if (key == 115 /*s*/) { - printStats = !printStats; - } - else device_key_pressed_default(key); - } - - // ================================================================================================== - // ================================================================================================== - // ================================================================================================== - - - unsigned int convertTriangleMesh(ISPCTriangleMesh* mesh, RTCScene scene_out) - { - /* if more than a single timestep, mark object as dynamic */ - RTCGeometryFlags object_flags = mesh->numTimeSteps > 1 ? RTC_GEOMETRY_DYNAMIC : RTC_GEOMETRY_STATIC; - /* create object */ - unsigned int geomID = rtcNewTriangleMesh (scene_out, object_flags, mesh->numTriangles, mesh->numVertices, 1); - /* generate vertex buffer */ - Vec3fa* vertices = (Vec3fa*) rtcMapBuffer(scene_out,geomID,RTC_VERTEX_BUFFER); - for (size_t i=0;inumVertices;i++) vertices[i] = mesh->positions[i]; - rtcUnmapBuffer(scene_out, geomID, RTC_VERTEX_BUFFER); - /* set index buffer */ - rtcSetBuffer(scene_out, geomID, RTC_INDEX_BUFFER, mesh->triangles, 0, sizeof(ISPCTriangle)); - mesh->geomID = geomID; - return geomID; - } - - - unsigned int convertQuadMesh(ISPCQuadMesh* mesh, RTCScene scene_out) - { - /* if more than a single timestep, mark object as dynamic */ - RTCGeometryFlags object_flags = mesh->numTimeSteps > 1 ? RTC_GEOMETRY_DYNAMIC : RTC_GEOMETRY_STATIC; - /* create object */ - unsigned int geomID = rtcNewQuadMesh (scene_out, object_flags, mesh->numQuads, mesh->numVertices, mesh->numTimeSteps); - /* generate vertex buffer */ - Vec3fa* vertices = (Vec3fa*) rtcMapBuffer(scene_out,geomID,RTC_VERTEX_BUFFER); - for (size_t i=0;inumVertices;i++) vertices[i] = mesh->positions[i]; - rtcUnmapBuffer(scene_out, geomID, RTC_VERTEX_BUFFER); - /* set index buffer */ - rtcSetBuffer(scene_out, geomID, RTC_INDEX_BUFFER, mesh->quads, 0, sizeof(ISPCQuad)); - mesh->geomID = geomID; - return geomID; - } - - unsigned int convertSubdivMesh(ISPCSubdivMesh* mesh, RTCScene scene_out) - { - /* if more than a single timestep, mark object as dynamic */ - RTCGeometryFlags object_flags = mesh->numTimeSteps > 1 ? RTC_GEOMETRY_DYNAMIC : RTC_GEOMETRY_STATIC; - /* create object */ - unsigned int geomID = rtcNewSubdivisionMesh(scene_out, object_flags, mesh->numFaces, mesh->numEdges, mesh->numVertices, - mesh->numEdgeCreases, mesh->numVertexCreases, mesh->numHoles, mesh->numTimeSteps); - mesh->geomID = geomID; - for (size_t i=0; inumEdges; i++) mesh->subdivlevel[i] = 4.0f; - /* generate vertex buffer */ - Vec3fa* vertices = (Vec3fa*) rtcMapBuffer(scene_out,geomID,RTC_VERTEX_BUFFER); - for (size_t i=0;inumVertices;i++) vertices[i] = mesh->positions[i]; - rtcUnmapBuffer(scene_out, geomID, RTC_VERTEX_BUFFER); - /* set all other buffers */ - rtcSetBuffer(scene_out, geomID, RTC_LEVEL_BUFFER, mesh->subdivlevel, 0, sizeof(float)); - rtcSetBuffer(scene_out, geomID, RTC_INDEX_BUFFER, mesh->position_indices , 0, sizeof(unsigned int)); - rtcSetBuffer(scene_out, geomID, RTC_FACE_BUFFER, mesh->verticesPerFace, 0, sizeof(unsigned int)); - rtcSetBuffer(scene_out, geomID, RTC_HOLE_BUFFER, mesh->holes, 0, sizeof(unsigned int)); - rtcSetBuffer(scene_out, geomID, RTC_EDGE_CREASE_INDEX_BUFFER, mesh->edge_creases, 0, 2*sizeof(unsigned int)); - rtcSetBuffer(scene_out, geomID, RTC_EDGE_CREASE_WEIGHT_BUFFER, mesh->edge_crease_weights, 0, sizeof(float)); - rtcSetBuffer(scene_out, geomID, RTC_VERTEX_CREASE_INDEX_BUFFER, mesh->vertex_creases, 0, sizeof(unsigned int)); - rtcSetBuffer(scene_out, geomID, RTC_VERTEX_CREASE_WEIGHT_BUFFER, mesh->vertex_crease_weights, 0, sizeof(float)); - rtcSetSubdivisionMode(scene_out, geomID, 0, mesh->position_subdiv_mode); - return geomID; - } - - unsigned int convertLineSegments(ISPCLineSegments* mesh, RTCScene scene_out) - { - /* if more than a single timestep, mark object as dynamic */ - RTCGeometryFlags object_flags = mesh->numTimeSteps > 1 ? RTC_GEOMETRY_DYNAMIC : RTC_GEOMETRY_STATIC; - /* create object */ - unsigned int geomID = rtcNewLineSegments (scene_out, object_flags, mesh->numSegments, mesh->numVertices, mesh->numTimeSteps); - /* generate vertex buffer */ - Vec3fa* vertices = (Vec3fa*) rtcMapBuffer(scene_out,geomID,RTC_VERTEX_BUFFER); - for (size_t i=0;inumVertices;i++) vertices[i] = mesh->positions[i]; - rtcUnmapBuffer(scene_out, geomID, RTC_VERTEX_BUFFER); - /* set index buffer */ - rtcSetBuffer(scene_out,geomID,RTC_INDEX_BUFFER,mesh->indices,0,sizeof(int)); - return geomID; - } - - unsigned int convertHairSet(ISPCHairSet* hair, RTCScene scene_out) - { - /* if more than a single timestep, mark object as dynamic */ - RTCGeometryFlags object_flags = hair->numTimeSteps > 1 ? RTC_GEOMETRY_DYNAMIC : RTC_GEOMETRY_STATIC; - /* create object */ - unsigned int geomID = rtcNewHairGeometry (scene_out, object_flags, hair->numHairs, hair->numVertices, hair->numTimeSteps); - /* generate vertex buffer */ - Vec3fa* vertices = (Vec3fa*) rtcMapBuffer(scene_out,geomID,RTC_VERTEX_BUFFER); - for (size_t i=0;inumVertices;i++) vertices[i] = hair->positions[i]; - rtcUnmapBuffer(scene_out, geomID, RTC_VERTEX_BUFFER); - /* set index buffer */ - rtcSetBuffer(scene_out,geomID,RTC_INDEX_BUFFER,hair->hairs,0,sizeof(ISPCHair)); - rtcSetTessellationRate(scene_out,geomID,(float)hair->tessellation_rate); - return geomID; - } - - unsigned int convertCurveGeometry(ISPCHairSet* hair, RTCScene scene_out) - { - /* if more than a single timestep, mark object as dynamic */ - RTCGeometryFlags object_flags = hair->numTimeSteps > 1 ? RTC_GEOMETRY_DYNAMIC : RTC_GEOMETRY_STATIC; - /* create object */ - unsigned int geomID = rtcNewCurveGeometry (scene_out, object_flags, hair->numHairs, hair->numVertices, hair->numTimeSteps); - /* generate vertex buffer */ - Vec3fa* vertices = (Vec3fa*) rtcMapBuffer(scene_out,geomID,RTC_VERTEX_BUFFER); - for (size_t i=0;inumVertices;i++) vertices[i] = hair->positions[i]; - rtcUnmapBuffer(scene_out, geomID, RTC_VERTEX_BUFFER); - /* set index buffer */ - rtcSetBuffer(scene_out,geomID,RTC_INDEX_BUFFER,hair->hairs,0,sizeof(ISPCHair)); - return geomID; - } - - size_t getNumObjects(ISPCScene* scene_in) - { - return scene_in->numGeometries; - } - - RTCScene createScene(ISPCScene* scene_in) - { - int scene_flags = RTC_SCENE_INCOHERENT | RTC_SCENE_DYNAMIC; - int scene_aflags = RTC_INTERSECT1 | RTC_INTERSECT_STREAM | RTC_INTERPOLATE; - return rtcDeviceNewScene(g_device, (RTCSceneFlags)scene_flags,(RTCAlgorithmFlags) scene_aflags); - } - - - void createObject(const size_t i, ISPCScene* scene_in, RTCScene scene_out) - { - ISPCGeometry* geometry = scene_in->geometries[i]; - unsigned int geomID = 0; - - if (geometry->type == SUBDIV_MESH) { - geomID = convertSubdivMesh((ISPCSubdivMesh*) geometry, scene_out); - ((ISPCSubdivMesh*)geometry)->geomID = geomID; - assert(geomID == i); - } - else if (geometry->type == TRIANGLE_MESH) { - geomID = convertTriangleMesh((ISPCTriangleMesh*) geometry, scene_out); - ((ISPCTriangleMesh*)geometry)->geomID = geomID; - assert(geomID == i); - } - else if (geometry->type == QUAD_MESH) { - geomID = convertQuadMesh((ISPCQuadMesh*) geometry, scene_out); - ((ISPCQuadMesh*)geometry)->geomID = geomID; - assert(geomID == i); - } - else if (geometry->type == LINE_SEGMENTS) { - geomID = convertLineSegments((ISPCLineSegments*) geometry, scene_out); - ((ISPCLineSegments*)geometry)->geomID = geomID; - assert(geomID == i); - } - else if (geometry->type == HAIR_SET) { - geomID = convertHairSet((ISPCHairSet*) geometry, scene_out); - ((ISPCHairSet*)geometry)->geomID = geomID; - assert(geomID == i); - } - else if (geometry->type == CURVES) { - geomID = convertCurveGeometry((ISPCHairSet*) geometry, scene_out); - ((ISPCHairSet*)geometry)->geomID = geomID; - assert(geomID == i); - } - else - assert(false); - } - - void interpolateVertices(RTCScene scene_out, - const unsigned int geomID, - const size_t numVertices, - const Vec3fa* __restrict__ const input0, - const Vec3fa* __restrict__ const input1, - const float tt) - { - Vec3fa* __restrict__ vertices = (Vec3fa*) rtcMapBuffer(scene_out,geomID,RTC_VERTEX_BUFFER); - parallel_for(size_t(0),numVertices,[&](const range& range) { - for (size_t i=range.begin(); igeometries[ID]; - - if (geometry->type == SUBDIV_MESH) { - unsigned int geomID = ((ISPCSubdivMesh*)geometry)->geomID; - /* if static do nothing */ - if (((ISPCSubdivMesh*)geometry)->numTimeSteps <= 1) return; - rtcUpdate(scene_out,geomID); - } - else if (geometry->type == TRIANGLE_MESH) { - ISPCTriangleMesh* mesh = (ISPCTriangleMesh*)geometry; - /* if static do nothing */ - if (mesh->numTimeSteps <= 1) return; - /* interpolate two vertices from two timesteps */ - const size_t t0 = (keyFrameID+0) % mesh->numTimeSteps; - const size_t t1 = (keyFrameID+1) % mesh->numTimeSteps; - const Vec3fa* __restrict__ const input0 = mesh->positions+t0*mesh->numVertices; - const Vec3fa* __restrict__ const input1 = mesh->positions+t1*mesh->numVertices; - interpolateVertices(scene_out, mesh->geomID, mesh->numVertices, input0, input1, tt); - } - else if (geometry->type == QUAD_MESH) { - ISPCQuadMesh* mesh = (ISPCQuadMesh*)geometry; - /* if static do nothing */ - if (mesh->numTimeSteps <= 1) return; - /* interpolate two vertices from two timesteps */ - const size_t t0 = (keyFrameID+0) % mesh->numTimeSteps; - const size_t t1 = (keyFrameID+1) % mesh->numTimeSteps; - const Vec3fa* __restrict__ const input0 = mesh->positions+t0*mesh->numVertices; - const Vec3fa* __restrict__ const input1 = mesh->positions+t1*mesh->numVertices; - interpolateVertices(scene_out, mesh->geomID, mesh->numVertices, input0, input1, tt); - } - else if (geometry->type == LINE_SEGMENTS) { - unsigned int geomID = ((ISPCLineSegments*)geometry)->geomID; - /* if static do nothing */ - if (((ISPCLineSegments*)geometry)->numTimeSteps <= 1) return; - rtcUpdate(scene_out,geomID); - } - else if (geometry->type == HAIR_SET) { - unsigned int geomID = ((ISPCHairSet*)geometry)->geomID; - /* if static do nothing */ - if (((ISPCHairSet*)geometry)->numTimeSteps <= 1) return; - rtcUpdate(scene_out,geomID); - } - else if (geometry->type == CURVES) { - unsigned int geomID = ((ISPCHairSet*)geometry)->geomID; - /* if static do nothing */ - if (((ISPCHairSet*)geometry)->numTimeSteps <= 1) return; - rtcUpdate(scene_out,geomID); - } - else - assert(false); - } - -inline Vec3fa face_forward(const Vec3fa& dir, const Vec3fa& _Ng) { - const Vec3fa Ng = _Ng; - return dot(dir,Ng) < 0.0f ? Ng : neg(Ng); -} - - -/* renders a single screen tile */ - void renderTileStandard(int taskIndex, - int* pixels, - const unsigned int width, - const unsigned int height, - const float time, - const ISPCCamera& camera, - const int numTilesX, - const int numTilesY) - { - const unsigned int tileY = taskIndex / numTilesX; - const unsigned int tileX = taskIndex - tileY * numTilesX; - const unsigned int x0 = tileX * TILE_SIZE_X; - const unsigned int x1 = min(x0+TILE_SIZE_X,width); - const unsigned int y0 = tileY * TILE_SIZE_Y; - const unsigned int y1 = min(y0+TILE_SIZE_Y,height); - - RTCRay rays[TILE_SIZE_X*TILE_SIZE_Y]; - - /* generate stream of primary rays */ - int N = 0; - for (unsigned int y=y0; ygeometries[ray.geomID]; - if (likely(geometry->type == TRIANGLE_MESH)) - { -#if VERTEX_NORMALS == 1 - ISPCTriangleMesh* mesh = (ISPCTriangleMesh*) geometry; - if (likely(mesh->normals)) - { - ISPCTriangle* tri = &mesh->triangles[ray.primID]; - - const Vec3fa n0 = mesh->normals[tri->v0]; - const Vec3fa n1 = mesh->normals[tri->v1]; - const Vec3fa n2 = mesh->normals[tri->v2]; - Ng = (1.0f-ray.u-ray.v)*n0 + ray.u*n1 + ray.v*n2; - } -#endif - } - /* final color */ - color = Vec3fa(abs(dot(ray.dir,normalize(Ng)))); - } - } - - -#if SHADOWS == 1 - /* do some hard shadows to point lights */ - if (g_ispc_scene->numLights) - { - for (unsigned int i=0; inumLights; i++) - { - /* init shadow/occlusion rays */ - for (int n=0;n ×, double time) - { - if (times[frameID] > 0.0f) - times[frameID] = (times[frameID] + time) * 0.5f; - else - times[frameID] = time; - } - -/* called by the C++ code to render */ - extern "C" void device_render (int* pixels, - const unsigned int width, - const unsigned int height, - const float time, - const ISPCCamera& camera) - { - assert(frameID < renderTime.size()); - assert(frameID < vertexUpdateTime.size()); - assert(frameID < buildTime.size()); - - /* =================================== */ - /* samples LS positions as pointlights */ - /* =================================== */ - - if (g_ispc_scene->numLights) - { - if (ls_positions == nullptr) ls_positions = new Vec3fa[g_ispc_scene->numLights]; - DifferentialGeometry dg; - dg.geomID = 0; - dg.primID = 0; - dg.u = 0.0f; - dg.v = 0.0f; - dg.P = Vec3fa(0.0f,0.0f,0.0f); - dg.Ng = Vec3fa(0.0f,0.0f,0.0f); - dg.Ns = dg.Ng; - for (size_t i=0; inumLights; i++) - { - const Light* l = g_ispc_scene->lights[i]; - Light_SampleRes ls = l->sample(l,dg,Vec2f(0.0f,0.0f)); - ls_positions[i] = ls.dir * ls.dist; - } - } - - /* ============ */ - /* render image */ - /* ============ */ - - const double renderTime0 = getSeconds(); - const int numTilesX = (width +TILE_SIZE_X-1)/TILE_SIZE_X; - const int numTilesY = (height+TILE_SIZE_Y-1)/TILE_SIZE_Y; - - parallel_for(size_t(0),size_t(numTilesX*numTilesY),[&](const range& range) { - for (size_t i=range.begin(); i 0.0f) Ng = neg(Ng); - - Vec3fa col = Vec3fa(min(1.0f,0.3f+0.8f*abs(dot(Ng,normalize(ray.dir))))); - - /* calculate hit point */ - float intensity = 0; - Vec3fa hitPos = ray.org + ray.tfar * ray.dir; - - RandomSampler sampler; - RandomSampler_init(sampler,x,y,0); - - /* enable only valid rays */ - for (int i=0; i& range) { - for (size_t i=range.begin(); iintersectors.ptr; - if (accel->type == AccelData::TY_BVH4) - bvh4 = (BVH4*)accel; - - /* if there are also other geometry types, one has to iterate over the toplevel AccelN structure */ - else if (accel->type == AccelData::TY_ACCELN) - { - AccelN* accelN = (AccelN*)(accel); - for (size_t i=0; iaccels.size(); i++) { - if (accelN->accels[i]->intersectors.ptr->type == AccelData::TY_BVH4) { - bvh4 = (BVH4*)accelN->accels[i]->intersectors.ptr; - if (bvh4->primTy.name == "triangle4v") break; - bvh4 = nullptr; - } - } - } - if (bvh4 == nullptr) - throw std::runtime_error("cannot access BVH4 acceleration structure"); // will not happen if you use this Embree version - - /* now lets print the entire hierarchy */ - print_bvh4_triangle4v(bvh4->root,0); - } - - /* main function in embree namespace */ - int main(int argc, char** argv) - { - /* for best performance set FTZ and DAZ flags in MXCSR control and status register */ - _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); - _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); - - /* create new Embree device and force bvh4.triangle4v hierarchy for triangles */ - RTCDevice device = rtcNewDevice("tri_accel=bvh4.triangle4v"); - - /* set error handler */ - rtcDeviceSetErrorFunction(device,error_handler); - - /* create scene */ - RTCScene scene = rtcDeviceNewScene(device,RTC_SCENE_STATIC,RTC_INTERSECT1); - addCube(scene,Vec3fa(-1,0,0)); - addCube(scene,Vec3fa(1,0,0)); - addCube(scene,Vec3fa(0,0,-1)); - addCube(scene,Vec3fa(0,0,1)); - addHair(scene); - addGroundPlane(scene); - rtcCommit (scene); - - /* print triangle BVH */ - print_bvh(scene); - - /* cleanup */ - rtcDeleteScene (scene); - rtcDeleteDevice(device); - return 0; - } -} - -int main(int argc, char** argv) -{ - try { - return embree::main(argc, argv); - } - catch (const std::exception& e) { - std::cout << "Error: " << e.what() << std::endl; - return 1; - } - catch (...) { - std::cout << "Error: unknown exception caught." << std::endl; - return 1; - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/bvh_builder/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/bvh_builder/CMakeLists.txt deleted file mode 100644 index 73d2a98dec65..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/bvh_builder/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2015 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -SET(ENABLE_ISPC_SUPPORT OFF) - -IF (TASKING_INTERNAL) - ADD_DEFINITIONS(-DTASKING_TBB_INTERNAL) -ELSE() - ADD_DEFINITIONS(-DTASKING_TBB) # FIXME: should not be necessary - SET(ADDITIONAL_LIBRARIES ${TBB_LIBRARIES}) -ENDIF() - -INCLUDE(tutorial) -ADD_TUTORIAL(bvh_builder) diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/bvh_builder/bvh_builder.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/bvh_builder/bvh_builder.cpp deleted file mode 100644 index 736197c416be..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/bvh_builder/bvh_builder.cpp +++ /dev/null @@ -1,156 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial.h" -#include "../common/image/image.h" - -namespace embree -{ - /* name of the tutorial */ - const char* tutorialName = "bvh_builder"; - - /* configuration */ - static std::string g_rtcore = ""; - static size_t g_numThreads = 0; - - /* output settings */ - static size_t g_width = 512; - static size_t g_height = 512; - static bool g_fullscreen = false; - static FileName outFilename = ""; - - static void parseCommandLine(Ref cin, const FileName& path) - { - while (true) - { - std::string tag = cin->getString(); - if (tag == "") return; - - /* parse command line parameters from a file */ - if (tag == "-c") { - FileName file = path + cin->getFileName(); - parseCommandLine(new ParseStream(new LineCommentFilter(file, "#")), file.path()); - } - - /* parse camera parameters */ - else if (tag == "-vp") g_camera.from = cin->getVec3fa(); - else if (tag == "-vi") g_camera.to = cin->getVec3fa(); - else if (tag == "-vd") g_camera.to = g_camera.from + cin->getVec3fa(); - else if (tag == "-vu") g_camera.up = cin->getVec3fa(); - else if (tag == "-fov") g_camera.fov = cin->getFloat(); - - /* frame buffer size */ - else if (tag == "-size") { - g_width = cin->getInt(); - g_height = cin->getInt(); - } - - /* full screen mode */ - else if (tag == "-fullscreen") - g_fullscreen = true; - - /* output filename */ - else if (tag == "-o") - outFilename = cin->getFileName(); - - /* rtcore configuration */ - else if (tag == "-rtcore") - g_rtcore = cin->getString(); - - /* number of threads to use */ - else if (tag == "-threads") - g_numThreads = cin->getInt(); - - /* skip unknown command line parameter */ - else { - std::cerr << "unknown command line parameter: " << tag << " "; - while (cin->peek() != "" && cin->peek()[0] != '-') std::cerr << cin->getString() << " "; - std::cerr << std::endl; - } - } - } - - void renderToFile(const FileName& fileName) - { - resize(g_width,g_height); - AffineSpace3fa pixel2world = g_camera.pixel2world(g_width,g_height); - - render(0.0f, - pixel2world.l.vx, - pixel2world.l.vy, - pixel2world.l.vz, - pixel2world.p); - - void* ptr = map(); - Ref image = new Image4uc(g_width, g_height, (Col4uc*)ptr); - storeImage(image, fileName); - unmap(); - } - - /* main function in embree namespace */ - int main(int argc, char** argv) - { - /* for best performance set FTZ and DAZ flags in MXCSR control and status register */ - _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); - _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); - - /* set default camera */ - g_camera.from = Vec3fa(1.5f,1.5f,-1.5f); - g_camera.to = Vec3fa(0.0f,0.0f,0.0f); - - /* create stream for parsing */ - Ref stream = new ParseStream(new CommandLineStream(argc, argv)); - - /* parse command line */ - parseCommandLine(stream, FileName()); - if (g_numThreads) - g_rtcore += ",threads=" + std::to_string((long long)g_numThreads); - - /* initialize ray tracing core */ - init(g_rtcore.c_str()); - -#if 0 - /* render to disk */ - if (outFilename.str() != "") { - renderToFile(outFilename); - return 0; - } - - /* initialize GLUT */ - initWindowState(argc,argv,tutorialName, g_width, g_height, g_fullscreen); - - /* enter the GLUT run loop */ - enterWindowRunLoop(); -#endif - - return 0; - } -} - -int main(int argc, char** argv) -{ - try { - return embree::main(argc, argv); - } - catch (const std::exception& e) { - std::cout << "Error: " << e.what() << std::endl; - return 1; - } - catch (...) { - std::cout << "Error: unknown exception caught." << std::endl; - return 1; - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/bvh_builder/bvh_builder_device.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/bvh_builder/bvh_builder_device.cpp deleted file mode 100644 index 6e8794ca7c18..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/bvh_builder/bvh_builder_device.cpp +++ /dev/null @@ -1,317 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial_device.h" -#include "../../kernels/common/alloc.h" -#include "../../kernels/xeon/builders/bvh_builder_sah.h" -#include "../../kernels/xeon/builders/bvh_builder_morton.h" - -RTCDevice g_device = nullptr; -RTCScene g_scene = nullptr; - -/* render function to use */ -renderPixelFunc renderPixel; - -/* error reporting function */ -void error_handler(const RTCError code, const char* str) -{ - printf("Embree: "); - switch (code) { - case RTC_UNKNOWN_ERROR : printf("RTC_UNKNOWN_ERROR"); break; - case RTC_INVALID_ARGUMENT : printf("RTC_INVALID_ARGUMENT"); break; - case RTC_INVALID_OPERATION: printf("RTC_INVALID_OPERATION"); break; - case RTC_OUT_OF_MEMORY : printf("RTC_OUT_OF_MEMORY"); break; - case RTC_UNSUPPORTED_CPU : printf("RTC_UNSUPPORTED_CPU"); break; - case RTC_CANCELLED : printf("RTC_CANCELLED"); break; - default : printf("invalid error code"); break; - } - if (str) { - printf(" ("); - while (*str) putchar(*str++); - printf(")\n"); - } - exit(1); -} - -/* These function called by the builder to signal progress and to - * report memory consumption. */ -namespace embree -{ - void memoryMonitor(ssize_t bytes, bool post) - { - // throw an exception here when nprims>0 to cancel the build operation - } -} - -struct Node -{ - virtual float sah() = 0; -}; - -struct InnerNode : public Node -{ - BBox3fa bounds[2]; - Node* children[2]; - - InnerNode() { - bounds[0] = bounds[1] = empty; - children[0] = children[1] = nullptr; - } - - float sah() { - return 1.0f + (area(bounds[0])*children[0]->sah() + area(bounds[1])*children[1]->sah())/area(merge(bounds[0],bounds[1])); - } -}; - -struct LeafNode : public Node -{ - size_t id; - BBox3fa bounds; - - LeafNode (size_t id, const BBox3fa& bounds) - : id(id), bounds(bounds) {} - - float sah() { - return 1.0f; - } -}; - -void build_sah(avector& prims, isa::PrimInfo& pinfo) -{ - size_t N = pinfo.size(); - - /* fast allocator that supports thread local operation */ - FastAllocator allocator(nullptr); - - for (size_t i=0; i<2; i++) - { - std::cout << "iteration " << i << ": building BVH over " << N << " primitives, " << std::flush; - double t0 = getSeconds(); - - allocator.reset(); - - Node* root; - isa::BVHBuilderBinnedSAH::build( - root, - /* thread local allocator for fast allocations */ - [&] () -> FastAllocator::ThreadLocal* { - return allocator.threadLocal(); - }, - - /* lambda function that creates BVH nodes */ - [&](const isa::BVHBuilderBinnedSAH::BuildRecord& current, isa::BVHBuilderBinnedSAH::BuildRecord* children, const size_t N, FastAllocator::ThreadLocal* alloc) -> int - { - assert(N <= 2); - InnerNode* node = new (alloc->malloc(sizeof(InnerNode))) InnerNode; - for (size_t i=0; ibounds[i] = children[i].pinfo.geomBounds; - children[i].parent = (size_t*) &node->children[i]; - } - *current.parent = (size_t) node; - return 0; - }, - - /* lambda function that creates BVH leaves */ - [&](const isa::BVHBuilderBinnedSAH::BuildRecord& current, FastAllocator::ThreadLocal* alloc) -> int - { - assert(current.prims.size() == 1); - Node* node = new (alloc->malloc(sizeof(LeafNode))) LeafNode(prims[current.prims.begin()].ID(),prims[current.prims.begin()].bounds()); - *current.parent = (size_t) node; - return 0; - }, - - /* progress monitor function */ - [&] (size_t dn) { - // throw an exception here to cancel the build operation - }, - - prims.data(),pinfo,2,1024,1,1,1,1.0f,1.0f); - - double t1 = getSeconds(); - - std::cout << 1000.0f*(t1-t0) << "ms, " << 1E-6*double(N)/(t1-t0) << " Mprims/s, sah = " << root->sah() << " [DONE]" << std::endl; - } -} - -void build_morton(avector& prims, isa::PrimInfo& pinfo) -{ - size_t N = pinfo.size(); - /* array for morton builder */ - avector morton_src(N); - avector morton_tmp(N); - for (size_t i=0; i node_bounds = isa::bvh_builder_morton( - - /* thread local allocator for fast allocations */ - [&] () -> FastAllocator::ThreadLocal* { - return allocator.threadLocal(); - }, - - BBox3fa(empty), - - /* lambda function that allocates BVH nodes */ - [&] ( isa::MortonBuildRecord& current, isa::MortonBuildRecord* children, size_t N, FastAllocator::ThreadLocal* alloc ) -> InnerNode* - { - assert(N <= 2); - InnerNode* node = new (alloc->malloc(sizeof(InnerNode))) InnerNode; - *current.parent = node; - for (size_t i=0; ichildren[i]; - return node; - }, - - /* lambda function that sets bounds */ - [&] (InnerNode* node, const BBox3fa* bounds, size_t N) -> BBox3fa - { - BBox3fa res = empty; - for (size_t i=0; ibounds[i] = b; - } - return res; - }, - - /* lambda function that creates BVH leaves */ - [&]( isa::MortonBuildRecord& current, FastAllocator::ThreadLocal* alloc, BBox3fa& box_o) -> Node* - { - assert(current.size() == 1); - const size_t id = morton_src[current.begin].index; // FIXME: dont use morton_src, should be input - const BBox3fa bounds = prims[id].bounds(); - Node* node = new (alloc->malloc(sizeof(LeafNode))) LeafNode(id,bounds); - *current.parent = node; - box_o = bounds; - return node; - }, - - /* lambda that calculates the bounds for some primitive */ - [&] (const isa::MortonID32Bit& morton) -> BBox3fa { - return prims[morton.index].bounds(); - }, - - /* progress monitor function */ - [&] (size_t dn) { - // throw an exception here to cancel the build operation - }, - - morton_src.data(),morton_tmp.data(),prims.size(),2,1024,1,1); - - Node* root = node_bounds.first; - - double t1 = getSeconds(); - - std::cout << 1000.0f*(t1-t0) << "ms, " << 1E-6*double(N)/(t1-t0) << " Mprims/s, sah = " << root->sah() << " [DONE]" << std::endl; - } -} - -/* called by the C++ code for initialization */ -extern "C" void device_init (char* cfg) -{ - /* create new Embree device */ - g_device = rtcNewDevice(cfg); - - /* set error handler */ - rtcDeviceSetErrorFunction(g_device,error_handler); - - /* set start render mode */ - renderPixel = renderPixelStandard; - - /* create random bounding boxes */ - const size_t N = 2300000; - isa::PrimInfo pinfo(empty); - avector prims; - for (size_t i=0; i - * Creation date: Thu Dec 2 1999 - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifdef __cplusplus - extern "C" { -#endif - -/* - * Additional GLUT Key definitions for the Special key function - */ -#define GLUT_KEY_NUM_LOCK 0x006D -#define GLUT_KEY_BEGIN 0x006E -#define GLUT_KEY_DELETE 0x006F -#define GLUT_KEY_SHIFT_L 0x0070 -#define GLUT_KEY_SHIFT_R 0x0071 -#define GLUT_KEY_CTRL_L 0x0072 -#define GLUT_KEY_CTRL_R 0x0073 -#define GLUT_KEY_ALT_L 0x0074 -#define GLUT_KEY_ALT_R 0x0075 - -/* - * GLUT API Extension macro definitions -- behaviour when the user clicks on an "x" to close a window - */ -#define GLUT_ACTION_EXIT 0 -#define GLUT_ACTION_GLUTMAINLOOP_RETURNS 1 -#define GLUT_ACTION_CONTINUE_EXECUTION 2 - -/* - * Create a new rendering context when the user opens a new window? - */ -#define GLUT_CREATE_NEW_CONTEXT 0 -#define GLUT_USE_CURRENT_CONTEXT 1 - -/* - * Direct/Indirect rendering context options (has meaning only in Unix/X11) - */ -#define GLUT_FORCE_INDIRECT_CONTEXT 0 -#define GLUT_ALLOW_DIRECT_CONTEXT 1 -#define GLUT_TRY_DIRECT_CONTEXT 2 -#define GLUT_FORCE_DIRECT_CONTEXT 3 - -/* - * GLUT API Extension macro definitions -- the glutGet parameters - */ -#define GLUT_INIT_STATE 0x007C - -#define GLUT_ACTION_ON_WINDOW_CLOSE 0x01F9 - -#define GLUT_WINDOW_BORDER_WIDTH 0x01FA -#define GLUT_WINDOW_BORDER_HEIGHT 0x01FB -#define GLUT_WINDOW_HEADER_HEIGHT 0x01FB /* Docs say it should always have been GLUT_WINDOW_BORDER_HEIGHT, keep this for backward compatibility */ - -#define GLUT_VERSION 0x01FC - -#define GLUT_RENDERING_CONTEXT 0x01FD -#define GLUT_DIRECT_RENDERING 0x01FE - -#define GLUT_FULL_SCREEN 0x01FF - -#define GLUT_SKIP_STALE_MOTION_EVENTS 0x0204 - -/* - * New tokens for glutInitDisplayMode. - * Only one GLUT_AUXn bit may be used at a time. - * Value 0x0400 is defined in OpenGLUT. - */ -#define GLUT_AUX 0x1000 - -#define GLUT_AUX1 0x1000 -#define GLUT_AUX2 0x2000 -#define GLUT_AUX3 0x4000 -#define GLUT_AUX4 0x8000 - -/* - * Context-related flags, see freeglut_state.c - */ -#define GLUT_INIT_MAJOR_VERSION 0x0200 -#define GLUT_INIT_MINOR_VERSION 0x0201 -#define GLUT_INIT_FLAGS 0x0202 -#define GLUT_INIT_PROFILE 0x0203 - -/* - * Flags for glutInitContextFlags, see freeglut_init.c - */ -#define GLUT_DEBUG 0x0001 -#define GLUT_FORWARD_COMPATIBLE 0x0002 - - -/* - * Flags for glutInitContextProfile, see freeglut_init.c - */ -#define GLUT_CORE_PROFILE 0x0001 -#define GLUT_COMPATIBILITY_PROFILE 0x0002 - -/* - * Process loop function, see freeglut_main.c - */ -FGAPI void FGAPIENTRY glutMainLoopEvent( void ); -FGAPI void FGAPIENTRY glutLeaveMainLoop( void ); -FGAPI void FGAPIENTRY glutExit ( void ); - -/* - * Window management functions, see freeglut_window.c - */ -FGAPI void FGAPIENTRY glutFullScreenToggle( void ); -FGAPI void FGAPIENTRY glutLeaveFullScreen( void ); - -/* - * Window-specific callback functions, see freeglut_callbacks.c - */ -FGAPI void FGAPIENTRY glutMouseWheelFunc( void (* callback)( int, int, int, int ) ); -FGAPI void FGAPIENTRY glutCloseFunc( void (* callback)( void ) ); -FGAPI void FGAPIENTRY glutWMCloseFunc( void (* callback)( void ) ); -/* A. Donev: Also a destruction callback for menus */ -FGAPI void FGAPIENTRY glutMenuDestroyFunc( void (* callback)( void ) ); - -/* - * State setting and retrieval functions, see freeglut_state.c - */ -FGAPI void FGAPIENTRY glutSetOption ( GLenum option_flag, int value ); -FGAPI int * FGAPIENTRY glutGetModeValues(GLenum mode, int * size); -/* A.Donev: User-data manipulation */ -FGAPI void* FGAPIENTRY glutGetWindowData( void ); -FGAPI void FGAPIENTRY glutSetWindowData(void* data); -FGAPI void* FGAPIENTRY glutGetMenuData( void ); -FGAPI void FGAPIENTRY glutSetMenuData(void* data); - -/* - * Font stuff, see freeglut_font.c - */ -FGAPI int FGAPIENTRY glutBitmapHeight( void* font ); -FGAPI GLfloat FGAPIENTRY glutStrokeHeight( void* font ); -FGAPI void FGAPIENTRY glutBitmapString( void* font, const unsigned char *string ); -FGAPI void FGAPIENTRY glutStrokeString( void* font, const unsigned char *string ); - -/* - * Geometry functions, see freeglut_geometry.c - */ -FGAPI void FGAPIENTRY glutWireRhombicDodecahedron( void ); -FGAPI void FGAPIENTRY glutSolidRhombicDodecahedron( void ); -FGAPI void FGAPIENTRY glutWireSierpinskiSponge ( int num_levels, GLdouble offset[3], GLdouble scale ); -FGAPI void FGAPIENTRY glutSolidSierpinskiSponge ( int num_levels, GLdouble offset[3], GLdouble scale ); -FGAPI void FGAPIENTRY glutWireCylinder( GLdouble radius, GLdouble height, GLint slices, GLint stacks); -FGAPI void FGAPIENTRY glutSolidCylinder( GLdouble radius, GLdouble height, GLint slices, GLint stacks); - -/* - * Extension functions, see freeglut_ext.c - */ -typedef void (*GLUTproc)(); -FGAPI GLUTproc FGAPIENTRY glutGetProcAddress( const char *procName ); - -/* - * Multi-touch/multi-pointer extensions - */ - -#define GLUT_HAS_MULTI 1 - -FGAPI void FGAPIENTRY glutMultiEntryFunc( void (* callback)( int, int ) ); -FGAPI void FGAPIENTRY glutMultiButtonFunc( void (* callback)( int, int, int, int, int ) ); -FGAPI void FGAPIENTRY glutMultiMotionFunc( void (* callback)( int, int, int ) ); -FGAPI void FGAPIENTRY glutMultiPassiveFunc( void (* callback)( int, int, int ) ); - -/* - * Joystick functions, see freeglut_joystick.c - */ -/* USE OF THESE FUNCTIONS IS DEPRECATED !!!!! */ -/* If you have a serious need for these functions in your application, please either - * contact the "freeglut" developer community at freeglut-developer@lists.sourceforge.net, - * switch to the OpenGLUT library, or else port your joystick functionality over to PLIB's - * "js" library. - */ -int glutJoystickGetNumAxes( int ident ); -int glutJoystickGetNumButtons( int ident ); -int glutJoystickNotWorking( int ident ); -float glutJoystickGetDeadBand( int ident, int axis ); -void glutJoystickSetDeadBand( int ident, int axis, float db ); -float glutJoystickGetSaturation( int ident, int axis ); -void glutJoystickSetSaturation( int ident, int axis, float st ); -void glutJoystickSetMinRange( int ident, float *axes ); -void glutJoystickSetMaxRange( int ident, float *axes ); -void glutJoystickSetCenter( int ident, float *axes ); -void glutJoystickGetMinRange( int ident, float *axes ); -void glutJoystickGetMaxRange( int ident, float *axes ); -void glutJoystickGetCenter( int ident, float *axes ); - -/* - * Initialization functions, see freeglut_init.c - */ -FGAPI void FGAPIENTRY glutInitContextVersion( int majorVersion, int minorVersion ); -FGAPI void FGAPIENTRY glutInitContextFlags( int flags ); -FGAPI void FGAPIENTRY glutInitContextProfile( int profile ); - -/* to get the typedef for va_list */ -#include - -FGAPI void FGAPIENTRY glutInitErrorFunc( void (* vError)( const char *fmt, va_list ap ) ); -FGAPI void FGAPIENTRY glutInitWarningFunc( void (* vWarning)( const char *fmt, va_list ap ) ); - -/* - * GLUT API macro definitions -- the display mode definitions - */ -#define GLUT_CAPTIONLESS 0x0400 -#define GLUT_BORDERLESS 0x0800 -#define GLUT_SRGB 0x1000 - -#ifdef __cplusplus - } -#endif - -/*** END OF FILE ***/ - -#endif /* __FREEGLUT_EXT_H__ */ diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/freeglut/include/GL/freeglut_std.h b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/freeglut/include/GL/freeglut_std.h deleted file mode 100644 index 2e41efd7c5e5..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/freeglut/include/GL/freeglut_std.h +++ /dev/null @@ -1,630 +0,0 @@ -#ifndef __FREEGLUT_STD_H__ -#define __FREEGLUT_STD_H__ - -/* - * freeglut_std.h - * - * The GLUT-compatible part of the freeglut library include file - * - * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. - * Written by Pawel W. Olszta, - * Creation date: Thu Dec 2 1999 - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifdef __cplusplus - extern "C" { -#endif - -/* - * Under windows, we have to differentiate between static and dynamic libraries - */ -#ifdef _WIN32 -/* #pragma may not be supported by some compilers. - * Discussion by FreeGLUT developers suggests that - * Visual C++ specific code involving pragmas may - * need to move to a separate header. 24th Dec 2003 - */ - -/* Define FREEGLUT_LIB_PRAGMAS to 1 to include library - * pragmas or to 0 to exclude library pragmas. - * The default behavior depends on the compiler/platform. - */ -# ifndef FREEGLUT_LIB_PRAGMAS -# if ( defined(_MSC_VER) || defined(__WATCOMC__) ) && !defined(_WIN32_WCE) -# define FREEGLUT_LIB_PRAGMAS 1 -# else -# define FREEGLUT_LIB_PRAGMAS 0 -# endif -# endif - -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN 1 -# endif -# ifndef NOMINMAX -# define NOMINMAX -# endif -# include - -/* Windows static library */ -# ifdef FREEGLUT_STATIC - -#error Static linking is not supported with this build. Please remove the FREEGLUT_STATIC preprocessor directive, or download the source code from http://freeglut.sf.net/ and build against that. - -/* Windows shared library (DLL) */ -# else - -# define FGAPIENTRY __stdcall -# if defined(FREEGLUT_EXPORTS) -# define FGAPI __declspec(dllexport) -# else -# define FGAPI __declspec(dllimport) - - /* Link with Win32 shared freeglut lib */ -# if FREEGLUT_LIB_PRAGMAS -# pragma comment (lib, "freeglut.lib") -# endif - -# endif - -# endif - -/* Drag in other Windows libraries as required by FreeGLUT */ -# if FREEGLUT_LIB_PRAGMAS -# pragma comment (lib, "glu32.lib") /* link OpenGL Utility lib */ -# pragma comment (lib, "opengl32.lib") /* link Microsoft OpenGL lib */ -# pragma comment (lib, "gdi32.lib") /* link Windows GDI lib */ -# pragma comment (lib, "winmm.lib") /* link Windows MultiMedia lib */ -# pragma comment (lib, "user32.lib") /* link Windows user lib */ -# endif - -#else - -/* Non-Windows definition of FGAPI and FGAPIENTRY */ -# define FGAPI -# define FGAPIENTRY - -#endif - -/* - * The freeglut and GLUT API versions - */ -#define FREEGLUT 1 -#define GLUT_API_VERSION 4 -#define GLUT_XLIB_IMPLEMENTATION 13 -/* Deprecated: - cf. http://sourceforge.net/mailarchive/forum.php?thread_name=CABcAi1hw7cr4xtigckaGXB5X8wddLfMcbA_rZ3NAuwMrX_zmsw%40mail.gmail.com&forum_name=freeglut-developer */ -#define FREEGLUT_VERSION_2_0 1 - -/* - * Always include OpenGL and GLU headers - */ -#if __APPLE__ -# include -# include -#else -# include -# include -#endif - -/* - * GLUT API macro definitions -- the special key codes: - */ -#define GLUT_KEY_F1 0x0001 -#define GLUT_KEY_F2 0x0002 -#define GLUT_KEY_F3 0x0003 -#define GLUT_KEY_F4 0x0004 -#define GLUT_KEY_F5 0x0005 -#define GLUT_KEY_F6 0x0006 -#define GLUT_KEY_F7 0x0007 -#define GLUT_KEY_F8 0x0008 -#define GLUT_KEY_F9 0x0009 -#define GLUT_KEY_F10 0x000A -#define GLUT_KEY_F11 0x000B -#define GLUT_KEY_F12 0x000C -#define GLUT_KEY_LEFT 0x0064 -#define GLUT_KEY_UP 0x0065 -#define GLUT_KEY_RIGHT 0x0066 -#define GLUT_KEY_DOWN 0x0067 -#define GLUT_KEY_PAGE_UP 0x0068 -#define GLUT_KEY_PAGE_DOWN 0x0069 -#define GLUT_KEY_HOME 0x006A -#define GLUT_KEY_END 0x006B -#define GLUT_KEY_INSERT 0x006C - -/* - * GLUT API macro definitions -- mouse state definitions - */ -#define GLUT_LEFT_BUTTON 0x0000 -#define GLUT_MIDDLE_BUTTON 0x0001 -#define GLUT_RIGHT_BUTTON 0x0002 -#define GLUT_DOWN 0x0000 -#define GLUT_UP 0x0001 -#define GLUT_LEFT 0x0000 -#define GLUT_ENTERED 0x0001 - -/* - * GLUT API macro definitions -- the display mode definitions - */ -#define GLUT_RGB 0x0000 -#define GLUT_RGBA 0x0000 -#define GLUT_INDEX 0x0001 -#define GLUT_SINGLE 0x0000 -#define GLUT_DOUBLE 0x0002 -#define GLUT_ACCUM 0x0004 -#define GLUT_ALPHA 0x0008 -#define GLUT_DEPTH 0x0010 -#define GLUT_STENCIL 0x0020 -#define GLUT_MULTISAMPLE 0x0080 -#define GLUT_STEREO 0x0100 -#define GLUT_LUMINANCE 0x0200 - -/* - * GLUT API macro definitions -- windows and menu related definitions - */ -#define GLUT_MENU_NOT_IN_USE 0x0000 -#define GLUT_MENU_IN_USE 0x0001 -#define GLUT_NOT_VISIBLE 0x0000 -#define GLUT_VISIBLE 0x0001 -#define GLUT_HIDDEN 0x0000 -#define GLUT_FULLY_RETAINED 0x0001 -#define GLUT_PARTIALLY_RETAINED 0x0002 -#define GLUT_FULLY_COVERED 0x0003 - -/* - * GLUT API macro definitions -- fonts definitions - * - * Steve Baker suggested to make it binary compatible with GLUT: - */ -#if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__WATCOMC__) -# define GLUT_STROKE_ROMAN ((void *)0x0000) -# define GLUT_STROKE_MONO_ROMAN ((void *)0x0001) -# define GLUT_BITMAP_9_BY_15 ((void *)0x0002) -# define GLUT_BITMAP_8_BY_13 ((void *)0x0003) -# define GLUT_BITMAP_TIMES_ROMAN_10 ((void *)0x0004) -# define GLUT_BITMAP_TIMES_ROMAN_24 ((void *)0x0005) -# define GLUT_BITMAP_HELVETICA_10 ((void *)0x0006) -# define GLUT_BITMAP_HELVETICA_12 ((void *)0x0007) -# define GLUT_BITMAP_HELVETICA_18 ((void *)0x0008) -#else - /* - * I don't really know if it's a good idea... But here it goes: - */ - extern void* glutStrokeRoman; - extern void* glutStrokeMonoRoman; - extern void* glutBitmap9By15; - extern void* glutBitmap8By13; - extern void* glutBitmapTimesRoman10; - extern void* glutBitmapTimesRoman24; - extern void* glutBitmapHelvetica10; - extern void* glutBitmapHelvetica12; - extern void* glutBitmapHelvetica18; - - /* - * Those pointers will be used by following definitions: - */ -# define GLUT_STROKE_ROMAN ((void *) &glutStrokeRoman) -# define GLUT_STROKE_MONO_ROMAN ((void *) &glutStrokeMonoRoman) -# define GLUT_BITMAP_9_BY_15 ((void *) &glutBitmap9By15) -# define GLUT_BITMAP_8_BY_13 ((void *) &glutBitmap8By13) -# define GLUT_BITMAP_TIMES_ROMAN_10 ((void *) &glutBitmapTimesRoman10) -# define GLUT_BITMAP_TIMES_ROMAN_24 ((void *) &glutBitmapTimesRoman24) -# define GLUT_BITMAP_HELVETICA_10 ((void *) &glutBitmapHelvetica10) -# define GLUT_BITMAP_HELVETICA_12 ((void *) &glutBitmapHelvetica12) -# define GLUT_BITMAP_HELVETICA_18 ((void *) &glutBitmapHelvetica18) -#endif - -/* - * GLUT API macro definitions -- the glutGet parameters - */ -#define GLUT_WINDOW_X 0x0064 -#define GLUT_WINDOW_Y 0x0065 -#define GLUT_WINDOW_WIDTH 0x0066 -#define GLUT_WINDOW_HEIGHT 0x0067 -#define GLUT_WINDOW_BUFFER_SIZE 0x0068 -#define GLUT_WINDOW_STENCIL_SIZE 0x0069 -#define GLUT_WINDOW_DEPTH_SIZE 0x006A -#define GLUT_WINDOW_RED_SIZE 0x006B -#define GLUT_WINDOW_GREEN_SIZE 0x006C -#define GLUT_WINDOW_BLUE_SIZE 0x006D -#define GLUT_WINDOW_ALPHA_SIZE 0x006E -#define GLUT_WINDOW_ACCUM_RED_SIZE 0x006F -#define GLUT_WINDOW_ACCUM_GREEN_SIZE 0x0070 -#define GLUT_WINDOW_ACCUM_BLUE_SIZE 0x0071 -#define GLUT_WINDOW_ACCUM_ALPHA_SIZE 0x0072 -#define GLUT_WINDOW_DOUBLEBUFFER 0x0073 -#define GLUT_WINDOW_RGBA 0x0074 -#define GLUT_WINDOW_PARENT 0x0075 -#define GLUT_WINDOW_NUM_CHILDREN 0x0076 -#define GLUT_WINDOW_COLORMAP_SIZE 0x0077 -#define GLUT_WINDOW_NUM_SAMPLES 0x0078 -#define GLUT_WINDOW_STEREO 0x0079 -#define GLUT_WINDOW_CURSOR 0x007A - -#define GLUT_SCREEN_WIDTH 0x00C8 -#define GLUT_SCREEN_HEIGHT 0x00C9 -#define GLUT_SCREEN_WIDTH_MM 0x00CA -#define GLUT_SCREEN_HEIGHT_MM 0x00CB -#define GLUT_MENU_NUM_ITEMS 0x012C -#define GLUT_DISPLAY_MODE_POSSIBLE 0x0190 -#define GLUT_INIT_WINDOW_X 0x01F4 -#define GLUT_INIT_WINDOW_Y 0x01F5 -#define GLUT_INIT_WINDOW_WIDTH 0x01F6 -#define GLUT_INIT_WINDOW_HEIGHT 0x01F7 -#define GLUT_INIT_DISPLAY_MODE 0x01F8 -#define GLUT_ELAPSED_TIME 0x02BC -#define GLUT_WINDOW_FORMAT_ID 0x007B - -/* - * GLUT API macro definitions -- the glutDeviceGet parameters - */ -#define GLUT_HAS_KEYBOARD 0x0258 -#define GLUT_HAS_MOUSE 0x0259 -#define GLUT_HAS_SPACEBALL 0x025A -#define GLUT_HAS_DIAL_AND_BUTTON_BOX 0x025B -#define GLUT_HAS_TABLET 0x025C -#define GLUT_NUM_MOUSE_BUTTONS 0x025D -#define GLUT_NUM_SPACEBALL_BUTTONS 0x025E -#define GLUT_NUM_BUTTON_BOX_BUTTONS 0x025F -#define GLUT_NUM_DIALS 0x0260 -#define GLUT_NUM_TABLET_BUTTONS 0x0261 -#define GLUT_DEVICE_IGNORE_KEY_REPEAT 0x0262 -#define GLUT_DEVICE_KEY_REPEAT 0x0263 -#define GLUT_HAS_JOYSTICK 0x0264 -#define GLUT_OWNS_JOYSTICK 0x0265 -#define GLUT_JOYSTICK_BUTTONS 0x0266 -#define GLUT_JOYSTICK_AXES 0x0267 -#define GLUT_JOYSTICK_POLL_RATE 0x0268 - -/* - * GLUT API macro definitions -- the glutLayerGet parameters - */ -#define GLUT_OVERLAY_POSSIBLE 0x0320 -#define GLUT_LAYER_IN_USE 0x0321 -#define GLUT_HAS_OVERLAY 0x0322 -#define GLUT_TRANSPARENT_INDEX 0x0323 -#define GLUT_NORMAL_DAMAGED 0x0324 -#define GLUT_OVERLAY_DAMAGED 0x0325 - -/* - * GLUT API macro definitions -- the glutVideoResizeGet parameters - */ -#define GLUT_VIDEO_RESIZE_POSSIBLE 0x0384 -#define GLUT_VIDEO_RESIZE_IN_USE 0x0385 -#define GLUT_VIDEO_RESIZE_X_DELTA 0x0386 -#define GLUT_VIDEO_RESIZE_Y_DELTA 0x0387 -#define GLUT_VIDEO_RESIZE_WIDTH_DELTA 0x0388 -#define GLUT_VIDEO_RESIZE_HEIGHT_DELTA 0x0389 -#define GLUT_VIDEO_RESIZE_X 0x038A -#define GLUT_VIDEO_RESIZE_Y 0x038B -#define GLUT_VIDEO_RESIZE_WIDTH 0x038C -#define GLUT_VIDEO_RESIZE_HEIGHT 0x038D - -/* - * GLUT API macro definitions -- the glutUseLayer parameters - */ -#define GLUT_NORMAL 0x0000 -#define GLUT_OVERLAY 0x0001 - -/* - * GLUT API macro definitions -- the glutGetModifiers parameters - */ -#define GLUT_ACTIVE_SHIFT 0x0001 -#define GLUT_ACTIVE_CTRL 0x0002 -#define GLUT_ACTIVE_ALT 0x0004 - -/* - * GLUT API macro definitions -- the glutSetCursor parameters - */ -#define GLUT_CURSOR_RIGHT_ARROW 0x0000 -#define GLUT_CURSOR_LEFT_ARROW 0x0001 -#define GLUT_CURSOR_INFO 0x0002 -#define GLUT_CURSOR_DESTROY 0x0003 -#define GLUT_CURSOR_HELP 0x0004 -#define GLUT_CURSOR_CYCLE 0x0005 -#define GLUT_CURSOR_SPRAY 0x0006 -#define GLUT_CURSOR_WAIT 0x0007 -#define GLUT_CURSOR_TEXT 0x0008 -#define GLUT_CURSOR_CROSSHAIR 0x0009 -#define GLUT_CURSOR_UP_DOWN 0x000A -#define GLUT_CURSOR_LEFT_RIGHT 0x000B -#define GLUT_CURSOR_TOP_SIDE 0x000C -#define GLUT_CURSOR_BOTTOM_SIDE 0x000D -#define GLUT_CURSOR_LEFT_SIDE 0x000E -#define GLUT_CURSOR_RIGHT_SIDE 0x000F -#define GLUT_CURSOR_TOP_LEFT_CORNER 0x0010 -#define GLUT_CURSOR_TOP_RIGHT_CORNER 0x0011 -#define GLUT_CURSOR_BOTTOM_RIGHT_CORNER 0x0012 -#define GLUT_CURSOR_BOTTOM_LEFT_CORNER 0x0013 -#define GLUT_CURSOR_INHERIT 0x0064 -#define GLUT_CURSOR_NONE 0x0065 -#define GLUT_CURSOR_FULL_CROSSHAIR 0x0066 - -/* - * GLUT API macro definitions -- RGB color component specification definitions - */ -#define GLUT_RED 0x0000 -#define GLUT_GREEN 0x0001 -#define GLUT_BLUE 0x0002 - -/* - * GLUT API macro definitions -- additional keyboard and joystick definitions - */ -#define GLUT_KEY_REPEAT_OFF 0x0000 -#define GLUT_KEY_REPEAT_ON 0x0001 -#define GLUT_KEY_REPEAT_DEFAULT 0x0002 - -#define GLUT_JOYSTICK_BUTTON_A 0x0001 -#define GLUT_JOYSTICK_BUTTON_B 0x0002 -#define GLUT_JOYSTICK_BUTTON_C 0x0004 -#define GLUT_JOYSTICK_BUTTON_D 0x0008 - -/* - * GLUT API macro definitions -- game mode definitions - */ -#define GLUT_GAME_MODE_ACTIVE 0x0000 -#define GLUT_GAME_MODE_POSSIBLE 0x0001 -#define GLUT_GAME_MODE_WIDTH 0x0002 -#define GLUT_GAME_MODE_HEIGHT 0x0003 -#define GLUT_GAME_MODE_PIXEL_DEPTH 0x0004 -#define GLUT_GAME_MODE_REFRESH_RATE 0x0005 -#define GLUT_GAME_MODE_DISPLAY_CHANGED 0x0006 - -/* - * Initialization functions, see fglut_init.c - */ -FGAPI void FGAPIENTRY glutInit( int* pargc, char** argv ); -FGAPI void FGAPIENTRY glutInitWindowPosition( int x, int y ); -FGAPI void FGAPIENTRY glutInitWindowSize( int width, int height ); -FGAPI void FGAPIENTRY glutInitDisplayMode( unsigned int displayMode ); -FGAPI void FGAPIENTRY glutInitDisplayString( const char* displayMode ); - -/* - * Process loop function, see freeglut_main.c - */ -FGAPI void FGAPIENTRY glutMainLoop( void ); - -/* - * Window management functions, see freeglut_window.c - */ -FGAPI int FGAPIENTRY glutCreateWindow( const char* title ); -FGAPI int FGAPIENTRY glutCreateSubWindow( int window, int x, int y, int width, int height ); -FGAPI void FGAPIENTRY glutDestroyWindow( int window ); -FGAPI void FGAPIENTRY glutSetWindow( int window ); -FGAPI int FGAPIENTRY glutGetWindow( void ); -FGAPI void FGAPIENTRY glutSetWindowTitle( const char* title ); -FGAPI void FGAPIENTRY glutSetIconTitle( const char* title ); -FGAPI void FGAPIENTRY glutReshapeWindow( int width, int height ); -FGAPI void FGAPIENTRY glutPositionWindow( int x, int y ); -FGAPI void FGAPIENTRY glutShowWindow( void ); -FGAPI void FGAPIENTRY glutHideWindow( void ); -FGAPI void FGAPIENTRY glutIconifyWindow( void ); -FGAPI void FGAPIENTRY glutPushWindow( void ); -FGAPI void FGAPIENTRY glutPopWindow( void ); -FGAPI void FGAPIENTRY glutFullScreen( void ); - -/* - * Display-connected functions, see freeglut_display.c - */ -FGAPI void FGAPIENTRY glutPostWindowRedisplay( int window ); -FGAPI void FGAPIENTRY glutPostRedisplay( void ); -FGAPI void FGAPIENTRY glutSwapBuffers( void ); - -/* - * Mouse cursor functions, see freeglut_cursor.c - */ -FGAPI void FGAPIENTRY glutWarpPointer( int x, int y ); -FGAPI void FGAPIENTRY glutSetCursor( int cursor ); - -/* - * Overlay stuff, see freeglut_overlay.c - */ -FGAPI void FGAPIENTRY glutEstablishOverlay( void ); -FGAPI void FGAPIENTRY glutRemoveOverlay( void ); -FGAPI void FGAPIENTRY glutUseLayer( GLenum layer ); -FGAPI void FGAPIENTRY glutPostOverlayRedisplay( void ); -FGAPI void FGAPIENTRY glutPostWindowOverlayRedisplay( int window ); -FGAPI void FGAPIENTRY glutShowOverlay( void ); -FGAPI void FGAPIENTRY glutHideOverlay( void ); - -/* - * Menu stuff, see freeglut_menu.c - */ -FGAPI int FGAPIENTRY glutCreateMenu( void (* callback)( int menu ) ); -FGAPI void FGAPIENTRY glutDestroyMenu( int menu ); -FGAPI int FGAPIENTRY glutGetMenu( void ); -FGAPI void FGAPIENTRY glutSetMenu( int menu ); -FGAPI void FGAPIENTRY glutAddMenuEntry( const char* label, int value ); -FGAPI void FGAPIENTRY glutAddSubMenu( const char* label, int subMenu ); -FGAPI void FGAPIENTRY glutChangeToMenuEntry( int item, const char* label, int value ); -FGAPI void FGAPIENTRY glutChangeToSubMenu( int item, const char* label, int value ); -FGAPI void FGAPIENTRY glutRemoveMenuItem( int item ); -FGAPI void FGAPIENTRY glutAttachMenu( int button ); -FGAPI void FGAPIENTRY glutDetachMenu( int button ); - -/* - * Global callback functions, see freeglut_callbacks.c - */ -FGAPI void FGAPIENTRY glutTimerFunc( unsigned int time, void (* callback)( int ), int value ); -FGAPI void FGAPIENTRY glutIdleFunc( void (* callback)( void ) ); - -/* - * Window-specific callback functions, see freeglut_callbacks.c - */ -FGAPI void FGAPIENTRY glutKeyboardFunc( void (* callback)( unsigned char, int, int ) ); -FGAPI void FGAPIENTRY glutSpecialFunc( void (* callback)( int, int, int ) ); -FGAPI void FGAPIENTRY glutReshapeFunc( void (* callback)( int, int ) ); -FGAPI void FGAPIENTRY glutVisibilityFunc( void (* callback)( int ) ); -FGAPI void FGAPIENTRY glutDisplayFunc( void (* callback)( void ) ); -FGAPI void FGAPIENTRY glutMouseFunc( void (* callback)( int, int, int, int ) ); -FGAPI void FGAPIENTRY glutMotionFunc( void (* callback)( int, int ) ); -FGAPI void FGAPIENTRY glutPassiveMotionFunc( void (* callback)( int, int ) ); -FGAPI void FGAPIENTRY glutEntryFunc( void (* callback)( int ) ); - -FGAPI void FGAPIENTRY glutKeyboardUpFunc( void (* callback)( unsigned char, int, int ) ); -FGAPI void FGAPIENTRY glutSpecialUpFunc( void (* callback)( int, int, int ) ); -FGAPI void FGAPIENTRY glutJoystickFunc( void (* callback)( unsigned int, int, int, int ), int pollInterval ); -FGAPI void FGAPIENTRY glutMenuStateFunc( void (* callback)( int ) ); -FGAPI void FGAPIENTRY glutMenuStatusFunc( void (* callback)( int, int, int ) ); -FGAPI void FGAPIENTRY glutOverlayDisplayFunc( void (* callback)( void ) ); -FGAPI void FGAPIENTRY glutWindowStatusFunc( void (* callback)( int ) ); - -FGAPI void FGAPIENTRY glutSpaceballMotionFunc( void (* callback)( int, int, int ) ); -FGAPI void FGAPIENTRY glutSpaceballRotateFunc( void (* callback)( int, int, int ) ); -FGAPI void FGAPIENTRY glutSpaceballButtonFunc( void (* callback)( int, int ) ); -FGAPI void FGAPIENTRY glutButtonBoxFunc( void (* callback)( int, int ) ); -FGAPI void FGAPIENTRY glutDialsFunc( void (* callback)( int, int ) ); -FGAPI void FGAPIENTRY glutTabletMotionFunc( void (* callback)( int, int ) ); -FGAPI void FGAPIENTRY glutTabletButtonFunc( void (* callback)( int, int, int, int ) ); - -/* - * State setting and retrieval functions, see freeglut_state.c - */ -FGAPI int FGAPIENTRY glutGet( GLenum query ); -FGAPI int FGAPIENTRY glutDeviceGet( GLenum query ); -FGAPI int FGAPIENTRY glutGetModifiers( void ); -FGAPI int FGAPIENTRY glutLayerGet( GLenum query ); - -/* - * Font stuff, see freeglut_font.c - */ -FGAPI void FGAPIENTRY glutBitmapCharacter( void* font, int character ); -FGAPI int FGAPIENTRY glutBitmapWidth( void* font, int character ); -FGAPI void FGAPIENTRY glutStrokeCharacter( void* font, int character ); -FGAPI int FGAPIENTRY glutStrokeWidth( void* font, int character ); -FGAPI int FGAPIENTRY glutBitmapLength( void* font, const unsigned char* string ); -FGAPI int FGAPIENTRY glutStrokeLength( void* font, const unsigned char* string ); - -/* - * Geometry functions, see freeglut_geometry.c - */ -FGAPI void FGAPIENTRY glutWireCube( GLdouble size ); -FGAPI void FGAPIENTRY glutSolidCube( GLdouble size ); -FGAPI void FGAPIENTRY glutWireSphere( GLdouble radius, GLint slices, GLint stacks ); -FGAPI void FGAPIENTRY glutSolidSphere( GLdouble radius, GLint slices, GLint stacks ); -FGAPI void FGAPIENTRY glutWireCone( GLdouble base, GLdouble height, GLint slices, GLint stacks ); -FGAPI void FGAPIENTRY glutSolidCone( GLdouble base, GLdouble height, GLint slices, GLint stacks ); - -FGAPI void FGAPIENTRY glutWireTorus( GLdouble innerRadius, GLdouble outerRadius, GLint sides, GLint rings ); -FGAPI void FGAPIENTRY glutSolidTorus( GLdouble innerRadius, GLdouble outerRadius, GLint sides, GLint rings ); -FGAPI void FGAPIENTRY glutWireDodecahedron( void ); -FGAPI void FGAPIENTRY glutSolidDodecahedron( void ); -FGAPI void FGAPIENTRY glutWireOctahedron( void ); -FGAPI void FGAPIENTRY glutSolidOctahedron( void ); -FGAPI void FGAPIENTRY glutWireTetrahedron( void ); -FGAPI void FGAPIENTRY glutSolidTetrahedron( void ); -FGAPI void FGAPIENTRY glutWireIcosahedron( void ); -FGAPI void FGAPIENTRY glutSolidIcosahedron( void ); - -/* - * Teapot rendering functions, found in freeglut_teapot.c - * NB: front facing polygons have clockwise winding, not counter clockwise - */ -FGAPI void FGAPIENTRY glutWireTeapot( GLdouble size ); -FGAPI void FGAPIENTRY glutSolidTeapot( GLdouble size ); - -/* - * Game mode functions, see freeglut_gamemode.c - */ -FGAPI void FGAPIENTRY glutGameModeString( const char* string ); -FGAPI int FGAPIENTRY glutEnterGameMode( void ); -FGAPI void FGAPIENTRY glutLeaveGameMode( void ); -FGAPI int FGAPIENTRY glutGameModeGet( GLenum query ); - -/* - * Video resize functions, see freeglut_videoresize.c - */ -FGAPI int FGAPIENTRY glutVideoResizeGet( GLenum query ); -FGAPI void FGAPIENTRY glutSetupVideoResizing( void ); -FGAPI void FGAPIENTRY glutStopVideoResizing( void ); -FGAPI void FGAPIENTRY glutVideoResize( int x, int y, int width, int height ); -FGAPI void FGAPIENTRY glutVideoPan( int x, int y, int width, int height ); - -/* - * Colormap functions, see freeglut_misc.c - */ -FGAPI void FGAPIENTRY glutSetColor( int color, GLfloat red, GLfloat green, GLfloat blue ); -FGAPI GLfloat FGAPIENTRY glutGetColor( int color, int component ); -FGAPI void FGAPIENTRY glutCopyColormap( int window ); - -/* - * Misc keyboard and joystick functions, see freeglut_misc.c - */ -FGAPI void FGAPIENTRY glutIgnoreKeyRepeat( int ignore ); -FGAPI void FGAPIENTRY glutSetKeyRepeat( int repeatMode ); -FGAPI void FGAPIENTRY glutForceJoystickFunc( void ); - -/* - * Misc functions, see freeglut_misc.c - */ -FGAPI int FGAPIENTRY glutExtensionSupported( const char* extension ); -FGAPI void FGAPIENTRY glutReportErrors( void ); - -/* Comment from glut.h of classic GLUT: - - Win32 has an annoying issue where there are multiple C run-time - libraries (CRTs). If the executable is linked with a different CRT - from the GLUT DLL, the GLUT DLL will not share the same CRT static - data seen by the executable. In particular, atexit callbacks registered - in the executable will not be called if GLUT calls its (different) - exit routine). GLUT is typically built with the - "/MD" option (the CRT with multithreading DLL support), but the Visual - C++ linker default is "/ML" (the single threaded CRT). - - One workaround to this issue is requiring users to always link with - the same CRT as GLUT is compiled with. That requires users supply a - non-standard option. GLUT 3.7 has its own built-in workaround where - the executable's "exit" function pointer is covertly passed to GLUT. - GLUT then calls the executable's exit function pointer to ensure that - any "atexit" calls registered by the application are called if GLUT - needs to exit. - - Note that the __glut*WithExit routines should NEVER be called directly. - To avoid the atexit workaround, #define GLUT_DISABLE_ATEXIT_HACK. */ - -/* to get the prototype for exit() */ -#include - -#if defined(_WIN32) && !defined(GLUT_DISABLE_ATEXIT_HACK) && !defined(__WATCOMC__) -FGAPI void FGAPIENTRY __glutInitWithExit(int *argcp, char **argv, void (__cdecl *exitfunc)(int)); -FGAPI int FGAPIENTRY __glutCreateWindowWithExit(const char *title, void (__cdecl *exitfunc)(int)); -FGAPI int FGAPIENTRY __glutCreateMenuWithExit(void (* func)(int), void (__cdecl *exitfunc)(int)); -#ifndef FREEGLUT_BUILDING_LIB -#if defined(__GNUC__) -#define FGUNUSED __attribute__((unused)) -#else -#define FGUNUSED -#endif -static void FGAPIENTRY FGUNUSED glutInit_ATEXIT_HACK(int *argcp, char **argv) { __glutInitWithExit(argcp, argv, exit); } -#define glutInit glutInit_ATEXIT_HACK -static int FGAPIENTRY FGUNUSED glutCreateWindow_ATEXIT_HACK(const char *title) { return __glutCreateWindowWithExit(title, exit); } -#define glutCreateWindow glutCreateWindow_ATEXIT_HACK -static int FGAPIENTRY FGUNUSED glutCreateMenu_ATEXIT_HACK(void (* func)(int)) { return __glutCreateMenuWithExit(func, exit); } -#define glutCreateMenu glutCreateMenu_ATEXIT_HACK -#endif -#endif - -#ifdef __cplusplus - } -#endif - -/*** END OF FILE ***/ - -#endif /* __FREEGLUT_STD_H__ */ - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/freeglut/include/GL/glext.h b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/freeglut/include/GL/glext.h deleted file mode 100644 index 99a4b4bdb295..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/freeglut/include/GL/glext.h +++ /dev/null @@ -1,11751 +0,0 @@ -#ifndef __glext_h_ -#define __glext_h_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** Copyright (c) 2007-2012 The Khronos Group Inc. -** -** Permission is hereby granted, free of charge, to any person obtaining a -** copy of this software and/or associated documentation files (the -** "Materials"), to deal in the Materials without restriction, including -** without limitation the rights to use, copy, modify, merge, publish, -** distribute, sublicense, and/or sell copies of the Materials, and to -** permit persons to whom the Materials are furnished to do so, subject to -** the following conditions: -** -** The above copyright notice and this permission notice shall be included -** in all copies or substantial portions of the Materials. -** -** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. -*/ - -/* Header file version number, required by OpenGL ABI for Linux */ -/* glext.h last updated $Date: 2012-03-05 02:52:51 -0800 (Mon, 05 Mar 2012) $ */ -/* Current version at http://www.opengl.org/registry/ */ -#define GL_GLEXT_VERSION 76 -/* Function declaration macros - to move into glplatform.h */ - -#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) -#define WIN32_LEAN_AND_MEAN 1 -#include -#endif - -#ifndef APIENTRY -#define APIENTRY -#endif -#ifndef APIENTRYP -#define APIENTRYP APIENTRY * -#endif -#ifndef GLAPI -#define GLAPI extern -#endif - -/*************************************************************/ - -#ifndef GL_VERSION_1_2 -#define GL_UNSIGNED_BYTE_3_3_2 0x8032 -#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 -#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 -#define GL_UNSIGNED_INT_8_8_8_8 0x8035 -#define GL_UNSIGNED_INT_10_10_10_2 0x8036 -#define GL_TEXTURE_BINDING_3D 0x806A -#define GL_PACK_SKIP_IMAGES 0x806B -#define GL_PACK_IMAGE_HEIGHT 0x806C -#define GL_UNPACK_SKIP_IMAGES 0x806D -#define GL_UNPACK_IMAGE_HEIGHT 0x806E -#define GL_TEXTURE_3D 0x806F -#define GL_PROXY_TEXTURE_3D 0x8070 -#define GL_TEXTURE_DEPTH 0x8071 -#define GL_TEXTURE_WRAP_R 0x8072 -#define GL_MAX_3D_TEXTURE_SIZE 0x8073 -#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 -#define GL_UNSIGNED_SHORT_5_6_5 0x8363 -#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 -#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 -#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 -#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 -#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 -#define GL_BGR 0x80E0 -#define GL_BGRA 0x80E1 -#define GL_MAX_ELEMENTS_VERTICES 0x80E8 -#define GL_MAX_ELEMENTS_INDICES 0x80E9 -#define GL_CLAMP_TO_EDGE 0x812F -#define GL_TEXTURE_MIN_LOD 0x813A -#define GL_TEXTURE_MAX_LOD 0x813B -#define GL_TEXTURE_BASE_LEVEL 0x813C -#define GL_TEXTURE_MAX_LEVEL 0x813D -#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 -#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 -#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 -#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 -#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E -#endif - -#ifndef GL_VERSION_1_2_DEPRECATED -#define GL_RESCALE_NORMAL 0x803A -#define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8 -#define GL_SINGLE_COLOR 0x81F9 -#define GL_SEPARATE_SPECULAR_COLOR 0x81FA -#define GL_ALIASED_POINT_SIZE_RANGE 0x846D -#endif - -#ifndef GL_ARB_imaging -#define GL_CONSTANT_COLOR 0x8001 -#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 -#define GL_CONSTANT_ALPHA 0x8003 -#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 -#define GL_BLEND_COLOR 0x8005 -#define GL_FUNC_ADD 0x8006 -#define GL_MIN 0x8007 -#define GL_MAX 0x8008 -#define GL_BLEND_EQUATION 0x8009 -#define GL_FUNC_SUBTRACT 0x800A -#define GL_FUNC_REVERSE_SUBTRACT 0x800B -#endif - -#ifndef GL_ARB_imaging_DEPRECATED -#define GL_CONVOLUTION_1D 0x8010 -#define GL_CONVOLUTION_2D 0x8011 -#define GL_SEPARABLE_2D 0x8012 -#define GL_CONVOLUTION_BORDER_MODE 0x8013 -#define GL_CONVOLUTION_FILTER_SCALE 0x8014 -#define GL_CONVOLUTION_FILTER_BIAS 0x8015 -#define GL_REDUCE 0x8016 -#define GL_CONVOLUTION_FORMAT 0x8017 -#define GL_CONVOLUTION_WIDTH 0x8018 -#define GL_CONVOLUTION_HEIGHT 0x8019 -#define GL_MAX_CONVOLUTION_WIDTH 0x801A -#define GL_MAX_CONVOLUTION_HEIGHT 0x801B -#define GL_POST_CONVOLUTION_RED_SCALE 0x801C -#define GL_POST_CONVOLUTION_GREEN_SCALE 0x801D -#define GL_POST_CONVOLUTION_BLUE_SCALE 0x801E -#define GL_POST_CONVOLUTION_ALPHA_SCALE 0x801F -#define GL_POST_CONVOLUTION_RED_BIAS 0x8020 -#define GL_POST_CONVOLUTION_GREEN_BIAS 0x8021 -#define GL_POST_CONVOLUTION_BLUE_BIAS 0x8022 -#define GL_POST_CONVOLUTION_ALPHA_BIAS 0x8023 -#define GL_HISTOGRAM 0x8024 -#define GL_PROXY_HISTOGRAM 0x8025 -#define GL_HISTOGRAM_WIDTH 0x8026 -#define GL_HISTOGRAM_FORMAT 0x8027 -#define GL_HISTOGRAM_RED_SIZE 0x8028 -#define GL_HISTOGRAM_GREEN_SIZE 0x8029 -#define GL_HISTOGRAM_BLUE_SIZE 0x802A -#define GL_HISTOGRAM_ALPHA_SIZE 0x802B -#define GL_HISTOGRAM_LUMINANCE_SIZE 0x802C -#define GL_HISTOGRAM_SINK 0x802D -#define GL_MINMAX 0x802E -#define GL_MINMAX_FORMAT 0x802F -#define GL_MINMAX_SINK 0x8030 -#define GL_TABLE_TOO_LARGE 0x8031 -#define GL_COLOR_MATRIX 0x80B1 -#define GL_COLOR_MATRIX_STACK_DEPTH 0x80B2 -#define GL_MAX_COLOR_MATRIX_STACK_DEPTH 0x80B3 -#define GL_POST_COLOR_MATRIX_RED_SCALE 0x80B4 -#define GL_POST_COLOR_MATRIX_GREEN_SCALE 0x80B5 -#define GL_POST_COLOR_MATRIX_BLUE_SCALE 0x80B6 -#define GL_POST_COLOR_MATRIX_ALPHA_SCALE 0x80B7 -#define GL_POST_COLOR_MATRIX_RED_BIAS 0x80B8 -#define GL_POST_COLOR_MATRIX_GREEN_BIAS 0x80B9 -#define GL_POST_COLOR_MATRIX_BLUE_BIAS 0x80BA -#define GL_POST_COLOR_MATRIX_ALPHA_BIAS 0x80BB -#define GL_COLOR_TABLE 0x80D0 -#define GL_POST_CONVOLUTION_COLOR_TABLE 0x80D1 -#define GL_POST_COLOR_MATRIX_COLOR_TABLE 0x80D2 -#define GL_PROXY_COLOR_TABLE 0x80D3 -#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE 0x80D4 -#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE 0x80D5 -#define GL_COLOR_TABLE_SCALE 0x80D6 -#define GL_COLOR_TABLE_BIAS 0x80D7 -#define GL_COLOR_TABLE_FORMAT 0x80D8 -#define GL_COLOR_TABLE_WIDTH 0x80D9 -#define GL_COLOR_TABLE_RED_SIZE 0x80DA -#define GL_COLOR_TABLE_GREEN_SIZE 0x80DB -#define GL_COLOR_TABLE_BLUE_SIZE 0x80DC -#define GL_COLOR_TABLE_ALPHA_SIZE 0x80DD -#define GL_COLOR_TABLE_LUMINANCE_SIZE 0x80DE -#define GL_COLOR_TABLE_INTENSITY_SIZE 0x80DF -#define GL_CONSTANT_BORDER 0x8151 -#define GL_REPLICATE_BORDER 0x8153 -#define GL_CONVOLUTION_BORDER_COLOR 0x8154 -#endif - -#ifndef GL_VERSION_1_3 -#define GL_TEXTURE0 0x84C0 -#define GL_TEXTURE1 0x84C1 -#define GL_TEXTURE2 0x84C2 -#define GL_TEXTURE3 0x84C3 -#define GL_TEXTURE4 0x84C4 -#define GL_TEXTURE5 0x84C5 -#define GL_TEXTURE6 0x84C6 -#define GL_TEXTURE7 0x84C7 -#define GL_TEXTURE8 0x84C8 -#define GL_TEXTURE9 0x84C9 -#define GL_TEXTURE10 0x84CA -#define GL_TEXTURE11 0x84CB -#define GL_TEXTURE12 0x84CC -#define GL_TEXTURE13 0x84CD -#define GL_TEXTURE14 0x84CE -#define GL_TEXTURE15 0x84CF -#define GL_TEXTURE16 0x84D0 -#define GL_TEXTURE17 0x84D1 -#define GL_TEXTURE18 0x84D2 -#define GL_TEXTURE19 0x84D3 -#define GL_TEXTURE20 0x84D4 -#define GL_TEXTURE21 0x84D5 -#define GL_TEXTURE22 0x84D6 -#define GL_TEXTURE23 0x84D7 -#define GL_TEXTURE24 0x84D8 -#define GL_TEXTURE25 0x84D9 -#define GL_TEXTURE26 0x84DA -#define GL_TEXTURE27 0x84DB -#define GL_TEXTURE28 0x84DC -#define GL_TEXTURE29 0x84DD -#define GL_TEXTURE30 0x84DE -#define GL_TEXTURE31 0x84DF -#define GL_ACTIVE_TEXTURE 0x84E0 -#define GL_MULTISAMPLE 0x809D -#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E -#define GL_SAMPLE_ALPHA_TO_ONE 0x809F -#define GL_SAMPLE_COVERAGE 0x80A0 -#define GL_SAMPLE_BUFFERS 0x80A8 -#define GL_SAMPLES 0x80A9 -#define GL_SAMPLE_COVERAGE_VALUE 0x80AA -#define GL_SAMPLE_COVERAGE_INVERT 0x80AB -#define GL_TEXTURE_CUBE_MAP 0x8513 -#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A -#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B -#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C -#define GL_COMPRESSED_RGB 0x84ED -#define GL_COMPRESSED_RGBA 0x84EE -#define GL_TEXTURE_COMPRESSION_HINT 0x84EF -#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 -#define GL_TEXTURE_COMPRESSED 0x86A1 -#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 -#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 -#define GL_CLAMP_TO_BORDER 0x812D -#endif - -#ifndef GL_VERSION_1_3_DEPRECATED -#define GL_CLIENT_ACTIVE_TEXTURE 0x84E1 -#define GL_MAX_TEXTURE_UNITS 0x84E2 -#define GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3 -#define GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4 -#define GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5 -#define GL_TRANSPOSE_COLOR_MATRIX 0x84E6 -#define GL_MULTISAMPLE_BIT 0x20000000 -#define GL_NORMAL_MAP 0x8511 -#define GL_REFLECTION_MAP 0x8512 -#define GL_COMPRESSED_ALPHA 0x84E9 -#define GL_COMPRESSED_LUMINANCE 0x84EA -#define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB -#define GL_COMPRESSED_INTENSITY 0x84EC -#define GL_COMBINE 0x8570 -#define GL_COMBINE_RGB 0x8571 -#define GL_COMBINE_ALPHA 0x8572 -#define GL_SOURCE0_RGB 0x8580 -#define GL_SOURCE1_RGB 0x8581 -#define GL_SOURCE2_RGB 0x8582 -#define GL_SOURCE0_ALPHA 0x8588 -#define GL_SOURCE1_ALPHA 0x8589 -#define GL_SOURCE2_ALPHA 0x858A -#define GL_OPERAND0_RGB 0x8590 -#define GL_OPERAND1_RGB 0x8591 -#define GL_OPERAND2_RGB 0x8592 -#define GL_OPERAND0_ALPHA 0x8598 -#define GL_OPERAND1_ALPHA 0x8599 -#define GL_OPERAND2_ALPHA 0x859A -#define GL_RGB_SCALE 0x8573 -#define GL_ADD_SIGNED 0x8574 -#define GL_INTERPOLATE 0x8575 -#define GL_SUBTRACT 0x84E7 -#define GL_CONSTANT 0x8576 -#define GL_PRIMARY_COLOR 0x8577 -#define GL_PREVIOUS 0x8578 -#define GL_DOT3_RGB 0x86AE -#define GL_DOT3_RGBA 0x86AF -#endif - -#ifndef GL_VERSION_1_4 -#define GL_BLEND_DST_RGB 0x80C8 -#define GL_BLEND_SRC_RGB 0x80C9 -#define GL_BLEND_DST_ALPHA 0x80CA -#define GL_BLEND_SRC_ALPHA 0x80CB -#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 -#define GL_DEPTH_COMPONENT16 0x81A5 -#define GL_DEPTH_COMPONENT24 0x81A6 -#define GL_DEPTH_COMPONENT32 0x81A7 -#define GL_MIRRORED_REPEAT 0x8370 -#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD -#define GL_TEXTURE_LOD_BIAS 0x8501 -#define GL_INCR_WRAP 0x8507 -#define GL_DECR_WRAP 0x8508 -#define GL_TEXTURE_DEPTH_SIZE 0x884A -#define GL_TEXTURE_COMPARE_MODE 0x884C -#define GL_TEXTURE_COMPARE_FUNC 0x884D -#endif - -#ifndef GL_VERSION_1_4_DEPRECATED -#define GL_POINT_SIZE_MIN 0x8126 -#define GL_POINT_SIZE_MAX 0x8127 -#define GL_POINT_DISTANCE_ATTENUATION 0x8129 -#define GL_GENERATE_MIPMAP 0x8191 -#define GL_GENERATE_MIPMAP_HINT 0x8192 -#define GL_FOG_COORDINATE_SOURCE 0x8450 -#define GL_FOG_COORDINATE 0x8451 -#define GL_FRAGMENT_DEPTH 0x8452 -#define GL_CURRENT_FOG_COORDINATE 0x8453 -#define GL_FOG_COORDINATE_ARRAY_TYPE 0x8454 -#define GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455 -#define GL_FOG_COORDINATE_ARRAY_POINTER 0x8456 -#define GL_FOG_COORDINATE_ARRAY 0x8457 -#define GL_COLOR_SUM 0x8458 -#define GL_CURRENT_SECONDARY_COLOR 0x8459 -#define GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A -#define GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B -#define GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C -#define GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D -#define GL_SECONDARY_COLOR_ARRAY 0x845E -#define GL_TEXTURE_FILTER_CONTROL 0x8500 -#define GL_DEPTH_TEXTURE_MODE 0x884B -#define GL_COMPARE_R_TO_TEXTURE 0x884E -#endif - -#ifndef GL_VERSION_1_5 -#define GL_BUFFER_SIZE 0x8764 -#define GL_BUFFER_USAGE 0x8765 -#define GL_QUERY_COUNTER_BITS 0x8864 -#define GL_CURRENT_QUERY 0x8865 -#define GL_QUERY_RESULT 0x8866 -#define GL_QUERY_RESULT_AVAILABLE 0x8867 -#define GL_ARRAY_BUFFER 0x8892 -#define GL_ELEMENT_ARRAY_BUFFER 0x8893 -#define GL_ARRAY_BUFFER_BINDING 0x8894 -#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 -#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F -#define GL_READ_ONLY 0x88B8 -#define GL_WRITE_ONLY 0x88B9 -#define GL_READ_WRITE 0x88BA -#define GL_BUFFER_ACCESS 0x88BB -#define GL_BUFFER_MAPPED 0x88BC -#define GL_BUFFER_MAP_POINTER 0x88BD -#define GL_STREAM_DRAW 0x88E0 -#define GL_STREAM_READ 0x88E1 -#define GL_STREAM_COPY 0x88E2 -#define GL_STATIC_DRAW 0x88E4 -#define GL_STATIC_READ 0x88E5 -#define GL_STATIC_COPY 0x88E6 -#define GL_DYNAMIC_DRAW 0x88E8 -#define GL_DYNAMIC_READ 0x88E9 -#define GL_DYNAMIC_COPY 0x88EA -#define GL_SAMPLES_PASSED 0x8914 -#endif - -#ifndef GL_VERSION_1_5_DEPRECATED -#define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896 -#define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897 -#define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898 -#define GL_INDEX_ARRAY_BUFFER_BINDING 0x8899 -#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A -#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B -#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C -#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D -#define GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E -#define GL_FOG_COORD_SRC 0x8450 -#define GL_FOG_COORD 0x8451 -#define GL_CURRENT_FOG_COORD 0x8453 -#define GL_FOG_COORD_ARRAY_TYPE 0x8454 -#define GL_FOG_COORD_ARRAY_STRIDE 0x8455 -#define GL_FOG_COORD_ARRAY_POINTER 0x8456 -#define GL_FOG_COORD_ARRAY 0x8457 -#define GL_FOG_COORD_ARRAY_BUFFER_BINDING 0x889D -#define GL_SRC0_RGB 0x8580 -#define GL_SRC1_RGB 0x8581 -#define GL_SRC2_RGB 0x8582 -#define GL_SRC0_ALPHA 0x8588 -#define GL_SRC1_ALPHA 0x8589 -#define GL_SRC2_ALPHA 0x858A -#endif - -#ifndef GL_VERSION_2_0 -#define GL_BLEND_EQUATION_RGB 0x8009 -#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 -#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 -#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 -#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 -#define GL_CURRENT_VERTEX_ATTRIB 0x8626 -#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 -#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 -#define GL_STENCIL_BACK_FUNC 0x8800 -#define GL_STENCIL_BACK_FAIL 0x8801 -#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 -#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 -#define GL_MAX_DRAW_BUFFERS 0x8824 -#define GL_DRAW_BUFFER0 0x8825 -#define GL_DRAW_BUFFER1 0x8826 -#define GL_DRAW_BUFFER2 0x8827 -#define GL_DRAW_BUFFER3 0x8828 -#define GL_DRAW_BUFFER4 0x8829 -#define GL_DRAW_BUFFER5 0x882A -#define GL_DRAW_BUFFER6 0x882B -#define GL_DRAW_BUFFER7 0x882C -#define GL_DRAW_BUFFER8 0x882D -#define GL_DRAW_BUFFER9 0x882E -#define GL_DRAW_BUFFER10 0x882F -#define GL_DRAW_BUFFER11 0x8830 -#define GL_DRAW_BUFFER12 0x8831 -#define GL_DRAW_BUFFER13 0x8832 -#define GL_DRAW_BUFFER14 0x8833 -#define GL_DRAW_BUFFER15 0x8834 -#define GL_BLEND_EQUATION_ALPHA 0x883D -#define GL_MAX_VERTEX_ATTRIBS 0x8869 -#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A -#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 -#define GL_FRAGMENT_SHADER 0x8B30 -#define GL_VERTEX_SHADER 0x8B31 -#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 -#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A -#define GL_MAX_VARYING_FLOATS 0x8B4B -#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C -#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D -#define GL_SHADER_TYPE 0x8B4F -#define GL_FLOAT_VEC2 0x8B50 -#define GL_FLOAT_VEC3 0x8B51 -#define GL_FLOAT_VEC4 0x8B52 -#define GL_INT_VEC2 0x8B53 -#define GL_INT_VEC3 0x8B54 -#define GL_INT_VEC4 0x8B55 -#define GL_BOOL 0x8B56 -#define GL_BOOL_VEC2 0x8B57 -#define GL_BOOL_VEC3 0x8B58 -#define GL_BOOL_VEC4 0x8B59 -#define GL_FLOAT_MAT2 0x8B5A -#define GL_FLOAT_MAT3 0x8B5B -#define GL_FLOAT_MAT4 0x8B5C -#define GL_SAMPLER_1D 0x8B5D -#define GL_SAMPLER_2D 0x8B5E -#define GL_SAMPLER_3D 0x8B5F -#define GL_SAMPLER_CUBE 0x8B60 -#define GL_SAMPLER_1D_SHADOW 0x8B61 -#define GL_SAMPLER_2D_SHADOW 0x8B62 -#define GL_DELETE_STATUS 0x8B80 -#define GL_COMPILE_STATUS 0x8B81 -#define GL_LINK_STATUS 0x8B82 -#define GL_VALIDATE_STATUS 0x8B83 -#define GL_INFO_LOG_LENGTH 0x8B84 -#define GL_ATTACHED_SHADERS 0x8B85 -#define GL_ACTIVE_UNIFORMS 0x8B86 -#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 -#define GL_SHADER_SOURCE_LENGTH 0x8B88 -#define GL_ACTIVE_ATTRIBUTES 0x8B89 -#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A -#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B -#define GL_SHADING_LANGUAGE_VERSION 0x8B8C -#define GL_CURRENT_PROGRAM 0x8B8D -#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 -#define GL_LOWER_LEFT 0x8CA1 -#define GL_UPPER_LEFT 0x8CA2 -#define GL_STENCIL_BACK_REF 0x8CA3 -#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 -#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 -#endif - -#ifndef GL_VERSION_2_0_DEPRECATED -#define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643 -#define GL_POINT_SPRITE 0x8861 -#define GL_COORD_REPLACE 0x8862 -#define GL_MAX_TEXTURE_COORDS 0x8871 -#endif - -#ifndef GL_VERSION_2_1 -#define GL_PIXEL_PACK_BUFFER 0x88EB -#define GL_PIXEL_UNPACK_BUFFER 0x88EC -#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED -#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF -#define GL_FLOAT_MAT2x3 0x8B65 -#define GL_FLOAT_MAT2x4 0x8B66 -#define GL_FLOAT_MAT3x2 0x8B67 -#define GL_FLOAT_MAT3x4 0x8B68 -#define GL_FLOAT_MAT4x2 0x8B69 -#define GL_FLOAT_MAT4x3 0x8B6A -#define GL_SRGB 0x8C40 -#define GL_SRGB8 0x8C41 -#define GL_SRGB_ALPHA 0x8C42 -#define GL_SRGB8_ALPHA8 0x8C43 -#define GL_COMPRESSED_SRGB 0x8C48 -#define GL_COMPRESSED_SRGB_ALPHA 0x8C49 -#endif - -#ifndef GL_VERSION_2_1_DEPRECATED -#define GL_CURRENT_RASTER_SECONDARY_COLOR 0x845F -#define GL_SLUMINANCE_ALPHA 0x8C44 -#define GL_SLUMINANCE8_ALPHA8 0x8C45 -#define GL_SLUMINANCE 0x8C46 -#define GL_SLUMINANCE8 0x8C47 -#define GL_COMPRESSED_SLUMINANCE 0x8C4A -#define GL_COMPRESSED_SLUMINANCE_ALPHA 0x8C4B -#endif - -#ifndef GL_VERSION_3_0 -#define GL_COMPARE_REF_TO_TEXTURE 0x884E -#define GL_CLIP_DISTANCE0 0x3000 -#define GL_CLIP_DISTANCE1 0x3001 -#define GL_CLIP_DISTANCE2 0x3002 -#define GL_CLIP_DISTANCE3 0x3003 -#define GL_CLIP_DISTANCE4 0x3004 -#define GL_CLIP_DISTANCE5 0x3005 -#define GL_CLIP_DISTANCE6 0x3006 -#define GL_CLIP_DISTANCE7 0x3007 -#define GL_MAX_CLIP_DISTANCES 0x0D32 -#define GL_MAJOR_VERSION 0x821B -#define GL_MINOR_VERSION 0x821C -#define GL_NUM_EXTENSIONS 0x821D -#define GL_CONTEXT_FLAGS 0x821E -#define GL_COMPRESSED_RED 0x8225 -#define GL_COMPRESSED_RG 0x8226 -#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x0001 -#define GL_RGBA32F 0x8814 -#define GL_RGB32F 0x8815 -#define GL_RGBA16F 0x881A -#define GL_RGB16F 0x881B -#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD -#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF -#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 -#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 -#define GL_CLAMP_READ_COLOR 0x891C -#define GL_FIXED_ONLY 0x891D -#define GL_MAX_VARYING_COMPONENTS 0x8B4B -#define GL_TEXTURE_1D_ARRAY 0x8C18 -#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 -#define GL_TEXTURE_2D_ARRAY 0x8C1A -#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B -#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C -#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D -#define GL_R11F_G11F_B10F 0x8C3A -#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B -#define GL_RGB9_E5 0x8C3D -#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E -#define GL_TEXTURE_SHARED_SIZE 0x8C3F -#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 -#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F -#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 -#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 -#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 -#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 -#define GL_PRIMITIVES_GENERATED 0x8C87 -#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 -#define GL_RASTERIZER_DISCARD 0x8C89 -#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A -#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B -#define GL_INTERLEAVED_ATTRIBS 0x8C8C -#define GL_SEPARATE_ATTRIBS 0x8C8D -#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E -#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F -#define GL_RGBA32UI 0x8D70 -#define GL_RGB32UI 0x8D71 -#define GL_RGBA16UI 0x8D76 -#define GL_RGB16UI 0x8D77 -#define GL_RGBA8UI 0x8D7C -#define GL_RGB8UI 0x8D7D -#define GL_RGBA32I 0x8D82 -#define GL_RGB32I 0x8D83 -#define GL_RGBA16I 0x8D88 -#define GL_RGB16I 0x8D89 -#define GL_RGBA8I 0x8D8E -#define GL_RGB8I 0x8D8F -#define GL_RED_INTEGER 0x8D94 -#define GL_GREEN_INTEGER 0x8D95 -#define GL_BLUE_INTEGER 0x8D96 -#define GL_RGB_INTEGER 0x8D98 -#define GL_RGBA_INTEGER 0x8D99 -#define GL_BGR_INTEGER 0x8D9A -#define GL_BGRA_INTEGER 0x8D9B -#define GL_SAMPLER_1D_ARRAY 0x8DC0 -#define GL_SAMPLER_2D_ARRAY 0x8DC1 -#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 -#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 -#define GL_SAMPLER_CUBE_SHADOW 0x8DC5 -#define GL_UNSIGNED_INT_VEC2 0x8DC6 -#define GL_UNSIGNED_INT_VEC3 0x8DC7 -#define GL_UNSIGNED_INT_VEC4 0x8DC8 -#define GL_INT_SAMPLER_1D 0x8DC9 -#define GL_INT_SAMPLER_2D 0x8DCA -#define GL_INT_SAMPLER_3D 0x8DCB -#define GL_INT_SAMPLER_CUBE 0x8DCC -#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE -#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF -#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 -#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 -#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 -#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 -#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 -#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 -#define GL_QUERY_WAIT 0x8E13 -#define GL_QUERY_NO_WAIT 0x8E14 -#define GL_QUERY_BY_REGION_WAIT 0x8E15 -#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 -#define GL_BUFFER_ACCESS_FLAGS 0x911F -#define GL_BUFFER_MAP_LENGTH 0x9120 -#define GL_BUFFER_MAP_OFFSET 0x9121 -/* Reuse tokens from ARB_depth_buffer_float */ -/* reuse GL_DEPTH_COMPONENT32F */ -/* reuse GL_DEPTH32F_STENCIL8 */ -/* reuse GL_FLOAT_32_UNSIGNED_INT_24_8_REV */ -/* Reuse tokens from ARB_framebuffer_object */ -/* reuse GL_INVALID_FRAMEBUFFER_OPERATION */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE */ -/* reuse GL_FRAMEBUFFER_DEFAULT */ -/* reuse GL_FRAMEBUFFER_UNDEFINED */ -/* reuse GL_DEPTH_STENCIL_ATTACHMENT */ -/* reuse GL_INDEX */ -/* reuse GL_MAX_RENDERBUFFER_SIZE */ -/* reuse GL_DEPTH_STENCIL */ -/* reuse GL_UNSIGNED_INT_24_8 */ -/* reuse GL_DEPTH24_STENCIL8 */ -/* reuse GL_TEXTURE_STENCIL_SIZE */ -/* reuse GL_TEXTURE_RED_TYPE */ -/* reuse GL_TEXTURE_GREEN_TYPE */ -/* reuse GL_TEXTURE_BLUE_TYPE */ -/* reuse GL_TEXTURE_ALPHA_TYPE */ -/* reuse GL_TEXTURE_DEPTH_TYPE */ -/* reuse GL_UNSIGNED_NORMALIZED */ -/* reuse GL_FRAMEBUFFER_BINDING */ -/* reuse GL_DRAW_FRAMEBUFFER_BINDING */ -/* reuse GL_RENDERBUFFER_BINDING */ -/* reuse GL_READ_FRAMEBUFFER */ -/* reuse GL_DRAW_FRAMEBUFFER */ -/* reuse GL_READ_FRAMEBUFFER_BINDING */ -/* reuse GL_RENDERBUFFER_SAMPLES */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER */ -/* reuse GL_FRAMEBUFFER_COMPLETE */ -/* reuse GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT */ -/* reuse GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT */ -/* reuse GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER */ -/* reuse GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER */ -/* reuse GL_FRAMEBUFFER_UNSUPPORTED */ -/* reuse GL_MAX_COLOR_ATTACHMENTS */ -/* reuse GL_COLOR_ATTACHMENT0 */ -/* reuse GL_COLOR_ATTACHMENT1 */ -/* reuse GL_COLOR_ATTACHMENT2 */ -/* reuse GL_COLOR_ATTACHMENT3 */ -/* reuse GL_COLOR_ATTACHMENT4 */ -/* reuse GL_COLOR_ATTACHMENT5 */ -/* reuse GL_COLOR_ATTACHMENT6 */ -/* reuse GL_COLOR_ATTACHMENT7 */ -/* reuse GL_COLOR_ATTACHMENT8 */ -/* reuse GL_COLOR_ATTACHMENT9 */ -/* reuse GL_COLOR_ATTACHMENT10 */ -/* reuse GL_COLOR_ATTACHMENT11 */ -/* reuse GL_COLOR_ATTACHMENT12 */ -/* reuse GL_COLOR_ATTACHMENT13 */ -/* reuse GL_COLOR_ATTACHMENT14 */ -/* reuse GL_COLOR_ATTACHMENT15 */ -/* reuse GL_DEPTH_ATTACHMENT */ -/* reuse GL_STENCIL_ATTACHMENT */ -/* reuse GL_FRAMEBUFFER */ -/* reuse GL_RENDERBUFFER */ -/* reuse GL_RENDERBUFFER_WIDTH */ -/* reuse GL_RENDERBUFFER_HEIGHT */ -/* reuse GL_RENDERBUFFER_INTERNAL_FORMAT */ -/* reuse GL_STENCIL_INDEX1 */ -/* reuse GL_STENCIL_INDEX4 */ -/* reuse GL_STENCIL_INDEX8 */ -/* reuse GL_STENCIL_INDEX16 */ -/* reuse GL_RENDERBUFFER_RED_SIZE */ -/* reuse GL_RENDERBUFFER_GREEN_SIZE */ -/* reuse GL_RENDERBUFFER_BLUE_SIZE */ -/* reuse GL_RENDERBUFFER_ALPHA_SIZE */ -/* reuse GL_RENDERBUFFER_DEPTH_SIZE */ -/* reuse GL_RENDERBUFFER_STENCIL_SIZE */ -/* reuse GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE */ -/* reuse GL_MAX_SAMPLES */ -/* Reuse tokens from ARB_framebuffer_sRGB */ -/* reuse GL_FRAMEBUFFER_SRGB */ -/* Reuse tokens from ARB_half_float_vertex */ -/* reuse GL_HALF_FLOAT */ -/* Reuse tokens from ARB_map_buffer_range */ -/* reuse GL_MAP_READ_BIT */ -/* reuse GL_MAP_WRITE_BIT */ -/* reuse GL_MAP_INVALIDATE_RANGE_BIT */ -/* reuse GL_MAP_INVALIDATE_BUFFER_BIT */ -/* reuse GL_MAP_FLUSH_EXPLICIT_BIT */ -/* reuse GL_MAP_UNSYNCHRONIZED_BIT */ -/* Reuse tokens from ARB_texture_compression_rgtc */ -/* reuse GL_COMPRESSED_RED_RGTC1 */ -/* reuse GL_COMPRESSED_SIGNED_RED_RGTC1 */ -/* reuse GL_COMPRESSED_RG_RGTC2 */ -/* reuse GL_COMPRESSED_SIGNED_RG_RGTC2 */ -/* Reuse tokens from ARB_texture_rg */ -/* reuse GL_RG */ -/* reuse GL_RG_INTEGER */ -/* reuse GL_R8 */ -/* reuse GL_R16 */ -/* reuse GL_RG8 */ -/* reuse GL_RG16 */ -/* reuse GL_R16F */ -/* reuse GL_R32F */ -/* reuse GL_RG16F */ -/* reuse GL_RG32F */ -/* reuse GL_R8I */ -/* reuse GL_R8UI */ -/* reuse GL_R16I */ -/* reuse GL_R16UI */ -/* reuse GL_R32I */ -/* reuse GL_R32UI */ -/* reuse GL_RG8I */ -/* reuse GL_RG8UI */ -/* reuse GL_RG16I */ -/* reuse GL_RG16UI */ -/* reuse GL_RG32I */ -/* reuse GL_RG32UI */ -/* Reuse tokens from ARB_vertex_array_object */ -/* reuse GL_VERTEX_ARRAY_BINDING */ -#endif - -#ifndef GL_VERSION_3_0_DEPRECATED -#define GL_CLAMP_VERTEX_COLOR 0x891A -#define GL_CLAMP_FRAGMENT_COLOR 0x891B -#define GL_ALPHA_INTEGER 0x8D97 -/* Reuse tokens from ARB_framebuffer_object */ -/* reuse GL_TEXTURE_LUMINANCE_TYPE */ -/* reuse GL_TEXTURE_INTENSITY_TYPE */ -#endif - -#ifndef GL_VERSION_3_1 -#define GL_SAMPLER_2D_RECT 0x8B63 -#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 -#define GL_SAMPLER_BUFFER 0x8DC2 -#define GL_INT_SAMPLER_2D_RECT 0x8DCD -#define GL_INT_SAMPLER_BUFFER 0x8DD0 -#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 -#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 -#define GL_TEXTURE_BUFFER 0x8C2A -#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B -#define GL_TEXTURE_BINDING_BUFFER 0x8C2C -#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D -#define GL_TEXTURE_BUFFER_FORMAT 0x8C2E -#define GL_TEXTURE_RECTANGLE 0x84F5 -#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 -#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 -#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 -#define GL_RED_SNORM 0x8F90 -#define GL_RG_SNORM 0x8F91 -#define GL_RGB_SNORM 0x8F92 -#define GL_RGBA_SNORM 0x8F93 -#define GL_R8_SNORM 0x8F94 -#define GL_RG8_SNORM 0x8F95 -#define GL_RGB8_SNORM 0x8F96 -#define GL_RGBA8_SNORM 0x8F97 -#define GL_R16_SNORM 0x8F98 -#define GL_RG16_SNORM 0x8F99 -#define GL_RGB16_SNORM 0x8F9A -#define GL_RGBA16_SNORM 0x8F9B -#define GL_SIGNED_NORMALIZED 0x8F9C -#define GL_PRIMITIVE_RESTART 0x8F9D -#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E -/* Reuse tokens from ARB_copy_buffer */ -/* reuse GL_COPY_READ_BUFFER */ -/* reuse GL_COPY_WRITE_BUFFER */ -/* Reuse tokens from ARB_draw_instanced (none) */ -/* Reuse tokens from ARB_uniform_buffer_object */ -/* reuse GL_UNIFORM_BUFFER */ -/* reuse GL_UNIFORM_BUFFER_BINDING */ -/* reuse GL_UNIFORM_BUFFER_START */ -/* reuse GL_UNIFORM_BUFFER_SIZE */ -/* reuse GL_MAX_VERTEX_UNIFORM_BLOCKS */ -/* reuse GL_MAX_FRAGMENT_UNIFORM_BLOCKS */ -/* reuse GL_MAX_COMBINED_UNIFORM_BLOCKS */ -/* reuse GL_MAX_UNIFORM_BUFFER_BINDINGS */ -/* reuse GL_MAX_UNIFORM_BLOCK_SIZE */ -/* reuse GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS */ -/* reuse GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS */ -/* reuse GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT */ -/* reuse GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH */ -/* reuse GL_ACTIVE_UNIFORM_BLOCKS */ -/* reuse GL_UNIFORM_TYPE */ -/* reuse GL_UNIFORM_SIZE */ -/* reuse GL_UNIFORM_NAME_LENGTH */ -/* reuse GL_UNIFORM_BLOCK_INDEX */ -/* reuse GL_UNIFORM_OFFSET */ -/* reuse GL_UNIFORM_ARRAY_STRIDE */ -/* reuse GL_UNIFORM_MATRIX_STRIDE */ -/* reuse GL_UNIFORM_IS_ROW_MAJOR */ -/* reuse GL_UNIFORM_BLOCK_BINDING */ -/* reuse GL_UNIFORM_BLOCK_DATA_SIZE */ -/* reuse GL_UNIFORM_BLOCK_NAME_LENGTH */ -/* reuse GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS */ -/* reuse GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES */ -/* reuse GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER */ -/* reuse GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER */ -/* reuse GL_INVALID_INDEX */ -#endif - -#ifndef GL_VERSION_3_2 -#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 -#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 -#define GL_LINES_ADJACENCY 0x000A -#define GL_LINE_STRIP_ADJACENCY 0x000B -#define GL_TRIANGLES_ADJACENCY 0x000C -#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D -#define GL_PROGRAM_POINT_SIZE 0x8642 -#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 -#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 -#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 -#define GL_GEOMETRY_SHADER 0x8DD9 -#define GL_GEOMETRY_VERTICES_OUT 0x8916 -#define GL_GEOMETRY_INPUT_TYPE 0x8917 -#define GL_GEOMETRY_OUTPUT_TYPE 0x8918 -#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF -#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 -#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 -#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 -#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 -#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 -#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 -#define GL_CONTEXT_PROFILE_MASK 0x9126 -/* reuse GL_MAX_VARYING_COMPONENTS */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER */ -/* Reuse tokens from ARB_depth_clamp */ -/* reuse GL_DEPTH_CLAMP */ -/* Reuse tokens from ARB_draw_elements_base_vertex (none) */ -/* Reuse tokens from ARB_fragment_coord_conventions (none) */ -/* Reuse tokens from ARB_provoking_vertex */ -/* reuse GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION */ -/* reuse GL_FIRST_VERTEX_CONVENTION */ -/* reuse GL_LAST_VERTEX_CONVENTION */ -/* reuse GL_PROVOKING_VERTEX */ -/* Reuse tokens from ARB_seamless_cube_map */ -/* reuse GL_TEXTURE_CUBE_MAP_SEAMLESS */ -/* Reuse tokens from ARB_sync */ -/* reuse GL_MAX_SERVER_WAIT_TIMEOUT */ -/* reuse GL_OBJECT_TYPE */ -/* reuse GL_SYNC_CONDITION */ -/* reuse GL_SYNC_STATUS */ -/* reuse GL_SYNC_FLAGS */ -/* reuse GL_SYNC_FENCE */ -/* reuse GL_SYNC_GPU_COMMANDS_COMPLETE */ -/* reuse GL_UNSIGNALED */ -/* reuse GL_SIGNALED */ -/* reuse GL_ALREADY_SIGNALED */ -/* reuse GL_TIMEOUT_EXPIRED */ -/* reuse GL_CONDITION_SATISFIED */ -/* reuse GL_WAIT_FAILED */ -/* reuse GL_TIMEOUT_IGNORED */ -/* reuse GL_SYNC_FLUSH_COMMANDS_BIT */ -/* reuse GL_TIMEOUT_IGNORED */ -/* Reuse tokens from ARB_texture_multisample */ -/* reuse GL_SAMPLE_POSITION */ -/* reuse GL_SAMPLE_MASK */ -/* reuse GL_SAMPLE_MASK_VALUE */ -/* reuse GL_MAX_SAMPLE_MASK_WORDS */ -/* reuse GL_TEXTURE_2D_MULTISAMPLE */ -/* reuse GL_PROXY_TEXTURE_2D_MULTISAMPLE */ -/* reuse GL_TEXTURE_2D_MULTISAMPLE_ARRAY */ -/* reuse GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY */ -/* reuse GL_TEXTURE_BINDING_2D_MULTISAMPLE */ -/* reuse GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY */ -/* reuse GL_TEXTURE_SAMPLES */ -/* reuse GL_TEXTURE_FIXED_SAMPLE_LOCATIONS */ -/* reuse GL_SAMPLER_2D_MULTISAMPLE */ -/* reuse GL_INT_SAMPLER_2D_MULTISAMPLE */ -/* reuse GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE */ -/* reuse GL_SAMPLER_2D_MULTISAMPLE_ARRAY */ -/* reuse GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY */ -/* reuse GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY */ -/* reuse GL_MAX_COLOR_TEXTURE_SAMPLES */ -/* reuse GL_MAX_DEPTH_TEXTURE_SAMPLES */ -/* reuse GL_MAX_INTEGER_SAMPLES */ -/* Don't need to reuse tokens from ARB_vertex_array_bgra since they're already in 1.2 core */ -#endif - -#ifndef GL_VERSION_3_3 -#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE -/* Reuse tokens from ARB_blend_func_extended */ -/* reuse GL_SRC1_COLOR */ -/* reuse GL_ONE_MINUS_SRC1_COLOR */ -/* reuse GL_ONE_MINUS_SRC1_ALPHA */ -/* reuse GL_MAX_DUAL_SOURCE_DRAW_BUFFERS */ -/* Reuse tokens from ARB_explicit_attrib_location (none) */ -/* Reuse tokens from ARB_occlusion_query2 */ -/* reuse GL_ANY_SAMPLES_PASSED */ -/* Reuse tokens from ARB_sampler_objects */ -/* reuse GL_SAMPLER_BINDING */ -/* Reuse tokens from ARB_shader_bit_encoding (none) */ -/* Reuse tokens from ARB_texture_rgb10_a2ui */ -/* reuse GL_RGB10_A2UI */ -/* Reuse tokens from ARB_texture_swizzle */ -/* reuse GL_TEXTURE_SWIZZLE_R */ -/* reuse GL_TEXTURE_SWIZZLE_G */ -/* reuse GL_TEXTURE_SWIZZLE_B */ -/* reuse GL_TEXTURE_SWIZZLE_A */ -/* reuse GL_TEXTURE_SWIZZLE_RGBA */ -/* Reuse tokens from ARB_timer_query */ -/* reuse GL_TIME_ELAPSED */ -/* reuse GL_TIMESTAMP */ -/* Reuse tokens from ARB_vertex_type_2_10_10_10_rev */ -/* reuse GL_INT_2_10_10_10_REV */ -#endif - -#ifndef GL_VERSION_4_0 -#define GL_SAMPLE_SHADING 0x8C36 -#define GL_MIN_SAMPLE_SHADING_VALUE 0x8C37 -#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E -#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F -#define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009 -#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A -#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY 0x900B -#define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C -#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D -#define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E -#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F -/* Reuse tokens from ARB_texture_query_lod (none) */ -/* Reuse tokens from ARB_draw_buffers_blend (none) */ -/* Reuse tokens from ARB_draw_indirect */ -/* reuse GL_DRAW_INDIRECT_BUFFER */ -/* reuse GL_DRAW_INDIRECT_BUFFER_BINDING */ -/* Reuse tokens from ARB_gpu_shader5 */ -/* reuse GL_GEOMETRY_SHADER_INVOCATIONS */ -/* reuse GL_MAX_GEOMETRY_SHADER_INVOCATIONS */ -/* reuse GL_MIN_FRAGMENT_INTERPOLATION_OFFSET */ -/* reuse GL_MAX_FRAGMENT_INTERPOLATION_OFFSET */ -/* reuse GL_FRAGMENT_INTERPOLATION_OFFSET_BITS */ -/* reuse GL_MAX_VERTEX_STREAMS */ -/* Reuse tokens from ARB_gpu_shader_fp64 */ -/* reuse GL_DOUBLE_VEC2 */ -/* reuse GL_DOUBLE_VEC3 */ -/* reuse GL_DOUBLE_VEC4 */ -/* reuse GL_DOUBLE_MAT2 */ -/* reuse GL_DOUBLE_MAT3 */ -/* reuse GL_DOUBLE_MAT4 */ -/* reuse GL_DOUBLE_MAT2x3 */ -/* reuse GL_DOUBLE_MAT2x4 */ -/* reuse GL_DOUBLE_MAT3x2 */ -/* reuse GL_DOUBLE_MAT3x4 */ -/* reuse GL_DOUBLE_MAT4x2 */ -/* reuse GL_DOUBLE_MAT4x3 */ -/* Reuse tokens from ARB_shader_subroutine */ -/* reuse GL_ACTIVE_SUBROUTINES */ -/* reuse GL_ACTIVE_SUBROUTINE_UNIFORMS */ -/* reuse GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS */ -/* reuse GL_ACTIVE_SUBROUTINE_MAX_LENGTH */ -/* reuse GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH */ -/* reuse GL_MAX_SUBROUTINES */ -/* reuse GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS */ -/* reuse GL_NUM_COMPATIBLE_SUBROUTINES */ -/* reuse GL_COMPATIBLE_SUBROUTINES */ -/* Reuse tokens from ARB_tessellation_shader */ -/* reuse GL_PATCHES */ -/* reuse GL_PATCH_VERTICES */ -/* reuse GL_PATCH_DEFAULT_INNER_LEVEL */ -/* reuse GL_PATCH_DEFAULT_OUTER_LEVEL */ -/* reuse GL_TESS_CONTROL_OUTPUT_VERTICES */ -/* reuse GL_TESS_GEN_MODE */ -/* reuse GL_TESS_GEN_SPACING */ -/* reuse GL_TESS_GEN_VERTEX_ORDER */ -/* reuse GL_TESS_GEN_POINT_MODE */ -/* reuse GL_ISOLINES */ -/* reuse GL_FRACTIONAL_ODD */ -/* reuse GL_FRACTIONAL_EVEN */ -/* reuse GL_MAX_PATCH_VERTICES */ -/* reuse GL_MAX_TESS_GEN_LEVEL */ -/* reuse GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS */ -/* reuse GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS */ -/* reuse GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS */ -/* reuse GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS */ -/* reuse GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS */ -/* reuse GL_MAX_TESS_PATCH_COMPONENTS */ -/* reuse GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS */ -/* reuse GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS */ -/* reuse GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS */ -/* reuse GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS */ -/* reuse GL_MAX_TESS_CONTROL_INPUT_COMPONENTS */ -/* reuse GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS */ -/* reuse GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS */ -/* reuse GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS */ -/* reuse GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER */ -/* reuse GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER */ -/* reuse GL_TESS_EVALUATION_SHADER */ -/* reuse GL_TESS_CONTROL_SHADER */ -/* Reuse tokens from ARB_texture_buffer_object_rgb32 (none) */ -/* Reuse tokens from ARB_transform_feedback2 */ -/* reuse GL_TRANSFORM_FEEDBACK */ -/* reuse GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED */ -/* reuse GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE */ -/* reuse GL_TRANSFORM_FEEDBACK_BINDING */ -/* Reuse tokens from ARB_transform_feedback3 */ -/* reuse GL_MAX_TRANSFORM_FEEDBACK_BUFFERS */ -/* reuse GL_MAX_VERTEX_STREAMS */ -#endif - -#ifndef GL_VERSION_4_1 -/* Reuse tokens from ARB_ES2_compatibility */ -/* reuse GL_FIXED */ -/* reuse GL_IMPLEMENTATION_COLOR_READ_TYPE */ -/* reuse GL_IMPLEMENTATION_COLOR_READ_FORMAT */ -/* reuse GL_LOW_FLOAT */ -/* reuse GL_MEDIUM_FLOAT */ -/* reuse GL_HIGH_FLOAT */ -/* reuse GL_LOW_INT */ -/* reuse GL_MEDIUM_INT */ -/* reuse GL_HIGH_INT */ -/* reuse GL_SHADER_COMPILER */ -/* reuse GL_NUM_SHADER_BINARY_FORMATS */ -/* reuse GL_MAX_VERTEX_UNIFORM_VECTORS */ -/* reuse GL_MAX_VARYING_VECTORS */ -/* reuse GL_MAX_FRAGMENT_UNIFORM_VECTORS */ -/* Reuse tokens from ARB_get_program_binary */ -/* reuse GL_PROGRAM_BINARY_RETRIEVABLE_HINT */ -/* reuse GL_PROGRAM_BINARY_LENGTH */ -/* reuse GL_NUM_PROGRAM_BINARY_FORMATS */ -/* reuse GL_PROGRAM_BINARY_FORMATS */ -/* Reuse tokens from ARB_separate_shader_objects */ -/* reuse GL_VERTEX_SHADER_BIT */ -/* reuse GL_FRAGMENT_SHADER_BIT */ -/* reuse GL_GEOMETRY_SHADER_BIT */ -/* reuse GL_TESS_CONTROL_SHADER_BIT */ -/* reuse GL_TESS_EVALUATION_SHADER_BIT */ -/* reuse GL_ALL_SHADER_BITS */ -/* reuse GL_PROGRAM_SEPARABLE */ -/* reuse GL_ACTIVE_PROGRAM */ -/* reuse GL_PROGRAM_PIPELINE_BINDING */ -/* Reuse tokens from ARB_shader_precision (none) */ -/* Reuse tokens from ARB_vertex_attrib_64bit - all are in GL 3.0 and 4.0 already */ -/* Reuse tokens from ARB_viewport_array - some are in GL 1.1 and ARB_provoking_vertex already */ -/* reuse GL_MAX_VIEWPORTS */ -/* reuse GL_VIEWPORT_SUBPIXEL_BITS */ -/* reuse GL_VIEWPORT_BOUNDS_RANGE */ -/* reuse GL_LAYER_PROVOKING_VERTEX */ -/* reuse GL_VIEWPORT_INDEX_PROVOKING_VERTEX */ -/* reuse GL_UNDEFINED_VERTEX */ -#endif - -#ifndef GL_VERSION_4_2 -/* Reuse tokens from ARB_base_instance (none) */ -/* Reuse tokens from ARB_shading_language_420pack (none) */ -/* Reuse tokens from ARB_transform_feedback_instanced (none) */ -/* Reuse tokens from ARB_compressed_texture_pixel_storage */ -/* reuse GL_UNPACK_COMPRESSED_BLOCK_WIDTH */ -/* reuse GL_UNPACK_COMPRESSED_BLOCK_HEIGHT */ -/* reuse GL_UNPACK_COMPRESSED_BLOCK_DEPTH */ -/* reuse GL_UNPACK_COMPRESSED_BLOCK_SIZE */ -/* reuse GL_PACK_COMPRESSED_BLOCK_WIDTH */ -/* reuse GL_PACK_COMPRESSED_BLOCK_HEIGHT */ -/* reuse GL_PACK_COMPRESSED_BLOCK_DEPTH */ -/* reuse GL_PACK_COMPRESSED_BLOCK_SIZE */ -/* Reuse tokens from ARB_conservative_depth (none) */ -/* Reuse tokens from ARB_internalformat_query */ -/* reuse GL_NUM_SAMPLE_COUNTS */ -/* Reuse tokens from ARB_map_buffer_alignment */ -/* reuse GL_MIN_MAP_BUFFER_ALIGNMENT */ -/* Reuse tokens from ARB_shader_atomic_counters */ -/* reuse GL_ATOMIC_COUNTER_BUFFER */ -/* reuse GL_ATOMIC_COUNTER_BUFFER_BINDING */ -/* reuse GL_ATOMIC_COUNTER_BUFFER_START */ -/* reuse GL_ATOMIC_COUNTER_BUFFER_SIZE */ -/* reuse GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE */ -/* reuse GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS */ -/* reuse GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES */ -/* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER */ -/* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER */ -/* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER */ -/* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER */ -/* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER */ -/* reuse GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS */ -/* reuse GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS */ -/* reuse GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS */ -/* reuse GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS */ -/* reuse GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS */ -/* reuse GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS */ -/* reuse GL_MAX_VERTEX_ATOMIC_COUNTERS */ -/* reuse GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS */ -/* reuse GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS */ -/* reuse GL_MAX_GEOMETRY_ATOMIC_COUNTERS */ -/* reuse GL_MAX_FRAGMENT_ATOMIC_COUNTERS */ -/* reuse GL_MAX_COMBINED_ATOMIC_COUNTERS */ -/* reuse GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE */ -/* reuse GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS */ -/* reuse GL_ACTIVE_ATOMIC_COUNTER_BUFFERS */ -/* reuse GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX */ -/* reuse GL_UNSIGNED_INT_ATOMIC_COUNTER */ -/* Reuse tokens from ARB_shader_image_load_store */ -/* reuse GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT */ -/* reuse GL_ELEMENT_ARRAY_BARRIER_BIT */ -/* reuse GL_UNIFORM_BARRIER_BIT */ -/* reuse GL_TEXTURE_FETCH_BARRIER_BIT */ -/* reuse GL_SHADER_IMAGE_ACCESS_BARRIER_BIT */ -/* reuse GL_COMMAND_BARRIER_BIT */ -/* reuse GL_PIXEL_BUFFER_BARRIER_BIT */ -/* reuse GL_TEXTURE_UPDATE_BARRIER_BIT */ -/* reuse GL_BUFFER_UPDATE_BARRIER_BIT */ -/* reuse GL_FRAMEBUFFER_BARRIER_BIT */ -/* reuse GL_TRANSFORM_FEEDBACK_BARRIER_BIT */ -/* reuse GL_ATOMIC_COUNTER_BARRIER_BIT */ -/* reuse GL_ALL_BARRIER_BITS */ -/* reuse GL_MAX_IMAGE_UNITS */ -/* reuse GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS */ -/* reuse GL_IMAGE_BINDING_NAME */ -/* reuse GL_IMAGE_BINDING_LEVEL */ -/* reuse GL_IMAGE_BINDING_LAYERED */ -/* reuse GL_IMAGE_BINDING_LAYER */ -/* reuse GL_IMAGE_BINDING_ACCESS */ -/* reuse GL_IMAGE_1D */ -/* reuse GL_IMAGE_2D */ -/* reuse GL_IMAGE_3D */ -/* reuse GL_IMAGE_2D_RECT */ -/* reuse GL_IMAGE_CUBE */ -/* reuse GL_IMAGE_BUFFER */ -/* reuse GL_IMAGE_1D_ARRAY */ -/* reuse GL_IMAGE_2D_ARRAY */ -/* reuse GL_IMAGE_CUBE_MAP_ARRAY */ -/* reuse GL_IMAGE_2D_MULTISAMPLE */ -/* reuse GL_IMAGE_2D_MULTISAMPLE_ARRAY */ -/* reuse GL_INT_IMAGE_1D */ -/* reuse GL_INT_IMAGE_2D */ -/* reuse GL_INT_IMAGE_3D */ -/* reuse GL_INT_IMAGE_2D_RECT */ -/* reuse GL_INT_IMAGE_CUBE */ -/* reuse GL_INT_IMAGE_BUFFER */ -/* reuse GL_INT_IMAGE_1D_ARRAY */ -/* reuse GL_INT_IMAGE_2D_ARRAY */ -/* reuse GL_INT_IMAGE_CUBE_MAP_ARRAY */ -/* reuse GL_INT_IMAGE_2D_MULTISAMPLE */ -/* reuse GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY */ -/* reuse GL_UNSIGNED_INT_IMAGE_1D */ -/* reuse GL_UNSIGNED_INT_IMAGE_2D */ -/* reuse GL_UNSIGNED_INT_IMAGE_3D */ -/* reuse GL_UNSIGNED_INT_IMAGE_2D_RECT */ -/* reuse GL_UNSIGNED_INT_IMAGE_CUBE */ -/* reuse GL_UNSIGNED_INT_IMAGE_BUFFER */ -/* reuse GL_UNSIGNED_INT_IMAGE_1D_ARRAY */ -/* reuse GL_UNSIGNED_INT_IMAGE_2D_ARRAY */ -/* reuse GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY */ -/* reuse GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE */ -/* reuse GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY */ -/* reuse GL_MAX_IMAGE_SAMPLES */ -/* reuse GL_IMAGE_BINDING_FORMAT */ -/* reuse GL_IMAGE_FORMAT_COMPATIBILITY_TYPE */ -/* reuse GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE */ -/* reuse GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS */ -/* reuse GL_MAX_VERTEX_IMAGE_UNIFORMS */ -/* reuse GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS */ -/* reuse GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS */ -/* reuse GL_MAX_GEOMETRY_IMAGE_UNIFORMS */ -/* reuse GL_MAX_FRAGMENT_IMAGE_UNIFORMS */ -/* reuse GL_MAX_COMBINED_IMAGE_UNIFORMS */ -/* Reuse tokens from ARB_shading_language_packing (none) */ -/* Reuse tokens from ARB_texture_storage */ -/* reuse GL_TEXTURE_IMMUTABLE_FORMAT */ -#endif - -#ifndef GL_ARB_multitexture -#define GL_TEXTURE0_ARB 0x84C0 -#define GL_TEXTURE1_ARB 0x84C1 -#define GL_TEXTURE2_ARB 0x84C2 -#define GL_TEXTURE3_ARB 0x84C3 -#define GL_TEXTURE4_ARB 0x84C4 -#define GL_TEXTURE5_ARB 0x84C5 -#define GL_TEXTURE6_ARB 0x84C6 -#define GL_TEXTURE7_ARB 0x84C7 -#define GL_TEXTURE8_ARB 0x84C8 -#define GL_TEXTURE9_ARB 0x84C9 -#define GL_TEXTURE10_ARB 0x84CA -#define GL_TEXTURE11_ARB 0x84CB -#define GL_TEXTURE12_ARB 0x84CC -#define GL_TEXTURE13_ARB 0x84CD -#define GL_TEXTURE14_ARB 0x84CE -#define GL_TEXTURE15_ARB 0x84CF -#define GL_TEXTURE16_ARB 0x84D0 -#define GL_TEXTURE17_ARB 0x84D1 -#define GL_TEXTURE18_ARB 0x84D2 -#define GL_TEXTURE19_ARB 0x84D3 -#define GL_TEXTURE20_ARB 0x84D4 -#define GL_TEXTURE21_ARB 0x84D5 -#define GL_TEXTURE22_ARB 0x84D6 -#define GL_TEXTURE23_ARB 0x84D7 -#define GL_TEXTURE24_ARB 0x84D8 -#define GL_TEXTURE25_ARB 0x84D9 -#define GL_TEXTURE26_ARB 0x84DA -#define GL_TEXTURE27_ARB 0x84DB -#define GL_TEXTURE28_ARB 0x84DC -#define GL_TEXTURE29_ARB 0x84DD -#define GL_TEXTURE30_ARB 0x84DE -#define GL_TEXTURE31_ARB 0x84DF -#define GL_ACTIVE_TEXTURE_ARB 0x84E0 -#define GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1 -#define GL_MAX_TEXTURE_UNITS_ARB 0x84E2 -#endif - -#ifndef GL_ARB_transpose_matrix -#define GL_TRANSPOSE_MODELVIEW_MATRIX_ARB 0x84E3 -#define GL_TRANSPOSE_PROJECTION_MATRIX_ARB 0x84E4 -#define GL_TRANSPOSE_TEXTURE_MATRIX_ARB 0x84E5 -#define GL_TRANSPOSE_COLOR_MATRIX_ARB 0x84E6 -#endif - -#ifndef GL_ARB_multisample -#define GL_MULTISAMPLE_ARB 0x809D -#define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E -#define GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F -#define GL_SAMPLE_COVERAGE_ARB 0x80A0 -#define GL_SAMPLE_BUFFERS_ARB 0x80A8 -#define GL_SAMPLES_ARB 0x80A9 -#define GL_SAMPLE_COVERAGE_VALUE_ARB 0x80AA -#define GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB -#define GL_MULTISAMPLE_BIT_ARB 0x20000000 -#endif - -#ifndef GL_ARB_texture_env_add -#endif - -#ifndef GL_ARB_texture_cube_map -#define GL_NORMAL_MAP_ARB 0x8511 -#define GL_REFLECTION_MAP_ARB 0x8512 -#define GL_TEXTURE_CUBE_MAP_ARB 0x8513 -#define GL_TEXTURE_BINDING_CUBE_MAP_ARB 0x8514 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x8515 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x8516 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x8517 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x8518 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x8519 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x851A -#define GL_PROXY_TEXTURE_CUBE_MAP_ARB 0x851B -#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB 0x851C -#endif - -#ifndef GL_ARB_texture_compression -#define GL_COMPRESSED_ALPHA_ARB 0x84E9 -#define GL_COMPRESSED_LUMINANCE_ARB 0x84EA -#define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB -#define GL_COMPRESSED_INTENSITY_ARB 0x84EC -#define GL_COMPRESSED_RGB_ARB 0x84ED -#define GL_COMPRESSED_RGBA_ARB 0x84EE -#define GL_TEXTURE_COMPRESSION_HINT_ARB 0x84EF -#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0 -#define GL_TEXTURE_COMPRESSED_ARB 0x86A1 -#define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2 -#define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3 -#endif - -#ifndef GL_ARB_texture_border_clamp -#define GL_CLAMP_TO_BORDER_ARB 0x812D -#endif - -#ifndef GL_ARB_point_parameters -#define GL_POINT_SIZE_MIN_ARB 0x8126 -#define GL_POINT_SIZE_MAX_ARB 0x8127 -#define GL_POINT_FADE_THRESHOLD_SIZE_ARB 0x8128 -#define GL_POINT_DISTANCE_ATTENUATION_ARB 0x8129 -#endif - -#ifndef GL_ARB_vertex_blend -#define GL_MAX_VERTEX_UNITS_ARB 0x86A4 -#define GL_ACTIVE_VERTEX_UNITS_ARB 0x86A5 -#define GL_WEIGHT_SUM_UNITY_ARB 0x86A6 -#define GL_VERTEX_BLEND_ARB 0x86A7 -#define GL_CURRENT_WEIGHT_ARB 0x86A8 -#define GL_WEIGHT_ARRAY_TYPE_ARB 0x86A9 -#define GL_WEIGHT_ARRAY_STRIDE_ARB 0x86AA -#define GL_WEIGHT_ARRAY_SIZE_ARB 0x86AB -#define GL_WEIGHT_ARRAY_POINTER_ARB 0x86AC -#define GL_WEIGHT_ARRAY_ARB 0x86AD -#define GL_MODELVIEW0_ARB 0x1700 -#define GL_MODELVIEW1_ARB 0x850A -#define GL_MODELVIEW2_ARB 0x8722 -#define GL_MODELVIEW3_ARB 0x8723 -#define GL_MODELVIEW4_ARB 0x8724 -#define GL_MODELVIEW5_ARB 0x8725 -#define GL_MODELVIEW6_ARB 0x8726 -#define GL_MODELVIEW7_ARB 0x8727 -#define GL_MODELVIEW8_ARB 0x8728 -#define GL_MODELVIEW9_ARB 0x8729 -#define GL_MODELVIEW10_ARB 0x872A -#define GL_MODELVIEW11_ARB 0x872B -#define GL_MODELVIEW12_ARB 0x872C -#define GL_MODELVIEW13_ARB 0x872D -#define GL_MODELVIEW14_ARB 0x872E -#define GL_MODELVIEW15_ARB 0x872F -#define GL_MODELVIEW16_ARB 0x8730 -#define GL_MODELVIEW17_ARB 0x8731 -#define GL_MODELVIEW18_ARB 0x8732 -#define GL_MODELVIEW19_ARB 0x8733 -#define GL_MODELVIEW20_ARB 0x8734 -#define GL_MODELVIEW21_ARB 0x8735 -#define GL_MODELVIEW22_ARB 0x8736 -#define GL_MODELVIEW23_ARB 0x8737 -#define GL_MODELVIEW24_ARB 0x8738 -#define GL_MODELVIEW25_ARB 0x8739 -#define GL_MODELVIEW26_ARB 0x873A -#define GL_MODELVIEW27_ARB 0x873B -#define GL_MODELVIEW28_ARB 0x873C -#define GL_MODELVIEW29_ARB 0x873D -#define GL_MODELVIEW30_ARB 0x873E -#define GL_MODELVIEW31_ARB 0x873F -#endif - -#ifndef GL_ARB_matrix_palette -#define GL_MATRIX_PALETTE_ARB 0x8840 -#define GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB 0x8841 -#define GL_MAX_PALETTE_MATRICES_ARB 0x8842 -#define GL_CURRENT_PALETTE_MATRIX_ARB 0x8843 -#define GL_MATRIX_INDEX_ARRAY_ARB 0x8844 -#define GL_CURRENT_MATRIX_INDEX_ARB 0x8845 -#define GL_MATRIX_INDEX_ARRAY_SIZE_ARB 0x8846 -#define GL_MATRIX_INDEX_ARRAY_TYPE_ARB 0x8847 -#define GL_MATRIX_INDEX_ARRAY_STRIDE_ARB 0x8848 -#define GL_MATRIX_INDEX_ARRAY_POINTER_ARB 0x8849 -#endif - -#ifndef GL_ARB_texture_env_combine -#define GL_COMBINE_ARB 0x8570 -#define GL_COMBINE_RGB_ARB 0x8571 -#define GL_COMBINE_ALPHA_ARB 0x8572 -#define GL_SOURCE0_RGB_ARB 0x8580 -#define GL_SOURCE1_RGB_ARB 0x8581 -#define GL_SOURCE2_RGB_ARB 0x8582 -#define GL_SOURCE0_ALPHA_ARB 0x8588 -#define GL_SOURCE1_ALPHA_ARB 0x8589 -#define GL_SOURCE2_ALPHA_ARB 0x858A -#define GL_OPERAND0_RGB_ARB 0x8590 -#define GL_OPERAND1_RGB_ARB 0x8591 -#define GL_OPERAND2_RGB_ARB 0x8592 -#define GL_OPERAND0_ALPHA_ARB 0x8598 -#define GL_OPERAND1_ALPHA_ARB 0x8599 -#define GL_OPERAND2_ALPHA_ARB 0x859A -#define GL_RGB_SCALE_ARB 0x8573 -#define GL_ADD_SIGNED_ARB 0x8574 -#define GL_INTERPOLATE_ARB 0x8575 -#define GL_SUBTRACT_ARB 0x84E7 -#define GL_CONSTANT_ARB 0x8576 -#define GL_PRIMARY_COLOR_ARB 0x8577 -#define GL_PREVIOUS_ARB 0x8578 -#endif - -#ifndef GL_ARB_texture_env_crossbar -#endif - -#ifndef GL_ARB_texture_env_dot3 -#define GL_DOT3_RGB_ARB 0x86AE -#define GL_DOT3_RGBA_ARB 0x86AF -#endif - -#ifndef GL_ARB_texture_mirrored_repeat -#define GL_MIRRORED_REPEAT_ARB 0x8370 -#endif - -#ifndef GL_ARB_depth_texture -#define GL_DEPTH_COMPONENT16_ARB 0x81A5 -#define GL_DEPTH_COMPONENT24_ARB 0x81A6 -#define GL_DEPTH_COMPONENT32_ARB 0x81A7 -#define GL_TEXTURE_DEPTH_SIZE_ARB 0x884A -#define GL_DEPTH_TEXTURE_MODE_ARB 0x884B -#endif - -#ifndef GL_ARB_shadow -#define GL_TEXTURE_COMPARE_MODE_ARB 0x884C -#define GL_TEXTURE_COMPARE_FUNC_ARB 0x884D -#define GL_COMPARE_R_TO_TEXTURE_ARB 0x884E -#endif - -#ifndef GL_ARB_shadow_ambient -#define GL_TEXTURE_COMPARE_FAIL_VALUE_ARB 0x80BF -#endif - -#ifndef GL_ARB_window_pos -#endif - -#ifndef GL_ARB_vertex_program -#define GL_COLOR_SUM_ARB 0x8458 -#define GL_VERTEX_PROGRAM_ARB 0x8620 -#define GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622 -#define GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB 0x8623 -#define GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624 -#define GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB 0x8625 -#define GL_CURRENT_VERTEX_ATTRIB_ARB 0x8626 -#define GL_PROGRAM_LENGTH_ARB 0x8627 -#define GL_PROGRAM_STRING_ARB 0x8628 -#define GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB 0x862E -#define GL_MAX_PROGRAM_MATRICES_ARB 0x862F -#define GL_CURRENT_MATRIX_STACK_DEPTH_ARB 0x8640 -#define GL_CURRENT_MATRIX_ARB 0x8641 -#define GL_VERTEX_PROGRAM_POINT_SIZE_ARB 0x8642 -#define GL_VERTEX_PROGRAM_TWO_SIDE_ARB 0x8643 -#define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645 -#define GL_PROGRAM_ERROR_POSITION_ARB 0x864B -#define GL_PROGRAM_BINDING_ARB 0x8677 -#define GL_MAX_VERTEX_ATTRIBS_ARB 0x8869 -#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A -#define GL_PROGRAM_ERROR_STRING_ARB 0x8874 -#define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875 -#define GL_PROGRAM_FORMAT_ARB 0x8876 -#define GL_PROGRAM_INSTRUCTIONS_ARB 0x88A0 -#define GL_MAX_PROGRAM_INSTRUCTIONS_ARB 0x88A1 -#define GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A2 -#define GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A3 -#define GL_PROGRAM_TEMPORARIES_ARB 0x88A4 -#define GL_MAX_PROGRAM_TEMPORARIES_ARB 0x88A5 -#define GL_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A6 -#define GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A7 -#define GL_PROGRAM_PARAMETERS_ARB 0x88A8 -#define GL_MAX_PROGRAM_PARAMETERS_ARB 0x88A9 -#define GL_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AA -#define GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AB -#define GL_PROGRAM_ATTRIBS_ARB 0x88AC -#define GL_MAX_PROGRAM_ATTRIBS_ARB 0x88AD -#define GL_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AE -#define GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AF -#define GL_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B0 -#define GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B1 -#define GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B2 -#define GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B3 -#define GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB 0x88B4 -#define GL_MAX_PROGRAM_ENV_PARAMETERS_ARB 0x88B5 -#define GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB 0x88B6 -#define GL_TRANSPOSE_CURRENT_MATRIX_ARB 0x88B7 -#define GL_MATRIX0_ARB 0x88C0 -#define GL_MATRIX1_ARB 0x88C1 -#define GL_MATRIX2_ARB 0x88C2 -#define GL_MATRIX3_ARB 0x88C3 -#define GL_MATRIX4_ARB 0x88C4 -#define GL_MATRIX5_ARB 0x88C5 -#define GL_MATRIX6_ARB 0x88C6 -#define GL_MATRIX7_ARB 0x88C7 -#define GL_MATRIX8_ARB 0x88C8 -#define GL_MATRIX9_ARB 0x88C9 -#define GL_MATRIX10_ARB 0x88CA -#define GL_MATRIX11_ARB 0x88CB -#define GL_MATRIX12_ARB 0x88CC -#define GL_MATRIX13_ARB 0x88CD -#define GL_MATRIX14_ARB 0x88CE -#define GL_MATRIX15_ARB 0x88CF -#define GL_MATRIX16_ARB 0x88D0 -#define GL_MATRIX17_ARB 0x88D1 -#define GL_MATRIX18_ARB 0x88D2 -#define GL_MATRIX19_ARB 0x88D3 -#define GL_MATRIX20_ARB 0x88D4 -#define GL_MATRIX21_ARB 0x88D5 -#define GL_MATRIX22_ARB 0x88D6 -#define GL_MATRIX23_ARB 0x88D7 -#define GL_MATRIX24_ARB 0x88D8 -#define GL_MATRIX25_ARB 0x88D9 -#define GL_MATRIX26_ARB 0x88DA -#define GL_MATRIX27_ARB 0x88DB -#define GL_MATRIX28_ARB 0x88DC -#define GL_MATRIX29_ARB 0x88DD -#define GL_MATRIX30_ARB 0x88DE -#define GL_MATRIX31_ARB 0x88DF -#endif - -#ifndef GL_ARB_fragment_program -#define GL_FRAGMENT_PROGRAM_ARB 0x8804 -#define GL_PROGRAM_ALU_INSTRUCTIONS_ARB 0x8805 -#define GL_PROGRAM_TEX_INSTRUCTIONS_ARB 0x8806 -#define GL_PROGRAM_TEX_INDIRECTIONS_ARB 0x8807 -#define GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808 -#define GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809 -#define GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A -#define GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B -#define GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C -#define GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D -#define GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E -#define GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F -#define GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810 -#define GL_MAX_TEXTURE_COORDS_ARB 0x8871 -#define GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872 -#endif - -#ifndef GL_ARB_vertex_buffer_object -#define GL_BUFFER_SIZE_ARB 0x8764 -#define GL_BUFFER_USAGE_ARB 0x8765 -#define GL_ARRAY_BUFFER_ARB 0x8892 -#define GL_ELEMENT_ARRAY_BUFFER_ARB 0x8893 -#define GL_ARRAY_BUFFER_BINDING_ARB 0x8894 -#define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895 -#define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896 -#define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897 -#define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898 -#define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899 -#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A -#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B -#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C -#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D -#define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E -#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F -#define GL_READ_ONLY_ARB 0x88B8 -#define GL_WRITE_ONLY_ARB 0x88B9 -#define GL_READ_WRITE_ARB 0x88BA -#define GL_BUFFER_ACCESS_ARB 0x88BB -#define GL_BUFFER_MAPPED_ARB 0x88BC -#define GL_BUFFER_MAP_POINTER_ARB 0x88BD -#define GL_STREAM_DRAW_ARB 0x88E0 -#define GL_STREAM_READ_ARB 0x88E1 -#define GL_STREAM_COPY_ARB 0x88E2 -#define GL_STATIC_DRAW_ARB 0x88E4 -#define GL_STATIC_READ_ARB 0x88E5 -#define GL_STATIC_COPY_ARB 0x88E6 -#define GL_DYNAMIC_DRAW_ARB 0x88E8 -#define GL_DYNAMIC_READ_ARB 0x88E9 -#define GL_DYNAMIC_COPY_ARB 0x88EA -#endif - -#ifndef GL_ARB_occlusion_query -#define GL_QUERY_COUNTER_BITS_ARB 0x8864 -#define GL_CURRENT_QUERY_ARB 0x8865 -#define GL_QUERY_RESULT_ARB 0x8866 -#define GL_QUERY_RESULT_AVAILABLE_ARB 0x8867 -#define GL_SAMPLES_PASSED_ARB 0x8914 -#endif - -#ifndef GL_ARB_shader_objects -#define GL_PROGRAM_OBJECT_ARB 0x8B40 -#define GL_SHADER_OBJECT_ARB 0x8B48 -#define GL_OBJECT_TYPE_ARB 0x8B4E -#define GL_OBJECT_SUBTYPE_ARB 0x8B4F -#define GL_FLOAT_VEC2_ARB 0x8B50 -#define GL_FLOAT_VEC3_ARB 0x8B51 -#define GL_FLOAT_VEC4_ARB 0x8B52 -#define GL_INT_VEC2_ARB 0x8B53 -#define GL_INT_VEC3_ARB 0x8B54 -#define GL_INT_VEC4_ARB 0x8B55 -#define GL_BOOL_ARB 0x8B56 -#define GL_BOOL_VEC2_ARB 0x8B57 -#define GL_BOOL_VEC3_ARB 0x8B58 -#define GL_BOOL_VEC4_ARB 0x8B59 -#define GL_FLOAT_MAT2_ARB 0x8B5A -#define GL_FLOAT_MAT3_ARB 0x8B5B -#define GL_FLOAT_MAT4_ARB 0x8B5C -#define GL_SAMPLER_1D_ARB 0x8B5D -#define GL_SAMPLER_2D_ARB 0x8B5E -#define GL_SAMPLER_3D_ARB 0x8B5F -#define GL_SAMPLER_CUBE_ARB 0x8B60 -#define GL_SAMPLER_1D_SHADOW_ARB 0x8B61 -#define GL_SAMPLER_2D_SHADOW_ARB 0x8B62 -#define GL_SAMPLER_2D_RECT_ARB 0x8B63 -#define GL_SAMPLER_2D_RECT_SHADOW_ARB 0x8B64 -#define GL_OBJECT_DELETE_STATUS_ARB 0x8B80 -#define GL_OBJECT_COMPILE_STATUS_ARB 0x8B81 -#define GL_OBJECT_LINK_STATUS_ARB 0x8B82 -#define GL_OBJECT_VALIDATE_STATUS_ARB 0x8B83 -#define GL_OBJECT_INFO_LOG_LENGTH_ARB 0x8B84 -#define GL_OBJECT_ATTACHED_OBJECTS_ARB 0x8B85 -#define GL_OBJECT_ACTIVE_UNIFORMS_ARB 0x8B86 -#define GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87 -#define GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88 -#endif - -#ifndef GL_ARB_vertex_shader -#define GL_VERTEX_SHADER_ARB 0x8B31 -#define GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A -#define GL_MAX_VARYING_FLOATS_ARB 0x8B4B -#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C -#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D -#define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB 0x8B89 -#define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A -#endif - -#ifndef GL_ARB_fragment_shader -#define GL_FRAGMENT_SHADER_ARB 0x8B30 -#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49 -#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B -#endif - -#ifndef GL_ARB_shading_language_100 -#define GL_SHADING_LANGUAGE_VERSION_ARB 0x8B8C -#endif - -#ifndef GL_ARB_texture_non_power_of_two -#endif - -#ifndef GL_ARB_point_sprite -#define GL_POINT_SPRITE_ARB 0x8861 -#define GL_COORD_REPLACE_ARB 0x8862 -#endif - -#ifndef GL_ARB_fragment_program_shadow -#endif - -#ifndef GL_ARB_draw_buffers -#define GL_MAX_DRAW_BUFFERS_ARB 0x8824 -#define GL_DRAW_BUFFER0_ARB 0x8825 -#define GL_DRAW_BUFFER1_ARB 0x8826 -#define GL_DRAW_BUFFER2_ARB 0x8827 -#define GL_DRAW_BUFFER3_ARB 0x8828 -#define GL_DRAW_BUFFER4_ARB 0x8829 -#define GL_DRAW_BUFFER5_ARB 0x882A -#define GL_DRAW_BUFFER6_ARB 0x882B -#define GL_DRAW_BUFFER7_ARB 0x882C -#define GL_DRAW_BUFFER8_ARB 0x882D -#define GL_DRAW_BUFFER9_ARB 0x882E -#define GL_DRAW_BUFFER10_ARB 0x882F -#define GL_DRAW_BUFFER11_ARB 0x8830 -#define GL_DRAW_BUFFER12_ARB 0x8831 -#define GL_DRAW_BUFFER13_ARB 0x8832 -#define GL_DRAW_BUFFER14_ARB 0x8833 -#define GL_DRAW_BUFFER15_ARB 0x8834 -#endif - -#ifndef GL_ARB_texture_rectangle -#define GL_TEXTURE_RECTANGLE_ARB 0x84F5 -#define GL_TEXTURE_BINDING_RECTANGLE_ARB 0x84F6 -#define GL_PROXY_TEXTURE_RECTANGLE_ARB 0x84F7 -#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8 -#endif - -#ifndef GL_ARB_color_buffer_float -#define GL_RGBA_FLOAT_MODE_ARB 0x8820 -#define GL_CLAMP_VERTEX_COLOR_ARB 0x891A -#define GL_CLAMP_FRAGMENT_COLOR_ARB 0x891B -#define GL_CLAMP_READ_COLOR_ARB 0x891C -#define GL_FIXED_ONLY_ARB 0x891D -#endif - -#ifndef GL_ARB_half_float_pixel -#define GL_HALF_FLOAT_ARB 0x140B -#endif - -#ifndef GL_ARB_texture_float -#define GL_TEXTURE_RED_TYPE_ARB 0x8C10 -#define GL_TEXTURE_GREEN_TYPE_ARB 0x8C11 -#define GL_TEXTURE_BLUE_TYPE_ARB 0x8C12 -#define GL_TEXTURE_ALPHA_TYPE_ARB 0x8C13 -#define GL_TEXTURE_LUMINANCE_TYPE_ARB 0x8C14 -#define GL_TEXTURE_INTENSITY_TYPE_ARB 0x8C15 -#define GL_TEXTURE_DEPTH_TYPE_ARB 0x8C16 -#define GL_UNSIGNED_NORMALIZED_ARB 0x8C17 -#define GL_RGBA32F_ARB 0x8814 -#define GL_RGB32F_ARB 0x8815 -#define GL_ALPHA32F_ARB 0x8816 -#define GL_INTENSITY32F_ARB 0x8817 -#define GL_LUMINANCE32F_ARB 0x8818 -#define GL_LUMINANCE_ALPHA32F_ARB 0x8819 -#define GL_RGBA16F_ARB 0x881A -#define GL_RGB16F_ARB 0x881B -#define GL_ALPHA16F_ARB 0x881C -#define GL_INTENSITY16F_ARB 0x881D -#define GL_LUMINANCE16F_ARB 0x881E -#define GL_LUMINANCE_ALPHA16F_ARB 0x881F -#endif - -#ifndef GL_ARB_pixel_buffer_object -#define GL_PIXEL_PACK_BUFFER_ARB 0x88EB -#define GL_PIXEL_UNPACK_BUFFER_ARB 0x88EC -#define GL_PIXEL_PACK_BUFFER_BINDING_ARB 0x88ED -#define GL_PIXEL_UNPACK_BUFFER_BINDING_ARB 0x88EF -#endif - -#ifndef GL_ARB_depth_buffer_float -#define GL_DEPTH_COMPONENT32F 0x8CAC -#define GL_DEPTH32F_STENCIL8 0x8CAD -#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD -#endif - -#ifndef GL_ARB_draw_instanced -#endif - -#ifndef GL_ARB_framebuffer_object -#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 -#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 -#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 -#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 -#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 -#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 -#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 -#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 -#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 -#define GL_FRAMEBUFFER_DEFAULT 0x8218 -#define GL_FRAMEBUFFER_UNDEFINED 0x8219 -#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A -#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 -#define GL_DEPTH_STENCIL 0x84F9 -#define GL_UNSIGNED_INT_24_8 0x84FA -#define GL_DEPTH24_STENCIL8 0x88F0 -#define GL_TEXTURE_STENCIL_SIZE 0x88F1 -#define GL_TEXTURE_RED_TYPE 0x8C10 -#define GL_TEXTURE_GREEN_TYPE 0x8C11 -#define GL_TEXTURE_BLUE_TYPE 0x8C12 -#define GL_TEXTURE_ALPHA_TYPE 0x8C13 -#define GL_TEXTURE_DEPTH_TYPE 0x8C16 -#define GL_UNSIGNED_NORMALIZED 0x8C17 -#define GL_FRAMEBUFFER_BINDING 0x8CA6 -#define GL_DRAW_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING -#define GL_RENDERBUFFER_BINDING 0x8CA7 -#define GL_READ_FRAMEBUFFER 0x8CA8 -#define GL_DRAW_FRAMEBUFFER 0x8CA9 -#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA -#define GL_RENDERBUFFER_SAMPLES 0x8CAB -#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 -#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 -#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 -#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 -#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 -#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB -#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC -#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD -#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF -#define GL_COLOR_ATTACHMENT0 0x8CE0 -#define GL_COLOR_ATTACHMENT1 0x8CE1 -#define GL_COLOR_ATTACHMENT2 0x8CE2 -#define GL_COLOR_ATTACHMENT3 0x8CE3 -#define GL_COLOR_ATTACHMENT4 0x8CE4 -#define GL_COLOR_ATTACHMENT5 0x8CE5 -#define GL_COLOR_ATTACHMENT6 0x8CE6 -#define GL_COLOR_ATTACHMENT7 0x8CE7 -#define GL_COLOR_ATTACHMENT8 0x8CE8 -#define GL_COLOR_ATTACHMENT9 0x8CE9 -#define GL_COLOR_ATTACHMENT10 0x8CEA -#define GL_COLOR_ATTACHMENT11 0x8CEB -#define GL_COLOR_ATTACHMENT12 0x8CEC -#define GL_COLOR_ATTACHMENT13 0x8CED -#define GL_COLOR_ATTACHMENT14 0x8CEE -#define GL_COLOR_ATTACHMENT15 0x8CEF -#define GL_DEPTH_ATTACHMENT 0x8D00 -#define GL_STENCIL_ATTACHMENT 0x8D20 -#define GL_FRAMEBUFFER 0x8D40 -#define GL_RENDERBUFFER 0x8D41 -#define GL_RENDERBUFFER_WIDTH 0x8D42 -#define GL_RENDERBUFFER_HEIGHT 0x8D43 -#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 -#define GL_STENCIL_INDEX1 0x8D46 -#define GL_STENCIL_INDEX4 0x8D47 -#define GL_STENCIL_INDEX8 0x8D48 -#define GL_STENCIL_INDEX16 0x8D49 -#define GL_RENDERBUFFER_RED_SIZE 0x8D50 -#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 -#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 -#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 -#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 -#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 -#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 -#define GL_MAX_SAMPLES 0x8D57 -#endif - -#ifndef GL_ARB_framebuffer_object_DEPRECATED -#define GL_INDEX 0x8222 -#define GL_TEXTURE_LUMINANCE_TYPE 0x8C14 -#define GL_TEXTURE_INTENSITY_TYPE 0x8C15 -#endif - -#ifndef GL_ARB_framebuffer_sRGB -#define GL_FRAMEBUFFER_SRGB 0x8DB9 -#endif - -#ifndef GL_ARB_geometry_shader4 -#define GL_LINES_ADJACENCY_ARB 0x000A -#define GL_LINE_STRIP_ADJACENCY_ARB 0x000B -#define GL_TRIANGLES_ADJACENCY_ARB 0x000C -#define GL_TRIANGLE_STRIP_ADJACENCY_ARB 0x000D -#define GL_PROGRAM_POINT_SIZE_ARB 0x8642 -#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB 0x8C29 -#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB 0x8DA7 -#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB 0x8DA8 -#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB 0x8DA9 -#define GL_GEOMETRY_SHADER_ARB 0x8DD9 -#define GL_GEOMETRY_VERTICES_OUT_ARB 0x8DDA -#define GL_GEOMETRY_INPUT_TYPE_ARB 0x8DDB -#define GL_GEOMETRY_OUTPUT_TYPE_ARB 0x8DDC -#define GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB 0x8DDD -#define GL_MAX_VERTEX_VARYING_COMPONENTS_ARB 0x8DDE -#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB 0x8DDF -#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB 0x8DE0 -#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB 0x8DE1 -/* reuse GL_MAX_VARYING_COMPONENTS */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER */ -#endif - -#ifndef GL_ARB_half_float_vertex -#define GL_HALF_FLOAT 0x140B -#endif - -#ifndef GL_ARB_instanced_arrays -#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB 0x88FE -#endif - -#ifndef GL_ARB_map_buffer_range -#define GL_MAP_READ_BIT 0x0001 -#define GL_MAP_WRITE_BIT 0x0002 -#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 -#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 -#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 -#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 -#endif - -#ifndef GL_ARB_texture_buffer_object -#define GL_TEXTURE_BUFFER_ARB 0x8C2A -#define GL_MAX_TEXTURE_BUFFER_SIZE_ARB 0x8C2B -#define GL_TEXTURE_BINDING_BUFFER_ARB 0x8C2C -#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_ARB 0x8C2D -#define GL_TEXTURE_BUFFER_FORMAT_ARB 0x8C2E -#endif - -#ifndef GL_ARB_texture_compression_rgtc -#define GL_COMPRESSED_RED_RGTC1 0x8DBB -#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC -#define GL_COMPRESSED_RG_RGTC2 0x8DBD -#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE -#endif - -#ifndef GL_ARB_texture_rg -#define GL_RG 0x8227 -#define GL_RG_INTEGER 0x8228 -#define GL_R8 0x8229 -#define GL_R16 0x822A -#define GL_RG8 0x822B -#define GL_RG16 0x822C -#define GL_R16F 0x822D -#define GL_R32F 0x822E -#define GL_RG16F 0x822F -#define GL_RG32F 0x8230 -#define GL_R8I 0x8231 -#define GL_R8UI 0x8232 -#define GL_R16I 0x8233 -#define GL_R16UI 0x8234 -#define GL_R32I 0x8235 -#define GL_R32UI 0x8236 -#define GL_RG8I 0x8237 -#define GL_RG8UI 0x8238 -#define GL_RG16I 0x8239 -#define GL_RG16UI 0x823A -#define GL_RG32I 0x823B -#define GL_RG32UI 0x823C -#endif - -#ifndef GL_ARB_vertex_array_object -#define GL_VERTEX_ARRAY_BINDING 0x85B5 -#endif - -#ifndef GL_ARB_uniform_buffer_object -#define GL_UNIFORM_BUFFER 0x8A11 -#define GL_UNIFORM_BUFFER_BINDING 0x8A28 -#define GL_UNIFORM_BUFFER_START 0x8A29 -#define GL_UNIFORM_BUFFER_SIZE 0x8A2A -#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B -#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C -#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D -#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E -#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F -#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 -#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 -#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 -#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 -#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 -#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 -#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 -#define GL_UNIFORM_TYPE 0x8A37 -#define GL_UNIFORM_SIZE 0x8A38 -#define GL_UNIFORM_NAME_LENGTH 0x8A39 -#define GL_UNIFORM_BLOCK_INDEX 0x8A3A -#define GL_UNIFORM_OFFSET 0x8A3B -#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C -#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D -#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E -#define GL_UNIFORM_BLOCK_BINDING 0x8A3F -#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 -#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 -#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 -#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 -#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 -#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 -#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 -#define GL_INVALID_INDEX 0xFFFFFFFFu -#endif - -#ifndef GL_ARB_compatibility -/* ARB_compatibility just defines tokens from core 3.0 */ -#endif - -#ifndef GL_ARB_copy_buffer -#define GL_COPY_READ_BUFFER 0x8F36 -#define GL_COPY_WRITE_BUFFER 0x8F37 -#endif - -#ifndef GL_ARB_shader_texture_lod -#endif - -#ifndef GL_ARB_depth_clamp -#define GL_DEPTH_CLAMP 0x864F -#endif - -#ifndef GL_ARB_draw_elements_base_vertex -#endif - -#ifndef GL_ARB_fragment_coord_conventions -#endif - -#ifndef GL_ARB_provoking_vertex -#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C -#define GL_FIRST_VERTEX_CONVENTION 0x8E4D -#define GL_LAST_VERTEX_CONVENTION 0x8E4E -#define GL_PROVOKING_VERTEX 0x8E4F -#endif - -#ifndef GL_ARB_seamless_cube_map -#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F -#endif - -#ifndef GL_ARB_sync -#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 -#define GL_OBJECT_TYPE 0x9112 -#define GL_SYNC_CONDITION 0x9113 -#define GL_SYNC_STATUS 0x9114 -#define GL_SYNC_FLAGS 0x9115 -#define GL_SYNC_FENCE 0x9116 -#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 -#define GL_UNSIGNALED 0x9118 -#define GL_SIGNALED 0x9119 -#define GL_ALREADY_SIGNALED 0x911A -#define GL_TIMEOUT_EXPIRED 0x911B -#define GL_CONDITION_SATISFIED 0x911C -#define GL_WAIT_FAILED 0x911D -#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 -#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull -#endif - -#ifndef GL_ARB_texture_multisample -#define GL_SAMPLE_POSITION 0x8E50 -#define GL_SAMPLE_MASK 0x8E51 -#define GL_SAMPLE_MASK_VALUE 0x8E52 -#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 -#define GL_TEXTURE_2D_MULTISAMPLE 0x9100 -#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 -#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 -#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 -#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 -#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 -#define GL_TEXTURE_SAMPLES 0x9106 -#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 -#define GL_SAMPLER_2D_MULTISAMPLE 0x9108 -#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 -#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A -#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B -#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C -#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D -#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E -#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F -#define GL_MAX_INTEGER_SAMPLES 0x9110 -#endif - -#ifndef GL_ARB_vertex_array_bgra -/* reuse GL_BGRA */ -#endif - -#ifndef GL_ARB_draw_buffers_blend -#endif - -#ifndef GL_ARB_sample_shading -#define GL_SAMPLE_SHADING_ARB 0x8C36 -#define GL_MIN_SAMPLE_SHADING_VALUE_ARB 0x8C37 -#endif - -#ifndef GL_ARB_texture_cube_map_array -#define GL_TEXTURE_CUBE_MAP_ARRAY_ARB 0x9009 -#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_ARB 0x900A -#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY_ARB 0x900B -#define GL_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900C -#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_ARB 0x900D -#define GL_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900E -#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900F -#endif - -#ifndef GL_ARB_texture_gather -#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5E -#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5F -#endif - -#ifndef GL_ARB_texture_query_lod -#endif - -#ifndef GL_ARB_shading_language_include -#define GL_SHADER_INCLUDE_ARB 0x8DAE -#define GL_NAMED_STRING_LENGTH_ARB 0x8DE9 -#define GL_NAMED_STRING_TYPE_ARB 0x8DEA -#endif - -#ifndef GL_ARB_texture_compression_bptc -#define GL_COMPRESSED_RGBA_BPTC_UNORM_ARB 0x8E8C -#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB 0x8E8D -#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB 0x8E8E -#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB 0x8E8F -#endif - -#ifndef GL_ARB_blend_func_extended -#define GL_SRC1_COLOR 0x88F9 -/* reuse GL_SRC1_ALPHA */ -#define GL_ONE_MINUS_SRC1_COLOR 0x88FA -#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB -#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC -#endif - -#ifndef GL_ARB_explicit_attrib_location -#endif - -#ifndef GL_ARB_occlusion_query2 -#define GL_ANY_SAMPLES_PASSED 0x8C2F -#endif - -#ifndef GL_ARB_sampler_objects -#define GL_SAMPLER_BINDING 0x8919 -#endif - -#ifndef GL_ARB_shader_bit_encoding -#endif - -#ifndef GL_ARB_texture_rgb10_a2ui -#define GL_RGB10_A2UI 0x906F -#endif - -#ifndef GL_ARB_texture_swizzle -#define GL_TEXTURE_SWIZZLE_R 0x8E42 -#define GL_TEXTURE_SWIZZLE_G 0x8E43 -#define GL_TEXTURE_SWIZZLE_B 0x8E44 -#define GL_TEXTURE_SWIZZLE_A 0x8E45 -#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 -#endif - -#ifndef GL_ARB_timer_query -#define GL_TIME_ELAPSED 0x88BF -#define GL_TIMESTAMP 0x8E28 -#endif - -#ifndef GL_ARB_vertex_type_2_10_10_10_rev -/* reuse GL_UNSIGNED_INT_2_10_10_10_REV */ -#define GL_INT_2_10_10_10_REV 0x8D9F -#endif - -#ifndef GL_ARB_draw_indirect -#define GL_DRAW_INDIRECT_BUFFER 0x8F3F -#define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43 -#endif - -#ifndef GL_ARB_gpu_shader5 -#define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F -#define GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A -#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B -#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C -#define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D -/* reuse GL_MAX_VERTEX_STREAMS */ -#endif - -#ifndef GL_ARB_gpu_shader_fp64 -/* reuse GL_DOUBLE */ -#define GL_DOUBLE_VEC2 0x8FFC -#define GL_DOUBLE_VEC3 0x8FFD -#define GL_DOUBLE_VEC4 0x8FFE -#define GL_DOUBLE_MAT2 0x8F46 -#define GL_DOUBLE_MAT3 0x8F47 -#define GL_DOUBLE_MAT4 0x8F48 -#define GL_DOUBLE_MAT2x3 0x8F49 -#define GL_DOUBLE_MAT2x4 0x8F4A -#define GL_DOUBLE_MAT3x2 0x8F4B -#define GL_DOUBLE_MAT3x4 0x8F4C -#define GL_DOUBLE_MAT4x2 0x8F4D -#define GL_DOUBLE_MAT4x3 0x8F4E -#endif - -#ifndef GL_ARB_shader_subroutine -#define GL_ACTIVE_SUBROUTINES 0x8DE5 -#define GL_ACTIVE_SUBROUTINE_UNIFORMS 0x8DE6 -#define GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS 0x8E47 -#define GL_ACTIVE_SUBROUTINE_MAX_LENGTH 0x8E48 -#define GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH 0x8E49 -#define GL_MAX_SUBROUTINES 0x8DE7 -#define GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS 0x8DE8 -#define GL_NUM_COMPATIBLE_SUBROUTINES 0x8E4A -#define GL_COMPATIBLE_SUBROUTINES 0x8E4B -/* reuse GL_UNIFORM_SIZE */ -/* reuse GL_UNIFORM_NAME_LENGTH */ -#endif - -#ifndef GL_ARB_tessellation_shader -#define GL_PATCHES 0x000E -#define GL_PATCH_VERTICES 0x8E72 -#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73 -#define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74 -#define GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75 -#define GL_TESS_GEN_MODE 0x8E76 -#define GL_TESS_GEN_SPACING 0x8E77 -#define GL_TESS_GEN_VERTEX_ORDER 0x8E78 -#define GL_TESS_GEN_POINT_MODE 0x8E79 -/* reuse GL_TRIANGLES */ -/* reuse GL_QUADS */ -#define GL_ISOLINES 0x8E7A -/* reuse GL_EQUAL */ -#define GL_FRACTIONAL_ODD 0x8E7B -#define GL_FRACTIONAL_EVEN 0x8E7C -/* reuse GL_CCW */ -/* reuse GL_CW */ -#define GL_MAX_PATCH_VERTICES 0x8E7D -#define GL_MAX_TESS_GEN_LEVEL 0x8E7E -#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F -#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80 -#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81 -#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82 -#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83 -#define GL_MAX_TESS_PATCH_COMPONENTS 0x8E84 -#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85 -#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86 -#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89 -#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A -#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C -#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D -#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E -#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F -#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0 -#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1 -#define GL_TESS_EVALUATION_SHADER 0x8E87 -#define GL_TESS_CONTROL_SHADER 0x8E88 -#endif - -#ifndef GL_ARB_texture_buffer_object_rgb32 -/* reuse GL_RGB32F */ -/* reuse GL_RGB32UI */ -/* reuse GL_RGB32I */ -#endif - -#ifndef GL_ARB_transform_feedback2 -#define GL_TRANSFORM_FEEDBACK 0x8E22 -#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED 0x8E23 -#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE 0x8E24 -#define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25 -#endif - -#ifndef GL_ARB_transform_feedback3 -#define GL_MAX_TRANSFORM_FEEDBACK_BUFFERS 0x8E70 -#define GL_MAX_VERTEX_STREAMS 0x8E71 -#endif - -#ifndef GL_ARB_ES2_compatibility -#define GL_FIXED 0x140C -#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A -#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B -#define GL_LOW_FLOAT 0x8DF0 -#define GL_MEDIUM_FLOAT 0x8DF1 -#define GL_HIGH_FLOAT 0x8DF2 -#define GL_LOW_INT 0x8DF3 -#define GL_MEDIUM_INT 0x8DF4 -#define GL_HIGH_INT 0x8DF5 -#define GL_SHADER_COMPILER 0x8DFA -#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 -#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB -#define GL_MAX_VARYING_VECTORS 0x8DFC -#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD -#endif - -#ifndef GL_ARB_get_program_binary -#define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257 -#define GL_PROGRAM_BINARY_LENGTH 0x8741 -#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE -#define GL_PROGRAM_BINARY_FORMATS 0x87FF -#endif - -#ifndef GL_ARB_separate_shader_objects -#define GL_VERTEX_SHADER_BIT 0x00000001 -#define GL_FRAGMENT_SHADER_BIT 0x00000002 -#define GL_GEOMETRY_SHADER_BIT 0x00000004 -#define GL_TESS_CONTROL_SHADER_BIT 0x00000008 -#define GL_TESS_EVALUATION_SHADER_BIT 0x00000010 -#define GL_ALL_SHADER_BITS 0xFFFFFFFF -#define GL_PROGRAM_SEPARABLE 0x8258 -#define GL_ACTIVE_PROGRAM 0x8259 -#define GL_PROGRAM_PIPELINE_BINDING 0x825A -#endif - -#ifndef GL_ARB_shader_precision -#endif - -#ifndef GL_ARB_vertex_attrib_64bit -/* reuse GL_RGB32I */ -/* reuse GL_DOUBLE_VEC2 */ -/* reuse GL_DOUBLE_VEC3 */ -/* reuse GL_DOUBLE_VEC4 */ -/* reuse GL_DOUBLE_MAT2 */ -/* reuse GL_DOUBLE_MAT3 */ -/* reuse GL_DOUBLE_MAT4 */ -/* reuse GL_DOUBLE_MAT2x3 */ -/* reuse GL_DOUBLE_MAT2x4 */ -/* reuse GL_DOUBLE_MAT3x2 */ -/* reuse GL_DOUBLE_MAT3x4 */ -/* reuse GL_DOUBLE_MAT4x2 */ -/* reuse GL_DOUBLE_MAT4x3 */ -#endif - -#ifndef GL_ARB_viewport_array -/* reuse GL_SCISSOR_BOX */ -/* reuse GL_VIEWPORT */ -/* reuse GL_DEPTH_RANGE */ -/* reuse GL_SCISSOR_TEST */ -#define GL_MAX_VIEWPORTS 0x825B -#define GL_VIEWPORT_SUBPIXEL_BITS 0x825C -#define GL_VIEWPORT_BOUNDS_RANGE 0x825D -#define GL_LAYER_PROVOKING_VERTEX 0x825E -#define GL_VIEWPORT_INDEX_PROVOKING_VERTEX 0x825F -#define GL_UNDEFINED_VERTEX 0x8260 -/* reuse GL_FIRST_VERTEX_CONVENTION */ -/* reuse GL_LAST_VERTEX_CONVENTION */ -/* reuse GL_PROVOKING_VERTEX */ -#endif - -#ifndef GL_ARB_cl_event -#define GL_SYNC_CL_EVENT_ARB 0x8240 -#define GL_SYNC_CL_EVENT_COMPLETE_ARB 0x8241 -#endif - -#ifndef GL_ARB_debug_output -#define GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242 -#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243 -#define GL_DEBUG_CALLBACK_FUNCTION_ARB 0x8244 -#define GL_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245 -#define GL_DEBUG_SOURCE_API_ARB 0x8246 -#define GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247 -#define GL_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248 -#define GL_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249 -#define GL_DEBUG_SOURCE_APPLICATION_ARB 0x824A -#define GL_DEBUG_SOURCE_OTHER_ARB 0x824B -#define GL_DEBUG_TYPE_ERROR_ARB 0x824C -#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D -#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E -#define GL_DEBUG_TYPE_PORTABILITY_ARB 0x824F -#define GL_DEBUG_TYPE_PERFORMANCE_ARB 0x8250 -#define GL_DEBUG_TYPE_OTHER_ARB 0x8251 -#define GL_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143 -#define GL_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144 -#define GL_DEBUG_LOGGED_MESSAGES_ARB 0x9145 -#define GL_DEBUG_SEVERITY_HIGH_ARB 0x9146 -#define GL_DEBUG_SEVERITY_MEDIUM_ARB 0x9147 -#define GL_DEBUG_SEVERITY_LOW_ARB 0x9148 -#endif - -#ifndef GL_ARB_robustness -/* reuse GL_NO_ERROR */ -#define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB 0x00000004 -#define GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 -#define GL_GUILTY_CONTEXT_RESET_ARB 0x8253 -#define GL_INNOCENT_CONTEXT_RESET_ARB 0x8254 -#define GL_UNKNOWN_CONTEXT_RESET_ARB 0x8255 -#define GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 -#define GL_NO_RESET_NOTIFICATION_ARB 0x8261 -#endif - -#ifndef GL_ARB_shader_stencil_export -#endif - -#ifndef GL_ARB_base_instance -#endif - -#ifndef GL_ARB_shading_language_420pack -#endif - -#ifndef GL_ARB_transform_feedback_instanced -#endif - -#ifndef GL_ARB_compressed_texture_pixel_storage -#define GL_UNPACK_COMPRESSED_BLOCK_WIDTH 0x9127 -#define GL_UNPACK_COMPRESSED_BLOCK_HEIGHT 0x9128 -#define GL_UNPACK_COMPRESSED_BLOCK_DEPTH 0x9129 -#define GL_UNPACK_COMPRESSED_BLOCK_SIZE 0x912A -#define GL_PACK_COMPRESSED_BLOCK_WIDTH 0x912B -#define GL_PACK_COMPRESSED_BLOCK_HEIGHT 0x912C -#define GL_PACK_COMPRESSED_BLOCK_DEPTH 0x912D -#define GL_PACK_COMPRESSED_BLOCK_SIZE 0x912E -#endif - -#ifndef GL_ARB_conservative_depth -#endif - -#ifndef GL_ARB_internalformat_query -#define GL_NUM_SAMPLE_COUNTS 0x9380 -#endif - -#ifndef GL_ARB_map_buffer_alignment -#define GL_MIN_MAP_BUFFER_ALIGNMENT 0x90BC -#endif - -#ifndef GL_ARB_shader_atomic_counters -#define GL_ATOMIC_COUNTER_BUFFER 0x92C0 -#define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1 -#define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2 -#define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3 -#define GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE 0x92C4 -#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS 0x92C5 -#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES 0x92C6 -#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER 0x92C7 -#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER 0x92C8 -#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER 0x92C9 -#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER 0x92CA -#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER 0x92CB -#define GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC -#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS 0x92CD -#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS 0x92CE -#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF -#define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0 -#define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1 -#define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2 -#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3 -#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4 -#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5 -#define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6 -#define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7 -#define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8 -#define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC -#define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9 -#define GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX 0x92DA -#define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB -#endif - -#ifndef GL_ARB_shader_image_load_store -#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001 -#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002 -#define GL_UNIFORM_BARRIER_BIT 0x00000004 -#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008 -#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020 -#define GL_COMMAND_BARRIER_BIT 0x00000040 -#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080 -#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100 -#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200 -#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400 -#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800 -#define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000 -#define GL_ALL_BARRIER_BITS 0xFFFFFFFF -#define GL_MAX_IMAGE_UNITS 0x8F38 -#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39 -#define GL_IMAGE_BINDING_NAME 0x8F3A -#define GL_IMAGE_BINDING_LEVEL 0x8F3B -#define GL_IMAGE_BINDING_LAYERED 0x8F3C -#define GL_IMAGE_BINDING_LAYER 0x8F3D -#define GL_IMAGE_BINDING_ACCESS 0x8F3E -#define GL_IMAGE_1D 0x904C -#define GL_IMAGE_2D 0x904D -#define GL_IMAGE_3D 0x904E -#define GL_IMAGE_2D_RECT 0x904F -#define GL_IMAGE_CUBE 0x9050 -#define GL_IMAGE_BUFFER 0x9051 -#define GL_IMAGE_1D_ARRAY 0x9052 -#define GL_IMAGE_2D_ARRAY 0x9053 -#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054 -#define GL_IMAGE_2D_MULTISAMPLE 0x9055 -#define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056 -#define GL_INT_IMAGE_1D 0x9057 -#define GL_INT_IMAGE_2D 0x9058 -#define GL_INT_IMAGE_3D 0x9059 -#define GL_INT_IMAGE_2D_RECT 0x905A -#define GL_INT_IMAGE_CUBE 0x905B -#define GL_INT_IMAGE_BUFFER 0x905C -#define GL_INT_IMAGE_1D_ARRAY 0x905D -#define GL_INT_IMAGE_2D_ARRAY 0x905E -#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F -#define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060 -#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061 -#define GL_UNSIGNED_INT_IMAGE_1D 0x9062 -#define GL_UNSIGNED_INT_IMAGE_2D 0x9063 -#define GL_UNSIGNED_INT_IMAGE_3D 0x9064 -#define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065 -#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066 -#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067 -#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068 -#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069 -#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A -#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B -#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C -#define GL_MAX_IMAGE_SAMPLES 0x906D -#define GL_IMAGE_BINDING_FORMAT 0x906E -#define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7 -#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8 -#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9 -#define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA -#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB -#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC -#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD -#define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE -#define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF -#endif - -#ifndef GL_ARB_shading_language_packing -#endif - -#ifndef GL_ARB_texture_storage -#define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F -#endif - -#ifndef GL_EXT_abgr -#define GL_ABGR_EXT 0x8000 -#endif - -#ifndef GL_EXT_blend_color -#define GL_CONSTANT_COLOR_EXT 0x8001 -#define GL_ONE_MINUS_CONSTANT_COLOR_EXT 0x8002 -#define GL_CONSTANT_ALPHA_EXT 0x8003 -#define GL_ONE_MINUS_CONSTANT_ALPHA_EXT 0x8004 -#define GL_BLEND_COLOR_EXT 0x8005 -#endif - -#ifndef GL_EXT_polygon_offset -#define GL_POLYGON_OFFSET_EXT 0x8037 -#define GL_POLYGON_OFFSET_FACTOR_EXT 0x8038 -#define GL_POLYGON_OFFSET_BIAS_EXT 0x8039 -#endif - -#ifndef GL_EXT_texture -#define GL_ALPHA4_EXT 0x803B -#define GL_ALPHA8_EXT 0x803C -#define GL_ALPHA12_EXT 0x803D -#define GL_ALPHA16_EXT 0x803E -#define GL_LUMINANCE4_EXT 0x803F -#define GL_LUMINANCE8_EXT 0x8040 -#define GL_LUMINANCE12_EXT 0x8041 -#define GL_LUMINANCE16_EXT 0x8042 -#define GL_LUMINANCE4_ALPHA4_EXT 0x8043 -#define GL_LUMINANCE6_ALPHA2_EXT 0x8044 -#define GL_LUMINANCE8_ALPHA8_EXT 0x8045 -#define GL_LUMINANCE12_ALPHA4_EXT 0x8046 -#define GL_LUMINANCE12_ALPHA12_EXT 0x8047 -#define GL_LUMINANCE16_ALPHA16_EXT 0x8048 -#define GL_INTENSITY_EXT 0x8049 -#define GL_INTENSITY4_EXT 0x804A -#define GL_INTENSITY8_EXT 0x804B -#define GL_INTENSITY12_EXT 0x804C -#define GL_INTENSITY16_EXT 0x804D -#define GL_RGB2_EXT 0x804E -#define GL_RGB4_EXT 0x804F -#define GL_RGB5_EXT 0x8050 -#define GL_RGB8_EXT 0x8051 -#define GL_RGB10_EXT 0x8052 -#define GL_RGB12_EXT 0x8053 -#define GL_RGB16_EXT 0x8054 -#define GL_RGBA2_EXT 0x8055 -#define GL_RGBA4_EXT 0x8056 -#define GL_RGB5_A1_EXT 0x8057 -#define GL_RGBA8_EXT 0x8058 -#define GL_RGB10_A2_EXT 0x8059 -#define GL_RGBA12_EXT 0x805A -#define GL_RGBA16_EXT 0x805B -#define GL_TEXTURE_RED_SIZE_EXT 0x805C -#define GL_TEXTURE_GREEN_SIZE_EXT 0x805D -#define GL_TEXTURE_BLUE_SIZE_EXT 0x805E -#define GL_TEXTURE_ALPHA_SIZE_EXT 0x805F -#define GL_TEXTURE_LUMINANCE_SIZE_EXT 0x8060 -#define GL_TEXTURE_INTENSITY_SIZE_EXT 0x8061 -#define GL_REPLACE_EXT 0x8062 -#define GL_PROXY_TEXTURE_1D_EXT 0x8063 -#define GL_PROXY_TEXTURE_2D_EXT 0x8064 -#define GL_TEXTURE_TOO_LARGE_EXT 0x8065 -#endif - -#ifndef GL_EXT_texture3D -#define GL_PACK_SKIP_IMAGES_EXT 0x806B -#define GL_PACK_IMAGE_HEIGHT_EXT 0x806C -#define GL_UNPACK_SKIP_IMAGES_EXT 0x806D -#define GL_UNPACK_IMAGE_HEIGHT_EXT 0x806E -#define GL_TEXTURE_3D_EXT 0x806F -#define GL_PROXY_TEXTURE_3D_EXT 0x8070 -#define GL_TEXTURE_DEPTH_EXT 0x8071 -#define GL_TEXTURE_WRAP_R_EXT 0x8072 -#define GL_MAX_3D_TEXTURE_SIZE_EXT 0x8073 -#endif - -#ifndef GL_SGIS_texture_filter4 -#define GL_FILTER4_SGIS 0x8146 -#define GL_TEXTURE_FILTER4_SIZE_SGIS 0x8147 -#endif - -#ifndef GL_EXT_subtexture -#endif - -#ifndef GL_EXT_copy_texture -#endif - -#ifndef GL_EXT_histogram -#define GL_HISTOGRAM_EXT 0x8024 -#define GL_PROXY_HISTOGRAM_EXT 0x8025 -#define GL_HISTOGRAM_WIDTH_EXT 0x8026 -#define GL_HISTOGRAM_FORMAT_EXT 0x8027 -#define GL_HISTOGRAM_RED_SIZE_EXT 0x8028 -#define GL_HISTOGRAM_GREEN_SIZE_EXT 0x8029 -#define GL_HISTOGRAM_BLUE_SIZE_EXT 0x802A -#define GL_HISTOGRAM_ALPHA_SIZE_EXT 0x802B -#define GL_HISTOGRAM_LUMINANCE_SIZE_EXT 0x802C -#define GL_HISTOGRAM_SINK_EXT 0x802D -#define GL_MINMAX_EXT 0x802E -#define GL_MINMAX_FORMAT_EXT 0x802F -#define GL_MINMAX_SINK_EXT 0x8030 -#define GL_TABLE_TOO_LARGE_EXT 0x8031 -#endif - -#ifndef GL_EXT_convolution -#define GL_CONVOLUTION_1D_EXT 0x8010 -#define GL_CONVOLUTION_2D_EXT 0x8011 -#define GL_SEPARABLE_2D_EXT 0x8012 -#define GL_CONVOLUTION_BORDER_MODE_EXT 0x8013 -#define GL_CONVOLUTION_FILTER_SCALE_EXT 0x8014 -#define GL_CONVOLUTION_FILTER_BIAS_EXT 0x8015 -#define GL_REDUCE_EXT 0x8016 -#define GL_CONVOLUTION_FORMAT_EXT 0x8017 -#define GL_CONVOLUTION_WIDTH_EXT 0x8018 -#define GL_CONVOLUTION_HEIGHT_EXT 0x8019 -#define GL_MAX_CONVOLUTION_WIDTH_EXT 0x801A -#define GL_MAX_CONVOLUTION_HEIGHT_EXT 0x801B -#define GL_POST_CONVOLUTION_RED_SCALE_EXT 0x801C -#define GL_POST_CONVOLUTION_GREEN_SCALE_EXT 0x801D -#define GL_POST_CONVOLUTION_BLUE_SCALE_EXT 0x801E -#define GL_POST_CONVOLUTION_ALPHA_SCALE_EXT 0x801F -#define GL_POST_CONVOLUTION_RED_BIAS_EXT 0x8020 -#define GL_POST_CONVOLUTION_GREEN_BIAS_EXT 0x8021 -#define GL_POST_CONVOLUTION_BLUE_BIAS_EXT 0x8022 -#define GL_POST_CONVOLUTION_ALPHA_BIAS_EXT 0x8023 -#endif - -#ifndef GL_SGI_color_matrix -#define GL_COLOR_MATRIX_SGI 0x80B1 -#define GL_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B2 -#define GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B3 -#define GL_POST_COLOR_MATRIX_RED_SCALE_SGI 0x80B4 -#define GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI 0x80B5 -#define GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI 0x80B6 -#define GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI 0x80B7 -#define GL_POST_COLOR_MATRIX_RED_BIAS_SGI 0x80B8 -#define GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI 0x80B9 -#define GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI 0x80BA -#define GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI 0x80BB -#endif - -#ifndef GL_SGI_color_table -#define GL_COLOR_TABLE_SGI 0x80D0 -#define GL_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D1 -#define GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D2 -#define GL_PROXY_COLOR_TABLE_SGI 0x80D3 -#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D4 -#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D5 -#define GL_COLOR_TABLE_SCALE_SGI 0x80D6 -#define GL_COLOR_TABLE_BIAS_SGI 0x80D7 -#define GL_COLOR_TABLE_FORMAT_SGI 0x80D8 -#define GL_COLOR_TABLE_WIDTH_SGI 0x80D9 -#define GL_COLOR_TABLE_RED_SIZE_SGI 0x80DA -#define GL_COLOR_TABLE_GREEN_SIZE_SGI 0x80DB -#define GL_COLOR_TABLE_BLUE_SIZE_SGI 0x80DC -#define GL_COLOR_TABLE_ALPHA_SIZE_SGI 0x80DD -#define GL_COLOR_TABLE_LUMINANCE_SIZE_SGI 0x80DE -#define GL_COLOR_TABLE_INTENSITY_SIZE_SGI 0x80DF -#endif - -#ifndef GL_SGIS_pixel_texture -#define GL_PIXEL_TEXTURE_SGIS 0x8353 -#define GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS 0x8354 -#define GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS 0x8355 -#define GL_PIXEL_GROUP_COLOR_SGIS 0x8356 -#endif - -#ifndef GL_SGIX_pixel_texture -#define GL_PIXEL_TEX_GEN_SGIX 0x8139 -#define GL_PIXEL_TEX_GEN_MODE_SGIX 0x832B -#endif - -#ifndef GL_SGIS_texture4D -#define GL_PACK_SKIP_VOLUMES_SGIS 0x8130 -#define GL_PACK_IMAGE_DEPTH_SGIS 0x8131 -#define GL_UNPACK_SKIP_VOLUMES_SGIS 0x8132 -#define GL_UNPACK_IMAGE_DEPTH_SGIS 0x8133 -#define GL_TEXTURE_4D_SGIS 0x8134 -#define GL_PROXY_TEXTURE_4D_SGIS 0x8135 -#define GL_TEXTURE_4DSIZE_SGIS 0x8136 -#define GL_TEXTURE_WRAP_Q_SGIS 0x8137 -#define GL_MAX_4D_TEXTURE_SIZE_SGIS 0x8138 -#define GL_TEXTURE_4D_BINDING_SGIS 0x814F -#endif - -#ifndef GL_SGI_texture_color_table -#define GL_TEXTURE_COLOR_TABLE_SGI 0x80BC -#define GL_PROXY_TEXTURE_COLOR_TABLE_SGI 0x80BD -#endif - -#ifndef GL_EXT_cmyka -#define GL_CMYK_EXT 0x800C -#define GL_CMYKA_EXT 0x800D -#define GL_PACK_CMYK_HINT_EXT 0x800E -#define GL_UNPACK_CMYK_HINT_EXT 0x800F -#endif - -#ifndef GL_EXT_texture_object -#define GL_TEXTURE_PRIORITY_EXT 0x8066 -#define GL_TEXTURE_RESIDENT_EXT 0x8067 -#define GL_TEXTURE_1D_BINDING_EXT 0x8068 -#define GL_TEXTURE_2D_BINDING_EXT 0x8069 -#define GL_TEXTURE_3D_BINDING_EXT 0x806A -#endif - -#ifndef GL_SGIS_detail_texture -#define GL_DETAIL_TEXTURE_2D_SGIS 0x8095 -#define GL_DETAIL_TEXTURE_2D_BINDING_SGIS 0x8096 -#define GL_LINEAR_DETAIL_SGIS 0x8097 -#define GL_LINEAR_DETAIL_ALPHA_SGIS 0x8098 -#define GL_LINEAR_DETAIL_COLOR_SGIS 0x8099 -#define GL_DETAIL_TEXTURE_LEVEL_SGIS 0x809A -#define GL_DETAIL_TEXTURE_MODE_SGIS 0x809B -#define GL_DETAIL_TEXTURE_FUNC_POINTS_SGIS 0x809C -#endif - -#ifndef GL_SGIS_sharpen_texture -#define GL_LINEAR_SHARPEN_SGIS 0x80AD -#define GL_LINEAR_SHARPEN_ALPHA_SGIS 0x80AE -#define GL_LINEAR_SHARPEN_COLOR_SGIS 0x80AF -#define GL_SHARPEN_TEXTURE_FUNC_POINTS_SGIS 0x80B0 -#endif - -#ifndef GL_EXT_packed_pixels -#define GL_UNSIGNED_BYTE_3_3_2_EXT 0x8032 -#define GL_UNSIGNED_SHORT_4_4_4_4_EXT 0x8033 -#define GL_UNSIGNED_SHORT_5_5_5_1_EXT 0x8034 -#define GL_UNSIGNED_INT_8_8_8_8_EXT 0x8035 -#define GL_UNSIGNED_INT_10_10_10_2_EXT 0x8036 -#endif - -#ifndef GL_SGIS_texture_lod -#define GL_TEXTURE_MIN_LOD_SGIS 0x813A -#define GL_TEXTURE_MAX_LOD_SGIS 0x813B -#define GL_TEXTURE_BASE_LEVEL_SGIS 0x813C -#define GL_TEXTURE_MAX_LEVEL_SGIS 0x813D -#endif - -#ifndef GL_SGIS_multisample -#define GL_MULTISAMPLE_SGIS 0x809D -#define GL_SAMPLE_ALPHA_TO_MASK_SGIS 0x809E -#define GL_SAMPLE_ALPHA_TO_ONE_SGIS 0x809F -#define GL_SAMPLE_MASK_SGIS 0x80A0 -#define GL_1PASS_SGIS 0x80A1 -#define GL_2PASS_0_SGIS 0x80A2 -#define GL_2PASS_1_SGIS 0x80A3 -#define GL_4PASS_0_SGIS 0x80A4 -#define GL_4PASS_1_SGIS 0x80A5 -#define GL_4PASS_2_SGIS 0x80A6 -#define GL_4PASS_3_SGIS 0x80A7 -#define GL_SAMPLE_BUFFERS_SGIS 0x80A8 -#define GL_SAMPLES_SGIS 0x80A9 -#define GL_SAMPLE_MASK_VALUE_SGIS 0x80AA -#define GL_SAMPLE_MASK_INVERT_SGIS 0x80AB -#define GL_SAMPLE_PATTERN_SGIS 0x80AC -#endif - -#ifndef GL_EXT_rescale_normal -#define GL_RESCALE_NORMAL_EXT 0x803A -#endif - -#ifndef GL_EXT_vertex_array -#define GL_VERTEX_ARRAY_EXT 0x8074 -#define GL_NORMAL_ARRAY_EXT 0x8075 -#define GL_COLOR_ARRAY_EXT 0x8076 -#define GL_INDEX_ARRAY_EXT 0x8077 -#define GL_TEXTURE_COORD_ARRAY_EXT 0x8078 -#define GL_EDGE_FLAG_ARRAY_EXT 0x8079 -#define GL_VERTEX_ARRAY_SIZE_EXT 0x807A -#define GL_VERTEX_ARRAY_TYPE_EXT 0x807B -#define GL_VERTEX_ARRAY_STRIDE_EXT 0x807C -#define GL_VERTEX_ARRAY_COUNT_EXT 0x807D -#define GL_NORMAL_ARRAY_TYPE_EXT 0x807E -#define GL_NORMAL_ARRAY_STRIDE_EXT 0x807F -#define GL_NORMAL_ARRAY_COUNT_EXT 0x8080 -#define GL_COLOR_ARRAY_SIZE_EXT 0x8081 -#define GL_COLOR_ARRAY_TYPE_EXT 0x8082 -#define GL_COLOR_ARRAY_STRIDE_EXT 0x8083 -#define GL_COLOR_ARRAY_COUNT_EXT 0x8084 -#define GL_INDEX_ARRAY_TYPE_EXT 0x8085 -#define GL_INDEX_ARRAY_STRIDE_EXT 0x8086 -#define GL_INDEX_ARRAY_COUNT_EXT 0x8087 -#define GL_TEXTURE_COORD_ARRAY_SIZE_EXT 0x8088 -#define GL_TEXTURE_COORD_ARRAY_TYPE_EXT 0x8089 -#define GL_TEXTURE_COORD_ARRAY_STRIDE_EXT 0x808A -#define GL_TEXTURE_COORD_ARRAY_COUNT_EXT 0x808B -#define GL_EDGE_FLAG_ARRAY_STRIDE_EXT 0x808C -#define GL_EDGE_FLAG_ARRAY_COUNT_EXT 0x808D -#define GL_VERTEX_ARRAY_POINTER_EXT 0x808E -#define GL_NORMAL_ARRAY_POINTER_EXT 0x808F -#define GL_COLOR_ARRAY_POINTER_EXT 0x8090 -#define GL_INDEX_ARRAY_POINTER_EXT 0x8091 -#define GL_TEXTURE_COORD_ARRAY_POINTER_EXT 0x8092 -#define GL_EDGE_FLAG_ARRAY_POINTER_EXT 0x8093 -#endif - -#ifndef GL_EXT_misc_attribute -#endif - -#ifndef GL_SGIS_generate_mipmap -#define GL_GENERATE_MIPMAP_SGIS 0x8191 -#define GL_GENERATE_MIPMAP_HINT_SGIS 0x8192 -#endif - -#ifndef GL_SGIX_clipmap -#define GL_LINEAR_CLIPMAP_LINEAR_SGIX 0x8170 -#define GL_TEXTURE_CLIPMAP_CENTER_SGIX 0x8171 -#define GL_TEXTURE_CLIPMAP_FRAME_SGIX 0x8172 -#define GL_TEXTURE_CLIPMAP_OFFSET_SGIX 0x8173 -#define GL_TEXTURE_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8174 -#define GL_TEXTURE_CLIPMAP_LOD_OFFSET_SGIX 0x8175 -#define GL_TEXTURE_CLIPMAP_DEPTH_SGIX 0x8176 -#define GL_MAX_CLIPMAP_DEPTH_SGIX 0x8177 -#define GL_MAX_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8178 -#define GL_NEAREST_CLIPMAP_NEAREST_SGIX 0x844D -#define GL_NEAREST_CLIPMAP_LINEAR_SGIX 0x844E -#define GL_LINEAR_CLIPMAP_NEAREST_SGIX 0x844F -#endif - -#ifndef GL_SGIX_shadow -#define GL_TEXTURE_COMPARE_SGIX 0x819A -#define GL_TEXTURE_COMPARE_OPERATOR_SGIX 0x819B -#define GL_TEXTURE_LEQUAL_R_SGIX 0x819C -#define GL_TEXTURE_GEQUAL_R_SGIX 0x819D -#endif - -#ifndef GL_SGIS_texture_edge_clamp -#define GL_CLAMP_TO_EDGE_SGIS 0x812F -#endif - -#ifndef GL_SGIS_texture_border_clamp -#define GL_CLAMP_TO_BORDER_SGIS 0x812D -#endif - -#ifndef GL_EXT_blend_minmax -#define GL_FUNC_ADD_EXT 0x8006 -#define GL_MIN_EXT 0x8007 -#define GL_MAX_EXT 0x8008 -#define GL_BLEND_EQUATION_EXT 0x8009 -#endif - -#ifndef GL_EXT_blend_subtract -#define GL_FUNC_SUBTRACT_EXT 0x800A -#define GL_FUNC_REVERSE_SUBTRACT_EXT 0x800B -#endif - -#ifndef GL_EXT_blend_logic_op -#endif - -#ifndef GL_SGIX_interlace -#define GL_INTERLACE_SGIX 0x8094 -#endif - -#ifndef GL_SGIX_pixel_tiles -#define GL_PIXEL_TILE_BEST_ALIGNMENT_SGIX 0x813E -#define GL_PIXEL_TILE_CACHE_INCREMENT_SGIX 0x813F -#define GL_PIXEL_TILE_WIDTH_SGIX 0x8140 -#define GL_PIXEL_TILE_HEIGHT_SGIX 0x8141 -#define GL_PIXEL_TILE_GRID_WIDTH_SGIX 0x8142 -#define GL_PIXEL_TILE_GRID_HEIGHT_SGIX 0x8143 -#define GL_PIXEL_TILE_GRID_DEPTH_SGIX 0x8144 -#define GL_PIXEL_TILE_CACHE_SIZE_SGIX 0x8145 -#endif - -#ifndef GL_SGIS_texture_select -#define GL_DUAL_ALPHA4_SGIS 0x8110 -#define GL_DUAL_ALPHA8_SGIS 0x8111 -#define GL_DUAL_ALPHA12_SGIS 0x8112 -#define GL_DUAL_ALPHA16_SGIS 0x8113 -#define GL_DUAL_LUMINANCE4_SGIS 0x8114 -#define GL_DUAL_LUMINANCE8_SGIS 0x8115 -#define GL_DUAL_LUMINANCE12_SGIS 0x8116 -#define GL_DUAL_LUMINANCE16_SGIS 0x8117 -#define GL_DUAL_INTENSITY4_SGIS 0x8118 -#define GL_DUAL_INTENSITY8_SGIS 0x8119 -#define GL_DUAL_INTENSITY12_SGIS 0x811A -#define GL_DUAL_INTENSITY16_SGIS 0x811B -#define GL_DUAL_LUMINANCE_ALPHA4_SGIS 0x811C -#define GL_DUAL_LUMINANCE_ALPHA8_SGIS 0x811D -#define GL_QUAD_ALPHA4_SGIS 0x811E -#define GL_QUAD_ALPHA8_SGIS 0x811F -#define GL_QUAD_LUMINANCE4_SGIS 0x8120 -#define GL_QUAD_LUMINANCE8_SGIS 0x8121 -#define GL_QUAD_INTENSITY4_SGIS 0x8122 -#define GL_QUAD_INTENSITY8_SGIS 0x8123 -#define GL_DUAL_TEXTURE_SELECT_SGIS 0x8124 -#define GL_QUAD_TEXTURE_SELECT_SGIS 0x8125 -#endif - -#ifndef GL_SGIX_sprite -#define GL_SPRITE_SGIX 0x8148 -#define GL_SPRITE_MODE_SGIX 0x8149 -#define GL_SPRITE_AXIS_SGIX 0x814A -#define GL_SPRITE_TRANSLATION_SGIX 0x814B -#define GL_SPRITE_AXIAL_SGIX 0x814C -#define GL_SPRITE_OBJECT_ALIGNED_SGIX 0x814D -#define GL_SPRITE_EYE_ALIGNED_SGIX 0x814E -#endif - -#ifndef GL_SGIX_texture_multi_buffer -#define GL_TEXTURE_MULTI_BUFFER_HINT_SGIX 0x812E -#endif - -#ifndef GL_EXT_point_parameters -#define GL_POINT_SIZE_MIN_EXT 0x8126 -#define GL_POINT_SIZE_MAX_EXT 0x8127 -#define GL_POINT_FADE_THRESHOLD_SIZE_EXT 0x8128 -#define GL_DISTANCE_ATTENUATION_EXT 0x8129 -#endif - -#ifndef GL_SGIS_point_parameters -#define GL_POINT_SIZE_MIN_SGIS 0x8126 -#define GL_POINT_SIZE_MAX_SGIS 0x8127 -#define GL_POINT_FADE_THRESHOLD_SIZE_SGIS 0x8128 -#define GL_DISTANCE_ATTENUATION_SGIS 0x8129 -#endif - -#ifndef GL_SGIX_instruments -#define GL_INSTRUMENT_BUFFER_POINTER_SGIX 0x8180 -#define GL_INSTRUMENT_MEASUREMENTS_SGIX 0x8181 -#endif - -#ifndef GL_SGIX_texture_scale_bias -#define GL_POST_TEXTURE_FILTER_BIAS_SGIX 0x8179 -#define GL_POST_TEXTURE_FILTER_SCALE_SGIX 0x817A -#define GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX 0x817B -#define GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX 0x817C -#endif - -#ifndef GL_SGIX_framezoom -#define GL_FRAMEZOOM_SGIX 0x818B -#define GL_FRAMEZOOM_FACTOR_SGIX 0x818C -#define GL_MAX_FRAMEZOOM_FACTOR_SGIX 0x818D -#endif - -#ifndef GL_SGIX_tag_sample_buffer -#endif - -#ifndef GL_FfdMaskSGIX -#define GL_TEXTURE_DEFORMATION_BIT_SGIX 0x00000001 -#define GL_GEOMETRY_DEFORMATION_BIT_SGIX 0x00000002 -#endif - -#ifndef GL_SGIX_polynomial_ffd -#define GL_GEOMETRY_DEFORMATION_SGIX 0x8194 -#define GL_TEXTURE_DEFORMATION_SGIX 0x8195 -#define GL_DEFORMATIONS_MASK_SGIX 0x8196 -#define GL_MAX_DEFORMATION_ORDER_SGIX 0x8197 -#endif - -#ifndef GL_SGIX_reference_plane -#define GL_REFERENCE_PLANE_SGIX 0x817D -#define GL_REFERENCE_PLANE_EQUATION_SGIX 0x817E -#endif - -#ifndef GL_SGIX_flush_raster -#endif - -#ifndef GL_SGIX_depth_texture -#define GL_DEPTH_COMPONENT16_SGIX 0x81A5 -#define GL_DEPTH_COMPONENT24_SGIX 0x81A6 -#define GL_DEPTH_COMPONENT32_SGIX 0x81A7 -#endif - -#ifndef GL_SGIS_fog_function -#define GL_FOG_FUNC_SGIS 0x812A -#define GL_FOG_FUNC_POINTS_SGIS 0x812B -#define GL_MAX_FOG_FUNC_POINTS_SGIS 0x812C -#endif - -#ifndef GL_SGIX_fog_offset -#define GL_FOG_OFFSET_SGIX 0x8198 -#define GL_FOG_OFFSET_VALUE_SGIX 0x8199 -#endif - -#ifndef GL_HP_image_transform -#define GL_IMAGE_SCALE_X_HP 0x8155 -#define GL_IMAGE_SCALE_Y_HP 0x8156 -#define GL_IMAGE_TRANSLATE_X_HP 0x8157 -#define GL_IMAGE_TRANSLATE_Y_HP 0x8158 -#define GL_IMAGE_ROTATE_ANGLE_HP 0x8159 -#define GL_IMAGE_ROTATE_ORIGIN_X_HP 0x815A -#define GL_IMAGE_ROTATE_ORIGIN_Y_HP 0x815B -#define GL_IMAGE_MAG_FILTER_HP 0x815C -#define GL_IMAGE_MIN_FILTER_HP 0x815D -#define GL_IMAGE_CUBIC_WEIGHT_HP 0x815E -#define GL_CUBIC_HP 0x815F -#define GL_AVERAGE_HP 0x8160 -#define GL_IMAGE_TRANSFORM_2D_HP 0x8161 -#define GL_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8162 -#define GL_PROXY_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8163 -#endif - -#ifndef GL_HP_convolution_border_modes -#define GL_IGNORE_BORDER_HP 0x8150 -#define GL_CONSTANT_BORDER_HP 0x8151 -#define GL_REPLICATE_BORDER_HP 0x8153 -#define GL_CONVOLUTION_BORDER_COLOR_HP 0x8154 -#endif - -#ifndef GL_INGR_palette_buffer -#endif - -#ifndef GL_SGIX_texture_add_env -#define GL_TEXTURE_ENV_BIAS_SGIX 0x80BE -#endif - -#ifndef GL_EXT_color_subtable -#endif - -#ifndef GL_PGI_vertex_hints -#define GL_VERTEX_DATA_HINT_PGI 0x1A22A -#define GL_VERTEX_CONSISTENT_HINT_PGI 0x1A22B -#define GL_MATERIAL_SIDE_HINT_PGI 0x1A22C -#define GL_MAX_VERTEX_HINT_PGI 0x1A22D -#define GL_COLOR3_BIT_PGI 0x00010000 -#define GL_COLOR4_BIT_PGI 0x00020000 -#define GL_EDGEFLAG_BIT_PGI 0x00040000 -#define GL_INDEX_BIT_PGI 0x00080000 -#define GL_MAT_AMBIENT_BIT_PGI 0x00100000 -#define GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI 0x00200000 -#define GL_MAT_DIFFUSE_BIT_PGI 0x00400000 -#define GL_MAT_EMISSION_BIT_PGI 0x00800000 -#define GL_MAT_COLOR_INDEXES_BIT_PGI 0x01000000 -#define GL_MAT_SHININESS_BIT_PGI 0x02000000 -#define GL_MAT_SPECULAR_BIT_PGI 0x04000000 -#define GL_NORMAL_BIT_PGI 0x08000000 -#define GL_TEXCOORD1_BIT_PGI 0x10000000 -#define GL_TEXCOORD2_BIT_PGI 0x20000000 -#define GL_TEXCOORD3_BIT_PGI 0x40000000 -#define GL_TEXCOORD4_BIT_PGI 0x80000000 -#define GL_VERTEX23_BIT_PGI 0x00000004 -#define GL_VERTEX4_BIT_PGI 0x00000008 -#endif - -#ifndef GL_PGI_misc_hints -#define GL_PREFER_DOUBLEBUFFER_HINT_PGI 0x1A1F8 -#define GL_CONSERVE_MEMORY_HINT_PGI 0x1A1FD -#define GL_RECLAIM_MEMORY_HINT_PGI 0x1A1FE -#define GL_NATIVE_GRAPHICS_HANDLE_PGI 0x1A202 -#define GL_NATIVE_GRAPHICS_BEGIN_HINT_PGI 0x1A203 -#define GL_NATIVE_GRAPHICS_END_HINT_PGI 0x1A204 -#define GL_ALWAYS_FAST_HINT_PGI 0x1A20C -#define GL_ALWAYS_SOFT_HINT_PGI 0x1A20D -#define GL_ALLOW_DRAW_OBJ_HINT_PGI 0x1A20E -#define GL_ALLOW_DRAW_WIN_HINT_PGI 0x1A20F -#define GL_ALLOW_DRAW_FRG_HINT_PGI 0x1A210 -#define GL_ALLOW_DRAW_MEM_HINT_PGI 0x1A211 -#define GL_STRICT_DEPTHFUNC_HINT_PGI 0x1A216 -#define GL_STRICT_LIGHTING_HINT_PGI 0x1A217 -#define GL_STRICT_SCISSOR_HINT_PGI 0x1A218 -#define GL_FULL_STIPPLE_HINT_PGI 0x1A219 -#define GL_CLIP_NEAR_HINT_PGI 0x1A220 -#define GL_CLIP_FAR_HINT_PGI 0x1A221 -#define GL_WIDE_LINE_HINT_PGI 0x1A222 -#define GL_BACK_NORMALS_HINT_PGI 0x1A223 -#endif - -#ifndef GL_EXT_paletted_texture -#define GL_COLOR_INDEX1_EXT 0x80E2 -#define GL_COLOR_INDEX2_EXT 0x80E3 -#define GL_COLOR_INDEX4_EXT 0x80E4 -#define GL_COLOR_INDEX8_EXT 0x80E5 -#define GL_COLOR_INDEX12_EXT 0x80E6 -#define GL_COLOR_INDEX16_EXT 0x80E7 -#define GL_TEXTURE_INDEX_SIZE_EXT 0x80ED -#endif - -#ifndef GL_EXT_clip_volume_hint -#define GL_CLIP_VOLUME_CLIPPING_HINT_EXT 0x80F0 -#endif - -#ifndef GL_SGIX_list_priority -#define GL_LIST_PRIORITY_SGIX 0x8182 -#endif - -#ifndef GL_SGIX_ir_instrument1 -#define GL_IR_INSTRUMENT1_SGIX 0x817F -#endif - -#ifndef GL_SGIX_calligraphic_fragment -#define GL_CALLIGRAPHIC_FRAGMENT_SGIX 0x8183 -#endif - -#ifndef GL_SGIX_texture_lod_bias -#define GL_TEXTURE_LOD_BIAS_S_SGIX 0x818E -#define GL_TEXTURE_LOD_BIAS_T_SGIX 0x818F -#define GL_TEXTURE_LOD_BIAS_R_SGIX 0x8190 -#endif - -#ifndef GL_SGIX_shadow_ambient -#define GL_SHADOW_AMBIENT_SGIX 0x80BF -#endif - -#ifndef GL_EXT_index_texture -#endif - -#ifndef GL_EXT_index_material -#define GL_INDEX_MATERIAL_EXT 0x81B8 -#define GL_INDEX_MATERIAL_PARAMETER_EXT 0x81B9 -#define GL_INDEX_MATERIAL_FACE_EXT 0x81BA -#endif - -#ifndef GL_EXT_index_func -#define GL_INDEX_TEST_EXT 0x81B5 -#define GL_INDEX_TEST_FUNC_EXT 0x81B6 -#define GL_INDEX_TEST_REF_EXT 0x81B7 -#endif - -#ifndef GL_EXT_index_array_formats -#define GL_IUI_V2F_EXT 0x81AD -#define GL_IUI_V3F_EXT 0x81AE -#define GL_IUI_N3F_V2F_EXT 0x81AF -#define GL_IUI_N3F_V3F_EXT 0x81B0 -#define GL_T2F_IUI_V2F_EXT 0x81B1 -#define GL_T2F_IUI_V3F_EXT 0x81B2 -#define GL_T2F_IUI_N3F_V2F_EXT 0x81B3 -#define GL_T2F_IUI_N3F_V3F_EXT 0x81B4 -#endif - -#ifndef GL_EXT_compiled_vertex_array -#define GL_ARRAY_ELEMENT_LOCK_FIRST_EXT 0x81A8 -#define GL_ARRAY_ELEMENT_LOCK_COUNT_EXT 0x81A9 -#endif - -#ifndef GL_EXT_cull_vertex -#define GL_CULL_VERTEX_EXT 0x81AA -#define GL_CULL_VERTEX_EYE_POSITION_EXT 0x81AB -#define GL_CULL_VERTEX_OBJECT_POSITION_EXT 0x81AC -#endif - -#ifndef GL_SGIX_ycrcb -#define GL_YCRCB_422_SGIX 0x81BB -#define GL_YCRCB_444_SGIX 0x81BC -#endif - -#ifndef GL_SGIX_fragment_lighting -#define GL_FRAGMENT_LIGHTING_SGIX 0x8400 -#define GL_FRAGMENT_COLOR_MATERIAL_SGIX 0x8401 -#define GL_FRAGMENT_COLOR_MATERIAL_FACE_SGIX 0x8402 -#define GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_SGIX 0x8403 -#define GL_MAX_FRAGMENT_LIGHTS_SGIX 0x8404 -#define GL_MAX_ACTIVE_LIGHTS_SGIX 0x8405 -#define GL_CURRENT_RASTER_NORMAL_SGIX 0x8406 -#define GL_LIGHT_ENV_MODE_SGIX 0x8407 -#define GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_SGIX 0x8408 -#define GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_SGIX 0x8409 -#define GL_FRAGMENT_LIGHT_MODEL_AMBIENT_SGIX 0x840A -#define GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_SGIX 0x840B -#define GL_FRAGMENT_LIGHT0_SGIX 0x840C -#define GL_FRAGMENT_LIGHT1_SGIX 0x840D -#define GL_FRAGMENT_LIGHT2_SGIX 0x840E -#define GL_FRAGMENT_LIGHT3_SGIX 0x840F -#define GL_FRAGMENT_LIGHT4_SGIX 0x8410 -#define GL_FRAGMENT_LIGHT5_SGIX 0x8411 -#define GL_FRAGMENT_LIGHT6_SGIX 0x8412 -#define GL_FRAGMENT_LIGHT7_SGIX 0x8413 -#endif - -#ifndef GL_IBM_rasterpos_clip -#define GL_RASTER_POSITION_UNCLIPPED_IBM 0x19262 -#endif - -#ifndef GL_HP_texture_lighting -#define GL_TEXTURE_LIGHTING_MODE_HP 0x8167 -#define GL_TEXTURE_POST_SPECULAR_HP 0x8168 -#define GL_TEXTURE_PRE_SPECULAR_HP 0x8169 -#endif - -#ifndef GL_EXT_draw_range_elements -#define GL_MAX_ELEMENTS_VERTICES_EXT 0x80E8 -#define GL_MAX_ELEMENTS_INDICES_EXT 0x80E9 -#endif - -#ifndef GL_WIN_phong_shading -#define GL_PHONG_WIN 0x80EA -#define GL_PHONG_HINT_WIN 0x80EB -#endif - -#ifndef GL_WIN_specular_fog -#define GL_FOG_SPECULAR_TEXTURE_WIN 0x80EC -#endif - -#ifndef GL_EXT_light_texture -#define GL_FRAGMENT_MATERIAL_EXT 0x8349 -#define GL_FRAGMENT_NORMAL_EXT 0x834A -#define GL_FRAGMENT_COLOR_EXT 0x834C -#define GL_ATTENUATION_EXT 0x834D -#define GL_SHADOW_ATTENUATION_EXT 0x834E -#define GL_TEXTURE_APPLICATION_MODE_EXT 0x834F -#define GL_TEXTURE_LIGHT_EXT 0x8350 -#define GL_TEXTURE_MATERIAL_FACE_EXT 0x8351 -#define GL_TEXTURE_MATERIAL_PARAMETER_EXT 0x8352 -/* reuse GL_FRAGMENT_DEPTH_EXT */ -#endif - -#ifndef GL_SGIX_blend_alpha_minmax -#define GL_ALPHA_MIN_SGIX 0x8320 -#define GL_ALPHA_MAX_SGIX 0x8321 -#endif - -#ifndef GL_SGIX_impact_pixel_texture -#define GL_PIXEL_TEX_GEN_Q_CEILING_SGIX 0x8184 -#define GL_PIXEL_TEX_GEN_Q_ROUND_SGIX 0x8185 -#define GL_PIXEL_TEX_GEN_Q_FLOOR_SGIX 0x8186 -#define GL_PIXEL_TEX_GEN_ALPHA_REPLACE_SGIX 0x8187 -#define GL_PIXEL_TEX_GEN_ALPHA_NO_REPLACE_SGIX 0x8188 -#define GL_PIXEL_TEX_GEN_ALPHA_LS_SGIX 0x8189 -#define GL_PIXEL_TEX_GEN_ALPHA_MS_SGIX 0x818A -#endif - -#ifndef GL_EXT_bgra -#define GL_BGR_EXT 0x80E0 -#define GL_BGRA_EXT 0x80E1 -#endif - -#ifndef GL_SGIX_async -#define GL_ASYNC_MARKER_SGIX 0x8329 -#endif - -#ifndef GL_SGIX_async_pixel -#define GL_ASYNC_TEX_IMAGE_SGIX 0x835C -#define GL_ASYNC_DRAW_PIXELS_SGIX 0x835D -#define GL_ASYNC_READ_PIXELS_SGIX 0x835E -#define GL_MAX_ASYNC_TEX_IMAGE_SGIX 0x835F -#define GL_MAX_ASYNC_DRAW_PIXELS_SGIX 0x8360 -#define GL_MAX_ASYNC_READ_PIXELS_SGIX 0x8361 -#endif - -#ifndef GL_SGIX_async_histogram -#define GL_ASYNC_HISTOGRAM_SGIX 0x832C -#define GL_MAX_ASYNC_HISTOGRAM_SGIX 0x832D -#endif - -#ifndef GL_INTEL_texture_scissor -#endif - -#ifndef GL_INTEL_parallel_arrays -#define GL_PARALLEL_ARRAYS_INTEL 0x83F4 -#define GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL 0x83F5 -#define GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL 0x83F6 -#define GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL 0x83F7 -#define GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL 0x83F8 -#endif - -#ifndef GL_HP_occlusion_test -#define GL_OCCLUSION_TEST_HP 0x8165 -#define GL_OCCLUSION_TEST_RESULT_HP 0x8166 -#endif - -#ifndef GL_EXT_pixel_transform -#define GL_PIXEL_TRANSFORM_2D_EXT 0x8330 -#define GL_PIXEL_MAG_FILTER_EXT 0x8331 -#define GL_PIXEL_MIN_FILTER_EXT 0x8332 -#define GL_PIXEL_CUBIC_WEIGHT_EXT 0x8333 -#define GL_CUBIC_EXT 0x8334 -#define GL_AVERAGE_EXT 0x8335 -#define GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8336 -#define GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8337 -#define GL_PIXEL_TRANSFORM_2D_MATRIX_EXT 0x8338 -#endif - -#ifndef GL_EXT_pixel_transform_color_table -#endif - -#ifndef GL_EXT_shared_texture_palette -#define GL_SHARED_TEXTURE_PALETTE_EXT 0x81FB -#endif - -#ifndef GL_EXT_separate_specular_color -#define GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8 -#define GL_SINGLE_COLOR_EXT 0x81F9 -#define GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA -#endif - -#ifndef GL_EXT_secondary_color -#define GL_COLOR_SUM_EXT 0x8458 -#define GL_CURRENT_SECONDARY_COLOR_EXT 0x8459 -#define GL_SECONDARY_COLOR_ARRAY_SIZE_EXT 0x845A -#define GL_SECONDARY_COLOR_ARRAY_TYPE_EXT 0x845B -#define GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT 0x845C -#define GL_SECONDARY_COLOR_ARRAY_POINTER_EXT 0x845D -#define GL_SECONDARY_COLOR_ARRAY_EXT 0x845E -#endif - -#ifndef GL_EXT_texture_perturb_normal -#define GL_PERTURB_EXT 0x85AE -#define GL_TEXTURE_NORMAL_EXT 0x85AF -#endif - -#ifndef GL_EXT_multi_draw_arrays -#endif - -#ifndef GL_EXT_fog_coord -#define GL_FOG_COORDINATE_SOURCE_EXT 0x8450 -#define GL_FOG_COORDINATE_EXT 0x8451 -#define GL_FRAGMENT_DEPTH_EXT 0x8452 -#define GL_CURRENT_FOG_COORDINATE_EXT 0x8453 -#define GL_FOG_COORDINATE_ARRAY_TYPE_EXT 0x8454 -#define GL_FOG_COORDINATE_ARRAY_STRIDE_EXT 0x8455 -#define GL_FOG_COORDINATE_ARRAY_POINTER_EXT 0x8456 -#define GL_FOG_COORDINATE_ARRAY_EXT 0x8457 -#endif - -#ifndef GL_REND_screen_coordinates -#define GL_SCREEN_COORDINATES_REND 0x8490 -#define GL_INVERTED_SCREEN_W_REND 0x8491 -#endif - -#ifndef GL_EXT_coordinate_frame -#define GL_TANGENT_ARRAY_EXT 0x8439 -#define GL_BINORMAL_ARRAY_EXT 0x843A -#define GL_CURRENT_TANGENT_EXT 0x843B -#define GL_CURRENT_BINORMAL_EXT 0x843C -#define GL_TANGENT_ARRAY_TYPE_EXT 0x843E -#define GL_TANGENT_ARRAY_STRIDE_EXT 0x843F -#define GL_BINORMAL_ARRAY_TYPE_EXT 0x8440 -#define GL_BINORMAL_ARRAY_STRIDE_EXT 0x8441 -#define GL_TANGENT_ARRAY_POINTER_EXT 0x8442 -#define GL_BINORMAL_ARRAY_POINTER_EXT 0x8443 -#define GL_MAP1_TANGENT_EXT 0x8444 -#define GL_MAP2_TANGENT_EXT 0x8445 -#define GL_MAP1_BINORMAL_EXT 0x8446 -#define GL_MAP2_BINORMAL_EXT 0x8447 -#endif - -#ifndef GL_EXT_texture_env_combine -#define GL_COMBINE_EXT 0x8570 -#define GL_COMBINE_RGB_EXT 0x8571 -#define GL_COMBINE_ALPHA_EXT 0x8572 -#define GL_RGB_SCALE_EXT 0x8573 -#define GL_ADD_SIGNED_EXT 0x8574 -#define GL_INTERPOLATE_EXT 0x8575 -#define GL_CONSTANT_EXT 0x8576 -#define GL_PRIMARY_COLOR_EXT 0x8577 -#define GL_PREVIOUS_EXT 0x8578 -#define GL_SOURCE0_RGB_EXT 0x8580 -#define GL_SOURCE1_RGB_EXT 0x8581 -#define GL_SOURCE2_RGB_EXT 0x8582 -#define GL_SOURCE0_ALPHA_EXT 0x8588 -#define GL_SOURCE1_ALPHA_EXT 0x8589 -#define GL_SOURCE2_ALPHA_EXT 0x858A -#define GL_OPERAND0_RGB_EXT 0x8590 -#define GL_OPERAND1_RGB_EXT 0x8591 -#define GL_OPERAND2_RGB_EXT 0x8592 -#define GL_OPERAND0_ALPHA_EXT 0x8598 -#define GL_OPERAND1_ALPHA_EXT 0x8599 -#define GL_OPERAND2_ALPHA_EXT 0x859A -#endif - -#ifndef GL_APPLE_specular_vector -#define GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE 0x85B0 -#endif - -#ifndef GL_APPLE_transform_hint -#define GL_TRANSFORM_HINT_APPLE 0x85B1 -#endif - -#ifndef GL_SGIX_fog_scale -#define GL_FOG_SCALE_SGIX 0x81FC -#define GL_FOG_SCALE_VALUE_SGIX 0x81FD -#endif - -#ifndef GL_SUNX_constant_data -#define GL_UNPACK_CONSTANT_DATA_SUNX 0x81D5 -#define GL_TEXTURE_CONSTANT_DATA_SUNX 0x81D6 -#endif - -#ifndef GL_SUN_global_alpha -#define GL_GLOBAL_ALPHA_SUN 0x81D9 -#define GL_GLOBAL_ALPHA_FACTOR_SUN 0x81DA -#endif - -#ifndef GL_SUN_triangle_list -#define GL_RESTART_SUN 0x0001 -#define GL_REPLACE_MIDDLE_SUN 0x0002 -#define GL_REPLACE_OLDEST_SUN 0x0003 -#define GL_TRIANGLE_LIST_SUN 0x81D7 -#define GL_REPLACEMENT_CODE_SUN 0x81D8 -#define GL_REPLACEMENT_CODE_ARRAY_SUN 0x85C0 -#define GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN 0x85C1 -#define GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN 0x85C2 -#define GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN 0x85C3 -#define GL_R1UI_V3F_SUN 0x85C4 -#define GL_R1UI_C4UB_V3F_SUN 0x85C5 -#define GL_R1UI_C3F_V3F_SUN 0x85C6 -#define GL_R1UI_N3F_V3F_SUN 0x85C7 -#define GL_R1UI_C4F_N3F_V3F_SUN 0x85C8 -#define GL_R1UI_T2F_V3F_SUN 0x85C9 -#define GL_R1UI_T2F_N3F_V3F_SUN 0x85CA -#define GL_R1UI_T2F_C4F_N3F_V3F_SUN 0x85CB -#endif - -#ifndef GL_SUN_vertex -#endif - -#ifndef GL_EXT_blend_func_separate -#define GL_BLEND_DST_RGB_EXT 0x80C8 -#define GL_BLEND_SRC_RGB_EXT 0x80C9 -#define GL_BLEND_DST_ALPHA_EXT 0x80CA -#define GL_BLEND_SRC_ALPHA_EXT 0x80CB -#endif - -#ifndef GL_INGR_color_clamp -#define GL_RED_MIN_CLAMP_INGR 0x8560 -#define GL_GREEN_MIN_CLAMP_INGR 0x8561 -#define GL_BLUE_MIN_CLAMP_INGR 0x8562 -#define GL_ALPHA_MIN_CLAMP_INGR 0x8563 -#define GL_RED_MAX_CLAMP_INGR 0x8564 -#define GL_GREEN_MAX_CLAMP_INGR 0x8565 -#define GL_BLUE_MAX_CLAMP_INGR 0x8566 -#define GL_ALPHA_MAX_CLAMP_INGR 0x8567 -#endif - -#ifndef GL_INGR_interlace_read -#define GL_INTERLACE_READ_INGR 0x8568 -#endif - -#ifndef GL_EXT_stencil_wrap -#define GL_INCR_WRAP_EXT 0x8507 -#define GL_DECR_WRAP_EXT 0x8508 -#endif - -#ifndef GL_EXT_422_pixels -#define GL_422_EXT 0x80CC -#define GL_422_REV_EXT 0x80CD -#define GL_422_AVERAGE_EXT 0x80CE -#define GL_422_REV_AVERAGE_EXT 0x80CF -#endif - -#ifndef GL_NV_texgen_reflection -#define GL_NORMAL_MAP_NV 0x8511 -#define GL_REFLECTION_MAP_NV 0x8512 -#endif - -#ifndef GL_EXT_texture_cube_map -#define GL_NORMAL_MAP_EXT 0x8511 -#define GL_REFLECTION_MAP_EXT 0x8512 -#define GL_TEXTURE_CUBE_MAP_EXT 0x8513 -#define GL_TEXTURE_BINDING_CUBE_MAP_EXT 0x8514 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT 0x8515 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT 0x8516 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT 0x8517 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT 0x8518 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT 0x8519 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT 0x851A -#define GL_PROXY_TEXTURE_CUBE_MAP_EXT 0x851B -#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT 0x851C -#endif - -#ifndef GL_SUN_convolution_border_modes -#define GL_WRAP_BORDER_SUN 0x81D4 -#endif - -#ifndef GL_EXT_texture_env_add -#endif - -#ifndef GL_EXT_texture_lod_bias -#define GL_MAX_TEXTURE_LOD_BIAS_EXT 0x84FD -#define GL_TEXTURE_FILTER_CONTROL_EXT 0x8500 -#define GL_TEXTURE_LOD_BIAS_EXT 0x8501 -#endif - -#ifndef GL_EXT_texture_filter_anisotropic -#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE -#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF -#endif - -#ifndef GL_EXT_vertex_weighting -#define GL_MODELVIEW0_STACK_DEPTH_EXT GL_MODELVIEW_STACK_DEPTH -#define GL_MODELVIEW1_STACK_DEPTH_EXT 0x8502 -#define GL_MODELVIEW0_MATRIX_EXT GL_MODELVIEW_MATRIX -#define GL_MODELVIEW1_MATRIX_EXT 0x8506 -#define GL_VERTEX_WEIGHTING_EXT 0x8509 -#define GL_MODELVIEW0_EXT GL_MODELVIEW -#define GL_MODELVIEW1_EXT 0x850A -#define GL_CURRENT_VERTEX_WEIGHT_EXT 0x850B -#define GL_VERTEX_WEIGHT_ARRAY_EXT 0x850C -#define GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT 0x850D -#define GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT 0x850E -#define GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT 0x850F -#define GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT 0x8510 -#endif - -#ifndef GL_NV_light_max_exponent -#define GL_MAX_SHININESS_NV 0x8504 -#define GL_MAX_SPOT_EXPONENT_NV 0x8505 -#endif - -#ifndef GL_NV_vertex_array_range -#define GL_VERTEX_ARRAY_RANGE_NV 0x851D -#define GL_VERTEX_ARRAY_RANGE_LENGTH_NV 0x851E -#define GL_VERTEX_ARRAY_RANGE_VALID_NV 0x851F -#define GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV 0x8520 -#define GL_VERTEX_ARRAY_RANGE_POINTER_NV 0x8521 -#endif - -#ifndef GL_NV_register_combiners -#define GL_REGISTER_COMBINERS_NV 0x8522 -#define GL_VARIABLE_A_NV 0x8523 -#define GL_VARIABLE_B_NV 0x8524 -#define GL_VARIABLE_C_NV 0x8525 -#define GL_VARIABLE_D_NV 0x8526 -#define GL_VARIABLE_E_NV 0x8527 -#define GL_VARIABLE_F_NV 0x8528 -#define GL_VARIABLE_G_NV 0x8529 -#define GL_CONSTANT_COLOR0_NV 0x852A -#define GL_CONSTANT_COLOR1_NV 0x852B -#define GL_PRIMARY_COLOR_NV 0x852C -#define GL_SECONDARY_COLOR_NV 0x852D -#define GL_SPARE0_NV 0x852E -#define GL_SPARE1_NV 0x852F -#define GL_DISCARD_NV 0x8530 -#define GL_E_TIMES_F_NV 0x8531 -#define GL_SPARE0_PLUS_SECONDARY_COLOR_NV 0x8532 -#define GL_UNSIGNED_IDENTITY_NV 0x8536 -#define GL_UNSIGNED_INVERT_NV 0x8537 -#define GL_EXPAND_NORMAL_NV 0x8538 -#define GL_EXPAND_NEGATE_NV 0x8539 -#define GL_HALF_BIAS_NORMAL_NV 0x853A -#define GL_HALF_BIAS_NEGATE_NV 0x853B -#define GL_SIGNED_IDENTITY_NV 0x853C -#define GL_SIGNED_NEGATE_NV 0x853D -#define GL_SCALE_BY_TWO_NV 0x853E -#define GL_SCALE_BY_FOUR_NV 0x853F -#define GL_SCALE_BY_ONE_HALF_NV 0x8540 -#define GL_BIAS_BY_NEGATIVE_ONE_HALF_NV 0x8541 -#define GL_COMBINER_INPUT_NV 0x8542 -#define GL_COMBINER_MAPPING_NV 0x8543 -#define GL_COMBINER_COMPONENT_USAGE_NV 0x8544 -#define GL_COMBINER_AB_DOT_PRODUCT_NV 0x8545 -#define GL_COMBINER_CD_DOT_PRODUCT_NV 0x8546 -#define GL_COMBINER_MUX_SUM_NV 0x8547 -#define GL_COMBINER_SCALE_NV 0x8548 -#define GL_COMBINER_BIAS_NV 0x8549 -#define GL_COMBINER_AB_OUTPUT_NV 0x854A -#define GL_COMBINER_CD_OUTPUT_NV 0x854B -#define GL_COMBINER_SUM_OUTPUT_NV 0x854C -#define GL_MAX_GENERAL_COMBINERS_NV 0x854D -#define GL_NUM_GENERAL_COMBINERS_NV 0x854E -#define GL_COLOR_SUM_CLAMP_NV 0x854F -#define GL_COMBINER0_NV 0x8550 -#define GL_COMBINER1_NV 0x8551 -#define GL_COMBINER2_NV 0x8552 -#define GL_COMBINER3_NV 0x8553 -#define GL_COMBINER4_NV 0x8554 -#define GL_COMBINER5_NV 0x8555 -#define GL_COMBINER6_NV 0x8556 -#define GL_COMBINER7_NV 0x8557 -/* reuse GL_TEXTURE0_ARB */ -/* reuse GL_TEXTURE1_ARB */ -/* reuse GL_ZERO */ -/* reuse GL_NONE */ -/* reuse GL_FOG */ -#endif - -#ifndef GL_NV_fog_distance -#define GL_FOG_DISTANCE_MODE_NV 0x855A -#define GL_EYE_RADIAL_NV 0x855B -#define GL_EYE_PLANE_ABSOLUTE_NV 0x855C -/* reuse GL_EYE_PLANE */ -#endif - -#ifndef GL_NV_texgen_emboss -#define GL_EMBOSS_LIGHT_NV 0x855D -#define GL_EMBOSS_CONSTANT_NV 0x855E -#define GL_EMBOSS_MAP_NV 0x855F -#endif - -#ifndef GL_NV_blend_square -#endif - -#ifndef GL_NV_texture_env_combine4 -#define GL_COMBINE4_NV 0x8503 -#define GL_SOURCE3_RGB_NV 0x8583 -#define GL_SOURCE3_ALPHA_NV 0x858B -#define GL_OPERAND3_RGB_NV 0x8593 -#define GL_OPERAND3_ALPHA_NV 0x859B -#endif - -#ifndef GL_MESA_resize_buffers -#endif - -#ifndef GL_MESA_window_pos -#endif - -#ifndef GL_EXT_texture_compression_s3tc -#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 -#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 -#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 -#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 -#endif - -#ifndef GL_IBM_cull_vertex -#define GL_CULL_VERTEX_IBM 103050 -#endif - -#ifndef GL_IBM_multimode_draw_arrays -#endif - -#ifndef GL_IBM_vertex_array_lists -#define GL_VERTEX_ARRAY_LIST_IBM 103070 -#define GL_NORMAL_ARRAY_LIST_IBM 103071 -#define GL_COLOR_ARRAY_LIST_IBM 103072 -#define GL_INDEX_ARRAY_LIST_IBM 103073 -#define GL_TEXTURE_COORD_ARRAY_LIST_IBM 103074 -#define GL_EDGE_FLAG_ARRAY_LIST_IBM 103075 -#define GL_FOG_COORDINATE_ARRAY_LIST_IBM 103076 -#define GL_SECONDARY_COLOR_ARRAY_LIST_IBM 103077 -#define GL_VERTEX_ARRAY_LIST_STRIDE_IBM 103080 -#define GL_NORMAL_ARRAY_LIST_STRIDE_IBM 103081 -#define GL_COLOR_ARRAY_LIST_STRIDE_IBM 103082 -#define GL_INDEX_ARRAY_LIST_STRIDE_IBM 103083 -#define GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM 103084 -#define GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM 103085 -#define GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM 103086 -#define GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM 103087 -#endif - -#ifndef GL_SGIX_subsample -#define GL_PACK_SUBSAMPLE_RATE_SGIX 0x85A0 -#define GL_UNPACK_SUBSAMPLE_RATE_SGIX 0x85A1 -#define GL_PIXEL_SUBSAMPLE_4444_SGIX 0x85A2 -#define GL_PIXEL_SUBSAMPLE_2424_SGIX 0x85A3 -#define GL_PIXEL_SUBSAMPLE_4242_SGIX 0x85A4 -#endif - -#ifndef GL_SGIX_ycrcb_subsample -#endif - -#ifndef GL_SGIX_ycrcba -#define GL_YCRCB_SGIX 0x8318 -#define GL_YCRCBA_SGIX 0x8319 -#endif - -#ifndef GL_SGI_depth_pass_instrument -#define GL_DEPTH_PASS_INSTRUMENT_SGIX 0x8310 -#define GL_DEPTH_PASS_INSTRUMENT_COUNTERS_SGIX 0x8311 -#define GL_DEPTH_PASS_INSTRUMENT_MAX_SGIX 0x8312 -#endif - -#ifndef GL_3DFX_texture_compression_FXT1 -#define GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0 -#define GL_COMPRESSED_RGBA_FXT1_3DFX 0x86B1 -#endif - -#ifndef GL_3DFX_multisample -#define GL_MULTISAMPLE_3DFX 0x86B2 -#define GL_SAMPLE_BUFFERS_3DFX 0x86B3 -#define GL_SAMPLES_3DFX 0x86B4 -#define GL_MULTISAMPLE_BIT_3DFX 0x20000000 -#endif - -#ifndef GL_3DFX_tbuffer -#endif - -#ifndef GL_EXT_multisample -#define GL_MULTISAMPLE_EXT 0x809D -#define GL_SAMPLE_ALPHA_TO_MASK_EXT 0x809E -#define GL_SAMPLE_ALPHA_TO_ONE_EXT 0x809F -#define GL_SAMPLE_MASK_EXT 0x80A0 -#define GL_1PASS_EXT 0x80A1 -#define GL_2PASS_0_EXT 0x80A2 -#define GL_2PASS_1_EXT 0x80A3 -#define GL_4PASS_0_EXT 0x80A4 -#define GL_4PASS_1_EXT 0x80A5 -#define GL_4PASS_2_EXT 0x80A6 -#define GL_4PASS_3_EXT 0x80A7 -#define GL_SAMPLE_BUFFERS_EXT 0x80A8 -#define GL_SAMPLES_EXT 0x80A9 -#define GL_SAMPLE_MASK_VALUE_EXT 0x80AA -#define GL_SAMPLE_MASK_INVERT_EXT 0x80AB -#define GL_SAMPLE_PATTERN_EXT 0x80AC -#define GL_MULTISAMPLE_BIT_EXT 0x20000000 -#endif - -#ifndef GL_SGIX_vertex_preclip -#define GL_VERTEX_PRECLIP_SGIX 0x83EE -#define GL_VERTEX_PRECLIP_HINT_SGIX 0x83EF -#endif - -#ifndef GL_SGIX_convolution_accuracy -#define GL_CONVOLUTION_HINT_SGIX 0x8316 -#endif - -#ifndef GL_SGIX_resample -#define GL_PACK_RESAMPLE_SGIX 0x842C -#define GL_UNPACK_RESAMPLE_SGIX 0x842D -#define GL_RESAMPLE_REPLICATE_SGIX 0x842E -#define GL_RESAMPLE_ZERO_FILL_SGIX 0x842F -#define GL_RESAMPLE_DECIMATE_SGIX 0x8430 -#endif - -#ifndef GL_SGIS_point_line_texgen -#define GL_EYE_DISTANCE_TO_POINT_SGIS 0x81F0 -#define GL_OBJECT_DISTANCE_TO_POINT_SGIS 0x81F1 -#define GL_EYE_DISTANCE_TO_LINE_SGIS 0x81F2 -#define GL_OBJECT_DISTANCE_TO_LINE_SGIS 0x81F3 -#define GL_EYE_POINT_SGIS 0x81F4 -#define GL_OBJECT_POINT_SGIS 0x81F5 -#define GL_EYE_LINE_SGIS 0x81F6 -#define GL_OBJECT_LINE_SGIS 0x81F7 -#endif - -#ifndef GL_SGIS_texture_color_mask -#define GL_TEXTURE_COLOR_WRITEMASK_SGIS 0x81EF -#endif - -#ifndef GL_EXT_texture_env_dot3 -#define GL_DOT3_RGB_EXT 0x8740 -#define GL_DOT3_RGBA_EXT 0x8741 -#endif - -#ifndef GL_ATI_texture_mirror_once -#define GL_MIRROR_CLAMP_ATI 0x8742 -#define GL_MIRROR_CLAMP_TO_EDGE_ATI 0x8743 -#endif - -#ifndef GL_NV_fence -#define GL_ALL_COMPLETED_NV 0x84F2 -#define GL_FENCE_STATUS_NV 0x84F3 -#define GL_FENCE_CONDITION_NV 0x84F4 -#endif - -#ifndef GL_IBM_texture_mirrored_repeat -#define GL_MIRRORED_REPEAT_IBM 0x8370 -#endif - -#ifndef GL_NV_evaluators -#define GL_EVAL_2D_NV 0x86C0 -#define GL_EVAL_TRIANGULAR_2D_NV 0x86C1 -#define GL_MAP_TESSELLATION_NV 0x86C2 -#define GL_MAP_ATTRIB_U_ORDER_NV 0x86C3 -#define GL_MAP_ATTRIB_V_ORDER_NV 0x86C4 -#define GL_EVAL_FRACTIONAL_TESSELLATION_NV 0x86C5 -#define GL_EVAL_VERTEX_ATTRIB0_NV 0x86C6 -#define GL_EVAL_VERTEX_ATTRIB1_NV 0x86C7 -#define GL_EVAL_VERTEX_ATTRIB2_NV 0x86C8 -#define GL_EVAL_VERTEX_ATTRIB3_NV 0x86C9 -#define GL_EVAL_VERTEX_ATTRIB4_NV 0x86CA -#define GL_EVAL_VERTEX_ATTRIB5_NV 0x86CB -#define GL_EVAL_VERTEX_ATTRIB6_NV 0x86CC -#define GL_EVAL_VERTEX_ATTRIB7_NV 0x86CD -#define GL_EVAL_VERTEX_ATTRIB8_NV 0x86CE -#define GL_EVAL_VERTEX_ATTRIB9_NV 0x86CF -#define GL_EVAL_VERTEX_ATTRIB10_NV 0x86D0 -#define GL_EVAL_VERTEX_ATTRIB11_NV 0x86D1 -#define GL_EVAL_VERTEX_ATTRIB12_NV 0x86D2 -#define GL_EVAL_VERTEX_ATTRIB13_NV 0x86D3 -#define GL_EVAL_VERTEX_ATTRIB14_NV 0x86D4 -#define GL_EVAL_VERTEX_ATTRIB15_NV 0x86D5 -#define GL_MAX_MAP_TESSELLATION_NV 0x86D6 -#define GL_MAX_RATIONAL_EVAL_ORDER_NV 0x86D7 -#endif - -#ifndef GL_NV_packed_depth_stencil -#define GL_DEPTH_STENCIL_NV 0x84F9 -#define GL_UNSIGNED_INT_24_8_NV 0x84FA -#endif - -#ifndef GL_NV_register_combiners2 -#define GL_PER_STAGE_CONSTANTS_NV 0x8535 -#endif - -#ifndef GL_NV_texture_compression_vtc -#endif - -#ifndef GL_NV_texture_rectangle -#define GL_TEXTURE_RECTANGLE_NV 0x84F5 -#define GL_TEXTURE_BINDING_RECTANGLE_NV 0x84F6 -#define GL_PROXY_TEXTURE_RECTANGLE_NV 0x84F7 -#define GL_MAX_RECTANGLE_TEXTURE_SIZE_NV 0x84F8 -#endif - -#ifndef GL_NV_texture_shader -#define GL_OFFSET_TEXTURE_RECTANGLE_NV 0x864C -#define GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV 0x864D -#define GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV 0x864E -#define GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV 0x86D9 -#define GL_UNSIGNED_INT_S8_S8_8_8_NV 0x86DA -#define GL_UNSIGNED_INT_8_8_S8_S8_REV_NV 0x86DB -#define GL_DSDT_MAG_INTENSITY_NV 0x86DC -#define GL_SHADER_CONSISTENT_NV 0x86DD -#define GL_TEXTURE_SHADER_NV 0x86DE -#define GL_SHADER_OPERATION_NV 0x86DF -#define GL_CULL_MODES_NV 0x86E0 -#define GL_OFFSET_TEXTURE_MATRIX_NV 0x86E1 -#define GL_OFFSET_TEXTURE_SCALE_NV 0x86E2 -#define GL_OFFSET_TEXTURE_BIAS_NV 0x86E3 -#define GL_OFFSET_TEXTURE_2D_MATRIX_NV GL_OFFSET_TEXTURE_MATRIX_NV -#define GL_OFFSET_TEXTURE_2D_SCALE_NV GL_OFFSET_TEXTURE_SCALE_NV -#define GL_OFFSET_TEXTURE_2D_BIAS_NV GL_OFFSET_TEXTURE_BIAS_NV -#define GL_PREVIOUS_TEXTURE_INPUT_NV 0x86E4 -#define GL_CONST_EYE_NV 0x86E5 -#define GL_PASS_THROUGH_NV 0x86E6 -#define GL_CULL_FRAGMENT_NV 0x86E7 -#define GL_OFFSET_TEXTURE_2D_NV 0x86E8 -#define GL_DEPENDENT_AR_TEXTURE_2D_NV 0x86E9 -#define GL_DEPENDENT_GB_TEXTURE_2D_NV 0x86EA -#define GL_DOT_PRODUCT_NV 0x86EC -#define GL_DOT_PRODUCT_DEPTH_REPLACE_NV 0x86ED -#define GL_DOT_PRODUCT_TEXTURE_2D_NV 0x86EE -#define GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV 0x86F0 -#define GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV 0x86F1 -#define GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV 0x86F2 -#define GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV 0x86F3 -#define GL_HILO_NV 0x86F4 -#define GL_DSDT_NV 0x86F5 -#define GL_DSDT_MAG_NV 0x86F6 -#define GL_DSDT_MAG_VIB_NV 0x86F7 -#define GL_HILO16_NV 0x86F8 -#define GL_SIGNED_HILO_NV 0x86F9 -#define GL_SIGNED_HILO16_NV 0x86FA -#define GL_SIGNED_RGBA_NV 0x86FB -#define GL_SIGNED_RGBA8_NV 0x86FC -#define GL_SIGNED_RGB_NV 0x86FE -#define GL_SIGNED_RGB8_NV 0x86FF -#define GL_SIGNED_LUMINANCE_NV 0x8701 -#define GL_SIGNED_LUMINANCE8_NV 0x8702 -#define GL_SIGNED_LUMINANCE_ALPHA_NV 0x8703 -#define GL_SIGNED_LUMINANCE8_ALPHA8_NV 0x8704 -#define GL_SIGNED_ALPHA_NV 0x8705 -#define GL_SIGNED_ALPHA8_NV 0x8706 -#define GL_SIGNED_INTENSITY_NV 0x8707 -#define GL_SIGNED_INTENSITY8_NV 0x8708 -#define GL_DSDT8_NV 0x8709 -#define GL_DSDT8_MAG8_NV 0x870A -#define GL_DSDT8_MAG8_INTENSITY8_NV 0x870B -#define GL_SIGNED_RGB_UNSIGNED_ALPHA_NV 0x870C -#define GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV 0x870D -#define GL_HI_SCALE_NV 0x870E -#define GL_LO_SCALE_NV 0x870F -#define GL_DS_SCALE_NV 0x8710 -#define GL_DT_SCALE_NV 0x8711 -#define GL_MAGNITUDE_SCALE_NV 0x8712 -#define GL_VIBRANCE_SCALE_NV 0x8713 -#define GL_HI_BIAS_NV 0x8714 -#define GL_LO_BIAS_NV 0x8715 -#define GL_DS_BIAS_NV 0x8716 -#define GL_DT_BIAS_NV 0x8717 -#define GL_MAGNITUDE_BIAS_NV 0x8718 -#define GL_VIBRANCE_BIAS_NV 0x8719 -#define GL_TEXTURE_BORDER_VALUES_NV 0x871A -#define GL_TEXTURE_HI_SIZE_NV 0x871B -#define GL_TEXTURE_LO_SIZE_NV 0x871C -#define GL_TEXTURE_DS_SIZE_NV 0x871D -#define GL_TEXTURE_DT_SIZE_NV 0x871E -#define GL_TEXTURE_MAG_SIZE_NV 0x871F -#endif - -#ifndef GL_NV_texture_shader2 -#define GL_DOT_PRODUCT_TEXTURE_3D_NV 0x86EF -#endif - -#ifndef GL_NV_vertex_array_range2 -#define GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV 0x8533 -#endif - -#ifndef GL_NV_vertex_program -#define GL_VERTEX_PROGRAM_NV 0x8620 -#define GL_VERTEX_STATE_PROGRAM_NV 0x8621 -#define GL_ATTRIB_ARRAY_SIZE_NV 0x8623 -#define GL_ATTRIB_ARRAY_STRIDE_NV 0x8624 -#define GL_ATTRIB_ARRAY_TYPE_NV 0x8625 -#define GL_CURRENT_ATTRIB_NV 0x8626 -#define GL_PROGRAM_LENGTH_NV 0x8627 -#define GL_PROGRAM_STRING_NV 0x8628 -#define GL_MODELVIEW_PROJECTION_NV 0x8629 -#define GL_IDENTITY_NV 0x862A -#define GL_INVERSE_NV 0x862B -#define GL_TRANSPOSE_NV 0x862C -#define GL_INVERSE_TRANSPOSE_NV 0x862D -#define GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV 0x862E -#define GL_MAX_TRACK_MATRICES_NV 0x862F -#define GL_MATRIX0_NV 0x8630 -#define GL_MATRIX1_NV 0x8631 -#define GL_MATRIX2_NV 0x8632 -#define GL_MATRIX3_NV 0x8633 -#define GL_MATRIX4_NV 0x8634 -#define GL_MATRIX5_NV 0x8635 -#define GL_MATRIX6_NV 0x8636 -#define GL_MATRIX7_NV 0x8637 -#define GL_CURRENT_MATRIX_STACK_DEPTH_NV 0x8640 -#define GL_CURRENT_MATRIX_NV 0x8641 -#define GL_VERTEX_PROGRAM_POINT_SIZE_NV 0x8642 -#define GL_VERTEX_PROGRAM_TWO_SIDE_NV 0x8643 -#define GL_PROGRAM_PARAMETER_NV 0x8644 -#define GL_ATTRIB_ARRAY_POINTER_NV 0x8645 -#define GL_PROGRAM_TARGET_NV 0x8646 -#define GL_PROGRAM_RESIDENT_NV 0x8647 -#define GL_TRACK_MATRIX_NV 0x8648 -#define GL_TRACK_MATRIX_TRANSFORM_NV 0x8649 -#define GL_VERTEX_PROGRAM_BINDING_NV 0x864A -#define GL_PROGRAM_ERROR_POSITION_NV 0x864B -#define GL_VERTEX_ATTRIB_ARRAY0_NV 0x8650 -#define GL_VERTEX_ATTRIB_ARRAY1_NV 0x8651 -#define GL_VERTEX_ATTRIB_ARRAY2_NV 0x8652 -#define GL_VERTEX_ATTRIB_ARRAY3_NV 0x8653 -#define GL_VERTEX_ATTRIB_ARRAY4_NV 0x8654 -#define GL_VERTEX_ATTRIB_ARRAY5_NV 0x8655 -#define GL_VERTEX_ATTRIB_ARRAY6_NV 0x8656 -#define GL_VERTEX_ATTRIB_ARRAY7_NV 0x8657 -#define GL_VERTEX_ATTRIB_ARRAY8_NV 0x8658 -#define GL_VERTEX_ATTRIB_ARRAY9_NV 0x8659 -#define GL_VERTEX_ATTRIB_ARRAY10_NV 0x865A -#define GL_VERTEX_ATTRIB_ARRAY11_NV 0x865B -#define GL_VERTEX_ATTRIB_ARRAY12_NV 0x865C -#define GL_VERTEX_ATTRIB_ARRAY13_NV 0x865D -#define GL_VERTEX_ATTRIB_ARRAY14_NV 0x865E -#define GL_VERTEX_ATTRIB_ARRAY15_NV 0x865F -#define GL_MAP1_VERTEX_ATTRIB0_4_NV 0x8660 -#define GL_MAP1_VERTEX_ATTRIB1_4_NV 0x8661 -#define GL_MAP1_VERTEX_ATTRIB2_4_NV 0x8662 -#define GL_MAP1_VERTEX_ATTRIB3_4_NV 0x8663 -#define GL_MAP1_VERTEX_ATTRIB4_4_NV 0x8664 -#define GL_MAP1_VERTEX_ATTRIB5_4_NV 0x8665 -#define GL_MAP1_VERTEX_ATTRIB6_4_NV 0x8666 -#define GL_MAP1_VERTEX_ATTRIB7_4_NV 0x8667 -#define GL_MAP1_VERTEX_ATTRIB8_4_NV 0x8668 -#define GL_MAP1_VERTEX_ATTRIB9_4_NV 0x8669 -#define GL_MAP1_VERTEX_ATTRIB10_4_NV 0x866A -#define GL_MAP1_VERTEX_ATTRIB11_4_NV 0x866B -#define GL_MAP1_VERTEX_ATTRIB12_4_NV 0x866C -#define GL_MAP1_VERTEX_ATTRIB13_4_NV 0x866D -#define GL_MAP1_VERTEX_ATTRIB14_4_NV 0x866E -#define GL_MAP1_VERTEX_ATTRIB15_4_NV 0x866F -#define GL_MAP2_VERTEX_ATTRIB0_4_NV 0x8670 -#define GL_MAP2_VERTEX_ATTRIB1_4_NV 0x8671 -#define GL_MAP2_VERTEX_ATTRIB2_4_NV 0x8672 -#define GL_MAP2_VERTEX_ATTRIB3_4_NV 0x8673 -#define GL_MAP2_VERTEX_ATTRIB4_4_NV 0x8674 -#define GL_MAP2_VERTEX_ATTRIB5_4_NV 0x8675 -#define GL_MAP2_VERTEX_ATTRIB6_4_NV 0x8676 -#define GL_MAP2_VERTEX_ATTRIB7_4_NV 0x8677 -#define GL_MAP2_VERTEX_ATTRIB8_4_NV 0x8678 -#define GL_MAP2_VERTEX_ATTRIB9_4_NV 0x8679 -#define GL_MAP2_VERTEX_ATTRIB10_4_NV 0x867A -#define GL_MAP2_VERTEX_ATTRIB11_4_NV 0x867B -#define GL_MAP2_VERTEX_ATTRIB12_4_NV 0x867C -#define GL_MAP2_VERTEX_ATTRIB13_4_NV 0x867D -#define GL_MAP2_VERTEX_ATTRIB14_4_NV 0x867E -#define GL_MAP2_VERTEX_ATTRIB15_4_NV 0x867F -#endif - -#ifndef GL_SGIX_texture_coordinate_clamp -#define GL_TEXTURE_MAX_CLAMP_S_SGIX 0x8369 -#define GL_TEXTURE_MAX_CLAMP_T_SGIX 0x836A -#define GL_TEXTURE_MAX_CLAMP_R_SGIX 0x836B -#endif - -#ifndef GL_SGIX_scalebias_hint -#define GL_SCALEBIAS_HINT_SGIX 0x8322 -#endif - -#ifndef GL_OML_interlace -#define GL_INTERLACE_OML 0x8980 -#define GL_INTERLACE_READ_OML 0x8981 -#endif - -#ifndef GL_OML_subsample -#define GL_FORMAT_SUBSAMPLE_24_24_OML 0x8982 -#define GL_FORMAT_SUBSAMPLE_244_244_OML 0x8983 -#endif - -#ifndef GL_OML_resample -#define GL_PACK_RESAMPLE_OML 0x8984 -#define GL_UNPACK_RESAMPLE_OML 0x8985 -#define GL_RESAMPLE_REPLICATE_OML 0x8986 -#define GL_RESAMPLE_ZERO_FILL_OML 0x8987 -#define GL_RESAMPLE_AVERAGE_OML 0x8988 -#define GL_RESAMPLE_DECIMATE_OML 0x8989 -#endif - -#ifndef GL_NV_copy_depth_to_color -#define GL_DEPTH_STENCIL_TO_RGBA_NV 0x886E -#define GL_DEPTH_STENCIL_TO_BGRA_NV 0x886F -#endif - -#ifndef GL_ATI_envmap_bumpmap -#define GL_BUMP_ROT_MATRIX_ATI 0x8775 -#define GL_BUMP_ROT_MATRIX_SIZE_ATI 0x8776 -#define GL_BUMP_NUM_TEX_UNITS_ATI 0x8777 -#define GL_BUMP_TEX_UNITS_ATI 0x8778 -#define GL_DUDV_ATI 0x8779 -#define GL_DU8DV8_ATI 0x877A -#define GL_BUMP_ENVMAP_ATI 0x877B -#define GL_BUMP_TARGET_ATI 0x877C -#endif - -#ifndef GL_ATI_fragment_shader -#define GL_FRAGMENT_SHADER_ATI 0x8920 -#define GL_REG_0_ATI 0x8921 -#define GL_REG_1_ATI 0x8922 -#define GL_REG_2_ATI 0x8923 -#define GL_REG_3_ATI 0x8924 -#define GL_REG_4_ATI 0x8925 -#define GL_REG_5_ATI 0x8926 -#define GL_REG_6_ATI 0x8927 -#define GL_REG_7_ATI 0x8928 -#define GL_REG_8_ATI 0x8929 -#define GL_REG_9_ATI 0x892A -#define GL_REG_10_ATI 0x892B -#define GL_REG_11_ATI 0x892C -#define GL_REG_12_ATI 0x892D -#define GL_REG_13_ATI 0x892E -#define GL_REG_14_ATI 0x892F -#define GL_REG_15_ATI 0x8930 -#define GL_REG_16_ATI 0x8931 -#define GL_REG_17_ATI 0x8932 -#define GL_REG_18_ATI 0x8933 -#define GL_REG_19_ATI 0x8934 -#define GL_REG_20_ATI 0x8935 -#define GL_REG_21_ATI 0x8936 -#define GL_REG_22_ATI 0x8937 -#define GL_REG_23_ATI 0x8938 -#define GL_REG_24_ATI 0x8939 -#define GL_REG_25_ATI 0x893A -#define GL_REG_26_ATI 0x893B -#define GL_REG_27_ATI 0x893C -#define GL_REG_28_ATI 0x893D -#define GL_REG_29_ATI 0x893E -#define GL_REG_30_ATI 0x893F -#define GL_REG_31_ATI 0x8940 -#define GL_CON_0_ATI 0x8941 -#define GL_CON_1_ATI 0x8942 -#define GL_CON_2_ATI 0x8943 -#define GL_CON_3_ATI 0x8944 -#define GL_CON_4_ATI 0x8945 -#define GL_CON_5_ATI 0x8946 -#define GL_CON_6_ATI 0x8947 -#define GL_CON_7_ATI 0x8948 -#define GL_CON_8_ATI 0x8949 -#define GL_CON_9_ATI 0x894A -#define GL_CON_10_ATI 0x894B -#define GL_CON_11_ATI 0x894C -#define GL_CON_12_ATI 0x894D -#define GL_CON_13_ATI 0x894E -#define GL_CON_14_ATI 0x894F -#define GL_CON_15_ATI 0x8950 -#define GL_CON_16_ATI 0x8951 -#define GL_CON_17_ATI 0x8952 -#define GL_CON_18_ATI 0x8953 -#define GL_CON_19_ATI 0x8954 -#define GL_CON_20_ATI 0x8955 -#define GL_CON_21_ATI 0x8956 -#define GL_CON_22_ATI 0x8957 -#define GL_CON_23_ATI 0x8958 -#define GL_CON_24_ATI 0x8959 -#define GL_CON_25_ATI 0x895A -#define GL_CON_26_ATI 0x895B -#define GL_CON_27_ATI 0x895C -#define GL_CON_28_ATI 0x895D -#define GL_CON_29_ATI 0x895E -#define GL_CON_30_ATI 0x895F -#define GL_CON_31_ATI 0x8960 -#define GL_MOV_ATI 0x8961 -#define GL_ADD_ATI 0x8963 -#define GL_MUL_ATI 0x8964 -#define GL_SUB_ATI 0x8965 -#define GL_DOT3_ATI 0x8966 -#define GL_DOT4_ATI 0x8967 -#define GL_MAD_ATI 0x8968 -#define GL_LERP_ATI 0x8969 -#define GL_CND_ATI 0x896A -#define GL_CND0_ATI 0x896B -#define GL_DOT2_ADD_ATI 0x896C -#define GL_SECONDARY_INTERPOLATOR_ATI 0x896D -#define GL_NUM_FRAGMENT_REGISTERS_ATI 0x896E -#define GL_NUM_FRAGMENT_CONSTANTS_ATI 0x896F -#define GL_NUM_PASSES_ATI 0x8970 -#define GL_NUM_INSTRUCTIONS_PER_PASS_ATI 0x8971 -#define GL_NUM_INSTRUCTIONS_TOTAL_ATI 0x8972 -#define GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI 0x8973 -#define GL_NUM_LOOPBACK_COMPONENTS_ATI 0x8974 -#define GL_COLOR_ALPHA_PAIRING_ATI 0x8975 -#define GL_SWIZZLE_STR_ATI 0x8976 -#define GL_SWIZZLE_STQ_ATI 0x8977 -#define GL_SWIZZLE_STR_DR_ATI 0x8978 -#define GL_SWIZZLE_STQ_DQ_ATI 0x8979 -#define GL_SWIZZLE_STRQ_ATI 0x897A -#define GL_SWIZZLE_STRQ_DQ_ATI 0x897B -#define GL_RED_BIT_ATI 0x00000001 -#define GL_GREEN_BIT_ATI 0x00000002 -#define GL_BLUE_BIT_ATI 0x00000004 -#define GL_2X_BIT_ATI 0x00000001 -#define GL_4X_BIT_ATI 0x00000002 -#define GL_8X_BIT_ATI 0x00000004 -#define GL_HALF_BIT_ATI 0x00000008 -#define GL_QUARTER_BIT_ATI 0x00000010 -#define GL_EIGHTH_BIT_ATI 0x00000020 -#define GL_SATURATE_BIT_ATI 0x00000040 -#define GL_COMP_BIT_ATI 0x00000002 -#define GL_NEGATE_BIT_ATI 0x00000004 -#define GL_BIAS_BIT_ATI 0x00000008 -#endif - -#ifndef GL_ATI_pn_triangles -#define GL_PN_TRIANGLES_ATI 0x87F0 -#define GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F1 -#define GL_PN_TRIANGLES_POINT_MODE_ATI 0x87F2 -#define GL_PN_TRIANGLES_NORMAL_MODE_ATI 0x87F3 -#define GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F4 -#define GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI 0x87F5 -#define GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI 0x87F6 -#define GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI 0x87F7 -#define GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI 0x87F8 -#endif - -#ifndef GL_ATI_vertex_array_object -#define GL_STATIC_ATI 0x8760 -#define GL_DYNAMIC_ATI 0x8761 -#define GL_PRESERVE_ATI 0x8762 -#define GL_DISCARD_ATI 0x8763 -#define GL_OBJECT_BUFFER_SIZE_ATI 0x8764 -#define GL_OBJECT_BUFFER_USAGE_ATI 0x8765 -#define GL_ARRAY_OBJECT_BUFFER_ATI 0x8766 -#define GL_ARRAY_OBJECT_OFFSET_ATI 0x8767 -#endif - -#ifndef GL_EXT_vertex_shader -#define GL_VERTEX_SHADER_EXT 0x8780 -#define GL_VERTEX_SHADER_BINDING_EXT 0x8781 -#define GL_OP_INDEX_EXT 0x8782 -#define GL_OP_NEGATE_EXT 0x8783 -#define GL_OP_DOT3_EXT 0x8784 -#define GL_OP_DOT4_EXT 0x8785 -#define GL_OP_MUL_EXT 0x8786 -#define GL_OP_ADD_EXT 0x8787 -#define GL_OP_MADD_EXT 0x8788 -#define GL_OP_FRAC_EXT 0x8789 -#define GL_OP_MAX_EXT 0x878A -#define GL_OP_MIN_EXT 0x878B -#define GL_OP_SET_GE_EXT 0x878C -#define GL_OP_SET_LT_EXT 0x878D -#define GL_OP_CLAMP_EXT 0x878E -#define GL_OP_FLOOR_EXT 0x878F -#define GL_OP_ROUND_EXT 0x8790 -#define GL_OP_EXP_BASE_2_EXT 0x8791 -#define GL_OP_LOG_BASE_2_EXT 0x8792 -#define GL_OP_POWER_EXT 0x8793 -#define GL_OP_RECIP_EXT 0x8794 -#define GL_OP_RECIP_SQRT_EXT 0x8795 -#define GL_OP_SUB_EXT 0x8796 -#define GL_OP_CROSS_PRODUCT_EXT 0x8797 -#define GL_OP_MULTIPLY_MATRIX_EXT 0x8798 -#define GL_OP_MOV_EXT 0x8799 -#define GL_OUTPUT_VERTEX_EXT 0x879A -#define GL_OUTPUT_COLOR0_EXT 0x879B -#define GL_OUTPUT_COLOR1_EXT 0x879C -#define GL_OUTPUT_TEXTURE_COORD0_EXT 0x879D -#define GL_OUTPUT_TEXTURE_COORD1_EXT 0x879E -#define GL_OUTPUT_TEXTURE_COORD2_EXT 0x879F -#define GL_OUTPUT_TEXTURE_COORD3_EXT 0x87A0 -#define GL_OUTPUT_TEXTURE_COORD4_EXT 0x87A1 -#define GL_OUTPUT_TEXTURE_COORD5_EXT 0x87A2 -#define GL_OUTPUT_TEXTURE_COORD6_EXT 0x87A3 -#define GL_OUTPUT_TEXTURE_COORD7_EXT 0x87A4 -#define GL_OUTPUT_TEXTURE_COORD8_EXT 0x87A5 -#define GL_OUTPUT_TEXTURE_COORD9_EXT 0x87A6 -#define GL_OUTPUT_TEXTURE_COORD10_EXT 0x87A7 -#define GL_OUTPUT_TEXTURE_COORD11_EXT 0x87A8 -#define GL_OUTPUT_TEXTURE_COORD12_EXT 0x87A9 -#define GL_OUTPUT_TEXTURE_COORD13_EXT 0x87AA -#define GL_OUTPUT_TEXTURE_COORD14_EXT 0x87AB -#define GL_OUTPUT_TEXTURE_COORD15_EXT 0x87AC -#define GL_OUTPUT_TEXTURE_COORD16_EXT 0x87AD -#define GL_OUTPUT_TEXTURE_COORD17_EXT 0x87AE -#define GL_OUTPUT_TEXTURE_COORD18_EXT 0x87AF -#define GL_OUTPUT_TEXTURE_COORD19_EXT 0x87B0 -#define GL_OUTPUT_TEXTURE_COORD20_EXT 0x87B1 -#define GL_OUTPUT_TEXTURE_COORD21_EXT 0x87B2 -#define GL_OUTPUT_TEXTURE_COORD22_EXT 0x87B3 -#define GL_OUTPUT_TEXTURE_COORD23_EXT 0x87B4 -#define GL_OUTPUT_TEXTURE_COORD24_EXT 0x87B5 -#define GL_OUTPUT_TEXTURE_COORD25_EXT 0x87B6 -#define GL_OUTPUT_TEXTURE_COORD26_EXT 0x87B7 -#define GL_OUTPUT_TEXTURE_COORD27_EXT 0x87B8 -#define GL_OUTPUT_TEXTURE_COORD28_EXT 0x87B9 -#define GL_OUTPUT_TEXTURE_COORD29_EXT 0x87BA -#define GL_OUTPUT_TEXTURE_COORD30_EXT 0x87BB -#define GL_OUTPUT_TEXTURE_COORD31_EXT 0x87BC -#define GL_OUTPUT_FOG_EXT 0x87BD -#define GL_SCALAR_EXT 0x87BE -#define GL_VECTOR_EXT 0x87BF -#define GL_MATRIX_EXT 0x87C0 -#define GL_VARIANT_EXT 0x87C1 -#define GL_INVARIANT_EXT 0x87C2 -#define GL_LOCAL_CONSTANT_EXT 0x87C3 -#define GL_LOCAL_EXT 0x87C4 -#define GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87C5 -#define GL_MAX_VERTEX_SHADER_VARIANTS_EXT 0x87C6 -#define GL_MAX_VERTEX_SHADER_INVARIANTS_EXT 0x87C7 -#define GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87C8 -#define GL_MAX_VERTEX_SHADER_LOCALS_EXT 0x87C9 -#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CA -#define GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT 0x87CB -#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87CC -#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT 0x87CD -#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT 0x87CE -#define GL_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CF -#define GL_VERTEX_SHADER_VARIANTS_EXT 0x87D0 -#define GL_VERTEX_SHADER_INVARIANTS_EXT 0x87D1 -#define GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87D2 -#define GL_VERTEX_SHADER_LOCALS_EXT 0x87D3 -#define GL_VERTEX_SHADER_OPTIMIZED_EXT 0x87D4 -#define GL_X_EXT 0x87D5 -#define GL_Y_EXT 0x87D6 -#define GL_Z_EXT 0x87D7 -#define GL_W_EXT 0x87D8 -#define GL_NEGATIVE_X_EXT 0x87D9 -#define GL_NEGATIVE_Y_EXT 0x87DA -#define GL_NEGATIVE_Z_EXT 0x87DB -#define GL_NEGATIVE_W_EXT 0x87DC -#define GL_ZERO_EXT 0x87DD -#define GL_ONE_EXT 0x87DE -#define GL_NEGATIVE_ONE_EXT 0x87DF -#define GL_NORMALIZED_RANGE_EXT 0x87E0 -#define GL_FULL_RANGE_EXT 0x87E1 -#define GL_CURRENT_VERTEX_EXT 0x87E2 -#define GL_MVP_MATRIX_EXT 0x87E3 -#define GL_VARIANT_VALUE_EXT 0x87E4 -#define GL_VARIANT_DATATYPE_EXT 0x87E5 -#define GL_VARIANT_ARRAY_STRIDE_EXT 0x87E6 -#define GL_VARIANT_ARRAY_TYPE_EXT 0x87E7 -#define GL_VARIANT_ARRAY_EXT 0x87E8 -#define GL_VARIANT_ARRAY_POINTER_EXT 0x87E9 -#define GL_INVARIANT_VALUE_EXT 0x87EA -#define GL_INVARIANT_DATATYPE_EXT 0x87EB -#define GL_LOCAL_CONSTANT_VALUE_EXT 0x87EC -#define GL_LOCAL_CONSTANT_DATATYPE_EXT 0x87ED -#endif - -#ifndef GL_ATI_vertex_streams -#define GL_MAX_VERTEX_STREAMS_ATI 0x876B -#define GL_VERTEX_STREAM0_ATI 0x876C -#define GL_VERTEX_STREAM1_ATI 0x876D -#define GL_VERTEX_STREAM2_ATI 0x876E -#define GL_VERTEX_STREAM3_ATI 0x876F -#define GL_VERTEX_STREAM4_ATI 0x8770 -#define GL_VERTEX_STREAM5_ATI 0x8771 -#define GL_VERTEX_STREAM6_ATI 0x8772 -#define GL_VERTEX_STREAM7_ATI 0x8773 -#define GL_VERTEX_SOURCE_ATI 0x8774 -#endif - -#ifndef GL_ATI_element_array -#define GL_ELEMENT_ARRAY_ATI 0x8768 -#define GL_ELEMENT_ARRAY_TYPE_ATI 0x8769 -#define GL_ELEMENT_ARRAY_POINTER_ATI 0x876A -#endif - -#ifndef GL_SUN_mesh_array -#define GL_QUAD_MESH_SUN 0x8614 -#define GL_TRIANGLE_MESH_SUN 0x8615 -#endif - -#ifndef GL_SUN_slice_accum -#define GL_SLICE_ACCUM_SUN 0x85CC -#endif - -#ifndef GL_NV_multisample_filter_hint -#define GL_MULTISAMPLE_FILTER_HINT_NV 0x8534 -#endif - -#ifndef GL_NV_depth_clamp -#define GL_DEPTH_CLAMP_NV 0x864F -#endif - -#ifndef GL_NV_occlusion_query -#define GL_PIXEL_COUNTER_BITS_NV 0x8864 -#define GL_CURRENT_OCCLUSION_QUERY_ID_NV 0x8865 -#define GL_PIXEL_COUNT_NV 0x8866 -#define GL_PIXEL_COUNT_AVAILABLE_NV 0x8867 -#endif - -#ifndef GL_NV_point_sprite -#define GL_POINT_SPRITE_NV 0x8861 -#define GL_COORD_REPLACE_NV 0x8862 -#define GL_POINT_SPRITE_R_MODE_NV 0x8863 -#endif - -#ifndef GL_NV_texture_shader3 -#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV 0x8850 -#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV 0x8851 -#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8852 -#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV 0x8853 -#define GL_OFFSET_HILO_TEXTURE_2D_NV 0x8854 -#define GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV 0x8855 -#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV 0x8856 -#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8857 -#define GL_DEPENDENT_HILO_TEXTURE_2D_NV 0x8858 -#define GL_DEPENDENT_RGB_TEXTURE_3D_NV 0x8859 -#define GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV 0x885A -#define GL_DOT_PRODUCT_PASS_THROUGH_NV 0x885B -#define GL_DOT_PRODUCT_TEXTURE_1D_NV 0x885C -#define GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV 0x885D -#define GL_HILO8_NV 0x885E -#define GL_SIGNED_HILO8_NV 0x885F -#define GL_FORCE_BLUE_TO_ONE_NV 0x8860 -#endif - -#ifndef GL_NV_vertex_program1_1 -#endif - -#ifndef GL_EXT_shadow_funcs -#endif - -#ifndef GL_EXT_stencil_two_side -#define GL_STENCIL_TEST_TWO_SIDE_EXT 0x8910 -#define GL_ACTIVE_STENCIL_FACE_EXT 0x8911 -#endif - -#ifndef GL_ATI_text_fragment_shader -#define GL_TEXT_FRAGMENT_SHADER_ATI 0x8200 -#endif - -#ifndef GL_APPLE_client_storage -#define GL_UNPACK_CLIENT_STORAGE_APPLE 0x85B2 -#endif - -#ifndef GL_APPLE_element_array -#define GL_ELEMENT_ARRAY_APPLE 0x8A0C -#define GL_ELEMENT_ARRAY_TYPE_APPLE 0x8A0D -#define GL_ELEMENT_ARRAY_POINTER_APPLE 0x8A0E -#endif - -#ifndef GL_APPLE_fence -#define GL_DRAW_PIXELS_APPLE 0x8A0A -#define GL_FENCE_APPLE 0x8A0B -#endif - -#ifndef GL_APPLE_vertex_array_object -#define GL_VERTEX_ARRAY_BINDING_APPLE 0x85B5 -#endif - -#ifndef GL_APPLE_vertex_array_range -#define GL_VERTEX_ARRAY_RANGE_APPLE 0x851D -#define GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE 0x851E -#define GL_VERTEX_ARRAY_STORAGE_HINT_APPLE 0x851F -#define GL_VERTEX_ARRAY_RANGE_POINTER_APPLE 0x8521 -#define GL_STORAGE_CLIENT_APPLE 0x85B4 -#define GL_STORAGE_CACHED_APPLE 0x85BE -#define GL_STORAGE_SHARED_APPLE 0x85BF -#endif - -#ifndef GL_APPLE_ycbcr_422 -#define GL_YCBCR_422_APPLE 0x85B9 -#define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA -#define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB -#endif - -#ifndef GL_S3_s3tc -#define GL_RGB_S3TC 0x83A0 -#define GL_RGB4_S3TC 0x83A1 -#define GL_RGBA_S3TC 0x83A2 -#define GL_RGBA4_S3TC 0x83A3 -#endif - -#ifndef GL_ATI_draw_buffers -#define GL_MAX_DRAW_BUFFERS_ATI 0x8824 -#define GL_DRAW_BUFFER0_ATI 0x8825 -#define GL_DRAW_BUFFER1_ATI 0x8826 -#define GL_DRAW_BUFFER2_ATI 0x8827 -#define GL_DRAW_BUFFER3_ATI 0x8828 -#define GL_DRAW_BUFFER4_ATI 0x8829 -#define GL_DRAW_BUFFER5_ATI 0x882A -#define GL_DRAW_BUFFER6_ATI 0x882B -#define GL_DRAW_BUFFER7_ATI 0x882C -#define GL_DRAW_BUFFER8_ATI 0x882D -#define GL_DRAW_BUFFER9_ATI 0x882E -#define GL_DRAW_BUFFER10_ATI 0x882F -#define GL_DRAW_BUFFER11_ATI 0x8830 -#define GL_DRAW_BUFFER12_ATI 0x8831 -#define GL_DRAW_BUFFER13_ATI 0x8832 -#define GL_DRAW_BUFFER14_ATI 0x8833 -#define GL_DRAW_BUFFER15_ATI 0x8834 -#endif - -#ifndef GL_ATI_pixel_format_float -#define GL_TYPE_RGBA_FLOAT_ATI 0x8820 -#define GL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI 0x8835 -#endif - -#ifndef GL_ATI_texture_env_combine3 -#define GL_MODULATE_ADD_ATI 0x8744 -#define GL_MODULATE_SIGNED_ADD_ATI 0x8745 -#define GL_MODULATE_SUBTRACT_ATI 0x8746 -#endif - -#ifndef GL_ATI_texture_float -#define GL_RGBA_FLOAT32_ATI 0x8814 -#define GL_RGB_FLOAT32_ATI 0x8815 -#define GL_ALPHA_FLOAT32_ATI 0x8816 -#define GL_INTENSITY_FLOAT32_ATI 0x8817 -#define GL_LUMINANCE_FLOAT32_ATI 0x8818 -#define GL_LUMINANCE_ALPHA_FLOAT32_ATI 0x8819 -#define GL_RGBA_FLOAT16_ATI 0x881A -#define GL_RGB_FLOAT16_ATI 0x881B -#define GL_ALPHA_FLOAT16_ATI 0x881C -#define GL_INTENSITY_FLOAT16_ATI 0x881D -#define GL_LUMINANCE_FLOAT16_ATI 0x881E -#define GL_LUMINANCE_ALPHA_FLOAT16_ATI 0x881F -#endif - -#ifndef GL_NV_float_buffer -#define GL_FLOAT_R_NV 0x8880 -#define GL_FLOAT_RG_NV 0x8881 -#define GL_FLOAT_RGB_NV 0x8882 -#define GL_FLOAT_RGBA_NV 0x8883 -#define GL_FLOAT_R16_NV 0x8884 -#define GL_FLOAT_R32_NV 0x8885 -#define GL_FLOAT_RG16_NV 0x8886 -#define GL_FLOAT_RG32_NV 0x8887 -#define GL_FLOAT_RGB16_NV 0x8888 -#define GL_FLOAT_RGB32_NV 0x8889 -#define GL_FLOAT_RGBA16_NV 0x888A -#define GL_FLOAT_RGBA32_NV 0x888B -#define GL_TEXTURE_FLOAT_COMPONENTS_NV 0x888C -#define GL_FLOAT_CLEAR_COLOR_VALUE_NV 0x888D -#define GL_FLOAT_RGBA_MODE_NV 0x888E -#endif - -#ifndef GL_NV_fragment_program -#define GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV 0x8868 -#define GL_FRAGMENT_PROGRAM_NV 0x8870 -#define GL_MAX_TEXTURE_COORDS_NV 0x8871 -#define GL_MAX_TEXTURE_IMAGE_UNITS_NV 0x8872 -#define GL_FRAGMENT_PROGRAM_BINDING_NV 0x8873 -#define GL_PROGRAM_ERROR_STRING_NV 0x8874 -#endif - -#ifndef GL_NV_half_float -#define GL_HALF_FLOAT_NV 0x140B -#endif - -#ifndef GL_NV_pixel_data_range -#define GL_WRITE_PIXEL_DATA_RANGE_NV 0x8878 -#define GL_READ_PIXEL_DATA_RANGE_NV 0x8879 -#define GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV 0x887A -#define GL_READ_PIXEL_DATA_RANGE_LENGTH_NV 0x887B -#define GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV 0x887C -#define GL_READ_PIXEL_DATA_RANGE_POINTER_NV 0x887D -#endif - -#ifndef GL_NV_primitive_restart -#define GL_PRIMITIVE_RESTART_NV 0x8558 -#define GL_PRIMITIVE_RESTART_INDEX_NV 0x8559 -#endif - -#ifndef GL_NV_texture_expand_normal -#define GL_TEXTURE_UNSIGNED_REMAP_MODE_NV 0x888F -#endif - -#ifndef GL_NV_vertex_program2 -#endif - -#ifndef GL_ATI_map_object_buffer -#endif - -#ifndef GL_ATI_separate_stencil -#define GL_STENCIL_BACK_FUNC_ATI 0x8800 -#define GL_STENCIL_BACK_FAIL_ATI 0x8801 -#define GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI 0x8802 -#define GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI 0x8803 -#endif - -#ifndef GL_ATI_vertex_attrib_array_object -#endif - -#ifndef GL_OES_read_format -#define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A -#define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B -#endif - -#ifndef GL_EXT_depth_bounds_test -#define GL_DEPTH_BOUNDS_TEST_EXT 0x8890 -#define GL_DEPTH_BOUNDS_EXT 0x8891 -#endif - -#ifndef GL_EXT_texture_mirror_clamp -#define GL_MIRROR_CLAMP_EXT 0x8742 -#define GL_MIRROR_CLAMP_TO_EDGE_EXT 0x8743 -#define GL_MIRROR_CLAMP_TO_BORDER_EXT 0x8912 -#endif - -#ifndef GL_EXT_blend_equation_separate -#define GL_BLEND_EQUATION_RGB_EXT 0x8009 -#define GL_BLEND_EQUATION_ALPHA_EXT 0x883D -#endif - -#ifndef GL_MESA_pack_invert -#define GL_PACK_INVERT_MESA 0x8758 -#endif - -#ifndef GL_MESA_ycbcr_texture -#define GL_UNSIGNED_SHORT_8_8_MESA 0x85BA -#define GL_UNSIGNED_SHORT_8_8_REV_MESA 0x85BB -#define GL_YCBCR_MESA 0x8757 -#endif - -#ifndef GL_EXT_pixel_buffer_object -#define GL_PIXEL_PACK_BUFFER_EXT 0x88EB -#define GL_PIXEL_UNPACK_BUFFER_EXT 0x88EC -#define GL_PIXEL_PACK_BUFFER_BINDING_EXT 0x88ED -#define GL_PIXEL_UNPACK_BUFFER_BINDING_EXT 0x88EF -#endif - -#ifndef GL_NV_fragment_program_option -#endif - -#ifndef GL_NV_fragment_program2 -#define GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV 0x88F4 -#define GL_MAX_PROGRAM_CALL_DEPTH_NV 0x88F5 -#define GL_MAX_PROGRAM_IF_DEPTH_NV 0x88F6 -#define GL_MAX_PROGRAM_LOOP_DEPTH_NV 0x88F7 -#define GL_MAX_PROGRAM_LOOP_COUNT_NV 0x88F8 -#endif - -#ifndef GL_NV_vertex_program2_option -/* reuse GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV */ -/* reuse GL_MAX_PROGRAM_CALL_DEPTH_NV */ -#endif - -#ifndef GL_NV_vertex_program3 -/* reuse GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB */ -#endif - -#ifndef GL_EXT_framebuffer_object -#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506 -#define GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8 -#define GL_FRAMEBUFFER_BINDING_EXT 0x8CA6 -#define GL_RENDERBUFFER_BINDING_EXT 0x8CA7 -#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0 -#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4 -#define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5 -#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6 -#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7 -#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9 -#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA -#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB -#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC -#define GL_FRAMEBUFFER_UNSUPPORTED_EXT 0x8CDD -#define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF -#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0 -#define GL_COLOR_ATTACHMENT1_EXT 0x8CE1 -#define GL_COLOR_ATTACHMENT2_EXT 0x8CE2 -#define GL_COLOR_ATTACHMENT3_EXT 0x8CE3 -#define GL_COLOR_ATTACHMENT4_EXT 0x8CE4 -#define GL_COLOR_ATTACHMENT5_EXT 0x8CE5 -#define GL_COLOR_ATTACHMENT6_EXT 0x8CE6 -#define GL_COLOR_ATTACHMENT7_EXT 0x8CE7 -#define GL_COLOR_ATTACHMENT8_EXT 0x8CE8 -#define GL_COLOR_ATTACHMENT9_EXT 0x8CE9 -#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA -#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB -#define GL_COLOR_ATTACHMENT12_EXT 0x8CEC -#define GL_COLOR_ATTACHMENT13_EXT 0x8CED -#define GL_COLOR_ATTACHMENT14_EXT 0x8CEE -#define GL_COLOR_ATTACHMENT15_EXT 0x8CEF -#define GL_DEPTH_ATTACHMENT_EXT 0x8D00 -#define GL_STENCIL_ATTACHMENT_EXT 0x8D20 -#define GL_FRAMEBUFFER_EXT 0x8D40 -#define GL_RENDERBUFFER_EXT 0x8D41 -#define GL_RENDERBUFFER_WIDTH_EXT 0x8D42 -#define GL_RENDERBUFFER_HEIGHT_EXT 0x8D43 -#define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44 -#define GL_STENCIL_INDEX1_EXT 0x8D46 -#define GL_STENCIL_INDEX4_EXT 0x8D47 -#define GL_STENCIL_INDEX8_EXT 0x8D48 -#define GL_STENCIL_INDEX16_EXT 0x8D49 -#define GL_RENDERBUFFER_RED_SIZE_EXT 0x8D50 -#define GL_RENDERBUFFER_GREEN_SIZE_EXT 0x8D51 -#define GL_RENDERBUFFER_BLUE_SIZE_EXT 0x8D52 -#define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53 -#define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54 -#define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55 -#endif - -#ifndef GL_GREMEDY_string_marker -#endif - -#ifndef GL_EXT_packed_depth_stencil -#define GL_DEPTH_STENCIL_EXT 0x84F9 -#define GL_UNSIGNED_INT_24_8_EXT 0x84FA -#define GL_DEPTH24_STENCIL8_EXT 0x88F0 -#define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1 -#endif - -#ifndef GL_EXT_stencil_clear_tag -#define GL_STENCIL_TAG_BITS_EXT 0x88F2 -#define GL_STENCIL_CLEAR_TAG_VALUE_EXT 0x88F3 -#endif - -#ifndef GL_EXT_texture_sRGB -#define GL_SRGB_EXT 0x8C40 -#define GL_SRGB8_EXT 0x8C41 -#define GL_SRGB_ALPHA_EXT 0x8C42 -#define GL_SRGB8_ALPHA8_EXT 0x8C43 -#define GL_SLUMINANCE_ALPHA_EXT 0x8C44 -#define GL_SLUMINANCE8_ALPHA8_EXT 0x8C45 -#define GL_SLUMINANCE_EXT 0x8C46 -#define GL_SLUMINANCE8_EXT 0x8C47 -#define GL_COMPRESSED_SRGB_EXT 0x8C48 -#define GL_COMPRESSED_SRGB_ALPHA_EXT 0x8C49 -#define GL_COMPRESSED_SLUMINANCE_EXT 0x8C4A -#define GL_COMPRESSED_SLUMINANCE_ALPHA_EXT 0x8C4B -#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C -#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D -#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E -#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F -#endif - -#ifndef GL_EXT_framebuffer_blit -#define GL_READ_FRAMEBUFFER_EXT 0x8CA8 -#define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9 -#define GL_DRAW_FRAMEBUFFER_BINDING_EXT GL_FRAMEBUFFER_BINDING_EXT -#define GL_READ_FRAMEBUFFER_BINDING_EXT 0x8CAA -#endif - -#ifndef GL_EXT_framebuffer_multisample -#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB -#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56 -#define GL_MAX_SAMPLES_EXT 0x8D57 -#endif - -#ifndef GL_MESAX_texture_stack -#define GL_TEXTURE_1D_STACK_MESAX 0x8759 -#define GL_TEXTURE_2D_STACK_MESAX 0x875A -#define GL_PROXY_TEXTURE_1D_STACK_MESAX 0x875B -#define GL_PROXY_TEXTURE_2D_STACK_MESAX 0x875C -#define GL_TEXTURE_1D_STACK_BINDING_MESAX 0x875D -#define GL_TEXTURE_2D_STACK_BINDING_MESAX 0x875E -#endif - -#ifndef GL_EXT_timer_query -#define GL_TIME_ELAPSED_EXT 0x88BF -#endif - -#ifndef GL_EXT_gpu_program_parameters -#endif - -#ifndef GL_APPLE_flush_buffer_range -#define GL_BUFFER_SERIALIZED_MODIFY_APPLE 0x8A12 -#define GL_BUFFER_FLUSHING_UNMAP_APPLE 0x8A13 -#endif - -#ifndef GL_NV_gpu_program4 -#define GL_MIN_PROGRAM_TEXEL_OFFSET_NV 0x8904 -#define GL_MAX_PROGRAM_TEXEL_OFFSET_NV 0x8905 -#define GL_PROGRAM_ATTRIB_COMPONENTS_NV 0x8906 -#define GL_PROGRAM_RESULT_COMPONENTS_NV 0x8907 -#define GL_MAX_PROGRAM_ATTRIB_COMPONENTS_NV 0x8908 -#define GL_MAX_PROGRAM_RESULT_COMPONENTS_NV 0x8909 -#define GL_MAX_PROGRAM_GENERIC_ATTRIBS_NV 0x8DA5 -#define GL_MAX_PROGRAM_GENERIC_RESULTS_NV 0x8DA6 -#endif - -#ifndef GL_NV_geometry_program4 -#define GL_LINES_ADJACENCY_EXT 0x000A -#define GL_LINE_STRIP_ADJACENCY_EXT 0x000B -#define GL_TRIANGLES_ADJACENCY_EXT 0x000C -#define GL_TRIANGLE_STRIP_ADJACENCY_EXT 0x000D -#define GL_GEOMETRY_PROGRAM_NV 0x8C26 -#define GL_MAX_PROGRAM_OUTPUT_VERTICES_NV 0x8C27 -#define GL_MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV 0x8C28 -#define GL_GEOMETRY_VERTICES_OUT_EXT 0x8DDA -#define GL_GEOMETRY_INPUT_TYPE_EXT 0x8DDB -#define GL_GEOMETRY_OUTPUT_TYPE_EXT 0x8DDC -#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT 0x8C29 -#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT 0x8DA7 -#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT 0x8DA8 -#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT 0x8DA9 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT 0x8CD4 -#define GL_PROGRAM_POINT_SIZE_EXT 0x8642 -#endif - -#ifndef GL_EXT_geometry_shader4 -#define GL_GEOMETRY_SHADER_EXT 0x8DD9 -/* reuse GL_GEOMETRY_VERTICES_OUT_EXT */ -/* reuse GL_GEOMETRY_INPUT_TYPE_EXT */ -/* reuse GL_GEOMETRY_OUTPUT_TYPE_EXT */ -/* reuse GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT */ -#define GL_MAX_GEOMETRY_VARYING_COMPONENTS_EXT 0x8DDD -#define GL_MAX_VERTEX_VARYING_COMPONENTS_EXT 0x8DDE -#define GL_MAX_VARYING_COMPONENTS_EXT 0x8B4B -#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT 0x8DDF -#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT 0x8DE0 -#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT 0x8DE1 -/* reuse GL_LINES_ADJACENCY_EXT */ -/* reuse GL_LINE_STRIP_ADJACENCY_EXT */ -/* reuse GL_TRIANGLES_ADJACENCY_EXT */ -/* reuse GL_TRIANGLE_STRIP_ADJACENCY_EXT */ -/* reuse GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT */ -/* reuse GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT */ -/* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT */ -/* reuse GL_PROGRAM_POINT_SIZE_EXT */ -#endif - -#ifndef GL_NV_vertex_program4 -#define GL_VERTEX_ATTRIB_ARRAY_INTEGER_NV 0x88FD -#endif - -#ifndef GL_EXT_gpu_shader4 -#define GL_SAMPLER_1D_ARRAY_EXT 0x8DC0 -#define GL_SAMPLER_2D_ARRAY_EXT 0x8DC1 -#define GL_SAMPLER_BUFFER_EXT 0x8DC2 -#define GL_SAMPLER_1D_ARRAY_SHADOW_EXT 0x8DC3 -#define GL_SAMPLER_2D_ARRAY_SHADOW_EXT 0x8DC4 -#define GL_SAMPLER_CUBE_SHADOW_EXT 0x8DC5 -#define GL_UNSIGNED_INT_VEC2_EXT 0x8DC6 -#define GL_UNSIGNED_INT_VEC3_EXT 0x8DC7 -#define GL_UNSIGNED_INT_VEC4_EXT 0x8DC8 -#define GL_INT_SAMPLER_1D_EXT 0x8DC9 -#define GL_INT_SAMPLER_2D_EXT 0x8DCA -#define GL_INT_SAMPLER_3D_EXT 0x8DCB -#define GL_INT_SAMPLER_CUBE_EXT 0x8DCC -#define GL_INT_SAMPLER_2D_RECT_EXT 0x8DCD -#define GL_INT_SAMPLER_1D_ARRAY_EXT 0x8DCE -#define GL_INT_SAMPLER_2D_ARRAY_EXT 0x8DCF -#define GL_INT_SAMPLER_BUFFER_EXT 0x8DD0 -#define GL_UNSIGNED_INT_SAMPLER_1D_EXT 0x8DD1 -#define GL_UNSIGNED_INT_SAMPLER_2D_EXT 0x8DD2 -#define GL_UNSIGNED_INT_SAMPLER_3D_EXT 0x8DD3 -#define GL_UNSIGNED_INT_SAMPLER_CUBE_EXT 0x8DD4 -#define GL_UNSIGNED_INT_SAMPLER_2D_RECT_EXT 0x8DD5 -#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT 0x8DD6 -#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT 0x8DD7 -#define GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT 0x8DD8 -#endif - -#ifndef GL_EXT_draw_instanced -#endif - -#ifndef GL_EXT_packed_float -#define GL_R11F_G11F_B10F_EXT 0x8C3A -#define GL_UNSIGNED_INT_10F_11F_11F_REV_EXT 0x8C3B -#define GL_RGBA_SIGNED_COMPONENTS_EXT 0x8C3C -#endif - -#ifndef GL_EXT_texture_array -#define GL_TEXTURE_1D_ARRAY_EXT 0x8C18 -#define GL_PROXY_TEXTURE_1D_ARRAY_EXT 0x8C19 -#define GL_TEXTURE_2D_ARRAY_EXT 0x8C1A -#define GL_PROXY_TEXTURE_2D_ARRAY_EXT 0x8C1B -#define GL_TEXTURE_BINDING_1D_ARRAY_EXT 0x8C1C -#define GL_TEXTURE_BINDING_2D_ARRAY_EXT 0x8C1D -#define GL_MAX_ARRAY_TEXTURE_LAYERS_EXT 0x88FF -#define GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT 0x884E -/* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT */ -#endif - -#ifndef GL_EXT_texture_buffer_object -#define GL_TEXTURE_BUFFER_EXT 0x8C2A -#define GL_MAX_TEXTURE_BUFFER_SIZE_EXT 0x8C2B -#define GL_TEXTURE_BINDING_BUFFER_EXT 0x8C2C -#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_EXT 0x8C2D -#define GL_TEXTURE_BUFFER_FORMAT_EXT 0x8C2E -#endif - -#ifndef GL_EXT_texture_compression_latc -#define GL_COMPRESSED_LUMINANCE_LATC1_EXT 0x8C70 -#define GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT 0x8C71 -#define GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT 0x8C72 -#define GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT 0x8C73 -#endif - -#ifndef GL_EXT_texture_compression_rgtc -#define GL_COMPRESSED_RED_RGTC1_EXT 0x8DBB -#define GL_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC -#define GL_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD -#define GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE -#endif - -#ifndef GL_EXT_texture_shared_exponent -#define GL_RGB9_E5_EXT 0x8C3D -#define GL_UNSIGNED_INT_5_9_9_9_REV_EXT 0x8C3E -#define GL_TEXTURE_SHARED_SIZE_EXT 0x8C3F -#endif - -#ifndef GL_NV_depth_buffer_float -#define GL_DEPTH_COMPONENT32F_NV 0x8DAB -#define GL_DEPTH32F_STENCIL8_NV 0x8DAC -#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV_NV 0x8DAD -#define GL_DEPTH_BUFFER_FLOAT_MODE_NV 0x8DAF -#endif - -#ifndef GL_NV_fragment_program4 -#endif - -#ifndef GL_NV_framebuffer_multisample_coverage -#define GL_RENDERBUFFER_COVERAGE_SAMPLES_NV 0x8CAB -#define GL_RENDERBUFFER_COLOR_SAMPLES_NV 0x8E10 -#define GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV 0x8E11 -#define GL_MULTISAMPLE_COVERAGE_MODES_NV 0x8E12 -#endif - -#ifndef GL_EXT_framebuffer_sRGB -#define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9 -#define GL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x8DBA -#endif - -#ifndef GL_NV_geometry_shader4 -#endif - -#ifndef GL_NV_parameter_buffer_object -#define GL_MAX_PROGRAM_PARAMETER_BUFFER_BINDINGS_NV 0x8DA0 -#define GL_MAX_PROGRAM_PARAMETER_BUFFER_SIZE_NV 0x8DA1 -#define GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV 0x8DA2 -#define GL_GEOMETRY_PROGRAM_PARAMETER_BUFFER_NV 0x8DA3 -#define GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV 0x8DA4 -#endif - -#ifndef GL_EXT_draw_buffers2 -#endif - -#ifndef GL_NV_transform_feedback -#define GL_BACK_PRIMARY_COLOR_NV 0x8C77 -#define GL_BACK_SECONDARY_COLOR_NV 0x8C78 -#define GL_TEXTURE_COORD_NV 0x8C79 -#define GL_CLIP_DISTANCE_NV 0x8C7A -#define GL_VERTEX_ID_NV 0x8C7B -#define GL_PRIMITIVE_ID_NV 0x8C7C -#define GL_GENERIC_ATTRIB_NV 0x8C7D -#define GL_TRANSFORM_FEEDBACK_ATTRIBS_NV 0x8C7E -#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_NV 0x8C7F -#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_NV 0x8C80 -#define GL_ACTIVE_VARYINGS_NV 0x8C81 -#define GL_ACTIVE_VARYING_MAX_LENGTH_NV 0x8C82 -#define GL_TRANSFORM_FEEDBACK_VARYINGS_NV 0x8C83 -#define GL_TRANSFORM_FEEDBACK_BUFFER_START_NV 0x8C84 -#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_NV 0x8C85 -#define GL_TRANSFORM_FEEDBACK_RECORD_NV 0x8C86 -#define GL_PRIMITIVES_GENERATED_NV 0x8C87 -#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_NV 0x8C88 -#define GL_RASTERIZER_DISCARD_NV 0x8C89 -#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_ATTRIBS_NV 0x8C8A -#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_NV 0x8C8B -#define GL_INTERLEAVED_ATTRIBS_NV 0x8C8C -#define GL_SEPARATE_ATTRIBS_NV 0x8C8D -#define GL_TRANSFORM_FEEDBACK_BUFFER_NV 0x8C8E -#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_NV 0x8C8F -#define GL_LAYER_NV 0x8DAA -#define GL_NEXT_BUFFER_NV -2 -#define GL_SKIP_COMPONENTS4_NV -3 -#define GL_SKIP_COMPONENTS3_NV -4 -#define GL_SKIP_COMPONENTS2_NV -5 -#define GL_SKIP_COMPONENTS1_NV -6 -#endif - -#ifndef GL_EXT_bindable_uniform -#define GL_MAX_VERTEX_BINDABLE_UNIFORMS_EXT 0x8DE2 -#define GL_MAX_FRAGMENT_BINDABLE_UNIFORMS_EXT 0x8DE3 -#define GL_MAX_GEOMETRY_BINDABLE_UNIFORMS_EXT 0x8DE4 -#define GL_MAX_BINDABLE_UNIFORM_SIZE_EXT 0x8DED -#define GL_UNIFORM_BUFFER_EXT 0x8DEE -#define GL_UNIFORM_BUFFER_BINDING_EXT 0x8DEF -#endif - -#ifndef GL_EXT_texture_integer -#define GL_RGBA32UI_EXT 0x8D70 -#define GL_RGB32UI_EXT 0x8D71 -#define GL_ALPHA32UI_EXT 0x8D72 -#define GL_INTENSITY32UI_EXT 0x8D73 -#define GL_LUMINANCE32UI_EXT 0x8D74 -#define GL_LUMINANCE_ALPHA32UI_EXT 0x8D75 -#define GL_RGBA16UI_EXT 0x8D76 -#define GL_RGB16UI_EXT 0x8D77 -#define GL_ALPHA16UI_EXT 0x8D78 -#define GL_INTENSITY16UI_EXT 0x8D79 -#define GL_LUMINANCE16UI_EXT 0x8D7A -#define GL_LUMINANCE_ALPHA16UI_EXT 0x8D7B -#define GL_RGBA8UI_EXT 0x8D7C -#define GL_RGB8UI_EXT 0x8D7D -#define GL_ALPHA8UI_EXT 0x8D7E -#define GL_INTENSITY8UI_EXT 0x8D7F -#define GL_LUMINANCE8UI_EXT 0x8D80 -#define GL_LUMINANCE_ALPHA8UI_EXT 0x8D81 -#define GL_RGBA32I_EXT 0x8D82 -#define GL_RGB32I_EXT 0x8D83 -#define GL_ALPHA32I_EXT 0x8D84 -#define GL_INTENSITY32I_EXT 0x8D85 -#define GL_LUMINANCE32I_EXT 0x8D86 -#define GL_LUMINANCE_ALPHA32I_EXT 0x8D87 -#define GL_RGBA16I_EXT 0x8D88 -#define GL_RGB16I_EXT 0x8D89 -#define GL_ALPHA16I_EXT 0x8D8A -#define GL_INTENSITY16I_EXT 0x8D8B -#define GL_LUMINANCE16I_EXT 0x8D8C -#define GL_LUMINANCE_ALPHA16I_EXT 0x8D8D -#define GL_RGBA8I_EXT 0x8D8E -#define GL_RGB8I_EXT 0x8D8F -#define GL_ALPHA8I_EXT 0x8D90 -#define GL_INTENSITY8I_EXT 0x8D91 -#define GL_LUMINANCE8I_EXT 0x8D92 -#define GL_LUMINANCE_ALPHA8I_EXT 0x8D93 -#define GL_RED_INTEGER_EXT 0x8D94 -#define GL_GREEN_INTEGER_EXT 0x8D95 -#define GL_BLUE_INTEGER_EXT 0x8D96 -#define GL_ALPHA_INTEGER_EXT 0x8D97 -#define GL_RGB_INTEGER_EXT 0x8D98 -#define GL_RGBA_INTEGER_EXT 0x8D99 -#define GL_BGR_INTEGER_EXT 0x8D9A -#define GL_BGRA_INTEGER_EXT 0x8D9B -#define GL_LUMINANCE_INTEGER_EXT 0x8D9C -#define GL_LUMINANCE_ALPHA_INTEGER_EXT 0x8D9D -#define GL_RGBA_INTEGER_MODE_EXT 0x8D9E -#endif - -#ifndef GL_GREMEDY_frame_terminator -#endif - -#ifndef GL_NV_conditional_render -#define GL_QUERY_WAIT_NV 0x8E13 -#define GL_QUERY_NO_WAIT_NV 0x8E14 -#define GL_QUERY_BY_REGION_WAIT_NV 0x8E15 -#define GL_QUERY_BY_REGION_NO_WAIT_NV 0x8E16 -#endif - -#ifndef GL_NV_present_video -#define GL_FRAME_NV 0x8E26 -#define GL_FIELDS_NV 0x8E27 -#define GL_CURRENT_TIME_NV 0x8E28 -#define GL_NUM_FILL_STREAMS_NV 0x8E29 -#define GL_PRESENT_TIME_NV 0x8E2A -#define GL_PRESENT_DURATION_NV 0x8E2B -#endif - -#ifndef GL_EXT_transform_feedback -#define GL_TRANSFORM_FEEDBACK_BUFFER_EXT 0x8C8E -#define GL_TRANSFORM_FEEDBACK_BUFFER_START_EXT 0x8C84 -#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_EXT 0x8C85 -#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_EXT 0x8C8F -#define GL_INTERLEAVED_ATTRIBS_EXT 0x8C8C -#define GL_SEPARATE_ATTRIBS_EXT 0x8C8D -#define GL_PRIMITIVES_GENERATED_EXT 0x8C87 -#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT 0x8C88 -#define GL_RASTERIZER_DISCARD_EXT 0x8C89 -#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT 0x8C8A -#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT 0x8C8B -#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT 0x8C80 -#define GL_TRANSFORM_FEEDBACK_VARYINGS_EXT 0x8C83 -#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_EXT 0x8C7F -#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH_EXT 0x8C76 -#endif - -#ifndef GL_EXT_direct_state_access -#define GL_PROGRAM_MATRIX_EXT 0x8E2D -#define GL_TRANSPOSE_PROGRAM_MATRIX_EXT 0x8E2E -#define GL_PROGRAM_MATRIX_STACK_DEPTH_EXT 0x8E2F -#endif - -#ifndef GL_EXT_vertex_array_bgra -/* reuse GL_BGRA */ -#endif - -#ifndef GL_EXT_texture_swizzle -#define GL_TEXTURE_SWIZZLE_R_EXT 0x8E42 -#define GL_TEXTURE_SWIZZLE_G_EXT 0x8E43 -#define GL_TEXTURE_SWIZZLE_B_EXT 0x8E44 -#define GL_TEXTURE_SWIZZLE_A_EXT 0x8E45 -#define GL_TEXTURE_SWIZZLE_RGBA_EXT 0x8E46 -#endif - -#ifndef GL_NV_explicit_multisample -#define GL_SAMPLE_POSITION_NV 0x8E50 -#define GL_SAMPLE_MASK_NV 0x8E51 -#define GL_SAMPLE_MASK_VALUE_NV 0x8E52 -#define GL_TEXTURE_BINDING_RENDERBUFFER_NV 0x8E53 -#define GL_TEXTURE_RENDERBUFFER_DATA_STORE_BINDING_NV 0x8E54 -#define GL_TEXTURE_RENDERBUFFER_NV 0x8E55 -#define GL_SAMPLER_RENDERBUFFER_NV 0x8E56 -#define GL_INT_SAMPLER_RENDERBUFFER_NV 0x8E57 -#define GL_UNSIGNED_INT_SAMPLER_RENDERBUFFER_NV 0x8E58 -#define GL_MAX_SAMPLE_MASK_WORDS_NV 0x8E59 -#endif - -#ifndef GL_NV_transform_feedback2 -#define GL_TRANSFORM_FEEDBACK_NV 0x8E22 -#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED_NV 0x8E23 -#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE_NV 0x8E24 -#define GL_TRANSFORM_FEEDBACK_BINDING_NV 0x8E25 -#endif - -#ifndef GL_ATI_meminfo -#define GL_VBO_FREE_MEMORY_ATI 0x87FB -#define GL_TEXTURE_FREE_MEMORY_ATI 0x87FC -#define GL_RENDERBUFFER_FREE_MEMORY_ATI 0x87FD -#endif - -#ifndef GL_AMD_performance_monitor -#define GL_COUNTER_TYPE_AMD 0x8BC0 -#define GL_COUNTER_RANGE_AMD 0x8BC1 -#define GL_UNSIGNED_INT64_AMD 0x8BC2 -#define GL_PERCENTAGE_AMD 0x8BC3 -#define GL_PERFMON_RESULT_AVAILABLE_AMD 0x8BC4 -#define GL_PERFMON_RESULT_SIZE_AMD 0x8BC5 -#define GL_PERFMON_RESULT_AMD 0x8BC6 -#endif - -#ifndef GL_AMD_texture_texture4 -#endif - -#ifndef GL_AMD_vertex_shader_tesselator -#define GL_SAMPLER_BUFFER_AMD 0x9001 -#define GL_INT_SAMPLER_BUFFER_AMD 0x9002 -#define GL_UNSIGNED_INT_SAMPLER_BUFFER_AMD 0x9003 -#define GL_TESSELLATION_MODE_AMD 0x9004 -#define GL_TESSELLATION_FACTOR_AMD 0x9005 -#define GL_DISCRETE_AMD 0x9006 -#define GL_CONTINUOUS_AMD 0x9007 -#endif - -#ifndef GL_EXT_provoking_vertex -#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT 0x8E4C -#define GL_FIRST_VERTEX_CONVENTION_EXT 0x8E4D -#define GL_LAST_VERTEX_CONVENTION_EXT 0x8E4E -#define GL_PROVOKING_VERTEX_EXT 0x8E4F -#endif - -#ifndef GL_EXT_texture_snorm -#define GL_ALPHA_SNORM 0x9010 -#define GL_LUMINANCE_SNORM 0x9011 -#define GL_LUMINANCE_ALPHA_SNORM 0x9012 -#define GL_INTENSITY_SNORM 0x9013 -#define GL_ALPHA8_SNORM 0x9014 -#define GL_LUMINANCE8_SNORM 0x9015 -#define GL_LUMINANCE8_ALPHA8_SNORM 0x9016 -#define GL_INTENSITY8_SNORM 0x9017 -#define GL_ALPHA16_SNORM 0x9018 -#define GL_LUMINANCE16_SNORM 0x9019 -#define GL_LUMINANCE16_ALPHA16_SNORM 0x901A -#define GL_INTENSITY16_SNORM 0x901B -/* reuse GL_RED_SNORM */ -/* reuse GL_RG_SNORM */ -/* reuse GL_RGB_SNORM */ -/* reuse GL_RGBA_SNORM */ -/* reuse GL_R8_SNORM */ -/* reuse GL_RG8_SNORM */ -/* reuse GL_RGB8_SNORM */ -/* reuse GL_RGBA8_SNORM */ -/* reuse GL_R16_SNORM */ -/* reuse GL_RG16_SNORM */ -/* reuse GL_RGB16_SNORM */ -/* reuse GL_RGBA16_SNORM */ -/* reuse GL_SIGNED_NORMALIZED */ -#endif - -#ifndef GL_AMD_draw_buffers_blend -#endif - -#ifndef GL_APPLE_texture_range -#define GL_TEXTURE_RANGE_LENGTH_APPLE 0x85B7 -#define GL_TEXTURE_RANGE_POINTER_APPLE 0x85B8 -#define GL_TEXTURE_STORAGE_HINT_APPLE 0x85BC -#define GL_STORAGE_PRIVATE_APPLE 0x85BD -/* reuse GL_STORAGE_CACHED_APPLE */ -/* reuse GL_STORAGE_SHARED_APPLE */ -#endif - -#ifndef GL_APPLE_float_pixels -#define GL_HALF_APPLE 0x140B -#define GL_RGBA_FLOAT32_APPLE 0x8814 -#define GL_RGB_FLOAT32_APPLE 0x8815 -#define GL_ALPHA_FLOAT32_APPLE 0x8816 -#define GL_INTENSITY_FLOAT32_APPLE 0x8817 -#define GL_LUMINANCE_FLOAT32_APPLE 0x8818 -#define GL_LUMINANCE_ALPHA_FLOAT32_APPLE 0x8819 -#define GL_RGBA_FLOAT16_APPLE 0x881A -#define GL_RGB_FLOAT16_APPLE 0x881B -#define GL_ALPHA_FLOAT16_APPLE 0x881C -#define GL_INTENSITY_FLOAT16_APPLE 0x881D -#define GL_LUMINANCE_FLOAT16_APPLE 0x881E -#define GL_LUMINANCE_ALPHA_FLOAT16_APPLE 0x881F -#define GL_COLOR_FLOAT_APPLE 0x8A0F -#endif - -#ifndef GL_APPLE_vertex_program_evaluators -#define GL_VERTEX_ATTRIB_MAP1_APPLE 0x8A00 -#define GL_VERTEX_ATTRIB_MAP2_APPLE 0x8A01 -#define GL_VERTEX_ATTRIB_MAP1_SIZE_APPLE 0x8A02 -#define GL_VERTEX_ATTRIB_MAP1_COEFF_APPLE 0x8A03 -#define GL_VERTEX_ATTRIB_MAP1_ORDER_APPLE 0x8A04 -#define GL_VERTEX_ATTRIB_MAP1_DOMAIN_APPLE 0x8A05 -#define GL_VERTEX_ATTRIB_MAP2_SIZE_APPLE 0x8A06 -#define GL_VERTEX_ATTRIB_MAP2_COEFF_APPLE 0x8A07 -#define GL_VERTEX_ATTRIB_MAP2_ORDER_APPLE 0x8A08 -#define GL_VERTEX_ATTRIB_MAP2_DOMAIN_APPLE 0x8A09 -#endif - -#ifndef GL_APPLE_aux_depth_stencil -#define GL_AUX_DEPTH_STENCIL_APPLE 0x8A14 -#endif - -#ifndef GL_APPLE_object_purgeable -#define GL_BUFFER_OBJECT_APPLE 0x85B3 -#define GL_RELEASED_APPLE 0x8A19 -#define GL_VOLATILE_APPLE 0x8A1A -#define GL_RETAINED_APPLE 0x8A1B -#define GL_UNDEFINED_APPLE 0x8A1C -#define GL_PURGEABLE_APPLE 0x8A1D -#endif - -#ifndef GL_APPLE_row_bytes -#define GL_PACK_ROW_BYTES_APPLE 0x8A15 -#define GL_UNPACK_ROW_BYTES_APPLE 0x8A16 -#endif - -#ifndef GL_APPLE_rgb_422 -#define GL_RGB_422_APPLE 0x8A1F -/* reuse GL_UNSIGNED_SHORT_8_8_APPLE */ -/* reuse GL_UNSIGNED_SHORT_8_8_REV_APPLE */ -#endif - -#ifndef GL_NV_video_capture -#define GL_VIDEO_BUFFER_NV 0x9020 -#define GL_VIDEO_BUFFER_BINDING_NV 0x9021 -#define GL_FIELD_UPPER_NV 0x9022 -#define GL_FIELD_LOWER_NV 0x9023 -#define GL_NUM_VIDEO_CAPTURE_STREAMS_NV 0x9024 -#define GL_NEXT_VIDEO_CAPTURE_BUFFER_STATUS_NV 0x9025 -#define GL_VIDEO_CAPTURE_TO_422_SUPPORTED_NV 0x9026 -#define GL_LAST_VIDEO_CAPTURE_STATUS_NV 0x9027 -#define GL_VIDEO_BUFFER_PITCH_NV 0x9028 -#define GL_VIDEO_COLOR_CONVERSION_MATRIX_NV 0x9029 -#define GL_VIDEO_COLOR_CONVERSION_MAX_NV 0x902A -#define GL_VIDEO_COLOR_CONVERSION_MIN_NV 0x902B -#define GL_VIDEO_COLOR_CONVERSION_OFFSET_NV 0x902C -#define GL_VIDEO_BUFFER_INTERNAL_FORMAT_NV 0x902D -#define GL_PARTIAL_SUCCESS_NV 0x902E -#define GL_SUCCESS_NV 0x902F -#define GL_FAILURE_NV 0x9030 -#define GL_YCBYCR8_422_NV 0x9031 -#define GL_YCBAYCR8A_4224_NV 0x9032 -#define GL_Z6Y10Z6CB10Z6Y10Z6CR10_422_NV 0x9033 -#define GL_Z6Y10Z6CB10Z6A10Z6Y10Z6CR10Z6A10_4224_NV 0x9034 -#define GL_Z4Y12Z4CB12Z4Y12Z4CR12_422_NV 0x9035 -#define GL_Z4Y12Z4CB12Z4A12Z4Y12Z4CR12Z4A12_4224_NV 0x9036 -#define GL_Z4Y12Z4CB12Z4CR12_444_NV 0x9037 -#define GL_VIDEO_CAPTURE_FRAME_WIDTH_NV 0x9038 -#define GL_VIDEO_CAPTURE_FRAME_HEIGHT_NV 0x9039 -#define GL_VIDEO_CAPTURE_FIELD_UPPER_HEIGHT_NV 0x903A -#define GL_VIDEO_CAPTURE_FIELD_LOWER_HEIGHT_NV 0x903B -#define GL_VIDEO_CAPTURE_SURFACE_ORIGIN_NV 0x903C -#endif - -#ifndef GL_NV_copy_image -#endif - -#ifndef GL_EXT_separate_shader_objects -#define GL_ACTIVE_PROGRAM_EXT 0x8B8D -#endif - -#ifndef GL_NV_parameter_buffer_object2 -#endif - -#ifndef GL_NV_shader_buffer_load -#define GL_BUFFER_GPU_ADDRESS_NV 0x8F1D -#define GL_GPU_ADDRESS_NV 0x8F34 -#define GL_MAX_SHADER_BUFFER_ADDRESS_NV 0x8F35 -#endif - -#ifndef GL_NV_vertex_buffer_unified_memory -#define GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV 0x8F1E -#define GL_ELEMENT_ARRAY_UNIFIED_NV 0x8F1F -#define GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV 0x8F20 -#define GL_VERTEX_ARRAY_ADDRESS_NV 0x8F21 -#define GL_NORMAL_ARRAY_ADDRESS_NV 0x8F22 -#define GL_COLOR_ARRAY_ADDRESS_NV 0x8F23 -#define GL_INDEX_ARRAY_ADDRESS_NV 0x8F24 -#define GL_TEXTURE_COORD_ARRAY_ADDRESS_NV 0x8F25 -#define GL_EDGE_FLAG_ARRAY_ADDRESS_NV 0x8F26 -#define GL_SECONDARY_COLOR_ARRAY_ADDRESS_NV 0x8F27 -#define GL_FOG_COORD_ARRAY_ADDRESS_NV 0x8F28 -#define GL_ELEMENT_ARRAY_ADDRESS_NV 0x8F29 -#define GL_VERTEX_ATTRIB_ARRAY_LENGTH_NV 0x8F2A -#define GL_VERTEX_ARRAY_LENGTH_NV 0x8F2B -#define GL_NORMAL_ARRAY_LENGTH_NV 0x8F2C -#define GL_COLOR_ARRAY_LENGTH_NV 0x8F2D -#define GL_INDEX_ARRAY_LENGTH_NV 0x8F2E -#define GL_TEXTURE_COORD_ARRAY_LENGTH_NV 0x8F2F -#define GL_EDGE_FLAG_ARRAY_LENGTH_NV 0x8F30 -#define GL_SECONDARY_COLOR_ARRAY_LENGTH_NV 0x8F31 -#define GL_FOG_COORD_ARRAY_LENGTH_NV 0x8F32 -#define GL_ELEMENT_ARRAY_LENGTH_NV 0x8F33 -#define GL_DRAW_INDIRECT_UNIFIED_NV 0x8F40 -#define GL_DRAW_INDIRECT_ADDRESS_NV 0x8F41 -#define GL_DRAW_INDIRECT_LENGTH_NV 0x8F42 -#endif - -#ifndef GL_NV_texture_barrier -#endif - -#ifndef GL_AMD_shader_stencil_export -#endif - -#ifndef GL_AMD_seamless_cubemap_per_texture -/* reuse GL_TEXTURE_CUBE_MAP_SEAMLESS */ -#endif - -#ifndef GL_AMD_conservative_depth -#endif - -#ifndef GL_EXT_shader_image_load_store -#define GL_MAX_IMAGE_UNITS_EXT 0x8F38 -#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS_EXT 0x8F39 -#define GL_IMAGE_BINDING_NAME_EXT 0x8F3A -#define GL_IMAGE_BINDING_LEVEL_EXT 0x8F3B -#define GL_IMAGE_BINDING_LAYERED_EXT 0x8F3C -#define GL_IMAGE_BINDING_LAYER_EXT 0x8F3D -#define GL_IMAGE_BINDING_ACCESS_EXT 0x8F3E -#define GL_IMAGE_1D_EXT 0x904C -#define GL_IMAGE_2D_EXT 0x904D -#define GL_IMAGE_3D_EXT 0x904E -#define GL_IMAGE_2D_RECT_EXT 0x904F -#define GL_IMAGE_CUBE_EXT 0x9050 -#define GL_IMAGE_BUFFER_EXT 0x9051 -#define GL_IMAGE_1D_ARRAY_EXT 0x9052 -#define GL_IMAGE_2D_ARRAY_EXT 0x9053 -#define GL_IMAGE_CUBE_MAP_ARRAY_EXT 0x9054 -#define GL_IMAGE_2D_MULTISAMPLE_EXT 0x9055 -#define GL_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x9056 -#define GL_INT_IMAGE_1D_EXT 0x9057 -#define GL_INT_IMAGE_2D_EXT 0x9058 -#define GL_INT_IMAGE_3D_EXT 0x9059 -#define GL_INT_IMAGE_2D_RECT_EXT 0x905A -#define GL_INT_IMAGE_CUBE_EXT 0x905B -#define GL_INT_IMAGE_BUFFER_EXT 0x905C -#define GL_INT_IMAGE_1D_ARRAY_EXT 0x905D -#define GL_INT_IMAGE_2D_ARRAY_EXT 0x905E -#define GL_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x905F -#define GL_INT_IMAGE_2D_MULTISAMPLE_EXT 0x9060 -#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x9061 -#define GL_UNSIGNED_INT_IMAGE_1D_EXT 0x9062 -#define GL_UNSIGNED_INT_IMAGE_2D_EXT 0x9063 -#define GL_UNSIGNED_INT_IMAGE_3D_EXT 0x9064 -#define GL_UNSIGNED_INT_IMAGE_2D_RECT_EXT 0x9065 -#define GL_UNSIGNED_INT_IMAGE_CUBE_EXT 0x9066 -#define GL_UNSIGNED_INT_IMAGE_BUFFER_EXT 0x9067 -#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY_EXT 0x9068 -#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY_EXT 0x9069 -#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x906A -#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_EXT 0x906B -#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x906C -#define GL_MAX_IMAGE_SAMPLES_EXT 0x906D -#define GL_IMAGE_BINDING_FORMAT_EXT 0x906E -#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT_EXT 0x00000001 -#define GL_ELEMENT_ARRAY_BARRIER_BIT_EXT 0x00000002 -#define GL_UNIFORM_BARRIER_BIT_EXT 0x00000004 -#define GL_TEXTURE_FETCH_BARRIER_BIT_EXT 0x00000008 -#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT_EXT 0x00000020 -#define GL_COMMAND_BARRIER_BIT_EXT 0x00000040 -#define GL_PIXEL_BUFFER_BARRIER_BIT_EXT 0x00000080 -#define GL_TEXTURE_UPDATE_BARRIER_BIT_EXT 0x00000100 -#define GL_BUFFER_UPDATE_BARRIER_BIT_EXT 0x00000200 -#define GL_FRAMEBUFFER_BARRIER_BIT_EXT 0x00000400 -#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT_EXT 0x00000800 -#define GL_ATOMIC_COUNTER_BARRIER_BIT_EXT 0x00001000 -#define GL_ALL_BARRIER_BITS_EXT 0xFFFFFFFF -#endif - -#ifndef GL_EXT_vertex_attrib_64bit -/* reuse GL_DOUBLE */ -#define GL_DOUBLE_VEC2_EXT 0x8FFC -#define GL_DOUBLE_VEC3_EXT 0x8FFD -#define GL_DOUBLE_VEC4_EXT 0x8FFE -#define GL_DOUBLE_MAT2_EXT 0x8F46 -#define GL_DOUBLE_MAT3_EXT 0x8F47 -#define GL_DOUBLE_MAT4_EXT 0x8F48 -#define GL_DOUBLE_MAT2x3_EXT 0x8F49 -#define GL_DOUBLE_MAT2x4_EXT 0x8F4A -#define GL_DOUBLE_MAT3x2_EXT 0x8F4B -#define GL_DOUBLE_MAT3x4_EXT 0x8F4C -#define GL_DOUBLE_MAT4x2_EXT 0x8F4D -#define GL_DOUBLE_MAT4x3_EXT 0x8F4E -#endif - -#ifndef GL_NV_gpu_program5 -#define GL_MAX_GEOMETRY_PROGRAM_INVOCATIONS_NV 0x8E5A -#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_NV 0x8E5B -#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_NV 0x8E5C -#define GL_FRAGMENT_PROGRAM_INTERPOLATION_OFFSET_BITS_NV 0x8E5D -#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_NV 0x8E5E -#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_NV 0x8E5F -#define GL_MAX_PROGRAM_SUBROUTINE_PARAMETERS_NV 0x8F44 -#define GL_MAX_PROGRAM_SUBROUTINE_NUM_NV 0x8F45 -#endif - -#ifndef GL_NV_gpu_shader5 -#define GL_INT64_NV 0x140E -#define GL_UNSIGNED_INT64_NV 0x140F -#define GL_INT8_NV 0x8FE0 -#define GL_INT8_VEC2_NV 0x8FE1 -#define GL_INT8_VEC3_NV 0x8FE2 -#define GL_INT8_VEC4_NV 0x8FE3 -#define GL_INT16_NV 0x8FE4 -#define GL_INT16_VEC2_NV 0x8FE5 -#define GL_INT16_VEC3_NV 0x8FE6 -#define GL_INT16_VEC4_NV 0x8FE7 -#define GL_INT64_VEC2_NV 0x8FE9 -#define GL_INT64_VEC3_NV 0x8FEA -#define GL_INT64_VEC4_NV 0x8FEB -#define GL_UNSIGNED_INT8_NV 0x8FEC -#define GL_UNSIGNED_INT8_VEC2_NV 0x8FED -#define GL_UNSIGNED_INT8_VEC3_NV 0x8FEE -#define GL_UNSIGNED_INT8_VEC4_NV 0x8FEF -#define GL_UNSIGNED_INT16_NV 0x8FF0 -#define GL_UNSIGNED_INT16_VEC2_NV 0x8FF1 -#define GL_UNSIGNED_INT16_VEC3_NV 0x8FF2 -#define GL_UNSIGNED_INT16_VEC4_NV 0x8FF3 -#define GL_UNSIGNED_INT64_VEC2_NV 0x8FF5 -#define GL_UNSIGNED_INT64_VEC3_NV 0x8FF6 -#define GL_UNSIGNED_INT64_VEC4_NV 0x8FF7 -#define GL_FLOAT16_NV 0x8FF8 -#define GL_FLOAT16_VEC2_NV 0x8FF9 -#define GL_FLOAT16_VEC3_NV 0x8FFA -#define GL_FLOAT16_VEC4_NV 0x8FFB -/* reuse GL_PATCHES */ -#endif - -#ifndef GL_NV_shader_buffer_store -#define GL_SHADER_GLOBAL_ACCESS_BARRIER_BIT_NV 0x00000010 -/* reuse GL_READ_WRITE */ -/* reuse GL_WRITE_ONLY */ -#endif - -#ifndef GL_NV_tessellation_program5 -#define GL_MAX_PROGRAM_PATCH_ATTRIBS_NV 0x86D8 -#define GL_TESS_CONTROL_PROGRAM_NV 0x891E -#define GL_TESS_EVALUATION_PROGRAM_NV 0x891F -#define GL_TESS_CONTROL_PROGRAM_PARAMETER_BUFFER_NV 0x8C74 -#define GL_TESS_EVALUATION_PROGRAM_PARAMETER_BUFFER_NV 0x8C75 -#endif - -#ifndef GL_NV_vertex_attrib_integer_64bit -/* reuse GL_INT64_NV */ -/* reuse GL_UNSIGNED_INT64_NV */ -#endif - -#ifndef GL_NV_multisample_coverage -#define GL_COVERAGE_SAMPLES_NV 0x80A9 -#define GL_COLOR_SAMPLES_NV 0x8E20 -#endif - -#ifndef GL_AMD_name_gen_delete -#define GL_DATA_BUFFER_AMD 0x9151 -#define GL_PERFORMANCE_MONITOR_AMD 0x9152 -#define GL_QUERY_OBJECT_AMD 0x9153 -#define GL_VERTEX_ARRAY_OBJECT_AMD 0x9154 -#define GL_SAMPLER_OBJECT_AMD 0x9155 -#endif - -#ifndef GL_AMD_debug_output -#define GL_MAX_DEBUG_LOGGED_MESSAGES_AMD 0x9144 -#define GL_DEBUG_LOGGED_MESSAGES_AMD 0x9145 -#define GL_DEBUG_SEVERITY_HIGH_AMD 0x9146 -#define GL_DEBUG_SEVERITY_MEDIUM_AMD 0x9147 -#define GL_DEBUG_SEVERITY_LOW_AMD 0x9148 -#define GL_DEBUG_CATEGORY_API_ERROR_AMD 0x9149 -#define GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD 0x914A -#define GL_DEBUG_CATEGORY_DEPRECATION_AMD 0x914B -#define GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD 0x914C -#define GL_DEBUG_CATEGORY_PERFORMANCE_AMD 0x914D -#define GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD 0x914E -#define GL_DEBUG_CATEGORY_APPLICATION_AMD 0x914F -#define GL_DEBUG_CATEGORY_OTHER_AMD 0x9150 -#endif - -#ifndef GL_NV_vdpau_interop -#define GL_SURFACE_STATE_NV 0x86EB -#define GL_SURFACE_REGISTERED_NV 0x86FD -#define GL_SURFACE_MAPPED_NV 0x8700 -#define GL_WRITE_DISCARD_NV 0x88BE -#endif - -#ifndef GL_AMD_transform_feedback3_lines_triangles -#endif - -#ifndef GL_AMD_depth_clamp_separate -#define GL_DEPTH_CLAMP_NEAR_AMD 0x901E -#define GL_DEPTH_CLAMP_FAR_AMD 0x901F -#endif - -#ifndef GL_EXT_texture_sRGB_decode -#define GL_TEXTURE_SRGB_DECODE_EXT 0x8A48 -#define GL_DECODE_EXT 0x8A49 -#define GL_SKIP_DECODE_EXT 0x8A4A -#endif - -#ifndef GL_NV_texture_multisample -#define GL_TEXTURE_COVERAGE_SAMPLES_NV 0x9045 -#define GL_TEXTURE_COLOR_SAMPLES_NV 0x9046 -#endif - -#ifndef GL_AMD_blend_minmax_factor -#define GL_FACTOR_MIN_AMD 0x901C -#define GL_FACTOR_MAX_AMD 0x901D -#endif - -#ifndef GL_AMD_sample_positions -#define GL_SUBSAMPLE_DISTANCE_AMD 0x883F -#endif - -#ifndef GL_EXT_x11_sync_object -#define GL_SYNC_X11_FENCE_EXT 0x90E1 -#endif - -#ifndef GL_AMD_multi_draw_indirect -#endif - -#ifndef GL_EXT_framebuffer_multisample_blit_scaled -#define GL_SCALED_RESOLVE_FASTEST_EXT 0x90BA -#define GL_SCALED_RESOLVE_NICEST_EXT 0x90BB -#endif - -#ifndef GL_NV_path_rendering -#define GL_PATH_FORMAT_SVG_NV 0x9070 -#define GL_PATH_FORMAT_PS_NV 0x9071 -#define GL_STANDARD_FONT_NAME_NV 0x9072 -#define GL_SYSTEM_FONT_NAME_NV 0x9073 -#define GL_FILE_NAME_NV 0x9074 -#define GL_PATH_STROKE_WIDTH_NV 0x9075 -#define GL_PATH_END_CAPS_NV 0x9076 -#define GL_PATH_INITIAL_END_CAP_NV 0x9077 -#define GL_PATH_TERMINAL_END_CAP_NV 0x9078 -#define GL_PATH_JOIN_STYLE_NV 0x9079 -#define GL_PATH_MITER_LIMIT_NV 0x907A -#define GL_PATH_DASH_CAPS_NV 0x907B -#define GL_PATH_INITIAL_DASH_CAP_NV 0x907C -#define GL_PATH_TERMINAL_DASH_CAP_NV 0x907D -#define GL_PATH_DASH_OFFSET_NV 0x907E -#define GL_PATH_CLIENT_LENGTH_NV 0x907F -#define GL_PATH_FILL_MODE_NV 0x9080 -#define GL_PATH_FILL_MASK_NV 0x9081 -#define GL_PATH_FILL_COVER_MODE_NV 0x9082 -#define GL_PATH_STROKE_COVER_MODE_NV 0x9083 -#define GL_PATH_STROKE_MASK_NV 0x9084 -#define GL_PATH_SAMPLE_QUALITY_NV 0x9085 -#define GL_PATH_STROKE_BOUND_NV 0x9086 -#define GL_PATH_STROKE_OVERSAMPLE_COUNT_NV 0x9087 -#define GL_COUNT_UP_NV 0x9088 -#define GL_COUNT_DOWN_NV 0x9089 -#define GL_PATH_OBJECT_BOUNDING_BOX_NV 0x908A -#define GL_CONVEX_HULL_NV 0x908B -#define GL_MULTI_HULLS_NV 0x908C -#define GL_BOUNDING_BOX_NV 0x908D -#define GL_TRANSLATE_X_NV 0x908E -#define GL_TRANSLATE_Y_NV 0x908F -#define GL_TRANSLATE_2D_NV 0x9090 -#define GL_TRANSLATE_3D_NV 0x9091 -#define GL_AFFINE_2D_NV 0x9092 -#define GL_PROJECTIVE_2D_NV 0x9093 -#define GL_AFFINE_3D_NV 0x9094 -#define GL_PROJECTIVE_3D_NV 0x9095 -#define GL_TRANSPOSE_AFFINE_2D_NV 0x9096 -#define GL_TRANSPOSE_PROJECTIVE_2D_NV 0x9097 -#define GL_TRANSPOSE_AFFINE_3D_NV 0x9098 -#define GL_TRANSPOSE_PROJECTIVE_3D_NV 0x9099 -#define GL_UTF8_NV 0x909A -#define GL_UTF16_NV 0x909B -#define GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV 0x909C -#define GL_PATH_COMMAND_COUNT_NV 0x909D -#define GL_PATH_COORD_COUNT_NV 0x909E -#define GL_PATH_DASH_ARRAY_COUNT_NV 0x909F -#define GL_PATH_COMPUTED_LENGTH_NV 0x90A0 -#define GL_PATH_FILL_BOUNDING_BOX_NV 0x90A1 -#define GL_PATH_STROKE_BOUNDING_BOX_NV 0x90A2 -#define GL_SQUARE_NV 0x90A3 -#define GL_ROUND_NV 0x90A4 -#define GL_TRIANGULAR_NV 0x90A5 -#define GL_BEVEL_NV 0x90A6 -#define GL_MITER_REVERT_NV 0x90A7 -#define GL_MITER_TRUNCATE_NV 0x90A8 -#define GL_SKIP_MISSING_GLYPH_NV 0x90A9 -#define GL_USE_MISSING_GLYPH_NV 0x90AA -#define GL_PATH_ERROR_POSITION_NV 0x90AB -#define GL_PATH_FOG_GEN_MODE_NV 0x90AC -#define GL_ACCUM_ADJACENT_PAIRS_NV 0x90AD -#define GL_ADJACENT_PAIRS_NV 0x90AE -#define GL_FIRST_TO_REST_NV 0x90AF -#define GL_PATH_GEN_MODE_NV 0x90B0 -#define GL_PATH_GEN_COEFF_NV 0x90B1 -#define GL_PATH_GEN_COLOR_FORMAT_NV 0x90B2 -#define GL_PATH_GEN_COMPONENTS_NV 0x90B3 -#define GL_PATH_STENCIL_FUNC_NV 0x90B7 -#define GL_PATH_STENCIL_REF_NV 0x90B8 -#define GL_PATH_STENCIL_VALUE_MASK_NV 0x90B9 -#define GL_PATH_STENCIL_DEPTH_OFFSET_FACTOR_NV 0x90BD -#define GL_PATH_STENCIL_DEPTH_OFFSET_UNITS_NV 0x90BE -#define GL_PATH_COVER_DEPTH_FUNC_NV 0x90BF -#define GL_PATH_DASH_OFFSET_RESET_NV 0x90B4 -#define GL_MOVE_TO_RESETS_NV 0x90B5 -#define GL_MOVE_TO_CONTINUES_NV 0x90B6 -#define GL_CLOSE_PATH_NV 0x00 -#define GL_MOVE_TO_NV 0x02 -#define GL_RELATIVE_MOVE_TO_NV 0x03 -#define GL_LINE_TO_NV 0x04 -#define GL_RELATIVE_LINE_TO_NV 0x05 -#define GL_HORIZONTAL_LINE_TO_NV 0x06 -#define GL_RELATIVE_HORIZONTAL_LINE_TO_NV 0x07 -#define GL_VERTICAL_LINE_TO_NV 0x08 -#define GL_RELATIVE_VERTICAL_LINE_TO_NV 0x09 -#define GL_QUADRATIC_CURVE_TO_NV 0x0A -#define GL_RELATIVE_QUADRATIC_CURVE_TO_NV 0x0B -#define GL_CUBIC_CURVE_TO_NV 0x0C -#define GL_RELATIVE_CUBIC_CURVE_TO_NV 0x0D -#define GL_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0E -#define GL_RELATIVE_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0F -#define GL_SMOOTH_CUBIC_CURVE_TO_NV 0x10 -#define GL_RELATIVE_SMOOTH_CUBIC_CURVE_TO_NV 0x11 -#define GL_SMALL_CCW_ARC_TO_NV 0x12 -#define GL_RELATIVE_SMALL_CCW_ARC_TO_NV 0x13 -#define GL_SMALL_CW_ARC_TO_NV 0x14 -#define GL_RELATIVE_SMALL_CW_ARC_TO_NV 0x15 -#define GL_LARGE_CCW_ARC_TO_NV 0x16 -#define GL_RELATIVE_LARGE_CCW_ARC_TO_NV 0x17 -#define GL_LARGE_CW_ARC_TO_NV 0x18 -#define GL_RELATIVE_LARGE_CW_ARC_TO_NV 0x19 -#define GL_RESTART_PATH_NV 0xF0 -#define GL_DUP_FIRST_CUBIC_CURVE_TO_NV 0xF2 -#define GL_DUP_LAST_CUBIC_CURVE_TO_NV 0xF4 -#define GL_RECT_NV 0xF6 -#define GL_CIRCULAR_CCW_ARC_TO_NV 0xF8 -#define GL_CIRCULAR_CW_ARC_TO_NV 0xFA -#define GL_CIRCULAR_TANGENT_ARC_TO_NV 0xFC -#define GL_ARC_TO_NV 0xFE -#define GL_RELATIVE_ARC_TO_NV 0xFF -#define GL_BOLD_BIT_NV 0x01 -#define GL_ITALIC_BIT_NV 0x02 -#define GL_GLYPH_WIDTH_BIT_NV 0x01 -#define GL_GLYPH_HEIGHT_BIT_NV 0x02 -#define GL_GLYPH_HORIZONTAL_BEARING_X_BIT_NV 0x04 -#define GL_GLYPH_HORIZONTAL_BEARING_Y_BIT_NV 0x08 -#define GL_GLYPH_HORIZONTAL_BEARING_ADVANCE_BIT_NV 0x10 -#define GL_GLYPH_VERTICAL_BEARING_X_BIT_NV 0x20 -#define GL_GLYPH_VERTICAL_BEARING_Y_BIT_NV 0x40 -#define GL_GLYPH_VERTICAL_BEARING_ADVANCE_BIT_NV 0x80 -#define GL_GLYPH_HAS_KERNING_NV 0x100 -#define GL_FONT_X_MIN_BOUNDS_NV 0x00010000 -#define GL_FONT_Y_MIN_BOUNDS_NV 0x00020000 -#define GL_FONT_X_MAX_BOUNDS_NV 0x00040000 -#define GL_FONT_Y_MAX_BOUNDS_NV 0x00080000 -#define GL_FONT_UNITS_PER_EM_NV 0x00100000 -#define GL_FONT_ASCENDER_NV 0x00200000 -#define GL_FONT_DESCENDER_NV 0x00400000 -#define GL_FONT_HEIGHT_NV 0x00800000 -#define GL_FONT_MAX_ADVANCE_WIDTH_NV 0x01000000 -#define GL_FONT_MAX_ADVANCE_HEIGHT_NV 0x02000000 -#define GL_FONT_UNDERLINE_POSITION_NV 0x04000000 -#define GL_FONT_UNDERLINE_THICKNESS_NV 0x08000000 -#define GL_FONT_HAS_KERNING_NV 0x10000000 -#endif - -#ifndef GL_AMD_pinned_memory -#define GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD 0x9160 -#endif - -#ifndef GL_AMD_stencil_operation_extended -#define GL_SET_AMD 0x874A -#define GL_REPLACE_VALUE_AMD 0x874B -#define GL_STENCIL_OP_VALUE_AMD 0x874C -#define GL_STENCIL_BACK_OP_VALUE_AMD 0x874D -#endif - - -/*************************************************************/ - -#include -#ifndef GL_VERSION_2_0 -/* GL type for program/shader text */ -typedef char GLchar; -#endif - -#ifndef GL_VERSION_1_5 -/* GL types for handling large vertex buffer objects */ -typedef ptrdiff_t GLintptr; -typedef ptrdiff_t GLsizeiptr; -#endif - -#ifndef GL_ARB_vertex_buffer_object -/* GL types for handling large vertex buffer objects */ -typedef ptrdiff_t GLintptrARB; -typedef ptrdiff_t GLsizeiptrARB; -#endif - -#ifndef GL_ARB_shader_objects -/* GL types for program/shader text and shader object handles */ -typedef char GLcharARB; -typedef unsigned int GLhandleARB; -#endif - -/* GL type for "half" precision (s10e5) float data in host memory */ -#ifndef GL_ARB_half_float_pixel -typedef unsigned short GLhalfARB; -#endif - -#ifndef GL_NV_half_float -typedef unsigned short GLhalfNV; -#endif - -#ifndef GLEXT_64_TYPES_DEFINED -/* This code block is duplicated in glxext.h, so must be protected */ -#define GLEXT_64_TYPES_DEFINED -/* Define int32_t, int64_t, and uint64_t types for UST/MSC */ -/* (as used in the GL_EXT_timer_query extension). */ -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L -#include -#elif defined(__sun__) || defined(__digital__) -#include -#if defined(__STDC__) -#if defined(__arch64__) || defined(_LP64) -typedef long int int64_t; -typedef unsigned long int uint64_t; -#else -typedef long long int int64_t; -typedef unsigned long long int uint64_t; -#endif /* __arch64__ */ -#endif /* __STDC__ */ -#elif defined( __VMS ) || defined(__sgi) -#include -#elif defined(__SCO__) || defined(__USLC__) -#include -#elif defined(__UNIXOS2__) || defined(__SOL64__) -typedef long int int32_t; -typedef long long int int64_t; -typedef unsigned long long int uint64_t; -#elif defined(_WIN32) && defined(__GNUC__) -#include -#elif defined(_WIN32) -typedef __int32 int32_t; -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -#else -/* Fallback if nothing above works */ -#include -#endif -#endif - -#ifndef GL_EXT_timer_query -typedef int64_t GLint64EXT; -typedef uint64_t GLuint64EXT; -#endif - -#ifndef GL_ARB_sync -typedef int64_t GLint64; -typedef uint64_t GLuint64; -typedef struct __GLsync *GLsync; -#endif - -#ifndef GL_ARB_cl_event -/* These incomplete types let us declare types compatible with OpenCL's cl_context and cl_event */ -struct _cl_context; -struct _cl_event; -#endif - -#ifndef GL_ARB_debug_output -typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,GLvoid *userParam); -#endif - -#ifndef GL_AMD_debug_output -typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,GLvoid *userParam); -#endif - -#ifndef GL_NV_vdpau_interop -typedef GLintptr GLvdpauSurfaceNV; -#endif - -#ifndef GL_VERSION_1_2 -#define GL_VERSION_1_2 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); -GLAPI void APIENTRY glBlendEquation (GLenum mode); -GLAPI void APIENTRY glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); -GLAPI void APIENTRY glTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBLENDCOLORPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); -typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode); -typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); -typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -#endif - -#ifndef GL_VERSION_1_2_DEPRECATED -#define GL_VERSION_1_2_DEPRECATED 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColorTable (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); -GLAPI void APIENTRY glColorTableParameterfv (GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glColorTableParameteriv (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glCopyColorTable (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glGetColorTable (GLenum target, GLenum format, GLenum type, GLvoid *table); -GLAPI void APIENTRY glGetColorTableParameterfv (GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetColorTableParameteriv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glColorSubTable (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); -GLAPI void APIENTRY glCopyColorSubTable (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glConvolutionFilter1D (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); -GLAPI void APIENTRY glConvolutionFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); -GLAPI void APIENTRY glConvolutionParameterf (GLenum target, GLenum pname, GLfloat params); -GLAPI void APIENTRY glConvolutionParameterfv (GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glConvolutionParameteri (GLenum target, GLenum pname, GLint params); -GLAPI void APIENTRY glConvolutionParameteriv (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glCopyConvolutionFilter1D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glCopyConvolutionFilter2D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetConvolutionFilter (GLenum target, GLenum format, GLenum type, GLvoid *image); -GLAPI void APIENTRY glGetConvolutionParameterfv (GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetConvolutionParameteriv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetSeparableFilter (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); -GLAPI void APIENTRY glSeparableFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); -GLAPI void APIENTRY glGetHistogram (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); -GLAPI void APIENTRY glGetHistogramParameterfv (GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetHistogramParameteriv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetMinmax (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); -GLAPI void APIENTRY glGetMinmaxParameterfv (GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetMinmaxParameteriv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glHistogram (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); -GLAPI void APIENTRY glMinmax (GLenum target, GLenum internalformat, GLboolean sink); -GLAPI void APIENTRY glResetHistogram (GLenum target); -GLAPI void APIENTRY glResetMinmax (GLenum target); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); -typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLCOPYCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table); -typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); -typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); -typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat params); -typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIPROC) (GLenum target, GLenum pname, GLint params); -typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image); -typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); -typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); -typedef void (APIENTRYP PFNGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); -typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); -typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLHISTOGRAMPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); -typedef void (APIENTRYP PFNGLMINMAXPROC) (GLenum target, GLenum internalformat, GLboolean sink); -typedef void (APIENTRYP PFNGLRESETHISTOGRAMPROC) (GLenum target); -typedef void (APIENTRYP PFNGLRESETMINMAXPROC) (GLenum target); -#endif - -#ifndef GL_VERSION_1_3 -#define GL_VERSION_1_3 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glActiveTexture (GLenum texture); -GLAPI void APIENTRY glSampleCoverage (GLclampf value, GLboolean invert); -GLAPI void APIENTRY glCompressedTexImage3D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexImage1D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glGetCompressedTexImage (GLenum target, GLint level, GLvoid *img); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture); -typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLclampf value, GLboolean invert); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, GLvoid *img); -#endif - -#ifndef GL_VERSION_1_3_DEPRECATED -#define GL_VERSION_1_3_DEPRECATED 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glClientActiveTexture (GLenum texture); -GLAPI void APIENTRY glMultiTexCoord1d (GLenum target, GLdouble s); -GLAPI void APIENTRY glMultiTexCoord1dv (GLenum target, const GLdouble *v); -GLAPI void APIENTRY glMultiTexCoord1f (GLenum target, GLfloat s); -GLAPI void APIENTRY glMultiTexCoord1fv (GLenum target, const GLfloat *v); -GLAPI void APIENTRY glMultiTexCoord1i (GLenum target, GLint s); -GLAPI void APIENTRY glMultiTexCoord1iv (GLenum target, const GLint *v); -GLAPI void APIENTRY glMultiTexCoord1s (GLenum target, GLshort s); -GLAPI void APIENTRY glMultiTexCoord1sv (GLenum target, const GLshort *v); -GLAPI void APIENTRY glMultiTexCoord2d (GLenum target, GLdouble s, GLdouble t); -GLAPI void APIENTRY glMultiTexCoord2dv (GLenum target, const GLdouble *v); -GLAPI void APIENTRY glMultiTexCoord2f (GLenum target, GLfloat s, GLfloat t); -GLAPI void APIENTRY glMultiTexCoord2fv (GLenum target, const GLfloat *v); -GLAPI void APIENTRY glMultiTexCoord2i (GLenum target, GLint s, GLint t); -GLAPI void APIENTRY glMultiTexCoord2iv (GLenum target, const GLint *v); -GLAPI void APIENTRY glMultiTexCoord2s (GLenum target, GLshort s, GLshort t); -GLAPI void APIENTRY glMultiTexCoord2sv (GLenum target, const GLshort *v); -GLAPI void APIENTRY glMultiTexCoord3d (GLenum target, GLdouble s, GLdouble t, GLdouble r); -GLAPI void APIENTRY glMultiTexCoord3dv (GLenum target, const GLdouble *v); -GLAPI void APIENTRY glMultiTexCoord3f (GLenum target, GLfloat s, GLfloat t, GLfloat r); -GLAPI void APIENTRY glMultiTexCoord3fv (GLenum target, const GLfloat *v); -GLAPI void APIENTRY glMultiTexCoord3i (GLenum target, GLint s, GLint t, GLint r); -GLAPI void APIENTRY glMultiTexCoord3iv (GLenum target, const GLint *v); -GLAPI void APIENTRY glMultiTexCoord3s (GLenum target, GLshort s, GLshort t, GLshort r); -GLAPI void APIENTRY glMultiTexCoord3sv (GLenum target, const GLshort *v); -GLAPI void APIENTRY glMultiTexCoord4d (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); -GLAPI void APIENTRY glMultiTexCoord4dv (GLenum target, const GLdouble *v); -GLAPI void APIENTRY glMultiTexCoord4f (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); -GLAPI void APIENTRY glMultiTexCoord4fv (GLenum target, const GLfloat *v); -GLAPI void APIENTRY glMultiTexCoord4i (GLenum target, GLint s, GLint t, GLint r, GLint q); -GLAPI void APIENTRY glMultiTexCoord4iv (GLenum target, const GLint *v); -GLAPI void APIENTRY glMultiTexCoord4s (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); -GLAPI void APIENTRY glMultiTexCoord4sv (GLenum target, const GLshort *v); -GLAPI void APIENTRY glLoadTransposeMatrixf (const GLfloat *m); -GLAPI void APIENTRY glLoadTransposeMatrixd (const GLdouble *m); -GLAPI void APIENTRY glMultTransposeMatrixf (const GLfloat *m); -GLAPI void APIENTRY glMultTransposeMatrixd (const GLdouble *m); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1DPROC) (GLenum target, GLdouble s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVPROC) (GLenum target, const GLdouble *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1FPROC) (GLenum target, GLfloat s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVPROC) (GLenum target, const GLfloat *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1IPROC) (GLenum target, GLint s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVPROC) (GLenum target, const GLint *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1SPROC) (GLenum target, GLshort s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVPROC) (GLenum target, const GLshort *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2DPROC) (GLenum target, GLdouble s, GLdouble t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVPROC) (GLenum target, const GLdouble *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC) (GLenum target, GLfloat s, GLfloat t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVPROC) (GLenum target, const GLfloat *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2IPROC) (GLenum target, GLint s, GLint t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVPROC) (GLenum target, const GLint *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2SPROC) (GLenum target, GLshort s, GLshort t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVPROC) (GLenum target, const GLshort *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVPROC) (GLenum target, const GLdouble *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVPROC) (GLenum target, const GLfloat *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3IPROC) (GLenum target, GLint s, GLint t, GLint r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVPROC) (GLenum target, const GLint *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3SPROC) (GLenum target, GLshort s, GLshort t, GLshort r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVPROC) (GLenum target, const GLshort *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVPROC) (GLenum target, const GLdouble *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVPROC) (GLenum target, const GLfloat *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4IPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVPROC) (GLenum target, const GLint *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4SPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVPROC) (GLenum target, const GLshort *v); -typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFPROC) (const GLfloat *m); -typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDPROC) (const GLdouble *m); -typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFPROC) (const GLfloat *m); -typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDPROC) (const GLdouble *m); -#endif - -#ifndef GL_VERSION_1_4 -#define GL_VERSION_1_4 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); -GLAPI void APIENTRY glMultiDrawArrays (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); -GLAPI void APIENTRY glMultiDrawElements (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); -GLAPI void APIENTRY glPointParameterf (GLenum pname, GLfloat param); -GLAPI void APIENTRY glPointParameterfv (GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glPointParameteri (GLenum pname, GLint param); -GLAPI void APIENTRY glPointParameteriv (GLenum pname, const GLint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); -typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); -typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC) (GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC) (GLenum pname, const GLint *params); -#endif - -#ifndef GL_VERSION_1_4_DEPRECATED -#define GL_VERSION_1_4_DEPRECATED 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFogCoordf (GLfloat coord); -GLAPI void APIENTRY glFogCoordfv (const GLfloat *coord); -GLAPI void APIENTRY glFogCoordd (GLdouble coord); -GLAPI void APIENTRY glFogCoorddv (const GLdouble *coord); -GLAPI void APIENTRY glFogCoordPointer (GLenum type, GLsizei stride, const GLvoid *pointer); -GLAPI void APIENTRY glSecondaryColor3b (GLbyte red, GLbyte green, GLbyte blue); -GLAPI void APIENTRY glSecondaryColor3bv (const GLbyte *v); -GLAPI void APIENTRY glSecondaryColor3d (GLdouble red, GLdouble green, GLdouble blue); -GLAPI void APIENTRY glSecondaryColor3dv (const GLdouble *v); -GLAPI void APIENTRY glSecondaryColor3f (GLfloat red, GLfloat green, GLfloat blue); -GLAPI void APIENTRY glSecondaryColor3fv (const GLfloat *v); -GLAPI void APIENTRY glSecondaryColor3i (GLint red, GLint green, GLint blue); -GLAPI void APIENTRY glSecondaryColor3iv (const GLint *v); -GLAPI void APIENTRY glSecondaryColor3s (GLshort red, GLshort green, GLshort blue); -GLAPI void APIENTRY glSecondaryColor3sv (const GLshort *v); -GLAPI void APIENTRY glSecondaryColor3ub (GLubyte red, GLubyte green, GLubyte blue); -GLAPI void APIENTRY glSecondaryColor3ubv (const GLubyte *v); -GLAPI void APIENTRY glSecondaryColor3ui (GLuint red, GLuint green, GLuint blue); -GLAPI void APIENTRY glSecondaryColor3uiv (const GLuint *v); -GLAPI void APIENTRY glSecondaryColor3us (GLushort red, GLushort green, GLushort blue); -GLAPI void APIENTRY glSecondaryColor3usv (const GLushort *v); -GLAPI void APIENTRY glSecondaryColorPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -GLAPI void APIENTRY glWindowPos2d (GLdouble x, GLdouble y); -GLAPI void APIENTRY glWindowPos2dv (const GLdouble *v); -GLAPI void APIENTRY glWindowPos2f (GLfloat x, GLfloat y); -GLAPI void APIENTRY glWindowPos2fv (const GLfloat *v); -GLAPI void APIENTRY glWindowPos2i (GLint x, GLint y); -GLAPI void APIENTRY glWindowPos2iv (const GLint *v); -GLAPI void APIENTRY glWindowPos2s (GLshort x, GLshort y); -GLAPI void APIENTRY glWindowPos2sv (const GLshort *v); -GLAPI void APIENTRY glWindowPos3d (GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glWindowPos3dv (const GLdouble *v); -GLAPI void APIENTRY glWindowPos3f (GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glWindowPos3fv (const GLfloat *v); -GLAPI void APIENTRY glWindowPos3i (GLint x, GLint y, GLint z); -GLAPI void APIENTRY glWindowPos3iv (const GLint *v); -GLAPI void APIENTRY glWindowPos3s (GLshort x, GLshort y, GLshort z); -GLAPI void APIENTRY glWindowPos3sv (const GLshort *v); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLFOGCOORDFPROC) (GLfloat coord); -typedef void (APIENTRYP PFNGLFOGCOORDFVPROC) (const GLfloat *coord); -typedef void (APIENTRYP PFNGLFOGCOORDDPROC) (GLdouble coord); -typedef void (APIENTRYP PFNGLFOGCOORDDVPROC) (const GLdouble *coord); -typedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BPROC) (GLbyte red, GLbyte green, GLbyte blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVPROC) (const GLbyte *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DPROC) (GLdouble red, GLdouble green, GLdouble blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FPROC) (GLfloat red, GLfloat green, GLfloat blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IPROC) (GLint red, GLint green, GLint blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SPROC) (GLshort red, GLshort green, GLshort blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVPROC) (const GLshort *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBPROC) (GLubyte red, GLubyte green, GLubyte blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVPROC) (const GLubyte *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIPROC) (GLuint red, GLuint green, GLuint blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVPROC) (const GLuint *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USPROC) (GLushort red, GLushort green, GLushort blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVPROC) (const GLushort *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLWINDOWPOS2DPROC) (GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLWINDOWPOS2DVPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLWINDOWPOS2FPROC) (GLfloat x, GLfloat y); -typedef void (APIENTRYP PFNGLWINDOWPOS2FVPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLWINDOWPOS2IPROC) (GLint x, GLint y); -typedef void (APIENTRYP PFNGLWINDOWPOS2IVPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLWINDOWPOS2SPROC) (GLshort x, GLshort y); -typedef void (APIENTRYP PFNGLWINDOWPOS2SVPROC) (const GLshort *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3DPROC) (GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLWINDOWPOS3DVPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3FPROC) (GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLWINDOWPOS3FVPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3IPROC) (GLint x, GLint y, GLint z); -typedef void (APIENTRYP PFNGLWINDOWPOS3IVPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3SPROC) (GLshort x, GLshort y, GLshort z); -typedef void (APIENTRYP PFNGLWINDOWPOS3SVPROC) (const GLshort *v); -#endif - -#ifndef GL_VERSION_1_5 -#define GL_VERSION_1_5 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGenQueries (GLsizei n, GLuint *ids); -GLAPI void APIENTRY glDeleteQueries (GLsizei n, const GLuint *ids); -GLAPI GLboolean APIENTRY glIsQuery (GLuint id); -GLAPI void APIENTRY glBeginQuery (GLenum target, GLuint id); -GLAPI void APIENTRY glEndQuery (GLenum target); -GLAPI void APIENTRY glGetQueryiv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetQueryObjectiv (GLuint id, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetQueryObjectuiv (GLuint id, GLenum pname, GLuint *params); -GLAPI void APIENTRY glBindBuffer (GLenum target, GLuint buffer); -GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers); -GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers); -GLAPI GLboolean APIENTRY glIsBuffer (GLuint buffer); -GLAPI void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); -GLAPI void APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); -GLAPI void APIENTRY glGetBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data); -GLAPI GLvoid* APIENTRY glMapBuffer (GLenum target, GLenum access); -GLAPI GLboolean APIENTRY glUnmapBuffer (GLenum target); -GLAPI void APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetBufferPointerv (GLenum target, GLenum pname, GLvoid* *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids); -typedef void (APIENTRYP PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids); -typedef GLboolean (APIENTRYP PFNGLISQUERYPROC) (GLuint id); -typedef void (APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id); -typedef void (APIENTRYP PFNGLENDQUERYPROC) (GLenum target); -typedef void (APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); -typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers); -typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers); -typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer); -typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); -typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); -typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data); -typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERPROC) (GLenum target, GLenum access); -typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target); -typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, GLvoid* *params); -#endif - -#ifndef GL_VERSION_2_0 -#define GL_VERSION_2_0 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha); -GLAPI void APIENTRY glDrawBuffers (GLsizei n, const GLenum *bufs); -GLAPI void APIENTRY glStencilOpSeparate (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); -GLAPI void APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask); -GLAPI void APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask); -GLAPI void APIENTRY glAttachShader (GLuint program, GLuint shader); -GLAPI void APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar *name); -GLAPI void APIENTRY glCompileShader (GLuint shader); -GLAPI GLuint APIENTRY glCreateProgram (void); -GLAPI GLuint APIENTRY glCreateShader (GLenum type); -GLAPI void APIENTRY glDeleteProgram (GLuint program); -GLAPI void APIENTRY glDeleteShader (GLuint shader); -GLAPI void APIENTRY glDetachShader (GLuint program, GLuint shader); -GLAPI void APIENTRY glDisableVertexAttribArray (GLuint index); -GLAPI void APIENTRY glEnableVertexAttribArray (GLuint index); -GLAPI void APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); -GLAPI void APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); -GLAPI void APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *obj); -GLAPI GLint APIENTRY glGetAttribLocation (GLuint program, const GLchar *name); -GLAPI void APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -GLAPI void APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -GLAPI void APIENTRY glGetShaderSource (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); -GLAPI GLint APIENTRY glGetUniformLocation (GLuint program, const GLchar *name); -GLAPI void APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat *params); -GLAPI void APIENTRY glGetUniformiv (GLuint program, GLint location, GLint *params); -GLAPI void APIENTRY glGetVertexAttribdv (GLuint index, GLenum pname, GLdouble *params); -GLAPI void APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, GLvoid* *pointer); -GLAPI GLboolean APIENTRY glIsProgram (GLuint program); -GLAPI GLboolean APIENTRY glIsShader (GLuint shader); -GLAPI void APIENTRY glLinkProgram (GLuint program); -GLAPI void APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar* *string, const GLint *length); -GLAPI void APIENTRY glUseProgram (GLuint program); -GLAPI void APIENTRY glUniform1f (GLint location, GLfloat v0); -GLAPI void APIENTRY glUniform2f (GLint location, GLfloat v0, GLfloat v1); -GLAPI void APIENTRY glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -GLAPI void APIENTRY glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -GLAPI void APIENTRY glUniform1i (GLint location, GLint v0); -GLAPI void APIENTRY glUniform2i (GLint location, GLint v0, GLint v1); -GLAPI void APIENTRY glUniform3i (GLint location, GLint v0, GLint v1, GLint v2); -GLAPI void APIENTRY glUniform4i (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -GLAPI void APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glValidateProgram (GLuint program); -GLAPI void APIENTRY glVertexAttrib1d (GLuint index, GLdouble x); -GLAPI void APIENTRY glVertexAttrib1dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib1f (GLuint index, GLfloat x); -GLAPI void APIENTRY glVertexAttrib1fv (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib1s (GLuint index, GLshort x); -GLAPI void APIENTRY glVertexAttrib1sv (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib2d (GLuint index, GLdouble x, GLdouble y); -GLAPI void APIENTRY glVertexAttrib2dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib2f (GLuint index, GLfloat x, GLfloat y); -GLAPI void APIENTRY glVertexAttrib2fv (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib2s (GLuint index, GLshort x, GLshort y); -GLAPI void APIENTRY glVertexAttrib2sv (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib3d (GLuint index, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glVertexAttrib3dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib3f (GLuint index, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glVertexAttrib3fv (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib3s (GLuint index, GLshort x, GLshort y, GLshort z); -GLAPI void APIENTRY glVertexAttrib3sv (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib4Nbv (GLuint index, const GLbyte *v); -GLAPI void APIENTRY glVertexAttrib4Niv (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttrib4Nsv (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib4Nub (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); -GLAPI void APIENTRY glVertexAttrib4Nubv (GLuint index, const GLubyte *v); -GLAPI void APIENTRY glVertexAttrib4Nuiv (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttrib4Nusv (GLuint index, const GLushort *v); -GLAPI void APIENTRY glVertexAttrib4bv (GLuint index, const GLbyte *v); -GLAPI void APIENTRY glVertexAttrib4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glVertexAttrib4dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib4f (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glVertexAttrib4fv (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib4iv (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttrib4s (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); -GLAPI void APIENTRY glVertexAttrib4sv (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib4ubv (GLuint index, const GLubyte *v); -GLAPI void APIENTRY glVertexAttrib4uiv (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttrib4usv (GLuint index, const GLushort *v); -GLAPI void APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha); -typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs); -typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); -typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC) (GLenum face, GLenum func, GLint ref, GLuint mask); -typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask); -typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); -typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name); -typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader); -typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void); -typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type); -typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program); -typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader); -typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader); -typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index); -typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index); -typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); -typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *obj); -typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name); -typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); -typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name); -typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params); -typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, GLvoid* *pointer); -typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC) (GLuint program); -typedef GLboolean (APIENTRYP PFNGLISSHADERPROC) (GLuint shader); -typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program); -typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar* *string, const GLint *length); -typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program); -typedef void (APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0); -typedef void (APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1); -typedef void (APIENTRYP PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -typedef void (APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0); -typedef void (APIENTRYP PFNGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1); -typedef void (APIENTRYP PFNGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2); -typedef void (APIENTRYP PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -typedef void (APIENTRYP PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC) (GLuint index, GLdouble x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC) (GLuint index, GLshort x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC) (GLuint index, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC) (GLuint index, GLshort x, GLshort y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC) (GLuint index, GLshort x, GLshort y, GLshort z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC) (GLuint index, const GLbyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC) (GLuint index, const GLubyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC) (GLuint index, const GLushort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC) (GLuint index, const GLbyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); -#endif - -#ifndef GL_VERSION_2_1 -#define GL_VERSION_2_1 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glUniformMatrix2x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix3x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix2x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix4x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix3x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix4x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -#endif - -#ifndef GL_VERSION_3_0 -#define GL_VERSION_3_0 1 -/* OpenGL 3.0 also reuses entry points from these extensions: */ -/* ARB_framebuffer_object */ -/* ARB_map_buffer_range */ -/* ARB_vertex_array_object */ -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColorMaski (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); -GLAPI void APIENTRY glGetBooleani_v (GLenum target, GLuint index, GLboolean *data); -GLAPI void APIENTRY glGetIntegeri_v (GLenum target, GLuint index, GLint *data); -GLAPI void APIENTRY glEnablei (GLenum target, GLuint index); -GLAPI void APIENTRY glDisablei (GLenum target, GLuint index); -GLAPI GLboolean APIENTRY glIsEnabledi (GLenum target, GLuint index); -GLAPI void APIENTRY glBeginTransformFeedback (GLenum primitiveMode); -GLAPI void APIENTRY glEndTransformFeedback (void); -GLAPI void APIENTRY glBindBufferRange (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -GLAPI void APIENTRY glBindBufferBase (GLenum target, GLuint index, GLuint buffer); -GLAPI void APIENTRY glTransformFeedbackVaryings (GLuint program, GLsizei count, const GLchar* *varyings, GLenum bufferMode); -GLAPI void APIENTRY glGetTransformFeedbackVarying (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); -GLAPI void APIENTRY glClampColor (GLenum target, GLenum clamp); -GLAPI void APIENTRY glBeginConditionalRender (GLuint id, GLenum mode); -GLAPI void APIENTRY glEndConditionalRender (void); -GLAPI void APIENTRY glVertexAttribIPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -GLAPI void APIENTRY glGetVertexAttribIiv (GLuint index, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVertexAttribIuiv (GLuint index, GLenum pname, GLuint *params); -GLAPI void APIENTRY glVertexAttribI1i (GLuint index, GLint x); -GLAPI void APIENTRY glVertexAttribI2i (GLuint index, GLint x, GLint y); -GLAPI void APIENTRY glVertexAttribI3i (GLuint index, GLint x, GLint y, GLint z); -GLAPI void APIENTRY glVertexAttribI4i (GLuint index, GLint x, GLint y, GLint z, GLint w); -GLAPI void APIENTRY glVertexAttribI1ui (GLuint index, GLuint x); -GLAPI void APIENTRY glVertexAttribI2ui (GLuint index, GLuint x, GLuint y); -GLAPI void APIENTRY glVertexAttribI3ui (GLuint index, GLuint x, GLuint y, GLuint z); -GLAPI void APIENTRY glVertexAttribI4ui (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -GLAPI void APIENTRY glVertexAttribI1iv (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttribI2iv (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttribI3iv (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttribI4iv (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttribI1uiv (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttribI2uiv (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttribI3uiv (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttribI4uiv (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttribI4bv (GLuint index, const GLbyte *v); -GLAPI void APIENTRY glVertexAttribI4sv (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttribI4ubv (GLuint index, const GLubyte *v); -GLAPI void APIENTRY glVertexAttribI4usv (GLuint index, const GLushort *v); -GLAPI void APIENTRY glGetUniformuiv (GLuint program, GLint location, GLuint *params); -GLAPI void APIENTRY glBindFragDataLocation (GLuint program, GLuint color, const GLchar *name); -GLAPI GLint APIENTRY glGetFragDataLocation (GLuint program, const GLchar *name); -GLAPI void APIENTRY glUniform1ui (GLint location, GLuint v0); -GLAPI void APIENTRY glUniform2ui (GLint location, GLuint v0, GLuint v1); -GLAPI void APIENTRY glUniform3ui (GLint location, GLuint v0, GLuint v1, GLuint v2); -GLAPI void APIENTRY glUniform4ui (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -GLAPI void APIENTRY glUniform1uiv (GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glUniform2uiv (GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glUniform3uiv (GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glUniform4uiv (GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glTexParameterIiv (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glTexParameterIuiv (GLenum target, GLenum pname, const GLuint *params); -GLAPI void APIENTRY glGetTexParameterIiv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetTexParameterIuiv (GLenum target, GLenum pname, GLuint *params); -GLAPI void APIENTRY glClearBufferiv (GLenum buffer, GLint drawbuffer, const GLint *value); -GLAPI void APIENTRY glClearBufferuiv (GLenum buffer, GLint drawbuffer, const GLuint *value); -GLAPI void APIENTRY glClearBufferfv (GLenum buffer, GLint drawbuffer, const GLfloat *value); -GLAPI void APIENTRY glClearBufferfi (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); -GLAPI const GLubyte * APIENTRY glGetStringi (GLenum name, GLuint index); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCOLORMASKIPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); -typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data); -typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data); -typedef void (APIENTRYP PFNGLENABLEIPROC) (GLenum target, GLuint index); -typedef void (APIENTRYP PFNGLDISABLEIPROC) (GLenum target, GLuint index); -typedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC) (GLenum target, GLuint index); -typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC) (GLenum primitiveMode); -typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC) (void); -typedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -typedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC) (GLenum target, GLuint index, GLuint buffer); -typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC) (GLuint program, GLsizei count, const GLchar* *varyings, GLenum bufferMode); -typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); -typedef void (APIENTRYP PFNGLCLAMPCOLORPROC) (GLenum target, GLenum clamp); -typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC) (GLuint id, GLenum mode); -typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC) (void); -typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC) (GLuint index, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC) (GLuint index, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC) (GLuint index, GLint x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC) (GLuint index, GLint x, GLint y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC) (GLuint index, GLint x, GLint y, GLint z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC) (GLuint index, GLuint x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC) (GLuint index, GLuint x, GLuint y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC) (GLuint index, const GLbyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC) (GLuint index, const GLubyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC) (GLuint index, const GLushort *v); -typedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC) (GLuint program, GLint location, GLuint *params); -typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC) (GLuint program, GLuint color, const GLchar *name); -typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC) (GLuint program, const GLchar *name); -typedef void (APIENTRYP PFNGLUNIFORM1UIPROC) (GLint location, GLuint v0); -typedef void (APIENTRYP PFNGLUNIFORM2UIPROC) (GLint location, GLuint v0, GLuint v1); -typedef void (APIENTRYP PFNGLUNIFORM3UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2); -typedef void (APIENTRYP PFNGLUNIFORM4UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, const GLuint *params); -typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC) (GLenum buffer, GLint drawbuffer, const GLint *value); -typedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint *value); -typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value); -typedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); -typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGIPROC) (GLenum name, GLuint index); -#endif - -#ifndef GL_VERSION_3_1 -#define GL_VERSION_3_1 1 -/* OpenGL 3.1 also reuses entry points from these extensions: */ -/* ARB_copy_buffer */ -/* ARB_uniform_buffer_object */ -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawArraysInstanced (GLenum mode, GLint first, GLsizei count, GLsizei primcount); -GLAPI void APIENTRY glDrawElementsInstanced (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); -GLAPI void APIENTRY glTexBuffer (GLenum target, GLenum internalformat, GLuint buffer); -GLAPI void APIENTRY glPrimitiveRestartIndex (GLuint index); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); -typedef void (APIENTRYP PFNGLTEXBUFFERPROC) (GLenum target, GLenum internalformat, GLuint buffer); -typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC) (GLuint index); -#endif - -#ifndef GL_VERSION_3_2 -#define GL_VERSION_3_2 1 -/* OpenGL 3.2 also reuses entry points from these extensions: */ -/* ARB_draw_elements_base_vertex */ -/* ARB_provoking_vertex */ -/* ARB_sync */ -/* ARB_texture_multisample */ -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetInteger64i_v (GLenum target, GLuint index, GLint64 *data); -GLAPI void APIENTRY glGetBufferParameteri64v (GLenum target, GLenum pname, GLint64 *params); -GLAPI void APIENTRY glFramebufferTexture (GLenum target, GLenum attachment, GLuint texture, GLint level); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data); -typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC) (GLenum target, GLenum pname, GLint64 *params); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); -#endif - -#ifndef GL_VERSION_3_3 -#define GL_VERSION_3_3 1 -/* OpenGL 3.3 also reuses entry points from these extensions: */ -/* ARB_blend_func_extended */ -/* ARB_sampler_objects */ -/* ARB_explicit_attrib_location, but it has none */ -/* ARB_occlusion_query2 (no entry points) */ -/* ARB_shader_bit_encoding (no entry points) */ -/* ARB_texture_rgb10_a2ui (no entry points) */ -/* ARB_texture_swizzle (no entry points) */ -/* ARB_timer_query */ -/* ARB_vertex_type_2_10_10_10_rev */ -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexAttribDivisor (GLuint index, GLuint divisor); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint divisor); -#endif - -#ifndef GL_VERSION_4_0 -#define GL_VERSION_4_0 1 -/* OpenGL 4.0 also reuses entry points from these extensions: */ -/* ARB_texture_query_lod (no entry points) */ -/* ARB_draw_indirect */ -/* ARB_gpu_shader5 (no entry points) */ -/* ARB_gpu_shader_fp64 */ -/* ARB_shader_subroutine */ -/* ARB_tessellation_shader */ -/* ARB_texture_buffer_object_rgb32 (no entry points) */ -/* ARB_texture_cube_map_array (no entry points) */ -/* ARB_texture_gather (no entry points) */ -/* ARB_transform_feedback2 */ -/* ARB_transform_feedback3 */ -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMinSampleShading (GLclampf value); -GLAPI void APIENTRY glBlendEquationi (GLuint buf, GLenum mode); -GLAPI void APIENTRY glBlendEquationSeparatei (GLuint buf, GLenum modeRGB, GLenum modeAlpha); -GLAPI void APIENTRY glBlendFunci (GLuint buf, GLenum src, GLenum dst); -GLAPI void APIENTRY glBlendFuncSeparatei (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLMINSAMPLESHADINGPROC) (GLclampf value); -typedef void (APIENTRYP PFNGLBLENDEQUATIONIPROC) (GLuint buf, GLenum mode); -typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); -typedef void (APIENTRYP PFNGLBLENDFUNCIPROC) (GLuint buf, GLenum src, GLenum dst); -typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); -#endif - -#ifndef GL_VERSION_4_1 -#define GL_VERSION_4_1 1 -/* OpenGL 4.1 reuses entry points from these extensions: */ -/* ARB_ES2_compatibility */ -/* ARB_get_program_binary */ -/* ARB_separate_shader_objects */ -/* ARB_shader_precision (no entry points) */ -/* ARB_vertex_attrib_64bit */ -/* ARB_viewport_array */ -#endif - -#ifndef GL_VERSION_4_2 -#define GL_VERSION_4_2 1 -/* OpenGL 4.2 reuses entry points from these extensions: */ -/* ARB_base_instance */ -/* ARB_shading_language_420pack (no entry points) */ -/* ARB_transform_feedback_instanced */ -/* ARB_compressed_texture_pixel_storage (no entry points) */ -/* ARB_conservative_depth (no entry points) */ -/* ARB_internalformat_query */ -/* ARB_map_buffer_alignment (no entry points) */ -/* ARB_shader_atomic_counters */ -/* ARB_shader_image_load_store */ -/* ARB_shading_language_packing (no entry points) */ -/* ARB_texture_storage */ -#endif - -#ifndef GL_ARB_multitexture -#define GL_ARB_multitexture 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glActiveTextureARB (GLenum texture); -GLAPI void APIENTRY glClientActiveTextureARB (GLenum texture); -GLAPI void APIENTRY glMultiTexCoord1dARB (GLenum target, GLdouble s); -GLAPI void APIENTRY glMultiTexCoord1dvARB (GLenum target, const GLdouble *v); -GLAPI void APIENTRY glMultiTexCoord1fARB (GLenum target, GLfloat s); -GLAPI void APIENTRY glMultiTexCoord1fvARB (GLenum target, const GLfloat *v); -GLAPI void APIENTRY glMultiTexCoord1iARB (GLenum target, GLint s); -GLAPI void APIENTRY glMultiTexCoord1ivARB (GLenum target, const GLint *v); -GLAPI void APIENTRY glMultiTexCoord1sARB (GLenum target, GLshort s); -GLAPI void APIENTRY glMultiTexCoord1svARB (GLenum target, const GLshort *v); -GLAPI void APIENTRY glMultiTexCoord2dARB (GLenum target, GLdouble s, GLdouble t); -GLAPI void APIENTRY glMultiTexCoord2dvARB (GLenum target, const GLdouble *v); -GLAPI void APIENTRY glMultiTexCoord2fARB (GLenum target, GLfloat s, GLfloat t); -GLAPI void APIENTRY glMultiTexCoord2fvARB (GLenum target, const GLfloat *v); -GLAPI void APIENTRY glMultiTexCoord2iARB (GLenum target, GLint s, GLint t); -GLAPI void APIENTRY glMultiTexCoord2ivARB (GLenum target, const GLint *v); -GLAPI void APIENTRY glMultiTexCoord2sARB (GLenum target, GLshort s, GLshort t); -GLAPI void APIENTRY glMultiTexCoord2svARB (GLenum target, const GLshort *v); -GLAPI void APIENTRY glMultiTexCoord3dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r); -GLAPI void APIENTRY glMultiTexCoord3dvARB (GLenum target, const GLdouble *v); -GLAPI void APIENTRY glMultiTexCoord3fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r); -GLAPI void APIENTRY glMultiTexCoord3fvARB (GLenum target, const GLfloat *v); -GLAPI void APIENTRY glMultiTexCoord3iARB (GLenum target, GLint s, GLint t, GLint r); -GLAPI void APIENTRY glMultiTexCoord3ivARB (GLenum target, const GLint *v); -GLAPI void APIENTRY glMultiTexCoord3sARB (GLenum target, GLshort s, GLshort t, GLshort r); -GLAPI void APIENTRY glMultiTexCoord3svARB (GLenum target, const GLshort *v); -GLAPI void APIENTRY glMultiTexCoord4dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); -GLAPI void APIENTRY glMultiTexCoord4dvARB (GLenum target, const GLdouble *v); -GLAPI void APIENTRY glMultiTexCoord4fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); -GLAPI void APIENTRY glMultiTexCoord4fvARB (GLenum target, const GLfloat *v); -GLAPI void APIENTRY glMultiTexCoord4iARB (GLenum target, GLint s, GLint t, GLint r, GLint q); -GLAPI void APIENTRY glMultiTexCoord4ivARB (GLenum target, const GLint *v); -GLAPI void APIENTRY glMultiTexCoord4sARB (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); -GLAPI void APIENTRY glMultiTexCoord4svARB (GLenum target, const GLshort *v); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLACTIVETEXTUREARBPROC) (GLenum texture); -typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v); -#endif - -#ifndef GL_ARB_transpose_matrix -#define GL_ARB_transpose_matrix 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glLoadTransposeMatrixfARB (const GLfloat *m); -GLAPI void APIENTRY glLoadTransposeMatrixdARB (const GLdouble *m); -GLAPI void APIENTRY glMultTransposeMatrixfARB (const GLfloat *m); -GLAPI void APIENTRY glMultTransposeMatrixdARB (const GLdouble *m); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFARBPROC) (const GLfloat *m); -typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDARBPROC) (const GLdouble *m); -typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFARBPROC) (const GLfloat *m); -typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDARBPROC) (const GLdouble *m); -#endif - -#ifndef GL_ARB_multisample -#define GL_ARB_multisample 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glSampleCoverageARB (GLclampf value, GLboolean invert); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLSAMPLECOVERAGEARBPROC) (GLclampf value, GLboolean invert); -#endif - -#ifndef GL_ARB_texture_env_add -#define GL_ARB_texture_env_add 1 -#endif - -#ifndef GL_ARB_texture_cube_map -#define GL_ARB_texture_cube_map 1 -#endif - -#ifndef GL_ARB_texture_compression -#define GL_ARB_texture_compression 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glCompressedTexImage3DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexImage2DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexImage1DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexSubImage3DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexSubImage2DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexSubImage1DARB (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glGetCompressedTexImageARB (GLenum target, GLint level, GLvoid *img); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint level, GLvoid *img); -#endif - -#ifndef GL_ARB_texture_border_clamp -#define GL_ARB_texture_border_clamp 1 -#endif - -#ifndef GL_ARB_point_parameters -#define GL_ARB_point_parameters 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPointParameterfARB (GLenum pname, GLfloat param); -GLAPI void APIENTRY glPointParameterfvARB (GLenum pname, const GLfloat *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPOINTPARAMETERFARBPROC) (GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLPOINTPARAMETERFVARBPROC) (GLenum pname, const GLfloat *params); -#endif - -#ifndef GL_ARB_vertex_blend -#define GL_ARB_vertex_blend 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glWeightbvARB (GLint size, const GLbyte *weights); -GLAPI void APIENTRY glWeightsvARB (GLint size, const GLshort *weights); -GLAPI void APIENTRY glWeightivARB (GLint size, const GLint *weights); -GLAPI void APIENTRY glWeightfvARB (GLint size, const GLfloat *weights); -GLAPI void APIENTRY glWeightdvARB (GLint size, const GLdouble *weights); -GLAPI void APIENTRY glWeightubvARB (GLint size, const GLubyte *weights); -GLAPI void APIENTRY glWeightusvARB (GLint size, const GLushort *weights); -GLAPI void APIENTRY glWeightuivARB (GLint size, const GLuint *weights); -GLAPI void APIENTRY glWeightPointerARB (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -GLAPI void APIENTRY glVertexBlendARB (GLint count); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLWEIGHTBVARBPROC) (GLint size, const GLbyte *weights); -typedef void (APIENTRYP PFNGLWEIGHTSVARBPROC) (GLint size, const GLshort *weights); -typedef void (APIENTRYP PFNGLWEIGHTIVARBPROC) (GLint size, const GLint *weights); -typedef void (APIENTRYP PFNGLWEIGHTFVARBPROC) (GLint size, const GLfloat *weights); -typedef void (APIENTRYP PFNGLWEIGHTDVARBPROC) (GLint size, const GLdouble *weights); -typedef void (APIENTRYP PFNGLWEIGHTUBVARBPROC) (GLint size, const GLubyte *weights); -typedef void (APIENTRYP PFNGLWEIGHTUSVARBPROC) (GLint size, const GLushort *weights); -typedef void (APIENTRYP PFNGLWEIGHTUIVARBPROC) (GLint size, const GLuint *weights); -typedef void (APIENTRYP PFNGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLVERTEXBLENDARBPROC) (GLint count); -#endif - -#ifndef GL_ARB_matrix_palette -#define GL_ARB_matrix_palette 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glCurrentPaletteMatrixARB (GLint index); -GLAPI void APIENTRY glMatrixIndexubvARB (GLint size, const GLubyte *indices); -GLAPI void APIENTRY glMatrixIndexusvARB (GLint size, const GLushort *indices); -GLAPI void APIENTRY glMatrixIndexuivARB (GLint size, const GLuint *indices); -GLAPI void APIENTRY glMatrixIndexPointerARB (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCURRENTPALETTEMATRIXARBPROC) (GLint index); -typedef void (APIENTRYP PFNGLMATRIXINDEXUBVARBPROC) (GLint size, const GLubyte *indices); -typedef void (APIENTRYP PFNGLMATRIXINDEXUSVARBPROC) (GLint size, const GLushort *indices); -typedef void (APIENTRYP PFNGLMATRIXINDEXUIVARBPROC) (GLint size, const GLuint *indices); -typedef void (APIENTRYP PFNGLMATRIXINDEXPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -#endif - -#ifndef GL_ARB_texture_env_combine -#define GL_ARB_texture_env_combine 1 -#endif - -#ifndef GL_ARB_texture_env_crossbar -#define GL_ARB_texture_env_crossbar 1 -#endif - -#ifndef GL_ARB_texture_env_dot3 -#define GL_ARB_texture_env_dot3 1 -#endif - -#ifndef GL_ARB_texture_mirrored_repeat -#define GL_ARB_texture_mirrored_repeat 1 -#endif - -#ifndef GL_ARB_depth_texture -#define GL_ARB_depth_texture 1 -#endif - -#ifndef GL_ARB_shadow -#define GL_ARB_shadow 1 -#endif - -#ifndef GL_ARB_shadow_ambient -#define GL_ARB_shadow_ambient 1 -#endif - -#ifndef GL_ARB_window_pos -#define GL_ARB_window_pos 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glWindowPos2dARB (GLdouble x, GLdouble y); -GLAPI void APIENTRY glWindowPos2dvARB (const GLdouble *v); -GLAPI void APIENTRY glWindowPos2fARB (GLfloat x, GLfloat y); -GLAPI void APIENTRY glWindowPos2fvARB (const GLfloat *v); -GLAPI void APIENTRY glWindowPos2iARB (GLint x, GLint y); -GLAPI void APIENTRY glWindowPos2ivARB (const GLint *v); -GLAPI void APIENTRY glWindowPos2sARB (GLshort x, GLshort y); -GLAPI void APIENTRY glWindowPos2svARB (const GLshort *v); -GLAPI void APIENTRY glWindowPos3dARB (GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glWindowPos3dvARB (const GLdouble *v); -GLAPI void APIENTRY glWindowPos3fARB (GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glWindowPos3fvARB (const GLfloat *v); -GLAPI void APIENTRY glWindowPos3iARB (GLint x, GLint y, GLint z); -GLAPI void APIENTRY glWindowPos3ivARB (const GLint *v); -GLAPI void APIENTRY glWindowPos3sARB (GLshort x, GLshort y, GLshort z); -GLAPI void APIENTRY glWindowPos3svARB (const GLshort *v); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLWINDOWPOS2DARBPROC) (GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLWINDOWPOS2DVARBPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLWINDOWPOS2FARBPROC) (GLfloat x, GLfloat y); -typedef void (APIENTRYP PFNGLWINDOWPOS2FVARBPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLWINDOWPOS2IARBPROC) (GLint x, GLint y); -typedef void (APIENTRYP PFNGLWINDOWPOS2IVARBPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLWINDOWPOS2SARBPROC) (GLshort x, GLshort y); -typedef void (APIENTRYP PFNGLWINDOWPOS2SVARBPROC) (const GLshort *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3DARBPROC) (GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLWINDOWPOS3DVARBPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3FARBPROC) (GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLWINDOWPOS3FVARBPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3IARBPROC) (GLint x, GLint y, GLint z); -typedef void (APIENTRYP PFNGLWINDOWPOS3IVARBPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3SARBPROC) (GLshort x, GLshort y, GLshort z); -typedef void (APIENTRYP PFNGLWINDOWPOS3SVARBPROC) (const GLshort *v); -#endif - -#ifndef GL_ARB_vertex_program -#define GL_ARB_vertex_program 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexAttrib1dARB (GLuint index, GLdouble x); -GLAPI void APIENTRY glVertexAttrib1dvARB (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib1fARB (GLuint index, GLfloat x); -GLAPI void APIENTRY glVertexAttrib1fvARB (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib1sARB (GLuint index, GLshort x); -GLAPI void APIENTRY glVertexAttrib1svARB (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib2dARB (GLuint index, GLdouble x, GLdouble y); -GLAPI void APIENTRY glVertexAttrib2dvARB (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib2fARB (GLuint index, GLfloat x, GLfloat y); -GLAPI void APIENTRY glVertexAttrib2fvARB (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib2sARB (GLuint index, GLshort x, GLshort y); -GLAPI void APIENTRY glVertexAttrib2svARB (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib3dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glVertexAttrib3dvARB (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib3fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glVertexAttrib3fvARB (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib3sARB (GLuint index, GLshort x, GLshort y, GLshort z); -GLAPI void APIENTRY glVertexAttrib3svARB (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib4NbvARB (GLuint index, const GLbyte *v); -GLAPI void APIENTRY glVertexAttrib4NivARB (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttrib4NsvARB (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib4NubARB (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); -GLAPI void APIENTRY glVertexAttrib4NubvARB (GLuint index, const GLubyte *v); -GLAPI void APIENTRY glVertexAttrib4NuivARB (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttrib4NusvARB (GLuint index, const GLushort *v); -GLAPI void APIENTRY glVertexAttrib4bvARB (GLuint index, const GLbyte *v); -GLAPI void APIENTRY glVertexAttrib4dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glVertexAttrib4dvARB (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib4fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glVertexAttrib4fvARB (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib4ivARB (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttrib4sARB (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); -GLAPI void APIENTRY glVertexAttrib4svARB (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib4ubvARB (GLuint index, const GLubyte *v); -GLAPI void APIENTRY glVertexAttrib4uivARB (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttrib4usvARB (GLuint index, const GLushort *v); -GLAPI void APIENTRY glVertexAttribPointerARB (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); -GLAPI void APIENTRY glEnableVertexAttribArrayARB (GLuint index); -GLAPI void APIENTRY glDisableVertexAttribArrayARB (GLuint index); -GLAPI void APIENTRY glProgramStringARB (GLenum target, GLenum format, GLsizei len, const GLvoid *string); -GLAPI void APIENTRY glBindProgramARB (GLenum target, GLuint program); -GLAPI void APIENTRY glDeleteProgramsARB (GLsizei n, const GLuint *programs); -GLAPI void APIENTRY glGenProgramsARB (GLsizei n, GLuint *programs); -GLAPI void APIENTRY glProgramEnvParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glProgramEnvParameter4dvARB (GLenum target, GLuint index, const GLdouble *params); -GLAPI void APIENTRY glProgramEnvParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glProgramEnvParameter4fvARB (GLenum target, GLuint index, const GLfloat *params); -GLAPI void APIENTRY glProgramLocalParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glProgramLocalParameter4dvARB (GLenum target, GLuint index, const GLdouble *params); -GLAPI void APIENTRY glProgramLocalParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glProgramLocalParameter4fvARB (GLenum target, GLuint index, const GLfloat *params); -GLAPI void APIENTRY glGetProgramEnvParameterdvARB (GLenum target, GLuint index, GLdouble *params); -GLAPI void APIENTRY glGetProgramEnvParameterfvARB (GLenum target, GLuint index, GLfloat *params); -GLAPI void APIENTRY glGetProgramLocalParameterdvARB (GLenum target, GLuint index, GLdouble *params); -GLAPI void APIENTRY glGetProgramLocalParameterfvARB (GLenum target, GLuint index, GLfloat *params); -GLAPI void APIENTRY glGetProgramivARB (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetProgramStringARB (GLenum target, GLenum pname, GLvoid *string); -GLAPI void APIENTRY glGetVertexAttribdvARB (GLuint index, GLenum pname, GLdouble *params); -GLAPI void APIENTRY glGetVertexAttribfvARB (GLuint index, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetVertexAttribivARB (GLuint index, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVertexAttribPointervARB (GLuint index, GLenum pname, GLvoid* *pointer); -GLAPI GLboolean APIENTRY glIsProgramARB (GLuint program); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVERTEXATTRIB1DARBPROC) (GLuint index, GLdouble x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVARBPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1FARBPROC) (GLuint index, GLfloat x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVARBPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1SARBPROC) (GLuint index, GLshort x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVARBPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2DARBPROC) (GLuint index, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVARBPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2FARBPROC) (GLuint index, GLfloat x, GLfloat y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVARBPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2SARBPROC) (GLuint index, GLshort x, GLshort y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVARBPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVARBPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVARBPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVARBPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVARBPROC) (GLuint index, const GLbyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVARBPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVARBPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBARBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVARBPROC) (GLuint index, const GLubyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVARBPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVARBPROC) (GLuint index, const GLushort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVARBPROC) (GLuint index, const GLbyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVARBPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVARBPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVARBPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVARBPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVARBPROC) (GLuint index, const GLubyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVARBPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVARBPROC) (GLuint index, const GLushort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYARBPROC) (GLuint index); -typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) (GLuint index); -typedef void (APIENTRYP PFNGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const GLvoid *string); -typedef void (APIENTRYP PFNGLBINDPROGRAMARBPROC) (GLenum target, GLuint program); -typedef void (APIENTRYP PFNGLDELETEPROGRAMSARBPROC) (GLsizei n, const GLuint *programs); -typedef void (APIENTRYP PFNGLGENPROGRAMSARBPROC) (GLsizei n, GLuint *programs); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params); -typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params); -typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params); -typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params); -typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params); -typedef void (APIENTRYP PFNGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, GLvoid *string); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVARBPROC) (GLuint index, GLenum pname, GLdouble *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVARBPROC) (GLuint index, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVARBPROC) (GLuint index, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, GLvoid* *pointer); -typedef GLboolean (APIENTRYP PFNGLISPROGRAMARBPROC) (GLuint program); -#endif - -#ifndef GL_ARB_fragment_program -#define GL_ARB_fragment_program 1 -/* All ARB_fragment_program entry points are shared with ARB_vertex_program. */ -#endif - -#ifndef GL_ARB_vertex_buffer_object -#define GL_ARB_vertex_buffer_object 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBindBufferARB (GLenum target, GLuint buffer); -GLAPI void APIENTRY glDeleteBuffersARB (GLsizei n, const GLuint *buffers); -GLAPI void APIENTRY glGenBuffersARB (GLsizei n, GLuint *buffers); -GLAPI GLboolean APIENTRY glIsBufferARB (GLuint buffer); -GLAPI void APIENTRY glBufferDataARB (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage); -GLAPI void APIENTRY glBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data); -GLAPI void APIENTRY glGetBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data); -GLAPI GLvoid* APIENTRY glMapBufferARB (GLenum target, GLenum access); -GLAPI GLboolean APIENTRY glUnmapBufferARB (GLenum target); -GLAPI void APIENTRY glGetBufferParameterivARB (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetBufferPointervARB (GLenum target, GLenum pname, GLvoid* *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer); -typedef void (APIENTRYP PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers); -typedef void (APIENTRYP PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers); -typedef GLboolean (APIENTRYP PFNGLISBUFFERARBPROC) (GLuint buffer); -typedef void (APIENTRYP PFNGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage); -typedef void (APIENTRYP PFNGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data); -typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data); -typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERARBPROC) (GLenum target, GLenum access); -typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERARBPROC) (GLenum target); -typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVARBPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, GLvoid* *params); -#endif - -#ifndef GL_ARB_occlusion_query -#define GL_ARB_occlusion_query 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGenQueriesARB (GLsizei n, GLuint *ids); -GLAPI void APIENTRY glDeleteQueriesARB (GLsizei n, const GLuint *ids); -GLAPI GLboolean APIENTRY glIsQueryARB (GLuint id); -GLAPI void APIENTRY glBeginQueryARB (GLenum target, GLuint id); -GLAPI void APIENTRY glEndQueryARB (GLenum target); -GLAPI void APIENTRY glGetQueryivARB (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetQueryObjectivARB (GLuint id, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetQueryObjectuivARB (GLuint id, GLenum pname, GLuint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGENQUERIESARBPROC) (GLsizei n, GLuint *ids); -typedef void (APIENTRYP PFNGLDELETEQUERIESARBPROC) (GLsizei n, const GLuint *ids); -typedef GLboolean (APIENTRYP PFNGLISQUERYARBPROC) (GLuint id); -typedef void (APIENTRYP PFNGLBEGINQUERYARBPROC) (GLenum target, GLuint id); -typedef void (APIENTRYP PFNGLENDQUERYARBPROC) (GLenum target); -typedef void (APIENTRYP PFNGLGETQUERYIVARBPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVARBPROC) (GLuint id, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVARBPROC) (GLuint id, GLenum pname, GLuint *params); -#endif - -#ifndef GL_ARB_shader_objects -#define GL_ARB_shader_objects 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDeleteObjectARB (GLhandleARB obj); -GLAPI GLhandleARB APIENTRY glGetHandleARB (GLenum pname); -GLAPI void APIENTRY glDetachObjectARB (GLhandleARB containerObj, GLhandleARB attachedObj); -GLAPI GLhandleARB APIENTRY glCreateShaderObjectARB (GLenum shaderType); -GLAPI void APIENTRY glShaderSourceARB (GLhandleARB shaderObj, GLsizei count, const GLcharARB* *string, const GLint *length); -GLAPI void APIENTRY glCompileShaderARB (GLhandleARB shaderObj); -GLAPI GLhandleARB APIENTRY glCreateProgramObjectARB (void); -GLAPI void APIENTRY glAttachObjectARB (GLhandleARB containerObj, GLhandleARB obj); -GLAPI void APIENTRY glLinkProgramARB (GLhandleARB programObj); -GLAPI void APIENTRY glUseProgramObjectARB (GLhandleARB programObj); -GLAPI void APIENTRY glValidateProgramARB (GLhandleARB programObj); -GLAPI void APIENTRY glUniform1fARB (GLint location, GLfloat v0); -GLAPI void APIENTRY glUniform2fARB (GLint location, GLfloat v0, GLfloat v1); -GLAPI void APIENTRY glUniform3fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -GLAPI void APIENTRY glUniform4fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -GLAPI void APIENTRY glUniform1iARB (GLint location, GLint v0); -GLAPI void APIENTRY glUniform2iARB (GLint location, GLint v0, GLint v1); -GLAPI void APIENTRY glUniform3iARB (GLint location, GLint v0, GLint v1, GLint v2); -GLAPI void APIENTRY glUniform4iARB (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -GLAPI void APIENTRY glUniform1fvARB (GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glUniform2fvARB (GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glUniform3fvARB (GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glUniform4fvARB (GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glUniform1ivARB (GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glUniform2ivARB (GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glUniform3ivARB (GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glUniform4ivARB (GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glUniformMatrix2fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix3fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glUniformMatrix4fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glGetObjectParameterfvARB (GLhandleARB obj, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetObjectParameterivARB (GLhandleARB obj, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetInfoLogARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); -GLAPI void APIENTRY glGetAttachedObjectsARB (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj); -GLAPI GLint APIENTRY glGetUniformLocationARB (GLhandleARB programObj, const GLcharARB *name); -GLAPI void APIENTRY glGetActiveUniformARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); -GLAPI void APIENTRY glGetUniformfvARB (GLhandleARB programObj, GLint location, GLfloat *params); -GLAPI void APIENTRY glGetUniformivARB (GLhandleARB programObj, GLint location, GLint *params); -GLAPI void APIENTRY glGetShaderSourceARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDELETEOBJECTARBPROC) (GLhandleARB obj); -typedef GLhandleARB (APIENTRYP PFNGLGETHANDLEARBPROC) (GLenum pname); -typedef void (APIENTRYP PFNGLDETACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB attachedObj); -typedef GLhandleARB (APIENTRYP PFNGLCREATESHADEROBJECTARBPROC) (GLenum shaderType); -typedef void (APIENTRYP PFNGLSHADERSOURCEARBPROC) (GLhandleARB shaderObj, GLsizei count, const GLcharARB* *string, const GLint *length); -typedef void (APIENTRYP PFNGLCOMPILESHADERARBPROC) (GLhandleARB shaderObj); -typedef GLhandleARB (APIENTRYP PFNGLCREATEPROGRAMOBJECTARBPROC) (void); -typedef void (APIENTRYP PFNGLATTACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB obj); -typedef void (APIENTRYP PFNGLLINKPROGRAMARBPROC) (GLhandleARB programObj); -typedef void (APIENTRYP PFNGLUSEPROGRAMOBJECTARBPROC) (GLhandleARB programObj); -typedef void (APIENTRYP PFNGLVALIDATEPROGRAMARBPROC) (GLhandleARB programObj); -typedef void (APIENTRYP PFNGLUNIFORM1FARBPROC) (GLint location, GLfloat v0); -typedef void (APIENTRYP PFNGLUNIFORM2FARBPROC) (GLint location, GLfloat v0, GLfloat v1); -typedef void (APIENTRYP PFNGLUNIFORM3FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -typedef void (APIENTRYP PFNGLUNIFORM4FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -typedef void (APIENTRYP PFNGLUNIFORM1IARBPROC) (GLint location, GLint v0); -typedef void (APIENTRYP PFNGLUNIFORM2IARBPROC) (GLint location, GLint v0, GLint v1); -typedef void (APIENTRYP PFNGLUNIFORM3IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2); -typedef void (APIENTRYP PFNGLUNIFORM4IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -typedef void (APIENTRYP PFNGLUNIFORM1FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORM2FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORM3FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORM4FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORM1IVARBPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLUNIFORM2IVARBPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLUNIFORM3IVARBPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLUNIFORM4IVARBPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERFVARBPROC) (GLhandleARB obj, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVARBPROC) (GLhandleARB obj, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETINFOLOGARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); -typedef void (APIENTRYP PFNGLGETATTACHEDOBJECTSARBPROC) (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj); -typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name); -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); -typedef void (APIENTRYP PFNGLGETUNIFORMFVARBPROC) (GLhandleARB programObj, GLint location, GLfloat *params); -typedef void (APIENTRYP PFNGLGETUNIFORMIVARBPROC) (GLhandleARB programObj, GLint location, GLint *params); -typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); -#endif - -#ifndef GL_ARB_vertex_shader -#define GL_ARB_vertex_shader 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBindAttribLocationARB (GLhandleARB programObj, GLuint index, const GLcharARB *name); -GLAPI void APIENTRY glGetActiveAttribARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); -GLAPI GLint APIENTRY glGetAttribLocationARB (GLhandleARB programObj, const GLcharARB *name); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONARBPROC) (GLhandleARB programObj, GLuint index, const GLcharARB *name); -typedef void (APIENTRYP PFNGLGETACTIVEATTRIBARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); -typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name); -#endif - -#ifndef GL_ARB_fragment_shader -#define GL_ARB_fragment_shader 1 -#endif - -#ifndef GL_ARB_shading_language_100 -#define GL_ARB_shading_language_100 1 -#endif - -#ifndef GL_ARB_texture_non_power_of_two -#define GL_ARB_texture_non_power_of_two 1 -#endif - -#ifndef GL_ARB_point_sprite -#define GL_ARB_point_sprite 1 -#endif - -#ifndef GL_ARB_fragment_program_shadow -#define GL_ARB_fragment_program_shadow 1 -#endif - -#ifndef GL_ARB_draw_buffers -#define GL_ARB_draw_buffers 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawBuffersARB (GLsizei n, const GLenum *bufs); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDRAWBUFFERSARBPROC) (GLsizei n, const GLenum *bufs); -#endif - -#ifndef GL_ARB_texture_rectangle -#define GL_ARB_texture_rectangle 1 -#endif - -#ifndef GL_ARB_color_buffer_float -#define GL_ARB_color_buffer_float 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glClampColorARB (GLenum target, GLenum clamp); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCLAMPCOLORARBPROC) (GLenum target, GLenum clamp); -#endif - -#ifndef GL_ARB_half_float_pixel -#define GL_ARB_half_float_pixel 1 -#endif - -#ifndef GL_ARB_texture_float -#define GL_ARB_texture_float 1 -#endif - -#ifndef GL_ARB_pixel_buffer_object -#define GL_ARB_pixel_buffer_object 1 -#endif - -#ifndef GL_ARB_depth_buffer_float -#define GL_ARB_depth_buffer_float 1 -#endif - -#ifndef GL_ARB_draw_instanced -#define GL_ARB_draw_instanced 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawArraysInstancedARB (GLenum mode, GLint first, GLsizei count, GLsizei primcount); -GLAPI void APIENTRY glDrawElementsInstancedARB (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDARBPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDARBPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); -#endif - -#ifndef GL_ARB_framebuffer_object -#define GL_ARB_framebuffer_object 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLboolean APIENTRY glIsRenderbuffer (GLuint renderbuffer); -GLAPI void APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer); -GLAPI void APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint *renderbuffers); -GLAPI void APIENTRY glGenRenderbuffers (GLsizei n, GLuint *renderbuffers); -GLAPI void APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint *params); -GLAPI GLboolean APIENTRY glIsFramebuffer (GLuint framebuffer); -GLAPI void APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer); -GLAPI void APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint *framebuffers); -GLAPI void APIENTRY glGenFramebuffers (GLsizei n, GLuint *framebuffers); -GLAPI GLenum APIENTRY glCheckFramebufferStatus (GLenum target); -GLAPI void APIENTRY glFramebufferTexture1D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLAPI void APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLAPI void APIENTRY glFramebufferTexture3D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -GLAPI void APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -GLAPI void APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint *params); -GLAPI void APIENTRY glGenerateMipmap (GLenum target); -GLAPI void APIENTRY glBlitFramebuffer (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -GLAPI void APIENTRY glRenderbufferStorageMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glFramebufferTextureLayer (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC) (GLuint renderbuffer); -typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC) (GLenum target, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC) (GLsizei n, const GLuint *renderbuffers); -typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers); -typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC) (GLuint framebuffer); -typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer); -typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint *framebuffers); -typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers); -typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC) (GLenum target); -typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -#endif - -#ifndef GL_ARB_framebuffer_sRGB -#define GL_ARB_framebuffer_sRGB 1 -#endif - -#ifndef GL_ARB_geometry_shader4 -#define GL_ARB_geometry_shader4 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProgramParameteriARB (GLuint program, GLenum pname, GLint value); -GLAPI void APIENTRY glFramebufferTextureARB (GLenum target, GLenum attachment, GLuint texture, GLint level); -GLAPI void APIENTRY glFramebufferTextureLayerARB (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -GLAPI void APIENTRY glFramebufferTextureFaceARB (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIARBPROC) (GLuint program, GLenum pname, GLint value); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); -#endif - -#ifndef GL_ARB_half_float_vertex -#define GL_ARB_half_float_vertex 1 -#endif - -#ifndef GL_ARB_instanced_arrays -#define GL_ARB_instanced_arrays 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexAttribDivisorARB (GLuint index, GLuint divisor); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORARBPROC) (GLuint index, GLuint divisor); -#endif - -#ifndef GL_ARB_map_buffer_range -#define GL_ARB_map_buffer_range 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLvoid* APIENTRY glMapBufferRange (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); -GLAPI void APIENTRY glFlushMappedBufferRange (GLenum target, GLintptr offset, GLsizeiptr length); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); -typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length); -#endif - -#ifndef GL_ARB_texture_buffer_object -#define GL_ARB_texture_buffer_object 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexBufferARB (GLenum target, GLenum internalformat, GLuint buffer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTEXBUFFERARBPROC) (GLenum target, GLenum internalformat, GLuint buffer); -#endif - -#ifndef GL_ARB_texture_compression_rgtc -#define GL_ARB_texture_compression_rgtc 1 -#endif - -#ifndef GL_ARB_texture_rg -#define GL_ARB_texture_rg 1 -#endif - -#ifndef GL_ARB_vertex_array_object -#define GL_ARB_vertex_array_object 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBindVertexArray (GLuint array); -GLAPI void APIENTRY glDeleteVertexArrays (GLsizei n, const GLuint *arrays); -GLAPI void APIENTRY glGenVertexArrays (GLsizei n, GLuint *arrays); -GLAPI GLboolean APIENTRY glIsVertexArray (GLuint array); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array); -typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays); -typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays); -typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC) (GLuint array); -#endif - -#ifndef GL_ARB_uniform_buffer_object -#define GL_ARB_uniform_buffer_object 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetUniformIndices (GLuint program, GLsizei uniformCount, const GLchar* *uniformNames, GLuint *uniformIndices); -GLAPI void APIENTRY glGetActiveUniformsiv (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetActiveUniformName (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); -GLAPI GLuint APIENTRY glGetUniformBlockIndex (GLuint program, const GLchar *uniformBlockName); -GLAPI void APIENTRY glGetActiveUniformBlockiv (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetActiveUniformBlockName (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); -GLAPI void APIENTRY glUniformBlockBinding (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGETUNIFORMINDICESPROC) (GLuint program, GLsizei uniformCount, const GLchar* *uniformNames, GLuint *uniformIndices); -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC) (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC) (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); -typedef GLuint (APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC) (GLuint program, const GLchar *uniformBlockName); -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); -typedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); -#endif - -#ifndef GL_ARB_compatibility -#define GL_ARB_compatibility 1 -#endif - -#ifndef GL_ARB_copy_buffer -#define GL_ARB_copy_buffer 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glCopyBufferSubData (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); -#endif - -#ifndef GL_ARB_shader_texture_lod -#define GL_ARB_shader_texture_lod 1 -#endif - -#ifndef GL_ARB_depth_clamp -#define GL_ARB_depth_clamp 1 -#endif - -#ifndef GL_ARB_draw_elements_base_vertex -#define GL_ARB_draw_elements_base_vertex 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawElementsBaseVertex (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); -GLAPI void APIENTRY glDrawRangeElementsBaseVertex (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); -GLAPI void APIENTRY glDrawElementsInstancedBaseVertex (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount, GLint basevertex); -GLAPI void APIENTRY glMultiDrawElementsBaseVertex (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount, const GLint *basevertex); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); -typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount, GLint basevertex); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount, const GLint *basevertex); -#endif - -#ifndef GL_ARB_fragment_coord_conventions -#define GL_ARB_fragment_coord_conventions 1 -#endif - -#ifndef GL_ARB_provoking_vertex -#define GL_ARB_provoking_vertex 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProvokingVertex (GLenum mode); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC) (GLenum mode); -#endif - -#ifndef GL_ARB_seamless_cube_map -#define GL_ARB_seamless_cube_map 1 -#endif - -#ifndef GL_ARB_sync -#define GL_ARB_sync 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLsync APIENTRY glFenceSync (GLenum condition, GLbitfield flags); -GLAPI GLboolean APIENTRY glIsSync (GLsync sync); -GLAPI void APIENTRY glDeleteSync (GLsync sync); -GLAPI GLenum APIENTRY glClientWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); -GLAPI void APIENTRY glWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); -GLAPI void APIENTRY glGetInteger64v (GLenum pname, GLint64 *params); -GLAPI void APIENTRY glGetSynciv (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLsync (APIENTRYP PFNGLFENCESYNCPROC) (GLenum condition, GLbitfield flags); -typedef GLboolean (APIENTRYP PFNGLISSYNCPROC) (GLsync sync); -typedef void (APIENTRYP PFNGLDELETESYNCPROC) (GLsync sync); -typedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); -typedef void (APIENTRYP PFNGLWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); -typedef void (APIENTRYP PFNGLGETINTEGER64VPROC) (GLenum pname, GLint64 *params); -typedef void (APIENTRYP PFNGLGETSYNCIVPROC) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); -#endif - -#ifndef GL_ARB_texture_multisample -#define GL_ARB_texture_multisample 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexImage2DMultisample (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -GLAPI void APIENTRY glTexImage3DMultisample (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); -GLAPI void APIENTRY glGetMultisamplefv (GLenum pname, GLuint index, GLfloat *val); -GLAPI void APIENTRY glSampleMaski (GLuint index, GLbitfield mask); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); -typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC) (GLenum pname, GLuint index, GLfloat *val); -typedef void (APIENTRYP PFNGLSAMPLEMASKIPROC) (GLuint index, GLbitfield mask); -#endif - -#ifndef GL_ARB_vertex_array_bgra -#define GL_ARB_vertex_array_bgra 1 -#endif - -#ifndef GL_ARB_draw_buffers_blend -#define GL_ARB_draw_buffers_blend 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendEquationiARB (GLuint buf, GLenum mode); -GLAPI void APIENTRY glBlendEquationSeparateiARB (GLuint buf, GLenum modeRGB, GLenum modeAlpha); -GLAPI void APIENTRY glBlendFunciARB (GLuint buf, GLenum src, GLenum dst); -GLAPI void APIENTRY glBlendFuncSeparateiARB (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBLENDEQUATIONIARBPROC) (GLuint buf, GLenum mode); -typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIARBPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); -typedef void (APIENTRYP PFNGLBLENDFUNCIARBPROC) (GLuint buf, GLenum src, GLenum dst); -typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIARBPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); -#endif - -#ifndef GL_ARB_sample_shading -#define GL_ARB_sample_shading 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMinSampleShadingARB (GLclampf value); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLMINSAMPLESHADINGARBPROC) (GLclampf value); -#endif - -#ifndef GL_ARB_texture_cube_map_array -#define GL_ARB_texture_cube_map_array 1 -#endif - -#ifndef GL_ARB_texture_gather -#define GL_ARB_texture_gather 1 -#endif - -#ifndef GL_ARB_texture_query_lod -#define GL_ARB_texture_query_lod 1 -#endif - -#ifndef GL_ARB_shading_language_include -#define GL_ARB_shading_language_include 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glNamedStringARB (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string); -GLAPI void APIENTRY glDeleteNamedStringARB (GLint namelen, const GLchar *name); -GLAPI void APIENTRY glCompileShaderIncludeARB (GLuint shader, GLsizei count, const GLchar* *path, const GLint *length); -GLAPI GLboolean APIENTRY glIsNamedStringARB (GLint namelen, const GLchar *name); -GLAPI void APIENTRY glGetNamedStringARB (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string); -GLAPI void APIENTRY glGetNamedStringivARB (GLint namelen, const GLchar *name, GLenum pname, GLint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLNAMEDSTRINGARBPROC) (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string); -typedef void (APIENTRYP PFNGLDELETENAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name); -typedef void (APIENTRYP PFNGLCOMPILESHADERINCLUDEARBPROC) (GLuint shader, GLsizei count, const GLchar* *path, const GLint *length); -typedef GLboolean (APIENTRYP PFNGLISNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name); -typedef void (APIENTRYP PFNGLGETNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string); -typedef void (APIENTRYP PFNGLGETNAMEDSTRINGIVARBPROC) (GLint namelen, const GLchar *name, GLenum pname, GLint *params); -#endif - -#ifndef GL_ARB_texture_compression_bptc -#define GL_ARB_texture_compression_bptc 1 -#endif - -#ifndef GL_ARB_blend_func_extended -#define GL_ARB_blend_func_extended 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBindFragDataLocationIndexed (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); -GLAPI GLint APIENTRY glGetFragDataIndex (GLuint program, const GLchar *name); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONINDEXEDPROC) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); -typedef GLint (APIENTRYP PFNGLGETFRAGDATAINDEXPROC) (GLuint program, const GLchar *name); -#endif - -#ifndef GL_ARB_explicit_attrib_location -#define GL_ARB_explicit_attrib_location 1 -#endif - -#ifndef GL_ARB_occlusion_query2 -#define GL_ARB_occlusion_query2 1 -#endif - -#ifndef GL_ARB_sampler_objects -#define GL_ARB_sampler_objects 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGenSamplers (GLsizei count, GLuint *samplers); -GLAPI void APIENTRY glDeleteSamplers (GLsizei count, const GLuint *samplers); -GLAPI GLboolean APIENTRY glIsSampler (GLuint sampler); -GLAPI void APIENTRY glBindSampler (GLuint unit, GLuint sampler); -GLAPI void APIENTRY glSamplerParameteri (GLuint sampler, GLenum pname, GLint param); -GLAPI void APIENTRY glSamplerParameteriv (GLuint sampler, GLenum pname, const GLint *param); -GLAPI void APIENTRY glSamplerParameterf (GLuint sampler, GLenum pname, GLfloat param); -GLAPI void APIENTRY glSamplerParameterfv (GLuint sampler, GLenum pname, const GLfloat *param); -GLAPI void APIENTRY glSamplerParameterIiv (GLuint sampler, GLenum pname, const GLint *param); -GLAPI void APIENTRY glSamplerParameterIuiv (GLuint sampler, GLenum pname, const GLuint *param); -GLAPI void APIENTRY glGetSamplerParameteriv (GLuint sampler, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetSamplerParameterIiv (GLuint sampler, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetSamplerParameterfv (GLuint sampler, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetSamplerParameterIuiv (GLuint sampler, GLenum pname, GLuint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers); -typedef void (APIENTRYP PFNGLDELETESAMPLERSPROC) (GLsizei count, const GLuint *samplers); -typedef GLboolean (APIENTRYP PFNGLISSAMPLERPROC) (GLuint sampler); -typedef void (APIENTRYP PFNGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler); -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIPROC) (GLuint sampler, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, const GLint *param); -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFPROC) (GLuint sampler, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, const GLfloat *param); -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, const GLint *param); -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, const GLuint *param); -typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, GLuint *params); -#endif - -#ifndef GL_ARB_shader_bit_encoding -#define GL_ARB_shader_bit_encoding 1 -#endif - -#ifndef GL_ARB_texture_rgb10_a2ui -#define GL_ARB_texture_rgb10_a2ui 1 -#endif - -#ifndef GL_ARB_texture_swizzle -#define GL_ARB_texture_swizzle 1 -#endif - -#ifndef GL_ARB_timer_query -#define GL_ARB_timer_query 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glQueryCounter (GLuint id, GLenum target); -GLAPI void APIENTRY glGetQueryObjecti64v (GLuint id, GLenum pname, GLint64 *params); -GLAPI void APIENTRY glGetQueryObjectui64v (GLuint id, GLenum pname, GLuint64 *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLQUERYCOUNTERPROC) (GLuint id, GLenum target); -typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VPROC) (GLuint id, GLenum pname, GLint64 *params); -typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VPROC) (GLuint id, GLenum pname, GLuint64 *params); -#endif - -#ifndef GL_ARB_vertex_type_2_10_10_10_rev -#define GL_ARB_vertex_type_2_10_10_10_rev 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexP2ui (GLenum type, GLuint value); -GLAPI void APIENTRY glVertexP2uiv (GLenum type, const GLuint *value); -GLAPI void APIENTRY glVertexP3ui (GLenum type, GLuint value); -GLAPI void APIENTRY glVertexP3uiv (GLenum type, const GLuint *value); -GLAPI void APIENTRY glVertexP4ui (GLenum type, GLuint value); -GLAPI void APIENTRY glVertexP4uiv (GLenum type, const GLuint *value); -GLAPI void APIENTRY glTexCoordP1ui (GLenum type, GLuint coords); -GLAPI void APIENTRY glTexCoordP1uiv (GLenum type, const GLuint *coords); -GLAPI void APIENTRY glTexCoordP2ui (GLenum type, GLuint coords); -GLAPI void APIENTRY glTexCoordP2uiv (GLenum type, const GLuint *coords); -GLAPI void APIENTRY glTexCoordP3ui (GLenum type, GLuint coords); -GLAPI void APIENTRY glTexCoordP3uiv (GLenum type, const GLuint *coords); -GLAPI void APIENTRY glTexCoordP4ui (GLenum type, GLuint coords); -GLAPI void APIENTRY glTexCoordP4uiv (GLenum type, const GLuint *coords); -GLAPI void APIENTRY glMultiTexCoordP1ui (GLenum texture, GLenum type, GLuint coords); -GLAPI void APIENTRY glMultiTexCoordP1uiv (GLenum texture, GLenum type, const GLuint *coords); -GLAPI void APIENTRY glMultiTexCoordP2ui (GLenum texture, GLenum type, GLuint coords); -GLAPI void APIENTRY glMultiTexCoordP2uiv (GLenum texture, GLenum type, const GLuint *coords); -GLAPI void APIENTRY glMultiTexCoordP3ui (GLenum texture, GLenum type, GLuint coords); -GLAPI void APIENTRY glMultiTexCoordP3uiv (GLenum texture, GLenum type, const GLuint *coords); -GLAPI void APIENTRY glMultiTexCoordP4ui (GLenum texture, GLenum type, GLuint coords); -GLAPI void APIENTRY glMultiTexCoordP4uiv (GLenum texture, GLenum type, const GLuint *coords); -GLAPI void APIENTRY glNormalP3ui (GLenum type, GLuint coords); -GLAPI void APIENTRY glNormalP3uiv (GLenum type, const GLuint *coords); -GLAPI void APIENTRY glColorP3ui (GLenum type, GLuint color); -GLAPI void APIENTRY glColorP3uiv (GLenum type, const GLuint *color); -GLAPI void APIENTRY glColorP4ui (GLenum type, GLuint color); -GLAPI void APIENTRY glColorP4uiv (GLenum type, const GLuint *color); -GLAPI void APIENTRY glSecondaryColorP3ui (GLenum type, GLuint color); -GLAPI void APIENTRY glSecondaryColorP3uiv (GLenum type, const GLuint *color); -GLAPI void APIENTRY glVertexAttribP1ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); -GLAPI void APIENTRY glVertexAttribP1uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -GLAPI void APIENTRY glVertexAttribP2ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); -GLAPI void APIENTRY glVertexAttribP2uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -GLAPI void APIENTRY glVertexAttribP3ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); -GLAPI void APIENTRY glVertexAttribP3uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -GLAPI void APIENTRY glVertexAttribP4ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); -GLAPI void APIENTRY glVertexAttribP4uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVERTEXP2UIPROC) (GLenum type, GLuint value); -typedef void (APIENTRYP PFNGLVERTEXP2UIVPROC) (GLenum type, const GLuint *value); -typedef void (APIENTRYP PFNGLVERTEXP3UIPROC) (GLenum type, GLuint value); -typedef void (APIENTRYP PFNGLVERTEXP3UIVPROC) (GLenum type, const GLuint *value); -typedef void (APIENTRYP PFNGLVERTEXP4UIPROC) (GLenum type, GLuint value); -typedef void (APIENTRYP PFNGLVERTEXP4UIVPROC) (GLenum type, const GLuint *value); -typedef void (APIENTRYP PFNGLTEXCOORDP1UIPROC) (GLenum type, GLuint coords); -typedef void (APIENTRYP PFNGLTEXCOORDP1UIVPROC) (GLenum type, const GLuint *coords); -typedef void (APIENTRYP PFNGLTEXCOORDP2UIPROC) (GLenum type, GLuint coords); -typedef void (APIENTRYP PFNGLTEXCOORDP2UIVPROC) (GLenum type, const GLuint *coords); -typedef void (APIENTRYP PFNGLTEXCOORDP3UIPROC) (GLenum type, GLuint coords); -typedef void (APIENTRYP PFNGLTEXCOORDP3UIVPROC) (GLenum type, const GLuint *coords); -typedef void (APIENTRYP PFNGLTEXCOORDP4UIPROC) (GLenum type, GLuint coords); -typedef void (APIENTRYP PFNGLTEXCOORDP4UIVPROC) (GLenum type, const GLuint *coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIPROC) (GLenum texture, GLenum type, GLuint coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIPROC) (GLenum texture, GLenum type, GLuint coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIPROC) (GLenum texture, GLenum type, GLuint coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIPROC) (GLenum texture, GLenum type, GLuint coords); -typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); -typedef void (APIENTRYP PFNGLNORMALP3UIPROC) (GLenum type, GLuint coords); -typedef void (APIENTRYP PFNGLNORMALP3UIVPROC) (GLenum type, const GLuint *coords); -typedef void (APIENTRYP PFNGLCOLORP3UIPROC) (GLenum type, GLuint color); -typedef void (APIENTRYP PFNGLCOLORP3UIVPROC) (GLenum type, const GLuint *color); -typedef void (APIENTRYP PFNGLCOLORP4UIPROC) (GLenum type, GLuint color); -typedef void (APIENTRYP PFNGLCOLORP4UIVPROC) (GLenum type, const GLuint *color); -typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIPROC) (GLenum type, GLuint color); -typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIVPROC) (GLenum type, const GLuint *color); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); -typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -#endif - -#ifndef GL_ARB_draw_indirect -#define GL_ARB_draw_indirect 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawArraysIndirect (GLenum mode, const GLvoid *indirect); -GLAPI void APIENTRY glDrawElementsIndirect (GLenum mode, GLenum type, const GLvoid *indirect); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDRAWARRAYSINDIRECTPROC) (GLenum mode, const GLvoid *indirect); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const GLvoid *indirect); -#endif - -#ifndef GL_ARB_gpu_shader5 -#define GL_ARB_gpu_shader5 1 -#endif - -#ifndef GL_ARB_gpu_shader_fp64 -#define GL_ARB_gpu_shader_fp64 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glUniform1d (GLint location, GLdouble x); -GLAPI void APIENTRY glUniform2d (GLint location, GLdouble x, GLdouble y); -GLAPI void APIENTRY glUniform3d (GLint location, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glUniform4d (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glUniform1dv (GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glUniform2dv (GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glUniform3dv (GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glUniform4dv (GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix2x3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix2x4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix3x2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix3x4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix4x2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glUniformMatrix4x3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glGetUniformdv (GLuint program, GLint location, GLdouble *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLUNIFORM1DPROC) (GLint location, GLdouble x); -typedef void (APIENTRYP PFNGLUNIFORM2DPROC) (GLint location, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLUNIFORM3DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLUNIFORM4DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLUNIFORM1DVPROC) (GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORM2DVPROC) (GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORM3DVPROC) (GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORM4DVPROC) (GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLGETUNIFORMDVPROC) (GLuint program, GLint location, GLdouble *params); -#endif - -#ifndef GL_ARB_shader_subroutine -#define GL_ARB_shader_subroutine 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLint APIENTRY glGetSubroutineUniformLocation (GLuint program, GLenum shadertype, const GLchar *name); -GLAPI GLuint APIENTRY glGetSubroutineIndex (GLuint program, GLenum shadertype, const GLchar *name); -GLAPI void APIENTRY glGetActiveSubroutineUniformiv (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values); -GLAPI void APIENTRY glGetActiveSubroutineUniformName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); -GLAPI void APIENTRY glGetActiveSubroutineName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); -GLAPI void APIENTRY glUniformSubroutinesuiv (GLenum shadertype, GLsizei count, const GLuint *indices); -GLAPI void APIENTRY glGetUniformSubroutineuiv (GLenum shadertype, GLint location, GLuint *params); -GLAPI void APIENTRY glGetProgramStageiv (GLuint program, GLenum shadertype, GLenum pname, GLint *values); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLint (APIENTRYP PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC) (GLuint program, GLenum shadertype, const GLchar *name); -typedef GLuint (APIENTRYP PFNGLGETSUBROUTINEINDEXPROC) (GLuint program, GLenum shadertype, const GLchar *name); -typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC) (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values); -typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); -typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINENAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); -typedef void (APIENTRYP PFNGLUNIFORMSUBROUTINESUIVPROC) (GLenum shadertype, GLsizei count, const GLuint *indices); -typedef void (APIENTRYP PFNGLGETUNIFORMSUBROUTINEUIVPROC) (GLenum shadertype, GLint location, GLuint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMSTAGEIVPROC) (GLuint program, GLenum shadertype, GLenum pname, GLint *values); -#endif - -#ifndef GL_ARB_tessellation_shader -#define GL_ARB_tessellation_shader 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPatchParameteri (GLenum pname, GLint value); -GLAPI void APIENTRY glPatchParameterfv (GLenum pname, const GLfloat *values); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPATCHPARAMETERIPROC) (GLenum pname, GLint value); -typedef void (APIENTRYP PFNGLPATCHPARAMETERFVPROC) (GLenum pname, const GLfloat *values); -#endif - -#ifndef GL_ARB_texture_buffer_object_rgb32 -#define GL_ARB_texture_buffer_object_rgb32 1 -#endif - -#ifndef GL_ARB_transform_feedback2 -#define GL_ARB_transform_feedback2 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBindTransformFeedback (GLenum target, GLuint id); -GLAPI void APIENTRY glDeleteTransformFeedbacks (GLsizei n, const GLuint *ids); -GLAPI void APIENTRY glGenTransformFeedbacks (GLsizei n, GLuint *ids); -GLAPI GLboolean APIENTRY glIsTransformFeedback (GLuint id); -GLAPI void APIENTRY glPauseTransformFeedback (void); -GLAPI void APIENTRY glResumeTransformFeedback (void); -GLAPI void APIENTRY glDrawTransformFeedback (GLenum mode, GLuint id); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKPROC) (GLenum target, GLuint id); -typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSPROC) (GLsizei n, const GLuint *ids); -typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids); -typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKPROC) (GLuint id); -typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKPROC) (void); -typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKPROC) (void); -typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKPROC) (GLenum mode, GLuint id); -#endif - -#ifndef GL_ARB_transform_feedback3 -#define GL_ARB_transform_feedback3 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawTransformFeedbackStream (GLenum mode, GLuint id, GLuint stream); -GLAPI void APIENTRY glBeginQueryIndexed (GLenum target, GLuint index, GLuint id); -GLAPI void APIENTRY glEndQueryIndexed (GLenum target, GLuint index); -GLAPI void APIENTRY glGetQueryIndexediv (GLenum target, GLuint index, GLenum pname, GLint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC) (GLenum mode, GLuint id, GLuint stream); -typedef void (APIENTRYP PFNGLBEGINQUERYINDEXEDPROC) (GLenum target, GLuint index, GLuint id); -typedef void (APIENTRYP PFNGLENDQUERYINDEXEDPROC) (GLenum target, GLuint index); -typedef void (APIENTRYP PFNGLGETQUERYINDEXEDIVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params); -#endif - -#ifndef GL_ARB_ES2_compatibility -#define GL_ARB_ES2_compatibility 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glReleaseShaderCompiler (void); -GLAPI void APIENTRY glShaderBinary (GLsizei count, const GLuint *shaders, GLenum binaryformat, const GLvoid *binary, GLsizei length); -GLAPI void APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); -GLAPI void APIENTRY glDepthRangef (GLclampf n, GLclampf f); -GLAPI void APIENTRY glClearDepthf (GLclampf d); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLRELEASESHADERCOMPILERPROC) (void); -typedef void (APIENTRYP PFNGLSHADERBINARYPROC) (GLsizei count, const GLuint *shaders, GLenum binaryformat, const GLvoid *binary, GLsizei length); -typedef void (APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC) (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); -typedef void (APIENTRYP PFNGLDEPTHRANGEFPROC) (GLclampf n, GLclampf f); -typedef void (APIENTRYP PFNGLCLEARDEPTHFPROC) (GLclampf d); -#endif - -#ifndef GL_ARB_get_program_binary -#define GL_ARB_get_program_binary 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetProgramBinary (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary); -GLAPI void APIENTRY glProgramBinary (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLsizei length); -GLAPI void APIENTRY glProgramParameteri (GLuint program, GLenum pname, GLint value); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary); -typedef void (APIENTRYP PFNGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLsizei length); -typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value); -#endif - -#ifndef GL_ARB_separate_shader_objects -#define GL_ARB_separate_shader_objects 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glUseProgramStages (GLuint pipeline, GLbitfield stages, GLuint program); -GLAPI void APIENTRY glActiveShaderProgram (GLuint pipeline, GLuint program); -GLAPI GLuint APIENTRY glCreateShaderProgramv (GLenum type, GLsizei count, const GLchar* *strings); -GLAPI void APIENTRY glBindProgramPipeline (GLuint pipeline); -GLAPI void APIENTRY glDeleteProgramPipelines (GLsizei n, const GLuint *pipelines); -GLAPI void APIENTRY glGenProgramPipelines (GLsizei n, GLuint *pipelines); -GLAPI GLboolean APIENTRY glIsProgramPipeline (GLuint pipeline); -GLAPI void APIENTRY glGetProgramPipelineiv (GLuint pipeline, GLenum pname, GLint *params); -GLAPI void APIENTRY glProgramUniform1i (GLuint program, GLint location, GLint v0); -GLAPI void APIENTRY glProgramUniform1iv (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniform1f (GLuint program, GLint location, GLfloat v0); -GLAPI void APIENTRY glProgramUniform1fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform1d (GLuint program, GLint location, GLdouble v0); -GLAPI void APIENTRY glProgramUniform1dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniform1ui (GLuint program, GLint location, GLuint v0); -GLAPI void APIENTRY glProgramUniform1uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glProgramUniform2i (GLuint program, GLint location, GLint v0, GLint v1); -GLAPI void APIENTRY glProgramUniform2iv (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniform2f (GLuint program, GLint location, GLfloat v0, GLfloat v1); -GLAPI void APIENTRY glProgramUniform2fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform2d (GLuint program, GLint location, GLdouble v0, GLdouble v1); -GLAPI void APIENTRY glProgramUniform2dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniform2ui (GLuint program, GLint location, GLuint v0, GLuint v1); -GLAPI void APIENTRY glProgramUniform2uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glProgramUniform3i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); -GLAPI void APIENTRY glProgramUniform3iv (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniform3f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -GLAPI void APIENTRY glProgramUniform3fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform3d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); -GLAPI void APIENTRY glProgramUniform3dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniform3ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); -GLAPI void APIENTRY glProgramUniform3uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glProgramUniform4i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -GLAPI void APIENTRY glProgramUniform4iv (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniform4f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -GLAPI void APIENTRY glProgramUniform4fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform4d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); -GLAPI void APIENTRY glProgramUniform4dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniform4ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -GLAPI void APIENTRY glProgramUniform4uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glProgramUniformMatrix2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix2x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix3x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix2x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix4x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix3x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix4x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix2x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix3x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix2x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix4x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix3x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix4x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glValidateProgramPipeline (GLuint pipeline); -GLAPI void APIENTRY glGetProgramPipelineInfoLog (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLUSEPROGRAMSTAGESPROC) (GLuint pipeline, GLbitfield stages, GLuint program); -typedef void (APIENTRYP PFNGLACTIVESHADERPROGRAMPROC) (GLuint pipeline, GLuint program); -typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMVPROC) (GLenum type, GLsizei count, const GLchar* *strings); -typedef void (APIENTRYP PFNGLBINDPROGRAMPIPELINEPROC) (GLuint pipeline); -typedef void (APIENTRYP PFNGLDELETEPROGRAMPIPELINESPROC) (GLsizei n, const GLuint *pipelines); -typedef void (APIENTRYP PFNGLGENPROGRAMPIPELINESPROC) (GLsizei n, GLuint *pipelines); -typedef GLboolean (APIENTRYP PFNGLISPROGRAMPIPELINEPROC) (GLuint pipeline); -typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEIVPROC) (GLuint pipeline, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IPROC) (GLuint program, GLint location, GLint v0); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FPROC) (GLuint program, GLint location, GLfloat v0); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DPROC) (GLuint program, GLint location, GLdouble v0); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIPROC) (GLuint program, GLint location, GLuint v0); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IPROC) (GLuint program, GLint location, GLint v0, GLint v1); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEPROC) (GLuint pipeline); -typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -#endif - -#ifndef GL_ARB_vertex_attrib_64bit -#define GL_ARB_vertex_attrib_64bit 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexAttribL1d (GLuint index, GLdouble x); -GLAPI void APIENTRY glVertexAttribL2d (GLuint index, GLdouble x, GLdouble y); -GLAPI void APIENTRY glVertexAttribL3d (GLuint index, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glVertexAttribL4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glVertexAttribL1dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribL2dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribL3dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribL4dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribLPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -GLAPI void APIENTRY glGetVertexAttribLdv (GLuint index, GLenum pname, GLdouble *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DPROC) (GLuint index, GLdouble x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DPROC) (GLuint index, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVPROC) (GLuint index, GLenum pname, GLdouble *params); -#endif - -#ifndef GL_ARB_viewport_array -#define GL_ARB_viewport_array 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glViewportArrayv (GLuint first, GLsizei count, const GLfloat *v); -GLAPI void APIENTRY glViewportIndexedf (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); -GLAPI void APIENTRY glViewportIndexedfv (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glScissorArrayv (GLuint first, GLsizei count, const GLint *v); -GLAPI void APIENTRY glScissorIndexed (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); -GLAPI void APIENTRY glScissorIndexedv (GLuint index, const GLint *v); -GLAPI void APIENTRY glDepthRangeArrayv (GLuint first, GLsizei count, const GLclampd *v); -GLAPI void APIENTRY glDepthRangeIndexed (GLuint index, GLclampd n, GLclampd f); -GLAPI void APIENTRY glGetFloati_v (GLenum target, GLuint index, GLfloat *data); -GLAPI void APIENTRY glGetDoublei_v (GLenum target, GLuint index, GLdouble *data); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVIEWPORTARRAYVPROC) (GLuint first, GLsizei count, const GLfloat *v); -typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); -typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLSCISSORARRAYVPROC) (GLuint first, GLsizei count, const GLint *v); -typedef void (APIENTRYP PFNGLSCISSORINDEXEDPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLSCISSORINDEXEDVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLDEPTHRANGEARRAYVPROC) (GLuint first, GLsizei count, const GLclampd *v); -typedef void (APIENTRYP PFNGLDEPTHRANGEINDEXEDPROC) (GLuint index, GLclampd n, GLclampd f); -typedef void (APIENTRYP PFNGLGETFLOATI_VPROC) (GLenum target, GLuint index, GLfloat *data); -typedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC) (GLenum target, GLuint index, GLdouble *data); -#endif - -#ifndef GL_ARB_cl_event -#define GL_ARB_cl_event 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLsync APIENTRY glCreateSyncFromCLeventARB (struct _cl_context * context, struct _cl_event * event, GLbitfield flags); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLsync (APIENTRYP PFNGLCREATESYNCFROMCLEVENTARBPROC) (struct _cl_context * context, struct _cl_event * event, GLbitfield flags); -#endif - -#ifndef GL_ARB_debug_output -#define GL_ARB_debug_output 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDebugMessageControlARB (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); -GLAPI void APIENTRY glDebugMessageInsertARB (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); -GLAPI void APIENTRY glDebugMessageCallbackARB (GLDEBUGPROCARB callback, const GLvoid *userParam); -GLAPI GLuint APIENTRY glGetDebugMessageLogARB (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLARBPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); -typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTARBPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); -typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKARBPROC) (GLDEBUGPROCARB callback, const GLvoid *userParam); -typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGARBPROC) (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); -#endif - -#ifndef GL_ARB_robustness -#define GL_ARB_robustness 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLenum APIENTRY glGetGraphicsResetStatusARB (void); -GLAPI void APIENTRY glGetnMapdvARB (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v); -GLAPI void APIENTRY glGetnMapfvARB (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v); -GLAPI void APIENTRY glGetnMapivARB (GLenum target, GLenum query, GLsizei bufSize, GLint *v); -GLAPI void APIENTRY glGetnPixelMapfvARB (GLenum map, GLsizei bufSize, GLfloat *values); -GLAPI void APIENTRY glGetnPixelMapuivARB (GLenum map, GLsizei bufSize, GLuint *values); -GLAPI void APIENTRY glGetnPixelMapusvARB (GLenum map, GLsizei bufSize, GLushort *values); -GLAPI void APIENTRY glGetnPolygonStippleARB (GLsizei bufSize, GLubyte *pattern); -GLAPI void APIENTRY glGetnColorTableARB (GLenum target, GLenum format, GLenum type, GLsizei bufSize, GLvoid *table); -GLAPI void APIENTRY glGetnConvolutionFilterARB (GLenum target, GLenum format, GLenum type, GLsizei bufSize, GLvoid *image); -GLAPI void APIENTRY glGetnSeparableFilterARB (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, GLvoid *row, GLsizei columnBufSize, GLvoid *column, GLvoid *span); -GLAPI void APIENTRY glGetnHistogramARB (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, GLvoid *values); -GLAPI void APIENTRY glGetnMinmaxARB (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, GLvoid *values); -GLAPI void APIENTRY glGetnTexImageARB (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, GLvoid *img); -GLAPI void APIENTRY glReadnPixelsARB (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLvoid *data); -GLAPI void APIENTRY glGetnCompressedTexImageARB (GLenum target, GLint lod, GLsizei bufSize, GLvoid *img); -GLAPI void APIENTRY glGetnUniformfvARB (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); -GLAPI void APIENTRY glGetnUniformivARB (GLuint program, GLint location, GLsizei bufSize, GLint *params); -GLAPI void APIENTRY glGetnUniformuivARB (GLuint program, GLint location, GLsizei bufSize, GLuint *params); -GLAPI void APIENTRY glGetnUniformdvARB (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSARBPROC) (void); -typedef void (APIENTRYP PFNGLGETNMAPDVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v); -typedef void (APIENTRYP PFNGLGETNMAPFVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v); -typedef void (APIENTRYP PFNGLGETNMAPIVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLint *v); -typedef void (APIENTRYP PFNGLGETNPIXELMAPFVARBPROC) (GLenum map, GLsizei bufSize, GLfloat *values); -typedef void (APIENTRYP PFNGLGETNPIXELMAPUIVARBPROC) (GLenum map, GLsizei bufSize, GLuint *values); -typedef void (APIENTRYP PFNGLGETNPIXELMAPUSVARBPROC) (GLenum map, GLsizei bufSize, GLushort *values); -typedef void (APIENTRYP PFNGLGETNPOLYGONSTIPPLEARBPROC) (GLsizei bufSize, GLubyte *pattern); -typedef void (APIENTRYP PFNGLGETNCOLORTABLEARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, GLvoid *table); -typedef void (APIENTRYP PFNGLGETNCONVOLUTIONFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, GLvoid *image); -typedef void (APIENTRYP PFNGLGETNSEPARABLEFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, GLvoid *row, GLsizei columnBufSize, GLvoid *column, GLvoid *span); -typedef void (APIENTRYP PFNGLGETNHISTOGRAMARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, GLvoid *values); -typedef void (APIENTRYP PFNGLGETNMINMAXARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, GLvoid *values); -typedef void (APIENTRYP PFNGLGETNTEXIMAGEARBPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, GLvoid *img); -typedef void (APIENTRYP PFNGLREADNPIXELSARBPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLvoid *data); -typedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint lod, GLsizei bufSize, GLvoid *img); -typedef void (APIENTRYP PFNGLGETNUNIFORMFVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); -typedef void (APIENTRYP PFNGLGETNUNIFORMIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params); -typedef void (APIENTRYP PFNGLGETNUNIFORMUIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params); -typedef void (APIENTRYP PFNGLGETNUNIFORMDVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); -#endif - -#ifndef GL_ARB_shader_stencil_export -#define GL_ARB_shader_stencil_export 1 -#endif - -#ifndef GL_ARB_base_instance -#define GL_ARB_base_instance 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawArraysInstancedBaseInstance (GLenum mode, GLint first, GLsizei count, GLsizei primcount, GLuint baseinstance); -GLAPI void APIENTRY glDrawElementsInstancedBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount, GLuint baseinstance); -GLAPI void APIENTRY glDrawElementsInstancedBaseVertexBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount, GLint basevertex, GLuint baseinstance); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount, GLuint baseinstance); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount, GLuint baseinstance); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount, GLint basevertex, GLuint baseinstance); -#endif - -#ifndef GL_ARB_shading_language_420pack -#define GL_ARB_shading_language_420pack 1 -#endif - -#ifndef GL_ARB_transform_feedback_instanced -#define GL_ARB_transform_feedback_instanced 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawTransformFeedbackInstanced (GLenum mode, GLuint id, GLsizei primcount); -GLAPI void APIENTRY glDrawTransformFeedbackStreamInstanced (GLenum mode, GLuint id, GLuint stream, GLsizei primcount); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC) (GLenum mode, GLuint id, GLsizei primcount); -typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC) (GLenum mode, GLuint id, GLuint stream, GLsizei primcount); -#endif - -#ifndef GL_ARB_compressed_texture_pixel_storage -#define GL_ARB_compressed_texture_pixel_storage 1 -#endif - -#ifndef GL_ARB_conservative_depth -#define GL_ARB_conservative_depth 1 -#endif - -#ifndef GL_ARB_internalformat_query -#define GL_ARB_internalformat_query 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetInternalformativ (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); -#endif - -#ifndef GL_ARB_map_buffer_alignment -#define GL_ARB_map_buffer_alignment 1 -#endif - -#ifndef GL_ARB_shader_atomic_counters -#define GL_ARB_shader_atomic_counters 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetActiveAtomicCounterBufferiv (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC) (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params); -#endif - -#ifndef GL_ARB_shader_image_load_store -#define GL_ARB_shader_image_load_store 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBindImageTexture (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); -GLAPI void APIENTRY glMemoryBarrier (GLbitfield barriers); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); -typedef void (APIENTRYP PFNGLMEMORYBARRIERPROC) (GLbitfield barriers); -#endif - -#ifndef GL_ARB_shading_language_packing -#define GL_ARB_shading_language_packing 1 -#endif - -#ifndef GL_ARB_texture_storage -#define GL_ARB_texture_storage 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexStorage1D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); -GLAPI void APIENTRY glTexStorage2D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glTexStorage3D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); -GLAPI void APIENTRY glTextureStorage1DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); -GLAPI void APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTEXSTORAGE1DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); -typedef void (APIENTRYP PFNGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); -typedef void (APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); -typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); -#endif - -#ifndef GL_EXT_abgr -#define GL_EXT_abgr 1 -#endif - -#ifndef GL_EXT_blend_color -#define GL_EXT_blend_color 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendColorEXT (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBLENDCOLOREXTPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); -#endif - -#ifndef GL_EXT_polygon_offset -#define GL_EXT_polygon_offset 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPolygonOffsetEXT (GLfloat factor, GLfloat bias); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPOLYGONOFFSETEXTPROC) (GLfloat factor, GLfloat bias); -#endif - -#ifndef GL_EXT_texture -#define GL_EXT_texture 1 -#endif - -#ifndef GL_EXT_texture3D -#define GL_EXT_texture3D 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexImage3DEXT (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTEXIMAGE3DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); -#endif - -#ifndef GL_SGIS_texture_filter4 -#define GL_SGIS_texture_filter4 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetTexFilterFuncSGIS (GLenum target, GLenum filter, GLfloat *weights); -GLAPI void APIENTRY glTexFilterFuncSGIS (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGETTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLfloat *weights); -typedef void (APIENTRYP PFNGLTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights); -#endif - -#ifndef GL_EXT_subtexture -#define GL_EXT_subtexture 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); -#endif - -#ifndef GL_EXT_copy_texture -#define GL_EXT_copy_texture 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glCopyTexImage1DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); -GLAPI void APIENTRY glCopyTexImage2DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -GLAPI void APIENTRY glCopyTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glCopyTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glCopyTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); -typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -#endif - -#ifndef GL_EXT_histogram -#define GL_EXT_histogram 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetHistogramEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); -GLAPI void APIENTRY glGetHistogramParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetHistogramParameterivEXT (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetMinmaxEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); -GLAPI void APIENTRY glGetMinmaxParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetMinmaxParameterivEXT (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glHistogramEXT (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); -GLAPI void APIENTRY glMinmaxEXT (GLenum target, GLenum internalformat, GLboolean sink); -GLAPI void APIENTRY glResetHistogramEXT (GLenum target); -GLAPI void APIENTRY glResetMinmaxEXT (GLenum target); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGETHISTOGRAMEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); -typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETMINMAXEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); -typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLHISTOGRAMEXTPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); -typedef void (APIENTRYP PFNGLMINMAXEXTPROC) (GLenum target, GLenum internalformat, GLboolean sink); -typedef void (APIENTRYP PFNGLRESETHISTOGRAMEXTPROC) (GLenum target); -typedef void (APIENTRYP PFNGLRESETMINMAXEXTPROC) (GLenum target); -#endif - -#ifndef GL_EXT_convolution -#define GL_EXT_convolution 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); -GLAPI void APIENTRY glConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); -GLAPI void APIENTRY glConvolutionParameterfEXT (GLenum target, GLenum pname, GLfloat params); -GLAPI void APIENTRY glConvolutionParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glConvolutionParameteriEXT (GLenum target, GLenum pname, GLint params); -GLAPI void APIENTRY glConvolutionParameterivEXT (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glCopyConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glCopyConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetConvolutionFilterEXT (GLenum target, GLenum format, GLenum type, GLvoid *image); -GLAPI void APIENTRY glGetConvolutionParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetConvolutionParameterivEXT (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetSeparableFilterEXT (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); -GLAPI void APIENTRY glSeparableFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); -typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); -typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat params); -typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint params); -typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image); -typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETSEPARABLEFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); -typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); -#endif - -#ifndef GL_SGI_color_matrix -#define GL_SGI_color_matrix 1 -#endif - -#ifndef GL_SGI_color_table -#define GL_SGI_color_table 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColorTableSGI (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); -GLAPI void APIENTRY glColorTableParameterfvSGI (GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glColorTableParameterivSGI (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glCopyColorTableSGI (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glGetColorTableSGI (GLenum target, GLenum format, GLenum type, GLvoid *table); -GLAPI void APIENTRY glGetColorTableParameterfvSGI (GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetColorTableParameterivSGI (GLenum target, GLenum pname, GLint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); -typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLCOPYCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLGETCOLORTABLESGIPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table); -typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, GLint *params); -#endif - -#ifndef GL_SGIX_pixel_texture -#define GL_SGIX_pixel_texture 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPixelTexGenSGIX (GLenum mode); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPIXELTEXGENSGIXPROC) (GLenum mode); -#endif - -#ifndef GL_SGIS_pixel_texture -#define GL_SGIS_pixel_texture 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPixelTexGenParameteriSGIS (GLenum pname, GLint param); -GLAPI void APIENTRY glPixelTexGenParameterivSGIS (GLenum pname, const GLint *params); -GLAPI void APIENTRY glPixelTexGenParameterfSGIS (GLenum pname, GLfloat param); -GLAPI void APIENTRY glPixelTexGenParameterfvSGIS (GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glGetPixelTexGenParameterivSGIS (GLenum pname, GLint *params); -GLAPI void APIENTRY glGetPixelTexGenParameterfvSGIS (GLenum pname, GLfloat *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERISGISPROC) (GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFSGISPROC) (GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, GLfloat *params); -#endif - -#ifndef GL_SGIS_texture4D -#define GL_SGIS_texture4D 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexImage4DSGIS (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glTexSubImage4DSGIS (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const GLvoid *pixels); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTEXIMAGE4DSGISPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLTEXSUBIMAGE4DSGISPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const GLvoid *pixels); -#endif - -#ifndef GL_SGI_texture_color_table -#define GL_SGI_texture_color_table 1 -#endif - -#ifndef GL_EXT_cmyka -#define GL_EXT_cmyka 1 -#endif - -#ifndef GL_EXT_texture_object -#define GL_EXT_texture_object 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLboolean APIENTRY glAreTexturesResidentEXT (GLsizei n, const GLuint *textures, GLboolean *residences); -GLAPI void APIENTRY glBindTextureEXT (GLenum target, GLuint texture); -GLAPI void APIENTRY glDeleteTexturesEXT (GLsizei n, const GLuint *textures); -GLAPI void APIENTRY glGenTexturesEXT (GLsizei n, GLuint *textures); -GLAPI GLboolean APIENTRY glIsTextureEXT (GLuint texture); -GLAPI void APIENTRY glPrioritizeTexturesEXT (GLsizei n, const GLuint *textures, const GLclampf *priorities); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLboolean (APIENTRYP PFNGLARETEXTURESRESIDENTEXTPROC) (GLsizei n, const GLuint *textures, GLboolean *residences); -typedef void (APIENTRYP PFNGLBINDTEXTUREEXTPROC) (GLenum target, GLuint texture); -typedef void (APIENTRYP PFNGLDELETETEXTURESEXTPROC) (GLsizei n, const GLuint *textures); -typedef void (APIENTRYP PFNGLGENTEXTURESEXTPROC) (GLsizei n, GLuint *textures); -typedef GLboolean (APIENTRYP PFNGLISTEXTUREEXTPROC) (GLuint texture); -typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESEXTPROC) (GLsizei n, const GLuint *textures, const GLclampf *priorities); -#endif - -#ifndef GL_SGIS_detail_texture -#define GL_SGIS_detail_texture 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDetailTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points); -GLAPI void APIENTRY glGetDetailTexFuncSGIS (GLenum target, GLfloat *points); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDETAILTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points); -typedef void (APIENTRYP PFNGLGETDETAILTEXFUNCSGISPROC) (GLenum target, GLfloat *points); -#endif - -#ifndef GL_SGIS_sharpen_texture -#define GL_SGIS_sharpen_texture 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glSharpenTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points); -GLAPI void APIENTRY glGetSharpenTexFuncSGIS (GLenum target, GLfloat *points); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLSHARPENTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points); -typedef void (APIENTRYP PFNGLGETSHARPENTEXFUNCSGISPROC) (GLenum target, GLfloat *points); -#endif - -#ifndef GL_EXT_packed_pixels -#define GL_EXT_packed_pixels 1 -#endif - -#ifndef GL_SGIS_texture_lod -#define GL_SGIS_texture_lod 1 -#endif - -#ifndef GL_SGIS_multisample -#define GL_SGIS_multisample 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glSampleMaskSGIS (GLclampf value, GLboolean invert); -GLAPI void APIENTRY glSamplePatternSGIS (GLenum pattern); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLSAMPLEMASKSGISPROC) (GLclampf value, GLboolean invert); -typedef void (APIENTRYP PFNGLSAMPLEPATTERNSGISPROC) (GLenum pattern); -#endif - -#ifndef GL_EXT_rescale_normal -#define GL_EXT_rescale_normal 1 -#endif - -#ifndef GL_EXT_vertex_array -#define GL_EXT_vertex_array 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glArrayElementEXT (GLint i); -GLAPI void APIENTRY glColorPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); -GLAPI void APIENTRY glDrawArraysEXT (GLenum mode, GLint first, GLsizei count); -GLAPI void APIENTRY glEdgeFlagPointerEXT (GLsizei stride, GLsizei count, const GLboolean *pointer); -GLAPI void APIENTRY glGetPointervEXT (GLenum pname, GLvoid* *params); -GLAPI void APIENTRY glIndexPointerEXT (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); -GLAPI void APIENTRY glNormalPointerEXT (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); -GLAPI void APIENTRY glTexCoordPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); -GLAPI void APIENTRY glVertexPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLARRAYELEMENTEXTPROC) (GLint i); -typedef void (APIENTRYP PFNGLCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLDRAWARRAYSEXTPROC) (GLenum mode, GLint first, GLsizei count); -typedef void (APIENTRYP PFNGLEDGEFLAGPOINTEREXTPROC) (GLsizei stride, GLsizei count, const GLboolean *pointer); -typedef void (APIENTRYP PFNGLGETPOINTERVEXTPROC) (GLenum pname, GLvoid* *params); -typedef void (APIENTRYP PFNGLINDEXPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLNORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLTEXCOORDPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLVERTEXPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); -#endif - -#ifndef GL_EXT_misc_attribute -#define GL_EXT_misc_attribute 1 -#endif - -#ifndef GL_SGIS_generate_mipmap -#define GL_SGIS_generate_mipmap 1 -#endif - -#ifndef GL_SGIX_clipmap -#define GL_SGIX_clipmap 1 -#endif - -#ifndef GL_SGIX_shadow -#define GL_SGIX_shadow 1 -#endif - -#ifndef GL_SGIS_texture_edge_clamp -#define GL_SGIS_texture_edge_clamp 1 -#endif - -#ifndef GL_SGIS_texture_border_clamp -#define GL_SGIS_texture_border_clamp 1 -#endif - -#ifndef GL_EXT_blend_minmax -#define GL_EXT_blend_minmax 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendEquationEXT (GLenum mode); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBLENDEQUATIONEXTPROC) (GLenum mode); -#endif - -#ifndef GL_EXT_blend_subtract -#define GL_EXT_blend_subtract 1 -#endif - -#ifndef GL_EXT_blend_logic_op -#define GL_EXT_blend_logic_op 1 -#endif - -#ifndef GL_SGIX_interlace -#define GL_SGIX_interlace 1 -#endif - -#ifndef GL_SGIX_pixel_tiles -#define GL_SGIX_pixel_tiles 1 -#endif - -#ifndef GL_SGIX_texture_select -#define GL_SGIX_texture_select 1 -#endif - -#ifndef GL_SGIX_sprite -#define GL_SGIX_sprite 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glSpriteParameterfSGIX (GLenum pname, GLfloat param); -GLAPI void APIENTRY glSpriteParameterfvSGIX (GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glSpriteParameteriSGIX (GLenum pname, GLint param); -GLAPI void APIENTRY glSpriteParameterivSGIX (GLenum pname, const GLint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLSPRITEPARAMETERFSGIXPROC) (GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLSPRITEPARAMETERFVSGIXPROC) (GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLSPRITEPARAMETERISGIXPROC) (GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLSPRITEPARAMETERIVSGIXPROC) (GLenum pname, const GLint *params); -#endif - -#ifndef GL_SGIX_texture_multi_buffer -#define GL_SGIX_texture_multi_buffer 1 -#endif - -#ifndef GL_EXT_point_parameters -#define GL_EXT_point_parameters 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPointParameterfEXT (GLenum pname, GLfloat param); -GLAPI void APIENTRY glPointParameterfvEXT (GLenum pname, const GLfloat *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPOINTPARAMETERFEXTPROC) (GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLPOINTPARAMETERFVEXTPROC) (GLenum pname, const GLfloat *params); -#endif - -#ifndef GL_SGIS_point_parameters -#define GL_SGIS_point_parameters 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPointParameterfSGIS (GLenum pname, GLfloat param); -GLAPI void APIENTRY glPointParameterfvSGIS (GLenum pname, const GLfloat *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPOINTPARAMETERFSGISPROC) (GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLPOINTPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params); -#endif - -#ifndef GL_SGIX_instruments -#define GL_SGIX_instruments 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLint APIENTRY glGetInstrumentsSGIX (void); -GLAPI void APIENTRY glInstrumentsBufferSGIX (GLsizei size, GLint *buffer); -GLAPI GLint APIENTRY glPollInstrumentsSGIX (GLint *marker_p); -GLAPI void APIENTRY glReadInstrumentsSGIX (GLint marker); -GLAPI void APIENTRY glStartInstrumentsSGIX (void); -GLAPI void APIENTRY glStopInstrumentsSGIX (GLint marker); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLint (APIENTRYP PFNGLGETINSTRUMENTSSGIXPROC) (void); -typedef void (APIENTRYP PFNGLINSTRUMENTSBUFFERSGIXPROC) (GLsizei size, GLint *buffer); -typedef GLint (APIENTRYP PFNGLPOLLINSTRUMENTSSGIXPROC) (GLint *marker_p); -typedef void (APIENTRYP PFNGLREADINSTRUMENTSSGIXPROC) (GLint marker); -typedef void (APIENTRYP PFNGLSTARTINSTRUMENTSSGIXPROC) (void); -typedef void (APIENTRYP PFNGLSTOPINSTRUMENTSSGIXPROC) (GLint marker); -#endif - -#ifndef GL_SGIX_texture_scale_bias -#define GL_SGIX_texture_scale_bias 1 -#endif - -#ifndef GL_SGIX_framezoom -#define GL_SGIX_framezoom 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFrameZoomSGIX (GLint factor); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLFRAMEZOOMSGIXPROC) (GLint factor); -#endif - -#ifndef GL_SGIX_tag_sample_buffer -#define GL_SGIX_tag_sample_buffer 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTagSampleBufferSGIX (void); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTAGSAMPLEBUFFERSGIXPROC) (void); -#endif - -#ifndef GL_SGIX_polynomial_ffd -#define GL_SGIX_polynomial_ffd 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDeformationMap3dSGIX (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points); -GLAPI void APIENTRY glDeformationMap3fSGIX (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points); -GLAPI void APIENTRY glDeformSGIX (GLbitfield mask); -GLAPI void APIENTRY glLoadIdentityDeformationMapSGIX (GLbitfield mask); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDEFORMATIONMAP3DSGIXPROC) (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points); -typedef void (APIENTRYP PFNGLDEFORMATIONMAP3FSGIXPROC) (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points); -typedef void (APIENTRYP PFNGLDEFORMSGIXPROC) (GLbitfield mask); -typedef void (APIENTRYP PFNGLLOADIDENTITYDEFORMATIONMAPSGIXPROC) (GLbitfield mask); -#endif - -#ifndef GL_SGIX_reference_plane -#define GL_SGIX_reference_plane 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glReferencePlaneSGIX (const GLdouble *equation); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLREFERENCEPLANESGIXPROC) (const GLdouble *equation); -#endif - -#ifndef GL_SGIX_flush_raster -#define GL_SGIX_flush_raster 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFlushRasterSGIX (void); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLFLUSHRASTERSGIXPROC) (void); -#endif - -#ifndef GL_SGIX_depth_texture -#define GL_SGIX_depth_texture 1 -#endif - -#ifndef GL_SGIS_fog_function -#define GL_SGIS_fog_function 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFogFuncSGIS (GLsizei n, const GLfloat *points); -GLAPI void APIENTRY glGetFogFuncSGIS (GLfloat *points); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLFOGFUNCSGISPROC) (GLsizei n, const GLfloat *points); -typedef void (APIENTRYP PFNGLGETFOGFUNCSGISPROC) (GLfloat *points); -#endif - -#ifndef GL_SGIX_fog_offset -#define GL_SGIX_fog_offset 1 -#endif - -#ifndef GL_HP_image_transform -#define GL_HP_image_transform 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glImageTransformParameteriHP (GLenum target, GLenum pname, GLint param); -GLAPI void APIENTRY glImageTransformParameterfHP (GLenum target, GLenum pname, GLfloat param); -GLAPI void APIENTRY glImageTransformParameterivHP (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glImageTransformParameterfvHP (GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glGetImageTransformParameterivHP (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetImageTransformParameterfvHP (GLenum target, GLenum pname, GLfloat *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIHPPROC) (GLenum target, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFHPPROC) (GLenum target, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, GLfloat *params); -#endif - -#ifndef GL_HP_convolution_border_modes -#define GL_HP_convolution_border_modes 1 -#endif - -#ifndef GL_SGIX_texture_add_env -#define GL_SGIX_texture_add_env 1 -#endif - -#ifndef GL_EXT_color_subtable -#define GL_EXT_color_subtable 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColorSubTableEXT (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); -GLAPI void APIENTRY glCopyColorSubTableEXT (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); -#endif - -#ifndef GL_PGI_vertex_hints -#define GL_PGI_vertex_hints 1 -#endif - -#ifndef GL_PGI_misc_hints -#define GL_PGI_misc_hints 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glHintPGI (GLenum target, GLint mode); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLHINTPGIPROC) (GLenum target, GLint mode); -#endif - -#ifndef GL_EXT_paletted_texture -#define GL_EXT_paletted_texture 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColorTableEXT (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); -GLAPI void APIENTRY glGetColorTableEXT (GLenum target, GLenum format, GLenum type, GLvoid *data); -GLAPI void APIENTRY glGetColorTableParameterivEXT (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetColorTableParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); -typedef void (APIENTRYP PFNGLGETCOLORTABLEEXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *data); -typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); -#endif - -#ifndef GL_EXT_clip_volume_hint -#define GL_EXT_clip_volume_hint 1 -#endif - -#ifndef GL_SGIX_list_priority -#define GL_SGIX_list_priority 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetListParameterfvSGIX (GLuint list, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetListParameterivSGIX (GLuint list, GLenum pname, GLint *params); -GLAPI void APIENTRY glListParameterfSGIX (GLuint list, GLenum pname, GLfloat param); -GLAPI void APIENTRY glListParameterfvSGIX (GLuint list, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glListParameteriSGIX (GLuint list, GLenum pname, GLint param); -GLAPI void APIENTRY glListParameterivSGIX (GLuint list, GLenum pname, const GLint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGETLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLLISTPARAMETERFSGIXPROC) (GLuint list, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLLISTPARAMETERISGIXPROC) (GLuint list, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, const GLint *params); -#endif - -#ifndef GL_SGIX_ir_instrument1 -#define GL_SGIX_ir_instrument1 1 -#endif - -#ifndef GL_SGIX_calligraphic_fragment -#define GL_SGIX_calligraphic_fragment 1 -#endif - -#ifndef GL_SGIX_texture_lod_bias -#define GL_SGIX_texture_lod_bias 1 -#endif - -#ifndef GL_SGIX_shadow_ambient -#define GL_SGIX_shadow_ambient 1 -#endif - -#ifndef GL_EXT_index_texture -#define GL_EXT_index_texture 1 -#endif - -#ifndef GL_EXT_index_material -#define GL_EXT_index_material 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glIndexMaterialEXT (GLenum face, GLenum mode); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLINDEXMATERIALEXTPROC) (GLenum face, GLenum mode); -#endif - -#ifndef GL_EXT_index_func -#define GL_EXT_index_func 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glIndexFuncEXT (GLenum func, GLclampf ref); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLINDEXFUNCEXTPROC) (GLenum func, GLclampf ref); -#endif - -#ifndef GL_EXT_index_array_formats -#define GL_EXT_index_array_formats 1 -#endif - -#ifndef GL_EXT_compiled_vertex_array -#define GL_EXT_compiled_vertex_array 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glLockArraysEXT (GLint first, GLsizei count); -GLAPI void APIENTRY glUnlockArraysEXT (void); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLLOCKARRAYSEXTPROC) (GLint first, GLsizei count); -typedef void (APIENTRYP PFNGLUNLOCKARRAYSEXTPROC) (void); -#endif - -#ifndef GL_EXT_cull_vertex -#define GL_EXT_cull_vertex 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glCullParameterdvEXT (GLenum pname, GLdouble *params); -GLAPI void APIENTRY glCullParameterfvEXT (GLenum pname, GLfloat *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCULLPARAMETERDVEXTPROC) (GLenum pname, GLdouble *params); -typedef void (APIENTRYP PFNGLCULLPARAMETERFVEXTPROC) (GLenum pname, GLfloat *params); -#endif - -#ifndef GL_SGIX_ycrcb -#define GL_SGIX_ycrcb 1 -#endif - -#ifndef GL_SGIX_fragment_lighting -#define GL_SGIX_fragment_lighting 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFragmentColorMaterialSGIX (GLenum face, GLenum mode); -GLAPI void APIENTRY glFragmentLightfSGIX (GLenum light, GLenum pname, GLfloat param); -GLAPI void APIENTRY glFragmentLightfvSGIX (GLenum light, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glFragmentLightiSGIX (GLenum light, GLenum pname, GLint param); -GLAPI void APIENTRY glFragmentLightivSGIX (GLenum light, GLenum pname, const GLint *params); -GLAPI void APIENTRY glFragmentLightModelfSGIX (GLenum pname, GLfloat param); -GLAPI void APIENTRY glFragmentLightModelfvSGIX (GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glFragmentLightModeliSGIX (GLenum pname, GLint param); -GLAPI void APIENTRY glFragmentLightModelivSGIX (GLenum pname, const GLint *params); -GLAPI void APIENTRY glFragmentMaterialfSGIX (GLenum face, GLenum pname, GLfloat param); -GLAPI void APIENTRY glFragmentMaterialfvSGIX (GLenum face, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glFragmentMaterialiSGIX (GLenum face, GLenum pname, GLint param); -GLAPI void APIENTRY glFragmentMaterialivSGIX (GLenum face, GLenum pname, const GLint *params); -GLAPI void APIENTRY glGetFragmentLightfvSGIX (GLenum light, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetFragmentLightivSGIX (GLenum light, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetFragmentMaterialfvSGIX (GLenum face, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetFragmentMaterialivSGIX (GLenum face, GLenum pname, GLint *params); -GLAPI void APIENTRY glLightEnviSGIX (GLenum pname, GLint param); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLFRAGMENTCOLORMATERIALSGIXPROC) (GLenum face, GLenum mode); -typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFSGIXPROC) (GLenum light, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLFRAGMENTLIGHTISGIXPROC) (GLenum light, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFSGIXPROC) (GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFVSGIXPROC) (GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELISGIXPROC) (GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELIVSGIXPROC) (GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFSGIXPROC) (GLenum face, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLFRAGMENTMATERIALISGIXPROC) (GLenum face, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLLIGHTENVISGIXPROC) (GLenum pname, GLint param); -#endif - -#ifndef GL_IBM_rasterpos_clip -#define GL_IBM_rasterpos_clip 1 -#endif - -#ifndef GL_HP_texture_lighting -#define GL_HP_texture_lighting 1 -#endif - -#ifndef GL_EXT_draw_range_elements -#define GL_EXT_draw_range_elements 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawRangeElementsEXT (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); -#endif - -#ifndef GL_WIN_phong_shading -#define GL_WIN_phong_shading 1 -#endif - -#ifndef GL_WIN_specular_fog -#define GL_WIN_specular_fog 1 -#endif - -#ifndef GL_EXT_light_texture -#define GL_EXT_light_texture 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glApplyTextureEXT (GLenum mode); -GLAPI void APIENTRY glTextureLightEXT (GLenum pname); -GLAPI void APIENTRY glTextureMaterialEXT (GLenum face, GLenum mode); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLAPPLYTEXTUREEXTPROC) (GLenum mode); -typedef void (APIENTRYP PFNGLTEXTURELIGHTEXTPROC) (GLenum pname); -typedef void (APIENTRYP PFNGLTEXTUREMATERIALEXTPROC) (GLenum face, GLenum mode); -#endif - -#ifndef GL_SGIX_blend_alpha_minmax -#define GL_SGIX_blend_alpha_minmax 1 -#endif - -#ifndef GL_EXT_bgra -#define GL_EXT_bgra 1 -#endif - -#ifndef GL_SGIX_async -#define GL_SGIX_async 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glAsyncMarkerSGIX (GLuint marker); -GLAPI GLint APIENTRY glFinishAsyncSGIX (GLuint *markerp); -GLAPI GLint APIENTRY glPollAsyncSGIX (GLuint *markerp); -GLAPI GLuint APIENTRY glGenAsyncMarkersSGIX (GLsizei range); -GLAPI void APIENTRY glDeleteAsyncMarkersSGIX (GLuint marker, GLsizei range); -GLAPI GLboolean APIENTRY glIsAsyncMarkerSGIX (GLuint marker); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLASYNCMARKERSGIXPROC) (GLuint marker); -typedef GLint (APIENTRYP PFNGLFINISHASYNCSGIXPROC) (GLuint *markerp); -typedef GLint (APIENTRYP PFNGLPOLLASYNCSGIXPROC) (GLuint *markerp); -typedef GLuint (APIENTRYP PFNGLGENASYNCMARKERSSGIXPROC) (GLsizei range); -typedef void (APIENTRYP PFNGLDELETEASYNCMARKERSSGIXPROC) (GLuint marker, GLsizei range); -typedef GLboolean (APIENTRYP PFNGLISASYNCMARKERSGIXPROC) (GLuint marker); -#endif - -#ifndef GL_SGIX_async_pixel -#define GL_SGIX_async_pixel 1 -#endif - -#ifndef GL_SGIX_async_histogram -#define GL_SGIX_async_histogram 1 -#endif - -#ifndef GL_INTEL_parallel_arrays -#define GL_INTEL_parallel_arrays 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexPointervINTEL (GLint size, GLenum type, const GLvoid* *pointer); -GLAPI void APIENTRY glNormalPointervINTEL (GLenum type, const GLvoid* *pointer); -GLAPI void APIENTRY glColorPointervINTEL (GLint size, GLenum type, const GLvoid* *pointer); -GLAPI void APIENTRY glTexCoordPointervINTEL (GLint size, GLenum type, const GLvoid* *pointer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVERTEXPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer); -typedef void (APIENTRYP PFNGLNORMALPOINTERVINTELPROC) (GLenum type, const GLvoid* *pointer); -typedef void (APIENTRYP PFNGLCOLORPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer); -typedef void (APIENTRYP PFNGLTEXCOORDPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer); -#endif - -#ifndef GL_HP_occlusion_test -#define GL_HP_occlusion_test 1 -#endif - -#ifndef GL_EXT_pixel_transform -#define GL_EXT_pixel_transform 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPixelTransformParameteriEXT (GLenum target, GLenum pname, GLint param); -GLAPI void APIENTRY glPixelTransformParameterfEXT (GLenum target, GLenum pname, GLfloat param); -GLAPI void APIENTRY glPixelTransformParameterivEXT (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glPixelTransformParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params); -#endif - -#ifndef GL_EXT_pixel_transform_color_table -#define GL_EXT_pixel_transform_color_table 1 -#endif - -#ifndef GL_EXT_shared_texture_palette -#define GL_EXT_shared_texture_palette 1 -#endif - -#ifndef GL_EXT_separate_specular_color -#define GL_EXT_separate_specular_color 1 -#endif - -#ifndef GL_EXT_secondary_color -#define GL_EXT_secondary_color 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glSecondaryColor3bEXT (GLbyte red, GLbyte green, GLbyte blue); -GLAPI void APIENTRY glSecondaryColor3bvEXT (const GLbyte *v); -GLAPI void APIENTRY glSecondaryColor3dEXT (GLdouble red, GLdouble green, GLdouble blue); -GLAPI void APIENTRY glSecondaryColor3dvEXT (const GLdouble *v); -GLAPI void APIENTRY glSecondaryColor3fEXT (GLfloat red, GLfloat green, GLfloat blue); -GLAPI void APIENTRY glSecondaryColor3fvEXT (const GLfloat *v); -GLAPI void APIENTRY glSecondaryColor3iEXT (GLint red, GLint green, GLint blue); -GLAPI void APIENTRY glSecondaryColor3ivEXT (const GLint *v); -GLAPI void APIENTRY glSecondaryColor3sEXT (GLshort red, GLshort green, GLshort blue); -GLAPI void APIENTRY glSecondaryColor3svEXT (const GLshort *v); -GLAPI void APIENTRY glSecondaryColor3ubEXT (GLubyte red, GLubyte green, GLubyte blue); -GLAPI void APIENTRY glSecondaryColor3ubvEXT (const GLubyte *v); -GLAPI void APIENTRY glSecondaryColor3uiEXT (GLuint red, GLuint green, GLuint blue); -GLAPI void APIENTRY glSecondaryColor3uivEXT (const GLuint *v); -GLAPI void APIENTRY glSecondaryColor3usEXT (GLushort red, GLushort green, GLushort blue); -GLAPI void APIENTRY glSecondaryColor3usvEXT (const GLushort *v); -GLAPI void APIENTRY glSecondaryColorPointerEXT (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BEXTPROC) (GLbyte red, GLbyte green, GLbyte blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVEXTPROC) (const GLbyte *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DEXTPROC) (GLdouble red, GLdouble green, GLdouble blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVEXTPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FEXTPROC) (GLfloat red, GLfloat green, GLfloat blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVEXTPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IEXTPROC) (GLint red, GLint green, GLint blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVEXTPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SEXTPROC) (GLshort red, GLshort green, GLshort blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVEXTPROC) (const GLshort *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBEXTPROC) (GLubyte red, GLubyte green, GLubyte blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVEXTPROC) (const GLubyte *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIEXTPROC) (GLuint red, GLuint green, GLuint blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVEXTPROC) (const GLuint *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USEXTPROC) (GLushort red, GLushort green, GLushort blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVEXTPROC) (const GLushort *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -#endif - -#ifndef GL_EXT_texture_perturb_normal -#define GL_EXT_texture_perturb_normal 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTextureNormalEXT (GLenum mode); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTEXTURENORMALEXTPROC) (GLenum mode); -#endif - -#ifndef GL_EXT_multi_draw_arrays -#define GL_EXT_multi_draw_arrays 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMultiDrawArraysEXT (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); -GLAPI void APIENTRY glMultiDrawElementsEXT (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); -#endif - -#ifndef GL_EXT_fog_coord -#define GL_EXT_fog_coord 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFogCoordfEXT (GLfloat coord); -GLAPI void APIENTRY glFogCoordfvEXT (const GLfloat *coord); -GLAPI void APIENTRY glFogCoorddEXT (GLdouble coord); -GLAPI void APIENTRY glFogCoorddvEXT (const GLdouble *coord); -GLAPI void APIENTRY glFogCoordPointerEXT (GLenum type, GLsizei stride, const GLvoid *pointer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLFOGCOORDFEXTPROC) (GLfloat coord); -typedef void (APIENTRYP PFNGLFOGCOORDFVEXTPROC) (const GLfloat *coord); -typedef void (APIENTRYP PFNGLFOGCOORDDEXTPROC) (GLdouble coord); -typedef void (APIENTRYP PFNGLFOGCOORDDVEXTPROC) (const GLdouble *coord); -typedef void (APIENTRYP PFNGLFOGCOORDPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); -#endif - -#ifndef GL_REND_screen_coordinates -#define GL_REND_screen_coordinates 1 -#endif - -#ifndef GL_EXT_coordinate_frame -#define GL_EXT_coordinate_frame 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTangent3bEXT (GLbyte tx, GLbyte ty, GLbyte tz); -GLAPI void APIENTRY glTangent3bvEXT (const GLbyte *v); -GLAPI void APIENTRY glTangent3dEXT (GLdouble tx, GLdouble ty, GLdouble tz); -GLAPI void APIENTRY glTangent3dvEXT (const GLdouble *v); -GLAPI void APIENTRY glTangent3fEXT (GLfloat tx, GLfloat ty, GLfloat tz); -GLAPI void APIENTRY glTangent3fvEXT (const GLfloat *v); -GLAPI void APIENTRY glTangent3iEXT (GLint tx, GLint ty, GLint tz); -GLAPI void APIENTRY glTangent3ivEXT (const GLint *v); -GLAPI void APIENTRY glTangent3sEXT (GLshort tx, GLshort ty, GLshort tz); -GLAPI void APIENTRY glTangent3svEXT (const GLshort *v); -GLAPI void APIENTRY glBinormal3bEXT (GLbyte bx, GLbyte by, GLbyte bz); -GLAPI void APIENTRY glBinormal3bvEXT (const GLbyte *v); -GLAPI void APIENTRY glBinormal3dEXT (GLdouble bx, GLdouble by, GLdouble bz); -GLAPI void APIENTRY glBinormal3dvEXT (const GLdouble *v); -GLAPI void APIENTRY glBinormal3fEXT (GLfloat bx, GLfloat by, GLfloat bz); -GLAPI void APIENTRY glBinormal3fvEXT (const GLfloat *v); -GLAPI void APIENTRY glBinormal3iEXT (GLint bx, GLint by, GLint bz); -GLAPI void APIENTRY glBinormal3ivEXT (const GLint *v); -GLAPI void APIENTRY glBinormal3sEXT (GLshort bx, GLshort by, GLshort bz); -GLAPI void APIENTRY glBinormal3svEXT (const GLshort *v); -GLAPI void APIENTRY glTangentPointerEXT (GLenum type, GLsizei stride, const GLvoid *pointer); -GLAPI void APIENTRY glBinormalPointerEXT (GLenum type, GLsizei stride, const GLvoid *pointer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTANGENT3BEXTPROC) (GLbyte tx, GLbyte ty, GLbyte tz); -typedef void (APIENTRYP PFNGLTANGENT3BVEXTPROC) (const GLbyte *v); -typedef void (APIENTRYP PFNGLTANGENT3DEXTPROC) (GLdouble tx, GLdouble ty, GLdouble tz); -typedef void (APIENTRYP PFNGLTANGENT3DVEXTPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLTANGENT3FEXTPROC) (GLfloat tx, GLfloat ty, GLfloat tz); -typedef void (APIENTRYP PFNGLTANGENT3FVEXTPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLTANGENT3IEXTPROC) (GLint tx, GLint ty, GLint tz); -typedef void (APIENTRYP PFNGLTANGENT3IVEXTPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLTANGENT3SEXTPROC) (GLshort tx, GLshort ty, GLshort tz); -typedef void (APIENTRYP PFNGLTANGENT3SVEXTPROC) (const GLshort *v); -typedef void (APIENTRYP PFNGLBINORMAL3BEXTPROC) (GLbyte bx, GLbyte by, GLbyte bz); -typedef void (APIENTRYP PFNGLBINORMAL3BVEXTPROC) (const GLbyte *v); -typedef void (APIENTRYP PFNGLBINORMAL3DEXTPROC) (GLdouble bx, GLdouble by, GLdouble bz); -typedef void (APIENTRYP PFNGLBINORMAL3DVEXTPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLBINORMAL3FEXTPROC) (GLfloat bx, GLfloat by, GLfloat bz); -typedef void (APIENTRYP PFNGLBINORMAL3FVEXTPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLBINORMAL3IEXTPROC) (GLint bx, GLint by, GLint bz); -typedef void (APIENTRYP PFNGLBINORMAL3IVEXTPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLBINORMAL3SEXTPROC) (GLshort bx, GLshort by, GLshort bz); -typedef void (APIENTRYP PFNGLBINORMAL3SVEXTPROC) (const GLshort *v); -typedef void (APIENTRYP PFNGLTANGENTPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLBINORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); -#endif - -#ifndef GL_EXT_texture_env_combine -#define GL_EXT_texture_env_combine 1 -#endif - -#ifndef GL_APPLE_specular_vector -#define GL_APPLE_specular_vector 1 -#endif - -#ifndef GL_APPLE_transform_hint -#define GL_APPLE_transform_hint 1 -#endif - -#ifndef GL_SGIX_fog_scale -#define GL_SGIX_fog_scale 1 -#endif - -#ifndef GL_SUNX_constant_data -#define GL_SUNX_constant_data 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFinishTextureSUNX (void); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLFINISHTEXTURESUNXPROC) (void); -#endif - -#ifndef GL_SUN_global_alpha -#define GL_SUN_global_alpha 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGlobalAlphaFactorbSUN (GLbyte factor); -GLAPI void APIENTRY glGlobalAlphaFactorsSUN (GLshort factor); -GLAPI void APIENTRY glGlobalAlphaFactoriSUN (GLint factor); -GLAPI void APIENTRY glGlobalAlphaFactorfSUN (GLfloat factor); -GLAPI void APIENTRY glGlobalAlphaFactordSUN (GLdouble factor); -GLAPI void APIENTRY glGlobalAlphaFactorubSUN (GLubyte factor); -GLAPI void APIENTRY glGlobalAlphaFactorusSUN (GLushort factor); -GLAPI void APIENTRY glGlobalAlphaFactoruiSUN (GLuint factor); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORBSUNPROC) (GLbyte factor); -typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORSSUNPROC) (GLshort factor); -typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORISUNPROC) (GLint factor); -typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORFSUNPROC) (GLfloat factor); -typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORDSUNPROC) (GLdouble factor); -typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUBSUNPROC) (GLubyte factor); -typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUSSUNPROC) (GLushort factor); -typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUISUNPROC) (GLuint factor); -#endif - -#ifndef GL_SUN_triangle_list -#define GL_SUN_triangle_list 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glReplacementCodeuiSUN (GLuint code); -GLAPI void APIENTRY glReplacementCodeusSUN (GLushort code); -GLAPI void APIENTRY glReplacementCodeubSUN (GLubyte code); -GLAPI void APIENTRY glReplacementCodeuivSUN (const GLuint *code); -GLAPI void APIENTRY glReplacementCodeusvSUN (const GLushort *code); -GLAPI void APIENTRY glReplacementCodeubvSUN (const GLubyte *code); -GLAPI void APIENTRY glReplacementCodePointerSUN (GLenum type, GLsizei stride, const GLvoid* *pointer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUISUNPROC) (GLuint code); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSSUNPROC) (GLushort code); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBSUNPROC) (GLubyte code); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVSUNPROC) (const GLuint *code); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSVSUNPROC) (const GLushort *code); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBVSUNPROC) (const GLubyte *code); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEPOINTERSUNPROC) (GLenum type, GLsizei stride, const GLvoid* *pointer); -#endif - -#ifndef GL_SUN_vertex -#define GL_SUN_vertex 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColor4ubVertex2fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y); -GLAPI void APIENTRY glColor4ubVertex2fvSUN (const GLubyte *c, const GLfloat *v); -GLAPI void APIENTRY glColor4ubVertex3fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glColor4ubVertex3fvSUN (const GLubyte *c, const GLfloat *v); -GLAPI void APIENTRY glColor3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glColor3fVertex3fvSUN (const GLfloat *c, const GLfloat *v); -GLAPI void APIENTRY glNormal3fVertex3fSUN (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glNormal3fVertex3fvSUN (const GLfloat *n, const GLfloat *v); -GLAPI void APIENTRY glColor4fNormal3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glColor4fNormal3fVertex3fvSUN (const GLfloat *c, const GLfloat *n, const GLfloat *v); -GLAPI void APIENTRY glTexCoord2fVertex3fSUN (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glTexCoord2fVertex3fvSUN (const GLfloat *tc, const GLfloat *v); -GLAPI void APIENTRY glTexCoord4fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glTexCoord4fVertex4fvSUN (const GLfloat *tc, const GLfloat *v); -GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fSUN (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fvSUN (const GLfloat *tc, const GLubyte *c, const GLfloat *v); -GLAPI void APIENTRY glTexCoord2fColor3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glTexCoord2fColor3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *v); -GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *n, const GLfloat *v); -GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); -GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); -GLAPI void APIENTRY glReplacementCodeuiVertex3fSUN (GLuint rc, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glReplacementCodeuiVertex3fvSUN (const GLuint *rc, const GLfloat *v); -GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fSUN (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fvSUN (const GLuint *rc, const GLubyte *c, const GLfloat *v); -GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *v); -GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fSUN (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *n, const GLfloat *v); -GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v); -GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *v); -GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v); -GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y); -typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FVSUNPROC) (const GLubyte *c, const GLfloat *v); -typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FVSUNPROC) (const GLubyte *c, const GLfloat *v); -typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *v); -typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FSUNPROC) (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *n, const GLfloat *v); -typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *n, const GLfloat *v); -typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *v); -typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *v); -typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FVSUNPROC) (const GLfloat *tc, const GLubyte *c, const GLfloat *v); -typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *v); -typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *n, const GLfloat *v); -typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); -typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FSUNPROC) (GLuint rc, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *v); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FSUNPROC) (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FVSUNPROC) (const GLuint *rc, const GLubyte *c, const GLfloat *v); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *v); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *n, const GLfloat *v); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *v); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); -#endif - -#ifndef GL_EXT_blend_func_separate -#define GL_EXT_blend_func_separate 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendFuncSeparateEXT (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEEXTPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); -#endif - -#ifndef GL_INGR_blend_func_separate -#define GL_INGR_blend_func_separate 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendFuncSeparateINGR (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINGRPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); -#endif - -#ifndef GL_INGR_color_clamp -#define GL_INGR_color_clamp 1 -#endif - -#ifndef GL_INGR_interlace_read -#define GL_INGR_interlace_read 1 -#endif - -#ifndef GL_EXT_stencil_wrap -#define GL_EXT_stencil_wrap 1 -#endif - -#ifndef GL_EXT_422_pixels -#define GL_EXT_422_pixels 1 -#endif - -#ifndef GL_NV_texgen_reflection -#define GL_NV_texgen_reflection 1 -#endif - -#ifndef GL_SUN_convolution_border_modes -#define GL_SUN_convolution_border_modes 1 -#endif - -#ifndef GL_EXT_texture_env_add -#define GL_EXT_texture_env_add 1 -#endif - -#ifndef GL_EXT_texture_lod_bias -#define GL_EXT_texture_lod_bias 1 -#endif - -#ifndef GL_EXT_texture_filter_anisotropic -#define GL_EXT_texture_filter_anisotropic 1 -#endif - -#ifndef GL_EXT_vertex_weighting -#define GL_EXT_vertex_weighting 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexWeightfEXT (GLfloat weight); -GLAPI void APIENTRY glVertexWeightfvEXT (const GLfloat *weight); -GLAPI void APIENTRY glVertexWeightPointerEXT (GLsizei size, GLenum type, GLsizei stride, const GLvoid *pointer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVERTEXWEIGHTFEXTPROC) (GLfloat weight); -typedef void (APIENTRYP PFNGLVERTEXWEIGHTFVEXTPROC) (const GLfloat *weight); -typedef void (APIENTRYP PFNGLVERTEXWEIGHTPOINTEREXTPROC) (GLsizei size, GLenum type, GLsizei stride, const GLvoid *pointer); -#endif - -#ifndef GL_NV_light_max_exponent -#define GL_NV_light_max_exponent 1 -#endif - -#ifndef GL_NV_vertex_array_range -#define GL_NV_vertex_array_range 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFlushVertexArrayRangeNV (void); -GLAPI void APIENTRY glVertexArrayRangeNV (GLsizei length, const GLvoid *pointer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGENVPROC) (void); -typedef void (APIENTRYP PFNGLVERTEXARRAYRANGENVPROC) (GLsizei length, const GLvoid *pointer); -#endif - -#ifndef GL_NV_register_combiners -#define GL_NV_register_combiners 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glCombinerParameterfvNV (GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glCombinerParameterfNV (GLenum pname, GLfloat param); -GLAPI void APIENTRY glCombinerParameterivNV (GLenum pname, const GLint *params); -GLAPI void APIENTRY glCombinerParameteriNV (GLenum pname, GLint param); -GLAPI void APIENTRY glCombinerInputNV (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); -GLAPI void APIENTRY glCombinerOutputNV (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum); -GLAPI void APIENTRY glFinalCombinerInputNV (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); -GLAPI void APIENTRY glGetCombinerInputParameterfvNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetCombinerInputParameterivNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetCombinerOutputParameterfvNV (GLenum stage, GLenum portion, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetCombinerOutputParameterivNV (GLenum stage, GLenum portion, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetFinalCombinerInputParameterfvNV (GLenum variable, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetFinalCombinerInputParameterivNV (GLenum variable, GLenum pname, GLint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFVNVPROC) (GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFNVPROC) (GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLCOMBINERPARAMETERIVNVPROC) (GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLCOMBINERPARAMETERINVPROC) (GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLCOMBINERINPUTNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); -typedef void (APIENTRYP PFNGLCOMBINEROUTPUTNVPROC) (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum); -typedef void (APIENTRYP PFNGLFINALCOMBINERINPUTNVPROC) (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); -typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC) (GLenum variable, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC) (GLenum variable, GLenum pname, GLint *params); -#endif - -#ifndef GL_NV_fog_distance -#define GL_NV_fog_distance 1 -#endif - -#ifndef GL_NV_texgen_emboss -#define GL_NV_texgen_emboss 1 -#endif - -#ifndef GL_NV_blend_square -#define GL_NV_blend_square 1 -#endif - -#ifndef GL_NV_texture_env_combine4 -#define GL_NV_texture_env_combine4 1 -#endif - -#ifndef GL_MESA_resize_buffers -#define GL_MESA_resize_buffers 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glResizeBuffersMESA (void); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLRESIZEBUFFERSMESAPROC) (void); -#endif - -#ifndef GL_MESA_window_pos -#define GL_MESA_window_pos 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glWindowPos2dMESA (GLdouble x, GLdouble y); -GLAPI void APIENTRY glWindowPos2dvMESA (const GLdouble *v); -GLAPI void APIENTRY glWindowPos2fMESA (GLfloat x, GLfloat y); -GLAPI void APIENTRY glWindowPos2fvMESA (const GLfloat *v); -GLAPI void APIENTRY glWindowPos2iMESA (GLint x, GLint y); -GLAPI void APIENTRY glWindowPos2ivMESA (const GLint *v); -GLAPI void APIENTRY glWindowPos2sMESA (GLshort x, GLshort y); -GLAPI void APIENTRY glWindowPos2svMESA (const GLshort *v); -GLAPI void APIENTRY glWindowPos3dMESA (GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glWindowPos3dvMESA (const GLdouble *v); -GLAPI void APIENTRY glWindowPos3fMESA (GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glWindowPos3fvMESA (const GLfloat *v); -GLAPI void APIENTRY glWindowPos3iMESA (GLint x, GLint y, GLint z); -GLAPI void APIENTRY glWindowPos3ivMESA (const GLint *v); -GLAPI void APIENTRY glWindowPos3sMESA (GLshort x, GLshort y, GLshort z); -GLAPI void APIENTRY glWindowPos3svMESA (const GLshort *v); -GLAPI void APIENTRY glWindowPos4dMESA (GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glWindowPos4dvMESA (const GLdouble *v); -GLAPI void APIENTRY glWindowPos4fMESA (GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glWindowPos4fvMESA (const GLfloat *v); -GLAPI void APIENTRY glWindowPos4iMESA (GLint x, GLint y, GLint z, GLint w); -GLAPI void APIENTRY glWindowPos4ivMESA (const GLint *v); -GLAPI void APIENTRY glWindowPos4sMESA (GLshort x, GLshort y, GLshort z, GLshort w); -GLAPI void APIENTRY glWindowPos4svMESA (const GLshort *v); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLWINDOWPOS2DMESAPROC) (GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLWINDOWPOS2DVMESAPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLWINDOWPOS2FMESAPROC) (GLfloat x, GLfloat y); -typedef void (APIENTRYP PFNGLWINDOWPOS2FVMESAPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLWINDOWPOS2IMESAPROC) (GLint x, GLint y); -typedef void (APIENTRYP PFNGLWINDOWPOS2IVMESAPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLWINDOWPOS2SMESAPROC) (GLshort x, GLshort y); -typedef void (APIENTRYP PFNGLWINDOWPOS2SVMESAPROC) (const GLshort *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3DMESAPROC) (GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLWINDOWPOS3DVMESAPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3FMESAPROC) (GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLWINDOWPOS3FVMESAPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3IMESAPROC) (GLint x, GLint y, GLint z); -typedef void (APIENTRYP PFNGLWINDOWPOS3IVMESAPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLWINDOWPOS3SMESAPROC) (GLshort x, GLshort y, GLshort z); -typedef void (APIENTRYP PFNGLWINDOWPOS3SVMESAPROC) (const GLshort *v); -typedef void (APIENTRYP PFNGLWINDOWPOS4DMESAPROC) (GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLWINDOWPOS4DVMESAPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNGLWINDOWPOS4FMESAPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLWINDOWPOS4FVMESAPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNGLWINDOWPOS4IMESAPROC) (GLint x, GLint y, GLint z, GLint w); -typedef void (APIENTRYP PFNGLWINDOWPOS4IVMESAPROC) (const GLint *v); -typedef void (APIENTRYP PFNGLWINDOWPOS4SMESAPROC) (GLshort x, GLshort y, GLshort z, GLshort w); -typedef void (APIENTRYP PFNGLWINDOWPOS4SVMESAPROC) (const GLshort *v); -#endif - -#ifndef GL_IBM_cull_vertex -#define GL_IBM_cull_vertex 1 -#endif - -#ifndef GL_IBM_multimode_draw_arrays -#define GL_IBM_multimode_draw_arrays 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMultiModeDrawArraysIBM (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride); -GLAPI void APIENTRY glMultiModeDrawElementsIBM (const GLenum *mode, const GLsizei *count, GLenum type, const GLvoid* const *indices, GLsizei primcount, GLint modestride); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLMULTIMODEDRAWARRAYSIBMPROC) (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride); -typedef void (APIENTRYP PFNGLMULTIMODEDRAWELEMENTSIBMPROC) (const GLenum *mode, const GLsizei *count, GLenum type, const GLvoid* const *indices, GLsizei primcount, GLint modestride); -#endif - -#ifndef GL_IBM_vertex_array_lists -#define GL_IBM_vertex_array_lists 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColorPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); -GLAPI void APIENTRY glSecondaryColorPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); -GLAPI void APIENTRY glEdgeFlagPointerListIBM (GLint stride, const GLboolean* *pointer, GLint ptrstride); -GLAPI void APIENTRY glFogCoordPointerListIBM (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); -GLAPI void APIENTRY glIndexPointerListIBM (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); -GLAPI void APIENTRY glNormalPointerListIBM (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); -GLAPI void APIENTRY glTexCoordPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); -GLAPI void APIENTRY glVertexPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); -typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); -typedef void (APIENTRYP PFNGLEDGEFLAGPOINTERLISTIBMPROC) (GLint stride, const GLboolean* *pointer, GLint ptrstride); -typedef void (APIENTRYP PFNGLFOGCOORDPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); -typedef void (APIENTRYP PFNGLINDEXPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); -typedef void (APIENTRYP PFNGLNORMALPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); -typedef void (APIENTRYP PFNGLTEXCOORDPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); -typedef void (APIENTRYP PFNGLVERTEXPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); -#endif - -#ifndef GL_SGIX_subsample -#define GL_SGIX_subsample 1 -#endif - -#ifndef GL_SGIX_ycrcba -#define GL_SGIX_ycrcba 1 -#endif - -#ifndef GL_SGIX_ycrcb_subsample -#define GL_SGIX_ycrcb_subsample 1 -#endif - -#ifndef GL_SGIX_depth_pass_instrument -#define GL_SGIX_depth_pass_instrument 1 -#endif - -#ifndef GL_3DFX_texture_compression_FXT1 -#define GL_3DFX_texture_compression_FXT1 1 -#endif - -#ifndef GL_3DFX_multisample -#define GL_3DFX_multisample 1 -#endif - -#ifndef GL_3DFX_tbuffer -#define GL_3DFX_tbuffer 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTbufferMask3DFX (GLuint mask); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTBUFFERMASK3DFXPROC) (GLuint mask); -#endif - -#ifndef GL_EXT_multisample -#define GL_EXT_multisample 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glSampleMaskEXT (GLclampf value, GLboolean invert); -GLAPI void APIENTRY glSamplePatternEXT (GLenum pattern); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLSAMPLEMASKEXTPROC) (GLclampf value, GLboolean invert); -typedef void (APIENTRYP PFNGLSAMPLEPATTERNEXTPROC) (GLenum pattern); -#endif - -#ifndef GL_SGIX_vertex_preclip -#define GL_SGIX_vertex_preclip 1 -#endif - -#ifndef GL_SGIX_convolution_accuracy -#define GL_SGIX_convolution_accuracy 1 -#endif - -#ifndef GL_SGIX_resample -#define GL_SGIX_resample 1 -#endif - -#ifndef GL_SGIS_point_line_texgen -#define GL_SGIS_point_line_texgen 1 -#endif - -#ifndef GL_SGIS_texture_color_mask -#define GL_SGIS_texture_color_mask 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTextureColorMaskSGIS (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTEXTURECOLORMASKSGISPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); -#endif - -#ifndef GL_SGIX_igloo_interface -#define GL_SGIX_igloo_interface 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glIglooInterfaceSGIX (GLenum pname, const GLvoid *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLIGLOOINTERFACESGIXPROC) (GLenum pname, const GLvoid *params); -#endif - -#ifndef GL_EXT_texture_env_dot3 -#define GL_EXT_texture_env_dot3 1 -#endif - -#ifndef GL_ATI_texture_mirror_once -#define GL_ATI_texture_mirror_once 1 -#endif - -#ifndef GL_NV_fence -#define GL_NV_fence 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDeleteFencesNV (GLsizei n, const GLuint *fences); -GLAPI void APIENTRY glGenFencesNV (GLsizei n, GLuint *fences); -GLAPI GLboolean APIENTRY glIsFenceNV (GLuint fence); -GLAPI GLboolean APIENTRY glTestFenceNV (GLuint fence); -GLAPI void APIENTRY glGetFenceivNV (GLuint fence, GLenum pname, GLint *params); -GLAPI void APIENTRY glFinishFenceNV (GLuint fence); -GLAPI void APIENTRY glSetFenceNV (GLuint fence, GLenum condition); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences); -typedef void (APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences); -typedef GLboolean (APIENTRYP PFNGLISFENCENVPROC) (GLuint fence); -typedef GLboolean (APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence); -typedef void (APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence); -typedef void (APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition); -#endif - -#ifndef GL_NV_evaluators -#define GL_NV_evaluators 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const GLvoid *points); -GLAPI void APIENTRY glMapParameterivNV (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glMapParameterfvNV (GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glGetMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, GLvoid *points); -GLAPI void APIENTRY glGetMapParameterivNV (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetMapParameterfvNV (GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetMapAttribParameterivNV (GLenum target, GLuint index, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetMapAttribParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glEvalMapsNV (GLenum target, GLenum mode); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const GLvoid *points); -typedef void (APIENTRYP PFNGLMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLGETMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, GLvoid *points); -typedef void (APIENTRYP PFNGLGETMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERIVNVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLEVALMAPSNVPROC) (GLenum target, GLenum mode); -#endif - -#ifndef GL_NV_packed_depth_stencil -#define GL_NV_packed_depth_stencil 1 -#endif - -#ifndef GL_NV_register_combiners2 -#define GL_NV_register_combiners2 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glCombinerStageParameterfvNV (GLenum stage, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glGetCombinerStageParameterfvNV (GLenum stage, GLenum pname, GLfloat *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, GLfloat *params); -#endif - -#ifndef GL_NV_texture_compression_vtc -#define GL_NV_texture_compression_vtc 1 -#endif - -#ifndef GL_NV_texture_rectangle -#define GL_NV_texture_rectangle 1 -#endif - -#ifndef GL_NV_texture_shader -#define GL_NV_texture_shader 1 -#endif - -#ifndef GL_NV_texture_shader2 -#define GL_NV_texture_shader2 1 -#endif - -#ifndef GL_NV_vertex_array_range2 -#define GL_NV_vertex_array_range2 1 -#endif - -#ifndef GL_NV_vertex_program -#define GL_NV_vertex_program 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLboolean APIENTRY glAreProgramsResidentNV (GLsizei n, const GLuint *programs, GLboolean *residences); -GLAPI void APIENTRY glBindProgramNV (GLenum target, GLuint id); -GLAPI void APIENTRY glDeleteProgramsNV (GLsizei n, const GLuint *programs); -GLAPI void APIENTRY glExecuteProgramNV (GLenum target, GLuint id, const GLfloat *params); -GLAPI void APIENTRY glGenProgramsNV (GLsizei n, GLuint *programs); -GLAPI void APIENTRY glGetProgramParameterdvNV (GLenum target, GLuint index, GLenum pname, GLdouble *params); -GLAPI void APIENTRY glGetProgramParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetProgramivNV (GLuint id, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetProgramStringNV (GLuint id, GLenum pname, GLubyte *program); -GLAPI void APIENTRY glGetTrackMatrixivNV (GLenum target, GLuint address, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVertexAttribdvNV (GLuint index, GLenum pname, GLdouble *params); -GLAPI void APIENTRY glGetVertexAttribfvNV (GLuint index, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetVertexAttribivNV (GLuint index, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVertexAttribPointervNV (GLuint index, GLenum pname, GLvoid* *pointer); -GLAPI GLboolean APIENTRY glIsProgramNV (GLuint id); -GLAPI void APIENTRY glLoadProgramNV (GLenum target, GLuint id, GLsizei len, const GLubyte *program); -GLAPI void APIENTRY glProgramParameter4dNV (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glProgramParameter4dvNV (GLenum target, GLuint index, const GLdouble *v); -GLAPI void APIENTRY glProgramParameter4fNV (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glProgramParameter4fvNV (GLenum target, GLuint index, const GLfloat *v); -GLAPI void APIENTRY glProgramParameters4dvNV (GLenum target, GLuint index, GLsizei count, const GLdouble *v); -GLAPI void APIENTRY glProgramParameters4fvNV (GLenum target, GLuint index, GLsizei count, const GLfloat *v); -GLAPI void APIENTRY glRequestResidentProgramsNV (GLsizei n, const GLuint *programs); -GLAPI void APIENTRY glTrackMatrixNV (GLenum target, GLuint address, GLenum matrix, GLenum transform); -GLAPI void APIENTRY glVertexAttribPointerNV (GLuint index, GLint fsize, GLenum type, GLsizei stride, const GLvoid *pointer); -GLAPI void APIENTRY glVertexAttrib1dNV (GLuint index, GLdouble x); -GLAPI void APIENTRY glVertexAttrib1dvNV (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib1fNV (GLuint index, GLfloat x); -GLAPI void APIENTRY glVertexAttrib1fvNV (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib1sNV (GLuint index, GLshort x); -GLAPI void APIENTRY glVertexAttrib1svNV (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib2dNV (GLuint index, GLdouble x, GLdouble y); -GLAPI void APIENTRY glVertexAttrib2dvNV (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib2fNV (GLuint index, GLfloat x, GLfloat y); -GLAPI void APIENTRY glVertexAttrib2fvNV (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib2sNV (GLuint index, GLshort x, GLshort y); -GLAPI void APIENTRY glVertexAttrib2svNV (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib3dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glVertexAttrib3dvNV (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib3fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glVertexAttrib3fvNV (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib3sNV (GLuint index, GLshort x, GLshort y, GLshort z); -GLAPI void APIENTRY glVertexAttrib3svNV (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib4dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glVertexAttrib4dvNV (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttrib4fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glVertexAttrib4fvNV (GLuint index, const GLfloat *v); -GLAPI void APIENTRY glVertexAttrib4sNV (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); -GLAPI void APIENTRY glVertexAttrib4svNV (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttrib4ubNV (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); -GLAPI void APIENTRY glVertexAttrib4ubvNV (GLuint index, const GLubyte *v); -GLAPI void APIENTRY glVertexAttribs1dvNV (GLuint index, GLsizei count, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribs1fvNV (GLuint index, GLsizei count, const GLfloat *v); -GLAPI void APIENTRY glVertexAttribs1svNV (GLuint index, GLsizei count, const GLshort *v); -GLAPI void APIENTRY glVertexAttribs2dvNV (GLuint index, GLsizei count, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribs2fvNV (GLuint index, GLsizei count, const GLfloat *v); -GLAPI void APIENTRY glVertexAttribs2svNV (GLuint index, GLsizei count, const GLshort *v); -GLAPI void APIENTRY glVertexAttribs3dvNV (GLuint index, GLsizei count, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribs3fvNV (GLuint index, GLsizei count, const GLfloat *v); -GLAPI void APIENTRY glVertexAttribs3svNV (GLuint index, GLsizei count, const GLshort *v); -GLAPI void APIENTRY glVertexAttribs4dvNV (GLuint index, GLsizei count, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribs4fvNV (GLuint index, GLsizei count, const GLfloat *v); -GLAPI void APIENTRY glVertexAttribs4svNV (GLuint index, GLsizei count, const GLshort *v); -GLAPI void APIENTRY glVertexAttribs4ubvNV (GLuint index, GLsizei count, const GLubyte *v); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLboolean (APIENTRYP PFNGLAREPROGRAMSRESIDENTNVPROC) (GLsizei n, const GLuint *programs, GLboolean *residences); -typedef void (APIENTRYP PFNGLBINDPROGRAMNVPROC) (GLenum target, GLuint id); -typedef void (APIENTRYP PFNGLDELETEPROGRAMSNVPROC) (GLsizei n, const GLuint *programs); -typedef void (APIENTRYP PFNGLEXECUTEPROGRAMNVPROC) (GLenum target, GLuint id, const GLfloat *params); -typedef void (APIENTRYP PFNGLGENPROGRAMSNVPROC) (GLsizei n, GLuint *programs); -typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERDVNVPROC) (GLenum target, GLuint index, GLenum pname, GLdouble *params); -typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETPROGRAMIVNVPROC) (GLuint id, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGNVPROC) (GLuint id, GLenum pname, GLubyte *program); -typedef void (APIENTRYP PFNGLGETTRACKMATRIXIVNVPROC) (GLenum target, GLuint address, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVNVPROC) (GLuint index, GLenum pname, GLdouble *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVNVPROC) (GLuint index, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVNVPROC) (GLuint index, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVNVPROC) (GLuint index, GLenum pname, GLvoid* *pointer); -typedef GLboolean (APIENTRYP PFNGLISPROGRAMNVPROC) (GLuint id); -typedef void (APIENTRYP PFNGLLOADPROGRAMNVPROC) (GLenum target, GLuint id, GLsizei len, const GLubyte *program); -typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DNVPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DVNVPROC) (GLenum target, GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FNVPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FVNVPROC) (GLenum target, GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4DVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLdouble *v); -typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4FVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *v); -typedef void (APIENTRYP PFNGLREQUESTRESIDENTPROGRAMSNVPROC) (GLsizei n, const GLuint *programs); -typedef void (APIENTRYP PFNGLTRACKMATRIXNVPROC) (GLenum target, GLuint address, GLenum matrix, GLenum transform); -typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERNVPROC) (GLuint index, GLint fsize, GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1DNVPROC) (GLuint index, GLdouble x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVNVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1FNVPROC) (GLuint index, GLfloat x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVNVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1SNVPROC) (GLuint index, GLshort x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVNVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2DNVPROC) (GLuint index, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVNVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2FNVPROC) (GLuint index, GLfloat x, GLfloat y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVNVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2SNVPROC) (GLuint index, GLshort x, GLshort y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVNVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVNVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVNVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVNVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVNVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVNVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVNVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBNVPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVNVPROC) (GLuint index, const GLubyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS1DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS1FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS1SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS2DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS2FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS2SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS3DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS3FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS3SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS4DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS4FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS4SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS4UBVNVPROC) (GLuint index, GLsizei count, const GLubyte *v); -#endif - -#ifndef GL_SGIX_texture_coordinate_clamp -#define GL_SGIX_texture_coordinate_clamp 1 -#endif - -#ifndef GL_SGIX_scalebias_hint -#define GL_SGIX_scalebias_hint 1 -#endif - -#ifndef GL_OML_interlace -#define GL_OML_interlace 1 -#endif - -#ifndef GL_OML_subsample -#define GL_OML_subsample 1 -#endif - -#ifndef GL_OML_resample -#define GL_OML_resample 1 -#endif - -#ifndef GL_NV_copy_depth_to_color -#define GL_NV_copy_depth_to_color 1 -#endif - -#ifndef GL_ATI_envmap_bumpmap -#define GL_ATI_envmap_bumpmap 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexBumpParameterivATI (GLenum pname, const GLint *param); -GLAPI void APIENTRY glTexBumpParameterfvATI (GLenum pname, const GLfloat *param); -GLAPI void APIENTRY glGetTexBumpParameterivATI (GLenum pname, GLint *param); -GLAPI void APIENTRY glGetTexBumpParameterfvATI (GLenum pname, GLfloat *param); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERIVATIPROC) (GLenum pname, const GLint *param); -typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERFVATIPROC) (GLenum pname, const GLfloat *param); -typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERIVATIPROC) (GLenum pname, GLint *param); -typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERFVATIPROC) (GLenum pname, GLfloat *param); -#endif - -#ifndef GL_ATI_fragment_shader -#define GL_ATI_fragment_shader 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLuint APIENTRY glGenFragmentShadersATI (GLuint range); -GLAPI void APIENTRY glBindFragmentShaderATI (GLuint id); -GLAPI void APIENTRY glDeleteFragmentShaderATI (GLuint id); -GLAPI void APIENTRY glBeginFragmentShaderATI (void); -GLAPI void APIENTRY glEndFragmentShaderATI (void); -GLAPI void APIENTRY glPassTexCoordATI (GLuint dst, GLuint coord, GLenum swizzle); -GLAPI void APIENTRY glSampleMapATI (GLuint dst, GLuint interp, GLenum swizzle); -GLAPI void APIENTRY glColorFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); -GLAPI void APIENTRY glColorFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); -GLAPI void APIENTRY glColorFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); -GLAPI void APIENTRY glAlphaFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); -GLAPI void APIENTRY glAlphaFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); -GLAPI void APIENTRY glAlphaFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); -GLAPI void APIENTRY glSetFragmentShaderConstantATI (GLuint dst, const GLfloat *value); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLuint (APIENTRYP PFNGLGENFRAGMENTSHADERSATIPROC) (GLuint range); -typedef void (APIENTRYP PFNGLBINDFRAGMENTSHADERATIPROC) (GLuint id); -typedef void (APIENTRYP PFNGLDELETEFRAGMENTSHADERATIPROC) (GLuint id); -typedef void (APIENTRYP PFNGLBEGINFRAGMENTSHADERATIPROC) (void); -typedef void (APIENTRYP PFNGLENDFRAGMENTSHADERATIPROC) (void); -typedef void (APIENTRYP PFNGLPASSTEXCOORDATIPROC) (GLuint dst, GLuint coord, GLenum swizzle); -typedef void (APIENTRYP PFNGLSAMPLEMAPATIPROC) (GLuint dst, GLuint interp, GLenum swizzle); -typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); -typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); -typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); -typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); -typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); -typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); -typedef void (APIENTRYP PFNGLSETFRAGMENTSHADERCONSTANTATIPROC) (GLuint dst, const GLfloat *value); -#endif - -#ifndef GL_ATI_pn_triangles -#define GL_ATI_pn_triangles 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPNTrianglesiATI (GLenum pname, GLint param); -GLAPI void APIENTRY glPNTrianglesfATI (GLenum pname, GLfloat param); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPNTRIANGLESIATIPROC) (GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLPNTRIANGLESFATIPROC) (GLenum pname, GLfloat param); -#endif - -#ifndef GL_ATI_vertex_array_object -#define GL_ATI_vertex_array_object 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLuint APIENTRY glNewObjectBufferATI (GLsizei size, const GLvoid *pointer, GLenum usage); -GLAPI GLboolean APIENTRY glIsObjectBufferATI (GLuint buffer); -GLAPI void APIENTRY glUpdateObjectBufferATI (GLuint buffer, GLuint offset, GLsizei size, const GLvoid *pointer, GLenum preserve); -GLAPI void APIENTRY glGetObjectBufferfvATI (GLuint buffer, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetObjectBufferivATI (GLuint buffer, GLenum pname, GLint *params); -GLAPI void APIENTRY glFreeObjectBufferATI (GLuint buffer); -GLAPI void APIENTRY glArrayObjectATI (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); -GLAPI void APIENTRY glGetArrayObjectfvATI (GLenum array, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetArrayObjectivATI (GLenum array, GLenum pname, GLint *params); -GLAPI void APIENTRY glVariantArrayObjectATI (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); -GLAPI void APIENTRY glGetVariantArrayObjectfvATI (GLuint id, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetVariantArrayObjectivATI (GLuint id, GLenum pname, GLint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLuint (APIENTRYP PFNGLNEWOBJECTBUFFERATIPROC) (GLsizei size, const GLvoid *pointer, GLenum usage); -typedef GLboolean (APIENTRYP PFNGLISOBJECTBUFFERATIPROC) (GLuint buffer); -typedef void (APIENTRYP PFNGLUPDATEOBJECTBUFFERATIPROC) (GLuint buffer, GLuint offset, GLsizei size, const GLvoid *pointer, GLenum preserve); -typedef void (APIENTRYP PFNGLGETOBJECTBUFFERFVATIPROC) (GLuint buffer, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETOBJECTBUFFERIVATIPROC) (GLuint buffer, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLFREEOBJECTBUFFERATIPROC) (GLuint buffer); -typedef void (APIENTRYP PFNGLARRAYOBJECTATIPROC) (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); -typedef void (APIENTRYP PFNGLGETARRAYOBJECTFVATIPROC) (GLenum array, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETARRAYOBJECTIVATIPROC) (GLenum array, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLVARIANTARRAYOBJECTATIPROC) (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); -typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTFVATIPROC) (GLuint id, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTIVATIPROC) (GLuint id, GLenum pname, GLint *params); -#endif - -#ifndef GL_EXT_vertex_shader -#define GL_EXT_vertex_shader 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBeginVertexShaderEXT (void); -GLAPI void APIENTRY glEndVertexShaderEXT (void); -GLAPI void APIENTRY glBindVertexShaderEXT (GLuint id); -GLAPI GLuint APIENTRY glGenVertexShadersEXT (GLuint range); -GLAPI void APIENTRY glDeleteVertexShaderEXT (GLuint id); -GLAPI void APIENTRY glShaderOp1EXT (GLenum op, GLuint res, GLuint arg1); -GLAPI void APIENTRY glShaderOp2EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2); -GLAPI void APIENTRY glShaderOp3EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3); -GLAPI void APIENTRY glSwizzleEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); -GLAPI void APIENTRY glWriteMaskEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); -GLAPI void APIENTRY glInsertComponentEXT (GLuint res, GLuint src, GLuint num); -GLAPI void APIENTRY glExtractComponentEXT (GLuint res, GLuint src, GLuint num); -GLAPI GLuint APIENTRY glGenSymbolsEXT (GLenum datatype, GLenum storagetype, GLenum range, GLuint components); -GLAPI void APIENTRY glSetInvariantEXT (GLuint id, GLenum type, const GLvoid *addr); -GLAPI void APIENTRY glSetLocalConstantEXT (GLuint id, GLenum type, const GLvoid *addr); -GLAPI void APIENTRY glVariantbvEXT (GLuint id, const GLbyte *addr); -GLAPI void APIENTRY glVariantsvEXT (GLuint id, const GLshort *addr); -GLAPI void APIENTRY glVariantivEXT (GLuint id, const GLint *addr); -GLAPI void APIENTRY glVariantfvEXT (GLuint id, const GLfloat *addr); -GLAPI void APIENTRY glVariantdvEXT (GLuint id, const GLdouble *addr); -GLAPI void APIENTRY glVariantubvEXT (GLuint id, const GLubyte *addr); -GLAPI void APIENTRY glVariantusvEXT (GLuint id, const GLushort *addr); -GLAPI void APIENTRY glVariantuivEXT (GLuint id, const GLuint *addr); -GLAPI void APIENTRY glVariantPointerEXT (GLuint id, GLenum type, GLuint stride, const GLvoid *addr); -GLAPI void APIENTRY glEnableVariantClientStateEXT (GLuint id); -GLAPI void APIENTRY glDisableVariantClientStateEXT (GLuint id); -GLAPI GLuint APIENTRY glBindLightParameterEXT (GLenum light, GLenum value); -GLAPI GLuint APIENTRY glBindMaterialParameterEXT (GLenum face, GLenum value); -GLAPI GLuint APIENTRY glBindTexGenParameterEXT (GLenum unit, GLenum coord, GLenum value); -GLAPI GLuint APIENTRY glBindTextureUnitParameterEXT (GLenum unit, GLenum value); -GLAPI GLuint APIENTRY glBindParameterEXT (GLenum value); -GLAPI GLboolean APIENTRY glIsVariantEnabledEXT (GLuint id, GLenum cap); -GLAPI void APIENTRY glGetVariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data); -GLAPI void APIENTRY glGetVariantIntegervEXT (GLuint id, GLenum value, GLint *data); -GLAPI void APIENTRY glGetVariantFloatvEXT (GLuint id, GLenum value, GLfloat *data); -GLAPI void APIENTRY glGetVariantPointervEXT (GLuint id, GLenum value, GLvoid* *data); -GLAPI void APIENTRY glGetInvariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data); -GLAPI void APIENTRY glGetInvariantIntegervEXT (GLuint id, GLenum value, GLint *data); -GLAPI void APIENTRY glGetInvariantFloatvEXT (GLuint id, GLenum value, GLfloat *data); -GLAPI void APIENTRY glGetLocalConstantBooleanvEXT (GLuint id, GLenum value, GLboolean *data); -GLAPI void APIENTRY glGetLocalConstantIntegervEXT (GLuint id, GLenum value, GLint *data); -GLAPI void APIENTRY glGetLocalConstantFloatvEXT (GLuint id, GLenum value, GLfloat *data); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBEGINVERTEXSHADEREXTPROC) (void); -typedef void (APIENTRYP PFNGLENDVERTEXSHADEREXTPROC) (void); -typedef void (APIENTRYP PFNGLBINDVERTEXSHADEREXTPROC) (GLuint id); -typedef GLuint (APIENTRYP PFNGLGENVERTEXSHADERSEXTPROC) (GLuint range); -typedef void (APIENTRYP PFNGLDELETEVERTEXSHADEREXTPROC) (GLuint id); -typedef void (APIENTRYP PFNGLSHADEROP1EXTPROC) (GLenum op, GLuint res, GLuint arg1); -typedef void (APIENTRYP PFNGLSHADEROP2EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2); -typedef void (APIENTRYP PFNGLSHADEROP3EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3); -typedef void (APIENTRYP PFNGLSWIZZLEEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); -typedef void (APIENTRYP PFNGLWRITEMASKEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); -typedef void (APIENTRYP PFNGLINSERTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num); -typedef void (APIENTRYP PFNGLEXTRACTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num); -typedef GLuint (APIENTRYP PFNGLGENSYMBOLSEXTPROC) (GLenum datatype, GLenum storagetype, GLenum range, GLuint components); -typedef void (APIENTRYP PFNGLSETINVARIANTEXTPROC) (GLuint id, GLenum type, const GLvoid *addr); -typedef void (APIENTRYP PFNGLSETLOCALCONSTANTEXTPROC) (GLuint id, GLenum type, const GLvoid *addr); -typedef void (APIENTRYP PFNGLVARIANTBVEXTPROC) (GLuint id, const GLbyte *addr); -typedef void (APIENTRYP PFNGLVARIANTSVEXTPROC) (GLuint id, const GLshort *addr); -typedef void (APIENTRYP PFNGLVARIANTIVEXTPROC) (GLuint id, const GLint *addr); -typedef void (APIENTRYP PFNGLVARIANTFVEXTPROC) (GLuint id, const GLfloat *addr); -typedef void (APIENTRYP PFNGLVARIANTDVEXTPROC) (GLuint id, const GLdouble *addr); -typedef void (APIENTRYP PFNGLVARIANTUBVEXTPROC) (GLuint id, const GLubyte *addr); -typedef void (APIENTRYP PFNGLVARIANTUSVEXTPROC) (GLuint id, const GLushort *addr); -typedef void (APIENTRYP PFNGLVARIANTUIVEXTPROC) (GLuint id, const GLuint *addr); -typedef void (APIENTRYP PFNGLVARIANTPOINTEREXTPROC) (GLuint id, GLenum type, GLuint stride, const GLvoid *addr); -typedef void (APIENTRYP PFNGLENABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id); -typedef void (APIENTRYP PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id); -typedef GLuint (APIENTRYP PFNGLBINDLIGHTPARAMETEREXTPROC) (GLenum light, GLenum value); -typedef GLuint (APIENTRYP PFNGLBINDMATERIALPARAMETEREXTPROC) (GLenum face, GLenum value); -typedef GLuint (APIENTRYP PFNGLBINDTEXGENPARAMETEREXTPROC) (GLenum unit, GLenum coord, GLenum value); -typedef GLuint (APIENTRYP PFNGLBINDTEXTUREUNITPARAMETEREXTPROC) (GLenum unit, GLenum value); -typedef GLuint (APIENTRYP PFNGLBINDPARAMETEREXTPROC) (GLenum value); -typedef GLboolean (APIENTRYP PFNGLISVARIANTENABLEDEXTPROC) (GLuint id, GLenum cap); -typedef void (APIENTRYP PFNGLGETVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); -typedef void (APIENTRYP PFNGLGETVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); -typedef void (APIENTRYP PFNGLGETVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); -typedef void (APIENTRYP PFNGLGETVARIANTPOINTERVEXTPROC) (GLuint id, GLenum value, GLvoid* *data); -typedef void (APIENTRYP PFNGLGETINVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); -typedef void (APIENTRYP PFNGLGETINVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); -typedef void (APIENTRYP PFNGLGETINVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); -typedef void (APIENTRYP PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); -typedef void (APIENTRYP PFNGLGETLOCALCONSTANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); -typedef void (APIENTRYP PFNGLGETLOCALCONSTANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); -#endif - -#ifndef GL_ATI_vertex_streams -#define GL_ATI_vertex_streams 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexStream1sATI (GLenum stream, GLshort x); -GLAPI void APIENTRY glVertexStream1svATI (GLenum stream, const GLshort *coords); -GLAPI void APIENTRY glVertexStream1iATI (GLenum stream, GLint x); -GLAPI void APIENTRY glVertexStream1ivATI (GLenum stream, const GLint *coords); -GLAPI void APIENTRY glVertexStream1fATI (GLenum stream, GLfloat x); -GLAPI void APIENTRY glVertexStream1fvATI (GLenum stream, const GLfloat *coords); -GLAPI void APIENTRY glVertexStream1dATI (GLenum stream, GLdouble x); -GLAPI void APIENTRY glVertexStream1dvATI (GLenum stream, const GLdouble *coords); -GLAPI void APIENTRY glVertexStream2sATI (GLenum stream, GLshort x, GLshort y); -GLAPI void APIENTRY glVertexStream2svATI (GLenum stream, const GLshort *coords); -GLAPI void APIENTRY glVertexStream2iATI (GLenum stream, GLint x, GLint y); -GLAPI void APIENTRY glVertexStream2ivATI (GLenum stream, const GLint *coords); -GLAPI void APIENTRY glVertexStream2fATI (GLenum stream, GLfloat x, GLfloat y); -GLAPI void APIENTRY glVertexStream2fvATI (GLenum stream, const GLfloat *coords); -GLAPI void APIENTRY glVertexStream2dATI (GLenum stream, GLdouble x, GLdouble y); -GLAPI void APIENTRY glVertexStream2dvATI (GLenum stream, const GLdouble *coords); -GLAPI void APIENTRY glVertexStream3sATI (GLenum stream, GLshort x, GLshort y, GLshort z); -GLAPI void APIENTRY glVertexStream3svATI (GLenum stream, const GLshort *coords); -GLAPI void APIENTRY glVertexStream3iATI (GLenum stream, GLint x, GLint y, GLint z); -GLAPI void APIENTRY glVertexStream3ivATI (GLenum stream, const GLint *coords); -GLAPI void APIENTRY glVertexStream3fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glVertexStream3fvATI (GLenum stream, const GLfloat *coords); -GLAPI void APIENTRY glVertexStream3dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glVertexStream3dvATI (GLenum stream, const GLdouble *coords); -GLAPI void APIENTRY glVertexStream4sATI (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w); -GLAPI void APIENTRY glVertexStream4svATI (GLenum stream, const GLshort *coords); -GLAPI void APIENTRY glVertexStream4iATI (GLenum stream, GLint x, GLint y, GLint z, GLint w); -GLAPI void APIENTRY glVertexStream4ivATI (GLenum stream, const GLint *coords); -GLAPI void APIENTRY glVertexStream4fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glVertexStream4fvATI (GLenum stream, const GLfloat *coords); -GLAPI void APIENTRY glVertexStream4dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glVertexStream4dvATI (GLenum stream, const GLdouble *coords); -GLAPI void APIENTRY glNormalStream3bATI (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz); -GLAPI void APIENTRY glNormalStream3bvATI (GLenum stream, const GLbyte *coords); -GLAPI void APIENTRY glNormalStream3sATI (GLenum stream, GLshort nx, GLshort ny, GLshort nz); -GLAPI void APIENTRY glNormalStream3svATI (GLenum stream, const GLshort *coords); -GLAPI void APIENTRY glNormalStream3iATI (GLenum stream, GLint nx, GLint ny, GLint nz); -GLAPI void APIENTRY glNormalStream3ivATI (GLenum stream, const GLint *coords); -GLAPI void APIENTRY glNormalStream3fATI (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz); -GLAPI void APIENTRY glNormalStream3fvATI (GLenum stream, const GLfloat *coords); -GLAPI void APIENTRY glNormalStream3dATI (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz); -GLAPI void APIENTRY glNormalStream3dvATI (GLenum stream, const GLdouble *coords); -GLAPI void APIENTRY glClientActiveVertexStreamATI (GLenum stream); -GLAPI void APIENTRY glVertexBlendEnviATI (GLenum pname, GLint param); -GLAPI void APIENTRY glVertexBlendEnvfATI (GLenum pname, GLfloat param); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVERTEXSTREAM1SATIPROC) (GLenum stream, GLshort x); -typedef void (APIENTRYP PFNGLVERTEXSTREAM1SVATIPROC) (GLenum stream, const GLshort *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM1IATIPROC) (GLenum stream, GLint x); -typedef void (APIENTRYP PFNGLVERTEXSTREAM1IVATIPROC) (GLenum stream, const GLint *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM1FATIPROC) (GLenum stream, GLfloat x); -typedef void (APIENTRYP PFNGLVERTEXSTREAM1FVATIPROC) (GLenum stream, const GLfloat *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM1DATIPROC) (GLenum stream, GLdouble x); -typedef void (APIENTRYP PFNGLVERTEXSTREAM1DVATIPROC) (GLenum stream, const GLdouble *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM2SATIPROC) (GLenum stream, GLshort x, GLshort y); -typedef void (APIENTRYP PFNGLVERTEXSTREAM2SVATIPROC) (GLenum stream, const GLshort *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM2IATIPROC) (GLenum stream, GLint x, GLint y); -typedef void (APIENTRYP PFNGLVERTEXSTREAM2IVATIPROC) (GLenum stream, const GLint *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM2FATIPROC) (GLenum stream, GLfloat x, GLfloat y); -typedef void (APIENTRYP PFNGLVERTEXSTREAM2FVATIPROC) (GLenum stream, const GLfloat *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM2DATIPROC) (GLenum stream, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLVERTEXSTREAM2DVATIPROC) (GLenum stream, const GLdouble *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM3SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z); -typedef void (APIENTRYP PFNGLVERTEXSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM3IATIPROC) (GLenum stream, GLint x, GLint y, GLint z); -typedef void (APIENTRYP PFNGLVERTEXSTREAM3IVATIPROC) (GLenum stream, const GLint *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM3FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLVERTEXSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM3DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLVERTEXSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM4SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w); -typedef void (APIENTRYP PFNGLVERTEXSTREAM4SVATIPROC) (GLenum stream, const GLshort *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM4IATIPROC) (GLenum stream, GLint x, GLint y, GLint z, GLint w); -typedef void (APIENTRYP PFNGLVERTEXSTREAM4IVATIPROC) (GLenum stream, const GLint *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM4FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLVERTEXSTREAM4FVATIPROC) (GLenum stream, const GLfloat *coords); -typedef void (APIENTRYP PFNGLVERTEXSTREAM4DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLVERTEXSTREAM4DVATIPROC) (GLenum stream, const GLdouble *coords); -typedef void (APIENTRYP PFNGLNORMALSTREAM3BATIPROC) (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz); -typedef void (APIENTRYP PFNGLNORMALSTREAM3BVATIPROC) (GLenum stream, const GLbyte *coords); -typedef void (APIENTRYP PFNGLNORMALSTREAM3SATIPROC) (GLenum stream, GLshort nx, GLshort ny, GLshort nz); -typedef void (APIENTRYP PFNGLNORMALSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords); -typedef void (APIENTRYP PFNGLNORMALSTREAM3IATIPROC) (GLenum stream, GLint nx, GLint ny, GLint nz); -typedef void (APIENTRYP PFNGLNORMALSTREAM3IVATIPROC) (GLenum stream, const GLint *coords); -typedef void (APIENTRYP PFNGLNORMALSTREAM3FATIPROC) (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz); -typedef void (APIENTRYP PFNGLNORMALSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords); -typedef void (APIENTRYP PFNGLNORMALSTREAM3DATIPROC) (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz); -typedef void (APIENTRYP PFNGLNORMALSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords); -typedef void (APIENTRYP PFNGLCLIENTACTIVEVERTEXSTREAMATIPROC) (GLenum stream); -typedef void (APIENTRYP PFNGLVERTEXBLENDENVIATIPROC) (GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLVERTEXBLENDENVFATIPROC) (GLenum pname, GLfloat param); -#endif - -#ifndef GL_ATI_element_array -#define GL_ATI_element_array 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glElementPointerATI (GLenum type, const GLvoid *pointer); -GLAPI void APIENTRY glDrawElementArrayATI (GLenum mode, GLsizei count); -GLAPI void APIENTRY glDrawRangeElementArrayATI (GLenum mode, GLuint start, GLuint end, GLsizei count); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLELEMENTPOINTERATIPROC) (GLenum type, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYATIPROC) (GLenum mode, GLsizei count); -typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYATIPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count); -#endif - -#ifndef GL_SUN_mesh_array -#define GL_SUN_mesh_array 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawMeshArraysSUN (GLenum mode, GLint first, GLsizei count, GLsizei width); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDRAWMESHARRAYSSUNPROC) (GLenum mode, GLint first, GLsizei count, GLsizei width); -#endif - -#ifndef GL_SUN_slice_accum -#define GL_SUN_slice_accum 1 -#endif - -#ifndef GL_NV_multisample_filter_hint -#define GL_NV_multisample_filter_hint 1 -#endif - -#ifndef GL_NV_depth_clamp -#define GL_NV_depth_clamp 1 -#endif - -#ifndef GL_NV_occlusion_query -#define GL_NV_occlusion_query 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGenOcclusionQueriesNV (GLsizei n, GLuint *ids); -GLAPI void APIENTRY glDeleteOcclusionQueriesNV (GLsizei n, const GLuint *ids); -GLAPI GLboolean APIENTRY glIsOcclusionQueryNV (GLuint id); -GLAPI void APIENTRY glBeginOcclusionQueryNV (GLuint id); -GLAPI void APIENTRY glEndOcclusionQueryNV (void); -GLAPI void APIENTRY glGetOcclusionQueryivNV (GLuint id, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetOcclusionQueryuivNV (GLuint id, GLenum pname, GLuint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGENOCCLUSIONQUERIESNVPROC) (GLsizei n, GLuint *ids); -typedef void (APIENTRYP PFNGLDELETEOCCLUSIONQUERIESNVPROC) (GLsizei n, const GLuint *ids); -typedef GLboolean (APIENTRYP PFNGLISOCCLUSIONQUERYNVPROC) (GLuint id); -typedef void (APIENTRYP PFNGLBEGINOCCLUSIONQUERYNVPROC) (GLuint id); -typedef void (APIENTRYP PFNGLENDOCCLUSIONQUERYNVPROC) (void); -typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYIVNVPROC) (GLuint id, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYUIVNVPROC) (GLuint id, GLenum pname, GLuint *params); -#endif - -#ifndef GL_NV_point_sprite -#define GL_NV_point_sprite 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPointParameteriNV (GLenum pname, GLint param); -GLAPI void APIENTRY glPointParameterivNV (GLenum pname, const GLint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPOINTPARAMETERINVPROC) (GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLPOINTPARAMETERIVNVPROC) (GLenum pname, const GLint *params); -#endif - -#ifndef GL_NV_texture_shader3 -#define GL_NV_texture_shader3 1 -#endif - -#ifndef GL_NV_vertex_program1_1 -#define GL_NV_vertex_program1_1 1 -#endif - -#ifndef GL_EXT_shadow_funcs -#define GL_EXT_shadow_funcs 1 -#endif - -#ifndef GL_EXT_stencil_two_side -#define GL_EXT_stencil_two_side 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glActiveStencilFaceEXT (GLenum face); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face); -#endif - -#ifndef GL_ATI_text_fragment_shader -#define GL_ATI_text_fragment_shader 1 -#endif - -#ifndef GL_APPLE_client_storage -#define GL_APPLE_client_storage 1 -#endif - -#ifndef GL_APPLE_element_array -#define GL_APPLE_element_array 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glElementPointerAPPLE (GLenum type, const GLvoid *pointer); -GLAPI void APIENTRY glDrawElementArrayAPPLE (GLenum mode, GLint first, GLsizei count); -GLAPI void APIENTRY glDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count); -GLAPI void APIENTRY glMultiDrawElementArrayAPPLE (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); -GLAPI void APIENTRY glMultiDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLELEMENTPOINTERAPPLEPROC) (GLenum type, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, GLint first, GLsizei count); -typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); -typedef void (APIENTRYP PFNGLMULTIDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount); -#endif - -#ifndef GL_APPLE_fence -#define GL_APPLE_fence 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGenFencesAPPLE (GLsizei n, GLuint *fences); -GLAPI void APIENTRY glDeleteFencesAPPLE (GLsizei n, const GLuint *fences); -GLAPI void APIENTRY glSetFenceAPPLE (GLuint fence); -GLAPI GLboolean APIENTRY glIsFenceAPPLE (GLuint fence); -GLAPI GLboolean APIENTRY glTestFenceAPPLE (GLuint fence); -GLAPI void APIENTRY glFinishFenceAPPLE (GLuint fence); -GLAPI GLboolean APIENTRY glTestObjectAPPLE (GLenum object, GLuint name); -GLAPI void APIENTRY glFinishObjectAPPLE (GLenum object, GLint name); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGENFENCESAPPLEPROC) (GLsizei n, GLuint *fences); -typedef void (APIENTRYP PFNGLDELETEFENCESAPPLEPROC) (GLsizei n, const GLuint *fences); -typedef void (APIENTRYP PFNGLSETFENCEAPPLEPROC) (GLuint fence); -typedef GLboolean (APIENTRYP PFNGLISFENCEAPPLEPROC) (GLuint fence); -typedef GLboolean (APIENTRYP PFNGLTESTFENCEAPPLEPROC) (GLuint fence); -typedef void (APIENTRYP PFNGLFINISHFENCEAPPLEPROC) (GLuint fence); -typedef GLboolean (APIENTRYP PFNGLTESTOBJECTAPPLEPROC) (GLenum object, GLuint name); -typedef void (APIENTRYP PFNGLFINISHOBJECTAPPLEPROC) (GLenum object, GLint name); -#endif - -#ifndef GL_APPLE_vertex_array_object -#define GL_APPLE_vertex_array_object 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBindVertexArrayAPPLE (GLuint array); -GLAPI void APIENTRY glDeleteVertexArraysAPPLE (GLsizei n, const GLuint *arrays); -GLAPI void APIENTRY glGenVertexArraysAPPLE (GLsizei n, GLuint *arrays); -GLAPI GLboolean APIENTRY glIsVertexArrayAPPLE (GLuint array); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBINDVERTEXARRAYAPPLEPROC) (GLuint array); -typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSAPPLEPROC) (GLsizei n, const GLuint *arrays); -typedef void (APIENTRYP PFNGLGENVERTEXARRAYSAPPLEPROC) (GLsizei n, GLuint *arrays); -typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYAPPLEPROC) (GLuint array); -#endif - -#ifndef GL_APPLE_vertex_array_range -#define GL_APPLE_vertex_array_range 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexArrayRangeAPPLE (GLsizei length, GLvoid *pointer); -GLAPI void APIENTRY glFlushVertexArrayRangeAPPLE (GLsizei length, GLvoid *pointer); -GLAPI void APIENTRY glVertexArrayParameteriAPPLE (GLenum pname, GLint param); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer); -typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer); -typedef void (APIENTRYP PFNGLVERTEXARRAYPARAMETERIAPPLEPROC) (GLenum pname, GLint param); -#endif - -#ifndef GL_APPLE_ycbcr_422 -#define GL_APPLE_ycbcr_422 1 -#endif - -#ifndef GL_S3_s3tc -#define GL_S3_s3tc 1 -#endif - -#ifndef GL_ATI_draw_buffers -#define GL_ATI_draw_buffers 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawBuffersATI (GLsizei n, const GLenum *bufs); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDRAWBUFFERSATIPROC) (GLsizei n, const GLenum *bufs); -#endif - -#ifndef GL_ATI_pixel_format_float -#define GL_ATI_pixel_format_float 1 -/* This is really a WGL extension, but defines some associated GL enums. - * ATI does not export "GL_ATI_pixel_format_float" in the GL_EXTENSIONS string. - */ -#endif - -#ifndef GL_ATI_texture_env_combine3 -#define GL_ATI_texture_env_combine3 1 -#endif - -#ifndef GL_ATI_texture_float -#define GL_ATI_texture_float 1 -#endif - -#ifndef GL_NV_float_buffer -#define GL_NV_float_buffer 1 -#endif - -#ifndef GL_NV_fragment_program -#define GL_NV_fragment_program 1 -/* Some NV_fragment_program entry points are shared with ARB_vertex_program. */ -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProgramNamedParameter4fNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glProgramNamedParameter4dNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glProgramNamedParameter4fvNV (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v); -GLAPI void APIENTRY glProgramNamedParameter4dvNV (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v); -GLAPI void APIENTRY glGetProgramNamedParameterfvNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params); -GLAPI void APIENTRY glGetProgramNamedParameterdvNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v); -typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v); -typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERFVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params); -typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERDVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params); -#endif - -#ifndef GL_NV_half_float -#define GL_NV_half_float 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertex2hNV (GLhalfNV x, GLhalfNV y); -GLAPI void APIENTRY glVertex2hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glVertex3hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z); -GLAPI void APIENTRY glVertex3hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glVertex4hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); -GLAPI void APIENTRY glVertex4hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glNormal3hNV (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz); -GLAPI void APIENTRY glNormal3hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue); -GLAPI void APIENTRY glColor3hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glColor4hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha); -GLAPI void APIENTRY glColor4hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glTexCoord1hNV (GLhalfNV s); -GLAPI void APIENTRY glTexCoord1hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glTexCoord2hNV (GLhalfNV s, GLhalfNV t); -GLAPI void APIENTRY glTexCoord2hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glTexCoord3hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r); -GLAPI void APIENTRY glTexCoord3hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glTexCoord4hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); -GLAPI void APIENTRY glTexCoord4hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glMultiTexCoord1hNV (GLenum target, GLhalfNV s); -GLAPI void APIENTRY glMultiTexCoord1hvNV (GLenum target, const GLhalfNV *v); -GLAPI void APIENTRY glMultiTexCoord2hNV (GLenum target, GLhalfNV s, GLhalfNV t); -GLAPI void APIENTRY glMultiTexCoord2hvNV (GLenum target, const GLhalfNV *v); -GLAPI void APIENTRY glMultiTexCoord3hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r); -GLAPI void APIENTRY glMultiTexCoord3hvNV (GLenum target, const GLhalfNV *v); -GLAPI void APIENTRY glMultiTexCoord4hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); -GLAPI void APIENTRY glMultiTexCoord4hvNV (GLenum target, const GLhalfNV *v); -GLAPI void APIENTRY glFogCoordhNV (GLhalfNV fog); -GLAPI void APIENTRY glFogCoordhvNV (const GLhalfNV *fog); -GLAPI void APIENTRY glSecondaryColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue); -GLAPI void APIENTRY glSecondaryColor3hvNV (const GLhalfNV *v); -GLAPI void APIENTRY glVertexWeighthNV (GLhalfNV weight); -GLAPI void APIENTRY glVertexWeighthvNV (const GLhalfNV *weight); -GLAPI void APIENTRY glVertexAttrib1hNV (GLuint index, GLhalfNV x); -GLAPI void APIENTRY glVertexAttrib1hvNV (GLuint index, const GLhalfNV *v); -GLAPI void APIENTRY glVertexAttrib2hNV (GLuint index, GLhalfNV x, GLhalfNV y); -GLAPI void APIENTRY glVertexAttrib2hvNV (GLuint index, const GLhalfNV *v); -GLAPI void APIENTRY glVertexAttrib3hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z); -GLAPI void APIENTRY glVertexAttrib3hvNV (GLuint index, const GLhalfNV *v); -GLAPI void APIENTRY glVertexAttrib4hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); -GLAPI void APIENTRY glVertexAttrib4hvNV (GLuint index, const GLhalfNV *v); -GLAPI void APIENTRY glVertexAttribs1hvNV (GLuint index, GLsizei n, const GLhalfNV *v); -GLAPI void APIENTRY glVertexAttribs2hvNV (GLuint index, GLsizei n, const GLhalfNV *v); -GLAPI void APIENTRY glVertexAttribs3hvNV (GLuint index, GLsizei n, const GLhalfNV *v); -GLAPI void APIENTRY glVertexAttribs4hvNV (GLuint index, GLsizei n, const GLhalfNV *v); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVERTEX2HNVPROC) (GLhalfNV x, GLhalfNV y); -typedef void (APIENTRYP PFNGLVERTEX2HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEX3HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z); -typedef void (APIENTRYP PFNGLVERTEX3HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEX4HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); -typedef void (APIENTRYP PFNGLVERTEX4HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLNORMAL3HNVPROC) (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz); -typedef void (APIENTRYP PFNGLNORMAL3HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); -typedef void (APIENTRYP PFNGLCOLOR3HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLCOLOR4HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha); -typedef void (APIENTRYP PFNGLCOLOR4HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLTEXCOORD1HNVPROC) (GLhalfNV s); -typedef void (APIENTRYP PFNGLTEXCOORD1HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLTEXCOORD2HNVPROC) (GLhalfNV s, GLhalfNV t); -typedef void (APIENTRYP PFNGLTEXCOORD2HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLTEXCOORD3HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r); -typedef void (APIENTRYP PFNGLTEXCOORD3HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLTEXCOORD4HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); -typedef void (APIENTRYP PFNGLTEXCOORD4HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1HNVPROC) (GLenum target, GLhalfNV s); -typedef void (APIENTRYP PFNGLMULTITEXCOORD1HVNVPROC) (GLenum target, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t); -typedef void (APIENTRYP PFNGLMULTITEXCOORD2HVNVPROC) (GLenum target, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r); -typedef void (APIENTRYP PFNGLMULTITEXCOORD3HVNVPROC) (GLenum target, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); -typedef void (APIENTRYP PFNGLMULTITEXCOORD4HVNVPROC) (GLenum target, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLFOGCOORDHNVPROC) (GLhalfNV fog); -typedef void (APIENTRYP PFNGLFOGCOORDHVNVPROC) (const GLhalfNV *fog); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); -typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HVNVPROC) (const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEXWEIGHTHNVPROC) (GLhalfNV weight); -typedef void (APIENTRYP PFNGLVERTEXWEIGHTHVNVPROC) (const GLhalfNV *weight); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1HNVPROC) (GLuint index, GLhalfNV x); -typedef void (APIENTRYP PFNGLVERTEXATTRIB1HVNVPROC) (GLuint index, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y); -typedef void (APIENTRYP PFNGLVERTEXATTRIB2HVNVPROC) (GLuint index, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z); -typedef void (APIENTRYP PFNGLVERTEXATTRIB3HVNVPROC) (GLuint index, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); -typedef void (APIENTRYP PFNGLVERTEXATTRIB4HVNVPROC) (GLuint index, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS1HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS2HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS3HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBS4HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); -#endif - -#ifndef GL_NV_pixel_data_range -#define GL_NV_pixel_data_range 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPixelDataRangeNV (GLenum target, GLsizei length, GLvoid *pointer); -GLAPI void APIENTRY glFlushPixelDataRangeNV (GLenum target); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPIXELDATARANGENVPROC) (GLenum target, GLsizei length, GLvoid *pointer); -typedef void (APIENTRYP PFNGLFLUSHPIXELDATARANGENVPROC) (GLenum target); -#endif - -#ifndef GL_NV_primitive_restart -#define GL_NV_primitive_restart 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPrimitiveRestartNV (void); -GLAPI void APIENTRY glPrimitiveRestartIndexNV (GLuint index); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPRIMITIVERESTARTNVPROC) (void); -typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXNVPROC) (GLuint index); -#endif - -#ifndef GL_NV_texture_expand_normal -#define GL_NV_texture_expand_normal 1 -#endif - -#ifndef GL_NV_vertex_program2 -#define GL_NV_vertex_program2 1 -#endif - -#ifndef GL_ATI_map_object_buffer -#define GL_ATI_map_object_buffer 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLvoid* APIENTRY glMapObjectBufferATI (GLuint buffer); -GLAPI void APIENTRY glUnmapObjectBufferATI (GLuint buffer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLvoid* (APIENTRYP PFNGLMAPOBJECTBUFFERATIPROC) (GLuint buffer); -typedef void (APIENTRYP PFNGLUNMAPOBJECTBUFFERATIPROC) (GLuint buffer); -#endif - -#ifndef GL_ATI_separate_stencil -#define GL_ATI_separate_stencil 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glStencilOpSeparateATI (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); -GLAPI void APIENTRY glStencilFuncSeparateATI (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEATIPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); -typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEATIPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); -#endif - -#ifndef GL_ATI_vertex_attrib_array_object -#define GL_ATI_vertex_attrib_array_object 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexAttribArrayObjectATI (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset); -GLAPI void APIENTRY glGetVertexAttribArrayObjectfvATI (GLuint index, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetVertexAttribArrayObjectivATI (GLuint index, GLenum pname, GLint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVERTEXATTRIBARRAYOBJECTATIPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTFVATIPROC) (GLuint index, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTIVATIPROC) (GLuint index, GLenum pname, GLint *params); -#endif - -#ifndef GL_OES_read_format -#define GL_OES_read_format 1 -#endif - -#ifndef GL_EXT_depth_bounds_test -#define GL_EXT_depth_bounds_test 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDepthBoundsEXT (GLclampd zmin, GLclampd zmax); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDEPTHBOUNDSEXTPROC) (GLclampd zmin, GLclampd zmax); -#endif - -#ifndef GL_EXT_texture_mirror_clamp -#define GL_EXT_texture_mirror_clamp 1 -#endif - -#ifndef GL_EXT_blend_equation_separate -#define GL_EXT_blend_equation_separate 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendEquationSeparateEXT (GLenum modeRGB, GLenum modeAlpha); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEEXTPROC) (GLenum modeRGB, GLenum modeAlpha); -#endif - -#ifndef GL_MESA_pack_invert -#define GL_MESA_pack_invert 1 -#endif - -#ifndef GL_MESA_ycbcr_texture -#define GL_MESA_ycbcr_texture 1 -#endif - -#ifndef GL_EXT_pixel_buffer_object -#define GL_EXT_pixel_buffer_object 1 -#endif - -#ifndef GL_NV_fragment_program_option -#define GL_NV_fragment_program_option 1 -#endif - -#ifndef GL_NV_fragment_program2 -#define GL_NV_fragment_program2 1 -#endif - -#ifndef GL_NV_vertex_program2_option -#define GL_NV_vertex_program2_option 1 -#endif - -#ifndef GL_NV_vertex_program3 -#define GL_NV_vertex_program3 1 -#endif - -#ifndef GL_EXT_framebuffer_object -#define GL_EXT_framebuffer_object 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLboolean APIENTRY glIsRenderbufferEXT (GLuint renderbuffer); -GLAPI void APIENTRY glBindRenderbufferEXT (GLenum target, GLuint renderbuffer); -GLAPI void APIENTRY glDeleteRenderbuffersEXT (GLsizei n, const GLuint *renderbuffers); -GLAPI void APIENTRY glGenRenderbuffersEXT (GLsizei n, GLuint *renderbuffers); -GLAPI void APIENTRY glRenderbufferStorageEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetRenderbufferParameterivEXT (GLenum target, GLenum pname, GLint *params); -GLAPI GLboolean APIENTRY glIsFramebufferEXT (GLuint framebuffer); -GLAPI void APIENTRY glBindFramebufferEXT (GLenum target, GLuint framebuffer); -GLAPI void APIENTRY glDeleteFramebuffersEXT (GLsizei n, const GLuint *framebuffers); -GLAPI void APIENTRY glGenFramebuffersEXT (GLsizei n, GLuint *framebuffers); -GLAPI GLenum APIENTRY glCheckFramebufferStatusEXT (GLenum target); -GLAPI void APIENTRY glFramebufferTexture1DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLAPI void APIENTRY glFramebufferTexture2DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLAPI void APIENTRY glFramebufferTexture3DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -GLAPI void APIENTRY glFramebufferRenderbufferEXT (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -GLAPI void APIENTRY glGetFramebufferAttachmentParameterivEXT (GLenum target, GLenum attachment, GLenum pname, GLint *params); -GLAPI void APIENTRY glGenerateMipmapEXT (GLenum target); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFEREXTPROC) (GLuint renderbuffer); -typedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC) (GLenum target, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers); -typedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC) (GLsizei n, GLuint *renderbuffers); -typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); -typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFEREXTPROC) (GLuint framebuffer); -typedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint framebuffer); -typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint *framebuffers); -typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers); -typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum target); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC) (GLenum target); -#endif - -#ifndef GL_GREMEDY_string_marker -#define GL_GREMEDY_string_marker 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glStringMarkerGREMEDY (GLsizei len, const GLvoid *string); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLSTRINGMARKERGREMEDYPROC) (GLsizei len, const GLvoid *string); -#endif - -#ifndef GL_EXT_packed_depth_stencil -#define GL_EXT_packed_depth_stencil 1 -#endif - -#ifndef GL_EXT_stencil_clear_tag -#define GL_EXT_stencil_clear_tag 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glStencilClearTagEXT (GLsizei stencilTagBits, GLuint stencilClearTag); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLSTENCILCLEARTAGEXTPROC) (GLsizei stencilTagBits, GLuint stencilClearTag); -#endif - -#ifndef GL_EXT_texture_sRGB -#define GL_EXT_texture_sRGB 1 -#endif - -#ifndef GL_EXT_framebuffer_blit -#define GL_EXT_framebuffer_blit 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlitFramebufferEXT (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBLITFRAMEBUFFEREXTPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -#endif - -#ifndef GL_EXT_framebuffer_multisample -#define GL_EXT_framebuffer_multisample 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glRenderbufferStorageMultisampleEXT (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -#endif - -#ifndef GL_MESAX_texture_stack -#define GL_MESAX_texture_stack 1 -#endif - -#ifndef GL_EXT_timer_query -#define GL_EXT_timer_query 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetQueryObjecti64vEXT (GLuint id, GLenum pname, GLint64EXT *params); -GLAPI void APIENTRY glGetQueryObjectui64vEXT (GLuint id, GLenum pname, GLuint64EXT *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VEXTPROC) (GLuint id, GLenum pname, GLint64EXT *params); -typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VEXTPROC) (GLuint id, GLenum pname, GLuint64EXT *params); -#endif - -#ifndef GL_EXT_gpu_program_parameters -#define GL_EXT_gpu_program_parameters 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProgramEnvParameters4fvEXT (GLenum target, GLuint index, GLsizei count, const GLfloat *params); -GLAPI void APIENTRY glProgramLocalParameters4fvEXT (GLenum target, GLuint index, GLsizei count, const GLfloat *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERS4FVEXTPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *params); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *params); -#endif - -#ifndef GL_APPLE_flush_buffer_range -#define GL_APPLE_flush_buffer_range 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBufferParameteriAPPLE (GLenum target, GLenum pname, GLint param); -GLAPI void APIENTRY glFlushMappedBufferRangeAPPLE (GLenum target, GLintptr offset, GLsizeiptr size); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBUFFERPARAMETERIAPPLEPROC) (GLenum target, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC) (GLenum target, GLintptr offset, GLsizeiptr size); -#endif - -#ifndef GL_NV_gpu_program4 -#define GL_NV_gpu_program4 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProgramLocalParameterI4iNV (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); -GLAPI void APIENTRY glProgramLocalParameterI4ivNV (GLenum target, GLuint index, const GLint *params); -GLAPI void APIENTRY glProgramLocalParametersI4ivNV (GLenum target, GLuint index, GLsizei count, const GLint *params); -GLAPI void APIENTRY glProgramLocalParameterI4uiNV (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -GLAPI void APIENTRY glProgramLocalParameterI4uivNV (GLenum target, GLuint index, const GLuint *params); -GLAPI void APIENTRY glProgramLocalParametersI4uivNV (GLenum target, GLuint index, GLsizei count, const GLuint *params); -GLAPI void APIENTRY glProgramEnvParameterI4iNV (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); -GLAPI void APIENTRY glProgramEnvParameterI4ivNV (GLenum target, GLuint index, const GLint *params); -GLAPI void APIENTRY glProgramEnvParametersI4ivNV (GLenum target, GLuint index, GLsizei count, const GLint *params); -GLAPI void APIENTRY glProgramEnvParameterI4uiNV (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -GLAPI void APIENTRY glProgramEnvParameterI4uivNV (GLenum target, GLuint index, const GLuint *params); -GLAPI void APIENTRY glProgramEnvParametersI4uivNV (GLenum target, GLuint index, GLsizei count, const GLuint *params); -GLAPI void APIENTRY glGetProgramLocalParameterIivNV (GLenum target, GLuint index, GLint *params); -GLAPI void APIENTRY glGetProgramLocalParameterIuivNV (GLenum target, GLuint index, GLuint *params); -GLAPI void APIENTRY glGetProgramEnvParameterIivNV (GLenum target, GLuint index, GLint *params); -GLAPI void APIENTRY glGetProgramEnvParameterIuivNV (GLenum target, GLuint index, GLuint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4INVPROC) (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4IVNVPROC) (GLenum target, GLuint index, const GLint *params); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERSI4IVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLint *params); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4UINVPROC) (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4UIVNVPROC) (GLenum target, GLuint index, const GLuint *params); -typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERSI4UIVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLuint *params); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4INVPROC) (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4IVNVPROC) (GLenum target, GLuint index, const GLint *params); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERSI4IVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLint *params); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4UINVPROC) (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4UIVNVPROC) (GLenum target, GLuint index, const GLuint *params); -typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERSI4UIVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLuint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERIIVNVPROC) (GLenum target, GLuint index, GLint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERIUIVNVPROC) (GLenum target, GLuint index, GLuint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERIIVNVPROC) (GLenum target, GLuint index, GLint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERIUIVNVPROC) (GLenum target, GLuint index, GLuint *params); -#endif - -#ifndef GL_NV_geometry_program4 -#define GL_NV_geometry_program4 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProgramVertexLimitNV (GLenum target, GLint limit); -GLAPI void APIENTRY glFramebufferTextureEXT (GLenum target, GLenum attachment, GLuint texture, GLint level); -GLAPI void APIENTRY glFramebufferTextureLayerEXT (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -GLAPI void APIENTRY glFramebufferTextureFaceEXT (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPROGRAMVERTEXLIMITNVPROC) (GLenum target, GLint limit); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); -#endif - -#ifndef GL_EXT_geometry_shader4 -#define GL_EXT_geometry_shader4 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProgramParameteriEXT (GLuint program, GLenum pname, GLint value); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value); -#endif - -#ifndef GL_NV_vertex_program4 -#define GL_NV_vertex_program4 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexAttribI1iEXT (GLuint index, GLint x); -GLAPI void APIENTRY glVertexAttribI2iEXT (GLuint index, GLint x, GLint y); -GLAPI void APIENTRY glVertexAttribI3iEXT (GLuint index, GLint x, GLint y, GLint z); -GLAPI void APIENTRY glVertexAttribI4iEXT (GLuint index, GLint x, GLint y, GLint z, GLint w); -GLAPI void APIENTRY glVertexAttribI1uiEXT (GLuint index, GLuint x); -GLAPI void APIENTRY glVertexAttribI2uiEXT (GLuint index, GLuint x, GLuint y); -GLAPI void APIENTRY glVertexAttribI3uiEXT (GLuint index, GLuint x, GLuint y, GLuint z); -GLAPI void APIENTRY glVertexAttribI4uiEXT (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -GLAPI void APIENTRY glVertexAttribI1ivEXT (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttribI2ivEXT (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttribI3ivEXT (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttribI4ivEXT (GLuint index, const GLint *v); -GLAPI void APIENTRY glVertexAttribI1uivEXT (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttribI2uivEXT (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttribI3uivEXT (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttribI4uivEXT (GLuint index, const GLuint *v); -GLAPI void APIENTRY glVertexAttribI4bvEXT (GLuint index, const GLbyte *v); -GLAPI void APIENTRY glVertexAttribI4svEXT (GLuint index, const GLshort *v); -GLAPI void APIENTRY glVertexAttribI4ubvEXT (GLuint index, const GLubyte *v); -GLAPI void APIENTRY glVertexAttribI4usvEXT (GLuint index, const GLushort *v); -GLAPI void APIENTRY glVertexAttribIPointerEXT (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -GLAPI void APIENTRY glGetVertexAttribIivEXT (GLuint index, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVertexAttribIuivEXT (GLuint index, GLenum pname, GLuint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IEXTPROC) (GLuint index, GLint x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IEXTPROC) (GLuint index, GLint x, GLint y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IEXTPROC) (GLuint index, GLint x, GLint y, GLint z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IEXTPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIEXTPROC) (GLuint index, GLuint x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIEXTPROC) (GLuint index, GLuint x, GLuint y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVEXTPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVEXTPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVEXTPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVEXTPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVEXTPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVEXTPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVEXTPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVEXTPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVEXTPROC) (GLuint index, const GLbyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVEXTPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVEXTPROC) (GLuint index, const GLubyte *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVEXTPROC) (GLuint index, const GLushort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVEXTPROC) (GLuint index, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVEXTPROC) (GLuint index, GLenum pname, GLuint *params); -#endif - -#ifndef GL_EXT_gpu_shader4 -#define GL_EXT_gpu_shader4 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetUniformuivEXT (GLuint program, GLint location, GLuint *params); -GLAPI void APIENTRY glBindFragDataLocationEXT (GLuint program, GLuint color, const GLchar *name); -GLAPI GLint APIENTRY glGetFragDataLocationEXT (GLuint program, const GLchar *name); -GLAPI void APIENTRY glUniform1uiEXT (GLint location, GLuint v0); -GLAPI void APIENTRY glUniform2uiEXT (GLint location, GLuint v0, GLuint v1); -GLAPI void APIENTRY glUniform3uiEXT (GLint location, GLuint v0, GLuint v1, GLuint v2); -GLAPI void APIENTRY glUniform4uiEXT (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -GLAPI void APIENTRY glUniform1uivEXT (GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glUniform2uivEXT (GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glUniform3uivEXT (GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glUniform4uivEXT (GLint location, GLsizei count, const GLuint *value); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGETUNIFORMUIVEXTPROC) (GLuint program, GLint location, GLuint *params); -typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONEXTPROC) (GLuint program, GLuint color, const GLchar *name); -typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONEXTPROC) (GLuint program, const GLchar *name); -typedef void (APIENTRYP PFNGLUNIFORM1UIEXTPROC) (GLint location, GLuint v0); -typedef void (APIENTRYP PFNGLUNIFORM2UIEXTPROC) (GLint location, GLuint v0, GLuint v1); -typedef void (APIENTRYP PFNGLUNIFORM3UIEXTPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2); -typedef void (APIENTRYP PFNGLUNIFORM4UIEXTPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -typedef void (APIENTRYP PFNGLUNIFORM1UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLUNIFORM2UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLUNIFORM3UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLUNIFORM4UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); -#endif - -#ifndef GL_EXT_draw_instanced -#define GL_EXT_draw_instanced 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawArraysInstancedEXT (GLenum mode, GLint start, GLsizei count, GLsizei primcount); -GLAPI void APIENTRY glDrawElementsInstancedEXT (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); -#endif - -#ifndef GL_EXT_packed_float -#define GL_EXT_packed_float 1 -#endif - -#ifndef GL_EXT_texture_array -#define GL_EXT_texture_array 1 -#endif - -#ifndef GL_EXT_texture_buffer_object -#define GL_EXT_texture_buffer_object 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexBufferEXT (GLenum target, GLenum internalformat, GLuint buffer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTEXBUFFEREXTPROC) (GLenum target, GLenum internalformat, GLuint buffer); -#endif - -#ifndef GL_EXT_texture_compression_latc -#define GL_EXT_texture_compression_latc 1 -#endif - -#ifndef GL_EXT_texture_compression_rgtc -#define GL_EXT_texture_compression_rgtc 1 -#endif - -#ifndef GL_EXT_texture_shared_exponent -#define GL_EXT_texture_shared_exponent 1 -#endif - -#ifndef GL_NV_depth_buffer_float -#define GL_NV_depth_buffer_float 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDepthRangedNV (GLdouble zNear, GLdouble zFar); -GLAPI void APIENTRY glClearDepthdNV (GLdouble depth); -GLAPI void APIENTRY glDepthBoundsdNV (GLdouble zmin, GLdouble zmax); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDEPTHRANGEDNVPROC) (GLdouble zNear, GLdouble zFar); -typedef void (APIENTRYP PFNGLCLEARDEPTHDNVPROC) (GLdouble depth); -typedef void (APIENTRYP PFNGLDEPTHBOUNDSDNVPROC) (GLdouble zmin, GLdouble zmax); -#endif - -#ifndef GL_NV_fragment_program4 -#define GL_NV_fragment_program4 1 -#endif - -#ifndef GL_NV_framebuffer_multisample_coverage -#define GL_NV_framebuffer_multisample_coverage 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glRenderbufferStorageMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); -#endif - -#ifndef GL_EXT_framebuffer_sRGB -#define GL_EXT_framebuffer_sRGB 1 -#endif - -#ifndef GL_NV_geometry_shader4 -#define GL_NV_geometry_shader4 1 -#endif - -#ifndef GL_NV_parameter_buffer_object -#define GL_NV_parameter_buffer_object 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProgramBufferParametersfvNV (GLenum target, GLuint buffer, GLuint index, GLsizei count, const GLfloat *params); -GLAPI void APIENTRY glProgramBufferParametersIivNV (GLenum target, GLuint buffer, GLuint index, GLsizei count, const GLint *params); -GLAPI void APIENTRY glProgramBufferParametersIuivNV (GLenum target, GLuint buffer, GLuint index, GLsizei count, const GLuint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSFVNVPROC) (GLenum target, GLuint buffer, GLuint index, GLsizei count, const GLfloat *params); -typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSIIVNVPROC) (GLenum target, GLuint buffer, GLuint index, GLsizei count, const GLint *params); -typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSIUIVNVPROC) (GLenum target, GLuint buffer, GLuint index, GLsizei count, const GLuint *params); -#endif - -#ifndef GL_EXT_draw_buffers2 -#define GL_EXT_draw_buffers2 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColorMaskIndexedEXT (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); -GLAPI void APIENTRY glGetBooleanIndexedvEXT (GLenum target, GLuint index, GLboolean *data); -GLAPI void APIENTRY glGetIntegerIndexedvEXT (GLenum target, GLuint index, GLint *data); -GLAPI void APIENTRY glEnableIndexedEXT (GLenum target, GLuint index); -GLAPI void APIENTRY glDisableIndexedEXT (GLenum target, GLuint index); -GLAPI GLboolean APIENTRY glIsEnabledIndexedEXT (GLenum target, GLuint index); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCOLORMASKINDEXEDEXTPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); -typedef void (APIENTRYP PFNGLGETBOOLEANINDEXEDVEXTPROC) (GLenum target, GLuint index, GLboolean *data); -typedef void (APIENTRYP PFNGLGETINTEGERINDEXEDVEXTPROC) (GLenum target, GLuint index, GLint *data); -typedef void (APIENTRYP PFNGLENABLEINDEXEDEXTPROC) (GLenum target, GLuint index); -typedef void (APIENTRYP PFNGLDISABLEINDEXEDEXTPROC) (GLenum target, GLuint index); -typedef GLboolean (APIENTRYP PFNGLISENABLEDINDEXEDEXTPROC) (GLenum target, GLuint index); -#endif - -#ifndef GL_NV_transform_feedback -#define GL_NV_transform_feedback 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBeginTransformFeedbackNV (GLenum primitiveMode); -GLAPI void APIENTRY glEndTransformFeedbackNV (void); -GLAPI void APIENTRY glTransformFeedbackAttribsNV (GLuint count, const GLint *attribs, GLenum bufferMode); -GLAPI void APIENTRY glBindBufferRangeNV (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -GLAPI void APIENTRY glBindBufferOffsetNV (GLenum target, GLuint index, GLuint buffer, GLintptr offset); -GLAPI void APIENTRY glBindBufferBaseNV (GLenum target, GLuint index, GLuint buffer); -GLAPI void APIENTRY glTransformFeedbackVaryingsNV (GLuint program, GLsizei count, const GLint *locations, GLenum bufferMode); -GLAPI void APIENTRY glActiveVaryingNV (GLuint program, const GLchar *name); -GLAPI GLint APIENTRY glGetVaryingLocationNV (GLuint program, const GLchar *name); -GLAPI void APIENTRY glGetActiveVaryingNV (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); -GLAPI void APIENTRY glGetTransformFeedbackVaryingNV (GLuint program, GLuint index, GLint *location); -GLAPI void APIENTRY glTransformFeedbackStreamAttribsNV (GLsizei count, const GLint *attribs, GLsizei nbuffers, const GLint *bufstreams, GLenum bufferMode); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKNVPROC) (GLenum primitiveMode); -typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKNVPROC) (void); -typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKATTRIBSNVPROC) (GLuint count, const GLint *attribs, GLenum bufferMode); -typedef void (APIENTRYP PFNGLBINDBUFFERRANGENVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -typedef void (APIENTRYP PFNGLBINDBUFFEROFFSETNVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset); -typedef void (APIENTRYP PFNGLBINDBUFFERBASENVPROC) (GLenum target, GLuint index, GLuint buffer); -typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSNVPROC) (GLuint program, GLsizei count, const GLint *locations, GLenum bufferMode); -typedef void (APIENTRYP PFNGLACTIVEVARYINGNVPROC) (GLuint program, const GLchar *name); -typedef GLint (APIENTRYP PFNGLGETVARYINGLOCATIONNVPROC) (GLuint program, const GLchar *name); -typedef void (APIENTRYP PFNGLGETACTIVEVARYINGNVPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); -typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGNVPROC) (GLuint program, GLuint index, GLint *location); -typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKSTREAMATTRIBSNVPROC) (GLsizei count, const GLint *attribs, GLsizei nbuffers, const GLint *bufstreams, GLenum bufferMode); -#endif - -#ifndef GL_EXT_bindable_uniform -#define GL_EXT_bindable_uniform 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glUniformBufferEXT (GLuint program, GLint location, GLuint buffer); -GLAPI GLint APIENTRY glGetUniformBufferSizeEXT (GLuint program, GLint location); -GLAPI GLintptr APIENTRY glGetUniformOffsetEXT (GLuint program, GLint location); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLUNIFORMBUFFEREXTPROC) (GLuint program, GLint location, GLuint buffer); -typedef GLint (APIENTRYP PFNGLGETUNIFORMBUFFERSIZEEXTPROC) (GLuint program, GLint location); -typedef GLintptr (APIENTRYP PFNGLGETUNIFORMOFFSETEXTPROC) (GLuint program, GLint location); -#endif - -#ifndef GL_EXT_texture_integer -#define GL_EXT_texture_integer 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexParameterIivEXT (GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glTexParameterIuivEXT (GLenum target, GLenum pname, const GLuint *params); -GLAPI void APIENTRY glGetTexParameterIivEXT (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetTexParameterIuivEXT (GLenum target, GLenum pname, GLuint *params); -GLAPI void APIENTRY glClearColorIiEXT (GLint red, GLint green, GLint blue, GLint alpha); -GLAPI void APIENTRY glClearColorIuiEXT (GLuint red, GLuint green, GLuint blue, GLuint alpha); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, const GLuint *params); -typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLCLEARCOLORIIEXTPROC) (GLint red, GLint green, GLint blue, GLint alpha); -typedef void (APIENTRYP PFNGLCLEARCOLORIUIEXTPROC) (GLuint red, GLuint green, GLuint blue, GLuint alpha); -#endif - -#ifndef GL_GREMEDY_frame_terminator -#define GL_GREMEDY_frame_terminator 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glFrameTerminatorGREMEDY (void); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLFRAMETERMINATORGREMEDYPROC) (void); -#endif - -#ifndef GL_NV_conditional_render -#define GL_NV_conditional_render 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBeginConditionalRenderNV (GLuint id, GLenum mode); -GLAPI void APIENTRY glEndConditionalRenderNV (void); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERNVPROC) (GLuint id, GLenum mode); -typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERNVPROC) (void); -#endif - -#ifndef GL_NV_present_video -#define GL_NV_present_video 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPresentFrameKeyedNV (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLuint key0, GLenum target1, GLuint fill1, GLuint key1); -GLAPI void APIENTRY glPresentFrameDualFillNV (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLenum target1, GLuint fill1, GLenum target2, GLuint fill2, GLenum target3, GLuint fill3); -GLAPI void APIENTRY glGetVideoivNV (GLuint video_slot, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVideouivNV (GLuint video_slot, GLenum pname, GLuint *params); -GLAPI void APIENTRY glGetVideoi64vNV (GLuint video_slot, GLenum pname, GLint64EXT *params); -GLAPI void APIENTRY glGetVideoui64vNV (GLuint video_slot, GLenum pname, GLuint64EXT *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPRESENTFRAMEKEYEDNVPROC) (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLuint key0, GLenum target1, GLuint fill1, GLuint key1); -typedef void (APIENTRYP PFNGLPRESENTFRAMEDUALFILLNVPROC) (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLenum target1, GLuint fill1, GLenum target2, GLuint fill2, GLenum target3, GLuint fill3); -typedef void (APIENTRYP PFNGLGETVIDEOIVNVPROC) (GLuint video_slot, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVIDEOUIVNVPROC) (GLuint video_slot, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLGETVIDEOI64VNVPROC) (GLuint video_slot, GLenum pname, GLint64EXT *params); -typedef void (APIENTRYP PFNGLGETVIDEOUI64VNVPROC) (GLuint video_slot, GLenum pname, GLuint64EXT *params); -#endif - -#ifndef GL_EXT_transform_feedback -#define GL_EXT_transform_feedback 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBeginTransformFeedbackEXT (GLenum primitiveMode); -GLAPI void APIENTRY glEndTransformFeedbackEXT (void); -GLAPI void APIENTRY glBindBufferRangeEXT (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -GLAPI void APIENTRY glBindBufferOffsetEXT (GLenum target, GLuint index, GLuint buffer, GLintptr offset); -GLAPI void APIENTRY glBindBufferBaseEXT (GLenum target, GLuint index, GLuint buffer); -GLAPI void APIENTRY glTransformFeedbackVaryingsEXT (GLuint program, GLsizei count, const GLchar* *varyings, GLenum bufferMode); -GLAPI void APIENTRY glGetTransformFeedbackVaryingEXT (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKEXTPROC) (GLenum primitiveMode); -typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKEXTPROC) (void); -typedef void (APIENTRYP PFNGLBINDBUFFERRANGEEXTPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -typedef void (APIENTRYP PFNGLBINDBUFFEROFFSETEXTPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset); -typedef void (APIENTRYP PFNGLBINDBUFFERBASEEXTPROC) (GLenum target, GLuint index, GLuint buffer); -typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSEXTPROC) (GLuint program, GLsizei count, const GLchar* *varyings, GLenum bufferMode); -typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGEXTPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); -#endif - -#ifndef GL_EXT_direct_state_access -#define GL_EXT_direct_state_access 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glClientAttribDefaultEXT (GLbitfield mask); -GLAPI void APIENTRY glPushClientAttribDefaultEXT (GLbitfield mask); -GLAPI void APIENTRY glMatrixLoadfEXT (GLenum mode, const GLfloat *m); -GLAPI void APIENTRY glMatrixLoaddEXT (GLenum mode, const GLdouble *m); -GLAPI void APIENTRY glMatrixMultfEXT (GLenum mode, const GLfloat *m); -GLAPI void APIENTRY glMatrixMultdEXT (GLenum mode, const GLdouble *m); -GLAPI void APIENTRY glMatrixLoadIdentityEXT (GLenum mode); -GLAPI void APIENTRY glMatrixRotatefEXT (GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glMatrixRotatedEXT (GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glMatrixScalefEXT (GLenum mode, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glMatrixScaledEXT (GLenum mode, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glMatrixTranslatefEXT (GLenum mode, GLfloat x, GLfloat y, GLfloat z); -GLAPI void APIENTRY glMatrixTranslatedEXT (GLenum mode, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glMatrixFrustumEXT (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); -GLAPI void APIENTRY glMatrixOrthoEXT (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); -GLAPI void APIENTRY glMatrixPopEXT (GLenum mode); -GLAPI void APIENTRY glMatrixPushEXT (GLenum mode); -GLAPI void APIENTRY glMatrixLoadTransposefEXT (GLenum mode, const GLfloat *m); -GLAPI void APIENTRY glMatrixLoadTransposedEXT (GLenum mode, const GLdouble *m); -GLAPI void APIENTRY glMatrixMultTransposefEXT (GLenum mode, const GLfloat *m); -GLAPI void APIENTRY glMatrixMultTransposedEXT (GLenum mode, const GLdouble *m); -GLAPI void APIENTRY glTextureParameterfEXT (GLuint texture, GLenum target, GLenum pname, GLfloat param); -GLAPI void APIENTRY glTextureParameterfvEXT (GLuint texture, GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glTextureParameteriEXT (GLuint texture, GLenum target, GLenum pname, GLint param); -GLAPI void APIENTRY glTextureParameterivEXT (GLuint texture, GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glCopyTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); -GLAPI void APIENTRY glCopyTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -GLAPI void APIENTRY glCopyTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glCopyTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetTextureImageEXT (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); -GLAPI void APIENTRY glGetTextureParameterfvEXT (GLuint texture, GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetTextureParameterivEXT (GLuint texture, GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetTextureLevelParameterfvEXT (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetTextureLevelParameterivEXT (GLuint texture, GLenum target, GLint level, GLenum pname, GLint *params); -GLAPI void APIENTRY glTextureImage3DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glCopyTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glMultiTexParameterfEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat param); -GLAPI void APIENTRY glMultiTexParameterfvEXT (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glMultiTexParameteriEXT (GLenum texunit, GLenum target, GLenum pname, GLint param); -GLAPI void APIENTRY glMultiTexParameterivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glCopyMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); -GLAPI void APIENTRY glCopyMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -GLAPI void APIENTRY glCopyMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glCopyMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetMultiTexImageEXT (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); -GLAPI void APIENTRY glGetMultiTexParameterfvEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetMultiTexParameterivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetMultiTexLevelParameterfvEXT (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetMultiTexLevelParameterivEXT (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint *params); -GLAPI void APIENTRY glMultiTexImage3DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glCopyMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glBindMultiTextureEXT (GLenum texunit, GLenum target, GLuint texture); -GLAPI void APIENTRY glEnableClientStateIndexedEXT (GLenum array, GLuint index); -GLAPI void APIENTRY glDisableClientStateIndexedEXT (GLenum array, GLuint index); -GLAPI void APIENTRY glMultiTexCoordPointerEXT (GLenum texunit, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -GLAPI void APIENTRY glMultiTexEnvfEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat param); -GLAPI void APIENTRY glMultiTexEnvfvEXT (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glMultiTexEnviEXT (GLenum texunit, GLenum target, GLenum pname, GLint param); -GLAPI void APIENTRY glMultiTexEnvivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glMultiTexGendEXT (GLenum texunit, GLenum coord, GLenum pname, GLdouble param); -GLAPI void APIENTRY glMultiTexGendvEXT (GLenum texunit, GLenum coord, GLenum pname, const GLdouble *params); -GLAPI void APIENTRY glMultiTexGenfEXT (GLenum texunit, GLenum coord, GLenum pname, GLfloat param); -GLAPI void APIENTRY glMultiTexGenfvEXT (GLenum texunit, GLenum coord, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glMultiTexGeniEXT (GLenum texunit, GLenum coord, GLenum pname, GLint param); -GLAPI void APIENTRY glMultiTexGenivEXT (GLenum texunit, GLenum coord, GLenum pname, const GLint *params); -GLAPI void APIENTRY glGetMultiTexEnvfvEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetMultiTexEnvivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetMultiTexGendvEXT (GLenum texunit, GLenum coord, GLenum pname, GLdouble *params); -GLAPI void APIENTRY glGetMultiTexGenfvEXT (GLenum texunit, GLenum coord, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetMultiTexGenivEXT (GLenum texunit, GLenum coord, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetFloatIndexedvEXT (GLenum target, GLuint index, GLfloat *data); -GLAPI void APIENTRY glGetDoubleIndexedvEXT (GLenum target, GLuint index, GLdouble *data); -GLAPI void APIENTRY glGetPointerIndexedvEXT (GLenum target, GLuint index, GLvoid* *data); -GLAPI void APIENTRY glCompressedTextureImage3DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glGetCompressedTextureImageEXT (GLuint texture, GLenum target, GLint lod, GLvoid *img); -GLAPI void APIENTRY glCompressedMultiTexImage3DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glGetCompressedMultiTexImageEXT (GLenum texunit, GLenum target, GLint lod, GLvoid *img); -GLAPI void APIENTRY glNamedProgramStringEXT (GLuint program, GLenum target, GLenum format, GLsizei len, const GLvoid *string); -GLAPI void APIENTRY glNamedProgramLocalParameter4dEXT (GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glNamedProgramLocalParameter4dvEXT (GLuint program, GLenum target, GLuint index, const GLdouble *params); -GLAPI void APIENTRY glNamedProgramLocalParameter4fEXT (GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI void APIENTRY glNamedProgramLocalParameter4fvEXT (GLuint program, GLenum target, GLuint index, const GLfloat *params); -GLAPI void APIENTRY glGetNamedProgramLocalParameterdvEXT (GLuint program, GLenum target, GLuint index, GLdouble *params); -GLAPI void APIENTRY glGetNamedProgramLocalParameterfvEXT (GLuint program, GLenum target, GLuint index, GLfloat *params); -GLAPI void APIENTRY glGetNamedProgramivEXT (GLuint program, GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetNamedProgramStringEXT (GLuint program, GLenum target, GLenum pname, GLvoid *string); -GLAPI void APIENTRY glNamedProgramLocalParameters4fvEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat *params); -GLAPI void APIENTRY glNamedProgramLocalParameterI4iEXT (GLuint program, GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); -GLAPI void APIENTRY glNamedProgramLocalParameterI4ivEXT (GLuint program, GLenum target, GLuint index, const GLint *params); -GLAPI void APIENTRY glNamedProgramLocalParametersI4ivEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLint *params); -GLAPI void APIENTRY glNamedProgramLocalParameterI4uiEXT (GLuint program, GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -GLAPI void APIENTRY glNamedProgramLocalParameterI4uivEXT (GLuint program, GLenum target, GLuint index, const GLuint *params); -GLAPI void APIENTRY glNamedProgramLocalParametersI4uivEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint *params); -GLAPI void APIENTRY glGetNamedProgramLocalParameterIivEXT (GLuint program, GLenum target, GLuint index, GLint *params); -GLAPI void APIENTRY glGetNamedProgramLocalParameterIuivEXT (GLuint program, GLenum target, GLuint index, GLuint *params); -GLAPI void APIENTRY glTextureParameterIivEXT (GLuint texture, GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glTextureParameterIuivEXT (GLuint texture, GLenum target, GLenum pname, const GLuint *params); -GLAPI void APIENTRY glGetTextureParameterIivEXT (GLuint texture, GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetTextureParameterIuivEXT (GLuint texture, GLenum target, GLenum pname, GLuint *params); -GLAPI void APIENTRY glMultiTexParameterIivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glMultiTexParameterIuivEXT (GLenum texunit, GLenum target, GLenum pname, const GLuint *params); -GLAPI void APIENTRY glGetMultiTexParameterIivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetMultiTexParameterIuivEXT (GLenum texunit, GLenum target, GLenum pname, GLuint *params); -GLAPI void APIENTRY glProgramUniform1fEXT (GLuint program, GLint location, GLfloat v0); -GLAPI void APIENTRY glProgramUniform2fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1); -GLAPI void APIENTRY glProgramUniform3fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -GLAPI void APIENTRY glProgramUniform4fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -GLAPI void APIENTRY glProgramUniform1iEXT (GLuint program, GLint location, GLint v0); -GLAPI void APIENTRY glProgramUniform2iEXT (GLuint program, GLint location, GLint v0, GLint v1); -GLAPI void APIENTRY glProgramUniform3iEXT (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); -GLAPI void APIENTRY glProgramUniform4iEXT (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -GLAPI void APIENTRY glProgramUniform1fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform2fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform3fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform4fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform1ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniform2ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniform3ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniform4ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); -GLAPI void APIENTRY glProgramUniformMatrix2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix2x3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix3x2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix2x4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix4x2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix3x4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniformMatrix4x3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI void APIENTRY glProgramUniform1uiEXT (GLuint program, GLint location, GLuint v0); -GLAPI void APIENTRY glProgramUniform2uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1); -GLAPI void APIENTRY glProgramUniform3uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); -GLAPI void APIENTRY glProgramUniform4uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -GLAPI void APIENTRY glProgramUniform1uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glProgramUniform2uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glProgramUniform3uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glProgramUniform4uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); -GLAPI void APIENTRY glNamedBufferDataEXT (GLuint buffer, GLsizeiptr size, const GLvoid *data, GLenum usage); -GLAPI void APIENTRY glNamedBufferSubDataEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, const GLvoid *data); -GLAPI GLvoid* APIENTRY glMapNamedBufferEXT (GLuint buffer, GLenum access); -GLAPI GLboolean APIENTRY glUnmapNamedBufferEXT (GLuint buffer); -GLAPI GLvoid* APIENTRY glMapNamedBufferRangeEXT (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); -GLAPI void APIENTRY glFlushMappedNamedBufferRangeEXT (GLuint buffer, GLintptr offset, GLsizeiptr length); -GLAPI void APIENTRY glNamedCopyBufferSubDataEXT (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); -GLAPI void APIENTRY glGetNamedBufferParameterivEXT (GLuint buffer, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetNamedBufferPointervEXT (GLuint buffer, GLenum pname, GLvoid* *params); -GLAPI void APIENTRY glGetNamedBufferSubDataEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, GLvoid *data); -GLAPI void APIENTRY glTextureBufferEXT (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer); -GLAPI void APIENTRY glMultiTexBufferEXT (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer); -GLAPI void APIENTRY glNamedRenderbufferStorageEXT (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetNamedRenderbufferParameterivEXT (GLuint renderbuffer, GLenum pname, GLint *params); -GLAPI GLenum APIENTRY glCheckNamedFramebufferStatusEXT (GLuint framebuffer, GLenum target); -GLAPI void APIENTRY glNamedFramebufferTexture1DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLAPI void APIENTRY glNamedFramebufferTexture2DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLAPI void APIENTRY glNamedFramebufferTexture3DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -GLAPI void APIENTRY glNamedFramebufferRenderbufferEXT (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -GLAPI void APIENTRY glGetNamedFramebufferAttachmentParameterivEXT (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); -GLAPI void APIENTRY glGenerateTextureMipmapEXT (GLuint texture, GLenum target); -GLAPI void APIENTRY glGenerateMultiTexMipmapEXT (GLenum texunit, GLenum target); -GLAPI void APIENTRY glFramebufferDrawBufferEXT (GLuint framebuffer, GLenum mode); -GLAPI void APIENTRY glFramebufferDrawBuffersEXT (GLuint framebuffer, GLsizei n, const GLenum *bufs); -GLAPI void APIENTRY glFramebufferReadBufferEXT (GLuint framebuffer, GLenum mode); -GLAPI void APIENTRY glGetFramebufferParameterivEXT (GLuint framebuffer, GLenum pname, GLint *params); -GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleEXT (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleCoverageEXT (GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI void APIENTRY glNamedFramebufferTextureEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); -GLAPI void APIENTRY glNamedFramebufferTextureLayerEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); -GLAPI void APIENTRY glNamedFramebufferTextureFaceEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLenum face); -GLAPI void APIENTRY glTextureRenderbufferEXT (GLuint texture, GLenum target, GLuint renderbuffer); -GLAPI void APIENTRY glMultiTexRenderbufferEXT (GLenum texunit, GLenum target, GLuint renderbuffer); -GLAPI void APIENTRY glProgramUniform1dEXT (GLuint program, GLint location, GLdouble x); -GLAPI void APIENTRY glProgramUniform2dEXT (GLuint program, GLint location, GLdouble x, GLdouble y); -GLAPI void APIENTRY glProgramUniform3dEXT (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glProgramUniform4dEXT (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glProgramUniform1dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniform2dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniform3dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniform4dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix2x3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix2x4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix3x2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix3x4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix4x2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -GLAPI void APIENTRY glProgramUniformMatrix4x3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask); -typedef void (APIENTRYP PFNGLPUSHCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask); -typedef void (APIENTRYP PFNGLMATRIXLOADFEXTPROC) (GLenum mode, const GLfloat *m); -typedef void (APIENTRYP PFNGLMATRIXLOADDEXTPROC) (GLenum mode, const GLdouble *m); -typedef void (APIENTRYP PFNGLMATRIXMULTFEXTPROC) (GLenum mode, const GLfloat *m); -typedef void (APIENTRYP PFNGLMATRIXMULTDEXTPROC) (GLenum mode, const GLdouble *m); -typedef void (APIENTRYP PFNGLMATRIXLOADIDENTITYEXTPROC) (GLenum mode); -typedef void (APIENTRYP PFNGLMATRIXROTATEFEXTPROC) (GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLMATRIXROTATEDEXTPROC) (GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLMATRIXSCALEFEXTPROC) (GLenum mode, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLMATRIXSCALEDEXTPROC) (GLenum mode, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLMATRIXTRANSLATEFEXTPROC) (GLenum mode, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNGLMATRIXTRANSLATEDEXTPROC) (GLenum mode, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLMATRIXFRUSTUMEXTPROC) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); -typedef void (APIENTRYP PFNGLMATRIXORTHOEXTPROC) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); -typedef void (APIENTRYP PFNGLMATRIXPOPEXTPROC) (GLenum mode); -typedef void (APIENTRYP PFNGLMATRIXPUSHEXTPROC) (GLenum mode); -typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m); -typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m); -typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m); -typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLCOPYTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); -typedef void (APIENTRYP PFNGLCOPYTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); -typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLMULTITEXPARAMETERFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLCOPYMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); -typedef void (APIENTRYP PFNGLCOPYMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); -typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLBINDMULTITEXTUREEXTPROC) (GLenum texunit, GLenum target, GLuint texture); -typedef void (APIENTRYP PFNGLENABLECLIENTSTATEINDEXEDEXTPROC) (GLenum array, GLuint index); -typedef void (APIENTRYP PFNGLDISABLECLIENTSTATEINDEXEDEXTPROC) (GLenum array, GLuint index); -typedef void (APIENTRYP PFNGLMULTITEXCOORDPOINTEREXTPROC) (GLenum texunit, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLMULTITEXENVFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLMULTITEXENVIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLMULTITEXENVIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLMULTITEXGENDEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLdouble param); -typedef void (APIENTRYP PFNGLMULTITEXGENDVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLdouble *params); -typedef void (APIENTRYP PFNGLMULTITEXGENFEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNGLMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLMULTITEXGENIEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint param); -typedef void (APIENTRYP PFNGLMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLGETMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETMULTITEXENVIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETMULTITEXGENDVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLdouble *params); -typedef void (APIENTRYP PFNGLGETMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETFLOATINDEXEDVEXTPROC) (GLenum target, GLuint index, GLfloat *data); -typedef void (APIENTRYP PFNGLGETDOUBLEINDEXEDVEXTPROC) (GLenum target, GLuint index, GLdouble *data); -typedef void (APIENTRYP PFNGLGETPOINTERINDEXEDVEXTPROC) (GLenum target, GLuint index, GLvoid* *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint lod, GLvoid *img); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLGETCOMPRESSEDMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint lod, GLvoid *img); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum format, GLsizei len, const GLvoid *string); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLdouble *params); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLfloat *params); -typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERDVEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble *params); -typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERFVEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat *params); -typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMIVEXTPROC) (GLuint program, GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum pname, GLvoid *string); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat *params); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4IEXTPROC) (GLuint program, GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4IVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLint *params); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERSI4IVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLint *params); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIEXTPROC) (GLuint program, GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLuint *params); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERSI4UIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint *params); -typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERIIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLint *params); -typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERIUIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLuint *params); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIUIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLuint *params); -typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIUIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIUIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLuint *params); -typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIUIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat v0); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint v0); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIEXTPROC) (GLuint program, GLint location, GLuint v0); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNGLNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLsizeiptr size, const GLvoid *data, GLenum usage); -typedef void (APIENTRYP PFNGLNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, const GLvoid *data); -typedef GLvoid* (APIENTRYP PFNGLMAPNAMEDBUFFEREXTPROC) (GLuint buffer, GLenum access); -typedef GLboolean (APIENTRYP PFNGLUNMAPNAMEDBUFFEREXTPROC) (GLuint buffer); -typedef GLvoid* (APIENTRYP PFNGLMAPNAMEDBUFFERRANGEEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); -typedef void (APIENTRYP PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length); -typedef void (APIENTRYP PFNGLNAMEDCOPYBUFFERSUBDATAEXTPROC) (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); -typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERIVEXTPROC) (GLuint buffer, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPOINTERVEXTPROC) (GLuint buffer, GLenum pname, GLvoid* *params); -typedef void (APIENTRYP PFNGLGETNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, GLvoid *data); -typedef void (APIENTRYP PFNGLTEXTUREBUFFEREXTPROC) (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer); -typedef void (APIENTRYP PFNGLMULTITEXBUFFEREXTPROC) (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer); -typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEEXTPROC) (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETNAMEDRENDERBUFFERPARAMETERIVEXTPROC) (GLuint renderbuffer, GLenum pname, GLint *params); -typedef GLenum (APIENTRYP PFNGLCHECKNAMEDFRAMEBUFFERSTATUSEXTPROC) (GLuint framebuffer, GLenum target); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE1DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE2DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE3DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERRENDERBUFFEREXTPROC) (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGENERATETEXTUREMIPMAPEXTPROC) (GLuint texture, GLenum target); -typedef void (APIENTRYP PFNGLGENERATEMULTITEXMIPMAPEXTPROC) (GLenum texunit, GLenum target); -typedef void (APIENTRYP PFNGLFRAMEBUFFERDRAWBUFFEREXTPROC) (GLuint framebuffer, GLenum mode); -typedef void (APIENTRYP PFNGLFRAMEBUFFERDRAWBUFFERSEXTPROC) (GLuint framebuffer, GLsizei n, const GLenum *bufs); -typedef void (APIENTRYP PFNGLFRAMEBUFFERREADBUFFEREXTPROC) (GLuint framebuffer, GLenum mode); -typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLECOVERAGEEXTPROC) (GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREEXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURELAYEREXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); -typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREFACEEXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLenum face); -typedef void (APIENTRYP PFNGLTEXTURERENDERBUFFEREXTPROC) (GLuint texture, GLenum target, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLMULTITEXRENDERBUFFEREXTPROC) (GLenum texunit, GLenum target, GLuint renderbuffer); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DEXTPROC) (GLuint program, GLint location, GLdouble x); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); -#endif - -#ifndef GL_EXT_vertex_array_bgra -#define GL_EXT_vertex_array_bgra 1 -#endif - -#ifndef GL_EXT_texture_swizzle -#define GL_EXT_texture_swizzle 1 -#endif - -#ifndef GL_NV_explicit_multisample -#define GL_NV_explicit_multisample 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetMultisamplefvNV (GLenum pname, GLuint index, GLfloat *val); -GLAPI void APIENTRY glSampleMaskIndexedNV (GLuint index, GLbitfield mask); -GLAPI void APIENTRY glTexRenderbufferNV (GLenum target, GLuint renderbuffer); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVNVPROC) (GLenum pname, GLuint index, GLfloat *val); -typedef void (APIENTRYP PFNGLSAMPLEMASKINDEXEDNVPROC) (GLuint index, GLbitfield mask); -typedef void (APIENTRYP PFNGLTEXRENDERBUFFERNVPROC) (GLenum target, GLuint renderbuffer); -#endif - -#ifndef GL_NV_transform_feedback2 -#define GL_NV_transform_feedback2 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBindTransformFeedbackNV (GLenum target, GLuint id); -GLAPI void APIENTRY glDeleteTransformFeedbacksNV (GLsizei n, const GLuint *ids); -GLAPI void APIENTRY glGenTransformFeedbacksNV (GLsizei n, GLuint *ids); -GLAPI GLboolean APIENTRY glIsTransformFeedbackNV (GLuint id); -GLAPI void APIENTRY glPauseTransformFeedbackNV (void); -GLAPI void APIENTRY glResumeTransformFeedbackNV (void); -GLAPI void APIENTRY glDrawTransformFeedbackNV (GLenum mode, GLuint id); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKNVPROC) (GLenum target, GLuint id); -typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSNVPROC) (GLsizei n, const GLuint *ids); -typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSNVPROC) (GLsizei n, GLuint *ids); -typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKNVPROC) (GLuint id); -typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKNVPROC) (void); -typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKNVPROC) (void); -typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKNVPROC) (GLenum mode, GLuint id); -#endif - -#ifndef GL_ATI_meminfo -#define GL_ATI_meminfo 1 -#endif - -#ifndef GL_AMD_performance_monitor -#define GL_AMD_performance_monitor 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetPerfMonitorGroupsAMD (GLint *numGroups, GLsizei groupsSize, GLuint *groups); -GLAPI void APIENTRY glGetPerfMonitorCountersAMD (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); -GLAPI void APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString); -GLAPI void APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString); -GLAPI void APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, GLvoid *data); -GLAPI void APIENTRY glGenPerfMonitorsAMD (GLsizei n, GLuint *monitors); -GLAPI void APIENTRY glDeletePerfMonitorsAMD (GLsizei n, GLuint *monitors); -GLAPI void APIENTRY glSelectPerfMonitorCountersAMD (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList); -GLAPI void APIENTRY glBeginPerfMonitorAMD (GLuint monitor); -GLAPI void APIENTRY glEndPerfMonitorAMD (GLuint monitor); -GLAPI void APIENTRY glGetPerfMonitorCounterDataAMD (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC) (GLint *numGroups, GLsizei groupsSize, GLuint *groups); -typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); -typedef void (APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString); -typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString); -typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, GLvoid *data); -typedef void (APIENTRYP PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors); -typedef void (APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors); -typedef void (APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC) (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList); -typedef void (APIENTRYP PFNGLBEGINPERFMONITORAMDPROC) (GLuint monitor); -typedef void (APIENTRYP PFNGLENDPERFMONITORAMDPROC) (GLuint monitor); -typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten); -#endif - -#ifndef GL_AMD_texture_texture4 -#define GL_AMD_texture_texture4 1 -#endif - -#ifndef GL_AMD_vertex_shader_tesselator -#define GL_AMD_vertex_shader_tesselator 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTessellationFactorAMD (GLfloat factor); -GLAPI void APIENTRY glTessellationModeAMD (GLenum mode); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTESSELLATIONFACTORAMDPROC) (GLfloat factor); -typedef void (APIENTRYP PFNGLTESSELLATIONMODEAMDPROC) (GLenum mode); -#endif - -#ifndef GL_EXT_provoking_vertex -#define GL_EXT_provoking_vertex 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProvokingVertexEXT (GLenum mode); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPROVOKINGVERTEXEXTPROC) (GLenum mode); -#endif - -#ifndef GL_EXT_texture_snorm -#define GL_EXT_texture_snorm 1 -#endif - -#ifndef GL_AMD_draw_buffers_blend -#define GL_AMD_draw_buffers_blend 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendFuncIndexedAMD (GLuint buf, GLenum src, GLenum dst); -GLAPI void APIENTRY glBlendFuncSeparateIndexedAMD (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); -GLAPI void APIENTRY glBlendEquationIndexedAMD (GLuint buf, GLenum mode); -GLAPI void APIENTRY glBlendEquationSeparateIndexedAMD (GLuint buf, GLenum modeRGB, GLenum modeAlpha); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBLENDFUNCINDEXEDAMDPROC) (GLuint buf, GLenum src, GLenum dst); -typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINDEXEDAMDPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); -typedef void (APIENTRYP PFNGLBLENDEQUATIONINDEXEDAMDPROC) (GLuint buf, GLenum mode); -typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEINDEXEDAMDPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); -#endif - -#ifndef GL_APPLE_texture_range -#define GL_APPLE_texture_range 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTextureRangeAPPLE (GLenum target, GLsizei length, const GLvoid *pointer); -GLAPI void APIENTRY glGetTexParameterPointervAPPLE (GLenum target, GLenum pname, GLvoid* *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTEXTURERANGEAPPLEPROC) (GLenum target, GLsizei length, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLGETTEXPARAMETERPOINTERVAPPLEPROC) (GLenum target, GLenum pname, GLvoid* *params); -#endif - -#ifndef GL_APPLE_float_pixels -#define GL_APPLE_float_pixels 1 -#endif - -#ifndef GL_APPLE_vertex_program_evaluators -#define GL_APPLE_vertex_program_evaluators 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glEnableVertexAttribAPPLE (GLuint index, GLenum pname); -GLAPI void APIENTRY glDisableVertexAttribAPPLE (GLuint index, GLenum pname); -GLAPI GLboolean APIENTRY glIsVertexAttribEnabledAPPLE (GLuint index, GLenum pname); -GLAPI void APIENTRY glMapVertexAttrib1dAPPLE (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); -GLAPI void APIENTRY glMapVertexAttrib1fAPPLE (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); -GLAPI void APIENTRY glMapVertexAttrib2dAPPLE (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); -GLAPI void APIENTRY glMapVertexAttrib2fAPPLE (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBAPPLEPROC) (GLuint index, GLenum pname); -typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBAPPLEPROC) (GLuint index, GLenum pname); -typedef GLboolean (APIENTRYP PFNGLISVERTEXATTRIBENABLEDAPPLEPROC) (GLuint index, GLenum pname); -typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB1DAPPLEPROC) (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); -typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB1FAPPLEPROC) (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); -typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB2DAPPLEPROC) (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); -typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB2FAPPLEPROC) (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); -#endif - -#ifndef GL_APPLE_aux_depth_stencil -#define GL_APPLE_aux_depth_stencil 1 -#endif - -#ifndef GL_APPLE_object_purgeable -#define GL_APPLE_object_purgeable 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLenum APIENTRY glObjectPurgeableAPPLE (GLenum objectType, GLuint name, GLenum option); -GLAPI GLenum APIENTRY glObjectUnpurgeableAPPLE (GLenum objectType, GLuint name, GLenum option); -GLAPI void APIENTRY glGetObjectParameterivAPPLE (GLenum objectType, GLuint name, GLenum pname, GLint *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLenum (APIENTRYP PFNGLOBJECTPURGEABLEAPPLEPROC) (GLenum objectType, GLuint name, GLenum option); -typedef GLenum (APIENTRYP PFNGLOBJECTUNPURGEABLEAPPLEPROC) (GLenum objectType, GLuint name, GLenum option); -typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVAPPLEPROC) (GLenum objectType, GLuint name, GLenum pname, GLint *params); -#endif - -#ifndef GL_APPLE_row_bytes -#define GL_APPLE_row_bytes 1 -#endif - -#ifndef GL_APPLE_rgb_422 -#define GL_APPLE_rgb_422 1 -#endif - -#ifndef GL_NV_video_capture -#define GL_NV_video_capture 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBeginVideoCaptureNV (GLuint video_capture_slot); -GLAPI void APIENTRY glBindVideoCaptureStreamBufferNV (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLintptrARB offset); -GLAPI void APIENTRY glBindVideoCaptureStreamTextureNV (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLenum target, GLuint texture); -GLAPI void APIENTRY glEndVideoCaptureNV (GLuint video_capture_slot); -GLAPI void APIENTRY glGetVideoCaptureivNV (GLuint video_capture_slot, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVideoCaptureStreamivNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVideoCaptureStreamfvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLfloat *params); -GLAPI void APIENTRY glGetVideoCaptureStreamdvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLdouble *params); -GLAPI GLenum APIENTRY glVideoCaptureNV (GLuint video_capture_slot, GLuint *sequence_num, GLuint64EXT *capture_time); -GLAPI void APIENTRY glVideoCaptureStreamParameterivNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLint *params); -GLAPI void APIENTRY glVideoCaptureStreamParameterfvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glVideoCaptureStreamParameterdvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLdouble *params); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBEGINVIDEOCAPTURENVPROC) (GLuint video_capture_slot); -typedef void (APIENTRYP PFNGLBINDVIDEOCAPTURESTREAMBUFFERNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLintptrARB offset); -typedef void (APIENTRYP PFNGLBINDVIDEOCAPTURESTREAMTEXTURENVPROC) (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLenum target, GLuint texture); -typedef void (APIENTRYP PFNGLENDVIDEOCAPTURENVPROC) (GLuint video_capture_slot); -typedef void (APIENTRYP PFNGLGETVIDEOCAPTUREIVNVPROC) (GLuint video_capture_slot, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMIVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMFVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMDVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLdouble *params); -typedef GLenum (APIENTRYP PFNGLVIDEOCAPTURENVPROC) (GLuint video_capture_slot, GLuint *sequence_num, GLuint64EXT *capture_time); -typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERIVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERFVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERDVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLdouble *params); -#endif - -#ifndef GL_NV_copy_image -#define GL_NV_copy_image 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glCopyImageSubDataNV (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLCOPYIMAGESUBDATANVPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); -#endif - -#ifndef GL_EXT_separate_shader_objects -#define GL_EXT_separate_shader_objects 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glUseShaderProgramEXT (GLenum type, GLuint program); -GLAPI void APIENTRY glActiveProgramEXT (GLuint program); -GLAPI GLuint APIENTRY glCreateShaderProgramEXT (GLenum type, const GLchar *string); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLUSESHADERPROGRAMEXTPROC) (GLenum type, GLuint program); -typedef void (APIENTRYP PFNGLACTIVEPROGRAMEXTPROC) (GLuint program); -typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMEXTPROC) (GLenum type, const GLchar *string); -#endif - -#ifndef GL_NV_parameter_buffer_object2 -#define GL_NV_parameter_buffer_object2 1 -#endif - -#ifndef GL_NV_shader_buffer_load -#define GL_NV_shader_buffer_load 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMakeBufferResidentNV (GLenum target, GLenum access); -GLAPI void APIENTRY glMakeBufferNonResidentNV (GLenum target); -GLAPI GLboolean APIENTRY glIsBufferResidentNV (GLenum target); -GLAPI void APIENTRY glMakeNamedBufferResidentNV (GLuint buffer, GLenum access); -GLAPI void APIENTRY glMakeNamedBufferNonResidentNV (GLuint buffer); -GLAPI GLboolean APIENTRY glIsNamedBufferResidentNV (GLuint buffer); -GLAPI void APIENTRY glGetBufferParameterui64vNV (GLenum target, GLenum pname, GLuint64EXT *params); -GLAPI void APIENTRY glGetNamedBufferParameterui64vNV (GLuint buffer, GLenum pname, GLuint64EXT *params); -GLAPI void APIENTRY glGetIntegerui64vNV (GLenum value, GLuint64EXT *result); -GLAPI void APIENTRY glUniformui64NV (GLint location, GLuint64EXT value); -GLAPI void APIENTRY glUniformui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glGetUniformui64vNV (GLuint program, GLint location, GLuint64EXT *params); -GLAPI void APIENTRY glProgramUniformui64NV (GLuint program, GLint location, GLuint64EXT value); -GLAPI void APIENTRY glProgramUniformui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLMAKEBUFFERRESIDENTNVPROC) (GLenum target, GLenum access); -typedef void (APIENTRYP PFNGLMAKEBUFFERNONRESIDENTNVPROC) (GLenum target); -typedef GLboolean (APIENTRYP PFNGLISBUFFERRESIDENTNVPROC) (GLenum target); -typedef void (APIENTRYP PFNGLMAKENAMEDBUFFERRESIDENTNVPROC) (GLuint buffer, GLenum access); -typedef void (APIENTRYP PFNGLMAKENAMEDBUFFERNONRESIDENTNVPROC) (GLuint buffer); -typedef GLboolean (APIENTRYP PFNGLISNAMEDBUFFERRESIDENTNVPROC) (GLuint buffer); -typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERUI64VNVPROC) (GLenum target, GLenum pname, GLuint64EXT *params); -typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERUI64VNVPROC) (GLuint buffer, GLenum pname, GLuint64EXT *params); -typedef void (APIENTRYP PFNGLGETINTEGERUI64VNVPROC) (GLenum value, GLuint64EXT *result); -typedef void (APIENTRYP PFNGLUNIFORMUI64NVPROC) (GLint location, GLuint64EXT value); -typedef void (APIENTRYP PFNGLUNIFORMUI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLGETUNIFORMUI64VNVPROC) (GLuint program, GLint location, GLuint64EXT *params); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMUI64NVPROC) (GLuint program, GLint location, GLuint64EXT value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORMUI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -#endif - -#ifndef GL_NV_vertex_buffer_unified_memory -#define GL_NV_vertex_buffer_unified_memory 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBufferAddressRangeNV (GLenum pname, GLuint index, GLuint64EXT address, GLsizeiptr length); -GLAPI void APIENTRY glVertexFormatNV (GLint size, GLenum type, GLsizei stride); -GLAPI void APIENTRY glNormalFormatNV (GLenum type, GLsizei stride); -GLAPI void APIENTRY glColorFormatNV (GLint size, GLenum type, GLsizei stride); -GLAPI void APIENTRY glIndexFormatNV (GLenum type, GLsizei stride); -GLAPI void APIENTRY glTexCoordFormatNV (GLint size, GLenum type, GLsizei stride); -GLAPI void APIENTRY glEdgeFlagFormatNV (GLsizei stride); -GLAPI void APIENTRY glSecondaryColorFormatNV (GLint size, GLenum type, GLsizei stride); -GLAPI void APIENTRY glFogCoordFormatNV (GLenum type, GLsizei stride); -GLAPI void APIENTRY glVertexAttribFormatNV (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride); -GLAPI void APIENTRY glVertexAttribIFormatNV (GLuint index, GLint size, GLenum type, GLsizei stride); -GLAPI void APIENTRY glGetIntegerui64i_vNV (GLenum value, GLuint index, GLuint64EXT *result); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBUFFERADDRESSRANGENVPROC) (GLenum pname, GLuint index, GLuint64EXT address, GLsizeiptr length); -typedef void (APIENTRYP PFNGLVERTEXFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLNORMALFORMATNVPROC) (GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLCOLORFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLINDEXFORMATNVPROC) (GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLTEXCOORDFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLEDGEFLAGFORMATNVPROC) (GLsizei stride); -typedef void (APIENTRYP PFNGLSECONDARYCOLORFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLFOGCOORDFORMATNVPROC) (GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride); -typedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLsizei stride); -typedef void (APIENTRYP PFNGLGETINTEGERUI64I_VNVPROC) (GLenum value, GLuint index, GLuint64EXT *result); -#endif - -#ifndef GL_NV_texture_barrier -#define GL_NV_texture_barrier 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTextureBarrierNV (void); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTEXTUREBARRIERNVPROC) (void); -#endif - -#ifndef GL_AMD_shader_stencil_export -#define GL_AMD_shader_stencil_export 1 -#endif - -#ifndef GL_AMD_seamless_cubemap_per_texture -#define GL_AMD_seamless_cubemap_per_texture 1 -#endif - -#ifndef GL_AMD_conservative_depth -#define GL_AMD_conservative_depth 1 -#endif - -#ifndef GL_EXT_shader_image_load_store -#define GL_EXT_shader_image_load_store 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBindImageTextureEXT (GLuint index, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLint format); -GLAPI void APIENTRY glMemoryBarrierEXT (GLbitfield barriers); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREEXTPROC) (GLuint index, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLint format); -typedef void (APIENTRYP PFNGLMEMORYBARRIEREXTPROC) (GLbitfield barriers); -#endif - -#ifndef GL_EXT_vertex_attrib_64bit -#define GL_EXT_vertex_attrib_64bit 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexAttribL1dEXT (GLuint index, GLdouble x); -GLAPI void APIENTRY glVertexAttribL2dEXT (GLuint index, GLdouble x, GLdouble y); -GLAPI void APIENTRY glVertexAttribL3dEXT (GLuint index, GLdouble x, GLdouble y, GLdouble z); -GLAPI void APIENTRY glVertexAttribL4dEXT (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI void APIENTRY glVertexAttribL1dvEXT (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribL2dvEXT (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribL3dvEXT (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribL4dvEXT (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribLPointerEXT (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -GLAPI void APIENTRY glGetVertexAttribLdvEXT (GLuint index, GLenum pname, GLdouble *params); -GLAPI void APIENTRY glVertexArrayVertexAttribLOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DEXTPROC) (GLuint index, GLdouble x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DEXTPROC) (GLuint index, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DEXTPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DEXTPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVEXTPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVEXTPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVEXTPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVEXTPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVEXTPROC) (GLuint index, GLenum pname, GLdouble *params); -typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBLOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); -#endif - -#ifndef GL_NV_gpu_program5 -#define GL_NV_gpu_program5 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProgramSubroutineParametersuivNV (GLenum target, GLsizei count, const GLuint *params); -GLAPI void APIENTRY glGetProgramSubroutineParameteruivNV (GLenum target, GLuint index, GLuint *param); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLPROGRAMSUBROUTINEPARAMETERSUIVNVPROC) (GLenum target, GLsizei count, const GLuint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMSUBROUTINEPARAMETERUIVNVPROC) (GLenum target, GLuint index, GLuint *param); -#endif - -#ifndef GL_NV_gpu_shader5 -#define GL_NV_gpu_shader5 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glUniform1i64NV (GLint location, GLint64EXT x); -GLAPI void APIENTRY glUniform2i64NV (GLint location, GLint64EXT x, GLint64EXT y); -GLAPI void APIENTRY glUniform3i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); -GLAPI void APIENTRY glUniform4i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); -GLAPI void APIENTRY glUniform1i64vNV (GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glUniform2i64vNV (GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glUniform3i64vNV (GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glUniform4i64vNV (GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glUniform1ui64NV (GLint location, GLuint64EXT x); -GLAPI void APIENTRY glUniform2ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y); -GLAPI void APIENTRY glUniform3ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); -GLAPI void APIENTRY glUniform4ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); -GLAPI void APIENTRY glUniform1ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glUniform2ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glUniform3ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glUniform4ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glGetUniformi64vNV (GLuint program, GLint location, GLint64EXT *params); -GLAPI void APIENTRY glProgramUniform1i64NV (GLuint program, GLint location, GLint64EXT x); -GLAPI void APIENTRY glProgramUniform2i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y); -GLAPI void APIENTRY glProgramUniform3i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); -GLAPI void APIENTRY glProgramUniform4i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); -GLAPI void APIENTRY glProgramUniform1i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glProgramUniform2i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glProgramUniform3i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glProgramUniform4i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glProgramUniform1ui64NV (GLuint program, GLint location, GLuint64EXT x); -GLAPI void APIENTRY glProgramUniform2ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y); -GLAPI void APIENTRY glProgramUniform3ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); -GLAPI void APIENTRY glProgramUniform4ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); -GLAPI void APIENTRY glProgramUniform1ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glProgramUniform2ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glProgramUniform3ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glProgramUniform4ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLUNIFORM1I64NVPROC) (GLint location, GLint64EXT x); -typedef void (APIENTRYP PFNGLUNIFORM2I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y); -typedef void (APIENTRYP PFNGLUNIFORM3I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); -typedef void (APIENTRYP PFNGLUNIFORM4I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); -typedef void (APIENTRYP PFNGLUNIFORM1I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM2I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM3I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM4I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM1UI64NVPROC) (GLint location, GLuint64EXT x); -typedef void (APIENTRYP PFNGLUNIFORM2UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y); -typedef void (APIENTRYP PFNGLUNIFORM3UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); -typedef void (APIENTRYP PFNGLUNIFORM4UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); -typedef void (APIENTRYP PFNGLUNIFORM1UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM2UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM3UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM4UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLGETUNIFORMI64VNVPROC) (GLuint program, GLint location, GLint64EXT *params); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64NVPROC) (GLuint program, GLint location, GLint64EXT x); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -#endif - -#ifndef GL_NV_shader_buffer_store -#define GL_NV_shader_buffer_store 1 -#endif - -#ifndef GL_NV_tessellation_program5 -#define GL_NV_tessellation_program5 1 -#endif - -#ifndef GL_NV_vertex_attrib_integer_64bit -#define GL_NV_vertex_attrib_integer_64bit 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexAttribL1i64NV (GLuint index, GLint64EXT x); -GLAPI void APIENTRY glVertexAttribL2i64NV (GLuint index, GLint64EXT x, GLint64EXT y); -GLAPI void APIENTRY glVertexAttribL3i64NV (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z); -GLAPI void APIENTRY glVertexAttribL4i64NV (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); -GLAPI void APIENTRY glVertexAttribL1i64vNV (GLuint index, const GLint64EXT *v); -GLAPI void APIENTRY glVertexAttribL2i64vNV (GLuint index, const GLint64EXT *v); -GLAPI void APIENTRY glVertexAttribL3i64vNV (GLuint index, const GLint64EXT *v); -GLAPI void APIENTRY glVertexAttribL4i64vNV (GLuint index, const GLint64EXT *v); -GLAPI void APIENTRY glVertexAttribL1ui64NV (GLuint index, GLuint64EXT x); -GLAPI void APIENTRY glVertexAttribL2ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y); -GLAPI void APIENTRY glVertexAttribL3ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); -GLAPI void APIENTRY glVertexAttribL4ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); -GLAPI void APIENTRY glVertexAttribL1ui64vNV (GLuint index, const GLuint64EXT *v); -GLAPI void APIENTRY glVertexAttribL2ui64vNV (GLuint index, const GLuint64EXT *v); -GLAPI void APIENTRY glVertexAttribL3ui64vNV (GLuint index, const GLuint64EXT *v); -GLAPI void APIENTRY glVertexAttribL4ui64vNV (GLuint index, const GLuint64EXT *v); -GLAPI void APIENTRY glGetVertexAttribLi64vNV (GLuint index, GLenum pname, GLint64EXT *params); -GLAPI void APIENTRY glGetVertexAttribLui64vNV (GLuint index, GLenum pname, GLuint64EXT *params); -GLAPI void APIENTRY glVertexAttribLFormatNV (GLuint index, GLint size, GLenum type, GLsizei stride); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1I64NVPROC) (GLuint index, GLint64EXT x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1I64VNVPROC) (GLuint index, const GLint64EXT *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2I64VNVPROC) (GLuint index, const GLint64EXT *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3I64VNVPROC) (GLuint index, const GLint64EXT *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4I64VNVPROC) (GLuint index, const GLint64EXT *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64NVPROC) (GLuint index, GLuint64EXT x); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64VNVPROC) (GLuint index, const GLuint64EXT *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL2UI64VNVPROC) (GLuint index, const GLuint64EXT *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL3UI64VNVPROC) (GLuint index, const GLuint64EXT *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBL4UI64VNVPROC) (GLuint index, const GLuint64EXT *v); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLI64VNVPROC) (GLuint index, GLenum pname, GLint64EXT *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLUI64VNVPROC) (GLuint index, GLenum pname, GLuint64EXT *params); -typedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLsizei stride); -#endif - -#ifndef GL_NV_multisample_coverage -#define GL_NV_multisample_coverage 1 -#endif - -#ifndef GL_AMD_name_gen_delete -#define GL_AMD_name_gen_delete 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGenNamesAMD (GLenum identifier, GLuint num, GLuint *names); -GLAPI void APIENTRY glDeleteNamesAMD (GLenum identifier, GLuint num, const GLuint *names); -GLAPI GLboolean APIENTRY glIsNameAMD (GLenum identifier, GLuint name); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLGENNAMESAMDPROC) (GLenum identifier, GLuint num, GLuint *names); -typedef void (APIENTRYP PFNGLDELETENAMESAMDPROC) (GLenum identifier, GLuint num, const GLuint *names); -typedef GLboolean (APIENTRYP PFNGLISNAMEAMDPROC) (GLenum identifier, GLuint name); -#endif - -#ifndef GL_AMD_debug_output -#define GL_AMD_debug_output 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDebugMessageEnableAMD (GLenum category, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); -GLAPI void APIENTRY glDebugMessageInsertAMD (GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar *buf); -GLAPI void APIENTRY glDebugMessageCallbackAMD (GLDEBUGPROCAMD callback, GLvoid *userParam); -GLAPI GLuint APIENTRY glGetDebugMessageLogAMD (GLuint count, GLsizei bufsize, GLenum *categories, GLuint *severities, GLuint *ids, GLsizei *lengths, GLchar *message); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDEBUGMESSAGEENABLEAMDPROC) (GLenum category, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); -typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTAMDPROC) (GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar *buf); -typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKAMDPROC) (GLDEBUGPROCAMD callback, GLvoid *userParam); -typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGAMDPROC) (GLuint count, GLsizei bufsize, GLenum *categories, GLuint *severities, GLuint *ids, GLsizei *lengths, GLchar *message); -#endif - -#ifndef GL_NV_vdpau_interop -#define GL_NV_vdpau_interop 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVDPAUInitNV (const GLvoid *vdpDevice, const GLvoid *getProcAddress); -GLAPI void APIENTRY glVDPAUFiniNV (void); -GLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterVideoSurfaceNV (GLvoid *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); -GLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterOutputSurfaceNV (GLvoid *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); -GLAPI void APIENTRY glVDPAUIsSurfaceNV (GLvdpauSurfaceNV surface); -GLAPI void APIENTRY glVDPAUUnregisterSurfaceNV (GLvdpauSurfaceNV surface); -GLAPI void APIENTRY glVDPAUGetSurfaceivNV (GLvdpauSurfaceNV surface, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); -GLAPI void APIENTRY glVDPAUSurfaceAccessNV (GLvdpauSurfaceNV surface, GLenum access); -GLAPI void APIENTRY glVDPAUMapSurfacesNV (GLsizei numSurfaces, const GLvdpauSurfaceNV *surfaces); -GLAPI void APIENTRY glVDPAUUnmapSurfacesNV (GLsizei numSurface, const GLvdpauSurfaceNV *surfaces); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLVDPAUINITNVPROC) (const GLvoid *vdpDevice, const GLvoid *getProcAddress); -typedef void (APIENTRYP PFNGLVDPAUFININVPROC) (void); -typedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTERVIDEOSURFACENVPROC) (GLvoid *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); -typedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC) (GLvoid *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); -typedef void (APIENTRYP PFNGLVDPAUISSURFACENVPROC) (GLvdpauSurfaceNV surface); -typedef void (APIENTRYP PFNGLVDPAUUNREGISTERSURFACENVPROC) (GLvdpauSurfaceNV surface); -typedef void (APIENTRYP PFNGLVDPAUGETSURFACEIVNVPROC) (GLvdpauSurfaceNV surface, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); -typedef void (APIENTRYP PFNGLVDPAUSURFACEACCESSNVPROC) (GLvdpauSurfaceNV surface, GLenum access); -typedef void (APIENTRYP PFNGLVDPAUMAPSURFACESNVPROC) (GLsizei numSurfaces, const GLvdpauSurfaceNV *surfaces); -typedef void (APIENTRYP PFNGLVDPAUUNMAPSURFACESNVPROC) (GLsizei numSurface, const GLvdpauSurfaceNV *surfaces); -#endif - -#ifndef GL_AMD_transform_feedback3_lines_triangles -#define GL_AMD_transform_feedback3_lines_triangles 1 -#endif - -#ifndef GL_AMD_depth_clamp_separate -#define GL_AMD_depth_clamp_separate 1 -#endif - -#ifndef GL_EXT_texture_sRGB_decode -#define GL_EXT_texture_sRGB_decode 1 -#endif - -#ifndef GL_NV_texture_multisample -#define GL_NV_texture_multisample 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexImage2DMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); -GLAPI void APIENTRY glTexImage3DMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); -GLAPI void APIENTRY glTextureImage2DMultisampleNV (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); -GLAPI void APIENTRY glTextureImage3DMultisampleNV (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); -GLAPI void APIENTRY glTextureImage2DMultisampleCoverageNV (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); -GLAPI void APIENTRY glTextureImage3DMultisampleCoverageNV (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); -typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); -typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DMULTISAMPLENVPROC) (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); -typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DMULTISAMPLENVPROC) (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); -typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DMULTISAMPLECOVERAGENVPROC) (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); -typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DMULTISAMPLECOVERAGENVPROC) (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); -#endif - -#ifndef GL_AMD_blend_minmax_factor -#define GL_AMD_blend_minmax_factor 1 -#endif - -#ifndef GL_AMD_sample_positions -#define GL_AMD_sample_positions 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glSetMultisamplefvAMD (GLenum pname, GLuint index, const GLfloat *val); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLSETMULTISAMPLEFVAMDPROC) (GLenum pname, GLuint index, const GLfloat *val); -#endif - -#ifndef GL_EXT_x11_sync_object -#define GL_EXT_x11_sync_object 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLsync APIENTRY glImportSyncEXT (GLenum external_sync_type, GLintptr external_sync, GLbitfield flags); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLsync (APIENTRYP PFNGLIMPORTSYNCEXTPROC) (GLenum external_sync_type, GLintptr external_sync, GLbitfield flags); -#endif - -#ifndef GL_AMD_multi_draw_indirect -#define GL_AMD_multi_draw_indirect 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMultiDrawArraysIndirectAMD (GLenum mode, const GLvoid *indirect, GLsizei primcount, GLsizei stride); -GLAPI void APIENTRY glMultiDrawElementsIndirectAMD (GLenum mode, GLenum type, const GLvoid *indirect, GLsizei primcount, GLsizei stride); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTAMDPROC) (GLenum mode, const GLvoid *indirect, GLsizei primcount, GLsizei stride); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTAMDPROC) (GLenum mode, GLenum type, const GLvoid *indirect, GLsizei primcount, GLsizei stride); -#endif - -#ifndef GL_EXT_framebuffer_multisample_blit_scaled -#define GL_EXT_framebuffer_multisample_blit_scaled 1 -#endif - -#ifndef GL_NV_path_rendering -#define GL_NV_path_rendering 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI GLuint APIENTRY glGenPathsNV (GLsizei range); -GLAPI void APIENTRY glDeletePathsNV (GLuint path, GLsizei range); -GLAPI GLboolean APIENTRY glIsPathNV (GLuint path); -GLAPI void APIENTRY glPathCommandsNV (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const GLvoid *coords); -GLAPI void APIENTRY glPathCoordsNV (GLuint path, GLsizei numCoords, GLenum coordType, const GLvoid *coords); -GLAPI void APIENTRY glPathSubCommandsNV (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const GLvoid *coords); -GLAPI void APIENTRY glPathSubCoordsNV (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const GLvoid *coords); -GLAPI void APIENTRY glPathStringNV (GLuint path, GLenum format, GLsizei length, const GLvoid *pathString); -GLAPI void APIENTRY glPathGlyphsNV (GLuint firstPathName, GLenum fontTarget, const GLvoid *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const GLvoid *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); -GLAPI void APIENTRY glPathGlyphRangeNV (GLuint firstPathName, GLenum fontTarget, const GLvoid *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); -GLAPI void APIENTRY glWeightPathsNV (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights); -GLAPI void APIENTRY glCopyPathNV (GLuint resultPath, GLuint srcPath); -GLAPI void APIENTRY glInterpolatePathsNV (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight); -GLAPI void APIENTRY glTransformPathNV (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues); -GLAPI void APIENTRY glPathParameterivNV (GLuint path, GLenum pname, const GLint *value); -GLAPI void APIENTRY glPathParameteriNV (GLuint path, GLenum pname, GLint value); -GLAPI void APIENTRY glPathParameterfvNV (GLuint path, GLenum pname, const GLfloat *value); -GLAPI void APIENTRY glPathParameterfNV (GLuint path, GLenum pname, GLfloat value); -GLAPI void APIENTRY glPathDashArrayNV (GLuint path, GLsizei dashCount, const GLfloat *dashArray); -GLAPI void APIENTRY glPathStencilFuncNV (GLenum func, GLint ref, GLuint mask); -GLAPI void APIENTRY glPathStencilDepthOffsetNV (GLfloat factor, GLfloat units); -GLAPI void APIENTRY glStencilFillPathNV (GLuint path, GLenum fillMode, GLuint mask); -GLAPI void APIENTRY glStencilStrokePathNV (GLuint path, GLint reference, GLuint mask); -GLAPI void APIENTRY glStencilFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues); -GLAPI void APIENTRY glStencilStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues); -GLAPI void APIENTRY glPathCoverDepthFuncNV (GLenum func); -GLAPI void APIENTRY glPathColorGenNV (GLenum color, GLenum genMode, GLenum colorFormat, const GLfloat *coeffs); -GLAPI void APIENTRY glPathTexGenNV (GLenum texCoordSet, GLenum genMode, GLint components, const GLfloat *coeffs); -GLAPI void APIENTRY glPathFogGenNV (GLenum genMode); -GLAPI void APIENTRY glCoverFillPathNV (GLuint path, GLenum coverMode); -GLAPI void APIENTRY glCoverStrokePathNV (GLuint path, GLenum coverMode); -GLAPI void APIENTRY glCoverFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); -GLAPI void APIENTRY glCoverStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); -GLAPI void APIENTRY glGetPathParameterivNV (GLuint path, GLenum pname, GLint *value); -GLAPI void APIENTRY glGetPathParameterfvNV (GLuint path, GLenum pname, GLfloat *value); -GLAPI void APIENTRY glGetPathCommandsNV (GLuint path, GLubyte *commands); -GLAPI void APIENTRY glGetPathCoordsNV (GLuint path, GLfloat *coords); -GLAPI void APIENTRY glGetPathDashArrayNV (GLuint path, GLfloat *dashArray); -GLAPI void APIENTRY glGetPathMetricsNV (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics); -GLAPI void APIENTRY glGetPathMetricRangeNV (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics); -GLAPI void APIENTRY glGetPathSpacingNV (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing); -GLAPI void APIENTRY glGetPathColorGenivNV (GLenum color, GLenum pname, GLint *value); -GLAPI void APIENTRY glGetPathColorGenfvNV (GLenum color, GLenum pname, GLfloat *value); -GLAPI void APIENTRY glGetPathTexGenivNV (GLenum texCoordSet, GLenum pname, GLint *value); -GLAPI void APIENTRY glGetPathTexGenfvNV (GLenum texCoordSet, GLenum pname, GLfloat *value); -GLAPI GLboolean APIENTRY glIsPointInFillPathNV (GLuint path, GLuint mask, GLfloat x, GLfloat y); -GLAPI GLboolean APIENTRY glIsPointInStrokePathNV (GLuint path, GLfloat x, GLfloat y); -GLAPI GLfloat APIENTRY glGetPathLengthNV (GLuint path, GLsizei startSegment, GLsizei numSegments); -GLAPI GLboolean APIENTRY glPointAlongPathNV (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef GLuint (APIENTRYP PFNGLGENPATHSNVPROC) (GLsizei range); -typedef void (APIENTRYP PFNGLDELETEPATHSNVPROC) (GLuint path, GLsizei range); -typedef GLboolean (APIENTRYP PFNGLISPATHNVPROC) (GLuint path); -typedef void (APIENTRYP PFNGLPATHCOMMANDSNVPROC) (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const GLvoid *coords); -typedef void (APIENTRYP PFNGLPATHCOORDSNVPROC) (GLuint path, GLsizei numCoords, GLenum coordType, const GLvoid *coords); -typedef void (APIENTRYP PFNGLPATHSUBCOMMANDSNVPROC) (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const GLvoid *coords); -typedef void (APIENTRYP PFNGLPATHSUBCOORDSNVPROC) (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const GLvoid *coords); -typedef void (APIENTRYP PFNGLPATHSTRINGNVPROC) (GLuint path, GLenum format, GLsizei length, const GLvoid *pathString); -typedef void (APIENTRYP PFNGLPATHGLYPHSNVPROC) (GLuint firstPathName, GLenum fontTarget, const GLvoid *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const GLvoid *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); -typedef void (APIENTRYP PFNGLPATHGLYPHRANGENVPROC) (GLuint firstPathName, GLenum fontTarget, const GLvoid *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); -typedef void (APIENTRYP PFNGLWEIGHTPATHSNVPROC) (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights); -typedef void (APIENTRYP PFNGLCOPYPATHNVPROC) (GLuint resultPath, GLuint srcPath); -typedef void (APIENTRYP PFNGLINTERPOLATEPATHSNVPROC) (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight); -typedef void (APIENTRYP PFNGLTRANSFORMPATHNVPROC) (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues); -typedef void (APIENTRYP PFNGLPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, const GLint *value); -typedef void (APIENTRYP PFNGLPATHPARAMETERINVPROC) (GLuint path, GLenum pname, GLint value); -typedef void (APIENTRYP PFNGLPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, const GLfloat *value); -typedef void (APIENTRYP PFNGLPATHPARAMETERFNVPROC) (GLuint path, GLenum pname, GLfloat value); -typedef void (APIENTRYP PFNGLPATHDASHARRAYNVPROC) (GLuint path, GLsizei dashCount, const GLfloat *dashArray); -typedef void (APIENTRYP PFNGLPATHSTENCILFUNCNVPROC) (GLenum func, GLint ref, GLuint mask); -typedef void (APIENTRYP PFNGLPATHSTENCILDEPTHOFFSETNVPROC) (GLfloat factor, GLfloat units); -typedef void (APIENTRYP PFNGLSTENCILFILLPATHNVPROC) (GLuint path, GLenum fillMode, GLuint mask); -typedef void (APIENTRYP PFNGLSTENCILSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask); -typedef void (APIENTRYP PFNGLSTENCILFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues); -typedef void (APIENTRYP PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues); -typedef void (APIENTRYP PFNGLPATHCOVERDEPTHFUNCNVPROC) (GLenum func); -typedef void (APIENTRYP PFNGLPATHCOLORGENNVPROC) (GLenum color, GLenum genMode, GLenum colorFormat, const GLfloat *coeffs); -typedef void (APIENTRYP PFNGLPATHTEXGENNVPROC) (GLenum texCoordSet, GLenum genMode, GLint components, const GLfloat *coeffs); -typedef void (APIENTRYP PFNGLPATHFOGGENNVPROC) (GLenum genMode); -typedef void (APIENTRYP PFNGLCOVERFILLPATHNVPROC) (GLuint path, GLenum coverMode); -typedef void (APIENTRYP PFNGLCOVERSTROKEPATHNVPROC) (GLuint path, GLenum coverMode); -typedef void (APIENTRYP PFNGLCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); -typedef void (APIENTRYP PFNGLCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); -typedef void (APIENTRYP PFNGLGETPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, GLint *value); -typedef void (APIENTRYP PFNGLGETPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, GLfloat *value); -typedef void (APIENTRYP PFNGLGETPATHCOMMANDSNVPROC) (GLuint path, GLubyte *commands); -typedef void (APIENTRYP PFNGLGETPATHCOORDSNVPROC) (GLuint path, GLfloat *coords); -typedef void (APIENTRYP PFNGLGETPATHDASHARRAYNVPROC) (GLuint path, GLfloat *dashArray); -typedef void (APIENTRYP PFNGLGETPATHMETRICSNVPROC) (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics); -typedef void (APIENTRYP PFNGLGETPATHMETRICRANGENVPROC) (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics); -typedef void (APIENTRYP PFNGLGETPATHSPACINGNVPROC) (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing); -typedef void (APIENTRYP PFNGLGETPATHCOLORGENIVNVPROC) (GLenum color, GLenum pname, GLint *value); -typedef void (APIENTRYP PFNGLGETPATHCOLORGENFVNVPROC) (GLenum color, GLenum pname, GLfloat *value); -typedef void (APIENTRYP PFNGLGETPATHTEXGENIVNVPROC) (GLenum texCoordSet, GLenum pname, GLint *value); -typedef void (APIENTRYP PFNGLGETPATHTEXGENFVNVPROC) (GLenum texCoordSet, GLenum pname, GLfloat *value); -typedef GLboolean (APIENTRYP PFNGLISPOINTINFILLPATHNVPROC) (GLuint path, GLuint mask, GLfloat x, GLfloat y); -typedef GLboolean (APIENTRYP PFNGLISPOINTINSTROKEPATHNVPROC) (GLuint path, GLfloat x, GLfloat y); -typedef GLfloat (APIENTRYP PFNGLGETPATHLENGTHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments); -typedef GLboolean (APIENTRYP PFNGLPOINTALONGPATHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY); -#endif - -#ifndef GL_AMD_pinned_memory -#define GL_AMD_pinned_memory 1 -#endif - -#ifndef GL_AMD_stencil_operation_extended -#define GL_AMD_stencil_operation_extended 1 -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glStencilOpValueAMD (GLenum face, GLuint value); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLSTENCILOPVALUEAMDPROC) (GLenum face, GLuint value); -#endif - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/freeglut/include/GL/glut.h b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/freeglut/include/GL/glut.h deleted file mode 100644 index 6191f77b75d7..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/freeglut/include/GL/glut.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __GLUT_H__ -#define __GLUT_H__ - -/* - * glut.h - * - * The freeglut library include file - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "freeglut_std.h" - -/*** END OF FILE ***/ - -#endif /* __GLUT_H__ */ diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/freeglut/include/GL/glxext.h b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/freeglut/include/GL/glxext.h deleted file mode 100644 index e640ff7e3977..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/freeglut/include/GL/glxext.h +++ /dev/null @@ -1,1001 +0,0 @@ -#ifndef __glxext_h_ -#define __glxext_h_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** Copyright (c) 2007-2012 The Khronos Group Inc. -** -** Permission is hereby granted, free of charge, to any person obtaining a -** copy of this software and/or associated documentation files (the -** "Materials"), to deal in the Materials without restriction, including -** without limitation the rights to use, copy, modify, merge, publish, -** distribute, sublicense, and/or sell copies of the Materials, and to -** permit persons to whom the Materials are furnished to do so, subject to -** the following conditions: -** -** The above copyright notice and this permission notice shall be included -** in all copies or substantial portions of the Materials. -** -** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. -*/ - -/* Function declaration macros - to move into glplatform.h */ - -#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) -#define WIN32_LEAN_AND_MEAN 1 -#include -#endif - -#ifndef APIENTRY -#define APIENTRY -#endif -#ifndef APIENTRYP -#define APIENTRYP APIENTRY * -#endif -#ifndef GLAPI -#define GLAPI extern -#endif - -/*************************************************************/ - -/* Header file version number, required by OpenGL ABI for Linux */ -/* glxext.h last updated 2012/02/29 */ -/* Current version at http://www.opengl.org/registry/ */ -#define GLX_GLXEXT_VERSION 33 - -#ifndef GLX_VERSION_1_3 -#define GLX_WINDOW_BIT 0x00000001 -#define GLX_PIXMAP_BIT 0x00000002 -#define GLX_PBUFFER_BIT 0x00000004 -#define GLX_RGBA_BIT 0x00000001 -#define GLX_COLOR_INDEX_BIT 0x00000002 -#define GLX_PBUFFER_CLOBBER_MASK 0x08000000 -#define GLX_FRONT_LEFT_BUFFER_BIT 0x00000001 -#define GLX_FRONT_RIGHT_BUFFER_BIT 0x00000002 -#define GLX_BACK_LEFT_BUFFER_BIT 0x00000004 -#define GLX_BACK_RIGHT_BUFFER_BIT 0x00000008 -#define GLX_AUX_BUFFERS_BIT 0x00000010 -#define GLX_DEPTH_BUFFER_BIT 0x00000020 -#define GLX_STENCIL_BUFFER_BIT 0x00000040 -#define GLX_ACCUM_BUFFER_BIT 0x00000080 -#define GLX_CONFIG_CAVEAT 0x20 -#define GLX_X_VISUAL_TYPE 0x22 -#define GLX_TRANSPARENT_TYPE 0x23 -#define GLX_TRANSPARENT_INDEX_VALUE 0x24 -#define GLX_TRANSPARENT_RED_VALUE 0x25 -#define GLX_TRANSPARENT_GREEN_VALUE 0x26 -#define GLX_TRANSPARENT_BLUE_VALUE 0x27 -#define GLX_TRANSPARENT_ALPHA_VALUE 0x28 -#define GLX_DONT_CARE 0xFFFFFFFF -#define GLX_NONE 0x8000 -#define GLX_SLOW_CONFIG 0x8001 -#define GLX_TRUE_COLOR 0x8002 -#define GLX_DIRECT_COLOR 0x8003 -#define GLX_PSEUDO_COLOR 0x8004 -#define GLX_STATIC_COLOR 0x8005 -#define GLX_GRAY_SCALE 0x8006 -#define GLX_STATIC_GRAY 0x8007 -#define GLX_TRANSPARENT_RGB 0x8008 -#define GLX_TRANSPARENT_INDEX 0x8009 -#define GLX_VISUAL_ID 0x800B -#define GLX_SCREEN 0x800C -#define GLX_NON_CONFORMANT_CONFIG 0x800D -#define GLX_DRAWABLE_TYPE 0x8010 -#define GLX_RENDER_TYPE 0x8011 -#define GLX_X_RENDERABLE 0x8012 -#define GLX_FBCONFIG_ID 0x8013 -#define GLX_RGBA_TYPE 0x8014 -#define GLX_COLOR_INDEX_TYPE 0x8015 -#define GLX_MAX_PBUFFER_WIDTH 0x8016 -#define GLX_MAX_PBUFFER_HEIGHT 0x8017 -#define GLX_MAX_PBUFFER_PIXELS 0x8018 -#define GLX_PRESERVED_CONTENTS 0x801B -#define GLX_LARGEST_PBUFFER 0x801C -#define GLX_WIDTH 0x801D -#define GLX_HEIGHT 0x801E -#define GLX_EVENT_MASK 0x801F -#define GLX_DAMAGED 0x8020 -#define GLX_SAVED 0x8021 -#define GLX_WINDOW 0x8022 -#define GLX_PBUFFER 0x8023 -#define GLX_PBUFFER_HEIGHT 0x8040 -#define GLX_PBUFFER_WIDTH 0x8041 -#endif - -#ifndef GLX_VERSION_1_4 -#define GLX_SAMPLE_BUFFERS 100000 -#define GLX_SAMPLES 100001 -#endif - -#ifndef GLX_ARB_get_proc_address -#endif - -#ifndef GLX_ARB_multisample -#define GLX_SAMPLE_BUFFERS_ARB 100000 -#define GLX_SAMPLES_ARB 100001 -#endif - -#ifndef GLX_ARB_vertex_buffer_object -#define GLX_CONTEXT_ALLOW_BUFFER_BYTE_ORDER_MISMATCH_ARB 0x2095 -#endif - -#ifndef GLX_ARB_fbconfig_float -#define GLX_RGBA_FLOAT_TYPE_ARB 0x20B9 -#define GLX_RGBA_FLOAT_BIT_ARB 0x00000004 -#endif - -#ifndef GLX_ARB_framebuffer_sRGB -#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2 -#endif - -#ifndef GLX_ARB_create_context -#define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001 -#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 -#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 -#define GLX_CONTEXT_FLAGS_ARB 0x2094 -#endif - -#ifndef GLX_ARB_create_context_profile -#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 -#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 -#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 -#endif - -#ifndef GLX_ARB_create_context_robustness -#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 -#define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252 -#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 -#define GLX_NO_RESET_NOTIFICATION_ARB 0x8261 -#endif - -#ifndef GLX_SGIS_multisample -#define GLX_SAMPLE_BUFFERS_SGIS 100000 -#define GLX_SAMPLES_SGIS 100001 -#endif - -#ifndef GLX_EXT_visual_info -#define GLX_X_VISUAL_TYPE_EXT 0x22 -#define GLX_TRANSPARENT_TYPE_EXT 0x23 -#define GLX_TRANSPARENT_INDEX_VALUE_EXT 0x24 -#define GLX_TRANSPARENT_RED_VALUE_EXT 0x25 -#define GLX_TRANSPARENT_GREEN_VALUE_EXT 0x26 -#define GLX_TRANSPARENT_BLUE_VALUE_EXT 0x27 -#define GLX_TRANSPARENT_ALPHA_VALUE_EXT 0x28 -#define GLX_NONE_EXT 0x8000 -#define GLX_TRUE_COLOR_EXT 0x8002 -#define GLX_DIRECT_COLOR_EXT 0x8003 -#define GLX_PSEUDO_COLOR_EXT 0x8004 -#define GLX_STATIC_COLOR_EXT 0x8005 -#define GLX_GRAY_SCALE_EXT 0x8006 -#define GLX_STATIC_GRAY_EXT 0x8007 -#define GLX_TRANSPARENT_RGB_EXT 0x8008 -#define GLX_TRANSPARENT_INDEX_EXT 0x8009 -#endif - -#ifndef GLX_SGI_swap_control -#endif - -#ifndef GLX_SGI_video_sync -#endif - -#ifndef GLX_SGI_make_current_read -#endif - -#ifndef GLX_SGIX_video_source -#endif - -#ifndef GLX_EXT_visual_rating -#define GLX_VISUAL_CAVEAT_EXT 0x20 -#define GLX_SLOW_VISUAL_EXT 0x8001 -#define GLX_NON_CONFORMANT_VISUAL_EXT 0x800D -/* reuse GLX_NONE_EXT */ -#endif - -#ifndef GLX_EXT_import_context -#define GLX_SHARE_CONTEXT_EXT 0x800A -#define GLX_VISUAL_ID_EXT 0x800B -#define GLX_SCREEN_EXT 0x800C -#endif - -#ifndef GLX_SGIX_fbconfig -#define GLX_WINDOW_BIT_SGIX 0x00000001 -#define GLX_PIXMAP_BIT_SGIX 0x00000002 -#define GLX_RGBA_BIT_SGIX 0x00000001 -#define GLX_COLOR_INDEX_BIT_SGIX 0x00000002 -#define GLX_DRAWABLE_TYPE_SGIX 0x8010 -#define GLX_RENDER_TYPE_SGIX 0x8011 -#define GLX_X_RENDERABLE_SGIX 0x8012 -#define GLX_FBCONFIG_ID_SGIX 0x8013 -#define GLX_RGBA_TYPE_SGIX 0x8014 -#define GLX_COLOR_INDEX_TYPE_SGIX 0x8015 -/* reuse GLX_SCREEN_EXT */ -#endif - -#ifndef GLX_SGIX_pbuffer -#define GLX_PBUFFER_BIT_SGIX 0x00000004 -#define GLX_BUFFER_CLOBBER_MASK_SGIX 0x08000000 -#define GLX_FRONT_LEFT_BUFFER_BIT_SGIX 0x00000001 -#define GLX_FRONT_RIGHT_BUFFER_BIT_SGIX 0x00000002 -#define GLX_BACK_LEFT_BUFFER_BIT_SGIX 0x00000004 -#define GLX_BACK_RIGHT_BUFFER_BIT_SGIX 0x00000008 -#define GLX_AUX_BUFFERS_BIT_SGIX 0x00000010 -#define GLX_DEPTH_BUFFER_BIT_SGIX 0x00000020 -#define GLX_STENCIL_BUFFER_BIT_SGIX 0x00000040 -#define GLX_ACCUM_BUFFER_BIT_SGIX 0x00000080 -#define GLX_SAMPLE_BUFFERS_BIT_SGIX 0x00000100 -#define GLX_MAX_PBUFFER_WIDTH_SGIX 0x8016 -#define GLX_MAX_PBUFFER_HEIGHT_SGIX 0x8017 -#define GLX_MAX_PBUFFER_PIXELS_SGIX 0x8018 -#define GLX_OPTIMAL_PBUFFER_WIDTH_SGIX 0x8019 -#define GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX 0x801A -#define GLX_PRESERVED_CONTENTS_SGIX 0x801B -#define GLX_LARGEST_PBUFFER_SGIX 0x801C -#define GLX_WIDTH_SGIX 0x801D -#define GLX_HEIGHT_SGIX 0x801E -#define GLX_EVENT_MASK_SGIX 0x801F -#define GLX_DAMAGED_SGIX 0x8020 -#define GLX_SAVED_SGIX 0x8021 -#define GLX_WINDOW_SGIX 0x8022 -#define GLX_PBUFFER_SGIX 0x8023 -#endif - -#ifndef GLX_SGI_cushion -#endif - -#ifndef GLX_SGIX_video_resize -#define GLX_SYNC_FRAME_SGIX 0x00000000 -#define GLX_SYNC_SWAP_SGIX 0x00000001 -#endif - -#ifndef GLX_SGIX_dmbuffer -#define GLX_DIGITAL_MEDIA_PBUFFER_SGIX 0x8024 -#endif - -#ifndef GLX_SGIX_swap_group -#endif - -#ifndef GLX_SGIX_swap_barrier -#endif - -#ifndef GLX_SGIS_blended_overlay -#define GLX_BLENDED_RGBA_SGIS 0x8025 -#endif - -#ifndef GLX_SGIS_shared_multisample -#define GLX_MULTISAMPLE_SUB_RECT_WIDTH_SGIS 0x8026 -#define GLX_MULTISAMPLE_SUB_RECT_HEIGHT_SGIS 0x8027 -#endif - -#ifndef GLX_SUN_get_transparent_index -#endif - -#ifndef GLX_3DFX_multisample -#define GLX_SAMPLE_BUFFERS_3DFX 0x8050 -#define GLX_SAMPLES_3DFX 0x8051 -#endif - -#ifndef GLX_MESA_copy_sub_buffer -#endif - -#ifndef GLX_MESA_pixmap_colormap -#endif - -#ifndef GLX_MESA_release_buffers -#endif - -#ifndef GLX_MESA_set_3dfx_mode -#define GLX_3DFX_WINDOW_MODE_MESA 0x1 -#define GLX_3DFX_FULLSCREEN_MODE_MESA 0x2 -#endif - -#ifndef GLX_SGIX_visual_select_group -#define GLX_VISUAL_SELECT_GROUP_SGIX 0x8028 -#endif - -#ifndef GLX_OML_swap_method -#define GLX_SWAP_METHOD_OML 0x8060 -#define GLX_SWAP_EXCHANGE_OML 0x8061 -#define GLX_SWAP_COPY_OML 0x8062 -#define GLX_SWAP_UNDEFINED_OML 0x8063 -#endif - -#ifndef GLX_OML_sync_control -#endif - -#ifndef GLX_NV_float_buffer -#define GLX_FLOAT_COMPONENTS_NV 0x20B0 -#endif - -#ifndef GLX_SGIX_hyperpipe -#define GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX 80 -#define GLX_BAD_HYPERPIPE_CONFIG_SGIX 91 -#define GLX_BAD_HYPERPIPE_SGIX 92 -#define GLX_HYPERPIPE_DISPLAY_PIPE_SGIX 0x00000001 -#define GLX_HYPERPIPE_RENDER_PIPE_SGIX 0x00000002 -#define GLX_PIPE_RECT_SGIX 0x00000001 -#define GLX_PIPE_RECT_LIMITS_SGIX 0x00000002 -#define GLX_HYPERPIPE_STEREO_SGIX 0x00000003 -#define GLX_HYPERPIPE_PIXEL_AVERAGE_SGIX 0x00000004 -#define GLX_HYPERPIPE_ID_SGIX 0x8030 -#endif - -#ifndef GLX_MESA_agp_offset -#endif - -#ifndef GLX_EXT_fbconfig_packed_float -#define GLX_RGBA_UNSIGNED_FLOAT_TYPE_EXT 0x20B1 -#define GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT 0x00000008 -#endif - -#ifndef GLX_EXT_framebuffer_sRGB -#define GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20B2 -#endif - -#ifndef GLX_EXT_texture_from_pixmap -#define GLX_TEXTURE_1D_BIT_EXT 0x00000001 -#define GLX_TEXTURE_2D_BIT_EXT 0x00000002 -#define GLX_TEXTURE_RECTANGLE_BIT_EXT 0x00000004 -#define GLX_BIND_TO_TEXTURE_RGB_EXT 0x20D0 -#define GLX_BIND_TO_TEXTURE_RGBA_EXT 0x20D1 -#define GLX_BIND_TO_MIPMAP_TEXTURE_EXT 0x20D2 -#define GLX_BIND_TO_TEXTURE_TARGETS_EXT 0x20D3 -#define GLX_Y_INVERTED_EXT 0x20D4 -#define GLX_TEXTURE_FORMAT_EXT 0x20D5 -#define GLX_TEXTURE_TARGET_EXT 0x20D6 -#define GLX_MIPMAP_TEXTURE_EXT 0x20D7 -#define GLX_TEXTURE_FORMAT_NONE_EXT 0x20D8 -#define GLX_TEXTURE_FORMAT_RGB_EXT 0x20D9 -#define GLX_TEXTURE_FORMAT_RGBA_EXT 0x20DA -#define GLX_TEXTURE_1D_EXT 0x20DB -#define GLX_TEXTURE_2D_EXT 0x20DC -#define GLX_TEXTURE_RECTANGLE_EXT 0x20DD -#define GLX_FRONT_LEFT_EXT 0x20DE -#define GLX_FRONT_RIGHT_EXT 0x20DF -#define GLX_BACK_LEFT_EXT 0x20E0 -#define GLX_BACK_RIGHT_EXT 0x20E1 -#define GLX_FRONT_EXT GLX_FRONT_LEFT_EXT -#define GLX_BACK_EXT GLX_BACK_LEFT_EXT -#define GLX_AUX0_EXT 0x20E2 -#define GLX_AUX1_EXT 0x20E3 -#define GLX_AUX2_EXT 0x20E4 -#define GLX_AUX3_EXT 0x20E5 -#define GLX_AUX4_EXT 0x20E6 -#define GLX_AUX5_EXT 0x20E7 -#define GLX_AUX6_EXT 0x20E8 -#define GLX_AUX7_EXT 0x20E9 -#define GLX_AUX8_EXT 0x20EA -#define GLX_AUX9_EXT 0x20EB -#endif - -#ifndef GLX_NV_present_video -#define GLX_NUM_VIDEO_SLOTS_NV 0x20F0 -#endif - -#ifndef GLX_NV_video_out -#define GLX_VIDEO_OUT_COLOR_NV 0x20C3 -#define GLX_VIDEO_OUT_ALPHA_NV 0x20C4 -#define GLX_VIDEO_OUT_DEPTH_NV 0x20C5 -#define GLX_VIDEO_OUT_COLOR_AND_ALPHA_NV 0x20C6 -#define GLX_VIDEO_OUT_COLOR_AND_DEPTH_NV 0x20C7 -#define GLX_VIDEO_OUT_FRAME_NV 0x20C8 -#define GLX_VIDEO_OUT_FIELD_1_NV 0x20C9 -#define GLX_VIDEO_OUT_FIELD_2_NV 0x20CA -#define GLX_VIDEO_OUT_STACKED_FIELDS_1_2_NV 0x20CB -#define GLX_VIDEO_OUT_STACKED_FIELDS_2_1_NV 0x20CC -#endif - -#ifndef GLX_NV_swap_group -#endif - -#ifndef GLX_NV_video_capture -#define GLX_DEVICE_ID_NV 0x20CD -#define GLX_UNIQUE_ID_NV 0x20CE -#define GLX_NUM_VIDEO_CAPTURE_SLOTS_NV 0x20CF -#endif - -#ifndef GLX_EXT_swap_control -#define GLX_SWAP_INTERVAL_EXT 0x20F1 -#define GLX_MAX_SWAP_INTERVAL_EXT 0x20F2 -#endif - -#ifndef GLX_NV_copy_image -#endif - -#ifndef GLX_INTEL_swap_event -#define GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK 0x04000000 -#define GLX_EXCHANGE_COMPLETE_INTEL 0x8180 -#define GLX_COPY_COMPLETE_INTEL 0x8181 -#define GLX_FLIP_COMPLETE_INTEL 0x8182 -#endif - -#ifndef GLX_NV_multisample_coverage -#define GLX_COVERAGE_SAMPLES_NV 100001 -#define GLX_COLOR_SAMPLES_NV 0x20B3 -#endif - -#ifndef GLX_AMD_gpu_association -#define GLX_GPU_VENDOR_AMD 0x1F00 -#define GLX_GPU_RENDERER_STRING_AMD 0x1F01 -#define GLX_GPU_OPENGL_VERSION_STRING_AMD 0x1F02 -#define GLX_GPU_FASTEST_TARGET_GPUS_AMD 0x21A2 -#define GLX_GPU_RAM_AMD 0x21A3 -#define GLX_GPU_CLOCK_AMD 0x21A4 -#define GLX_GPU_NUM_PIPES_AMD 0x21A5 -#define GLX_GPU_NUM_SIMD_AMD 0x21A6 -#define GLX_GPU_NUM_RB_AMD 0x21A7 -#define GLX_GPU_NUM_SPI_AMD 0x21A8 -#endif - -#ifndef GLX_EXT_create_context_es2_profile -#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 -#endif - -#ifndef GLX_EXT_swap_control_tear -#define GLX_LATE_SWAPS_TEAR_EXT 0x20F3 -#endif - - -/*************************************************************/ - -#ifndef GLX_ARB_get_proc_address -typedef void (*__GLXextFuncPtr)(void); -#endif - -#ifndef GLX_SGIX_video_source -typedef XID GLXVideoSourceSGIX; -#endif - -#ifndef GLX_SGIX_fbconfig -typedef XID GLXFBConfigIDSGIX; -typedef struct __GLXFBConfigRec *GLXFBConfigSGIX; -#endif - -#ifndef GLX_SGIX_pbuffer -typedef XID GLXPbufferSGIX; -typedef struct { - int type; - unsigned long serial; /* # of last request processed by server */ - Bool send_event; /* true if this came for SendEvent request */ - Display *display; /* display the event was read from */ - GLXDrawable drawable; /* i.d. of Drawable */ - int event_type; /* GLX_DAMAGED_SGIX or GLX_SAVED_SGIX */ - int draw_type; /* GLX_WINDOW_SGIX or GLX_PBUFFER_SGIX */ - unsigned int mask; /* mask indicating which buffers are affected*/ - int x, y; - int width, height; - int count; /* if nonzero, at least this many more */ -} GLXBufferClobberEventSGIX; -#endif - -#ifndef GLX_NV_video_output -typedef unsigned int GLXVideoDeviceNV; -#endif - -#ifndef GLX_NV_video_capture -typedef XID GLXVideoCaptureDeviceNV; -#endif - -#ifndef GLEXT_64_TYPES_DEFINED -/* This code block is duplicated in glext.h, so must be protected */ -#define GLEXT_64_TYPES_DEFINED -/* Define int32_t, int64_t, and uint64_t types for UST/MSC */ -/* (as used in the GLX_OML_sync_control extension). */ -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L -#include -#elif defined(__sun__) || defined(__digital__) -#include -#if defined(__STDC__) -#if defined(__arch64__) || defined(_LP64) -typedef long int int64_t; -typedef unsigned long int uint64_t; -#else -typedef long long int int64_t; -typedef unsigned long long int uint64_t; -#endif /* __arch64__ */ -#endif /* __STDC__ */ -#elif defined( __VMS ) || defined(__sgi) -#include -#elif defined(__SCO__) || defined(__USLC__) -#include -#elif defined(__UNIXOS2__) || defined(__SOL64__) -typedef long int int32_t; -typedef long long int int64_t; -typedef unsigned long long int uint64_t; -#elif defined(_WIN32) && defined(__GNUC__) -#include -#elif defined(_WIN32) -typedef __int32 int32_t; -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -#else -#include /* Fallback option */ -#endif -#endif - -#ifndef GLX_VERSION_1_3 -#define GLX_VERSION_1_3 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern GLXFBConfig * glXGetFBConfigs (Display *dpy, int screen, int *nelements); -extern GLXFBConfig * glXChooseFBConfig (Display *dpy, int screen, const int *attrib_list, int *nelements); -extern int glXGetFBConfigAttrib (Display *dpy, GLXFBConfig config, int attribute, int *value); -extern XVisualInfo * glXGetVisualFromFBConfig (Display *dpy, GLXFBConfig config); -extern GLXWindow glXCreateWindow (Display *dpy, GLXFBConfig config, Window win, const int *attrib_list); -extern void glXDestroyWindow (Display *dpy, GLXWindow win); -extern GLXPixmap glXCreatePixmap (Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attrib_list); -extern void glXDestroyPixmap (Display *dpy, GLXPixmap pixmap); -extern GLXPbuffer glXCreatePbuffer (Display *dpy, GLXFBConfig config, const int *attrib_list); -extern void glXDestroyPbuffer (Display *dpy, GLXPbuffer pbuf); -extern void glXQueryDrawable (Display *dpy, GLXDrawable draw, int attribute, unsigned int *value); -extern GLXContext glXCreateNewContext (Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct); -extern Bool glXMakeContextCurrent (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx); -extern GLXDrawable glXGetCurrentReadDrawable (void); -extern Display * glXGetCurrentDisplay (void); -extern int glXQueryContext (Display *dpy, GLXContext ctx, int attribute, int *value); -extern void glXSelectEvent (Display *dpy, GLXDrawable draw, unsigned long event_mask); -extern void glXGetSelectedEvent (Display *dpy, GLXDrawable draw, unsigned long *event_mask); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef GLXFBConfig * ( * PFNGLXGETFBCONFIGSPROC) (Display *dpy, int screen, int *nelements); -typedef GLXFBConfig * ( * PFNGLXCHOOSEFBCONFIGPROC) (Display *dpy, int screen, const int *attrib_list, int *nelements); -typedef int ( * PFNGLXGETFBCONFIGATTRIBPROC) (Display *dpy, GLXFBConfig config, int attribute, int *value); -typedef XVisualInfo * ( * PFNGLXGETVISUALFROMFBCONFIGPROC) (Display *dpy, GLXFBConfig config); -typedef GLXWindow ( * PFNGLXCREATEWINDOWPROC) (Display *dpy, GLXFBConfig config, Window win, const int *attrib_list); -typedef void ( * PFNGLXDESTROYWINDOWPROC) (Display *dpy, GLXWindow win); -typedef GLXPixmap ( * PFNGLXCREATEPIXMAPPROC) (Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attrib_list); -typedef void ( * PFNGLXDESTROYPIXMAPPROC) (Display *dpy, GLXPixmap pixmap); -typedef GLXPbuffer ( * PFNGLXCREATEPBUFFERPROC) (Display *dpy, GLXFBConfig config, const int *attrib_list); -typedef void ( * PFNGLXDESTROYPBUFFERPROC) (Display *dpy, GLXPbuffer pbuf); -typedef void ( * PFNGLXQUERYDRAWABLEPROC) (Display *dpy, GLXDrawable draw, int attribute, unsigned int *value); -typedef GLXContext ( * PFNGLXCREATENEWCONTEXTPROC) (Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct); -typedef Bool ( * PFNGLXMAKECONTEXTCURRENTPROC) (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx); -typedef GLXDrawable ( * PFNGLXGETCURRENTREADDRAWABLEPROC) (void); -typedef Display * ( * PFNGLXGETCURRENTDISPLAYPROC) (void); -typedef int ( * PFNGLXQUERYCONTEXTPROC) (Display *dpy, GLXContext ctx, int attribute, int *value); -typedef void ( * PFNGLXSELECTEVENTPROC) (Display *dpy, GLXDrawable draw, unsigned long event_mask); -typedef void ( * PFNGLXGETSELECTEDEVENTPROC) (Display *dpy, GLXDrawable draw, unsigned long *event_mask); -#endif - -#ifndef GLX_VERSION_1_4 -#define GLX_VERSION_1_4 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern __GLXextFuncPtr glXGetProcAddress (const GLubyte *procName); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef __GLXextFuncPtr ( * PFNGLXGETPROCADDRESSPROC) (const GLubyte *procName); -#endif - -#ifndef GLX_ARB_get_proc_address -#define GLX_ARB_get_proc_address 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern __GLXextFuncPtr glXGetProcAddressARB (const GLubyte *procName); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef __GLXextFuncPtr ( * PFNGLXGETPROCADDRESSARBPROC) (const GLubyte *procName); -#endif - -#ifndef GLX_ARB_multisample -#define GLX_ARB_multisample 1 -#endif - -#ifndef GLX_ARB_fbconfig_float -#define GLX_ARB_fbconfig_float 1 -#endif - -#ifndef GLX_ARB_framebuffer_sRGB -#define GLX_ARB_framebuffer_sRGB 1 -#endif - -#ifndef GLX_ARB_create_context -#define GLX_ARB_create_context 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern GLXContext glXCreateContextAttribsARB (Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef GLXContext ( * PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list); -#endif - -#ifndef GLX_ARB_create_context_profile -#define GLX_ARB_create_context_profile 1 -#endif - -#ifndef GLX_ARB_create_context_robustness -#define GLX_ARB_create_context_robustness 1 -#endif - -#ifndef GLX_SGIS_multisample -#define GLX_SGIS_multisample 1 -#endif - -#ifndef GLX_EXT_visual_info -#define GLX_EXT_visual_info 1 -#endif - -#ifndef GLX_SGI_swap_control -#define GLX_SGI_swap_control 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern int glXSwapIntervalSGI (int interval); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef int ( * PFNGLXSWAPINTERVALSGIPROC) (int interval); -#endif - -#ifndef GLX_SGI_video_sync -#define GLX_SGI_video_sync 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern int glXGetVideoSyncSGI (unsigned int *count); -extern int glXWaitVideoSyncSGI (int divisor, int remainder, unsigned int *count); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef int ( * PFNGLXGETVIDEOSYNCSGIPROC) (unsigned int *count); -typedef int ( * PFNGLXWAITVIDEOSYNCSGIPROC) (int divisor, int remainder, unsigned int *count); -#endif - -#ifndef GLX_SGI_make_current_read -#define GLX_SGI_make_current_read 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern Bool glXMakeCurrentReadSGI (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx); -extern GLXDrawable glXGetCurrentReadDrawableSGI (void); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef Bool ( * PFNGLXMAKECURRENTREADSGIPROC) (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx); -typedef GLXDrawable ( * PFNGLXGETCURRENTREADDRAWABLESGIPROC) (void); -#endif - -#ifndef GLX_SGIX_video_source -#define GLX_SGIX_video_source 1 -#ifdef _VL_H -#ifdef GLX_GLXEXT_PROTOTYPES -extern GLXVideoSourceSGIX glXCreateGLXVideoSourceSGIX (Display *display, int screen, VLServer server, VLPath path, int nodeClass, VLNode drainNode); -extern void glXDestroyGLXVideoSourceSGIX (Display *dpy, GLXVideoSourceSGIX glxvideosource); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef GLXVideoSourceSGIX ( * PFNGLXCREATEGLXVIDEOSOURCESGIXPROC) (Display *display, int screen, VLServer server, VLPath path, int nodeClass, VLNode drainNode); -typedef void ( * PFNGLXDESTROYGLXVIDEOSOURCESGIXPROC) (Display *dpy, GLXVideoSourceSGIX glxvideosource); -#endif /* _VL_H */ -#endif - -#ifndef GLX_EXT_visual_rating -#define GLX_EXT_visual_rating 1 -#endif - -#ifndef GLX_EXT_import_context -#define GLX_EXT_import_context 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern Display * glXGetCurrentDisplayEXT (void); -extern int glXQueryContextInfoEXT (Display *dpy, GLXContext context, int attribute, int *value); -extern GLXContextID glXGetContextIDEXT (const GLXContext context); -extern GLXContext glXImportContextEXT (Display *dpy, GLXContextID contextID); -extern void glXFreeContextEXT (Display *dpy, GLXContext context); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef Display * ( * PFNGLXGETCURRENTDISPLAYEXTPROC) (void); -typedef int ( * PFNGLXQUERYCONTEXTINFOEXTPROC) (Display *dpy, GLXContext context, int attribute, int *value); -typedef GLXContextID ( * PFNGLXGETCONTEXTIDEXTPROC) (const GLXContext context); -typedef GLXContext ( * PFNGLXIMPORTCONTEXTEXTPROC) (Display *dpy, GLXContextID contextID); -typedef void ( * PFNGLXFREECONTEXTEXTPROC) (Display *dpy, GLXContext context); -#endif - -#ifndef GLX_SGIX_fbconfig -#define GLX_SGIX_fbconfig 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern int glXGetFBConfigAttribSGIX (Display *dpy, GLXFBConfigSGIX config, int attribute, int *value); -extern GLXFBConfigSGIX * glXChooseFBConfigSGIX (Display *dpy, int screen, int *attrib_list, int *nelements); -extern GLXPixmap glXCreateGLXPixmapWithConfigSGIX (Display *dpy, GLXFBConfigSGIX config, Pixmap pixmap); -extern GLXContext glXCreateContextWithConfigSGIX (Display *dpy, GLXFBConfigSGIX config, int render_type, GLXContext share_list, Bool direct); -extern XVisualInfo * glXGetVisualFromFBConfigSGIX (Display *dpy, GLXFBConfigSGIX config); -extern GLXFBConfigSGIX glXGetFBConfigFromVisualSGIX (Display *dpy, XVisualInfo *vis); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef int ( * PFNGLXGETFBCONFIGATTRIBSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, int attribute, int *value); -typedef GLXFBConfigSGIX * ( * PFNGLXCHOOSEFBCONFIGSGIXPROC) (Display *dpy, int screen, int *attrib_list, int *nelements); -typedef GLXPixmap ( * PFNGLXCREATEGLXPIXMAPWITHCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, Pixmap pixmap); -typedef GLXContext ( * PFNGLXCREATECONTEXTWITHCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, int render_type, GLXContext share_list, Bool direct); -typedef XVisualInfo * ( * PFNGLXGETVISUALFROMFBCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config); -typedef GLXFBConfigSGIX ( * PFNGLXGETFBCONFIGFROMVISUALSGIXPROC) (Display *dpy, XVisualInfo *vis); -#endif - -#ifndef GLX_SGIX_pbuffer -#define GLX_SGIX_pbuffer 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern GLXPbufferSGIX glXCreateGLXPbufferSGIX (Display *dpy, GLXFBConfigSGIX config, unsigned int width, unsigned int height, int *attrib_list); -extern void glXDestroyGLXPbufferSGIX (Display *dpy, GLXPbufferSGIX pbuf); -extern int glXQueryGLXPbufferSGIX (Display *dpy, GLXPbufferSGIX pbuf, int attribute, unsigned int *value); -extern void glXSelectEventSGIX (Display *dpy, GLXDrawable drawable, unsigned long mask); -extern void glXGetSelectedEventSGIX (Display *dpy, GLXDrawable drawable, unsigned long *mask); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef GLXPbufferSGIX ( * PFNGLXCREATEGLXPBUFFERSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, unsigned int width, unsigned int height, int *attrib_list); -typedef void ( * PFNGLXDESTROYGLXPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuf); -typedef int ( * PFNGLXQUERYGLXPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuf, int attribute, unsigned int *value); -typedef void ( * PFNGLXSELECTEVENTSGIXPROC) (Display *dpy, GLXDrawable drawable, unsigned long mask); -typedef void ( * PFNGLXGETSELECTEDEVENTSGIXPROC) (Display *dpy, GLXDrawable drawable, unsigned long *mask); -#endif - -#ifndef GLX_SGI_cushion -#define GLX_SGI_cushion 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern void glXCushionSGI (Display *dpy, Window window, float cushion); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef void ( * PFNGLXCUSHIONSGIPROC) (Display *dpy, Window window, float cushion); -#endif - -#ifndef GLX_SGIX_video_resize -#define GLX_SGIX_video_resize 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern int glXBindChannelToWindowSGIX (Display *display, int screen, int channel, Window window); -extern int glXChannelRectSGIX (Display *display, int screen, int channel, int x, int y, int w, int h); -extern int glXQueryChannelRectSGIX (Display *display, int screen, int channel, int *dx, int *dy, int *dw, int *dh); -extern int glXQueryChannelDeltasSGIX (Display *display, int screen, int channel, int *x, int *y, int *w, int *h); -extern int glXChannelRectSyncSGIX (Display *display, int screen, int channel, GLenum synctype); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef int ( * PFNGLXBINDCHANNELTOWINDOWSGIXPROC) (Display *display, int screen, int channel, Window window); -typedef int ( * PFNGLXCHANNELRECTSGIXPROC) (Display *display, int screen, int channel, int x, int y, int w, int h); -typedef int ( * PFNGLXQUERYCHANNELRECTSGIXPROC) (Display *display, int screen, int channel, int *dx, int *dy, int *dw, int *dh); -typedef int ( * PFNGLXQUERYCHANNELDELTASSGIXPROC) (Display *display, int screen, int channel, int *x, int *y, int *w, int *h); -typedef int ( * PFNGLXCHANNELRECTSYNCSGIXPROC) (Display *display, int screen, int channel, GLenum synctype); -#endif - -#ifndef GLX_SGIX_dmbuffer -#define GLX_SGIX_dmbuffer 1 -#ifdef _DM_BUFFER_H_ -#ifdef GLX_GLXEXT_PROTOTYPES -extern Bool glXAssociateDMPbufferSGIX (Display *dpy, GLXPbufferSGIX pbuffer, DMparams *params, DMbuffer dmbuffer); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef Bool ( * PFNGLXASSOCIATEDMPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuffer, DMparams *params, DMbuffer dmbuffer); -#endif /* _DM_BUFFER_H_ */ -#endif - -#ifndef GLX_SGIX_swap_group -#define GLX_SGIX_swap_group 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern void glXJoinSwapGroupSGIX (Display *dpy, GLXDrawable drawable, GLXDrawable member); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef void ( * PFNGLXJOINSWAPGROUPSGIXPROC) (Display *dpy, GLXDrawable drawable, GLXDrawable member); -#endif - -#ifndef GLX_SGIX_swap_barrier -#define GLX_SGIX_swap_barrier 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern void glXBindSwapBarrierSGIX (Display *dpy, GLXDrawable drawable, int barrier); -extern Bool glXQueryMaxSwapBarriersSGIX (Display *dpy, int screen, int *max); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef void ( * PFNGLXBINDSWAPBARRIERSGIXPROC) (Display *dpy, GLXDrawable drawable, int barrier); -typedef Bool ( * PFNGLXQUERYMAXSWAPBARRIERSSGIXPROC) (Display *dpy, int screen, int *max); -#endif - -#ifndef GLX_SUN_get_transparent_index -#define GLX_SUN_get_transparent_index 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern Status glXGetTransparentIndexSUN (Display *dpy, Window overlay, Window underlay, long *pTransparentIndex); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef Status ( * PFNGLXGETTRANSPARENTINDEXSUNPROC) (Display *dpy, Window overlay, Window underlay, long *pTransparentIndex); -#endif - -#ifndef GLX_MESA_copy_sub_buffer -#define GLX_MESA_copy_sub_buffer 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern void glXCopySubBufferMESA (Display *dpy, GLXDrawable drawable, int x, int y, int width, int height); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef void ( * PFNGLXCOPYSUBBUFFERMESAPROC) (Display *dpy, GLXDrawable drawable, int x, int y, int width, int height); -#endif - -#ifndef GLX_MESA_pixmap_colormap -#define GLX_MESA_pixmap_colormap 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern GLXPixmap glXCreateGLXPixmapMESA (Display *dpy, XVisualInfo *visual, Pixmap pixmap, Colormap cmap); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef GLXPixmap ( * PFNGLXCREATEGLXPIXMAPMESAPROC) (Display *dpy, XVisualInfo *visual, Pixmap pixmap, Colormap cmap); -#endif - -#ifndef GLX_MESA_release_buffers -#define GLX_MESA_release_buffers 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern Bool glXReleaseBuffersMESA (Display *dpy, GLXDrawable drawable); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef Bool ( * PFNGLXRELEASEBUFFERSMESAPROC) (Display *dpy, GLXDrawable drawable); -#endif - -#ifndef GLX_MESA_set_3dfx_mode -#define GLX_MESA_set_3dfx_mode 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern Bool glXSet3DfxModeMESA (int mode); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef Bool ( * PFNGLXSET3DFXMODEMESAPROC) (int mode); -#endif - -#ifndef GLX_SGIX_visual_select_group -#define GLX_SGIX_visual_select_group 1 -#endif - -#ifndef GLX_OML_swap_method -#define GLX_OML_swap_method 1 -#endif - -#ifndef GLX_OML_sync_control -#define GLX_OML_sync_control 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern Bool glXGetSyncValuesOML (Display *dpy, GLXDrawable drawable, int64_t *ust, int64_t *msc, int64_t *sbc); -extern Bool glXGetMscRateOML (Display *dpy, GLXDrawable drawable, int32_t *numerator, int32_t *denominator); -extern int64_t glXSwapBuffersMscOML (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder); -extern Bool glXWaitForMscOML (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc); -extern Bool glXWaitForSbcOML (Display *dpy, GLXDrawable drawable, int64_t target_sbc, int64_t *ust, int64_t *msc, int64_t *sbc); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef Bool ( * PFNGLXGETSYNCVALUESOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t *ust, int64_t *msc, int64_t *sbc); -typedef Bool ( * PFNGLXGETMSCRATEOMLPROC) (Display *dpy, GLXDrawable drawable, int32_t *numerator, int32_t *denominator); -typedef int64_t ( * PFNGLXSWAPBUFFERSMSCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder); -typedef Bool ( * PFNGLXWAITFORMSCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc); -typedef Bool ( * PFNGLXWAITFORSBCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_sbc, int64_t *ust, int64_t *msc, int64_t *sbc); -#endif - -#ifndef GLX_NV_float_buffer -#define GLX_NV_float_buffer 1 -#endif - -#ifndef GLX_SGIX_hyperpipe -#define GLX_SGIX_hyperpipe 1 - -typedef struct { - char pipeName[GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX]; - int networkId; -} GLXHyperpipeNetworkSGIX; - -typedef struct { - char pipeName[GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX]; - int channel; - unsigned int - participationType; - int timeSlice; -} GLXHyperpipeConfigSGIX; - -typedef struct { - char pipeName[GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX]; - int srcXOrigin, srcYOrigin, srcWidth, srcHeight; - int destXOrigin, destYOrigin, destWidth, destHeight; -} GLXPipeRect; - -typedef struct { - char pipeName[GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX]; - int XOrigin, YOrigin, maxHeight, maxWidth; -} GLXPipeRectLimits; - -#ifdef GLX_GLXEXT_PROTOTYPES -extern GLXHyperpipeNetworkSGIX * glXQueryHyperpipeNetworkSGIX (Display *dpy, int *npipes); -extern int glXHyperpipeConfigSGIX (Display *dpy, int networkId, int npipes, GLXHyperpipeConfigSGIX *cfg, int *hpId); -extern GLXHyperpipeConfigSGIX * glXQueryHyperpipeConfigSGIX (Display *dpy, int hpId, int *npipes); -extern int glXDestroyHyperpipeConfigSGIX (Display *dpy, int hpId); -extern int glXBindHyperpipeSGIX (Display *dpy, int hpId); -extern int glXQueryHyperpipeBestAttribSGIX (Display *dpy, int timeSlice, int attrib, int size, void *attribList, void *returnAttribList); -extern int glXHyperpipeAttribSGIX (Display *dpy, int timeSlice, int attrib, int size, void *attribList); -extern int glXQueryHyperpipeAttribSGIX (Display *dpy, int timeSlice, int attrib, int size, void *returnAttribList); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef GLXHyperpipeNetworkSGIX * ( * PFNGLXQUERYHYPERPIPENETWORKSGIXPROC) (Display *dpy, int *npipes); -typedef int ( * PFNGLXHYPERPIPECONFIGSGIXPROC) (Display *dpy, int networkId, int npipes, GLXHyperpipeConfigSGIX *cfg, int *hpId); -typedef GLXHyperpipeConfigSGIX * ( * PFNGLXQUERYHYPERPIPECONFIGSGIXPROC) (Display *dpy, int hpId, int *npipes); -typedef int ( * PFNGLXDESTROYHYPERPIPECONFIGSGIXPROC) (Display *dpy, int hpId); -typedef int ( * PFNGLXBINDHYPERPIPESGIXPROC) (Display *dpy, int hpId); -typedef int ( * PFNGLXQUERYHYPERPIPEBESTATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *attribList, void *returnAttribList); -typedef int ( * PFNGLXHYPERPIPEATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *attribList); -typedef int ( * PFNGLXQUERYHYPERPIPEATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *returnAttribList); -#endif - -#ifndef GLX_MESA_agp_offset -#define GLX_MESA_agp_offset 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern unsigned int glXGetAGPOffsetMESA (const void *pointer); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef unsigned int ( * PFNGLXGETAGPOFFSETMESAPROC) (const void *pointer); -#endif - -#ifndef GLX_EXT_fbconfig_packed_float -#define GLX_EXT_fbconfig_packed_float 1 -#endif - -#ifndef GLX_EXT_framebuffer_sRGB -#define GLX_EXT_framebuffer_sRGB 1 -#endif - -#ifndef GLX_EXT_texture_from_pixmap -#define GLX_EXT_texture_from_pixmap 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern void glXBindTexImageEXT (Display *dpy, GLXDrawable drawable, int buffer, const int *attrib_list); -extern void glXReleaseTexImageEXT (Display *dpy, GLXDrawable drawable, int buffer); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef void ( * PFNGLXBINDTEXIMAGEEXTPROC) (Display *dpy, GLXDrawable drawable, int buffer, const int *attrib_list); -typedef void ( * PFNGLXRELEASETEXIMAGEEXTPROC) (Display *dpy, GLXDrawable drawable, int buffer); -#endif - -#ifndef GLX_NV_present_video -#define GLX_NV_present_video 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern unsigned int * glXEnumerateVideoDevicesNV (Display *dpy, int screen, int *nelements); -extern int glXBindVideoDeviceNV (Display *dpy, unsigned int video_slot, unsigned int video_device, const int *attrib_list); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef unsigned int * ( * PFNGLXENUMERATEVIDEODEVICESNVPROC) (Display *dpy, int screen, int *nelements); -typedef int ( * PFNGLXBINDVIDEODEVICENVPROC) (Display *dpy, unsigned int video_slot, unsigned int video_device, const int *attrib_list); -#endif - -#ifndef GLX_NV_video_output -#define GLX_NV_video_output 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern int glXGetVideoDeviceNV (Display *dpy, int screen, int numVideoDevices, GLXVideoDeviceNV *pVideoDevice); -extern int glXReleaseVideoDeviceNV (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice); -extern int glXBindVideoImageNV (Display *dpy, GLXVideoDeviceNV VideoDevice, GLXPbuffer pbuf, int iVideoBuffer); -extern int glXReleaseVideoImageNV (Display *dpy, GLXPbuffer pbuf); -extern int glXSendPbufferToVideoNV (Display *dpy, GLXPbuffer pbuf, int iBufferType, unsigned long *pulCounterPbuffer, GLboolean bBlock); -extern int glXGetVideoInfoNV (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef int ( * PFNGLXGETVIDEODEVICENVPROC) (Display *dpy, int screen, int numVideoDevices, GLXVideoDeviceNV *pVideoDevice); -typedef int ( * PFNGLXRELEASEVIDEODEVICENVPROC) (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice); -typedef int ( * PFNGLXBINDVIDEOIMAGENVPROC) (Display *dpy, GLXVideoDeviceNV VideoDevice, GLXPbuffer pbuf, int iVideoBuffer); -typedef int ( * PFNGLXRELEASEVIDEOIMAGENVPROC) (Display *dpy, GLXPbuffer pbuf); -typedef int ( * PFNGLXSENDPBUFFERTOVIDEONVPROC) (Display *dpy, GLXPbuffer pbuf, int iBufferType, unsigned long *pulCounterPbuffer, GLboolean bBlock); -typedef int ( * PFNGLXGETVIDEOINFONVPROC) (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo); -#endif - -#ifndef GLX_NV_swap_group -#define GLX_NV_swap_group 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern Bool glXJoinSwapGroupNV (Display *dpy, GLXDrawable drawable, GLuint group); -extern Bool glXBindSwapBarrierNV (Display *dpy, GLuint group, GLuint barrier); -extern Bool glXQuerySwapGroupNV (Display *dpy, GLXDrawable drawable, GLuint *group, GLuint *barrier); -extern Bool glXQueryMaxSwapGroupsNV (Display *dpy, int screen, GLuint *maxGroups, GLuint *maxBarriers); -extern Bool glXQueryFrameCountNV (Display *dpy, int screen, GLuint *count); -extern Bool glXResetFrameCountNV (Display *dpy, int screen); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef Bool ( * PFNGLXJOINSWAPGROUPNVPROC) (Display *dpy, GLXDrawable drawable, GLuint group); -typedef Bool ( * PFNGLXBINDSWAPBARRIERNVPROC) (Display *dpy, GLuint group, GLuint barrier); -typedef Bool ( * PFNGLXQUERYSWAPGROUPNVPROC) (Display *dpy, GLXDrawable drawable, GLuint *group, GLuint *barrier); -typedef Bool ( * PFNGLXQUERYMAXSWAPGROUPSNVPROC) (Display *dpy, int screen, GLuint *maxGroups, GLuint *maxBarriers); -typedef Bool ( * PFNGLXQUERYFRAMECOUNTNVPROC) (Display *dpy, int screen, GLuint *count); -typedef Bool ( * PFNGLXRESETFRAMECOUNTNVPROC) (Display *dpy, int screen); -#endif - -#ifndef GLX_NV_video_capture -#define GLX_NV_video_capture 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern int glXBindVideoCaptureDeviceNV (Display *dpy, unsigned int video_capture_slot, GLXVideoCaptureDeviceNV device); -extern GLXVideoCaptureDeviceNV * glXEnumerateVideoCaptureDevicesNV (Display *dpy, int screen, int *nelements); -extern void glXLockVideoCaptureDeviceNV (Display *dpy, GLXVideoCaptureDeviceNV device); -extern int glXQueryVideoCaptureDeviceNV (Display *dpy, GLXVideoCaptureDeviceNV device, int attribute, int *value); -extern void glXReleaseVideoCaptureDeviceNV (Display *dpy, GLXVideoCaptureDeviceNV device); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef int ( * PFNGLXBINDVIDEOCAPTUREDEVICENVPROC) (Display *dpy, unsigned int video_capture_slot, GLXVideoCaptureDeviceNV device); -typedef GLXVideoCaptureDeviceNV * ( * PFNGLXENUMERATEVIDEOCAPTUREDEVICESNVPROC) (Display *dpy, int screen, int *nelements); -typedef void ( * PFNGLXLOCKVIDEOCAPTUREDEVICENVPROC) (Display *dpy, GLXVideoCaptureDeviceNV device); -typedef int ( * PFNGLXQUERYVIDEOCAPTUREDEVICENVPROC) (Display *dpy, GLXVideoCaptureDeviceNV device, int attribute, int *value); -typedef void ( * PFNGLXRELEASEVIDEOCAPTUREDEVICENVPROC) (Display *dpy, GLXVideoCaptureDeviceNV device); -#endif - -#ifndef GLX_EXT_swap_control -#define GLX_EXT_swap_control 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern void glXSwapIntervalEXT (Display *dpy, GLXDrawable drawable, int interval); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef void ( * PFNGLXSWAPINTERVALEXTPROC) (Display *dpy, GLXDrawable drawable, int interval); -#endif - -#ifndef GLX_NV_copy_image -#define GLX_NV_copy_image 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern void glXCopyImageSubDataNV (Display *dpy, GLXContext srcCtx, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLXContext dstCtx, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef void ( * PFNGLXCOPYIMAGESUBDATANVPROC) (Display *dpy, GLXContext srcCtx, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLXContext dstCtx, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); -#endif - -#ifndef GLX_INTEL_swap_event -#define GLX_INTEL_swap_event 1 -#endif - -#ifndef GLX_NV_multisample_coverage -#define GLX_NV_multisample_coverage 1 -#endif - -#ifndef GLX_EXT_swap_control_tear -#define GLX_EXT_swap_control_tear 1 -#endif - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/freeglut/include/GL/wglext.h b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/freeglut/include/GL/wglext.h deleted file mode 100644 index b5dc7bf7f132..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/freeglut/include/GL/wglext.h +++ /dev/null @@ -1,943 +0,0 @@ -#ifndef __wglext_h_ -#define __wglext_h_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** Copyright (c) 2007-2012 The Khronos Group Inc. -** -** Permission is hereby granted, free of charge, to any person obtaining a -** copy of this software and/or associated documentation files (the -** "Materials"), to deal in the Materials without restriction, including -** without limitation the rights to use, copy, modify, merge, publish, -** distribute, sublicense, and/or sell copies of the Materials, and to -** permit persons to whom the Materials are furnished to do so, subject to -** the following conditions: -** -** The above copyright notice and this permission notice shall be included -** in all copies or substantial portions of the Materials. -** -** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. -*/ - -/* Function declaration macros - to move into glplatform.h */ - -#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) -#define WIN32_LEAN_AND_MEAN 1 -#include -#endif - -#ifndef APIENTRY -#define APIENTRY -#endif -#ifndef APIENTRYP -#define APIENTRYP APIENTRY * -#endif -#ifndef GLAPI -#define GLAPI extern -#endif - -/*************************************************************/ - -/* Header file version number */ -/* wglext.h last updated 2012/01/04 */ -/* Current version at http://www.opengl.org/registry/ */ -#define WGL_WGLEXT_VERSION 24 - -#ifndef WGL_ARB_buffer_region -#define WGL_FRONT_COLOR_BUFFER_BIT_ARB 0x00000001 -#define WGL_BACK_COLOR_BUFFER_BIT_ARB 0x00000002 -#define WGL_DEPTH_BUFFER_BIT_ARB 0x00000004 -#define WGL_STENCIL_BUFFER_BIT_ARB 0x00000008 -#endif - -#ifndef WGL_ARB_multisample -#define WGL_SAMPLE_BUFFERS_ARB 0x2041 -#define WGL_SAMPLES_ARB 0x2042 -#endif - -#ifndef WGL_ARB_extensions_string -#endif - -#ifndef WGL_ARB_pixel_format -#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 -#define WGL_DRAW_TO_WINDOW_ARB 0x2001 -#define WGL_DRAW_TO_BITMAP_ARB 0x2002 -#define WGL_ACCELERATION_ARB 0x2003 -#define WGL_NEED_PALETTE_ARB 0x2004 -#define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005 -#define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006 -#define WGL_SWAP_METHOD_ARB 0x2007 -#define WGL_NUMBER_OVERLAYS_ARB 0x2008 -#define WGL_NUMBER_UNDERLAYS_ARB 0x2009 -#define WGL_TRANSPARENT_ARB 0x200A -#define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037 -#define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038 -#define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039 -#define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A -#define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B -#define WGL_SHARE_DEPTH_ARB 0x200C -#define WGL_SHARE_STENCIL_ARB 0x200D -#define WGL_SHARE_ACCUM_ARB 0x200E -#define WGL_SUPPORT_GDI_ARB 0x200F -#define WGL_SUPPORT_OPENGL_ARB 0x2010 -#define WGL_DOUBLE_BUFFER_ARB 0x2011 -#define WGL_STEREO_ARB 0x2012 -#define WGL_PIXEL_TYPE_ARB 0x2013 -#define WGL_COLOR_BITS_ARB 0x2014 -#define WGL_RED_BITS_ARB 0x2015 -#define WGL_RED_SHIFT_ARB 0x2016 -#define WGL_GREEN_BITS_ARB 0x2017 -#define WGL_GREEN_SHIFT_ARB 0x2018 -#define WGL_BLUE_BITS_ARB 0x2019 -#define WGL_BLUE_SHIFT_ARB 0x201A -#define WGL_ALPHA_BITS_ARB 0x201B -#define WGL_ALPHA_SHIFT_ARB 0x201C -#define WGL_ACCUM_BITS_ARB 0x201D -#define WGL_ACCUM_RED_BITS_ARB 0x201E -#define WGL_ACCUM_GREEN_BITS_ARB 0x201F -#define WGL_ACCUM_BLUE_BITS_ARB 0x2020 -#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 -#define WGL_DEPTH_BITS_ARB 0x2022 -#define WGL_STENCIL_BITS_ARB 0x2023 -#define WGL_AUX_BUFFERS_ARB 0x2024 -#define WGL_NO_ACCELERATION_ARB 0x2025 -#define WGL_GENERIC_ACCELERATION_ARB 0x2026 -#define WGL_FULL_ACCELERATION_ARB 0x2027 -#define WGL_SWAP_EXCHANGE_ARB 0x2028 -#define WGL_SWAP_COPY_ARB 0x2029 -#define WGL_SWAP_UNDEFINED_ARB 0x202A -#define WGL_TYPE_RGBA_ARB 0x202B -#define WGL_TYPE_COLORINDEX_ARB 0x202C -#endif - -#ifndef WGL_ARB_make_current_read -#define ERROR_INVALID_PIXEL_TYPE_ARB 0x2043 -#define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054 -#endif - -#ifndef WGL_ARB_pbuffer -#define WGL_DRAW_TO_PBUFFER_ARB 0x202D -#define WGL_MAX_PBUFFER_PIXELS_ARB 0x202E -#define WGL_MAX_PBUFFER_WIDTH_ARB 0x202F -#define WGL_MAX_PBUFFER_HEIGHT_ARB 0x2030 -#define WGL_PBUFFER_LARGEST_ARB 0x2033 -#define WGL_PBUFFER_WIDTH_ARB 0x2034 -#define WGL_PBUFFER_HEIGHT_ARB 0x2035 -#define WGL_PBUFFER_LOST_ARB 0x2036 -#endif - -#ifndef WGL_ARB_render_texture -#define WGL_BIND_TO_TEXTURE_RGB_ARB 0x2070 -#define WGL_BIND_TO_TEXTURE_RGBA_ARB 0x2071 -#define WGL_TEXTURE_FORMAT_ARB 0x2072 -#define WGL_TEXTURE_TARGET_ARB 0x2073 -#define WGL_MIPMAP_TEXTURE_ARB 0x2074 -#define WGL_TEXTURE_RGB_ARB 0x2075 -#define WGL_TEXTURE_RGBA_ARB 0x2076 -#define WGL_NO_TEXTURE_ARB 0x2077 -#define WGL_TEXTURE_CUBE_MAP_ARB 0x2078 -#define WGL_TEXTURE_1D_ARB 0x2079 -#define WGL_TEXTURE_2D_ARB 0x207A -#define WGL_MIPMAP_LEVEL_ARB 0x207B -#define WGL_CUBE_MAP_FACE_ARB 0x207C -#define WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x207D -#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x207E -#define WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x207F -#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x2080 -#define WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x2081 -#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x2082 -#define WGL_FRONT_LEFT_ARB 0x2083 -#define WGL_FRONT_RIGHT_ARB 0x2084 -#define WGL_BACK_LEFT_ARB 0x2085 -#define WGL_BACK_RIGHT_ARB 0x2086 -#define WGL_AUX0_ARB 0x2087 -#define WGL_AUX1_ARB 0x2088 -#define WGL_AUX2_ARB 0x2089 -#define WGL_AUX3_ARB 0x208A -#define WGL_AUX4_ARB 0x208B -#define WGL_AUX5_ARB 0x208C -#define WGL_AUX6_ARB 0x208D -#define WGL_AUX7_ARB 0x208E -#define WGL_AUX8_ARB 0x208F -#define WGL_AUX9_ARB 0x2090 -#endif - -#ifndef WGL_ARB_pixel_format_float -#define WGL_TYPE_RGBA_FLOAT_ARB 0x21A0 -#endif - -#ifndef WGL_ARB_framebuffer_sRGB -#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9 -#endif - -#ifndef WGL_ARB_create_context -#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 -#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 -#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 -#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 -#define WGL_CONTEXT_FLAGS_ARB 0x2094 -#define ERROR_INVALID_VERSION_ARB 0x2095 -#endif - -#ifndef WGL_ARB_create_context_profile -#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 -#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 -#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 -#define ERROR_INVALID_PROFILE_ARB 0x2096 -#endif - -#ifndef WGL_ARB_create_context_robustness -#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 -#define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 -#define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 -#define WGL_NO_RESET_NOTIFICATION_ARB 0x8261 -#endif - -#ifndef WGL_EXT_make_current_read -#define ERROR_INVALID_PIXEL_TYPE_EXT 0x2043 -#endif - -#ifndef WGL_EXT_pixel_format -#define WGL_NUMBER_PIXEL_FORMATS_EXT 0x2000 -#define WGL_DRAW_TO_WINDOW_EXT 0x2001 -#define WGL_DRAW_TO_BITMAP_EXT 0x2002 -#define WGL_ACCELERATION_EXT 0x2003 -#define WGL_NEED_PALETTE_EXT 0x2004 -#define WGL_NEED_SYSTEM_PALETTE_EXT 0x2005 -#define WGL_SWAP_LAYER_BUFFERS_EXT 0x2006 -#define WGL_SWAP_METHOD_EXT 0x2007 -#define WGL_NUMBER_OVERLAYS_EXT 0x2008 -#define WGL_NUMBER_UNDERLAYS_EXT 0x2009 -#define WGL_TRANSPARENT_EXT 0x200A -#define WGL_TRANSPARENT_VALUE_EXT 0x200B -#define WGL_SHARE_DEPTH_EXT 0x200C -#define WGL_SHARE_STENCIL_EXT 0x200D -#define WGL_SHARE_ACCUM_EXT 0x200E -#define WGL_SUPPORT_GDI_EXT 0x200F -#define WGL_SUPPORT_OPENGL_EXT 0x2010 -#define WGL_DOUBLE_BUFFER_EXT 0x2011 -#define WGL_STEREO_EXT 0x2012 -#define WGL_PIXEL_TYPE_EXT 0x2013 -#define WGL_COLOR_BITS_EXT 0x2014 -#define WGL_RED_BITS_EXT 0x2015 -#define WGL_RED_SHIFT_EXT 0x2016 -#define WGL_GREEN_BITS_EXT 0x2017 -#define WGL_GREEN_SHIFT_EXT 0x2018 -#define WGL_BLUE_BITS_EXT 0x2019 -#define WGL_BLUE_SHIFT_EXT 0x201A -#define WGL_ALPHA_BITS_EXT 0x201B -#define WGL_ALPHA_SHIFT_EXT 0x201C -#define WGL_ACCUM_BITS_EXT 0x201D -#define WGL_ACCUM_RED_BITS_EXT 0x201E -#define WGL_ACCUM_GREEN_BITS_EXT 0x201F -#define WGL_ACCUM_BLUE_BITS_EXT 0x2020 -#define WGL_ACCUM_ALPHA_BITS_EXT 0x2021 -#define WGL_DEPTH_BITS_EXT 0x2022 -#define WGL_STENCIL_BITS_EXT 0x2023 -#define WGL_AUX_BUFFERS_EXT 0x2024 -#define WGL_NO_ACCELERATION_EXT 0x2025 -#define WGL_GENERIC_ACCELERATION_EXT 0x2026 -#define WGL_FULL_ACCELERATION_EXT 0x2027 -#define WGL_SWAP_EXCHANGE_EXT 0x2028 -#define WGL_SWAP_COPY_EXT 0x2029 -#define WGL_SWAP_UNDEFINED_EXT 0x202A -#define WGL_TYPE_RGBA_EXT 0x202B -#define WGL_TYPE_COLORINDEX_EXT 0x202C -#endif - -#ifndef WGL_EXT_pbuffer -#define WGL_DRAW_TO_PBUFFER_EXT 0x202D -#define WGL_MAX_PBUFFER_PIXELS_EXT 0x202E -#define WGL_MAX_PBUFFER_WIDTH_EXT 0x202F -#define WGL_MAX_PBUFFER_HEIGHT_EXT 0x2030 -#define WGL_OPTIMAL_PBUFFER_WIDTH_EXT 0x2031 -#define WGL_OPTIMAL_PBUFFER_HEIGHT_EXT 0x2032 -#define WGL_PBUFFER_LARGEST_EXT 0x2033 -#define WGL_PBUFFER_WIDTH_EXT 0x2034 -#define WGL_PBUFFER_HEIGHT_EXT 0x2035 -#endif - -#ifndef WGL_EXT_depth_float -#define WGL_DEPTH_FLOAT_EXT 0x2040 -#endif - -#ifndef WGL_3DFX_multisample -#define WGL_SAMPLE_BUFFERS_3DFX 0x2060 -#define WGL_SAMPLES_3DFX 0x2061 -#endif - -#ifndef WGL_EXT_multisample -#define WGL_SAMPLE_BUFFERS_EXT 0x2041 -#define WGL_SAMPLES_EXT 0x2042 -#endif - -#ifndef WGL_I3D_digital_video_control -#define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_FRAMEBUFFER_I3D 0x2050 -#define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_VALUE_I3D 0x2051 -#define WGL_DIGITAL_VIDEO_CURSOR_INCLUDED_I3D 0x2052 -#define WGL_DIGITAL_VIDEO_GAMMA_CORRECTED_I3D 0x2053 -#endif - -#ifndef WGL_I3D_gamma -#define WGL_GAMMA_TABLE_SIZE_I3D 0x204E -#define WGL_GAMMA_EXCLUDE_DESKTOP_I3D 0x204F -#endif - -#ifndef WGL_I3D_genlock -#define WGL_GENLOCK_SOURCE_MULTIVIEW_I3D 0x2044 -#define WGL_GENLOCK_SOURCE_EXTENAL_SYNC_I3D 0x2045 -#define WGL_GENLOCK_SOURCE_EXTENAL_FIELD_I3D 0x2046 -#define WGL_GENLOCK_SOURCE_EXTENAL_TTL_I3D 0x2047 -#define WGL_GENLOCK_SOURCE_DIGITAL_SYNC_I3D 0x2048 -#define WGL_GENLOCK_SOURCE_DIGITAL_FIELD_I3D 0x2049 -#define WGL_GENLOCK_SOURCE_EDGE_FALLING_I3D 0x204A -#define WGL_GENLOCK_SOURCE_EDGE_RISING_I3D 0x204B -#define WGL_GENLOCK_SOURCE_EDGE_BOTH_I3D 0x204C -#endif - -#ifndef WGL_I3D_image_buffer -#define WGL_IMAGE_BUFFER_MIN_ACCESS_I3D 0x00000001 -#define WGL_IMAGE_BUFFER_LOCK_I3D 0x00000002 -#endif - -#ifndef WGL_I3D_swap_frame_lock -#endif - -#ifndef WGL_NV_render_depth_texture -#define WGL_BIND_TO_TEXTURE_DEPTH_NV 0x20A3 -#define WGL_BIND_TO_TEXTURE_RECTANGLE_DEPTH_NV 0x20A4 -#define WGL_DEPTH_TEXTURE_FORMAT_NV 0x20A5 -#define WGL_TEXTURE_DEPTH_COMPONENT_NV 0x20A6 -#define WGL_DEPTH_COMPONENT_NV 0x20A7 -#endif - -#ifndef WGL_NV_render_texture_rectangle -#define WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV 0x20A0 -#define WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV 0x20A1 -#define WGL_TEXTURE_RECTANGLE_NV 0x20A2 -#endif - -#ifndef WGL_ATI_pixel_format_float -#define WGL_TYPE_RGBA_FLOAT_ATI 0x21A0 -#endif - -#ifndef WGL_NV_float_buffer -#define WGL_FLOAT_COMPONENTS_NV 0x20B0 -#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV 0x20B1 -#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV 0x20B2 -#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV 0x20B3 -#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV 0x20B4 -#define WGL_TEXTURE_FLOAT_R_NV 0x20B5 -#define WGL_TEXTURE_FLOAT_RG_NV 0x20B6 -#define WGL_TEXTURE_FLOAT_RGB_NV 0x20B7 -#define WGL_TEXTURE_FLOAT_RGBA_NV 0x20B8 -#endif - -#ifndef WGL_3DL_stereo_control -#define WGL_STEREO_EMITTER_ENABLE_3DL 0x2055 -#define WGL_STEREO_EMITTER_DISABLE_3DL 0x2056 -#define WGL_STEREO_POLARITY_NORMAL_3DL 0x2057 -#define WGL_STEREO_POLARITY_INVERT_3DL 0x2058 -#endif - -#ifndef WGL_EXT_pixel_format_packed_float -#define WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT 0x20A8 -#endif - -#ifndef WGL_EXT_framebuffer_sRGB -#define WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20A9 -#endif - -#ifndef WGL_NV_present_video -#define WGL_NUM_VIDEO_SLOTS_NV 0x20F0 -#endif - -#ifndef WGL_NV_video_out -#define WGL_BIND_TO_VIDEO_RGB_NV 0x20C0 -#define WGL_BIND_TO_VIDEO_RGBA_NV 0x20C1 -#define WGL_BIND_TO_VIDEO_RGB_AND_DEPTH_NV 0x20C2 -#define WGL_VIDEO_OUT_COLOR_NV 0x20C3 -#define WGL_VIDEO_OUT_ALPHA_NV 0x20C4 -#define WGL_VIDEO_OUT_DEPTH_NV 0x20C5 -#define WGL_VIDEO_OUT_COLOR_AND_ALPHA_NV 0x20C6 -#define WGL_VIDEO_OUT_COLOR_AND_DEPTH_NV 0x20C7 -#define WGL_VIDEO_OUT_FRAME 0x20C8 -#define WGL_VIDEO_OUT_FIELD_1 0x20C9 -#define WGL_VIDEO_OUT_FIELD_2 0x20CA -#define WGL_VIDEO_OUT_STACKED_FIELDS_1_2 0x20CB -#define WGL_VIDEO_OUT_STACKED_FIELDS_2_1 0x20CC -#endif - -#ifndef WGL_NV_swap_group -#endif - -#ifndef WGL_NV_gpu_affinity -#define WGL_ERROR_INCOMPATIBLE_AFFINITY_MASKS_NV 0x20D0 -#define WGL_ERROR_MISSING_AFFINITY_MASK_NV 0x20D1 -#endif - -#ifndef WGL_AMD_gpu_association -#define WGL_GPU_VENDOR_AMD 0x1F00 -#define WGL_GPU_RENDERER_STRING_AMD 0x1F01 -#define WGL_GPU_OPENGL_VERSION_STRING_AMD 0x1F02 -#define WGL_GPU_FASTEST_TARGET_GPUS_AMD 0x21A2 -#define WGL_GPU_RAM_AMD 0x21A3 -#define WGL_GPU_CLOCK_AMD 0x21A4 -#define WGL_GPU_NUM_PIPES_AMD 0x21A5 -#define WGL_GPU_NUM_SIMD_AMD 0x21A6 -#define WGL_GPU_NUM_RB_AMD 0x21A7 -#define WGL_GPU_NUM_SPI_AMD 0x21A8 -#endif - -#ifndef WGL_NV_video_capture -#define WGL_UNIQUE_ID_NV 0x20CE -#define WGL_NUM_VIDEO_CAPTURE_SLOTS_NV 0x20CF -#endif - -#ifndef WGL_NV_copy_image -#endif - -#ifndef WGL_NV_multisample_coverage -#define WGL_COVERAGE_SAMPLES_NV 0x2042 -#define WGL_COLOR_SAMPLES_NV 0x20B9 -#endif - -#ifndef WGL_EXT_create_context_es2_profile -#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 -#endif - -#ifndef WGL_NV_DX_interop -#define WGL_ACCESS_READ_ONLY_NV 0x00000000 -#define WGL_ACCESS_READ_WRITE_NV 0x00000001 -#define WGL_ACCESS_WRITE_DISCARD_NV 0x00000002 -#endif - -#ifndef WGL_NV_DX_interop2 -#endif - -#ifndef WGL_EXT_swap_control_tear -#endif - - -/*************************************************************/ - -#ifndef WGL_ARB_pbuffer -DECLARE_HANDLE(HPBUFFERARB); -#endif -#ifndef WGL_EXT_pbuffer -DECLARE_HANDLE(HPBUFFEREXT); -#endif -#ifndef WGL_NV_present_video -DECLARE_HANDLE(HVIDEOOUTPUTDEVICENV); -#endif -#ifndef WGL_NV_video_output -DECLARE_HANDLE(HPVIDEODEV); -#endif -#ifndef WGL_NV_gpu_affinity -DECLARE_HANDLE(HPGPUNV); -DECLARE_HANDLE(HGPUNV); - -typedef struct _GPU_DEVICE { - DWORD cb; - CHAR DeviceName[32]; - CHAR DeviceString[128]; - DWORD Flags; - RECT rcVirtualScreen; -} GPU_DEVICE, *PGPU_DEVICE; -#endif -#ifndef WGL_NV_video_capture -DECLARE_HANDLE(HVIDEOINPUTDEVICENV); -#endif - -#ifndef WGL_ARB_buffer_region -#define WGL_ARB_buffer_region 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern HANDLE WINAPI wglCreateBufferRegionARB (HDC hDC, int iLayerPlane, UINT uType); -extern VOID WINAPI wglDeleteBufferRegionARB (HANDLE hRegion); -extern BOOL WINAPI wglSaveBufferRegionARB (HANDLE hRegion, int x, int y, int width, int height); -extern BOOL WINAPI wglRestoreBufferRegionARB (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef HANDLE (WINAPI * PFNWGLCREATEBUFFERREGIONARBPROC) (HDC hDC, int iLayerPlane, UINT uType); -typedef VOID (WINAPI * PFNWGLDELETEBUFFERREGIONARBPROC) (HANDLE hRegion); -typedef BOOL (WINAPI * PFNWGLSAVEBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height); -typedef BOOL (WINAPI * PFNWGLRESTOREBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc); -#endif - -#ifndef WGL_ARB_multisample -#define WGL_ARB_multisample 1 -#endif - -#ifndef WGL_ARB_extensions_string -#define WGL_ARB_extensions_string 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern const char * WINAPI wglGetExtensionsStringARB (HDC hdc); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc); -#endif - -#ifndef WGL_ARB_pixel_format -#define WGL_ARB_pixel_format 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglGetPixelFormatAttribivARB (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues); -extern BOOL WINAPI wglGetPixelFormatAttribfvARB (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues); -extern BOOL WINAPI wglChoosePixelFormatARB (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues); -typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues); -typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); -#endif - -#ifndef WGL_ARB_make_current_read -#define WGL_ARB_make_current_read 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglMakeContextCurrentARB (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); -extern HDC WINAPI wglGetCurrentReadDCARB (void); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTARBPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); -typedef HDC (WINAPI * PFNWGLGETCURRENTREADDCARBPROC) (void); -#endif - -#ifndef WGL_ARB_pbuffer -#define WGL_ARB_pbuffer 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern HPBUFFERARB WINAPI wglCreatePbufferARB (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); -extern HDC WINAPI wglGetPbufferDCARB (HPBUFFERARB hPbuffer); -extern int WINAPI wglReleasePbufferDCARB (HPBUFFERARB hPbuffer, HDC hDC); -extern BOOL WINAPI wglDestroyPbufferARB (HPBUFFERARB hPbuffer); -extern BOOL WINAPI wglQueryPbufferARB (HPBUFFERARB hPbuffer, int iAttribute, int *piValue); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef HPBUFFERARB (WINAPI * PFNWGLCREATEPBUFFERARBPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); -typedef HDC (WINAPI * PFNWGLGETPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer); -typedef int (WINAPI * PFNWGLRELEASEPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer, HDC hDC); -typedef BOOL (WINAPI * PFNWGLDESTROYPBUFFERARBPROC) (HPBUFFERARB hPbuffer); -typedef BOOL (WINAPI * PFNWGLQUERYPBUFFERARBPROC) (HPBUFFERARB hPbuffer, int iAttribute, int *piValue); -#endif - -#ifndef WGL_ARB_render_texture -#define WGL_ARB_render_texture 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglBindTexImageARB (HPBUFFERARB hPbuffer, int iBuffer); -extern BOOL WINAPI wglReleaseTexImageARB (HPBUFFERARB hPbuffer, int iBuffer); -extern BOOL WINAPI wglSetPbufferAttribARB (HPBUFFERARB hPbuffer, const int *piAttribList); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLBINDTEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer); -typedef BOOL (WINAPI * PFNWGLRELEASETEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer); -typedef BOOL (WINAPI * PFNWGLSETPBUFFERATTRIBARBPROC) (HPBUFFERARB hPbuffer, const int *piAttribList); -#endif - -#ifndef WGL_ARB_pixel_format_float -#define WGL_ARB_pixel_format_float 1 -#endif - -#ifndef WGL_ARB_framebuffer_sRGB -#define WGL_ARB_framebuffer_sRGB 1 -#endif - -#ifndef WGL_ARB_create_context -#define WGL_ARB_create_context 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern HGLRC WINAPI wglCreateContextAttribsARB (HDC hDC, HGLRC hShareContext, const int *attribList); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList); -#endif - -#ifndef WGL_ARB_create_context_profile -#define WGL_ARB_create_context_profile 1 -#endif - -#ifndef WGL_ARB_create_context_robustness -#define WGL_ARB_create_context_robustness 1 -#endif - -#ifndef WGL_EXT_display_color_table -#define WGL_EXT_display_color_table 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern GLboolean WINAPI wglCreateDisplayColorTableEXT (GLushort id); -extern GLboolean WINAPI wglLoadDisplayColorTableEXT (const GLushort *table, GLuint length); -extern GLboolean WINAPI wglBindDisplayColorTableEXT (GLushort id); -extern VOID WINAPI wglDestroyDisplayColorTableEXT (GLushort id); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef GLboolean (WINAPI * PFNWGLCREATEDISPLAYCOLORTABLEEXTPROC) (GLushort id); -typedef GLboolean (WINAPI * PFNWGLLOADDISPLAYCOLORTABLEEXTPROC) (const GLushort *table, GLuint length); -typedef GLboolean (WINAPI * PFNWGLBINDDISPLAYCOLORTABLEEXTPROC) (GLushort id); -typedef VOID (WINAPI * PFNWGLDESTROYDISPLAYCOLORTABLEEXTPROC) (GLushort id); -#endif - -#ifndef WGL_EXT_extensions_string -#define WGL_EXT_extensions_string 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern const char * WINAPI wglGetExtensionsStringEXT (void); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC) (void); -#endif - -#ifndef WGL_EXT_make_current_read -#define WGL_EXT_make_current_read 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglMakeContextCurrentEXT (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); -extern HDC WINAPI wglGetCurrentReadDCEXT (void); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTEXTPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); -typedef HDC (WINAPI * PFNWGLGETCURRENTREADDCEXTPROC) (void); -#endif - -#ifndef WGL_EXT_pbuffer -#define WGL_EXT_pbuffer 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern HPBUFFEREXT WINAPI wglCreatePbufferEXT (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); -extern HDC WINAPI wglGetPbufferDCEXT (HPBUFFEREXT hPbuffer); -extern int WINAPI wglReleasePbufferDCEXT (HPBUFFEREXT hPbuffer, HDC hDC); -extern BOOL WINAPI wglDestroyPbufferEXT (HPBUFFEREXT hPbuffer); -extern BOOL WINAPI wglQueryPbufferEXT (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef HPBUFFEREXT (WINAPI * PFNWGLCREATEPBUFFEREXTPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); -typedef HDC (WINAPI * PFNWGLGETPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer); -typedef int (WINAPI * PFNWGLRELEASEPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer, HDC hDC); -typedef BOOL (WINAPI * PFNWGLDESTROYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer); -typedef BOOL (WINAPI * PFNWGLQUERYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue); -#endif - -#ifndef WGL_EXT_pixel_format -#define WGL_EXT_pixel_format 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglGetPixelFormatAttribivEXT (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues); -extern BOOL WINAPI wglGetPixelFormatAttribfvEXT (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues); -extern BOOL WINAPI wglChoosePixelFormatEXT (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues); -typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues); -typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATEXTPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); -#endif - -#ifndef WGL_EXT_swap_control -#define WGL_EXT_swap_control 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglSwapIntervalEXT (int interval); -extern int WINAPI wglGetSwapIntervalEXT (void); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval); -typedef int (WINAPI * PFNWGLGETSWAPINTERVALEXTPROC) (void); -#endif - -#ifndef WGL_EXT_depth_float -#define WGL_EXT_depth_float 1 -#endif - -#ifndef WGL_NV_vertex_array_range -#define WGL_NV_vertex_array_range 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern void* WINAPI wglAllocateMemoryNV (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority); -extern void WINAPI wglFreeMemoryNV (void *pointer); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef void* (WINAPI * PFNWGLALLOCATEMEMORYNVPROC) (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority); -typedef void (WINAPI * PFNWGLFREEMEMORYNVPROC) (void *pointer); -#endif - -#ifndef WGL_3DFX_multisample -#define WGL_3DFX_multisample 1 -#endif - -#ifndef WGL_EXT_multisample -#define WGL_EXT_multisample 1 -#endif - -#ifndef WGL_OML_sync_control -#define WGL_OML_sync_control 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglGetSyncValuesOML (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc); -extern BOOL WINAPI wglGetMscRateOML (HDC hdc, INT32 *numerator, INT32 *denominator); -extern INT64 WINAPI wglSwapBuffersMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder); -extern INT64 WINAPI wglSwapLayerBuffersMscOML (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder); -extern BOOL WINAPI wglWaitForMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc); -extern BOOL WINAPI wglWaitForSbcOML (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLGETSYNCVALUESOMLPROC) (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc); -typedef BOOL (WINAPI * PFNWGLGETMSCRATEOMLPROC) (HDC hdc, INT32 *numerator, INT32 *denominator); -typedef INT64 (WINAPI * PFNWGLSWAPBUFFERSMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder); -typedef INT64 (WINAPI * PFNWGLSWAPLAYERBUFFERSMSCOMLPROC) (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder); -typedef BOOL (WINAPI * PFNWGLWAITFORMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc); -typedef BOOL (WINAPI * PFNWGLWAITFORSBCOMLPROC) (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc); -#endif - -#ifndef WGL_I3D_digital_video_control -#define WGL_I3D_digital_video_control 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglGetDigitalVideoParametersI3D (HDC hDC, int iAttribute, int *piValue); -extern BOOL WINAPI wglSetDigitalVideoParametersI3D (HDC hDC, int iAttribute, const int *piValue); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLGETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue); -typedef BOOL (WINAPI * PFNWGLSETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue); -#endif - -#ifndef WGL_I3D_gamma -#define WGL_I3D_gamma 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglGetGammaTableParametersI3D (HDC hDC, int iAttribute, int *piValue); -extern BOOL WINAPI wglSetGammaTableParametersI3D (HDC hDC, int iAttribute, const int *piValue); -extern BOOL WINAPI wglGetGammaTableI3D (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue); -extern BOOL WINAPI wglSetGammaTableI3D (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLGETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue); -typedef BOOL (WINAPI * PFNWGLSETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue); -typedef BOOL (WINAPI * PFNWGLGETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue); -typedef BOOL (WINAPI * PFNWGLSETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue); -#endif - -#ifndef WGL_I3D_genlock -#define WGL_I3D_genlock 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglEnableGenlockI3D (HDC hDC); -extern BOOL WINAPI wglDisableGenlockI3D (HDC hDC); -extern BOOL WINAPI wglIsEnabledGenlockI3D (HDC hDC, BOOL *pFlag); -extern BOOL WINAPI wglGenlockSourceI3D (HDC hDC, UINT uSource); -extern BOOL WINAPI wglGetGenlockSourceI3D (HDC hDC, UINT *uSource); -extern BOOL WINAPI wglGenlockSourceEdgeI3D (HDC hDC, UINT uEdge); -extern BOOL WINAPI wglGetGenlockSourceEdgeI3D (HDC hDC, UINT *uEdge); -extern BOOL WINAPI wglGenlockSampleRateI3D (HDC hDC, UINT uRate); -extern BOOL WINAPI wglGetGenlockSampleRateI3D (HDC hDC, UINT *uRate); -extern BOOL WINAPI wglGenlockSourceDelayI3D (HDC hDC, UINT uDelay); -extern BOOL WINAPI wglGetGenlockSourceDelayI3D (HDC hDC, UINT *uDelay); -extern BOOL WINAPI wglQueryGenlockMaxSourceDelayI3D (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLENABLEGENLOCKI3DPROC) (HDC hDC); -typedef BOOL (WINAPI * PFNWGLDISABLEGENLOCKI3DPROC) (HDC hDC); -typedef BOOL (WINAPI * PFNWGLISENABLEDGENLOCKI3DPROC) (HDC hDC, BOOL *pFlag); -typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEI3DPROC) (HDC hDC, UINT uSource); -typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEI3DPROC) (HDC hDC, UINT *uSource); -typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT uEdge); -typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT *uEdge); -typedef BOOL (WINAPI * PFNWGLGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT uRate); -typedef BOOL (WINAPI * PFNWGLGETGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT *uRate); -typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT uDelay); -typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT *uDelay); -typedef BOOL (WINAPI * PFNWGLQUERYGENLOCKMAXSOURCEDELAYI3DPROC) (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay); -#endif - -#ifndef WGL_I3D_image_buffer -#define WGL_I3D_image_buffer 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern LPVOID WINAPI wglCreateImageBufferI3D (HDC hDC, DWORD dwSize, UINT uFlags); -extern BOOL WINAPI wglDestroyImageBufferI3D (HDC hDC, LPVOID pAddress); -extern BOOL WINAPI wglAssociateImageBufferEventsI3D (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count); -extern BOOL WINAPI wglReleaseImageBufferEventsI3D (HDC hDC, const LPVOID *pAddress, UINT count); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef LPVOID (WINAPI * PFNWGLCREATEIMAGEBUFFERI3DPROC) (HDC hDC, DWORD dwSize, UINT uFlags); -typedef BOOL (WINAPI * PFNWGLDESTROYIMAGEBUFFERI3DPROC) (HDC hDC, LPVOID pAddress); -typedef BOOL (WINAPI * PFNWGLASSOCIATEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count); -typedef BOOL (WINAPI * PFNWGLRELEASEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const LPVOID *pAddress, UINT count); -#endif - -#ifndef WGL_I3D_swap_frame_lock -#define WGL_I3D_swap_frame_lock 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglEnableFrameLockI3D (void); -extern BOOL WINAPI wglDisableFrameLockI3D (void); -extern BOOL WINAPI wglIsEnabledFrameLockI3D (BOOL *pFlag); -extern BOOL WINAPI wglQueryFrameLockMasterI3D (BOOL *pFlag); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLENABLEFRAMELOCKI3DPROC) (void); -typedef BOOL (WINAPI * PFNWGLDISABLEFRAMELOCKI3DPROC) (void); -typedef BOOL (WINAPI * PFNWGLISENABLEDFRAMELOCKI3DPROC) (BOOL *pFlag); -typedef BOOL (WINAPI * PFNWGLQUERYFRAMELOCKMASTERI3DPROC) (BOOL *pFlag); -#endif - -#ifndef WGL_I3D_swap_frame_usage -#define WGL_I3D_swap_frame_usage 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglGetFrameUsageI3D (float *pUsage); -extern BOOL WINAPI wglBeginFrameTrackingI3D (void); -extern BOOL WINAPI wglEndFrameTrackingI3D (void); -extern BOOL WINAPI wglQueryFrameTrackingI3D (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLGETFRAMEUSAGEI3DPROC) (float *pUsage); -typedef BOOL (WINAPI * PFNWGLBEGINFRAMETRACKINGI3DPROC) (void); -typedef BOOL (WINAPI * PFNWGLENDFRAMETRACKINGI3DPROC) (void); -typedef BOOL (WINAPI * PFNWGLQUERYFRAMETRACKINGI3DPROC) (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage); -#endif - -#ifndef WGL_ATI_pixel_format_float -#define WGL_ATI_pixel_format_float 1 -#endif - -#ifndef WGL_NV_float_buffer -#define WGL_NV_float_buffer 1 -#endif - -#ifndef WGL_3DL_stereo_control -#define WGL_3DL_stereo_control 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglSetStereoEmitterState3DL (HDC hDC, UINT uState); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLSETSTEREOEMITTERSTATE3DLPROC) (HDC hDC, UINT uState); -#endif - -#ifndef WGL_EXT_pixel_format_packed_float -#define WGL_EXT_pixel_format_packed_float 1 -#endif - -#ifndef WGL_EXT_framebuffer_sRGB -#define WGL_EXT_framebuffer_sRGB 1 -#endif - -#ifndef WGL_NV_present_video -#define WGL_NV_present_video 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern int WINAPI wglEnumerateVideoDevicesNV (HDC hDC, HVIDEOOUTPUTDEVICENV *phDeviceList); -extern BOOL WINAPI wglBindVideoDeviceNV (HDC hDC, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList); -extern BOOL WINAPI wglQueryCurrentContextNV (int iAttribute, int *piValue); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef int (WINAPI * PFNWGLENUMERATEVIDEODEVICESNVPROC) (HDC hDC, HVIDEOOUTPUTDEVICENV *phDeviceList); -typedef BOOL (WINAPI * PFNWGLBINDVIDEODEVICENVPROC) (HDC hDC, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList); -typedef BOOL (WINAPI * PFNWGLQUERYCURRENTCONTEXTNVPROC) (int iAttribute, int *piValue); -#endif - -#ifndef WGL_NV_video_output -#define WGL_NV_video_output 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglGetVideoDeviceNV (HDC hDC, int numDevices, HPVIDEODEV *hVideoDevice); -extern BOOL WINAPI wglReleaseVideoDeviceNV (HPVIDEODEV hVideoDevice); -extern BOOL WINAPI wglBindVideoImageNV (HPVIDEODEV hVideoDevice, HPBUFFERARB hPbuffer, int iVideoBuffer); -extern BOOL WINAPI wglReleaseVideoImageNV (HPBUFFERARB hPbuffer, int iVideoBuffer); -extern BOOL WINAPI wglSendPbufferToVideoNV (HPBUFFERARB hPbuffer, int iBufferType, unsigned long *pulCounterPbuffer, BOOL bBlock); -extern BOOL WINAPI wglGetVideoInfoNV (HPVIDEODEV hpVideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLGETVIDEODEVICENVPROC) (HDC hDC, int numDevices, HPVIDEODEV *hVideoDevice); -typedef BOOL (WINAPI * PFNWGLRELEASEVIDEODEVICENVPROC) (HPVIDEODEV hVideoDevice); -typedef BOOL (WINAPI * PFNWGLBINDVIDEOIMAGENVPROC) (HPVIDEODEV hVideoDevice, HPBUFFERARB hPbuffer, int iVideoBuffer); -typedef BOOL (WINAPI * PFNWGLRELEASEVIDEOIMAGENVPROC) (HPBUFFERARB hPbuffer, int iVideoBuffer); -typedef BOOL (WINAPI * PFNWGLSENDPBUFFERTOVIDEONVPROC) (HPBUFFERARB hPbuffer, int iBufferType, unsigned long *pulCounterPbuffer, BOOL bBlock); -typedef BOOL (WINAPI * PFNWGLGETVIDEOINFONVPROC) (HPVIDEODEV hpVideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo); -#endif - -#ifndef WGL_NV_swap_group -#define WGL_NV_swap_group 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglJoinSwapGroupNV (HDC hDC, GLuint group); -extern BOOL WINAPI wglBindSwapBarrierNV (GLuint group, GLuint barrier); -extern BOOL WINAPI wglQuerySwapGroupNV (HDC hDC, GLuint *group, GLuint *barrier); -extern BOOL WINAPI wglQueryMaxSwapGroupsNV (HDC hDC, GLuint *maxGroups, GLuint *maxBarriers); -extern BOOL WINAPI wglQueryFrameCountNV (HDC hDC, GLuint *count); -extern BOOL WINAPI wglResetFrameCountNV (HDC hDC); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLJOINSWAPGROUPNVPROC) (HDC hDC, GLuint group); -typedef BOOL (WINAPI * PFNWGLBINDSWAPBARRIERNVPROC) (GLuint group, GLuint barrier); -typedef BOOL (WINAPI * PFNWGLQUERYSWAPGROUPNVPROC) (HDC hDC, GLuint *group, GLuint *barrier); -typedef BOOL (WINAPI * PFNWGLQUERYMAXSWAPGROUPSNVPROC) (HDC hDC, GLuint *maxGroups, GLuint *maxBarriers); -typedef BOOL (WINAPI * PFNWGLQUERYFRAMECOUNTNVPROC) (HDC hDC, GLuint *count); -typedef BOOL (WINAPI * PFNWGLRESETFRAMECOUNTNVPROC) (HDC hDC); -#endif - -#ifndef WGL_NV_gpu_affinity -#define WGL_NV_gpu_affinity 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglEnumGpusNV (UINT iGpuIndex, HGPUNV *phGpu); -extern BOOL WINAPI wglEnumGpuDevicesNV (HGPUNV hGpu, UINT iDeviceIndex, PGPU_DEVICE lpGpuDevice); -extern HDC WINAPI wglCreateAffinityDCNV (const HGPUNV *phGpuList); -extern BOOL WINAPI wglEnumGpusFromAffinityDCNV (HDC hAffinityDC, UINT iGpuIndex, HGPUNV *hGpu); -extern BOOL WINAPI wglDeleteDCNV (HDC hdc); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLENUMGPUSNVPROC) (UINT iGpuIndex, HGPUNV *phGpu); -typedef BOOL (WINAPI * PFNWGLENUMGPUDEVICESNVPROC) (HGPUNV hGpu, UINT iDeviceIndex, PGPU_DEVICE lpGpuDevice); -typedef HDC (WINAPI * PFNWGLCREATEAFFINITYDCNVPROC) (const HGPUNV *phGpuList); -typedef BOOL (WINAPI * PFNWGLENUMGPUSFROMAFFINITYDCNVPROC) (HDC hAffinityDC, UINT iGpuIndex, HGPUNV *hGpu); -typedef BOOL (WINAPI * PFNWGLDELETEDCNVPROC) (HDC hdc); -#endif - -#ifndef WGL_AMD_gpu_association -#define WGL_AMD_gpu_association 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern UINT WINAPI wglGetGPUIDsAMD (UINT maxCount, UINT *ids); -extern INT WINAPI wglGetGPUInfoAMD (UINT id, int property, GLenum dataType, UINT size, void *data); -extern UINT WINAPI wglGetContextGPUIDAMD (HGLRC hglrc); -extern HGLRC WINAPI wglCreateAssociatedContextAMD (UINT id); -extern HGLRC WINAPI wglCreateAssociatedContextAttribsAMD (UINT id, HGLRC hShareContext, const int *attribList); -extern BOOL WINAPI wglDeleteAssociatedContextAMD (HGLRC hglrc); -extern BOOL WINAPI wglMakeAssociatedContextCurrentAMD (HGLRC hglrc); -extern HGLRC WINAPI wglGetCurrentAssociatedContextAMD (void); -extern VOID WINAPI wglBlitContextFramebufferAMD (HGLRC dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef UINT (WINAPI * PFNWGLGETGPUIDSAMDPROC) (UINT maxCount, UINT *ids); -typedef INT (WINAPI * PFNWGLGETGPUINFOAMDPROC) (UINT id, int property, GLenum dataType, UINT size, void *data); -typedef UINT (WINAPI * PFNWGLGETCONTEXTGPUIDAMDPROC) (HGLRC hglrc); -typedef HGLRC (WINAPI * PFNWGLCREATEASSOCIATEDCONTEXTAMDPROC) (UINT id); -typedef HGLRC (WINAPI * PFNWGLCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC) (UINT id, HGLRC hShareContext, const int *attribList); -typedef BOOL (WINAPI * PFNWGLDELETEASSOCIATEDCONTEXTAMDPROC) (HGLRC hglrc); -typedef BOOL (WINAPI * PFNWGLMAKEASSOCIATEDCONTEXTCURRENTAMDPROC) (HGLRC hglrc); -typedef HGLRC (WINAPI * PFNWGLGETCURRENTASSOCIATEDCONTEXTAMDPROC) (void); -typedef VOID (WINAPI * PFNWGLBLITCONTEXTFRAMEBUFFERAMDPROC) (HGLRC dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -#endif - -#ifndef WGL_NV_video_capture -#define WGL_NV_video_capture 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglBindVideoCaptureDeviceNV (UINT uVideoSlot, HVIDEOINPUTDEVICENV hDevice); -extern UINT WINAPI wglEnumerateVideoCaptureDevicesNV (HDC hDc, HVIDEOINPUTDEVICENV *phDeviceList); -extern BOOL WINAPI wglLockVideoCaptureDeviceNV (HDC hDc, HVIDEOINPUTDEVICENV hDevice); -extern BOOL WINAPI wglQueryVideoCaptureDeviceNV (HDC hDc, HVIDEOINPUTDEVICENV hDevice, int iAttribute, int *piValue); -extern BOOL WINAPI wglReleaseVideoCaptureDeviceNV (HDC hDc, HVIDEOINPUTDEVICENV hDevice); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLBINDVIDEOCAPTUREDEVICENVPROC) (UINT uVideoSlot, HVIDEOINPUTDEVICENV hDevice); -typedef UINT (WINAPI * PFNWGLENUMERATEVIDEOCAPTUREDEVICESNVPROC) (HDC hDc, HVIDEOINPUTDEVICENV *phDeviceList); -typedef BOOL (WINAPI * PFNWGLLOCKVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice); -typedef BOOL (WINAPI * PFNWGLQUERYVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice, int iAttribute, int *piValue); -typedef BOOL (WINAPI * PFNWGLRELEASEVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice); -#endif - -#ifndef WGL_NV_copy_image -#define WGL_NV_copy_image 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglCopyImageSubDataNV (HGLRC hSrcRC, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, HGLRC hDstRC, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLCOPYIMAGESUBDATANVPROC) (HGLRC hSrcRC, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, HGLRC hDstRC, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); -#endif - -#ifndef WGL_NV_multisample_coverage -#define WGL_NV_multisample_coverage 1 -#endif - -#ifndef WGL_NV_DX_interop -#define WGL_NV_DX_interop 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglDXSetResourceShareHandleNV (void *dxObject, HANDLE shareHandle); -extern HANDLE WINAPI wglDXOpenDeviceNV (void *dxDevice); -extern BOOL WINAPI wglDXCloseDeviceNV (HANDLE hDevice); -extern HANDLE WINAPI wglDXRegisterObjectNV (HANDLE hDevice, void *dxObject, GLuint name, GLenum type, GLenum access); -extern BOOL WINAPI wglDXUnregisterObjectNV (HANDLE hDevice, HANDLE hObject); -extern BOOL WINAPI wglDXObjectAccessNV (HANDLE hObject, GLenum access); -extern BOOL WINAPI wglDXLockObjectsNV (HANDLE hDevice, GLint count, HANDLE *hObjects); -extern BOOL WINAPI wglDXUnlockObjectsNV (HANDLE hDevice, GLint count, HANDLE *hObjects); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLDXSETRESOURCESHAREHANDLENVPROC) (void *dxObject, HANDLE shareHandle); -typedef HANDLE (WINAPI * PFNWGLDXOPENDEVICENVPROC) (void *dxDevice); -typedef BOOL (WINAPI * PFNWGLDXCLOSEDEVICENVPROC) (HANDLE hDevice); -typedef HANDLE (WINAPI * PFNWGLDXREGISTEROBJECTNVPROC) (HANDLE hDevice, void *dxObject, GLuint name, GLenum type, GLenum access); -typedef BOOL (WINAPI * PFNWGLDXUNREGISTEROBJECTNVPROC) (HANDLE hDevice, HANDLE hObject); -typedef BOOL (WINAPI * PFNWGLDXOBJECTACCESSNVPROC) (HANDLE hObject, GLenum access); -typedef BOOL (WINAPI * PFNWGLDXLOCKOBJECTSNVPROC) (HANDLE hDevice, GLint count, HANDLE *hObjects); -typedef BOOL (WINAPI * PFNWGLDXUNLOCKOBJECTSNVPROC) (HANDLE hDevice, GLint count, HANDLE *hObjects); -#endif - -#ifndef WGL_NV_DX_interop2 -#define WGL_NV_DX_interop2 1 -#endif - -#ifndef WGL_EXT_swap_control_tear -#define WGL_EXT_swap_control_tear 1 -#endif - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/CMakeLists.txt deleted file mode 100644 index fbf94e6c056f..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/CMakeLists.txt +++ /dev/null @@ -1,72 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2015 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -SET(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_MODULE_PATH}) -INCLUDE(CMakeDependentOption) - -SET(ADDITIONAL_SOURCES) - -FIND_PACKAGE(ImageMagick COMPONENTS Magick++) -MARK_AS_ADVANCED( - ImageMagick_EXECUTABLE_DIR - ImageMagick_Magick++_INCLUDE_DIR - ImageMagick_Magick++_ARCH_INCLUDE_DIR - ImageMagick_Magick++_LIBRARY -) -CMAKE_DEPENDENT_OPTION(USE_IMAGE_MAGICK "Enables BMP, GIF, PNG, TGA, TIFF image codecs." OFF "IMAGEMAGICK_FOUND" OFF) -IF (USE_IMAGE_MAGICK) - ADD_DEFINITIONS(-DUSE_IMAGEMAGICK) - INCLUDE_DIRECTORIES(${ImageMagick_Magick++_INCLUDE_DIR}) - SET(ADDITIONAL_LIBRARIES ${ADDITIONAL_LIBRARIES} ${ImageMagick_Magick++_LIBRARY}) - SET(ADDITIONAL_SOURCES ${ADDITIONAL_SOURCES} magick.cpp) -ENDIF (USE_IMAGE_MAGICK) - -FIND_PACKAGE(JPEG) -CMAKE_DEPENDENT_OPTION(USE_LIBJPEG "Enables JPEG image codec." ON "JPEG_FOUND" OFF) -IF (USE_LIBJPEG) - ADD_DEFINITIONS(-DUSE_LIBJPEG) - INCLUDE_DIRECTORIES(${JPEG_INCLUDE_DIR}) - SET(ADDITIONAL_LIBRARIES ${ADDITIONAL_LIBRARIES} ${JPEG_LIBRARIES}) - SET(ADDITIONAL_SOURCES ${ADDITIONAL_SOURCES} jpeg.cpp) -ENDIF (USE_LIBJPEG) - -FIND_PACKAGE(OpenEXR) -CMAKE_DEPENDENT_OPTION(USE_OPENEXR "Enables OpenEXR image codec." ON "OPENEXR_FOUND" OFF) -IF (USE_OPENEXR) - ADD_DEFINITIONS(-DUSE_OPENEXR) - INCLUDE_DIRECTORIES(${OPENEXR_INCLUDE_DIRS}) - SET(ADDITIONAL_LIBRARIES ${ADDITIONAL_LIBRARIES} ${OPENEXR_LIBRARIES}) - SET(ADDITIONAL_SOURCES ${ADDITIONAL_SOURCES} exr.cpp) -ENDIF (USE_OPENEXR) - -FIND_PACKAGE(PNG) -CMAKE_DEPENDENT_OPTION(USE_LIBPNG "Enables PNG image codecs." ON "PNG_FOUND" OFF) -IF (USE_LIBPNG) - ADD_DEFINITIONS(-DUSE_LIBPNG) - INCLUDE_DIRECTORIES(${PNG_INCLUDE_DIR}) - SET(ADDITIONAL_LIBRARIES ${ADDITIONAL_LIBRARIES} ${PNG_LIBRARIES}) -ENDIF (USE_LIBPNG) - -ADD_LIBRARY(image STATIC - image.cpp - pfm.cpp - ppm.cpp - tga.cpp - png.cpp - ${ADDITIONAL_SOURCES} - ) -TARGET_LINK_LIBRARIES(image sys ${ADDITIONAL_LIBRARIES}) -SET_PROPERTY(TARGET image PROPERTY FOLDER tutorials/common) diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/exr.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/exr.cpp deleted file mode 100644 index da30146a590b..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/exr.cpp +++ /dev/null @@ -1,90 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#ifdef USE_OPENEXR - -#include "image.h" - -/* include OpenEXR headers */ -#ifdef __WIN32__ -#include -#include -#pragma comment (lib, "Half.lib") -#pragma comment (lib, "Iex.lib") -#pragma comment (lib, "IlmImf.lib") -#pragma comment (lib, "IlmThread.lib") -#pragma comment (lib, "Imath.lib") -#pragma comment (lib, "zlib.lib") -#else -#include -#include -#endif - -namespace embree -{ - /*! load an EXR file from disk */ - Ref loadExr(const FileName& filename) - { - Imf::RgbaInputFile file (filename.c_str()); - Imath::Box2i dw = file.dataWindow(); - ssize_t width = dw.max.x - dw.min.x + 1; - ssize_t height = dw.max.y - dw.min.y + 1; - - Imf::Array2D pixels(height, width); - file.setFrameBuffer (&pixels[0][0] - dw.min.x - dw.min.y * width, 1, width); - file.readPixels (dw.min.y, dw.max.y); - - Ref img = new Image3f(width,height,filename); - - if (file.lineOrder() == Imf::INCREASING_Y) { - for (ssize_t y=0; yset(x,y,Color4(c.r,c.g,c.b,c.a)); - } - } - } - else { - for (ssize_t y=0; yset(x,height-y-1,Color4(c.r,c.g,c.b,c.a)); - } - } - } - - return img; - } - - /*! store an EXR file to disk */ - void storeExr(const Ref& img, const FileName& filename) - { - Imf::Array2D pixels(img->height,img->width); - for (size_t y=0; yheight; y++) { - for (size_t x=0; xwidth; x++) { - const Color4 c = img->get(x,y); - pixels[y][x] = Imf::Rgba(c.r,c.g,c.b,c.a); - } - } - - Imf::RgbaOutputFile file(filename.c_str(), img->width, img->height, Imf::WRITE_RGBA); - file.setFrameBuffer(&pixels[0][0], 1, img->width); - file.writePixels(img->height); - } -} - -#endif // USE_OPENEXR - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/image.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/image.cpp deleted file mode 100644 index cf778f0a4ff8..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/image.cpp +++ /dev/null @@ -1,94 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "image.h" -#include "../../../common/sys/string.h" - -#include -#include - -namespace embree -{ - /*! loads an image from a file with auto-detection of format */ - Ref loadImageFromDisk(const FileName& fileName) - { - std::string ext = strlwr(fileName.ext()); -#ifdef USE_OPENEXR - if (ext == "exr" ) return loadExr(fileName); -#endif - -#ifdef USE_LIBPNG - if (ext == "png" ) return loadPNG(fileName); -#endif - -#ifdef USE_IMAGEMAGICK - if (ext == "bmp" ) return loadMagick(fileName); - if (ext == "gif" ) return loadMagick(fileName); - if (ext == "tga" ) return loadMagick(fileName); - if (ext == "tif" ) return loadMagick(fileName); - if (ext == "tiff") return loadMagick(fileName); - if (ext == "png" ) return loadMagick(fileName); -#endif -#ifdef USE_LIBJPEG - if (ext == "jpg" ) return loadJPEG(fileName); -#endif - if (ext == "pfm" ) return loadPFM(fileName); - if (ext == "ppm" ) return loadPPM(fileName); - THROW_RUNTIME_ERROR("image format " + ext + " not supported"); - } - - /*! loads an image from a file with auto-detection of format */ - Ref loadImage(const FileName& fileName, bool cache) - { - static std::map > image_cache; - - if (!cache) - return loadImageFromDisk(fileName); - - if (image_cache.find(fileName) == image_cache.end()) - image_cache[fileName] = loadImageFromDisk(fileName); - - return image_cache[fileName]; - } - - /*! stores an image to file with auto-detection of format */ - void storeImage(const Ref& img, const FileName& fileName) - { - std::string ext = strlwr(fileName.ext()); -#ifdef USE_OPENEXR - if (ext == "exr" ) { storeExr(img, fileName); return; } -#endif -#ifdef USE_IMAGEMAGICK - if (ext == "bmp" ) { storeMagick(img, fileName); return; } - if (ext == "gif" ) { storeMagick(img, fileName); return; } - if (ext == "png" ) { storeMagick(img, fileName); return; } - if (ext == "tif" ) { storeMagick(img, fileName); return; } - if (ext == "tiff") { storeMagick(img, fileName); return; } -#endif -#ifdef USE_LIBJPEG - if (ext == "jpg" ) { storeJPEG(img, fileName); return; } -#endif - if (ext == "pfm" ) { storePFM(img, fileName); return; } - if (ext == "ppm" ) { storePPM(img, fileName); return; } - if (ext == "tga" ) { storeTga(img, fileName); return; } - THROW_RUNTIME_ERROR("image format " + ext + " not supported"); - } - - /*! template instantiations */ - template class ImageT; - template class ImageT; - -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/image.h b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/image.h deleted file mode 100644 index d8406d4fee30..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/image.h +++ /dev/null @@ -1,180 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include -#include - -#include "../../../common/sys/platform.h" -#include "../../../common/sys/ref.h" -#include "../../../common/sys/filename.h" -#include "../../../common/math/color.h" - -namespace embree -{ - /* virtual interface to image */ - class Image : public RefCount { - public: - Image (size_t width, size_t height, const std::string& name) : width(width), height(height), name(name) {} - virtual ~Image() {} - virtual Color4 get(size_t x, size_t y) const = 0; - virtual void set(size_t x, size_t y, const Color4& c) = 0; - void set(size_t x, size_t y, const Color& c) { set(x,y,Color4(c.r,c.g,c.b,1.0f)); } - void convertToRGBA8(unsigned char *dest) - { - for (size_t y=0;y - class ImageT : public Image { - public: - - /*! create empty image */ - ImageT (size_t width = 0, size_t height = 0, const std::string& name = "") - : Image(width,height,name) - { - data = (T*) malloc(width*height*sizeof(T)); - memset(data,0,width*height*sizeof(T)); - } - - /*! create image of constant color */ - ImageT (size_t width, size_t height, const T& color, const std::string& name = "") - : Image(width,height,name) - { - data = (T*) malloc(width*height*sizeof(T)); - for (size_t i=0; i Image3uc; - typedef ImageT Image3f; - typedef ImageT Image4uc; - typedef ImageT Image4f; - - /*! Generate a JPEG encoded image from a RGB8 buffer in memory. */ - void encodeRGB8_to_JPEG(unsigned char *image, size_t width, size_t height, unsigned char **encoded, size_t *capacity); - - /*! Loads image from EXR file. */ - Ref loadExr(const FileName& fileName); - - /*! Loads image from file. Format is auto detected. */ - Ref loadImage(const FileName& filename, bool cache = false); - - /*! Loads image from JPEG file. */ - Ref loadJPEG(const FileName& fileName); - - /*! Loads image using ImageMagick. */ - Ref loadMagick(const FileName& fileName); - - /*! Loads image from PFM file. */ - Ref loadPFM(const FileName& fileName); - - /*! Loads image from PNG file. */ - Ref loadPNG(const FileName& fileName); - - /*! Loads image from PPM file. */ - Ref loadPPM(const FileName& fileName); - - /*! Loads image from TIFF file. */ -//Ref loadTIFF(const FileName& fileName); - - /*! Store image to EXR file. */ - void storeExr(const Ref& img, const FileName& fileName); - - /*! Store image to file. Format is auto detected. */ - void storeImage(const Ref& image, const FileName& filename); - - /*! Store image to JPEG file. */ - void storeJPEG(const Ref& img, const FileName& fileName); - - /*! Store image to file using ImageMagick. */ - void storeMagick(const Ref& img, const FileName& fileName); - - /*! Store image to PFM file. */ - void storePFM(const Ref& img, const FileName& fileName); - - /*! Store image to PNG file. */ -//void storePNG(const Ref& img, const FileName& fileName); - - /*! Store image to PPM file. */ - void storePPM(const Ref& img, const FileName& fileName); - - /*! Store image to TGA file. */ - void storeTga(const Ref& img, const FileName& fileName); - - /*! Store image to TIFF file. */ -//void storeTIFF(const Ref& img, const FileName& fileName); - -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/jpeg.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/jpeg.cpp deleted file mode 100644 index 0031ed1ee221..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/jpeg.cpp +++ /dev/null @@ -1,198 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#ifdef USE_LIBJPEG - -#include "image.h" -#include "jpeglib.h" - -namespace embree -{ - - void compress(struct jpeg_compress_struct *cinfo, unsigned char *image) - { - - /*! Start compression. */ - jpeg_start_compress(cinfo, TRUE); - - /*! Pointer to and size of a scanline in the image. */ - JSAMPROW scanline[1]; size_t bytes = cinfo->image_width * cinfo->input_components; - - /*! Here we use the library state variable 'next_scanline' as the loop index. */ - while (cinfo->next_scanline < cinfo->image_height) scanline[0] = &image[cinfo->next_scanline * bytes], jpeg_write_scanlines(cinfo, scanline, 1); - - /*! Finish compression. */ - jpeg_finish_compress(cinfo); - - } - - unsigned char *decompress(struct jpeg_decompress_struct *cinfo) - { - - /*! Start decompression. */ - jpeg_start_decompress(cinfo); - - /*! Bytes per row in the scanline buffer. */ - size_t bytes = cinfo->output_width * cinfo->output_components; - - /*! Allocate scratch space for a single scanline. */ - JSAMPARRAY scanline = (*cinfo->mem->alloc_sarray)((j_common_ptr) cinfo, JPOOL_IMAGE, bytes, 1); - - /*! Allocate storage for the decompressed image. */ - unsigned char *image = (unsigned char *) malloc(cinfo->output_height * bytes); if (image == nullptr) return(nullptr); - - /*! Here we use the library state variable 'output_scanline' as the loop index. */ - while (cinfo->output_scanline < cinfo->output_height) jpeg_read_scanlines(cinfo, scanline, 1), memcpy(&image[(cinfo->output_scanline - 1) * bytes], scanline[0], bytes); - - /*! Finish decompression. */ - jpeg_finish_decompress(cinfo); return(image); - - } - - void encodeRGB8_to_JPEG(unsigned char *image, size_t width, size_t height, unsigned char **encoded, size_t *capacity) - { - -#if JPEG_LIB_VERSION >= 80 - - /*! Compression parameters and scratch space pointers (allocated by the library). */ - struct jpeg_compress_struct cinfo; - - /*! The library error handler. */ - struct jpeg_error_mgr jerror; cinfo.err = jpeg_std_error(&jerror); - - /*! Initialize the JPEG compression object. */ - jpeg_create_compress(&cinfo); - - /*! Specify the incoming image resolution, color space, and color space components. */ - cinfo.image_width = width; cinfo.image_height = height; cinfo.in_color_space = JCS_RGB; cinfo.input_components = 3; - - /*! Fill in a sensible set of defaults. */ - jpeg_set_defaults(&cinfo); - - /*! Set the image quality. */ - jpeg_set_quality(&cinfo, 90, TRUE); - - /*! Specify the data source. */ - jpeg_mem_dest(&cinfo, encoded, capacity); - - /*! Compress and write the image into the target buffer. */ - compress(&cinfo, image); - - /*! At this point 'jerror.num_warnings' could be checked for corrupt-data warnings. */ - jpeg_destroy_compress(&cinfo); - -#else // JPEG_LIB_VERSION - - THROW_RUNTIME_ERROR("JPEG encoding into a memory buffer requires LibJPEG 8a or higher"); - -#endif // JPEG_LIB_VERSION - - } - - Ref loadJPEG(const FileName &filename) - { - - /*! Open the source JPEG file. */ - FILE *file = fopen(filename.c_str(), "rb"); if (!file) THROW_RUNTIME_ERROR("Unable to open \"" + filename.str() + "\"."); - - /*! Decompression parameters and scratch space pointers allocated by the library. */ - struct jpeg_decompress_struct cinfo; - - /*! The library error handler. */ - struct jpeg_error_mgr jerror; cinfo.err = jpeg_std_error(&jerror); - - /*! Initialize the JPEG decompression object. */ - jpeg_create_decompress(&cinfo); - - /*! Specify the data source. */ - jpeg_stdio_src(&cinfo, file); - - /*! Read file parameters with jpeg_read_header(). */ - jpeg_read_header(&cinfo, TRUE); - - /*! Specify the color space and color space components of the decompressed image. */ - cinfo.out_color_space = JCS_RGB; cinfo.output_components = 3; - - /*! Decompress the image into an output buffer and get the image dimensions. */ - unsigned char *rgb = decompress(&cinfo); size_t width = cinfo.output_width; size_t height = cinfo.output_height; - - /*! Allocate the Embree image. */ - Ref image = new Image4uc(width, height, filename); - - /*! Convert the image from unsigned char RGB to unsigned char RGBA. */ - for (size_t y=0, i=0 ; y < height ; y++) { - for (size_t x=0 ; x < width ; x++) { - const float r = (float) rgb[i++] / 255.0f; - const float g = (float) rgb[i++] / 255.0f; - const float b = (float) rgb[i++] / 255.0f; - image->set(x, y, Color4(r,g,b,1.0f)); - } - } - - /*! Clean up. */ - jpeg_destroy_decompress(&cinfo); free(rgb); fclose(file); return(image); - - } - - void storeJPEG(const Ref &image, const FileName &filename) - { - - /*! Open the target JPEG file. */ - FILE *file = fopen(filename.c_str(), "wb"); if (!file) THROW_RUNTIME_ERROR("Unable to open \"" + filename.str() + "\"."); - - /*! Compression parameters and scratch space pointers (allocated by the library). */ - struct jpeg_compress_struct cinfo; - - /*! The library error handler. */ - struct jpeg_error_mgr jerror; cinfo.err = jpeg_std_error(&jerror); - - /*! Initialize the JPEG compression object. */ - jpeg_create_compress(&cinfo); - - /*! Specify the incoming image resolution, color space, and color space components. */ - cinfo.image_width = image->width; cinfo.image_height = image->height; cinfo.in_color_space = JCS_RGB; cinfo.input_components = 3; - - /*! Fill in a sensible set of defaults. */ - jpeg_set_defaults(&cinfo); - - /*! Specify the data source. */ - jpeg_stdio_dest(&cinfo, file); - - /*! Allocate storage for the uncompressed packed image. */ - unsigned char *rgb = (unsigned char *) malloc(image->height * image->width); - - /*! Convert the image to unsigned char RGB. */ - for (size_t y=0, i=0 ; y < image->height ; y++) { - for (size_t x=0 ; x < image->width ; x++) { - const Color4 pixel = image->get(x, y); - rgb[i++] = (unsigned char)(clamp(pixel.r) * 255.0f); - rgb[i++] = (unsigned char)(clamp(pixel.g) * 255.0f); - rgb[i++] = (unsigned char)(clamp(pixel.b) * 255.0f); - } - } - - /*! Compress and write the image into the target file. */ - compress(&cinfo, rgb); - - /*! At this point 'jerror.num_warnings' could be checked for corrupt-data warnings. */ - jpeg_destroy_compress(&cinfo); free(rgb); fclose(file); - - } - -} - -#endif // USE_LIBJPEG - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/magick.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/magick.cpp deleted file mode 100644 index 470814fdc05c..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/magick.cpp +++ /dev/null @@ -1,73 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#ifdef USE_IMAGEMAGICK - -#include "image.h" -#include - -/*! include Image Magick headers */ -#include -using namespace Magick; - -namespace embree -{ - Ref loadMagick(const FileName& fileName) - { - Magick::Image image(fileName.c_str()); - Image* out = new Image4uc(image.columns(),image.rows(),fileName); - float rcpMaxRGB = 1.0f/float(MaxRGB); - Magick::Pixels pixel_cache(image); - Magick::PixelPacket* pixels = pixel_cache.get(0,0,out->width,out->height); - - for (size_t y=0; yheight; y++) { - for (size_t x=0; xwidth; x++) { - Color4 c; - c.r = float(pixels[y*out->width+x].red )*rcpMaxRGB; - c.g = float(pixels[y*out->width+x].green )*rcpMaxRGB; - c.b = float(pixels[y*out->width+x].blue )*rcpMaxRGB; - c.a = float(pixels[y*out->width+x].opacity)*rcpMaxRGB; - out->set(x,y,c); - } - } - - return out; - } - - void storeMagick(const Ref& img, const FileName& fileName) - { - Magick::Image image(Magick::Geometry(img->width,img->height), - Magick::ColorRGB(0,0,0)); - image.modifyImage(); - - Magick::Pixels pixel_cache(image); - Magick::PixelPacket* pixels = pixel_cache.get(0,0,img->width,img->height); - for (size_t y=0; yheight; y++) { - for (size_t x=0; xwidth; x++) { - Color4 c = img->get(x,y); - pixels[y*img->width+x].red = Magick::Quantum(clamp(c.r)*MaxRGB); - pixels[y*img->width+x].green = Magick::Quantum(clamp(c.g)*MaxRGB); - pixels[y*img->width+x].blue = Magick::Quantum(clamp(c.b)*MaxRGB); - pixels[y*img->width+x].opacity = Magick::Quantum(clamp(c.a)*MaxRGB); - } - } - pixel_cache.sync(); - image.write(fileName.c_str()); - } -} - -#endif // USE_IMAGEMAGICK - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/pfm.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/pfm.cpp deleted file mode 100644 index 9676df442dbb..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/pfm.cpp +++ /dev/null @@ -1,114 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "image.h" - -#include -#include -#include - -namespace embree -{ - /*! read a single comment line starting with #, or read a space */ - static bool readCommentLine(FILE* file) - { - int c = fgetc(file); - if (isspace(c)) return true; - if (c != '#') { - ungetc(c, file); - return false; - } - char line[1024]; - if (fgets(line, sizeof(line), file) == nullptr) - THROW_RUNTIME_ERROR("Error reading PPM file!"); - return true; - } - - /*! read PFM file from disk */ - Ref loadPFM(const FileName& fileName) - { - /* open PPM file */ - FILE* file = fopen(fileName.c_str(), "rb"); - if (!file) THROW_RUNTIME_ERROR("cannot open " + fileName.str()); - - /* read file type */ - char type[8]; - if (fscanf(file, "%7s", type) != 1) - THROW_RUNTIME_ERROR("Error reading " + fileName.str()); - - /* skip comment lines */ - while (readCommentLine(file)) {}; - - /* read width, height, and maximal color value */ - int width, height; - float maxColor; - if (fscanf(file, "%i %i %f", &width, &height, &maxColor) != 3) - THROW_RUNTIME_ERROR("Error reading " + fileName.str()); - - /* Check for big endian PFM file */ - if (maxColor > 0.0f) { - fclose(file); - THROW_RUNTIME_ERROR("Big endian PFM files not supported"); - } - float rcpMaxColor = -1.0f/float(maxColor); - - /* get return or space */ - fgetc(file); - - /* create image and fill with data */ - Ref img = new Image3f(width,height,fileName); - - /* image in binary format 32 bit */ - if (!strcmp(type, "PF")) - { - float rgb[3]; - for (ssize_t y=0; yset(x,y,Color4(float(rgb[0])*rcpMaxColor,float(rgb[1])*rcpMaxColor,float(rgb[2])*rcpMaxColor,1.0f)); - } - } - } - - /* invalid magic value */ - else { - fclose(file); - THROW_RUNTIME_ERROR("Invalid magic value in PFM file"); - } - - fclose(file); - return img; - } - - /*! store PFM file to disk */ - void storePFM(const Ref& img, const FileName& fileName) - { - FILE* file = fopen(fileName.c_str(), "wb"); - if (!file) THROW_RUNTIME_ERROR("cannot open file " + fileName.str()); - fprintf(file,"PF\n%i %i\n%f\n", int(img->width), int(img->height), -1.0f); - - float rgb[3]; - for (size_t y=0; yheight; y++) { - for (size_t x=0; xwidth; x++) { - Color4 c = img->get(x,y); - rgb[0] = c.r; rgb[1] = c.g; rgb[2] = c.b; - fwrite(rgb,sizeof(rgb),1,file); - } - } - fclose(file); - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/png.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/png.cpp deleted file mode 100644 index ad2e83caa993..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/png.cpp +++ /dev/null @@ -1,174 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#ifdef USE_LIBPNG - -#include "image.h" - -#include -#include -#include -#include - -namespace embree -{ - /*! read PNG file from disk */ - Ref loadPNG(const FileName& fileName) - { - size_t width, height; - - //header for testing if it is a png - png_byte header[8]; - - //open file as binary - FILE* fp = fopen(fileName.c_str(), "rb"); - if (!fp) - THROW_RUNTIME_ERROR("cannot open file "+fileName.str()); - - //read the header - fread(header, 1, 8, fp); - - //test if png - int is_png = !png_sig_cmp(header, 0, 8); - if (!is_png) { - fclose(fp); - THROW_RUNTIME_ERROR("invalid PNG file "+fileName.str()); - } - - //create png struct - png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, - nullptr, nullptr); - if (!png_ptr) { - fclose(fp); - THROW_RUNTIME_ERROR("invalid PNG file "+fileName.str()); - } - - //create png info struct - png_infop info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - png_destroy_read_struct(&png_ptr, (png_infopp) nullptr, (png_infopp) nullptr); - fclose(fp); - THROW_RUNTIME_ERROR("invalid PNG file "+fileName.str()); - } - - //create png info struct - png_infop end_info = png_create_info_struct(png_ptr); - if (!end_info) { - png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) nullptr); - fclose(fp); - THROW_RUNTIME_ERROR("invalid PNG file "+fileName.str()); - } - - //png error stuff, not sure libpng man suggests this. - //if (setjmp(png_jmpbuf(png_ptr))) { - // png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); - // fclose(fp); - /// return (TEXTURE_LOAD_ERROR); - //} - - //init png reading - png_init_io(png_ptr, fp); - - //let libpng know you already read the first 8 bytes - png_set_sig_bytes(png_ptr, 8); - - // read all the info up to the image data - png_read_info(png_ptr, info_ptr); - - //variables to pass to get info - int bit_depth, color_type; - png_uint_32 twidth, theight; - - // get info about png - png_get_IHDR(png_ptr, info_ptr, &twidth, &theight, &bit_depth, &color_type, - nullptr, nullptr, nullptr); - - //update width and height based on png info - width = twidth; - height = theight; - - Ref img = new Image4uc(width,height,fileName); - - // Update the png info struct. - png_read_update_info(png_ptr, info_ptr); - - // Row size in bytes. - int rowbytes = png_get_rowbytes(png_ptr, info_ptr); - - // Allocate the image_data as a big block, to be given to opengl - unsigned char *data = new png_byte[rowbytes * height]; - if (!data) { - //clean up memory and close stuff - png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); - fclose(fp); - THROW_RUNTIME_ERROR("invalid PNG file "+fileName.str()); - return img; - } - - // row_pointers is for pointing to image_data for reading the png with libpng - png_bytep *row_pointers = new png_bytep[height]; - if (!row_pointers) { - //clean up memory and close stuff - png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); - delete[] data; - fclose(fp); - THROW_RUNTIME_ERROR("invalid PNG file "+fileName.str()); - } - - // set the individual row_pointers to point at the correct offsets of image_data - for (int i = 0; i < height; ++i) - row_pointers[height - 1 - i] = (unsigned char*)data + i * rowbytes; - - // read the png into image_data through row_pointers - png_read_image(png_ptr, row_pointers); - - // clean up memory and close stuff - png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); - delete[] row_pointers; - fclose(fp); - - - if (color_type == PNG_COLOR_TYPE_RGB && bit_depth == 8) - { - for (size_t y=0;yset(x,y,c); - } - } - else if (color_type == PNG_COLOR_TYPE_RGBA && bit_depth == 8) - { - for (size_t y=0;yset(x,y,c); - } - } - else - THROW_RUNTIME_ERROR("invalid color type in PNG file "+fileName.str()); - - delete[] data; - - return img; - } -} - -#endif - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/ppm.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/ppm.cpp deleted file mode 100644 index 378c6a8bcc4f..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/ppm.cpp +++ /dev/null @@ -1,133 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "image.h" - -#include -#include -#include - -namespace embree -{ - /*! read a single comment line starting with #, or read a space */ - static bool readCommentLine(FILE* file) - { - int c = fgetc(file); - if (isspace(c)) return true; - if (c != '#') { - ungetc(c, file); - return false; - } - char line[1024]; - if(fgets(line, sizeof(line), file) == nullptr) - THROW_RUNTIME_ERROR("Error reading PPM file!"); - return true; - } - - /*! read PPM file from disk */ - Ref loadPPM(const FileName& fileName) - { - /* open PPM file */ - FILE* file = fopen(fileName.c_str(), "rb"); - if (!file) THROW_RUNTIME_ERROR("cannot open " + fileName.str()); - - /* read file type */ - char type[8]; - if (fscanf(file, "%7s", type) != 1) - THROW_RUNTIME_ERROR("Error reading " + fileName.str()); - - /* skip comment lines */ - while (readCommentLine(file)) {}; - - /* read width, height, and maximal color value */ - int width, height, maxColor; - if (fscanf(file, "%i %i %i", &width, &height, &maxColor) != 3) - THROW_RUNTIME_ERROR("Error reading " + fileName.str()); - float rcpMaxColor = 1.0f/float(maxColor); - - /* get return or space */ - fgetc(file); - - /* create image and fill with data */ - Ref img = new Image4uc(width,height,fileName); - - /* image in text format */ - if (!strcmp(type, "P3")) - { - int r, g, b; - for (ssize_t y=0; yset(x,y,Color4(float(r)*rcpMaxColor,float(g)*rcpMaxColor,float(b)*rcpMaxColor,1.0f)); - } - } - } - - /* image in binary format 8 bit */ - else if (!strcmp(type, "P6") && maxColor <= 255) - { - unsigned char rgb[3]; - for (ssize_t y=0; yset(x,y,Color4(float(rgb[0])*rcpMaxColor,float(rgb[1])*rcpMaxColor,float(rgb[2])*rcpMaxColor,1.0f)); - } - } - } - - /* image in binary format 16 bit */ - else if (!strcmp(type, "P6")) - { - unsigned short rgb[3]; - for (ssize_t y=0; yset(x,y,Color4(float(rgb[0])*rcpMaxColor,float(rgb[1])*rcpMaxColor,float(rgb[2])*rcpMaxColor,1.0f)); - } - } - } - - /* invalid magic value */ - else { - fclose(file); - THROW_RUNTIME_ERROR("Invalid magic value in PPM file"); - } - - fclose(file); - return img; - } - - /*! store PPM file to disk */ - void storePPM(const Ref& img, const FileName& fileName) - { - FILE* file = fopen(fileName.c_str(), "wb"); - if (!file) THROW_RUNTIME_ERROR("cannot open file " + fileName.str()); - fprintf(file,"P6\n%i %i\n255\n", int(img->width), int(img->height)); - - for (size_t y=0; yheight; y++) { - for (size_t x=0; xwidth; x++) { - const Color4 c = img->get(x,y); - fputc((unsigned char)(clamp(c.r)*255.0f), file); - fputc((unsigned char)(clamp(c.g)*255.0f), file); - fputc((unsigned char)(clamp(c.b)*255.0f), file); - } - } - fclose(file); - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/tga.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/tga.cpp deleted file mode 100644 index 235f96adc367..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/image/tga.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "image.h" - -#include - -namespace embree -{ - inline void fwrite_uchar (unsigned char v, FILE* file) { fwrite(&v, sizeof(v), 1, file); } - inline void fwrite_ushort(unsigned short v, FILE* file) { fwrite(&v, sizeof(v), 1, file); } - - void storeTga(const Ref& img, const FileName& fileName) - { - FILE* file = fopen(fileName.c_str(), "wb"); - if (!file) THROW_RUNTIME_ERROR("error opening file " + fileName.str()); - - fwrite_uchar(0x00, file); - fwrite_uchar(0x00, file); - fwrite_uchar(0x02, file); - fwrite_ushort(0x0000, file); - fwrite_ushort(0x0000, file); - fwrite_ushort(0x0000, file); - fwrite_ushort(0x0000, file); - fwrite_uchar(0x00, file); - fwrite_ushort((unsigned short)img->width , file); - fwrite_ushort((unsigned short)img->height, file); - fwrite_uchar(0x18, file); - fwrite_uchar(0x20, file); - - for (size_t y=0; yheight; y++) { - for (size_t x=0; xwidth; x++) { - Color c = img->get(x,y); - fwrite_uchar((unsigned char)(clamp(c.b)*255.0f), file); - fwrite_uchar((unsigned char)(clamp(c.g)*255.0f), file); - fwrite_uchar((unsigned char)(clamp(c.r)*255.0f), file); - } - } - fclose(file); - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/transport/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/transport/CMakeLists.txt deleted file mode 100644 index e4821328125c..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/transport/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2015 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -ADD_LIBRARY(transport STATIC transport.cpp) -TARGET_LINK_LIBRARIES(transport sys) -SET_PROPERTY(TARGET transport PROPERTY FOLDER tutorials/common) \ No newline at end of file diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/transport/transport.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/transport/transport.cpp deleted file mode 100644 index eec88fa2f456..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/transport/transport.cpp +++ /dev/null @@ -1,225 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "transport_host.h" -#include "transport_device.h" -#include "../../common/tutorial/obj_loader.h" -#include "../../common/tutorial/tutorial_device.h" -#include "../../common/tutorial/scene_device.h" - -extern "C" int64_t get_tsc() { - return read_tsc(); -} - -namespace embree -{ - /* framebuffer */ - int* g_pixels = nullptr; - int g_width = -1; - int g_height = -1; - - /* scene */ - extern "C" ISPCScene* g_ispc_scene = nullptr; - - extern "C" ISPCScene** g_ispc_scene_keyframes = nullptr; - extern "C" size_t g_numframes = 0; - - ISPCHairSet* convertHair (OBJScene::HairSet* in) - { - ISPCHairSet* out = new ISPCHairSet; - out->v = in->v.size() ? &in->v[0] : nullptr; - out->v2 = in->v2.size() ? &in->v2[0] : nullptr; - out->hairs = (ISPCHair*) (in->hairs.size() ? &in->hairs[0] : nullptr); - out->numVertices = in->v.size(); - out->numHairs = in->hairs.size(); - return out; - } - - ISPCMesh* convertMesh (OBJScene::Mesh* in) - { - ISPCMesh* out = new ISPCMesh; - out->positions = in->v.size() ? &in->v[0] : nullptr; - out->positions2 = in->v2.size() ? &in->v2[0] : nullptr; - out->normals = in->vn.size() ? &in->vn[0] : nullptr; - out->texcoords = in->vt.size() ? &in->vt[0] : nullptr; - out->triangles = (ISPCTriangle*) (in->triangles.size() ? &in->triangles[0] : nullptr); - out->quads = (ISPCQuad*) (in->quads.size() ? &in->quads[0] : nullptr); - out->numVertices = in->v.size(); - out->numTriangles = in->triangles.size(); - out->numQuads = in->quads.size(); - out->geomID = -1; - out->meshMaterialID = in->meshMaterialID; - return out; - } - - ISPCSubdivMesh* convertSubdivMesh (OBJScene::SubdivMesh* in) - { - ISPCSubdivMesh* out = new ISPCSubdivMesh; - out->positions = in->positions.size() ? &in->positions[0] : nullptr; - out->normals = in->normals.size() ? &in->normals[0] : nullptr; - out->texcoords = in->texcoords.size() ? &in->texcoords[0] : nullptr; - out->position_indices = in->position_indices.size() ? &in->position_indices[0] : nullptr; - out->normal_indices = in->normal_indices.size() ? &in->normal_indices[0] : nullptr; - out->texcoord_indices = in->texcoord_indices.size() ? &in->texcoord_indices[0] : nullptr; - out->verticesPerFace = in->verticesPerFace.size() ? &in->verticesPerFace[0] : nullptr; - out->holes = in->holes.size() ? &in->holes[0] : nullptr; - out->edge_creases = in->edge_creases.size() ? &in->edge_creases[0] : nullptr; - out->edge_crease_weights = in->edge_crease_weights.size() ? &in->edge_crease_weights[0] : nullptr; - out->vertex_creases = in->vertex_creases.size() ? &in->vertex_creases[0] : nullptr; - out->vertex_crease_weights = in->vertex_crease_weights.size() ? &in->vertex_crease_weights[0] : nullptr; - out->numVertices = in->positions.size(); - out->numFaces = in->verticesPerFace.size(); - out->numEdges = in->position_indices.size(); - out->numEdgeCreases = in->edge_creases.size(); - out->numVertexCreases = in->vertex_creases.size(); - out->numHoles = in->holes.size(); - out->materialID = in->materialID; - out->geomID = -1; - out->colors = (Vec3fa*) alignedMalloc(in->positions.size()*sizeof(Vec3fa)); - for (size_t i=0; ipositions.size(); i++) - out->colors[i] = Vec3fa(drand48(),drand48(),drand48()); - - size_t numEdges = in->position_indices.size(); - size_t numFaces = in->verticesPerFace.size(); - out->subdivlevel = new float[numEdges]; - out->face_offsets = new int[numFaces]; - for (size_t i=0; isubdivlevel[i] = 1.0f; - int offset = 0; - for (size_t i=0; iface_offsets[i] = offset; - offset+=out->verticesPerFace[i]; - } - return out; - } - - void init(const char* cfg) { - device_init(cfg); - } - - void key_pressed (int key) - { - call_key_pressed_handler(key); - } - - void resize(int width, int height) - { - if (width == g_width && height == g_height) - return; - - if (g_pixels) alignedFree(g_pixels); - g_width = width; - g_height = height; - g_pixels = (int*) alignedMalloc(g_width*g_height*sizeof(int),64); - } - - void set_scene (OBJScene* in) - { - ISPCScene* out = new ISPCScene; - - size_t total_triangles = 0; - size_t total_quads = 0; - - out->meshes = new ISPCMesh*[in->meshes.size()]; - for (size_t i=0; imeshes.size(); i++) - { - out->meshes[i] = convertMesh(in->meshes[i]); - total_triangles += out->meshes[i]->numTriangles; - total_quads += out->meshes[i]->numQuads; - } - - out->numMeshes = in->meshes.size(); - - out->materials = (ISPCMaterial*) (in->materials.size() ? &in->materials[0] : nullptr); - out->numMaterials = in->materials.size(); - - out->hairs = new ISPCHairSet*[in->hairsets.size()]; - for (size_t i=0; ihairsets.size(); i++) out->hairs[i] = convertHair(in->hairsets[i]); - out->numHairSets = in->hairsets.size(); - - out->ambientLights = (ISPCAmbientLight*) (in->ambientLights.size() ? &*in->ambientLights.begin() : nullptr); - out->numAmbientLights = in->ambientLights.size(); - - out->pointLights = (ISPCPointLight*) (in->pointLights.size() ? &*in->pointLights.begin() : nullptr); - out->numPointLights = in->pointLights.size(); - - out->dirLights = (ISPCDirectionalLight*) (in->directionalLights.size() ? &*in->directionalLights.begin() : nullptr); - out->numDirectionalLights = in->directionalLights.size(); - - out->distantLights = (ISPCDistantLight*) (in->distantLights.size() ? &*in->distantLights.begin() : nullptr); - out->numDistantLights = in->distantLights.size(); - - out->subdiv = new ISPCSubdivMesh*[in->subdiv.size()]; - - size_t coarse_primitives = 0; - for (size_t i=0; isubdiv.size(); i++) - { - out->subdiv[i] = convertSubdivMesh(in->subdiv[i]); - coarse_primitives += out->subdiv[i]->numFaces; - } - out->numSubdivMeshes = in->subdiv.size(); - - out->subdivMeshKeyFrames = nullptr; - out->numSubdivMeshKeyFrames = 0; - - g_ispc_scene = out; - } - - void set_scene_keyframes(OBJScene** in, size_t numKeyFrames) - { - if (g_ispc_scene) - { - g_ispc_scene->subdivMeshKeyFrames = new ISPCSubdivMeshKeyFrame*[numKeyFrames]; - g_ispc_scene->numSubdivMeshKeyFrames = numKeyFrames; - for (size_t k=0;ksubdiv = new ISPCSubdivMesh*[in[k]->subdiv.size()]; - - for (size_t i=0; isubdiv.size(); i++) - kf->subdiv[i] = convertSubdivMesh(in[k]->subdiv[i]); - - kf->numSubdivMeshes = in[k]->subdiv.size(); - - g_ispc_scene->subdivMeshKeyFrames[k] = kf; - - } - } - } - - bool pick(const float x, const float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p, Vec3fa& hitPos) { - return device_pick(x,y,vx,vy,vz,p,hitPos); - } - - void render(const float time, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p) { - device_render(g_pixels,g_width,g_height,time,vx,vy,vz,p); - } - - int* map () { - return g_pixels; - } - - void unmap () { - } - - void cleanup() - { - device_cleanup(); - alignedFree(g_pixels); - g_pixels = nullptr; - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/transport/transport_device.h b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/transport/transport_device.h deleted file mode 100644 index 09c7565eee76..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/transport/transport_device.h +++ /dev/null @@ -1,49 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../../../common/math/vec3.h" - -namespace embree -{ - struct Scene - { - void* materials; //!< material list - void* positions; //!< vertex position array - void* normals; //!< vertex normal array - void* texcoords; //!< vertex texcoord array - void* triangles; //!< list of triangles - int numMaterials; - int numVertices; - int numTriangles; - embree::Vec3f pointLightPosition; - embree::Vec3f pointLightIntensity; - embree::Vec3f ambientLightIntensity; - }; - - extern "C" void device_init(const char* cfg); - extern "C" void call_key_pressed_handler (int key); - extern "C" void (*key_pressed_handler)(int key); - - extern "C" void device_set_scene(Scene* scene); - extern "C" void device_resize(int width, int height); - extern "C" bool device_pick(const float x, const float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p, Vec3fa& hitPos); - - extern "C" void device_render(int* pixels, const int width, const int height, - const float time, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p); - extern "C" void device_cleanup(); -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/transport/transport_host.h b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/transport/transport_host.h deleted file mode 100644 index 0d7feb25e9fa..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/transport/transport_host.h +++ /dev/null @@ -1,52 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../../../common/math/vec3.h" - -namespace embree -{ - /* initialize renderer */ - void init(const char* cfg); - - /* keypressed event */ - void key_pressed(int key); - - /* resize framebuffer */ - void resize(int width, int height); - - /* set scene to use */ - struct OBJScene; - void set_scene (OBJScene* in); - - void set_scene_keyframes(OBJScene** in, size_t numKeyFrames); - - /* pick event */ - bool pick(const float x, const float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p, Vec3fa& hitPos); - - /* render frame and map framebuffer */ - void render(const float time, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p); - - /* map framebuffer */ - int* map (); - - /* unmap framebuffer */ - void unmap (); - - /* cleanup renderer */ - void cleanup(); -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/transport_coi/common.h b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/transport_coi/common.h deleted file mode 100644 index bfa353bcabbc..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/transport_coi/common.h +++ /dev/null @@ -1,96 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../../../common/math/vec3.h" - -namespace embree -{ - struct InitData - { - char cfg[1024]; - }; - - struct KeyPressedData - { - int key; - }; - - struct CreateSceneData - { - int numMaterials; - int numMeshes; - int numHairSets; - int numAmbientLights; - int numPointLights; - int numDirectionalLights; - int numDistantLights; - int numSubdivMeshes; - }; - - struct CreateMeshData - { - int numVertices; - int numTriangles; - int numQuads; - int meshMaterialID; - }; - - struct CreateSubdivMeshData - { - int numPositions; - int numNormals; - int numTextureCoords; - int numPositionIndices; - int numNormalIndices; - int numTexCoordIndices; - int numVerticesPerFace; - int numHoles; - int numEdgeCreases; - int numEdgeCreaseWeights; - int numVertexCreases; - int numVertexCreaseWeights; - int materialID; - }; - - struct CreateHairSetData - { - int numVertices; - int numHairs; - }; - - struct ResizeData { - int width, height; - }; - - struct PickDataSend { - float x,y; - Vec3fa vx,vy,vz,p; - }; - - struct PickDataReceive { - Vec3fa pos; - bool hit; - }; - - struct RenderData { - float time; - Vec3fa vx,vy,vz,p; - int width; - int height; - }; -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/transport_coi/device/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/transport_coi/device/CMakeLists.txt deleted file mode 100644 index f619042ba650..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/transport_coi/device/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2015 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -INCLUDE (icc_xeonphi) - -FIND_PACKAGE(COI REQUIRED) -INCLUDE_DIRECTORIES(${COI_INCLUDE_PATHS}) - -ADD_LIBRARY(transport_device STATIC tutorials_device.cpp) -SET_PROPERTY(TARGET transport_device PROPERTY FOLDER tutorials/common) -TARGET_LINK_LIBRARIES(transport_device ${COI_DEV_LIBRARIES}) diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/transport_coi/device/tutorials_device.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/transport_coi/device/tutorials_device.cpp deleted file mode 100644 index 22c5b66d087b..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/transport_coi/device/tutorials_device.cpp +++ /dev/null @@ -1,593 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../../../common/tutorial/obj_loader.h" -#include "../../transport/transport_host.h" -#include "../../transport/transport_device.h" -#include "../common.h" - -#include -#include -#include -#include -#include - - -extern "C" int64_t get_tsc() { -return embree::read_tsc(); -} - -float g_debug = 0.0f; - -namespace embree -{ - /* ISPC compatible mesh */ - struct ISPCMesh - { - ALIGNED_CLASS; - public: - ISPCMesh (int numTriangles, - int numQuads, - int numVertices, - int meshMaterialID) - : numTriangles(numTriangles), numQuads(numQuads), numVertices(numVertices), - positions(nullptr), positions2(nullptr), normals(nullptr), texcoords(nullptr), triangles(nullptr), quads(nullptr), edge_level(nullptr), meshMaterialID(meshMaterialID) - { - sizePositions = 0; - sizeNormals = 0; - sizeTexCoords = 0; - sizeTriangles = 0; - sizeQuads = 0; - } - - ~ISPCMesh () { - if (positions) os_free(positions ,sizePositions); - if (positions2) os_free(positions2,sizePositions); - if (normals) os_free(normals ,sizeNormals); - if (texcoords) os_free(texcoords ,sizeTexCoords); - if (triangles) os_free(triangles ,sizeTriangles); - if (quads) os_free(quads ,sizeQuads); - - positions = nullptr; - positions2 = nullptr; - normals = nullptr; - texcoords = nullptr; - triangles = nullptr; - quads = nullptr; - } - - public: - Vec3fa* positions; //!< vertex position array - Vec3fa* positions2; //!< vertex position array - Vec3fa* normals; //!< vertex normal array - Vec2f* texcoords; //!< vertex texcoord array - OBJScene::Triangle* triangles; //!< list of triangles - OBJScene::Quad* quads; //!< list of quads - float *edge_level; - - int numVertices; - int numTriangles; - int numQuads; - int geomID; - int meshMaterialID; - size_t sizePositions; - size_t sizeNormals; - size_t sizeTexCoords; - size_t sizeTriangles; - size_t sizeQuads; - }; - - -struct ISPCSubdivMesh -{ - ALIGNED_CLASS; -public: - ISPCSubdivMesh(int numVertices, int numFaces, int numEdges, int materialID) : - numVertices(numVertices), numFaces(numFaces), numEdges(numEdges), materialID(materialID), - numEdgeCreases(0),numVertexCreases(0),numHoles(0),geomID(0), - positions(nullptr),normals(nullptr),position_indices(nullptr), - normal_indices(nullptr),texcoord_indices(nullptr), verticesPerFace(nullptr), - holes(nullptr), subdivlevel(nullptr), - edge_creases(nullptr), edge_crease_weights(nullptr), vertex_creases(nullptr), - vertex_crease_weights(nullptr) - { - //PRINT(numVertices); - //PRINT(numFaces); - //PRINT(numEdges); - } - - Vec3fa* positions; //!< vertex positions - Vec3fa* normals; //!< face vertex normals - Vec2f* texcoords; //!< face texture coordinates - int* position_indices; //!< position indices for all faces - int* normal_indices; //!< normal indices for all faces - int* texcoord_indices; //!< texcoord indices for all faces - int* verticesPerFace; //!< number of indices of each face - int* holes; //!< face ID of holes - float* subdivlevel; //!< subdivision level - Vec2i* edge_creases; //!< crease index pairs - float* edge_crease_weights; //!< weight for each crease - int* vertex_creases; //!< indices of vertex creases - float* vertex_crease_weights; //!< weight for each vertex crease - int* face_offsets; - int numVertices; - int numFaces; - int numEdges; - int numEdgeCreases; - int numVertexCreases; - int numHoles; - int materialID; - int geomID; -}; - - /* ISPC compatible scene */ - struct ISPCHair - { - public: - ISPCHair () {} - ISPCHair (int vertex, int id) - : vertex(vertex), id(id) {} - - int vertex,id; //!< index of first control point and hair ID - }; - - /*! Hair Set. */ - struct ISPCHairSet - { - ALIGNED_CLASS; - public: - Vec3fa *positions; //!< hair control points (x,y,z,r) - Vec3fa *positions2; //!< hair control points (x,y,z,r) - ISPCHair *hairs; //!< list of hairs - int numVertices; - int numHairs; - ISPCHairSet(int numHairs, int numVertices) - : numHairs(numHairs),numVertices(numVertices),positions(nullptr),positions2(nullptr),hairs(nullptr) {} - ~ISPCHairSet() { - if (positions) free(positions); - if (positions2) free(positions2); - if (hairs) free(hairs); - } - }; - -struct ISPCSubdivMeshKeyFrame { - ISPCSubdivMesh** subdiv; //!< list of subdiv meshes - int numSubdivMeshes; //!< number of subdiv meshes -}; - - - /* ISPC compatible scene */ - struct ISPCScene - { - ALIGNED_CLASS; - public: - ISPCScene (int numMeshes, int numHairSets, - void* materials_in, int numMaterials, - void* ambientLights_in, int numAmbientLights, - void* pointLights_in, int numPointLights, - void* directionalLights_in, int numDirectionalLights, - void* distantLights_in, int numDistantLights, - int numSubdivMeshes) - - : meshes(nullptr), numMeshes(numMeshes), numHairSets(numHairSets), - materials(nullptr), numMaterials(numMaterials), - ambientLights(nullptr), numAmbientLights(numAmbientLights), - pointLights(nullptr), numPointLights(numPointLights), - directionalLights(nullptr), numDirectionalLights(numDirectionalLights), - distantLights(nullptr), numDistantLights(numDistantLights), - subdiv(nullptr), numSubdivMeshes(numSubdivMeshes), subdivMeshKeyFrames(nullptr), numSubdivMeshKeyFrames(0) - { - meshes = new ISPCMesh*[numMeshes]; - for (size_t i=0; imap_Kd = NULL; - objm->map_Displ = NULL; - } - - ambientLights = new AmbientLight[numAmbientLights]; - memcpy(ambientLights,ambientLights_in,numAmbientLights*sizeof(AmbientLight)); - - pointLights = new PointLight[numPointLights]; - memcpy(pointLights,pointLights_in,numPointLights*sizeof(PointLight)); - - directionalLights = new DirectionalLight[numDirectionalLights]; - memcpy(directionalLights,directionalLights_in,numDirectionalLights*sizeof(DirectionalLight)); - - distantLights = new DistantLight[numDistantLights]; - memcpy(distantLights,distantLights_in,numDistantLights*sizeof(DistantLight)); - - subdiv = new ISPCSubdivMesh*[numSubdivMeshes]; - for (size_t i=0; icfg); - } - - extern "C" void run_key_pressed(uint32_t in_BufferCount, - void** in_ppBufferPointers, - uint64_t* in_pBufferLengths, - KeyPressedData* in_pMiscData, - uint16_t in_MiscDataLength, - void* in_pReturnValue, - uint16_t in_ReturnValueLength) - { - call_key_pressed_handler(in_pMiscData->key); - } - - extern "C" void run_create_mesh(uint32_t in_BufferCount, - void** in_ppBufferPointers, - uint64_t* in_pBufferLengths, - CreateMeshData* in_pMiscData, - uint16_t in_MiscDataLength, - void* in_pReturnValue, - uint16_t in_ReturnValueLength) - { - size_t meshID = g_meshID++; - -#if 0 - PRINT( in_pMiscData->numTriangles ); - PRINT( in_pMiscData->numQuads ); - PRINT( in_pMiscData->numVertices ); -#endif - - ISPCMesh* mesh = new ISPCMesh(in_pMiscData->numTriangles,in_pMiscData->numQuads,in_pMiscData->numVertices,in_pMiscData->meshMaterialID); - assert( mesh ); - assert( in_pMiscData->numTriangles*sizeof(OBJScene::Triangle) == in_pBufferLengths[3] ); - assert( in_pMiscData->numQuads*sizeof(OBJScene::Quad) == in_pBufferLengths[4] ); - - //assert( in_pMiscData->numVertices*sizeof(Vec3fa) == in_pBufferLengths[1] ); - - mesh->positions = (Vec3fa*)os_malloc(in_pBufferLengths[0]); - mesh->normals = (Vec3fa*)os_malloc(in_pBufferLengths[1]); - mesh->texcoords = (Vec2f* )os_malloc(in_pBufferLengths[2]); - mesh->triangles = (OBJScene::Triangle*)os_malloc(in_pBufferLengths[3]); - mesh->quads = (OBJScene::Quad*)os_malloc(in_pBufferLengths[4]); - - memcpy(mesh->positions,in_ppBufferPointers[0],in_pBufferLengths[0]); - memcpy(mesh->normals ,in_ppBufferPointers[1],in_pBufferLengths[1]); - memcpy(mesh->texcoords,in_ppBufferPointers[2],in_pBufferLengths[2]); - memcpy(mesh->triangles,in_ppBufferPointers[3],in_pBufferLengths[3]); - memcpy(mesh->quads ,in_ppBufferPointers[4],in_pBufferLengths[4]); - - mesh->sizePositions = in_pBufferLengths[0]; - mesh->sizeNormals = in_pBufferLengths[1]; - mesh->sizeTexCoords = in_pBufferLengths[2]; - mesh->sizeTriangles = in_pBufferLengths[3]; - mesh->sizeQuads = in_pBufferLengths[4]; - -#if 1 - if (mesh->quads[0].v0 == 0, - mesh->quads[0].v1 == 0, - mesh->quads[0].v2 == 0, - mesh->quads[0].v3 == 0) - { - mesh->quads = nullptr; - mesh->numQuads = 0; - mesh->sizeQuads = 0; - } -#endif - -#if 0 - PRINT( mesh->sizePositions ); - PRINT( mesh->sizeNormals ); - PRINT( mesh->sizeTexCoords ); - PRINT( mesh->sizeTriangles ); - PRINT( mesh->sizeQuads ); -#endif - - g_ispc_scene->meshes[meshID] = mesh; - } - - - extern "C" void run_create_subdiv_mesh(uint32_t in_BufferCount, - void** in_ppBufferPointers, - uint64_t* in_pBufferLengths, - CreateSubdivMeshData* in_pMiscData, - uint16_t in_MiscDataLength, - void* in_pReturnValue, - uint16_t in_ReturnValueLength) - { - size_t meshID = g_meshID++; - - const size_t numVertices = in_pMiscData->numPositions; - const size_t numEdges = in_pMiscData->numPositionIndices; - const size_t numFaces = in_pMiscData->numVerticesPerFace; - -#if 0 - PRINT( numVertices ); - PRINT( numEdges ); - PRINT( numFaces ); -#endif - - ISPCSubdivMesh* mesh = new ISPCSubdivMesh(numVertices, - numFaces, - numEdges, - in_pMiscData->materialID); - assert( mesh ); - - assert( in_pMiscData->numPositions*sizeof(Vec3fa) == in_pBufferLengths[0] ); - assert( in_pMiscData->numPositionIndices*sizeof(int) == in_pBufferLengths[1] ); - assert( in_pMiscData->numVerticesPerFace*sizeof(int) == in_pBufferLengths[2] ); - - mesh->positions = (Vec3fa*)os_malloc(in_pBufferLengths[0]); - memcpy(mesh->positions ,in_ppBufferPointers[0],in_pBufferLengths[0]); - - mesh->position_indices = (int*) os_malloc(in_pBufferLengths[1]); - memcpy(mesh->position_indices,in_ppBufferPointers[1],in_pBufferLengths[1]); - - mesh->verticesPerFace = (int*) os_malloc(in_pBufferLengths[2]); - memcpy(mesh->verticesPerFace ,in_ppBufferPointers[2],in_pBufferLengths[2]); - - - mesh->subdivlevel = (float*) os_malloc(in_pBufferLengths[1]); - mesh->face_offsets = (int*) os_malloc(sizeof(int) * in_pMiscData->numVerticesPerFace); - -#if 0 - PRINT("DEVICE"); - PRINT(mesh->numVertices); - PRINT(mesh->numEdges); - PRINT(mesh->numFaces); - PRINT(in_pMiscData->numEdgeCreases); - PRINT(in_pMiscData->numEdgeCreaseWeights); - PRINT(in_pMiscData->numVertexCreases); -#endif - - if ( in_pMiscData->numEdgeCreases ) - { - assert(in_pBufferLengths[3] == sizeof(Vec2i) * in_pMiscData->numEdgeCreases); - mesh->edge_creases = (Vec2i*)os_malloc(sizeof(Vec2i) * in_pMiscData->numEdgeCreases); - memcpy(mesh->edge_creases ,in_ppBufferPointers[3],in_pBufferLengths[3]); - mesh->numEdgeCreases = in_pMiscData->numEdgeCreases; - } - - if ( in_pMiscData->numEdgeCreaseWeights ) - { - assert(in_pBufferLengths[4] == sizeof(float) * in_pMiscData->numEdgeCreaseWeights); - mesh->edge_crease_weights = (float*)os_malloc(sizeof(float) * in_pMiscData->numEdgeCreaseWeights); - memcpy(mesh->edge_crease_weights ,in_ppBufferPointers[4],in_pBufferLengths[4]); - } - - if ( in_pMiscData->numVertexCreases ) - { - mesh->numVertexCreases = in_pMiscData->numVertexCreases; - assert(in_pBufferLengths[5] == sizeof(int) * in_pMiscData->numVertexCreases); - mesh->vertex_creases = (int*)os_malloc(sizeof(int) * in_pMiscData->numVertexCreases); - memcpy(mesh->vertex_creases ,in_ppBufferPointers[5],in_pBufferLengths[5]); - } - - if ( in_pMiscData->numVertexCreaseWeights ) - { - assert(in_pBufferLengths[6] == sizeof(float) * in_pMiscData->numVertexCreaseWeights); - mesh->vertex_crease_weights = (float*)os_malloc(sizeof(float) * in_pMiscData->numVertexCreaseWeights); - memcpy(mesh->vertex_crease_weights ,in_ppBufferPointers[6],in_pBufferLengths[6]); - } - - if ( in_pMiscData->numHoles ) - { - mesh->numHoles = in_pMiscData->numHoles; - assert(in_pBufferLengths[7] == sizeof(int) * in_pMiscData->numHoles); - mesh->holes = (int*)os_malloc(sizeof(int) * in_pMiscData->numHoles); - memcpy(mesh->holes ,in_ppBufferPointers[7],in_pBufferLengths[7]); - } - - for (size_t i=0; isubdivlevel[i] = 1.0f; - int offset = 0; - for (size_t i=0; iface_offsets[i] = offset; - offset+=mesh->verticesPerFace[i]; - } - - g_ispc_scene->subdiv[meshID] = mesh; - } - - extern "C" void run_create_hairset(uint32_t in_BufferCount, - void** in_ppBufferPointers, - uint64_t* in_pBufferLengths, - CreateHairSetData* in_pMiscData, - uint16_t in_MiscDataLength, - void* in_pReturnValue, - uint16_t in_ReturnValueLength) - { - size_t hairsetID = g_hairsetID++; - ISPCHairSet* hairset = new ISPCHairSet(in_pMiscData->numHairs,in_pMiscData->numVertices); - memcpy(hairset->positions = (Vec3fa*)malloc(in_pBufferLengths[0]),in_ppBufferPointers[0],in_pBufferLengths[0]); - memcpy(hairset->hairs = (ISPCHair*)malloc(in_pBufferLengths[1]),in_ppBufferPointers[1],in_pBufferLengths[1]); - g_ispc_scene->hairsets[hairsetID] = hairset; - } - - extern "C" void run_create_scene(uint32_t in_BufferCount, - void** in_ppBufferPointers, - uint64_t* in_pBufferLengths, - CreateSceneData* in_pMiscData, - uint16_t in_MiscDataLength, - void* in_pReturnValue, - uint16_t in_ReturnValueLength) - { - g_meshID = 0; - g_ispc_scene = new ISPCScene(in_pMiscData->numMeshes, - in_pMiscData->numHairSets, - in_ppBufferPointers[0],in_pMiscData->numMaterials, - in_ppBufferPointers[1],in_pMiscData->numAmbientLights, - in_ppBufferPointers[2],in_pMiscData->numPointLights, - in_ppBufferPointers[3],in_pMiscData->numDirectionalLights, - in_ppBufferPointers[4],in_pMiscData->numDistantLights, - in_pMiscData->numSubdivMeshes); - } - - extern "C" void run_pick(uint32_t in_BufferCount, - void** in_ppBufferPointers, - uint64_t* in_pBufferLengths, - PickDataSend* in_pMiscData, - uint16_t in_MiscDataLength, - PickDataReceive* in_pReturnValue, - uint16_t in_ReturnValueLength) - { - Vec3fa hitPos = zero; - bool hit = device_pick(in_pMiscData->x, - in_pMiscData->y, - in_pMiscData->vx, - in_pMiscData->vy, - in_pMiscData->vz, - in_pMiscData->p, - hitPos); - in_pReturnValue->pos = hitPos; - in_pReturnValue->hit = hit; - } - - extern "C" void run_render(uint32_t in_BufferCount, - void** in_ppBufferPointers, - uint64_t* in_pBufferLengths, - RenderData* in_pMiscData, - uint16_t in_MiscDataLength, - void* in_pReturnValue, - uint16_t in_ReturnValueLength) - { - //double t0 = getSeconds(); - device_render((int*)in_ppBufferPointers[0], - in_pMiscData->width, - in_pMiscData->height, - in_pMiscData->time, - in_pMiscData->vx, - in_pMiscData->vy, - in_pMiscData->vz, - in_pMiscData->p); - //double dt = getSeconds() - t0; - //printf("render %3.2f fps, %.2f ms\n",1.0f/dt,dt*1000.0f); flush(std::cout); - } - - extern "C" void run_cleanup(uint32_t in_BufferCount, - void** in_ppBufferPointers, - uint64_t* in_pBufferLengths, - void* in_pMiscData, - uint16_t in_MiscDataLength, - void* in_pReturnValue, - uint16_t in_ReturnValueLength) - { - device_cleanup(); - if (g_ispc_scene) delete g_ispc_scene; g_ispc_scene = nullptr; - } -} - -int main(int argc, char** argv) -{ - UNUSED_ATTR COIRESULT result; - UNREFERENCED_PARAM (argc); - UNREFERENCED_PARAM (argv); - - /* enable wait to attach with debugger */ -#if 0 - std::cout << "waiting for debugger to attach ..." << std::flush; -#if 0 - volatile int loop = 1; - do { - volatile int a = 1; - } while (loop); - -#else - for (int i=0; i<20; i++) { - sleep(1); - std::cout << "." << std::flush; - } -#endif - std::cout << " [DONE]" << std::endl; -#endif - - // Functions enqueued on the sink side will not start executing until - // you call COIPipelineStartExecutingRunFunctions(). This call is to - // synchronize any initialization required on the sink side - result = COIPipelineStartExecutingRunFunctions(); - assert(result == COI_SUCCESS); - - // This call will wait until COIProcessDestroy() gets called on the source - // side. If COIProcessDestroy is called without force flag set, this call - // will make sure all the functions enqueued are executed and does all - // clean up required to exit gracefully. - COIProcessWaitForShutdown(); - return 0; -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/transport_coi/host/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/transport_coi/host/CMakeLists.txt deleted file mode 100644 index ad0f6e7c0832..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/transport_coi/host/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2015 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -FIND_PACKAGE(COI REQUIRED) -INCLUDE_DIRECTORIES(${COI_INCLUDE_PATHS}) - -ADD_LIBRARY(transport_host STATIC tutorials_host.cpp) -SET_PROPERTY(TARGET transport_host PROPERTY FOLDER tutorials/common) -TARGET_LINK_LIBRARIES(transport_host ${COI_HOST_LIBRARIES}) diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/transport_coi/host/tutorials_host.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/transport_coi/host/tutorials_host.cpp deleted file mode 100644 index 754596f27f53..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/transport_coi/host/tutorials_host.cpp +++ /dev/null @@ -1,601 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../../transport/transport_host.h" -#include "../common.h" -#include "../../../common/tutorial/obj_loader.h" -#include "../../../../common/sys/string.h" - -#include -#include -#include -#include -#include - -namespace embree -{ - COIENGINE engine; - COIPROCESS process; - COIPIPELINE pipeline; - - COIFUNCTION runInit; - COIFUNCTION runKeyPressed; - COIFUNCTION runCreateMesh; - COIFUNCTION runCreateHairSet; - COIFUNCTION runCreateScene; - COIFUNCTION runPick; - COIFUNCTION runRender; - COIFUNCTION runCleanup; - COIFUNCTION runCreateSubdivMesh; - - COIBUFFER frameBuffer; - COIMAPINSTANCE mapInst; - int g_width = -1, g_height = -1; - - extern const char* tutorialName; - - void init(const char* cfg) - { - /* get number of Xeon Phi devices */ - uint32_t engines = 0; - COIEngineGetCount( COI_ISA_MIC, &engines ); - if (engines == 0) THROW_RUNTIME_ERROR("No Xeon Phi device found."); - - /* get engine handle */ - COIRESULT result; - result = COIEngineGetHandle( COI_ISA_MIC, 0, &engine ); - if (result != COI_SUCCESS) - THROW_RUNTIME_ERROR("Failed to load engine number " + std::to_string((long long)0) + ": " + COIResultGetName(result)); - - /* print info of engine */ - COI_ENGINE_INFO info; - result = COIEngineGetInfo(engine,sizeof(info),&info); - std::cout << "Found Xeon Phi device with " << info.NumCores << " cores and " << (info.PhysicalMemory/1024/1024) << "MB memory" << std::endl; - - /* create process */ - const FileName executable = FileName::executableFolder()+(std::string(tutorialName)+"_xeonphi_device"); - result = COIProcessCreateFromFile - (engine, - executable.c_str(), // The local path to the sink side binary to launch. - 0, nullptr, // argc and argv for the sink process. - false, nullptr, // Environment variables to set for the sink process. - true, nullptr, // Enable the proxy but don't specify a proxy root path. - 0, // The amount of memory to reserve for COIBuffers. - nullptr, // Path to search for dependencies - &process // The resulting process handle. - ); - - if (result != COI_SUCCESS) - THROW_RUNTIME_ERROR("Failed to create process " + executable.str() +": " + COIResultGetName(result)); - - /* create pipeline */ - COI_CPU_MASK cpuMask; - result = COIPipelineClearCPUMask(&cpuMask); - if (result != COI_SUCCESS) - THROW_RUNTIME_ERROR(std::string("COIPipelineClearCPUMask failed: ") + COIResultGetName(result)); - - result = COIPipelineSetCPUMask(process,info.NumCores-1,0,&cpuMask); - result = COIPipelineSetCPUMask(process,info.NumCores-1,1,&cpuMask); - result = COIPipelineSetCPUMask(process,info.NumCores-1,2,&cpuMask); - result = COIPipelineSetCPUMask(process,info.NumCores-1,3,&cpuMask); - if (result != COI_SUCCESS) - THROW_RUNTIME_ERROR(std::string("COIPipelineSetCPUMask failed: ") + COIResultGetName(result)); - - result = COIPipelineCreate(process,cpuMask,0,&pipeline); - if (result != COI_SUCCESS) - THROW_RUNTIME_ERROR(std::string("COIPipelineCreate failed: ") + COIResultGetName(result)); - - /* get run functions */ - const char *fctNameArray[9] = { "run_init", "run_key_pressed", "run_create_mesh", "run_create_hairset", "run_create_scene", "run_pick", "run_render", "run_cleanup", "run_create_subdiv_mesh" }; - result = COIProcessGetFunctionHandles (process, 9, fctNameArray, &runInit); - if (result != COI_SUCCESS) - THROW_RUNTIME_ERROR("COIProcessGetFunctionHandles failed: "+std::string(COIResultGetName(result))); - - /* run init runfunction */ - InitData parms; - strncpy(parms.cfg,cfg,sizeof(parms.cfg)); - result = COIPipelineRunFunction (pipeline, runInit, 0, nullptr, nullptr, 0, nullptr, &parms, sizeof(parms), nullptr, 0, nullptr); - if (result != COI_SUCCESS) - THROW_RUNTIME_ERROR("COIPipelineRunFunction failed: "+std::string(COIResultGetName(result))); - - } - - void key_pressed(int key) - { - KeyPressedData parms; - parms.key = key; - COIRESULT result = COIPipelineRunFunction (pipeline, runKeyPressed, 0, nullptr, nullptr, 0, nullptr, &parms, sizeof(parms), nullptr, 0, nullptr); - if (result != COI_SUCCESS) - THROW_RUNTIME_ERROR("COIPipelineRunFunction failed: "+std::string(COIResultGetName(result))); - } - - void send_hairset (OBJScene::HairSet* hairset) - { - COIRESULT result; - struct { - COIBUFFER position; //!< vertex position array - COIBUFFER hairs; //!< hair array - } buffers; - - size_t positionBytes = max(size_t(16),hairset->v.size()*sizeof(Vec3fa)); - void* positionPtr = hairset->v.size() ? &hairset->v.front() : nullptr; - result = COIBufferCreate(positionBytes,COI_BUFFER_NORMAL,0,positionPtr,1,&process,&buffers.position); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIBufferCreate failed: " + std::string(COIResultGetName(result))); - - size_t hairsBytes = max(size_t(16),hairset->hairs.size()*sizeof(OBJScene::Hair)); - void* hairsPtr = hairset->hairs.size() ? &hairset->hairs.front() : nullptr; - result = COIBufferCreate(hairsBytes,COI_BUFFER_NORMAL,0,hairsPtr,1,&process,&buffers.hairs); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIBufferCreate failed: " + std::string(COIResultGetName(result))); - - CreateHairSetData parms; - - parms.numVertices = hairset->v.size(); - parms.numHairs = hairset->hairs.size(); - COI_ACCESS_FLAGS flags[2] = { COI_SINK_READ, COI_SINK_READ}; - - COIEVENT event; - memset(&event,0,sizeof(event)); - - /* run set scene runfunction */ - result = COIPipelineRunFunction (pipeline, runCreateHairSet, 2, &buffers.position, flags, 0, nullptr, &parms, sizeof(parms), nullptr, 0, &event); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIPipelineRunFunction failed: "+std::string(COIResultGetName(result))); - - result = COIEventWait(1,&event,-1,1,nullptr,nullptr); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIEventWait failed: "+std::string(COIResultGetName(result))); - - /* destroy buffers again */ - result = COIBufferDestroy(buffers.position); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIPipelineRunFunction failed: "+std::string(COIResultGetName(result))); - result = COIBufferDestroy(buffers.hairs); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIPipelineRunFunction failed: "+std::string(COIResultGetName(result))); - } - - void send_mesh (OBJScene::Mesh* mesh) - { - COIRESULT result; - struct { - COIBUFFER position; //!< vertex position array - COIBUFFER normal; //!< vertex normal array - COIBUFFER texcoord; //!< vertex texcoord array - COIBUFFER triangle; //!< list of triangles - COIBUFFER quad; //!< list of quads - } buffers; - - assert( mesh->v.size() ); - - if (mesh->triangles.size() == 0) - { - OBJScene::Triangle dummy(0,0,0,0); - mesh->triangles.push_back(dummy); - } - - if (mesh->vn.size() == 0) - for (size_t i=0;i<4;i++) - mesh->vn.push_back(Vec3f(0.0f,0.0f,0.0f)); - - if (mesh->vt.size() == 0) - for (size_t i=0;i<2;i++) - mesh->vt.push_back(Vec2f(0.0f,0.0f)); - - if (mesh->quads.size() == 0) - { - OBJScene::Quad dummy(0,0,0,0); - mesh->quads.push_back(dummy); - } - - assert( mesh->vn.size() ); - assert( mesh->vt.size() ); - assert( mesh->quads.size() ); - - - size_t positionBytes = max(size_t(16),mesh->v.size()*sizeof(Vec3fa)); - - void* positionPtr = mesh->v.size() ? &mesh->v.front() : nullptr; - //result = COIBufferCreate(positionBytes,COI_BUFFER_STREAMING_TO_SINK,0,positionPtr,1,&process,&buffers.position); - result = COIBufferCreateFromMemory(positionBytes,COI_BUFFER_NORMAL,0,positionPtr,1,&process,&buffers.position); - - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIBufferCreate failed: " + std::string(COIResultGetName(result))); - - size_t normalBytes = max(size_t(16),mesh->vn.size()*sizeof(Vec3fa)); - void* normalPtr = mesh->vn.size() ? &mesh->vn.front() : nullptr; - //result = COIBufferCreate(normalBytes,COI_BUFFER_STREAMING_TO_SINK,0,normalPtr,1,&process,&buffers.normal); - result = COIBufferCreateFromMemory(normalBytes,COI_BUFFER_NORMAL,0,normalPtr,1,&process,&buffers.normal); - - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIBufferCreate failed: " + std::string(COIResultGetName(result))); - - size_t texcoordBytes = max(size_t(16),mesh->vt.size()*sizeof(Vec2f)); - void* texcoordPtr = mesh->vt.size() ? &mesh->vt.front() : nullptr; - //result = COIBufferCreate(texcoordBytes,COI_BUFFER_STREAMING_TO_SINK,0,texcoordPtr,1,&process,&buffers.texcoord); - result = COIBufferCreateFromMemory(texcoordBytes,COI_BUFFER_NORMAL,0,texcoordPtr,1,&process,&buffers.texcoord); - - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIBufferCreate failed: " + std::string(COIResultGetName(result))); - - size_t triangleBytes = max(size_t(16),mesh->triangles.size()*sizeof(OBJScene::Triangle)); - void* trianglePtr = mesh->triangles.size() ? &mesh->triangles.front() : nullptr; - //result = COIBufferCreate(triangleBytes,COI_BUFFER_STREAMING_TO_SINK,0,trianglePtr,1,&process,&buffers.triangle); - result = COIBufferCreateFromMemory(triangleBytes,COI_BUFFER_NORMAL,0,trianglePtr,1,&process,&buffers.triangle); - - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIBufferCreate failed: " + std::string(COIResultGetName(result))); - - size_t quadBytes = max(size_t(16),mesh->quads.size()*sizeof(OBJScene::Quad)); - void* quadPtr = mesh->quads.size() ? &mesh->quads.front() : nullptr; - //result = COIBufferCreate(quadBytes,COI_BUFFER_STREAMING_TO_SINK,0,quadPtr,1,&process,&buffers.quad); - result = COIBufferCreateFromMemory(quadBytes,COI_BUFFER_NORMAL,0,quadPtr,1,&process,&buffers.quad); - - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIBufferCreate failed: " + std::string(COIResultGetName(result))); - - CreateMeshData parms; - parms.numVertices = mesh->v.size(); - parms.numTriangles = mesh->triangles.size(); - parms.numQuads = mesh->quads.size(); - parms.meshMaterialID = mesh->meshMaterialID; - - COI_ACCESS_FLAGS flags[5] = { COI_SINK_READ, COI_SINK_READ, COI_SINK_READ, COI_SINK_READ, COI_SINK_READ }; - - COIEVENT event; - memset(&event,0,sizeof(event)); - - /* run set scene runfunction */ - result = COIPipelineRunFunction (pipeline, runCreateMesh, 5, &buffers.position, flags, 0, nullptr, &parms, sizeof(parms), nullptr, 0, &event); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIPipelineRunFunction failed: "+std::string(COIResultGetName(result))); - - result = COIEventWait(1,&event,-1,1,nullptr,nullptr); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIEventWait failed: "+std::string(COIResultGetName(result))); - - /* destroy buffers again */ - result = COIBufferDestroy(buffers.position); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIPipelineRunFunction failed: "+std::string(COIResultGetName(result))); - result = COIBufferDestroy(buffers.normal); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIPipelineRunFunction failed: "+std::string(COIResultGetName(result))); - result = COIBufferDestroy(buffers.texcoord); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIPipelineRunFunction failed: "+std::string(COIResultGetName(result))); - result = COIBufferDestroy(buffers.triangle); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIPipelineRunFunction failed: "+std::string(COIResultGetName(result))); - result = COIBufferDestroy(buffers.quad); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIPipelineRunFunction failed: "+std::string(COIResultGetName(result))); - } - - - void send_subdiv_mesh (OBJScene::SubdivMesh* mesh) - { - COIRESULT result; - struct { - COIBUFFER positions; - COIBUFFER position_indices; - COIBUFFER vertices_per_face; - COIBUFFER edge_creases; - COIBUFFER edge_crease_weights; - COIBUFFER vertex_creases; - COIBUFFER vertex_crease_weights; - COIBUFFER holes; - } buffers; - - assert( mesh->positions.size() ); - assert( mesh->position_indices.size() ); - assert( mesh->verticesPerFace.size() ); - -#if 0 - PRINT( "HOST" ); - PRINT( mesh->positions.size() ); - PRINT( mesh->position_indices.size() ); - PRINT( mesh->verticesPerFace.size() ); - PRINT( mesh->edge_creases.size() ); - PRINT( mesh->edge_crease_weights.size() ); - PRINT( mesh->vertex_creases.size() ); - PRINT( mesh->vertex_crease_weights.size() ); - PRINT( mesh->holes.size() ); -#endif - - void *dummy_buffer = &mesh->positions.front(); - - /* positions */ - result = COIBufferCreateFromMemory(mesh->positions.size()*sizeof(Vec3fa), - COI_BUFFER_NORMAL, - 0,&mesh->positions.front(), - 1, - &process, - &buffers.positions); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIBufferCreate failed: " + std::string(COIResultGetName(result))); - - /* position_indices */ - result = COIBufferCreateFromMemory(mesh->position_indices.size()*sizeof(int), - COI_BUFFER_NORMAL, - 0,&mesh->position_indices.front(), - 1, - &process, - &buffers.position_indices); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIBufferCreate failed: " + std::string(COIResultGetName(result))); - - /* vertices_per_face */ - result = COIBufferCreateFromMemory(mesh->verticesPerFace.size()*sizeof(int), - COI_BUFFER_NORMAL, - 0,&mesh->verticesPerFace.front(), - 1, - &process, - &buffers.vertices_per_face); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIBufferCreate failed: " + std::string(COIResultGetName(result))); - - /* edge creases */ - result = COIBufferCreateFromMemory(max((size_t)4,mesh->edge_creases.size()*sizeof(Vec2i)), - COI_BUFFER_NORMAL, - 0, - mesh->edge_creases.size() ? &mesh->edge_creases.front() : dummy_buffer, - 1, - &process, - &buffers.edge_creases); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIBufferCreate failed: " + std::string(COIResultGetName(result))); - - /* edge creases weights */ - result = COIBufferCreateFromMemory(max((size_t)4,mesh->edge_crease_weights.size()*sizeof(float)), - COI_BUFFER_NORMAL, - 0, - mesh->edge_crease_weights.size() ? &mesh->edge_crease_weights.front() : dummy_buffer, - 1, - &process, - &buffers.edge_crease_weights); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIBufferCreate failed: " + std::string(COIResultGetName(result))); - - /* vertex creases */ - result = COIBufferCreateFromMemory(max((size_t)4,mesh->vertex_creases.size()*sizeof(int)), - COI_BUFFER_NORMAL, - 0, - mesh->vertex_creases.size() ? &mesh->vertex_creases.front() : dummy_buffer, - 1, - &process, - &buffers.vertex_creases); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIBufferCreate failed: " + std::string(COIResultGetName(result))); - - /* vertex creases weights */ - result = COIBufferCreateFromMemory(max((size_t)4,mesh->vertex_crease_weights.size()*sizeof(float)), - COI_BUFFER_NORMAL, - 0, - mesh->vertex_crease_weights.size() ? &mesh->vertex_crease_weights.front() : dummy_buffer, - 1, - &process, - &buffers.vertex_crease_weights); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIBufferCreate failed: " + std::string(COIResultGetName(result))); - - /* holes */ - result = COIBufferCreateFromMemory(max((size_t)4,mesh->holes.size()*sizeof(int)), - COI_BUFFER_NORMAL, - 0, - mesh->holes.size() ? &mesh->holes.front() : dummy_buffer, - 1, - &process, - &buffers.holes); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIBufferCreate failed: " + std::string(COIResultGetName(result))); - - - CreateSubdivMeshData parms; - parms.numPositions = mesh->positions.size(); - parms.numNormals = mesh->normals.size(); - parms.numTextureCoords = mesh->texcoords.size(); - parms.numPositionIndices = mesh->position_indices.size(); - parms.numNormalIndices = mesh->normal_indices.size(); - parms.numTexCoordIndices = mesh->texcoord_indices.size(); - parms.numVerticesPerFace = mesh->verticesPerFace.size(); - parms.numHoles = mesh->holes.size(); - parms.numEdgeCreases = mesh->edge_creases.size(); - parms.numEdgeCreaseWeights = mesh->edge_crease_weights.size(); - parms.numVertexCreases = mesh->vertex_creases.size(); - parms.numVertexCreaseWeights = mesh->vertex_crease_weights.size(); - parms.materialID = mesh->materialID; - - - COI_ACCESS_FLAGS flags[8] = { COI_SINK_READ, COI_SINK_READ, COI_SINK_READ, COI_SINK_READ, COI_SINK_READ, COI_SINK_READ, COI_SINK_READ, COI_SINK_READ}; - - COIEVENT event; - memset(&event,0,sizeof(event)); - - /* run set scene runfunction */ - result = COIPipelineRunFunction (pipeline, runCreateSubdivMesh, 8, &buffers.positions, flags, 0, nullptr, &parms, sizeof(parms), nullptr, 0, &event); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIPipelineRunFunction failed: "+std::string(COIResultGetName(result))); - - result = COIEventWait(1,&event,-1,1,nullptr,nullptr); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIEventWait failed: "+std::string(COIResultGetName(result))); - - /* destroy buffers again */ - result = COIBufferDestroy(buffers.positions); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIPipelineRunFunction failed: "+std::string(COIResultGetName(result))); - result = COIBufferDestroy(buffers.position_indices); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIPipelineRunFunction failed: "+std::string(COIResultGetName(result))); - result = COIBufferDestroy(buffers.vertices_per_face); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIPipelineRunFunction failed: "+std::string(COIResultGetName(result))); - } - - - /* set scene to use */ - void set_scene (OBJScene* scene) - { - COIRESULT result; - COIBUFFER buffers[5]; - COI_ACCESS_FLAGS flags[5] = { COI_SINK_READ, COI_SINK_READ, COI_SINK_READ, COI_SINK_READ, COI_SINK_READ }; - - /* send materials */ - size_t materialBytes = max(size_t(16),scene->materials.size()*sizeof(Material)); - void* materialPtr = scene->materials.size() ? &scene->materials.front() : nullptr; - result = COIBufferCreate(materialBytes,COI_BUFFER_NORMAL,0,materialPtr,1,&process,&buffers[0]); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIBufferCreate failed: " + std::string(COIResultGetName(result))); - - /* send ambient lights */ - COIBUFFER ambientLightsBuffer; - size_t ambientLightsBytes = max(size_t(16),scene->ambientLights.size()*sizeof(AmbientLight)); - void* ambientLightsPtr = scene->ambientLights.size() ? &scene->ambientLights.front() : nullptr; - result = COIBufferCreate(ambientLightsBytes,COI_BUFFER_NORMAL,0,ambientLightsPtr,1,&process,&buffers[1]); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIBufferCreate failed: " + std::string(COIResultGetName(result))); - - /* send point lights */ - COIBUFFER pointLightsBuffer; - size_t pointLightsBytes = max(size_t(16),scene->pointLights.size()*sizeof(PointLight)); - void* pointLightsPtr = scene->pointLights.size() ? &scene->pointLights.front() : nullptr; - result = COIBufferCreate(pointLightsBytes,COI_BUFFER_NORMAL,0,pointLightsPtr,1,&process,&buffers[2]); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIBufferCreate failed: " + std::string(COIResultGetName(result))); - - /* send directional lights */ - COIBUFFER directionalLightsBuffer; - size_t directionalLightsBytes = max(size_t(16),scene->directionalLights.size()*sizeof(DirectionalLight)); - void* directionalLightsPtr = scene->directionalLights.size() ? &scene->directionalLights.front() : nullptr; - result = COIBufferCreate(directionalLightsBytes,COI_BUFFER_NORMAL,0,directionalLightsPtr,1,&process,&buffers[3]); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIBufferCreate failed: " + std::string(COIResultGetName(result))); - - /* send distant lights */ - COIBUFFER distantLightsBuffer; - size_t distantLightsBytes = max(size_t(16),scene->distantLights.size()*sizeof(DistantLight)); - void* distantLightsPtr = scene->distantLights.size() ? &scene->distantLights.front() : nullptr; - result = COIBufferCreate(distantLightsBytes,COI_BUFFER_NORMAL,0,distantLightsPtr,1,&process,&buffers[4]); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIBufferCreate failed: " + std::string(COIResultGetName(result))); - - CreateSceneData parms; - parms.numMaterials = scene->materials.size(); - parms.numMeshes = scene->meshes.size(); - parms.numHairSets = scene->hairsets.size(); - parms.numAmbientLights = scene->ambientLights.size(); - parms.numPointLights = scene->pointLights.size(); - parms.numDirectionalLights = scene->directionalLights.size(); - parms.numDistantLights = scene->distantLights.size(); - parms.numSubdivMeshes = scene->subdiv.size(); - - COIEVENT event; - memset(&event,0,sizeof(event)); - - /* run set scene runfunction */ - result = COIPipelineRunFunction (pipeline, runCreateScene, 5, buffers, flags, 0, nullptr, &parms, sizeof(parms), nullptr, 0, &event); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIPipelineRunFunction failed: "+std::string(COIResultGetName(result))); - - result = COIEventWait(1,&event,-1,1,nullptr,nullptr); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIEventWait failed: "+std::string(COIResultGetName(result))); - - /* destroy buffers again */ - // result = COIBufferDestroy(materialBuffer); - // if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIPipelineRunFunction failed: "+std::string(COIResultGetName(result))); - - /* send all meshes */ - for (size_t i=0; imeshes.size(); i++) - send_mesh(scene->meshes[i]); - - /* send all hairsets */ - for (size_t i=0; ihairsets.size(); i++) - send_hairset(scene->hairsets[i]); - - /* send all subdiv meshes */ - for (size_t i=0; isubdiv.size(); i++) - send_subdiv_mesh(scene->subdiv[i]); - - } - - void resize(int width, int height) - { - COIRESULT result; - if (g_width == width && g_height == height) - return; - - /* destroy old framebuffer */ - if (g_width != -1 && g_height != -1) { - result = COIBufferDestroy(frameBuffer); - if (result != COI_SUCCESS) - THROW_RUNTIME_ERROR("COIBufferDestroy failed: "+std::string(COIResultGetName(result))); - } - - /* create new framebuffer */ - g_width = width; - g_height = height; - result = COIBufferCreate (width*height*4+64, COI_BUFFER_NORMAL, COI_OPTIMIZE_SOURCE_READ|COI_OPTIMIZE_SINK_WRITE|COI_OPTIMIZE_HUGE_PAGE_SIZE, nullptr, 1, &process, &frameBuffer); - - if (result != COI_SUCCESS) - THROW_RUNTIME_ERROR("COIBufferCreate failed: " + std::string(COIResultGetName(result))); - } - - void set_scene_keyframes(OBJScene** in, size_t numKeyFrames) - { - NOT_IMPLEMENTED; - } - - bool pick(const float x, const float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p, Vec3fa& hitPos) - { - PickDataSend send; - send.x = x; send.y = y; - send.vx = vx; send.vy = vy; send.vz = vz; send.p = p; - - COIEVENT event; - memset(&event,0,sizeof(event)); - - PickDataReceive receive; - COIRESULT result = COIPipelineRunFunction (pipeline, runPick, 0, nullptr, nullptr, 0, nullptr, &send, sizeof(send), &receive, sizeof(receive), &event); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIPipelineRunFunction failed: "+std::string(COIResultGetName(result))); - - result = COIEventWait(1,&event,-1,1,nullptr,nullptr); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIEventWait failed: "+std::string(COIResultGetName(result))); - - hitPos = receive.pos; - return receive.hit; - } - - void render(const float time, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p) - { - /* set parameters for rendering */ - RenderData parms; - parms.time = time; - parms.vx = vx; - parms.vy = vy; - parms.vz = vz; - parms.p = p; - parms.width = g_width; - parms.height = g_height; - COI_ACCESS_FLAGS flags = COI_SINK_WRITE_ENTIRE; - - COIEVENT event; - memset(&event,0,sizeof(event)); - - /* run init runfunction */ - COIRESULT result = COIPipelineRunFunction (pipeline, runRender, 1, &frameBuffer, &flags, 0, nullptr, &parms, sizeof(parms), nullptr, 0, &event); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIPipelineRunFunction failed: "+std::string(COIResultGetName(result))); - - result = COIEventWait(1,&event,-1,1,nullptr,nullptr); - if (result != COI_SUCCESS) THROW_RUNTIME_ERROR("COIEventWait failed: "+std::string(COIResultGetName(result))); - } - - int* map () - { - /* map the framebuffer */ - void* ptr = nullptr; - COIRESULT result = COIBufferMap(frameBuffer,0,g_width*g_height*4,COI_MAP_READ_ONLY,0,nullptr,nullptr,&mapInst,&ptr); - if (result != COI_SUCCESS) - THROW_RUNTIME_ERROR("COIBufferMap failed: "+std::string(COIResultGetName(result))); - - return (int*) ptr; - } - - void unmap () - { - COIRESULT result = COIBufferUnmap(mapInst,0,nullptr,nullptr); - if (result != COI_SUCCESS) - THROW_RUNTIME_ERROR("COIBufferUnmap failed: "+std::string(COIResultGetName(result))); - } - - void cleanup() - { - /* run cleanup runfunction */ - COIRESULT result = COIPipelineRunFunction (pipeline, runCleanup, 0, nullptr, nullptr, 0, nullptr, nullptr, 0, nullptr, 0, nullptr); - - if (result != COI_SUCCESS) - THROW_RUNTIME_ERROR("Error launching runfunction: "+std::string(COIResultGetName(result))); - - /* destroy Xeon Phi process */ - result = COIProcessDestroy(process,-1,0,nullptr,nullptr); - if (result != COI_SUCCESS) - THROW_RUNTIME_ERROR(std::string("Destroying COI process failed: ") + std::string(COIResultGetName(result))); - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/CMakeLists.txt deleted file mode 100644 index f8f83cccd741..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/CMakeLists.txt +++ /dev/null @@ -1,87 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2015 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -IF (__XEON__) - -IF (TASKING_INTERNAL) - ADD_DEFINITIONS(-DTASKING_TBB_INTERNAL) -ELSE() - ADD_DEFINITIONS(-DTASKING_TBB) -ENDIF() - -IF (WIN32) -# FindGLUT.cmake is broken for Windows in CMake until 3.0: does not support PATH - FIND_PATH(GLUT_INCLUDE_DIR NAMES GL/glut.h PATHS ../freeglut/include) - # detect and select Win32 or x64 - IF (CMAKE_SIZEOF_VOID_P EQUAL 8) - SET(ARCH x64) - ELSE() - SET(ARCH Win32) - ENDIF() - FIND_LIBRARY(GLUT_glut_LIBRARY freeglut ../freeglut/${ARCH}) - SET(GLUT_LIBRARIES ${GLUT_glut_LIBRARY}) - MARK_AS_ADVANCED( - GLUT_INCLUDE_DIR - GLUT_glut_LIBRARY - ) -ELSE (WIN32) - FIND_PACKAGE(GLUT REQUIRED) -ENDIF (WIN32) - -FIND_PACKAGE(OpenGL REQUIRED) - -INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR} ${GLUT_INCLUDE_DIR}) -ADD_LIBRARY(tutorial STATIC - glutdisplay.cpp - xml_parser.cpp - xml_loader.cpp - obj_loader.cpp - hair_loader.cpp - texture_loader.cpp - cy_hair_loader.cpp - scene.cpp) -TARGET_LINK_LIBRARIES(tutorial sys lexers ${OPENGL_LIBRARIES} -${GLUT_LIBRARIES} ${PTEX_LIBRARIES}) -SET_PROPERTY(TARGET tutorial PROPERTY FOLDER tutorials/common) - -IF (WIN32) - GET_FILENAME_COMPONENT(GLUT_DIR ${GLUT_glut_LIBRARY} PATH) - ADD_CUSTOM_COMMAND(TARGET tutorial POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${GLUT_DIR}/freeglut.dll $ - COMMENT "Copy FreeGlut DLL" VERBATIM - ) - INSTALL(PROGRAMS ${GLUT_DIR}/freeglut.dll DESTINATION bin COMPONENT examples) -ENDIF (WIN32) - -ADD_LIBRARY(tutorial_device STATIC tutorial_device.cpp) -TARGET_LINK_LIBRARIES(tutorial_device tutorial) -SET_PROPERTY(TARGET tutorial_device PROPERTY FOLDER tutorials/common) - -IF (ENABLE_ISPC_SUPPORT) - ADD_ISPC_LIBRARY(tutorial_device_ispc STATIC tutorial_device.ispc) - TARGET_LINK_LIBRARIES(tutorial_device_ispc tutorial) - SET_TARGET_PROPERTIES(tutorial_device_ispc PROPERTIES LINKER_LANGUAGE C) - SET_PROPERTY(TARGET tutorial_device_ispc PROPERTY FOLDER tutorials/common) -ENDIF() - -ELSE (__XEON__) - - INCLUDE (icc_xeonphi) - ADD_ISPC_LIBRARY(tutorial_xeonphi_device_ispc STATIC tutorial_device.ispc) - SET_TARGET_PROPERTIES(tutorial_xeonphi_device_ispc PROPERTIES LINKER_LANGUAGE C) - SET_PROPERTY(TARGET tutorial_xeonphi_device_ispc PROPERTY FOLDER tutorials/common) - -ENDIF (__XEON__) diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/camera.h b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/camera.h deleted file mode 100644 index 8540929a1918..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/camera.h +++ /dev/null @@ -1,111 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../../../common/sys/platform.h" -#include "../../../common/sys/ref.h" -#include "../../../common/math/math.h" -#include "../../../common/math/vec3.h" -#include "../../../common/math/affinespace.h" - -namespace embree -{ - /* camera settings */ - struct Camera - { - public: - size_t frames; - Camera () - : from(0.0001f,0.0001f,-3.0f), to(0,0,0), up(0,1,0), fov(90), anim(false),frames(0) {} - - Camera (Vec3fa& from, Vec3fa& to, Vec3fa& up, float fov) - : from(from), to(to), up(up), fov(fov), anim(false),frames(0) {} - - AffineSpace3fa camera2world () { return AffineSpace3fa::lookat(from, to, up); } - AffineSpace3fa world2camera () { return rcp(AffineSpace3fa::lookat(from, to, up)); } - Vec3fa world2camera(const Vec3fa& p) { return xfmPoint(world2camera(),p); } - Vec3fa camera2world(const Vec3fa& p) { return xfmPoint(camera2world(),p); } - - AffineSpace3fa pixel2world (size_t width, size_t height) - { - - if (anim) - { - const float step = 5.0f; - //if (frames % 2) - rotateOrbit(-0.005f*step,0.005f*0); - frames++; - } - - const float fovScale = 1.0f/tanf(deg2rad(0.5f*fov)); - const AffineSpace3fa local2world = AffineSpace3fa::lookat(from, to, up); - return AffineSpace3fa(local2world.l.vx, - -local2world.l.vy, - -0.5f*width*local2world.l.vx + 0.5f*height*local2world.l.vy + 0.5f*height*fovScale*local2world.l.vz, - local2world.p); - } - - void move (float dx, float dy, float dz) - { - AffineSpace3fa xfm = camera2world(); - Vec3fa ds = xfmVector(xfm,Vec3fa(dx,dy,dz)); - from += ds; - to += ds; - } - - void rotate (float dtheta, float dphi) - { - Vec3fa view = xfmPoint(world2camera(),to); - float theta = atan2f(view.x, view.z); theta += dtheta; - float phi = asinf (view.y); phi += dphi; - float x = cosf(phi)*sinf(theta); - float y = sinf(phi); - float z = cosf(phi)*cosf(theta); - to = xfmPoint(camera2world(),length(view)*Vec3fa(x,y,z)); - } - - void rotateOrbit (float dtheta, float dphi) - { - Vec3fa view = normalize(xfmVector(world2camera(),to - from)); - float theta = atan2f(view.x, view.z); theta += dtheta; - float phi = asinf (view.y); phi += dphi; - assert(std::isfinite(theta)); - assert(std::isfinite(phi)); - float x = cosf(phi)*sinf(theta); - float y = sinf(phi); - float z = cosf(phi)*cosf(theta); - Vec3fa view1 = xfmVector(camera2world(),Vec3fa(x,y,z)); - from = to - length(to - from) * view1; - } - - void dolly (float ds) - { - float dollySpeed = 0.01f; - float k = powf((1.0f-dollySpeed), ds); - from += length(to-from) * (1-k) * normalize(to-from); - } - - void enableAnimMode() { anim = true; } - - public: - Vec3fa from; //!< position of camera - Vec3fa to; //!< look at point - Vec3fa up; //!< up vector - float fov; //!< field of view - bool anim; - }; -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/cy_hair_loader.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/cy_hair_loader.cpp deleted file mode 100644 index 7be9d9912b45..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/cy_hair_loader.cpp +++ /dev/null @@ -1,191 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "cy_hair_loader.h" - -#include -#include - -namespace embree -{ - // ------------------------------------------- - // -- Based on the format by Cem Yuksel -- - // -- www.cemyuksel.com/research/hairmodels -- - // ------------------------------------------- - -#define CY_HAIR_FILE_SEGMENTS_BIT 1 -#define CY_HAIR_FILE_POINTS_BIT 2 -#define CY_HAIR_FILE_THICKNESS_BIT 4 -#define CY_HAIR_FILE_TRANSPARENCY_BIT 8 -#define CY_HAIR_FILE_COLORS_BIT 16 -#define CY_HAIR_FILE_INFO_SIZE 88 - - struct cyHeader - { - char signature[4]; ///< This should be "HAIR" - unsigned int numStrands; ///< number of hair strands - unsigned int numPoints; ///< total number of points of all strands - unsigned int bitarrays; ///< bit array of data in the file - unsigned int defaultSegments; ///< default number of segments of each strand - float defaultThickness; ///< default thickness of hair strands - float defaultTransparency; ///< default transparency of hair strands - float defaultColor[3]; ///< default color of hair strands - char info[CY_HAIR_FILE_INFO_SIZE]; ///< information about the file - }; - - class cyHairFile - { - public: - cyHairFile() : segments(nullptr), points(nullptr), thickness(nullptr), transparency(nullptr), colors(nullptr) {init(); } - ~cyHairFile() { - if ( segments ) delete [] segments; - if ( points ) delete [] points; - if ( colors ) delete [] colors; - if ( thickness ) delete [] thickness; - if ( transparency ) delete [] transparency; - } - - - void init() - { - header.signature[0] = 'H'; - header.signature[1] = 'A'; - header.signature[2] = 'I'; - header.signature[3] = 'R'; - header.numStrands = 0; - header.numPoints = 0; - header.bitarrays = 0; - header.defaultSegments = 0; - header.defaultThickness = 1.0f; - header.defaultTransparency = 0.0f; - header.defaultColor[0] = 1.0f; - header.defaultColor[1] = 1.0f; - header.defaultColor[2] = 1.0f; - memset( header.info, '\0', CY_HAIR_FILE_INFO_SIZE ); - } - - int load( const char *filename ) - { - init(); - - FILE *file; - file = fopen( filename, "rb" ); - if ( file == nullptr ) - THROW_RUNTIME_ERROR("can't open file"); - - size_t h = fread( &header, sizeof(cyHeader), 1, file ); - - if ( h < 1 ) - THROW_RUNTIME_ERROR("can't read header"); - - if ( strncmp( header.signature, "HAIR", 4) != 0 ) - THROW_RUNTIME_ERROR("wrong signature"); - - if ( header.bitarrays & CY_HAIR_FILE_SEGMENTS_BIT ) { - segments = new unsigned short[ header.numStrands ]; - size_t r = fread( segments, sizeof(unsigned short), header.numStrands, file ); - if ( r < header.numStrands ) - THROW_RUNTIME_ERROR("error reading segments"); - } - - if ( header.bitarrays & CY_HAIR_FILE_POINTS_BIT ) { - points = new float[ header.numPoints*3 ]; - size_t r = fread( points, sizeof(float), header.numPoints*3, file ); - if ( r < header.numPoints*3 ) - THROW_RUNTIME_ERROR("error reading points"); - } - - if ( header.bitarrays & CY_HAIR_FILE_THICKNESS_BIT ) { - thickness = new float[ header.numPoints ]; - size_t r = fread( thickness, sizeof(float), header.numPoints, file ); - if ( r < header.numPoints ) - THROW_RUNTIME_ERROR("error reading thickness values"); - } - - if ( header.bitarrays & CY_HAIR_FILE_TRANSPARENCY_BIT ) { - transparency = new float[ header.numPoints ]; - size_t r = fread( transparency, sizeof(float), header.numPoints, file ); - if ( r < header.numPoints ) - THROW_RUNTIME_ERROR("error reading transparency values"); - } - - if ( header.bitarrays & CY_HAIR_FILE_COLORS_BIT ) { - colors = new float[ header.numPoints*3 ]; - size_t r = fread( colors, sizeof(float), header.numPoints*3, file ); - if ( r < header.numPoints*3 ) - THROW_RUNTIME_ERROR("error reading color values"); - } - - fclose( file ); - - return header.numStrands; - } - - - cyHeader header; - unsigned short *segments; - float *points; - float *thickness; - float *transparency; - float *colors; - }; - - Ref loadCYHair(const FileName& fileName) - { - cyHairFile cyFile; - int numHairs = cyFile.load(fileName.c_str()); - - Material objmtl; new (&objmtl) OBJMaterial; - Ref material = new SceneGraph::MaterialNode(objmtl); - Ref hairset = new SceneGraph::HairSetNode(material); - - for (size_t i=0;iv.push_back(v); - } - - ssize_t index = 0; - for (ssize_t i=0;ihairs.push_back(SceneGraph::HairSetNode::Hair(index + j,i)); - } - index += numSegments+1; - } - else - { - ssize_t numSegments = cyFile.header.defaultSegments; - for (ssize_t j=0; jhairs.push_back(SceneGraph::HairSetNode::Hair(index + j,i)); - } - index += numSegments+1; - - } - } - - return hairset.cast(); - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/cy_hair_loader.h b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/cy_hair_loader.h deleted file mode 100644 index 208675b4b56b..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/cy_hair_loader.h +++ /dev/null @@ -1,25 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "obj_loader.h" -#include "scenegraph.h" - -namespace embree -{ - Ref loadCYHair(const FileName& fileName); -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/glutdisplay.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/glutdisplay.cpp deleted file mode 100644 index be66c8bfce8e..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/glutdisplay.cpp +++ /dev/null @@ -1,316 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "glutdisplay.h" -#include "../../../common/sys/filename.h" -#include "../../../common/sys/sysinfo.h" -#include "../../../common/lexers/streamfilters.h" -#include "../../../common/lexers/parsestream.h" -#include "../transport/transport_host.h" - -#include -#include - -/* include GLUT for display */ -#if defined(__MACOSX__) -# include -# include -#elif defined(__WIN32__) -# include -# include -# include -#else -# include -# include -#endif - -extern "C" float g_debug = 0.0f; - -namespace embree -{ - static const double g_time0 = getSeconds(); - - /* camera */ - Camera g_camera; - - /* output settings */ - static size_t g_width = 512; - static size_t g_height = 512; - static bool g_display = true; - - /* fullscreen settings */ - static bool g_fullscreen = false; - static size_t g_window_width = 512; - static size_t g_window_height = 512; - - /* ID of created window */ - static int g_window = 0; - - /*************************************************************************************************/ - /* Keyboard control */ - /*************************************************************************************************/ - - typedef void (* KeyBinding)(unsigned char key, int x, int y); - - static float g_speed = 1.0f; - static std::map keyBindings; - - void mapKeyToFunction(unsigned char key, KeyBinding binding) - { - keyBindings[key] = binding; - } - - void keyboardFunc(unsigned char key, int x, int y) - { - - if (keyBindings.find(key) != keyBindings.end()) { keyBindings[key](key, x, y); return; } - - key_pressed(key); - - switch (key) - { - case 'f' : - if (g_fullscreen) { - g_fullscreen = false; - glutReshapeWindow(g_window_width,g_window_height); - } else { - g_fullscreen = true; - g_window_width = g_width; - g_window_height = g_height; - glutFullScreen(); - } - break; - case 'c' : { - std::cout.precision(10); - std::cout << "-vp " << g_camera.from.x << " " << g_camera.from.y << " " << g_camera.from.z << " " << std::endl - << "-vi " << g_camera.to.x << " " << g_camera.to.y << " " << g_camera.to.z << " " << std::endl - << "-vd " << g_camera.to.x-g_camera.from.x << " " << g_camera.to.y-g_camera.from.y << " " << g_camera.to.z-g_camera.from.z << " " << std::endl - << "-vu " << g_camera.up.x << " " << g_camera.up.y << " " << g_camera.up.z << " " << std::endl - << "-fov " << g_camera.fov << std::endl; - break; - } - //case 'a' : g_camera.rotate(-0.02f,0.0f); break; - //case 'd' : g_camera.rotate(+0.02f,0.0f); break; - //case 'w' : g_camera.move(0.0f,0.0f,+g_speed); break; - //case 's' : g_camera.move(0.0f,0.0f,-g_speed); break; - //case ' ' : g_display = !g_display; break; - - case '+' : g_debug=clamp(g_debug+0.01f); PRINT(g_debug); break; - case '-' : g_debug=clamp(g_debug-0.01f); PRINT(g_debug); break; - - case '\033': case 'q': case 'Q': - cleanup(); - glutDestroyWindow(g_window); -#if defined(__MACOSX__) - exit(1); -#endif - break; - } - } - - void specialFunc(int key, int, int) - { - key_pressed(key); - - switch (key) { - case GLUT_KEY_LEFT : g_camera.rotate(-0.02f,0.0f); break; - case GLUT_KEY_RIGHT : g_camera.rotate(+0.02f,0.0f); break; - case GLUT_KEY_UP : g_camera.move(0.0f,0.0f,+g_speed); break; - case GLUT_KEY_DOWN : g_camera.move(0.0f,0.0f,-g_speed); break; - case GLUT_KEY_PAGE_UP : g_speed *= 1.2f; break; - case GLUT_KEY_PAGE_DOWN : g_speed /= 1.2f; break; - } - } - - /*************************************************************************************************/ - /* Mouse control */ - /*************************************************************************************************/ - - static int mouseMode = 0; - static int clickX = 0, clickY = 0; - static bool flip14 = false; - - void clickFunc(int button, int state, int x, int y) - { - if (state == GLUT_UP) - { - mouseMode = 0; - if (button == GLUT_LEFT_BUTTON && glutGetModifiers() == GLUT_ACTIVE_SHIFT) - { - AffineSpace3fa pixel2world = g_camera.pixel2world(g_width,g_height); - Vec3fa p; bool hit = pick(x,y, pixel2world.l.vx, pixel2world.l.vy, pixel2world.l.vz, pixel2world.p, p); - - if (hit) { - Vec3fa delta = p - g_camera.to; - Vec3fa right = normalize(pixel2world.l.vx); - Vec3fa up = normalize(pixel2world.l.vy); - g_camera.to = p; - g_camera.from += dot(delta,right)*right + dot(delta,up)*up; - } - } - else if (button == GLUT_LEFT_BUTTON && glutGetModifiers() == (GLUT_ACTIVE_CTRL | GLUT_ACTIVE_SHIFT)) - { - AffineSpace3fa pixel2world = g_camera.pixel2world(g_width,g_height); - Vec3fa p; bool hit = pick(x,y, pixel2world.l.vx, pixel2world.l.vy, pixel2world.l.vz, pixel2world.p, p); - if (hit) g_camera.to = p; - } - - } else { - clickX = x; clickY = y; - int modifiers = glutGetModifiers(); - if (button == GLUT_LEFT_BUTTON && modifiers == GLUT_ACTIVE_SHIFT) mouseMode = 1; - else if (button == GLUT_MIDDLE_BUTTON) mouseMode = 2; - else if (button == GLUT_RIGHT_BUTTON ) mouseMode = 3; - else if (button == GLUT_LEFT_BUTTON && modifiers == GLUT_ACTIVE_CTRL ) mouseMode = 3; - else if (button == GLUT_LEFT_BUTTON ) mouseMode = 4; - - if (flip14) { - if (mouseMode == 4) mouseMode = 1; - else if (mouseMode == 1) mouseMode = 4; - } - } - } - - void motionFunc(int x, int y) - { - float dClickX = float(clickX - x), dClickY = float(clickY - y); - clickX = x; clickY = y; - - switch (mouseMode) { - case 1: g_camera.rotateOrbit(-0.005f*dClickX,0.005f*dClickY); break; - case 2: break; - case 3: g_camera.dolly(-dClickY); break; - case 4: g_camera.rotate(-0.005f*dClickX,0.005f*dClickY); break; - } - } - - /*************************************************************************************************/ - /* Window control */ - /*************************************************************************************************/ - - void displayFunc(void) - { - AffineSpace3fa pixel2world = g_camera.pixel2world(g_width,g_height); - - /* render image using ISPC */ - double t0 = getSeconds(); - render(g_time0-t0, - pixel2world.l.vx, - -pixel2world.l.vy, - pixel2world.l.vz+g_height*pixel2world.l.vy, - pixel2world.p); - - double dt0 = getSeconds()-t0; - - if (g_display) - { - /* draw pixels to screen */ - int* pixels = map(); - glDrawPixels(g_width,g_height,GL_RGBA,GL_UNSIGNED_BYTE,pixels); - - if (g_fullscreen) - { - glMatrixMode( GL_PROJECTION ); - glPushMatrix(); - glLoadIdentity(); - gluOrtho2D( 0, g_width, 0, g_height ); - glMatrixMode( GL_MODELVIEW ); - glPushMatrix(); - glLoadIdentity(); - - /* print frame rate */ - std::ostringstream stream; - stream.setf(std::ios::fixed, std::ios::floatfield); - stream.precision(2); - stream << 1.0f/dt0 << " fps"; - std::string str = stream.str(); - - glRasterPos2i( g_width-str.size()*12, g_height - 24); - for ( int i = 0; i < str.size(); ++i ) - glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, str[i]); - - glRasterPos2i( 0, 0 ); - glPopMatrix(); - glMatrixMode( GL_PROJECTION ); - glPopMatrix(); - glMatrixMode( GL_MODELVIEW ); - } - - glutSwapBuffers(); - unmap(); - } - double dt1 = getSeconds()-t0; - - /* print frame rate */ - std::ostringstream stream; - stream.setf(std::ios::fixed, std::ios::floatfield); - stream.precision(2); - stream << "render: "; - stream << 1.0f/dt0 << " fps, "; - stream << dt0*1000.0f << " ms, "; - stream << "display: "; - stream << 1.0f/dt1 << " fps, "; - stream << dt1*1000.0f << " ms, "; - stream << g_width << "x" << g_height << " pixels"; - std::cout << stream.str() << std::endl; - } - - void reshapeFunc(int width, int height) - { - resize(width,height); - glViewport(0, 0, width, height); - g_width = width; g_height = height; - } - - void idleFunc() - { - glutPostRedisplay(); - } - - void enterWindowRunLoop(bool anim) - { - if (anim) - g_camera.enableAnimMode(); - - glutMainLoop(); - } - - /* initialize GLUT */ - void initWindowState(int& argc, char** argv, const std::string name, const size_t width, const size_t height, const bool fullscreen, const bool mouseMode) - { - g_width = width; - g_height = height; - resize(g_width,g_height); - - g_fullscreen = fullscreen; - flip14 = mouseMode; - glutInit(&argc, argv); - glutInitWindowSize((GLsizei)g_width, (GLsizei)g_height); - glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); - glutInitWindowPosition(0, 0); - g_window = glutCreateWindow(name.c_str()); - if (g_fullscreen) glutFullScreen(); - glutDisplayFunc(displayFunc); - glutIdleFunc(idleFunc); - glutKeyboardFunc(keyboardFunc); - glutSpecialFunc(specialFunc); - glutMouseFunc(clickFunc); - glutMotionFunc(motionFunc); - glutReshapeFunc(reshapeFunc); - } - -} - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/glutdisplay.h b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/glutdisplay.h deleted file mode 100644 index bdf8070bf95b..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/glutdisplay.h +++ /dev/null @@ -1,38 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../../../common/sys/platform.h" -#include "../../../common/sys/ref.h" -#include "camera.h" - -namespace embree -{ - - /* camera */ - extern Camera g_camera; - - /* enter the GLUT main run loop */ - void enterWindowRunLoop(const bool anim = false); - - /* initialize GLUT */ - void initWindowState(int& argc, char** argv, const std::string name, const size_t width, const size_t height, const bool fullscreen, const bool mouseMode = true); - - /* set a callback for a key */ - void mapKeyToFunction(unsigned char key, void (*func)(unsigned char key, int x, int y)); - -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/hair_loader.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/hair_loader.cpp deleted file mode 100644 index ceae7c41718e..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/hair_loader.cpp +++ /dev/null @@ -1,131 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "hair_loader.h" - -#define CONVERT_TO_BINARY 0 - -namespace embree -{ - const int hair_bin_magick = 0x12EF3F90; - - int loadHairASCII(const FileName& fileName, Ref hairset) - { - /* open hair file */ - FILE* f = fopen(fileName.c_str(),"r"); - if (!f) THROW_RUNTIME_ERROR("could not open " + fileName.str()); - - char line[10000]; - fgets(line,10000,f); - int numCurves = 0; - - while (fgets(line,10000,f) && !feof(f)) - { - /* comment */ - if (line[0] == '#') - continue; - - if (!strncmp(line,"Curve:",strlen("Curve:"))) - { - char name[1000]; - unsigned int tracks, points; - sscanf(line,"Curve: %s %d Tracks %d Points",name,&tracks,&points); - - /* skip Tracks line */ - fgets(line,10000,f); - - const int vertex_start_id = hairset->v.size(); - - unsigned int id = 0; - for (int i=0; iv.push_back(v); - } - - /* add indices to hair starts */ - for (int i=0; ihairs.push_back(SceneGraph::HairSetNode::Hair(vertex_start_id + i,numCurves)); - - if (id != points-1) - THROW_RUNTIME_ERROR("hair parsing error"); - - numCurves++; - } - } - fclose(f); - return numCurves; - } - - int loadHairBin(const FileName& fileName, Ref hairset) - { - FILE* fin = fopen(fileName.c_str(),"rb"); - if (!fin) THROW_RUNTIME_ERROR("could not open " + fileName.str()); - int magick; fread(&magick,sizeof(int),1,fin); - if (magick != hair_bin_magick) - THROW_RUNTIME_ERROR("invalid binary hair file " + fileName.str()); - int numHairs; fread(&numHairs,sizeof(int),1,fin); - int numPoints; fread(&numPoints,sizeof(int),1,fin); - int numSegments; fread(&numSegments,sizeof(int),1,fin); - hairset->v.resize(numPoints); - hairset->hairs.resize(numSegments); - if (numPoints) fread(&hairset->v[0],sizeof(Vec3fa),numPoints,fin); - if (numSegments) fread(&hairset->hairs[0],sizeof(OBJScene::Hair),numSegments,fin); - fclose(fin); - return numHairs; - } - - Ref loadHair(const FileName& fileName) - { - /* add new hair set to scene */ - Material objmtl; new (&objmtl) OBJMaterial; - Ref material = new SceneGraph::MaterialNode(objmtl); - Ref hairset = new SceneGraph::HairSetNode(material); - - int numHairs = 0; - if (fileName.ext() == "txt") - numHairs = loadHairASCII(fileName,hairset); - else - numHairs = loadHairBin(fileName,hairset); - -#if CONVERT_TO_BINARY - int numPoints = hairset->v.size(); - int numSegments = hairset->hairs.size(); - FILE* fout = fopen(fileName.setExt(".bin").c_str(),"wb"); - if (!fout) THROW_RUNTIME_ERROR("could not open " + fileName.str()); - fwrite(&hair_bin_magick,sizeof(int),1,fout); - fwrite(&numHairs,sizeof(int),1,fout); - fwrite(&numPoints,sizeof(int),1,fout); - fwrite(&numSegments,sizeof(int),1,fout); - if (numPoints) fwrite(&hairset->v[0],sizeof(Vec3fa),numPoints,fout); - if (numSegments) fwrite(&hairset->hairs[0],sizeof(SceneGraph::HairSet::Hair),numSegments,fout); - fclose(fout); -#endif - - return hairset.cast(); - } -} - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/hair_loader.h b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/hair_loader.h deleted file mode 100644 index 96ececd88368..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/hair_loader.h +++ /dev/null @@ -1,25 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "obj_loader.h" -#include "scenegraph.h" - -namespace embree -{ - Ref loadHair(const FileName& fileName); -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/obj_loader.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/obj_loader.cpp deleted file mode 100644 index 6ba534a638f7..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/obj_loader.cpp +++ /dev/null @@ -1,428 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "obj_loader.h" -#include "texture_loader.h" - -#include -#include -#include -#include -#include - -namespace embree -{ - /*! Three-index vertex, indexing start at 0, -1 means invalid vertex. */ - struct Vertex { - int v, vt, vn; - Vertex() {}; - Vertex(int v) : v(v), vt(v), vn(v) {}; - Vertex(int v, int vt, int vn) : v(v), vt(vt), vn(vn) {}; - }; - - struct Crease { - float w; - int a, b; - Crease() : w(0), a(-1), b(-1) {}; - Crease(float w, int a, int b) : w(w), a(a), b(b) {}; - }; - - static inline bool operator < ( const Vertex& a, const Vertex& b ) { - if (a.v != b.v) return a.v < b.v; - if (a.vn != b.vn) return a.vn < b.vn; - if (a.vt != b.vt) return a.vt < b.vt; - return false; - } - - /*! Fill space at the end of the token with 0s. */ - static inline const char* trimEnd(const char* token) { - size_t len = strlen(token); - if (len == 0) return token; - char* pe = (char*)(token + len - 1); - while ((*pe == ' ' || *pe == '\t' || *pe == '\r') && pe >= token) *pe-- = 0; - return token; - } - - /*! Determine if character is a separator. */ - static inline bool isSep(const char c) { - return (c == ' ') || (c == '\t'); - } - - /*! Parse separator. */ - static inline const char* parseSep(const char*& token) { - size_t sep = strspn(token, " \t"); - if (!sep) THROW_RUNTIME_ERROR("separator expected"); - return token+=sep; - } - - /*! Parse optional separator. */ - static inline const char* parseSepOpt(const char*& token) { - return token+=strspn(token, " \t"); - } - - /*! Read float from a string. */ - static inline float getFloat(const char*& token) { - token += strspn(token, " \t"); - float n = (float)atof(token); - token += strcspn(token, " \t\r"); - return n; - } - - /*! Read int from a string. */ - static inline int getInt(const char*& token) { - token += strspn(token, " \t"); - int n = (float)atoi(token); - token += strcspn(token, " \t\r"); - return n; - } - - /*! Read Vec2f from a string. */ - static inline Vec2f getVec2f(const char*& token) { - float x = getFloat(token); - float y = getFloat(token); - return Vec2f(x,y); - } - - /*! Read Vec3f from a string. */ - static inline Vec3f getVec3f(const char*& token) { - float x = getFloat(token); - float y = getFloat(token); - float z = getFloat(token); - return Vec3f(x,y,z); - } - - class OBJLoader - { - public: - - /*! Constructor. */ - OBJLoader(const FileName& fileName, const bool subdivMode); - - /*! output model */ - Ref group; - - private: - - /*! file to load */ - FileName path; - - /*! load only quads and ignore triangles */ - bool subdivMode; - - /*! Geometry buffer. */ - avector v; - avector vn; - std::vector vt; - std::vector ec; - - std::vector > curGroup; - - /*! Material handling. */ - Ref curMaterial; - std::map > material; - - private: - void loadMTL(const FileName& fileName); - int fix_v (int index); - int fix_vt(int index); - int fix_vn(int index); - void flushFaceGroup(); - Vertex getInt3(const char*& token); - uint32_t getVertex(std::map& vertexMap, Ref mesh, const Vertex& i); - }; - - OBJLoader::OBJLoader(const FileName &fileName, const bool subdivMode) - : path(fileName.path()), group(new SceneGraph::GroupNode), subdivMode(subdivMode) - { - /* open file */ - std::ifstream cin; - cin.open(fileName.c_str()); - if (!cin.is_open()) { - THROW_RUNTIME_ERROR("cannot open " + fileName.str()); - return; - } - - /* generate default material */ - Material objmtl; new (&objmtl) OBJMaterial; - Ref defaultMaterial = new SceneGraph::MaterialNode(objmtl); - curMaterial = defaultMaterial; - - char line[10000]; - memset(line, 0, sizeof(line)); - - while (cin.peek() != -1) - { - /* load next multiline */ - char* pline = line; - while (true) { - cin.getline(pline, sizeof(line) - (pline - line) - 16, '\n'); - ssize_t last = strlen(pline) - 1; - if (last < 0 || pline[last] != '\\') break; - pline += last; - *pline++ = ' '; - } - - const char* token = trimEnd(line + strspn(line, " \t")); - if (token[0] == 0) continue; - - /*! parse position */ - if (token[0] == 'v' && isSep(token[1])) { - v.push_back(getVec3f(token += 2)); continue; - } - - /* parse normal */ - if (token[0] == 'v' && token[1] == 'n' && isSep(token[2])) { - vn.push_back(getVec3f(token += 3)); - continue; - } - - /* parse texcoord */ - if (token[0] == 'v' && token[1] == 't' && isSep(token[2])) { vt.push_back(getVec2f(token += 3)); continue; } - - /*! parse face */ - if (token[0] == 'f' && isSep(token[1])) - { - parseSep(token += 1); - - std::vector face; - while (token[0]) { - Vertex vtx = getInt3(token); - face.push_back(vtx); - parseSepOpt(token); - } - curGroup.push_back(face); - continue; - } - - /*! parse edge crease */ - if (token[0] == 'e' && token[1] == 'c' && isSep(token[2])) - { - parseSep(token += 2); - float w = getFloat(token); - parseSepOpt(token); - int a = fix_v(getInt(token)); - parseSepOpt(token); - int b = fix_v(getInt(token)); - parseSepOpt(token); - ec.push_back(Crease(w, a, b)); - continue; - } - - /*! use material */ - if (!strncmp(token, "usemtl", 6) && isSep(token[6])) - { - flushFaceGroup(); - std::string name(parseSep(token += 6)); - if (material.find(name) == material.end()) curMaterial = defaultMaterial; - else curMaterial = material[name]; - continue; - } - - /* load material library */ - if (!strncmp(token, "mtllib", 6) && isSep(token[6])) { - loadMTL(path + std::string(parseSep(token += 6))); - continue; - } - - // ignore unknown stuff - } - flushFaceGroup(); - - cin.close(); - } - - /* load material file */ - void OBJLoader::loadMTL(const FileName &fileName) - { - std::ifstream cin; - cin.open(fileName.c_str()); - if (!cin.is_open()) { - std::cerr << "cannot open " << fileName.str() << std::endl; - return; - } - - char line[10000]; - memset(line, 0, sizeof(line)); - - OBJMaterial* cur = nullptr; - while (cin.peek() != -1) - { - /* load next multiline */ - char* pline = line; - while (true) { - cin.getline(pline, sizeof(line) - (pline - line) - 16, '\n'); - ssize_t last = strlen(pline) - 1; - if (last < 0 || pline[last] != '\\') break; - pline += last; - *pline++ = ' '; - } - const char* token = trimEnd(line + strspn(line, " \t")); - - if (token[0] == 0 ) continue; // ignore empty lines - if (token[0] == '#') continue; // ignore comments - - if (!strncmp(token, "newmtl", 6)) { - parseSep(token+=6); - std::string name(token); - Material objmtl; new (&objmtl) OBJMaterial; - Ref mtl = new SceneGraph::MaterialNode(objmtl); - material[name] = mtl; - cur = (OBJMaterial*) &mtl->material; - continue; - } - - if (!cur) THROW_RUNTIME_ERROR("invalid material file: newmtl expected first"); - - if (!strncmp(token, "illum", 5)) { parseSep(token += 5); continue; } - - if (!strncmp(token, "d", 1)) { parseSep(token += 1); cur->d = getFloat(token); continue; } - if (!strncmp(token, "Ns", 2)) { parseSep(token += 2); cur->Ns = getFloat(token); continue; } - if (!strncmp(token, "Ni", 2)) { parseSep(token += 2); cur->Ni = getFloat(token); continue; } - - if (!strncmp(token, "Ka_map", 6)) { continue; } - if (!strncmp(token, "Kd_map", 6) || !strncmp(token, "map_Kd", 6)) { - parseSep(token += 6); - cur->map_Kd = loadTexture(path + FileName(token)); - continue; - } - - - if (!strncmp(token, "Ks_map", 6)) { continue; } - if (!strncmp(token, "Tf_map", 6)) { continue; } - if (!strncmp(token, "Displ_map", 9) || !strncmp(token, "map_Displ", 9)) { - parseSep(token += 9); - cur->map_Displ = loadTexture(path + FileName(token)); - continue; - } - - if (!strncmp(token, "Ka", 2)) { parseSep(token += 2); cur->Ka = getVec3f(token); continue; } - if (!strncmp(token, "Kd", 2)) { parseSep(token += 2); cur->Kd = getVec3f(token); continue; } - if (!strncmp(token, "Ks", 2)) { parseSep(token += 2); cur->Ks = getVec3f(token); continue; } - if (!strncmp(token, "Tf", 2)) { parseSep(token += 2); cur->Kt = getVec3f(token); continue; } - } - cin.close(); - } - - /*! handles relative indices and starts indexing from 0 */ - int OBJLoader::fix_v (int index) { return (index > 0 ? index - 1 : (index == 0 ? 0 : (int) v .size() + index)); } - int OBJLoader::fix_vt(int index) { return (index > 0 ? index - 1 : (index == 0 ? 0 : (int) vt.size() + index)); } - int OBJLoader::fix_vn(int index) { return (index > 0 ? index - 1 : (index == 0 ? 0 : (int) vn.size() + index)); } - - /*! Parse differently formated triplets like: n0, n0/n1/n2, n0//n2, n0/n1. */ - /*! All indices are converted to C-style (from 0). Missing entries are assigned -1. */ - Vertex OBJLoader::getInt3(const char*& token) - { - Vertex v(-1); - v.v = fix_v(atoi(token)); - token += strcspn(token, "/ \t\r"); - if (token[0] != '/') return(v); - token++; - - // it is i//n - if (token[0] == '/') { - token++; - v.vn = fix_vn(atoi(token)); - token += strcspn(token, " \t\r"); - return(v); - } - - // it is i/t/n or i/t - v.vt = fix_vt(atoi(token)); - token += strcspn(token, "/ \t\r"); - if (token[0] != '/') return(v); - token++; - - // it is i/t/n - v.vn = fix_vn(atoi(token)); - token += strcspn(token, " \t\r"); - return(v); - } - - uint32_t OBJLoader::getVertex(std::map& vertexMap, Ref mesh, const Vertex& i) - { - const std::map::iterator& entry = vertexMap.find(i); - if (entry != vertexMap.end()) return(entry->second); - mesh->v.push_back(Vec3fa(v[i.v].x,v[i.v].y,v[i.v].z)); - if (i.vn >= 0) mesh->vn.push_back(vn[i.vn]); - if (i.vt >= 0) mesh->vt.push_back(vt[i.vt]); - return(vertexMap[i] = int(mesh->v.size()) - 1); - } - - /*! end current facegroup and append to mesh */ - void OBJLoader::flushFaceGroup() - { - if (curGroup.empty()) return; - - if (subdivMode) - { - Ref mesh = new SceneGraph::SubdivMeshNode(curMaterial); - group->add(mesh.cast()); - - for (size_t i=0; ipositions.push_back(v[i]); - for (size_t i=0; inormals .push_back(vn[i]); - for (size_t i=0; itexcoords.push_back(vt[i]); - - for (size_t i=0; iedge_creases.push_back(Vec2i(ec[i].a, ec[i].b)); - mesh->edge_crease_weights.push_back(ec[i].w); - } - - for (size_t j=0; j& face = curGroup[j]; - mesh->verticesPerFace.push_back(face.size()); - for (size_t i=0; iposition_indices.push_back(face[i].v); - } - } - else - { - Ref mesh = new SceneGraph::TriangleMeshNode(curMaterial); - group->add(mesh.cast()); - - // merge three indices into one - std::map vertexMap; - for (size_t j=0; j& face = curGroup[j]; - - /* triangulate the face with a triangle fan */ - Vertex i0 = face[0], i1 = Vertex(-1), i2 = face[1]; - for (size_t k=2; k < face.size(); k++) - { - i1 = i2; i2 = face[k]; - uint32_t v0,v1,v2; - v0 = getVertex(vertexMap, mesh, i0); - v1 = getVertex(vertexMap, mesh, i1); - v2 = getVertex(vertexMap, mesh, i2); - assert(v0 < mesh->v.size()); - assert(v1 < mesh->v.size()); - assert(v2 < mesh->v.size()); - mesh->triangles.push_back(SceneGraph::TriangleMeshNode::Triangle(v0,v1,v2)); - } - } - } - curGroup.clear(); - ec.clear(); - } - - Ref loadOBJ(const FileName& fileName, const bool subdivMode) { - OBJLoader loader(fileName,subdivMode); return loader.group.cast(); - } -} - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/obj_loader.h b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/obj_loader.h deleted file mode 100644 index 0939fd2d0bb9..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/obj_loader.h +++ /dev/null @@ -1,33 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../../../common/sys/platform.h" -#include "../../../common/sys/filename.h" -#include "../../../common/sys/vector.h" -#include "../../../common/math/vec2.h" -#include "../../../common/math/vec3.h" -#include "../../../common/math/affinespace.h" -#include "scene.h" - -#include -#include - -namespace embree -{ - Ref loadOBJ(const FileName& fileName, const bool subdivMode); -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/ray.h b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/ray.h deleted file mode 100644 index 149df676ad63..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/ray.h +++ /dev/null @@ -1,75 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../../../common/sys/platform.h" -#include "../../../common/sys/ref.h" -#include "../../../common/sys/intrinsics.h" -#include "../../../common/sys/sysinfo.h" -#include "../../../common/sys/atomic.h" -#include "../../../common/sys/vector.h" -#include "../../../common/sys/string.h" - -#include "../../../common/math/math.h" -#include "../../../common/math/vec2.h" -#include "../../../common/math/vec3.h" -#include "../../../common/math/vec4.h" -#include "../../../common/math/bbox.h" -#include "../../../common/math/affinespace.h" - -#include "../../../common/simd/simd.h" - - /*! Ray structure. Contains all information about a ray including - * precomputed reciprocal direction. */ - struct RTCRay - { - /*! Default construction does nothing. */ - __forceinline RTCRay() {} - - /*! Constructs a ray from origin, direction, and ray segment. Near - * has to be smaller than far. */ - __forceinline RTCRay(const embree::Vec3fa& org, const embree::Vec3fa& dir, - float tnear = embree::zero, float tfar = embree::inf, - float time = embree::zero, int mask = -1) - : org(org), dir(dir), tnear(tnear), tfar(tfar), geomID(-1), primID(-1), instID(-1), mask(mask), time(time) {} - - /*! Tests if we hit something. */ - __forceinline operator bool() const { return geomID != -1; } - - public: - embree::Vec3fa org; //!< Ray origin - embree::Vec3fa dir; //!< Ray direction - float tnear; //!< Start of ray segment - float tfar; //!< End of ray segment - float time; //!< Time of this ray for motion blur. - int mask; //!< used to mask out objects during traversal - - public: - embree::Vec3fa Ng; //!< Not normalized geometry normal - float u; //!< Barycentric u coordinate of hit - float v; //!< Barycentric v coordinate of hit - int geomID; //!< geometry ID - int primID; //!< primitive ID - int instID; //!< instance ID - }; - - /*! Outputs ray to stream. */ - inline std::ostream& operator<<(std::ostream& cout, const RTCRay& ray) { - return cout << "{ " << - "org = " << ray.org << ", dir = " << ray.dir << ", near = " << ray.tnear << ", far = " << ray.tfar << ", time = " << ray.time << ", " << - "instID = " << ray.instID << ", geomID = " << ray.geomID << ", primID = " << ray.primID << ", " << "u = " << ray.u << ", v = " << ray.v << ", Ng = " << ray.Ng << " }"; -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/scene.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/scene.cpp deleted file mode 100644 index 280412ba40a3..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/scene.cpp +++ /dev/null @@ -1,179 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "scene.h" - -namespace embree -{ - struct SceneGraph2OBJScene - { - OBJScene* scene; - std::map, size_t> material2id; - - SceneGraph2OBJScene (Ref in, OBJScene* scene) - : scene(scene) { convert(in,one); } - - int convert(Ref node) - { - if (material2id.find(node) == material2id.end()) { - scene->materials.push_back(node->material); - material2id[node] = scene->materials.size()-1; - } - return material2id[node]; - } - - void convert(Ref node, const AffineSpace3fa& space) - { - if (Ref xfmNode = node.dynamicCast()) { - convert(xfmNode->child, space*xfmNode->xfm); - } - else if (Ref groupNode = node.dynamicCast()) { - for (auto child : groupNode->children) convert(child,space); - } - else if (Ref > ambientLight = node.dynamicCast >()) { - scene->ambientLights.push_back(ambientLight->light.transform(space)); - } - else if (Ref > pointLight = node.dynamicCast >()) { - scene->pointLights.push_back(pointLight->light.transform(space)); - } - else if (Ref > directionalLight = node.dynamicCast >()) { - scene->directionalLights.push_back(directionalLight->light.transform(space)); - } - else if (Ref > spotLight = node.dynamicCast >()) { - //scene->spotLights.push_back(spotLight->light.transform(space)); - } - else if (Ref > distantLight = node.dynamicCast >()) { - scene->distantLights.push_back(distantLight->light.transform(space)); - } - else if (Ref mesh = node.dynamicCast()) - { - int materialID = convert(mesh->material); - - OBJScene::Mesh* objmesh = new OBJScene::Mesh(); - const LinearSpace3fa nspace = rcp(space.l).transposed(); - objmesh->v. resize(mesh->v. size()); for (size_t i=0; iv. size(); i++) objmesh->v [i] = xfmPoint ( space,mesh->v [i]); - objmesh->v2.resize(mesh->v2.size()); for (size_t i=0; iv2.size(); i++) objmesh->v2[i] = xfmPoint ( space,mesh->v2[i]); - objmesh->vn.resize(mesh->vn.size()); for (size_t i=0; ivn.size(); i++) objmesh->vn[i] = xfmVector(nspace,mesh->vn[i]); - objmesh->vt = mesh->vt; - - objmesh->triangles.resize(mesh->triangles.size()); - for (size_t i=0; itriangles.size(); i++) { - SceneGraph::TriangleMeshNode::Triangle& tri = mesh->triangles[i]; - objmesh->triangles[i] = OBJScene::Triangle(tri.v0,tri.v1,tri.v2,materialID); - } - objmesh->meshMaterialID = materialID; - scene->meshes.push_back(objmesh); - } - else if (Ref mesh = node.dynamicCast()) - { - int materialID = convert(mesh->material); - - OBJScene::SubdivMesh* subdivmesh = new OBJScene::SubdivMesh(); - const LinearSpace3fa nspace = rcp(space.l).transposed(); - - subdivmesh->positions.resize(mesh->positions.size()); - for (size_t i=0; ipositions.size(); i++) - subdivmesh->positions[i] = xfmPoint(space,mesh->positions[i]); - - subdivmesh->normals.resize(mesh->normals.size()); - for (size_t i=0; inormals.size(); i++) - subdivmesh->normals[i] = xfmVector(nspace,mesh->normals[i]); - - subdivmesh->texcoords = mesh->texcoords; - subdivmesh->position_indices = mesh->position_indices; - subdivmesh->normal_indices = mesh->normal_indices; - subdivmesh->texcoord_indices = mesh->texcoord_indices; - subdivmesh->verticesPerFace = mesh->verticesPerFace; - subdivmesh->holes = mesh->holes; - subdivmesh->edge_creases = mesh->edge_creases; - subdivmesh->edge_crease_weights = mesh->edge_crease_weights; - subdivmesh->vertex_creases = mesh->vertex_creases; - subdivmesh->vertex_crease_weights = mesh->vertex_crease_weights; - subdivmesh->materialID = materialID; - scene->subdiv.push_back(subdivmesh); - } - else if (Ref mesh = node.dynamicCast()) - { - int materialID = convert(mesh->material); - - OBJScene::HairSet* hairset = new OBJScene::HairSet; - - hairset->v.resize(mesh->v.size()); - for (size_t i=0; iv.size(); i++) { - hairset->v[i] = xfmPoint(space,mesh->v[i]); - hairset->v[i].w = mesh->v[i].w; - } - - hairset->v2.resize(mesh->v2.size()); - for (size_t i=0; iv2.size(); i++) { - hairset->v2[i] = xfmPoint(space,mesh->v2[i]); - hairset->v2[i].w = mesh->v2[i].w; - } - - hairset->hairs.resize(mesh->hairs.size()); - for (size_t i=0; ihairs.size(); i++) - hairset->hairs[i] = OBJScene::Hair(mesh->hairs[i].vertex,mesh->hairs[i].id); - - scene->hairsets.push_back(hairset); - } - } - }; - - void OBJScene::add(Ref node) { - SceneGraph2OBJScene(node,this); - } - - void OBJScene::Mesh::set_motion_blur(const Mesh* other) - { - if (v.size() != other->v.size()) - THROW_RUNTIME_ERROR("incompatible geometry"); - - bool different = false; - for (size_t i=0; iv[i]; - - if (different) - v2 = other->v; - } - - void OBJScene::HairSet::set_motion_blur(const HairSet* other) - { - if (v.size() != other->v.size()) - THROW_RUNTIME_ERROR("incompatible geometry"); - - bool different = false; - for (size_t i=0; iv[i]; - - if (different) - v2 = other->v; - } - - void OBJScene::set_motion_blur(OBJScene& other) - { - if (meshes.size() != other.meshes.size()) - THROW_RUNTIME_ERROR("incompatible geometry"); - - for (size_t i=0; iset_motion_blur(other.meshes[i]); - - if (hairsets.size() != other.hairsets.size()) - THROW_RUNTIME_ERROR("incompatible geometry"); - - for (size_t i=0; iset_motion_blur(other.hairsets[i]); - } -}; diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/scene.h b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/scene.h deleted file mode 100644 index 05894a1fb7d5..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/scene.h +++ /dev/null @@ -1,172 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../../../common/sys/ref.h" -#include "../../../common/sys/vector.h" -#include "../../../common/math/vec2.h" -#include "../../../common/math/vec3.h" -#include "../../../common/math/affinespace.h" -#include "scenegraph.h" - -#include -#include -#include - -namespace embree -{ - /*! Scene representing the OBJ file */ - struct OBJScene // FIXME: name Scene - { - OBJScene () {} - - void add (Ref node); - - ~OBJScene () - { - for (size_t i=0; i v; - avector v2; - avector vn; - - std::vector vt; - std::vector triangles; - std::vector quads; - int meshMaterialID; - }; - - /*! Subdivision Mesh. */ - struct SubdivMesh - { - avector positions; //!< vertex positions - avector normals; //!< face vertex normals - std::vector texcoords; //!< face texture coordinates - std::vector position_indices; //!< position indices for all faces - std::vector normal_indices; //!< normal indices for all faces - std::vector texcoord_indices; //!< texcoord indices for all faces - std::vector verticesPerFace; //!< number of indices of each face - std::vector holes; //!< face ID of holes - std::vector edge_creases; //!< index pairs for edge crease - std::vector edge_crease_weights; //!< weight for each edge crease - std::vector vertex_creases; //!< indices of vertex creases - std::vector vertex_crease_weights; //!< weight for each vertex crease - int materialID; - }; - - struct Hair - { - public: - Hair () {} - Hair (int vertex, int id) - : vertex(vertex), id(id) {} - public: - int vertex,id; //!< index of first control point and hair ID - }; - - /*! Hair Set. */ - struct HairSet - { - void set_motion_blur(const HairSet* other); - - avector v; //!< hair control points (x,y,z,r) - avector v2; //!< hair control points (x,y,z,r) - std::vector hairs; //!< list of hairs - }; - - bool empty() const { - return meshes.size() == 0 && hairsets.size() == 0; - } - - void set_motion_blur(OBJScene& other); - - void convert_to_subdiv() - { - for (size_t i=0; ipositions = mesh->v; - smesh->normals = mesh->vn; - smesh->texcoords = mesh->vt; - const size_t numTriangles = mesh->triangles.size(); - smesh->verticesPerFace.resize(numTriangles); - smesh->position_indices.resize(3*numTriangles); - int materialID = 0; - for (size_t j=0; jverticesPerFace[j] = 3; - smesh->position_indices[3*j+0] = mesh->triangles[j].v0; - smesh->position_indices[3*j+1] = mesh->triangles[j].v1; - smesh->position_indices[3*j+2] = mesh->triangles[j].v2; - materialID = mesh->triangles[j].materialID; - } - smesh->materialID = materialID; - - delete mesh; - subdiv.push_back(smesh); - } - meshes.clear(); - } - - public: - avector materials; //!< material list - std::vector meshes; //!< list of meshes - std::vector hairsets; //!< list of hair sets - std::vector subdiv; //!< list of subdivision meshes - avector ambientLights; //!< list of ambient lights - avector pointLights; //!< list of point lights - avector directionalLights; //!< list of directional lights - avector distantLights; //!< list of distant lights - }; -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/scene_device.h b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/scene_device.h deleted file mode 100644 index 995131258c7a..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/scene_device.h +++ /dev/null @@ -1,172 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - - -struct ISPCTriangle -{ - int v0; /*< first triangle vertex */ - int v1; /*< second triangle vertex */ - int v2; /*< third triangle vertex */ - int materialID; /*< material of triangle */ -}; - -struct ISPCQuad -{ - int v0; /*< first triangle vertex */ - int v1; /*< second triangle vertex */ - int v2; /*< third triangle vertex */ - int v3; /*< fourth triangle vertex */ -}; - -struct ISPCHair -{ - int vertex; - int id; -}; - -struct ISPCHairSet -{ - Vec3fa* v; //!< hair control points (x,y,z,r) - Vec3fa* v2; //!< hair control points (x,y,z,r) - ISPCHair* hairs; //!< for each hair, index to first control point - int numVertices; - int numHairs; -}; - - -struct ISPCMesh -{ - Vec3fa* positions; //!< vertex position array - Vec3fa* positions2; //!< vertex position array - Vec3fa* normals; //!< vertex normal array - Vec2f* texcoords; //!< vertex texcoord array - ISPCTriangle* triangles; //!< list of triangles - ISPCQuad* quads; //!< list of triangles - float* edge_level; - int numVertices; - int numTriangles; - int numQuads; - int geomID; - int meshMaterialID; -}; - -struct ISPCSubdivMesh -{ - Vec3fa* positions; //!< vertex positions - Vec3fa* normals; //!< face vertex normals - Vec2f* texcoords; //!< face texture coordinates - int* position_indices; //!< position indices for all faces - int* normal_indices; //!< normal indices for all faces - int* texcoord_indices; //!< texcoord indices for all faces - int* verticesPerFace; //!< number of indices of each face - int* holes; //!< face ID of holes - float* subdivlevel; //!< subdivision level - Vec2i* edge_creases; //!< crease index pairs - float* edge_crease_weights; //!< weight for each crease - int* vertex_creases; //!< indices of vertex creases - float* vertex_crease_weights; //!< weight for each vertex crease - int *face_offsets; - int numVertices; - int numFaces; - int numEdges; - int numEdgeCreases; - int numVertexCreases; - int numHoles; - int materialID; - int geomID; - Vec3fa* colors; // FIXME: remove -}; - -struct ISPCAmbientLight -{ - Vec3fa L; //!< radiance of ambient light -}; - -struct ISPCPointLight -{ - Vec3fa P; //!< position of point light - Vec3fa I; //!< radiant intensity of point light -}; - -struct ISPCDirectionalLight -{ - Vec3fa D; //!< Light direction - Vec3fa E; //!< Irradiance (W/m^2) -}; - -struct ISPCDistantLight -{ - Vec3fa D; //!< Light direction - Vec3fa L; //!< Radiance (W/(m^2*sr)) - float halfAngle; //!< Half illumination angle - float radHalfAngle; //!< Half illumination angle in radians - float cosHalfAngle; //!< Cosine of half illumination angle -}; - -//enum MaterialTy { MATERIAL_OBJ, MATERIAL_THIN_DIELECTRIC, MATERIAL_METAL, MATERIAL_VELVET, MATERIAL_DIELECTRIC, MATERIAL_METALLIC_PAINT, MATERIAL_MATTE, MATERIAL_MIRROR, MATERIAL_REFLECTIVE_METAL }; - -struct ISPCMaterial -{ - int ty; - int align0,align1,align2; - Vec3fa v[7]; -}; - -enum TEXTURE_FORMAT { - RGBA8 = 1, - RGB8 = 2, - FLOAT32 = 3, - PTEX_RGBA8 = 4, - PTEX_FLOAT32 = 5 -}; - -struct ISPCSubdivMeshKeyFrame { - ISPCSubdivMesh** subdiv; //!< list of subdiv meshes - int numSubdivMeshes; //!< number of subdiv meshes -}; - -struct ISPCScene { - - ISPCMesh** meshes; //!< list of meshes - ISPCMaterial* materials; //!< material list - int numMeshes; //!< number of meshes - int numMaterials; //!< number of materials - - ISPCHairSet** hairs; - int numHairSets; - - ISPCAmbientLight* ambientLights; //!< list of ambient lights - int numAmbientLights; //!< number of ambient lights - - ISPCPointLight* pointLights; //!< list of point lights - int numPointLights; //!< number of point lights - - ISPCDirectionalLight* dirLights; //!< list of directional lights - int numDirectionalLights; //!< number of directional lights - - ISPCDistantLight* distantLights; //!< list of distant lights - int numDistantLights; //!< number of distant lights - - ISPCSubdivMesh** subdiv; //!< list of subdiv meshes - int numSubdivMeshes; //!< number of subdiv meshes - - ISPCSubdivMeshKeyFrame** subdivMeshKeyFrames; - int numSubdivMeshKeyFrames; -}; // ISPCScene - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/scenegraph.h b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/scenegraph.h deleted file mode 100644 index 31ef92e020bb..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/scenegraph.h +++ /dev/null @@ -1,439 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../../../common/sys/ref.h" -#include "../../../common/sys/vector.h" -#include "../../../common/math/vec2.h" -#include "../../../common/math/vec3.h" -#include "../../../common/math/affinespace.h" - -#include -#include - - -namespace embree -{ - enum MaterialTy { MATERIAL_OBJ, MATERIAL_THIN_DIELECTRIC, MATERIAL_METAL, MATERIAL_VELVET, MATERIAL_DIELECTRIC, MATERIAL_METALLIC_PAINT, MATERIAL_MATTE, MATERIAL_MIRROR, MATERIAL_REFLECTIVE_METAL }; - - struct MatteMaterial - { - public: - MatteMaterial (const Vec3fa& reflectance) - : ty(MATERIAL_MATTE), reflectance(reflectance) {} - - public: - int ty; - int align[3]; - Vec3fa reflectance; - }; - - struct MirrorMaterial - { - public: - MirrorMaterial (const Vec3fa& reflectance) - : ty(MATERIAL_MIRROR), reflectance(reflectance) {} - - public: - int ty; - int align[3]; - Vec3fa reflectance; - }; - - struct ThinDielectricMaterial - { - public: - ThinDielectricMaterial (const Vec3fa& transmission, const float eta, const float thickness) - : ty(MATERIAL_THIN_DIELECTRIC), transmission(log(transmission)*thickness), eta(eta) {} - - public: - int ty; - int align[3]; - Vec3fa transmission; - float eta; - }; - - /*! OBJ material */ - struct OBJMaterial - { - public: - OBJMaterial () - : ty(MATERIAL_OBJ), illum(0), d(1.f), Ns(1.f), Ni(1.f), Ka(0.f), Kd(1.f), Ks(0.f), Kt(0.0f), map_Kd(nullptr), map_Displ(nullptr) - {}; - - OBJMaterial (float d, const Vec3fa& Kd, const Vec3fa& Ks, const float Ns) - : ty(MATERIAL_OBJ), illum(0), d(d), Ns(Ns), Ni(1.f), Ka(0.f), Kd(Kd), Ks(Ks), Kt(0.0f), map_Kd(nullptr), map_Displ(nullptr) - {}; - - ~OBJMaterial() { // FIXME: destructor never called! - } - - public: - int ty; - int align[3]; - - int illum; /*< illumination model */ - float d; /*< dissolve factor, 1=opaque, 0=transparent */ - float Ns; /*< specular exponent */ - float Ni; /*< optical density for the surface (index of refraction) */ - - Vec3fa Ka; /*< ambient reflectivity */ - Vec3fa Kd; /*< diffuse reflectivity */ - Vec3fa Ks; /*< specular reflectivity */ - Vec3fa Kt; /*< transmission filter */ - - void* map_Kd; /*< dummy */ - void* map_Displ; /*< dummy */ - }; - - struct MetalMaterial - { - public: - MetalMaterial (const Vec3fa& reflectance, const Vec3fa& eta, const Vec3fa& k) - : ty(MATERIAL_REFLECTIVE_METAL), reflectance(reflectance), eta(eta), k(k), roughness(0.0f) {} - - MetalMaterial (const Vec3fa& reflectance, const Vec3fa& eta, const Vec3fa& k, const float roughness) - : ty(MATERIAL_METAL), reflectance(reflectance), eta(eta), k(k), roughness(roughness) {} - - public: - int ty; - int align[3]; - - Vec3fa reflectance; - Vec3fa eta; - Vec3fa k; - float roughness; - }; - - typedef MetalMaterial ReflectiveMetalMaterial; - - struct VelvetMaterial - { - VelvetMaterial (const Vec3fa& reflectance, const float backScattering, const Vec3fa& horizonScatteringColor, const float horizonScatteringFallOff) - : ty(MATERIAL_VELVET), reflectance(reflectance), backScattering(backScattering), horizonScatteringColor(horizonScatteringColor), horizonScatteringFallOff(horizonScatteringFallOff) {} - - public: - int ty; - int align[3]; - - Vec3fa reflectance; - Vec3fa horizonScatteringColor; - float backScattering; - float horizonScatteringFallOff; - }; - - struct DielectricMaterial - { - DielectricMaterial (const Vec3fa& transmissionOutside, const Vec3fa& transmissionInside, const float etaOutside, const float etaInside) - : ty(MATERIAL_DIELECTRIC), transmissionOutside(transmissionOutside), transmissionInside(transmissionInside), etaOutside(etaOutside), etaInside(etaInside) {} - - public: - int ty; - int align[3]; - Vec3fa transmissionOutside; - Vec3fa transmissionInside; - float etaOutside; - float etaInside; - }; - - struct MetallicPaintMaterial - { - MetallicPaintMaterial (const Vec3fa& shadeColor, const Vec3fa& glitterColor, float glitterSpread, float eta) - : ty(MATERIAL_METALLIC_PAINT), shadeColor(shadeColor), glitterColor(glitterColor), glitterSpread(glitterSpread), eta(eta) {} - - public: - int ty; - int align[3]; - Vec3fa shadeColor; - Vec3fa glitterColor; - float glitterSpread; - float eta; - }; - - /*! Material */ - struct Material - { - public: - Material () { memset(this,0,sizeof(Material)); } - Material (const OBJMaterial& in) { *((OBJMaterial*)this) = in; } - OBJMaterial& obj() { return *(OBJMaterial*)this; } - - public: - int ty; - int align[3]; - Vec3fa v[7]; - }; - - struct AmbientLight - { - public: - AmbientLight () {} - - AmbientLight (const Vec3fa& L) - : L(L) {} - - const AmbientLight transform(const AffineSpace3fa& space) const { - return AmbientLight(L); - } - - public: - Vec3fa L; //!< radiance of ambient light - }; - - struct PointLight - { - public: - PointLight() {} - - PointLight (const Vec3fa& P, const Vec3fa& I) - : P(P), I(I) {} - - const PointLight transform(const AffineSpace3fa& space) const { - return PointLight(xfmPoint(space,P),I); - } - - public: - Vec3fa P; //!< position of point light - Vec3fa I; //!< radiant intensity of point light - }; - - struct DirectionalLight - { - public: - DirectionalLight () {} - - DirectionalLight (const Vec3fa& D, const Vec3fa& E) - : D(D), E(E) {} - - const DirectionalLight transform(const AffineSpace3fa& space) const { - return DirectionalLight(xfmVector(space,D),E); - } - - public: - Vec3fa D; //!< Light direction - Vec3fa E; //!< Irradiance (W/m^2) - }; - - struct SpotLight - { - SpotLight () {} - - SpotLight (const Vec3fa& P, const Vec3fa& D, const Vec3fa& I, const float angleMin, const float angleMax) - : P(P), D(D), I(I), angleMin(angleMin), angleMax(angleMax) {} - - const SpotLight transform(const AffineSpace3fa& space) const { - return SpotLight(xfmPoint(space,P),xfmVector(space,D),I,angleMin,angleMax); - } - - public: - Vec3fa P; //!< Position of the spot light - Vec3fa D; //!< Light direction of the spot light - Vec3fa I; //!< Radiant intensity (W/sr) - float angleMin, angleMax; //!< Linear falloff region - }; - - struct DistantLight - { - public: - DistantLight () {} - - DistantLight (const Vec3fa& D, const Vec3fa& L, const float halfAngle) - : D(D), L(L), halfAngle(halfAngle), radHalfAngle(deg2rad(halfAngle)), cosHalfAngle(cos(deg2rad(halfAngle))) {} - - const DistantLight transform(const AffineSpace3fa& space) const { - return DistantLight(xfmVector(space,D),L,halfAngle); - } - - public: - Vec3fa D; //!< Light direction - Vec3fa L; //!< Radiance (W/(m^2*sr)) - float halfAngle; //!< Half illumination angle - float radHalfAngle; //!< Half illumination angle in radians - float cosHalfAngle; //!< Cosine of half illumination angle - }; - - struct TriangleLight - { - TriangleLight() {} - - TriangleLight (const Vec3fa& v0, const Vec3fa& v1, const Vec3fa& v2, const Vec3fa& L) - : v0(v0), v1(v1), v2(v2), L(L) {} - - const TriangleLight transform(const AffineSpace3fa& space) const { - return TriangleLight(xfmPoint(space,v0),xfmPoint(space,v1),xfmPoint(space,v2),L); - } - - public: - Vec3fa v0; - Vec3fa v1; - Vec3fa v2; - Vec3fa L; - }; - - struct QuadLight - { - QuadLight() {} - - QuadLight (const Vec3fa& v0, const Vec3fa& v1, const Vec3fa& v2, const Vec3fa& v3, const Vec3fa& L) - : v0(v0), v1(v1), v2(v2), v3(v3), L(L) {} - - const QuadLight transform(const AffineSpace3fa& space) const { - return QuadLight(xfmPoint(space,v0),xfmPoint(space,v1),xfmPoint(space,v2),xfmPoint(space,v3),L); - } - - public: - Vec3fa v0; - Vec3fa v1; - Vec3fa v2; - Vec3fa v3; - Vec3fa L; - }; - - struct SceneGraph - { - struct Node : public RefCount - { - Node () - : name("unnamed") {} - - Node (const std::string& name) - : name(name) {} - - std::string name; - }; - - struct TransformNode : public Node - { - ALIGNED_STRUCT; - TransformNode (const AffineSpace3fa& xfm, const Ref& child) - : xfm(xfm), child(child) {} - - public: - AffineSpace3fa xfm; - Ref child; - }; - - struct GroupNode : public Node - { - GroupNode (const size_t N = 0) { - children.resize(N); - } - - void add(const Ref& node) { - children.push_back(node); - } - - void set(const size_t i, const Ref& node) { - children[i] = node; - } - - public: - std::vector > children; - }; - - template - struct LightNode : public Node - { - ALIGNED_STRUCT; - - LightNode(const Light& light) - : light(light) {} - - Light light; - }; - - struct MaterialNode : public Node - { - ALIGNED_STRUCT; - - MaterialNode(const Material& material) - : material(material) {} - - Material material; - }; - - /*! Mesh. */ - struct TriangleMeshNode : public Node - { - struct Triangle - { - public: - Triangle (int v0, int v1, int v2) - : v0(v0), v1(v1), v2(v2) {} - public: - int v0, v1, v2; - }; - - public: - TriangleMeshNode (Ref material) - : material(material) {} - - public: - avector v; - avector v2; - avector vn; - std::vector vt; - std::vector triangles; - Ref material; - }; - - /*! Subdivision Mesh. */ - struct SubdivMeshNode : public Node - { - SubdivMeshNode (Ref material) - : material(material) {} - - avector positions; //!< vertex positions - avector normals; //!< face vertex normals - std::vector texcoords; //!< face texture coordinates - std::vector position_indices; //!< position indices for all faces - std::vector normal_indices; //!< normal indices for all faces - std::vector texcoord_indices; //!< texcoord indices for all faces - std::vector verticesPerFace; //!< number of indices of each face - std::vector holes; //!< face ID of holes - std::vector edge_creases; //!< index pairs for edge crease - std::vector edge_crease_weights; //!< weight for each edge crease - std::vector vertex_creases; //!< indices of vertex creases - std::vector vertex_crease_weights; //!< weight for each vertex crease - Ref material; - }; - - /*! Hair Set. */ - struct HairSetNode : public Node - { - struct Hair - { - public: - Hair () {} - Hair (int vertex, int id) - : vertex(vertex), id(id) {} - public: - int vertex,id; //!< index of first control point and hair ID - }; - - public: - HairSetNode (Ref material) - : material(material) {} - - public: - avector v; //!< hair control points (x,y,z,r) - avector v2; //!< hair control points (x,y,z,r) - std::vector hairs; //!< list of hairs - Ref material; - }; - }; -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/texture_loader.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/texture_loader.cpp deleted file mode 100644 index 153f635d1640..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/texture_loader.cpp +++ /dev/null @@ -1,164 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "texture_loader.h" -#include "../image/image.h" - -#if defined(USE_PTEX) -#include "Ptexture.h" -#endif - -#include -#include -#include "../../../common/sys/string.h" - -namespace embree -{ - bool isPowerOf2 (unsigned int x) - { - while (((x % 2) == 0) && x > 1) - x /= 2; - return (x == 1); - } - - /*! read png texture from disk */ - Texture *loadTexture(const FileName& fileName) - { - Texture *texture = new Texture(); - - std::string ext = strlwr(fileName.ext()); - if (ext == "ptx" ) return loadPtexTexture(fileName); - - Ref img = loadImage(fileName); - - texture->width = img.ptr->width; - texture->height = img.ptr->height; - texture->format = Texture::RGBA8; - texture->bytesPerTexel = 4; - texture->data = _mm_malloc(sizeof(int)*texture->width*texture->height,64); - texture->width_mask = isPowerOf2(texture->width) ? texture->width-1 : 0; - texture->height_mask = isPowerOf2(texture->height) ? texture->height-1 : 0; - img.ptr->convertToRGBA8((unsigned char*)texture->data); - return texture; - } - - Texture *loadPtexTexture(const FileName& filename) - { -#if defined(USE_PTEX) - std::string fn = filename.str(); - Ptex::String error; - std::cout << "opening " << fn << " ... " << std::flush; - PtexTexture* tex = PtexTexture::open(fn.c_str(),error); - if (!tex) { - std::cout << "[FAILED]" << std::endl; - THROW_RUNTIME_ERROR("cannot open ptex file: "+fn); - } - - PtexMetaData *metadata = tex->getMetaData(); - const int32_t *vertices_per_face = nullptr; - int geom_faces = 0; - metadata->getValue("PtexFaceVertCounts", vertices_per_face, geom_faces); - - Texture **face_textures = new Texture *[geom_faces]; - for (size_t i=0;iwidth = 0; - texture->height = 0; - texture->format = Texture::PTEX_RGBA8; - texture->faceTextures = geom_faces; - texture->data = face_textures; - texture->width_mask = 0; - texture->height_mask = 0; - - int nchan = tex->numChannels(); - if (nchan != 3 && nchan != 1) - { - std::cout << "[FAILED]" << std::endl; - THROW_RUNTIME_ERROR(fn+": ptex file with other than 1 or 3 channels found!"); - } - - if (nchan == 1) - texture->format = Texture::PTEX_FLOAT32; - - float px[3]; - int ptex_face_id = 0; - - for (size_t geom_face_id=0;geom_face_idgetFaceInfo(ptex_face_id); - - int n = vertices_per_face[geom_face_id]; - if (n == 4) /* ptex data only for quads */ - { - Ptex::Res res = fi.res; - - Texture *face_txt = new Texture(); - face_txt->width = res.u(); - face_txt->height = res.v(); - face_txt->width_mask = 0; - face_txt->height_mask = 0; - face_txt->data = nullptr; - face_textures[geom_face_id] = face_txt; - - if (nchan == 3) /* rgb color data */ - { - face_txt->format = Texture::RGBA8; - face_txt->bytesPerTexel = 4; - unsigned char *data = new unsigned char[face_txt->bytesPerTexel*face_txt->width*face_txt->height]; - face_txt->data = data; - - for (int vi = 0; vi < face_txt->height; vi++) { - for (int ui = 0; ui < face_txt->width; ui++) { - tex->getPixel(ptex_face_id, ui, vi, px, 0, nchan, res); - data[(vi*face_txt->width+ui)*4+0] = (unsigned char)(px[0]*255.0f); - data[(vi*face_txt->width+ui)*4+1] = (unsigned char)(px[1]*255.0f); - data[(vi*face_txt->width+ui)*4+2] = (unsigned char)(px[2]*255.0f); - } - } - } - else if (nchan == 1) /* displacement data */ - { - face_txt->format = Texture::FLOAT32; - face_txt->bytesPerTexel = 4; - float*data = new float[face_txt->width*face_txt->height]; - face_txt->data = data; - - for (int vi = 0; vi < face_txt->height; vi++) { - for (int ui = 0; ui < face_txt->width; ui++) { - tex->getPixel(ptex_face_id, ui, vi, px, 0, nchan, res); - if (!isfinite(px[0])) - px[0] = 0.0f; - data[vi*face_txt->width+ui] = px[0]; - } - } - } - ptex_face_id++; - } - else - ptex_face_id += 3; - } - std::cout << "done" << std::endl << std::flush; - return texture; -#else - return nullptr; -#endif - } - -} - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/texture_loader.h b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/texture_loader.h deleted file mode 100644 index 057dcba74bae..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/texture_loader.h +++ /dev/null @@ -1,62 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../../../common/sys/platform.h" -#include "../../../common/sys/filename.h" -#include "../../../common/sys/vector.h" -#include "../../../common/math/vec2.h" -#include "../../../common/math/vec3.h" -#include "../../../common/math/affinespace.h" -#include "scene.h" - -#include -#include - -namespace embree -{ - struct Texture { - - enum { - RGBA8 = 1, - RGB8 = 2, - FLOAT32 = 3, - PTEX_RGBA8 = 4, - PTEX_FLOAT32 = 5 - }; - - int width; - int height; - int format; - union { - int bytesPerTexel; - int faceTextures; - }; - int width_mask; - int height_mask; - - void *data; - - Texture() - : width(-1), height(-1), format(-1), bytesPerTexel(0), data(nullptr), width_mask(0), height_mask(0) {} - - }; - - /*! read texture from disk */ - Texture *loadTexture(const FileName& fileName); - Texture *loadPtexTexture(const FileName& fileName); -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/tutorial.h b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/tutorial.h deleted file mode 100644 index 1411c784c866..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/tutorial.h +++ /dev/null @@ -1,40 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../../../common/sys/platform.h" -#include "../../../common/sys/sysinfo.h" -#include "../../../common/sys/ref.h" -#include "../../../common/lexers/streamfilters.h" -#include "../../../common/lexers/parsestream.h" -#include "glutdisplay.h" -#include "../transport/transport_host.h" - -#include - -#if !defined(_MM_SET_DENORMALS_ZERO_MODE) -#define _MM_DENORMALS_ZERO_ON (0x0040) -#define _MM_DENORMALS_ZERO_OFF (0x0000) -#define _MM_DENORMALS_ZERO_MASK (0x0040) -#define _MM_SET_DENORMALS_ZERO_MODE(x) (_mm_setcsr((_mm_getcsr() & ~_MM_DENORMALS_ZERO_MASK) | (x))) -#endif - -#if defined __WIN32__ -inline double drand48() { - return (double)rand()/(double)RAND_MAX; -} -#endif diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/tutorial_device.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/tutorial_device.cpp deleted file mode 100644 index 24452168e6c9..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/tutorial_device.cpp +++ /dev/null @@ -1,767 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "tutorial_device.h" -#include "../../../kernels/algorithms/parallel_for.h" -#include "scene_device.h" - -/* the scene to render */ -extern RTCScene g_scene; - -/* global subdivision level for subdivision geometry */ -unsigned int g_subdivision_levels = 0; - -/* intensity scaling for traversal cost visualization */ -//float scale = 0.001f; -float scale = 1.0f / 1000000.0f; - -extern "C" bool g_changed = false; - -/* stores pointer to currently used rendePixel function */ -extern renderPixelFunc renderPixel; - -extern "C" float g_debug; - -/* standard rendering function for each tutorial */ -Vec3fa renderPixelStandard(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p); - -/* renders a single pixel with eyelight shading */ -Vec3fa renderPixelEyeLight(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p) -{ - /* initialize ray */ - RTCRay ray; - ray.org = p; - ray.dir = normalize(x*vx + y*vy + vz); - ray.tnear = 0.0f; - ray.tfar = inf; - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.primID = RTC_INVALID_GEOMETRY_ID; - ray.mask = -1; - ray.time = g_debug; - - /* intersect ray with scene */ - rtcIntersect(g_scene,ray); - - /* shade pixel */ - if (ray.geomID == RTC_INVALID_GEOMETRY_ID) return Vec3fa(0.0f); - else return Vec3fa(embree::abs(dot(ray.dir,normalize(ray.Ng)))); -} - -__noinline void setray(RTCRay& ray) -{ - ray.u = ray.v = 0.001f; - ray.Ng = Vec3fa(0,1,0); - ray.geomID = 0; - ray.primID = 0; -} - -/* renders a single pixel with wireframe shading */ -Vec3fa renderPixelWireframe(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p) -{ - /* initialize ray */ - RTCRay ray; - ray.org = p; - ray.dir = normalize(x*vx + y*vy + vz); - ray.tnear = 0.0f; - ray.tfar = inf; - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.primID = RTC_INVALID_GEOMETRY_ID; - ray.mask = -1; - ray.time = g_debug; - - /* intersect ray with scene */ - rtcIntersect(g_scene,ray); - - /* return black if nothing hit */ - if (ray.geomID == RTC_INVALID_GEOMETRY_ID) return Vec3fa(1.0f); - - /* calculate wireframe around triangles */ - const float border = 0.05f; - Vec3fa color = Vec3fa(1.0f); - if (ray.u < border) color = Vec3fa(0.0f); - if (ray.v < border) color = Vec3fa(0.0f); - if (1.0f-ray.u-ray.v < border) color = Vec3fa(0.0f); - - /* perform eyelight shading */ - return color*Vec3fa(embree::abs(dot(ray.dir,normalize(ray.Ng)))); -} - -/* renders a single pixel with UV shading */ -Vec3fa renderPixelUV(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p) -{ - /* initialize ray */ - RTCRay ray; - ray.org = p; - ray.dir = normalize(x*vx + y*vy + vz); - ray.tnear = 0.0f; - ray.tfar = inf; - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.primID = RTC_INVALID_GEOMETRY_ID; - ray.mask = -1; - ray.time = g_debug; - - /* intersect ray with scene */ - rtcIntersect(g_scene,ray); - - /* shade pixel */ - if (ray.geomID == RTC_INVALID_GEOMETRY_ID) return Vec3fa(0.0f); - else return Vec3fa(ray.u,ray.v,1.0f-ray.u-ray.v); -} - -/* renders a single pixel with geometry normal shading */ -Vec3fa renderPixelNg(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p) -{ - /* initialize ray */ - RTCRay ray; - ray.org = p; - ray.dir = normalize(x*vx + y*vy + vz); - ray.tnear = 0.0f; - ray.tfar = inf; - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.primID = RTC_INVALID_GEOMETRY_ID; - ray.mask = -1; - ray.time = g_debug; - - /* intersect ray with scene */ - rtcIntersect(g_scene,ray); - - /* shade pixel */ - if (ray.geomID == RTC_INVALID_GEOMETRY_ID) return Vec3fa(0.0f); - else { - //if (dot(ray.dir,ray.Ng) > 0.0f) return Vec3fa(zero); else - return abs(normalize(Vec3fa(ray.Ng.x,ray.Ng.y,ray.Ng.z))); - } -} - -Vec3fa randomColor(const int ID) -{ - int r = ((ID+13)*17*23) & 255; - int g = ((ID+15)*11*13) & 255; - int b = ((ID+17)* 7*19) & 255; - const float oneOver255f = 1.f/255.f; - return Vec3fa(r*oneOver255f,g*oneOver255f,b*oneOver255f); -} - -/* geometry ID shading */ -Vec3fa renderPixelGeomID(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p) -{ - /* initialize ray */ - RTCRay ray; - ray.org = p; - ray.dir = normalize(x*vx + y*vy + vz); - ray.tnear = 0.0f; - ray.tfar = inf; - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.primID = RTC_INVALID_GEOMETRY_ID; - ray.mask = -1; - ray.time = g_debug; - - /* intersect ray with scene */ - rtcIntersect(g_scene,ray); - - /* shade pixel */ - if (ray.geomID == RTC_INVALID_GEOMETRY_ID) return Vec3fa(0.0f); - else return randomColor(ray.geomID); -} - -/* geometry ID and primitive ID shading */ -Vec3fa renderPixelGeomIDPrimID(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p) -{ - /* initialize ray */ - RTCRay ray; - ray.org = p; - ray.dir = normalize(x*vx + y*vy + vz); - ray.tnear = 0.0f; - ray.tfar = inf; - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.primID = RTC_INVALID_GEOMETRY_ID; - ray.mask = -1; - ray.time = g_debug; - - /* intersect ray with scene */ - rtcIntersect(g_scene,ray); - - /* shade pixel */ - if (ray.geomID == RTC_INVALID_GEOMETRY_ID) return Vec3fa(0.0f); - else return randomColor(ray.geomID ^ ray.primID)*Vec3fa(embree::abs(dot(ray.dir,normalize(ray.Ng)))); -} - -/* vizualizes the traversal cost of a pixel */ -Vec3fa renderPixelCycles(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p) -{ - /* initialize ray */ - RTCRay ray; - ray.org = p; - ray.dir = normalize(x*vx + y*vy + vz); - ray.tnear = 0.0f; - ray.tfar = inf; - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.primID = RTC_INVALID_GEOMETRY_ID; - ray.mask = -1; - ray.time = g_debug; - - /* intersect ray with scene */ - int64_t c0 = get_tsc(); - rtcIntersect(g_scene,ray); - int64_t c1 = get_tsc(); - /* shade pixel */ - return Vec3fa((float)(c1-c0)*scale,0.0f,0.0f); -} - -/* renders a single pixel with UV shading */ -Vec3fa renderPixelUV16(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p) -{ - /* initialize ray */ - RTCRay ray; - ray.org = p; - ray.dir = normalize(x*vx + y*vy + vz); - ray.tnear = 0.0f; - ray.tfar = inf; - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.primID = RTC_INVALID_GEOMETRY_ID; - ray.mask = -1; - ray.time = g_debug; - - /* intersect ray with scene */ - for (int i=0; i<16; i++) { - ray.tfar = inf; - rtcIntersect(g_scene,ray); - } - - /* shade pixel */ - if (ray.geomID == RTC_INVALID_GEOMETRY_ID) return Vec3fa(0.0f); - else return Vec3fa(ray.u,ray.v,1.0f-ray.u-ray.v); -} - -/* renders a single pixel casting with ambient occlusion */ -Vec3fa renderPixelAmbientOcclusion(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p) -{ - /* initialize ray */ - RTCRay ray; - ray.org = p; - ray.dir = normalize(x*vx + y*vy + vz); - ray.tnear = 0.0f; - ray.tfar = inf; - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.primID = RTC_INVALID_GEOMETRY_ID; - ray.mask = -1; - ray.time = g_debug; - - /* intersect ray with scene */ - rtcIntersect(g_scene,ray); - - /* shade pixel */ - if (ray.geomID == RTC_INVALID_GEOMETRY_ID) return Vec3fa(0.0f); - - Vec3fa Ng = normalize(ray.Ng); - Vec3fa col = Vec3fa(min(1.f,.3f+.8f*abs(dot(Ng,normalize(ray.dir))))); - - /* calculate hit point */ - float intensity = 0; - Vec3fa hitPos = ray.org + ray.tfar * ray.dir; - -#define AMBIENT_OCCLUSION_SAMPLES 64 - /* trace some ambient occlusion rays */ - int seed = 34*x+12*y; - for (int i=0; i& r) { - for (size_t tid=r.begin(); tid= numTiles) break; - renderTile(i,pixels,width,height,time,vx,vy,vz,p,numTilesX,numTilesY); - } - } - }); - -#else - parallel_for(size_t(0),size_t(numTiles),[&] (const range& r) { - //if (inrender) PING; - //inrender = true; - for (size_t i=r.begin(); i& m) { - for (size_t i=m.begin(); iformat == PTEX_RGBA8) - { - assert(faceId < texture->faceTextures); - Texture **face_texture = (Texture **)texture->data; - return getTextureTexel3f(face_texture[faceId],u,v); - } - return zero; -} - -float getPtexTexel1f(void* _texture, const int faceId, const float u, const float v) -{ - Texture *texture = (Texture*)_texture; - if (texture->format == PTEX_FLOAT32) - { - assert(faceId < texture->faceTextures); - Texture **face_texture = (Texture **)texture->data; - return getTextureTexel1f(face_texture[faceId],u,v); - } - return 0.0f; -} - -Vec2f getTextureCoordinatesSubdivMesh(void* _mesh, const unsigned int primID, const float u, const float v) -{ - ISPCSubdivMesh *mesh = (ISPCSubdivMesh *)_mesh; - Vec2f st; - st.x = u; - st.y = v; - if (mesh && mesh->texcoord_indices && mesh->texcoords) - { - assert(primID < mesh->numFaces); - const size_t face_offset = mesh->face_offsets[primID]; - if (mesh->verticesPerFace[primID] == 3) - { - const size_t t0 = mesh->texcoord_indices[face_offset+0]; - const size_t t1 = mesh->texcoord_indices[face_offset+1]; - const size_t t2 = mesh->texcoord_indices[face_offset+2]; - const Vec2f &txt0 = mesh->texcoords[t0]; - const Vec2f &txt1 = mesh->texcoords[t1]; - const Vec2f &txt2 = mesh->texcoords[t2]; - const float w = 1.0f - u - v; - st = w * txt0 + u * txt1 + v * txt2; - } - else if (mesh->verticesPerFace[primID] == 4) - { - const size_t t0 = mesh->texcoord_indices[face_offset+0]; - const size_t t1 = mesh->texcoord_indices[face_offset+1]; - const size_t t2 = mesh->texcoord_indices[face_offset+2]; - const size_t t3 = mesh->texcoord_indices[face_offset+3]; - const Vec2f &txt0 = mesh->texcoords[t0]; - const Vec2f &txt1 = mesh->texcoords[t1]; - const Vec2f &txt2 = mesh->texcoords[t2]; - const Vec2f &txt3 = mesh->texcoords[t3]; - const float u0 = u; - const float v0 = v; - const float u1 = 1.0f - u; - const float v1 = 1.0f - v; - st = u1*v1 * txt0 + u0*v1* txt1 + u0*v0 * txt2 + u1*v0* txt3; - } -#if defined(_DEBUG) - else - PRINT("not supported"); -#endif - } - return st; -} - -float getTextureTexel1f(void *_texture, const float s, const float t) -{ - Texture *texture = (Texture*)_texture; - if (likely(texture && texture->format == FLOAT32)) - { - const float u = min(max(s,0.0f),1.0f); - const float v = min(max(t,0.0f),1.0f); - const int ui = min((int)floorf((texture->width-1)*u),texture->width-1); - const int vi = min((int)floorf((texture->height-1)*v),texture->height-1); - float *data = (float *)texture->data; - return data[vi*texture->width + ui]; - } - return 0.0f; -} - -Vec3f getTextureTexel3f(void *_texture,const float s, const float t) -{ - Texture *texture = (Texture*)_texture; - if (likely(texture && texture->format == RGBA8)) - { - //u = max(min(u,1.0f),0.0f); - //v = max(min(v,1.0f),0.0f); - - int iu = (int)(s * (float)(texture->width)); - if (texture->width_mask) - iu &= texture->width_mask; - else - iu = min(iu,texture->width-1); - int iv = (int)(t * (float)(texture->height)); - if (texture->height_mask) - iv &= texture->height_mask; - else - iv = min(iv,texture->height-1); - unsigned char *t = (unsigned char*)texture->data + (iv * texture->width + iu) * 4; //texture->bytesPerTexel; - return Vec3f( (float)t[0] * 1.0f/255.0f, (float)t[1] * 1.0f/255.0f, (float)t[2] * 1.0f/255.0f ); - } - return Vec3f(0.0f);; -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/tutorial_device.h b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/tutorial_device.h deleted file mode 100644 index e4fc2518c50d..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/tutorial_device.h +++ /dev/null @@ -1,132 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -/* size of screen tiles */ -#define TILE_SIZE_X 8 -#define TILE_SIZE_Y 8 - -/* vertex and triangle layout */ -#if !defined(__NO_VERTEX__) -struct Vertex { float x,y,z,r; }; -#endif -struct Triangle { int v0, v1, v2; }; - -#include "../../../include/embree2/rtcore.h" -#include "ray.h" - -//FIXME: -#include "texture_loader.h" -using namespace embree; - -/* returns time stamp counter */ -extern "C" int64_t get_tsc(); - -/* face forward for shading normals */ -__forceinline Vec3f faceforward( const Vec3f& N, const Vec3f& I, const Vec3f& Ng ) { - return dot(I, Ng) < 0 ? N : -N; -} - -/* glut keys codes */ -#define GLUT_KEY_F1 1 -#define GLUT_KEY_F2 2 -#define GLUT_KEY_F3 3 -#define GLUT_KEY_F4 4 -#define GLUT_KEY_F5 5 -#define GLUT_KEY_F6 6 -#define GLUT_KEY_F7 7 -#define GLUT_KEY_F8 8 -#define GLUT_KEY_F9 9 -#define GLUT_KEY_F10 10 -#define GLUT_KEY_F11 11 -#define GLUT_KEY_F12 12 - -enum Shader { - SHADER_DEFAULT = 0, - SHADER_EYELIGHT = 1, - SHADER_UV = 2, - SHADER_NG = 3, - SHADER_GEOMID = 4, - SHADER_GEOMID_PRIMID = 5 -}; - -/* standard shading function */ -typedef Vec3fa (* renderPixelFunc)(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p); - -extern "C" void device_key_pressed_default(int key); -extern "C" void (*key_pressed_handler)(int key); - -Vec3fa renderPixelStandard(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p); -Vec3fa renderPixelUV (float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p); -Vec3fa renderPixelGeomIDPrimID(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p); -Vec3fa renderPixelGeomID (float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p); -Vec3fa renderPixelCycles(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p); - -__forceinline Vec3f neg(const Vec3f& a ) { return -a; } -__forceinline Vec3fa neg(const Vec3fa& a) { return -a; } -__forceinline bool eq (const Vec3fa& a, const Vec3fa& b) { return a == b; } -__forceinline bool ne (const Vec3fa& a, const Vec3fa& b) { return a != b; } - -/* parallel invokation of renderTile function */ -void launch_renderTile (int numTiles, - int* pixels, const int width, const int height, const float time, - const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p, const int numTilesX, const int numTilesY); - -/* parallel invokation of animateSphere function */ -typedef void (*animateSphereFunc) (int taskIndex, Vertex* vertices, - const float rcpNumTheta, - const float rcpNumPhi, - const Vec3fa& pos, - const float r, - const float f); - -void launch_animateSphere(animateSphereFunc func, - int taskSize, - Vertex* vertices, - const float rcpNumTheta, - const float rcpNumPhi, - const Vec3fa& pos, - const float r, - const float f); - -struct Sample3f -{ - Sample3f () {} - - Sample3f (const Vec3fa& v, const float pdf) - : v(v), pdf(pdf) {} - - Vec3fa v; - float pdf; -}; - -/* noise functions */ -float noise(const Vec3fa& p); -Vec3fa noise3D(const Vec3fa& p); - -/* draws progress bar */ -void progressStart(); -bool progressMonitor(void* ptr, const double dn); -void progressEnd(); - -Vec2f getTextureCoordinatesSubdivMesh(void* mesh, const unsigned int primID, const float u, const float v); - -float getPtexTexel1f(void* ptex, const int faceId, const float u, const float v); -Vec3f getPtexTexel3f(void* ptex, const int faceId, const float u, const float v); - -float getTextureTexel1f(void *texture,const float u, const float v); -Vec3f getTextureTexel3f(void *texture,const float u, const float v); diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/xml_loader.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/xml_loader.cpp deleted file mode 100644 index 1d3377e79728..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/xml_loader.cpp +++ /dev/null @@ -1,938 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "xml_loader.h" -#include "xml_parser.h" -#include "scene.h" -#include "../../../common/math/affinespace.h" -#include "../../../common/math/vec2.h" -#include "../../../common/math/vec3.h" -#include "../../../common/math/vec4.h" -#include - -namespace embree -{ - struct Variant - { - ALIGNED_CLASS - public: - - /*! Determines which kind of value is stored in the variant. */ - enum Type { - EMPTY, /*!< variant is empty */ - BOOL1, /*!< variant stores bool value */ - BOOL2, /*!< variant stores bool2 value */ - BOOL3, /*!< variant stores bool3 value */ - BOOL4, /*!< variant stores bool4 value */ - INT1, /*!< variant stores int value */ - INT2, /*!< variant stores int2 value */ - INT3, /*!< variant stores int3 value */ - INT4, /*!< variant stores int4 value */ - FLOAT1, /*!< variant stores float value */ - FLOAT2, /*!< variant stores float2 value */ - FLOAT3, /*!< variant stores float3 value */ - FLOAT4, /*!< variant stores float4 value */ - STRING, /*!< variant stores string value */ - }; - - /*! Constructs an empty variant object. */ - Variant ( ) : type(EMPTY) { } - - /*! Constructs a variant object holding a bool value. */ - Variant (bool b0 ) : type(BOOL1) { b[0] = b0; } - - /*! Constructs a variant object holding a bool2 value. */ - Variant (bool b0, bool b1 ) : type(BOOL2) { b[0] = b0; b[1] = b1; } - - /*! Constructs a variant object holding a bool3 value. */ - Variant (bool b0, bool b1, bool b2 ) : type(BOOL3) { b[0] = b0; b[1] = b1; b[2] = b2; } - - /*! Constructs a variant object holding a bool4 value. */ - Variant (bool b0, bool b1, bool b2, bool b3) : type(BOOL4) { b[0] = b0; b[1] = b1; b[2] = b2; b[3] = b3; } - - /*! Constructs a variant object holding an int value. */ - Variant (int i0) : type(INT1) { i[0] = i0; } - - /*! Constructs a variant object holding an int2 value. */ - Variant (Vec2i v) : type(INT2) { i[0] = v.x; i[1] = v.y; } - - /*! Constructs a variant object holding an int3 value. */ - Variant (Vec3i v) : type(INT3) { i[0] = v.x; i[1] = v.y; i[2] = v.z; } - - /*! Constructs a variant object holding an int4 value. */ - Variant (Vec4i v) : type(INT4) { i[0] = v.x; i[1] = v.y; i[2] = v.z; i[3] = v.w; } - - /*! Constructs a variant object holding a float value. */ - Variant (float f0) : type(FLOAT1) { f[0] = f0; } - - /*! Constructs a variant object holding a float2 value. */ - Variant (Vec2f v) : type(FLOAT2) { f[0] = v.x; f[1] = v.y; } - - /*! Constructs a variant object holding a float3 value. */ - Variant (Vec3f v) : type(FLOAT3) { f[0] = v.x; f[1] = v.y; f[2] = v.z; } - - /*! Constructs a variant object holding a float4 value. */ - Variant (Vec4f v) : type(FLOAT4) { f[0] = v.x; f[1] = v.y; f[2] = v.z; f[3] = v.w; } - - /*! Constructs a variant object holding a string value. */ - Variant (const char* str) : type(STRING), str(str) {} - - /*! Constructs a variant object holding a string value. */ - Variant (const std::string& str) : type(STRING), str(str) {} - - /*! Extracts a boolean from the variant type. */ - bool getBool () const { return b[0]; } - - /*! Extracts an integer from the variant type. */ - int getInt () const { return i[0]; } - - /*! Extracts a float from the variant type. */ - float getFloat() const { return f[0]; } - - /*! Extracts a Vec2f from the variant type. */ - Vec2f getVec2f() const { return Vec2f(f[0],f[1]); } - - /*! Extracts a Vec3f from the variant type. */ - Vec3f getVec3f() const { return Vec3f(f[0],f[1],f[2]); } - - /*! Extracts a Vec3fa from the variant type. */ - Vec3f getVec3fa() const { return Vec3fa(f[0],f[1],f[2]); } - - /*! Extracts a string from the variant type. */ - std::string getString() const { return str; } - - operator bool() const { - return type != EMPTY; - } - - public: - Type type; //!< Type of the data contained in the variant. - union { - bool b[4]; //!< Storage for single bool,bool2,bool3, and bool4 values. - int i[4]; //!< Storage for single int,int2,int3, and int4 values. - float f[12]; //!< Storage for single float,float2,float3, float4, and AffineSpace3f values. - }; - std::string str; //!< Storage for string values. - }; - - /*! Parameter container. Implements parameter container as a mapping - * from a string to variant values. This container is used to pass - * parameters for constructing objects from the API to the - * constructors of that objects. All the extraction functions - * return a default values in case the parameter is not found. */ - class Parms - { - public: - - /*! clears the parameter container */ - void clear() { - m.clear(); - } - - /*! Extracts a named boolean out of the container. */ - bool getBool(const char* name, bool def = false) const { - std::map::const_iterator i = m.find(name); - if (i == m.end() || (*i).second.type != Variant::BOOL1) return def; - return (*i).second.getBool(); - } - - /*! Extracts a named integer out of the container. */ - int getInt(const char* name, int def = zero) const { - std::map::const_iterator i = m.find(name); - if (i == m.end() || (*i).second.type != Variant::INT1) return def; - return (*i).second.getInt(); - } - - /*! Extracts a named float out of the container. */ - float getFloat(const char* name, float def = zero) const { - std::map::const_iterator i = m.find(name); - if (i == m.end() || (*i).second.type != Variant::FLOAT1) return def; - return (*i).second.getFloat(); - } - - /*! Extracts a named Vec2f out of the container. */ - Vec2f getVec2f(const char* name, const Vec2f& def = zero) const { - std::map::const_iterator i = m.find(name); - if (i == m.end() || (*i).second.type != Variant::FLOAT2) return def; - return (*i).second.getVec2f(); - } - - /*! Extracts a named Vec3f out of the container. */ - Vec3f getVec3f(const char* name, const Vec3f& def = zero) const { - std::map::const_iterator i = m.find(name); - if (i == m.end() || (*i).second.type != Variant::FLOAT3) return def; - return (*i).second.getVec3f(); - } - - /*! Extracts a named Vec3f out of the container. */ - Vec3fa getVec3fa(const char* name, const Vec3fa& def = zero) const { - std::map::const_iterator i = m.find(name); - if (i == m.end() || (*i).second.type != Variant::FLOAT3) return def; - return (*i).second.getVec3fa(); - } - - /*! Extracts a named string out of the container. */ - std::string getString(const char* name, std::string def = "") const { - std::map::const_iterator i = m.find(name); - if (i == m.end() || (*i).second.type != Variant::STRING) return def; - return (*i).second.getString(); - } - - /*! Adds a new named element to the container. */ - void add(const std::string& name, Variant data) { - m[name] = data; - } - - private: - - /*! Implementation of the container as an STL map. */ - std::map m; - }; - - class XMLLoader - { - public: - - static Ref load(const FileName& fileName, const AffineSpace3fa& space); - XMLLoader(const FileName& fileName, const AffineSpace3fa& space); - ~XMLLoader(); - - public: - Parms loadMaterialParms(const Ref& parms); - Ref addMaterial(const std::string& type, const Parms& parms); - - public: - Ref loadPointLight(const Ref& xml); - Ref loadSpotLight(const Ref& xml); - Ref loadDirectionalLight(const Ref& xml); - Ref loadDistantLight(const Ref& xml); - Ref loadAmbientLight(const Ref& xml); - Ref loadTriangleLight(const Ref& xml); - Ref loadQuadLight(const Ref& xml); - Ref loadHDRILight(const Ref& xml); - - Ref loadTriangleMesh(const Ref& xml); - Ref loadSubdivMesh(const Ref& xml); - - private: - Ref loadMaterial(const Ref& xml); - Ref loadTransformNode(const Ref& xml); - Ref loadGroupNode(const Ref& xml); - Ref loadNode(const Ref& xml); - - private: - Ref loadBGFMaterial(const Ref& xml); - Ref loadBGFTransformNode(const Ref& xml); - Ref loadBGFGroupNode(const Ref& xml); - Ref loadBGFNode(const Ref& xml); - - private: - template T load(const Ref& xml) { assert(false); return T(zero); } - template T load(const Ref& xml, const T& opt) { assert(false); return T(zero); } - char* loadBinary(const Ref& xml, size_t eltSize, size_t& size); - - std::vector loadFloatArray(const Ref& xml); - std::vector loadVec2fArray(const Ref& xml); - std::vector loadVec3fArray(const Ref& xml); - std::vector loadIntArray(const Ref& xml); - std::vector loadVec2iArray(const Ref& xml); - std::vector loadVec3iArray(const Ref& xml); - - private: - FileName path; //!< path to XML file - FILE* binFile; //!< .bin file for reading binary data - FileName binFileName; //!< name of the .bin file - - private: - std::map > materialMap; //!< named materials - std::map, Ref > materialCache; //!< map for detecting repeated materials - std::map > sceneMap; - std::map > id2node; - std::map > id2material; - - public: - Ref root; - }; - - ////////////////////////////////////////////////////////////////////////////// - //// Loading standard types from an XML node - ////////////////////////////////////////////////////////////////////////////// - - template<> std::string XMLLoader::load(const Ref& xml) { - if (xml->body.size() < 1) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong string body"); - return xml->body[0].String(); - } - - template<> bool XMLLoader::load(const Ref& xml, const bool& opt) { - if (xml == null) return opt; - if (xml->body.size() != 1) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong bool body"); - return xml->body[0].Int() != 0; - } - - template<> int XMLLoader::load(const Ref& xml) { - if (xml->body.size() != 1) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong int body"); - return xml->body[0].Int(); - } - - template<> Vec2i XMLLoader::load(const Ref& xml) { - if (xml->body.size() != 2) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong int2 body"); - return Vec2i(xml->body[0].Int(),xml->body[1].Int()); - } - - template<> Vec3i XMLLoader::load(const Ref& xml) { - if (xml->body.size() != 3) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong int3 body"); - return Vec3i(xml->body[0].Int(),xml->body[1].Int(),xml->body[2].Int()); - } - - template<> Vec4i XMLLoader::load(const Ref& xml) { - if (xml->body.size() != 4) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong int4 body"); - return Vec4i(xml->body[0].Int(),xml->body[1].Int(),xml->body[2].Int(),xml->body[3].Int()); - } - - template<> float XMLLoader::load(const Ref& xml) { - if (xml->body.size() != 1) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong float body"); - return xml->body[0].Float(); - } - - template<> float XMLLoader::load(const Ref& xml, const float& opt) { - if (xml == null) return opt; - if (xml->body.size() != 1) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong float body"); - return xml->body[0].Float(); - } - - template<> Vec2f XMLLoader::load(const Ref& xml) { - if (xml->body.size() != 2) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong float2 body"); - return Vec2f(xml->body[0].Float(),xml->body[1].Float()); - } - - template<> Vec3f XMLLoader::load(const Ref& xml) { - if (xml->body.size() != 3) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong float3 body"); - return Vec3f(xml->body[0].Float(),xml->body[1].Float(),xml->body[2].Float()); - } - - template<> Vec3fa XMLLoader::load(const Ref& xml) { - if (xml->body.size() != 3) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong float3 body"); - return Vec3fa(xml->body[0].Float(),xml->body[1].Float(),xml->body[2].Float()); - } - - template<> Vec3fa XMLLoader::load(const Ref& xml, const Vec3fa& opt) { - if (xml == null) return opt; - if (xml->body.size() != 3) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong float3 body"); - return Vec3fa(xml->body[0].Float(),xml->body[1].Float(),xml->body[2].Float()); - } - - template<> Vec4f XMLLoader::load(const Ref& xml) { - if (xml->body.size() != 4) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong float4 body"); - return Vec4f(xml->body[0].Float(),xml->body[1].Float(),xml->body[2].Float(),xml->body[3].Float()); - } - - template<> AffineSpace3fa XMLLoader::load(const Ref& xml) - { - if (xml->parm("translate") != "") { - float x,y,z; sscanf(xml->parm("translate").c_str(),"%f %f %f",&x,&y,&z); - return AffineSpace3fa::translate(Vec3f(x,y,z)); - } else if (xml->parm("scale") != "") { - float x,y,z; sscanf(xml->parm("scale").c_str(),"%f %f %f",&x,&y,&z); - return AffineSpace3fa::scale(Vec3f(x,y,z)); - } else if (xml->parm("rotate_x") != "") { - float degrees; sscanf(xml->parm("rotate_x").c_str(),"%f",°rees); - return AffineSpace3fa::rotate(Vec3f(1,0,0),deg2rad(degrees)); - } else if (xml->parm("rotate_y") != "") { - float degrees; sscanf(xml->parm("rotate_y").c_str(),"%f",°rees); - return AffineSpace3fa::rotate(Vec3f(0,1,0),deg2rad(degrees)); - } else if (xml->parm("rotate_z") != "") { - float degrees; sscanf(xml->parm("rotate_z").c_str(),"%f",°rees); - return AffineSpace3fa::rotate(Vec3f(0,0,1),deg2rad(degrees)); - } else if (xml->parm("rotate") != "" && xml->parm("axis") != "") { - float degrees; sscanf(xml->parm("rotate").c_str(),"%f",°rees); - float x,y,z; sscanf(xml->parm("axis").c_str(),"%f %f %f",&x,&y,&z); - return AffineSpace3fa::rotate(Vec3f(x,y,z),deg2rad(degrees)); - } else { - if (xml->body.size() != 12) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong AffineSpace body"); - return AffineSpace3fa(LinearSpace3fa(xml->body[0].Float(),xml->body[1].Float(),xml->body[ 2].Float(), - xml->body[4].Float(),xml->body[5].Float(),xml->body[ 6].Float(), - xml->body[8].Float(),xml->body[9].Float(),xml->body[10].Float()), - Vec3fa(xml->body[3].Float(),xml->body[7].Float(),xml->body[11].Float())); - } - } - - char* XMLLoader::loadBinary(const Ref& xml, size_t eltSize, size_t& size) - { - if (!binFile) - THROW_RUNTIME_ERROR("cannot open file "+binFileName.str()+" for reading"); - - size_t ofs = atol(xml->parm("ofs").c_str()); - fseek(binFile,long(ofs),SEEK_SET); - - size = atol(xml->parm("size").c_str()); - char* data = (char*) alignedMalloc(size*eltSize); - - if (size != fread(data, eltSize, size, binFile)) - THROW_RUNTIME_ERROR("error reading from binary file: "+binFileName.str()); - - return data; - } - - std::vector XMLLoader::loadFloatArray(const Ref& xml) - { - /*! do not fail of array does not exist */ - if (!xml) { return std::vector(); } - - size_t size = 0; - float* data = nullptr; - if (xml->parm("ofs") != "") { - data = (float*)loadBinary(xml,sizeof(float),size); - } else { - size_t elts = xml->body.size(); - size = elts; - data = (float*) alignedMalloc(size*sizeof(float)); - for (size_t i=0; ibody[i].Float(); - } - std::vector res; - for (size_t i=0; i XMLLoader::loadVec2fArray(const Ref& xml) - { - /*! do not fail of array does not exist */ - if (!xml) { return std::vector(); } - - size_t size = 0; - Vec2f* data = nullptr; - if (xml->parm("ofs") != "") { - data = (Vec2f*)loadBinary(xml,2*sizeof(float),size); - } else { - size_t elts = xml->body.size(); - if (elts % 2 != 0) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong vector body"); - size = elts/2; - data = (Vec2f*) alignedMalloc(size*sizeof(Vec2f)); - for (size_t i=0; ibody[2*i+0].Float(),xml->body[2*i+1].Float()); - } - std::vector res; - for (size_t i=0; i XMLLoader::loadVec3fArray(const Ref& xml) - { - /*! do not fail of array does not exist */ - if (!xml) { return std::vector(); } - - size_t size = 0; - Vec3f* data = nullptr; - if (xml->parm("ofs") != "") { - data = (Vec3f*) loadBinary(xml,3*sizeof(float),size); - } - else { - size_t elts = xml->body.size(); - if (elts % 3 != 0) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong vector body"); - size = elts/3; - data = (Vec3f*) alignedMalloc(size*sizeof(Vec3f)); - for (size_t i=0; ibody[3*i+0].Float(),xml->body[3*i+1].Float(),xml->body[3*i+2].Float()); - } - std::vector res; - for (size_t i=0; i XMLLoader::loadIntArray(const Ref& xml) - { - /*! do not fail of array does not exist */ - if (!xml) { return std::vector(); } - - size_t size = 0; - int* data = nullptr; - if (xml->parm("ofs") != "") { - data = (int*)loadBinary(xml,sizeof(int),size); - } else { - size_t elts = xml->body.size(); - size = elts; - data = (int*) alignedMalloc(size*sizeof(int)); - for (size_t i=0; ibody[i].Int(); - } - std::vector res; - for (size_t i=0; i XMLLoader::loadVec2iArray(const Ref& xml) - { - /*! do not fail of array does not exist */ - if (!xml) { return std::vector(); } - - size_t size = 0; - Vec2i* data = nullptr; - if (xml->parm("ofs") != "") { - data = (Vec2i*) loadBinary(xml,2*sizeof(int),size); - } - else { - size_t elts = xml->body.size(); - if (elts % 2 != 0) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong vector body"); - size = elts/2; - data = (Vec2i*) alignedMalloc(size*sizeof(Vec2i)); - for (size_t i=0; ibody[2*i+0].Int(),xml->body[2*i+1].Int()); - } - std::vector res; - for (size_t i=0; i XMLLoader::loadVec3iArray(const Ref& xml) - { - /*! do not fail of array does not exist */ - if (!xml) { return std::vector(); } - - size_t size = 0; - Vec3i* data = nullptr; - if (xml->parm("ofs") != "") { - data = (Vec3i*) loadBinary(xml,3*sizeof(int),size); - } - else { - size_t elts = xml->body.size(); - if (elts % 3 != 0) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong vector body"); - size = elts/3; - data = (Vec3i*) alignedMalloc(size*sizeof(Vec3i)); - for (size_t i=0; ibody[3*i+0].Int(),xml->body[3*i+1].Int(),xml->body[3*i+2].Int()); - } - std::vector res; - for (size_t i=0; i XMLLoader::loadPointLight(const Ref& xml) - { - const AffineSpace3fa space = load(xml->child("AffineSpace")); - const Vec3fa I = load(xml->child("I")); - const Vec3fa P = Vec3fa(zero); - return new SceneGraph::TransformNode(space, new SceneGraph::LightNode(PointLight(P,I))); - } - - Ref XMLLoader::loadSpotLight(const Ref& xml) - { - const AffineSpace3fa space = load(xml->child("AffineSpace")); - const Vec3fa I = load(xml->child("I")); - const Vec3fa P = Vec3fa(zero); - const Vec3fa D = Vec3fa(0,0,1); - const float angleMin = load(xml->child("angleMin")); - const float angleMax = load(xml->child("angleMax")); - return new SceneGraph::TransformNode(space, new SceneGraph::LightNode(SpotLight(P,D,I,angleMin,angleMax))); - } - - Ref XMLLoader::loadDirectionalLight(const Ref& xml) - { - const AffineSpace3fa space = load(xml->child("AffineSpace")); - const Vec3fa E = load(xml->child("E")); - const Vec3fa D = Vec3fa(0,0,1); - return new SceneGraph::TransformNode(space, new SceneGraph::LightNode(DirectionalLight(D,E))); - } - - Ref XMLLoader::loadDistantLight(const Ref& xml) - { - const AffineSpace3fa space = load(xml->child("AffineSpace")); - const Vec3fa L = load(xml->child("L")); - const Vec3fa D = Vec3fa(0,0,1); - const float halfAngle = load(xml->child("halfAngle")); - return new SceneGraph::TransformNode(space, new SceneGraph::LightNode(DistantLight(D,L,halfAngle))); - } - - Ref XMLLoader::loadAmbientLight(const Ref& xml) - { - const Vec3fa L = load(xml->child("L")); - return new SceneGraph::LightNode(AmbientLight(L)); - } - - Ref XMLLoader::loadTriangleLight(const Ref& xml) - { - const AffineSpace3fa space = load(xml->child("AffineSpace")); - const Vec3fa L = load(xml->child("L")); - const Vec3fa v0 = xfmPoint(space, Vec3fa(1, 0, 0)); - const Vec3fa v1 = xfmPoint(space, Vec3fa(0, 1, 0)); - const Vec3fa v2 = xfmPoint(space, Vec3fa(0, 0, 0)); - return new SceneGraph::LightNode(TriangleLight(v0,v1,v2,L)); - } - - Ref XMLLoader::loadQuadLight(const Ref& xml) - { - const AffineSpace3fa space = load(xml->child("AffineSpace")); - const Vec3fa L = load(xml->child("L")); - const Vec3fa v0 = xfmPoint(space, Vec3fa(0, 0, 0)); - const Vec3fa v1 = xfmPoint(space, Vec3fa(0, 1, 0)); - const Vec3fa v2 = xfmPoint(space, Vec3fa(1, 1, 0)); - const Vec3fa v3 = xfmPoint(space, Vec3fa(1, 0, 0)); - return new SceneGraph::LightNode(QuadLight(v0,v1,v2,v3,L)); - } - - Ref XMLLoader::loadHDRILight(const Ref& xml) - { - AffineSpace3fa space = load(xml->child("AffineSpace")); - Vec3fa L = load(xml->child("L")); - //image = rtLoadImage(path + load(xml->child("image")))); - std::cout << "Warning: ignoring HDRILight" << std::endl; // FIXME: HDRI light not yet supported - return new SceneGraph::GroupNode(0); - } - - Parms XMLLoader::loadMaterialParms(const Ref& parms) - { - Parms material; - for (size_t i=0; ichildren.size(); i++) - { - Ref entry = parms->children[i]; - std::string name = entry->parm("name"); - if (entry->name == "int" ) { material.add(name, load (entry)); } - else if (entry->name == "int2" ) { material.add(name, load(entry)); } - else if (entry->name == "int3" ) { material.add(name, load(entry)); } - else if (entry->name == "int4" ) { material.add(name, load(entry)); } - else if (entry->name == "float" ) { material.add(name, load(entry)); } - else if (entry->name == "float2" ) { material.add(name, load(entry)); } - else if (entry->name == "float3" ) { material.add(name, load(entry)); } - else if (entry->name == "float4" ) { material.add(name, load(entry)); } - else if (entry->name == "texture") { material.add(name, (path + load(entry)).str()); } - else if (entry->name == "param") { - const std::string type = entry->parm("type"); - if (type == "int" ) { material.add(name, load (entry)); } - else if (type == "int2" ) { material.add(name, load(entry)); } - else if (type == "int3" ) { material.add(name, load(entry)); } - else if (type == "int4" ) { material.add(name, load(entry)); } - else if (type == "float" ) { material.add(name, load(entry)); } - else if (type == "float2" ) { material.add(name, load(entry)); } - else if (type == "float3" ) { material.add(name, load(entry)); } - else if (type == "float4" ) { material.add(name, load(entry)); } - else THROW_RUNTIME_ERROR(entry->loc.str()+": invalid param type: "+type); - } - else if (entry->name == "textures") { - // we do not parse textures for now - } - else THROW_RUNTIME_ERROR(entry->loc.str()+": invalid type: "+entry->name); - } - return material; - } - - Ref XMLLoader::loadMaterial(const Ref& xml) - { - if (xml->parm("id") != "") { - return materialMap[xml->parm("id")]; - } - - Ref parameters = xml->child("parameters"); - if (materialCache.find(parameters) != materialCache.end()) { - return materialCache[parameters]; - } - - std::string type = load(xml->child("code")).c_str(); - Parms parms = loadMaterialParms(parameters); - Ref material = addMaterial(type,parms); - materialCache[parameters] = material; - return material; - } - - Ref XMLLoader::addMaterial(const std::string& type, const Parms& parms) - { - Material material; - if (type == "Matte") - { - const Vec3fa reflectance = parms.getVec3fa("reflectance",one); - new (&material) MatteMaterial(reflectance); - } - else if (type == "Mirror") - { - const Vec3fa reflectance = parms.getVec3fa("reflectance",one); - new (&material) MirrorMaterial(reflectance); - } - else if (type == "OBJ") - { - //map_d = parms.getTexture("map_d"); - const float d = parms.getFloat("d", 1.0f); - //map_Kd = parms.getTexture("map_Kd"); - const Vec3fa Kd = parms.getVec3fa("Kd", one); - //map_Ks = parms.getTexture("map_Ks"); - const Vec3fa Ks = parms.getVec3fa("Ks", zero); - //map_Ns = parms.getTexture("map_Ns"); - const float Ns = parms.getFloat("Ns", 10.0f); - //map_Bump = parms.getTexture("map_Bump"); - new (&material) OBJMaterial(d,Kd,Ks,Ns); - } - else if (type == "ThinDielectric" || type == "ThinGlass") - { - const Vec3fa transmission = parms.getVec3fa("transmission",one); - const float eta = parms.getFloat("eta",1.4f); - const float thickness = parms.getFloat("thickness",0.1f); - new (&material) ThinDielectricMaterial(transmission,eta,thickness); - } - else if (type == "Plastic") - { - const Vec3fa pigmentColor = parms.getVec3fa("pigmentColor",one); - const float eta = parms.getFloat("eta",1.4f); - const float roughness = parms.getFloat("roughness",0.01f); - new (&material) MetallicPaintMaterial(pigmentColor,pigmentColor,roughness,eta); - } - else if (type == "Metal") - { - const Vec3fa reflectance = parms.getVec3fa("reflectance",one); - const Vec3fa eta = parms.getVec3fa("eta",Vec3fa(1.4f)); - const Vec3fa k = parms.getVec3fa("k",Vec3fa(0.0f)); - const float roughness = parms.getFloat("roughness",0.01f); - if (roughness == 0.0f) - new (&material) MetalMaterial(reflectance,eta,k); - else - new (&material) MetalMaterial(reflectance,eta,k,roughness); - } - else if (type == "Velvet") - { - const Vec3fa reflectance = parms.getVec3fa("reflectance",one); - const float backScattering = parms.getFloat("backScattering",zero); - const Vec3fa horizonScatteringColor = parms.getVec3fa("horizonScatteringColor",one); - const float horizonScatteringFallOff = parms.getFloat("horizonScatteringFallOff",zero); - new (&material) VelvetMaterial(reflectance,backScattering,horizonScatteringColor,horizonScatteringFallOff); - } - else if (type == "Dielectric") - { - const Vec3fa transmissionOutside = parms.getVec3fa("transmissionOutside",one); - const Vec3fa transmissionInside = parms.getVec3fa("transmission",one); - const float etaOutside = parms.getFloat("etaOutside",1.0f); - const float etaInside = parms.getFloat("etaInside",1.4f); - new (&material) DielectricMaterial(transmissionOutside,transmissionInside,etaOutside,etaInside); - } - else if (type == "MetallicPaint") - { - const Vec3fa shadeColor = parms.getVec3fa("shadeColor",one); - const Vec3fa glitterColor = parms.getVec3fa("glitterColor",zero); - const float glitterSpread = parms.getFloat("glitterSpread",1.0f); - const float eta = parms.getFloat("eta",1.4f); - new (&material) MetallicPaintMaterial(shadeColor,glitterColor,glitterSpread,eta); - } - else { - std::cout << "Warning: unsupported material " << type << std::endl; - new (&material) OBJMaterial(1.0f,Vec3fa(0.5f),Vec3fa(0.0f),0.0f); - } - return new SceneGraph::MaterialNode(material); - } - - Ref XMLLoader::loadSubdivMesh(const Ref& xml) - { - Ref material = loadMaterial(xml->child("material")); - - SceneGraph::SubdivMeshNode* mesh = new SceneGraph::SubdivMeshNode(material); - std::vector positions = loadVec3fArray(xml->childOpt("positions")); - for (size_t i=0; ipositions.push_back(positions[i]); - std::vector normals = loadVec3fArray(xml->childOpt("normals")); - for (size_t i=0; inormals.push_back(normals[i]); - mesh->texcoords = loadVec2fArray(xml->childOpt("texcoords")); - mesh->position_indices = loadIntArray(xml->childOpt("position_indices")); - mesh->normal_indices = loadIntArray(xml->childOpt("normal_indices")); - mesh->texcoord_indices = loadIntArray(xml->childOpt("texcoord_indices")); - mesh->verticesPerFace = loadIntArray(xml->childOpt("faces")); - mesh->holes = loadIntArray(xml->childOpt("holes")); - mesh->edge_creases = loadVec2iArray(xml->childOpt("edge_creases")); - mesh->edge_crease_weights = loadFloatArray(xml->childOpt("edge_crease_weights")); - mesh->vertex_creases = loadIntArray(xml->childOpt("vertex_creases")); - mesh->vertex_crease_weights = loadFloatArray(xml->childOpt("vertex_crease_weights")); - return mesh; - } - - Ref XMLLoader::loadTriangleMesh(const Ref& xml) - { - Ref material = loadMaterial(xml->child("material")); - std::vector positions = loadVec3fArray(xml->childOpt("positions")); - std::vector motions = loadVec3fArray(xml->childOpt("motions" )); - std::vector normals = loadVec3fArray(xml->childOpt("normals" )); - std::vector texcoords = loadVec2fArray(xml->childOpt("texcoords")); - std::vector triangles = loadVec3iArray(xml->childOpt("triangles")); - - SceneGraph::TriangleMeshNode* mesh = new SceneGraph::TriangleMeshNode(material); - for (size_t i=0; iv.push_back(positions[i]); - for (size_t i=0; ivn.push_back(normals[i]); - for (size_t i=0; ivt.push_back(texcoords[i]); - for (size_t i=0; itriangles.push_back(SceneGraph::TriangleMeshNode::Triangle(triangles[i].x,triangles[i].y,triangles[i].z)); - return mesh; - } - - Ref XMLLoader::loadTransformNode(const Ref& xml) - { - AffineSpace3fa space = load(xml->children[0]); - Ref group = new SceneGraph::GroupNode; - for (size_t i=1; ichildren.size(); i++) { - group->add(loadNode(xml->children[i])); - } - return new SceneGraph::TransformNode(space,group.cast()); - } - - Ref XMLLoader::loadGroupNode(const Ref& xml) - { - Ref group = new SceneGraph::GroupNode; - for (size_t i=0; ichildren.size(); i++) - group->add(loadNode(xml->children[i])); - return group.cast(); - } - - Ref XMLLoader::loadNode(const Ref& xml) - { - if (xml->name == "assign") - { - if (xml->parm("type") == "material") - { - Ref material = loadMaterial(xml->child(0)); - materialMap[xml->parm("id")] = material; - return material.cast(); - } - else if (xml->parm("type") == "scene") - return sceneMap[xml->parm("id")] = loadNode(xml->child(0)); - else - THROW_RUNTIME_ERROR(xml->loc.str()+": unknown type: "+xml->parm("type")); - } - else - { - if (xml->name == "xml") { - return XMLLoader::load(path + xml->parm("src"),one); - } - else if (xml->name == "extern") { - FileName fname = path + xml->parm("src"); - if (fname.ext() == "xml") return XMLLoader::load(path + xml->parm("src"),one); - else THROW_RUNTIME_ERROR("unknown file type:" + fname.str()); - } - else if (xml->name == "ref" ) return sceneMap[xml->parm("id")]; - - else if (xml->name == "PointLight" ) return loadPointLight (xml); - else if (xml->name == "SpotLight" ) return loadSpotLight (xml); - else if (xml->name == "DirectionalLight") return loadDirectionalLight(xml); - else if (xml->name == "DistantLight" ) return loadDistantLight (xml); - else if (xml->name == "AmbientLight" ) return loadAmbientLight (xml); - else if (xml->name == "TriangleLight" ) return loadTriangleLight (xml); - else if (xml->name == "QuadLight" ) return loadQuadLight (xml); - else if (xml->name == "HDRILight" ) return loadHDRILight (xml); - - else if (xml->name == "TriangleMesh" ) return loadTriangleMesh (xml); - else if (xml->name == "SubdivisionMesh" ) return loadSubdivMesh (xml); - else if (xml->name == "Group" ) return loadGroupNode (xml); - else if (xml->name == "Transform" ) return loadTransformNode (xml); - - else THROW_RUNTIME_ERROR(xml->loc.str()+": unknown tag: "+xml->name); - } - - return nullptr; - } - - /*******************************************************************************************/ - - Ref XMLLoader::loadBGFMaterial(const Ref& xml) - { - std::string type = xml->parm("type"); - std::string name = xml->parm("name"); - Parms parms = loadMaterialParms(xml); - return addMaterial(type,parms); - } - - Ref XMLLoader::loadBGFTransformNode(const Ref& xml) - { - const size_t child = stoi(xml->parm("child")); - const AffineSpace3fa space = load(xml); - return new SceneGraph::TransformNode(space,id2node[child]); - } - - Ref XMLLoader::loadBGFGroupNode(const Ref& xml) - { - const size_t N = stoi(xml->parm("numChildren")); - if (xml->body.size() != N) - THROW_RUNTIME_ERROR(xml->loc.str()+": invalid group node"); - - Ref group = new SceneGraph::GroupNode(N); - for (size_t i=0; ichildren.size(); i++) - group->set(i,id2node[xml->body[i].Int()]); - return group.cast(); - } - - Ref XMLLoader::loadBGFNode(const Ref& xml) - { - const size_t id = stoi(xml->parm("id")); - if (xml->name == "TriangleMesh") return id2node[id] = loadTriangleMesh(xml); - else if (xml->name == "Group" ) return id2node[id] = loadBGFGroupNode(xml); - else if (xml->name == "Transform" ) return id2node[id] = loadBGFTransformNode(xml); - else if (xml->name == "Material" ) - { - Ref material = loadBGFMaterial(xml); - id2material[id] = material; - return material.cast(); - } - else THROW_RUNTIME_ERROR(xml->loc.str()+": unknown tag: "+xml->name); - } - - /*******************************************************************************************/ - - - Ref XMLLoader::load(const FileName& fileName, const AffineSpace3fa& space) { - XMLLoader loader(fileName,space); return loader.root; - } - - XMLLoader::XMLLoader(const FileName& fileName, const AffineSpace3fa& space) : binFile(nullptr) - { - path = fileName.path(); - binFileName = fileName.setExt(".bin"); - binFile = fopen(binFileName.c_str(),"rb"); - if (!binFile) { - binFileName = fileName.addExt(".bin"); - binFile = fopen(binFileName.c_str(),"rb"); - } - - Ref xml = parseXML(fileName); - if (xml->name == "scene") - { - Ref group = new SceneGraph::GroupNode; - for (size_t i=0; ichildren.size(); i++) { - group->add(loadNode(xml->children[i])); - } - root = group.cast(); - } - else if (xml->name == "BGFscene") - { - Ref last = nullptr; - for (size_t i=0; ichildren.size(); i++) { - root = loadBGFNode(xml->children[i]); - } - } - else - THROW_RUNTIME_ERROR(xml->loc.str()+": invalid scene tag"); - - if (space == AffineSpace3fa(one)) - return; - - root = new SceneGraph::TransformNode(space,root); - } - - XMLLoader::~XMLLoader() { - if (binFile) fclose(binFile); - } - - /*! read from disk */ - Ref loadXML(const FileName& fileName, const AffineSpace3fa& space) { - return XMLLoader::load(fileName,space); - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/xml_loader.h b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/xml_loader.h deleted file mode 100644 index c9bace8fcb74..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/xml_loader.h +++ /dev/null @@ -1,29 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#ifndef __EMBREE_XML_LOADER_H__ -#define __EMBREE_XML_LOADER_H__ - -#include "obj_loader.h" -#include "scenegraph.h" - -namespace embree -{ - /*! read from disk */ - Ref loadXML(const FileName& fileName, const AffineSpace3fa& space); -} - -#endif diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/xml_parser.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/xml_parser.cpp deleted file mode 100644 index 6f9f62d02b0c..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/xml_parser.cpp +++ /dev/null @@ -1,202 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "xml_parser.h" - -#include - -namespace embree -{ - ////////////////////////////////////////////////////////////////////////////// - /// XML Input - ////////////////////////////////////////////////////////////////////////////// - - /*! parse a list of XML comments */ - void parseComments(Ref >& cin) - { - while (cin->peek() == Token::Sym("")) cin->drop(); - cin->drop(); - } - } - - /*! parse XML parameter */ - void parseParm(Ref >& cin, std::map& parms) - { - std::string name = cin->get().Identifier(); - if (cin->get() != Token::Sym("=")) THROW_RUNTIME_ERROR(cin->unget().Location().str()+": symbol \"=\" expected"); - parms[name] = cin->get().String(); - } - - /*! parse XML header */ - Ref parseHeader(Ref >& cin) - { - Ref xml = new XML; - if (cin->get() != Token::Sym("unget().Location().str()+": wrong XML header"); - xml->name = cin->get().Identifier(); - parseComments(cin); - while (cin->peek() != Token::Sym("?>")) { - parseParm(cin,xml->parms); - parseComments(cin); - } - cin->drop(); - return xml; - } - - /*! parse XML tag */ - Ref parseXML(Ref >& cin) - { - Ref xml = new XML; - xml->loc = cin->peek().Location(); - - /* parse tag opening */ - if (cin->get() != Token::Sym("<")) THROW_RUNTIME_ERROR(cin->unget().Location().str()+": tag expected"); - - xml->name = cin->get().Identifier(); - parseComments(cin); - while (cin->peek() != Token::Sym("/>") && cin->peek() != Token::Sym(">")) { - parseParm(cin,xml->parms); - parseComments(cin); - } - if (cin->peek() == Token::Sym("/>")) { - cin->drop(); - return xml; - } - cin->drop(); - - /* parse body token list */ - parseComments(cin); - while (cin->peek() != Token::Sym("<") && cin->peek() != Token::Sym("body.push_back(cin->get()); - parseComments(cin); - } - - /* the body also contains children */ - if (cin->peek() == Token::Sym("<")) { - while (cin->peek() != Token::Sym("children.push_back(parseXML(cin)); - parseComments(cin); - } - } - - /* parse tag closing */ - if (cin->get() != Token::Sym("unget().Location().str()+": symbol \"get() != Token::Id(xml->name)) THROW_RUNTIME_ERROR(cin->unget().Location().str()+": closing "+xml->name+" expected"); - if (cin->get() != Token::Sym(">") ) THROW_RUNTIME_ERROR(cin->unget().Location().str()+": symbol \">\" expected"); - - return xml; - } - - /* load XML from token stream */ - Ref parseXML(Ref > chars, bool hasHeader = true, bool hasTail = false) - { - /* create lexer for XML file */ - std::vector symbols; - symbols.push_back(""); - symbols.push_back(""); - symbols.push_back(""); - symbols.push_back("<"); - symbols.push_back(">"); - symbols.push_back("="); - Ref > cin = new TokenStream(chars,TokenStream::alpha + TokenStream::ALPHA + "_", TokenStream::separators, symbols); - - if (hasHeader) parseHeader(cin); - parseComments(cin); - Ref xml = parseXML(cin); - parseComments(cin); - - if (!hasTail) - if (cin->peek() != Token::Eof()) THROW_RUNTIME_ERROR(cin->peek().Location().str()+": end of file expected"); - - return xml; - } - - /*! load XML file from stream */ - std::istream& operator>>(std::istream& cin, Ref& xml) { - xml = parseXML(new StdStream(cin),false,true); - return cin; - } - - /*! load XML file from disk */ - Ref parseXML(const FileName& fileName) { - return parseXML(new FileStream(fileName),true,false); - } - - - ////////////////////////////////////////////////////////////////////////////// - /// XML Output - ////////////////////////////////////////////////////////////////////////////// - - - /* indent to some hierarchy level using spaces */ - void indent(std::ostream& cout, size_t depth) { - for (size_t i=0; i<2*depth; i++) cout << " "; - } - - /* store XML to a stream */ - std::ostream& emitXML(std::ostream& cout, const Ref& xml, size_t depth = 0) - { - /* print header */ - if (depth == 0) cout << "" << std::endl << std::endl; - - /* print tag opening */ - indent(cout,depth); cout << "<" << xml->name; - for (std::map::const_iterator i=xml->parms.begin(); i!=xml->parms.end(); i++) - cout << " " << i->first << "=" << "\"" << i->second << "\""; - if (xml->children.size() == 0 && xml->body.size() == 0) { - cout << "/>" << std::endl; - return cout; - } - cout << ">"; - - bool compact = xml->body.size() < 16 && xml->children.size() == 0; - if (!compact) cout << std::endl; - - /* print token list */ - if (xml->body.size()) { - if (!compact) indent(cout,depth+1); - for (size_t i=0; ibody.size(); i++) - cout << xml->body[i] << (i!=xml->body.size()-1?" ":""); - if (!compact) cout << std::endl; - } - - /* print children */ - for (size_t i=0; ichildren.size(); i++) - emitXML(cout,xml->children[i],depth+1); - - /* print tag closing */ - if (!compact) indent(cout,depth); - return cout << "name << ">" << std::endl; - } - - /* store XML to stream */ - std::ostream& operator<<(std::ostream& cout, const Ref& xml) { - return emitXML(cout,xml); - } - - /*! store XML to disk */ - void emitXML(const FileName& fileName, const Ref& xml) - { - std::ofstream cout(fileName.c_str()); - if (!cout.is_open()) THROW_RUNTIME_ERROR("cannot open file " + fileName.str() + " for writing"); - emitXML(cout,xml); - cout.close(); - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/xml_parser.h b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/xml_parser.h deleted file mode 100644 index d8b899323df9..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/common/tutorial/xml_parser.h +++ /dev/null @@ -1,117 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -#include "../../../common/sys/platform.h" -#include "../../../common/sys/filename.h" -#include "../../../common/lexers/tokenstream.h" - -#include -#include -#include - -namespace embree -{ - /* an XML node */ - class XML : public RefCount - { - public: - XML (const std::string& name = "") : name(name) {} - - /*! returns a parameter of the XML node */ - std::string parm(const std::string& parmID) const { - std::map::const_iterator i = parms.find(parmID); - if (i == parms.end()) return ""; else return i->second; - } - - /*! returns the nth child */ - const Ref child(const size_t id) const - { - if (id >= children.size()) - THROW_RUNTIME_ERROR (loc.str()+": XML node has no child \"" + std::to_string((long long)id) + "\""); - return children[id]; - } - - /*! returns child by node tag */ - const Ref child(const std::string& childID) const - { - for (size_t i=0; iname == childID) return children[i]; - THROW_RUNTIME_ERROR (loc.str()+": XML node has no child \"" + childID + "\""); - } - - /*! returns child by node tag without failing */ - const Ref childOpt(const std::string& childID) const - { - for (size_t i=0; iname == childID) return children[i]; - return null; - } - - /*! adds a new parameter to the node */ - Ref add(const std::string& name, const std::string& val) { - parms[name] = val; - return this; - } - - /*! adds a new child */ - Ref add(const Ref& xml) { - children.push_back(xml); - return this; - } - - /*! adds new data tokens to the body of the node */ - Ref add(const Token& tok) { - body.push_back(tok); - return this; - } - - /*! compares two XML nodes */ - friend bool operator ==( const Ref& a, const Ref& b ) { - return a->name == b->name && a->parms == b->parms && a->children == b->children && a->body == b->body; - } - - /*! orders two XML nodes */ - friend bool operator <( const Ref& a, const Ref& b ) { - if (a->name != b->name ) return a->name < b->name; - if (a->parms != b->parms ) return a->parms < b->parms; - if (a->children != b->children) return a->children < b->children; - if (a->body != b->body ) return a->body < b->body; - return false; - } - - public: - ParseLocation loc; - std::string name; - std::map parms; - std::vector > children; - std::vector body; - }; - - /*! load XML file from stream */ - std::istream& operator>>(std::istream& cin, Ref& xml); - - /*! load XML file from disk */ - Ref parseXML(const FileName& fileName); - - /* store XML to stream */ - std::ostream& operator<<(std::ostream& cout, const Ref& xml); - - /*! store XML to disk */ - void emitXML(const FileName& fileName, const Ref& xml); -} - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/displacement_geometry/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/displacement_geometry/CMakeLists.txt deleted file mode 100644 index 25cd5fd2fc53..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/displacement_geometry/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2015 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -INCLUDE(CMakeDependentOption) - -INCLUDE(tutorial) -ADD_TUTORIAL(displacement_geometry) - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/displacement_geometry/displacement_geometry.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/displacement_geometry/displacement_geometry.cpp deleted file mode 100644 index 13caa8f6c26d..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/displacement_geometry/displacement_geometry.cpp +++ /dev/null @@ -1,180 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial.h" -#include "../common/tutorial/obj_loader.h" -#include "../common/tutorial/xml_loader.h" -#include "../common/image/image.h" - -namespace embree -{ - /* name of the tutorial */ - const char* tutorialName = "displacement_geometry"; - - /* configuration */ - static std::string g_rtcore = ""; - static size_t g_numThreads = 0; - static std::string g_subdiv_mode = ""; - - /* output settings */ - static size_t g_width = 512; - static size_t g_height = 512; - static bool g_fullscreen = false; - static FileName outFilename = ""; - static bool g_interactive = true; - - /* scene */ - OBJScene g_obj_scene; - static FileName filename = ""; - - static std::string getParameterString(Ref &cin, std::string &term) { - - /*! Parameter name and options. */ - std::string parameter = term + " "; while (cin->peek() != "" && cin->peek()[0] != '-') parameter += cin->getString(); return(parameter); - - } - - static void initEmbreeState(std::string configuration) { - - /*! Initialize Embree state. */ - init(configuration.c_str()); - - } - - static void parseCommandLine(Ref cin, const FileName &path) { - - for (std::string term = cin->getString() ; term != "" ; term = cin->getString()) { - - /*! Command line parameters from a file. */ - if (term == "-c") { FileName file = path + cin->getFileName(); parseCommandLine(new ParseStream(new LineCommentFilter(file, "#")), file.path()); } - - /* load OBJ model*/ - else if (term == "-i") { - filename = path + cin->getFileName(); - } - - /*! Camera field of view. */ - else if (term == "-fov") g_camera.fov = cin->getFloat(); - - /*! Full screen mode. */ - else if (term == "-fullscreen") g_fullscreen = true; - - /* output filename */ - else if (term == "-o") { - g_interactive = false; - outFilename = cin->getFileName(); - } - - /*! Embree configuration. */ - else if (term == "-rtcore") g_rtcore = cin->getString(); - - /*! Window size. */ - else if (term == "-size") { g_width = cin->getInt(); g_height = cin->getInt(); } - - /*! Thread count. */ - else if (term == "-threads") { g_numThreads = cin->getInt(); } - - /*! Camera view direction. */ - else if (term == "-vd") g_camera.to = g_camera.from + cin->getVec3fa(); - - /*! Camera look point. */ - else if (term == "-vi") g_camera.to = cin->getVec3fa(); - - /*! Camera position. */ - else if (term == "-vp") g_camera.from = cin->getVec3fa(); - - /*! Camera up vector. */ - else if (term == "-vu") g_camera.up = cin->getVec3fa(); - - else if (term == "-cache") - g_subdiv_mode = ",subdiv_accel=bvh4.subdivpatch1cached"; - - else if (term == "-pregenerate") - g_subdiv_mode = ",subdiv_accel=bvh4.grid.eager"; - - /*! Skip unknown command line parameters. */ - else std::cerr << "Unknown command line parameter: " << getParameterString(cin, term) << std::endl; - - } - - } - - void renderToFile(const FileName& fileName) - { - resize(g_width,g_height); - AffineSpace3fa pixel2world = g_camera.pixel2world(g_width,g_height); - - render(0.0f, - pixel2world.l.vx, - pixel2world.l.vy, - pixel2world.l.vz, - pixel2world.p); - - void* ptr = map(); - Ref image = new Image4uc(g_width, g_height, (Col4uc*)ptr); - storeImage(image, fileName); - unmap(); - cleanup(); - } - - int main(int argc, char **argv) - { - /* for best performance set FTZ and DAZ flags in MXCSR control and status register */ - _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); - _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); - - std::cout << " === Possible cmd line options: -pregenerate, -cache === " << std::endl; - - /* set default camera */ - g_camera.from = Vec3fa(1.5f,1.5f,-1.5f); - g_camera.to = Vec3fa(0.0f,0.0f,0.0f); - - /*! Parse command line options. */ - parseCommandLine(new ParseStream(new CommandLineStream(argc, argv)), FileName()); - - /*! Set the thread count in the Embree configuration string. */ - if (g_numThreads) g_rtcore += ",threads=" + std::to_string((long long)g_numThreads); - g_rtcore += g_subdiv_mode; - - /*! Initialize Embree state. */ - init(g_rtcore.c_str()); - - /* render to disk */ - if (outFilename.str() != "") - renderToFile(outFilename); - - /* interactive mode */ - if (g_interactive) { - initWindowState(argc,argv,tutorialName, g_width, g_height, g_fullscreen); - enterWindowRunLoop(); - } - return 0; - } -} - -int main(int argc, char** argv) -{ - /*! Tutorial entry point. */ - try { return embree::main(argc, argv); } - - /*! Known exception. */ - catch (const std::exception& e) { std::cout << "Error: " << e.what() << std::endl; return(1); } - - /*! Unknown exception. */ - catch (...) { std::cout << "Error: unknown exception caught." << std::endl; return(1); } - -} - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/displacement_geometry/displacement_geometry_device.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/displacement_geometry/displacement_geometry_device.cpp deleted file mode 100644 index 73c149a1aa40..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/displacement_geometry/displacement_geometry_device.cpp +++ /dev/null @@ -1,332 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial_device.h" - -/* configuration */ -#define EDGE_LEVEL 256.0f -#define ENABLE_SMOOTH_NORMALS 0 - -/* scene data */ -RTCDevice g_device = nullptr; -RTCScene g_scene = nullptr; - -/* render function to use */ -renderPixelFunc renderPixel; - -/* previous camera position */ -Vec3fa old_p; - -/* error reporting function */ -void error_handler(const RTCError code, const char* str) -{ - printf("Embree: "); - switch (code) { - case RTC_UNKNOWN_ERROR : printf("RTC_UNKNOWN_ERROR"); break; - case RTC_INVALID_ARGUMENT : printf("RTC_INVALID_ARGUMENT"); break; - case RTC_INVALID_OPERATION: printf("RTC_INVALID_OPERATION"); break; - case RTC_OUT_OF_MEMORY : printf("RTC_OUT_OF_MEMORY"); break; - case RTC_UNSUPPORTED_CPU : printf("RTC_UNSUPPORTED_CPU"); break; - case RTC_CANCELLED : printf("RTC_CANCELLED"); break; - default : printf("invalid error code"); break; - } - if (str) { - printf(" ("); - while (*str) putchar(*str++); - printf(")\n"); - } - exit(1); -} - -__aligned(16) float cube_vertices[8][4] = -{ - { -1.0f, -1.0f, -1.0f, 0.0f }, - { 1.0f, -1.0f, -1.0f, 0.0f }, - { 1.0f, -1.0f, 1.0f, 0.0f }, - { -1.0f, -1.0f, 1.0f, 0.0f }, - { -1.0f, 1.0f, -1.0f, 0.0f }, - { 1.0f, 1.0f, -1.0f, 0.0f }, - { 1.0f, 1.0f, 1.0f, 0.0f }, - { -1.0f, 1.0f, 1.0f, 0.0f } -}; - -#if 1 - -#define NUM_INDICES 24 -#define NUM_FACES 6 -#define FACE_SIZE 4 - -unsigned int cube_indices[24] = { - 0, 1, 5, 4, - 1, 2, 6, 5, - 2, 3, 7, 6, - 0, 4, 7, 3, - 4, 5, 6, 7, - 0, 3, 2, 1, -}; - -unsigned int cube_faces[6] = { - 4, 4, 4, 4, 4, 4 -}; - -#else - -#define NUM_INDICES 36 -#define NUM_FACES 12 -#define FACE_SIZE 3 - -unsigned int cube_indices[36] = { - 1, 5, 4, 0, 1, 4, - 2, 6, 5, 1, 2, 5, - 3, 7, 6, 2, 3, 6, - 4, 7, 3, 0, 4, 3, - 5, 6, 7, 4, 5, 7, - 3, 2, 1, 0, 3, 1 -}; - -unsigned int cube_faces[12] = { - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 -}; - -#endif - -float displacement(const Vec3fa& P) -{ - float dN = 0.0f; - for (float freq = 1.0f; freq<40.0f; freq*= 2) { - float n = abs(noise(freq*P)); - dN += 1.4f*n*n/freq; - } - return dN; -} - -float displacement_du(const Vec3fa& P, const Vec3fa& dPdu) -{ - const float du = 0.001f; - return (displacement(P+du*dPdu)-displacement(P))/du; -} - -float displacement_dv(const Vec3fa& P, const Vec3fa& dPdv) -{ - const float dv = 0.001f; - return (displacement(P+dv*dPdv)-displacement(P))/dv; -} - -void displacementFunction(void* ptr, unsigned int geomID, int unsigned primID, - const float* u, /*!< u coordinates (source) */ - const float* v, /*!< v coordinates (source) */ - const float* nx, /*!< x coordinates of normal at point to displace (source) */ - const float* ny, /*!< y coordinates of normal at point to displace (source) */ - const float* nz, /*!< z coordinates of normal at point to displace (source) */ - float* px, /*!< x coordinates of points to displace (source and target) */ - float* py, /*!< y coordinates of points to displace (source and target) */ - float* pz, /*!< z coordinates of points to displace (source and target) */ - size_t N) -{ - for (size_t i = 0; i 0) { - Vec3fa dPdu,dPdv; - int geomID = ray.geomID; { - rtcInterpolate(g_scene,geomID,ray.primID,ray.u,ray.v,RTC_VERTEX_BUFFER,nullptr,&dPdu.x,&dPdv.x,3); - } - Ng = normalize(cross(dPdv,dPdu)); - dPdu = dPdu + Ng*displacement_du(P,dPdu); - dPdv = dPdv + Ng*displacement_dv(P,dPdv); - Ng = normalize(cross(dPdv,dPdu)); - } -#endif - - /* initialize shadow ray */ - RTCRay shadow; - shadow.org = ray.org + ray.tfar*ray.dir; - shadow.dir = neg(lightDir); - shadow.tnear = 0.001f; - shadow.tfar = inf; - shadow.geomID = RTC_INVALID_GEOMETRY_ID; - shadow.primID = RTC_INVALID_GEOMETRY_ID; - shadow.mask = -1; - shadow.time = 0; - - /* trace shadow ray */ - rtcOccluded(g_scene,shadow); - - /* add light contribution */ - if (shadow.geomID == RTC_INVALID_GEOMETRY_ID) - color = color + diffuse*clamp(-(dot(lightDir,Ng)),0.0f,1.0f); // FIXME: += - } - return color; -} - -/* task that renders a single screen tile */ -void renderTile(int taskIndex, int* pixels, - const int width, - const int height, - const float time, - const Vec3fa& vx, - const Vec3fa& vy, - const Vec3fa& vz, - const Vec3fa& p, - const int numTilesX, - const int numTilesY) -{ - const int tileY = taskIndex / numTilesX; - const int tileX = taskIndex - tileY * numTilesX; - const int x0 = tileX * TILE_SIZE_X; - const int x1 = min(x0+TILE_SIZE_X,width); - const int y0 = tileY * TILE_SIZE_Y; - const int y1 = min(y0+TILE_SIZE_Y,height); - - for (int y = y0; y cin, const FileName& path) - { - while (true) - { - std::string tag = cin->getString(); - if (tag == "") return; - - /* parse command line parameters from a file */ - if (tag == "-c") { - FileName file = path + cin->getFileName(); - parseCommandLine(new ParseStream(new LineCommentFilter(file, "#")), file.path()); - } - - /* parse camera parameters */ - else if (tag == "-vp") g_camera.from = cin->getVec3fa(); - else if (tag == "-vi") g_camera.to = cin->getVec3fa(); - else if (tag == "-vd") g_camera.to = g_camera.from + cin->getVec3fa(); - else if (tag == "-vu") g_camera.up = cin->getVec3fa(); - else if (tag == "-fov") g_camera.fov = cin->getFloat(); - - /* frame buffer size */ - else if (tag == "-size") { - g_width = cin->getInt(); - g_height = cin->getInt(); - } - - /* full screen mode */ - else if (tag == "-fullscreen") - g_fullscreen = true; - - /* output filename */ - else if (tag == "-o") - outFilename = cin->getFileName(); - - /* rtcore configuration */ - else if (tag == "-rtcore") - g_rtcore = cin->getString(); - - /* number of threads to use */ - else if (tag == "-threads") - g_numThreads = cin->getInt(); - - /* skip unknown command line parameter */ - else { - std::cerr << "unknown command line parameter: " << tag << " "; - while (cin->peek() != "" && cin->peek()[0] != '-') std::cerr << cin->getString() << " "; - std::cerr << std::endl; - } - } - } - - void renderToFile(const FileName& fileName) - { - resize(g_width,g_height); - AffineSpace3fa pixel2world = g_camera.pixel2world(g_width,g_height); - - render(0.0f, - pixel2world.l.vx, - pixel2world.l.vy, - pixel2world.l.vz, - pixel2world.p); - - void* ptr = map(); - Ref image = new Image4uc(g_width, g_height, (Col4uc*)ptr); - storeImage(image, fileName); - unmap(); - cleanup(); - } - - /* main function in embree namespace */ - int main(int argc, char** argv) - { - /* for best performance set FTZ and DAZ flags in MXCSR control and status register */ - _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); - _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); - - /* set start camera */ - g_camera.from = Vec3f(2,2,2); - g_camera.to = Vec3f(0,0,0); - - /* create stream for parsing */ - Ref stream = new ParseStream(new CommandLineStream(argc, argv)); - - /* parse command line */ - parseCommandLine(stream, FileName()); - if (g_numThreads) - g_rtcore += ",threads=" + std::to_string((long long)g_numThreads); - - /* initialize ray tracing core */ - init(g_rtcore.c_str()); - - /* render to disk */ - if (outFilename.str() != "") { - renderToFile(outFilename); - return 0; - } - - /* initialize GLUT */ - initWindowState(argc,argv,tutorialName, g_width, g_height, g_fullscreen); - - /* enter the GLUT run loop */ - enterWindowRunLoop(); - - return 0; - } -} - -int main(int argc, char** argv) -{ - try { - return embree::main(argc, argv); - } - catch (const std::exception& e) { - std::cout << "Error: " << e.what() << std::endl; - return 1; - } - catch (...) { - std::cout << "Error: unknown exception caught." << std::endl; - return 1; - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/dynamic_scene/dynamic_scene_device.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/dynamic_scene/dynamic_scene_device.cpp deleted file mode 100644 index 9834d18828e2..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/dynamic_scene/dynamic_scene_device.cpp +++ /dev/null @@ -1,338 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial_device.h" - -#if 0 -const int numSpheres = 1000; -const int numPhi = 5; -#else -const int numSpheres = 20; -const int numPhi = 120; -//const int numPhi = 400; -#endif -const int numTheta = 2*numPhi; - -/* scene data */ -RTCDevice g_device = nullptr; -RTCScene g_scene = nullptr; -Vec3fa position[numSpheres]; -Vec3fa colors[numSpheres+1]; -float radius[numSpheres]; -int disabledID = -1; - -/* render function to use */ -renderPixelFunc renderPixel; - -/* error reporting function */ -void error_handler(const RTCError code, const char* str) -{ - printf("Embree: "); - switch (code) { - case RTC_UNKNOWN_ERROR : printf("RTC_UNKNOWN_ERROR"); break; - case RTC_INVALID_ARGUMENT : printf("RTC_INVALID_ARGUMENT"); break; - case RTC_INVALID_OPERATION: printf("RTC_INVALID_OPERATION"); break; - case RTC_OUT_OF_MEMORY : printf("RTC_OUT_OF_MEMORY"); break; - case RTC_UNSUPPORTED_CPU : printf("RTC_UNSUPPORTED_CPU"); break; - case RTC_CANCELLED : printf("RTC_CANCELLED"); break; - default : printf("invalid error code"); break; - } - if (str) { - printf(" ("); - while (*str) putchar(*str++); - printf(")\n"); - } - exit(1); -} - -/* adds a sphere to the scene */ -unsigned int createSphere (RTCGeometryFlags flags, const Vec3fa& pos, const float r) -{ - /* create a triangulated sphere */ - unsigned int mesh = rtcNewTriangleMesh (g_scene, flags, 2*numTheta*(numPhi-1), numTheta*(numPhi+1)); - - /* map triangle and vertex buffer */ - Vertex* vertices = (Vertex* ) rtcMapBuffer(g_scene,mesh,RTC_VERTEX_BUFFER); - Triangle* triangles = (Triangle*) rtcMapBuffer(g_scene,mesh,RTC_INDEX_BUFFER); - - /* create sphere geometry */ - int tri = 0; - const float rcpNumTheta = rcp((float)numTheta); - const float rcpNumPhi = rcp((float)numPhi); - for (int phi=0; phi<=numPhi; phi++) - { - for (int theta=0; theta 1) { - triangles[tri].v0 = p10; - triangles[tri].v1 = p00; - triangles[tri].v2 = p01; - tri++; - } - - if (phi < numPhi) { - triangles[tri].v0 = p11; - triangles[tri].v1 = p10; - triangles[tri].v2 = p01; - tri++; - } - } - } - rtcUnmapBuffer(g_scene,mesh,RTC_VERTEX_BUFFER); - rtcUnmapBuffer(g_scene,mesh,RTC_INDEX_BUFFER); - - return mesh; -} - -/* adds a ground plane to the scene */ -unsigned int addGroundPlane (RTCScene scene_i) -{ - /* create a triangulated plane with 2 triangles and 4 vertices */ - unsigned int mesh = rtcNewTriangleMesh (scene_i, RTC_GEOMETRY_STATIC, 2, 4); - - /* set vertices */ - Vertex* vertices = (Vertex*) rtcMapBuffer(scene_i,mesh,RTC_VERTEX_BUFFER); - vertices[0].x = -10; vertices[0].y = -2; vertices[0].z = -10; - vertices[1].x = -10; vertices[1].y = -2; vertices[1].z = +10; - vertices[2].x = +10; vertices[2].y = -2; vertices[2].z = -10; - vertices[3].x = +10; vertices[3].y = -2; vertices[3].z = +10; - rtcUnmapBuffer(scene_i,mesh,RTC_VERTEX_BUFFER); - - /* set triangles */ - Triangle* triangles = (Triangle*) rtcMapBuffer(scene_i,mesh,RTC_INDEX_BUFFER); - triangles[0].v0 = 0; triangles[0].v1 = 2; triangles[0].v2 = 1; - triangles[1].v0 = 1; triangles[1].v1 = 2; triangles[1].v2 = 3; - rtcUnmapBuffer(scene_i,mesh,RTC_INDEX_BUFFER); - - return mesh; -} - -/* called by the C++ code for initialization */ -extern "C" void device_init (char* cfg) -{ - /* create new Embree device */ - g_device = rtcNewDevice(cfg); - - /* set error handler */ - rtcDeviceSetErrorFunction(g_device,error_handler); - - /* create scene */ - g_scene = rtcDeviceNewScene(g_device,RTC_SCENE_DYNAMIC | RTC_SCENE_ROBUST, RTC_INTERSECT1); - - /* create some triangulated spheres */ - for (int i=0; ix = pos.x + r*sin(f*phif)*sin(thetaf); - v->y = pos.y + r*cos(phif); - v->z = pos.z + r*sin(f*phif)*cos(thetaf); - } -} - -/* task that renders a single screen tile */ -Vec3fa renderPixelStandard(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p) -{ - /* initialize ray */ - RTCRay ray; - ray.org = p; - ray.dir = normalize(x*vx + y*vy + vz); - ray.tnear = 0.0f; - ray.tfar = inf; - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.primID = RTC_INVALID_GEOMETRY_ID; - ray.mask = -1; - ray.time = 0; - - /* intersect ray with scene */ - rtcIntersect(g_scene,ray); - - /* shade pixels */ - Vec3fa color = Vec3fa(0.0f); - if (ray.geomID != RTC_INVALID_GEOMETRY_ID) - { - Vec3fa diffuse = colors[ray.geomID]; - color = color + diffuse*0.1f; // FIXME: += - Vec3fa lightDir = normalize(Vec3fa(-1,-1,-1)); - - /* initialize shadow ray */ - RTCRay shadow; - shadow.org = ray.org + ray.tfar*ray.dir; - shadow.dir = neg(lightDir); - shadow.tnear = 0.001f; - shadow.tfar = inf; - shadow.geomID = 1; - shadow.primID = 0; - shadow.mask = -1; - shadow.time = 0; - - /* trace shadow ray */ - rtcOccluded(g_scene,shadow); - - /* add light contribution */ - if (shadow.geomID) - color = color + diffuse*clamp(-dot(lightDir,normalize(ray.Ng)),0.0f,1.0f); // FIXME: += - } - return color; -} - -/* task that renders a single screen tile */ -void renderTile(int taskIndex, int* pixels, - const int width, - const int height, - const float time, - const Vec3fa& vx, - const Vec3fa& vy, - const Vec3fa& vz, - const Vec3fa& p, - const int numTilesX, - const int numTilesY) -{ - const int tileY = taskIndex / numTilesX; - const int tileX = taskIndex - tileY * numTilesX; - const int x0 = tileX * TILE_SIZE_X; - const int x1 = min(x0+TILE_SIZE_X,width); - const int y0 = tileY * TILE_SIZE_Y; - const int y1 = min(y0+TILE_SIZE_Y,height); - - for (int y = y0; yx = pos.x+r*sin(f*phif)*sin(thetaf); - v->y = pos.y+r*cos(phif); - v->z = pos.z+r*sin(f*phif)*cos(thetaf); - } -#endif - - rtcUnmapBuffer(g_scene,id,RTC_VERTEX_BUFFER); - - /* update mesh */ - rtcUpdate (g_scene,id); -} - -/* called by the C++ code to render */ -extern "C" void device_render (int* pixels, - const int width, - const int height, - const float time, - const Vec3fa& vx, - const Vec3fa& vy, - const Vec3fa& vz, - const Vec3fa& p) -{ - /* animate sphere */ - for (int i=0; i - -#include -//#include // use this to get _MM_SET_DENORMALS_ZERO_MODE when compiling for SSE3 or higher - -#if !defined(_MM_SET_DENORMALS_ZERO_MODE) -#define _MM_DENORMALS_ZERO_ON (0x0040) -#define _MM_DENORMALS_ZERO_OFF (0x0000) -#define _MM_DENORMALS_ZERO_MASK (0x0040) -#define _MM_SET_DENORMALS_ZERO_MODE(x) (_mm_setcsr((_mm_getcsr() & ~_MM_DENORMALS_ZERO_MASK) | (x))) -#endif - -int main(int argc, char* argv[]) -{ - /* for best performance set FTZ and DAZ flags in MXCSR control and status register */ - _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); - _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); - - /* create new Embree device */ - RTCDevice device = rtcNewDevice("verbose=1"); - - /* ddelete device again */ - rtcDeleteDevice(device); - - return 0; -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/find_embree/find_embree_ispc.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/find_embree/find_embree_ispc.cpp deleted file mode 100644 index ce3ca9cd33df..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/find_embree/find_embree_ispc.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include - -#include -//#include // use this to get _MM_SET_DENORMALS_ZERO_MODE when compiling for SSE3 or higher - -#if !defined(_MM_SET_DENORMALS_ZERO_MODE) -#define _MM_DENORMALS_ZERO_ON (0x0040) -#define _MM_DENORMALS_ZERO_OFF (0x0000) -#define _MM_DENORMALS_ZERO_MASK (0x0040) -#define _MM_SET_DENORMALS_ZERO_MODE(x) (_mm_setcsr((_mm_getcsr() & ~_MM_DENORMALS_ZERO_MASK) | (x))) -#endif - -extern "C" void ispcEntry(); - -int main(int argc, char* argv[]) -{ - /* for best performance set FTZ and DAZ flags in MXCSR control and status register */ - _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); - _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); - - ispcEntry(); - - return 0; -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/hair_geometry/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/hair_geometry/CMakeLists.txt deleted file mode 100644 index 16c9f991e07b..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/hair_geometry/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2015 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -INCLUDE(tutorial) -ADD_TUTORIAL(hair_geometry) diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/hair_geometry/hair_geometry.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/hair_geometry/hair_geometry.cpp deleted file mode 100644 index e1005f472f60..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/hair_geometry/hair_geometry.cpp +++ /dev/null @@ -1,571 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial.h" -#include "../common/tutorial/obj_loader.h" -#include "../common/tutorial/hair_loader.h" -#include "../common/tutorial/cy_hair_loader.h" -#include "../common/image/image.h" - -extern "C" embree::Vec3fa g_dirlight_direction = embree::normalize(embree::Vec3fa(1,-1,1)); -extern "C" embree::Vec3fa g_dirlight_intensity = embree::Vec3fa(4.0f); -extern "C" embree::Vec3fa g_ambient_intensity = embree::Vec3fa(1.0f); - -namespace embree -{ - /* name of the tutorial */ - const char* tutorialName = "hair_geometry"; - - /* configuration */ - static std::string g_rtcore = ""; - - static size_t g_width = 512; - static size_t g_height = 512; - static bool g_fullscreen = false; - static size_t g_numThreads = 0; - - /* scene */ - OBJScene g_obj_scene; - OBJScene g_obj_scene2; - static FileName objFilename = ""; - static FileName objFilename2 = ""; - static FileName hairFilename = ""; - static FileName hairFilename2 = ""; - static FileName cy_hairFilename = ""; - static FileName outFilename = ""; - static int g_skipBenchmarkFrames = 0; - static int g_numBenchmarkFrames = 0; - static bool g_interactive = true; - - Vec3fa offset = zero; - Vec3fa offset_mb = zero; - - Vec3fa uniformSampleSphere(const float& u, const float& v) - { - const float phi = float(two_pi) * u; - const float cosTheta = 1.0f - 2.0f * v, sinTheta = 2.0f * sqrt(v * (1.0f - v)); - return Vec3fa(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta); - } - -static int p[513] = { - 151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23, - 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33, - 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166, - 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244, - 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196, - 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123, - 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42, - 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9, - 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228, - 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107, - 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, - 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180, - 151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23, - 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33, - 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166, - 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244, - 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196, - 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123, - 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42, - 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9, - 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228, - 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107, - 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, - 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180, - 151 -}; - -static float g1[128] = { - -0.20707, 0.680971, -0.293328, -0.106833, -0.362614, 0.772857, -0.968834, 0.16818, -0.681263, -0.232568, 0.382009, -0.882282, 0.799709, -0.672908, -0.681857, 0.0661294, 0.208288, 0.165398, -0.460058, -0.219044, -0.413199, 0.484755, -0.402949, -0.848924, -0.190035, 0.714756, 0.883937, 0.325661, 0.692952, -0.99449, -0.0752415, 0.065192, 0.575753, -0.468776, 0.965505, -0.38643, 0.20171, 0.217431, -0.575122, 0.77179, -0.390686, -0.69628, -0.324676, -0.225046, 0.28722, 0.507107, 0.207232, 0.0632565, -0.0812794, 0.304977, -0.345638, 0.892741, -0.26392, 0.887781, -0.985143, 0.0331999, -0.454458, -0.951402, 0.183909, -0.590073, 0.755387, -0.881263, -0.478315, -0.394342, 0.78299, -0.00360388, 0.420051, -0.427172, 0.729847, 0.351081, -0.0830201, 0.919271, 0.549351, -0.246897, -0.542722, -0.290932, -0.399364, 0.339532, 0.437933, 0.131909, 0.648931, -0.218776, 0.637533, 0.688017, -0.639064, 0.886792, -0.150226, 0.0413316, -0.868712, 0.827016, 0.765169, 0.522728, -0.202155, 0.376514, 0.523097, -0.189982, -0.749498, -0.0307322, -0.555075, 0.746242, 0.0576438, -0.997172, 0.721028, -0.962605, 0.629784, -0.514232, -0.370856, 0.931465, 0.87112, 0.618863, -0.0157817, -0.559729, 0.152707, -0.421942, -0.357866, -0.477353, -0.652024, -0.996365, -0.910432, -0.517651, -0.169098, 0.403249, -0.556309, 0.00782069, -0.86594, -0.213873, -0.0410469, -0.563716 -}; - -static float g2[128*2] = { -0.605609, 0.538399, 0.796519, -0.944204, 0.908294, 0.756016, 0.0977536, -0.863638, 0.842196, -0.744751, -0.932081, 0.932392, -0.588525, 0.516884, 0.841188, -0.978497, -0.608649, -0.868011, 0.992137, -0.772425, 0.963049, -0.0478757, 0.953878, 0.889467, 0.562174, 0.624644, -0.356598, -0.520726, -0.821833, 0.99985, 0.234183, -0.9791, -0.971815, -0.0979374, -0.108159, -0.34927, -0.592124, -0.775632, 0.97228, 0.753819, 0.941608, 0.578291, 0.852108, -0.760312, -0.784772, 0.0223242, -0.606013, -0.980319, 0.252581, -0.575064, 0.884701, 0.943763, 0.737344, 0.938496, 0.0466562, -0.994566, 0.989782, 0.988368, -0.546155, 0.279211, -0.69504, 0.931229, 0.99768, -0.325874, -0.630157, -0.999936, -0.968623, -0.226805, -0.750428, -0.450961, 0.257868, 0.968011, -0.988005, -0.713965, 0.991007, -0.61059, 0.950437, -0.483042, -0.98105, -0.915356, -0.892527, -0.772958, -0.9081, 0.55692, 0.906075, 0.937419, 0.454624, -0.991582, 0.400857, 0.855933, -0.672619, 0.0713424, 0.593249, -0.378286, -0.997369, -0.827112, 0.708222, -0.995343, 0.985069, 0.698711, -0.180105, 0.999961, -0.768451, 0.993107, -0.918024, 0.0446961, 0.91882, 0.97691, -0.393915, 0.364803, 0.0495592, 0.186545, -0.461553, -0.242776, 0.901952, -0.0710866, 0.888101, 0.999935, 0.277688, 0.0554235, 0.506599, -0.299293, 0.984394, -0.999698, 0.408822, -0.782639, 0.128596, 0.198834, 0.981707, 0.864566, 0.808197, 0.352335, 0.970484, -0.667503, 0.330243, 0.208392, 0.191539, -0.938943, 0.895002, 0.910575, -0.537691, -0.98548, -0.721635, -0.335382, -0.424701, -0.960452, 0.595047, 0.783579, -0.937749, 0.529096, -0.997906, -0.581313, -0.899828, -0.88461, 0.989469, 0.91872, -0.850793, 0.955954, 0.715768, -0.736686, 0.80392, -0.717276, -0.788579, 0.987003, -0.839648, 0.885176, -0.998929, -0.0376033, -0.578371, -0.718771, 0.906081, 0.239947, -0.803563, -0.00826282, 0.991011, -0.0057943, -0.349232, 0.65319, 0.992067, -0.953535, 0.893781, 0.661689, 0.957253, -0.425442, -0.866609, 0.712892, -0.807777, 0.89632, -0.595147, -0.0224999, -0.643786, 0.545815, -0.870124, -0.696306, -0.99902, 0.773648, -0.806008, -0.931319, -0.780114, -0.552154, -0.933812, -0.563108, -0.619909, 0.966532, 0.692454, 0.993284, 0.338885, -0.75104, 0.237272, -0.713619, -0.160187, -0.199242, -0.371265, -0.781439, -0.914125, -0.944104, 0.169525, -0.984403, 0.976056, -0.265228, 0.94232, 0.993906, -0.877517, -0.89618, 0.611817, -0.106758, 0.680403, 0.163329, -0.325386, -0.0687362, -0.901164, 0.460314, 0.999981, -0.0408026, 0.850356, -0.763343, -0.170806, -0.102919, 0.581564, 0.688634, 0.284368, -0.276419, 0.616641, -0.929771, 0.927865, 0.440373, 0.153446, 0.840456, 0.996966, 0.867209, -0.135077, -0.493238, -0.577193, 0.0588088, 0.715215, 0.0143633 -}; - -static float g3[128*4] = { - -0.582745, 0.443494, -0.680971, 0, -0.601153, 0.791961, 0.106833, 0, -0.265466, 0.576385, -0.772857, 0, 0.981035, 0.0963612, -0.16818, 0, 0.524388, 0.819103, 0.232568, 0, -0.170518, -0.43875, 0.882282, 0, 0.598053, -0.435348, 0.672908, 0, 0.53956, 0.839346, -0.0661294, 0, -0.782511, -0.600267, -0.165398, 0, -0.122114, 0.968043, 0.219044, 0, -0.235567, 0.842331, -0.484755, 0, -0.158657, 0.504139, 0.848924, 0, -0.578396, 0.39317, -0.714756, 0, 0.883328, -0.337159, -0.325661, 0, 0.0597264, -0.0861552, 0.99449, 0, -0.970124, 0.233685, -0.0651921, 0, 0.208238, -0.858421, 0.468776, 0, 0.916908, -0.0997567, 0.38643, 0, -0.786568, -0.577957, -0.217431, 0, 0.14868, 0.618251, -0.77179, 0, -0.24168, 0.675858, 0.69628, 0, -0.50994, 0.83025, 0.225046, 0, -0.534183, -0.676382, -0.507107, 0, -0.793861, -0.6048, -0.0632565, 0, -0.92148, 0.240548, -0.304977, 0, -0.210037, 0.39862, -0.892741, 0, -0.310918, 0.339375, -0.887781, 0, 0.99836, 0.0466305, -0.0331999, 0, -0.0439099, 0.304806, 0.951402, 0, -0.676304, -0.440938, 0.590073, 0, 0.339805, -0.328495, 0.881263, 0, -0.0625568, 0.916832, 0.394342, 0, 0.776463, -0.630153, 0.00360388, 0, -0.224717, -0.8758, 0.427172, 0, 0.618879, -0.70266, -0.351081, 0, -0.380313, 0.101503, -0.919271, 0, 0.149639, -0.957418, 0.246897, 0, 0.128024, 0.948139, 0.290932, 0, -0.292448, 0.893976, -0.339532, 0, -0.192062, -0.972477, -0.131909, 0, 0.44007, -0.870905, 0.218776, 0, 0.303887, -0.659003, -0.688017, 0, 0.195552, 0.41876, -0.886792, 0, -0.889922, 0.454236, -0.0413315, 0, 0.515034, 0.225353, -0.827016, 0, 0.63084, -0.573408, -0.522728, 0, -0.745779, 0.549592, -0.376514, 0, 0.0711763, -0.979204, 0.189982, 0, 0.705657, 0.707887, 0.0307322, 0, 0.114603, 0.655735, -0.746242, 0, -0.0739232, -0.0135353, 0.997172, 0, 0.173356, -0.20818, 0.962605, 0, 0.34008, -0.787344, 0.514232, 0, -0.143596, 0.334295, -0.931465, 0, 0.721989, -0.30942, -0.618863, 0, -0.827657, 0.0410685, 0.559729, 0, -0.804277, -0.418454, 0.421942, 0, -0.379459, 0.792556, 0.477353, 0, 0.0391537, 0.0756503, 0.996365, 0, 0.821943, 0.237588, 0.517651, 0, -0.788974, 0.463584, -0.403249, 0, 0.175972, 0.984364, -0.00782073, 0, 0.891497, 0.399363, 0.213873, 0, -0.819111, 0.106216, 0.563716, 0, 0.105511, 0.544028, -0.832406, 0, -0.464551, 0.63753, 0.614612, 0, 0.232387, 0.935154, -0.267363, 0, 0.777619, 0.272068, -0.566823, 0, 0.975331, 0.190338, 0.111807, 0, 0.224313, 0.450072, -0.86436, 0, 0.841897, -0.536898, 0.0543103, 0, 0.637123, -0.664145, -0.391135, 0, 0.901675, -0.422984, 0.0898189, 0, -0.496241, 0.367413, -0.786608, 0, -0.255468, -0.689763, -0.677469, 0, -0.0616459, -0.951141, -0.302539, 0, -0.431011, -0.889035, -0.154425, 0, -0.0711688, 0.486502, -0.870776, 0, -0.223359, -0.36162, 0.905175, 0, -0.678546, 0.695482, -0.23639, 0, 0.576553, 0.77934, 0.245389, 0, -0.194568, -0.24951, 0.948624, 0, 0.28962, -0.447736, 0.845962, 0, -0.0403821, -0.871893, 0.488028, 0, 0.790972, -0.560788, 0.244705, 0, -0.34553, 0.739953, 0.57713, 0, -0.516376, -0.697122, 0.49737, 0, 0.115998, 0.859293, 0.498156, 0, 0.643831, -0.239955, 0.72657, 0, -0.125114, 0.987348, -0.0974144, 0, -0.306452, 0.610699, -0.73016, 0, -0.269845, 0.893027, -0.360119, 0, 0.328563, -0.570628, -0.752615, 0, -0.306918, -0.42057, 0.853769, 0, 0.699245, -0.51785, 0.492837, 0, -0.558362, -0.469763, -0.68378, 0, 0.476563, -0.841398, 0.254826, 0, 0.0276172, -0.623206, 0.78157, 0, 0.587723, -0.800313, -0.118659, 0, 0.594035, -0.740708, 0.313806, 0, -0.340185, -0.887929, 0.309605, 0, 0.312245, -0.246681, -0.917416, 0, 0.194206, 0.186398, -0.963089, 0, 0.915704, 0.329835, -0.229553, 0, 0.94133, 0.229917, 0.247055, 0, -0.888253, -0.144148, 0.436152, 0, -0.906917, -0.362625, -0.214486, 0, 0.403108, -0.908884, 0.10693, 0, 0.983963, 0.169256, 0.056292, 0, -0.197949, 0.888236, 0.414553, 0, 0.0879741, 0.247673, 0.964841, 0, 0.474384, -0.868071, -0.146331, 0, 0.699884, 0.541342, -0.465953, 0, 0.610965, 0.567249, 0.552223, 0, 0.830508, -0.285788, -0.478103, 0, 0.328573, -0.683076, -0.652263, 0, -0.00537775, 0.873381, 0.487009, 0, -0.51289, 0.828835, 0.223557, 0, -0.871168, -0.15102, 0.467182, 0, -0.545561, 0.390016, -0.741789, 0, 0.874063, 0.259258, 0.410852, 0, -0.781555, 0.612184, -0.120005, 0, -0.284928, 0.708938, -0.645154, 0, -0.568809, 0.0883274, 0.817713, 0, -0.0429388, 0.549957, -0.834088, 0, 0.933296, -0.127233, 0.335813, 0, 0.698149, -0.493464, 0.51873, 0, -0.603413, 0.617495, -0.504572, 0 -}; - -__forceinline float fade(float t) { - return (t * t * t) * (t * (t * 6 - 15) + 10); -} - -/*__forceinline float fade(float t) { - return t * t * (3 - t * 2); - }*/ - -__forceinline float lerp(float t, float a, float b) { - return a + t * (b - a); -} - -__forceinline float grad(int hash, float x) { - return x*g1[hash&127]; -} - -__forceinline float grad(int hash, float x, float y) { - int h = hash&127; - return x*g2[2*h+0]+y*g2[2*h+1]; -} - -__forceinline float grad(int hash, float x, float y, float z) { - int h = hash&127; - return x*g3[4*h+0]+y*g3[4*h+1]+z*g3[4*h+2]; -} - -float noise(float x) -{ - float fx = floorf(x); - int X = (int)fx & 255; - x -= fx; - float u = fade(x); - float g00 = grad(p[X ],x ); - float g10 = grad(p[X+1],x-1); - return lerp(u,g00,g10); -} - -float noise(float x, float y) -{ - float fx = floorf(x); - float fy = floorf(y); - - int X = (int)fx & 255; - int Y = (int)fy & 255; - - x -= fx; - y -= fy; - - float u = fade(x); - float v = fade(y); - - int p00 = p[X ]+Y; - int p10 = p[X+1]+Y; - int p01 = p[X ]+Y+1; - int p11 = p[X+1]+Y+1; - - float g00 = grad(p[p00],x ,y ); - float g10 = grad(p[p10],x-1,y ); - float g01 = grad(p[p01],x ,y-1); - float g11 = grad(p[p11],x-1,y-1); - - return lerp(v,lerp(u,g00,g10),lerp(u,g01,g11)); -} - -float noise(float x, float y, float z) -{ - float fx = floorf(x); - float fy = floorf(y); - float fz = floorf(z); - - int X = (int)fx & 255; - int Y = (int)fy & 255; - int Z = (int)fz & 255; - - x -= fx; - y -= fy; - z -= fz; - - float u = fade(x); - float v = fade(y); - float w = fade(z); - - int p00 = p[X]+Y; - int p000 = p[p00]+Z; - int p010 = p[p00+1]+Z; - int p001 = p000+1; - int p011 = p010+1; - int p10 = p[X+1]+Y; - int p100 = p[p10]+Z; - int p110 = p[p10+1]+Z; - int p101 = p100+1; - int p111 = p110+1; - - float g000 = grad(p[p000],x ,y ,z ); - float g100 = grad(p[p100],x-1,y ,z ); - float g010 = grad(p[p010],x ,y-1,z ); - float g110 = grad(p[p110],x-1,y-1,z ); - float g001 = grad(p[p001],x ,y ,z-1); - float g101 = grad(p[p101],x-1,y ,z-1); - float g011 = grad(p[p011],x ,y-1,z-1); - float g111 = grad(p[p111],x-1,y-1,z-1); - - return lerp(w, - lerp(v,lerp(u,g000,g100),lerp(u,g010,g110)), - lerp(v,lerp(u,g001,g101),lerp(u,g011,g111))); -} - - Vec3fa noise3D(const Vec3fa& p) - { - float x = noise(4.0f*p.x); - float y = noise(4.0f*p.y); - float z = noise(4.0f*p.z); - return p+0.2f*Vec3fa(x,y,z); - } - - void addHairySphere (OBJScene& scene, const Vec3fa& p, float r) - { - const size_t numPhi = 20; - const size_t numTheta = 2*numPhi; - OBJScene::Mesh* mesh = new OBJScene::Mesh; - - Material material; - int materialID = scene.materials.size(); - scene.materials.push_back(material); - - const float rcpNumTheta = rcp((float)numTheta); - const float rcpNumPhi = rcp((float)numPhi); - for (int phi=0; phi<=numPhi; phi++) - { - for (int theta=0; thetav. push_back(p+r*dp); - mesh->vn.push_back(dp); - } - if (phi == 0) continue; - - for (int theta=1; theta<=numTheta; theta++) - { - int p00 = (phi-1)*numTheta+theta-1; - int p01 = (phi-1)*numTheta+theta%numTheta; - int p10 = phi*numTheta+theta-1; - int p11 = phi*numTheta+theta%numTheta; - - if (phi > 1) - mesh->triangles.push_back(OBJScene::Triangle(p10,p00,p01,materialID)); - - if (phi < numPhi) - mesh->triangles.push_back(OBJScene::Triangle(p11,p10,p01,materialID)); - } - } - scene.meshes.push_back(mesh); - //generateHairOnTriangleMesh(scene,mesh,0.5f*r,0.001f*r,80); - -#if 0 - const float thickness = 0.01f*r; - OBJScene::HairSet* hairset = new OBJScene::HairSet; - srand48(123456789); - for (size_t t=0; t<16; t++) - { - Vec3fa dp = uniformSampleSphere(drand48(),drand48()); - - Vec3fa l0 = p + r* (dp + 0.00f*dp); l0.w = thickness; - Vec3fa l1 = p + r* (dp + 0.25f*dp); l1.w = thickness; - Vec3fa l2 = p + r*noise3D(dp + 0.50f*dp); l2.w = thickness; - Vec3fa l3 = p + r*noise3D(dp + 0.75f*dp); l3.w = thickness; - - const unsigned int v_index = hairset->v.size(); - hairset->v.push_back(l0); - hairset->v.push_back(l1); - hairset->v.push_back(l2); - hairset->v.push_back(l3); - - hairset->hairs.push_back( OBJScene::Hair(v_index,hairset->hairs.size()) ); - } - scene.hairsets.push_back(hairset); -#else - const float thickness = 0.001f*r; - OBJScene::HairSet* hairset = new OBJScene::HairSet; - - for (size_t t=0; t<100000; t++) - { - Vec3fa dp = uniformSampleSphere(drand48(),drand48()); - - Vec3fa l0 = p + r* (dp + 0.00f*dp); l0.w = thickness; - Vec3fa l1 = p + r* (dp + 0.25f*dp); l1.w = thickness; - Vec3fa l2 = p + r*noise3D(dp + 0.50f*dp); l2.w = thickness; - Vec3fa l3 = p + r*noise3D(dp + 0.75f*dp); l3.w = thickness; - - const unsigned int v_index = hairset->v.size(); - hairset->v.push_back(l0); - hairset->v.push_back(l1); - hairset->v.push_back(l2); - hairset->v.push_back(l3); - - hairset->hairs.push_back( OBJScene::Hair(v_index,hairset->hairs.size()) ); - } - scene.hairsets.push_back(hairset); -#endif - } - - void addGroundPlane (OBJScene& scene, const Vec3fa& p00, const Vec3fa& p01, const Vec3fa& p10, const Vec3fa& p11) - { - OBJScene::Mesh* mesh = new OBJScene::Mesh; - - Material material; - int materialID = scene.materials.size(); - scene.materials.push_back(material); - - mesh->v.push_back(p00); - mesh->v.push_back(p01); - mesh->v.push_back(p10); - mesh->v.push_back(p11); - - mesh->triangles.push_back(OBJScene::Triangle(0,1,2,materialID)); - mesh->triangles.push_back(OBJScene::Triangle(2,1,3,materialID)); - - scene.meshes.push_back(mesh); - } - - static void parseCommandLine(Ref cin, const FileName& path) - { - while (true) - { - std::string tag = cin->getString(); - if (tag == "") return; - - /* parse command line parameters from a file */ - if (tag == "-c") { - FileName file = path + cin->getFileName(); - parseCommandLine(new ParseStream(new LineCommentFilter(file, "#")), file.path()); - } - - /* load OBJ model */ - else if (tag == "-i") { - objFilename = path + cin->getFileName(); - } - - /* load motion blur OBJ model */ - else if (tag == "-i_mb") { - objFilename = path + cin->getFileName(); - objFilename2 = path + cin->getFileName(); - } - - /* load hair model */ - else if (tag == "--hair") { - hairFilename = path + cin->getFileName(); - } - - /* motion blur hair model */ - else if (tag == "--hair_mb") { - hairFilename = path + cin->getFileName(); - hairFilename2 = path + cin->getFileName(); - } - - /* load hair model */ - else if (tag == "--cy_hair") { - cy_hairFilename = path + cin->getFileName(); - } - - /* scene offset */ - else if (tag == "--offset") { - offset = cin->getVec3fa(); - } - - /* scene offset */ - else if (tag == "--offset_mb") { - offset_mb = cin->getVec3fa(); - } - - /* directional light */ - else if (tag == "--dirlight") { - g_dirlight_direction = normalize(cin->getVec3fa()); - g_dirlight_intensity = cin->getVec3fa(); - } - - /* ambient light */ - else if (tag == "--ambient") { - g_ambient_intensity = cin->getVec3fa(); - } - - /* output filename */ - else if (tag == "-o") { - outFilename = cin->getFileName(); - g_interactive = false; - } - - /* number of frames to render in benchmark mode */ - else if (tag == "-benchmark") { - g_skipBenchmarkFrames = cin->getInt(); - g_numBenchmarkFrames = cin->getInt(); - g_interactive = false; - } - - /* parse camera parameters */ - else if (tag == "-vp") { - g_camera.from = cin->getVec3fa(); - } - else if (tag == "-vi") g_camera.to = cin->getVec3fa(); - else if (tag == "-vd") g_camera.to = g_camera.from + cin->getVec3fa(); - else if (tag == "-vu") g_camera.up = cin->getVec3fa(); - else if (tag == "-fov") g_camera.fov = cin->getFloat(); - - /* frame buffer size */ - else if (tag == "-size") { - g_width = cin->getInt(); - g_height = cin->getInt(); - } - - /* full screen mode */ - else if (tag == "-fullscreen") - g_fullscreen = true; - - /* rtcore configuration */ - else if (tag == "-rtcore") - g_rtcore = cin->getString(); - - /* number of threads to use */ - else if (tag == "-threads") - g_numThreads = cin->getInt(); - - /* skip unknown command line parameter */ - else { - std::cerr << "unknown command line parameter: " << tag << " "; - while (cin->peek() != "" && cin->peek()[0] != '-') std::cerr << cin->getString() << " "; - std::cerr << std::endl; - } - } - } - - void renderBenchmark(const FileName& fileName) - { - resize(g_width,g_height); - AffineSpace3fa pixel2world = g_camera.pixel2world(g_width,g_height); - - double dt = 0.0f; - size_t numTotalFrames = g_skipBenchmarkFrames + g_numBenchmarkFrames; - for (size_t i=0; i= g_skipBenchmarkFrames) dt += t1-t0; - } - std::cout << "frame [" << g_skipBenchmarkFrames << " - " << numTotalFrames << "] " << std::flush; - std::cout << double(g_numBenchmarkFrames)/dt << "fps " << std::endl; - std::cout << "BENCHMARK_RENDER " << double(g_numBenchmarkFrames)/dt << std::endl; - } - - void renderToFile(const FileName& fileName) - { - resize(g_width,g_height); - AffineSpace3fa pixel2world = g_camera.pixel2world(g_width,g_height); - - render(0.0f, - pixel2world.l.vx, - pixel2world.l.vy, - pixel2world.l.vz, - pixel2world.p); - - void* ptr = map(); - Ref image = new Image4uc(g_width, g_height, (Col4uc*)ptr); - storeImage(image, fileName); - unmap(); - cleanup(); - } - - /* main function in embree namespace */ - int main(int argc, char** argv) - { - /* for best performance set FTZ and DAZ flags in MXCSR control and status register */ - _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); - _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); - - g_camera.from = Vec3fa(3.21034f,0.320831f,-0.162478f); - g_camera.to = Vec3fa(2.57003f,0.524887f, 0.163145f); - - g_camera.from = Vec3fa(-3,3,3); - g_camera.to = Vec3fa(0,1,0); - g_camera.up = Vec3fa(0,1,0); - - /* create stream for parsing */ - Ref stream = new ParseStream(new CommandLineStream(argc, argv)); - - /* parse command line */ - parseCommandLine(stream, FileName()); - if (g_numThreads) - g_rtcore += ",threads=" + std::to_string((long long)g_numThreads); - - /* initialize ray tracing core */ - init(g_rtcore.c_str()); - - /* load scene */ - if (objFilename.str() != "" && objFilename.str() != "none") { - Ref node = loadOBJ(objFilename,false); - g_obj_scene.add(new SceneGraph::TransformNode(AffineSpace3fa::translate(-offset),node)); - if (objFilename2.str() != "") { - Ref node = loadOBJ(objFilename2,false); - g_obj_scene2.add(new SceneGraph::TransformNode(AffineSpace3fa::translate(-offset_mb),node)); - } - } - - /* load hair */ - if (hairFilename.str() != "" && hairFilename.str() != "none") { - Ref node = loadHair(hairFilename); - g_obj_scene.add(new SceneGraph::TransformNode(AffineSpace3fa::translate(-offset),node)); - if (hairFilename2.str() != "") { - Ref node2 = loadHair(hairFilename2); - g_obj_scene2.add(new SceneGraph::TransformNode(AffineSpace3fa::translate(-offset_mb),node2)); - } - } - - /* load cy_hair */ - if (cy_hairFilename.str() != "") { - Ref node = loadCYHair(cy_hairFilename); - g_obj_scene.add(new SceneGraph::TransformNode(AffineSpace3fa::translate(-offset),node)); - } - - if (!g_obj_scene2.empty()) { - g_obj_scene.set_motion_blur(g_obj_scene2); - } - - /* if scene is empty, create default scene */ - if (g_obj_scene.meshes.size() + g_obj_scene.hairsets.size() == 0) { - addHairySphere(g_obj_scene,Vec3fa(0,1.5f,0),1.5f); - addGroundPlane(g_obj_scene,Vec3fa(-10,0,-10),Vec3fa(-10,0,+10),Vec3fa(+10,0,-10),Vec3fa(+10,0,+10)); - } - - /* send model */ - set_scene(&g_obj_scene); - - /* benchmark mode */ - if (g_numBenchmarkFrames) - renderBenchmark(outFilename); - - /* render to disk */ - if (outFilename.str() != "") - renderToFile(outFilename); - - /* interactive mode */ - if (g_interactive) { - initWindowState(argc,argv,tutorialName, g_width, g_height, g_fullscreen); - enterWindowRunLoop(); - } - - return 0; - } -} - -int main(int argc, char** argv) -{ - try { - return embree::main(argc, argv); - } - catch (const std::exception& e) { - std::cout << "Error: " << e.what() << std::endl; - return 1; - } - catch (...) { - std::cout << "Error: unknown exception caught." << std::endl; - return 1; - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/hair_geometry/hair_geometry_device.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/hair_geometry/hair_geometry_device.cpp deleted file mode 100644 index 1915fb561270..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/hair_geometry/hair_geometry_device.cpp +++ /dev/null @@ -1,607 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial_device.h" -#include "../common/tutorial/scene_device.h" - -#if defined(__XEON_PHI__) // FIXME: gather of pointers not working in ISPC for Xeon Phi -#define renderPixelTestEyeLight renderPixelStandard -#else -#define renderPixelPathTrace renderPixelStandard -#endif - -/* accumulation buffer */ -Vec3fa* g_accu = nullptr; -size_t g_accu_width = 0; -size_t g_accu_height = 0; -size_t g_accu_count = 0; -Vec3fa g_accu_vx; -Vec3fa g_accu_vy; -Vec3fa g_accu_vz; -Vec3fa g_accu_p; -extern "C" bool g_changed; -bool g_subdiv_mode = false; - -/* light settings */ -extern "C" Vec3fa g_dirlight_direction; -extern "C" Vec3fa g_dirlight_intensity; -extern "C" Vec3fa g_ambient_intensity; - -/* hair material */ -Vec3fa hair_K; -Vec3fa hair_dK; -Vec3fa hair_Kr; //!< reflectivity of hair -Vec3fa hair_Kt; //!< transparency of hair - -void filterDispatch(void* ptr, struct RTCRay2& ray); - -/* scene data */ -extern "C" ISPCScene* g_ispc_scene; -RTCDevice g_device = nullptr; -RTCScene g_scene = nullptr; - -/* error reporting function */ -void error_handler(const RTCError code, const char* str) -{ - printf("Embree: "); - switch (code) { - case RTC_UNKNOWN_ERROR : printf("RTC_UNKNOWN_ERROR"); break; - case RTC_INVALID_ARGUMENT : printf("RTC_INVALID_ARGUMENT"); break; - case RTC_INVALID_OPERATION: printf("RTC_INVALID_OPERATION"); break; - case RTC_OUT_OF_MEMORY : printf("RTC_OUT_OF_MEMORY"); break; - case RTC_UNSUPPORTED_CPU : printf("RTC_UNSUPPORTED_CPU"); break; - case RTC_CANCELLED : printf("RTC_CANCELLED"); break; - default : printf("invalid error code"); break; - } - if (str) { - printf(" ("); - while (*str) putchar(*str++); - printf(")\n"); - } - exit(1); -} - -/* render function to use */ -renderPixelFunc renderPixel; - -Vec3fa renderPixelTestEyeLight(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p); - -/*! random number generator for floating point numbers in range [0,1] */ -inline float frand(int& seed) { - seed = 7 * seed + 5; - return (seed & 0xFFFF)/(float)0xFFFF; -} - -/*! Uniform hemisphere sampling. Up direction is the z direction. */ -Vec3fa sampleSphere(const float u, const float v) -{ - const float phi = 2.0f*(float)pi * u; - const float cosTheta = 1.0f - 2.0f * v, sinTheta = 2.0f * sqrt(v * (1.0f - v)); - return Vec3fa(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta, float(one_over_four_pi)); -} - -RTCScene convertScene(ISPCScene* scene_in) -{ - //scene_in->numHairSets = 0; - //scene_in->numMeshes = 0; - - /* create scene */ - RTCScene scene_out = rtcDeviceNewScene(g_device, RTC_SCENE_STATIC | RTC_SCENE_INCOHERENT, RTC_INTERSECT1); - - /* add all hair sets to the scene */ - for (int i=0; inumHairSets; i++) - { - ISPCHairSet* hair = scene_in->hairs[i]; - unsigned int geomID = rtcNewHairGeometry (scene_out, RTC_GEOMETRY_STATIC, hair->numHairs, hair->numVertices, hair->v2 ? 2 : 1); - rtcSetBuffer(scene_out,geomID,RTC_VERTEX_BUFFER,hair->v,0,sizeof(Vertex)); - if (hair->v2) rtcSetBuffer(scene_out,geomID,RTC_VERTEX_BUFFER1,hair->v2,0,sizeof(Vertex)); - rtcSetBuffer(scene_out,geomID,RTC_INDEX_BUFFER,hair->hairs,0,sizeof(ISPCHair)); - rtcSetOcclusionFilterFunction(scene_out,geomID,(RTCFilterFunc)&filterDispatch); - } - - /* add all triangle meshes to the scene */ - for (int i=0; inumMeshes; i++) - { - ISPCMesh* mesh = scene_in->meshes[i]; - unsigned int geomID = rtcNewTriangleMesh (scene_out, RTC_GEOMETRY_STATIC, mesh->numTriangles, mesh->numVertices, mesh->positions2 ? 2 : 1); - rtcSetBuffer(scene_out,geomID,RTC_VERTEX_BUFFER,mesh->positions,0,sizeof(Vertex)); - if (mesh->positions2) rtcSetBuffer(scene_out,geomID,RTC_VERTEX_BUFFER1,mesh->positions2,0,sizeof(Vertex)); - rtcSetBuffer(scene_out,geomID,RTC_INDEX_BUFFER,mesh->triangles,0,sizeof(ISPCTriangle)); - rtcSetOcclusionFilterFunction(scene_out,geomID,(RTCFilterFunc)&filterDispatch); - } - - /* commit changes to scene */ - rtcCommit (scene_out); - - return scene_out; -} - -////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////// - - -/* called by the C++ code for initialization */ -extern "C" void device_init (char* cfg) -{ - /* initialize last seen camera */ - g_accu_vx = Vec3fa(0.0f); - g_accu_vy = Vec3fa(0.0f); - g_accu_vz = Vec3fa(0.0f); - g_accu_p = Vec3fa(0.0f); - - /* initialize hair colors */ - hair_K = Vec3fa(0.8f,0.57f,0.32f); - hair_dK = Vec3fa(0.1f,0.12f,0.08f); - hair_Kr = 0.2f*hair_K; //!< reflectivity of hair - hair_Kt = 0.8f*hair_K; //!< transparency of hair - - /* create new Embree device */ - g_device = rtcNewDevice(cfg); - - /* set error handler */ - rtcDeviceSetErrorFunction(g_device,error_handler); - - /* set start render mode */ - renderPixel = renderPixelStandard; - key_pressed_handler = device_key_pressed_default; -} - -#if !defined(__XEON_PHI__) - -/*! Anisotropic power cosine microfacet distribution. */ -struct AnisotropicBlinn { - Vec3fa dx; //!< x-direction of the distribution. - float nx; //!< Glossiness in x direction with range [0,infinity[ where 0 is a diffuse surface. - Vec3fa dy; //!< y-direction of the distribution. - float ny; //!< Exponent that determines the glossiness in y direction. - Vec3fa dz; //!< z-direction of the distribution. - float norm1; //!< Normalization constant for calculating the pdf for sampling. - float norm2; //!< Normalization constant for calculating the distribution. - Vec3fa Kr,Kt; - float side; -}; - - /*! Anisotropic power cosine distribution constructor. */ -inline void AnisotropicBlinn__Constructor(AnisotropicBlinn* This, const Vec3fa& Kr, const Vec3fa& Kt, - const Vec3fa& dx, float nx, const Vec3fa& dy, float ny, const Vec3fa& dz) -{ - This->Kr = Kr; - This->Kt = Kt; - This->dx = dx; - This->nx = nx; - This->dy = dy; - This->ny = ny; - This->dz = dz; - This->norm1 = sqrtf((nx+1)*(ny+1)) * float(one_over_two_pi); - This->norm2 = sqrtf((nx+2)*(ny+2)) * float(one_over_two_pi); - This->side = reduce_max(Kr)/(reduce_max(Kr)+reduce_max(Kt)); -} - -/*! Evaluates the power cosine distribution. \param wh is the half - * vector */ -inline float AnisotropicBlinn__eval(const AnisotropicBlinn* This, const Vec3fa& wh) -{ - const float cosPhiH = dot(wh, This->dx); - const float sinPhiH = dot(wh, This->dy); - const float cosThetaH = dot(wh, This->dz); - const float R = sqr(cosPhiH)+sqr(sinPhiH); - if (R == 0.0f) return This->norm2; - const float n = (This->nx*sqr(cosPhiH)+This->ny*sqr(sinPhiH))*rcp(R); - return This->norm2 * pow(abs(cosThetaH), n); -} - -/*! Samples the distribution. \param s is the sample location - * provided by the caller. */ -inline Vec3fa AnisotropicBlinn__sample(const AnisotropicBlinn* This, const float sx, const float sy) -{ - const float phi =float(two_pi)*sx; - const float sinPhi0 = sqrtf(This->nx+1)*sinf(phi); - const float cosPhi0 = sqrtf(This->ny+1)*cosf(phi); - const float norm = rsqrt(sqr(sinPhi0)+sqr(cosPhi0)); - const float sinPhi = sinPhi0*norm; - const float cosPhi = cosPhi0*norm; - const float n = This->nx*sqr(cosPhi)+This->ny*sqr(sinPhi); - const float cosTheta = powf(sy,rcp(n+1)); - const float sinTheta = cos2sin(cosTheta); - const float pdf = This->norm1*powf(cosTheta,n); - const Vec3fa h = Vec3fa(cosPhi * sinTheta, sinPhi * sinTheta, cosTheta); - const Vec3fa wh = h.x*This->dx + h.y*This->dy + h.z*This->dz; - return Vec3fa(wh,pdf); -} - -inline Vec3fa AnisotropicBlinn__eval(const AnisotropicBlinn* This, const Vec3fa& wo, const Vec3fa& wi) -{ - const float cosThetaI = dot(wi,This->dz); - - /* reflection */ - if (cosThetaI > 0.0f) { - const Vec3fa wh = normalize(wi + wo); - return This->Kr * AnisotropicBlinn__eval(This,wh) * abs(cosThetaI); - } - - /* transmission */ - else { - const Vec3fa wh = normalize(reflect(wi,This->dz) + wo); - return This->Kt * AnisotropicBlinn__eval(This,wh) * abs(cosThetaI); - } -} - -inline Vec3fa AnisotropicBlinn__sample(const AnisotropicBlinn* This, const Vec3fa& wo, Vec3fa& wi, const float sx, const float sy, const float sz) -{ - //wi = Vec3fa(reflect(normalize(wo),normalize(dz)),1.0f); return Kr; - //wi = Vec3fa(neg(wo),1.0f); return Kt; - const Vec3fa wh = AnisotropicBlinn__sample(This,sx,sy); - //if (dot(wo,wh) < 0.0f) return Vec3fa(0.0f,0.0f); - - /* reflection */ - if (sz < This->side) { - wi = Vec3fa(reflect(wo,Vec3fa(wh)),wh.w*This->side); - const float cosThetaI = dot(Vec3fa(wi),This->dz); - return This->Kr * AnisotropicBlinn__eval(This,Vec3fa(wh)) * abs(cosThetaI); - } - - /* transmission */ - else { - wi = Vec3fa(reflect(reflect(wo,Vec3fa(wh)),This->dz),wh.w*(1-This->side)); - const float cosThetaI = dot(Vec3fa(wi),This->dz); - return This->Kt * AnisotropicBlinn__eval(This,Vec3fa(wh)) * abs(cosThetaI); - } -} - -typedef Vec3fa*_Vec3fa_ptr; - -inline Vec3fa evalBezier(const int geomID, const int primID, const float t) -{ - const float t0 = 1.0f - t, t1 = t; - const ISPCHairSet* hair = g_ispc_scene->hairs[geomID]; - const Vec3fa* vertices = hair->v; - const ISPCHair* hairs = hair->hairs; - - const int i = hairs[primID].vertex; - const Vec3fa p00 = vertices[i+0]; - const Vec3fa p01 = vertices[i+1]; - const Vec3fa p02 = vertices[i+2]; - const Vec3fa p03 = vertices[i+3]; - - const Vec3fa p10 = p00 * t0 + p01 * t1; - const Vec3fa p11 = p01 * t0 + p02 * t1; - const Vec3fa p12 = p02 * t0 + p03 * t1; - const Vec3fa p20 = p10 * t0 + p11 * t1; - const Vec3fa p21 = p11 * t0 + p12 * t1; - const Vec3fa p30 = p20 * t0 + p21 * t1; - - return p30; - //tangent = p21-p20; -} - -#endif - -/* extended ray structure that includes total transparency along the ray */ -struct RTCRay2 -{ - Vec3fa org; //!< Ray origin - Vec3fa dir; //!< Ray direction - float tnear; //!< Start of ray segment - float tfar; //!< End of ray segment - float time; //!< Time of this ray for motion blur. - int mask; //!< used to mask out objects during traversal - Vec3fa Ng; //!< Geometric normal. - float u; //!< Barycentric u coordinate of hit - float v; //!< Barycentric v coordinate of hit - int geomID; //!< geometry ID - int primID; //!< primitive ID - int instID; //!< instance ID - - // ray extensions - RTCFilterFunc filter; - Vec3fa transparency; //!< accumulated transparency value -}; - -bool enableFilterDispatch = false; - -/* filter dispatch function */ -void filterDispatch(void* ptr, RTCRay2& ray) { - if (!enableFilterDispatch) return; - if (ray.filter) ray.filter(ptr,*((RTCRay*)&ray)); // FIXME: use RTCRay& cast -} - -#if !defined(__XEON_PHI__) - -/* occlusion filter function */ -void occlusionFilter(void* ptr, RTCRay2& ray) -{ - /* make all surfaces opaque */ - if (ray.geomID >= g_ispc_scene->numHairSets) { - ray.transparency = Vec3fa(0.0f); - return; - } - Vec3fa T = hair_Kt; - T = T * ray.transparency; // FIXME: use *= operator - ray.transparency = T; - if (ne(T,Vec3fa(0.0f))) ray.geomID = RTC_INVALID_GEOMETRY_ID; // FIXME: use != operator -} - -Vec3fa occluded(RTCScene scene, RTCRay2& ray) -{ - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.primID = RTC_INVALID_GEOMETRY_ID; - ray.mask = -1; - ray.filter = (RTCFilterFunc) &occlusionFilter; - ray.transparency = Vec3fa(1.0f); - rtcOccluded(scene,*((RTCRay*)&ray)); // FIXME: use (RTCRay&) cast - - return ray.transparency; -} - -/* task that renders a single screen tile */ -Vec3fa renderPixelPathTrace(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p) -{ - int seed = 21344*x+121233*y+234532*g_accu_count; - float time = frand(seed); - - /* initialize ray */ - RTCRay2 ray; - ray.org = p; - ray.dir = normalize(x*vx + y*vy + vz); - ray.tnear = 0.0f; - ray.tfar = inf; - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.primID = RTC_INVALID_GEOMETRY_ID; - ray.mask = -1; - ray.time = time; - ray.filter = nullptr; - - Vec3fa color = Vec3fa(0.0f); - Vec3fa weight = Vec3fa(1.0f); - size_t depth = 0; - - while (true) - { - /* terminate ray path */ - if (reduce_max(weight) < 0.01 || depth > 20) - return color; - - /* intersect ray with scene and gather all hits */ - rtcIntersect(g_scene,*((RTCRay*)&ray)); // FIXME: use (RTCRay&) cast - - /* exit if we hit environment */ - if (ray.geomID == RTC_INVALID_GEOMETRY_ID) - return color + weight*Vec3fa(g_ambient_intensity); - - /* calculate transmissivity of hair */ - AnisotropicBlinn brdf; - float tnear_eps = 0.0001f; - - if (ray.geomID < g_ispc_scene->numHairSets) - { - /* calculate tangent space */ - const Vec3fa dx = normalize(ray.Ng); - const Vec3fa dy = normalize(cross(ray.dir,dx)); - const Vec3fa dz = normalize(cross(dy,dx)); - - /* generate anisotropic BRDF */ - AnisotropicBlinn__Constructor(&brdf,hair_Kr,hair_Kt,dx,20.0f,dy,2.0f,dz); - brdf.Kr = hair_Kr; - Vec3fa p = evalBezier(ray.geomID,ray.primID,ray.u); - tnear_eps = 1.1f*p.w; - } - else - { - int meshID = ray.geomID-g_ispc_scene->numHairSets; - ISPCMesh* mesh = g_ispc_scene->meshes[meshID]; - - ISPCTriangle* triangle = &mesh->triangles[ray.primID]; - OBJMaterial* material = (OBJMaterial*) &g_ispc_scene->materials[triangle->materialID]; - - if (dot(ray.dir,ray.Ng) > 0) ray.Ng = neg(ray.Ng); - - /* calculate tangent space */ - const Vec3fa dz = normalize(ray.Ng); - const Vec3fa dx = normalize(cross(dz,ray.dir)); - const Vec3fa dy = normalize(cross(dz,dx)); - - /* generate isotropic BRDF */ - AnisotropicBlinn__Constructor(&brdf,Vec3fa(1.0f),Vec3fa(0.0f),dx,1.0f,dy,1.0f,dz); - } - - /* sample directional light */ - RTCRay2 shadow; - shadow.org = ray.org + ray.tfar*ray.dir; - shadow.dir = neg(Vec3fa(g_dirlight_direction)); - shadow.tnear = tnear_eps; - shadow.tfar = inf; - shadow.time = time; - Vec3fa T = occluded(g_scene,shadow); - Vec3fa c = AnisotropicBlinn__eval(&brdf,neg(ray.dir),neg(Vec3fa(g_dirlight_direction))); - color = color + weight*c*T*Vec3fa(g_dirlight_intensity); // FIXME: use += operator - -#if 1 - /* sample BRDF */ - Vec3fa wi; - c = AnisotropicBlinn__sample(&brdf,neg(ray.dir),wi,frand(seed),frand(seed),frand(seed)); - if (wi.w <= 0.0f) return color; - - /* calculate secondary ray and offset it out of the hair */ - float sign = dot(Vec3fa(wi),brdf.dz) < 0.0f ? -1.0f : 1.0f; - ray.org = ray.org + ray.tfar*ray.dir + sign*tnear_eps*brdf.dz; - ray.dir = Vec3fa(wi); - ray.tnear = 0.001f; - ray.tfar = inf; - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.primID = RTC_INVALID_GEOMETRY_ID; - ray.mask = -1; - ray.time = time; - ray.filter = nullptr; - weight = weight * c/wi.w; // FIXME: use *= operator - -#else - - /* continue with transparency ray */ - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.tnear = 1.001f*ray.tfar; - ray.tfar = inf; - weight *= brdf.Kt; - -#endif - - depth++; - } - return color; -} - -#endif - -Vec3fa renderPixelTestEyeLight(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p) -{ - /* initialize ray */ - RTCRay2 ray; - ray.org = p; - ray.dir = normalize(x*vx + y*vy + vz); - Vec3fa dir1 = normalize((x+1)*vx + (y+1)*vy + vz); - ray.tnear = 0.0f; - ray.tfar = inf; - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.primID = RTC_INVALID_GEOMETRY_ID; - ray.mask = -1; - ray.time = 0; - - Vec3fa color = Vec3fa(0.0f); - float weight = 1.0f; - - rtcIntersect(g_scene,*((RTCRay*)&ray)); // FIXME: use (RTCRay&) cast - ray.filter = nullptr; - - if (ray.primID == -1) - return Vec3fa(0.0f); - - Vec3fa Ng; - if (ray.geomID < g_ispc_scene->numHairSets) - { - const Vec3fa dx = normalize(ray.Ng); - const Vec3fa dy = normalize(cross(ray.dir,dx)); - const Vec3fa dz = normalize(cross(dy,dx)); - Ng = dz; - } - else - { - if (dot(ray.dir,ray.Ng) > 0) ray.Ng = neg(ray.Ng); - const Vec3fa dz = normalize(ray.Ng); - const Vec3fa dx = normalize(cross(dz,ray.dir)); - const Vec3fa dy = normalize(cross(dz,dx)); - Ng = dz; - } - - color = color + Vec3fa(0.2f + 0.5f * abs(dot(ray.dir,Ng))); // FIXME: use += operator - return color; -} - -/* task that renders a single screen tile */ -void renderTile(int taskIndex, int* pixels, - const int width, - const int height, - const float time, - const Vec3fa& vx, - const Vec3fa& vy, - const Vec3fa& vz, - const Vec3fa& p, - const int numTilesX, - const int numTilesY) -{ - const int tileY = taskIndex / numTilesX; - const int tileX = taskIndex - tileY * numTilesX; - const int x0 = tileX * TILE_SIZE_X; - const int x1 = min(x0+TILE_SIZE_X,width); - const int y0 = tileY * TILE_SIZE_Y; - const int y1 = min(y0+TILE_SIZE_Y,height); - //int seed = tileY*numTilesX+tileX+0 + g_accu_count; - int seed = (tileY*numTilesX+tileX+0) * g_accu_count; - - for (int y = y0; yw)); - unsigned int r = (unsigned int) (255.0f * clamp(dst->x*f,0.0f,1.0f)); - unsigned int g = (unsigned int) (255.0f * clamp(dst->y*f,0.0f,1.0f)); - unsigned int b = (unsigned int) (255.0f * clamp(dst->z*f,0.0f,1.0f)); - pixels[y*width+x] = (b << 16) + (g << 8) + r; - } -} - -/* called by the C++ code to render */ -extern "C" void device_render (int* pixels, - const int width, - const int height, - const float time, - const Vec3fa& vx, - const Vec3fa& vy, - const Vec3fa& vz, - const Vec3fa& p) -{ - /* create scene */ - if (g_scene == nullptr) - g_scene = convertScene(g_ispc_scene); - - /* create accumulator */ - if (g_accu_width != width || g_accu_height != height) { - g_accu = (Vec3fa*) alignedMalloc(width*height*sizeof(Vec3fa)); - g_accu_width = width; - g_accu_height = height; - memset(g_accu,0,width*height*sizeof(Vec3fa)); - } - - /* reset accumulator */ - bool camera_changed = g_changed; g_changed = false; - camera_changed |= ne(g_accu_vx,vx); g_accu_vx = vx; // FIXME: use != operator - camera_changed |= ne(g_accu_vy,vy); g_accu_vy = vy; // FIXME: use != operator - camera_changed |= ne(g_accu_vz,vz); g_accu_vz = vz; // FIXME: use != operator - camera_changed |= ne(g_accu_p, p); g_accu_p = p; // FIXME: use != operator - g_accu_count++; - if (camera_changed) { - g_accu_count=0; - memset(g_accu,0,width*height*sizeof(Vec3fa)); - } - - /* render frame */ - const int numTilesX = (width +TILE_SIZE_X-1)/TILE_SIZE_X; - const int numTilesY = (height+TILE_SIZE_Y-1)/TILE_SIZE_Y; - enableFilterDispatch = renderPixel == renderPixelStandard; - launch_renderTile(numTilesX*numTilesY,pixels,width,height,time,vx,vy,vz,p,numTilesX,numTilesY); - enableFilterDispatch = false; -} - -/* called by the C++ code for cleanup */ -extern "C" void device_cleanup () -{ - rtcDeleteScene (g_scene); - rtcDeleteDevice(g_device); -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/instanced_geometry/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/instanced_geometry/CMakeLists.txt deleted file mode 100644 index 4fe432934ae2..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/instanced_geometry/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2015 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -INCLUDE(tutorial) -ADD_TUTORIAL(instanced_geometry) diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/instanced_geometry/instanced_geometry.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/instanced_geometry/instanced_geometry.cpp deleted file mode 100644 index df329c16d053..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/instanced_geometry/instanced_geometry.cpp +++ /dev/null @@ -1,155 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial.h" -#include "../common/image/image.h" - -namespace embree -{ - /* name of the tutorial */ - const char* tutorialName = "instanced_geometry"; - - /* configuration */ - static std::string g_rtcore = ""; - static size_t g_numThreads = 0; - - /* output settings */ - static size_t g_width = 512; - static size_t g_height = 512; - static bool g_fullscreen = false; - static FileName outFilename = ""; - - static void parseCommandLine(Ref cin, const FileName& path) - { - while (true) - { - std::string tag = cin->getString(); - if (tag == "") return; - - /* parse command line parameters from a file */ - if (tag == "-c") { - FileName file = path + cin->getFileName(); - parseCommandLine(new ParseStream(new LineCommentFilter(file, "#")), file.path()); - } - - /* parse camera parameters */ - else if (tag == "-vp") g_camera.from = cin->getVec3fa(); - else if (tag == "-vi") g_camera.to = cin->getVec3fa(); - else if (tag == "-vd") g_camera.to = g_camera.from + cin->getVec3fa(); - else if (tag == "-vu") g_camera.up = cin->getVec3fa(); - else if (tag == "-fov") g_camera.fov = cin->getFloat(); - - /* frame buffer size */ - else if (tag == "-size") { - g_width = cin->getInt(); - g_height = cin->getInt(); - } - - /* full screen mode */ - else if (tag == "-fullscreen") - g_fullscreen = true; - - /* output filename */ - else if (tag == "-o") - outFilename = cin->getFileName(); - - /* rtcore configuration */ - else if (tag == "-rtcore") - g_rtcore = cin->getString(); - - /* number of threads to use */ - else if (tag == "-threads") - g_numThreads = cin->getInt(); - - /* skip unknown command line parameter */ - else { - std::cerr << "unknown command line parameter: " << tag << " "; - while (cin->peek() != "" && cin->peek()[0] != '-') std::cerr << cin->getString() << " "; - std::cerr << std::endl; - } - } - } - - void renderToFile(const FileName& fileName) - { - resize(g_width,g_height); - AffineSpace3fa pixel2world = g_camera.pixel2world(g_width,g_height); - - render(0.0f, - pixel2world.l.vx, - pixel2world.l.vy, - pixel2world.l.vz, - pixel2world.p); - - void* ptr = map(); - Ref image = new Image4uc(g_width, g_height, (Col4uc*)ptr); - storeImage(image, fileName); - unmap(); - cleanup(); - } - - /* main function in embree namespace */ - int main(int argc, char** argv) - { - /* for best performance set FTZ and DAZ flags in MXCSR control and status register */ - _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); - _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); - - /* set default camera */ - g_camera.from = Vec3fa(2.5f,2.5f,2.5f); - g_camera.to = Vec3fa(0.0f,0.0f,0.0f); - - /* create stream for parsing */ - Ref stream = new ParseStream(new CommandLineStream(argc, argv)); - - /* parse command line */ - parseCommandLine(stream, FileName()); - if (g_numThreads) - g_rtcore += ",threads=" + std::to_string((long long)g_numThreads); - - /* initialize ray tracing core */ - init(g_rtcore.c_str()); - - /* render to disk */ - if (outFilename.str() != "") { - renderToFile(outFilename); - return 0; - } - - /* initialize GLUT */ - initWindowState(argc,argv,tutorialName, g_width, g_height, g_fullscreen); - - /* enter the GLUT run loop */ - enterWindowRunLoop(); - - return 0; - } -} - -int main(int argc, char** argv) -{ - try { - return embree::main(argc, argv); - } - catch (const std::exception& e) { - std::cout << "Error: " << e.what() << std::endl; - return 1; - } - catch (...) { - std::cout << "Error: unknown exception caught." << std::endl; - return 1; - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/instanced_geometry/instanced_geometry_device.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/instanced_geometry/instanced_geometry_device.cpp deleted file mode 100644 index 4ded95e27981..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/instanced_geometry/instanced_geometry_device.cpp +++ /dev/null @@ -1,316 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial_device.h" - -/* render function to use */ -renderPixelFunc renderPixel; - -/* error reporting function */ -void error_handler(const RTCError code, const char* str) -{ - printf("Embree: "); - switch (code) { - case RTC_UNKNOWN_ERROR : printf("RTC_UNKNOWN_ERROR"); break; - case RTC_INVALID_ARGUMENT : printf("RTC_INVALID_ARGUMENT"); break; - case RTC_INVALID_OPERATION: printf("RTC_INVALID_OPERATION"); break; - case RTC_OUT_OF_MEMORY : printf("RTC_OUT_OF_MEMORY"); break; - case RTC_UNSUPPORTED_CPU : printf("RTC_UNSUPPORTED_CPU"); break; - case RTC_CANCELLED : printf("RTC_CANCELLED"); break; - default : printf("invalid error code"); break; - } - if (str) { - printf(" ("); - while (*str) putchar(*str++); - printf(")\n"); - } - exit(1); -} - -const int numPhi = 5; -const int numTheta = 2*numPhi; - -unsigned int createTriangulatedSphere (RTCScene scene, const Vec3fa& p, float r) -{ - /* create triangle mesh */ - unsigned int mesh = rtcNewTriangleMesh (scene, RTC_GEOMETRY_STATIC, 2*numTheta*(numPhi-1), numTheta*(numPhi+1)); - - /* map triangle and vertex buffers */ - Vertex* vertices = (Vertex*) rtcMapBuffer(scene,mesh,RTC_VERTEX_BUFFER); - Triangle* triangles = (Triangle*) rtcMapBuffer(scene,mesh,RTC_INDEX_BUFFER); - - /* create sphere */ - int tri = 0; - const float rcpNumTheta = rcp((float)numTheta); - const float rcpNumPhi = rcp((float)numPhi); - for (int phi=0; phi<=numPhi; phi++) - { - for (int theta=0; theta 1) { - triangles[tri].v0 = p10; - triangles[tri].v1 = p00; - triangles[tri].v2 = p01; - tri++; - } - - if (phi < numPhi) { - triangles[tri].v0 = p11; - triangles[tri].v1 = p10; - triangles[tri].v2 = p01; - tri++; - } - } - } - rtcUnmapBuffer(scene,mesh,RTC_VERTEX_BUFFER); - rtcUnmapBuffer(scene,mesh,RTC_INDEX_BUFFER); - return mesh; -} - -/* creates a ground plane */ -unsigned int createGroundPlane (RTCScene scene) -{ - /* create a triangulated plane with 2 triangles and 4 vertices */ - unsigned int mesh = rtcNewTriangleMesh (scene, RTC_GEOMETRY_STATIC, 2, 4); - - /* set vertices */ - Vertex* vertices = (Vertex*) rtcMapBuffer(scene,mesh,RTC_VERTEX_BUFFER); - vertices[0].x = -10; vertices[0].y = -2; vertices[0].z = -10; - vertices[1].x = -10; vertices[1].y = -2; vertices[1].z = +10; - vertices[2].x = +10; vertices[2].y = -2; vertices[2].z = -10; - vertices[3].x = +10; vertices[3].y = -2; vertices[3].z = +10; - rtcUnmapBuffer(scene,mesh,RTC_VERTEX_BUFFER); - - /* set triangles */ - Triangle* triangles = (Triangle*) rtcMapBuffer(scene,mesh,RTC_INDEX_BUFFER); - triangles[0].v0 = 0; triangles[0].v1 = 2; triangles[0].v2 = 1; - triangles[1].v0 = 1; triangles[1].v1 = 2; triangles[1].v2 = 3; - rtcUnmapBuffer(scene,mesh,RTC_INDEX_BUFFER); - - return mesh; -} - -/* scene data */ -RTCDevice g_device = nullptr; -RTCScene g_scene = nullptr; -RTCScene g_scene1 = nullptr; - -unsigned int g_instance0 = -1; -unsigned int g_instance1 = -1; -unsigned int g_instance2 = -1; -unsigned int g_instance3 = -1; - -Vec3fa colors[4][4]; - -/* called by the C++ code for initialization */ -extern "C" void device_init (char* cfg) -{ - /* create new Embree device */ - g_device = rtcNewDevice(cfg); - - /* set error handler */ - rtcDeviceSetErrorFunction(g_device,error_handler); - - /* create scene */ - g_scene = rtcDeviceNewScene(g_device, RTC_SCENE_DYNAMIC,RTC_INTERSECT1); - - /* create scene with 4 triangulated spheres */ - g_scene1 = rtcDeviceNewScene(g_device, RTC_SCENE_STATIC,RTC_INTERSECT1); - createTriangulatedSphere(g_scene1,Vec3fa( 0, 0,+1),0.5); - createTriangulatedSphere(g_scene1,Vec3fa(+1, 0, 0),0.5); - createTriangulatedSphere(g_scene1,Vec3fa( 0, 0,-1),0.5); - createTriangulatedSphere(g_scene1,Vec3fa(-1, 0, 0),0.5); - rtcCommit (g_scene1); - - /* instantiate geometry */ - g_instance0 = rtcNewInstance(g_scene,g_scene1); - g_instance1 = rtcNewInstance(g_scene,g_scene1); - g_instance2 = rtcNewInstance(g_scene,g_scene1); - g_instance3 = rtcNewInstance(g_scene,g_scene1); - createGroundPlane(g_scene); - - /* set all colors */ - colors[0][0] = Vec3fa(0.25,0,0); - colors[0][1] = Vec3fa(0.50,0,0); - colors[0][2] = Vec3fa(0.75,0,0); - colors[0][3] = Vec3fa(1.00,0,0); - - colors[1][0] = Vec3fa(0,0.25,0); - colors[1][1] = Vec3fa(0,0.50,0); - colors[1][2] = Vec3fa(0,0.75,0); - colors[1][3] = Vec3fa(0,1.00,0); - - colors[2][0] = Vec3fa(0,0,0.25); - colors[2][1] = Vec3fa(0,0,0.50); - colors[2][2] = Vec3fa(0,0,0.75); - colors[2][3] = Vec3fa(0,0,1.00); - - colors[3][0] = Vec3fa(0.25,0.25,0); - colors[3][1] = Vec3fa(0.50,0.50,0); - colors[3][2] = Vec3fa(0.75,0.75,0); - colors[3][3] = Vec3fa(1.00,1.00,0); - - /* set start render mode */ - renderPixel = renderPixelStandard; - key_pressed_handler = device_key_pressed_default; -} - -/* task that renders a single screen tile */ -Vec3fa renderPixelStandard(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p) -{ - /* initialize ray */ - RTCRay ray; - ray.org = p; - ray.dir = normalize(x*vx + y*vy + vz); - ray.tnear = 0.0f; - ray.tfar = inf; - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.primID = RTC_INVALID_GEOMETRY_ID; - ray.instID = -1; - ray.mask = -1; - ray.time = 0; - - /* intersect ray with scene */ - rtcIntersect(g_scene,ray); - - /* shade pixels */ - Vec3fa color = Vec3fa(0.0f); - if (ray.geomID != RTC_INVALID_GEOMETRY_ID) - { - Vec3fa diffuse = Vec3fa(1,1,1); - if (ray.instID != -1) - diffuse = colors[ray.instID][ray.geomID]; - color = color + diffuse*0.5; // FIXME: += - Vec3fa lightDir = normalize(Vec3fa(-1,-1,-1)); - - /* initialize shadow ray */ - RTCRay shadow; - shadow.org = ray.org + ray.tfar*ray.dir; - shadow.dir = neg(lightDir); - shadow.tnear = 0.001f; - shadow.tfar = inf; - shadow.geomID = 1; - shadow.primID = 0; - shadow.mask = -1; - shadow.time = 0; - - /* trace shadow ray */ - rtcOccluded(g_scene,shadow); - - /* add light contribution */ - if (shadow.geomID) - color = color + diffuse*clamp(-dot(lightDir,normalize(ray.Ng)),0.0f,1.0f); // FIXME: += - } - return color; -} - -/* task that renders a single screen tile */ -void renderTile(int taskIndex, int* pixels, - const int width, - const int height, - const float time, - const Vec3fa& vx, - const Vec3fa& vy, - const Vec3fa& vz, - const Vec3fa& p, - const int numTilesX, - const int numTilesY) -{ - const int tileY = taskIndex / numTilesX; - const int tileX = taskIndex - tileY * numTilesX; - const int x0 = tileX * TILE_SIZE_X; - const int x1 = min(x0+TILE_SIZE_X,width); - const int y0 = tileY * TILE_SIZE_Y; - const int y1 = min(y0+TILE_SIZE_Y,height); - - for (int y = y0; y cin, const FileName& path) - { - while (true) - { - std::string tag = cin->getString(); - if (tag == "") return; - - /* parse command line parameters from a file */ - if (tag == "-c") { - FileName file = path + cin->getFileName(); - parseCommandLine(new ParseStream(new LineCommentFilter(file, "#")), file.path()); - } - - /* parse camera parameters */ - else if (tag == "-vp") g_camera.from = cin->getVec3fa(); - else if (tag == "-vi") g_camera.to = cin->getVec3fa(); - else if (tag == "-vd") g_camera.to = g_camera.from + cin->getVec3fa(); - else if (tag == "-vu") g_camera.up = cin->getVec3fa(); - else if (tag == "-fov") g_camera.fov = cin->getFloat(); - - /* frame buffer size */ - else if (tag == "-size") { - g_width = cin->getInt(); - g_height = cin->getInt(); - } - - /* full screen mode */ - else if (tag == "-fullscreen") - g_fullscreen = true; - - /* output filename */ - else if (tag == "-o") { - outFilename = cin->getFileName(); - g_interactive = false; - } - - /* rtcore configuration */ - else if (tag == "-rtcore") - g_rtcore = cin->getString(); - - /* number of threads to use */ - else if (tag == "-threads") - g_numThreads = cin->getInt(); - - /* number of frames to render in benchmark mode */ - else if (tag == "-benchmark") { - g_skipBenchmarkFrames = cin->getInt(); - g_numBenchmarkFrames = cin->getInt(); - g_interactive = false; - } - - /* skip unknown command line parameter */ - else { - std::cerr << "unknown command line parameter: " << tag << " "; - while (cin->peek() != "" && cin->peek()[0] != '-') std::cerr << cin->getString() << " "; - std::cerr << std::endl; - } - } - } - - void renderBenchmark(const FileName& fileName) - { - resize(g_width,g_height); - AffineSpace3fa pixel2world = g_camera.pixel2world(g_width,g_height); - - double dt = 0.0f; - size_t numTotalFrames = g_skipBenchmarkFrames + g_numBenchmarkFrames; - for (size_t i=0; i= g_skipBenchmarkFrames) dt += t1-t0; - } - std::cout << "frame [" << g_skipBenchmarkFrames << " - " << numTotalFrames << "] " << std::flush; - std::cout << double(g_numBenchmarkFrames)/dt << "fps " << std::endl; - std::cout << "BENCHMARK_RENDER " << double(g_numBenchmarkFrames)/dt << std::endl; - } - - void renderToFile(const FileName& fileName) - { - resize(g_width,g_height); - AffineSpace3fa pixel2world = g_camera.pixel2world(g_width,g_height); - - render(0.0f, - pixel2world.l.vx, - pixel2world.l.vy, - pixel2world.l.vz, - pixel2world.p); - - void* ptr = map(); - Ref image = new Image4uc(g_width, g_height, (Col4uc*)ptr); - storeImage(image, fileName); - unmap(); - } - - /* main function in embree namespace */ - int main(int argc, char** argv) - { - /* for best performance set FTZ and DAZ flags in MXCSR control and status register */ - _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); - _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); - - /* set default camera */ - g_camera.from = Vec3fa(7.0f,2.0f,1.0f); - g_camera.to = Vec3fa(0.0f,0.0f,1.0f); - - /* create stream for parsing */ - Ref stream = new ParseStream(new CommandLineStream(argc, argv)); - - /* parse command line */ - parseCommandLine(stream, FileName()); - if (g_numThreads) - g_rtcore += ",threads=" + std::to_string((long long)g_numThreads); - //if (g_numBenchmarkFrames) - //g_rtcore += ",benchmark=1"; - - /* initialize ray tracing core */ - init(g_rtcore.c_str()); - - /* benchmark mode */ - if (g_numBenchmarkFrames) - renderBenchmark(outFilename); - - /* render to disk */ - if (outFilename.str() != "") { - renderToFile(outFilename); - return 0; - } - - /* interactive mode */ - if (g_interactive) { - initWindowState(argc,argv,tutorialName, g_width, g_height, g_fullscreen); - enterWindowRunLoop(); - } - - return 0; - } -} - -int main(int argc, char** argv) -{ - try { - return embree::main(argc, argv); - } - catch (const std::exception& e) { - std::cout << "Error: " << e.what() << std::endl; - return 1; - } - catch (...) { - std::cout << "Error: unknown exception caught." << std::endl; - return 1; - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/interpolation/interpolation_device.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/interpolation/interpolation_device.cpp deleted file mode 100644 index 07cc4b75da76..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/interpolation/interpolation_device.cpp +++ /dev/null @@ -1,484 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial_device.h" - -//#define FORCE_FIXED_EDGE_TESSELLATION -#define FIXED_EDGE_TESSELLATION_VALUE 16 - -#define MAX_EDGE_LEVEL 64.0f -#define MIN_EDGE_LEVEL 4.0f -#define LEVEL_FACTOR 128.0f - - -/* scene data */ -RTCDevice g_device = nullptr; -RTCScene g_scene = nullptr; -Vec3fa* vertex_colors = nullptr; -unsigned int triCubeID, quadCubeID, quadCubeID2; - -/* render function to use */ -renderPixelFunc renderPixel; - -/* error reporting function */ -void error_handler(const RTCError code, const char* str) -{ - printf("Embree: "); - switch (code) { - case RTC_UNKNOWN_ERROR : printf("RTC_UNKNOWN_ERROR"); break; - case RTC_INVALID_ARGUMENT : printf("RTC_INVALID_ARGUMENT"); break; - case RTC_INVALID_OPERATION: printf("RTC_INVALID_OPERATION"); break; - case RTC_OUT_OF_MEMORY : printf("RTC_OUT_OF_MEMORY"); break; - case RTC_UNSUPPORTED_CPU : printf("RTC_UNSUPPORTED_CPU"); break; - case RTC_CANCELLED : printf("RTC_CANCELLED"); break; - default : printf("invalid error code"); break; - } - if (str) { - printf(" ("); - while (*str) putchar(*str++); - printf(")\n"); - } - exit(1); -} - -#define NUM_VERTICES 8 - -__aligned(16) float cube_vertices[8][4] = -{ - { -1.0f, -1.0f, -1.0f, 0.0f }, - { 1.0f, -1.0f, -1.0f, 0.0f }, - { 1.0f, -1.0f, 1.0f, 0.0f }, - { -1.0f, -1.0f, 1.0f, 0.0f }, - { -1.0f, 1.0f, -1.0f, 0.0f }, - { 1.0f, 1.0f, -1.0f, 0.0f }, - { 1.0f, 1.0f, 1.0f, 0.0f }, - { -1.0f, 1.0f, 1.0f, 0.0f } -}; - -__aligned(16) float cube_vertex_colors[8][4] = -{ - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 1.0f, 0.0f, 0.0f, 0.0f }, - { 1.0f, 0.0f, 1.0f, 0.0f }, - { 0.0f, 0.0f, 1.0f, 0.0f }, - { 0.0f, 1.0f, 0.0f, 0.0f }, - { 1.0f, 1.0f, 0.0f, 0.0f }, - { 1.0f, 1.0f, 1.0f, 0.0f }, - { 0.0f, 1.0f, 1.0f, 0.0f } -}; - -__aligned(16) float cube_vertex_crease_weights[8] = { - inf, inf,inf, inf, inf, inf, inf, inf -}; - -__aligned(16) unsigned int cube_vertex_crease_indices[8] = { - 0,1,2,3,4,5,6,7 -}; - -__aligned(16) float cube_edge_crease_weights[12] = { - inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf -}; - -__aligned(16) unsigned int cube_edge_crease_indices[24] = -{ - 0,1, 1,2, 2,3, 3,0, - 4,5, 5,6, 6,7, 7,4, - 0,4, 1,5, 2,6, 3,7, -}; - -#define NUM_QUAD_INDICES 24 -#define NUM_QUAD_FACES 6 - -unsigned int cube_quad_indices[24] = { - 0, 1, 5, 4, - 1, 2, 6, 5, - 2, 3, 7, 6, - 0, 4, 7, 3, - 4, 5, 6, 7, - 0, 3, 2, 1, -}; - -unsigned int cube_quad_faces[6] = { - 4, 4, 4, 4, 4, 4 -}; - -#define NUM_TRI_INDICES 36 -#define NUM_TRI_FACES 12 - -unsigned int cube_tri_indices[36] = { - 1, 5, 4, 0, 1, 4, - 2, 6, 5, 1, 2, 5, - 3, 7, 6, 2, 3, 6, - 4, 7, 3, 0, 4, 3, - 5, 6, 7, 4, 5, 7, - 3, 2, 1, 0, 3, 1 -}; - -unsigned int cube_tri_faces[12] = { - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 -}; - -#define NUM_HAIR_VERTICES 4 - -__aligned(16) float hair_vertices[4][4] = -{ - { 0.0f, 0.0f, 0.0f, 0.1f }, - { 0.5f, 1.0f, 0.0f, 0.1f }, - { 0.0f, 2.0f, -0.5f, 0.1f }, - { 0.0f, 3.0f, 0.0f, 0.1f } -}; - -__aligned(16) float hair_vertex_colors[4][4] = -{ - { 1.0f, 0.0f, 0.0f, 0.0f }, - { 1.0f, 1.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 1.0f, 0.0f }, - { 1.0f, 1.0f, 1.0f, 0.0f }, -}; - -unsigned int hair_indices[1] = { - 0 -}; - -inline float updateEdgeLevel(const Vec3fa& cam_pos, Vec3fa* vtx, unsigned int* indices, const size_t e0, const size_t e1) -{ - const Vec3fa v0 = vtx[indices[e0]]; - const Vec3fa v1 = vtx[indices[e1]]; - const Vec3fa edge = v1-v0; - const Vec3fa P = 0.5f*(v1+v0); - const Vec3fa dist = cam_pos - P; - const float level = max(min(LEVEL_FACTOR*(0.5f*length(edge)/length(dist)),MAX_EDGE_LEVEL),MIN_EDGE_LEVEL); - return level; -} - -/* adds a subdiv cube to the scene */ -unsigned int addTriangleSubdivCube (RTCScene scene_i, const Vec3fa& pos) -{ - unsigned int geomID = rtcNewSubdivisionMesh(scene_i, RTC_GEOMETRY_DYNAMIC, NUM_TRI_FACES, NUM_TRI_INDICES, NUM_VERTICES, 0, 0, 0); - - //rtcSetBuffer(scene_i, geomID, RTC_VERTEX_BUFFER, cube_vertices, 0, sizeof(Vec3fa )); - Vec3fa* vtx = (Vec3fa*) rtcMapBuffer(scene_i, geomID, RTC_VERTEX_BUFFER); - for (size_t i=0; i 0) - { - int geomID = ray.geomID; { - int geom = geomID == quadCubeID ? quadCubeID2 : geomID; // use special interpolation mesh - rtcInterpolate(g_scene,geom,ray.primID,ray.u,ray.v,RTC_USER_VERTEX_BUFFER0,&diffuse.x,nullptr,nullptr,3); - } - //return diffuse; - diffuse = 0.5f*diffuse; - } - - /* calculate smooth shading normal */ - Vec3fa Ng = ray.Ng; - if (ray.geomID >= 3) { - Vec3fa dPdu,dPdv; - int geomID = ray.geomID; { - rtcInterpolate(g_scene,geomID,ray.primID,ray.u,ray.v,RTC_VERTEX_BUFFER0,nullptr,&dPdu.x,&dPdv.x,3); - } - //return dPdu; - Ng = cross(dPdv,dPdu); - } - Ng = normalize(Ng); - color = color + diffuse*0.5f; // FIXME: += - Vec3fa lightDir = normalize(Vec3fa(-1,-1,-1)); - - /* initialize shadow ray */ - RTCRay shadow; - shadow.org = ray.org + ray.tfar*ray.dir; - shadow.dir = neg(lightDir); - shadow.tnear = 0.001f; - shadow.tfar = inf; - shadow.geomID = 1; - shadow.primID = 0; - shadow.mask = -1; - shadow.time = 0; - - /* trace shadow ray */ - rtcOccluded(g_scene,shadow); - - /* add light contribution */ - if (shadow.geomID) { - Vec3fa r = normalize(reflect(ray.dir,Ng)); - float s = pow(clamp(dot(r,lightDir),0.0f,1.0f),10.0f); - float d = clamp(-dot(lightDir,Ng),0.0f,1.0f); - color = color + diffuse*d + 0.5f*Vec3fa(s); // FIXME: += - } - } - return color; -} - -/* task that renders a single screen tile */ -void renderTile(int taskIndex, int* pixels, - const int width, - const int height, - const float time, - const Vec3fa& vx, - const Vec3fa& vy, - const Vec3fa& vz, - const Vec3fa& p, - const int numTilesX, - const int numTilesY) -{ - const int tileY = taskIndex / numTilesX; - const int tileX = taskIndex - tileY * numTilesX; - const int x0 = tileX * TILE_SIZE_X; - const int x1 = min(x0+TILE_SIZE_X,width); - const int y0 = tileY * TILE_SIZE_Y; - const int y1 = min(y0+TILE_SIZE_Y,height); - - for (int y = y0; y cin, const FileName& path) - { - while (true) - { - std::string tag = cin->getString(); - if (tag == "") return; - - /* parse command line parameters from a file */ - if (tag == "-c") { - FileName file = path + cin->getFileName(); - parseCommandLine(new ParseStream(new LineCommentFilter(file, "#")), file.path()); - } - - /* parse camera parameters */ - else if (tag == "-vp") g_camera.from = cin->getVec3fa(); - else if (tag == "-vi") g_camera.to = cin->getVec3fa(); - else if (tag == "-vd") g_camera.to = g_camera.from + cin->getVec3fa(); - else if (tag == "-vu") g_camera.up = cin->getVec3fa(); - else if (tag == "-fov") g_camera.fov = cin->getFloat(); - - /* frame buffer size */ - else if (tag == "-size") { - g_width = cin->getInt(); - g_height = cin->getInt(); - } - - /* full screen mode */ - else if (tag == "-fullscreen") - g_fullscreen = true; - - /* output filename */ - else if (tag == "-o") - outFilename = cin->getFileName(); - - /* rtcore configuration */ - else if (tag == "-rtcore") - g_rtcore = cin->getString(); - - /* number of threads to use */ - else if (tag == "-threads") - g_numThreads = cin->getInt(); - - /* skip unknown command line parameter */ - else { - std::cerr << "unknown command line parameter: " << tag << " "; - while (cin->peek() != "" && cin->peek()[0] != '-') std::cerr << cin->getString() << " "; - std::cerr << std::endl; - } - } - } - - void renderToFile(const FileName& fileName) - { - resize(g_width,g_height); - AffineSpace3fa pixel2world = g_camera.pixel2world(g_width,g_height); - - render(0.0f, - pixel2world.l.vx, - pixel2world.l.vy, - pixel2world.l.vz, - pixel2world.p); - - void* ptr = map(); - Ref image = new Image4uc(g_width, g_height, (Col4uc*)ptr); - storeImage(image, fileName); - unmap(); - cleanup(); - } - - /* main function in embree namespace */ - int main(int argc, char** argv) - { - /* for best performance set FTZ and DAZ flags in MXCSR control and status register */ - _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); - _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); - - /* set default camera */ - g_camera.from = Vec3fa(1.4f,1.3f,-1.5f); - g_camera.to = Vec3fa(0.0f,0.0f,0.0f); - - /* create stream for parsing */ - Ref stream = new ParseStream(new CommandLineStream(argc, argv)); - - /* parse command line */ - parseCommandLine(stream, FileName()); - if (g_numThreads) - g_rtcore += ",threads=" + std::to_string((long long)g_numThreads); - - /* initialize ray tracing core */ - init(g_rtcore.c_str()); - - /* render to disk */ - if (outFilename.str() != "") { - renderToFile(outFilename); - return 0; - } - - /* initialize GLUT */ - initWindowState(argc,argv,tutorialName, g_width, g_height, g_fullscreen); - - /* enter the GLUT run loop */ - enterWindowRunLoop(); - - return 0; - } -} - -int main(int argc, char** argv) -{ - try { - return embree::main(argc, argv); - } - catch (const std::exception& e) { - std::cout << "Error: " << e.what() << std::endl; - return 1; - } - catch (...) { - std::cout << "Error: unknown exception caught." << std::endl; - return 1; - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/intersection_filter/intersection_filter_device.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/intersection_filter/intersection_filter_device.cpp deleted file mode 100644 index f4bbfa3d6477..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/intersection_filter/intersection_filter_device.cpp +++ /dev/null @@ -1,361 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial_device.h" - -/* scene data */ -RTCDevice g_device = nullptr; -RTCScene g_scene = nullptr; -Vec3fa* colors = nullptr; - -/* render function to use */ -renderPixelFunc renderPixel; - -/* error reporting function */ -void error_handler(const RTCError code, const char* str) -{ - printf("Embree: "); - switch (code) { - case RTC_UNKNOWN_ERROR : printf("RTC_UNKNOWN_ERROR"); break; - case RTC_INVALID_ARGUMENT : printf("RTC_INVALID_ARGUMENT"); break; - case RTC_INVALID_OPERATION: printf("RTC_INVALID_OPERATION"); break; - case RTC_OUT_OF_MEMORY : printf("RTC_OUT_OF_MEMORY"); break; - case RTC_UNSUPPORTED_CPU : printf("RTC_UNSUPPORTED_CPU"); break; - case RTC_CANCELLED : printf("RTC_CANCELLED"); break; - default : printf("invalid error code"); break; - } - if (str) { - printf(" ("); - while (*str) putchar(*str++); - printf(")\n"); - } - exit(1); -} - -#define NUM_VERTICES 8 -#define NUM_QUAD_INDICES 24 -#define NUM_TRI_INDICES 36 -#define NUM_QUAD_FACES 6 -#define NUM_TRI_FACES 12 - -__aligned(16) float cube_vertices[NUM_VERTICES][4] = -{ - { -1, -1, -1, 0 }, - { -1, -1, +1, 0 }, - { -1, +1, -1, 0 }, - { -1, +1, +1, 0 }, - { +1, -1, -1, 0 }, - { +1, -1, +1, 0 }, - { +1, +1, -1, 0 }, - { +1, +1, +1, 0 }, -}; - -unsigned int cube_quad_indices[NUM_QUAD_INDICES] = { - 0, 2, 3, 1, - 5, 7, 6, 4, - 0, 1, 5, 4, - 6, 7, 3, 2, - 0, 4, 6, 2, - 3, 7, 5, 1 -}; - -unsigned int cube_tri_indices[NUM_TRI_INDICES] = { - 0, 2, 1, 2, 3, 1, - 5, 7, 4, 7, 6, 4, - 0, 1, 4, 1, 5, 4, - 6, 7, 2, 7, 3, 2, - 0, 4, 2, 4, 6, 2, - 3, 7, 1, 7, 5, 1 -}; - -unsigned int cube_quad_faces[NUM_QUAD_FACES] = { - 4, 4, 4, 4, 4, 4 -}; - -/* extended ray structure that includes total transparency along the ray */ -struct RTCRay2 -{ - Vec3fa org; //!< Ray origin - Vec3fa dir; //!< Ray direction - float tnear; //!< Start of ray segment - float tfar; //!< End of ray segment - float time; //!< Time of this ray for motion blur. - int mask; //!< used to mask out objects during traversal - Vec3fa Ng; //!< Geometric normal. - float u; //!< Barycentric u coordinate of hit - float v; //!< Barycentric v coordinate of hit - int geomID; //!< geometry ID - int primID; //!< primitive ID - int instID; //!< instance ID - - // ray extensions - float transparency; //!< accumulated transparency value -}; - -/* 3D procedural transparency */ -inline float transparencyFunction(RTCRay2& ray) -{ - Vec3fa h = ray.org + ray.dir*ray.tfar; - float v = abs(sin(4.0f*h.x)*cos(4.0f*h.y)*sin(4.0f*h.z)); - float T = clamp((v-0.1f)*3.0f,0.0f,1.0f); - return T; -} - -/* intersection filter function */ -void intersectionFilter(void* ptr, RTCRay2& ray) -{ - float T = transparencyFunction(ray); - if (T >= 1.0f) ray.geomID = RTC_INVALID_GEOMETRY_ID; - else ray.transparency = T; -} - -/* occlusion filter function */ -void occlusionFilter(void* ptr, RTCRay2& ray) -{ - float T = transparencyFunction(ray); - T *= ray.transparency; - ray.transparency = T; - if (T != 0.0f) ray.geomID = RTC_INVALID_GEOMETRY_ID; -} - -/* adds a cube to the scene */ -unsigned int addCube (RTCScene scene_i) -{ - /* create a triangulated cube with 12 triangles and 8 vertices */ - unsigned int geomID = rtcNewTriangleMesh (scene_i, RTC_GEOMETRY_STATIC, NUM_TRI_FACES, NUM_VERTICES); - rtcSetBuffer(scene_i, geomID, RTC_VERTEX_BUFFER, cube_vertices, 0, sizeof(Vec3fa )); - rtcSetBuffer(scene_i, geomID, RTC_INDEX_BUFFER, cube_tri_indices , 0, 3*sizeof(unsigned int)); - - /* create per-triangle color array */ - colors = (Vec3fa*) alignedMalloc(12*sizeof(Vec3fa)); - colors[0] = Vec3fa(1,0,0); // left side - colors[1] = Vec3fa(1,0,0); - colors[2] = Vec3fa(0,1,0); // right side - colors[3] = Vec3fa(0,1,0); - colors[4] = Vec3fa(0.5f); // bottom side - colors[5] = Vec3fa(0.5f); - colors[6] = Vec3fa(1.0f); // top side - colors[7] = Vec3fa(1.0f); - colors[8] = Vec3fa(0,0,1); // front side - colors[9] = Vec3fa(0,0,1); - colors[10] = Vec3fa(1,1,0); // back side - colors[11] = Vec3fa(1,1,0); - - /* set intersection filter for the cube */ - rtcSetIntersectionFilterFunction(scene_i,geomID,(RTCFilterFunc)&intersectionFilter); - rtcSetOcclusionFilterFunction (scene_i,geomID,(RTCFilterFunc)&occlusionFilter); - - return geomID; -} - -/* adds a cube to the scene */ -unsigned int addSubdivCube (RTCScene scene_i) -{ - unsigned int geomID = rtcNewSubdivisionMesh(scene_i, RTC_GEOMETRY_STATIC, NUM_QUAD_FACES, NUM_QUAD_INDICES, NUM_VERTICES, 0, 0, 0); - rtcSetBuffer(scene_i, geomID, RTC_VERTEX_BUFFER, cube_vertices, 0, sizeof(Vec3fa )); - rtcSetBuffer(scene_i, geomID, RTC_INDEX_BUFFER, cube_quad_indices , 0, sizeof(unsigned int)); - rtcSetBuffer(scene_i, geomID, RTC_FACE_BUFFER, cube_quad_faces, 0, sizeof(unsigned int)); - - float* level = (float*) rtcMapBuffer(scene_i, geomID, RTC_LEVEL_BUFFER); - for (size_t i=0; i= numMaterials) continue;//g' $2 -sed -i.backup 's/foreach_unique (geomID in ray.geomID)/int geomID = ray.geomID; /g' $2 - -sed -i.backup 's/foreach_unique (id in materialID)//g' $2 -sed -i.backup 's/ISPCMaterial\* material = \&materials\[id\];/ISPCMaterial\* material = \&materials\[materialID\];/g' $2 -sed -i.backup 's/\#define __device__//g' $2 -sed -i.backup 's/__device__//g' $2 - -sed -i.backup 's/make_Ray/RTCRay/g' $2 - -sed -i.backup 's/\#define PARALLEL_COMMIT//g' $2 -sed -i.backup 's/atomic_compare_exchange_global/atomic_cmpxchg/g' $2 -sed -i.backup 's/memory_barrier/__memory_barrier/g' $2 - -sed -i.backup 's/make_LinearSpace3f_rotate/LinearSpace3f::rotate/g' $2 -sed -i.backup 's/LinearSpace3f/LinearSpace3fa/g' $2 - -sed -i.backup 's/make_AffineSpace3f_rotate/AffineSpace3f::rotate/g' $2 -sed -i.backup 's/AffineSpace3f/AffineSpace3fa/g' $2 - -sed -i.backup 's/int8/char/g' $2 -sed -i.backup 's/int16/int16_t/g' $2 -sed -i.backup 's/int32/int32_t/g' $2 diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/lazy_geometry/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/lazy_geometry/CMakeLists.txt deleted file mode 100644 index 46d71f8aa2c2..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/lazy_geometry/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2015 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -INCLUDE(tutorial) -ADD_TUTORIAL(lazy_geometry) diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/lazy_geometry/lazy_geometry.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/lazy_geometry/lazy_geometry.cpp deleted file mode 100644 index 8c2c29be098e..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/lazy_geometry/lazy_geometry.cpp +++ /dev/null @@ -1,155 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial.h" -#include "../common/image/image.h" - -namespace embree -{ - /* name of the tutorial */ - const char* tutorialName = "lazy_geometry"; - - /* configuration */ - static std::string g_rtcore = ""; - static size_t g_numThreads = 0; - - /* output settings */ - static size_t g_width = 512; - static size_t g_height = 512; - static bool g_fullscreen = false; - static FileName outFilename = ""; - - static void parseCommandLine(Ref cin, const FileName& path) - { - while (true) - { - std::string tag = cin->getString(); - if (tag == "") return; - - /* parse command line parameters from a file */ - if (tag == "-c") { - FileName file = path + cin->getFileName(); - parseCommandLine(new ParseStream(new LineCommentFilter(file, "#")), file.path()); - } - - /* parse camera parameters */ - else if (tag == "-vp") g_camera.from = cin->getVec3fa(); - else if (tag == "-vi") g_camera.to = cin->getVec3fa(); - else if (tag == "-vd") g_camera.to = g_camera.from + cin->getVec3fa(); - else if (tag == "-vu") g_camera.up = cin->getVec3fa(); - else if (tag == "-fov") g_camera.fov = cin->getFloat(); - - /* frame buffer size */ - else if (tag == "-size") { - g_width = cin->getInt(); - g_height = cin->getInt(); - } - - /* full screen mode */ - else if (tag == "-fullscreen") - g_fullscreen = true; - - /* output filename */ - else if (tag == "-o") - outFilename = cin->getFileName(); - - /* rtcore configuration */ - else if (tag == "-rtcore") - g_rtcore = cin->getString(); - - /* number of threads to use */ - else if (tag == "-threads") - g_numThreads = cin->getInt(); - - /* skip unknown command line parameter */ - else { - std::cerr << "unknown command line parameter: " << tag << " "; - while (cin->peek() != "" && cin->peek()[0] != '-') std::cerr << cin->getString() << " "; - std::cerr << std::endl; - } - } - } - - void renderToFile(const FileName& fileName) - { - resize(g_width,g_height); - AffineSpace3fa pixel2world = g_camera.pixel2world(g_width,g_height); - - render(0.0f, - pixel2world.l.vx, - pixel2world.l.vy, - pixel2world.l.vz, - pixel2world.p); - - void* ptr = map(); - Ref image = new Image4uc(g_width, g_height, (Col4uc*)ptr); - storeImage(image, fileName); - unmap(); - cleanup(); - } - - /* main function in embree namespace */ - int main(int argc, char** argv) - { - /* for best performance set FTZ and DAZ flags in MXCSR control and status register */ - _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); - _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); - - /* set default camera */ - g_camera.from = Vec3fa(2.5f,2.5f,2.5f); - g_camera.to = Vec3fa(0.0f,0.0f,0.0f); - - /* create stream for parsing */ - Ref stream = new ParseStream(new CommandLineStream(argc, argv)); - - /* parse command line */ - parseCommandLine(stream, FileName()); - if (g_numThreads) - g_rtcore += ",threads=" + std::to_string((long long)g_numThreads); - - /* initialize ray tracing core */ - init(g_rtcore.c_str()); - - /* render to disk */ - if (outFilename.str() != "") { - renderToFile(outFilename); - return 0; - } - - /* initialize GLUT */ - initWindowState(argc,argv,tutorialName, g_width, g_height, g_fullscreen); - - /* enter the GLUT run loop */ - enterWindowRunLoop(); - - return 0; - } -} - -int main(int argc, char** argv) -{ - try { - return embree::main(argc, argv); - } - catch (const std::exception& e) { - std::cout << "Error: " << e.what() << std::endl; - return 1; - } - catch (...) { - std::cout << "Error: unknown exception caught." << std::endl; - return 1; - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/lazy_geometry/lazy_geometry_device.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/lazy_geometry/lazy_geometry_device.cpp deleted file mode 100644 index 25b5a37175f6..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/lazy_geometry/lazy_geometry_device.cpp +++ /dev/null @@ -1,357 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial_device.h" - -RTCDevice g_device = nullptr; - -const int numPhi = 20; -const int numTheta = 2*numPhi; -const int numSpheres = 64; - -/* render function to use */ -renderPixelFunc renderPixel; - -/* error reporting function */ -void error_handler(const RTCError code, const char* str) -{ - printf("Embree: "); - switch (code) { - case RTC_UNKNOWN_ERROR : printf("RTC_UNKNOWN_ERROR"); break; - case RTC_INVALID_ARGUMENT : printf("RTC_INVALID_ARGUMENT"); break; - case RTC_INVALID_OPERATION: printf("RTC_INVALID_OPERATION"); break; - case RTC_OUT_OF_MEMORY : printf("RTC_OUT_OF_MEMORY"); break; - case RTC_UNSUPPORTED_CPU : printf("RTC_UNSUPPORTED_CPU"); break; - case RTC_CANCELLED : printf("RTC_CANCELLED"); break; - default : printf("invalid error code"); break; - } - if (str) { - printf(" ("); - while (*str) putchar(*str++); - printf(")\n"); - } - exit(1); -} - -/* state of the lazy geometry */ -enum LazyState -{ - LAZY_INVALID = 0, // the geometry is not yet created - LAZY_CREATE = 1, // one thread is creating the geometry - LAZY_COMMIT = 2, // possible multiple threads are committing the geometry - LAZY_VALID = 3 // the geometry is created -}; - -/* representation for our lazy geometry */ -struct LazyGeometry -{ - ALIGNED_STRUCT - unsigned int geometry; - LazyState state; - RTCScene object; - int userID; - Vec3fa center; - float radius; -}; - -void instanceBoundsFunc(const LazyGeometry* instance, size_t item, RTCBounds* bounds_o) -{ - Vec3fa lower = instance->center-Vec3fa(instance->radius); - Vec3fa upper = instance->center+Vec3fa(instance->radius); - bounds_o->lower_x = lower.x; - bounds_o->lower_y = lower.y; - bounds_o->lower_z = lower.z; - bounds_o->upper_x = upper.x; - bounds_o->upper_y = upper.y; - bounds_o->upper_z = upper.z; -} - -unsigned int createTriangulatedSphere (RTCScene scene, const Vec3fa& p, float r) -{ - /* create triangle mesh */ - unsigned int mesh = rtcNewTriangleMesh (scene, RTC_GEOMETRY_STATIC, 2*numTheta*(numPhi-1), numTheta*(numPhi+1)); - - /* map triangle and vertex buffers */ - Vertex* vertices = (Vertex*) rtcMapBuffer(scene,mesh,RTC_VERTEX_BUFFER); - Triangle* triangles = (Triangle*) rtcMapBuffer(scene,mesh,RTC_INDEX_BUFFER); - - /* create sphere */ - int tri = 0; - const float rcpNumTheta = rcp((float)numTheta); - const float rcpNumPhi = rcp((float)numPhi); - for (int phi=0; phi<=numPhi; phi++) - { - for (int theta=0; theta 1) { - triangles[tri].v0 = p10; - triangles[tri].v1 = p00; - triangles[tri].v2 = p01; - tri++; - } - - if (phi < numPhi) { - triangles[tri].v0 = p11; - triangles[tri].v1 = p10; - triangles[tri].v2 = p01; - tri++; - } - } - } - rtcUnmapBuffer(scene,mesh,RTC_VERTEX_BUFFER); - rtcUnmapBuffer(scene,mesh,RTC_INDEX_BUFFER); - return mesh; -} - -void lazyCreate(LazyGeometry* instance) -{ - /* one thread will switch the object from the LAZY_INVALID state to the LAZY_CREATE state */ - if (atomic_cmpxchg((int32_t*)&instance->state,LAZY_INVALID,LAZY_CREATE) == 0) - { - /* create the geometry */ - printf("creating sphere %i\n",instance->userID); - instance->object = rtcDeviceNewScene(g_device,RTC_SCENE_STATIC,RTC_INTERSECT1); - createTriangulatedSphere(instance->object,instance->center,instance->radius); - - /* now switch to the LAZY_COMMIT state */ - __memory_barrier(); - instance->state = LAZY_COMMIT; - } - else - { - /* wait until the geometry got created */ - while (atomic_cmpxchg((int32_t*)&instance->state,10,11) < LAZY_COMMIT) { - // instead of actively spinning here, best use a condition to let the thread sleep, or let it help in the creation stage - } - } - - /* multiple threads might enter the rtcCommit function to jointly - * build the internal data structures */ - rtcCommit(instance->object); - - /* switch to LAZY_VALID state */ - atomic_cmpxchg((int32_t*)&instance->state,LAZY_COMMIT,LAZY_VALID); -} - -void instanceIntersectFunc(LazyGeometry* instance, RTCRay& ray, size_t item) -{ - /* create the object if it is not yet created */ - if (instance->state != LAZY_VALID) - lazyCreate(instance); - - /* trace ray inside object */ - const int geomID = ray.geomID; - ray.geomID = RTC_INVALID_GEOMETRY_ID; - rtcIntersect(instance->object,ray); - if (ray.geomID == RTC_INVALID_GEOMETRY_ID) ray.geomID = geomID; - else ray.instID = instance->userID; -} - -void instanceOccludedFunc(LazyGeometry* instance, RTCRay& ray, size_t item) -{ - /* create the object if it is not yet created */ - if (instance->state != LAZY_VALID) - lazyCreate(instance); - - /* trace ray inside object */ - rtcOccluded(instance->object,ray); -} - -LazyGeometry* createLazyObject (RTCScene scene, int userID, const Vec3fa& center, const float radius) -{ - LazyGeometry* instance = new LazyGeometry; - instance->state = LAZY_INVALID; - instance->object = nullptr; - instance->userID = userID; - instance->center = center; - instance->radius = radius; - instance->geometry = rtcNewUserGeometry(scene,1); - rtcSetUserData(scene,instance->geometry,instance); - rtcSetBoundsFunction(scene,instance->geometry,(RTCBoundsFunc)&instanceBoundsFunc); - rtcSetIntersectFunction(scene,instance->geometry,(RTCIntersectFunc)&instanceIntersectFunc); - rtcSetOccludedFunction (scene,instance->geometry,(RTCOccludedFunc )&instanceOccludedFunc); - return instance; -} - -/* creates a ground plane */ -unsigned int createGroundPlane (RTCScene scene) -{ - /* create a triangulated plane with 2 triangles and 4 vertices */ - unsigned int mesh = rtcNewTriangleMesh (scene, RTC_GEOMETRY_STATIC, 2, 4); - - /* set vertices */ - Vertex* vertices = (Vertex*) rtcMapBuffer(scene,mesh,RTC_VERTEX_BUFFER); - vertices[0].x = -10; vertices[0].y = -2; vertices[0].z = -10; - vertices[1].x = -10; vertices[1].y = -2; vertices[1].z = +10; - vertices[2].x = +10; vertices[2].y = -2; vertices[2].z = -10; - vertices[3].x = +10; vertices[3].y = -2; vertices[3].z = +10; - rtcUnmapBuffer(scene,mesh,RTC_VERTEX_BUFFER); - - /* set triangles */ - Triangle* triangles = (Triangle*) rtcMapBuffer(scene,mesh,RTC_INDEX_BUFFER); - triangles[0].v0 = 0; triangles[0].v1 = 2; triangles[0].v2 = 1; - triangles[1].v0 = 1; triangles[1].v1 = 2; triangles[1].v2 = 3; - rtcUnmapBuffer(scene,mesh,RTC_INDEX_BUFFER); - - return mesh; -} - -/* scene data */ -RTCScene g_scene = nullptr; - -/* called by the C++ code for initialization */ -extern "C" void device_init (char* cfg) -{ - /* create new Embree device */ - g_device = rtcNewDevice(cfg); - - /* set error handler */ - rtcDeviceSetErrorFunction(g_device,error_handler); - - /* create scene */ - g_scene = rtcDeviceNewScene(g_device,RTC_SCENE_STATIC,RTC_INTERSECT1); - - /* instantiate geometry */ - createGroundPlane(g_scene); - for (size_t i=0; i - - - - - - - -1.0 0.0 -1.0 - 0.0 0.0 -1.0 - +1.0 0.0 -1.0 - -1.0 1.0 0.0 - 0.0 1.0 0.0 - +1.0 1.0 0.0 - -1.0 0.0 +1.0 - 0.0 0.0 +1.0 - +1.0 0.0 +1.0 - - - - 0 1 4 3 - 1 2 5 4 - 3 4 7 6 - 4 5 8 7 - - - - 4 4 4 4 - - - - 3 4 4 5 - - - - 1 10 - - - - 0 2 6 8 - - - - 0 +inf 0 +inf - - - - "OBJ" - - 1 1 1 - - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/models/subdiv1.xml b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/models/subdiv1.xml deleted file mode 100644 index 10dccf1ca885..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/models/subdiv1.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - -1.0 -1.0 -1.0 - 1.0 -1.0 -1.0 - 1.0 -1.0 1.0 - -1.0 -1.0 1.0 - -1.0 1.0 -1.0 - 1.0 1.0 -1.0 - 1.0 1.0 1.0 - -1.0 1.0 1.0 - - - - 0 1 5 4 - 1 2 6 5 - 2 3 7 6 - 0 4 7 3 - 4 5 6 7 - 0 3 2 1 - - - - 4 4 4 4 4 4 - - - - "OBJ" - - 1 1 1 - - - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/models/subdiv2.xml b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/models/subdiv2.xml deleted file mode 100644 index 6a05377925fa..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/models/subdiv2.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - -1.0 -1.0 -1.0 - 1.0 -1.0 -1.0 - 1.0 -1.0 1.0 - -1.0 -1.0 1.0 - -1.0 1.0 -1.0 - 1.0 1.0 -1.0 - 1.0 1.0 1.0 - -1.0 1.0 1.0 - - - - 0 1 5 4 - 1 2 6 5 - 2 3 7 6 - 0 4 7 3 - 4 5 6 7 - 0 3 2 1 - - - - 4 4 4 4 4 4 - - - - 0 1 1 2 2 3 3 0 - 4 5 5 6 6 7 7 4 - - - - 4 4 4 4 - 4 4 4 4 - - - - "OBJ" - - 1 1 1 - - - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/models/subdiv3.xml b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/models/subdiv3.xml deleted file mode 100644 index 2634306402fe..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/models/subdiv3.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - -1.0 -1.0 -1.0 - 1.0 -1.0 -1.0 - 1.0 -1.0 1.0 - -1.0 -1.0 1.0 - -1.0 1.0 -1.0 - 1.0 1.0 -1.0 - 1.0 1.0 1.0 - -1.0 1.0 1.0 - - - - 0 1 4 5 - 1 2 6 5 - 2 3 7 6 - 0 4 7 3 - 4 5 6 7 - 0 3 2 1 - - - - 4 4 4 4 4 4 - - - - 0 - - - - "OBJ" - - 1 1 1 - - - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/models/subdiv4.xml b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/models/subdiv4.xml deleted file mode 100644 index 417c4a9a7bea..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/models/subdiv4.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - 0.0 0.0 +1.0 - 0.0 0.0 -1.0 - - +1.0 0.0 +1.0 - +1.0 0.0 -1.0 - - -1.0 0.0 +1.0 - -1.0 0.0 -1.0 - - 0.0 +1.0 +1.0 - 0.0 +1.0 -1.0 - - 0.0 -1.0 +1.0 - 0.0 -1.0 -1.0 - - - - - 2 3 1 0 - 4 5 1 0 - 6 7 1 0 - 8 9 1 0 - - - - 4 4 4 4 - - - - "OBJ" - - 1 1 1 - - - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/models/subdiv5.xml b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/models/subdiv5.xml deleted file mode 100644 index 433f6169aa4d..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/models/subdiv5.xml +++ /dev/null @@ -1,173 +0,0 @@ - - - - - "OBJ" - - 0.0000 0.0000 0.0000 - 1.0000 1.0000 1.0000 - 0.0000 0.0000 0.0000 - 0.0000 0.0000 0.0000 - 0.0000 - - - - - - - - 5 - 4 - 4 - 4 - 4 - 4 - 3 - 3 - 3 - 3 - 3 - - - -6.161304 3.084484 2.848330 - -2.643319 2.844333 3.752810 - -6.362397 2.310006 -1.083433 - -0.425384 2.985474 0.748454 - -2.414260 2.862669 -2.040039 - -7.162443 0.000000 -3.766171 - -3.198509 0.000000 -4.628065 - 1.854593 0.000000 -0.350175 - -0.334927 0.000000 -3.630392 - -0.294475 0.000000 5.092125 - 1.997062 0.000000 2.211453 - -6.599835 0.000000 5.503421 - -3.358078 0.000000 6.251306 - -9.117918 0.000000 -0.733933 - -8.480494 0.000000 3.151634 - - - 2 4 3 1 0 - 4 2 5 6 - 8 7 3 4 - 10 9 1 3 - 12 11 0 1 - 14 13 2 0 - 2 13 5 - 4 6 8 - 3 7 10 - 9 12 1 - 0 11 14 - - - 0.000000 0.000000 - 1.000000 0.000000 - 0.000000 0.963555 - 1.000000 0.670366 - 0.755295 0.963555 - 0.000000 0.000000 - 1.000000 0.000000 - 1.000000 1.000000 - 0.000000 1.000000 - 0.000000 0.000000 - 1.000000 0.000000 - 1.000000 1.000000 - 0.000000 1.000000 - 0.000000 0.000000 - 1.000000 0.000000 - 1.000000 1.000000 - 0.000000 1.000000 - 0.000000 0.000000 - 1.000000 0.000000 - 1.000000 1.000000 - 0.000000 1.000000 - 0.000000 0.000000 - 1.000000 0.000000 - 1.000000 1.000000 - 0.000000 1.000000 - 1.000000 0.000000 - 1.000000 1.000000 - 0.000000 1.000000 - 0.000000 0.000000 - 1.000000 1.000000 - 0.000000 1.000000 - 1.000000 0.000000 - 1.000000 1.000000 - 0.000000 1.000000 - 0.000000 0.000000 - 1.000000 0.000000 - 0.000000 1.000000 - 0.000000 0.000000 - 1.000000 1.000000 - 0.000000 1.000000 - - - 0 1 3 4 2 - 5 6 7 8 - 9 10 11 12 - 13 14 15 16 - 17 18 19 20 - 21 22 23 24 - 27 25 26 - 28 29 30 - 33 31 32 - 34 35 36 - 37 38 39 - - - -0.047363 0.997192 -0.058001 - -0.047363 0.997192 -0.058001 - -0.047363 0.997192 -0.058001 - -0.047363 0.997192 -0.058001 - -0.047363 0.997192 -0.058001 - -0.201349 0.728675 -0.654592 - -0.201349 0.728675 -0.654592 - -0.201349 0.728675 -0.654592 - -0.201349 0.728675 -0.654592 - 0.613888 0.658071 -0.435987 - 0.613888 0.658070 -0.435987 - 0.613888 0.658071 -0.435987 - 0.613888 0.658070 -0.435987 - 0.570399 0.684823 0.453499 - 0.570399 0.684823 0.453499 - 0.570399 0.684823 0.453499 - 0.570399 0.684823 0.453499 - -0.154934 0.665114 0.730492 - -0.154934 0.665114 0.730492 - -0.154934 0.665114 0.730492 - -0.154934 0.665114 0.730492 - -0.727717 0.685803 0.010114 - -0.727717 0.685803 0.010114 - -0.727717 0.685803 0.010114 - -0.727717 0.685803 0.010114 - -0.618327 0.677248 -0.398756 - -0.618327 0.677248 -0.398756 - -0.618327 0.677248 -0.398756 - 0.261487 0.606894 -0.750536 - 0.261487 0.606894 -0.750536 - 0.261487 0.606894 -0.750536 - 0.786161 0.616473 -0.043724 - 0.786161 0.616473 -0.043724 - 0.786161 0.616473 -0.043724 - 0.285470 0.591000 0.754471 - 0.285470 0.591000 0.754471 - 0.285470 0.591000 0.754471 - -0.655228 0.544182 0.523968 - -0.655228 0.544182 0.523968 - -0.655228 0.544182 0.523968 - - - 0 1 2 3 4 - 5 6 7 8 - 9 10 11 12 - 13 14 15 16 - 17 18 19 20 - 21 22 23 24 - 25 26 27 - 28 29 30 - 31 32 33 - 34 35 36 - 37 38 39 - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/models/subdiv6.xml b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/models/subdiv6.xml deleted file mode 100644 index 61f89a297fb9..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/models/subdiv6.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - -1.0 -1.0 0.0 - 0.0 -1.0 0.0 - +1.0 -1.0 0.0 - +2.0 -1.0 0.0 - - -1.0 0.0 0.0 - 0.0 0.0 0.0 - +1.0 0.0 0.0 - +2.0 0.0 0.0 - - -1.0 +1.0 0.0 - 0.0 +1.0 0.0 - +1.0 +1.0 0.0 - +2.0 +1.0 0.0 - - -1.0 +2.0 0.0 - 0.0 +2.0 0.0 - +1.0 +2.0 0.0 - +2.0 +2.0 0.0 - - - - - 0 1 5 4 - 1 2 6 5 - 2 3 7 6 - 4 5 9 8 - 5 6 10 9 - 6 7 11 10 - 8 9 13 12 - 9 10 14 13 - 10 11 15 14 - - - - 4 4 4 4 4 4 4 4 4 - - - - "OBJ" - - 1 1 1 - - - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/models/subdiv7.xml b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/models/subdiv7.xml deleted file mode 100644 index f577f346a4ee..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/models/subdiv7.xml +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - -1.0 -1.0 0.0 - 0.0 -1.0 0.0 - +1.0 -1.0 0.0 - +2.0 -1.0 0.0 - - -1.0 0.0 0.0 - 0.0 0.0 0.0 - +1.0 0.0 0.0 - +2.0 0.0 0.0 - - -1.0 +1.0 0.0 - 0.0 +1.0 0.0 - +1.0 +1.0 0.0 - +2.0 +1.0 0.0 - - -1.0 +2.0 0.0 - 0.0 +2.0 0.0 - +1.0 +2.0 0.0 - +2.0 +2.0 0.0 - - - - - 0 1 5 4 - 1 2 6 5 - 2 3 7 6 - 4 5 9 8 - 6 7 11 10 - 8 9 13 12 - 9 10 14 13 - 10 11 15 14 - - - - 4 4 4 4 4 4 4 4 - - - - 0 3 12 15 - 5 6 9 10 - - - - +inf +inf +inf +inf - +inf +inf +inf +inf - - - - "OBJ" - - 1 1 1 - - - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/models/subdiv8.xml b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/models/subdiv8.xml deleted file mode 100644 index 7fbbf80e20cd..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/models/subdiv8.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - -1.0 -1.0 0.0 - 0.0 -1.0 0.0 - +1.0 -1.0 0.0 - +2.0 -1.0 0.0 - - -1.0 0.0 0.0 - 0.0 0.0 0.0 - +1.0 0.0 0.0 - +2.0 0.0 0.0 - - -1.0 +1.0 0.0 - 0.0 +1.0 0.0 - +1.0 +1.0 0.0 - +2.0 +1.0 0.0 - - -1.0 +2.0 0.0 - 0.0 +2.0 0.0 - +1.0 +2.0 0.0 - +2.0 +2.0 0.0 - - - - - 1 2 6 5 - 4 5 9 8 - 5 6 10 9 - 6 7 11 10 - 9 10 14 13 - - - - 4 4 4 4 4 - - - - "OBJ" - - 1 1 1 - - - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/models/subdiv9.xml b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/models/subdiv9.xml deleted file mode 100644 index 6865837fbd3e..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/models/subdiv9.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - -1.0 -1.0 0.0 - 0.0 -1.0 0.0 - +1.0 -1.0 0.0 - +2.0 -1.0 0.0 - - -1.0 0.0 0.0 - 0.0 0.0 0.0 - +1.0 0.0 0.0 - +2.0 0.0 0.0 - - -1.0 +1.0 0.0 - 0.0 +1.0 0.0 - +1.0 +1.0 0.0 - +2.0 +1.0 0.0 - - -1.0 +2.0 0.0 - 0.0 +2.0 0.0 - +1.0 +2.0 0.0 - +2.0 +2.0 0.0 - - - - - 0 1 5 4 - - - - 4 - - - - "OBJ" - - 1 1 1 - - - - - - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/motion_blur_geometry/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/motion_blur_geometry/CMakeLists.txt deleted file mode 100644 index 0503a7017610..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/motion_blur_geometry/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2015 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -INCLUDE(tutorial) -ADD_TUTORIAL(motion_blur_geometry) diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/motion_blur_geometry/motion_blur_geometry.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/motion_blur_geometry/motion_blur_geometry.cpp deleted file mode 100644 index dd88743cd307..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/motion_blur_geometry/motion_blur_geometry.cpp +++ /dev/null @@ -1,154 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial.h" -#include "../common/image/image.h" - -namespace embree -{ - /* name of the tutorial */ - const char* tutorialName = "motion_blur_geometry"; - - /* configuration */ - static std::string g_rtcore = ""; - static size_t g_numThreads = 0; - - /* output settings */ - static size_t g_width = 512; - static size_t g_height = 512; - static bool g_fullscreen = false; - static FileName outFilename = ""; - - static void parseCommandLine(Ref cin, const FileName& path) - { - while (true) - { - std::string tag = cin->getString(); - if (tag == "") return; - - /* parse command line parameters from a file */ - if (tag == "-c") { - FileName file = path + cin->getFileName(); - parseCommandLine(new ParseStream(new LineCommentFilter(file, "#")), file.path()); - } - - /* parse camera parameters */ - else if (tag == "-vp") g_camera.from = cin->getVec3fa(); - else if (tag == "-vi") g_camera.to = cin->getVec3fa(); - else if (tag == "-vd") g_camera.to = g_camera.from + cin->getVec3fa(); - else if (tag == "-vu") g_camera.up = cin->getVec3fa(); - else if (tag == "-fov") g_camera.fov = cin->getFloat(); - - /* frame buffer size */ - else if (tag == "-size") { - g_width = cin->getInt(); - g_height = cin->getInt(); - } - - /* full screen mode */ - else if (tag == "-fullscreen") - g_fullscreen = true; - - /* output filename */ - else if (tag == "-o") - outFilename = cin->getFileName(); - - /* rtcore configuration */ - else if (tag == "-rtcore") - g_rtcore = cin->getString(); - - /* number of threads to use */ - else if (tag == "-threads") - g_numThreads = cin->getInt(); - - /* skip unknown command line parameter */ - else { - std::cerr << "unknown command line parameter: " << tag << " "; - while (cin->peek() != "" && cin->peek()[0] != '-') std::cerr << cin->getString() << " "; - std::cerr << std::endl; - } - } - } - - void renderToFile(const FileName& fileName) - { - resize(g_width,g_height); - AffineSpace3fa pixel2world = g_camera.pixel2world(g_width,g_height); - - render(0.0f, - pixel2world.l.vx, - pixel2world.l.vy, - pixel2world.l.vz, - pixel2world.p); - - void* ptr = map(); - Ref image = new Image4uc(g_width, g_height, (Col4uc*)ptr); - storeImage(image, fileName); - unmap(); - } - - /* main function in embree namespace */ - int main(int argc, char** argv) - { - /* for best performance set FTZ and DAZ flags in MXCSR control and status register */ - _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); - _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); - - /* set default camera */ - g_camera.from = Vec3fa(2.863559246f,2.610507727f,-2.664560795f); - g_camera.to = Vec3fa(0.562128067f,1.999999762f,-0.3622088432f); - - /* create stream for parsing */ - Ref stream = new ParseStream(new CommandLineStream(argc, argv)); - - /* parse command line */ - parseCommandLine(stream, FileName()); - if (g_numThreads) - g_rtcore += ",threads=" + std::to_string((long long)g_numThreads); - - /* initialize ray tracing core */ - init(g_rtcore.c_str()); - - /* render to disk */ - if (outFilename.str() != "") { - renderToFile(outFilename); - return 0; - } - - /* initialize GLUT */ - initWindowState(argc,argv,tutorialName, g_width, g_height, g_fullscreen); - - /* enter the GLUT run loop */ - enterWindowRunLoop(); - - return 0; - } -} - -int main(int argc, char** argv) -{ - try { - return embree::main(argc, argv); - } - catch (const std::exception& e) { - std::cout << "Error: " << e.what() << std::endl; - return 1; - } - catch (...) { - std::cout << "Error: unknown exception caught." << std::endl; - return 1; - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/motion_blur_geometry/motion_blur_geometry_device.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/motion_blur_geometry/motion_blur_geometry_device.cpp deleted file mode 100644 index 4397980c71e6..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/motion_blur_geometry/motion_blur_geometry_device.cpp +++ /dev/null @@ -1,351 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial_device.h" - -/* scene data */ -RTCDevice g_device = nullptr; -RTCScene g_scene = nullptr; -Vec3fa* face_colors = nullptr; - -/* accumulation buffer */ -Vec3fa* g_accu = nullptr; -unsigned int g_accu_width = 0; -unsigned int g_accu_height = 0; -unsigned int g_accu_count = 0; -Vec3fa g_accu_vx; -Vec3fa g_accu_vy; -Vec3fa g_accu_vz; -Vec3fa g_accu_p; -extern "C" bool g_changed; - -/* render function to use */ -renderPixelFunc renderPixel; - -/* error reporting function */ -void error_handler(const RTCError code, const char* str) -{ - printf("Embree: "); - switch (code) { - case RTC_UNKNOWN_ERROR : printf("RTC_UNKNOWN_ERROR"); break; - case RTC_INVALID_ARGUMENT : printf("RTC_INVALID_ARGUMENT"); break; - case RTC_INVALID_OPERATION: printf("RTC_INVALID_OPERATION"); break; - case RTC_OUT_OF_MEMORY : printf("RTC_OUT_OF_MEMORY"); break; - case RTC_UNSUPPORTED_CPU : printf("RTC_UNSUPPORTED_CPU"); break; - case RTC_CANCELLED : printf("RTC_CANCELLED"); break; - default : printf("invalid error code"); break; - } - if (str) { - printf(" ("); - while (*str) putchar(*str++); - printf(")\n"); - } - exit(1); -} - -__aligned(16) float cube_vertices[8][4] = -{ - { -1.0f, -1.0f, -1.0f, 0.0f }, - { -1.0f, -1.0f, +1.0f, 0.0f }, - { -1.0f, +1.0f, -1.0f, 0.0f }, - { -1.0f, +1.0f, +1.0f, 0.0f }, - { +1.0f, -1.0f, -1.0f, 0.0f }, - { +1.0f, -1.0f, +1.0f, 0.0f }, - { +1.0f, +1.0f, -1.0f, 0.0f }, - { +1.0f, +1.0f, +1.0f, 0.0f } -}; - -unsigned int cube_indices[36] = { - 0, 2, 1, 1, 2, 3, - 4, 5, 6, 5, 7, 6, - 0, 1, 4, 1, 5, 4, - 2, 6, 3, 3, 6, 7, - 0, 4, 2, 2, 4, 6, - 1, 3, 5, 3, 7, 5 -}; - -unsigned int cube_faces[12] = { - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 -}; - -/* adds a cube to the scene */ -unsigned int addCube (RTCScene scene) -{ - /* create a triangulated cube with 12 triangles and 8 vertices */ - unsigned int geomID = rtcNewTriangleMesh (scene, RTC_GEOMETRY_STATIC, 12, 8, 2); - rtcSetBuffer(scene, geomID, RTC_INDEX_BUFFER, cube_indices , 0, 3*sizeof(unsigned int)); - - AffineSpace3fa rotation = AffineSpace3fa::rotate(Vec3fa(0,3,0),Vec3fa(1,1,0),0.44f); - Vec3fa* vertex0 = (Vec3fa*) rtcMapBuffer(scene,geomID,RTC_VERTEX_BUFFER0); - Vec3fa* vertex1 = (Vec3fa*) rtcMapBuffer(scene,geomID,RTC_VERTEX_BUFFER1); - for (int i=0; i<8; i++) - { - Vec3fa v = Vec3fa(cube_vertices[i][0],cube_vertices[i][1],cube_vertices[i][2])+Vec3fa(0,3,0); - vertex0[i] = Vec3fa(v); - vertex1[i] = Vec3fa(xfmPoint(rotation,v)); - } - rtcUnmapBuffer(scene,geomID,RTC_VERTEX_BUFFER0); - rtcUnmapBuffer(scene,geomID,RTC_VERTEX_BUFFER1); - - /* create face color array */ - face_colors = (Vec3fa*) alignedMalloc(12*sizeof(Vec3fa)); - face_colors[0] = Vec3fa(1,0,0); - face_colors[1] = Vec3fa(1,0,0); - face_colors[2] = Vec3fa(0,1,0); - face_colors[3] = Vec3fa(0,1,0); - face_colors[4] = Vec3fa(0.5f); - face_colors[5] = Vec3fa(0.5f); - face_colors[6] = Vec3fa(1.0f); - face_colors[7] = Vec3fa(1.0f); - face_colors[8] = Vec3fa(0,0,1); - face_colors[9] = Vec3fa(0,0,1); - face_colors[10] = Vec3fa(1,1,0); - face_colors[11] = Vec3fa(1,1,0); - - return geomID; -} - -/* add hair geometry */ -unsigned int addHair (RTCScene scene) -{ - unsigned int geomID = rtcNewHairGeometry (scene, RTC_GEOMETRY_STATIC, 16, 4*16, 2); - - AffineSpace3fa rotation = AffineSpace3fa::rotate(Vec3fa(0,3,0),Vec3fa(1,1,0),0.44f); - Vec3fa* vertices0 = (Vec3fa*) rtcMapBuffer(scene,geomID,RTC_VERTEX_BUFFER0); - Vec3fa* vertices1 = (Vec3fa*) rtcMapBuffer(scene,geomID,RTC_VERTEX_BUFFER1); - for (size_t i=0; i<16; i++) - { - Vec3fa org = Vec3fa((i%4+0.5f)*0.5f-1.0f,2.0f,(i/4+0.5f)*0.5f-1.0f); - Vec3fa p0 = org + Vec3fa(0.0f,+0.0f,0.0f); - Vec3fa p1 = org + Vec3fa(0.3f,+0.0f,0.0f); - Vec3fa p2 = org + Vec3fa(0.3f,-3.0f,0.3f); - Vec3fa p3 = org + Vec3fa(0.0f,-3.0f,0.0f); - vertices0[4*i+0] = Vec3fa(p0,0.02f); - vertices0[4*i+1] = Vec3fa(p1,0.02f); - vertices0[4*i+2] = Vec3fa(p2,0.02f); - vertices0[4*i+3] = Vec3fa(p3,0.02f); - vertices1[4*i+0] = Vec3fa(xfmPoint(rotation,p0),0.02f); - vertices1[4*i+1] = Vec3fa(xfmPoint(rotation,p1),0.02f); - vertices1[4*i+2] = Vec3fa(p2,0.02f); - vertices1[4*i+3] = Vec3fa(p3,0.02f); - } - rtcUnmapBuffer(scene,geomID,RTC_VERTEX_BUFFER0); - rtcUnmapBuffer(scene,geomID,RTC_VERTEX_BUFFER1); - - int* indices = (int*) rtcMapBuffer(scene,geomID,RTC_INDEX_BUFFER); - for (size_t i=0; i<16; i++) { - indices[i] = 4*i; - } - rtcUnmapBuffer(scene,geomID,RTC_INDEX_BUFFER); - - return geomID; -} - -/* adds a ground plane to the scene */ -unsigned int addGroundPlane (RTCScene scene) -{ - /* create a triangulated plane with 2 triangles and 4 vertices */ - unsigned int mesh = rtcNewTriangleMesh (scene, RTC_GEOMETRY_STATIC, 2, 4); - - /* set vertices */ - Vertex* vertices = (Vertex*) rtcMapBuffer(scene,mesh,RTC_VERTEX_BUFFER); - vertices[0].x = -10; vertices[0].y = -2; vertices[0].z = -10; - vertices[1].x = -10; vertices[1].y = -2; vertices[1].z = +10; - vertices[2].x = +10; vertices[2].y = -2; vertices[2].z = -10; - vertices[3].x = +10; vertices[3].y = -2; vertices[3].z = +10; - rtcUnmapBuffer(scene,mesh,RTC_VERTEX_BUFFER); - - /* set triangles */ - Triangle* triangles = (Triangle*) rtcMapBuffer(scene,mesh,RTC_INDEX_BUFFER); - triangles[0].v0 = 0; triangles[0].v1 = 2; triangles[0].v2 = 1; - triangles[1].v0 = 1; triangles[1].v1 = 2; triangles[1].v2 = 3; - rtcUnmapBuffer(scene,mesh,RTC_INDEX_BUFFER); - - return mesh; -} - -/* called by the C++ code for initialization */ -extern "C" void device_init (char* cfg) -{ - /* initialize last seen camera */ - g_accu_vx = Vec3fa(0.0f); - g_accu_vy = Vec3fa(0.0f); - g_accu_vz = Vec3fa(0.0f); - g_accu_p = Vec3fa(0.0f); - - /* create new Embree device */ - g_device = rtcNewDevice(cfg); - - /* set error handler */ - rtcDeviceSetErrorFunction(g_device,error_handler); - - /* create scene */ - g_scene = rtcDeviceNewScene(g_device, RTC_SCENE_STATIC,RTC_INTERSECT1); - - /* add cube */ - addCube(g_scene); - - /* add hair */ - addHair(g_scene); - - /* add ground plane */ - addGroundPlane(g_scene); - - /* commit changes to scene */ - rtcCommit (g_scene); - - /* set start render mode */ - renderPixel = renderPixelStandard; - key_pressed_handler = device_key_pressed_default; -} - -int frameID = 0; - -/* task that renders a single screen tile */ -Vec3fa renderPixelStandard(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p) -{ - float time = abs((int)(0.01f*frameID) - 0.01f*frameID); - - /* initialize ray */ - RTCRay ray; - ray.org = p; - ray.dir = normalize(x*vx + y*vy + vz); - ray.tnear = 0.0f; - ray.tfar = inf; - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.primID = RTC_INVALID_GEOMETRY_ID; - ray.mask = -1; - ray.time = time; - - /* intersect ray with scene */ - rtcIntersect(g_scene,ray); - - /* shade pixels */ - Vec3fa color = Vec3fa(0.0f); - if (ray.geomID != RTC_INVALID_GEOMETRY_ID) - { - Vec3fa diffuse; - if (ray.geomID == 0) diffuse = face_colors[ray.primID]; - else if (ray.geomID == 1) diffuse = Vec3fa(0.0f,1.0f,0.0f); - else diffuse = Vec3fa(0.5f,0.5f,0.5f); - color = color + diffuse*0.5f; // FIXME: += - Vec3fa lightDir = normalize(Vec3fa(-1,-4,-1)); - - /* initialize shadow ray */ - RTCRay shadow; - shadow.org = ray.org + ray.tfar*ray.dir; - shadow.dir = neg(lightDir); - shadow.tnear = 0.001f; - shadow.tfar = inf; - shadow.geomID = 1; - shadow.primID = 0; - shadow.mask = -1; - shadow.time = time; - - /* trace shadow ray */ - rtcOccluded(g_scene,shadow); - - /* add light contribution */ - if (shadow.geomID) - color = color + diffuse*clamp(-dot(lightDir,normalize(ray.Ng)),0.0f,1.0f); // FIXME: += - } - return color; -} - -/* task that renders a single screen tile */ -void renderTile(int taskIndex, int* pixels, - const int width, - const int height, - const float time, - const Vec3fa& vx, - const Vec3fa& vy, - const Vec3fa& vz, - const Vec3fa& p, - const int numTilesX, - const int numTilesY) -{ - const int tileY = taskIndex / numTilesX; - const int tileX = taskIndex - tileY * numTilesX; - const int x0 = tileX * TILE_SIZE_X; - const int x1 = min(x0+TILE_SIZE_X,width); - const int y0 = tileY * TILE_SIZE_Y; - const int y1 = min(y0+TILE_SIZE_Y,height); - - for (int y = y0; yw)); - unsigned int r = (unsigned int) (255.0f * clamp(dst->x*f,0.0f,1.0f)); - unsigned int g = (unsigned int) (255.0f * clamp(dst->y*f,0.0f,1.0f)); - unsigned int b = (unsigned int) (255.0f * clamp(dst->z*f,0.0f,1.0f)); - pixels[y*width+x] = (b << 16) + (g << 8) + r; - } -} - -/* called by the C++ code to render */ -extern "C" void device_render (int* pixels, - const int width, - const int height, - const float time, - const Vec3fa& vx, - const Vec3fa& vy, - const Vec3fa& vz, - const Vec3fa& p) -{ - Vec3fa cam_org = Vec3fa(p.x,p.y,p.z); - - /* create accumulator */ - if (g_accu_width != width || g_accu_height != height) { - alignedFree(g_accu); - g_accu = (Vec3fa*) alignedMalloc(width*height*sizeof(Vec3fa)); - g_accu_width = width; - g_accu_height = height; - memset(g_accu,0,width*height*sizeof(Vec3fa)); - } - - /* reset accumulator */ - bool camera_changed = g_changed; g_changed = false; - camera_changed |= ne(g_accu_vx,vx); g_accu_vx = vx; // FIXME: use != operator - camera_changed |= ne(g_accu_vy,vy); g_accu_vy = vy; // FIXME: use != operator - camera_changed |= ne(g_accu_vz,vz); g_accu_vz = vz; // FIXME: use != operator - camera_changed |= ne(g_accu_p, p); g_accu_p = p; // FIXME: use != operator - //camera_changed = true; - if (camera_changed) { - g_accu_count=0; - memset(g_accu,0,width*height*sizeof(Vec3fa)); - } - - /* render next frame */ - frameID++; - const int numTilesX = (width +TILE_SIZE_X-1)/TILE_SIZE_X; - const int numTilesY = (height+TILE_SIZE_Y-1)/TILE_SIZE_Y; - launch_renderTile(numTilesX*numTilesY,pixels,width,height,time,vx,vy,vz,p,numTilesX,numTilesY); -} - -/* called by the C++ code for cleanup */ -extern "C" void device_cleanup () -{ - rtcDeleteScene (g_scene); - rtcDeleteDevice(g_device); - alignedFree(face_colors); - alignedFree(g_accu); -} - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/pathtracer/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/pathtracer/CMakeLists.txt deleted file mode 100644 index 8e3a5cc2b10b..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/pathtracer/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2015 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -INCLUDE(tutorial) -ADD_TUTORIAL(pathtracer) diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/pathtracer/optics.h b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/pathtracer/optics.h deleted file mode 100644 index 8b3e17f6f63b..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/pathtracer/optics.h +++ /dev/null @@ -1,174 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -/*! \addtogroup rivl_render_embree_ivl */ -/*! @{ */ - -/*! Reflects a viewing vector V at a normal N. */ -inline Sample3f reflect_(const Vec3fa &V, const Vec3fa &N) { - float cosi = dot(V,N); - return Sample3f(2.0f*cosi*N-V, 1.0f); -} - -/*! Reflects a viewing vector V at a normal N. Cosine between V - * and N is given as input. */ -inline Sample3f reflect_(const Vec3fa &V, const Vec3fa &N, const float cosi) { - return Sample3f(2.0f*cosi*N-V, 1.0f); -} - -// ======================================================= -/*!Refracts a viewing vector V at a normal N using the relative - * refraction index eta. Eta is refraction index of outside medium - * (where N points into) divided by refraction index of the inside - * medium. The vectors V and N have to point towards the same side - * of the surface. The cosine between V and N is given as input and - * the cosine of -N and transmission ray is computed as output. */ -inline Sample3f refract(const Vec3fa& V, const Vec3fa& N, const float eta, - const float cosi, float &cost) -{ - const float k = 1.0f-eta*eta*(1.0f-cosi*cosi); - if (k < 0.0f) { cost = 0.0f; return Sample3f(Vec3fa(0.f),0.0f); } - cost = sqrt(k); - return Sample3f(eta*(cosi*N-V)-cost*N, sqr(eta)); -} - -/*! Computes fresnel coefficient for media interface with relative - * refraction index eta. Eta is the outside refraction index - * divided by the inside refraction index. Both cosines have to be - * positive. */ -inline float fresnelDielectric(const float cosi, const float cost, const float eta) -{ - const float Rper = (eta*cosi - cost) * rcp(eta*cosi + cost); - const float Rpar = ( cosi - eta*cost) * rcp( cosi + eta*cost); - return 0.5f*(Rpar*Rpar + Rper*Rper); -} - - /*! Computes fresnel coefficient for media interface with relative - * refraction index eta. Eta is the outside refraction index - * divided by the inside refraction index. The cosine has to be - * positive. */ -inline float fresnelDielectric(const float cosi, const float eta) -{ - const float k = 1.0f-eta*eta*(1.0f-cosi*cosi); - if (k < 0.0f) return 1.0f; - const float cost = sqrt(k); - return fresnelDielectric(cosi, cost, eta); -} - -/*! Computes fresnel coefficient for conductor medium with complex - * refraction index (eta,k). The cosine has to be positive. */ -inline Vec3fa fresnelConductor(const float cosi, const Vec3fa& eta, const Vec3fa& k) -{ - const Vec3fa tmp = eta*eta + k*k; - const Vec3fa Rpar = (tmp * (cosi*cosi) - 2.0f*eta*cosi + Vec3fa(1.0f)) * - rcp(tmp * (cosi*cosi) + 2.0f*eta*cosi + Vec3fa(1.0f)); - const Vec3fa Rper = (tmp - 2.0f*eta*cosi + Vec3fa(cosi*cosi)) * - rcp(tmp + 2.0f*eta*cosi + Vec3fa(cosi*cosi)); - return 0.5f * (Rpar + Rper); -} - -// ======================================================= -struct FresnelConductor { - Vec3fa eta; //!< Real part of refraction index - Vec3fa k; //!< Imaginary part of refraction index -}; - -inline Vec3fa eval(const FresnelConductor& This, const float cosTheta) { - return fresnelConductor(cosTheta,This.eta,This.k); -} - -inline FresnelConductor make_FresnelConductor(const Vec3fa& eta, const Vec3fa& k) { - FresnelConductor m; m.eta = eta; m.k = k; return m; -} - -#if defined(ISPC) -inline FresnelConductor make_FresnelConductor(const Vec3fa& eta, const Vec3fa& k) { - FresnelConductor m; m.eta = eta; m.k = k; return m; -} -#endif - -// ======================================================= -struct FresnelDielectric -{ - /*! refraction index of the medium the incident ray travels in */ - float etai; - - /*! refraction index of the medium the outgoing transmission rays - * travels in */ - float etat; -}; - -inline Vec3fa eval(const FresnelDielectric& This, const float cosTheta) { - return Vec3fa(fresnelDielectric(cosTheta,This.etai/This.etat)); -} - -inline FresnelDielectric make_FresnelDielectric(const float etai, const float etat) { - FresnelDielectric m; m.etai = etai; m.etat = etat; return m; -} - -#if defined(ISPC) -inline FresnelDielectric make_FresnelDielectric(const float etai, const float etat) { - FresnelDielectric m; m.etai = etai; m.etat = etat; return m; -} -#endif - -// ======================================================= -struct PowerCosineDistribution { - float exp; -}; - -inline float eval(const PowerCosineDistribution &This, const float cosThetaH) { - return (This.exp+2) * (1.0f/(2.0f*(float(pi)))) * pow(abs(cosThetaH), This.exp); -} - -#if defined(ISPC) - -inline float eval(const PowerCosineDistribution &This, const float cosThetaH) { - return (This.exp+2) * (1.0f/(2.0f*(float(pi)))) * pow(abs(cosThetaH), This.exp); -} -#endif - -/*! Samples the power cosine distribution. */ -inline void sample(const PowerCosineDistribution& This, const Vec3fa& wo, const Vec3fa& N, Sample3f &wi, const Vec2f s) -{ - Sample3f wh = powerCosineSampleHemisphere(s.x,s.y,N,This.exp); - Sample3f r = reflect_(wo,wh.v); - wi = Sample3f(r.v,wh.pdf/(4.0f*abs(dot(wo,wh.v)))); -} - -/*! Samples the power cosine distribution. */ -#if defined(ISPC) -inline void sample(const PowerCosineDistribution& This, const Vec3fa& wo, const Vec3fa& N, Sample3f &wi, const Vec2f s) -{ - Sample3f wh = powerCosineSampleHemisphere(s.x,s.y,N,This.exp); - Sample3f r = reflect_(wo,wh.v); - wi = Sample3f(r.v,wh.pdf/(4.0f*abs(dot(wo,wh.v)))); -} -#endif - -inline PowerCosineDistribution make_PowerCosineDistribution(const float _exp) { - PowerCosineDistribution m; m.exp = _exp; return m; -} - -#if defined(ISPC) -inline PowerCosineDistribution make_PowerCosineDistribution(const float _exp) { - PowerCosineDistribution m; m.exp = _exp; return m; -} -#endif - -/*! @} */ diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/pathtracer/pathtracer.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/pathtracer/pathtracer.cpp deleted file mode 100644 index 563592e977f3..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/pathtracer/pathtracer.cpp +++ /dev/null @@ -1,348 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial.h" -#include "../common/tutorial/obj_loader.h" -#include "../common/tutorial/xml_loader.h" -#include "../common/image/image.h" -#include "../common/tutorial/tutorial_device.h" - -namespace embree -{ - /* name of the tutorial */ - const char* tutorialName = "pathtracer"; - - /* configuration */ - static std::string g_rtcore = ""; - static size_t g_numThreads = 0; - static std::string g_subdiv_mode = ""; - - /* output settings */ - static size_t g_width = 512; - static size_t g_height = 512; - static bool g_fullscreen = false; - static FileName outFilename = ""; - static int g_skipBenchmarkFrames = 0; - static int g_numBenchmarkFrames = 0; - static bool g_interactive = true; - static bool g_only_subdivs = false; - static bool g_anim_mode = false; - static bool g_loop_mode = false; - static Shader g_shader = SHADER_DEFAULT; - - /* scene */ - OBJScene g_obj_scene; - static FileName filename = ""; - std::vector keyframeList; - std::vector g_keyframes; - - static void parseCommandLine(Ref cin, const FileName& path) - { - while (true) - { - std::string tag = cin->getString(); - if (tag == "") return; - - /* parse command line parameters from a file */ - else if (tag == "-c") { - FileName file = path + cin->getFileName(); - parseCommandLine(new ParseStream(new LineCommentFilter(file, "#")), file.path()); - } - - /* load OBJ model*/ - else if (tag == "-i") { - filename = path + cin->getFileName(); - } - - /* parse camera parameters */ - else if (tag == "-vp") g_camera.from = cin->getVec3fa(); - else if (tag == "-vi") g_camera.to = cin->getVec3fa(); - else if (tag == "-vd") g_camera.to = g_camera.from + cin->getVec3fa(); - else if (tag == "-vu") g_camera.up = cin->getVec3fa(); - else if (tag == "-fov") g_camera.fov = cin->getFloat(); - - /* frame buffer size */ - else if (tag == "-size") { - g_width = cin->getInt(); - g_height = cin->getInt(); - } - - /* full screen mode */ - else if (tag == "-fullscreen") - g_fullscreen = true; - - /* output filename */ - else if (tag == "-o") { - outFilename = cin->getFileName(); - g_interactive = false; - } - - else if (tag == "-objlist") { - while (cin->peek() != "" && cin->peek()[0] != '-') - keyframeList.push_back(path + cin->getFileName()); - } - - /* subdivision mode */ - else if (tag == "-cache") - g_subdiv_mode = ",subdiv_accel=bvh4.subdivpatch1cached"; - - else if (tag == "-pregenerate") - g_subdiv_mode = ",subdiv_accel=bvh4.grid.eager"; - - else if (tag == "-loop") - g_loop_mode = true; - - else if (tag == "-anim") - g_anim_mode = true; - - else if (tag == "-shader") { - std::string mode = cin->getString(); - if (mode == "default" ) g_shader = SHADER_DEFAULT; - else if (mode == "eyelight") g_shader = SHADER_EYELIGHT; - else if (mode == "uv" ) g_shader = SHADER_UV; - else if (mode == "Ng" ) g_shader = SHADER_NG; - else if (mode == "geomID" ) g_shader = SHADER_GEOMID; - else if (mode == "primID" ) g_shader = SHADER_GEOMID_PRIMID; - else throw std::runtime_error("invalid shader:" +mode); - } - - /* number of frames to render in benchmark mode */ - else if (tag == "-benchmark") { - g_skipBenchmarkFrames = cin->getInt(); - g_numBenchmarkFrames = cin->getInt(); - g_interactive = false; - } - - /* rtcore configuration */ - else if (tag == "-rtcore") - g_rtcore = cin->getString(); - - /* number of threads to use */ - else if (tag == "-threads") - g_numThreads = cin->getInt(); - - /* ambient light source */ - else if (tag == "-ambientlight") - { - const Vec3fa L = cin->getVec3fa(); - g_obj_scene.ambientLights.push_back(AmbientLight(L)); - } - - /* point light source */ - else if (tag == "-pointlight") - { - const Vec3fa P = cin->getVec3fa(); - const Vec3fa I = cin->getVec3fa(); - g_obj_scene.pointLights.push_back(PointLight(P,I)); - } - - /* directional light source */ - else if (tag == "-directionallight" || tag == "-dirlight") - { - const Vec3fa D = cin->getVec3fa(); - const Vec3fa E = cin->getVec3fa(); - g_obj_scene.directionalLights.push_back(DirectionalLight(D,E)); - } - - /* distant light source */ - else if (tag == "-distantlight") - { - const Vec3fa D = cin->getVec3fa(); - const Vec3fa L = cin->getVec3fa(); - const float halfAngle = cin->getFloat(); - g_obj_scene.distantLights.push_back(DistantLight(D,L,halfAngle)); - } - - /* converts triangle meshes into subdiv meshes */ - else if (tag == "-subdiv") { - g_only_subdivs = true; - } - - /* skip unknown command line parameter */ - else { - std::cerr << "unknown command line parameter: " << tag << " "; - while (cin->peek() != "" && cin->peek()[0] != '-') std::cerr << cin->getString() << " "; - std::cerr << std::endl; - } - } - } - - void renderBenchmark(const FileName& fileName) - { - resize(g_width,g_height); - AffineSpace3fa pixel2world = g_camera.pixel2world(g_width,g_height); - - double dt = 0.0f; - size_t numTotalFrames = g_skipBenchmarkFrames + g_numBenchmarkFrames; - for (size_t i=0; i= g_skipBenchmarkFrames) dt += t1-t0; - } - std::cout << "frame [" << g_skipBenchmarkFrames << " - " << numTotalFrames << "] " << std::flush; - std::cout << double(g_numBenchmarkFrames)/dt << "fps " << std::endl; - std::cout << "BENCHMARK_RENDER " << double(g_numBenchmarkFrames)/dt << std::endl; - } - - void renderToFile(const FileName& fileName) - { - resize(g_width,g_height); - if (g_anim_mode) g_camera.anim = true; - - do { - double msec = getSeconds(); - AffineSpace3fa pixel2world = g_camera.pixel2world(g_width,g_height); - render(0.0f,pixel2world.l.vx,pixel2world.l.vy,pixel2world.l.vz,pixel2world.p); - msec = getSeconds() - msec; - std::cout << "render time " << 1.0/msec << " fps" << std::endl; - - } while(g_loop_mode); - - void* ptr = map(); - Ref image = new Image4uc(g_width, g_height, (Col4uc*)ptr); - storeImage(image, fileName); - unmap(); - cleanup(); - } - - void loadKeyFrameAnimation(std::vector& fileName) - { - for (size_t i=0; i node = loadOBJ(keyframe,true); - scene->add(node); - if (g_obj_scene.subdiv.size() != scene->subdiv.size()) - FATAL("#subdiv meshes differ"); - for (size_t i=0;ipositions.size() != scene->subdiv[i]->positions.size()) - FATAL("#positions differ"); - - g_keyframes.push_back(scene); - } - } - - - /* main function in embree namespace */ - int main(int argc, char** argv) - { - /* for best performance set FTZ and DAZ flags in MXCSR control and status register */ - _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); - _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); - - /* create stream for parsing */ - Ref stream = new ParseStream(new CommandLineStream(argc, argv)); - - /* parse command line */ - parseCommandLine(stream, FileName()); - - /* load default scene if none specified */ - if (filename.ext() == "") { - FileName file = FileName::executableFolder() + FileName("models/cornell_box.ecs"); - parseCommandLine(new ParseStream(new LineCommentFilter(file, "#")), file.path()); - } - - /* configure number of threads */ - if (g_numThreads) - g_rtcore += ",threads=" + std::to_string((long long)g_numThreads); - if (g_numBenchmarkFrames) - g_rtcore += ",benchmark=1"; - - g_rtcore += g_subdiv_mode; - - /* load scene */ - if (strlwr(filename.ext()) == std::string("obj")) - { - Ref node = loadOBJ(filename,g_subdiv_mode != ""); - g_obj_scene.add(node); - } - else if (strlwr(filename.ext()) == std::string("xml")) { - Ref node = loadXML(filename,one); - g_obj_scene.add(node); - } - else if (filename.ext() != "") - THROW_RUNTIME_ERROR("invalid scene type: "+strlwr(filename.ext())); - - /* load keyframes */ - if (keyframeList.size()) - loadKeyFrameAnimation(keyframeList); - - /* initialize ray tracing core */ - init(g_rtcore.c_str()); - - /* set shader mode */ - switch (g_shader) { - case SHADER_DEFAULT : break; - case SHADER_EYELIGHT: key_pressed(GLUT_KEY_F2); break; - case SHADER_UV : key_pressed(GLUT_KEY_F4); break; - case SHADER_NG : key_pressed(GLUT_KEY_F5); break; - case SHADER_GEOMID : key_pressed(GLUT_KEY_F6); break; - case SHADER_GEOMID_PRIMID: key_pressed(GLUT_KEY_F7); break; - }; - - /* convert triangle meshes to subdiv meshes */ - if (g_only_subdivs) - g_obj_scene.convert_to_subdiv(); - - /* send model */ - set_scene(&g_obj_scene); - - /* send keyframes */ - if (g_keyframes.size()) - set_scene_keyframes(&*g_keyframes.begin(),g_keyframes.size()); - - /* benchmark mode */ - if (g_numBenchmarkFrames) - renderBenchmark(outFilename); - - /* render to disk */ - if (outFilename.str() != "") - renderToFile(outFilename); - - /* interactive mode */ - if (g_interactive) { - initWindowState(argc,argv,tutorialName, g_width, g_height, g_fullscreen); - enterWindowRunLoop(g_anim_mode); - - } - - return 0; - } -} - -int main(int argc, char** argv) -{ - try { - return embree::main(argc, argv); - } - catch (const std::exception& e) { - std::cout << "Error: " << e.what() << std::endl; - return 1; - } - catch (...) { - std::cout << "Error: unknown exception caught." << std::endl; - return 1; - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/pathtracer/pathtracer_device.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/pathtracer/pathtracer_device.cpp deleted file mode 100644 index 8ba2d0876757..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/pathtracer/pathtracer_device.cpp +++ /dev/null @@ -1,1570 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial_device.h" -#include "../common/tutorial/scene_device.h" -#include "shapesampler.h" -#include "optics.h" - - - -#undef TILE_SIZE_X -#undef TILE_SIZE_Y - -#define TILE_SIZE_X 4 -#define TILE_SIZE_Y 4 - -#define FIXED_SAMPLING 0 -#define SAMPLES_PER_PIXEL 1 - -#define ENABLE_TEXTURING 0 -#define ENABLE_TEXTURE_COORDINATES 0 -#define ENABLE_OCCLUSION_FILTER 0 -#define ENABLE_DISPLACEMENTS 0 - -//#define FORCE_FIXED_EDGE_TESSELLATION -#define FIXED_EDGE_TESSELLATION_VALUE 4 - -#define MAX_EDGE_LEVEL 128.0f -#define MIN_EDGE_LEVEL 4.0f -#define LEVEL_FACTOR 64.0f -#define MAX_PATH_LENGTH 8 - -bool g_subdiv_mode = false; -unsigned int keyframeID = 0; - -struct DifferentialGeometry -{ - int geomID; - int primID; - float u,v; - Vec3fa P; - Vec3fa Ng; - Vec3fa Ns; -}; - -struct BRDF -{ - float Ns; /*< specular exponent */ - float Ni; /*< optical density for the surface (index of refraction) */ - Vec3fa Ka; /*< ambient reflectivity */ - Vec3fa Kd; /*< diffuse reflectivity */ - Vec3fa Ks; /*< specular reflectivity */ - Vec3fa Kt; /*< transmission filter */ -}; - -struct Medium -{ - Vec3fa transmission; //!< Transmissivity of medium. - float eta; //!< Refraction index of medium. -}; - -inline Medium make_Medium(const Vec3fa& transmission, const float eta) -{ - Medium m; - m.transmission = transmission; - m.eta = eta; - return m; -} - -inline Medium make_Medium_Vacuum() { - return make_Medium(Vec3fa((float)1.0f),1.0f); -} - -inline bool eq(const Medium& a, const Medium& b) { - return (a.eta == b.eta) && eq(a.transmission, b.transmission); -} - -inline Vec3fa sample_component2(const Vec3fa& c0, const Sample3f& wi0, const Medium& medium0, - const Vec3fa& c1, const Sample3f& wi1, const Medium& medium1, - const Vec3fa& Lw, Sample3f& wi_o, Medium& medium_o, const float s) -{ - const Vec3fa m0 = Lw*c0/wi0.pdf; - const Vec3fa m1 = Lw*c1/wi1.pdf; - - const float C0 = wi0.pdf == 0.0f ? 0.0f : max(max(m0.x,m0.y),m0.z); - const float C1 = wi1.pdf == 0.0f ? 0.0f : max(max(m1.x,m1.y),m1.z); - const float C = C0 + C1; - - if (C == 0.0f) { - wi_o = Sample3f(Vec3fa(0,0,0),0); - return Vec3fa(0,0,0); - } - - const float CP0 = C0/C; - const float CP1 = C1/C; - if (s < CP0) { - wi_o = Sample3f(wi0.v,wi0.pdf*CP0); - medium_o = medium0; return c0; - } - else { - wi_o = Sample3f(wi1.v,wi1.pdf*CP1); - medium_o = medium1; return c1; - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Ambient Light // -//////////////////////////////////////////////////////////////////////////////// - -inline Vec3fa AmbientLight__eval(const ISPCAmbientLight& light, const Vec3fa& wo) { - return Vec3fa(light.L); -} - -inline Vec3fa AmbientLight__sample(const ISPCAmbientLight& light, const DifferentialGeometry& dg, Sample3f& wi, float& tMax, const Vec2f& s) -{ - wi = cosineSampleHemisphere(s.x,s.y,dg.Ns); - tMax = 1e20f; - return Vec3fa(light.L); -} - -//////////////////////////////////////////////////////////////////////////////// -// Point Light // -//////////////////////////////////////////////////////////////////////////////// - -inline Vec3fa PointLight__sample(const ISPCPointLight& light, - const DifferentialGeometry& dg, - Sample3f& wi, - float& tMax, - const Vec2f& s) -{ - Vec3fa d = Vec3fa(light.P) - dg.P; - float distance = length(d); - wi = Sample3f(d*rcp(distance), distance*distance); - tMax = distance; - return Vec3fa(light.I); -} - -//////////////////////////////////////////////////////////////////////////////// -// Directional Light // -//////////////////////////////////////////////////////////////////////////////// - -inline Vec3fa DirectionalLight__sample(const ISPCDirectionalLight& light, - const DifferentialGeometry& dg, - Sample3f& wi, - float& tMax, - const Vec2f& s) -{ - wi = Sample3f(neg(normalize(Vec3fa(light.D))),1.0f); - tMax = inf; - return Vec3fa(light.E); -} - -//////////////////////////////////////////////////////////////////////////////// -// Distant Light // -//////////////////////////////////////////////////////////////////////////////// - -inline Vec3fa DistantLight__eval(const ISPCDistantLight& light, const Vec3fa& wo) -{ - if (-dot(wo,Vec3fa(light.D)) >= light.cosHalfAngle) return Vec3fa(light.L); - return Vec3fa(0.0f); -} - -inline Vec3fa DistantLight__sample(const ISPCDistantLight& light, - const DifferentialGeometry& dg, - Sample3f& wi, - float& tMax, - const Vec2f& s) -{ - wi = UniformSampleCone(s.x,s.y,light.radHalfAngle,Vec3fa((Vec3fa)neg(light.D))); - tMax = 1e20f; - - return Vec3fa(light.L); -} - -//////////////////////////////////////////////////////////////////////////////// -// Minneart BRDF // -//////////////////////////////////////////////////////////////////////////////// - -struct Minneart -{ - /*! The reflectance parameter. The vale 0 means no reflection, - * and 1 means full reflection. */ - Vec3fa R; - - /*! The amount of backscattering. A value of 0 means lambertian - * diffuse, and inf means maximum backscattering. */ - float b; -}; - -inline Vec3fa Minneart__eval(const Minneart* This, - const Vec3fa &wo, const DifferentialGeometry &dg, const Vec3fa &wi) -{ - const float cosThetaI = clamp(dot(wi,dg.Ns)); - const float backScatter = pow(clamp(dot(wo,wi)), This->b); - return (backScatter * cosThetaI * float(one_over_pi)) * This->R; -} - -inline Vec3fa Minneart__sample(const Minneart* This, - const Vec3fa &wo, - const DifferentialGeometry &dg, - Sample3f &wi, - const Vec2f &s) -{ - wi = cosineSampleHemisphere(s.x,s.y,dg.Ns); - return Minneart__eval(This, wo, dg, wi.v); -} - -inline void Minneart__Constructor(Minneart* This, const Vec3fa& R, const float b) -{ - This->R = R; - This->b = b; -} - -inline Minneart make_Minneart(const Vec3fa& R, const float f) { - Minneart m; Minneart__Constructor(&m,R,f); return m; -} - -//////////////////////////////////////////////////////////////////////////////// -// Velvet BRDF // -//////////////////////////////////////////////////////////////////////////////// - -struct Velvety -{ - BRDF base; - - /*! The reflectance parameter. The vale 0 means no reflection, - * and 1 means full reflection. */ - Vec3fa R; - - /*! The falloff of horizon scattering. 0 no falloff, - * and inf means maximum falloff. */ - float f; -}; - -inline Vec3fa Velvety__eval(const Velvety* This, - const Vec3fa &wo, const DifferentialGeometry &dg, const Vec3fa &wi) -{ - const float cosThetaO = clamp(dot(wo,dg.Ns)); - const float cosThetaI = clamp(dot(wi,dg.Ns)); - const float sinThetaO = sqrt(1.0f - cosThetaO * cosThetaO); - const float horizonScatter = pow(sinThetaO, This->f); - return (horizonScatter * cosThetaI * float(one_over_pi)) * This->R; -} - -inline Vec3fa Velvety__sample(const Velvety* This, - const Vec3fa &wo, - const DifferentialGeometry &dg, - Sample3f &wi, - const Vec2f &s) -{ - wi = cosineSampleHemisphere(s.x,s.y,dg.Ns); - return Velvety__eval(This, wo, dg, wi.v); -} - -inline void Velvety__Constructor(Velvety* This, const Vec3fa& R, const float f) -{ - This->R = R; - This->f = f; -} - -inline Velvety make_Velvety(const Vec3fa& R, const float f) { - Velvety m; Velvety__Constructor(&m,R,f); return m; -} - -//////////////////////////////////////////////////////////////////////////////// -// Dielectric Reflection BRDF // -//////////////////////////////////////////////////////////////////////////////// - -struct DielectricReflection -{ - float eta; -}; - -inline Vec3fa DielectricReflection__eval(const DielectricReflection* This, const Vec3fa &wo, const DifferentialGeometry &dg, const Vec3fa &wi) { - return Vec3fa(0.f); -} - -inline Vec3fa DielectricReflection__sample(const DielectricReflection* This, const Vec3fa &wo, const DifferentialGeometry &dg, Sample3f &wi, const Vec2f &s) -{ - const float cosThetaO = clamp(dot(wo,dg.Ns)); - wi = reflect_(wo,dg.Ns,cosThetaO); - return Vec3fa(fresnelDielectric(cosThetaO,This->eta)); -} - -inline void DielectricReflection__Constructor(DielectricReflection* This, - const float etai, - const float etat) -{ - This->eta = etai*rcp(etat); -} - -inline DielectricReflection make_DielectricReflection(const float etai, const float etat) { - DielectricReflection v; DielectricReflection__Constructor(&v,etai,etat); return v; -} - -//////////////////////////////////////////////////////////////////////////////// -// Lambertian BRDF // -//////////////////////////////////////////////////////////////////////////////// - -struct Lambertian -{ - Vec3fa R; -}; - -inline Vec3fa Lambertian__eval(const Lambertian* This, - const Vec3fa &wo, const DifferentialGeometry &dg, const Vec3fa &wi) -{ - return This->R * (1.0f/(float)(float(pi))) * clamp(dot(wi,dg.Ns)); -} - -inline Vec3fa Lambertian__sample(const Lambertian* This, - const Vec3fa &wo, - const DifferentialGeometry &dg, - Sample3f &wi, - const Vec2f &s) -{ - wi = cosineSampleHemisphere(s.x,s.y,dg.Ns); - return Lambertian__eval(This, wo, dg, wi.v); -} - -inline void Lambertian__Constructor(Lambertian* This, const Vec3fa& R) -{ - This->R = R; -} - -inline Lambertian make_Lambertian(const Vec3fa& R) { - Lambertian v; Lambertian__Constructor(&v,R); return v; -} - - -//////////////////////////////////////////////////////////////////////////////// -// Lambertian BRDF with Dielectric Layer on top // -//////////////////////////////////////////////////////////////////////////////// - -struct DielectricLayerLambertian -{ - Vec3fa T; //!< Transmission coefficient of dielectricum - float etait; //!< Relative refraction index etai/etat of both media - float etati; //!< relative refraction index etat/etai of both media - Lambertian ground; //!< the BRDF of the ground layer -}; - -inline Vec3fa DielectricLayerLambertian__eval(const DielectricLayerLambertian* This, - const Vec3fa &wo, const DifferentialGeometry &dg, const Vec3fa &wi) -{ - const float cosThetaO = dot(wo,dg.Ns); - const float cosThetaI = dot(wi,dg.Ns); - if (cosThetaI <= 0.0f || cosThetaO <= 0.0f) return Vec3fa(0.f); - - float cosThetaO1; - const Sample3f wo1 = refract(wo,dg.Ns,This->etait,cosThetaO,cosThetaO1); - float cosThetaI1; - const Sample3f wi1 = refract(wi,dg.Ns,This->etait,cosThetaI,cosThetaI1); - const float Fi = 1.0f - fresnelDielectric(cosThetaI,cosThetaI1,This->etait); - const Vec3fa Fg = Lambertian__eval(&This->ground,neg(wo1.v),dg,neg(wi1.v)); - const float Fo = 1.0f - fresnelDielectric(cosThetaO,cosThetaO1,This->etait); - return Fo * This->T * Fg * This->T * Fi; -} - -inline Vec3fa DielectricLayerLambertian__sample(const DielectricLayerLambertian* This, - const Vec3fa &wo, - const DifferentialGeometry &dg, - Sample3f &wi, - const Vec2f &s) -{ - /*! refract ray into medium */ - float cosThetaO = dot(wo,dg.Ns); - if (cosThetaO <= 0.0f) return Vec3fa(0.f); - float cosThetaO1; Sample3f wo1 = refract(wo,dg.Ns,This->etait,cosThetaO,cosThetaO1); - - /*! sample ground BRDF */ - Sample3f wi1 = Sample3f(Vec3fa(0.f),1.f); - Vec3fa Fg = Lambertian__sample(&This->ground,neg(wo1.v),dg,wi1,s); - - /*! refract ray out of medium */ - float cosThetaI1 = dot(wi1.v,dg.Ns); - if (cosThetaI1 <= 0.0f) return Vec3fa(0.f); - - float cosThetaI; - Sample3f wi0 = refract(neg(wi1.v),neg(dg.Ns),This->etati,cosThetaI1,cosThetaI); - if (wi0.pdf == 0.0f) return Vec3fa(0.f); - - /*! accumulate contribution of path */ - wi = Sample3f(wi0.v,wi1.pdf); - float Fi = 1.0f - fresnelDielectric(cosThetaI,cosThetaI1,This->etait); - float Fo = 1.0f - fresnelDielectric(cosThetaO,cosThetaO1,This->etait); - return Fo * This->T * Fg * This->T * Fi; -} - -inline void DielectricLayerLambertian__Constructor(DielectricLayerLambertian* This, - const Vec3fa& T, - const float etai, - const float etat, - const Lambertian& ground) -{ - This->T = T; - This->etait = etai*rcp(etat); - This->etati = etat*rcp(etai); - This->ground = ground; -} - -inline DielectricLayerLambertian make_DielectricLayerLambertian(const Vec3fa& T, - const float etai, - const float etat, - const Lambertian& ground) -{ - DielectricLayerLambertian m; - DielectricLayerLambertian__Constructor(&m,T,etai,etat,ground); - return m; -} - -//////////////////////////////////////////////////////////////////////////////// -// Matte Material // -//////////////////////////////////////////////////////////////////////////////// - - void MatteMaterial__preprocess(MatteMaterial* material, BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Medium& medium) -{ -} - - Vec3fa MatteMaterial__eval(MatteMaterial* This, const BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Vec3fa& wi) -{ - Lambertian lambertian = make_Lambertian(Vec3fa((Vec3fa)This->reflectance)); - return Lambertian__eval(&lambertian,wo,dg,wi); -} - - Vec3fa MatteMaterial__sample(MatteMaterial* This, const BRDF& brdf, const Vec3fa& Lw, const Vec3fa& wo, const DifferentialGeometry& dg, Sample3f& wi_o, Medium& medium, const Vec2f& s) -{ - Lambertian lambertian = make_Lambertian(Vec3fa((Vec3fa)This->reflectance)); - return Lambertian__sample(&lambertian,wo,dg,wi_o,s); -} - -//////////////////////////////////////////////////////////////////////////////// -// Mirror Material // -//////////////////////////////////////////////////////////////////////////////// - - void MirrorMaterial__preprocess(MirrorMaterial* material, BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Medium& medium) -{ -} - - Vec3fa MirrorMaterial__eval(MirrorMaterial* This, const BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Vec3fa& wi) { - return Vec3fa(0.0f); -} - - Vec3fa MirrorMaterial__sample(MirrorMaterial* This, const BRDF& brdf, const Vec3fa& Lw, const Vec3fa& wo, const DifferentialGeometry& dg, Sample3f& wi_o, Medium& medium, const Vec2f& s) -{ - wi_o = reflect_(wo,dg.Ns); - return Vec3fa(This->reflectance); -} - -//////////////////////////////////////////////////////////////////////////////// -// OBJ Material // -//////////////////////////////////////////////////////////////////////////////// - - void OBJMaterial__preprocess(OBJMaterial* material, BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Medium& medium) -{ - - float d = material->d; - //if (material->map_d) { d *= material->map_d.get(s,t); } - brdf.Ka = Vec3fa(material->Ka); - //if (material->map_Ka) { brdf.Ka *= material->map_Ka->get(dg.st); } - brdf.Kd = d * Vec3fa(material->Kd); - //if (material->map_Kd) brdf.Kd *= material->map_Kd->get(dg.st); - -#if ENABLE_TEXTURING == 1 - if (material->map_Kd) - { -#if ENABLE_PTEX == 1 - brdf.Kd = d * getPtexTexel3f(material->map_Kd, dg.primID, dg.v, dg.u); -#else - brdf.Kd = getTextureTexel3f(material->map_Kd,dg.u,dg.v); -#endif - } -#endif - - brdf.Ks = d * Vec3fa(material->Ks); - //if (material->map_Ks) brdf.Ks *= material->map_Ks->get(dg.st); - brdf.Ns = material->Ns; - //if (material->map_Ns) { brdf.Ns *= material->map_Ns.get(dg.st); } - brdf.Kt = (1.0f-d)*Vec3fa(material->Kt); - brdf.Ni = material->Ni; - -} - - Vec3fa OBJMaterial__eval(OBJMaterial* material, const BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Vec3fa& wi) -{ - Vec3fa R = Vec3fa(0.0f,0.0f,0.0f); - const float Md = max(max(brdf.Kd.x,brdf.Kd.y),brdf.Kd.z); - const float Ms = max(max(brdf.Ks.x,brdf.Ks.y),brdf.Ks.z); - const float Mt = max(max(brdf.Kt.x,brdf.Kt.y),brdf.Kt.z); - if (Md > 0.0f) { - R = R + (1.0f/float(pi)) * clamp(dot(wi,dg.Ns)) * brdf.Kd; // FIXME: += - } - if (Ms > 0.0f) { - const Sample3f refl = reflect_(wo,dg.Ns); - if (dot(refl.v,wi) > 0.0f) - R = R + (brdf.Ns+2) * float(one_over_two_pi) * pow(max(1e-10f,dot(refl.v,wi)),brdf.Ns) * clamp(dot(wi,dg.Ns)) * brdf.Ks; // FIXME: += - } - if (Mt > 0.0f) { - } - return R; -} - - Vec3fa OBJMaterial__sample(OBJMaterial* material, const BRDF& brdf, const Vec3fa& Lw, const Vec3fa& wo, const DifferentialGeometry& dg, Sample3f& wi_o, Medium& medium, const Vec2f& s) -{ - Vec3fa cd = Vec3fa(0.0f); - Sample3f wid = Sample3f(Vec3fa(0.0f),0.0f); - if (max(max(brdf.Kd.x,brdf.Kd.y),brdf.Kd.z) > 0.0f) { - wid = cosineSampleHemisphere(s.x,s.y,dg.Ns); - cd = float(one_over_pi) * clamp(dot(wid.v,dg.Ns)) * brdf.Kd; - } - - Vec3fa cs = Vec3fa(0.0f); - Sample3f wis = Sample3f(Vec3fa(0.0f),0.0f); - if (max(max(brdf.Ks.x,brdf.Ks.y),brdf.Ks.z) > 0.0f) - { - const Sample3f refl = reflect_(wo,dg.Ns); - wis = powerCosineSampleHemisphere(s.x,s.y,refl.v,brdf.Ns); - cs = (brdf.Ns+2) * float(one_over_two_pi) * pow(dot(refl.v,wis.v),brdf.Ns) * clamp(dot(wis.v,dg.Ns)) * brdf.Ks; - } - - Vec3fa ct = Vec3fa(0.0f); - Sample3f wit = Sample3f(Vec3fa(0.0f),0.0f); - if (max(max(brdf.Kt.x,brdf.Kt.y),brdf.Kt.z) > 0.0f) - { - wit = Sample3f(neg(wo),1.0f); - ct = brdf.Kt; - } - - const Vec3fa md = Lw*cd/wid.pdf; - const Vec3fa ms = Lw*cs/wis.pdf; - const Vec3fa mt = Lw*ct/wit.pdf; - - const float Cd = wid.pdf == 0.0f ? 0.0f : max(max(md.x,md.y),md.z); - const float Cs = wis.pdf == 0.0f ? 0.0f : max(max(ms.x,ms.y),ms.z); - const float Ct = wit.pdf == 0.0f ? 0.0f : max(max(mt.x,mt.y),mt.z); - const float C = Cd + Cs + Ct; - - if (C == 0.0f) { - wi_o = Sample3f(Vec3fa(0,0,0),0); - return Vec3fa(0,0,0); - } - - const float CPd = Cd/C; - const float CPs = Cs/C; - const float CPt = Ct/C; - - if (s.x < CPd) { - wi_o = Sample3f(wid.v,wid.pdf*CPd); - return cd; - } - else if (s.x < CPd + CPs) - { - wi_o = Sample3f(wis.v,wis.pdf*CPs); - return cs; - } - else - { - wi_o = Sample3f(wit.v,wit.pdf*CPt); - return ct; - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Metal Material // -//////////////////////////////////////////////////////////////////////////////// - - void MetalMaterial__preprocess(MetalMaterial* material, BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Medium& medium) -{ -} - - Vec3fa MetalMaterial__eval(MetalMaterial* This, const BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Vec3fa& wi) -{ - const FresnelConductor fresnel = make_FresnelConductor(Vec3fa(This->eta),Vec3fa(This->k)); - const PowerCosineDistribution distribution = make_PowerCosineDistribution(rcp(This->roughness)); - - const float cosThetaO = dot(wo,dg.Ns); - const float cosThetaI = dot(wi,dg.Ns); - if (cosThetaI <= 0.0f || cosThetaO <= 0.0f) return Vec3fa(0.f); - const Vec3fa wh = normalize(wi+wo); - const float cosThetaH = dot(wh, dg.Ns); - const float cosTheta = dot(wi, wh); // = dot(wo, wh); - const Vec3fa F = eval(fresnel,cosTheta); - const float D = eval(distribution,cosThetaH); - const float G = min(1.0f, min(2.0f * cosThetaH * cosThetaO / cosTheta, - 2.0f * cosThetaH * cosThetaI / cosTheta)); - return (Vec3fa(This->reflectance)*F) * D * G * rcp(4.0f*cosThetaO); -} - - Vec3fa MetalMaterial__sample(MetalMaterial* This, const BRDF& brdf, const Vec3fa& Lw, const Vec3fa& wo, const DifferentialGeometry& dg, Sample3f& wi_o, Medium& medium, const Vec2f& s) -{ - const PowerCosineDistribution distribution = make_PowerCosineDistribution(rcp(This->roughness)); - - if (dot(wo,dg.Ns) <= 0.0f) return Vec3fa(0.0f); - sample(distribution,wo,dg.Ns,wi_o,s); - if (dot(wi_o.v,dg.Ns) <= 0.0f) return Vec3fa(0.0f); - return MetalMaterial__eval(This,brdf,wo,dg,wi_o.v); -} - -//////////////////////////////////////////////////////////////////////////////// -// ReflectiveMetal Material // -//////////////////////////////////////////////////////////////////////////////// - - void ReflectiveMetalMaterial__preprocess(ReflectiveMetalMaterial* material, BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Medium& medium) { -} - - Vec3fa ReflectiveMetalMaterial__eval(ReflectiveMetalMaterial* This, const BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Vec3fa& wi) { - return Vec3fa(0.0f); -} - - Vec3fa ReflectiveMetalMaterial__sample(ReflectiveMetalMaterial* This, const BRDF& brdf, const Vec3fa& Lw, const Vec3fa& wo, const DifferentialGeometry& dg, Sample3f& wi_o, Medium& medium, const Vec2f& s) -{ - wi_o = reflect_(wo,dg.Ns); - return Vec3fa(This->reflectance) * fresnelConductor(dot(wo,dg.Ns),Vec3fa((Vec3fa)This->eta),Vec3fa((Vec3fa)This->k)); -} - -//////////////////////////////////////////////////////////////////////////////// -// Velvet Material // -//////////////////////////////////////////////////////////////////////////////// - - void VelvetMaterial__preprocess(VelvetMaterial* material, BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Medium& medium) -{ -} - - Vec3fa VelvetMaterial__eval(VelvetMaterial* This, const BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Vec3fa& wi) -{ - Minneart minneart; Minneart__Constructor(&minneart,(Vec3fa)Vec3fa(This->reflectance),This->backScattering); - Velvety velvety; Velvety__Constructor (&velvety,Vec3fa((Vec3fa)This->horizonScatteringColor),This->horizonScatteringFallOff); - return Minneart__eval(&minneart,wo,dg,wi) + Velvety__eval(&velvety,wo,dg,wi); -} - - Vec3fa VelvetMaterial__sample(VelvetMaterial* This, const BRDF& brdf, const Vec3fa& Lw, const Vec3fa& wo, const DifferentialGeometry& dg, Sample3f& wi_o, Medium& medium, const Vec2f& s) -{ - Minneart minneart; Minneart__Constructor(&minneart,Vec3fa((Vec3fa)This->reflectance),This->backScattering); - Velvety velvety; Velvety__Constructor (&velvety,Vec3fa((Vec3fa)This->horizonScatteringColor),This->horizonScatteringFallOff); - - Sample3f wi0; Vec3fa c0 = Minneart__sample(&minneart,wo,dg,wi0,s); - Sample3f wi1; Vec3fa c1 = Velvety__sample(&velvety,wo,dg,wi1,s); - return sample_component2(c0,wi0,medium,c1,wi1,medium,Lw,wi_o,medium,s.x); -} - -//////////////////////////////////////////////////////////////////////////////// -// Dielectric Material // -//////////////////////////////////////////////////////////////////////////////// - - void DielectricMaterial__preprocess(DielectricMaterial* material, BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Medium& medium) -{ -} - - Vec3fa DielectricMaterial__eval(DielectricMaterial* material, const BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Vec3fa& wi) { - return Vec3fa(0.0f); -} - - Vec3fa DielectricMaterial__sample(DielectricMaterial* material, const BRDF& brdf, const Vec3fa& Lw, const Vec3fa& wo, const DifferentialGeometry& dg, Sample3f& wi_o, Medium& medium, const Vec2f& s) -{ - float eta = 0.0f; - Medium mediumOutside = make_Medium(Vec3fa((Vec3fa)material->transmissionOutside),material->etaOutside); - Medium mediumInside = make_Medium(Vec3fa((Vec3fa)material->transmissionInside ),material->etaInside ); - Medium mediumFront, mediumBack; - if (eq(medium,mediumInside)) { - eta = material->etaInside/material->etaOutside; - mediumFront = mediumInside; - mediumBack = mediumOutside; - } - else { - eta = material->etaOutside/material->etaInside; - mediumFront = mediumOutside; - mediumBack = mediumInside; - } - - float cosThetaO = clamp(dot(wo,dg.Ns)); - float cosThetaI; Sample3f wit = refract(wo,dg.Ns,eta,cosThetaO,cosThetaI); - Sample3f wis = reflect_(wo,dg.Ns); - float R = fresnelDielectric(cosThetaO,cosThetaI,eta); - Vec3fa cs = Vec3fa(R); - Vec3fa ct = Vec3fa(1.0f-R); - return sample_component2(cs,wis,mediumFront,ct,wit,mediumBack,Lw,wi_o,medium,s.x); -} - -//////////////////////////////////////////////////////////////////////////////// -// ThinDielectric Material // -//////////////////////////////////////////////////////////////////////////////// - - void ThinDielectricMaterial__preprocess(ThinDielectricMaterial* This, BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Medium& medium) -{ -} - - Vec3fa ThinDielectricMaterial__eval(ThinDielectricMaterial* This, const BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Vec3fa& wi) { - return Vec3fa(0.0f); -} - - Vec3fa ThinDielectricMaterial__sample(ThinDielectricMaterial* This, const BRDF& brdf, const Vec3fa& Lw, const Vec3fa& wo, const DifferentialGeometry& dg, Sample3f& wi_o, Medium& medium, const Vec2f& s) -{ - float cosThetaO = clamp(dot(wo,dg.Ns)); - if (cosThetaO <= 0.0f) return Vec3fa(0.0f); - float R = fresnelDielectric(cosThetaO,rcp(This->eta)); - Sample3f wit = Sample3f(neg(wo),1.0f); - Sample3f wis = reflect_(wo,dg.Ns); - Vec3fa ct = exp(Vec3fa(This->transmission)*rcp(cosThetaO))*Vec3fa(1.0f-R); - Vec3fa cs = Vec3fa(R); - return sample_component2(cs,wis,medium,ct,wit,medium,Lw,wi_o,medium,s.x); -} - -//////////////////////////////////////////////////////////////////////////////// -// MetallicPaint Material // -//////////////////////////////////////////////////////////////////////////////// - - void MetallicPaintMaterial__preprocess(MetallicPaintMaterial* material, BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Medium& medium) -{ -} - - Vec3fa MetallicPaintMaterial__eval(MetallicPaintMaterial* This, const BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Vec3fa& wi) -{ - DielectricReflection reflection; DielectricReflection__Constructor(&reflection, 1.0f, This->eta); - DielectricLayerLambertian lambertian; DielectricLayerLambertian__Constructor(&lambertian, Vec3fa((float)1.0f), 1.0f, This->eta, make_Lambertian(Vec3fa((Vec3fa)This->shadeColor))); - return DielectricReflection__eval(&reflection,wo,dg,wi) + DielectricLayerLambertian__eval(&lambertian,wo,dg,wi); -} - - Vec3fa MetallicPaintMaterial__sample(MetallicPaintMaterial* This, const BRDF& brdf, const Vec3fa& Lw, const Vec3fa& wo, const DifferentialGeometry& dg, Sample3f& wi_o, Medium& medium, const Vec2f& s) -{ - DielectricReflection reflection; DielectricReflection__Constructor(&reflection, 1.0f, This->eta); - DielectricLayerLambertian lambertian; DielectricLayerLambertian__Constructor(&lambertian, Vec3fa((float)1.0f), 1.0f, This->eta, make_Lambertian(Vec3fa((Vec3fa)This->shadeColor))); - Sample3f wi0; Vec3fa c0 = DielectricReflection__sample(&reflection,wo,dg,wi0,s); - Sample3f wi1; Vec3fa c1 = DielectricLayerLambertian__sample(&lambertian,wo,dg,wi1,s); - return sample_component2(c0,wi0,medium,c1,wi1,medium,Lw,wi_o,medium,s.x); -} - -//////////////////////////////////////////////////////////////////////////////// -// Material // -//////////////////////////////////////////////////////////////////////////////// - -inline void Material__preprocess(ISPCMaterial* materials, int materialID, int numMaterials, BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Medium& medium) -{ - - { - - ISPCMaterial* material = &materials[materialID]; - - switch (material->ty) { - case MATERIAL_OBJ : OBJMaterial__preprocess ((OBJMaterial*) material,brdf,wo,dg,medium); break; - case MATERIAL_METAL: MetalMaterial__preprocess((MetalMaterial*)material,brdf,wo,dg,medium); break; - case MATERIAL_REFLECTIVE_METAL: ReflectiveMetalMaterial__preprocess((ReflectiveMetalMaterial*)material,brdf,wo,dg,medium); break; - case MATERIAL_VELVET: VelvetMaterial__preprocess((VelvetMaterial*)material,brdf,wo,dg,medium); break; - case MATERIAL_DIELECTRIC: DielectricMaterial__preprocess((DielectricMaterial*)material,brdf,wo,dg,medium); break; - case MATERIAL_METALLIC_PAINT: MetallicPaintMaterial__preprocess((MetallicPaintMaterial*)material,brdf,wo,dg,medium); break; - case MATERIAL_MATTE: MatteMaterial__preprocess((MatteMaterial*)material,brdf,wo,dg,medium); break; - case MATERIAL_MIRROR: MirrorMaterial__preprocess((MirrorMaterial*)material,brdf,wo,dg,medium); break; - case MATERIAL_THIN_DIELECTRIC: ThinDielectricMaterial__preprocess((ThinDielectricMaterial*)material,brdf,wo,dg,medium); break; - default: break; - } - } -} - -inline Vec3fa Material__eval(ISPCMaterial* materials, int materialID, int numMaterials, const BRDF& brdf, const Vec3fa& wo, const DifferentialGeometry& dg, const Vec3fa& wi) -{ - Vec3fa c = Vec3fa(0.0f); - - { - - ISPCMaterial* material = &materials[materialID]; - switch (material->ty) { - case MATERIAL_OBJ : c = OBJMaterial__eval ((OBJMaterial*) material, brdf, wo, dg, wi); break; - case MATERIAL_METAL: c = MetalMaterial__eval((MetalMaterial*)material, brdf, wo, dg, wi); break; - case MATERIAL_REFLECTIVE_METAL: c = ReflectiveMetalMaterial__eval((ReflectiveMetalMaterial*)material, brdf, wo, dg, wi); break; - case MATERIAL_VELVET: c = VelvetMaterial__eval((VelvetMaterial*)material, brdf, wo, dg, wi); break; - case MATERIAL_DIELECTRIC: c = DielectricMaterial__eval((DielectricMaterial*)material, brdf, wo, dg, wi); break; - case MATERIAL_METALLIC_PAINT: c = MetallicPaintMaterial__eval((MetallicPaintMaterial*)material, brdf, wo, dg, wi); break; - case MATERIAL_MATTE: c = MatteMaterial__eval((MatteMaterial*)material, brdf, wo, dg, wi); break; - case MATERIAL_MIRROR: c = MirrorMaterial__eval((MirrorMaterial*)material, brdf, wo, dg, wi); break; - case MATERIAL_THIN_DIELECTRIC: c = ThinDielectricMaterial__eval((ThinDielectricMaterial*)material, brdf, wo, dg, wi); break; - default: c = Vec3fa(0.0f); - } - } - return c; -} - -inline Vec3fa Material__sample(ISPCMaterial* materials, int materialID, int numMaterials, const BRDF& brdf, const Vec3fa& Lw, const Vec3fa& wo, const DifferentialGeometry& dg, Sample3f& wi_o, Medium& medium, const Vec2f& s) -{ - Vec3fa c = Vec3fa(0.0f); - - { - - ISPCMaterial* material = &materials[materialID]; - switch (material->ty) { - case MATERIAL_OBJ : c = OBJMaterial__sample ((OBJMaterial*) material, brdf, Lw, wo, dg, wi_o, medium, s); break; - case MATERIAL_METAL: c = MetalMaterial__sample((MetalMaterial*)material, brdf, Lw, wo, dg, wi_o, medium, s); break; - case MATERIAL_REFLECTIVE_METAL: c = ReflectiveMetalMaterial__sample((ReflectiveMetalMaterial*)material, brdf, Lw, wo, dg, wi_o, medium, s); break; - case MATERIAL_VELVET: c = VelvetMaterial__sample((VelvetMaterial*)material, brdf, Lw, wo, dg, wi_o, medium, s); break; - case MATERIAL_DIELECTRIC: c = DielectricMaterial__sample((DielectricMaterial*)material, brdf, Lw, wo, dg, wi_o, medium, s); break; - case MATERIAL_METALLIC_PAINT: c = MetallicPaintMaterial__sample((MetallicPaintMaterial*)material, brdf, Lw, wo, dg, wi_o, medium, s); break; - case MATERIAL_MATTE: c = MatteMaterial__sample((MatteMaterial*)material, brdf, Lw, wo, dg, wi_o, medium, s); break; - case MATERIAL_MIRROR: c = MirrorMaterial__sample((MirrorMaterial*)material, brdf, Lw, wo, dg, wi_o, medium, s); break; - case MATERIAL_THIN_DIELECTRIC: c = ThinDielectricMaterial__sample((ThinDielectricMaterial*)material, brdf, Lw, wo, dg, wi_o, medium, s); break; - default: c = Vec3fa(0.0f); - } - } - return c; -} - -#if !defined(CODE_DISABLED) - -//////////////////////////////////////////////////////////////////////////////// -// Scene // -//////////////////////////////////////////////////////////////////////////////// - -/* scene data */ -extern "C" ISPCScene* g_ispc_scene; -RTCDevice g_device = nullptr; -RTCScene g_scene = nullptr; -void** geomID_to_mesh = nullptr; -int* geomID_to_type = nullptr; - -/* render function to use */ -renderPixelFunc renderPixel; - -/* occlusion filter function */ -#if ENABLE_OCCLUSION_FILTER == 1 -void occlusionFilterReject(void* ptr, RTCRay& ray) { - ray.geomID = RTC_INVALID_GEOMETRY_ID; -} -#endif - -/* error reporting function */ -void error_handler(const RTCError code, const char* str) -{ - printf("Embree: "); - switch (code) { - case RTC_UNKNOWN_ERROR : printf("RTC_UNKNOWN_ERROR"); break; - case RTC_INVALID_ARGUMENT : printf("RTC_INVALID_ARGUMENT"); break; - case RTC_INVALID_OPERATION: printf("RTC_INVALID_OPERATION"); break; - case RTC_OUT_OF_MEMORY : printf("RTC_OUT_OF_MEMORY"); break; - case RTC_UNSUPPORTED_CPU : printf("RTC_UNSUPPORTED_CPU"); break; - case RTC_CANCELLED : printf("RTC_CANCELLED"); break; - default : printf("invalid error code"); break; - } - if (str) { - printf(" ("); - while (*str) putchar(*str++); - printf(")\n"); - } - exit(1); -} // error handler - -/* accumulation buffer */ -Vec3fa* g_accu = nullptr; -unsigned int g_accu_width = 0; -unsigned int g_accu_height = 0; -unsigned int g_accu_count = 0; -Vec3fa g_accu_vx; -Vec3fa g_accu_vy; -Vec3fa g_accu_vz; -Vec3fa g_accu_p; -extern "C" bool g_changed; - -bool g_animation = true; -bool g_use_smooth_normals = false; -void device_key_pressed(int key) -{ - if (key == 32 /* */) g_animation = !g_animation; - if (key == 115 /*c*/) { g_use_smooth_normals = !g_use_smooth_normals; g_changed = true; } - else device_key_pressed_default(key); -} - -/* called by the C++ code for initialization */ -extern "C" void device_init (char* cfg) -{ - /* initialize last seen camera */ - g_accu_vx = Vec3fa(0.0f); - g_accu_vy = Vec3fa(0.0f); - g_accu_vz = Vec3fa(0.0f); - g_accu_p = Vec3fa(0.0f); - - /* create new Embree device */ - g_device = rtcNewDevice(cfg); - - /* set error handler */ - rtcDeviceSetErrorFunction(g_device,error_handler); - - /* set start render mode */ - renderPixel = renderPixelStandard; - // renderPixel = renderPixelEyeLight; - key_pressed_handler = device_key_pressed; - -} // device_init - - -#if ENABLE_DISPLACEMENTS -void displacementFunction(void* ptr, unsigned int geomID, int unsigned primID, - const float* u, /*!< u coordinates (source) */ - const float* v, /*!< v coordinates (source) */ - const float* nx, /*!< x coordinates of normal at point to displace (source) */ - const float* ny, /*!< y coordinates of normal at point to displace (source) */ - const float* nz, /*!< z coordinates of normal at point to displace (source) */ - float* px, /*!< x coordinates of points to displace (source and target) */ - float* py, /*!< y coordinates of points to displace (source and target) */ - float* pz, /*!< z coordinates of points to displace (source and target) */ - size_t N) -{ - ISPCSubdivMesh* mesh = (ISPCSubdivMesh*)geomID_to_mesh[geomID]; - int materialID = mesh->materialID; - int numMaterials = g_ispc_scene->numMaterials; - OBJMaterial* material = (OBJMaterial*)&g_ispc_scene->materials[materialID]; - if (material->map_Displ) - for (size_t i=0;imap_Displ, primID, v[i], u[i]); - px[i] += nx[i] * displ; - py[i] += ny[i] * displ; - pz[i] += nz[i] * displ; - } -} -#endif - -void convertTriangleMeshes(ISPCScene* scene_in, RTCScene scene_out, size_t numGeometries) -{ - /* add all meshes to the scene */ - for (int i=0; inumMeshes; i++) - { - - /* get ith mesh */ - ISPCMesh* mesh = scene_in->meshes[i]; - - /* create a triangle mesh */ - unsigned int geomID = rtcNewTriangleMesh (scene_out, RTC_GEOMETRY_STATIC, mesh->numTriangles, mesh->numVertices); - assert(geomID < numGeometries); - geomID_to_mesh[geomID] = mesh; - geomID_to_type[geomID] = 0; - - /* set vertices */ - Vertex* vertices = (Vertex*) rtcMapBuffer(scene_out,geomID,RTC_VERTEX_BUFFER); - for (int j=0; jnumVertices; j++) { - vertices[j].x = mesh->positions[j].x; - vertices[j].y = mesh->positions[j].y; - vertices[j].z = mesh->positions[j].z; - } - rtcUnmapBuffer(scene_out,geomID,RTC_VERTEX_BUFFER); - - /* set triangles */ - Triangle* triangles = (Triangle*) rtcMapBuffer(scene_out,geomID,RTC_INDEX_BUFFER); - for (int j=0; jnumTriangles; j++) { - triangles[j].v0 = mesh->triangles[j].v0; - triangles[j].v1 = mesh->triangles[j].v1; - triangles[j].v2 = mesh->triangles[j].v2; - } - rtcUnmapBuffer(scene_out,geomID,RTC_INDEX_BUFFER); - - bool allOpaque = true; - bool allTransparent = true; - for (size_t j=0; jnumTriangles; j++) { - ISPCTriangle triangle = mesh->triangles[j]; - if (g_ispc_scene->materials[triangle.materialID].ty == MATERIAL_DIELECTRIC || - g_ispc_scene->materials[triangle.materialID].ty == MATERIAL_THIN_DIELECTRIC) - allOpaque = false; - else - allTransparent = false; - } - -#if ENABLE_OCCLUSION_FILTER == 1 - if (allTransparent) - rtcSetOcclusionFilterFunction(scene_out,geomID,(RTCFilterFunc)&occlusionFilterReject); -#endif - - } -} - -inline float updateEdgeLevel( ISPCSubdivMesh* mesh, const Vec3fa& cam_pos, const size_t e0, const size_t e1) -{ - const Vec3fa v0 = mesh->positions[mesh->position_indices[e0]]; - const Vec3fa v1 = mesh->positions[mesh->position_indices[e1]]; - const Vec3fa edge = v1-v0; - const Vec3fa P = 0.5f*(v1+v0); - const Vec3fa dist = cam_pos - P; - return max(min(LEVEL_FACTOR*(0.5f*length(edge)/length(dist)),MAX_EDGE_LEVEL),MIN_EDGE_LEVEL); -} - -void updateEdgeLevelBuffer( ISPCSubdivMesh* mesh, const Vec3fa& cam_pos, size_t startID, size_t endID ) -{ - for (size_t f=startID; fface_offsets[f]; - int N = mesh->verticesPerFace[f]; - if (N == 4) /* fast path for quads */ - for (size_t i=0; i<4; i++) - mesh->subdivlevel[e+i] = updateEdgeLevel(mesh,cam_pos,e+(i+0),e+(i+1)%4); - else if (N == 3) /* fast path for triangles */ - for (size_t i=0; i<3; i++) - mesh->subdivlevel[e+i] = updateEdgeLevel(mesh,cam_pos,e+(i+0),e+(i+1)%3); - else /* fast path for general polygons */ - for (size_t i=0; isubdivlevel[e+i] = updateEdgeLevel(mesh,cam_pos,e+(i+0),e+(i+1)%N); - } -} - -#if defined(ISPC) -task void updateEdgeLevelBufferTask( ISPCSubdivMesh* mesh, const Vec3fa& cam_pos ) -{ - const size_t size = mesh->numFaces; - const size_t startID = ((taskIndex+0)*size)/taskCount; - const size_t endID = ((taskIndex+1)*size)/taskCount; - updateEdgeLevelBuffer(mesh,cam_pos,startID,endID); -} -#endif - -void updateKeyFrame(ISPCScene* scene_in) -{ - for (size_t g=0; gnumSubdivMeshes; g++) - { - ISPCSubdivMesh* mesh = g_ispc_scene->subdiv[g]; - unsigned int geomID = mesh->geomID; - - if (g_ispc_scene->subdivMeshKeyFrames) - { - ISPCSubdivMeshKeyFrame *keyframe = g_ispc_scene->subdivMeshKeyFrames[keyframeID]; - ISPCSubdivMesh *keyframe_mesh = keyframe->subdiv[g]; - rtcSetBuffer(g_scene, geomID, RTC_VERTEX_BUFFER, keyframe_mesh->positions, 0, sizeof(Vec3fa )); - rtcUpdateBuffer(g_scene,geomID,RTC_VERTEX_BUFFER); - } - } - - keyframeID++; - if (keyframeID >= g_ispc_scene->numSubdivMeshKeyFrames) - keyframeID = 0; - -} - - -void updateEdgeLevels(ISPCScene* scene_in, const Vec3fa& cam_pos) -{ - for (size_t g=0; gnumSubdivMeshes; g++) - { - ISPCSubdivMesh* mesh = g_ispc_scene->subdiv[g]; - unsigned int geomID = mesh->geomID; -#if defined(ISPC) - launch[ getNumHWThreads() ] updateEdgeLevelBufferTask(mesh,cam_pos); -#else - updateEdgeLevelBuffer(mesh,cam_pos,0,mesh->numFaces); -#endif - rtcUpdateBuffer(g_scene,geomID,RTC_LEVEL_BUFFER); - } -} - - - -void convertSubdivMeshes(ISPCScene* scene_in, RTCScene scene_out, size_t numGeometries, const Vec3fa& cam_pos) -{ - for (size_t i=0; inumSubdivMeshes; i++) - { - ISPCSubdivMesh* mesh = g_ispc_scene->subdiv[i]; - unsigned int geomID = rtcNewSubdivisionMesh(scene_out, RTC_GEOMETRY_DYNAMIC, mesh->numFaces, mesh->numEdges, mesh->numVertices, - mesh->numEdgeCreases, mesh->numVertexCreases, mesh->numHoles); - mesh->geomID = geomID; - assert(geomID < numGeometries); - geomID_to_mesh[geomID] = mesh; - geomID_to_type[geomID] = 1; //2 - - for (size_t i=0; inumEdges; i++) mesh->subdivlevel[i] = FIXED_EDGE_TESSELLATION_VALUE; - rtcSetBuffer(scene_out, geomID, RTC_VERTEX_BUFFER, mesh->positions, 0, sizeof(Vec3fa )); - rtcSetBuffer(scene_out, geomID, RTC_LEVEL_BUFFER, mesh->subdivlevel, 0, sizeof(float)); - rtcSetBuffer(scene_out, geomID, RTC_INDEX_BUFFER, mesh->position_indices , 0, sizeof(unsigned int)); - rtcSetBuffer(scene_out, geomID, RTC_FACE_BUFFER, mesh->verticesPerFace, 0, sizeof(unsigned int)); - rtcSetBuffer(scene_out, geomID, RTC_HOLE_BUFFER, mesh->holes, 0, sizeof(unsigned int)); - rtcSetBuffer(scene_out, geomID, RTC_EDGE_CREASE_INDEX_BUFFER, mesh->edge_creases, 0, 2*sizeof(unsigned int)); - rtcSetBuffer(scene_out, geomID, RTC_EDGE_CREASE_WEIGHT_BUFFER, mesh->edge_crease_weights, 0, sizeof(float)); - rtcSetBuffer(scene_out, geomID, RTC_VERTEX_CREASE_INDEX_BUFFER, mesh->vertex_creases, 0, sizeof(unsigned int)); - rtcSetBuffer(scene_out, geomID, RTC_VERTEX_CREASE_WEIGHT_BUFFER, mesh->vertex_crease_weights, 0, sizeof(float)); -#if ENABLE_DISPLACEMENTS == 1 - rtcSetDisplacementFunction(scene_out,geomID,(RTCDisplacementFunc)&displacementFunction,nullptr); -#endif - } -} - - - - -typedef void* void_ptr; - -RTCScene convertScene(ISPCScene* scene_in,const Vec3fa& cam_org) -{ - size_t numGeometries = scene_in->numMeshes + scene_in->numSubdivMeshes; - - geomID_to_mesh = new void_ptr[numGeometries]; - geomID_to_type = new int[numGeometries]; - - /* create scene */ - int scene_flags = RTC_SCENE_STATIC | RTC_SCENE_INCOHERENT; - int scene_aflags = RTC_INTERSECT1; - - if (g_subdiv_mode) - scene_flags = RTC_SCENE_DYNAMIC | RTC_SCENE_INCOHERENT | RTC_SCENE_ROBUST; - - scene_aflags |= RTC_INTERPOLATE; - - RTCScene scene_out = rtcDeviceNewScene(g_device,(RTCSceneFlags)scene_flags, (RTCAlgorithmFlags) scene_aflags); - convertTriangleMeshes(scene_in,scene_out,numGeometries); - convertSubdivMeshes(scene_in,scene_out,numGeometries,cam_org); - - - /* commit changes to scene */ - progressStart(); - rtcSetProgressMonitorFunction(scene_out,progressMonitor,nullptr); - rtcCommit (scene_out); - rtcSetProgressMonitorFunction(scene_out,nullptr,nullptr); - progressEnd(); - - return scene_out; -} // convertScene - -#endif - -/* for details about this random number generator see: P. L'Ecuyer, - "Maximally Equidistributed Combined Tausworthe Generators", - Mathematics of Computation, 65, 213 (1996), 203--213: - http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps */ - -struct rand_state { - unsigned int s1, s2, s3; -}; - -inline unsigned int irand(rand_state& state) -{ - state.s1 = ((state.s1 & 4294967294U) << 12U) ^ (((state.s1<<13U)^state.s1)>>19U); - state.s2 = ((state.s2 & 4294967288U) << 4U) ^ (((state.s2<< 2U)^state.s2)>>25U); - state.s3 = ((state.s3 & 4294967280U) << 17U) ^ (((state.s3<< 3U)^state.s3)>>11U); - return state.s1 ^ state.s2 ^ state.s3; -} - -inline void init_rand(rand_state& state, unsigned int x, unsigned int y, unsigned int z) -{ - state.s1 = x >= 2 ? x : x + 2; - state.s2 = y >= 8 ? y : y + 8; - state.s3 = z >= 16 ? z : z + 16; - for (int i=0; i<10; i++) irand(state); -} - -inline float frand(rand_state& state) { - return irand(state)*2.3283064365386963e-10f; -} - -inline Vec3fa face_forward(const Vec3fa& dir, const Vec3fa& _Ng) { - const Vec3fa Ng = _Ng; - return dot(dir,Ng) < 0.0f ? Ng : neg(Ng); -} - -#if 0 -inline Vec3fa interpolate_normal(RTCRay& ray) -{ -#if 1 // FIXME: pointer gather not implemented on ISPC for Xeon Phi - ISPCMesh* mesh = g_ispc_scene->meshes[ray.geomID]; - ISPCTriangle* tri = &mesh->triangles[ray.primID]; - - /* load material ID */ - int materialID = tri->materialID; - - /* interpolate shading normal */ - if (mesh->normals) { - Vec3fa n0 = Vec3fa(mesh->normals[tri->v0]); - Vec3fa n1 = Vec3fa(mesh->normals[tri->v1]); - Vec3fa n2 = Vec3fa(mesh->normals[tri->v2]); - float u = ray.u, v = ray.v, w = 1.0f-ray.u-ray.v; - return normalize(w*n0 + u*n1 + v*n2); - } else { - return normalize(ray.Ng); - } - -#else - - Vec3fa Ns = Vec3fa(0.0f); - int materialID = 0; - int geomID = ray.geomID; - { - if (geomID >= 0 && geomID < g_ispc_scene->numMeshes) { // FIXME: workaround for ISPC bug - - ISPCMesh* mesh = g_ispc_scene->meshes[geomID]; - - foreach_unique (primID in ray.primID) - { - ISPCTriangle* tri = &mesh->triangles[primID]; - - /* load material ID */ - materialID = tri->materialID; - - /* interpolate shading normal */ - if (mesh->normals) { - Vec3fa n0 = Vec3fa(mesh->normals[tri->v0]); - Vec3fa n1 = Vec3fa(mesh->normals[tri->v1]); - Vec3fa n2 = Vec3fa(mesh->normals[tri->v2]); - float u = ray.u, v = ray.v, w = 1.0f-ray.u-ray.v; - Ns = w*n0 + u*n1 + v*n2; - } else { - Ns = normalize(ray.Ng); - } - } - } - } - return normalize(Ns); -#endif -} -#endif - -#if !defined(CODE_DISABLED) -#if 1 // FIXME: pointer gather not implemented in ISPC for Xeon Phi -inline int getMaterialID(const RTCRay& ray, DifferentialGeometry& dg) -{ - int materialID = 0; - if (geomID_to_type[ray.geomID] == 0) - materialID = ((ISPCMesh*) geomID_to_mesh[ray.geomID])->triangles[ray.primID].materialID; - else if (geomID_to_type[ray.geomID] == 1) - { - materialID = ((ISPCSubdivMesh*) geomID_to_mesh[ray.geomID])->materialID; -#if ENABLE_TEXTURING == 1 - const Vec2f st = getTextureCoordinatesSubdivMesh((ISPCSubdivMesh*) geomID_to_mesh[ray.geomID],ray.primID,ray.u,ray.v); - dg.u = st.x; - dg.v = st.y; -#endif - } - else - materialID = ((ISPCMesh*) geomID_to_mesh[ray.geomID])->meshMaterialID; - - return materialID; -} -#else -inline int getMaterialID(const RTCRay& ray, DifferentialGeometry dg) -{ - int materialID = 0; - int geomID = ray.geomID; { - - if (geomID >= 0 && geomID < g_ispc_scene->numMeshes+g_ispc_scene->numSubdivMeshes) { // FIXME: workaround for ISPC bug - if (geomID_to_type[geomID] == 0) - materialID = ((ISPCMesh*) geomID_to_mesh[geomID])->triangles[ray.primID].materialID; - else if (geomID_to_type[geomID] == 1) - { - materialID = ((ISPCSubdivMesh*) geomID_to_mesh[geomID])->materialID; -#if ENABLE_TEXTURE_COORDINATES == 1 - const Vec2f st = getTextureCoordinatesSubdivMesh((ISPCSubdivMesh*) geomID_to_mesh[geomID],ray.primID,ray.u,ray.v); - dg.u = st.x; - dg.v = st.y; -#endif - } - else - materialID = ((ISPCMesh*) geomID_to_mesh[geomID])->meshMaterialID; - } - } - return materialID; -} -#endif -#endif - -Vec3fa renderPixelFunction(float x, float y, rand_state& state, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p) -{ - - /* radiance accumulator and weight */ - Vec3fa L = Vec3fa(0.0f); - Vec3fa Lw = Vec3fa(1.0f); - Medium medium = make_Medium_Vacuum(); - - /* initialize ray */ - RTCRay ray = RTCRay(p,normalize(x*vx + y*vy + vz),0.0f,inf); - - /* iterative path tracer loop */ - for (int i=0; inumAmbientLights; i++) - L = L + Lw*AmbientLight__eval(g_ispc_scene->ambientLights[i],ray.dir); // FIXME: += -#endif - -#if 0 - /* iterate over all distant lights */ - for (size_t i=0; inumDistantLights; i++) - L = L + Lw*DistantLight__eval(g_ispc_scene->distantLights[i],ray.dir); // FIXME: += -#endif - break; - } - Vec3fa Ns = normalize(ray.Ng); - - if (g_use_smooth_normals) - if (ray.geomID != RTC_INVALID_GEOMETRY_ID) // FIXME: workaround for ISPC bug, location reached with empty execution mask - { - Vec3fa dPdu,dPdv; - int geomID = ray.geomID; { - rtcInterpolate(g_scene,geomID,ray.primID,ray.u,ray.v,RTC_VERTEX_BUFFER0,nullptr,&dPdu.x,&dPdv.x,3); - } - Ns = normalize(cross(dPdv,dPdu)); - } - - /* compute differential geometry */ - DifferentialGeometry dg; - dg.geomID = ray.geomID; - dg.primID = ray.primID; - dg.u = ray.u; - dg.v = ray.v; - dg.P = ray.org+ray.tfar*ray.dir; - dg.Ng = face_forward(ray.dir,normalize(ray.Ng)); - dg.Ns = face_forward(ray.dir,Ns); - - /* shade all rays that hit something */ - int materialID = getMaterialID(ray,dg); - - /*! Compute simple volumetric effect. */ - Vec3fa c = Vec3fa(1.0f); - const Vec3fa transmission = medium.transmission; - if (ne(transmission,Vec3fa(1.0f))) - c = c * pow(transmission,ray.tfar); - - /* calculate BRDF */ // FIXME: avoid gathers - BRDF brdf; - int numMaterials = g_ispc_scene->numMaterials; - //ISPCMaterial* material = &g_ispc_scene->materials[materialID]; - ISPCMaterial* material_array = &g_ispc_scene->materials[0]; - - - Material__preprocess(material_array,materialID,numMaterials,brdf,wo,dg,medium); - - - /* sample BRDF at hit point */ - Sample3f wi1; - c = c * Material__sample(material_array,materialID,numMaterials,brdf,Lw, wo, dg, wi1, medium, Vec2f(frand(state),frand(state))); - - - /* iterate over ambient lights */ - for (size_t i=0; inumAmbientLights; i++) - { -#if 1 - Vec3fa L0 = Vec3fa(0.0f); - Sample3f wi0; float tMax0; - Vec3fa Ll0 = AmbientLight__sample(g_ispc_scene->ambientLights[i],dg,wi0,tMax0,Vec2f(frand(state),frand(state))); - - if (wi0.pdf > 0.0f) { - RTCRay shadow = RTCRay(dg.P,wi0.v,0.001f,tMax0); - rtcOccluded(g_scene,shadow); - if (shadow.geomID == RTC_INVALID_GEOMETRY_ID) { - L0 = Ll0/wi0.pdf*Material__eval(material_array,materialID,numMaterials,brdf,wo,dg,wi0.v); - } - - L = L + Lw*L0; - } -#endif - -#if 0 - Vec3fa L1 = Vec3fa(0.0f); - Vec3fa Ll1 = AmbientLight__eval(g_ispc_scene->ambientLights[i],wi1.v); - if (wi1.pdf > 0.0f) { - RTCRay shadow = RTCRay(dg.P,wi1.v,0.001f,inf); - rtcOccluded(g_scene,shadow); - if (shadow.geomID == RTC_INVALID_GEOMETRY_ID) { - L1 = Ll1/wi1.pdf*c; - } - L = L + Lw*L1; - } -#endif - -#if 0 - float s = wi0.pdf*wi0.pdf + wi1.pdf*wi1.pdf; - if (s > 0) { - float w0 = 0; - float w1 = 1; - //float w0 = wi0.pdf*wi0.pdf/s; - //float w1 = wi1.pdf*wi1.pdf/s; - L = L + Lw*(w0*L0+w1*L1); - } -#endif - } - Sample3f wi; float tMax; - - /* iterate over point lights */ - for (size_t i=0; inumPointLights; i++) - { - Vec3fa Ll = PointLight__sample(g_ispc_scene->pointLights[i],dg,wi,tMax,Vec2f(frand(state),frand(state))); - if (wi.pdf <= 0.0f) continue; - RTCRay shadow = RTCRay(dg.P,wi.v,0.001f,tMax); - rtcOccluded(g_scene,shadow); - if (shadow.geomID != RTC_INVALID_GEOMETRY_ID) continue; - L = L + Lw*Ll/wi.pdf*Material__eval(material_array,materialID,numMaterials,brdf,wo,dg,wi.v); // FIXME: += - } - - /* iterate over directional lights */ - for (size_t i=0; inumDirectionalLights; i++) - { - Vec3fa Ll = DirectionalLight__sample(g_ispc_scene->dirLights[i],dg,wi,tMax,Vec2f(frand(state),frand(state))); - if (wi.pdf <= 0.0f) continue; - RTCRay shadow = RTCRay(dg.P,wi.v,0.00001f,tMax); - rtcOccluded(g_scene,shadow); - if (shadow.geomID != RTC_INVALID_GEOMETRY_ID) continue; - L = L + Lw*Ll/wi.pdf*Material__eval(material_array,materialID,numMaterials,brdf,wo,dg,wi.v); // FIXME: += - } - - /* iterate over distant lights */ - for (size_t i=0; inumDistantLights; i++) - { - Vec3fa Ll = DistantLight__sample(g_ispc_scene->distantLights[i],dg,wi,tMax,Vec2f(frand(state),frand(state))); - - if (wi.pdf <= 0.0f) continue; - RTCRay shadow = RTCRay(dg.P,wi.v,0.001f,tMax); - rtcOccluded(g_scene,shadow); - if (shadow.geomID != RTC_INVALID_GEOMETRY_ID) continue; - L = L + Lw*Ll/wi.pdf*Material__eval(material_array,materialID,numMaterials,brdf,wo,dg,wi.v); // FIXME: += - } - if (wi1.pdf <= 1E-4f /* 0.0f */) break; - Lw = Lw*c/wi1.pdf; // FIXME: *= - - /* setup secondary ray */ - ray = RTCRay(dg.P,normalize(wi1.v),0.001f,inf); - } - return L; -} - -/* task that renders a single screen tile */ -Vec3fa renderPixelStandard(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p) -{ - rand_state state; - - Vec3fa L = Vec3fa(0.0f,0.0f,0.0f); - - for (int i=0; iw)); - unsigned int r = (unsigned int) (255.0f * clamp(dst->x*f,0.0f,1.0f)); - unsigned int g = (unsigned int) (255.0f * clamp(dst->y*f,0.0f,1.0f)); - unsigned int b = (unsigned int) (255.0f * clamp(dst->z*f,0.0f,1.0f)); - pixels[y*width+x] = (b << 16) + (g << 8) + r; - } -} // renderTile - -/* called by the C++ code to render */ -extern "C" void device_render (int* pixels, - const int width, - const int height, - const float time, - const Vec3fa& vx, - const Vec3fa& vy, - const Vec3fa& vz, - const Vec3fa& p) -{ - Vec3fa cam_org = Vec3fa(p.x,p.y,p.z); - - /* create scene */ - if (g_scene == nullptr) - { - if (g_ispc_scene->numSubdivMeshes > 0) - g_subdiv_mode = true; - - g_scene = convertScene(g_ispc_scene,cam_org); - -#if !defined(FORCE_FIXED_EDGE_TESSELLATION) - if (g_subdiv_mode) - updateEdgeLevels(g_ispc_scene, cam_org); -#endif - - } - - /* create accumulator */ - if (g_accu_width != width || g_accu_height != height) { - alignedFree(g_accu); - g_accu = (Vec3fa*) alignedMalloc(width*height*sizeof(Vec3fa)); - g_accu_width = width; - g_accu_height = height; - memset(g_accu,0,width*height*sizeof(Vec3fa)); - } - - /* reset accumulator */ - bool camera_changed = g_changed; g_changed = false; - camera_changed |= ne(g_accu_vx,vx); g_accu_vx = vx; // FIXME: use != operator - camera_changed |= ne(g_accu_vy,vy); g_accu_vy = vy; // FIXME: use != operator - camera_changed |= ne(g_accu_vz,vz); g_accu_vz = vz; // FIXME: use != operator - camera_changed |= ne(g_accu_p, p); g_accu_p = p; // FIXME: use != operator - - if (g_animation && g_ispc_scene->numSubdivMeshKeyFrames) - { - updateKeyFrame(g_ispc_scene); - rtcCommit(g_scene); - g_changed = true; - } - -#if FIXED_SAMPLING == 0 - g_accu_count++; -#endif - - if (camera_changed) { - g_accu_count=0; - memset(g_accu,0,width*height*sizeof(Vec3fa)); - -#if !defined(FORCE_FIXED_EDGE_TESSELLATION) - if (g_subdiv_mode) - { - updateEdgeLevels(g_ispc_scene, cam_org); - rtcCommit (g_scene); - } -#endif - - } - - /* render image */ - const int numTilesX = (width +TILE_SIZE_X-1)/TILE_SIZE_X; - const int numTilesY = (height+TILE_SIZE_Y-1)/TILE_SIZE_Y; - launch_renderTile(numTilesX*numTilesY,pixels,width,height,time,vx,vy,vz,p,numTilesX,numTilesY); - //rtcDebug(); -} // device_render - -/* called by the C++ code for cleanup */ -extern "C" void device_cleanup () -{ - rtcDeleteScene (g_scene); - rtcDeleteDevice(g_device); - alignedFree(g_accu); -} // device_cleanup - -#endif diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/pathtracer/shapesampler.h b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/pathtracer/shapesampler.h deleted file mode 100644 index a029790c15ba..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/pathtracer/shapesampler.h +++ /dev/null @@ -1,123 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#pragma once - -/*! \file shapesampler.isph Implements sampling functions for different - * geometric shapes. */ - -//inline float cos2sin(const float f) { return sqrt(max(0.f,1.f-f*f)); } -//inline float sin2cos(const float f) { return sqrt(max(0.f,1.f-f*f)); } - -/*! Cosine weighted hemisphere sampling. Up direction is the z direction. */ -inline Sample3f cosineSampleHemisphere(const float u, const float v) { - const float phi = 2.0f * (float(pi)) * u; - const float cosTheta = sqrt(v); - const float sinTheta = sqrt(1.0f - v); - return Sample3f(Vec3fa(cos(phi) * sinTheta, - sin(phi) * sinTheta, - cosTheta), - cosTheta*(1.f/(float(pi)))); -} - -/*! Cosine weighted hemisphere sampling. Up direction is provided as argument. */ -inline Sample3f cosineSampleHemisphere(const float u, const float v, const Vec3fa& N) -{ - Sample3f s = cosineSampleHemisphere(u,v); - return Sample3f(frame(N)*s.v,s.pdf); -} - - /*! Samples hemisphere with power cosine distribution. Up direction - * is the z direction. */ -inline Sample3f powerCosineSampleHemisphere(const float u, const float v, const float _exp) -{ - const float phi = 2.0f * (float(pi)) * u; - const float cosTheta = pow(v,1.0f/(_exp+1.0f)); - const float sinTheta = cos2sin(cosTheta); - return Sample3f(Vec3fa(cos(phi) * sinTheta, - sin(phi) * sinTheta, - cosTheta), - (_exp+1.0f)*pow(cosTheta,_exp)*0.5f/(float(pi))); -} - -/*! Computes the probability density for the power cosine sampling of the hemisphere. */ -inline float powerCosineSampleHemispherePDF(const Vec3fa& s, const float _exp) { - if (s.z < 0.f) return 0.f; - return (_exp+1.0f)*pow(s.z,_exp)*0.5f/float(pi); -} - -/*! Samples hemisphere with power cosine distribution. Up direction - * is provided as argument. */ -inline Sample3f powerCosineSampleHemisphere(const float u, const float v, const Vec3fa& N, const float _exp) { - Sample3f s = powerCosineSampleHemisphere(u,v,_exp); - return Sample3f(frame(N)*s.v,s.pdf); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Sampling of Spherical Cone -//////////////////////////////////////////////////////////////////////////////// - - -/*! Uniform sampling of spherical cone. Cone direction is the z - * direction. */ -inline Sample3f UniformSampleCone(const float u, const float v, const float angle) { - const float phi = (float)(2.0f * float(pi)) * u; - const float cosTheta = 1.0f - v*(1.0f - cos(angle)); - const float sinTheta = cos2sin(cosTheta); - return Sample3f(Vec3fa(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta), 1.0f/((float)(4.0f*float(pi))*sqr(sin(0.5f*angle)))); -} - -/*! Computes the probability density of spherical cone sampling. */ -inline float UniformSampleConePDF(const Vec3fa &s, const float angle) { - return select(s.z < cos(angle), 0.0f, 1.0f/((float)(4.0f*float(pi))*sqr(sin(0.5f*angle)))); -} - -/*! Uniform sampling of spherical cone. Cone direction is provided as argument. */ -inline Sample3f UniformSampleCone(const float u, const float v, const float angle, const Vec3fa& N) { - Sample3f s = UniformSampleCone(u,v,angle); - return Sample3f(frame(N)*s.v,s.pdf); -} - -/*! Computes the probability density of spherical cone sampling. */ -inline float UniformSampleConePDF(const Vec3fa &s, const float angle, const Vec3fa &N) { - // return make_select(dot(s,N) < cos(angle), 0.0f, 1.0f/((float)(4.0f*float(pi))*sqr(sin(0.5f*angle)))); - if (dot(s,N) < cos(angle)) - return 0.f; - else - return 1.0f/((float)(4.0f*float(pi))*sqr(sin(0.5f*angle))); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Sampling of Triangle -//////////////////////////////////////////////////////////////////////////////// - -/*! Uniform sampling of triangle. */ -inline Vec3fa UniformSampleTriangle(const float u, const float v, const Vec3fa& A, const Vec3fa& B, const Vec3fa& C) { - const float su = sqrt(u); - return C + (1.0f-su)*(A-C) + (v*su)*(B-C); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Sampling of Disk -//////////////////////////////////////////////////////////////////////////////// - -/*! Uniform sampling of disk. */ -inline Vec2f UniformSampleDisk(const Vec2f &sample, const float radius) -{ - const float r = sqrt(sample.x); - const float theta = (2.f*float(pi)) * sample.y; - return Vec2f(radius*r*cos(theta), radius*r*sin(theta)); -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/subdivision_geometry/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/subdivision_geometry/CMakeLists.txt deleted file mode 100644 index d760ca6cbfd6..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/subdivision_geometry/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2015 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -# INCLUDE(CMakeDependentOption) - -INCLUDE(tutorial) -ADD_TUTORIAL(subdivision_geometry) diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/subdivision_geometry/subdivision_geometry.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/subdivision_geometry/subdivision_geometry.cpp deleted file mode 100644 index 907a6944c364..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/subdivision_geometry/subdivision_geometry.cpp +++ /dev/null @@ -1,180 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial.h" -#include "../common/tutorial/obj_loader.h" -#include "../common/tutorial/xml_loader.h" -#include "../common/image/image.h" - -namespace embree -{ - /* name of the tutorial */ - const char* tutorialName = "subdivision_geometry"; - - /* configuration */ - static std::string g_rtcore = ""; - static size_t g_numThreads = 0; - static std::string g_subdiv_mode = ""; - - /* output settings */ - static size_t g_width = 512; - static size_t g_height = 512; - static bool g_fullscreen = false; - static FileName outFilename = ""; - static bool g_interactive = true; - - /* scene */ - OBJScene g_obj_scene; - static FileName filename = ""; - - static std::string getParameterString(Ref &cin, std::string &term) { - - /*! Parameter name and options. */ - std::string parameter = term + " "; while (cin->peek() != "" && cin->peek()[0] != '-') parameter += cin->getString(); return(parameter); - - } - - static void initEmbreeState(std::string configuration) { - - /*! Initialize Embree state. */ - init(configuration.c_str()); - - } - - static void parseCommandLine(Ref cin, const FileName &path) { - - for (std::string term = cin->getString() ; term != "" ; term = cin->getString()) { - - /*! Command line parameters from a file. */ - if (term == "-c") { FileName file = path + cin->getFileName(); parseCommandLine(new ParseStream(new LineCommentFilter(file, "#")), file.path()); } - - /* load OBJ model*/ - else if (term == "-i") { - filename = path + cin->getFileName(); - } - - /*! Camera field of view. */ - else if (term == "-fov") g_camera.fov = cin->getFloat(); - - /*! Full screen mode. */ - else if (term == "-fullscreen") g_fullscreen = true; - - /* output filename */ - else if (term == "-o") { - g_interactive = false; - outFilename = cin->getFileName(); - } - - /*! Embree configuration. */ - else if (term == "-rtcore") g_rtcore = cin->getString(); - - /*! Window size. */ - else if (term == "-size") { g_width = cin->getInt(); g_height = cin->getInt(); } - - /*! Thread count. */ - else if (term == "-threads") { g_numThreads = cin->getInt(); } - - /*! Camera view direction. */ - else if (term == "-vd") g_camera.to = g_camera.from + cin->getVec3fa(); - - /*! Camera look point. */ - else if (term == "-vi") g_camera.to = cin->getVec3fa(); - - /*! Camera position. */ - else if (term == "-vp") g_camera.from = cin->getVec3fa(); - - /*! Camera up vector. */ - else if (term == "-vu") g_camera.up = cin->getVec3fa(); - - else if (term == "-cache") - g_subdiv_mode = ",subdiv_accel=bvh4.subdivpatch1cached"; - - else if (term == "-pregenerate") - g_subdiv_mode = ",subdiv_accel=bvh4.grid.eager"; - - /*! Skip unknown command line parameters. */ - else std::cerr << "Unknown command line parameter: " << getParameterString(cin, term) << std::endl; - - } - - } - - void renderToFile(const FileName& fileName) - { - resize(g_width,g_height); - AffineSpace3fa pixel2world = g_camera.pixel2world(g_width,g_height); - - render(0.0f, - pixel2world.l.vx, - pixel2world.l.vy, - pixel2world.l.vz, - pixel2world.p); - - void* ptr = map(); - Ref image = new Image4uc(g_width, g_height, (Col4uc*)ptr); - storeImage(image, fileName); - unmap(); - cleanup(); - } - - int main(int argc, char **argv) - { - /* for best performance set FTZ and DAZ flags in MXCSR control and status register */ - _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); - _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); - - std::cout << " === Possible cmd line options: -pregenerate, -cache === " << std::endl; - - /* set default camera */ - g_camera.from = Vec3fa(1.5f,1.5f,-1.5f); - g_camera.to = Vec3fa(0.0f,0.0f,0.0f); - - /*! Parse command line options. */ - parseCommandLine(new ParseStream(new CommandLineStream(argc, argv)), FileName()); - - /*! Set the thread count in the Embree configuration string. */ - if (g_numThreads) g_rtcore += ",threads=" + std::to_string((long long)g_numThreads); - g_rtcore += g_subdiv_mode; - - /*! Initialize Embree state. */ - init(g_rtcore.c_str()); - - /* render to disk */ - if (outFilename.str() != "") - renderToFile(outFilename); - - /* interactive mode */ - if (g_interactive) { - initWindowState(argc,argv,tutorialName, g_width, g_height, g_fullscreen); - enterWindowRunLoop(); - } - return 0; - } -} - -int main(int argc, char** argv) -{ - /*! Tutorial entry point. */ - try { return embree::main(argc, argv); } - - /*! Known exception. */ - catch (const std::exception& e) { std::cout << "Error: " << e.what() << std::endl; return(1); } - - /*! Unknown exception. */ - catch (...) { std::cout << "Error: unknown exception caught." << std::endl; return(1); } - -} - diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/subdivision_geometry/subdivision_geometry_device.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/subdivision_geometry/subdivision_geometry_device.cpp deleted file mode 100644 index 1d881ecaac8b..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/subdivision_geometry/subdivision_geometry_device.cpp +++ /dev/null @@ -1,363 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial_device.h" - -/* configuration */ -#define MIN_EDGE_LEVEL 2.0f -#define MAX_EDGE_LEVEL 64.0f -#define LEVEL_FACTOR 64.0f - -#if defined(__XEON_PHI__) -#define EDGE_LEVEL 64.0f -#else -#define EDGE_LEVEL 256.0f -#endif - - -/* scene data */ -RTCDevice g_device = nullptr; -RTCScene g_scene = nullptr; - -/* render function to use */ -renderPixelFunc renderPixel; - -/* previous camera position */ -Vec3fa old_p; - -/* error reporting function */ -void error_handler(const RTCError code, const char* str) -{ - printf("Embree: "); - switch (code) { - case RTC_UNKNOWN_ERROR : printf("RTC_UNKNOWN_ERROR"); break; - case RTC_INVALID_ARGUMENT : printf("RTC_INVALID_ARGUMENT"); break; - case RTC_INVALID_OPERATION: printf("RTC_INVALID_OPERATION"); break; - case RTC_OUT_OF_MEMORY : printf("RTC_OUT_OF_MEMORY"); break; - case RTC_UNSUPPORTED_CPU : printf("RTC_UNSUPPORTED_CPU"); break; - case RTC_CANCELLED : printf("RTC_CANCELLED"); break; - default : printf("invalid error code"); break; - } - if (str) { - printf(" ("); - while (*str) putchar(*str++); - printf(")\n"); - } - exit(1); -} - -__aligned(16) float cube_vertices[8][4] = -{ - { -1.0f, -1.0f, -1.0f, 0.0f }, - { 1.0f, -1.0f, -1.0f, 0.0f }, - { 1.0f, -1.0f, 1.0f, 0.0f }, - { -1.0f, -1.0f, 1.0f, 0.0f }, - { -1.0f, 1.0f, -1.0f, 0.0f }, - { 1.0f, 1.0f, -1.0f, 0.0f }, - { 1.0f, 1.0f, 1.0f, 0.0f }, - { -1.0f, 1.0f, 1.0f, 0.0f } -}; - -__aligned(16) float cube_colors[8][4] = -{ - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 1.0f, 0.0f, 0.0f, 0.0f }, - { 1.0f, 0.0f, 1.0f, 0.0f }, - { 0.0f, 0.0f, 1.0f, 0.0f }, - { 0.0f, 1.0f, 0.0f, 0.0f }, - { 1.0f, 1.0f, 0.0f, 0.0f }, - { 1.0f, 1.0f, 1.0f, 0.0f }, - { 0.0f, 1.0f, 1.0f, 0.0f } -}; - -__aligned(16) float cube_vertex_crease_weights[8] = { - inf, inf,inf, inf, inf, inf, inf, inf -}; - -__aligned(16) unsigned int cube_vertex_crease_indices[8] = { - 0,1,2,3,4,5,6,7 -}; - -__aligned(16) float cube_edge_crease_weights[12] = { - inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf -}; - -__aligned(16) unsigned int cube_edge_crease_indices[24] = -{ - 0,1, 1,2, 2,3, 3,0, - 4,5, 5,6, 6,7, 7,4, - 0,4, 1,5, 2,6, 3,7, -}; - -#if 1 - -#define NUM_INDICES 24 -#define NUM_FACES 6 -#define FACE_SIZE 4 - -unsigned int cube_indices[24] = { - 0, 1, 5, 4, - 1, 2, 6, 5, - 2, 3, 7, 6, - 0, 4, 7, 3, - 4, 5, 6, 7, - 0, 3, 2, 1, -}; - -unsigned int cube_faces[6] = { - 4, 4, 4, 4, 4, 4 -}; - -#else - -#define NUM_INDICES 36 -#define NUM_FACES 12 -#define FACE_SIZE 3 - -unsigned int cube_indices[36] = { - 1, 5, 4, 0, 1, 4, - 2, 6, 5, 1, 2, 5, - 3, 7, 6, 2, 3, 6, - 4, 7, 3, 0, 4, 3, - 5, 6, 7, 4, 5, 7, - 3, 2, 1, 0, 3, 1 -}; - -unsigned int cube_faces[12] = { - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 -}; - -#endif - -/* adds a cube to the scene */ -unsigned int addCube (RTCScene scene_i) -{ - /* create a triangulated cube with 6 quads and 8 vertices */ - //unsigned int geomID = rtcNewTriangleMesh(scene_i, RTC_GEOMETRY_STATIC, NUM_FACES, NUM_INDICES/3); - unsigned int geomID = rtcNewSubdivisionMesh(scene_i, RTC_GEOMETRY_STATIC, NUM_FACES, NUM_INDICES, 8, 0, 0, 0); - //unsigned int geomID = rtcNewSubdivisionMesh(scene_i, RTC_GEOMETRY_STATIC, NUM_FACES, NUM_INDICES, 8, 12, 8, 0); - - rtcSetBuffer(scene_i, geomID, RTC_VERTEX_BUFFER, cube_vertices, 0, sizeof(Vec3fa )); - rtcSetBuffer(scene_i, geomID, RTC_INDEX_BUFFER, cube_indices , 0, sizeof(unsigned int)); - //rtcSetBuffer(scene_i, geomID, RTC_INDEX_BUFFER, cube_indices , 0, 3*sizeof(unsigned int)); - rtcSetBuffer(scene_i, geomID, RTC_FACE_BUFFER, cube_faces, 0, sizeof(unsigned int)); - - rtcSetBuffer(scene_i, geomID, RTC_EDGE_CREASE_INDEX_BUFFER, cube_edge_crease_indices, 0, 2*sizeof(unsigned int)); - rtcSetBuffer(scene_i, geomID, RTC_EDGE_CREASE_WEIGHT_BUFFER, cube_edge_crease_weights, 0, sizeof(float)); - - rtcSetBuffer(scene_i, geomID, RTC_VERTEX_CREASE_INDEX_BUFFER, cube_vertex_crease_indices,0, sizeof(unsigned int)); - rtcSetBuffer(scene_i, geomID, RTC_VERTEX_CREASE_WEIGHT_BUFFER,cube_vertex_crease_weights,0, sizeof(float)); - - rtcSetBuffer(scene_i, geomID, RTC_USER_VERTEX_BUFFER0, cube_colors, 0, sizeof(Vec3fa)); - - float* level = (float*) rtcMapBuffer(scene_i, geomID, RTC_LEVEL_BUFFER); - for (size_t i=0; i 0) { - Vec3fa dPdu,dPdv; - int geomID = ray.geomID; { - rtcInterpolate(g_scene,geomID,ray.primID,ray.u,ray.v,RTC_VERTEX_BUFFER,nullptr,&dPdu.x,&dPdv.x,3); - } - Ng = cross(dPdv,dPdu); - } - - color = color + diffuse*0.5f; // FIXME: += - Vec3fa lightDir = normalize(Vec3fa(-1,-1,-1)); - - /* initialize shadow ray */ - RTCRay shadow; - shadow.org = ray.org + ray.tfar*ray.dir; - shadow.dir = neg(lightDir); - shadow.tnear = 0.001f; - shadow.tfar = inf; - shadow.geomID = RTC_INVALID_GEOMETRY_ID; - shadow.primID = RTC_INVALID_GEOMETRY_ID; - shadow.mask = -1; - shadow.time = 0; - - /* trace shadow ray */ - rtcOccluded(g_scene,shadow); - - /* add light contribution */ - if (shadow.geomID == RTC_INVALID_GEOMETRY_ID) - color = color + diffuse*clamp(-dot(lightDir,normalize(Ng)),0.0f,1.0f); // FIXME: += - } - return color; -} - -/* task that renders a single screen tile */ -void renderTile(int taskIndex, int* pixels, - const int width, - const int height, - const float time, - const Vec3fa& vx, - const Vec3fa& vy, - const Vec3fa& vz, - const Vec3fa& p, - const int numTilesX, - const int numTilesY) -{ - const int tileY = taskIndex / numTilesX; - const int tileX = taskIndex - tileY * numTilesX; - const int x0 = tileX * TILE_SIZE_X; - const int x1 = min(x0+TILE_SIZE_X,width); - const int y0 = tileY * TILE_SIZE_Y; - const int y1 = min(y0+TILE_SIZE_Y,height); - - for (int y = y0; y cin, const FileName& path) - { - while (true) - { - std::string tag = cin->getString(); - if (tag == "") return; - - /* parse command line parameters from a file */ - if (tag == "-c") { - FileName file = path + cin->getFileName(); - parseCommandLine(new ParseStream(new LineCommentFilter(file, "#")), file.path()); - } - - /* parse camera parameters */ - else if (tag == "-vp") g_camera.from = cin->getVec3fa(); - else if (tag == "-vi") g_camera.to = cin->getVec3fa(); - else if (tag == "-vd") g_camera.to = g_camera.from + cin->getVec3fa(); - else if (tag == "-vu") g_camera.up = cin->getVec3fa(); - else if (tag == "-fov") g_camera.fov = cin->getFloat(); - - /* frame buffer size */ - else if (tag == "-size") { - g_width = cin->getInt(); - g_height = cin->getInt(); - } - - /* full screen mode */ - else if (tag == "-fullscreen") - g_fullscreen = true; - - /* output filename */ - else if (tag == "-o") - outFilename = cin->getFileName(); - - /* rtcore configuration */ - else if (tag == "-rtcore") - g_rtcore = cin->getString(); - - /* number of threads to use */ - else if (tag == "-threads") - g_numThreads = cin->getInt(); - - /* skip unknown command line parameter */ - else { - std::cerr << "unknown command line parameter: " << tag << " "; - while (cin->peek() != "" && cin->peek()[0] != '-') std::cerr << cin->getString() << " "; - std::cerr << std::endl; - } - } - } - - void renderToFile(const FileName& fileName) - { - resize(g_width,g_height); - AffineSpace3fa pixel2world = g_camera.pixel2world(g_width,g_height); - - render(0.0f, - pixel2world.l.vx, - pixel2world.l.vy, - pixel2world.l.vz, - pixel2world.p); - - void* ptr = map(); - Ref image = new Image4uc(g_width, g_height, (Col4uc*)ptr); - storeImage(image, fileName); - unmap(); - } - - /* main function in embree namespace */ - int main(int argc, char** argv) - { - /* for best performance set FTZ and DAZ flags in MXCSR control and status register */ - _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); - _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); - - /* set default camera */ - g_camera.from = Vec3fa(1.5f,1.5f,-1.5f); - g_camera.to = Vec3fa(0.0f,0.0f,0.0f); - - /* create stream for parsing */ - Ref stream = new ParseStream(new CommandLineStream(argc, argv)); - - /* parse command line */ - parseCommandLine(stream, FileName()); - if (g_numThreads) - g_rtcore += ",threads=" + std::to_string((long long)g_numThreads); - - /* initialize ray tracing core */ - init(g_rtcore.c_str()); - - /* render to disk */ - if (outFilename.str() != "") { - renderToFile(outFilename); - return 0; - } - - /* initialize GLUT */ - initWindowState(argc,argv,tutorialName, g_width, g_height, g_fullscreen); - - /* enter the GLUT run loop */ - enterWindowRunLoop(); - - return 0; - } -} - -int main(int argc, char** argv) -{ - try { - return embree::main(argc, argv); - } - catch (const std::exception& e) { - std::cout << "Error: " << e.what() << std::endl; - return 1; - } - catch (...) { - std::cout << "Error: unknown exception caught." << std::endl; - return 1; - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/triangle_geometry/triangle_geometry_device.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/triangle_geometry/triangle_geometry_device.cpp deleted file mode 100644 index 0b3aa530f65d..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/triangle_geometry/triangle_geometry_device.cpp +++ /dev/null @@ -1,256 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial_device.h" - -/* scene data */ -RTCDevice g_device = nullptr; -RTCScene g_scene = nullptr; -Vec3fa* face_colors = nullptr; -Vec3fa* vertex_colors = nullptr; - -/* render function to use */ -renderPixelFunc renderPixel; - -/* error reporting function */ -void error_handler(const RTCError code, const char* str) -{ - printf("Embree: "); - switch (code) { - case RTC_UNKNOWN_ERROR : printf("RTC_UNKNOWN_ERROR"); break; - case RTC_INVALID_ARGUMENT : printf("RTC_INVALID_ARGUMENT"); break; - case RTC_INVALID_OPERATION: printf("RTC_INVALID_OPERATION"); break; - case RTC_OUT_OF_MEMORY : printf("RTC_OUT_OF_MEMORY"); break; - case RTC_UNSUPPORTED_CPU : printf("RTC_UNSUPPORTED_CPU"); break; - case RTC_CANCELLED : printf("RTC_CANCELLED"); break; - default : printf("invalid error code"); break; - } - if (str) { - printf(" ("); - while (*str) putchar(*str++); - printf(")\n"); - } - exit(1); -} - -/* adds a cube to the scene */ -unsigned int addCube (RTCScene scene_i) -{ - /* create a triangulated cube with 12 triangles and 8 vertices */ - unsigned int mesh = rtcNewTriangleMesh (scene_i, RTC_GEOMETRY_STATIC, 12, 8); - - /* create face and vertex color arrays */ - face_colors = (Vec3fa*) alignedMalloc(12*sizeof(Vec3fa)); - vertex_colors = (Vec3fa*) alignedMalloc(8*sizeof(Vec3fa)); - - /* set vertices and vertex colors */ - Vertex* vertices = (Vertex*) rtcMapBuffer(scene_i,mesh,RTC_VERTEX_BUFFER); - vertex_colors[0] = Vec3fa(0,0,0); vertices[0].x = -1; vertices[0].y = -1; vertices[0].z = -1; - vertex_colors[1] = Vec3fa(0,0,1); vertices[1].x = -1; vertices[1].y = -1; vertices[1].z = +1; - vertex_colors[2] = Vec3fa(0,1,0); vertices[2].x = -1; vertices[2].y = +1; vertices[2].z = -1; - vertex_colors[3] = Vec3fa(0,1,1); vertices[3].x = -1; vertices[3].y = +1; vertices[3].z = +1; - vertex_colors[4] = Vec3fa(1,0,0); vertices[4].x = +1; vertices[4].y = -1; vertices[4].z = -1; - vertex_colors[5] = Vec3fa(1,0,1); vertices[5].x = +1; vertices[5].y = -1; vertices[5].z = +1; - vertex_colors[6] = Vec3fa(1,1,0); vertices[6].x = +1; vertices[6].y = +1; vertices[6].z = -1; - vertex_colors[7] = Vec3fa(1,1,1); vertices[7].x = +1; vertices[7].y = +1; vertices[7].z = +1; - rtcUnmapBuffer(scene_i,mesh,RTC_VERTEX_BUFFER); - - /* set triangles and face colors */ - int tri = 0; - Triangle* triangles = (Triangle*) rtcMapBuffer(scene_i,mesh,RTC_INDEX_BUFFER); - - // left side - face_colors[tri] = Vec3fa(1,0,0); triangles[tri].v0 = 0; triangles[tri].v1 = 2; triangles[tri].v2 = 1; tri++; - face_colors[tri] = Vec3fa(1,0,0); triangles[tri].v0 = 1; triangles[tri].v1 = 2; triangles[tri].v2 = 3; tri++; - - // right side - face_colors[tri] = Vec3fa(0,1,0); triangles[tri].v0 = 4; triangles[tri].v1 = 5; triangles[tri].v2 = 6; tri++; - face_colors[tri] = Vec3fa(0,1,0); triangles[tri].v0 = 5; triangles[tri].v1 = 7; triangles[tri].v2 = 6; tri++; - - // bottom side - face_colors[tri] = Vec3fa(0.5f); triangles[tri].v0 = 0; triangles[tri].v1 = 1; triangles[tri].v2 = 4; tri++; - face_colors[tri] = Vec3fa(0.5f); triangles[tri].v0 = 1; triangles[tri].v1 = 5; triangles[tri].v2 = 4; tri++; - - // top side - face_colors[tri] = Vec3fa(1.0f); triangles[tri].v0 = 2; triangles[tri].v1 = 6; triangles[tri].v2 = 3; tri++; - face_colors[tri] = Vec3fa(1.0f); triangles[tri].v0 = 3; triangles[tri].v1 = 6; triangles[tri].v2 = 7; tri++; - - // front side - face_colors[tri] = Vec3fa(0,0,1); triangles[tri].v0 = 0; triangles[tri].v1 = 4; triangles[tri].v2 = 2; tri++; - face_colors[tri] = Vec3fa(0,0,1); triangles[tri].v0 = 2; triangles[tri].v1 = 4; triangles[tri].v2 = 6; tri++; - - // back side - face_colors[tri] = Vec3fa(1,1,0); triangles[tri].v0 = 1; triangles[tri].v1 = 3; triangles[tri].v2 = 5; tri++; - face_colors[tri] = Vec3fa(1,1,0); triangles[tri].v0 = 3; triangles[tri].v1 = 7; triangles[tri].v2 = 5; tri++; - - rtcUnmapBuffer(scene_i,mesh,RTC_INDEX_BUFFER); - - rtcSetBuffer(scene_i,mesh,RTC_USER_VERTEX_BUFFER0,vertex_colors,0,sizeof(Vec3fa)); - - return mesh; -} - -/* adds a ground plane to the scene */ -unsigned int addGroundPlane (RTCScene scene_i) -{ - /* create a triangulated plane with 2 triangles and 4 vertices */ - unsigned int mesh = rtcNewTriangleMesh (scene_i, RTC_GEOMETRY_STATIC, 2, 4); - - /* set vertices */ - Vertex* vertices = (Vertex*) rtcMapBuffer(scene_i,mesh,RTC_VERTEX_BUFFER); - vertices[0].x = -10; vertices[0].y = -2; vertices[0].z = -10; - vertices[1].x = -10; vertices[1].y = -2; vertices[1].z = +10; - vertices[2].x = +10; vertices[2].y = -2; vertices[2].z = -10; - vertices[3].x = +10; vertices[3].y = -2; vertices[3].z = +10; - rtcUnmapBuffer(scene_i,mesh,RTC_VERTEX_BUFFER); - - /* set triangles */ - Triangle* triangles = (Triangle*) rtcMapBuffer(scene_i,mesh,RTC_INDEX_BUFFER); - triangles[0].v0 = 0; triangles[0].v1 = 2; triangles[0].v2 = 1; - triangles[1].v0 = 1; triangles[1].v1 = 2; triangles[1].v2 = 3; - rtcUnmapBuffer(scene_i,mesh,RTC_INDEX_BUFFER); - - return mesh; -} - -/* called by the C++ code for initialization */ -extern "C" void device_init (char* cfg) -{ - /* create new Embree device */ - g_device = rtcNewDevice(cfg); - - /* set error handler */ - rtcDeviceSetErrorFunction(g_device,error_handler); - - /* create scene */ - g_scene = rtcDeviceNewScene(g_device, RTC_SCENE_STATIC,RTC_INTERSECT1); - - /* add cube */ - addCube(g_scene); - - /* add ground plane */ - addGroundPlane(g_scene); - - /* commit changes to scene */ - rtcCommit (g_scene); - - /* set start render mode */ - renderPixel = renderPixelStandard; - key_pressed_handler = device_key_pressed_default; -} - -/* task that renders a single screen tile */ -Vec3fa renderPixelStandard(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p) -{ - /* initialize ray */ - RTCRay ray; - ray.org = p; - ray.dir = normalize(x*vx + y*vy + vz); - ray.tnear = 0.0f; - ray.tfar = inf; - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.primID = RTC_INVALID_GEOMETRY_ID; - ray.mask = -1; - ray.time = 0; - - /* intersect ray with scene */ - rtcIntersect(g_scene,ray); - - /* shade pixels */ - Vec3fa color = Vec3fa(0.0f); - if (ray.geomID != RTC_INVALID_GEOMETRY_ID) - { - Vec3fa diffuse = face_colors[ray.primID]; - color = color + diffuse*0.5f; // FIXME: += - Vec3fa lightDir = normalize(Vec3fa(-1,-1,-1)); - - /* initialize shadow ray */ - RTCRay shadow; - shadow.org = ray.org + ray.tfar*ray.dir; - shadow.dir = neg(lightDir); - shadow.tnear = 0.001f; - shadow.tfar = inf; - shadow.geomID = 1; - shadow.primID = 0; - shadow.mask = -1; - shadow.time = 0; - - /* trace shadow ray */ - rtcOccluded(g_scene,shadow); - - /* add light contribution */ - if (shadow.geomID) - color = color + diffuse*clamp(-dot(lightDir,normalize(ray.Ng)),0.0f,1.0f); // FIXME: += - } - return color; -} - -/* task that renders a single screen tile */ -void renderTile(int taskIndex, int* pixels, - const int width, - const int height, - const float time, - const Vec3fa& vx, - const Vec3fa& vy, - const Vec3fa& vz, - const Vec3fa& p, - const int numTilesX, - const int numTilesY) -{ - const int tileY = taskIndex / numTilesX; - const int tileX = taskIndex - tileY * numTilesX; - const int x0 = tileX * TILE_SIZE_X; - const int x1 = min(x0+TILE_SIZE_X,width); - const int y0 = tileY * TILE_SIZE_Y; - const int y1 = min(y0+TILE_SIZE_Y,height); - - for (int y = y0; y cin, const FileName& path) - { - while (true) - { - std::string tag = cin->getString(); - if (tag == "") return; - - /* parse command line parameters from a file */ - if (tag == "-c") { - FileName file = path + cin->getFileName(); - parseCommandLine(new ParseStream(new LineCommentFilter(file, "#")), file.path()); - } - - /* parse camera parameters */ - else if (tag == "-vp") g_camera.from = cin->getVec3fa(); - else if (tag == "-vi") g_camera.to = cin->getVec3fa(); - else if (tag == "-vd") g_camera.to = g_camera.from + cin->getVec3fa(); - else if (tag == "-vu") g_camera.up = cin->getVec3fa(); - else if (tag == "-fov") g_camera.fov = cin->getFloat(); - - /* frame buffer size */ - else if (tag == "-size") { - g_width = cin->getInt(); - g_height = cin->getInt(); - } - - /* full screen mode */ - else if (tag == "-fullscreen") - g_fullscreen = true; - - /* output filename */ - else if (tag == "-o") - outFilename = cin->getFileName(); - - /* rtcore configuration */ - else if (tag == "-rtcore") - g_rtcore = cin->getString(); - - /* number of threads to use */ - else if (tag == "-threads") - g_numThreads = cin->getInt(); - - /* skip unknown command line parameter */ - else { - std::cerr << "unknown command line parameter: " << tag << " "; - while (cin->peek() != "" && cin->peek()[0] != '-') std::cerr << cin->getString() << " "; - std::cerr << std::endl; - } - } - } - - void renderToFile(const FileName& fileName) - { - resize(g_width,g_height); - AffineSpace3fa pixel2world = g_camera.pixel2world(g_width,g_height); - - render(0.0f, - pixel2world.l.vx, - pixel2world.l.vy, - pixel2world.l.vz, - pixel2world.p); - - void* ptr = map(); - Ref image = new Image4uc(g_width, g_height, (Col4uc*)ptr); - storeImage(image, fileName); - unmap(); - cleanup(); - } - - /* main function in embree namespace */ - int main(int argc, char** argv) - { - /* for best performance set FTZ and DAZ flags in MXCSR control and status register */ - _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); - _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); - - /* set default camera */ - g_camera.from = Vec3fa(2.5f,2.5f,2.5f); - g_camera.to = Vec3fa(0.0f,0.0f,0.0f); - - /* create stream for parsing */ - Ref stream = new ParseStream(new CommandLineStream(argc, argv)); - - /* parse command line */ - parseCommandLine(stream, FileName()); - if (g_numThreads) - g_rtcore += ",threads=" + std::to_string((long long)g_numThreads); - - /* initialize ray tracing core */ - init(g_rtcore.c_str()); - - /* render to disk */ - if (outFilename.str() != "") { - renderToFile(outFilename); - return 0; - } - - /* initialize GLUT */ - initWindowState(argc,argv,tutorialName, g_width, g_height, g_fullscreen); - - /* enter the GLUT run loop */ - enterWindowRunLoop(); - - return 0; - } -} - -int main(int argc, char** argv) -{ - try { - return embree::main(argc, argv); - } - catch (const std::exception& e) { - std::cout << "Error: " << e.what() << std::endl; - return 1; - } - catch (...) { - std::cout << "Error: unknown exception caught." << std::endl; - return 1; - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/user_geometry/user_geometry_device.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/user_geometry/user_geometry_device.cpp deleted file mode 100644 index b9363d9d6505..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/user_geometry/user_geometry_device.cpp +++ /dev/null @@ -1,524 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial_device.h" - -const int numPhi = 5; -const int numTheta = 2*numPhi; - -/* render function to use */ -renderPixelFunc renderPixel; - -/* error reporting function */ -void error_handler(const RTCError code, const char* str) -{ - printf("Embree: "); - switch (code) { - case RTC_UNKNOWN_ERROR : printf("RTC_UNKNOWN_ERROR"); break; - case RTC_INVALID_ARGUMENT : printf("RTC_INVALID_ARGUMENT"); break; - case RTC_INVALID_OPERATION: printf("RTC_INVALID_OPERATION"); break; - case RTC_OUT_OF_MEMORY : printf("RTC_OUT_OF_MEMORY"); break; - case RTC_UNSUPPORTED_CPU : printf("RTC_UNSUPPORTED_CPU"); break; - case RTC_CANCELLED : printf("RTC_CANCELLED"); break; - default : printf("invalid error code"); break; - } - if (str) { - printf(" ("); - while (*str) putchar(*str++); - printf(")\n"); - } - exit(1); -} - -// ======================================================================== // -// User defined instancing // -// ======================================================================== // - -struct Instance -{ - ALIGNED_STRUCT - unsigned int geometry; - RTCScene object; - int userID; - AffineSpace3fa local2world; - AffineSpace3fa world2local; - Vec3fa lower; - Vec3fa upper; -}; - -void instanceBoundsFunc(const Instance* instance, size_t item, RTCBounds* bounds_o) -{ - Vec3fa l = instance->lower; - Vec3fa u = instance->upper; - Vec3fa p000 = xfmPoint(instance->local2world,Vec3fa(l.x,l.y,l.z)); - Vec3fa p001 = xfmPoint(instance->local2world,Vec3fa(l.x,l.y,u.z)); - Vec3fa p010 = xfmPoint(instance->local2world,Vec3fa(l.x,u.y,l.z)); - Vec3fa p011 = xfmPoint(instance->local2world,Vec3fa(l.x,u.y,u.z)); - Vec3fa p100 = xfmPoint(instance->local2world,Vec3fa(u.x,l.y,l.z)); - Vec3fa p101 = xfmPoint(instance->local2world,Vec3fa(u.x,l.y,u.z)); - Vec3fa p110 = xfmPoint(instance->local2world,Vec3fa(u.x,u.y,l.z)); - Vec3fa p111 = xfmPoint(instance->local2world,Vec3fa(u.x,u.y,u.z)); - Vec3fa lower = min(min(min(p000,p001),min(p010,p011)),min(min(p100,p101),min(p110,p111))); - Vec3fa upper = max(max(max(p000,p001),max(p010,p011)),max(max(p100,p101),max(p110,p111))); - bounds_o->lower_x = lower.x; - bounds_o->lower_y = lower.y; - bounds_o->lower_z = lower.z; - bounds_o->upper_x = upper.x; - bounds_o->upper_y = upper.y; - bounds_o->upper_z = upper.z; -} - -void instanceIntersectFunc(const Instance* instance, RTCRay& ray, size_t item) -{ - const Vec3fa ray_org = ray.org; - const Vec3fa ray_dir = ray.dir; - const int geomID = ray.geomID; - ray.org = xfmPoint (instance->world2local,ray_org); - ray.dir = xfmVector(instance->world2local,ray_dir); - ray.geomID = RTC_INVALID_GEOMETRY_ID; - rtcIntersect(instance->object,ray); - ray.org = ray_org; - ray.dir = ray_dir; - if (ray.geomID == RTC_INVALID_GEOMETRY_ID) ray.geomID = geomID; - else ray.instID = instance->userID; -} - -void instanceOccludedFunc(const Instance* instance, RTCRay& ray, size_t item) -{ - const Vec3fa ray_org = ray.org; - const Vec3fa ray_dir = ray.dir; - ray.org = xfmPoint (instance->world2local,ray_org); - ray.dir = xfmVector(instance->world2local,ray_dir); - rtcOccluded(instance->object,ray); - ray.org = ray_org; - ray.dir = ray_dir; -} - -Instance* createInstance (RTCScene scene, RTCScene object, int userID, const Vec3fa& lower, const Vec3fa& upper) -{ - Instance* instance = new Instance; - instance->object = object; - instance->userID = userID; - instance->lower = lower; - instance->upper = upper; - instance->local2world.l.vx = Vec3fa(1,0,0); - instance->local2world.l.vy = Vec3fa(0,1,0); - instance->local2world.l.vz = Vec3fa(0,0,1); - instance->local2world.p = Vec3fa(0,0,0); - instance->geometry = rtcNewUserGeometry(scene,1); - rtcSetUserData(scene,instance->geometry,instance); - rtcSetBoundsFunction(scene,instance->geometry,(RTCBoundsFunc)&instanceBoundsFunc); - rtcSetIntersectFunction(scene,instance->geometry,(RTCIntersectFunc)&instanceIntersectFunc); - rtcSetOccludedFunction (scene,instance->geometry,(RTCOccludedFunc )&instanceOccludedFunc); - return instance; -} - -void updateInstance (RTCScene scene, Instance* instance) -{ - unsigned int geometry = instance->geometry; - instance->world2local = rcp(instance->local2world); - rtcUpdate(scene,instance->geometry); -} - -// ======================================================================== // -// User defined sphere geometry // -// ======================================================================== // - -struct Sphere -{ - ALIGNED_STRUCT - Vec3fa p; //!< position of the sphere - float r; //!< radius of the sphere - unsigned int geomID; -}; - -void sphereBoundsFunc(const Sphere* spheres, size_t item, RTCBounds* bounds_o) -{ - const Sphere& sphere = spheres[item]; - bounds_o->lower_x = sphere.p.x-sphere.r; - bounds_o->lower_y = sphere.p.y-sphere.r; - bounds_o->lower_z = sphere.p.z-sphere.r; - bounds_o->upper_x = sphere.p.x+sphere.r; - bounds_o->upper_y = sphere.p.y+sphere.r; - bounds_o->upper_z = sphere.p.z+sphere.r; -} - -void sphereIntersectFunc(const Sphere* spheres, RTCRay& ray, size_t item) -{ - const Sphere& sphere = spheres[item]; - const Vec3fa v = ray.org-sphere.p; - const float A = dot(ray.dir,ray.dir); - const float B = 2.0f*dot(v,ray.dir); - const float C = dot(v,v) - sqr(sphere.r); - const float D = B*B - 4.0f*A*C; - if (D < 0.0f) return; - const float Q = sqrt(D); - const float rcpA = rcp(A); - const float t0 = 0.5f*rcpA*(-B-Q); - const float t1 = 0.5f*rcpA*(-B+Q); - if ((ray.tnear < t0) & (t0 < ray.tfar)) { - ray.u = 0.0f; - ray.v = 0.0f; - ray.tfar = t0; - ray.geomID = sphere.geomID; - ray.primID = item; - ray.Ng = ray.org+t0*ray.dir-sphere.p; - } - if ((ray.tnear < t1) & (t1 < ray.tfar)) { - ray.u = 0.0f; - ray.v = 0.0f; - ray.tfar = t1; - ray.geomID = sphere.geomID; - ray.primID = item; - ray.Ng = ray.org+t1*ray.dir-sphere.p; - } -} - -void sphereOccludedFunc(const Sphere* spheres, RTCRay& ray, size_t item) -{ - const Sphere& sphere = spheres[item]; - const Vec3fa v = ray.org-sphere.p; - const float A = dot(ray.dir,ray.dir); - const float B = 2.0f*dot(v,ray.dir); - const float C = dot(v,v) - sqr(sphere.r); - const float D = B*B - 4.0f*A*C; - if (D < 0.0f) return; - const float Q = sqrt(D); - const float rcpA = rcp(A); - const float t0 = 0.5f*rcpA*(-B-Q); - const float t1 = 0.5f*rcpA*(-B+Q); - if ((ray.tnear < t0) & (t0 < ray.tfar)) { - ray.geomID = 0; - } - if ((ray.tnear < t1) & (t1 < ray.tfar)) { - ray.geomID = 0; - } -} - -Sphere* createAnalyticalSphere (RTCScene scene, const Vec3fa& p, float r) -{ - unsigned int geomID = rtcNewUserGeometry(scene,1); - Sphere* sphere = new Sphere; - sphere->p = p; - sphere->r = r; - sphere->geomID = geomID; - rtcSetUserData(scene,geomID,sphere); - rtcSetBoundsFunction(scene,geomID,(RTCBoundsFunc)&sphereBoundsFunc); - rtcSetIntersectFunction(scene,geomID,(RTCIntersectFunc)&sphereIntersectFunc); - rtcSetOccludedFunction (scene,geomID,(RTCOccludedFunc )&sphereOccludedFunc); - return sphere; -} - -Sphere* createAnalyticalSpheres (RTCScene scene, size_t N) -{ - unsigned int geomID = rtcNewUserGeometry(scene,N); - Sphere* spheres = new Sphere[N]; - for (int i=0; i 1) { - triangles[tri].v0 = p10; - triangles[tri].v1 = p00; - triangles[tri].v2 = p01; - tri++; - } - - if (phi < numPhi) { - triangles[tri].v0 = p11; - triangles[tri].v1 = p10; - triangles[tri].v2 = p01; - tri++; - } - } - } - rtcUnmapBuffer(scene,mesh,RTC_VERTEX_BUFFER); - rtcUnmapBuffer(scene,mesh,RTC_INDEX_BUFFER); - return mesh; -} - -/* creates a ground plane */ -unsigned int createGroundPlane (RTCScene scene) -{ - /* create a triangulated plane with 2 triangles and 4 vertices */ - unsigned int mesh = rtcNewTriangleMesh (scene, RTC_GEOMETRY_STATIC, 2, 4); - - /* set vertices */ - Vertex* vertices = (Vertex*) rtcMapBuffer(scene,mesh,RTC_VERTEX_BUFFER); - vertices[0].x = -10; vertices[0].y = -2; vertices[0].z = -10; - vertices[1].x = -10; vertices[1].y = -2; vertices[1].z = +10; - vertices[2].x = +10; vertices[2].y = -2; vertices[2].z = -10; - vertices[3].x = +10; vertices[3].y = -2; vertices[3].z = +10; - rtcUnmapBuffer(scene,mesh,RTC_VERTEX_BUFFER); - - /* set triangles */ - Triangle* triangles = (Triangle*) rtcMapBuffer(scene,mesh,RTC_INDEX_BUFFER); - triangles[0].v0 = 0; triangles[0].v1 = 2; triangles[0].v2 = 1; - triangles[1].v0 = 1; triangles[1].v1 = 2; triangles[1].v2 = 3; - rtcUnmapBuffer(scene,mesh,RTC_INDEX_BUFFER); - - return mesh; -} - -/* scene data */ -RTCDevice g_device = nullptr; -RTCScene g_scene = nullptr; -RTCScene g_scene0 = nullptr; -RTCScene g_scene1 = nullptr; -RTCScene g_scene2 = nullptr; - -Instance* g_instance0 = nullptr; -Instance* g_instance1 = nullptr; -Instance* g_instance2 = nullptr; -Instance* g_instance3 = nullptr; - -Vec3fa colors[5][4]; - -/* called by the C++ code for initialization */ -extern "C" void device_init (char* cfg) -{ - /* create new Embree device */ - g_device = rtcNewDevice(cfg); - - /* set error handler */ - rtcDeviceSetErrorFunction(g_device,error_handler); - - /* create scene */ - g_scene = rtcDeviceNewScene(g_device, RTC_SCENE_DYNAMIC,RTC_INTERSECT1); - - /* create scene with 4 analytical spheres */ - g_scene0 = rtcDeviceNewScene(g_device, RTC_SCENE_STATIC,RTC_INTERSECT1); - Sphere* spheres = createAnalyticalSpheres(g_scene0,4); - spheres[0].p = Vec3fa( 0, 0,+1); spheres[0].r = 0.5f; - spheres[1].p = Vec3fa(+1, 0, 0); spheres[1].r = 0.5f; - spheres[2].p = Vec3fa( 0, 0,-1); spheres[2].r = 0.5f; - spheres[3].p = Vec3fa(-1, 0, 0); spheres[3].r = 0.5f; - rtcCommit(g_scene0); - - /* create scene with 4 triangulated spheres */ - g_scene1 = rtcDeviceNewScene(g_device, RTC_SCENE_STATIC,RTC_INTERSECT1); - createTriangulatedSphere(g_scene1,Vec3fa( 0, 0,+1),0.5); - createTriangulatedSphere(g_scene1,Vec3fa(+1, 0, 0),0.5); - createTriangulatedSphere(g_scene1,Vec3fa( 0, 0,-1),0.5); - createTriangulatedSphere(g_scene1,Vec3fa(-1, 0, 0),0.5); - rtcCommit(g_scene1); - - /* create scene with 2 triangulated and 2 analytical spheres */ - g_scene2 = rtcDeviceNewScene(g_device, RTC_SCENE_STATIC,RTC_INTERSECT1); - createTriangulatedSphere(g_scene2,Vec3fa( 0, 0,+1),0.5); - createAnalyticalSphere (g_scene2,Vec3fa(+1, 0, 0),0.5); - createTriangulatedSphere(g_scene2,Vec3fa( 0, 0,-1),0.5); - createAnalyticalSphere (g_scene2,Vec3fa(-1, 0, 0),0.5); - rtcCommit(g_scene2); - - /* instantiate geometry */ - createGroundPlane(g_scene); - g_instance0 = createInstance(g_scene,g_scene0,0,Vec3fa(-2,-2,-2),Vec3fa(+2,+2,+2)); - g_instance1 = createInstance(g_scene,g_scene1,1,Vec3fa(-2,-2,-2),Vec3fa(+2,+2,+2)); - g_instance2 = createInstance(g_scene,g_scene2,2,Vec3fa(-2,-2,-2),Vec3fa(+2,+2,+2)); - g_instance3 = createInstance(g_scene,g_scene2,3,Vec3fa(-2,-2,-2),Vec3fa(+2,+2,+2)); - - /* set all colors */ - colors[0][0] = Vec3fa(0.25,0,0); - colors[0][1] = Vec3fa(0.50,0,0); - colors[0][2] = Vec3fa(0.75,0,0); - colors[0][3] = Vec3fa(1.00,0,0); - - colors[1][0] = Vec3fa(0,0.25,0); - colors[1][1] = Vec3fa(0,0.50,0); - colors[1][2] = Vec3fa(0,0.75,0); - colors[1][3] = Vec3fa(0,1.00,0); - - colors[2][0] = Vec3fa(0,0,0.25); - colors[2][1] = Vec3fa(0,0,0.50); - colors[2][2] = Vec3fa(0,0,0.75); - colors[2][3] = Vec3fa(0,0,1.00); - - colors[3][0] = Vec3fa(0.25,0.25,0); - colors[3][1] = Vec3fa(0.50,0.50,0); - colors[3][2] = Vec3fa(0.75,0.75,0); - colors[3][3] = Vec3fa(1.00,1.00,0); - - colors[4][0] = Vec3fa(1.0,1.0,1.0); - colors[4][1] = Vec3fa(1.0,1.0,1.0); - colors[4][2] = Vec3fa(1.0,1.0,1.0); - colors[4][3] = Vec3fa(1.0,1.0,1.0); - - /* set start render mode */ - renderPixel = renderPixelStandard; - key_pressed_handler = device_key_pressed_default; -} - -/* task that renders a single screen tile */ -Vec3fa renderPixelStandard(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p) -{ - /* initialize ray */ - RTCRay ray; - ray.org = p; - ray.dir = normalize(x*vx + y*vy + vz); - ray.tnear = 0.0f; - ray.tfar = inf; - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.primID = RTC_INVALID_GEOMETRY_ID; - ray.instID = 4; // set default instance ID - ray.mask = -1; - ray.time = 0; - - /* intersect ray with scene */ - rtcIntersect(g_scene,ray); - - /* shade pixels */ - Vec3fa color = Vec3fa(0.0f); - if (ray.geomID != RTC_INVALID_GEOMETRY_ID) - { - Vec3fa diffuse = Vec3fa(0.0f); - if (ray.instID == 0) diffuse = colors[ray.instID][ray.primID]; - else diffuse = colors[ray.instID][ray.geomID]; - color = color + diffuse*0.5; // FIXME: += - Vec3fa lightDir = normalize(Vec3fa(-1,-1,-1)); - - /* initialize shadow ray */ - RTCRay shadow; - shadow.org = ray.org + ray.tfar*ray.dir; - shadow.dir = neg(lightDir); - shadow.tnear = 0.001f; - shadow.tfar = inf; - shadow.geomID = 1; - shadow.primID = 0; - shadow.mask = -1; - shadow.time = 0; - - /* trace shadow ray */ - rtcOccluded(g_scene,shadow); - - /* add light contribution */ - if (shadow.geomID) - color = color + diffuse*clamp(-dot(lightDir,normalize(ray.Ng)),0.0f,1.0f); // FIXME: += - } - return color; -} - -/* task that renders a single screen tile */ -void renderTile(int taskIndex, int* pixels, - const int width, - const int height, - const float time, - const Vec3fa& vx, - const Vec3fa& vy, - const Vec3fa& vz, - const Vec3fa& p, - const int numTilesX, - const int numTilesY) -{ - const int tileY = taskIndex / numTilesX; - const int tileX = taskIndex - tileY * numTilesX; - const int x0 = tileX * TILE_SIZE_X; - const int x1 = min(x0+TILE_SIZE_X,width); - const int y0 = tileY * TILE_SIZE_Y; - const int y1 = min(y0+TILE_SIZE_Y,height); - - for (int y = y0; ylocal2world.p = 2.0f*Vec3fa(+cos(t),0.0f,+sin(t)); - g_instance1->local2world.p = 2.0f*Vec3fa(-cos(t),0.0f,-sin(t)); - g_instance2->local2world.p = 2.0f*Vec3fa(-sin(t),0.0f,+cos(t)); - g_instance3->local2world.p = 2.0f*Vec3fa(+sin(t),0.0f,-cos(t)); - updateInstance(g_scene,g_instance0); - updateInstance(g_scene,g_instance1); - updateInstance(g_scene,g_instance2); - updateInstance(g_scene,g_instance3); - rtcCommit (g_scene); - - /* render all pixels */ - const int numTilesX = (width +TILE_SIZE_X-1)/TILE_SIZE_X; - const int numTilesY = (height+TILE_SIZE_Y-1)/TILE_SIZE_Y; - launch_renderTile(numTilesX*numTilesY,pixels,width,height,time,vx,vy,vz,p,numTilesX,numTilesY); -} - -/* called by the C++ code for cleanup */ -extern "C" void device_cleanup () -{ - rtcDeleteScene (g_scene); - rtcDeleteScene (g_scene0); - rtcDeleteScene (g_scene1); - rtcDeleteScene (g_scene2); - rtcDeleteDevice(g_device); -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/viewer/CMakeLists.txt b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/viewer/CMakeLists.txt deleted file mode 100644 index 22738a370050..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/viewer/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -## ======================================================================== ## -## Copyright 2009-2015 Intel Corporation ## -## ## -## Licensed under the Apache License, Version 2.0 (the "License"); ## -## you may not use this file except in compliance with the License. ## -## You may obtain a copy of the License at ## -## ## -## http://www.apache.org/licenses/LICENSE-2.0 ## -## ## -## Unless required by applicable law or agreed to in writing, software ## -## distributed under the License is distributed on an "AS IS" BASIS, ## -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## -## See the License for the specific language governing permissions and ## -## limitations under the License. ## -## ======================================================================== ## - -INCLUDE(tutorial) -ADD_TUTORIAL(viewer) diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/viewer/viewer.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/viewer/viewer.cpp deleted file mode 100644 index 8fd775f599da..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/viewer/viewer.cpp +++ /dev/null @@ -1,273 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial.h" -#include "../common/tutorial/obj_loader.h" -#include "../common/tutorial/xml_loader.h" -#include "../common/image/image.h" - -namespace embree -{ - /* name of the tutorial */ - const char* tutorialName = "viewer"; - - /* configuration */ - static std::string g_rtcore = ""; - static size_t g_numThreads = 0; - static std::string g_subdiv_mode = ""; - - /* output settings */ - static size_t g_width = 512; - static size_t g_height = 512; - static bool g_fullscreen = false; - static FileName outFilename = ""; - static int g_skipBenchmarkFrames = 0; - static int g_numBenchmarkFrames = 0; - static bool g_interactive = true; - static bool g_anim_mode = false; - static bool g_loop_mode = false; - static FileName keyframeList = ""; - - /* scene */ - OBJScene g_obj_scene; - static FileName filename = ""; - - static void parseCommandLine(Ref cin, const FileName& path) - { - while (true) - { - std::string tag = cin->getString(); - if (tag == "") return; - - /* parse command line parameters from a file */ - else if (tag == "-c") { - FileName file = path + cin->getFileName(); - parseCommandLine(new ParseStream(new LineCommentFilter(file, "#")), file.path()); - } - - /* load OBJ model*/ - else if (tag == "-i") { - filename = path + cin->getFileName(); - } - - /* parse camera parameters */ - else if (tag == "-vp") g_camera.from = cin->getVec3fa(); - else if (tag == "-vi") g_camera.to = cin->getVec3fa(); - else if (tag == "-vd") g_camera.to = g_camera.from + cin->getVec3fa(); - else if (tag == "-vu") g_camera.up = cin->getVec3fa(); - else if (tag == "-fov") g_camera.fov = cin->getFloat(); - - /* frame buffer size */ - else if (tag == "-size") { - g_width = cin->getInt(); - g_height = cin->getInt(); - } - - /* full screen mode */ - else if (tag == "-fullscreen") - g_fullscreen = true; - - /* output filename */ - else if (tag == "-o") { - outFilename = cin->getFileName(); - g_interactive = false; - } - - else if (tag == "-objlist") { - keyframeList = cin->getFileName(); - } - - /* subdivision mode */ - else if (tag == "-cache") - g_subdiv_mode = ",subdiv_accel=bvh4.subdivpatch1cached"; - - else if (tag == "-pregenerate") - g_subdiv_mode = ",subdiv_accel=bvh4.grid.eager"; - - else if (tag == "-loop") - g_loop_mode = true; - - else if (tag == "-anim") - g_anim_mode = true; - - /* number of frames to render in benchmark mode */ - else if (tag == "-benchmark") { - g_skipBenchmarkFrames = cin->getInt(); - g_numBenchmarkFrames = cin->getInt(); - g_interactive = false; - } - - /* rtcore configuration */ - else if (tag == "-rtcore") - g_rtcore = cin->getString(); - - /* number of threads to use */ - else if (tag == "-threads") - g_numThreads = cin->getInt(); - - /* ambient light source */ - else if (tag == "-ambientlight") - { - const Vec3fa L = cin->getVec3fa(); - g_obj_scene.ambientLights.push_back(AmbientLight(L)); - } - - /* point light source */ - else if (tag == "-pointlight") - { - const Vec3fa P = cin->getVec3fa(); - const Vec3fa I = cin->getVec3fa(); - g_obj_scene.pointLights.push_back(PointLight(P,I)); - } - - /* directional light source */ - else if (tag == "-directionallight" || tag == "-dirlight") - { - const Vec3fa D = cin->getVec3fa(); - const Vec3fa E = cin->getVec3fa(); - g_obj_scene.directionalLights.push_back(DirectionalLight(D,E)); - } - - /* distant light source */ - else if (tag == "-distantlight") - { - const Vec3fa D = cin->getVec3fa(); - const Vec3fa L = cin->getVec3fa(); - const float halfAngle = cin->getFloat(); - g_obj_scene.distantLights.push_back(DistantLight(D,L,halfAngle)); - } - - /* skip unknown command line parameter */ - else { - std::cerr << "unknown command line parameter: " << tag << " "; - while (cin->peek() != "" && cin->peek()[0] != '-') std::cerr << cin->getString() << " "; - std::cerr << std::endl; - } - } - } - - void renderBenchmark(const FileName& fileName) - { - resize(g_width,g_height); - AffineSpace3fa pixel2world = g_camera.pixel2world(g_width,g_height); - - double dt = 0.0f; - size_t numTotalFrames = g_skipBenchmarkFrames + g_numBenchmarkFrames; - for (size_t i=0; i= g_skipBenchmarkFrames) dt += t1-t0; - } - std::cout << "frame [" << g_skipBenchmarkFrames << " - " << numTotalFrames << "] " << std::flush; - std::cout << double(g_numBenchmarkFrames)/dt << "fps " << std::endl; - std::cout << "BENCHMARK_RENDER " << double(g_numBenchmarkFrames)/dt << std::endl; - } - - void renderToFile(const FileName& fileName) - { - resize(g_width,g_height); - AffineSpace3fa pixel2world = g_camera.pixel2world(g_width,g_height); - render(0.0f,pixel2world.l.vx,pixel2world.l.vy,pixel2world.l.vz,pixel2world.p); - void* ptr = map(); - Ref image = new Image4uc(g_width, g_height, (Col4uc*)ptr); - storeImage(image, fileName); - unmap(); - cleanup(); - } - - /* main function in embree namespace */ - int main(int argc, char** argv) - { - /* for best performance set FTZ and DAZ flags in MXCSR control and status register */ - _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); - _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); - - /* create stream for parsing */ - Ref stream = new ParseStream(new CommandLineStream(argc, argv)); - - /* parse command line */ - parseCommandLine(stream, FileName()); - - /* load default scene if none specified */ - if (filename.ext() == "") { - FileName file = FileName::executableFolder() + FileName("models/cornell_box.ecs"); - parseCommandLine(new ParseStream(new LineCommentFilter(file, "#")), file.path()); - } - - /* configure number of threads */ - if (g_numThreads) - g_rtcore += ",threads=" + std::to_string((long long)g_numThreads); - if (g_numBenchmarkFrames) - g_rtcore += ",benchmark=1"; - - g_rtcore += g_subdiv_mode; - - /* load scene */ - if (strlwr(filename.ext()) == std::string("obj")) { - Ref node = loadOBJ(filename,g_subdiv_mode != ""); - g_obj_scene.add(node); - } - else if (strlwr(filename.ext()) == std::string("xml")) { - Ref node = loadXML(filename,one); - g_obj_scene.add(node); - } - else if (filename.ext() != "") - THROW_RUNTIME_ERROR("invalid scene type: "+strlwr(filename.ext())); - - /* initialize ray tracing core */ - init(g_rtcore.c_str()); - - /* send model */ - set_scene(&g_obj_scene); - - /* benchmark mode */ - if (g_numBenchmarkFrames) - renderBenchmark(outFilename); - - /* render to disk */ - if (outFilename.str() != "") - renderToFile(outFilename); - - /* interactive mode */ - if (g_interactive) { - initWindowState(argc,argv,tutorialName, g_width, g_height, g_fullscreen); - enterWindowRunLoop(g_anim_mode); - } - - return 0; - } -} - -int main(int argc, char** argv) -{ - try { - return embree::main(argc, argv); - } - catch (const std::exception& e) { - std::cout << "Error: " << e.what() << std::endl; - return 1; - } - catch (...) { - std::cout << "Error: unknown exception caught." << std::endl; - return 1; - } -} diff --git a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/viewer/viewer_device.cpp b/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/viewer/viewer_device.cpp deleted file mode 100644 index ff76124a4fdf..000000000000 --- a/Engine/Source/ThirdParty/IntelEmbree/Embree270/src/tutorials/viewer/viewer_device.cpp +++ /dev/null @@ -1,418 +0,0 @@ -// ======================================================================== // -// Copyright 2009-2015 Intel Corporation // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // -// See the License for the specific language governing permissions and // -// limitations under the License. // -// ======================================================================== // - -#include "../common/tutorial/tutorial_device.h" -#include "../common/tutorial/scene_device.h" - -extern "C" ISPCScene* g_ispc_scene; -extern "C" bool g_changed; - -/* scene data */ -RTCDevice g_device = nullptr; -RTCScene g_scene = nullptr; -void** geomID_to_mesh = nullptr; -int* geomID_to_type = nullptr; -bool g_subdiv_mode = false; - -#define SPP 1 - -//#define FORCE_FIXED_EDGE_TESSELLATION -#define FIXED_EDGE_TESSELLATION_VALUE 3 - -#define MAX_EDGE_LEVEL 64.0f -#define MIN_EDGE_LEVEL 4.0f -#define LEVEL_FACTOR 64.0f - -inline float updateEdgeLevel( ISPCSubdivMesh* mesh, const Vec3fa& cam_pos, const size_t e0, const size_t e1) -{ - const Vec3fa v0 = mesh->positions[mesh->position_indices[e0]]; - const Vec3fa v1 = mesh->positions[mesh->position_indices[e1]]; - const Vec3fa edge = v1-v0; - const Vec3fa P = 0.5f*(v1+v0); - const Vec3fa dist = cam_pos - P; - return max(min(LEVEL_FACTOR*(0.5f*length(edge)/length(dist)),MAX_EDGE_LEVEL),MIN_EDGE_LEVEL); -} - - -void updateEdgeLevelBuffer( ISPCSubdivMesh* mesh, const Vec3fa& cam_pos, size_t startID, size_t endID ) -{ - for (size_t f=startID; fface_offsets[f]; - int N = mesh->verticesPerFace[f]; - if (N == 4) /* fast path for quads */ - for (size_t i=0; i<4; i++) - mesh->subdivlevel[e+i] = updateEdgeLevel(mesh,cam_pos,e+(i+0),e+(i+1)%4); - else if (N == 3) /* fast path for triangles */ - for (size_t i=0; i<3; i++) - mesh->subdivlevel[e+i] = updateEdgeLevel(mesh,cam_pos,e+(i+0),e+(i+1)%3); - else /* fast path for general polygons */ - for (size_t i=0; isubdivlevel[e+i] = updateEdgeLevel(mesh,cam_pos,e+(i+0),e+(i+1)%N); - } -} - -#if defined(ISPC) -task void updateSubMeshEdgeLevelBufferTask( ISPCSubdivMesh* mesh, const Vec3fa& cam_pos ) -{ - const size_t size = mesh->numFaces; - const size_t startID = ((taskIndex+0)*size)/taskCount; - const size_t endID = ((taskIndex+1)*size)/taskCount; - updateEdgeLevelBuffer(mesh,cam_pos,startID,endID); -} -task void updateMeshEdgeLevelBufferTask( ISPCScene* scene_in, const Vec3fa& cam_pos ) -{ - ISPCSubdivMesh* mesh = g_ispc_scene->subdiv[taskIndex]; - unsigned int geomID = mesh->geomID; - if (mesh->numFaces < 10000) { - updateEdgeLevelBuffer(mesh,cam_pos,0,mesh->numFaces); - rtcUpdateBuffer(g_scene,mesh->geomID,RTC_LEVEL_BUFFER); - } -} -#endif - -void updateEdgeLevels(ISPCScene* scene_in, const Vec3fa& cam_pos) -{ - /* first update small meshes */ -#if defined(ISPC) - launch[ scene_in->numSubdivMeshes ] updateMeshEdgeLevelBufferTask(scene_in,cam_pos); -#endif - - /* now update large meshes */ - for (size_t g=0; gnumSubdivMeshes; g++) - { - ISPCSubdivMesh* mesh = g_ispc_scene->subdiv[g]; - if (mesh->numFaces < 10000) continue; -#if defined(ISPC) - launch[ getNumHWThreads() ] updateSubMeshEdgeLevelBufferTask(mesh,cam_pos); -#else - updateEdgeLevelBuffer(mesh,cam_pos,0,mesh->numFaces); -#endif - rtcUpdateBuffer(g_scene,mesh->geomID,RTC_LEVEL_BUFFER); - } -} - -/* render function to use */ -renderPixelFunc renderPixel; - -/* error reporting function */ -void error_handler(const RTCError code, const char* str) -{ - printf("Embree: "); - switch (code) { - case RTC_UNKNOWN_ERROR : printf("RTC_UNKNOWN_ERROR"); break; - case RTC_INVALID_ARGUMENT : printf("RTC_INVALID_ARGUMENT"); break; - case RTC_INVALID_OPERATION: printf("RTC_INVALID_OPERATION"); break; - case RTC_OUT_OF_MEMORY : printf("RTC_OUT_OF_MEMORY"); break; - case RTC_UNSUPPORTED_CPU : printf("RTC_UNSUPPORTED_CPU"); break; - case RTC_CANCELLED : printf("RTC_CANCELLED"); break; - default : printf("invalid error code"); break; - } - if (str) { - printf(" ("); - while (*str) putchar(*str++); - printf(")\n"); - } - exit(1); -} - -bool g_use_smooth_normals = false; -void device_key_pressed(int key) -{ - //printf("key = %\n",key); - if (key == 115 /*c*/) g_use_smooth_normals = !g_use_smooth_normals; - else device_key_pressed_default(key); -} - -Vec3fa renderPixelEyeLight(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p); - - -/* called by the C++ code for initialization */ -extern "C" void device_init (char* cfg) -{ - /* create new Embree device */ - g_device = rtcNewDevice(cfg); - - /* set error handler */ - rtcDeviceSetErrorFunction(g_device,error_handler); - - /* set start render mode */ - renderPixel = renderPixelStandard; - //renderPixel = renderPixelEyeLight; - key_pressed_handler = device_key_pressed; -} - -RTCScene convertScene(ISPCScene* scene_in) -{ - /* create scene */ - if (g_ispc_scene->numSubdivMeshes) - g_subdiv_mode = true; - - size_t numGeometries = scene_in->numMeshes + scene_in->numSubdivMeshes; - typedef void* void_ptr; - geomID_to_mesh = new void_ptr[numGeometries]; - geomID_to_type = new int[numGeometries]; - - int scene_flags = RTC_SCENE_STATIC | RTC_SCENE_INCOHERENT; - int scene_aflags = RTC_INTERSECT1 | RTC_INTERPOLATE; - if (g_subdiv_mode) - scene_flags = RTC_SCENE_DYNAMIC | RTC_SCENE_INCOHERENT | RTC_SCENE_ROBUST; - - RTCScene scene_out = rtcDeviceNewScene(g_device, (RTCSceneFlags)scene_flags,(RTCAlgorithmFlags) scene_aflags); - - for (size_t i=0; inumSubdivMeshes; i++) - { - ISPCSubdivMesh* mesh = scene_in->subdiv[i]; - unsigned int geomID = rtcNewSubdivisionMesh(scene_out, - RTC_GEOMETRY_STATIC, - mesh->numFaces, mesh->numEdges, mesh->numVertices, - mesh->numEdgeCreases, mesh->numVertexCreases, mesh->numHoles); - mesh->geomID = geomID; - geomID_to_mesh[geomID] = mesh; - geomID_to_type[geomID] = 1; //2 - - for (size_t i=0; inumEdges; i++) mesh->subdivlevel[i] = FIXED_EDGE_TESSELLATION_VALUE; - rtcSetBuffer(scene_out, geomID, RTC_VERTEX_BUFFER, mesh->positions, 0, sizeof(Vec3fa )); - rtcSetBuffer(scene_out, geomID, RTC_LEVEL_BUFFER, mesh->subdivlevel, 0, sizeof(float)); - rtcSetBuffer(scene_out, geomID, RTC_INDEX_BUFFER, mesh->position_indices , 0, sizeof(unsigned int)); - rtcSetBuffer(scene_out, geomID, RTC_FACE_BUFFER, mesh->verticesPerFace, 0, sizeof(unsigned int)); - rtcSetBuffer(scene_out, geomID, RTC_HOLE_BUFFER, mesh->holes, 0, sizeof(unsigned int)); - rtcSetBuffer(scene_out, geomID, RTC_EDGE_CREASE_INDEX_BUFFER, mesh->edge_creases, 0, 2*sizeof(unsigned int)); - rtcSetBuffer(scene_out, geomID, RTC_EDGE_CREASE_WEIGHT_BUFFER, mesh->edge_crease_weights, 0, sizeof(float)); - rtcSetBuffer(scene_out, geomID, RTC_VERTEX_CREASE_INDEX_BUFFER, mesh->vertex_creases, 0, sizeof(unsigned int)); - rtcSetBuffer(scene_out, geomID, RTC_VERTEX_CREASE_WEIGHT_BUFFER, mesh->vertex_crease_weights, 0, sizeof(float)); - } - - /* add all meshes to the scene */ - for (int i=0; inumMeshes; i++) - { - /* get ith mesh */ - ISPCMesh* mesh = scene_in->meshes[i]; - - /* create a triangle mesh */ - unsigned int geomID = rtcNewTriangleMesh (scene_out, RTC_GEOMETRY_STATIC, mesh->numTriangles, mesh->numVertices); - - geomID_to_mesh[geomID] = mesh; - geomID_to_type[geomID] = 0; - - /* share vertex buffer */ - rtcSetBuffer(scene_out, geomID, RTC_VERTEX_BUFFER, mesh->positions, 0, sizeof(Vec3fa )); - rtcSetBuffer(scene_out, geomID, RTC_INDEX_BUFFER, mesh->triangles, 0, sizeof(ISPCTriangle)); - } - - /* commit changes to scene */ - return scene_out; -} - -/* task that renders a single screen tile */ -Vec3fa renderPixelStandard(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p) -{ - /* initialize ray */ - RTCRay ray; - ray.org = p; - ray.dir = normalize(x*vx + y*vy + vz); - ray.tnear = 0.0f; - ray.tfar = inf; - ray.geomID = RTC_INVALID_GEOMETRY_ID; - ray.primID = RTC_INVALID_GEOMETRY_ID; - ray.mask = -1; - ray.time = 0; - - /* intersect ray with scene */ - rtcIntersect(g_scene,ray); - -#if 1 - /* shade background black */ - if (ray.geomID == RTC_INVALID_GEOMETRY_ID) { - return Vec3fa(0.0f); - } - - /* shade all rays that hit something */ - Vec3fa color = Vec3fa(0.0f); - Vec3fa Ns = ray.Ng; - - if (g_use_smooth_normals) - if (ray.geomID != RTC_INVALID_GEOMETRY_ID) // FIXME: workaround for ISPC bug, location reached with empty execution mask - { - Vec3fa dPdu,dPdv; - int geomID = ray.geomID; { - rtcInterpolate(g_scene,geomID,ray.primID,ray.u,ray.v,RTC_VERTEX_BUFFER0,nullptr,&dPdu.x,&dPdv.x,3); - } - Ns = cross(dPdv,dPdu); - } - - int materialID = 0; -#if 1 // FIXME: pointer gather not implemented on ISPC for Xeon Phi - if (geomID_to_type[ray.geomID] == 0) - { - ISPCMesh* mesh = g_ispc_scene->meshes[ray.geomID]; - ISPCTriangle* tri = &mesh->triangles[ray.primID]; - - /* load material ID */ - materialID = tri->materialID; - - /* interpolate shading normal */ - if (mesh->normals) { - Vec3fa n0 = Vec3fa(mesh->normals[tri->v0]); - Vec3fa n1 = Vec3fa(mesh->normals[tri->v1]); - Vec3fa n2 = Vec3fa(mesh->normals[tri->v2]); - float u = ray.u, v = ray.v, w = 1.0f-ray.u-ray.v; - Ns = normalize(w*n0 + u*n1 + v*n2); - } else { - Ns = normalize(ray.Ng); - } - } - else - { - materialID = ((ISPCSubdivMesh*) geomID_to_mesh[ray.geomID])->materialID; - } -#else - - int geomID = ray.geomID; - { - if (geomID_to_type[ray.geomID] == 0) - { - ISPCMesh* mesh = g_ispc_scene->meshes[geomID]; - - foreach_unique (primID in ray.primID) - { - ISPCTriangle* tri = &mesh->triangles[primID]; - - /* load material ID */ - materialID = tri->materialID; - - /* interpolate shading normal */ - if (mesh->normals) { - Vec3fa n0 = Vec3fa(mesh->normals[tri->v0]); - Vec3fa n1 = Vec3fa(mesh->normals[tri->v1]); - Vec3fa n2 = Vec3fa(mesh->normals[tri->v2]); - float u = ray.u, v = ray.v, w = 1.0f-ray.u-ray.v; - Ns = w*n0 + u*n1 + v*n2; - } else { - Ns = normalize(ray.Ng); - } - } - } - else - { - materialID = ((ISPCSubdivMesh*) geomID_to_mesh[geomID])->materialID; - } - - } -#endif - Ns = normalize(Ns); - OBJMaterial* material = (OBJMaterial*) &g_ispc_scene->materials[materialID]; - color = Vec3fa(material->Kd); - - /* apply ambient light */ - Vec3fa Nf = faceforward(Ns,neg(ray.dir),Ns); - //Vec3fa Ng = normalize(ray.Ng); - //Vec3fa Nf = dot(ray.dir,Ng) < 0.0f ? Ng : neg(Ng); - color = color*dot(ray.dir,Nf); // FIXME: *= -#else - Vec3fa color = Vec3fa(0.0f); - -#endif - return color; -} - -/* task that renders a single screen tile */ -void renderTile(int taskIndex, int* pixels, - const int width, - const int height, - const float time, - const Vec3fa& vx, - const Vec3fa& vy, - const Vec3fa& vz, - const Vec3fa& p, - const int numTilesX, - const int numTilesY) -{ - const int tileY = taskIndex / numTilesX; - const int tileX = taskIndex - tileY * numTilesX; - const int x0 = tileX * TILE_SIZE_X; - const int x1 = min(x0+TILE_SIZE_X,width); - const int y0 = tileY * TILE_SIZE_Y; - const int y1 = min(y0+TILE_SIZE_Y,height); - - for (int y = y0; yProgramDatabase false $(OutDir)$(TargetName).pdb + false /nologo /DLL /MAP /DEBUG /fixed:no /INCREMENTAL:NO /DEF:"$(IntDir)tbbmalloc.def" %(AdditionalOptions) @@ -225,6 +226,9 @@ MachineX86 + + false + @@ -240,6 +244,7 @@ ProgramDatabase false $(OutDir)$(TargetName).pdb + false /nologo /DLL /MAP /DEBUG /fixed:no /INCREMENTAL:NO /DEF:"$(IntDir)tbbmalloc.def" %(AdditionalOptions) @@ -253,6 +258,9 @@ MachineX64 + + false + @@ -316,6 +324,7 @@ Level4 ProgramDatabase false + false /nologo /DLL /MAP /DEBUG /fixed:no /INCREMENTAL:NO /DEF:"$(IntDir)tbbmalloc.def" %(AdditionalOptions) @@ -341,6 +350,7 @@ Level4 ProgramDatabase false + false /nologo /DLL /MAP /DEBUG /fixed:no /INCREMENTAL:NO /DEF:"$(IntDir)tbbmalloc.def" %(AdditionalOptions) diff --git a/Engine/Source/ThirdParty/IntelTBB/IntelTBB-4.4u3/src/tbbmalloc/tbbmalloc.cpp b/Engine/Source/ThirdParty/IntelTBB/IntelTBB-4.4u3/src/tbbmalloc/tbbmalloc.cpp index faf9607ad5c9..66ce7374511c 100644 --- a/Engine/Source/ThirdParty/IntelTBB/IntelTBB-4.4u3/src/tbbmalloc/tbbmalloc.cpp +++ b/Engine/Source/ThirdParty/IntelTBB/IntelTBB-4.4u3/src/tbbmalloc/tbbmalloc.cpp @@ -83,6 +83,7 @@ void init_tbbmalloc() { } #if !__TBB_SOURCE_DIRECTLY_INCLUDED +#if EPIC_DOES_NOT_USE_TBB_AS_DLL #if USE_WINTHREAD extern "C" BOOL WINAPI DllMain( HINSTANCE /*hInst*/, DWORD callReason, LPVOID ) { @@ -112,6 +113,7 @@ struct RegisterProcessShutdownNotification { }; static RegisterProcessShutdownNotification reg; +#endif /* EPIC_DOES_NOT_USE_TBB_AS_DLL */ #endif /* !USE_WINTHREAD */ #endif /* !__TBB_SOURCE_DIRECTLY_INCLUDED */ diff --git a/Engine/Source/ThirdParty/Licenses/FBNotifications_License.txt b/Engine/Source/ThirdParty/Licenses/FBNotifications_License.txt new file mode 100644 index 000000000000..0a1e777167ef --- /dev/null +++ b/Engine/Source/ThirdParty/Licenses/FBNotifications_License.txt @@ -0,0 +1,19 @@ +Copyright (c) 2016-present, Facebook, Inc. All rights reserved. + +For Facebook In-App Notifications Framework software + +You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +copy, modify, and distribute this software in source code or binary form for use +in connection with the web services and APIs provided by Facebook. + +As with any software that integrates with the Facebook platform, your use of +this software is subject to the Facebook Developer Principles and Policies +[http://developers.facebook.com/policy/]. This copyright notice shall be +included in all copies or substantial portions of the software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/Engine/Source/ThirdParty/Licenses/Facebook_SDK4.01_LICENSE.txt b/Engine/Source/ThirdParty/Licenses/FacebookSDKiOS_License.txt similarity index 100% rename from Engine/Source/ThirdParty/Licenses/Facebook_SDK4.01_LICENSE.txt rename to Engine/Source/ThirdParty/Licenses/FacebookSDKiOS_License.txt diff --git a/Engine/Source/ThirdParty/Licenses/Gradle_License.txt b/Engine/Source/ThirdParty/Licenses/Gradle_License.txt new file mode 100644 index 000000000000..0f3f8864f620 --- /dev/null +++ b/Engine/Source/ThirdParty/Licenses/Gradle_License.txt @@ -0,0 +1,965 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + +============================================================================== +Gradle Subcomponents: + +------------------------------------------------------------------------------ +License for the slf4j package +------------------------------------------------------------------------------ +SLF4J License + +Copyright (c) 2004-2007 QOS.ch +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +These terms are identical to those of the MIT License, also called the X License or the X11 License, +which is a simple, permissive non-copyleft free software license. It is deemed compatible with virtually +all types of licenses, commercial or otherwise. In particular, the Free Software Foundation has declared it +compatible with GNU GPL. It is also known to be approved by the Apache Software Foundation as compatible +with Apache Software License. + + +------------------------------------------------------------------------------ +License for the JUnit package +------------------------------------------------------------------------------ +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON PUBLIC +LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM +CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + +a) in the case of the initial Contributor, the initial code and +documentation distributed under this Agreement, and + +b) in the case of each subsequent Contributor: + +i) changes to the Program, and + +ii) additions to the Program; + +where such changes and/or additions to the Program originate from and are +distributed by that particular Contributor. A Contribution 'originates' from a +Contributor if it was added to the Program by such Contributor itself or anyone +acting on such Contributor's behalf. Contributions do not include additions to +the Program which: (i) are separate modules of software distributed in +conjunction with the Program under their own license agreement, and (ii) are not +derivative works of the Program. + +"Contributor" means any person or entity that distributes the Program. + +"Licensed Patents " mean patent claims licensable by a Contributor which are +necessarily infringed by the use or sale of its Contribution alone or when +combined with the Program. + +"Program" means the Contributions distributed in accordance with this Agreement. + +"Recipient" means anyone who receives the Program under this Agreement, +including all Contributors. + +2. GRANT OF RIGHTS + +a) Subject to the terms of this Agreement, each Contributor hereby grants +Recipient a non-exclusive, worldwide, royalty-free copyright license to +reproduce, prepare derivative works of, publicly display, publicly perform, +distribute and sublicense the Contribution of such Contributor, if any, and such +derivative works, in source code and object code form. + +b) Subject to the terms of this Agreement, each Contributor hereby grants +Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed +Patents to make, use, sell, offer to sell, import and otherwise transfer the +Contribution of such Contributor, if any, in source code and object code form. +This patent license shall apply to the combination of the Contribution and the +Program if, at the time the Contribution is added by the Contributor, such +addition of the Contribution causes such combination to be covered by the +Licensed Patents. The patent license shall not apply to any other combinations +which include the Contribution. No hardware per se is licensed hereunder. + +c) Recipient understands that although each Contributor grants the licenses +to its Contributions set forth herein, no assurances are provided by any +Contributor that the Program does not infringe the patent or other intellectual +property rights of any other entity. Each Contributor disclaims any liability to +Recipient for claims brought by any other entity based on infringement of +intellectual property rights or otherwise. As a condition to exercising the +rights and licenses granted hereunder, each Recipient hereby assumes sole +responsibility to secure any other intellectual property rights needed, if any. +For example, if a third party patent license is required to allow Recipient to +distribute the Program, it is Recipient's responsibility to acquire that license +before distributing the Program. + +d) Each Contributor represents that to its knowledge it has sufficient +copyright rights in its Contribution, if any, to grant the copyright license set +forth in this Agreement. + +3. REQUIREMENTS + +A Contributor may choose to distribute the Program in object code form under its +own license agreement, provided that: + +a) it complies with the terms and conditions of this Agreement; and + +b) its license agreement: + +i) effectively disclaims on behalf of all Contributors all warranties and +conditions, express and implied, including warranties or conditions of title and +non-infringement, and implied warranties or conditions of merchantability and +fitness for a particular purpose; + +ii) effectively excludes on behalf of all Contributors all liability for +damages, including direct, indirect, special, incidental and consequential +damages, such as lost profits; + +iii) states that any provisions which differ from this Agreement are offered +by that Contributor alone and not by any other party; and + +iv) states that source code for the Program is available from such +Contributor, and informs licensees how to obtain it in a reasonable manner on or +through a medium customarily used for software exchange. + +When the Program is made available in source code form: + +a) it must be made available under this Agreement; and + +b) a copy of this Agreement must be included with each copy of the Program. + +Contributors may not remove or alter any copyright notices contained within the +Program. + +Each Contributor must identify itself as the originator of its Contribution, if +any, in a manner that reasonably allows subsequent Recipients to identify the +originator of the Contribution. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities with +respect to end users, business partners and the like. While this license is +intended to facilitate the commercial use of the Program, the Contributor who +includes the Program in a commercial product offering should do so in a manner +which does not create potential liability for other Contributors. Therefore, if +a Contributor includes the Program in a commercial product offering, such +Contributor ("Commercial Contributor") hereby agrees to defend and indemnify +every other Contributor ("Indemnified Contributor") against any losses, damages +and costs (collectively "Losses") arising from claims, lawsuits and other legal +actions brought by a third party against the Indemnified Contributor to the +extent caused by the acts or omissions of such Commercial Contributor in +connection with its distribution of the Program in a commercial product +offering. The obligations in this section do not apply to any claims or Losses +relating to any actual or alleged intellectual property infringement. In order +to qualify, an Indemnified Contributor must: a) promptly notify the Commercial +Contributor in writing of such claim, and b) allow the Commercial Contributor to +control, and cooperate with the Commercial Contributor in, the defense and any +related settlement negotiations. The Indemnified Contributor may participate in +any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial product +offering, Product X. That Contributor is then a Commercial Contributor. If that +Commercial Contributor then makes performance claims, or offers warranties +related to Product X, those performance claims and warranties are such +Commercial Contributor's responsibility alone. Under this section, the +Commercial Contributor would have to defend claims against the other +Contributors related to those performance claims and warranties, and if a court +requires any other Contributor to pay any damages as a result, the Commercial +Contributor must pay those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR +IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each +Recipient is solely responsible for determining the appropriateness of using and +distributing the Program and assumes all risks associated with its exercise of +rights under this Agreement, including but not limited to the risks and costs of +program errors, compliance with applicable laws, damage to or loss of data, +programs or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY +CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST +PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS +GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under applicable +law, it shall not affect the validity or enforceability of the remainder of the +terms of this Agreement, and without further action by the parties hereto, such +provision shall be reformed to the minimum extent necessary to make such +provision valid and enforceable. + +If Recipient institutes patent litigation against a Contributor with respect to +a patent applicable to software (including a cross-claim or counterclaim in a +lawsuit), then any patent licenses granted by that Contributor to such Recipient +under this Agreement shall terminate as of the date such litigation is filed. In +addition, if Recipient institutes patent litigation against any entity +(including a cross-claim or counterclaim in a lawsuit) alleging that the Program +itself (excluding combinations of the Program with other software or hardware) +infringes such Recipient's patent(s), then such Recipient's rights granted under +Section 2(b) shall terminate as of the date such litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it fails to +comply with any of the material terms or conditions of this Agreement and does +not cure such failure in a reasonable period of time after becoming aware of +such noncompliance. If all Recipient's rights under this Agreement terminate, +Recipient agrees to cease use and distribution of the Program as soon as +reasonably practicable. However, Recipient's obligations under this Agreement +and any licenses granted by Recipient relating to the Program shall continue and +survive. + +Everyone is permitted to copy and distribute copies of this Agreement, but in +order to avoid inconsistency the Agreement is copyrighted and may only be +modified in the following manner. The Agreement Steward reserves the right to +publish new versions (including revisions) of this Agreement from time to time. +No one other than the Agreement Steward has the right to modify this Agreement. +IBM is the initial Agreement Steward. IBM may assign the responsibility to serve +as the Agreement Steward to a suitable separate entity. Each new version of the +Agreement will be given a distinguishing version number. The Program (including +Contributions) may always be distributed subject to the version of the Agreement +under which it was received. In addition, after a new version of the Agreement +is published, Contributor may elect to distribute the Program (including its +Contributions) under the new version. Except as expressly stated in Sections +2(a) and 2(b) above, Recipient receives no rights or licenses to the +intellectual property of any Contributor under this Agreement, whether +expressly, by implication, estoppel or otherwise. All rights in the Program not +expressly granted under this Agreement are reserved. + +This Agreement is governed by the laws of the State of New York and the +intellectual property laws of the United States of America. No party to this +Agreement will bring a legal action under this Agreement more than one year +after the cause of action arose. Each party waives its rights to a jury trial in +any resulting litigation. + +------------------------------------------------------------------------------ +License for the JCIFS package +------------------------------------------------------------------------------ +JCIFS License + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + diff --git a/Engine/Source/ThirdParty/Licenses/JPEG_License.txt b/Engine/Source/ThirdParty/Licenses/JPEG_License.txt index d1fb306e0874..86cc20669d61 100644 --- a/Engine/Source/ThirdParty/Licenses/JPEG_License.txt +++ b/Engine/Source/ThirdParty/Licenses/JPEG_License.txt @@ -1,11 +1,385 @@ -JPEG +The Independent JPEG Group's JPEG software +========================================== -The authors make NO WARRANTY or representation, either express or implied, with respect to this software, its quality, accuracy, merchantability, or fitness for a particular purpose. This software is provided AS IS, and you, its user, assume the entire risk as to its quality and accuracy. +README for release 6b of 27-Mar-1998 +==================================== -This software is copyright (C) 1991-1998, Thomas G. Lane. +This distribution contains the sixth public release of the Independent JPEG +Group's free JPEG software. You are welcome to redistribute this software and +to use it for any purpose, subject to the conditions under LEGAL ISSUES, below. +Serious users of this software (particularly those incorporating it into +larger programs) should contact IJG at jpeg-info@uunet.uu.net to be added to +our electronic mailing list. Mailing list members are notified of updates +and have a chance to participate in technical discussions, etc. + +This software is the work of Tom Lane, Philip Gladstone, Jim Boucher, +Lee Crocker, Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi, +Guido Vollbeding, Ge' Weijers, and other members of the Independent JPEG +Group. + +IJG is not affiliated with the official ISO JPEG standards committee. + + +DOCUMENTATION ROADMAP +===================== + +This file contains the following sections: + +OVERVIEW General description of JPEG and the IJG software. +LEGAL ISSUES Copyright, lack of warranty, terms of distribution. +REFERENCES Where to learn more about JPEG. +ARCHIVE LOCATIONS Where to find newer versions of this software. +RELATED SOFTWARE Other stuff you should get. +FILE FORMAT WARS Software *not* to get. +TO DO Plans for future IJG releases. + +Other documentation files in the distribution are: + +User documentation: + install.doc How to configure and install the IJG software. + usage.doc Usage instructions for cjpeg, djpeg, jpegtran, + rdjpgcom, and wrjpgcom. + *.1 Unix-style man pages for programs (same info as usage.doc). + wizard.doc Advanced usage instructions for JPEG wizards only. + change.log Version-to-version change highlights. +Programmer and internal documentation: + libjpeg.doc How to use the JPEG library in your own programs. + example.c Sample code for calling the JPEG library. + structure.doc Overview of the JPEG library's internal structure. + filelist.doc Road map of IJG files. + coderules.doc Coding style rules --- please read if you contribute code. + +Please read at least the files install.doc and usage.doc. Useful information +can also be found in the JPEG FAQ (Frequently Asked Questions) article. See +ARCHIVE LOCATIONS below to find out where to obtain the FAQ article. + +If you want to understand how the JPEG code works, we suggest reading one or +more of the REFERENCES, then looking at the documentation files (in roughly +the order listed) before diving into the code. + + +OVERVIEW +======== + +This package contains C software to implement JPEG image compression and +decompression. JPEG (pronounced "jay-peg") is a standardized compression +method for full-color and gray-scale images. JPEG is intended for compressing +"real-world" scenes; line drawings, cartoons and other non-realistic images +are not its strong suit. JPEG is lossy, meaning that the output image is not +exactly identical to the input image. Hence you must not use JPEG if you +have to have identical output bits. However, on typical photographic images, +very good compression levels can be obtained with no visible change, and +remarkably high compression levels are possible if you can tolerate a +low-quality image. For more details, see the references, or just experiment +with various compression settings. + +This software implements JPEG baseline, extended-sequential, and progressive +compression processes. Provision is made for supporting all variants of these +processes, although some uncommon parameter settings aren't implemented yet. +For legal reasons, we are not distributing code for the arithmetic-coding +variants of JPEG; see LEGAL ISSUES. We have made no provision for supporting +the hierarchical or lossless processes defined in the standard. + +We provide a set of library routines for reading and writing JPEG image files, +plus two sample applications "cjpeg" and "djpeg", which use the library to +perform conversion between JPEG and some other popular image file formats. +The library is intended to be reused in other applications. + +In order to support file conversion and viewing software, we have included +considerable functionality beyond the bare JPEG coding/decoding capability; +for example, the color quantization modules are not strictly part of JPEG +decoding, but they are essential for output to colormapped file formats or +colormapped displays. These extra functions can be compiled out of the +library if not required for a particular application. We have also included +"jpegtran", a utility for lossless transcoding between different JPEG +processes, and "rdjpgcom" and "wrjpgcom", two simple applications for +inserting and extracting textual comments in JFIF files. + +The emphasis in designing this software has been on achieving portability and +flexibility, while also making it fast enough to be useful. In particular, +the software is not intended to be read as a tutorial on JPEG. (See the +REFERENCES section for introductory material.) Rather, it is intended to +be reliable, portable, industrial-strength code. We do not claim to have +achieved that goal in every aspect of the software, but we strive for it. + +We welcome the use of this software as a component of commercial products. +No royalty is required, but we do ask for an acknowledgement in product +documentation, as described under LEGAL ISSUES. + + +LEGAL ISSUES +============ + +In plain English: + +1. We don't promise that this software works. (But if you find any bugs, + please let us know!) +2. You can use this software for whatever you want. You don't have to pay us. +3. You may not pretend that you wrote this software. If you use it in a + program, you must acknowledge somewhere in your documentation that + you've used the IJG code. + +In legalese: + +The authors make NO WARRANTY or representation, either express or implied, +with respect to this software, its quality, accuracy, merchantability, or +fitness for a particular purpose. This software is provided "AS IS", and you, +its user, assume the entire risk as to its quality and accuracy. + +This software is copyright (C) 1991-1998, Thomas G. Lane. All Rights Reserved except as specified below. -Permission is hereby granted to use, copy, modify, and distribute this software (or portions thereof) for any purpose, without fee, subject to these conditions: (1) If any part of the source code for this software is distributed, then this README file must be included, with this copyright and no-warranty notice unaltered; and any additions, deletions, or changes to the original files must be clearly indicated in accompanying documentation. (2) If only executable code is distributed, then the accompanying documentation must state that this software is based in part on the work of the Independent PEG Group. (3) Permission for use of this software is granted only if the user accepts full responsibility for any undesirable consequences; the authors accept NO LIABILITY for damages of any kind. +Permission is hereby granted to use, copy, modify, and distribute this +software (or portions thereof) for any purpose, without fee, subject to these +conditions: +(1) If any part of the source code for this software is distributed, then this +README file must be included, with this copyright and no-warranty notice +unaltered; and any additions, deletions, or changes to the original files +must be clearly indicated in accompanying documentation. +(2) If only executable code is distributed, then the accompanying +documentation must state that "this software is based in part on the work of +the Independent JPEG Group". +(3) Permission for use of this software is granted only if the user accepts +full responsibility for any undesirable consequences; the authors accept +NO LIABILITY for damages of any kind. -These conditions apply to any software derived from or based on the I]G code, not just to the unmodified library. If you use our work, you ought to acknowledge us. Permission is NOT granted for the use of any IJG authors name or company name In advertising or publicity relating to this software or products derived from it. This software may be referred to only as the Independent IPEG Groups software. We specifically permit and encourage the use of this software as the basis of commercial products, provided that all warranty or liability claims are assumed by the product vendor. +These conditions apply to any software derived from or based on the IJG code, +not just to the unmodified library. If you use our work, you ought to +acknowledge us. + +Permission is NOT granted for the use of any IJG author's name or company name +in advertising or publicity relating to this software or products derived from +it. This software may be referred to only as "the Independent JPEG Group's +software". + +We specifically permit and encourage the use of this software as the basis of +commercial products, provided that all warranty or liability claims are +assumed by the product vendor. + + +ansi2knr.c is included in this distribution by permission of L. Peter Deutsch, +sole proprietor of its copyright holder, Aladdin Enterprises of Menlo Park, CA. +ansi2knr.c is NOT covered by the above copyright and conditions, but instead +by the usual distribution terms of the Free Software Foundation; principally, +that you must include source code if you redistribute it. (See the file +ansi2knr.c for full details.) However, since ansi2knr.c is not needed as part +of any program generated from the IJG code, this does not limit you more than +the foregoing paragraphs do. + +The Unix configuration script "configure" was produced with GNU Autoconf. +It is copyright by the Free Software Foundation but is freely distributable. +The same holds for its supporting scripts (config.guess, config.sub, +ltconfig, ltmain.sh). Another support script, install-sh, is copyright +by M.I.T. but is also freely distributable. + +It appears that the arithmetic coding option of the JPEG spec is covered by +patents owned by IBM, AT&T, and Mitsubishi. Hence arithmetic coding cannot +legally be used without obtaining one or more licenses. For this reason, +support for arithmetic coding has been removed from the free JPEG software. +(Since arithmetic coding provides only a marginal gain over the unpatented +Huffman mode, it is unlikely that very many implementations will support it.) +So far as we are aware, there are no patent restrictions on the remaining +code. + +The IJG distribution formerly included code to read and write GIF files. +To avoid entanglement with the Unisys LZW patent, GIF reading support has +been removed altogether, and the GIF writer has been simplified to produce +"uncompressed GIFs". This technique does not use the LZW algorithm; the +resulting GIF files are larger than usual, but are readable by all standard +GIF decoders. + +We are required to state that + "The Graphics Interchange Format(c) is the Copyright property of + CompuServe Incorporated. GIF(sm) is a Service Mark property of + CompuServe Incorporated." + + +REFERENCES +========== + +We highly recommend reading one or more of these references before trying to +understand the innards of the JPEG software. + +The best short technical introduction to the JPEG compression algorithm is + Wallace, Gregory K. "The JPEG Still Picture Compression Standard", + Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44. +(Adjacent articles in that issue discuss MPEG motion picture compression, +applications of JPEG, and related topics.) If you don't have the CACM issue +handy, a PostScript file containing a revised version of Wallace's article is +available at ftp://ftp.uu.net/graphics/jpeg/wallace.ps.gz. The file (actually +a preprint for an article that appeared in IEEE Trans. Consumer Electronics) +omits the sample images that appeared in CACM, but it includes corrections +and some added material. Note: the Wallace article is copyright ACM and IEEE, +and it may not be used for commercial purposes. + +A somewhat less technical, more leisurely introduction to JPEG can be found in +"The Data Compression Book" by Mark Nelson and Jean-loup Gailly, published by +M&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1. This book provides +good explanations and example C code for a multitude of compression methods +including JPEG. It is an excellent source if you are comfortable reading C +code but don't know much about data compression in general. The book's JPEG +sample code is far from industrial-strength, but when you are ready to look +at a full implementation, you've got one here... + +The best full description of JPEG is the textbook "JPEG Still Image Data +Compression Standard" by William B. Pennebaker and Joan L. Mitchell, published +by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1. Price US$59.95, 638 pp. +The book includes the complete text of the ISO JPEG standards (DIS 10918-1 +and draft DIS 10918-2). This is by far the most complete exposition of JPEG +in existence, and we highly recommend it. + +The JPEG standard itself is not available electronically; you must order a +paper copy through ISO or ITU. (Unless you feel a need to own a certified +official copy, we recommend buying the Pennebaker and Mitchell book instead; +it's much cheaper and includes a great deal of useful explanatory material.) +In the USA, copies of the standard may be ordered from ANSI Sales at (212) +642-4900, or from Global Engineering Documents at (800) 854-7179. (ANSI +doesn't take credit card orders, but Global does.) It's not cheap: as of +1992, ANSI was charging $95 for Part 1 and $47 for Part 2, plus 7% +shipping/handling. The standard is divided into two parts, Part 1 being the +actual specification, while Part 2 covers compliance testing methods. Part 1 +is titled "Digital Compression and Coding of Continuous-tone Still Images, +Part 1: Requirements and guidelines" and has document numbers ISO/IEC IS +10918-1, ITU-T T.81. Part 2 is titled "Digital Compression and Coding of +Continuous-tone Still Images, Part 2: Compliance testing" and has document +numbers ISO/IEC IS 10918-2, ITU-T T.83. + +Some extensions to the original JPEG standard are defined in JPEG Part 3, +a newer ISO standard numbered ISO/IEC IS 10918-3 and ITU-T T.84. IJG +currently does not support any Part 3 extensions. + +The JPEG standard does not specify all details of an interchangeable file +format. For the omitted details we follow the "JFIF" conventions, revision +1.02. A copy of the JFIF spec is available from: + Literature Department + C-Cube Microsystems, Inc. + 1778 McCarthy Blvd. + Milpitas, CA 95035 + phone (408) 944-6300, fax (408) 944-6314 +A PostScript version of this document is available by FTP at +ftp://ftp.uu.net/graphics/jpeg/jfif.ps.gz. There is also a plain text +version at ftp://ftp.uu.net/graphics/jpeg/jfif.txt.gz, but it is missing +the figures. + +The TIFF 6.0 file format specification can be obtained by FTP from +ftp://ftp.sgi.com/graphics/tiff/TIFF6.ps.gz. The JPEG incorporation scheme +found in the TIFF 6.0 spec of 3-June-92 has a number of serious problems. +IJG does not recommend use of the TIFF 6.0 design (TIFF Compression tag 6). +Instead, we recommend the JPEG design proposed by TIFF Technical Note #2 +(Compression tag 7). Copies of this Note can be obtained from ftp.sgi.com or +from ftp://ftp.uu.net/graphics/jpeg/. It is expected that the next revision +of the TIFF spec will replace the 6.0 JPEG design with the Note's design. +Although IJG's own code does not support TIFF/JPEG, the free libtiff library +uses our library to implement TIFF/JPEG per the Note. libtiff is available +from ftp://ftp.sgi.com/graphics/tiff/. + + +ARCHIVE LOCATIONS +================= + +The "official" archive site for this software is ftp.uu.net (Internet +address 192.48.96.9). The most recent released version can always be found +there in directory graphics/jpeg. This particular version will be archived +as ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz. If you don't have +direct Internet access, UUNET's archives are also available via UUCP; contact +help@uunet.uu.net for information on retrieving files that way. + +Numerous Internet sites maintain copies of the UUNET files. However, only +ftp.uu.net is guaranteed to have the latest official version. + +You can also obtain this software in DOS-compatible "zip" archive format from +the SimTel archives (ftp://ftp.simtel.net/pub/simtelnet/msdos/graphics/), or +on CompuServe in the Graphics Support forum (GO CIS:GRAPHSUP), library 12 +"JPEG Tools". Again, these versions may sometimes lag behind the ftp.uu.net +release. + +The JPEG FAQ (Frequently Asked Questions) article is a useful source of +general information about JPEG. It is updated constantly and therefore is +not included in this distribution. The FAQ is posted every two weeks to +Usenet newsgroups comp.graphics.misc, news.answers, and other groups. +It is available on the World Wide Web at http://www.faqs.org/faqs/jpeg-faq/ +and other news.answers archive sites, including the official news.answers +archive at rtfm.mit.edu: ftp://rtfm.mit.edu/pub/usenet/news.answers/jpeg-faq/. +If you don't have Web or FTP access, send e-mail to mail-server@rtfm.mit.edu +with body + send usenet/news.answers/jpeg-faq/part1 + send usenet/news.answers/jpeg-faq/part2 + + +RELATED SOFTWARE +================ + +Numerous viewing and image manipulation programs now support JPEG. (Quite a +few of them use this library to do so.) The JPEG FAQ described above lists +some of the more popular free and shareware viewers, and tells where to +obtain them on Internet. + +If you are on a Unix machine, we highly recommend Jef Poskanzer's free +PBMPLUS software, which provides many useful operations on PPM-format image +files. In particular, it can convert PPM images to and from a wide range of +other formats, thus making cjpeg/djpeg considerably more useful. The latest +version is distributed by the NetPBM group, and is available from numerous +sites, notably ftp://wuarchive.wustl.edu/graphics/graphics/packages/NetPBM/. +Unfortunately PBMPLUS/NETPBM is not nearly as portable as the IJG software is; +you are likely to have difficulty making it work on any non-Unix machine. + +A different free JPEG implementation, written by the PVRG group at Stanford, +is available from ftp://havefun.stanford.edu/pub/jpeg/. This program +is designed for research and experimentation rather than production use; +it is slower, harder to use, and less portable than the IJG code, but it +is easier to read and modify. Also, the PVRG code supports lossless JPEG, +which we do not. (On the other hand, it doesn't do progressive JPEG.) + + +FILE FORMAT WARS +================ + +Some JPEG programs produce files that are not compatible with our library. +The root of the problem is that the ISO JPEG committee failed to specify a +concrete file format. Some vendors "filled in the blanks" on their own, +creating proprietary formats that no one else could read. (For example, none +of the early commercial JPEG implementations for the Macintosh were able to +exchange compressed files.) + +The file format we have adopted is called JFIF (see REFERENCES). This format +has been agreed to by a number of major commercial JPEG vendors, and it has +become the de facto standard. JFIF is a minimal or "low end" representation. +We recommend the use of TIFF/JPEG (TIFF revision 6.0 as modified by TIFF +Technical Note #2) for "high end" applications that need to record a lot of +additional data about an image. TIFF/JPEG is fairly new and not yet widely +supported, unfortunately. + +The upcoming JPEG Part 3 standard defines a file format called SPIFF. +SPIFF is interoperable with JFIF, in the sense that most JFIF decoders should +be able to read the most common variant of SPIFF. SPIFF has some technical +advantages over JFIF, but its major claim to fame is simply that it is an +official standard rather than an informal one. At this point it is unclear +whether SPIFF will supersede JFIF or whether JFIF will remain the de-facto +standard. IJG intends to support SPIFF once the standard is frozen, but we +have not decided whether it should become our default output format or not. +(In any case, our decoder will remain capable of reading JFIF indefinitely.) + +Various proprietary file formats incorporating JPEG compression also exist. +We have little or no sympathy for the existence of these formats. Indeed, +one of the original reasons for developing this free software was to help +force convergence on common, open format standards for JPEG files. Don't +use a proprietary file format! + + +TO DO +===== + +The major thrust for v7 will probably be improvement of visual quality. +The current method for scaling the quantization tables is known not to be +very good at low Q values. We also intend to investigate block boundary +smoothing, "poor man's variable quantization", and other means of improving +quality-vs-file-size performance without sacrificing compatibility. + +In future versions, we are considering supporting some of the upcoming JPEG +Part 3 extensions --- principally, variable quantization and the SPIFF file +format. + +As always, speeding things up is of great interest. + +Please send bug reports, offers of help, etc. to jpeg-info@uunet.uu.net. diff --git a/Engine/Source/ThirdParty/Licenses/MarketplacePlugins/ExtendedFacebookOnlineSubsystem_FacebookSDKAndroid_Notice.txt b/Engine/Source/ThirdParty/Licenses/MarketplacePlugins/ExtendedFacebookOnlineSubsystem_FacebookSDKAndroid_Notice.txt new file mode 100644 index 000000000000..7e869a6befc7 --- /dev/null +++ b/Engine/Source/ThirdParty/Licenses/MarketplacePlugins/ExtendedFacebookOnlineSubsystem_FacebookSDKAndroid_Notice.txt @@ -0,0 +1,61 @@ +THE FOLLOWING SETS FORTH ATTRIBUTION NOTICES FOR THIRD PARTY SOFTWARE THAT MAY BE CONTAINED IN PORTIONS OF THE FACEBOOK PRODUCT. + +----- + +The following software may be included in this product: Android. This software contains the following license and notice below: + +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + +(a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + +(b) You must cause any modified files to carry prominent notices stating that You changed the files; and + +(c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + +(d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/Engine/Source/ThirdParty/Licenses/NanoVG_License.txt b/Engine/Source/ThirdParty/Licenses/NanoVG_License.txt new file mode 100644 index 000000000000..0102d88bb9f3 --- /dev/null +++ b/Engine/Source/ThirdParty/Licenses/NanoVG_License.txt @@ -0,0 +1,17 @@ +Copyright (c) 2013 Mikko Mononen memon@inside.org + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. \ No newline at end of file diff --git a/Engine/Source/ThirdParty/Licenses/OpenEXR_License.txt b/Engine/Source/ThirdParty/Licenses/OpenEXR_License.txt index 91fd1c29d0f1..8f8456e9170e 100644 --- a/Engine/Source/ThirdParty/Licenses/OpenEXR_License.txt +++ b/Engine/Source/ThirdParty/Licenses/OpenEXR_License.txt @@ -1,11 +1,33 @@ -Modified BSD License: +Copyright (c) 2006, Industrial Light & Magic, a division of Lucasfilm +Entertainment Company Ltd. Portions contributed and copyright held by +others as indicated. All rights reserved. -Copyright (c) 2002-2011, Industrial Light & Magic, a division of Lucasfilm Entertainment Company Ltd. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - Neither the name of Industrial Light & Magic nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided with + the distribution. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file + * Neither the name of Industrial Light & Magic nor the names of + any other contributors to this software may be used to endorse or + promote products derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/Engine/Source/ThirdParty/Licenses/OpenVDB_License.txt b/Engine/Source/ThirdParty/Licenses/OpenVDB_License.txt new file mode 100644 index 000000000000..2954c3531608 --- /dev/null +++ b/Engine/Source/ThirdParty/Licenses/OpenVDB_License.txt @@ -0,0 +1,25 @@ +Copyright (c) 2012-2013 DreamWorks Animation LLC + +All rights reserved. This software is distributed under the +Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) + +Redistributions of source code must retain the above copyright +and license notice and the following restrictions and disclaimer. + +* Neither the name of DreamWorks Animation nor the names of +its contributors may be used to endorse or promote products derived +from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE +LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. \ No newline at end of file diff --git a/Engine/Source/ThirdParty/Oculus/Common/AsyncLoadingSplash.cpp b/Engine/Source/ThirdParty/Oculus/Common/AsyncLoadingSplash.cpp index ede71d5b4189..2979511148f8 100644 --- a/Engine/Source/ThirdParty/Oculus/Common/AsyncLoadingSplash.cpp +++ b/Engine/Source/ThirdParty/Oculus/Common/AsyncLoadingSplash.cpp @@ -2,8 +2,6 @@ #include "AsyncLoadingSplash.h" -DEFINE_LOG_CATEGORY_STATIC(LogLoadingSplash, Log, All); - FAsyncLoadingSplash::FAsyncLoadingSplash() : bAutoShow(true) , bInitialized(false) diff --git a/Engine/Source/ThirdParty/Oculus/Common/HeadMountedDisplayCommon.cpp b/Engine/Source/ThirdParty/Oculus/Common/HeadMountedDisplayCommon.cpp index b7647e854d7d..2c15fc06dc09 100644 --- a/Engine/Source/ThirdParty/Oculus/Common/HeadMountedDisplayCommon.cpp +++ b/Engine/Source/ThirdParty/Oculus/Common/HeadMountedDisplayCommon.cpp @@ -883,9 +883,15 @@ void FHeadMountedDisplay::UpdateSplashScreen() FTexture2DRHIRef Texture2D = (bSplashShowMovie && SplashMovie.IsValid()) ? SplashMovie : SplashTexture; FTextureRHIRef Texture; + float InvAspectRatio = 1.0; if (Texture2D.IsValid()) { Texture = (FRHITexture*)Texture2D.GetReference(); + const FIntPoint TextureSize = Texture2D->GetSizeXY(); + if (TextureSize.X > 0) + { + InvAspectRatio = float(TextureSize.Y) / float(TextureSize.X); + } } // Disable features incompatible with the generalized VR splash screen @@ -908,7 +914,8 @@ void FHeadMountedDisplay::UpdateSplashScreen() FAsyncLoadingSplash::FSplashDesc NewDesc; NewDesc.LoadedTexture = Texture; - NewDesc.QuadSizeInMeters = FVector2D(8.0f, 4.5f); + // Set texture size to 8m wide, keeping the aspect ratio. + NewDesc.QuadSizeInMeters = FVector2D(8.0f, 8.0f * InvAspectRatio); FTransform Translation(FVector(5.0f, 0.0f, 0.0f)); @@ -1444,25 +1451,45 @@ void FHMDLayerManager::PreSubmitUpdate_RenderThread(FRHICommandListImmediate& RH } } - struct Comparator + static const auto CVarMixLayerPriorities = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("vr.StereoLayers.bMixLayerPriorities")); + const bool bRenderHeadLockedFront = (CVarMixLayerPriorities->GetValueOnRenderThread() == 0) ; + + auto Comparator = [=](const TSharedPtr& l1, const TSharedPtr& l2) { - bool operator()(const TSharedPtr& l1, - const TSharedPtr& l2) const + if (!l1.IsValid()) { - if (!l1.IsValid()) + return false; + } + if (!l2.IsValid()) + { + return true; + } + auto LayerDesc1 = l1->GetLayerDesc(); + auto LayerDesc2 = l2->GetLayerDesc(); + if (LayerDesc1.IsPokeAHole() == LayerDesc2.IsPokeAHole()) + { + if (LayerDesc1.GetType() == LayerDesc2.GetType()) { - return false; + if (bRenderHeadLockedFront || LayerDesc1.IsHeadLocked() == LayerDesc2.IsHeadLocked()) + { + return LayerDesc1.GetPriority() < LayerDesc2.GetPriority(); + } + else + { + return LayerDesc2.IsHeadLocked(); + } } - if (!l2.IsValid()) + else { - return true; + return bool(LayerDesc1.IsPokeAHole() ^ (LayerDesc1.GetType() < LayerDesc2.GetType())); } - auto LayerDesc1 = l1->GetLayerDesc(); - auto LayerDesc2 = l2->GetLayerDesc(); - return LayerDesc1.IsPokeAHole() == LayerDesc2.IsPokeAHole() ? (LayerDesc1.GetType() == LayerDesc2.GetType() ? (LayerDesc1.GetPriority() < LayerDesc2.GetPriority()) : LayerDesc1.IsPokeAHole() ^ (LayerDesc1.GetType() < LayerDesc2.GetType())) : LayerDesc1.IsPokeAHole(); + } + else + { + return LayerDesc1.IsPokeAHole(); } }; - LayersToRender.Sort(Comparator()); + LayersToRender.Sort(Comparator); // all empty (nullptr) entries should be at the end of the array. // The total number of render layers should be equal to sum of all layers. LayersToRender.SetNum(EyeLayers.Num() + QuadLayers.Num() + DebugLayers.Num()); diff --git a/Engine/Source/ThirdParty/Oculus/Common/HeadMountedDisplayCommon.h b/Engine/Source/ThirdParty/Oculus/Common/HeadMountedDisplayCommon.h index 8e3ddae31b6d..caead62476cc 100644 --- a/Engine/Source/ThirdParty/Oculus/Common/HeadMountedDisplayCommon.h +++ b/Engine/Source/ThirdParty/Oculus/Common/HeadMountedDisplayCommon.h @@ -659,8 +659,6 @@ public: FMemory::Memzero(OutData); } - // 1060 paintbrush drive sunnyvale - /** * User profile structure. */ @@ -818,7 +816,3 @@ public: static void QuantizeBufferSize(int32& InOutBufferSizeX, int32& InOutBufferSizeY, uint32 DividableBy = 32); }; - -DEFINE_LOG_CATEGORY_STATIC(LogHMD, Log, All); - - diff --git a/Engine/Source/ThirdParty/Oculus/LibOVR/LibOVR_1_0_0/Src/OVR_CAPIShim.c b/Engine/Source/ThirdParty/Oculus/LibOVR/LibOVR_1_0_0/Src/OVR_CAPIShim.c index c64b1c630987..1b2552c149db 100644 --- a/Engine/Source/ThirdParty/Oculus/LibOVR/LibOVR_1_0_0/Src/OVR_CAPIShim.c +++ b/Engine/Source/ThirdParty/Oculus/LibOVR/LibOVR_1_0_0/Src/OVR_CAPIShim.c @@ -483,7 +483,7 @@ static ValidateCertificateContentsResult ValidateCertificateContents(Certificate pCertData->pCert, CERT_NAME_ATTR_TYPE, 0, - szOID_COMMON_NAME, + (void*)szOID_COMMON_NAME, subjectStr, ARRAYSIZE(subjectStr)); diff --git a/Engine/Source/ThirdParty/OpenSSL/OpenSSL.tps b/Engine/Source/ThirdParty/OpenSSL/OpenSSL.tps index b67a4eb81145..f5c46cdd1496 100644 --- a/Engine/Source/ThirdParty/OpenSSL/OpenSSL.tps +++ b/Engine/Source/ThirdParty/OpenSSL/OpenSSL.tps @@ -11,5 +11,5 @@ Git P4 - /Engine/Source/ThirdParty/Licenses/OpenSSL1.0.1e_License.txt + /Engine/Source/ThirdParty/Licenses/OpenSSL_License.txt \ No newline at end of file diff --git a/Engine/Source/ThirdParty/OpenVR/OpenVR.build.cs b/Engine/Source/ThirdParty/OpenVR/OpenVR.build.cs index d7881c4a3a22..86f9a35ba27f 100644 --- a/Engine/Source/ThirdParty/OpenVR/OpenVR.build.cs +++ b/Engine/Source/ThirdParty/OpenVR/OpenVR.build.cs @@ -51,14 +51,14 @@ public class OpenVR : ModuleRules string OpenVRBinariesDir = String.Format("$(EngineDir)/Binaries/ThirdParty/OpenVR/OpenVR{0}/osx32/", OpenVRVersion); RuntimeDependencies.Add(new RuntimeDependency(OpenVRBinariesDir + "libopenvr_api.dylib")); } - else if (Target.Platform == UnrealTargetPlatform.Linux) + else if (Target.Platform == UnrealTargetPlatform.Linux && Target.Architecture.StartsWith("x86_64")) { PublicLibraryPaths.Add(LibraryPath + "linux64"); PublicAdditionalLibraries.Add("openvr_api"); - PublicDelayLoadDLLs.Add("libopenvr_api.so"); - string OpenVRBinariesDir = String.Format("$(EngineDir)/Binaries/ThirdParty/OpenVR/OpenVR{0}/linux64/", OpenVRVersion); - RuntimeDependencies.Add(new RuntimeDependency(OpenVRBinariesDir + "libopenvr_api.so")); + string DylibPath = UEBuildConfiguration.UEThirdPartyBinariesDirectory + "OpenVR/OpenVR" + OpenVRVersion + "/linux64/libopenvr_api.so"; + PublicDelayLoadDLLs.Add(DylibPath); + RuntimeDependencies.Add(new RuntimeDependency(DylibPath)); } } } diff --git a/Engine/Source/ThirdParty/PLCrashReporter/PLCrashReporter.Build.cs b/Engine/Source/ThirdParty/PLCrashReporter/PLCrashReporter.Build.cs index 15da8c3b1e58..ff1c671cd0c1 100644 --- a/Engine/Source/ThirdParty/PLCrashReporter/PLCrashReporter.Build.cs +++ b/Engine/Source/ThirdParty/PLCrashReporter/PLCrashReporter.Build.cs @@ -21,5 +21,17 @@ public class PLCrashReporter : ModuleRules PublicAdditionalLibraries.Add(PLCrashReporterPath + "Mac/Release/libCrashReporter-MacOSX-Static.a"); } } - } + else if (Target.Platform == UnrealTargetPlatform.IOS) + { + PublicSystemIncludePaths.Add(PLCrashReporterPath + "Source"); + if (Target.Configuration == UnrealTargetConfiguration.Debug && BuildConfiguration.bDebugBuildsActuallyUseDebugCRT) + { + PublicAdditionalLibraries.Add(PLCrashReporterPath + "IOS/Debug/libCrashReporter-iphoneos.a"); + } + else + { + PublicAdditionalLibraries.Add(PLCrashReporterPath + "IOS/Release/libCrashReporter-iphoneos.a"); + } + } + } } diff --git a/Engine/Source/ThirdParty/PhysX/NvCloth.Build.cs b/Engine/Source/ThirdParty/PhysX/NvCloth.Build.cs index 5a04d162f051..4c4f1a74eec0 100644 --- a/Engine/Source/ThirdParty/PhysX/NvCloth.Build.cs +++ b/Engine/Source/ThirdParty/PhysX/NvCloth.Build.cs @@ -241,7 +241,16 @@ public class NvCloth : ModuleRules LibraryFormatString = "{0}"; } - else if (Target.Platform == UnrealTargetPlatform.XboxOne) + else if (Target.Platform == UnrealTargetPlatform.Switch) + { + NvClothLibDir += "/Switch"; + PublicLibraryPaths.Add(NvClothLibDir); + + NvClothLibraries.Add("NvCloth{0}"); + + LibraryFormatString = "{0}"; + } + else if (Target.Platform == UnrealTargetPlatform.XboxOne) { Definitions.Add("_XBOX_ONE=1"); diff --git a/Engine/Source/ThirdParty/PhysX/NvCloth/CmakeGenerateAll.bat b/Engine/Source/ThirdParty/PhysX/NvCloth/CmakeGenerateAll.bat index fe332dbce9d4..e379f4359bd3 100644 --- a/Engine/Source/ThirdParty/PhysX/NvCloth/CmakeGenerateAll.bat +++ b/Engine/Source/ThirdParty/PhysX/NvCloth/CmakeGenerateAll.bat @@ -12,5 +12,6 @@ SET PATH=%PATH%;"%CMAKE_PATH_F%" call CmakeGenerateProjects.bat call CmakeGenerateProjectsLinux.sh call CmakeGenerateProjectsPs4.bat +call CmakeGenerateProjectsSwitch.bat call CmakeGenerateProjectsXboxOne.bat pause \ No newline at end of file diff --git a/Engine/Source/ThirdParty/PhysX/NvCloth/CmakeGenerateProjectsSwitch.bat b/Engine/Source/ThirdParty/PhysX/NvCloth/CmakeGenerateProjectsSwitch.bat new file mode 100644 index 000000000000..52e5d0d2f167 --- /dev/null +++ b/Engine/Source/ThirdParty/PhysX/NvCloth/CmakeGenerateProjectsSwitch.bat @@ -0,0 +1,43 @@ +@echo off + +REM Make sure the various variables that we need are set + +IF EXIST %~dp0..\Externals\CMakeModules ( + set GW_DEPS_ROOT=%~dp0..\ +) + +IF NOT DEFINED GW_DEPS_ROOT GOTO GW_DEPS_ROOT_UNDEFINED + +IF EXIST %GW_DEPS_ROOT%\Externals\CMakeModules ( + set CMAKE_MODULE_PATH=%GW_DEPS_ROOT%\Externals\CMakeModules +) ELSE ( + set CMAKE_MODULE_PATH=%GW_DEPS_ROOT%\sw\physx\tools\CMakeModules +) + +set PX_OUTPUT_ROOT=%~dp0 + +REM Generate projects here + +rmdir /s /q compiler\vc14switch-cmake\ +mkdir compiler\vc14switch-cmake\ +pushd compiler\vc14switch-cmake\ +cmake ..\cmake\switch -G "Visual Studio 14 2015" -DTARGET_BUILD_PLATFORM=SWITCH -DPX_OUTPUT_LIB_DIR=%PX_OUTPUT_ROOT%\Lib\vc14switch-cmake -DCMAKE_TOOLCHAIN_FILE="%CMAKE_MODULE_PATH%\switch\SwitchToolchain.txt" -DCMAKE_GENERATOR_PLATFORM=SWITCH +popd + +GOTO :End + +:GW_DEPS_ROOT_UNDEFINED +ECHO GW_DEPS_ROOT has to be defined, pointing to the root of the dependency tree. +PAUSE +GOTO END + +:BOOST_ROOT_UNDEFINED +ECHO BOOST_ROOT has to be defined, pointing to the root of your local Boost install. +PAUSE +GOTO END + +:CUDA_ROOT_UNDEFINED +ECHO CUDA_BIN_PATH has to be defined, pointing to the bin folder of your local CUDA install. +PAUSE + +:End diff --git a/Engine/Source/ThirdParty/PhysX/NvCloth/compiler/cmake/common/IfTemplate.txt b/Engine/Source/ThirdParty/PhysX/NvCloth/compiler/cmake/common/IfTemplate.txt index f50b32e10687..00d2e545b7ee 100644 --- a/Engine/Source/ThirdParty/PhysX/NvCloth/compiler/cmake/common/IfTemplate.txt +++ b/Engine/Source/ThirdParty/PhysX/NvCloth/compiler/cmake/common/IfTemplate.txt @@ -1,5 +1,6 @@ IF(TARGET_BUILD_PLATFORM STREQUAL "Windows") ELSEIF(TARGET_BUILD_PLATFORM STREQUAL "PS4") +ELSEIF(TARGET_BUILD_PLATFORM STREQUAL "Switch") ELSEIF(TARGET_BUILD_PLATFORM STREQUAL "XboxOne") ELSEIF(TARGET_BUILD_PLATFORM STREQUAL "Unix") ENDIF() \ No newline at end of file diff --git a/Engine/Source/ThirdParty/PhysX/NvCloth/compiler/xpj/create_projects.bat b/Engine/Source/ThirdParty/PhysX/NvCloth/compiler/xpj/create_projects.bat index be599fd14662..db7e44f0da18 100644 --- a/Engine/Source/ThirdParty/PhysX/NvCloth/compiler/xpj/create_projects.bat +++ b/Engine/Source/ThirdParty/PhysX/NvCloth/compiler/xpj/create_projects.bat @@ -14,5 +14,6 @@ call "../../scripts/locate_xpj.bat" XPJ "%XPJ%\xpj4.exe" -t vc14 -p win32 -x "%CD%\NvCloth.xpj" "%XPJ%\xpj4.exe" -t vc14 -p xboxone -x "%CD%\NvCloth.xpj" "%XPJ%\xpj4.exe" -t vc14 -p ps4 -x "%CD%\NvCloth.xpj" +"%XPJ%\xpj4.exe" -t vc14 -p switch -x "%CD%\NvCloth.xpj" pause \ No newline at end of file diff --git a/Engine/Source/ThirdParty/PhysX/NvCloth/src/neon/SwCollisionHelpers.h b/Engine/Source/ThirdParty/PhysX/NvCloth/src/neon/SwCollisionHelpers.h index c2f959b26edd..e8abfc032ea8 100644 --- a/Engine/Source/ThirdParty/PhysX/NvCloth/src/neon/SwCollisionHelpers.h +++ b/Engine/Source/ThirdParty/PhysX/NvCloth/src/neon/SwCollisionHelpers.h @@ -33,7 +33,7 @@ #include #endif -namespace physx +namespace nv { namespace cloth { diff --git a/Engine/Source/ThirdParty/PhysX/NvCloth/src/scalar/SwCollisionHelpers.h b/Engine/Source/ThirdParty/PhysX/NvCloth/src/scalar/SwCollisionHelpers.h index 36df5d8462f7..5c741b1d4619 100644 --- a/Engine/Source/ThirdParty/PhysX/NvCloth/src/scalar/SwCollisionHelpers.h +++ b/Engine/Source/ThirdParty/PhysX/NvCloth/src/scalar/SwCollisionHelpers.h @@ -29,7 +29,7 @@ #pragma once -namespace physx +namespace nv { namespace cloth { diff --git a/Engine/Source/ThirdParty/PhysX/NvCloth/test/CmakeGenerateAll.bat b/Engine/Source/ThirdParty/PhysX/NvCloth/test/CmakeGenerateAll.bat index f5558b5440c6..4765c770d852 100644 --- a/Engine/Source/ThirdParty/PhysX/NvCloth/test/CmakeGenerateAll.bat +++ b/Engine/Source/ThirdParty/PhysX/NvCloth/test/CmakeGenerateAll.bat @@ -11,5 +11,6 @@ echo CMAKE_PATH_F = %CMAKE_PATH_F% SET PATH=%PATH%;"%CMAKE_PATH_F%" call CmakeGenerateProjects.bat call CmakeGenerateProjectsPs4.bat +call CmakeGenerateProjectsSwitch.bat call CmakeGenerateProjectsXboxOne.bat pause \ No newline at end of file diff --git a/Engine/Source/ThirdParty/PhysX/NvCloth/test/CmakeGenerateProjectsSwitch.bat b/Engine/Source/ThirdParty/PhysX/NvCloth/test/CmakeGenerateProjectsSwitch.bat new file mode 100644 index 000000000000..52e5d0d2f167 --- /dev/null +++ b/Engine/Source/ThirdParty/PhysX/NvCloth/test/CmakeGenerateProjectsSwitch.bat @@ -0,0 +1,43 @@ +@echo off + +REM Make sure the various variables that we need are set + +IF EXIST %~dp0..\Externals\CMakeModules ( + set GW_DEPS_ROOT=%~dp0..\ +) + +IF NOT DEFINED GW_DEPS_ROOT GOTO GW_DEPS_ROOT_UNDEFINED + +IF EXIST %GW_DEPS_ROOT%\Externals\CMakeModules ( + set CMAKE_MODULE_PATH=%GW_DEPS_ROOT%\Externals\CMakeModules +) ELSE ( + set CMAKE_MODULE_PATH=%GW_DEPS_ROOT%\sw\physx\tools\CMakeModules +) + +set PX_OUTPUT_ROOT=%~dp0 + +REM Generate projects here + +rmdir /s /q compiler\vc14switch-cmake\ +mkdir compiler\vc14switch-cmake\ +pushd compiler\vc14switch-cmake\ +cmake ..\cmake\switch -G "Visual Studio 14 2015" -DTARGET_BUILD_PLATFORM=SWITCH -DPX_OUTPUT_LIB_DIR=%PX_OUTPUT_ROOT%\Lib\vc14switch-cmake -DCMAKE_TOOLCHAIN_FILE="%CMAKE_MODULE_PATH%\switch\SwitchToolchain.txt" -DCMAKE_GENERATOR_PLATFORM=SWITCH +popd + +GOTO :End + +:GW_DEPS_ROOT_UNDEFINED +ECHO GW_DEPS_ROOT has to be defined, pointing to the root of the dependency tree. +PAUSE +GOTO END + +:BOOST_ROOT_UNDEFINED +ECHO BOOST_ROOT has to be defined, pointing to the root of your local Boost install. +PAUSE +GOTO END + +:CUDA_ROOT_UNDEFINED +ECHO CUDA_BIN_PATH has to be defined, pointing to the bin folder of your local CUDA install. +PAUSE + +:End diff --git a/Engine/Source/ThirdParty/PhysX/NvCloth/test/_____GenerateAll.bat b/Engine/Source/ThirdParty/PhysX/NvCloth/test/_____GenerateAll.bat index 8444ed558b8b..3df45751f1fa 100644 --- a/Engine/Source/ThirdParty/PhysX/NvCloth/test/_____GenerateAll.bat +++ b/Engine/Source/ThirdParty/PhysX/NvCloth/test/_____GenerateAll.bat @@ -10,5 +10,6 @@ echo CMAKE_PATH_F = %CMAKE_PATH_F% SET PATH=%PATH%;"%CMAKE_PATH_F%" call GenerateProjects.bat call GenerateProjectsPs4.bat +call GenerateProjectsSwitch.bat call GenerateProjectsXboxOne.bat pause \ No newline at end of file diff --git a/Engine/Source/ThirdParty/PhysX/NvCloth/test/compiler/xpj/create_projects.bat b/Engine/Source/ThirdParty/PhysX/NvCloth/test/compiler/xpj/create_projects.bat index 26ad75577c9c..2728a71928da 100644 --- a/Engine/Source/ThirdParty/PhysX/NvCloth/test/compiler/xpj/create_projects.bat +++ b/Engine/Source/ThirdParty/PhysX/NvCloth/test/compiler/xpj/create_projects.bat @@ -17,6 +17,7 @@ rem set GOOGLETEST=..\..\..\..\..\..\..\physx\externals\GoogleTest\gtest-1.4.0 "%XPJ%\xpj4.exe" -t vc14 -p win32 -x "%CD%\NvClothUnitTests.xpj" "%XPJ%\xpj4.exe" -t vc14 -p xboxone -x "%CD%\NvClothUnitTests.xpj" "%XPJ%\xpj4.exe" -t vc14 -p ps4 -x "%CD%\NvClothUnitTests.xpj" +"%XPJ%\xpj4.exe" -t vc14 -p switch -x "%CD%\NvClothUnitTests.xpj" call "../GetFoundationDLLs.bat" diff --git a/Engine/Source/ThirdParty/PhysX/PhysX.Build.cs b/Engine/Source/ThirdParty/PhysX/PhysX.Build.cs index 81b0e6bc132a..bf84fc170a4d 100644 --- a/Engine/Source/ThirdParty/PhysX/PhysX.Build.cs +++ b/Engine/Source/ThirdParty/PhysX/PhysX.Build.cs @@ -280,7 +280,7 @@ public class PhysX : ModuleRules string[] StaticLibrariesAndroid = new string[] { "PhysX3{0}", "PhysX3Extensions{0}", - // "PhysX3Cooking{0}", // not needed until Apex + "PhysX3Cooking{0}", // not needed until Apex "PhysX3Common{0}", //"PhysXVisualDebuggerSDK{0}", "PxFoundation{0}", diff --git a/Engine/Source/ThirdParty/PhysX/PhysXCookingLib.Build.cs b/Engine/Source/ThirdParty/PhysX/PhysXCookingLib.Build.cs new file mode 100644 index 000000000000..cf2ab9b0bfb5 --- /dev/null +++ b/Engine/Source/ThirdParty/PhysX/PhysXCookingLib.Build.cs @@ -0,0 +1,163 @@ +// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + +using UnrealBuildTool; +using System; +using System.IO; + +public class PhysXCookingLib : ModuleRules +{ + enum PhysXLibraryMode + { + Debug, + Profile, + Checked, + Shipping + } + + PhysXLibraryMode GetPhysXLibraryMode(UnrealTargetConfiguration Config) + { + switch (Config) + { + case UnrealTargetConfiguration.Debug: + if (BuildConfiguration.bDebugBuildsActuallyUseDebugCRT) + { + return PhysXLibraryMode.Debug; + } + else + { + return PhysXLibraryMode.Checked; + } + case UnrealTargetConfiguration.Shipping: + case UnrealTargetConfiguration.Test: + return PhysXLibraryMode.Shipping; + case UnrealTargetConfiguration.Development: + case UnrealTargetConfiguration.DebugGame: + case UnrealTargetConfiguration.Unknown: + default: + if (BuildConfiguration.bUseShippingPhysXLibraries) + { + return PhysXLibraryMode.Shipping; + } + else if (BuildConfiguration.bUseCheckedPhysXLibraries) + { + return PhysXLibraryMode.Checked; + } + else + { + return PhysXLibraryMode.Profile; + } + } + } + + static string GetPhysXLibrarySuffix(PhysXLibraryMode Mode) + { + switch (Mode) + { + case PhysXLibraryMode.Debug: + return "DEBUG"; + case PhysXLibraryMode.Checked: + return "CHECKED"; + case PhysXLibraryMode.Profile: + return "PROFILE"; + case PhysXLibraryMode.Shipping: + default: + return ""; + } + } + + public PhysXCookingLib(ReadOnlyTargetRules Target) : base(Target) + { + Type = ModuleType.External; + + // Determine which kind of libraries to link against + PhysXLibraryMode LibraryMode = GetPhysXLibraryMode(Target.Configuration); + string LibrarySuffix = GetPhysXLibrarySuffix(LibraryMode); + + string PhysXLibDir = UEBuildConfiguration.UEThirdPartySourceDirectory + "PhysX/Lib/"; + + // Libraries and DLLs for windows platform + if (Target.Platform == UnrealTargetPlatform.Win64) + { + PublicAdditionalLibraries.Add(String.Format("PhysX3Cooking{0}_x64.lib", LibrarySuffix)); + PublicDelayLoadDLLs.Add(String.Format("PhysX3Cooking{0}_x64.dll", LibrarySuffix)); + + string PhysXBinariesDir = String.Format("$(EngineDir)/Binaries/ThirdParty/PhysX/Win64/VS{0}/", WindowsPlatform.GetVisualStudioCompilerVersionName()); + string FileName = PhysXBinariesDir + String.Format("PhysX3Cooking{0}_x64.dll", LibrarySuffix); + RuntimeDependencies.Add(FileName, StagedFileType.NonUFS); + RuntimeDependencies.Add(Path.ChangeExtension(FileName, ".pdb"), StagedFileType.DebugNonUFS); + } + else if (Target.Platform == UnrealTargetPlatform.Win32 || (Target.Platform == UnrealTargetPlatform.HTML5 && Target.Architecture == "-win32")) + { + PublicAdditionalLibraries.Add(String.Format("PhysX3Cooking{0}_x86.lib", LibrarySuffix)); + PublicDelayLoadDLLs.Add(String.Format("PhysX3Cooking{0}_x86.dll", LibrarySuffix)); + + string PhysXBinariesDir = String.Format("$(EngineDir)/Binaries/ThirdParty/PhysX/Win32/VS{0}/", WindowsPlatform.GetVisualStudioCompilerVersionName()); + string FileName = PhysXBinariesDir + String.Format("PhysX3Cooking{0}_x86.dll", LibrarySuffix); + RuntimeDependencies.Add(FileName, StagedFileType.NonUFS); + RuntimeDependencies.Add(Path.ChangeExtension(FileName, ".pdb"), StagedFileType.DebugNonUFS); + } + else if (Target.Platform == UnrealTargetPlatform.Mac) + { + string PhysXBinariesDir = UEBuildConfiguration.UEThirdPartyBinariesDirectory + "PhysX/Mac/"; + string LibraryPath = PhysXBinariesDir + String.Format("libPhysX3Cooking{0}.dylib", LibrarySuffix); + + PublicDelayLoadDLLs.Add(LibraryPath); + RuntimeDependencies.Add(new RuntimeDependency(LibraryPath)); + } + else if (Target.Platform == UnrealTargetPlatform.Android) + { + PublicAdditionalLibraries.Add(String.Format("PhysX3Cooking{0}", LibrarySuffix)); + } + else if (Target.Platform == UnrealTargetPlatform.Linux) + { + PublicAdditionalLibraries.Add(String.Format("PhysX3Cooking{0}", LibrarySuffix)); + } + else if (Target.Platform == UnrealTargetPlatform.IOS) + { + PhysXLibDir = Path.Combine(PhysXLibDir, "IOS/"); + PublicAdditionalLibraries.Add("PhysX3Cooking" + LibrarySuffix); + PublicAdditionalShadowFiles.Add(Path.Combine(PhysXLibDir, "libPhysX3Cooking" + LibrarySuffix + ".a")); + } + else if (Target.Platform == UnrealTargetPlatform.TVOS) + { + PhysXLibDir = Path.Combine(PhysXLibDir, "TVOS/"); + PublicAdditionalLibraries.Add("PhysX3Cooking" + LibrarySuffix); + PublicAdditionalShadowFiles.Add(Path.Combine(PhysXLibDir, "libPhysX3Cooking" + LibrarySuffix + ".a")); + } + else if (Target.Platform == UnrealTargetPlatform.HTML5) + { + PhysXLibDir = Path.Combine(PhysXLibDir, "HTML5/"); + string OpimizationSuffix = ""; + if (UEBuildConfiguration.bCompileForSize) + { + OpimizationSuffix = "_Oz"; + } + else + { + if (Target.Configuration == UnrealTargetConfiguration.Development) + { + OpimizationSuffix = "_O2"; + } + else if (Target.Configuration == UnrealTargetConfiguration.Shipping) + { + OpimizationSuffix = "_O3"; + } + } + + PublicAdditionalLibraries.Add(PhysXLibDir + "PhysX3Cooking" + OpimizationSuffix + ".bc"); + + } + else if (Target.Platform == UnrealTargetPlatform.PS4) + { + PublicAdditionalLibraries.Add(String.Format("PhysX3Cooking{0}", LibrarySuffix)); + } + else if (Target.Platform == UnrealTargetPlatform.XboxOne) + { + PublicAdditionalLibraries.Add(String.Format("PhysX3Cooking{0}.lib", LibrarySuffix)); + } + else if (Target.Platform == UnrealTargetPlatform.Switch) + { + PublicAdditionalLibraries.Add("PhysX3Cooking" + LibrarySuffix); + } + } +} diff --git a/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/Common/src/CmUtils.h b/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/Common/src/CmUtils.h index 4aa126c15613..e7bccbbd23f4 100644 --- a/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/Common/src/CmUtils.h +++ b/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/Common/src/CmUtils.h @@ -136,7 +136,7 @@ public: PX_ASSERT(&element=mData+mSize); if(mSize==mCapacity) - (owner.*realloc)(mData, mCapacity, mSize, PxU16(mSize+1)); + (owner.*realloc)(mData, mCapacity, mSize, IndexType(mSize+1)); PX_ASSERT(mData && mSizeallocateBounds(); aggregate->computeBounds(mBoundsArray, mContactDistance.begin()); mBoundsArray.begin()[aggregate->mIndex] = aggregate->mBounds; - mUpdatedHandles.pushBack(i); // PT: TODO: BoundsIndex-to-ShapeHandle confusion here + if(!mAddedHandleMap.test(i)) + mUpdatedHandles.pushBack(i); // PT: TODO: BoundsIndex-to-ShapeHandle confusion here } } } diff --git a/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/SimulationController/src/ScNPhaseCore.cpp b/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/SimulationController/src/ScNPhaseCore.cpp index a388dee0fb12..8ed2a5f9909a 100644 --- a/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/SimulationController/src/ScNPhaseCore.cpp +++ b/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/SimulationController/src/ScNPhaseCore.cpp @@ -1453,11 +1453,11 @@ Sc::ActorPair* Sc::NPhaseCore::findActorPair(ShapeSim* s0, ShapeSim* s1, Ps::Int RigidSim* aLess = &s0->getRbSim(); RigidSim* aMore = &s1->getRbSim(); - if(aLess > aMore) + if (aLess->getID() > aMore->getID()) Ps::swap(aLess, aMore); - key.mSim0 = aLess; - key.mSim1 = aMore; + key.mSim0 = aLess->getID(); + key.mSim1 = aMore->getID(); Sc::ActorPair*& actorPair = mActorPairMap[key]; @@ -2211,12 +2211,14 @@ void Sc::NPhaseCore::lostTouchReports(ShapeInteraction* si, PxU32 flags, PxU32 c { RigidSim* sim0 = static_cast(&si->getActor0()); RigidSim* sim1 = static_cast(&si->getActor1()); - if (sim0 > sim1) - Ps::swap(sim0, sim1); BodyPairKey pair; - pair.mSim0 = sim0; - pair.mSim1 = sim1; + + if (sim0->getID() > sim1->getID()) + Ps::swap(sim0, sim1); + + pair.mSim0 = sim0->getID(); + pair.mSim1 = sim1->getID(); mActorPairMap.erase(pair); @@ -2283,16 +2285,11 @@ void Sc::NPhaseCore::clearContactReportActorPairs(bool shrinkToZero) } else { - - RigidSim* sim0 = &aPair->getActorA(); - RigidSim* sim1 = &aPair->getActorB(); - - if(sim0 > sim1) - Ps::swap(sim0, sim1); - BodyPairKey pair; - pair.mSim0 = sim0; - pair.mSim1 = sim1; + PxU32 actorAID = aPair->getActorAID(); + PxU32 actorBID = aPair->getActorBID(); + pair.mSim0 = PxMin(actorAID, actorBID); + pair.mSim1 = PxMax(actorAID, actorBID); mActorPairMap.erase(pair); destroyActorPairReport(*aPair); diff --git a/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/SimulationController/src/ScNPhaseCore.h b/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/SimulationController/src/ScNPhaseCore.h index 1c1780189346..427dd32301a1 100644 --- a/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/SimulationController/src/ScNPhaseCore.h +++ b/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/SimulationController/src/ScNPhaseCore.h @@ -119,8 +119,8 @@ namespace Sc struct BodyPairKey { - RigidSim* mSim0; - RigidSim* mSim1; + PxU32 mSim0; + PxU32 mSim1; bool operator == (const BodyPairKey& pair) const { return mSim0 == pair.mSim0 && mSim1 == pair.mSim1; } }; @@ -129,12 +129,8 @@ namespace Sc PX_INLINE PxU32 hash(const BodyPairKey& key) { - PxU32 add0 = (size_t(key.mSim0))&0xFFFFFFFF; - PxU32 add1 = (size_t(key.mSim1))&0xFFFFFFFF; - - //Clear the lower 2 bits, they will be 0s anyway - add0 = add0 >> 2; - add1 = add1 >> 2; + PxU32 add0 = key.mSim0; + PxU32 add1 = key.mSim1; PxU32 base = PxU32((add0 & 0xFFFF) | (add1 << 16)); diff --git a/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/SimulationController/src/ScScene.cpp b/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/SimulationController/src/ScScene.cpp index fc637d99456f..86deff2ba6e3 100644 --- a/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/SimulationController/src/ScScene.cpp +++ b/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/SimulationController/src/ScScene.cpp @@ -6424,6 +6424,24 @@ void Sc::Scene::finishBroadPhase(PxU32 ccdPass, PxBaseTask* continuation) { PX_PROFILE_ZONE("Sim.processNewOverlaps", getContextId()); + + { + //KS - these functions call "registerInActors", while OverlapFilterTask reads the list of interactions + //in an actor. This could lead to a race condition and a crash if they occur at the same time, so we + //serialize these operations + PX_PROFILE_ZONE("Sim.processNewOverlaps.createOverlapsNoShapeInteractions", getContextId()); + for (PxU32 i = Bp::VolumeBuckets::ePARTICLE; i < Bp::VolumeBuckets::eCOUNT; ++i) + { + + PxU32 createdOverlapCount; + const Bp::AABBOverlap* PX_RESTRICT p = aabbMgr->getCreatedOverlaps(i, createdOverlapCount); + + + mLLContext->getSimStats().mNbNewPairs += createdOverlapCount; + mNPhaseCore->onOverlapCreated(p, createdOverlapCount, ccdPass, bpPairs); + } + } + { PxU32 createdOverlapCount; @@ -6465,19 +6483,7 @@ void Sc::Scene::finishBroadPhase(PxU32 ccdPass, PxBaseTask* continuation) mPreallocateContactManagers.removeReference(); - { - PX_PROFILE_ZONE("Sim.processNewOverlaps.createOverlapsNoShapeInteractions", getContextId()); - for (PxU32 i = Bp::VolumeBuckets::ePARTICLE; i < Bp::VolumeBuckets::eCOUNT; ++i) - { - - PxU32 createdOverlapCount; - const Bp::AABBOverlap* PX_RESTRICT p = aabbMgr->getCreatedOverlaps(i, createdOverlapCount); - - - mLLContext->getSimStats().mNbNewPairs += createdOverlapCount; - mNPhaseCore->onOverlapCreated(p, createdOverlapCount, ccdPass, bpPairs); - } - } + } } diff --git a/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/compiler/cmake/Android/CMakeLists.txt b/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/compiler/cmake/Android/CMakeLists.txt index ccb0461a51e2..c86421ae04c1 100644 --- a/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/compiler/cmake/Android/CMakeLists.txt +++ b/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/compiler/cmake/Android/CMakeLists.txt @@ -62,7 +62,7 @@ INCLUDE(LowLevelParticles.cmake) INCLUDE(PhysX.cmake) #INCLUDE(PhysXCharacterKinematic.cmake) INCLUDE(PhysXCommon.cmake) -#INCLUDE(PhysXCooking.cmake) +INCLUDE(PhysXCooking.cmake) INCLUDE(PhysXExtensions.cmake) INCLUDE(PhysXVehicle.cmake) INCLUDE(SceneQuery.cmake) diff --git a/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/compiler/cmake/Linux/CMakeLists.txt b/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/compiler/cmake/Linux/CMakeLists.txt index 3fa147b439fa..3b85eeb52136 100644 --- a/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/compiler/cmake/Linux/CMakeLists.txt +++ b/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/compiler/cmake/Linux/CMakeLists.txt @@ -42,12 +42,7 @@ SET(CMAKE_CXX_FLAGS_RELEASE "-O3 -g -gdwarf-3") # Controls PX_NVTX for all projects on linux SET(PHYSX_LINUX_ENABLE_NVTX 0) -IF(DEFINED PX_GENERATE_GPU_PROJECTS) SET(PHYSX_LINUX_COMPILE_DEFS ) -ELSE() -# Disable cuda and dx for all projects on linux -SET(PHYSX_LINUX_COMPILE_DEFS DISABLE_CUDA_PHYSX) -ENDIF() SET(PHYSX_LINUX_DEBUG_COMPILE_DEFS _DEBUG;PX_DEBUG=1;PX_CHECKED=1;PX_NVTX=${PHYSX_LINUX_ENABLE_NVTX};PX_SUPPORT_PVD=1) SET(PHYSX_LINUX_CHECKED_COMPILE_DEFS NDEBUG;PX_CHECKED=1;PX_NVTX=${PHYSX_LINUX_ENABLE_NVTX};PX_SUPPORT_PVD=1) SET(PHYSX_LINUX_PROFILE_COMPILE_DEFS NDEBUG;PX_PROFILE=1;PX_NVTX=${PHYSX_LINUX_ENABLE_NVTX};PX_SUPPORT_PVD=1) diff --git a/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/compiler/cmake/html5/CMakeLists.txt b/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/compiler/cmake/html5/CMakeLists.txt index 7270ab9d4b3a..b6aacc00f8cb 100644 --- a/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/compiler/cmake/html5/CMakeLists.txt +++ b/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/compiler/cmake/html5/CMakeLists.txt @@ -13,7 +13,7 @@ IF (NOT ${TARGET_BUILD_PLATFORM} IN_LIST PLATFORM_LIST) MESSAGE(FATAL_ERROR "Invalid platform:" ${TARGET_BUILD_PLATFORM}) ENDIF() -SET(CMAKE_CXX_FLAGS "${EPIC_BUILD_FLAGS} -fdiagnostics-show-option -fno-rtti -fno-exceptions -ffast-math -ffunction-sections -fdata-sections -Werror -ferror-limit=0 -Wall -Wextra -fstrict-aliasing -Wstrict-aliasing=2 -pedantic -Weverything -Wno-c++11-long-long -Wno-padded -Wno-reserved-id-macro -Wno-float-equal -Wno-sign-conversion -Wno-covered-switch-default -Wno-documentation-unknown-command -Wno-weak-vtables -Wno-missing-prototypes -Wno-unused-local-typedef -Wno-float-conversion -Wno-global-constructors -Wno-missing-variable-declarations -Wno-exit-time-destructors -Wno-unused-macros -Wno-undef -Wno-c++11-extra-semi -Wno-c++11-extensions -Wno-non-virtual-dtor -Wno-unknown-pragmas -Wno-old-style-cast -Wno-extra-semi -Wno-cast-align -Wno-documentation -Wno-shadow -Wno-conversion -Wno-newline-eof -Wno-header-hygiene -Wno-switch-enum -Wno-undefined-reinterpret-cast -Wno-variadic-macros -Wno-gnu-zero-variadic-macro-arguments -Wno-overloaded-virtual -Wno-dynamic-class-memaccess -Wno-nested-anon-types -Wno-invalid-offsetof -Wno-reorder -Wno-local-type-template-args -Wno-unreachable-code -Wno-unreachable-code-return -Wno-format-pedantic -Wno-unused-private-field -Wno-unused-parameter -Wno-unused-member-function -Wno-used-but-marked-unused -Wno-unused-variable -Wno-format-nonliteral -Wno-shift-sign-overflow -Wno-comma -Wno-expansion-to-defined -Wno-undefined-func-template -Wno-weak-template-vtables -Wno-double-promotion -Wno-nonportable-include-path -Wno-disabled-macro-expansion -Wno-missing-noreturn") +SET(CMAKE_CXX_FLAGS "${EPIC_BUILD_FLAGS} -fdiagnostics-show-option -fno-rtti -fno-exceptions -ffast-math -ffunction-sections -fdata-sections -Werror -ferror-limit=0 -Wall -Wextra -fstrict-aliasing -Wstrict-aliasing=2 -pedantic -Weverything -Wno-c++11-long-long -Wno-padded -Wno-reserved-id-macro -Wno-float-equal -Wno-sign-conversion -Wno-covered-switch-default -Wno-documentation-unknown-command -Wno-weak-vtables -Wno-missing-prototypes -Wno-unused-local-typedef -Wno-float-conversion -Wno-global-constructors -Wno-missing-variable-declarations -Wno-exit-time-destructors -Wno-unused-macros -Wno-undef -Wno-c++11-extra-semi -Wno-c++11-extensions -Wno-non-virtual-dtor -Wno-unknown-pragmas -Wno-old-style-cast -Wno-extra-semi -Wno-cast-align -Wno-documentation -Wno-shadow -Wno-conversion -Wno-newline-eof -Wno-header-hygiene -Wno-switch-enum -Wno-undefined-reinterpret-cast -Wno-variadic-macros -Wno-gnu-zero-variadic-macro-arguments -Wno-overloaded-virtual -Wno-dynamic-class-memaccess -Wno-nested-anon-types -Wno-invalid-offsetof -Wno-reorder -Wno-local-type-template-args -Wno-unreachable-code -Wno-unreachable-code-return -Wno-format-pedantic -Wno-unused-private-field -Wno-unused-parameter -Wno-unused-member-function -Wno-used-but-marked-unused -Wno-unused-variable -Wno-format-nonliteral -Wno-shift-sign-overflow -Wno-comma -Wno-expansion-to-defined -Wno-undefined-func-template -Wno-weak-template-vtables -Wno-double-promotion -Wno-nonportable-include-path -Wno-disabled-macro-expansion -Wno-missing-noreturn -Wno-dollar-in-identifier-extension") SET(CMAKE_STATIC_LIBRARY_PREFIX "") SET(PHYSX_HTML5_COMPILE_DEFS _LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;PX_PHYSX_STATIC_LIB) diff --git a/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/compiler/cmake/windows/CMakeLists.txt b/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/compiler/cmake/windows/CMakeLists.txt index 53aff0274e3f..3629d4dc8ec6 100644 --- a/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/compiler/cmake/windows/CMakeLists.txt +++ b/Engine/Source/ThirdParty/PhysX/PhysX_3.4/Source/compiler/cmake/windows/CMakeLists.txt @@ -37,12 +37,7 @@ ENDIF(CMAKE_CL_64) # Controls PX_NVTX for all projects on windows SET(PHYSX_WINDOWS_ENABLE_NVTX 0) -IF(DEFINED PX_GENERATE_GPU_PROJECTS) SET(PHYSX_WINDOWS_COMPILE_DEFS WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_WINSOCK_DEPRECATED_NO_WARNINGS) -ELSE() -# Disable cuda and dx for all projects on windows -SET(PHYSX_WINDOWS_COMPILE_DEFS DISABLE_CUDA_PHYSX;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_WINSOCK_DEPRECATED_NO_WARNINGS) -ENDIF() SET(PHYSX_WINDOWS_DEBUG_COMPILE_DEFS _DEBUG;PX_DEBUG=1;PX_CHECKED=1;PX_NVTX=${PHYSX_WINDOWS_ENABLE_NVTX};PX_SUPPORT_PVD=1) SET(PHYSX_WINDOWS_CHECKED_COMPILE_DEFS NDEBUG;PX_CHECKED=1;PX_NVTX=${PHYSX_WINDOWS_ENABLE_NVTX};PX_SUPPORT_PVD=1) SET(PHYSX_WINDOWS_PROFILE_COMPILE_DEFS NDEBUG;PX_PROFILE=1;PX_NVTX=${PHYSX_WINDOWS_ENABLE_NVTX};PX_SUPPORT_PVD=1) diff --git a/Engine/Source/ThirdParty/PhysX/PxShared/include/foundation/PxSimpleTypes.h b/Engine/Source/ThirdParty/PhysX/PxShared/include/foundation/PxSimpleTypes.h index 6ecba13e5e9d..0587151fd9e3 100644 --- a/Engine/Source/ThirdParty/PhysX/PxShared/include/foundation/PxSimpleTypes.h +++ b/Engine/Source/ThirdParty/PhysX/PxShared/include/foundation/PxSimpleTypes.h @@ -56,7 +56,7 @@ #if PX_VC // we could use inttypes.h starting with VC12 #define PX_PRIu64 "I64u" #else -#if !PX_PS4 && !PX_APPLE_FAMILY +#if !PX_PS4 && !PX_APPLE_FAMILY && !PX_NX #define __STDC_FORMAT_MACROS #endif #include diff --git a/Engine/Source/ThirdParty/SDL2/SDL-gui-backend/src/video/x11/SDL_x11vulkan.c b/Engine/Source/ThirdParty/SDL2/SDL-gui-backend/src/video/x11/SDL_x11vulkan.c index 632c882c9415..1a3fed993064 100644 --- a/Engine/Source/ThirdParty/SDL2/SDL-gui-backend/src/video/x11/SDL_x11vulkan.c +++ b/Engine/Source/ThirdParty/SDL2/SDL-gui-backend/src/video/x11/SDL_x11vulkan.c @@ -6,7 +6,7 @@ #include "SDL_assert.h" #include "SDL_x11vulkan.h" -#define DEFAULT_VULKAN "libvulkan.so" +#define DEFAULT_VULKAN "libvulkan.so.1" #define VULKAN_REQUIRES_DLOPEN #if defined(VULKAN_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN) #include diff --git a/Engine/Source/ThirdParty/Windows/DX12/DX12.Build.cs b/Engine/Source/ThirdParty/Windows/DX12/DX12.Build.cs index e19b2bd468f0..12c29ad75ae9 100644 --- a/Engine/Source/ThirdParty/Windows/DX12/DX12.Build.cs +++ b/Engine/Source/ThirdParty/Windows/DX12/DX12.Build.cs @@ -13,7 +13,11 @@ public class DX12 : ModuleRules if (Target.Platform == UnrealTargetPlatform.Win64) { PublicLibraryPaths.Add(DirectXSDKDir + "/Lib/x64"); - } + + PublicDelayLoadDLLs.Add("WinPixEventRuntime.dll"); + PublicAdditionalLibraries.Add("WinPixEventRuntime.lib"); + RuntimeDependencies.Add(new RuntimeDependency("$(EngineDir)/Binaries/ThirdParty/Windows/DirectX/x64/WinPixEventRuntime.dll")); + } else if (Target.Platform == UnrealTargetPlatform.Win32) { PublicLibraryPaths.Add(DirectXSDKDir + "/Lib/x86"); diff --git a/Engine/Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/glsl_types.cpp b/Engine/Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/glsl_types.cpp index 4ec3e1d17cac..e73cfb5b58c0 100644 --- a/Engine/Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/glsl_types.cpp +++ b/Engine/Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/glsl_types.cpp @@ -537,6 +537,7 @@ const glsl_type * glsl_type::get_templated_instance(const glsl_type *base, const hash_table_insert(sampler_types, new glsl_type(GLSL_SAMPLER_DIM_1D, /*shadow=*/ false, /*array=*/ false, /*multisample=*/ false, /*samples=*/ 0, /*sampler_buffer=*/ false, /*type=*/ NULL, "sampler1D", "texture1d"), "Texture1D"); hash_table_insert(sampler_types, new glsl_type(GLSL_SAMPLER_DIM_1D, /*shadow=*/ false, /*array=*/ true, /*multisample=*/ false, /*samples=*/ 0, /*sampler_buffer=*/ false, /*type=*/ NULL, "sampler1DArray", nullptr), "Texture1DArray"); hash_table_insert(sampler_types, new glsl_type(GLSL_SAMPLER_DIM_2D, /*shadow=*/ false, /*array=*/ false, /*multisample=*/ false, /*samples=*/ 0, /*sampler_buffer=*/ false, /*type=*/ NULL, "sampler2D", "texture2d"), "Texture2D"); + hash_table_insert(sampler_types, new glsl_type(GLSL_SAMPLER_DIM_2D, /*shadow=*/ false, /*array=*/ false, /*multisample=*/ false, /*samples=*/ 0, /*sampler_buffer=*/ false, /*type=*/ NULL, "samplerExternalOES", "texture2d"), "TextureExternal"); hash_table_insert(sampler_types, new glsl_type(GLSL_SAMPLER_DIM_2D, /*shadow=*/ false, /*array=*/ true, /*multisample=*/ false, /*samples=*/ 0, /*sampler_buffer=*/ false, /*type=*/ NULL, "sampler2DArray", nullptr), "Texture2DArray"); hash_table_insert(sampler_types, new glsl_type(GLSL_SAMPLER_DIM_2D, /*shadow=*/ false, /*array=*/ false, /*multisample=*/ true, /*samples=*/ 0, /*sampler_buffer=*/ false, /*type=*/ NULL, "sampler2DMS", nullptr), "Texture2DMS"); hash_table_insert(sampler_types, new glsl_type(GLSL_SAMPLER_DIM_2D, /*shadow=*/ false, /*array=*/ true, /*multisample=*/ true, /*samples=*/ 0, /*sampler_buffer=*/ false, /*type=*/ NULL, "sampler2DMSArray", nullptr), "Texture2DMSArray"); diff --git a/Engine/Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.inl b/Engine/Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.inl index 2a16f7d69621..33206c8e5bfe 100644 --- a/Engine/Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.inl +++ b/Engine/Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.inl @@ -349,8 +349,8 @@ static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner ); *yy_cp = '\0'; \ yyg->yy_c_buf_p = yy_cp; -#define YY_NUM_RULES 226 -#define YY_END_OF_BUFFER 227 +#define YY_NUM_RULES 227 +#define YY_END_OF_BUFFER 228 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -358,110 +358,111 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static yyconst flex_int16_t yy_accept[930] = +static yyconst flex_int16_t yy_accept[938] = { 0, - 0, 0, 14, 14, 0, 0, 227, 225, 1, 19, - 225, 225, 225, 225, 225, 225, 225, 225, 225, 126, - 124, 225, 225, 225, 224, 224, 224, 224, 224, 224, - 224, 224, 224, 225, 224, 224, 224, 224, 224, 224, - 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, - 224, 224, 224, 225, 1, 225, 226, 14, 18, 226, - 17, 15, 16, 12, 11, 1, 109, 0, 127, 117, - 110, 120, 114, 104, 116, 105, 123, 129, 115, 130, - 126, 0, 0, 132, 126, 0, 124, 124, 112, 106, - 108, 107, 113, 224, 224, 224, 224, 224, 224, 224, + 0, 0, 14, 14, 0, 0, 228, 226, 1, 19, + 226, 226, 226, 226, 226, 226, 226, 226, 226, 127, + 125, 226, 226, 226, 225, 225, 225, 225, 225, 225, + 225, 225, 225, 226, 225, 225, 225, 225, 225, 225, + 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, + 225, 225, 225, 226, 1, 226, 227, 14, 18, 227, + 17, 15, 16, 12, 11, 1, 110, 0, 128, 118, + 111, 121, 115, 105, 117, 106, 124, 130, 116, 131, + 127, 0, 0, 133, 127, 0, 125, 125, 113, 107, + 109, 108, 114, 225, 225, 225, 225, 225, 225, 225, - 224, 224, 224, 121, 224, 224, 224, 224, 224, 224, - 224, 224, 224, 224, 224, 29, 224, 224, 224, 224, - 224, 224, 224, 224, 224, 224, 224, 33, 224, 224, - 67, 224, 224, 224, 224, 224, 224, 224, 224, 224, - 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, - 224, 224, 224, 224, 224, 224, 122, 111, 1, 0, - 0, 2, 0, 0, 14, 13, 17, 16, 0, 129, - 128, 0, 130, 0, 131, 125, 118, 119, 224, 224, - 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, - 135, 224, 224, 224, 224, 224, 224, 224, 224, 224, + 225, 225, 225, 122, 225, 225, 225, 225, 225, 225, + 225, 225, 225, 225, 225, 29, 225, 225, 225, 225, + 225, 225, 225, 225, 225, 225, 225, 33, 225, 225, + 67, 225, 225, 225, 225, 225, 225, 225, 225, 225, + 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, + 225, 225, 225, 225, 225, 225, 123, 112, 1, 0, + 0, 2, 0, 0, 14, 13, 17, 16, 0, 130, + 129, 0, 131, 0, 132, 126, 119, 120, 225, 225, + 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, + 136, 225, 225, 225, 225, 225, 225, 225, 225, 225, - 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, - 32, 224, 224, 224, 224, 224, 224, 224, 224, 25, - 224, 224, 224, 224, 224, 224, 68, 224, 224, 224, - 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, - 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, - 224, 224, 224, 0, 0, 13, 0, 129, 0, 128, - 0, 130, 131, 125, 224, 224, 224, 224, 224, 224, - 224, 224, 224, 224, 224, 224, 224, 21, 224, 193, - 190, 224, 224, 224, 224, 224, 224, 224, 224, 224, - 224, 31, 138, 224, 224, 224, 224, 224, 224, 143, + 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, + 32, 225, 225, 225, 225, 225, 225, 225, 225, 25, + 225, 225, 225, 225, 225, 225, 68, 225, 225, 225, + 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, + 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, + 225, 225, 225, 0, 0, 13, 0, 130, 0, 129, + 0, 131, 132, 126, 225, 225, 225, 225, 225, 225, + 225, 225, 225, 225, 225, 225, 225, 21, 225, 194, + 191, 225, 225, 225, 225, 225, 225, 225, 225, 225, + 225, 31, 139, 225, 225, 225, 225, 225, 225, 144, - 224, 24, 224, 224, 224, 224, 39, 40, 41, 224, - 224, 58, 154, 224, 224, 224, 224, 224, 224, 224, - 224, 224, 224, 224, 224, 224, 224, 224, 224, 141, - 224, 133, 224, 224, 26, 224, 224, 224, 224, 224, - 103, 224, 224, 0, 0, 0, 128, 224, 224, 224, - 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, - 36, 37, 38, 27, 224, 224, 136, 224, 224, 20, - 224, 224, 224, 224, 224, 134, 224, 157, 22, 224, - 224, 159, 160, 161, 224, 224, 224, 69, 224, 224, - 224, 224, 224, 224, 224, 224, 224, 57, 224, 224, + 225, 24, 225, 225, 225, 225, 39, 40, 41, 225, + 225, 58, 155, 225, 225, 225, 225, 225, 225, 225, + 225, 225, 225, 225, 225, 225, 225, 225, 225, 142, + 225, 134, 225, 225, 26, 225, 225, 225, 225, 225, + 104, 225, 225, 0, 0, 0, 129, 225, 225, 225, + 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, + 36, 37, 38, 27, 225, 225, 137, 225, 225, 20, + 225, 225, 225, 225, 225, 135, 225, 158, 22, 225, + 225, 160, 161, 162, 225, 225, 225, 69, 225, 225, + 225, 225, 225, 225, 225, 225, 225, 57, 225, 225, - 224, 224, 155, 224, 224, 224, 224, 224, 224, 224, - 224, 42, 43, 44, 224, 137, 224, 192, 224, 224, - 30, 0, 0, 81, 224, 224, 224, 224, 224, 224, - 224, 224, 224, 224, 224, 196, 224, 224, 224, 194, - 224, 224, 224, 156, 151, 198, 174, 175, 176, 23, - 45, 46, 47, 224, 224, 224, 224, 224, 224, 224, - 224, 224, 224, 224, 146, 224, 224, 224, 75, 224, - 224, 224, 224, 142, 224, 149, 35, 224, 224, 189, - 150, 101, 144, 224, 224, 224, 224, 224, 224, 224, - 224, 0, 0, 224, 224, 224, 224, 224, 224, 224, + 225, 225, 156, 225, 225, 225, 225, 225, 225, 225, + 225, 42, 43, 44, 225, 138, 225, 193, 225, 225, + 30, 0, 0, 81, 225, 225, 225, 225, 225, 225, + 225, 225, 225, 225, 225, 197, 225, 225, 225, 195, + 225, 225, 225, 157, 152, 199, 175, 176, 177, 23, + 45, 46, 47, 225, 225, 225, 225, 225, 225, 225, + 225, 225, 225, 225, 147, 225, 225, 225, 75, 225, + 225, 225, 225, 143, 225, 150, 35, 225, 225, 190, + 151, 102, 145, 225, 225, 225, 225, 225, 225, 225, + 225, 0, 0, 225, 225, 225, 225, 225, 225, 225, - 224, 224, 224, 224, 102, 224, 224, 224, 145, 34, - 171, 172, 173, 224, 224, 224, 224, 224, 224, 224, - 224, 224, 162, 163, 164, 165, 166, 167, 168, 169, - 170, 224, 224, 224, 224, 224, 199, 200, 201, 224, - 224, 224, 224, 60, 224, 224, 224, 224, 224, 224, - 224, 224, 224, 139, 224, 224, 224, 224, 224, 70, - 224, 71, 224, 0, 0, 0, 224, 224, 224, 224, - 93, 224, 224, 224, 224, 224, 224, 224, 224, 224, - 224, 72, 224, 28, 152, 177, 178, 179, 180, 181, - 182, 183, 184, 185, 48, 49, 50, 51, 52, 53, + 225, 225, 225, 225, 103, 225, 225, 225, 146, 34, + 172, 173, 174, 225, 225, 225, 225, 225, 225, 225, + 225, 225, 163, 164, 165, 166, 167, 168, 169, 170, + 171, 225, 225, 225, 225, 225, 200, 201, 202, 225, + 225, 225, 225, 60, 225, 225, 225, 225, 225, 225, + 225, 225, 225, 140, 225, 225, 225, 225, 225, 70, + 225, 71, 225, 0, 0, 0, 225, 225, 225, 225, + 94, 225, 225, 225, 225, 225, 225, 225, 225, 225, + 225, 225, 72, 225, 28, 153, 178, 179, 180, 181, + 182, 183, 184, 185, 186, 48, 49, 50, 51, 52, - 54, 55, 56, 224, 224, 203, 204, 205, 224, 224, - 224, 224, 224, 224, 224, 224, 224, 224, 224, 147, - 224, 224, 224, 224, 224, 224, 224, 140, 59, 207, - 208, 209, 224, 224, 158, 148, 0, 4, 0, 0, - 0, 10, 224, 224, 224, 224, 224, 224, 224, 224, - 224, 82, 84, 88, 224, 224, 224, 224, 224, 224, - 224, 224, 224, 224, 224, 224, 224, 224, 202, 153, - 73, 191, 224, 224, 195, 79, 224, 224, 224, 224, - 224, 224, 224, 224, 0, 0, 0, 0, 0, 65, - 63, 224, 224, 224, 224, 224, 224, 224, 224, 224, + 53, 54, 55, 56, 225, 225, 204, 205, 206, 225, + 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, + 148, 225, 225, 225, 225, 225, 225, 225, 141, 59, + 208, 209, 210, 225, 225, 159, 149, 0, 4, 0, + 0, 0, 10, 225, 225, 225, 225, 225, 225, 225, + 225, 225, 82, 84, 89, 225, 225, 225, 225, 225, + 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, + 203, 154, 73, 192, 225, 225, 196, 79, 225, 225, + 225, 225, 225, 225, 225, 225, 0, 0, 0, 0, + 0, 65, 63, 225, 225, 225, 225, 225, 225, 225, - 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, - 224, 206, 224, 224, 224, 224, 224, 224, 224, 224, - 224, 224, 224, 224, 224, 224, 210, 0, 0, 0, - 0, 0, 66, 62, 224, 224, 96, 98, 100, 224, - 224, 224, 224, 86, 89, 224, 224, 224, 78, 224, - 224, 224, 224, 224, 224, 224, 221, 224, 224, 224, - 224, 224, 61, 224, 224, 224, 0, 3, 0, 0, - 0, 224, 224, 224, 224, 224, 91, 224, 224, 224, - 224, 224, 80, 224, 224, 224, 222, 211, 224, 212, - 224, 224, 224, 224, 224, 224, 224, 224, 223, 0, + 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, + 225, 225, 225, 225, 207, 225, 225, 225, 225, 225, + 225, 225, 225, 225, 225, 225, 225, 225, 225, 211, + 0, 0, 0, 0, 0, 66, 62, 225, 225, 97, + 99, 101, 225, 225, 225, 225, 87, 90, 225, 225, + 225, 225, 78, 225, 225, 225, 225, 225, 225, 225, + 222, 225, 225, 225, 225, 225, 61, 225, 225, 225, + 0, 3, 0, 0, 0, 225, 225, 225, 225, 225, + 92, 225, 225, 225, 225, 225, 225, 80, 225, 225, + 225, 223, 212, 225, 213, 225, 225, 225, 225, 225, - 0, 0, 224, 224, 224, 224, 224, 224, 224, 224, - 224, 224, 224, 213, 214, 224, 217, 224, 218, 224, - 76, 186, 187, 197, 215, 216, 0, 0, 0, 224, - 224, 224, 224, 224, 83, 85, 224, 224, 64, 224, - 224, 224, 224, 224, 0, 0, 0, 0, 224, 224, - 224, 224, 224, 224, 224, 224, 224, 224, 74, 224, - 0, 0, 0, 0, 224, 224, 97, 99, 224, 87, - 90, 77, 224, 224, 224, 0, 0, 0, 0, 224, - 224, 224, 224, 224, 224, 0, 0, 0, 5, 0, - 0, 224, 94, 224, 219, 220, 224, 0, 0, 6, + 225, 225, 225, 224, 0, 0, 0, 225, 225, 225, + 225, 225, 225, 225, 225, 225, 225, 225, 225, 214, + 215, 225, 218, 225, 219, 225, 76, 187, 188, 198, + 216, 217, 0, 0, 0, 225, 225, 225, 225, 225, + 83, 86, 225, 225, 225, 64, 225, 225, 225, 225, + 225, 0, 0, 0, 0, 225, 225, 225, 225, 225, + 225, 225, 85, 225, 225, 225, 74, 225, 0, 0, + 0, 0, 225, 225, 98, 100, 225, 88, 91, 77, + 225, 225, 225, 0, 0, 0, 0, 225, 225, 225, + 225, 225, 225, 0, 0, 0, 5, 0, 0, 225, - 0, 0, 95, 224, 188, 0, 0, 0, 224, 0, - 0, 0, 7, 224, 0, 0, 8, 92, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 9, 0 + 95, 225, 220, 221, 225, 0, 0, 6, 0, 0, + 96, 225, 189, 0, 0, 0, 225, 0, 0, 0, + 7, 225, 0, 0, 8, 93, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 9, 0 } ; static yyconst flex_int32_t yy_ec[256] = @@ -508,221 +509,223 @@ static yyconst flex_int32_t yy_meta[75] = 4, 4, 4, 1 } ; -static yyconst flex_int16_t yy_base[939] = +static yyconst flex_int16_t yy_base[947] = { 0, - 0, 73, 80, 154, 1274, 1273, 1275, 1278, 74, 1278, - 1248, 1267, 1246, 99, 1245, 96, 97, 95, 1244, 214, - 271, 94, 1243, 102, 0, 1200, 1205, 1209, 1197, 1201, - 1218, 1213, 68, 1235, 73, 14, 81, 79, 75, 133, - 80, 1211, 130, 90, 89, 1191, 134, 132, 149, 155, - 137, 137, 1202, 178, 205, 211, 1278, 146, 1278, 1241, - 221, 1278, 0, 1278, 1278, 147, 1278, 1250, 1278, 1278, - 1278, 1278, 1278, 1278, 1278, 1278, 1278, 278, 1278, 323, - 177, 363, 299, 1278, 1278, 0, 0, 1278, 1229, 1278, - 1278, 1278, 1228, 0, 1199, 1188, 1189, 1183, 1192, 220, + 0, 73, 80, 154, 1282, 1281, 1283, 1286, 74, 1286, + 1256, 1275, 1254, 99, 1253, 96, 97, 95, 1252, 214, + 271, 94, 1251, 102, 0, 1208, 1213, 1217, 1205, 1209, + 1226, 1221, 68, 1243, 73, 14, 81, 79, 75, 133, + 80, 1219, 130, 90, 89, 1199, 134, 132, 149, 155, + 137, 137, 1210, 178, 205, 211, 1286, 146, 1286, 1249, + 221, 1286, 0, 1286, 1286, 147, 1286, 1258, 1286, 1286, + 1286, 1286, 1286, 1286, 1286, 1286, 1286, 278, 1286, 323, + 177, 363, 299, 1286, 1286, 0, 0, 1286, 1237, 1286, + 1286, 1286, 1236, 0, 1207, 1196, 1197, 1191, 1200, 220, - 1187, 1176, 1189, 1278, 1178, 1183, 1180, 1189, 1175, 1172, - 1177, 1189, 164, 1183, 1170, 1167, 1168, 1165, 1165, 1171, - 150, 1167, 1164, 1165, 1160, 1163, 1165, 0, 1163, 1174, - 190, 1160, 1159, 1159, 158, 1152, 200, 1161, 1167, 1149, - 1145, 1153, 1150, 1139, 61, 1154, 1149, 1152, 188, 1144, - 127, 198, 1150, 1141, 209, 1148, 1278, 1278, 270, 303, - 305, 1278, 1147, 1138, 274, 0, 330, 0, 380, 1278, - 387, 408, 1278, 415, 425, 186, 1278, 1278, 1148, 1133, - 1147, 1135, 1136, 211, 1130, 1143, 1131, 1127, 1144, 1135, - 0, 1131, 1141, 217, 1135, 1121, 1121, 1118, 1124, 151, + 1195, 1184, 1197, 1286, 1186, 1191, 1188, 1197, 1183, 1180, + 1185, 1197, 164, 1191, 1178, 1175, 1176, 1173, 1173, 1179, + 150, 1175, 1172, 1173, 1168, 1171, 1173, 0, 1171, 1182, + 190, 1168, 1167, 1167, 158, 1160, 200, 1169, 1175, 1157, + 1153, 1161, 1158, 1147, 61, 1162, 1157, 1160, 188, 1152, + 127, 198, 1158, 1149, 209, 1156, 1286, 1286, 270, 303, + 305, 1286, 1155, 1146, 274, 0, 330, 0, 380, 1286, + 387, 408, 1286, 415, 425, 186, 1286, 1286, 1156, 1141, + 1155, 1143, 1144, 211, 1138, 1151, 1139, 1135, 1152, 1143, + 0, 1139, 1149, 217, 1143, 1129, 1129, 1126, 1132, 151, - 1135, 1132, 1132, 1128, 1119, 1126, 1112, 1110, 1123, 1126, - 0, 1124, 1110, 1104, 1117, 1121, 1114, 1111, 1099, 307, - 1117, 1112, 1109, 1110, 1100, 1108, 0, 1101, 1092, 1096, - 1097, 1088, 1107, 1090, 1088, 1099, 1084, 1082, 1082, 1084, - 1081, 1097, 1092, 1091, 1094, 1075, 260, 1084, 1078, 1067, - 1086, 1088, 1076, 1073, 1085, 0, 432, 442, 463, 1278, - 449, 470, 1278, 1278, 1080, 1065, 1089, 1062, 1062, 1074, - 1060, 1061, 1054, 1064, 1055, 1060, 1052, 314, 1061, 0, - 0, 1065, 1053, 1051, 1055, 1052, 1047, 1056, 1044, 1062, - 1050, 0, 0, 1044, 1055, 1054, 1054, 1038, 1055, 0, + 1143, 1140, 1140, 1136, 1127, 1134, 1120, 1118, 1131, 1134, + 0, 1132, 1118, 1112, 1125, 1129, 1122, 1119, 1107, 307, + 1125, 1120, 1117, 1118, 1108, 1116, 0, 1109, 1100, 1104, + 1105, 1096, 1115, 1098, 1096, 1107, 1092, 1090, 1090, 1092, + 1089, 1105, 1100, 1099, 1102, 1083, 260, 1092, 1086, 1075, + 1094, 1096, 1084, 1081, 1093, 0, 432, 442, 463, 1286, + 449, 470, 1286, 1286, 1088, 1073, 1097, 1070, 1070, 1082, + 1068, 1069, 1062, 1072, 1063, 1068, 1060, 314, 1069, 0, + 0, 1073, 1061, 1059, 1063, 1060, 1055, 1064, 1052, 1070, + 1058, 0, 0, 1052, 1063, 1062, 1062, 1046, 1063, 0, - 1039, 317, 1047, 1048, 1038, 1032, 0, 0, 0, 1033, - 1032, 1047, 0, 1029, 213, 1029, 1040, 1035, 1024, 1033, - 1024, 1027, 1027, 1019, 1022, 1027, 1032, 1031, 1021, 0, - 1018, 0, 1027, 1023, 338, 1014, 1014, 1020, 1019, 1016, - 0, 1005, 1018, 1017, 1014, 487, 494, 1003, 1027, 999, - 998, 1022, 1009, 1009, 993, 993, 1006, 993, 1002, 1003, - 0, 0, 0, 0, 1002, 991, 0, 991, 990, 0, - 989, 990, 984, 995, 985, 0, 981, 351, 369, 985, - 978, 972, 971, 970, 987, 394, 986, 0, 984, 980, - 309, 972, 978, 981, 967, 980, 964, 0, 979, 967, + 1047, 317, 1055, 1056, 1046, 1040, 0, 0, 0, 1041, + 1040, 1055, 0, 1037, 213, 1037, 1048, 1043, 1032, 1041, + 1032, 1035, 1035, 1027, 1030, 1035, 1040, 1039, 1029, 0, + 1026, 0, 1035, 1031, 338, 1022, 1022, 1028, 1027, 1024, + 0, 1013, 1026, 1025, 1022, 487, 494, 1011, 1035, 1007, + 1006, 1030, 1017, 1017, 1001, 1001, 1014, 1001, 1010, 1011, + 0, 0, 0, 0, 1010, 999, 0, 999, 998, 0, + 997, 998, 992, 1003, 993, 0, 989, 351, 369, 993, + 986, 980, 979, 978, 995, 394, 994, 0, 992, 988, + 309, 980, 986, 989, 975, 988, 972, 0, 987, 975, - 979, 974, 0, 972, 974, 957, 967, 973, 966, 967, - 966, 0, 0, 0, 953, 0, 955, 0, 954, 958, - 0, 1012, 952, 0, 963, 946, 970, 942, 955, 979, - 955, 937, 939, 950, 942, 0, 936, 943, 951, 0, - 930, 930, 944, 478, 946, 0, 923, 922, 921, 0, - 920, 919, 918, 928, 931, 481, 499, 502, 510, 955, - 954, 953, 915, 914, 0, 932, 931, 921, 0, 929, - 915, 911, 911, 0, 917, 0, 0, 915, 907, 0, - 0, 0, 0, 904, 910, 915, 513, 907, 914, 911, - 905, 532, 915, 896, 909, 912, 895, 894, 906, 890, + 987, 982, 0, 980, 982, 965, 975, 981, 974, 975, + 974, 0, 0, 0, 961, 0, 963, 0, 962, 966, + 0, 1020, 960, 0, 971, 954, 978, 950, 963, 987, + 963, 945, 947, 958, 950, 0, 944, 951, 959, 0, + 938, 938, 952, 478, 954, 0, 931, 930, 929, 0, + 928, 927, 926, 936, 939, 481, 499, 502, 510, 963, + 962, 961, 923, 922, 0, 940, 939, 929, 0, 937, + 923, 919, 919, 0, 925, 0, 0, 923, 915, 0, + 0, 0, 0, 912, 918, 923, 513, 915, 922, 919, + 913, 532, 923, 904, 917, 920, 903, 902, 914, 898, - 891, 324, 517, 902, 0, 902, 892, 899, 0, 0, - 0, 0, 0, 891, 525, 537, 540, 543, 546, 549, - 878, 900, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 917, 916, 915, 877, 876, 543, 544, 0, 889, - 892, 890, 878, 0, 888, 885, 873, 883, 872, 871, - 554, 880, 879, 0, 900, 899, 898, 860, 859, 0, - 874, 0, 872, 573, 579, 922, 872, 873, 854, 867, - 0, 867, 850, 864, 853, 848, 883, 882, 881, 843, - 868, 0, 860, 0, 0, 0, 0, 0, 0, 0, + 899, 324, 526, 910, 0, 910, 900, 907, 0, 0, + 0, 0, 0, 899, 516, 540, 543, 546, 549, 552, + 886, 908, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 925, 924, 923, 885, 884, 546, 547, 0, 897, + 900, 898, 886, 0, 896, 893, 881, 891, 880, 879, + 557, 888, 887, 0, 908, 907, 906, 868, 867, 0, + 882, 0, 880, 576, 582, 930, 880, 881, 862, 875, + 0, 875, 858, 872, 861, 856, 891, 890, 889, 851, + 847, 875, 0, 867, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 857, 842, 878, 877, 0, 850, 853, - 837, 845, 835, 843, 844, 844, 843, 828, 841, 0, - 830, 841, 829, 825, 858, 857, 819, 0, 837, 857, - 856, 0, 829, 832, 0, 0, 601, 1278, 603, 0, - 609, 606, 825, 819, 828, 829, 812, 811, 559, 814, - 825, 845, 605, 0, 822, 804, 812, 806, 815, 802, - 801, 811, 811, 798, 813, 796, 811, 806, 0, 0, - 0, 0, 798, 790, 0, 0, 815, 814, 800, 801, - 787, 786, 796, 796, 842, 327, 804, 793, 781, 0, - 0, 788, 782, 789, 788, 809, 808, 807, 773, 769, + 0, 0, 0, 0, 864, 849, 885, 884, 0, 857, + 860, 844, 852, 842, 850, 851, 851, 850, 835, 848, + 0, 837, 848, 836, 832, 865, 864, 826, 0, 844, + 864, 863, 0, 836, 839, 0, 0, 604, 1286, 606, + 0, 612, 609, 832, 826, 835, 836, 819, 818, 562, + 821, 832, 852, 519, 0, 829, 811, 810, 818, 812, + 821, 808, 807, 817, 817, 804, 819, 802, 817, 812, + 0, 0, 0, 0, 804, 796, 0, 0, 821, 820, + 806, 807, 793, 792, 802, 802, 848, 327, 810, 799, + 787, 0, 0, 794, 788, 795, 794, 815, 814, 813, - 770, 769, 791, 779, 766, 767, 773, 776, 762, 761, - 772, 0, 775, 771, 773, 769, 755, 770, 761, 764, - 763, 761, 756, 748, 745, 753, 0, 792, 607, 756, - 736, 718, 0, 0, 718, 730, 753, 752, 0, 730, - 724, 711, 710, 746, 745, 719, 706, 717, 0, 720, - 718, 701, 693, 701, 691, 699, 0, 694, 691, 708, - 706, 702, 0, 705, 704, 687, 612, 1278, 227, 213, - 230, 236, 280, 297, 299, 303, 0, 324, 326, 314, - 326, 343, 0, 346, 343, 346, 0, 397, 386, 415, - 403, 417, 425, 427, 428, 460, 454, 466, 0, 504, + 779, 775, 776, 775, 797, 785, 784, 771, 772, 778, + 781, 767, 766, 777, 0, 780, 776, 778, 774, 760, + 775, 766, 769, 768, 764, 756, 741, 730, 741, 0, + 787, 610, 761, 740, 722, 0, 0, 722, 735, 757, + 756, 0, 734, 729, 716, 715, 751, 750, 712, 722, + 709, 720, 0, 723, 722, 705, 697, 705, 695, 702, + 0, 696, 693, 710, 709, 208, 0, 232, 238, 237, + 615, 1286, 275, 294, 307, 302, 344, 310, 314, 326, + 0, 343, 362, 350, 353, 377, 407, 0, 392, 401, + 402, 0, 436, 424, 453, 455, 469, 485, 474, 516, - 525, 523, 558, 520, 524, 551, 560, 562, 563, 571, - 572, 577, 586, 0, 0, 584, 0, 585, 0, 579, - 0, 603, 0, 0, 0, 0, 644, 645, 592, 582, - 597, 603, 604, 588, 0, 0, 607, 608, 0, 597, - 611, 612, 600, 607, 662, 663, 664, 594, 614, 616, - 599, 600, 611, 603, 604, 610, 626, 627, 0, 631, - 619, 680, 629, 631, 631, 633, 0, 0, 625, 0, - 0, 0, 625, 626, 638, 623, 639, 692, 694, 642, - 632, 656, 629, 630, 638, 653, 703, 704, 1278, 706, - 705, 644, 0, 643, 0, 0, 641, 647, 711, 1278, + 522, 518, 519, 0, 555, 564, 559, 607, 569, 573, + 574, 583, 569, 570, 578, 579, 596, 585, 595, 0, + 0, 593, 0, 594, 0, 589, 0, 611, 0, 0, + 0, 0, 652, 653, 599, 589, 604, 610, 611, 596, + 0, 0, 615, 616, 606, 0, 605, 619, 620, 608, + 615, 671, 672, 673, 603, 623, 624, 607, 608, 618, + 611, 612, 0, 618, 634, 635, 0, 639, 627, 688, + 637, 639, 639, 641, 0, 0, 633, 0, 0, 0, + 633, 634, 646, 631, 647, 700, 702, 650, 640, 664, + 637, 638, 646, 661, 711, 712, 1286, 714, 713, 652, - 715, 664, 0, 671, 0, 664, 669, 722, 658, 679, - 727, 728, 1278, 678, 670, 733, 1278, 0, 667, 735, - 738, 734, 739, 682, 686, 745, 747, 1278, 1278, 788, - 792, 796, 798, 800, 747, 804, 748, 808 + 0, 651, 0, 0, 649, 655, 719, 1286, 723, 672, + 0, 678, 0, 672, 677, 730, 666, 686, 735, 736, + 1286, 686, 678, 741, 1286, 0, 675, 743, 746, 742, + 747, 690, 694, 753, 755, 1286, 1286, 796, 800, 804, + 806, 808, 755, 812, 756, 816 } ; -static yyconst flex_int16_t yy_def[939] = +static yyconst flex_int16_t yy_def[947] = { 0, - 929, 1, 930, 930, 931, 931, 929, 929, 929, 929, - 929, 932, 929, 929, 929, 929, 929, 929, 929, 929, - 929, 929, 929, 929, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 929, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 929, 929, 929, 929, 929, 929, 929, - 929, 929, 934, 929, 929, 929, 929, 932, 929, 929, - 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, - 20, 929, 929, 929, 929, 935, 21, 929, 929, 929, - 929, 929, 929, 933, 933, 933, 933, 933, 933, 933, + 937, 1, 938, 938, 939, 939, 937, 937, 937, 937, + 937, 940, 937, 937, 937, 937, 937, 937, 937, 937, + 937, 937, 937, 937, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 937, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 937, 937, 937, 937, 937, 937, 937, + 937, 937, 942, 937, 937, 937, 937, 940, 937, 937, + 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, + 20, 937, 937, 937, 937, 943, 21, 937, 937, 937, + 937, 937, 937, 941, 941, 941, 941, 941, 941, 941, - 933, 933, 933, 929, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 929, 929, 929, 929, - 929, 929, 929, 929, 929, 936, 929, 934, 929, 929, - 929, 929, 929, 929, 929, 935, 929, 929, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, + 941, 941, 941, 937, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 937, 937, 937, 937, + 937, 937, 937, 937, 937, 944, 937, 942, 937, 937, + 937, 937, 937, 937, 937, 943, 937, 937, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 929, 929, 936, 929, 929, 929, 929, - 929, 929, 929, 929, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 937, 937, 944, 937, 937, 937, 937, + 937, 937, 937, 937, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 929, 929, 929, 929, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 937, 937, 937, 937, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 929, 929, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 929, 929, 933, 933, 933, 933, 933, 933, 933, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 937, 937, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 937, 937, 941, 941, 941, 941, 941, 941, 941, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 929, 929, 929, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 937, 937, 937, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 929, 929, 929, 937, - 929, 929, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 938, 937, 929, 929, 929, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 937, 937, 937, + 945, 937, 937, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 946, 945, 937, 937, + 937, 941, 941, 941, 941, 941, 941, 941, 941, 941, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 938, 938, 929, - 929, 929, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 938, 929, 929, 929, - 929, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 929, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 946, 946, 937, 937, 937, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 946, 937, 937, 937, 937, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, - 929, 929, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 933, 929, 929, 929, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 929, 929, 929, 929, 933, 933, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 929, 929, 929, 929, 933, 933, 933, 933, 933, 933, - 933, 933, 933, 933, 933, 929, 929, 929, 929, 933, - 933, 933, 933, 933, 933, 929, 929, 929, 929, 929, - 929, 933, 933, 933, 933, 933, 933, 929, 929, 929, + 941, 941, 941, 941, 937, 937, 937, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 937, 937, 937, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 937, 937, 937, 937, 941, 941, 941, 941, 941, + 941, 941, 941, 941, 941, 941, 941, 941, 937, 937, + 937, 937, 941, 941, 941, 941, 941, 941, 941, 941, + 941, 941, 941, 937, 937, 937, 937, 941, 941, 941, + 941, 941, 941, 937, 937, 937, 937, 937, 937, 941, - 929, 929, 933, 933, 933, 929, 929, 929, 933, 929, - 929, 929, 929, 933, 929, 929, 929, 933, 929, 929, - 929, 929, 929, 929, 929, 929, 929, 929, 0, 929, - 929, 929, 929, 929, 929, 929, 929, 929 + 941, 941, 941, 941, 941, 937, 937, 937, 937, 937, + 941, 941, 941, 937, 937, 937, 941, 937, 937, 937, + 937, 941, 937, 937, 937, 941, 937, 937, 937, 937, + 937, 937, 937, 937, 937, 937, 0, 937, 937, 937, + 937, 937, 937, 937, 937, 937 } ; -static yyconst flex_int16_t yy_nxt[1353] = +static yyconst flex_int16_t yy_nxt[1361] = { 0, 8, 9, 10, 9, 11, 12, 8, 13, 14, 8, 8, 15, 16, 17, 18, 19, 20, 21, 21, 21, @@ -748,134 +751,134 @@ static yyconst flex_int16_t yy_nxt[1353] = 57, 139, 153, 157, 143, 144, 159, 147, 66, 208, 148, 160, 161, 162, 225, 145, 287, 288, 146, 149, - 209, 226, 929, 198, 199, 200, 150, 57, 80, 264, + 209, 226, 937, 198, 199, 200, 150, 57, 80, 264, 81, 81, 81, 81, 81, 81, 82, 167, 167, 167, - 167, 167, 167, 167, 242, 83, 84, 929, 184, 218, + 167, 167, 167, 167, 242, 83, 84, 937, 184, 218, 228, 158, 219, 264, 247, 243, 220, 85, 221, 86, - 800, 185, 186, 248, 229, 251, 83, 84, 252, 280, + 801, 185, 186, 248, 229, 251, 83, 84, 252, 280, 163, 159, 393, 66, 164, 165, 160, 165, 270, 394, - 801, 85, 271, 281, 86, 80, 802, 87, 87, 87, + 802, 85, 271, 281, 86, 80, 803, 87, 87, 87, 87, 87, 87, 87, 78, 78, 78, 78, 78, 78, - 78, 803, 83, 84, 161, 162, 161, 162, 804, 169, + 78, 804, 83, 84, 161, 162, 161, 162, 805, 169, 170, 174, 174, 336, 88, 175, 175, 175, 175, 175, - 175, 175, 337, 83, 84, 307, 308, 309, 637, 638, + 175, 175, 337, 83, 84, 307, 308, 309, 638, 639, 169, 170, 361, 362, 363, 382, 383, 384, 88, 171, 171, 171, 171, 171, 171, 171, 167, 167, 167, 167, 167, 167, 167, 575, 172, 173, 412, 413, 414, 310, - 468, 805, 163, 806, 163, 576, 164, 807, 164, 447, - 448, 449, 808, 469, 809, 172, 173, 80, 810, 82, + 468, 806, 163, 807, 163, 576, 164, 808, 164, 447, + 448, 449, 809, 469, 810, 172, 173, 80, 811, 82, 82, 82, 82, 82, 82, 82, 450, 451, 452, 453, - 811, 812, 257, 257, 83, 84, 258, 258, 258, 258, + 812, 813, 257, 257, 83, 84, 258, 258, 258, 258, 258, 258, 258, 171, 171, 171, 171, 171, 171, 171, - 813, 460, 461, 462, 814, 83, 84, 815, 259, 260, + 814, 460, 461, 462, 815, 83, 84, 816, 259, 260, 261, 261, 463, 464, 262, 262, 262, 262, 262, 262, - 262, 175, 175, 175, 175, 175, 175, 175, 816, 259, + 262, 175, 175, 175, 175, 175, 175, 175, 817, 259, 260, 175, 175, 175, 175, 175, 175, 175, 258, 258, - 258, 258, 258, 258, 258, 817, 818, 263, 258, 258, + 258, 258, 258, 258, 258, 818, 819, 263, 258, 258, 258, 258, 258, 258, 258, 262, 262, 262, 262, 262, - 262, 262, 819, 820, 170, 346, 346, 821, 263, 347, + 262, 262, 820, 821, 170, 346, 346, 822, 263, 347, 347, 347, 347, 347, 347, 347, 262, 262, 262, 262, - 262, 262, 262, 822, 823, 170, 511, 512, 513, 523, + 262, 262, 262, 823, 824, 170, 511, 512, 513, 523, 524, 525, 173, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 526, 527, 528, - 529, 530, 531, 173, 824, 825, 260, 532, 533, 534, - 555, 556, 557, 492, 577, 578, 579, 826, 535, 536, - 827, 558, 559, 586, 587, 588, 580, 260, 564, 565, - 565, 565, 565, 565, 565, 589, 590, 591, 592, 593, - 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, - 611, 613, 625, 626, 637, 638, 696, 697, 698, 828, - 637, 638, 627, 829, 612, 614, 830, 831, 832, 639, - 639, 639, 639, 639, 639, 641, 641, 641, 641, 641, + 529, 530, 531, 173, 825, 826, 260, 532, 533, 534, + 555, 556, 557, 492, 587, 588, 589, 827, 535, 536, + 828, 558, 559, 577, 578, 579, 704, 260, 564, 565, + 565, 565, 565, 565, 565, 580, 705, 581, 590, 591, + 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, + 602, 603, 604, 612, 614, 626, 627, 638, 639, 698, + 699, 700, 829, 638, 639, 628, 830, 613, 615, 831, + 832, 833, 640, 640, 640, 640, 640, 640, 642, 642, - 641, 641, 637, 638, 637, 638, 685, 642, 767, 768, - 637, 638, 729, 767, 768, 833, 834, 729, 640, 639, - 639, 639, 639, 639, 639, 641, 641, 641, 641, 641, - 641, 641, 702, 835, 836, 837, 838, 839, 840, 841, - 842, 843, 703, 640, 844, 845, 846, 687, 848, 849, - 850, 851, 852, 853, 847, 854, 855, 688, 856, 857, - 858, 859, 860, 845, 846, 862, 864, 865, 689, 866, - 867, 868, 847, 869, 870, 871, 872, 873, 874, 875, - 876, 862, 877, 879, 880, 881, 882, 883, 884, 885, - 878, 886, 887, 888, 892, 890, 893, 894, 895, 896, + 642, 642, 642, 642, 642, 638, 639, 638, 639, 687, + 643, 771, 772, 638, 639, 732, 771, 772, 834, 835, + 732, 641, 640, 640, 640, 640, 640, 640, 642, 642, + 642, 642, 642, 642, 642, 836, 837, 838, 839, 840, + 841, 842, 843, 844, 845, 846, 641, 847, 848, 849, + 689, 850, 851, 852, 853, 855, 856, 857, 858, 859, + 690, 860, 854, 861, 862, 863, 864, 865, 866, 867, + 868, 691, 852, 853, 870, 872, 873, 874, 875, 876, + 877, 854, 878, 879, 880, 881, 882, 883, 884, 870, + 885, 887, 888, 889, 890, 891, 892, 893, 886, 894, - 897, 898, 889, 891, 899, 888, 901, 890, 903, 904, - 905, 906, 899, 900, 889, 891, 901, 907, 861, 909, - 910, 900, 911, 912, 914, 908, 863, 915, 916, 912, - 918, 919, 913, 920, 916, 923, 921, 917, 913, 921, - 923, 925, 863, 917, 922, 926, 927, 922, 927, 176, - 686, 799, 798, 797, 796, 928, 795, 928, 794, 793, - 792, 791, 790, 789, 788, 787, 786, 902, 785, 784, - 783, 782, 781, 780, 779, 778, 777, 902, 776, 775, - 774, 773, 924, 772, 771, 770, 769, 924, 63, 63, - 63, 63, 64, 64, 64, 64, 68, 729, 68, 68, + 895, 896, 900, 898, 901, 902, 903, 904, 905, 906, + 897, 899, 907, 896, 909, 898, 911, 912, 913, 914, + 907, 908, 897, 899, 909, 915, 917, 869, 918, 908, + 919, 920, 922, 916, 923, 871, 924, 920, 926, 927, + 921, 928, 924, 931, 929, 925, 921, 929, 931, 933, + 871, 925, 930, 934, 935, 930, 935, 176, 688, 800, + 799, 798, 797, 936, 796, 936, 795, 794, 793, 792, + 791, 790, 789, 788, 787, 910, 786, 785, 784, 783, + 782, 781, 780, 779, 778, 910, 777, 776, 775, 774, + 932, 773, 732, 770, 769, 932, 63, 63, 63, 63, - 94, 94, 168, 168, 256, 766, 256, 256, 728, 765, - 728, 728, 764, 763, 762, 761, 760, 759, 758, 757, - 756, 755, 754, 753, 752, 751, 750, 749, 748, 747, - 746, 745, 744, 743, 742, 741, 740, 739, 738, 737, - 736, 735, 734, 733, 732, 731, 730, 729, 727, 726, - 725, 724, 723, 722, 721, 720, 719, 718, 717, 716, - 715, 714, 713, 712, 711, 710, 709, 708, 707, 706, - 705, 704, 701, 700, 699, 695, 694, 693, 692, 691, - 690, 684, 683, 682, 681, 680, 679, 678, 677, 676, - 675, 674, 673, 672, 671, 670, 669, 668, 667, 666, + 64, 64, 64, 64, 68, 768, 68, 68, 94, 94, + 168, 168, 256, 767, 256, 256, 731, 766, 731, 731, + 765, 764, 763, 762, 761, 760, 759, 758, 757, 756, + 755, 754, 753, 752, 751, 750, 749, 748, 747, 746, + 745, 744, 743, 742, 741, 740, 739, 738, 737, 736, + 735, 734, 733, 732, 730, 729, 728, 727, 726, 725, + 724, 723, 722, 721, 720, 719, 718, 717, 716, 715, + 714, 713, 712, 711, 710, 709, 708, 707, 706, 703, + 702, 701, 697, 696, 695, 694, 693, 692, 686, 685, + 684, 683, 682, 681, 680, 679, 678, 677, 676, 675, - 665, 664, 663, 662, 661, 660, 659, 658, 657, 656, - 655, 654, 653, 652, 651, 650, 649, 648, 647, 646, - 645, 644, 643, 642, 636, 635, 634, 633, 632, 631, - 630, 629, 628, 624, 623, 622, 621, 620, 619, 618, - 617, 616, 615, 610, 609, 608, 607, 606, 605, 604, - 585, 584, 583, 582, 581, 574, 573, 572, 571, 570, - 569, 568, 567, 566, 563, 562, 561, 560, 554, 553, - 552, 551, 550, 549, 548, 547, 546, 545, 544, 543, - 542, 541, 540, 539, 538, 537, 522, 521, 520, 519, - 518, 517, 516, 515, 514, 510, 509, 508, 507, 506, + 674, 673, 672, 671, 670, 669, 668, 667, 666, 665, + 664, 663, 662, 661, 660, 659, 658, 657, 656, 655, + 654, 653, 652, 651, 650, 649, 648, 647, 646, 645, + 644, 643, 637, 636, 635, 634, 633, 632, 631, 630, + 629, 625, 624, 623, 622, 621, 620, 619, 618, 617, + 616, 611, 610, 609, 608, 607, 606, 605, 586, 585, + 584, 583, 582, 574, 573, 572, 571, 570, 569, 568, + 567, 566, 563, 562, 561, 560, 554, 553, 552, 551, + 550, 549, 548, 547, 546, 545, 544, 543, 542, 541, + 540, 539, 538, 537, 522, 521, 520, 519, 518, 517, - 505, 504, 503, 502, 501, 500, 499, 498, 497, 496, - 495, 494, 493, 492, 491, 490, 489, 488, 487, 486, - 485, 484, 483, 482, 481, 480, 479, 478, 477, 476, - 475, 474, 473, 472, 471, 470, 467, 466, 465, 459, - 458, 457, 456, 455, 454, 446, 445, 444, 443, 442, - 441, 440, 439, 438, 437, 436, 435, 434, 433, 432, - 431, 430, 429, 428, 427, 426, 425, 424, 423, 422, - 421, 420, 419, 418, 417, 416, 415, 411, 410, 409, - 408, 407, 406, 405, 404, 403, 402, 401, 400, 399, - 398, 397, 396, 395, 392, 391, 390, 389, 388, 387, + 516, 515, 514, 510, 509, 508, 507, 506, 505, 504, + 503, 502, 501, 500, 499, 498, 497, 496, 495, 494, + 493, 492, 491, 490, 489, 488, 487, 486, 485, 484, + 483, 482, 481, 480, 479, 478, 477, 476, 475, 474, + 473, 472, 471, 470, 467, 466, 465, 459, 458, 457, + 456, 455, 454, 446, 445, 444, 443, 442, 441, 440, + 439, 438, 437, 436, 435, 434, 433, 432, 431, 430, + 429, 428, 427, 426, 425, 424, 423, 422, 421, 420, + 419, 418, 417, 416, 415, 411, 410, 409, 408, 407, + 406, 405, 404, 403, 402, 401, 400, 399, 398, 397, - 386, 385, 381, 380, 379, 378, 377, 376, 375, 374, - 373, 372, 371, 370, 369, 368, 367, 366, 365, 364, - 360, 359, 358, 357, 356, 355, 354, 353, 352, 351, - 350, 349, 348, 345, 344, 343, 342, 341, 340, 339, - 338, 335, 334, 333, 332, 331, 330, 329, 328, 327, - 326, 325, 324, 323, 322, 321, 320, 319, 318, 317, - 316, 315, 314, 313, 312, 311, 306, 305, 304, 303, - 302, 301, 300, 299, 298, 297, 296, 295, 294, 293, - 292, 291, 290, 289, 286, 285, 284, 283, 282, 279, - 278, 277, 276, 275, 274, 273, 272, 269, 268, 267, + 396, 395, 392, 391, 390, 389, 388, 387, 386, 385, + 381, 380, 379, 378, 377, 376, 375, 374, 373, 372, + 371, 370, 369, 368, 367, 366, 365, 364, 360, 359, + 358, 357, 356, 355, 354, 353, 352, 351, 350, 349, + 348, 345, 344, 343, 342, 341, 340, 339, 338, 335, + 334, 333, 332, 331, 330, 329, 328, 327, 326, 325, + 324, 323, 322, 321, 320, 319, 318, 317, 316, 315, + 314, 313, 312, 311, 306, 305, 304, 303, 302, 301, + 300, 299, 298, 297, 296, 295, 294, 293, 292, 291, + 290, 289, 286, 285, 284, 283, 282, 279, 278, 277, - 266, 265, 255, 254, 253, 250, 249, 244, 241, 240, - 239, 236, 235, 234, 233, 232, 231, 230, 227, 224, - 223, 222, 217, 216, 215, 214, 213, 212, 211, 210, - 207, 206, 205, 204, 203, 202, 201, 197, 196, 195, - 194, 193, 192, 191, 190, 189, 188, 187, 183, 182, - 181, 180, 179, 178, 177, 69, 166, 156, 136, 127, - 104, 101, 100, 99, 98, 97, 96, 95, 91, 79, - 73, 70, 69, 67, 929, 65, 65, 7, 929, 929, - 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, - 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, + 276, 275, 274, 273, 272, 269, 268, 267, 266, 265, + 255, 254, 253, 250, 249, 244, 241, 240, 239, 236, + 235, 234, 233, 232, 231, 230, 227, 224, 223, 222, + 217, 216, 215, 214, 213, 212, 211, 210, 207, 206, + 205, 204, 203, 202, 201, 197, 196, 195, 194, 193, + 192, 191, 190, 189, 188, 187, 183, 182, 181, 180, + 179, 178, 177, 69, 166, 156, 136, 127, 104, 101, + 100, 99, 98, 97, 96, 95, 91, 79, 73, 70, + 69, 67, 937, 65, 65, 7, 937, 937, 937, 937, + 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, - 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, - 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, - 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, - 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, - 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, - 929, 929 + 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, + 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, + 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, + 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, + 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, + 937, 937, 937, 937, 937, 937, 937, 937, 937, 937 } ; -static yyconst flex_int16_t yy_chk[1353] = +static yyconst flex_int16_t yy_chk[1361] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -905,127 +908,127 @@ static yyconst flex_int16_t yy_chk[1353] = 20, 20, 20, 20, 20, 20, 20, 61, 61, 61, 61, 61, 61, 61, 149, 20, 20, 81, 100, 131, 137, 54, 131, 176, 152, 149, 131, 20, 131, 20, - 769, 100, 100, 152, 137, 155, 20, 20, 155, 194, + 766, 100, 100, 152, 137, 155, 20, 20, 155, 194, 56, 159, 315, 159, 56, 165, 159, 165, 184, 315, - 770, 20, 184, 194, 20, 21, 771, 21, 21, 21, + 768, 20, 184, 194, 20, 21, 769, 21, 21, 21, 21, 21, 21, 21, 78, 78, 78, 78, 78, 78, - 78, 772, 21, 21, 160, 160, 161, 161, 773, 78, + 78, 770, 21, 21, 160, 160, 161, 161, 773, 78, 78, 83, 83, 247, 21, 83, 83, 83, 83, 83, - 83, 83, 247, 21, 21, 220, 220, 220, 686, 686, + 83, 83, 247, 21, 21, 220, 220, 220, 688, 688, 78, 78, 278, 278, 278, 302, 302, 302, 21, 80, 80, 80, 80, 80, 80, 80, 167, 167, 167, 167, 167, 167, 167, 502, 80, 80, 335, 335, 335, 220, 391, 774, 160, 775, 161, 502, 160, 776, 161, 378, - 378, 378, 778, 391, 779, 80, 80, 82, 780, 82, + 378, 378, 777, 391, 778, 80, 80, 82, 779, 82, 82, 82, 82, 82, 82, 82, 379, 379, 379, 379, - 781, 782, 169, 169, 82, 82, 169, 169, 169, 169, + 780, 782, 169, 169, 82, 82, 169, 169, 169, 169, 169, 169, 169, 171, 171, 171, 171, 171, 171, 171, - 784, 386, 386, 386, 785, 82, 82, 786, 171, 171, + 783, 386, 386, 386, 784, 82, 82, 785, 171, 171, 172, 172, 386, 386, 172, 172, 172, 172, 172, 172, - 172, 174, 174, 174, 174, 174, 174, 174, 788, 171, + 172, 174, 174, 174, 174, 174, 174, 174, 786, 171, 171, 175, 175, 175, 175, 175, 175, 175, 257, 257, - 257, 257, 257, 257, 257, 789, 790, 175, 258, 258, + 257, 257, 257, 257, 257, 787, 789, 175, 258, 258, 258, 258, 258, 258, 258, 261, 261, 261, 261, 261, - 261, 261, 791, 792, 258, 259, 259, 793, 175, 259, + 261, 261, 790, 791, 258, 259, 259, 793, 175, 259, 259, 259, 259, 259, 259, 259, 262, 262, 262, 262, 262, 262, 262, 794, 795, 258, 444, 444, 444, 456, 456, 456, 262, 346, 346, 346, 346, 346, 346, 346, 347, 347, 347, 347, 347, 347, 347, 457, 457, 457, 458, 458, 458, 262, 796, 797, 347, 459, 459, 459, - 487, 487, 487, 492, 503, 503, 503, 798, 459, 459, - 800, 487, 487, 515, 515, 515, 503, 347, 492, 492, - 492, 492, 492, 492, 492, 516, 516, 516, 517, 517, - 517, 518, 518, 518, 519, 519, 519, 520, 520, 520, - 537, 538, 551, 551, 564, 564, 649, 649, 649, 801, - 565, 565, 551, 802, 537, 538, 803, 804, 805, 564, - 564, 564, 564, 564, 564, 565, 565, 565, 565, 565, + 487, 487, 487, 492, 515, 515, 515, 798, 459, 459, + 799, 487, 487, 503, 503, 503, 654, 347, 492, 492, + 492, 492, 492, 492, 492, 503, 654, 503, 516, 516, + 516, 517, 517, 517, 518, 518, 518, 519, 519, 519, + 520, 520, 520, 537, 538, 551, 551, 564, 564, 650, + 650, 650, 800, 565, 565, 551, 801, 537, 538, 802, + 803, 805, 564, 564, 564, 564, 564, 564, 565, 565, - 565, 565, 637, 637, 639, 639, 637, 642, 729, 729, - 641, 641, 729, 767, 767, 806, 807, 767, 564, 639, - 639, 639, 639, 639, 639, 641, 641, 641, 641, 641, - 641, 641, 653, 808, 809, 810, 811, 812, 813, 816, - 818, 820, 653, 564, 822, 827, 828, 642, 829, 830, - 831, 832, 833, 834, 828, 837, 838, 642, 840, 841, - 842, 843, 844, 845, 846, 847, 848, 849, 642, 850, - 851, 852, 846, 853, 854, 855, 856, 857, 858, 860, - 861, 862, 863, 864, 865, 866, 869, 873, 874, 875, - 863, 876, 877, 878, 880, 879, 881, 882, 883, 884, + 565, 565, 565, 565, 565, 638, 638, 640, 640, 638, + 643, 732, 732, 642, 642, 732, 771, 771, 806, 807, + 771, 564, 640, 640, 640, 640, 640, 640, 642, 642, + 642, 642, 642, 642, 642, 808, 809, 810, 811, 812, + 813, 814, 815, 816, 817, 818, 564, 819, 822, 824, + 643, 826, 828, 833, 834, 835, 836, 837, 838, 839, + 643, 840, 834, 843, 844, 845, 847, 848, 849, 850, + 851, 643, 852, 853, 854, 855, 856, 857, 858, 859, + 860, 853, 861, 862, 864, 865, 866, 868, 869, 870, + 871, 872, 873, 874, 877, 881, 882, 883, 871, 884, - 885, 886, 878, 879, 887, 888, 891, 890, 892, 894, - 897, 898, 899, 887, 888, 890, 901, 902, 845, 904, - 906, 899, 907, 908, 909, 902, 847, 910, 911, 912, - 914, 915, 908, 919, 916, 922, 920, 911, 912, 921, - 923, 924, 862, 916, 920, 925, 926, 921, 927, 935, - 937, 766, 765, 764, 762, 926, 761, 927, 760, 759, - 758, 756, 755, 754, 753, 752, 751, 891, 750, 748, - 747, 746, 745, 744, 743, 742, 741, 901, 740, 738, - 737, 736, 922, 735, 732, 731, 730, 923, 930, 930, - 930, 930, 931, 931, 931, 931, 932, 728, 932, 932, + 885, 886, 888, 887, 889, 890, 891, 892, 893, 894, + 886, 887, 895, 896, 899, 898, 900, 902, 905, 906, + 907, 895, 896, 898, 909, 910, 912, 852, 914, 907, + 915, 916, 917, 910, 918, 854, 919, 920, 922, 923, + 916, 927, 924, 930, 928, 919, 920, 929, 931, 932, + 870, 924, 928, 933, 934, 929, 935, 943, 945, 765, + 764, 763, 762, 934, 760, 935, 759, 758, 757, 756, + 755, 754, 752, 751, 750, 899, 749, 748, 747, 746, + 745, 744, 743, 741, 740, 909, 739, 738, 735, 734, + 930, 733, 731, 729, 728, 931, 938, 938, 938, 938, - 933, 933, 934, 934, 936, 726, 936, 936, 938, 725, - 938, 938, 724, 723, 722, 721, 720, 719, 718, 717, - 716, 715, 714, 713, 711, 710, 709, 708, 707, 706, - 705, 704, 703, 702, 701, 700, 699, 698, 697, 696, - 695, 694, 693, 692, 689, 688, 687, 685, 684, 683, - 682, 681, 680, 679, 678, 677, 674, 673, 668, 667, - 666, 665, 664, 663, 662, 661, 660, 659, 658, 657, - 656, 655, 652, 651, 650, 648, 647, 646, 645, 644, - 643, 634, 633, 631, 630, 629, 627, 626, 625, 624, - 623, 622, 621, 619, 618, 617, 616, 615, 614, 613, + 939, 939, 939, 939, 940, 727, 940, 940, 941, 941, + 942, 942, 944, 726, 944, 944, 946, 725, 946, 946, + 724, 723, 722, 721, 720, 719, 718, 717, 716, 714, + 713, 712, 711, 710, 709, 708, 707, 706, 705, 704, + 703, 702, 701, 700, 699, 698, 697, 696, 695, 694, + 691, 690, 689, 687, 686, 685, 684, 683, 682, 681, + 680, 679, 676, 675, 670, 669, 668, 667, 666, 665, + 664, 663, 662, 661, 660, 659, 658, 657, 656, 653, + 652, 651, 649, 648, 647, 646, 645, 644, 635, 634, + 632, 631, 630, 628, 627, 626, 625, 624, 623, 622, - 612, 611, 610, 609, 607, 606, 605, 604, 583, 581, - 580, 579, 578, 577, 576, 575, 574, 573, 572, 570, - 569, 568, 567, 566, 563, 561, 559, 558, 557, 556, - 555, 553, 552, 550, 549, 548, 547, 546, 545, 543, - 542, 541, 540, 536, 535, 534, 533, 532, 522, 521, - 514, 508, 507, 506, 504, 501, 500, 499, 498, 497, - 496, 495, 494, 493, 491, 490, 489, 488, 486, 485, - 484, 479, 478, 475, 473, 472, 471, 470, 468, 467, - 466, 464, 463, 462, 461, 460, 455, 454, 453, 452, - 451, 449, 448, 447, 445, 443, 442, 441, 439, 438, + 620, 619, 618, 617, 616, 615, 614, 613, 612, 611, + 610, 608, 607, 606, 605, 584, 582, 581, 580, 579, + 578, 577, 576, 575, 574, 573, 572, 570, 569, 568, + 567, 566, 563, 561, 559, 558, 557, 556, 555, 553, + 552, 550, 549, 548, 547, 546, 545, 543, 542, 541, + 540, 536, 535, 534, 533, 532, 522, 521, 514, 508, + 507, 506, 504, 501, 500, 499, 498, 497, 496, 495, + 494, 493, 491, 490, 489, 488, 486, 485, 484, 479, + 478, 475, 473, 472, 471, 470, 468, 467, 466, 464, + 463, 462, 461, 460, 455, 454, 453, 452, 451, 449, - 437, 435, 434, 433, 432, 431, 430, 429, 428, 427, - 426, 425, 423, 422, 420, 419, 417, 415, 411, 410, - 409, 408, 407, 406, 405, 404, 402, 401, 400, 399, - 397, 396, 395, 394, 393, 392, 390, 389, 387, 385, - 384, 383, 382, 381, 380, 377, 375, 374, 373, 372, - 371, 369, 368, 366, 365, 360, 359, 358, 357, 356, - 355, 354, 353, 352, 351, 350, 349, 348, 345, 344, - 343, 342, 340, 339, 338, 337, 336, 334, 333, 331, - 329, 328, 327, 326, 325, 324, 323, 322, 321, 320, - 319, 318, 317, 316, 314, 312, 311, 310, 306, 305, + 448, 447, 445, 443, 442, 441, 439, 438, 437, 435, + 434, 433, 432, 431, 430, 429, 428, 427, 426, 425, + 423, 422, 420, 419, 417, 415, 411, 410, 409, 408, + 407, 406, 405, 404, 402, 401, 400, 399, 397, 396, + 395, 394, 393, 392, 390, 389, 387, 385, 384, 383, + 382, 381, 380, 377, 375, 374, 373, 372, 371, 369, + 368, 366, 365, 360, 359, 358, 357, 356, 355, 354, + 353, 352, 351, 350, 349, 348, 345, 344, 343, 342, + 340, 339, 338, 337, 336, 334, 333, 331, 329, 328, + 327, 326, 325, 324, 323, 322, 321, 320, 319, 318, - 304, 303, 301, 299, 298, 297, 296, 295, 294, 291, - 290, 289, 288, 287, 286, 285, 284, 283, 282, 279, - 277, 276, 275, 274, 273, 272, 271, 270, 269, 268, - 267, 266, 265, 255, 254, 253, 252, 251, 250, 249, - 248, 246, 245, 244, 243, 242, 241, 240, 239, 238, - 237, 236, 235, 234, 233, 232, 231, 230, 229, 228, - 226, 225, 224, 223, 222, 221, 219, 218, 217, 216, - 215, 214, 213, 212, 210, 209, 208, 207, 206, 205, - 204, 203, 202, 201, 199, 198, 197, 196, 195, 193, - 192, 190, 189, 188, 187, 186, 185, 183, 182, 181, + 317, 316, 314, 312, 311, 310, 306, 305, 304, 303, + 301, 299, 298, 297, 296, 295, 294, 291, 290, 289, + 288, 287, 286, 285, 284, 283, 282, 279, 277, 276, + 275, 274, 273, 272, 271, 270, 269, 268, 267, 266, + 265, 255, 254, 253, 252, 251, 250, 249, 248, 246, + 245, 244, 243, 242, 241, 240, 239, 238, 237, 236, + 235, 234, 233, 232, 231, 230, 229, 228, 226, 225, + 224, 223, 222, 221, 219, 218, 217, 216, 215, 214, + 213, 212, 210, 209, 208, 207, 206, 205, 204, 203, + 202, 201, 199, 198, 197, 196, 195, 193, 192, 190, - 180, 179, 164, 163, 156, 154, 153, 150, 148, 147, - 146, 144, 143, 142, 141, 140, 139, 138, 136, 134, - 133, 132, 130, 129, 127, 126, 125, 124, 123, 122, - 120, 119, 118, 117, 116, 115, 114, 112, 111, 110, - 109, 108, 107, 106, 105, 103, 102, 101, 99, 98, - 97, 96, 95, 93, 89, 68, 60, 53, 46, 42, - 34, 32, 31, 30, 29, 28, 27, 26, 23, 19, - 15, 13, 12, 11, 7, 6, 5, 929, 929, 929, - 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, - 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, + 189, 188, 187, 186, 185, 183, 182, 181, 180, 179, + 164, 163, 156, 154, 153, 150, 148, 147, 146, 144, + 143, 142, 141, 140, 139, 138, 136, 134, 133, 132, + 130, 129, 127, 126, 125, 124, 123, 122, 120, 119, + 118, 117, 116, 115, 114, 112, 111, 110, 109, 108, + 107, 106, 105, 103, 102, 101, 99, 98, 97, 96, + 95, 93, 89, 68, 60, 53, 46, 42, 34, 32, + 31, 30, 29, 28, 27, 26, 23, 19, 15, 13, + 12, 11, 7, 6, 5, 937, 937, 937, 937, 937, + 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, - 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, - 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, - 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, - 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, - 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, - 929, 929 + 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, + 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, + 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, + 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, + 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, + 937, 937, 937, 937, 937, 937, 937, 937, 937, 937 } ; /* The intent behind this definition is that it'll catch @@ -1170,7 +1173,7 @@ literal_integer(char *text, int len, struct _mesa_glsl_parse_state *state, literal_integer(yytext, yyleng, yyextra, yylval, yylloc, base) -#line 1174 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.inl" +#line 1177 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.inl" #define INITIAL 0 #define PP 1 @@ -1407,7 +1410,7 @@ YY_DECL #line 151 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -#line 1411 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.inl" +#line 1414 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.inl" yylval = yylval_param; @@ -1465,13 +1468,13 @@ yy_match: while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 930 ) + if ( yy_current_state >= 938 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } - while ( yy_current_state != 929 ); + while ( yy_current_state != 937 ); yy_cp = yyg->yy_last_accepting_cpos; yy_current_state = yyg->yy_last_accepting_state; @@ -1977,222 +1980,227 @@ return TEXTURE2D; case 85: YY_RULE_SETUP #line 300 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return TEXTURE2D_ARRAY; +return TEXTURE_EXTERNAL; YY_BREAK case 86: YY_RULE_SETUP #line 301 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return TEXTURE2DMS; +return TEXTURE2D_ARRAY; YY_BREAK case 87: YY_RULE_SETUP #line 302 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return TEXTURE2DMS_ARRAY; +return TEXTURE2DMS; YY_BREAK case 88: YY_RULE_SETUP #line 303 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return TEXTURE3D; +return TEXTURE2DMS_ARRAY; YY_BREAK case 89: YY_RULE_SETUP #line 304 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return TEXTURECUBE; +return TEXTURE3D; YY_BREAK case 90: YY_RULE_SETUP #line 305 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(100, 310, TEXTURECUBE_ARRAY); +return TEXTURECUBE; YY_BREAK case 91: YY_RULE_SETUP #line 306 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return SAMPLERSTATE; +KEYWORD(100, 310, TEXTURECUBE_ARRAY); YY_BREAK case 92: YY_RULE_SETUP #line 307 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return SAMPLERSTATE_CMP; +return SAMPLERSTATE; YY_BREAK case 93: YY_RULE_SETUP -#line 309 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(100, 310, RWBUFFER); +#line 308 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" +return SAMPLERSTATE_CMP; YY_BREAK case 94: YY_RULE_SETUP #line 310 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(100, 430, RWSTRUCTUREDBUFFER); +KEYWORD(100, 310, RWBUFFER); YY_BREAK case 95: YY_RULE_SETUP #line 311 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(100, 430, RWBYTEADDRESSBUFFER); +KEYWORD(100, 430, RWSTRUCTUREDBUFFER); YY_BREAK case 96: YY_RULE_SETUP #line 312 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(100, 310, RWTEXTURE1D); +KEYWORD(100, 430, RWBYTEADDRESSBUFFER); YY_BREAK case 97: YY_RULE_SETUP #line 313 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(100, 310, RWTEXTURE1D_ARRAY); +KEYWORD(100, 310, RWTEXTURE1D); YY_BREAK case 98: YY_RULE_SETUP #line 314 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(100, 310, RWTEXTURE2D); +KEYWORD(100, 310, RWTEXTURE1D_ARRAY); YY_BREAK case 99: YY_RULE_SETUP #line 315 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(100, 310, RWTEXTURE2D_ARRAY); +KEYWORD(100, 310, RWTEXTURE2D); YY_BREAK case 100: YY_RULE_SETUP #line 316 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(100, 310, RWTEXTURE3D); +KEYWORD(100, 310, RWTEXTURE2D_ARRAY); YY_BREAK case 101: YY_RULE_SETUP -#line 318 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return STRUCT; +#line 317 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" +KEYWORD(100, 310, RWTEXTURE3D); YY_BREAK case 102: YY_RULE_SETUP #line 319 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return CBUFFER; +return STRUCT; YY_BREAK case 103: YY_RULE_SETUP #line 320 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return VOID_TOK; +return CBUFFER; YY_BREAK case 104: YY_RULE_SETUP -#line 322 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return INC_OP; +#line 321 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" +return VOID_TOK; YY_BREAK case 105: YY_RULE_SETUP #line 323 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return DEC_OP; +return INC_OP; YY_BREAK case 106: YY_RULE_SETUP #line 324 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return LE_OP; +return DEC_OP; YY_BREAK case 107: YY_RULE_SETUP #line 325 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return GE_OP; +return LE_OP; YY_BREAK case 108: YY_RULE_SETUP #line 326 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return EQ_OP; +return GE_OP; YY_BREAK case 109: YY_RULE_SETUP #line 327 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return NE_OP; +return EQ_OP; YY_BREAK case 110: YY_RULE_SETUP #line 328 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return AND_OP; +return NE_OP; YY_BREAK case 111: YY_RULE_SETUP #line 329 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return OR_OP; +return AND_OP; YY_BREAK case 112: YY_RULE_SETUP #line 330 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return LEFT_OP; +return OR_OP; YY_BREAK case 113: YY_RULE_SETUP #line 331 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return RIGHT_OP; +return LEFT_OP; YY_BREAK case 114: YY_RULE_SETUP -#line 333 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return MUL_ASSIGN; +#line 332 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" +return RIGHT_OP; YY_BREAK case 115: YY_RULE_SETUP #line 334 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return DIV_ASSIGN; +return MUL_ASSIGN; YY_BREAK case 116: YY_RULE_SETUP #line 335 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return ADD_ASSIGN; +return DIV_ASSIGN; YY_BREAK case 117: YY_RULE_SETUP #line 336 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return MOD_ASSIGN; +return ADD_ASSIGN; YY_BREAK case 118: YY_RULE_SETUP #line 337 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return LEFT_ASSIGN; +return MOD_ASSIGN; YY_BREAK case 119: YY_RULE_SETUP #line 338 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return RIGHT_ASSIGN; +return LEFT_ASSIGN; YY_BREAK case 120: YY_RULE_SETUP #line 339 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return AND_ASSIGN; +return RIGHT_ASSIGN; YY_BREAK case 121: YY_RULE_SETUP #line 340 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return XOR_ASSIGN; +return AND_ASSIGN; YY_BREAK case 122: YY_RULE_SETUP #line 341 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return OR_ASSIGN; +return XOR_ASSIGN; YY_BREAK case 123: YY_RULE_SETUP #line 342 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return SUB_ASSIGN; +return OR_ASSIGN; YY_BREAK case 124: YY_RULE_SETUP -#line 344 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" +#line 343 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" +return SUB_ASSIGN; + YY_BREAK +case 125: +YY_RULE_SETUP +#line 345 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" { return LITERAL_INTEGER(10); } YY_BREAK -case 125: +case 126: YY_RULE_SETUP -#line 347 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" +#line 348 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" { return LITERAL_INTEGER(16); } YY_BREAK -case 126: +case 127: YY_RULE_SETUP -#line 350 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" +#line 351 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" { return LITERAL_INTEGER(8); } YY_BREAK -case 127: +case 128: YY_RULE_SETUP -#line 354 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" +#line 355 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" { struct _mesa_glsl_parse_state *state = yyextra; void *ctx = state; @@ -2200,17 +2208,9 @@ YY_RULE_SETUP return STRINGCONSTANT; } YY_BREAK -case 128: -YY_RULE_SETUP -#line 361 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -{ - yylval->real = glsl_strtod(yytext, NULL); - return FLOATCONSTANT; - } - YY_BREAK case 129: YY_RULE_SETUP -#line 365 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" +#line 362 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" { yylval->real = glsl_strtod(yytext, NULL); return FLOATCONSTANT; @@ -2218,7 +2218,7 @@ YY_RULE_SETUP YY_BREAK case 130: YY_RULE_SETUP -#line 369 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" +#line 366 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" { yylval->real = glsl_strtod(yytext, NULL); return FLOATCONSTANT; @@ -2226,7 +2226,7 @@ YY_RULE_SETUP YY_BREAK case 131: YY_RULE_SETUP -#line 373 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" +#line 370 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" { yylval->real = glsl_strtod(yytext, NULL); return FLOATCONSTANT; @@ -2234,7 +2234,7 @@ YY_RULE_SETUP YY_BREAK case 132: YY_RULE_SETUP -#line 377 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" +#line 374 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" { yylval->real = glsl_strtod(yytext, NULL); return FLOATCONSTANT; @@ -2242,470 +2242,478 @@ YY_RULE_SETUP YY_BREAK case 133: YY_RULE_SETUP -#line 382 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" +#line 378 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" +{ + yylval->real = glsl_strtod(yytext, NULL); + return FLOATCONSTANT; + } + YY_BREAK +case 134: +YY_RULE_SETUP +#line 383 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" { yylval->n = 1; return BOOLCONSTANT; } YY_BREAK -case 134: +case 135: YY_RULE_SETUP -#line 386 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" +#line 387 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" { yylval->n = 0; return BOOLCONSTANT; } YY_BREAK /* Reserved words in GLSL 1.10. */ -case 135: -YY_RULE_SETUP -#line 393 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 999, ASM); - YY_BREAK case 136: YY_RULE_SETUP #line 394 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 999, CLASS); +KEYWORD(110 || ES, 999, ASM); YY_BREAK case 137: YY_RULE_SETUP #line 395 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 999, UNION); +KEYWORD(110 || ES, 999, CLASS); YY_BREAK case 138: YY_RULE_SETUP #line 396 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 999, ENUM); +KEYWORD(110 || ES, 999, UNION); YY_BREAK case 139: YY_RULE_SETUP #line 397 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 999, TYPEDEF); +KEYWORD(110 || ES, 999, ENUM); YY_BREAK case 140: YY_RULE_SETUP #line 398 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 999, TEMPLATE); +KEYWORD(110 || ES, 999, TYPEDEF); YY_BREAK case 141: YY_RULE_SETUP #line 399 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 999, THIS); +KEYWORD(110 || ES, 999, TEMPLATE); YY_BREAK case 142: YY_RULE_SETUP #line 400 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 999, PACKED_TOK); +KEYWORD(110 || ES, 999, THIS); YY_BREAK case 143: YY_RULE_SETUP #line 401 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 999, GOTO); +KEYWORD(110 || ES, 999, PACKED_TOK); YY_BREAK case 144: YY_RULE_SETUP #line 402 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 130, SWITCH); +KEYWORD(110 || ES, 999, GOTO); YY_BREAK case 145: YY_RULE_SETUP #line 403 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 130, DEFAULT); +KEYWORD(110 || ES, 130, SWITCH); YY_BREAK case 146: YY_RULE_SETUP #line 404 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return INLINE_TOK; +KEYWORD(110 || ES, 130, DEFAULT); YY_BREAK case 147: YY_RULE_SETUP #line 405 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 999, NOINLINE); +return INLINE_TOK; YY_BREAK case 148: YY_RULE_SETUP #line 406 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 999, VOLATILE); +KEYWORD(110 || ES, 999, NOINLINE); YY_BREAK case 149: YY_RULE_SETUP #line 407 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 999, PUBLIC_TOK); +KEYWORD(110 || ES, 999, VOLATILE); YY_BREAK case 150: YY_RULE_SETUP #line 408 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return STATIC; +KEYWORD(110 || ES, 999, PUBLIC_TOK); YY_BREAK case 151: YY_RULE_SETUP #line 409 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 999, EXTERN); +return STATIC; YY_BREAK case 152: YY_RULE_SETUP #line 410 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 999, EXTERNAL); +KEYWORD(110 || ES, 999, EXTERN); YY_BREAK case 153: YY_RULE_SETUP #line 411 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 999, INTERFACE); +KEYWORD(110 || ES, 999, EXTERNAL); YY_BREAK case 154: YY_RULE_SETUP #line 412 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 999, LONG_TOK); +KEYWORD(110 || ES, 999, INTERFACE); YY_BREAK case 155: YY_RULE_SETUP #line 413 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 999, SHORT_TOK); +KEYWORD(110 || ES, 999, LONG_TOK); YY_BREAK case 156: YY_RULE_SETUP #line 414 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 400, DOUBLE_TOK); +KEYWORD(110 || ES, 999, SHORT_TOK); YY_BREAK case 157: YY_RULE_SETUP #line 415 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 110, FIXED_TOK); +KEYWORD(110 || ES, 400, DOUBLE_TOK); YY_BREAK case 158: YY_RULE_SETUP #line 416 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 999, UNSIGNED); +KEYWORD(110 || ES, 110, FIXED_TOK); YY_BREAK case 159: YY_RULE_SETUP #line 417 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 150, HVEC2); +KEYWORD(110 || ES, 999, UNSIGNED); YY_BREAK case 160: YY_RULE_SETUP #line 418 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 150, HVEC3); +KEYWORD(110 || ES, 150, HVEC2); YY_BREAK case 161: YY_RULE_SETUP #line 419 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 150, HVEC4); +KEYWORD(110 || ES, 150, HVEC3); YY_BREAK case 162: YY_RULE_SETUP #line 420 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(120, 120, HMAT2X2); +KEYWORD(110 || ES, 150, HVEC4); YY_BREAK case 163: YY_RULE_SETUP #line 421 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(120, 120, HMAT2X3); +KEYWORD(120, 120, HMAT2X2); YY_BREAK case 164: YY_RULE_SETUP #line 422 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(120, 120, HMAT2X4); +KEYWORD(120, 120, HMAT2X3); YY_BREAK case 165: YY_RULE_SETUP #line 423 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(120, 120, HMAT3X2); +KEYWORD(120, 120, HMAT2X4); YY_BREAK case 166: YY_RULE_SETUP #line 424 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(120, 120, HMAT3X3); +KEYWORD(120, 120, HMAT3X2); YY_BREAK case 167: YY_RULE_SETUP #line 425 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(120, 120, HMAT3X4); +KEYWORD(120, 120, HMAT3X3); YY_BREAK case 168: YY_RULE_SETUP #line 426 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(120, 120, HMAT4X2); +KEYWORD(120, 120, HMAT3X4); YY_BREAK case 169: YY_RULE_SETUP #line 427 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(120, 120, HMAT4X3); +KEYWORD(120, 120, HMAT4X2); YY_BREAK case 170: YY_RULE_SETUP #line 428 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(120, 120, HMAT4X4); +KEYWORD(120, 120, HMAT4X3); YY_BREAK case 171: YY_RULE_SETUP #line 429 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 400, DVEC2); +KEYWORD(120, 120, HMAT4X4); YY_BREAK case 172: YY_RULE_SETUP #line 430 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 400, DVEC3); +KEYWORD(110 || ES, 400, DVEC2); YY_BREAK case 173: YY_RULE_SETUP #line 431 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 400, DVEC4); +KEYWORD(110 || ES, 400, DVEC3); YY_BREAK case 174: YY_RULE_SETUP #line 432 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 110, FVEC2); +KEYWORD(110 || ES, 400, DVEC4); YY_BREAK case 175: YY_RULE_SETUP #line 433 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 110, FVEC3); +KEYWORD(110 || ES, 110, FVEC2); YY_BREAK case 176: YY_RULE_SETUP #line 434 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 110, FVEC4); +KEYWORD(110 || ES, 110, FVEC3); YY_BREAK case 177: YY_RULE_SETUP #line 435 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 110, FMAT2X2); +KEYWORD(110 || ES, 110, FVEC4); YY_BREAK case 178: YY_RULE_SETUP #line 436 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 110, FMAT2X3); +KEYWORD(110 || ES, 110, FMAT2X2); YY_BREAK case 179: YY_RULE_SETUP #line 437 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 110, FMAT2X4); +KEYWORD(110 || ES, 110, FMAT2X3); YY_BREAK case 180: YY_RULE_SETUP #line 438 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 110, FMAT3X2); +KEYWORD(110 || ES, 110, FMAT2X4); YY_BREAK case 181: YY_RULE_SETUP #line 439 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 110, FMAT3X3); +KEYWORD(110 || ES, 110, FMAT3X2); YY_BREAK case 182: YY_RULE_SETUP #line 440 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 110, FMAT3X4); +KEYWORD(110 || ES, 110, FMAT3X3); YY_BREAK case 183: YY_RULE_SETUP #line 441 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 110, FMAT4X2); +KEYWORD(110 || ES, 110, FMAT3X4); YY_BREAK case 184: YY_RULE_SETUP #line 442 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 110, FMAT4X3); +KEYWORD(110 || ES, 110, FMAT4X2); YY_BREAK case 185: YY_RULE_SETUP #line 443 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 110, FMAT4X4); +KEYWORD(110 || ES, 110, FMAT4X3); YY_BREAK case 186: YY_RULE_SETUP #line 444 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return SAMPLER2DRECT; +KEYWORD(110 || ES, 110, FMAT4X4); YY_BREAK case 187: YY_RULE_SETUP #line 445 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 999, SAMPLER3DRECT); +return SAMPLER2DRECT; YY_BREAK case 188: YY_RULE_SETUP #line 446 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -return SAMPLER2DRECTSHADOW; +KEYWORD(110 || ES, 999, SAMPLER3DRECT); YY_BREAK case 189: YY_RULE_SETUP #line 447 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 999, SIZEOF); +return SAMPLER2DRECTSHADOW; YY_BREAK case 190: YY_RULE_SETUP #line 448 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 999, CAST); +KEYWORD(110 || ES, 999, SIZEOF); YY_BREAK case 191: YY_RULE_SETUP #line 449 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(110 || ES, 999, NAMESPACE); +KEYWORD(110 || ES, 999, CAST); YY_BREAK case 192: YY_RULE_SETUP #line 450 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" +KEYWORD(110 || ES, 999, NAMESPACE); + YY_BREAK +case 193: +YY_RULE_SETUP +#line 451 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" KEYWORD(110 || ES, 999, USING); YY_BREAK /* Additional reserved words in GLSL 1.30. */ -case 193: -YY_RULE_SETUP -#line 453 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 130, CASE); - YY_BREAK case 194: YY_RULE_SETUP #line 454 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, COMMON); +KEYWORD(130, 130, CASE); YY_BREAK case 195: YY_RULE_SETUP #line 455 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, PARTITION); +KEYWORD(130, 999, COMMON); YY_BREAK case 196: YY_RULE_SETUP #line 456 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, ACTIVE); +KEYWORD(130, 999, PARTITION); YY_BREAK case 197: YY_RULE_SETUP #line 457 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 140, SAMPLERBUFFER); +KEYWORD(130, 999, ACTIVE); YY_BREAK case 198: YY_RULE_SETUP #line 458 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, FILTER); +KEYWORD(130, 140, SAMPLERBUFFER); YY_BREAK case 199: YY_RULE_SETUP #line 459 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, IMAGE1D); +KEYWORD(130, 999, FILTER); YY_BREAK case 200: YY_RULE_SETUP #line 460 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, IMAGE2D); +KEYWORD(130, 999, IMAGE1D); YY_BREAK case 201: YY_RULE_SETUP #line 461 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, IMAGE3D); +KEYWORD(130, 999, IMAGE2D); YY_BREAK case 202: YY_RULE_SETUP #line 462 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, IMAGECUBE); +KEYWORD(130, 999, IMAGE3D); YY_BREAK case 203: YY_RULE_SETUP #line 463 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, IIMAGE1D); +KEYWORD(130, 999, IMAGECUBE); YY_BREAK case 204: YY_RULE_SETUP #line 464 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, IIMAGE2D); +KEYWORD(130, 999, IIMAGE1D); YY_BREAK case 205: YY_RULE_SETUP #line 465 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, IIMAGE3D); +KEYWORD(130, 999, IIMAGE2D); YY_BREAK case 206: YY_RULE_SETUP #line 466 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, IIMAGECUBE); +KEYWORD(130, 999, IIMAGE3D); YY_BREAK case 207: YY_RULE_SETUP #line 467 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, UIMAGE1D); +KEYWORD(130, 999, IIMAGECUBE); YY_BREAK case 208: YY_RULE_SETUP #line 468 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, UIMAGE2D); +KEYWORD(130, 999, UIMAGE1D); YY_BREAK case 209: YY_RULE_SETUP #line 469 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, UIMAGE3D); +KEYWORD(130, 999, UIMAGE2D); YY_BREAK case 210: YY_RULE_SETUP #line 470 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, UIMAGECUBE); +KEYWORD(130, 999, UIMAGE3D); YY_BREAK case 211: YY_RULE_SETUP #line 471 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, IMAGE1DARRAY); +KEYWORD(130, 999, UIMAGECUBE); YY_BREAK case 212: YY_RULE_SETUP #line 472 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, IMAGE2DARRAY); +KEYWORD(130, 999, IMAGE1DARRAY); YY_BREAK case 213: YY_RULE_SETUP #line 473 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, IIMAGE1DARRAY); +KEYWORD(130, 999, IMAGE2DARRAY); YY_BREAK case 214: YY_RULE_SETUP #line 474 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, IIMAGE2DARRAY); +KEYWORD(130, 999, IIMAGE1DARRAY); YY_BREAK case 215: YY_RULE_SETUP #line 475 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, UIMAGE1DARRAY); +KEYWORD(130, 999, IIMAGE2DARRAY); YY_BREAK case 216: YY_RULE_SETUP #line 476 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, UIMAGE2DARRAY); +KEYWORD(130, 999, UIMAGE1DARRAY); YY_BREAK case 217: YY_RULE_SETUP #line 477 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, IMAGE1DSHADOW); +KEYWORD(130, 999, UIMAGE2DARRAY); YY_BREAK case 218: YY_RULE_SETUP #line 478 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, IMAGE2DSHADOW); +KEYWORD(130, 999, IMAGE1DSHADOW); YY_BREAK case 219: YY_RULE_SETUP #line 479 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, IMAGE1DARRAYSHADOW); +KEYWORD(130, 999, IMAGE2DSHADOW); YY_BREAK case 220: YY_RULE_SETUP #line 480 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, IMAGE2DARRAYSHADOW); +KEYWORD(130, 999, IMAGE1DARRAYSHADOW); YY_BREAK case 221: YY_RULE_SETUP #line 481 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, IMAGEBUFFER); +KEYWORD(130, 999, IMAGE2DARRAYSHADOW); YY_BREAK case 222: YY_RULE_SETUP #line 482 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, IIMAGEBUFFER); +KEYWORD(130, 999, IMAGEBUFFER); YY_BREAK case 223: YY_RULE_SETUP #line 483 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -KEYWORD(130, 999, UIMAGEBUFFER); +KEYWORD(130, 999, IIMAGEBUFFER); YY_BREAK case 224: YY_RULE_SETUP -#line 485 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" +#line 484 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" +KEYWORD(130, 999, UIMAGEBUFFER); + YY_BREAK +case 225: +YY_RULE_SETUP +#line 486 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" { struct _mesa_glsl_parse_state *state = yyextra; void *ctx = state; @@ -2713,17 +2721,17 @@ YY_RULE_SETUP return classify_identifier(state, yytext); } YY_BREAK -case 225: -YY_RULE_SETUP -#line 492 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" -{ return yytext[0]; } - YY_BREAK case 226: YY_RULE_SETUP -#line 494 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" +#line 493 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" +{ return yytext[0]; } + YY_BREAK +case 227: +YY_RULE_SETUP +#line 495 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" ECHO; YY_BREAK -#line 2727 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.inl" +#line 2735 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.inl" case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(PP): case YY_STATE_EOF(PRAGMA): @@ -3021,7 +3029,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 930 ) + if ( yy_current_state >= 938 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; @@ -3050,11 +3058,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 930 ) + if ( yy_current_state >= 938 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - yy_is_jam = (yy_current_state == 929); + yy_is_jam = (yy_current_state == 937); return yy_is_jam ? 0 : yy_current_state; } @@ -3866,7 +3874,7 @@ void _mesa_hlsl_free (void * ptr , yyscan_t yyscanner) #define YYTABLES_NAME "yytables" -#line 494 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" +#line 495 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_lexer.ll" diff --git a/Engine/Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.h b/Engine/Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.h index f2c155013a40..e15cc524dd7f 100644 --- a/Engine/Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.h +++ b/Engine/Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.h @@ -115,142 +115,143 @@ TEXTURE2D = 333, TEXTURE2D_ARRAY = 334, TEXTURE2DMS = 335, - TEXTURE2DMS_ARRAY = 336, - TEXTURE3D = 337, - TEXTURECUBE = 338, - TEXTURECUBE_ARRAY = 339, - RWBUFFER = 340, - RWTEXTURE1D = 341, - RWTEXTURE1D_ARRAY = 342, - RWTEXTURE2D = 343, - RWTEXTURE2D_ARRAY = 344, - RWTEXTURE3D = 345, - RWSTRUCTUREDBUFFER = 346, - RWBYTEADDRESSBUFFER = 347, - POINT_TOK = 348, - LINE_TOK = 349, - TRIANGLE_TOK = 350, - LINEADJ_TOK = 351, - TRIANGLEADJ_TOK = 352, - POINTSTREAM = 353, - LINESTREAM = 354, - TRIANGLESTREAM = 355, - INPUTPATCH = 356, - OUTPUTPATCH = 357, - STRUCT = 358, - VOID_TOK = 359, - WHILE = 360, - CBUFFER = 361, - IDENTIFIER = 362, - TYPE_IDENTIFIER = 363, - NEW_IDENTIFIER = 364, - FLOATCONSTANT = 365, - INTCONSTANT = 366, - UINTCONSTANT = 367, - BOOLCONSTANT = 368, - STRINGCONSTANT = 369, - FIELD_SELECTION = 370, - LEFT_OP = 371, - RIGHT_OP = 372, - INC_OP = 373, - DEC_OP = 374, - LE_OP = 375, - GE_OP = 376, - EQ_OP = 377, - NE_OP = 378, - AND_OP = 379, - OR_OP = 380, - MUL_ASSIGN = 381, - DIV_ASSIGN = 382, - ADD_ASSIGN = 383, - MOD_ASSIGN = 384, - LEFT_ASSIGN = 385, - RIGHT_ASSIGN = 386, - AND_ASSIGN = 387, - XOR_ASSIGN = 388, - OR_ASSIGN = 389, - SUB_ASSIGN = 390, - INVARIANT = 391, - VERSION_TOK = 392, - EXTENSION = 393, - LINE = 394, - COLON = 395, - EOL = 396, - INTERFACE = 397, - OUTPUT = 398, - PRAGMA_DEBUG_ON = 399, - PRAGMA_DEBUG_OFF = 400, - PRAGMA_OPTIMIZE_ON = 401, - PRAGMA_OPTIMIZE_OFF = 402, - PRAGMA_INVARIANT_ALL = 403, - ASM = 404, - CLASS = 405, - UNION = 406, - ENUM = 407, - TYPEDEF = 408, - TEMPLATE = 409, - THIS = 410, - PACKED_TOK = 411, - GOTO = 412, - INLINE_TOK = 413, - NOINLINE = 414, - VOLATILE = 415, - PUBLIC_TOK = 416, - STATIC = 417, - EXTERN = 418, - EXTERNAL = 419, - LONG_TOK = 420, - SHORT_TOK = 421, - DOUBLE_TOK = 422, - HALF = 423, - FIXED_TOK = 424, - UNSIGNED = 425, - DVEC2 = 426, - DVEC3 = 427, - DVEC4 = 428, - FVEC2 = 429, - FVEC3 = 430, - FVEC4 = 431, - SAMPLER2DRECT = 432, - SAMPLER3DRECT = 433, - SAMPLER2DRECTSHADOW = 434, - SIZEOF = 435, - CAST = 436, - NAMESPACE = 437, - USING = 438, - ERROR_TOK = 439, - COMMON = 440, - PARTITION = 441, - ACTIVE = 442, - SAMPLERBUFFER = 443, - FILTER = 444, - IMAGE1D = 445, - IMAGE2D = 446, - IMAGE3D = 447, - IMAGECUBE = 448, - IMAGE1DARRAY = 449, - IMAGE2DARRAY = 450, - IIMAGE1D = 451, - IIMAGE2D = 452, - IIMAGE3D = 453, - IIMAGECUBE = 454, - IIMAGE1DARRAY = 455, - IIMAGE2DARRAY = 456, - UIMAGE1D = 457, - UIMAGE2D = 458, - UIMAGE3D = 459, - UIMAGECUBE = 460, - UIMAGE1DARRAY = 461, - UIMAGE2DARRAY = 462, - IMAGE1DSHADOW = 463, - IMAGE2DSHADOW = 464, - IMAGEBUFFER = 465, - IIMAGEBUFFER = 466, - UIMAGEBUFFER = 467, - IMAGE1DARRAYSHADOW = 468, - IMAGE2DARRAYSHADOW = 469, - ROW_MAJOR = 470, - COLUMN_MAJOR = 471 + TEXTURE_EXTERNAL = 336, + TEXTURE2DMS_ARRAY = 337, + TEXTURE3D = 338, + TEXTURECUBE = 339, + TEXTURECUBE_ARRAY = 340, + RWBUFFER = 341, + RWTEXTURE1D = 342, + RWTEXTURE1D_ARRAY = 343, + RWTEXTURE2D = 344, + RWTEXTURE2D_ARRAY = 345, + RWTEXTURE3D = 346, + RWSTRUCTUREDBUFFER = 347, + RWBYTEADDRESSBUFFER = 348, + POINT_TOK = 349, + LINE_TOK = 350, + TRIANGLE_TOK = 351, + LINEADJ_TOK = 352, + TRIANGLEADJ_TOK = 353, + POINTSTREAM = 354, + LINESTREAM = 355, + TRIANGLESTREAM = 356, + INPUTPATCH = 357, + OUTPUTPATCH = 358, + STRUCT = 359, + VOID_TOK = 360, + WHILE = 361, + CBUFFER = 362, + IDENTIFIER = 363, + TYPE_IDENTIFIER = 364, + NEW_IDENTIFIER = 365, + FLOATCONSTANT = 366, + INTCONSTANT = 367, + UINTCONSTANT = 368, + BOOLCONSTANT = 369, + STRINGCONSTANT = 370, + FIELD_SELECTION = 371, + LEFT_OP = 372, + RIGHT_OP = 373, + INC_OP = 374, + DEC_OP = 375, + LE_OP = 376, + GE_OP = 377, + EQ_OP = 378, + NE_OP = 379, + AND_OP = 380, + OR_OP = 381, + MUL_ASSIGN = 382, + DIV_ASSIGN = 383, + ADD_ASSIGN = 384, + MOD_ASSIGN = 385, + LEFT_ASSIGN = 386, + RIGHT_ASSIGN = 387, + AND_ASSIGN = 388, + XOR_ASSIGN = 389, + OR_ASSIGN = 390, + SUB_ASSIGN = 391, + INVARIANT = 392, + VERSION_TOK = 393, + EXTENSION = 394, + LINE = 395, + COLON = 396, + EOL = 397, + INTERFACE = 398, + OUTPUT = 399, + PRAGMA_DEBUG_ON = 400, + PRAGMA_DEBUG_OFF = 401, + PRAGMA_OPTIMIZE_ON = 402, + PRAGMA_OPTIMIZE_OFF = 403, + PRAGMA_INVARIANT_ALL = 404, + ASM = 405, + CLASS = 406, + UNION = 407, + ENUM = 408, + TYPEDEF = 409, + TEMPLATE = 410, + THIS = 411, + PACKED_TOK = 412, + GOTO = 413, + INLINE_TOK = 414, + NOINLINE = 415, + VOLATILE = 416, + PUBLIC_TOK = 417, + STATIC = 418, + EXTERN = 419, + EXTERNAL = 420, + LONG_TOK = 421, + SHORT_TOK = 422, + DOUBLE_TOK = 423, + HALF = 424, + FIXED_TOK = 425, + UNSIGNED = 426, + DVEC2 = 427, + DVEC3 = 428, + DVEC4 = 429, + FVEC2 = 430, + FVEC3 = 431, + FVEC4 = 432, + SAMPLER2DRECT = 433, + SAMPLER3DRECT = 434, + SAMPLER2DRECTSHADOW = 435, + SIZEOF = 436, + CAST = 437, + NAMESPACE = 438, + USING = 439, + ERROR_TOK = 440, + COMMON = 441, + PARTITION = 442, + ACTIVE = 443, + SAMPLERBUFFER = 444, + FILTER = 445, + IMAGE1D = 446, + IMAGE2D = 447, + IMAGE3D = 448, + IMAGECUBE = 449, + IMAGE1DARRAY = 450, + IMAGE2DARRAY = 451, + IIMAGE1D = 452, + IIMAGE2D = 453, + IIMAGE3D = 454, + IIMAGECUBE = 455, + IIMAGE1DARRAY = 456, + IIMAGE2DARRAY = 457, + UIMAGE1D = 458, + UIMAGE2D = 459, + UIMAGE3D = 460, + UIMAGECUBE = 461, + UIMAGE1DARRAY = 462, + UIMAGE2DARRAY = 463, + IMAGE1DSHADOW = 464, + IMAGE2DSHADOW = 465, + IMAGEBUFFER = 466, + IIMAGEBUFFER = 467, + UIMAGEBUFFER = 468, + IMAGE1DARRAYSHADOW = 469, + IMAGE2DARRAYSHADOW = 470, + ROW_MAJOR = 471, + COLUMN_MAJOR = 472 }; #endif @@ -303,7 +304,7 @@ typedef union YYSTYPE /* Line 2068 of yacc.c */ -#line 307 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.h" +#line 308 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.h" } YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ diff --git a/Engine/Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.inl b/Engine/Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.inl index b07fe0e34218..e6185b5f4f45 100644 --- a/Engine/Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.inl +++ b/Engine/Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.inl @@ -226,142 +226,143 @@ static void yyerror(YYLTYPE *loc, _mesa_glsl_parse_state *st, const char *msg) TEXTURE2D = 333, TEXTURE2D_ARRAY = 334, TEXTURE2DMS = 335, - TEXTURE2DMS_ARRAY = 336, - TEXTURE3D = 337, - TEXTURECUBE = 338, - TEXTURECUBE_ARRAY = 339, - RWBUFFER = 340, - RWTEXTURE1D = 341, - RWTEXTURE1D_ARRAY = 342, - RWTEXTURE2D = 343, - RWTEXTURE2D_ARRAY = 344, - RWTEXTURE3D = 345, - RWSTRUCTUREDBUFFER = 346, - RWBYTEADDRESSBUFFER = 347, - POINT_TOK = 348, - LINE_TOK = 349, - TRIANGLE_TOK = 350, - LINEADJ_TOK = 351, - TRIANGLEADJ_TOK = 352, - POINTSTREAM = 353, - LINESTREAM = 354, - TRIANGLESTREAM = 355, - INPUTPATCH = 356, - OUTPUTPATCH = 357, - STRUCT = 358, - VOID_TOK = 359, - WHILE = 360, - CBUFFER = 361, - IDENTIFIER = 362, - TYPE_IDENTIFIER = 363, - NEW_IDENTIFIER = 364, - FLOATCONSTANT = 365, - INTCONSTANT = 366, - UINTCONSTANT = 367, - BOOLCONSTANT = 368, - STRINGCONSTANT = 369, - FIELD_SELECTION = 370, - LEFT_OP = 371, - RIGHT_OP = 372, - INC_OP = 373, - DEC_OP = 374, - LE_OP = 375, - GE_OP = 376, - EQ_OP = 377, - NE_OP = 378, - AND_OP = 379, - OR_OP = 380, - MUL_ASSIGN = 381, - DIV_ASSIGN = 382, - ADD_ASSIGN = 383, - MOD_ASSIGN = 384, - LEFT_ASSIGN = 385, - RIGHT_ASSIGN = 386, - AND_ASSIGN = 387, - XOR_ASSIGN = 388, - OR_ASSIGN = 389, - SUB_ASSIGN = 390, - INVARIANT = 391, - VERSION_TOK = 392, - EXTENSION = 393, - LINE = 394, - COLON = 395, - EOL = 396, - INTERFACE = 397, - OUTPUT = 398, - PRAGMA_DEBUG_ON = 399, - PRAGMA_DEBUG_OFF = 400, - PRAGMA_OPTIMIZE_ON = 401, - PRAGMA_OPTIMIZE_OFF = 402, - PRAGMA_INVARIANT_ALL = 403, - ASM = 404, - CLASS = 405, - UNION = 406, - ENUM = 407, - TYPEDEF = 408, - TEMPLATE = 409, - THIS = 410, - PACKED_TOK = 411, - GOTO = 412, - INLINE_TOK = 413, - NOINLINE = 414, - VOLATILE = 415, - PUBLIC_TOK = 416, - STATIC = 417, - EXTERN = 418, - EXTERNAL = 419, - LONG_TOK = 420, - SHORT_TOK = 421, - DOUBLE_TOK = 422, - HALF = 423, - FIXED_TOK = 424, - UNSIGNED = 425, - DVEC2 = 426, - DVEC3 = 427, - DVEC4 = 428, - FVEC2 = 429, - FVEC3 = 430, - FVEC4 = 431, - SAMPLER2DRECT = 432, - SAMPLER3DRECT = 433, - SAMPLER2DRECTSHADOW = 434, - SIZEOF = 435, - CAST = 436, - NAMESPACE = 437, - USING = 438, - ERROR_TOK = 439, - COMMON = 440, - PARTITION = 441, - ACTIVE = 442, - SAMPLERBUFFER = 443, - FILTER = 444, - IMAGE1D = 445, - IMAGE2D = 446, - IMAGE3D = 447, - IMAGECUBE = 448, - IMAGE1DARRAY = 449, - IMAGE2DARRAY = 450, - IIMAGE1D = 451, - IIMAGE2D = 452, - IIMAGE3D = 453, - IIMAGECUBE = 454, - IIMAGE1DARRAY = 455, - IIMAGE2DARRAY = 456, - UIMAGE1D = 457, - UIMAGE2D = 458, - UIMAGE3D = 459, - UIMAGECUBE = 460, - UIMAGE1DARRAY = 461, - UIMAGE2DARRAY = 462, - IMAGE1DSHADOW = 463, - IMAGE2DSHADOW = 464, - IMAGEBUFFER = 465, - IIMAGEBUFFER = 466, - UIMAGEBUFFER = 467, - IMAGE1DARRAYSHADOW = 468, - IMAGE2DARRAYSHADOW = 469, - ROW_MAJOR = 470, - COLUMN_MAJOR = 471 + TEXTURE_EXTERNAL = 336, + TEXTURE2DMS_ARRAY = 337, + TEXTURE3D = 338, + TEXTURECUBE = 339, + TEXTURECUBE_ARRAY = 340, + RWBUFFER = 341, + RWTEXTURE1D = 342, + RWTEXTURE1D_ARRAY = 343, + RWTEXTURE2D = 344, + RWTEXTURE2D_ARRAY = 345, + RWTEXTURE3D = 346, + RWSTRUCTUREDBUFFER = 347, + RWBYTEADDRESSBUFFER = 348, + POINT_TOK = 349, + LINE_TOK = 350, + TRIANGLE_TOK = 351, + LINEADJ_TOK = 352, + TRIANGLEADJ_TOK = 353, + POINTSTREAM = 354, + LINESTREAM = 355, + TRIANGLESTREAM = 356, + INPUTPATCH = 357, + OUTPUTPATCH = 358, + STRUCT = 359, + VOID_TOK = 360, + WHILE = 361, + CBUFFER = 362, + IDENTIFIER = 363, + TYPE_IDENTIFIER = 364, + NEW_IDENTIFIER = 365, + FLOATCONSTANT = 366, + INTCONSTANT = 367, + UINTCONSTANT = 368, + BOOLCONSTANT = 369, + STRINGCONSTANT = 370, + FIELD_SELECTION = 371, + LEFT_OP = 372, + RIGHT_OP = 373, + INC_OP = 374, + DEC_OP = 375, + LE_OP = 376, + GE_OP = 377, + EQ_OP = 378, + NE_OP = 379, + AND_OP = 380, + OR_OP = 381, + MUL_ASSIGN = 382, + DIV_ASSIGN = 383, + ADD_ASSIGN = 384, + MOD_ASSIGN = 385, + LEFT_ASSIGN = 386, + RIGHT_ASSIGN = 387, + AND_ASSIGN = 388, + XOR_ASSIGN = 389, + OR_ASSIGN = 390, + SUB_ASSIGN = 391, + INVARIANT = 392, + VERSION_TOK = 393, + EXTENSION = 394, + LINE = 395, + COLON = 396, + EOL = 397, + INTERFACE = 398, + OUTPUT = 399, + PRAGMA_DEBUG_ON = 400, + PRAGMA_DEBUG_OFF = 401, + PRAGMA_OPTIMIZE_ON = 402, + PRAGMA_OPTIMIZE_OFF = 403, + PRAGMA_INVARIANT_ALL = 404, + ASM = 405, + CLASS = 406, + UNION = 407, + ENUM = 408, + TYPEDEF = 409, + TEMPLATE = 410, + THIS = 411, + PACKED_TOK = 412, + GOTO = 413, + INLINE_TOK = 414, + NOINLINE = 415, + VOLATILE = 416, + PUBLIC_TOK = 417, + STATIC = 418, + EXTERN = 419, + EXTERNAL = 420, + LONG_TOK = 421, + SHORT_TOK = 422, + DOUBLE_TOK = 423, + HALF = 424, + FIXED_TOK = 425, + UNSIGNED = 426, + DVEC2 = 427, + DVEC3 = 428, + DVEC4 = 429, + FVEC2 = 430, + FVEC3 = 431, + FVEC4 = 432, + SAMPLER2DRECT = 433, + SAMPLER3DRECT = 434, + SAMPLER2DRECTSHADOW = 435, + SIZEOF = 436, + CAST = 437, + NAMESPACE = 438, + USING = 439, + ERROR_TOK = 440, + COMMON = 441, + PARTITION = 442, + ACTIVE = 443, + SAMPLERBUFFER = 444, + FILTER = 445, + IMAGE1D = 446, + IMAGE2D = 447, + IMAGE3D = 448, + IMAGECUBE = 449, + IMAGE1DARRAY = 450, + IMAGE2DARRAY = 451, + IIMAGE1D = 452, + IIMAGE2D = 453, + IIMAGE3D = 454, + IIMAGECUBE = 455, + IIMAGE1DARRAY = 456, + IIMAGE2DARRAY = 457, + UIMAGE1D = 458, + UIMAGE2D = 459, + UIMAGE3D = 460, + UIMAGECUBE = 461, + UIMAGE1DARRAY = 462, + UIMAGE2DARRAY = 463, + IMAGE1DSHADOW = 464, + IMAGE2DSHADOW = 465, + IMAGEBUFFER = 466, + IIMAGEBUFFER = 467, + UIMAGEBUFFER = 468, + IMAGE1DARRAYSHADOW = 469, + IMAGE2DARRAYSHADOW = 470, + ROW_MAJOR = 471, + COLUMN_MAJOR = 472 }; #endif @@ -414,7 +415,7 @@ typedef union YYSTYPE /* Line 293 of yacc.c */ -#line 418 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.inl" +#line 419 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.inl" } YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ @@ -439,7 +440,7 @@ typedef struct YYLTYPE /* Line 343 of yacc.c */ -#line 443 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.inl" +#line 444 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.inl" #ifdef short # undef short @@ -660,20 +661,20 @@ union yyalloc /* YYFINAL -- State number of the termination state. */ #define YYFINAL 3 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 6141 +#define YYLAST 6189 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 241 +#define YYNTOKENS 242 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 104 /* YYNRULES -- Number of rules. */ -#define YYNRULES 361 +#define YYNRULES 362 /* YYNRULES -- Number of states. */ -#define YYNSTATES 557 +#define YYNSTATES 558 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 -#define YYMAXUTOK 471 +#define YYMAXUTOK 472 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) @@ -684,16 +685,16 @@ static const yytype_uint8 yytranslate[] = 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 225, 2, 2, 2, 229, 232, 2, - 217, 218, 227, 223, 222, 224, 221, 228, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 236, 238, - 230, 237, 231, 235, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 226, 2, 2, 2, 230, 233, 2, + 218, 219, 228, 224, 223, 225, 222, 229, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 237, 239, + 231, 238, 232, 236, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 219, 2, 220, 233, 2, 2, 2, 2, 2, + 2, 220, 2, 221, 234, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 239, 234, 240, 226, 2, 2, 2, + 2, 2, 2, 240, 235, 241, 227, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -728,7 +729,7 @@ static const yytype_uint8 yytranslate[] = 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, - 215, 216 + 215, 216, 217 }; #if YYDEBUG @@ -762,84 +763,84 @@ static const yytype_uint16 yyprhs[] = 670, 672, 674, 676, 678, 680, 682, 684, 686, 688, 690, 692, 694, 696, 698, 700, 702, 704, 706, 708, 710, 712, 714, 716, 718, 720, 722, 724, 726, 728, - 730, 732, 734, 736, 742, 750, 755, 760, 767, 771, - 777, 782, 784, 787, 791, 793, 796, 798, 801, 804, - 806, 808, 812, 814, 816, 820, 827, 832, 837, 839, - 843, 845, 849, 852, 854, 856, 858, 861, 864, 866, - 868, 870, 872, 874, 876, 879, 880, 885, 887, 889, - 892, 896, 898, 901, 903, 906, 912, 916, 918, 920, - 925, 931, 934, 938, 942, 945, 947, 950, 953, 956, - 958, 961, 967, 975, 982, 984, 986, 988, 989, 992, - 996, 999, 1002, 1005, 1009, 1012, 1014, 1016, 1018, 1020, - 1022, 1026, 1030, 1034, 1041, 1048, 1051, 1053, 1056, 1060, - 1062, 1065 + 730, 732, 734, 736, 738, 744, 752, 757, 762, 769, + 773, 779, 784, 786, 789, 793, 795, 798, 800, 803, + 806, 808, 810, 814, 816, 818, 822, 829, 834, 839, + 841, 845, 847, 851, 854, 856, 858, 860, 863, 866, + 868, 870, 872, 874, 876, 878, 881, 882, 887, 889, + 891, 894, 898, 900, 903, 905, 908, 914, 918, 920, + 922, 927, 933, 936, 940, 944, 947, 949, 952, 955, + 958, 960, 963, 969, 977, 984, 986, 988, 990, 991, + 994, 998, 1001, 1004, 1007, 1011, 1014, 1016, 1018, 1020, + 1022, 1024, 1028, 1032, 1036, 1043, 1050, 1053, 1055, 1058, + 1062, 1064, 1067 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yytype_int16 yyrhs[] = { - 242, 0, -1, -1, 243, 245, -1, 107, -1, 108, - -1, 109, -1, 338, -1, 245, 338, -1, 107, -1, - 109, -1, 246, -1, 111, -1, 112, -1, 110, -1, - 113, -1, 217, 276, 218, -1, 247, -1, 248, 219, - 249, 220, -1, 250, -1, 248, 221, 244, -1, 248, - 118, -1, 248, 119, -1, 276, -1, 251, -1, 252, - -1, 248, 221, 257, -1, 254, 218, -1, 253, 218, - -1, 255, 104, -1, 255, -1, 255, 274, -1, 254, - 222, 274, -1, 256, 217, -1, 295, -1, 246, -1, - 115, -1, 259, 218, -1, 258, 218, -1, 260, 104, - -1, 260, -1, 260, 274, -1, 259, 222, 274, -1, - 246, 217, -1, 248, -1, 118, 261, -1, 119, 261, - -1, 262, 261, -1, 217, 298, 218, 261, -1, 217, - 3, 298, 218, 261, -1, 217, 298, 3, 218, 261, - -1, 223, -1, 224, -1, 225, -1, 226, -1, 261, - -1, 263, 227, 261, -1, 263, 228, 261, -1, 263, - 229, 261, -1, 263, -1, 264, 223, 263, -1, 264, - 224, 263, -1, 264, -1, 265, 116, 264, -1, 265, - 117, 264, -1, 265, -1, 266, 230, 265, -1, 266, - 231, 265, -1, 266, 120, 265, -1, 266, 121, 265, - -1, 266, -1, 267, 122, 266, -1, 267, 123, 266, - -1, 267, -1, 268, 232, 267, -1, 268, -1, 269, - 233, 268, -1, 269, -1, 270, 234, 269, -1, 270, - -1, 271, 124, 270, -1, 271, -1, 272, 125, 271, - -1, 272, -1, 272, 235, 276, 236, 274, -1, 273, - -1, 261, 275, 274, -1, 237, -1, 126, -1, 127, - -1, 129, -1, 128, -1, 135, -1, 130, -1, 131, - -1, 132, -1, 133, -1, 134, -1, 274, -1, 276, - 222, 274, -1, 273, -1, 280, 238, -1, 278, -1, - 288, 238, -1, 281, 218, -1, 281, 218, 236, 244, - -1, 283, -1, 282, -1, 283, 285, -1, 282, 222, - 285, -1, 290, 246, 217, -1, 158, 290, 246, 217, - -1, 295, 244, -1, 295, 244, 237, 277, -1, 295, - 244, 236, 244, -1, 295, 312, -1, 295, 244, 219, - 277, 220, 236, 244, -1, 292, 286, 284, -1, 286, - 292, 284, -1, 292, 286, 292, 284, -1, 286, 284, - -1, 292, 284, -1, 284, -1, 292, 286, 287, -1, - 286, 287, -1, 35, -1, 36, -1, 37, -1, 35, - 36, -1, 36, 35, -1, 93, -1, 94, -1, 95, - -1, 96, -1, 97, -1, 295, -1, 289, -1, 288, - 222, 244, -1, 288, 222, 244, 219, 220, -1, 288, - 222, 312, -1, 288, 222, 244, 219, 220, 237, 313, - -1, 288, 222, 312, 237, 313, -1, 288, 222, 244, - 237, 313, -1, 290, -1, 290, 244, -1, 290, 244, - 219, 220, -1, 290, 312, -1, 290, 244, 219, 220, - 237, 313, -1, 290, 312, 237, 313, -1, 290, 244, - 237, 313, -1, 136, 246, -1, 295, -1, 293, 295, - -1, 45, -1, 44, -1, 43, -1, 291, -1, 42, - 291, -1, 291, 42, -1, 42, -1, 3, -1, 38, - -1, 294, -1, 291, -1, 291, 294, -1, 136, 294, - -1, 136, 291, 294, -1, 136, -1, 3, -1, 39, + 243, 0, -1, -1, 244, 246, -1, 108, -1, 109, + -1, 110, -1, 339, -1, 246, 339, -1, 108, -1, + 110, -1, 247, -1, 112, -1, 113, -1, 111, -1, + 114, -1, 218, 277, 219, -1, 248, -1, 249, 220, + 250, 221, -1, 251, -1, 249, 222, 245, -1, 249, + 119, -1, 249, 120, -1, 277, -1, 252, -1, 253, + -1, 249, 222, 258, -1, 255, 219, -1, 254, 219, + -1, 256, 105, -1, 256, -1, 256, 275, -1, 255, + 223, 275, -1, 257, 218, -1, 296, -1, 247, -1, + 116, -1, 260, 219, -1, 259, 219, -1, 261, 105, + -1, 261, -1, 261, 275, -1, 260, 223, 275, -1, + 247, 218, -1, 249, -1, 119, 262, -1, 120, 262, + -1, 263, 262, -1, 218, 299, 219, 262, -1, 218, + 3, 299, 219, 262, -1, 218, 299, 3, 219, 262, + -1, 224, -1, 225, -1, 226, -1, 227, -1, 262, + -1, 264, 228, 262, -1, 264, 229, 262, -1, 264, + 230, 262, -1, 264, -1, 265, 224, 264, -1, 265, + 225, 264, -1, 265, -1, 266, 117, 265, -1, 266, + 118, 265, -1, 266, -1, 267, 231, 266, -1, 267, + 232, 266, -1, 267, 121, 266, -1, 267, 122, 266, + -1, 267, -1, 268, 123, 267, -1, 268, 124, 267, + -1, 268, -1, 269, 233, 268, -1, 269, -1, 270, + 234, 269, -1, 270, -1, 271, 235, 270, -1, 271, + -1, 272, 125, 271, -1, 272, -1, 273, 126, 272, + -1, 273, -1, 273, 236, 277, 237, 275, -1, 274, + -1, 262, 276, 275, -1, 238, -1, 127, -1, 128, + -1, 130, -1, 129, -1, 136, -1, 131, -1, 132, + -1, 133, -1, 134, -1, 135, -1, 275, -1, 277, + 223, 275, -1, 274, -1, 281, 239, -1, 279, -1, + 289, 239, -1, 282, 219, -1, 282, 219, 237, 245, + -1, 284, -1, 283, -1, 284, 286, -1, 283, 223, + 286, -1, 291, 247, 218, -1, 159, 291, 247, 218, + -1, 296, 245, -1, 296, 245, 238, 278, -1, 296, + 245, 237, 245, -1, 296, 313, -1, 296, 245, 220, + 278, 221, 237, 245, -1, 293, 287, 285, -1, 287, + 293, 285, -1, 293, 287, 293, 285, -1, 287, 285, + -1, 293, 285, -1, 285, -1, 293, 287, 288, -1, + 287, 288, -1, 35, -1, 36, -1, 37, -1, 35, + 36, -1, 36, 35, -1, 94, -1, 95, -1, 96, + -1, 97, -1, 98, -1, 296, -1, 290, -1, 289, + 223, 245, -1, 289, 223, 245, 220, 221, -1, 289, + 223, 313, -1, 289, 223, 245, 220, 221, 238, 314, + -1, 289, 223, 313, 238, 314, -1, 289, 223, 245, + 238, 314, -1, 291, -1, 291, 245, -1, 291, 245, + 220, 221, -1, 291, 313, -1, 291, 245, 220, 221, + 238, 314, -1, 291, 313, 238, 314, -1, 291, 245, + 238, 314, -1, 137, 247, -1, 296, -1, 294, 296, + -1, 45, -1, 44, -1, 43, -1, 292, -1, 42, + 292, -1, 292, 42, -1, 42, -1, 3, -1, 38, + -1, 295, -1, 292, -1, 292, 295, -1, 137, 295, + -1, 137, 292, 295, -1, 137, -1, 3, -1, 39, -1, 42, 39, -1, 35, -1, 36, -1, 42, 35, - -1, 42, 36, -1, 38, -1, 215, -1, 216, -1, - 162, -1, 3, 162, -1, 162, 3, -1, 40, -1, - 41, -1, 296, -1, 298, -1, 297, -1, 298, 219, - 220, -1, 297, 219, 220, -1, 298, 219, 277, 220, - -1, 297, 219, 277, 220, -1, 299, -1, 300, -1, - 300, 230, 299, 222, 111, 231, -1, 300, 230, 299, - 231, -1, 91, 230, 108, 231, -1, 301, 230, 108, - 231, -1, 302, 230, 108, 222, 111, 231, -1, 303, - 230, 108, 222, 111, 231, -1, 304, -1, 108, -1, - 104, -1, 5, -1, 31, -1, 6, -1, 7, -1, + -1, 42, 36, -1, 38, -1, 216, -1, 217, -1, + 163, -1, 3, 163, -1, 163, 3, -1, 40, -1, + 41, -1, 297, -1, 299, -1, 298, -1, 299, 220, + 221, -1, 298, 220, 221, -1, 299, 220, 278, 221, + -1, 298, 220, 278, 221, -1, 300, -1, 301, -1, + 301, 231, 300, 223, 112, 232, -1, 301, 231, 300, + 232, -1, 92, 231, 109, 232, -1, 302, 231, 109, + 232, -1, 303, 231, 109, 223, 112, 232, -1, 304, + 231, 109, 223, 112, 232, -1, 305, -1, 109, -1, + 105, -1, 5, -1, 31, -1, 6, -1, 7, -1, 4, -1, 28, -1, 29, -1, 30, -1, 32, -1, 33, -1, 34, -1, 19, -1, 20, -1, 21, -1, 22, -1, 23, -1, 24, -1, 25, -1, 26, -1, @@ -849,42 +850,42 @@ static const yytype_int16 yyrhs[] = 60, -1, 61, -1, 62, -1, 63, -1, 73, -1, 74, -1, 75, -1, 76, -1, 77, -1, 78, -1, 79, -1, 80, -1, 81, -1, 82, -1, 83, -1, - 84, -1, 85, -1, 92, -1, 86, -1, 87, -1, - 88, -1, 89, -1, 90, -1, 98, -1, 99, -1, - 100, -1, 101, -1, 102, -1, 103, 244, 239, 306, - 240, -1, 103, 244, 236, 108, 239, 306, 240, -1, - 103, 239, 306, 240, -1, 103, 244, 239, 240, -1, - 103, 244, 236, 108, 239, 240, -1, 103, 239, 240, - -1, 106, 244, 239, 306, 240, -1, 106, 244, 239, - 240, -1, 307, -1, 306, 307, -1, 308, 310, 238, - -1, 295, -1, 309, 295, -1, 291, -1, 42, 291, - -1, 291, 42, -1, 42, -1, 311, -1, 310, 222, - 311, -1, 244, -1, 312, -1, 244, 236, 244, -1, - 244, 219, 277, 220, 236, 244, -1, 244, 219, 277, - 220, -1, 312, 219, 277, 220, -1, 274, -1, 239, - 314, 240, -1, 313, -1, 314, 222, 313, -1, 314, - 222, -1, 279, -1, 318, -1, 317, -1, 342, 318, - -1, 342, 317, -1, 315, -1, 323, -1, 324, -1, - 327, -1, 333, -1, 337, -1, 239, 240, -1, -1, - 239, 319, 322, 240, -1, 321, -1, 317, -1, 239, - 240, -1, 239, 322, 240, -1, 316, -1, 322, 316, - -1, 238, -1, 276, 238, -1, 13, 217, 276, 218, - 325, -1, 316, 11, 316, -1, 316, -1, 276, -1, - 290, 244, 237, 313, -1, 16, 217, 276, 218, 328, - -1, 239, 240, -1, 239, 332, 240, -1, 17, 276, - 236, -1, 18, 236, -1, 329, -1, 330, 329, -1, - 330, 316, -1, 331, 316, -1, 331, -1, 332, 331, - -1, 105, 217, 326, 218, 320, -1, 10, 316, 105, - 217, 276, 218, 238, -1, 12, 217, 334, 336, 218, - 320, -1, 323, -1, 315, -1, 326, -1, -1, 335, - 238, -1, 335, 238, 276, -1, 9, 238, -1, 8, - 238, -1, 15, 238, -1, 15, 276, 238, -1, 14, - 238, -1, 343, -1, 344, -1, 277, -1, 114, -1, - 339, -1, 340, 222, 339, -1, 219, 244, 220, -1, - 219, 299, 220, -1, 219, 244, 217, 340, 218, 220, - -1, 219, 299, 217, 340, 218, 220, -1, 342, 341, - -1, 341, -1, 280, 321, -1, 342, 280, 321, -1, - 278, -1, 288, 238, -1, 305, -1 + 84, -1, 85, -1, 86, -1, 93, -1, 87, -1, + 88, -1, 89, -1, 90, -1, 91, -1, 99, -1, + 100, -1, 101, -1, 102, -1, 103, -1, 104, 245, + 240, 307, 241, -1, 104, 245, 237, 109, 240, 307, + 241, -1, 104, 240, 307, 241, -1, 104, 245, 240, + 241, -1, 104, 245, 237, 109, 240, 241, -1, 104, + 240, 241, -1, 107, 245, 240, 307, 241, -1, 107, + 245, 240, 241, -1, 308, -1, 307, 308, -1, 309, + 311, 239, -1, 296, -1, 310, 296, -1, 292, -1, + 42, 292, -1, 292, 42, -1, 42, -1, 312, -1, + 311, 223, 312, -1, 245, -1, 313, -1, 245, 237, + 245, -1, 245, 220, 278, 221, 237, 245, -1, 245, + 220, 278, 221, -1, 313, 220, 278, 221, -1, 275, + -1, 240, 315, 241, -1, 314, -1, 315, 223, 314, + -1, 315, 223, -1, 280, -1, 319, -1, 318, -1, + 343, 319, -1, 343, 318, -1, 316, -1, 324, -1, + 325, -1, 328, -1, 334, -1, 338, -1, 240, 241, + -1, -1, 240, 320, 323, 241, -1, 322, -1, 318, + -1, 240, 241, -1, 240, 323, 241, -1, 317, -1, + 323, 317, -1, 239, -1, 277, 239, -1, 13, 218, + 277, 219, 326, -1, 317, 11, 317, -1, 317, -1, + 277, -1, 291, 245, 238, 314, -1, 16, 218, 277, + 219, 329, -1, 240, 241, -1, 240, 333, 241, -1, + 17, 277, 237, -1, 18, 237, -1, 330, -1, 331, + 330, -1, 331, 317, -1, 332, 317, -1, 332, -1, + 333, 332, -1, 106, 218, 327, 219, 321, -1, 10, + 317, 106, 218, 277, 219, 239, -1, 12, 218, 335, + 337, 219, 321, -1, 324, -1, 316, -1, 327, -1, + -1, 336, 239, -1, 336, 239, 277, -1, 9, 239, + -1, 8, 239, -1, 15, 239, -1, 15, 277, 239, + -1, 14, 239, -1, 344, -1, 345, -1, 278, -1, + 115, -1, 340, -1, 341, 223, 340, -1, 220, 245, + 221, -1, 220, 300, 221, -1, 220, 245, 218, 341, + 219, 221, -1, 220, 300, 218, 341, 219, 221, -1, + 343, 342, -1, 342, -1, 281, 322, -1, 343, 281, + 322, -1, 279, -1, 289, 239, -1, 306, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ @@ -915,18 +916,18 @@ static const yytype_uint16 yyrline[] = 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1467, 1468, 1469, 1470, 1471, 1472, 1473, 1474, 1475, 1476, 1511, 1512, 1513, 1514, 1515, 1516, 1517, 1518, 1519, - 1520, 1521, 1522, 1523, 1524, 1525, 1526, 1527, 1531, 1532, - 1533, 1537, 1541, 1545, 1552, 1559, 1565, 1572, 1579, 1588, - 1594, 1602, 1607, 1615, 1625, 1632, 1643, 1644, 1649, 1654, - 1662, 1667, 1675, 1682, 1687, 1695, 1705, 1711, 1720, 1721, - 1730, 1735, 1740, 1747, 1753, 1754, 1755, 1760, 1768, 1769, - 1770, 1771, 1772, 1773, 1777, 1784, 1783, 1797, 1798, 1802, - 1808, 1817, 1827, 1839, 1845, 1854, 1863, 1868, 1876, 1880, - 1898, 1906, 1911, 1919, 1924, 1932, 1940, 1948, 1956, 1964, - 1972, 1980, 1987, 1994, 2004, 2005, 2009, 2011, 2017, 2022, - 2031, 2037, 2043, 2049, 2055, 2064, 2065, 2069, 2075, 2084, - 2088, 2096, 2102, 2108, 2115, 2125, 2130, 2137, 2147, 2161, - 2165, 2173 + 1520, 1521, 1522, 1523, 1524, 1525, 1526, 1527, 1528, 1532, + 1533, 1534, 1538, 1542, 1546, 1553, 1560, 1566, 1573, 1580, + 1589, 1595, 1603, 1608, 1616, 1626, 1633, 1644, 1645, 1650, + 1655, 1663, 1668, 1676, 1683, 1688, 1696, 1706, 1712, 1721, + 1722, 1731, 1736, 1741, 1748, 1754, 1755, 1756, 1761, 1769, + 1770, 1771, 1772, 1773, 1774, 1778, 1785, 1784, 1798, 1799, + 1803, 1809, 1818, 1828, 1840, 1846, 1855, 1864, 1869, 1877, + 1881, 1899, 1907, 1912, 1920, 1925, 1933, 1941, 1949, 1957, + 1965, 1973, 1981, 1988, 1995, 2005, 2006, 2010, 2012, 2018, + 2023, 2032, 2038, 2044, 2050, 2056, 2065, 2066, 2070, 2076, + 2085, 2089, 2097, 2103, 2109, 2116, 2126, 2131, 2138, 2148, + 2162, 2166, 2174 }; #endif @@ -948,29 +949,29 @@ static const char *const yytname[] = "FMAT2X3", "FMAT2X4", "FMAT3X2", "FMAT3X3", "FMAT3X4", "FMAT4X2", "FMAT4X3", "FMAT4X4", "SAMPLERSTATE", "SAMPLERSTATE_CMP", "BUFFER", "TEXTURE1D", "TEXTURE1D_ARRAY", "TEXTURE2D", "TEXTURE2D_ARRAY", - "TEXTURE2DMS", "TEXTURE2DMS_ARRAY", "TEXTURE3D", "TEXTURECUBE", - "TEXTURECUBE_ARRAY", "RWBUFFER", "RWTEXTURE1D", "RWTEXTURE1D_ARRAY", - "RWTEXTURE2D", "RWTEXTURE2D_ARRAY", "RWTEXTURE3D", "RWSTRUCTUREDBUFFER", - "RWBYTEADDRESSBUFFER", "POINT_TOK", "LINE_TOK", "TRIANGLE_TOK", - "LINEADJ_TOK", "TRIANGLEADJ_TOK", "POINTSTREAM", "LINESTREAM", - "TRIANGLESTREAM", "INPUTPATCH", "OUTPUTPATCH", "STRUCT", "VOID_TOK", - "WHILE", "CBUFFER", "IDENTIFIER", "TYPE_IDENTIFIER", "NEW_IDENTIFIER", - "FLOATCONSTANT", "INTCONSTANT", "UINTCONSTANT", "BOOLCONSTANT", - "STRINGCONSTANT", "FIELD_SELECTION", "LEFT_OP", "RIGHT_OP", "INC_OP", - "DEC_OP", "LE_OP", "GE_OP", "EQ_OP", "NE_OP", "AND_OP", "OR_OP", - "MUL_ASSIGN", "DIV_ASSIGN", "ADD_ASSIGN", "MOD_ASSIGN", "LEFT_ASSIGN", - "RIGHT_ASSIGN", "AND_ASSIGN", "XOR_ASSIGN", "OR_ASSIGN", "SUB_ASSIGN", - "INVARIANT", "VERSION_TOK", "EXTENSION", "LINE", "COLON", "EOL", - "INTERFACE", "OUTPUT", "PRAGMA_DEBUG_ON", "PRAGMA_DEBUG_OFF", - "PRAGMA_OPTIMIZE_ON", "PRAGMA_OPTIMIZE_OFF", "PRAGMA_INVARIANT_ALL", - "ASM", "CLASS", "UNION", "ENUM", "TYPEDEF", "TEMPLATE", "THIS", - "PACKED_TOK", "GOTO", "INLINE_TOK", "NOINLINE", "VOLATILE", "PUBLIC_TOK", - "STATIC", "EXTERN", "EXTERNAL", "LONG_TOK", "SHORT_TOK", "DOUBLE_TOK", - "HALF", "FIXED_TOK", "UNSIGNED", "DVEC2", "DVEC3", "DVEC4", "FVEC2", - "FVEC3", "FVEC4", "SAMPLER2DRECT", "SAMPLER3DRECT", - "SAMPLER2DRECTSHADOW", "SIZEOF", "CAST", "NAMESPACE", "USING", - "ERROR_TOK", "COMMON", "PARTITION", "ACTIVE", "SAMPLERBUFFER", "FILTER", - "IMAGE1D", "IMAGE2D", "IMAGE3D", "IMAGECUBE", "IMAGE1DARRAY", + "TEXTURE2DMS", "TEXTURE_EXTERNAL", "TEXTURE2DMS_ARRAY", "TEXTURE3D", + "TEXTURECUBE", "TEXTURECUBE_ARRAY", "RWBUFFER", "RWTEXTURE1D", + "RWTEXTURE1D_ARRAY", "RWTEXTURE2D", "RWTEXTURE2D_ARRAY", "RWTEXTURE3D", + "RWSTRUCTUREDBUFFER", "RWBYTEADDRESSBUFFER", "POINT_TOK", "LINE_TOK", + "TRIANGLE_TOK", "LINEADJ_TOK", "TRIANGLEADJ_TOK", "POINTSTREAM", + "LINESTREAM", "TRIANGLESTREAM", "INPUTPATCH", "OUTPUTPATCH", "STRUCT", + "VOID_TOK", "WHILE", "CBUFFER", "IDENTIFIER", "TYPE_IDENTIFIER", + "NEW_IDENTIFIER", "FLOATCONSTANT", "INTCONSTANT", "UINTCONSTANT", + "BOOLCONSTANT", "STRINGCONSTANT", "FIELD_SELECTION", "LEFT_OP", + "RIGHT_OP", "INC_OP", "DEC_OP", "LE_OP", "GE_OP", "EQ_OP", "NE_OP", + "AND_OP", "OR_OP", "MUL_ASSIGN", "DIV_ASSIGN", "ADD_ASSIGN", + "MOD_ASSIGN", "LEFT_ASSIGN", "RIGHT_ASSIGN", "AND_ASSIGN", "XOR_ASSIGN", + "OR_ASSIGN", "SUB_ASSIGN", "INVARIANT", "VERSION_TOK", "EXTENSION", + "LINE", "COLON", "EOL", "INTERFACE", "OUTPUT", "PRAGMA_DEBUG_ON", + "PRAGMA_DEBUG_OFF", "PRAGMA_OPTIMIZE_ON", "PRAGMA_OPTIMIZE_OFF", + "PRAGMA_INVARIANT_ALL", "ASM", "CLASS", "UNION", "ENUM", "TYPEDEF", + "TEMPLATE", "THIS", "PACKED_TOK", "GOTO", "INLINE_TOK", "NOINLINE", + "VOLATILE", "PUBLIC_TOK", "STATIC", "EXTERN", "EXTERNAL", "LONG_TOK", + "SHORT_TOK", "DOUBLE_TOK", "HALF", "FIXED_TOK", "UNSIGNED", "DVEC2", + "DVEC3", "DVEC4", "FVEC2", "FVEC3", "FVEC4", "SAMPLER2DRECT", + "SAMPLER3DRECT", "SAMPLER2DRECTSHADOW", "SIZEOF", "CAST", "NAMESPACE", + "USING", "ERROR_TOK", "COMMON", "PARTITION", "ACTIVE", "SAMPLERBUFFER", + "FILTER", "IMAGE1D", "IMAGE2D", "IMAGE3D", "IMAGECUBE", "IMAGE1DARRAY", "IMAGE2DARRAY", "IIMAGE1D", "IIMAGE2D", "IIMAGE3D", "IIMAGECUBE", "IIMAGE1DARRAY", "IIMAGE2DARRAY", "UIMAGE1D", "UIMAGE2D", "UIMAGE3D", "UIMAGECUBE", "UIMAGE1DARRAY", "UIMAGE2DARRAY", "IMAGE1DSHADOW", @@ -1048,53 +1049,53 @@ static const yytype_uint16 yytoknum[] = 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, - 465, 466, 467, 468, 469, 470, 471, 40, 41, 91, - 93, 46, 44, 43, 45, 33, 126, 42, 47, 37, - 60, 62, 38, 94, 124, 63, 58, 61, 59, 123, - 125 + 465, 466, 467, 468, 469, 470, 471, 472, 40, 41, + 91, 93, 46, 44, 43, 45, 33, 126, 42, 47, + 37, 60, 62, 38, 94, 124, 63, 58, 61, 59, + 123, 125 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint16 yyr1[] = { - 0, 241, 243, 242, 244, 244, 244, 245, 245, 246, - 246, 247, 247, 247, 247, 247, 247, 248, 248, 248, - 248, 248, 248, 249, 250, 251, 251, 252, 252, 253, - 253, 254, 254, 255, 256, 256, 256, 257, 257, 258, - 258, 259, 259, 260, 261, 261, 261, 261, 261, 261, - 261, 262, 262, 262, 262, 263, 263, 263, 263, 264, - 264, 264, 265, 265, 265, 266, 266, 266, 266, 266, - 267, 267, 267, 268, 268, 269, 269, 270, 270, 271, - 271, 272, 272, 273, 273, 274, 274, 275, 275, 275, - 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, - 277, 278, 279, 279, 280, 280, 281, 281, 282, 282, - 283, 283, 284, 284, 284, 284, 284, 285, 285, 285, - 285, 285, 285, 285, 285, 286, 286, 286, 286, 286, - 286, 286, 286, 286, 286, 287, 288, 288, 288, 288, - 288, 288, 288, 289, 289, 289, 289, 289, 289, 289, - 289, 290, 290, 291, 291, 291, 292, 292, 292, 292, - 292, 292, 293, 293, 293, 293, 293, 293, 294, 294, - 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, - 294, 294, 294, 295, 296, 296, 297, 297, 297, 297, - 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, + 0, 242, 244, 243, 245, 245, 245, 246, 246, 247, + 247, 248, 248, 248, 248, 248, 248, 249, 249, 249, + 249, 249, 249, 250, 251, 252, 252, 253, 253, 254, + 254, 255, 255, 256, 257, 257, 257, 258, 258, 259, + 259, 260, 260, 261, 262, 262, 262, 262, 262, 262, + 262, 263, 263, 263, 263, 264, 264, 264, 264, 265, + 265, 265, 266, 266, 266, 267, 267, 267, 267, 267, + 268, 268, 268, 269, 269, 270, 270, 271, 271, 272, + 272, 273, 273, 274, 274, 275, 275, 276, 276, 276, + 276, 276, 276, 276, 276, 276, 276, 276, 277, 277, + 278, 279, 280, 280, 281, 281, 282, 282, 283, 283, + 284, 284, 285, 285, 285, 285, 285, 286, 286, 286, + 286, 286, 286, 286, 286, 287, 287, 287, 287, 287, + 287, 287, 287, 287, 287, 288, 289, 289, 289, 289, + 289, 289, 289, 290, 290, 290, 290, 290, 290, 290, + 290, 291, 291, 292, 292, 292, 293, 293, 293, 293, + 293, 293, 294, 294, 294, 294, 294, 294, 295, 295, + 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, + 295, 295, 295, 296, 297, 297, 298, 298, 298, 298, 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, - 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, - 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, - 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, - 299, 300, 300, 300, 300, 300, 300, 300, 300, 300, - 300, 300, 300, 300, 300, 300, 300, 300, 301, 301, - 301, 302, 303, 304, 304, 304, 304, 304, 304, 305, - 305, 306, 306, 307, 308, 308, 309, 309, 309, 309, - 310, 310, 311, 311, 311, 311, 312, 312, 313, 313, - 314, 314, 314, 315, 316, 316, 316, 316, 317, 317, - 317, 317, 317, 317, 318, 319, 318, 320, 320, 321, - 321, 322, 322, 323, 323, 324, 325, 325, 326, 326, - 327, 328, 328, 329, 329, 330, 330, 331, 331, 332, - 332, 333, 333, 333, 334, 334, 335, 335, 336, 336, - 337, 337, 337, 337, 337, 338, 338, 339, 339, 340, - 340, 341, 341, 341, 341, 342, 342, 343, 343, 344, - 344, 344 + 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, + 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, + 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, + 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, + 300, 301, 301, 301, 301, 301, 301, 301, 301, 301, + 301, 301, 301, 301, 301, 301, 301, 301, 301, 302, + 302, 302, 303, 304, 305, 305, 305, 305, 305, 305, + 306, 306, 307, 307, 308, 309, 309, 310, 310, 310, + 310, 311, 311, 312, 312, 312, 312, 313, 313, 314, + 314, 315, 315, 315, 316, 317, 317, 317, 317, 318, + 318, 318, 318, 318, 318, 319, 320, 319, 321, 321, + 322, 322, 323, 323, 324, 324, 325, 326, 326, 327, + 327, 328, 329, 329, 330, 330, 331, 331, 332, 332, + 333, 333, 334, 334, 334, 335, 335, 336, 336, 337, + 337, 338, 338, 338, 338, 338, 339, 339, 340, 340, + 341, 341, 342, 342, 342, 342, 343, 343, 344, 344, + 345, 345, 345 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ @@ -1126,17 +1127,17 @@ static const yytype_uint8 yyr2[] = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 5, 7, 4, 4, 6, 3, 5, - 4, 1, 2, 3, 1, 2, 1, 2, 2, 1, - 1, 3, 1, 1, 3, 6, 4, 4, 1, 3, - 1, 3, 2, 1, 1, 1, 2, 2, 1, 1, - 1, 1, 1, 1, 2, 0, 4, 1, 1, 2, - 3, 1, 2, 1, 2, 5, 3, 1, 1, 4, - 5, 2, 3, 3, 2, 1, 2, 2, 2, 1, - 2, 5, 7, 6, 1, 1, 1, 0, 2, 3, - 2, 2, 2, 3, 2, 1, 1, 1, 1, 1, - 3, 3, 3, 6, 6, 2, 1, 2, 3, 1, - 2, 1 + 1, 1, 1, 1, 5, 7, 4, 4, 6, 3, + 5, 4, 1, 2, 3, 1, 2, 1, 2, 2, + 1, 1, 3, 1, 1, 3, 6, 4, 4, 1, + 3, 1, 3, 2, 1, 1, 1, 2, 2, 1, + 1, 1, 1, 1, 1, 2, 0, 4, 1, 1, + 2, 3, 1, 2, 1, 2, 5, 3, 1, 1, + 4, 5, 2, 3, 3, 2, 1, 2, 2, 2, + 1, 2, 5, 7, 6, 1, 1, 1, 0, 2, + 3, 2, 2, 2, 3, 2, 1, 1, 1, 1, + 1, 3, 3, 3, 6, 6, 2, 1, 2, 3, + 1, 2, 1 }; /* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. @@ -1150,151 +1151,151 @@ static const yytype_uint16 yydefact[] = 182, 0, 155, 154, 153, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, - 246, 247, 248, 249, 250, 251, 253, 254, 255, 256, - 257, 0, 252, 258, 259, 260, 261, 262, 0, 200, - 0, 199, 167, 0, 178, 176, 177, 0, 3, 359, - 0, 0, 107, 106, 0, 136, 143, 163, 0, 162, - 151, 183, 185, 184, 190, 191, 0, 0, 0, 198, - 361, 7, 356, 0, 345, 346, 179, 173, 174, 170, - 0, 4, 5, 6, 0, 0, 0, 9, 10, 150, - 0, 165, 167, 0, 180, 0, 0, 8, 101, 0, - 357, 104, 0, 160, 125, 126, 127, 161, 159, 130, - 131, 132, 133, 134, 122, 108, 0, 156, 0, 0, - 0, 360, 4, 6, 144, 0, 146, 164, 152, 0, - 0, 0, 0, 0, 0, 0, 0, 355, 0, 279, - 268, 276, 274, 0, 271, 0, 0, 0, 0, 0, - 166, 0, 0, 351, 0, 352, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 14, 12, 13, 15, 36, - 0, 0, 0, 51, 52, 53, 54, 313, 305, 309, - 11, 17, 44, 19, 24, 25, 0, 0, 30, 0, - 55, 0, 59, 62, 65, 70, 73, 75, 77, 79, - 81, 83, 85, 98, 0, 102, 293, 0, 0, 151, - 298, 311, 295, 294, 0, 299, 300, 301, 302, 303, - 0, 0, 109, 128, 129, 157, 120, 124, 0, 135, - 158, 121, 0, 112, 115, 137, 139, 0, 0, 110, - 0, 0, 187, 55, 100, 0, 34, 186, 0, 0, - 0, 0, 0, 358, 194, 277, 278, 265, 272, 282, - 0, 280, 283, 275, 0, 266, 0, 270, 0, 111, - 348, 347, 349, 0, 0, 341, 340, 0, 0, 0, - 344, 342, 0, 0, 0, 45, 46, 0, 0, 184, - 304, 0, 21, 22, 0, 0, 28, 27, 0, 200, - 31, 33, 88, 89, 91, 90, 93, 94, 95, 96, - 97, 92, 87, 0, 47, 0, 0, 0, 0, 0, + 246, 247, 248, 249, 250, 251, 252, 254, 255, 256, + 257, 258, 0, 253, 259, 260, 261, 262, 263, 0, + 200, 0, 199, 167, 0, 178, 176, 177, 0, 3, + 360, 0, 0, 107, 106, 0, 136, 143, 163, 0, + 162, 151, 183, 185, 184, 190, 191, 0, 0, 0, + 198, 362, 7, 357, 0, 346, 347, 179, 173, 174, + 170, 0, 4, 5, 6, 0, 0, 0, 9, 10, + 150, 0, 165, 167, 0, 180, 0, 0, 8, 101, + 0, 358, 104, 0, 160, 125, 126, 127, 161, 159, + 130, 131, 132, 133, 134, 122, 108, 0, 156, 0, + 0, 0, 361, 4, 6, 144, 0, 146, 164, 152, + 0, 0, 0, 0, 0, 0, 0, 0, 356, 0, + 280, 269, 277, 275, 0, 272, 0, 0, 0, 0, + 0, 166, 0, 0, 352, 0, 353, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 14, 12, 13, 15, + 36, 0, 0, 0, 51, 52, 53, 54, 314, 306, + 310, 11, 17, 44, 19, 24, 25, 0, 0, 30, + 0, 55, 0, 59, 62, 65, 70, 73, 75, 77, + 79, 81, 83, 85, 98, 0, 102, 294, 0, 0, + 151, 299, 312, 296, 295, 0, 300, 301, 302, 303, + 304, 0, 0, 109, 128, 129, 157, 120, 124, 0, + 135, 158, 121, 0, 112, 115, 137, 139, 0, 0, + 110, 0, 0, 187, 55, 100, 0, 34, 186, 0, + 0, 0, 0, 0, 359, 194, 278, 279, 266, 273, + 283, 0, 281, 284, 276, 0, 267, 0, 271, 0, + 111, 349, 348, 350, 0, 0, 342, 341, 0, 0, + 0, 345, 343, 0, 0, 0, 45, 46, 0, 0, + 184, 305, 0, 21, 22, 0, 0, 28, 27, 0, + 200, 31, 33, 88, 89, 91, 90, 93, 94, 95, + 96, 97, 92, 87, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 314, 103, 310, 312, 297, - 296, 105, 118, 117, 123, 0, 0, 0, 0, 0, - 0, 0, 145, 0, 0, 288, 149, 0, 148, 189, - 188, 0, 193, 195, 0, 0, 0, 0, 0, 273, - 0, 263, 269, 0, 0, 0, 0, 335, 334, 337, - 0, 343, 0, 318, 0, 0, 0, 16, 0, 0, - 0, 0, 23, 20, 0, 26, 0, 0, 40, 32, - 86, 56, 57, 58, 60, 61, 63, 64, 68, 69, - 66, 67, 71, 72, 74, 76, 78, 80, 82, 0, - 99, 119, 0, 114, 113, 138, 142, 141, 0, 286, - 290, 0, 287, 0, 0, 0, 0, 284, 281, 267, - 0, 353, 350, 354, 0, 336, 0, 0, 0, 0, - 0, 0, 0, 0, 48, 306, 18, 43, 38, 37, - 0, 200, 41, 0, 286, 0, 147, 292, 289, 192, - 196, 197, 286, 264, 0, 338, 0, 317, 315, 0, - 320, 0, 308, 331, 307, 49, 50, 42, 84, 0, - 140, 291, 0, 0, 339, 333, 0, 0, 0, 321, - 325, 0, 329, 0, 319, 116, 285, 332, 316, 0, - 324, 327, 326, 328, 322, 330, 323 + 0, 0, 0, 0, 0, 0, 315, 103, 311, 313, + 298, 297, 105, 118, 117, 123, 0, 0, 0, 0, + 0, 0, 0, 145, 0, 0, 289, 149, 0, 148, + 189, 188, 0, 193, 195, 0, 0, 0, 0, 0, + 274, 0, 264, 270, 0, 0, 0, 0, 336, 335, + 338, 0, 344, 0, 319, 0, 0, 0, 16, 0, + 0, 0, 0, 23, 20, 0, 26, 0, 0, 40, + 32, 86, 56, 57, 58, 60, 61, 63, 64, 68, + 69, 66, 67, 71, 72, 74, 76, 78, 80, 82, + 0, 99, 119, 0, 114, 113, 138, 142, 141, 0, + 287, 291, 0, 288, 0, 0, 0, 0, 285, 282, + 268, 0, 354, 351, 355, 0, 337, 0, 0, 0, + 0, 0, 0, 0, 0, 48, 307, 18, 43, 38, + 37, 0, 200, 41, 0, 287, 0, 147, 293, 290, + 192, 196, 197, 287, 265, 0, 339, 0, 318, 316, + 0, 321, 0, 309, 332, 308, 49, 50, 42, 84, + 0, 140, 292, 0, 0, 340, 334, 0, 0, 0, + 322, 326, 0, 330, 0, 320, 116, 286, 333, 317, + 0, 325, 328, 327, 329, 323, 331, 324 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { - -1, 1, 2, 273, 88, 220, 221, 222, 431, 223, - 224, 225, 226, 227, 228, 229, 435, 436, 437, 438, - 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, - 240, 241, 242, 243, 353, 244, 311, 245, 246, 247, - 91, 92, 93, 154, 155, 156, 267, 248, 95, 96, - 97, 158, 98, 99, 286, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 183, 184, 185, 186, 300, - 301, 274, 396, 471, 250, 251, 252, 253, 331, 523, - 524, 254, 255, 256, 518, 425, 257, 520, 540, 541, - 542, 543, 258, 419, 486, 487, 259, 111, 312, 313, - 112, 260, 114, 115 + -1, 1, 2, 274, 89, 221, 222, 223, 432, 224, + 225, 226, 227, 228, 229, 230, 436, 437, 438, 439, + 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, + 241, 242, 243, 244, 354, 245, 312, 246, 247, 248, + 92, 93, 94, 155, 156, 157, 268, 249, 96, 97, + 98, 159, 99, 100, 287, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 184, 185, 186, 187, 301, + 302, 275, 397, 472, 251, 252, 253, 254, 332, 524, + 525, 255, 256, 257, 519, 426, 258, 521, 541, 542, + 543, 544, 259, 420, 487, 488, 260, 112, 313, 314, + 113, 261, 115, 116 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ -#define YYPACT_NINF -252 +#define YYPACT_NINF -256 static const yytype_int16 yypact[] = { - -252, 80, 5294, -252, -57, -252, -252, -252, -252, -252, - -252, -252, -252, -252, -252, -252, -252, -252, -252, -252, - -252, -252, -252, -252, -252, -252, -252, -252, -252, -252, - -252, 67, -252, -252, -252, -252, -252, -252, -252, -252, - -252, -252, -252, -252, -252, -252, -252, -252, -252, -252, - -252, -252, -252, -252, -252, -252, -252, -252, -252, -252, - -252, -252, -252, -252, -252, -252, -252, -252, -252, -252, - -252, -50, -252, -252, -252, -252, -252, -252, -79, -252, - 105, -252, 2855, 5588, 82, -252, -252, 665, 5294, -252, - -23, -94, -61, 5732, -150, -252, 112, 314, 6033, -252, - -252, -252, -46, -37, -252, -42, -39, -32, -8, -252, - -252, -252, -252, 5441, -252, -252, -252, -252, -252, -252, - 94, -252, -252, -252, 1953, -121, -11, -252, -252, -252, - 314, -252, 452, 44, -252, -25, -9, -252, -252, 542, - -252, 20, 5732, -252, 226, 232, -252, -252, 182, -252, - -252, -252, -252, -252, -252, -252, 5838, 227, 5928, 105, - 105, -252, 54, 62, -176, 63, -173, -252, -252, 3819, - 4000, 898, 174, 175, 177, 47, 44, -252, 57, 182, - -252, 248, -252, 2043, -252, 105, 6033, 184, 2152, 2242, - -252, 78, 4181, -252, 4181, -252, 58, 59, 1493, 81, - 83, 61, 3199, 84, 86, -252, -252, -252, -252, -252, - 4724, 4724, 3638, -252, -252, -252, -252, -252, 65, -252, - 90, -252, -78, -252, -252, -252, 96, -114, 4905, 91, - 37, 4724, 3, -14, 118, -82, 120, 87, 79, 89, - 194, -100, -252, -252, -148, -252, -252, 88, -145, 103, - -252, -252, -252, -252, 780, -252, -252, -252, -252, -252, - 1493, 105, -252, -252, -252, -252, -252, -252, 6033, 105, - -252, -252, 5838, -171, 102, -168, -167, 4362, 2976, -252, - 4724, 2976, -252, -252, -252, 104, -252, -252, 107, -124, - 97, 108, 111, -252, -252, -252, -252, -252, -252, -160, - -144, -252, 102, -252, 95, -252, 2351, -252, 2441, -252, - -252, -252, -252, -106, -105, -252, -252, 230, 2753, 4724, - -252, -252, -139, 4724, 3423, -252, -252, 6033, -72, 5, - -252, 1493, -252, -252, 4724, 112, -252, -252, 4724, 119, - -252, -252, -252, -252, -252, -252, -252, -252, -252, -252, - -252, -252, -252, 4724, -252, 4724, 4724, 4724, 4724, 4724, - 4724, 4724, 4724, 4724, 4724, 4724, 4724, 4724, 4724, 4724, - 4724, 4724, 4724, 4724, 4724, -252, -252, -252, -252, -252, - -252, -252, -252, -252, -252, 6033, 4724, 105, 4724, 4543, - 2976, 2976, 99, 123, 2976, -252, -252, 126, -252, -252, - -252, 229, -252, -252, 240, 249, 4724, 105, 105, -252, - 2550, -252, -252, 139, 4181, 141, 121, -252, -252, 3423, - -44, -252, -43, 158, 105, 163, 164, -252, 166, 4724, - 1018, 165, 158, -252, 169, -252, 170, -29, 5086, -252, - -252, -252, -252, -252, 3, 3, -14, -14, 118, 118, - 118, 118, -82, -82, 120, 87, 79, 89, 194, -154, - -252, -252, 171, -252, -252, 152, -252, -252, 2976, -252, - -252, -169, -252, 159, 161, 167, 179, -252, -252, -252, - 2640, -252, -252, -252, 4724, -252, 156, 183, 1493, 168, - 160, 1730, 4724, 4724, -252, -252, -252, -252, -252, -252, - 4724, 185, -252, 4724, 173, 2976, -252, 2976, -252, -252, - -252, -252, 176, -252, -28, 4724, 1730, 389, -252, 1, - -252, 2976, -252, -252, -252, -252, -252, -252, -252, 105, - -252, -252, 105, 172, 158, -252, 1493, 4724, 178, -252, - -252, 1256, 1493, 9, -252, -252, -252, -252, -252, -147, - -252, -252, -252, -252, -252, 1493, -252 + -256, 55, 5335, -256, -77, -256, -256, -256, -256, -256, + -256, -256, -256, -256, -256, -256, -256, -256, -256, -256, + -256, -256, -256, -256, -256, -256, -256, -256, -256, -256, + -256, 128, -256, -256, -256, -256, -256, -256, -256, -256, + -256, -256, -256, -256, -256, -256, -256, -256, -256, -256, + -256, -256, -256, -256, -256, -256, -256, -256, -256, -256, + -256, -256, -256, -256, -256, -256, -256, -256, -256, -256, + -256, -256, -112, -256, -256, -256, -256, -256, -256, -50, + -256, -33, -256, 2884, 5631, 121, -256, -256, 683, 5335, + -256, -11, -65, -62, 5776, -150, -256, 148, 67, 6080, + -256, -256, -256, -37, -31, -256, -10, 1, 11, 13, + -256, -256, -256, -256, 5483, -256, -256, -256, -256, -256, + -256, 125, -256, -256, -256, 1977, -56, -4, -256, -256, + -256, 67, -256, 130, -12, -256, -15, -1, -256, -256, + 560, -256, 14, 5776, -256, 213, 226, -256, -256, 225, + -256, -256, -256, -256, -256, -256, -256, 5883, 232, 5974, + -33, -33, -256, 61, 74, -205, 76, -176, -256, -256, + 3852, 4034, 922, 180, 195, 201, 73, -12, -256, 79, + 225, -256, 272, -256, 2068, -256, -33, 6080, 206, 2177, + 2268, -256, 101, 4216, -256, 4216, -256, 81, 83, 1515, + 106, 107, 87, 3229, 109, 111, -256, -256, -256, -256, + -256, 4762, 4762, 3670, -256, -256, -256, -256, -256, 93, + -256, 117, -256, -29, -256, -256, -256, 118, -67, 4944, + 122, 80, 4762, 71, -182, 159, -84, 158, 103, 114, + 115, 216, -92, -256, -256, -145, -256, -256, 112, -144, + 134, -256, -256, -256, -256, 799, -256, -256, -256, -256, + -256, 1515, -33, -256, -256, -256, -256, -256, -256, 6080, + -33, -256, -256, 5883, -166, 133, -173, -171, 4398, 3005, + -256, 4762, 3005, -256, -256, -256, 135, -256, -256, 136, + -110, 123, 131, 137, -256, -256, -256, -256, -256, -256, + -168, -140, -256, 133, -256, 119, -256, 2377, -256, 2468, + -256, -256, -256, -256, -43, -27, -256, -256, 255, 2781, + 4762, -256, -256, -139, 4762, 3454, -256, -256, 6080, -25, + 4, -256, 1515, -256, -256, 4762, 148, -256, -256, 4762, + 143, -256, -256, -256, -256, -256, -256, -256, -256, -256, + -256, -256, -256, -256, 4762, -256, 4762, 4762, 4762, 4762, + 4762, 4762, 4762, 4762, 4762, 4762, 4762, 4762, 4762, 4762, + 4762, 4762, 4762, 4762, 4762, 4762, -256, -256, -256, -256, + -256, -256, -256, -256, -256, -256, 6080, 4762, -33, 4762, + 4580, 3005, 3005, 144, 160, 3005, -256, -256, 162, -256, + -256, -256, 273, -256, -256, 274, 275, 4762, -33, -33, + -256, 2577, -256, -256, 168, 4216, 169, 173, -256, -256, + 3454, -24, -256, -18, 170, -33, 176, 179, -256, 181, + 4762, 1038, 171, 170, -256, 183, -256, 185, 3, 5126, + -256, -256, -256, -256, -256, 71, 71, -182, -182, 159, + 159, 159, 159, -84, -84, 158, 103, 114, 115, 216, + -86, -256, -256, 178, -256, -256, 164, -256, -256, 3005, + -256, -256, -178, -256, 174, 175, 184, 187, -256, -256, + -256, 2668, -256, -256, -256, 4762, -256, 166, 191, 1515, + 177, 182, 1753, 4762, 4762, -256, -256, -256, -256, -256, + -256, 4762, 192, -256, 4762, 186, 3005, -256, 3005, -256, + -256, -256, -256, 188, -256, 12, 4762, 1753, 402, -256, + 5, -256, 3005, -256, -256, -256, -256, -256, -256, -256, + -33, -256, -256, -33, 189, 170, -256, 1515, 4762, 190, + -256, -256, 1277, 1515, 9, -256, -256, -256, -256, -256, + -78, -256, -256, -256, -256, -256, 1515, -256 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { - -252, -252, -252, -76, -252, -75, -252, -252, -252, -252, - -252, -252, -252, -252, -252, -252, -252, -252, -252, -252, - 7, -252, -113, -107, -158, -89, 34, 36, 45, 49, - 32, -252, -138, -81, -252, -190, -125, 33, -252, 12, - -252, -252, -252, -141, 264, 258, 146, 35, -252, -77, - -69, -140, -252, -35, -2, -252, -252, -189, -45, -252, - -252, -252, -252, -252, -252, -155, -178, -252, -252, -252, - 15, -93, -232, -252, 109, -197, -251, 181, -252, -91, - -30, 98, 113, -252, -252, 11, -252, -252, -109, -252, - -110, -252, -252, -252, -252, -252, -252, 346, 21, 243, - -103, 48, -252, -252 + -256, -256, -256, -76, -256, -73, -256, -256, -256, -256, + -256, -256, -256, -256, -256, -256, -256, -256, -256, -256, + 7, -256, -57, -75, -68, -59, 46, 51, 48, 54, + 57, -256, -142, 49, -256, -195, -135, 29, -256, 28, + -256, -256, -256, -111, 288, 276, 161, 37, -256, -82, + -69, -146, -256, -17, -2, -256, -256, -197, -71, -256, + -256, -256, -256, -256, -256, -170, -175, -256, -256, -256, + 23, -93, -242, -256, 120, -198, -255, 172, -256, -81, + -41, 110, 124, -256, -256, 18, -256, -256, -97, -256, + -98, -256, -256, -256, -256, -256, -256, 358, 33, 254, + -101, 39, -256, -256 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If @@ -1303,86 +1304,64 @@ static const yytype_int16 yypgoto[] = #define YYTABLE_NINF -40 static const yytype_int16 yytable[] = { - 100, 317, 125, 166, 126, 298, 133, 129, 428, 379, - 177, 135, 322, 130, 90, 266, 268, 271, 537, 538, - 164, 165, 328, 329, 157, 372, 537, 538, 121, 122, - 123, 284, 284, 306, 308, 89, 176, 94, 362, 363, - 332, 333, 136, 277, 285, 288, 280, 131, 386, 398, - 113, 389, 280, 507, 284, 181, 284, 378, 191, 406, - 140, 278, 167, 130, 281, 387, 388, 276, 374, 390, - 391, 508, 160, 157, 374, 374, 407, 160, 408, 265, - 3, 100, 503, 374, 275, 134, 100, 157, 161, 556, - 375, 159, 302, 376, 409, 190, 168, 131, 401, 421, - 90, 165, 117, 118, 337, 116, 119, 402, 338, 299, - 295, 100, 413, 415, 181, 187, 414, 414, 188, 181, - 181, 89, 182, 94, 141, 175, 289, 382, 298, 420, - 298, 383, 385, 422, 423, 373, 113, 249, 426, 284, - 159, 334, 284, 335, 432, 293, 427, 340, 364, 365, - 374, 127, 393, 128, 269, 397, 159, 177, 466, 467, - 124, 142, 470, 342, 343, 344, 345, 346, 347, 348, - 349, 350, 351, 169, 488, 489, 283, 283, 374, 374, - 120, 182, 170, 459, 303, 381, 182, 182, 171, 499, - 533, 172, 192, 500, 374, 193, 249, 395, 173, 283, - 395, 283, 178, 157, 448, 449, 450, 451, 194, 358, - 359, 195, 121, 122, 123, 138, 139, 325, 326, 162, - 122, 163, 174, 429, 170, 32, 33, 34, 189, 423, - 355, 356, 357, 378, 360, 361, 506, 181, 354, 181, - 522, 539, 366, 367, 461, 444, 445, 424, 284, 554, - 284, 284, 249, 446, 447, 480, 261, 439, 249, 433, - 434, 462, 263, 464, 393, 522, 159, 264, 284, 270, - 269, -9, 440, 530, 352, 531, 284, 452, 453, -10, - 279, 476, 290, 291, 283, 292, 139, 283, 294, 544, - 296, 517, 304, 460, 514, 309, 315, 316, 318, 320, - 319, 323, 298, 324, 182, 330, 182, -35, 341, 395, - 395, 463, 369, 395, 336, 302, 249, 4, 371, 368, - -34, 280, 249, 370, 399, 534, 138, 400, 403, 249, - 404, 477, 299, 405, 410, 416, 468, -29, 484, 548, - 473, 181, 424, 469, 551, 553, 472, 549, 490, 25, - 26, 474, 27, 28, 29, 30, 31, 502, 553, 481, - 475, 483, 441, 442, 443, 283, 283, 283, 283, 283, - 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, - 374, 491, 492, 159, 493, 496, 497, 395, 498, 505, - 509, 504, 510, 283, 515, 283, 283, 521, 511, 512, - 536, 516, 454, -39, 458, 455, 262, 519, 182, 529, - 547, 181, 532, 283, 550, 456, 272, 249, 384, 527, - 457, 283, 528, 478, 395, 535, 395, 417, 249, 430, - 485, 418, 552, 555, 137, 482, 494, 314, 0, 0, - 395, 380, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 545, 0, 4, 546, 0, 0, 0, + 101, 318, 134, 126, 167, 127, 380, 429, 323, 299, + 130, 269, 136, 178, 131, 278, 330, 137, 329, 307, + 309, 165, 538, 539, 166, 158, 538, 539, 285, 285, + 91, 90, 177, 279, 373, 286, 289, 363, 364, 95, + 399, 114, 359, 360, 281, 508, 267, 390, 272, 281, + 141, 285, 407, 285, 387, 3, 182, 379, 122, 123, + 124, 192, 282, 509, 131, 391, 132, 392, 277, 408, + 4, 388, 389, 161, 158, 122, 123, 124, 375, 161, + 266, 168, 101, 409, 375, 276, 117, 101, 158, 162, + 333, 334, 160, 303, 376, 377, 128, 169, 129, 410, + 422, 290, 25, 26, 166, 27, 28, 29, 30, 31, + 300, 296, 101, 402, 191, 182, 132, 91, 90, 121, + 182, 182, 403, 183, 135, 421, 95, 386, 114, 423, + 424, 427, 299, 4, 299, 294, 285, 375, 250, 285, + 433, 160, 176, 394, 374, 375, 398, 365, 366, 467, + 468, 504, 338, 471, 142, 270, 339, 160, 383, 557, + 178, 143, 384, 118, 119, 25, 26, 120, 27, 28, + 29, 30, 31, 32, 33, 34, 414, 284, 284, 460, + 415, 188, 183, 170, 189, 304, 382, 183, 183, 171, + 125, 335, 416, 336, 428, 489, 415, 250, 375, 375, + 284, 490, 284, 193, 158, 375, 194, 343, 344, 345, + 346, 347, 348, 349, 350, 351, 352, 195, 326, 327, + 196, 172, 500, 430, 171, 424, 501, 507, 139, 140, + 85, 534, 173, 379, 179, 375, 190, 523, 182, 355, + 182, 481, 174, 425, 175, 285, 540, 285, 285, 264, + 555, 262, 463, 250, 465, 394, 163, 123, 164, 250, + 434, 265, 523, 435, 531, 285, 532, 160, 32, 33, + 34, 270, 477, 285, 271, 462, 361, 362, 341, -9, + 545, 367, 368, 86, 87, 284, 447, 448, 284, 291, + 515, 518, -10, 85, 280, 449, 450, 451, 452, 356, + 357, 358, 445, 446, 292, 183, 299, 183, 453, 454, + 293, 295, 464, 140, 297, 305, 303, 250, 353, 310, + 316, 535, 317, 250, 319, 320, 321, 324, 396, 325, + 250, 396, 478, 300, 331, -35, 369, 337, 425, 549, + 342, 372, 182, 550, 552, 554, 86, 87, 370, 491, + 371, 139, -34, 281, 405, 404, 400, 401, 554, 411, + 406, 417, -29, 442, 443, 444, 284, 284, 284, 284, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, + 284, 470, 469, 473, 160, 474, 475, 476, 440, 482, + 484, 485, 497, 375, 284, 492, 284, 284, 493, 505, + 494, 498, 506, 441, 499, 516, 510, 511, 513, 183, + 517, -39, 182, 537, 284, 455, 512, 520, 250, 457, + 522, 456, 284, 530, 461, 533, 458, 551, 548, 250, + 459, 263, 479, 381, 385, 273, 536, 495, 486, 418, + 396, 396, 431, 419, 396, 553, 556, 138, 483, 315, + 0, 0, 0, 0, 546, 0, 0, 547, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 84, 0, 182, 0, - 0, 0, 0, 0, 0, 0, 249, 25, 26, 249, - 27, 28, 29, 30, 31, 32, 33, 34, 0, 525, - 526, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 249, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, - 86, 0, 0, 0, 249, 0, 0, 0, 0, 249, - 249, 0, 0, 0, 0, 4, 5, 6, 7, 8, - 196, 197, 198, 249, 199, 200, 201, 202, 203, 0, - 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 0, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 0, 0, 0, 0, - 0, 0, 0, 0, 84, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, - 68, 69, 70, 71, 72, 0, 0, 0, 0, 0, - 73, 74, 75, 76, 77, 78, 79, 204, 0, 127, - 81, 128, 205, 206, 207, 208, 0, 209, 0, 0, - 210, 211, 0, 0, 0, 0, 0, 85, 86, 5, - 6, 7, 8, 0, 0, 0, 0, 0, 82, 0, - 0, 0, 0, 0, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 83, 0, 0, 0, 84, 0, 0, 0, 0, 0, - 0, 35, 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, 52, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 183, + 0, 0, 0, 0, 0, 0, 0, 250, 503, 0, + 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 526, 527, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 250, 0, 0, 396, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 85, 86, 212, - 0, 87, 0, 0, 0, 213, 214, 215, 216, 79, - 0, 0, 121, 122, 123, 0, 0, 0, 0, 0, - 217, 218, 219, 4, 5, 6, 7, 8, 196, 197, - 198, 0, 199, 200, 201, 202, 203, 0, 0, 9, + 0, 0, 0, 0, 0, 250, 0, 0, 0, 0, + 250, 250, 0, 0, 0, 0, 0, 0, 0, 0, + 528, 0, 0, 529, 250, 396, 0, 396, 0, 0, + 0, 0, 0, 4, 5, 6, 7, 8, 197, 198, + 199, 396, 200, 201, 202, 203, 204, 0, 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 0, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, @@ -1390,23 +1369,47 @@ static const yytype_int16 yytable[] = 49, 50, 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 0, 0, 0, 0, 0, 73, 74, - 75, 76, 77, 78, 79, 204, 0, 127, 81, 128, - 205, 206, 207, 208, 0, 209, 0, 0, 210, 211, - 0, 0, 5, 6, 7, 8, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 82, 9, 10, 11, - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 0, 0, 0, 0, 0, 83, 0, - 0, 0, 84, 0, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, - 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 53, 54, 0, 0, 0, 0, 0, 0, 0, + 70, 71, 72, 73, 0, 0, 0, 0, 0, 74, + 75, 76, 77, 78, 79, 80, 205, 0, 128, 82, + 129, 206, 207, 208, 209, 0, 210, 0, 0, 211, + 212, 0, 0, 0, 0, 0, 0, 5, 6, 7, + 8, 0, 0, 0, 0, 0, 0, 83, 0, 0, + 0, 0, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 0, 84, + 0, 0, 0, 85, 0, 0, 0, 0, 0, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 53, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 85, 86, 212, 0, 87, - 0, 0, 79, 213, 214, 215, 216, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 217, 218, - 377, 4, 5, 6, 7, 8, 196, 197, 198, 0, - 199, 200, 201, 202, 203, 0, 0, 9, 10, 11, + 0, 0, 0, 0, 0, 0, 86, 87, 213, 0, + 88, 0, 0, 0, 214, 215, 216, 217, 80, 0, + 0, 122, 123, 124, 0, 0, 0, 0, 0, 218, + 219, 220, 4, 5, 6, 7, 8, 197, 198, 199, + 0, 200, 201, 202, 203, 204, 0, 0, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 0, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 0, 0, 0, 0, 0, 74, 75, + 76, 77, 78, 79, 80, 205, 0, 128, 82, 129, + 206, 207, 208, 209, 0, 210, 0, 0, 211, 212, + 0, 0, 0, 0, 0, 0, 5, 6, 7, 8, + 0, 0, 0, 0, 0, 0, 83, 0, 0, 0, + 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 0, 84, 0, + 0, 0, 85, 0, 0, 0, 0, 0, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 53, 54, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 86, 87, 213, 0, 88, + 0, 0, 0, 214, 215, 216, 217, 80, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 218, 219, + 378, 4, 5, 6, 7, 8, 197, 198, 199, 0, + 200, 201, 202, 203, 204, 0, 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 0, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, @@ -1414,46 +1417,70 @@ static const yytype_int16 yytable[] = 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 0, 0, 0, 0, 0, 73, 74, 75, 76, - 77, 78, 79, 204, 0, 127, 81, 128, 205, 206, - 207, 208, 0, 209, 0, 0, 210, 211, 0, 0, + 72, 73, 0, 0, 0, 0, 0, 74, 75, 76, + 77, 78, 79, 80, 205, 0, 128, 82, 129, 206, + 207, 208, 209, 0, 210, 0, 0, 211, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 82, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 83, 0, 0, 0, - 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, + 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 85, 86, 212, 0, 87, 0, 0, - 0, 213, 214, 215, 216, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 217, 218, 495, 4, - 5, 6, 7, 8, 196, 197, 198, 0, 199, 200, - 201, 202, 203, 537, 538, 9, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 0, 27, 28, 29, 30, 31, 32, - 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, - 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, - 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 0, - 0, 0, 0, 0, 73, 74, 75, 76, 77, 78, - 79, 204, 0, 127, 81, 128, 205, 206, 207, 208, - 0, 209, 0, 0, 210, 211, 0, 0, 0, 0, + 0, 0, 0, 0, 86, 87, 213, 0, 88, 0, + 0, 0, 214, 215, 216, 217, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 218, 219, 496, + 4, 5, 6, 7, 8, 197, 198, 199, 0, 200, + 201, 202, 203, 204, 538, 539, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 0, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 0, 0, 0, 0, 0, 74, 75, 76, 77, + 78, 79, 80, 205, 0, 128, 82, 129, 206, 207, + 208, 209, 0, 210, 0, 0, 211, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 83, 0, 0, 0, 84, 0, + 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, + 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 86, 87, 213, 0, 88, 0, 0, + 0, 214, 215, 216, 217, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 218, 219, 4, 5, + 6, 7, 8, 197, 198, 199, 0, 200, 201, 202, + 203, 204, 0, 0, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 0, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 0, + 0, 0, 0, 0, 74, 75, 76, 77, 78, 79, + 80, 205, 0, 128, 82, 129, 206, 207, 208, 209, + 0, 210, 0, 0, 211, 212, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 84, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 85, 86, 212, 0, 87, 0, 0, 0, 213, - 214, 215, 216, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 217, 218, 4, 5, 6, 7, - 8, 196, 197, 198, 0, 199, 200, 201, 202, 203, + 0, 86, 87, 213, 0, 88, 0, 0, 0, 214, + 215, 216, 217, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 218, 219, 4, 5, 6, 7, + 8, 197, 198, 199, 0, 200, 201, 202, 203, 204, 0, 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 0, 27, 28, 29, 30, 31, 32, 33, 34, 35, @@ -1461,158 +1488,135 @@ static const yytype_int16 yytable[] = 46, 47, 48, 49, 50, 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 0, 0, 0, 0, - 0, 73, 74, 75, 76, 77, 78, 79, 204, 0, - 127, 81, 128, 205, 206, 207, 208, 0, 209, 0, - 0, 210, 211, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, + 67, 68, 69, 70, 71, 72, 73, 0, 0, 0, + 0, 0, 74, 75, 76, 77, 78, 79, 80, 205, + 0, 128, 82, 129, 206, 207, 208, 209, 0, 210, + 0, 0, 211, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 83, 0, 0, 0, 84, 0, 0, 0, 0, + 0, 0, 84, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 85, 86, - 212, 0, 87, 0, 0, 0, 213, 214, 215, 216, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 217, 218, 4, 5, 6, 7, 8, 196, 197, - 198, 0, 199, 200, 201, 202, 203, 0, 0, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 0, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 52, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 0, 0, 0, 0, 0, 73, 74, - 75, 76, 77, 78, 79, 204, 0, 127, 81, 128, - 205, 206, 207, 208, 0, 209, 0, 0, 210, 211, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 82, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 83, 0, - 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 85, 86, 212, 0, 0, - 0, 0, 0, 213, 214, 215, 216, 5, 6, 7, - 8, 0, 0, 0, 0, 0, 0, 0, 217, 139, - 0, 0, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 0, 0, - 0, 0, 0, 0, 0, 179, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 53, 54, 55, 56, - 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 0, 5, 6, 7, - 8, 73, 74, 75, 76, 77, 78, 79, 0, 0, - 0, 81, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 0, 0, - 0, 0, 0, 0, 0, 179, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 53, 54, 55, 56, - 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 0, 0, 0, 0, - 0, 73, 74, 75, 76, 77, 78, 79, 0, 0, - 0, 81, 0, 0, 0, 0, 5, 6, 7, 8, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 0, 0, 0, - 0, 0, 0, 180, 179, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, - 68, 69, 70, 71, 72, 0, 5, 6, 7, 8, - 73, 74, 75, 76, 77, 78, 79, 0, 0, 0, - 81, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 0, 0, 0, - 0, 0, 0, 297, 179, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, - 68, 69, 70, 71, 72, 0, 0, 0, 0, 0, - 73, 74, 75, 76, 77, 78, 79, 0, 0, 0, - 81, 0, 0, 0, 0, 5, 6, 7, 8, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, + 87, 213, 0, 0, 0, 0, 0, 214, 215, 216, + 217, 5, 6, 7, 8, 0, 0, 0, 0, 0, + 0, 0, 218, 140, 0, 0, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 0, 0, 0, 0, 0, 0, 0, 180, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 0, 5, 6, 7, 8, 74, 75, 76, 77, + 78, 79, 80, 0, 0, 0, 82, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 0, 0, 0, 0, 0, 0, 0, + 180, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 0, 0, 0, 0, 0, 74, 75, 76, + 77, 78, 79, 80, 0, 0, 0, 82, 0, 0, + 0, 5, 6, 7, 8, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 0, 0, 0, 0, 0, 0, 181, 180, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 0, 5, 6, 7, 8, 74, 75, 76, 77, + 78, 79, 80, 0, 0, 0, 82, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 0, 0, 0, 0, 0, 0, 298, + 180, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 0, 0, 0, 0, 0, 74, 75, 76, + 77, 78, 79, 80, 0, 0, 0, 82, 0, 0, + 0, 5, 6, 7, 8, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 0, 0, 0, 0, 0, 0, 306, 180, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 0, 5, 6, 7, 8, 74, 75, 76, 77, + 78, 79, 80, 0, 0, 0, 82, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 0, 0, 0, 0, 0, 0, 308, + 180, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 0, 0, 0, 0, 0, 74, 75, 76, + 77, 78, 79, 80, 0, 0, 0, 82, 0, 0, + 0, 5, 6, 7, 8, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 0, 0, 0, 0, 0, 0, 412, 180, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 0, 5, 6, 7, 8, 74, 75, 76, 77, + 78, 79, 80, 0, 0, 0, 82, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 0, 0, 0, 0, 0, 0, 413, + 180, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 0, 0, 0, 0, 0, 74, 75, 76, + 77, 78, 79, 80, 0, 0, 0, 82, 0, 0, + 0, 0, 0, 0, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 0, 0, 0, 0, - 0, 0, 305, 179, 32, 33, 34, 35, 36, 37, + 19, 20, 21, 22, 23, 24, 25, 26, 480, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 0, 5, 6, 7, 8, 73, - 74, 75, 76, 77, 78, 79, 0, 0, 0, 81, - 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 0, 0, 0, 0, - 0, 0, 307, 179, 32, 33, 34, 35, 36, 37, - 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 53, 54, 55, 56, 57, 58, - 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 0, 0, 0, 0, 0, 73, - 74, 75, 76, 77, 78, 79, 0, 0, 0, 81, - 0, 0, 0, 0, 5, 6, 7, 8, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 0, 0, 0, 0, 0, - 0, 411, 179, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 52, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 0, 5, 6, 7, 8, 73, 74, - 75, 76, 77, 78, 79, 0, 0, 0, 81, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 0, 0, 0, 0, 0, - 0, 412, 179, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 52, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 0, 0, 0, 0, 0, 73, 74, - 75, 76, 77, 78, 79, 0, 0, 0, 81, 0, - 0, 0, 0, 0, 0, 0, 4, 5, 6, 7, - 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 479, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 53, 54, 55, 56, - 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 0, 0, 0, 0, - 0, 73, 74, 75, 76, 77, 78, 79, 4, 0, - 127, 81, 128, 205, 206, 207, 208, 0, 209, 0, - 0, 210, 211, 0, 0, 0, 0, 0, 0, 0, - 513, 0, 0, 0, 0, 0, 0, 0, 0, 82, - 25, 26, 0, 27, 28, 29, 30, 31, 32, 33, - 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 83, 0, 0, 0, 84, 0, 0, 0, 0, + 69, 70, 71, 72, 73, 0, 0, 0, 0, 0, + 74, 75, 76, 77, 78, 79, 80, 4, 0, 128, + 82, 129, 206, 207, 208, 209, 0, 210, 0, 0, + 211, 212, 0, 0, 0, 0, 0, 0, 0, 514, + 0, 0, 0, 0, 0, 0, 0, 0, 83, 25, + 26, 0, 27, 28, 29, 30, 31, 32, 33, 34, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 84, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 127, 0, 128, 0, 0, 0, 85, 86, - 212, 0, 0, 0, 0, 0, 213, 214, 215, 216, - 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, - 0, 217, 0, 0, 0, 9, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 0, 0, 0, 0, 0, 0, 84, 0, 0, - 0, 0, 35, 36, 37, 38, 39, 40, 41, 42, - 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, - 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 0, - 85, 86, 0, 0, 73, 74, 75, 76, 77, 78, - 79, 0, 0, 127, 81, 128, 205, 206, 207, 208, - 0, 209, 0, 0, 210, 211, 0, 0, 0, 0, + 0, 0, 128, 0, 129, 0, 0, 86, 87, 213, + 0, 0, 0, 0, 0, 214, 215, 216, 217, 5, + 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, + 218, 0, 0, 0, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, + 0, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 0, + 86, 87, 0, 0, 74, 75, 76, 77, 78, 79, + 80, 0, 0, 128, 82, 129, 206, 207, 208, 209, + 0, 210, 0, 0, 211, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1622,9 +1626,9 @@ static const yytype_int16 yytable[] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 212, 0, 0, 0, 0, 0, 213, - 214, 215, 216, 5, 6, 7, 8, 0, 0, 0, - 0, 0, 0, 0, 0, 394, 0, 0, 9, 10, + 0, 0, 0, 213, 0, 0, 0, 0, 0, 214, + 215, 216, 217, 5, 6, 7, 8, 0, 0, 0, + 0, 0, 0, 0, 0, 395, 0, 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 36, 37, 38, 39, @@ -1632,9 +1636,9 @@ static const yytype_int16 yytable[] = 50, 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, - 71, 72, 0, 0, 0, 0, 0, 73, 74, 75, - 76, 77, 78, 79, 0, 0, 127, 81, 128, 205, - 206, 207, 208, 0, 209, 0, 0, 210, 211, 0, + 71, 72, 73, 0, 0, 0, 0, 0, 74, 75, + 76, 77, 78, 79, 80, 0, 0, 128, 82, 129, + 206, 207, 208, 209, 0, 210, 0, 0, 211, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1644,96 +1648,42 @@ static const yytype_int16 yytable[] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 212, 0, 0, 0, - 0, 0, 213, 214, 215, 216, 4, 5, 6, 7, - 8, 0, 0, 0, 0, 0, 0, 321, 0, 0, - 0, 0, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 0, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 53, 54, 55, 56, - 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 0, 0, 0, 0, - 0, 73, 74, 75, 76, 77, 78, 79, 0, 0, - 127, 81, 128, 205, 206, 207, 208, 0, 209, 0, - 0, 210, 211, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 132, + 0, 0, 0, 0, 0, 0, 0, 213, 0, 0, + 0, 0, 0, 214, 215, 216, 217, 4, 5, 6, + 7, 8, 0, 0, 0, 0, 0, 0, 322, 0, + 0, 0, 0, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 0, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 0, 0, + 0, 0, 0, 74, 75, 76, 77, 78, 79, 80, + 0, 0, 128, 82, 129, 206, 207, 208, 209, 0, + 210, 0, 0, 211, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 133, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 85, 86, - 212, 327, 5, 6, 7, 8, 213, 214, 215, 216, - 0, 0, 0, 0, 0, 0, 0, 9, 10, 11, - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, - 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 0, 0, 0, 0, 0, 73, 74, 75, 76, - 77, 78, 79, 0, 0, 127, 81, 128, 205, 206, - 207, 208, 0, 209, 0, 0, 210, 211, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 5, 6, 7, 8, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 0, 212, 0, 0, 0, 0, - 0, 213, 214, 215, 216, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 53, 54, 55, 56, 57, 58, 59, 60, - 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, - 71, 72, 0, 0, 0, 0, 0, 73, 74, 75, - 76, 77, 78, 79, 0, 0, 127, 81, 128, 205, - 206, 207, 208, 0, 209, 0, 0, 210, 211, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 5, 6, 7, 8, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, + 86, 87, 213, 328, 5, 6, 7, 8, 214, 215, + 216, 217, 0, 0, 0, 0, 0, 0, 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 0, 212, 0, 0, 282, - 0, 0, 213, 214, 215, 216, 35, 36, 37, 38, + 20, 21, 22, 23, 24, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 0, 0, 0, 0, 0, 73, 74, - 75, 76, 77, 78, 79, 0, 0, 127, 81, 128, - 205, 206, 207, 208, 0, 209, 0, 0, 210, 211, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 5, 6, 7, 8, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 0, 212, 0, 0, - 287, 0, 0, 213, 214, 215, 216, 35, 36, 37, - 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 53, 54, 55, 56, 57, 58, - 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 0, 0, 0, 0, 0, 73, - 74, 75, 76, 77, 78, 79, 0, 0, 127, 81, - 128, 205, 206, 207, 208, 310, 209, 0, 0, 210, - 211, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 70, 71, 72, 73, 0, 0, 0, 0, 0, 74, + 75, 76, 77, 78, 79, 80, 0, 0, 128, 82, + 129, 206, 207, 208, 209, 0, 210, 0, 0, 211, + 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1742,34 +1692,16 @@ static const yytype_int16 yytable[] = 0, 0, 0, 0, 0, 0, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 0, 212, 0, - 0, 0, 0, 0, 213, 214, 215, 216, 35, 36, + 18, 19, 20, 21, 22, 23, 24, 0, 213, 0, + 0, 0, 0, 0, 214, 215, 216, 217, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, - 68, 69, 70, 71, 72, 0, 0, 0, 0, 0, - 73, 74, 75, 76, 77, 78, 79, 0, 0, 127, - 81, 128, 205, 206, 207, 208, 0, 209, 0, 0, - 210, 211, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 5, 6, 7, - 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 0, 212, - 0, 0, 392, 0, 0, 213, 214, 215, 216, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 53, 54, 55, 56, - 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 0, 0, 0, 0, - 0, 73, 74, 75, 76, 77, 78, 79, 0, 0, - 127, 81, 128, 205, 206, 207, 208, 0, 209, 0, - 0, 210, 211, 0, 0, 0, 0, 0, 0, 0, + 68, 69, 70, 71, 72, 73, 0, 0, 0, 0, + 0, 74, 75, 76, 77, 78, 79, 80, 0, 0, + 128, 82, 129, 206, 207, 208, 209, 0, 210, 0, + 0, 211, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1779,33 +1711,15 @@ static const yytype_int16 yytable[] = 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 0, - 212, 0, 0, 465, 0, 0, 213, 214, 215, 216, + 213, 0, 0, 283, 0, 0, 214, 215, 216, 217, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 0, 0, 0, - 0, 0, 73, 74, 75, 76, 77, 78, 79, 0, - 0, 127, 81, 128, 205, 206, 207, 208, 0, 209, - 0, 0, 210, 211, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, - 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 0, 212, 0, 0, 0, 0, 0, 213, 214, 215, - 216, 35, 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, 52, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, 70, 71, 72, 0, 0, - 0, 0, 0, 73, 74, 75, 76, 77, 78, 339, - 0, 0, 127, 81, 128, 205, 206, 207, 208, 0, - 209, 0, 0, 210, 211, 0, 0, 0, 0, 0, + 66, 67, 68, 69, 70, 71, 72, 73, 0, 0, + 0, 0, 0, 74, 75, 76, 77, 78, 79, 80, + 0, 0, 128, 82, 129, 206, 207, 208, 209, 0, + 210, 0, 0, 211, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1815,199 +1729,268 @@ static const yytype_int16 yytable[] = 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 0, 212, 0, 0, 0, 0, 0, 213, 214, - 215, 216, 35, 36, 37, 38, 39, 40, 41, 42, + 24, 0, 213, 0, 0, 288, 0, 0, 214, 215, + 216, 217, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 0, - 0, 0, 0, 0, 73, 74, 75, 76, 77, 78, - 501, 0, 0, 127, 81, 128, 205, 206, 207, 208, - 0, 209, 0, 0, 210, 211, 0, 0, 0, 0, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 0, 0, 0, 0, 0, 74, 75, 76, 77, 78, + 79, 80, 0, 0, 128, 82, 129, 206, 207, 208, + 209, 311, 210, 0, 0, 211, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5, 6, 7, 8, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 0, 213, 0, 0, 0, 0, 0, + 214, 215, 216, 217, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 0, 0, 0, 0, 0, 74, 75, 76, + 77, 78, 79, 80, 0, 0, 128, 82, 129, 206, + 207, 208, 209, 0, 210, 0, 0, 211, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 4, 5, 6, - 7, 8, 0, 212, 0, 0, 0, 0, 0, 213, - 214, 215, 216, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 0, 27, 28, 29, 30, 31, 32, 33, 34, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 5, 6, 7, 8, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 0, 213, 0, 0, 393, + 0, 0, 214, 215, 216, 217, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 0, 0, 0, 0, 0, 74, + 75, 76, 77, 78, 79, 80, 0, 0, 128, 82, + 129, 206, 207, 208, 209, 0, 210, 0, 0, 211, + 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 5, 6, 7, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 0, 213, 0, + 0, 466, 0, 0, 214, 215, 216, 217, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 0, 0, 0, 0, + 0, 74, 75, 76, 77, 78, 79, 80, 0, 0, + 128, 82, 129, 206, 207, 208, 209, 0, 210, 0, + 0, 211, 212, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, + 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 0, + 213, 0, 0, 0, 0, 0, 214, 215, 216, 217, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 0, 0, 0, - 0, 0, 73, 74, 75, 76, 77, 78, 79, 0, - 80, 0, 81, 0, 0, 0, 0, 0, 0, 0, + 66, 67, 68, 69, 70, 71, 72, 73, 0, 0, + 0, 0, 0, 74, 75, 76, 77, 78, 79, 340, + 0, 0, 128, 82, 129, 206, 207, 208, 209, 0, + 210, 0, 0, 211, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 0, 213, 0, 0, 0, 0, 0, 214, 215, + 216, 217, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 0, 0, 0, 0, 0, 74, 75, 76, 77, 78, + 79, 502, 0, 0, 128, 82, 129, 206, 207, 208, + 209, 0, 210, 0, 0, 211, 212, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, + 6, 7, 8, 0, 213, 0, 0, 0, 0, 0, + 214, 215, 216, 217, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 0, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 0, + 0, 0, 0, 0, 74, 75, 76, 77, 78, 79, + 80, 0, 81, 0, 82, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 4, 5, 6, 7, + 8, 0, 0, 0, 84, 0, 0, 0, 85, 0, + 0, 0, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 0, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 0, 0, 0, + 0, 86, 87, 0, 0, 88, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 0, 0, 0, + 0, 0, 74, 75, 76, 77, 78, 79, 80, 0, + 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 133, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 6, 7, 8, 0, - 0, 0, 83, 0, 0, 0, 84, 0, 0, 0, + 0, 0, 84, 0, 0, 0, 85, 0, 0, 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 0, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 0, 0, 0, 0, 85, - 86, 0, 0, 87, 53, 54, 55, 56, 57, 58, + 48, 49, 50, 51, 52, 0, 0, 0, 0, 86, + 87, 0, 0, 88, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 0, 0, 0, 0, 0, 73, - 74, 75, 76, 77, 78, 79, 0, 0, 0, 81, + 69, 70, 71, 72, 73, 0, 0, 0, 0, 0, + 74, 75, 76, 77, 78, 79, 80, 0, 0, 0, + 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 132, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 4, 5, 6, 7, 8, 0, 0, 0, 83, - 0, 0, 0, 84, 0, 0, 0, 9, 10, 11, - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 0, 27, 28, 29, 30, - 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, - 51, 52, 0, 0, 0, 0, 85, 86, 0, 0, - 87, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 0, 0, 0, 0, 0, 73, 74, 75, 76, - 77, 78, 79, 0, 0, 0, 81, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 132, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 143, 5, 6, 7, 8, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 84, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 144, 145, 146, - 147, 0, 0, 0, 148, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 0, 0, 0, 0, - 0, 0, 0, 85, 86, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, - 68, 69, 70, 71, 72, 149, 150, 151, 152, 153, - 73, 74, 75, 76, 77, 78, 79, 0, 0, 0, - 81, 143, 5, 6, 7, 8, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 9, 10, 11, - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 0, 0, 0, 147, 0, 0, 0, - 148, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, - 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 0, 5, 6, 7, 8, 73, 74, 75, 76, - 77, 78, 79, 0, 0, 0, 81, 9, 10, 11, - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 144, 145, 146, 0, 0, 0, 0, - 0, 0, 0, 0, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, - 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 149, 150, 151, 152, 153, 73, 74, 75, 76, - 77, 78, 79, 0, 0, 0, 81, 5, 6, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 133, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, + 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 85, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 145, 146, 147, 148, 0, 0, 0, 149, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 0, 0, 0, 0, 0, 0, 0, 86, 87, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 150, 151, 152, 153, 154, 74, 75, 76, 77, 78, + 79, 80, 0, 0, 0, 82, 144, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, + 0, 148, 0, 0, 0, 149, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 0, 0, 0, 0, - 0, 73, 74, 75, 76, 77, 78, 79, 0, 0, - 0, 81 + 67, 68, 69, 70, 71, 72, 73, 0, 5, 6, + 7, 8, 74, 75, 76, 77, 78, 79, 80, 0, + 0, 0, 82, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 145, + 146, 147, 0, 0, 0, 0, 0, 0, 0, 0, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 150, 151, + 152, 153, 154, 74, 75, 76, 77, 78, 79, 80, + 0, 0, 0, 82, 5, 6, 7, 8, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 0, 0, 0, 0, 0, 74, + 75, 76, 77, 78, 79, 80, 0, 0, 0, 82 }; #define yypact_value_is_default(yystate) \ - ((yystate) == (-252)) + ((yystate) == (-256)) #define yytable_value_is_error(yytable_value) \ YYID (0) static const yytype_int16 yycheck[] = { - 2, 198, 78, 96, 80, 183, 83, 82, 3, 260, - 113, 87, 202, 82, 2, 156, 156, 158, 17, 18, - 96, 96, 212, 212, 93, 125, 17, 18, 107, 108, - 109, 169, 170, 188, 189, 2, 113, 2, 120, 121, - 118, 119, 87, 219, 169, 170, 219, 82, 219, 281, - 2, 219, 219, 222, 192, 124, 194, 254, 133, 219, - 90, 237, 97, 132, 237, 236, 237, 160, 222, 237, - 237, 240, 222, 142, 222, 222, 236, 222, 222, 148, - 0, 83, 236, 222, 160, 3, 88, 156, 238, 236, - 238, 93, 185, 238, 238, 130, 98, 132, 222, 238, - 88, 176, 35, 36, 218, 162, 39, 231, 222, 185, - 179, 113, 218, 218, 183, 236, 222, 222, 239, 188, - 189, 88, 124, 88, 218, 113, 171, 268, 306, 319, - 308, 272, 272, 323, 324, 235, 88, 139, 327, 277, - 142, 219, 280, 221, 334, 175, 218, 228, 230, 231, - 222, 107, 277, 109, 156, 280, 158, 260, 390, 391, - 239, 222, 394, 126, 127, 128, 129, 130, 131, 132, - 133, 134, 135, 219, 218, 218, 169, 170, 222, 222, - 230, 183, 219, 373, 186, 261, 188, 189, 230, 218, - 218, 230, 217, 222, 222, 220, 198, 278, 230, 192, - 281, 194, 108, 272, 362, 363, 364, 365, 217, 223, - 224, 220, 107, 108, 109, 238, 239, 210, 211, 107, - 108, 109, 230, 218, 219, 43, 44, 45, 239, 419, - 227, 228, 229, 430, 116, 117, 468, 306, 231, 308, - 491, 240, 122, 123, 385, 358, 359, 324, 386, 240, - 388, 389, 254, 360, 361, 410, 236, 338, 260, 335, - 335, 386, 36, 388, 389, 516, 268, 35, 406, 42, - 272, 217, 353, 505, 237, 507, 414, 366, 367, 217, - 217, 406, 108, 108, 277, 108, 239, 280, 231, 521, - 42, 488, 108, 374, 484, 217, 238, 238, 217, 238, - 217, 217, 480, 217, 306, 240, 308, 217, 217, 390, - 391, 387, 233, 394, 218, 408, 318, 3, 124, 232, - 217, 219, 324, 234, 220, 515, 238, 220, 231, 331, - 222, 407, 408, 222, 239, 105, 237, 218, 217, 536, - 111, 410, 419, 220, 541, 542, 220, 537, 424, 35, - 36, 111, 38, 39, 40, 41, 42, 438, 555, 220, - 111, 220, 355, 356, 357, 358, 359, 360, 361, 362, + 2, 199, 84, 79, 97, 81, 261, 3, 203, 184, + 83, 157, 88, 114, 83, 220, 213, 88, 213, 189, + 190, 97, 17, 18, 97, 94, 17, 18, 170, 171, + 2, 2, 114, 238, 126, 170, 171, 121, 122, 2, + 282, 2, 224, 225, 220, 223, 157, 220, 159, 220, + 91, 193, 220, 195, 220, 0, 125, 255, 108, 109, + 110, 134, 238, 241, 133, 238, 83, 238, 161, 237, + 3, 237, 238, 223, 143, 108, 109, 110, 223, 223, + 149, 98, 84, 223, 223, 161, 163, 89, 157, 239, + 119, 120, 94, 186, 239, 239, 108, 99, 110, 239, + 239, 172, 35, 36, 177, 38, 39, 40, 41, 42, + 186, 180, 114, 223, 131, 184, 133, 89, 89, 231, + 189, 190, 232, 125, 3, 320, 89, 273, 89, 324, + 325, 328, 307, 3, 309, 176, 278, 223, 140, 281, + 335, 143, 114, 278, 236, 223, 281, 231, 232, 391, + 392, 237, 219, 395, 219, 157, 223, 159, 269, 237, + 261, 223, 273, 35, 36, 35, 36, 39, 38, 39, + 40, 41, 42, 43, 44, 45, 219, 170, 171, 374, + 223, 237, 184, 220, 240, 187, 262, 189, 190, 220, + 240, 220, 219, 222, 219, 219, 223, 199, 223, 223, + 193, 219, 195, 218, 273, 223, 221, 127, 128, 129, + 130, 131, 132, 133, 134, 135, 136, 218, 211, 212, + 221, 231, 219, 219, 220, 420, 223, 469, 239, 240, + 163, 219, 231, 431, 109, 223, 240, 492, 307, 232, + 309, 411, 231, 325, 231, 387, 241, 389, 390, 36, + 241, 237, 387, 255, 389, 390, 108, 109, 110, 261, + 336, 35, 517, 336, 506, 407, 508, 269, 43, 44, + 45, 273, 407, 415, 42, 386, 117, 118, 229, 218, + 522, 123, 124, 216, 217, 278, 361, 362, 281, 109, + 485, 489, 218, 163, 218, 363, 364, 365, 366, 228, + 229, 230, 359, 360, 109, 307, 481, 309, 367, 368, + 109, 232, 388, 240, 42, 109, 409, 319, 238, 218, + 239, 516, 239, 325, 218, 218, 239, 218, 279, 218, + 332, 282, 408, 409, 241, 218, 233, 219, 420, 537, + 218, 125, 411, 538, 542, 543, 216, 217, 234, 425, + 235, 239, 218, 220, 223, 232, 221, 221, 556, 240, + 223, 106, 219, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, - 222, 218, 218, 385, 218, 220, 217, 468, 218, 237, - 231, 220, 231, 386, 238, 388, 389, 237, 231, 220, - 11, 218, 368, 218, 372, 369, 142, 239, 410, 236, - 238, 480, 236, 406, 236, 370, 158, 419, 272, 500, - 371, 414, 503, 408, 505, 516, 507, 318, 430, 331, - 419, 318, 541, 543, 88, 414, 429, 194, -1, -1, - 521, 260, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 529, -1, 3, 532, -1, -1, -1, + 373, 221, 238, 221, 386, 112, 112, 112, 339, 221, + 221, 218, 221, 223, 387, 219, 389, 390, 219, 221, + 219, 218, 238, 354, 219, 239, 232, 232, 221, 411, + 219, 219, 481, 11, 407, 369, 232, 240, 420, 371, + 238, 370, 415, 237, 375, 237, 372, 237, 239, 431, + 373, 143, 409, 261, 273, 159, 517, 430, 420, 319, + 391, 392, 332, 319, 395, 542, 544, 89, 415, 195, + -1, -1, -1, -1, 530, -1, -1, 533, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 162, -1, 480, -1, - -1, -1, -1, -1, -1, -1, 488, 35, 36, 491, - 38, 39, 40, 41, 42, 43, 44, 45, -1, 492, - 493, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 516, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 215, - 216, -1, -1, -1, 536, -1, -1, -1, -1, 541, - 542, -1, -1, -1, -1, 3, 4, 5, 6, 7, - 8, 9, 10, 555, 12, 13, 14, 15, 16, -1, - -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 33, 34, 35, 36, -1, - 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, -1, -1, -1, -1, - -1, -1, -1, -1, 162, 73, 74, 75, 76, 77, - 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, -1, -1, -1, -1, -1, - 98, 99, 100, 101, 102, 103, 104, 105, -1, 107, - 108, 109, 110, 111, 112, 113, -1, 115, -1, -1, - 118, 119, -1, -1, -1, -1, -1, 215, 216, 4, - 5, 6, 7, -1, -1, -1, -1, -1, 136, -1, - -1, -1, -1, -1, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 158, -1, -1, -1, 162, -1, -1, -1, -1, -1, - -1, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 73, 74, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 481, + -1, -1, -1, -1, -1, -1, -1, 489, 439, -1, + 492, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 493, 494, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 517, -1, -1, 469, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 215, 216, 217, - -1, 219, -1, -1, -1, 223, 224, 225, 226, 104, - -1, -1, 107, 108, 109, -1, -1, -1, -1, -1, - 238, 239, 240, 3, 4, 5, 6, 7, 8, 9, - 10, -1, 12, 13, 14, 15, 16, -1, -1, 19, + -1, -1, -1, -1, -1, 537, -1, -1, -1, -1, + 542, 543, -1, -1, -1, -1, -1, -1, -1, -1, + 501, -1, -1, 504, 556, 506, -1, 508, -1, -1, + -1, -1, -1, 3, 4, 5, 6, 7, 8, 9, + 10, 522, 12, 13, 14, 15, 16, -1, -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, -1, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, @@ -2015,22 +1998,46 @@ static const yytype_int16 yycheck[] = 60, 61, 62, 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, -1, -1, -1, -1, -1, 98, 99, - 100, 101, 102, 103, 104, 105, -1, 107, 108, 109, - 110, 111, 112, 113, -1, 115, -1, -1, 118, 119, - -1, -1, 4, 5, 6, 7, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 136, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, -1, -1, -1, -1, -1, 158, -1, - -1, -1, 162, -1, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 73, 74, -1, -1, -1, -1, -1, -1, -1, + 90, 91, 92, 93, -1, -1, -1, -1, -1, 99, + 100, 101, 102, 103, 104, 105, 106, -1, 108, 109, + 110, 111, 112, 113, 114, -1, 116, -1, -1, 119, + 120, -1, -1, -1, -1, -1, -1, 4, 5, 6, + 7, -1, -1, -1, -1, -1, -1, 137, -1, -1, + -1, -1, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, -1, 159, + -1, -1, -1, 163, -1, -1, -1, -1, -1, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 73, 74, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 215, 216, 217, -1, 219, - -1, -1, 104, 223, 224, 225, 226, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 238, 239, - 240, 3, 4, 5, 6, 7, 8, 9, 10, -1, + -1, -1, -1, -1, -1, -1, 216, 217, 218, -1, + 220, -1, -1, -1, 224, 225, 226, 227, 105, -1, + -1, 108, 109, 110, -1, -1, -1, -1, -1, 239, + 240, 241, 3, 4, 5, 6, 7, 8, 9, 10, + -1, 12, 13, 14, 15, 16, -1, -1, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, -1, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, -1, -1, -1, -1, -1, 99, 100, + 101, 102, 103, 104, 105, 106, -1, 108, 109, 110, + 111, 112, 113, 114, -1, 116, -1, -1, 119, 120, + -1, -1, -1, -1, -1, -1, 4, 5, 6, 7, + -1, -1, -1, -1, -1, -1, 137, -1, -1, -1, + -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, -1, 159, -1, + -1, -1, 163, -1, -1, -1, -1, -1, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 73, 74, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 216, 217, 218, -1, 220, + -1, -1, -1, 224, 225, 226, 227, 105, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 239, 240, + 241, 3, 4, 5, 6, 7, 8, 9, 10, -1, 12, 13, 14, 15, 16, -1, -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, -1, 38, 39, 40, 41, @@ -2039,45 +2046,69 @@ static const yytype_int16 yycheck[] = 62, 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, -1, -1, -1, -1, -1, 98, 99, 100, 101, - 102, 103, 104, 105, -1, 107, 108, 109, 110, 111, - 112, 113, -1, 115, -1, -1, 118, 119, -1, -1, + 92, 93, -1, -1, -1, -1, -1, 99, 100, 101, + 102, 103, 104, 105, 106, -1, 108, 109, 110, 111, + 112, 113, 114, -1, 116, -1, -1, 119, 120, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 136, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 137, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 158, -1, -1, -1, - 162, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 159, -1, -1, + -1, 163, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 215, 216, 217, -1, 219, -1, -1, - -1, 223, 224, 225, 226, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 238, 239, 240, 3, - 4, 5, 6, 7, 8, 9, 10, -1, 12, 13, - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, - 34, 35, 36, -1, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 73, - 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, - 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, - -1, -1, -1, -1, 98, 99, 100, 101, 102, 103, - 104, 105, -1, 107, 108, 109, 110, 111, 112, 113, - -1, 115, -1, -1, 118, 119, -1, -1, -1, -1, + -1, -1, -1, -1, 216, 217, 218, -1, 220, -1, + -1, -1, 224, 225, 226, 227, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 239, 240, 241, + 3, 4, 5, 6, 7, 8, 9, 10, -1, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, -1, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, -1, -1, -1, -1, -1, 99, 100, 101, 102, + 103, 104, 105, 106, -1, 108, 109, 110, 111, 112, + 113, 114, -1, 116, -1, -1, 119, 120, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 136, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 137, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 158, -1, -1, -1, 162, -1, + -1, -1, -1, -1, -1, -1, 159, -1, -1, -1, + 163, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 216, 217, 218, -1, 220, -1, -1, + -1, 224, 225, 226, 227, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 239, 240, 3, 4, + 5, 6, 7, 8, 9, 10, -1, 12, 13, 14, + 15, 16, -1, -1, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, -1, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, -1, + -1, -1, -1, -1, 99, 100, 101, 102, 103, 104, + 105, 106, -1, 108, 109, 110, 111, 112, 113, 114, + -1, 116, -1, -1, 119, 120, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 137, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 159, -1, -1, -1, 163, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 215, 216, 217, -1, 219, -1, -1, -1, 223, - 224, 225, 226, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 238, 239, 3, 4, 5, 6, + -1, 216, 217, 218, -1, 220, -1, -1, -1, 224, + 225, 226, 227, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 239, 240, 3, 4, 5, 6, 7, 8, 9, 10, -1, 12, 13, 14, 15, 16, -1, -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, @@ -2086,158 +2117,135 @@ static const yytype_int16 yycheck[] = 57, 58, 59, 60, 61, 62, 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, -1, -1, -1, -1, - -1, 98, 99, 100, 101, 102, 103, 104, 105, -1, - 107, 108, 109, 110, 111, 112, 113, -1, 115, -1, - -1, 118, 119, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 136, + 87, 88, 89, 90, 91, 92, 93, -1, -1, -1, + -1, -1, 99, 100, 101, 102, 103, 104, 105, 106, + -1, 108, 109, 110, 111, 112, 113, 114, -1, 116, + -1, -1, 119, 120, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 137, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 158, -1, -1, -1, 162, -1, -1, -1, -1, + -1, -1, 159, -1, -1, -1, 163, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 215, 216, - 217, -1, 219, -1, -1, -1, 223, 224, 225, 226, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 238, 239, 3, 4, 5, 6, 7, 8, 9, - 10, -1, 12, 13, 14, 15, 16, -1, -1, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, -1, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, -1, -1, -1, -1, -1, 98, 99, - 100, 101, 102, 103, 104, 105, -1, 107, 108, 109, - 110, 111, 112, 113, -1, 115, -1, -1, 118, 119, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 136, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 158, -1, - -1, -1, 162, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 215, 216, 217, -1, -1, - -1, -1, -1, 223, 224, 225, 226, 4, 5, 6, - 7, -1, -1, -1, -1, -1, -1, -1, 238, 239, - -1, -1, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, -1, -1, - -1, -1, -1, -1, -1, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 59, 60, 61, 62, 63, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 73, 74, 75, 76, - 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, -1, 4, 5, 6, - 7, 98, 99, 100, 101, 102, 103, 104, -1, -1, - -1, 108, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, -1, -1, - -1, -1, -1, -1, -1, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 59, 60, 61, 62, 63, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 73, 74, 75, 76, - 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, -1, -1, -1, -1, - -1, 98, 99, 100, 101, 102, 103, 104, -1, -1, - -1, 108, -1, -1, -1, -1, 4, 5, 6, 7, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 33, 34, -1, -1, -1, - -1, -1, -1, 240, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 73, 74, 75, 76, 77, - 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, -1, 4, 5, 6, 7, - 98, 99, 100, 101, 102, 103, 104, -1, -1, -1, - 108, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 33, 34, -1, -1, -1, - -1, -1, -1, 240, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 73, 74, 75, 76, 77, - 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, -1, -1, -1, -1, -1, - 98, 99, 100, 101, 102, 103, 104, -1, -1, -1, - 108, -1, -1, -1, -1, 4, 5, 6, 7, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 216, + 217, 218, -1, -1, -1, -1, -1, 224, 225, 226, + 227, 4, 5, 6, 7, -1, -1, -1, -1, -1, + -1, -1, 239, 240, -1, -1, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, -1, -1, -1, -1, -1, -1, -1, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, -1, 4, 5, 6, 7, 99, 100, 101, 102, + 103, 104, 105, -1, -1, -1, 109, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, -1, -1, -1, -1, -1, -1, -1, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 93, -1, -1, -1, -1, -1, 99, 100, 101, + 102, 103, 104, 105, -1, -1, -1, 109, -1, -1, + -1, 4, 5, 6, 7, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, -1, -1, -1, -1, -1, -1, 241, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, -1, 4, 5, 6, 7, 99, 100, 101, 102, + 103, 104, 105, -1, -1, -1, 109, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, -1, -1, -1, -1, -1, -1, 241, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 93, -1, -1, -1, -1, -1, 99, 100, 101, + 102, 103, 104, 105, -1, -1, -1, 109, -1, -1, + -1, 4, 5, 6, 7, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, -1, -1, -1, -1, -1, -1, 241, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, -1, 4, 5, 6, 7, 99, 100, 101, 102, + 103, 104, 105, -1, -1, -1, 109, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, -1, -1, -1, -1, -1, -1, 241, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 93, -1, -1, -1, -1, -1, 99, 100, 101, + 102, 103, 104, 105, -1, -1, -1, 109, -1, -1, + -1, 4, 5, 6, 7, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, -1, -1, -1, -1, -1, -1, 241, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, -1, 4, 5, 6, 7, 99, 100, 101, 102, + 103, 104, 105, -1, -1, -1, 109, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, -1, -1, -1, -1, -1, -1, 241, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 93, -1, -1, -1, -1, -1, 99, 100, 101, + 102, 103, 104, 105, -1, -1, -1, 109, -1, -1, + -1, -1, -1, -1, 3, 4, 5, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 34, -1, -1, -1, -1, - -1, -1, 240, 42, 43, 44, 45, 46, 47, 48, + 29, 30, 31, 32, 33, 34, 35, 36, 241, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, -1, 4, 5, 6, 7, 98, - 99, 100, 101, 102, 103, 104, -1, -1, -1, 108, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 34, -1, -1, -1, -1, - -1, -1, 240, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, - 59, 60, 61, 62, 63, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 73, 74, 75, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, -1, -1, -1, -1, -1, 98, - 99, 100, 101, 102, 103, 104, -1, -1, -1, 108, - -1, -1, -1, -1, 4, 5, 6, 7, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, -1, -1, -1, -1, -1, - -1, 240, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, -1, 4, 5, 6, 7, 98, 99, - 100, 101, 102, 103, 104, -1, -1, -1, 108, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, -1, -1, -1, -1, -1, - -1, 240, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, -1, -1, -1, -1, -1, 98, 99, - 100, 101, 102, 103, 104, -1, -1, -1, 108, -1, - -1, -1, -1, -1, -1, -1, 3, 4, 5, 6, - 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 240, 38, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 59, 60, 61, 62, 63, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 73, 74, 75, 76, - 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, -1, -1, -1, -1, - -1, 98, 99, 100, 101, 102, 103, 104, 3, -1, - 107, 108, 109, 110, 111, 112, 113, -1, 115, -1, - -1, 118, 119, -1, -1, -1, -1, -1, -1, -1, - 240, -1, -1, -1, -1, -1, -1, -1, -1, 136, - 35, 36, -1, 38, 39, 40, 41, 42, 43, 44, - 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 158, -1, -1, -1, 162, -1, -1, -1, -1, + 89, 90, 91, 92, 93, -1, -1, -1, -1, -1, + 99, 100, 101, 102, 103, 104, 105, 3, -1, 108, + 109, 110, 111, 112, 113, 114, -1, 116, -1, -1, + 119, 120, -1, -1, -1, -1, -1, -1, -1, 241, + -1, -1, -1, -1, -1, -1, -1, -1, 137, 35, + 36, -1, 38, 39, 40, 41, 42, 43, 44, 45, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 159, -1, -1, -1, 163, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 107, -1, 109, -1, -1, -1, 215, 216, - 217, -1, -1, -1, -1, -1, 223, 224, 225, 226, - 4, 5, 6, 7, -1, -1, -1, -1, -1, -1, - -1, 238, -1, -1, -1, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, - 34, -1, -1, -1, -1, -1, -1, 162, -1, -1, - -1, -1, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 73, - 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, - 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, - 215, 216, -1, -1, 98, 99, 100, 101, 102, 103, - 104, -1, -1, 107, 108, 109, 110, 111, 112, 113, - -1, 115, -1, -1, 118, 119, -1, -1, -1, -1, + -1, -1, 108, -1, 110, -1, -1, 216, 217, 218, + -1, -1, -1, -1, -1, 224, 225, 226, 227, 4, + 5, 6, 7, -1, -1, -1, -1, -1, -1, -1, + 239, -1, -1, -1, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + -1, -1, -1, -1, -1, -1, -1, 163, -1, -1, + -1, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, -1, + 216, 217, -1, -1, 99, 100, 101, 102, 103, 104, + 105, -1, -1, 108, 109, 110, 111, 112, 113, 114, + -1, 116, -1, -1, 119, 120, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -2247,9 +2255,9 @@ static const yytype_int16 yycheck[] = -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 217, -1, -1, -1, -1, -1, 223, - 224, 225, 226, 4, 5, 6, 7, -1, -1, -1, - -1, -1, -1, -1, -1, 239, -1, -1, 19, 20, + -1, -1, -1, 218, -1, -1, -1, -1, -1, 224, + 225, 226, 227, 4, 5, 6, 7, -1, -1, -1, + -1, -1, -1, -1, -1, 240, -1, -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46, 47, 48, 49, 50, @@ -2257,9 +2265,9 @@ static const yytype_int16 yycheck[] = 61, 62, 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, -1, -1, -1, -1, -1, 98, 99, 100, - 101, 102, 103, 104, -1, -1, 107, 108, 109, 110, - 111, 112, 113, -1, 115, -1, -1, 118, 119, -1, + 91, 92, 93, -1, -1, -1, -1, -1, 99, 100, + 101, 102, 103, 104, 105, -1, -1, 108, 109, 110, + 111, 112, 113, 114, -1, 116, -1, -1, 119, 120, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -2269,96 +2277,42 @@ static const yytype_int16 yycheck[] = -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 217, -1, -1, -1, - -1, -1, 223, 224, 225, 226, 3, 4, 5, 6, - 7, -1, -1, -1, -1, -1, -1, 238, -1, -1, - -1, -1, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - -1, 38, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 59, 60, 61, 62, 63, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 73, 74, 75, 76, - 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, -1, -1, -1, -1, - -1, 98, 99, 100, 101, 102, 103, 104, -1, -1, - 107, 108, 109, 110, 111, 112, 113, -1, 115, -1, - -1, 118, 119, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 136, + -1, -1, -1, -1, -1, -1, -1, 218, -1, -1, + -1, -1, -1, 224, 225, 226, 227, 3, 4, 5, + 6, 7, -1, -1, -1, -1, -1, -1, 239, -1, + -1, -1, -1, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, -1, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 73, 74, 75, + 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, -1, -1, + -1, -1, -1, 99, 100, 101, 102, 103, 104, 105, + -1, -1, 108, 109, 110, 111, 112, 113, 114, -1, + 116, -1, -1, 119, 120, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 137, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 162, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 215, 216, - 217, 3, 4, 5, 6, 7, 223, 224, 225, 226, - -1, -1, -1, -1, -1, -1, -1, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 73, 74, 75, 76, 77, 78, 79, 80, 81, - 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, -1, -1, -1, -1, -1, 98, 99, 100, 101, - 102, 103, 104, -1, -1, 107, 108, 109, 110, 111, - 112, 113, -1, 115, -1, -1, 118, 119, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 163, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 4, 5, 6, 7, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, - 31, 32, 33, 34, -1, 217, -1, -1, -1, -1, - -1, 223, 224, 225, 226, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, - 61, 62, 63, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 73, 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, -1, -1, -1, -1, -1, 98, 99, 100, - 101, 102, 103, 104, -1, -1, 107, 108, 109, 110, - 111, 112, 113, -1, 115, -1, -1, 118, 119, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 4, 5, 6, 7, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 19, + 216, 217, 218, 3, 4, 5, 6, 7, 224, 225, + 226, 227, -1, -1, -1, -1, -1, -1, -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, -1, 217, -1, -1, 220, - -1, -1, 223, 224, 225, 226, 46, 47, 48, 49, + 30, 31, 32, 33, 34, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, -1, -1, -1, -1, -1, 98, 99, - 100, 101, 102, 103, 104, -1, -1, 107, 108, 109, - 110, 111, 112, 113, -1, 115, -1, -1, 118, 119, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 4, 5, 6, 7, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 34, -1, 217, -1, -1, - 220, -1, -1, 223, 224, 225, 226, 46, 47, 48, - 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, - 59, 60, 61, 62, 63, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 73, 74, 75, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, -1, -1, -1, -1, -1, 98, - 99, 100, 101, 102, 103, 104, -1, -1, 107, 108, - 109, 110, 111, 112, 113, 114, 115, -1, -1, 118, - 119, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 90, 91, 92, 93, -1, -1, -1, -1, -1, 99, + 100, 101, 102, 103, 104, 105, -1, -1, 108, 109, + 110, 111, 112, 113, 114, -1, 116, -1, -1, 119, + 120, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -2367,34 +2321,16 @@ static const yytype_int16 yycheck[] = -1, -1, -1, -1, -1, -1, 4, 5, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 33, 34, -1, 217, -1, - -1, -1, -1, -1, 223, 224, 225, 226, 46, 47, + 28, 29, 30, 31, 32, 33, 34, -1, 218, -1, + -1, -1, -1, -1, 224, 225, 226, 227, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, -1, -1, -1, -1, -1, - 98, 99, 100, 101, 102, 103, 104, -1, -1, 107, - 108, 109, 110, 111, 112, 113, -1, 115, -1, -1, - 118, 119, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 4, 5, 6, - 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, -1, 217, - -1, -1, 220, -1, -1, 223, 224, 225, 226, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 59, 60, 61, 62, 63, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 73, 74, 75, 76, - 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, -1, -1, -1, -1, - -1, 98, 99, 100, 101, 102, 103, 104, -1, -1, - 107, 108, 109, 110, 111, 112, 113, -1, 115, -1, - -1, 118, 119, -1, -1, -1, -1, -1, -1, -1, + 88, 89, 90, 91, 92, 93, -1, -1, -1, -1, + -1, 99, 100, 101, 102, 103, 104, 105, -1, -1, + 108, 109, 110, 111, 112, 113, 114, -1, 116, -1, + -1, 119, 120, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -2404,33 +2340,15 @@ static const yytype_int16 yycheck[] = 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, -1, - 217, -1, -1, 220, -1, -1, 223, 224, 225, 226, + 218, -1, -1, 221, -1, -1, 224, 225, 226, 227, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, -1, -1, -1, - -1, -1, 98, 99, 100, 101, 102, 103, 104, -1, - -1, 107, 108, 109, 110, 111, 112, 113, -1, 115, - -1, -1, 118, 119, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, - 5, 6, 7, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - -1, 217, -1, -1, -1, -1, -1, 223, 224, 225, - 226, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 73, 74, - 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, - 85, 86, 87, 88, 89, 90, 91, 92, -1, -1, - -1, -1, -1, 98, 99, 100, 101, 102, 103, 104, - -1, -1, 107, 108, 109, 110, 111, 112, 113, -1, - 115, -1, -1, 118, 119, -1, -1, -1, -1, -1, + 86, 87, 88, 89, 90, 91, 92, 93, -1, -1, + -1, -1, -1, 99, 100, 101, 102, 103, 104, 105, + -1, -1, 108, 109, 110, 111, 112, 113, 114, -1, + 116, -1, -1, 119, 120, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -2440,171 +2358,262 @@ static const yytype_int16 yycheck[] = 4, 5, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, - 34, -1, 217, -1, -1, -1, -1, -1, 223, 224, - 225, 226, 46, 47, 48, 49, 50, 51, 52, 53, + 34, -1, 218, -1, -1, 221, -1, -1, 224, 225, + 226, 227, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, - 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, - -1, -1, -1, -1, 98, 99, 100, 101, 102, 103, - 104, -1, -1, 107, 108, 109, 110, 111, 112, 113, - -1, 115, -1, -1, 118, 119, -1, -1, -1, -1, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + -1, -1, -1, -1, -1, 99, 100, 101, 102, 103, + 104, 105, -1, -1, 108, 109, 110, 111, 112, 113, + 114, 115, 116, -1, -1, 119, 120, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 4, 5, 6, 7, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, -1, 218, -1, -1, -1, -1, -1, + 224, 225, 226, 227, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 93, -1, -1, -1, -1, -1, 99, 100, 101, + 102, 103, 104, 105, -1, -1, 108, 109, 110, 111, + 112, 113, 114, -1, 116, -1, -1, 119, 120, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 3, 4, 5, - 6, 7, -1, 217, -1, -1, -1, -1, -1, 223, - 224, 225, 226, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, -1, 38, 39, 40, 41, 42, 43, 44, 45, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 4, 5, 6, 7, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, -1, 218, -1, -1, 221, + -1, -1, 224, 225, 226, 227, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, -1, -1, -1, -1, -1, 99, + 100, 101, 102, 103, 104, 105, -1, -1, 108, 109, + 110, 111, 112, 113, 114, -1, 116, -1, -1, 119, + 120, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 4, 5, 6, 7, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, -1, 218, -1, + -1, 221, -1, -1, 224, 225, 226, 227, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, -1, -1, -1, -1, + -1, 99, 100, 101, 102, 103, 104, 105, -1, -1, + 108, 109, 110, 111, 112, 113, 114, -1, 116, -1, + -1, 119, 120, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 4, 5, + 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, -1, + 218, -1, -1, -1, -1, -1, 224, 225, 226, 227, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, -1, -1, -1, - -1, -1, 98, 99, 100, 101, 102, 103, 104, -1, - 106, -1, 108, -1, -1, -1, -1, -1, -1, -1, + 86, 87, 88, 89, 90, 91, 92, 93, -1, -1, + -1, -1, -1, 99, 100, 101, 102, 103, 104, 105, + -1, -1, 108, 109, 110, 111, 112, 113, 114, -1, + 116, -1, -1, 119, 120, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 136, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 4, 5, 6, 7, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, -1, 218, -1, -1, -1, -1, -1, 224, 225, + 226, 227, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + -1, -1, -1, -1, -1, 99, 100, 101, 102, 103, + 104, 105, -1, -1, 108, 109, 110, 111, 112, 113, + 114, -1, 116, -1, -1, 119, 120, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 3, 4, + 5, 6, 7, -1, 218, -1, -1, -1, -1, -1, + 224, 225, 226, 227, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, -1, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, -1, + -1, -1, -1, -1, 99, 100, 101, 102, 103, 104, + 105, -1, 107, -1, 109, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 137, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 3, 4, 5, 6, + 7, -1, -1, -1, 159, -1, -1, -1, 163, -1, + -1, -1, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + -1, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, -1, -1, -1, + -1, 216, 217, -1, -1, 220, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, -1, -1, -1, + -1, -1, 99, 100, 101, 102, 103, 104, 105, -1, + -1, -1, 109, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 137, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, 4, 5, 6, 7, -1, - -1, -1, 158, -1, -1, -1, 162, -1, -1, -1, + -1, -1, 159, -1, -1, -1, 163, -1, -1, -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, -1, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, - 59, 60, 61, 62, 63, -1, -1, -1, -1, 215, - 216, -1, -1, 219, 73, 74, 75, 76, 77, 78, + 59, 60, 61, 62, 63, -1, -1, -1, -1, 216, + 217, -1, -1, 220, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, -1, -1, -1, -1, -1, 98, - 99, 100, 101, 102, 103, 104, -1, -1, -1, 108, + 89, 90, 91, 92, 93, -1, -1, -1, -1, -1, + 99, 100, 101, 102, 103, 104, 105, -1, -1, -1, + 109, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 136, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 3, 4, 5, 6, 7, -1, -1, -1, 158, - -1, -1, -1, 162, -1, -1, -1, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, -1, 38, 39, 40, 41, - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, -1, -1, -1, -1, 215, 216, -1, -1, - 219, 73, 74, 75, 76, 77, 78, 79, 80, 81, - 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, -1, -1, -1, -1, -1, 98, 99, 100, 101, - 102, 103, 104, -1, -1, -1, 108, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 136, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 3, 4, 5, 6, 7, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 162, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, - 38, -1, -1, -1, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, -1, -1, -1, -1, - -1, -1, -1, 215, 216, 73, 74, 75, 76, 77, - 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, - 98, 99, 100, 101, 102, 103, 104, -1, -1, -1, - 108, 3, 4, 5, 6, 7, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, -1, -1, -1, 38, -1, -1, -1, - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 73, 74, 75, 76, 77, 78, 79, 80, 81, - 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, -1, 4, 5, 6, 7, 98, 99, 100, 101, - 102, 103, 104, -1, -1, -1, 108, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, -1, -1, -1, -1, - -1, -1, -1, -1, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 73, 74, 75, 76, 77, 78, 79, 80, 81, - 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, - 102, 103, 104, -1, -1, -1, 108, 4, 5, 6, + -1, -1, -1, -1, -1, -1, -1, -1, 137, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, + 4, 5, 6, 7, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 163, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, -1, -1, -1, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + -1, -1, -1, -1, -1, -1, -1, 216, 217, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, -1, -1, -1, 109, 3, 4, 5, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 46, + -1, 38, -1, -1, -1, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, -1, -1, -1, -1, - -1, 98, 99, 100, 101, 102, 103, 104, -1, -1, - -1, 108 + 87, 88, 89, 90, 91, 92, 93, -1, 4, 5, + 6, 7, 99, 100, 101, 102, 103, 104, 105, -1, + -1, -1, 109, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, -1, -1, -1, -1, -1, -1, -1, -1, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 73, 74, 75, + 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + -1, -1, -1, 109, 4, 5, 6, 7, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, -1, -1, -1, -1, -1, 99, + 100, 101, 102, 103, 104, 105, -1, -1, -1, 109 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint16 yystos[] = { - 0, 242, 243, 0, 3, 4, 5, 6, 7, 19, + 0, 243, 244, 0, 3, 4, 5, 6, 7, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 98, 99, 100, 101, 102, 103, 104, - 106, 108, 136, 158, 162, 215, 216, 219, 245, 278, - 280, 281, 282, 283, 288, 289, 290, 291, 293, 294, + 90, 91, 92, 93, 99, 100, 101, 102, 103, 104, + 105, 107, 109, 137, 159, 163, 216, 217, 220, 246, + 279, 281, 282, 283, 284, 289, 290, 291, 292, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, - 305, 338, 341, 342, 343, 344, 162, 35, 36, 39, - 230, 107, 108, 109, 239, 244, 244, 107, 109, 246, - 291, 294, 136, 290, 3, 244, 299, 338, 238, 239, - 321, 218, 222, 3, 35, 36, 37, 38, 42, 93, - 94, 95, 96, 97, 284, 285, 286, 291, 292, 295, - 222, 238, 107, 109, 244, 246, 312, 294, 295, 219, - 219, 230, 230, 230, 230, 280, 290, 341, 108, 42, - 240, 291, 295, 306, 307, 308, 309, 236, 239, 239, - 294, 246, 217, 220, 217, 220, 8, 9, 10, 12, - 13, 14, 15, 16, 105, 110, 111, 112, 113, 115, - 118, 119, 217, 223, 224, 225, 226, 238, 239, 240, - 246, 247, 248, 250, 251, 252, 253, 254, 255, 256, - 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, - 271, 272, 273, 274, 276, 278, 279, 280, 288, 295, - 315, 316, 317, 318, 322, 323, 324, 327, 333, 337, - 342, 236, 285, 36, 35, 291, 284, 287, 292, 295, - 42, 284, 286, 244, 312, 244, 312, 219, 237, 217, - 219, 237, 220, 261, 273, 277, 295, 220, 277, 299, - 108, 108, 108, 321, 231, 291, 42, 240, 307, 244, - 310, 311, 312, 295, 108, 240, 306, 240, 306, 217, - 114, 277, 339, 340, 340, 238, 238, 316, 217, 217, - 238, 238, 276, 217, 217, 261, 261, 3, 276, 298, - 240, 319, 118, 119, 219, 221, 218, 218, 222, 104, - 274, 217, 126, 127, 128, 129, 130, 131, 132, 133, - 134, 135, 237, 275, 261, 227, 228, 229, 223, 224, - 116, 117, 120, 121, 230, 231, 122, 123, 232, 233, - 234, 124, 125, 235, 222, 238, 238, 240, 316, 317, - 318, 244, 284, 284, 287, 292, 219, 236, 237, 219, - 237, 237, 220, 277, 239, 274, 313, 277, 313, 220, - 220, 222, 231, 231, 222, 222, 219, 236, 222, 238, - 239, 240, 240, 218, 222, 218, 105, 315, 323, 334, - 276, 238, 276, 276, 290, 326, 298, 218, 3, 218, - 322, 249, 276, 244, 246, 257, 258, 259, 260, 274, - 274, 261, 261, 261, 263, 263, 264, 264, 265, 265, - 265, 265, 266, 266, 267, 268, 269, 270, 271, 276, - 274, 284, 277, 244, 277, 220, 313, 313, 237, 220, - 313, 314, 220, 111, 111, 111, 277, 244, 311, 240, - 306, 220, 339, 220, 217, 326, 335, 336, 218, 218, - 244, 218, 218, 218, 261, 240, 220, 217, 218, 218, - 222, 104, 274, 236, 220, 237, 313, 222, 240, 231, - 231, 231, 220, 240, 276, 238, 218, 316, 325, 239, - 328, 237, 317, 320, 321, 261, 261, 274, 274, 236, - 313, 313, 236, 218, 276, 320, 11, 17, 18, 240, - 329, 330, 331, 332, 313, 244, 244, 238, 316, 276, - 236, 316, 329, 316, 240, 331, 236 + 305, 306, 339, 342, 343, 344, 345, 163, 35, 36, + 39, 231, 108, 109, 110, 240, 245, 245, 108, 110, + 247, 292, 295, 137, 291, 3, 245, 300, 339, 239, + 240, 322, 219, 223, 3, 35, 36, 37, 38, 42, + 94, 95, 96, 97, 98, 285, 286, 287, 292, 293, + 296, 223, 239, 108, 110, 245, 247, 313, 295, 296, + 220, 220, 231, 231, 231, 231, 281, 291, 342, 109, + 42, 241, 292, 296, 307, 308, 309, 310, 237, 240, + 240, 295, 247, 218, 221, 218, 221, 8, 9, 10, + 12, 13, 14, 15, 16, 106, 111, 112, 113, 114, + 116, 119, 120, 218, 224, 225, 226, 227, 239, 240, + 241, 247, 248, 249, 251, 252, 253, 254, 255, 256, + 257, 262, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 273, 274, 275, 277, 279, 280, 281, 289, + 296, 316, 317, 318, 319, 323, 324, 325, 328, 334, + 338, 343, 237, 286, 36, 35, 292, 285, 288, 293, + 296, 42, 285, 287, 245, 313, 245, 313, 220, 238, + 218, 220, 238, 221, 262, 274, 278, 296, 221, 278, + 300, 109, 109, 109, 322, 232, 292, 42, 241, 308, + 245, 311, 312, 313, 296, 109, 241, 307, 241, 307, + 218, 115, 278, 340, 341, 341, 239, 239, 317, 218, + 218, 239, 239, 277, 218, 218, 262, 262, 3, 277, + 299, 241, 320, 119, 120, 220, 222, 219, 219, 223, + 105, 275, 218, 127, 128, 129, 130, 131, 132, 133, + 134, 135, 136, 238, 276, 262, 228, 229, 230, 224, + 225, 117, 118, 121, 122, 231, 232, 123, 124, 233, + 234, 235, 125, 126, 236, 223, 239, 239, 241, 317, + 318, 319, 245, 285, 285, 288, 293, 220, 237, 238, + 220, 238, 238, 221, 278, 240, 275, 314, 278, 314, + 221, 221, 223, 232, 232, 223, 223, 220, 237, 223, + 239, 240, 241, 241, 219, 223, 219, 106, 316, 324, + 335, 277, 239, 277, 277, 291, 327, 299, 219, 3, + 219, 323, 250, 277, 245, 247, 258, 259, 260, 261, + 275, 275, 262, 262, 262, 264, 264, 265, 265, 266, + 266, 266, 266, 267, 267, 268, 269, 270, 271, 272, + 277, 275, 285, 278, 245, 278, 221, 314, 314, 238, + 221, 314, 315, 221, 112, 112, 112, 278, 245, 312, + 241, 307, 221, 340, 221, 218, 327, 336, 337, 219, + 219, 245, 219, 219, 219, 262, 241, 221, 218, 219, + 219, 223, 105, 275, 237, 221, 238, 314, 223, 241, + 232, 232, 232, 221, 241, 277, 239, 219, 317, 326, + 240, 329, 238, 318, 321, 322, 262, 262, 275, 275, + 237, 314, 314, 237, 219, 277, 321, 11, 17, 18, + 241, 330, 331, 332, 333, 314, 245, 245, 239, 317, + 277, 237, 317, 330, 317, 241, 332, 237 }; #define yyerrok (yyerrstatus = 0) @@ -3318,7 +3327,7 @@ YYLTYPE yylloc; } /* Line 1590 of yacc.c */ -#line 3322 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.inl" +#line 3331 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.inl" yylsp[0] = yylloc; goto yysetstate; @@ -5571,118 +5580,125 @@ yyreduce: /* Line 1806 of yacc.c */ #line 1517 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" - { (yyval.identifier) = "Texture2DMSArray"; } + { (yyval.identifier) = "TextureExternal"; } break; case 248: /* Line 1806 of yacc.c */ #line 1518 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" - { (yyval.identifier) = "Texture3D"; } + { (yyval.identifier) = "Texture2DMSArray"; } break; case 249: /* Line 1806 of yacc.c */ #line 1519 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" - { (yyval.identifier) = "TextureCube"; } + { (yyval.identifier) = "Texture3D"; } break; case 250: /* Line 1806 of yacc.c */ #line 1520 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" - { (yyval.identifier) = "TextureCubeArray"; } + { (yyval.identifier) = "TextureCube"; } break; case 251: /* Line 1806 of yacc.c */ #line 1521 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" - { (yyval.identifier) = "RWBuffer"; } + { (yyval.identifier) = "TextureCubeArray"; } break; case 252: /* Line 1806 of yacc.c */ #line 1522 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" - { (yyval.identifier) = "RWByteAddressBuffer"; } + { (yyval.identifier) = "RWBuffer"; } break; case 253: /* Line 1806 of yacc.c */ #line 1523 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" - { (yyval.identifier) = "RWTexture1D"; } + { (yyval.identifier) = "RWByteAddressBuffer"; } break; case 254: /* Line 1806 of yacc.c */ #line 1524 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" - { (yyval.identifier) = "RWTexture1DArray"; } + { (yyval.identifier) = "RWTexture1D"; } break; case 255: /* Line 1806 of yacc.c */ #line 1525 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" - { (yyval.identifier) = "RWTexture2D"; } + { (yyval.identifier) = "RWTexture1DArray"; } break; case 256: /* Line 1806 of yacc.c */ #line 1526 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" - { (yyval.identifier) = "RWTexture2DArray"; } + { (yyval.identifier) = "RWTexture2D"; } break; case 257: /* Line 1806 of yacc.c */ #line 1527 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" - { (yyval.identifier) = "RWTexture3D"; } + { (yyval.identifier) = "RWTexture2DArray"; } break; case 258: /* Line 1806 of yacc.c */ -#line 1531 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" - { (yyval.identifier) = "PointStream"; } +#line 1528 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" + { (yyval.identifier) = "RWTexture3D"; } break; case 259: /* Line 1806 of yacc.c */ #line 1532 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" - { (yyval.identifier) = "LineStream"; } + { (yyval.identifier) = "PointStream"; } break; case 260: /* Line 1806 of yacc.c */ #line 1533 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" - { (yyval.identifier) = "TriangleStream"; } + { (yyval.identifier) = "LineStream"; } break; case 261: /* Line 1806 of yacc.c */ -#line 1537 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" - { (yyval.identifier) = "InputPatch"; } +#line 1534 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" + { (yyval.identifier) = "TriangleStream"; } break; case 262: /* Line 1806 of yacc.c */ -#line 1541 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" - { (yyval.identifier) = "OutputPatch"; } +#line 1538 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" + { (yyval.identifier) = "InputPatch"; } break; case 263: /* Line 1806 of yacc.c */ -#line 1546 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1542 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" + { (yyval.identifier) = "OutputPatch"; } + break; + + case 264: + +/* Line 1806 of yacc.c */ +#line 1547 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.struct_specifier) = new(ctx) ast_struct_specifier((yyvsp[(2) - (5)].identifier), (yyvsp[(4) - (5)].node)); @@ -5691,10 +5707,10 @@ yyreduce: } break; - case 264: + case 265: /* Line 1806 of yacc.c */ -#line 1553 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1554 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.struct_specifier) = new(ctx) ast_struct_specifier((yyvsp[(2) - (7)].identifier), (yyvsp[(4) - (7)].identifier), (yyvsp[(6) - (7)].node)); @@ -5703,10 +5719,10 @@ yyreduce: } break; - case 265: + case 266: /* Line 1806 of yacc.c */ -#line 1560 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1561 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.struct_specifier) = new(ctx) ast_struct_specifier(NULL, (yyvsp[(3) - (4)].node)); @@ -5714,10 +5730,10 @@ yyreduce: } break; - case 266: + case 267: /* Line 1806 of yacc.c */ -#line 1566 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1567 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.struct_specifier) = new(ctx) ast_struct_specifier((yyvsp[(2) - (4)].identifier),NULL); @@ -5726,10 +5742,10 @@ yyreduce: } break; - case 267: + case 268: /* Line 1806 of yacc.c */ -#line 1573 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1574 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.struct_specifier) = new(ctx) ast_struct_specifier((yyvsp[(2) - (6)].identifier), (yyvsp[(4) - (6)].identifier), NULL); @@ -5738,10 +5754,10 @@ yyreduce: } break; - case 268: + case 269: /* Line 1806 of yacc.c */ -#line 1580 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1581 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.struct_specifier) = new(ctx) ast_struct_specifier(NULL,NULL); @@ -5749,10 +5765,10 @@ yyreduce: } break; - case 269: + case 270: /* Line 1806 of yacc.c */ -#line 1589 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1590 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.node) = new(ctx) ast_cbuffer_declaration((yyvsp[(2) - (5)].identifier), (yyvsp[(4) - (5)].node)); @@ -5760,40 +5776,40 @@ yyreduce: } break; - case 270: + case 271: /* Line 1806 of yacc.c */ -#line 1595 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1596 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { /* Do nothing! */ (yyval.node) = NULL; } break; - case 271: + case 272: /* Line 1806 of yacc.c */ -#line 1603 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1604 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { (yyval.node) = (ast_node *) (yyvsp[(1) - (1)].declarator_list); (yyvsp[(1) - (1)].declarator_list)->link.self_link(); } break; - case 272: + case 273: /* Line 1806 of yacc.c */ -#line 1608 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1609 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { (yyval.node) = (ast_node *) (yyvsp[(1) - (2)].node); (yyval.node)->link.insert_before(& (yyvsp[(2) - (2)].declarator_list)->link); } break; - case 273: + case 274: /* Line 1806 of yacc.c */ -#line 1616 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1617 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.declarator_list) = new(ctx) ast_declarator_list((yyvsp[(1) - (3)].fully_specified_type)); @@ -5802,10 +5818,10 @@ yyreduce: } break; - case 274: + case 275: /* Line 1806 of yacc.c */ -#line 1626 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1627 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.fully_specified_type) = new(ctx) ast_fully_specified_type(); @@ -5814,10 +5830,10 @@ yyreduce: } break; - case 275: + case 276: /* Line 1806 of yacc.c */ -#line 1633 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1634 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.fully_specified_type) = new(ctx) ast_fully_specified_type(); @@ -5827,22 +5843,12 @@ yyreduce: } break; - case 277: - -/* Line 1806 of yacc.c */ -#line 1645 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" - { - (yyval.type_qualifier) = (yyvsp[(2) - (2)].type_qualifier); - (yyval.type_qualifier).flags.q.centroid = 1; - } - break; - case 278: /* Line 1806 of yacc.c */ -#line 1650 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1646 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { - (yyval.type_qualifier) = (yyvsp[(1) - (2)].type_qualifier); + (yyval.type_qualifier) = (yyvsp[(2) - (2)].type_qualifier); (yyval.type_qualifier).flags.q.centroid = 1; } break; @@ -5850,9 +5856,9 @@ yyreduce: case 279: /* Line 1806 of yacc.c */ -#line 1655 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1651 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { - memset(& (yyval.type_qualifier), 0, sizeof((yyval.type_qualifier))); + (yyval.type_qualifier) = (yyvsp[(1) - (2)].type_qualifier); (yyval.type_qualifier).flags.q.centroid = 1; } break; @@ -5860,27 +5866,37 @@ yyreduce: case 280: /* Line 1806 of yacc.c */ -#line 1663 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1656 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { - (yyval.declaration) = (yyvsp[(1) - (1)].declaration); - (yyvsp[(1) - (1)].declaration)->link.self_link(); + memset(& (yyval.type_qualifier), 0, sizeof((yyval.type_qualifier))); + (yyval.type_qualifier).flags.q.centroid = 1; } break; case 281: /* Line 1806 of yacc.c */ -#line 1668 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1664 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { - (yyval.declaration) = (yyvsp[(1) - (3)].declaration); - (yyval.declaration)->link.insert_before(& (yyvsp[(3) - (3)].declaration)->link); + (yyval.declaration) = (yyvsp[(1) - (1)].declaration); + (yyvsp[(1) - (1)].declaration)->link.self_link(); } break; case 282: /* Line 1806 of yacc.c */ -#line 1676 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1669 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" + { + (yyval.declaration) = (yyvsp[(1) - (3)].declaration); + (yyval.declaration)->link.insert_before(& (yyvsp[(3) - (3)].declaration)->link); + } + break; + + case 283: + +/* Line 1806 of yacc.c */ +#line 1677 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.declaration) = new(ctx) ast_declaration((yyvsp[(1) - (1)].identifier), false, NULL, NULL); @@ -5889,20 +5905,20 @@ yyreduce: } break; - case 283: + case 284: /* Line 1806 of yacc.c */ -#line 1683 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1684 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.declaration) = (yyvsp[(1) - (1)].declaration); } break; - case 284: + case 285: /* Line 1806 of yacc.c */ -#line 1688 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1689 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.declaration) = new(ctx) ast_declaration((yyvsp[(1) - (3)].identifier), false, NULL, NULL); @@ -5912,10 +5928,10 @@ yyreduce: } break; - case 285: + case 286: /* Line 1806 of yacc.c */ -#line 1696 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1697 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.declaration) = new(ctx) ast_declaration((yyvsp[(1) - (6)].identifier), true, (yyvsp[(3) - (6)].expression), NULL); @@ -5924,10 +5940,10 @@ yyreduce: } break; - case 286: + case 287: /* Line 1806 of yacc.c */ -#line 1706 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1707 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.declaration) = new(ctx) ast_declaration((yyvsp[(1) - (4)].identifier), true, (yyvsp[(3) - (4)].expression), NULL); @@ -5935,10 +5951,10 @@ yyreduce: } break; - case 287: + case 288: /* Line 1806 of yacc.c */ -#line 1712 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1713 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.declaration) = (yyvsp[(1) - (4)].declaration); @@ -5947,10 +5963,10 @@ yyreduce: } break; - case 289: + case 290: /* Line 1806 of yacc.c */ -#line 1722 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1723 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.expression) = new(ctx) ast_initializer_list_expression(); @@ -5958,66 +5974,66 @@ yyreduce: } break; - case 290: + case 291: /* Line 1806 of yacc.c */ -#line 1731 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1732 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { (yyval.expression) = (yyvsp[(1) - (1)].expression); (yyval.expression)->link.self_link(); } break; - case 291: + case 292: /* Line 1806 of yacc.c */ -#line 1736 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1737 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { (yyval.expression) = (yyvsp[(1) - (3)].expression); (yyval.expression)->link.insert_before(& (yyvsp[(3) - (3)].expression)->link); } break; - case 292: + case 293: /* Line 1806 of yacc.c */ -#line 1741 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1742 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { (yyval.expression) = (yyvsp[(1) - (2)].expression); } break; - case 294: + case 295: /* Line 1806 of yacc.c */ -#line 1753 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1754 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { (yyval.node) = (ast_node *) (yyvsp[(1) - (1)].compound_statement); } break; - case 296: + case 297: /* Line 1806 of yacc.c */ -#line 1756 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1757 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { (yyval.node) = (ast_node *) (yyvsp[(2) - (2)].compound_statement); (yyval.node)->attributes.push_degenerate_list_at_head( & (yyvsp[(1) - (2)].attribute)->link); } break; - case 297: + case 298: /* Line 1806 of yacc.c */ -#line 1761 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1762 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { (yyval.node) = (yyvsp[(2) - (2)].node); (yyval.node)->attributes.push_degenerate_list_at_head( & (yyvsp[(1) - (2)].attribute)->link); } break; - case 304: + case 305: /* Line 1806 of yacc.c */ -#line 1778 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1779 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.compound_statement) = new(ctx) ast_compound_statement(true, NULL); @@ -6025,19 +6041,19 @@ yyreduce: } break; - case 305: + case 306: /* Line 1806 of yacc.c */ -#line 1784 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1785 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { state->symbols->push_scope(); } break; - case 306: + case 307: /* Line 1806 of yacc.c */ -#line 1788 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1789 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.compound_statement) = new(ctx) ast_compound_statement(true, (yyvsp[(3) - (4)].node)); @@ -6046,17 +6062,17 @@ yyreduce: } break; - case 307: + case 308: /* Line 1806 of yacc.c */ -#line 1797 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1798 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { (yyval.node) = (ast_node *) (yyvsp[(1) - (1)].compound_statement); } break; - case 309: + case 310: /* Line 1806 of yacc.c */ -#line 1803 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1804 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.compound_statement) = new(ctx) ast_compound_statement(false, NULL); @@ -6064,10 +6080,10 @@ yyreduce: } break; - case 310: + case 311: /* Line 1806 of yacc.c */ -#line 1809 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1810 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.compound_statement) = new(ctx) ast_compound_statement(false, (yyvsp[(2) - (3)].node)); @@ -6075,10 +6091,10 @@ yyreduce: } break; - case 311: + case 312: /* Line 1806 of yacc.c */ -#line 1818 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1819 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { if ((yyvsp[(1) - (1)].node) == NULL) { _mesa_glsl_error(& (yylsp[(1) - (1)]), state, " statement\n"); @@ -6090,10 +6106,10 @@ yyreduce: } break; - case 312: + case 313: /* Line 1806 of yacc.c */ -#line 1828 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1829 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { if ((yyvsp[(2) - (2)].node) == NULL) { _mesa_glsl_error(& (yylsp[(2) - (2)]), state, " statement\n"); @@ -6104,10 +6120,10 @@ yyreduce: } break; - case 313: + case 314: /* Line 1806 of yacc.c */ -#line 1840 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1841 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.node) = new(ctx) ast_expression_statement(NULL); @@ -6115,10 +6131,10 @@ yyreduce: } break; - case 314: + case 315: /* Line 1806 of yacc.c */ -#line 1846 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1847 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.node) = new(ctx) ast_expression_statement((yyvsp[(1) - (2)].expression)); @@ -6126,10 +6142,10 @@ yyreduce: } break; - case 315: + case 316: /* Line 1806 of yacc.c */ -#line 1855 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1856 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { (yyval.node) = new(state) ast_selection_statement((yyvsp[(3) - (5)].expression), (yyvsp[(5) - (5)].selection_rest_statement).then_statement, (yyvsp[(5) - (5)].selection_rest_statement).else_statement); @@ -6137,39 +6153,39 @@ yyreduce: } break; - case 316: + case 317: /* Line 1806 of yacc.c */ -#line 1864 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1865 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { (yyval.selection_rest_statement).then_statement = (yyvsp[(1) - (3)].node); (yyval.selection_rest_statement).else_statement = (yyvsp[(3) - (3)].node); } break; - case 317: + case 318: /* Line 1806 of yacc.c */ -#line 1869 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1870 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { (yyval.selection_rest_statement).then_statement = (yyvsp[(1) - (1)].node); (yyval.selection_rest_statement).else_statement = NULL; } break; - case 318: + case 319: /* Line 1806 of yacc.c */ -#line 1877 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1878 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { (yyval.node) = (ast_node *) (yyvsp[(1) - (1)].expression); } break; - case 319: + case 320: /* Line 1806 of yacc.c */ -#line 1881 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1882 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; ast_declaration *decl = new(ctx) ast_declaration((yyvsp[(2) - (4)].identifier), false, NULL, (yyvsp[(4) - (4)].expression)); @@ -6182,32 +6198,22 @@ yyreduce: } break; - case 320: + case 321: /* Line 1806 of yacc.c */ -#line 1899 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1900 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { (yyval.node) = new(state) ast_switch_statement((yyvsp[(3) - (5)].expression), (yyvsp[(5) - (5)].switch_body)); (yyval.node)->set_location(yylloc); } break; - case 321: - -/* Line 1806 of yacc.c */ -#line 1907 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" - { - (yyval.switch_body) = new(state) ast_switch_body(NULL); - (yyval.switch_body)->set_location(yylloc); - } - break; - case 322: /* Line 1806 of yacc.c */ -#line 1912 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1908 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { - (yyval.switch_body) = new(state) ast_switch_body((yyvsp[(2) - (3)].case_statement_list)); + (yyval.switch_body) = new(state) ast_switch_body(NULL); (yyval.switch_body)->set_location(yylloc); } break; @@ -6215,19 +6221,19 @@ yyreduce: case 323: /* Line 1806 of yacc.c */ -#line 1920 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1913 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { - (yyval.case_label) = new(state) ast_case_label((yyvsp[(2) - (3)].expression)); - (yyval.case_label)->set_location(yylloc); + (yyval.switch_body) = new(state) ast_switch_body((yyvsp[(2) - (3)].case_statement_list)); + (yyval.switch_body)->set_location(yylloc); } break; case 324: /* Line 1806 of yacc.c */ -#line 1925 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1921 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { - (yyval.case_label) = new(state) ast_case_label(NULL); + (yyval.case_label) = new(state) ast_case_label((yyvsp[(2) - (3)].expression)); (yyval.case_label)->set_location(yylloc); } break; @@ -6235,7 +6241,17 @@ yyreduce: case 325: /* Line 1806 of yacc.c */ -#line 1933 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1926 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" + { + (yyval.case_label) = new(state) ast_case_label(NULL); + (yyval.case_label)->set_location(yylloc); + } + break; + + case 326: + +/* Line 1806 of yacc.c */ +#line 1934 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { ast_case_label_list *labels = new(state) ast_case_label_list(); @@ -6245,20 +6261,20 @@ yyreduce: } break; - case 326: + case 327: /* Line 1806 of yacc.c */ -#line 1941 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1942 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { (yyval.case_label_list) = (yyvsp[(1) - (2)].case_label_list); (yyval.case_label_list)->labels.push_tail(& (yyvsp[(2) - (2)].case_label)->link); } break; - case 327: + case 328: /* Line 1806 of yacc.c */ -#line 1949 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1950 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { ast_case_statement *stmts = new(state) ast_case_statement((yyvsp[(1) - (2)].case_label_list)); stmts->set_location(yylloc); @@ -6268,20 +6284,20 @@ yyreduce: } break; - case 328: + case 329: /* Line 1806 of yacc.c */ -#line 1957 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1958 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { (yyval.case_statement) = (yyvsp[(1) - (2)].case_statement); (yyval.case_statement)->stmts.push_tail(& (yyvsp[(2) - (2)].node)->link); } break; - case 329: + case 330: /* Line 1806 of yacc.c */ -#line 1965 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1966 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { ast_case_statement_list *cases= new(state) ast_case_statement_list(); cases->set_location(yylloc); @@ -6291,20 +6307,20 @@ yyreduce: } break; - case 330: + case 331: /* Line 1806 of yacc.c */ -#line 1973 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1974 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { (yyval.case_statement_list) = (yyvsp[(1) - (2)].case_statement_list); (yyval.case_statement_list)->cases.push_tail(& (yyvsp[(2) - (2)].case_statement)->link); } break; - case 331: + case 332: /* Line 1806 of yacc.c */ -#line 1981 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1982 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.node) = new(ctx) ast_iteration_statement(ast_iteration_statement::ast_while, @@ -6313,10 +6329,10 @@ yyreduce: } break; - case 332: + case 333: /* Line 1806 of yacc.c */ -#line 1988 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1989 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.node) = new(ctx) ast_iteration_statement(ast_iteration_statement::ast_do_while, @@ -6325,10 +6341,10 @@ yyreduce: } break; - case 333: + case 334: /* Line 1806 of yacc.c */ -#line 1995 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 1996 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.node) = new(ctx) ast_iteration_statement(ast_iteration_statement::ast_for, @@ -6337,39 +6353,39 @@ yyreduce: } break; - case 337: - -/* Line 1806 of yacc.c */ -#line 2011 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" - { - (yyval.node) = NULL; - } - break; - case 338: /* Line 1806 of yacc.c */ -#line 2018 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 2012 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { - (yyval.for_rest_statement).cond = (yyvsp[(1) - (2)].node); - (yyval.for_rest_statement).rest = NULL; + (yyval.node) = NULL; } break; case 339: /* Line 1806 of yacc.c */ -#line 2023 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 2019 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { - (yyval.for_rest_statement).cond = (yyvsp[(1) - (3)].node); - (yyval.for_rest_statement).rest = (yyvsp[(3) - (3)].expression); + (yyval.for_rest_statement).cond = (yyvsp[(1) - (2)].node); + (yyval.for_rest_statement).rest = NULL; } break; case 340: /* Line 1806 of yacc.c */ -#line 2032 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 2024 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" + { + (yyval.for_rest_statement).cond = (yyvsp[(1) - (3)].node); + (yyval.for_rest_statement).rest = (yyvsp[(3) - (3)].expression); + } + break; + + case 341: + +/* Line 1806 of yacc.c */ +#line 2033 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.node) = new(ctx) ast_jump_statement(ast_jump_statement::ast_continue, NULL); @@ -6377,10 +6393,10 @@ yyreduce: } break; - case 341: + case 342: /* Line 1806 of yacc.c */ -#line 2038 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 2039 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.node) = new(ctx) ast_jump_statement(ast_jump_statement::ast_break, NULL); @@ -6388,10 +6404,10 @@ yyreduce: } break; - case 342: + case 343: /* Line 1806 of yacc.c */ -#line 2044 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 2045 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.node) = new(ctx) ast_jump_statement(ast_jump_statement::ast_return, NULL); @@ -6399,10 +6415,10 @@ yyreduce: } break; - case 343: + case 344: /* Line 1806 of yacc.c */ -#line 2050 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 2051 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.node) = new(ctx) ast_jump_statement(ast_jump_statement::ast_return, (yyvsp[(2) - (3)].expression)); @@ -6410,10 +6426,10 @@ yyreduce: } break; - case 344: + case 345: /* Line 1806 of yacc.c */ -#line 2056 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 2057 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.node) = new(ctx) ast_jump_statement(ast_jump_statement::ast_discard, NULL); @@ -6421,24 +6437,24 @@ yyreduce: } break; - case 345: - -/* Line 1806 of yacc.c */ -#line 2064 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" - { (yyval.node) = (yyvsp[(1) - (1)].function_definition); } - break; - case 346: /* Line 1806 of yacc.c */ #line 2065 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" - { (yyval.node) = (yyvsp[(1) - (1)].node); } + { (yyval.node) = (yyvsp[(1) - (1)].function_definition); } break; case 347: /* Line 1806 of yacc.c */ -#line 2070 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 2066 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 348: + +/* Line 1806 of yacc.c */ +#line 2071 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.attribute_arg) = new(ctx) ast_attribute_arg( (yyvsp[(1) - (1)].expression) ); @@ -6446,10 +6462,10 @@ yyreduce: } break; - case 348: + case 349: /* Line 1806 of yacc.c */ -#line 2076 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 2077 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.attribute_arg) = new(ctx) ast_attribute_arg( (yyvsp[(1) - (1)].string_literal) ); @@ -6457,40 +6473,29 @@ yyreduce: } break; - case 349: - -/* Line 1806 of yacc.c */ -#line 2085 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" - { - (yyval.attribute_arg) = (yyvsp[(1) - (1)].attribute_arg); - } - break; - case 350: /* Line 1806 of yacc.c */ -#line 2089 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 2086 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { - (yyval.attribute_arg) = (yyvsp[(1) - (3)].attribute_arg); - (yyval.attribute_arg)->link.insert_before( & (yyvsp[(3) - (3)].attribute_arg)->link); + (yyval.attribute_arg) = (yyvsp[(1) - (1)].attribute_arg); } break; case 351: /* Line 1806 of yacc.c */ -#line 2097 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 2090 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { - void *ctx = state; - (yyval.attribute) = new(ctx) ast_attribute( (yyvsp[(2) - (3)].identifier) ); - (yyval.attribute)->link.self_link(); + (yyval.attribute_arg) = (yyvsp[(1) - (3)].attribute_arg); + (yyval.attribute_arg)->link.insert_before( & (yyvsp[(3) - (3)].attribute_arg)->link); } break; case 352: /* Line 1806 of yacc.c */ -#line 2103 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 2098 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.attribute) = new(ctx) ast_attribute( (yyvsp[(2) - (3)].identifier) ); @@ -6501,19 +6506,18 @@ yyreduce: case 353: /* Line 1806 of yacc.c */ -#line 2109 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 2104 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; - (yyval.attribute) = new(ctx) ast_attribute( (yyvsp[(2) - (6)].identifier) ); + (yyval.attribute) = new(ctx) ast_attribute( (yyvsp[(2) - (3)].identifier) ); (yyval.attribute)->link.self_link(); - (yyval.attribute)->arguments.push_degenerate_list_at_head( & (yyvsp[(4) - (6)].attribute_arg)->link ); } break; case 354: /* Line 1806 of yacc.c */ -#line 2116 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 2110 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.attribute) = new(ctx) ast_attribute( (yyvsp[(2) - (6)].identifier) ); @@ -6525,26 +6529,38 @@ yyreduce: case 355: /* Line 1806 of yacc.c */ -#line 2126 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 2117 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { - (yyval.attribute) = (yyvsp[(1) - (2)].attribute); - (yyval.attribute)->link.insert_before( & (yyvsp[(2) - (2)].attribute)->link); + void *ctx = state; + (yyval.attribute) = new(ctx) ast_attribute( (yyvsp[(2) - (6)].identifier) ); + (yyval.attribute)->link.self_link(); + (yyval.attribute)->arguments.push_degenerate_list_at_head( & (yyvsp[(4) - (6)].attribute_arg)->link ); } break; case 356: /* Line 1806 of yacc.c */ -#line 2131 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 2127 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { - (yyval.attribute) = (yyvsp[(1) - (1)].attribute); + (yyval.attribute) = (yyvsp[(1) - (2)].attribute); + (yyval.attribute)->link.insert_before( & (yyvsp[(2) - (2)].attribute)->link); } break; case 357: /* Line 1806 of yacc.c */ -#line 2138 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 2132 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" + { + (yyval.attribute) = (yyvsp[(1) - (1)].attribute); + } + break; + + case 358: + +/* Line 1806 of yacc.c */ +#line 2139 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.function_definition) = new(ctx) ast_function_definition(); @@ -6556,10 +6572,10 @@ yyreduce: } break; - case 358: + case 359: /* Line 1806 of yacc.c */ -#line 2148 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 2149 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { void *ctx = state; (yyval.function_definition) = new(ctx) ast_function_definition(); @@ -6572,19 +6588,19 @@ yyreduce: } break; - case 359: + case 360: /* Line 1806 of yacc.c */ -#line 2162 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 2163 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { (yyval.node) = (yyvsp[(1) - (1)].function); } break; - case 360: + case 361: /* Line 1806 of yacc.c */ -#line 2166 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 2167 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { if ((yyvsp[(1) - (2)].declarator_list)->type->qualifier.flags.q.is_static == 0 && (yyvsp[(1) - (2)].declarator_list)->type->qualifier.flags.q.shared == 0) { @@ -6594,10 +6610,10 @@ yyreduce: } break; - case 361: + case 362: /* Line 1806 of yacc.c */ -#line 2174 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" +#line 2175 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.yy" { (yyval.node) = (yyvsp[(1) - (1)].node); } @@ -6606,7 +6622,7 @@ yyreduce: /* Line 1806 of yacc.c */ -#line 6610 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.inl" +#line 6626 "../../../Source/ThirdParty/hlslcc/hlslcc/src/hlslcc_lib/hlsl_parser.inl" default: break; } /* User semantic actions sometimes alter yychar, and that requires diff --git a/Engine/Source/ThirdParty/libOpus/libOpus.build.cs b/Engine/Source/ThirdParty/libOpus/libOpus.build.cs index 0826691fad28..782f3dbe74fe 100644 --- a/Engine/Source/ThirdParty/libOpus/libOpus.build.cs +++ b/Engine/Source/ThirdParty/libOpus/libOpus.build.cs @@ -65,6 +65,17 @@ public class libOpus : ModuleRules PublicAdditionalLibraries.Add("opus"); PublicAdditionalLibraries.Add("speex_resampler"); } + else if (Target.Platform == UnrealTargetPlatform.XboxOne) + { + LibraryPath += "XboxOne/VS2015/Release/"; - } + PublicLibraryPaths.Add(LibraryPath); + + PublicAdditionalLibraries.Add("silk_common.lib"); + PublicAdditionalLibraries.Add("silk_float.lib"); + PublicAdditionalLibraries.Add("celt.lib"); + PublicAdditionalLibraries.Add("opus.lib"); + PublicAdditionalLibraries.Add("speex_resampler.lib"); + } + } } diff --git a/Engine/Source/ThirdParty/libPhonon/LibPhonon.Build.cs b/Engine/Source/ThirdParty/libPhonon/LibPhonon.Build.cs index 3b5bb97e214a..d4f25556e220 100644 --- a/Engine/Source/ThirdParty/libPhonon/LibPhonon.Build.cs +++ b/Engine/Source/ThirdParty/libPhonon/LibPhonon.Build.cs @@ -1,4 +1,5 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + using UnrealBuildTool; public class libPhonon : ModuleRules diff --git a/Engine/Source/ThirdParty/libPhonon/LibPhonon.tps b/Engine/Source/ThirdParty/libPhonon/LibPhonon.tps index 9406a434bfc9..abc0fc6b3b30 100644 --- a/Engine/Source/ThirdParty/libPhonon/LibPhonon.tps +++ b/Engine/Source/ThirdParty/libPhonon/LibPhonon.tps @@ -1,25 +1,15 @@  Phonon - + /Engine/Source/ThirdParty/libPhonon/ 2017-01-20T11:16:30.8126987-08:00 Physics-based audio for games and virtual reality To get realistic occlusion, reverb, and spatialization tech - - PC - Mac - Android - Linux - - - UE4 - - lib - - - false - false - None - - + Custom agreement between Valve/Epic + + Licensees + Git + P4 + + None \ No newline at end of file diff --git a/Engine/Source/ThirdParty/libPhonon/phonon_api/include/phonon.h b/Engine/Source/ThirdParty/libPhonon/phonon_api/include/phonon.h index 7cbc030df7df..de5fdae336e5 100644 --- a/Engine/Source/ThirdParty/libPhonon/phonon_api/include/phonon.h +++ b/Engine/Source/ThirdParty/libPhonon/phonon_api/include/phonon.h @@ -63,7 +63,7 @@ extern "C" { /* Context */ /*****************************************************************************************************************/ - /** \defgroup context Context + /** \defgroup context Context * Defines a Context object, which controls low-level operations of Phonon. Typically, a Context is specified * once during the execution of the client program, before calling any other API functions. Once any API function * is called, changing the Context may lead to undefined behavior. @@ -120,9 +120,10 @@ extern "C" { * \{ */ - /** A point or vector in 3D space. Phonon uses a right-handed coordinate system, with the x-axis pointing right, - * the y-axis pointing up, and the z-axis pointing ahead. Position and direction data obtained from a game - * engine or audio engine must be properly transformed before being passed to any Phonon API function. + /** A point or vector in 3D space. Phonon uses a right-handed coordinate system, with the positive x-axis pointing + * right, the positive y-axis pointing up, and the negative z-axis pointing ahead. Position and direction data + * obtained from a game engine or audio engine must be properly transformed before being passed to any Phonon API + * function. */ typedef struct { IPLfloat32 x; /**< The x-coordinate. */ @@ -715,15 +716,15 @@ extern "C" { * \f$ -l \leq m \leq l \f$. * * There are many different conventions used by the audio engineering community to encode Ambisonics coefficients. - * Phonon supports many of them. + * Phonon supports many of them. * * This enumeration defines the sequence in which Ambisonics channels are stored. Since two integers are needed to * identify an Ambisonics channel, there is more than one way to use a single integer to identify an Ambisonics - * channel. + * channel. */ typedef enum { IPL_AMBISONICSORDERING_FURSEMALHAM, /**< Specifies the Furse-Malham (FuMa) channel ordering. This is an - extension of traditional B-format encoding to higher-order + extension of traditional B-format encoding to higher-order Ambisonics. */ IPL_AMBISONICSORDERING_ACN /**< Specifies the Ambisonics Channel Number scheme for channel ordering. This is the new standard adopted by the AmbiX Ambisonics format. The @@ -763,13 +764,13 @@ extern "C" { /** The format of an audio buffer. Whenever you pass audio data to or from Phonon, you must describe the format in * which the audio is encoded. **Phonon only supports uncompressed PCM wave data, stored in 32-bit floating point * format**. However, Phonon supports many different multi-channel and Ambisonics formats, and the - * \c IPLAudioFormat tells Phonon how to interpret a buffer of audio data. + * \c IPLAudioFormat tells Phonon how to interpret a buffer of audio data. */ typedef struct { - IPLChannelLayoutType channelLayoutType; /**< Indicates whether or not the audio should be + IPLChannelLayoutType channelLayoutType; /**< Indicates whether or not the audio should be interpreted as Ambisonics data. */ IPLChannelLayout channelLayout; /**< Specifies the speaker configuration used for - multi-channel, speaker-based audio data. Ignored + multi-channel, speaker-based audio data. Ignored if \c channelLayoutType is \c ::IPL_CHANNELLAYOUTTYPE_AMBISONICS. */ IPLint32 numSpeakers; /**< The number of channels in the audio data. Must be @@ -826,7 +827,7 @@ extern "C" { IPLAPI IPLvoid iplMixAudioBuffers(IPLint32 numBuffers, IPLAudioBuffer* inputAudio, IPLAudioBuffer outputAudio); /** Interleaves a deinterleaved audio buffer. The formats of \c inputAudio and \c outputAudio must be identical - * except for the \c channelOrder field. + * except for the \c channelOrder field. * * \param inputAudio The input audio buffer. This audio buffer must be deinterleaved. * \param outputAudio The output audio buffer. This audio buffer must be interleaved. @@ -926,7 +927,7 @@ extern "C" { * * \param context The Context object used by the audio engine. * \param renderingSettings An \c IPLRenderingSettings object describing the audio pipeline's DSP processing - * parameters. These properties must remain constant throughout the lifetime of your + * parameters. These properties must remain constant throughout the lifetime of your * application. * \param hrtfData Pointer to a byte array containing HRTF data. For most situations, set this * parameter to \c NULL; Phonon will use its built-in HRTF data. If you want to use @@ -960,7 +961,7 @@ extern "C" { */ /** Creates a Panning Effect object. This can be used to render a point source on surround speakers, or using - * Ambisonics. + * Ambisonics. * * \param renderer Handle to a Binaural Renderer object. * \param inputFormat The format of the audio buffers that will be passed as input to this effect. All @@ -986,7 +987,7 @@ extern "C" { /** Applies 3D panning to a buffer of audio data, using the configuration of a Panning Effect object. The input * audio is treated as emanating from a single point. If the input audio buffer contains more than one channel, - * it will automatically be downmixed to mono. + * it will automatically be downmixed to mono. * * \param effect Handle to a Panning Effect object. * \param inputAudio Audio buffer containing the data to render using 3D panning. The format of this @@ -999,6 +1000,14 @@ extern "C" { IPLAPI IPLvoid iplApplyPanningEffect(IPLhandle effect, IPLAudioBuffer inputAudio, IPLVector3 direction, IPLAudioBuffer outputAudio); + /** Resets any internal state maintained by a Panning Effect object. This is useful if the Panning Effect object + * is going to be disabled/unused for a few frames; resetting the internal state will prevent an audible glitch + * when the Panning Effect object is re-enabled at a later time. + * + * \param effect Handle to a Panning Effect object. + */ + IPLAPI IPLvoid iplFlushPanningEffect(IPLhandle effect); + /** \} */ @@ -1009,7 +1018,7 @@ extern "C" { /** \defgroup binauraleffect Object-Based Binaural Effect * Functionality for accurately spatializing point sources in 3D, using Head-Related Transfer Functions (HRTFs). * The Phonon API includes a simple set of functions for applying high-performance binaural rendering to point - * source audio data. + * source audio data. * \{ */ @@ -1033,8 +1042,8 @@ extern "C" { * \c IPLAudioBuffer objects with the same format as specified here. The input format * must not be Ambisonics. * \param outputFormat The format of the audio buffers which will be used to retrieve the output from this - * effect. All subsequent calls to \c ::iplApplyBinauralEffect for this effect object - * must use \c IPLAudioBuffer objects with the same format as specified here. The + * effect. All subsequent calls to \c ::iplApplyBinauralEffect for this effect object + * must use \c IPLAudioBuffer objects with the same format as specified here. The * output format must be stereo (2 channels). * \param effect [out] Handle to the created Object-Based Binaural Effect object. * @@ -1052,8 +1061,8 @@ extern "C" { /** Applies HRTF-based binaural rendering to a buffer of audio data. The input audio is treated as emanating from * a single point. If the input audio buffer contains more than one channel, it will automatically be downmixed to - * mono. Using bilinear interpolation (by setting \c interpolation to \c ::IPL_HRTFINTERPOLATION_BILINEAR) can - * incur a relatively high CPU cost. Use it only on sources where nearest-neighbor filtering + * mono. Using bilinear interpolation (by setting \c interpolation to \c ::IPL_HRTFINTERPOLATION_BILINEAR) can + * incur a relatively high CPU cost. Use it only on sources where nearest-neighbor filtering * (\c ::IPL_HRTFINTERPOLATION_NEAREST) produces suboptimal results. Typically, bilinear filtering is most useful * for wide-band noise-like sounds, such as radio static, mechanical noise, fire, etc. * @@ -1072,6 +1081,15 @@ extern "C" { IPLAPI IPLvoid iplApplyBinauralEffect(IPLhandle effect, IPLAudioBuffer inputAudio, IPLVector3 direction, IPLHrtfInterpolation interpolation, IPLAudioBuffer outputAudio); + /** Resets any internal state maintained by an Object-Based Binaural Effect object. This is useful if the + * Object-Based Binaural Effect object is going to be disabled/unused for a few frames; resetting the internal + * state will prevent an audible glitch when the Object-Based Binaural Effect object is re-enabled at a later + * time. + * + * \param effect Handle to an Object-Based Binaural Effect object. + */ + IPLAPI IPLvoid iplFlushBinauralEffect(IPLhandle effect); + /** \} */ @@ -1085,7 +1103,7 @@ extern "C" { * for each speaker using binaural rendering. In other words, the audio signal for each speaker is rendered as if * it were emanating from a point in space corresponding to the speaker's position. This allows users to * experience, say, a 7.1 surround sound mix over regular stereo headphones. - * + * * Virtual Surround also works as a fast way to get approximate binaural rendering. All sound sources can be * panned to some surround format (say 7.1); after they are mixed, the 7.1 surround mix can be rendered using * virtual surround. This can save CPU cycles, at the cost of spatialization accuracy. @@ -1130,6 +1148,86 @@ extern "C" { IPLAPI IPLvoid iplApplyVirtualSurroundEffect(IPLhandle effect, IPLAudioBuffer inputAudio, IPLAudioBuffer outputAudio); + /** Resets any internal state maintained by a Virtual Surround Effect object. This is useful if the Virtual + * Surround Effect object is going to be disabled/unused for a few frames; resetting the internal state will + * prevent an audible glitch when the Virtual Surround Effect object is re-enabled at a later time. + * + * \param effect Handle to a Virtual Surround Effect object. + */ + IPLAPI IPLvoid iplFlushVirtualSurroundEffect(IPLhandle effect); + + /** \} */ + + + /*****************************************************************************************************************/ + /* Ambisonics Panning Effect */ + /*****************************************************************************************************************/ + + /** \defgroup ambisonicspanning Ambisonics Panning Effect + * Functionality for rendering Ambisonics data by panning it to standard speaker layouts. Ambisonics is a powerful + * format for encoding 3D sound fields, and exchanging them. Phonon can encode data into Ambisonics using the + * Panning Effect: to spatialize a sound source and create an Ambisonics track, use the Panning Effect with + * \c outputFormat.channelLayoutType set to \c ::IPL_CHANNELLAYOUTTYPE_AMBISONICS. + * + * Phonon can also decode and render Ambisonics data, using panning. This involves approximating the sound field + * as if it were generated by sound coming from each speaker. + * + * Ambisonics also allows 3D audio rendering in VR to be significantly accelerated: instead of applying + * object-based binaural rendering to each source individually, the sources can be encoded into Ambisonics first, + * then mixed, and finally the mix can be rendered using Ambisonics binaural rendering. This saves CPU cycles, at + * the cost of some spatialization accuracy. + * \{ + */ + + /** Creates an Ambisonics Panning Effect object. This can be used to render higher-order Ambisonics data using + * standard panning algorithms. + * + * \param renderer Handle to a Binaural Renderer object. + * \param inputFormat The format of the audio buffers that will be passed as input to this effect. All + * subsequent calls to \c ::iplApplyAmbisonicsPanningEffect for this effect object must + * use \c IPLAudioBuffer objects with the same format as specified here. The input + * format must be Ambisonics. + * \param outputFormat The format of the audio buffers which will be used to retrieve the output from this + * effect. All subsequent calls to \c ::iplApplyAmbisonicsPanningEffect for this + * effect object must use \c IPLAudioBuffer objects with the same format as specified + * here. + * \param effect [out] Handle to the created Ambisonics Panning Effect object. + * + * \return Status code indicating whether or not the operation succeeded. + */ + IPLAPI IPLerror iplCreateAmbisonicsPanningEffect(IPLhandle renderer, IPLAudioFormat inputFormat, + IPLAudioFormat outputFormat, IPLhandle* effect); + + /** Destroys an Ambisonics Panning Effect object. + * + * \param effect [in, out] Address of a handle to the Ambisonics Panning Effect object to destroy. + */ + IPLAPI IPLvoid iplDestroyAmbisonicsPanningEffect(IPLhandle* effect); + + /** Applies a panning-based rendering algorithm to a buffer of Ambisonics audio data. Ambisonics encoders and decoders + * use many different conventions to store the multiple Ambisonics channels, as well as different normalization + * schemes. Make sure that you correctly specify these settings when creating the Ambisonics Panning Effect + * object, otherwise the rendered audio will be incorrect. + * + * \param effect Handle to an Ambisonics Panning Effect object. + * \param inputAudio Audio buffer containing the data to render. The format of + * this buffer must match the \c inputFormat parameter passed to + * \c ::iplCreateAmbisonicsPanningEffect. + * \param outputAudio Audio buffer that should contain the rendered audio data. The format of this buffer + * must match the \c outputFormat parameter passed to + * \c ::iplCreateAmbisonicsPanningEffect. + */ + IPLAPI IPLvoid iplApplyAmbisonicsPanningEffect(IPLhandle effect, IPLAudioBuffer inputAudio, + IPLAudioBuffer outputAudio); + + /** Resets any internal state maintained by an Ambisonics Panning Effect object. This is useful if the Ambisonics + * Panning Effect object is going to be disabled/unused for a few frames; resetting the internal state will + * prevent an audible glitch when the Ambisonics Panning Effect object is re-enabled at a later time. + * + * \param effect Handle to an Ambisonics Panning Effect object. + */ + IPLAPI IPLvoid iplFlushAmbisonicsPanningEffect(IPLhandle effect); + /** \} */ @@ -1141,21 +1239,21 @@ extern "C" { * Functionality for rendering Ambisonics data using HRTF-based binaural rendering. Ambisonics is a powerful * format for encoding 3D sound fields, and exchanging them. Phonon can encode data into Ambisonics using the * Panning Effect: to spatialize a sound source and create an Ambisonics track, use the Panning Effect with - * \c outputFormat.channelLayoutType set to \c ::IPL_CHANNELLAYOUTTYPE_AMBISONICS. + * \c outputFormat.channelLayoutType set to \c ::IPL_CHANNELLAYOUTTYPE_AMBISONICS. * * Phonon can also decode and render Ambisonics data, using Ambisonics binaural rendering. This involves * recreating the 3D sound field as perceived by each ear. This is a powerful and intuitive way of listening to - * Ambisonics data. It is extremely useful for rendering audio tracks recorded for 360 video projects. + * Ambisonics data. It is extremely useful for rendering audio tracks recorded for 360 video projects. * * Ambisonics also allows 3D audio rendering in VR to be significantly accelerated: instead of applying * object-based binaural rendering to each source individually, the sources can be encoded into Ambisonics first, * then mixed, and finally the mix can be rendered using Ambisonics binaural rendering. This saves CPU cycles, at - * the cost of some spatialization accuracy. + * the cost of some spatialization accuracy. * \{ */ /** Creates an Ambisonics Binaural Effect object. This can be used to render higher-order Ambisonics data using - * HRTF-based binaural rendering. + * HRTF-based binaural rendering. * * \param renderer Handle to a Binaural Renderer object. * \param inputFormat The format of the audio buffers that will be passed as input to this effect. All @@ -1190,11 +1288,19 @@ extern "C" { * \c ::iplCreateAmbisonicsBinauralEffect. * \param outputAudio Audio buffer that should contain the rendered audio data. The format of this buffer * must match the \c outputFormat parameter passed to - * \c ::iplCreateAmbisonicsBinauralEffect. + * \c ::iplCreateAmbisonicsBinauralEffect. */ IPLAPI IPLvoid iplApplyAmbisonicsBinauralEffect(IPLhandle effect, IPLAudioBuffer inputAudio, IPLAudioBuffer outputAudio); + /** Resets any internal state maintained by an Ambisonics Binaural Effect object. This is useful if the Ambisonics + * Binaural Effect object is going to be disabled/unused for a few frames; resetting the internal state will + * prevent an audible glitch when the Ambisonics Binaural Effect object is re-enabled at a later time. + * + * \param effect Handle to an Ambisonics Binaural Effect object. + */ + IPLAPI IPLvoid iplFlushAmbisonicsBinauralEffect(IPLhandle effect); + /** \} */ @@ -1239,6 +1345,21 @@ extern "C" { /** \} */ + IPLAPI IPLerror iplCreateSimulationData(IPLSimulationSettings simulationSettings, + IPLRenderingSettings renderingSettings, IPLhandle* simulationData); + + IPLAPI IPLvoid iplDestroySimulationData(IPLhandle* simulationData); + + IPLAPI IPLint32 iplGetNumIrSamples(IPLhandle simulationData); + + IPLAPI IPLint32 iplGetNumIrChannels(IPLhandle simulationData); + + IPLAPI IPLvoid iplGenerateSimulationData(IPLhandle simulationData, IPLhandle environment, + IPLVector3 listenerPosition, IPLVector3 listenerAhead, IPLVector3 listenerUp, IPLVector3* sources); + + IPLAPI IPLvoid iplGetSimulationResult(IPLhandle simulationData, IPLint32 sourceIndex, IPLint32 channel, + IPLfloat32* buffer); + /*****************************************************************************************************************/ /* Direct Sound */ @@ -1333,7 +1454,7 @@ extern "C" { * If you want this Convolution Effect to be used to render baked reverb, pass * \c "__reverb__" as the name. * \param simulationType Whether this Convolution Effect object should use baked data or real-time simulation. - * \param inputFormat Format of all audio buffers passed as input to + * \param inputFormat Format of all audio buffers passed as input to * \c ::iplSetDryAudioForConvolutionEffect. * \param outputFormat Format of all output audio buffers passed to \c ::iplGetWetAudioForConvolutionEffect. * \param effect [out] Handle to the created Convolution Effect object. @@ -1395,6 +1516,14 @@ extern "C" { IPLAPI IPLvoid iplGetMixedEnvironmentalAudio(IPLhandle renderer, IPLVector3 listenerPosition, IPLVector3 listenerAhead, IPLVector3 listenerUp, IPLAudioBuffer mixedWetAudio); + /** Resets any internal state maintained by a Convolution Effect object. This is useful if the Convolution Effect + * object is going to be disabled/unused for a few frames; resetting the internal state will prevent an audible + * glitch when the Convolution Effect object is re-enabled at a later time. + * + * \param effect Handle to a Convolution Effect object. + */ + IPLAPI IPLvoid iplFlushConvolutionEffect(IPLhandle effect); + /** \} */ @@ -1441,11 +1570,11 @@ extern "C" { IPLfloat32 spacing; /**< Spacing between probes along the horizontal plane. Only used if \c placement is \c ::IPL_PLACEMENT_UNIFORMFLOOR. */ IPLfloat32 heightAboveFloor; /**< Height of the probes above the closest floor or terrain - surfaces. Only used if \c placement is + surfaces. Only used if \c placement is \c ::IPL_PLACEMENT_UNIFORMFLOOR. */ - IPLfloat32 maxOctreeTriangles; /**< The maximum number of triangles to store in an octree leaf + IPLint32 maxOctreeTriangles; /**< The maximum number of triangles to store in an octree leaf node. Only used if \c placement is \c ::IPL_PLACEMENT_OCTREE. */ - IPLfloat32 maxOctreeDepth; /**< The maximum depth of the octree. Increasing this value increases + IPLint32 maxOctreeDepth; /**< The maximum depth of the octree. Increasing this value increases density of the generated probes. Only used if \c placement is \c ::IPL_PLACEMENT_OCTREE. */ } IPLProbePlacementParams; @@ -1453,7 +1582,7 @@ extern "C" { /** A callback that is called to update the application on the progress of the \c ::iplCreateProbeBox function. * You can use this to provide visual feedback to the user, like a progress bar. * - * \param progress Fraction of the probe generation process that has been completed, between + * \param progress Fraction of the probe generation process that has been completed, between * 0.0 and 1.0. */ typedef void (*IPLProbePlacementProgressCallback)(IPLfloat32 progress); @@ -1696,7 +1825,7 @@ extern "C" { * * \param environment Handle to an Environment object. * \param probeBox Handle to the Probe Box containing the probes for which to bake reverb. - * \param listener Position of the listener. + * \param listenerInfluence Position and influence radius of the listener. * \param listenerName Name of the listener. At run-time, a Convolution Effect object can use this * name prefixed with \c __staticlistener__ to look up the correct impulse * response information. @@ -1704,7 +1833,7 @@ extern "C" { * \param progressCallback Pointer to a function that reports the percentage of this function's work that * has been completed. May be \c NULL. */ - IPLAPI IPLvoid iplBakeStaticListener(IPLhandle environment, IPLhandle probeBox, IPLVector3 listener, + IPLAPI IPLvoid iplBakeStaticListener(IPLhandle environment, IPLhandle probeBox, IPLSphere listenerInfluence, IPLstring listenerName, IPLBakingSettings bakingSettings, IPLBakeProgressCallback progressCallback); /** Cancels any bake operations that may be in progress. Typically, an application will call \c ::iplBakeReverb @@ -1734,8 +1863,9 @@ extern "C" { /** \} */ + #ifdef __cplusplus } #endif -#endif \ No newline at end of file +#endif diff --git a/Engine/Source/ThirdParty/libWebSockets/libwebsockets/include/Linux/x86_64-unknown-linux-gnu/libwebsockets.h b/Engine/Source/ThirdParty/libWebSockets/libwebsockets/include/Linux/x86_64-unknown-linux-gnu/libwebsockets.h index fe152989f85f..306db45c860c 100644 --- a/Engine/Source/ThirdParty/libWebSockets/libwebsockets/include/Linux/x86_64-unknown-linux-gnu/libwebsockets.h +++ b/Engine/Source/ThirdParty/libWebSockets/libwebsockets/include/Linux/x86_64-unknown-linux-gnu/libwebsockets.h @@ -241,8 +241,9 @@ LWS_VISIBLE LWS_EXTERN void _lws_logv(int filter, const char *format, va_list vl * that gets rid of the overhead of checking while keeping _warn and _err * active */ -#ifdef _DEBUG - +//@UE4 BEGIN - Enable all log levels in release builds +#if 1 // def _DEBUG +//@UE4 END - Enable all log levels in release builds #define lwsl_info(...) _lws_log(LLL_INFO, __VA_ARGS__) #define lwsl_debug(...) _lws_log(LLL_DEBUG, __VA_ARGS__) #define lwsl_parser(...) _lws_log(LLL_PARSER, __VA_ARGS__) diff --git a/Engine/Source/ThirdParty/libWebSockets/libwebsockets/include/Win32/2013/libwebsockets.h b/Engine/Source/ThirdParty/libWebSockets/libwebsockets/include/Win32/2013/libwebsockets.h index fe152989f85f..306db45c860c 100644 --- a/Engine/Source/ThirdParty/libWebSockets/libwebsockets/include/Win32/2013/libwebsockets.h +++ b/Engine/Source/ThirdParty/libWebSockets/libwebsockets/include/Win32/2013/libwebsockets.h @@ -241,8 +241,9 @@ LWS_VISIBLE LWS_EXTERN void _lws_logv(int filter, const char *format, va_list vl * that gets rid of the overhead of checking while keeping _warn and _err * active */ -#ifdef _DEBUG - +//@UE4 BEGIN - Enable all log levels in release builds +#if 1 // def _DEBUG +//@UE4 END - Enable all log levels in release builds #define lwsl_info(...) _lws_log(LLL_INFO, __VA_ARGS__) #define lwsl_debug(...) _lws_log(LLL_DEBUG, __VA_ARGS__) #define lwsl_parser(...) _lws_log(LLL_PARSER, __VA_ARGS__) diff --git a/Engine/Source/ThirdParty/libWebSockets/libwebsockets/include/Win32/2015/libwebsockets.h b/Engine/Source/ThirdParty/libWebSockets/libwebsockets/include/Win32/2015/libwebsockets.h index fe152989f85f..306db45c860c 100644 --- a/Engine/Source/ThirdParty/libWebSockets/libwebsockets/include/Win32/2015/libwebsockets.h +++ b/Engine/Source/ThirdParty/libWebSockets/libwebsockets/include/Win32/2015/libwebsockets.h @@ -241,8 +241,9 @@ LWS_VISIBLE LWS_EXTERN void _lws_logv(int filter, const char *format, va_list vl * that gets rid of the overhead of checking while keeping _warn and _err * active */ -#ifdef _DEBUG - +//@UE4 BEGIN - Enable all log levels in release builds +#if 1 // def _DEBUG +//@UE4 END - Enable all log levels in release builds #define lwsl_info(...) _lws_log(LLL_INFO, __VA_ARGS__) #define lwsl_debug(...) _lws_log(LLL_DEBUG, __VA_ARGS__) #define lwsl_parser(...) _lws_log(LLL_PARSER, __VA_ARGS__) diff --git a/Engine/Source/ThirdParty/libWebSockets/libwebsockets/include/Win64/2013/libwebsockets.h b/Engine/Source/ThirdParty/libWebSockets/libwebsockets/include/Win64/2013/libwebsockets.h index fe152989f85f..306db45c860c 100644 --- a/Engine/Source/ThirdParty/libWebSockets/libwebsockets/include/Win64/2013/libwebsockets.h +++ b/Engine/Source/ThirdParty/libWebSockets/libwebsockets/include/Win64/2013/libwebsockets.h @@ -241,8 +241,9 @@ LWS_VISIBLE LWS_EXTERN void _lws_logv(int filter, const char *format, va_list vl * that gets rid of the overhead of checking while keeping _warn and _err * active */ -#ifdef _DEBUG - +//@UE4 BEGIN - Enable all log levels in release builds +#if 1 // def _DEBUG +//@UE4 END - Enable all log levels in release builds #define lwsl_info(...) _lws_log(LLL_INFO, __VA_ARGS__) #define lwsl_debug(...) _lws_log(LLL_DEBUG, __VA_ARGS__) #define lwsl_parser(...) _lws_log(LLL_PARSER, __VA_ARGS__) diff --git a/Engine/Source/ThirdParty/libWebSockets/libwebsockets/include/Win64/2015/libwebsockets.h b/Engine/Source/ThirdParty/libWebSockets/libwebsockets/include/Win64/2015/libwebsockets.h index fe152989f85f..306db45c860c 100644 --- a/Engine/Source/ThirdParty/libWebSockets/libwebsockets/include/Win64/2015/libwebsockets.h +++ b/Engine/Source/ThirdParty/libWebSockets/libwebsockets/include/Win64/2015/libwebsockets.h @@ -241,8 +241,9 @@ LWS_VISIBLE LWS_EXTERN void _lws_logv(int filter, const char *format, va_list vl * that gets rid of the overhead of checking while keeping _warn and _err * active */ -#ifdef _DEBUG - +//@UE4 BEGIN - Enable all log levels in release builds +#if 1 // def _DEBUG +//@UE4 END - Enable all log levels in release builds #define lwsl_info(...) _lws_log(LLL_INFO, __VA_ARGS__) #define lwsl_debug(...) _lws_log(LLL_DEBUG, __VA_ARGS__) #define lwsl_parser(...) _lws_log(LLL_PARSER, __VA_ARGS__) diff --git a/Engine/Source/ThirdParty/libWebSockets/libwebsockets/lib/x64/2013/websockets.exp b/Engine/Source/ThirdParty/libWebSockets/libwebsockets/lib/x64/2013/websockets.exp deleted file mode 100644 index 3f13f4e438c9..000000000000 Binary files a/Engine/Source/ThirdParty/libWebSockets/libwebsockets/lib/x64/2013/websockets.exp and /dev/null differ diff --git a/Engine/Source/ThirdParty/libWebSockets/libwebsockets_src/LICENSE b/Engine/Source/ThirdParty/libWebSockets/libwebsockets_src/LICENSE index da87198c6c47..9ce0f416084b 100644 --- a/Engine/Source/ThirdParty/libWebSockets/libwebsockets_src/LICENSE +++ b/Engine/Source/ThirdParty/libWebSockets/libwebsockets_src/LICENSE @@ -1,7 +1,13 @@ Libwebsockets and included programs are provided under the terms of the GNU Library General Public License (LGPL) 2.1, with the following exceptions: -1) Static linking of programs with the libwebsockets library does not +1) Any reference, whether in these modifications or in the GNU +Library General Public License 2.1, to this License, these terms, the +GNU Lesser Public License, GNU Library General Public License, LGPL, or +any similar reference shall refer to the GNU Library General Public +License 2.1 as modified by these paragraphs 1) through 4). + +2) Static linking of programs with the libwebsockets library does not constitute a derivative work and does not require the author to provide source code for the program, use the shared libwebsockets libraries, or link their program against a user-supplied version of libwebsockets. @@ -10,7 +16,7 @@ If you link the program to a modified version of libwebsockets, then the changes to libwebsockets must be provided under the terms of the LGPL in sections 1, 2, and 4. -2) You do not have to provide a copy of the libwebsockets license with +3) You do not have to provide a copy of the libwebsockets license with programs that are linked to the libwebsockets library, nor do you have to identify the libwebsockets license in your program or documentation as required by section 6 of the LGPL. @@ -22,7 +28,7 @@ satisfy this requirement: "[program] is based in part on the work of the libwebsockets project (https://libwebsockets.org)" -3) Some sources included have their own, more liberal licenses, or options +4) Some sources included have their own, more liberal licenses, or options to get original sources with the liberal terms. Original liberal license retained @@ -40,8 +46,10 @@ Public Domain (CC-zero) to simplify reuse - test-server/*.c - test-server/*.h + - lwsws/* - +------ end of exceptions + GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 diff --git a/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPerson.Build.cs b/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPerson.Build.cs index 6b9bc742eebb..deffb0acb66a 100644 --- a/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPerson.Build.cs +++ b/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPerson.Build.cs @@ -6,6 +6,8 @@ public class FP_FirstPerson : ModuleRules { public FP_FirstPerson(ReadOnlyTargetRules Target) : base(Target) { + PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; + PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" }); } } diff --git a/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPerson.cpp b/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPerson.cpp index 40e1ceefd5b3..3573c854a1fa 100644 --- a/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPerson.cpp +++ b/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPerson.cpp @@ -1,7 +1,7 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "FP_FirstPerson.h" - +#include "ModuleManager.h" IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, FP_FirstPerson, "FP_FirstPerson" ); \ No newline at end of file diff --git a/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPerson.h b/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPerson.h index 3aca1890b8eb..25b0d2941503 100644 --- a/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPerson.h +++ b/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPerson.h @@ -1,9 +1,5 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#ifndef __FP_FIRSTPERSON_H__ -#define __FP_FIRSTPERSON_H__ +#pragma once -#include "EngineMinimal.h" - - -#endif +#include "CoreMinimal.h" diff --git a/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPersonCharacter.cpp b/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPersonCharacter.cpp index 76b719b72131..f98ca93d9d90 100644 --- a/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPersonCharacter.cpp +++ b/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPersonCharacter.cpp @@ -1,10 +1,13 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "FP_FirstPerson.h" #include "FP_FirstPersonCharacter.h" #include "Animation/AnimInstance.h" +#include "Components/CapsuleComponent.h" +#include "Components/InputComponent.h" +#include "Camera/CameraComponent.h" +#include "Kismet/GameplayStatics.h" +#include "GameFramework/PlayerController.h" -static FName WeaponFireTraceIdent = FName(TEXT("WeaponTrace")); #define COLLISION_WEAPON ECC_GameTraceChannel1 DEFINE_LOG_CATEGORY_STATIC(LogFPChar, Warning, All); @@ -245,7 +248,7 @@ void AFP_FirstPersonCharacter::LookUpAtRate(float Rate) FHitResult AFP_FirstPersonCharacter::WeaponTrace(const FVector& StartTrace, const FVector& EndTrace) const { // Perform trace to retrieve hit info - FCollisionQueryParams TraceParams(WeaponFireTraceIdent, true, Instigator); + FCollisionQueryParams TraceParams(SCENE_QUERY_STAT(WeaponTrace), true, Instigator); TraceParams.bTraceAsyncScene = true; TraceParams.bReturnPhysicalMaterial = true; diff --git a/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPersonCharacter.h b/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPersonCharacter.h index 1915b613d3ec..60f1bf3dcf4d 100644 --- a/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPersonCharacter.h +++ b/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPersonCharacter.h @@ -1,5 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once + +#include "CoreMinimal.h" #include "GameFramework/Character.h" #include "FP_FirstPersonCharacter.generated.h" diff --git a/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPersonGameMode.cpp b/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPersonGameMode.cpp index 551433fab3aa..e3701ad97099 100644 --- a/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPersonGameMode.cpp +++ b/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPersonGameMode.cpp @@ -1,9 +1,9 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "FP_FirstPerson.h" #include "FP_FirstPersonGameMode.h" #include "FP_FirstPersonHUD.h" #include "FP_FirstPersonCharacter.h" +#include "UObject/ConstructorHelpers.h" AFP_FirstPersonGameMode::AFP_FirstPersonGameMode() { diff --git a/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPersonGameMode.h b/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPersonGameMode.h index c540799363eb..16c3d31027a3 100644 --- a/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPersonGameMode.h +++ b/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPersonGameMode.h @@ -1,5 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once + +#include "CoreMinimal.h" #include "GameFramework/GameModeBase.h" #include "FP_FirstPersonGameMode.generated.h" diff --git a/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPersonHUD.cpp b/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPersonHUD.cpp index e71d440fff2e..24b53b86868c 100644 --- a/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPersonHUD.cpp +++ b/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPersonHUD.cpp @@ -1,10 +1,11 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "FP_FirstPerson.h" #include "FP_FirstPersonHUD.h" #include "Engine/Canvas.h" #include "TextureResource.h" #include "CanvasItem.h" +#include "UObject/ConstructorHelpers.h" +#include "Engine/Texture2D.h" AFP_FirstPersonHUD::AFP_FirstPersonHUD() { diff --git a/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPersonHUD.h b/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPersonHUD.h index b14c8feca6e5..f5557e3775f2 100644 --- a/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPersonHUD.h +++ b/Templates/FP_FirstPerson/Source/FP_FirstPerson/FP_FirstPersonHUD.h @@ -1,5 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#pragma once + +#pragma once + +#include "CoreMinimal.h" #include "GameFramework/HUD.h" #include "FP_FirstPersonHUD.generated.h" diff --git a/Templates/TP_2DSideScroller/Source/TP_2DSideScroller/TP_2DSideScroller.Build.cs b/Templates/TP_2DSideScroller/Source/TP_2DSideScroller/TP_2DSideScroller.Build.cs index 5b6138833614..6d419d48e4ab 100644 --- a/Templates/TP_2DSideScroller/Source/TP_2DSideScroller/TP_2DSideScroller.Build.cs +++ b/Templates/TP_2DSideScroller/Source/TP_2DSideScroller/TP_2DSideScroller.Build.cs @@ -6,6 +6,8 @@ public class TP_2DSideScroller : ModuleRules { public TP_2DSideScroller(ReadOnlyTargetRules Target) : base(Target) { + PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; + PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "Paper2D" }); } } diff --git a/Templates/TP_2DSideScroller/Source/TP_2DSideScroller/TP_2DSideScroller.cpp b/Templates/TP_2DSideScroller/Source/TP_2DSideScroller/TP_2DSideScroller.cpp index 4df055b17ab2..3ac332e9f112 100644 --- a/Templates/TP_2DSideScroller/Source/TP_2DSideScroller/TP_2DSideScroller.cpp +++ b/Templates/TP_2DSideScroller/Source/TP_2DSideScroller/TP_2DSideScroller.cpp @@ -1,6 +1,6 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "TP_2DSideScroller.h" +#include "Modules/ModuleManager.h" IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, TP_2DSideScroller, "TP_2DSideScroller" ); - \ No newline at end of file diff --git a/Templates/TP_2DSideScroller/Source/TP_2DSideScroller/TP_2DSideScroller.h b/Templates/TP_2DSideScroller/Source/TP_2DSideScroller/TP_2DSideScroller.h index 1335e2680024..25b0d2941503 100644 --- a/Templates/TP_2DSideScroller/Source/TP_2DSideScroller/TP_2DSideScroller.h +++ b/Templates/TP_2DSideScroller/Source/TP_2DSideScroller/TP_2DSideScroller.h @@ -2,9 +2,4 @@ #pragma once -// This file is the private precompiled header for your game. -// You must include it first in each .cpp file. -// -// Place any includes here that are needed by the majority of your .cpp files - -#include "EngineMinimal.h" +#include "CoreMinimal.h" diff --git a/Templates/TP_2DSideScroller/Source/TP_2DSideScroller/TP_2DSideScrollerCharacter.cpp b/Templates/TP_2DSideScroller/Source/TP_2DSideScroller/TP_2DSideScrollerCharacter.cpp index 0c32c61cf76e..27685ffab29a 100644 --- a/Templates/TP_2DSideScroller/Source/TP_2DSideScroller/TP_2DSideScrollerCharacter.cpp +++ b/Templates/TP_2DSideScroller/Source/TP_2DSideScroller/TP_2DSideScrollerCharacter.cpp @@ -1,13 +1,17 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_2DSideScroller.h" #include "TP_2DSideScrollerCharacter.h" #include "PaperFlipbookComponent.h" #include "Components/TextRenderComponent.h" - - +#include "Components/CapsuleComponent.h" +#include "Components/InputComponent.h" +#include "GameFramework/SpringArmComponent.h" +#include "GameFramework/CharacterMovementComponent.h" +#include "GameFramework/Controller.h" +#include "Camera/CameraComponent.h" DEFINE_LOG_CATEGORY_STATIC(SideScrollerCharacter, Log, All); + ////////////////////////////////////////////////////////////////////////// // ATP_2DSideScrollerCharacter diff --git a/Templates/TP_2DSideScroller/Source/TP_2DSideScroller/TP_2DSideScrollerCharacter.h b/Templates/TP_2DSideScroller/Source/TP_2DSideScroller/TP_2DSideScrollerCharacter.h index f01024e0cb20..5037a9a34326 100644 --- a/Templates/TP_2DSideScroller/Source/TP_2DSideScroller/TP_2DSideScrollerCharacter.h +++ b/Templates/TP_2DSideScroller/Source/TP_2DSideScroller/TP_2DSideScrollerCharacter.h @@ -2,6 +2,7 @@ #pragma once +#include "CoreMinimal.h" #include "PaperCharacter.h" #include "TP_2DSideScrollerCharacter.generated.h" diff --git a/Templates/TP_2DSideScroller/Source/TP_2DSideScroller/TP_2DSideScrollerGameMode.cpp b/Templates/TP_2DSideScroller/Source/TP_2DSideScroller/TP_2DSideScrollerGameMode.cpp index aef7882ee5ea..40f03a6b3c5d 100644 --- a/Templates/TP_2DSideScroller/Source/TP_2DSideScroller/TP_2DSideScrollerGameMode.cpp +++ b/Templates/TP_2DSideScroller/Source/TP_2DSideScroller/TP_2DSideScrollerGameMode.cpp @@ -1,6 +1,5 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_2DSideScroller.h" #include "TP_2DSideScrollerGameMode.h" #include "TP_2DSideScrollerCharacter.h" diff --git a/Templates/TP_2DSideScroller/Source/TP_2DSideScroller/TP_2DSideScrollerGameMode.h b/Templates/TP_2DSideScroller/Source/TP_2DSideScroller/TP_2DSideScrollerGameMode.h index c532ce1cd33e..dd11529ecba9 100644 --- a/Templates/TP_2DSideScroller/Source/TP_2DSideScroller/TP_2DSideScrollerGameMode.h +++ b/Templates/TP_2DSideScroller/Source/TP_2DSideScroller/TP_2DSideScrollerGameMode.h @@ -1,6 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #pragma once + +#include "CoreMinimal.h" #include "GameFramework/GameModeBase.h" #include "TP_2DSideScrollerGameMode.generated.h" diff --git a/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPerson.Build.cs b/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPerson.Build.cs index 55b9c0ba7972..ef8c1a6c156d 100644 --- a/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPerson.Build.cs +++ b/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPerson.Build.cs @@ -6,6 +6,8 @@ public class TP_FirstPerson : ModuleRules { public TP_FirstPerson(ReadOnlyTargetRules Target) : base(Target) { + PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; + PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay" }); } } diff --git a/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPerson.cpp b/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPerson.cpp index 8e031309acc7..f0dd4331ec36 100644 --- a/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPerson.cpp +++ b/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPerson.cpp @@ -1,7 +1,7 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "TP_FirstPerson.h" - +#include "Modules/ModuleManager.h" IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, TP_FirstPerson, "TP_FirstPerson" ); \ No newline at end of file diff --git a/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPerson.h b/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPerson.h index c97395aa7f0a..25b0d2941503 100644 --- a/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPerson.h +++ b/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPerson.h @@ -1,9 +1,5 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#ifndef __TP_FIRSTPERSON_H__ -#define __TP_FIRSTPERSON_H__ +#pragma once -#include "EngineMinimal.h" - - -#endif +#include "CoreMinimal.h" diff --git a/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonCharacter.cpp b/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonCharacter.cpp index e0d12dd892b2..6c87c50c4d6f 100644 --- a/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonCharacter.cpp +++ b/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonCharacter.cpp @@ -1,11 +1,14 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_FirstPerson.h" #include "TP_FirstPersonCharacter.h" #include "TP_FirstPersonProjectile.h" #include "Animation/AnimInstance.h" +#include "Camera/CameraComponent.h" +#include "Components/CapsuleComponent.h" +#include "Components/InputComponent.h" #include "GameFramework/InputSettings.h" #include "Kismet/HeadMountedDisplayFunctionLibrary.h" +#include "Kismet/GameplayStatics.h" #include "MotionControllerComponent.h" DEFINE_LOG_CATEGORY_STATIC(LogFPChar, Warning, All); diff --git a/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonCharacter.h b/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonCharacter.h index 21beceb8eee2..ed068ae1ff0a 100644 --- a/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonCharacter.h +++ b/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonCharacter.h @@ -1,5 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once + +#include "CoreMinimal.h" #include "GameFramework/Character.h" #include "TP_FirstPersonCharacter.generated.h" diff --git a/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonGameMode.cpp b/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonGameMode.cpp index f9d9428a6d73..4b633fa59c09 100644 --- a/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonGameMode.cpp +++ b/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonGameMode.cpp @@ -1,9 +1,9 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_FirstPerson.h" #include "TP_FirstPersonGameMode.h" #include "TP_FirstPersonHUD.h" #include "TP_FirstPersonCharacter.h" +#include "UObject/ConstructorHelpers.h" ATP_FirstPersonGameMode::ATP_FirstPersonGameMode() : Super() diff --git a/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonGameMode.h b/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonGameMode.h index c3e85d5b9781..2793b2d55ff1 100644 --- a/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonGameMode.h +++ b/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonGameMode.h @@ -1,5 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once + +#include "CoreMinimal.h" #include "GameFramework/GameModeBase.h" #include "TP_FirstPersonGameMode.generated.h" diff --git a/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonHUD.cpp b/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonHUD.cpp index a5d2597d441d..aa899054f532 100644 --- a/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonHUD.cpp +++ b/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonHUD.cpp @@ -1,10 +1,11 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_FirstPerson.h" #include "TP_FirstPersonHUD.h" #include "Engine/Canvas.h" +#include "Engine/Texture2D.h" #include "TextureResource.h" #include "CanvasItem.h" +#include "UObject/ConstructorHelpers.h" ATP_FirstPersonHUD::ATP_FirstPersonHUD() { diff --git a/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonHUD.h b/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonHUD.h index 9705d9043591..fd9ead0ae5fd 100644 --- a/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonHUD.h +++ b/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonHUD.h @@ -1,5 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once + +#include "CoreMinimal.h" #include "GameFramework/HUD.h" #include "TP_FirstPersonHUD.generated.h" diff --git a/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonProjectile.cpp b/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonProjectile.cpp index 9ed5846f2c6d..3d4a698b08b3 100644 --- a/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonProjectile.cpp +++ b/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonProjectile.cpp @@ -1,8 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_FirstPerson.h" #include "TP_FirstPersonProjectile.h" #include "GameFramework/ProjectileMovementComponent.h" +#include "Components/SphereComponent.h" ATP_FirstPersonProjectile::ATP_FirstPersonProjectile() { diff --git a/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonProjectile.h b/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonProjectile.h index acc7ac3b3ac9..22639320610a 100644 --- a/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonProjectile.h +++ b/Templates/TP_FirstPerson/Source/TP_FirstPerson/TP_FirstPersonProjectile.h @@ -1,5 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once + +#include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "TP_FirstPersonProjectile.generated.h" diff --git a/Templates/TP_Flying/Source/TP_Flying/TP_Flying.Build.cs b/Templates/TP_Flying/Source/TP_Flying/TP_Flying.Build.cs index 306339bcbdfb..55e423efeb56 100644 --- a/Templates/TP_Flying/Source/TP_Flying/TP_Flying.Build.cs +++ b/Templates/TP_Flying/Source/TP_Flying/TP_Flying.Build.cs @@ -6,6 +6,8 @@ public class TP_Flying : ModuleRules { public TP_Flying(ReadOnlyTargetRules Target) : base(Target) { + PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; + PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" }); } } diff --git a/Templates/TP_Flying/Source/TP_Flying/TP_Flying.cpp b/Templates/TP_Flying/Source/TP_Flying/TP_Flying.cpp index 742d416511b7..2c573fe78354 100644 --- a/Templates/TP_Flying/Source/TP_Flying/TP_Flying.cpp +++ b/Templates/TP_Flying/Source/TP_Flying/TP_Flying.cpp @@ -1,10 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "TP_Flying.h" - +#include "Modules/ModuleManager.h" IMPLEMENT_PRIMARY_GAME_MODULE(FDefaultGameModuleImpl, TP_Flying, "TP_Flying"); DEFINE_LOG_CATEGORY(LogFlying) - - \ No newline at end of file diff --git a/Templates/TP_Flying/Source/TP_Flying/TP_Flying.h b/Templates/TP_Flying/Source/TP_Flying/TP_Flying.h index 1e6355a54821..c0fc15cea3e2 100644 --- a/Templates/TP_Flying/Source/TP_Flying/TP_Flying.h +++ b/Templates/TP_Flying/Source/TP_Flying/TP_Flying.h @@ -1,10 +1,7 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#ifndef __TP_FLYING_H__ -#define __TP_FLYING_H__ +#pragma once -#include "EngineMinimal.h" +#include "CoreMinimal.h" DECLARE_LOG_CATEGORY_EXTERN(LogFlying, Log, All); - -#endif diff --git a/Templates/TP_Flying/Source/TP_Flying/TP_FlyingGameMode.cpp b/Templates/TP_Flying/Source/TP_Flying/TP_FlyingGameMode.cpp index 3a24d306dfd5..8e60d539fb9e 100644 --- a/Templates/TP_Flying/Source/TP_Flying/TP_FlyingGameMode.cpp +++ b/Templates/TP_Flying/Source/TP_Flying/TP_FlyingGameMode.cpp @@ -1,6 +1,5 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_Flying.h" #include "TP_FlyingGameMode.h" #include "TP_FlyingPawn.h" diff --git a/Templates/TP_Flying/Source/TP_Flying/TP_FlyingGameMode.h b/Templates/TP_Flying/Source/TP_Flying/TP_FlyingGameMode.h index 999a2df7a871..418edf55fd9f 100644 --- a/Templates/TP_Flying/Source/TP_Flying/TP_FlyingGameMode.h +++ b/Templates/TP_Flying/Source/TP_Flying/TP_FlyingGameMode.h @@ -1,9 +1,12 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once + +#include "CoreMinimal.h" #include "GameFramework/GameModeBase.h" #include "TP_FlyingGameMode.generated.h" -UCLASS(minimalapi) +UCLASS(MinimalAPI) class ATP_FlyingGameMode : public AGameModeBase { GENERATED_BODY() diff --git a/Templates/TP_Flying/Source/TP_Flying/TP_FlyingPawn.cpp b/Templates/TP_Flying/Source/TP_Flying/TP_FlyingPawn.cpp index c1fc1986dc0c..e7e2b88de4b6 100644 --- a/Templates/TP_Flying/Source/TP_Flying/TP_FlyingPawn.cpp +++ b/Templates/TP_Flying/Source/TP_Flying/TP_FlyingPawn.cpp @@ -1,7 +1,13 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_Flying.h" #include "TP_FlyingPawn.h" +#include "UObject/ConstructorHelpers.h" +#include "Camera/CameraComponent.h" +#include "Components/StaticMeshComponent.h" +#include "Components/InputComponent.h" +#include "GameFramework/SpringArmComponent.h" +#include "Engine/World.h" +#include "Engine/StaticMesh.h" ATP_FlyingPawn::ATP_FlyingPawn() { diff --git a/Templates/TP_Flying/Source/TP_Flying/TP_FlyingPawn.h b/Templates/TP_Flying/Source/TP_Flying/TP_FlyingPawn.h index d5384660dc9c..c4f5516b5da5 100644 --- a/Templates/TP_Flying/Source/TP_Flying/TP_FlyingPawn.h +++ b/Templates/TP_Flying/Source/TP_Flying/TP_FlyingPawn.h @@ -1,9 +1,11 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #pragma once + +#include "CoreMinimal.h" #include "GameFramework/Pawn.h" #include "TP_FlyingPawn.generated.h" -UCLASS(config=Game) +UCLASS(Config=Game) class ATP_FlyingPawn : public APawn { GENERATED_BODY() diff --git a/Templates/TP_Puzzle/Config/config.ini b/Templates/TP_Puzzle/Config/config.ini index 714263c253ac..70229ee625ae 100644 --- a/Templates/TP_Puzzle/Config/config.ini +++ b/Templates/TP_Puzzle/Config/config.ini @@ -1,3 +1,6 @@ +[InputSettings] ++ActionMappings=(ActionName="ResetVR",Key=R,bShift=False,bCtrl=False,bAlt=False,bCmd=False) + [Redirects] GameName=TP_Puzzle diff --git a/Templates/TP_Puzzle/Source/TP_Puzzle/TP_Puzzle.Build.cs b/Templates/TP_Puzzle/Source/TP_Puzzle/TP_Puzzle.Build.cs index 862ac81b55db..2cc7f1663c46 100644 --- a/Templates/TP_Puzzle/Source/TP_Puzzle/TP_Puzzle.Build.cs +++ b/Templates/TP_Puzzle/Source/TP_Puzzle/TP_Puzzle.Build.cs @@ -6,6 +6,8 @@ public class TP_Puzzle : ModuleRules { public TP_Puzzle(ReadOnlyTargetRules Target) : base(Target) { + PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; + PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay" }); } } diff --git a/Templates/TP_Puzzle/Source/TP_Puzzle/TP_Puzzle.cpp b/Templates/TP_Puzzle/Source/TP_Puzzle/TP_Puzzle.cpp index 29e296150716..8f950728f733 100644 --- a/Templates/TP_Puzzle/Source/TP_Puzzle/TP_Puzzle.cpp +++ b/Templates/TP_Puzzle/Source/TP_Puzzle/TP_Puzzle.cpp @@ -1,10 +1,6 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "TP_Puzzle.h" - +#include "Modules/ModuleManager.h" IMPLEMENT_PRIMARY_GAME_MODULE(FDefaultGameModuleImpl, TP_Puzzle, "TP_Puzzle"); - - - - \ No newline at end of file diff --git a/Templates/TP_Puzzle/Source/TP_Puzzle/TP_Puzzle.h b/Templates/TP_Puzzle/Source/TP_Puzzle/TP_Puzzle.h index dad545dc2e67..25b0d2941503 100644 --- a/Templates/TP_Puzzle/Source/TP_Puzzle/TP_Puzzle.h +++ b/Templates/TP_Puzzle/Source/TP_Puzzle/TP_Puzzle.h @@ -1,10 +1,5 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#ifndef __TP_PUZZLE_H__ -#define __TP_PUZZLE_H__ +#pragma once - -#include "EngineMinimal.h" - - -#endif +#include "CoreMinimal.h" diff --git a/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzleBlock.cpp b/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzleBlock.cpp index 4049b2556ad1..def00b408c07 100644 --- a/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzleBlock.cpp +++ b/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzleBlock.cpp @@ -1,8 +1,11 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_Puzzle.h" #include "TP_PuzzleBlock.h" #include "TP_PuzzleBlockGrid.h" +#include "UObject/ConstructorHelpers.h" +#include "Components/StaticMeshComponent.h" +#include "Engine/StaticMesh.h" +#include "Materials/MaterialInstance.h" ATP_PuzzleBlock::ATP_PuzzleBlock() { diff --git a/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzleBlock.h b/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzleBlock.h index 238d823cae8e..c9afd56e7362 100644 --- a/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzleBlock.h +++ b/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzleBlock.h @@ -1,5 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once + +#include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "TP_PuzzleBlock.generated.h" diff --git a/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzleBlockGrid.cpp b/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzleBlockGrid.cpp index e4bcea145f67..15bd12a80ef9 100644 --- a/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzleBlockGrid.cpp +++ b/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzleBlockGrid.cpp @@ -1,9 +1,9 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_Puzzle.h" #include "TP_PuzzleBlockGrid.h" #include "TP_PuzzleBlock.h" #include "Components/TextRenderComponent.h" +#include "Engine/World.h" #define LOCTEXT_NAMESPACE "PuzzleBlockGrid" diff --git a/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzleBlockGrid.h b/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzleBlockGrid.h index ece66320ef1b..535c85b8d9fa 100644 --- a/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzleBlockGrid.h +++ b/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzleBlockGrid.h @@ -1,5 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once + +#include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "TP_PuzzleBlockGrid.generated.h" diff --git a/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzleGameMode.cpp b/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzleGameMode.cpp index bc1cd93895fb..ed5d0cbf56aa 100644 --- a/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzleGameMode.cpp +++ b/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzleGameMode.cpp @@ -1,6 +1,5 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_Puzzle.h" #include "TP_PuzzleGameMode.h" #include "TP_PuzzlePlayerController.h" #include "TP_PuzzlePawn.h" diff --git a/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzleGameMode.h b/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzleGameMode.h index d408f79a820a..77769d56d82a 100644 --- a/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzleGameMode.h +++ b/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzleGameMode.h @@ -1,5 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once + +#include "CoreMinimal.h" #include "GameFramework/GameModeBase.h" #include "TP_PuzzleGameMode.generated.h" diff --git a/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzlePawn.cpp b/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzlePawn.cpp index 155f64c152a0..b8511a9319bf 100644 --- a/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzlePawn.cpp +++ b/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzlePawn.cpp @@ -1,9 +1,11 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_Puzzle.h" #include "TP_PuzzlePawn.h" #include "TP_PuzzleBlock.h" #include "Kismet/HeadMountedDisplayFunctionLibrary.h" +#include "Camera/CameraComponent.h" +#include "GameFramework/PlayerController.h" +#include "Engine/World.h" #include "DrawDebugHelpers.h" ATP_PuzzlePawn::ATP_PuzzlePawn(const FObjectInitializer& ObjectInitializer) diff --git a/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzlePawn.h b/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzlePawn.h index e6ca443286d9..e55abd507ebb 100644 --- a/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzlePawn.h +++ b/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzlePawn.h @@ -1,6 +1,9 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once +#include "CoreMinimal.h" +#include "GameFramework/Pawn.h" #include "TP_PuzzlePawn.generated.h" UCLASS(config=Game) diff --git a/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzlePlayerController.cpp b/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzlePlayerController.cpp index e5d602d1a6a9..4b5bb7ea3c57 100644 --- a/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzlePlayerController.cpp +++ b/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzlePlayerController.cpp @@ -1,6 +1,5 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_Puzzle.h" #include "TP_PuzzlePlayerController.h" ATP_PuzzlePlayerController::ATP_PuzzlePlayerController() diff --git a/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzlePlayerController.h b/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzlePlayerController.h index 5d4f94e488ce..4c13a28e8949 100644 --- a/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzlePlayerController.h +++ b/Templates/TP_Puzzle/Source/TP_Puzzle/TP_PuzzlePlayerController.h @@ -1,5 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once + +#include "CoreMinimal.h" #include "GameFramework/PlayerController.h" #include "TP_PuzzlePlayerController.generated.h" diff --git a/Templates/TP_PuzzleBP/Config/config.ini b/Templates/TP_PuzzleBP/Config/config.ini index 5961d58f8339..a6a0feaaee46 100644 --- a/Templates/TP_PuzzleBP/Config/config.ini +++ b/Templates/TP_PuzzleBP/Config/config.ini @@ -1,3 +1,6 @@ +[InputSettings] ++ActionMappings=(ActionName="ResetVR",Key=R,bShift=False,bCtrl=False,bAlt=False,bCmd=False) + [Redirects] GameName=TP_PuzzleBP diff --git a/Templates/TP_Rolling/Source/TP_Rolling/TP_Rolling.Build.cs b/Templates/TP_Rolling/Source/TP_Rolling/TP_Rolling.Build.cs index 953453a32739..4e0ddb03ca9c 100644 --- a/Templates/TP_Rolling/Source/TP_Rolling/TP_Rolling.Build.cs +++ b/Templates/TP_Rolling/Source/TP_Rolling/TP_Rolling.Build.cs @@ -6,6 +6,8 @@ public class TP_Rolling : ModuleRules { public TP_Rolling(ReadOnlyTargetRules Target) : base(Target) { + PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; + PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" }); } } diff --git a/Templates/TP_Rolling/Source/TP_Rolling/TP_Rolling.cpp b/Templates/TP_Rolling/Source/TP_Rolling/TP_Rolling.cpp index de5efac5187a..cd676d4d3b82 100644 --- a/Templates/TP_Rolling/Source/TP_Rolling/TP_Rolling.cpp +++ b/Templates/TP_Rolling/Source/TP_Rolling/TP_Rolling.cpp @@ -1,6 +1,7 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "TP_Rolling.h" +#include "Modules/ModuleManager.h" IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, TP_Rolling, "TP_Rolling" ); \ No newline at end of file diff --git a/Templates/TP_Rolling/Source/TP_Rolling/TP_Rolling.h b/Templates/TP_Rolling/Source/TP_Rolling/TP_Rolling.h index 4c0bbf16d435..25b0d2941503 100644 --- a/Templates/TP_Rolling/Source/TP_Rolling/TP_Rolling.h +++ b/Templates/TP_Rolling/Source/TP_Rolling/TP_Rolling.h @@ -1,8 +1,5 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#ifndef __TP_ROLLING_H__ -#define __TP_ROLLING_H__ +#pragma once -#include "EngineMinimal.h" - -#endif +#include "CoreMinimal.h" diff --git a/Templates/TP_Rolling/Source/TP_Rolling/TP_RollingBall.cpp b/Templates/TP_Rolling/Source/TP_Rolling/TP_RollingBall.cpp index 52ebdd01159b..8da42bccc540 100644 --- a/Templates/TP_Rolling/Source/TP_Rolling/TP_RollingBall.cpp +++ b/Templates/TP_Rolling/Source/TP_Rolling/TP_RollingBall.cpp @@ -1,7 +1,13 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_Rolling.h" #include "TP_RollingBall.h" +#include "UObject/ConstructorHelpers.h" +#include "Camera/CameraComponent.h" +#include "Components/StaticMeshComponent.h" +#include "Components/InputComponent.h" +#include "GameFramework/SpringArmComponent.h" +#include "Engine/CollisionProfile.h" +#include "Engine/StaticMesh.h" ATP_RollingBall::ATP_RollingBall() { diff --git a/Templates/TP_Rolling/Source/TP_Rolling/TP_RollingBall.h b/Templates/TP_Rolling/Source/TP_Rolling/TP_RollingBall.h index ba6c3c5621c6..861cb7dd21a6 100644 --- a/Templates/TP_Rolling/Source/TP_Rolling/TP_RollingBall.h +++ b/Templates/TP_Rolling/Source/TP_Rolling/TP_RollingBall.h @@ -1,5 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once + +#include "CoreMinimal.h" #include "GameFramework/Pawn.h" #include "TP_RollingBall.generated.h" diff --git a/Templates/TP_Rolling/Source/TP_Rolling/TP_RollingGameMode.cpp b/Templates/TP_Rolling/Source/TP_Rolling/TP_RollingGameMode.cpp index 7fc06bfc4cde..f7bf953e1f51 100644 --- a/Templates/TP_Rolling/Source/TP_Rolling/TP_RollingGameMode.cpp +++ b/Templates/TP_Rolling/Source/TP_Rolling/TP_RollingGameMode.cpp @@ -1,6 +1,5 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_Rolling.h" #include "TP_RollingGameMode.h" #include "TP_RollingBall.h" diff --git a/Templates/TP_Rolling/Source/TP_Rolling/TP_RollingGameMode.h b/Templates/TP_Rolling/Source/TP_Rolling/TP_RollingGameMode.h index b5679a486ddd..bcb77ace1010 100644 --- a/Templates/TP_Rolling/Source/TP_Rolling/TP_RollingGameMode.h +++ b/Templates/TP_Rolling/Source/TP_Rolling/TP_RollingGameMode.h @@ -1,5 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once + +#include "CoreMinimal.h" #include "GameFramework/GameModeBase.h" #include "TP_RollingGameMode.generated.h" diff --git a/Templates/TP_SideScroller/Source/TP_SideScroller/TP_SideScroller.Build.cs b/Templates/TP_SideScroller/Source/TP_SideScroller/TP_SideScroller.Build.cs index 83b35bc81fb6..fa2d453bc1cc 100644 --- a/Templates/TP_SideScroller/Source/TP_SideScroller/TP_SideScroller.Build.cs +++ b/Templates/TP_SideScroller/Source/TP_SideScroller/TP_SideScroller.Build.cs @@ -6,6 +6,8 @@ public class TP_SideScroller : ModuleRules { public TP_SideScroller(ReadOnlyTargetRules Target) : base(Target) { + PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; + PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" }); } } diff --git a/Templates/TP_SideScroller/Source/TP_SideScroller/TP_SideScroller.cpp b/Templates/TP_SideScroller/Source/TP_SideScroller/TP_SideScroller.cpp index b6e707032462..cc83ac5aed38 100644 --- a/Templates/TP_SideScroller/Source/TP_SideScroller/TP_SideScroller.cpp +++ b/Templates/TP_SideScroller/Source/TP_SideScroller/TP_SideScroller.cpp @@ -1,7 +1,7 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "TP_SideScroller.h" - +#include "Modules/ModuleManager.h" IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, TP_SideScroller, "TP_SideScroller" ); \ No newline at end of file diff --git a/Templates/TP_SideScroller/Source/TP_SideScroller/TP_SideScroller.h b/Templates/TP_SideScroller/Source/TP_SideScroller/TP_SideScroller.h index 41b2df803b69..25b0d2941503 100644 --- a/Templates/TP_SideScroller/Source/TP_SideScroller/TP_SideScroller.h +++ b/Templates/TP_SideScroller/Source/TP_SideScroller/TP_SideScroller.h @@ -1,8 +1,5 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#ifndef __TP_SIDESCROLLER_H__ -#define __TP_SIDESCROLLER_H__ +#pragma once -#include "EngineMinimal.h" - -#endif +#include "CoreMinimal.h" diff --git a/Templates/TP_SideScroller/Source/TP_SideScroller/TP_SideScrollerCharacter.cpp b/Templates/TP_SideScroller/Source/TP_SideScroller/TP_SideScrollerCharacter.cpp index f818c5cc5de7..549e7011e4d7 100644 --- a/Templates/TP_SideScroller/Source/TP_SideScroller/TP_SideScrollerCharacter.cpp +++ b/Templates/TP_SideScroller/Source/TP_SideScroller/TP_SideScrollerCharacter.cpp @@ -1,7 +1,11 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_SideScroller.h" #include "TP_SideScrollerCharacter.h" +#include "Camera/CameraComponent.h" +#include "Components/CapsuleComponent.h" +#include "Components/InputComponent.h" +#include "GameFramework/SpringArmComponent.h" +#include "GameFramework/CharacterMovementComponent.h" ATP_SideScrollerCharacter::ATP_SideScrollerCharacter() { diff --git a/Templates/TP_SideScroller/Source/TP_SideScroller/TP_SideScrollerCharacter.h b/Templates/TP_SideScroller/Source/TP_SideScroller/TP_SideScrollerCharacter.h index c253aabda3bc..b91f7538f054 100644 --- a/Templates/TP_SideScroller/Source/TP_SideScroller/TP_SideScrollerCharacter.h +++ b/Templates/TP_SideScroller/Source/TP_SideScroller/TP_SideScrollerCharacter.h @@ -1,5 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once + +#include "CoreMinimal.h" #include "GameFramework/Character.h" #include "TP_SideScrollerCharacter.generated.h" diff --git a/Templates/TP_SideScroller/Source/TP_SideScroller/TP_SideScrollerGameMode.cpp b/Templates/TP_SideScroller/Source/TP_SideScroller/TP_SideScrollerGameMode.cpp index 2c1c6dd7b7ea..54a6c1bbd30a 100644 --- a/Templates/TP_SideScroller/Source/TP_SideScroller/TP_SideScrollerGameMode.cpp +++ b/Templates/TP_SideScroller/Source/TP_SideScroller/TP_SideScrollerGameMode.cpp @@ -1,8 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_SideScroller.h" #include "TP_SideScrollerGameMode.h" #include "TP_SideScrollerCharacter.h" +#include "UObject/ConstructorHelpers.h" ATP_SideScrollerGameMode::ATP_SideScrollerGameMode() { diff --git a/Templates/TP_SideScroller/Source/TP_SideScroller/TP_SideScrollerGameMode.h b/Templates/TP_SideScroller/Source/TP_SideScroller/TP_SideScrollerGameMode.h index b5e2a6c7dff4..1239ef466d44 100644 --- a/Templates/TP_SideScroller/Source/TP_SideScroller/TP_SideScrollerGameMode.h +++ b/Templates/TP_SideScroller/Source/TP_SideScroller/TP_SideScrollerGameMode.h @@ -1,5 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once + +#include "CoreMinimal.h" #include "GameFramework/GameModeBase.h" #include "TP_SideScrollerGameMode.generated.h" diff --git a/Templates/TP_ThirdPerson/Config/config.ini b/Templates/TP_ThirdPerson/Config/config.ini index af6971384362..2bdddd29bd50 100644 --- a/Templates/TP_ThirdPerson/Config/config.ini +++ b/Templates/TP_ThirdPerson/Config/config.ini @@ -1,6 +1,7 @@ [InputSettings] +ActionMappings=(ActionName="Jump", Key=SpaceBar) +ActionMappings=(ActionName="Jump", Key=Gamepad_FaceButton_Bottom) ++ActionMappings=(ActionName="ResetVR", Key=R) +AxisMappings=(AxisName="MoveForward", Key=W, Scale=1.f) +AxisMappings=(AxisName="MoveForward", Key=S, Scale=-1.f) diff --git a/Templates/TP_ThirdPerson/Source/TP_ThirdPerson/TP_ThirdPerson.Build.cs b/Templates/TP_ThirdPerson/Source/TP_ThirdPerson/TP_ThirdPerson.Build.cs index bf40a82c297b..2ce8287024d4 100644 --- a/Templates/TP_ThirdPerson/Source/TP_ThirdPerson/TP_ThirdPerson.Build.cs +++ b/Templates/TP_ThirdPerson/Source/TP_ThirdPerson/TP_ThirdPerson.Build.cs @@ -6,6 +6,8 @@ public class TP_ThirdPerson : ModuleRules { public TP_ThirdPerson(ReadOnlyTargetRules Target) : base(Target) { + PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; + PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay" }); } } diff --git a/Templates/TP_ThirdPerson/Source/TP_ThirdPerson/TP_ThirdPerson.cpp b/Templates/TP_ThirdPerson/Source/TP_ThirdPerson/TP_ThirdPerson.cpp index ec5cbd08a551..846291892b99 100644 --- a/Templates/TP_ThirdPerson/Source/TP_ThirdPerson/TP_ThirdPerson.cpp +++ b/Templates/TP_ThirdPerson/Source/TP_ThirdPerson/TP_ThirdPerson.cpp @@ -1,7 +1,7 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "TP_ThirdPerson.h" - +#include "Modules/ModuleManager.h" IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, TP_ThirdPerson, "TP_ThirdPerson" ); \ No newline at end of file diff --git a/Templates/TP_ThirdPerson/Source/TP_ThirdPerson/TP_ThirdPerson.h b/Templates/TP_ThirdPerson/Source/TP_ThirdPerson/TP_ThirdPerson.h index c433d4511d12..25b0d2941503 100644 --- a/Templates/TP_ThirdPerson/Source/TP_ThirdPerson/TP_ThirdPerson.h +++ b/Templates/TP_ThirdPerson/Source/TP_ThirdPerson/TP_ThirdPerson.h @@ -1,8 +1,5 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#ifndef __TP_THIRDPERSON_H__ -#define __TP_THIRDPERSON_H__ +#pragma once -#include "EngineMinimal.h" - -#endif +#include "CoreMinimal.h" diff --git a/Templates/TP_ThirdPerson/Source/TP_ThirdPerson/TP_ThirdPersonCharacter.cpp b/Templates/TP_ThirdPerson/Source/TP_ThirdPerson/TP_ThirdPersonCharacter.cpp index 9bf3936ce5b6..d2c49d3efe46 100644 --- a/Templates/TP_ThirdPerson/Source/TP_ThirdPerson/TP_ThirdPersonCharacter.cpp +++ b/Templates/TP_ThirdPerson/Source/TP_ThirdPerson/TP_ThirdPersonCharacter.cpp @@ -1,8 +1,13 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_ThirdPerson.h" -#include "Kismet/HeadMountedDisplayFunctionLibrary.h" #include "TP_ThirdPersonCharacter.h" +#include "Kismet/HeadMountedDisplayFunctionLibrary.h" +#include "Camera/CameraComponent.h" +#include "Components/CapsuleComponent.h" +#include "Components/InputComponent.h" +#include "GameFramework/CharacterMovementComponent.h" +#include "GameFramework/Controller.h" +#include "GameFramework/SpringArmComponent.h" ////////////////////////////////////////////////////////////////////////// // ATP_ThirdPersonCharacter diff --git a/Templates/TP_ThirdPerson/Source/TP_ThirdPerson/TP_ThirdPersonCharacter.h b/Templates/TP_ThirdPerson/Source/TP_ThirdPerson/TP_ThirdPersonCharacter.h index e400d89ac39d..c3f3b30c4026 100644 --- a/Templates/TP_ThirdPerson/Source/TP_ThirdPerson/TP_ThirdPersonCharacter.h +++ b/Templates/TP_ThirdPerson/Source/TP_ThirdPerson/TP_ThirdPersonCharacter.h @@ -1,5 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once + +#include "CoreMinimal.h" #include "GameFramework/Character.h" #include "TP_ThirdPersonCharacter.generated.h" diff --git a/Templates/TP_ThirdPerson/Source/TP_ThirdPerson/TP_ThirdPersonGameMode.cpp b/Templates/TP_ThirdPerson/Source/TP_ThirdPerson/TP_ThirdPersonGameMode.cpp index 2c37b6db7a50..a852416a5568 100644 --- a/Templates/TP_ThirdPerson/Source/TP_ThirdPerson/TP_ThirdPersonGameMode.cpp +++ b/Templates/TP_ThirdPerson/Source/TP_ThirdPerson/TP_ThirdPersonGameMode.cpp @@ -1,8 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_ThirdPerson.h" #include "TP_ThirdPersonGameMode.h" #include "TP_ThirdPersonCharacter.h" +#include "UObject/ConstructorHelpers.h" ATP_ThirdPersonGameMode::ATP_ThirdPersonGameMode() { diff --git a/Templates/TP_ThirdPerson/Source/TP_ThirdPerson/TP_ThirdPersonGameMode.h b/Templates/TP_ThirdPerson/Source/TP_ThirdPerson/TP_ThirdPersonGameMode.h index 84f25bac895f..0be6da0b87a8 100644 --- a/Templates/TP_ThirdPerson/Source/TP_ThirdPerson/TP_ThirdPersonGameMode.h +++ b/Templates/TP_ThirdPerson/Source/TP_ThirdPerson/TP_ThirdPersonGameMode.h @@ -1,5 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once + +#include "CoreMinimal.h" #include "GameFramework/GameModeBase.h" #include "TP_ThirdPersonGameMode.generated.h" diff --git a/Templates/TP_ThirdPersonBP/Config/config.ini b/Templates/TP_ThirdPersonBP/Config/config.ini index 70e3cc537acf..6b339621f099 100644 --- a/Templates/TP_ThirdPersonBP/Config/config.ini +++ b/Templates/TP_ThirdPersonBP/Config/config.ini @@ -1,6 +1,7 @@ [InputSettings] +ActionMappings=(ActionName="Jump", Key=SpaceBar) +ActionMappings=(ActionName="Jump", Key=Gamepad_FaceButton_Bottom) ++ActionMappings=(ActionName="ResetVR", Key=R) +AxisMappings=(AxisName="MoveForward", Key=W, Scale=1.f) +AxisMappings=(AxisName="MoveForward", Key=S, Scale=-1.f) diff --git a/Templates/TP_TopDown/Config/config.ini b/Templates/TP_TopDown/Config/config.ini index 9e67567483e7..6011ac4be365 100644 --- a/Templates/TP_TopDown/Config/config.ini +++ b/Templates/TP_TopDown/Config/config.ini @@ -5,6 +5,7 @@ +AxisMappings=(AxisName="MoveRight", Key=D, Scale=1.f) +AxisMappings=(AxisName="MoveRight", Key=A, Scale=-1.f) +ActionMappings=(ActionName="SetDestination", Key=LeftMouseButton) ++ActionMappings=(ActionName="ResetVR",Key=R,bShift=False,bCtrl=False,bAlt=False,bCmd=False) [Redirects] GameName=TP_TopDown diff --git a/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDown.Build.cs b/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDown.Build.cs index 8729153e7c2f..7357a6e37844 100644 --- a/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDown.Build.cs +++ b/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDown.Build.cs @@ -6,6 +6,8 @@ public class TP_TopDown : ModuleRules { public TP_TopDown(ReadOnlyTargetRules Target) : base(Target) { + PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; + PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay" }); } } diff --git a/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDown.cpp b/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDown.cpp index e51a67d2bf0e..09a4faabb324 100644 --- a/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDown.cpp +++ b/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDown.cpp @@ -1,7 +1,7 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "TP_TopDown.h" - +#include "Modules/ModuleManager.h" IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, TP_TopDown, "TP_TopDown" ); diff --git a/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDown.h b/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDown.h index 75f9ddb090db..8cc7d93090aa 100644 --- a/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDown.h +++ b/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDown.h @@ -1,11 +1,7 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#ifndef __TP_TOPDOWN_H__ -#define __TP_TOPDOWN_H__ +#pragma once -#include "EngineMinimal.h" +#include "CoreMinimal.h" DECLARE_LOG_CATEGORY_EXTERN(LogTP_TopDown, Log, All); - - -#endif diff --git a/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDownCharacter.cpp b/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDownCharacter.cpp index 12054642a737..02c022928035 100644 --- a/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDownCharacter.cpp +++ b/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDownCharacter.cpp @@ -1,10 +1,15 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_TopDown.h" #include "TP_TopDownCharacter.h" -#include "Runtime/CoreUObject/Public/UObject/ConstructorHelpers.h" -#include "Runtime/Engine/Classes/Components/DecalComponent.h" +#include "UObject/ConstructorHelpers.h" +#include "Camera/CameraComponent.h" +#include "Components/DecalComponent.h" +#include "Components/CapsuleComponent.h" +#include "GameFramework/CharacterMovementComponent.h" +#include "GameFramework/PlayerController.h" +#include "GameFramework/SpringArmComponent.h" #include "Kismet/HeadMountedDisplayFunctionLibrary.h" +#include "Materials/Material.h" ATP_TopDownCharacter::ATP_TopDownCharacter() { @@ -30,7 +35,7 @@ ATP_TopDownCharacter::ATP_TopDownCharacter() CameraBoom->RelativeRotation = FRotator(-60.f, 0.f, 0.f); CameraBoom->bDoCollisionTest = false; // Don't want to pull camera in when it collides with level - // Create a camera... + // Create a camera... TopDownCameraComponent = CreateDefaultSubobject(TEXT("TopDownCamera")); TopDownCameraComponent->SetupAttachment(CameraBoom, USpringArmComponent::SocketName); TopDownCameraComponent->bUsePawnControlRotation = false; // Camera does not rotate relative to arm @@ -62,7 +67,7 @@ void ATP_TopDownCharacter::Tick(float DeltaSeconds) if (UWorld* World = GetWorld()) { FHitResult HitResult; - FCollisionQueryParams Params; + FCollisionQueryParams Params(NAME_None, FCollisionQueryParams::GetUnknownStatId()); FVector StartLocation = TopDownCameraComponent->GetComponentLocation(); FVector EndLocation = TopDownCameraComponent->GetComponentRotation().Vector() * 2000.0f; Params.AddIgnoredActor(this); diff --git a/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDownCharacter.h b/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDownCharacter.h index faf56cbeb36f..1947e368eef9 100644 --- a/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDownCharacter.h +++ b/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDownCharacter.h @@ -1,5 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once + +#include "CoreMinimal.h" #include "GameFramework/Character.h" #include "TP_TopDownCharacter.generated.h" diff --git a/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDownGameMode.cpp b/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDownGameMode.cpp index 36f49071a4ed..8705272fe002 100644 --- a/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDownGameMode.cpp +++ b/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDownGameMode.cpp @@ -1,9 +1,9 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_TopDown.h" #include "TP_TopDownGameMode.h" #include "TP_TopDownPlayerController.h" #include "TP_TopDownCharacter.h" +#include "UObject/ConstructorHelpers.h" ATP_TopDownGameMode::ATP_TopDownGameMode() { diff --git a/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDownGameMode.h b/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDownGameMode.h index aad544e936be..6c7887edaf22 100644 --- a/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDownGameMode.h +++ b/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDownGameMode.h @@ -1,5 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once + +#include "CoreMinimal.h" #include "GameFramework/GameModeBase.h" #include "TP_TopDownGameMode.generated.h" diff --git a/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDownPlayerController.cpp b/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDownPlayerController.cpp index d9a14722ab01..b006f9642779 100644 --- a/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDownPlayerController.cpp +++ b/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDownPlayerController.cpp @@ -1,6 +1,5 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_TopDown.h" #include "TP_TopDownPlayerController.h" #include "AI/Navigation/NavigationSystem.h" #include "Runtime/Engine/Classes/Components/DecalComponent.h" diff --git a/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDownPlayerController.h b/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDownPlayerController.h index 99f6542ffef6..203c786555b2 100644 --- a/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDownPlayerController.h +++ b/Templates/TP_TopDown/Source/TP_TopDown/TP_TopDownPlayerController.h @@ -1,5 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once + +#include "CoreMinimal.h" #include "GameFramework/PlayerController.h" #include "TP_TopDownPlayerController.generated.h" diff --git a/Templates/TP_TopDownBP/Config/config.ini b/Templates/TP_TopDownBP/Config/config.ini index 2610fa7a9a30..ebfcf46641af 100644 --- a/Templates/TP_TopDownBP/Config/config.ini +++ b/Templates/TP_TopDownBP/Config/config.ini @@ -5,6 +5,7 @@ +AxisMappings=(AxisName="MoveRight", Key=D, Scale=1.f) +AxisMappings=(AxisName="MoveRight", Key=A, Scale=-1.f) +ActionMappings=(ActionName="SetDestination", Key=LeftMouseButton) ++ActionMappings=(ActionName="ResetVR",Key=R,bShift=False,bCtrl=False,bAlt=False,bCmd=False) [Redirects] GameName=TP_TopDownBP diff --git a/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStick.Build.cs b/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStick.Build.cs index 4c739dd041fe..5354c1486778 100644 --- a/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStick.Build.cs +++ b/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStick.Build.cs @@ -6,6 +6,8 @@ public class TP_TwinStick : ModuleRules { public TP_TwinStick(ReadOnlyTargetRules Target) : base(Target) { + PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; + PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" }); } } diff --git a/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStick.cpp b/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStick.cpp index 59ac657adcad..0b0f2778d740 100644 --- a/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStick.cpp +++ b/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStick.cpp @@ -1,7 +1,7 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "TP_TwinStick.h" - +#include "Modules/ModuleManager.h" IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, TP_TwinStick, "TP_TwinStick" ); diff --git a/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStick.h b/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStick.h index 30ad2d66fa6d..0a0c15b25b46 100644 --- a/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStick.h +++ b/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStick.h @@ -1,16 +1,7 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#ifndef __TP_TWINSTICK_H__ -#define __TP_TWINSTICK_H__ +#pragma once -// This file is the private precompiled header for your game. -// You must include it first in each .cpp file. -// -// Place any includes here that are needed by the majority of your .cpp files - -#include "EngineMinimal.h" +#include "CoreMinimal.h" DECLARE_LOG_CATEGORY_EXTERN(LogTP_TwinStick, Log, All); - - -#endif diff --git a/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStickGameMode.cpp b/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStickGameMode.cpp index 0f41605d931d..6073b47e342e 100644 --- a/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStickGameMode.cpp +++ b/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStickGameMode.cpp @@ -1,6 +1,5 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_TwinStick.h" #include "TP_TwinStickGameMode.h" #include "TP_TwinStickPawn.h" diff --git a/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStickGameMode.h b/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStickGameMode.h index 79437a41d083..05032accb921 100644 --- a/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStickGameMode.h +++ b/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStickGameMode.h @@ -1,11 +1,12 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once +#include "CoreMinimal.h" #include "GameFramework/GameModeBase.h" #include "TP_TwinStickGameMode.generated.h" - -UCLASS(minimalapi) +UCLASS(MinimalAPI) class ATP_TwinStickGameMode : public AGameModeBase { GENERATED_BODY() diff --git a/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStickPawn.cpp b/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStickPawn.cpp index 8dcadd1a0908..64f8e6fb0c7c 100644 --- a/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStickPawn.cpp +++ b/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStickPawn.cpp @@ -1,9 +1,17 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_TwinStick.h" #include "TP_TwinStickPawn.h" #include "TP_TwinStickProjectile.h" #include "TimerManager.h" +#include "UObject/ConstructorHelpers.h" +#include "Camera/CameraComponent.h" +#include "Components/StaticMeshComponent.h" +#include "Components/InputComponent.h" +#include "GameFramework/SpringArmComponent.h" +#include "Engine/CollisionProfile.h" +#include "Engine/StaticMesh.h" +#include "Kismet/GameplayStatics.h" +#include "Sound/SoundBase.h" const FName ATP_TwinStickPawn::MoveForwardBinding("MoveForward"); const FName ATP_TwinStickPawn::MoveRightBinding("MoveRight"); diff --git a/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStickPawn.h b/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStickPawn.h index 28cb2fc8d66e..dcb7fe1366f0 100644 --- a/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStickPawn.h +++ b/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStickPawn.h @@ -1,6 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once +#include "CoreMinimal.h" #include "GameFramework/Character.h" #include "TP_TwinStickPawn.generated.h" diff --git a/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStickProjectile.cpp b/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStickProjectile.cpp index bdec831adb4f..c5068e76a12d 100644 --- a/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStickProjectile.cpp +++ b/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStickProjectile.cpp @@ -1,8 +1,11 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserve -#include "TP_TwinStick.h" #include "TP_TwinStickProjectile.h" #include "GameFramework/ProjectileMovementComponent.h" +#include "UObject/ConstructorHelpers.h" +#include "Components/StaticMeshComponent.h" +#include "GameFramework/ProjectileMovementComponent.h" +#include "Engine/StaticMesh.h" ATP_TwinStickProjectile::ATP_TwinStickProjectile() { diff --git a/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStickProjectile.h b/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStickProjectile.h index 5918537caab9..bf301b575b4c 100644 --- a/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStickProjectile.h +++ b/Templates/TP_TwinStick/Source/TP_TwinStick/TP_TwinStickProjectile.h @@ -1,6 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once +#include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "TP_TwinStickProjectile.generated.h" diff --git a/Templates/TP_Vehicle/Source/TP_Vehicle/TP_Vehicle.Build.cs b/Templates/TP_Vehicle/Source/TP_Vehicle/TP_Vehicle.Build.cs index 131781127dc5..6a9db6c641d9 100644 --- a/Templates/TP_Vehicle/Source/TP_Vehicle/TP_Vehicle.Build.cs +++ b/Templates/TP_Vehicle/Source/TP_Vehicle/TP_Vehicle.Build.cs @@ -6,6 +6,10 @@ public class TP_Vehicle : ModuleRules { public TP_Vehicle(ReadOnlyTargetRules Target) : base(Target) { + PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; + PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "PhysXVehicles", "HeadMountedDisplay" }); + + Definitions.Add("HMD_MODULE_INCLUDED=1"); } } diff --git a/Templates/TP_Vehicle/Source/TP_Vehicle/TP_Vehicle.cpp b/Templates/TP_Vehicle/Source/TP_Vehicle/TP_Vehicle.cpp index b578d42ed33a..6453eaff71a4 100644 --- a/Templates/TP_Vehicle/Source/TP_Vehicle/TP_Vehicle.cpp +++ b/Templates/TP_Vehicle/Source/TP_Vehicle/TP_Vehicle.cpp @@ -1,7 +1,7 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "TP_Vehicle.h" - +#include "Modules/ModuleManager.h" IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, TP_Vehicle, "TP_Vehicle" ); \ No newline at end of file diff --git a/Templates/TP_Vehicle/Source/TP_Vehicle/TP_Vehicle.h b/Templates/TP_Vehicle/Source/TP_Vehicle/TP_Vehicle.h index 3bf694c78dc9..098d1622fa8e 100644 --- a/Templates/TP_Vehicle/Source/TP_Vehicle/TP_Vehicle.h +++ b/Templates/TP_Vehicle/Source/TP_Vehicle/TP_Vehicle.h @@ -1,10 +1,5 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#ifndef __TP_VEHICLE_H__ -#define __TP_VEHICLE_H__ +#pragma once -#include "CoreUObject.h" - -#define HMD_MODULE_INCLUDED 1 - -#endif +#include "CoreMinimal.h" \ No newline at end of file diff --git a/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehicleGameMode.cpp b/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehicleGameMode.cpp index de79b1dccee9..9714c3b792bc 100644 --- a/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehicleGameMode.cpp +++ b/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehicleGameMode.cpp @@ -1,6 +1,5 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_Vehicle.h" #include "TP_VehicleGameMode.h" #include "TP_VehiclePawn.h" #include "TP_VehicleHud.h" diff --git a/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehicleHud.cpp b/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehicleHud.cpp index d79805454f54..124b0818740e 100644 --- a/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehicleHud.cpp +++ b/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehicleHud.cpp @@ -1,6 +1,5 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_Vehicle.h" #include "TP_VehicleHud.h" #include "TP_VehiclePawn.h" #include "WheeledVehicle.h" @@ -10,7 +9,8 @@ #include "WheeledVehicleMovementComponent.h" #include "Engine/Font.h" #include "CanvasItem.h" -#include "Engine.h" +#include "UObject/ConstructorHelpers.h" +#include "Engine/Engine.h" // Needed for VR Headset #if HMD_MODULE_INCLUDED diff --git a/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehiclePawn.cpp b/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehiclePawn.cpp index 1d5799b2b08a..2cb169f2eef3 100644 --- a/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehiclePawn.cpp +++ b/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehiclePawn.cpp @@ -1,6 +1,5 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_Vehicle.h" #include "TP_VehiclePawn.h" #include "TP_VehicleWheelFront.h" #include "TP_VehicleWheelRear.h" @@ -11,7 +10,11 @@ #include "Components/InputComponent.h" #include "WheeledVehicleMovementComponent4W.h" #include "Engine/SkeletalMesh.h" -#include "Engine.h" +#include "Engine/Engine.h" +#include "UObject/ConstructorHelpers.h" +#include "Components/TextRenderComponent.h" +#include "Materials/Material.h" +#include "GameFramework/Controller.h" // Needed for VR Headset #if HMD_MODULE_INCLUDED diff --git a/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehiclePawn.h b/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehiclePawn.h index b0f75714554e..60af6c36d80c 100644 --- a/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehiclePawn.h +++ b/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehiclePawn.h @@ -1,5 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once + +#include "CoreMinimal.h" #include "WheeledVehicle.h" #include "TP_VehiclePawn.generated.h" @@ -7,6 +10,7 @@ class UCameraComponent; class USpringArmComponent; class UTextRenderComponent; class UInputComponent; + UCLASS(config=Game) class ATP_VehiclePawn : public AWheeledVehicle { diff --git a/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehicleWheelFront.cpp b/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehicleWheelFront.cpp index c7f4d52dc202..2efeaa13db85 100644 --- a/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehicleWheelFront.cpp +++ b/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehicleWheelFront.cpp @@ -1,6 +1,5 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_Vehicle.h" #include "TP_VehicleWheelFront.h" UTP_VehicleWheelFront::UTP_VehicleWheelFront() diff --git a/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehicleWheelFront.h b/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehicleWheelFront.h index b547d9c2235b..573589854d03 100644 --- a/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehicleWheelFront.h +++ b/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehicleWheelFront.h @@ -1,5 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once + +#include "CoreMinimal.h" #include "VehicleWheel.h" #include "TP_VehicleWheelFront.generated.h" diff --git a/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehicleWheelRear.cpp b/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehicleWheelRear.cpp index 7e7ee105bc85..94777f9472cc 100644 --- a/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehicleWheelRear.cpp +++ b/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehicleWheelRear.cpp @@ -1,6 +1,5 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_Vehicle.h" #include "TP_VehicleWheelRear.h" UTP_VehicleWheelRear::UTP_VehicleWheelRear() diff --git a/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehicleWheelRear.h b/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehicleWheelRear.h index 5d05f900dfdc..f43acfc7266a 100644 --- a/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehicleWheelRear.h +++ b/Templates/TP_Vehicle/Source/TP_Vehicle/TP_VehicleWheelRear.h @@ -1,5 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once + +#include "CoreMinimal.h" #include "VehicleWheel.h" #include "TP_VehicleWheelRear.generated.h" diff --git a/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdv.Build.cs b/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdv.Build.cs index cd9f7048d97f..e8bdd27aeead 100644 --- a/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdv.Build.cs +++ b/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdv.Build.cs @@ -6,6 +6,10 @@ public class TP_VehicleAdv : ModuleRules { public TP_VehicleAdv(ReadOnlyTargetRules Target) : base(Target) { + PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; + PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "PhysXVehicles", "HeadMountedDisplay" }); + + Definitions.Add("HMD_MODULE_INCLUDED=1"); } } diff --git a/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdv.cpp b/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdv.cpp index 1849ebb3cd27..19be3a3a6bd5 100644 --- a/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdv.cpp +++ b/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdv.cpp @@ -1,7 +1,7 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "TP_VehicleAdv.h" - +#include "Modules/ModuleManager.h" IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, TP_VehicleAdv, "TP_VehicleAdv" ); \ No newline at end of file diff --git a/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdv.h b/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdv.h index c85e05547cf5..25b0d2941503 100644 --- a/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdv.h +++ b/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdv.h @@ -1,10 +1,5 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#ifndef __TP_VehicleAdvADV_H__ -#define __TP_VehicleAdvADV_H__ +#pragma once -#include "EngineMinimal.h" - -#define HMD_MODULE_INCLUDED 1 - -#endif +#include "CoreMinimal.h" diff --git a/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvGameMode.cpp b/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvGameMode.cpp index e71c787dce2c..0715b41fb04e 100644 --- a/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvGameMode.cpp +++ b/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvGameMode.cpp @@ -1,6 +1,5 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_VehicleAdv.h" #include "TP_VehicleAdvGameMode.h" #include "TP_VehicleAdvPawn.h" #include "TP_VehicleAdvHud.h" diff --git a/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvGameMode.h b/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvGameMode.h index 2c1c4ada2b50..6e67fb2a3925 100644 --- a/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvGameMode.h +++ b/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvGameMode.h @@ -1,9 +1,12 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once + +#include "CoreMinimal.h" #include "GameFramework/GameModeBase.h" #include "TP_VehicleAdvGameMode.generated.h" -UCLASS(minimalapi) +UCLASS(MinimalAPI) class ATP_VehicleAdvGameMode : public AGameModeBase { GENERATED_BODY() diff --git a/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvHud.cpp b/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvHud.cpp index 0ad29ec16024..ae1515cd7566 100644 --- a/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvHud.cpp +++ b/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvHud.cpp @@ -1,11 +1,12 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_VehicleAdv.h" #include "TP_VehicleAdvHud.h" #include "TP_VehicleAdvPawn.h" #include "Engine/Canvas.h" #include "Engine/Font.h" #include "CanvasItem.h" +#include "UObject/ConstructorHelpers.h" +#include "Engine/Engine.h" // Needed for VR Headset #include "Engine.h" diff --git a/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvHud.h b/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvHud.h index b2115960afc3..0831b47e8c09 100644 --- a/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvHud.h +++ b/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvHud.h @@ -1,9 +1,11 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once + +#include "CoreMinimal.h" #include "GameFramework/HUD.h" #include "TP_VehicleAdvHud.generated.h" - UCLASS(config = Game) class ATP_VehicleAdvHud : public AHUD { diff --git a/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvPawn.cpp b/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvPawn.cpp index d29f68b3278e..394caa18e710 100644 --- a/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvPawn.cpp +++ b/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvPawn.cpp @@ -1,6 +1,5 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_VehicleAdv.h" #include "TP_VehicleAdvPawn.h" #include "TP_VehicleAdvWheelFront.h" #include "TP_VehicleAdvWheelRear.h" @@ -10,14 +9,16 @@ #include "Camera/CameraComponent.h" #include "Components/InputComponent.h" #include "Components/TextRenderComponent.h" +#include "Components/AudioComponent.h" #include "Sound/SoundCue.h" #include "PhysicalMaterials/PhysicalMaterial.h" #include "WheeledVehicleMovementComponent4W.h" #include "Engine/SkeletalMesh.h" - +#include "Engine/Engine.h" +#include "GameFramework/Controller.h" +#include "UObject/ConstructorHelpers.h" // Needed for VR Headset -#include "Engine.h" #if HMD_MODULE_INCLUDED #include "IHeadMountedDisplay.h" #endif // HMD_MODULE_INCLUDED diff --git a/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvPawn.h b/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvPawn.h index c77b05eb0185..e1f9bbb92b74 100644 --- a/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvPawn.h +++ b/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvPawn.h @@ -1,5 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once + +#include "CoreMinimal.h" #include "WheeledVehicle.h" #include "TP_VehicleAdvPawn.generated.h" @@ -8,6 +11,7 @@ class UCameraComponent; class USpringArmComponent; class UTextRenderComponent; class UInputComponent; +class UAudioComponent; UCLASS(config=Game) class ATP_VehicleAdvPawn : public AWheeledVehicle diff --git a/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvWheelFront.cpp b/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvWheelFront.cpp index f9e791545af4..896957c6dfb7 100644 --- a/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvWheelFront.cpp +++ b/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvWheelFront.cpp @@ -1,8 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_VehicleAdv.h" #include "TP_VehicleAdvWheelFront.h" #include "TireConfig.h" +#include "UObject/ConstructorHelpers.h" UTP_VehicleAdvWheelFront::UTP_VehicleAdvWheelFront() { diff --git a/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvWheelFront.h b/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvWheelFront.h index f429db63b502..b6c4f1bce1bb 100644 --- a/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvWheelFront.h +++ b/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvWheelFront.h @@ -1,5 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once + +#include "CoreMinimal.h" #include "VehicleWheel.h" #include "TP_VehicleAdvWheelFront.generated.h" diff --git a/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvWheelRear.cpp b/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvWheelRear.cpp index 8eb26ca6e549..d64efcec66e3 100644 --- a/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvWheelRear.cpp +++ b/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvWheelRear.cpp @@ -1,8 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. -#include "TP_VehicleAdv.h" #include "TP_VehicleAdvWheelRear.h" #include "TireConfig.h" +#include "UObject/ConstructorHelpers.h" UTP_VehicleAdvWheelRear::UTP_VehicleAdvWheelRear() { diff --git a/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvWheelRear.h b/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvWheelRear.h index 796092bf3c89..10235a24c5e6 100644 --- a/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvWheelRear.h +++ b/Templates/TP_VehicleAdv/Source/TP_VehicleAdv/TP_VehicleAdvWheelRear.h @@ -1,5 +1,8 @@ // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. + #pragma once + +#include "CoreMinimal.h" #include "VehicleWheel.h" #include "TP_VehicleAdvWheelRear.generated.h"